From 871480933a1c28f8a9fed4c4d34d06c439a7a422 Mon Sep 17 00:00:00 2001 From: Srikant Patnaik Date: Sun, 11 Jan 2015 12:28:04 +0530 Subject: Moved, renamed, and deleted files The original directory structure was scattered and unorganized. Changes are basically to make it look like kernel structure. --- ANDROID_3.4.5/drivers/usb/Kconfig | 186 - ANDROID_3.4.5/drivers/usb/Makefile | 58 - ANDROID_3.4.5/drivers/usb/README | 54 - ANDROID_3.4.5/drivers/usb/atm/Kconfig | 68 - ANDROID_3.4.5/drivers/usb/atm/Makefile | 11 - ANDROID_3.4.5/drivers/usb/atm/cxacru.c | 1380 ------ ANDROID_3.4.5/drivers/usb/atm/speedtch.c | 961 ---- ANDROID_3.4.5/drivers/usb/atm/ueagle-atm.c | 2760 ------------ ANDROID_3.4.5/drivers/usb/atm/usbatm.c | 1388 ------ ANDROID_3.4.5/drivers/usb/atm/usbatm.h | 222 - ANDROID_3.4.5/drivers/usb/atm/xusbatm.c | 233 - ANDROID_3.4.5/drivers/usb/c67x00/Makefile | 9 - ANDROID_3.4.5/drivers/usb/c67x00/c67x00-drv.c | 234 - ANDROID_3.4.5/drivers/usb/c67x00/c67x00-hcd.c | 411 -- ANDROID_3.4.5/drivers/usb/c67x00/c67x00-hcd.h | 133 - ANDROID_3.4.5/drivers/usb/c67x00/c67x00-ll-hpi.c | 481 -- ANDROID_3.4.5/drivers/usb/c67x00/c67x00-sched.c | 1171 ----- ANDROID_3.4.5/drivers/usb/c67x00/c67x00.h | 294 -- ANDROID_3.4.5/drivers/usb/class/Kconfig | 52 - ANDROID_3.4.5/drivers/usb/class/Makefile | 9 - ANDROID_3.4.5/drivers/usb/class/cdc-acm.c | 1752 -------- ANDROID_3.4.5/drivers/usb/class/cdc-acm.h | 130 - ANDROID_3.4.5/drivers/usb/class/cdc-wdm.c | 1048 ----- ANDROID_3.4.5/drivers/usb/class/usblp.c | 1421 ------ ANDROID_3.4.5/drivers/usb/class/usbtmc.c | 1121 ----- ANDROID_3.4.5/drivers/usb/core/Kconfig | 150 - ANDROID_3.4.5/drivers/usb/core/Makefile | 14 - ANDROID_3.4.5/drivers/usb/core/buffer.c | 151 - ANDROID_3.4.5/drivers/usb/core/config.c | 860 ---- ANDROID_3.4.5/drivers/usb/core/devices.c | 688 --- ANDROID_3.4.5/drivers/usb/core/devio.c | 2181 --------- ANDROID_3.4.5/drivers/usb/core/driver.c | 1741 -------- ANDROID_3.4.5/drivers/usb/core/endpoint.c | 218 - ANDROID_3.4.5/drivers/usb/core/file.c | 253 -- ANDROID_3.4.5/drivers/usb/core/generic.c | 247 - ANDROID_3.4.5/drivers/usb/core/hcd-pci.c | 602 --- ANDROID_3.4.5/drivers/usb/core/hcd.c | 2656 ----------- ANDROID_3.4.5/drivers/usb/core/hub.c | 4284 ------------------ ANDROID_3.4.5/drivers/usb/core/inode.c | 748 ---- ANDROID_3.4.5/drivers/usb/core/message.c | 1952 -------- ANDROID_3.4.5/drivers/usb/core/notify.c | 69 - ANDROID_3.4.5/drivers/usb/core/otg_whitelist.h | 112 - ANDROID_3.4.5/drivers/usb/core/quirks.c | 199 - ANDROID_3.4.5/drivers/usb/core/sysfs.c | 947 ---- ANDROID_3.4.5/drivers/usb/core/urb.c | 888 ---- ANDROID_3.4.5/drivers/usb/core/usb.c | 1131 ----- ANDROID_3.4.5/drivers/usb/core/usb.h | 158 - ANDROID_3.4.5/drivers/usb/dwc3/Kconfig | 28 - ANDROID_3.4.5/drivers/usb/dwc3/Makefile | 47 - ANDROID_3.4.5/drivers/usb/dwc3/core.c | 605 --- ANDROID_3.4.5/drivers/usb/dwc3/core.h | 784 ---- ANDROID_3.4.5/drivers/usb/dwc3/debug.h | 50 - ANDROID_3.4.5/drivers/usb/dwc3/debugfs.c | 710 --- ANDROID_3.4.5/drivers/usb/dwc3/dwc3-exynos.c | 151 - ANDROID_3.4.5/drivers/usb/dwc3/dwc3-omap.c | 392 -- ANDROID_3.4.5/drivers/usb/dwc3/dwc3-pci.c | 173 - ANDROID_3.4.5/drivers/usb/dwc3/ep0.c | 873 ---- ANDROID_3.4.5/drivers/usb/dwc3/gadget.c | 2396 ---------- ANDROID_3.4.5/drivers/usb/dwc3/gadget.h | 187 - ANDROID_3.4.5/drivers/usb/dwc3/host.c | 102 - ANDROID_3.4.5/drivers/usb/dwc3/io.h | 54 - ANDROID_3.4.5/drivers/usb/early/Makefile | 5 - ANDROID_3.4.5/drivers/usb/early/ehci-dbgp.c | 1089 ----- ANDROID_3.4.5/drivers/usb/gadget/Kconfig | 1000 ----- ANDROID_3.4.5/drivers/usb/gadget/Makefile | 78 - ANDROID_3.4.5/drivers/usb/gadget/acm_ms.c | 256 -- ANDROID_3.4.5/drivers/usb/gadget/amd5536udc.c | 3422 -------------- ANDROID_3.4.5/drivers/usb/gadget/amd5536udc.h | 617 --- ANDROID_3.4.5/drivers/usb/gadget/android.c | 1691 ------- ANDROID_3.4.5/drivers/usb/gadget/at91_udc.c | 2035 --------- ANDROID_3.4.5/drivers/usb/gadget/at91_udc.h | 172 - ANDROID_3.4.5/drivers/usb/gadget/atmel_usba_udc.c | 2118 --------- ANDROID_3.4.5/drivers/usb/gadget/atmel_usba_udc.h | 359 -- ANDROID_3.4.5/drivers/usb/gadget/audio.c | 224 - ANDROID_3.4.5/drivers/usb/gadget/cdc2.c | 257 -- ANDROID_3.4.5/drivers/usb/gadget/ci13xxx_msm.c | 126 - ANDROID_3.4.5/drivers/usb/gadget/ci13xxx_pci.c | 176 - ANDROID_3.4.5/drivers/usb/gadget/ci13xxx_udc.c | 2996 ------------- ANDROID_3.4.5/drivers/usb/gadget/ci13xxx_udc.h | 227 - ANDROID_3.4.5/drivers/usb/gadget/composite.c | 1674 ------- ANDROID_3.4.5/drivers/usb/gadget/config.c | 158 - ANDROID_3.4.5/drivers/usb/gadget/dbgp.c | 433 -- ANDROID_3.4.5/drivers/usb/gadget/dummy_hcd.c | 2673 ----------- ANDROID_3.4.5/drivers/usb/gadget/epautoconf.c | 430 -- ANDROID_3.4.5/drivers/usb/gadget/ether.c | 413 -- ANDROID_3.4.5/drivers/usb/gadget/f_accessory.c | 1190 ----- ANDROID_3.4.5/drivers/usb/gadget/f_acm.c | 814 ---- ANDROID_3.4.5/drivers/usb/gadget/f_adb.c | 620 --- ANDROID_3.4.5/drivers/usb/gadget/f_audio_source.c | 828 ---- ANDROID_3.4.5/drivers/usb/gadget/f_ecm.c | 924 ---- ANDROID_3.4.5/drivers/usb/gadget/f_eem.c | 598 --- ANDROID_3.4.5/drivers/usb/gadget/f_fs.c | 2415 ---------- ANDROID_3.4.5/drivers/usb/gadget/f_hid.c | 659 --- ANDROID_3.4.5/drivers/usb/gadget/f_loopback.c | 430 -- ANDROID_3.4.5/drivers/usb/gadget/f_mass_storage.c | 3218 -------------- ANDROID_3.4.5/drivers/usb/gadget/f_midi.c | 990 ----- ANDROID_3.4.5/drivers/usb/gadget/f_mtp.c | 1295 ------ ANDROID_3.4.5/drivers/usb/gadget/f_ncm.c | 1378 ------ ANDROID_3.4.5/drivers/usb/gadget/f_obex.c | 471 -- ANDROID_3.4.5/drivers/usb/gadget/f_phonet.c | 629 --- ANDROID_3.4.5/drivers/usb/gadget/f_rawbulk.c | 322 -- ANDROID_3.4.5/drivers/usb/gadget/f_rndis.c | 936 ---- ANDROID_3.4.5/drivers/usb/gadget/f_serial.c | 321 -- ANDROID_3.4.5/drivers/usb/gadget/f_sourcesink.c | 584 --- ANDROID_3.4.5/drivers/usb/gadget/f_subset.c | 460 -- ANDROID_3.4.5/drivers/usb/gadget/f_uac1.c | 776 ---- ANDROID_3.4.5/drivers/usb/gadget/f_uac2.c | 1449 ------ ANDROID_3.4.5/drivers/usb/gadget/f_uvc.c | 662 --- ANDROID_3.4.5/drivers/usb/gadget/f_uvc.h | 25 - ANDROID_3.4.5/drivers/usb/gadget/file_storage.c | 3676 --------------- ANDROID_3.4.5/drivers/usb/gadget/fsl_mxc_udc.c | 123 - ANDROID_3.4.5/drivers/usb/gadget/fsl_qe_udc.c | 2823 ------------ ANDROID_3.4.5/drivers/usb/gadget/fsl_qe_udc.h | 422 -- ANDROID_3.4.5/drivers/usb/gadget/fsl_udc_core.c | 2778 ------------ ANDROID_3.4.5/drivers/usb/gadget/fsl_usb2_udc.h | 600 --- ANDROID_3.4.5/drivers/usb/gadget/fusb300_udc.c | 1561 ------- ANDROID_3.4.5/drivers/usb/gadget/fusb300_udc.h | 677 --- ANDROID_3.4.5/drivers/usb/gadget/g_ffs.c | 327 -- ANDROID_3.4.5/drivers/usb/gadget/g_zero.h | 25 - ANDROID_3.4.5/drivers/usb/gadget/gadget_chips.h | 147 - ANDROID_3.4.5/drivers/usb/gadget/gmidi.c | 206 - ANDROID_3.4.5/drivers/usb/gadget/goku_udc.c | 1908 -------- ANDROID_3.4.5/drivers/usb/gadget/goku_udc.h | 293 -- ANDROID_3.4.5/drivers/usb/gadget/hid.c | 288 -- ANDROID_3.4.5/drivers/usb/gadget/imx_udc.c | 1595 ------- ANDROID_3.4.5/drivers/usb/gadget/imx_udc.h | 351 -- ANDROID_3.4.5/drivers/usb/gadget/inode.c | 2135 --------- ANDROID_3.4.5/drivers/usb/gadget/langwell_udc.c | 3434 -------------- ANDROID_3.4.5/drivers/usb/gadget/langwell_udc.h | 224 - ANDROID_3.4.5/drivers/usb/gadget/m66592-udc.c | 1773 -------- ANDROID_3.4.5/drivers/usb/gadget/m66592-udc.h | 610 --- ANDROID_3.4.5/drivers/usb/gadget/mass_storage.c | 182 - ANDROID_3.4.5/drivers/usb/gadget/multi.c | 362 -- ANDROID_3.4.5/drivers/usb/gadget/mv_udc.h | 315 -- ANDROID_3.4.5/drivers/usb/gadget/mv_udc_core.c | 2494 ----------- ANDROID_3.4.5/drivers/usb/gadget/ncm.c | 240 - ANDROID_3.4.5/drivers/usb/gadget/ndis.h | 211 - ANDROID_3.4.5/drivers/usb/gadget/net2272.c | 2715 ----------- ANDROID_3.4.5/drivers/usb/gadget/net2272.h | 601 --- ANDROID_3.4.5/drivers/usb/gadget/net2280.c | 2896 ------------ ANDROID_3.4.5/drivers/usb/gadget/net2280.h | 308 -- ANDROID_3.4.5/drivers/usb/gadget/nokia.c | 259 -- ANDROID_3.4.5/drivers/usb/gadget/omap_udc.c | 3148 ------------- ANDROID_3.4.5/drivers/usb/gadget/omap_udc.h | 207 - ANDROID_3.4.5/drivers/usb/gadget/pch_udc.c | 3310 -------------- ANDROID_3.4.5/drivers/usb/gadget/printer.c | 1600 ------- ANDROID_3.4.5/drivers/usb/gadget/pxa25x_udc.c | 2373 ---------- ANDROID_3.4.5/drivers/usb/gadget/pxa25x_udc.h | 252 -- ANDROID_3.4.5/drivers/usb/gadget/pxa27x_udc.c | 2679 ----------- ANDROID_3.4.5/drivers/usb/gadget/pxa27x_udc.h | 496 --- ANDROID_3.4.5/drivers/usb/gadget/r8a66597-udc.c | 2043 --------- ANDROID_3.4.5/drivers/usb/gadget/r8a66597-udc.h | 294 -- ANDROID_3.4.5/drivers/usb/gadget/rawbulk.c | 1272 ------ .../drivers/usb/gadget/rawbulk_transfer.c | 1372 ------ ANDROID_3.4.5/drivers/usb/gadget/rndis.c | 1209 ----- ANDROID_3.4.5/drivers/usb/gadget/rndis.h | 268 -- ANDROID_3.4.5/drivers/usb/gadget/s3c-hsotg.c | 3478 --------------- ANDROID_3.4.5/drivers/usb/gadget/s3c-hsudc.c | 1413 ------ ANDROID_3.4.5/drivers/usb/gadget/s3c2410_udc.c | 2106 --------- ANDROID_3.4.5/drivers/usb/gadget/s3c2410_udc.h | 100 - ANDROID_3.4.5/drivers/usb/gadget/serial.c | 283 -- ANDROID_3.4.5/drivers/usb/gadget/storage_common.c | 938 ---- ANDROID_3.4.5/drivers/usb/gadget/u_ether.c | 1015 ----- ANDROID_3.4.5/drivers/usb/gadget/u_ether.h | 126 - ANDROID_3.4.5/drivers/usb/gadget/u_phonet.h | 21 - ANDROID_3.4.5/drivers/usb/gadget/u_serial.c | 1344 ------ ANDROID_3.4.5/drivers/usb/gadget/u_serial.h | 65 - ANDROID_3.4.5/drivers/usb/gadget/u_uac1.c | 327 -- ANDROID_3.4.5/drivers/usb/gadget/u_uac1.h | 56 - ANDROID_3.4.5/drivers/usb/gadget/udc-core.c | 539 --- ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.c | 4699 -------------------- ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.h | 801 ---- ANDROID_3.4.5/drivers/usb/gadget/usbstring.c | 71 - ANDROID_3.4.5/drivers/usb/gadget/uvc.h | 199 - ANDROID_3.4.5/drivers/usb/gadget/uvc_queue.c | 585 --- ANDROID_3.4.5/drivers/usb/gadget/uvc_queue.h | 69 - ANDROID_3.4.5/drivers/usb/gadget/uvc_v4l2.c | 356 -- ANDROID_3.4.5/drivers/usb/gadget/uvc_video.c | 385 -- ANDROID_3.4.5/drivers/usb/gadget/webcam.c | 399 -- ANDROID_3.4.5/drivers/usb/gadget/zero.c | 353 -- ANDROID_3.4.5/drivers/usb/host/Kconfig | 655 --- ANDROID_3.4.5/drivers/usb/host/Makefile | 43 - ANDROID_3.4.5/drivers/usb/host/alchemy-common.c | 614 --- ANDROID_3.4.5/drivers/usb/host/ehci-atmel.c | 256 -- ANDROID_3.4.5/drivers/usb/host/ehci-au1xxx.c | 267 -- ANDROID_3.4.5/drivers/usb/host/ehci-cns3xxx.c | 171 - ANDROID_3.4.5/drivers/usb/host/ehci-dbg.c | 1089 ----- ANDROID_3.4.5/drivers/usb/host/ehci-fsl.c | 706 --- ANDROID_3.4.5/drivers/usb/host/ehci-fsl.h | 53 - ANDROID_3.4.5/drivers/usb/host/ehci-grlib.c | 242 - ANDROID_3.4.5/drivers/usb/host/ehci-hcd.c | 1554 ------- ANDROID_3.4.5/drivers/usb/host/ehci-hub.c | 1405 ------ ANDROID_3.4.5/drivers/usb/host/ehci-ixp4xx.c | 156 - ANDROID_3.4.5/drivers/usb/host/ehci-lpm.c | 84 - ANDROID_3.4.5/drivers/usb/host/ehci-ls1x.c | 159 - ANDROID_3.4.5/drivers/usb/host/ehci-mem.c | 264 -- ANDROID_3.4.5/drivers/usb/host/ehci-msm.c | 247 - ANDROID_3.4.5/drivers/usb/host/ehci-mv.c | 391 -- ANDROID_3.4.5/drivers/usb/host/ehci-mxc.c | 344 -- ANDROID_3.4.5/drivers/usb/host/ehci-octeon.c | 209 - ANDROID_3.4.5/drivers/usb/host/ehci-omap.c | 377 -- ANDROID_3.4.5/drivers/usb/host/ehci-orion.c | 320 -- ANDROID_3.4.5/drivers/usb/host/ehci-pci.c | 575 --- ANDROID_3.4.5/drivers/usb/host/ehci-platform.c | 196 - ANDROID_3.4.5/drivers/usb/host/ehci-pmcmsp.c | 383 -- ANDROID_3.4.5/drivers/usb/host/ehci-ppc-of.c | 284 -- ANDROID_3.4.5/drivers/usb/host/ehci-ps3.c | 282 -- ANDROID_3.4.5/drivers/usb/host/ehci-q.c | 1321 ------ ANDROID_3.4.5/drivers/usb/host/ehci-s5p.c | 313 -- ANDROID_3.4.5/drivers/usb/host/ehci-sched.c | 2502 ----------- ANDROID_3.4.5/drivers/usb/host/ehci-sh.c | 243 - ANDROID_3.4.5/drivers/usb/host/ehci-spear.c | 291 -- ANDROID_3.4.5/drivers/usb/host/ehci-sysfs.c | 190 - ANDROID_3.4.5/drivers/usb/host/ehci-tegra.c | 873 ---- ANDROID_3.4.5/drivers/usb/host/ehci-vt8500.c | 175 - ANDROID_3.4.5/drivers/usb/host/ehci-w90x900.c | 186 - ANDROID_3.4.5/drivers/usb/host/ehci-xilinx-of.c | 299 -- ANDROID_3.4.5/drivers/usb/host/ehci-xls.c | 161 - ANDROID_3.4.5/drivers/usb/host/ehci.h | 796 ---- ANDROID_3.4.5/drivers/usb/host/fhci-dbg.c | 139 - ANDROID_3.4.5/drivers/usb/host/fhci-hcd.c | 833 ---- ANDROID_3.4.5/drivers/usb/host/fhci-hub.c | 345 -- ANDROID_3.4.5/drivers/usb/host/fhci-mem.c | 114 - ANDROID_3.4.5/drivers/usb/host/fhci-q.c | 285 -- ANDROID_3.4.5/drivers/usb/host/fhci-sched.c | 895 ---- ANDROID_3.4.5/drivers/usb/host/fhci-tds.c | 626 --- ANDROID_3.4.5/drivers/usb/host/fhci.h | 612 --- ANDROID_3.4.5/drivers/usb/host/fsl-mph-dr-of.c | 303 -- ANDROID_3.4.5/drivers/usb/host/hwa-hc.c | 843 ---- ANDROID_3.4.5/drivers/usb/host/imx21-dbg.c | 527 --- ANDROID_3.4.5/drivers/usb/host/imx21-hcd.c | 1932 -------- ANDROID_3.4.5/drivers/usb/host/imx21-hcd.h | 440 -- ANDROID_3.4.5/drivers/usb/host/isp116x-hcd.c | 1713 ------- ANDROID_3.4.5/drivers/usb/host/isp116x.h | 606 --- ANDROID_3.4.5/drivers/usb/host/isp1362-hcd.c | 2869 ------------ ANDROID_3.4.5/drivers/usb/host/isp1362.h | 1057 ----- ANDROID_3.4.5/drivers/usb/host/isp1760-hcd.c | 2262 ---------- ANDROID_3.4.5/drivers/usb/host/isp1760-hcd.h | 208 - ANDROID_3.4.5/drivers/usb/host/isp1760-if.c | 473 -- ANDROID_3.4.5/drivers/usb/host/octeon2-common.c | 200 - ANDROID_3.4.5/drivers/usb/host/ohci-at91.c | 717 --- ANDROID_3.4.5/drivers/usb/host/ohci-au1xxx.c | 233 - ANDROID_3.4.5/drivers/usb/host/ohci-cns3xxx.c | 165 - ANDROID_3.4.5/drivers/usb/host/ohci-da8xx.c | 456 -- ANDROID_3.4.5/drivers/usb/host/ohci-dbg.c | 877 ---- ANDROID_3.4.5/drivers/usb/host/ohci-ep93xx.c | 216 - ANDROID_3.4.5/drivers/usb/host/ohci-exynos.c | 272 -- ANDROID_3.4.5/drivers/usb/host/ohci-hcd.c | 1305 ------ ANDROID_3.4.5/drivers/usb/host/ohci-hub.c | 825 ---- ANDROID_3.4.5/drivers/usb/host/ohci-jz4740.c | 276 -- ANDROID_3.4.5/drivers/usb/host/ohci-mem.c | 138 - ANDROID_3.4.5/drivers/usb/host/ohci-nxp.c | 528 --- ANDROID_3.4.5/drivers/usb/host/ohci-octeon.c | 214 - ANDROID_3.4.5/drivers/usb/host/ohci-omap.c | 557 --- ANDROID_3.4.5/drivers/usb/host/ohci-omap3.c | 243 - ANDROID_3.4.5/drivers/usb/host/ohci-pci.c | 422 -- ANDROID_3.4.5/drivers/usb/host/ohci-platform.c | 194 - ANDROID_3.4.5/drivers/usb/host/ohci-pnx8550.c | 242 - ANDROID_3.4.5/drivers/usb/host/ohci-ppc-of.c | 253 -- ANDROID_3.4.5/drivers/usb/host/ohci-ppc-soc.c | 215 - ANDROID_3.4.5/drivers/usb/host/ohci-ps3.c | 249 -- ANDROID_3.4.5/drivers/usb/host/ohci-pxa27x.c | 551 --- ANDROID_3.4.5/drivers/usb/host/ohci-q.c | 1134 ----- ANDROID_3.4.5/drivers/usb/host/ohci-s3c2410.c | 552 --- ANDROID_3.4.5/drivers/usb/host/ohci-sa1111.c | 257 -- ANDROID_3.4.5/drivers/usb/host/ohci-sh.c | 141 - ANDROID_3.4.5/drivers/usb/host/ohci-sm501.c | 265 -- ANDROID_3.4.5/drivers/usb/host/ohci-spear.c | 239 - ANDROID_3.4.5/drivers/usb/host/ohci-ssb.c | 260 -- ANDROID_3.4.5/drivers/usb/host/ohci-tmio.c | 373 -- ANDROID_3.4.5/drivers/usb/host/ohci-xls.c | 151 - ANDROID_3.4.5/drivers/usb/host/ohci.h | 725 --- ANDROID_3.4.5/drivers/usb/host/oxu210hp-hcd.c | 3957 ---------------- ANDROID_3.4.5/drivers/usb/host/oxu210hp.h | 447 -- ANDROID_3.4.5/drivers/usb/host/pci-quirks.c | 934 ---- ANDROID_3.4.5/drivers/usb/host/pci-quirks.h | 19 - ANDROID_3.4.5/drivers/usb/host/r8a66597-hcd.c | 2558 ----------- ANDROID_3.4.5/drivers/usb/host/r8a66597.h | 350 -- ANDROID_3.4.5/drivers/usb/host/sl811-hcd.c | 1822 -------- ANDROID_3.4.5/drivers/usb/host/sl811.h | 266 -- ANDROID_3.4.5/drivers/usb/host/sl811_cs.c | 216 - ANDROID_3.4.5/drivers/usb/host/u132-hcd.c | 3260 -------------- ANDROID_3.4.5/drivers/usb/host/uhci-debug.c | 593 --- ANDROID_3.4.5/drivers/usb/host/uhci-grlib.c | 208 - ANDROID_3.4.5/drivers/usb/host/uhci-hcd.c | 939 ---- ANDROID_3.4.5/drivers/usb/host/uhci-hcd.h | 664 --- ANDROID_3.4.5/drivers/usb/host/uhci-hub.c | 421 -- ANDROID_3.4.5/drivers/usb/host/uhci-pci.c | 325 -- ANDROID_3.4.5/drivers/usb/host/uhci-q.c | 1791 -------- ANDROID_3.4.5/drivers/usb/host/whci/Kbuild | 12 - ANDROID_3.4.5/drivers/usb/host/whci/asl.c | 389 -- ANDROID_3.4.5/drivers/usb/host/whci/debug.c | 203 - ANDROID_3.4.5/drivers/usb/host/whci/hcd.c | 368 -- ANDROID_3.4.5/drivers/usb/host/whci/hw.c | 104 - ANDROID_3.4.5/drivers/usb/host/whci/init.c | 189 - ANDROID_3.4.5/drivers/usb/host/whci/int.c | 94 - ANDROID_3.4.5/drivers/usb/host/whci/pzl.c | 417 -- ANDROID_3.4.5/drivers/usb/host/whci/qset.c | 832 ---- ANDROID_3.4.5/drivers/usb/host/whci/whcd.h | 215 - ANDROID_3.4.5/drivers/usb/host/whci/whci-hc.h | 414 -- ANDROID_3.4.5/drivers/usb/host/whci/wusb.c | 222 - ANDROID_3.4.5/drivers/usb/host/xhci-dbg.c | 576 --- ANDROID_3.4.5/drivers/usb/host/xhci-ext-caps.h | 155 - ANDROID_3.4.5/drivers/usb/host/xhci-hub.c | 1096 ----- ANDROID_3.4.5/drivers/usb/host/xhci-mem.c | 2460 ---------- ANDROID_3.4.5/drivers/usb/host/xhci-pci.c | 335 -- ANDROID_3.4.5/drivers/usb/host/xhci-plat.c | 205 - ANDROID_3.4.5/drivers/usb/host/xhci-ring.c | 3691 --------------- ANDROID_3.4.5/drivers/usb/host/xhci.c | 4114 ----------------- ANDROID_3.4.5/drivers/usb/host/xhci.h | 1810 -------- ANDROID_3.4.5/drivers/usb/image/Kconfig | 30 - ANDROID_3.4.5/drivers/usb/image/Makefile | 6 - ANDROID_3.4.5/drivers/usb/image/mdc800.c | 1089 ----- ANDROID_3.4.5/drivers/usb/image/microtek.c | 816 ---- ANDROID_3.4.5/drivers/usb/image/microtek.h | 54 - ANDROID_3.4.5/drivers/usb/misc/Kconfig | 246 - ANDROID_3.4.5/drivers/usb/misc/Makefile | 29 - ANDROID_3.4.5/drivers/usb/misc/adutux.c | 892 ---- ANDROID_3.4.5/drivers/usb/misc/appledisplay.c | 381 -- ANDROID_3.4.5/drivers/usb/misc/cypress_cy7c63.c | 279 -- ANDROID_3.4.5/drivers/usb/misc/cytherm.c | 424 -- ANDROID_3.4.5/drivers/usb/misc/emi26.c | 286 -- ANDROID_3.4.5/drivers/usb/misc/emi62.c | 300 -- ANDROID_3.4.5/drivers/usb/misc/ftdi-elan.c | 2946 ------------ ANDROID_3.4.5/drivers/usb/misc/idmouse.c | 436 -- ANDROID_3.4.5/drivers/usb/misc/iowarrior.c | 930 ---- ANDROID_3.4.5/drivers/usb/misc/isight_firmware.c | 134 - ANDROID_3.4.5/drivers/usb/misc/ldusb.c | 825 ---- ANDROID_3.4.5/drivers/usb/misc/legousbtower.c | 1052 ----- ANDROID_3.4.5/drivers/usb/misc/rio500.c | 539 --- ANDROID_3.4.5/drivers/usb/misc/rio500_usb.h | 37 - ANDROID_3.4.5/drivers/usb/misc/sisusbvga/Kconfig | 46 - ANDROID_3.4.5/drivers/usb/misc/sisusbvga/Makefile | 7 - ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb.c | 3285 -------------- ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb.h | 311 -- .../drivers/usb/misc/sisusbvga/sisusb_con.c | 1564 ------- .../drivers/usb/misc/sisusbvga/sisusb_init.c | 959 ---- .../drivers/usb/misc/sisusbvga/sisusb_init.h | 841 ---- .../drivers/usb/misc/sisusbvga/sisusb_struct.h | 161 - ANDROID_3.4.5/drivers/usb/misc/trancevibrator.c | 144 - ANDROID_3.4.5/drivers/usb/misc/usb_u132.h | 101 - ANDROID_3.4.5/drivers/usb/misc/usblcd.c | 457 -- ANDROID_3.4.5/drivers/usb/misc/usbled.c | 240 - ANDROID_3.4.5/drivers/usb/misc/usbsevseg.c | 444 -- ANDROID_3.4.5/drivers/usb/misc/usbtest.c | 2529 ----------- ANDROID_3.4.5/drivers/usb/misc/uss720.c | 825 ---- ANDROID_3.4.5/drivers/usb/misc/yurex.c | 540 --- ANDROID_3.4.5/drivers/usb/mon/Kconfig | 13 - ANDROID_3.4.5/drivers/usb/mon/Makefile | 7 - ANDROID_3.4.5/drivers/usb/mon/mon_bin.c | 1389 ------ ANDROID_3.4.5/drivers/usb/mon/mon_main.c | 431 -- ANDROID_3.4.5/drivers/usb/mon/mon_stat.c | 69 - ANDROID_3.4.5/drivers/usb/mon/mon_text.c | 761 ---- ANDROID_3.4.5/drivers/usb/mon/usb_mon.h | 75 - ANDROID_3.4.5/drivers/usb/musb/Kconfig | 117 - ANDROID_3.4.5/drivers/usb/musb/Makefile | 30 - ANDROID_3.4.5/drivers/usb/musb/am35x.c | 656 --- ANDROID_3.4.5/drivers/usb/musb/blackfin.c | 600 --- ANDROID_3.4.5/drivers/usb/musb/blackfin.h | 87 - ANDROID_3.4.5/drivers/usb/musb/cppi_dma.c | 1563 ------- ANDROID_3.4.5/drivers/usb/musb/cppi_dma.h | 134 - ANDROID_3.4.5/drivers/usb/musb/da8xx.c | 601 --- ANDROID_3.4.5/drivers/usb/musb/davinci.c | 635 --- ANDROID_3.4.5/drivers/usb/musb/davinci.h | 107 - ANDROID_3.4.5/drivers/usb/musb/musb_core.c | 2416 ---------- ANDROID_3.4.5/drivers/usb/musb/musb_core.h | 606 --- ANDROID_3.4.5/drivers/usb/musb/musb_debug.h | 58 - ANDROID_3.4.5/drivers/usb/musb/musb_debugfs.c | 278 -- ANDROID_3.4.5/drivers/usb/musb/musb_dma.h | 186 - ANDROID_3.4.5/drivers/usb/musb/musb_gadget.c | 2239 ---------- ANDROID_3.4.5/drivers/usb/musb/musb_gadget.h | 121 - ANDROID_3.4.5/drivers/usb/musb/musb_gadget_ep0.c | 1083 ----- ANDROID_3.4.5/drivers/usb/musb/musb_host.c | 2331 ---------- ANDROID_3.4.5/drivers/usb/musb/musb_host.h | 108 - ANDROID_3.4.5/drivers/usb/musb/musb_io.h | 142 - ANDROID_3.4.5/drivers/usb/musb/musb_regs.h | 645 --- ANDROID_3.4.5/drivers/usb/musb/musb_virthub.c | 435 -- ANDROID_3.4.5/drivers/usb/musb/musbhsdma.c | 422 -- ANDROID_3.4.5/drivers/usb/musb/musbhsdma.h | 165 - ANDROID_3.4.5/drivers/usb/musb/omap2430.c | 555 --- ANDROID_3.4.5/drivers/usb/musb/omap2430.h | 52 - ANDROID_3.4.5/drivers/usb/musb/tusb6010.c | 1265 ------ ANDROID_3.4.5/drivers/usb/musb/tusb6010.h | 232 - ANDROID_3.4.5/drivers/usb/musb/tusb6010_omap.c | 727 --- ANDROID_3.4.5/drivers/usb/musb/ux500.c | 219 - ANDROID_3.4.5/drivers/usb/musb/ux500_dma.c | 393 -- ANDROID_3.4.5/drivers/usb/otg/Kconfig | 139 - ANDROID_3.4.5/drivers/usb/otg/Makefile | 24 - ANDROID_3.4.5/drivers/usb/otg/ab8500-usb.c | 596 --- ANDROID_3.4.5/drivers/usb/otg/fsl_otg.c | 1169 ----- ANDROID_3.4.5/drivers/usb/otg/fsl_otg.h | 406 -- ANDROID_3.4.5/drivers/usb/otg/gpio_vbus.c | 381 -- ANDROID_3.4.5/drivers/usb/otg/isp1301_omap.c | 1656 ------- ANDROID_3.4.5/drivers/usb/otg/msm_otg.c | 1773 -------- ANDROID_3.4.5/drivers/usb/otg/mv_otg.c | 973 ---- ANDROID_3.4.5/drivers/usb/otg/mv_otg.h | 165 - ANDROID_3.4.5/drivers/usb/otg/nop-usb-xceiv.c | 175 - ANDROID_3.4.5/drivers/usb/otg/otg-wakelock.c | 170 - ANDROID_3.4.5/drivers/usb/otg/otg.c | 102 - ANDROID_3.4.5/drivers/usb/otg/otg_fsm.c | 348 -- ANDROID_3.4.5/drivers/usb/otg/otg_fsm.h | 154 - ANDROID_3.4.5/drivers/usb/otg/twl4030-usb.c | 734 --- ANDROID_3.4.5/drivers/usb/otg/twl6030-usb.c | 539 --- ANDROID_3.4.5/drivers/usb/otg/ulpi.c | 283 -- ANDROID_3.4.5/drivers/usb/otg/ulpi_viewport.c | 80 - ANDROID_3.4.5/drivers/usb/renesas_usbhs/Kconfig | 15 - ANDROID_3.4.5/drivers/usb/renesas_usbhs/Makefile | 15 - ANDROID_3.4.5/drivers/usb/renesas_usbhs/common.c | 648 --- ANDROID_3.4.5/drivers/usb/renesas_usbhs/common.h | 324 -- ANDROID_3.4.5/drivers/usb/renesas_usbhs/fifo.c | 1193 ----- ANDROID_3.4.5/drivers/usb/renesas_usbhs/fifo.h | 104 - ANDROID_3.4.5/drivers/usb/renesas_usbhs/mod.c | 369 -- ANDROID_3.4.5/drivers/usb/renesas_usbhs/mod.h | 172 - .../drivers/usb/renesas_usbhs/mod_gadget.c | 1021 ----- ANDROID_3.4.5/drivers/usb/renesas_usbhs/mod_host.c | 1560 ------- ANDROID_3.4.5/drivers/usb/renesas_usbhs/pipe.c | 725 --- ANDROID_3.4.5/drivers/usb/renesas_usbhs/pipe.h | 115 - ANDROID_3.4.5/drivers/usb/serial/Kconfig | 682 --- ANDROID_3.4.5/drivers/usb/serial/Makefile | 65 - .../drivers/usb/serial/Makefile-keyspan_pda_fw | 16 - ANDROID_3.4.5/drivers/usb/serial/aircable.c | 207 - ANDROID_3.4.5/drivers/usb/serial/ark3116.c | 859 ---- ANDROID_3.4.5/drivers/usb/serial/belkin_sa.c | 535 --- ANDROID_3.4.5/drivers/usb/serial/belkin_sa.h | 124 - ANDROID_3.4.5/drivers/usb/serial/bus.c | 179 - ANDROID_3.4.5/drivers/usb/serial/ch341.c | 660 --- ANDROID_3.4.5/drivers/usb/serial/console.c | 317 -- ANDROID_3.4.5/drivers/usb/serial/cp210x.c | 913 ---- ANDROID_3.4.5/drivers/usb/serial/cyberjack.c | 486 -- ANDROID_3.4.5/drivers/usb/serial/cypress_m8.c | 1363 ------ ANDROID_3.4.5/drivers/usb/serial/cypress_m8.h | 70 - ANDROID_3.4.5/drivers/usb/serial/digi_acceleport.c | 1590 ------- ANDROID_3.4.5/drivers/usb/serial/empeg.c | 148 - ANDROID_3.4.5/drivers/usb/serial/ezusb.c | 61 - ANDROID_3.4.5/drivers/usb/serial/ezusb_convert.pl | 50 - ANDROID_3.4.5/drivers/usb/serial/f81232.c | 405 -- ANDROID_3.4.5/drivers/usb/serial/ftdi_sio.c | 2481 ----------- ANDROID_3.4.5/drivers/usb/serial/ftdi_sio.h | 564 --- ANDROID_3.4.5/drivers/usb/serial/ftdi_sio_ids.h | 1218 ----- ANDROID_3.4.5/drivers/usb/serial/funsoft.c | 52 - ANDROID_3.4.5/drivers/usb/serial/garmin_gps.c | 1528 ------- ANDROID_3.4.5/drivers/usb/serial/generic.c | 580 --- ANDROID_3.4.5/drivers/usb/serial/hp4x.c | 63 - ANDROID_3.4.5/drivers/usb/serial/io_16654.h | 195 - ANDROID_3.4.5/drivers/usb/serial/io_edgeport.c | 3195 ------------- ANDROID_3.4.5/drivers/usb/serial/io_edgeport.h | 134 - ANDROID_3.4.5/drivers/usb/serial/io_ionsp.h | 455 -- ANDROID_3.4.5/drivers/usb/serial/io_tables.h | 227 - ANDROID_3.4.5/drivers/usb/serial/io_ti.c | 2804 ------------ ANDROID_3.4.5/drivers/usb/serial/io_ti.h | 186 - ANDROID_3.4.5/drivers/usb/serial/io_usbvend.h | 683 --- ANDROID_3.4.5/drivers/usb/serial/ipaq.c | 670 --- ANDROID_3.4.5/drivers/usb/serial/ipw.c | 344 -- ANDROID_3.4.5/drivers/usb/serial/ir-usb.c | 476 -- ANDROID_3.4.5/drivers/usb/serial/iuu_phoenix.c | 1324 ------ ANDROID_3.4.5/drivers/usb/serial/iuu_phoenix.h | 122 - ANDROID_3.4.5/drivers/usb/serial/keyspan.c | 2616 ----------- ANDROID_3.4.5/drivers/usb/serial/keyspan.h | 623 --- ANDROID_3.4.5/drivers/usb/serial/keyspan_pda.c | 844 ---- .../drivers/usb/serial/keyspan_usa26msg.h | 260 -- .../drivers/usb/serial/keyspan_usa28msg.h | 201 - .../drivers/usb/serial/keyspan_usa49msg.h | 282 -- .../drivers/usb/serial/keyspan_usa67msg.h | 254 -- .../drivers/usb/serial/keyspan_usa90msg.h | 198 - ANDROID_3.4.5/drivers/usb/serial/kl5kusb105.c | 702 --- ANDROID_3.4.5/drivers/usb/serial/kl5kusb105.h | 68 - ANDROID_3.4.5/drivers/usb/serial/kobil_sct.c | 693 --- ANDROID_3.4.5/drivers/usb/serial/kobil_sct.h | 77 - ANDROID_3.4.5/drivers/usb/serial/mct_u232.c | 919 ---- ANDROID_3.4.5/drivers/usb/serial/mct_u232.h | 467 -- ANDROID_3.4.5/drivers/usb/serial/metro-usb.c | 394 -- ANDROID_3.4.5/drivers/usb/serial/mos7720.c | 2213 --------- ANDROID_3.4.5/drivers/usb/serial/mos7840.c | 2716 ----------- ANDROID_3.4.5/drivers/usb/serial/moto_modem.c | 55 - ANDROID_3.4.5/drivers/usb/serial/navman.c | 140 - ANDROID_3.4.5/drivers/usb/serial/omninet.c | 331 -- ANDROID_3.4.5/drivers/usb/serial/opticon.c | 640 --- ANDROID_3.4.5/drivers/usb/serial/option.c | 1556 ------- ANDROID_3.4.5/drivers/usb/serial/oti6858.c | 970 ---- ANDROID_3.4.5/drivers/usb/serial/oti6858.h | 15 - ANDROID_3.4.5/drivers/usb/serial/pl2303.c | 865 ---- ANDROID_3.4.5/drivers/usb/serial/pl2303.h | 151 - ANDROID_3.4.5/drivers/usb/serial/qcaux.c | 101 - ANDROID_3.4.5/drivers/usb/serial/qcserial.c | 301 -- ANDROID_3.4.5/drivers/usb/serial/safe_serial.c | 351 -- ANDROID_3.4.5/drivers/usb/serial/siemens_mpi.c | 56 - ANDROID_3.4.5/drivers/usb/serial/sierra.c | 1136 ----- ANDROID_3.4.5/drivers/usb/serial/spcp8x5.c | 676 --- ANDROID_3.4.5/drivers/usb/serial/ssu100.c | 704 --- ANDROID_3.4.5/drivers/usb/serial/symbolserial.c | 317 -- .../drivers/usb/serial/ti_usb_3410_5052.c | 1750 -------- .../drivers/usb/serial/ti_usb_3410_5052.h | 245 - ANDROID_3.4.5/drivers/usb/serial/usb-serial.c | 1455 ------ ANDROID_3.4.5/drivers/usb/serial/usb-wwan.h | 69 - ANDROID_3.4.5/drivers/usb/serial/usb_debug.c | 87 - ANDROID_3.4.5/drivers/usb/serial/usb_wwan.c | 774 ---- ANDROID_3.4.5/drivers/usb/serial/via_option.c | 1218 ----- ANDROID_3.4.5/drivers/usb/serial/via_usb-wwan.h | 88 - ANDROID_3.4.5/drivers/usb/serial/via_usb_wwan.c | 1013 ----- ANDROID_3.4.5/drivers/usb/serial/visor.c | 716 --- ANDROID_3.4.5/drivers/usb/serial/visor.h | 161 - ANDROID_3.4.5/drivers/usb/serial/vivopay-serial.c | 53 - ANDROID_3.4.5/drivers/usb/serial/whiteheat.c | 1470 ------ ANDROID_3.4.5/drivers/usb/serial/whiteheat.h | 302 -- ANDROID_3.4.5/drivers/usb/serial/zio.c | 46 - ANDROID_3.4.5/drivers/usb/storage/Kconfig | 229 - ANDROID_3.4.5/drivers/usb/storage/Makefile | 51 - ANDROID_3.4.5/drivers/usb/storage/alauda.c | 1282 ------ ANDROID_3.4.5/drivers/usb/storage/cypress_atacb.c | 278 -- ANDROID_3.4.5/drivers/usb/storage/datafab.c | 757 ---- ANDROID_3.4.5/drivers/usb/storage/debug.c | 177 - ANDROID_3.4.5/drivers/usb/storage/debug.h | 62 - ANDROID_3.4.5/drivers/usb/storage/ene_ub6250.c | 2413 ---------- ANDROID_3.4.5/drivers/usb/storage/freecom.c | 559 --- ANDROID_3.4.5/drivers/usb/storage/initializers.c | 106 - ANDROID_3.4.5/drivers/usb/storage/initializers.h | 50 - ANDROID_3.4.5/drivers/usb/storage/isd200.c | 1572 ------- ANDROID_3.4.5/drivers/usb/storage/jumpshot.c | 683 --- ANDROID_3.4.5/drivers/usb/storage/karma.c | 236 - ANDROID_3.4.5/drivers/usb/storage/libusual.c | 243 - ANDROID_3.4.5/drivers/usb/storage/onetouch.c | 318 -- ANDROID_3.4.5/drivers/usb/storage/option_ms.c | 170 - ANDROID_3.4.5/drivers/usb/storage/option_ms.h | 4 - ANDROID_3.4.5/drivers/usb/storage/protocol.c | 220 - ANDROID_3.4.5/drivers/usb/storage/protocol.h | 57 - ANDROID_3.4.5/drivers/usb/storage/realtek_cr.c | 1112 ----- ANDROID_3.4.5/drivers/usb/storage/scsiglue.c | 595 --- ANDROID_3.4.5/drivers/usb/storage/scsiglue.h | 48 - ANDROID_3.4.5/drivers/usb/storage/sddr09.c | 1793 -------- ANDROID_3.4.5/drivers/usb/storage/sddr55.c | 1012 ----- ANDROID_3.4.5/drivers/usb/storage/shuttle_usbat.c | 1869 -------- ANDROID_3.4.5/drivers/usb/storage/sierra_ms.c | 207 - ANDROID_3.4.5/drivers/usb/storage/sierra_ms.h | 4 - ANDROID_3.4.5/drivers/usb/storage/transport.c | 1353 ------ ANDROID_3.4.5/drivers/usb/storage/transport.h | 103 - ANDROID_3.4.5/drivers/usb/storage/uas.c | 862 ---- ANDROID_3.4.5/drivers/usb/storage/unusual_alauda.h | 31 - .../drivers/usb/storage/unusual_cypress.h | 39 - .../drivers/usb/storage/unusual_datafab.h | 98 - ANDROID_3.4.5/drivers/usb/storage/unusual_devs.h | 2050 --------- .../drivers/usb/storage/unusual_ene_ub6250.h | 26 - .../drivers/usb/storage/unusual_freecom.h | 26 - ANDROID_3.4.5/drivers/usb/storage/unusual_isd200.h | 57 - .../drivers/usb/storage/unusual_jumpshot.h | 27 - ANDROID_3.4.5/drivers/usb/storage/unusual_karma.h | 26 - .../drivers/usb/storage/unusual_onetouch.h | 36 - .../drivers/usb/storage/unusual_realtek.h | 41 - ANDROID_3.4.5/drivers/usb/storage/unusual_sddr09.h | 56 - ANDROID_3.4.5/drivers/usb/storage/unusual_sddr55.h | 44 - ANDROID_3.4.5/drivers/usb/storage/unusual_usbat.h | 43 - ANDROID_3.4.5/drivers/usb/storage/usb.c | 1127 ----- ANDROID_3.4.5/drivers/usb/storage/usb.h | 204 - ANDROID_3.4.5/drivers/usb/storage/usual-tables.c | 118 - ANDROID_3.4.5/drivers/usb/usb-common.c | 35 - ANDROID_3.4.5/drivers/usb/usb-skeleton.c | 679 --- ANDROID_3.4.5/drivers/usb/wusbcore/Kconfig | 42 - ANDROID_3.4.5/drivers/usb/wusbcore/Makefile | 25 - ANDROID_3.4.5/drivers/usb/wusbcore/cbaf.c | 662 --- ANDROID_3.4.5/drivers/usb/wusbcore/crypto.c | 518 --- ANDROID_3.4.5/drivers/usb/wusbcore/dev-sysfs.c | 139 - ANDROID_3.4.5/drivers/usb/wusbcore/devconnect.c | 1133 ----- ANDROID_3.4.5/drivers/usb/wusbcore/mmc.c | 287 -- ANDROID_3.4.5/drivers/usb/wusbcore/pal.c | 54 - ANDROID_3.4.5/drivers/usb/wusbcore/reservation.c | 118 - ANDROID_3.4.5/drivers/usb/wusbcore/rh.c | 452 -- ANDROID_3.4.5/drivers/usb/wusbcore/security.c | 577 --- ANDROID_3.4.5/drivers/usb/wusbcore/wa-hc.c | 97 - ANDROID_3.4.5/drivers/usb/wusbcore/wa-hc.h | 417 -- ANDROID_3.4.5/drivers/usb/wusbcore/wa-nep.c | 305 -- ANDROID_3.4.5/drivers/usb/wusbcore/wa-rpipe.c | 530 --- ANDROID_3.4.5/drivers/usb/wusbcore/wa-xfer.c | 1616 ------- ANDROID_3.4.5/drivers/usb/wusbcore/wusbhc.c | 450 -- ANDROID_3.4.5/drivers/usb/wusbcore/wusbhc.h | 496 --- 573 files changed, 400437 deletions(-) delete mode 100644 ANDROID_3.4.5/drivers/usb/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/usb/Makefile delete mode 100644 ANDROID_3.4.5/drivers/usb/README delete mode 100644 ANDROID_3.4.5/drivers/usb/atm/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/usb/atm/Makefile delete mode 100644 ANDROID_3.4.5/drivers/usb/atm/cxacru.c delete mode 100644 ANDROID_3.4.5/drivers/usb/atm/speedtch.c delete mode 100644 ANDROID_3.4.5/drivers/usb/atm/ueagle-atm.c delete mode 100644 ANDROID_3.4.5/drivers/usb/atm/usbatm.c delete mode 100644 ANDROID_3.4.5/drivers/usb/atm/usbatm.h delete mode 100644 ANDROID_3.4.5/drivers/usb/atm/xusbatm.c delete mode 100644 ANDROID_3.4.5/drivers/usb/c67x00/Makefile delete mode 100644 ANDROID_3.4.5/drivers/usb/c67x00/c67x00-drv.c delete mode 100644 ANDROID_3.4.5/drivers/usb/c67x00/c67x00-hcd.c delete mode 100644 ANDROID_3.4.5/drivers/usb/c67x00/c67x00-hcd.h delete mode 100644 ANDROID_3.4.5/drivers/usb/c67x00/c67x00-ll-hpi.c delete mode 100644 ANDROID_3.4.5/drivers/usb/c67x00/c67x00-sched.c delete mode 100644 ANDROID_3.4.5/drivers/usb/c67x00/c67x00.h delete mode 100644 ANDROID_3.4.5/drivers/usb/class/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/usb/class/Makefile delete mode 100644 ANDROID_3.4.5/drivers/usb/class/cdc-acm.c delete mode 100644 ANDROID_3.4.5/drivers/usb/class/cdc-acm.h delete mode 100644 ANDROID_3.4.5/drivers/usb/class/cdc-wdm.c delete mode 100644 ANDROID_3.4.5/drivers/usb/class/usblp.c delete mode 100644 ANDROID_3.4.5/drivers/usb/class/usbtmc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/core/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/usb/core/Makefile delete mode 100644 ANDROID_3.4.5/drivers/usb/core/buffer.c delete mode 100644 ANDROID_3.4.5/drivers/usb/core/config.c delete mode 100644 ANDROID_3.4.5/drivers/usb/core/devices.c delete mode 100644 ANDROID_3.4.5/drivers/usb/core/devio.c delete mode 100644 ANDROID_3.4.5/drivers/usb/core/driver.c delete mode 100644 ANDROID_3.4.5/drivers/usb/core/endpoint.c delete mode 100644 ANDROID_3.4.5/drivers/usb/core/file.c delete mode 100644 ANDROID_3.4.5/drivers/usb/core/generic.c delete mode 100644 ANDROID_3.4.5/drivers/usb/core/hcd-pci.c delete mode 100644 ANDROID_3.4.5/drivers/usb/core/hcd.c delete mode 100644 ANDROID_3.4.5/drivers/usb/core/hub.c delete mode 100644 ANDROID_3.4.5/drivers/usb/core/inode.c delete mode 100644 ANDROID_3.4.5/drivers/usb/core/message.c delete mode 100644 ANDROID_3.4.5/drivers/usb/core/notify.c delete mode 100644 ANDROID_3.4.5/drivers/usb/core/otg_whitelist.h delete mode 100644 ANDROID_3.4.5/drivers/usb/core/quirks.c delete mode 100644 ANDROID_3.4.5/drivers/usb/core/sysfs.c delete mode 100644 ANDROID_3.4.5/drivers/usb/core/urb.c delete mode 100644 ANDROID_3.4.5/drivers/usb/core/usb.c delete mode 100644 ANDROID_3.4.5/drivers/usb/core/usb.h delete mode 100644 ANDROID_3.4.5/drivers/usb/dwc3/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/usb/dwc3/Makefile delete mode 100644 ANDROID_3.4.5/drivers/usb/dwc3/core.c delete mode 100644 ANDROID_3.4.5/drivers/usb/dwc3/core.h delete mode 100644 ANDROID_3.4.5/drivers/usb/dwc3/debug.h delete mode 100644 ANDROID_3.4.5/drivers/usb/dwc3/debugfs.c delete mode 100644 ANDROID_3.4.5/drivers/usb/dwc3/dwc3-exynos.c delete mode 100644 ANDROID_3.4.5/drivers/usb/dwc3/dwc3-omap.c delete mode 100644 ANDROID_3.4.5/drivers/usb/dwc3/dwc3-pci.c delete mode 100644 ANDROID_3.4.5/drivers/usb/dwc3/ep0.c delete mode 100644 ANDROID_3.4.5/drivers/usb/dwc3/gadget.c delete mode 100644 ANDROID_3.4.5/drivers/usb/dwc3/gadget.h delete mode 100644 ANDROID_3.4.5/drivers/usb/dwc3/host.c delete mode 100644 ANDROID_3.4.5/drivers/usb/dwc3/io.h delete mode 100644 ANDROID_3.4.5/drivers/usb/early/Makefile delete mode 100644 ANDROID_3.4.5/drivers/usb/early/ehci-dbgp.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/Makefile delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/acm_ms.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/amd5536udc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/amd5536udc.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/android.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/at91_udc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/at91_udc.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/atmel_usba_udc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/atmel_usba_udc.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/audio.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/cdc2.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/ci13xxx_msm.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/ci13xxx_pci.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/ci13xxx_udc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/ci13xxx_udc.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/composite.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/config.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/dbgp.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/dummy_hcd.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/epautoconf.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/ether.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/f_accessory.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/f_acm.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/f_adb.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/f_audio_source.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/f_ecm.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/f_eem.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/f_fs.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/f_hid.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/f_loopback.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/f_mass_storage.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/f_midi.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/f_mtp.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/f_ncm.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/f_obex.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/f_phonet.c delete mode 100755 ANDROID_3.4.5/drivers/usb/gadget/f_rawbulk.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/f_rndis.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/f_serial.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/f_sourcesink.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/f_subset.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/f_uac1.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/f_uac2.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/f_uvc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/f_uvc.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/file_storage.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/fsl_mxc_udc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/fsl_qe_udc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/fsl_qe_udc.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/fsl_udc_core.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/fsl_usb2_udc.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/fusb300_udc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/fusb300_udc.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/g_ffs.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/g_zero.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/gadget_chips.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/gmidi.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/goku_udc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/goku_udc.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/hid.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/imx_udc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/imx_udc.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/inode.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/langwell_udc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/langwell_udc.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/m66592-udc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/m66592-udc.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/mass_storage.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/multi.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/mv_udc.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/mv_udc_core.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/ncm.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/ndis.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/net2272.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/net2272.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/net2280.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/net2280.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/nokia.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/omap_udc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/omap_udc.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/pch_udc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/printer.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/pxa25x_udc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/pxa25x_udc.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/pxa27x_udc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/pxa27x_udc.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/r8a66597-udc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/r8a66597-udc.h delete mode 100755 ANDROID_3.4.5/drivers/usb/gadget/rawbulk.c delete mode 100755 ANDROID_3.4.5/drivers/usb/gadget/rawbulk_transfer.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/rndis.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/rndis.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/s3c-hsotg.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/s3c-hsudc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/s3c2410_udc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/s3c2410_udc.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/serial.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/storage_common.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/u_ether.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/u_ether.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/u_phonet.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/u_serial.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/u_serial.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/u_uac1.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/u_uac1.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/udc-core.c delete mode 100755 ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.c delete mode 100755 ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/usbstring.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/uvc.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/uvc_queue.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/uvc_queue.h delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/uvc_v4l2.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/uvc_video.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/webcam.c delete mode 100644 ANDROID_3.4.5/drivers/usb/gadget/zero.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/usb/host/Makefile delete mode 100644 ANDROID_3.4.5/drivers/usb/host/alchemy-common.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-atmel.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-au1xxx.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-cns3xxx.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-dbg.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-fsl.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-fsl.h delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-grlib.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-hcd.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-hub.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-ixp4xx.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-lpm.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-ls1x.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-mem.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-msm.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-mv.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-mxc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-octeon.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-omap.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-orion.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-pci.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-platform.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-pmcmsp.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-ppc-of.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-ps3.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-q.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-s5p.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-sched.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-sh.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-spear.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-sysfs.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-tegra.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-vt8500.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-w90x900.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-xilinx-of.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci-xls.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ehci.h delete mode 100644 ANDROID_3.4.5/drivers/usb/host/fhci-dbg.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/fhci-hcd.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/fhci-hub.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/fhci-mem.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/fhci-q.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/fhci-sched.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/fhci-tds.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/fhci.h delete mode 100644 ANDROID_3.4.5/drivers/usb/host/fsl-mph-dr-of.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/hwa-hc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/imx21-dbg.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/imx21-hcd.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/imx21-hcd.h delete mode 100644 ANDROID_3.4.5/drivers/usb/host/isp116x-hcd.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/isp116x.h delete mode 100644 ANDROID_3.4.5/drivers/usb/host/isp1362-hcd.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/isp1362.h delete mode 100644 ANDROID_3.4.5/drivers/usb/host/isp1760-hcd.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/isp1760-hcd.h delete mode 100644 ANDROID_3.4.5/drivers/usb/host/isp1760-if.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/octeon2-common.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-at91.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-au1xxx.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-cns3xxx.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-da8xx.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-dbg.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-ep93xx.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-exynos.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-hcd.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-hub.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-jz4740.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-mem.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-nxp.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-octeon.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-omap.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-omap3.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-pci.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-platform.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-pnx8550.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-ppc-of.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-ppc-soc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-ps3.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-pxa27x.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-q.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-s3c2410.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-sa1111.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-sh.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-sm501.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-spear.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-ssb.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-tmio.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci-xls.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/ohci.h delete mode 100644 ANDROID_3.4.5/drivers/usb/host/oxu210hp-hcd.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/oxu210hp.h delete mode 100644 ANDROID_3.4.5/drivers/usb/host/pci-quirks.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/pci-quirks.h delete mode 100644 ANDROID_3.4.5/drivers/usb/host/r8a66597-hcd.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/r8a66597.h delete mode 100644 ANDROID_3.4.5/drivers/usb/host/sl811-hcd.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/sl811.h delete mode 100644 ANDROID_3.4.5/drivers/usb/host/sl811_cs.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/u132-hcd.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/uhci-debug.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/uhci-grlib.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/uhci-hcd.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/uhci-hcd.h delete mode 100644 ANDROID_3.4.5/drivers/usb/host/uhci-hub.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/uhci-pci.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/uhci-q.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/whci/Kbuild delete mode 100644 ANDROID_3.4.5/drivers/usb/host/whci/asl.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/whci/debug.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/whci/hcd.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/whci/hw.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/whci/init.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/whci/int.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/whci/pzl.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/whci/qset.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/whci/whcd.h delete mode 100644 ANDROID_3.4.5/drivers/usb/host/whci/whci-hc.h delete mode 100644 ANDROID_3.4.5/drivers/usb/host/whci/wusb.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/xhci-dbg.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/xhci-ext-caps.h delete mode 100644 ANDROID_3.4.5/drivers/usb/host/xhci-hub.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/xhci-mem.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/xhci-pci.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/xhci-plat.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/xhci-ring.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/xhci.c delete mode 100644 ANDROID_3.4.5/drivers/usb/host/xhci.h delete mode 100644 ANDROID_3.4.5/drivers/usb/image/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/usb/image/Makefile delete mode 100644 ANDROID_3.4.5/drivers/usb/image/mdc800.c delete mode 100644 ANDROID_3.4.5/drivers/usb/image/microtek.c delete mode 100644 ANDROID_3.4.5/drivers/usb/image/microtek.h delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/Makefile delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/adutux.c delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/appledisplay.c delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/cypress_cy7c63.c delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/cytherm.c delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/emi26.c delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/emi62.c delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/ftdi-elan.c delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/idmouse.c delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/iowarrior.c delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/isight_firmware.c delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/ldusb.c delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/legousbtower.c delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/rio500.c delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/rio500_usb.h delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/sisusbvga/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/sisusbvga/Makefile delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb.c delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb.h delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb_con.c delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb_init.c delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb_init.h delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb_struct.h delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/trancevibrator.c delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/usb_u132.h delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/usblcd.c delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/usbled.c delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/usbsevseg.c delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/usbtest.c delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/uss720.c delete mode 100644 ANDROID_3.4.5/drivers/usb/misc/yurex.c delete mode 100644 ANDROID_3.4.5/drivers/usb/mon/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/usb/mon/Makefile delete mode 100644 ANDROID_3.4.5/drivers/usb/mon/mon_bin.c delete mode 100644 ANDROID_3.4.5/drivers/usb/mon/mon_main.c delete mode 100644 ANDROID_3.4.5/drivers/usb/mon/mon_stat.c delete mode 100644 ANDROID_3.4.5/drivers/usb/mon/mon_text.c delete mode 100644 ANDROID_3.4.5/drivers/usb/mon/usb_mon.h delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/Makefile delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/am35x.c delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/blackfin.c delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/blackfin.h delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/cppi_dma.c delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/cppi_dma.h delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/da8xx.c delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/davinci.c delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/davinci.h delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/musb_core.c delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/musb_core.h delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/musb_debug.h delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/musb_debugfs.c delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/musb_dma.h delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/musb_gadget.c delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/musb_gadget.h delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/musb_gadget_ep0.c delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/musb_host.c delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/musb_host.h delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/musb_io.h delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/musb_regs.h delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/musb_virthub.c delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/musbhsdma.c delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/musbhsdma.h delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/omap2430.c delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/omap2430.h delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/tusb6010.c delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/tusb6010.h delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/tusb6010_omap.c delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/ux500.c delete mode 100644 ANDROID_3.4.5/drivers/usb/musb/ux500_dma.c delete mode 100644 ANDROID_3.4.5/drivers/usb/otg/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/usb/otg/Makefile delete mode 100644 ANDROID_3.4.5/drivers/usb/otg/ab8500-usb.c delete mode 100644 ANDROID_3.4.5/drivers/usb/otg/fsl_otg.c delete mode 100644 ANDROID_3.4.5/drivers/usb/otg/fsl_otg.h delete mode 100644 ANDROID_3.4.5/drivers/usb/otg/gpio_vbus.c delete mode 100644 ANDROID_3.4.5/drivers/usb/otg/isp1301_omap.c delete mode 100644 ANDROID_3.4.5/drivers/usb/otg/msm_otg.c delete mode 100644 ANDROID_3.4.5/drivers/usb/otg/mv_otg.c delete mode 100644 ANDROID_3.4.5/drivers/usb/otg/mv_otg.h delete mode 100644 ANDROID_3.4.5/drivers/usb/otg/nop-usb-xceiv.c delete mode 100644 ANDROID_3.4.5/drivers/usb/otg/otg-wakelock.c delete mode 100644 ANDROID_3.4.5/drivers/usb/otg/otg.c delete mode 100644 ANDROID_3.4.5/drivers/usb/otg/otg_fsm.c delete mode 100644 ANDROID_3.4.5/drivers/usb/otg/otg_fsm.h delete mode 100644 ANDROID_3.4.5/drivers/usb/otg/twl4030-usb.c delete mode 100644 ANDROID_3.4.5/drivers/usb/otg/twl6030-usb.c delete mode 100644 ANDROID_3.4.5/drivers/usb/otg/ulpi.c delete mode 100644 ANDROID_3.4.5/drivers/usb/otg/ulpi_viewport.c delete mode 100644 ANDROID_3.4.5/drivers/usb/renesas_usbhs/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/usb/renesas_usbhs/Makefile delete mode 100644 ANDROID_3.4.5/drivers/usb/renesas_usbhs/common.c delete mode 100644 ANDROID_3.4.5/drivers/usb/renesas_usbhs/common.h delete mode 100644 ANDROID_3.4.5/drivers/usb/renesas_usbhs/fifo.c delete mode 100644 ANDROID_3.4.5/drivers/usb/renesas_usbhs/fifo.h delete mode 100644 ANDROID_3.4.5/drivers/usb/renesas_usbhs/mod.c delete mode 100644 ANDROID_3.4.5/drivers/usb/renesas_usbhs/mod.h delete mode 100644 ANDROID_3.4.5/drivers/usb/renesas_usbhs/mod_gadget.c delete mode 100644 ANDROID_3.4.5/drivers/usb/renesas_usbhs/mod_host.c delete mode 100644 ANDROID_3.4.5/drivers/usb/renesas_usbhs/pipe.c delete mode 100644 ANDROID_3.4.5/drivers/usb/renesas_usbhs/pipe.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/Makefile delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/Makefile-keyspan_pda_fw delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/aircable.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/ark3116.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/belkin_sa.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/belkin_sa.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/bus.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/ch341.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/console.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/cp210x.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/cyberjack.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/cypress_m8.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/cypress_m8.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/digi_acceleport.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/empeg.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/ezusb.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/ezusb_convert.pl delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/f81232.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/ftdi_sio.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/ftdi_sio.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/ftdi_sio_ids.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/funsoft.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/garmin_gps.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/generic.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/hp4x.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/io_16654.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/io_edgeport.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/io_edgeport.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/io_ionsp.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/io_tables.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/io_ti.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/io_ti.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/io_usbvend.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/ipaq.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/ipw.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/ir-usb.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/iuu_phoenix.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/iuu_phoenix.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/keyspan.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/keyspan.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/keyspan_pda.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/keyspan_usa26msg.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/keyspan_usa28msg.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/keyspan_usa49msg.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/keyspan_usa67msg.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/keyspan_usa90msg.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/kl5kusb105.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/kl5kusb105.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/kobil_sct.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/kobil_sct.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/mct_u232.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/mct_u232.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/metro-usb.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/mos7720.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/mos7840.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/moto_modem.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/navman.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/omninet.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/opticon.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/option.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/oti6858.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/oti6858.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/pl2303.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/pl2303.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/qcaux.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/qcserial.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/safe_serial.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/siemens_mpi.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/sierra.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/spcp8x5.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/ssu100.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/symbolserial.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/ti_usb_3410_5052.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/ti_usb_3410_5052.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/usb-serial.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/usb-wwan.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/usb_debug.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/usb_wwan.c delete mode 100755 ANDROID_3.4.5/drivers/usb/serial/via_option.c delete mode 100755 ANDROID_3.4.5/drivers/usb/serial/via_usb-wwan.h delete mode 100755 ANDROID_3.4.5/drivers/usb/serial/via_usb_wwan.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/visor.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/visor.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/vivopay-serial.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/whiteheat.c delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/whiteheat.h delete mode 100644 ANDROID_3.4.5/drivers/usb/serial/zio.c delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/Makefile delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/alauda.c delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/cypress_atacb.c delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/datafab.c delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/debug.c delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/debug.h delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/ene_ub6250.c delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/freecom.c delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/initializers.c delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/initializers.h delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/isd200.c delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/jumpshot.c delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/karma.c delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/libusual.c delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/onetouch.c delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/option_ms.c delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/option_ms.h delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/protocol.c delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/protocol.h delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/realtek_cr.c delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/scsiglue.c delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/scsiglue.h delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/sddr09.c delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/sddr55.c delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/shuttle_usbat.c delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/sierra_ms.c delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/sierra_ms.h delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/transport.c delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/transport.h delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/uas.c delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/unusual_alauda.h delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/unusual_cypress.h delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/unusual_datafab.h delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/unusual_devs.h delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/unusual_ene_ub6250.h delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/unusual_freecom.h delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/unusual_isd200.h delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/unusual_jumpshot.h delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/unusual_karma.h delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/unusual_onetouch.h delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/unusual_realtek.h delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/unusual_sddr09.h delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/unusual_sddr55.h delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/unusual_usbat.h delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/usb.c delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/usb.h delete mode 100644 ANDROID_3.4.5/drivers/usb/storage/usual-tables.c delete mode 100644 ANDROID_3.4.5/drivers/usb/usb-common.c delete mode 100644 ANDROID_3.4.5/drivers/usb/usb-skeleton.c delete mode 100644 ANDROID_3.4.5/drivers/usb/wusbcore/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/usb/wusbcore/Makefile delete mode 100644 ANDROID_3.4.5/drivers/usb/wusbcore/cbaf.c delete mode 100644 ANDROID_3.4.5/drivers/usb/wusbcore/crypto.c delete mode 100644 ANDROID_3.4.5/drivers/usb/wusbcore/dev-sysfs.c delete mode 100644 ANDROID_3.4.5/drivers/usb/wusbcore/devconnect.c delete mode 100644 ANDROID_3.4.5/drivers/usb/wusbcore/mmc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/wusbcore/pal.c delete mode 100644 ANDROID_3.4.5/drivers/usb/wusbcore/reservation.c delete mode 100644 ANDROID_3.4.5/drivers/usb/wusbcore/rh.c delete mode 100644 ANDROID_3.4.5/drivers/usb/wusbcore/security.c delete mode 100644 ANDROID_3.4.5/drivers/usb/wusbcore/wa-hc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/wusbcore/wa-hc.h delete mode 100644 ANDROID_3.4.5/drivers/usb/wusbcore/wa-nep.c delete mode 100644 ANDROID_3.4.5/drivers/usb/wusbcore/wa-rpipe.c delete mode 100644 ANDROID_3.4.5/drivers/usb/wusbcore/wa-xfer.c delete mode 100644 ANDROID_3.4.5/drivers/usb/wusbcore/wusbhc.c delete mode 100644 ANDROID_3.4.5/drivers/usb/wusbcore/wusbhc.h (limited to 'ANDROID_3.4.5/drivers/usb') diff --git a/ANDROID_3.4.5/drivers/usb/Kconfig b/ANDROID_3.4.5/drivers/usb/Kconfig deleted file mode 100644 index 76316a33..00000000 --- a/ANDROID_3.4.5/drivers/usb/Kconfig +++ /dev/null @@ -1,186 +0,0 @@ -# -# USB device configuration -# - -# many non-PCI SOC chips embed OHCI -config USB_ARCH_HAS_OHCI - boolean - # ARM: - default y if SA1111 - default y if ARCH_OMAP - default y if ARCH_S3C24XX - default y if PXA27x - default y if PXA3xx - default y if ARCH_EP93XX - default y if ARCH_AT91 - default y if ARCH_PNX4008 && I2C - default y if MFD_TC6393XB - default y if ARCH_W90X900 - default y if ARCH_DAVINCI_DA8XX - default y if ARCH_CNS3XXX - default y if PLAT_SPEAR - default y if ARCH_EXYNOS - # PPC: - default y if STB03xxx - default y if PPC_MPC52xx - # MIPS: - default y if MIPS_ALCHEMY - default y if MACH_JZ4740 - # more: - default PCI - -# some non-PCI hcds implement EHCI -config USB_ARCH_HAS_EHCI - boolean - default y if FSL_SOC - default y if PPC_MPC512x - default y if ARCH_IXP4XX - default y if ARCH_W90X900 - default y if ARCH_AT91 - default y if ARCH_MXC - default y if ARCH_OMAP3 - default y if ARCH_CNS3XXX - default y if ARCH_VT8500 - default y if PLAT_SPEAR - default y if PLAT_S5P - default y if ARCH_MSM - default y if MICROBLAZE - default y if SPARC_LEON - default y if ARCH_MMP - default y if MACH_LOONGSON1 - default PCI - -# some non-PCI HCDs implement xHCI -config USB_ARCH_HAS_XHCI - boolean - default PCI - -menuconfig USB_SUPPORT - bool "USB support" - depends on HAS_IOMEM - default y - ---help--- - This option adds core support for Universal Serial Bus (USB). - You will also need drivers from the following menu to make use of it. - -if USB_SUPPORT - -config USB_COMMON - tristate - default y - depends on USB || USB_GADGET - -# Host-side USB depends on having a host controller -# NOTE: dummy_hcd is always an option, but it's ignored here ... -# NOTE: SL-811 option should be board-specific ... -config USB_ARCH_HAS_HCD - boolean - default y if USB_ARCH_HAS_OHCI - default y if USB_ARCH_HAS_EHCI - default y if USB_ARCH_HAS_XHCI - default y if PCMCIA && !M32R # sl811_cs - default y if ARM # SL-811 - default y if BLACKFIN # SL-811 - default y if SUPERH # r8a66597-hcd - default PCI - -# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface. -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 - traditional PC serial port. The bus supplies power to peripherals - and allows for hot swapping. Up to 127 USB peripherals can be - connected to a single USB host in a tree structure. - - The USB host is the root of the tree, the peripherals are the - leaves and the inner nodes are special USB devices called hubs. - Most PCs now have USB host ports, used to connect peripherals - such as scanners, keyboards, mice, modems, cameras, disks, - flash memory, network links, and printers to the PC. - - Say Y here if your computer has a host-side USB port and you want - to use USB devices. You then need to say Y to at least one of the - Host Controller Driver (HCD) options below. Choose a USB 1.1 - controller, such as "UHCI HCD support" or "OHCI HCD support", - and "EHCI HCD (USB 2.0) support" except for older systems that - do not have USB 2.0 support. It doesn't normally hurt to select - them all if you are not certain. - - If your system has a device-side USB port, used in the peripheral - side of the USB protocol, see the "USB Gadget" framework instead. - - After choosing your HCD, then select drivers for the USB peripherals - you'll be using. You may want to check out the information provided - in and especially the links given in - . - - To compile this driver as a module, choose M here: the - module will be called usbcore. - -source "drivers/usb/core/Kconfig" - -source "drivers/usb/dwc3/Kconfig" - -source "drivers/usb/mon/Kconfig" - -source "drivers/usb/wusbcore/Kconfig" - -source "drivers/usb/host/Kconfig" - -source "drivers/usb/musb/Kconfig" - -source "drivers/usb/renesas_usbhs/Kconfig" - -source "drivers/usb/class/Kconfig" - -source "drivers/usb/storage/Kconfig" - -source "drivers/usb/image/Kconfig" - -comment "USB port drivers" - depends on USB - -config USB_USS720 - tristate "USS720 parport driver" - depends on USB && PARPORT - select PARPORT_NOT_PC - ---help--- - This driver is for USB parallel port adapters that use the Lucent - Technologies USS-720 chip. These cables are plugged into your USB - port and provide USB compatibility to peripherals designed with - parallel port interfaces. - - The chip has two modes: automatic mode and manual mode. In automatic - mode, it looks to the computer like a standard USB printer. Only - printers may be connected to the USS-720 in this mode. The generic - USB printer driver ("USB Printer support", above) may be used in - that mode, and you can say N here if you want to use the chip only - in this mode. - - Manual mode is not limited to printers, any parallel port - device should work. This driver utilizes manual mode. - Note however that some operations are three orders of magnitude - slower than on a PCI/ISA Parallel Port, so timing critical - applications might not work. - - Say Y here if you own an USS-720 USB->Parport cable and intend to - connect anything other than a printer to it. - - To compile this driver as a module, choose M here: the - module will be called uss720. - -source "drivers/usb/serial/Kconfig" - -source "drivers/usb/misc/Kconfig" - -source "drivers/usb/atm/Kconfig" - -source "drivers/usb/gadget/Kconfig" - -source "drivers/usb/otg/Kconfig" - -endif # USB_SUPPORT diff --git a/ANDROID_3.4.5/drivers/usb/Makefile b/ANDROID_3.4.5/drivers/usb/Makefile deleted file mode 100644 index 53a7bc07..00000000 --- a/ANDROID_3.4.5/drivers/usb/Makefile +++ /dev/null @@ -1,58 +0,0 @@ -# -# Makefile for the kernel USB device drivers. -# - -# Object files in subdirectories - -obj-$(CONFIG_USB) += core/ - -obj-$(CONFIG_USB_OTG_UTILS) += otg/ - -obj-$(CONFIG_USB_DWC3) += dwc3/ - -obj-$(CONFIG_USB_MON) += mon/ - -obj-$(CONFIG_PCI) += host/ -obj-$(CONFIG_USB_EHCI_HCD) += host/ -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_ISP1362_HCD) += host/ -obj-$(CONFIG_USB_U132_HCD) += host/ -obj-$(CONFIG_USB_R8A66597_HCD) += host/ -obj-$(CONFIG_USB_HWA_HCD) += host/ -obj-$(CONFIG_USB_ISP1760_HCD) += host/ -obj-$(CONFIG_USB_IMX21_HCD) += host/ -obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/ - -obj-$(CONFIG_USB_C67X00_HCD) += c67x00/ - -obj-$(CONFIG_USB_WUSB) += wusbcore/ - -obj-$(CONFIG_USB_ACM) += class/ -obj-$(CONFIG_USB_PRINTER) += class/ -obj-$(CONFIG_USB_WDM) += class/ -obj-$(CONFIG_USB_TMC) += class/ - -obj-$(CONFIG_USB_STORAGE) += storage/ -obj-$(CONFIG_USB) += storage/ - -obj-$(CONFIG_USB_MDC800) += image/ -obj-$(CONFIG_USB_MICROTEK) += image/ - -obj-$(CONFIG_USB_SERIAL) += serial/ - -obj-$(CONFIG_USB) += misc/ -obj-$(CONFIG_EARLY_PRINTK_DBGP) += early/ - -obj-$(CONFIG_USB_ATM) += atm/ -obj-$(CONFIG_USB_SPEEDTOUCH) += atm/ - -obj-$(CONFIG_USB_MUSB_HDRC) += musb/ -obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs/ -obj-$(CONFIG_USB_GADGET) += gadget/ - -obj-$(CONFIG_USB_COMMON) += usb-common.o diff --git a/ANDROID_3.4.5/drivers/usb/README b/ANDROID_3.4.5/drivers/usb/README deleted file mode 100644 index 284f46b3..00000000 --- a/ANDROID_3.4.5/drivers/usb/README +++ /dev/null @@ -1,54 +0,0 @@ -To understand all the Linux-USB framework, you'll use these resources: - - * This source code. This is necessarily an evolving work, and - includes kerneldoc that should help you get a current overview. - ("make pdfdocs", and then look at "usb.pdf" for host side and - "gadget.pdf" for peripheral side.) Also, Documentation/usb has - more information. - - * The USB 2.0 specification (from www.usb.org), with supplements - such as those for USB OTG and the various device classes. - The USB specification has a good overview chapter, and USB - peripherals conform to the widely known "Chapter 9". - - * Chip specifications for USB controllers. Examples include - host controllers (on PCs, servers, and more); peripheral - controllers (in devices with Linux firmware, like printers or - cell phones); and hard-wired peripherals like Ethernet adapters. - - * Specifications for other protocols implemented by USB peripheral - functions. Some are vendor-specific; others are vendor-neutral - but just standardized outside of the www.usb.org team. - -Here is a list of what each subdirectory here is, and what is contained in -them. - -core/ - This is for the core USB host code, including the - usbfs files and the hub class driver ("khubd"). - -host/ - This is for USB host controller drivers. This - includes UHCI, OHCI, EHCI, and others that might - be used with more specialized "embedded" systems. - -gadget/ - This is for USB peripheral controller drivers and - the various gadget drivers which talk to them. - - -Individual USB driver directories. A new driver should be added to the -first subdirectory in the list below that it fits into. - -image/ - This is for still image drivers, like scanners or - digital cameras. -../input/ - This is for any driver that uses the input subsystem, - like keyboard, mice, touchscreens, tablets, etc. -../media/ - This is for multimedia drivers, like video cameras, - radios, and any other drivers that talk to the v4l - subsystem. -../net/ - This is for network drivers. -serial/ - This is for USB to serial drivers. -storage/ - This is for USB mass-storage drivers. -class/ - This is for all USB device drivers that do not fit - into any of the above categories, and work for a range - of USB Class specified devices. -misc/ - This is for all USB device drivers that do not fit - into any of the above categories. diff --git a/ANDROID_3.4.5/drivers/usb/atm/Kconfig b/ANDROID_3.4.5/drivers/usb/atm/Kconfig deleted file mode 100644 index be0b8daa..00000000 --- a/ANDROID_3.4.5/drivers/usb/atm/Kconfig +++ /dev/null @@ -1,68 +0,0 @@ -# -# USB/ATM DSL configuration -# - -menuconfig USB_ATM - tristate "USB DSL modem support" - depends on USB && ATM - select CRC32 - default n - help - Say Y here if you want to connect a USB Digital Subscriber Line (DSL) - modem to your computer's USB port. You will then need to choose your - modem from the list below. - - To compile this driver as a module, choose M here: the - module will be called usbatm. - -if USB_ATM - -config USB_SPEEDTOUCH - tristate "Speedtouch USB support" - select FW_LOADER - help - Say Y here if you have an SpeedTouch USB or SpeedTouch 330 - modem. In order to use your modem you will need to install the - two parts of the firmware, extracted by the user space tools; see - for details. - - To compile this driver as a module, choose M here: the - module will be called speedtch. - -config USB_CXACRU - tristate "Conexant AccessRunner USB support" - select FW_LOADER - help - Say Y here if you have an ADSL USB modem based on the Conexant - AccessRunner chipset. In order to use your modem you will need to - install the firmware, extracted by the user space tools; see - for details. - - To compile this driver as a module, choose M here: the - module will be called cxacru. - -config USB_UEAGLEATM - tristate "ADI 930 and eagle USB DSL modem" - select FW_LOADER - help - Say Y here if you have an ADSL USB modem based on the ADI 930 - or eagle chipset. In order to use your modem you will need to - install firmwares and CMV (Command Management Variables); see - for details. - - To compile this driver as a module, choose M here: the - module will be called ueagle-atm. - -config USB_XUSBATM - tristate "Other USB DSL modem support" - help - Say Y here if you have a DSL USB modem not explicitly supported by - another USB DSL drivers. In order to use your modem you will need to - pass the vendor ID, product ID, and endpoint numbers for transmission - and reception as module parameters. You may need to initialize - the modem using a user space utility (a firmware loader for example). - - To compile this driver as a module, choose M here: the - module will be called xusbatm. - -endif # USB_ATM diff --git a/ANDROID_3.4.5/drivers/usb/atm/Makefile b/ANDROID_3.4.5/drivers/usb/atm/Makefile deleted file mode 100644 index a5d792ec..00000000 --- a/ANDROID_3.4.5/drivers/usb/atm/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# -# Makefile for USB ATM/xDSL drivers -# - -ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG - -obj-$(CONFIG_USB_CXACRU) += cxacru.o -obj-$(CONFIG_USB_SPEEDTOUCH) += speedtch.o -obj-$(CONFIG_USB_UEAGLEATM) += ueagle-atm.o -obj-$(CONFIG_USB_ATM) += usbatm.o -obj-$(CONFIG_USB_XUSBATM) += xusbatm.o diff --git a/ANDROID_3.4.5/drivers/usb/atm/cxacru.c b/ANDROID_3.4.5/drivers/usb/atm/cxacru.c deleted file mode 100644 index 98b89fe1..00000000 --- a/ANDROID_3.4.5/drivers/usb/atm/cxacru.c +++ /dev/null @@ -1,1380 +0,0 @@ -/****************************************************************************** - * cxacru.c - driver for USB ADSL modems based on - * Conexant AccessRunner chipset - * - * Copyright (C) 2004 David Woodhouse, Duncan Sands, Roman Kagan - * Copyright (C) 2005 Duncan Sands, Roman Kagan (rkagan % mail ! ru) - * Copyright (C) 2007 Simon Arlott - * Copyright (C) 2009 Simon Arlott - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - ******************************************************************************/ - -/* - * Credit is due for Josep Comas, who created the original patch to speedtch.c - * to support the different padding used by the AccessRunner (now generalized - * into usbatm), and the userspace firmware loading utility. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "usbatm.h" - -#define DRIVER_AUTHOR "Roman Kagan, David Woodhouse, Duncan Sands, Simon Arlott" -#define DRIVER_VERSION "0.4" -#define DRIVER_DESC "Conexant AccessRunner ADSL USB modem driver" - -static const char cxacru_driver_name[] = "cxacru"; - -#define CXACRU_EP_CMD 0x01 /* Bulk/interrupt in/out */ -#define CXACRU_EP_DATA 0x02 /* Bulk in/out */ - -#define CMD_PACKET_SIZE 64 /* Should be maxpacket(ep)? */ -#define CMD_MAX_CONFIG ((CMD_PACKET_SIZE / 4 - 1) / 2) - -/* Addresses */ -#define PLLFCLK_ADDR 0x00350068 -#define PLLBCLK_ADDR 0x0035006c -#define SDRAMEN_ADDR 0x00350010 -#define FW_ADDR 0x00801000 -#define BR_ADDR 0x00180600 -#define SIG_ADDR 0x00180500 -#define BR_STACK_ADDR 0x00187f10 - -/* Values */ -#define SDRAM_ENA 0x1 - -#define CMD_TIMEOUT 2000 /* msecs */ -#define POLL_INTERVAL 1 /* secs */ - -/* commands for interaction with the modem through the control channel before - * firmware is loaded */ -enum cxacru_fw_request { - FW_CMD_ERR, - FW_GET_VER, - FW_READ_MEM, - FW_WRITE_MEM, - FW_RMW_MEM, - FW_CHECKSUM_MEM, - FW_GOTO_MEM, -}; - -/* commands for interaction with the modem through the control channel once - * firmware is loaded */ -enum cxacru_cm_request { - CM_REQUEST_UNDEFINED = 0x80, - CM_REQUEST_TEST, - CM_REQUEST_CHIP_GET_MAC_ADDRESS, - CM_REQUEST_CHIP_GET_DP_VERSIONS, - CM_REQUEST_CHIP_ADSL_LINE_START, - CM_REQUEST_CHIP_ADSL_LINE_STOP, - CM_REQUEST_CHIP_ADSL_LINE_GET_STATUS, - CM_REQUEST_CHIP_ADSL_LINE_GET_SPEED, - CM_REQUEST_CARD_INFO_GET, - CM_REQUEST_CARD_DATA_GET, - CM_REQUEST_CARD_DATA_SET, - CM_REQUEST_COMMAND_HW_IO, - CM_REQUEST_INTERFACE_HW_IO, - CM_REQUEST_CARD_SERIAL_DATA_PATH_GET, - CM_REQUEST_CARD_SERIAL_DATA_PATH_SET, - CM_REQUEST_CARD_CONTROLLER_VERSION_GET, - CM_REQUEST_CARD_GET_STATUS, - CM_REQUEST_CARD_GET_MAC_ADDRESS, - CM_REQUEST_CARD_GET_DATA_LINK_STATUS, - CM_REQUEST_MAX, -}; - -/* commands for interaction with the flash memory - * - * read: response is the contents of the first 60 bytes of flash memory - * write: request contains the 60 bytes of data to write to flash memory - * response is the contents of the first 60 bytes of flash memory - * - * layout: PP PP VV VV MM MM MM MM MM MM ?? ?? SS SS SS SS SS SS SS SS - * SS SS SS SS SS SS SS SS 00 00 00 00 00 00 00 00 00 00 00 00 - * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - * - * P: le16 USB Product ID - * V: le16 USB Vendor ID - * M: be48 MAC Address - * S: le16 ASCII Serial Number - */ -enum cxacru_cm_flash { - CM_FLASH_READ = 0xa1, - CM_FLASH_WRITE = 0xa2 -}; - -/* reply codes to the commands above */ -enum cxacru_cm_status { - CM_STATUS_UNDEFINED, - CM_STATUS_SUCCESS, - CM_STATUS_ERROR, - CM_STATUS_UNSUPPORTED, - CM_STATUS_UNIMPLEMENTED, - CM_STATUS_PARAMETER_ERROR, - CM_STATUS_DBG_LOOPBACK, - CM_STATUS_MAX, -}; - -/* indices into CARD_INFO_GET return array */ -enum cxacru_info_idx { - CXINF_DOWNSTREAM_RATE, - CXINF_UPSTREAM_RATE, - CXINF_LINK_STATUS, - CXINF_LINE_STATUS, - CXINF_MAC_ADDRESS_HIGH, - CXINF_MAC_ADDRESS_LOW, - CXINF_UPSTREAM_SNR_MARGIN, - CXINF_DOWNSTREAM_SNR_MARGIN, - CXINF_UPSTREAM_ATTENUATION, - CXINF_DOWNSTREAM_ATTENUATION, - CXINF_TRANSMITTER_POWER, - CXINF_UPSTREAM_BITS_PER_FRAME, - CXINF_DOWNSTREAM_BITS_PER_FRAME, - CXINF_STARTUP_ATTEMPTS, - CXINF_UPSTREAM_CRC_ERRORS, - CXINF_DOWNSTREAM_CRC_ERRORS, - CXINF_UPSTREAM_FEC_ERRORS, - CXINF_DOWNSTREAM_FEC_ERRORS, - CXINF_UPSTREAM_HEC_ERRORS, - CXINF_DOWNSTREAM_HEC_ERRORS, - CXINF_LINE_STARTABLE, - CXINF_MODULATION, - CXINF_ADSL_HEADEND, - CXINF_ADSL_HEADEND_ENVIRONMENT, - CXINF_CONTROLLER_VERSION, - /* dunno what the missing two mean */ - CXINF_MAX = 0x1c, -}; - -enum cxacru_poll_state { - CXPOLL_STOPPING, - CXPOLL_STOPPED, - CXPOLL_POLLING, - CXPOLL_SHUTDOWN -}; - -struct cxacru_modem_type { - u32 pll_f_clk; - u32 pll_b_clk; - int boot_rom_patch; -}; - -struct cxacru_data { - struct usbatm_data *usbatm; - - const struct cxacru_modem_type *modem_type; - - int line_status; - struct mutex adsl_state_serialize; - int adsl_status; - struct delayed_work poll_work; - u32 card_info[CXINF_MAX]; - struct mutex poll_state_serialize; - enum cxacru_poll_state poll_state; - - /* contol handles */ - struct mutex cm_serialize; - u8 *rcv_buf; - u8 *snd_buf; - struct urb *rcv_urb; - struct urb *snd_urb; - struct completion rcv_done; - struct completion snd_done; -}; - -static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, - u8 *wdata, int wsize, u8 *rdata, int rsize); -static void cxacru_poll_status(struct work_struct *work); - -/* Card info exported through sysfs */ -#define CXACRU__ATTR_INIT(_name) \ -static DEVICE_ATTR(_name, S_IRUGO, cxacru_sysfs_show_##_name, NULL) - -#define CXACRU_CMD_INIT(_name) \ -static DEVICE_ATTR(_name, S_IWUSR | S_IRUGO, \ - cxacru_sysfs_show_##_name, cxacru_sysfs_store_##_name) - -#define CXACRU_SET_INIT(_name) \ -static DEVICE_ATTR(_name, S_IWUSR, \ - NULL, cxacru_sysfs_store_##_name) - -#define CXACRU_ATTR_INIT(_value, _type, _name) \ -static ssize_t cxacru_sysfs_show_##_name(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct cxacru_data *instance = to_usbatm_driver_data(\ - to_usb_interface(dev)); \ -\ - if (instance == NULL) \ - return -ENODEV; \ -\ - return cxacru_sysfs_showattr_##_type(instance->card_info[_value], buf); \ -} \ -CXACRU__ATTR_INIT(_name) - -#define CXACRU_ATTR_CREATE(_v, _t, _name) CXACRU_DEVICE_CREATE_FILE(_name) -#define CXACRU_CMD_CREATE(_name) CXACRU_DEVICE_CREATE_FILE(_name) -#define CXACRU_SET_CREATE(_name) CXACRU_DEVICE_CREATE_FILE(_name) -#define CXACRU__ATTR_CREATE(_name) CXACRU_DEVICE_CREATE_FILE(_name) - -#define CXACRU_ATTR_REMOVE(_v, _t, _name) CXACRU_DEVICE_REMOVE_FILE(_name) -#define CXACRU_CMD_REMOVE(_name) CXACRU_DEVICE_REMOVE_FILE(_name) -#define CXACRU_SET_REMOVE(_name) CXACRU_DEVICE_REMOVE_FILE(_name) -#define CXACRU__ATTR_REMOVE(_name) CXACRU_DEVICE_REMOVE_FILE(_name) - -static ssize_t cxacru_sysfs_showattr_u32(u32 value, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%u\n", value); -} - -static ssize_t cxacru_sysfs_showattr_s8(s8 value, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", value); -} - -static ssize_t cxacru_sysfs_showattr_dB(s16 value, char *buf) -{ - if (likely(value >= 0)) { - return snprintf(buf, PAGE_SIZE, "%u.%02u\n", - value / 100, value % 100); - } else { - value = -value; - return snprintf(buf, PAGE_SIZE, "-%u.%02u\n", - value / 100, value % 100); - } -} - -static ssize_t cxacru_sysfs_showattr_bool(u32 value, char *buf) -{ - static char *str[] = { "no", "yes" }; - if (unlikely(value >= ARRAY_SIZE(str))) - return snprintf(buf, PAGE_SIZE, "%u\n", value); - return snprintf(buf, PAGE_SIZE, "%s\n", str[value]); -} - -static ssize_t cxacru_sysfs_showattr_LINK(u32 value, char *buf) -{ - static char *str[] = { NULL, "not connected", "connected", "lost" }; - if (unlikely(value >= ARRAY_SIZE(str) || str[value] == NULL)) - return snprintf(buf, PAGE_SIZE, "%u\n", value); - return snprintf(buf, PAGE_SIZE, "%s\n", str[value]); -} - -static ssize_t cxacru_sysfs_showattr_LINE(u32 value, char *buf) -{ - static char *str[] = { "down", "attempting to activate", - "training", "channel analysis", "exchange", "up", - "waiting", "initialising" - }; - if (unlikely(value >= ARRAY_SIZE(str))) - return snprintf(buf, PAGE_SIZE, "%u\n", value); - return snprintf(buf, PAGE_SIZE, "%s\n", str[value]); -} - -static ssize_t cxacru_sysfs_showattr_MODU(u32 value, char *buf) -{ - static char *str[] = { - "", - "ANSI T1.413", - "ITU-T G.992.1 (G.DMT)", - "ITU-T G.992.2 (G.LITE)" - }; - if (unlikely(value >= ARRAY_SIZE(str))) - return snprintf(buf, PAGE_SIZE, "%u\n", value); - return snprintf(buf, PAGE_SIZE, "%s\n", str[value]); -} - -/* - * This could use MAC_ADDRESS_HIGH and MAC_ADDRESS_LOW, but since - * this data is already in atm_dev there's no point. - * - * MAC_ADDRESS_HIGH = 0x????5544 - * MAC_ADDRESS_LOW = 0x33221100 - * Where 00-55 are bytes 0-5 of the MAC. - */ -static ssize_t cxacru_sysfs_show_mac_address(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct cxacru_data *instance = to_usbatm_driver_data( - to_usb_interface(dev)); - - if (instance == NULL || instance->usbatm->atm_dev == NULL) - return -ENODEV; - - return snprintf(buf, PAGE_SIZE, "%pM\n", - instance->usbatm->atm_dev->esi); -} - -static ssize_t cxacru_sysfs_show_adsl_state(struct device *dev, - struct device_attribute *attr, char *buf) -{ - static char *str[] = { "running", "stopped" }; - struct cxacru_data *instance = to_usbatm_driver_data( - to_usb_interface(dev)); - u32 value; - - if (instance == NULL) - return -ENODEV; - - value = instance->card_info[CXINF_LINE_STARTABLE]; - if (unlikely(value >= ARRAY_SIZE(str))) - return snprintf(buf, PAGE_SIZE, "%u\n", value); - return snprintf(buf, PAGE_SIZE, "%s\n", str[value]); -} - -static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct cxacru_data *instance = to_usbatm_driver_data( - to_usb_interface(dev)); - int ret; - int poll = -1; - char str_cmd[8]; - int len = strlen(buf); - - if (!capable(CAP_NET_ADMIN)) - return -EACCES; - - ret = sscanf(buf, "%7s", str_cmd); - if (ret != 1) - return -EINVAL; - ret = 0; - - if (instance == NULL) - return -ENODEV; - - if (mutex_lock_interruptible(&instance->adsl_state_serialize)) - return -ERESTARTSYS; - - if (!strcmp(str_cmd, "stop") || !strcmp(str_cmd, "restart")) { - ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_STOP, NULL, 0, NULL, 0); - if (ret < 0) { - atm_err(instance->usbatm, "change adsl state:" - " CHIP_ADSL_LINE_STOP returned %d\n", ret); - - ret = -EIO; - } else { - ret = len; - poll = CXPOLL_STOPPED; - } - } - - /* Line status is only updated every second - * and the device appears to only react to - * START/STOP every second too. Wait 1.5s to - * be sure that restart will have an effect. */ - if (!strcmp(str_cmd, "restart")) - msleep(1500); - - if (!strcmp(str_cmd, "start") || !strcmp(str_cmd, "restart")) { - ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_START, NULL, 0, NULL, 0); - if (ret < 0) { - atm_err(instance->usbatm, "change adsl state:" - " CHIP_ADSL_LINE_START returned %d\n", ret); - - ret = -EIO; - } else { - ret = len; - poll = CXPOLL_POLLING; - } - } - - if (!strcmp(str_cmd, "poll")) { - ret = len; - poll = CXPOLL_POLLING; - } - - if (ret == 0) { - ret = -EINVAL; - poll = -1; - } - - if (poll == CXPOLL_POLLING) { - mutex_lock(&instance->poll_state_serialize); - switch (instance->poll_state) { - case CXPOLL_STOPPED: - /* start polling */ - instance->poll_state = CXPOLL_POLLING; - break; - - case CXPOLL_STOPPING: - /* abort stop request */ - instance->poll_state = CXPOLL_POLLING; - case CXPOLL_POLLING: - case CXPOLL_SHUTDOWN: - /* don't start polling */ - poll = -1; - } - mutex_unlock(&instance->poll_state_serialize); - } else if (poll == CXPOLL_STOPPED) { - mutex_lock(&instance->poll_state_serialize); - /* request stop */ - if (instance->poll_state == CXPOLL_POLLING) - instance->poll_state = CXPOLL_STOPPING; - mutex_unlock(&instance->poll_state_serialize); - } - - mutex_unlock(&instance->adsl_state_serialize); - - if (poll == CXPOLL_POLLING) - cxacru_poll_status(&instance->poll_work.work); - - return ret; -} - -/* CM_REQUEST_CARD_DATA_GET times out, so no show attribute */ - -static ssize_t cxacru_sysfs_store_adsl_config(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct cxacru_data *instance = to_usbatm_driver_data( - to_usb_interface(dev)); - int len = strlen(buf); - int ret, pos, num; - __le32 data[CMD_PACKET_SIZE / 4]; - - if (!capable(CAP_NET_ADMIN)) - return -EACCES; - - if (instance == NULL) - return -ENODEV; - - pos = 0; - num = 0; - while (pos < len) { - int tmp; - u32 index; - u32 value; - - ret = sscanf(buf + pos, "%x=%x%n", &index, &value, &tmp); - if (ret < 2) - return -EINVAL; - if (index < 0 || index > 0x7f) - return -EINVAL; - pos += tmp; - - /* skip trailing newline */ - if (buf[pos] == '\n' && pos == len-1) - pos++; - - data[num * 2 + 1] = cpu_to_le32(index); - data[num * 2 + 2] = cpu_to_le32(value); - num++; - - /* send config values when data buffer is full - * or no more data - */ - if (pos >= len || num >= CMD_MAX_CONFIG) { - char log[CMD_MAX_CONFIG * 12 + 1]; /* %02x=%08x */ - - data[0] = cpu_to_le32(num); - ret = cxacru_cm(instance, CM_REQUEST_CARD_DATA_SET, - (u8 *) data, 4 + num * 8, NULL, 0); - if (ret < 0) { - atm_err(instance->usbatm, - "set card data returned %d\n", ret); - return -EIO; - } - - for (tmp = 0; tmp < num; tmp++) - snprintf(log + tmp*12, 13, " %02x=%08x", - le32_to_cpu(data[tmp * 2 + 1]), - le32_to_cpu(data[tmp * 2 + 2])); - atm_info(instance->usbatm, "config%s\n", log); - num = 0; - } - } - - return len; -} - -/* - * All device attributes are included in CXACRU_ALL_FILES - * so that the same list can be used multiple times: - * INIT (define the device attributes) - * CREATE (create all the device files) - * REMOVE (remove all the device files) - * - * With the last two being defined as needed in the functions - * they are used in before calling CXACRU_ALL_FILES() - */ -#define CXACRU_ALL_FILES(_action) \ -CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_RATE, u32, downstream_rate); \ -CXACRU_ATTR_##_action(CXINF_UPSTREAM_RATE, u32, upstream_rate); \ -CXACRU_ATTR_##_action(CXINF_LINK_STATUS, LINK, link_status); \ -CXACRU_ATTR_##_action(CXINF_LINE_STATUS, LINE, line_status); \ -CXACRU__ATTR_##_action( mac_address); \ -CXACRU_ATTR_##_action(CXINF_UPSTREAM_SNR_MARGIN, dB, upstream_snr_margin); \ -CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_SNR_MARGIN, dB, downstream_snr_margin); \ -CXACRU_ATTR_##_action(CXINF_UPSTREAM_ATTENUATION, dB, upstream_attenuation); \ -CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_ATTENUATION, dB, downstream_attenuation); \ -CXACRU_ATTR_##_action(CXINF_TRANSMITTER_POWER, s8, transmitter_power); \ -CXACRU_ATTR_##_action(CXINF_UPSTREAM_BITS_PER_FRAME, u32, upstream_bits_per_frame); \ -CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_BITS_PER_FRAME, u32, downstream_bits_per_frame); \ -CXACRU_ATTR_##_action(CXINF_STARTUP_ATTEMPTS, u32, startup_attempts); \ -CXACRU_ATTR_##_action(CXINF_UPSTREAM_CRC_ERRORS, u32, upstream_crc_errors); \ -CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_CRC_ERRORS, u32, downstream_crc_errors); \ -CXACRU_ATTR_##_action(CXINF_UPSTREAM_FEC_ERRORS, u32, upstream_fec_errors); \ -CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_FEC_ERRORS, u32, downstream_fec_errors); \ -CXACRU_ATTR_##_action(CXINF_UPSTREAM_HEC_ERRORS, u32, upstream_hec_errors); \ -CXACRU_ATTR_##_action(CXINF_DOWNSTREAM_HEC_ERRORS, u32, downstream_hec_errors); \ -CXACRU_ATTR_##_action(CXINF_LINE_STARTABLE, bool, line_startable); \ -CXACRU_ATTR_##_action(CXINF_MODULATION, MODU, modulation); \ -CXACRU_ATTR_##_action(CXINF_ADSL_HEADEND, u32, adsl_headend); \ -CXACRU_ATTR_##_action(CXINF_ADSL_HEADEND_ENVIRONMENT, u32, adsl_headend_environment); \ -CXACRU_ATTR_##_action(CXINF_CONTROLLER_VERSION, u32, adsl_controller_version); \ -CXACRU_CMD_##_action( adsl_state); \ -CXACRU_SET_##_action( adsl_config); - -CXACRU_ALL_FILES(INIT); - -/* the following three functions are stolen from drivers/usb/core/message.c */ -static void cxacru_blocking_completion(struct urb *urb) -{ - complete(urb->context); -} - -static void cxacru_timeout_kill(unsigned long data) -{ - usb_unlink_urb((struct urb *) data); -} - -static int cxacru_start_wait_urb(struct urb *urb, struct completion *done, - int *actual_length) -{ - struct timer_list timer; - - init_timer(&timer); - timer.expires = jiffies + msecs_to_jiffies(CMD_TIMEOUT); - timer.data = (unsigned long) urb; - timer.function = cxacru_timeout_kill; - add_timer(&timer); - wait_for_completion(done); - del_timer_sync(&timer); - - if (actual_length) - *actual_length = urb->actual_length; - return urb->status; /* must read status after completion */ -} - -static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, - u8 *wdata, int wsize, u8 *rdata, int rsize) -{ - int ret, actlen; - int offb, offd; - const int stride = CMD_PACKET_SIZE - 4; - u8 *wbuf = instance->snd_buf; - u8 *rbuf = instance->rcv_buf; - int wbuflen = ((wsize - 1) / stride + 1) * CMD_PACKET_SIZE; - int rbuflen = ((rsize - 1) / stride + 1) * CMD_PACKET_SIZE; - - if (wbuflen > PAGE_SIZE || rbuflen > PAGE_SIZE) { - if (printk_ratelimit()) - usb_err(instance->usbatm, "requested transfer size too large (%d, %d)\n", - wbuflen, rbuflen); - ret = -ENOMEM; - goto err; - } - - mutex_lock(&instance->cm_serialize); - - /* submit reading urb before the writing one */ - init_completion(&instance->rcv_done); - ret = usb_submit_urb(instance->rcv_urb, GFP_KERNEL); - if (ret < 0) { - if (printk_ratelimit()) - usb_err(instance->usbatm, "submit of read urb for cm %#x failed (%d)\n", - cm, ret); - goto fail; - } - - memset(wbuf, 0, wbuflen); - /* handle wsize == 0 */ - wbuf[0] = cm; - for (offb = offd = 0; offd < wsize; offd += stride, offb += CMD_PACKET_SIZE) { - wbuf[offb] = cm; - memcpy(wbuf + offb + 4, wdata + offd, min_t(int, stride, wsize - offd)); - } - - instance->snd_urb->transfer_buffer_length = wbuflen; - init_completion(&instance->snd_done); - ret = usb_submit_urb(instance->snd_urb, GFP_KERNEL); - if (ret < 0) { - if (printk_ratelimit()) - usb_err(instance->usbatm, "submit of write urb for cm %#x failed (%d)\n", - cm, ret); - goto fail; - } - - ret = cxacru_start_wait_urb(instance->snd_urb, &instance->snd_done, NULL); - if (ret < 0) { - if (printk_ratelimit()) - usb_err(instance->usbatm, "send of cm %#x failed (%d)\n", cm, ret); - goto fail; - } - - ret = cxacru_start_wait_urb(instance->rcv_urb, &instance->rcv_done, &actlen); - if (ret < 0) { - if (printk_ratelimit()) - usb_err(instance->usbatm, "receive of cm %#x failed (%d)\n", cm, ret); - goto fail; - } - if (actlen % CMD_PACKET_SIZE || !actlen) { - if (printk_ratelimit()) - usb_err(instance->usbatm, "invalid response length to cm %#x: %d\n", - cm, actlen); - ret = -EIO; - goto fail; - } - - /* check the return status and copy the data to the output buffer, if needed */ - for (offb = offd = 0; offd < rsize && offb < actlen; offb += CMD_PACKET_SIZE) { - if (rbuf[offb] != cm) { - if (printk_ratelimit()) - usb_err(instance->usbatm, "wrong cm %#x in response to cm %#x\n", - rbuf[offb], cm); - ret = -EIO; - goto fail; - } - if (rbuf[offb + 1] != CM_STATUS_SUCCESS) { - if (printk_ratelimit()) - usb_err(instance->usbatm, "response to cm %#x failed: %#x\n", - cm, rbuf[offb + 1]); - ret = -EIO; - goto fail; - } - if (offd >= rsize) - break; - memcpy(rdata + offd, rbuf + offb + 4, min_t(int, stride, rsize - offd)); - offd += stride; - } - - ret = offd; - dbg("cm %#x", cm); -fail: - mutex_unlock(&instance->cm_serialize); -err: - return ret; -} - -static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_request cm, - u32 *data, int size) -{ - int ret, len; - __le32 *buf; - int offb, offd; - const int stride = CMD_PACKET_SIZE / (4 * 2) - 1; - int buflen = ((size - 1) / stride + 1 + size * 2) * 4; - - buf = kmalloc(buflen, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ret = cxacru_cm(instance, cm, NULL, 0, (u8 *) buf, buflen); - if (ret < 0) - goto cleanup; - - /* len > 0 && len % 4 == 0 guaranteed by cxacru_cm() */ - len = ret / 4; - for (offb = 0; offb < len; ) { - int l = le32_to_cpu(buf[offb++]); - if (l < 0 || l > stride || l > (len - offb) / 2) { - if (printk_ratelimit()) - usb_err(instance->usbatm, "invalid data length from cm %#x: %d\n", - cm, l); - ret = -EIO; - goto cleanup; - } - while (l--) { - offd = le32_to_cpu(buf[offb++]); - if (offd >= size) { - if (printk_ratelimit()) - usb_err(instance->usbatm, "wrong index %#x in response to cm %#x\n", - offd, cm); - ret = -EIO; - goto cleanup; - } - data[offd] = le32_to_cpu(buf[offb++]); - } - } - - ret = 0; - -cleanup: - kfree(buf); - return ret; -} - -static int cxacru_card_status(struct cxacru_data *instance) -{ - int ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0); - if (ret < 0) { /* firmware not loaded */ - dbg("cxacru_adsl_start: CARD_GET_STATUS returned %d", ret); - return ret; - } - return 0; -} - -static void cxacru_remove_device_files(struct usbatm_data *usbatm_instance, - struct atm_dev *atm_dev) -{ - struct usb_interface *intf = usbatm_instance->usb_intf; - - #define CXACRU_DEVICE_REMOVE_FILE(_name) \ - device_remove_file(&intf->dev, &dev_attr_##_name); - CXACRU_ALL_FILES(REMOVE); - #undef CXACRU_DEVICE_REMOVE_FILE -} - -static int cxacru_atm_start(struct usbatm_data *usbatm_instance, - struct atm_dev *atm_dev) -{ - struct cxacru_data *instance = usbatm_instance->driver_data; - struct usb_interface *intf = usbatm_instance->usb_intf; - int ret; - int start_polling = 1; - - dbg("cxacru_atm_start"); - - /* Read MAC address */ - ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_MAC_ADDRESS, NULL, 0, - atm_dev->esi, sizeof(atm_dev->esi)); - if (ret < 0) { - atm_err(usbatm_instance, "cxacru_atm_start: CARD_GET_MAC_ADDRESS returned %d\n", ret); - return ret; - } - - #define CXACRU_DEVICE_CREATE_FILE(_name) \ - ret = device_create_file(&intf->dev, &dev_attr_##_name); \ - if (unlikely(ret)) \ - goto fail_sysfs; - CXACRU_ALL_FILES(CREATE); - #undef CXACRU_DEVICE_CREATE_FILE - - /* start ADSL */ - mutex_lock(&instance->adsl_state_serialize); - ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_START, NULL, 0, NULL, 0); - if (ret < 0) - atm_err(usbatm_instance, "cxacru_atm_start: CHIP_ADSL_LINE_START returned %d\n", ret); - - /* Start status polling */ - mutex_lock(&instance->poll_state_serialize); - switch (instance->poll_state) { - case CXPOLL_STOPPED: - /* start polling */ - instance->poll_state = CXPOLL_POLLING; - break; - - case CXPOLL_STOPPING: - /* abort stop request */ - instance->poll_state = CXPOLL_POLLING; - case CXPOLL_POLLING: - case CXPOLL_SHUTDOWN: - /* don't start polling */ - start_polling = 0; - } - mutex_unlock(&instance->poll_state_serialize); - mutex_unlock(&instance->adsl_state_serialize); - - printk(KERN_INFO "%s%d: %s %pM\n", atm_dev->type, atm_dev->number, - usbatm_instance->description, atm_dev->esi); - - if (start_polling) - cxacru_poll_status(&instance->poll_work.work); - return 0; - -fail_sysfs: - usb_err(usbatm_instance, "cxacru_atm_start: device_create_file failed (%d)\n", ret); - cxacru_remove_device_files(usbatm_instance, atm_dev); - return ret; -} - -static void cxacru_poll_status(struct work_struct *work) -{ - struct cxacru_data *instance = - container_of(work, struct cxacru_data, poll_work.work); - u32 buf[CXINF_MAX] = {}; - struct usbatm_data *usbatm = instance->usbatm; - struct atm_dev *atm_dev = usbatm->atm_dev; - int keep_polling = 1; - int ret; - - ret = cxacru_cm_get_array(instance, CM_REQUEST_CARD_INFO_GET, buf, CXINF_MAX); - if (ret < 0) { - if (ret != -ESHUTDOWN) - atm_warn(usbatm, "poll status: error %d\n", ret); - - mutex_lock(&instance->poll_state_serialize); - if (instance->poll_state != CXPOLL_SHUTDOWN) { - instance->poll_state = CXPOLL_STOPPED; - - if (ret != -ESHUTDOWN) - atm_warn(usbatm, "polling disabled, set adsl_state" - " to 'start' or 'poll' to resume\n"); - } - mutex_unlock(&instance->poll_state_serialize); - goto reschedule; - } - - memcpy(instance->card_info, buf, sizeof(instance->card_info)); - - if (instance->adsl_status != buf[CXINF_LINE_STARTABLE]) { - instance->adsl_status = buf[CXINF_LINE_STARTABLE]; - - switch (instance->adsl_status) { - case 0: - atm_printk(KERN_INFO, usbatm, "ADSL state: running\n"); - break; - - case 1: - atm_printk(KERN_INFO, usbatm, "ADSL state: stopped\n"); - break; - - default: - atm_printk(KERN_INFO, usbatm, "Unknown adsl status %02x\n", instance->adsl_status); - break; - } - } - - if (instance->line_status == buf[CXINF_LINE_STATUS]) - goto reschedule; - - instance->line_status = buf[CXINF_LINE_STATUS]; - switch (instance->line_status) { - case 0: - atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST); - atm_info(usbatm, "ADSL line: down\n"); - break; - - case 1: - atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST); - atm_info(usbatm, "ADSL line: attempting to activate\n"); - break; - - case 2: - atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST); - atm_info(usbatm, "ADSL line: training\n"); - break; - - case 3: - atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST); - atm_info(usbatm, "ADSL line: channel analysis\n"); - break; - - case 4: - atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST); - atm_info(usbatm, "ADSL line: exchange\n"); - break; - - case 5: - atm_dev->link_rate = buf[CXINF_DOWNSTREAM_RATE] * 1000 / 424; - atm_dev_signal_change(atm_dev, ATM_PHY_SIG_FOUND); - - atm_info(usbatm, "ADSL line: up (%d kb/s down | %d kb/s up)\n", - buf[CXINF_DOWNSTREAM_RATE], buf[CXINF_UPSTREAM_RATE]); - break; - - case 6: - atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST); - atm_info(usbatm, "ADSL line: waiting\n"); - break; - - case 7: - atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST); - atm_info(usbatm, "ADSL line: initializing\n"); - break; - - default: - atm_dev_signal_change(atm_dev, ATM_PHY_SIG_UNKNOWN); - atm_info(usbatm, "Unknown line state %02x\n", instance->line_status); - break; - } -reschedule: - - mutex_lock(&instance->poll_state_serialize); - if (instance->poll_state == CXPOLL_STOPPING && - instance->adsl_status == 1 && /* stopped */ - instance->line_status == 0) /* down */ - instance->poll_state = CXPOLL_STOPPED; - - if (instance->poll_state == CXPOLL_STOPPED) - keep_polling = 0; - mutex_unlock(&instance->poll_state_serialize); - - if (keep_polling) - schedule_delayed_work(&instance->poll_work, - round_jiffies_relative(POLL_INTERVAL*HZ)); -} - -static int cxacru_fw(struct usb_device *usb_dev, enum cxacru_fw_request fw, - u8 code1, u8 code2, u32 addr, const u8 *data, int size) -{ - int ret; - u8 *buf; - int offd, offb; - const int stride = CMD_PACKET_SIZE - 8; - - buf = (u8 *) __get_free_page(GFP_KERNEL); - if (!buf) - return -ENOMEM; - - offb = offd = 0; - do { - int l = min_t(int, stride, size - offd); - buf[offb++] = fw; - buf[offb++] = l; - buf[offb++] = code1; - buf[offb++] = code2; - put_unaligned(cpu_to_le32(addr), (__le32 *)(buf + offb)); - offb += 4; - addr += l; - if (l) - memcpy(buf + offb, data + offd, l); - if (l < stride) - memset(buf + offb + l, 0, stride - l); - offb += stride; - offd += stride; - if ((offb >= PAGE_SIZE) || (offd >= size)) { - ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_CMD), - buf, offb, NULL, CMD_TIMEOUT); - if (ret < 0) { - dbg("sending fw %#x failed", fw); - goto cleanup; - } - offb = 0; - } - } while (offd < size); - dbg("sent fw %#x", fw); - - ret = 0; - -cleanup: - free_page((unsigned long) buf); - return ret; -} - -static void cxacru_upload_firmware(struct cxacru_data *instance, - const struct firmware *fw, - const struct firmware *bp) -{ - int ret; - struct usbatm_data *usbatm = instance->usbatm; - struct usb_device *usb_dev = usbatm->usb_dev; - __le16 signature[] = { usb_dev->descriptor.idVendor, - usb_dev->descriptor.idProduct }; - __le32 val; - - dbg("cxacru_upload_firmware"); - - /* FirmwarePllFClkValue */ - val = cpu_to_le32(instance->modem_type->pll_f_clk); - ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, PLLFCLK_ADDR, (u8 *) &val, 4); - if (ret) { - usb_err(usbatm, "FirmwarePllFClkValue failed: %d\n", ret); - return; - } - - /* FirmwarePllBClkValue */ - val = cpu_to_le32(instance->modem_type->pll_b_clk); - ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, PLLBCLK_ADDR, (u8 *) &val, 4); - if (ret) { - usb_err(usbatm, "FirmwarePllBClkValue failed: %d\n", ret); - return; - } - - /* Enable SDRAM */ - val = cpu_to_le32(SDRAM_ENA); - ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, SDRAMEN_ADDR, (u8 *) &val, 4); - if (ret) { - usb_err(usbatm, "Enable SDRAM failed: %d\n", ret); - return; - } - - /* Firmware */ - usb_info(usbatm, "loading firmware\n"); - ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, FW_ADDR, fw->data, fw->size); - if (ret) { - usb_err(usbatm, "Firmware upload failed: %d\n", ret); - return; - } - - /* Boot ROM patch */ - if (instance->modem_type->boot_rom_patch) { - usb_info(usbatm, "loading boot ROM patch\n"); - ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_ADDR, bp->data, bp->size); - if (ret) { - usb_err(usbatm, "Boot ROM patching failed: %d\n", ret); - return; - } - } - - /* Signature */ - ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, SIG_ADDR, (u8 *) signature, 4); - if (ret) { - usb_err(usbatm, "Signature storing failed: %d\n", ret); - return; - } - - usb_info(usbatm, "starting device\n"); - if (instance->modem_type->boot_rom_patch) { - val = cpu_to_le32(BR_ADDR); - ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_STACK_ADDR, (u8 *) &val, 4); - } else { - ret = cxacru_fw(usb_dev, FW_GOTO_MEM, 0x0, 0x0, FW_ADDR, NULL, 0); - } - if (ret) { - usb_err(usbatm, "Passing control to firmware failed: %d\n", ret); - return; - } - - /* Delay to allow firmware to start up. */ - msleep_interruptible(1000); - - usb_clear_halt(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_CMD)); - usb_clear_halt(usb_dev, usb_rcvbulkpipe(usb_dev, CXACRU_EP_CMD)); - usb_clear_halt(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_DATA)); - usb_clear_halt(usb_dev, usb_rcvbulkpipe(usb_dev, CXACRU_EP_DATA)); - - ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0); - if (ret < 0) { - usb_err(usbatm, "modem failed to initialize: %d\n", ret); - return; - } -} - -static int cxacru_find_firmware(struct cxacru_data *instance, - char *phase, const struct firmware **fw_p) -{ - struct usbatm_data *usbatm = instance->usbatm; - struct device *dev = &usbatm->usb_intf->dev; - char buf[16]; - - sprintf(buf, "cxacru-%s.bin", phase); - dbg("cxacru_find_firmware: looking for %s", buf); - - if (request_firmware(fw_p, buf, dev)) { - usb_dbg(usbatm, "no stage %s firmware found\n", phase); - return -ENOENT; - } - - usb_info(usbatm, "found firmware %s\n", buf); - - return 0; -} - -static int cxacru_heavy_init(struct usbatm_data *usbatm_instance, - struct usb_interface *usb_intf) -{ - const struct firmware *fw, *bp; - struct cxacru_data *instance = usbatm_instance->driver_data; - - int ret = cxacru_find_firmware(instance, "fw", &fw); - if (ret) { - usb_warn(usbatm_instance, "firmware (cxacru-fw.bin) unavailable (system misconfigured?)\n"); - return ret; - } - - if (instance->modem_type->boot_rom_patch) { - ret = cxacru_find_firmware(instance, "bp", &bp); - if (ret) { - usb_warn(usbatm_instance, "boot ROM patch (cxacru-bp.bin) unavailable (system misconfigured?)\n"); - release_firmware(fw); - return ret; - } - } - - cxacru_upload_firmware(instance, fw, bp); - - if (instance->modem_type->boot_rom_patch) - release_firmware(bp); - release_firmware(fw); - - ret = cxacru_card_status(instance); - if (ret) - dbg("modem initialisation failed"); - else - dbg("done setting up the modem"); - - return ret; -} - -static int cxacru_bind(struct usbatm_data *usbatm_instance, - struct usb_interface *intf, const struct usb_device_id *id) -{ - struct cxacru_data *instance; - struct usb_device *usb_dev = interface_to_usbdev(intf); - struct usb_host_endpoint *cmd_ep = usb_dev->ep_in[CXACRU_EP_CMD]; - int ret; - - /* instance init */ - instance = kzalloc(sizeof(*instance), GFP_KERNEL); - if (!instance) { - dbg("cxacru_bind: no memory for instance data"); - return -ENOMEM; - } - - instance->usbatm = usbatm_instance; - instance->modem_type = (struct cxacru_modem_type *) id->driver_info; - - mutex_init(&instance->poll_state_serialize); - instance->poll_state = CXPOLL_STOPPED; - instance->line_status = -1; - instance->adsl_status = -1; - - mutex_init(&instance->adsl_state_serialize); - - instance->rcv_buf = (u8 *) __get_free_page(GFP_KERNEL); - if (!instance->rcv_buf) { - dbg("cxacru_bind: no memory for rcv_buf"); - ret = -ENOMEM; - goto fail; - } - instance->snd_buf = (u8 *) __get_free_page(GFP_KERNEL); - if (!instance->snd_buf) { - dbg("cxacru_bind: no memory for snd_buf"); - ret = -ENOMEM; - goto fail; - } - instance->rcv_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!instance->rcv_urb) { - dbg("cxacru_bind: no memory for rcv_urb"); - ret = -ENOMEM; - goto fail; - } - instance->snd_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!instance->snd_urb) { - dbg("cxacru_bind: no memory for snd_urb"); - ret = -ENOMEM; - goto fail; - } - - if (!cmd_ep) { - dbg("cxacru_bind: no command endpoint"); - ret = -ENODEV; - goto fail; - } - - if ((cmd_ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_INT) { - usb_fill_int_urb(instance->rcv_urb, - usb_dev, usb_rcvintpipe(usb_dev, CXACRU_EP_CMD), - instance->rcv_buf, PAGE_SIZE, - cxacru_blocking_completion, &instance->rcv_done, 1); - - usb_fill_int_urb(instance->snd_urb, - usb_dev, usb_sndintpipe(usb_dev, CXACRU_EP_CMD), - instance->snd_buf, PAGE_SIZE, - cxacru_blocking_completion, &instance->snd_done, 4); - } else { - usb_fill_bulk_urb(instance->rcv_urb, - usb_dev, usb_rcvbulkpipe(usb_dev, CXACRU_EP_CMD), - instance->rcv_buf, PAGE_SIZE, - cxacru_blocking_completion, &instance->rcv_done); - - usb_fill_bulk_urb(instance->snd_urb, - usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_CMD), - instance->snd_buf, PAGE_SIZE, - cxacru_blocking_completion, &instance->snd_done); - } - - mutex_init(&instance->cm_serialize); - - INIT_DELAYED_WORK(&instance->poll_work, cxacru_poll_status); - - usbatm_instance->driver_data = instance; - - usbatm_instance->flags = (cxacru_card_status(instance) ? 0 : UDSL_SKIP_HEAVY_INIT); - - return 0; - - fail: - free_page((unsigned long) instance->snd_buf); - free_page((unsigned long) instance->rcv_buf); - usb_free_urb(instance->snd_urb); - usb_free_urb(instance->rcv_urb); - kfree(instance); - - return ret; -} - -static void cxacru_unbind(struct usbatm_data *usbatm_instance, - struct usb_interface *intf) -{ - struct cxacru_data *instance = usbatm_instance->driver_data; - int is_polling = 1; - - dbg("cxacru_unbind entered"); - - if (!instance) { - dbg("cxacru_unbind: NULL instance!"); - return; - } - - mutex_lock(&instance->poll_state_serialize); - BUG_ON(instance->poll_state == CXPOLL_SHUTDOWN); - - /* ensure that status polling continues unless - * it has already stopped */ - if (instance->poll_state == CXPOLL_STOPPED) - is_polling = 0; - - /* stop polling from being stopped or started */ - instance->poll_state = CXPOLL_SHUTDOWN; - mutex_unlock(&instance->poll_state_serialize); - - if (is_polling) - cancel_delayed_work_sync(&instance->poll_work); - - usb_kill_urb(instance->snd_urb); - usb_kill_urb(instance->rcv_urb); - usb_free_urb(instance->snd_urb); - usb_free_urb(instance->rcv_urb); - - free_page((unsigned long) instance->snd_buf); - free_page((unsigned long) instance->rcv_buf); - - kfree(instance); - - usbatm_instance->driver_data = NULL; -} - -static const struct cxacru_modem_type cxacru_cafe = { - .pll_f_clk = 0x02d874df, - .pll_b_clk = 0x0196a51a, - .boot_rom_patch = 1, -}; - -static const struct cxacru_modem_type cxacru_cb00 = { - .pll_f_clk = 0x5, - .pll_b_clk = 0x3, - .boot_rom_patch = 0, -}; - -static const struct usb_device_id cxacru_usb_ids[] = { - { /* V = Conexant P = ADSL modem (Euphrates project) */ - USB_DEVICE(0x0572, 0xcafe), .driver_info = (unsigned long) &cxacru_cafe - }, - { /* V = Conexant P = ADSL modem (Hasbani project) */ - USB_DEVICE(0x0572, 0xcb00), .driver_info = (unsigned long) &cxacru_cb00 - }, - { /* V = Conexant P = ADSL modem */ - USB_DEVICE(0x0572, 0xcb01), .driver_info = (unsigned long) &cxacru_cb00 - }, - { /* V = Conexant P = ADSL modem (Well PTI-800) */ - USB_DEVICE(0x0572, 0xcb02), .driver_info = (unsigned long) &cxacru_cb00 - }, - { /* V = Conexant P = ADSL modem */ - USB_DEVICE(0x0572, 0xcb06), .driver_info = (unsigned long) &cxacru_cb00 - }, - { /* V = Conexant P = ADSL modem (ZTE ZXDSL 852) */ - USB_DEVICE(0x0572, 0xcb07), .driver_info = (unsigned long) &cxacru_cb00 - }, - { /* V = Olitec P = ADSL modem version 2 */ - USB_DEVICE(0x08e3, 0x0100), .driver_info = (unsigned long) &cxacru_cafe - }, - { /* V = Olitec P = ADSL modem version 3 */ - USB_DEVICE(0x08e3, 0x0102), .driver_info = (unsigned long) &cxacru_cb00 - }, - { /* V = Trust/Amigo Technology Co. P = AMX-CA86U */ - USB_DEVICE(0x0eb0, 0x3457), .driver_info = (unsigned long) &cxacru_cafe - }, - { /* V = Zoom P = 5510 */ - USB_DEVICE(0x1803, 0x5510), .driver_info = (unsigned long) &cxacru_cb00 - }, - { /* V = Draytek P = Vigor 318 */ - USB_DEVICE(0x0675, 0x0200), .driver_info = (unsigned long) &cxacru_cb00 - }, - { /* V = Zyxel P = 630-C1 aka OMNI ADSL USB (Annex A) */ - USB_DEVICE(0x0586, 0x330a), .driver_info = (unsigned long) &cxacru_cb00 - }, - { /* V = Zyxel P = 630-C3 aka OMNI ADSL USB (Annex B) */ - USB_DEVICE(0x0586, 0x330b), .driver_info = (unsigned long) &cxacru_cb00 - }, - { /* V = Aethra P = Starmodem UM1020 */ - USB_DEVICE(0x0659, 0x0020), .driver_info = (unsigned long) &cxacru_cb00 - }, - { /* V = Aztech Systems P = ? AKA Pirelli AUA-010 */ - USB_DEVICE(0x0509, 0x0812), .driver_info = (unsigned long) &cxacru_cb00 - }, - { /* V = Netopia P = Cayman 3341(Annex A)/3351(Annex B) */ - USB_DEVICE(0x100d, 0xcb01), .driver_info = (unsigned long) &cxacru_cb00 - }, - { /* V = Netopia P = Cayman 3342(Annex A)/3352(Annex B) */ - USB_DEVICE(0x100d, 0x3342), .driver_info = (unsigned long) &cxacru_cb00 - }, - {} -}; - -MODULE_DEVICE_TABLE(usb, cxacru_usb_ids); - -static struct usbatm_driver cxacru_driver = { - .driver_name = cxacru_driver_name, - .bind = cxacru_bind, - .heavy_init = cxacru_heavy_init, - .unbind = cxacru_unbind, - .atm_start = cxacru_atm_start, - .atm_stop = cxacru_remove_device_files, - .bulk_in = CXACRU_EP_DATA, - .bulk_out = CXACRU_EP_DATA, - .rx_padding = 3, - .tx_padding = 11, -}; - -static int cxacru_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *usb_dev = interface_to_usbdev(intf); - char buf[15]; - - /* Avoid ADSL routers (cx82310_eth). - * Abort if bDeviceClass is 0xff and iProduct is "USB NET CARD". - */ - if (usb_dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC - && usb_string(usb_dev, usb_dev->descriptor.iProduct, - buf, sizeof(buf)) > 0) { - if (!strcmp(buf, "USB NET CARD")) { - dev_info(&intf->dev, "ignoring cx82310_eth device\n"); - return -ENODEV; - } - } - - return usbatm_usb_probe(intf, id, &cxacru_driver); -} - -static struct usb_driver cxacru_usb_driver = { - .name = cxacru_driver_name, - .probe = cxacru_usb_probe, - .disconnect = usbatm_usb_disconnect, - .id_table = cxacru_usb_ids -}; - -module_usb_driver(cxacru_usb_driver); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRIVER_VERSION); diff --git a/ANDROID_3.4.5/drivers/usb/atm/speedtch.c b/ANDROID_3.4.5/drivers/usb/atm/speedtch.c deleted file mode 100644 index 98dd9e49..00000000 --- a/ANDROID_3.4.5/drivers/usb/atm/speedtch.c +++ /dev/null @@ -1,961 +0,0 @@ -/****************************************************************************** - * speedtch.c - Alcatel SpeedTouch USB xDSL modem driver - * - * Copyright (C) 2001, Alcatel - * Copyright (C) 2003, Duncan Sands - * Copyright (C) 2004, David Woodhouse - * - * Based on "modem_run.c", copyright (C) 2001, Benoit Papillault - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - ******************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "usbatm.h" - -#define DRIVER_AUTHOR "Johan Verrept, Duncan Sands " -#define DRIVER_VERSION "1.10" -#define DRIVER_DESC "Alcatel SpeedTouch USB driver version " DRIVER_VERSION - -static const char speedtch_driver_name[] = "speedtch"; - -#define CTRL_TIMEOUT 2000 /* milliseconds */ -#define DATA_TIMEOUT 2000 /* milliseconds */ - -#define OFFSET_7 0 /* size 1 */ -#define OFFSET_b 1 /* size 8 */ -#define OFFSET_d 9 /* size 4 */ -#define OFFSET_e 13 /* size 1 */ -#define OFFSET_f 14 /* size 1 */ - -#define SIZE_7 1 -#define SIZE_b 8 -#define SIZE_d 4 -#define SIZE_e 1 -#define SIZE_f 1 - -#define MIN_POLL_DELAY 5000 /* milliseconds */ -#define MAX_POLL_DELAY 60000 /* milliseconds */ - -#define RESUBMIT_DELAY 1000 /* milliseconds */ - -#define DEFAULT_BULK_ALTSETTING 1 -#define DEFAULT_ISOC_ALTSETTING 3 -#define DEFAULT_DL_512_FIRST 0 -#define DEFAULT_ENABLE_ISOC 0 -#define DEFAULT_SW_BUFFERING 0 - -static unsigned int altsetting = 0; /* zero means: use the default */ -static bool dl_512_first = DEFAULT_DL_512_FIRST; -static bool enable_isoc = DEFAULT_ENABLE_ISOC; -static bool sw_buffering = DEFAULT_SW_BUFFERING; - -#define DEFAULT_B_MAX_DSL 8128 -#define DEFAULT_MODEM_MODE 11 -#define MODEM_OPTION_LENGTH 16 -static const unsigned char DEFAULT_MODEM_OPTION[MODEM_OPTION_LENGTH] = { - 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static unsigned int BMaxDSL = DEFAULT_B_MAX_DSL; -static unsigned char ModemMode = DEFAULT_MODEM_MODE; -static unsigned char ModemOption[MODEM_OPTION_LENGTH]; -static unsigned int num_ModemOption; - -module_param(altsetting, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(altsetting, - "Alternative setting for data interface (bulk_default: " - __MODULE_STRING(DEFAULT_BULK_ALTSETTING) "; isoc_default: " - __MODULE_STRING(DEFAULT_ISOC_ALTSETTING) ")"); - -module_param(dl_512_first, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(dl_512_first, - "Read 512 bytes before sending firmware (default: " - __MODULE_STRING(DEFAULT_DL_512_FIRST) ")"); - -module_param(enable_isoc, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(enable_isoc, - "Use isochronous transfers if available (default: " - __MODULE_STRING(DEFAULT_ENABLE_ISOC) ")"); - -module_param(sw_buffering, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(sw_buffering, - "Enable software buffering (default: " - __MODULE_STRING(DEFAULT_SW_BUFFERING) ")"); - -module_param(BMaxDSL, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(BMaxDSL, - "default: " __MODULE_STRING(DEFAULT_B_MAX_DSL)); - -module_param(ModemMode, byte, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(ModemMode, - "default: " __MODULE_STRING(DEFAULT_MODEM_MODE)); - -module_param_array(ModemOption, byte, &num_ModemOption, S_IRUGO); -MODULE_PARM_DESC(ModemOption, "default: 0x10,0x00,0x00,0x00,0x20"); - -#define INTERFACE_DATA 1 -#define ENDPOINT_INT 0x81 -#define ENDPOINT_BULK_DATA 0x07 -#define ENDPOINT_ISOC_DATA 0x07 -#define ENDPOINT_FIRMWARE 0x05 - -struct speedtch_params { - unsigned int altsetting; - unsigned int BMaxDSL; - unsigned char ModemMode; - unsigned char ModemOption[MODEM_OPTION_LENGTH]; -}; - -struct speedtch_instance_data { - struct usbatm_data *usbatm; - - struct speedtch_params params; /* set in probe, constant afterwards */ - - struct timer_list status_check_timer; - struct work_struct status_check_work; - - unsigned char last_status; - - int poll_delay; /* milliseconds */ - - struct timer_list resubmit_timer; - struct urb *int_urb; - unsigned char int_data[16]; - - unsigned char scratch_buffer[16]; -}; - -/*************** -** firmware ** -***************/ - -static void speedtch_set_swbuff(struct speedtch_instance_data *instance, int state) -{ - struct usbatm_data *usbatm = instance->usbatm; - struct usb_device *usb_dev = usbatm->usb_dev; - int ret; - - ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), - 0x32, 0x40, state ? 0x01 : 0x00, 0x00, NULL, 0, CTRL_TIMEOUT); - if (ret < 0) - usb_warn(usbatm, - "%sabling SW buffering: usb_control_msg returned %d\n", - state ? "En" : "Dis", ret); - else - dbg("speedtch_set_swbuff: %sbled SW buffering", state ? "En" : "Dis"); -} - -static void speedtch_test_sequence(struct speedtch_instance_data *instance) -{ - struct usbatm_data *usbatm = instance->usbatm; - struct usb_device *usb_dev = usbatm->usb_dev; - unsigned char *buf = instance->scratch_buffer; - int ret; - - /* URB 147 */ - buf[0] = 0x1c; - buf[1] = 0x50; - ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), - 0x01, 0x40, 0x0b, 0x00, buf, 2, CTRL_TIMEOUT); - if (ret < 0) - usb_warn(usbatm, "%s failed on URB147: %d\n", __func__, ret); - - /* URB 148 */ - buf[0] = 0x32; - buf[1] = 0x00; - ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), - 0x01, 0x40, 0x02, 0x00, buf, 2, CTRL_TIMEOUT); - if (ret < 0) - usb_warn(usbatm, "%s failed on URB148: %d\n", __func__, ret); - - /* URB 149 */ - buf[0] = 0x01; - buf[1] = 0x00; - buf[2] = 0x01; - ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), - 0x01, 0x40, 0x03, 0x00, buf, 3, CTRL_TIMEOUT); - if (ret < 0) - usb_warn(usbatm, "%s failed on URB149: %d\n", __func__, ret); - - /* URB 150 */ - buf[0] = 0x01; - buf[1] = 0x00; - buf[2] = 0x01; - ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), - 0x01, 0x40, 0x04, 0x00, buf, 3, CTRL_TIMEOUT); - if (ret < 0) - usb_warn(usbatm, "%s failed on URB150: %d\n", __func__, ret); - - /* Extra initialisation in recent drivers - gives higher speeds */ - - /* URBext1 */ - buf[0] = instance->params.ModemMode; - ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), - 0x01, 0x40, 0x11, 0x00, buf, 1, CTRL_TIMEOUT); - if (ret < 0) - usb_warn(usbatm, "%s failed on URBext1: %d\n", __func__, ret); - - /* URBext2 */ - /* This seems to be the one which actually triggers the higher sync - rate -- it does require the new firmware too, although it works OK - with older firmware */ - ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), - 0x01, 0x40, 0x14, 0x00, - instance->params.ModemOption, - MODEM_OPTION_LENGTH, CTRL_TIMEOUT); - if (ret < 0) - usb_warn(usbatm, "%s failed on URBext2: %d\n", __func__, ret); - - /* URBext3 */ - buf[0] = instance->params.BMaxDSL & 0xff; - buf[1] = instance->params.BMaxDSL >> 8; - ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), - 0x01, 0x40, 0x12, 0x00, buf, 2, CTRL_TIMEOUT); - if (ret < 0) - usb_warn(usbatm, "%s failed on URBext3: %d\n", __func__, ret); -} - -static int speedtch_upload_firmware(struct speedtch_instance_data *instance, - const struct firmware *fw1, - const struct firmware *fw2) -{ - unsigned char *buffer; - struct usbatm_data *usbatm = instance->usbatm; - struct usb_device *usb_dev = usbatm->usb_dev; - int actual_length; - int ret = 0; - int offset; - - usb_dbg(usbatm, "%s entered\n", __func__); - - if (!(buffer = (unsigned char *)__get_free_page(GFP_KERNEL))) { - ret = -ENOMEM; - usb_dbg(usbatm, "%s: no memory for buffer!\n", __func__); - goto out; - } - - if (!usb_ifnum_to_if(usb_dev, 2)) { - ret = -ENODEV; - usb_dbg(usbatm, "%s: interface not found!\n", __func__); - goto out_free; - } - - /* URB 7 */ - if (dl_512_first) { /* some modems need a read before writing the firmware */ - ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, ENDPOINT_FIRMWARE), - buffer, 0x200, &actual_length, 2000); - - if (ret < 0 && ret != -ETIMEDOUT) - usb_warn(usbatm, "%s: read BLOCK0 from modem failed (%d)!\n", __func__, ret); - else - usb_dbg(usbatm, "%s: BLOCK0 downloaded (%d bytes)\n", __func__, ret); - } - - /* URB 8 : both leds are static green */ - for (offset = 0; offset < fw1->size; offset += PAGE_SIZE) { - int thislen = min_t(int, PAGE_SIZE, fw1->size - offset); - memcpy(buffer, fw1->data + offset, thislen); - - ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, ENDPOINT_FIRMWARE), - buffer, thislen, &actual_length, DATA_TIMEOUT); - - if (ret < 0) { - usb_err(usbatm, "%s: write BLOCK1 to modem failed (%d)!\n", __func__, ret); - goto out_free; - } - usb_dbg(usbatm, "%s: BLOCK1 uploaded (%zu bytes)\n", __func__, fw1->size); - } - - /* USB led blinking green, ADSL led off */ - - /* URB 11 */ - ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, ENDPOINT_FIRMWARE), - buffer, 0x200, &actual_length, DATA_TIMEOUT); - - if (ret < 0) { - usb_err(usbatm, "%s: read BLOCK2 from modem failed (%d)!\n", __func__, ret); - goto out_free; - } - usb_dbg(usbatm, "%s: BLOCK2 downloaded (%d bytes)\n", __func__, actual_length); - - /* URBs 12 to 139 - USB led blinking green, ADSL led off */ - for (offset = 0; offset < fw2->size; offset += PAGE_SIZE) { - int thislen = min_t(int, PAGE_SIZE, fw2->size - offset); - memcpy(buffer, fw2->data + offset, thislen); - - ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, ENDPOINT_FIRMWARE), - buffer, thislen, &actual_length, DATA_TIMEOUT); - - if (ret < 0) { - usb_err(usbatm, "%s: write BLOCK3 to modem failed (%d)!\n", __func__, ret); - goto out_free; - } - } - usb_dbg(usbatm, "%s: BLOCK3 uploaded (%zu bytes)\n", __func__, fw2->size); - - /* USB led static green, ADSL led static red */ - - /* URB 142 */ - ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, ENDPOINT_FIRMWARE), - buffer, 0x200, &actual_length, DATA_TIMEOUT); - - if (ret < 0) { - usb_err(usbatm, "%s: read BLOCK4 from modem failed (%d)!\n", __func__, ret); - goto out_free; - } - - /* success */ - usb_dbg(usbatm, "%s: BLOCK4 downloaded (%d bytes)\n", __func__, actual_length); - - /* Delay to allow firmware to start up. We can do this here - because we're in our own kernel thread anyway. */ - msleep_interruptible(1000); - - if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->params.altsetting)) < 0) { - usb_err(usbatm, "%s: setting interface to %d failed (%d)!\n", __func__, instance->params.altsetting, ret); - goto out_free; - } - - /* Enable software buffering, if requested */ - if (sw_buffering) - speedtch_set_swbuff(instance, 1); - - /* Magic spell; don't ask us what this does */ - speedtch_test_sequence(instance); - - ret = 0; - -out_free: - free_page((unsigned long)buffer); -out: - return ret; -} - -static int speedtch_find_firmware(struct usbatm_data *usbatm, struct usb_interface *intf, - int phase, const struct firmware **fw_p) -{ - struct device *dev = &intf->dev; - const u16 bcdDevice = le16_to_cpu(interface_to_usbdev(intf)->descriptor.bcdDevice); - const u8 major_revision = bcdDevice >> 8; - const u8 minor_revision = bcdDevice & 0xff; - char buf[24]; - - sprintf(buf, "speedtch-%d.bin.%x.%02x", phase, major_revision, minor_revision); - usb_dbg(usbatm, "%s: looking for %s\n", __func__, buf); - - if (request_firmware(fw_p, buf, dev)) { - sprintf(buf, "speedtch-%d.bin.%x", phase, major_revision); - usb_dbg(usbatm, "%s: looking for %s\n", __func__, buf); - - if (request_firmware(fw_p, buf, dev)) { - sprintf(buf, "speedtch-%d.bin", phase); - usb_dbg(usbatm, "%s: looking for %s\n", __func__, buf); - - if (request_firmware(fw_p, buf, dev)) { - usb_err(usbatm, "%s: no stage %d firmware found!\n", __func__, phase); - return -ENOENT; - } - } - } - - usb_info(usbatm, "found stage %d firmware %s\n", phase, buf); - - return 0; -} - -static int speedtch_heavy_init(struct usbatm_data *usbatm, struct usb_interface *intf) -{ - const struct firmware *fw1, *fw2; - struct speedtch_instance_data *instance = usbatm->driver_data; - int ret; - - if ((ret = speedtch_find_firmware(usbatm, intf, 1, &fw1)) < 0) - return ret; - - if ((ret = speedtch_find_firmware(usbatm, intf, 2, &fw2)) < 0) { - release_firmware(fw1); - return ret; - } - - if ((ret = speedtch_upload_firmware(instance, fw1, fw2)) < 0) - usb_err(usbatm, "%s: firmware upload failed (%d)!\n", __func__, ret); - - release_firmware(fw2); - release_firmware(fw1); - - return ret; -} - - -/********** -** ATM ** -**********/ - -static int speedtch_read_status(struct speedtch_instance_data *instance) -{ - struct usbatm_data *usbatm = instance->usbatm; - struct usb_device *usb_dev = usbatm->usb_dev; - unsigned char *buf = instance->scratch_buffer; - int ret; - - memset(buf, 0, 16); - - ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), - 0x12, 0xc0, 0x07, 0x00, buf + OFFSET_7, SIZE_7, - CTRL_TIMEOUT); - if (ret < 0) { - atm_dbg(usbatm, "%s: MSG 7 failed\n", __func__); - return ret; - } - - ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), - 0x12, 0xc0, 0x0b, 0x00, buf + OFFSET_b, SIZE_b, - CTRL_TIMEOUT); - if (ret < 0) { - atm_dbg(usbatm, "%s: MSG B failed\n", __func__); - return ret; - } - - ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), - 0x12, 0xc0, 0x0d, 0x00, buf + OFFSET_d, SIZE_d, - CTRL_TIMEOUT); - if (ret < 0) { - atm_dbg(usbatm, "%s: MSG D failed\n", __func__); - return ret; - } - - ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), - 0x01, 0xc0, 0x0e, 0x00, buf + OFFSET_e, SIZE_e, - CTRL_TIMEOUT); - if (ret < 0) { - atm_dbg(usbatm, "%s: MSG E failed\n", __func__); - return ret; - } - - ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), - 0x01, 0xc0, 0x0f, 0x00, buf + OFFSET_f, SIZE_f, - CTRL_TIMEOUT); - if (ret < 0) { - atm_dbg(usbatm, "%s: MSG F failed\n", __func__); - return ret; - } - - return 0; -} - -static int speedtch_start_synchro(struct speedtch_instance_data *instance) -{ - struct usbatm_data *usbatm = instance->usbatm; - struct usb_device *usb_dev = usbatm->usb_dev; - unsigned char *buf = instance->scratch_buffer; - int ret; - - atm_dbg(usbatm, "%s entered\n", __func__); - - memset(buf, 0, 2); - - ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), - 0x12, 0xc0, 0x04, 0x00, - buf, 2, CTRL_TIMEOUT); - - if (ret < 0) - atm_warn(usbatm, "failed to start ADSL synchronisation: %d\n", ret); - else - atm_dbg(usbatm, "%s: modem prodded. %d bytes returned: %02x %02x\n", - __func__, ret, buf[0], buf[1]); - - return ret; -} - -static void speedtch_check_status(struct work_struct *work) -{ - struct speedtch_instance_data *instance = - container_of(work, struct speedtch_instance_data, - status_check_work); - struct usbatm_data *usbatm = instance->usbatm; - struct atm_dev *atm_dev = usbatm->atm_dev; - unsigned char *buf = instance->scratch_buffer; - int down_speed, up_speed, ret; - unsigned char status; - -#ifdef VERBOSE_DEBUG - atm_dbg(usbatm, "%s entered\n", __func__); -#endif - - ret = speedtch_read_status(instance); - if (ret < 0) { - atm_warn(usbatm, "error %d fetching device status\n", ret); - instance->poll_delay = min(2 * instance->poll_delay, MAX_POLL_DELAY); - return; - } - - instance->poll_delay = max(instance->poll_delay / 2, MIN_POLL_DELAY); - - status = buf[OFFSET_7]; - - if ((status != instance->last_status) || !status) { - atm_dbg(usbatm, "%s: line state 0x%02x\n", __func__, status); - - switch (status) { - case 0: - atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST); - if (instance->last_status) - atm_info(usbatm, "ADSL line is down\n"); - /* It may never resync again unless we ask it to... */ - ret = speedtch_start_synchro(instance); - break; - - case 0x08: - atm_dev_signal_change(atm_dev, ATM_PHY_SIG_UNKNOWN); - atm_info(usbatm, "ADSL line is blocked?\n"); - break; - - case 0x10: - atm_dev_signal_change(atm_dev, ATM_PHY_SIG_LOST); - atm_info(usbatm, "ADSL line is synchronising\n"); - break; - - case 0x20: - down_speed = buf[OFFSET_b] | (buf[OFFSET_b + 1] << 8) - | (buf[OFFSET_b + 2] << 16) | (buf[OFFSET_b + 3] << 24); - up_speed = buf[OFFSET_b + 4] | (buf[OFFSET_b + 5] << 8) - | (buf[OFFSET_b + 6] << 16) | (buf[OFFSET_b + 7] << 24); - - if (!(down_speed & 0x0000ffff) && !(up_speed & 0x0000ffff)) { - down_speed >>= 16; - up_speed >>= 16; - } - - atm_dev->link_rate = down_speed * 1000 / 424; - atm_dev_signal_change(atm_dev, ATM_PHY_SIG_FOUND); - - atm_info(usbatm, - "ADSL line is up (%d kb/s down | %d kb/s up)\n", - down_speed, up_speed); - break; - - default: - atm_dev_signal_change(atm_dev, ATM_PHY_SIG_UNKNOWN); - atm_info(usbatm, "unknown line state %02x\n", status); - break; - } - - instance->last_status = status; - } -} - -static void speedtch_status_poll(unsigned long data) -{ - struct speedtch_instance_data *instance = (void *)data; - - schedule_work(&instance->status_check_work); - - /* The following check is racy, but the race is harmless */ - if (instance->poll_delay < MAX_POLL_DELAY) - mod_timer(&instance->status_check_timer, jiffies + msecs_to_jiffies(instance->poll_delay)); - else - atm_warn(instance->usbatm, "Too many failures - disabling line status polling\n"); -} - -static void speedtch_resubmit_int(unsigned long data) -{ - struct speedtch_instance_data *instance = (void *)data; - struct urb *int_urb = instance->int_urb; - int ret; - - atm_dbg(instance->usbatm, "%s entered\n", __func__); - - if (int_urb) { - ret = usb_submit_urb(int_urb, GFP_ATOMIC); - if (!ret) - schedule_work(&instance->status_check_work); - else { - atm_dbg(instance->usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret); - mod_timer(&instance->resubmit_timer, jiffies + msecs_to_jiffies(RESUBMIT_DELAY)); - } - } -} - -static void speedtch_handle_int(struct urb *int_urb) -{ - struct speedtch_instance_data *instance = int_urb->context; - struct usbatm_data *usbatm = instance->usbatm; - unsigned int count = int_urb->actual_length; - int status = int_urb->status; - int ret; - - /* The magic interrupt for "up state" */ - static const unsigned char up_int[6] = { 0xa1, 0x00, 0x01, 0x00, 0x00, 0x00 }; - /* The magic interrupt for "down state" */ - static const unsigned char down_int[6] = { 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - atm_dbg(usbatm, "%s entered\n", __func__); - - if (status < 0) { - atm_dbg(usbatm, "%s: nonzero urb status %d!\n", __func__, status); - goto fail; - } - - if ((count == 6) && !memcmp(up_int, instance->int_data, 6)) { - del_timer(&instance->status_check_timer); - atm_info(usbatm, "DSL line goes up\n"); - } else if ((count == 6) && !memcmp(down_int, instance->int_data, 6)) { - atm_info(usbatm, "DSL line goes down\n"); - } else { - int i; - - atm_dbg(usbatm, "%s: unknown interrupt packet of length %d:", __func__, count); - for (i = 0; i < count; i++) - printk(" %02x", instance->int_data[i]); - printk("\n"); - goto fail; - } - - if ((int_urb = instance->int_urb)) { - ret = usb_submit_urb(int_urb, GFP_ATOMIC); - schedule_work(&instance->status_check_work); - if (ret < 0) { - atm_dbg(usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret); - goto fail; - } - } - - return; - -fail: - if ((int_urb = instance->int_urb)) - mod_timer(&instance->resubmit_timer, jiffies + msecs_to_jiffies(RESUBMIT_DELAY)); -} - -static int speedtch_atm_start(struct usbatm_data *usbatm, struct atm_dev *atm_dev) -{ - struct usb_device *usb_dev = usbatm->usb_dev; - struct speedtch_instance_data *instance = usbatm->driver_data; - int i, ret; - unsigned char mac_str[13]; - - atm_dbg(usbatm, "%s entered\n", __func__); - - /* Set MAC address, it is stored in the serial number */ - memset(atm_dev->esi, 0, sizeof(atm_dev->esi)); - if (usb_string(usb_dev, usb_dev->descriptor.iSerialNumber, mac_str, sizeof(mac_str)) == 12) { - for (i = 0; i < 6; i++) - atm_dev->esi[i] = (hex_to_bin(mac_str[i * 2]) << 4) + - hex_to_bin(mac_str[i * 2 + 1]); - } - - /* Start modem synchronisation */ - ret = speedtch_start_synchro(instance); - - /* Set up interrupt endpoint */ - if (instance->int_urb) { - ret = usb_submit_urb(instance->int_urb, GFP_KERNEL); - if (ret < 0) { - /* Doesn't matter; we'll poll anyway */ - atm_dbg(usbatm, "%s: submission of interrupt URB failed (%d)!\n", __func__, ret); - usb_free_urb(instance->int_urb); - instance->int_urb = NULL; - } - } - - /* Start status polling */ - mod_timer(&instance->status_check_timer, jiffies + msecs_to_jiffies(1000)); - - return 0; -} - -static void speedtch_atm_stop(struct usbatm_data *usbatm, struct atm_dev *atm_dev) -{ - struct speedtch_instance_data *instance = usbatm->driver_data; - struct urb *int_urb = instance->int_urb; - - atm_dbg(usbatm, "%s entered\n", __func__); - - del_timer_sync(&instance->status_check_timer); - - /* - * Since resubmit_timer and int_urb can schedule themselves and - * each other, shutting them down correctly takes some care - */ - instance->int_urb = NULL; /* signal shutdown */ - mb(); - usb_kill_urb(int_urb); - del_timer_sync(&instance->resubmit_timer); - /* - * At this point, speedtch_handle_int and speedtch_resubmit_int - * can run or be running, but instance->int_urb == NULL means that - * they will not reschedule - */ - usb_kill_urb(int_urb); - del_timer_sync(&instance->resubmit_timer); - usb_free_urb(int_urb); - - flush_work_sync(&instance->status_check_work); -} - -static int speedtch_pre_reset(struct usb_interface *intf) -{ - return 0; -} - -static int speedtch_post_reset(struct usb_interface *intf) -{ - return 0; -} - - -/********** -** USB ** -**********/ - -static struct usb_device_id speedtch_usb_ids[] = { - {USB_DEVICE(0x06b9, 0x4061)}, - {} -}; - -MODULE_DEVICE_TABLE(usb, speedtch_usb_ids); - -static int speedtch_usb_probe(struct usb_interface *, const struct usb_device_id *); - -static struct usb_driver speedtch_usb_driver = { - .name = speedtch_driver_name, - .probe = speedtch_usb_probe, - .disconnect = usbatm_usb_disconnect, - .pre_reset = speedtch_pre_reset, - .post_reset = speedtch_post_reset, - .id_table = speedtch_usb_ids -}; - -static void speedtch_release_interfaces(struct usb_device *usb_dev, - int num_interfaces) -{ - struct usb_interface *cur_intf; - int i; - - for (i = 0; i < num_interfaces; i++) - if ((cur_intf = usb_ifnum_to_if(usb_dev, i))) { - usb_set_intfdata(cur_intf, NULL); - usb_driver_release_interface(&speedtch_usb_driver, cur_intf); - } -} - -static int speedtch_bind(struct usbatm_data *usbatm, - struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *usb_dev = interface_to_usbdev(intf); - struct usb_interface *cur_intf, *data_intf; - struct speedtch_instance_data *instance; - int ifnum = intf->altsetting->desc.bInterfaceNumber; - int num_interfaces = usb_dev->actconfig->desc.bNumInterfaces; - int i, ret; - int use_isoc; - - usb_dbg(usbatm, "%s entered\n", __func__); - - /* sanity checks */ - - if (usb_dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) { - usb_err(usbatm, "%s: wrong device class %d\n", __func__, usb_dev->descriptor.bDeviceClass); - return -ENODEV; - } - - if (!(data_intf = usb_ifnum_to_if(usb_dev, INTERFACE_DATA))) { - usb_err(usbatm, "%s: data interface not found!\n", __func__); - return -ENODEV; - } - - /* claim all interfaces */ - - for (i = 0; i < num_interfaces; i++) { - cur_intf = usb_ifnum_to_if(usb_dev, i); - - if ((i != ifnum) && cur_intf) { - ret = usb_driver_claim_interface(&speedtch_usb_driver, cur_intf, usbatm); - - if (ret < 0) { - usb_err(usbatm, "%s: failed to claim interface %2d (%d)!\n", __func__, i, ret); - speedtch_release_interfaces(usb_dev, i); - return ret; - } - } - } - - instance = kzalloc(sizeof(*instance), GFP_KERNEL); - - if (!instance) { - usb_err(usbatm, "%s: no memory for instance data!\n", __func__); - ret = -ENOMEM; - goto fail_release; - } - - instance->usbatm = usbatm; - - /* module parameters may change at any moment, so take a snapshot */ - instance->params.altsetting = altsetting; - instance->params.BMaxDSL = BMaxDSL; - instance->params.ModemMode = ModemMode; - memcpy(instance->params.ModemOption, DEFAULT_MODEM_OPTION, MODEM_OPTION_LENGTH); - memcpy(instance->params.ModemOption, ModemOption, num_ModemOption); - use_isoc = enable_isoc; - - if (instance->params.altsetting) - if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->params.altsetting)) < 0) { - usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, instance->params.altsetting, ret); - instance->params.altsetting = 0; /* fall back to default */ - } - - if (!instance->params.altsetting && use_isoc) - if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_ISOC_ALTSETTING)) < 0) { - usb_dbg(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_ISOC_ALTSETTING, ret); - use_isoc = 0; /* fall back to bulk */ - } - - if (use_isoc) { - const struct usb_host_interface *desc = data_intf->cur_altsetting; - const __u8 target_address = USB_DIR_IN | usbatm->driver->isoc_in; - - use_isoc = 0; /* fall back to bulk if endpoint not found */ - - for (i = 0; i < desc->desc.bNumEndpoints; i++) { - const struct usb_endpoint_descriptor *endpoint_desc = &desc->endpoint[i].desc; - - if ((endpoint_desc->bEndpointAddress == target_address)) { - use_isoc = - usb_endpoint_xfer_isoc(endpoint_desc); - break; - } - } - - if (!use_isoc) - usb_info(usbatm, "isochronous transfer not supported - using bulk\n"); - } - - if (!use_isoc && !instance->params.altsetting) - if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_BULK_ALTSETTING)) < 0) { - usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_BULK_ALTSETTING, ret); - goto fail_free; - } - - if (!instance->params.altsetting) - instance->params.altsetting = use_isoc ? DEFAULT_ISOC_ALTSETTING : DEFAULT_BULK_ALTSETTING; - - usbatm->flags |= (use_isoc ? UDSL_USE_ISOC : 0); - - INIT_WORK(&instance->status_check_work, speedtch_check_status); - init_timer(&instance->status_check_timer); - - instance->status_check_timer.function = speedtch_status_poll; - instance->status_check_timer.data = (unsigned long)instance; - instance->last_status = 0xff; - instance->poll_delay = MIN_POLL_DELAY; - - init_timer(&instance->resubmit_timer); - instance->resubmit_timer.function = speedtch_resubmit_int; - instance->resubmit_timer.data = (unsigned long)instance; - - instance->int_urb = usb_alloc_urb(0, GFP_KERNEL); - - if (instance->int_urb) - usb_fill_int_urb(instance->int_urb, usb_dev, - usb_rcvintpipe(usb_dev, ENDPOINT_INT), - instance->int_data, sizeof(instance->int_data), - speedtch_handle_int, instance, 50); - else - usb_dbg(usbatm, "%s: no memory for interrupt urb!\n", __func__); - - /* check whether the modem already seems to be alive */ - ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), - 0x12, 0xc0, 0x07, 0x00, - instance->scratch_buffer + OFFSET_7, SIZE_7, 500); - - usbatm->flags |= (ret == SIZE_7 ? UDSL_SKIP_HEAVY_INIT : 0); - - usb_dbg(usbatm, "%s: firmware %s loaded\n", __func__, usbatm->flags & UDSL_SKIP_HEAVY_INIT ? "already" : "not"); - - if (!(usbatm->flags & UDSL_SKIP_HEAVY_INIT)) - if ((ret = usb_reset_device(usb_dev)) < 0) { - usb_err(usbatm, "%s: device reset failed (%d)!\n", __func__, ret); - goto fail_free; - } - - usbatm->driver_data = instance; - - return 0; - -fail_free: - usb_free_urb(instance->int_urb); - kfree(instance); -fail_release: - speedtch_release_interfaces(usb_dev, num_interfaces); - return ret; -} - -static void speedtch_unbind(struct usbatm_data *usbatm, struct usb_interface *intf) -{ - struct usb_device *usb_dev = interface_to_usbdev(intf); - struct speedtch_instance_data *instance = usbatm->driver_data; - - usb_dbg(usbatm, "%s entered\n", __func__); - - speedtch_release_interfaces(usb_dev, usb_dev->actconfig->desc.bNumInterfaces); - usb_free_urb(instance->int_urb); - kfree(instance); -} - - -/*********** -** init ** -***********/ - -static struct usbatm_driver speedtch_usbatm_driver = { - .driver_name = speedtch_driver_name, - .bind = speedtch_bind, - .heavy_init = speedtch_heavy_init, - .unbind = speedtch_unbind, - .atm_start = speedtch_atm_start, - .atm_stop = speedtch_atm_stop, - .bulk_in = ENDPOINT_BULK_DATA, - .bulk_out = ENDPOINT_BULK_DATA, - .isoc_in = ENDPOINT_ISOC_DATA -}; - -static int speedtch_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - return usbatm_usb_probe(intf, id, &speedtch_usbatm_driver); -} - -module_usb_driver(speedtch_usb_driver); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRIVER_VERSION); diff --git a/ANDROID_3.4.5/drivers/usb/atm/ueagle-atm.c b/ANDROID_3.4.5/drivers/usb/atm/ueagle-atm.c deleted file mode 100644 index 01ea5d74..00000000 --- a/ANDROID_3.4.5/drivers/usb/atm/ueagle-atm.c +++ /dev/null @@ -1,2760 +0,0 @@ -/*- - * Copyright (c) 2003, 2004 - * Damien Bergamini . All rights reserved. - * - * Copyright (c) 2005-2007 Matthieu Castet - * Copyright (c) 2005-2007 Stanislaw Gruszka - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * BSD license below: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice unmodified, this list of conditions, and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * GPL license : - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * - * HISTORY : some part of the code was base on ueagle 1.3 BSD driver, - * Damien Bergamini agree to put his code under a DUAL GPL/BSD license. - * - * The rest of the code was was rewritten from scratch. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "usbatm.h" - -#define EAGLEUSBVERSION "ueagle 1.4" - - -/* - * Debug macros - */ -#define uea_dbg(usb_dev, format, args...) \ - do { \ - if (debug >= 1) \ - dev_dbg(&(usb_dev)->dev, \ - "[ueagle-atm dbg] %s: " format, \ - __func__, ##args); \ - } while (0) - -#define uea_vdbg(usb_dev, format, args...) \ - do { \ - if (debug >= 2) \ - dev_dbg(&(usb_dev)->dev, \ - "[ueagle-atm vdbg] " format, ##args); \ - } while (0) - -#define uea_enters(usb_dev) \ - uea_vdbg(usb_dev, "entering %s\n" , __func__) - -#define uea_leaves(usb_dev) \ - uea_vdbg(usb_dev, "leaving %s\n" , __func__) - -#define uea_err(usb_dev, format, args...) \ - dev_err(&(usb_dev)->dev , "[UEAGLE-ATM] " format , ##args) - -#define uea_warn(usb_dev, format, args...) \ - dev_warn(&(usb_dev)->dev , "[Ueagle-atm] " format, ##args) - -#define uea_info(usb_dev, format, args...) \ - dev_info(&(usb_dev)->dev , "[ueagle-atm] " format, ##args) - -struct intr_pkt; - -/* cmv's from firmware */ -struct uea_cmvs_v1 { - u32 address; - u16 offset; - u32 data; -} __packed; - -struct uea_cmvs_v2 { - u32 group; - u32 address; - u32 offset; - u32 data; -} __packed; - -/* information about currently processed cmv */ -struct cmv_dsc_e1 { - u8 function; - u16 idx; - u32 address; - u16 offset; -}; - -struct cmv_dsc_e4 { - u16 function; - u16 offset; - u16 address; - u16 group; -}; - -union cmv_dsc { - struct cmv_dsc_e1 e1; - struct cmv_dsc_e4 e4; -}; - -struct uea_softc { - struct usb_device *usb_dev; - struct usbatm_data *usbatm; - - int modem_index; - unsigned int driver_info; - int annex; -#define ANNEXA 0 -#define ANNEXB 1 - - int booting; - int reset; - - wait_queue_head_t sync_q; - - struct task_struct *kthread; - u32 data; - u32 data1; - - int cmv_ack; - union cmv_dsc cmv_dsc; - - struct work_struct task; - u16 pageno; - u16 ovl; - - const struct firmware *dsp_firm; - struct urb *urb_int; - - void (*dispatch_cmv) (struct uea_softc *, struct intr_pkt *); - void (*schedule_load_page) (struct uea_softc *, struct intr_pkt *); - int (*stat) (struct uea_softc *); - int (*send_cmvs) (struct uea_softc *); - - /* keep in sync with eaglectl */ - struct uea_stats { - struct { - u32 state; - u32 flags; - u32 mflags; - u32 vidcpe; - u32 vidco; - u32 dsrate; - u32 usrate; - u32 dsunc; - u32 usunc; - u32 dscorr; - u32 uscorr; - u32 txflow; - u32 rxflow; - u32 usattenuation; - u32 dsattenuation; - u32 dsmargin; - u32 usmargin; - u32 firmid; - } phy; - } stats; -}; - -/* - * Elsa IDs - */ -#define ELSA_VID 0x05CC -#define ELSA_PID_PSTFIRM 0x3350 -#define ELSA_PID_PREFIRM 0x3351 - -#define ELSA_PID_A_PREFIRM 0x3352 -#define ELSA_PID_A_PSTFIRM 0x3353 -#define ELSA_PID_B_PREFIRM 0x3362 -#define ELSA_PID_B_PSTFIRM 0x3363 - -/* - * Devolo IDs : pots if (pid & 0x10) - */ -#define DEVOLO_VID 0x1039 -#define DEVOLO_EAGLE_I_A_PID_PSTFIRM 0x2110 -#define DEVOLO_EAGLE_I_A_PID_PREFIRM 0x2111 - -#define DEVOLO_EAGLE_I_B_PID_PSTFIRM 0x2100 -#define DEVOLO_EAGLE_I_B_PID_PREFIRM 0x2101 - -#define DEVOLO_EAGLE_II_A_PID_PSTFIRM 0x2130 -#define DEVOLO_EAGLE_II_A_PID_PREFIRM 0x2131 - -#define DEVOLO_EAGLE_II_B_PID_PSTFIRM 0x2120 -#define DEVOLO_EAGLE_II_B_PID_PREFIRM 0x2121 - -/* - * Reference design USB IDs - */ -#define ANALOG_VID 0x1110 -#define ADI930_PID_PREFIRM 0x9001 -#define ADI930_PID_PSTFIRM 0x9000 - -#define EAGLE_I_PID_PREFIRM 0x9010 /* Eagle I */ -#define EAGLE_I_PID_PSTFIRM 0x900F /* Eagle I */ - -#define EAGLE_IIC_PID_PREFIRM 0x9024 /* Eagle IIC */ -#define EAGLE_IIC_PID_PSTFIRM 0x9023 /* Eagle IIC */ - -#define EAGLE_II_PID_PREFIRM 0x9022 /* Eagle II */ -#define EAGLE_II_PID_PSTFIRM 0x9021 /* Eagle II */ - -#define EAGLE_III_PID_PREFIRM 0x9032 /* Eagle III */ -#define EAGLE_III_PID_PSTFIRM 0x9031 /* Eagle III */ - -#define EAGLE_IV_PID_PREFIRM 0x9042 /* Eagle IV */ -#define EAGLE_IV_PID_PSTFIRM 0x9041 /* Eagle IV */ - -/* - * USR USB IDs - */ -#define USR_VID 0x0BAF -#define MILLER_A_PID_PREFIRM 0x00F2 -#define MILLER_A_PID_PSTFIRM 0x00F1 -#define MILLER_B_PID_PREFIRM 0x00FA -#define MILLER_B_PID_PSTFIRM 0x00F9 -#define HEINEKEN_A_PID_PREFIRM 0x00F6 -#define HEINEKEN_A_PID_PSTFIRM 0x00F5 -#define HEINEKEN_B_PID_PREFIRM 0x00F8 -#define HEINEKEN_B_PID_PSTFIRM 0x00F7 - -#define PREFIRM 0 -#define PSTFIRM (1<<7) -#define AUTO_ANNEX_A (1<<8) -#define AUTO_ANNEX_B (1<<9) - -enum { - ADI930 = 0, - EAGLE_I, - EAGLE_II, - EAGLE_III, - EAGLE_IV -}; - -/* macros for both struct usb_device_id and struct uea_softc */ -#define UEA_IS_PREFIRM(x) \ - (!((x)->driver_info & PSTFIRM)) -#define UEA_CHIP_VERSION(x) \ - ((x)->driver_info & 0xf) - -#define IS_ISDN(x) \ - ((x)->annex & ANNEXB) - -#define INS_TO_USBDEV(ins) (ins->usb_dev) - -#define GET_STATUS(data) \ - ((data >> 8) & 0xf) - -#define IS_OPERATIONAL(sc) \ - ((UEA_CHIP_VERSION(sc) != EAGLE_IV) ? \ - (GET_STATUS(sc->stats.phy.state) == 2) : \ - (sc->stats.phy.state == 7)) - -/* - * Set of macros to handle unaligned data in the firmware blob. - * The FW_GET_BYTE() macro is provided only for consistency. - */ - -#define FW_GET_BYTE(p) (*((__u8 *) (p))) - -#define FW_DIR "ueagle-atm/" -#define UEA_FW_NAME_MAX 30 -#define NB_MODEM 4 - -#define BULK_TIMEOUT 300 -#define CTRL_TIMEOUT 1000 - -#define ACK_TIMEOUT msecs_to_jiffies(3000) - -#define UEA_INTR_IFACE_NO 0 -#define UEA_US_IFACE_NO 1 -#define UEA_DS_IFACE_NO 2 - -#define FASTEST_ISO_INTF 8 - -#define UEA_BULK_DATA_PIPE 0x02 -#define UEA_IDMA_PIPE 0x04 -#define UEA_INTR_PIPE 0x04 -#define UEA_ISO_DATA_PIPE 0x08 - -#define UEA_E1_SET_BLOCK 0x0001 -#define UEA_E4_SET_BLOCK 0x002c -#define UEA_SET_MODE 0x0003 -#define UEA_SET_2183_DATA 0x0004 -#define UEA_SET_TIMEOUT 0x0011 - -#define UEA_LOOPBACK_OFF 0x0002 -#define UEA_LOOPBACK_ON 0x0003 -#define UEA_BOOT_IDMA 0x0006 -#define UEA_START_RESET 0x0007 -#define UEA_END_RESET 0x0008 - -#define UEA_SWAP_MAILBOX (0x3fcd | 0x4000) -#define UEA_MPTX_START (0x3fce | 0x4000) -#define UEA_MPTX_MAILBOX (0x3fd6 | 0x4000) -#define UEA_MPRX_MAILBOX (0x3fdf | 0x4000) - -/* block information in eagle4 dsp firmware */ -struct block_index { - __le32 PageOffset; - __le32 NotLastBlock; - __le32 dummy; - __le32 PageSize; - __le32 PageAddress; - __le16 dummy1; - __le16 PageNumber; -} __packed; - -#define E4_IS_BOOT_PAGE(PageSize) ((le32_to_cpu(PageSize)) & 0x80000000) -#define E4_PAGE_BYTES(PageSize) ((le32_to_cpu(PageSize) & 0x7fffffff) * 4) - -#define E4_L1_STRING_HEADER 0x10 -#define E4_MAX_PAGE_NUMBER 0x58 -#define E4_NO_SWAPPAGE_HEADERS 0x31 - -/* l1_code is eagle4 dsp firmware format */ -struct l1_code { - u8 string_header[E4_L1_STRING_HEADER]; - u8 page_number_to_block_index[E4_MAX_PAGE_NUMBER]; - struct block_index page_header[E4_NO_SWAPPAGE_HEADERS]; - u8 code[0]; -} __packed; - -/* structures describing a block within a DSP page */ -struct block_info_e1 { - __le16 wHdr; - __le16 wAddress; - __le16 wSize; - __le16 wOvlOffset; - __le16 wOvl; /* overlay */ - __le16 wLast; -} __packed; -#define E1_BLOCK_INFO_SIZE 12 - -struct block_info_e4 { - __be16 wHdr; - __u8 bBootPage; - __u8 bPageNumber; - __be32 dwSize; - __be32 dwAddress; - __be16 wReserved; -} __packed; -#define E4_BLOCK_INFO_SIZE 14 - -#define UEA_BIHDR 0xabcd -#define UEA_RESERVED 0xffff - -/* constants describing cmv type */ -#define E1_PREAMBLE 0x535c -#define E1_MODEMTOHOST 0x01 -#define E1_HOSTTOMODEM 0x10 - -#define E1_MEMACCESS 0x1 -#define E1_ADSLDIRECTIVE 0x7 -#define E1_FUNCTION_TYPE(f) ((f) >> 4) -#define E1_FUNCTION_SUBTYPE(f) ((f) & 0x0f) - -#define E4_MEMACCESS 0 -#define E4_ADSLDIRECTIVE 0xf -#define E4_FUNCTION_TYPE(f) ((f) >> 8) -#define E4_FUNCTION_SIZE(f) ((f) & 0x0f) -#define E4_FUNCTION_SUBTYPE(f) (((f) >> 4) & 0x0f) - -/* for MEMACCESS */ -#define E1_REQUESTREAD 0x0 -#define E1_REQUESTWRITE 0x1 -#define E1_REPLYREAD 0x2 -#define E1_REPLYWRITE 0x3 - -#define E4_REQUESTREAD 0x0 -#define E4_REQUESTWRITE 0x4 -#define E4_REPLYREAD (E4_REQUESTREAD | 1) -#define E4_REPLYWRITE (E4_REQUESTWRITE | 1) - -/* for ADSLDIRECTIVE */ -#define E1_KERNELREADY 0x0 -#define E1_MODEMREADY 0x1 - -#define E4_KERNELREADY 0x0 -#define E4_MODEMREADY 0x1 - -#define E1_MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf)) -#define E4_MAKEFUNCTION(t, st, s) (((t) & 0xf) << 8 | \ - ((st) & 0xf) << 4 | ((s) & 0xf)) - -#define E1_MAKESA(a, b, c, d) \ - (((c) & 0xff) << 24 | \ - ((d) & 0xff) << 16 | \ - ((a) & 0xff) << 8 | \ - ((b) & 0xff)) - -#define E1_GETSA1(a) ((a >> 8) & 0xff) -#define E1_GETSA2(a) (a & 0xff) -#define E1_GETSA3(a) ((a >> 24) & 0xff) -#define E1_GETSA4(a) ((a >> 16) & 0xff) - -#define E1_SA_CNTL E1_MAKESA('C', 'N', 'T', 'L') -#define E1_SA_DIAG E1_MAKESA('D', 'I', 'A', 'G') -#define E1_SA_INFO E1_MAKESA('I', 'N', 'F', 'O') -#define E1_SA_OPTN E1_MAKESA('O', 'P', 'T', 'N') -#define E1_SA_RATE E1_MAKESA('R', 'A', 'T', 'E') -#define E1_SA_STAT E1_MAKESA('S', 'T', 'A', 'T') - -#define E4_SA_CNTL 1 -#define E4_SA_STAT 2 -#define E4_SA_INFO 3 -#define E4_SA_TEST 4 -#define E4_SA_OPTN 5 -#define E4_SA_RATE 6 -#define E4_SA_DIAG 7 -#define E4_SA_CNFG 8 - -/* structures representing a CMV (Configuration and Management Variable) */ -struct cmv_e1 { - __le16 wPreamble; - __u8 bDirection; - __u8 bFunction; - __le16 wIndex; - __le32 dwSymbolicAddress; - __le16 wOffsetAddress; - __le32 dwData; -} __packed; - -struct cmv_e4 { - __be16 wGroup; - __be16 wFunction; - __be16 wOffset; - __be16 wAddress; - __be32 dwData[6]; -} __packed; - -/* structures representing swap information */ -struct swap_info_e1 { - __u8 bSwapPageNo; - __u8 bOvl; /* overlay */ -} __packed; - -struct swap_info_e4 { - __u8 bSwapPageNo; -} __packed; - -/* structures representing interrupt data */ -#define e1_bSwapPageNo u.e1.s1.swapinfo.bSwapPageNo -#define e1_bOvl u.e1.s1.swapinfo.bOvl -#define e4_bSwapPageNo u.e4.s1.swapinfo.bSwapPageNo - -#define INT_LOADSWAPPAGE 0x0001 -#define INT_INCOMINGCMV 0x0002 - -union intr_data_e1 { - struct { - struct swap_info_e1 swapinfo; - __le16 wDataSize; - } __packed s1; - struct { - struct cmv_e1 cmv; - __le16 wDataSize; - } __packed s2; -} __packed; - -union intr_data_e4 { - struct { - struct swap_info_e4 swapinfo; - __le16 wDataSize; - } __packed s1; - struct { - struct cmv_e4 cmv; - __le16 wDataSize; - } __packed s2; -} __packed; - -struct intr_pkt { - __u8 bType; - __u8 bNotification; - __le16 wValue; - __le16 wIndex; - __le16 wLength; - __le16 wInterrupt; - union { - union intr_data_e1 e1; - union intr_data_e4 e4; - } u; -} __packed; - -#define E1_INTR_PKT_SIZE 28 -#define E4_INTR_PKT_SIZE 64 - -static struct usb_driver uea_driver; -static DEFINE_MUTEX(uea_mutex); -static const char * const chip_name[] = { - "ADI930", "Eagle I", "Eagle II", "Eagle III", "Eagle IV"}; - -static int modem_index; -static unsigned int debug; -static unsigned int altsetting[NB_MODEM] = { - [0 ... (NB_MODEM - 1)] = FASTEST_ISO_INTF}; -static bool sync_wait[NB_MODEM]; -static char *cmv_file[NB_MODEM]; -static int annex[NB_MODEM]; - -module_param(debug, uint, 0644); -MODULE_PARM_DESC(debug, "module debug level (0=off,1=on,2=verbose)"); -module_param_array(altsetting, uint, NULL, 0644); -MODULE_PARM_DESC(altsetting, "alternate setting for incoming traffic: 0=bulk, " - "1=isoc slowest, ... , 8=isoc fastest (default)"); -module_param_array(sync_wait, bool, NULL, 0644); -MODULE_PARM_DESC(sync_wait, "wait the synchronisation before starting ATM"); -module_param_array(cmv_file, charp, NULL, 0644); -MODULE_PARM_DESC(cmv_file, - "file name with configuration and management variables"); -module_param_array(annex, uint, NULL, 0644); -MODULE_PARM_DESC(annex, - "manually set annex a/b (0=auto, 1=annex a, 2=annex b)"); - -#define uea_wait(sc, cond, timeo) \ -({ \ - int _r = wait_event_interruptible_timeout(sc->sync_q, \ - (cond) || kthread_should_stop(), timeo); \ - if (kthread_should_stop()) \ - _r = -ENODEV; \ - _r; \ -}) - -#define UPDATE_ATM_STAT(type, val) \ - do { \ - if (sc->usbatm->atm_dev) \ - sc->usbatm->atm_dev->type = val; \ - } while (0) - -#define UPDATE_ATM_SIGNAL(val) \ - do { \ - if (sc->usbatm->atm_dev) \ - atm_dev_signal_change(sc->usbatm->atm_dev, val); \ - } while (0) - - -/* Firmware loading */ -#define LOAD_INTERNAL 0xA0 -#define F8051_USBCS 0x7f92 - -/** - * uea_send_modem_cmd - Send a command for pre-firmware devices. - */ -static int uea_send_modem_cmd(struct usb_device *usb, - u16 addr, u16 size, const u8 *buff) -{ - int ret = -ENOMEM; - u8 *xfer_buff; - - xfer_buff = kmemdup(buff, size, GFP_KERNEL); - if (xfer_buff) { - ret = usb_control_msg(usb, - usb_sndctrlpipe(usb, 0), - LOAD_INTERNAL, - USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, addr, 0, xfer_buff, - size, CTRL_TIMEOUT); - kfree(xfer_buff); - } - - if (ret < 0) - return ret; - - return (ret == size) ? 0 : -EIO; -} - -static void uea_upload_pre_firmware(const struct firmware *fw_entry, - void *context) -{ - struct usb_device *usb = context; - const u8 *pfw; - u8 value; - u32 crc = 0; - int ret, size; - - uea_enters(usb); - if (!fw_entry) { - uea_err(usb, "firmware is not available\n"); - goto err; - } - - pfw = fw_entry->data; - size = fw_entry->size; - if (size < 4) - goto err_fw_corrupted; - - crc = get_unaligned_le32(pfw); - pfw += 4; - size -= 4; - if (crc32_be(0, pfw, size) != crc) - goto err_fw_corrupted; - - /* - * Start to upload firmware : send reset - */ - value = 1; - ret = uea_send_modem_cmd(usb, F8051_USBCS, sizeof(value), &value); - - if (ret < 0) { - uea_err(usb, "modem reset failed with error %d\n", ret); - goto err; - } - - while (size > 3) { - u8 len = FW_GET_BYTE(pfw); - u16 add = get_unaligned_le16(pfw + 1); - - size -= len + 3; - if (size < 0) - goto err_fw_corrupted; - - ret = uea_send_modem_cmd(usb, add, len, pfw + 3); - if (ret < 0) { - uea_err(usb, "uploading firmware data failed " - "with error %d\n", ret); - goto err; - } - pfw += len + 3; - } - - if (size != 0) - goto err_fw_corrupted; - - /* - * Tell the modem we finish : de-assert reset - */ - value = 0; - ret = uea_send_modem_cmd(usb, F8051_USBCS, 1, &value); - if (ret < 0) - uea_err(usb, "modem de-assert failed with error %d\n", ret); - else - uea_info(usb, "firmware uploaded\n"); - - goto err; - -err_fw_corrupted: - uea_err(usb, "firmware is corrupted\n"); -err: - release_firmware(fw_entry); - uea_leaves(usb); -} - -/** - * uea_load_firmware - Load usb firmware for pre-firmware devices. - */ -static int uea_load_firmware(struct usb_device *usb, unsigned int ver) -{ - int ret; - char *fw_name = FW_DIR "eagle.fw"; - - uea_enters(usb); - uea_info(usb, "pre-firmware device, uploading firmware\n"); - - switch (ver) { - case ADI930: - fw_name = FW_DIR "adi930.fw"; - break; - case EAGLE_I: - fw_name = FW_DIR "eagleI.fw"; - break; - case EAGLE_II: - fw_name = FW_DIR "eagleII.fw"; - break; - case EAGLE_III: - fw_name = FW_DIR "eagleIII.fw"; - break; - case EAGLE_IV: - fw_name = FW_DIR "eagleIV.fw"; - break; - } - - ret = request_firmware_nowait(THIS_MODULE, 1, fw_name, &usb->dev, - GFP_KERNEL, usb, - uea_upload_pre_firmware); - if (ret) - uea_err(usb, "firmware %s is not available\n", fw_name); - else - uea_info(usb, "loading firmware %s\n", fw_name); - - uea_leaves(usb); - return ret; -} - -/* modem management : dsp firmware, send/read CMV, monitoring statistic - */ - -/* - * Make sure that the DSP code provided is safe to use. - */ -static int check_dsp_e1(const u8 *dsp, unsigned int len) -{ - u8 pagecount, blockcount; - u16 blocksize; - u32 pageoffset; - unsigned int i, j, p, pp; - - pagecount = FW_GET_BYTE(dsp); - p = 1; - - /* enough space for page offsets? */ - if (p + 4 * pagecount > len) - return 1; - - for (i = 0; i < pagecount; i++) { - - pageoffset = get_unaligned_le32(dsp + p); - p += 4; - - if (pageoffset == 0) - continue; - - /* enough space for blockcount? */ - if (pageoffset >= len) - return 1; - - pp = pageoffset; - blockcount = FW_GET_BYTE(dsp + pp); - pp += 1; - - for (j = 0; j < blockcount; j++) { - - /* enough space for block header? */ - if (pp + 4 > len) - return 1; - - pp += 2; /* skip blockaddr */ - blocksize = get_unaligned_le16(dsp + pp); - pp += 2; - - /* enough space for block data? */ - if (pp + blocksize > len) - return 1; - - pp += blocksize; - } - } - - return 0; -} - -static int check_dsp_e4(const u8 *dsp, int len) -{ - int i; - struct l1_code *p = (struct l1_code *) dsp; - unsigned int sum = p->code - dsp; - - if (len < sum) - return 1; - - if (strcmp("STRATIPHY ANEXA", p->string_header) != 0 && - strcmp("STRATIPHY ANEXB", p->string_header) != 0) - return 1; - - for (i = 0; i < E4_MAX_PAGE_NUMBER; i++) { - struct block_index *blockidx; - u8 blockno = p->page_number_to_block_index[i]; - if (blockno >= E4_NO_SWAPPAGE_HEADERS) - continue; - - do { - u64 l; - - if (blockno >= E4_NO_SWAPPAGE_HEADERS) - return 1; - - blockidx = &p->page_header[blockno++]; - if ((u8 *)(blockidx + 1) - dsp >= len) - return 1; - - if (le16_to_cpu(blockidx->PageNumber) != i) - return 1; - - l = E4_PAGE_BYTES(blockidx->PageSize); - sum += l; - l += le32_to_cpu(blockidx->PageOffset); - if (l > len) - return 1; - - /* zero is zero regardless endianes */ - } while (blockidx->NotLastBlock); - } - - return (sum == len) ? 0 : 1; -} - -/* - * send data to the idma pipe - * */ -static int uea_idma_write(struct uea_softc *sc, const void *data, u32 size) -{ - int ret = -ENOMEM; - u8 *xfer_buff; - int bytes_read; - - xfer_buff = kmemdup(data, size, GFP_KERNEL); - if (!xfer_buff) { - uea_err(INS_TO_USBDEV(sc), "can't allocate xfer_buff\n"); - return ret; - } - - ret = usb_bulk_msg(sc->usb_dev, - usb_sndbulkpipe(sc->usb_dev, UEA_IDMA_PIPE), - xfer_buff, size, &bytes_read, BULK_TIMEOUT); - - kfree(xfer_buff); - if (ret < 0) - return ret; - if (size != bytes_read) { - uea_err(INS_TO_USBDEV(sc), "size != bytes_read %d %d\n", size, - bytes_read); - return -EIO; - } - - return 0; -} - -static int request_dsp(struct uea_softc *sc) -{ - int ret; - char *dsp_name; - - if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { - if (IS_ISDN(sc)) - dsp_name = FW_DIR "DSP4i.bin"; - else - dsp_name = FW_DIR "DSP4p.bin"; - } else if (UEA_CHIP_VERSION(sc) == ADI930) { - if (IS_ISDN(sc)) - dsp_name = FW_DIR "DSP9i.bin"; - else - dsp_name = FW_DIR "DSP9p.bin"; - } else { - if (IS_ISDN(sc)) - dsp_name = FW_DIR "DSPei.bin"; - else - dsp_name = FW_DIR "DSPep.bin"; - } - - ret = request_firmware(&sc->dsp_firm, dsp_name, &sc->usb_dev->dev); - if (ret < 0) { - uea_err(INS_TO_USBDEV(sc), - "requesting firmware %s failed with error %d\n", - dsp_name, ret); - return ret; - } - - if (UEA_CHIP_VERSION(sc) == EAGLE_IV) - ret = check_dsp_e4(sc->dsp_firm->data, sc->dsp_firm->size); - else - ret = check_dsp_e1(sc->dsp_firm->data, sc->dsp_firm->size); - - if (ret) { - uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", - dsp_name); - release_firmware(sc->dsp_firm); - sc->dsp_firm = NULL; - return -EILSEQ; - } - - return 0; -} - -/* - * The uea_load_page() function must be called within a process context - */ -static void uea_load_page_e1(struct work_struct *work) -{ - struct uea_softc *sc = container_of(work, struct uea_softc, task); - u16 pageno = sc->pageno; - u16 ovl = sc->ovl; - struct block_info_e1 bi; - - const u8 *p; - u8 pagecount, blockcount; - u16 blockaddr, blocksize; - u32 pageoffset; - int i; - - /* reload firmware when reboot start and it's loaded already */ - if (ovl == 0 && pageno == 0 && sc->dsp_firm) { - release_firmware(sc->dsp_firm); - sc->dsp_firm = NULL; - } - - if (sc->dsp_firm == NULL && request_dsp(sc) < 0) - return; - - p = sc->dsp_firm->data; - pagecount = FW_GET_BYTE(p); - p += 1; - - if (pageno >= pagecount) - goto bad1; - - p += 4 * pageno; - pageoffset = get_unaligned_le32(p); - - if (pageoffset == 0) - goto bad1; - - p = sc->dsp_firm->data + pageoffset; - blockcount = FW_GET_BYTE(p); - p += 1; - - uea_dbg(INS_TO_USBDEV(sc), - "sending %u blocks for DSP page %u\n", blockcount, pageno); - - bi.wHdr = cpu_to_le16(UEA_BIHDR); - bi.wOvl = cpu_to_le16(ovl); - bi.wOvlOffset = cpu_to_le16(ovl | 0x8000); - - for (i = 0; i < blockcount; i++) { - blockaddr = get_unaligned_le16(p); - p += 2; - - blocksize = get_unaligned_le16(p); - p += 2; - - bi.wSize = cpu_to_le16(blocksize); - bi.wAddress = cpu_to_le16(blockaddr); - bi.wLast = cpu_to_le16((i == blockcount - 1) ? 1 : 0); - - /* send block info through the IDMA pipe */ - if (uea_idma_write(sc, &bi, E1_BLOCK_INFO_SIZE)) - goto bad2; - - /* send block data through the IDMA pipe */ - if (uea_idma_write(sc, p, blocksize)) - goto bad2; - - p += blocksize; - } - - return; - -bad2: - uea_err(INS_TO_USBDEV(sc), "sending DSP block %u failed\n", i); - return; -bad1: - uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno); -} - -static void __uea_load_page_e4(struct uea_softc *sc, u8 pageno, int boot) -{ - struct block_info_e4 bi; - struct block_index *blockidx; - struct l1_code *p = (struct l1_code *) sc->dsp_firm->data; - u8 blockno = p->page_number_to_block_index[pageno]; - - bi.wHdr = cpu_to_be16(UEA_BIHDR); - bi.bBootPage = boot; - bi.bPageNumber = pageno; - bi.wReserved = cpu_to_be16(UEA_RESERVED); - - do { - const u8 *blockoffset; - unsigned int blocksize; - - blockidx = &p->page_header[blockno]; - blocksize = E4_PAGE_BYTES(blockidx->PageSize); - blockoffset = sc->dsp_firm->data + le32_to_cpu( - blockidx->PageOffset); - - bi.dwSize = cpu_to_be32(blocksize); - bi.dwAddress = cpu_to_be32(le32_to_cpu(blockidx->PageAddress)); - - uea_dbg(INS_TO_USBDEV(sc), - "sending block %u for DSP page " - "%u size %u address %x\n", - blockno, pageno, blocksize, - le32_to_cpu(blockidx->PageAddress)); - - /* send block info through the IDMA pipe */ - if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE)) - goto bad; - - /* send block data through the IDMA pipe */ - if (uea_idma_write(sc, blockoffset, blocksize)) - goto bad; - - blockno++; - } while (blockidx->NotLastBlock); - - return; - -bad: - uea_err(INS_TO_USBDEV(sc), "sending DSP block %u failed\n", blockno); - return; -} - -static void uea_load_page_e4(struct work_struct *work) -{ - struct uea_softc *sc = container_of(work, struct uea_softc, task); - u8 pageno = sc->pageno; - int i; - struct block_info_e4 bi; - struct l1_code *p; - - uea_dbg(INS_TO_USBDEV(sc), "sending DSP page %u\n", pageno); - - /* reload firmware when reboot start and it's loaded already */ - if (pageno == 0 && sc->dsp_firm) { - release_firmware(sc->dsp_firm); - sc->dsp_firm = NULL; - } - - if (sc->dsp_firm == NULL && request_dsp(sc) < 0) - return; - - p = (struct l1_code *) sc->dsp_firm->data; - if (pageno >= le16_to_cpu(p->page_header[0].PageNumber)) { - uea_err(INS_TO_USBDEV(sc), "invalid DSP " - "page %u requested\n", pageno); - return; - } - - if (pageno != 0) { - __uea_load_page_e4(sc, pageno, 0); - return; - } - - uea_dbg(INS_TO_USBDEV(sc), - "sending Main DSP page %u\n", p->page_header[0].PageNumber); - - for (i = 0; i < le16_to_cpu(p->page_header[0].PageNumber); i++) { - if (E4_IS_BOOT_PAGE(p->page_header[i].PageSize)) - __uea_load_page_e4(sc, i, 1); - } - - uea_dbg(INS_TO_USBDEV(sc) , "sending start bi\n"); - - bi.wHdr = cpu_to_be16(UEA_BIHDR); - bi.bBootPage = 0; - bi.bPageNumber = 0xff; - bi.wReserved = cpu_to_be16(UEA_RESERVED); - bi.dwSize = cpu_to_be32(E4_PAGE_BYTES(p->page_header[0].PageSize)); - bi.dwAddress = cpu_to_be32(le32_to_cpu(p->page_header[0].PageAddress)); - - /* send block info through the IDMA pipe */ - if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE)) - uea_err(INS_TO_USBDEV(sc), "sending DSP start bi failed\n"); -} - -static inline void wake_up_cmv_ack(struct uea_softc *sc) -{ - BUG_ON(sc->cmv_ack); - sc->cmv_ack = 1; - wake_up(&sc->sync_q); -} - -static inline int wait_cmv_ack(struct uea_softc *sc) -{ - int ret = uea_wait(sc, sc->cmv_ack , ACK_TIMEOUT); - - sc->cmv_ack = 0; - - uea_dbg(INS_TO_USBDEV(sc), "wait_event_timeout : %d ms\n", - jiffies_to_msecs(ret)); - - if (ret < 0) - return ret; - - return (ret == 0) ? -ETIMEDOUT : 0; -} - -#define UCDC_SEND_ENCAPSULATED_COMMAND 0x00 - -static int uea_request(struct uea_softc *sc, - u16 value, u16 index, u16 size, const void *data) -{ - u8 *xfer_buff; - int ret = -ENOMEM; - - xfer_buff = kmemdup(data, size, GFP_KERNEL); - if (!xfer_buff) { - uea_err(INS_TO_USBDEV(sc), "can't allocate xfer_buff\n"); - return ret; - } - - ret = usb_control_msg(sc->usb_dev, usb_sndctrlpipe(sc->usb_dev, 0), - UCDC_SEND_ENCAPSULATED_COMMAND, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, xfer_buff, size, CTRL_TIMEOUT); - - kfree(xfer_buff); - if (ret < 0) { - uea_err(INS_TO_USBDEV(sc), "usb_control_msg error %d\n", ret); - return ret; - } - - if (ret != size) { - uea_err(INS_TO_USBDEV(sc), - "usb_control_msg send only %d bytes (instead of %d)\n", - ret, size); - return -EIO; - } - - return 0; -} - -static int uea_cmv_e1(struct uea_softc *sc, - u8 function, u32 address, u16 offset, u32 data) -{ - struct cmv_e1 cmv; - int ret; - - uea_enters(INS_TO_USBDEV(sc)); - uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Address : %c%c%c%c, " - "offset : 0x%04x, data : 0x%08x\n", - E1_FUNCTION_TYPE(function), - E1_FUNCTION_SUBTYPE(function), - E1_GETSA1(address), E1_GETSA2(address), - E1_GETSA3(address), - E1_GETSA4(address), offset, data); - - /* we send a request, but we expect a reply */ - sc->cmv_dsc.e1.function = function | 0x2; - sc->cmv_dsc.e1.idx++; - sc->cmv_dsc.e1.address = address; - sc->cmv_dsc.e1.offset = offset; - - cmv.wPreamble = cpu_to_le16(E1_PREAMBLE); - cmv.bDirection = E1_HOSTTOMODEM; - cmv.bFunction = function; - cmv.wIndex = cpu_to_le16(sc->cmv_dsc.e1.idx); - put_unaligned_le32(address, &cmv.dwSymbolicAddress); - cmv.wOffsetAddress = cpu_to_le16(offset); - put_unaligned_le32(data >> 16 | data << 16, &cmv.dwData); - - ret = uea_request(sc, UEA_E1_SET_BLOCK, UEA_MPTX_START, - sizeof(cmv), &cmv); - if (ret < 0) - return ret; - ret = wait_cmv_ack(sc); - uea_leaves(INS_TO_USBDEV(sc)); - return ret; -} - -static int uea_cmv_e4(struct uea_softc *sc, - u16 function, u16 group, u16 address, u16 offset, u32 data) -{ - struct cmv_e4 cmv; - int ret; - - uea_enters(INS_TO_USBDEV(sc)); - memset(&cmv, 0, sizeof(cmv)); - - uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Group : 0x%04x, " - "Address : 0x%04x, offset : 0x%04x, data : 0x%08x\n", - E4_FUNCTION_TYPE(function), E4_FUNCTION_SUBTYPE(function), - group, address, offset, data); - - /* we send a request, but we expect a reply */ - sc->cmv_dsc.e4.function = function | (0x1 << 4); - sc->cmv_dsc.e4.offset = offset; - sc->cmv_dsc.e4.address = address; - sc->cmv_dsc.e4.group = group; - - cmv.wFunction = cpu_to_be16(function); - cmv.wGroup = cpu_to_be16(group); - cmv.wAddress = cpu_to_be16(address); - cmv.wOffset = cpu_to_be16(offset); - cmv.dwData[0] = cpu_to_be32(data); - - ret = uea_request(sc, UEA_E4_SET_BLOCK, UEA_MPTX_START, - sizeof(cmv), &cmv); - if (ret < 0) - return ret; - ret = wait_cmv_ack(sc); - uea_leaves(INS_TO_USBDEV(sc)); - return ret; -} - -static inline int uea_read_cmv_e1(struct uea_softc *sc, - u32 address, u16 offset, u32 *data) -{ - int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTREAD), - address, offset, 0); - if (ret < 0) - uea_err(INS_TO_USBDEV(sc), - "reading cmv failed with error %d\n", ret); - else - *data = sc->data; - - return ret; -} - -static inline int uea_read_cmv_e4(struct uea_softc *sc, - u8 size, u16 group, u16 address, u16 offset, u32 *data) -{ - int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, - E4_REQUESTREAD, size), - group, address, offset, 0); - if (ret < 0) - uea_err(INS_TO_USBDEV(sc), - "reading cmv failed with error %d\n", ret); - else { - *data = sc->data; - /* size is in 16-bit word quantities */ - if (size > 2) - *(data + 1) = sc->data1; - } - return ret; -} - -static inline int uea_write_cmv_e1(struct uea_softc *sc, - u32 address, u16 offset, u32 data) -{ - int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTWRITE), - address, offset, data); - if (ret < 0) - uea_err(INS_TO_USBDEV(sc), - "writing cmv failed with error %d\n", ret); - - return ret; -} - -static inline int uea_write_cmv_e4(struct uea_softc *sc, - u8 size, u16 group, u16 address, u16 offset, u32 data) -{ - int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, - E4_REQUESTWRITE, size), - group, address, offset, data); - if (ret < 0) - uea_err(INS_TO_USBDEV(sc), - "writing cmv failed with error %d\n", ret); - - return ret; -} - -static void uea_set_bulk_timeout(struct uea_softc *sc, u32 dsrate) -{ - int ret; - u16 timeout; - - /* in bulk mode the modem have problem with high rate - * changing internal timing could improve things, but the - * value is mysterious. - * ADI930 don't support it (-EPIPE error). - */ - - if (UEA_CHIP_VERSION(sc) == ADI930 || - altsetting[sc->modem_index] > 0 || - sc->stats.phy.dsrate == dsrate) - return; - - /* Original timming (1Mbit/s) from ADI (used in windows driver) */ - timeout = (dsrate <= 1024*1024) ? 0 : 1; - ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL); - uea_info(INS_TO_USBDEV(sc), "setting new timeout %d%s\n", - timeout, ret < 0 ? " failed" : ""); - -} - -/* - * Monitor the modem and update the stat - * return 0 if everything is ok - * return < 0 if an error occurs (-EAGAIN reboot needed) - */ -static int uea_stat_e1(struct uea_softc *sc) -{ - u32 data; - int ret; - - uea_enters(INS_TO_USBDEV(sc)); - data = sc->stats.phy.state; - - ret = uea_read_cmv_e1(sc, E1_SA_STAT, 0, &sc->stats.phy.state); - if (ret < 0) - return ret; - - switch (GET_STATUS(sc->stats.phy.state)) { - case 0: /* not yet synchronized */ - uea_dbg(INS_TO_USBDEV(sc), - "modem not yet synchronized\n"); - return 0; - - case 1: /* initialization */ - uea_dbg(INS_TO_USBDEV(sc), "modem initializing\n"); - return 0; - - case 2: /* operational */ - uea_vdbg(INS_TO_USBDEV(sc), "modem operational\n"); - break; - - case 3: /* fail ... */ - uea_info(INS_TO_USBDEV(sc), "modem synchronization failed" - " (may be try other cmv/dsp)\n"); - return -EAGAIN; - - case 4 ... 6: /* test state */ - uea_warn(INS_TO_USBDEV(sc), - "modem in test mode - not supported\n"); - return -EAGAIN; - - case 7: /* fast-retain ... */ - uea_info(INS_TO_USBDEV(sc), "modem in fast-retain mode\n"); - return 0; - default: - uea_err(INS_TO_USBDEV(sc), "modem invalid SW mode %d\n", - GET_STATUS(sc->stats.phy.state)); - return -EAGAIN; - } - - if (GET_STATUS(data) != 2) { - uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_OFF, 0, NULL); - uea_info(INS_TO_USBDEV(sc), "modem operational\n"); - - /* release the dsp firmware as it is not needed until - * the next failure - */ - if (sc->dsp_firm) { - release_firmware(sc->dsp_firm); - sc->dsp_firm = NULL; - } - } - - /* always update it as atm layer could not be init when we switch to - * operational state - */ - UPDATE_ATM_SIGNAL(ATM_PHY_SIG_FOUND); - - /* wake up processes waiting for synchronization */ - wake_up(&sc->sync_q); - - ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 2, &sc->stats.phy.flags); - if (ret < 0) - return ret; - sc->stats.phy.mflags |= sc->stats.phy.flags; - - /* in case of a flags ( for example delineation LOSS (& 0x10)), - * we check the status again in order to detect the failure earlier - */ - if (sc->stats.phy.flags) { - uea_dbg(INS_TO_USBDEV(sc), "Stat flag = 0x%x\n", - sc->stats.phy.flags); - return 0; - } - - ret = uea_read_cmv_e1(sc, E1_SA_RATE, 0, &data); - if (ret < 0) - return ret; - - uea_set_bulk_timeout(sc, (data >> 16) * 32); - sc->stats.phy.dsrate = (data >> 16) * 32; - sc->stats.phy.usrate = (data & 0xffff) * 32; - UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424); - - ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 23, &data); - if (ret < 0) - return ret; - sc->stats.phy.dsattenuation = (data & 0xff) / 2; - - ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 47, &data); - if (ret < 0) - return ret; - sc->stats.phy.usattenuation = (data & 0xff) / 2; - - ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 25, &sc->stats.phy.dsmargin); - if (ret < 0) - return ret; - - ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 49, &sc->stats.phy.usmargin); - if (ret < 0) - return ret; - - ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 51, &sc->stats.phy.rxflow); - if (ret < 0) - return ret; - - ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 52, &sc->stats.phy.txflow); - if (ret < 0) - return ret; - - ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 54, &sc->stats.phy.dsunc); - if (ret < 0) - return ret; - - /* only for atu-c */ - ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 58, &sc->stats.phy.usunc); - if (ret < 0) - return ret; - - ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 53, &sc->stats.phy.dscorr); - if (ret < 0) - return ret; - - /* only for atu-c */ - ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 57, &sc->stats.phy.uscorr); - if (ret < 0) - return ret; - - ret = uea_read_cmv_e1(sc, E1_SA_INFO, 8, &sc->stats.phy.vidco); - if (ret < 0) - return ret; - - ret = uea_read_cmv_e1(sc, E1_SA_INFO, 13, &sc->stats.phy.vidcpe); - if (ret < 0) - return ret; - - return 0; -} - -static int uea_stat_e4(struct uea_softc *sc) -{ - u32 data; - u32 tmp_arr[2]; - int ret; - - uea_enters(INS_TO_USBDEV(sc)); - data = sc->stats.phy.state; - - /* XXX only need to be done before operationnal... */ - ret = uea_read_cmv_e4(sc, 1, E4_SA_STAT, 0, 0, &sc->stats.phy.state); - if (ret < 0) - return ret; - - switch (sc->stats.phy.state) { - case 0x0: /* not yet synchronized */ - case 0x1: - case 0x3: - case 0x4: - uea_dbg(INS_TO_USBDEV(sc), "modem not yet " - "synchronized\n"); - return 0; - case 0x5: /* initialization */ - case 0x6: - case 0x9: - case 0xa: - uea_dbg(INS_TO_USBDEV(sc), "modem initializing\n"); - return 0; - case 0x2: /* fail ... */ - uea_info(INS_TO_USBDEV(sc), "modem synchronization " - "failed (may be try other cmv/dsp)\n"); - return -EAGAIN; - case 0x7: /* operational */ - break; - default: - uea_warn(INS_TO_USBDEV(sc), "unknown state: %x\n", - sc->stats.phy.state); - return 0; - } - - if (data != 7) { - uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_OFF, 0, NULL); - uea_info(INS_TO_USBDEV(sc), "modem operational\n"); - - /* release the dsp firmware as it is not needed until - * the next failure - */ - if (sc->dsp_firm) { - release_firmware(sc->dsp_firm); - sc->dsp_firm = NULL; - } - } - - /* always update it as atm layer could not be init when we switch to - * operational state - */ - UPDATE_ATM_SIGNAL(ATM_PHY_SIG_FOUND); - - /* wake up processes waiting for synchronization */ - wake_up(&sc->sync_q); - - /* TODO improve this state machine : - * we need some CMV info : what they do and their unit - * we should find the equivalent of eagle3- CMV - */ - /* check flags */ - ret = uea_read_cmv_e4(sc, 1, E4_SA_DIAG, 0, 0, &sc->stats.phy.flags); - if (ret < 0) - return ret; - sc->stats.phy.mflags |= sc->stats.phy.flags; - - /* in case of a flags ( for example delineation LOSS (& 0x10)), - * we check the status again in order to detect the failure earlier - */ - if (sc->stats.phy.flags) { - uea_dbg(INS_TO_USBDEV(sc), "Stat flag = 0x%x\n", - sc->stats.phy.flags); - if (sc->stats.phy.flags & 1) /* delineation LOSS */ - return -EAGAIN; - if (sc->stats.phy.flags & 0x4000) /* Reset Flag */ - return -EAGAIN; - return 0; - } - - /* rate data may be in upper or lower half of 64 bit word, strange */ - ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 0, 0, tmp_arr); - if (ret < 0) - return ret; - data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1]; - sc->stats.phy.usrate = data / 1000; - - ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 1, 0, tmp_arr); - if (ret < 0) - return ret; - data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1]; - uea_set_bulk_timeout(sc, data / 1000); - sc->stats.phy.dsrate = data / 1000; - UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424); - - ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 1, &data); - if (ret < 0) - return ret; - sc->stats.phy.dsattenuation = data / 10; - - ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 1, &data); - if (ret < 0) - return ret; - sc->stats.phy.usattenuation = data / 10; - - ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 3, &data); - if (ret < 0) - return ret; - sc->stats.phy.dsmargin = data / 2; - - ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 3, &data); - if (ret < 0) - return ret; - sc->stats.phy.usmargin = data / 10; - - return 0; -} - -static void cmvs_file_name(struct uea_softc *sc, char *const cmv_name, int ver) -{ - char file_arr[] = "CMVxy.bin"; - char *file; - - kparam_block_sysfs_write(cmv_file); - /* set proper name corresponding modem version and line type */ - if (cmv_file[sc->modem_index] == NULL) { - if (UEA_CHIP_VERSION(sc) == ADI930) - file_arr[3] = '9'; - else if (UEA_CHIP_VERSION(sc) == EAGLE_IV) - file_arr[3] = '4'; - else - file_arr[3] = 'e'; - - file_arr[4] = IS_ISDN(sc) ? 'i' : 'p'; - file = file_arr; - } else - file = cmv_file[sc->modem_index]; - - strcpy(cmv_name, FW_DIR); - strlcat(cmv_name, file, UEA_FW_NAME_MAX); - if (ver == 2) - strlcat(cmv_name, ".v2", UEA_FW_NAME_MAX); - kparam_unblock_sysfs_write(cmv_file); -} - -static int request_cmvs_old(struct uea_softc *sc, - void **cmvs, const struct firmware **fw) -{ - int ret, size; - u8 *data; - char cmv_name[UEA_FW_NAME_MAX]; /* 30 bytes stack variable */ - - cmvs_file_name(sc, cmv_name, 1); - ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev); - if (ret < 0) { - uea_err(INS_TO_USBDEV(sc), - "requesting firmware %s failed with error %d\n", - cmv_name, ret); - return ret; - } - - data = (u8 *) (*fw)->data; - size = (*fw)->size; - if (size < 1) - goto err_fw_corrupted; - - if (size != *data * sizeof(struct uea_cmvs_v1) + 1) - goto err_fw_corrupted; - - *cmvs = (void *)(data + 1); - return *data; - -err_fw_corrupted: - uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name); - release_firmware(*fw); - return -EILSEQ; -} - -static int request_cmvs(struct uea_softc *sc, - void **cmvs, const struct firmware **fw, int *ver) -{ - int ret, size; - u32 crc; - u8 *data; - char cmv_name[UEA_FW_NAME_MAX]; /* 30 bytes stack variable */ - - cmvs_file_name(sc, cmv_name, 2); - ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev); - if (ret < 0) { - /* if caller can handle old version, try to provide it */ - if (*ver == 1) { - uea_warn(INS_TO_USBDEV(sc), "requesting " - "firmware %s failed, " - "try to get older cmvs\n", cmv_name); - return request_cmvs_old(sc, cmvs, fw); - } - uea_err(INS_TO_USBDEV(sc), - "requesting firmware %s failed with error %d\n", - cmv_name, ret); - return ret; - } - - size = (*fw)->size; - data = (u8 *) (*fw)->data; - if (size < 4 || strncmp(data, "cmv2", 4) != 0) { - if (*ver == 1) { - uea_warn(INS_TO_USBDEV(sc), "firmware %s is corrupted," - " try to get older cmvs\n", cmv_name); - release_firmware(*fw); - return request_cmvs_old(sc, cmvs, fw); - } - goto err_fw_corrupted; - } - - *ver = 2; - - data += 4; - size -= 4; - if (size < 5) - goto err_fw_corrupted; - - crc = get_unaligned_le32(data); - data += 4; - size -= 4; - if (crc32_be(0, data, size) != crc) - goto err_fw_corrupted; - - if (size != *data * sizeof(struct uea_cmvs_v2) + 1) - goto err_fw_corrupted; - - *cmvs = (void *) (data + 1); - return *data; - -err_fw_corrupted: - uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name); - release_firmware(*fw); - return -EILSEQ; -} - -static int uea_send_cmvs_e1(struct uea_softc *sc) -{ - int i, ret, len; - void *cmvs_ptr; - const struct firmware *cmvs_fw; - int ver = 1; /* we can handle v1 cmv firmware version; */ - - /* Enter in R-IDLE (cmv) until instructed otherwise */ - ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 1); - if (ret < 0) - return ret; - - /* Dump firmware version */ - ret = uea_read_cmv_e1(sc, E1_SA_INFO, 10, &sc->stats.phy.firmid); - if (ret < 0) - return ret; - uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", - sc->stats.phy.firmid); - - /* get options */ - ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver); - if (ret < 0) - return ret; - - /* send options */ - if (ver == 1) { - struct uea_cmvs_v1 *cmvs_v1 = cmvs_ptr; - - uea_warn(INS_TO_USBDEV(sc), "use deprecated cmvs version, " - "please update your firmware\n"); - - for (i = 0; i < len; i++) { - ret = uea_write_cmv_e1(sc, - get_unaligned_le32(&cmvs_v1[i].address), - get_unaligned_le16(&cmvs_v1[i].offset), - get_unaligned_le32(&cmvs_v1[i].data)); - if (ret < 0) - goto out; - } - } else if (ver == 2) { - struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr; - - for (i = 0; i < len; i++) { - ret = uea_write_cmv_e1(sc, - get_unaligned_le32(&cmvs_v2[i].address), - (u16) get_unaligned_le32(&cmvs_v2[i].offset), - get_unaligned_le32(&cmvs_v2[i].data)); - if (ret < 0) - goto out; - } - } else { - /* This really should not happen */ - uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver); - goto out; - } - - /* Enter in R-ACT-REQ */ - ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 2); - uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n"); - uea_info(INS_TO_USBDEV(sc), "modem started, waiting " - "synchronization...\n"); -out: - release_firmware(cmvs_fw); - return ret; -} - -static int uea_send_cmvs_e4(struct uea_softc *sc) -{ - int i, ret, len; - void *cmvs_ptr; - const struct firmware *cmvs_fw; - int ver = 2; /* we can only handle v2 cmv firmware version; */ - - /* Enter in R-IDLE (cmv) until instructed otherwise */ - ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 1); - if (ret < 0) - return ret; - - /* Dump firmware version */ - /* XXX don't read the 3th byte as it is always 6 */ - ret = uea_read_cmv_e4(sc, 2, E4_SA_INFO, 55, 0, &sc->stats.phy.firmid); - if (ret < 0) - return ret; - uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", - sc->stats.phy.firmid); - - - /* get options */ - ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver); - if (ret < 0) - return ret; - - /* send options */ - if (ver == 2) { - struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr; - - for (i = 0; i < len; i++) { - ret = uea_write_cmv_e4(sc, 1, - get_unaligned_le32(&cmvs_v2[i].group), - get_unaligned_le32(&cmvs_v2[i].address), - get_unaligned_le32(&cmvs_v2[i].offset), - get_unaligned_le32(&cmvs_v2[i].data)); - if (ret < 0) - goto out; - } - } else { - /* This really should not happen */ - uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver); - goto out; - } - - /* Enter in R-ACT-REQ */ - ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 2); - uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n"); - uea_info(INS_TO_USBDEV(sc), "modem started, waiting " - "synchronization...\n"); -out: - release_firmware(cmvs_fw); - return ret; -} - -/* Start boot post firmware modem: - * - send reset commands through usb control pipe - * - start workqueue for DSP loading - * - send CMV options to modem - */ - -static int uea_start_reset(struct uea_softc *sc) -{ - u16 zero = 0; /* ;-) */ - int ret; - - uea_enters(INS_TO_USBDEV(sc)); - uea_info(INS_TO_USBDEV(sc), "(re)booting started\n"); - - /* mask interrupt */ - sc->booting = 1; - /* We need to set this here because, a ack timeout could have occurred, - * but before we start the reboot, the ack occurs and set this to 1. - * So we will failed to wait Ready CMV. - */ - sc->cmv_ack = 0; - UPDATE_ATM_SIGNAL(ATM_PHY_SIG_LOST); - - /* reset statistics */ - memset(&sc->stats, 0, sizeof(struct uea_stats)); - - /* tell the modem that we want to boot in IDMA mode */ - uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_ON, 0, NULL); - uea_request(sc, UEA_SET_MODE, UEA_BOOT_IDMA, 0, NULL); - - /* enter reset mode */ - uea_request(sc, UEA_SET_MODE, UEA_START_RESET, 0, NULL); - - /* original driver use 200ms, but windows driver use 100ms */ - ret = uea_wait(sc, 0, msecs_to_jiffies(100)); - if (ret < 0) - return ret; - - /* leave reset mode */ - uea_request(sc, UEA_SET_MODE, UEA_END_RESET, 0, NULL); - - if (UEA_CHIP_VERSION(sc) != EAGLE_IV) { - /* clear tx and rx mailboxes */ - uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero); - uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero); - uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero); - } - - ret = uea_wait(sc, 0, msecs_to_jiffies(1000)); - if (ret < 0) - return ret; - - if (UEA_CHIP_VERSION(sc) == EAGLE_IV) - sc->cmv_dsc.e4.function = E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, - E4_MODEMREADY, 1); - else - sc->cmv_dsc.e1.function = E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, - E1_MODEMREADY); - - /* demask interrupt */ - sc->booting = 0; - - /* start loading DSP */ - sc->pageno = 0; - sc->ovl = 0; - schedule_work(&sc->task); - - /* wait for modem ready CMV */ - ret = wait_cmv_ack(sc); - if (ret < 0) - return ret; - - uea_vdbg(INS_TO_USBDEV(sc), "Ready CMV received\n"); - - ret = sc->send_cmvs(sc); - if (ret < 0) - return ret; - - sc->reset = 0; - uea_leaves(INS_TO_USBDEV(sc)); - return ret; -} - -/* - * In case of an error wait 1s before rebooting the modem - * if the modem don't request reboot (-EAGAIN). - * Monitor the modem every 1s. - */ - -static int uea_kthread(void *data) -{ - struct uea_softc *sc = data; - int ret = -EAGAIN; - - set_freezable(); - uea_enters(INS_TO_USBDEV(sc)); - while (!kthread_should_stop()) { - if (ret < 0 || sc->reset) - ret = uea_start_reset(sc); - if (!ret) - ret = sc->stat(sc); - if (ret != -EAGAIN) - uea_wait(sc, 0, msecs_to_jiffies(1000)); - try_to_freeze(); - } - uea_leaves(INS_TO_USBDEV(sc)); - return ret; -} - -/* Load second usb firmware for ADI930 chip */ -static int load_XILINX_firmware(struct uea_softc *sc) -{ - const struct firmware *fw_entry; - int ret, size, u, ln; - const u8 *pfw; - u8 value; - char *fw_name = FW_DIR "930-fpga.bin"; - - uea_enters(INS_TO_USBDEV(sc)); - - ret = request_firmware(&fw_entry, fw_name, &sc->usb_dev->dev); - if (ret) { - uea_err(INS_TO_USBDEV(sc), "firmware %s is not available\n", - fw_name); - goto err0; - } - - pfw = fw_entry->data; - size = fw_entry->size; - if (size != 0x577B) { - uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", - fw_name); - ret = -EILSEQ; - goto err1; - } - for (u = 0; u < size; u += ln) { - ln = min(size - u, 64); - ret = uea_request(sc, 0xe, 0, ln, pfw + u); - if (ret < 0) { - uea_err(INS_TO_USBDEV(sc), - "elsa download data failed (%d)\n", ret); - goto err1; - } - } - - /* finish to send the fpga */ - ret = uea_request(sc, 0xe, 1, 0, NULL); - if (ret < 0) { - uea_err(INS_TO_USBDEV(sc), - "elsa download data failed (%d)\n", ret); - goto err1; - } - - /* Tell the modem we finish : de-assert reset */ - value = 0; - ret = uea_send_modem_cmd(sc->usb_dev, 0xe, 1, &value); - if (ret < 0) - uea_err(sc->usb_dev, "elsa de-assert failed with error" - " %d\n", ret); - -err1: - release_firmware(fw_entry); -err0: - uea_leaves(INS_TO_USBDEV(sc)); - return ret; -} - -/* The modem send us an ack. First with check if it right */ -static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr) -{ - struct cmv_dsc_e1 *dsc = &sc->cmv_dsc.e1; - struct cmv_e1 *cmv = &intr->u.e1.s2.cmv; - - uea_enters(INS_TO_USBDEV(sc)); - if (le16_to_cpu(cmv->wPreamble) != E1_PREAMBLE) - goto bad1; - - if (cmv->bDirection != E1_MODEMTOHOST) - goto bad1; - - /* FIXME : ADI930 reply wrong preambule (func = 2, sub = 2) to - * the first MEMACCESS cmv. Ignore it... - */ - if (cmv->bFunction != dsc->function) { - if (UEA_CHIP_VERSION(sc) == ADI930 - && cmv->bFunction == E1_MAKEFUNCTION(2, 2)) { - cmv->wIndex = cpu_to_le16(dsc->idx); - put_unaligned_le32(dsc->address, - &cmv->dwSymbolicAddress); - cmv->wOffsetAddress = cpu_to_le16(dsc->offset); - } else - goto bad2; - } - - if (cmv->bFunction == E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, - E1_MODEMREADY)) { - wake_up_cmv_ack(sc); - uea_leaves(INS_TO_USBDEV(sc)); - return; - } - - /* in case of MEMACCESS */ - if (le16_to_cpu(cmv->wIndex) != dsc->idx || - get_unaligned_le32(&cmv->dwSymbolicAddress) != dsc->address || - le16_to_cpu(cmv->wOffsetAddress) != dsc->offset) - goto bad2; - - sc->data = get_unaligned_le32(&cmv->dwData); - sc->data = sc->data << 16 | sc->data >> 16; - - wake_up_cmv_ack(sc); - uea_leaves(INS_TO_USBDEV(sc)); - return; - -bad2: - uea_err(INS_TO_USBDEV(sc), "unexpected cmv received, " - "Function : %d, Subfunction : %d\n", - E1_FUNCTION_TYPE(cmv->bFunction), - E1_FUNCTION_SUBTYPE(cmv->bFunction)); - uea_leaves(INS_TO_USBDEV(sc)); - return; - -bad1: - uea_err(INS_TO_USBDEV(sc), "invalid cmv received, " - "wPreamble %d, bDirection %d\n", - le16_to_cpu(cmv->wPreamble), cmv->bDirection); - uea_leaves(INS_TO_USBDEV(sc)); -} - -/* The modem send us an ack. First with check if it right */ -static void uea_dispatch_cmv_e4(struct uea_softc *sc, struct intr_pkt *intr) -{ - struct cmv_dsc_e4 *dsc = &sc->cmv_dsc.e4; - struct cmv_e4 *cmv = &intr->u.e4.s2.cmv; - - uea_enters(INS_TO_USBDEV(sc)); - uea_dbg(INS_TO_USBDEV(sc), "cmv %x %x %x %x %x %x\n", - be16_to_cpu(cmv->wGroup), be16_to_cpu(cmv->wFunction), - be16_to_cpu(cmv->wOffset), be16_to_cpu(cmv->wAddress), - be32_to_cpu(cmv->dwData[0]), be32_to_cpu(cmv->dwData[1])); - - if (be16_to_cpu(cmv->wFunction) != dsc->function) - goto bad2; - - if (be16_to_cpu(cmv->wFunction) == E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, - E4_MODEMREADY, 1)) { - wake_up_cmv_ack(sc); - uea_leaves(INS_TO_USBDEV(sc)); - return; - } - - /* in case of MEMACCESS */ - if (be16_to_cpu(cmv->wOffset) != dsc->offset || - be16_to_cpu(cmv->wGroup) != dsc->group || - be16_to_cpu(cmv->wAddress) != dsc->address) - goto bad2; - - sc->data = be32_to_cpu(cmv->dwData[0]); - sc->data1 = be32_to_cpu(cmv->dwData[1]); - wake_up_cmv_ack(sc); - uea_leaves(INS_TO_USBDEV(sc)); - return; - -bad2: - uea_err(INS_TO_USBDEV(sc), "unexpected cmv received, " - "Function : %d, Subfunction : %d\n", - E4_FUNCTION_TYPE(cmv->wFunction), - E4_FUNCTION_SUBTYPE(cmv->wFunction)); - uea_leaves(INS_TO_USBDEV(sc)); - return; -} - -static void uea_schedule_load_page_e1(struct uea_softc *sc, - struct intr_pkt *intr) -{ - sc->pageno = intr->e1_bSwapPageNo; - sc->ovl = intr->e1_bOvl >> 4 | intr->e1_bOvl << 4; - schedule_work(&sc->task); -} - -static void uea_schedule_load_page_e4(struct uea_softc *sc, - struct intr_pkt *intr) -{ - sc->pageno = intr->e4_bSwapPageNo; - schedule_work(&sc->task); -} - -/* - * interrupt handler - */ -static void uea_intr(struct urb *urb) -{ - struct uea_softc *sc = urb->context; - struct intr_pkt *intr = urb->transfer_buffer; - int status = urb->status; - - uea_enters(INS_TO_USBDEV(sc)); - - if (unlikely(status < 0)) { - uea_err(INS_TO_USBDEV(sc), "uea_intr() failed with %d\n", - status); - return; - } - - /* device-to-host interrupt */ - if (intr->bType != 0x08 || sc->booting) { - uea_err(INS_TO_USBDEV(sc), "wrong interrupt\n"); - goto resubmit; - } - - switch (le16_to_cpu(intr->wInterrupt)) { - case INT_LOADSWAPPAGE: - sc->schedule_load_page(sc, intr); - break; - - case INT_INCOMINGCMV: - sc->dispatch_cmv(sc, intr); - break; - - default: - uea_err(INS_TO_USBDEV(sc), "unknown interrupt %u\n", - le16_to_cpu(intr->wInterrupt)); - } - -resubmit: - usb_submit_urb(sc->urb_int, GFP_ATOMIC); -} - -/* - * Start the modem : init the data and start kernel thread - */ -static int uea_boot(struct uea_softc *sc) -{ - int ret, size; - struct intr_pkt *intr; - - uea_enters(INS_TO_USBDEV(sc)); - - if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { - size = E4_INTR_PKT_SIZE; - sc->dispatch_cmv = uea_dispatch_cmv_e4; - sc->schedule_load_page = uea_schedule_load_page_e4; - sc->stat = uea_stat_e4; - sc->send_cmvs = uea_send_cmvs_e4; - INIT_WORK(&sc->task, uea_load_page_e4); - } else { - size = E1_INTR_PKT_SIZE; - sc->dispatch_cmv = uea_dispatch_cmv_e1; - sc->schedule_load_page = uea_schedule_load_page_e1; - sc->stat = uea_stat_e1; - sc->send_cmvs = uea_send_cmvs_e1; - INIT_WORK(&sc->task, uea_load_page_e1); - } - - init_waitqueue_head(&sc->sync_q); - - if (UEA_CHIP_VERSION(sc) == ADI930) - load_XILINX_firmware(sc); - - intr = kmalloc(size, GFP_KERNEL); - if (!intr) { - uea_err(INS_TO_USBDEV(sc), - "cannot allocate interrupt package\n"); - goto err0; - } - - sc->urb_int = usb_alloc_urb(0, GFP_KERNEL); - if (!sc->urb_int) { - uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt URB\n"); - goto err1; - } - - usb_fill_int_urb(sc->urb_int, sc->usb_dev, - usb_rcvintpipe(sc->usb_dev, UEA_INTR_PIPE), - intr, size, uea_intr, sc, - sc->usb_dev->actconfig->interface[0]->altsetting[0]. - endpoint[0].desc.bInterval); - - ret = usb_submit_urb(sc->urb_int, GFP_KERNEL); - if (ret < 0) { - uea_err(INS_TO_USBDEV(sc), - "urb submition failed with error %d\n", ret); - goto err1; - } - - /* Create worker thread, but don't start it here. Start it after - * all usbatm generic initialization is done. - */ - sc->kthread = kthread_create(uea_kthread, sc, "ueagle-atm"); - if (IS_ERR(sc->kthread)) { - uea_err(INS_TO_USBDEV(sc), "failed to create thread\n"); - goto err2; - } - - uea_leaves(INS_TO_USBDEV(sc)); - return 0; - -err2: - usb_kill_urb(sc->urb_int); -err1: - usb_free_urb(sc->urb_int); - sc->urb_int = NULL; - kfree(intr); -err0: - uea_leaves(INS_TO_USBDEV(sc)); - return -ENOMEM; -} - -/* - * Stop the modem : kill kernel thread and free data - */ -static void uea_stop(struct uea_softc *sc) -{ - int ret; - uea_enters(INS_TO_USBDEV(sc)); - ret = kthread_stop(sc->kthread); - uea_dbg(INS_TO_USBDEV(sc), "kthread finish with status %d\n", ret); - - uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_ON, 0, NULL); - - usb_kill_urb(sc->urb_int); - kfree(sc->urb_int->transfer_buffer); - usb_free_urb(sc->urb_int); - - /* flush the work item, when no one can schedule it */ - flush_work_sync(&sc->task); - - if (sc->dsp_firm) - release_firmware(sc->dsp_firm); - uea_leaves(INS_TO_USBDEV(sc)); -} - -/* syfs interface */ -static struct uea_softc *dev_to_uea(struct device *dev) -{ - struct usb_interface *intf; - struct usbatm_data *usbatm; - - intf = to_usb_interface(dev); - if (!intf) - return NULL; - - usbatm = usb_get_intfdata(intf); - if (!usbatm) - return NULL; - - return usbatm->driver_data; -} - -static ssize_t read_status(struct device *dev, struct device_attribute *attr, - char *buf) -{ - int ret = -ENODEV; - struct uea_softc *sc; - - mutex_lock(&uea_mutex); - sc = dev_to_uea(dev); - if (!sc) - goto out; - ret = snprintf(buf, 10, "%08x\n", sc->stats.phy.state); -out: - mutex_unlock(&uea_mutex); - return ret; -} - -static ssize_t reboot(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - int ret = -ENODEV; - struct uea_softc *sc; - - mutex_lock(&uea_mutex); - sc = dev_to_uea(dev); - if (!sc) - goto out; - sc->reset = 1; - ret = count; -out: - mutex_unlock(&uea_mutex); - return ret; -} - -static DEVICE_ATTR(stat_status, S_IWUSR | S_IRUGO, read_status, reboot); - -static ssize_t read_human_status(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int ret = -ENODEV; - int modem_state; - struct uea_softc *sc; - - mutex_lock(&uea_mutex); - sc = dev_to_uea(dev); - if (!sc) - goto out; - - if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { - switch (sc->stats.phy.state) { - case 0x0: /* not yet synchronized */ - case 0x1: - case 0x3: - case 0x4: - modem_state = 0; - break; - case 0x5: /* initialization */ - case 0x6: - case 0x9: - case 0xa: - modem_state = 1; - break; - case 0x7: /* operational */ - modem_state = 2; - break; - case 0x2: /* fail ... */ - modem_state = 3; - break; - default: /* unknown */ - modem_state = 4; - break; - } - } else - modem_state = GET_STATUS(sc->stats.phy.state); - - switch (modem_state) { - case 0: - ret = sprintf(buf, "Modem is booting\n"); - break; - case 1: - ret = sprintf(buf, "Modem is initializing\n"); - break; - case 2: - ret = sprintf(buf, "Modem is operational\n"); - break; - case 3: - ret = sprintf(buf, "Modem synchronization failed\n"); - break; - default: - ret = sprintf(buf, "Modem state is unknown\n"); - break; - } -out: - mutex_unlock(&uea_mutex); - return ret; -} - -static DEVICE_ATTR(stat_human_status, S_IRUGO, read_human_status, NULL); - -static ssize_t read_delin(struct device *dev, struct device_attribute *attr, - char *buf) -{ - int ret = -ENODEV; - struct uea_softc *sc; - char *delin = "GOOD"; - - mutex_lock(&uea_mutex); - sc = dev_to_uea(dev); - if (!sc) - goto out; - - if (UEA_CHIP_VERSION(sc) == EAGLE_IV) { - if (sc->stats.phy.flags & 0x4000) - delin = "RESET"; - else if (sc->stats.phy.flags & 0x0001) - delin = "LOSS"; - } else { - if (sc->stats.phy.flags & 0x0C00) - delin = "ERROR"; - else if (sc->stats.phy.flags & 0x0030) - delin = "LOSS"; - } - - ret = sprintf(buf, "%s\n", delin); -out: - mutex_unlock(&uea_mutex); - return ret; -} - -static DEVICE_ATTR(stat_delin, S_IRUGO, read_delin, NULL); - -#define UEA_ATTR(name, reset) \ - \ -static ssize_t read_##name(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - int ret = -ENODEV; \ - struct uea_softc *sc; \ - \ - mutex_lock(&uea_mutex); \ - sc = dev_to_uea(dev); \ - if (!sc) \ - goto out; \ - ret = snprintf(buf, 10, "%08x\n", sc->stats.phy.name); \ - if (reset) \ - sc->stats.phy.name = 0; \ -out: \ - mutex_unlock(&uea_mutex); \ - return ret; \ -} \ - \ -static DEVICE_ATTR(stat_##name, S_IRUGO, read_##name, NULL) - -UEA_ATTR(mflags, 1); -UEA_ATTR(vidcpe, 0); -UEA_ATTR(usrate, 0); -UEA_ATTR(dsrate, 0); -UEA_ATTR(usattenuation, 0); -UEA_ATTR(dsattenuation, 0); -UEA_ATTR(usmargin, 0); -UEA_ATTR(dsmargin, 0); -UEA_ATTR(txflow, 0); -UEA_ATTR(rxflow, 0); -UEA_ATTR(uscorr, 0); -UEA_ATTR(dscorr, 0); -UEA_ATTR(usunc, 0); -UEA_ATTR(dsunc, 0); -UEA_ATTR(firmid, 0); - -/* Retrieve the device End System Identifier (MAC) */ - -static int uea_getesi(struct uea_softc *sc, u_char * esi) -{ - unsigned char mac_str[2 * ETH_ALEN + 1]; - int i; - if (usb_string - (sc->usb_dev, sc->usb_dev->descriptor.iSerialNumber, mac_str, - sizeof(mac_str)) != 2 * ETH_ALEN) - return 1; - - for (i = 0; i < ETH_ALEN; i++) - esi[i] = hex_to_bin(mac_str[2 * i]) * 16 + - hex_to_bin(mac_str[2 * i + 1]); - - return 0; -} - -/* ATM stuff */ -static int uea_atm_open(struct usbatm_data *usbatm, struct atm_dev *atm_dev) -{ - struct uea_softc *sc = usbatm->driver_data; - - return uea_getesi(sc, atm_dev->esi); -} - -static int uea_heavy(struct usbatm_data *usbatm, struct usb_interface *intf) -{ - struct uea_softc *sc = usbatm->driver_data; - - wait_event_interruptible(sc->sync_q, IS_OPERATIONAL(sc)); - - return 0; - -} - -static int claim_interface(struct usb_device *usb_dev, - struct usbatm_data *usbatm, int ifnum) -{ - int ret; - struct usb_interface *intf = usb_ifnum_to_if(usb_dev, ifnum); - - if (!intf) { - uea_err(usb_dev, "interface %d not found\n", ifnum); - return -ENODEV; - } - - ret = usb_driver_claim_interface(&uea_driver, intf, usbatm); - if (ret != 0) - uea_err(usb_dev, "can't claim interface %d, error %d\n", ifnum, - ret); - return ret; -} - -static struct attribute *attrs[] = { - &dev_attr_stat_status.attr, - &dev_attr_stat_mflags.attr, - &dev_attr_stat_human_status.attr, - &dev_attr_stat_delin.attr, - &dev_attr_stat_vidcpe.attr, - &dev_attr_stat_usrate.attr, - &dev_attr_stat_dsrate.attr, - &dev_attr_stat_usattenuation.attr, - &dev_attr_stat_dsattenuation.attr, - &dev_attr_stat_usmargin.attr, - &dev_attr_stat_dsmargin.attr, - &dev_attr_stat_txflow.attr, - &dev_attr_stat_rxflow.attr, - &dev_attr_stat_uscorr.attr, - &dev_attr_stat_dscorr.attr, - &dev_attr_stat_usunc.attr, - &dev_attr_stat_dsunc.attr, - &dev_attr_stat_firmid.attr, - NULL, -}; -static struct attribute_group attr_grp = { - .attrs = attrs, -}; - -static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *usb = interface_to_usbdev(intf); - struct uea_softc *sc; - int ret, ifnum = intf->altsetting->desc.bInterfaceNumber; - unsigned int alt; - - uea_enters(usb); - - /* interface 0 is for firmware/monitoring */ - if (ifnum != UEA_INTR_IFACE_NO) - return -ENODEV; - - usbatm->flags = (sync_wait[modem_index] ? 0 : UDSL_SKIP_HEAVY_INIT); - - /* interface 1 is for outbound traffic */ - ret = claim_interface(usb, usbatm, UEA_US_IFACE_NO); - if (ret < 0) - return ret; - - /* ADI930 has only 2 interfaces and inbound traffic is on interface 1 */ - if (UEA_CHIP_VERSION(id) != ADI930) { - /* interface 2 is for inbound traffic */ - ret = claim_interface(usb, usbatm, UEA_DS_IFACE_NO); - if (ret < 0) - return ret; - } - - sc = kzalloc(sizeof(struct uea_softc), GFP_KERNEL); - if (!sc) { - uea_err(usb, "uea_init: not enough memory !\n"); - return -ENOMEM; - } - - sc->usb_dev = usb; - usbatm->driver_data = sc; - sc->usbatm = usbatm; - sc->modem_index = (modem_index < NB_MODEM) ? modem_index++ : 0; - sc->driver_info = id->driver_info; - - /* first try to use module parameter */ - if (annex[sc->modem_index] == 1) - sc->annex = ANNEXA; - else if (annex[sc->modem_index] == 2) - sc->annex = ANNEXB; - /* try to autodetect annex */ - else if (sc->driver_info & AUTO_ANNEX_A) - sc->annex = ANNEXA; - else if (sc->driver_info & AUTO_ANNEX_B) - sc->annex = ANNEXB; - else - sc->annex = (le16_to_cpu - (sc->usb_dev->descriptor.bcdDevice) & 0x80) ? ANNEXB : ANNEXA; - - alt = altsetting[sc->modem_index]; - /* ADI930 don't support iso */ - if (UEA_CHIP_VERSION(id) != ADI930 && alt > 0) { - if (alt <= 8 && - usb_set_interface(usb, UEA_DS_IFACE_NO, alt) == 0) { - uea_dbg(usb, "set alternate %u for 2 interface\n", alt); - uea_info(usb, "using iso mode\n"); - usbatm->flags |= UDSL_USE_ISOC | UDSL_IGNORE_EILSEQ; - } else { - uea_err(usb, "setting alternate %u failed for " - "2 interface, using bulk mode\n", alt); - } - } - - ret = sysfs_create_group(&intf->dev.kobj, &attr_grp); - if (ret < 0) - goto error; - - ret = uea_boot(sc); - if (ret < 0) - goto error_rm_grp; - - return 0; - -error_rm_grp: - sysfs_remove_group(&intf->dev.kobj, &attr_grp); -error: - kfree(sc); - return ret; -} - -static void uea_unbind(struct usbatm_data *usbatm, struct usb_interface *intf) -{ - struct uea_softc *sc = usbatm->driver_data; - - sysfs_remove_group(&intf->dev.kobj, &attr_grp); - uea_stop(sc); - kfree(sc); -} - -static struct usbatm_driver uea_usbatm_driver = { - .driver_name = "ueagle-atm", - .bind = uea_bind, - .atm_start = uea_atm_open, - .unbind = uea_unbind, - .heavy_init = uea_heavy, - .bulk_in = UEA_BULK_DATA_PIPE, - .bulk_out = UEA_BULK_DATA_PIPE, - .isoc_in = UEA_ISO_DATA_PIPE, -}; - -static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_device *usb = interface_to_usbdev(intf); - int ret; - - uea_enters(usb); - uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) Rev (%#X): %s\n", - le16_to_cpu(usb->descriptor.idVendor), - le16_to_cpu(usb->descriptor.idProduct), - le16_to_cpu(usb->descriptor.bcdDevice), - chip_name[UEA_CHIP_VERSION(id)]); - - usb_reset_device(usb); - - if (UEA_IS_PREFIRM(id)) - return uea_load_firmware(usb, UEA_CHIP_VERSION(id)); - - ret = usbatm_usb_probe(intf, id, &uea_usbatm_driver); - if (ret == 0) { - struct usbatm_data *usbatm = usb_get_intfdata(intf); - struct uea_softc *sc = usbatm->driver_data; - - /* Ensure carrier is initialized to off as early as possible */ - UPDATE_ATM_SIGNAL(ATM_PHY_SIG_LOST); - - /* Only start the worker thread when all init is done */ - wake_up_process(sc->kthread); - } - - return ret; -} - -static void uea_disconnect(struct usb_interface *intf) -{ - struct usb_device *usb = interface_to_usbdev(intf); - int ifnum = intf->altsetting->desc.bInterfaceNumber; - uea_enters(usb); - - /* ADI930 has 2 interfaces and eagle 3 interfaces. - * Pre-firmware device has one interface - */ - if (usb->config->desc.bNumInterfaces != 1 && ifnum == 0) { - mutex_lock(&uea_mutex); - usbatm_usb_disconnect(intf); - mutex_unlock(&uea_mutex); - uea_info(usb, "ADSL device removed\n"); - } - - uea_leaves(usb); -} - -/* - * List of supported VID/PID - */ -static const struct usb_device_id uea_ids[] = { - {USB_DEVICE(ANALOG_VID, ADI930_PID_PREFIRM), - .driver_info = ADI930 | PREFIRM}, - {USB_DEVICE(ANALOG_VID, ADI930_PID_PSTFIRM), - .driver_info = ADI930 | PSTFIRM}, - {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PREFIRM), - .driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(ANALOG_VID, EAGLE_I_PID_PSTFIRM), - .driver_info = EAGLE_I | PSTFIRM}, - {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PREFIRM), - .driver_info = EAGLE_II | PREFIRM}, - {USB_DEVICE(ANALOG_VID, EAGLE_II_PID_PSTFIRM), - .driver_info = EAGLE_II | PSTFIRM}, - {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PREFIRM), - .driver_info = EAGLE_II | PREFIRM}, - {USB_DEVICE(ANALOG_VID, EAGLE_IIC_PID_PSTFIRM), - .driver_info = EAGLE_II | PSTFIRM}, - {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PREFIRM), - .driver_info = EAGLE_III | PREFIRM}, - {USB_DEVICE(ANALOG_VID, EAGLE_III_PID_PSTFIRM), - .driver_info = EAGLE_III | PSTFIRM}, - {USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PREFIRM), - .driver_info = EAGLE_IV | PREFIRM}, - {USB_DEVICE(ANALOG_VID, EAGLE_IV_PID_PSTFIRM), - .driver_info = EAGLE_IV | PSTFIRM}, - {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PREFIRM), - .driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_A_PID_PSTFIRM), - .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A}, - {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PREFIRM), - .driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_I_B_PID_PSTFIRM), - .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B}, - {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PREFIRM), - .driver_info = EAGLE_II | PREFIRM}, - {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_A_PID_PSTFIRM), - .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_A}, - {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PREFIRM), - .driver_info = EAGLE_II | PREFIRM}, - {USB_DEVICE(DEVOLO_VID, DEVOLO_EAGLE_II_B_PID_PSTFIRM), - .driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_B}, - {USB_DEVICE(ELSA_VID, ELSA_PID_PREFIRM), - .driver_info = ADI930 | PREFIRM}, - {USB_DEVICE(ELSA_VID, ELSA_PID_PSTFIRM), - .driver_info = ADI930 | PSTFIRM}, - {USB_DEVICE(ELSA_VID, ELSA_PID_A_PREFIRM), - .driver_info = ADI930 | PREFIRM}, - {USB_DEVICE(ELSA_VID, ELSA_PID_A_PSTFIRM), - .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_A}, - {USB_DEVICE(ELSA_VID, ELSA_PID_B_PREFIRM), - .driver_info = ADI930 | PREFIRM}, - {USB_DEVICE(ELSA_VID, ELSA_PID_B_PSTFIRM), - .driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_B}, - {USB_DEVICE(USR_VID, MILLER_A_PID_PREFIRM), - .driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(USR_VID, MILLER_A_PID_PSTFIRM), - .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A}, - {USB_DEVICE(USR_VID, MILLER_B_PID_PREFIRM), - .driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(USR_VID, MILLER_B_PID_PSTFIRM), - .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B}, - {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PREFIRM), - .driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(USR_VID, HEINEKEN_A_PID_PSTFIRM), - .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A}, - {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PREFIRM), - .driver_info = EAGLE_I | PREFIRM}, - {USB_DEVICE(USR_VID, HEINEKEN_B_PID_PSTFIRM), - .driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B}, - {} -}; - -/* - * USB driver descriptor - */ -static struct usb_driver uea_driver = { - .name = "ueagle-atm", - .id_table = uea_ids, - .probe = uea_probe, - .disconnect = uea_disconnect, -}; - -MODULE_DEVICE_TABLE(usb, uea_ids); - -module_usb_driver(uea_driver); - -MODULE_AUTHOR("Damien Bergamini/Matthieu Castet/Stanislaw W. Gruszka"); -MODULE_DESCRIPTION("ADI 930/Eagle USB ADSL Modem driver"); -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/atm/usbatm.c b/ANDROID_3.4.5/drivers/usb/atm/usbatm.c deleted file mode 100644 index d3448ca1..00000000 --- a/ANDROID_3.4.5/drivers/usb/atm/usbatm.c +++ /dev/null @@ -1,1388 +0,0 @@ -/****************************************************************************** - * usbatm.c - Generic USB xDSL driver core - * - * Copyright (C) 2001, Alcatel - * Copyright (C) 2003, Duncan Sands, SolNegro, Josep Comas - * Copyright (C) 2004, David Woodhouse, Roman Kagan - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - ******************************************************************************/ - -/* - * Written by Johan Verrept, Duncan Sands (duncan.sands@free.fr) and David Woodhouse - * - * 1.7+: - See the check-in logs - * - * 1.6: - No longer opens a connection if the firmware is not loaded - * - Added support for the speedtouch 330 - * - Removed the limit on the number of devices - * - Module now autoloads on device plugin - * - Merged relevant parts of sarlib - * - Replaced the kernel thread with a tasklet - * - New packet transmission code - * - Changed proc file contents - * - Fixed all known SMP races - * - Many fixes and cleanups - * - Various fixes by Oliver Neukum (oliver@neukum.name) - * - * 1.5A: - Version for inclusion in 2.5 series kernel - * - Modifications by Richard Purdie (rpurdie@rpsys.net) - * - made compatible with kernel 2.5.6 onwards by changing - * usbatm_usb_send_data_context->urb to a pointer and adding code - * to alloc and free it - * - remove_wait_queue() added to usbatm_atm_processqueue_thread() - * - * 1.5: - fixed memory leak when atmsar_decode_aal5 returned NULL. - * (reported by stephen.robinson@zen.co.uk) - * - * 1.4: - changed the spin_lock() under interrupt to spin_lock_irqsave() - * - unlink all active send urbs of a vcc that is being closed. - * - * 1.3.1: - added the version number - * - * 1.3: - Added multiple send urb support - * - fixed memory leak and vcc->tx_inuse starvation bug - * when not enough memory left in vcc. - * - * 1.2: - Fixed race condition in usbatm_usb_send_data() - * 1.1: - Turned off packet debugging - * - */ - -#include "usbatm.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef VERBOSE_DEBUG -static int usbatm_print_packet(const unsigned char *data, int len); -#define PACKETDEBUG(arg...) usbatm_print_packet(arg) -#define vdbg(arg...) dbg(arg) -#else -#define PACKETDEBUG(arg...) -#define vdbg(arg...) -#endif - -#define DRIVER_AUTHOR "Johan Verrept, Duncan Sands " -#define DRIVER_VERSION "1.10" -#define DRIVER_DESC "Generic USB ATM/DSL I/O, version " DRIVER_VERSION - -static const char usbatm_driver_name[] = "usbatm"; - -#define UDSL_MAX_RCV_URBS 16 -#define UDSL_MAX_SND_URBS 16 -#define UDSL_MAX_BUF_SIZE 65536 -#define UDSL_DEFAULT_RCV_URBS 4 -#define UDSL_DEFAULT_SND_URBS 4 -#define UDSL_DEFAULT_RCV_BUF_SIZE 3392 /* 64 * ATM_CELL_SIZE */ -#define UDSL_DEFAULT_SND_BUF_SIZE 3392 /* 64 * ATM_CELL_SIZE */ - -#define ATM_CELL_HEADER (ATM_CELL_SIZE - ATM_CELL_PAYLOAD) - -#define THROTTLE_MSECS 100 /* delay to recover processing after urb submission fails */ - -static unsigned int num_rcv_urbs = UDSL_DEFAULT_RCV_URBS; -static unsigned int num_snd_urbs = UDSL_DEFAULT_SND_URBS; -static unsigned int rcv_buf_bytes = UDSL_DEFAULT_RCV_BUF_SIZE; -static unsigned int snd_buf_bytes = UDSL_DEFAULT_SND_BUF_SIZE; - -module_param(num_rcv_urbs, uint, S_IRUGO); -MODULE_PARM_DESC(num_rcv_urbs, - "Number of urbs used for reception (range: 0-" - __MODULE_STRING(UDSL_MAX_RCV_URBS) ", default: " - __MODULE_STRING(UDSL_DEFAULT_RCV_URBS) ")"); - -module_param(num_snd_urbs, uint, S_IRUGO); -MODULE_PARM_DESC(num_snd_urbs, - "Number of urbs used for transmission (range: 0-" - __MODULE_STRING(UDSL_MAX_SND_URBS) ", default: " - __MODULE_STRING(UDSL_DEFAULT_SND_URBS) ")"); - -module_param(rcv_buf_bytes, uint, S_IRUGO); -MODULE_PARM_DESC(rcv_buf_bytes, - "Size of the buffers used for reception, in bytes (range: 1-" - __MODULE_STRING(UDSL_MAX_BUF_SIZE) ", default: " - __MODULE_STRING(UDSL_DEFAULT_RCV_BUF_SIZE) ")"); - -module_param(snd_buf_bytes, uint, S_IRUGO); -MODULE_PARM_DESC(snd_buf_bytes, - "Size of the buffers used for transmission, in bytes (range: 1-" - __MODULE_STRING(UDSL_MAX_BUF_SIZE) ", default: " - __MODULE_STRING(UDSL_DEFAULT_SND_BUF_SIZE) ")"); - - -/* receive */ - -struct usbatm_vcc_data { - /* vpi/vci lookup */ - struct list_head list; - short vpi; - int vci; - struct atm_vcc *vcc; - - /* raw cell reassembly */ - struct sk_buff *sarb; -}; - - -/* send */ - -struct usbatm_control { - struct atm_skb_data atm; - u32 len; - u32 crc; -}; - -#define UDSL_SKB(x) ((struct usbatm_control *)(x)->cb) - - -/* ATM */ - -static void usbatm_atm_dev_close(struct atm_dev *atm_dev); -static int usbatm_atm_open(struct atm_vcc *vcc); -static void usbatm_atm_close(struct atm_vcc *vcc); -static int usbatm_atm_ioctl(struct atm_dev *atm_dev, unsigned int cmd, void __user * arg); -static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb); -static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *page); - -static struct atmdev_ops usbatm_atm_devops = { - .dev_close = usbatm_atm_dev_close, - .open = usbatm_atm_open, - .close = usbatm_atm_close, - .ioctl = usbatm_atm_ioctl, - .send = usbatm_atm_send, - .proc_read = usbatm_atm_proc_read, - .owner = THIS_MODULE, -}; - - -/*********** -** misc ** -***********/ - -static inline unsigned int usbatm_pdu_length(unsigned int length) -{ - length += ATM_CELL_PAYLOAD - 1 + ATM_AAL5_TRAILER; - return length - length % ATM_CELL_PAYLOAD; -} - -static inline void usbatm_pop(struct atm_vcc *vcc, struct sk_buff *skb) -{ - if (vcc->pop) - vcc->pop(vcc, skb); - else - dev_kfree_skb_any(skb); -} - - -/*********** -** urbs ** -************/ - -static struct urb *usbatm_pop_urb(struct usbatm_channel *channel) -{ - struct urb *urb; - - spin_lock_irq(&channel->lock); - if (list_empty(&channel->list)) { - spin_unlock_irq(&channel->lock); - return NULL; - } - - urb = list_entry(channel->list.next, struct urb, urb_list); - list_del(&urb->urb_list); - spin_unlock_irq(&channel->lock); - - return urb; -} - -static int usbatm_submit_urb(struct urb *urb) -{ - struct usbatm_channel *channel = urb->context; - int ret; - - vdbg("%s: submitting urb 0x%p, size %u", - __func__, urb, urb->transfer_buffer_length); - - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) { - if (printk_ratelimit()) - atm_warn(channel->usbatm, "%s: urb 0x%p submission failed (%d)!\n", - __func__, urb, ret); - - /* consider all errors transient and return the buffer back to the queue */ - urb->status = -EAGAIN; - spin_lock_irq(&channel->lock); - - /* must add to the front when sending; doesn't matter when receiving */ - list_add(&urb->urb_list, &channel->list); - - spin_unlock_irq(&channel->lock); - - /* make sure the channel doesn't stall */ - mod_timer(&channel->delay, jiffies + msecs_to_jiffies(THROTTLE_MSECS)); - } - - return ret; -} - -static void usbatm_complete(struct urb *urb) -{ - struct usbatm_channel *channel = urb->context; - unsigned long flags; - int status = urb->status; - - vdbg("%s: urb 0x%p, status %d, actual_length %d", - __func__, urb, status, urb->actual_length); - - /* usually in_interrupt(), but not always */ - spin_lock_irqsave(&channel->lock, flags); - - /* must add to the back when receiving; doesn't matter when sending */ - list_add_tail(&urb->urb_list, &channel->list); - - spin_unlock_irqrestore(&channel->lock, flags); - - if (unlikely(status) && - (!(channel->usbatm->flags & UDSL_IGNORE_EILSEQ) || - status != -EILSEQ)) { - if (status == -ESHUTDOWN) - return; - - if (printk_ratelimit()) - atm_warn(channel->usbatm, "%s: urb 0x%p failed (%d)!\n", - __func__, urb, status); - /* throttle processing in case of an error */ - mod_timer(&channel->delay, jiffies + msecs_to_jiffies(THROTTLE_MSECS)); - } else - tasklet_schedule(&channel->tasklet); -} - - -/************* -** decode ** -*************/ - -static inline struct usbatm_vcc_data *usbatm_find_vcc(struct usbatm_data *instance, - short vpi, int vci) -{ - struct usbatm_vcc_data *vcc_data; - - list_for_each_entry(vcc_data, &instance->vcc_list, list) - if ((vcc_data->vci == vci) && (vcc_data->vpi == vpi)) - return vcc_data; - return NULL; -} - -static void usbatm_extract_one_cell(struct usbatm_data *instance, unsigned char *source) -{ - struct atm_vcc *vcc; - struct sk_buff *sarb; - short vpi = ((source[0] & 0x0f) << 4) | (source[1] >> 4); - int vci = ((source[1] & 0x0f) << 12) | (source[2] << 4) | (source[3] >> 4); - u8 pti = ((source[3] & 0xe) >> 1); - - vdbg("%s: vpi %hd, vci %d, pti %d", __func__, vpi, vci, pti); - - if ((vci != instance->cached_vci) || (vpi != instance->cached_vpi)) { - instance->cached_vpi = vpi; - instance->cached_vci = vci; - - instance->cached_vcc = usbatm_find_vcc(instance, vpi, vci); - - if (!instance->cached_vcc) - atm_rldbg(instance, "%s: unknown vpi/vci (%hd/%d)!\n", __func__, vpi, vci); - } - - if (!instance->cached_vcc) - return; - - vcc = instance->cached_vcc->vcc; - - /* OAM F5 end-to-end */ - if (pti == ATM_PTI_E2EF5) { - if (printk_ratelimit()) - atm_warn(instance, "%s: OAM not supported (vpi %d, vci %d)!\n", - __func__, vpi, vci); - atomic_inc(&vcc->stats->rx_err); - return; - } - - sarb = instance->cached_vcc->sarb; - - if (sarb->tail + ATM_CELL_PAYLOAD > sarb->end) { - atm_rldbg(instance, "%s: buffer overrun (sarb->len %u, vcc: 0x%p)!\n", - __func__, sarb->len, vcc); - /* discard cells already received */ - skb_trim(sarb, 0); - UDSL_ASSERT(instance, sarb->tail + ATM_CELL_PAYLOAD <= sarb->end); - } - - memcpy(skb_tail_pointer(sarb), source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD); - __skb_put(sarb, ATM_CELL_PAYLOAD); - - if (pti & 1) { - struct sk_buff *skb; - unsigned int length; - unsigned int pdu_length; - - length = (source[ATM_CELL_SIZE - 6] << 8) + source[ATM_CELL_SIZE - 5]; - - /* guard against overflow */ - if (length > ATM_MAX_AAL5_PDU) { - atm_rldbg(instance, "%s: bogus length %u (vcc: 0x%p)!\n", - __func__, length, vcc); - atomic_inc(&vcc->stats->rx_err); - goto out; - } - - pdu_length = usbatm_pdu_length(length); - - if (sarb->len < pdu_length) { - atm_rldbg(instance, "%s: bogus pdu_length %u (sarb->len: %u, vcc: 0x%p)!\n", - __func__, pdu_length, sarb->len, vcc); - atomic_inc(&vcc->stats->rx_err); - goto out; - } - - if (crc32_be(~0, skb_tail_pointer(sarb) - pdu_length, pdu_length) != 0xc704dd7b) { - atm_rldbg(instance, "%s: packet failed crc check (vcc: 0x%p)!\n", - __func__, vcc); - atomic_inc(&vcc->stats->rx_err); - goto out; - } - - vdbg("%s: got packet (length: %u, pdu_length: %u, vcc: 0x%p)", __func__, length, pdu_length, vcc); - - if (!(skb = dev_alloc_skb(length))) { - if (printk_ratelimit()) - atm_err(instance, "%s: no memory for skb (length: %u)!\n", - __func__, length); - atomic_inc(&vcc->stats->rx_drop); - goto out; - } - - vdbg("%s: allocated new sk_buff (skb: 0x%p, skb->truesize: %u)", __func__, skb, skb->truesize); - - if (!atm_charge(vcc, skb->truesize)) { - atm_rldbg(instance, "%s: failed atm_charge (skb->truesize: %u)!\n", - __func__, skb->truesize); - dev_kfree_skb_any(skb); - goto out; /* atm_charge increments rx_drop */ - } - - skb_copy_to_linear_data(skb, - skb_tail_pointer(sarb) - pdu_length, - length); - __skb_put(skb, length); - - vdbg("%s: sending skb 0x%p, skb->len %u, skb->truesize %u", - __func__, skb, skb->len, skb->truesize); - - PACKETDEBUG(skb->data, skb->len); - - vcc->push(vcc, skb); - - atomic_inc(&vcc->stats->rx); - out: - skb_trim(sarb, 0); - } -} - -static void usbatm_extract_cells(struct usbatm_data *instance, - unsigned char *source, unsigned int avail_data) -{ - unsigned int stride = instance->rx_channel.stride; - unsigned int buf_usage = instance->buf_usage; - - /* extract cells from incoming data, taking into account that - * the length of avail data may not be a multiple of stride */ - - if (buf_usage > 0) { - /* we have a partially received atm cell */ - unsigned char *cell_buf = instance->cell_buf; - unsigned int space_left = stride - buf_usage; - - UDSL_ASSERT(instance, buf_usage <= stride); - - if (avail_data >= space_left) { - /* add new data and process cell */ - memcpy(cell_buf + buf_usage, source, space_left); - source += space_left; - avail_data -= space_left; - usbatm_extract_one_cell(instance, cell_buf); - instance->buf_usage = 0; - } else { - /* not enough data to fill the cell */ - memcpy(cell_buf + buf_usage, source, avail_data); - instance->buf_usage = buf_usage + avail_data; - return; - } - } - - for (; avail_data >= stride; avail_data -= stride, source += stride) - usbatm_extract_one_cell(instance, source); - - if (avail_data > 0) { - /* length was not a multiple of stride - - * save remaining data for next call */ - memcpy(instance->cell_buf, source, avail_data); - instance->buf_usage = avail_data; - } -} - - -/************* -** encode ** -*************/ - -static unsigned int usbatm_write_cells(struct usbatm_data *instance, - struct sk_buff *skb, - u8 *target, unsigned int avail_space) -{ - struct usbatm_control *ctrl = UDSL_SKB(skb); - struct atm_vcc *vcc = ctrl->atm.vcc; - unsigned int bytes_written; - unsigned int stride = instance->tx_channel.stride; - - vdbg("%s: skb->len=%d, avail_space=%u", __func__, skb->len, avail_space); - UDSL_ASSERT(instance, !(avail_space % stride)); - - for (bytes_written = 0; bytes_written < avail_space && ctrl->len; - bytes_written += stride, target += stride) { - unsigned int data_len = min_t(unsigned int, skb->len, ATM_CELL_PAYLOAD); - unsigned int left = ATM_CELL_PAYLOAD - data_len; - u8 *ptr = target; - - ptr[0] = vcc->vpi >> 4; - ptr[1] = (vcc->vpi << 4) | (vcc->vci >> 12); - ptr[2] = vcc->vci >> 4; - ptr[3] = vcc->vci << 4; - ptr[4] = 0xec; - ptr += ATM_CELL_HEADER; - - skb_copy_from_linear_data(skb, ptr, data_len); - ptr += data_len; - __skb_pull(skb, data_len); - - if (!left) - continue; - - memset(ptr, 0, left); - - if (left >= ATM_AAL5_TRAILER) { /* trailer will go in this cell */ - u8 *trailer = target + ATM_CELL_SIZE - ATM_AAL5_TRAILER; - /* trailer[0] = 0; UU = 0 */ - /* trailer[1] = 0; CPI = 0 */ - trailer[2] = ctrl->len >> 8; - trailer[3] = ctrl->len; - - ctrl->crc = ~crc32_be(ctrl->crc, ptr, left - 4); - - trailer[4] = ctrl->crc >> 24; - trailer[5] = ctrl->crc >> 16; - trailer[6] = ctrl->crc >> 8; - trailer[7] = ctrl->crc; - - target[3] |= 0x2; /* adjust PTI */ - - ctrl->len = 0; /* tag this skb finished */ - } else - ctrl->crc = crc32_be(ctrl->crc, ptr, left); - } - - return bytes_written; -} - - -/************** -** receive ** -**************/ - -static void usbatm_rx_process(unsigned long data) -{ - struct usbatm_data *instance = (struct usbatm_data *)data; - struct urb *urb; - - while ((urb = usbatm_pop_urb(&instance->rx_channel))) { - vdbg("%s: processing urb 0x%p", __func__, urb); - - if (usb_pipeisoc(urb->pipe)) { - unsigned char *merge_start = NULL; - unsigned int merge_length = 0; - const unsigned int packet_size = instance->rx_channel.packet_size; - int i; - - for (i = 0; i < urb->number_of_packets; i++) { - if (!urb->iso_frame_desc[i].status) { - unsigned int actual_length = urb->iso_frame_desc[i].actual_length; - - UDSL_ASSERT(instance, actual_length <= packet_size); - - if (!merge_length) - merge_start = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset; - merge_length += actual_length; - if (merge_length && (actual_length < packet_size)) { - usbatm_extract_cells(instance, merge_start, merge_length); - merge_length = 0; - } - } else { - atm_rldbg(instance, "%s: status %d in frame %d!\n", __func__, urb->status, i); - if (merge_length) - usbatm_extract_cells(instance, merge_start, merge_length); - merge_length = 0; - instance->buf_usage = 0; - } - } - - if (merge_length) - usbatm_extract_cells(instance, merge_start, merge_length); - } else - if (!urb->status) - usbatm_extract_cells(instance, urb->transfer_buffer, urb->actual_length); - else - instance->buf_usage = 0; - - if (usbatm_submit_urb(urb)) - return; - } -} - - -/*********** -** send ** -***********/ - -static void usbatm_tx_process(unsigned long data) -{ - struct usbatm_data *instance = (struct usbatm_data *)data; - struct sk_buff *skb = instance->current_skb; - struct urb *urb = NULL; - const unsigned int buf_size = instance->tx_channel.buf_size; - unsigned int bytes_written = 0; - u8 *buffer = NULL; - - if (!skb) - skb = skb_dequeue(&instance->sndqueue); - - while (skb) { - if (!urb) { - urb = usbatm_pop_urb(&instance->tx_channel); - if (!urb) - break; /* no more senders */ - buffer = urb->transfer_buffer; - bytes_written = (urb->status == -EAGAIN) ? - urb->transfer_buffer_length : 0; - } - - bytes_written += usbatm_write_cells(instance, skb, - buffer + bytes_written, - buf_size - bytes_written); - - vdbg("%s: wrote %u bytes from skb 0x%p to urb 0x%p", - __func__, bytes_written, skb, urb); - - if (!UDSL_SKB(skb)->len) { - struct atm_vcc *vcc = UDSL_SKB(skb)->atm.vcc; - - usbatm_pop(vcc, skb); - atomic_inc(&vcc->stats->tx); - - skb = skb_dequeue(&instance->sndqueue); - } - - if (bytes_written == buf_size || (!skb && bytes_written)) { - urb->transfer_buffer_length = bytes_written; - - if (usbatm_submit_urb(urb)) - break; - urb = NULL; - } - } - - instance->current_skb = skb; -} - -static void usbatm_cancel_send(struct usbatm_data *instance, - struct atm_vcc *vcc) -{ - struct sk_buff *skb, *n; - - atm_dbg(instance, "%s entered\n", __func__); - spin_lock_irq(&instance->sndqueue.lock); - skb_queue_walk_safe(&instance->sndqueue, skb, n) { - if (UDSL_SKB(skb)->atm.vcc == vcc) { - atm_dbg(instance, "%s: popping skb 0x%p\n", __func__, skb); - __skb_unlink(skb, &instance->sndqueue); - usbatm_pop(vcc, skb); - } - } - spin_unlock_irq(&instance->sndqueue.lock); - - tasklet_disable(&instance->tx_channel.tasklet); - if ((skb = instance->current_skb) && (UDSL_SKB(skb)->atm.vcc == vcc)) { - atm_dbg(instance, "%s: popping current skb (0x%p)\n", __func__, skb); - instance->current_skb = NULL; - usbatm_pop(vcc, skb); - } - tasklet_enable(&instance->tx_channel.tasklet); - atm_dbg(instance, "%s done\n", __func__); -} - -static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) -{ - struct usbatm_data *instance = vcc->dev->dev_data; - struct usbatm_control *ctrl = UDSL_SKB(skb); - int err; - - vdbg("%s called (skb 0x%p, len %u)", __func__, skb, skb->len); - - /* racy disconnection check - fine */ - if (!instance || instance->disconnected) { -#ifdef DEBUG - printk_ratelimited(KERN_DEBUG "%s: %s!\n", __func__, instance ? "disconnected" : "NULL instance"); -#endif - err = -ENODEV; - goto fail; - } - - if (vcc->qos.aal != ATM_AAL5) { - atm_rldbg(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal); - err = -EINVAL; - goto fail; - } - - if (skb->len > ATM_MAX_AAL5_PDU) { - atm_rldbg(instance, "%s: packet too long (%d vs %d)!\n", - __func__, skb->len, ATM_MAX_AAL5_PDU); - err = -EINVAL; - goto fail; - } - - PACKETDEBUG(skb->data, skb->len); - - /* initialize the control block */ - ctrl->atm.vcc = vcc; - ctrl->len = skb->len; - ctrl->crc = crc32_be(~0, skb->data, skb->len); - - skb_queue_tail(&instance->sndqueue, skb); - tasklet_schedule(&instance->tx_channel.tasklet); - - return 0; - - fail: - usbatm_pop(vcc, skb); - return err; -} - - -/******************** -** bean counting ** -********************/ - -static void usbatm_destroy_instance(struct kref *kref) -{ - struct usbatm_data *instance = container_of(kref, struct usbatm_data, refcount); - - dbg("%s", __func__); - - tasklet_kill(&instance->rx_channel.tasklet); - tasklet_kill(&instance->tx_channel.tasklet); - usb_put_dev(instance->usb_dev); - kfree(instance); -} - -static void usbatm_get_instance(struct usbatm_data *instance) -{ - dbg("%s", __func__); - - kref_get(&instance->refcount); -} - -static void usbatm_put_instance(struct usbatm_data *instance) -{ - dbg("%s", __func__); - - kref_put(&instance->refcount, usbatm_destroy_instance); -} - - -/********** -** ATM ** -**********/ - -static void usbatm_atm_dev_close(struct atm_dev *atm_dev) -{ - struct usbatm_data *instance = atm_dev->dev_data; - - dbg("%s", __func__); - - if (!instance) - return; - - atm_dev->dev_data = NULL; /* catch bugs */ - usbatm_put_instance(instance); /* taken in usbatm_atm_init */ -} - -static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *page) -{ - struct usbatm_data *instance = atm_dev->dev_data; - int left = *pos; - - if (!instance) { - dbg("%s: NULL instance!", __func__); - return -ENODEV; - } - - if (!left--) - return sprintf(page, "%s\n", instance->description); - - if (!left--) - return sprintf(page, "MAC: %pM\n", atm_dev->esi); - - if (!left--) - return sprintf(page, - "AAL5: tx %d ( %d err ), rx %d ( %d err, %d drop )\n", - atomic_read(&atm_dev->stats.aal5.tx), - atomic_read(&atm_dev->stats.aal5.tx_err), - atomic_read(&atm_dev->stats.aal5.rx), - atomic_read(&atm_dev->stats.aal5.rx_err), - atomic_read(&atm_dev->stats.aal5.rx_drop)); - - if (!left--) { - if (instance->disconnected) - return sprintf(page, "Disconnected\n"); - else - switch (atm_dev->signal) { - case ATM_PHY_SIG_FOUND: - return sprintf(page, "Line up\n"); - case ATM_PHY_SIG_LOST: - return sprintf(page, "Line down\n"); - default: - return sprintf(page, "Line state unknown\n"); - } - } - - return 0; -} - -static int usbatm_atm_open(struct atm_vcc *vcc) -{ - struct usbatm_data *instance = vcc->dev->dev_data; - struct usbatm_vcc_data *new = NULL; - int ret; - int vci = vcc->vci; - short vpi = vcc->vpi; - - if (!instance) { - dbg("%s: NULL data!", __func__); - return -ENODEV; - } - - atm_dbg(instance, "%s: vpi %hd, vci %d\n", __func__, vpi, vci); - - /* only support AAL5 */ - if ((vcc->qos.aal != ATM_AAL5)) { - atm_warn(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal); - return -EINVAL; - } - - /* sanity checks */ - if ((vcc->qos.rxtp.max_sdu < 0) || (vcc->qos.rxtp.max_sdu > ATM_MAX_AAL5_PDU)) { - atm_dbg(instance, "%s: max_sdu %d out of range!\n", __func__, vcc->qos.rxtp.max_sdu); - return -EINVAL; - } - - mutex_lock(&instance->serialize); /* vs self, usbatm_atm_close, usbatm_usb_disconnect */ - - if (instance->disconnected) { - atm_dbg(instance, "%s: disconnected!\n", __func__); - ret = -ENODEV; - goto fail; - } - - if (usbatm_find_vcc(instance, vpi, vci)) { - atm_dbg(instance, "%s: %hd/%d already in use!\n", __func__, vpi, vci); - ret = -EADDRINUSE; - goto fail; - } - - if (!(new = kzalloc(sizeof(struct usbatm_vcc_data), GFP_KERNEL))) { - atm_err(instance, "%s: no memory for vcc_data!\n", __func__); - ret = -ENOMEM; - goto fail; - } - - new->vcc = vcc; - new->vpi = vpi; - new->vci = vci; - - new->sarb = alloc_skb(usbatm_pdu_length(vcc->qos.rxtp.max_sdu), GFP_KERNEL); - if (!new->sarb) { - atm_err(instance, "%s: no memory for SAR buffer!\n", __func__); - ret = -ENOMEM; - goto fail; - } - - vcc->dev_data = new; - - tasklet_disable(&instance->rx_channel.tasklet); - instance->cached_vcc = new; - instance->cached_vpi = vpi; - instance->cached_vci = vci; - list_add(&new->list, &instance->vcc_list); - tasklet_enable(&instance->rx_channel.tasklet); - - set_bit(ATM_VF_ADDR, &vcc->flags); - set_bit(ATM_VF_PARTIAL, &vcc->flags); - set_bit(ATM_VF_READY, &vcc->flags); - - mutex_unlock(&instance->serialize); - - atm_dbg(instance, "%s: allocated vcc data 0x%p\n", __func__, new); - - return 0; - -fail: - kfree(new); - mutex_unlock(&instance->serialize); - return ret; -} - -static void usbatm_atm_close(struct atm_vcc *vcc) -{ - struct usbatm_data *instance = vcc->dev->dev_data; - struct usbatm_vcc_data *vcc_data = vcc->dev_data; - - if (!instance || !vcc_data) { - dbg("%s: NULL data!", __func__); - return; - } - - atm_dbg(instance, "%s entered\n", __func__); - - atm_dbg(instance, "%s: deallocating vcc 0x%p with vpi %d vci %d\n", - __func__, vcc_data, vcc_data->vpi, vcc_data->vci); - - usbatm_cancel_send(instance, vcc); - - mutex_lock(&instance->serialize); /* vs self, usbatm_atm_open, usbatm_usb_disconnect */ - - tasklet_disable(&instance->rx_channel.tasklet); - if (instance->cached_vcc == vcc_data) { - instance->cached_vcc = NULL; - instance->cached_vpi = ATM_VPI_UNSPEC; - instance->cached_vci = ATM_VCI_UNSPEC; - } - list_del(&vcc_data->list); - tasklet_enable(&instance->rx_channel.tasklet); - - kfree_skb(vcc_data->sarb); - vcc_data->sarb = NULL; - - kfree(vcc_data); - vcc->dev_data = NULL; - - vcc->vpi = ATM_VPI_UNSPEC; - vcc->vci = ATM_VCI_UNSPEC; - clear_bit(ATM_VF_READY, &vcc->flags); - clear_bit(ATM_VF_PARTIAL, &vcc->flags); - clear_bit(ATM_VF_ADDR, &vcc->flags); - - mutex_unlock(&instance->serialize); - - atm_dbg(instance, "%s successful\n", __func__); -} - -static int usbatm_atm_ioctl(struct atm_dev *atm_dev, unsigned int cmd, - void __user * arg) -{ - struct usbatm_data *instance = atm_dev->dev_data; - - if (!instance || instance->disconnected) { - dbg("%s: %s!", __func__, instance ? "disconnected" : "NULL instance"); - return -ENODEV; - } - - switch (cmd) { - case ATM_QUERYLOOP: - return put_user(ATM_LM_NONE, (int __user *)arg) ? -EFAULT : 0; - default: - return -ENOIOCTLCMD; - } -} - -static int usbatm_atm_init(struct usbatm_data *instance) -{ - struct atm_dev *atm_dev; - int ret, i; - - /* ATM init. The ATM initialization scheme suffers from an intrinsic race - * condition: callbacks we register can be executed at once, before we have - * initialized the struct atm_dev. To protect against this, all callbacks - * abort if atm_dev->dev_data is NULL. */ - atm_dev = atm_dev_register(instance->driver_name, - &instance->usb_intf->dev, &usbatm_atm_devops, - -1, NULL); - if (!atm_dev) { - usb_err(instance, "%s: failed to register ATM device!\n", __func__); - return -1; - } - - instance->atm_dev = atm_dev; - - atm_dev->ci_range.vpi_bits = ATM_CI_MAX; - atm_dev->ci_range.vci_bits = ATM_CI_MAX; - atm_dev->signal = ATM_PHY_SIG_UNKNOWN; - - /* temp init ATM device, set to 128kbit */ - atm_dev->link_rate = 128 * 1000 / 424; - - if (instance->driver->atm_start && ((ret = instance->driver->atm_start(instance, atm_dev)) < 0)) { - atm_err(instance, "%s: atm_start failed: %d!\n", __func__, ret); - goto fail; - } - - usbatm_get_instance(instance); /* dropped in usbatm_atm_dev_close */ - - /* ready for ATM callbacks */ - mb(); - atm_dev->dev_data = instance; - - /* submit all rx URBs */ - for (i = 0; i < num_rcv_urbs; i++) - usbatm_submit_urb(instance->urbs[i]); - - return 0; - - fail: - instance->atm_dev = NULL; - atm_dev_deregister(atm_dev); /* usbatm_atm_dev_close will eventually be called */ - return ret; -} - - -/********** -** USB ** -**********/ - -static int usbatm_do_heavy_init(void *arg) -{ - struct usbatm_data *instance = arg; - int ret; - - allow_signal(SIGTERM); - complete(&instance->thread_started); - - ret = instance->driver->heavy_init(instance, instance->usb_intf); - - if (!ret) - ret = usbatm_atm_init(instance); - - mutex_lock(&instance->serialize); - instance->thread = NULL; - mutex_unlock(&instance->serialize); - - complete_and_exit(&instance->thread_exited, ret); -} - -static int usbatm_heavy_init(struct usbatm_data *instance) -{ - struct task_struct *t; - - t = kthread_create(usbatm_do_heavy_init, instance, - instance->driver->driver_name); - if (IS_ERR(t)) { - usb_err(instance, "%s: failed to create kernel_thread (%ld)!\n", - __func__, PTR_ERR(t)); - return PTR_ERR(t); - } - - instance->thread = t; - wake_up_process(t); - wait_for_completion(&instance->thread_started); - - return 0; -} - -static void usbatm_tasklet_schedule(unsigned long data) -{ - tasklet_schedule((struct tasklet_struct *) data); -} - -static void usbatm_init_channel(struct usbatm_channel *channel) -{ - spin_lock_init(&channel->lock); - INIT_LIST_HEAD(&channel->list); - channel->delay.function = usbatm_tasklet_schedule; - channel->delay.data = (unsigned long) &channel->tasklet; - init_timer(&channel->delay); -} - -int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, - struct usbatm_driver *driver) -{ - struct device *dev = &intf->dev; - struct usb_device *usb_dev = interface_to_usbdev(intf); - struct usbatm_data *instance; - char *buf; - int error = -ENOMEM; - int i, length; - unsigned int maxpacket, num_packets; - - dev_dbg(dev, "%s: trying driver %s with vendor=%04x, product=%04x, ifnum %2d\n", - __func__, driver->driver_name, - le16_to_cpu(usb_dev->descriptor.idVendor), - le16_to_cpu(usb_dev->descriptor.idProduct), - intf->altsetting->desc.bInterfaceNumber); - - /* instance init */ - instance = kzalloc(sizeof(*instance) + sizeof(struct urb *) * (num_rcv_urbs + num_snd_urbs), GFP_KERNEL); - if (!instance) { - dev_err(dev, "%s: no memory for instance data!\n", __func__); - return -ENOMEM; - } - - /* public fields */ - - instance->driver = driver; - snprintf(instance->driver_name, sizeof(instance->driver_name), driver->driver_name); - - instance->usb_dev = usb_dev; - instance->usb_intf = intf; - - buf = instance->description; - length = sizeof(instance->description); - - if ((i = usb_string(usb_dev, usb_dev->descriptor.iProduct, buf, length)) < 0) - goto bind; - - buf += i; - length -= i; - - i = scnprintf(buf, length, " ("); - buf += i; - length -= i; - - if (length <= 0 || (i = usb_make_path(usb_dev, buf, length)) < 0) - goto bind; - - buf += i; - length -= i; - - snprintf(buf, length, ")"); - - bind: - if (driver->bind && (error = driver->bind(instance, intf, id)) < 0) { - dev_err(dev, "%s: bind failed: %d!\n", __func__, error); - goto fail_free; - } - - /* private fields */ - - kref_init(&instance->refcount); /* dropped in usbatm_usb_disconnect */ - mutex_init(&instance->serialize); - - instance->thread = NULL; - init_completion(&instance->thread_started); - init_completion(&instance->thread_exited); - - INIT_LIST_HEAD(&instance->vcc_list); - skb_queue_head_init(&instance->sndqueue); - - usbatm_init_channel(&instance->rx_channel); - usbatm_init_channel(&instance->tx_channel); - tasklet_init(&instance->rx_channel.tasklet, usbatm_rx_process, (unsigned long)instance); - tasklet_init(&instance->tx_channel.tasklet, usbatm_tx_process, (unsigned long)instance); - instance->rx_channel.stride = ATM_CELL_SIZE + driver->rx_padding; - instance->tx_channel.stride = ATM_CELL_SIZE + driver->tx_padding; - instance->rx_channel.usbatm = instance->tx_channel.usbatm = instance; - - if ((instance->flags & UDSL_USE_ISOC) && driver->isoc_in) - instance->rx_channel.endpoint = usb_rcvisocpipe(usb_dev, driver->isoc_in); - else - instance->rx_channel.endpoint = usb_rcvbulkpipe(usb_dev, driver->bulk_in); - - instance->tx_channel.endpoint = usb_sndbulkpipe(usb_dev, driver->bulk_out); - - /* tx buffer size must be a positive multiple of the stride */ - instance->tx_channel.buf_size = max(instance->tx_channel.stride, - snd_buf_bytes - (snd_buf_bytes % instance->tx_channel.stride)); - - /* rx buffer size must be a positive multiple of the endpoint maxpacket */ - maxpacket = usb_maxpacket(usb_dev, instance->rx_channel.endpoint, 0); - - if ((maxpacket < 1) || (maxpacket > UDSL_MAX_BUF_SIZE)) { - dev_err(dev, "%s: invalid endpoint %02x!\n", __func__, - usb_pipeendpoint(instance->rx_channel.endpoint)); - error = -EINVAL; - goto fail_unbind; - } - - num_packets = max(1U, (rcv_buf_bytes + maxpacket / 2) / maxpacket); /* round */ - - if (num_packets * maxpacket > UDSL_MAX_BUF_SIZE) - num_packets--; - - instance->rx_channel.buf_size = num_packets * maxpacket; - instance->rx_channel.packet_size = maxpacket; - -#ifdef DEBUG - for (i = 0; i < 2; i++) { - struct usbatm_channel *channel = i ? - &instance->tx_channel : &instance->rx_channel; - - dev_dbg(dev, "%s: using %d byte buffer for %s channel 0x%p\n", __func__, channel->buf_size, i ? "tx" : "rx", channel); - } -#endif - - /* initialize urbs */ - - for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) { - u8 *buffer; - struct usbatm_channel *channel = i < num_rcv_urbs ? - &instance->rx_channel : &instance->tx_channel; - struct urb *urb; - unsigned int iso_packets = usb_pipeisoc(channel->endpoint) ? channel->buf_size / channel->packet_size : 0; - - UDSL_ASSERT(instance, !usb_pipeisoc(channel->endpoint) || usb_pipein(channel->endpoint)); - - urb = usb_alloc_urb(iso_packets, GFP_KERNEL); - if (!urb) { - dev_err(dev, "%s: no memory for urb %d!\n", __func__, i); - error = -ENOMEM; - goto fail_unbind; - } - - instance->urbs[i] = urb; - - /* zero the tx padding to avoid leaking information */ - buffer = kzalloc(channel->buf_size, GFP_KERNEL); - if (!buffer) { - dev_err(dev, "%s: no memory for buffer %d!\n", __func__, i); - error = -ENOMEM; - goto fail_unbind; - } - - usb_fill_bulk_urb(urb, instance->usb_dev, channel->endpoint, - buffer, channel->buf_size, usbatm_complete, channel); - if (iso_packets) { - int j; - urb->interval = 1; - urb->transfer_flags = URB_ISO_ASAP; - urb->number_of_packets = iso_packets; - for (j = 0; j < iso_packets; j++) { - urb->iso_frame_desc[j].offset = channel->packet_size * j; - urb->iso_frame_desc[j].length = channel->packet_size; - } - } - - /* put all tx URBs on the list of spares */ - if (i >= num_rcv_urbs) - list_add_tail(&urb->urb_list, &channel->list); - - vdbg("%s: alloced buffer 0x%p buf size %u urb 0x%p", - __func__, urb->transfer_buffer, urb->transfer_buffer_length, urb); - } - - instance->cached_vpi = ATM_VPI_UNSPEC; - instance->cached_vci = ATM_VCI_UNSPEC; - instance->cell_buf = kmalloc(instance->rx_channel.stride, GFP_KERNEL); - - if (!instance->cell_buf) { - dev_err(dev, "%s: no memory for cell buffer!\n", __func__); - error = -ENOMEM; - goto fail_unbind; - } - - if (!(instance->flags & UDSL_SKIP_HEAVY_INIT) && driver->heavy_init) { - error = usbatm_heavy_init(instance); - } else { - complete(&instance->thread_exited); /* pretend that heavy_init was run */ - error = usbatm_atm_init(instance); - } - - if (error < 0) - goto fail_unbind; - - usb_get_dev(usb_dev); - usb_set_intfdata(intf, instance); - - return 0; - - fail_unbind: - if (instance->driver->unbind) - instance->driver->unbind(instance, intf); - fail_free: - kfree(instance->cell_buf); - - for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) { - if (instance->urbs[i]) - kfree(instance->urbs[i]->transfer_buffer); - usb_free_urb(instance->urbs[i]); - } - - kfree(instance); - - return error; -} -EXPORT_SYMBOL_GPL(usbatm_usb_probe); - -void usbatm_usb_disconnect(struct usb_interface *intf) -{ - struct device *dev = &intf->dev; - struct usbatm_data *instance = usb_get_intfdata(intf); - struct usbatm_vcc_data *vcc_data; - int i; - - dev_dbg(dev, "%s entered\n", __func__); - - if (!instance) { - dev_dbg(dev, "%s: NULL instance!\n", __func__); - return; - } - - usb_set_intfdata(intf, NULL); - - mutex_lock(&instance->serialize); - instance->disconnected = 1; - if (instance->thread != NULL) - send_sig(SIGTERM, instance->thread, 1); - mutex_unlock(&instance->serialize); - - wait_for_completion(&instance->thread_exited); - - mutex_lock(&instance->serialize); - list_for_each_entry(vcc_data, &instance->vcc_list, list) - vcc_release_async(vcc_data->vcc, -EPIPE); - mutex_unlock(&instance->serialize); - - tasklet_disable(&instance->rx_channel.tasklet); - tasklet_disable(&instance->tx_channel.tasklet); - - for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) - usb_kill_urb(instance->urbs[i]); - - del_timer_sync(&instance->rx_channel.delay); - del_timer_sync(&instance->tx_channel.delay); - - /* turn usbatm_[rt]x_process into something close to a no-op */ - /* no need to take the spinlock */ - INIT_LIST_HEAD(&instance->rx_channel.list); - INIT_LIST_HEAD(&instance->tx_channel.list); - - tasklet_enable(&instance->rx_channel.tasklet); - tasklet_enable(&instance->tx_channel.tasklet); - - if (instance->atm_dev && instance->driver->atm_stop) - instance->driver->atm_stop(instance, instance->atm_dev); - - if (instance->driver->unbind) - instance->driver->unbind(instance, intf); - - instance->driver_data = NULL; - - for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) { - kfree(instance->urbs[i]->transfer_buffer); - usb_free_urb(instance->urbs[i]); - } - - kfree(instance->cell_buf); - - /* ATM finalize */ - if (instance->atm_dev) { - atm_dev_deregister(instance->atm_dev); - instance->atm_dev = NULL; - } - - usbatm_put_instance(instance); /* taken in usbatm_usb_probe */ -} -EXPORT_SYMBOL_GPL(usbatm_usb_disconnect); - - -/*********** -** init ** -***********/ - -static int __init usbatm_usb_init(void) -{ - dbg("%s: driver version %s", __func__, DRIVER_VERSION); - - if (sizeof(struct usbatm_control) > FIELD_SIZEOF(struct sk_buff, cb)) { - printk(KERN_ERR "%s unusable with this kernel!\n", usbatm_driver_name); - return -EIO; - } - - if ((num_rcv_urbs > UDSL_MAX_RCV_URBS) - || (num_snd_urbs > UDSL_MAX_SND_URBS) - || (rcv_buf_bytes < 1) - || (rcv_buf_bytes > UDSL_MAX_BUF_SIZE) - || (snd_buf_bytes < 1) - || (snd_buf_bytes > UDSL_MAX_BUF_SIZE)) - return -EINVAL; - - return 0; -} -module_init(usbatm_usb_init); - -static void __exit usbatm_usb_exit(void) -{ - dbg("%s", __func__); -} -module_exit(usbatm_usb_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRIVER_VERSION); - -/************ -** debug ** -************/ - -#ifdef VERBOSE_DEBUG -static int usbatm_print_packet(const unsigned char *data, int len) -{ - unsigned char buffer[256]; - int i = 0, j = 0; - - for (i = 0; i < len;) { - buffer[0] = '\0'; - sprintf(buffer, "%.3d :", i); - for (j = 0; (j < 16) && (i < len); j++, i++) - sprintf(buffer, "%s %2.2x", buffer, data[i]); - dbg("%s", buffer); - } - return i; -} -#endif diff --git a/ANDROID_3.4.5/drivers/usb/atm/usbatm.h b/ANDROID_3.4.5/drivers/usb/atm/usbatm.h deleted file mode 100644 index 5fc48940..00000000 --- a/ANDROID_3.4.5/drivers/usb/atm/usbatm.h +++ /dev/null @@ -1,222 +0,0 @@ -/****************************************************************************** - * usbatm.h - Generic USB xDSL driver core - * - * Copyright (C) 2001, Alcatel - * Copyright (C) 2003, Duncan Sands, SolNegro, Josep Comas - * Copyright (C) 2004, David Woodhouse - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - ******************************************************************************/ - -#ifndef _USBATM_H_ -#define _USBATM_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* -#define VERBOSE_DEBUG -*/ - -#ifdef DEBUG -#define UDSL_ASSERT(instance, x) BUG_ON(!(x)) -#else -#define UDSL_ASSERT(instance, x) \ - do { \ - if (!(x)) \ - dev_warn(&(instance)->usb_intf->dev, \ - "failed assertion '%s' at line %d", \ - __stringify(x), __LINE__); \ - } while (0) -#endif - -#define usb_err(instance, format, arg...) \ - dev_err(&(instance)->usb_intf->dev , format , ## arg) -#define usb_info(instance, format, arg...) \ - dev_info(&(instance)->usb_intf->dev , format , ## arg) -#define usb_warn(instance, format, arg...) \ - dev_warn(&(instance)->usb_intf->dev , format , ## arg) -#ifdef DEBUG -#define usb_dbg(instance, format, arg...) \ - dev_printk(KERN_DEBUG , &(instance)->usb_intf->dev , format , ## arg) -#else -#define usb_dbg(instance, format, arg...) \ - do {} while (0) -#endif - -/* FIXME: move to dev_* once ATM is driver model aware */ -#define atm_printk(level, instance, format, arg...) \ - printk(level "ATM dev %d: " format , \ - (instance)->atm_dev->number , ## arg) - -#define atm_err(instance, format, arg...) \ - atm_printk(KERN_ERR, instance , format , ## arg) -#define atm_info(instance, format, arg...) \ - atm_printk(KERN_INFO, instance , format , ## arg) -#define atm_warn(instance, format, arg...) \ - atm_printk(KERN_WARNING, instance , format , ## arg) -#ifdef DEBUG -#define atm_dbg(instance, format, arg...) \ - atm_printk(KERN_DEBUG, instance , format , ## arg) -#define atm_rldbg(instance, format, arg...) \ - if (printk_ratelimit()) \ - atm_printk(KERN_DEBUG, instance , format , ## arg) -#else -#define atm_dbg(instance, format, arg...) \ - do {} while (0) -#define atm_rldbg(instance, format, arg...) \ - do {} while (0) -#endif - - -/* flags, set by mini-driver in bind() */ - -#define UDSL_SKIP_HEAVY_INIT (1<<0) -#define UDSL_USE_ISOC (1<<1) -#define UDSL_IGNORE_EILSEQ (1<<2) - - -/* mini driver */ - -struct usbatm_data; - -/* -* Assuming all methods exist and succeed, they are called in this order: -* -* bind, heavy_init, atm_start, ..., atm_stop, unbind -*/ - -struct usbatm_driver { - const char *driver_name; - - /* init device ... can sleep, or cause probe() failure */ - int (*bind) (struct usbatm_data *, struct usb_interface *, - const struct usb_device_id *id); - - /* additional device initialization that is too slow to be done in probe() */ - int (*heavy_init) (struct usbatm_data *, struct usb_interface *); - - /* cleanup device ... can sleep, but can't fail */ - void (*unbind) (struct usbatm_data *, struct usb_interface *); - - /* init ATM device ... can sleep, or cause ATM initialization failure */ - int (*atm_start) (struct usbatm_data *, struct atm_dev *); - - /* cleanup ATM device ... can sleep, but can't fail */ - void (*atm_stop) (struct usbatm_data *, struct atm_dev *); - - int bulk_in; /* bulk rx endpoint */ - int isoc_in; /* isochronous rx endpoint */ - int bulk_out; /* bulk tx endpoint */ - - unsigned rx_padding; - unsigned tx_padding; -}; - -extern int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, - struct usbatm_driver *driver); -extern void usbatm_usb_disconnect(struct usb_interface *intf); - - -struct usbatm_channel { - int endpoint; /* usb pipe */ - unsigned int stride; /* ATM cell size + padding */ - unsigned int buf_size; /* urb buffer size */ - unsigned int packet_size; /* endpoint maxpacket */ - spinlock_t lock; - struct list_head list; - struct tasklet_struct tasklet; - struct timer_list delay; - struct usbatm_data *usbatm; -}; - -/* main driver data */ - -struct usbatm_data { - /****************** - * public fields * - ******************/ - - /* mini driver */ - struct usbatm_driver *driver; - void *driver_data; - char driver_name[16]; - unsigned int flags; /* set by mini-driver in bind() */ - - /* USB device */ - struct usb_device *usb_dev; - struct usb_interface *usb_intf; - char description[64]; - - /* ATM device */ - struct atm_dev *atm_dev; - - /******************************** - * private fields - do not use * - ********************************/ - - struct kref refcount; - struct mutex serialize; - int disconnected; - - /* heavy init */ - struct task_struct *thread; - struct completion thread_started; - struct completion thread_exited; - - /* ATM device */ - struct list_head vcc_list; - - struct usbatm_channel rx_channel; - struct usbatm_channel tx_channel; - - struct sk_buff_head sndqueue; - struct sk_buff *current_skb; /* being emptied */ - - struct usbatm_vcc_data *cached_vcc; - int cached_vci; - short cached_vpi; - - unsigned char *cell_buf; /* holds partial rx cell */ - unsigned int buf_usage; - - struct urb *urbs[0]; -}; - -static inline void *to_usbatm_driver_data(struct usb_interface *intf) -{ - struct usbatm_data *usbatm_instance; - - if (intf == NULL) - return NULL; - - usbatm_instance = usb_get_intfdata(intf); - - if (usbatm_instance == NULL) /* set NULL before unbind() */ - return NULL; - - return usbatm_instance->driver_data; /* set NULL after unbind() */ -} - -#endif /* _USBATM_H_ */ diff --git a/ANDROID_3.4.5/drivers/usb/atm/xusbatm.c b/ANDROID_3.4.5/drivers/usb/atm/xusbatm.c deleted file mode 100644 index 48ee0c5f..00000000 --- a/ANDROID_3.4.5/drivers/usb/atm/xusbatm.c +++ /dev/null @@ -1,233 +0,0 @@ -/****************************************************************************** - * xusbatm.c - dumb usbatm-based driver for modems initialized in userspace - * - * Copyright (C) 2005 Duncan Sands, Roman Kagan (rkagan % mail ! ru) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - ******************************************************************************/ - -#include -#include /* for random_ether_addr() */ - -#include "usbatm.h" - - -#define XUSBATM_DRIVERS_MAX 8 - -#define XUSBATM_PARM(name, type, parmtype, desc) \ - static type name[XUSBATM_DRIVERS_MAX]; \ - static unsigned int num_##name; \ - module_param_array(name, parmtype, &num_##name, 0444); \ - MODULE_PARM_DESC(name, desc) - -XUSBATM_PARM(vendor, unsigned short, ushort, "USB device vendor"); -XUSBATM_PARM(product, unsigned short, ushort, "USB device product"); - -XUSBATM_PARM(rx_endpoint, unsigned char, byte, "rx endpoint number"); -XUSBATM_PARM(tx_endpoint, unsigned char, byte, "tx endpoint number"); -XUSBATM_PARM(rx_padding, unsigned char, byte, "rx padding (default 0)"); -XUSBATM_PARM(tx_padding, unsigned char, byte, "tx padding (default 0)"); -XUSBATM_PARM(rx_altsetting, unsigned char, byte, "rx altsetting (default 0)"); -XUSBATM_PARM(tx_altsetting, unsigned char, byte, "rx altsetting (default 0)"); - -static const char xusbatm_driver_name[] = "xusbatm"; - -static struct usbatm_driver xusbatm_drivers[XUSBATM_DRIVERS_MAX]; -static struct usb_device_id xusbatm_usb_ids[XUSBATM_DRIVERS_MAX + 1]; -static struct usb_driver xusbatm_usb_driver; - -static struct usb_interface *xusbatm_find_intf(struct usb_device *usb_dev, int altsetting, u8 ep) -{ - struct usb_host_interface *alt; - struct usb_interface *intf; - int i, j; - - for (i = 0; i < usb_dev->actconfig->desc.bNumInterfaces; i++) - if ((intf = usb_dev->actconfig->interface[i]) && (alt = usb_altnum_to_altsetting(intf, altsetting))) - for (j = 0; j < alt->desc.bNumEndpoints; j++) - if (alt->endpoint[j].desc.bEndpointAddress == ep) - return intf; - return NULL; -} - -static int xusbatm_capture_intf(struct usbatm_data *usbatm, struct usb_device *usb_dev, - struct usb_interface *intf, int altsetting, int claim) -{ - int ifnum = intf->altsetting->desc.bInterfaceNumber; - int ret; - - if (claim && (ret = usb_driver_claim_interface(&xusbatm_usb_driver, intf, usbatm))) { - usb_err(usbatm, "%s: failed to claim interface %2d (%d)!\n", __func__, ifnum, ret); - return ret; - } - if ((ret = usb_set_interface(usb_dev, ifnum, altsetting))) { - usb_err(usbatm, "%s: altsetting %2d for interface %2d failed (%d)!\n", __func__, altsetting, ifnum, ret); - return ret; - } - return 0; -} - -static void xusbatm_release_intf(struct usb_device *usb_dev, struct usb_interface *intf, int claimed) -{ - if (claimed) { - usb_set_intfdata(intf, NULL); - usb_driver_release_interface(&xusbatm_usb_driver, intf); - } -} - -static int xusbatm_bind(struct usbatm_data *usbatm, - struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_device *usb_dev = interface_to_usbdev(intf); - int drv_ix = id - xusbatm_usb_ids; - int rx_alt = rx_altsetting[drv_ix]; - int tx_alt = tx_altsetting[drv_ix]; - struct usb_interface *rx_intf = xusbatm_find_intf(usb_dev, rx_alt, rx_endpoint[drv_ix]); - struct usb_interface *tx_intf = xusbatm_find_intf(usb_dev, tx_alt, tx_endpoint[drv_ix]); - int ret; - - usb_dbg(usbatm, "%s: binding driver %d: vendor %04x product %04x" - " rx: ep %02x padd %d alt %2d tx: ep %02x padd %d alt %2d\n", - __func__, drv_ix, vendor[drv_ix], product[drv_ix], - rx_endpoint[drv_ix], rx_padding[drv_ix], rx_alt, - tx_endpoint[drv_ix], tx_padding[drv_ix], tx_alt); - - if (!rx_intf || !tx_intf) { - if (!rx_intf) - usb_dbg(usbatm, "%s: no interface contains endpoint %02x in altsetting %2d\n", - __func__, rx_endpoint[drv_ix], rx_alt); - if (!tx_intf) - usb_dbg(usbatm, "%s: no interface contains endpoint %02x in altsetting %2d\n", - __func__, tx_endpoint[drv_ix], tx_alt); - return -ENODEV; - } - - if ((rx_intf != intf) && (tx_intf != intf)) - return -ENODEV; - - if ((rx_intf == tx_intf) && (rx_alt != tx_alt)) { - usb_err(usbatm, "%s: altsettings clash on interface %2d (%2d vs %2d)!\n", __func__, - rx_intf->altsetting->desc.bInterfaceNumber, rx_alt, tx_alt); - return -EINVAL; - } - - usb_dbg(usbatm, "%s: rx If#=%2d; tx If#=%2d\n", __func__, - rx_intf->altsetting->desc.bInterfaceNumber, - tx_intf->altsetting->desc.bInterfaceNumber); - - if ((ret = xusbatm_capture_intf(usbatm, usb_dev, rx_intf, rx_alt, rx_intf != intf))) - return ret; - - if ((tx_intf != rx_intf) && (ret = xusbatm_capture_intf(usbatm, usb_dev, tx_intf, tx_alt, tx_intf != intf))) { - xusbatm_release_intf(usb_dev, rx_intf, rx_intf != intf); - return ret; - } - - return 0; -} - -static void xusbatm_unbind(struct usbatm_data *usbatm, - struct usb_interface *intf) -{ - struct usb_device *usb_dev = interface_to_usbdev(intf); - int i; - - usb_dbg(usbatm, "%s entered\n", __func__); - - for (i = 0; i < usb_dev->actconfig->desc.bNumInterfaces; i++) { - struct usb_interface *cur_intf = usb_dev->actconfig->interface[i]; - - if (cur_intf && (usb_get_intfdata(cur_intf) == usbatm)) { - usb_set_intfdata(cur_intf, NULL); - usb_driver_release_interface(&xusbatm_usb_driver, cur_intf); - } - } -} - -static int xusbatm_atm_start(struct usbatm_data *usbatm, - struct atm_dev *atm_dev) -{ - atm_dbg(usbatm, "%s entered\n", __func__); - - /* use random MAC as we've no way to get it from the device */ - random_ether_addr(atm_dev->esi); - - return 0; -} - - -static int xusbatm_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return usbatm_usb_probe(intf, id, - xusbatm_drivers + (id - xusbatm_usb_ids)); -} - -static struct usb_driver xusbatm_usb_driver = { - .name = xusbatm_driver_name, - .probe = xusbatm_usb_probe, - .disconnect = usbatm_usb_disconnect, - .id_table = xusbatm_usb_ids -}; - -static int __init xusbatm_init(void) -{ - int i; - - dbg("xusbatm_init"); - - if (!num_vendor || - num_vendor != num_product || - num_vendor != num_rx_endpoint || - num_vendor != num_tx_endpoint) { - printk(KERN_WARNING "xusbatm: malformed module parameters\n"); - return -EINVAL; - } - - for (i = 0; i < num_vendor; i++) { - rx_endpoint[i] |= USB_DIR_IN; - tx_endpoint[i] &= USB_ENDPOINT_NUMBER_MASK; - - xusbatm_usb_ids[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE; - xusbatm_usb_ids[i].idVendor = vendor[i]; - xusbatm_usb_ids[i].idProduct = product[i]; - - xusbatm_drivers[i].driver_name = xusbatm_driver_name; - xusbatm_drivers[i].bind = xusbatm_bind; - xusbatm_drivers[i].unbind = xusbatm_unbind; - xusbatm_drivers[i].atm_start = xusbatm_atm_start; - xusbatm_drivers[i].bulk_in = rx_endpoint[i]; - xusbatm_drivers[i].bulk_out = tx_endpoint[i]; - xusbatm_drivers[i].rx_padding = rx_padding[i]; - xusbatm_drivers[i].tx_padding = tx_padding[i]; - } - - return usb_register(&xusbatm_usb_driver); -} -module_init(xusbatm_init); - -static void __exit xusbatm_exit(void) -{ - dbg("xusbatm_exit entered"); - - usb_deregister(&xusbatm_usb_driver); -} -module_exit(xusbatm_exit); - -MODULE_AUTHOR("Roman Kagan, Duncan Sands"); -MODULE_DESCRIPTION("Driver for USB ADSL modems initialized in userspace"); -MODULE_LICENSE("GPL"); -MODULE_VERSION("0.1"); diff --git a/ANDROID_3.4.5/drivers/usb/c67x00/Makefile b/ANDROID_3.4.5/drivers/usb/c67x00/Makefile deleted file mode 100644 index b1218683..00000000 --- a/ANDROID_3.4.5/drivers/usb/c67x00/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Makefile for Cypress C67X00 USB Controller -# - -ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG - -obj-$(CONFIG_USB_C67X00_HCD) += c67x00.o - -c67x00-y := c67x00-drv.o c67x00-ll-hpi.o c67x00-hcd.o c67x00-sched.o diff --git a/ANDROID_3.4.5/drivers/usb/c67x00/c67x00-drv.c b/ANDROID_3.4.5/drivers/usb/c67x00/c67x00-drv.c deleted file mode 100644 index 6f3b6e26..00000000 --- a/ANDROID_3.4.5/drivers/usb/c67x00/c67x00-drv.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - * c67x00-drv.c: Cypress C67X00 USB Common infrastructure - * - * Copyright (C) 2006-2008 Barco N.V. - * Derived from the Cypress cy7c67200/300 ezusb linux driver and - * based on multiple host controller drivers inside the linux kernel. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA. - */ - -/* - * This file implements the common infrastructure for using the c67x00. - * It is both the link between the platform configuration and subdrivers and - * the link between the common hardware parts and the subdrivers (e.g. - * interrupt handling). - * - * The c67x00 has 2 SIE's (serial interface engine) which can be configured - * to be host, device or OTG (with some limitations, E.G. only SIE1 can be OTG). - * - * Depending on the platform configuration, the SIE's are created and - * the corresponding subdriver is initialized (c67x00_probe_sie). - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "c67x00.h" -#include "c67x00-hcd.h" - -static void c67x00_probe_sie(struct c67x00_sie *sie, - struct c67x00_device *dev, int sie_num) -{ - spin_lock_init(&sie->lock); - sie->dev = dev; - sie->sie_num = sie_num; - sie->mode = c67x00_sie_config(dev->pdata->sie_config, sie_num); - - switch (sie->mode) { - case C67X00_SIE_HOST: - c67x00_hcd_probe(sie); - break; - - case C67X00_SIE_UNUSED: - dev_info(sie_dev(sie), - "Not using SIE %d as requested\n", sie->sie_num); - break; - - default: - dev_err(sie_dev(sie), - "Unsupported configuration: 0x%x for SIE %d\n", - sie->mode, sie->sie_num); - break; - } -} - -static void c67x00_remove_sie(struct c67x00_sie *sie) -{ - switch (sie->mode) { - case C67X00_SIE_HOST: - c67x00_hcd_remove(sie); - break; - - default: - break; - } -} - -static irqreturn_t c67x00_irq(int irq, void *__dev) -{ - struct c67x00_device *c67x00 = __dev; - struct c67x00_sie *sie; - u16 msg, int_status; - int i, count = 8; - - int_status = c67x00_ll_hpi_status(c67x00); - if (!int_status) - return IRQ_NONE; - - while (int_status != 0 && (count-- >= 0)) { - c67x00_ll_irq(c67x00, int_status); - for (i = 0; i < C67X00_SIES; i++) { - sie = &c67x00->sie[i]; - msg = 0; - if (int_status & SIEMSG_FLG(i)) - msg = c67x00_ll_fetch_siemsg(c67x00, i); - if (sie->irq) - sie->irq(sie, int_status, msg); - } - int_status = c67x00_ll_hpi_status(c67x00); - } - - if (int_status) - dev_warn(&c67x00->pdev->dev, "Not all interrupts handled! " - "status = 0x%04x\n", int_status); - - return IRQ_HANDLED; -} - -/* ------------------------------------------------------------------------- */ - -static int __devinit c67x00_drv_probe(struct platform_device *pdev) -{ - struct c67x00_device *c67x00; - struct c67x00_platform_data *pdata; - struct resource *res, *res2; - int ret, i; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res2) - return -ENODEV; - - pdata = pdev->dev.platform_data; - if (!pdata) - return -ENODEV; - - c67x00 = kzalloc(sizeof(*c67x00), GFP_KERNEL); - if (!c67x00) - return -ENOMEM; - - if (!request_mem_region(res->start, resource_size(res), - pdev->name)) { - dev_err(&pdev->dev, "Memory region busy\n"); - ret = -EBUSY; - goto request_mem_failed; - } - c67x00->hpi.base = ioremap(res->start, resource_size(res)); - if (!c67x00->hpi.base) { - dev_err(&pdev->dev, "Unable to map HPI registers\n"); - ret = -EIO; - goto map_failed; - } - - spin_lock_init(&c67x00->hpi.lock); - c67x00->hpi.regstep = pdata->hpi_regstep; - c67x00->pdata = pdev->dev.platform_data; - c67x00->pdev = pdev; - - c67x00_ll_init(c67x00); - c67x00_ll_hpi_reg_init(c67x00); - - ret = request_irq(res2->start, c67x00_irq, 0, pdev->name, c67x00); - if (ret) { - dev_err(&pdev->dev, "Cannot claim IRQ\n"); - goto request_irq_failed; - } - - ret = c67x00_ll_reset(c67x00); - if (ret) { - dev_err(&pdev->dev, "Device reset failed\n"); - goto reset_failed; - } - - for (i = 0; i < C67X00_SIES; i++) - c67x00_probe_sie(&c67x00->sie[i], c67x00, i); - - platform_set_drvdata(pdev, c67x00); - - return 0; - - reset_failed: - free_irq(res2->start, c67x00); - request_irq_failed: - iounmap(c67x00->hpi.base); - map_failed: - release_mem_region(res->start, resource_size(res)); - request_mem_failed: - kfree(c67x00); - - return ret; -} - -static int __devexit c67x00_drv_remove(struct platform_device *pdev) -{ - struct c67x00_device *c67x00 = platform_get_drvdata(pdev); - struct resource *res; - int i; - - for (i = 0; i < C67X00_SIES; i++) - c67x00_remove_sie(&c67x00->sie[i]); - - c67x00_ll_release(c67x00); - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (res) - free_irq(res->start, c67x00); - - iounmap(c67x00->hpi.base); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res) - release_mem_region(res->start, resource_size(res)); - - kfree(c67x00); - - return 0; -} - -static struct platform_driver c67x00_driver = { - .probe = c67x00_drv_probe, - .remove = __devexit_p(c67x00_drv_remove), - .driver = { - .owner = THIS_MODULE, - .name = "c67x00", - }, -}; - -module_platform_driver(c67x00_driver); - -MODULE_AUTHOR("Peter Korsgaard, Jan Veldeman, Grant Likely"); -MODULE_DESCRIPTION("Cypress C67X00 USB Controller Driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:c67x00"); diff --git a/ANDROID_3.4.5/drivers/usb/c67x00/c67x00-hcd.c b/ANDROID_3.4.5/drivers/usb/c67x00/c67x00-hcd.c deleted file mode 100644 index 75e47b86..00000000 --- a/ANDROID_3.4.5/drivers/usb/c67x00/c67x00-hcd.c +++ /dev/null @@ -1,411 +0,0 @@ -/* - * c67x00-hcd.c: Cypress C67X00 USB Host Controller Driver - * - * Copyright (C) 2006-2008 Barco N.V. - * Derived from the Cypress cy7c67200/300 ezusb linux driver and - * based on multiple host controller drivers inside the linux kernel. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA. - */ - -#include -#include -#include - -#include "c67x00.h" -#include "c67x00-hcd.h" - -/* -------------------------------------------------------------------------- - * Root Hub Support - */ - -static __u8 c67x00_hub_des[] = { - 0x09, /* __u8 bLength; */ - 0x29, /* __u8 bDescriptorType; Hub-descriptor */ - 0x02, /* __u8 bNbrPorts; */ - 0x00, /* __u16 wHubCharacteristics; */ - 0x00, /* (per-port OC, no power switching) */ - 0x32, /* __u8 bPwrOn2pwrGood; 2ms */ - 0x00, /* __u8 bHubContrCurrent; 0 mA */ - 0x00, /* __u8 DeviceRemovable; ** 7 Ports max ** */ - 0xff, /* __u8 PortPwrCtrlMask; ** 7 ports max ** */ -}; - -static void c67x00_hub_reset_host_port(struct c67x00_sie *sie, int port) -{ - struct c67x00_hcd *c67x00 = sie->private_data; - unsigned long flags; - - c67x00_ll_husb_reset(sie, port); - - spin_lock_irqsave(&c67x00->lock, flags); - c67x00_ll_husb_reset_port(sie, port); - spin_unlock_irqrestore(&c67x00->lock, flags); - - c67x00_ll_set_husb_eot(sie->dev, DEFAULT_EOT); -} - -static int c67x00_hub_status_data(struct usb_hcd *hcd, char *buf) -{ - struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd); - struct c67x00_sie *sie = c67x00->sie; - u16 status; - int i; - - *buf = 0; - status = c67x00_ll_usb_get_status(sie); - for (i = 0; i < C67X00_PORTS; i++) - if (status & PORT_CONNECT_CHANGE(i)) - *buf |= (1 << i); - - /* bit 0 denotes hub change, b1..n port change */ - *buf <<= 1; - - return !!*buf; -} - -static int c67x00_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, - u16 wIndex, char *buf, u16 wLength) -{ - struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd); - struct c67x00_sie *sie = c67x00->sie; - u16 status, usb_status; - int len = 0; - unsigned int port = wIndex-1; - u16 wPortChange, wPortStatus; - - switch (typeReq) { - - case GetHubStatus: - *(__le32 *) buf = cpu_to_le32(0); - len = 4; /* hub power */ - break; - - case GetPortStatus: - if (wIndex > C67X00_PORTS) - return -EPIPE; - - status = c67x00_ll_usb_get_status(sie); - usb_status = c67x00_ll_get_usb_ctl(sie); - - wPortChange = 0; - if (status & PORT_CONNECT_CHANGE(port)) - wPortChange |= USB_PORT_STAT_C_CONNECTION; - - wPortStatus = USB_PORT_STAT_POWER; - if (!(status & PORT_SE0_STATUS(port))) - wPortStatus |= USB_PORT_STAT_CONNECTION; - if (usb_status & LOW_SPEED_PORT(port)) { - wPortStatus |= USB_PORT_STAT_LOW_SPEED; - c67x00->low_speed_ports |= (1 << port); - } else - c67x00->low_speed_ports &= ~(1 << port); - - if (usb_status & SOF_EOP_EN(port)) - wPortStatus |= USB_PORT_STAT_ENABLE; - - *(__le16 *) buf = cpu_to_le16(wPortStatus); - *(__le16 *) (buf + 2) = cpu_to_le16(wPortChange); - len = 4; - break; - - case SetHubFeature: /* We don't implement these */ - case ClearHubFeature: - switch (wValue) { - case C_HUB_OVER_CURRENT: - case C_HUB_LOCAL_POWER: - len = 0; - break; - - default: - return -EPIPE; - } - break; - - case SetPortFeature: - if (wIndex > C67X00_PORTS) - return -EPIPE; - - switch (wValue) { - case USB_PORT_FEAT_SUSPEND: - dev_dbg(c67x00_hcd_dev(c67x00), - "SetPortFeature %d (SUSPEND)\n", port); - len = 0; - break; - - case USB_PORT_FEAT_RESET: - c67x00_hub_reset_host_port(sie, port); - len = 0; - break; - - case USB_PORT_FEAT_POWER: - /* Power always enabled */ - len = 0; - break; - - default: - dev_dbg(c67x00_hcd_dev(c67x00), - "%s: SetPortFeature %d (0x%04x) Error!\n", - __func__, port, wValue); - return -EPIPE; - } - break; - - case ClearPortFeature: - if (wIndex > C67X00_PORTS) - return -EPIPE; - - switch (wValue) { - case USB_PORT_FEAT_ENABLE: - /* Reset the port so that the c67x00 also notices the - * disconnect */ - c67x00_hub_reset_host_port(sie, port); - len = 0; - break; - - case USB_PORT_FEAT_C_ENABLE: - dev_dbg(c67x00_hcd_dev(c67x00), - "ClearPortFeature (%d): C_ENABLE\n", port); - len = 0; - break; - - case USB_PORT_FEAT_SUSPEND: - dev_dbg(c67x00_hcd_dev(c67x00), - "ClearPortFeature (%d): SUSPEND\n", port); - len = 0; - break; - - case USB_PORT_FEAT_C_SUSPEND: - dev_dbg(c67x00_hcd_dev(c67x00), - "ClearPortFeature (%d): C_SUSPEND\n", port); - len = 0; - break; - - case USB_PORT_FEAT_POWER: - dev_dbg(c67x00_hcd_dev(c67x00), - "ClearPortFeature (%d): POWER\n", port); - return -EPIPE; - - case USB_PORT_FEAT_C_CONNECTION: - c67x00_ll_usb_clear_status(sie, - PORT_CONNECT_CHANGE(port)); - len = 0; - break; - - case USB_PORT_FEAT_C_OVER_CURRENT: - dev_dbg(c67x00_hcd_dev(c67x00), - "ClearPortFeature (%d): OVER_CURRENT\n", port); - len = 0; - break; - - case USB_PORT_FEAT_C_RESET: - dev_dbg(c67x00_hcd_dev(c67x00), - "ClearPortFeature (%d): C_RESET\n", port); - len = 0; - break; - - default: - dev_dbg(c67x00_hcd_dev(c67x00), - "%s: ClearPortFeature %d (0x%04x) Error!\n", - __func__, port, wValue); - return -EPIPE; - } - break; - - case GetHubDescriptor: - len = min_t(unsigned int, sizeof(c67x00_hub_des), wLength); - memcpy(buf, c67x00_hub_des, len); - break; - - default: - dev_dbg(c67x00_hcd_dev(c67x00), "%s: unknown\n", __func__); - return -EPIPE; - } - - return 0; -} - -/* --------------------------------------------------------------------- - * Main part of host controller driver - */ - -/** - * c67x00_hcd_irq - * - * This function is called from the interrupt handler in c67x00-drv.c - */ -static void c67x00_hcd_irq(struct c67x00_sie *sie, u16 int_status, u16 msg) -{ - struct c67x00_hcd *c67x00 = sie->private_data; - struct usb_hcd *hcd = c67x00_hcd_to_hcd(c67x00); - - /* Handle sie message flags */ - if (msg) { - if (msg & HUSB_TDListDone) - c67x00_sched_kick(c67x00); - else - dev_warn(c67x00_hcd_dev(c67x00), - "Unknown SIE msg flag(s): 0x%04x\n", msg); - } - - if (unlikely(hcd->state == HC_STATE_HALT)) - return; - - if (!HCD_HW_ACCESSIBLE(hcd)) - return; - - /* Handle Start of frame events */ - if (int_status & SOFEOP_FLG(sie->sie_num)) { - c67x00_ll_usb_clear_status(sie, SOF_EOP_IRQ_FLG); - c67x00_sched_kick(c67x00); - } -} - -/** - * c67x00_hcd_start: Host controller start hook - */ -static int c67x00_hcd_start(struct usb_hcd *hcd) -{ - hcd->uses_new_polling = 1; - hcd->state = HC_STATE_RUNNING; - set_bit(HCD_FLAG_POLL_RH, &hcd->flags); - - return 0; -} - -/** - * c67x00_hcd_stop: Host controller stop hook - */ -static void c67x00_hcd_stop(struct usb_hcd *hcd) -{ - /* Nothing to do */ -} - -static int c67x00_hcd_get_frame(struct usb_hcd *hcd) -{ - struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd); - u16 temp_val; - - dev_dbg(c67x00_hcd_dev(c67x00), "%s\n", __func__); - temp_val = c67x00_ll_husb_get_frame(c67x00->sie); - temp_val &= HOST_FRAME_MASK; - return temp_val ? (temp_val - 1) : HOST_FRAME_MASK; -} - -static struct hc_driver c67x00_hc_driver = { - .description = "c67x00-hcd", - .product_desc = "Cypress C67X00 Host Controller", - .hcd_priv_size = sizeof(struct c67x00_hcd), - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .start = c67x00_hcd_start, - .stop = c67x00_hcd_stop, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = c67x00_urb_enqueue, - .urb_dequeue = c67x00_urb_dequeue, - .endpoint_disable = c67x00_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = c67x00_hcd_get_frame, - - /* - * root hub support - */ - .hub_status_data = c67x00_hub_status_data, - .hub_control = c67x00_hub_control, -}; - -/* --------------------------------------------------------------------- - * Setup/Teardown routines - */ - -int c67x00_hcd_probe(struct c67x00_sie *sie) -{ - struct c67x00_hcd *c67x00; - struct usb_hcd *hcd; - unsigned long flags; - int retval; - - if (usb_disabled()) - return -ENODEV; - - hcd = usb_create_hcd(&c67x00_hc_driver, sie_dev(sie), "c67x00_sie"); - if (!hcd) { - retval = -ENOMEM; - goto err0; - } - c67x00 = hcd_to_c67x00_hcd(hcd); - - spin_lock_init(&c67x00->lock); - c67x00->sie = sie; - - INIT_LIST_HEAD(&c67x00->list[PIPE_ISOCHRONOUS]); - INIT_LIST_HEAD(&c67x00->list[PIPE_INTERRUPT]); - INIT_LIST_HEAD(&c67x00->list[PIPE_CONTROL]); - INIT_LIST_HEAD(&c67x00->list[PIPE_BULK]); - c67x00->urb_count = 0; - INIT_LIST_HEAD(&c67x00->td_list); - c67x00->td_base_addr = CY_HCD_BUF_ADDR + SIE_TD_OFFSET(sie->sie_num); - c67x00->buf_base_addr = CY_HCD_BUF_ADDR + SIE_BUF_OFFSET(sie->sie_num); - c67x00->max_frame_bw = MAX_FRAME_BW_STD; - - c67x00_ll_husb_init_host_port(sie); - - init_completion(&c67x00->endpoint_disable); - retval = c67x00_sched_start_scheduler(c67x00); - if (retval) - goto err1; - - retval = usb_add_hcd(hcd, 0, 0); - if (retval) { - dev_dbg(sie_dev(sie), "%s: usb_add_hcd returned %d\n", - __func__, retval); - goto err2; - } - - spin_lock_irqsave(&sie->lock, flags); - sie->private_data = c67x00; - sie->irq = c67x00_hcd_irq; - spin_unlock_irqrestore(&sie->lock, flags); - - return retval; - - err2: - c67x00_sched_stop_scheduler(c67x00); - err1: - usb_put_hcd(hcd); - err0: - return retval; -} - -/* may be called with controller, bus, and devices active */ -void c67x00_hcd_remove(struct c67x00_sie *sie) -{ - struct c67x00_hcd *c67x00 = sie->private_data; - struct usb_hcd *hcd = c67x00_hcd_to_hcd(c67x00); - - c67x00_sched_stop_scheduler(c67x00); - usb_remove_hcd(hcd); - usb_put_hcd(hcd); -} diff --git a/ANDROID_3.4.5/drivers/usb/c67x00/c67x00-hcd.h b/ANDROID_3.4.5/drivers/usb/c67x00/c67x00-hcd.h deleted file mode 100644 index e3d493d4..00000000 --- a/ANDROID_3.4.5/drivers/usb/c67x00/c67x00-hcd.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * c67x00-hcd.h: Cypress C67X00 USB HCD - * - * Copyright (C) 2006-2008 Barco N.V. - * Derived from the Cypress cy7c67200/300 ezusb linux driver and - * based on multiple host controller drivers inside the linux kernel. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA. - */ - -#ifndef _USB_C67X00_HCD_H -#define _USB_C67X00_HCD_H - -#include -#include -#include -#include -#include -#include "c67x00.h" - -/* - * The following parameters depend on the CPU speed, bus speed, ... - * These can be tuned for specific use cases, e.g. if isochronous transfers - * are very important, bandwidth can be sacrificed to guarantee that the - * 1ms deadline will be met. - * If bulk transfers are important, the MAX_FRAME_BW can be increased, - * but some (or many) isochronous deadlines might not be met. - * - * The values are specified in bittime. - */ - -/* - * The current implementation switches between _STD (default) and _ISO (when - * isochronous transfers are scheduled), in order to optimize the throughput - * in normal cicrumstances, but also provide good isochronous behaviour. - * - * Bandwidth is described in bit time so with a 12MHz USB clock and 1ms - * frames; there are 12000 bit times per frame. - */ - -#define TOTAL_FRAME_BW 12000 -#define DEFAULT_EOT 2250 - -#define MAX_FRAME_BW_STD (TOTAL_FRAME_BW - DEFAULT_EOT) -#define MAX_FRAME_BW_ISO 2400 - -/* - * Periodic transfers may only use 90% of the full frame, but as - * we currently don't even use 90% of the full frame, we may - * use the full usable time for periodic transfers. - */ -#define MAX_PERIODIC_BW(full_bw) full_bw - -/* -------------------------------------------------------------------------- */ - -struct c67x00_hcd { - spinlock_t lock; - struct c67x00_sie *sie; - unsigned int low_speed_ports; /* bitmask of low speed ports */ - unsigned int urb_count; - unsigned int urb_iso_count; - - struct list_head list[4]; /* iso, int, ctrl, bulk */ -#if PIPE_BULK != 3 -#error "Sanity check failed, this code presumes PIPE_... to range from 0 to 3" -#endif - - /* USB bandwidth allocated to td_list */ - int bandwidth_allocated; - /* USB bandwidth allocated for isoc/int transfer */ - int periodic_bw_allocated; - struct list_head td_list; - int max_frame_bw; - - u16 td_base_addr; - u16 buf_base_addr; - u16 next_td_addr; - u16 next_buf_addr; - - struct tasklet_struct tasklet; - - struct completion endpoint_disable; - - u16 current_frame; - u16 last_frame; -}; - -static inline struct c67x00_hcd *hcd_to_c67x00_hcd(struct usb_hcd *hcd) -{ - return (struct c67x00_hcd *)(hcd->hcd_priv); -} - -static inline struct usb_hcd *c67x00_hcd_to_hcd(struct c67x00_hcd *c67x00) -{ - return container_of((void *)c67x00, struct usb_hcd, hcd_priv); -} - -/* --------------------------------------------------------------------- - * Functions used by c67x00-drv - */ - -int c67x00_hcd_probe(struct c67x00_sie *sie); -void c67x00_hcd_remove(struct c67x00_sie *sie); - -/* --------------------------------------------------------------------- - * Transfer Descriptor scheduling functions - */ -int c67x00_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags); -int c67x00_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status); -void c67x00_endpoint_disable(struct usb_hcd *hcd, - struct usb_host_endpoint *ep); - -void c67x00_hcd_msg_received(struct c67x00_sie *sie, u16 msg); -void c67x00_sched_kick(struct c67x00_hcd *c67x00); -int c67x00_sched_start_scheduler(struct c67x00_hcd *c67x00); -void c67x00_sched_stop_scheduler(struct c67x00_hcd *c67x00); - -#define c67x00_hcd_dev(x) (c67x00_hcd_to_hcd(x)->self.controller) - -#endif /* _USB_C67X00_HCD_H */ diff --git a/ANDROID_3.4.5/drivers/usb/c67x00/c67x00-ll-hpi.c b/ANDROID_3.4.5/drivers/usb/c67x00/c67x00-ll-hpi.c deleted file mode 100644 index a9636f43..00000000 --- a/ANDROID_3.4.5/drivers/usb/c67x00/c67x00-ll-hpi.c +++ /dev/null @@ -1,481 +0,0 @@ -/* - * c67x00-ll-hpi.c: Cypress C67X00 USB Low level interface using HPI - * - * Copyright (C) 2006-2008 Barco N.V. - * Derived from the Cypress cy7c67200/300 ezusb linux driver and - * based on multiple host controller drivers inside the linux kernel. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA. - */ - -#include -#include -#include -#include -#include "c67x00.h" - -#define COMM_REGS 14 - -struct c67x00_lcp_int_data { - u16 regs[COMM_REGS]; -}; - -/* -------------------------------------------------------------------------- */ -/* Interface definitions */ - -#define COMM_ACK 0x0FED -#define COMM_NAK 0xDEAD - -#define COMM_RESET 0xFA50 -#define COMM_EXEC_INT 0xCE01 -#define COMM_INT_NUM 0x01C2 - -/* Registers 0 to COMM_REGS-1 */ -#define COMM_R(x) (0x01C4 + 2 * (x)) - -#define HUSB_SIE_pCurrentTDPtr(x) ((x) ? 0x01B2 : 0x01B0) -#define HUSB_SIE_pTDListDone_Sem(x) ((x) ? 0x01B8 : 0x01B6) -#define HUSB_pEOT 0x01B4 - -/* Software interrupts */ -/* 114, 115: */ -#define HUSB_SIE_INIT_INT(x) ((x) ? 0x0073 : 0x0072) -#define HUSB_RESET_INT 0x0074 - -#define SUSB_INIT_INT 0x0071 -#define SUSB_INIT_INT_LOC (SUSB_INIT_INT * 2) - -/* ----------------------------------------------------------------------- - * HPI implementation - * - * The c67x00 chip also support control via SPI or HSS serial - * interfaces. However, this driver assumes that register access can - * be performed from IRQ context. While this is a safe assuption with - * the HPI interface, it is not true for the serial interfaces. - */ - -/* HPI registers */ -#define HPI_DATA 0 -#define HPI_MAILBOX 1 -#define HPI_ADDR 2 -#define HPI_STATUS 3 - -static inline u16 hpi_read_reg(struct c67x00_device *dev, int reg) -{ - return __raw_readw(dev->hpi.base + reg * dev->hpi.regstep); -} - -static inline void hpi_write_reg(struct c67x00_device *dev, int reg, u16 value) -{ - __raw_writew(value, dev->hpi.base + reg * dev->hpi.regstep); -} - -static inline u16 hpi_read_word_nolock(struct c67x00_device *dev, u16 reg) -{ - hpi_write_reg(dev, HPI_ADDR, reg); - return hpi_read_reg(dev, HPI_DATA); -} - -static u16 hpi_read_word(struct c67x00_device *dev, u16 reg) -{ - u16 value; - unsigned long flags; - - spin_lock_irqsave(&dev->hpi.lock, flags); - value = hpi_read_word_nolock(dev, reg); - spin_unlock_irqrestore(&dev->hpi.lock, flags); - - return value; -} - -static void hpi_write_word_nolock(struct c67x00_device *dev, u16 reg, u16 value) -{ - hpi_write_reg(dev, HPI_ADDR, reg); - hpi_write_reg(dev, HPI_DATA, value); -} - -static void hpi_write_word(struct c67x00_device *dev, u16 reg, u16 value) -{ - unsigned long flags; - - spin_lock_irqsave(&dev->hpi.lock, flags); - hpi_write_word_nolock(dev, reg, value); - spin_unlock_irqrestore(&dev->hpi.lock, flags); -} - -/* - * Only data is little endian, addr has cpu endianess - */ -static void hpi_write_words_le16(struct c67x00_device *dev, u16 addr, - __le16 *data, u16 count) -{ - unsigned long flags; - int i; - - spin_lock_irqsave(&dev->hpi.lock, flags); - - hpi_write_reg(dev, HPI_ADDR, addr); - for (i = 0; i < count; i++) - hpi_write_reg(dev, HPI_DATA, le16_to_cpu(*data++)); - - spin_unlock_irqrestore(&dev->hpi.lock, flags); -} - -/* - * Only data is little endian, addr has cpu endianess - */ -static void hpi_read_words_le16(struct c67x00_device *dev, u16 addr, - __le16 *data, u16 count) -{ - unsigned long flags; - int i; - - spin_lock_irqsave(&dev->hpi.lock, flags); - hpi_write_reg(dev, HPI_ADDR, addr); - for (i = 0; i < count; i++) - *data++ = cpu_to_le16(hpi_read_reg(dev, HPI_DATA)); - - spin_unlock_irqrestore(&dev->hpi.lock, flags); -} - -static void hpi_set_bits(struct c67x00_device *dev, u16 reg, u16 mask) -{ - u16 value; - unsigned long flags; - - spin_lock_irqsave(&dev->hpi.lock, flags); - value = hpi_read_word_nolock(dev, reg); - hpi_write_word_nolock(dev, reg, value | mask); - spin_unlock_irqrestore(&dev->hpi.lock, flags); -} - -static void hpi_clear_bits(struct c67x00_device *dev, u16 reg, u16 mask) -{ - u16 value; - unsigned long flags; - - spin_lock_irqsave(&dev->hpi.lock, flags); - value = hpi_read_word_nolock(dev, reg); - hpi_write_word_nolock(dev, reg, value & ~mask); - spin_unlock_irqrestore(&dev->hpi.lock, flags); -} - -static u16 hpi_recv_mbox(struct c67x00_device *dev) -{ - u16 value; - unsigned long flags; - - spin_lock_irqsave(&dev->hpi.lock, flags); - value = hpi_read_reg(dev, HPI_MAILBOX); - spin_unlock_irqrestore(&dev->hpi.lock, flags); - - return value; -} - -static u16 hpi_send_mbox(struct c67x00_device *dev, u16 value) -{ - unsigned long flags; - - spin_lock_irqsave(&dev->hpi.lock, flags); - hpi_write_reg(dev, HPI_MAILBOX, value); - spin_unlock_irqrestore(&dev->hpi.lock, flags); - - return value; -} - -u16 c67x00_ll_hpi_status(struct c67x00_device *dev) -{ - u16 value; - unsigned long flags; - - spin_lock_irqsave(&dev->hpi.lock, flags); - value = hpi_read_reg(dev, HPI_STATUS); - spin_unlock_irqrestore(&dev->hpi.lock, flags); - - return value; -} - -void c67x00_ll_hpi_reg_init(struct c67x00_device *dev) -{ - int i; - - hpi_recv_mbox(dev); - c67x00_ll_hpi_status(dev); - hpi_write_word(dev, HPI_IRQ_ROUTING_REG, 0); - - for (i = 0; i < C67X00_SIES; i++) { - hpi_write_word(dev, SIEMSG_REG(i), 0); - hpi_read_word(dev, SIEMSG_REG(i)); - } -} - -void c67x00_ll_hpi_enable_sofeop(struct c67x00_sie *sie) -{ - hpi_set_bits(sie->dev, HPI_IRQ_ROUTING_REG, - SOFEOP_TO_HPI_EN(sie->sie_num)); -} - -void c67x00_ll_hpi_disable_sofeop(struct c67x00_sie *sie) -{ - hpi_clear_bits(sie->dev, HPI_IRQ_ROUTING_REG, - SOFEOP_TO_HPI_EN(sie->sie_num)); -} - -/* -------------------------------------------------------------------------- */ -/* Transactions */ - -static inline u16 ll_recv_msg(struct c67x00_device *dev) -{ - u16 res; - - res = wait_for_completion_timeout(&dev->hpi.lcp.msg_received, 5 * HZ); - WARN_ON(!res); - - return (res == 0) ? -EIO : 0; -} - -/* -------------------------------------------------------------------------- */ -/* General functions */ - -u16 c67x00_ll_fetch_siemsg(struct c67x00_device *dev, int sie_num) -{ - u16 val; - - val = hpi_read_word(dev, SIEMSG_REG(sie_num)); - /* clear register to allow next message */ - hpi_write_word(dev, SIEMSG_REG(sie_num), 0); - - return val; -} - -u16 c67x00_ll_get_usb_ctl(struct c67x00_sie *sie) -{ - return hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num)); -} - -/** - * c67x00_ll_usb_clear_status - clear the USB status bits - */ -void c67x00_ll_usb_clear_status(struct c67x00_sie *sie, u16 bits) -{ - hpi_write_word(sie->dev, USB_STAT_REG(sie->sie_num), bits); -} - -u16 c67x00_ll_usb_get_status(struct c67x00_sie *sie) -{ - return hpi_read_word(sie->dev, USB_STAT_REG(sie->sie_num)); -} - -/* -------------------------------------------------------------------------- */ - -static int c67x00_comm_exec_int(struct c67x00_device *dev, u16 nr, - struct c67x00_lcp_int_data *data) -{ - int i, rc; - - mutex_lock(&dev->hpi.lcp.mutex); - hpi_write_word(dev, COMM_INT_NUM, nr); - for (i = 0; i < COMM_REGS; i++) - hpi_write_word(dev, COMM_R(i), data->regs[i]); - hpi_send_mbox(dev, COMM_EXEC_INT); - rc = ll_recv_msg(dev); - mutex_unlock(&dev->hpi.lcp.mutex); - - return rc; -} - -/* -------------------------------------------------------------------------- */ -/* Host specific functions */ - -void c67x00_ll_set_husb_eot(struct c67x00_device *dev, u16 value) -{ - mutex_lock(&dev->hpi.lcp.mutex); - hpi_write_word(dev, HUSB_pEOT, value); - mutex_unlock(&dev->hpi.lcp.mutex); -} - -static inline void c67x00_ll_husb_sie_init(struct c67x00_sie *sie) -{ - struct c67x00_device *dev = sie->dev; - struct c67x00_lcp_int_data data; - int rc; - - rc = c67x00_comm_exec_int(dev, HUSB_SIE_INIT_INT(sie->sie_num), &data); - BUG_ON(rc); /* No return path for error code; crash spectacularly */ -} - -void c67x00_ll_husb_reset(struct c67x00_sie *sie, int port) -{ - struct c67x00_device *dev = sie->dev; - struct c67x00_lcp_int_data data; - int rc; - - data.regs[0] = 50; /* Reset USB port for 50ms */ - data.regs[1] = port | (sie->sie_num << 1); - rc = c67x00_comm_exec_int(dev, HUSB_RESET_INT, &data); - BUG_ON(rc); /* No return path for error code; crash spectacularly */ -} - -void c67x00_ll_husb_set_current_td(struct c67x00_sie *sie, u16 addr) -{ - hpi_write_word(sie->dev, HUSB_SIE_pCurrentTDPtr(sie->sie_num), addr); -} - -u16 c67x00_ll_husb_get_current_td(struct c67x00_sie *sie) -{ - return hpi_read_word(sie->dev, HUSB_SIE_pCurrentTDPtr(sie->sie_num)); -} - -u16 c67x00_ll_husb_get_frame(struct c67x00_sie *sie) -{ - return hpi_read_word(sie->dev, HOST_FRAME_REG(sie->sie_num)); -} - -void c67x00_ll_husb_init_host_port(struct c67x00_sie *sie) -{ - /* Set port into host mode */ - hpi_set_bits(sie->dev, USB_CTL_REG(sie->sie_num), HOST_MODE); - c67x00_ll_husb_sie_init(sie); - /* Clear interrupts */ - c67x00_ll_usb_clear_status(sie, HOST_STAT_MASK); - /* Check */ - if (!(hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num)) & HOST_MODE)) - dev_warn(sie_dev(sie), - "SIE %d not set to host mode\n", sie->sie_num); -} - -void c67x00_ll_husb_reset_port(struct c67x00_sie *sie, int port) -{ - /* Clear connect change */ - c67x00_ll_usb_clear_status(sie, PORT_CONNECT_CHANGE(port)); - - /* Enable interrupts */ - hpi_set_bits(sie->dev, HPI_IRQ_ROUTING_REG, - SOFEOP_TO_CPU_EN(sie->sie_num)); - hpi_set_bits(sie->dev, HOST_IRQ_EN_REG(sie->sie_num), - SOF_EOP_IRQ_EN | DONE_IRQ_EN); - - /* Enable pull down transistors */ - hpi_set_bits(sie->dev, USB_CTL_REG(sie->sie_num), PORT_RES_EN(port)); -} - -/* -------------------------------------------------------------------------- */ - -void c67x00_ll_irq(struct c67x00_device *dev, u16 int_status) -{ - if ((int_status & MBX_OUT_FLG) == 0) - return; - - dev->hpi.lcp.last_msg = hpi_recv_mbox(dev); - complete(&dev->hpi.lcp.msg_received); -} - -/* -------------------------------------------------------------------------- */ - -int c67x00_ll_reset(struct c67x00_device *dev) -{ - int rc; - - mutex_lock(&dev->hpi.lcp.mutex); - hpi_send_mbox(dev, COMM_RESET); - rc = ll_recv_msg(dev); - mutex_unlock(&dev->hpi.lcp.mutex); - - return rc; -} - -/* -------------------------------------------------------------------------- */ - -/** - * c67x00_ll_write_mem_le16 - write into c67x00 memory - * Only data is little endian, addr has cpu endianess. - */ -void c67x00_ll_write_mem_le16(struct c67x00_device *dev, u16 addr, - void *data, int len) -{ - u8 *buf = data; - - /* Sanity check */ - if (addr + len > 0xffff) { - dev_err(&dev->pdev->dev, - "Trying to write beyond writable region!\n"); - return; - } - - if (addr & 0x01) { - /* unaligned access */ - u16 tmp; - tmp = hpi_read_word(dev, addr - 1); - tmp = (tmp & 0x00ff) | (*buf++ << 8); - hpi_write_word(dev, addr - 1, tmp); - addr++; - len--; - } - - hpi_write_words_le16(dev, addr, (__le16 *)buf, len / 2); - buf += len & ~0x01; - addr += len & ~0x01; - len &= 0x01; - - if (len) { - u16 tmp; - tmp = hpi_read_word(dev, addr); - tmp = (tmp & 0xff00) | *buf; - hpi_write_word(dev, addr, tmp); - } -} - -/** - * c67x00_ll_read_mem_le16 - read from c67x00 memory - * Only data is little endian, addr has cpu endianess. - */ -void c67x00_ll_read_mem_le16(struct c67x00_device *dev, u16 addr, - void *data, int len) -{ - u8 *buf = data; - - if (addr & 0x01) { - /* unaligned access */ - u16 tmp; - tmp = hpi_read_word(dev, addr - 1); - *buf++ = (tmp >> 8) & 0x00ff; - addr++; - len--; - } - - hpi_read_words_le16(dev, addr, (__le16 *)buf, len / 2); - buf += len & ~0x01; - addr += len & ~0x01; - len &= 0x01; - - if (len) { - u16 tmp; - tmp = hpi_read_word(dev, addr); - *buf = tmp & 0x00ff; - } -} - -/* -------------------------------------------------------------------------- */ - -void c67x00_ll_init(struct c67x00_device *dev) -{ - mutex_init(&dev->hpi.lcp.mutex); - init_completion(&dev->hpi.lcp.msg_received); -} - -void c67x00_ll_release(struct c67x00_device *dev) -{ -} diff --git a/ANDROID_3.4.5/drivers/usb/c67x00/c67x00-sched.c b/ANDROID_3.4.5/drivers/usb/c67x00/c67x00-sched.c deleted file mode 100644 index a03fbc15..00000000 --- a/ANDROID_3.4.5/drivers/usb/c67x00/c67x00-sched.c +++ /dev/null @@ -1,1171 +0,0 @@ -/* - * c67x00-sched.c: Cypress C67X00 USB Host Controller Driver - TD scheduling - * - * Copyright (C) 2006-2008 Barco N.V. - * Derived from the Cypress cy7c67200/300 ezusb linux driver and - * based on multiple host controller drivers inside the linux kernel. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA. - */ - -#include -#include - -#include "c67x00.h" -#include "c67x00-hcd.h" - -/* - * These are the stages for a control urb, they are kept - * in both urb->interval and td->privdata. - */ -#define SETUP_STAGE 0 -#define DATA_STAGE 1 -#define STATUS_STAGE 2 - -/* -------------------------------------------------------------------------- */ - -/** - * struct c67x00_ep_data: Host endpoint data structure - */ -struct c67x00_ep_data { - struct list_head queue; - struct list_head node; - struct usb_host_endpoint *hep; - struct usb_device *dev; - u16 next_frame; /* For int/isoc transactions */ -}; - -/** - * struct c67x00_td - * - * Hardware parts are little endiannes, SW in CPU endianess. - */ -struct c67x00_td { - /* HW specific part */ - __le16 ly_base_addr; /* Bytes 0-1 */ - __le16 port_length; /* Bytes 2-3 */ - u8 pid_ep; /* Byte 4 */ - u8 dev_addr; /* Byte 5 */ - u8 ctrl_reg; /* Byte 6 */ - u8 status; /* Byte 7 */ - u8 retry_cnt; /* Byte 8 */ -#define TT_OFFSET 2 -#define TT_CONTROL 0 -#define TT_ISOCHRONOUS 1 -#define TT_BULK 2 -#define TT_INTERRUPT 3 - u8 residue; /* Byte 9 */ - __le16 next_td_addr; /* Bytes 10-11 */ - /* SW part */ - struct list_head td_list; - u16 td_addr; - void *data; - struct urb *urb; - unsigned long privdata; - - /* These are needed for handling the toggle bits: - * an urb can be dequeued while a td is in progress - * after checking the td, the toggle bit might need to - * be fixed */ - struct c67x00_ep_data *ep_data; - unsigned int pipe; -}; - -struct c67x00_urb_priv { - struct list_head hep_node; - struct urb *urb; - int port; - int cnt; /* packet number for isoc */ - int status; - struct c67x00_ep_data *ep_data; -}; - -#define td_udev(td) ((td)->ep_data->dev) - -#define CY_TD_SIZE 12 - -#define TD_PIDEP_OFFSET 0x04 -#define TD_PIDEPMASK_PID 0xF0 -#define TD_PIDEPMASK_EP 0x0F -#define TD_PORTLENMASK_DL 0x02FF -#define TD_PORTLENMASK_PN 0xC000 - -#define TD_STATUS_OFFSET 0x07 -#define TD_STATUSMASK_ACK 0x01 -#define TD_STATUSMASK_ERR 0x02 -#define TD_STATUSMASK_TMOUT 0x04 -#define TD_STATUSMASK_SEQ 0x08 -#define TD_STATUSMASK_SETUP 0x10 -#define TD_STATUSMASK_OVF 0x20 -#define TD_STATUSMASK_NAK 0x40 -#define TD_STATUSMASK_STALL 0x80 - -#define TD_ERROR_MASK (TD_STATUSMASK_ERR | TD_STATUSMASK_TMOUT | \ - TD_STATUSMASK_STALL) - -#define TD_RETRYCNT_OFFSET 0x08 -#define TD_RETRYCNTMASK_ACT_FLG 0x10 -#define TD_RETRYCNTMASK_TX_TYPE 0x0C -#define TD_RETRYCNTMASK_RTY_CNT 0x03 - -#define TD_RESIDUE_OVERFLOW 0x80 - -#define TD_PID_IN 0x90 - -/* Residue: signed 8bits, neg -> OVERFLOW, pos -> UNDERFLOW */ -#define td_residue(td) ((__s8)(td->residue)) -#define td_ly_base_addr(td) (__le16_to_cpu((td)->ly_base_addr)) -#define td_port_length(td) (__le16_to_cpu((td)->port_length)) -#define td_next_td_addr(td) (__le16_to_cpu((td)->next_td_addr)) - -#define td_active(td) ((td)->retry_cnt & TD_RETRYCNTMASK_ACT_FLG) -#define td_length(td) (td_port_length(td) & TD_PORTLENMASK_DL) - -#define td_sequence_ok(td) (!td->status || \ - (!(td->status & TD_STATUSMASK_SEQ) == \ - !(td->ctrl_reg & SEQ_SEL))) - -#define td_acked(td) (!td->status || \ - (td->status & TD_STATUSMASK_ACK)) -#define td_actual_bytes(td) (td_length(td) - td_residue(td)) - -/* -------------------------------------------------------------------------- */ - -#ifdef DEBUG - -/** - * dbg_td - Dump the contents of the TD - */ -static void dbg_td(struct c67x00_hcd *c67x00, struct c67x00_td *td, char *msg) -{ - struct device *dev = c67x00_hcd_dev(c67x00); - - dev_dbg(dev, "### %s at 0x%04x\n", msg, td->td_addr); - dev_dbg(dev, "urb: 0x%p\n", td->urb); - dev_dbg(dev, "endpoint: %4d\n", usb_pipeendpoint(td->pipe)); - dev_dbg(dev, "pipeout: %4d\n", usb_pipeout(td->pipe)); - dev_dbg(dev, "ly_base_addr: 0x%04x\n", td_ly_base_addr(td)); - dev_dbg(dev, "port_length: 0x%04x\n", td_port_length(td)); - dev_dbg(dev, "pid_ep: 0x%02x\n", td->pid_ep); - dev_dbg(dev, "dev_addr: 0x%02x\n", td->dev_addr); - dev_dbg(dev, "ctrl_reg: 0x%02x\n", td->ctrl_reg); - dev_dbg(dev, "status: 0x%02x\n", td->status); - dev_dbg(dev, "retry_cnt: 0x%02x\n", td->retry_cnt); - dev_dbg(dev, "residue: 0x%02x\n", td->residue); - dev_dbg(dev, "next_td_addr: 0x%04x\n", td_next_td_addr(td)); - dev_dbg(dev, "data:"); - print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 1, - td->data, td_length(td), 1); -} -#else /* DEBUG */ - -static inline void -dbg_td(struct c67x00_hcd *c67x00, struct c67x00_td *td, char *msg) { } - -#endif /* DEBUG */ - -/* -------------------------------------------------------------------------- */ -/* Helper functions */ - -static inline u16 c67x00_get_current_frame_number(struct c67x00_hcd *c67x00) -{ - return c67x00_ll_husb_get_frame(c67x00->sie) & HOST_FRAME_MASK; -} - -/** - * frame_add - * Software wraparound for framenumbers. - */ -static inline u16 frame_add(u16 a, u16 b) -{ - return (a + b) & HOST_FRAME_MASK; -} - -/** - * frame_after - is frame a after frame b - */ -static inline int frame_after(u16 a, u16 b) -{ - return ((HOST_FRAME_MASK + a - b) & HOST_FRAME_MASK) < - (HOST_FRAME_MASK / 2); -} - -/** - * frame_after_eq - is frame a after or equal to frame b - */ -static inline int frame_after_eq(u16 a, u16 b) -{ - return ((HOST_FRAME_MASK + 1 + a - b) & HOST_FRAME_MASK) < - (HOST_FRAME_MASK / 2); -} - -/* -------------------------------------------------------------------------- */ - -/** - * c67x00_release_urb - remove link from all tds to this urb - * Disconnects the urb from it's tds, so that it can be given back. - * pre: urb->hcpriv != NULL - */ -static void c67x00_release_urb(struct c67x00_hcd *c67x00, struct urb *urb) -{ - struct c67x00_td *td; - struct c67x00_urb_priv *urbp; - - BUG_ON(!urb); - - c67x00->urb_count--; - - if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { - c67x00->urb_iso_count--; - if (c67x00->urb_iso_count == 0) - c67x00->max_frame_bw = MAX_FRAME_BW_STD; - } - - /* TODO this might be not so efficient when we've got many urbs! - * Alternatives: - * * only clear when needed - * * keep a list of tds with each urbp - */ - list_for_each_entry(td, &c67x00->td_list, td_list) - if (urb == td->urb) - td->urb = NULL; - - urbp = urb->hcpriv; - urb->hcpriv = NULL; - list_del(&urbp->hep_node); - kfree(urbp); -} - -/* -------------------------------------------------------------------------- */ - -static struct c67x00_ep_data * -c67x00_ep_data_alloc(struct c67x00_hcd *c67x00, struct urb *urb) -{ - struct usb_host_endpoint *hep = urb->ep; - struct c67x00_ep_data *ep_data; - int type; - - c67x00->current_frame = c67x00_get_current_frame_number(c67x00); - - /* Check if endpoint already has a c67x00_ep_data struct allocated */ - if (hep->hcpriv) { - ep_data = hep->hcpriv; - if (frame_after(c67x00->current_frame, ep_data->next_frame)) - ep_data->next_frame = - frame_add(c67x00->current_frame, 1); - return hep->hcpriv; - } - - /* Allocate and initialize a new c67x00 endpoint data structure */ - ep_data = kzalloc(sizeof(*ep_data), GFP_ATOMIC); - if (!ep_data) - return NULL; - - INIT_LIST_HEAD(&ep_data->queue); - INIT_LIST_HEAD(&ep_data->node); - ep_data->hep = hep; - - /* hold a reference to udev as long as this endpoint lives, - * this is needed to possibly fix the data toggle */ - ep_data->dev = usb_get_dev(urb->dev); - hep->hcpriv = ep_data; - - /* For ISOC and INT endpoints, start ASAP: */ - ep_data->next_frame = frame_add(c67x00->current_frame, 1); - - /* Add the endpoint data to one of the pipe lists; must be added - in order of endpoint address */ - type = usb_pipetype(urb->pipe); - if (list_empty(&ep_data->node)) { - list_add(&ep_data->node, &c67x00->list[type]); - } else { - struct c67x00_ep_data *prev; - - list_for_each_entry(prev, &c67x00->list[type], node) { - if (prev->hep->desc.bEndpointAddress > - hep->desc.bEndpointAddress) { - list_add(&ep_data->node, prev->node.prev); - break; - } - } - } - - return ep_data; -} - -static int c67x00_ep_data_free(struct usb_host_endpoint *hep) -{ - struct c67x00_ep_data *ep_data = hep->hcpriv; - - if (!ep_data) - return 0; - - if (!list_empty(&ep_data->queue)) - return -EBUSY; - - usb_put_dev(ep_data->dev); - list_del(&ep_data->queue); - list_del(&ep_data->node); - - kfree(ep_data); - hep->hcpriv = NULL; - - return 0; -} - -void c67x00_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep) -{ - struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd); - unsigned long flags; - - if (!list_empty(&ep->urb_list)) - dev_warn(c67x00_hcd_dev(c67x00), "error: urb list not empty\n"); - - spin_lock_irqsave(&c67x00->lock, flags); - - /* loop waiting for all transfers in the endpoint queue to complete */ - while (c67x00_ep_data_free(ep)) { - /* Drop the lock so we can sleep waiting for the hardware */ - spin_unlock_irqrestore(&c67x00->lock, flags); - - /* it could happen that we reinitialize this completion, while - * somebody was waiting for that completion. The timeout and - * while loop handle such cases, but this might be improved */ - INIT_COMPLETION(c67x00->endpoint_disable); - c67x00_sched_kick(c67x00); - wait_for_completion_timeout(&c67x00->endpoint_disable, 1 * HZ); - - spin_lock_irqsave(&c67x00->lock, flags); - } - - spin_unlock_irqrestore(&c67x00->lock, flags); -} - -/* -------------------------------------------------------------------------- */ - -static inline int get_root_port(struct usb_device *dev) -{ - while (dev->parent->parent) - dev = dev->parent; - return dev->portnum; -} - -int c67x00_urb_enqueue(struct usb_hcd *hcd, - struct urb *urb, gfp_t mem_flags) -{ - int ret; - unsigned long flags; - struct c67x00_urb_priv *urbp; - struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd); - int port = get_root_port(urb->dev)-1; - - spin_lock_irqsave(&c67x00->lock, flags); - - /* Make sure host controller is running */ - if (!HC_IS_RUNNING(hcd->state)) { - ret = -ENODEV; - goto err_not_linked; - } - - ret = usb_hcd_link_urb_to_ep(hcd, urb); - if (ret) - goto err_not_linked; - - /* Allocate and initialize urb private data */ - urbp = kzalloc(sizeof(*urbp), mem_flags); - if (!urbp) { - ret = -ENOMEM; - goto err_urbp; - } - - INIT_LIST_HEAD(&urbp->hep_node); - urbp->urb = urb; - urbp->port = port; - - urbp->ep_data = c67x00_ep_data_alloc(c67x00, urb); - - if (!urbp->ep_data) { - ret = -ENOMEM; - goto err_epdata; - } - - /* TODO claim bandwidth with usb_claim_bandwidth? - * also release it somewhere! */ - - urb->hcpriv = urbp; - - urb->actual_length = 0; /* Nothing received/transmitted yet */ - - switch (usb_pipetype(urb->pipe)) { - case PIPE_CONTROL: - urb->interval = SETUP_STAGE; - break; - case PIPE_INTERRUPT: - break; - case PIPE_BULK: - break; - case PIPE_ISOCHRONOUS: - if (c67x00->urb_iso_count == 0) - c67x00->max_frame_bw = MAX_FRAME_BW_ISO; - c67x00->urb_iso_count++; - /* Assume always URB_ISO_ASAP, FIXME */ - if (list_empty(&urbp->ep_data->queue)) - urb->start_frame = urbp->ep_data->next_frame; - else { - /* Go right after the last one */ - struct urb *last_urb; - - last_urb = list_entry(urbp->ep_data->queue.prev, - struct c67x00_urb_priv, - hep_node)->urb; - urb->start_frame = - frame_add(last_urb->start_frame, - last_urb->number_of_packets * - last_urb->interval); - } - urbp->cnt = 0; - break; - } - - /* Add the URB to the endpoint queue */ - list_add_tail(&urbp->hep_node, &urbp->ep_data->queue); - - /* If this is the only URB, kick start the controller */ - if (!c67x00->urb_count++) - c67x00_ll_hpi_enable_sofeop(c67x00->sie); - - c67x00_sched_kick(c67x00); - spin_unlock_irqrestore(&c67x00->lock, flags); - - return 0; - -err_epdata: - kfree(urbp); -err_urbp: - usb_hcd_unlink_urb_from_ep(hcd, urb); -err_not_linked: - spin_unlock_irqrestore(&c67x00->lock, flags); - - return ret; -} - -int c67x00_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) -{ - struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd); - unsigned long flags; - int rc; - - spin_lock_irqsave(&c67x00->lock, flags); - rc = usb_hcd_check_unlink_urb(hcd, urb, status); - if (rc) - goto done; - - c67x00_release_urb(c67x00, urb); - usb_hcd_unlink_urb_from_ep(hcd, urb); - - spin_unlock(&c67x00->lock); - usb_hcd_giveback_urb(hcd, urb, status); - spin_lock(&c67x00->lock); - - spin_unlock_irqrestore(&c67x00->lock, flags); - - return 0; - - done: - spin_unlock_irqrestore(&c67x00->lock, flags); - return rc; -} - -/* -------------------------------------------------------------------------- */ - -/* - * pre: c67x00 locked, urb unlocked - */ -static void -c67x00_giveback_urb(struct c67x00_hcd *c67x00, struct urb *urb, int status) -{ - struct c67x00_urb_priv *urbp; - - if (!urb) - return; - - urbp = urb->hcpriv; - urbp->status = status; - - list_del_init(&urbp->hep_node); - - c67x00_release_urb(c67x00, urb); - usb_hcd_unlink_urb_from_ep(c67x00_hcd_to_hcd(c67x00), urb); - spin_unlock(&c67x00->lock); - usb_hcd_giveback_urb(c67x00_hcd_to_hcd(c67x00), urb, urbp->status); - spin_lock(&c67x00->lock); -} - -/* -------------------------------------------------------------------------- */ - -static int c67x00_claim_frame_bw(struct c67x00_hcd *c67x00, struct urb *urb, - int len, int periodic) -{ - struct c67x00_urb_priv *urbp = urb->hcpriv; - int bit_time; - - /* According to the C67x00 BIOS user manual, page 3-18,19, the - * following calculations provide the full speed bit times for - * a transaction. - * - * FS(in) = 112.5 + 9.36*BC + HOST_DELAY - * FS(in,iso) = 90.5 + 9.36*BC + HOST_DELAY - * FS(out) = 112.5 + 9.36*BC + HOST_DELAY - * FS(out,iso) = 78.4 + 9.36*BC + HOST_DELAY - * LS(in) = 802.4 + 75.78*BC + HOST_DELAY - * LS(out) = 802.6 + 74.67*BC + HOST_DELAY - * - * HOST_DELAY == 106 for the c67200 and c67300. - */ - - /* make calculations in 1/100 bit times to maintain resolution */ - if (urbp->ep_data->dev->speed == USB_SPEED_LOW) { - /* Low speed pipe */ - if (usb_pipein(urb->pipe)) - bit_time = 80240 + 7578*len; - else - bit_time = 80260 + 7467*len; - } else { - /* FS pipes */ - if (usb_pipeisoc(urb->pipe)) - bit_time = usb_pipein(urb->pipe) ? 9050 : 7840; - else - bit_time = 11250; - bit_time += 936*len; - } - - /* Scale back down to integer bit times. Use a host delay of 106. - * (this is the only place it is used) */ - bit_time = ((bit_time+50) / 100) + 106; - - if (unlikely(bit_time + c67x00->bandwidth_allocated >= - c67x00->max_frame_bw)) - return -EMSGSIZE; - - if (unlikely(c67x00->next_td_addr + CY_TD_SIZE >= - c67x00->td_base_addr + SIE_TD_SIZE)) - return -EMSGSIZE; - - if (unlikely(c67x00->next_buf_addr + len >= - c67x00->buf_base_addr + SIE_TD_BUF_SIZE)) - return -EMSGSIZE; - - if (periodic) { - if (unlikely(bit_time + c67x00->periodic_bw_allocated >= - MAX_PERIODIC_BW(c67x00->max_frame_bw))) - return -EMSGSIZE; - c67x00->periodic_bw_allocated += bit_time; - } - - c67x00->bandwidth_allocated += bit_time; - return 0; -} - -/* -------------------------------------------------------------------------- */ - -/** - * td_addr and buf_addr must be word aligned - */ -static int c67x00_create_td(struct c67x00_hcd *c67x00, struct urb *urb, - void *data, int len, int pid, int toggle, - unsigned long privdata) -{ - struct c67x00_td *td; - struct c67x00_urb_priv *urbp = urb->hcpriv; - const __u8 active_flag = 1, retry_cnt = 1; - __u8 cmd = 0; - int tt = 0; - - if (c67x00_claim_frame_bw(c67x00, urb, len, usb_pipeisoc(urb->pipe) - || usb_pipeint(urb->pipe))) - return -EMSGSIZE; /* Not really an error, but expected */ - - td = kzalloc(sizeof(*td), GFP_ATOMIC); - if (!td) - return -ENOMEM; - - td->pipe = urb->pipe; - td->ep_data = urbp->ep_data; - - if ((td_udev(td)->speed == USB_SPEED_LOW) && - !(c67x00->low_speed_ports & (1 << urbp->port))) - cmd |= PREAMBLE_EN; - - switch (usb_pipetype(td->pipe)) { - case PIPE_ISOCHRONOUS: - tt = TT_ISOCHRONOUS; - cmd |= ISO_EN; - break; - case PIPE_CONTROL: - tt = TT_CONTROL; - break; - case PIPE_BULK: - tt = TT_BULK; - break; - case PIPE_INTERRUPT: - tt = TT_INTERRUPT; - break; - } - - if (toggle) - cmd |= SEQ_SEL; - - cmd |= ARM_EN; - - /* SW part */ - td->td_addr = c67x00->next_td_addr; - c67x00->next_td_addr = c67x00->next_td_addr + CY_TD_SIZE; - - /* HW part */ - td->ly_base_addr = __cpu_to_le16(c67x00->next_buf_addr); - td->port_length = __cpu_to_le16((c67x00->sie->sie_num << 15) | - (urbp->port << 14) | (len & 0x3FF)); - td->pid_ep = ((pid & 0xF) << TD_PIDEP_OFFSET) | - (usb_pipeendpoint(td->pipe) & 0xF); - td->dev_addr = usb_pipedevice(td->pipe) & 0x7F; - td->ctrl_reg = cmd; - td->status = 0; - td->retry_cnt = (tt << TT_OFFSET) | (active_flag << 4) | retry_cnt; - td->residue = 0; - td->next_td_addr = __cpu_to_le16(c67x00->next_td_addr); - - /* SW part */ - td->data = data; - td->urb = urb; - td->privdata = privdata; - - c67x00->next_buf_addr += (len + 1) & ~0x01; /* properly align */ - - list_add_tail(&td->td_list, &c67x00->td_list); - return 0; -} - -static inline void c67x00_release_td(struct c67x00_td *td) -{ - list_del_init(&td->td_list); - kfree(td); -} - -/* -------------------------------------------------------------------------- */ - -static int c67x00_add_data_urb(struct c67x00_hcd *c67x00, struct urb *urb) -{ - int remaining; - int toggle; - int pid; - int ret = 0; - int maxps; - int need_empty; - - toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe)); - remaining = urb->transfer_buffer_length - urb->actual_length; - - maxps = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); - - need_empty = (urb->transfer_flags & URB_ZERO_PACKET) && - usb_pipeout(urb->pipe) && !(remaining % maxps); - - while (remaining || need_empty) { - int len; - char *td_buf; - - len = (remaining > maxps) ? maxps : remaining; - if (!len) - need_empty = 0; - - pid = usb_pipeout(urb->pipe) ? USB_PID_OUT : USB_PID_IN; - td_buf = urb->transfer_buffer + urb->transfer_buffer_length - - remaining; - ret = c67x00_create_td(c67x00, urb, td_buf, len, pid, toggle, - DATA_STAGE); - if (ret) - return ret; /* td wasn't created */ - - toggle ^= 1; - remaining -= len; - if (usb_pipecontrol(urb->pipe)) - break; - } - - return 0; -} - -/** - * return 0 in case more bandwidth is available, else errorcode - */ -static int c67x00_add_ctrl_urb(struct c67x00_hcd *c67x00, struct urb *urb) -{ - int ret; - int pid; - - switch (urb->interval) { - default: - case SETUP_STAGE: - ret = c67x00_create_td(c67x00, urb, urb->setup_packet, - 8, USB_PID_SETUP, 0, SETUP_STAGE); - if (ret) - return ret; - urb->interval = SETUP_STAGE; - usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe), 1); - break; - case DATA_STAGE: - if (urb->transfer_buffer_length) { - ret = c67x00_add_data_urb(c67x00, urb); - if (ret) - return ret; - break; - } /* else fallthrough */ - case STATUS_STAGE: - pid = !usb_pipeout(urb->pipe) ? USB_PID_OUT : USB_PID_IN; - ret = c67x00_create_td(c67x00, urb, NULL, 0, pid, 1, - STATUS_STAGE); - if (ret) - return ret; - break; - } - - return 0; -} - -/* - * return 0 in case more bandwidth is available, else errorcode - */ -static int c67x00_add_int_urb(struct c67x00_hcd *c67x00, struct urb *urb) -{ - struct c67x00_urb_priv *urbp = urb->hcpriv; - - if (frame_after_eq(c67x00->current_frame, urbp->ep_data->next_frame)) { - urbp->ep_data->next_frame = - frame_add(urbp->ep_data->next_frame, urb->interval); - return c67x00_add_data_urb(c67x00, urb); - } - return 0; -} - -static int c67x00_add_iso_urb(struct c67x00_hcd *c67x00, struct urb *urb) -{ - struct c67x00_urb_priv *urbp = urb->hcpriv; - - if (frame_after_eq(c67x00->current_frame, urbp->ep_data->next_frame)) { - char *td_buf; - int len, pid, ret; - - BUG_ON(urbp->cnt >= urb->number_of_packets); - - td_buf = urb->transfer_buffer + - urb->iso_frame_desc[urbp->cnt].offset; - len = urb->iso_frame_desc[urbp->cnt].length; - pid = usb_pipeout(urb->pipe) ? USB_PID_OUT : USB_PID_IN; - - ret = c67x00_create_td(c67x00, urb, td_buf, len, pid, 0, - urbp->cnt); - if (ret) { - printk(KERN_DEBUG "create failed: %d\n", ret); - urb->iso_frame_desc[urbp->cnt].actual_length = 0; - urb->iso_frame_desc[urbp->cnt].status = ret; - if (urbp->cnt + 1 == urb->number_of_packets) - c67x00_giveback_urb(c67x00, urb, 0); - } - - urbp->ep_data->next_frame = - frame_add(urbp->ep_data->next_frame, urb->interval); - urbp->cnt++; - } - return 0; -} - -/* -------------------------------------------------------------------------- */ - -static void c67x00_fill_from_list(struct c67x00_hcd *c67x00, int type, - int (*add)(struct c67x00_hcd *, struct urb *)) -{ - struct c67x00_ep_data *ep_data; - struct urb *urb; - - /* traverse every endpoint on the list */ - list_for_each_entry(ep_data, &c67x00->list[type], node) { - if (!list_empty(&ep_data->queue)) { - /* and add the first urb */ - /* isochronous transfer rely on this */ - urb = list_entry(ep_data->queue.next, - struct c67x00_urb_priv, - hep_node)->urb; - add(c67x00, urb); - } - } -} - -static void c67x00_fill_frame(struct c67x00_hcd *c67x00) -{ - struct c67x00_td *td, *ttd; - - /* Check if we can proceed */ - if (!list_empty(&c67x00->td_list)) { - dev_warn(c67x00_hcd_dev(c67x00), - "TD list not empty! This should not happen!\n"); - list_for_each_entry_safe(td, ttd, &c67x00->td_list, td_list) { - dbg_td(c67x00, td, "Unprocessed td"); - c67x00_release_td(td); - } - } - - /* Reinitialize variables */ - c67x00->bandwidth_allocated = 0; - c67x00->periodic_bw_allocated = 0; - - c67x00->next_td_addr = c67x00->td_base_addr; - c67x00->next_buf_addr = c67x00->buf_base_addr; - - /* Fill the list */ - c67x00_fill_from_list(c67x00, PIPE_ISOCHRONOUS, c67x00_add_iso_urb); - c67x00_fill_from_list(c67x00, PIPE_INTERRUPT, c67x00_add_int_urb); - c67x00_fill_from_list(c67x00, PIPE_CONTROL, c67x00_add_ctrl_urb); - c67x00_fill_from_list(c67x00, PIPE_BULK, c67x00_add_data_urb); -} - -/* -------------------------------------------------------------------------- */ - -/** - * Get TD from C67X00 - */ -static inline void -c67x00_parse_td(struct c67x00_hcd *c67x00, struct c67x00_td *td) -{ - c67x00_ll_read_mem_le16(c67x00->sie->dev, - td->td_addr, td, CY_TD_SIZE); - - if (usb_pipein(td->pipe) && td_actual_bytes(td)) - c67x00_ll_read_mem_le16(c67x00->sie->dev, td_ly_base_addr(td), - td->data, td_actual_bytes(td)); -} - -static int c67x00_td_to_error(struct c67x00_hcd *c67x00, struct c67x00_td *td) -{ - if (td->status & TD_STATUSMASK_ERR) { - dbg_td(c67x00, td, "ERROR_FLAG"); - return -EILSEQ; - } - if (td->status & TD_STATUSMASK_STALL) { - /* dbg_td(c67x00, td, "STALL"); */ - return -EPIPE; - } - if (td->status & TD_STATUSMASK_TMOUT) { - dbg_td(c67x00, td, "TIMEOUT"); - return -ETIMEDOUT; - } - - return 0; -} - -static inline int c67x00_end_of_data(struct c67x00_td *td) -{ - int maxps, need_empty, remaining; - struct urb *urb = td->urb; - int act_bytes; - - act_bytes = td_actual_bytes(td); - - if (unlikely(!act_bytes)) - return 1; /* This was an empty packet */ - - maxps = usb_maxpacket(td_udev(td), td->pipe, usb_pipeout(td->pipe)); - - if (unlikely(act_bytes < maxps)) - return 1; /* Smaller then full packet */ - - remaining = urb->transfer_buffer_length - urb->actual_length; - need_empty = (urb->transfer_flags & URB_ZERO_PACKET) && - usb_pipeout(urb->pipe) && !(remaining % maxps); - - if (unlikely(!remaining && !need_empty)) - return 1; - - return 0; -} - -/* -------------------------------------------------------------------------- */ - -/* Remove all td's from the list which come - * after last_td and are meant for the same pipe. - * This is used when a short packet has occurred */ -static inline void c67x00_clear_pipe(struct c67x00_hcd *c67x00, - struct c67x00_td *last_td) -{ - struct c67x00_td *td, *tmp; - td = last_td; - tmp = last_td; - while (td->td_list.next != &c67x00->td_list) { - td = list_entry(td->td_list.next, struct c67x00_td, td_list); - if (td->pipe == last_td->pipe) { - c67x00_release_td(td); - td = tmp; - } - tmp = td; - } -} - -/* -------------------------------------------------------------------------- */ - -static void c67x00_handle_successful_td(struct c67x00_hcd *c67x00, - struct c67x00_td *td) -{ - struct urb *urb = td->urb; - - if (!urb) - return; - - urb->actual_length += td_actual_bytes(td); - - switch (usb_pipetype(td->pipe)) { - /* isochronous tds are handled separately */ - case PIPE_CONTROL: - switch (td->privdata) { - case SETUP_STAGE: - urb->interval = - urb->transfer_buffer_length ? - DATA_STAGE : STATUS_STAGE; - /* Don't count setup_packet with normal data: */ - urb->actual_length = 0; - break; - - case DATA_STAGE: - if (c67x00_end_of_data(td)) { - urb->interval = STATUS_STAGE; - c67x00_clear_pipe(c67x00, td); - } - break; - - case STATUS_STAGE: - urb->interval = 0; - c67x00_giveback_urb(c67x00, urb, 0); - break; - } - break; - - case PIPE_INTERRUPT: - case PIPE_BULK: - if (unlikely(c67x00_end_of_data(td))) { - c67x00_clear_pipe(c67x00, td); - c67x00_giveback_urb(c67x00, urb, 0); - } - break; - } -} - -static void c67x00_handle_isoc(struct c67x00_hcd *c67x00, struct c67x00_td *td) -{ - struct urb *urb = td->urb; - struct c67x00_urb_priv *urbp; - int cnt; - - if (!urb) - return; - - urbp = urb->hcpriv; - cnt = td->privdata; - - if (td->status & TD_ERROR_MASK) - urb->error_count++; - - urb->iso_frame_desc[cnt].actual_length = td_actual_bytes(td); - urb->iso_frame_desc[cnt].status = c67x00_td_to_error(c67x00, td); - if (cnt + 1 == urb->number_of_packets) /* Last packet */ - c67x00_giveback_urb(c67x00, urb, 0); -} - -/* -------------------------------------------------------------------------- */ - -/** - * c67x00_check_td_list - handle tds which have been processed by the c67x00 - * pre: current_td == 0 - */ -static inline void c67x00_check_td_list(struct c67x00_hcd *c67x00) -{ - struct c67x00_td *td, *tmp; - struct urb *urb; - int ack_ok; - int clear_endpoint; - - list_for_each_entry_safe(td, tmp, &c67x00->td_list, td_list) { - /* get the TD */ - c67x00_parse_td(c67x00, td); - urb = td->urb; /* urb can be NULL! */ - ack_ok = 0; - clear_endpoint = 1; - - /* Handle isochronous transfers separately */ - if (usb_pipeisoc(td->pipe)) { - clear_endpoint = 0; - c67x00_handle_isoc(c67x00, td); - goto cont; - } - - /* When an error occurs, all td's for that pipe go into an - * inactive state. This state matches successful transfers so - * we must make sure not to service them. */ - if (td->status & TD_ERROR_MASK) { - c67x00_giveback_urb(c67x00, urb, - c67x00_td_to_error(c67x00, td)); - goto cont; - } - - if ((td->status & TD_STATUSMASK_NAK) || !td_sequence_ok(td) || - !td_acked(td)) - goto cont; - - /* Sequence ok and acked, don't need to fix toggle */ - ack_ok = 1; - - if (unlikely(td->status & TD_STATUSMASK_OVF)) { - if (td_residue(td) & TD_RESIDUE_OVERFLOW) { - /* Overflow */ - c67x00_giveback_urb(c67x00, urb, -EOVERFLOW); - goto cont; - } - } - - clear_endpoint = 0; - c67x00_handle_successful_td(c67x00, td); - -cont: - if (clear_endpoint) - c67x00_clear_pipe(c67x00, td); - if (ack_ok) - usb_settoggle(td_udev(td), usb_pipeendpoint(td->pipe), - usb_pipeout(td->pipe), - !(td->ctrl_reg & SEQ_SEL)); - /* next in list could have been removed, due to clear_pipe! */ - tmp = list_entry(td->td_list.next, typeof(*td), td_list); - c67x00_release_td(td); - } -} - -/* -------------------------------------------------------------------------- */ - -static inline int c67x00_all_tds_processed(struct c67x00_hcd *c67x00) -{ - /* If all tds are processed, we can check the previous frame (if - * there was any) and start our next frame. - */ - return !c67x00_ll_husb_get_current_td(c67x00->sie); -} - -/** - * Send td to C67X00 - */ -static void c67x00_send_td(struct c67x00_hcd *c67x00, struct c67x00_td *td) -{ - int len = td_length(td); - - if (len && ((td->pid_ep & TD_PIDEPMASK_PID) != TD_PID_IN)) - c67x00_ll_write_mem_le16(c67x00->sie->dev, td_ly_base_addr(td), - td->data, len); - - c67x00_ll_write_mem_le16(c67x00->sie->dev, - td->td_addr, td, CY_TD_SIZE); -} - -static void c67x00_send_frame(struct c67x00_hcd *c67x00) -{ - struct c67x00_td *td; - - if (list_empty(&c67x00->td_list)) - dev_warn(c67x00_hcd_dev(c67x00), - "%s: td list should not be empty here!\n", - __func__); - - list_for_each_entry(td, &c67x00->td_list, td_list) { - if (td->td_list.next == &c67x00->td_list) - td->next_td_addr = 0; /* Last td in list */ - - c67x00_send_td(c67x00, td); - } - - c67x00_ll_husb_set_current_td(c67x00->sie, c67x00->td_base_addr); -} - -/* -------------------------------------------------------------------------- */ - -/** - * c67x00_do_work - Schedulers state machine - */ -static void c67x00_do_work(struct c67x00_hcd *c67x00) -{ - spin_lock(&c67x00->lock); - /* Make sure all tds are processed */ - if (!c67x00_all_tds_processed(c67x00)) - goto out; - - c67x00_check_td_list(c67x00); - - /* no td's are being processed (current == 0) - * and all have been "checked" */ - complete(&c67x00->endpoint_disable); - - if (!list_empty(&c67x00->td_list)) - goto out; - - c67x00->current_frame = c67x00_get_current_frame_number(c67x00); - if (c67x00->current_frame == c67x00->last_frame) - goto out; /* Don't send tds in same frame */ - c67x00->last_frame = c67x00->current_frame; - - /* If no urbs are scheduled, our work is done */ - if (!c67x00->urb_count) { - c67x00_ll_hpi_disable_sofeop(c67x00->sie); - goto out; - } - - c67x00_fill_frame(c67x00); - if (!list_empty(&c67x00->td_list)) - /* TD's have been added to the frame */ - c67x00_send_frame(c67x00); - - out: - spin_unlock(&c67x00->lock); -} - -/* -------------------------------------------------------------------------- */ - -static void c67x00_sched_tasklet(unsigned long __c67x00) -{ - struct c67x00_hcd *c67x00 = (struct c67x00_hcd *)__c67x00; - c67x00_do_work(c67x00); -} - -void c67x00_sched_kick(struct c67x00_hcd *c67x00) -{ - tasklet_hi_schedule(&c67x00->tasklet); -} - -int c67x00_sched_start_scheduler(struct c67x00_hcd *c67x00) -{ - tasklet_init(&c67x00->tasklet, c67x00_sched_tasklet, - (unsigned long)c67x00); - return 0; -} - -void c67x00_sched_stop_scheduler(struct c67x00_hcd *c67x00) -{ - tasklet_kill(&c67x00->tasklet); -} diff --git a/ANDROID_3.4.5/drivers/usb/c67x00/c67x00.h b/ANDROID_3.4.5/drivers/usb/c67x00/c67x00.h deleted file mode 100644 index a26e9ded..00000000 --- a/ANDROID_3.4.5/drivers/usb/c67x00/c67x00.h +++ /dev/null @@ -1,294 +0,0 @@ -/* - * c67x00.h: Cypress C67X00 USB register and field definitions - * - * Copyright (C) 2006-2008 Barco N.V. - * Derived from the Cypress cy7c67200/300 ezusb linux driver and - * based on multiple host controller drivers inside the linux kernel. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA. - */ - -#ifndef _USB_C67X00_H -#define _USB_C67X00_H - -#include -#include -#include -#include - -/* --------------------------------------------------------------------- - * Cypress C67x00 register definitions - */ - -/* Hardware Revision Register */ -#define HW_REV_REG 0xC004 - -/* General USB registers */ -/* ===================== */ - -/* USB Control Register */ -#define USB_CTL_REG(x) ((x) ? 0xC0AA : 0xC08A) - -#define LOW_SPEED_PORT(x) ((x) ? 0x0800 : 0x0400) -#define HOST_MODE 0x0200 -#define PORT_RES_EN(x) ((x) ? 0x0100 : 0x0080) -#define SOF_EOP_EN(x) ((x) ? 0x0002 : 0x0001) - -/* USB status register - Notice it has different content in hcd/udc mode */ -#define USB_STAT_REG(x) ((x) ? 0xC0B0 : 0xC090) - -#define EP0_IRQ_FLG 0x0001 -#define EP1_IRQ_FLG 0x0002 -#define EP2_IRQ_FLG 0x0004 -#define EP3_IRQ_FLG 0x0008 -#define EP4_IRQ_FLG 0x0010 -#define EP5_IRQ_FLG 0x0020 -#define EP6_IRQ_FLG 0x0040 -#define EP7_IRQ_FLG 0x0080 -#define RESET_IRQ_FLG 0x0100 -#define SOF_EOP_IRQ_FLG 0x0200 -#define ID_IRQ_FLG 0x4000 -#define VBUS_IRQ_FLG 0x8000 - -/* USB Host only registers */ -/* ======================= */ - -/* Host n Control Register */ -#define HOST_CTL_REG(x) ((x) ? 0xC0A0 : 0xC080) - -#define PREAMBLE_EN 0x0080 /* Preamble enable */ -#define SEQ_SEL 0x0040 /* Data Toggle Sequence Bit Select */ -#define ISO_EN 0x0010 /* Isochronous enable */ -#define ARM_EN 0x0001 /* Arm operation */ - -/* Host n Interrupt Enable Register */ -#define HOST_IRQ_EN_REG(x) ((x) ? 0xC0AC : 0xC08C) - -#define SOF_EOP_IRQ_EN 0x0200 /* SOF/EOP Interrupt Enable */ -#define SOF_EOP_TMOUT_IRQ_EN 0x0800 /* SOF/EOP Timeout Interrupt Enable */ -#define ID_IRQ_EN 0x4000 /* ID interrupt enable */ -#define VBUS_IRQ_EN 0x8000 /* VBUS interrupt enable */ -#define DONE_IRQ_EN 0x0001 /* Done Interrupt Enable */ - -/* USB status register */ -#define HOST_STAT_MASK 0x02FD -#define PORT_CONNECT_CHANGE(x) ((x) ? 0x0020 : 0x0010) -#define PORT_SE0_STATUS(x) ((x) ? 0x0008 : 0x0004) - -/* Host Frame Register */ -#define HOST_FRAME_REG(x) ((x) ? 0xC0B6 : 0xC096) - -#define HOST_FRAME_MASK 0x07FF - -/* USB Peripheral only registers */ -/* ============================= */ - -/* Device n Port Sel reg */ -#define DEVICE_N_PORT_SEL(x) ((x) ? 0xC0A4 : 0xC084) - -/* Device n Interrupt Enable Register */ -#define DEVICE_N_IRQ_EN_REG(x) ((x) ? 0xC0AC : 0xC08C) - -#define DEVICE_N_ENDPOINT_N_CTL_REG(dev, ep) ((dev) \ - ? (0x0280 + (ep << 4)) \ - : (0x0200 + (ep << 4))) -#define DEVICE_N_ENDPOINT_N_STAT_REG(dev, ep) ((dev) \ - ? (0x0286 + (ep << 4)) \ - : (0x0206 + (ep << 4))) - -#define DEVICE_N_ADDRESS(dev) ((dev) ? (0xC0AE) : (0xC08E)) - -/* HPI registers */ -/* ============= */ - -/* HPI Status register */ -#define SOFEOP_FLG(x) (1 << ((x) ? 12 : 10)) -#define SIEMSG_FLG(x) (1 << (4 + (x))) -#define RESET_FLG(x) ((x) ? 0x0200 : 0x0002) -#define DONE_FLG(x) (1 << (2 + (x))) -#define RESUME_FLG(x) (1 << (6 + (x))) -#define MBX_OUT_FLG 0x0001 /* Message out available */ -#define MBX_IN_FLG 0x0100 -#define ID_FLG 0x4000 -#define VBUS_FLG 0x8000 - -/* Interrupt routing register */ -#define HPI_IRQ_ROUTING_REG 0x0142 - -#define HPI_SWAP_ENABLE(x) ((x) ? 0x0100 : 0x0001) -#define RESET_TO_HPI_ENABLE(x) ((x) ? 0x0200 : 0x0002) -#define DONE_TO_HPI_ENABLE(x) ((x) ? 0x0008 : 0x0004) -#define RESUME_TO_HPI_ENABLE(x) ((x) ? 0x0080 : 0x0040) -#define SOFEOP_TO_HPI_EN(x) ((x) ? 0x2000 : 0x0800) -#define SOFEOP_TO_CPU_EN(x) ((x) ? 0x1000 : 0x0400) -#define ID_TO_HPI_ENABLE 0x4000 -#define VBUS_TO_HPI_ENABLE 0x8000 - -/* SIE msg registers */ -#define SIEMSG_REG(x) ((x) ? 0x0148 : 0x0144) - -#define HUSB_TDListDone 0x1000 - -#define SUSB_EP0_MSG 0x0001 -#define SUSB_EP1_MSG 0x0002 -#define SUSB_EP2_MSG 0x0004 -#define SUSB_EP3_MSG 0x0008 -#define SUSB_EP4_MSG 0x0010 -#define SUSB_EP5_MSG 0x0020 -#define SUSB_EP6_MSG 0x0040 -#define SUSB_EP7_MSG 0x0080 -#define SUSB_RST_MSG 0x0100 -#define SUSB_SOF_MSG 0x0200 -#define SUSB_CFG_MSG 0x0400 -#define SUSB_SUS_MSG 0x0800 -#define SUSB_ID_MSG 0x4000 -#define SUSB_VBUS_MSG 0x8000 - -/* BIOS interrupt routines */ - -#define SUSBx_RECEIVE_INT(x) ((x) ? 97 : 81) -#define SUSBx_SEND_INT(x) ((x) ? 96 : 80) - -#define SUSBx_DEV_DESC_VEC(x) ((x) ? 0x00D4 : 0x00B4) -#define SUSBx_CONF_DESC_VEC(x) ((x) ? 0x00D6 : 0x00B6) -#define SUSBx_STRING_DESC_VEC(x) ((x) ? 0x00D8 : 0x00B8) - -#define CY_HCD_BUF_ADDR 0x500 /* Base address for host */ -#define SIE_TD_SIZE 0x200 /* size of the td list */ -#define SIE_TD_BUF_SIZE 0x400 /* size of the data buffer */ - -#define SIE_TD_OFFSET(host) ((host) ? (SIE_TD_SIZE+SIE_TD_BUF_SIZE) : 0) -#define SIE_BUF_OFFSET(host) (SIE_TD_OFFSET(host) + SIE_TD_SIZE) - -/* Base address of HCD + 2 x TD_SIZE + 2 x TD_BUF_SIZE */ -#define CY_UDC_REQ_HEADER_BASE 0x1100 -/* 8- byte request headers for IN/OUT transfers */ -#define CY_UDC_REQ_HEADER_SIZE 8 - -#define CY_UDC_REQ_HEADER_ADDR(ep_num) (CY_UDC_REQ_HEADER_BASE + \ - ((ep_num) * CY_UDC_REQ_HEADER_SIZE)) -#define CY_UDC_DESC_BASE_ADDRESS (CY_UDC_REQ_HEADER_ADDR(8)) - -#define CY_UDC_BIOS_REPLACE_BASE 0x1800 -#define CY_UDC_REQ_BUFFER_BASE 0x2000 -#define CY_UDC_REQ_BUFFER_SIZE 0x0400 -#define CY_UDC_REQ_BUFFER_ADDR(ep_num) (CY_UDC_REQ_BUFFER_BASE + \ - ((ep_num) * CY_UDC_REQ_BUFFER_SIZE)) - -/* --------------------------------------------------------------------- - * Driver data structures - */ - -struct c67x00_device; - -/** - * struct c67x00_sie - Common data associated with a SIE - * @lock: lock to protect this struct and the associated chip registers - * @private_data: subdriver dependent data - * @irq: subdriver dependent irq handler, set NULL when not used - * @dev: link to common driver structure - * @sie_num: SIE number on chip, starting from 0 - * @mode: SIE mode (host/peripheral/otg/not used) - */ -struct c67x00_sie { - /* Entries to be used by the subdrivers */ - spinlock_t lock; /* protect this structure */ - void *private_data; - void (*irq) (struct c67x00_sie *sie, u16 int_status, u16 msg); - - /* Read only: */ - struct c67x00_device *dev; - int sie_num; - int mode; -}; - -#define sie_dev(s) (&(s)->dev->pdev->dev) - -/** - * struct c67x00_lcp - */ -struct c67x00_lcp { - /* Internal use only */ - struct mutex mutex; - struct completion msg_received; - u16 last_msg; -}; - -/* - * struct c67x00_hpi - */ -struct c67x00_hpi { - void __iomem *base; - int regstep; - spinlock_t lock; - struct c67x00_lcp lcp; -}; - -#define C67X00_SIES 2 -#define C67X00_PORTS 2 - -/** - * struct c67x00_device - Common data associated with a c67x00 instance - * @hpi: hpi addresses - * @sie: array of sie's on this chip - * @pdev: platform device of instance - * @pdata: configuration provided by the platform - */ -struct c67x00_device { - struct c67x00_hpi hpi; - struct c67x00_sie sie[C67X00_SIES]; - struct platform_device *pdev; - struct c67x00_platform_data *pdata; -}; - -/* --------------------------------------------------------------------- - * Low level interface functions - */ - -/* Host Port Interface (HPI) functions */ -u16 c67x00_ll_hpi_status(struct c67x00_device *dev); -void c67x00_ll_hpi_reg_init(struct c67x00_device *dev); -void c67x00_ll_hpi_enable_sofeop(struct c67x00_sie *sie); -void c67x00_ll_hpi_disable_sofeop(struct c67x00_sie *sie); - -/* General functions */ -u16 c67x00_ll_fetch_siemsg(struct c67x00_device *dev, int sie_num); -u16 c67x00_ll_get_usb_ctl(struct c67x00_sie *sie); -void c67x00_ll_usb_clear_status(struct c67x00_sie *sie, u16 bits); -u16 c67x00_ll_usb_get_status(struct c67x00_sie *sie); -void c67x00_ll_write_mem_le16(struct c67x00_device *dev, u16 addr, - void *data, int len); -void c67x00_ll_read_mem_le16(struct c67x00_device *dev, u16 addr, - void *data, int len); - -/* Host specific functions */ -void c67x00_ll_set_husb_eot(struct c67x00_device *dev, u16 value); -void c67x00_ll_husb_reset(struct c67x00_sie *sie, int port); -void c67x00_ll_husb_set_current_td(struct c67x00_sie *sie, u16 addr); -u16 c67x00_ll_husb_get_current_td(struct c67x00_sie *sie); -u16 c67x00_ll_husb_get_frame(struct c67x00_sie *sie); -void c67x00_ll_husb_init_host_port(struct c67x00_sie *sie); -void c67x00_ll_husb_reset_port(struct c67x00_sie *sie, int port); - -/* Called by c67x00_irq to handle lcp interrupts */ -void c67x00_ll_irq(struct c67x00_device *dev, u16 int_status); - -/* Setup and teardown */ -void c67x00_ll_init(struct c67x00_device *dev); -void c67x00_ll_release(struct c67x00_device *dev); -int c67x00_ll_reset(struct c67x00_device *dev); - -#endif /* _USB_C67X00_H */ diff --git a/ANDROID_3.4.5/drivers/usb/class/Kconfig b/ANDROID_3.4.5/drivers/usb/class/Kconfig deleted file mode 100644 index 2519e320..00000000 --- a/ANDROID_3.4.5/drivers/usb/class/Kconfig +++ /dev/null @@ -1,52 +0,0 @@ -# -# USB Class driver configuration -# -comment "USB Device Class drivers" - depends on USB - -config USB_ACM - tristate "USB Modem (CDC ACM) support" - depends on USB - ---help--- - This driver supports USB modems and ISDN adapters which support the - Communication Device Class Abstract Control Model interface. - Please read for details. - - If your modem only reports "Cls=ff(vend.)" in the descriptors in - /proc/bus/usb/devices, then your modem will not work with this - driver. - - To compile this driver as a module, choose M here: the - module will be called cdc-acm. - -config USB_PRINTER - tristate "USB Printer support" - depends on USB - help - Say Y here if you want to connect a USB printer to your computer's - USB port. - - To compile this driver as a module, choose M here: the - module will be called usblp. - -config USB_WDM - tristate "USB Wireless Device Management support" - depends on USB - ---help--- - This driver supports the WMC Device Management functionality - of cell phones compliant to the CDC WMC specification. You can use - AT commands over this device. - - To compile this driver as a module, choose M here: the - module will be called cdc-wdm. - -config USB_TMC - tristate "USB Test and Measurement Class support" - depends on USB - help - Say Y here if you want to connect a USB device that follows - the USB.org specification for USB Test and Measurement devices - to your computer's USB port. - - To compile this driver as a module, choose M here: the - module will be called usbtmc. diff --git a/ANDROID_3.4.5/drivers/usb/class/Makefile b/ANDROID_3.4.5/drivers/usb/class/Makefile deleted file mode 100644 index 32e85277..00000000 --- a/ANDROID_3.4.5/drivers/usb/class/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Makefile for USB Class drivers -# (one step up from the misc category) -# - -obj-$(CONFIG_USB_ACM) += cdc-acm.o -obj-$(CONFIG_USB_PRINTER) += usblp.o -obj-$(CONFIG_USB_WDM) += cdc-wdm.o -obj-$(CONFIG_USB_TMC) += usbtmc.o diff --git a/ANDROID_3.4.5/drivers/usb/class/cdc-acm.c b/ANDROID_3.4.5/drivers/usb/class/cdc-acm.c deleted file mode 100644 index 640cf798..00000000 --- a/ANDROID_3.4.5/drivers/usb/class/cdc-acm.c +++ /dev/null @@ -1,1752 +0,0 @@ -/* - * cdc-acm.c - * - * Copyright (c) 1999 Armin Fuerst - * Copyright (c) 1999 Pavel Machek - * Copyright (c) 1999 Johannes Erdfelt - * Copyright (c) 2000 Vojtech Pavlik - * Copyright (c) 2004 Oliver Neukum - * Copyright (c) 2005 David Kubicek - * Copyright (c) 2011 Johan Hovold - * - * USB Abstract Control Model driver for USB modems and ISDN adapters - * - * Sponsored by SuSE - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#undef DEBUG -#undef VERBOSE_DEBUG - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cdc-acm.h" - - -#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek, Johan Hovold" -#define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters" - -static struct usb_driver acm_driver; -static struct tty_driver *acm_tty_driver; -static struct acm *acm_table[ACM_TTY_MINORS]; - -static DEFINE_MUTEX(acm_table_lock); - -/* - * acm_table accessors - */ - -/* - * Look up an ACM structure by index. If found and not disconnected, increment - * its refcount and return it with its mutex held. - */ -static struct acm *acm_get_by_index(unsigned index) -{ - struct acm *acm; - - mutex_lock(&acm_table_lock); - acm = acm_table[index]; - if (acm) { - mutex_lock(&acm->mutex); - if (acm->disconnected) { - mutex_unlock(&acm->mutex); - acm = NULL; - } else { - tty_port_get(&acm->port); - mutex_unlock(&acm->mutex); - } - } - mutex_unlock(&acm_table_lock); - return acm; -} - -/* - * Try to find an available minor number and if found, associate it with 'acm'. - */ -static int acm_alloc_minor(struct acm *acm) -{ - int minor; - - mutex_lock(&acm_table_lock); - for (minor = 0; minor < ACM_TTY_MINORS; minor++) { - if (!acm_table[minor]) { - acm_table[minor] = acm; - break; - } - } - mutex_unlock(&acm_table_lock); - - return minor; -} - -/* Release the minor number associated with 'acm'. */ -static void acm_release_minor(struct acm *acm) -{ - mutex_lock(&acm_table_lock); - acm_table[acm->minor] = NULL; - mutex_unlock(&acm_table_lock); -} - -/* - * Functions for ACM control messages. - */ - -static int acm_ctrl_msg(struct acm *acm, int request, int value, - void *buf, int len) -{ - int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0), - request, USB_RT_ACM, value, - acm->control->altsetting[0].desc.bInterfaceNumber, - buf, len, 5000); - dev_dbg(&acm->control->dev, - "%s - rq 0x%02x, val %#x, len %#x, result %d\n", - __func__, request, value, len, retval); - return retval < 0 ? retval : 0; -} - -/* devices aren't required to support these requests. - * the cdc acm descriptor tells whether they do... - */ -#define acm_set_control(acm, control) \ - acm_ctrl_msg(acm, USB_CDC_REQ_SET_CONTROL_LINE_STATE, control, NULL, 0) -#define acm_set_line(acm, line) \ - acm_ctrl_msg(acm, USB_CDC_REQ_SET_LINE_CODING, 0, line, sizeof *(line)) -#define acm_send_break(acm, ms) \ - acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0) - -/* - * Write buffer management. - * All of these assume proper locks taken by the caller. - */ - -static int acm_wb_alloc(struct acm *acm) -{ - int i, wbn; - struct acm_wb *wb; - - wbn = 0; - i = 0; - for (;;) { - wb = &acm->wb[wbn]; - if (!wb->use) { - wb->use = 1; - return wbn; - } - wbn = (wbn + 1) % ACM_NW; - if (++i >= ACM_NW) - return -1; - } -} - -static int acm_wb_is_avail(struct acm *acm) -{ - int i, n; - unsigned long flags; - - n = ACM_NW; - spin_lock_irqsave(&acm->write_lock, flags); - for (i = 0; i < ACM_NW; i++) - n -= acm->wb[i].use; - spin_unlock_irqrestore(&acm->write_lock, flags); - return n; -} - -/* - * Finish write. Caller must hold acm->write_lock - */ -static void acm_write_done(struct acm *acm, struct acm_wb *wb) -{ - wb->use = 0; - acm->transmitting--; - usb_autopm_put_interface_async(acm->control); -} - -/* - * Poke write. - * - * the caller is responsible for locking - */ - -static int acm_start_wb(struct acm *acm, struct acm_wb *wb) -{ - int rc; - - acm->transmitting++; - - wb->urb->transfer_buffer = wb->buf; - wb->urb->transfer_dma = wb->dmah; - wb->urb->transfer_buffer_length = wb->len; - wb->urb->dev = acm->dev; - - rc = usb_submit_urb(wb->urb, GFP_ATOMIC); - if (rc < 0) { - dev_err(&acm->data->dev, - "%s - usb_submit_urb(write bulk) failed: %d\n", - __func__, rc); - acm_write_done(acm, wb); - } - return rc; -} - -static int acm_write_start(struct acm *acm, int wbn) -{ - unsigned long flags; - struct acm_wb *wb = &acm->wb[wbn]; - int rc; - - spin_lock_irqsave(&acm->write_lock, flags); - if (!acm->dev) { - wb->use = 0; - spin_unlock_irqrestore(&acm->write_lock, flags); - return -ENODEV; - } - - dev_vdbg(&acm->data->dev, "%s - susp_count %d\n", __func__, - acm->susp_count); - usb_autopm_get_interface_async(acm->control); - if (acm->susp_count) { - if (!acm->delayed_wb) - acm->delayed_wb = wb; - else - usb_autopm_put_interface_async(acm->control); - spin_unlock_irqrestore(&acm->write_lock, flags); - return 0; /* A white lie */ - } - usb_mark_last_busy(acm->dev); - - rc = acm_start_wb(acm, wb); - spin_unlock_irqrestore(&acm->write_lock, flags); - - return rc; - -} -/* - * attributes exported through sysfs - */ -static ssize_t show_caps -(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct acm *acm = usb_get_intfdata(intf); - - return sprintf(buf, "%d", acm->ctrl_caps); -} -static DEVICE_ATTR(bmCapabilities, S_IRUGO, show_caps, NULL); - -static ssize_t show_country_codes -(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct acm *acm = usb_get_intfdata(intf); - - memcpy(buf, acm->country_codes, acm->country_code_size); - return acm->country_code_size; -} - -static DEVICE_ATTR(wCountryCodes, S_IRUGO, show_country_codes, NULL); - -static ssize_t show_country_rel_date -(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct acm *acm = usb_get_intfdata(intf); - - return sprintf(buf, "%d", acm->country_rel_date); -} - -static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL); -/* - * Interrupt handlers for various ACM device responses - */ - -/* control interface reports status changes with "interrupt" transfers */ -static void acm_ctrl_irq(struct urb *urb) -{ - struct acm *acm = urb->context; - struct usb_cdc_notification *dr = urb->transfer_buffer; - struct tty_struct *tty; - unsigned char *data; - int newctrl; - int retval; - int status = urb->status; - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dev_dbg(&acm->control->dev, - "%s - urb shutting down with status: %d\n", - __func__, status); - return; - default: - dev_dbg(&acm->control->dev, - "%s - nonzero urb status received: %d\n", - __func__, status); - goto exit; - } - - usb_mark_last_busy(acm->dev); - - data = (unsigned char *)(dr + 1); - switch (dr->bNotificationType) { - case USB_CDC_NOTIFY_NETWORK_CONNECTION: - dev_dbg(&acm->control->dev, "%s - network connection: %d\n", - __func__, dr->wValue); - break; - - case USB_CDC_NOTIFY_SERIAL_STATE: - tty = tty_port_tty_get(&acm->port); - newctrl = get_unaligned_le16(data); - - if (tty) { - if (!acm->clocal && - (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) { - dev_dbg(&acm->control->dev, - "%s - calling hangup\n", __func__); - tty_hangup(tty); - } - tty_kref_put(tty); - } - - acm->ctrlin = newctrl; - - dev_dbg(&acm->control->dev, - "%s - input control lines: dcd%c dsr%c break%c " - "ring%c framing%c parity%c overrun%c\n", - __func__, - acm->ctrlin & ACM_CTRL_DCD ? '+' : '-', - acm->ctrlin & ACM_CTRL_DSR ? '+' : '-', - acm->ctrlin & ACM_CTRL_BRK ? '+' : '-', - acm->ctrlin & ACM_CTRL_RI ? '+' : '-', - acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-', - acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-', - acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-'); - break; - - default: - dev_dbg(&acm->control->dev, - "%s - unknown notification %d received: index %d " - "len %d data0 %d data1 %d\n", - __func__, - dr->bNotificationType, dr->wIndex, - dr->wLength, data[0], data[1]); - break; - } -exit: - retval = usb_submit_urb(urb, GFP_ATOMIC); - if (retval) - dev_err(&acm->control->dev, "%s - usb_submit_urb failed: %d\n", - __func__, retval); -} - -static int acm_submit_read_urb(struct acm *acm, int index, gfp_t mem_flags) -{ - int res; - - if (!test_and_clear_bit(index, &acm->read_urbs_free)) - return 0; - - dev_vdbg(&acm->data->dev, "%s - urb %d\n", __func__, index); - - res = usb_submit_urb(acm->read_urbs[index], mem_flags); - if (res) { - if (res != -EPERM) { - dev_err(&acm->data->dev, - "%s - usb_submit_urb failed: %d\n", - __func__, res); - } - set_bit(index, &acm->read_urbs_free); - return res; - } - - return 0; -} - -static int acm_submit_read_urbs(struct acm *acm, gfp_t mem_flags) -{ - int res; - int i; - - for (i = 0; i < acm->rx_buflimit; ++i) { - res = acm_submit_read_urb(acm, i, mem_flags); - if (res) - return res; - } - - return 0; -} - -static void acm_process_read_urb(struct acm *acm, struct urb *urb) -{ - struct tty_struct *tty; - - if (!urb->actual_length) - return; - - tty = tty_port_tty_get(&acm->port); - if (!tty) - return; - - tty_insert_flip_string(tty, urb->transfer_buffer, urb->actual_length); - tty_flip_buffer_push(tty); - - tty_kref_put(tty); -} - -static void acm_read_bulk_callback(struct urb *urb) -{ - struct acm_rb *rb = urb->context; - struct acm *acm = rb->instance; - unsigned long flags; - - dev_vdbg(&acm->data->dev, "%s - urb %d, len %d\n", __func__, - rb->index, urb->actual_length); - set_bit(rb->index, &acm->read_urbs_free); - - if (!acm->dev) { - dev_dbg(&acm->data->dev, "%s - disconnected\n", __func__); - return; - } - usb_mark_last_busy(acm->dev); - - if (urb->status) { - dev_dbg(&acm->data->dev, "%s - non-zero urb status: %d\n", - __func__, urb->status); - return; - } - acm_process_read_urb(acm, urb); - - /* throttle device if requested by tty */ - spin_lock_irqsave(&acm->read_lock, flags); - acm->throttled = acm->throttle_req; - if (!acm->throttled && !acm->susp_count) { - spin_unlock_irqrestore(&acm->read_lock, flags); - acm_submit_read_urb(acm, rb->index, GFP_ATOMIC); - } else { - spin_unlock_irqrestore(&acm->read_lock, flags); - } -} - -/* data interface wrote those outgoing bytes */ -static void acm_write_bulk(struct urb *urb) -{ - struct acm_wb *wb = urb->context; - struct acm *acm = wb->instance; - unsigned long flags; - - if (urb->status || (urb->actual_length != urb->transfer_buffer_length)) - dev_vdbg(&acm->data->dev, "%s - len %d/%d, status %d\n", - __func__, - urb->actual_length, - urb->transfer_buffer_length, - urb->status); - - spin_lock_irqsave(&acm->write_lock, flags); - acm_write_done(acm, wb); - spin_unlock_irqrestore(&acm->write_lock, flags); - schedule_work(&acm->work); -} - -static void acm_softint(struct work_struct *work) -{ - struct acm *acm = container_of(work, struct acm, work); - struct tty_struct *tty; - - dev_vdbg(&acm->data->dev, "%s\n", __func__); - - tty = tty_port_tty_get(&acm->port); - if (!tty) - return; - tty_wakeup(tty); - tty_kref_put(tty); -} - -/* - * TTY handlers - */ - -static int acm_tty_install(struct tty_driver *driver, struct tty_struct *tty) -{ - struct acm *acm; - int retval; - - dev_dbg(tty->dev, "%s\n", __func__); - - acm = acm_get_by_index(tty->index); - if (!acm) - return -ENODEV; - - retval = tty_standard_install(driver, tty); - if (retval) - goto error_init_termios; - - tty->driver_data = acm; - - return 0; - -error_init_termios: - tty_port_put(&acm->port); - return retval; -} - -static int acm_tty_open(struct tty_struct *tty, struct file *filp) -{ - struct acm *acm = tty->driver_data; - - dev_dbg(tty->dev, "%s\n", __func__); - - return tty_port_open(&acm->port, tty, filp); -} - -static int acm_port_activate(struct tty_port *port, struct tty_struct *tty) -{ - struct acm *acm = container_of(port, struct acm, port); - int retval = -ENODEV; - - dev_dbg(&acm->control->dev, "%s\n", __func__); - - mutex_lock(&acm->mutex); - if (acm->disconnected) - goto disconnected; - - retval = usb_autopm_get_interface(acm->control); - if (retval) - goto error_get_interface; - - /* - * FIXME: Why do we need this? Allocating 64K of physically contiguous - * memory is really nasty... - */ - set_bit(TTY_NO_WRITE_SPLIT, &tty->flags); - acm->control->needs_remote_wakeup = 1; - - acm->ctrlurb->dev = acm->dev; - if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) { - dev_err(&acm->control->dev, - "%s - usb_submit_urb(ctrl irq) failed\n", __func__); - goto error_submit_urb; - } - - acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS; - if (acm_set_control(acm, acm->ctrlout) < 0 && - (acm->ctrl_caps & USB_CDC_CAP_LINE)) - goto error_set_control; - - usb_autopm_put_interface(acm->control); - - /* - * Unthrottle device in case the TTY was closed while throttled. - */ - spin_lock_irq(&acm->read_lock); - acm->throttled = 0; - acm->throttle_req = 0; - spin_unlock_irq(&acm->read_lock); - - if (acm_submit_read_urbs(acm, GFP_KERNEL)) - goto error_submit_read_urbs; - - mutex_unlock(&acm->mutex); - - return 0; - -error_submit_read_urbs: - acm->ctrlout = 0; - acm_set_control(acm, acm->ctrlout); -error_set_control: - usb_kill_urb(acm->ctrlurb); -error_submit_urb: - usb_autopm_put_interface(acm->control); -error_get_interface: -disconnected: - mutex_unlock(&acm->mutex); - return retval; -} - -static void acm_port_destruct(struct tty_port *port) -{ - struct acm *acm = container_of(port, struct acm, port); - - dev_dbg(&acm->control->dev, "%s\n", __func__); - - tty_unregister_device(acm_tty_driver, acm->minor); - acm_release_minor(acm); - usb_put_intf(acm->control); - kfree(acm->country_codes); - kfree(acm); -} - -static void acm_port_shutdown(struct tty_port *port) -{ - struct acm *acm = container_of(port, struct acm, port); - int i; - - dev_dbg(&acm->control->dev, "%s\n", __func__); - - mutex_lock(&acm->mutex); - if (!acm->disconnected) { - usb_autopm_get_interface(acm->control); - acm_set_control(acm, acm->ctrlout = 0); - usb_kill_urb(acm->ctrlurb); - for (i = 0; i < ACM_NW; i++) - usb_kill_urb(acm->wb[i].urb); - for (i = 0; i < acm->rx_buflimit; i++) - usb_kill_urb(acm->read_urbs[i]); - acm->control->needs_remote_wakeup = 0; - usb_autopm_put_interface(acm->control); - } - mutex_unlock(&acm->mutex); -} - -static void acm_tty_cleanup(struct tty_struct *tty) -{ - struct acm *acm = tty->driver_data; - dev_dbg(&acm->control->dev, "%s\n", __func__); - tty_port_put(&acm->port); -} - -static void acm_tty_hangup(struct tty_struct *tty) -{ - struct acm *acm = tty->driver_data; - dev_dbg(&acm->control->dev, "%s\n", __func__); - tty_port_hangup(&acm->port); -} - -static void acm_tty_close(struct tty_struct *tty, struct file *filp) -{ - struct acm *acm = tty->driver_data; - dev_dbg(&acm->control->dev, "%s\n", __func__); - tty_port_close(&acm->port, tty, filp); -} - -static int acm_tty_write(struct tty_struct *tty, - const unsigned char *buf, int count) -{ - struct acm *acm = tty->driver_data; - int stat; - unsigned long flags; - int wbn; - struct acm_wb *wb; - - if (!count) - return 0; - - dev_vdbg(&acm->data->dev, "%s - count %d\n", __func__, count); - - spin_lock_irqsave(&acm->write_lock, flags); - wbn = acm_wb_alloc(acm); - if (wbn < 0) { - spin_unlock_irqrestore(&acm->write_lock, flags); - return 0; - } - wb = &acm->wb[wbn]; - - count = (count > acm->writesize) ? acm->writesize : count; - dev_vdbg(&acm->data->dev, "%s - write %d\n", __func__, count); - memcpy(wb->buf, buf, count); - wb->len = count; - spin_unlock_irqrestore(&acm->write_lock, flags); - - stat = acm_write_start(acm, wbn); - if (stat < 0) - return stat; - return count; -} - -static int acm_tty_write_room(struct tty_struct *tty) -{ - struct acm *acm = tty->driver_data; - /* - * Do not let the line discipline to know that we have a reserve, - * or it might get too enthusiastic. - */ - return acm_wb_is_avail(acm) ? acm->writesize : 0; -} - -static int acm_tty_chars_in_buffer(struct tty_struct *tty) -{ - struct acm *acm = tty->driver_data; - /* - * if the device was unplugged then any remaining characters fell out - * of the connector ;) - */ - if (acm->disconnected) - return 0; - /* - * This is inaccurate (overcounts), but it works. - */ - return (ACM_NW - acm_wb_is_avail(acm)) * acm->writesize; -} - -static void acm_tty_throttle(struct tty_struct *tty) -{ - struct acm *acm = tty->driver_data; - - spin_lock_irq(&acm->read_lock); - acm->throttle_req = 1; - spin_unlock_irq(&acm->read_lock); -} - -static void acm_tty_unthrottle(struct tty_struct *tty) -{ - struct acm *acm = tty->driver_data; - unsigned int was_throttled; - - spin_lock_irq(&acm->read_lock); - was_throttled = acm->throttled; - acm->throttled = 0; - acm->throttle_req = 0; - spin_unlock_irq(&acm->read_lock); - - if (was_throttled) - acm_submit_read_urbs(acm, GFP_KERNEL); -} - -static int acm_tty_break_ctl(struct tty_struct *tty, int state) -{ - struct acm *acm = tty->driver_data; - int retval; - - retval = acm_send_break(acm, state ? 0xffff : 0); - if (retval < 0) - dev_dbg(&acm->control->dev, "%s - send break failed\n", - __func__); - return retval; -} - -static int acm_tty_tiocmget(struct tty_struct *tty) -{ - struct acm *acm = tty->driver_data; - - return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) | - (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) | - (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) | - (acm->ctrlin & ACM_CTRL_RI ? TIOCM_RI : 0) | - (acm->ctrlin & ACM_CTRL_DCD ? TIOCM_CD : 0) | - TIOCM_CTS; -} - -static int acm_tty_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct acm *acm = tty->driver_data; - unsigned int newctrl; - - newctrl = acm->ctrlout; - set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | - (set & TIOCM_RTS ? ACM_CTRL_RTS : 0); - clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) | - (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0); - - newctrl = (newctrl & ~clear) | set; - - if (acm->ctrlout == newctrl) - return 0; - return acm_set_control(acm, acm->ctrlout = newctrl); -} - -static int get_serial_info(struct acm *acm, struct serial_struct __user *info) -{ - struct serial_struct tmp; - - if (!info) - return -EINVAL; - - memset(&tmp, 0, sizeof(tmp)); - tmp.flags = ASYNC_LOW_LATENCY; - tmp.xmit_fifo_size = acm->writesize; - tmp.baud_base = le32_to_cpu(acm->line.dwDTERate); - - if (copy_to_user(info, &tmp, sizeof(tmp))) - return -EFAULT; - else - return 0; -} - -static int acm_tty_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct acm *acm = tty->driver_data; - int rv = -ENOIOCTLCMD; - - switch (cmd) { - case TIOCGSERIAL: /* gets serial port data */ - rv = get_serial_info(acm, (struct serial_struct __user *) arg); - break; - } - - return rv; -} - -static const __u32 acm_tty_speed[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, - 1200, 1800, 2400, 4800, 9600, 19200, 38400, - 57600, 115200, 230400, 460800, 500000, 576000, - 921600, 1000000, 1152000, 1500000, 2000000, - 2500000, 3000000, 3500000, 4000000 -}; - -static const __u8 acm_tty_size[] = { - 5, 6, 7, 8 -}; - -static void acm_tty_set_termios(struct tty_struct *tty, - struct ktermios *termios_old) -{ - struct acm *acm = tty->driver_data; - struct ktermios *termios = tty->termios; - struct usb_cdc_line_coding newline; - int newctrl = acm->ctrlout; - - newline.dwDTERate = cpu_to_le32(tty_get_baud_rate(tty)); - newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0; - newline.bParityType = termios->c_cflag & PARENB ? - (termios->c_cflag & PARODD ? 1 : 2) + - (termios->c_cflag & CMSPAR ? 2 : 0) : 0; - newline.bDataBits = acm_tty_size[(termios->c_cflag & CSIZE) >> 4]; - /* FIXME: Needs to clear unsupported bits in the termios */ - acm->clocal = ((termios->c_cflag & CLOCAL) != 0); - - if (!newline.dwDTERate) { - newline.dwDTERate = acm->line.dwDTERate; - newctrl &= ~ACM_CTRL_DTR; - } else - newctrl |= ACM_CTRL_DTR; - - if (newctrl != acm->ctrlout) - acm_set_control(acm, acm->ctrlout = newctrl); - - if (memcmp(&acm->line, &newline, sizeof newline)) { - memcpy(&acm->line, &newline, sizeof newline); - dev_dbg(&acm->control->dev, "%s - set line: %d %d %d %d\n", - __func__, - le32_to_cpu(newline.dwDTERate), - newline.bCharFormat, newline.bParityType, - newline.bDataBits); - acm_set_line(acm, &acm->line); - } -} - -static const struct tty_port_operations acm_port_ops = { - .shutdown = acm_port_shutdown, - .activate = acm_port_activate, - .destruct = acm_port_destruct, -}; - -/* - * USB probe and disconnect routines. - */ - -/* Little helpers: write/read buffers free */ -static void acm_write_buffers_free(struct acm *acm) -{ - int i; - struct acm_wb *wb; - struct usb_device *usb_dev = interface_to_usbdev(acm->control); - - for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) - usb_free_coherent(usb_dev, acm->writesize, wb->buf, wb->dmah); -} - -static void acm_read_buffers_free(struct acm *acm) -{ - struct usb_device *usb_dev = interface_to_usbdev(acm->control); - int i; - - for (i = 0; i < acm->rx_buflimit; i++) - usb_free_coherent(usb_dev, acm->readsize, - acm->read_buffers[i].base, acm->read_buffers[i].dma); -} - -/* Little helper: write buffers allocate */ -static int acm_write_buffers_alloc(struct acm *acm) -{ - int i; - struct acm_wb *wb; - - for (wb = &acm->wb[0], i = 0; i < ACM_NW; i++, wb++) { - wb->buf = usb_alloc_coherent(acm->dev, acm->writesize, GFP_KERNEL, - &wb->dmah); - if (!wb->buf) { - while (i != 0) { - --i; - --wb; - usb_free_coherent(acm->dev, acm->writesize, - wb->buf, wb->dmah); - } - return -ENOMEM; - } - } - return 0; -} - -static int acm_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_cdc_union_desc *union_header = NULL; - struct usb_cdc_country_functional_desc *cfd = NULL; - unsigned char *buffer = intf->altsetting->extra; - int buflen = intf->altsetting->extralen; - struct usb_interface *control_interface; - struct usb_interface *data_interface; - 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; - int ctrlsize, readsize; - u8 *buf; - u8 ac_management_function = 0; - u8 call_management_function = 0; - int call_interface_num = -1; - int data_interface_num = -1; - unsigned long quirks; - int num_rx_buf; - int i; - int combined_interfaces = 0; - - /* normal quirks */ - quirks = (unsigned long)id->driver_info; - num_rx_buf = (quirks == SINGLE_RX_URB) ? 1 : ACM_NR; - - /* handle quirks deadly to normal probing*/ - if (quirks == NO_UNION_NORMAL) { - data_interface = usb_ifnum_to_if(usb_dev, 1); - control_interface = usb_ifnum_to_if(usb_dev, 0); - goto skip_normal_probe; - } - - /* normal probing*/ - if (!buffer) { - dev_err(&intf->dev, "Weird descriptor references\n"); - return -EINVAL; - } - - if (!buflen) { - if (intf->cur_altsetting->endpoint && - intf->cur_altsetting->endpoint->extralen && - intf->cur_altsetting->endpoint->extra) { - dev_dbg(&intf->dev, - "Seeking extra descriptors on endpoint\n"); - buflen = intf->cur_altsetting->endpoint->extralen; - buffer = intf->cur_altsetting->endpoint->extra; - } else { - dev_err(&intf->dev, - "Zero length descriptor references\n"); - return -EINVAL; - } - } - - while (buflen > 0) { - if (buffer[1] != USB_DT_CS_INTERFACE) { - dev_err(&intf->dev, "skipping garbage\n"); - goto next_desc; - } - - switch (buffer[2]) { - case USB_CDC_UNION_TYPE: /* we've found it */ - if (union_header) { - dev_err(&intf->dev, "More than one " - "union descriptor, skipping ...\n"); - goto next_desc; - } - union_header = (struct usb_cdc_union_desc *)buffer; - break; - case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/ - cfd = (struct usb_cdc_country_functional_desc *)buffer; - break; - case USB_CDC_HEADER_TYPE: /* maybe check version */ - break; /* for now we ignore it */ - case USB_CDC_ACM_TYPE: - ac_management_function = buffer[3]; - break; - case USB_CDC_CALL_MANAGEMENT_TYPE: - call_management_function = buffer[3]; - call_interface_num = buffer[4]; - if ( (quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3) - dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n"); - break; - default: - /* there are LOTS more CDC descriptors that - * could legitimately be found here. - */ - dev_dbg(&intf->dev, "Ignoring descriptor: " - "type %02x, length %d\n", - buffer[2], buffer[0]); - break; - } -next_desc: - buflen -= buffer[0]; - buffer += buffer[0]; - } - - if (!union_header) { - if (call_interface_num > 0) { - dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n"); - /* quirks for Droids MuIn LCD */ - if (quirks & NO_DATA_INTERFACE) - data_interface = usb_ifnum_to_if(usb_dev, 0); - else - data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num)); - control_interface = intf; - } else { - 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); - data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); - if (!control_interface || !data_interface) { - dev_dbg(&intf->dev, "no interfaces\n"); - return -ENODEV; - } - } - - 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 */ - if (data_interface->cur_altsetting->desc.bInterfaceClass - != CDC_DATA_INTERFACE_TYPE) { - if (control_interface->cur_altsetting->desc.bInterfaceClass - == CDC_DATA_INTERFACE_TYPE) { - struct usb_interface *t; - dev_dbg(&intf->dev, - "Your device has switched interfaces.\n"); - t = control_interface; - control_interface = data_interface; - data_interface = t; - } else { - return -EINVAL; - } - } - - /* Accept probe requests only for the control interface */ - if (!combined_interfaces && intf != control_interface) - return -ENODEV; - - 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; - } - - - if (data_interface->cur_altsetting->desc.bNumEndpoints < 2) - return -EINVAL; - - epctrl = &control_interface->cur_altsetting->endpoint[0].desc; - epread = &data_interface->cur_altsetting->endpoint[0].desc; - epwrite = &data_interface->cur_altsetting->endpoint[1].desc; - - - /* workaround for switched endpoints */ - if (!usb_endpoint_dir_in(epread)) { - /* descriptors are swapped */ - struct usb_endpoint_descriptor *t; - dev_dbg(&intf->dev, - "The data interface has switched endpoints\n"); - t = epread; - epread = epwrite; - epwrite = t; - } -made_compressed_probe: - dev_dbg(&intf->dev, "interfaces are valid\n"); - - acm = kzalloc(sizeof(struct acm), GFP_KERNEL); - if (acm == NULL) { - dev_err(&intf->dev, "out of memory (acm kzalloc)\n"); - goto alloc_fail; - } - - minor = acm_alloc_minor(acm); - if (minor == ACM_TTY_MINORS) { - dev_err(&intf->dev, "no more free acm devices\n"); - kfree(acm); - return -ENODEV; - } - - ctrlsize = usb_endpoint_maxp(epctrl); - readsize = usb_endpoint_maxp(epread) * - (quirks == SINGLE_RX_URB ? 1 : 2); - acm->combined_interfaces = combined_interfaces; - acm->writesize = usb_endpoint_maxp(epwrite) * 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; - INIT_WORK(&acm->work, acm_softint); - spin_lock_init(&acm->write_lock); - spin_lock_init(&acm->read_lock); - mutex_init(&acm->mutex); - acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress); - acm->is_int_ep = usb_endpoint_xfer_int(epread); - if (acm->is_int_ep) - acm->bInterval = epread->bInterval; - tty_port_init(&acm->port); - acm->port.ops = &acm_port_ops; - - buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); - if (!buf) { - dev_err(&intf->dev, "out of memory (ctrl buffer alloc)\n"); - goto alloc_fail2; - } - acm->ctrl_buffer = buf; - - if (acm_write_buffers_alloc(acm) < 0) { - dev_err(&intf->dev, "out of memory (write buffer alloc)\n"); - goto alloc_fail4; - } - - acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL); - if (!acm->ctrlurb) { - dev_err(&intf->dev, "out of memory (ctrlurb kmalloc)\n"); - goto alloc_fail5; - } - for (i = 0; i < num_rx_buf; i++) { - struct acm_rb *rb = &(acm->read_buffers[i]); - struct urb *urb; - - rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL, - &rb->dma); - if (!rb->base) { - dev_err(&intf->dev, "out of memory " - "(read bufs usb_alloc_coherent)\n"); - goto alloc_fail6; - } - rb->index = i; - rb->instance = acm; - - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - dev_err(&intf->dev, - "out of memory (read urbs usb_alloc_urb)\n"); - goto alloc_fail6; - } - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - urb->transfer_dma = rb->dma; - if (acm->is_int_ep) { - usb_fill_int_urb(urb, acm->dev, - acm->rx_endpoint, - rb->base, - acm->readsize, - acm_read_bulk_callback, rb, - acm->bInterval); - } else { - usb_fill_bulk_urb(urb, acm->dev, - acm->rx_endpoint, - rb->base, - acm->readsize, - acm_read_bulk_callback, rb); - } - - acm->read_urbs[i] = urb; - __set_bit(i, &acm->read_urbs_free); - } - for (i = 0; i < ACM_NW; i++) { - struct acm_wb *snd = &(acm->wb[i]); - - snd->urb = usb_alloc_urb(0, GFP_KERNEL); - if (snd->urb == NULL) { - dev_err(&intf->dev, - "out of memory (write urbs usb_alloc_urb)\n"); - goto alloc_fail7; - } - - if (usb_endpoint_xfer_int(epwrite)) - usb_fill_int_urb(snd->urb, usb_dev, - usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), - NULL, acm->writesize, acm_write_bulk, snd, epwrite->bInterval); - else - usb_fill_bulk_urb(snd->urb, usb_dev, - usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), - NULL, acm->writesize, acm_write_bulk, snd); - snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - snd->instance = acm; - } - - usb_set_intfdata(intf, acm); - - i = device_create_file(&intf->dev, &dev_attr_bmCapabilities); - if (i < 0) - goto alloc_fail7; - - if (cfd) { /* export the country data */ - acm->country_codes = kmalloc(cfd->bLength - 4, GFP_KERNEL); - if (!acm->country_codes) - goto skip_countries; - acm->country_code_size = cfd->bLength - 4; - memcpy(acm->country_codes, (u8 *)&cfd->wCountyCode0, - cfd->bLength - 4); - acm->country_rel_date = cfd->iCountryCodeRelDate; - - i = device_create_file(&intf->dev, &dev_attr_wCountryCodes); - if (i < 0) { - kfree(acm->country_codes); - acm->country_codes = NULL; - acm->country_code_size = 0; - goto skip_countries; - } - - i = device_create_file(&intf->dev, - &dev_attr_iCountryCodeRelDate); - if (i < 0) { - device_remove_file(&intf->dev, &dev_attr_wCountryCodes); - kfree(acm->country_codes); - acm->country_codes = NULL; - acm->country_code_size = 0; - goto skip_countries; - } - } - -skip_countries: - usb_fill_int_urb(acm->ctrlurb, usb_dev, - 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; - - dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); - - acm_set_control(acm, acm->ctrlout); - - acm->line.dwDTERate = cpu_to_le32(9600); - acm->line.bDataBits = 8; - acm_set_line(acm, &acm->line); - - usb_driver_claim_interface(&acm_driver, data_interface, acm); - usb_set_intfdata(data_interface, acm); - - usb_get_intf(control_interface); - tty_register_device(acm_tty_driver, minor, &control_interface->dev); - - return 0; -alloc_fail7: - for (i = 0; i < ACM_NW; i++) - usb_free_urb(acm->wb[i].urb); -alloc_fail6: - for (i = 0; i < num_rx_buf; i++) - usb_free_urb(acm->read_urbs[i]); - acm_read_buffers_free(acm); - usb_free_urb(acm->ctrlurb); -alloc_fail5: - acm_write_buffers_free(acm); -alloc_fail4: - usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); -alloc_fail2: - acm_release_minor(acm); - kfree(acm); -alloc_fail: - return -ENOMEM; -} - -static void stop_data_traffic(struct acm *acm) -{ - int i; - - dev_dbg(&acm->control->dev, "%s\n", __func__); - - usb_kill_urb(acm->ctrlurb); - for (i = 0; i < ACM_NW; i++) - usb_kill_urb(acm->wb[i].urb); - for (i = 0; i < acm->rx_buflimit; i++) - usb_kill_urb(acm->read_urbs[i]); - - cancel_work_sync(&acm->work); -} - -static void acm_disconnect(struct usb_interface *intf) -{ - struct acm *acm = usb_get_intfdata(intf); - struct usb_device *usb_dev = interface_to_usbdev(intf); - struct tty_struct *tty; - int i; - - dev_dbg(&intf->dev, "%s\n", __func__); - - /* sibling interface is already cleaning up */ - if (!acm) - return; - - mutex_lock(&acm->mutex); - acm->disconnected = true; - if (acm->country_codes) { - device_remove_file(&acm->control->dev, - &dev_attr_wCountryCodes); - device_remove_file(&acm->control->dev, - &dev_attr_iCountryCodeRelDate); - } - device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities); - usb_set_intfdata(acm->control, NULL); - usb_set_intfdata(acm->data, NULL); - mutex_unlock(&acm->mutex); - - tty = tty_port_tty_get(&acm->port); - if (tty) { - tty_vhangup(tty); - tty_kref_put(tty); - } - - stop_data_traffic(acm); - - usb_free_urb(acm->ctrlurb); - for (i = 0; i < ACM_NW; i++) - usb_free_urb(acm->wb[i].urb); - for (i = 0; i < acm->rx_buflimit; i++) - usb_free_urb(acm->read_urbs[i]); - acm_write_buffers_free(acm); - usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); - acm_read_buffers_free(acm); - - if (!acm->combined_interfaces) - usb_driver_release_interface(&acm_driver, intf == acm->control ? - acm->data : acm->control); - - tty_port_put(&acm->port); -} - -#ifdef CONFIG_PM -static int acm_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct acm *acm = usb_get_intfdata(intf); - int cnt; - - if (PMSG_IS_AUTO(message)) { - int b; - - spin_lock_irq(&acm->write_lock); - b = acm->transmitting; - spin_unlock_irq(&acm->write_lock); - if (b) - return -EBUSY; - } - - spin_lock_irq(&acm->read_lock); - spin_lock(&acm->write_lock); - cnt = acm->susp_count++; - spin_unlock(&acm->write_lock); - spin_unlock_irq(&acm->read_lock); - - if (cnt) - return 0; - - if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) - stop_data_traffic(acm); - - return 0; -} - -static int acm_resume(struct usb_interface *intf) -{ - struct acm *acm = usb_get_intfdata(intf); - struct acm_wb *wb; - int rv = 0; - int cnt; - - spin_lock_irq(&acm->read_lock); - acm->susp_count -= 1; - cnt = acm->susp_count; - spin_unlock_irq(&acm->read_lock); - - if (cnt) - return 0; - - if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) { - rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); - - spin_lock_irq(&acm->write_lock); - if (acm->delayed_wb) { - wb = acm->delayed_wb; - acm->delayed_wb = NULL; - spin_unlock_irq(&acm->write_lock); - acm_start_wb(acm, wb); - } else { - spin_unlock_irq(&acm->write_lock); - } - - /* - * delayed error checking because we must - * do the write path at all cost - */ - if (rv < 0) - goto err_out; - - rv = acm_submit_read_urbs(acm, GFP_NOIO); - } - -err_out: - return rv; -} - -static int acm_reset_resume(struct usb_interface *intf) -{ - struct acm *acm = usb_get_intfdata(intf); - struct tty_struct *tty; - - if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) { - tty = tty_port_tty_get(&acm->port); - if (tty) { - tty_hangup(tty); - tty_kref_put(tty); - } - } - - return acm_resume(intf); -} - -#endif /* CONFIG_PM */ - -#define NOKIA_PCSUITE_ACM_INFO(x) \ - USB_DEVICE_AND_INTERFACE_INFO(0x0421, x, \ - USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, \ - USB_CDC_ACM_PROTO_VENDOR) - -#define SAMSUNG_PCSUITE_ACM_INFO(x) \ - USB_DEVICE_AND_INTERFACE_INFO(0x04e7, x, \ - USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, \ - USB_CDC_ACM_PROTO_VENDOR) - -/* - * USB driver structure. - */ - -static const struct usb_device_id acm_ids[] = { - /* quirky and broken devices */ - { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */ - .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ - }, - { USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */ - .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ - }, - { USB_DEVICE(0x0e8d, 0x3329), /* MediaTek Inc GPS */ - .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ - }, - { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */ - .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ - }, - { USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */ - .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ - }, - { USB_DEVICE(0x0ace, 0x1602), /* ZyDAS 56K USB MODEM */ - .driver_info = SINGLE_RX_URB, - }, - { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */ - .driver_info = SINGLE_RX_URB, /* firmware bug */ - }, - { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */ - .driver_info = SINGLE_RX_URB, /* firmware bug */ - }, - { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */ - .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ - }, - { USB_DEVICE(0x0803, 0x3095), /* Zoom Telephonics Model 3095F USB MODEM */ - .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ - }, - { USB_DEVICE(0x0572, 0x1321), /* Conexant USB MODEM CX93010 */ - .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ - }, - { USB_DEVICE(0x0572, 0x1324), /* Conexant USB MODEM RD02-D400 */ - .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ - }, - { USB_DEVICE(0x0572, 0x1328), /* Shiro / Aztech USB MODEM UM-3100 */ - .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ - }, - { USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */ - }, - /* Motorola H24 HSPA module: */ - { USB_DEVICE(0x22b8, 0x2d91) }, /* modem */ - { USB_DEVICE(0x22b8, 0x2d92) }, /* modem + diagnostics */ - { USB_DEVICE(0x22b8, 0x2d93) }, /* modem + AT port */ - { USB_DEVICE(0x22b8, 0x2d95) }, /* modem + AT port + diagnostics */ - { USB_DEVICE(0x22b8, 0x2d96) }, /* modem + NMEA */ - { USB_DEVICE(0x22b8, 0x2d97) }, /* modem + diagnostics + NMEA */ - { USB_DEVICE(0x22b8, 0x2d99) }, /* modem + AT port + NMEA */ - { USB_DEVICE(0x22b8, 0x2d9a) }, /* modem + AT port + diagnostics + NMEA */ - - { USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */ - .driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on - data interface instead of - communications interface. - 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 */ - }, - { USB_DEVICE(0x1576, 0x03b1), /* Maretron USB100 */ - .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */ - }, - - /* Nokia S60 phones expose two ACM channels. The first is - * a modem and is picked up by the standard AT-command - * information below. The second is 'vendor-specific' but - * is treated as a serial device at the S60 end, so we want - * to expose it on Linux too. */ - { NOKIA_PCSUITE_ACM_INFO(0x042D), }, /* Nokia 3250 */ - { NOKIA_PCSUITE_ACM_INFO(0x04D8), }, /* Nokia 5500 Sport */ - { NOKIA_PCSUITE_ACM_INFO(0x04C9), }, /* Nokia E50 */ - { NOKIA_PCSUITE_ACM_INFO(0x0419), }, /* Nokia E60 */ - { NOKIA_PCSUITE_ACM_INFO(0x044D), }, /* Nokia E61 */ - { NOKIA_PCSUITE_ACM_INFO(0x0001), }, /* Nokia E61i */ - { NOKIA_PCSUITE_ACM_INFO(0x0475), }, /* Nokia E62 */ - { NOKIA_PCSUITE_ACM_INFO(0x0508), }, /* Nokia E65 */ - { NOKIA_PCSUITE_ACM_INFO(0x0418), }, /* Nokia E70 */ - { NOKIA_PCSUITE_ACM_INFO(0x0425), }, /* Nokia N71 */ - { NOKIA_PCSUITE_ACM_INFO(0x0486), }, /* Nokia N73 */ - { NOKIA_PCSUITE_ACM_INFO(0x04DF), }, /* Nokia N75 */ - { NOKIA_PCSUITE_ACM_INFO(0x000e), }, /* Nokia N77 */ - { NOKIA_PCSUITE_ACM_INFO(0x0445), }, /* Nokia N80 */ - { NOKIA_PCSUITE_ACM_INFO(0x042F), }, /* Nokia N91 & N91 8GB */ - { NOKIA_PCSUITE_ACM_INFO(0x048E), }, /* Nokia N92 */ - { NOKIA_PCSUITE_ACM_INFO(0x0420), }, /* Nokia N93 */ - { NOKIA_PCSUITE_ACM_INFO(0x04E6), }, /* Nokia N93i */ - { NOKIA_PCSUITE_ACM_INFO(0x04B2), }, /* Nokia 5700 XpressMusic */ - { NOKIA_PCSUITE_ACM_INFO(0x0134), }, /* Nokia 6110 Navigator (China) */ - { NOKIA_PCSUITE_ACM_INFO(0x046E), }, /* Nokia 6110 Navigator */ - { NOKIA_PCSUITE_ACM_INFO(0x002f), }, /* Nokia 6120 classic & */ - { NOKIA_PCSUITE_ACM_INFO(0x0088), }, /* Nokia 6121 classic */ - { NOKIA_PCSUITE_ACM_INFO(0x00fc), }, /* Nokia 6124 classic */ - { NOKIA_PCSUITE_ACM_INFO(0x0042), }, /* Nokia E51 */ - { NOKIA_PCSUITE_ACM_INFO(0x00b0), }, /* Nokia E66 */ - { NOKIA_PCSUITE_ACM_INFO(0x00ab), }, /* Nokia E71 */ - { NOKIA_PCSUITE_ACM_INFO(0x0481), }, /* Nokia N76 */ - { NOKIA_PCSUITE_ACM_INFO(0x0007), }, /* Nokia N81 & N81 8GB */ - { NOKIA_PCSUITE_ACM_INFO(0x0071), }, /* Nokia N82 */ - { NOKIA_PCSUITE_ACM_INFO(0x04F0), }, /* Nokia N95 & N95-3 NAM */ - { NOKIA_PCSUITE_ACM_INFO(0x0070), }, /* Nokia N95 8GB */ - { NOKIA_PCSUITE_ACM_INFO(0x00e9), }, /* Nokia 5320 XpressMusic */ - { NOKIA_PCSUITE_ACM_INFO(0x0099), }, /* Nokia 6210 Navigator, RM-367 */ - { NOKIA_PCSUITE_ACM_INFO(0x0128), }, /* Nokia 6210 Navigator, RM-419 */ - { NOKIA_PCSUITE_ACM_INFO(0x008f), }, /* Nokia 6220 Classic */ - { NOKIA_PCSUITE_ACM_INFO(0x00a0), }, /* Nokia 6650 */ - { NOKIA_PCSUITE_ACM_INFO(0x007b), }, /* Nokia N78 */ - { NOKIA_PCSUITE_ACM_INFO(0x0094), }, /* Nokia N85 */ - { NOKIA_PCSUITE_ACM_INFO(0x003a), }, /* Nokia N96 & N96-3 */ - { NOKIA_PCSUITE_ACM_INFO(0x00e9), }, /* Nokia 5320 XpressMusic */ - { NOKIA_PCSUITE_ACM_INFO(0x0108), }, /* Nokia 5320 XpressMusic 2G */ - { NOKIA_PCSUITE_ACM_INFO(0x01f5), }, /* Nokia N97, RM-505 */ - { NOKIA_PCSUITE_ACM_INFO(0x02e3), }, /* Nokia 5230, RM-588 */ - { NOKIA_PCSUITE_ACM_INFO(0x0178), }, /* Nokia E63 */ - { NOKIA_PCSUITE_ACM_INFO(0x010e), }, /* Nokia E75 */ - { NOKIA_PCSUITE_ACM_INFO(0x02d9), }, /* Nokia 6760 Slide */ - { NOKIA_PCSUITE_ACM_INFO(0x01d0), }, /* Nokia E52 */ - { NOKIA_PCSUITE_ACM_INFO(0x0223), }, /* Nokia E72 */ - { NOKIA_PCSUITE_ACM_INFO(0x0275), }, /* Nokia X6 */ - { NOKIA_PCSUITE_ACM_INFO(0x026c), }, /* Nokia N97 Mini */ - { NOKIA_PCSUITE_ACM_INFO(0x0154), }, /* Nokia 5800 XpressMusic */ - { NOKIA_PCSUITE_ACM_INFO(0x04ce), }, /* Nokia E90 */ - { NOKIA_PCSUITE_ACM_INFO(0x01d4), }, /* Nokia E55 */ - { NOKIA_PCSUITE_ACM_INFO(0x0302), }, /* Nokia N8 */ - { NOKIA_PCSUITE_ACM_INFO(0x0335), }, /* Nokia E7 */ - { NOKIA_PCSUITE_ACM_INFO(0x03cd), }, /* Nokia C7 */ - { SAMSUNG_PCSUITE_ACM_INFO(0x6651), }, /* Samsung GTi8510 (INNOV8) */ - - /* Support for Owen devices */ - { USB_DEVICE(0x03eb, 0x0030), }, /* Owen SI30 */ - - /* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */ - - /* Support Lego NXT using pbLua firmware */ - { USB_DEVICE(0x0694, 0xff00), - .driver_info = NOT_A_MODEM, - }, - - /* Support for Droids MuIn LCD */ - { USB_DEVICE(0x04d8, 0x000b), - .driver_info = NO_DATA_INTERFACE, - }, - - /* control interfaces without any protocol set */ - { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, - USB_CDC_PROTO_NONE) }, - - /* control interfaces with various AT-command sets */ - { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, - USB_CDC_ACM_PROTO_AT_V25TER) }, - { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, - USB_CDC_ACM_PROTO_AT_PCCA101) }, - { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, - USB_CDC_ACM_PROTO_AT_PCCA101_WAKE) }, - { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, - USB_CDC_ACM_PROTO_AT_GSM) }, - { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, - USB_CDC_ACM_PROTO_AT_3G) }, - { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM, - USB_CDC_ACM_PROTO_AT_CDMA) }, - - { } -}; - -MODULE_DEVICE_TABLE(usb, acm_ids); - -static struct usb_driver acm_driver = { - .name = "cdc_acm", - .probe = acm_probe, - .disconnect = acm_disconnect, -#ifdef CONFIG_PM - .suspend = acm_suspend, - .resume = acm_resume, - .reset_resume = acm_reset_resume, -#endif - .id_table = acm_ids, -#ifdef CONFIG_PM - .supports_autosuspend = 1, -#endif -}; - -/* - * TTY driver structures. - */ - -static const struct tty_operations acm_ops = { - .install = acm_tty_install, - .open = acm_tty_open, - .close = acm_tty_close, - .cleanup = acm_tty_cleanup, - .hangup = acm_tty_hangup, - .write = acm_tty_write, - .write_room = acm_tty_write_room, - .ioctl = acm_tty_ioctl, - .throttle = acm_tty_throttle, - .unthrottle = acm_tty_unthrottle, - .chars_in_buffer = acm_tty_chars_in_buffer, - .break_ctl = acm_tty_break_ctl, - .set_termios = acm_tty_set_termios, - .tiocmget = acm_tty_tiocmget, - .tiocmset = acm_tty_tiocmset, -}; - -/* - * Init / exit. - */ - -static int __init acm_init(void) -{ - int retval; - acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS); - if (!acm_tty_driver) - return -ENOMEM; - acm_tty_driver->driver_name = "acm", - acm_tty_driver->name = "ttyACM", - acm_tty_driver->major = ACM_TTY_MAJOR, - acm_tty_driver->minor_start = 0, - acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL, - acm_tty_driver->subtype = SERIAL_TYPE_NORMAL, - acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - acm_tty_driver->init_termios = tty_std_termios; - acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | - HUPCL | CLOCAL; - tty_set_operations(acm_tty_driver, &acm_ops); - - retval = tty_register_driver(acm_tty_driver); - if (retval) { - put_tty_driver(acm_tty_driver); - return retval; - } - - retval = usb_register(&acm_driver); - if (retval) { - tty_unregister_driver(acm_tty_driver); - put_tty_driver(acm_tty_driver); - return retval; - } - - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n"); - - return 0; -} - -static void __exit acm_exit(void) -{ - usb_deregister(&acm_driver); - tty_unregister_driver(acm_tty_driver); - put_tty_driver(acm_tty_driver); -} - -module_init(acm_init); -module_exit(acm_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_CHARDEV_MAJOR(ACM_TTY_MAJOR); diff --git a/ANDROID_3.4.5/drivers/usb/class/cdc-acm.h b/ANDROID_3.4.5/drivers/usb/class/cdc-acm.h deleted file mode 100644 index 35ef887b..00000000 --- a/ANDROID_3.4.5/drivers/usb/class/cdc-acm.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * - * Includes for cdc-acm.c - * - * Mainly take from usbnet's cdc-ether part - * - */ - -/* - * CMSPAR, some architectures can't have space and mark parity. - */ - -#ifndef CMSPAR -#define CMSPAR 0 -#endif - -/* - * Major and minor numbers. - */ - -#define ACM_TTY_MAJOR 166 -#define ACM_TTY_MINORS 32 - -/* - * Requests. - */ - -#define USB_RT_ACM (USB_TYPE_CLASS | USB_RECIP_INTERFACE) - -/* - * Output control lines. - */ - -#define ACM_CTRL_DTR 0x01 -#define ACM_CTRL_RTS 0x02 - -/* - * Input control lines and line errors. - */ - -#define ACM_CTRL_DCD 0x01 -#define ACM_CTRL_DSR 0x02 -#define ACM_CTRL_BRK 0x04 -#define ACM_CTRL_RI 0x08 - -#define ACM_CTRL_FRAMING 0x10 -#define ACM_CTRL_PARITY 0x20 -#define ACM_CTRL_OVERRUN 0x40 - -/* - * Internal driver structures. - */ - -/* - * The only reason to have several buffers is to accommodate assumptions - * in line disciplines. They ask for empty space amount, receive our URB size, - * and proceed to issue several 1-character writes, assuming they will fit. - * The very first write takes a complete URB. Fortunately, this only happens - * when processing onlcr, so we only need 2 buffers. These values must be - * powers of 2. - */ -#define ACM_NW 16 -#define ACM_NR 16 - -struct acm_wb { - unsigned char *buf; - dma_addr_t dmah; - int len; - int use; - struct urb *urb; - struct acm *instance; -}; - -struct acm_rb { - int size; - unsigned char *base; - dma_addr_t dma; - int index; - struct acm *instance; -}; - -struct acm { - struct usb_device *dev; /* the corresponding usb device */ - struct usb_interface *control; /* control interface */ - struct usb_interface *data; /* data interface */ - struct tty_port port; /* our tty port data */ - struct urb *ctrlurb; /* urbs */ - u8 *ctrl_buffer; /* buffers of urbs */ - dma_addr_t ctrl_dma; /* dma handles of buffers */ - u8 *country_codes; /* country codes from device */ - unsigned int country_code_size; /* size of this buffer */ - unsigned int country_rel_date; /* release date of version */ - struct acm_wb wb[ACM_NW]; - unsigned long read_urbs_free; - struct urb *read_urbs[ACM_NR]; - struct acm_rb read_buffers[ACM_NR]; - int rx_buflimit; - int rx_endpoint; - spinlock_t read_lock; - int write_used; /* number of non-empty write buffers */ - int transmitting; - spinlock_t write_lock; - struct mutex mutex; - bool disconnected; - struct usb_cdc_line_coding line; /* bits, stop, parity */ - struct work_struct work; /* work queue entry for line discipline waking up */ - unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */ - unsigned int ctrlout; /* output control lines (DTR, RTS) */ - unsigned int writesize; /* max packet size for the output bulk endpoint */ - unsigned int readsize,ctrlsize; /* buffer sizes for freeing */ - unsigned int minor; /* acm minor number */ - unsigned char clocal; /* termios CLOCAL */ - unsigned int ctrl_caps; /* control capabilities from the class specific header */ - unsigned int susp_count; /* number of suspended interfaces */ - unsigned int combined_interfaces:1; /* control and data collapsed */ - unsigned int is_int_ep:1; /* interrupt endpoints contrary to spec used */ - unsigned int throttled:1; /* actually throttled */ - unsigned int throttle_req:1; /* throttle requested */ - u8 bInterval; - struct acm_wb *delayed_wb; /* write queued for a device about to be woken */ -}; - -#define CDC_DATA_INTERFACE_TYPE 0x0a - -/* constants describing various quirks and errors */ -#define NO_UNION_NORMAL 1 -#define SINGLE_RX_URB 2 -#define NO_CAP_LINE 4 -#define NOT_A_MODEM 8 -#define NO_DATA_INTERFACE 16 diff --git a/ANDROID_3.4.5/drivers/usb/class/cdc-wdm.c b/ANDROID_3.4.5/drivers/usb/class/cdc-wdm.c deleted file mode 100644 index 01d247e8..00000000 --- a/ANDROID_3.4.5/drivers/usb/class/cdc-wdm.c +++ /dev/null @@ -1,1048 +0,0 @@ -/* - * cdc-wdm.c - * - * This driver supports USB CDC WCM Device Management. - * - * Copyright (c) 2007-2009 Oliver Neukum - * - * Some code taken from cdc-acm.c - * - * Released under the GPLv2. - * - * Many thanks to Carl Nordbeck - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Version Information - */ -#define DRIVER_VERSION "v0.03" -#define DRIVER_AUTHOR "Oliver Neukum" -#define DRIVER_DESC "USB Abstract Control Model driver for USB WCM Device Management" - -#define HUAWEI_VENDOR_ID 0x12D1 - -static const struct usb_device_id wdm_ids[] = { - { - .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS | - USB_DEVICE_ID_MATCH_INT_SUBCLASS, - .bInterfaceClass = USB_CLASS_COMM, - .bInterfaceSubClass = USB_CDC_SUBCLASS_DMM - }, - { - /* - * Huawei E392, E398 and possibly other Qualcomm based modems - * embed the Qualcomm QMI protocol inside CDC on CDC ECM like - * control interfaces. Userspace access to this is required - * to configure the accompanying data interface - */ - .match_flags = USB_DEVICE_ID_MATCH_VENDOR | - USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = HUAWEI_VENDOR_ID, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 9, /* NOTE: CDC ECM control interface! */ - }, - { - /* Vodafone/Huawei K5005 (12d1:14c8) and similar modems */ - .match_flags = USB_DEVICE_ID_MATCH_VENDOR | - USB_DEVICE_ID_MATCH_INT_INFO, - .idVendor = HUAWEI_VENDOR_ID, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 57, /* NOTE: CDC ECM control interface! */ - }, - { } -}; - -MODULE_DEVICE_TABLE (usb, wdm_ids); - -#define WDM_MINOR_BASE 176 - - -#define WDM_IN_USE 1 -#define WDM_DISCONNECTING 2 -#define WDM_RESULT 3 -#define WDM_READ 4 -#define WDM_INT_STALL 5 -#define WDM_POLL_RUNNING 6 -#define WDM_RESPONDING 7 -#define WDM_SUSPENDING 8 -#define WDM_RESETTING 9 - -#define WDM_MAX 16 - -/* CDC-WMC r1.1 requires wMaxCommand to be "at least 256 decimal (0x100)" */ -#define WDM_DEFAULT_BUFSIZE 256 - -static DEFINE_MUTEX(wdm_mutex); -static DEFINE_SPINLOCK(wdm_device_list_lock); -static LIST_HEAD(wdm_device_list); - -/* --- method tables --- */ - -struct wdm_device { - u8 *inbuf; /* buffer for response */ - u8 *outbuf; /* buffer for command */ - u8 *sbuf; /* buffer for status */ - u8 *ubuf; /* buffer for copy to user space */ - - struct urb *command; - struct urb *response; - struct urb *validity; - struct usb_interface *intf; - struct usb_ctrlrequest *orq; - struct usb_ctrlrequest *irq; - spinlock_t iuspin; - - unsigned long flags; - u16 bufsize; - u16 wMaxCommand; - u16 wMaxPacketSize; - __le16 inum; - int reslength; - int length; - int read; - int count; - dma_addr_t shandle; - dma_addr_t ihandle; - struct mutex wlock; - struct mutex rlock; - wait_queue_head_t wait; - struct work_struct rxwork; - int werr; - int rerr; - - struct list_head device_list; - int (*manage_power)(struct usb_interface *, int); -}; - -static struct usb_driver wdm_driver; - -/* return intfdata if we own the interface, else look up intf in the list */ -static struct wdm_device *wdm_find_device(struct usb_interface *intf) -{ - struct wdm_device *desc = NULL; - - spin_lock(&wdm_device_list_lock); - list_for_each_entry(desc, &wdm_device_list, device_list) - if (desc->intf == intf) - break; - spin_unlock(&wdm_device_list_lock); - - return desc; -} - -static struct wdm_device *wdm_find_device_by_minor(int minor) -{ - struct wdm_device *desc = NULL; - - spin_lock(&wdm_device_list_lock); - list_for_each_entry(desc, &wdm_device_list, device_list) - if (desc->intf->minor == minor) - break; - spin_unlock(&wdm_device_list_lock); - - return desc; -} - -/* --- callbacks --- */ -static void wdm_out_callback(struct urb *urb) -{ - struct wdm_device *desc; - desc = urb->context; - spin_lock(&desc->iuspin); - desc->werr = urb->status; - spin_unlock(&desc->iuspin); - kfree(desc->outbuf); - desc->outbuf = NULL; - clear_bit(WDM_IN_USE, &desc->flags); - wake_up(&desc->wait); -} - -static void wdm_in_callback(struct urb *urb) -{ - struct wdm_device *desc = urb->context; - int status = urb->status; - - spin_lock(&desc->iuspin); - clear_bit(WDM_RESPONDING, &desc->flags); - - if (status) { - switch (status) { - case -ENOENT: - dev_dbg(&desc->intf->dev, - "nonzero urb status received: -ENOENT"); - goto skip_error; - case -ECONNRESET: - dev_dbg(&desc->intf->dev, - "nonzero urb status received: -ECONNRESET"); - goto skip_error; - case -ESHUTDOWN: - dev_dbg(&desc->intf->dev, - "nonzero urb status received: -ESHUTDOWN"); - goto skip_error; - case -EPIPE: - dev_err(&desc->intf->dev, - "nonzero urb status received: -EPIPE\n"); - break; - default: - dev_err(&desc->intf->dev, - "Unexpected error %d\n", status); - break; - } - } - - desc->rerr = status; - desc->reslength = urb->actual_length; - memmove(desc->ubuf + desc->length, desc->inbuf, desc->reslength); - desc->length += desc->reslength; -skip_error: - wake_up(&desc->wait); - - set_bit(WDM_READ, &desc->flags); - spin_unlock(&desc->iuspin); -} - -static void wdm_int_callback(struct urb *urb) -{ - int rv = 0; - int status = urb->status; - struct wdm_device *desc; - struct usb_cdc_notification *dr; - - desc = urb->context; - dr = (struct usb_cdc_notification *)desc->sbuf; - - if (status) { - switch (status) { - case -ESHUTDOWN: - case -ENOENT: - case -ECONNRESET: - return; /* unplug */ - case -EPIPE: - set_bit(WDM_INT_STALL, &desc->flags); - dev_err(&desc->intf->dev, "Stall on int endpoint\n"); - goto sw; /* halt is cleared in work */ - default: - dev_err(&desc->intf->dev, - "nonzero urb status received: %d\n", status); - break; - } - } - - if (urb->actual_length < sizeof(struct usb_cdc_notification)) { - dev_err(&desc->intf->dev, "wdm_int_callback - %d bytes\n", - urb->actual_length); - goto exit; - } - - switch (dr->bNotificationType) { - case USB_CDC_NOTIFY_RESPONSE_AVAILABLE: - dev_dbg(&desc->intf->dev, - "NOTIFY_RESPONSE_AVAILABLE received: index %d len %d", - dr->wIndex, dr->wLength); - break; - - case USB_CDC_NOTIFY_NETWORK_CONNECTION: - - dev_dbg(&desc->intf->dev, - "NOTIFY_NETWORK_CONNECTION %s network", - dr->wValue ? "connected to" : "disconnected from"); - goto exit; - default: - clear_bit(WDM_POLL_RUNNING, &desc->flags); - dev_err(&desc->intf->dev, - "unknown notification %d received: index %d len %d\n", - dr->bNotificationType, dr->wIndex, dr->wLength); - goto exit; - } - - spin_lock(&desc->iuspin); - clear_bit(WDM_READ, &desc->flags); - set_bit(WDM_RESPONDING, &desc->flags); - if (!test_bit(WDM_DISCONNECTING, &desc->flags) - && !test_bit(WDM_SUSPENDING, &desc->flags)) { - rv = usb_submit_urb(desc->response, GFP_ATOMIC); - dev_dbg(&desc->intf->dev, "%s: usb_submit_urb %d", - __func__, rv); - } - spin_unlock(&desc->iuspin); - if (rv < 0) { - clear_bit(WDM_RESPONDING, &desc->flags); - if (rv == -EPERM) - return; - if (rv == -ENOMEM) { -sw: - rv = schedule_work(&desc->rxwork); - if (rv) - dev_err(&desc->intf->dev, - "Cannot schedule work\n"); - } - } -exit: - rv = usb_submit_urb(urb, GFP_ATOMIC); - if (rv) - dev_err(&desc->intf->dev, - "%s - usb_submit_urb failed with result %d\n", - __func__, rv); - -} - -static void kill_urbs(struct wdm_device *desc) -{ - /* the order here is essential */ - usb_kill_urb(desc->command); - usb_kill_urb(desc->validity); - usb_kill_urb(desc->response); -} - -static void free_urbs(struct wdm_device *desc) -{ - usb_free_urb(desc->validity); - usb_free_urb(desc->response); - usb_free_urb(desc->command); -} - -static void cleanup(struct wdm_device *desc) -{ - kfree(desc->sbuf); - kfree(desc->inbuf); - kfree(desc->orq); - kfree(desc->irq); - kfree(desc->ubuf); - free_urbs(desc); - kfree(desc); -} - -static ssize_t wdm_write -(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - u8 *buf; - int rv = -EMSGSIZE, r, we; - struct wdm_device *desc = file->private_data; - struct usb_ctrlrequest *req; - - if (count > desc->wMaxCommand) - count = desc->wMaxCommand; - - spin_lock_irq(&desc->iuspin); - we = desc->werr; - desc->werr = 0; - spin_unlock_irq(&desc->iuspin); - if (we < 0) - return -EIO; - - buf = kmalloc(count, GFP_KERNEL); - if (!buf) { - rv = -ENOMEM; - goto outnl; - } - - r = copy_from_user(buf, buffer, count); - if (r > 0) { - kfree(buf); - rv = -EFAULT; - goto outnl; - } - - /* concurrent writes and disconnect */ - r = mutex_lock_interruptible(&desc->wlock); - rv = -ERESTARTSYS; - if (r) { - kfree(buf); - goto outnl; - } - - if (test_bit(WDM_DISCONNECTING, &desc->flags)) { - kfree(buf); - rv = -ENODEV; - goto outnp; - } - - r = usb_autopm_get_interface(desc->intf); - if (r < 0) { - kfree(buf); - goto outnp; - } - - if (!(file->f_flags & O_NONBLOCK)) - r = wait_event_interruptible(desc->wait, !test_bit(WDM_IN_USE, - &desc->flags)); - else - if (test_bit(WDM_IN_USE, &desc->flags)) - r = -EAGAIN; - - if (test_bit(WDM_RESETTING, &desc->flags)) - r = -EIO; - - if (r < 0) { - kfree(buf); - goto out; - } - - req = desc->orq; - usb_fill_control_urb( - desc->command, - interface_to_usbdev(desc->intf), - /* using common endpoint 0 */ - usb_sndctrlpipe(interface_to_usbdev(desc->intf), 0), - (unsigned char *)req, - buf, - count, - wdm_out_callback, - desc - ); - - req->bRequestType = (USB_DIR_OUT | USB_TYPE_CLASS | - USB_RECIP_INTERFACE); - req->bRequest = USB_CDC_SEND_ENCAPSULATED_COMMAND; - req->wValue = 0; - req->wIndex = desc->inum; - req->wLength = cpu_to_le16(count); - set_bit(WDM_IN_USE, &desc->flags); - desc->outbuf = buf; - - rv = usb_submit_urb(desc->command, GFP_KERNEL); - if (rv < 0) { - kfree(buf); - desc->outbuf = NULL; - clear_bit(WDM_IN_USE, &desc->flags); - dev_err(&desc->intf->dev, "Tx URB error: %d\n", rv); - } else { - dev_dbg(&desc->intf->dev, "Tx URB has been submitted index=%d", - req->wIndex); - } -out: - usb_autopm_put_interface(desc->intf); -outnp: - mutex_unlock(&desc->wlock); -outnl: - return rv < 0 ? rv : count; -} - -static ssize_t wdm_read -(struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - int rv, cntr; - int i = 0; - struct wdm_device *desc = file->private_data; - - - rv = mutex_lock_interruptible(&desc->rlock); /*concurrent reads */ - if (rv < 0) - return -ERESTARTSYS; - - cntr = ACCESS_ONCE(desc->length); - if (cntr == 0) { - desc->read = 0; -retry: - if (test_bit(WDM_DISCONNECTING, &desc->flags)) { - rv = -ENODEV; - goto err; - } - i++; - if (file->f_flags & O_NONBLOCK) { - if (!test_bit(WDM_READ, &desc->flags)) { - rv = cntr ? cntr : -EAGAIN; - goto err; - } - rv = 0; - } else { - rv = wait_event_interruptible(desc->wait, - test_bit(WDM_READ, &desc->flags)); - } - - /* may have happened while we slept */ - if (test_bit(WDM_DISCONNECTING, &desc->flags)) { - rv = -ENODEV; - goto err; - } - if (test_bit(WDM_RESETTING, &desc->flags)) { - rv = -EIO; - goto err; - } - usb_mark_last_busy(interface_to_usbdev(desc->intf)); - if (rv < 0) { - rv = -ERESTARTSYS; - goto err; - } - - spin_lock_irq(&desc->iuspin); - - if (desc->rerr) { /* read completed, error happened */ - desc->rerr = 0; - spin_unlock_irq(&desc->iuspin); - rv = -EIO; - goto err; - } - /* - * recheck whether we've lost the race - * against the completion handler - */ - if (!test_bit(WDM_READ, &desc->flags)) { /* lost race */ - spin_unlock_irq(&desc->iuspin); - goto retry; - } - if (!desc->reslength) { /* zero length read */ - dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__); - clear_bit(WDM_READ, &desc->flags); - spin_unlock_irq(&desc->iuspin); - goto retry; - } - cntr = desc->length; - spin_unlock_irq(&desc->iuspin); - } - - if (cntr > count) - cntr = count; - rv = copy_to_user(buffer, desc->ubuf, cntr); - if (rv > 0) { - rv = -EFAULT; - goto err; - } - - spin_lock_irq(&desc->iuspin); - - for (i = 0; i < desc->length - cntr; i++) - desc->ubuf[i] = desc->ubuf[i + cntr]; - - desc->length -= cntr; - /* in case we had outstanding data */ - if (!desc->length) - clear_bit(WDM_READ, &desc->flags); - - spin_unlock_irq(&desc->iuspin); - - rv = cntr; - -err: - mutex_unlock(&desc->rlock); - return rv; -} - -static int wdm_flush(struct file *file, fl_owner_t id) -{ - struct wdm_device *desc = file->private_data; - - wait_event(desc->wait, !test_bit(WDM_IN_USE, &desc->flags)); - - /* cannot dereference desc->intf if WDM_DISCONNECTING */ - if (desc->werr < 0 && !test_bit(WDM_DISCONNECTING, &desc->flags)) - dev_err(&desc->intf->dev, "Error in flush path: %d\n", - desc->werr); - - return usb_translate_errors(desc->werr); -} - -static unsigned int wdm_poll(struct file *file, struct poll_table_struct *wait) -{ - struct wdm_device *desc = file->private_data; - unsigned long flags; - unsigned int mask = 0; - - spin_lock_irqsave(&desc->iuspin, flags); - if (test_bit(WDM_DISCONNECTING, &desc->flags)) { - mask = POLLHUP | POLLERR; - spin_unlock_irqrestore(&desc->iuspin, flags); - goto desc_out; - } - if (test_bit(WDM_READ, &desc->flags)) - mask = POLLIN | POLLRDNORM; - if (desc->rerr || desc->werr) - mask |= POLLERR; - if (!test_bit(WDM_IN_USE, &desc->flags)) - mask |= POLLOUT | POLLWRNORM; - spin_unlock_irqrestore(&desc->iuspin, flags); - - poll_wait(file, &desc->wait, wait); - -desc_out: - return mask; -} - -static int wdm_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - int rv = -ENODEV; - struct usb_interface *intf; - struct wdm_device *desc; - - mutex_lock(&wdm_mutex); - desc = wdm_find_device_by_minor(minor); - if (!desc) - goto out; - - intf = desc->intf; - if (test_bit(WDM_DISCONNECTING, &desc->flags)) - goto out; - file->private_data = desc; - - rv = usb_autopm_get_interface(desc->intf); - if (rv < 0) { - dev_err(&desc->intf->dev, "Error autopm - %d\n", rv); - goto out; - } - - /* using write lock to protect desc->count */ - mutex_lock(&desc->wlock); - if (!desc->count++) { - desc->werr = 0; - desc->rerr = 0; - rv = usb_submit_urb(desc->validity, GFP_KERNEL); - if (rv < 0) { - desc->count--; - dev_err(&desc->intf->dev, - "Error submitting int urb - %d\n", rv); - } - } else { - rv = 0; - } - mutex_unlock(&desc->wlock); - if (desc->count == 1) - desc->manage_power(intf, 1); - usb_autopm_put_interface(desc->intf); -out: - mutex_unlock(&wdm_mutex); - return rv; -} - -static int wdm_release(struct inode *inode, struct file *file) -{ - struct wdm_device *desc = file->private_data; - - mutex_lock(&wdm_mutex); - - /* using write lock to protect desc->count */ - mutex_lock(&desc->wlock); - desc->count--; - mutex_unlock(&desc->wlock); - - if (!desc->count) { - if (!test_bit(WDM_DISCONNECTING, &desc->flags)) { - dev_dbg(&desc->intf->dev, "wdm_release: cleanup"); - kill_urbs(desc); - desc->manage_power(desc->intf, 0); - } else { - /* must avoid dev_printk here as desc->intf is invalid */ - pr_debug(KBUILD_MODNAME " %s: device gone - cleaning up\n", __func__); - cleanup(desc); - } - } - mutex_unlock(&wdm_mutex); - return 0; -} - -static const struct file_operations wdm_fops = { - .owner = THIS_MODULE, - .read = wdm_read, - .write = wdm_write, - .open = wdm_open, - .flush = wdm_flush, - .release = wdm_release, - .poll = wdm_poll, - .llseek = noop_llseek, -}; - -static struct usb_class_driver wdm_class = { - .name = "cdc-wdm%d", - .fops = &wdm_fops, - .minor_base = WDM_MINOR_BASE, -}; - -/* --- error handling --- */ -static void wdm_rxwork(struct work_struct *work) -{ - struct wdm_device *desc = container_of(work, struct wdm_device, rxwork); - unsigned long flags; - int rv; - - spin_lock_irqsave(&desc->iuspin, flags); - if (test_bit(WDM_DISCONNECTING, &desc->flags)) { - spin_unlock_irqrestore(&desc->iuspin, flags); - } else { - spin_unlock_irqrestore(&desc->iuspin, flags); - rv = usb_submit_urb(desc->response, GFP_KERNEL); - if (rv < 0 && rv != -EPERM) { - spin_lock_irqsave(&desc->iuspin, flags); - if (!test_bit(WDM_DISCONNECTING, &desc->flags)) - schedule_work(&desc->rxwork); - spin_unlock_irqrestore(&desc->iuspin, flags); - } - } -} - -/* --- hotplug --- */ - -static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor *ep, - u16 bufsize, int (*manage_power)(struct usb_interface *, int)) -{ - int rv = -ENOMEM; - struct wdm_device *desc; - - desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL); - if (!desc) - goto out; - INIT_LIST_HEAD(&desc->device_list); - mutex_init(&desc->rlock); - mutex_init(&desc->wlock); - spin_lock_init(&desc->iuspin); - init_waitqueue_head(&desc->wait); - desc->wMaxCommand = bufsize; - /* this will be expanded and needed in hardware endianness */ - desc->inum = cpu_to_le16((u16)intf->cur_altsetting->desc.bInterfaceNumber); - desc->intf = intf; - INIT_WORK(&desc->rxwork, wdm_rxwork); - - rv = -EINVAL; - if (!usb_endpoint_is_int_in(ep)) - goto err; - - desc->wMaxPacketSize = usb_endpoint_maxp(ep); - - desc->orq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); - if (!desc->orq) - goto err; - desc->irq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); - if (!desc->irq) - goto err; - - desc->validity = usb_alloc_urb(0, GFP_KERNEL); - if (!desc->validity) - goto err; - - desc->response = usb_alloc_urb(0, GFP_KERNEL); - if (!desc->response) - goto err; - - desc->command = usb_alloc_urb(0, GFP_KERNEL); - if (!desc->command) - goto err; - - desc->ubuf = kmalloc(desc->wMaxCommand, GFP_KERNEL); - if (!desc->ubuf) - goto err; - - desc->sbuf = kmalloc(desc->wMaxPacketSize, GFP_KERNEL); - if (!desc->sbuf) - goto err; - - desc->inbuf = kmalloc(desc->wMaxCommand, GFP_KERNEL); - if (!desc->inbuf) - goto err; - - usb_fill_int_urb( - desc->validity, - interface_to_usbdev(intf), - usb_rcvintpipe(interface_to_usbdev(intf), ep->bEndpointAddress), - desc->sbuf, - desc->wMaxPacketSize, - wdm_int_callback, - desc, - ep->bInterval - ); - - desc->irq->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE); - desc->irq->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE; - desc->irq->wValue = 0; - desc->irq->wIndex = desc->inum; - desc->irq->wLength = cpu_to_le16(desc->wMaxCommand); - - usb_fill_control_urb( - desc->response, - interface_to_usbdev(intf), - /* using common endpoint 0 */ - usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0), - (unsigned char *)desc->irq, - desc->inbuf, - desc->wMaxCommand, - wdm_in_callback, - desc - ); - - desc->manage_power = manage_power; - - spin_lock(&wdm_device_list_lock); - list_add(&desc->device_list, &wdm_device_list); - spin_unlock(&wdm_device_list_lock); - - rv = usb_register_dev(intf, &wdm_class); - if (rv < 0) - goto err; - else - dev_info(&intf->dev, "%s: USB WDM device\n", dev_name(intf->usb_dev)); -out: - return rv; -err: - spin_lock(&wdm_device_list_lock); - list_del(&desc->device_list); - spin_unlock(&wdm_device_list_lock); - cleanup(desc); - return rv; -} - -static int wdm_manage_power(struct usb_interface *intf, int on) -{ - /* need autopm_get/put here to ensure the usbcore sees the new value */ - int rv = usb_autopm_get_interface(intf); - if (rv < 0) - goto err; - - intf->needs_remote_wakeup = on; - usb_autopm_put_interface(intf); -err: - return rv; -} - -static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - int rv = -EINVAL; - struct usb_host_interface *iface; - struct usb_endpoint_descriptor *ep; - struct usb_cdc_dmm_desc *dmhd; - u8 *buffer = intf->altsetting->extra; - int buflen = intf->altsetting->extralen; - u16 maxcom = WDM_DEFAULT_BUFSIZE; - - if (!buffer) - goto err; - while (buflen > 2) { - if (buffer[1] != USB_DT_CS_INTERFACE) { - dev_err(&intf->dev, "skipping garbage\n"); - goto next_desc; - } - - switch (buffer[2]) { - case USB_CDC_HEADER_TYPE: - break; - case USB_CDC_DMM_TYPE: - dmhd = (struct usb_cdc_dmm_desc *)buffer; - maxcom = le16_to_cpu(dmhd->wMaxCommand); - dev_dbg(&intf->dev, - "Finding maximum buffer length: %d", maxcom); - break; - default: - dev_err(&intf->dev, - "Ignoring extra header, type %d, length %d\n", - buffer[2], buffer[0]); - break; - } -next_desc: - buflen -= buffer[0]; - buffer += buffer[0]; - } - - iface = intf->cur_altsetting; - if (iface->desc.bNumEndpoints != 1) - goto err; - ep = &iface->endpoint[0].desc; - - rv = wdm_create(intf, ep, maxcom, &wdm_manage_power); - -err: - return rv; -} - -/** - * usb_cdc_wdm_register - register a WDM subdriver - * @intf: usb interface the subdriver will associate with - * @ep: interrupt endpoint to monitor for notifications - * @bufsize: maximum message size to support for read/write - * - * Create WDM usb class character device and associate it with intf - * without binding, allowing another driver to manage the interface. - * - * The subdriver will manage the given interrupt endpoint exclusively - * and will issue control requests referring to the given intf. It - * will otherwise avoid interferring, and in particular not do - * usb_set_intfdata/usb_get_intfdata on intf. - * - * The return value is a pointer to the subdriver's struct usb_driver. - * The registering driver is responsible for calling this subdriver's - * disconnect, suspend, resume, pre_reset and post_reset methods from - * its own. - */ -struct usb_driver *usb_cdc_wdm_register(struct usb_interface *intf, - struct usb_endpoint_descriptor *ep, - int bufsize, - int (*manage_power)(struct usb_interface *, int)) -{ - int rv = -EINVAL; - - rv = wdm_create(intf, ep, bufsize, manage_power); - if (rv < 0) - goto err; - - return &wdm_driver; -err: - return ERR_PTR(rv); -} -EXPORT_SYMBOL(usb_cdc_wdm_register); - -static void wdm_disconnect(struct usb_interface *intf) -{ - struct wdm_device *desc; - unsigned long flags; - - usb_deregister_dev(intf, &wdm_class); - desc = wdm_find_device(intf); - mutex_lock(&wdm_mutex); - - /* the spinlock makes sure no new urbs are generated in the callbacks */ - spin_lock_irqsave(&desc->iuspin, flags); - set_bit(WDM_DISCONNECTING, &desc->flags); - set_bit(WDM_READ, &desc->flags); - /* to terminate pending flushes */ - clear_bit(WDM_IN_USE, &desc->flags); - spin_unlock_irqrestore(&desc->iuspin, flags); - wake_up_all(&desc->wait); - mutex_lock(&desc->rlock); - mutex_lock(&desc->wlock); - kill_urbs(desc); - cancel_work_sync(&desc->rxwork); - mutex_unlock(&desc->wlock); - mutex_unlock(&desc->rlock); - - /* the desc->intf pointer used as list key is now invalid */ - spin_lock(&wdm_device_list_lock); - list_del(&desc->device_list); - spin_unlock(&wdm_device_list_lock); - - if (!desc->count) - cleanup(desc); - mutex_unlock(&wdm_mutex); -} - -#ifdef CONFIG_PM -static int wdm_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct wdm_device *desc = wdm_find_device(intf); - int rv = 0; - - dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor); - - /* if this is an autosuspend the caller does the locking */ - if (!PMSG_IS_AUTO(message)) { - mutex_lock(&desc->rlock); - mutex_lock(&desc->wlock); - } - spin_lock_irq(&desc->iuspin); - - if (PMSG_IS_AUTO(message) && - (test_bit(WDM_IN_USE, &desc->flags) - || test_bit(WDM_RESPONDING, &desc->flags))) { - spin_unlock_irq(&desc->iuspin); - rv = -EBUSY; - } else { - - set_bit(WDM_SUSPENDING, &desc->flags); - spin_unlock_irq(&desc->iuspin); - /* callback submits work - order is essential */ - kill_urbs(desc); - cancel_work_sync(&desc->rxwork); - } - if (!PMSG_IS_AUTO(message)) { - mutex_unlock(&desc->wlock); - mutex_unlock(&desc->rlock); - } - - return rv; -} -#endif - -static int recover_from_urb_loss(struct wdm_device *desc) -{ - int rv = 0; - - if (desc->count) { - rv = usb_submit_urb(desc->validity, GFP_NOIO); - if (rv < 0) - dev_err(&desc->intf->dev, - "Error resume submitting int urb - %d\n", rv); - } - return rv; -} - -#ifdef CONFIG_PM -static int wdm_resume(struct usb_interface *intf) -{ - struct wdm_device *desc = wdm_find_device(intf); - int rv; - - dev_dbg(&desc->intf->dev, "wdm%d_resume\n", intf->minor); - - clear_bit(WDM_SUSPENDING, &desc->flags); - rv = recover_from_urb_loss(desc); - - return rv; -} -#endif - -static int wdm_pre_reset(struct usb_interface *intf) -{ - struct wdm_device *desc = wdm_find_device(intf); - - /* - * we notify everybody using poll of - * an exceptional situation - * must be done before recovery lest a spontaneous - * message from the device is lost - */ - spin_lock_irq(&desc->iuspin); - set_bit(WDM_RESETTING, &desc->flags); /* inform read/write */ - set_bit(WDM_READ, &desc->flags); /* unblock read */ - clear_bit(WDM_IN_USE, &desc->flags); /* unblock write */ - desc->rerr = -EINTR; - spin_unlock_irq(&desc->iuspin); - wake_up_all(&desc->wait); - mutex_lock(&desc->rlock); - mutex_lock(&desc->wlock); - kill_urbs(desc); - cancel_work_sync(&desc->rxwork); - return 0; -} - -static int wdm_post_reset(struct usb_interface *intf) -{ - struct wdm_device *desc = wdm_find_device(intf); - int rv; - - clear_bit(WDM_RESETTING, &desc->flags); - rv = recover_from_urb_loss(desc); - mutex_unlock(&desc->wlock); - mutex_unlock(&desc->rlock); - return 0; -} - -static struct usb_driver wdm_driver = { - .name = "cdc_wdm", - .probe = wdm_probe, - .disconnect = wdm_disconnect, -#ifdef CONFIG_PM - .suspend = wdm_suspend, - .resume = wdm_resume, - .reset_resume = wdm_resume, -#endif - .pre_reset = wdm_pre_reset, - .post_reset = wdm_post_reset, - .id_table = wdm_ids, - .supports_autosuspend = 1, -}; - -module_usb_driver(wdm_driver); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/class/usblp.c b/ANDROID_3.4.5/drivers/usb/class/usblp.c deleted file mode 100644 index a68c1a63..00000000 --- a/ANDROID_3.4.5/drivers/usb/class/usblp.c +++ /dev/null @@ -1,1421 +0,0 @@ -/* - * usblp.c - * - * Copyright (c) 1999 Michael Gee - * Copyright (c) 1999 Pavel Machek - * Copyright (c) 2000 Randy Dunlap - * Copyright (c) 2000 Vojtech Pavlik - # Copyright (c) 2001 Pete Zaitcev - # Copyright (c) 2001 David Paschal - * Copyright (c) 2006 Oliver Neukum - * - * USB Printer Device Class driver for USB printers and printer cables - * - * Sponsored by SuSE - * - * ChangeLog: - * v0.1 - thorough cleaning, URBification, almost a rewrite - * v0.2 - some more cleanups - * v0.3 - cleaner again, waitqueue fixes - * v0.4 - fixes in unidirectional mode - * v0.5 - add DEVICE_ID string support - * v0.6 - never time out - * v0.7 - fixed bulk-IN read and poll (David Paschal) - * v0.8 - add devfs support - * v0.9 - fix unplug-while-open paths - * v0.10- remove sleep_on, fix error on oom (oliver@neukum.org) - * v0.11 - add proto_bias option (Pete Zaitcev) - * v0.12 - add hpoj.sourceforge.net ioctls (David Paschal) - * v0.13 - alloc space for statusbuf ( not on stack); - * use usb_alloc_coherent() for read buf & write buf; - * none - Maintained in Linux kernel after v0.13 - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#undef DEBUG -#include -#include - -/* - * Version Information - */ -#define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap, Pete Zaitcev, David Paschal" -#define DRIVER_DESC "USB Printer Device Class driver" - -#define USBLP_BUF_SIZE 8192 -#define USBLP_BUF_SIZE_IN 1024 -#define USBLP_DEVICE_ID_SIZE 1024 - -/* ioctls: */ -#define IOCNR_GET_DEVICE_ID 1 -#define IOCNR_GET_PROTOCOLS 2 -#define IOCNR_SET_PROTOCOL 3 -#define IOCNR_HP_SET_CHANNEL 4 -#define IOCNR_GET_BUS_ADDRESS 5 -#define IOCNR_GET_VID_PID 6 -#define IOCNR_SOFT_RESET 7 -/* Get device_id string: */ -#define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len) -/* The following ioctls were added for http://hpoj.sourceforge.net: */ -/* Get two-int array: - * [0]=current protocol (1=7/1/1, 2=7/1/2, 3=7/1/3), - * [1]=supported protocol mask (mask&(1<wmut locks wstatus. - * ->mut locks the whole usblp, except [rw]complete, and thus, by indirection, - * [rw]status. We only touch status when we know the side idle. - * ->lock locks what interrupt accesses. - */ -struct usblp { - struct usb_device *dev; /* USB device */ - struct mutex wmut; - struct mutex mut; - spinlock_t lock; /* locks rcomplete, wcomplete */ - char *readbuf; /* read transfer_buffer */ - char *statusbuf; /* status transfer_buffer */ - struct usb_anchor urbs; - wait_queue_head_t rwait, wwait; - int readcount; /* Counter for reads */ - int ifnum; /* Interface number */ - struct usb_interface *intf; /* The interface */ - /* Alternate-setting numbers and endpoints for each protocol - * (7/1/{index=1,2,3}) that the device supports: */ - struct { - int alt_setting; - struct usb_endpoint_descriptor *epwrite; - struct usb_endpoint_descriptor *epread; - } protocol[USBLP_MAX_PROTOCOLS]; - int current_protocol; - int minor; /* minor number of device */ - int wcomplete, rcomplete; - int wstatus; /* bytes written or error */ - int rstatus; /* bytes ready or error */ - unsigned int quirks; /* quirks flags */ - unsigned int flags; /* mode flags */ - unsigned char used; /* True if open */ - unsigned char present; /* True if not disconnected */ - unsigned char bidir; /* interface is bidirectional */ - unsigned char no_paper; /* Paper Out happened */ - unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */ - /* first 2 bytes are (big-endian) length */ -}; - -#ifdef DEBUG -static void usblp_dump(struct usblp *usblp) -{ - int p; - - dbg("usblp=0x%p", usblp); - dbg("dev=0x%p", usblp->dev); - dbg("present=%d", usblp->present); - dbg("readbuf=0x%p", usblp->readbuf); - dbg("readcount=%d", usblp->readcount); - dbg("ifnum=%d", usblp->ifnum); - for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) { - dbg("protocol[%d].alt_setting=%d", p, usblp->protocol[p].alt_setting); - dbg("protocol[%d].epwrite=%p", p, usblp->protocol[p].epwrite); - dbg("protocol[%d].epread=%p", p, usblp->protocol[p].epread); - } - dbg("current_protocol=%d", usblp->current_protocol); - dbg("minor=%d", usblp->minor); - dbg("wstatus=%d", usblp->wstatus); - dbg("rstatus=%d", usblp->rstatus); - dbg("quirks=%d", usblp->quirks); - dbg("used=%d", usblp->used); - dbg("bidir=%d", usblp->bidir); - dbg("device_id_string=\"%s\"", - usblp->device_id_string ? - usblp->device_id_string + 2 : - (unsigned char *)"(null)"); -} -#endif - -/* Quirks: various printer quirks are handled by this table & its flags. */ - -struct quirk_printer_struct { - __u16 vendorId; - __u16 productId; - unsigned int quirks; -}; - -#define USBLP_QUIRK_BIDIR 0x1 /* reports bidir but requires unidirectional mode (no INs/reads) */ -#define USBLP_QUIRK_USB_INIT 0x2 /* needs vendor USB init string */ -#define USBLP_QUIRK_BAD_CLASS 0x4 /* descriptor uses vendor-specific Class or SubClass */ - -static const struct quirk_printer_struct quirk_printers[] = { - { 0x03f0, 0x0004, USBLP_QUIRK_BIDIR }, /* HP DeskJet 895C */ - { 0x03f0, 0x0104, USBLP_QUIRK_BIDIR }, /* HP DeskJet 880C */ - { 0x03f0, 0x0204, USBLP_QUIRK_BIDIR }, /* HP DeskJet 815C */ - { 0x03f0, 0x0304, USBLP_QUIRK_BIDIR }, /* HP DeskJet 810C/812C */ - { 0x03f0, 0x0404, USBLP_QUIRK_BIDIR }, /* HP DeskJet 830C */ - { 0x03f0, 0x0504, USBLP_QUIRK_BIDIR }, /* HP DeskJet 885C */ - { 0x03f0, 0x0604, USBLP_QUIRK_BIDIR }, /* HP DeskJet 840C */ - { 0x03f0, 0x0804, USBLP_QUIRK_BIDIR }, /* HP DeskJet 816C */ - { 0x03f0, 0x1104, USBLP_QUIRK_BIDIR }, /* HP Deskjet 959C */ - { 0x0409, 0xefbe, USBLP_QUIRK_BIDIR }, /* NEC Picty900 (HP OEM) */ - { 0x0409, 0xbef4, USBLP_QUIRK_BIDIR }, /* NEC Picty760 (HP OEM) */ - { 0x0409, 0xf0be, USBLP_QUIRK_BIDIR }, /* NEC Picty920 (HP OEM) */ - { 0x0409, 0xf1be, USBLP_QUIRK_BIDIR }, /* NEC Picty800 (HP OEM) */ - { 0x0482, 0x0010, USBLP_QUIRK_BIDIR }, /* Kyocera Mita FS 820, by zut */ - { 0x04f9, 0x000d, USBLP_QUIRK_BIDIR }, /* Brother Industries, Ltd HL-1440 Laser Printer */ - { 0x04b8, 0x0202, USBLP_QUIRK_BAD_CLASS }, /* Seiko Epson Receipt Printer M129C */ - { 0, 0 } -}; - -static int usblp_wwait(struct usblp *usblp, int nonblock); -static int usblp_wtest(struct usblp *usblp, int nonblock); -static int usblp_rwait_and_lock(struct usblp *usblp, int nonblock); -static int usblp_rtest(struct usblp *usblp, int nonblock); -static int usblp_submit_read(struct usblp *usblp); -static int usblp_select_alts(struct usblp *usblp); -static int usblp_set_protocol(struct usblp *usblp, int protocol); -static int usblp_cache_device_id_string(struct usblp *usblp); - -/* forward reference to make our lives easier */ -static struct usb_driver usblp_driver; -static DEFINE_MUTEX(usblp_mutex); /* locks the existence of usblp's */ - -/* - * Functions for usblp control messages. - */ - -static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, int recip, int value, void *buf, int len) -{ - int retval; - int index = usblp->ifnum; - - /* High byte has the interface index. - Low byte has the alternate setting. - */ - if ((request == USBLP_REQ_GET_ID) && (type == USB_TYPE_CLASS)) - index = (usblp->ifnum<<8)|usblp->protocol[usblp->current_protocol].alt_setting; - - retval = usb_control_msg(usblp->dev, - dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0), - request, type | dir | recip, value, index, buf, len, USBLP_CTL_TIMEOUT); - dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d", - request, !!dir, recip, value, index, len, retval); - return retval < 0 ? retval : 0; -} - -#define usblp_read_status(usblp, status)\ - usblp_ctrl_msg(usblp, USBLP_REQ_GET_STATUS, USB_TYPE_CLASS, USB_DIR_IN, USB_RECIP_INTERFACE, 0, status, 1) -#define usblp_get_id(usblp, config, id, maxlen)\ - usblp_ctrl_msg(usblp, USBLP_REQ_GET_ID, USB_TYPE_CLASS, USB_DIR_IN, USB_RECIP_INTERFACE, config, id, maxlen) -#define usblp_reset(usblp)\ - usblp_ctrl_msg(usblp, USBLP_REQ_RESET, USB_TYPE_CLASS, USB_DIR_OUT, USB_RECIP_OTHER, 0, NULL, 0) - -#define usblp_hp_channel_change_request(usblp, channel, buffer) \ - usblp_ctrl_msg(usblp, USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST, USB_TYPE_VENDOR, USB_DIR_IN, USB_RECIP_INTERFACE, channel, buffer, 1) - -/* - * See the description for usblp_select_alts() below for the usage - * explanation. Look into your /proc/bus/usb/devices and dmesg in - * case of any trouble. - */ -static int proto_bias = -1; - -/* - * URB callback. - */ - -static void usblp_bulk_read(struct urb *urb) -{ - struct usblp *usblp = urb->context; - int status = urb->status; - - if (usblp->present && usblp->used) { - if (status) - printk(KERN_WARNING "usblp%d: " - "nonzero read bulk status received: %d\n", - usblp->minor, status); - } - spin_lock(&usblp->lock); - if (status < 0) - usblp->rstatus = status; - else - usblp->rstatus = urb->actual_length; - usblp->rcomplete = 1; - wake_up(&usblp->rwait); - spin_unlock(&usblp->lock); - - usb_free_urb(urb); -} - -static void usblp_bulk_write(struct urb *urb) -{ - struct usblp *usblp = urb->context; - int status = urb->status; - - if (usblp->present && usblp->used) { - if (status) - printk(KERN_WARNING "usblp%d: " - "nonzero write bulk status received: %d\n", - usblp->minor, status); - } - spin_lock(&usblp->lock); - if (status < 0) - usblp->wstatus = status; - else - usblp->wstatus = urb->actual_length; - usblp->no_paper = 0; - usblp->wcomplete = 1; - wake_up(&usblp->wwait); - spin_unlock(&usblp->lock); - - usb_free_urb(urb); -} - -/* - * Get and print printer errors. - */ - -static const char *usblp_messages[] = { "ok", "out of paper", "off-line", "on fire" }; - -static int usblp_check_status(struct usblp *usblp, int err) -{ - unsigned char status, newerr = 0; - int error; - - mutex_lock(&usblp->mut); - if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) { - mutex_unlock(&usblp->mut); - printk_ratelimited(KERN_ERR - "usblp%d: error %d reading printer status\n", - usblp->minor, error); - return 0; - } - status = *usblp->statusbuf; - mutex_unlock(&usblp->mut); - - if (~status & LP_PERRORP) - newerr = 3; - if (status & LP_POUTPA) - newerr = 1; - if (~status & LP_PSELECD) - newerr = 2; - - if (newerr != err) { - printk(KERN_INFO "usblp%d: %s\n", - usblp->minor, usblp_messages[newerr]); - } - - return newerr; -} - -static int handle_bidir(struct usblp *usblp) -{ - if (usblp->bidir && usblp->used) { - if (usblp_submit_read(usblp) < 0) - return -EIO; - } - return 0; -} - -/* - * File op functions. - */ - -static int usblp_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - struct usblp *usblp; - struct usb_interface *intf; - int retval; - - if (minor < 0) - return -ENODEV; - - mutex_lock(&usblp_mutex); - - retval = -ENODEV; - intf = usb_find_interface(&usblp_driver, minor); - if (!intf) - goto out; - usblp = usb_get_intfdata(intf); - if (!usblp || !usblp->dev || !usblp->present) - goto out; - - retval = -EBUSY; - if (usblp->used) - goto out; - - /* - * We do not implement LP_ABORTOPEN/LPABORTOPEN for two reasons: - * - We do not want persistent state which close(2) does not clear - * - It is not used anyway, according to CUPS people - */ - - retval = usb_autopm_get_interface(intf); - if (retval < 0) - goto out; - usblp->used = 1; - file->private_data = usblp; - - usblp->wcomplete = 1; /* we begin writeable */ - usblp->wstatus = 0; - usblp->rcomplete = 0; - - if (handle_bidir(usblp) < 0) { - usb_autopm_put_interface(intf); - usblp->used = 0; - file->private_data = NULL; - retval = -EIO; - } -out: - mutex_unlock(&usblp_mutex); - return retval; -} - -static void usblp_cleanup(struct usblp *usblp) -{ - printk(KERN_INFO "usblp%d: removed\n", usblp->minor); - - kfree(usblp->readbuf); - kfree(usblp->device_id_string); - kfree(usblp->statusbuf); - kfree(usblp); -} - -static void usblp_unlink_urbs(struct usblp *usblp) -{ - usb_kill_anchored_urbs(&usblp->urbs); -} - -static int usblp_release(struct inode *inode, struct file *file) -{ - struct usblp *usblp = file->private_data; - - usblp->flags &= ~LP_ABORT; - - mutex_lock(&usblp_mutex); - usblp->used = 0; - if (usblp->present) { - usblp_unlink_urbs(usblp); - usb_autopm_put_interface(usblp->intf); - } else /* finish cleanup from disconnect */ - usblp_cleanup(usblp); - mutex_unlock(&usblp_mutex); - return 0; -} - -/* No kernel lock - fine */ -static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait) -{ - int ret; - unsigned long flags; - - struct usblp *usblp = file->private_data; - /* Should we check file->f_mode & FMODE_WRITE before poll_wait()? */ - poll_wait(file, &usblp->rwait, wait); - poll_wait(file, &usblp->wwait, wait); - spin_lock_irqsave(&usblp->lock, flags); - ret = ((usblp->bidir && usblp->rcomplete) ? POLLIN | POLLRDNORM : 0) | - ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0); - spin_unlock_irqrestore(&usblp->lock, flags); - return ret; -} - -static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct usblp *usblp = file->private_data; - int length, err, i; - unsigned char newChannel; - int status; - int twoints[2]; - int retval = 0; - - mutex_lock(&usblp->mut); - if (!usblp->present) { - retval = -ENODEV; - goto done; - } - - dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd), - _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd)); - - if (_IOC_TYPE(cmd) == 'P') /* new-style ioctl number */ - - switch (_IOC_NR(cmd)) { - - case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */ - if (_IOC_DIR(cmd) != _IOC_READ) { - retval = -EINVAL; - goto done; - } - - length = usblp_cache_device_id_string(usblp); - if (length < 0) { - retval = length; - goto done; - } - if (length > _IOC_SIZE(cmd)) - length = _IOC_SIZE(cmd); /* truncate */ - - if (copy_to_user((void __user *) arg, - usblp->device_id_string, - (unsigned long) length)) { - retval = -EFAULT; - goto done; - } - - break; - - case IOCNR_GET_PROTOCOLS: - if (_IOC_DIR(cmd) != _IOC_READ || - _IOC_SIZE(cmd) < sizeof(twoints)) { - retval = -EINVAL; - goto done; - } - - twoints[0] = usblp->current_protocol; - twoints[1] = 0; - for (i = USBLP_FIRST_PROTOCOL; - i <= USBLP_LAST_PROTOCOL; i++) { - if (usblp->protocol[i].alt_setting >= 0) - twoints[1] |= (1<current_protocol); - } - break; - - case IOCNR_HP_SET_CHANNEL: - if (_IOC_DIR(cmd) != _IOC_WRITE || - le16_to_cpu(usblp->dev->descriptor.idVendor) != 0x03F0 || - usblp->quirks & USBLP_QUIRK_BIDIR) { - retval = -EINVAL; - goto done; - } - - err = usblp_hp_channel_change_request(usblp, - arg, &newChannel); - if (err < 0) { - dev_err(&usblp->dev->dev, - "usblp%d: error = %d setting " - "HP channel\n", - usblp->minor, err); - retval = -EIO; - goto done; - } - - dbg("usblp%d requested/got HP channel %ld/%d", - usblp->minor, arg, newChannel); - break; - - case IOCNR_GET_BUS_ADDRESS: - if (_IOC_DIR(cmd) != _IOC_READ || - _IOC_SIZE(cmd) < sizeof(twoints)) { - retval = -EINVAL; - goto done; - } - - twoints[0] = usblp->dev->bus->busnum; - twoints[1] = usblp->dev->devnum; - if (copy_to_user((void __user *)arg, - (unsigned char *)twoints, - sizeof(twoints))) { - retval = -EFAULT; - goto done; - } - - dbg("usblp%d is bus=%d, device=%d", - usblp->minor, twoints[0], twoints[1]); - break; - - case IOCNR_GET_VID_PID: - if (_IOC_DIR(cmd) != _IOC_READ || - _IOC_SIZE(cmd) < sizeof(twoints)) { - retval = -EINVAL; - goto done; - } - - twoints[0] = le16_to_cpu(usblp->dev->descriptor.idVendor); - twoints[1] = le16_to_cpu(usblp->dev->descriptor.idProduct); - if (copy_to_user((void __user *)arg, - (unsigned char *)twoints, - sizeof(twoints))) { - retval = -EFAULT; - goto done; - } - - dbg("usblp%d is VID=0x%4.4X, PID=0x%4.4X", - usblp->minor, twoints[0], twoints[1]); - break; - - case IOCNR_SOFT_RESET: - if (_IOC_DIR(cmd) != _IOC_NONE) { - retval = -EINVAL; - goto done; - } - retval = usblp_reset(usblp); - break; - default: - retval = -ENOTTY; - } - else /* old-style ioctl value */ - switch (cmd) { - - case LPGETSTATUS: - if ((retval = usblp_read_status(usblp, usblp->statusbuf))) { - printk_ratelimited(KERN_ERR "usblp%d:" - "failed reading printer status (%d)\n", - usblp->minor, retval); - retval = -EIO; - goto done; - } - status = *usblp->statusbuf; - if (copy_to_user((void __user *)arg, &status, sizeof(int))) - retval = -EFAULT; - break; - - case LPABORT: - if (arg) - usblp->flags |= LP_ABORT; - else - usblp->flags &= ~LP_ABORT; - break; - - default: - retval = -ENOTTY; - } - -done: - mutex_unlock(&usblp->mut); - return retval; -} - -static struct urb *usblp_new_writeurb(struct usblp *usblp, int transfer_length) -{ - struct urb *urb; - char *writebuf; - - if ((writebuf = kmalloc(transfer_length, GFP_KERNEL)) == NULL) - return NULL; - if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) { - kfree(writebuf); - return NULL; - } - - usb_fill_bulk_urb(urb, usblp->dev, - usb_sndbulkpipe(usblp->dev, - usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress), - writebuf, transfer_length, usblp_bulk_write, usblp); - urb->transfer_flags |= URB_FREE_BUFFER; - - return urb; -} - -static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct usblp *usblp = file->private_data; - struct urb *writeurb; - int rv; - int transfer_length; - ssize_t writecount = 0; - - if (mutex_lock_interruptible(&usblp->wmut)) { - rv = -EINTR; - goto raise_biglock; - } - if ((rv = usblp_wwait(usblp, !!(file->f_flags & O_NONBLOCK))) < 0) - goto raise_wait; - - while (writecount < count) { - /* - * Step 1: Submit next block. - */ - if ((transfer_length = count - writecount) > USBLP_BUF_SIZE) - transfer_length = USBLP_BUF_SIZE; - - rv = -ENOMEM; - if ((writeurb = usblp_new_writeurb(usblp, transfer_length)) == NULL) - goto raise_urb; - usb_anchor_urb(writeurb, &usblp->urbs); - - if (copy_from_user(writeurb->transfer_buffer, - buffer + writecount, transfer_length)) { - rv = -EFAULT; - goto raise_badaddr; - } - - spin_lock_irq(&usblp->lock); - usblp->wcomplete = 0; - spin_unlock_irq(&usblp->lock); - if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) { - usblp->wstatus = 0; - spin_lock_irq(&usblp->lock); - usblp->no_paper = 0; - usblp->wcomplete = 1; - wake_up(&usblp->wwait); - spin_unlock_irq(&usblp->lock); - if (rv != -ENOMEM) - rv = -EIO; - goto raise_submit; - } - - /* - * Step 2: Wait for transfer to end, collect results. - */ - rv = usblp_wwait(usblp, !!(file->f_flags&O_NONBLOCK)); - if (rv < 0) { - if (rv == -EAGAIN) { - /* Presume that it's going to complete well. */ - writecount += transfer_length; - } - if (rv == -ENOSPC) { - spin_lock_irq(&usblp->lock); - usblp->no_paper = 1; /* Mark for poll(2) */ - spin_unlock_irq(&usblp->lock); - writecount += transfer_length; - } - /* Leave URB dangling, to be cleaned on close. */ - goto collect_error; - } - - if (usblp->wstatus < 0) { - rv = -EIO; - goto collect_error; - } - /* - * This is critical: it must be our URB, not other writer's. - * The wmut exists mainly to cover us here. - */ - writecount += usblp->wstatus; - } - - mutex_unlock(&usblp->wmut); - return writecount; - -raise_submit: -raise_badaddr: - usb_unanchor_urb(writeurb); - usb_free_urb(writeurb); -raise_urb: -raise_wait: -collect_error: /* Out of raise sequence */ - mutex_unlock(&usblp->wmut); -raise_biglock: - return writecount ? writecount : rv; -} - -/* - * Notice that we fail to restart in a few cases: on EFAULT, on restart - * error, etc. This is the historical behaviour. In all such cases we return - * EIO, and applications loop in order to get the new read going. - */ -static ssize_t usblp_read(struct file *file, char __user *buffer, size_t len, loff_t *ppos) -{ - struct usblp *usblp = file->private_data; - ssize_t count; - ssize_t avail; - int rv; - - if (!usblp->bidir) - return -EINVAL; - - rv = usblp_rwait_and_lock(usblp, !!(file->f_flags & O_NONBLOCK)); - if (rv < 0) - return rv; - - if ((avail = usblp->rstatus) < 0) { - printk(KERN_ERR "usblp%d: error %d reading from printer\n", - usblp->minor, (int)avail); - usblp_submit_read(usblp); - count = -EIO; - goto done; - } - - count = len < avail - usblp->readcount ? len : avail - usblp->readcount; - if (count != 0 && - copy_to_user(buffer, usblp->readbuf + usblp->readcount, count)) { - count = -EFAULT; - goto done; - } - - if ((usblp->readcount += count) == avail) { - if (usblp_submit_read(usblp) < 0) { - /* We don't want to leak USB return codes into errno. */ - if (count == 0) - count = -EIO; - goto done; - } - } - -done: - mutex_unlock(&usblp->mut); - return count; -} - -/* - * Wait for the write path to come idle. - * This is called under the ->wmut, so the idle path stays idle. - * - * Our write path has a peculiar property: it does not buffer like a tty, - * but waits for the write to succeed. This allows our ->release to bug out - * without waiting for writes to drain. But it obviously does not work - * when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use - * select(2) or poll(2) to wait for the buffer to drain before closing. - * Alternatively, set blocking mode with fcntl and issue a zero-size write. - */ -static int usblp_wwait(struct usblp *usblp, int nonblock) -{ - DECLARE_WAITQUEUE(waita, current); - int rc; - int err = 0; - - add_wait_queue(&usblp->wwait, &waita); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (mutex_lock_interruptible(&usblp->mut)) { - rc = -EINTR; - break; - } - rc = usblp_wtest(usblp, nonblock); - mutex_unlock(&usblp->mut); - if (rc <= 0) - break; - - if (schedule_timeout(msecs_to_jiffies(1500)) == 0) { - if (usblp->flags & LP_ABORT) { - err = usblp_check_status(usblp, err); - if (err == 1) { /* Paper out */ - rc = -ENOSPC; - break; - } - } else { - /* Prod the printer, Gentoo#251237. */ - mutex_lock(&usblp->mut); - usblp_read_status(usblp, usblp->statusbuf); - mutex_unlock(&usblp->mut); - } - } - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&usblp->wwait, &waita); - return rc; -} - -static int usblp_wtest(struct usblp *usblp, int nonblock) -{ - unsigned long flags; - - if (!usblp->present) - return -ENODEV; - if (signal_pending(current)) - return -EINTR; - spin_lock_irqsave(&usblp->lock, flags); - if (usblp->wcomplete) { - spin_unlock_irqrestore(&usblp->lock, flags); - return 0; - } - spin_unlock_irqrestore(&usblp->lock, flags); - if (nonblock) - return -EAGAIN; - return 1; -} - -/* - * Wait for read bytes to become available. This probably should have been - * called usblp_r_lock_and_wait(), because we lock first. But it's a traditional - * name for functions which lock and return. - * - * We do not use wait_event_interruptible because it makes locking iffy. - */ -static int usblp_rwait_and_lock(struct usblp *usblp, int nonblock) -{ - DECLARE_WAITQUEUE(waita, current); - int rc; - - add_wait_queue(&usblp->rwait, &waita); - for (;;) { - if (mutex_lock_interruptible(&usblp->mut)) { - rc = -EINTR; - break; - } - set_current_state(TASK_INTERRUPTIBLE); - if ((rc = usblp_rtest(usblp, nonblock)) < 0) { - mutex_unlock(&usblp->mut); - break; - } - if (rc == 0) /* Keep it locked */ - break; - mutex_unlock(&usblp->mut); - schedule(); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&usblp->rwait, &waita); - return rc; -} - -static int usblp_rtest(struct usblp *usblp, int nonblock) -{ - unsigned long flags; - - if (!usblp->present) - return -ENODEV; - if (signal_pending(current)) - return -EINTR; - spin_lock_irqsave(&usblp->lock, flags); - if (usblp->rcomplete) { - spin_unlock_irqrestore(&usblp->lock, flags); - return 0; - } - spin_unlock_irqrestore(&usblp->lock, flags); - if (nonblock) - return -EAGAIN; - return 1; -} - -/* - * Please check ->bidir and other such things outside for now. - */ -static int usblp_submit_read(struct usblp *usblp) -{ - struct urb *urb; - unsigned long flags; - int rc; - - rc = -ENOMEM; - if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) - goto raise_urb; - - usb_fill_bulk_urb(urb, usblp->dev, - usb_rcvbulkpipe(usblp->dev, - usblp->protocol[usblp->current_protocol].epread->bEndpointAddress), - usblp->readbuf, USBLP_BUF_SIZE_IN, - usblp_bulk_read, usblp); - usb_anchor_urb(urb, &usblp->urbs); - - spin_lock_irqsave(&usblp->lock, flags); - usblp->readcount = 0; /* XXX Why here? */ - usblp->rcomplete = 0; - spin_unlock_irqrestore(&usblp->lock, flags); - if ((rc = usb_submit_urb(urb, GFP_KERNEL)) < 0) { - dbg("error submitting urb (%d)", rc); - spin_lock_irqsave(&usblp->lock, flags); - usblp->rstatus = rc; - usblp->rcomplete = 1; - spin_unlock_irqrestore(&usblp->lock, flags); - goto raise_submit; - } - - return 0; - -raise_submit: - usb_unanchor_urb(urb); - usb_free_urb(urb); -raise_urb: - return rc; -} - -/* - * Checks for printers that have quirks, such as requiring unidirectional - * communication but reporting bidirectional; currently some HP printers - * have this flaw (HP 810, 880, 895, etc.), or needing an init string - * sent at each open (like some Epsons). - * Returns 1 if found, 0 if not found. - * - * HP recommended that we use the bidirectional interface but - * don't attempt any bulk IN transfers from the IN endpoint. - * Here's some more detail on the problem: - * The problem is not that it isn't bidirectional though. The problem - * is that if you request a device ID, or status information, while - * the buffers are full, the return data will end up in the print data - * buffer. For example if you make sure you never request the device ID - * while you are sending print data, and you don't try to query the - * printer status every couple of milliseconds, you will probably be OK. - */ -static unsigned int usblp_quirks(__u16 vendor, __u16 product) -{ - int i; - - for (i = 0; quirk_printers[i].vendorId; i++) { - if (vendor == quirk_printers[i].vendorId && - product == quirk_printers[i].productId) - return quirk_printers[i].quirks; - } - return 0; -} - -static const struct file_operations usblp_fops = { - .owner = THIS_MODULE, - .read = usblp_read, - .write = usblp_write, - .poll = usblp_poll, - .unlocked_ioctl = usblp_ioctl, - .compat_ioctl = usblp_ioctl, - .open = usblp_open, - .release = usblp_release, - .llseek = noop_llseek, -}; - -static char *usblp_devnode(struct device *dev, umode_t *mode) -{ - return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev)); -} - -static struct usb_class_driver usblp_class = { - .name = "lp%d", - .devnode = usblp_devnode, - .fops = &usblp_fops, - .minor_base = USBLP_MINOR_BASE, -}; - -static ssize_t usblp_show_ieee1284_id(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct usblp *usblp = usb_get_intfdata(intf); - - if (usblp->device_id_string[0] == 0 && - usblp->device_id_string[1] == 0) - return 0; - - return sprintf(buf, "%s", usblp->device_id_string+2); -} - -static DEVICE_ATTR(ieee1284_id, S_IRUGO, usblp_show_ieee1284_id, NULL); - -static int usblp_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - struct usblp *usblp; - int protocol; - int retval; - - /* Malloc and start initializing usblp structure so we can use it - * directly. */ - usblp = kzalloc(sizeof(struct usblp), GFP_KERNEL); - if (!usblp) { - retval = -ENOMEM; - goto abort_ret; - } - usblp->dev = dev; - mutex_init(&usblp->wmut); - mutex_init(&usblp->mut); - spin_lock_init(&usblp->lock); - init_waitqueue_head(&usblp->rwait); - init_waitqueue_head(&usblp->wwait); - init_usb_anchor(&usblp->urbs); - usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; - usblp->intf = intf; - - /* Malloc device ID string buffer to the largest expected length, - * since we can re-query it on an ioctl and a dynamic string - * could change in length. */ - if (!(usblp->device_id_string = kmalloc(USBLP_DEVICE_ID_SIZE, GFP_KERNEL))) { - retval = -ENOMEM; - goto abort; - } - - /* - * Allocate read buffer. We somewhat wastefully - * malloc both regardless of bidirectionality, because the - * alternate setting can be changed later via an ioctl. - */ - if (!(usblp->readbuf = kmalloc(USBLP_BUF_SIZE_IN, GFP_KERNEL))) { - retval = -ENOMEM; - goto abort; - } - - /* Allocate buffer for printer status */ - usblp->statusbuf = kmalloc(STATUS_BUF_SIZE, GFP_KERNEL); - if (!usblp->statusbuf) { - retval = -ENOMEM; - goto abort; - } - - /* Lookup quirks for this printer. */ - usblp->quirks = usblp_quirks( - le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct)); - - /* Analyze and pick initial alternate settings and endpoints. */ - protocol = usblp_select_alts(usblp); - if (protocol < 0) { - dbg("incompatible printer-class device 0x%4.4X/0x%4.4X", - le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct)); - retval = -ENODEV; - goto abort; - } - - /* Setup the selected alternate setting and endpoints. */ - if (usblp_set_protocol(usblp, protocol) < 0) { - retval = -ENODEV; /* ->probe isn't ->ioctl */ - goto abort; - } - - /* Retrieve and store the device ID string. */ - usblp_cache_device_id_string(usblp); - retval = device_create_file(&intf->dev, &dev_attr_ieee1284_id); - if (retval) - goto abort_intfdata; - -#ifdef DEBUG - usblp_check_status(usblp, 0); -#endif - - usb_set_intfdata(intf, usblp); - - usblp->present = 1; - - retval = usb_register_dev(intf, &usblp_class); - if (retval) { - printk(KERN_ERR "usblp: Not able to get a minor" - " (base %u, slice default): %d\n", - USBLP_MINOR_BASE, retval); - goto abort_intfdata; - } - usblp->minor = intf->minor; - printk(KERN_INFO "usblp%d: USB %sdirectional printer dev %d " - "if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X\n", - usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum, - usblp->ifnum, - usblp->protocol[usblp->current_protocol].alt_setting, - usblp->current_protocol, - le16_to_cpu(usblp->dev->descriptor.idVendor), - le16_to_cpu(usblp->dev->descriptor.idProduct)); - - return 0; - -abort_intfdata: - usb_set_intfdata(intf, NULL); - device_remove_file(&intf->dev, &dev_attr_ieee1284_id); -abort: - kfree(usblp->readbuf); - kfree(usblp->statusbuf); - kfree(usblp->device_id_string); - kfree(usblp); -abort_ret: - return retval; -} - -/* - * We are a "new" style driver with usb_device_id table, - * but our requirements are too intricate for simple match to handle. - * - * The "proto_bias" option may be used to specify the preferred protocol - * for all USB printers (1=7/1/1, 2=7/1/2, 3=7/1/3). If the device - * supports the preferred protocol, then we bind to it. - * - * The best interface for us is 7/1/2, because it is compatible - * with a stream of characters. If we find it, we bind to it. - * - * Note that the people from hpoj.sourceforge.net need to be able to - * bind to 7/1/3 (MLC/1284.4), so we provide them ioctls for this purpose. - * - * Failing 7/1/2, we look for 7/1/3, even though it's probably not - * stream-compatible, because this matches the behaviour of the old code. - * - * If nothing else, we bind to 7/1/1 - the unidirectional interface. - */ -static int usblp_select_alts(struct usblp *usblp) -{ - struct usb_interface *if_alt; - struct usb_host_interface *ifd; - struct usb_endpoint_descriptor *epd, *epwrite, *epread; - int p, i, e; - - if_alt = usblp->intf; - - for (p = 0; p < USBLP_MAX_PROTOCOLS; p++) - usblp->protocol[p].alt_setting = -1; - - /* Find out what we have. */ - for (i = 0; i < if_alt->num_altsetting; i++) { - ifd = &if_alt->altsetting[i]; - - if (ifd->desc.bInterfaceClass != 7 || ifd->desc.bInterfaceSubClass != 1) - if (!(usblp->quirks & USBLP_QUIRK_BAD_CLASS)) - continue; - - if (ifd->desc.bInterfaceProtocol < USBLP_FIRST_PROTOCOL || - ifd->desc.bInterfaceProtocol > USBLP_LAST_PROTOCOL) - continue; - - /* Look for bulk OUT and IN endpoints. */ - epwrite = epread = NULL; - for (e = 0; e < ifd->desc.bNumEndpoints; e++) { - epd = &ifd->endpoint[e].desc; - - if (usb_endpoint_is_bulk_out(epd)) - if (!epwrite) - epwrite = epd; - - if (usb_endpoint_is_bulk_in(epd)) - if (!epread) - epread = epd; - } - - /* Ignore buggy hardware without the right endpoints. */ - if (!epwrite || (ifd->desc.bInterfaceProtocol > 1 && !epread)) - continue; - - /* Turn off reads for 7/1/1 (unidirectional) interfaces - * and buggy bidirectional printers. */ - if (ifd->desc.bInterfaceProtocol == 1) { - epread = NULL; - } else if (usblp->quirks & USBLP_QUIRK_BIDIR) { - printk(KERN_INFO "usblp%d: Disabling reads from " - "problematic bidirectional printer\n", - usblp->minor); - epread = NULL; - } - - usblp->protocol[ifd->desc.bInterfaceProtocol].alt_setting = - ifd->desc.bAlternateSetting; - usblp->protocol[ifd->desc.bInterfaceProtocol].epwrite = epwrite; - usblp->protocol[ifd->desc.bInterfaceProtocol].epread = epread; - } - - /* If our requested protocol is supported, then use it. */ - if (proto_bias >= USBLP_FIRST_PROTOCOL && - proto_bias <= USBLP_LAST_PROTOCOL && - usblp->protocol[proto_bias].alt_setting != -1) - return proto_bias; - - /* Ordering is important here. */ - if (usblp->protocol[2].alt_setting != -1) - return 2; - if (usblp->protocol[1].alt_setting != -1) - return 1; - if (usblp->protocol[3].alt_setting != -1) - return 3; - - /* If nothing is available, then don't bind to this device. */ - return -1; -} - -static int usblp_set_protocol(struct usblp *usblp, int protocol) -{ - int r, alts; - - if (protocol < USBLP_FIRST_PROTOCOL || protocol > USBLP_LAST_PROTOCOL) - return -EINVAL; - - alts = usblp->protocol[protocol].alt_setting; - if (alts < 0) - return -EINVAL; - r = usb_set_interface(usblp->dev, usblp->ifnum, alts); - if (r < 0) { - printk(KERN_ERR "usblp: can't set desired altsetting %d on interface %d\n", - alts, usblp->ifnum); - return r; - } - - usblp->bidir = (usblp->protocol[protocol].epread != NULL); - usblp->current_protocol = protocol; - dbg("usblp%d set protocol %d", usblp->minor, protocol); - return 0; -} - -/* Retrieves and caches device ID string. - * Returns length, including length bytes but not null terminator. - * On error, returns a negative errno value. */ -static int usblp_cache_device_id_string(struct usblp *usblp) -{ - int err, length; - - err = usblp_get_id(usblp, 0, usblp->device_id_string, USBLP_DEVICE_ID_SIZE - 1); - if (err < 0) { - dbg("usblp%d: error = %d reading IEEE-1284 Device ID string", - usblp->minor, err); - usblp->device_id_string[0] = usblp->device_id_string[1] = '\0'; - return -EIO; - } - - /* First two bytes are length in big-endian. - * They count themselves, and we copy them into - * the user's buffer. */ - length = be16_to_cpu(*((__be16 *)usblp->device_id_string)); - if (length < 2) - length = 2; - else if (length >= USBLP_DEVICE_ID_SIZE) - length = USBLP_DEVICE_ID_SIZE - 1; - usblp->device_id_string[length] = '\0'; - - dbg("usblp%d Device ID string [len=%d]=\"%s\"", - usblp->minor, length, &usblp->device_id_string[2]); - - return length; -} - -static void usblp_disconnect(struct usb_interface *intf) -{ - struct usblp *usblp = usb_get_intfdata(intf); - - usb_deregister_dev(intf, &usblp_class); - - if (!usblp || !usblp->dev) { - dev_err(&intf->dev, "bogus disconnect\n"); - BUG(); - } - - device_remove_file(&intf->dev, &dev_attr_ieee1284_id); - - mutex_lock(&usblp_mutex); - mutex_lock(&usblp->mut); - usblp->present = 0; - wake_up(&usblp->wwait); - wake_up(&usblp->rwait); - usb_set_intfdata(intf, NULL); - - usblp_unlink_urbs(usblp); - mutex_unlock(&usblp->mut); - - if (!usblp->used) - usblp_cleanup(usblp); - mutex_unlock(&usblp_mutex); -} - -static int usblp_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct usblp *usblp = usb_get_intfdata(intf); - - usblp_unlink_urbs(usblp); -#if 0 /* XXX Do we want this? What if someone is reading, should we fail? */ - /* not strictly necessary, but just in case */ - wake_up(&usblp->wwait); - wake_up(&usblp->rwait); -#endif - - return 0; -} - -static int usblp_resume(struct usb_interface *intf) -{ - struct usblp *usblp = usb_get_intfdata(intf); - int r; - - r = handle_bidir(usblp); - - return r; -} - -static const struct usb_device_id usblp_ids[] = { - { USB_DEVICE_INFO(7, 1, 1) }, - { USB_DEVICE_INFO(7, 1, 2) }, - { USB_DEVICE_INFO(7, 1, 3) }, - { USB_INTERFACE_INFO(7, 1, 1) }, - { USB_INTERFACE_INFO(7, 1, 2) }, - { USB_INTERFACE_INFO(7, 1, 3) }, - { USB_DEVICE(0x04b8, 0x0202) }, /* Seiko Epson Receipt Printer M129C */ - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, usblp_ids); - -static struct usb_driver usblp_driver = { - .name = "usblp", - .probe = usblp_probe, - .disconnect = usblp_disconnect, - .suspend = usblp_suspend, - .resume = usblp_resume, - .id_table = usblp_ids, - .supports_autosuspend = 1, -}; - -module_usb_driver(usblp_driver); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -module_param(proto_bias, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(proto_bias, "Favourite protocol number"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/class/usbtmc.c b/ANDROID_3.4.5/drivers/usb/class/usbtmc.c deleted file mode 100644 index 70d69d06..00000000 --- a/ANDROID_3.4.5/drivers/usb/class/usbtmc.c +++ /dev/null @@ -1,1121 +0,0 @@ -/** - * drivers/usb/class/usbtmc.c - USB Test & Measurement class driver - * - * Copyright (C) 2007 Stefan Kopp, Gechingen, Germany - * Copyright (C) 2008 Novell, Inc. - * Copyright (C) 2008 Greg Kroah-Hartman - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * The GNU General Public License is available at - * http://www.gnu.org/copyleft/gpl.html. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#define USBTMC_MINOR_BASE 176 - -/* - * Size of driver internal IO buffer. Must be multiple of 4 and at least as - * large as wMaxPacketSize (which is usually 512 bytes). - */ -#define USBTMC_SIZE_IOBUFFER 2048 - -/* Default USB timeout (in milliseconds) */ -#define USBTMC_TIMEOUT 5000 - -/* - * Maximum number of read cycles to empty bulk in endpoint during CLEAR and - * ABORT_BULK_IN requests. Ends the loop if (for whatever reason) a short - * packet is never read. - */ -#define USBTMC_MAX_READS_TO_CLEAR_BULK_IN 100 - -static const struct usb_device_id usbtmc_devices[] = { - { USB_INTERFACE_INFO(USB_CLASS_APP_SPEC, 3, 0), }, - { USB_INTERFACE_INFO(USB_CLASS_APP_SPEC, 3, 1), }, - { 0, } /* terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, usbtmc_devices); - -/* - * This structure is the capabilities for the device - * See section 4.2.1.8 of the USBTMC specification, - * and section 4.2.2 of the USBTMC usb488 subclass - * specification for details. - */ -struct usbtmc_dev_capabilities { - __u8 interface_capabilities; - __u8 device_capabilities; - __u8 usb488_interface_capabilities; - __u8 usb488_device_capabilities; -}; - -/* This structure holds private data for each USBTMC device. One copy is - * allocated for each USBTMC device in the driver's probe function. - */ -struct usbtmc_device_data { - const struct usb_device_id *id; - struct usb_device *usb_dev; - struct usb_interface *intf; - - unsigned int bulk_in; - unsigned int bulk_out; - - u8 bTag; - u8 bTag_last_write; /* needed for abort */ - u8 bTag_last_read; /* needed for abort */ - - /* attributes from the USB TMC spec for this device */ - u8 TermChar; - bool TermCharEnabled; - bool auto_abort; - - bool zombie; /* fd of disconnected device */ - - struct usbtmc_dev_capabilities capabilities; - struct kref kref; - struct mutex io_mutex; /* only one i/o function running at a time */ -}; -#define to_usbtmc_data(d) container_of(d, struct usbtmc_device_data, kref) - -/* Forward declarations */ -static struct usb_driver usbtmc_driver; - -static void usbtmc_delete(struct kref *kref) -{ - struct usbtmc_device_data *data = to_usbtmc_data(kref); - - usb_put_dev(data->usb_dev); - kfree(data); -} - -static int usbtmc_open(struct inode *inode, struct file *filp) -{ - struct usb_interface *intf; - struct usbtmc_device_data *data; - int retval = 0; - - intf = usb_find_interface(&usbtmc_driver, iminor(inode)); - if (!intf) { - printk(KERN_ERR KBUILD_MODNAME - ": can not find device for minor %d", iminor(inode)); - retval = -ENODEV; - goto exit; - } - - data = usb_get_intfdata(intf); - kref_get(&data->kref); - - /* Store pointer in file structure's private data field */ - filp->private_data = data; - -exit: - return retval; -} - -static int usbtmc_release(struct inode *inode, struct file *file) -{ - struct usbtmc_device_data *data = file->private_data; - - kref_put(&data->kref, usbtmc_delete); - return 0; -} - -static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data) -{ - u8 *buffer; - struct device *dev; - int rv; - int n; - int actual; - struct usb_host_interface *current_setting; - int max_size; - - dev = &data->intf->dev; - buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - rv = usb_control_msg(data->usb_dev, - usb_rcvctrlpipe(data->usb_dev, 0), - USBTMC_REQUEST_INITIATE_ABORT_BULK_IN, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, - data->bTag_last_read, data->bulk_in, - buffer, 2, USBTMC_TIMEOUT); - - if (rv < 0) { - dev_err(dev, "usb_control_msg returned %d\n", rv); - goto exit; - } - - dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]); - - if (buffer[0] == USBTMC_STATUS_FAILED) { - rv = 0; - goto exit; - } - - if (buffer[0] != USBTMC_STATUS_SUCCESS) { - dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n", - buffer[0]); - rv = -EPERM; - goto exit; - } - - max_size = 0; - current_setting = data->intf->cur_altsetting; - for (n = 0; n < current_setting->desc.bNumEndpoints; n++) - if (current_setting->endpoint[n].desc.bEndpointAddress == - data->bulk_in) - max_size = usb_endpoint_maxp(¤t_setting->endpoint[n].desc); - - if (max_size == 0) { - dev_err(dev, "Couldn't get wMaxPacketSize\n"); - rv = -EPERM; - goto exit; - } - - dev_dbg(&data->intf->dev, "wMaxPacketSize is %d\n", max_size); - - n = 0; - - do { - dev_dbg(dev, "Reading from bulk in EP\n"); - - rv = usb_bulk_msg(data->usb_dev, - usb_rcvbulkpipe(data->usb_dev, - data->bulk_in), - buffer, USBTMC_SIZE_IOBUFFER, - &actual, USBTMC_TIMEOUT); - - n++; - - if (rv < 0) { - dev_err(dev, "usb_bulk_msg returned %d\n", rv); - goto exit; - } - } while ((actual == max_size) && - (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)); - - if (actual == max_size) { - dev_err(dev, "Couldn't clear device buffer within %d cycles\n", - USBTMC_MAX_READS_TO_CLEAR_BULK_IN); - rv = -EPERM; - goto exit; - } - - n = 0; - -usbtmc_abort_bulk_in_status: - rv = usb_control_msg(data->usb_dev, - usb_rcvctrlpipe(data->usb_dev, 0), - USBTMC_REQUEST_CHECK_ABORT_BULK_IN_STATUS, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, - 0, data->bulk_in, buffer, 0x08, - USBTMC_TIMEOUT); - - if (rv < 0) { - dev_err(dev, "usb_control_msg returned %d\n", rv); - goto exit; - } - - dev_dbg(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]); - - if (buffer[0] == USBTMC_STATUS_SUCCESS) { - rv = 0; - goto exit; - } - - if (buffer[0] != USBTMC_STATUS_PENDING) { - dev_err(dev, "INITIATE_ABORT_BULK_IN returned %x\n", buffer[0]); - rv = -EPERM; - goto exit; - } - - if (buffer[1] == 1) - do { - dev_dbg(dev, "Reading from bulk in EP\n"); - - rv = usb_bulk_msg(data->usb_dev, - usb_rcvbulkpipe(data->usb_dev, - data->bulk_in), - buffer, USBTMC_SIZE_IOBUFFER, - &actual, USBTMC_TIMEOUT); - - n++; - - if (rv < 0) { - dev_err(dev, "usb_bulk_msg returned %d\n", rv); - goto exit; - } - } while ((actual == max_size) && - (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)); - - if (actual == max_size) { - dev_err(dev, "Couldn't clear device buffer within %d cycles\n", - USBTMC_MAX_READS_TO_CLEAR_BULK_IN); - rv = -EPERM; - goto exit; - } - - goto usbtmc_abort_bulk_in_status; - -exit: - kfree(buffer); - return rv; - -} - -static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data) -{ - struct device *dev; - u8 *buffer; - int rv; - int n; - - dev = &data->intf->dev; - - buffer = kmalloc(8, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - rv = usb_control_msg(data->usb_dev, - usb_rcvctrlpipe(data->usb_dev, 0), - USBTMC_REQUEST_INITIATE_ABORT_BULK_OUT, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, - data->bTag_last_write, data->bulk_out, - buffer, 2, USBTMC_TIMEOUT); - - if (rv < 0) { - dev_err(dev, "usb_control_msg returned %d\n", rv); - goto exit; - } - - dev_dbg(dev, "INITIATE_ABORT_BULK_OUT returned %x\n", buffer[0]); - - if (buffer[0] != USBTMC_STATUS_SUCCESS) { - dev_err(dev, "INITIATE_ABORT_BULK_OUT returned %x\n", - buffer[0]); - rv = -EPERM; - goto exit; - } - - n = 0; - -usbtmc_abort_bulk_out_check_status: - rv = usb_control_msg(data->usb_dev, - usb_rcvctrlpipe(data->usb_dev, 0), - USBTMC_REQUEST_CHECK_ABORT_BULK_OUT_STATUS, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT, - 0, data->bulk_out, buffer, 0x08, - USBTMC_TIMEOUT); - n++; - if (rv < 0) { - dev_err(dev, "usb_control_msg returned %d\n", rv); - goto exit; - } - - dev_dbg(dev, "CHECK_ABORT_BULK_OUT returned %x\n", buffer[0]); - - if (buffer[0] == USBTMC_STATUS_SUCCESS) - goto usbtmc_abort_bulk_out_clear_halt; - - if ((buffer[0] == USBTMC_STATUS_PENDING) && - (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)) - goto usbtmc_abort_bulk_out_check_status; - - rv = -EPERM; - goto exit; - -usbtmc_abort_bulk_out_clear_halt: - rv = usb_clear_halt(data->usb_dev, - usb_sndbulkpipe(data->usb_dev, data->bulk_out)); - - if (rv < 0) { - dev_err(dev, "usb_control_msg returned %d\n", rv); - goto exit; - } - rv = 0; - -exit: - kfree(buffer); - return rv; -} - -static ssize_t usbtmc_read(struct file *filp, char __user *buf, - size_t count, loff_t *f_pos) -{ - struct usbtmc_device_data *data; - struct device *dev; - u32 n_characters; - u8 *buffer; - int actual; - size_t done; - size_t remaining; - int retval; - size_t this_part; - - /* Get pointer to private data structure */ - data = filp->private_data; - dev = &data->intf->dev; - - buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - mutex_lock(&data->io_mutex); - if (data->zombie) { - retval = -ENODEV; - goto exit; - } - - remaining = count; - done = 0; - - while (remaining > 0) { - if (remaining > USBTMC_SIZE_IOBUFFER - 12 - 3) - this_part = USBTMC_SIZE_IOBUFFER - 12 - 3; - else - this_part = remaining; - - /* Setup IO buffer for DEV_DEP_MSG_IN message - * Refer to class specs for details - */ - buffer[0] = 2; - buffer[1] = data->bTag; - buffer[2] = ~(data->bTag); - buffer[3] = 0; /* Reserved */ - buffer[4] = (this_part) & 255; - buffer[5] = ((this_part) >> 8) & 255; - buffer[6] = ((this_part) >> 16) & 255; - buffer[7] = ((this_part) >> 24) & 255; - buffer[8] = data->TermCharEnabled * 2; - /* Use term character? */ - buffer[9] = data->TermChar; - buffer[10] = 0; /* Reserved */ - buffer[11] = 0; /* Reserved */ - - /* Send bulk URB */ - retval = usb_bulk_msg(data->usb_dev, - usb_sndbulkpipe(data->usb_dev, - data->bulk_out), - buffer, 12, &actual, USBTMC_TIMEOUT); - - /* Store bTag (in case we need to abort) */ - data->bTag_last_write = data->bTag; - - /* Increment bTag -- and increment again if zero */ - data->bTag++; - if (!data->bTag) - (data->bTag)++; - - if (retval < 0) { - dev_err(dev, "usb_bulk_msg returned %d\n", retval); - if (data->auto_abort) - usbtmc_ioctl_abort_bulk_out(data); - goto exit; - } - - /* Send bulk URB */ - retval = usb_bulk_msg(data->usb_dev, - usb_rcvbulkpipe(data->usb_dev, - data->bulk_in), - buffer, USBTMC_SIZE_IOBUFFER, &actual, - USBTMC_TIMEOUT); - - /* Store bTag (in case we need to abort) */ - data->bTag_last_read = data->bTag; - - if (retval < 0) { - dev_err(dev, "Unable to read data, error %d\n", retval); - if (data->auto_abort) - usbtmc_ioctl_abort_bulk_in(data); - goto exit; - } - - /* How many characters did the instrument send? */ - n_characters = buffer[4] + - (buffer[5] << 8) + - (buffer[6] << 16) + - (buffer[7] << 24); - - /* Ensure the instrument doesn't lie about it */ - if(n_characters > actual - 12) { - dev_err(dev, "Device lies about message size: %u > %d\n", n_characters, actual - 12); - n_characters = actual - 12; - } - - /* Ensure the instrument doesn't send more back than requested */ - if(n_characters > this_part) { - dev_err(dev, "Device returns more than requested: %zu > %zu\n", done + n_characters, done + this_part); - n_characters = this_part; - } - - /* Bound amount of data received by amount of data requested */ - if (n_characters > this_part) - n_characters = this_part; - - /* Copy buffer to user space */ - if (copy_to_user(buf + done, &buffer[12], n_characters)) { - /* There must have been an addressing problem */ - retval = -EFAULT; - goto exit; - } - - done += n_characters; - /* Terminate if end-of-message bit received from device */ - if ((buffer[8] & 0x01) && (actual >= n_characters + 12)) - remaining = 0; - else - remaining -= n_characters; - } - - /* Update file position value */ - *f_pos = *f_pos + done; - retval = done; - -exit: - mutex_unlock(&data->io_mutex); - kfree(buffer); - return retval; -} - -static ssize_t usbtmc_write(struct file *filp, const char __user *buf, - size_t count, loff_t *f_pos) -{ - struct usbtmc_device_data *data; - u8 *buffer; - int retval; - int actual; - unsigned long int n_bytes; - int remaining; - int done; - int this_part; - - data = filp->private_data; - - buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - mutex_lock(&data->io_mutex); - if (data->zombie) { - retval = -ENODEV; - goto exit; - } - - remaining = count; - done = 0; - - while (remaining > 0) { - if (remaining > USBTMC_SIZE_IOBUFFER - 12) { - this_part = USBTMC_SIZE_IOBUFFER - 12; - buffer[8] = 0; - } else { - this_part = remaining; - buffer[8] = 1; - } - - /* Setup IO buffer for DEV_DEP_MSG_OUT message */ - buffer[0] = 1; - buffer[1] = data->bTag; - buffer[2] = ~(data->bTag); - buffer[3] = 0; /* Reserved */ - buffer[4] = this_part & 255; - buffer[5] = (this_part >> 8) & 255; - buffer[6] = (this_part >> 16) & 255; - buffer[7] = (this_part >> 24) & 255; - /* buffer[8] is set above... */ - buffer[9] = 0; /* Reserved */ - buffer[10] = 0; /* Reserved */ - buffer[11] = 0; /* Reserved */ - - if (copy_from_user(&buffer[12], buf + done, this_part)) { - retval = -EFAULT; - goto exit; - } - - n_bytes = roundup(12 + this_part, 4); - memset(buffer + 12 + this_part, 0, n_bytes - (12 + this_part)); - - do { - retval = usb_bulk_msg(data->usb_dev, - usb_sndbulkpipe(data->usb_dev, - data->bulk_out), - buffer, n_bytes, - &actual, USBTMC_TIMEOUT); - if (retval != 0) - break; - n_bytes -= actual; - } while (n_bytes); - - data->bTag_last_write = data->bTag; - data->bTag++; - - if (!data->bTag) - data->bTag++; - - if (retval < 0) { - dev_err(&data->intf->dev, - "Unable to send data, error %d\n", retval); - if (data->auto_abort) - usbtmc_ioctl_abort_bulk_out(data); - goto exit; - } - - remaining -= this_part; - done += this_part; - } - - retval = count; -exit: - mutex_unlock(&data->io_mutex); - kfree(buffer); - return retval; -} - -static int usbtmc_ioctl_clear(struct usbtmc_device_data *data) -{ - struct usb_host_interface *current_setting; - struct usb_endpoint_descriptor *desc; - struct device *dev; - u8 *buffer; - int rv; - int n; - int actual; - int max_size; - - dev = &data->intf->dev; - - dev_dbg(dev, "Sending INITIATE_CLEAR request\n"); - - buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - rv = usb_control_msg(data->usb_dev, - usb_rcvctrlpipe(data->usb_dev, 0), - USBTMC_REQUEST_INITIATE_CLEAR, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, 0, buffer, 1, USBTMC_TIMEOUT); - if (rv < 0) { - dev_err(dev, "usb_control_msg returned %d\n", rv); - goto exit; - } - - dev_dbg(dev, "INITIATE_CLEAR returned %x\n", buffer[0]); - - if (buffer[0] != USBTMC_STATUS_SUCCESS) { - dev_err(dev, "INITIATE_CLEAR returned %x\n", buffer[0]); - rv = -EPERM; - goto exit; - } - - max_size = 0; - current_setting = data->intf->cur_altsetting; - for (n = 0; n < current_setting->desc.bNumEndpoints; n++) { - desc = ¤t_setting->endpoint[n].desc; - if (desc->bEndpointAddress == data->bulk_in) - max_size = usb_endpoint_maxp(desc); - } - - if (max_size == 0) { - dev_err(dev, "Couldn't get wMaxPacketSize\n"); - rv = -EPERM; - goto exit; - } - - dev_dbg(dev, "wMaxPacketSize is %d\n", max_size); - - n = 0; - -usbtmc_clear_check_status: - - dev_dbg(dev, "Sending CHECK_CLEAR_STATUS request\n"); - - rv = usb_control_msg(data->usb_dev, - usb_rcvctrlpipe(data->usb_dev, 0), - USBTMC_REQUEST_CHECK_CLEAR_STATUS, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, 0, buffer, 2, USBTMC_TIMEOUT); - if (rv < 0) { - dev_err(dev, "usb_control_msg returned %d\n", rv); - goto exit; - } - - dev_dbg(dev, "CHECK_CLEAR_STATUS returned %x\n", buffer[0]); - - if (buffer[0] == USBTMC_STATUS_SUCCESS) - goto usbtmc_clear_bulk_out_halt; - - if (buffer[0] != USBTMC_STATUS_PENDING) { - dev_err(dev, "CHECK_CLEAR_STATUS returned %x\n", buffer[0]); - rv = -EPERM; - goto exit; - } - - if (buffer[1] == 1) - do { - dev_dbg(dev, "Reading from bulk in EP\n"); - - rv = usb_bulk_msg(data->usb_dev, - usb_rcvbulkpipe(data->usb_dev, - data->bulk_in), - buffer, USBTMC_SIZE_IOBUFFER, - &actual, USBTMC_TIMEOUT); - n++; - - if (rv < 0) { - dev_err(dev, "usb_control_msg returned %d\n", - rv); - goto exit; - } - } while ((actual == max_size) && - (n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN)); - - if (actual == max_size) { - dev_err(dev, "Couldn't clear device buffer within %d cycles\n", - USBTMC_MAX_READS_TO_CLEAR_BULK_IN); - rv = -EPERM; - goto exit; - } - - goto usbtmc_clear_check_status; - -usbtmc_clear_bulk_out_halt: - - rv = usb_clear_halt(data->usb_dev, - usb_sndbulkpipe(data->usb_dev, data->bulk_out)); - if (rv < 0) { - dev_err(dev, "usb_control_msg returned %d\n", rv); - goto exit; - } - rv = 0; - -exit: - kfree(buffer); - return rv; -} - -static int usbtmc_ioctl_clear_out_halt(struct usbtmc_device_data *data) -{ - u8 *buffer; - int rv; - - buffer = kmalloc(2, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - rv = usb_clear_halt(data->usb_dev, - usb_sndbulkpipe(data->usb_dev, data->bulk_out)); - - if (rv < 0) { - dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n", - rv); - goto exit; - } - rv = 0; - -exit: - kfree(buffer); - return rv; -} - -static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data) -{ - u8 *buffer; - int rv; - - buffer = kmalloc(2, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - rv = usb_clear_halt(data->usb_dev, - usb_rcvbulkpipe(data->usb_dev, data->bulk_in)); - - if (rv < 0) { - dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n", - rv); - goto exit; - } - rv = 0; - -exit: - kfree(buffer); - return rv; -} - -static int get_capabilities(struct usbtmc_device_data *data) -{ - struct device *dev = &data->usb_dev->dev; - char *buffer; - int rv = 0; - - buffer = kmalloc(0x18, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - rv = usb_control_msg(data->usb_dev, usb_rcvctrlpipe(data->usb_dev, 0), - USBTMC_REQUEST_GET_CAPABILITIES, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, 0, buffer, 0x18, USBTMC_TIMEOUT); - if (rv < 0) { - dev_err(dev, "usb_control_msg returned %d\n", rv); - goto err_out; - } - - dev_dbg(dev, "GET_CAPABILITIES returned %x\n", buffer[0]); - if (buffer[0] != USBTMC_STATUS_SUCCESS) { - dev_err(dev, "GET_CAPABILITIES returned %x\n", buffer[0]); - rv = -EPERM; - goto err_out; - } - dev_dbg(dev, "Interface capabilities are %x\n", buffer[4]); - dev_dbg(dev, "Device capabilities are %x\n", buffer[5]); - dev_dbg(dev, "USB488 interface capabilities are %x\n", buffer[14]); - dev_dbg(dev, "USB488 device capabilities are %x\n", buffer[15]); - - data->capabilities.interface_capabilities = buffer[4]; - data->capabilities.device_capabilities = buffer[5]; - data->capabilities.usb488_interface_capabilities = buffer[14]; - data->capabilities.usb488_device_capabilities = buffer[15]; - rv = 0; - -err_out: - kfree(buffer); - return rv; -} - -#define capability_attribute(name) \ -static ssize_t show_##name(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct usb_interface *intf = to_usb_interface(dev); \ - struct usbtmc_device_data *data = usb_get_intfdata(intf); \ - \ - return sprintf(buf, "%d\n", data->capabilities.name); \ -} \ -static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) - -capability_attribute(interface_capabilities); -capability_attribute(device_capabilities); -capability_attribute(usb488_interface_capabilities); -capability_attribute(usb488_device_capabilities); - -static struct attribute *capability_attrs[] = { - &dev_attr_interface_capabilities.attr, - &dev_attr_device_capabilities.attr, - &dev_attr_usb488_interface_capabilities.attr, - &dev_attr_usb488_device_capabilities.attr, - NULL, -}; - -static struct attribute_group capability_attr_grp = { - .attrs = capability_attrs, -}; - -static ssize_t show_TermChar(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct usbtmc_device_data *data = usb_get_intfdata(intf); - - return sprintf(buf, "%c\n", data->TermChar); -} - -static ssize_t store_TermChar(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct usbtmc_device_data *data = usb_get_intfdata(intf); - - if (count < 1) - return -EINVAL; - data->TermChar = buf[0]; - return count; -} -static DEVICE_ATTR(TermChar, S_IRUGO, show_TermChar, store_TermChar); - -#define data_attribute(name) \ -static ssize_t show_##name(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct usb_interface *intf = to_usb_interface(dev); \ - struct usbtmc_device_data *data = usb_get_intfdata(intf); \ - \ - return sprintf(buf, "%d\n", data->name); \ -} \ -static ssize_t store_##name(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct usb_interface *intf = to_usb_interface(dev); \ - struct usbtmc_device_data *data = usb_get_intfdata(intf); \ - ssize_t result; \ - unsigned val; \ - \ - result = sscanf(buf, "%u\n", &val); \ - if (result != 1) \ - result = -EINVAL; \ - data->name = val; \ - if (result < 0) \ - return result; \ - else \ - return count; \ -} \ -static DEVICE_ATTR(name, S_IRUGO, show_##name, store_##name) - -data_attribute(TermCharEnabled); -data_attribute(auto_abort); - -static struct attribute *data_attrs[] = { - &dev_attr_TermChar.attr, - &dev_attr_TermCharEnabled.attr, - &dev_attr_auto_abort.attr, - NULL, -}; - -static struct attribute_group data_attr_grp = { - .attrs = data_attrs, -}; - -static int usbtmc_ioctl_indicator_pulse(struct usbtmc_device_data *data) -{ - struct device *dev; - u8 *buffer; - int rv; - - dev = &data->intf->dev; - - buffer = kmalloc(2, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - rv = usb_control_msg(data->usb_dev, - usb_rcvctrlpipe(data->usb_dev, 0), - USBTMC_REQUEST_INDICATOR_PULSE, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, 0, buffer, 0x01, USBTMC_TIMEOUT); - - if (rv < 0) { - dev_err(dev, "usb_control_msg returned %d\n", rv); - goto exit; - } - - dev_dbg(dev, "INDICATOR_PULSE returned %x\n", buffer[0]); - - if (buffer[0] != USBTMC_STATUS_SUCCESS) { - dev_err(dev, "INDICATOR_PULSE returned %x\n", buffer[0]); - rv = -EPERM; - goto exit; - } - rv = 0; - -exit: - kfree(buffer); - return rv; -} - -static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct usbtmc_device_data *data; - int retval = -EBADRQC; - - data = file->private_data; - mutex_lock(&data->io_mutex); - if (data->zombie) { - retval = -ENODEV; - goto skip_io_on_zombie; - } - - 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; - } - -skip_io_on_zombie: - mutex_unlock(&data->io_mutex); - return retval; -} - -static const struct file_operations fops = { - .owner = THIS_MODULE, - .read = usbtmc_read, - .write = usbtmc_write, - .open = usbtmc_open, - .release = usbtmc_release, - .unlocked_ioctl = usbtmc_ioctl, - .llseek = default_llseek, -}; - -static struct usb_class_driver usbtmc_class = { - .name = "usbtmc%d", - .fops = &fops, - .minor_base = USBTMC_MINOR_BASE, -}; - - -static int usbtmc_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usbtmc_device_data *data; - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - int n; - int retcode; - - dev_dbg(&intf->dev, "%s called\n", __func__); - - data = kmalloc(sizeof(struct usbtmc_device_data), GFP_KERNEL); - if (!data) { - dev_err(&intf->dev, "Unable to allocate kernel memory\n"); - return -ENOMEM; - } - - data->intf = intf; - data->id = id; - data->usb_dev = usb_get_dev(interface_to_usbdev(intf)); - usb_set_intfdata(intf, data); - kref_init(&data->kref); - mutex_init(&data->io_mutex); - data->zombie = 0; - - /* Initialize USBTMC bTag and other fields */ - data->bTag = 1; - data->TermCharEnabled = 0; - data->TermChar = '\n'; - - /* USBTMC devices have only one setting, so use that */ - iface_desc = data->intf->cur_altsetting; - - /* Find bulk in endpoint */ - for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) { - endpoint = &iface_desc->endpoint[n].desc; - - if (usb_endpoint_is_bulk_in(endpoint)) { - data->bulk_in = endpoint->bEndpointAddress; - dev_dbg(&intf->dev, "Found bulk in endpoint at %u\n", - data->bulk_in); - break; - } - } - - /* Find bulk out endpoint */ - for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) { - endpoint = &iface_desc->endpoint[n].desc; - - if (usb_endpoint_is_bulk_out(endpoint)) { - data->bulk_out = endpoint->bEndpointAddress; - dev_dbg(&intf->dev, "Found Bulk out endpoint at %u\n", - data->bulk_out); - break; - } - } - - retcode = get_capabilities(data); - if (retcode) - dev_err(&intf->dev, "can't read capabilities\n"); - else - retcode = sysfs_create_group(&intf->dev.kobj, - &capability_attr_grp); - - retcode = sysfs_create_group(&intf->dev.kobj, &data_attr_grp); - - retcode = usb_register_dev(intf, &usbtmc_class); - if (retcode) { - dev_err(&intf->dev, "Not able to get a minor" - " (base %u, slice default): %d\n", USBTMC_MINOR_BASE, - retcode); - goto error_register; - } - dev_dbg(&intf->dev, "Using minor number %d\n", intf->minor); - - return 0; - -error_register: - sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp); - sysfs_remove_group(&intf->dev.kobj, &data_attr_grp); - kref_put(&data->kref, usbtmc_delete); - return retcode; -} - -static void usbtmc_disconnect(struct usb_interface *intf) -{ - struct usbtmc_device_data *data; - - dev_dbg(&intf->dev, "usbtmc_disconnect called\n"); - - data = usb_get_intfdata(intf); - usb_deregister_dev(intf, &usbtmc_class); - sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp); - sysfs_remove_group(&intf->dev.kobj, &data_attr_grp); - mutex_lock(&data->io_mutex); - data->zombie = 1; - mutex_unlock(&data->io_mutex); - kref_put(&data->kref, usbtmc_delete); -} - -static int usbtmc_suspend(struct usb_interface *intf, pm_message_t message) -{ - /* this driver does not have pending URBs */ - return 0; -} - -static int usbtmc_resume(struct usb_interface *intf) -{ - return 0; -} - -static struct usb_driver usbtmc_driver = { - .name = "usbtmc", - .id_table = usbtmc_devices, - .probe = usbtmc_probe, - .disconnect = usbtmc_disconnect, - .suspend = usbtmc_suspend, - .resume = usbtmc_resume, -}; - -module_usb_driver(usbtmc_driver); - -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/core/Kconfig b/ANDROID_3.4.5/drivers/usb/core/Kconfig deleted file mode 100644 index 18d02e32..00000000 --- a/ANDROID_3.4.5/drivers/usb/core/Kconfig +++ /dev/null @@ -1,150 +0,0 @@ -# -# USB Core configuration -# -config USB_DEBUG - bool "USB verbose debug messages" - depends on USB - help - Say Y here if you want the USB core & hub drivers to produce a bunch - of debug messages to the system log. Select this if you are having a - problem with USB support and want to see more of what is going on. - -config USB_ANNOUNCE_NEW_DEVICES - bool "USB announce new devices" - depends on USB - default N - help - Say Y here if you want the USB core to always announce the - idVendor, idProduct, Manufacturer, Product, and SerialNumber - strings for every new USB device to the syslog. This option is - usually used by distro vendors to help with debugging and to - let users know what specific device was added to the machine - in what location. - - If you do not want this kind of information sent to the system - log, or have any doubts about this, say N here. - -comment "Miscellaneous USB options" - depends on USB - -config USB_DEVICEFS - bool "USB device filesystem (DEPRECATED)" - depends on USB - ---help--- - If you say Y here (and to "/proc file system support" in the "File - systems" section, above), you will get a file /proc/bus/usb/devices - which lists the devices currently connected to your USB bus or - busses, and for every connected device a file named - "/proc/bus/usb/xxx/yyy", where xxx is the bus number and yyy the - device number; the latter files can be used by user space programs - to talk directly to the device. These files are "virtual", meaning - they are generated on the fly and not stored on the hard drive. - - You may need to mount the usbfs file system to see the files, use - mount -t usbfs none /proc/bus/usb - - For the format of the various /proc/bus/usb/ files, please read - . - - 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)" - depends on USB - default y - ---help--- - Userspace access to USB devices is granted by device-nodes exported - directly from the usbdev in sysfs. Old versions of the driver - core and udev needed additional class devices to export device nodes. - - These additional devices are difficult to handle in userspace, if - information about USB interfaces must be available. One device - contains the device node, the other device contains the interface - data. Both devices are at the same level in sysfs (siblings) and one - can't access the other. The device node created directly by the - usb device is the parent device of the interface and therefore - easily accessible from the interface event. - - This option provides backward compatibility for libusb device - nodes (lsusb) when usbfs is not used, and the following udev rule - doesn't exist: - SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", \ - NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644" - -config USB_DYNAMIC_MINORS - bool "Dynamic USB minor allocation" - depends on USB - help - If you say Y here, the USB subsystem will use dynamic minor - allocation for any device that uses the USB major number. - This means that you can have more than 16 of a single type - of device (like USB printers). - - If you are unsure about this, say N here. - -config USB_SUSPEND - bool "USB runtime power management (autosuspend) and wakeup" - depends on USB && PM_RUNTIME - help - If you say Y here, you can use driver calls or the sysfs - "power/control" file to enable or disable autosuspend for - individual USB peripherals (see - Documentation/usb/power-management.txt for more details). - - Also, USB "remote wakeup" signaling is supported, whereby some - USB devices (like keyboards and network adapters) can wake up - their parent hub. That wakeup cascades up the USB tree, and - could wake the system from states like suspend-to-RAM. - - If you are unsure about this, say N here. - -config USB_OTG - bool "OTG support" - depends on USB && EXPERIMENTAL - depends on USB_SUSPEND - default n - help - The most notable feature of USB OTG is support for a - "Dual-Role" device, which can act as either a device - or a host. The initial role is decided by the type of - plug inserted and can be changed later when two dual - role devices talk to each other. - - Select this only if your board has Mini-AB/Micro-AB - connector. - -config USB_OTG_WHITELIST - bool "Rely on OTG Targeted Peripherals List" - depends on USB_OTG || EXPERT - default y if USB_OTG - default n if EXPERT - help - If you say Y here, the "otg_whitelist.h" file will be used as a - product whitelist, so USB peripherals not listed there will be - rejected during enumeration. This behavior is required by the - USB OTG specification for all devices not on your product's - "Targeted Peripherals List". "Embedded Hosts" are likewise - allowed to support only a limited number of peripherals. - - Otherwise, peripherals not listed there will only generate a - warning and enumeration will continue. That's more like what - normal Linux-USB hosts do (other than the warning), and is - convenient for many stages of product development. - -config USB_OTG_BLACKLIST_HUB - bool "Disable external hubs" - depends on USB_OTG || EXPERT - help - If you say Y here, then Linux will refuse to enumerate - external hubs. OTG hosts are allowed to reduce hardware - and software costs by not supporting external hubs. So - are "Embedded Hosts" that don't offer OTG support. - diff --git a/ANDROID_3.4.5/drivers/usb/core/Makefile b/ANDROID_3.4.5/drivers/usb/core/Makefile deleted file mode 100644 index 507a4e1b..00000000 --- a/ANDROID_3.4.5/drivers/usb/core/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# -# Makefile for USB Core files and filesystem -# - -ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG - -usbcore-y := usb.o hub.o hcd.o urb.o message.o driver.o -usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o -usbcore-y += devio.o notify.o generic.o quirks.o devices.o - -usbcore-$(CONFIG_PCI) += hcd-pci.o -usbcore-$(CONFIG_USB_DEVICEFS) += inode.o - -obj-$(CONFIG_USB) += usbcore.o diff --git a/ANDROID_3.4.5/drivers/usb/core/buffer.c b/ANDROID_3.4.5/drivers/usb/core/buffer.c deleted file mode 100644 index b0585e62..00000000 --- a/ANDROID_3.4.5/drivers/usb/core/buffer.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * DMA memory management for framework level HCD code (hc_driver) - * - * This implementation plugs in through generic "usb_bus" level methods, - * and should work with all USB controllers, regardles of bus type. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* - * DMA-Coherent Buffers - */ - -/* FIXME tune these based on pool statistics ... */ -static const size_t pool_max[HCD_BUFFER_POOLS] = { - /* platforms without dma-friendly caches might need to - * prevent cacheline sharing... - */ - 32, - 128, - 512, - PAGE_SIZE / 2 - /* bigger --> allocate pages */ -}; - - -/* SETUP primitives */ - -/** - * hcd_buffer_create - initialize buffer pools - * @hcd: the bus whose buffer pools are to be initialized - * Context: !in_interrupt() - * - * Call this as part of initializing a host controller that uses the dma - * memory allocators. It initializes some pools of dma-coherent memory that - * will be shared by all drivers using that controller, or returns a negative - * errno value on error. - * - * Call hcd_buffer_destroy() to clean up after using those pools. - */ -int hcd_buffer_create(struct usb_hcd *hcd) -{ - char name[16]; - int i, size; - - if (!hcd->self.controller->dma_mask && - !(hcd->driver->flags & HCD_LOCAL_MEM)) - return 0; - - for (i = 0; i < HCD_BUFFER_POOLS; i++) { - size = pool_max[i]; - if (!size) - continue; - snprintf(name, sizeof name, "buffer-%d", size); - hcd->pool[i] = dma_pool_create(name, hcd->self.controller, - size, size, 0); - if (!hcd->pool[i]) { - hcd_buffer_destroy(hcd); - return -ENOMEM; - } - } - return 0; -} - - -/** - * hcd_buffer_destroy - deallocate buffer pools - * @hcd: the bus whose buffer pools are to be destroyed - * Context: !in_interrupt() - * - * This frees the buffer pools created by hcd_buffer_create(). - */ -void hcd_buffer_destroy(struct usb_hcd *hcd) -{ - int i; - - for (i = 0; i < HCD_BUFFER_POOLS; i++) { - struct dma_pool *pool = hcd->pool[i]; - if (pool) { - dma_pool_destroy(pool); - hcd->pool[i] = NULL; - } - } -} - - -/* sometimes alloc/free could use kmalloc with GFP_DMA, for - * better sharing and to leverage mm/slab.c intelligence. - */ - -void *hcd_buffer_alloc( - struct usb_bus *bus, - size_t size, - gfp_t mem_flags, - dma_addr_t *dma -) -{ - struct usb_hcd *hcd = bus_to_hcd(bus); - int i; - - /* some USB hosts just use PIO */ - if (!bus->controller->dma_mask && - !(hcd->driver->flags & HCD_LOCAL_MEM)) { - *dma = ~(dma_addr_t) 0; - return kmalloc(size, mem_flags); - } - - for (i = 0; i < HCD_BUFFER_POOLS; i++) { - if (size <= pool_max[i]) - return dma_pool_alloc(hcd->pool[i], mem_flags, dma); - } - return dma_alloc_coherent(hcd->self.controller, size, dma, mem_flags); -} - -void hcd_buffer_free( - struct usb_bus *bus, - size_t size, - void *addr, - dma_addr_t dma -) -{ - struct usb_hcd *hcd = bus_to_hcd(bus); - int i; - - if (!addr) - return; - - if (!bus->controller->dma_mask && - !(hcd->driver->flags & HCD_LOCAL_MEM)) { - kfree(addr); - return; - } - - for (i = 0; i < HCD_BUFFER_POOLS; i++) { - if (size <= pool_max[i]) { - dma_pool_free(hcd->pool[i], addr, dma); - return; - } - } - dma_free_coherent(hcd->self.controller, size, addr, dma); -} diff --git a/ANDROID_3.4.5/drivers/usb/core/config.c b/ANDROID_3.4.5/drivers/usb/core/config.c deleted file mode 100644 index f4bdd0ce..00000000 --- a/ANDROID_3.4.5/drivers/usb/core/config.c +++ /dev/null @@ -1,860 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "usb.h" - - -#define USB_MAXALTSETTING 128 /* Hard limit */ -#define USB_MAXENDPOINTS 30 /* Hard limit */ - -#define USB_MAXCONFIG 8 /* Arbitrary limit */ - - -static inline const char *plural(int n) -{ - return (n == 1 ? "" : "s"); -} - -static int find_next_descriptor(unsigned char *buffer, int size, - int dt1, int dt2, int *num_skipped) -{ - struct usb_descriptor_header *h; - int n = 0; - unsigned char *buffer0 = buffer; - - /* Find the next descriptor of type dt1 or dt2 */ - while (size > 0) { - h = (struct usb_descriptor_header *) buffer; - if (h->bDescriptorType == dt1 || h->bDescriptorType == dt2) - 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 void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno, - int inum, int asnum, struct usb_host_endpoint *ep, - unsigned char *buffer, int size) -{ - struct usb_ss_ep_comp_descriptor *desc; - int max_tx; - - /* The SuperSpeed endpoint companion descriptor is supposed to - * be the first thing immediately following the endpoint descriptor. - */ - desc = (struct usb_ss_ep_comp_descriptor *) buffer; - if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP || - size < USB_DT_SS_EP_COMP_SIZE) { - 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); - - /* Fill in some default values. - * 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. - */ - ep->ss_ep_comp.bLength = USB_DT_SS_EP_COMP_SIZE; - ep->ss_ep_comp.bDescriptorType = USB_DT_SS_ENDPOINT_COMP; - if (usb_endpoint_xfer_isoc(&ep->desc) || - usb_endpoint_xfer_int(&ep->desc)) - ep->ss_ep_comp.wBytesPerInterval = - ep->desc.wMaxPacketSize; - return; - } - - memcpy(&ep->ss_ep_comp, desc, USB_DT_SS_EP_COMP_SIZE); - - /* 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); - ep->ss_ep_comp.bMaxBurst = 0; - } else 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); - ep->ss_ep_comp.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); - ep->ss_ep_comp.bmAttributes = 0; - } else 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); - ep->ss_ep_comp.bmAttributes = 16; - } else 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); - ep->ss_ep_comp.bmAttributes = 2; - } - - if (usb_endpoint_xfer_isoc(&ep->desc)) - max_tx = (desc->bMaxBurst + 1) * (desc->bmAttributes + 1) * - usb_endpoint_maxp(&ep->desc); - else if (usb_endpoint_xfer_int(&ep->desc)) - max_tx = usb_endpoint_maxp(&ep->desc) * - (desc->bMaxBurst + 1); - else - max_tx = 999999; - if (le16_to_cpu(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", - le16_to_cpu(desc->wBytesPerInterval), - cfgno, inum, asnum, ep->desc.bEndpointAddress, - max_tx); - ep->ss_ep_comp.wBytesPerInterval = cpu_to_le16(max_tx); - } -} - -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) -{ - unsigned char *buffer0 = buffer; - struct usb_endpoint_descriptor *d; - struct usb_host_endpoint *endpoint; - int n, i, j, retval; - - d = (struct usb_endpoint_descriptor *) buffer; - buffer += d->bLength; - size -= d->bLength; - - if (d->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE) - n = USB_DT_ENDPOINT_AUDIO_SIZE; - else if (d->bLength >= USB_DT_ENDPOINT_SIZE) - n = USB_DT_ENDPOINT_SIZE; - else { - dev_warn(ddev, "config %d interface %d altsetting %d has an " - "invalid endpoint descriptor of length %d, skipping\n", - cfgno, inum, asnum, d->bLength); - goto skip_to_next_endpoint_or_interface_descriptor; - } - - i = d->bEndpointAddress & ~USB_ENDPOINT_DIR_MASK; - if (i >= 16 || i == 0) { - dev_warn(ddev, "config %d interface %d altsetting %d has an " - "invalid endpoint with address 0x%X, skipping\n", - cfgno, inum, asnum, d->bEndpointAddress); - goto skip_to_next_endpoint_or_interface_descriptor; - } - - /* Only store as many endpoints as we have room for */ - if (ifp->desc.bNumEndpoints >= num_ep) - goto skip_to_next_endpoint_or_interface_descriptor; - - endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints]; - ++ifp->desc.bNumEndpoints; - - memcpy(&endpoint->desc, d, n); - INIT_LIST_HEAD(&endpoint->urb_list); - - /* Fix up bInterval values outside the legal range. Use 32 ms if no - * proper value can be guessed. */ - i = 0; /* i = min, j = max, n = default */ - j = 255; - 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 - * descriptors. Try to fix those and fall back to a - * 32 ms default value otherwise. */ - n = fls(d->bInterval*8); - if (n == 0) - n = 9; /* 32 ms = 2^(9-1) uframes */ - j = 16; - break; - default: /* USB_SPEED_FULL or _LOW */ - /* For low-speed, 10 ms is the official minimum. - * But some "overclocked" devices might want faster - * polling so we'll allow it. */ - n = 32; - break; - } - } else if (usb_endpoint_xfer_isoc(d)) { - i = 1; - j = 16; - switch (to_usb_device(ddev)->speed) { - case USB_SPEED_HIGH: - n = 9; /* 32 ms = 2^(9-1) uframes */ - break; - default: /* USB_SPEED_FULL */ - n = 6; /* 32 ms = 2^(6-1) frames */ - break; - } - } - if (d->bInterval < i || d->bInterval > j) { - dev_warn(ddev, "config %d interface %d altsetting %d " - "endpoint 0x%X has an invalid bInterval %d, " - "changing to %d\n", - cfgno, inum, asnum, - d->bEndpointAddress, d->bInterval, n); - endpoint->desc.bInterval = n; - } - - /* Some buggy low-speed devices have Bulk endpoints, which is - * explicitly forbidden by the USB spec. In an attempt to make - * them usable, we will try treating them as Interrupt endpoints. - */ - if (to_usb_device(ddev)->speed == USB_SPEED_LOW && - usb_endpoint_xfer_bulk(d)) { - dev_warn(ddev, "config %d interface %d altsetting %d " - "endpoint 0x%X is Bulk; changing to Interrupt\n", - cfgno, inum, asnum, d->bEndpointAddress); - endpoint->desc.bmAttributes = USB_ENDPOINT_XFER_INT; - endpoint->desc.bInterval = 1; - if (usb_endpoint_maxp(&endpoint->desc) > 8) - endpoint->desc.wMaxPacketSize = cpu_to_le16(8); - } - - /* - * Some buggy high speed devices have bulk endpoints using - * maxpacket sizes other than 512. High speed HCDs may not - * be able to handle that particular bug, so let's warn... - */ - if (to_usb_device(ddev)->speed == USB_SPEED_HIGH - && usb_endpoint_xfer_bulk(d)) { - unsigned maxp; - - maxp = usb_endpoint_maxp(&endpoint->desc) & 0x07ff; - if (maxp != 512) - dev_warn(ddev, "config %d interface %d altsetting %d " - "bulk endpoint 0x%X has invalid maxpacket %d\n", - cfgno, inum, asnum, d->bEndpointAddress, - maxp); - } - - /* Parse a possible SuperSpeed endpoint companion descriptor */ - if (to_usb_device(ddev)->speed == USB_SPEED_SUPER) - usb_parse_ss_endpoint_companion(ddev, cfgno, - inum, asnum, endpoint, buffer, size); - - /* 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 retval; - -skip_to_next_endpoint_or_interface_descriptor: - i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, - USB_DT_INTERFACE, NULL); - return buffer - buffer0 + i; -} - -void usb_release_interface_cache(struct kref *ref) -{ - struct usb_interface_cache *intfc = ref_to_usb_interface_cache(ref); - int j; - - for (j = 0; j < intfc->num_altsetting; j++) { - struct usb_host_interface *alt = &intfc->altsetting[j]; - - kfree(alt->endpoint); - kfree(alt->string); - } - kfree(intfc); -} - -static int usb_parse_interface(struct device *ddev, int cfgno, - struct usb_host_config *config, unsigned char *buffer, int size, - u8 inums[], u8 nalts[]) -{ - unsigned char *buffer0 = buffer; - struct usb_interface_descriptor *d; - int inum, asnum; - struct usb_interface_cache *intfc; - struct usb_host_interface *alt; - int i, n; - int len, retval; - int num_ep, num_ep_orig; - - d = (struct usb_interface_descriptor *) buffer; - buffer += d->bLength; - size -= d->bLength; - - if (d->bLength < USB_DT_INTERFACE_SIZE) - goto skip_to_next_interface_descriptor; - - /* Which interface entry is this? */ - intfc = NULL; - inum = d->bInterfaceNumber; - for (i = 0; i < config->desc.bNumInterfaces; ++i) { - if (inums[i] == inum) { - intfc = config->intf_cache[i]; - break; - } - } - if (!intfc || intfc->num_altsetting >= nalts[i]) - goto skip_to_next_interface_descriptor; - - /* Check for duplicate altsetting entries */ - asnum = d->bAlternateSetting; - for ((i = 0, alt = &intfc->altsetting[0]); - i < intfc->num_altsetting; - (++i, ++alt)) { - if (alt->desc.bAlternateSetting == asnum) { - dev_warn(ddev, "Duplicate descriptor for config %d " - "interface %d altsetting %d, skipping\n", - cfgno, inum, asnum); - goto skip_to_next_interface_descriptor; - } - } - - ++intfc->num_altsetting; - memcpy(&alt->desc, d, USB_DT_INTERFACE_SIZE); - - /* Skip over any Class Specific or Vendor Specific descriptors; - * find the first endpoint or interface descriptor */ - alt->extra = buffer; - i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT, - USB_DT_INTERFACE, &n); - alt->extralen = i; - if (n > 0) - dev_dbg(ddev, "skipped %d descriptor%s after %s\n", - n, plural(n), "interface"); - buffer += i; - size -= i; - - /* Allocate space for the right(?) number of endpoints */ - num_ep = num_ep_orig = alt->desc.bNumEndpoints; - alt->desc.bNumEndpoints = 0; /* Use as a counter */ - if (num_ep > USB_MAXENDPOINTS) { - dev_warn(ddev, "too many endpoints for config %d interface %d " - "altsetting %d: %d, using maximum allowed: %d\n", - cfgno, inum, asnum, num_ep, USB_MAXENDPOINTS); - num_ep = USB_MAXENDPOINTS; - } - - if (num_ep > 0) { - /* Can't allocate 0 bytes */ - len = sizeof(struct usb_host_endpoint) * num_ep; - alt->endpoint = kzalloc(len, GFP_KERNEL); - if (!alt->endpoint) - return -ENOMEM; - } - - /* Parse all the endpoint descriptors */ - n = 0; - while (size > 0) { - if (((struct usb_descriptor_header *) buffer)->bDescriptorType - == USB_DT_INTERFACE) - break; - retval = usb_parse_endpoint(ddev, cfgno, inum, asnum, alt, - num_ep, buffer, size); - if (retval < 0) - return retval; - ++n; - - buffer += retval; - size -= retval; - } - - if (n != num_ep_orig) - dev_warn(ddev, "config %d interface %d altsetting %d has %d " - "endpoint descriptor%s, different from the interface " - "descriptor's value: %d\n", - cfgno, inum, asnum, n, plural(n), num_ep_orig); - return buffer - buffer0; - -skip_to_next_interface_descriptor: - i = find_next_descriptor(buffer, size, USB_DT_INTERFACE, - USB_DT_INTERFACE, NULL); - return buffer - buffer0 + i; -} - -static int usb_parse_configuration(struct usb_device *dev, int cfgidx, - struct usb_host_config *config, unsigned char *buffer, int size) -{ - struct device *ddev = &dev->dev; - unsigned char *buffer0 = buffer; - int cfgno; - int nintf, nintf_orig; - int i, j, n; - struct usb_interface_cache *intfc; - unsigned char *buffer2; - int size2; - struct usb_descriptor_header *header; - int len, retval; - u8 inums[USB_MAXINTERFACES], nalts[USB_MAXINTERFACES]; - unsigned iad_num = 0; - - memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE); - if (config->desc.bDescriptorType != USB_DT_CONFIG || - config->desc.bLength < USB_DT_CONFIG_SIZE) { - dev_err(ddev, "invalid descriptor for config index %d: " - "type = 0x%X, length = %d\n", cfgidx, - config->desc.bDescriptorType, config->desc.bLength); - return -EINVAL; - } - cfgno = config->desc.bConfigurationValue; - - buffer += config->desc.bLength; - size -= config->desc.bLength; - - nintf = nintf_orig = config->desc.bNumInterfaces; - if (nintf > USB_MAXINTERFACES) { - dev_warn(ddev, "config %d has too many interfaces: %d, " - "using maximum allowed: %d\n", - cfgno, nintf, USB_MAXINTERFACES); - nintf = USB_MAXINTERFACES; - } - - /* Go through the descriptors, checking their length and counting the - * number of altsettings for each interface */ - n = 0; - for ((buffer2 = buffer, size2 = size); - size2 > 0; - (buffer2 += header->bLength, size2 -= header->bLength)) { - - if (size2 < sizeof(struct usb_descriptor_header)) { - dev_warn(ddev, "config %d descriptor has %d excess " - "byte%s, ignoring\n", - cfgno, size2, plural(size2)); - break; - } - - header = (struct usb_descriptor_header *) buffer2; - if ((header->bLength > size2) || (header->bLength < 2)) { - dev_warn(ddev, "config %d has an invalid descriptor " - "of length %d, skipping remainder of the config\n", - cfgno, header->bLength); - break; - } - - if (header->bDescriptorType == USB_DT_INTERFACE) { - struct usb_interface_descriptor *d; - int inum; - - d = (struct usb_interface_descriptor *) header; - if (d->bLength < USB_DT_INTERFACE_SIZE) { - dev_warn(ddev, "config %d has an invalid " - "interface descriptor of length %d, " - "skipping\n", cfgno, d->bLength); - continue; - } - - inum = d->bInterfaceNumber; - - if ((dev->quirks & USB_QUIRK_HONOR_BNUMINTERFACES) && - n >= nintf_orig) { - dev_warn(ddev, "config %d has more interface " - "descriptors, than it declares in " - "bNumInterfaces, ignoring interface " - "number: %d\n", cfgno, inum); - continue; - } - - if (inum >= nintf_orig) - dev_warn(ddev, "config %d has an invalid " - "interface number: %d but max is %d\n", - cfgno, inum, nintf_orig - 1); - - /* Have we already encountered this interface? - * Count its altsettings */ - for (i = 0; i < n; ++i) { - if (inums[i] == inum) - break; - } - if (i < n) { - if (nalts[i] < 255) - ++nalts[i]; - } else if (n < USB_MAXINTERFACES) { - inums[n] = inum; - nalts[n] = 1; - ++n; - } - - } else if (header->bDescriptorType == - USB_DT_INTERFACE_ASSOCIATION) { - if (iad_num == USB_MAXIADS) { - dev_warn(ddev, "found more Interface " - "Association Descriptors " - "than allocated for in " - "configuration %d\n", cfgno); - } else { - config->intf_assoc[iad_num] = - (struct usb_interface_assoc_descriptor - *)header; - iad_num++; - } - - } else if (header->bDescriptorType == USB_DT_DEVICE || - header->bDescriptorType == USB_DT_CONFIG) - dev_warn(ddev, "config %d contains an unexpected " - "descriptor of type 0x%X, skipping\n", - cfgno, header->bDescriptorType); - - } /* for ((buffer2 = buffer, size2 = size); ...) */ - size = buffer2 - buffer; - config->desc.wTotalLength = cpu_to_le16(buffer2 - buffer0); - - if (n != nintf) - dev_warn(ddev, "config %d has %d interface%s, different from " - "the descriptor's value: %d\n", - cfgno, n, plural(n), nintf_orig); - else if (n == 0) - dev_warn(ddev, "config %d has no interfaces?\n", cfgno); - config->desc.bNumInterfaces = nintf = n; - - /* Check for missing interface numbers */ - for (i = 0; i < nintf; ++i) { - for (j = 0; j < nintf; ++j) { - if (inums[j] == i) - break; - } - if (j >= nintf) - dev_warn(ddev, "config %d has no interface number " - "%d\n", cfgno, i); - } - - /* Allocate the usb_interface_caches and altsetting arrays */ - for (i = 0; i < nintf; ++i) { - j = nalts[i]; - if (j > USB_MAXALTSETTING) { - dev_warn(ddev, "too many alternate settings for " - "config %d interface %d: %d, " - "using maximum allowed: %d\n", - cfgno, inums[i], j, USB_MAXALTSETTING); - nalts[i] = j = USB_MAXALTSETTING; - } - - len = sizeof(*intfc) + sizeof(struct usb_host_interface) * j; - config->intf_cache[i] = intfc = kzalloc(len, GFP_KERNEL); - if (!intfc) - return -ENOMEM; - 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; - i = find_next_descriptor(buffer, size, USB_DT_INTERFACE, - USB_DT_INTERFACE, &n); - config->extralen = i; - if (n > 0) - dev_dbg(ddev, "skipped %d descriptor%s after %s\n", - n, plural(n), "configuration"); - buffer += i; - size -= i; - - /* Parse all the interface/altsetting descriptors */ - while (size > 0) { - retval = usb_parse_interface(ddev, cfgno, config, - buffer, size, inums, nalts); - if (retval < 0) - return retval; - - buffer += retval; - size -= retval; - } - - /* Check for missing altsettings */ - for (i = 0; i < nintf; ++i) { - intfc = config->intf_cache[i]; - for (j = 0; j < intfc->num_altsetting; ++j) { - for (n = 0; n < intfc->num_altsetting; ++n) { - if (intfc->altsetting[n].desc. - bAlternateSetting == j) - break; - } - if (n >= intfc->num_altsetting) - dev_warn(ddev, "config %d interface %d has no " - "altsetting %d\n", cfgno, inums[i], j); - } - } - - return 0; -} - -/* hub-only!! ... and only exported for reset/reinit path. - * otherwise used internally on disconnect/destroy path - */ -void usb_destroy_configuration(struct usb_device *dev) -{ - int c, i; - - if (!dev->config) - return; - - if (dev->rawdescriptors) { - for (i = 0; i < dev->descriptor.bNumConfigurations; i++) - kfree(dev->rawdescriptors[i]); - - kfree(dev->rawdescriptors); - dev->rawdescriptors = NULL; - } - - for (c = 0; c < dev->descriptor.bNumConfigurations; c++) { - struct usb_host_config *cf = &dev->config[c]; - - kfree(cf->string); - for (i = 0; i < cf->desc.bNumInterfaces; i++) { - if (cf->intf_cache[i]) - kref_put(&cf->intf_cache[i]->ref, - usb_release_interface_cache); - } - } - kfree(dev->config); - dev->config = NULL; -} - - -/* - * Get the USB config descriptors, cache and parse'em - * - * hub-only!! ... and only in reset path, or usb_new_device() - * (used by real hubs and virtual root hubs) - * - * NOTE: if this is a WUSB device and is not authorized, we skip the - * whole thing. A non-authorized USB device has no - * configurations. - */ -int usb_get_configuration(struct usb_device *dev) -{ - struct device *ddev = &dev->dev; - int ncfg = dev->descriptor.bNumConfigurations; - int result = 0; - unsigned int cfgno, length; - unsigned char *bigbuffer; - struct usb_config_descriptor *desc; - - cfgno = 0; - if (dev->authorized == 0) /* Not really an error */ - goto out_not_authorized; - result = -ENOMEM; - if (ncfg > USB_MAXCONFIG) { - dev_warn(ddev, "too many configurations: %d, " - "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG); - dev->descriptor.bNumConfigurations = ncfg = USB_MAXCONFIG; - } - - if (ncfg < 1) { - dev_err(ddev, "no configurations\n"); - return -EINVAL; - } - - length = ncfg * sizeof(struct usb_host_config); - dev->config = kzalloc(length, GFP_KERNEL); - if (!dev->config) - goto err2; - - length = ncfg * sizeof(char *); - dev->rawdescriptors = kzalloc(length, GFP_KERNEL); - if (!dev->rawdescriptors) - goto err2; - - desc = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL); - if (!desc) - goto err2; - - result = 0; - for (; cfgno < ncfg; cfgno++) { - /* We grab just the first descriptor so we know how long - * the whole configuration is */ - result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, - desc, USB_DT_CONFIG_SIZE); - if (result < 0) { - dev_err(ddev, "unable to read config index %d " - "descriptor/%s: %d\n", cfgno, "start", result); - dev_err(ddev, "chopping to %d config(s)\n", cfgno); - dev->descriptor.bNumConfigurations = cfgno; - break; - } else if (result < 4) { - dev_err(ddev, "config index %d descriptor too short " - "(expected %i, got %i)\n", cfgno, - USB_DT_CONFIG_SIZE, result); - result = -EINVAL; - goto err; - } - length = max((int) le16_to_cpu(desc->wTotalLength), - USB_DT_CONFIG_SIZE); - - /* Now that we know the length, get the whole thing */ - bigbuffer = kmalloc(length, GFP_KERNEL); - if (!bigbuffer) { - result = -ENOMEM; - goto err; - } - result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, - bigbuffer, length); - if (result < 0) { - dev_err(ddev, "unable to read config index %d " - "descriptor/%s\n", cfgno, "all"); - kfree(bigbuffer); - goto err; - } - if (result < length) { - dev_warn(ddev, "config index %d descriptor too short " - "(expected %i, got %i)\n", cfgno, length, result); - length = result; - } - - dev->rawdescriptors[cfgno] = bigbuffer; - - result = usb_parse_configuration(dev, cfgno, - &dev->config[cfgno], bigbuffer, length); - if (result < 0) { - ++cfgno; - goto err; - } - } - result = 0; - -err: - kfree(desc); -out_not_authorized: - dev->descriptor.bNumConfigurations = cfgno; -err2: - if (result == -ENOMEM) - dev_err(ddev, "out of memory\n"); - return result; -} - -void usb_release_bos_descriptor(struct usb_device *dev) -{ - if (dev->bos) { - kfree(dev->bos->desc); - kfree(dev->bos); - dev->bos = NULL; - } -} - -/* Get BOS descriptor set */ -int usb_get_bos_descriptor(struct usb_device *dev) -{ - struct device *ddev = &dev->dev; - struct usb_bos_descriptor *bos; - struct usb_dev_cap_header *cap; - unsigned char *buffer; - int length, total_len, num, i; - int ret; - - bos = kzalloc(sizeof(struct usb_bos_descriptor), GFP_KERNEL); - if (!bos) - return -ENOMEM; - - /* Get BOS descriptor */ - ret = usb_get_descriptor(dev, USB_DT_BOS, 0, bos, USB_DT_BOS_SIZE); - if (ret < USB_DT_BOS_SIZE) { - dev_err(ddev, "unable to get BOS descriptor\n"); - if (ret >= 0) - ret = -ENOMSG; - kfree(bos); - return ret; - } - - length = bos->bLength; - total_len = le16_to_cpu(bos->wTotalLength); - num = bos->bNumDeviceCaps; - kfree(bos); - if (total_len < length) - return -EINVAL; - - dev->bos = kzalloc(sizeof(struct usb_host_bos), GFP_KERNEL); - if (!dev->bos) - return -ENOMEM; - - /* Now let's get the whole BOS descriptor set */ - buffer = kzalloc(total_len, GFP_KERNEL); - if (!buffer) { - ret = -ENOMEM; - goto err; - } - dev->bos->desc = (struct usb_bos_descriptor *)buffer; - - ret = usb_get_descriptor(dev, USB_DT_BOS, 0, buffer, total_len); - if (ret < total_len) { - dev_err(ddev, "unable to get BOS descriptor set\n"); - if (ret >= 0) - ret = -ENOMSG; - goto err; - } - total_len -= length; - - for (i = 0; i < num; i++) { - buffer += length; - cap = (struct usb_dev_cap_header *)buffer; - length = cap->bLength; - - if (total_len < length) - break; - total_len -= length; - - if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) { - dev_warn(ddev, "descriptor type invalid, skip\n"); - continue; - } - - switch (cap->bDevCapabilityType) { - case USB_CAP_TYPE_WIRELESS_USB: - /* Wireless USB cap descriptor is handled by wusb */ - break; - case USB_CAP_TYPE_EXT: - dev->bos->ext_cap = - (struct usb_ext_cap_descriptor *)buffer; - break; - case USB_SS_CAP_TYPE: - dev->bos->ss_cap = - (struct usb_ss_cap_descriptor *)buffer; - break; - case CONTAINER_ID_TYPE: - dev->bos->ss_id = - (struct usb_ss_container_id_descriptor *)buffer; - break; - default: - break; - } - } - - return 0; - -err: - usb_release_bos_descriptor(dev); - return ret; -} diff --git a/ANDROID_3.4.5/drivers/usb/core/devices.c b/ANDROID_3.4.5/drivers/usb/core/devices.c deleted file mode 100644 index d9569658..00000000 --- a/ANDROID_3.4.5/drivers/usb/core/devices.c +++ /dev/null @@ -1,688 +0,0 @@ -/* - * devices.c - * (C) Copyright 1999 Randy Dunlap. - * (C) Copyright 1999,2000 Thomas Sailer . - * (proc file per device) - * (C) Copyright 1999 Deti Fliegl (new USB architecture) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ************************************************************* - * - * /devices contains USB topology, device, config, class, - * interface, & endpoint data. - * - * I considered using /proc/bus/usb/devices/device# for each device - * as it is attached or detached, but I didn't like this for some - * reason -- maybe it's just too deep of a directory structure. - * I also don't like looking in multiple places to gather and view - * the data. Having only one file for ./devices also prevents race - * conditions that could arise if a program was reading device info - * for devices that are being removed (unplugged). (That is, the - * program may find a directory for devnum_12 then try to open it, - * but it was just unplugged, so the directory is now deleted. - * But programs would just have to be prepared for situations like - * this in any plug-and-play environment.) - * - * 1999-12-16: Thomas Sailer - * Converted the whole proc stuff to real - * read methods. Now not the whole device list needs to fit - * into one page, only the device list for one bus. - * Added a poll method to /proc/bus/usb/devices, to wake - * up an eventual usbd - * 2000-01-04: Thomas Sailer - * Turned into its own filesystem - * 2000-07-05: Ashley Montanaro - * Converted file reading routine to dump to buffer once - * per device, not per bus - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "usb.h" - -/* Define ALLOW_SERIAL_NUMBER if you want to see the serial number of devices */ -#define ALLOW_SERIAL_NUMBER - -static const char format_topo[] = -/* T: Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=dddd MxCh=dd */ -"\nT: Bus=%2.2d Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%-4s MxCh=%2d\n"; - -static const char format_string_manufacturer[] = -/* S: Manufacturer=xxxx */ - "S: Manufacturer=%.100s\n"; - -static const char format_string_product[] = -/* S: Product=xxxx */ - "S: Product=%.100s\n"; - -#ifdef ALLOW_SERIAL_NUMBER -static const char format_string_serialnumber[] = -/* S: SerialNumber=xxxx */ - "S: SerialNumber=%.100s\n"; -#endif - -static const char format_bandwidth[] = -/* B: Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd */ - "B: Alloc=%3d/%3d us (%2d%%), #Int=%3d, #Iso=%3d\n"; - -static const char format_device1[] = -/* D: Ver=xx.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd */ - "D: Ver=%2x.%02x Cls=%02x(%-5s) Sub=%02x Prot=%02x MxPS=%2d #Cfgs=%3d\n"; - -static const char format_device2[] = -/* P: Vendor=xxxx ProdID=xxxx Rev=xx.xx */ - "P: Vendor=%04x ProdID=%04x Rev=%2x.%02x\n"; - -static const char format_config[] = -/* C: #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA */ - "C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n"; - -static const char format_iad[] = -/* A: FirstIf#=dd IfCount=dd Cls=xx(sssss) Sub=xx Prot=xx */ - "A: FirstIf#=%2d IfCount=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x\n"; - -static const char format_iface[] = -/* I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/ - "I:%c If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n"; - -static const char format_endpt[] = -/* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */ - "E: Ad=%02x(%c) Atr=%02x(%-4s) MxPS=%4d Ivl=%d%cs\n"; - - -/* - * Need access to the driver and USB bus lists. - * extern struct list_head usb_bus_list; - * However, these will come from functions that return ptrs to each of them. - */ - -/* - * Wait for an connect/disconnect event to happen. We initialize - * the event counter with an odd number, and each event will increment - * the event counter by two, so it will always _stay_ odd. That means - * that it will never be zero, so "event 0" will never match a current - * event, and thus 'poll' will always trigger as readable for the first - * time it gets called. - */ -static struct device_connect_event { - atomic_t count; - wait_queue_head_t wait; -} device_event = { - .count = ATOMIC_INIT(1), - .wait = __WAIT_QUEUE_HEAD_INITIALIZER(device_event.wait) -}; - -struct class_info { - int class; - char *class_name; -}; - -static const struct class_info clas_info[] = { - /* max. 5 chars. per name string */ - {USB_CLASS_PER_INTERFACE, ">ifc"}, - {USB_CLASS_AUDIO, "audio"}, - {USB_CLASS_COMM, "comm."}, - {USB_CLASS_HID, "HID"}, - {USB_CLASS_PHYSICAL, "PID"}, - {USB_CLASS_STILL_IMAGE, "still"}, - {USB_CLASS_PRINTER, "print"}, - {USB_CLASS_MASS_STORAGE, "stor."}, - {USB_CLASS_HUB, "hub"}, - {USB_CLASS_CDC_DATA, "data"}, - {USB_CLASS_CSCID, "scard"}, - {USB_CLASS_CONTENT_SEC, "c-sec"}, - {USB_CLASS_VIDEO, "video"}, - {USB_CLASS_WIRELESS_CONTROLLER, "wlcon"}, - {USB_CLASS_MISC, "misc"}, - {USB_CLASS_APP_SPEC, "app."}, - {USB_CLASS_VENDOR_SPEC, "vend."}, - {-1, "unk."} /* leave as last */ -}; - -/*****************************************************************/ - -void usbfs_conn_disc_event(void) -{ - atomic_add(2, &device_event.count); - wake_up(&device_event.wait); -} - -static const char *class_decode(const int class) -{ - int ix; - - for (ix = 0; clas_info[ix].class != -1; ix++) - if (clas_info[ix].class == class) - break; - return clas_info[ix].class_name; -} - -static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end, - const struct usb_endpoint_descriptor *desc) -{ - char dir, unit, *type; - unsigned interval, bandwidth = 1; - - if (start > end) - return start; - - dir = usb_endpoint_dir_in(desc) ? 'I' : 'O'; - - if (speed == USB_SPEED_HIGH) { - switch (usb_endpoint_maxp(desc) & (0x03 << 11)) { - case 1 << 11: - bandwidth = 2; break; - case 2 << 11: - bandwidth = 3; break; - } - } - - /* this isn't checking for illegal values */ - switch (usb_endpoint_type(desc)) { - case USB_ENDPOINT_XFER_CONTROL: - type = "Ctrl"; - if (speed == USB_SPEED_HIGH) /* uframes per NAK */ - interval = desc->bInterval; - else - interval = 0; - dir = 'B'; /* ctrl is bidirectional */ - break; - case USB_ENDPOINT_XFER_ISOC: - type = "Isoc"; - interval = 1 << (desc->bInterval - 1); - break; - case USB_ENDPOINT_XFER_BULK: - type = "Bulk"; - if (speed == USB_SPEED_HIGH && dir == 'O') /* uframes per NAK */ - interval = desc->bInterval; - else - interval = 0; - break; - case USB_ENDPOINT_XFER_INT: - type = "Int."; - if (speed == USB_SPEED_HIGH || speed == USB_SPEED_SUPER) - interval = 1 << (desc->bInterval - 1); - else - interval = desc->bInterval; - break; - default: /* "can't happen" */ - return start; - } - interval *= (speed == USB_SPEED_HIGH || - speed == USB_SPEED_SUPER) ? 125 : 1000; - if (interval % 1000) - unit = 'u'; - else { - unit = 'm'; - interval /= 1000; - } - - start += sprintf(start, format_endpt, desc->bEndpointAddress, dir, - desc->bmAttributes, type, - (usb_endpoint_maxp(desc) & 0x07ff) * - bandwidth, - interval, unit); - return start; -} - -static char *usb_dump_interface_descriptor(char *start, char *end, - const struct usb_interface_cache *intfc, - const struct usb_interface *iface, - int setno) -{ - const struct usb_interface_descriptor *desc; - const char *driver_name = ""; - int active = 0; - - if (start > end) - return start; - desc = &intfc->altsetting[setno].desc; - if (iface) { - driver_name = (iface->dev.driver - ? iface->dev.driver->name - : "(none)"); - active = (desc == &iface->cur_altsetting->desc); - } - start += sprintf(start, format_iface, - active ? '*' : ' ', /* mark active altsetting */ - desc->bInterfaceNumber, - desc->bAlternateSetting, - desc->bNumEndpoints, - desc->bInterfaceClass, - class_decode(desc->bInterfaceClass), - desc->bInterfaceSubClass, - desc->bInterfaceProtocol, - driver_name); - return start; -} - -static char *usb_dump_interface(int speed, char *start, char *end, - const struct usb_interface_cache *intfc, - const struct usb_interface *iface, int setno) -{ - const struct usb_host_interface *desc = &intfc->altsetting[setno]; - int i; - - start = usb_dump_interface_descriptor(start, end, intfc, iface, setno); - for (i = 0; i < desc->desc.bNumEndpoints; i++) { - if (start > end) - return start; - start = usb_dump_endpoint_descriptor(speed, - start, end, &desc->endpoint[i].desc); - } - return start; -} - -static char *usb_dump_iad_descriptor(char *start, char *end, - const struct usb_interface_assoc_descriptor *iad) -{ - if (start > end) - return start; - start += sprintf(start, format_iad, - iad->bFirstInterface, - iad->bInterfaceCount, - iad->bFunctionClass, - class_decode(iad->bFunctionClass), - iad->bFunctionSubClass, - iad->bFunctionProtocol); - return start; -} - -/* TBD: - * 0. TBDs - * 1. marking active interface altsettings (code lists all, but should mark - * which ones are active, if any) - */ -static char *usb_dump_config_descriptor(char *start, char *end, - const struct usb_config_descriptor *desc, - int active) -{ - if (start > end) - return start; - start += sprintf(start, format_config, - /* mark active/actual/current cfg. */ - active ? '*' : ' ', - desc->bNumInterfaces, - desc->bConfigurationValue, - desc->bmAttributes, - desc->bMaxPower * 2); - return start; -} - -static char *usb_dump_config(int speed, char *start, char *end, - const struct usb_host_config *config, int active) -{ - int i, j; - struct usb_interface_cache *intfc; - struct usb_interface *interface; - - if (start > end) - return start; - if (!config) - /* getting these some in 2.3.7; none in 2.3.6 */ - return start + sprintf(start, "(null Cfg. desc.)\n"); - start = usb_dump_config_descriptor(start, end, &config->desc, active); - for (i = 0; i < USB_MAXIADS; i++) { - if (config->intf_assoc[i] == NULL) - break; - start = usb_dump_iad_descriptor(start, end, - config->intf_assoc[i]); - } - for (i = 0; i < config->desc.bNumInterfaces; i++) { - intfc = config->intf_cache[i]; - interface = config->interface[i]; - for (j = 0; j < intfc->num_altsetting; j++) { - if (start > end) - return start; - start = usb_dump_interface(speed, - start, end, intfc, interface, j); - } - } - return start; -} - -/* - * Dump the different USB descriptors. - */ -static char *usb_dump_device_descriptor(char *start, char *end, - const struct usb_device_descriptor *desc) -{ - u16 bcdUSB = le16_to_cpu(desc->bcdUSB); - u16 bcdDevice = le16_to_cpu(desc->bcdDevice); - - if (start > end) - return start; - start += sprintf(start, format_device1, - bcdUSB >> 8, bcdUSB & 0xff, - desc->bDeviceClass, - class_decode(desc->bDeviceClass), - desc->bDeviceSubClass, - desc->bDeviceProtocol, - desc->bMaxPacketSize0, - desc->bNumConfigurations); - if (start > end) - return start; - start += sprintf(start, format_device2, - le16_to_cpu(desc->idVendor), - le16_to_cpu(desc->idProduct), - bcdDevice >> 8, bcdDevice & 0xff); - return start; -} - -/* - * Dump the different strings that this device holds. - */ -static char *usb_dump_device_strings(char *start, char *end, - struct usb_device *dev) -{ - if (start > end) - return start; - if (dev->manufacturer) - start += sprintf(start, format_string_manufacturer, - dev->manufacturer); - if (start > end) - goto out; - if (dev->product) - start += sprintf(start, format_string_product, dev->product); - if (start > end) - goto out; -#ifdef ALLOW_SERIAL_NUMBER - if (dev->serial) - start += sprintf(start, format_string_serialnumber, - dev->serial); -#endif - out: - return start; -} - -static char *usb_dump_desc(char *start, char *end, struct usb_device *dev) -{ - int i; - - if (start > end) - return start; - - start = usb_dump_device_descriptor(start, end, &dev->descriptor); - - if (start > end) - return start; - - start = usb_dump_device_strings(start, end, dev); - - for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { - if (start > end) - return start; - start = usb_dump_config(dev->speed, - start, end, dev->config + i, - /* active ? */ - (dev->config + i) == dev->actconfig); - } - return start; -} - - -#ifdef PROC_EXTRA /* TBD: may want to add this code later */ - -static char *usb_dump_hub_descriptor(char *start, char *end, - const struct usb_hub_descriptor *desc) -{ - int leng = USB_DT_HUB_NONVAR_SIZE; - unsigned char *ptr = (unsigned char *)desc; - - if (start > end) - return start; - start += sprintf(start, "Interface:"); - while (leng && start <= end) { - start += sprintf(start, " %02x", *ptr); - ptr++; leng--; - } - *start++ = '\n'; - return start; -} - -static char *usb_dump_string(char *start, char *end, - const struct usb_device *dev, char *id, int index) -{ - if (start > end) - return start; - start += sprintf(start, "Interface:"); - if (index <= dev->maxstring && dev->stringindex && - dev->stringindex[index]) - start += sprintf(start, "%s: %.100s ", id, - dev->stringindex[index]); - return start; -} - -#endif /* PROC_EXTRA */ - -/*****************************************************************/ - -/* This is a recursive function. Parameters: - * buffer - the user-space buffer to write data into - * nbytes - the maximum number of bytes to write - * skip_bytes - the number of bytes to skip before writing anything - * file_offset - the offset into the devices file on completion - * The caller must own the device lock. - */ -static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, - loff_t *skip_bytes, loff_t *file_offset, - struct usb_device *usbdev, struct usb_bus *bus, - int level, int index, int count) -{ - int chix; - int ret, cnt = 0; - int parent_devnum = 0; - char *pages_start, *data_end, *speed; - unsigned int length; - ssize_t total_written = 0; - - /* don't bother with anything else if we're not writing any data */ - if (*nbytes <= 0) - return 0; - - if (level > MAX_TOPO_LEVEL) - return 0; - /* allocate 2^1 pages = 8K (on i386); - * should be more than enough for one device */ - pages_start = (char *)__get_free_pages(GFP_NOIO, 1); - if (!pages_start) - return -ENOMEM; - - if (usbdev->parent && usbdev->parent->devnum != -1) - parent_devnum = usbdev->parent->devnum; - /* - * So the root hub's parent is 0 and any device that is - * plugged into the root hub has a parent of 0. - */ - switch (usbdev->speed) { - case USB_SPEED_LOW: - speed = "1.5"; break; - case USB_SPEED_UNKNOWN: /* usb 1.1 root hub code */ - case USB_SPEED_FULL: - speed = "12"; break; - case USB_SPEED_WIRELESS: /* Wireless has no real fixed speed */ - case USB_SPEED_HIGH: - speed = "480"; break; - case USB_SPEED_SUPER: - speed = "5000"; break; - default: - speed = "??"; - } - data_end = pages_start + sprintf(pages_start, format_topo, - bus->busnum, level, parent_devnum, - index, count, usbdev->devnum, - speed, usbdev->maxchild); - /* - * level = topology-tier level; - * parent_devnum = parent device number; - * index = parent's connector number; - * count = device count at this level - */ - /* If this is the root hub, display the bandwidth information */ - if (level == 0) { - int max; - - /* super/high speed reserves 80%, full/low reserves 90% */ - if (usbdev->speed == USB_SPEED_HIGH || - usbdev->speed == USB_SPEED_SUPER) - max = 800; - else - max = FRAME_TIME_MAX_USECS_ALLOC; - - /* report "average" periodic allocation over a microsecond. - * the schedules are actually bursty, HCDs need to deal with - * that and just compute/report this average. - */ - data_end += sprintf(data_end, format_bandwidth, - bus->bandwidth_allocated, max, - (100 * bus->bandwidth_allocated + max / 2) - / max, - bus->bandwidth_int_reqs, - bus->bandwidth_isoc_reqs); - - } - data_end = usb_dump_desc(data_end, pages_start + (2 * PAGE_SIZE) - 256, - usbdev); - - if (data_end > (pages_start + (2 * PAGE_SIZE) - 256)) - data_end += sprintf(data_end, "(truncated)\n"); - - length = data_end - pages_start; - /* if we can start copying some data to the user */ - if (length > *skip_bytes) { - length -= *skip_bytes; - if (length > *nbytes) - length = *nbytes; - if (copy_to_user(*buffer, pages_start + *skip_bytes, length)) { - free_pages((unsigned long)pages_start, 1); - return -EFAULT; - } - *nbytes -= length; - *file_offset += length; - total_written += length; - *buffer += length; - *skip_bytes = 0; - } else - *skip_bytes -= length; - - free_pages((unsigned long)pages_start, 1); - - /* Now look at all of this device's children. */ - for (chix = 0; chix < usbdev->maxchild; chix++) { - struct usb_device *childdev = usbdev->children[chix]; - - if (childdev) { - usb_lock_device(childdev); - ret = usb_device_dump(buffer, nbytes, skip_bytes, - file_offset, childdev, bus, - level + 1, chix, ++cnt); - usb_unlock_device(childdev); - if (ret == -EFAULT) - return total_written; - total_written += ret; - } - } - return total_written; -} - -static ssize_t usb_device_read(struct file *file, char __user *buf, - size_t nbytes, loff_t *ppos) -{ - struct usb_bus *bus; - ssize_t ret, total_written = 0; - loff_t skip_bytes = *ppos; - - if (*ppos < 0) - return -EINVAL; - if (nbytes <= 0) - return 0; - if (!access_ok(VERIFY_WRITE, buf, nbytes)) - return -EFAULT; - - mutex_lock(&usb_bus_list_lock); - /* print devices for all busses */ - list_for_each_entry(bus, &usb_bus_list, bus_list) { - /* recurse through all children of the root hub */ - if (!bus->root_hub) - continue; - usb_lock_device(bus->root_hub); - ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, - bus->root_hub, bus, 0, 0, 0); - usb_unlock_device(bus->root_hub); - if (ret < 0) { - mutex_unlock(&usb_bus_list_lock); - return ret; - } - total_written += ret; - } - mutex_unlock(&usb_bus_list_lock); - return total_written; -} - -/* Kernel lock for "lastev" protection */ -static unsigned int usb_device_poll(struct file *file, - struct poll_table_struct *wait) -{ - unsigned int event_count; - - poll_wait(file, &device_event.wait, wait); - - event_count = atomic_read(&device_event.count); - if (file->f_version != event_count) { - file->f_version = event_count; - return POLLIN | POLLRDNORM; - } - - return 0; -} - -static loff_t usb_device_lseek(struct file *file, loff_t offset, int orig) -{ - loff_t ret; - - mutex_lock(&file->f_dentry->d_inode->i_mutex); - - switch (orig) { - case 0: - file->f_pos = offset; - ret = file->f_pos; - break; - case 1: - file->f_pos += offset; - ret = file->f_pos; - break; - case 2: - default: - ret = -EINVAL; - } - - mutex_unlock(&file->f_dentry->d_inode->i_mutex); - return ret; -} - -const struct file_operations usbfs_devices_fops = { - .llseek = usb_device_lseek, - .read = usb_device_read, - .poll = usb_device_poll, -}; diff --git a/ANDROID_3.4.5/drivers/usb/core/devio.c b/ANDROID_3.4.5/drivers/usb/core/devio.c deleted file mode 100644 index 4e577728..00000000 --- a/ANDROID_3.4.5/drivers/usb/core/devio.c +++ /dev/null @@ -1,2181 +0,0 @@ -/*****************************************************************************/ - -/* - * devio.c -- User space communication with USB devices. - * - * Copyright (C) 1999-2000 Thomas Sailer (sailer@ife.ee.ethz.ch) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * This file implements the usbfs/x/y files, where - * x is the bus number and y the device number. - * - * It allows user space programs/"drivers" to communicate directly - * with USB devices without intervening kernel driver. - * - * Revision history - * 22.12.1999 0.1 Initial release (split from proc_usb.c) - * 04.01.2000 0.2 Turned into its own filesystem - * 30.09.2005 0.3 Fix user-triggerable oops in async URB delivery - * (CAN-2005-3055) - */ - -/*****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for usbcore internals */ -#include -#include -#include -#include -#include -#include -#include - -#include "usb.h" - -#define USB_MAXBUS 64 -#define USB_DEVICE_MAX USB_MAXBUS * 128 - -/* Mutual exclusion for removal, open, and release */ -DEFINE_MUTEX(usbfs_mutex); - -struct dev_state { - struct list_head list; /* state list */ - struct usb_device *dev; - struct file *file; - spinlock_t lock; /* protects the async urb lists */ - struct list_head async_pending; - struct list_head async_completed; - wait_queue_head_t wait; /* wake up if a request completed */ - unsigned int discsignr; - struct pid *disc_pid; - const struct cred *cred; - void __user *disccontext; - unsigned long ifclaimed; - u32 secid; - u32 disabled_bulk_eps; -}; - -struct async { - struct list_head asynclist; - struct dev_state *ps; - struct pid *pid; - const struct cred *cred; - unsigned int signr; - unsigned int ifnum; - void __user *userbuffer; - void __user *userurb; - struct urb *urb; - unsigned int mem_usage; - int status; - u32 secid; - u8 bulk_addr; - u8 bulk_status; -}; - -static bool usbfs_snoop; -module_param(usbfs_snoop, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic"); - -#define snoop(dev, format, arg...) \ - do { \ - if (usbfs_snoop) \ - dev_info(dev , format , ## arg); \ - } while (0) - -enum snoop_when { - SUBMIT, COMPLETE -}; - -#define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0) - -/* Limit on the total amount of memory we can allocate for transfers */ -static unsigned usbfs_memory_mb = 16; -module_param(usbfs_memory_mb, uint, 0644); -MODULE_PARM_DESC(usbfs_memory_mb, - "maximum MB allowed for usbfs buffers (0 = no limit)"); - -/* Hard limit, necessary to avoid aithmetic overflow */ -#define USBFS_XFER_MAX (UINT_MAX / 2 - 1000000) - -static atomic_t usbfs_memory_usage; /* Total memory currently allocated */ - -/* Check whether it's okay to allocate more memory for a transfer */ -static int usbfs_increase_memory_usage(unsigned amount) -{ - unsigned lim; - - /* - * Convert usbfs_memory_mb to bytes, avoiding overflows. - * 0 means use the hard limit (effectively unlimited). - */ - lim = ACCESS_ONCE(usbfs_memory_mb); - if (lim == 0 || lim > (USBFS_XFER_MAX >> 20)) - lim = USBFS_XFER_MAX; - else - lim <<= 20; - - atomic_add(amount, &usbfs_memory_usage); - if (atomic_read(&usbfs_memory_usage) <= lim) - return 0; - atomic_sub(amount, &usbfs_memory_usage); - return -ENOMEM; -} - -/* Memory for a transfer is being deallocated */ -static void usbfs_decrease_memory_usage(unsigned amount) -{ - atomic_sub(amount, &usbfs_memory_usage); -} - -static int connected(struct dev_state *ps) -{ - return (!list_empty(&ps->list) && - ps->dev->state != USB_STATE_NOTATTACHED); -} - -static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig) -{ - loff_t ret; - - mutex_lock(&file->f_dentry->d_inode->i_mutex); - - switch (orig) { - case 0: - file->f_pos = offset; - ret = file->f_pos; - break; - case 1: - file->f_pos += offset; - ret = file->f_pos; - break; - case 2: - default: - ret = -EINVAL; - } - - mutex_unlock(&file->f_dentry->d_inode->i_mutex); - return ret; -} - -static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, - loff_t *ppos) -{ - struct dev_state *ps = file->private_data; - struct usb_device *dev = ps->dev; - ssize_t ret = 0; - unsigned len; - loff_t pos; - int i; - - pos = *ppos; - usb_lock_device(dev); - if (!connected(ps)) { - ret = -ENODEV; - goto err; - } else if (pos < 0) { - ret = -EINVAL; - goto err; - } - - if (pos < sizeof(struct usb_device_descriptor)) { - /* 18 bytes - fits on the stack */ - struct usb_device_descriptor temp_desc; - - memcpy(&temp_desc, &dev->descriptor, sizeof(dev->descriptor)); - le16_to_cpus(&temp_desc.bcdUSB); - le16_to_cpus(&temp_desc.idVendor); - le16_to_cpus(&temp_desc.idProduct); - le16_to_cpus(&temp_desc.bcdDevice); - - len = sizeof(struct usb_device_descriptor) - pos; - if (len > nbytes) - len = nbytes; - if (copy_to_user(buf, ((char *)&temp_desc) + pos, len)) { - ret = -EFAULT; - goto err; - } - - *ppos += len; - buf += len; - nbytes -= len; - ret += len; - } - - pos = sizeof(struct usb_device_descriptor); - for (i = 0; nbytes && i < dev->descriptor.bNumConfigurations; i++) { - struct usb_config_descriptor *config = - (struct usb_config_descriptor *)dev->rawdescriptors[i]; - unsigned int length = le16_to_cpu(config->wTotalLength); - - if (*ppos < pos + length) { - - /* The descriptor may claim to be longer than it - * really is. Here is the actual allocated length. */ - unsigned alloclen = - le16_to_cpu(dev->config[i].desc.wTotalLength); - - len = length - (*ppos - pos); - if (len > nbytes) - len = nbytes; - - /* Simply don't write (skip over) unallocated parts */ - if (alloclen > (*ppos - pos)) { - alloclen -= (*ppos - pos); - if (copy_to_user(buf, - dev->rawdescriptors[i] + (*ppos - pos), - min(len, alloclen))) { - ret = -EFAULT; - goto err; - } - } - - *ppos += len; - buf += len; - nbytes -= len; - ret += len; - } - - pos += length; - } - -err: - usb_unlock_device(dev); - return ret; -} - -/* - * async list handling - */ - -static struct async *alloc_async(unsigned int numisoframes) -{ - struct async *as; - - as = kzalloc(sizeof(struct async), GFP_KERNEL); - if (!as) - return NULL; - as->urb = usb_alloc_urb(numisoframes, GFP_KERNEL); - if (!as->urb) { - kfree(as); - return NULL; - } - return as; -} - -static void free_async(struct async *as) -{ - put_pid(as->pid); - if (as->cred) - put_cred(as->cred); - kfree(as->urb->transfer_buffer); - kfree(as->urb->setup_packet); - usb_free_urb(as->urb); - usbfs_decrease_memory_usage(as->mem_usage); - kfree(as); -} - -static void async_newpending(struct async *as) -{ - struct dev_state *ps = as->ps; - unsigned long flags; - - spin_lock_irqsave(&ps->lock, flags); - list_add_tail(&as->asynclist, &ps->async_pending); - spin_unlock_irqrestore(&ps->lock, flags); -} - -static void async_removepending(struct async *as) -{ - struct dev_state *ps = as->ps; - unsigned long flags; - - spin_lock_irqsave(&ps->lock, flags); - list_del_init(&as->asynclist); - spin_unlock_irqrestore(&ps->lock, flags); -} - -static struct async *async_getcompleted(struct dev_state *ps) -{ - unsigned long flags; - struct async *as = NULL; - - spin_lock_irqsave(&ps->lock, flags); - if (!list_empty(&ps->async_completed)) { - as = list_entry(ps->async_completed.next, struct async, - asynclist); - list_del_init(&as->asynclist); - } - spin_unlock_irqrestore(&ps->lock, flags); - return as; -} - -static struct async *async_getpending(struct dev_state *ps, - void __user *userurb) -{ - struct async *as; - - list_for_each_entry(as, &ps->async_pending, asynclist) - if (as->userurb == userurb) { - list_del_init(&as->asynclist); - return as; - } - - return NULL; -} - -static void snoop_urb(struct usb_device *udev, - void __user *userurb, int pipe, unsigned length, - int timeout_or_status, enum snoop_when when, - unsigned char *data, unsigned data_len) -{ - static const char *types[] = {"isoc", "int", "ctrl", "bulk"}; - static const char *dirs[] = {"out", "in"}; - int ep; - const char *t, *d; - - if (!usbfs_snoop) - return; - - ep = usb_pipeendpoint(pipe); - t = types[usb_pipetype(pipe)]; - d = dirs[!!usb_pipein(pipe)]; - - if (userurb) { /* Async */ - if (when == SUBMIT) - dev_info(&udev->dev, "userurb %p, ep%d %s-%s, " - "length %u\n", - userurb, ep, t, d, length); - else - dev_info(&udev->dev, "userurb %p, ep%d %s-%s, " - "actual_length %u status %d\n", - userurb, ep, t, d, length, - timeout_or_status); - } else { - if (when == SUBMIT) - dev_info(&udev->dev, "ep%d %s-%s, length %u, " - "timeout %d\n", - ep, t, d, length, timeout_or_status); - else - dev_info(&udev->dev, "ep%d %s-%s, actual_length %u, " - "status %d\n", - ep, t, d, length, timeout_or_status); - } - - if (data && data_len > 0) { - print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1, - data, data_len, 1); - } -} - -#define AS_CONTINUATION 1 -#define AS_UNLINK 2 - -static void cancel_bulk_urbs(struct dev_state *ps, unsigned bulk_addr) -__releases(ps->lock) -__acquires(ps->lock) -{ - struct urb *urb; - struct async *as; - - /* Mark all the pending URBs that match bulk_addr, up to but not - * including the first one without AS_CONTINUATION. If such an - * URB is encountered then a new transfer has already started so - * the endpoint doesn't need to be disabled; otherwise it does. - */ - list_for_each_entry(as, &ps->async_pending, asynclist) { - if (as->bulk_addr == bulk_addr) { - if (as->bulk_status != AS_CONTINUATION) - goto rescan; - as->bulk_status = AS_UNLINK; - as->bulk_addr = 0; - } - } - ps->disabled_bulk_eps |= (1 << bulk_addr); - - /* Now carefully unlink all the marked pending URBs */ - rescan: - list_for_each_entry(as, &ps->async_pending, asynclist) { - if (as->bulk_status == AS_UNLINK) { - as->bulk_status = 0; /* Only once */ - urb = as->urb; - usb_get_urb(urb); - spin_unlock(&ps->lock); /* Allow completions */ - usb_unlink_urb(urb); - usb_put_urb(urb); - spin_lock(&ps->lock); - goto rescan; - } - } -} - -static void async_completed(struct urb *urb) -{ - struct async *as = urb->context; - struct dev_state *ps = as->ps; - struct siginfo sinfo; - struct pid *pid = NULL; - u32 secid = 0; - const struct cred *cred = NULL; - int signr; - - spin_lock(&ps->lock); - list_move_tail(&as->asynclist, &ps->async_completed); - as->status = urb->status; - signr = as->signr; - if (signr) { - sinfo.si_signo = as->signr; - sinfo.si_errno = as->status; - sinfo.si_code = SI_ASYNCIO; - sinfo.si_addr = as->userurb; - pid = get_pid(as->pid); - cred = get_cred(as->cred); - secid = as->secid; - } - snoop(&urb->dev->dev, "urb complete\n"); - snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length, - as->status, COMPLETE, - ((urb->transfer_flags & URB_DIR_MASK) == USB_DIR_OUT) ? - NULL : urb->transfer_buffer, urb->actual_length); - if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET && - as->status != -ENOENT) - cancel_bulk_urbs(ps, as->bulk_addr); - spin_unlock(&ps->lock); - - if (signr) { - kill_pid_info_as_cred(sinfo.si_signo, &sinfo, pid, cred, secid); - put_pid(pid); - put_cred(cred); - } - - wake_up(&ps->wait); -} - -static void destroy_async(struct dev_state *ps, struct list_head *list) -{ - struct urb *urb; - struct async *as; - unsigned long flags; - - spin_lock_irqsave(&ps->lock, flags); - while (!list_empty(list)) { - as = list_entry(list->next, struct async, asynclist); - list_del_init(&as->asynclist); - urb = as->urb; - usb_get_urb(urb); - - /* drop the spinlock so the completion handler can run */ - spin_unlock_irqrestore(&ps->lock, flags); - usb_kill_urb(urb); - usb_put_urb(urb); - spin_lock_irqsave(&ps->lock, flags); - } - spin_unlock_irqrestore(&ps->lock, flags); -} - -static void destroy_async_on_interface(struct dev_state *ps, - unsigned int ifnum) -{ - struct list_head *p, *q, hitlist; - unsigned long flags; - - INIT_LIST_HEAD(&hitlist); - spin_lock_irqsave(&ps->lock, flags); - list_for_each_safe(p, q, &ps->async_pending) - if (ifnum == list_entry(p, struct async, asynclist)->ifnum) - list_move_tail(p, &hitlist); - spin_unlock_irqrestore(&ps->lock, flags); - destroy_async(ps, &hitlist); -} - -static void destroy_all_async(struct dev_state *ps) -{ - destroy_async(ps, &ps->async_pending); -} - -/* - * interface claims are made only at the request of user level code, - * which can also release them (explicitly or by closing files). - * they're also undone when devices disconnect. - */ - -static int driver_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - return -ENODEV; -} - -static void driver_disconnect(struct usb_interface *intf) -{ - struct dev_state *ps = usb_get_intfdata(intf); - unsigned int ifnum = intf->altsetting->desc.bInterfaceNumber; - - if (!ps) - return; - - /* NOTE: this relies on usbcore having canceled and completed - * all pending I/O requests; 2.6 does that. - */ - - if (likely(ifnum < 8*sizeof(ps->ifclaimed))) - clear_bit(ifnum, &ps->ifclaimed); - else - dev_warn(&intf->dev, "interface number %u out of range\n", - ifnum); - - usb_set_intfdata(intf, NULL); - - /* force async requests to complete */ - destroy_async_on_interface(ps, ifnum); -} - -/* The following routines are merely placeholders. There is no way - * to inform a user task about suspend or resumes. - */ -static int driver_suspend(struct usb_interface *intf, pm_message_t msg) -{ - return 0; -} - -static int driver_resume(struct usb_interface *intf) -{ - return 0; -} - -struct usb_driver usbfs_driver = { - .name = "usbfs", - .probe = driver_probe, - .disconnect = driver_disconnect, - .suspend = driver_suspend, - .resume = driver_resume, -}; - -static int claimintf(struct dev_state *ps, unsigned int ifnum) -{ - struct usb_device *dev = ps->dev; - struct usb_interface *intf; - int err; - - if (ifnum >= 8*sizeof(ps->ifclaimed)) - return -EINVAL; - /* already claimed */ - if (test_bit(ifnum, &ps->ifclaimed)) - return 0; - - intf = usb_ifnum_to_if(dev, ifnum); - if (!intf) - err = -ENOENT; - else - err = usb_driver_claim_interface(&usbfs_driver, intf, ps); - if (err == 0) - set_bit(ifnum, &ps->ifclaimed); - return err; -} - -static int releaseintf(struct dev_state *ps, unsigned int ifnum) -{ - struct usb_device *dev; - struct usb_interface *intf; - int err; - - err = -EINVAL; - if (ifnum >= 8*sizeof(ps->ifclaimed)) - return err; - dev = ps->dev; - intf = usb_ifnum_to_if(dev, ifnum); - if (!intf) - err = -ENOENT; - else if (test_and_clear_bit(ifnum, &ps->ifclaimed)) { - usb_driver_release_interface(&usbfs_driver, intf); - err = 0; - } - return err; -} - -static int checkintf(struct dev_state *ps, unsigned int ifnum) -{ - if (ps->dev->state != USB_STATE_CONFIGURED) - return -EHOSTUNREACH; - if (ifnum >= 8*sizeof(ps->ifclaimed)) - return -EINVAL; - if (test_bit(ifnum, &ps->ifclaimed)) - return 0; - /* if not yet claimed, claim it for the driver */ - dev_warn(&ps->dev->dev, "usbfs: process %d (%s) did not claim " - "interface %u before use\n", task_pid_nr(current), - current->comm, ifnum); - return claimintf(ps, ifnum); -} - -static int findintfep(struct usb_device *dev, unsigned int ep) -{ - unsigned int i, j, e; - struct usb_interface *intf; - struct usb_host_interface *alts; - struct usb_endpoint_descriptor *endpt; - - if (ep & ~(USB_DIR_IN|0xf)) - return -EINVAL; - if (!dev->actconfig) - return -ESRCH; - for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { - intf = dev->actconfig->interface[i]; - for (j = 0; j < intf->num_altsetting; j++) { - alts = &intf->altsetting[j]; - for (e = 0; e < alts->desc.bNumEndpoints; e++) { - endpt = &alts->endpoint[e].desc; - if (endpt->bEndpointAddress == ep) - return alts->desc.bInterfaceNumber; - } - } - } - return -ENOENT; -} - -static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, - unsigned int request, unsigned int index) -{ - int ret = 0; - struct usb_host_interface *alt_setting; - - if (ps->dev->state != USB_STATE_UNAUTHENTICATED - && ps->dev->state != USB_STATE_ADDRESS - && ps->dev->state != USB_STATE_CONFIGURED) - return -EHOSTUNREACH; - if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype)) - return 0; - - /* - * check for the special corner case 'get_device_id' in the printer - * class specification, where wIndex is (interface << 8 | altsetting) - * instead of just interface - */ - if (requesttype == 0xa1 && request == 0) { - alt_setting = usb_find_alt_setting(ps->dev->actconfig, - index >> 8, index & 0xff); - if (alt_setting - && alt_setting->desc.bInterfaceClass == USB_CLASS_PRINTER) - index >>= 8; - } - - index &= 0xff; - switch (requesttype & USB_RECIP_MASK) { - case USB_RECIP_ENDPOINT: - ret = findintfep(ps->dev, index); - if (ret >= 0) - ret = checkintf(ps, ret); - break; - - case USB_RECIP_INTERFACE: - ret = checkintf(ps, index); - break; - } - return ret; -} - -static int match_devt(struct device *dev, void *data) -{ - return dev->devt == (dev_t) (unsigned long) data; -} - -static struct usb_device *usbdev_lookup_by_devt(dev_t devt) -{ - struct device *dev; - - dev = bus_find_device(&usb_bus_type, NULL, - (void *) (unsigned long) devt, match_devt); - if (!dev) - return NULL; - return container_of(dev, struct usb_device, dev); -} - -/* - * file operations - */ -static int usbdev_open(struct inode *inode, struct file *file) -{ - struct usb_device *dev = NULL; - struct dev_state *ps; - int ret; - - ret = -ENOMEM; - ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL); - if (!ps) - goto out_free_ps; - - ret = -ENODEV; - - /* Protect against simultaneous removal or release */ - mutex_lock(&usbfs_mutex); - - /* usbdev device-node */ - if (imajor(inode) == USB_DEVICE_MAJOR) - dev = usbdev_lookup_by_devt(inode->i_rdev); - -#ifdef CONFIG_USB_DEVICEFS - /* procfs file */ - if (!dev) { - dev = inode->i_private; - if (dev && dev->usbfs_dentry && - dev->usbfs_dentry->d_inode == inode) - usb_get_dev(dev); - else - dev = NULL; - } -#endif - mutex_unlock(&usbfs_mutex); - - if (!dev) - goto out_free_ps; - - usb_lock_device(dev); - if (dev->state == USB_STATE_NOTATTACHED) - goto out_unlock_device; - - ret = usb_autoresume_device(dev); - if (ret) - goto out_unlock_device; - - ps->dev = dev; - ps->file = file; - spin_lock_init(&ps->lock); - INIT_LIST_HEAD(&ps->list); - INIT_LIST_HEAD(&ps->async_pending); - INIT_LIST_HEAD(&ps->async_completed); - init_waitqueue_head(&ps->wait); - ps->discsignr = 0; - ps->disc_pid = get_pid(task_pid(current)); - ps->cred = get_current_cred(); - ps->disccontext = NULL; - ps->ifclaimed = 0; - security_task_getsecid(current, &ps->secid); - smp_wmb(); - list_add_tail(&ps->list, &dev->filelist); - file->private_data = ps; - usb_unlock_device(dev); - snoop(&dev->dev, "opened by process %d: %s\n", task_pid_nr(current), - current->comm); - return ret; - - out_unlock_device: - usb_unlock_device(dev); - usb_put_dev(dev); - out_free_ps: - kfree(ps); - return ret; -} - -static int usbdev_release(struct inode *inode, struct file *file) -{ - struct dev_state *ps = file->private_data; - struct usb_device *dev = ps->dev; - unsigned int ifnum; - struct async *as; - - usb_lock_device(dev); - usb_hub_release_all_ports(dev, ps); - - list_del_init(&ps->list); - - for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed); - ifnum++) { - if (test_bit(ifnum, &ps->ifclaimed)) - releaseintf(ps, ifnum); - } - destroy_all_async(ps); - usb_autosuspend_device(dev); - usb_unlock_device(dev); - usb_put_dev(dev); - put_pid(ps->disc_pid); - put_cred(ps->cred); - - as = async_getcompleted(ps); - while (as) { - free_async(as); - as = async_getcompleted(ps); - } - kfree(ps); - return 0; -} - -static int proc_control(struct dev_state *ps, void __user *arg) -{ - struct usb_device *dev = ps->dev; - struct usbdevfs_ctrltransfer ctrl; - unsigned int tmo; - unsigned char *tbuf; - unsigned wLength; - int i, pipe, ret; - - if (copy_from_user(&ctrl, arg, sizeof(ctrl))) - return -EFAULT; - ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.bRequest, - ctrl.wIndex); - if (ret) - return ret; - wLength = ctrl.wLength; /* To suppress 64k PAGE_SIZE warning */ - if (wLength > PAGE_SIZE) - return -EINVAL; - ret = usbfs_increase_memory_usage(PAGE_SIZE + sizeof(struct urb) + - sizeof(struct usb_ctrlrequest)); - if (ret) - return ret; - tbuf = (unsigned char *)__get_free_page(GFP_KERNEL); - if (!tbuf) { - ret = -ENOMEM; - goto done; - } - tmo = ctrl.timeout; - snoop(&dev->dev, "control urb: bRequestType=%02x " - "bRequest=%02x wValue=%04x " - "wIndex=%04x wLength=%04x\n", - ctrl.bRequestType, ctrl.bRequest, - __le16_to_cpup(&ctrl.wValue), - __le16_to_cpup(&ctrl.wIndex), - __le16_to_cpup(&ctrl.wLength)); - if (ctrl.bRequestType & 0x80) { - if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data, - ctrl.wLength)) { - ret = -EINVAL; - goto done; - } - pipe = usb_rcvctrlpipe(dev, 0); - snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT, NULL, 0); - - usb_unlock_device(dev); - i = usb_control_msg(dev, pipe, ctrl.bRequest, - ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, - tbuf, ctrl.wLength, tmo); - usb_lock_device(dev); - snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE, - tbuf, max(i, 0)); - if ((i > 0) && ctrl.wLength) { - if (copy_to_user(ctrl.data, tbuf, i)) { - ret = -EFAULT; - goto done; - } - } - } else { - if (ctrl.wLength) { - if (copy_from_user(tbuf, ctrl.data, ctrl.wLength)) { - ret = -EFAULT; - goto done; - } - } - pipe = usb_sndctrlpipe(dev, 0); - snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT, - tbuf, ctrl.wLength); - - usb_unlock_device(dev); - i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, - ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, - tbuf, ctrl.wLength, tmo); - usb_lock_device(dev); - snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE, NULL, 0); - } - if (i < 0 && i != -EPIPE) { - dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL " - "failed cmd %s rqt %u rq %u len %u ret %d\n", - current->comm, ctrl.bRequestType, ctrl.bRequest, - ctrl.wLength, i); - } - ret = i; - done: - free_page((unsigned long) tbuf); - usbfs_decrease_memory_usage(PAGE_SIZE + sizeof(struct urb) + - sizeof(struct usb_ctrlrequest)); - return ret; -} - -static int proc_bulk(struct dev_state *ps, void __user *arg) -{ - struct usb_device *dev = ps->dev; - struct usbdevfs_bulktransfer bulk; - unsigned int tmo, len1, pipe; - int len2; - unsigned char *tbuf; - int i, ret; - - if (copy_from_user(&bulk, arg, sizeof(bulk))) - return -EFAULT; - ret = findintfep(ps->dev, bulk.ep); - if (ret < 0) - return ret; - ret = checkintf(ps, ret); - if (ret) - return ret; - if (bulk.ep & USB_DIR_IN) - pipe = usb_rcvbulkpipe(dev, bulk.ep & 0x7f); - else - pipe = usb_sndbulkpipe(dev, bulk.ep & 0x7f); - if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN))) - return -EINVAL; - len1 = bulk.len; - if (len1 >= USBFS_XFER_MAX) - return -EINVAL; - ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb)); - if (ret) - return ret; - if (!(tbuf = kmalloc(len1, GFP_KERNEL))) { - ret = -ENOMEM; - goto done; - } - tmo = bulk.timeout; - if (bulk.ep & 0x80) { - if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) { - ret = -EINVAL; - goto done; - } - snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, NULL, 0); - - usb_unlock_device(dev); - i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); - usb_lock_device(dev); - snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, tbuf, len2); - - if (!i && len2) { - if (copy_to_user(bulk.data, tbuf, len2)) { - ret = -EFAULT; - goto done; - } - } - } else { - if (len1) { - if (copy_from_user(tbuf, bulk.data, len1)) { - ret = -EFAULT; - goto done; - } - } - snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, tbuf, len1); - - usb_unlock_device(dev); - i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); - usb_lock_device(dev); - snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, NULL, 0); - } - ret = (i < 0 ? i : len2); - done: - kfree(tbuf); - usbfs_decrease_memory_usage(len1 + sizeof(struct urb)); - return ret; -} - -static int proc_resetep(struct dev_state *ps, void __user *arg) -{ - unsigned int ep; - int ret; - - if (get_user(ep, (unsigned int __user *)arg)) - return -EFAULT; - ret = findintfep(ps->dev, ep); - if (ret < 0) - return ret; - ret = checkintf(ps, ret); - if (ret) - return ret; - usb_reset_endpoint(ps->dev, ep); - return 0; -} - -static int proc_clearhalt(struct dev_state *ps, void __user *arg) -{ - unsigned int ep; - int pipe; - int ret; - - if (get_user(ep, (unsigned int __user *)arg)) - return -EFAULT; - ret = findintfep(ps->dev, ep); - if (ret < 0) - return ret; - ret = checkintf(ps, ret); - if (ret) - return ret; - if (ep & USB_DIR_IN) - pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f); - else - pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f); - - return usb_clear_halt(ps->dev, pipe); -} - -static int proc_getdriver(struct dev_state *ps, void __user *arg) -{ - struct usbdevfs_getdriver gd; - struct usb_interface *intf; - int ret; - - if (copy_from_user(&gd, arg, sizeof(gd))) - return -EFAULT; - intf = usb_ifnum_to_if(ps->dev, gd.interface); - if (!intf || !intf->dev.driver) - ret = -ENODATA; - else { - strncpy(gd.driver, intf->dev.driver->name, - sizeof(gd.driver)); - ret = (copy_to_user(arg, &gd, sizeof(gd)) ? -EFAULT : 0); - } - return ret; -} - -static int proc_connectinfo(struct dev_state *ps, void __user *arg) -{ - struct usbdevfs_connectinfo ci = { - .devnum = ps->dev->devnum, - .slow = ps->dev->speed == USB_SPEED_LOW - }; - - if (copy_to_user(arg, &ci, sizeof(ci))) - return -EFAULT; - return 0; -} - -static int proc_resetdevice(struct dev_state *ps) -{ - return usb_reset_device(ps->dev); -} - -static int proc_setintf(struct dev_state *ps, void __user *arg) -{ - struct usbdevfs_setinterface setintf; - int ret; - - if (copy_from_user(&setintf, arg, sizeof(setintf))) - return -EFAULT; - if ((ret = checkintf(ps, setintf.interface))) - return ret; - return usb_set_interface(ps->dev, setintf.interface, - setintf.altsetting); -} - -static int proc_setconfig(struct dev_state *ps, void __user *arg) -{ - int u; - int status = 0; - struct usb_host_config *actconfig; - - if (get_user(u, (int __user *)arg)) - return -EFAULT; - - actconfig = ps->dev->actconfig; - - /* Don't touch the device if any interfaces are claimed. - * It could interfere with other drivers' operations, and if - * an interface is claimed by usbfs it could easily deadlock. - */ - if (actconfig) { - int i; - - for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) { - if (usb_interface_claimed(actconfig->interface[i])) { - dev_warn(&ps->dev->dev, - "usbfs: interface %d claimed by %s " - "while '%s' sets config #%d\n", - actconfig->interface[i] - ->cur_altsetting - ->desc.bInterfaceNumber, - actconfig->interface[i] - ->dev.driver->name, - current->comm, u); - status = -EBUSY; - break; - } - } - } - - /* SET_CONFIGURATION is often abused as a "cheap" driver reset, - * so avoid usb_set_configuration()'s kick to sysfs - */ - if (status == 0) { - if (actconfig && actconfig->desc.bConfigurationValue == u) - status = usb_reset_configuration(ps->dev); - else - status = usb_set_configuration(ps->dev, u); - } - - return status; -} - -static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, - struct usbdevfs_iso_packet_desc __user *iso_frame_desc, - void __user *arg) -{ - struct usbdevfs_iso_packet_desc *isopkt = NULL; - struct usb_host_endpoint *ep; - struct async *as = NULL; - struct usb_ctrlrequest *dr = NULL; - unsigned int u, totlen, isofrmlen; - int ret, ifnum = -1; - int is_in; - - if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP | - USBDEVFS_URB_SHORT_NOT_OK | - USBDEVFS_URB_BULK_CONTINUATION | - USBDEVFS_URB_NO_FSBR | - USBDEVFS_URB_ZERO_PACKET | - USBDEVFS_URB_NO_INTERRUPT)) - return -EINVAL; - if (uurb->buffer_length > 0 && !uurb->buffer) - return -EINVAL; - if (!(uurb->type == USBDEVFS_URB_TYPE_CONTROL && - (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) { - ifnum = findintfep(ps->dev, uurb->endpoint); - if (ifnum < 0) - return ifnum; - ret = checkintf(ps, ifnum); - if (ret) - return ret; - } - if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) { - is_in = 1; - ep = ps->dev->ep_in[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; - } else { - is_in = 0; - ep = ps->dev->ep_out[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; - } - if (!ep) - return -ENOENT; - - u = 0; - switch(uurb->type) { - case USBDEVFS_URB_TYPE_CONTROL: - if (!usb_endpoint_xfer_control(&ep->desc)) - return -EINVAL; - /* min 8 byte setup packet */ - if (uurb->buffer_length < 8) - return -EINVAL; - dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); - if (!dr) - return -ENOMEM; - if (copy_from_user(dr, uurb->buffer, 8)) { - ret = -EFAULT; - goto error; - } - if (uurb->buffer_length < (le16_to_cpup(&dr->wLength) + 8)) { - ret = -EINVAL; - goto error; - } - ret = check_ctrlrecip(ps, dr->bRequestType, dr->bRequest, - le16_to_cpup(&dr->wIndex)); - if (ret) - goto error; - uurb->number_of_packets = 0; - uurb->buffer_length = le16_to_cpup(&dr->wLength); - uurb->buffer += 8; - if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) { - is_in = 1; - uurb->endpoint |= USB_DIR_IN; - } else { - is_in = 0; - uurb->endpoint &= ~USB_DIR_IN; - } - snoop(&ps->dev->dev, "control urb: bRequestType=%02x " - "bRequest=%02x wValue=%04x " - "wIndex=%04x wLength=%04x\n", - dr->bRequestType, dr->bRequest, - __le16_to_cpup(&dr->wValue), - __le16_to_cpup(&dr->wIndex), - __le16_to_cpup(&dr->wLength)); - u = sizeof(struct usb_ctrlrequest); - break; - - case USBDEVFS_URB_TYPE_BULK: - switch (usb_endpoint_type(&ep->desc)) { - case USB_ENDPOINT_XFER_CONTROL: - case USB_ENDPOINT_XFER_ISOC: - return -EINVAL; - case USB_ENDPOINT_XFER_INT: - /* allow single-shot interrupt transfers */ - uurb->type = USBDEVFS_URB_TYPE_INTERRUPT; - goto interrupt_urb; - } - uurb->number_of_packets = 0; - break; - - case USBDEVFS_URB_TYPE_INTERRUPT: - if (!usb_endpoint_xfer_int(&ep->desc)) - return -EINVAL; - interrupt_urb: - uurb->number_of_packets = 0; - break; - - case USBDEVFS_URB_TYPE_ISO: - /* arbitrary limit */ - if (uurb->number_of_packets < 1 || - uurb->number_of_packets > 128) - return -EINVAL; - if (!usb_endpoint_xfer_isoc(&ep->desc)) - return -EINVAL; - isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * - uurb->number_of_packets; - if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL))) - return -ENOMEM; - if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) { - ret = -EFAULT; - goto error; - } - for (totlen = u = 0; u < uurb->number_of_packets; u++) { - /* arbitrary limit, - * sufficient for USB 2.0 high-bandwidth iso */ - if (isopkt[u].length > 8192) { - ret = -EINVAL; - goto error; - } - totlen += isopkt[u].length; - } - u *= sizeof(struct usb_iso_packet_descriptor); - uurb->buffer_length = totlen; - break; - - default: - return -EINVAL; - } - - if (uurb->buffer_length >= USBFS_XFER_MAX) { - ret = -EINVAL; - goto error; - } - if (uurb->buffer_length > 0 && - !access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, - uurb->buffer, uurb->buffer_length)) { - ret = -EFAULT; - goto error; - } - as = alloc_async(uurb->number_of_packets); - if (!as) { - ret = -ENOMEM; - goto error; - } - u += sizeof(struct async) + sizeof(struct urb) + uurb->buffer_length; - ret = usbfs_increase_memory_usage(u); - if (ret) - goto error; - as->mem_usage = u; - - if (uurb->buffer_length > 0) { - as->urb->transfer_buffer = kmalloc(uurb->buffer_length, - GFP_KERNEL); - if (!as->urb->transfer_buffer) { - ret = -ENOMEM; - goto error; - } - /* Isochronous input data may end up being discontiguous - * if some of the packets are short. Clear the buffer so - * that the gaps don't leak kernel data to userspace. - */ - if (is_in && uurb->type == USBDEVFS_URB_TYPE_ISO) - memset(as->urb->transfer_buffer, 0, - uurb->buffer_length); - } - as->urb->dev = ps->dev; - as->urb->pipe = (uurb->type << 30) | - __create_pipe(ps->dev, uurb->endpoint & 0xf) | - (uurb->endpoint & USB_DIR_IN); - - /* This tedious sequence is necessary because the URB_* flags - * are internal to the kernel and subject to change, whereas - * the USBDEVFS_URB_* flags are a user API and must not be changed. - */ - u = (is_in ? URB_DIR_IN : URB_DIR_OUT); - if (uurb->flags & USBDEVFS_URB_ISO_ASAP) - u |= URB_ISO_ASAP; - if (uurb->flags & USBDEVFS_URB_SHORT_NOT_OK) - u |= URB_SHORT_NOT_OK; - if (uurb->flags & USBDEVFS_URB_NO_FSBR) - u |= URB_NO_FSBR; - if (uurb->flags & USBDEVFS_URB_ZERO_PACKET) - u |= URB_ZERO_PACKET; - if (uurb->flags & USBDEVFS_URB_NO_INTERRUPT) - u |= URB_NO_INTERRUPT; - as->urb->transfer_flags = u; - - as->urb->transfer_buffer_length = uurb->buffer_length; - as->urb->setup_packet = (unsigned char *)dr; - dr = NULL; - as->urb->start_frame = uurb->start_frame; - as->urb->number_of_packets = uurb->number_of_packets; - if (uurb->type == USBDEVFS_URB_TYPE_ISO || - ps->dev->speed == USB_SPEED_HIGH) - as->urb->interval = 1 << min(15, ep->desc.bInterval - 1); - else - as->urb->interval = ep->desc.bInterval; - as->urb->context = as; - as->urb->complete = async_completed; - for (totlen = u = 0; u < uurb->number_of_packets; u++) { - as->urb->iso_frame_desc[u].offset = totlen; - as->urb->iso_frame_desc[u].length = isopkt[u].length; - totlen += isopkt[u].length; - } - kfree(isopkt); - isopkt = NULL; - as->ps = ps; - as->userurb = arg; - if (is_in && uurb->buffer_length > 0) - as->userbuffer = uurb->buffer; - else - as->userbuffer = NULL; - as->signr = uurb->signr; - as->ifnum = ifnum; - as->pid = get_pid(task_pid(current)); - as->cred = get_current_cred(); - security_task_getsecid(current, &as->secid); - if (!is_in && uurb->buffer_length > 0) { - if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, - uurb->buffer_length)) { - ret = -EFAULT; - goto error; - } - } - snoop_urb(ps->dev, as->userurb, as->urb->pipe, - as->urb->transfer_buffer_length, 0, SUBMIT, - is_in ? NULL : as->urb->transfer_buffer, - uurb->buffer_length); - async_newpending(as); - - if (usb_endpoint_xfer_bulk(&ep->desc)) { - spin_lock_irq(&ps->lock); - - /* Not exactly the endpoint address; the direction bit is - * shifted to the 0x10 position so that the value will be - * between 0 and 31. - */ - as->bulk_addr = usb_endpoint_num(&ep->desc) | - ((ep->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) - >> 3); - - /* If this bulk URB is the start of a new transfer, re-enable - * the endpoint. Otherwise mark it as a continuation URB. - */ - if (uurb->flags & USBDEVFS_URB_BULK_CONTINUATION) - as->bulk_status = AS_CONTINUATION; - else - ps->disabled_bulk_eps &= ~(1 << as->bulk_addr); - - /* Don't accept continuation URBs if the endpoint is - * disabled because of an earlier error. - */ - if (ps->disabled_bulk_eps & (1 << as->bulk_addr)) - ret = -EREMOTEIO; - else - ret = usb_submit_urb(as->urb, GFP_ATOMIC); - spin_unlock_irq(&ps->lock); - } else { - ret = usb_submit_urb(as->urb, GFP_KERNEL); - } - - if (ret) { - dev_printk(KERN_DEBUG, &ps->dev->dev, - "usbfs: usb_submit_urb returned %d\n", ret); - snoop_urb(ps->dev, as->userurb, as->urb->pipe, - 0, ret, COMPLETE, NULL, 0); - async_removepending(as); - goto error; - } - return 0; - - error: - kfree(isopkt); - kfree(dr); - if (as) - free_async(as); - return ret; -} - -static int proc_submiturb(struct dev_state *ps, void __user *arg) -{ - struct usbdevfs_urb uurb; - - if (copy_from_user(&uurb, arg, sizeof(uurb))) - return -EFAULT; - - return proc_do_submiturb(ps, &uurb, - (((struct usbdevfs_urb __user *)arg)->iso_frame_desc), - arg); -} - -static int proc_unlinkurb(struct dev_state *ps, void __user *arg) -{ - struct urb *urb; - struct async *as; - unsigned long flags; - - spin_lock_irqsave(&ps->lock, flags); - as = async_getpending(ps, arg); - if (!as) { - spin_unlock_irqrestore(&ps->lock, flags); - return -EINVAL; - } - - urb = as->urb; - usb_get_urb(urb); - spin_unlock_irqrestore(&ps->lock, flags); - - usb_kill_urb(urb); - usb_put_urb(urb); - - return 0; -} - -static int processcompl(struct async *as, void __user * __user *arg) -{ - struct urb *urb = as->urb; - struct usbdevfs_urb __user *userurb = as->userurb; - void __user *addr = as->userurb; - unsigned int i; - - if (as->userbuffer && urb->actual_length) { - if (urb->number_of_packets > 0) /* Isochronous */ - i = urb->transfer_buffer_length; - else /* Non-Isoc */ - i = urb->actual_length; - if (copy_to_user(as->userbuffer, urb->transfer_buffer, i)) - goto err_out; - } - if (put_user(as->status, &userurb->status)) - goto err_out; - if (put_user(urb->actual_length, &userurb->actual_length)) - goto err_out; - if (put_user(urb->error_count, &userurb->error_count)) - goto err_out; - - if (usb_endpoint_xfer_isoc(&urb->ep->desc)) { - for (i = 0; i < urb->number_of_packets; i++) { - if (put_user(urb->iso_frame_desc[i].actual_length, - &userurb->iso_frame_desc[i].actual_length)) - goto err_out; - if (put_user(urb->iso_frame_desc[i].status, - &userurb->iso_frame_desc[i].status)) - goto err_out; - } - } - - if (put_user(addr, (void __user * __user *)arg)) - return -EFAULT; - return 0; - -err_out: - return -EFAULT; -} - -static struct async *reap_as(struct dev_state *ps) -{ - DECLARE_WAITQUEUE(wait, current); - struct async *as = NULL; - struct usb_device *dev = ps->dev; - - add_wait_queue(&ps->wait, &wait); - for (;;) { - __set_current_state(TASK_INTERRUPTIBLE); - as = async_getcompleted(ps); - if (as) - break; - if (signal_pending(current)) - break; - usb_unlock_device(dev); - schedule(); - usb_lock_device(dev); - } - remove_wait_queue(&ps->wait, &wait); - set_current_state(TASK_RUNNING); - return as; -} - -static int proc_reapurb(struct dev_state *ps, void __user *arg) -{ - struct async *as = reap_as(ps); - if (as) { - int retval = processcompl(as, (void __user * __user *)arg); - free_async(as); - return retval; - } - if (signal_pending(current)) - return -EINTR; - return -EIO; -} - -static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg) -{ - int retval; - struct async *as; - - as = async_getcompleted(ps); - retval = -EAGAIN; - if (as) { - retval = processcompl(as, (void __user * __user *)arg); - free_async(as); - } - return retval; -} - -#ifdef CONFIG_COMPAT -static int proc_control_compat(struct dev_state *ps, - struct usbdevfs_ctrltransfer32 __user *p32) -{ - struct usbdevfs_ctrltransfer __user *p; - __u32 udata; - p = compat_alloc_user_space(sizeof(*p)); - if (copy_in_user(p, p32, (sizeof(*p32) - sizeof(compat_caddr_t))) || - get_user(udata, &p32->data) || - put_user(compat_ptr(udata), &p->data)) - return -EFAULT; - return proc_control(ps, p); -} - -static int proc_bulk_compat(struct dev_state *ps, - struct usbdevfs_bulktransfer32 __user *p32) -{ - struct usbdevfs_bulktransfer __user *p; - compat_uint_t n; - compat_caddr_t addr; - - p = compat_alloc_user_space(sizeof(*p)); - - if (get_user(n, &p32->ep) || put_user(n, &p->ep) || - get_user(n, &p32->len) || put_user(n, &p->len) || - get_user(n, &p32->timeout) || put_user(n, &p->timeout) || - get_user(addr, &p32->data) || put_user(compat_ptr(addr), &p->data)) - return -EFAULT; - - return proc_bulk(ps, p); -} -static int proc_disconnectsignal_compat(struct dev_state *ps, void __user *arg) -{ - struct usbdevfs_disconnectsignal32 ds; - - if (copy_from_user(&ds, arg, sizeof(ds))) - return -EFAULT; - ps->discsignr = ds.signr; - ps->disccontext = compat_ptr(ds.context); - return 0; -} - -static int get_urb32(struct usbdevfs_urb *kurb, - struct usbdevfs_urb32 __user *uurb) -{ - __u32 uptr; - if (!access_ok(VERIFY_READ, uurb, sizeof(*uurb)) || - __get_user(kurb->type, &uurb->type) || - __get_user(kurb->endpoint, &uurb->endpoint) || - __get_user(kurb->status, &uurb->status) || - __get_user(kurb->flags, &uurb->flags) || - __get_user(kurb->buffer_length, &uurb->buffer_length) || - __get_user(kurb->actual_length, &uurb->actual_length) || - __get_user(kurb->start_frame, &uurb->start_frame) || - __get_user(kurb->number_of_packets, &uurb->number_of_packets) || - __get_user(kurb->error_count, &uurb->error_count) || - __get_user(kurb->signr, &uurb->signr)) - return -EFAULT; - - if (__get_user(uptr, &uurb->buffer)) - return -EFAULT; - kurb->buffer = compat_ptr(uptr); - if (__get_user(uptr, &uurb->usercontext)) - return -EFAULT; - kurb->usercontext = compat_ptr(uptr); - - return 0; -} - -static int proc_submiturb_compat(struct dev_state *ps, void __user *arg) -{ - struct usbdevfs_urb uurb; - - if (get_urb32(&uurb, (struct usbdevfs_urb32 __user *)arg)) - return -EFAULT; - - return proc_do_submiturb(ps, &uurb, - ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc, - arg); -} - -static int processcompl_compat(struct async *as, void __user * __user *arg) -{ - struct urb *urb = as->urb; - struct usbdevfs_urb32 __user *userurb = as->userurb; - void __user *addr = as->userurb; - unsigned int i; - - if (as->userbuffer && urb->actual_length) - if (copy_to_user(as->userbuffer, urb->transfer_buffer, - urb->actual_length)) - return -EFAULT; - if (put_user(as->status, &userurb->status)) - return -EFAULT; - if (put_user(urb->actual_length, &userurb->actual_length)) - return -EFAULT; - if (put_user(urb->error_count, &userurb->error_count)) - return -EFAULT; - - if (usb_endpoint_xfer_isoc(&urb->ep->desc)) { - for (i = 0; i < urb->number_of_packets; i++) { - if (put_user(urb->iso_frame_desc[i].actual_length, - &userurb->iso_frame_desc[i].actual_length)) - return -EFAULT; - if (put_user(urb->iso_frame_desc[i].status, - &userurb->iso_frame_desc[i].status)) - return -EFAULT; - } - } - - if (put_user(ptr_to_compat(addr), (u32 __user *)arg)) - return -EFAULT; - return 0; -} - -static int proc_reapurb_compat(struct dev_state *ps, void __user *arg) -{ - struct async *as = reap_as(ps); - if (as) { - int retval = processcompl_compat(as, (void __user * __user *)arg); - free_async(as); - return retval; - } - if (signal_pending(current)) - return -EINTR; - return -EIO; -} - -static int proc_reapurbnonblock_compat(struct dev_state *ps, void __user *arg) -{ - int retval; - struct async *as; - - retval = -EAGAIN; - as = async_getcompleted(ps); - if (as) { - retval = processcompl_compat(as, (void __user * __user *)arg); - free_async(as); - } - return retval; -} - - -#endif - -static int proc_disconnectsignal(struct dev_state *ps, void __user *arg) -{ - struct usbdevfs_disconnectsignal ds; - - if (copy_from_user(&ds, arg, sizeof(ds))) - return -EFAULT; - ps->discsignr = ds.signr; - ps->disccontext = ds.context; - return 0; -} - -static int proc_claiminterface(struct dev_state *ps, void __user *arg) -{ - unsigned int ifnum; - - if (get_user(ifnum, (unsigned int __user *)arg)) - return -EFAULT; - return claimintf(ps, ifnum); -} - -static int proc_releaseinterface(struct dev_state *ps, void __user *arg) -{ - unsigned int ifnum; - int ret; - - if (get_user(ifnum, (unsigned int __user *)arg)) - return -EFAULT; - if ((ret = releaseintf(ps, ifnum)) < 0) - return ret; - destroy_async_on_interface (ps, ifnum); - return 0; -} - -static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) -{ - int size; - void *buf = NULL; - int retval = 0; - struct usb_interface *intf = NULL; - struct usb_driver *driver = NULL; - - /* alloc buffer */ - if ((size = _IOC_SIZE(ctl->ioctl_code)) > 0) { - if ((buf = kmalloc(size, GFP_KERNEL)) == NULL) - return -ENOMEM; - if ((_IOC_DIR(ctl->ioctl_code) & _IOC_WRITE)) { - if (copy_from_user(buf, ctl->data, size)) { - kfree(buf); - return -EFAULT; - } - } else { - memset(buf, 0, size); - } - } - - if (!connected(ps)) { - kfree(buf); - return -ENODEV; - } - - if (ps->dev->state != USB_STATE_CONFIGURED) - retval = -EHOSTUNREACH; - else if (!(intf = usb_ifnum_to_if(ps->dev, ctl->ifno))) - retval = -EINVAL; - else switch (ctl->ioctl_code) { - - /* disconnect kernel driver from interface */ - case USBDEVFS_DISCONNECT: - if (intf->dev.driver) { - driver = to_usb_driver(intf->dev.driver); - dev_dbg(&intf->dev, "disconnect by usbfs\n"); - usb_driver_release_interface(driver, intf); - } else - retval = -ENODATA; - break; - - /* let kernel drivers try to (re)bind to the interface */ - case USBDEVFS_CONNECT: - if (!intf->dev.driver) - retval = device_attach(&intf->dev); - else - retval = -EBUSY; - break; - - /* talk directly to the interface's driver */ - default: - if (intf->dev.driver) - driver = to_usb_driver(intf->dev.driver); - if (driver == NULL || driver->unlocked_ioctl == NULL) { - retval = -ENOTTY; - } else { - retval = driver->unlocked_ioctl(intf, ctl->ioctl_code, buf); - if (retval == -ENOIOCTLCMD) - retval = -ENOTTY; - } - } - - /* cleanup and return */ - if (retval >= 0 - && (_IOC_DIR(ctl->ioctl_code) & _IOC_READ) != 0 - && size > 0 - && copy_to_user(ctl->data, buf, size) != 0) - retval = -EFAULT; - - kfree(buf); - return retval; -} - -static int proc_ioctl_default(struct dev_state *ps, void __user *arg) -{ - struct usbdevfs_ioctl ctrl; - - if (copy_from_user(&ctrl, arg, sizeof(ctrl))) - return -EFAULT; - return proc_ioctl(ps, &ctrl); -} - -#ifdef CONFIG_COMPAT -static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg) -{ - struct usbdevfs_ioctl32 __user *uioc; - struct usbdevfs_ioctl ctrl; - u32 udata; - - uioc = compat_ptr((long)arg); - if (!access_ok(VERIFY_READ, uioc, sizeof(*uioc)) || - __get_user(ctrl.ifno, &uioc->ifno) || - __get_user(ctrl.ioctl_code, &uioc->ioctl_code) || - __get_user(udata, &uioc->data)) - return -EFAULT; - ctrl.data = compat_ptr(udata); - - return proc_ioctl(ps, &ctrl); -} -#endif - -static int proc_claim_port(struct dev_state *ps, void __user *arg) -{ - unsigned portnum; - int rc; - - if (get_user(portnum, (unsigned __user *) arg)) - return -EFAULT; - rc = usb_hub_claim_port(ps->dev, portnum, ps); - if (rc == 0) - snoop(&ps->dev->dev, "port %d claimed by process %d: %s\n", - portnum, task_pid_nr(current), current->comm); - return rc; -} - -static int proc_release_port(struct dev_state *ps, void __user *arg) -{ - unsigned portnum; - - if (get_user(portnum, (unsigned __user *) arg)) - return -EFAULT; - return usb_hub_release_port(ps->dev, portnum, ps); -} - -/* - * NOTE: All requests here that have interface numbers as parameters - * are assuming that somehow the configuration has been prevented from - * changing. But there's no mechanism to ensure that... - */ -static long usbdev_do_ioctl(struct file *file, unsigned int cmd, - void __user *p) -{ - struct dev_state *ps = file->private_data; - struct inode *inode = file->f_path.dentry->d_inode; - struct usb_device *dev = ps->dev; - int ret = -ENOTTY; - - if (!(file->f_mode & FMODE_WRITE)) - return -EPERM; - - usb_lock_device(dev); - if (!connected(ps)) { - usb_unlock_device(dev); - return -ENODEV; - } - - switch (cmd) { - case USBDEVFS_CONTROL: - snoop(&dev->dev, "%s: CONTROL\n", __func__); - ret = proc_control(ps, p); - if (ret >= 0) - inode->i_mtime = CURRENT_TIME; - break; - - case USBDEVFS_BULK: - snoop(&dev->dev, "%s: BULK\n", __func__); - ret = proc_bulk(ps, p); - if (ret >= 0) - inode->i_mtime = CURRENT_TIME; - break; - - case USBDEVFS_RESETEP: - snoop(&dev->dev, "%s: RESETEP\n", __func__); - ret = proc_resetep(ps, p); - if (ret >= 0) - inode->i_mtime = CURRENT_TIME; - break; - - case USBDEVFS_RESET: - snoop(&dev->dev, "%s: RESET\n", __func__); - ret = proc_resetdevice(ps); - break; - - case USBDEVFS_CLEAR_HALT: - snoop(&dev->dev, "%s: CLEAR_HALT\n", __func__); - ret = proc_clearhalt(ps, p); - if (ret >= 0) - inode->i_mtime = CURRENT_TIME; - break; - - case USBDEVFS_GETDRIVER: - snoop(&dev->dev, "%s: GETDRIVER\n", __func__); - ret = proc_getdriver(ps, p); - break; - - case USBDEVFS_CONNECTINFO: - snoop(&dev->dev, "%s: CONNECTINFO\n", __func__); - ret = proc_connectinfo(ps, p); - break; - - case USBDEVFS_SETINTERFACE: - snoop(&dev->dev, "%s: SETINTERFACE\n", __func__); - ret = proc_setintf(ps, p); - break; - - case USBDEVFS_SETCONFIGURATION: - snoop(&dev->dev, "%s: SETCONFIGURATION\n", __func__); - ret = proc_setconfig(ps, p); - break; - - case USBDEVFS_SUBMITURB: - snoop(&dev->dev, "%s: SUBMITURB\n", __func__); - ret = proc_submiturb(ps, p); - if (ret >= 0) - inode->i_mtime = CURRENT_TIME; - break; - -#ifdef CONFIG_COMPAT - case USBDEVFS_CONTROL32: - snoop(&dev->dev, "%s: CONTROL32\n", __func__); - ret = proc_control_compat(ps, p); - if (ret >= 0) - inode->i_mtime = CURRENT_TIME; - break; - - case USBDEVFS_BULK32: - snoop(&dev->dev, "%s: BULK32\n", __func__); - ret = proc_bulk_compat(ps, p); - if (ret >= 0) - inode->i_mtime = CURRENT_TIME; - break; - - case USBDEVFS_DISCSIGNAL32: - snoop(&dev->dev, "%s: DISCSIGNAL32\n", __func__); - ret = proc_disconnectsignal_compat(ps, p); - break; - - case USBDEVFS_SUBMITURB32: - snoop(&dev->dev, "%s: SUBMITURB32\n", __func__); - ret = proc_submiturb_compat(ps, p); - if (ret >= 0) - inode->i_mtime = CURRENT_TIME; - break; - - case USBDEVFS_REAPURB32: - snoop(&dev->dev, "%s: REAPURB32\n", __func__); - ret = proc_reapurb_compat(ps, p); - break; - - case USBDEVFS_REAPURBNDELAY32: - snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__); - ret = proc_reapurbnonblock_compat(ps, p); - break; - - case USBDEVFS_IOCTL32: - snoop(&dev->dev, "%s: IOCTL32\n", __func__); - ret = proc_ioctl_compat(ps, ptr_to_compat(p)); - break; -#endif - - case USBDEVFS_DISCARDURB: - snoop(&dev->dev, "%s: DISCARDURB\n", __func__); - ret = proc_unlinkurb(ps, p); - break; - - case USBDEVFS_REAPURB: - snoop(&dev->dev, "%s: REAPURB\n", __func__); - ret = proc_reapurb(ps, p); - break; - - case USBDEVFS_REAPURBNDELAY: - snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__); - ret = proc_reapurbnonblock(ps, p); - break; - - case USBDEVFS_DISCSIGNAL: - snoop(&dev->dev, "%s: DISCSIGNAL\n", __func__); - ret = proc_disconnectsignal(ps, p); - break; - - case USBDEVFS_CLAIMINTERFACE: - snoop(&dev->dev, "%s: CLAIMINTERFACE\n", __func__); - ret = proc_claiminterface(ps, p); - break; - - case USBDEVFS_RELEASEINTERFACE: - snoop(&dev->dev, "%s: RELEASEINTERFACE\n", __func__); - ret = proc_releaseinterface(ps, p); - break; - - case USBDEVFS_IOCTL: - snoop(&dev->dev, "%s: IOCTL\n", __func__); - ret = proc_ioctl_default(ps, p); - break; - - case USBDEVFS_CLAIM_PORT: - snoop(&dev->dev, "%s: CLAIM_PORT\n", __func__); - ret = proc_claim_port(ps, p); - break; - - case USBDEVFS_RELEASE_PORT: - snoop(&dev->dev, "%s: RELEASE_PORT\n", __func__); - ret = proc_release_port(ps, p); - break; - } - usb_unlock_device(dev); - if (ret >= 0) - inode->i_atime = CURRENT_TIME; - return ret; -} - -static long usbdev_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - int ret; - - ret = usbdev_do_ioctl(file, cmd, (void __user *)arg); - - return ret; -} - -#ifdef CONFIG_COMPAT -static long usbdev_compat_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - int ret; - - ret = usbdev_do_ioctl(file, cmd, compat_ptr(arg)); - - return ret; -} -#endif - -/* No kernel lock - fine */ -static unsigned int usbdev_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct dev_state *ps = file->private_data; - unsigned int mask = 0; - - poll_wait(file, &ps->wait, wait); - if (file->f_mode & FMODE_WRITE && !list_empty(&ps->async_completed)) - mask |= POLLOUT | POLLWRNORM; - if (!connected(ps)) - mask |= POLLERR | POLLHUP; - return mask; -} - -const struct file_operations usbdev_file_operations = { - .owner = THIS_MODULE, - .llseek = usbdev_lseek, - .read = usbdev_read, - .poll = usbdev_poll, - .unlocked_ioctl = usbdev_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = usbdev_compat_ioctl, -#endif - .open = usbdev_open, - .release = usbdev_release, -}; - -static void usbdev_remove(struct usb_device *udev) -{ - struct dev_state *ps; - struct siginfo sinfo; - - while (!list_empty(&udev->filelist)) { - ps = list_entry(udev->filelist.next, struct dev_state, list); - destroy_all_async(ps); - wake_up_all(&ps->wait); - list_del_init(&ps->list); - if (ps->discsignr) { - sinfo.si_signo = ps->discsignr; - sinfo.si_errno = EPIPE; - sinfo.si_code = SI_ASYNCIO; - sinfo.si_addr = ps->disccontext; - kill_pid_info_as_cred(ps->discsignr, &sinfo, - ps->disc_pid, ps->cred, ps->secid); - } - } -} - -#ifdef CONFIG_USB_DEVICE_CLASS -static struct class *usb_classdev_class; - -static int usb_classdev_add(struct usb_device *dev) -{ - struct device *cldev; - - cldev = device_create(usb_classdev_class, &dev->dev, dev->dev.devt, - NULL, "usbdev%d.%d", dev->bus->busnum, - dev->devnum); - if (IS_ERR(cldev)) - return PTR_ERR(cldev); - dev->usb_classdev = cldev; - return 0; -} - -static void usb_classdev_remove(struct usb_device *dev) -{ - if (dev->usb_classdev) - device_unregister(dev->usb_classdev); -} - -#else -#define usb_classdev_add(dev) 0 -#define usb_classdev_remove(dev) do {} while (0) - -#endif - -static int usbdev_notify(struct notifier_block *self, - unsigned long action, void *dev) -{ - switch (action) { - case USB_DEVICE_ADD: - if (usb_classdev_add(dev)) - return NOTIFY_BAD; - break; - case USB_DEVICE_REMOVE: - usb_classdev_remove(dev); - usbdev_remove(dev); - break; - } - return NOTIFY_OK; -} - -static struct notifier_block usbdev_nb = { - .notifier_call = usbdev_notify, -}; - -static struct cdev usb_device_cdev; - -int __init usb_devio_init(void) -{ - int retval; - - retval = register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX, - "usb_device"); - if (retval) { - printk(KERN_ERR "Unable to register minors for usb_device\n"); - goto out; - } - cdev_init(&usb_device_cdev, &usbdev_file_operations); - retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX); - if (retval) { - printk(KERN_ERR "Unable to get usb_device major %d\n", - USB_DEVICE_MAJOR); - goto error_cdev; - } -#ifdef CONFIG_USB_DEVICE_CLASS - usb_classdev_class = class_create(THIS_MODULE, "usb_device"); - if (IS_ERR(usb_classdev_class)) { - printk(KERN_ERR "Unable to register usb_device class\n"); - retval = PTR_ERR(usb_classdev_class); - cdev_del(&usb_device_cdev); - usb_classdev_class = NULL; - goto out; - } - /* devices of this class shadow the major:minor of their parent - * device, so clear ->dev_kobj to prevent adding duplicate entries - * to /sys/dev - */ - usb_classdev_class->dev_kobj = NULL; -#endif - usb_register_notify(&usbdev_nb); -out: - return retval; - -error_cdev: - unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); - goto out; -} - -void usb_devio_cleanup(void) -{ - usb_unregister_notify(&usbdev_nb); -#ifdef CONFIG_USB_DEVICE_CLASS - class_destroy(usb_classdev_class); -#endif - cdev_del(&usb_device_cdev); - unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); -} diff --git a/ANDROID_3.4.5/drivers/usb/core/driver.c b/ANDROID_3.4.5/drivers/usb/core/driver.c deleted file mode 100644 index b3df4e9a..00000000 --- a/ANDROID_3.4.5/drivers/usb/core/driver.c +++ /dev/null @@ -1,1741 +0,0 @@ -/* - * drivers/usb/driver.c - most of the driver model stuff for usb - * - * (C) Copyright 2005 Greg Kroah-Hartman - * - * based on drivers/usb/usb.c which had the following copyrights: - * (C) Copyright Linus Torvalds 1999 - * (C) Copyright Johannes Erdfelt 1999-2001 - * (C) Copyright Andreas Gal 1999 - * (C) Copyright Gregory P. Smith 1999 - * (C) Copyright Deti Fliegl 1999 (new USB architecture) - * (C) Copyright Randy Dunlap 2000 - * (C) Copyright David Brownell 2000-2004 - * (C) Copyright Yggdrasil Computing, Inc. 2000 - * (usb_device_id matching changes by Adam J. Richter) - * (C) Copyright Greg Kroah-Hartman 2002-2003 - * - * NOTE! This is not actually a driver at all, rather this is - * just a collection of helper routines that implement the - * matching, probing, releasing, suspending and resuming for - * real drivers. - * - */ - -#include -#include -#include -#include -#include -#include - -#include "usb.h" - - -#ifdef CONFIG_HOTPLUG - -/* - * Adds a new dynamic USBdevice ID to this driver, - * and cause the driver to probe for all devices again. - */ -ssize_t usb_store_new_id(struct usb_dynids *dynids, - struct device_driver *driver, - const char *buf, size_t count) -{ - struct usb_dynid *dynid; - u32 idVendor = 0; - u32 idProduct = 0; - unsigned int bInterfaceClass = 0; - int fields = 0; - int retval = 0; - - fields = sscanf(buf, "%x %x %x", &idVendor, &idProduct, - &bInterfaceClass); - if (fields < 2) - return -EINVAL; - - dynid = kzalloc(sizeof(*dynid), GFP_KERNEL); - if (!dynid) - return -ENOMEM; - - INIT_LIST_HEAD(&dynid->node); - dynid->id.idVendor = idVendor; - dynid->id.idProduct = idProduct; - dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE; - if (fields == 3) { - dynid->id.bInterfaceClass = (u8)bInterfaceClass; - dynid->id.match_flags |= USB_DEVICE_ID_MATCH_INT_CLASS; - } - - spin_lock(&dynids->lock); - list_add_tail(&dynid->node, &dynids->list); - spin_unlock(&dynids->lock); - - retval = driver_attach(driver); - - if (retval) - return retval; - return count; -} -EXPORT_SYMBOL_GPL(usb_store_new_id); - -static ssize_t store_new_id(struct device_driver *driver, - const char *buf, size_t count) -{ - struct usb_driver *usb_drv = to_usb_driver(driver); - - return usb_store_new_id(&usb_drv->dynids, driver, buf, count); -} -static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); - -/** - * store_remove_id - remove a USB device ID from this driver - * @driver: target device driver - * @buf: buffer for scanning device ID data - * @count: input size - * - * Removes a dynamic usb device ID from this driver. - */ -static ssize_t -store_remove_id(struct device_driver *driver, const char *buf, size_t count) -{ - struct usb_dynid *dynid, *n; - struct usb_driver *usb_driver = to_usb_driver(driver); - u32 idVendor = 0; - u32 idProduct = 0; - int fields = 0; - int retval = 0; - - fields = sscanf(buf, "%x %x", &idVendor, &idProduct); - if (fields < 2) - return -EINVAL; - - spin_lock(&usb_driver->dynids.lock); - list_for_each_entry_safe(dynid, n, &usb_driver->dynids.list, node) { - struct usb_device_id *id = &dynid->id; - if ((id->idVendor == idVendor) && - (id->idProduct == idProduct)) { - list_del(&dynid->node); - kfree(dynid); - retval = 0; - break; - } - } - spin_unlock(&usb_driver->dynids.lock); - - if (retval) - return retval; - return count; -} -static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id); - -static int usb_create_newid_files(struct usb_driver *usb_drv) -{ - int error = 0; - - if (usb_drv->no_dynamic_id) - goto exit; - - if (usb_drv->probe != NULL) { - error = driver_create_file(&usb_drv->drvwrap.driver, - &driver_attr_new_id); - if (error == 0) { - error = driver_create_file(&usb_drv->drvwrap.driver, - &driver_attr_remove_id); - if (error) - driver_remove_file(&usb_drv->drvwrap.driver, - &driver_attr_new_id); - } - } -exit: - return error; -} - -static void usb_remove_newid_files(struct usb_driver *usb_drv) -{ - if (usb_drv->no_dynamic_id) - return; - - if (usb_drv->probe != NULL) { - driver_remove_file(&usb_drv->drvwrap.driver, - &driver_attr_remove_id); - driver_remove_file(&usb_drv->drvwrap.driver, - &driver_attr_new_id); - } -} - -static void usb_free_dynids(struct usb_driver *usb_drv) -{ - struct usb_dynid *dynid, *n; - - spin_lock(&usb_drv->dynids.lock); - list_for_each_entry_safe(dynid, n, &usb_drv->dynids.list, node) { - list_del(&dynid->node); - kfree(dynid); - } - spin_unlock(&usb_drv->dynids.lock); -} -#else -static inline int usb_create_newid_files(struct usb_driver *usb_drv) -{ - return 0; -} - -static void usb_remove_newid_files(struct usb_driver *usb_drv) -{ -} - -static inline void usb_free_dynids(struct usb_driver *usb_drv) -{ -} -#endif - -static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *intf, - struct usb_driver *drv) -{ - struct usb_dynid *dynid; - - spin_lock(&drv->dynids.lock); - list_for_each_entry(dynid, &drv->dynids.list, node) { - if (usb_match_one_id(intf, &dynid->id)) { - spin_unlock(&drv->dynids.lock); - return &dynid->id; - } - } - spin_unlock(&drv->dynids.lock); - return NULL; -} - - -/* called from driver core with dev locked */ -static int usb_probe_device(struct device *dev) -{ - struct usb_device_driver *udriver = to_usb_device_driver(dev->driver); - struct usb_device *udev = to_usb_device(dev); - int error = 0; - - dev_dbg(dev, "%s\n", __func__); - - /* TODO: Add real matching code */ - - /* The device should always appear to be in use - * unless the driver suports autosuspend. - */ - if (!udriver->supports_autosuspend) - error = usb_autoresume_device(udev); - - if (!error) - error = udriver->probe(udev); - return error; -} - -/* called from driver core with dev locked */ -static int usb_unbind_device(struct device *dev) -{ - struct usb_device *udev = to_usb_device(dev); - struct usb_device_driver *udriver = to_usb_device_driver(dev->driver); - - udriver->disconnect(udev); - if (!udriver->supports_autosuspend) - usb_autosuspend_device(udev); - return 0; -} - -/* - * Cancel any pending scheduled resets - * - * [see usb_queue_reset_device()] - * - * Called after unconfiguring / when releasing interfaces. See - * comments in __usb_queue_reset_device() regarding - * udev->reset_running. - */ -static void usb_cancel_queued_reset(struct usb_interface *iface) -{ - if (iface->reset_running == 0) - cancel_work_sync(&iface->reset_ws); -} - -/* called from driver core with dev locked */ -static int usb_probe_interface(struct device *dev) -{ - struct usb_driver *driver = to_usb_driver(dev->driver); - 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__); - - intf->needs_binding = 0; - - if (usb_device_is_owned(udev)) - return error; - - if (udev->authorized == 0) { - dev_err(&intf->dev, "Device is not authorized for usage\n"); - return error; - } - - id = usb_match_id(intf, driver->id_table); - if (!id) - id = usb_match_dynamic_id(intf, driver); - if (!id) - return error; - - dev_dbg(dev, "%s - got id\n", __func__); - - error = usb_autoresume_device(udev); - if (error) - return error; - - intf->condition = USB_INTERFACE_BINDING; - - /* Probed interfaces are initially active. They are - * runtime-PM-enabled only if the driver has autosuspend support. - * They are sensitive to their children's power states. - */ - pm_runtime_set_active(dev); - pm_suspend_ignore_children(dev, false); - if (driver->supports_autosuspend) - pm_runtime_enable(dev); - - /* Carry out a deferred switch to altsetting 0 */ - if (intf->needs_altsetting0) { - error = usb_set_interface(udev, intf->altsetting[0]. - desc.bInterfaceNumber, 0); - if (error < 0) - goto err; - intf->needs_altsetting0 = 0; - } - - error = driver->probe(intf, id); - if (error) - goto err; - - intf->condition = USB_INTERFACE_BOUND; - usb_autosuspend_device(udev); - return error; - - err: - intf->needs_remote_wakeup = 0; - intf->condition = USB_INTERFACE_UNBOUND; - usb_cancel_queued_reset(intf); - - /* Unbound interfaces are always runtime-PM-disabled and -suspended */ - if (driver->supports_autosuspend) - pm_runtime_disable(dev); - pm_runtime_set_suspended(dev); - - usb_autosuspend_device(udev); - return error; -} - -/* called from driver core with dev locked */ -static int usb_unbind_interface(struct device *dev) -{ - struct usb_driver *driver = to_usb_driver(dev->driver); - struct usb_interface *intf = to_usb_interface(dev); - struct usb_device *udev; - int error, r; - - intf->condition = USB_INTERFACE_UNBINDING; - - /* Autoresume for set_interface call below */ - udev = interface_to_usbdev(intf); - error = usb_autoresume_device(udev); - - /* Terminate all URBs for this interface unless the driver - * supports "soft" unbinding. - */ - if (!driver->soft_unbind) - usb_disable_interface(udev, intf, false); - - driver->disconnect(intf); - usb_cancel_queued_reset(intf); - - /* Reset other interface state. - * We cannot do a Set-Interface if the device is suspended or - * if it is prepared for a system sleep (since installing a new - * altsetting means creating new endpoint device entries). - * When either of these happens, defer the Set-Interface. - */ - if (intf->cur_altsetting->desc.bAlternateSetting == 0) { - /* Already in altsetting 0 so skip Set-Interface. - * Just re-enable it without affecting the endpoint toggles. - */ - usb_enable_interface(udev, intf, false); - } else if (!error && !intf->dev.power.is_prepared) { - r = usb_set_interface(udev, intf->altsetting[0]. - desc.bInterfaceNumber, 0); - if (r < 0) - intf->needs_altsetting0 = 1; - } else { - intf->needs_altsetting0 = 1; - } - usb_set_intfdata(intf, NULL); - - intf->condition = USB_INTERFACE_UNBOUND; - intf->needs_remote_wakeup = 0; - - /* Unbound interfaces are always runtime-PM-disabled and -suspended */ - if (driver->supports_autosuspend) - pm_runtime_disable(dev); - pm_runtime_set_suspended(dev); - - /* Undo any residual pm_autopm_get_interface_* calls */ - for (r = atomic_read(&intf->pm_usage_cnt); r > 0; --r) - usb_autopm_put_interface_no_suspend(intf); - atomic_set(&intf->pm_usage_cnt, 0); - - if (!error) - usb_autosuspend_device(udev); - - return 0; -} - -/** - * usb_driver_claim_interface - bind a driver to an interface - * @driver: the driver to be bound - * @iface: the interface to which it will be bound; must be in the - * usb device's active configuration - * @priv: driver data associated with that interface - * - * This is used by usb device drivers that need to claim more than one - * interface on a device when probing (audio and acm are current examples). - * No device driver should directly modify internal usb_interface or - * usb_device structure members. - * - * Few drivers should need to use this routine, since the most natural - * way to bind to an interface is to return the private data from - * the driver's probe() method. - * - * Callers must own the device lock, so driver probe() entries don't need - * extra locking, but other call contexts may need to explicitly claim that - * lock. - */ -int usb_driver_claim_interface(struct usb_driver *driver, - struct usb_interface *iface, void *priv) -{ - struct device *dev = &iface->dev; - int retval = 0; - - if (dev->driver) - return -EBUSY; - - dev->driver = &driver->drvwrap.driver; - usb_set_intfdata(iface, priv); - iface->needs_binding = 0; - - iface->condition = USB_INTERFACE_BOUND; - - /* Claimed interfaces are initially inactive (suspended) and - * runtime-PM-enabled, but only if the driver has autosuspend - * support. Otherwise they are marked active, to prevent the - * device from being autosuspended, but left disabled. In either - * case they are sensitive to their children's power states. - */ - pm_suspend_ignore_children(dev, false); - if (driver->supports_autosuspend) - pm_runtime_enable(dev); - else - pm_runtime_set_active(dev); - - /* if interface was already added, bind now; else let - * the future device_add() bind it, bypassing probe() - */ - if (device_is_registered(dev)) - retval = device_bind_driver(dev); - - return retval; -} -EXPORT_SYMBOL_GPL(usb_driver_claim_interface); - -/** - * usb_driver_release_interface - unbind a driver from an interface - * @driver: the driver to be unbound - * @iface: the interface from which it will be unbound - * - * This can be used by drivers to release an interface without waiting - * for their disconnect() methods to be called. In typical cases this - * also causes the driver disconnect() method to be called. - * - * This call is synchronous, and may not be used in an interrupt context. - * Callers must own the device lock, so driver disconnect() entries don't - * need extra locking, but other call contexts may need to explicitly claim - * that lock. - */ -void usb_driver_release_interface(struct usb_driver *driver, - struct usb_interface *iface) -{ - struct device *dev = &iface->dev; - - /* this should never happen, don't release something that's not ours */ - if (!dev->driver || dev->driver != &driver->drvwrap.driver) - return; - - /* don't release from within disconnect() */ - if (iface->condition != USB_INTERFACE_BOUND) - return; - iface->condition = USB_INTERFACE_UNBINDING; - - /* Release via the driver core only if the interface - * has already been registered - */ - if (device_is_registered(dev)) { - device_release_driver(dev); - } else { - device_lock(dev); - usb_unbind_interface(dev); - dev->driver = NULL; - device_unlock(dev); - } -} -EXPORT_SYMBOL_GPL(usb_driver_release_interface); - -/* returns 0 if no match, 1 if match */ -int usb_match_device(struct usb_device *dev, const struct usb_device_id *id) -{ - if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) && - id->idVendor != le16_to_cpu(dev->descriptor.idVendor)) - return 0; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) && - id->idProduct != le16_to_cpu(dev->descriptor.idProduct)) - return 0; - - /* No need to test id->bcdDevice_lo != 0, since 0 is never - greater than any unsigned number. */ - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) && - (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice))) - return 0; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) && - (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice))) - return 0; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) && - (id->bDeviceClass != dev->descriptor.bDeviceClass)) - return 0; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) && - (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass)) - return 0; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) && - (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol)) - return 0; - - return 1; -} - -/* returns 0 if no match, 1 if match */ -int usb_match_one_id(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_host_interface *intf; - struct usb_device *dev; - - /* proc_connectinfo in devio.c may call us with id == NULL. */ - if (id == NULL) - return 0; - - intf = interface->cur_altsetting; - dev = interface_to_usbdev(interface); - - if (!usb_match_device(dev, id)) - return 0; - - /* The interface class, subclass, and protocol should never be - * checked for a match if the device class is Vendor Specific, - * unless the match record specifies the Vendor ID. */ - if (dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC && - !(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) && - (id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS | - USB_DEVICE_ID_MATCH_INT_SUBCLASS | - USB_DEVICE_ID_MATCH_INT_PROTOCOL))) - return 0; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) && - (id->bInterfaceClass != intf->desc.bInterfaceClass)) - return 0; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) && - (id->bInterfaceSubClass != intf->desc.bInterfaceSubClass)) - return 0; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) && - (id->bInterfaceProtocol != intf->desc.bInterfaceProtocol)) - return 0; - - return 1; -} -EXPORT_SYMBOL_GPL(usb_match_one_id); - -/** - * usb_match_id - find first usb_device_id matching device or interface - * @interface: the interface of interest - * @id: array of usb_device_id structures, terminated by zero entry - * - * usb_match_id searches an array of usb_device_id's and returns - * the first one matching the device or interface, or null. - * This is used when binding (or rebinding) a driver to an interface. - * Most USB device drivers will use this indirectly, through the usb core, - * but some layered driver frameworks use it directly. - * These device tables are exported with MODULE_DEVICE_TABLE, through - * modutils, to support the driver loading functionality of USB hotplugging. - * - * What Matches: - * - * The "match_flags" element in a usb_device_id controls which - * members are used. If the corresponding bit is set, the - * value in the device_id must match its corresponding member - * in the device or interface descriptor, or else the device_id - * does not match. - * - * "driver_info" is normally used only by device drivers, - * but you can create a wildcard "matches anything" usb_device_id - * as a driver's "modules.usbmap" entry if you provide an id with - * only a nonzero "driver_info" field. If you do this, the USB device - * driver's probe() routine should use additional intelligence to - * decide whether to bind to the specified interface. - * - * What Makes Good usb_device_id Tables: - * - * The match algorithm is very simple, so that intelligence in - * driver selection must come from smart driver id records. - * Unless you have good reasons to use another selection policy, - * provide match elements only in related groups, and order match - * specifiers from specific to general. Use the macros provided - * for that purpose if you can. - * - * The most specific match specifiers use device descriptor - * data. These are commonly used with product-specific matches; - * the USB_DEVICE macro lets you provide vendor and product IDs, - * and you can also match against ranges of product revisions. - * These are widely used for devices with application or vendor - * specific bDeviceClass values. - * - * Matches based on device class/subclass/protocol specifications - * are slightly more general; use the USB_DEVICE_INFO macro, or - * its siblings. These are used with single-function devices - * where bDeviceClass doesn't specify that each interface has - * its own class. - * - * Matches based on interface class/subclass/protocol are the - * most general; they let drivers bind to any interface on a - * multiple-function device. Use the USB_INTERFACE_INFO - * macro, or its siblings, to match class-per-interface style - * devices (as recorded in bInterfaceClass). - * - * Note that an entry created by USB_INTERFACE_INFO won't match - * any interface if the device class is set to Vendor-Specific. - * This is deliberate; according to the USB spec the meanings of - * the interface class/subclass/protocol for these devices are also - * vendor-specific, and hence matching against a standard product - * class wouldn't work anyway. If you really want to use an - * interface-based match for such a device, create a match record - * that also specifies the vendor ID. (Unforunately there isn't a - * standard macro for creating records like this.) - * - * Within those groups, remember that not all combinations are - * meaningful. For example, don't give a product version range - * without vendor and product IDs; or specify a protocol without - * its associated class and subclass. - */ -const struct usb_device_id *usb_match_id(struct usb_interface *interface, - const struct usb_device_id *id) -{ - /* proc_connectinfo in devio.c may call us with id == NULL. */ - if (id == NULL) - return NULL; - - /* It is important to check that id->driver_info is nonzero, - since an entry that is all zeroes except for a nonzero - id->driver_info is the way to create an entry that - indicates that the driver want to examine every - device and interface. */ - for (; id->idVendor || id->idProduct || id->bDeviceClass || - id->bInterfaceClass || id->driver_info; id++) { - if (usb_match_one_id(interface, id)) - return id; - } - - return NULL; -} -EXPORT_SYMBOL_GPL(usb_match_id); - -static int usb_device_match(struct device *dev, struct device_driver *drv) -{ - /* devices and interfaces are handled separately */ - if (is_usb_device(dev)) { - - /* interface drivers never match devices */ - if (!is_usb_device_driver(drv)) - return 0; - - /* TODO: Add real matching code */ - return 1; - - } else if (is_usb_interface(dev)) { - struct usb_interface *intf; - struct usb_driver *usb_drv; - const struct usb_device_id *id; - - /* device drivers never match interfaces */ - if (is_usb_device_driver(drv)) - return 0; - - intf = to_usb_interface(dev); - usb_drv = to_usb_driver(drv); - - id = usb_match_id(intf, usb_drv->id_table); - if (id) - return 1; - - id = usb_match_dynamic_id(intf, usb_drv); - if (id) - return 1; - } - - return 0; -} - -#ifdef CONFIG_HOTPLUG -static int usb_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - struct usb_device *usb_dev; - - if (is_usb_device(dev)) { - usb_dev = to_usb_device(dev); - } 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) { - /* driver is often null here; dev_dbg() would oops */ - pr_debug("usb %s: already deleted?\n", dev_name(dev)); - return -ENODEV; - } - if (!usb_dev->bus) { - pr_debug("usb %s: bus removed?\n", dev_name(dev)); - return -ENODEV; - } - -#ifdef CONFIG_USB_DEVICEFS - /* If this is available, userspace programs can directly read - * all the device descriptors we don't tell them about. Or - * act as usermode drivers. - */ - if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d", - usb_dev->bus->busnum, usb_dev->devnum)) - return -ENOMEM; -#endif - - /* per-device configurations are common */ - if (add_uevent_var(env, "PRODUCT=%x/%x/%x", - le16_to_cpu(usb_dev->descriptor.idVendor), - le16_to_cpu(usb_dev->descriptor.idProduct), - le16_to_cpu(usb_dev->descriptor.bcdDevice))) - return -ENOMEM; - - /* class-based driver binding models */ - if (add_uevent_var(env, "TYPE=%d/%d/%d", - usb_dev->descriptor.bDeviceClass, - usb_dev->descriptor.bDeviceSubClass, - usb_dev->descriptor.bDeviceProtocol)) - return -ENOMEM; - - return 0; -} - -#else - -static int usb_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - return -ENODEV; -} -#endif /* CONFIG_HOTPLUG */ - -/** - * usb_register_device_driver - register a USB device (not interface) driver - * @new_udriver: USB operations for the device driver - * @owner: module owner of this driver. - * - * Registers a USB device driver with the USB core. The list of - * unattached devices will be rescanned whenever a new driver is - * added, allowing the new driver to attach to any recognized devices. - * Returns a negative error code on failure and 0 on success. - */ -int usb_register_device_driver(struct usb_device_driver *new_udriver, - struct module *owner) -{ - int retval = 0; - - if (usb_disabled()) - return -ENODEV; - - new_udriver->drvwrap.for_devices = 1; - new_udriver->drvwrap.driver.name = (char *) new_udriver->name; - new_udriver->drvwrap.driver.bus = &usb_bus_type; - new_udriver->drvwrap.driver.probe = usb_probe_device; - new_udriver->drvwrap.driver.remove = usb_unbind_device; - new_udriver->drvwrap.driver.owner = owner; - - retval = driver_register(&new_udriver->drvwrap.driver); - - if (!retval) { - pr_info("%s: registered new device driver %s\n", - usbcore_name, new_udriver->name); - usbfs_update_special(); - } else { - printk(KERN_ERR "%s: error %d registering device " - " driver %s\n", - usbcore_name, retval, new_udriver->name); - } - - return retval; -} -EXPORT_SYMBOL_GPL(usb_register_device_driver); - -/** - * usb_deregister_device_driver - unregister a USB device (not interface) driver - * @udriver: USB operations of the device driver to unregister - * Context: must be able to sleep - * - * Unlinks the specified driver from the internal USB driver list. - */ -void usb_deregister_device_driver(struct usb_device_driver *udriver) -{ - pr_info("%s: deregistering device driver %s\n", - usbcore_name, udriver->name); - - driver_unregister(&udriver->drvwrap.driver); - usbfs_update_special(); -} -EXPORT_SYMBOL_GPL(usb_deregister_device_driver); - -/** - * usb_register_driver - register a USB interface driver - * @new_driver: USB operations for the interface driver - * @owner: module owner of this driver. - * @mod_name: module name string - * - * Registers a USB interface driver with the USB core. The list of - * unattached interfaces will be rescanned whenever a new driver is - * added, allowing the new driver to attach to any recognized interfaces. - * Returns a negative error code on failure and 0 on success. - * - * NOTE: if you want your driver to use the USB major number, you must call - * usb_register_dev() to enable that functionality. This function no longer - * takes care of that. - */ -int usb_register_driver(struct usb_driver *new_driver, struct module *owner, - const char *mod_name) -{ - int retval = 0; - - if (usb_disabled()) - return -ENODEV; - - new_driver->drvwrap.for_devices = 0; - new_driver->drvwrap.driver.name = (char *) new_driver->name; - new_driver->drvwrap.driver.bus = &usb_bus_type; - new_driver->drvwrap.driver.probe = usb_probe_interface; - new_driver->drvwrap.driver.remove = usb_unbind_interface; - new_driver->drvwrap.driver.owner = owner; - new_driver->drvwrap.driver.mod_name = mod_name; - spin_lock_init(&new_driver->dynids.lock); - INIT_LIST_HEAD(&new_driver->dynids.list); - - retval = driver_register(&new_driver->drvwrap.driver); - if (retval) - goto out; - - usbfs_update_special(); - - retval = usb_create_newid_files(new_driver); - if (retval) - goto out_newid; - - pr_info("%s: registered new interface driver %s\n", - usbcore_name, new_driver->name); - -out: - return retval; - -out_newid: - driver_unregister(&new_driver->drvwrap.driver); - - printk(KERN_ERR "%s: error %d registering interface " - " driver %s\n", - usbcore_name, retval, new_driver->name); - goto out; -} -EXPORT_SYMBOL_GPL(usb_register_driver); - -/** - * usb_deregister - unregister a USB interface driver - * @driver: USB operations of the interface driver to unregister - * Context: must be able to sleep - * - * Unlinks the specified driver from the internal USB driver list. - * - * NOTE: If you called usb_register_dev(), you still need to call - * usb_deregister_dev() to clean up your driver's allocated minor numbers, - * this * call will no longer do it for you. - */ -void usb_deregister(struct usb_driver *driver) -{ - pr_info("%s: deregistering interface driver %s\n", - usbcore_name, driver->name); - - usb_remove_newid_files(driver); - driver_unregister(&driver->drvwrap.driver); - usb_free_dynids(driver); - - usbfs_update_special(); -} -EXPORT_SYMBOL_GPL(usb_deregister); - -/* Forced unbinding of a USB interface driver, either because - * it doesn't support pre_reset/post_reset/reset_resume or - * because it doesn't support suspend/resume. - * - * The caller must hold @intf's device's lock, but not its pm_mutex - * and not @intf->dev.sem. - */ -void usb_forced_unbind_intf(struct usb_interface *intf) -{ - struct usb_driver *driver = to_usb_driver(intf->dev.driver); - - dev_dbg(&intf->dev, "forced unbind\n"); - usb_driver_release_interface(driver, intf); - - /* Mark the interface for later rebinding */ - intf->needs_binding = 1; -} - -/* Delayed forced unbinding of a USB interface driver and scan - * for rebinding. - * - * The caller must hold @intf's device's lock, but not its pm_mutex - * and not @intf->dev.sem. - * - * Note: Rebinds will be skipped if a system sleep transition is in - * progress and the PM "complete" callback hasn't occurred yet. - */ -void usb_rebind_intf(struct usb_interface *intf) -{ - int rc; - - /* Delayed unbind of an existing driver */ - if (intf->dev.driver) - usb_forced_unbind_intf(intf); - - /* Try to rebind the interface */ - if (!intf->dev.power.is_prepared) { - intf->needs_binding = 0; - rc = device_attach(&intf->dev); - if (rc < 0) - dev_warn(&intf->dev, "rebind failed: %d\n", rc); - } -} - -#ifdef CONFIG_PM - -/* Unbind drivers for @udev's interfaces that don't support suspend/resume - * There is no check for reset_resume here because it can be determined - * only during resume whether reset_resume is needed. - * - * The caller must hold @udev's device lock. - */ -static void unbind_no_pm_drivers_interfaces(struct usb_device *udev) -{ - struct usb_host_config *config; - int i; - struct usb_interface *intf; - struct usb_driver *drv; - - config = udev->actconfig; - if (config) { - for (i = 0; i < config->desc.bNumInterfaces; ++i) { - intf = config->interface[i]; - - if (intf->dev.driver) { - drv = to_usb_driver(intf->dev.driver); - if (!drv->suspend || !drv->resume) - usb_forced_unbind_intf(intf); - } - } - } -} - -/* Unbind drivers for @udev's interfaces that failed to support reset-resume. - * These interfaces have the needs_binding flag set by usb_resume_interface(). - * - * The caller must hold @udev's device lock. - */ -static void unbind_no_reset_resume_drivers_interfaces(struct usb_device *udev) -{ - struct usb_host_config *config; - int i; - struct usb_interface *intf; - - config = udev->actconfig; - if (config) { - for (i = 0; i < config->desc.bNumInterfaces; ++i) { - intf = config->interface[i]; - if (intf->dev.driver && intf->needs_binding) - usb_forced_unbind_intf(intf); - } - } -} - -static void do_rebind_interfaces(struct usb_device *udev) -{ - struct usb_host_config *config; - int i; - struct usb_interface *intf; - - config = udev->actconfig; - if (config) { - for (i = 0; i < config->desc.bNumInterfaces; ++i) { - intf = config->interface[i]; - if (intf->needs_binding) - usb_rebind_intf(intf); - } - } -} - -static int usb_suspend_device(struct usb_device *udev, pm_message_t msg) -{ - struct usb_device_driver *udriver; - int status = 0; - - if (udev->state == USB_STATE_NOTATTACHED || - udev->state == USB_STATE_SUSPENDED) - goto done; - - /* For devices that don't have a driver, we do a generic suspend. */ - if (udev->dev.driver) - udriver = to_usb_device_driver(udev->dev.driver); - else { - udev->do_remote_wakeup = 0; - udriver = &usb_generic_driver; - } - status = udriver->suspend(udev, msg); - - done: - dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status); - return status; -} - -static int usb_resume_device(struct usb_device *udev, pm_message_t msg) -{ - struct usb_device_driver *udriver; - int status = 0; - - if (udev->state == USB_STATE_NOTATTACHED) - goto done; - - /* Can't resume it if it doesn't have a driver. */ - if (udev->dev.driver == NULL) { - status = -ENOTCONN; - goto done; - } - - /* Non-root devices on a full/low-speed bus must wait for their - * companion high-speed root hub, in case a handoff is needed. - */ - if (!PMSG_IS_AUTO(msg) && udev->parent && udev->bus->hs_companion) - device_pm_wait_for_dev(&udev->dev, - &udev->bus->hs_companion->root_hub->dev); - - if (udev->quirks & USB_QUIRK_RESET_RESUME) - udev->reset_resume = 1; - - udriver = to_usb_device_driver(udev->dev.driver); - status = udriver->resume(udev, msg); - - done: - dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status); - return status; -} - -static int usb_suspend_interface(struct usb_device *udev, - struct usb_interface *intf, pm_message_t msg) -{ - struct usb_driver *driver; - int status = 0; - - if (udev->state == USB_STATE_NOTATTACHED || - intf->condition == USB_INTERFACE_UNBOUND) - goto done; - driver = to_usb_driver(intf->dev.driver); - - /* at this time we know the driver supports suspend */ - status = driver->suspend(intf, msg); - if (status && !PMSG_IS_AUTO(msg)) - dev_err(&intf->dev, "suspend error %d\n", status); - - done: - dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status); - return status; -} - -static int usb_resume_interface(struct usb_device *udev, - struct usb_interface *intf, pm_message_t msg, int reset_resume) -{ - struct usb_driver *driver; - int status = 0; - - if (udev->state == USB_STATE_NOTATTACHED) - goto done; - - /* Don't let autoresume interfere with unbinding */ - if (intf->condition == USB_INTERFACE_UNBINDING) - goto done; - - /* Can't resume it if it doesn't have a driver. */ - if (intf->condition == USB_INTERFACE_UNBOUND) { - - /* Carry out a deferred switch to altsetting 0 */ - if (intf->needs_altsetting0 && !intf->dev.power.is_prepared) { - usb_set_interface(udev, intf->altsetting[0]. - desc.bInterfaceNumber, 0); - intf->needs_altsetting0 = 0; - } - goto done; - } - - /* Don't resume if the interface is marked for rebinding */ - if (intf->needs_binding) - goto done; - driver = to_usb_driver(intf->dev.driver); - - if (reset_resume) { - if (driver->reset_resume) { - status = driver->reset_resume(intf); - if (status) - dev_err(&intf->dev, "%s error %d\n", - "reset_resume", status); - } else { - intf->needs_binding = 1; - dev_warn(&intf->dev, "no %s for driver %s?\n", - "reset_resume", driver->name); - } - } else { - status = driver->resume(intf); - if (status) - dev_err(&intf->dev, "resume error %d\n", status); - } - -done: - dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status); - - /* Later we will unbind the driver and/or reprobe, if necessary */ - return status; -} - -/** - * usb_suspend_both - suspend a USB device and its interfaces - * @udev: the usb_device to suspend - * @msg: Power Management message describing this state transition - * - * This is the central routine for suspending USB devices. It calls the - * suspend methods for all the interface drivers in @udev and then calls - * the suspend method for @udev itself. If an error occurs at any stage, - * all the interfaces which were suspended are resumed so that they remain - * in the same state as the device. - * - * Autosuspend requests originating from a child device or an interface - * driver may be made without the protection of @udev's device lock, but - * all other suspend calls will hold the lock. Usbcore will insure that - * method calls do not arrive during bind, unbind, or reset operations. - * However drivers must be prepared to handle suspend calls arriving at - * unpredictable times. - * - * This routine can run only in process context. - */ -static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) -{ - int status = 0; - int i = 0, n = 0; - struct usb_interface *intf; - - if (udev->state == USB_STATE_NOTATTACHED || - udev->state == USB_STATE_SUSPENDED) - goto done; - - /* Suspend all the interfaces and then udev itself */ - if (udev->actconfig) { - n = udev->actconfig->desc.bNumInterfaces; - for (i = n - 1; i >= 0; --i) { - intf = udev->actconfig->interface[i]; - status = usb_suspend_interface(udev, intf, msg); - - /* Ignore errors during system sleep transitions */ - if (!PMSG_IS_AUTO(msg)) - status = 0; - if (status != 0) - break; - } - } - if (status == 0) { - status = usb_suspend_device(udev, msg); - - /* - * Ignore errors from non-root-hub devices during - * system sleep transitions. For the most part, - * these devices should go to low power anyway when - * the entire bus is suspended. - */ - if (udev->parent && !PMSG_IS_AUTO(msg)) - status = 0; - } - - /* If the suspend failed, resume interfaces that did get suspended */ - if (status != 0) { - msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME); - while (++i < n) { - intf = udev->actconfig->interface[i]; - usb_resume_interface(udev, intf, msg, 0); - } - - /* If the suspend succeeded then prevent any more URB submissions - * and flush any outstanding URBs. - */ - } else { - udev->can_submit = 0; - for (i = 0; i < 16; ++i) { - usb_hcd_flush_endpoint(udev, udev->ep_out[i]); - usb_hcd_flush_endpoint(udev, udev->ep_in[i]); - } - } - - done: - dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status); - return status; -} - -/** - * usb_resume_both - resume a USB device and its interfaces - * @udev: the usb_device to resume - * @msg: Power Management message describing this state transition - * - * This is the central routine for resuming USB devices. It calls the - * the resume method for @udev and then calls the resume methods for all - * the interface drivers in @udev. - * - * Autoresume requests originating from a child device or an interface - * driver may be made without the protection of @udev's device lock, but - * all other resume calls will hold the lock. Usbcore will insure that - * method calls do not arrive during bind, unbind, or reset operations. - * However drivers must be prepared to handle resume calls arriving at - * unpredictable times. - * - * This routine can run only in process context. - */ -static int usb_resume_both(struct usb_device *udev, pm_message_t msg) -{ - int status = 0; - int i; - struct usb_interface *intf; - - if (udev->state == USB_STATE_NOTATTACHED) { - status = -ENODEV; - goto done; - } - udev->can_submit = 1; - - /* Resume the device */ - if (udev->state == USB_STATE_SUSPENDED || udev->reset_resume) - status = usb_resume_device(udev, msg); - - /* Resume the interfaces */ - if (status == 0 && udev->actconfig) { - for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { - intf = udev->actconfig->interface[i]; - usb_resume_interface(udev, intf, msg, - udev->reset_resume); - } - } - usb_mark_last_busy(udev); - - done: - dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status); - if (!(&udev->dev)) - printk("(NULL device *): %s: status %d\n", __func__, status); - else - printk("%s%s : %s: status %d\n",dev_driver_string(&udev->dev), dev_name(&udev->dev), __func__, status); - if (!status) - udev->reset_resume = 0; - return status; -} - -static void choose_wakeup(struct usb_device *udev, pm_message_t msg) -{ - int w; - - /* Remote wakeup is needed only when we actually go to sleep. - * For things like FREEZE and QUIESCE, if the device is already - * autosuspended then its current wakeup setting is okay. - */ - if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_QUIESCE) { - if (udev->state != USB_STATE_SUSPENDED) - udev->do_remote_wakeup = 0; - return; - } - - /* Enable remote wakeup if it is allowed, even if no interface drivers - * actually want it. - */ - w = device_may_wakeup(&udev->dev); - - /* If the device is autosuspended with the wrong wakeup setting, - * autoresume now so the setting can be changed. - */ - if (udev->state == USB_STATE_SUSPENDED && w != udev->do_remote_wakeup) - pm_runtime_resume(&udev->dev); - udev->do_remote_wakeup = w; -} - -/* The device lock is held by the PM core */ -int usb_suspend(struct device *dev, pm_message_t msg) -{ - struct usb_device *udev = to_usb_device(dev); - - unbind_no_pm_drivers_interfaces(udev); - - /* From now on we are sure all drivers support suspend/resume - * but not necessarily reset_resume() - * so we may still need to unbind and rebind upon resume - */ - choose_wakeup(udev, msg); - return usb_suspend_both(udev, msg); -} - -/* The device lock is held by the PM core */ -int usb_resume_complete(struct device *dev) -{ - struct usb_device *udev = to_usb_device(dev); - - /* For PM complete calls, all we do is rebind interfaces - * whose needs_binding flag is set - */ - if (udev->state != USB_STATE_NOTATTACHED) - do_rebind_interfaces(udev); - return 0; -} - -/* The device lock is held by the PM core */ -int usb_resume(struct device *dev, pm_message_t msg) -{ - struct usb_device *udev = to_usb_device(dev); - int status; - - /* For all calls, take the device back to full power and - * tell the PM core in case it was autosuspended previously. - * Unbind the interfaces that will need rebinding later, - * because they fail to support reset_resume. - * (This can't be done in usb_resume_interface() - * above because it doesn't own the right set of locks.) - */ - status = usb_resume_both(udev, msg); - if (status == 0) { - pm_runtime_disable(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - unbind_no_reset_resume_drivers_interfaces(udev); - } - - /* Avoid PM error messages for devices disconnected while suspended - * as we'll display regular disconnect messages just a bit later. - */ - if (status == -ENODEV || status == -ESHUTDOWN) - status = 0; - return status; -} - -#endif /* CONFIG_PM */ - -#ifdef CONFIG_USB_SUSPEND - -/** - * usb_enable_autosuspend - allow a USB device to be autosuspended - * @udev: the USB device which may be autosuspended - * - * This routine allows @udev to be autosuspended. An autosuspend won't - * take place until the autosuspend_delay has elapsed and all the other - * necessary conditions are satisfied. - * - * The caller must hold @udev's device lock. - */ -void usb_enable_autosuspend(struct usb_device *udev) -{ - pm_runtime_allow(&udev->dev); -} -EXPORT_SYMBOL_GPL(usb_enable_autosuspend); - -/** - * usb_disable_autosuspend - prevent a USB device from being autosuspended - * @udev: the USB device which may not be autosuspended - * - * This routine prevents @udev from being autosuspended and wakes it up - * if it is already autosuspended. - * - * The caller must hold @udev's device lock. - */ -void usb_disable_autosuspend(struct usb_device *udev) -{ - pm_runtime_forbid(&udev->dev); -} -EXPORT_SYMBOL_GPL(usb_disable_autosuspend); - -/** - * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces - * @udev: the usb_device to autosuspend - * - * This routine should be called when a core subsystem is finished using - * @udev and wants to allow it to autosuspend. Examples would be when - * @udev's device file in usbfs is closed or after a configuration change. - * - * @udev's usage counter is decremented; if it drops to 0 and all the - * interfaces are inactive then a delayed autosuspend will be attempted. - * The attempt may fail (see autosuspend_check()). - * - * The caller must hold @udev's device lock. - * - * This routine can run only in process context. - */ -void usb_autosuspend_device(struct usb_device *udev) -{ - int status; - - usb_mark_last_busy(udev); - status = pm_runtime_put_sync_autosuspend(&udev->dev); - dev_vdbg(&udev->dev, "%s: cnt %d -> %d\n", - __func__, atomic_read(&udev->dev.power.usage_count), - status); -} - -/** - * usb_autoresume_device - immediately autoresume a USB device and its interfaces - * @udev: the usb_device to autoresume - * - * This routine should be called when a core subsystem wants to use @udev - * and needs to guarantee that it is not suspended. No autosuspend will - * occur until usb_autosuspend_device() is called. (Note that this will - * not prevent suspend events originating in the PM core.) Examples would - * be when @udev's device file in usbfs is opened or when a remote-wakeup - * request is received. - * - * @udev's usage counter is incremented to prevent subsequent autosuspends. - * However if the autoresume fails then the usage counter is re-decremented. - * - * The caller must hold @udev's device lock. - * - * This routine can run only in process context. - */ -int usb_autoresume_device(struct usb_device *udev) -{ - int status; - - status = pm_runtime_get_sync(&udev->dev); - if (status < 0) - pm_runtime_put_sync(&udev->dev); - dev_vdbg(&udev->dev, "%s: cnt %d -> %d\n", - __func__, atomic_read(&udev->dev.power.usage_count), - status); - if (status > 0) - status = 0; - return status; -} - -/** - * usb_autopm_put_interface - decrement a USB interface's PM-usage counter - * @intf: the usb_interface whose counter should be decremented - * - * This routine should be called by an interface driver when it is - * finished using @intf and wants to allow it to autosuspend. A typical - * example would be a character-device driver when its device file is - * closed. - * - * The routine decrements @intf's usage counter. When the counter reaches - * 0, a delayed autosuspend request for @intf's device is attempted. The - * attempt may fail (see autosuspend_check()). - * - * This routine can run only in process context. - */ -void usb_autopm_put_interface(struct usb_interface *intf) -{ - struct usb_device *udev = interface_to_usbdev(intf); - int status; - - usb_mark_last_busy(udev); - atomic_dec(&intf->pm_usage_cnt); - status = pm_runtime_put_sync(&intf->dev); - dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n", - __func__, atomic_read(&intf->dev.power.usage_count), - status); -} -EXPORT_SYMBOL_GPL(usb_autopm_put_interface); - -/** - * usb_autopm_put_interface_async - decrement a USB interface's PM-usage counter - * @intf: the usb_interface whose counter should be decremented - * - * This routine does much the same thing as usb_autopm_put_interface(): - * It decrements @intf's usage counter and schedules a delayed - * autosuspend request if the counter is <= 0. The difference is that it - * does not perform any synchronization; callers should hold a private - * lock and handle all synchronization issues themselves. - * - * Typically a driver would call this routine during an URB's completion - * handler, if no more URBs were pending. - * - * This routine can run in atomic context. - */ -void usb_autopm_put_interface_async(struct usb_interface *intf) -{ - struct usb_device *udev = interface_to_usbdev(intf); - int status; - - usb_mark_last_busy(udev); - atomic_dec(&intf->pm_usage_cnt); - status = pm_runtime_put(&intf->dev); - dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n", - __func__, atomic_read(&intf->dev.power.usage_count), - status); -} -EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async); - -/** - * usb_autopm_put_interface_no_suspend - decrement a USB interface's PM-usage counter - * @intf: the usb_interface whose counter should be decremented - * - * This routine decrements @intf's usage counter but does not carry out an - * autosuspend. - * - * This routine can run in atomic context. - */ -void usb_autopm_put_interface_no_suspend(struct usb_interface *intf) -{ - struct usb_device *udev = interface_to_usbdev(intf); - - usb_mark_last_busy(udev); - atomic_dec(&intf->pm_usage_cnt); - pm_runtime_put_noidle(&intf->dev); -} -EXPORT_SYMBOL_GPL(usb_autopm_put_interface_no_suspend); - -/** - * usb_autopm_get_interface - increment a USB interface's PM-usage counter - * @intf: the usb_interface whose counter should be incremented - * - * This routine should be called by an interface driver when it wants to - * use @intf and needs to guarantee that it is not suspended. In addition, - * the routine prevents @intf from being autosuspended subsequently. (Note - * that this will not prevent suspend events originating in the PM core.) - * This prevention will persist until usb_autopm_put_interface() is called - * or @intf is unbound. A typical example would be a character-device - * driver when its device file is opened. - * - * @intf's usage counter is incremented to prevent subsequent autosuspends. - * However if the autoresume fails then the counter is re-decremented. - * - * This routine can run only in process context. - */ -int usb_autopm_get_interface(struct usb_interface *intf) -{ - int status; - - status = pm_runtime_get_sync(&intf->dev); - if (status < 0) - pm_runtime_put_sync(&intf->dev); - else - atomic_inc(&intf->pm_usage_cnt); - dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n", - __func__, atomic_read(&intf->dev.power.usage_count), - status); - if (status > 0) - status = 0; - return status; -} -EXPORT_SYMBOL_GPL(usb_autopm_get_interface); - -/** - * usb_autopm_get_interface_async - increment a USB interface's PM-usage counter - * @intf: the usb_interface whose counter should be incremented - * - * This routine does much the same thing as - * usb_autopm_get_interface(): It increments @intf's usage counter and - * queues an autoresume request if the device is suspended. The - * differences are that it does not perform any synchronization (callers - * should hold a private lock and handle all synchronization issues - * themselves), and it does not autoresume the device directly (it only - * queues a request). After a successful call, the device may not yet be - * resumed. - * - * This routine can run in atomic context. - */ -int usb_autopm_get_interface_async(struct usb_interface *intf) -{ - int status; - - status = pm_runtime_get(&intf->dev); - if (status < 0 && status != -EINPROGRESS) - pm_runtime_put_noidle(&intf->dev); - else - atomic_inc(&intf->pm_usage_cnt); - dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n", - __func__, atomic_read(&intf->dev.power.usage_count), - status); - if (status > 0 || status == -EINPROGRESS) - status = 0; - return status; -} -EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async); - -/** - * usb_autopm_get_interface_no_resume - increment a USB interface's PM-usage counter - * @intf: the usb_interface whose counter should be incremented - * - * This routine increments @intf's usage counter but does not carry out an - * autoresume. - * - * This routine can run in atomic context. - */ -void usb_autopm_get_interface_no_resume(struct usb_interface *intf) -{ - struct usb_device *udev = interface_to_usbdev(intf); - - usb_mark_last_busy(udev); - atomic_inc(&intf->pm_usage_cnt); - pm_runtime_get_noresume(&intf->dev); -} -EXPORT_SYMBOL_GPL(usb_autopm_get_interface_no_resume); - -/* Internal routine to check whether we may autosuspend a device. */ -static int autosuspend_check(struct usb_device *udev) -{ - int w, i; - struct usb_interface *intf; - - /* Fail if autosuspend is disabled, or any interfaces are in use, or - * any interface drivers require remote wakeup but it isn't available. - */ - w = 0; - if (udev->actconfig) { - for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { - intf = udev->actconfig->interface[i]; - - /* We don't need to check interfaces that are - * disabled for runtime PM. Either they are unbound - * or else their drivers don't support autosuspend - * and so they are permanently active. - */ - if (intf->dev.power.disable_depth) - continue; - if (atomic_read(&intf->dev.power.usage_count) > 0) - return -EBUSY; - w |= intf->needs_remote_wakeup; - - /* Don't allow autosuspend if the device will need - * a reset-resume and any of its interface drivers - * doesn't include support or needs remote wakeup. - */ - if (udev->quirks & USB_QUIRK_RESET_RESUME) { - struct usb_driver *driver; - - driver = to_usb_driver(intf->dev.driver); - if (!driver->reset_resume || - intf->needs_remote_wakeup) - return -EOPNOTSUPP; - } - } - } - if (w && !device_can_wakeup(&udev->dev)) { - dev_dbg(&udev->dev, "remote wakeup needed for autosuspend\n"); - return -EOPNOTSUPP; - } - udev->do_remote_wakeup = w; - return 0; -} - -int usb_runtime_suspend(struct device *dev) -{ - struct usb_device *udev = to_usb_device(dev); - int status; - - /* A USB device can be suspended if it passes the various autosuspend - * checks. Runtime suspend for a USB device means suspending all the - * interfaces and then the device itself. - */ - if (autosuspend_check(udev) != 0) - return -EAGAIN; - - status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND); - - /* Allow a retry if autosuspend failed temporarily */ - if (status == -EAGAIN || status == -EBUSY) - usb_mark_last_busy(udev); - - /* The PM core reacts badly unless the return code is 0, - * -EAGAIN, or -EBUSY, so always return -EBUSY on an error. - */ - if (status != 0) - return -EBUSY; - return status; -} - -int usb_runtime_resume(struct device *dev) -{ - struct usb_device *udev = to_usb_device(dev); - int status; - - /* Runtime resume for a USB device means resuming both the device - * and all its interfaces. - */ - status = usb_resume_both(udev, PMSG_AUTO_RESUME); - return status; -} - -int usb_runtime_idle(struct device *dev) -{ - struct usb_device *udev = to_usb_device(dev); - - /* An idle USB device can be suspended if it passes the various - * autosuspend checks. - */ - if (autosuspend_check(udev) == 0) - pm_runtime_autosuspend(dev); - return 0; -} - -int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) -{ - struct usb_hcd *hcd = bus_to_hcd(udev->bus); - int ret = -EPERM; - - if (hcd->driver->set_usb2_hw_lpm) { - ret = hcd->driver->set_usb2_hw_lpm(hcd, udev, enable); - if (!ret) - udev->usb2_hw_lpm_enabled = enable; - } - - return ret; -} - -#endif /* CONFIG_USB_SUSPEND */ - -struct bus_type usb_bus_type = { - .name = "usb", - .match = usb_device_match, - .uevent = usb_uevent, -}; diff --git a/ANDROID_3.4.5/drivers/usb/core/endpoint.c b/ANDROID_3.4.5/drivers/usb/core/endpoint.c deleted file mode 100644 index db7fe50c..00000000 --- a/ANDROID_3.4.5/drivers/usb/core/endpoint.c +++ /dev/null @@ -1,218 +0,0 @@ -/* - * drivers/usb/core/endpoint.c - * - * (C) Copyright 2002,2004,2006 Greg Kroah-Hartman - * (C) Copyright 2002,2004 IBM Corp. - * (C) Copyright 2006 Novell Inc. - * - * Endpoint sysfs stuff - * - */ - -#include -#include -#include -#include -#include -#include "usb.h" - -struct ep_device { - struct usb_endpoint_descriptor *desc; - struct usb_device *udev; - struct device dev; -}; -#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 *, - struct usb_endpoint_descriptor *, char *); -}; -#define to_ep_attribute(_attr) \ - container_of(_attr, struct ep_attribute, attr) - -#define usb_ep_attr(field, format_string) \ -static ssize_t show_ep_##field(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct ep_device *ep = to_ep_device(dev); \ - return sprintf(buf, format_string, ep->desc->field); \ -} \ -static DEVICE_ATTR(field, S_IRUGO, show_ep_##field, NULL); - -usb_ep_attr(bLength, "%02x\n") -usb_ep_attr(bEndpointAddress, "%02x\n") -usb_ep_attr(bmAttributes, "%02x\n") -usb_ep_attr(bInterval, "%02x\n") - -static ssize_t show_ep_wMaxPacketSize(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ep_device *ep = to_ep_device(dev); - return sprintf(buf, "%04x\n", - usb_endpoint_maxp(ep->desc) & 0x07ff); -} -static DEVICE_ATTR(wMaxPacketSize, S_IRUGO, show_ep_wMaxPacketSize, NULL); - -static ssize_t show_ep_type(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct ep_device *ep = to_ep_device(dev); - char *type = "unknown"; - - switch (usb_endpoint_type(ep->desc)) { - case USB_ENDPOINT_XFER_CONTROL: - type = "Control"; - break; - case USB_ENDPOINT_XFER_ISOC: - type = "Isoc"; - break; - case USB_ENDPOINT_XFER_BULK: - type = "Bulk"; - break; - case USB_ENDPOINT_XFER_INT: - type = "Interrupt"; - break; - } - return sprintf(buf, "%s\n", type); -} -static DEVICE_ATTR(type, S_IRUGO, show_ep_type, NULL); - -static ssize_t show_ep_interval(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ep_device *ep = to_ep_device(dev); - char unit; - unsigned interval = 0; - unsigned in; - - in = (ep->desc->bEndpointAddress & USB_DIR_IN); - - switch (usb_endpoint_type(ep->desc)) { - case USB_ENDPOINT_XFER_CONTROL: - if (ep->udev->speed == USB_SPEED_HIGH) - /* uframes per NAK */ - interval = ep->desc->bInterval; - break; - - case USB_ENDPOINT_XFER_ISOC: - interval = 1 << (ep->desc->bInterval - 1); - break; - - case USB_ENDPOINT_XFER_BULK: - if (ep->udev->speed == USB_SPEED_HIGH && !in) - /* uframes per NAK */ - interval = ep->desc->bInterval; - break; - - case USB_ENDPOINT_XFER_INT: - if (ep->udev->speed == USB_SPEED_HIGH) - interval = 1 << (ep->desc->bInterval - 1); - else - interval = ep->desc->bInterval; - break; - } - interval *= (ep->udev->speed == USB_SPEED_HIGH) ? 125 : 1000; - if (interval % 1000) - unit = 'u'; - else { - unit = 'm'; - interval /= 1000; - } - - return sprintf(buf, "%d%cs\n", interval, unit); -} -static DEVICE_ATTR(interval, S_IRUGO, show_ep_interval, NULL); - -static ssize_t show_ep_direction(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ep_device *ep = to_ep_device(dev); - char *direction; - - if (usb_endpoint_xfer_control(ep->desc)) - direction = "both"; - else if (usb_endpoint_dir_in(ep->desc)) - direction = "in"; - else - direction = "out"; - return sprintf(buf, "%s\n", direction); -} -static DEVICE_ATTR(direction, S_IRUGO, show_ep_direction, NULL); - -static struct attribute *ep_dev_attrs[] = { - &dev_attr_bLength.attr, - &dev_attr_bEndpointAddress.attr, - &dev_attr_bmAttributes.attr, - &dev_attr_bInterval.attr, - &dev_attr_wMaxPacketSize.attr, - &dev_attr_interval.attr, - &dev_attr_type.attr, - &dev_attr_direction.attr, - NULL, -}; -static struct attribute_group ep_dev_attr_grp = { - .attrs = ep_dev_attrs, -}; -static const struct attribute_group *ep_dev_groups[] = { - &ep_dev_attr_grp, - NULL -}; - -static void ep_device_release(struct device *dev) -{ - struct ep_device *ep_dev = to_ep_device(dev); - - kfree(ep_dev); -} - -int usb_create_ep_devs(struct device *parent, - struct usb_host_endpoint *endpoint, - struct usb_device *udev) -{ - struct ep_device *ep_dev; - int retval; - - ep_dev = kzalloc(sizeof(*ep_dev), GFP_KERNEL); - if (!ep_dev) { - retval = -ENOMEM; - goto exit; - } - - ep_dev->desc = &endpoint->desc; - ep_dev->udev = udev; - ep_dev->dev.groups = ep_dev_groups; - 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, "ep_%02x", endpoint->desc.bEndpointAddress); - - retval = device_register(&ep_dev->dev); - if (retval) - goto error_register; - - device_enable_async_suspend(&ep_dev->dev); - endpoint->ep_dev = ep_dev; - return retval; - -error_register: - put_device(&ep_dev->dev); -exit: - return retval; -} - -void usb_remove_ep_devs(struct usb_host_endpoint *endpoint) -{ - struct ep_device *ep_dev = endpoint->ep_dev; - - if (ep_dev) { - device_unregister(&ep_dev->dev); - endpoint->ep_dev = NULL; - } -} diff --git a/ANDROID_3.4.5/drivers/usb/core/file.c b/ANDROID_3.4.5/drivers/usb/core/file.c deleted file mode 100644 index d95760de..00000000 --- a/ANDROID_3.4.5/drivers/usb/core/file.c +++ /dev/null @@ -1,253 +0,0 @@ -/* - * drivers/usb/core/file.c - * - * (C) Copyright Linus Torvalds 1999 - * (C) Copyright Johannes Erdfelt 1999-2001 - * (C) Copyright Andreas Gal 1999 - * (C) Copyright Gregory P. Smith 1999 - * (C) Copyright Deti Fliegl 1999 (new USB architecture) - * (C) Copyright Randy Dunlap 2000 - * (C) Copyright David Brownell 2000-2001 (kernel hotplug, usb_device_id, - more docs, etc) - * (C) Copyright Yggdrasil Computing, Inc. 2000 - * (usb_device_id matching changes by Adam J. Richter) - * (C) Copyright Greg Kroah-Hartman 2002-2003 - * - */ - -#include -#include -#include -#include -#include - -#include "usb.h" - -#define MAX_USB_MINORS 256 -static const struct file_operations *usb_minors[MAX_USB_MINORS]; -static DECLARE_RWSEM(minor_rwsem); - -static int usb_open(struct inode * inode, struct file * file) -{ - int minor = iminor(inode); - const struct file_operations *c; - int err = -ENODEV; - const struct file_operations *old_fops, *new_fops = NULL; - - down_read(&minor_rwsem); - c = usb_minors[minor]; - - if (!c || !(new_fops = fops_get(c))) - goto done; - - old_fops = file->f_op; - file->f_op = new_fops; - /* Curiouser and curiouser... NULL ->open() as "no device" ? */ - if (file->f_op->open) - err = file->f_op->open(inode,file); - if (err) { - fops_put(file->f_op); - file->f_op = fops_get(old_fops); - } - fops_put(old_fops); - done: - up_read(&minor_rwsem); - return err; -} - -static const struct file_operations usb_fops = { - .owner = THIS_MODULE, - .open = usb_open, - .llseek = noop_llseek, -}; - -static struct usb_class { - struct kref kref; - struct class *class; -} *usb_class; - -static char *usb_devnode(struct device *dev, umode_t *mode) -{ - struct usb_class_driver *drv; - - drv = dev_get_drvdata(dev); - if (!drv || !drv->devnode) - return NULL; - return drv->devnode(dev, mode); -} - -static int init_usb_class(void) -{ - int result = 0; - - if (usb_class != NULL) { - kref_get(&usb_class->kref); - goto exit; - } - - usb_class = kmalloc(sizeof(*usb_class), GFP_KERNEL); - if (!usb_class) { - result = -ENOMEM; - goto exit; - } - - kref_init(&usb_class->kref); - usb_class->class = class_create(THIS_MODULE, "usb"); - if (IS_ERR(usb_class->class)) { - result = IS_ERR(usb_class->class); - printk(KERN_ERR "class_create failed for usb devices\n"); - kfree(usb_class); - usb_class = NULL; - goto exit; - } - usb_class->class->devnode = usb_devnode; - -exit: - return result; -} - -static void release_usb_class(struct kref *kref) -{ - /* Ok, we cheat as we know we only have one usb_class */ - class_destroy(usb_class->class); - kfree(usb_class); - usb_class = NULL; -} - -static void destroy_usb_class(void) -{ - if (usb_class) - kref_put(&usb_class->kref, release_usb_class); -} - -int usb_major_init(void) -{ - int error; - - error = register_chrdev(USB_MAJOR, "usb", &usb_fops); - if (error) - printk(KERN_ERR "Unable to get major %d for usb devices\n", - USB_MAJOR); - - return error; -} - -void usb_major_cleanup(void) -{ - unregister_chrdev(USB_MAJOR, "usb"); -} - -/** - * usb_register_dev - register a USB device, and ask for a minor number - * @intf: pointer to the usb_interface that is being registered - * @class_driver: pointer to the usb_class_driver for this device - * - * This should be called by all USB drivers that use the USB major number. - * If CONFIG_USB_DYNAMIC_MINORS is enabled, the minor number will be - * dynamically allocated out of the list of available ones. If it is not - * enabled, the minor number will be based on the next available free minor, - * starting at the class_driver->minor_base. - * - * This function also creates a usb class device in the sysfs tree. - * - * usb_deregister_dev() must be called when the driver is done with - * the minor numbers given out by this function. - * - * Returns -EINVAL if something bad happens with trying to register a - * device, and 0 on success. - */ -int usb_register_dev(struct usb_interface *intf, - struct usb_class_driver *class_driver) -{ - int retval; - int minor_base = class_driver->minor_base; - int minor; - char name[20]; - char *temp; - -#ifdef CONFIG_USB_DYNAMIC_MINORS - /* - * We don't care what the device tries to start at, we want to start - * at zero to pack the devices into the smallest available space with - * no holes in the minor range. - */ - minor_base = 0; -#endif - - if (class_driver->fops == NULL) - return -EINVAL; - if (intf->minor >= 0) - return -EADDRINUSE; - - retval = init_usb_class(); - if (retval) - return retval; - - dev_dbg(&intf->dev, "looking for a minor, starting at %d", minor_base); - - down_write(&minor_rwsem); - for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) { - if (usb_minors[minor]) - continue; - - usb_minors[minor] = class_driver->fops; - intf->minor = minor; - break; - } - up_write(&minor_rwsem); - if (intf->minor < 0) - return -EXFULL; - - /* create a usb class device for this usb interface */ - snprintf(name, sizeof(name), class_driver->name, minor - minor_base); - temp = strrchr(name, '/'); - if (temp && (temp[1] != '\0')) - ++temp; - else - temp = name; - intf->usb_dev = device_create(usb_class->class, &intf->dev, - MKDEV(USB_MAJOR, minor), class_driver, - "%s", temp); - if (IS_ERR(intf->usb_dev)) { - down_write(&minor_rwsem); - usb_minors[minor] = NULL; - intf->minor = -1; - up_write(&minor_rwsem); - retval = PTR_ERR(intf->usb_dev); - } - return retval; -} -EXPORT_SYMBOL_GPL(usb_register_dev); - -/** - * usb_deregister_dev - deregister a USB device's dynamic minor. - * @intf: pointer to the usb_interface that is being deregistered - * @class_driver: pointer to the usb_class_driver for this device - * - * Used in conjunction with usb_register_dev(). This function is called - * when the USB driver is finished with the minor numbers gotten from a - * call to usb_register_dev() (usually when the device is disconnected - * from the system.) - * - * This function also removes the usb class device from the sysfs tree. - * - * This should be called by all drivers that use the USB major number. - */ -void usb_deregister_dev(struct usb_interface *intf, - struct usb_class_driver *class_driver) -{ - if (intf->minor == -1) - return; - - dbg ("removing %d minor", intf->minor); - - down_write(&minor_rwsem); - usb_minors[intf->minor] = NULL; - up_write(&minor_rwsem); - - device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor)); - intf->usb_dev = NULL; - intf->minor = -1; - destroy_usb_class(); -} -EXPORT_SYMBOL_GPL(usb_deregister_dev); diff --git a/ANDROID_3.4.5/drivers/usb/core/generic.c b/ANDROID_3.4.5/drivers/usb/core/generic.c deleted file mode 100644 index ec4bfde3..00000000 --- a/ANDROID_3.4.5/drivers/usb/core/generic.c +++ /dev/null @@ -1,247 +0,0 @@ -/* - * drivers/usb/generic.c - generic driver for USB devices (not interfaces) - * - * (C) Copyright 2005 Greg Kroah-Hartman - * - * based on drivers/usb/usb.c which had the following copyrights: - * (C) Copyright Linus Torvalds 1999 - * (C) Copyright Johannes Erdfelt 1999-2001 - * (C) Copyright Andreas Gal 1999 - * (C) Copyright Gregory P. Smith 1999 - * (C) Copyright Deti Fliegl 1999 (new USB architecture) - * (C) Copyright Randy Dunlap 2000 - * (C) Copyright David Brownell 2000-2004 - * (C) Copyright Yggdrasil Computing, Inc. 2000 - * (usb_device_id matching changes by Adam J. Richter) - * (C) Copyright Greg Kroah-Hartman 2002-2003 - * - */ - -#include -#include -#include "usb.h" -extern int usb_power_insuf_skip=0; //read from uboot,default is false; - -static inline const char *plural(int n) -{ - return (n == 1 ? "" : "s"); -} - -static int is_rndis(struct usb_interface_descriptor *desc) -{ - return desc->bInterfaceClass == USB_CLASS_COMM - && desc->bInterfaceSubClass == 2 - && desc->bInterfaceProtocol == 0xff; -} - -static int is_activesync(struct usb_interface_descriptor *desc) -{ - return desc->bInterfaceClass == USB_CLASS_MISC - && desc->bInterfaceSubClass == 1 - && desc->bInterfaceProtocol == 1; -} - -int usb_choose_configuration(struct usb_device *udev) -{ - int i; - int num_configs; - int insufficient_power = 0; - struct usb_host_config *c, *best; - - best = NULL; - c = udev->config; - num_configs = udev->descriptor.bNumConfigurations; - for (i = 0; i < num_configs; (i++, c++)) { - struct usb_interface_descriptor *desc = NULL; - - /* It's possible that a config has no interfaces! */ - if (c->desc.bNumInterfaces > 0) - desc = &c->intf_cache[0]->altsetting->desc; - - /* - * HP's USB bus-powered keyboard has only one configuration - * and it claims to be self-powered; other devices may have - * similar errors in their descriptors. If the next test - * were allowed to execute, such configurations would always - * be rejected and the devices would not work as expected. - * In the meantime, we run the risk of selecting a config - * that requires external power at a time when that power - * isn't available. It seems to be the lesser of two evils. - * - * Bugzilla #6448 reports a device that appears to crash - * when it receives a GET_DEVICE_STATUS request! We don't - * have any other way to tell whether a device is self-powered, - * but since we don't use that information anywhere but here, - * the call has been removed. - * - * Maybe the GET_DEVICE_STATUS call and the test below can - * be reinstated when device firmwares become more reliable. - * Don't hold your breath. - */ -#if 0 - /* Rule out self-powered configs for a bus-powered device */ - if (bus_powered && (c->desc.bmAttributes & - USB_CONFIG_ATT_SELFPOWER)) - continue; -#endif - - /* - * The next test may not be as effective as it should be. - * Some hubs have errors in their descriptor, claiming - * to be self-powered when they are really bus-powered. - * We will overestimate the amount of current such hubs - * make available for each port. - * - * This is a fairly benign sort of failure. It won't - * cause us to reject configurations that we should have - * accepted. - */ - - /* Rule out configs that draw too much bus current */ - if(!usb_power_insuf_skip) - if (c->desc.bMaxPower * 2 > udev->bus_mA) { - insufficient_power++; - continue; - } - - /* When the first config's first interface is one of Microsoft's - * pet nonstandard Ethernet-over-USB protocols, ignore it unless - * this kernel has enabled the necessary host side driver. - * But: Don't ignore it if it's the only config. - */ - if (i == 0 && num_configs > 1 && desc && - (is_rndis(desc) || is_activesync(desc))) { -#if !defined(CONFIG_USB_NET_RNDIS_HOST) && !defined(CONFIG_USB_NET_RNDIS_HOST_MODULE) - continue; -#else - best = c; -#endif - } - - /* From the remaining configs, choose the first one whose - * first interface is for a non-vendor-specific class. - * Reason: Linux is more likely to have a class driver - * than a vendor-specific driver. */ - else if (udev->descriptor.bDeviceClass != - USB_CLASS_VENDOR_SPEC && - (desc && desc->bInterfaceClass != - USB_CLASS_VENDOR_SPEC)) { - best = c; - break; - } - - /* If all the remaining configs are vendor-specific, - * choose the first one. */ - else if (!best) - best = c; - } - - if (insufficient_power > 0) - dev_info(&udev->dev, "rejected %d configuration%s " - "due to insufficient available bus power\n", - insufficient_power, plural(insufficient_power)); - - if (best) { - i = best->desc.bConfigurationValue; - dev_dbg(&udev->dev, - "configuration #%d chosen from %d choice%s\n", - i, num_configs, plural(num_configs)); - } else { - i = -1; - dev_warn(&udev->dev, - "no configuration chosen from %d choice%s\n", - num_configs, plural(num_configs)); - } - return i; -} - -static int generic_probe(struct usb_device *udev) -{ - int err, c; - - /* Choose and set the configuration. This registers the interfaces - * with the driver core and lets interface drivers bind to them. - */ - if (usb_device_is_owned(udev)) - ; /* Don't configure if the device is owned */ - else if (udev->authorized == 0) - dev_err(&udev->dev, "Device is not authorized for usage\n"); - else { - c = usb_choose_configuration(udev); - if (c >= 0) { - err = usb_set_configuration(udev, c); - if (err) { - dev_err(&udev->dev, "can't set config #%d, error %d\n", - c, err); - /* This need not be fatal. The user can try to - * set other configurations. */ - } - } - } - /* USB device state == configured ... usable */ - usb_notify_add_device(udev); - - return 0; -} - -static void generic_disconnect(struct usb_device *udev) -{ - usb_notify_remove_device(udev); - - /* if this is only an unbind, not a physical disconnect, then - * unconfigure the device */ - if (udev->actconfig) - usb_set_configuration(udev, -1); -} - -#ifdef CONFIG_PM - -static int generic_suspend(struct usb_device *udev, pm_message_t msg) -{ - int rc; - - /* Normal USB devices suspend through their upstream port. - * Root hubs don't have upstream ports to suspend, - * so we have to shut down their downstream HC-to-USB - * interfaces manually by doing a bus (or "global") suspend. - */ - if (!udev->parent) - rc = hcd_bus_suspend(udev, msg); - - /* Non-root devices don't need to do anything for FREEZE or PRETHAW */ - else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW) - rc = 0; - else - rc = usb_port_suspend(udev, msg); - - return rc; -} - -static int generic_resume(struct usb_device *udev, pm_message_t msg) -{ - int rc; - - /* Normal USB devices resume/reset through their upstream port. - * Root hubs don't have upstream ports to resume or reset, - * so we have to start up their downstream HC-to-USB - * interfaces manually by doing a bus (or "global") resume. - */ - if (!udev->parent) - rc = hcd_bus_resume(udev, msg); - else - rc = usb_port_resume(udev, msg); - return rc; -} - -#endif /* CONFIG_PM */ - -struct usb_device_driver usb_generic_driver = { - .name = "usb", - .probe = generic_probe, - .disconnect = generic_disconnect, -#ifdef CONFIG_PM - .suspend = generic_suspend, - .resume = generic_resume, -#endif - .supports_autosuspend = 1, -}; diff --git a/ANDROID_3.4.5/drivers/usb/core/hcd-pci.c b/ANDROID_3.4.5/drivers/usb/core/hcd-pci.c deleted file mode 100644 index 622b4a48..00000000 --- a/ANDROID_3.4.5/drivers/usb/core/hcd-pci.c +++ /dev/null @@ -1,602 +0,0 @@ -/* - * (C) Copyright David Brownell 2000-2002 - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include - -#include -#include - -#ifdef CONFIG_PPC_PMAC -#include -#include -#include -#include -#endif - -#include "usb.h" - - -/* PCI-based HCs are common, but plenty of non-PCI HCs are used too */ - -#ifdef CONFIG_PM_SLEEP - -/* Coordinate handoffs between EHCI and companion controllers - * during system resume - */ - -static DEFINE_MUTEX(companions_mutex); - -#define CL_UHCI PCI_CLASS_SERIAL_USB_UHCI -#define CL_OHCI PCI_CLASS_SERIAL_USB_OHCI -#define CL_EHCI PCI_CLASS_SERIAL_USB_EHCI - -enum companion_action { - SET_HS_COMPANION, CLEAR_HS_COMPANION, WAIT_FOR_COMPANIONS -}; - -static void companion_common(struct pci_dev *pdev, struct usb_hcd *hcd, - enum companion_action action) -{ - struct pci_dev *companion; - struct usb_hcd *companion_hcd; - unsigned int slot = PCI_SLOT(pdev->devfn); - - /* Iterate through other PCI functions in the same slot. - * If pdev is OHCI or UHCI then we are looking for EHCI, and - * vice versa. - */ - companion = NULL; - for_each_pci_dev(companion) { - if (companion->bus != pdev->bus || - PCI_SLOT(companion->devfn) != slot) - continue; - - companion_hcd = pci_get_drvdata(companion); - if (!companion_hcd) - continue; - - /* For SET_HS_COMPANION, store a pointer to the EHCI bus in - * the OHCI/UHCI companion bus structure. - * For CLEAR_HS_COMPANION, clear the pointer to the EHCI bus - * in the OHCI/UHCI companion bus structure. - * For WAIT_FOR_COMPANIONS, wait until the OHCI/UHCI - * companion controllers have fully resumed. - */ - - if ((pdev->class == CL_OHCI || pdev->class == CL_UHCI) && - companion->class == CL_EHCI) { - /* action must be SET_HS_COMPANION */ - dev_dbg(&companion->dev, "HS companion for %s\n", - dev_name(&pdev->dev)); - hcd->self.hs_companion = &companion_hcd->self; - - } else if (pdev->class == CL_EHCI && - (companion->class == CL_OHCI || - companion->class == CL_UHCI)) { - switch (action) { - case SET_HS_COMPANION: - dev_dbg(&pdev->dev, "HS companion for %s\n", - dev_name(&companion->dev)); - companion_hcd->self.hs_companion = &hcd->self; - break; - case CLEAR_HS_COMPANION: - companion_hcd->self.hs_companion = NULL; - break; - case WAIT_FOR_COMPANIONS: - device_pm_wait_for_dev(&pdev->dev, - &companion->dev); - break; - } - } - } -} - -static void set_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd) -{ - mutex_lock(&companions_mutex); - dev_set_drvdata(&pdev->dev, hcd); - companion_common(pdev, hcd, SET_HS_COMPANION); - mutex_unlock(&companions_mutex); -} - -static void clear_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd) -{ - mutex_lock(&companions_mutex); - dev_set_drvdata(&pdev->dev, NULL); - - /* If pdev is OHCI or UHCI, just clear its hs_companion pointer */ - if (pdev->class == CL_OHCI || pdev->class == CL_UHCI) - hcd->self.hs_companion = NULL; - - /* Otherwise search for companion buses and clear their pointers */ - else - companion_common(pdev, hcd, CLEAR_HS_COMPANION); - mutex_unlock(&companions_mutex); -} - -static void wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd) -{ - /* Only EHCI controllers need to wait. - * No locking is needed because a controller cannot be resumed - * while one of its companions is getting unbound. - */ - if (pdev->class == CL_EHCI) - companion_common(pdev, hcd, WAIT_FOR_COMPANIONS); -} - -#else /* !CONFIG_PM_SLEEP */ - -static inline void set_hs_companion(struct pci_dev *d, struct usb_hcd *h) {} -static inline void clear_hs_companion(struct pci_dev *d, struct usb_hcd *h) {} -static inline void wait_for_companions(struct pci_dev *d, struct usb_hcd *h) {} - -#endif /* !CONFIG_PM_SLEEP */ - -/*-------------------------------------------------------------------------*/ - -/* configure so an HC device and id are always provided */ -/* always called with process context; sleeping is OK */ - -/** - * usb_hcd_pci_probe - initialize PCI-based HCDs - * @dev: USB Host Controller being probed - * @id: pci hotplug id connecting controller to HCD framework - * Context: !in_interrupt() - * - * Allocates basic PCI resources for this USB host controller, and - * then invokes the start() method for the HCD associated with it - * through the hotplug entry's driver_data. - * - * Store this function in the HCD's struct pci_driver as probe(). - */ -int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - struct hc_driver *driver; - struct usb_hcd *hcd; - int retval; - - if (usb_disabled()) - return -ENODEV; - - if (!id) - return -EINVAL; - driver = (struct hc_driver *)id->driver_data; - if (!driver) - return -EINVAL; - - if (pci_enable_device(dev) < 0) - return -ENODEV; - dev->current_state = PCI_D0; - - /* The xHCI driver supports MSI and MSI-X, - * so don't fail if the BIOS doesn't provide a legacy IRQ. - */ - if (!dev->irq && (driver->flags & HCD_MASK) != HCD_USB3) { - dev_err(&dev->dev, - "Found HC with no IRQ. Check BIOS/PCI %s setup!\n", - pci_name(dev)); - retval = -ENODEV; - goto disable_pci; - } - - hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev)); - if (!hcd) { - retval = -ENOMEM; - goto disable_pci; - } - - if (driver->flags & HCD_MEMORY) { - /* EHCI, OHCI */ - hcd->rsrc_start = pci_resource_start(dev, 0); - hcd->rsrc_len = pci_resource_len(dev, 0); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) { - dev_dbg(&dev->dev, "controller already in use\n"); - retval = -EBUSY; - goto clear_companion; - } - hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); - if (hcd->regs == NULL) { - dev_dbg(&dev->dev, "error mapping memory\n"); - retval = -EFAULT; - goto release_mem_region; - } - - } else { - /* UHCI */ - int region; - - for (region = 0; region < PCI_ROM_RESOURCE; region++) { - if (!(pci_resource_flags(dev, region) & - IORESOURCE_IO)) - continue; - - hcd->rsrc_start = pci_resource_start(dev, region); - hcd->rsrc_len = pci_resource_len(dev, region); - if (request_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) - break; - } - if (region == PCI_ROM_RESOURCE) { - dev_dbg(&dev->dev, "no i/o regions available\n"); - retval = -EBUSY; - goto clear_companion; - } - } - - pci_set_master(dev); - - retval = usb_add_hcd(hcd, dev->irq, IRQF_SHARED); - if (retval != 0) - goto unmap_registers; - set_hs_companion(dev, hcd); - - if (pci_dev_run_wake(dev)) - pm_runtime_put_noidle(&dev->dev); - return retval; - -unmap_registers: - if (driver->flags & HCD_MEMORY) { - iounmap(hcd->regs); -release_mem_region: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - } else - release_region(hcd->rsrc_start, hcd->rsrc_len); -clear_companion: - clear_hs_companion(dev, hcd); - usb_put_hcd(hcd); -disable_pci: - pci_disable_device(dev); - dev_err(&dev->dev, "init %s fail, %d\n", pci_name(dev), retval); - return retval; -} -EXPORT_SYMBOL_GPL(usb_hcd_pci_probe); - - -/* may be called without controller electrically present */ -/* may be called with controller, bus, and devices active */ - -/** - * usb_hcd_pci_remove - shutdown processing for PCI-based HCDs - * @dev: USB Host Controller being removed - * Context: !in_interrupt() - * - * Reverses the effect of usb_hcd_pci_probe(), first invoking - * the HCD's stop() method. It is always called from a thread - * context, normally "rmmod", "apmd", or something similar. - * - * Store this function in the HCD's struct pci_driver as remove(). - */ -void usb_hcd_pci_remove(struct pci_dev *dev) -{ - struct usb_hcd *hcd; - - hcd = pci_get_drvdata(dev); - if (!hcd) - return; - - if (pci_dev_run_wake(dev)) - pm_runtime_get_noresume(&dev->dev); - - /* Fake an interrupt request in order to give the driver a chance - * to test whether the controller hardware has been removed (e.g., - * cardbus physical eject). - */ - local_irq_disable(); - usb_hcd_irq(0, hcd); - local_irq_enable(); - - usb_remove_hcd(hcd); - if (hcd->driver->flags & HCD_MEMORY) { - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - } else { - release_region(hcd->rsrc_start, hcd->rsrc_len); - } - clear_hs_companion(dev, hcd); - usb_put_hcd(hcd); - pci_disable_device(dev); -} -EXPORT_SYMBOL_GPL(usb_hcd_pci_remove); - -/** - * usb_hcd_pci_shutdown - shutdown host controller - * @dev: USB Host Controller being shutdown - */ -void usb_hcd_pci_shutdown(struct pci_dev *dev) -{ - struct usb_hcd *hcd; - - hcd = pci_get_drvdata(dev); - if (!hcd) - return; - - if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) && - hcd->driver->shutdown) { - hcd->driver->shutdown(hcd); - pci_disable_device(dev); - } -} -EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown); - -#ifdef CONFIG_PM - -#ifdef CONFIG_PPC_PMAC -static void powermac_set_asic(struct pci_dev *pci_dev, int enable) -{ - /* Enanble or 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, enable); - } -} - -#else - -static inline void powermac_set_asic(struct pci_dev *pci_dev, int enable) -{} - -#endif /* CONFIG_PPC_PMAC */ - -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_RH_RUNNING(hcd)) { - dev_warn(dev, "Root hub is not suspended\n"); - return -EBUSY; - } - if (hcd->shared_hcd) { - hcd = hcd->shared_hcd; - if (HCD_RH_RUNNING(hcd)) { - dev_warn(dev, "Secondary root hub is not suspended\n"); - return -EBUSY; - } - } - return 0; -} - -#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME) -static int suspend_common(struct device *dev, bool do_wakeup) -{ - 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; - - if (hcd->driver->pci_suspend && !HCD_DEAD(hcd)) { - /* Optimization: Don't suspend if a root-hub wakeup is - * pending and it would cause the HCD to wake up anyway. - */ - if (do_wakeup && HCD_WAKEUP_PENDING(hcd)) - return -EBUSY; - if (do_wakeup && hcd->shared_hcd && - HCD_WAKEUP_PENDING(hcd->shared_hcd)) - return -EBUSY; - retval = hcd->driver->pci_suspend(hcd, do_wakeup); - suspend_report_result(hcd->driver->pci_suspend, retval); - - /* Check again in case wakeup raced with pci_suspend */ - if ((retval == 0 && do_wakeup && HCD_WAKEUP_PENDING(hcd)) || - (retval == 0 && do_wakeup && hcd->shared_hcd && - HCD_WAKEUP_PENDING(hcd->shared_hcd))) { - if (hcd->driver->pci_resume) - hcd->driver->pci_resume(hcd, false); - retval = -EBUSY; - } - if (retval) - return retval; - } - - /* If MSI-X is enabled, the driver will have synchronized all vectors - * in pci_suspend(). If MSI or legacy PCI is enabled, that will be - * synchronized here. - */ - if (!hcd->msix_enabled) - 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 resume_common(struct device *dev, int event) -{ - struct pci_dev *pci_dev = to_pci_dev(dev); - struct usb_hcd *hcd = pci_get_drvdata(pci_dev); - int retval; - - if (HCD_RH_RUNNING(hcd) || - (hcd->shared_hcd && - HCD_RH_RUNNING(hcd->shared_hcd))) { - 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); - - if (hcd->driver->pci_resume && !HCD_DEAD(hcd)) { - if (event != PM_EVENT_AUTO_RESUME) - wait_for_companions(pci_dev, hcd); - - retval = hcd->driver->pci_resume(hcd, - event == PM_EVENT_RESTORE); - if (retval) { - dev_err(dev, "PCI post-resume error %d!\n", retval); - if (hcd->shared_hcd) - usb_hc_died(hcd->shared_hcd); - usb_hc_died(hcd); - } - } - return retval; -} -#endif /* SLEEP || RUNTIME */ - -#ifdef CONFIG_PM_SLEEP - -static int hcd_pci_suspend(struct device *dev) -{ - return suspend_common(dev, device_may_wakeup(dev)); -} - -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 dead rather than suspended, disallow remote - * wakeup. usb_hc_died() should ensure that both hosts are marked as - * dying, so we only need to check the primary roothub. - */ - if (HCD_DEAD(hcd)) - 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; - } - - powermac_set_asic(pci_dev, 0); - return retval; -} - -static int hcd_pci_resume_noirq(struct device *dev) -{ - struct pci_dev *pci_dev = to_pci_dev(dev); - - powermac_set_asic(pci_dev, 1); - - /* Go back to D0 and disable remote wakeup */ - pci_back_from_sleep(pci_dev); - return 0; -} - -static int hcd_pci_resume(struct device *dev) -{ - return resume_common(dev, PM_EVENT_RESUME); -} - -static int hcd_pci_restore(struct device *dev) -{ - return resume_common(dev, PM_EVENT_RESTORE); -} - -#else - -#define hcd_pci_suspend NULL -#define hcd_pci_suspend_noirq NULL -#define hcd_pci_resume_noirq NULL -#define hcd_pci_resume NULL -#define hcd_pci_restore NULL - -#endif /* CONFIG_PM_SLEEP */ - -#ifdef CONFIG_PM_RUNTIME - -static int hcd_pci_runtime_suspend(struct device *dev) -{ - int retval; - - retval = suspend_common(dev, true); - if (retval == 0) - powermac_set_asic(to_pci_dev(dev), 0); - dev_dbg(dev, "hcd_pci_runtime_suspend: %d\n", retval); - return retval; -} - -static int hcd_pci_runtime_resume(struct device *dev) -{ - int retval; - - powermac_set_asic(to_pci_dev(dev), 1); - retval = resume_common(dev, PM_EVENT_AUTO_RESUME); - dev_dbg(dev, "hcd_pci_runtime_resume: %d\n", retval); - return retval; -} - -#else - -#define hcd_pci_runtime_suspend NULL -#define hcd_pci_runtime_resume NULL - -#endif /* CONFIG_PM_RUNTIME */ - -const 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, - .runtime_suspend = hcd_pci_runtime_suspend, - .runtime_resume = hcd_pci_runtime_resume, -}; -EXPORT_SYMBOL_GPL(usb_hcd_pci_pm_ops); - -#endif /* CONFIG_PM */ diff --git a/ANDROID_3.4.5/drivers/usb/core/hcd.c b/ANDROID_3.4.5/drivers/usb/core/hcd.c deleted file mode 100644 index 8318901f..00000000 --- a/ANDROID_3.4.5/drivers/usb/core/hcd.c +++ /dev/null @@ -1,2656 +0,0 @@ -/* - * (C) Copyright Linus Torvalds 1999 - * (C) Copyright Johannes Erdfelt 1999-2001 - * (C) Copyright Andreas Gal 1999 - * (C) Copyright Gregory P. Smith 1999 - * (C) Copyright Deti Fliegl 1999 - * (C) Copyright Randy Dunlap 2000 - * (C) Copyright David Brownell 2000-2002 - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "usb.h" - - -/*-------------------------------------------------------------------------*/ - -/* - * USB Host Controller Driver framework - * - * Plugs into usbcore (usb_bus) and lets HCDs share code, minimizing - * HCD-specific behaviors/bugs. - * - * This does error checks, tracks devices and urbs, and delegates to a - * "hc_driver" only for code (and data) that really needs to know about - * hardware differences. That includes root hub registers, i/o queues, - * and so on ... but as little else as possible. - * - * Shared code includes most of the "root hub" code (these are emulated, - * though each HC's hardware works differently) and PCI glue, plus request - * tracking overhead. The HCD code should only block on spinlocks or on - * hardware handshaking; blocking on software events (such as other kernel - * threads releasing resources, or completing actions) is all generic. - * - * Happens the USB 2.0 spec says this would be invisible inside the "USBD", - * and includes mostly a "HCDI" (HCD Interface) along with some APIs used - * only by the hub driver ... and that neither should be seen or used by - * usb client device drivers. - * - * Contributors of ideas or unattributed patches include: David Brownell, - * Roman Weissgaerber, Rory Bolt, Greg Kroah-Hartman, ... - * - * HISTORY: - * 2002-02-21 Pull in most of the usb_bus support from usb.c; some - * associated cleanup. "usb_hcd" still != "usb_bus". - * 2001-12-12 Initial patch version for Linux 2.5.1 kernel. - */ - -/*-------------------------------------------------------------------------*/ - -/* Keep track of which host controller drivers are loaded */ -unsigned long usb_hcds_loaded; -EXPORT_SYMBOL_GPL(usb_hcds_loaded); - -/* host controllers we manage */ -LIST_HEAD (usb_bus_list); -EXPORT_SYMBOL_GPL (usb_bus_list); - -/* used when allocating bus numbers */ -#define USB_MAXBUS 64 -struct usb_busmap { - unsigned long busmap [USB_MAXBUS / (8*sizeof (unsigned long))]; -}; -static struct usb_busmap busmap; - -/* used when updating list of hcds */ -DEFINE_MUTEX(usb_bus_list_lock); /* exported only for usbfs */ -EXPORT_SYMBOL_GPL (usb_bus_list_lock); - -/* used for controlling access to virtual root hubs */ -static DEFINE_SPINLOCK(hcd_root_hub_lock); - -/* used when updating an endpoint's URB list */ -static DEFINE_SPINLOCK(hcd_urb_list_lock); - -/* used to protect against unlinking URBs after the device is gone */ -static DEFINE_SPINLOCK(hcd_urb_unlink_lock); - -/* wait queue for synchronous unlinks */ -DECLARE_WAIT_QUEUE_HEAD(usb_kill_urb_queue); - -static inline int is_root_hub(struct usb_device *udev) -{ - return (udev->parent == NULL); -} - -/*-------------------------------------------------------------------------*/ - -/* - * Sharable chunks of root hub code. - */ - -/*-------------------------------------------------------------------------*/ - -#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 */ - 0x03, 0x00, /* __le16 idProduct; device 0x0003 */ - 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; */ - 0x01, /* __u8 bDescriptorType; Device */ - 0x00, 0x02, /* __le16 bcdUSB; v2.0 */ - - 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ - 0x00, /* __u8 bDeviceSubClass; */ - 0x00, /* __u8 bDeviceProtocol; [ usb 2.0 no TT ] */ - 0x40, /* __u8 bMaxPacketSize0; 64 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; */ -}; - -/* no usb 2.0 root hub "device qualifier" descriptor: one speed only */ - -/* usb 1.1 root hub device descriptor */ -static const u8 usb11_rh_dev_descriptor [18] = { - 0x12, /* __u8 bLength; */ - 0x01, /* __u8 bDescriptorType; Device */ - 0x10, 0x01, /* __le16 bcdUSB; v1.1 */ - - 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ - 0x00, /* __u8 bDeviceSubClass; */ - 0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */ - 0x40, /* __u8 bMaxPacketSize0; 64 Bytes */ - - 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */ - 0x01, 0x00, /* __le16 idProduct; device 0x0001 */ - KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */ - - 0x03, /* __u8 iManufacturer; */ - 0x02, /* __u8 iProduct; */ - 0x01, /* __u8 iSerialNumber; */ - 0x01 /* __u8 bNumConfigurations; */ -}; - - -/*-------------------------------------------------------------------------*/ - -/* Configuration descriptors for our root hubs */ - -static const u8 fs_rh_config_descriptor [] = { - - /* one configuration */ - 0x09, /* __u8 bLength; */ - 0x02, /* __u8 bDescriptorType; Configuration */ - 0x19, 0x00, /* __le16 wTotalLength; */ - 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; */ - - /* USB 1.1: - * USB 2.0, single TT organization (mandatory): - * one interface, protocol 0 - * - * USB 2.0, multiple TT organization (optional): - * two interfaces, protocols 1 (like single TT) - * and 2 (multiple TT mode) ... config is - * sometimes settable - * NOT IMPLEMENTED - */ - - /* 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; [usb1.1 or single tt] */ - 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 */ - 0x02, 0x00, /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ - 0xff /* __u8 ep_bInterval; (255ms -- usb 2.0 spec) */ -}; - -static const u8 hs_rh_config_descriptor [] = { - - /* one configuration */ - 0x09, /* __u8 bLength; */ - 0x02, /* __u8 bDescriptorType; Configuration */ - 0x19, 0x00, /* __le16 wTotalLength; */ - 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; */ - - /* USB 1.1: - * USB 2.0, single TT organization (mandatory): - * one interface, protocol 0 - * - * USB 2.0, multiple TT organization (optional): - * two interfaces, protocols 1 (like single TT) - * and 2 (multiple TT mode) ... config is - * sometimes settable - * NOT IMPLEMENTED - */ - - /* 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; [usb1.1 or single tt] */ - 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) */ -}; - -static const u8 ss_rh_config_descriptor[] = { - /* one configuration */ - 0x09, /* __u8 bLength; */ - 0x02, /* __u8 bDescriptorType; Configuration */ - 0x1f, 0x00, /* __le16 wTotalLength; */ - 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) */ - - /* one SuperSpeed endpoint companion descriptor */ - 0x06, /* __u8 ss_bLength */ - 0x30, /* __u8 ss_bDescriptorType; SuperSpeed EP Companion */ - 0x00, /* __u8 ss_bMaxBurst; allows 1 TX between ACKs */ - 0x00, /* __u8 ss_bmAttributes; 1 packet per service interval */ - 0x02, 0x00 /* __le16 ss_wBytesPerInterval; 15 bits for max 15 ports */ -}; - -/* authorized_default behaviour: - * -1 is authorized for all devices except wireless (old behaviour) - * 0 is unauthorized for all devices - * 1 is authorized for all devices - */ -static int authorized_default = -1; -module_param(authorized_default, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(authorized_default, - "Default USB device authorization: 0 is not authorized, 1 is " - "authorized, -1 is authorized except for wireless USB (default, " - "old behaviour"); -/*-------------------------------------------------------------------------*/ - -/** - * ascii2desc() - Helper routine for producing UTF-16LE string descriptors - * @s: Null-terminated ASCII (actually ISO-8859-1) string - * @buf: Buffer for USB string descriptor (header + UTF-16LE) - * @len: Length (in bytes; may be odd) of descriptor buffer. - * - * The return value is the number of bytes filled in: 2 + 2*strlen(s) or - * buflen, whichever is less. - * - * USB String descriptors can contain at most 126 characters; input - * strings longer than that are truncated. - */ -static unsigned -ascii2desc(char const *s, u8 *buf, unsigned len) -{ - unsigned n, t = 2 + 2*strlen(s); - - if (t > 254) - t = 254; /* Longest possible UTF string descriptor */ - if (len > t) - len = t; - - t += USB_DT_STRING << 8; /* Now t is first 16 bits to store */ - - n = len; - while (n--) { - *buf++ = t; - if (!n--) - break; - *buf++ = t >> 8; - t = (unsigned char)*s++; - } - return len; -} - -/** - * rh_string() - provides string descriptors for root hub - * @id: the string ID number (0: langids, 1: serial #, 2: product, 3: vendor) - * @hcd: the host controller for this root hub - * @data: buffer for output packet - * @len: length of the provided buffer - * - * Produces either a manufacturer, product or serial number string for the - * virtual root hub device. - * Returns the number of bytes filled in: the length of the descriptor or - * of the provided buffer, whichever is less. - */ -static unsigned -rh_string(int id, struct usb_hcd const *hcd, u8 *data, unsigned len) -{ - char buf[100]; - char const *s; - static char const langids[4] = {4, USB_DT_STRING, 0x09, 0x04}; - - // language ids - switch (id) { - case 0: - /* Array of LANGID codes (0x0409 is MSFT-speak for "en-us") */ - /* See http://www.usb.org/developers/docs/USB_LANGIDs.pdf */ - if (len > 4) - len = 4; - memcpy(data, langids, len); - return len; - case 1: - /* Serial number */ - s = hcd->self.bus_name; - break; - case 2: - /* Product name */ - s = hcd->product_desc; - break; - case 3: - /* Manufacturer */ - snprintf (buf, sizeof buf, "%s %s %s", init_utsname()->sysname, - init_utsname()->release, hcd->driver->description); - s = buf; - break; - default: - /* Can't happen; caller guarantees it */ - return 0; - } - - return ascii2desc(s, data, len); -} - - -/* Root hub control transfers execute synchronously */ -static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) -{ - struct usb_ctrlrequest *cmd; - u16 typeReq, wValue, wIndex, wLength; - u8 *ubuf = urb->transfer_buffer; - /* - * tbuf should be as big as the BOS descriptor and - * the USB hub descriptor. - */ - u8 tbuf[USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE] - __attribute__((aligned(4))); - const u8 *bufp = tbuf; - unsigned len = 0; - int status; - u8 patch_wakeup = 0; - u8 patch_protocol = 0; - - might_sleep(); - - spin_lock_irq(&hcd_root_hub_lock); - status = usb_hcd_link_urb_to_ep(hcd, urb); - spin_unlock_irq(&hcd_root_hub_lock); - if (status) - return status; - urb->hcpriv = hcd; /* Indicate it's queued */ - - cmd = (struct usb_ctrlrequest *) urb->setup_packet; - typeReq = (cmd->bRequestType << 8) | cmd->bRequest; - wValue = le16_to_cpu (cmd->wValue); - wIndex = le16_to_cpu (cmd->wIndex); - wLength = le16_to_cpu (cmd->wLength); - - if (wLength > urb->transfer_buffer_length) - goto error; - - urb->actual_length = 0; - switch (typeReq) { - - /* DEVICE REQUESTS */ - - /* The root hub's remote wakeup enable bit is implemented using - * driver model wakeup flags. If this system supports wakeup - * through USB, userspace may change the default "allow wakeup" - * policy through sysfs or these calls. - * - * Most root hubs support wakeup from downstream devices, for - * runtime power management (disabling USB clocks and reducing - * VBUS power usage). However, not all of them do so; silicon, - * board, and BIOS bugs here are not uncommon, so these can't - * be treated quite like external hubs. - * - * Likewise, not all root hubs will pass wakeup events upstream, - * to wake up the whole system. So don't assume root hub and - * controller capabilities are identical. - */ - - case DeviceRequest | USB_REQ_GET_STATUS: - tbuf [0] = (device_may_wakeup(&hcd->self.root_hub->dev) - << USB_DEVICE_REMOTE_WAKEUP) - | (1 << USB_DEVICE_SELF_POWERED); - tbuf [1] = 0; - len = 2; - break; - case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: - if (wValue == USB_DEVICE_REMOTE_WAKEUP) - device_set_wakeup_enable(&hcd->self.root_hub->dev, 0); - else - goto error; - break; - case DeviceOutRequest | USB_REQ_SET_FEATURE: - if (device_can_wakeup(&hcd->self.root_hub->dev) - && wValue == USB_DEVICE_REMOTE_WAKEUP) - device_set_wakeup_enable(&hcd->self.root_hub->dev, 1); - else - goto error; - break; - case DeviceRequest | USB_REQ_GET_CONFIGURATION: - tbuf [0] = 1; - len = 1; - /* FALLTHROUGH */ - case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: - break; - case DeviceRequest | USB_REQ_GET_DESCRIPTOR: - switch (wValue & 0xff00) { - case USB_DT_DEVICE << 8: - switch (hcd->speed) { - case HCD_USB3: - bufp = usb3_rh_dev_descriptor; - break; - case HCD_USB2: - bufp = usb2_rh_dev_descriptor; - break; - case HCD_USB11: - bufp = usb11_rh_dev_descriptor; - break; - default: - goto error; - } - len = 18; - if (hcd->has_tt) - patch_protocol = 1; - break; - case USB_DT_CONFIG << 8: - switch (hcd->speed) { - 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; - 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; - break; - case USB_DT_STRING << 8: - if ((wValue & 0xff) < 4) - urb->actual_length = rh_string(wValue & 0xff, - hcd, ubuf, wLength); - else /* unsupported IDs --> "protocol stall" */ - goto error; - break; - case USB_DT_BOS << 8: - goto nongeneric; - default: - goto error; - } - break; - case DeviceRequest | USB_REQ_GET_INTERFACE: - tbuf [0] = 0; - len = 1; - /* FALLTHROUGH */ - case DeviceOutRequest | USB_REQ_SET_INTERFACE: - break; - case DeviceOutRequest | USB_REQ_SET_ADDRESS: - // wValue == urb->dev->devaddr - dev_dbg (hcd->self.controller, "root hub device address %d\n", - wValue); - break; - - /* INTERFACE REQUESTS (no defined feature/status flags) */ - - /* ENDPOINT REQUESTS */ - - case EndpointRequest | USB_REQ_GET_STATUS: - // ENDPOINT_HALT flag - tbuf [0] = 0; - tbuf [1] = 0; - len = 2; - /* FALLTHROUGH */ - case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: - case EndpointOutRequest | USB_REQ_SET_FEATURE: - dev_dbg (hcd->self.controller, "no endpoint features yet\n"); - break; - - /* CLASS REQUESTS (and errors) */ - - default: -nongeneric: - /* non-generic request */ - switch (typeReq) { - case GetHubStatus: - case GetPortStatus: - len = 4; - break; - case GetHubDescriptor: - len = sizeof (struct usb_hub_descriptor); - break; - case DeviceRequest | USB_REQ_GET_DESCRIPTOR: - /* len is returned by hub_control */ - break; - } - status = hcd->driver->hub_control (hcd, - typeReq, wValue, wIndex, - tbuf, wLength); - break; -error: - /* "protocol stall" on error */ - status = -EPIPE; - } - - if (status < 0) { - len = 0; - if (status != -EPIPE) { - dev_dbg (hcd->self.controller, - "CTRL: TypeReq=0x%x val=0x%x " - "idx=0x%x len=%d ==> %d\n", - typeReq, wValue, wIndex, - wLength, status); - } - } else if (status > 0) { - /* hub_control may return the length of data copied. */ - len = status; - status = 0; - } - if (len) { - if (urb->transfer_buffer_length < len) - len = urb->transfer_buffer_length; - urb->actual_length = len; - // always USB_DIR_IN, toward host - memcpy (ubuf, bufp, len); - - /* report whether RH hardware supports remote wakeup */ - if (patch_wakeup && - len > offsetof (struct usb_config_descriptor, - bmAttributes)) - ((struct usb_config_descriptor *)ubuf)->bmAttributes - |= USB_CONFIG_ATT_WAKEUP; - - /* report whether RH hardware has an integrated TT */ - if (patch_protocol && - len > offsetof(struct usb_device_descriptor, - bDeviceProtocol)) - ((struct usb_device_descriptor *) ubuf)-> - bDeviceProtocol = USB_HUB_PR_HS_SINGLE_TT; - } - - /* any errors get returned through the urb completion */ - spin_lock_irq(&hcd_root_hub_lock); - usb_hcd_unlink_urb_from_ep(hcd, urb); - - /* This peculiar use of spinlocks echoes what real HC drivers do. - * Avoiding calls to local_irq_disable/enable makes the code - * RT-friendly. - */ - spin_unlock(&hcd_root_hub_lock); - usb_hcd_giveback_urb(hcd, urb, status); - spin_lock(&hcd_root_hub_lock); - - spin_unlock_irq(&hcd_root_hub_lock); - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* - * Root Hub interrupt transfers are polled using a timer if the - * driver requests it; otherwise the driver is responsible for - * calling usb_hcd_poll_rh_status() when an event occurs. - * - * Completions are called in_interrupt(), but they may or may not - * be in_irq(). - */ -void usb_hcd_poll_rh_status(struct usb_hcd *hcd) -{ - struct urb *urb; - int length; - unsigned long flags; - char buffer[6]; /* Any root hubs with > 31 ports? */ - - if (unlikely(!hcd->rh_pollable)) - return; - if (!hcd->uses_new_polling && !hcd->status_urb) - return; - - length = hcd->driver->hub_status_data(hcd, buffer); - if (length > 0) { - - /* try to complete the status urb */ - spin_lock_irqsave(&hcd_root_hub_lock, flags); - urb = hcd->status_urb; - if (urb) { - clear_bit(HCD_FLAG_POLL_PENDING, &hcd->flags); - hcd->status_urb = NULL; - urb->actual_length = length; - memcpy(urb->transfer_buffer, buffer, length); - - usb_hcd_unlink_urb_from_ep(hcd, urb); - spin_unlock(&hcd_root_hub_lock); - usb_hcd_giveback_urb(hcd, urb, 0); - spin_lock(&hcd_root_hub_lock); - } else { - length = 0; - set_bit(HCD_FLAG_POLL_PENDING, &hcd->flags); - } - spin_unlock_irqrestore(&hcd_root_hub_lock, flags); - } - - /* The USB 2.0 spec says 256 ms. This is close enough and won't - * exceed that limit if HZ is 100. The math is more clunky than - * maybe expected, this is to make sure that all timers for USB devices - * fire at the same time to give the CPU a break in between */ - if (hcd->uses_new_polling ? HCD_POLL_RH(hcd) : - (length == 0 && hcd->status_urb != NULL)) - mod_timer (&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4)); -} -EXPORT_SYMBOL_GPL(usb_hcd_poll_rh_status); - -/* timer callback */ -static void rh_timer_func (unsigned long _hcd) -{ - usb_hcd_poll_rh_status((struct usb_hcd *) _hcd); -} - -/*-------------------------------------------------------------------------*/ - -static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb) -{ - int retval; - unsigned long flags; - unsigned len = 1 + (urb->dev->maxchild / 8); - - spin_lock_irqsave (&hcd_root_hub_lock, flags); - if (hcd->status_urb || urb->transfer_buffer_length < len) { - dev_dbg (hcd->self.controller, "not queuing rh status urb\n"); - retval = -EINVAL; - goto done; - } - - retval = usb_hcd_link_urb_to_ep(hcd, urb); - if (retval) - goto done; - - hcd->status_urb = urb; - urb->hcpriv = hcd; /* indicate it's queued */ - if (!hcd->uses_new_polling) - mod_timer(&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4)); - - /* If a status change has already occurred, report it ASAP */ - else if (HCD_POLL_PENDING(hcd)) - mod_timer(&hcd->rh_timer, jiffies); - retval = 0; - done: - spin_unlock_irqrestore (&hcd_root_hub_lock, flags); - return retval; -} - -static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) -{ - if (usb_endpoint_xfer_int(&urb->ep->desc)) - return rh_queue_status (hcd, urb); - if (usb_endpoint_xfer_control(&urb->ep->desc)) - return rh_call_control (hcd, urb); - return -EINVAL; -} - -/*-------------------------------------------------------------------------*/ - -/* Unlinks of root-hub control URBs are legal, but they don't do anything - * since these URBs always execute synchronously. - */ -static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) -{ - unsigned long flags; - int rc; - - spin_lock_irqsave(&hcd_root_hub_lock, flags); - rc = usb_hcd_check_unlink_urb(hcd, urb, status); - if (rc) - goto done; - - if (usb_endpoint_num(&urb->ep->desc) == 0) { /* Control URB */ - ; /* Do nothing */ - - } else { /* Status URB */ - if (!hcd->uses_new_polling) - del_timer (&hcd->rh_timer); - if (urb == hcd->status_urb) { - hcd->status_urb = NULL; - usb_hcd_unlink_urb_from_ep(hcd, urb); - - spin_unlock(&hcd_root_hub_lock); - usb_hcd_giveback_urb(hcd, urb, status); - spin_lock(&hcd_root_hub_lock); - } - } - done: - spin_unlock_irqrestore(&hcd_root_hub_lock, flags); - return rc; -} - - - -/* - * Show & store the current value of authorized_default - */ -static ssize_t usb_host_authorized_default_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct usb_device *rh_usb_dev = to_usb_device(dev); - struct usb_bus *usb_bus = rh_usb_dev->bus; - struct usb_hcd *usb_hcd; - - if (usb_bus == NULL) /* FIXME: not sure if this case is possible */ - return -ENODEV; - usb_hcd = bus_to_hcd(usb_bus); - return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default); -} - -static ssize_t usb_host_authorized_default_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - ssize_t result; - unsigned val; - struct usb_device *rh_usb_dev = to_usb_device(dev); - struct usb_bus *usb_bus = rh_usb_dev->bus; - struct usb_hcd *usb_hcd; - - if (usb_bus == NULL) /* FIXME: not sure if this case is possible */ - return -ENODEV; - usb_hcd = bus_to_hcd(usb_bus); - result = sscanf(buf, "%u\n", &val); - if (result == 1) { - usb_hcd->authorized_default = val? 1 : 0; - result = size; - } - else - result = -EINVAL; - return result; -} - -static DEVICE_ATTR(authorized_default, 0644, - usb_host_authorized_default_show, - usb_host_authorized_default_store); - - -/* Group all the USB bus attributes */ -static struct attribute *usb_bus_attrs[] = { - &dev_attr_authorized_default.attr, - NULL, -}; - -static struct attribute_group usb_bus_attr_group = { - .name = NULL, /* we want them in the same directory */ - .attrs = usb_bus_attrs, -}; - - - -/*-------------------------------------------------------------------------*/ - -/** - * usb_bus_init - shared initialization code - * @bus: the bus structure being initialized - * - * This code is used to initialize a usb_bus structure, memory for which is - * separately managed. - */ -static void usb_bus_init (struct usb_bus *bus) -{ - memset (&bus->devmap, 0, sizeof(struct usb_devmap)); - - bus->devnum_next = 1; - - bus->root_hub = NULL; - bus->busnum = -1; - bus->bandwidth_allocated = 0; - bus->bandwidth_int_reqs = 0; - bus->bandwidth_isoc_reqs = 0; - - INIT_LIST_HEAD (&bus->bus_list); -} - -/*-------------------------------------------------------------------------*/ - -/** - * usb_register_bus - registers the USB host controller with the usb core - * @bus: pointer to the bus to register - * Context: !in_interrupt() - * - * Assigns a bus number, and links the controller into usbcore data - * structures so that it can be seen by scanning the bus list. - */ -static int usb_register_bus(struct usb_bus *bus) -{ - int result = -E2BIG; - int busnum; - - mutex_lock(&usb_bus_list_lock); - busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1); - if (busnum >= USB_MAXBUS) { - printk (KERN_ERR "%s: too many buses\n", usbcore_name); - goto error_find_busnum; - } - set_bit (busnum, busmap.busmap); - bus->busnum = busnum; - - /* Add it to the local list of buses */ - list_add (&bus->bus_list, &usb_bus_list); - mutex_unlock(&usb_bus_list_lock); - - usb_notify_add_bus(bus); - - dev_info (bus->controller, "new USB bus registered, assigned bus " - "number %d\n", bus->busnum); - return 0; - -error_find_busnum: - mutex_unlock(&usb_bus_list_lock); - return result; -} - -/** - * usb_deregister_bus - deregisters the USB host controller - * @bus: pointer to the bus to deregister - * Context: !in_interrupt() - * - * Recycles the bus number, and unlinks the controller from usbcore data - * structures so that it won't be seen by scanning the bus list. - */ -static void usb_deregister_bus (struct usb_bus *bus) -{ - dev_info (bus->controller, "USB bus %d deregistered\n", bus->busnum); - - /* - * NOTE: make sure that all the devices are removed by the - * controller code, as well as having it call this when cleaning - * itself up - */ - mutex_lock(&usb_bus_list_lock); - list_del (&bus->bus_list); - mutex_unlock(&usb_bus_list_lock); - - usb_notify_remove_bus(bus); - - clear_bit (bus->busnum, busmap.busmap); -} - -/** - * register_root_hub - called by usb_add_hcd() to register a root hub - * @hcd: host controller for this root hub - * - * This function registers the root hub with the USB subsystem. It sets up - * the device properly in the device tree and then calls usb_new_device() - * to register the usb device. It also assigns the root hub's USB address - * (always 1). - */ -static int register_root_hub(struct usb_hcd *hcd) -{ - struct device *parent_dev = hcd->self.controller; - struct usb_device *usb_dev = hcd->self.root_hub; - const int devnum = 1; - int retval; - - usb_dev->devnum = devnum; - usb_dev->bus->devnum_next = devnum + 1; - memset (&usb_dev->bus->devmap.devicemap, 0, - sizeof usb_dev->bus->devmap.devicemap); - set_bit (devnum, usb_dev->bus->devmap.devicemap); - usb_set_device_state(usb_dev, USB_STATE_ADDRESS); - - mutex_lock(&usb_bus_list_lock); - - usb_dev->ep0.desc.wMaxPacketSize = cpu_to_le16(64); - retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE); - if (retval != sizeof usb_dev->descriptor) { - mutex_unlock(&usb_bus_list_lock); - dev_dbg (parent_dev, "can't read %s device descriptor %d\n", - dev_name(&usb_dev->dev), retval); - return (retval < 0) ? retval : -EMSGSIZE; - } - - retval = usb_new_device (usb_dev); - if (retval) { - dev_err (parent_dev, "can't register root hub for %s, %d\n", - dev_name(&usb_dev->dev), retval); - } - mutex_unlock(&usb_bus_list_lock); - - if (retval == 0) { - spin_lock_irq (&hcd_root_hub_lock); - hcd->rh_registered = 1; - spin_unlock_irq (&hcd_root_hub_lock); - - /* Did the HC die before the root hub was registered? */ - if (HCD_DEAD(hcd)) - usb_hc_died (hcd); /* This time clean up */ - } - - return retval; -} - - -/*-------------------------------------------------------------------------*/ - -/** - * usb_calc_bus_time - approximate periodic transaction time in nanoseconds - * @speed: from dev->speed; USB_SPEED_{LOW,FULL,HIGH} - * @is_input: true iff the transaction sends data to the host - * @isoc: true for isochronous transactions, false for interrupt ones - * @bytecount: how many bytes in the transaction. - * - * Returns approximate bus time in nanoseconds for a periodic transaction. - * See USB 2.0 spec section 5.11.3; only periodic transfers need to be - * scheduled in software, this function is only used for such scheduling. - */ -long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount) -{ - unsigned long tmp; - - switch (speed) { - case USB_SPEED_LOW: /* INTR only */ - if (is_input) { - tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L; - return (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); - } else { - tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L; - return (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); - } - case USB_SPEED_FULL: /* ISOC or INTR */ - if (isoc) { - tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; - return (((is_input) ? 7268L : 6265L) + BW_HOST_DELAY + tmp); - } else { - tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; - return (9107L + BW_HOST_DELAY + tmp); - } - case USB_SPEED_HIGH: /* ISOC or INTR */ - // FIXME adjust for input vs output - if (isoc) - tmp = HS_NSECS_ISO (bytecount); - else - tmp = HS_NSECS (bytecount); - return tmp; - default: - pr_debug ("%s: bogus device speed!\n", usbcore_name); - return -1; - } -} -EXPORT_SYMBOL_GPL(usb_calc_bus_time); - - -/*-------------------------------------------------------------------------*/ - -/* - * Generic HC operations. - */ - -/*-------------------------------------------------------------------------*/ - -/** - * usb_hcd_link_urb_to_ep - add an URB to its endpoint queue - * @hcd: host controller to which @urb was submitted - * @urb: URB being submitted - * - * Host controller drivers should call this routine in their enqueue() - * method. The HCD's private spinlock must be held and interrupts must - * be disabled. The actions carried out here are required for URB - * submission, as well as for endpoint shutdown and for usb_kill_urb. - * - * Returns 0 for no error, otherwise a negative error code (in which case - * the enqueue() method must fail). If no error occurs but enqueue() fails - * anyway, it must call usb_hcd_unlink_urb_from_ep() before releasing - * the private spinlock and returning. - */ -int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb) -{ - int rc = 0; - - spin_lock(&hcd_urb_list_lock); - - /* Check that the URB isn't being killed */ - if (unlikely(atomic_read(&urb->reject))) { - rc = -EPERM; - goto done; - } - - if (unlikely(!urb->ep->enabled)) { - rc = -ENOENT; - goto done; - } - - if (unlikely(!urb->dev->can_submit)) { - rc = -EHOSTUNREACH; - goto done; - } - - /* - * Check the host controller's state and add the URB to the - * endpoint's queue. - */ - if (HCD_RH_RUNNING(hcd)) { - urb->unlinked = 0; - list_add_tail(&urb->urb_list, &urb->ep->urb_list); - } else { - rc = -ESHUTDOWN; - goto done; - } - done: - spin_unlock(&hcd_urb_list_lock); - return rc; -} -EXPORT_SYMBOL_GPL(usb_hcd_link_urb_to_ep); - -/** - * usb_hcd_check_unlink_urb - check whether an URB may be unlinked - * @hcd: host controller to which @urb was submitted - * @urb: URB being checked for unlinkability - * @status: error code to store in @urb if the unlink succeeds - * - * Host controller drivers should call this routine in their dequeue() - * method. The HCD's private spinlock must be held and interrupts must - * be disabled. The actions carried out here are required for making - * sure than an unlink is valid. - * - * Returns 0 for no error, otherwise a negative error code (in which case - * the dequeue() method must fail). The possible error codes are: - * - * -EIDRM: @urb was not submitted or has already completed. - * The completion function may not have been called yet. - * - * -EBUSY: @urb has already been unlinked. - */ -int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb, - int status) -{ - struct list_head *tmp; - - /* insist the urb is still queued */ - list_for_each(tmp, &urb->ep->urb_list) { - if (tmp == &urb->urb_list) - break; - } - if (tmp != &urb->urb_list) - return -EIDRM; - - /* Any status except -EINPROGRESS means something already started to - * unlink this URB from the hardware. So there's no more work to do. - */ - if (urb->unlinked) - return -EBUSY; - urb->unlinked = status; - return 0; -} -EXPORT_SYMBOL_GPL(usb_hcd_check_unlink_urb); - -/** - * usb_hcd_unlink_urb_from_ep - remove an URB from its endpoint queue - * @hcd: host controller to which @urb was submitted - * @urb: URB being unlinked - * - * Host controller drivers should call this routine before calling - * usb_hcd_giveback_urb(). The HCD's private spinlock must be held and - * interrupts must be disabled. The actions carried out here are required - * for URB completion. - */ -void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb) -{ - /* clear all state linking urb to this dev (and hcd) */ - spin_lock(&hcd_urb_list_lock); - list_del_init(&urb->urb_list); - spin_unlock(&hcd_urb_list_lock); -} -EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep); - -/* - * Some usb host controllers can only perform dma using a small SRAM area. - * The usb core itself is however optimized for host controllers that can dma - * using regular system memory - like pci devices doing bus mastering. - * - * To support host controllers with limited dma capabilites we provide dma - * bounce buffers. This feature can be enabled using the HCD_LOCAL_MEM flag. - * For this to work properly the host controller code must first use the - * function dma_declare_coherent_memory() to point out which memory area - * that should be used for dma allocations. - * - * The HCD_LOCAL_MEM flag then tells the usb code to allocate all data for - * dma using dma_alloc_coherent() which in turn allocates from the memory - * area pointed out with dma_declare_coherent_memory(). - * - * So, to summarize... - * - * - We need "local" memory, canonical example being - * a small SRAM on a discrete controller being the - * only memory that the controller can read ... - * (a) "normal" kernel memory is no good, and - * (b) there's not enough to share - * - * - The only *portable* hook for such stuff in the - * DMA framework is dma_declare_coherent_memory() - * - * - So we use that, even though the primary requirement - * is that the memory be "local" (hence addressible - * by that device), not "coherent". - * - */ - -static int hcd_alloc_coherent(struct usb_bus *bus, - gfp_t mem_flags, dma_addr_t *dma_handle, - void **vaddr_handle, size_t size, - enum dma_data_direction dir) -{ - unsigned char *vaddr; - - if (*vaddr_handle == NULL) { - WARN_ON_ONCE(1); - return -EFAULT; - } - - vaddr = hcd_buffer_alloc(bus, size + sizeof(vaddr), - mem_flags, dma_handle); - if (!vaddr) - return -ENOMEM; - - /* - * Store the virtual address of the buffer at the end - * of the allocated dma buffer. The size of the buffer - * may be uneven so use unaligned functions instead - * of just rounding up. It makes sense to optimize for - * memory footprint over access speed since the amount - * of memory available for dma may be limited. - */ - put_unaligned((unsigned long)*vaddr_handle, - (unsigned long *)(vaddr + size)); - - if (dir == DMA_TO_DEVICE) - memcpy(vaddr, *vaddr_handle, size); - - *vaddr_handle = vaddr; - return 0; -} - -static void hcd_free_coherent(struct usb_bus *bus, dma_addr_t *dma_handle, - void **vaddr_handle, size_t size, - enum dma_data_direction dir) -{ - unsigned char *vaddr = *vaddr_handle; - - vaddr = (void *)get_unaligned((unsigned long *)(vaddr + size)); - - if (dir == DMA_FROM_DEVICE) - memcpy(vaddr, *vaddr_handle, size); - - hcd_buffer_free(bus, size + sizeof(vaddr), *vaddr_handle, *dma_handle); - - *vaddr_handle = vaddr; - *dma_handle = 0; -} - -void usb_hcd_unmap_urb_setup_for_dma(struct usb_hcd *hcd, struct urb *urb) -{ - if (urb->transfer_flags & URB_SETUP_MAP_SINGLE) - dma_unmap_single(hcd->self.controller, - urb->setup_dma, - sizeof(struct usb_ctrlrequest), - DMA_TO_DEVICE); - else if (urb->transfer_flags & URB_SETUP_MAP_LOCAL) - hcd_free_coherent(urb->dev->bus, - &urb->setup_dma, - (void **) &urb->setup_packet, - sizeof(struct usb_ctrlrequest), - DMA_TO_DEVICE); - - /* Make it safe to call this routine more than once */ - urb->transfer_flags &= ~(URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL); -} -EXPORT_SYMBOL_GPL(usb_hcd_unmap_urb_setup_for_dma); - -static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) -{ - if (hcd->driver->unmap_urb_for_dma) - hcd->driver->unmap_urb_for_dma(hcd, urb); - else - usb_hcd_unmap_urb_for_dma(hcd, urb); -} - -void usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) -{ - enum dma_data_direction dir; - - usb_hcd_unmap_urb_setup_for_dma(hcd, urb); - - dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - if (urb->transfer_flags & URB_DMA_MAP_SG) - dma_unmap_sg(hcd->self.controller, - urb->sg, - urb->num_sgs, - dir); - else if (urb->transfer_flags & URB_DMA_MAP_PAGE) - dma_unmap_page(hcd->self.controller, - urb->transfer_dma, - urb->transfer_buffer_length, - dir); - else if (urb->transfer_flags & URB_DMA_MAP_SINGLE) - dma_unmap_single(hcd->self.controller, - urb->transfer_dma, - urb->transfer_buffer_length, - dir); - else if (urb->transfer_flags & URB_MAP_LOCAL) - hcd_free_coherent(urb->dev->bus, - &urb->transfer_dma, - &urb->transfer_buffer, - urb->transfer_buffer_length, - dir); - - /* Make it safe to call this routine more than once */ - urb->transfer_flags &= ~(URB_DMA_MAP_SG | URB_DMA_MAP_PAGE | - URB_DMA_MAP_SINGLE | URB_MAP_LOCAL); -} -EXPORT_SYMBOL_GPL(usb_hcd_unmap_urb_for_dma); - -static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, - gfp_t mem_flags) -{ - if (hcd->driver->map_urb_for_dma) - return hcd->driver->map_urb_for_dma(hcd, urb, mem_flags); - else - return usb_hcd_map_urb_for_dma(hcd, urb, mem_flags); -} - -int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, - gfp_t mem_flags) -{ - enum dma_data_direction dir; - int ret = 0; - - /* 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, - * or uses the provided scatter gather list for bulk. - */ - - if (usb_endpoint_xfer_control(&urb->ep->desc)) { - if (hcd->self.uses_pio_for_control) - return ret; - if (hcd->self.uses_dma) { - urb->setup_dma = dma_map_single( - hcd->self.controller, - urb->setup_packet, - sizeof(struct usb_ctrlrequest), - DMA_TO_DEVICE); - if (dma_mapping_error(hcd->self.controller, - urb->setup_dma)) - return -EAGAIN; - urb->transfer_flags |= URB_SETUP_MAP_SINGLE; - } else if (hcd->driver->flags & HCD_LOCAL_MEM) { - ret = hcd_alloc_coherent( - urb->dev->bus, mem_flags, - &urb->setup_dma, - (void **)&urb->setup_packet, - sizeof(struct usb_ctrlrequest), - DMA_TO_DEVICE); - if (ret) - return ret; - urb->transfer_flags |= URB_SETUP_MAP_LOCAL; - } - } - - dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - if (urb->transfer_buffer_length != 0 - && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) { - if (hcd->self.uses_dma) { - if (urb->num_sgs) { - int n = dma_map_sg( - hcd->self.controller, - urb->sg, - urb->num_sgs, - dir); - if (n <= 0) - ret = -EAGAIN; - else - urb->transfer_flags |= URB_DMA_MAP_SG; - urb->num_mapped_sgs = n; - if (n != urb->num_sgs) - urb->transfer_flags |= - URB_DMA_SG_COMBINED; - } else if (urb->sg) { - struct scatterlist *sg = urb->sg; - urb->transfer_dma = dma_map_page( - hcd->self.controller, - sg_page(sg), - sg->offset, - urb->transfer_buffer_length, - dir); - if (dma_mapping_error(hcd->self.controller, - urb->transfer_dma)) - ret = -EAGAIN; - else - urb->transfer_flags |= URB_DMA_MAP_PAGE; - } else { - urb->transfer_dma = dma_map_single( - hcd->self.controller, - urb->transfer_buffer, - urb->transfer_buffer_length, - dir); - if (dma_mapping_error(hcd->self.controller, - urb->transfer_dma)) - ret = -EAGAIN; - else - urb->transfer_flags |= URB_DMA_MAP_SINGLE; - } - } else if (hcd->driver->flags & HCD_LOCAL_MEM) { - ret = hcd_alloc_coherent( - urb->dev->bus, mem_flags, - &urb->transfer_dma, - &urb->transfer_buffer, - urb->transfer_buffer_length, - dir); - if (ret == 0) - urb->transfer_flags |= URB_MAP_LOCAL; - } - if (ret && (urb->transfer_flags & (URB_SETUP_MAP_SINGLE | - URB_SETUP_MAP_LOCAL))) - usb_hcd_unmap_urb_for_dma(hcd, urb); - } - return ret; -} -EXPORT_SYMBOL_GPL(usb_hcd_map_urb_for_dma); - -/*-------------------------------------------------------------------------*/ - -/* may be called in any context with a valid urb->dev usecount - * caller surrenders "ownership" of urb - * expects usb_submit_urb() to have sanity checked and conditioned all - * inputs in the urb - */ -int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags) -{ - int status; - struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); - - /* increment urb's reference count as part of giving it to the HCD - * (which will control it). HCD guarantees that it either returns - * an error or calls giveback(), but not both. - */ - usb_get_urb(urb); - atomic_inc(&urb->use_count); - atomic_inc(&urb->dev->urbnum); - usbmon_urb_submit(&hcd->self, urb); - - /* NOTE requirements on root-hub callers (usbfs and the hub - * driver, for now): URBs' urb->transfer_buffer must be - * valid and usb_buffer_{sync,unmap}() not be needed, since - * they could clobber root hub response data. Also, control - * URBs must be submitted in process context with interrupts - * enabled. - */ - - if (is_root_hub(urb->dev)) { - status = rh_urb_enqueue(hcd, urb); - } else { - status = map_urb_for_dma(hcd, urb, mem_flags); - if (likely(status == 0)) { - status = hcd->driver->urb_enqueue(hcd, urb, mem_flags); - if (unlikely(status)) - unmap_urb_for_dma(hcd, urb); - } - } - - if (unlikely(status)) { - usbmon_urb_submit_error(&hcd->self, urb, status); - urb->hcpriv = NULL; - INIT_LIST_HEAD(&urb->urb_list); - atomic_dec(&urb->use_count); - atomic_dec(&urb->dev->urbnum); - if (atomic_read(&urb->reject)) - wake_up(&usb_kill_urb_queue); - usb_put_urb(urb); - } - return status; -} - -/*-------------------------------------------------------------------------*/ - -/* this makes the hcd giveback() the urb more quickly, by kicking it - * off hardware queues (which may take a while) and returning it as - * soon as practical. we've already set up the urb's return status, - * but we can't know if the callback completed already. - */ -static int unlink1(struct usb_hcd *hcd, struct urb *urb, int status) -{ - int value; - - if (is_root_hub(urb->dev)) - value = usb_rh_urb_dequeue(hcd, urb, status); - else { - - /* The only reason an HCD might fail this call is if - * it has not yet fully queued the urb to begin with. - * Such failures should be harmless. */ - value = hcd->driver->urb_dequeue(hcd, urb, status); - } - return value; -} - -/* - * called in any context - * - * caller guarantees urb won't be recycled till both unlink() - * and the urb's completion function return - */ -int usb_hcd_unlink_urb (struct urb *urb, int status) -{ - struct usb_hcd *hcd; - int retval = -EIDRM; - unsigned long flags; - - /* Prevent the device and bus from going away while - * the unlink is carried out. If they are already gone - * then urb->use_count must be 0, since disconnected - * devices can't have any active URBs. - */ - spin_lock_irqsave(&hcd_urb_unlink_lock, flags); - if (atomic_read(&urb->use_count) > 0) { - retval = 0; - usb_get_dev(urb->dev); - } - spin_unlock_irqrestore(&hcd_urb_unlink_lock, flags); - if (retval == 0) { - hcd = bus_to_hcd(urb->dev->bus); - retval = unlink1(hcd, urb, status); - usb_put_dev(urb->dev); - } - - if (retval == 0) - retval = -EINPROGRESS; - else if (retval != -EIDRM && retval != -EBUSY) - dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n", - urb, retval); - return retval; -} - -/*-------------------------------------------------------------------------*/ - -/** - * usb_hcd_giveback_urb - return URB from HCD to device driver - * @hcd: host controller returning the URB - * @urb: urb being returned to the USB device driver. - * @status: completion status code for the URB. - * Context: in_interrupt() - * - * This hands the URB from HCD to its USB device driver, using its - * completion function. The HCD has freed all per-urb resources - * (and is done using urb->hcpriv). It also released all HCD locks; - * the device driver won't cause problems if it frees, modifies, - * or resubmits this URB. - * - * If @urb was unlinked, the value of @status will be overridden by - * @urb->unlinked. Erroneous short transfers are detected in case - * the HCD hasn't checked for them. - */ -void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status) -{ - urb->hcpriv = NULL; - if (unlikely(urb->unlinked)) - status = urb->unlinked; - else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) && - urb->actual_length < urb->transfer_buffer_length && - !status)) - status = -EREMOTEIO; - - unmap_urb_for_dma(hcd, urb); - usbmon_urb_complete(&hcd->self, urb, status); - usb_unanchor_urb(urb); - - /* pass ownership to the completion handler */ - urb->status = status; - urb->complete (urb); - atomic_dec (&urb->use_count); - if (unlikely(atomic_read(&urb->reject))) - wake_up (&usb_kill_urb_queue); - usb_put_urb (urb); -} -EXPORT_SYMBOL_GPL(usb_hcd_giveback_urb); - -/*-------------------------------------------------------------------------*/ - -/* Cancel all URBs pending on this endpoint and wait for the endpoint's - * queue to drain completely. The caller must first insure that no more - * URBs can be submitted for this endpoint. - */ -void usb_hcd_flush_endpoint(struct usb_device *udev, - struct usb_host_endpoint *ep) -{ - struct usb_hcd *hcd; - struct urb *urb; - - if (!ep) - return; - might_sleep(); - hcd = bus_to_hcd(udev->bus); - - /* No more submits can occur */ - spin_lock_irq(&hcd_urb_list_lock); -rescan: - list_for_each_entry (urb, &ep->urb_list, urb_list) { - int is_in; - - if (urb->unlinked) - continue; - usb_get_urb (urb); - is_in = usb_urb_dir_in(urb); - spin_unlock(&hcd_urb_list_lock); - - /* kick hcd */ - unlink1(hcd, urb, -ESHUTDOWN); - dev_dbg (hcd->self.controller, - "shutdown urb %p ep%d%s%s\n", - urb, usb_endpoint_num(&ep->desc), - is_in ? "in" : "out", - ({ char *s; - - switch (usb_endpoint_type(&ep->desc)) { - case USB_ENDPOINT_XFER_CONTROL: - s = ""; break; - case USB_ENDPOINT_XFER_BULK: - s = "-bulk"; break; - case USB_ENDPOINT_XFER_INT: - s = "-intr"; break; - default: - s = "-iso"; break; - }; - s; - })); - usb_put_urb (urb); - - /* list contents may have changed */ - spin_lock(&hcd_urb_list_lock); - goto rescan; - } - spin_unlock_irq(&hcd_urb_list_lock); - - /* Wait until the endpoint queue is completely empty */ - while (!list_empty (&ep->urb_list)) { - spin_lock_irq(&hcd_urb_list_lock); - - /* The list may have changed while we acquired the spinlock */ - urb = NULL; - if (!list_empty (&ep->urb_list)) { - urb = list_entry (ep->urb_list.prev, struct urb, - urb_list); - usb_get_urb (urb); - } - spin_unlock_irq(&hcd_urb_list_lock); - - if (urb) { - usb_kill_urb (urb); - usb_put_urb (urb); - } - } -} - -/** - * usb_hcd_alloc_bandwidth - check whether a new bandwidth setting exceeds - * the bus bandwidth - * @udev: target &usb_device - * @new_config: new configuration to install - * @cur_alt: the current alternate interface setting - * @new_alt: alternate interface setting that is being installed - * - * To change configurations, pass in the new configuration in new_config, - * and pass NULL for cur_alt and new_alt. - * - * To reset a device's configuration (put the device in the ADDRESSED state), - * pass in NULL for new_config, cur_alt, and new_alt. - * - * To change alternate interface settings, pass in NULL for new_config, - * pass in the current alternate interface setting in cur_alt, - * and pass in the new alternate interface setting in new_alt. - * - * Returns an error if the requested bandwidth change exceeds the - * bus bandwidth or host controller internal resources. - */ -int usb_hcd_alloc_bandwidth(struct usb_device *udev, - struct usb_host_config *new_config, - struct usb_host_interface *cur_alt, - struct usb_host_interface *new_alt) -{ - int num_intfs, i, j; - struct usb_host_interface *alt = NULL; - 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 && !cur_alt) { - 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) { - struct usb_host_interface *first_alt; - int iface_num; - - first_alt = &new_config->intf_cache[i]->altsetting[0]; - iface_num = first_alt->desc.bInterfaceNumber; - /* Set up endpoints for alternate interface setting 0 */ - alt = usb_find_alt_setting(new_config, iface_num, 0); - if (!alt) - /* No alt setting 0? Pick the first setting. */ - alt = first_alt; - - for (j = 0; j < alt->desc.bNumEndpoints; j++) { - ret = hcd->driver->add_endpoint(hcd, udev, &alt->endpoint[j]); - if (ret < 0) - goto reset; - } - } - } - if (cur_alt && new_alt) { - struct usb_interface *iface = usb_ifnum_to_if(udev, - cur_alt->desc.bInterfaceNumber); - - if (!iface) - return -EINVAL; - if (iface->resetting_device) { - /* - * The USB core just reset the device, so the xHCI host - * and the device will think alt setting 0 is installed. - * However, the USB core will pass in the alternate - * setting installed before the reset as cur_alt. Dig - * out the alternate setting 0 structure, or the first - * alternate setting if a broken device doesn't have alt - * setting 0. - */ - cur_alt = usb_altnum_to_altsetting(iface, 0); - if (!cur_alt) - cur_alt = &iface->altsetting[0]; - } - - /* Drop all the endpoints in the current alt setting */ - for (i = 0; i < cur_alt->desc.bNumEndpoints; i++) { - ret = hcd->driver->drop_endpoint(hcd, udev, - &cur_alt->endpoint[i]); - if (ret < 0) - goto reset; - } - /* Add all the endpoints in the new alt setting */ - for (i = 0; i < new_alt->desc.bNumEndpoints; i++) { - ret = hcd->driver->add_endpoint(hcd, udev, - &new_alt->endpoint[i]); - 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, - * driver removal, physical disconnect. - * - * example: a qh stored in ep->hcpriv, holding state related to endpoint - * type, maxpacket size, toggle, halt status, and scheduling. - */ -void usb_hcd_disable_endpoint(struct usb_device *udev, - struct usb_host_endpoint *ep) -{ - struct usb_hcd *hcd; - - might_sleep(); - hcd = bus_to_hcd(udev->bus); - if (hcd->driver->endpoint_disable) - hcd->driver->endpoint_disable(hcd, ep); -} - -/** - * usb_hcd_reset_endpoint - reset host endpoint state - * @udev: USB device. - * @ep: the endpoint to reset. - * - * Resets any host endpoint state such as the toggle bit, sequence - * number and current window. - */ -void usb_hcd_reset_endpoint(struct usb_device *udev, - struct usb_host_endpoint *ep) -{ - struct usb_hcd *hcd = bus_to_hcd(udev->bus); - - if (hcd->driver->endpoint_reset) - hcd->driver->endpoint_reset(hcd, ep); - else { - int epnum = usb_endpoint_num(&ep->desc); - int is_out = usb_endpoint_dir_out(&ep->desc); - int is_control = usb_endpoint_xfer_control(&ep->desc); - - usb_settoggle(udev, epnum, is_out, 0); - if (is_control) - usb_settoggle(udev, epnum, !is_out, 0); - } -} - -/** - * usb_alloc_streams - allocate bulk endpoint stream IDs. - * @interface: alternate setting that includes all endpoints. - * @eps: array of endpoints that need streams. - * @num_eps: number of endpoints in the array. - * @num_streams: number of streams to allocate. - * @mem_flags: flags hcd should use to allocate memory. - * - * Sets up a group of bulk endpoints to have num_streams stream IDs available. - * Drivers may queue multiple transfers to different stream IDs, which may - * complete in a different order than they were queued. - */ -int usb_alloc_streams(struct usb_interface *interface, - struct usb_host_endpoint **eps, unsigned int num_eps, - unsigned int num_streams, gfp_t mem_flags) -{ - struct usb_hcd *hcd; - struct usb_device *dev; - int i; - - dev = interface_to_usbdev(interface); - hcd = bus_to_hcd(dev->bus); - if (!hcd->driver->alloc_streams || !hcd->driver->free_streams) - return -EINVAL; - if (dev->speed != USB_SPEED_SUPER) - return -EINVAL; - - /* Streams only apply to bulk endpoints. */ - for (i = 0; i < num_eps; i++) - if (!usb_endpoint_xfer_bulk(&eps[i]->desc)) - return -EINVAL; - - return hcd->driver->alloc_streams(hcd, dev, eps, num_eps, - num_streams, mem_flags); -} -EXPORT_SYMBOL_GPL(usb_alloc_streams); - -/** - * usb_free_streams - free bulk endpoint stream IDs. - * @interface: alternate setting that includes all endpoints. - * @eps: array of endpoints to remove streams from. - * @num_eps: number of endpoints in the array. - * @mem_flags: flags hcd should use to allocate memory. - * - * Reverts a group of bulk endpoints back to not using stream IDs. - * Can fail if we are given bad arguments, or HCD is broken. - */ -void usb_free_streams(struct usb_interface *interface, - struct usb_host_endpoint **eps, unsigned int num_eps, - gfp_t mem_flags) -{ - struct usb_hcd *hcd; - struct usb_device *dev; - int i; - - dev = interface_to_usbdev(interface); - hcd = bus_to_hcd(dev->bus); - if (dev->speed != USB_SPEED_SUPER) - return; - - /* Streams only apply to bulk endpoints. */ - for (i = 0; i < num_eps; i++) - if (!eps[i] || !usb_endpoint_xfer_bulk(&eps[i]->desc)) - return; - - hcd->driver->free_streams(hcd, dev, eps, num_eps, mem_flags); -} -EXPORT_SYMBOL_GPL(usb_free_streams); - -/* Protect against drivers that try to unlink URBs after the device - * is gone, by waiting until all unlinks for @udev are finished. - * Since we don't currently track URBs by device, simply wait until - * nothing is running in the locked region of usb_hcd_unlink_urb(). - */ -void usb_hcd_synchronize_unlinks(struct usb_device *udev) -{ - spin_lock_irq(&hcd_urb_unlink_lock); - spin_unlock_irq(&hcd_urb_unlink_lock); -} - -/*-------------------------------------------------------------------------*/ - -/* called in any context */ -int usb_hcd_get_frame_number (struct usb_device *udev) -{ - struct usb_hcd *hcd = bus_to_hcd(udev->bus); - - if (!HCD_RH_RUNNING(hcd)) - return -ESHUTDOWN; - return hcd->driver->get_frame_number (hcd); -} - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_PM - -int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg) -{ - struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self); - int status; - int old_state = hcd->state; - - dev_dbg(&rhdev->dev, "bus %ssuspend, wakeup %d\n", - (PMSG_IS_AUTO(msg) ? "auto-" : ""), - rhdev->do_remote_wakeup); - if (HCD_DEAD(hcd)) { - dev_dbg(&rhdev->dev, "skipped %s of dead bus\n", "suspend"); - return 0; - } - - if (!hcd->driver->bus_suspend) { - status = -ENOENT; - } else { - clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags); - hcd->state = HC_STATE_QUIESCING; - status = hcd->driver->bus_suspend(hcd); - } - if (status == 0) { - usb_set_device_state(rhdev, USB_STATE_SUSPENDED); - hcd->state = HC_STATE_SUSPENDED; - - /* Did we race with a root-hub wakeup event? */ - if (rhdev->do_remote_wakeup) { - char buffer[6]; - - status = hcd->driver->hub_status_data(hcd, buffer); - if (status != 0) { - dev_dbg(&rhdev->dev, "suspend raced with wakeup event\n"); - hcd_bus_resume(rhdev, PMSG_AUTO_RESUME); - status = -EBUSY; - } - } - } else { - spin_lock_irq(&hcd_root_hub_lock); - if (!HCD_DEAD(hcd)) { - set_bit(HCD_FLAG_RH_RUNNING, &hcd->flags); - hcd->state = old_state; - } - spin_unlock_irq(&hcd_root_hub_lock); - dev_dbg(&rhdev->dev, "bus %s fail, err %d\n", - "suspend", status); - } - return status; -} - -int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg) -{ - struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self); - int status; - int old_state = hcd->state; - - dev_dbg(&rhdev->dev, "usb %sresume\n", - (PMSG_IS_AUTO(msg) ? "auto-" : "")); - if (HCD_DEAD(hcd)) { - dev_dbg(&rhdev->dev, "skipped %s of dead bus\n", "resume"); - return 0; - } - if (!hcd->driver->bus_resume) - return -ENOENT; - if (HCD_RH_RUNNING(hcd)) - return 0; - - hcd->state = HC_STATE_RESUMING; - status = hcd->driver->bus_resume(hcd); - clear_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags); - if (status == 0) { - /* TRSMRCY = 10 msec */ - msleep(10); - spin_lock_irq(&hcd_root_hub_lock); - if (!HCD_DEAD(hcd)) { - usb_set_device_state(rhdev, rhdev->actconfig - ? USB_STATE_CONFIGURED - : USB_STATE_ADDRESS); - set_bit(HCD_FLAG_RH_RUNNING, &hcd->flags); - hcd->state = HC_STATE_RUNNING; - } - spin_unlock_irq(&hcd_root_hub_lock); - } else { - hcd->state = old_state; - dev_dbg(&rhdev->dev, "bus %s fail, err %d\n", - "resume", status); - if (status != -ESHUTDOWN) - usb_hc_died(hcd); - } - return status; -} - -#endif /* CONFIG_PM */ - -#ifdef CONFIG_USB_SUSPEND - -/* Workqueue routine for root-hub remote wakeup */ -static void hcd_resume_work(struct work_struct *work) -{ - struct usb_hcd *hcd = container_of(work, struct usb_hcd, wakeup_work); - struct usb_device *udev = hcd->self.root_hub; - - usb_lock_device(udev); - usb_remote_wakeup(udev); - usb_unlock_device(udev); -} - -/** - * usb_hcd_resume_root_hub - called by HCD to resume its root hub - * @hcd: host controller for this root hub - * - * The USB host controller calls this function when its root hub is - * suspended (with the remote wakeup feature enabled) and a remote - * wakeup request is received. The routine submits a workqueue request - * to resume the root hub (that is, manage its downstream ports again). - */ -void usb_hcd_resume_root_hub (struct usb_hcd *hcd) -{ - unsigned long flags; - - spin_lock_irqsave (&hcd_root_hub_lock, flags); - if (hcd->rh_registered) { - set_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags); - queue_work(pm_wq, &hcd->wakeup_work); - } - spin_unlock_irqrestore (&hcd_root_hub_lock, flags); -} -EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub); - -#endif /* CONFIG_USB_SUSPEND */ - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_USB_OTG - -/** - * usb_bus_start_enum - start immediate enumeration (for OTG) - * @bus: the bus (must use hcd framework) - * @port_num: 1-based number of port; usually bus->otg_port - * Context: in_interrupt() - * - * Starts enumeration, with an immediate reset followed later by - * khubd identifying and possibly configuring the device. - * This is needed by OTG controller drivers, where it helps meet - * HNP protocol timing requirements for starting a port reset. - */ -int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num) -{ - struct usb_hcd *hcd; - int status = -EOPNOTSUPP; - - /* NOTE: since HNP can't start by grabbing the bus's address0_sem, - * boards with root hubs hooked up to internal devices (instead of - * just the OTG port) may need more attention to resetting... - */ - hcd = container_of (bus, struct usb_hcd, self); - if (port_num && hcd->driver->start_port_reset) - status = hcd->driver->start_port_reset(hcd, port_num); - - /* run khubd shortly after (first) root port reset finishes; - * it may issue others, until at least 50 msecs have passed. - */ - if (status == 0) - mod_timer(&hcd->rh_timer, jiffies + msecs_to_jiffies(10)); - return status; -} -EXPORT_SYMBOL_GPL(usb_bus_start_enum); - -#endif - -/*-------------------------------------------------------------------------*/ - -/** - * usb_hcd_irq - hook IRQs to HCD framework (bus glue) - * @irq: the IRQ being raised - * @__hcd: pointer to the HCD whose IRQ is being signaled - * - * If the controller isn't HALTed, calls the driver's irq handler. - * Checks whether the controller is now dead. - */ -irqreturn_t usb_hcd_irq (int irq, void *__hcd) -{ - struct usb_hcd *hcd = __hcd; - unsigned long flags; - irqreturn_t rc; - - /* IRQF_DISABLED doesn't work correctly with shared IRQs - * when the first handler doesn't use it. So let's just - * assume it's never used. - */ - local_irq_save(flags); - - if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd))) - rc = IRQ_NONE; - else if (hcd->driver->irq(hcd) == IRQ_NONE) - rc = IRQ_NONE; - else - rc = IRQ_HANDLED; - - local_irq_restore(flags); - return rc; -} -EXPORT_SYMBOL_GPL(usb_hcd_irq); - -/*-------------------------------------------------------------------------*/ - -/** - * usb_hc_died - report abnormal shutdown of a host controller (bus glue) - * @hcd: pointer to the HCD representing the controller - * - * This is called by bus glue to report a USB host controller that died - * while operations may still have been pending. It's called automatically - * by the PCI glue, so only glue for non-PCI busses should need to call it. - * - * Only call this function with the primary HCD. - */ -void usb_hc_died (struct usb_hcd *hcd) -{ - unsigned long flags; - - dev_err (hcd->self.controller, "HC died; cleaning up\n"); - - spin_lock_irqsave (&hcd_root_hub_lock, flags); - clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags); - set_bit(HCD_FLAG_DEAD, &hcd->flags); - if (hcd->rh_registered) { - clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); - - /* make khubd clean up old urbs and devices */ - usb_set_device_state (hcd->self.root_hub, - USB_STATE_NOTATTACHED); - usb_kick_khubd (hcd->self.root_hub); - } - if (usb_hcd_is_primary_hcd(hcd) && hcd->shared_hcd) { - hcd = hcd->shared_hcd; - if (hcd->rh_registered) { - clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); - - /* make khubd clean up old urbs and devices */ - usb_set_device_state(hcd->self.root_hub, - USB_STATE_NOTATTACHED); - usb_kick_khubd(hcd->self.root_hub); - } - } - spin_unlock_irqrestore (&hcd_root_hub_lock, flags); - /* Make sure that the other roothub is also deallocated. */ -} -EXPORT_SYMBOL_GPL (usb_hc_died); - -/*-------------------------------------------------------------------------*/ - -/** - * usb_create_shared_hcd - create and initialize an HCD structure - * @driver: HC driver that will use this hcd - * @dev: device for this HC, stored in hcd->self.controller - * @bus_name: value to store in hcd->self.bus_name - * @primary_hcd: a pointer to the usb_hcd structure that is sharing the - * PCI device. Only allocate certain resources for the primary HCD - * Context: !in_interrupt() - * - * Allocate a struct usb_hcd, with extra space at the end for the - * HC driver's private data. Initialize the generic members of the - * hcd structure. - * - * If memory is unavailable, returns NULL. - */ -struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver, - struct device *dev, const char *bus_name, - struct usb_hcd *primary_hcd) -{ - struct usb_hcd *hcd; - - hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL); - if (!hcd) { - dev_dbg (dev, "hcd alloc failed\n"); - return NULL; - } - if (primary_hcd == NULL) { - hcd->bandwidth_mutex = kmalloc(sizeof(*hcd->bandwidth_mutex), - GFP_KERNEL); - if (!hcd->bandwidth_mutex) { - kfree(hcd); - dev_dbg(dev, "hcd bandwidth mutex alloc failed\n"); - return NULL; - } - mutex_init(hcd->bandwidth_mutex); - dev_set_drvdata(dev, hcd); - } else { - hcd->bandwidth_mutex = primary_hcd->bandwidth_mutex; - hcd->primary_hcd = primary_hcd; - primary_hcd->primary_hcd = primary_hcd; - hcd->shared_hcd = primary_hcd; - primary_hcd->shared_hcd = hcd; - } - - kref_init(&hcd->kref); - - usb_bus_init(&hcd->self); - hcd->self.controller = dev; - hcd->self.bus_name = bus_name; - hcd->self.uses_dma = (dev->dma_mask != NULL); - - init_timer(&hcd->rh_timer); - hcd->rh_timer.function = rh_timer_func; - hcd->rh_timer.data = (unsigned long) hcd; -#ifdef CONFIG_USB_SUSPEND - INIT_WORK(&hcd->wakeup_work, hcd_resume_work); -#endif - - hcd->driver = driver; - hcd->speed = driver->flags & HCD_MASK; - hcd->product_desc = (driver->product_desc) ? driver->product_desc : - "USB Host Controller"; - return hcd; -} -EXPORT_SYMBOL_GPL(usb_create_shared_hcd); - -/** - * usb_create_hcd - create and initialize an HCD structure - * @driver: HC driver that will use this hcd - * @dev: device for this HC, stored in hcd->self.controller - * @bus_name: value to store in hcd->self.bus_name - * Context: !in_interrupt() - * - * Allocate a struct usb_hcd, with extra space at the end for the - * HC driver's private data. Initialize the generic members of the - * hcd structure. - * - * If memory is unavailable, returns NULL. - */ -struct usb_hcd *usb_create_hcd(const struct hc_driver *driver, - struct device *dev, const char *bus_name) -{ - return usb_create_shared_hcd(driver, dev, bus_name, NULL); -} -EXPORT_SYMBOL_GPL(usb_create_hcd); - -/* - * Roothubs that share one PCI device must also share the bandwidth mutex. - * Don't deallocate the bandwidth_mutex until the last shared usb_hcd is - * deallocated. - * - * Make sure to only deallocate the bandwidth_mutex when the primary HCD is - * freed. When hcd_release() is called for the non-primary HCD, set the - * primary_hcd's shared_hcd pointer to null (since the non-primary HCD will be - * freed shortly). - */ -static void hcd_release (struct kref *kref) -{ - struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref); - - if (usb_hcd_is_primary_hcd(hcd)) - kfree(hcd->bandwidth_mutex); - else - hcd->shared_hcd->shared_hcd = NULL; - kfree(hcd); -} - -struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd) -{ - if (hcd) - kref_get (&hcd->kref); - return hcd; -} -EXPORT_SYMBOL_GPL(usb_get_hcd); - -void usb_put_hcd (struct usb_hcd *hcd) -{ - if (hcd) - kref_put (&hcd->kref, hcd_release); -} -EXPORT_SYMBOL_GPL(usb_put_hcd); - -int usb_hcd_is_primary_hcd(struct usb_hcd *hcd) -{ - if (!hcd->primary_hcd) - return 1; - return hcd == hcd->primary_hcd; -} -EXPORT_SYMBOL_GPL(usb_hcd_is_primary_hcd); - -static int usb_hcd_request_irqs(struct usb_hcd *hcd, - unsigned int irqnum, unsigned long irqflags) -{ - int retval; - - if (hcd->driver->irq) { - - /* IRQF_DISABLED doesn't work as advertised when used together - * with IRQF_SHARED. As usb_hcd_irq() will always disable - * interrupts we can remove it here. - */ - if (irqflags & IRQF_SHARED) - irqflags &= ~IRQF_DISABLED; - - snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d", - hcd->driver->description, hcd->self.busnum); - retval = request_irq(irqnum, &usb_hcd_irq, irqflags, - hcd->irq_descr, hcd); - if (retval != 0) { - dev_err(hcd->self.controller, - "request interrupt %d failed\n", - irqnum); - return retval; - } - hcd->irq = irqnum; - dev_info(hcd->self.controller, "irq %d, %s 0x%08llx\n", irqnum, - (hcd->driver->flags & HCD_MEMORY) ? - "io mem" : "io base", - (unsigned long long)hcd->rsrc_start); - } else { - hcd->irq = 0; - if (hcd->rsrc_start) - dev_info(hcd->self.controller, "%s 0x%08llx\n", - (hcd->driver->flags & HCD_MEMORY) ? - "io mem" : "io base", - (unsigned long long)hcd->rsrc_start); - } - return 0; -} - -/** - * usb_add_hcd - finish generic HCD structure initialization and register - * @hcd: the usb_hcd structure to initialize - * @irqnum: Interrupt line to allocate - * @irqflags: Interrupt type flags - * - * Finish the remaining parts of generic HCD initialization: allocate the - * buffers of consistent memory, register the bus, request the IRQ line, - * and call the driver's reset() and start() routines. - */ -extern char enable_ehci_wake; - -int usb_add_hcd(struct usb_hcd *hcd, - unsigned int irqnum, unsigned long irqflags) -{ - int retval; - struct usb_device *rhdev; - - dev_info(hcd->self.controller, "%s\n", hcd->product_desc); - - /* Keep old behaviour if authorized_default is not in [0, 1]. */ - if (authorized_default < 0 || authorized_default > 1) - hcd->authorized_default = hcd->wireless? 0 : 1; - else - hcd->authorized_default = authorized_default; - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - - /* HC is in reset state, but accessible. Now do the one-time init, - * bottom up so that hcds can customize the root hubs before khubd - * starts talking to them. (Note, bus id is assigned early too.) - */ - if ((retval = hcd_buffer_create(hcd)) != 0) { - dev_dbg(hcd->self.controller, "pool alloc failed\n"); - return retval; - } - - if ((retval = usb_register_bus(&hcd->self)) < 0) - goto err_register_bus; - - if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) { - dev_err(hcd->self.controller, "unable to allocate root hub\n"); - retval = -ENOMEM; - goto err_allocate_root_hub; - } - hcd->self.root_hub = rhdev; - - switch (hcd->speed) { - 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: - retval = -EINVAL; - goto err_set_rh_speed; - } - - /* wakeup flag init defaults to "everything works" for root hubs, - * but drivers can override it in reset() if needed, along with - * recording the overall controller's system wakeup capability. - */ - if (enable_ehci_wake) { - device_init_wakeup(&rhdev->dev, 1); - } - - //device_set_wakeup_capable(&rhdev->dev, 1); - - /* HCD_FLAG_RH_RUNNING doesn't matter until the root hub is - * registered. But since the controller can die at any time, - * let's initialize the flag before touching the hardware. - */ - set_bit(HCD_FLAG_RH_RUNNING, &hcd->flags); - - /* "reset" is misnamed; its role is now one-time init. the controller - * should already have been reset (and boot firmware kicked off etc). - */ - if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) { - dev_err(hcd->self.controller, "can't setup\n"); - goto err_hcd_driver_setup; - } - hcd->rh_pollable = 1; - - /* NOTE: root hub and controller capabilities may not be the same */ - if (device_can_wakeup(hcd->self.controller) - && device_can_wakeup(&hcd->self.root_hub->dev)) - dev_dbg(hcd->self.controller, "supports USB remote wakeup\n"); - - /* enable irqs just before we start the controller, - * if the BIOS provides legacy PCI irqs. - */ - if (usb_hcd_is_primary_hcd(hcd) && irqnum) { - retval = usb_hcd_request_irqs(hcd, irqnum, irqflags); - if (retval) - goto err_request_irq; - } - - hcd->state = HC_STATE_RUNNING; - retval = hcd->driver->start(hcd); - if (retval < 0) { - dev_err(hcd->self.controller, "startup error %d\n", retval); - goto err_hcd_driver_start; - } - - /* starting here, usbcore will pay attention to this root hub */ - rhdev->bus_mA = min(500u, hcd->power_budget); - if ((retval = register_root_hub(hcd)) != 0) - goto err_register_root_hub; - - retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group); - if (retval < 0) { - printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n", - retval); - goto error_create_attr_group; - } - if (hcd->uses_new_polling && HCD_POLL_RH(hcd)) - usb_hcd_poll_rh_status(hcd); - - /* - * Host controllers don't generate their own wakeup requests; - * they only forward requests from the root hub. Therefore - * controllers should always be enabled for remote wakeup. - */ - - if (enable_ehci_wake) { - device_wakeup_enable(hcd->self.controller); - } - - return retval; - -error_create_attr_group: - clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags); - if (HC_IS_RUNNING(hcd->state)) - hcd->state = HC_STATE_QUIESCING; - spin_lock_irq(&hcd_root_hub_lock); - hcd->rh_registered = 0; - spin_unlock_irq(&hcd_root_hub_lock); - -#ifdef CONFIG_USB_SUSPEND - cancel_work_sync(&hcd->wakeup_work); -#endif - mutex_lock(&usb_bus_list_lock); - usb_disconnect(&rhdev); /* Sets rhdev to NULL */ - mutex_unlock(&usb_bus_list_lock); -err_register_root_hub: - hcd->rh_pollable = 0; - clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); - del_timer_sync(&hcd->rh_timer); - hcd->driver->stop(hcd); - hcd->state = HC_STATE_HALT; - clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); - del_timer_sync(&hcd->rh_timer); -err_hcd_driver_start: - if (usb_hcd_is_primary_hcd(hcd) && hcd->irq > 0) - free_irq(irqnum, hcd); -err_request_irq: -err_hcd_driver_setup: -err_set_rh_speed: - usb_put_dev(hcd->self.root_hub); -err_allocate_root_hub: - usb_deregister_bus(&hcd->self); -err_register_bus: - hcd_buffer_destroy(hcd); - return retval; -} -EXPORT_SYMBOL_GPL(usb_add_hcd); - -/** - * usb_remove_hcd - shutdown processing for generic HCDs - * @hcd: the usb_hcd structure to remove - * Context: !in_interrupt() - * - * Disconnects the root hub, then reverses the effects of usb_add_hcd(), - * invoking the HCD's stop() method. - */ -void usb_remove_hcd(struct usb_hcd *hcd) -{ - struct usb_device *rhdev = hcd->self.root_hub; - - dev_info(hcd->self.controller, "remove, state %x\n", hcd->state); - - usb_get_dev(rhdev); - sysfs_remove_group(&rhdev->dev.kobj, &usb_bus_attr_group); - - clear_bit(HCD_FLAG_RH_RUNNING, &hcd->flags); - if (HC_IS_RUNNING (hcd->state)) - hcd->state = HC_STATE_QUIESCING; - - dev_dbg(hcd->self.controller, "roothub graceful disconnect\n"); - spin_lock_irq (&hcd_root_hub_lock); - hcd->rh_registered = 0; - spin_unlock_irq (&hcd_root_hub_lock); - -#ifdef CONFIG_USB_SUSPEND - cancel_work_sync(&hcd->wakeup_work); -#endif - - mutex_lock(&usb_bus_list_lock); - usb_disconnect(&rhdev); /* Sets rhdev to NULL */ - mutex_unlock(&usb_bus_list_lock); - - /* Prevent any more root-hub status calls from the timer. - * The HCD might still restart the timer (if a port status change - * interrupt occurs), but usb_hcd_poll_rh_status() won't invoke - * the hub_status_data() callback. - */ - hcd->rh_pollable = 0; - clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); - del_timer_sync(&hcd->rh_timer); - - hcd->driver->stop(hcd); - hcd->state = HC_STATE_HALT; - - /* In case the HCD restarted the timer, stop it again. */ - clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); - del_timer_sync(&hcd->rh_timer); - - if (usb_hcd_is_primary_hcd(hcd)) { - if (hcd->irq > 0) - free_irq(hcd->irq, hcd); - } - - usb_put_dev(hcd->self.root_hub); - usb_deregister_bus(&hcd->self); - hcd_buffer_destroy(hcd); -} -EXPORT_SYMBOL_GPL(usb_remove_hcd); - -void -usb_hcd_platform_shutdown(struct platform_device* dev) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} -EXPORT_SYMBOL_GPL(usb_hcd_platform_shutdown); - -/*-------------------------------------------------------------------------*/ - -#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE) - -struct usb_mon_operations *mon_ops; - -/* - * The registration is unlocked. - * We do it this way because we do not want to lock in hot paths. - * - * Notice that the code is minimally error-proof. Because usbmon needs - * symbols from usbcore, usbcore gets referenced and cannot be unloaded first. - */ - -int usb_mon_register (struct usb_mon_operations *ops) -{ - - if (mon_ops) - return -EBUSY; - - mon_ops = ops; - mb(); - return 0; -} -EXPORT_SYMBOL_GPL (usb_mon_register); - -void usb_mon_deregister (void) -{ - - if (mon_ops == NULL) { - printk(KERN_ERR "USB: monitor was not registered\n"); - return; - } - mon_ops = NULL; - mb(); -} -EXPORT_SYMBOL_GPL (usb_mon_deregister); - -#endif /* CONFIG_USB_MON || CONFIG_USB_MON_MODULE */ diff --git a/ANDROID_3.4.5/drivers/usb/core/hub.c b/ANDROID_3.4.5/drivers/usb/core/hub.c deleted file mode 100644 index d6dab03a..00000000 --- a/ANDROID_3.4.5/drivers/usb/core/hub.c +++ /dev/null @@ -1,4284 +0,0 @@ -/* - * USB hub driver. - * - * (C) Copyright 1999 Linus Torvalds - * (C) Copyright 1999 Johannes Erdfelt - * (C) Copyright 1999 Gregory P. Smith - * (C) Copyright 2001 Brad Hards (bhards@bigpond.net.au) - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "usb.h" - -/* if we are in debug mode, always announce new devices */ -#ifdef DEBUG -#ifndef CONFIG_USB_ANNOUNCE_NEW_DEVICES -#define CONFIG_USB_ANNOUNCE_NEW_DEVICES -#endif -#endif - -struct usb_hub { - struct device *intfdev; /* the "interface" device */ - struct usb_device *hdev; - struct kref kref; - struct urb *urb; /* for interrupt polling pipe */ - - /* buffer for urb ... with extra space in case of babble */ - char (*buffer)[8]; - union { - struct usb_hub_status hub; - struct usb_port_status port; - } *status; /* buffer for status reports */ - struct mutex status_mutex; /* for the status buffer */ - - int error; /* last reported error */ - int nerrors; /* track consecutive errors */ - - struct list_head event_list; /* hubs w/data or errs ready */ - unsigned long event_bits[1]; /* status change bitmask */ - unsigned long change_bits[1]; /* ports with logical connect - status change */ - unsigned long busy_bits[1]; /* ports being reset or - resumed */ - unsigned long removed_bits[1]; /* ports with a "removed" - device present */ - unsigned long wakeup_bits[1]; /* ports that have signaled - remote wakeup */ -#if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */ -#error event_bits[] is too short! -#endif - - struct usb_hub_descriptor *descriptor; /* class descriptor */ - struct usb_tt tt; /* Transaction Translator */ - - unsigned mA_per_port; /* current for each child */ - - unsigned limited_power:1; - unsigned quiescing:1; - unsigned disconnected:1; - - unsigned has_indicators:1; - u8 indicator[USB_MAXCHILDREN]; - struct delayed_work leds; - struct delayed_work init_work; - void **port_owners; -}; - -static inline int hub_is_superspeed(struct usb_device *hdev) -{ - return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS); -} - -/* Protect struct usb_device->state and ->children members - * Note: Both are also protected by ->dev.sem, except that ->state can - * change to USB_STATE_NOTATTACHED even when the semaphore isn't held. */ -static DEFINE_SPINLOCK(device_state_lock); - -/* khubd's worklist and its lock */ -static DEFINE_SPINLOCK(hub_event_lock); -static LIST_HEAD(hub_event_list); /* List of hubs needing servicing */ - -/* Wakes up khubd */ -static DECLARE_WAIT_QUEUE_HEAD(khubd_wait); - -static struct task_struct *khubd_task; - -/* cycle leds on hubs that aren't blinking for attention */ -static bool blinkenlights = 0; -module_param (blinkenlights, bool, S_IRUGO); -MODULE_PARM_DESC (blinkenlights, "true to cycle leds on hubs"); - -/* - * Device SATA8000 FW1.0 from DATAST0R Technology Corp requires about - * 10 seconds to send reply for the initial 64-byte descriptor request. - */ -/* define initial 64-byte descriptor request timeout in milliseconds */ -static int initial_descriptor_timeout = USB_CTRL_GET_TIMEOUT; -module_param(initial_descriptor_timeout, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(initial_descriptor_timeout, - "initial 64-byte descriptor request timeout in milliseconds " - "(default 5000 - 5.0 seconds)"); - -/* - * As of 2.6.10 we introduce a new USB device initialization scheme which - * closely resembles the way Windows works. Hopefully it will be compatible - * with a wider range of devices than the old scheme. However some previously - * working devices may start giving rise to "device not accepting address" - * errors; if that happens the user can try the old scheme by adjusting the - * following module parameters. - * - * For maximum flexibility there are two boolean parameters to control the - * hub driver's behavior. On the first initialization attempt, if the - * "old_scheme_first" parameter is set then the old scheme will be used, - * otherwise the new scheme is used. If that fails and "use_both_schemes" - * is set, then the driver will make another attempt, using the other scheme. - */ -static bool old_scheme_first = 0; -module_param(old_scheme_first, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(old_scheme_first, - "start with the old device initialization scheme"); - -static bool use_both_schemes = 1; -module_param(use_both_schemes, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(use_both_schemes, - "try the other device initialization scheme if the " - "first one fails"); - -/* Mutual exclusion for EHCI CF initialization. This interferes with - * port reset on some companion controllers. - */ -DECLARE_RWSEM(ehci_cf_port_reset_rwsem); -EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem); - -#define HUB_DEBOUNCE_TIMEOUT 1500 -#define HUB_DEBOUNCE_STEP 25 -#define HUB_DEBOUNCE_STABLE 100 -unsigned int usb_storage_id = 0; - -static int usb_reset_and_verify_device(struct usb_device *udev); - -static inline char *portspeed(struct usb_hub *hub, int portstatus) -{ - if (hub_is_superspeed(hub->hdev)) - return "5.0 Gb/s"; - if (portstatus & USB_PORT_STAT_HIGH_SPEED) - return "480 Mb/s"; - else if (portstatus & USB_PORT_STAT_LOW_SPEED) - return "1.5 Mb/s"; - else - return "12 Mb/s"; -} - -/* Note that hdev or one of its children must be locked! */ -static struct usb_hub *hdev_to_hub(struct usb_device *hdev) -{ - if (!hdev || !hdev->actconfig) - return NULL; - return usb_get_intfdata(hdev->actconfig->interface[0]); -} - -/* USB 2.0 spec Section 11.24.4.5 */ -static int get_hub_descriptor(struct usb_device *hdev, void *data) -{ - int i, ret, size; - unsigned dtype; - - if (hub_is_superspeed(hdev)) { - dtype = USB_DT_SS_HUB; - size = USB_DT_SS_HUB_SIZE; - } else { - dtype = USB_DT_HUB; - size = sizeof(struct usb_hub_descriptor); - } - - for (i = 0; i < 3; i++) { - ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0), - USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB, - dtype << 8, 0, data, size, - USB_CTRL_GET_TIMEOUT); - if (ret >= (USB_DT_HUB_NONVAR_SIZE + 2)) - return ret; - } - return -EINVAL; -} - -/* - * USB 2.0 spec Section 11.24.2.1 - */ -static int clear_hub_feature(struct usb_device *hdev, int feature) -{ - return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), - USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0, NULL, 0, 1000); -} - -/* - * USB 2.0 spec Section 11.24.2.2 - */ -static int clear_port_feature(struct usb_device *hdev, int port1, int feature) -{ - return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), - USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port1, - NULL, 0, 1000); -} - -/* - * USB 2.0 spec Section 11.24.2.13 - */ -static int set_port_feature(struct usb_device *hdev, int port1, int feature) -{ - return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), - USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port1, - NULL, 0, 1000); -} - -/* - * USB 2.0 spec Section 11.24.2.7.1.10 and table 11-7 - * for info about using port indicators - */ -static void set_port_led( - struct usb_hub *hub, - int port1, - int selector -) -{ - int status = set_port_feature(hub->hdev, (selector << 8) | port1, - USB_PORT_FEAT_INDICATOR); - if (status < 0) - dev_dbg (hub->intfdev, - "port %d indicator %s status %d\n", - port1, - ({ char *s; switch (selector) { - case HUB_LED_AMBER: s = "amber"; break; - case HUB_LED_GREEN: s = "green"; break; - case HUB_LED_OFF: s = "off"; break; - case HUB_LED_AUTO: s = "auto"; break; - default: s = "??"; break; - }; s; }), - status); -} - -#define LED_CYCLE_PERIOD ((2*HZ)/3) - -static void led_work (struct work_struct *work) -{ - struct usb_hub *hub = - container_of(work, struct usb_hub, leds.work); - struct usb_device *hdev = hub->hdev; - unsigned i; - unsigned changed = 0; - int cursor = -1; - - if (hdev->state != USB_STATE_CONFIGURED || hub->quiescing) - return; - - for (i = 0; i < hub->descriptor->bNbrPorts; i++) { - unsigned selector, mode; - - /* 30%-50% duty cycle */ - - switch (hub->indicator[i]) { - /* cycle marker */ - case INDICATOR_CYCLE: - cursor = i; - selector = HUB_LED_AUTO; - mode = INDICATOR_AUTO; - break; - /* blinking green = sw attention */ - case INDICATOR_GREEN_BLINK: - selector = HUB_LED_GREEN; - mode = INDICATOR_GREEN_BLINK_OFF; - break; - case INDICATOR_GREEN_BLINK_OFF: - selector = HUB_LED_OFF; - mode = INDICATOR_GREEN_BLINK; - break; - /* blinking amber = hw attention */ - case INDICATOR_AMBER_BLINK: - selector = HUB_LED_AMBER; - mode = INDICATOR_AMBER_BLINK_OFF; - break; - case INDICATOR_AMBER_BLINK_OFF: - selector = HUB_LED_OFF; - mode = INDICATOR_AMBER_BLINK; - break; - /* blink green/amber = reserved */ - case INDICATOR_ALT_BLINK: - selector = HUB_LED_GREEN; - mode = INDICATOR_ALT_BLINK_OFF; - break; - case INDICATOR_ALT_BLINK_OFF: - selector = HUB_LED_AMBER; - mode = INDICATOR_ALT_BLINK; - break; - default: - continue; - } - if (selector != HUB_LED_AUTO) - changed = 1; - set_port_led(hub, i + 1, selector); - hub->indicator[i] = mode; - } - if (!changed && blinkenlights) { - cursor++; - cursor %= hub->descriptor->bNbrPorts; - set_port_led(hub, cursor + 1, HUB_LED_GREEN); - hub->indicator[cursor] = INDICATOR_CYCLE; - changed++; - } - if (changed) - schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD); -} - -/* use a short timeout for hub/port status fetches */ -#define USB_STS_TIMEOUT 1000 -#define USB_STS_RETRIES 5 - -/* - * USB 2.0 spec Section 11.24.2.6 - */ -static int get_hub_status(struct usb_device *hdev, - struct usb_hub_status *data) -{ - int i, status = -ETIMEDOUT; - - for (i = 0; i < USB_STS_RETRIES && - (status == -ETIMEDOUT || status == -EPIPE); i++) { - status = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0), - USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0, - data, sizeof(*data), USB_STS_TIMEOUT); - } - return status; -} - -/* - * USB 2.0 spec Section 11.24.2.7 - */ -static int get_port_status(struct usb_device *hdev, int port1, - struct usb_port_status *data) -{ - int i, status = -ETIMEDOUT; - - for (i = 0; i < USB_STS_RETRIES && - (status == -ETIMEDOUT || status == -EPIPE); i++) { - status = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0), - USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port1, - data, sizeof(*data), USB_STS_TIMEOUT); - } - return status; -} - -static int hub_port_status(struct usb_hub *hub, int port1, - u16 *status, u16 *change) -{ - int ret; - - mutex_lock(&hub->status_mutex); - ret = get_port_status(hub->hdev, port1, &hub->status->port); - if (ret < 4) { - dev_err(hub->intfdev, - "%s failed (err = %d)\n", __func__, ret); - if (ret >= 0) - ret = -EIO; - } else { - *status = le16_to_cpu(hub->status->port.wPortStatus); - *change = le16_to_cpu(hub->status->port.wPortChange); - - ret = 0; - } - mutex_unlock(&hub->status_mutex); - return ret; -} - -static void kick_khubd(struct usb_hub *hub) -{ - unsigned long flags; - - spin_lock_irqsave(&hub_event_lock, flags); - if (!hub->disconnected && list_empty(&hub->event_list)) { - list_add_tail(&hub->event_list, &hub_event_list); - - /* Suppress autosuspend until khubd runs */ - usb_autopm_get_interface_no_resume( - to_usb_interface(hub->intfdev)); - wake_up(&khubd_wait); - } - spin_unlock_irqrestore(&hub_event_lock, flags); -} - -void usb_kick_khubd(struct usb_device *hdev) -{ - struct usb_hub *hub = hdev_to_hub(hdev); - - if (hub) - kick_khubd(hub); -} - -/* - * Let the USB core know that a USB 3.0 device has sent a Function Wake Device - * Notification, which indicates it had initiated remote wakeup. - * - * USB 3.0 hubs do not report the port link state change from U3 to U0 when the - * device initiates resume, so the USB core will not receive notice of the - * resume through the normal hub interrupt URB. - */ -void usb_wakeup_notification(struct usb_device *hdev, - unsigned int portnum) -{ - struct usb_hub *hub; - - if (!hdev) - return; - - hub = hdev_to_hub(hdev); - if (hub) { - set_bit(portnum, hub->wakeup_bits); - kick_khubd(hub); - } -} -EXPORT_SYMBOL_GPL(usb_wakeup_notification); - -/* completion function, fires on port status changes and various faults */ -static void hub_irq(struct urb *urb) -{ - struct usb_hub *hub = urb->context; - int status = urb->status; - unsigned i; - unsigned long bits; - - switch (status) { - case -ENOENT: /* synchronous unlink */ - case -ECONNRESET: /* async unlink */ - case -ESHUTDOWN: /* hardware going away */ - return; - - default: /* presumably an error */ - /* Cause a hub reset after 10 consecutive errors */ - dev_dbg (hub->intfdev, "transfer --> %d\n", status); - if ((++hub->nerrors < 10) || hub->error) - goto resubmit; - hub->error = status; - /* FALL THROUGH */ - - /* let khubd handle things */ - case 0: /* we got data: port status changed */ - bits = 0; - for (i = 0; i < urb->actual_length; ++i) - bits |= ((unsigned long) ((*hub->buffer)[i])) - << (i*8); - hub->event_bits[0] = bits; - break; - } - - hub->nerrors = 0; - - /* Something happened, let khubd figure it out */ - kick_khubd(hub); - -resubmit: - if (hub->quiescing) - return; - - if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0 - && status != -ENODEV && status != -EPERM) - dev_err (hub->intfdev, "resubmit --> %d\n", status); -} - -/* USB 2.0 spec Section 11.24.2.3 */ -static inline int -hub_clear_tt_buffer (struct usb_device *hdev, u16 devinfo, u16 tt) -{ - return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), - HUB_CLEAR_TT_BUFFER, USB_RT_PORT, devinfo, - tt, NULL, 0, 1000); -} - -/* - * enumeration blocks khubd for a long time. we use keventd instead, since - * long blocking there is the exception, not the rule. accordingly, HCDs - * talking to TTs must queue control transfers (not just bulk and iso), so - * both can talk to the same hub concurrently. - */ -static void hub_tt_work(struct work_struct *work) -{ - struct usb_hub *hub = - container_of(work, struct usb_hub, tt.clear_work); - unsigned long flags; - int limit = 100; - - spin_lock_irqsave (&hub->tt.lock, flags); - while (--limit && !list_empty (&hub->tt.clear_list)) { - struct list_head *next; - struct usb_tt_clear *clear; - struct usb_device *hdev = hub->hdev; - const struct hc_driver *drv; - int status; - - 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 */ - spin_unlock_irqrestore (&hub->tt.lock, flags); - status = hub_clear_tt_buffer (hdev, clear->devinfo, clear->tt); - if (status) - dev_err (&hdev->dev, - "clear tt %d (%04x) error %d\n", - clear->tt, clear->devinfo, status); - - /* Tell the HCD, even if the operation failed */ - drv = clear->hcd->driver; - if (drv->clear_tt_buffer_complete) - (drv->clear_tt_buffer_complete)(clear->hcd, clear->ep); - - kfree(clear); - spin_lock_irqsave(&hub->tt.lock, flags); - } - spin_unlock_irqrestore (&hub->tt.lock, flags); -} - -/** - * usb_hub_clear_tt_buffer - clear control/bulk TT state in high speed hub - * @urb: an URB associated with the failed or incomplete split transaction - * - * High speed HCDs use this to tell the hub driver that some split control or - * bulk transaction failed in a way that requires clearing internal state of - * a transaction translator. This is normally detected (and reported) from - * interrupt context. - * - * It may not be possible for that hub to handle additional full (or low) - * speed transactions until that state is fully cleared out. - */ -int usb_hub_clear_tt_buffer(struct urb *urb) -{ - struct usb_device *udev = urb->dev; - int pipe = urb->pipe; - struct usb_tt *tt = udev->tt; - unsigned long flags; - struct usb_tt_clear *clear; - - /* we've got to cope with an arbitrary number of pending TT clears, - * since each TT has "at least two" buffers that can need it (and - * there can be many TTs per hub). even if they're uncommon. - */ - if ((clear = kmalloc (sizeof *clear, GFP_ATOMIC)) == NULL) { - dev_err (&udev->dev, "can't save CLEAR_TT_BUFFER state\n"); - /* FIXME recover somehow ... RESET_TT? */ - return -ENOMEM; - } - - /* info that CLEAR_TT_BUFFER needs */ - clear->tt = tt->multi ? udev->ttport : 1; - clear->devinfo = usb_pipeendpoint (pipe); - clear->devinfo |= udev->devnum << 4; - clear->devinfo |= usb_pipecontrol (pipe) - ? (USB_ENDPOINT_XFER_CONTROL << 11) - : (USB_ENDPOINT_XFER_BULK << 11); - if (usb_pipein (pipe)) - clear->devinfo |= 1 << 15; - - /* info for completion callback */ - clear->hcd = bus_to_hcd(udev->bus); - clear->ep = urb->ep; - - /* tell keventd to clear state for this TT */ - spin_lock_irqsave (&tt->lock, flags); - list_add_tail (&clear->clear_list, &tt->clear_list); - schedule_work(&tt->clear_work); - spin_unlock_irqrestore (&tt->lock, flags); - return 0; -} -EXPORT_SYMBOL_GPL(usb_hub_clear_tt_buffer); - -/* If do_delay is false, return the number of milliseconds the caller - * needs to delay. - */ -/*CharlesTu,2012.09.14,improve resume time*/ -unsigned char usb_resume_flag=0; -static unsigned hub_power_on(struct usb_hub *hub, bool do_delay) -{ - int port1; - unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2; - unsigned delay; - u16 wHubCharacteristics = - le16_to_cpu(hub->descriptor->wHubCharacteristics); - - /* Enable power on each port. Some hubs have reserved values - * of LPSM (> 2) in their descriptors, even though they are - * USB 2.0 hubs. Some hubs do not implement port-power switching - * but only emulate it. In all cases, the ports won't work - * unless we send these messages to the hub. - */ - if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2) - dev_dbg(hub->intfdev, "enabling power on all ports\n"); - else - dev_dbg(hub->intfdev, "trying to enable port power on " - "non-switchable hub\n"); - for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++) - set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER); - - /* Wait at least 100 msec for power to become stable */ - delay = max(pgood_delay, (unsigned) 100); - if (do_delay) - if (!usb_resume_flag) { - msleep(delay); - } - return delay; -} - -static int hub_hub_status(struct usb_hub *hub, - u16 *status, u16 *change) -{ - int ret; - - mutex_lock(&hub->status_mutex); - ret = get_hub_status(hub->hdev, &hub->status->hub); - if (ret < 0) - dev_err (hub->intfdev, - "%s failed (err = %d)\n", __func__, ret); - else { - *status = le16_to_cpu(hub->status->hub.wHubStatus); - *change = le16_to_cpu(hub->status->hub.wHubChange); - ret = 0; - } - mutex_unlock(&hub->status_mutex); - return ret; -} - -static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) -{ - struct usb_device *hdev = hub->hdev; - int ret = 0; - - if (hdev->children[port1-1] && set_state) - usb_set_device_state(hdev->children[port1-1], - USB_STATE_NOTATTACHED); - if (!hub->error && !hub_is_superspeed(hub->hdev)) - ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE); - if (ret) - dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n", - port1, ret); - return ret; -} - -/* - * Disable a port and mark a logical connect-change event, so that some - * time later khubd will disconnect() any existing usb_device on the port - * and will re-enumerate if there actually is a device attached. - */ -static void hub_port_logical_disconnect(struct usb_hub *hub, int port1) -{ - dev_dbg(hub->intfdev, "logical disconnect on port %d\n", port1); - hub_port_disable(hub, port1, 1); - - /* FIXME let caller ask to power down the port: - * - some devices won't enumerate without a VBUS power cycle - * - SRP saves power that way - * - ... new call, TBD ... - * That's easy if this hub can switch power per-port, and - * khubd reactivates the port later (timer, SRP, etc). - * Powerdown must be optional, because of reset/DFU. - */ - - set_bit(port1, hub->change_bits); - kick_khubd(hub); -} - -/** - * usb_remove_device - disable a device's port on its parent hub - * @udev: device to be disabled and removed - * Context: @udev locked, must be able to sleep. - * - * After @udev's port has been disabled, khubd is notified and it will - * see that the device has been disconnected. When the device is - * physically unplugged and something is plugged in, the events will - * be received and processed normally. - */ -int usb_remove_device(struct usb_device *udev) -{ - struct usb_hub *hub; - struct usb_interface *intf; - - if (!udev->parent) /* Can't remove a root hub */ - return -EINVAL; - hub = hdev_to_hub(udev->parent); - intf = to_usb_interface(hub->intfdev); - - usb_autopm_get_interface(intf); - set_bit(udev->portnum, hub->removed_bits); - hub_port_logical_disconnect(hub, udev->portnum); - usb_autopm_put_interface(intf); - return 0; -} - -enum hub_activation_type { - HUB_INIT, HUB_INIT2, HUB_INIT3, /* INITs must come first */ - HUB_POST_RESET, HUB_RESUME, HUB_RESET_RESUME, -}; - -static void hub_init_func2(struct work_struct *ws); -static void hub_init_func3(struct work_struct *ws); - -static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) -{ - struct usb_device *hdev = hub->hdev; - struct usb_hcd *hcd; - int ret; - int port1; - int status; - bool need_debounce_delay = false; - unsigned delay; - - /* Continue a partial initialization */ - if (type == HUB_INIT2) - goto init2; - if (type == HUB_INIT3) - goto init3; - - /* The superspeed hub except for root hub has to use Hub Depth - * value as an offset into the route string to locate the bits - * it uses to determine the downstream port number. So hub driver - * should send a set hub depth request to superspeed hub after - * the superspeed hub is set configuration in initialization or - * reset procedure. - * - * After a resume, port power should still be on. - * For any other type of activation, turn it on. - */ - if (type != HUB_RESUME) { - if (hdev->parent && hub_is_superspeed(hdev)) { - ret = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), - HUB_SET_DEPTH, USB_RT_HUB, - hdev->level - 1, 0, NULL, 0, - USB_CTRL_SET_TIMEOUT); - if (ret < 0) - dev_err(hub->intfdev, - "set hub depth failed\n"); - } - - /* Speed up system boot by using a delayed_work for the - * hub's initial power-up delays. This is pretty awkward - * and the implementation looks like a home-brewed sort of - * setjmp/longjmp, but it saves at least 100 ms for each - * root hub (assuming usbcore is compiled into the kernel - * rather than as a module). It adds up. - * - * This can't be done for HUB_RESUME or HUB_RESET_RESUME - * because for those activation types the ports have to be - * operational when we return. In theory this could be done - * for HUB_POST_RESET, but it's easier not to. - */ - if (type == HUB_INIT) { - delay = hub_power_on(hub, false); - PREPARE_DELAYED_WORK(&hub->init_work, hub_init_func2); - schedule_delayed_work(&hub->init_work, - msecs_to_jiffies(delay)); - - /* Suppress autosuspend until init is done */ - usb_autopm_get_interface_no_resume( - to_usb_interface(hub->intfdev)); - return; /* Continues at init2: below */ - } else if (type == HUB_RESET_RESUME) { - /* The internal host controller state for the hub device - * may be gone after a host power loss on system resume. - * Update the device's info so the HW knows it's a hub. - */ - hcd = bus_to_hcd(hdev->bus); - if (hcd->driver->update_hub_device) { - ret = hcd->driver->update_hub_device(hcd, hdev, - &hub->tt, GFP_NOIO); - if (ret < 0) { - dev_err(hub->intfdev, "Host not " - "accepting hub info " - "update.\n"); - dev_err(hub->intfdev, "LS/FS devices " - "and hubs may not work " - "under this hub\n."); - } - } - hub_power_on(hub, true); - } else { - hub_power_on(hub, true); - } - } - init2: - - /* Check each port and set hub->change_bits to let khubd know - * which ports need attention. - */ - for (port1 = 1; port1 <= hdev->maxchild; ++port1) { - struct usb_device *udev = hdev->children[port1-1]; - u16 portstatus, portchange; - - portstatus = portchange = 0; - status = hub_port_status(hub, port1, &portstatus, &portchange); - if (udev || (portstatus & USB_PORT_STAT_CONNECTION)) - dev_dbg(hub->intfdev, - "port %d: status %04x change %04x\n", - port1, portstatus, portchange); - - /* After anything other than HUB_RESUME (i.e., initialization - * or any sort of reset), every port should be disabled. - * Unconnected ports should likewise be disabled (paranoia), - * and so should ports for which we have no usb_device. - */ - if ((portstatus & USB_PORT_STAT_ENABLE) && ( - type != HUB_RESUME || - !(portstatus & USB_PORT_STAT_CONNECTION) || - !udev || - udev->state == USB_STATE_NOTATTACHED)) { - /* - * USB3 protocol ports will automatically transition - * to Enabled state when detect an USB3.0 device attach. - * Do not disable USB3 protocol ports. - */ - if (!hub_is_superspeed(hdev)) { - clear_port_feature(hdev, port1, - USB_PORT_FEAT_ENABLE); - portstatus &= ~USB_PORT_STAT_ENABLE; - } else { - /* Pretend that power was lost for USB3 devs */ - portstatus &= ~USB_PORT_STAT_ENABLE; - } - } - - /* Clear status-change flags; we'll debounce later */ - if (portchange & USB_PORT_STAT_C_CONNECTION) { - if (!usb_resume_flag) { - need_debounce_delay = true; - } - clear_port_feature(hub->hdev, port1, - USB_PORT_FEAT_C_CONNECTION); - } - if (portchange & USB_PORT_STAT_C_ENABLE) { - - if (!usb_resume_flag) { - need_debounce_delay = true; - } - clear_port_feature(hub->hdev, port1, - USB_PORT_FEAT_C_ENABLE); - } - if ((portchange & USB_PORT_STAT_C_BH_RESET) && - hub_is_superspeed(hub->hdev)) { - need_debounce_delay = true; - clear_port_feature(hub->hdev, port1, - USB_PORT_FEAT_C_BH_PORT_RESET); - } - /* We can forget about a "removed" device when there's a - * physical disconnect or the connect status changes. - */ - if (!(portstatus & USB_PORT_STAT_CONNECTION) || - (portchange & USB_PORT_STAT_C_CONNECTION)) - clear_bit(port1, hub->removed_bits); - - if (!udev || udev->state == USB_STATE_NOTATTACHED) { - /* Tell khubd to disconnect the device or - * check for a new connection - */ - if (udev || (portstatus & USB_PORT_STAT_CONNECTION)) - set_bit(port1, hub->change_bits); - - } else if (portstatus & USB_PORT_STAT_ENABLE) { - bool port_resumed = (portstatus & - USB_PORT_STAT_LINK_STATE) == - USB_SS_PORT_LS_U0; - /* The power session apparently survived the resume. - * If there was an overcurrent or suspend change - * (i.e., remote wakeup request), have khubd - * take care of it. Look at the port link state - * for USB 3.0 hubs, since they don't have a suspend - * change bit, and they don't set the port link change - * bit on device-initiated resume. - */ - if (portchange || (hub_is_superspeed(hub->hdev) && - port_resumed)) - set_bit(port1, hub->change_bits); - - } else if (udev->persist_enabled) { -#ifdef CONFIG_PM - udev->reset_resume = 1; -#endif - set_bit(port1, hub->change_bits); - - } else { - /* The power session is gone; tell khubd */ - usb_set_device_state(udev, USB_STATE_NOTATTACHED); - set_bit(port1, hub->change_bits); - } - } - - /* If no port-status-change flags were set, we don't need any - * debouncing. If flags were set we can try to debounce the - * ports all at once right now, instead of letting khubd do them - * one at a time later on. - * - * If any port-status changes do occur during this delay, khubd - * will see them later and handle them normally. - */ - if (need_debounce_delay) { - delay = HUB_DEBOUNCE_STABLE; - - /* Don't do a long sleep inside a workqueue routine */ - if (type == HUB_INIT2) { - PREPARE_DELAYED_WORK(&hub->init_work, hub_init_func3); - schedule_delayed_work(&hub->init_work, - msecs_to_jiffies(delay)); - return; /* Continues at init3: below */ - } else { - msleep(delay); - } - } - init3: - hub->quiescing = 0; - - status = usb_submit_urb(hub->urb, GFP_NOIO); - if (status < 0) - dev_err(hub->intfdev, "activate --> %d\n", status); - if (hub->has_indicators && blinkenlights) - schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD); - - /* Scan all ports that need attention */ - kick_khubd(hub); - - /* Allow autosuspend if it was suppressed */ - if (type <= HUB_INIT3) - usb_autopm_put_interface_async(to_usb_interface(hub->intfdev)); -} - -/* Implement the continuations for the delays above */ -static void hub_init_func2(struct work_struct *ws) -{ - struct usb_hub *hub = container_of(ws, struct usb_hub, init_work.work); - - hub_activate(hub, HUB_INIT2); -} - -static void hub_init_func3(struct work_struct *ws) -{ - struct usb_hub *hub = container_of(ws, struct usb_hub, init_work.work); - - hub_activate(hub, HUB_INIT3); -} - -enum hub_quiescing_type { - HUB_DISCONNECT, HUB_PRE_RESET, HUB_SUSPEND -}; - -static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type) -{ - struct usb_device *hdev = hub->hdev; - int i; - - cancel_delayed_work_sync(&hub->init_work); - - /* khubd and related activity won't re-trigger */ - hub->quiescing = 1; - - if (type != HUB_SUSPEND) { - /* Disconnect all the children */ - for (i = 0; i < hdev->maxchild; ++i) { - if (hdev->children[i]) - usb_disconnect(&hdev->children[i]); - } - } - - /* Stop khubd and related activity */ - usb_kill_urb(hub->urb); - if (hub->has_indicators) - cancel_delayed_work_sync(&hub->leds); - if (hub->tt.hub) - cancel_work_sync(&hub->tt.clear_work); -} - -/* caller has locked the hub device */ -static int hub_pre_reset(struct usb_interface *intf) -{ - struct usb_hub *hub = usb_get_intfdata(intf); - - hub_quiesce(hub, HUB_PRE_RESET); - return 0; -} - -/* caller has locked the hub device */ -static int hub_post_reset(struct usb_interface *intf) -{ - struct usb_hub *hub = usb_get_intfdata(intf); - - hub_activate(hub, HUB_POST_RESET); - return 0; -} - -static int hub_configure(struct usb_hub *hub, - struct usb_endpoint_descriptor *endpoint) -{ - struct usb_hcd *hcd; - struct usb_device *hdev = hub->hdev; - struct device *hub_dev = hub->intfdev; - u16 hubstatus, hubchange; - u16 wHubCharacteristics; - unsigned int pipe; - int maxp, ret; - char *message = "out of memory"; - - hub->buffer = kmalloc(sizeof(*hub->buffer), GFP_KERNEL); - if (!hub->buffer) { - ret = -ENOMEM; - goto fail; - } - - hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL); - if (!hub->status) { - ret = -ENOMEM; - goto fail; - } - mutex_init(&hub->status_mutex); - - hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL); - if (!hub->descriptor) { - ret = -ENOMEM; - goto fail; - } - - /* Request the entire hub descriptor. - * hub->descriptor can handle USB_MAXCHILDREN ports, - * but the hub can/will return fewer bytes here. - */ - ret = get_hub_descriptor(hdev, hub->descriptor); - if (ret < 0) { - message = "can't read hub descriptor"; - goto fail; - } else if (hub->descriptor->bNbrPorts > USB_MAXCHILDREN) { - message = "hub has too many ports!"; - ret = -ENODEV; - goto fail; - } - - hdev->maxchild = hub->descriptor->bNbrPorts; - dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild, - (hdev->maxchild == 1) ? "" : "s"); - - hdev->children = kzalloc(hdev->maxchild * - sizeof(struct usb_device *), GFP_KERNEL); - hub->port_owners = kzalloc(hdev->maxchild * sizeof(void *), GFP_KERNEL); - if (!hdev->children || !hub->port_owners) { - ret = -ENOMEM; - goto fail; - } - - wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); - - /* FIXME for USB 3.0, skip for now */ - if ((wHubCharacteristics & HUB_CHAR_COMPOUND) && - !(hub_is_superspeed(hdev))) { - int i; - char portstr [USB_MAXCHILDREN + 1]; - - for (i = 0; i < hdev->maxchild; i++) - portstr[i] = hub->descriptor->u.hs.DeviceRemovable - [((i + 1) / 8)] & (1 << ((i + 1) % 8)) - ? 'F' : 'R'; - portstr[hdev->maxchild] = 0; - dev_dbg(hub_dev, "compound device; port removable status: %s\n", portstr); - } else - dev_dbg(hub_dev, "standalone hub\n"); - - switch (wHubCharacteristics & HUB_CHAR_LPSM) { - case HUB_CHAR_COMMON_LPSM: - dev_dbg(hub_dev, "ganged power switching\n"); - break; - case HUB_CHAR_INDV_PORT_LPSM: - dev_dbg(hub_dev, "individual port power switching\n"); - break; - case HUB_CHAR_NO_LPSM: - case HUB_CHAR_LPSM: - dev_dbg(hub_dev, "no power switching (usb 1.0)\n"); - break; - } - - switch (wHubCharacteristics & HUB_CHAR_OCPM) { - case HUB_CHAR_COMMON_OCPM: - dev_dbg(hub_dev, "global over-current protection\n"); - break; - case HUB_CHAR_INDV_PORT_OCPM: - dev_dbg(hub_dev, "individual port over-current protection\n"); - break; - case HUB_CHAR_NO_OCPM: - case HUB_CHAR_OCPM: - dev_dbg(hub_dev, "no over-current protection\n"); - break; - } - - spin_lock_init (&hub->tt.lock); - INIT_LIST_HEAD (&hub->tt.clear_list); - INIT_WORK(&hub->tt.clear_work, hub_tt_work); - switch (hdev->descriptor.bDeviceProtocol) { - case USB_HUB_PR_FS: - break; - case USB_HUB_PR_HS_SINGLE_TT: - dev_dbg(hub_dev, "Single TT\n"); - hub->tt.hub = hdev; - break; - case USB_HUB_PR_HS_MULTI_TT: - ret = usb_set_interface(hdev, 0, 1); - if (ret == 0) { - dev_dbg(hub_dev, "TT per port\n"); - hub->tt.multi = 1; - } else - dev_err(hub_dev, "Using single TT (err %d)\n", - ret); - hub->tt.hub = hdev; - break; - case USB_HUB_PR_SS: - /* USB 3.0 hubs don't have a TT */ - break; - default: - dev_dbg(hub_dev, "Unrecognized hub protocol %d\n", - hdev->descriptor.bDeviceProtocol); - break; - } - - /* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */ - switch (wHubCharacteristics & HUB_CHAR_TTTT) { - case HUB_TTTT_8_BITS: - if (hdev->descriptor.bDeviceProtocol != 0) { - hub->tt.think_time = 666; - dev_dbg(hub_dev, "TT requires at most %d " - "FS bit times (%d ns)\n", - 8, hub->tt.think_time); - } - break; - case HUB_TTTT_16_BITS: - hub->tt.think_time = 666 * 2; - dev_dbg(hub_dev, "TT requires at most %d " - "FS bit times (%d ns)\n", - 16, hub->tt.think_time); - break; - case HUB_TTTT_24_BITS: - hub->tt.think_time = 666 * 3; - dev_dbg(hub_dev, "TT requires at most %d " - "FS bit times (%d ns)\n", - 24, hub->tt.think_time); - break; - case HUB_TTTT_32_BITS: - hub->tt.think_time = 666 * 4; - dev_dbg(hub_dev, "TT requires at most %d " - "FS bit times (%d ns)\n", - 32, hub->tt.think_time); - break; - } - - /* probe() zeroes hub->indicator[] */ - if (wHubCharacteristics & HUB_CHAR_PORTIND) { - hub->has_indicators = 1; - dev_dbg(hub_dev, "Port indicators are supported\n"); - } - - dev_dbg(hub_dev, "power on to power good time: %dms\n", - hub->descriptor->bPwrOn2PwrGood * 2); - - /* power budgeting mostly matters with bus-powered hubs, - * and battery-powered root hubs (may provide just 8 mA). - */ - ret = usb_get_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus); - if (ret < 2) { - message = "can't get hub status"; - goto fail; - } - le16_to_cpus(&hubstatus); - if (hdev == hdev->bus->root_hub) { - if (hdev->bus_mA == 0 || hdev->bus_mA >= 500) - hub->mA_per_port = 500; - else { - hub->mA_per_port = hdev->bus_mA; - hub->limited_power = 1; - } - } else if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) { - dev_dbg(hub_dev, "hub controller current requirement: %dmA\n", - hub->descriptor->bHubContrCurrent); - hub->limited_power = 1; - if (hdev->maxchild > 0) { - int remaining = hdev->bus_mA - - hub->descriptor->bHubContrCurrent; - - if (remaining < hdev->maxchild * 100) - dev_warn(hub_dev, - "insufficient power available " - "to use all downstream ports\n"); - hub->mA_per_port = 100; /* 7.2.1.1 */ - } - } else { /* Self-powered external hub */ - /* FIXME: What about battery-powered external hubs that - * provide less current per port? */ - hub->mA_per_port = 500; - } - if (hub->mA_per_port < 500) - dev_dbg(hub_dev, "%umA bus power budget for each child\n", - hub->mA_per_port); - - /* Update the HCD's internal representation of this hub before khubd - * starts getting port status changes for devices under the hub. - */ - hcd = bus_to_hcd(hdev->bus); - if (hcd->driver->update_hub_device) { - ret = hcd->driver->update_hub_device(hcd, hdev, - &hub->tt, GFP_KERNEL); - if (ret < 0) { - message = "can't update HCD hub info"; - goto fail; - } - } - - ret = hub_hub_status(hub, &hubstatus, &hubchange); - if (ret < 0) { - message = "can't get hub status"; - goto fail; - } - - /* local power status reports aren't always correct */ - if (hdev->actconfig->desc.bmAttributes & USB_CONFIG_ATT_SELFPOWER) - dev_dbg(hub_dev, "local power source is %s\n", - (hubstatus & HUB_STATUS_LOCAL_POWER) - ? "lost (inactive)" : "good"); - - if ((wHubCharacteristics & HUB_CHAR_OCPM) == 0) - dev_dbg(hub_dev, "%sover-current condition exists\n", - (hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no "); - - /* set up the interrupt endpoint - * We use the EP's maxpacket size instead of (PORTS+1+7)/8 - * bytes as USB2.0[11.12.3] says because some hubs are known - * to send more data (and thus cause overflow). For root hubs, - * maxpktsize is defined in hcd.c's fake endpoint descriptors - * to be big enough for at least USB_MAXCHILDREN ports. */ - pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress); - maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe)); - - if (maxp > sizeof(*hub->buffer)) - maxp = sizeof(*hub->buffer); - - hub->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!hub->urb) { - ret = -ENOMEM; - goto fail; - } - - usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq, - hub, endpoint->bInterval); - - /* maybe cycle the hub leds */ - if (hub->has_indicators && blinkenlights) - hub->indicator [0] = INDICATOR_CYCLE; - - hub_activate(hub, HUB_INIT); - return 0; - -fail: - dev_err (hub_dev, "config failed, %s (err %d)\n", - message, ret); - /* hub_disconnect() frees urb and descriptor */ - return ret; -} - -static void hub_release(struct kref *kref) -{ - struct usb_hub *hub = container_of(kref, struct usb_hub, kref); - - usb_put_intf(to_usb_interface(hub->intfdev)); - kfree(hub); -} - -static unsigned highspeed_hubs; - -static void hub_disconnect(struct usb_interface *intf) -{ - struct usb_hub *hub = usb_get_intfdata(intf); - struct usb_device *hdev = interface_to_usbdev(intf); - - /* Take the hub off the event list and don't let it be added again */ - spin_lock_irq(&hub_event_lock); - if (!list_empty(&hub->event_list)) { - list_del_init(&hub->event_list); - usb_autopm_put_interface_no_suspend(intf); - } - hub->disconnected = 1; - spin_unlock_irq(&hub_event_lock); - - /* Disconnect all children and quiesce the hub */ - hub->error = 0; - hub_quiesce(hub, HUB_DISCONNECT); - - usb_set_intfdata (intf, NULL); - hub->hdev->maxchild = 0; - - if (hub->hdev->speed == USB_SPEED_HIGH) - highspeed_hubs--; - - usb_free_urb(hub->urb); - kfree(hdev->children); - kfree(hub->port_owners); - kfree(hub->descriptor); - kfree(hub->status); - kfree(hub->buffer); - - kref_put(&hub->kref, hub_release); -} - -static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_host_interface *desc; - struct usb_endpoint_descriptor *endpoint; - struct usb_device *hdev; - struct usb_hub *hub; - - desc = intf->cur_altsetting; - hdev = interface_to_usbdev(intf); - - /* Hubs have proper suspend/resume support. */ - usb_enable_autosuspend(hdev); - - if (hdev->level == MAX_TOPO_LEVEL) { - dev_err(&intf->dev, - "Unsupported bus topology: hub nested too deep\n"); - return -E2BIG; - } - -#ifdef CONFIG_USB_OTG_BLACKLIST_HUB - if (hdev->parent) { - dev_warn(&intf->dev, "ignoring external hub\n"); - return -ENODEV; - } -#endif - - /* Some hubs have a subclass of 1, which AFAICT according to the */ - /* specs is not defined, but it works */ - if ((desc->desc.bInterfaceSubClass != 0) && - (desc->desc.bInterfaceSubClass != 1)) { -descriptor_error: - dev_err (&intf->dev, "bad descriptor, ignoring hub\n"); - return -EIO; - } - - /* Multiple endpoints? What kind of mutant ninja-hub is this? */ - if (desc->desc.bNumEndpoints != 1) - goto descriptor_error; - - endpoint = &desc->endpoint[0].desc; - - /* If it's not an interrupt in endpoint, we'd better punt! */ - if (!usb_endpoint_is_int_in(endpoint)) - goto descriptor_error; - - /* We found a hub */ - dev_info (&intf->dev, "USB hub found\n"); - - hub = kzalloc(sizeof(*hub), GFP_KERNEL); - if (!hub) { - dev_dbg (&intf->dev, "couldn't kmalloc hub struct\n"); - return -ENOMEM; - } - - kref_init(&hub->kref); - INIT_LIST_HEAD(&hub->event_list); - hub->intfdev = &intf->dev; - hub->hdev = hdev; - INIT_DELAYED_WORK(&hub->leds, led_work); - INIT_DELAYED_WORK(&hub->init_work, NULL); - usb_get_intf(intf); - - usb_set_intfdata (intf, hub); - intf->needs_remote_wakeup = 1; - - if (hdev->speed == USB_SPEED_HIGH) - highspeed_hubs++; - - if (hub_configure(hub, endpoint) >= 0) - return 0; - - hub_disconnect (intf); - return -ENODEV; -} - -static int -hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data) -{ - struct usb_device *hdev = interface_to_usbdev (intf); - - /* assert ifno == 0 (part of hub spec) */ - switch (code) { - case USBDEVFS_HUB_PORTINFO: { - struct usbdevfs_hub_portinfo *info = user_data; - int i; - - spin_lock_irq(&device_state_lock); - if (hdev->devnum <= 0) - info->nports = 0; - else { - info->nports = hdev->maxchild; - for (i = 0; i < info->nports; i++) { - if (hdev->children[i] == NULL) - info->port[i] = 0; - else - info->port[i] = - hdev->children[i]->devnum; - } - } - spin_unlock_irq(&device_state_lock); - - return info->nports + 1; - } - - default: - return -ENOSYS; - } -} - -/* - * Allow user programs to claim ports on a hub. When a device is attached - * to one of these "claimed" ports, the program will "own" the device. - */ -static int find_port_owner(struct usb_device *hdev, unsigned port1, - void ***ppowner) -{ - if (hdev->state == USB_STATE_NOTATTACHED) - return -ENODEV; - if (port1 == 0 || port1 > hdev->maxchild) - return -EINVAL; - - /* This assumes that devices not managed by the hub driver - * will always have maxchild equal to 0. - */ - *ppowner = &(hdev_to_hub(hdev)->port_owners[port1 - 1]); - return 0; -} - -/* In the following three functions, the caller must hold hdev's lock */ -int usb_hub_claim_port(struct usb_device *hdev, unsigned port1, void *owner) -{ - int rc; - void **powner; - - rc = find_port_owner(hdev, port1, &powner); - if (rc) - return rc; - if (*powner) - return -EBUSY; - *powner = owner; - return rc; -} - -int usb_hub_release_port(struct usb_device *hdev, unsigned port1, void *owner) -{ - int rc; - void **powner; - - rc = find_port_owner(hdev, port1, &powner); - if (rc) - return rc; - if (*powner != owner) - return -ENOENT; - *powner = NULL; - return rc; -} - -void usb_hub_release_all_ports(struct usb_device *hdev, void *owner) -{ - int n; - void **powner; - - n = find_port_owner(hdev, 1, &powner); - if (n == 0) { - for (; n < hdev->maxchild; (++n, ++powner)) { - if (*powner == owner) - *powner = NULL; - } - } -} - -/* The caller must hold udev's lock */ -bool usb_device_is_owned(struct usb_device *udev) -{ - struct usb_hub *hub; - - if (udev->state == USB_STATE_NOTATTACHED || !udev->parent) - return false; - hub = hdev_to_hub(udev->parent); - return !!hub->port_owners[udev->portnum - 1]; -} - - -static void recursively_mark_NOTATTACHED(struct usb_device *udev) -{ - int i; - - for (i = 0; i < udev->maxchild; ++i) { - if (udev->children[i]) - recursively_mark_NOTATTACHED(udev->children[i]); - } - if (udev->state == USB_STATE_SUSPENDED) - udev->active_duration -= jiffies; - udev->state = USB_STATE_NOTATTACHED; -} - -/** - * usb_set_device_state - change a device's current state (usbcore, hcds) - * @udev: pointer to device whose state should be changed - * @new_state: new state value to be stored - * - * udev->state is _not_ fully protected by the device lock. Although - * most transitions are made only while holding the lock, the state can - * can change to USB_STATE_NOTATTACHED at almost any time. This - * is so that devices can be marked as disconnected as soon as possible, - * without having to wait for any semaphores to be released. As a result, - * all changes to any device's state must be protected by the - * device_state_lock spinlock. - * - * Once a device has been added to the device tree, all changes to its state - * should be made using this routine. The state should _not_ be set directly. - * - * If udev->state is already USB_STATE_NOTATTACHED then no change is made. - * Otherwise udev->state is set to new_state, and if new_state is - * USB_STATE_NOTATTACHED then all of udev's descendants' states are also set - * to USB_STATE_NOTATTACHED. - */ - -extern char enable_ehci_wake; - -void usb_set_device_state(struct usb_device *udev, - enum usb_device_state new_state) -{ - unsigned long flags; - int wakeup = -1; - - spin_lock_irqsave(&device_state_lock, flags); - if (udev->state == USB_STATE_NOTATTACHED) - ; /* do nothing */ - else if (new_state != USB_STATE_NOTATTACHED) { - - /* root hub wakeup capabilities are managed out-of-band - * and may involve silicon errata ... ignore them here. - */ - if (udev->parent) { - if (udev->state == USB_STATE_SUSPENDED - || new_state == USB_STATE_SUSPENDED) - ; /* No change to wakeup settings */ - else if (new_state == USB_STATE_CONFIGURED) - wakeup = udev->actconfig->desc.bmAttributes - & USB_CONFIG_ATT_WAKEUP; - else - wakeup = 0; - } - if (udev->state == USB_STATE_SUSPENDED && - new_state != USB_STATE_SUSPENDED) - udev->active_duration -= jiffies; - else if (new_state == USB_STATE_SUSPENDED && - udev->state != USB_STATE_SUSPENDED) - udev->active_duration += jiffies; - udev->state = new_state; - } else - recursively_mark_NOTATTACHED(udev); - spin_unlock_irqrestore(&device_state_lock, flags); - if (wakeup >= 0) { - device_set_wakeup_capable(&udev->dev, wakeup); - if (enable_ehci_wake) - device_wakeup_enable(&udev->dev);//gri - } -} -EXPORT_SYMBOL_GPL(usb_set_device_state); - -/* - * Choose a device number. - * - * Device numbers are used as filenames in usbfs. On USB-1.1 and - * USB-2.0 buses they are also used as device addresses, however on - * USB-3.0 buses the address is assigned by the controller hardware - * and it usually is not the same as the device number. - * - * WUSB devices are simple: they have no hubs behind, so the mapping - * device <-> virtual port number becomes 1:1. Why? to simplify the - * life of the device connection logic in - * drivers/usb/wusbcore/devconnect.c. When we do the initial secret - * handshake we need to assign a temporary address in the unauthorized - * space. For simplicity we use the first virtual port number found to - * be free [drivers/usb/wusbcore/devconnect.c:wusbhc_devconnect_ack()] - * and that becomes it's address [X < 128] or its unauthorized address - * [X | 0x80]. - * - * We add 1 as an offset to the one-based USB-stack port number - * (zero-based wusb virtual port index) for two reasons: (a) dev addr - * 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_devnum(struct usb_device *udev) -{ - int devnum; - struct usb_bus *bus = udev->bus; - - /* If khubd ever becomes multithreaded, this will need a lock */ - if (udev->wusb) { - devnum = udev->portnum + 1; - BUG_ON(test_bit(devnum, bus->devmap.devicemap)); - } else { - /* Try to allocate the next devnum beginning at - * bus->devnum_next. */ - devnum = find_next_zero_bit(bus->devmap.devicemap, 128, - bus->devnum_next); - if (devnum >= 128) - devnum = find_next_zero_bit(bus->devmap.devicemap, - 128, 1); - bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1); - } - if (devnum < 128) { - set_bit(devnum, bus->devmap.devicemap); - udev->devnum = devnum; - } -} - -static void release_devnum(struct usb_device *udev) -{ - if (udev->devnum > 0) { - clear_bit(udev->devnum, udev->bus->devmap.devicemap); - udev->devnum = -1; - } -} - -static void update_devnum(struct usb_device *udev, int devnum) -{ - /* The address for a WUSB device is managed by wusbcore. */ - if (!udev->wusb) - udev->devnum = devnum; -} - -static void hub_free_dev(struct usb_device *udev) -{ - struct usb_hcd *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_disconnect - disconnect a device (usbcore-internal) - * @pdev: pointer to device being disconnected - * Context: !in_interrupt () - * - * Something got disconnected. Get rid of it and all of its children. - * - * If *pdev is a normal device then the parent hub must already be locked. - * If *pdev is a root hub then this routine will acquire the - * usb_bus_list_lock on behalf of the caller. - * - * Only hub drivers (including virtual root hub drivers for host - * controllers) should ever call this. - * - * This call is synchronous, and may not be used in an interrupt context. - */ -void usb_disconnect(struct usb_device **pdev) -{ - struct usb_device *udev = *pdev; - int i; - - int wmt_usb_patch = 0; - struct usb_hcd *hcd = bus_to_hcd(udev->bus); - - if ((udev->portnum == 1) && (udev->parent == udev->bus->root_hub) - && ((udev->speed == 3) || (hcd->rsrc_start == 0xfe007b00))) - wmt_usb_patch = 1; - - - /* mark the device as inactive, so any further urb submissions for - * this device (and any of its children) will fail immediately. - * this quiesces everything except pending urbs. - */ - usb_set_device_state(udev, USB_STATE_NOTATTACHED); - dev_info(&udev->dev, "USB disconnect, device number %d\n", - udev->devnum); - - usb_lock_device(udev); - - /* Free up all the children before we remove this device */ - for (i = 0; i < udev->maxchild; i++) { - if (udev->children[i]) - usb_disconnect(&udev->children[i]); - } - - /* deallocate hcd/hardware state ... nuking all pending urbs and - * cleaning up all state associated with the current configuration - * so that the hardware is now fully quiesced. - */ - dev_dbg (&udev->dev, "unregistering device\n"); - usb_disable_device(udev, 0); - usb_hcd_synchronize_unlinks(udev); - - usb_remove_ep_devs(&udev->ep0); - usb_unlock_device(udev); - - /* Unregister the device. The device driver is responsible - * for de-configuring the device and invoking the remove-device - * notifier chain (used by usbfs and possibly others). - */ - device_del(&udev->dev); - - /* Free the device number and delete the parent's children[] - * (or root_hub) pointer. - */ - release_devnum(udev); - - /* Avoid races with recursively_mark_NOTATTACHED() */ - spin_lock_irq(&device_state_lock); - *pdev = NULL; - spin_unlock_irq(&device_state_lock); - - hub_free_dev(udev); - - put_device(&udev->dev); - - if (wmt_usb_patch) - *(unsigned char *)0xfe11010e = ((*(unsigned char *)0xfe11010e & (~0x3)) | 0x2); -} - -#ifdef CONFIG_USB_ANNOUNCE_NEW_DEVICES -static void show_string(struct usb_device *udev, char *id, char *string) -{ - if (!string) - return; - dev_printk(KERN_INFO, &udev->dev, "%s: %s\n", id, string); -} - -static void announce_device(struct usb_device *udev) -{ - dev_info(&udev->dev, "New USB device found, idVendor=%04x, idProduct=%04x\n", - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct)); - dev_info(&udev->dev, - "New USB device strings: Mfr=%d, Product=%d, SerialNumber=%d\n", - udev->descriptor.iManufacturer, - udev->descriptor.iProduct, - udev->descriptor.iSerialNumber); - show_string(udev, "Product", udev->product); - show_string(udev, "Manufacturer", udev->manufacturer); - show_string(udev, "SerialNumber", udev->serial); -} -#else -static inline void announce_device(struct usb_device *udev) { } -#endif - -#ifdef CONFIG_USB_OTG -#include "otg_whitelist.h" -#endif - -/** - * usb_enumerate_device_otg - FIXME (usbcore-internal) - * @udev: newly addressed device (in ADDRESS state) - * - * Finish enumeration for On-The-Go devices - */ -static int usb_enumerate_device_otg(struct usb_device *udev) -{ - int err = 0; - -#ifdef CONFIG_USB_OTG - /* - * OTG-aware devices on OTG-capable root hubs may be able to use SRP, - * to wake us after we've powered off VBUS; and HNP, switching roles - * "host" to "peripheral". The OTG descriptor helps figure this out. - */ - if (!udev->bus->is_b_host - && udev->config - && udev->parent == udev->bus->root_hub) { - struct usb_otg_descriptor *desc = NULL; - struct usb_bus *bus = udev->bus; - - /* descriptor may appear anywhere in config */ - if (__usb_get_extra_descriptor (udev->rawdescriptors[0], - le16_to_cpu(udev->config[0].desc.wTotalLength), - USB_DT_OTG, (void **) &desc) == 0) { - if (desc->bmAttributes & USB_OTG_HNP) { - unsigned port1 = udev->portnum; - - dev_info(&udev->dev, - "Dual-Role OTG device on %sHNP port\n", - (port1 == bus->otg_port) - ? "" : "non-"); - - /* enable HNP before suspend, it's simpler */ - if (port1 == bus->otg_port) - bus->b_hnp_enable = 1; - err = usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - USB_REQ_SET_FEATURE, 0, - bus->b_hnp_enable - ? USB_DEVICE_B_HNP_ENABLE - : USB_DEVICE_A_ALT_HNP_SUPPORT, - 0, NULL, 0, USB_CTRL_SET_TIMEOUT); - if (err < 0) { - /* OTG MESSAGE: report errors here, - * customize to match your product. - */ - dev_info(&udev->dev, - "can't set HNP mode: %d\n", - err); - bus->b_hnp_enable = 0; - } - } - } - } - - if (!is_targeted(udev)) { - - /* Maybe it can talk to us, though we can't talk to it. - * (Includes HNP test device.) - */ - if (udev->bus->b_hnp_enable || udev->bus->is_b_host) { - err = usb_port_suspend(udev, PMSG_SUSPEND); - if (err < 0) - dev_dbg(&udev->dev, "HNP fail, %d\n", err); - } - err = -ENOTSUPP; - goto fail; - } -fail: -#endif - return err; -} - - -/** - * usb_enumerate_device - Read device configs/intfs/otg (usbcore-internal) - * @udev: newly addressed device (in ADDRESS state) - * - * This is only called by usb_new_device() and usb_authorize_device() - * and FIXME -- all comments that apply to them apply here wrt to - * environment. - * - * If the device is WUSB and not authorized, we don't attempt to read - * the string descriptors, as they will be errored out by the device - * until it has been authorized. - */ -static int usb_enumerate_device(struct usb_device *udev) -{ - int err; - - if (udev->config == NULL) { - err = usb_get_configuration(udev); - if (err < 0) { - dev_err(&udev->dev, "can't read configurations, error %d\n", - err); - goto fail; - } - } - if (udev->wusb == 1 && udev->authorized == 0) { - udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); - udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); - udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); - } - else { - /* read the standard strings and cache them if present */ - udev->product = usb_cache_string(udev, udev->descriptor.iProduct); - udev->manufacturer = usb_cache_string(udev, - udev->descriptor.iManufacturer); - udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); - } - err = usb_enumerate_device_otg(udev); -fail: - return err; -} - -static void set_usb_port_removable(struct usb_device *udev) -{ - struct usb_device *hdev = udev->parent; - struct usb_hub *hub; - u8 port = udev->portnum; - u16 wHubCharacteristics; - bool removable = true; - - if (!hdev) - return; - - hub = hdev_to_hub(udev->parent); - - wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); - - if (!(wHubCharacteristics & HUB_CHAR_COMPOUND)) - return; - - if (hub_is_superspeed(hdev)) { - if (hub->descriptor->u.ss.DeviceRemovable & (1 << port)) - removable = false; - } else { - if (hub->descriptor->u.hs.DeviceRemovable[port / 8] & (1 << (port % 8))) - removable = false; - } - - if (removable) - udev->removable = USB_DEVICE_REMOVABLE; - else - udev->removable = USB_DEVICE_FIXED; -} - -/** - * usb_new_device - perform initial device setup (usbcore-internal) - * @udev: newly addressed device (in ADDRESS state) - * - * This is called with devices which have been detected but not fully - * enumerated. The device descriptor is available, but not descriptors - * for any device configuration. The caller must have locked either - * the parent hub (if udev is a normal device) or else the - * usb_bus_list_lock (if udev is a root hub). The parent's pointer to - * udev has already been installed, but udev is not yet visible through - * sysfs or other filesystem code. - * - * It will return if the device is configured properly or not. Zero if - * the interface was registered with the driver core; else a negative - * errno value. - * - * This call is synchronous, and may not be used in an interrupt context. - * - * Only the hub driver or root-hub registrar should ever call this. - */ -int usb_new_device(struct usb_device *udev) -{ - int err; - - if (udev->parent) { - /* Initialize non-root-hub device wakeup to disabled; - * device (un)configuration controls wakeup capable - * sysfs power/wakeup controls wakeup enabled/disabled - */ - device_init_wakeup(&udev->dev, 0); - } - - /* Tell the runtime-PM framework the device is active */ - pm_runtime_set_active(&udev->dev); - pm_runtime_get_noresume(&udev->dev); - pm_runtime_use_autosuspend(&udev->dev); - pm_runtime_enable(&udev->dev); - - /* By default, forbid autosuspend for all devices. It will be - * allowed for hubs during binding. - */ - usb_disable_autosuspend(udev); - - err = usb_enumerate_device(udev); /* Read descriptors */ - 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))); - - /* Tell the world! */ - announce_device(udev); - - device_enable_async_suspend(&udev->dev); - - /* - * check whether the hub marks this port as non-removable. Do it - * now so that platform-specific data can override it in - * device_add() - */ - if (udev->parent) - set_usb_port_removable(udev); - - /* Register the device. The device driver is responsible - * for configuring the device and invoking the add-device - * notifier chain (used by usbfs and possibly others). - */ - err = device_add(&udev->dev); - if (err) { - dev_err(&udev->dev, "can't device_add, error %d\n", err); - goto fail; - } - - (void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev); - usb_mark_last_busy(udev); - pm_runtime_put_sync_autosuspend(&udev->dev); - - { - struct usb_hcd *hcd = bus_to_hcd(udev->bus); - - if ((udev->portnum == 1) && (udev->parent == udev->bus->root_hub) - && ((udev->speed == 3) || (hcd->rsrc_start == 0xfe007b00))) - *(unsigned char *)0xfe11010e = ((*(unsigned char *)0xfe11010e & (~0x3)) | 0x1); - } - return err; - -fail: - usb_set_device_state(udev, USB_STATE_NOTATTACHED); - pm_runtime_disable(&udev->dev); - pm_runtime_set_suspended(&udev->dev); - return err; -} - - -/** - * usb_deauthorize_device - deauthorize a device (usbcore-internal) - * @usb_dev: USB device - * - * Move the USB device to a very basic state where interfaces are disabled - * and the device is in fact unconfigured and unusable. - * - * We share a lock (that we have) with device_del(), so we need to - * defer its call. - */ -int usb_deauthorize_device(struct usb_device *usb_dev) -{ - usb_lock_device(usb_dev); - if (usb_dev->authorized == 0) - goto out_unauthorized; - - usb_dev->authorized = 0; - usb_set_configuration(usb_dev, -1); - - kfree(usb_dev->product); - usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); - kfree(usb_dev->manufacturer); - usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); - kfree(usb_dev->serial); - usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); - - usb_destroy_configuration(usb_dev); - usb_dev->descriptor.bNumConfigurations = 0; - -out_unauthorized: - usb_unlock_device(usb_dev); - return 0; -} - - -int usb_authorize_device(struct usb_device *usb_dev) -{ - int result = 0, c; - - usb_lock_device(usb_dev); - if (usb_dev->authorized == 1) - goto out_authorized; - - result = usb_autoresume_device(usb_dev); - if (result < 0) { - dev_err(&usb_dev->dev, - "can't autoresume for authorization: %d\n", result); - goto error_autoresume; - } - result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor)); - if (result < 0) { - dev_err(&usb_dev->dev, "can't re-read device descriptor for " - "authorization: %d\n", result); - goto error_device_descriptor; - } - - kfree(usb_dev->product); - usb_dev->product = NULL; - kfree(usb_dev->manufacturer); - usb_dev->manufacturer = NULL; - kfree(usb_dev->serial); - usb_dev->serial = NULL; - - usb_dev->authorized = 1; - result = usb_enumerate_device(usb_dev); - if (result < 0) - goto error_enumerate; - /* Choose and set the configuration. This registers the interfaces - * with the driver core and lets interface drivers bind to them. - */ - c = usb_choose_configuration(usb_dev); - if (c >= 0) { - result = usb_set_configuration(usb_dev, c); - if (result) { - dev_err(&usb_dev->dev, - "can't set config #%d, error %d\n", c, result); - /* This need not be fatal. The user can try to - * set other configurations. */ - } - } - dev_info(&usb_dev->dev, "authorized to connect\n"); - -error_enumerate: -error_device_descriptor: - usb_autosuspend_device(usb_dev); -error_autoresume: -out_authorized: - usb_unlock_device(usb_dev); // complements locktree - return result; -} - - -/* Returns 1 if @hub is a WUSB root hub, 0 otherwise */ -static unsigned hub_is_wusb(struct usb_hub *hub) -{ - struct usb_hcd *hcd; - if (hub->hdev->parent != NULL) /* not a root hub? */ - return 0; - hcd = container_of(hub->hdev->bus, struct usb_hcd, self); - return hcd->wireless; -} - - -#define PORT_RESET_TRIES 5 -#define SET_ADDRESS_TRIES 2 -#define GET_DESCRIPTOR_TRIES 2 -#define SET_CONFIG_TRIES (2 * (use_both_schemes + 1)) -#define USE_NEW_SCHEME(i) ((i) / 2 == (int)old_scheme_first) - -#define HUB_ROOT_RESET_TIME 50 /* times are in msec */ -#define HUB_SHORT_RESET_TIME 10 -#define HUB_BH_RESET_TIME 50 -#define HUB_LONG_RESET_TIME 200 -#define HUB_RESET_TIMEOUT 500 - -static int hub_port_reset(struct usb_hub *hub, int port1, - struct usb_device *udev, unsigned int delay, bool warm); - -/* Is a USB 3.0 port in the Inactive or Complinance Mode state? - * Port worm reset is required to recover - */ -static bool hub_port_warm_reset_required(struct usb_hub *hub, u16 portstatus) -{ - return hub_is_superspeed(hub->hdev) && - (((portstatus & USB_PORT_STAT_LINK_STATE) == - USB_SS_PORT_LS_SS_INACTIVE) || - ((portstatus & USB_PORT_STAT_LINK_STATE) == - USB_SS_PORT_LS_COMP_MOD)) ; -} - -static int hub_port_wait_reset(struct usb_hub *hub, int port1, - struct usb_device *udev, unsigned int delay, bool warm) -{ - int delay_time, ret; - u16 portstatus; - u16 portchange; - - for (delay_time = 0; - delay_time < HUB_RESET_TIMEOUT; - delay_time += delay) { - /* wait to give the device a chance to reset */ - msleep(delay); - - /* read and decode port status */ - ret = hub_port_status(hub, port1, &portstatus, &portchange); - if (ret < 0) - return ret; - - /* - * Some buggy devices require a warm reset to be issued even - * when the port appears not to be connected. - */ - if (!warm) { - /* - * Some buggy devices can cause an NEC host controller - * to transition to the "Error" state after a hot port - * reset. This will show up as the port state in - * "Inactive", and the port may also report a - * disconnect. Forcing a warm port reset seems to make - * the device work. - * - * See https://bugzilla.kernel.org/show_bug.cgi?id=41752 - */ - if (hub_port_warm_reset_required(hub, portstatus)) { - int ret; - - if ((portchange & USB_PORT_STAT_C_CONNECTION)) - clear_port_feature(hub->hdev, port1, - USB_PORT_FEAT_C_CONNECTION); - if (portchange & USB_PORT_STAT_C_LINK_STATE) - clear_port_feature(hub->hdev, port1, - USB_PORT_FEAT_C_PORT_LINK_STATE); - if (portchange & USB_PORT_STAT_C_RESET) - clear_port_feature(hub->hdev, port1, - USB_PORT_FEAT_C_RESET); - dev_dbg(hub->intfdev, "hot reset failed, warm reset port %d\n", - port1); - ret = hub_port_reset(hub, port1, - udev, HUB_BH_RESET_TIME, - true); - if ((portchange & USB_PORT_STAT_C_CONNECTION)) - clear_port_feature(hub->hdev, port1, - USB_PORT_FEAT_C_CONNECTION); - return ret; - } - /* Device went away? */ - if (!(portstatus & USB_PORT_STAT_CONNECTION)) - return -ENOTCONN; - - /* bomb out completely if the connection bounced */ - if ((portchange & USB_PORT_STAT_C_CONNECTION)) - return -ENOTCONN; - - /* if we`ve finished resetting, then break out of - * the loop - */ - if (!(portstatus & USB_PORT_STAT_RESET) && - (portstatus & USB_PORT_STAT_ENABLE)) { - if (hub_is_wusb(hub)) - udev->speed = USB_SPEED_WIRELESS; - else if (hub_is_superspeed(hub->hdev)) - udev->speed = USB_SPEED_SUPER; - else if (portstatus & USB_PORT_STAT_HIGH_SPEED) - udev->speed = USB_SPEED_HIGH; - else if (portstatus & USB_PORT_STAT_LOW_SPEED) - udev->speed = USB_SPEED_LOW; - else - udev->speed = USB_SPEED_FULL; - return 0; - } - } else { - if (portchange & USB_PORT_STAT_C_BH_RESET) - return 0; - } - - /* switch to the long delay after two short delay failures */ - if (delay_time >= 2 * HUB_SHORT_RESET_TIME) - delay = HUB_LONG_RESET_TIME; - - dev_dbg (hub->intfdev, - "port %d not %sreset yet, waiting %dms\n", - port1, warm ? "warm " : "", delay); - } - - return -EBUSY; -} - -static void hub_port_finish_reset(struct usb_hub *hub, int port1, - struct usb_device *udev, int *status, bool warm) -{ - switch (*status) { - case 0: - if (!warm) { - struct usb_hcd *hcd; - /* TRSTRCY = 10 ms; plus some extra */ - msleep(10); /*CharlesTu,2012.09.14,improve resume time*/ - update_devnum(udev, 0); - hcd = bus_to_hcd(udev->bus); - if (hcd->driver->reset_device) { - *status = hcd->driver->reset_device(hcd, udev); - if (*status < 0) { - dev_err(&udev->dev, "Cannot reset " - "HCD device state\n"); - break; - } - } - } - /* FALL THROUGH */ - case -ENOTCONN: - case -ENODEV: - clear_port_feature(hub->hdev, - port1, USB_PORT_FEAT_C_RESET); - /* FIXME need disconnect() for NOTATTACHED device */ - if (warm) { - clear_port_feature(hub->hdev, port1, - USB_PORT_FEAT_C_BH_PORT_RESET); - clear_port_feature(hub->hdev, port1, - USB_PORT_FEAT_C_PORT_LINK_STATE); - } else { - usb_set_device_state(udev, *status - ? USB_STATE_NOTATTACHED - : USB_STATE_DEFAULT); - } - break; - } -} - -/* Handle port reset and port warm(BH) reset (for USB3 protocol ports) */ -static int hub_port_reset(struct usb_hub *hub, int port1, - struct usb_device *udev, unsigned int delay, bool warm) -{ - int i, status; - - if (!warm) { - /* Block EHCI CF initialization during the port reset. - * Some companion controllers don't like it when they mix. - */ - down_read(&ehci_cf_port_reset_rwsem); - } else { - if (!hub_is_superspeed(hub->hdev)) { - dev_err(hub->intfdev, "only USB3 hub support " - "warm reset\n"); - return -EINVAL; - } - } - - /* Reset the port */ - for (i = 0; i < PORT_RESET_TRIES; i++) { - status = set_port_feature(hub->hdev, port1, (warm ? - USB_PORT_FEAT_BH_PORT_RESET : - USB_PORT_FEAT_RESET)); - if (status) { - dev_err(hub->intfdev, - "cannot %sreset port %d (err = %d)\n", - warm ? "warm " : "", port1, status); - } else { - status = hub_port_wait_reset(hub, port1, udev, delay, - warm); - if (status && status != -ENOTCONN) - dev_dbg(hub->intfdev, - "port_wait_reset: err = %d\n", - status); - } - - /* return on disconnect or reset */ - if (status == 0 || status == -ENOTCONN || status == -ENODEV) { - hub_port_finish_reset(hub, port1, udev, &status, warm); - goto done; - } - - dev_dbg (hub->intfdev, - "port %d not enabled, trying %sreset again...\n", - port1, warm ? "warm " : ""); - delay = HUB_LONG_RESET_TIME; - } - - dev_err (hub->intfdev, - "Cannot enable port %i. Maybe the USB cable is bad?\n", - port1); - -done: - if (!warm) - up_read(&ehci_cf_port_reset_rwsem); - - return status; -} - -/* Check if a port is power on */ -static int port_is_power_on(struct usb_hub *hub, unsigned portstatus) -{ - int ret = 0; - - if (hub_is_superspeed(hub->hdev)) { - if (portstatus & USB_SS_PORT_STAT_POWER) - ret = 1; - } else { - if (portstatus & USB_PORT_STAT_POWER) - ret = 1; - } - - return ret; -} - -#ifdef CONFIG_PM - -/* Check if a port is suspended(USB2.0 port) or in U3 state(USB3.0 port) */ -static int port_is_suspended(struct usb_hub *hub, unsigned portstatus) -{ - int ret = 0; - - if (hub_is_superspeed(hub->hdev)) { - if ((portstatus & USB_PORT_STAT_LINK_STATE) - == USB_SS_PORT_LS_U3) - ret = 1; - } else { - if (portstatus & USB_PORT_STAT_SUSPEND) - ret = 1; - } - - return ret; -} - -/* Determine whether the device on a port is ready for a normal resume, - * is ready for a reset-resume, or should be disconnected. - */ -static int check_port_resume_type(struct usb_device *udev, - struct usb_hub *hub, int port1, - int status, unsigned portchange, unsigned portstatus) -{ - /* Is the device still present? */ - if (status || port_is_suspended(hub, portstatus) || - !port_is_power_on(hub, portstatus) || - !(portstatus & USB_PORT_STAT_CONNECTION)) { - if (status >= 0) - status = -ENODEV; - } - - /* Can't do a normal resume if the port isn't enabled, - * so try a reset-resume instead. - */ - else if (!(portstatus & USB_PORT_STAT_ENABLE) && !udev->reset_resume) { - if (udev->persist_enabled) - udev->reset_resume = 1; - else - status = -ENODEV; - } - - if (status) { - dev_dbg(hub->intfdev, - "port %d status %04x.%04x after resume, %d\n", - port1, portchange, portstatus, status); - } else if (udev->reset_resume) { - - /* Late port handoff can set status-change bits */ - if (portchange & USB_PORT_STAT_C_CONNECTION) - clear_port_feature(hub->hdev, port1, - USB_PORT_FEAT_C_CONNECTION); - if (portchange & USB_PORT_STAT_C_ENABLE) - clear_port_feature(hub->hdev, port1, - USB_PORT_FEAT_C_ENABLE); - } - - return status; -} - -#ifdef CONFIG_USB_SUSPEND - -/* - * usb_port_suspend - suspend a usb device's upstream port - * @udev: device that's no longer in active use, not a root hub - * Context: must be able to sleep; device not locked; pm locks held - * - * Suspends a USB device that isn't in active use, conserving power. - * Devices may wake out of a suspend, if anything important happens, - * using the remote wakeup mechanism. They may also be taken out of - * suspend by the host, using usb_port_resume(). It's also routine - * to disconnect devices while they are suspended. - * - * This only affects the USB hardware for a device; its interfaces - * (and, for hubs, child devices) must already have been suspended. - * - * Selective port suspend reduces power; most suspended devices draw - * less than 500 uA. It's also used in OTG, along with remote wakeup. - * All devices below the suspended port are also suspended. - * - * Devices leave suspend state when the host wakes them up. Some devices - * also support "remote wakeup", where the device can activate the USB - * tree above them to deliver data, such as a keypress or packet. In - * some cases, this wakes the USB host. - * - * Suspending OTG devices may trigger HNP, if that's been enabled - * between a pair of dual-role devices. That will change roles, such - * as from A-Host to A-Peripheral or from B-Host back to B-Peripheral. - * - * Devices on USB hub ports have only one "suspend" state, corresponding - * to ACPI D2, "may cause the device to lose some context". - * State transitions include: - * - * - suspend, resume ... when the VBUS power link stays live - * - suspend, disconnect ... VBUS lost - * - * Once VBUS drop breaks the circuit, the port it's using has to go through - * normal re-enumeration procedures, starting with enabling VBUS power. - * Other than re-initializing the hub (plug/unplug, except for root hubs), - * Linux (2.6) currently has NO mechanisms to initiate that: no khubd - * timer, no SRP, no requests through sysfs. - * - * If CONFIG_USB_SUSPEND isn't enabled, devices only really suspend when - * the root hub for their bus goes into global suspend ... so we don't - * (falsely) update the device power state to say it suspended. - * - * Returns 0 on success, else negative errno. - */ -int usb_port_suspend(struct usb_device *udev, pm_message_t msg) -{ - struct usb_hub *hub = hdev_to_hub(udev->parent); - int port1 = udev->portnum; - int status; - - /* enable remote wakeup when appropriate; this lets the device - * wake up the upstream hub (including maybe the root hub). - * - * NOTE: OTG devices may issue remote wakeup (or SRP) even when - * we don't explicitly enable it here. - */ - if (udev->do_remote_wakeup) { - if (!hub_is_superspeed(hub->hdev)) { - status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - USB_REQ_SET_FEATURE, USB_RECIP_DEVICE, - USB_DEVICE_REMOTE_WAKEUP, 0, - NULL, 0, - USB_CTRL_SET_TIMEOUT); - } else { - /* Assume there's only one function on the USB 3.0 - * device and enable remote wake for the first - * interface. FIXME if the interface association - * descriptor shows there's more than one function. - */ - status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - USB_REQ_SET_FEATURE, - USB_RECIP_INTERFACE, - USB_INTRF_FUNC_SUSPEND, - USB_INTRF_FUNC_SUSPEND_RW | - USB_INTRF_FUNC_SUSPEND_LP, - NULL, 0, - USB_CTRL_SET_TIMEOUT); - } - if (status) { - dev_dbg(&udev->dev, "won't remote wakeup, status %d\n", - status); - /* bail if autosuspend is requested */ - if (PMSG_IS_AUTO(msg)) - return status; - } - } - - /* disable USB2 hardware LPM */ - if (udev->usb2_hw_lpm_enabled == 1) - usb_set_usb2_hardware_lpm(udev, 0); - - /* see 7.1.7.6 */ - if (hub_is_superspeed(hub->hdev)) - status = set_port_feature(hub->hdev, - port1 | (USB_SS_PORT_LS_U3 << 3), - USB_PORT_FEAT_LINK_STATE); - else - status = set_port_feature(hub->hdev, port1, - USB_PORT_FEAT_SUSPEND); - if (status) { - dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n", - port1, status); - /* paranoia: "should not happen" */ - if (udev->do_remote_wakeup) - (void) usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE, - USB_DEVICE_REMOTE_WAKEUP, 0, - NULL, 0, - USB_CTRL_SET_TIMEOUT); - - /* Try to enable USB2 hardware LPM again */ - if (udev->usb2_hw_lpm_capable == 1) - usb_set_usb2_hardware_lpm(udev, 1); - - /* System sleep transitions should never fail */ - if (!PMSG_IS_AUTO(msg)) - status = 0; - } else { - /* device has up to 10 msec to fully suspend */ - dev_dbg(&udev->dev, "usb %ssuspend, wakeup %d\n", - (PMSG_IS_AUTO(msg) ? "auto-" : ""), - udev->do_remote_wakeup); - usb_set_device_state(udev, USB_STATE_SUSPENDED); - msleep(10); - } - usb_mark_last_busy(hub->hdev); - return status; -} - -/* - * If the USB "suspend" state is in use (rather than "global suspend"), - * many devices will be individually taken out of suspend state using - * special "resume" signaling. This routine kicks in shortly after - * hardware resume signaling is finished, either because of selective - * resume (by host) or remote wakeup (by device) ... now see what changed - * in the tree that's rooted at this device. - * - * If @udev->reset_resume is set then the device is reset before the - * status check is done. - */ -static int finish_port_resume(struct usb_device *udev) -{ - int status = 0; - u16 devstatus; - - /* caller owns the udev device lock */ - dev_dbg(&udev->dev, "%s\n", - udev->reset_resume ? "finish reset-resume" : "finish resume"); - - /* usb ch9 identifies four variants of SUSPENDED, based on what - * state the device resumes to. Linux currently won't see the - * first two on the host side; they'd be inside hub_port_init() - * during many timeouts, but khubd can't suspend until later. - */ - usb_set_device_state(udev, udev->actconfig - ? USB_STATE_CONFIGURED - : USB_STATE_ADDRESS); - - /* 10.5.4.5 says not to reset a suspended port if the attached - * device is enabled for remote wakeup. Hence the reset - * operation is carried out here, after the port has been - * resumed. - */ - if (udev->reset_resume) - retry_reset_resume: - status = usb_reset_and_verify_device(udev); - - /* 10.5.4.5 says be sure devices in the tree are still there. - * For now let's assume the device didn't go crazy on resume, - * and device drivers will know about any resume quirks. - */ - if (status == 0) { - devstatus = 0; - status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus); - if (status >= 0) - status = (status > 0 ? 0 : -ENODEV); - - /* If a normal resume failed, try doing a reset-resume */ - if (status && !udev->reset_resume && udev->persist_enabled) { - dev_dbg(&udev->dev, "retry with reset-resume\n"); - udev->reset_resume = 1; - goto retry_reset_resume; - } - } - - if (status) { - dev_dbg(&udev->dev, "gone after usb resume? status %d\n", - status); - } else if (udev->actconfig) { - le16_to_cpus(&devstatus); - if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { - status = usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - USB_REQ_CLEAR_FEATURE, - USB_RECIP_DEVICE, - USB_DEVICE_REMOTE_WAKEUP, 0, - NULL, 0, - USB_CTRL_SET_TIMEOUT); - if (status) - dev_dbg(&udev->dev, - "disable remote wakeup, status %d\n", - status); - } - status = 0; - } - return status; -} - -/* - * usb_port_resume - re-activate a suspended usb device's upstream port - * @udev: device to re-activate, not a root hub - * Context: must be able to sleep; device not locked; pm locks held - * - * This will re-activate the suspended device, increasing power usage - * while letting drivers communicate again with its endpoints. - * USB resume explicitly guarantees that the power session between - * the host and the device is the same as it was when the device - * suspended. - * - * If @udev->reset_resume is set then this routine won't check that the - * port is still enabled. Furthermore, finish_port_resume() above will - * reset @udev. The end result is that a broken power session can be - * recovered and @udev will appear to persist across a loss of VBUS power. - * - * For example, if a host controller doesn't maintain VBUS suspend current - * during a system sleep or is reset when the system wakes up, all the USB - * power sessions below it will be broken. This is especially troublesome - * for mass-storage devices containing mounted filesystems, since the - * device will appear to have disconnected and all the memory mappings - * to it will be lost. Using the USB_PERSIST facility, the device can be - * made to appear as if it had not disconnected. - * - * This facility can be dangerous. Although usb_reset_and_verify_device() makes - * every effort to insure that the same device is present after the - * reset as before, it cannot provide a 100% guarantee. Furthermore it's - * quite possible for a device to remain unaltered but its media to be - * changed. If the user replaces a flash memory card while the system is - * asleep, he will have only himself to blame when the filesystem on the - * new card is corrupted and the system crashes. - * - * Returns 0 on success, else negative errno. - */ -int usb_port_resume(struct usb_device *udev, pm_message_t msg) -{ - struct usb_hub *hub = hdev_to_hub(udev->parent); - int port1 = udev->portnum; - int status; - u16 portchange, portstatus; - - /* Skip the initial Clear-Suspend step for a remote wakeup */ - status = hub_port_status(hub, port1, &portstatus, &portchange); - if (status == 0 && !port_is_suspended(hub, portstatus)) - goto SuspendCleared; - - // dev_dbg(hub->intfdev, "resume port %d\n", port1); - - set_bit(port1, hub->busy_bits); - - /* see 7.1.7.7; affects power usage, but not budgeting */ - if (hub_is_superspeed(hub->hdev)) - status = set_port_feature(hub->hdev, - port1 | (USB_SS_PORT_LS_U0 << 3), - USB_PORT_FEAT_LINK_STATE); - else - status = clear_port_feature(hub->hdev, - port1, USB_PORT_FEAT_SUSPEND); - if (status) { - dev_dbg(hub->intfdev, "can't resume port %d, status %d\n", - port1, status); - } else { - /* drive resume for at least 20 msec */ - dev_dbg(&udev->dev, "usb %sresume\n", - (PMSG_IS_AUTO(msg) ? "auto-" : "")); - msleep(25); - - /* Virtual root hubs can trigger on GET_PORT_STATUS to - * stop resume signaling. Then finish the resume - * sequence. - */ - status = hub_port_status(hub, port1, &portstatus, &portchange); - - /* TRSMRCY = 10 msec */ - msleep(10); - } - - SuspendCleared: - if (status == 0) { - if (hub_is_superspeed(hub->hdev)) { - if (portchange & USB_PORT_STAT_C_LINK_STATE) - clear_port_feature(hub->hdev, port1, - USB_PORT_FEAT_C_PORT_LINK_STATE); - } else { - if (portchange & USB_PORT_STAT_C_SUSPEND) - clear_port_feature(hub->hdev, port1, - USB_PORT_FEAT_C_SUSPEND); - } - } - - clear_bit(port1, hub->busy_bits); - - status = check_port_resume_type(udev, - hub, port1, status, portchange, portstatus); - if (status == 0) - status = finish_port_resume(udev); - if (status < 0) { - dev_dbg(&udev->dev, "can't resume, status %d\n", status); - hub_port_logical_disconnect(hub, port1); - } else { - /* Try to enable USB2 hardware LPM */ - if (udev->usb2_hw_lpm_capable == 1) - usb_set_usb2_hardware_lpm(udev, 1); - } - - return status; -} - -/* caller has locked udev */ -int usb_remote_wakeup(struct usb_device *udev) -{ - int status = 0; - - if (udev->state == USB_STATE_SUSPENDED) { - dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-"); - status = usb_autoresume_device(udev); - if (status == 0) { - /* Let the drivers do their thing, then... */ - usb_autosuspend_device(udev); - } - } - return status; -} - -#else /* CONFIG_USB_SUSPEND */ - -/* When CONFIG_USB_SUSPEND isn't set, we never suspend or resume any ports. */ - -int usb_port_suspend(struct usb_device *udev, pm_message_t msg) -{ - return 0; -} - -/* However we may need to do a reset-resume */ - -int usb_port_resume(struct usb_device *udev, pm_message_t msg) -{ - struct usb_hub *hub = hdev_to_hub(udev->parent); - int port1 = udev->portnum; - int status; - u16 portchange, portstatus; - - status = hub_port_status(hub, port1, &portstatus, &portchange); - status = check_port_resume_type(udev, - hub, port1, status, portchange, portstatus); - - if (status) { - dev_dbg(&udev->dev, "can't resume, status %d\n", status); - hub_port_logical_disconnect(hub, port1); - } else if (udev->reset_resume) { - dev_dbg(&udev->dev, "reset-resume\n"); - status = usb_reset_and_verify_device(udev); - } - return status; -} - -#endif - -static int hub_suspend(struct usb_interface *intf, pm_message_t msg) -{ - struct usb_hub *hub = usb_get_intfdata (intf); - struct usb_device *hdev = hub->hdev; - unsigned port1; - int status; - - /* Warn if children aren't already suspended */ - for (port1 = 1; port1 <= hdev->maxchild; port1++) { - struct usb_device *udev; - - udev = hdev->children [port1-1]; - if (udev && udev->can_submit) { - dev_warn(&intf->dev, "port %d nyet suspended\n", port1); - if (PMSG_IS_AUTO(msg)) - return -EBUSY; - } - } - if (hub_is_superspeed(hdev) && hdev->do_remote_wakeup) { - /* Enable hub to send remote wakeup for all ports. */ - for (port1 = 1; port1 <= hdev->maxchild; port1++) { - status = set_port_feature(hdev, - port1 | - USB_PORT_FEAT_REMOTE_WAKE_CONNECT | - USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT | - USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT, - USB_PORT_FEAT_REMOTE_WAKE_MASK); - } - } - - dev_dbg(&intf->dev, "%s\n", __func__); - - /* stop khubd and related activity */ - hub_quiesce(hub, HUB_SUSPEND); - return 0; -} - -static int hub_resume(struct usb_interface *intf) -{ - struct usb_hub *hub = usb_get_intfdata(intf); - - dev_dbg(&intf->dev, "%s\n", __func__); - hub_activate(hub, HUB_RESUME); - return 0; -} - -static int hub_reset_resume(struct usb_interface *intf) -{ - struct usb_hub *hub = usb_get_intfdata(intf); - usb_resume_flag = 1; - dev_dbg(&intf->dev, "%s\n", __func__); - hub_activate(hub, HUB_RESET_RESUME); - usb_resume_flag = 0; - return 0; -} - -/** - * usb_root_hub_lost_power - called by HCD if the root hub lost Vbus power - * @rhdev: struct usb_device for the root hub - * - * The USB host controller driver calls this function when its root hub - * is resumed and Vbus power has been interrupted or the controller - * has been reset. The routine marks @rhdev as having lost power. - * When the hub driver is resumed it will take notice and carry out - * power-session recovery for all the "USB-PERSIST"-enabled child devices; - * the others will be disconnected. - */ -void usb_root_hub_lost_power(struct usb_device *rhdev) -{ - dev_warn(&rhdev->dev, "root hub lost power or was reset\n"); - rhdev->reset_resume = 1; -} -EXPORT_SYMBOL_GPL(usb_root_hub_lost_power); - -#else /* CONFIG_PM */ - -#define hub_suspend NULL -#define hub_resume NULL -#define hub_reset_resume NULL -#endif - - -/* USB 2.0 spec, 7.1.7.3 / fig 7-29: - * - * Between connect detection and reset signaling there must be a delay - * of 100ms at least for debounce and power-settling. The corresponding - * timer shall restart whenever the downstream port detects a disconnect. - * - * Apparently there are some bluetooth and irda-dongles and a number of - * low-speed devices for which this debounce period may last over a second. - * Not covered by the spec - but easy to deal with. - * - * This implementation uses a 1500ms total debounce timeout; if the - * connection isn't stable by then it returns -ETIMEDOUT. It checks - * every 25ms for transient disconnects. When the port status has been - * unchanged for 100ms it returns the port status. - */ -static int hub_port_debounce(struct usb_hub *hub, int port1) -{ - int ret; - int total_time, stable_time = 0; - u16 portchange, portstatus; - unsigned connection = 0xffff; - - for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) { - ret = hub_port_status(hub, port1, &portstatus, &portchange); - if (ret < 0) - return ret; - - if (!(portchange & USB_PORT_STAT_C_CONNECTION) && - (portstatus & USB_PORT_STAT_CONNECTION) == connection) { - stable_time += HUB_DEBOUNCE_STEP; - if (stable_time >= HUB_DEBOUNCE_STABLE) - break; - } else { - stable_time = 0; - connection = portstatus & USB_PORT_STAT_CONNECTION; - } - - if (portchange & USB_PORT_STAT_C_CONNECTION) { - clear_port_feature(hub->hdev, port1, - USB_PORT_FEAT_C_CONNECTION); - } - - if (total_time >= HUB_DEBOUNCE_TIMEOUT) - break; - msleep(HUB_DEBOUNCE_STEP); - } - - dev_dbg (hub->intfdev, - "debounce: port %d: total %dms stable %dms status 0x%x\n", - port1, total_time, stable_time, portstatus); - - if (stable_time < HUB_DEBOUNCE_STABLE) - return -ETIMEDOUT; - return portstatus; -} - -void usb_ep0_reinit(struct usb_device *udev) -{ - usb_disable_endpoint(udev, 0 + USB_DIR_IN, true); - usb_disable_endpoint(udev, 0 + USB_DIR_OUT, true); - usb_enable_endpoint(udev, &udev->ep0, true); -} -EXPORT_SYMBOL_GPL(usb_ep0_reinit); - -#define usb_sndaddr0pipe() (PIPE_CONTROL << 30) -#define usb_rcvaddr0pipe() ((PIPE_CONTROL << 30) | USB_DIR_IN) - -static int hub_set_address(struct usb_device *udev, int devnum) -{ - int retval; - struct usb_hcd *hcd = bus_to_hcd(udev->bus); - - /* - * 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; - 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_devnum(udev, devnum); - /* Device now using proper address. */ - usb_set_device_state(udev, USB_STATE_ADDRESS); - usb_ep0_reinit(udev); - } - return retval; -} - -/* Reset device, (re)assign address, get device descriptor. - * Device connection must be stable, no more debouncing needed. - * Returns device in USB_STATE_ADDRESS, except on error. - * - * If this is called for an already-existing device (as part of - * usb_reset_and_verify_device), the caller must own the device lock. For a - * newly detected device that is not accessible through any global - * pointers, it's not necessary to lock the device. - */ -static int -hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, - int retry_counter) -{ - 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; - const char *speed; - int devnum = udev->devnum; - - /* root hub ports have a slightly longer reset period - * (from USB 2.0 spec, section 7.1.7.5) - */ - if (!hdev->parent) { - delay = HUB_ROOT_RESET_TIME; - if (port1 == hdev->bus->otg_port) - hdev->bus->b_hnp_enable = 0; - } - - /* Some low speed devices have problems with the quick delay, so */ - /* be a bit pessimistic with those devices. RHbug #23670 */ - if (oldspeed == USB_SPEED_LOW) - delay = HUB_LONG_RESET_TIME; - - mutex_lock(&usb_address0_mutex); - - /* 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, false); - if (retval < 0) /* error or disconnect */ - goto fail; - /* success, speed is known */ - - retval = -ENODEV; - - if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) { - dev_dbg(&udev->dev, "device reset changed speed!\n"); - goto fail; - } - oldspeed = udev->speed; - - /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ... - * it's fixed size except for full speed devices. - * For Wireless USB devices, ep0 max packet is always 512 (tho - * reported as 0xff in the device descriptor). WUSB1.0[4.8.1]. - */ - switch (udev->speed) { - case USB_SPEED_SUPER: - case USB_SPEED_WIRELESS: /* fixed at 512 */ - udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512); - break; - case USB_SPEED_HIGH: /* fixed at 64 */ - udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64); - break; - case USB_SPEED_FULL: /* 8, 16, 32, or 64 */ - /* to determine the ep0 maxpacket size, try to read - * the device descriptor to get bMaxPacketSize0 and - * then correct our initial guess. - */ - udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64); - break; - case USB_SPEED_LOW: /* fixed at 8 */ - udev->ep0.desc.wMaxPacketSize = cpu_to_le16(8); - break; - default: - goto fail; - } - - if (udev->speed == USB_SPEED_WIRELESS) - speed = "variable speed Wireless"; - else - speed = usb_speed_string(udev->speed); - - if (udev->speed != USB_SPEED_SUPER) - dev_info(&udev->dev, - "%s %s USB device number %d using %s\n", - (udev->config) ? "reset" : "new", speed, - devnum, udev->bus->controller->driver->name); - - /* Set up TT records, if needed */ - if (hdev->tt) { - udev->tt = hdev->tt; - udev->ttport = hdev->ttport; - } else if (udev->speed != USB_SPEED_HIGH - && hdev->speed == USB_SPEED_HIGH) { - if (!hub->tt.hub) { - dev_err(&udev->dev, "parent hub has no TT\n"); - retval = -EINVAL; - goto fail; - } - udev->tt = &hub->tt; - udev->ttport = port1; - } - - /* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way? - * Because device hardware and firmware is sometimes buggy in - * this area, and this is how Linux has done it for ages. - * Change it cautiously. - * - * NOTE: If USE_NEW_SCHEME() is true we will start by issuing - * a 64-byte GET_DESCRIPTOR request. This is what Windows does, - * so it may help with some non-standards-compliant devices. - * Otherwise we start with SET_ADDRESS and then try to read the - * first 8 bytes of the device descriptor to get the ep0 maxpacket - * value. - */ - for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) { - if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) { - struct usb_device_descriptor *buf; - int r = 0; - -#define GET_DESCRIPTOR_BUFSIZE 64 - buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO); - if (!buf) { - retval = -ENOMEM; - continue; - } - - /* Retry on all errors; some devices are flakey. - * 255 is for WUSB devices, we actually need to use - * 512 (WUSB1.0[4.8.1]). - */ - for (j = 0; j < 3; ++j) { - buf->bMaxPacketSize0 = 0; - r = usb_control_msg(udev, usb_rcvaddr0pipe(), - USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, - USB_DT_DEVICE << 8, 0, - buf, GET_DESCRIPTOR_BUFSIZE, - initial_descriptor_timeout); - switch (buf->bMaxPacketSize0) { - case 8: case 16: case 32: case 64: case 255: - if (buf->bDescriptorType == - USB_DT_DEVICE) { - r = 0; - break; - } - /* FALL THROUGH */ - default: - if (r == 0) - r = -EPROTO; - break; - } - if (r == 0) - break; - } - udev->descriptor.bMaxPacketSize0 = - buf->bMaxPacketSize0; - kfree(buf); - - retval = hub_port_reset(hub, port1, udev, delay, false); - if (retval < 0) /* error or disconnect */ - goto fail; - if (oldspeed != udev->speed) { - dev_dbg(&udev->dev, - "device reset changed speed!\n"); - retval = -ENODEV; - goto fail; - } - if (r) { - dev_err(&udev->dev, - "device descriptor read/64, error %d\n", - r); - retval = -EMSGSIZE; - continue; - } -#undef GET_DESCRIPTOR_BUFSIZE - } - - /* - * If device is WUSB, we already assigned an - * unauthorized address in the Connect Ack sequence; - * authorization will assign the final address. - */ - if (udev->wusb == 0) { - for (j = 0; j < SET_ADDRESS_TRIES; ++j) { - retval = hub_set_address(udev, devnum); - if (retval >= 0) - break; - msleep(200); - } - if (retval < 0) { - dev_err(&udev->dev, - "device not accepting address %d, error %d\n", - devnum, retval); - goto fail; - } - if (udev->speed == USB_SPEED_SUPER) { - devnum = udev->devnum; - dev_info(&udev->dev, - "%s SuperSpeed USB device number %d using %s\n", - (udev->config) ? "reset" : "new", - devnum, udev->bus->controller->driver->name); - } - - /* 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) && !(hcd->driver->flags & HCD_USB3)) - break; - } - - retval = usb_get_device_descriptor(udev, 8); - if (retval < 8) { - dev_err(&udev->dev, - "device descriptor read/8, error %d\n", - retval); - if (retval >= 0) - retval = -EMSGSIZE; - } else { - retval = 0; - break; - } - } - if (retval) - goto fail; - - /* - * Some superspeed devices have finished the link training process - * and attached to a superspeed hub port, but the device descriptor - * got from those devices show they aren't superspeed devices. Warm - * reset the port attached by the devices can fix them. - */ - if ((udev->speed == USB_SPEED_SUPER) && - (le16_to_cpu(udev->descriptor.bcdUSB) < 0x0300)) { - dev_err(&udev->dev, "got a wrong device descriptor, " - "warm reset device\n"); - hub_port_reset(hub, port1, udev, - HUB_BH_RESET_TIME, true); - retval = -EINVAL; - goto fail; - } - - if (udev->descriptor.bMaxPacketSize0 == 0xff || - udev->speed == USB_SPEED_SUPER) - i = 512; - else - i = udev->descriptor.bMaxPacketSize0; - if (usb_endpoint_maxp(&udev->ep0.desc) != i) { - if (udev->speed == USB_SPEED_LOW || - !(i == 8 || i == 16 || i == 32 || i == 64)) { - dev_err(&udev->dev, "Invalid ep0 maxpacket: %d\n", i); - retval = -EMSGSIZE; - goto fail; - } - if (udev->speed == USB_SPEED_FULL) - dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", i); - else - dev_warn(&udev->dev, "Using ep0 maxpacket: %d\n", i); - udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i); - usb_ep0_reinit(udev); - } - - retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE); - if (retval < (signed)sizeof(udev->descriptor)) { - dev_err(&udev->dev, "device descriptor read/all, error %d\n", - retval); - if (retval >= 0) - retval = -ENOMSG; - goto fail; - } - - if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) { - retval = usb_get_bos_descriptor(udev); - if (!retval) { - if (udev->bos->ext_cap && (USB_LPM_SUPPORT & - le32_to_cpu(udev->bos->ext_cap->bmAttributes))) - udev->lpm_capable = 1; - } - } - - retval = 0; - /* notify HCD that we have a device connected and addressed */ - if (hcd->driver->update_device) - hcd->driver->update_device(hcd, udev); -fail: - if (retval) { - hub_port_disable(hub, port1, 0); - update_devnum(udev, devnum); /* for disconnect processing */ - } - mutex_unlock(&usb_address0_mutex); - return retval; -} - -static void -check_highspeed (struct usb_hub *hub, struct usb_device *udev, int port1) -{ - struct usb_qualifier_descriptor *qual; - int status; - - qual = kmalloc (sizeof *qual, GFP_KERNEL); - if (qual == NULL) - return; - - status = usb_get_descriptor (udev, USB_DT_DEVICE_QUALIFIER, 0, - qual, sizeof *qual); - if (status == sizeof *qual) { - dev_info(&udev->dev, "not running at top speed; " - "connect to a high speed hub\n"); - /* hub LEDs are probably harder to miss than syslog */ - if (hub->has_indicators) { - hub->indicator[port1-1] = INDICATOR_GREEN_BLINK; - schedule_delayed_work (&hub->leds, 0); - } - } - kfree(qual); -} - -static unsigned -hub_power_remaining (struct usb_hub *hub) -{ - struct usb_device *hdev = hub->hdev; - int remaining; - int port1; - - if (!hub->limited_power) - return 0; - - remaining = hdev->bus_mA - hub->descriptor->bHubContrCurrent; - for (port1 = 1; port1 <= hdev->maxchild; ++port1) { - struct usb_device *udev = hdev->children[port1 - 1]; - int delta; - - if (!udev) - continue; - - /* Unconfigured devices may not use more than 100mA, - * or 8mA for OTG ports */ - if (udev->actconfig) - delta = udev->actconfig->desc.bMaxPower * 2; - else if (port1 != udev->bus->otg_port || hdev->parent) - delta = 100; - else - delta = 8; - if (delta > hub->mA_per_port) - dev_warn(&udev->dev, - "%dmA is over %umA budget for port %d!\n", - delta, hub->mA_per_port, port1); - remaining -= delta; - } - if (remaining < 0) { - dev_warn(hub->intfdev, "%dmA over power budget!\n", - - remaining); - remaining = 0; - } - return remaining; -} - -/* Handle physical or logical connection change events. - * This routine is called when: - * a port connection-change occurs; - * a port enable-change occurs (often caused by EMI); - * usb_reset_and_verify_device() encounters changed descriptors (as from - * a firmware download) - * caller already locked the hub - */ -static void hub_port_connect_change(struct usb_hub *hub, int port1, - u16 portstatus, u16 portchange) -{ - struct usb_device *hdev = hub->hdev; - struct device *hub_dev = hub->intfdev; - struct usb_hcd *hcd = bus_to_hcd(hdev->bus); - unsigned wHubCharacteristics = - le16_to_cpu(hub->descriptor->wHubCharacteristics); - struct usb_device *udev; - int status, i; - - dev_dbg (hub_dev, - "port %d, status %04x, change %04x, %s\n", - port1, portstatus, portchange, portspeed(hub, portstatus)); - - if (hub->has_indicators) { - set_port_led(hub, port1, HUB_LED_AUTO); - hub->indicator[port1-1] = INDICATOR_AUTO; - } - -#ifdef CONFIG_USB_OTG - /* during HNP, don't repeat the debounce */ - if (hdev->bus->is_b_host) - portchange &= ~(USB_PORT_STAT_C_CONNECTION | - USB_PORT_STAT_C_ENABLE); -#endif - - /* Try to resuscitate an existing device */ - udev = hdev->children[port1-1]; - if ((portstatus & USB_PORT_STAT_CONNECTION) && udev && - udev->state != USB_STATE_NOTATTACHED) { - usb_lock_device(udev); - if (portstatus & USB_PORT_STAT_ENABLE) { - status = 0; /* Nothing to do */ - -#ifdef CONFIG_USB_SUSPEND - } else if (udev->state == USB_STATE_SUSPENDED && - udev->persist_enabled) { - /* For a suspended device, treat this as a - * remote wakeup event. - */ - status = usb_remote_wakeup(udev); -#endif - - } else { - status = -ENODEV; /* Don't resuscitate */ - } - usb_unlock_device(udev); - - if (status == 0) { - clear_bit(port1, hub->change_bits); - return; - } - } - - /* Disconnect any existing devices under this port */ - if (udev) - usb_disconnect(&hdev->children[port1-1]); - clear_bit(port1, hub->change_bits); - - /* We can forget about a "removed" device when there's a physical - * disconnect or the connect status changes. - */ - if (!(portstatus & USB_PORT_STAT_CONNECTION) || - (portchange & USB_PORT_STAT_C_CONNECTION)) - clear_bit(port1, hub->removed_bits); - - if (portchange & (USB_PORT_STAT_C_CONNECTION | - USB_PORT_STAT_C_ENABLE)) { - status = hub_port_debounce(hub, port1); - if (status < 0) { - if (printk_ratelimit()) - dev_err(hub_dev, "connect-debounce failed, " - "port %d disabled\n", port1); - portstatus &= ~USB_PORT_STAT_CONNECTION; - } else { - portstatus = status; - } - } - - /* Return now if debouncing failed or nothing is connected or - * the device was "removed". - */ - if (!(portstatus & USB_PORT_STAT_CONNECTION) || - test_bit(port1, hub->removed_bits)) { - - /* maybe switch power back on (e.g. root hub was reset) */ - if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2 - && !port_is_power_on(hub, portstatus)) - set_port_feature(hdev, port1, USB_PORT_FEAT_POWER); - - if (portstatus & USB_PORT_STAT_ENABLE) - goto done; - return; - } - - for (i = 0; i < SET_CONFIG_TRIES; i++) { - - /* reallocate for each attempt, since references - * to the previous one can escape in various ways - */ - udev = usb_alloc_dev(hdev, hdev->bus, port1); - if (!udev) { - dev_err (hub_dev, - "couldn't allocate port %d usb_device\n", - port1); - goto done; - } - - usb_set_device_state(udev, USB_STATE_POWERED); - udev->bus_mA = hub->mA_per_port; - udev->level = hdev->level + 1; - udev->wusb = hub_is_wusb(hub); - - /* Only USB 3.0 devices are connected to SuperSpeed hubs. */ - if (hub_is_superspeed(hub->hdev)) - udev->speed = USB_SPEED_SUPER; - else - udev->speed = USB_SPEED_UNKNOWN; - - choose_devnum(udev); - if (udev->devnum <= 0) { - status = -ENOTCONN; /* Don't retry */ - goto loop; - } - - /* reset (non-USB 3.0 devices) and get descriptor */ - status = hub_port_init(hub, udev, port1, i); - if (status < 0) - goto loop; - - usb_detect_quirks(udev); - if (udev->quirks & USB_QUIRK_DELAY_INIT) - msleep(1000); - - /* consecutive bus-powered hubs aren't reliable; they can - * violate the voltage drop budget. if the new child has - * a "powered" LED, users should notice we didn't enable it - * (without reading syslog), even without per-port LEDs - * on the parent. - */ - if (udev->descriptor.bDeviceClass == USB_CLASS_HUB - && udev->bus_mA <= 100) { - u16 devstat; - - status = usb_get_status(udev, USB_RECIP_DEVICE, 0, - &devstat); - if (status < 2) { - dev_dbg(&udev->dev, "get status %d ?\n", status); - goto loop_disable; - } - le16_to_cpus(&devstat); - if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) { - dev_err(&udev->dev, - "can't connect bus-powered hub " - "to this port\n"); - if (hub->has_indicators) { - hub->indicator[port1-1] = - INDICATOR_AMBER_BLINK; - schedule_delayed_work (&hub->leds, 0); - } - status = -ENOTCONN; /* Don't retry */ - goto loop_disable; - } - } - - /* check for devices running slower than they could */ - if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200 - && udev->speed == USB_SPEED_FULL - && highspeed_hubs != 0) - check_highspeed (hub, udev, port1); - - /* Store the parent's children[] pointer. At this point - * udev becomes globally accessible, although presumably - * no one will look at it until hdev is unlocked. - */ - status = 0; - - /* We mustn't add new devices if the parent hub has - * been disconnected; we would race with the - * recursively_mark_NOTATTACHED() routine. - */ - spin_lock_irq(&device_state_lock); - if (hdev->state == USB_STATE_NOTATTACHED) - status = -ENOTCONN; - else - hdev->children[port1-1] = udev; - spin_unlock_irq(&device_state_lock); - - /* Run it through the hoops (find a driver, etc) */ - if (!status) { - status = usb_new_device(udev); - if (status) { - spin_lock_irq(&device_state_lock); - hdev->children[port1-1] = NULL; - spin_unlock_irq(&device_state_lock); - } - } - - if (status) - goto loop_disable; - - status = hub_power_remaining(hub); - if (status) - dev_dbg(hub_dev, "%dmA power budget left\n", status); - - return; - -loop_disable: - hub_port_disable(hub, port1, 1); -loop: - usb_ep0_reinit(udev); - release_devnum(udev); - hub_free_dev(udev); - usb_put_dev(udev); - if ((status == -ENOTCONN) || (status == -ENOTSUPP)) - break; - } - if (hub->hdev->parent || - !hcd->driver->port_handed_over || - !(hcd->driver->port_handed_over)(hcd, port1)) - dev_err(hub_dev, "unable to enumerate USB device on port %d\n", - port1); - -done: - hub_port_disable(hub, port1, 1); - if (hcd->driver->relinquish_port && !hub->hdev->parent) - hcd->driver->relinquish_port(hcd, port1); -} - -/* Returns 1 if there was a remote wakeup and a connect status change. */ -static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, - u16 portstatus, u16 portchange) -{ - struct usb_device *hdev; - struct usb_device *udev; - int connect_change = 0; - int ret; - - hdev = hub->hdev; - udev = hdev->children[port-1]; - if (!hub_is_superspeed(hdev)) { - if (!(portchange & USB_PORT_STAT_C_SUSPEND)) - return 0; - clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND); - } else { - if (!udev || udev->state != USB_STATE_SUSPENDED || - (portstatus & USB_PORT_STAT_LINK_STATE) != - USB_SS_PORT_LS_U0) - return 0; - } - - if (udev) { - /* TRSMRCY = 10 msec */ - msleep(10); - - usb_lock_device(udev); - ret = usb_remote_wakeup(udev); - usb_unlock_device(udev); - if (ret < 0) - connect_change = 1; - } else { - ret = -ENODEV; - hub_port_disable(hub, port, 1); - } - dev_dbg(hub->intfdev, "resume on port %d, status %d\n", - port, ret); - return connect_change; -} - -static void hub_events(void) -{ - struct list_head *tmp; - struct usb_device *hdev; - struct usb_interface *intf; - struct usb_hub *hub; - struct device *hub_dev; - u16 hubstatus; - u16 hubchange; - u16 portstatus; - u16 portchange; - int i, ret,j = 0; - int connect_change, wakeup_change; - - /* - * We restart the list every time to avoid a deadlock with - * deleting hubs downstream from this one. This should be - * safe since we delete the hub from the event list. - * Not the most efficient, but avoids deadlocks. - */ - while (1) { - - /* Grab the first entry at the beginning of the list */ - spin_lock_irq(&hub_event_lock); - if (list_empty(&hub_event_list)) { - spin_unlock_irq(&hub_event_lock); - break; - } - - tmp = hub_event_list.next; - list_del_init(tmp); - - hub = list_entry(tmp, struct usb_hub, event_list); - kref_get(&hub->kref); - spin_unlock_irq(&hub_event_lock); - - hdev = hub->hdev; - hub_dev = hub->intfdev; - intf = to_usb_interface(hub_dev); - dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n", - hdev->state, hub->descriptor - ? hub->descriptor->bNbrPorts - : 0, - /* NOTE: expects max 15 ports... */ - (u16) hub->change_bits[0], - (u16) hub->event_bits[0]); - - /* Lock the device, then check to see if we were - * disconnected while waiting for the lock to succeed. */ - usb_lock_device(hdev); - if (unlikely(hub->disconnected)) - goto loop_disconnected; - - /* If the hub has died, clean up after it */ - if (hdev->state == USB_STATE_NOTATTACHED) { - hub->error = -ENODEV; - hub_quiesce(hub, HUB_DISCONNECT); - goto loop; - } - - /* Autoresume */ - ret = usb_autopm_get_interface(intf); - if (ret) { - dev_dbg(hub_dev, "Can't autoresume: %d\n", ret); - goto loop; - } - - /* If this is an inactive hub, do nothing */ - if (hub->quiescing) - goto loop_autopm; - - if (hub->error) { - dev_dbg (hub_dev, "resetting for error %d\n", - hub->error); - - ret = usb_reset_device(hdev); - if (ret) { - dev_dbg (hub_dev, - "error resetting hub: %d\n", ret); - goto loop_autopm; - } - - hub->nerrors = 0; - hub->error = 0; - } - - /* deal with other port status changes */ - - //for (i = 1; i <= hub->descriptor->bNbrPorts; i++) { - for (j = 1; j <= hub->descriptor->bNbrPorts; j++) { - i = j; - if (hub->descriptor->bNbrPorts > 2 ) { - if (usb_storage_id) - i = (j + usb_storage_id -2 ) % hub->descriptor->bNbrPorts + 1 ; - - }; - - - if (test_bit(i, hub->busy_bits)) - continue; - connect_change = test_bit(i, hub->change_bits); - wakeup_change = test_and_clear_bit(i, hub->wakeup_bits); - if (!test_and_clear_bit(i, hub->event_bits) && - !connect_change && !wakeup_change) - continue; - - ret = hub_port_status(hub, i, - &portstatus, &portchange); - if (ret < 0) - continue; - - if (portchange & USB_PORT_STAT_C_CONNECTION) { - clear_port_feature(hdev, i, - USB_PORT_FEAT_C_CONNECTION); - connect_change = 1; - } - - if (portchange & USB_PORT_STAT_C_ENABLE) { - if (!connect_change) - dev_dbg (hub_dev, - "port %d enable change, " - "status %08x\n", - i, portstatus); - clear_port_feature(hdev, i, - USB_PORT_FEAT_C_ENABLE); - - /* - * EM interference sometimes causes badly - * shielded USB devices to be shutdown by - * the hub, this hack enables them again. - * Works at least with mouse driver. - */ - if (!(portstatus & USB_PORT_STAT_ENABLE) - && !connect_change - && hdev->children[i-1]) { - dev_err (hub_dev, - "port %i " - "disabled by hub (EMI?), " - "re-enabling...\n", - i); - connect_change = 1; - } - } - - if (hub_handle_remote_wakeup(hub, i, - portstatus, portchange)) - connect_change = 1; - - if (portchange & USB_PORT_STAT_C_OVERCURRENT) { - u16 status = 0; - u16 unused; - - dev_dbg(hub_dev, "over-current change on port " - "%d\n", i); - clear_port_feature(hdev, i, - USB_PORT_FEAT_C_OVER_CURRENT); - msleep(100); /* Cool down */ - hub_power_on(hub, true); - hub_port_status(hub, i, &status, &unused); - if (status & USB_PORT_STAT_OVERCURRENT) - dev_err(hub_dev, "over-current " - "condition on port %d\n", i); - } - - if (portchange & USB_PORT_STAT_C_RESET) { - dev_dbg (hub_dev, - "reset change on port %d\n", - i); - clear_port_feature(hdev, i, - USB_PORT_FEAT_C_RESET); - } - if ((portchange & USB_PORT_STAT_C_BH_RESET) && - hub_is_superspeed(hub->hdev)) { - dev_dbg(hub_dev, - "warm reset change on port %d\n", - i); - clear_port_feature(hdev, i, - USB_PORT_FEAT_C_BH_PORT_RESET); - } - if (portchange & USB_PORT_STAT_C_LINK_STATE) { - clear_port_feature(hub->hdev, i, - USB_PORT_FEAT_C_PORT_LINK_STATE); - } - if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) { - dev_warn(hub_dev, - "config error on port %d\n", - i); - clear_port_feature(hub->hdev, i, - USB_PORT_FEAT_C_PORT_CONFIG_ERROR); - } - - /* Warm reset a USB3 protocol port if it's in - * SS.Inactive state. - */ - if (hub_port_warm_reset_required(hub, portstatus)) { - dev_dbg(hub_dev, "warm reset port %d\n", i); - hub_port_reset(hub, i, NULL, - HUB_BH_RESET_TIME, true); - } - - if (connect_change) - hub_port_connect_change(hub, i, - portstatus, portchange); - } /* end for i */ - - /* deal with hub status changes */ - if (test_and_clear_bit(0, hub->event_bits) == 0) - ; /* do nothing */ - else if (hub_hub_status(hub, &hubstatus, &hubchange) < 0) - dev_err (hub_dev, "get_hub_status failed\n"); - else { - if (hubchange & HUB_CHANGE_LOCAL_POWER) { - dev_dbg (hub_dev, "power change\n"); - clear_hub_feature(hdev, C_HUB_LOCAL_POWER); - if (hubstatus & HUB_STATUS_LOCAL_POWER) - /* FIXME: Is this always true? */ - hub->limited_power = 1; - else - hub->limited_power = 0; - } - if (hubchange & HUB_CHANGE_OVERCURRENT) { - u16 status = 0; - u16 unused; - - dev_dbg(hub_dev, "over-current change\n"); - clear_hub_feature(hdev, C_HUB_OVER_CURRENT); - msleep(500); /* Cool down */ - hub_power_on(hub, true); - hub_hub_status(hub, &status, &unused); - if (status & HUB_STATUS_OVERCURRENT) - dev_err(hub_dev, "over-current " - "condition\n"); - } - } - - loop_autopm: - /* Balance the usb_autopm_get_interface() above */ - usb_autopm_put_interface_no_suspend(intf); - loop: - /* Balance the usb_autopm_get_interface_no_resume() in - * kick_khubd() and allow autosuspend. - */ - usb_autopm_put_interface(intf); - loop_disconnected: - usb_unlock_device(hdev); - kref_put(&hub->kref, hub_release); - - } /* end while (1) */ -} - -static int hub_thread(void *__unused) -{ - /* khubd needs to be freezable to avoid intefering with USB-PERSIST - * port handover. Otherwise it might see that a full-speed device - * was gone before the EHCI controller had handed its port over to - * the companion full-speed controller. - */ - set_freezable(); - - do { - hub_events(); - wait_event_freezable(khubd_wait, - !list_empty(&hub_event_list) || - kthread_should_stop()); - } while (!kthread_should_stop() || !list_empty(&hub_event_list)); - - pr_debug("%s: khubd exiting\n", usbcore_name); - return 0; -} - -static const struct usb_device_id hub_id_table[] = { - { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS, - .bDeviceClass = USB_CLASS_HUB}, - { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, - .bInterfaceClass = USB_CLASS_HUB}, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, hub_id_table); - -static struct usb_driver hub_driver = { - .name = "hub", - .probe = hub_probe, - .disconnect = hub_disconnect, - .suspend = hub_suspend, - .resume = hub_resume, - .reset_resume = hub_reset_resume, - .pre_reset = hub_pre_reset, - .post_reset = hub_post_reset, - .unlocked_ioctl = hub_ioctl, - .id_table = hub_id_table, - .supports_autosuspend = 1, -}; - -int usb_hub_init(void) -{ - if (usb_register(&hub_driver) < 0) { - printk(KERN_ERR "%s: can't register hub driver\n", - usbcore_name); - return -1; - } - - khubd_task = kthread_run(hub_thread, NULL, "khubd"); - if (!IS_ERR(khubd_task)) - return 0; - - /* Fall through if kernel_thread failed */ - usb_deregister(&hub_driver); - printk(KERN_ERR "%s: can't start khubd\n", usbcore_name); - - return -1; -} - -void usb_hub_cleanup(void) -{ - kthread_stop(khubd_task); - - /* - * Hub resources are freed for us by usb_deregister. It calls - * usb_driver_purge on every device which in turn calls that - * devices disconnect function if it is using this driver. - * The hub_disconnect function takes care of releasing the - * individual hub resources. -greg - */ - usb_deregister(&hub_driver); -} /* usb_hub_cleanup() */ - -static int descriptors_changed(struct usb_device *udev, - struct usb_device_descriptor *old_device_descriptor) -{ - int changed = 0; - unsigned index; - unsigned serial_len = 0; - unsigned len; - unsigned old_length; - int length; - char *buf; - - if (memcmp(&udev->descriptor, old_device_descriptor, - sizeof(*old_device_descriptor)) != 0) - return 1; - - /* Since the idVendor, idProduct, and bcdDevice values in the - * device descriptor haven't changed, we will assume the - * Manufacturer and Product strings haven't changed either. - * But the SerialNumber string could be different (e.g., a - * different flash card of the same brand). - */ - if (udev->serial) - serial_len = strlen(udev->serial) + 1; - - len = serial_len; - for (index = 0; index < udev->descriptor.bNumConfigurations; index++) { - old_length = le16_to_cpu(udev->config[index].desc.wTotalLength); - len = max(len, old_length); - } - - buf = kmalloc(len, GFP_NOIO); - if (buf == NULL) { - dev_err(&udev->dev, "no mem to re-read configs after reset\n"); - /* assume the worst */ - return 1; - } - for (index = 0; index < udev->descriptor.bNumConfigurations; index++) { - old_length = le16_to_cpu(udev->config[index].desc.wTotalLength); - length = usb_get_descriptor(udev, USB_DT_CONFIG, index, buf, - old_length); - if (length != old_length) { - dev_dbg(&udev->dev, "config index %d, error %d\n", - index, length); - changed = 1; - break; - } - if (memcmp (buf, udev->rawdescriptors[index], old_length) - != 0) { - dev_dbg(&udev->dev, "config index %d changed (#%d)\n", - index, - ((struct usb_config_descriptor *) buf)-> - bConfigurationValue); - changed = 1; - break; - } - } - - if (!changed && serial_len) { - length = usb_string(udev, udev->descriptor.iSerialNumber, - buf, serial_len); - if (length + 1 != serial_len) { - dev_dbg(&udev->dev, "serial string error %d\n", - length); - changed = 1; - } else if (memcmp(buf, udev->serial, length) != 0) { - dev_dbg(&udev->dev, "serial string changed\n"); - changed = 1; - } - } - - kfree(buf); - return changed; -} - -/** - * usb_reset_and_verify_device - perform a USB port reset to reinitialize a device - * @udev: device to reset (not in SUSPENDED or NOTATTACHED state) - * - * WARNING - don't use this routine to reset a composite device - * (one with multiple interfaces owned by separate drivers)! - * Use usb_reset_device() instead. - * - * Do a port reset, reassign the device's address, and establish its - * former operating configuration. If the reset fails, or the device's - * descriptors change from their values before the reset, or the original - * configuration and altsettings cannot be restored, a flag will be set - * telling khubd to pretend the device has been disconnected and then - * re-connected. All drivers will be unbound, and the device will be - * re-enumerated and probed all over again. - * - * Returns 0 if the reset succeeded, -ENODEV if the device has been - * flagged for logical disconnection, or some other negative error code - * if the reset wasn't even attempted. - * - * The caller must own the device lock. For example, it's safe to use - * this from a driver probe() routine after downloading new firmware. - * For calls that might not occur during probe(), drivers should lock - * the device using usb_lock_device_for_reset(). - * - * Locking exception: This routine may also be called from within an - * autoresume handler. Such usage won't conflict with other tasks - * holding the device lock because these tasks should always call - * usb_autopm_resume_device(), thereby preventing any unwanted autoresume. - */ -static int usb_reset_and_verify_device(struct usb_device *udev) -{ - struct usb_device *parent_hdev = udev->parent; - struct usb_hub *parent_hub; - struct usb_hcd *hcd = bus_to_hcd(udev->bus); - struct usb_device_descriptor descriptor = udev->descriptor; - int i, ret = 0; - int port1 = udev->portnum; - - if (udev->state == USB_STATE_NOTATTACHED || - udev->state == USB_STATE_SUSPENDED) { - dev_dbg(&udev->dev, "device reset not allowed in state %d\n", - udev->state); - return -EINVAL; - } - - if (!parent_hdev) { - /* this requires hcd-specific logic; see ohci_restart() */ - dev_dbg(&udev->dev, "%s for root hub!\n", __func__); - return -EISDIR; - } - parent_hub = hdev_to_hub(parent_hdev); - - set_bit(port1, parent_hub->busy_bits); - for (i = 0; i < SET_CONFIG_TRIES; ++i) { - - /* ep0 maxpacket size may change; let the HCD know about it. - * Other endpoints will be handled by re-enumeration. */ - usb_ep0_reinit(udev); - ret = hub_port_init(parent_hub, udev, port1, i); - if (ret >= 0 || ret == -ENOTCONN || ret == -ENODEV) - break; - } - clear_bit(port1, parent_hub->busy_bits); - - if (ret < 0) - goto re_enumerate; - - /* Device might have changed firmware (DFU or similar) */ - if (descriptors_changed(udev, &descriptor)) { - dev_info(&udev->dev, "device firmware changed\n"); - udev->descriptor = descriptor; /* for disconnect() calls */ - goto re_enumerate; - } - - /* Restore the device's previous configuration */ - if (!udev->actconfig) - goto done; - - mutex_lock(hcd->bandwidth_mutex); - ret = usb_hcd_alloc_bandwidth(udev, udev->actconfig, NULL, NULL); - if (ret < 0) { - dev_warn(&udev->dev, - "Busted HC? Not enough HCD resources for " - "old configuration.\n"); - mutex_unlock(hcd->bandwidth_mutex); - goto re_enumerate; - } - ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - USB_REQ_SET_CONFIGURATION, 0, - udev->actconfig->desc.bConfigurationValue, 0, - NULL, 0, USB_CTRL_SET_TIMEOUT); - if (ret < 0) { - dev_err(&udev->dev, - "can't restore configuration #%d (error=%d)\n", - udev->actconfig->desc.bConfigurationValue, ret); - mutex_unlock(hcd->bandwidth_mutex); - goto re_enumerate; - } - mutex_unlock(hcd->bandwidth_mutex); - usb_set_device_state(udev, USB_STATE_CONFIGURED); - - /* Put interfaces back into the same altsettings as before. - * Don't bother to send the Set-Interface request for interfaces - * that were already in altsetting 0; besides being unnecessary, - * many devices can't handle it. Instead just reset the host-side - * endpoint state. - */ - for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { - struct usb_host_config *config = udev->actconfig; - struct usb_interface *intf = config->interface[i]; - struct usb_interface_descriptor *desc; - - desc = &intf->cur_altsetting->desc; - if (desc->bAlternateSetting == 0) { - usb_disable_interface(udev, intf, true); - usb_enable_interface(udev, intf, true); - ret = 0; - } else { - /* Let the bandwidth allocation function know that this - * device has been reset, and it will have to use - * alternate setting 0 as the current alternate setting. - */ - intf->resetting_device = 1; - ret = usb_set_interface(udev, desc->bInterfaceNumber, - desc->bAlternateSetting); - intf->resetting_device = 0; - } - if (ret < 0) { - dev_err(&udev->dev, "failed to restore interface %d " - "altsetting %d (error=%d)\n", - desc->bInterfaceNumber, - desc->bAlternateSetting, - ret); - goto re_enumerate; - } - } - -done: - return 0; - -re_enumerate: - hub_port_logical_disconnect(parent_hub, port1); - return -ENODEV; -} - -/** - * usb_reset_device - warn interface drivers and perform a USB port reset - * @udev: device to reset (not in SUSPENDED or NOTATTACHED state) - * - * Warns all drivers bound to registered interfaces (using their pre_reset - * method), performs the port reset, and then lets the drivers know that - * the reset is over (using their post_reset method). - * - * Return value is the same as for usb_reset_and_verify_device(). - * - * The caller must own the device lock. For example, it's safe to use - * this from a driver probe() routine after downloading new firmware. - * For calls that might not occur during probe(), drivers should lock - * the device using usb_lock_device_for_reset(). - * - * If an interface is currently being probed or disconnected, we assume - * its driver knows how to handle resets. For all other interfaces, - * if the driver doesn't have pre_reset and post_reset methods then - * we attempt to unbind it and rebind afterward. - */ -int usb_reset_device(struct usb_device *udev) -{ - int ret; - int i; - struct usb_host_config *config = udev->actconfig; - - if (udev->state == USB_STATE_NOTATTACHED || - udev->state == USB_STATE_SUSPENDED) { - dev_dbg(&udev->dev, "device reset not allowed in state %d\n", - udev->state); - return -EINVAL; - } - - /* Prevent autosuspend during the reset */ - usb_autoresume_device(udev); - - if (config) { - for (i = 0; i < config->desc.bNumInterfaces; ++i) { - struct usb_interface *cintf = config->interface[i]; - struct usb_driver *drv; - int unbind = 0; - - if (cintf->dev.driver) { - drv = to_usb_driver(cintf->dev.driver); - if (drv->pre_reset && drv->post_reset) - unbind = (drv->pre_reset)(cintf); - else if (cintf->condition == - USB_INTERFACE_BOUND) - unbind = 1; - if (unbind) - usb_forced_unbind_intf(cintf); - } - } - } - - ret = usb_reset_and_verify_device(udev); - - if (config) { - for (i = config->desc.bNumInterfaces - 1; i >= 0; --i) { - struct usb_interface *cintf = config->interface[i]; - struct usb_driver *drv; - int rebind = cintf->needs_binding; - - if (!rebind && cintf->dev.driver) { - drv = to_usb_driver(cintf->dev.driver); - if (drv->post_reset) - rebind = (drv->post_reset)(cintf); - else if (cintf->condition == - USB_INTERFACE_BOUND) - rebind = 1; - } - if (ret == 0 && rebind) - usb_rebind_intf(cintf); - } - } - - usb_autosuspend_device(udev); - return ret; -} -EXPORT_SYMBOL_GPL(usb_reset_device); - - -/** - * usb_queue_reset_device - Reset a USB device from an atomic context - * @iface: USB interface belonging to the device to reset - * - * This function can be used to reset a USB device from an atomic - * context, where usb_reset_device() won't work (as it blocks). - * - * Doing a reset via this method is functionally equivalent to calling - * usb_reset_device(), except for the fact that it is delayed to a - * workqueue. This means that any drivers bound to other interfaces - * might be unbound, as well as users from usbfs in user space. - * - * Corner cases: - * - * - Scheduling two resets at the same time from two different drivers - * attached to two different interfaces of the same device is - * possible; depending on how the driver attached to each interface - * handles ->pre_reset(), the second reset might happen or not. - * - * - If a driver is unbound and it had a pending reset, the reset will - * be cancelled. - * - * - This function can be called during .probe() or .disconnect() - * times. On return from .disconnect(), any pending resets will be - * cancelled. - * - * There is no no need to lock/unlock the @reset_ws as schedule_work() - * does its own. - * - * NOTE: We don't do any reference count tracking because it is not - * needed. The lifecycle of the work_struct is tied to the - * usb_interface. Before destroying the interface we cancel the - * work_struct, so the fact that work_struct is queued and or - * running means the interface (and thus, the device) exist and - * are referenced. - */ -void usb_queue_reset_device(struct usb_interface *iface) -{ - schedule_work(&iface->reset_ws); -} -EXPORT_SYMBOL_GPL(usb_queue_reset_device); diff --git a/ANDROID_3.4.5/drivers/usb/core/inode.c b/ANDROID_3.4.5/drivers/usb/core/inode.c deleted file mode 100644 index d2b9af59..00000000 --- a/ANDROID_3.4.5/drivers/usb/core/inode.c +++ /dev/null @@ -1,748 +0,0 @@ -/*****************************************************************************/ - -/* - * inode.c -- Inode/Dentry functions for the USB device file system. - * - * Copyright (C) 2000 Thomas Sailer (sailer@ife.ee.ethz.ch) - * Copyright (C) 2001,2002,2004 Greg Kroah-Hartman (greg@kroah.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * History: - * 0.1 04.01.2000 Created - * 0.2 10.12.2001 converted to use the vfs layer better - */ - -/*****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "usb.h" - -#define USBFS_DEFAULT_DEVMODE (S_IWUSR | S_IRUGO) -#define USBFS_DEFAULT_BUSMODE (S_IXUGO | S_IRUGO) -#define USBFS_DEFAULT_LISTMODE S_IRUGO - -static const struct file_operations default_file_operations; -static struct vfsmount *usbfs_mount; -static int usbfs_mount_count; /* = 0 */ - -static struct dentry *devices_usbfs_dentry; -static int num_buses; /* = 0 */ - -static uid_t devuid; /* = 0 */ -static uid_t busuid; /* = 0 */ -static uid_t listuid; /* = 0 */ -static gid_t devgid; /* = 0 */ -static gid_t busgid; /* = 0 */ -static gid_t listgid; /* = 0 */ -static umode_t devmode = USBFS_DEFAULT_DEVMODE; -static umode_t busmode = USBFS_DEFAULT_BUSMODE; -static umode_t listmode = USBFS_DEFAULT_LISTMODE; - -static int usbfs_show_options(struct seq_file *seq, struct dentry *root) -{ - if (devuid != 0) - seq_printf(seq, ",devuid=%u", devuid); - if (devgid != 0) - seq_printf(seq, ",devgid=%u", devgid); - if (devmode != USBFS_DEFAULT_DEVMODE) - seq_printf(seq, ",devmode=%o", devmode); - if (busuid != 0) - seq_printf(seq, ",busuid=%u", busuid); - if (busgid != 0) - seq_printf(seq, ",busgid=%u", busgid); - if (busmode != USBFS_DEFAULT_BUSMODE) - seq_printf(seq, ",busmode=%o", busmode); - if (listuid != 0) - seq_printf(seq, ",listuid=%u", listuid); - if (listgid != 0) - seq_printf(seq, ",listgid=%u", listgid); - if (listmode != USBFS_DEFAULT_LISTMODE) - seq_printf(seq, ",listmode=%o", listmode); - - return 0; -} - -enum { - Opt_devuid, Opt_devgid, Opt_devmode, - Opt_busuid, Opt_busgid, Opt_busmode, - Opt_listuid, Opt_listgid, Opt_listmode, - Opt_err, -}; - -static const match_table_t tokens = { - {Opt_devuid, "devuid=%u"}, - {Opt_devgid, "devgid=%u"}, - {Opt_devmode, "devmode=%o"}, - {Opt_busuid, "busuid=%u"}, - {Opt_busgid, "busgid=%u"}, - {Opt_busmode, "busmode=%o"}, - {Opt_listuid, "listuid=%u"}, - {Opt_listgid, "listgid=%u"}, - {Opt_listmode, "listmode=%o"}, - {Opt_err, NULL} -}; - -static int parse_options(struct super_block *s, char *data) -{ - char *p; - int option; - - /* (re)set to defaults. */ - devuid = 0; - busuid = 0; - listuid = 0; - devgid = 0; - busgid = 0; - listgid = 0; - devmode = USBFS_DEFAULT_DEVMODE; - busmode = USBFS_DEFAULT_BUSMODE; - listmode = USBFS_DEFAULT_LISTMODE; - - while ((p = strsep(&data, ",")) != NULL) { - substring_t args[MAX_OPT_ARGS]; - int token; - if (!*p) - continue; - - token = match_token(p, tokens, args); - switch (token) { - case Opt_devuid: - if (match_int(&args[0], &option)) - return -EINVAL; - devuid = option; - break; - case Opt_devgid: - if (match_int(&args[0], &option)) - return -EINVAL; - devgid = option; - break; - case Opt_devmode: - if (match_octal(&args[0], &option)) - return -EINVAL; - devmode = option & S_IRWXUGO; - break; - case Opt_busuid: - if (match_int(&args[0], &option)) - return -EINVAL; - busuid = option; - break; - case Opt_busgid: - if (match_int(&args[0], &option)) - return -EINVAL; - busgid = option; - break; - case Opt_busmode: - if (match_octal(&args[0], &option)) - return -EINVAL; - busmode = option & S_IRWXUGO; - break; - case Opt_listuid: - if (match_int(&args[0], &option)) - return -EINVAL; - listuid = option; - break; - case Opt_listgid: - if (match_int(&args[0], &option)) - return -EINVAL; - listgid = option; - break; - case Opt_listmode: - if (match_octal(&args[0], &option)) - return -EINVAL; - listmode = option & S_IRWXUGO; - break; - default: - printk(KERN_ERR "usbfs: unrecognised mount option " - "\"%s\" or missing value\n", p); - return -EINVAL; - } - } - - return 0; -} - -static void update_special(struct dentry *special) -{ - special->d_inode->i_uid = listuid; - special->d_inode->i_gid = listgid; - special->d_inode->i_mode = S_IFREG | listmode; -} - -static void update_dev(struct dentry *dev) -{ - dev->d_inode->i_uid = devuid; - dev->d_inode->i_gid = devgid; - dev->d_inode->i_mode = S_IFREG | devmode; -} - -static void update_bus(struct dentry *bus) -{ - struct dentry *dev = NULL; - - bus->d_inode->i_uid = busuid; - bus->d_inode->i_gid = busgid; - bus->d_inode->i_mode = S_IFDIR | busmode; - - mutex_lock(&bus->d_inode->i_mutex); - - list_for_each_entry(dev, &bus->d_subdirs, d_u.d_child) - if (dev->d_inode) - update_dev(dev); - - mutex_unlock(&bus->d_inode->i_mutex); -} - -static void update_sb(struct super_block *sb) -{ - struct dentry *root = sb->s_root; - struct dentry *bus = NULL; - - if (!root) - return; - - mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_PARENT); - - list_for_each_entry(bus, &root->d_subdirs, d_u.d_child) { - if (bus->d_inode) { - switch (S_IFMT & bus->d_inode->i_mode) { - case S_IFDIR: - update_bus(bus); - break; - case S_IFREG: - update_special(bus); - break; - default: - printk(KERN_WARNING "usbfs: Unknown node %s " - "mode %x found on remount!\n", - bus->d_name.name, bus->d_inode->i_mode); - break; - } - } - } - - mutex_unlock(&root->d_inode->i_mutex); -} - -static int remount(struct super_block *sb, int *flags, char *data) -{ - /* If this is not a real mount, - * i.e. it's a simple_pin_fs from create_special_files, - * then ignore it. - */ - if (*flags & MS_KERNMOUNT) - return 0; - - if (parse_options(sb, data)) { - printk(KERN_WARNING "usbfs: mount parameter error.\n"); - return -EINVAL; - } - - if (usbfs_mount) - update_sb(usbfs_mount->mnt_sb); - - return 0; -} - -static struct inode *usbfs_get_inode (struct super_block *sb, umode_t mode, dev_t dev) -{ - struct inode *inode = new_inode(sb); - - if (inode) { - inode->i_ino = get_next_ino(); - inode_init_owner(inode, NULL, mode); - inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - switch (mode & S_IFMT) { - default: - init_special_inode(inode, mode, dev); - break; - case S_IFREG: - inode->i_fop = &default_file_operations; - break; - case S_IFDIR: - inode->i_op = &simple_dir_inode_operations; - inode->i_fop = &simple_dir_operations; - - /* directory inodes start off with i_nlink == 2 (for "." entry) */ - inc_nlink(inode); - break; - } - } - return inode; -} - -/* SMP-safe */ -static int usbfs_mknod (struct inode *dir, struct dentry *dentry, umode_t mode, - dev_t dev) -{ - struct inode *inode = usbfs_get_inode(dir->i_sb, mode, dev); - int error = -EPERM; - - if (dentry->d_inode) - return -EEXIST; - - if (inode) { - d_instantiate(dentry, inode); - dget(dentry); - error = 0; - } - return error; -} - -static int usbfs_mkdir (struct inode *dir, struct dentry *dentry, umode_t mode) -{ - int res; - - mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR; - res = usbfs_mknod (dir, dentry, mode, 0); - if (!res) - inc_nlink(dir); - return res; -} - -static int usbfs_create (struct inode *dir, struct dentry *dentry, umode_t mode) -{ - mode = (mode & S_IALLUGO) | S_IFREG; - return usbfs_mknod (dir, dentry, mode, 0); -} - -static inline int usbfs_positive (struct dentry *dentry) -{ - return dentry->d_inode && !d_unhashed(dentry); -} - -static int usbfs_empty (struct dentry *dentry) -{ - struct list_head *list; - - spin_lock(&dentry->d_lock); - list_for_each(list, &dentry->d_subdirs) { - struct dentry *de = list_entry(list, struct dentry, d_u.d_child); - - spin_lock_nested(&de->d_lock, DENTRY_D_LOCK_NESTED); - if (usbfs_positive(de)) { - spin_unlock(&de->d_lock); - spin_unlock(&dentry->d_lock); - return 0; - } - spin_unlock(&de->d_lock); - } - spin_unlock(&dentry->d_lock); - return 1; -} - -static int usbfs_unlink (struct inode *dir, struct dentry *dentry) -{ - struct inode *inode = dentry->d_inode; - mutex_lock(&inode->i_mutex); - drop_nlink(dentry->d_inode); - dput(dentry); - mutex_unlock(&inode->i_mutex); - d_delete(dentry); - return 0; -} - -static int usbfs_rmdir(struct inode *dir, struct dentry *dentry) -{ - int error = -ENOTEMPTY; - struct inode * inode = dentry->d_inode; - - mutex_lock(&inode->i_mutex); - dentry_unhash(dentry); - if (usbfs_empty(dentry)) { - dont_mount(dentry); - drop_nlink(dentry->d_inode); - drop_nlink(dentry->d_inode); - dput(dentry); - inode->i_flags |= S_DEAD; - drop_nlink(dir); - error = 0; - } - mutex_unlock(&inode->i_mutex); - if (!error) - d_delete(dentry); - return error; -} - - -/* default file operations */ -static ssize_t default_read_file (struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - return 0; -} - -static ssize_t default_write_file (struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - return count; -} - -static loff_t default_file_lseek (struct file *file, loff_t offset, int orig) -{ - loff_t retval = -EINVAL; - - mutex_lock(&file->f_path.dentry->d_inode->i_mutex); - switch(orig) { - case 0: - if (offset > 0) { - file->f_pos = offset; - retval = file->f_pos; - } - break; - case 1: - if ((offset + file->f_pos) > 0) { - file->f_pos += offset; - retval = file->f_pos; - } - break; - default: - break; - } - mutex_unlock(&file->f_path.dentry->d_inode->i_mutex); - return retval; -} - -static const struct file_operations default_file_operations = { - .read = default_read_file, - .write = default_write_file, - .open = simple_open, - .llseek = default_file_lseek, -}; - -static const struct super_operations usbfs_ops = { - .statfs = simple_statfs, - .drop_inode = generic_delete_inode, - .remount_fs = remount, - .show_options = usbfs_show_options, -}; - -static int usbfs_fill_super(struct super_block *sb, void *data, int silent) -{ - struct inode *inode; - - sb->s_blocksize = PAGE_CACHE_SIZE; - sb->s_blocksize_bits = PAGE_CACHE_SHIFT; - sb->s_magic = USBDEVICE_SUPER_MAGIC; - sb->s_op = &usbfs_ops; - sb->s_time_gran = 1; - inode = usbfs_get_inode(sb, S_IFDIR | 0755, 0); - sb->s_root = d_make_root(inode); - if (!sb->s_root) { - dbg("%s: could not get root dentry!",__func__); - return -ENOMEM; - } - return 0; -} - -/* - * fs_create_by_name - create a file, given a name - * @name: name of file - * @mode: type of file - * @parent: dentry of directory to create it in - * @dentry: resulting dentry of file - * - * This function handles both regular files and directories. - */ -static int fs_create_by_name (const char *name, umode_t mode, - struct dentry *parent, struct dentry **dentry) -{ - int error = 0; - - /* If the parent is not specified, we create it in the root. - * We need the root dentry to do this, which is in the super - * block. A pointer to that is in the struct vfsmount that we - * have around. - */ - if (!parent ) { - if (usbfs_mount) - parent = usbfs_mount->mnt_root; - } - - if (!parent) { - dbg("Ah! can not find a parent!"); - return -EFAULT; - } - - *dentry = NULL; - mutex_lock(&parent->d_inode->i_mutex); - *dentry = lookup_one_len(name, parent, strlen(name)); - if (!IS_ERR(*dentry)) { - if (S_ISDIR(mode)) - error = usbfs_mkdir (parent->d_inode, *dentry, mode); - else - error = usbfs_create (parent->d_inode, *dentry, mode); - } else - error = PTR_ERR(*dentry); - mutex_unlock(&parent->d_inode->i_mutex); - - return error; -} - -static struct dentry *fs_create_file (const char *name, umode_t mode, - struct dentry *parent, void *data, - const struct file_operations *fops, - uid_t uid, gid_t gid) -{ - struct dentry *dentry; - int error; - - dbg("creating file '%s'",name); - - error = fs_create_by_name (name, mode, parent, &dentry); - if (error) { - dentry = NULL; - } else { - if (dentry->d_inode) { - if (data) - dentry->d_inode->i_private = data; - if (fops) - dentry->d_inode->i_fop = fops; - dentry->d_inode->i_uid = uid; - dentry->d_inode->i_gid = gid; - } - } - - return dentry; -} - -static void fs_remove_file (struct dentry *dentry) -{ - struct dentry *parent = dentry->d_parent; - - if (!parent || !parent->d_inode) - return; - - mutex_lock_nested(&parent->d_inode->i_mutex, I_MUTEX_PARENT); - if (usbfs_positive(dentry)) { - if (dentry->d_inode) { - if (S_ISDIR(dentry->d_inode->i_mode)) - usbfs_rmdir(parent->d_inode, dentry); - else - usbfs_unlink(parent->d_inode, dentry); - dput(dentry); - } - } - mutex_unlock(&parent->d_inode->i_mutex); -} - -/* --------------------------------------------------------------------- */ - -static struct dentry *usb_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - return mount_single(fs_type, flags, data, usbfs_fill_super); -} - -static struct file_system_type usb_fs_type = { - .owner = THIS_MODULE, - .name = "usbfs", - .mount = usb_mount, - .kill_sb = kill_litter_super, -}; - -/* --------------------------------------------------------------------- */ - -static int create_special_files (void) -{ - struct dentry *parent; - int retval; - - /* create the devices special file */ - retval = simple_pin_fs(&usb_fs_type, &usbfs_mount, &usbfs_mount_count); - if (retval) { - printk(KERN_ERR "Unable to get usbfs mount\n"); - goto exit; - } - - parent = usbfs_mount->mnt_root; - devices_usbfs_dentry = fs_create_file ("devices", - listmode | S_IFREG, parent, - NULL, &usbfs_devices_fops, - listuid, listgid); - if (devices_usbfs_dentry == NULL) { - printk(KERN_ERR "Unable to create devices usbfs file\n"); - retval = -ENODEV; - goto error_clean_mounts; - } - - goto exit; - -error_clean_mounts: - simple_release_fs(&usbfs_mount, &usbfs_mount_count); -exit: - return retval; -} - -static void remove_special_files (void) -{ - if (devices_usbfs_dentry) - fs_remove_file (devices_usbfs_dentry); - devices_usbfs_dentry = NULL; - simple_release_fs(&usbfs_mount, &usbfs_mount_count); -} - -void usbfs_update_special (void) -{ - struct inode *inode; - - if (devices_usbfs_dentry) { - inode = devices_usbfs_dentry->d_inode; - if (inode) - inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - } -} - -static void usbfs_add_bus(struct usb_bus *bus) -{ - struct dentry *parent; - char name[8]; - int retval; - - /* create the special files if this is the first bus added */ - if (num_buses == 0) { - retval = create_special_files(); - if (retval) - return; - } - ++num_buses; - - sprintf (name, "%03d", bus->busnum); - - parent = usbfs_mount->mnt_root; - bus->usbfs_dentry = fs_create_file (name, busmode | S_IFDIR, parent, - bus, NULL, busuid, busgid); - if (bus->usbfs_dentry == NULL) { - printk(KERN_ERR "Error creating usbfs bus entry\n"); - return; - } -} - -static void usbfs_remove_bus(struct usb_bus *bus) -{ - if (bus->usbfs_dentry) { - fs_remove_file (bus->usbfs_dentry); - bus->usbfs_dentry = NULL; - } - - --num_buses; - if (num_buses <= 0) { - remove_special_files(); - num_buses = 0; - } -} - -static void usbfs_add_device(struct usb_device *dev) -{ - char name[8]; - int i; - int i_size; - - sprintf (name, "%03d", dev->devnum); - dev->usbfs_dentry = fs_create_file (name, devmode | S_IFREG, - dev->bus->usbfs_dentry, dev, - &usbdev_file_operations, - devuid, devgid); - if (dev->usbfs_dentry == NULL) { - printk(KERN_ERR "Error creating usbfs device entry\n"); - return; - } - - /* Set the size of the device's file to be - * equal to the size of the device descriptors. */ - i_size = sizeof (struct usb_device_descriptor); - for (i = 0; i < dev->descriptor.bNumConfigurations; ++i) { - struct usb_config_descriptor *config = - (struct usb_config_descriptor *)dev->rawdescriptors[i]; - i_size += le16_to_cpu(config->wTotalLength); - } - if (dev->usbfs_dentry->d_inode) - dev->usbfs_dentry->d_inode->i_size = i_size; -} - -static void usbfs_remove_device(struct usb_device *dev) -{ - if (dev->usbfs_dentry) { - fs_remove_file (dev->usbfs_dentry); - dev->usbfs_dentry = NULL; - } -} - -static int usbfs_notify(struct notifier_block *self, unsigned long action, void *dev) -{ - switch (action) { - case USB_DEVICE_ADD: - usbfs_add_device(dev); - break; - case USB_DEVICE_REMOVE: - usbfs_remove_device(dev); - break; - case USB_BUS_ADD: - usbfs_add_bus(dev); - break; - case USB_BUS_REMOVE: - usbfs_remove_bus(dev); - } - - usbfs_update_special(); - usbfs_conn_disc_event(); - return NOTIFY_OK; -} - -static struct notifier_block usbfs_nb = { - .notifier_call = usbfs_notify, -}; - -/* --------------------------------------------------------------------- */ - -static struct proc_dir_entry *usbdir = NULL; - -int __init usbfs_init(void) -{ - int retval; - - retval = register_filesystem(&usb_fs_type); - if (retval) - return retval; - - usb_register_notify(&usbfs_nb); - - /* create mount point for usbfs */ - usbdir = proc_mkdir("bus/usb", NULL); - - return 0; -} - -void usbfs_cleanup(void) -{ - usb_unregister_notify(&usbfs_nb); - unregister_filesystem(&usb_fs_type); - if (usbdir) - remove_proc_entry("bus/usb", NULL); -} - diff --git a/ANDROID_3.4.5/drivers/usb/core/message.c b/ANDROID_3.4.5/drivers/usb/core/message.c deleted file mode 100644 index ef116a55..00000000 --- a/ANDROID_3.4.5/drivers/usb/core/message.c +++ /dev/null @@ -1,1952 +0,0 @@ -/* - * message.c - synchronous message handling - */ - -#include /* for scatterlist macros */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for usbcore internals */ -#include - -#include "usb.h" - -static void cancel_async_set_config(struct usb_device *udev); - -struct api_context { - struct completion done; - int status; -}; - -static void usb_api_blocking_completion(struct urb *urb) -{ - struct api_context *ctx = urb->context; - - ctx->status = urb->status; - complete(&ctx->done); -} - - -/* - * Starts urb and waits for completion or timeout. Note that this call - * is NOT interruptible. Many device driver i/o requests should be - * interruptible and therefore these drivers should implement their - * own interruptible routines. - */ -static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length) -{ - struct api_context ctx; - unsigned long expire; - int retval; - - init_completion(&ctx.done); - urb->context = &ctx; - urb->actual_length = 0; - retval = usb_submit_urb(urb, GFP_NOIO); - if (unlikely(retval)) - goto out; - - expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT; - if (!wait_for_completion_timeout(&ctx.done, expire)) { - usb_kill_urb(urb); - retval = (ctx.status == -ENOENT ? -ETIMEDOUT : ctx.status); - - dev_dbg(&urb->dev->dev, - "%s timed out on ep%d%s len=%u/%u\n", - current->comm, - usb_endpoint_num(&urb->ep->desc), - usb_urb_dir_in(urb) ? "in" : "out", - urb->actual_length, - urb->transfer_buffer_length); - } else - retval = ctx.status; -out: - if (actual_length) - *actual_length = urb->actual_length; - - usb_free_urb(urb); - return retval; -} - -/*-------------------------------------------------------------------*/ -/* returns status (negative) or length (positive) */ -static int usb_internal_control_msg(struct usb_device *usb_dev, - unsigned int pipe, - struct usb_ctrlrequest *cmd, - void *data, int len, int timeout) -{ - struct urb *urb; - int retv; - int length; - - urb = usb_alloc_urb(0, GFP_NOIO); - if (!urb) - return -ENOMEM; - - usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data, - len, usb_api_blocking_completion, NULL); - - retv = usb_start_wait_urb(urb, timeout, &length); - if (retv < 0) - return retv; - else - return length; -} - -/** - * usb_control_msg - Builds a control urb, sends it off and waits for completion - * @dev: pointer to the usb device to send the message to - * @pipe: endpoint "pipe" to send the message to - * @request: USB message request value - * @requesttype: USB message request type value - * @value: USB message value - * @index: USB message index value - * @data: pointer to the data to send - * @size: length in bytes of the data to send - * @timeout: time in msecs to wait for the message to complete before timing - * out (if 0 the wait is forever) - * - * Context: !in_interrupt () - * - * This function sends a simple control message to a specified endpoint and - * waits for the message to complete, or timeout. - * - * If successful, it returns the number of bytes transferred, otherwise a - * negative error number. - * - * Don't use this function from within an interrupt context, like a bottom half - * handler. If you need an asynchronous message, or need to send a message - * from within interrupt context, use usb_submit_urb(). - * If a thread in your driver uses this call, make sure your disconnect() - * method can wait for it to complete. Since you don't have a handle on the - * URB used, you can't cancel the request. - */ -int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, - __u8 requesttype, __u16 value, __u16 index, void *data, - __u16 size, int timeout) -{ - struct usb_ctrlrequest *dr; - int ret; - - dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO); - if (!dr) - return -ENOMEM; - - dr->bRequestType = requesttype; - dr->bRequest = request; - dr->wValue = cpu_to_le16(value); - dr->wIndex = cpu_to_le16(index); - dr->wLength = cpu_to_le16(size); - - /* dbg("usb_control_msg"); */ - - ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout); - - kfree(dr); - - return ret; -} -EXPORT_SYMBOL_GPL(usb_control_msg); - -/** - * usb_interrupt_msg - Builds an interrupt urb, sends it off and waits for completion - * @usb_dev: pointer to the usb device to send the message to - * @pipe: endpoint "pipe" to send the message to - * @data: pointer to the data to send - * @len: length in bytes of the data to send - * @actual_length: pointer to a location to put the actual length transferred - * in bytes - * @timeout: time in msecs to wait for the message to complete before - * timing out (if 0 the wait is forever) - * - * Context: !in_interrupt () - * - * This function sends a simple interrupt message to a specified endpoint and - * waits for the message to complete, or timeout. - * - * If successful, it returns 0, otherwise a negative error number. The number - * of actual bytes transferred will be stored in the actual_length paramater. - * - * Don't use this function from within an interrupt context, like a bottom half - * handler. If you need an asynchronous message, or need to send a message - * from within interrupt context, use usb_submit_urb() If a thread in your - * driver uses this call, make sure your disconnect() method can wait for it to - * complete. Since you don't have a handle on the URB used, you can't cancel - * the request. - */ -int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe, - void *data, int len, int *actual_length, int timeout) -{ - return usb_bulk_msg(usb_dev, pipe, data, len, actual_length, timeout); -} -EXPORT_SYMBOL_GPL(usb_interrupt_msg); - -/** - * usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion - * @usb_dev: pointer to the usb device to send the message to - * @pipe: endpoint "pipe" to send the message to - * @data: pointer to the data to send - * @len: length in bytes of the data to send - * @actual_length: pointer to a location to put the actual length transferred - * in bytes - * @timeout: time in msecs to wait for the message to complete before - * timing out (if 0 the wait is forever) - * - * Context: !in_interrupt () - * - * This function sends a simple bulk message to a specified endpoint - * and waits for the message to complete, or timeout. - * - * If successful, it returns 0, otherwise a negative error number. The number - * of actual bytes transferred will be stored in the actual_length paramater. - * - * Don't use this function from within an interrupt context, like a bottom half - * handler. If you need an asynchronous message, or need to send a message - * from within interrupt context, use usb_submit_urb() If a thread in your - * driver uses this call, make sure your disconnect() method can wait for it to - * complete. Since you don't have a handle on the URB used, you can't cancel - * the request. - * - * Because there is no usb_interrupt_msg() and no USBDEVFS_INTERRUPT ioctl, - * users are forced to abuse this routine by using it to submit URBs for - * interrupt endpoints. We will take the liberty of creating an interrupt URB - * (with the default interval) if the target is an interrupt endpoint. - */ -int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, - void *data, int len, int *actual_length, int timeout) -{ - struct urb *urb; - struct usb_host_endpoint *ep; - - ep = usb_pipe_endpoint(usb_dev, pipe); - if (!ep || len < 0) - return -EINVAL; - - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return -ENOMEM; - - if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_INT) { - pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30); - usb_fill_int_urb(urb, usb_dev, pipe, data, len, - usb_api_blocking_completion, NULL, - ep->desc.bInterval); - } else - usb_fill_bulk_urb(urb, usb_dev, pipe, data, len, - usb_api_blocking_completion, NULL); - - return usb_start_wait_urb(urb, timeout, actual_length); -} -EXPORT_SYMBOL_GPL(usb_bulk_msg); - -/*-------------------------------------------------------------------*/ - -static void sg_clean(struct usb_sg_request *io) -{ - if (io->urbs) { - while (io->entries--) - usb_free_urb(io->urbs [io->entries]); - kfree(io->urbs); - io->urbs = NULL; - } - io->dev = NULL; -} - -static void sg_complete(struct urb *urb) -{ - struct usb_sg_request *io = urb->context; - int status = urb->status; - - spin_lock(&io->lock); - - /* In 2.5 we require hcds' endpoint queues not to progress after fault - * reports, until the completion callback (this!) returns. That lets - * device driver code (like this routine) unlink queued urbs first, - * if it needs to, since the HC won't work on them at all. So it's - * not possible for page N+1 to overwrite page N, and so on. - * - * That's only for "hard" faults; "soft" faults (unlinks) sometimes - * complete before the HCD can get requests away from hardware, - * though never during cleanup after a hard fault. - */ - if (io->status - && (io->status != -ECONNRESET - || status != -ECONNRESET) - && urb->actual_length) { - dev_err(io->dev->bus->controller, - "dev %s ep%d%s scatterlist error %d/%d\n", - io->dev->devpath, - usb_endpoint_num(&urb->ep->desc), - usb_urb_dir_in(urb) ? "in" : "out", - status, io->status); - /* BUG (); */ - } - - if (io->status == 0 && status && status != -ECONNRESET) { - int i, found, retval; - - io->status = status; - - /* the previous urbs, and this one, completed already. - * unlink pending urbs so they won't rx/tx bad data. - * careful: unlink can sometimes be synchronous... - */ - spin_unlock(&io->lock); - for (i = 0, found = 0; i < io->entries; i++) { - if (!io->urbs [i] || !io->urbs [i]->dev) - continue; - if (found) { - retval = usb_unlink_urb(io->urbs [i]); - if (retval != -EINPROGRESS && - retval != -ENODEV && - retval != -EBUSY && - retval != -EIDRM) - dev_err(&io->dev->dev, - "%s, unlink --> %d\n", - __func__, retval); - } else if (urb == io->urbs [i]) - found = 1; - } - spin_lock(&io->lock); - } - - /* on the last completion, signal usb_sg_wait() */ - io->bytes += urb->actual_length; - io->count--; - if (!io->count) - complete(&io->complete); - - spin_unlock(&io->lock); -} - - -/** - * usb_sg_init - initializes scatterlist-based bulk/interrupt I/O request - * @io: request block being initialized. until usb_sg_wait() returns, - * treat this as a pointer to an opaque block of memory, - * @dev: the usb device that will send or receive the data - * @pipe: endpoint "pipe" used to transfer the data - * @period: polling rate for interrupt endpoints, in frames or - * (for high speed endpoints) microframes; ignored for bulk - * @sg: scatterlist entries - * @nents: how many entries in the scatterlist - * @length: how many bytes to send from the scatterlist, or zero to - * send every byte identified in the list. - * @mem_flags: SLAB_* flags affecting memory allocations in this call - * - * Returns zero for success, else a negative errno value. This initializes a - * scatter/gather request, allocating resources such as I/O mappings and urb - * memory (except maybe memory used by USB controller drivers). - * - * The request must be issued using usb_sg_wait(), which waits for the I/O to - * complete (or to be canceled) and then cleans up all resources allocated by - * usb_sg_init(). - * - * The request may be canceled with usb_sg_cancel(), either before or after - * usb_sg_wait() is called. - */ -int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev, - unsigned pipe, unsigned period, struct scatterlist *sg, - int nents, size_t length, gfp_t mem_flags) -{ - int i; - int urb_flags; - int use_sg; - - if (!io || !dev || !sg - || usb_pipecontrol(pipe) - || usb_pipeisoc(pipe) - || nents <= 0) - return -EINVAL; - - spin_lock_init(&io->lock); - io->dev = dev; - io->pipe = pipe; - - if (dev->bus->sg_tablesize > 0) { - use_sg = true; - io->entries = 1; - } else { - use_sg = false; - io->entries = nents; - } - - /* initialize all the urbs we'll use */ - io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags); - if (!io->urbs) - goto nomem; - - urb_flags = URB_NO_INTERRUPT; - if (usb_pipein(pipe)) - urb_flags |= URB_SHORT_NOT_OK; - - for_each_sg(sg, sg, io->entries, i) { - struct urb *urb; - unsigned len; - - urb = usb_alloc_urb(0, mem_flags); - if (!urb) { - io->entries = i; - goto nomem; - } - io->urbs[i] = urb; - - urb->dev = NULL; - urb->pipe = pipe; - urb->interval = period; - urb->transfer_flags = urb_flags; - urb->complete = sg_complete; - urb->context = io; - urb->sg = sg; - - if (use_sg) { - /* There is no single transfer buffer */ - urb->transfer_buffer = NULL; - urb->num_sgs = nents; - - /* A length of zero means transfer the whole sg list */ - len = length; - if (len == 0) { - struct scatterlist *sg2; - int j; - - for_each_sg(sg, sg2, nents, j) - len += sg2->length; - } - } else { - /* - * Some systems can't use DMA; they use PIO instead. - * For their sakes, transfer_buffer is set whenever - * possible. - */ - if (!PageHighMem(sg_page(sg))) - urb->transfer_buffer = sg_virt(sg); - else - urb->transfer_buffer = NULL; - - len = sg->length; - if (length) { - len = min_t(size_t, len, length); - length -= len; - if (length == 0) - io->entries = i + 1; - } - } - urb->transfer_buffer_length = len; - } - io->urbs[--i]->transfer_flags &= ~URB_NO_INTERRUPT; - - /* transaction state */ - io->count = io->entries; - io->status = 0; - io->bytes = 0; - init_completion(&io->complete); - return 0; - -nomem: - sg_clean(io); - return -ENOMEM; -} -EXPORT_SYMBOL_GPL(usb_sg_init); - -/** - * usb_sg_wait - synchronously execute scatter/gather request - * @io: request block handle, as initialized with usb_sg_init(). - * some fields become accessible when this call returns. - * Context: !in_interrupt () - * - * This function blocks until the specified I/O operation completes. It - * leverages the grouping of the related I/O requests to get good transfer - * rates, by queueing the requests. At higher speeds, such queuing can - * significantly improve USB throughput. - * - * There are three kinds of completion for this function. - * (1) success, where io->status is zero. The number of io->bytes - * transferred is as requested. - * (2) error, where io->status is a negative errno value. The number - * of io->bytes transferred before the error is usually less - * than requested, and can be nonzero. - * (3) cancellation, a type of error with status -ECONNRESET that - * is initiated by usb_sg_cancel(). - * - * When this function returns, all memory allocated through usb_sg_init() or - * this call will have been freed. The request block parameter may still be - * passed to usb_sg_cancel(), or it may be freed. It could also be - * reinitialized and then reused. - * - * Data Transfer Rates: - * - * Bulk transfers are valid for full or high speed endpoints. - * The best full speed data rate is 19 packets of 64 bytes each - * per frame, or 1216 bytes per millisecond. - * The best high speed data rate is 13 packets of 512 bytes each - * per microframe, or 52 KBytes per millisecond. - * - * The reason to use interrupt transfers through this API would most likely - * be to reserve high speed bandwidth, where up to 24 KBytes per millisecond - * 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) -{ - int i; - int entries = io->entries; - - /* queue the urbs. */ - spin_lock_irq(&io->lock); - i = 0; - while (i < entries && !io->status) { - int retval; - - io->urbs[i]->dev = io->dev; - retval = usb_submit_urb(io->urbs [i], GFP_ATOMIC); - - /* after we submit, let completions or cancelations fire; - * we handshake using io->status. - */ - spin_unlock_irq(&io->lock); - switch (retval) { - /* maybe we retrying will recover */ - case -ENXIO: /* hc didn't queue this one */ - case -EAGAIN: - case -ENOMEM: - retval = 0; - yield(); - break; - - /* no error? continue immediately. - * - * NOTE: to work better with UHCI (4K I/O buffer may - * need 3K of TDs) it may be good to limit how many - * URBs are queued at once; N milliseconds? - */ - case 0: - ++i; - cpu_relax(); - break; - - /* fail any uncompleted urbs */ - default: - io->urbs[i]->status = retval; - dev_dbg(&io->dev->dev, "%s, submit --> %d\n", - __func__, retval); - usb_sg_cancel(io); - } - spin_lock_irq(&io->lock); - if (retval && (io->status == 0 || io->status == -ECONNRESET)) - io->status = retval; - } - io->count -= entries - i; - if (io->count == 0) - complete(&io->complete); - spin_unlock_irq(&io->lock); - - /* OK, yes, this could be packaged as non-blocking. - * So could the submit loop above ... but it's easier to - * solve neither problem than to solve both! - */ - wait_for_completion(&io->complete); - - sg_clean(io); -} -EXPORT_SYMBOL_GPL(usb_sg_wait); - -/** - * usb_sg_cancel - stop scatter/gather i/o issued by usb_sg_wait() - * @io: request block, initialized with usb_sg_init() - * - * This stops a request after it has been started by usb_sg_wait(). - * It can also prevents one initialized by usb_sg_init() from starting, - * so that call just frees resources allocated to the request. - */ -void usb_sg_cancel(struct usb_sg_request *io) -{ - unsigned long flags; - - spin_lock_irqsave(&io->lock, flags); - - /* shut everything down, if it didn't already */ - if (!io->status) { - int i; - - io->status = -ECONNRESET; - spin_unlock(&io->lock); - for (i = 0; i < io->entries; i++) { - int retval; - - if (!io->urbs [i]->dev) - continue; - retval = usb_unlink_urb(io->urbs [i]); - if (retval != -EINPROGRESS - && retval != -ENODEV - && retval != -EBUSY - && retval != -EIDRM) - dev_warn(&io->dev->dev, "%s, unlink --> %d\n", - __func__, retval); - } - spin_lock(&io->lock); - } - spin_unlock_irqrestore(&io->lock, flags); -} -EXPORT_SYMBOL_GPL(usb_sg_cancel); - -/*-------------------------------------------------------------------*/ - -/** - * usb_get_descriptor - issues a generic GET_DESCRIPTOR request - * @dev: the device whose descriptor is being retrieved - * @type: the descriptor type (USB_DT_*) - * @index: the number of the descriptor - * @buf: where to put the descriptor - * @size: how big is "buf"? - * Context: !in_interrupt () - * - * Gets a USB descriptor. Convenience functions exist to simplify - * getting some types of descriptors. Use - * usb_get_string() or usb_string() for USB_DT_STRING. - * Device (USB_DT_DEVICE) and configuration descriptors (USB_DT_CONFIG) - * are part of the device structure. - * In addition to a number of USB-standard descriptors, some - * devices also use class-specific or vendor-specific descriptors. - * - * This call is synchronous, and may not be used in an interrupt context. - * - * Returns the number of bytes received on success, or else the status code - * returned by the underlying usb_control_msg() call. - */ -int usb_get_descriptor(struct usb_device *dev, unsigned char type, - unsigned char index, void *buf, int size) -{ - int i; - int result; - - memset(buf, 0, size); /* Make sure we parse really received data */ - - for (i = 0; i < 3; ++i) { - /* retry on length 0 or error; some devices are flakey */ - result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, - (type << 8) + index, 0, buf, size, - USB_CTRL_GET_TIMEOUT); - if (result <= 0 && result != -ETIMEDOUT) - continue; - if (result > 1 && ((u8 *)buf)[1] != type) { - result = -ENODATA; - continue; - } - break; - } - return result; -} -EXPORT_SYMBOL_GPL(usb_get_descriptor); - -/** - * usb_get_string - gets a string descriptor - * @dev: the device whose string descriptor is being retrieved - * @langid: code for language chosen (from string descriptor zero) - * @index: the number of the descriptor - * @buf: where to put the string - * @size: how big is "buf"? - * Context: !in_interrupt () - * - * Retrieves a string, encoded using UTF-16LE (Unicode, 16 bits per character, - * in little-endian byte order). - * The usb_string() function will often be a convenient way to turn - * these strings into kernel-printable form. - * - * Strings may be referenced in device, configuration, interface, or other - * descriptors, and could also be used in vendor-specific ways. - * - * This call is synchronous, and may not be used in an interrupt context. - * - * Returns the number of bytes received on success, or else the status code - * returned by the underlying usb_control_msg() call. - */ -static int usb_get_string(struct usb_device *dev, unsigned short langid, - unsigned char index, void *buf, int size) -{ - int i; - int result; - - for (i = 0; i < 3; ++i) { - /* retry on length 0 or stall; some devices are flakey */ - result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, - (USB_DT_STRING << 8) + index, langid, buf, size, - USB_CTRL_GET_TIMEOUT); - if (result == 0 || result == -EPIPE) - continue; - if (result > 1 && ((u8 *) buf)[1] != USB_DT_STRING) { - result = -ENODATA; - continue; - } - break; - } - return result; -} - -static void usb_try_string_workarounds(unsigned char *buf, int *length) -{ - int newlength, oldlength = *length; - - for (newlength = 2; newlength + 1 < oldlength; newlength += 2) - if (!isprint(buf[newlength]) || buf[newlength + 1]) - break; - - if (newlength > 2) { - buf[0] = newlength; - *length = newlength; - } -} - -static int usb_string_sub(struct usb_device *dev, unsigned int langid, - unsigned int index, unsigned char *buf) -{ - int rc; - - /* Try to read the string descriptor by asking for the maximum - * possible number of bytes */ - if (dev->quirks & USB_QUIRK_STRING_FETCH_255) - rc = -EIO; - else - rc = usb_get_string(dev, langid, index, buf, 255); - - /* If that failed try to read the descriptor length, then - * ask for just that many bytes */ - if (rc < 2) { - rc = usb_get_string(dev, langid, index, buf, 2); - if (rc == 2) - rc = usb_get_string(dev, langid, index, buf, buf[0]); - } - - if (rc >= 2) { - if (!buf[0] && !buf[1]) - usb_try_string_workarounds(buf, &rc); - - /* There might be extra junk at the end of the descriptor */ - if (buf[0] < rc) - rc = buf[0]; - - rc = rc - (rc & 1); /* force a multiple of two */ - } - - if (rc < 2) - rc = (rc < 0 ? rc : -EINVAL); - - return rc; -} - -static int usb_get_langid(struct usb_device *dev, unsigned char *tbuf) -{ - int err; - - if (dev->have_langid) - return 0; - - if (dev->string_langid < 0) - return -EPIPE; - - err = usb_string_sub(dev, 0, 0, tbuf); - - /* If the string was reported but is malformed, default to english - * (0x0409) */ - if (err == -ENODATA || (err > 0 && err < 4)) { - dev->string_langid = 0x0409; - dev->have_langid = 1; - dev_err(&dev->dev, - "string descriptor 0 malformed (err = %d), " - "defaulting to 0x%04x\n", - err, dev->string_langid); - return 0; - } - - /* In case of all other errors, we assume the device is not able to - * deal with strings at all. Set string_langid to -1 in order to - * prevent any string to be retrieved from the device */ - if (err < 0) { - dev_err(&dev->dev, "string descriptor 0 read error: %d\n", - err); - dev->string_langid = -1; - return -EPIPE; - } - - /* always use the first langid listed */ - dev->string_langid = tbuf[2] | (tbuf[3] << 8); - dev->have_langid = 1; - dev_dbg(&dev->dev, "default language 0x%04x\n", - dev->string_langid); - return 0; -} - -/** - * 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 - * @size: how big is "buf"? - * Context: !in_interrupt () - * - * This converts the UTF-16LE encoded strings returned by devices, from - * 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. - * - * 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). - */ -int usb_string(struct usb_device *dev, int index, char *buf, size_t size) -{ - unsigned char *tbuf; - int err; - - if (dev->state == USB_STATE_SUSPENDED) - return -EHOSTUNREACH; - if (size <= 0 || !buf || !index) - return -EINVAL; - buf[0] = 0; - tbuf = kmalloc(256, GFP_NOIO); - if (!tbuf) - return -ENOMEM; - - err = usb_get_langid(dev, tbuf); - if (err < 0) - goto errout; - - err = usb_string_sub(dev, dev->string_langid, index, tbuf); - if (err < 0) - goto errout; - - size--; /* leave room for trailing NULL char in output buffer */ - 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, - "wrong descriptor type %02x for string %d (\"%s\")\n", - tbuf[1], index, buf); - - errout: - kfree(tbuf); - return err; -} -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 - * @index: the descriptor index - * - * Returns a pointer to a kmalloc'ed buffer containing the descriptor string, - * or NULL if the index is 0 or the string could not be read. - */ -char *usb_cache_string(struct usb_device *udev, int index) -{ - char *buf; - char *smallbuf = NULL; - int len; - - if (index <= 0) - return NULL; - - buf = kmalloc(MAX_USB_STRING_SIZE, GFP_NOIO); - if (buf) { - len = usb_string(udev, index, buf, MAX_USB_STRING_SIZE); - if (len > 0) { - smallbuf = kmalloc(++len, GFP_NOIO); - if (!smallbuf) - return buf; - memcpy(smallbuf, buf, len); - } - kfree(buf); - } - return smallbuf; -} - -/* - * usb_get_device_descriptor - (re)reads the device descriptor (usbcore) - * @dev: the device whose device descriptor is being updated - * @size: how much of the descriptor to read - * Context: !in_interrupt () - * - * Updates the copy of the device descriptor stored in the device structure, - * which dedicates space for this purpose. - * - * Not exported, only for use by the core. If drivers really want to read - * the device descriptor directly, they can call usb_get_descriptor() with - * type = USB_DT_DEVICE and index = 0. - * - * This call is synchronous, and may not be used in an interrupt context. - * - * Returns the number of bytes received on success, or else the status code - * returned by the underlying usb_control_msg() call. - */ -int usb_get_device_descriptor(struct usb_device *dev, unsigned int size) -{ - struct usb_device_descriptor *desc; - int ret; - - if (size > sizeof(*desc)) - return -EINVAL; - desc = kmalloc(sizeof(*desc), GFP_NOIO); - if (!desc) - return -ENOMEM; - - ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, size); - if (ret >= 0) - memcpy(&dev->descriptor, desc, size); - kfree(desc); - return ret; -} - -/** - * usb_get_status - issues a GET_STATUS call - * @dev: the device whose status is being checked - * @type: USB_RECIP_*; for device, interface, or endpoint - * @target: zero (for device), else interface or endpoint number - * @data: pointer to two bytes of bitmap data - * Context: !in_interrupt () - * - * Returns device, interface, or endpoint status. Normally only of - * interest to see if the device is self powered, or has enabled the - * remote wakeup facility; or whether a bulk or interrupt endpoint - * is halted ("stalled"). - * - * Bits in these status bitmaps are set using the SET_FEATURE request, - * and cleared using the CLEAR_FEATURE request. The usb_clear_halt() - * function should be used to clear halt ("stall") status. - * - * This call is synchronous, and may not be used in an interrupt context. - * - * Returns the number of bytes received on success, or else the status code - * returned by the underlying usb_control_msg() call. - */ -int usb_get_status(struct usb_device *dev, int type, int target, void *data) -{ - int ret; - u16 *status = kmalloc(sizeof(*status), GFP_KERNEL); - - if (!status) - return -ENOMEM; - - ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, status, - sizeof(*status), USB_CTRL_GET_TIMEOUT); - - *(u16 *)data = *status; - kfree(status); - return ret; -} -EXPORT_SYMBOL_GPL(usb_get_status); - -/** - * usb_clear_halt - tells device to clear endpoint halt/stall condition - * @dev: device whose endpoint is halted - * @pipe: endpoint "pipe" being cleared - * Context: !in_interrupt () - * - * This is used to clear halt conditions for bulk and interrupt endpoints, - * as reported by URB completion status. Endpoints that are halted are - * sometimes referred to as being "stalled". Such endpoints are unable - * to transmit or receive data until the halt status is cleared. Any URBs - * queued for such an endpoint should normally be unlinked by the driver - * before clearing the halt condition, as described in sections 5.7.5 - * and 5.8.5 of the USB 2.0 spec. - * - * Note that control and isochronous endpoints don't halt, although control - * endpoints report "protocol stall" (for unsupported requests) using the - * same status code used to report a true stall. - * - * This call is synchronous, and may not be used in an interrupt context. - * - * Returns zero on success, or else the status code returned by the - * underlying usb_control_msg() call. - */ -int usb_clear_halt(struct usb_device *dev, int pipe) -{ - int result; - int endp = usb_pipeendpoint(pipe); - - if (usb_pipein(pipe)) - endp |= USB_DIR_IN; - - /* we don't care if it wasn't halted first. in fact some devices - * (like some ibmcam model 1 units) seem to expect hosts to make - * this request for iso endpoints, which can't halt! - */ - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, - USB_ENDPOINT_HALT, endp, NULL, 0, - USB_CTRL_SET_TIMEOUT); - - /* don't un-halt or force to DATA0 except on success */ - if (result < 0) - return result; - - /* NOTE: seems like Microsoft and Apple don't bother verifying - * the clear "took", so some devices could lock up if you check... - * such as the Hagiwara FlashGate DUAL. So we won't bother. - * - * NOTE: make sure the logic here doesn't diverge much from - * the copy in usb-storage, for as long as we need two copies. - */ - - usb_reset_endpoint(dev, endp); - - return 0; -} -EXPORT_SYMBOL_GPL(usb_clear_halt); - -static int create_intf_ep_devs(struct usb_interface *intf) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct usb_host_interface *alt = intf->cur_altsetting; - int i; - - if (intf->ep_devs_created || intf->unregistering) - return 0; - - for (i = 0; i < alt->desc.bNumEndpoints; ++i) - (void) usb_create_ep_devs(&intf->dev, &alt->endpoint[i], udev); - intf->ep_devs_created = 1; - return 0; -} - -static void remove_intf_ep_devs(struct usb_interface *intf) -{ - struct usb_host_interface *alt = intf->cur_altsetting; - int i; - - if (!intf->ep_devs_created) - return; - - for (i = 0; i < alt->desc.bNumEndpoints; ++i) - usb_remove_ep_devs(&alt->endpoint[i]); - intf->ep_devs_created = 0; -} - -/** - * usb_disable_endpoint -- Disable an endpoint by address - * @dev: the device whose endpoint is being disabled - * @epaddr: the endpoint's address. Endpoint number for output, - * endpoint number + USB_DIR_IN for input - * @reset_hardware: flag to erase any endpoint state stored in the - * controller hardware - * - * Disables the endpoint for URB submission and nukes all pending URBs. - * If @reset_hardware is set then also deallocates hcd/hardware state - * for the endpoint. - */ -void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr, - bool reset_hardware) -{ - unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK; - struct usb_host_endpoint *ep; - - if (!dev) - return; - - if (usb_endpoint_out(epaddr)) { - ep = dev->ep_out[epnum]; - if (reset_hardware) - dev->ep_out[epnum] = NULL; - } else { - ep = dev->ep_in[epnum]; - if (reset_hardware) - dev->ep_in[epnum] = NULL; - } - if (ep) { - ep->enabled = 0; - usb_hcd_flush_endpoint(dev, ep); - if (reset_hardware) - usb_hcd_disable_endpoint(dev, ep); - } -} - -/** - * usb_reset_endpoint - Reset an endpoint's state. - * @dev: the device whose endpoint is to be reset - * @epaddr: the endpoint's address. Endpoint number for output, - * endpoint number + USB_DIR_IN for input - * - * Resets any host-side endpoint state such as the toggle bit, - * sequence number or current window. - */ -void usb_reset_endpoint(struct usb_device *dev, unsigned int epaddr) -{ - unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK; - struct usb_host_endpoint *ep; - - if (usb_endpoint_out(epaddr)) - ep = dev->ep_out[epnum]; - else - ep = dev->ep_in[epnum]; - if (ep) - usb_hcd_reset_endpoint(dev, ep); -} -EXPORT_SYMBOL_GPL(usb_reset_endpoint); - - -/** - * usb_disable_interface -- Disable all endpoints for an interface - * @dev: the device whose interface is being disabled - * @intf: pointer to the interface descriptor - * @reset_hardware: flag to erase any endpoint state stored in the - * controller hardware - * - * Disables all the endpoints for the interface's current altsetting. - */ -void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf, - bool reset_hardware) -{ - struct usb_host_interface *alt = intf->cur_altsetting; - int i; - - for (i = 0; i < alt->desc.bNumEndpoints; ++i) { - usb_disable_endpoint(dev, - alt->endpoint[i].desc.bEndpointAddress, - reset_hardware); - } -} - -/** - * usb_disable_device - Disable all the endpoints for a USB device - * @dev: the device whose endpoints are being disabled - * @skip_ep0: 0 to disable endpoint 0, 1 to skip it. - * - * Disables all the device's endpoints, potentially including endpoint 0. - * Deallocates hcd/hardware state for the endpoints (nuking all or most - * pending urbs) and usbcore state for the interfaces, so that usbcore - * must usb_set_configuration() before any interfaces could be used. - */ -void usb_disable_device(struct usb_device *dev, int skip_ep0) -{ - int i; - struct usb_hcd *hcd = bus_to_hcd(dev->bus); - - /* getting rid of interfaces will disconnect - * any drivers bound to them (a key side effect) - */ - if (dev->actconfig) { - /* - * FIXME: In order to avoid self-deadlock involving the - * bandwidth_mutex, we have to mark all the interfaces - * before unregistering any of them. - */ - for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) - dev->actconfig->interface[i]->unregistering = 1; - - for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { - struct usb_interface *interface; - - /* remove this interface if it has been registered */ - interface = dev->actconfig->interface[i]; - if (!device_is_registered(&interface->dev)) - continue; - dev_dbg(&dev->dev, "unregistering interface %s\n", - dev_name(&interface->dev)); - remove_intf_ep_devs(interface); - device_del(&interface->dev); - } - - /* Now that the interfaces are unbound, nobody should - * try to access them. - */ - for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) { - put_device(&dev->actconfig->interface[i]->dev); - dev->actconfig->interface[i] = NULL; - } - dev->actconfig = NULL; - if (dev->state == USB_STATE_CONFIGURED) - usb_set_device_state(dev, USB_STATE_ADDRESS); - } - - dev_dbg(&dev->dev, "%s nuking %s URBs\n", __func__, - skip_ep0 ? "non-ep0" : "all"); - if (hcd->driver->check_bandwidth) { - /* First pass: Cancel URBs, leave endpoint pointers intact. */ - for (i = skip_ep0; i < 16; ++i) { - usb_disable_endpoint(dev, i, false); - usb_disable_endpoint(dev, i + USB_DIR_IN, false); - } - /* Remove endpoints from the host controller internal state */ - mutex_lock(hcd->bandwidth_mutex); - usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL); - mutex_unlock(hcd->bandwidth_mutex); - /* Second pass: remove endpoint pointers */ - } - for (i = skip_ep0; i < 16; ++i) { - usb_disable_endpoint(dev, i, true); - usb_disable_endpoint(dev, i + USB_DIR_IN, true); - } -} - -/** - * usb_enable_endpoint - Enable an endpoint for USB communications - * @dev: the device whose interface is being enabled - * @ep: the endpoint - * @reset_ep: flag to reset the endpoint state - * - * Resets the endpoint state if asked, and sets dev->ep_{in,out} pointers. - * For control endpoints, both the input and output sides are handled. - */ -void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep, - bool reset_ep) -{ - int epnum = usb_endpoint_num(&ep->desc); - int is_out = usb_endpoint_dir_out(&ep->desc); - int is_control = usb_endpoint_xfer_control(&ep->desc); - - if (reset_ep) - usb_hcd_reset_endpoint(dev, ep); - if (is_out || is_control) - dev->ep_out[epnum] = ep; - if (!is_out || is_control) - dev->ep_in[epnum] = ep; - ep->enabled = 1; -} - -/** - * usb_enable_interface - Enable all the endpoints for an interface - * @dev: the device whose interface is being enabled - * @intf: pointer to the interface descriptor - * @reset_eps: flag to reset the endpoints' state - * - * Enables all the endpoints for the interface's current altsetting. - */ -void usb_enable_interface(struct usb_device *dev, - struct usb_interface *intf, bool reset_eps) -{ - struct usb_host_interface *alt = intf->cur_altsetting; - int i; - - for (i = 0; i < alt->desc.bNumEndpoints; ++i) - usb_enable_endpoint(dev, &alt->endpoint[i], reset_eps); -} - -/** - * usb_set_interface - Makes a particular alternate setting be current - * @dev: the device whose interface is being updated - * @interface: the interface being updated - * @alternate: the setting being chosen. - * Context: !in_interrupt () - * - * This is used to enable data transfers on interfaces that may not - * be enabled by default. Not all devices support such configurability. - * Only the driver bound to an interface may change its setting. - * - * Within any given configuration, each interface may have several - * alternative settings. These are often used to control levels of - * bandwidth consumption. For example, the default setting for a high - * speed interrupt endpoint may not send more than 64 bytes per microframe, - * while interrupt transfers of up to 3KBytes per microframe are legal. - * Also, isochronous endpoints may never be part of an - * interface's default setting. To access such bandwidth, alternate - * interface settings must be made current. - * - * Note that in the Linux USB subsystem, bandwidth associated with - * an endpoint in a given alternate setting is not reserved until an URB - * is submitted that needs that bandwidth. Some other operating systems - * allocate bandwidth early, when a configuration is chosen. - * - * This call is synchronous, and may not be used in an interrupt context. - * Also, drivers must not change altsettings while urbs are scheduled for - * endpoints in that interface; all such urbs must first be completed - * (perhaps forced by unlinking). - * - * Returns zero on success, or else the status code returned by the - * underlying usb_control_msg() call. - */ -int usb_set_interface(struct usb_device *dev, int interface, int alternate) -{ - struct usb_interface *iface; - struct usb_host_interface *alt; - struct usb_hcd *hcd = bus_to_hcd(dev->bus); - int ret; - int manual = 0; - unsigned int epaddr; - unsigned int pipe; - - if (dev->state == USB_STATE_SUSPENDED) - return -EHOSTUNREACH; - - iface = usb_ifnum_to_if(dev, interface); - if (!iface) { - dev_dbg(&dev->dev, "selecting invalid interface %d\n", - interface); - return -EINVAL; - } - if (iface->unregistering) - return -ENODEV; - - alt = usb_altnum_to_altsetting(iface, alternate); - if (!alt) { - dev_warn(&dev->dev, "selecting invalid altsetting %d\n", - alternate); - return -EINVAL; - } - - /* Make sure we have enough bandwidth for this alternate interface. - * Remove the current alt setting and add the new alt setting. - */ - mutex_lock(hcd->bandwidth_mutex); - ret = usb_hcd_alloc_bandwidth(dev, NULL, iface->cur_altsetting, alt); - if (ret < 0) { - dev_info(&dev->dev, "Not enough bandwidth for altsetting %d\n", - alternate); - mutex_unlock(hcd->bandwidth_mutex); - return ret; - } - - if (dev->quirks & USB_QUIRK_NO_SET_INTF) - ret = -EPIPE; - else - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, - alternate, interface, NULL, 0, 5000); - - /* 9.4.10 says devices don't need this and are free to STALL the - * request if the interface only has one alternate setting. - */ - if (ret == -EPIPE && iface->num_altsetting == 1) { - dev_dbg(&dev->dev, - "manual set_interface for iface %d, alt %d\n", - interface, alternate); - manual = 1; - } else if (ret < 0) { - /* Re-instate the old alt setting */ - usb_hcd_alloc_bandwidth(dev, NULL, alt, iface->cur_altsetting); - mutex_unlock(hcd->bandwidth_mutex); - return ret; - } - mutex_unlock(hcd->bandwidth_mutex); - - /* FIXME drivers shouldn't need to replicate/bugfix the logic here - * when they implement async or easily-killable versions of this or - * other "should-be-internal" functions (like clear_halt). - * should hcd+usbcore postprocess control requests? - */ - - /* prevent submissions using previous endpoint settings */ - if (iface->cur_altsetting != alt) { - remove_intf_ep_devs(iface); - usb_remove_sysfs_intf_files(iface); - } - usb_disable_interface(dev, iface, true); - - iface->cur_altsetting = alt; - - /* If the interface only has one altsetting and the device didn't - * accept the request, we attempt to carry out the equivalent action - * by manually clearing the HALT feature for each endpoint in the - * new altsetting. - */ - if (manual) { - int i; - - for (i = 0; i < alt->desc.bNumEndpoints; i++) { - epaddr = alt->endpoint[i].desc.bEndpointAddress; - pipe = __create_pipe(dev, - USB_ENDPOINT_NUMBER_MASK & epaddr) | - (usb_endpoint_out(epaddr) ? - USB_DIR_OUT : USB_DIR_IN); - - usb_clear_halt(dev, pipe); - } - } - - /* 9.1.1.5: reset toggles for all endpoints in the new altsetting - * - * Note: - * Despite EP0 is always present in all interfaces/AS, the list of - * endpoints from the descriptor does not contain EP0. Due to its - * omnipresence one might expect EP0 being considered "affected" by - * any SetInterface request and hence assume toggles need to be reset. - * However, EP0 toggles are re-synced for every individual transfer - * during the SETUP stage - hence EP0 toggles are "don't care" here. - * (Likewise, EP0 never "halts" on well designed devices.) - */ - usb_enable_interface(dev, iface, true); - if (device_is_registered(&iface->dev)) { - usb_create_sysfs_intf_files(iface); - create_intf_ep_devs(iface); - } - return 0; -} -EXPORT_SYMBOL_GPL(usb_set_interface); - -/** - * usb_reset_configuration - lightweight device reset - * @dev: the device whose configuration is being reset - * - * This issues a standard SET_CONFIGURATION request to the device using - * the current configuration. The effect is to reset most USB-related - * state in the device, including interface altsettings (reset to zero), - * endpoint halts (cleared), and endpoint state (only for bulk and interrupt - * endpoints). Other usbcore state is unchanged, including bindings of - * usb device drivers to interfaces. - * - * Because this affects multiple interfaces, avoid using this with composite - * (multi-interface) devices. Instead, the driver for each interface may - * use usb_set_interface() on the interfaces it claims. Be careful though; - * some devices don't support the SET_INTERFACE request, and others won't - * reset all the interface state (notably endpoint state). Resetting the whole - * configuration would affect other drivers' interfaces. - * - * The caller must own the device lock. - * - * Returns zero on success, else a negative error code. - */ -int usb_reset_configuration(struct usb_device *dev) -{ - int i, retval; - struct usb_host_config *config; - struct usb_hcd *hcd = bus_to_hcd(dev->bus); - - if (dev->state == USB_STATE_SUSPENDED) - return -EHOSTUNREACH; - - /* caller must have locked the device and must own - * the usb bus readlock (so driver bindings are stable); - * calls during probe() are fine - */ - - for (i = 1; i < 16; ++i) { - usb_disable_endpoint(dev, i, true); - usb_disable_endpoint(dev, i + USB_DIR_IN, true); - } - - config = dev->actconfig; - retval = 0; - mutex_lock(hcd->bandwidth_mutex); - /* Make sure we have enough bandwidth for each alternate setting 0 */ - for (i = 0; i < config->desc.bNumInterfaces; i++) { - struct usb_interface *intf = config->interface[i]; - struct usb_host_interface *alt; - - alt = usb_altnum_to_altsetting(intf, 0); - if (!alt) - alt = &intf->altsetting[0]; - if (alt != intf->cur_altsetting) - retval = usb_hcd_alloc_bandwidth(dev, NULL, - intf->cur_altsetting, alt); - if (retval < 0) - break; - } - /* If not, reinstate the old alternate settings */ - if (retval < 0) { -reset_old_alts: - for (i--; i >= 0; i--) { - struct usb_interface *intf = config->interface[i]; - struct usb_host_interface *alt; - - alt = usb_altnum_to_altsetting(intf, 0); - if (!alt) - alt = &intf->altsetting[0]; - if (alt != intf->cur_altsetting) - usb_hcd_alloc_bandwidth(dev, NULL, - alt, intf->cur_altsetting); - } - mutex_unlock(hcd->bandwidth_mutex); - return retval; - } - retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_SET_CONFIGURATION, 0, - config->desc.bConfigurationValue, 0, - NULL, 0, USB_CTRL_SET_TIMEOUT); - if (retval < 0) - goto reset_old_alts; - mutex_unlock(hcd->bandwidth_mutex); - - /* re-init hc/hcd interface/endpoint state */ - for (i = 0; i < config->desc.bNumInterfaces; i++) { - struct usb_interface *intf = config->interface[i]; - struct usb_host_interface *alt; - - alt = usb_altnum_to_altsetting(intf, 0); - - /* No altsetting 0? We'll assume the first altsetting. - * We could use a GetInterface call, but if a device is - * so non-compliant that it doesn't have altsetting 0 - * then I wouldn't trust its reply anyway. - */ - if (!alt) - alt = &intf->altsetting[0]; - - if (alt != intf->cur_altsetting) { - remove_intf_ep_devs(intf); - usb_remove_sysfs_intf_files(intf); - } - intf->cur_altsetting = alt; - usb_enable_interface(dev, intf, true); - if (device_is_registered(&intf->dev)) { - usb_create_sysfs_intf_files(intf); - create_intf_ep_devs(intf); - } - } - return 0; -} -EXPORT_SYMBOL_GPL(usb_reset_configuration); - -static void usb_release_interface(struct device *dev) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct usb_interface_cache *intfc = - altsetting_to_usb_interface_cache(intf->altsetting); - - kref_put(&intfc->ref, usb_release_interface_cache); - kfree(intf); -} - -#ifdef CONFIG_HOTPLUG -static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - struct usb_device *usb_dev; - struct usb_interface *intf; - struct usb_host_interface *alt; - - intf = to_usb_interface(dev); - usb_dev = interface_to_usbdev(intf); - alt = intf->cur_altsetting; - - if (add_uevent_var(env, "INTERFACE=%d/%d/%d", - alt->desc.bInterfaceClass, - alt->desc.bInterfaceSubClass, - alt->desc.bInterfaceProtocol)) - return -ENOMEM; - - if (add_uevent_var(env, - "MODALIAS=usb:" - "v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", - le16_to_cpu(usb_dev->descriptor.idVendor), - le16_to_cpu(usb_dev->descriptor.idProduct), - le16_to_cpu(usb_dev->descriptor.bcdDevice), - usb_dev->descriptor.bDeviceClass, - usb_dev->descriptor.bDeviceSubClass, - usb_dev->descriptor.bDeviceProtocol, - alt->desc.bInterfaceClass, - alt->desc.bInterfaceSubClass, - alt->desc.bInterfaceProtocol)) - return -ENOMEM; - - return 0; -} - -#else - -static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - return -ENODEV; -} -#endif /* CONFIG_HOTPLUG */ - -struct device_type usb_if_device_type = { - .name = "usb_interface", - .release = usb_release_interface, - .uevent = usb_if_uevent, -}; - -static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev, - struct usb_host_config *config, - u8 inum) -{ - struct usb_interface_assoc_descriptor *retval = NULL; - struct usb_interface_assoc_descriptor *intf_assoc; - int first_intf; - int last_intf; - int i; - - for (i = 0; (i < USB_MAXIADS && config->intf_assoc[i]); i++) { - intf_assoc = config->intf_assoc[i]; - if (intf_assoc->bInterfaceCount == 0) - continue; - - first_intf = intf_assoc->bFirstInterface; - last_intf = first_intf + (intf_assoc->bInterfaceCount - 1); - if (inum >= first_intf && inum <= last_intf) { - if (!retval) - retval = intf_assoc; - else - dev_err(&dev->dev, "Interface #%d referenced" - " by multiple IADs\n", inum); - } - } - - return retval; -} - - -/* - * Internal function to queue a device reset - * - * This is initialized into the workstruct in 'struct - * usb_device->reset_ws' that is launched by - * message.c:usb_set_configuration() when initializing each 'struct - * usb_interface'. - * - * It is safe to get the USB device without reference counts because - * the life cycle of @iface is bound to the life cycle of @udev. Then, - * this function will be ran only if @iface is alive (and before - * freeing it any scheduled instances of it will have been cancelled). - * - * We need to set a flag (usb_dev->reset_running) because when we call - * the reset, the interfaces might be unbound. The current interface - * cannot try to remove the queued work as it would cause a deadlock - * (you cannot remove your work from within your executing - * workqueue). This flag lets it know, so that - * usb_cancel_queued_reset() doesn't try to do it. - * - * See usb_queue_reset_device() for more details - */ -static void __usb_queue_reset_device(struct work_struct *ws) -{ - int rc; - struct usb_interface *iface = - container_of(ws, struct usb_interface, reset_ws); - struct usb_device *udev = interface_to_usbdev(iface); - - rc = usb_lock_device_for_reset(udev, iface); - if (rc >= 0) { - iface->reset_running = 1; - usb_reset_device(udev); - iface->reset_running = 0; - usb_unlock_device(udev); - } -} - - -/* - * usb_set_configuration - Makes a particular device setting be current - * @dev: the device whose configuration is being updated - * @configuration: the configuration being chosen. - * Context: !in_interrupt(), caller owns the device lock - * - * This is used to enable non-default device modes. Not all devices - * use this kind of configurability; many devices only have one - * configuration. - * - * @configuration is the value of the configuration to be installed. - * According to the USB spec (e.g. section 9.1.1.5), configuration values - * must be non-zero; a value of zero indicates that the device in - * unconfigured. However some devices erroneously use 0 as one of their - * configuration values. To help manage such devices, this routine will - * accept @configuration = -1 as indicating the device should be put in - * an unconfigured state. - * - * USB device configurations may affect Linux interoperability, - * power consumption and the functionality available. For example, - * the default configuration is limited to using 100mA of bus power, - * so that when certain device functionality requires more power, - * and the device is bus powered, that functionality should be in some - * non-default device configuration. Other device modes may also be - * reflected as configuration options, such as whether two ISDN - * channels are available independently; and choosing between open - * standard device protocols (like CDC) or proprietary ones. - * - * Note that a non-authorized device (dev->authorized == 0) will only - * be put in unconfigured mode. - * - * Note that USB has an additional level of device configurability, - * associated with interfaces. That configurability is accessed using - * usb_set_interface(). - * - * This call is synchronous. The calling context must be able to sleep, - * must own the device lock, and must not hold the driver model's USB - * bus mutex; usb interface driver probe() methods cannot use this routine. - * - * Returns zero on success, or else the status code returned by the - * underlying call that failed. On successful completion, each interface - * in the original device configuration has been destroyed, and each one - * in the new configuration has been probed by all relevant usb device - * drivers currently known to the kernel. - */ -int usb_set_configuration(struct usb_device *dev, int configuration) -{ - int i, ret; - struct usb_host_config *cp = NULL; - struct usb_interface **new_interfaces = NULL; - struct usb_hcd *hcd = bus_to_hcd(dev->bus); - int n, nintf; - - if (dev->authorized == 0 || configuration == -1) - configuration = 0; - else { - for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { - if (dev->config[i].desc.bConfigurationValue == - configuration) { - cp = &dev->config[i]; - break; - } - } - } - if ((!cp && configuration != 0)) - return -EINVAL; - - /* The USB spec says configuration 0 means unconfigured. - * But if a device includes a configuration numbered 0, - * we will accept it as a correctly configured state. - * Use -1 if you really want to unconfigure the device. - */ - if (cp && configuration == 0) - dev_warn(&dev->dev, "config 0 descriptor??\n"); - - /* Allocate memory for new interfaces before doing anything else, - * so that if we run out then nothing will have changed. */ - n = nintf = 0; - if (cp) { - nintf = cp->desc.bNumInterfaces; - new_interfaces = kmalloc(nintf * sizeof(*new_interfaces), - GFP_NOIO); - if (!new_interfaces) { - dev_err(&dev->dev, "Out of memory\n"); - return -ENOMEM; - } - - for (; n < nintf; ++n) { - new_interfaces[n] = kzalloc( - sizeof(struct usb_interface), - GFP_NOIO); - if (!new_interfaces[n]) { - dev_err(&dev->dev, "Out of memory\n"); - ret = -ENOMEM; -free_interfaces: - while (--n >= 0) - kfree(new_interfaces[n]); - kfree(new_interfaces); - return ret; - } - } - - i = dev->bus_mA - cp->desc.bMaxPower * 2; - if (i < 0) - dev_warn(&dev->dev, "new config #%d exceeds power " - "limit by %dmA\n", - configuration, -i); - } - - /* Wake up the device so we can send it the Set-Config request */ - ret = usb_autoresume_device(dev); - if (ret) - goto free_interfaces; - - /* if it's already configured, clear out old state first. - * getting rid of old interfaces means unbinding their drivers. - */ - if (dev->state != USB_STATE_ADDRESS) - usb_disable_device(dev, 1); /* Skip ep0 */ - - /* Get rid of pending async Set-Config requests for this device */ - cancel_async_set_config(dev); - - /* 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. - */ - mutex_lock(hcd->bandwidth_mutex); - ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL); - if (ret < 0) { - mutex_unlock(hcd->bandwidth_mutex); - usb_autosuspend_device(dev); - goto free_interfaces; - } - - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_SET_CONFIGURATION, 0, configuration, 0, - NULL, 0, USB_CTRL_SET_TIMEOUT); - if (ret < 0) { - /* All the old state is gone, so what else can we do? - * The device is probably useless now anyway. - */ - cp = NULL; - } - - dev->actconfig = cp; - if (!cp) { - usb_set_device_state(dev, USB_STATE_ADDRESS); - usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL); - mutex_unlock(hcd->bandwidth_mutex); - usb_autosuspend_device(dev); - goto free_interfaces; - } - mutex_unlock(hcd->bandwidth_mutex); - usb_set_device_state(dev, USB_STATE_CONFIGURED); - - /* Initialize the new interface structures and the - * hc/hcd/usbcore interface/endpoint state. - */ - for (i = 0; i < nintf; ++i) { - struct usb_interface_cache *intfc; - struct usb_interface *intf; - struct usb_host_interface *alt; - - cp->interface[i] = intf = new_interfaces[i]; - intfc = cp->intf_cache[i]; - intf->altsetting = intfc->altsetting; - intf->num_altsetting = intfc->num_altsetting; - kref_get(&intfc->ref); - - alt = usb_altnum_to_altsetting(intf, 0); - - /* No altsetting 0? We'll assume the first altsetting. - * We could use a GetInterface call, but if a device is - * so non-compliant that it doesn't have altsetting 0 - * then I wouldn't trust its reply anyway. - */ - if (!alt) - alt = &intf->altsetting[0]; - - intf->intf_assoc = - find_iad(dev, cp, alt->desc.bInterfaceNumber); - intf->cur_altsetting = alt; - usb_enable_interface(dev, intf, true); - intf->dev.parent = &dev->dev; - intf->dev.driver = NULL; - intf->dev.bus = &usb_bus_type; - intf->dev.type = &usb_if_device_type; - intf->dev.groups = usb_interface_groups; - intf->dev.dma_mask = dev->dev.dma_mask; - INIT_WORK(&intf->reset_ws, __usb_queue_reset_device); - intf->minor = -1; - device_initialize(&intf->dev); - pm_runtime_no_callbacks(&intf->dev); - dev_set_name(&intf->dev, "%d-%s:%d.%d", - dev->bus->busnum, dev->devpath, - configuration, alt->desc.bInterfaceNumber); - } - kfree(new_interfaces); - - if (cp->string == NULL && - !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS)) - cp->string = usb_cache_string(dev, cp->desc.iConfiguration); - - /* Now that all the interfaces are set up, register them - * to trigger binding of drivers to interfaces. probe() - * routines may install different altsettings and may - * claim() any interfaces not yet bound. Many class drivers - * need that: CDC, audio, video, etc. - */ - for (i = 0; i < nintf; ++i) { - struct usb_interface *intf = cp->interface[i]; - - dev_dbg(&dev->dev, - "adding %s (config #%d, interface %d)\n", - dev_name(&intf->dev), configuration, - intf->cur_altsetting->desc.bInterfaceNumber); - device_enable_async_suspend(&intf->dev); - ret = device_add(&intf->dev); - if (ret != 0) { - dev_err(&dev->dev, "device_add(%s) --> %d\n", - dev_name(&intf->dev), ret); - continue; - } - create_intf_ep_devs(intf); - } - - usb_autosuspend_device(dev); - return 0; -} - -static LIST_HEAD(set_config_list); -static DEFINE_SPINLOCK(set_config_lock); - -struct set_config_request { - struct usb_device *udev; - int config; - struct work_struct work; - struct list_head node; -}; - -/* Worker routine for usb_driver_set_configuration() */ -static void driver_set_config_work(struct work_struct *work) -{ - struct set_config_request *req = - container_of(work, struct set_config_request, work); - struct usb_device *udev = req->udev; - - usb_lock_device(udev); - spin_lock(&set_config_lock); - list_del(&req->node); - spin_unlock(&set_config_lock); - - if (req->config >= -1) /* Is req still valid? */ - usb_set_configuration(udev, req->config); - usb_unlock_device(udev); - usb_put_dev(udev); - kfree(req); -} - -/* Cancel pending Set-Config requests for a device whose configuration - * was just changed - */ -static void cancel_async_set_config(struct usb_device *udev) -{ - struct set_config_request *req; - - spin_lock(&set_config_lock); - list_for_each_entry(req, &set_config_list, node) { - if (req->udev == udev) - req->config = -999; /* Mark as cancelled */ - } - spin_unlock(&set_config_lock); -} - -/** - * usb_driver_set_configuration - Provide a way for drivers to change device configurations - * @udev: the device whose configuration is being updated - * @config: the configuration being chosen. - * Context: In process context, must be able to sleep - * - * Device interface drivers are not allowed to change device configurations. - * This is because changing configurations will destroy the interface the - * driver is bound to and create new ones; it would be like a floppy-disk - * driver telling the computer to replace the floppy-disk drive with a - * tape drive! - * - * Still, in certain specialized circumstances the need may arise. This - * routine gets around the normal restrictions by using a work thread to - * submit the change-config request. - * - * Returns 0 if the request was successfully queued, error code otherwise. - * The caller has no way to know whether the queued request will eventually - * succeed. - */ -int usb_driver_set_configuration(struct usb_device *udev, int config) -{ - struct set_config_request *req; - - req = kmalloc(sizeof(*req), GFP_KERNEL); - if (!req) - return -ENOMEM; - req->udev = udev; - req->config = config; - INIT_WORK(&req->work, driver_set_config_work); - - spin_lock(&set_config_lock); - list_add(&req->node, &set_config_list); - spin_unlock(&set_config_lock); - - usb_get_dev(udev); - schedule_work(&req->work); - return 0; -} -EXPORT_SYMBOL_GPL(usb_driver_set_configuration); diff --git a/ANDROID_3.4.5/drivers/usb/core/notify.c b/ANDROID_3.4.5/drivers/usb/core/notify.c deleted file mode 100644 index 7728c91d..00000000 --- a/ANDROID_3.4.5/drivers/usb/core/notify.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * All the USB notify logic - * - * (C) Copyright 2005 Greg Kroah-Hartman - * - * notifier functions originally based on those in kernel/sys.c - * but fixed up to not be so broken. - * - */ - - -#include -#include -#include -#include -#include -#include "usb.h" - -static BLOCKING_NOTIFIER_HEAD(usb_notifier_list); - -/** - * usb_register_notify - register a notifier callback whenever a usb change happens - * @nb: pointer to the notifier block for the callback events. - * - * These changes are either USB devices or busses being added or removed. - */ -void usb_register_notify(struct notifier_block *nb) -{ - blocking_notifier_chain_register(&usb_notifier_list, nb); -} -EXPORT_SYMBOL_GPL(usb_register_notify); - -/** - * usb_unregister_notify - unregister a notifier callback - * @nb: pointer to the notifier block for the callback events. - * - * usb_register_notify() must have been previously called for this function - * to work properly. - */ -void usb_unregister_notify(struct notifier_block *nb) -{ - blocking_notifier_chain_unregister(&usb_notifier_list, nb); -} -EXPORT_SYMBOL_GPL(usb_unregister_notify); - - -void usb_notify_add_device(struct usb_device *udev) -{ - blocking_notifier_call_chain(&usb_notifier_list, USB_DEVICE_ADD, udev); -} - -void usb_notify_remove_device(struct usb_device *udev) -{ - /* Protect against simultaneous usbfs open */ - mutex_lock(&usbfs_mutex); - blocking_notifier_call_chain(&usb_notifier_list, - USB_DEVICE_REMOVE, udev); - mutex_unlock(&usbfs_mutex); -} - -void usb_notify_add_bus(struct usb_bus *ubus) -{ - blocking_notifier_call_chain(&usb_notifier_list, USB_BUS_ADD, ubus); -} - -void usb_notify_remove_bus(struct usb_bus *ubus) -{ - blocking_notifier_call_chain(&usb_notifier_list, USB_BUS_REMOVE, ubus); -} diff --git a/ANDROID_3.4.5/drivers/usb/core/otg_whitelist.h b/ANDROID_3.4.5/drivers/usb/core/otg_whitelist.h deleted file mode 100644 index e8cdce57..00000000 --- a/ANDROID_3.4.5/drivers/usb/core/otg_whitelist.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * drivers/usb/core/otg_whitelist.h - * - * Copyright (C) 2004 Texas Instruments - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -/* - * This OTG Whitelist is the OTG "Targeted Peripheral List". It should - * mostly use of USB_DEVICE() or USB_DEVICE_VER() entries.. - * - * YOU _SHOULD_ CHANGE THIS LIST TO MATCH YOUR PRODUCT AND ITS TESTING! - */ - -static struct usb_device_id whitelist_table [] = { - -/* hubs are optional in OTG, but very handy ... */ -{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), }, -{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 1), }, - -#ifdef CONFIG_USB_PRINTER /* ignoring nonstatic linkage! */ -/* FIXME actually, printers are NOT supposed to use device classes; - * they're supposed to use interface classes... - */ -{ USB_DEVICE_INFO(7, 1, 1) }, -{ USB_DEVICE_INFO(7, 1, 2) }, -{ USB_DEVICE_INFO(7, 1, 3) }, -#endif - -#ifdef CONFIG_USB_NET_CDCETHER -/* Linux-USB CDC Ethernet gadget */ -{ USB_DEVICE(0x0525, 0xa4a1), }, -/* Linux-USB CDC Ethernet + RNDIS gadget */ -{ USB_DEVICE(0x0525, 0xa4a2), }, -#endif - -#if defined(CONFIG_USB_TEST) || defined(CONFIG_USB_TEST_MODULE) -/* gadget zero, for testing */ -{ USB_DEVICE(0x0525, 0xa4a0), }, -#endif - -{ } /* Terminating entry */ -}; - -static int is_targeted(struct usb_device *dev) -{ - struct usb_device_id *id = whitelist_table; - - /* possible in developer configs only! */ - if (!dev->bus->otg_port) - return 1; - - /* HNP test device is _never_ targeted (see OTG spec 6.6.6) */ - if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a && - le16_to_cpu(dev->descriptor.idProduct) == 0xbadd)) - return 0; - - /* NOTE: can't use usb_match_id() since interface caches - * aren't set up yet. this is cut/paste from that code. - */ - for (id = whitelist_table; id->match_flags; id++) { - if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) && - id->idVendor != le16_to_cpu(dev->descriptor.idVendor)) - continue; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) && - id->idProduct != le16_to_cpu(dev->descriptor.idProduct)) - continue; - - /* No need to test id->bcdDevice_lo != 0, since 0 is never - greater than any unsigned number. */ - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) && - (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice))) - continue; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) && - (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice))) - continue; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) && - (id->bDeviceClass != dev->descriptor.bDeviceClass)) - continue; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) && - (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass)) - continue; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) && - (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol)) - continue; - - return 1; - } - - /* add other match criteria here ... */ - - - /* OTG MESSAGE: report errors here, customize to match your product */ - dev_err(&dev->dev, "device v%04x p%04x is not supported\n", - le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct)); -#ifdef CONFIG_USB_OTG_WHITELIST - return 0; -#else - return 1; -#endif -} - diff --git a/ANDROID_3.4.5/drivers/usb/core/quirks.c b/ANDROID_3.4.5/drivers/usb/core/quirks.c deleted file mode 100644 index 32d3adc3..00000000 --- a/ANDROID_3.4.5/drivers/usb/core/quirks.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * USB device quirk handling logic and table - * - * Copyright (c) 2007 Oliver Neukum - * Copyright (c) 2007 Greg Kroah-Hartman - * - * 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, version 2. - * - * - */ - -#include -#include -#include "usb.h" - -/* List of quirky USB devices. Please keep this list ordered by: - * 1) Vendor ID - * 2) Product ID - * 3) Class ID - * - * as we want specific devices to be overridden first, and only after that, any - * class specific quirks. - * - * Right now the logic aborts if it finds a valid device in the table, we might - * want to change that in the future if it turns out that a whole class of - * devices is broken... - */ -static const struct usb_device_id usb_quirk_list[] = { - /* CBM - Flash disk */ - { USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* HP 5300/5370C scanner */ - { USB_DEVICE(0x03f0, 0x0701), .driver_info = - USB_QUIRK_STRING_FETCH_255 }, - - /* Creative SB Audigy 2 NX */ - { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* Logitech Webcam C200 */ - { USB_DEVICE(0x046d, 0x0802), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* Logitech Webcam C250 */ - { USB_DEVICE(0x046d, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* Logitech Webcam C300 */ - { USB_DEVICE(0x046d, 0x0805), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* Logitech Webcam B/C500 */ - { USB_DEVICE(0x046d, 0x0807), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* Logitech Webcam C600 */ - { USB_DEVICE(0x046d, 0x0808), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* Logitech Webcam Pro 9000 */ - { USB_DEVICE(0x046d, 0x0809), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* Logitech Webcam C905 */ - { USB_DEVICE(0x046d, 0x080a), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* Logitech Webcam C210 */ - { USB_DEVICE(0x046d, 0x0819), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* Logitech Webcam C260 */ - { USB_DEVICE(0x046d, 0x081a), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* Logitech Webcam C310 */ - { USB_DEVICE(0x046d, 0x081b), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* Logitech Webcam C910 */ - { USB_DEVICE(0x046d, 0x0821), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* Logitech Webcam C160 */ - { USB_DEVICE(0x046d, 0x0824), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* Logitech Webcam C270 */ - { USB_DEVICE(0x046d, 0x0825), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* Logitech Quickcam Pro 9000 */ - { USB_DEVICE(0x046d, 0x0990), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* Logitech Quickcam E3500 */ - { USB_DEVICE(0x046d, 0x09a4), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* Logitech Quickcam Vision Pro */ - { USB_DEVICE(0x046d, 0x09a6), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* Logitech Harmony 700-series */ - { USB_DEVICE(0x046d, 0xc122), .driver_info = USB_QUIRK_DELAY_INIT }, - - /* Philips PSC805 audio device */ - { USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* Artisman Watchdog Dongle */ - { USB_DEVICE(0x04b4, 0x0526), .driver_info = - USB_QUIRK_CONFIG_INTF_STRINGS }, - - /* Samsung Android phone modem - ID conflict with SPH-I500 */ - { USB_DEVICE(0x04e8, 0x6601), .driver_info = - USB_QUIRK_CONFIG_INTF_STRINGS }, - - /* Roland SC-8820 */ - { USB_DEVICE(0x0582, 0x0007), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* Edirol SD-20 */ - { USB_DEVICE(0x0582, 0x0027), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* appletouch */ - { USB_DEVICE(0x05ac, 0x021a), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* Avision AV600U */ - { USB_DEVICE(0x0638, 0x0a13), .driver_info = - USB_QUIRK_STRING_FETCH_255 }, - - /* Saitek Cyborg Gold Joystick */ - { USB_DEVICE(0x06a3, 0x0006), .driver_info = - USB_QUIRK_CONFIG_INTF_STRINGS }, - - /* Guillemot Webcam Hercules Dualpix Exchange (2nd ID) */ - { USB_DEVICE(0x06f8, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* Guillemot Webcam Hercules Dualpix Exchange*/ - { USB_DEVICE(0x06f8, 0x3005), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* Midiman M-Audio Keystation 88es */ - { USB_DEVICE(0x0763, 0x0192), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* M-Systems Flash Disk Pioneers */ - { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* Keytouch QWERTY Panel keyboard */ - { USB_DEVICE(0x0926, 0x3333), .driver_info = - USB_QUIRK_CONFIG_INTF_STRINGS }, - - /* X-Rite/Gretag-Macbeth Eye-One Pro display colorimeter */ - { USB_DEVICE(0x0971, 0x2000), .driver_info = USB_QUIRK_NO_SET_INTF }, - - /* Broadcom BCM92035DGROM BT dongle */ - { USB_DEVICE(0x0a5c, 0x2021), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* Action Semiconductor flash disk */ - { USB_DEVICE(0x10d6, 0x2200), .driver_info = - USB_QUIRK_STRING_FETCH_255 }, - - /* SKYMEDI USB_DRIVE */ - { USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME }, - - /* BUILDWIN Photo Frame */ - { USB_DEVICE(0x1908, 0x1315), .driver_info = - USB_QUIRK_HONOR_BNUMINTERFACES }, - - /* INTEL VALUE SSD */ - { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, - - { } /* terminating entry must be last */ -}; - -static const struct usb_device_id *find_id(struct usb_device *udev) -{ - const struct usb_device_id *id = usb_quirk_list; - - for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass || - id->driver_info; id++) { - if (usb_match_device(udev, id)) - return id; - } - return NULL; -} - -/* - * Detect any quirks the device has, and do any housekeeping for it if needed. - */ -void usb_detect_quirks(struct usb_device *udev) -{ - const struct usb_device_id *id = usb_quirk_list; - - id = find_id(udev); - if (id) - udev->quirks = (u32)(id->driver_info); - if (udev->quirks) - dev_dbg(&udev->dev, "USB quirks for this device: %x\n", - udev->quirks); - - /* For the present, all devices default to USB-PERSIST enabled */ -#if 0 /* was: #ifdef CONFIG_PM */ - /* Hubs are automatically enabled for USB-PERSIST */ - if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) - udev->persist_enabled = 1; - -#else - /* In the absence of PM, we can safely enable USB-PERSIST - * for all devices. It will affect things like hub resets - * and EMF-related port disables. - */ - if (!(udev->quirks & USB_QUIRK_RESET_MORPHS)) - udev->persist_enabled = 1; -#endif /* CONFIG_PM */ -} diff --git a/ANDROID_3.4.5/drivers/usb/core/sysfs.c b/ANDROID_3.4.5/drivers/usb/core/sysfs.c deleted file mode 100644 index 566d9f94..00000000 --- a/ANDROID_3.4.5/drivers/usb/core/sysfs.c +++ /dev/null @@ -1,947 +0,0 @@ -/* - * drivers/usb/core/sysfs.c - * - * (C) Copyright 2002 David Brownell - * (C) Copyright 2002,2004 Greg Kroah-Hartman - * (C) Copyright 2002,2004 IBM Corp. - * - * All of the sysfs file attributes for usb devices and interfaces. - * - */ - - -#include -#include -#include -#include -#include "usb.h" - -/* Active configuration fields */ -#define usb_actconfig_show(field, multiplier, format_string) \ -static ssize_t show_##field(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct usb_device *udev; \ - struct usb_host_config *actconfig; \ - \ - udev = to_usb_device(dev); \ - actconfig = udev->actconfig; \ - if (actconfig) \ - return sprintf(buf, format_string, \ - actconfig->desc.field * multiplier); \ - else \ - return 0; \ -} \ - -#define usb_actconfig_attr(field, multiplier, format_string) \ -usb_actconfig_show(field, multiplier, format_string) \ -static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); - -usb_actconfig_attr(bNumInterfaces, 1, "%2d\n") -usb_actconfig_attr(bmAttributes, 1, "%2x\n") -usb_actconfig_attr(bMaxPower, 2, "%3dmA\n") - -static ssize_t show_configuration_string(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct usb_device *udev; - struct usb_host_config *actconfig; - - udev = to_usb_device(dev); - actconfig = udev->actconfig; - if ((!actconfig) || (!actconfig->string)) - return 0; - return sprintf(buf, "%s\n", actconfig->string); -} -static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL); - -/* configuration value is always present, and r/w */ -usb_actconfig_show(bConfigurationValue, 1, "%u\n"); - -static ssize_t -set_bConfigurationValue(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct usb_device *udev = to_usb_device(dev); - int config, value; - - if (sscanf(buf, "%d", &config) != 1 || config < -1 || config > 255) - return -EINVAL; - usb_lock_device(udev); - value = usb_set_configuration(udev, config); - usb_unlock_device(udev); - return (value < 0) ? value : count; -} - -static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR, - show_bConfigurationValue, set_bConfigurationValue); - -/* String fields */ -#define usb_string_attr(name) \ -static ssize_t show_##name(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct usb_device *udev; \ - int retval; \ - \ - udev = to_usb_device(dev); \ - usb_lock_device(udev); \ - retval = sprintf(buf, "%s\n", udev->name); \ - usb_unlock_device(udev); \ - return retval; \ -} \ -static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); - -usb_string_attr(product); -usb_string_attr(manufacturer); -usb_string_attr(serial); - -static ssize_t -show_speed(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_device *udev; - char *speed; - - udev = to_usb_device(dev); - - switch (udev->speed) { - case USB_SPEED_LOW: - speed = "1.5"; - break; - case USB_SPEED_UNKNOWN: - case USB_SPEED_FULL: - speed = "12"; - break; - case USB_SPEED_HIGH: - speed = "480"; - break; - case USB_SPEED_WIRELESS: - speed = "480"; - break; - case USB_SPEED_SUPER: - speed = "5000"; - break; - default: - speed = "unknown"; - } - return sprintf(buf, "%s\n", speed); -} -static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL); - -static ssize_t -show_busnum(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_device *udev; - - udev = to_usb_device(dev); - return sprintf(buf, "%d\n", udev->bus->busnum); -} -static DEVICE_ATTR(busnum, S_IRUGO, show_busnum, NULL); - -static ssize_t -show_devnum(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_device *udev; - - udev = to_usb_device(dev); - return sprintf(buf, "%d\n", udev->devnum); -} -static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL); - -static ssize_t -show_devpath(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_device *udev; - - udev = to_usb_device(dev); - return sprintf(buf, "%s\n", udev->devpath); -} -static DEVICE_ATTR(devpath, S_IRUGO, show_devpath, NULL); - -static ssize_t -show_version(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_device *udev; - u16 bcdUSB; - - udev = to_usb_device(dev); - bcdUSB = le16_to_cpu(udev->descriptor.bcdUSB); - return sprintf(buf, "%2x.%02x\n", bcdUSB >> 8, bcdUSB & 0xff); -} -static DEVICE_ATTR(version, S_IRUGO, show_version, NULL); - -static ssize_t -show_maxchild(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_device *udev; - - udev = to_usb_device(dev); - return sprintf(buf, "%d\n", udev->maxchild); -} -static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL); - -static ssize_t -show_quirks(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_device *udev; - - udev = to_usb_device(dev); - return sprintf(buf, "0x%x\n", udev->quirks); -} -static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL); - -static ssize_t -show_avoid_reset_quirk(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_device *udev; - - udev = to_usb_device(dev); - return sprintf(buf, "%d\n", !!(udev->quirks & USB_QUIRK_RESET_MORPHS)); -} - -static ssize_t -set_avoid_reset_quirk(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct usb_device *udev = to_usb_device(dev); - int config; - - if (sscanf(buf, "%d", &config) != 1 || config < 0 || config > 1) - return -EINVAL; - usb_lock_device(udev); - if (config) - udev->quirks |= USB_QUIRK_RESET_MORPHS; - else - udev->quirks &= ~USB_QUIRK_RESET_MORPHS; - usb_unlock_device(udev); - return count; -} - -static DEVICE_ATTR(avoid_reset_quirk, S_IRUGO | S_IWUSR, - show_avoid_reset_quirk, set_avoid_reset_quirk); - -static ssize_t -show_urbnum(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_device *udev; - - udev = to_usb_device(dev); - return sprintf(buf, "%d\n", atomic_read(&udev->urbnum)); -} -static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL); - -static ssize_t -show_removable(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_device *udev; - char *state; - - udev = to_usb_device(dev); - - switch (udev->removable) { - case USB_DEVICE_REMOVABLE: - state = "removable"; - break; - case USB_DEVICE_FIXED: - state = "fixed"; - break; - default: - state = "unknown"; - } - - return sprintf(buf, "%s\n", state); -} -static DEVICE_ATTR(removable, S_IRUGO, show_removable, NULL); - -#ifdef CONFIG_PM - -static ssize_t -show_persist(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_device *udev = to_usb_device(dev); - - return sprintf(buf, "%d\n", udev->persist_enabled); -} - -static ssize_t -set_persist(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct usb_device *udev = to_usb_device(dev); - int value; - - /* Hubs are always enabled for USB_PERSIST */ - if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) - return -EPERM; - - if (sscanf(buf, "%d", &value) != 1) - return -EINVAL; - - usb_lock_device(udev); - udev->persist_enabled = !!value; - usb_unlock_device(udev); - return count; -} - -static DEVICE_ATTR(persist, S_IRUGO | S_IWUSR, show_persist, set_persist); - -static int add_persist_attributes(struct device *dev) -{ - int rc = 0; - - if (is_usb_device(dev)) { - struct usb_device *udev = to_usb_device(dev); - - /* Hubs are automatically enabled for USB_PERSIST, - * no point in creating the attribute file. - */ - if (udev->descriptor.bDeviceClass != USB_CLASS_HUB) - rc = sysfs_add_file_to_group(&dev->kobj, - &dev_attr_persist.attr, - power_group_name); - } - return rc; -} - -static void remove_persist_attributes(struct device *dev) -{ - sysfs_remove_file_from_group(&dev->kobj, - &dev_attr_persist.attr, - power_group_name); -} -#else - -#define add_persist_attributes(dev) 0 -#define remove_persist_attributes(dev) do {} while (0) - -#endif /* CONFIG_PM */ - -#ifdef CONFIG_USB_SUSPEND - -static ssize_t -show_connected_duration(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct usb_device *udev = to_usb_device(dev); - - return sprintf(buf, "%u\n", - jiffies_to_msecs(jiffies - udev->connect_time)); -} - -static DEVICE_ATTR(connected_duration, S_IRUGO, show_connected_duration, NULL); - -/* - * If the device is resumed, the last time the device was suspended has - * been pre-subtracted from active_duration. We add the current time to - * get the duration that the device was actually active. - * - * If the device is suspended, the active_duration is up-to-date. - */ -static ssize_t -show_active_duration(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct usb_device *udev = to_usb_device(dev); - int duration; - - if (udev->state != USB_STATE_SUSPENDED) - duration = jiffies_to_msecs(jiffies + udev->active_duration); - else - duration = jiffies_to_msecs(udev->active_duration); - return sprintf(buf, "%u\n", duration); -} - -static DEVICE_ATTR(active_duration, S_IRUGO, show_active_duration, NULL); - -static ssize_t -show_autosuspend(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", dev->power.autosuspend_delay / 1000); -} - -static ssize_t -set_autosuspend(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - int value; - - if (sscanf(buf, "%d", &value) != 1 || value >= INT_MAX/1000 || - value <= -INT_MAX/1000) - return -EINVAL; - - pm_runtime_set_autosuspend_delay(dev, value * 1000); - return count; -} - -static DEVICE_ATTR(autosuspend, S_IRUGO | S_IWUSR, - show_autosuspend, set_autosuspend); - -static const char on_string[] = "on"; -static const char auto_string[] = "auto"; - -static void warn_level(void) { - static int level_warned; - - if (!level_warned) { - level_warned = 1; - printk(KERN_WARNING "WARNING! power/level is deprecated; " - "use power/control instead\n"); - } -} - -static ssize_t -show_level(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_device *udev = to_usb_device(dev); - const char *p = auto_string; - - warn_level(); - if (udev->state != USB_STATE_SUSPENDED && !udev->dev.power.runtime_auto) - p = on_string; - return sprintf(buf, "%s\n", p); -} - -static ssize_t -set_level(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct usb_device *udev = to_usb_device(dev); - int len = count; - char *cp; - int rc = count; - - warn_level(); - cp = memchr(buf, '\n', count); - if (cp) - len = cp - buf; - - usb_lock_device(udev); - - if (len == sizeof on_string - 1 && - strncmp(buf, on_string, len) == 0) - usb_disable_autosuspend(udev); - - else if (len == sizeof auto_string - 1 && - strncmp(buf, auto_string, len) == 0) - usb_enable_autosuspend(udev); - - else - rc = -EINVAL; - - usb_unlock_device(udev); - return rc; -} - -static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, show_level, set_level); - -static ssize_t -show_usb2_hardware_lpm(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct usb_device *udev = to_usb_device(dev); - const char *p; - - if (udev->usb2_hw_lpm_enabled == 1) - p = "enabled"; - else - p = "disabled"; - - return sprintf(buf, "%s\n", p); -} - -static ssize_t -set_usb2_hardware_lpm(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct usb_device *udev = to_usb_device(dev); - bool value; - int ret; - - usb_lock_device(udev); - - ret = strtobool(buf, &value); - - if (!ret) - ret = usb_set_usb2_hardware_lpm(udev, value); - - usb_unlock_device(udev); - - if (!ret) - return count; - - return ret; -} - -static DEVICE_ATTR(usb2_hardware_lpm, S_IRUGO | S_IWUSR, show_usb2_hardware_lpm, - set_usb2_hardware_lpm); - -static struct attribute *usb2_hardware_lpm_attr[] = { - &dev_attr_usb2_hardware_lpm.attr, - NULL, -}; -static struct attribute_group usb2_hardware_lpm_attr_group = { - .name = power_group_name, - .attrs = usb2_hardware_lpm_attr, -}; - -static struct attribute *power_attrs[] = { - &dev_attr_autosuspend.attr, - &dev_attr_level.attr, - &dev_attr_connected_duration.attr, - &dev_attr_active_duration.attr, - NULL, -}; -static struct attribute_group power_attr_group = { - .name = power_group_name, - .attrs = power_attrs, -}; - -static int add_power_attributes(struct device *dev) -{ - int rc = 0; - - if (is_usb_device(dev)) { - struct usb_device *udev = to_usb_device(dev); - rc = sysfs_merge_group(&dev->kobj, &power_attr_group); - if (udev->usb2_hw_lpm_capable == 1) - rc = sysfs_merge_group(&dev->kobj, - &usb2_hardware_lpm_attr_group); - } - - return rc; -} - -static void remove_power_attributes(struct device *dev) -{ - sysfs_unmerge_group(&dev->kobj, &usb2_hardware_lpm_attr_group); - sysfs_unmerge_group(&dev->kobj, &power_attr_group); -} - -#else - -#define add_power_attributes(dev) 0 -#define remove_power_attributes(dev) do {} while (0) - -#endif /* CONFIG_USB_SUSPEND */ - - -/* Descriptor fields */ -#define usb_descriptor_attr_le16(field, format_string) \ -static ssize_t \ -show_##field(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct usb_device *udev; \ - \ - udev = to_usb_device(dev); \ - return sprintf(buf, format_string, \ - le16_to_cpu(udev->descriptor.field)); \ -} \ -static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); - -usb_descriptor_attr_le16(idVendor, "%04x\n") -usb_descriptor_attr_le16(idProduct, "%04x\n") -usb_descriptor_attr_le16(bcdDevice, "%04x\n") - -#define usb_descriptor_attr(field, format_string) \ -static ssize_t \ -show_##field(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct usb_device *udev; \ - \ - udev = to_usb_device(dev); \ - return sprintf(buf, format_string, udev->descriptor.field); \ -} \ -static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); - -usb_descriptor_attr(bDeviceClass, "%02x\n") -usb_descriptor_attr(bDeviceSubClass, "%02x\n") -usb_descriptor_attr(bDeviceProtocol, "%02x\n") -usb_descriptor_attr(bNumConfigurations, "%d\n") -usb_descriptor_attr(bMaxPacketSize0, "%d\n") - - - -/* show if the device is authorized (1) or not (0) */ -static ssize_t usb_dev_authorized_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct usb_device *usb_dev = to_usb_device(dev); - return snprintf(buf, PAGE_SIZE, "%u\n", usb_dev->authorized); -} - - -/* - * Authorize a device to be used in the system - * - * Writing a 0 deauthorizes the device, writing a 1 authorizes it. - */ -static ssize_t usb_dev_authorized_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - ssize_t result; - struct usb_device *usb_dev = to_usb_device(dev); - unsigned val; - result = sscanf(buf, "%u\n", &val); - if (result != 1) - result = -EINVAL; - else if (val == 0) - result = usb_deauthorize_device(usb_dev); - else - result = usb_authorize_device(usb_dev); - return result < 0? result : size; -} - -static DEVICE_ATTR(authorized, 0644, - usb_dev_authorized_show, usb_dev_authorized_store); - -/* "Safely remove a device" */ -static ssize_t usb_remove_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct usb_device *udev = to_usb_device(dev); - int rc = 0; - - usb_lock_device(udev); - if (udev->state != USB_STATE_NOTATTACHED) { - - /* To avoid races, first unconfigure and then remove */ - usb_set_configuration(udev, -1); - rc = usb_remove_device(udev); - } - if (rc == 0) - rc = count; - usb_unlock_device(udev); - return rc; -} -static DEVICE_ATTR(remove, 0200, NULL, usb_remove_store); - - -static struct attribute *dev_attrs[] = { - /* current configuration's attributes */ - &dev_attr_configuration.attr, - &dev_attr_bNumInterfaces.attr, - &dev_attr_bConfigurationValue.attr, - &dev_attr_bmAttributes.attr, - &dev_attr_bMaxPower.attr, - /* device attributes */ - &dev_attr_urbnum.attr, - &dev_attr_idVendor.attr, - &dev_attr_idProduct.attr, - &dev_attr_bcdDevice.attr, - &dev_attr_bDeviceClass.attr, - &dev_attr_bDeviceSubClass.attr, - &dev_attr_bDeviceProtocol.attr, - &dev_attr_bNumConfigurations.attr, - &dev_attr_bMaxPacketSize0.attr, - &dev_attr_speed.attr, - &dev_attr_busnum.attr, - &dev_attr_devnum.attr, - &dev_attr_devpath.attr, - &dev_attr_version.attr, - &dev_attr_maxchild.attr, - &dev_attr_quirks.attr, - &dev_attr_avoid_reset_quirk.attr, - &dev_attr_authorized.attr, - &dev_attr_remove.attr, - &dev_attr_removable.attr, - NULL, -}; -static struct attribute_group dev_attr_grp = { - .attrs = dev_attrs, -}; - -/* When modifying this list, be sure to modify dev_string_attrs_are_visible() - * accordingly. - */ -static struct attribute *dev_string_attrs[] = { - &dev_attr_manufacturer.attr, - &dev_attr_product.attr, - &dev_attr_serial.attr, - NULL -}; - -static umode_t dev_string_attrs_are_visible(struct kobject *kobj, - struct attribute *a, int n) -{ - 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) - return 0; - } else if (a == &dev_attr_product.attr) { - if (udev->product == NULL) - return 0; - } else if (a == &dev_attr_serial.attr) { - if (udev->serial == NULL) - return 0; - } - return a->mode; -} - -static struct attribute_group dev_string_attr_grp = { - .attrs = dev_string_attrs, - .is_visible = dev_string_attrs_are_visible, -}; - -const struct attribute_group *usb_device_groups[] = { - &dev_attr_grp, - &dev_string_attr_grp, - NULL -}; - -/* Binary descriptors */ - -static ssize_t -read_descriptors(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, - char *buf, loff_t off, size_t count) -{ - 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; - void *src; - - /* The binary attribute begins with the device descriptor. - * Following that are the raw descriptor entries for all the - * configurations (config plus subsidiary descriptors). - */ - for (cfgno = -1; cfgno < udev->descriptor.bNumConfigurations && - nleft > 0; ++cfgno) { - if (cfgno < 0) { - src = &udev->descriptor; - srclen = sizeof(struct usb_device_descriptor); - } else { - src = udev->rawdescriptors[cfgno]; - srclen = __le16_to_cpu(udev->config[cfgno].desc. - wTotalLength); - } - if (off < srclen) { - n = min(nleft, srclen - (size_t) off); - memcpy(buf, src + off, n); - nleft -= n; - buf += n; - off = 0; - } else { - off -= srclen; - } - } - return count - nleft; -} - -static struct bin_attribute dev_bin_attr_descriptors = { - .attr = {.name = "descriptors", .mode = 0444}, - .read = read_descriptors, - .size = 18 + 65535, /* dev descr + max-size raw descriptor */ -}; - -int usb_create_sysfs_dev_files(struct usb_device *udev) -{ - struct device *dev = &udev->dev; - int retval; - - retval = device_create_bin_file(dev, &dev_bin_attr_descriptors); - if (retval) - goto error; - - retval = add_persist_attributes(dev); - if (retval) - goto error; - - retval = add_power_attributes(dev); - if (retval) - goto error; - return retval; -error: - usb_remove_sysfs_dev_files(udev); - return retval; -} - -void usb_remove_sysfs_dev_files(struct usb_device *udev) -{ - struct device *dev = &udev->dev; - - remove_power_attributes(dev); - remove_persist_attributes(dev); - device_remove_bin_file(dev, &dev_bin_attr_descriptors); -} - -/* Interface Accociation Descriptor fields */ -#define usb_intf_assoc_attr(field, format_string) \ -static ssize_t \ -show_iad_##field(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct usb_interface *intf = to_usb_interface(dev); \ - \ - return sprintf(buf, format_string, \ - intf->intf_assoc->field); \ -} \ -static DEVICE_ATTR(iad_##field, S_IRUGO, show_iad_##field, NULL); - -usb_intf_assoc_attr(bFirstInterface, "%02x\n") -usb_intf_assoc_attr(bInterfaceCount, "%02d\n") -usb_intf_assoc_attr(bFunctionClass, "%02x\n") -usb_intf_assoc_attr(bFunctionSubClass, "%02x\n") -usb_intf_assoc_attr(bFunctionProtocol, "%02x\n") - -/* Interface fields */ -#define usb_intf_attr(field, format_string) \ -static ssize_t \ -show_##field(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct usb_interface *intf = to_usb_interface(dev); \ - \ - return sprintf(buf, format_string, \ - intf->cur_altsetting->desc.field); \ -} \ -static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); - -usb_intf_attr(bInterfaceNumber, "%02x\n") -usb_intf_attr(bAlternateSetting, "%2d\n") -usb_intf_attr(bNumEndpoints, "%02x\n") -usb_intf_attr(bInterfaceClass, "%02x\n") -usb_intf_attr(bInterfaceSubClass, "%02x\n") -usb_intf_attr(bInterfaceProtocol, "%02x\n") - -static ssize_t show_interface_string(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf; - char *string; - - intf = to_usb_interface(dev); - string = intf->cur_altsetting->string; - barrier(); /* The altsetting might change! */ - - if (!string) - return 0; - return sprintf(buf, "%s\n", string); -} -static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL); - -static ssize_t show_modalias(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf; - struct usb_device *udev; - struct usb_host_interface *alt; - - intf = to_usb_interface(dev); - udev = interface_to_usbdev(intf); - alt = intf->cur_altsetting; - - return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X" - "ic%02Xisc%02Xip%02X\n", - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct), - le16_to_cpu(udev->descriptor.bcdDevice), - udev->descriptor.bDeviceClass, - udev->descriptor.bDeviceSubClass, - udev->descriptor.bDeviceProtocol, - alt->desc.bInterfaceClass, - alt->desc.bInterfaceSubClass, - alt->desc.bInterfaceProtocol); -} -static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL); - -static ssize_t show_supports_autosuspend(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf; - struct usb_device *udev; - int ret; - - intf = to_usb_interface(dev); - udev = interface_to_usbdev(intf); - - usb_lock_device(udev); - /* Devices will be autosuspended even when an interface isn't claimed */ - if (!intf->dev.driver || - to_usb_driver(intf->dev.driver)->supports_autosuspend) - ret = sprintf(buf, "%u\n", 1); - else - ret = sprintf(buf, "%u\n", 0); - usb_unlock_device(udev); - - return ret; -} -static DEVICE_ATTR(supports_autosuspend, S_IRUGO, show_supports_autosuspend, NULL); - -static struct attribute *intf_attrs[] = { - &dev_attr_bInterfaceNumber.attr, - &dev_attr_bAlternateSetting.attr, - &dev_attr_bNumEndpoints.attr, - &dev_attr_bInterfaceClass.attr, - &dev_attr_bInterfaceSubClass.attr, - &dev_attr_bInterfaceProtocol.attr, - &dev_attr_modalias.attr, - &dev_attr_supports_autosuspend.attr, - NULL, -}; -static struct attribute_group intf_attr_grp = { - .attrs = intf_attrs, -}; - -static struct attribute *intf_assoc_attrs[] = { - &dev_attr_iad_bFirstInterface.attr, - &dev_attr_iad_bInterfaceCount.attr, - &dev_attr_iad_bFunctionClass.attr, - &dev_attr_iad_bFunctionSubClass.attr, - &dev_attr_iad_bFunctionProtocol.attr, - NULL, -}; - -static umode_t intf_assoc_attrs_are_visible(struct kobject *kobj, - struct attribute *a, int n) -{ - struct device *dev = container_of(kobj, struct device, kobj); - struct usb_interface *intf = to_usb_interface(dev); - - if (intf->intf_assoc == NULL) - return 0; - return a->mode; -} - -static struct attribute_group intf_assoc_attr_grp = { - .attrs = intf_assoc_attrs, - .is_visible = intf_assoc_attrs_are_visible, -}; - -const struct attribute_group *usb_interface_groups[] = { - &intf_attr_grp, - &intf_assoc_attr_grp, - NULL -}; - -void usb_create_sysfs_intf_files(struct usb_interface *intf) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct usb_host_interface *alt = intf->cur_altsetting; - - if (intf->sysfs_files_created || intf->unregistering) - return; - - if (!alt->string && !(udev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS)) - alt->string = usb_cache_string(udev, alt->desc.iInterface); - if (alt->string && device_create_file(&intf->dev, &dev_attr_interface)) - ; /* We don't actually care if the function fails. */ - intf->sysfs_files_created = 1; -} - -void usb_remove_sysfs_intf_files(struct usb_interface *intf) -{ - if (!intf->sysfs_files_created) - return; - - device_remove_file(&intf->dev, &dev_attr_interface); - intf->sysfs_files_created = 0; -} diff --git a/ANDROID_3.4.5/drivers/usb/core/urb.c b/ANDROID_3.4.5/drivers/usb/core/urb.c deleted file mode 100644 index 9d912bfd..00000000 --- a/ANDROID_3.4.5/drivers/usb/core/urb.c +++ /dev/null @@ -1,888 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define to_urb(d) container_of(d, struct urb, kref) - - -static void urb_destroy(struct kref *kref) -{ - struct urb *urb = to_urb(kref); - - if (urb->transfer_flags & URB_FREE_BUFFER) - kfree(urb->transfer_buffer); - - kfree(urb); -} - -/** - * usb_init_urb - initializes a urb so that it can be used by a USB driver - * @urb: pointer to the urb to initialize - * - * Initializes a urb so that the USB subsystem can use it properly. - * - * If a urb is created with a call to usb_alloc_urb() it is not - * necessary to call this function. Only use this if you allocate the - * space for a struct urb on your own. If you call this function, be - * careful when freeing the memory for your urb that it is no longer in - * use by the USB core. - * - * Only use this function if you _really_ understand what you are doing. - */ -void usb_init_urb(struct urb *urb) -{ - if (urb) { - memset(urb, 0, sizeof(*urb)); - kref_init(&urb->kref); - INIT_LIST_HEAD(&urb->anchor_list); - } -} -EXPORT_SYMBOL_GPL(usb_init_urb); - -/** - * usb_alloc_urb - creates a new urb for a USB driver to use - * @iso_packets: number of iso packets for this urb - * @mem_flags: the type of memory to allocate, see kmalloc() for a list of - * valid options for this. - * - * Creates an urb for the USB driver to use, initializes a few internal - * structures, incrementes the usage counter, and returns a pointer to it. - * - * If no memory is available, NULL is returned. - * - * If the driver want to use this urb for interrupt, control, or bulk - * endpoints, pass '0' as the number of iso packets. - * - * The driver must call usb_free_urb() when it is finished with the urb. - */ -struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags) -{ - struct urb *urb; - - urb = kmalloc(sizeof(struct urb) + - iso_packets * sizeof(struct usb_iso_packet_descriptor), - mem_flags); - if (!urb) { - printk(KERN_ERR "alloc_urb: kmalloc failed\n"); - return NULL; - } - usb_init_urb(urb); - return urb; -} -EXPORT_SYMBOL_GPL(usb_alloc_urb); - -/** - * usb_free_urb - frees the memory used by a urb when all users of it are finished - * @urb: pointer to the urb to free, may be NULL - * - * Must be called when a user of a urb is finished with it. When the last user - * of the urb calls this function, the memory of the urb is freed. - * - * Note: The transfer buffer associated with the urb is not freed unless the - * URB_FREE_BUFFER transfer flag is set. - */ -void usb_free_urb(struct urb *urb) -{ - if (urb) - kref_put(&urb->kref, urb_destroy); -} -EXPORT_SYMBOL_GPL(usb_free_urb); - -/** - * usb_get_urb - increments the reference count of the urb - * @urb: pointer to the urb to modify, may be NULL - * - * This must be called whenever a urb is transferred from a device driver to a - * host controller driver. This allows proper reference counting to happen - * for urbs. - * - * A pointer to the urb with the incremented reference counter is returned. - */ -struct urb *usb_get_urb(struct urb *urb) -{ - if (urb) - kref_get(&urb->kref); - return urb; -} -EXPORT_SYMBOL_GPL(usb_get_urb); - -/** - * usb_anchor_urb - anchors an URB while it is processed - * @urb: pointer to the urb to anchor - * @anchor: pointer to the anchor - * - * This can be called to have access to URBs which are to be executed - * without bothering to track them - */ -void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor) -{ - unsigned long flags; - - spin_lock_irqsave(&anchor->lock, flags); - usb_get_urb(urb); - list_add_tail(&urb->anchor_list, &anchor->urb_list); - urb->anchor = anchor; - - if (unlikely(anchor->poisoned)) { - atomic_inc(&urb->reject); - } - - spin_unlock_irqrestore(&anchor->lock, flags); -} -EXPORT_SYMBOL_GPL(usb_anchor_urb); - -/* Callers must hold anchor->lock */ -static void __usb_unanchor_urb(struct urb *urb, struct usb_anchor *anchor) -{ - urb->anchor = NULL; - list_del(&urb->anchor_list); - usb_put_urb(urb); - if (list_empty(&anchor->urb_list)) - wake_up(&anchor->wait); -} - -/** - * usb_unanchor_urb - unanchors an URB - * @urb: pointer to the urb to anchor - * - * Call this to stop the system keeping track of this URB - */ -void usb_unanchor_urb(struct urb *urb) -{ - unsigned long flags; - struct usb_anchor *anchor; - - if (!urb) - return; - - anchor = urb->anchor; - if (!anchor) - return; - - spin_lock_irqsave(&anchor->lock, flags); - /* - * At this point, we could be competing with another thread which - * has the same intention. To protect the urb from being unanchored - * twice, only the winner of the race gets the job. - */ - if (likely(anchor == urb->anchor)) - __usb_unanchor_urb(urb, anchor); - spin_unlock_irqrestore(&anchor->lock, flags); -} -EXPORT_SYMBOL_GPL(usb_unanchor_urb); - -/*-------------------------------------------------------------------*/ - -/** - * usb_submit_urb - issue an asynchronous transfer request for an endpoint - * @urb: pointer to the urb describing the request - * @mem_flags: the type of memory to allocate, see kmalloc() for a list - * of valid options for this. - * - * This submits a transfer request, and transfers control of the URB - * describing that request to the USB subsystem. Request completion will - * be indicated later, asynchronously, by calling the completion handler. - * The three types of completion are success, error, and unlink - * (a software-induced fault, also called "request cancellation"). - * - * URBs may be submitted in interrupt context. - * - * The caller must have correctly initialized the URB before submitting - * it. Functions such as usb_fill_bulk_urb() and usb_fill_control_urb() are - * available to ensure that most fields are correctly initialized, for - * the particular kind of transfer, although they will not initialize - * any transfer flags. - * - * Successful submissions return 0; otherwise this routine returns a - * negative error number. If the submission is successful, the complete() - * callback from the URB will be called exactly once, when the USB core and - * Host Controller Driver (HCD) are finished with the URB. When the completion - * function is called, control of the URB is returned to the device - * driver which issued the request. The completion handler may then - * immediately free or reuse that URB. - * - * With few exceptions, USB device drivers should never access URB fields - * provided by usbcore or the HCD until its complete() is called. - * The exceptions relate to periodic transfer scheduling. For both - * interrupt and isochronous urbs, as part of successful URB submission - * urb->interval is modified to reflect the actual transfer period used - * (normally some power of two units). And for isochronous urbs, - * urb->start_frame is modified to reflect when the URB's transfers were - * scheduled to start. Not all isochronous transfer scheduling policies - * will work, but most host controller drivers should easily handle ISO - * queues going from now until 10-200 msec into the future. - * - * For control endpoints, the synchronous usb_control_msg() call is - * often used (in non-interrupt context) instead of this call. - * That is often used through convenience wrappers, for the requests - * that are standardized in the USB 2.0 specification. For bulk - * endpoints, a synchronous usb_bulk_msg() call is available. - * - * Request Queuing: - * - * URBs may be submitted to endpoints before previous ones complete, to - * minimize the impact of interrupt latencies and system overhead on data - * throughput. With that queuing policy, an endpoint's queue would never - * be empty. This is required for continuous isochronous data streams, - * and may also be required for some kinds of interrupt transfers. Such - * queuing also maximizes bandwidth utilization by letting USB controllers - * start work on later requests before driver software has finished the - * completion processing for earlier (successful) requests. - * - * As of Linux 2.6, all USB endpoint transfer queues support depths greater - * than one. This was previously a HCD-specific behavior, except for ISO - * transfers. Non-isochronous endpoint queues are inactive during cleanup - * after faults (transfer errors or cancellation). - * - * Reserved Bandwidth Transfers: - * - * Periodic transfers (interrupt or isochronous) are performed repeatedly, - * using the interval specified in the urb. Submitting the first urb to - * the endpoint reserves the bandwidth necessary to make those transfers. - * 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 - * queued, the endpoint's bandwidth reservation is canceled. This means - * drivers can use their completion handlers to ensure they keep bandwidth - * they need, by reinitializing and resubmitting the just-completed urb - * until the driver longer needs that periodic bandwidth. - * - * Memory Flags: - * - * The general rules for how to decide which mem_flags to use - * are the same as for kmalloc. There are four - * different possible values; GFP_KERNEL, GFP_NOFS, GFP_NOIO and - * GFP_ATOMIC. - * - * GFP_NOFS is not ever used, as it has not been implemented yet. - * - * GFP_ATOMIC is used when - * (a) you are inside a completion handler, an interrupt, bottom half, - * tasklet or timer, or - * (b) you are holding a spinlock or rwlock (does not apply to - * semaphores), or - * (c) current->state != TASK_RUNNING, this is the case only after - * you've changed it. - * - * GFP_NOIO is used in the block io path and error handling of storage - * devices. - * - * All other situations use GFP_KERNEL. - * - * Some more specific rules for mem_flags can be inferred, such as - * (1) start_xmit, timeout, and receive methods of network drivers must - * use GFP_ATOMIC (they are called with a spinlock held); - * (2) queuecommand methods of scsi drivers must use GFP_ATOMIC (also - * called with a spinlock held); - * (3) If you use a kernel thread with a network driver you must use - * GFP_NOIO, unless (b) or (c) apply; - * (4) after you have done a down() you can use GFP_KERNEL, unless (b) or (c) - * apply or your are in a storage driver's block io path; - * (5) USB probe and disconnect can use GFP_KERNEL unless (b) or (c) apply; and - * (6) changing firmware on a running storage or net device uses - * GFP_NOIO, unless b) or c) apply - * - */ -int usb_submit_urb(struct urb *urb, gfp_t mem_flags) -{ - int xfertype, max; - struct usb_device *dev; - struct usb_host_endpoint *ep; - int is_out; - - if (!urb || urb->hcpriv || !urb->complete) - return -EINVAL; - dev = urb->dev; - if ((!dev) || (dev->state < USB_STATE_UNAUTHENTICATED)) - return -ENODEV; - - /* For now, get the endpoint from the pipe. Eventually drivers - * will be required to set urb->ep directly and we will eliminate - * urb->pipe. - */ - ep = usb_pipe_endpoint(dev, urb->pipe); - if (!ep) - return -ENOENT; - - urb->ep = ep; - urb->status = -EINPROGRESS; - urb->actual_length = 0; - - /* Lots of sanity checks, so HCDs can rely on clean data - * and don't need to duplicate tests - */ - xfertype = usb_endpoint_type(&ep->desc); - if (xfertype == USB_ENDPOINT_XFER_CONTROL) { - struct usb_ctrlrequest *setup = - (struct usb_ctrlrequest *) urb->setup_packet; - - if (!setup) - return -ENOEXEC; - is_out = !(setup->bRequestType & USB_DIR_IN) || - !setup->wLength; - } else { - is_out = usb_endpoint_dir_out(&ep->desc); - } - - /* Clear the internal flags and cache the direction for later use */ - urb->transfer_flags &= ~(URB_DIR_MASK | URB_DMA_MAP_SINGLE | - URB_DMA_MAP_PAGE | URB_DMA_MAP_SG | URB_MAP_LOCAL | - URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL | - URB_DMA_SG_COMBINED); - urb->transfer_flags |= (is_out ? URB_DIR_OUT : URB_DIR_IN); - - if (xfertype != USB_ENDPOINT_XFER_CONTROL && - dev->state < USB_STATE_CONFIGURED) - return -ENODEV; - - max = usb_endpoint_maxp(&ep->desc); - if (max <= 0) { - dev_dbg(&dev->dev, - "bogus endpoint ep%d%s in %s (bad maxpacket %d)\n", - usb_endpoint_num(&ep->desc), is_out ? "out" : "in", - __func__, max); - return -EMSGSIZE; - } - - /* periodic transfers limit size per frame/uframe, - * but drivers only control those sizes for ISO. - * while we're checking, initialize return status. - */ - if (xfertype == USB_ENDPOINT_XFER_ISOC) { - int n, len; - - /* SuperSpeed isoc endpoints have up to 16 bursts of up to - * 3 packets each - */ - if (dev->speed == USB_SPEED_SUPER) { - int burst = 1 + ep->ss_ep_comp.bMaxBurst; - int mult = USB_SS_MULT(ep->ss_ep_comp.bmAttributes); - max *= burst; - max *= mult; - } - - /* "high bandwidth" mode, 1-3 packets/uframe? */ - if (dev->speed == USB_SPEED_HIGH) { - int mult = 1 + ((max >> 11) & 0x03); - max &= 0x07ff; - max *= mult; - } - - if (urb->number_of_packets <= 0) - return -EINVAL; - for (n = 0; n < urb->number_of_packets; n++) { - len = urb->iso_frame_desc[n].length; - if (len < 0 || len > max) - return -EMSGSIZE; - urb->iso_frame_desc[n].status = -EXDEV; - urb->iso_frame_desc[n].actual_length = 0; - } - } - - /* the I/O buffer must be mapped/unmapped, except when length=0 */ - if (urb->transfer_buffer_length > INT_MAX) - return -EMSGSIZE; - -#ifdef DEBUG - /* stuff that drivers shouldn't do, but which shouldn't - * cause problems in HCDs if they get it wrong. - */ - { - unsigned int allowed; - static int pipetypes[4] = { - PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT - }; - - /* Check that the pipe's type matches the endpoint's type */ - if (usb_pipetype(urb->pipe) != pipetypes[xfertype]) - dev_WARN(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n", - usb_pipetype(urb->pipe), pipetypes[xfertype]); - - /* Check against a simple/standard policy */ - allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT | URB_DIR_MASK | - URB_FREE_BUFFER); - switch (xfertype) { - case USB_ENDPOINT_XFER_BULK: - if (is_out) - allowed |= URB_ZERO_PACKET; - /* FALLTHROUGH */ - case USB_ENDPOINT_XFER_CONTROL: - allowed |= URB_NO_FSBR; /* only affects UHCI */ - /* FALLTHROUGH */ - default: /* all non-iso endpoints */ - if (!is_out) - allowed |= URB_SHORT_NOT_OK; - break; - case USB_ENDPOINT_XFER_ISOC: - allowed |= URB_ISO_ASAP; - break; - } - allowed &= urb->transfer_flags; - - /* warn if submitter gave bogus flags */ - if (allowed != urb->transfer_flags) - dev_WARN(&dev->dev, "BOGUS urb flags, %x --> %x\n", - urb->transfer_flags, allowed); - } -#endif - /* - * Force periodic transfer intervals to be legal values that are - * a power of two (so HCDs don't need to). - * - * FIXME want bus->{intr,iso}_sched_horizon values here. Each HC - * supports different values... this uses EHCI/UHCI defaults (and - * EHCI can use smaller non-default values). - */ - switch (xfertype) { - case USB_ENDPOINT_XFER_ISOC: - case USB_ENDPOINT_XFER_INT: - /* too small? */ - switch (dev->speed) { - case USB_SPEED_WIRELESS: - if (urb->interval < 6) - return -EINVAL; - break; - default: - if (urb->interval <= 0) - return -EINVAL; - break; - } - /* 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; - break; - case USB_SPEED_WIRELESS: - if (urb->interval > 16) - return -EINVAL; - break; - case USB_SPEED_HIGH: /* units are microframes */ - /* NOTE usb handles 2^15 */ - if (urb->interval > (1024 * 8)) - urb->interval = 1024 * 8; - max = 1024 * 8; - break; - case USB_SPEED_FULL: /* units are frames/msec */ - case USB_SPEED_LOW: - if (xfertype == USB_ENDPOINT_XFER_INT) { - if (urb->interval > 255) - return -EINVAL; - /* NOTE ohci only handles up to 32 */ - max = 128; - } else { - if (urb->interval > 1024) - urb->interval = 1024; - /* NOTE usb and ohci handle up to 2^15 */ - max = 1024; - } - break; - default: - return -EINVAL; - } - if (dev->speed != USB_SPEED_WIRELESS) { - /* Round down to a power of 2, no more than max */ - urb->interval = min(max, 1 << ilog2(urb->interval)); - } - } - - return usb_hcd_submit_urb(urb, mem_flags); -} -EXPORT_SYMBOL_GPL(usb_submit_urb); - -/*-------------------------------------------------------------------*/ - -/** - * usb_unlink_urb - abort/cancel a transfer request for an endpoint - * @urb: pointer to urb describing a previously submitted request, - * may be NULL - * - * This routine cancels an in-progress request. URBs complete only once - * per submission, and may be canceled only once per submission. - * Successful cancellation means termination of @urb will be expedited - * and the completion handler will be called with a status code - * indicating that the request has been canceled (rather than any other - * code). - * - * Drivers should not call this routine or related routines, such as - * usb_kill_urb() or usb_unlink_anchored_urbs(), after their disconnect - * method has returned. The disconnect function should synchronize with - * a driver's I/O routines to insure that all URB-related activity has - * completed before it returns. - * - * This request is asynchronous, however the HCD might call the ->complete() - * callback during unlink. Therefore when drivers call usb_unlink_urb(), they - * must not hold any locks that may be taken by the completion function. - * Success is indicated by returning -EINPROGRESS, at which time the URB will - * probably not yet have been given back to the device driver. When it is - * eventually called, the completion function will see @urb->status == - * -ECONNRESET. - * Failure is indicated by usb_unlink_urb() returning any other value. - * Unlinking will fail when @urb is not currently "linked" (i.e., it was - * never submitted, or it was unlinked before, or the hardware is already - * finished with it), even if the completion handler has not yet run. - * - * The URB must not be deallocated while this routine is running. In - * particular, when a driver calls this routine, it must insure that the - * completion handler cannot deallocate the URB. - * - * Unlinking and Endpoint Queues: - * - * [The behaviors and guarantees described below do not apply to virtual - * root hubs but only to endpoint queues for physical USB devices.] - * - * Host Controller Drivers (HCDs) place all the URBs for a particular - * endpoint in a queue. Normally the queue advances as the controller - * hardware processes each request. But when an URB terminates with an - * error its queue generally stops (see below), at least until that URB's - * completion routine returns. It is guaranteed that a stopped queue - * will not restart until all its unlinked URBs have been fully retired, - * with their completion routines run, even if that's not until some time - * after the original completion handler returns. The same behavior and - * guarantee apply when an URB terminates because it was unlinked. - * - * Bulk and interrupt endpoint queues are guaranteed to stop whenever an - * URB terminates with any sort of error, including -ECONNRESET, -ENOENT, - * and -EREMOTEIO. Control endpoint queues behave the same way except - * that they are not guaranteed to stop for -EREMOTEIO errors. Queues - * for isochronous endpoints are treated differently, because they must - * advance at fixed rates. Such queues do not stop when an URB - * encounters an error or is unlinked. An unlinked isochronous URB may - * leave a gap in the stream of packets; it is undefined whether such - * gaps can be filled in. - * - * Note that early termination of an URB because a short packet was - * received will generate a -EREMOTEIO error if and only if the - * URB_SHORT_NOT_OK flag is set. By setting this flag, USB device - * drivers can build deep queues for large or complex bulk transfers - * and clean them up reliably after any sort of aborted transfer by - * unlinking all pending URBs at the first fault. - * - * When a control URB terminates with an error other than -EREMOTEIO, it - * is quite likely that the status stage of the transfer will not take - * place. - */ -int usb_unlink_urb(struct urb *urb) -{ - if (!urb) - return -EINVAL; - if (!urb->dev) - return -ENODEV; - if (!urb->ep) - return -EIDRM; - return usb_hcd_unlink_urb(urb, -ECONNRESET); -} -EXPORT_SYMBOL_GPL(usb_unlink_urb); - -/** - * usb_kill_urb - cancel a transfer request and wait for it to finish - * @urb: pointer to URB describing a previously submitted request, - * may be NULL - * - * This routine cancels an in-progress request. It is guaranteed that - * upon return all completion handlers will have finished and the URB - * will be totally idle and available for reuse. These features make - * this an ideal way to stop I/O in a disconnect() callback or close() - * function. If the request has not already finished or been unlinked - * the completion handler will see urb->status == -ENOENT. - * - * While the routine is running, attempts to resubmit the URB will fail - * with error -EPERM. Thus even if the URB's completion handler always - * tries to resubmit, it will not succeed and the URB will become idle. - * - * The URB must not be deallocated while this routine is running. In - * particular, when a driver calls this routine, it must insure that the - * completion handler cannot deallocate the URB. - * - * This routine may not be used in an interrupt context (such as a bottom - * half or a completion handler), or when holding a spinlock, or in other - * situations where the caller can't schedule(). - * - * This routine should not be called by a driver after its disconnect - * method has returned. - */ -void usb_kill_urb(struct urb *urb) -{ - might_sleep(); - if (!(urb && urb->dev && urb->ep)) - return; - atomic_inc(&urb->reject); - - usb_hcd_unlink_urb(urb, -ENOENT); - wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0); - - atomic_dec(&urb->reject); -} -EXPORT_SYMBOL_GPL(usb_kill_urb); - -/** - * usb_poison_urb - reliably kill a transfer and prevent further use of an URB - * @urb: pointer to URB describing a previously submitted request, - * may be NULL - * - * This routine cancels an in-progress request. It is guaranteed that - * upon return all completion handlers will have finished and the URB - * will be totally idle and cannot be reused. These features make - * this an ideal way to stop I/O in a disconnect() callback. - * If the request has not already finished or been unlinked - * the completion handler will see urb->status == -ENOENT. - * - * After and while the routine runs, attempts to resubmit the URB will fail - * with error -EPERM. Thus even if the URB's completion handler always - * tries to resubmit, it will not succeed and the URB will become idle. - * - * The URB must not be deallocated while this routine is running. In - * particular, when a driver calls this routine, it must insure that the - * completion handler cannot deallocate the URB. - * - * This routine may not be used in an interrupt context (such as a bottom - * half or a completion handler), or when holding a spinlock, or in other - * situations where the caller can't schedule(). - * - * This routine should not be called by a driver after its disconnect - * method has returned. - */ -void usb_poison_urb(struct urb *urb) -{ - might_sleep(); - if (!(urb && urb->dev && urb->ep)) - return; - atomic_inc(&urb->reject); - - usb_hcd_unlink_urb(urb, -ENOENT); - wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0); -} -EXPORT_SYMBOL_GPL(usb_poison_urb); - -void usb_unpoison_urb(struct urb *urb) -{ - if (!urb) - return; - - atomic_dec(&urb->reject); -} -EXPORT_SYMBOL_GPL(usb_unpoison_urb); - -/** - * usb_block_urb - reliably prevent further use of an URB - * @urb: pointer to URB to be blocked, may be NULL - * - * After the routine has run, attempts to resubmit the URB will fail - * with error -EPERM. Thus even if the URB's completion handler always - * tries to resubmit, it will not succeed and the URB will become idle. - * - * The URB must not be deallocated while this routine is running. In - * particular, when a driver calls this routine, it must insure that the - * completion handler cannot deallocate the URB. - */ -void usb_block_urb(struct urb *urb) -{ - if (!urb) - return; - - atomic_inc(&urb->reject); -} -EXPORT_SYMBOL_GPL(usb_block_urb); - -/** - * usb_kill_anchored_urbs - cancel transfer requests en masse - * @anchor: anchor the requests are bound to - * - * this allows all outstanding URBs to be killed starting - * from the back of the queue - * - * This routine should not be called by a driver after its disconnect - * method has returned. - */ -void usb_kill_anchored_urbs(struct usb_anchor *anchor) -{ - struct urb *victim; - - spin_lock_irq(&anchor->lock); - while (!list_empty(&anchor->urb_list)) { - victim = list_entry(anchor->urb_list.prev, struct urb, - anchor_list); - /* we must make sure the URB isn't freed before we kill it*/ - usb_get_urb(victim); - spin_unlock_irq(&anchor->lock); - /* this will unanchor the URB */ - usb_kill_urb(victim); - usb_put_urb(victim); - spin_lock_irq(&anchor->lock); - } - spin_unlock_irq(&anchor->lock); -} -EXPORT_SYMBOL_GPL(usb_kill_anchored_urbs); - - -/** - * usb_poison_anchored_urbs - cease all traffic from an anchor - * @anchor: anchor the requests are bound to - * - * this allows all outstanding URBs to be poisoned starting - * from the back of the queue. Newly added URBs will also be - * poisoned - * - * This routine should not be called by a driver after its disconnect - * method has returned. - */ -void usb_poison_anchored_urbs(struct usb_anchor *anchor) -{ - struct urb *victim; - - spin_lock_irq(&anchor->lock); - anchor->poisoned = 1; - while (!list_empty(&anchor->urb_list)) { - victim = list_entry(anchor->urb_list.prev, struct urb, - anchor_list); - /* we must make sure the URB isn't freed before we kill it*/ - usb_get_urb(victim); - spin_unlock_irq(&anchor->lock); - /* this will unanchor the URB */ - usb_poison_urb(victim); - usb_put_urb(victim); - spin_lock_irq(&anchor->lock); - } - spin_unlock_irq(&anchor->lock); -} -EXPORT_SYMBOL_GPL(usb_poison_anchored_urbs); - -/** - * usb_unpoison_anchored_urbs - let an anchor be used successfully again - * @anchor: anchor the requests are bound to - * - * Reverses the effect of usb_poison_anchored_urbs - * the anchor can be used normally after it returns - */ -void usb_unpoison_anchored_urbs(struct usb_anchor *anchor) -{ - unsigned long flags; - struct urb *lazarus; - - spin_lock_irqsave(&anchor->lock, flags); - list_for_each_entry(lazarus, &anchor->urb_list, anchor_list) { - usb_unpoison_urb(lazarus); - } - anchor->poisoned = 0; - spin_unlock_irqrestore(&anchor->lock, flags); -} -EXPORT_SYMBOL_GPL(usb_unpoison_anchored_urbs); -/** - * usb_unlink_anchored_urbs - asynchronously cancel transfer requests en masse - * @anchor: anchor the requests are bound to - * - * this allows all outstanding URBs to be unlinked starting - * from the back of the queue. This function is asynchronous. - * The unlinking is just tiggered. It may happen after this - * function has returned. - * - * This routine should not be called by a driver after its disconnect - * method has returned. - */ -void usb_unlink_anchored_urbs(struct usb_anchor *anchor) -{ - struct urb *victim; - - while ((victim = usb_get_from_anchor(anchor)) != NULL) { - usb_unlink_urb(victim); - usb_put_urb(victim); - } -} -EXPORT_SYMBOL_GPL(usb_unlink_anchored_urbs); - -/** - * usb_wait_anchor_empty_timeout - wait for an anchor to be unused - * @anchor: the anchor you want to become unused - * @timeout: how long you are willing to wait in milliseconds - * - * Call this is you want to be sure all an anchor's - * URBs have finished - */ -int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor, - unsigned int timeout) -{ - return wait_event_timeout(anchor->wait, list_empty(&anchor->urb_list), - msecs_to_jiffies(timeout)); -} -EXPORT_SYMBOL_GPL(usb_wait_anchor_empty_timeout); - -/** - * usb_get_from_anchor - get an anchor's oldest urb - * @anchor: the anchor whose urb you want - * - * this will take the oldest urb from an anchor, - * unanchor and return it - */ -struct urb *usb_get_from_anchor(struct usb_anchor *anchor) -{ - struct urb *victim; - unsigned long flags; - - spin_lock_irqsave(&anchor->lock, flags); - if (!list_empty(&anchor->urb_list)) { - victim = list_entry(anchor->urb_list.next, struct urb, - anchor_list); - usb_get_urb(victim); - __usb_unanchor_urb(victim, anchor); - } else { - victim = NULL; - } - spin_unlock_irqrestore(&anchor->lock, flags); - - return victim; -} - -EXPORT_SYMBOL_GPL(usb_get_from_anchor); - -/** - * usb_scuttle_anchored_urbs - unanchor all an anchor's urbs - * @anchor: the anchor whose urbs you want to unanchor - * - * use this to get rid of all an anchor's urbs - */ -void usb_scuttle_anchored_urbs(struct usb_anchor *anchor) -{ - struct urb *victim; - unsigned long flags; - - spin_lock_irqsave(&anchor->lock, flags); - while (!list_empty(&anchor->urb_list)) { - victim = list_entry(anchor->urb_list.prev, struct urb, - anchor_list); - __usb_unanchor_urb(victim, anchor); - } - spin_unlock_irqrestore(&anchor->lock, flags); -} - -EXPORT_SYMBOL_GPL(usb_scuttle_anchored_urbs); - -/** - * usb_anchor_empty - is an anchor empty - * @anchor: the anchor you want to query - * - * returns 1 if the anchor has no urbs associated with it - */ -int usb_anchor_empty(struct usb_anchor *anchor) -{ - return list_empty(&anchor->urb_list); -} - -EXPORT_SYMBOL_GPL(usb_anchor_empty); - diff --git a/ANDROID_3.4.5/drivers/usb/core/usb.c b/ANDROID_3.4.5/drivers/usb/core/usb.c deleted file mode 100644 index 0fc63407..00000000 --- a/ANDROID_3.4.5/drivers/usb/core/usb.c +++ /dev/null @@ -1,1131 +0,0 @@ -/* - * drivers/usb/core/usb.c - * - * (C) Copyright Linus Torvalds 1999 - * (C) Copyright Johannes Erdfelt 1999-2001 - * (C) Copyright Andreas Gal 1999 - * (C) Copyright Gregory P. Smith 1999 - * (C) Copyright Deti Fliegl 1999 (new USB architecture) - * (C) Copyright Randy Dunlap 2000 - * (C) Copyright David Brownell 2000-2004 - * (C) Copyright Yggdrasil Computing, Inc. 2000 - * (usb_device_id matching changes by Adam J. Richter) - * (C) Copyright Greg Kroah-Hartman 2002-2003 - * - * NOTE! This is not actually a driver at all, rather this is - * just a collection of helper routines that implement the - * generic USB things that the real drivers can use.. - * - * Think of this as a "USB library" rather than anything else. - * It should be considered a slave, with no callbacks. Callbacks - * are evil. - */ - -#include -#include -#include -#include -#include -#include /* for in_interrupt() */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "usb.h" - - -const char *usbcore_name = "usbcore"; - -static bool nousb; /* Disable USB when built into kernel image */ - -#ifdef CONFIG_USB_SUSPEND -static int usb_autosuspend_delay = 2; /* Default delay value, - * in seconds */ -module_param_named(autosuspend, usb_autosuspend_delay, int, 0644); -MODULE_PARM_DESC(autosuspend, "default autosuspend delay"); - -#else -#define usb_autosuspend_delay 0 -#endif - - -/** - * usb_find_alt_setting() - Given a configuration, find the alternate setting - * for the given interface. - * @config: the configuration to search (not necessarily the current config). - * @iface_num: interface number to search in - * @alt_num: alternate interface setting number to search for. - * - * Search the configuration's interface cache for the given alt setting. - */ -struct usb_host_interface *usb_find_alt_setting( - struct usb_host_config *config, - unsigned int iface_num, - unsigned int alt_num) -{ - struct usb_interface_cache *intf_cache = NULL; - int i; - - for (i = 0; i < config->desc.bNumInterfaces; i++) { - if (config->intf_cache[i]->altsetting[0].desc.bInterfaceNumber - == iface_num) { - intf_cache = config->intf_cache[i]; - break; - } - } - if (!intf_cache) - return NULL; - for (i = 0; i < intf_cache->num_altsetting; i++) - if (intf_cache->altsetting[i].desc.bAlternateSetting == alt_num) - return &intf_cache->altsetting[i]; - - printk(KERN_DEBUG "Did not find alt setting %u for intf %u, " - "config %u\n", alt_num, iface_num, - config->desc.bConfigurationValue); - return NULL; -} -EXPORT_SYMBOL_GPL(usb_find_alt_setting); - -/** - * usb_ifnum_to_if - get the interface object with a given interface number - * @dev: the device whose current configuration is considered - * @ifnum: the desired interface - * - * This walks the device descriptor for the currently active configuration - * and returns a pointer to the interface with that particular interface - * number, or null. - * - * Note that configuration descriptors are not required to assign interface - * numbers sequentially, so that it would be incorrect to assume that - * the first interface in that descriptor corresponds to interface zero. - * This routine helps device drivers avoid such mistakes. - * However, you should make sure that you do the right thing with any - * alternate settings available for this interfaces. - * - * Don't call this function unless you are bound to one of the interfaces - * on this device or you have locked the device! - */ -struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev, - unsigned ifnum) -{ - struct usb_host_config *config = dev->actconfig; - int i; - - if (!config) - return NULL; - for (i = 0; i < config->desc.bNumInterfaces; i++) - if (config->interface[i]->altsetting[0] - .desc.bInterfaceNumber == ifnum) - return config->interface[i]; - - return NULL; -} -EXPORT_SYMBOL_GPL(usb_ifnum_to_if); - -/** - * usb_altnum_to_altsetting - get the altsetting structure with a given alternate setting number. - * @intf: the interface containing the altsetting in question - * @altnum: the desired alternate setting number - * - * This searches the altsetting array of the specified interface for - * an entry with the correct bAlternateSetting value and returns a pointer - * to that entry, or null. - * - * Note that altsettings need not be stored sequentially by number, so - * it would be incorrect to assume that the first altsetting entry in - * the array corresponds to altsetting zero. This routine helps device - * drivers avoid such mistakes. - * - * Don't call this function unless you are bound to the intf interface - * or you have locked the device! - */ -struct usb_host_interface *usb_altnum_to_altsetting( - const struct usb_interface *intf, - unsigned int altnum) -{ - int i; - - for (i = 0; i < intf->num_altsetting; i++) { - if (intf->altsetting[i].desc.bAlternateSetting == altnum) - return &intf->altsetting[i]; - } - return NULL; -} -EXPORT_SYMBOL_GPL(usb_altnum_to_altsetting); - -struct find_interface_arg { - int minor; - struct device_driver *drv; -}; - -static int __find_interface(struct device *dev, void *data) -{ - struct find_interface_arg *arg = data; - struct usb_interface *intf; - - if (!is_usb_interface(dev)) - return 0; - - if (dev->driver != arg->drv) - return 0; - intf = to_usb_interface(dev); - return intf->minor == arg->minor; -} - -/** - * usb_find_interface - find usb_interface pointer for driver and device - * @drv: the driver whose current configuration is considered - * @minor: the minor number of the desired device - * - * This walks the bus device list and returns a pointer to the interface - * with the matching minor and driver. Note, this only works for devices - * that share the USB major number. - */ -struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor) -{ - struct find_interface_arg argb; - struct device *dev; - - argb.minor = minor; - argb.drv = &drv->drvwrap.driver; - - dev = bus_find_device(&usb_bus_type, NULL, &argb, __find_interface); - - /* Drop reference count from bus_find_device */ - put_device(dev); - - return dev ? to_usb_interface(dev) : NULL; -} -EXPORT_SYMBOL_GPL(usb_find_interface); - -/** - * usb_release_dev - free a usb device structure when all users of it are finished. - * @dev: device that's been disconnected - * - * Will be called only by the device core when all users of this usb device are - * done. - */ -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_release_bos_descriptor(udev); - usb_put_hcd(hcd); - kfree(udev->product); - kfree(udev->manufacturer); - kfree(udev->serial); - kfree(udev); -} - -#ifdef CONFIG_HOTPLUG -static int usb_dev_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - struct usb_device *usb_dev; - - usb_dev = to_usb_device(dev); - - if (add_uevent_var(env, "BUSNUM=%03d", usb_dev->bus->busnum)) - return -ENOMEM; - - if (add_uevent_var(env, "DEVNUM=%03d", usb_dev->devnum)) - return -ENOMEM; - - return 0; -} - -#else - -static int usb_dev_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - return -ENODEV; -} -#endif /* CONFIG_HOTPLUG */ - -#ifdef CONFIG_PM - -/* USB device Power-Management thunks. - * There's no need to distinguish here between quiescing a USB device - * and powering it down; the generic_suspend() routine takes care of - * it by skipping the usb_port_suspend() call for a quiesce. And for - * USB interfaces there's no difference at all. - */ - -static int usb_dev_prepare(struct device *dev) -{ - return 0; /* Implement eventually? */ -} - -static void usb_dev_complete(struct device *dev) -{ - /* Currently used only for rebinding interfaces */ - usb_resume_complete(dev); -} - -static int usb_dev_suspend(struct device *dev) -{ - return usb_suspend(dev, PMSG_SUSPEND); -} - -static int usb_dev_resume(struct device *dev) -{ - return usb_resume(dev, PMSG_RESUME); -} - -static int usb_dev_freeze(struct device *dev) -{ - return usb_suspend(dev, PMSG_FREEZE); -} - -static int usb_dev_thaw(struct device *dev) -{ - return usb_resume(dev, PMSG_THAW); -} - -static int usb_dev_poweroff(struct device *dev) -{ - return usb_suspend(dev, PMSG_HIBERNATE); -} - -static int usb_dev_restore(struct device *dev) -{ - return usb_resume(dev, PMSG_RESTORE); -} - -static const struct dev_pm_ops usb_device_pm_ops = { - .prepare = usb_dev_prepare, - .complete = usb_dev_complete, - .suspend = usb_dev_suspend, - .resume = usb_dev_resume, - .freeze = usb_dev_freeze, - .thaw = usb_dev_thaw, - .poweroff = usb_dev_poweroff, - .restore = usb_dev_restore, -#ifdef CONFIG_USB_SUSPEND - .runtime_suspend = usb_runtime_suspend, - .runtime_resume = usb_runtime_resume, - .runtime_idle = usb_runtime_idle, -#endif -}; - -#endif /* CONFIG_PM */ - - -static char *usb_devnode(struct device *dev, umode_t *mode) -{ - struct usb_device *usb_dev; - - usb_dev = to_usb_device(dev); - return kasprintf(GFP_KERNEL, "bus/usb/%03d/%03d", - usb_dev->bus->busnum, usb_dev->devnum); -} - -struct device_type usb_device_type = { - .name = "usb_device", - .release = usb_release_dev, - .uevent = usb_dev_uevent, - .devnode = usb_devnode, -#ifdef CONFIG_PM - .pm = &usb_device_pm_ops, -#endif -}; - - -/* Returns 1 if @usb_bus is WUSB, 0 otherwise */ -static unsigned usb_bus_is_wusb(struct usb_bus *bus) -{ - struct usb_hcd *hcd = container_of(bus, struct usb_hcd, self); - return hcd->wireless; -} - - -/** - * usb_alloc_dev - usb device constructor (usbcore-internal) - * @parent: hub to which device is connected; null to allocate a root hub - * @bus: bus used to access the device - * @port1: one-based index of port; ignored for root hubs - * Context: !in_interrupt() - * - * Only hub drivers (including virtual root hub drivers for host - * controllers) should ever call this. - * - * This call may not be used in a non-sleeping context. - */ -struct usb_device *usb_alloc_dev(struct usb_device *parent, - struct usb_bus *bus, unsigned port1) -{ - struct usb_device *dev; - struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self); - unsigned root_hub = 0; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return NULL; - - if (!usb_get_hcd(bus_to_hcd(bus))) { - 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; - dev->dev.type = &usb_device_type; - dev->dev.groups = usb_device_groups; - dev->dev.dma_mask = bus->controller->dma_mask; - set_dev_node(&dev->dev, dev_to_node(bus->controller)); - dev->state = USB_STATE_ATTACHED; - atomic_set(&dev->urbnum, 0); - - INIT_LIST_HEAD(&dev->ep0.urb_list); - dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE; - dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT; - /* ep0 maxpacket comes later, from device descriptor */ - usb_enable_endpoint(dev, &dev->ep0, false); - dev->can_submit = 1; - - /* Save readable and stable topology id, distinguishing devices - * by location for diagnostics, tools, driver model, etc. The - * string is a path along hub ports, from the root. Each device's - * dev->devpath will be stable until USB is re-cabled, and hubs - * are often labeled with these port numbers. The name isn't - * as stable: bus->busnum changes easily from modprobe order, - * cardbus or pci hotplugging, and so on. - */ - 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') { - snprintf(dev->devpath, sizeof dev->devpath, - "%d", port1); - /* Root ports are not counted in route string */ - dev->route = 0; - } else { - snprintf(dev->devpath, sizeof dev->devpath, - "%s.%d", parent->devpath, port1); - /* Route string assumes hubs have less than 16 ports */ - if (port1 < 15) - dev->route = parent->route + - (port1 << ((parent->level - 1)*4)); - else - dev->route = parent->route + - (15 << ((parent->level - 1)*4)); - } - - dev->dev.parent = &parent->dev; - dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath); - - /* hub driver sets up TT records */ - } - - dev->portnum = port1; - dev->bus = bus; - dev->parent = parent; - INIT_LIST_HEAD(&dev->filelist); - -#ifdef CONFIG_PM - pm_runtime_set_autosuspend_delay(&dev->dev, - usb_autosuspend_delay * 1000); - dev->connect_time = jiffies; - dev->active_duration = -jiffies; -#endif - if (root_hub) /* Root hub always ok [and always wired] */ - dev->authorized = 1; - else { - dev->authorized = usb_hcd->authorized_default; - dev->wusb = usb_bus_is_wusb(bus)? 1 : 0; - } - return dev; -} - -/** - * usb_get_dev - increments the reference count of the usb device structure - * @dev: the device being referenced - * - * Each live reference to a device should be refcounted. - * - * Drivers for USB interfaces should normally record such references in - * their probe() methods, when they bind to an interface, and release - * them by calling usb_put_dev(), in their disconnect() methods. - * - * A pointer to the device with the incremented reference counter is returned. - */ -struct usb_device *usb_get_dev(struct usb_device *dev) -{ - if (dev) - get_device(&dev->dev); - return dev; -} -EXPORT_SYMBOL_GPL(usb_get_dev); - -/** - * usb_put_dev - release a use of the usb device structure - * @dev: device that's been disconnected - * - * Must be called when a user of a device is finished with it. When the last - * user of the device calls this function, the memory of the device is freed. - */ -void usb_put_dev(struct usb_device *dev) -{ - if (dev) - put_device(&dev->dev); -} -EXPORT_SYMBOL_GPL(usb_put_dev); - -/** - * usb_get_intf - increments the reference count of the usb interface structure - * @intf: the interface being referenced - * - * Each live reference to a interface must be refcounted. - * - * Drivers for USB interfaces should normally record such references in - * their probe() methods, when they bind to an interface, and release - * them by calling usb_put_intf(), in their disconnect() methods. - * - * A pointer to the interface with the incremented reference counter is - * returned. - */ -struct usb_interface *usb_get_intf(struct usb_interface *intf) -{ - if (intf) - get_device(&intf->dev); - return intf; -} -EXPORT_SYMBOL_GPL(usb_get_intf); - -/** - * usb_put_intf - release a use of the usb interface structure - * @intf: interface that's been decremented - * - * Must be called when a user of an interface is finished with it. When the - * last user of the interface calls this function, the memory of the interface - * is freed. - */ -void usb_put_intf(struct usb_interface *intf) -{ - if (intf) - put_device(&intf->dev); -} -EXPORT_SYMBOL_GPL(usb_put_intf); - -/* USB device locking - * - * USB devices and interfaces are locked using the semaphore in their - * embedded struct device. The hub driver guarantees that whenever a - * device is connected or disconnected, drivers are called with the - * USB device locked as well as their particular interface. - * - * Complications arise when several devices are to be locked at the same - * time. Only hub-aware drivers that are part of usbcore ever have to - * do this; nobody else needs to worry about it. The rule for locking - * is simple: - * - * When locking both a device and its parent, always lock the - * the parent first. - */ - -/** - * usb_lock_device_for_reset - cautiously acquire the lock for a usb device structure - * @udev: device that's being locked - * @iface: interface bound to the driver making the request (optional) - * - * Attempts to acquire the device lock, but fails if the device is - * NOTATTACHED or SUSPENDED, or if iface is specified and the interface - * is neither BINDING nor BOUND. Rather than sleeping to wait for the - * lock, the routine polls repeatedly. This is to prevent deadlock with - * disconnect; in some drivers (such as usb-storage) the disconnect() - * or suspend() method will block waiting for a device reset to complete. - * - * Returns a negative error code for failure, otherwise 0. - */ -int usb_lock_device_for_reset(struct usb_device *udev, - const struct usb_interface *iface) -{ - unsigned long jiffies_expire = jiffies + HZ; - - if (udev->state == USB_STATE_NOTATTACHED) - return -ENODEV; - if (udev->state == USB_STATE_SUSPENDED) - return -EHOSTUNREACH; - if (iface && (iface->condition == USB_INTERFACE_UNBINDING || - iface->condition == USB_INTERFACE_UNBOUND)) - return -EINTR; - - while (!usb_trylock_device(udev)) { - - /* If we can't acquire the lock after waiting one second, - * we're probably deadlocked */ - if (time_after(jiffies, jiffies_expire)) - return -EBUSY; - - msleep(15); - if (udev->state == USB_STATE_NOTATTACHED) - return -ENODEV; - if (udev->state == USB_STATE_SUSPENDED) - return -EHOSTUNREACH; - if (iface && (iface->condition == USB_INTERFACE_UNBINDING || - iface->condition == USB_INTERFACE_UNBOUND)) - return -EINTR; - } - return 0; -} -EXPORT_SYMBOL_GPL(usb_lock_device_for_reset); - -/** - * usb_get_current_frame_number - return current bus frame number - * @dev: the device whose bus is being queried - * - * Returns the current frame number for the USB host controller - * used with the given USB device. This can be used when scheduling - * isochronous requests. - * - * Note that different kinds of host controller have different - * "scheduling horizons". While one type might support scheduling only - * 32 frames into the future, others could support scheduling up to - * 1024 frames into the future. - */ -int usb_get_current_frame_number(struct usb_device *dev) -{ - return usb_hcd_get_frame_number(dev); -} -EXPORT_SYMBOL_GPL(usb_get_current_frame_number); - -/*-------------------------------------------------------------------*/ -/* - * __usb_get_extra_descriptor() finds a descriptor of specific type in the - * extra field of the interface and endpoint descriptor structs. - */ - -int __usb_get_extra_descriptor(char *buffer, unsigned size, - unsigned char type, void **ptr) -{ - struct usb_descriptor_header *header; - - while (size >= sizeof(struct usb_descriptor_header)) { - header = (struct usb_descriptor_header *)buffer; - - if (header->bLength < 2) { - printk(KERN_ERR - "%s: bogus descriptor, type %d length %d\n", - usbcore_name, - header->bDescriptorType, - header->bLength); - return -1; - } - - if (header->bDescriptorType == type) { - *ptr = header; - return 0; - } - - buffer += header->bLength; - size -= header->bLength; - } - return -1; -} -EXPORT_SYMBOL_GPL(__usb_get_extra_descriptor); - -/** - * usb_alloc_coherent - allocate dma-consistent buffer for URB_NO_xxx_DMA_MAP - * @dev: device the buffer will be used with - * @size: requested buffer size - * @mem_flags: affect whether allocation may block - * @dma: used to return DMA address of buffer - * - * Return value is either null (indicating no buffer could be allocated), or - * the cpu-space pointer to a buffer that may be used to perform DMA to the - * specified device. Such cpu-space buffers are returned along with the DMA - * address (through the pointer provided). - * - * These buffers are used with URB_NO_xxx_DMA_MAP set in urb->transfer_flags - * to avoid behaviors like using "DMA bounce buffers", or thrashing IOMMU - * hardware during URB completion/resubmit. The implementation varies between - * platforms, depending on details of how DMA will work to this device. - * Using these buffers also eliminates cacheline sharing problems on - * architectures where CPU caches are not DMA-coherent. On systems without - * bus-snooping caches, these buffers are uncached. - * - * When the buffer is no longer used, free it with usb_free_coherent(). - */ -void *usb_alloc_coherent(struct usb_device *dev, size_t size, gfp_t mem_flags, - dma_addr_t *dma) -{ - if (!dev || !dev->bus) - return NULL; - return hcd_buffer_alloc(dev->bus, size, mem_flags, dma); -} -EXPORT_SYMBOL_GPL(usb_alloc_coherent); - -/** - * usb_free_coherent - free memory allocated with usb_alloc_coherent() - * @dev: device the buffer was used with - * @size: requested buffer size - * @addr: CPU address of buffer - * @dma: DMA address of buffer - * - * This reclaims an I/O buffer, letting it be reused. The memory must have - * been allocated using usb_alloc_coherent(), and the parameters must match - * those provided in that allocation request. - */ -void usb_free_coherent(struct usb_device *dev, size_t size, void *addr, - dma_addr_t dma) -{ - if (!dev || !dev->bus) - return; - if (!addr) - return; - hcd_buffer_free(dev->bus, size, addr, dma); -} -EXPORT_SYMBOL_GPL(usb_free_coherent); - -/** - * usb_buffer_map - create DMA mapping(s) for an urb - * @urb: urb whose transfer_buffer/setup_packet will be mapped - * - * Return value is either null (indicating no buffer could be mapped), or - * the parameter. URB_NO_TRANSFER_DMA_MAP is - * added to urb->transfer_flags if the operation succeeds. If the device - * is connected to this system through a non-DMA controller, this operation - * always succeeds. - * - * This call would normally be used for an urb which is reused, perhaps - * as the target of a large periodic transfer, with usb_buffer_dmasync() - * calls to synchronize memory and dma state. - * - * Reverse the effect of this call with usb_buffer_unmap(). - */ -#if 0 -struct urb *usb_buffer_map(struct urb *urb) -{ - struct usb_bus *bus; - struct device *controller; - - if (!urb - || !urb->dev - || !(bus = urb->dev->bus) - || !(controller = bus->controller)) - return NULL; - - if (controller->dma_mask) { - urb->transfer_dma = dma_map_single(controller, - urb->transfer_buffer, urb->transfer_buffer_length, - usb_pipein(urb->pipe) - ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - /* FIXME generic api broken like pci, can't report errors */ - /* if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; */ - } else - urb->transfer_dma = ~0; - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - return urb; -} -EXPORT_SYMBOL_GPL(usb_buffer_map); -#endif /* 0 */ - -/* XXX DISABLED, no users currently. If you wish to re-enable this - * XXX please determine whether the sync is to transfer ownership of - * XXX the buffer from device to cpu or vice verse, and thusly use the - * XXX appropriate _for_{cpu,device}() method. -DaveM - */ -#if 0 - -/** - * usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s) - * @urb: urb whose transfer_buffer/setup_packet will be synchronized - */ -void usb_buffer_dmasync(struct urb *urb) -{ - struct usb_bus *bus; - struct device *controller; - - if (!urb - || !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) - || !urb->dev - || !(bus = urb->dev->bus) - || !(controller = bus->controller)) - return; - - if (controller->dma_mask) { - 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_for_cpu(controller, - urb->setup_dma, - sizeof(struct usb_ctrlrequest), - DMA_TO_DEVICE); - } -} -EXPORT_SYMBOL_GPL(usb_buffer_dmasync); -#endif - -/** - * usb_buffer_unmap - free DMA mapping(s) for an urb - * @urb: urb whose transfer_buffer will be unmapped - * - * Reverses the effect of usb_buffer_map(). - */ -#if 0 -void usb_buffer_unmap(struct urb *urb) -{ - struct usb_bus *bus; - struct device *controller; - - if (!urb - || !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) - || !urb->dev - || !(bus = urb->dev->bus) - || !(controller = bus->controller)) - return; - - if (controller->dma_mask) { - dma_unmap_single(controller, - urb->transfer_dma, urb->transfer_buffer_length, - usb_pipein(urb->pipe) - ? DMA_FROM_DEVICE : DMA_TO_DEVICE); - } - urb->transfer_flags &= ~URB_NO_TRANSFER_DMA_MAP; -} -EXPORT_SYMBOL_GPL(usb_buffer_unmap); -#endif /* 0 */ - -#if 0 -/** - * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint - * @dev: device to which the scatterlist will be mapped - * @is_in: mapping transfer direction - * @sg: the scatterlist to map - * @nents: the number of entries in the scatterlist - * - * Return value is either < 0 (indicating no buffers could be mapped), or - * the number of DMA mapping array entries in the scatterlist. - * - * The caller is responsible for placing the resulting DMA addresses from - * the scatterlist into URB transfer buffer pointers, and for setting the - * URB_NO_TRANSFER_DMA_MAP transfer flag in each of those URBs. - * - * Top I/O rates come from queuing URBs, instead of waiting for each one - * to complete before starting the next I/O. This is particularly easy - * to do with scatterlists. Just allocate and submit one URB for each DMA - * mapping entry returned, stopping on the first error or when all succeed. - * Better yet, use the usb_sg_*() calls, which do that (and more) for you. - * - * This call would normally be used when translating scatterlist requests, - * rather than usb_buffer_map(), since on some hardware (with IOMMUs) it - * may be able to coalesce mappings for improved I/O efficiency. - * - * Reverse the effect of this call with usb_buffer_unmap_sg(). - */ -int usb_buffer_map_sg(const struct usb_device *dev, int is_in, - struct scatterlist *sg, int nents) -{ - struct usb_bus *bus; - struct device *controller; - - if (!dev - || !(bus = dev->bus) - || !(controller = bus->controller) - || !controller->dma_mask) - return -EINVAL; - - /* FIXME generic api broken like pci, can't report errors */ - return dma_map_sg(controller, sg, nents, - is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE) ? : -ENOMEM; -} -EXPORT_SYMBOL_GPL(usb_buffer_map_sg); -#endif - -/* XXX DISABLED, no users currently. If you wish to re-enable this - * XXX please determine whether the sync is to transfer ownership of - * XXX the buffer from device to cpu or vice verse, and thusly use the - * XXX appropriate _for_{cpu,device}() method. -DaveM - */ -#if 0 - -/** - * usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s) - * @dev: device to which the scatterlist will be mapped - * @is_in: mapping transfer direction - * @sg: the scatterlist to synchronize - * @n_hw_ents: the positive return value from usb_buffer_map_sg - * - * Use this when you are re-using a scatterlist's data buffers for - * another USB request. - */ -void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in, - struct scatterlist *sg, int n_hw_ents) -{ - struct usb_bus *bus; - struct device *controller; - - if (!dev - || !(bus = dev->bus) - || !(controller = bus->controller) - || !controller->dma_mask) - return; - - 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 - -#if 0 -/** - * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist - * @dev: device to which the scatterlist will be mapped - * @is_in: mapping transfer direction - * @sg: the scatterlist to unmap - * @n_hw_ents: the positive return value from usb_buffer_map_sg - * - * Reverses the effect of usb_buffer_map_sg(). - */ -void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in, - struct scatterlist *sg, int n_hw_ents) -{ - struct usb_bus *bus; - struct device *controller; - - if (!dev - || !(bus = dev->bus) - || !(controller = bus->controller) - || !controller->dma_mask) - return; - - dma_unmap_sg(controller, sg, n_hw_ents, - is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); -} -EXPORT_SYMBOL_GPL(usb_buffer_unmap_sg); -#endif - -/* To disable USB, kernel command line is 'nousb' not 'usbcore.nousb' */ -#ifdef MODULE -module_param(nousb, bool, 0444); -#else -core_param(nousb, nousb, bool, 0444); -#endif - -/* - * for external read access to - */ -int usb_disabled(void) -{ - return nousb; -} -EXPORT_SYMBOL_GPL(usb_disabled); - -/* - * Notifications of device and interface registration - */ -static int usb_bus_notify(struct notifier_block *nb, unsigned long action, - void *data) -{ - struct device *dev = data; - - switch (action) { - case BUS_NOTIFY_ADD_DEVICE: - if (dev->type == &usb_device_type) - (void) usb_create_sysfs_dev_files(to_usb_device(dev)); - else if (dev->type == &usb_if_device_type) - usb_create_sysfs_intf_files(to_usb_interface(dev)); - break; - - case BUS_NOTIFY_DEL_DEVICE: - if (dev->type == &usb_device_type) - usb_remove_sysfs_dev_files(to_usb_device(dev)); - else if (dev->type == &usb_if_device_type) - usb_remove_sysfs_intf_files(to_usb_interface(dev)); - break; - } - return 0; -} - -static struct notifier_block usb_bus_nb = { - .notifier_call = usb_bus_notify, -}; - -struct dentry *usb_debug_root; -EXPORT_SYMBOL_GPL(usb_debug_root); - -static 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); -} - -unsigned char usb_sus = 0; -extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); - -/* - * Init - */ - -extern char enable_uhci0_wake; -extern char enable_uhci1_wake; -extern char enable_ehci_wake ; - -char enable_ehci_disc_wakeup = 0; - -static int __init usb_init(void) -{ - - int retval; - - char usb_env_pmc_name[] = "wmt.pmc.param"; - char usb_env_pmc_val[120] = "0"; - int varpmclen = 120; - unsigned int usb_pmc_param[7]; - - if(wmt_getsyspara(usb_env_pmc_name, usb_env_pmc_val, &varpmclen) == 0) { - sscanf(usb_env_pmc_val,"%X:%X:%X:%X:%X:%X:%X", &usb_pmc_param[0],&usb_pmc_param[1], - &usb_pmc_param[2],&usb_pmc_param[3],&usb_pmc_param[4],&usb_pmc_param[5],&usb_pmc_param[6]); - printk("*** uhci_hcd_init usb_param[0] =%x ,usb_param[1]=%x ,usb_param[2]=%x ,usb_param[3]=%x ,usb_param[4]=%x, usb_param[5]=%x, usb_param[6]=%x\n" - ,usb_pmc_param[0],usb_pmc_param[1],usb_pmc_param[2],usb_pmc_param[3],usb_pmc_param[4] - ,usb_pmc_param[5],usb_pmc_param[6]); - if (usb_pmc_param[0]) { - if(usb_pmc_param[1] & 0x00100000) { - enable_ehci_wake = 1; - //printk("usb_storage_id =%x , it should be small than or equal 4 .\n",usb_storage_id); - } else { - enable_ehci_wake = 0;// default port B - } - if (usb_pmc_param[5] & 0x1) - enable_uhci0_wake = 1; - else - enable_uhci0_wake = 0; - if (usb_pmc_param[5] & 0x2) - enable_uhci1_wake = 1; - else - enable_uhci1_wake = 0; - if (usb_pmc_param[6] & 0x1) - enable_ehci_disc_wakeup = 1; - } else { - enable_ehci_wake = 0; - enable_uhci1_wake = 0; - enable_uhci0_wake = 0; - } - } - - if (nousb) { - pr_info("%s: USB support disabled\n", usbcore_name); - return 0; - } - - retval = usb_debugfs_init(); - if (retval) - goto out; - - retval = bus_register(&usb_bus_type); - if (retval) - goto bus_register_failed; - retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb); - if (retval) - goto bus_notifier_failed; - retval = usb_major_init(); - if (retval) - goto major_init_failed; - retval = usb_register(&usbfs_driver); - if (retval) - goto driver_register_failed; - retval = usb_devio_init(); - if (retval) - goto usb_devio_init_failed; - retval = usbfs_init(); - if (retval) - goto fs_init_failed; - retval = usb_hub_init(); - if (retval) - goto hub_init_failed; - retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE); - if (!retval) - goto out; - - usb_hub_cleanup(); -hub_init_failed: - usbfs_cleanup(); -fs_init_failed: - usb_devio_cleanup(); -usb_devio_init_failed: - usb_deregister(&usbfs_driver); -driver_register_failed: - usb_major_cleanup(); -major_init_failed: - bus_unregister_notifier(&usb_bus_type, &usb_bus_nb); -bus_notifier_failed: - bus_unregister(&usb_bus_type); -bus_register_failed: - usb_debugfs_cleanup(); -out: - return retval; -} - -/* - * Cleanup - */ -static void __exit usb_exit(void) -{ - /* This will matter if shutdown/reboot does exitcalls. */ - if (nousb) - return; - - usb_deregister_device_driver(&usb_generic_driver); - usb_major_cleanup(); - usbfs_cleanup(); - usb_deregister(&usbfs_driver); - usb_devio_cleanup(); - usb_hub_cleanup(); - bus_unregister_notifier(&usb_bus_type, &usb_bus_nb); - bus_unregister(&usb_bus_type); - usb_debugfs_cleanup(); -} - -subsys_initcall(usb_init); -module_exit(usb_exit); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/core/usb.h b/ANDROID_3.4.5/drivers/usb/core/usb.h deleted file mode 100644 index 71648dcb..00000000 --- a/ANDROID_3.4.5/drivers/usb/core/usb.h +++ /dev/null @@ -1,158 +0,0 @@ -#include - -/* Functions local to drivers/usb/core/ */ - -extern int usb_create_sysfs_dev_files(struct usb_device *dev); -extern void usb_remove_sysfs_dev_files(struct usb_device *dev); -extern void usb_create_sysfs_intf_files(struct usb_interface *intf); -extern void usb_remove_sysfs_intf_files(struct usb_interface *intf); -extern int usb_create_ep_devs(struct device *parent, - struct usb_host_endpoint *endpoint, - struct usb_device *udev); -extern void usb_remove_ep_devs(struct usb_host_endpoint *endpoint); - -extern void usb_enable_endpoint(struct usb_device *dev, - struct usb_host_endpoint *ep, bool reset_toggle); -extern void usb_enable_interface(struct usb_device *dev, - struct usb_interface *intf, bool reset_toggles); -extern void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr, - bool reset_hardware); -extern void usb_disable_interface(struct usb_device *dev, - struct usb_interface *intf, bool reset_hardware); -extern void usb_release_interface_cache(struct kref *ref); -extern void usb_disable_device(struct usb_device *dev, int skip_ep0); -extern int usb_deauthorize_device(struct usb_device *); -extern int usb_authorize_device(struct usb_device *); -extern void usb_detect_quirks(struct usb_device *udev); -extern int usb_remove_device(struct usb_device *udev); - -extern int usb_get_device_descriptor(struct usb_device *dev, - unsigned int size); -extern int usb_get_bos_descriptor(struct usb_device *dev); -extern void usb_release_bos_descriptor(struct usb_device *dev); -extern char *usb_cache_string(struct usb_device *udev, int index); -extern int usb_set_configuration(struct usb_device *dev, int configuration); -extern int usb_choose_configuration(struct usb_device *udev); - -extern void usb_kick_khubd(struct usb_device *dev); -extern int usb_match_device(struct usb_device *dev, - const struct usb_device_id *id); -extern void usb_forced_unbind_intf(struct usb_interface *intf); -extern void usb_rebind_intf(struct usb_interface *intf); - -extern int usb_hub_claim_port(struct usb_device *hdev, unsigned port, - void *owner); -extern int usb_hub_release_port(struct usb_device *hdev, unsigned port, - void *owner); -extern void usb_hub_release_all_ports(struct usb_device *hdev, void *owner); -extern bool usb_device_is_owned(struct usb_device *udev); - -extern int usb_hub_init(void); -extern void usb_hub_cleanup(void); -extern int usb_major_init(void); -extern void usb_major_cleanup(void); - -#ifdef CONFIG_PM - -extern int usb_suspend(struct device *dev, pm_message_t msg); -extern int usb_resume(struct device *dev, pm_message_t msg); -extern int usb_resume_complete(struct device *dev); - -extern int usb_port_suspend(struct usb_device *dev, pm_message_t msg); -extern int usb_port_resume(struct usb_device *dev, pm_message_t msg); - -#else - -static inline int usb_port_suspend(struct usb_device *udev, pm_message_t msg) -{ - return 0; -} - -static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg) -{ - return 0; -} - -#endif - -#ifdef CONFIG_USB_SUSPEND - -extern void usb_autosuspend_device(struct usb_device *udev); -extern int usb_autoresume_device(struct usb_device *udev); -extern int usb_remote_wakeup(struct usb_device *dev); -extern int usb_runtime_suspend(struct device *dev); -extern int usb_runtime_resume(struct device *dev); -extern int usb_runtime_idle(struct device *dev); -extern int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable); - -#else - -#define usb_autosuspend_device(udev) do {} while (0) -static inline int usb_autoresume_device(struct usb_device *udev) -{ - return 0; -} - -static inline int usb_remote_wakeup(struct usb_device *udev) -{ - return 0; -} - -static inline int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable) -{ - return 0; -} -#endif - -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) -{ - 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) -{ - return container_of(drv, struct usbdrv_wrap, driver)-> - for_devices; -} - -/* for labeling diagnostics */ -extern const char *usbcore_name; - -/* sysfs stuff */ -extern const struct attribute_group *usb_device_groups[]; -extern const struct attribute_group *usb_interface_groups[]; - -/* usbfs stuff */ -extern struct mutex usbfs_mutex; -extern struct usb_driver usbfs_driver; -extern const struct file_operations usbfs_devices_fops; -extern const struct file_operations usbdev_file_operations; -extern void usbfs_conn_disc_event(void); - -extern int usb_devio_init(void); -extern void usb_devio_cleanup(void); - -/* internal notify stuff */ -extern void usb_notify_add_device(struct usb_device *udev); -extern void usb_notify_remove_device(struct usb_device *udev); -extern void usb_notify_add_bus(struct usb_bus *ubus); -extern void usb_notify_remove_bus(struct usb_bus *ubus); - diff --git a/ANDROID_3.4.5/drivers/usb/dwc3/Kconfig b/ANDROID_3.4.5/drivers/usb/dwc3/Kconfig deleted file mode 100644 index d8f741f9..00000000 --- a/ANDROID_3.4.5/drivers/usb/dwc3/Kconfig +++ /dev/null @@ -1,28 +0,0 @@ -config USB_DWC3 - tristate "DesignWare USB3 DRD Core Support" - depends on (USB && USB_GADGET) - select USB_OTG_UTILS - select USB_GADGET_DUALSPEED - select USB_GADGET_SUPERSPEED - select USB_XHCI_PLATFORM - help - Say Y or M here if your system has a Dual Role SuperSpeed - USB controller based on the DesignWare USB3 IP Core. - - If you choose to build this driver is a dynamically linked - module, the module will be called dwc3.ko. - -if USB_DWC3 - -config USB_DWC3_DEBUG - bool "Enable Debugging Messages" - help - Say Y here to enable debugging messages on DWC3 Driver. - -config USB_DWC3_VERBOSE - bool "Enable Verbose Debugging Messages" - depends on USB_DWC3_DEBUG - help - Say Y here to enable verbose debugging messages on DWC3 Driver. - -endif diff --git a/ANDROID_3.4.5/drivers/usb/dwc3/Makefile b/ANDROID_3.4.5/drivers/usb/dwc3/Makefile deleted file mode 100644 index d441fe4c..00000000 --- a/ANDROID_3.4.5/drivers/usb/dwc3/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -ccflags-$(CONFIG_USB_DWC3_DEBUG) := -DDEBUG -ccflags-$(CONFIG_USB_DWC3_VERBOSE) += -DVERBOSE_DEBUG - -obj-$(CONFIG_USB_DWC3) += dwc3.o - -dwc3-y := core.o -dwc3-y += host.o -dwc3-y += gadget.o ep0.o - -ifneq ($(CONFIG_DEBUG_FS),) - dwc3-y += debugfs.o -endif - -## -# Platform-specific glue layers go here -# -# NOTICE: Make sure your glue layer doesn't depend on anything -# which is arch-specific and that it compiles on all situations. -# -# We want to keep this requirement in order to be able to compile -# the entire driver (with all its glue layers) on several architectures -# and make sure it compiles fine. This will also help with allmodconfig -# and allyesconfig builds. -# -# The only exception is the PCI glue layer, but that's only because -# PCI doesn't provide nops if CONFIG_PCI isn't enabled. -## - -obj-$(CONFIG_USB_DWC3) += dwc3-omap.o - -## -# REVISIT Samsung Exynos platform needs the clk API which isn't -# defined on all architectures. If we allow dwc3-exynos.c compile -# always we will fail the linking phase on those architectures -# which don't provide clk api implementation and that's unnaceptable. -# -# When Samsung's platform start supporting pm_runtime, this check -# for HAVE_CLK should be removed. -## -ifneq ($(CONFIG_HAVE_CLK),) - obj-$(CONFIG_USB_DWC3) += dwc3-exynos.o -endif - -ifneq ($(CONFIG_PCI),) - obj-$(CONFIG_USB_DWC3) += dwc3-pci.o -endif - diff --git a/ANDROID_3.4.5/drivers/usb/dwc3/core.c b/ANDROID_3.4.5/drivers/usb/dwc3/core.c deleted file mode 100644 index 99b58d84..00000000 --- a/ANDROID_3.4.5/drivers/usb/dwc3/core.c +++ /dev/null @@ -1,605 +0,0 @@ -/** - * core.c - DesignWare USB3 DRD Controller Core file - * - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com - * - * Authors: Felipe Balbi , - * Sebastian Andrzej Siewior - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "core.h" -#include "gadget.h" -#include "io.h" - -#include "debug.h" - -static char *maximum_speed = "super"; -module_param(maximum_speed, charp, 0); -MODULE_PARM_DESC(maximum_speed, "Maximum supported speed."); - -/* -------------------------------------------------------------------------- */ - -#define DWC3_DEVS_POSSIBLE 32 - -static DECLARE_BITMAP(dwc3_devs, DWC3_DEVS_POSSIBLE); - -int dwc3_get_device_id(void) -{ - int id; - -again: - id = find_first_zero_bit(dwc3_devs, DWC3_DEVS_POSSIBLE); - if (id < DWC3_DEVS_POSSIBLE) { - int old; - - old = test_and_set_bit(id, dwc3_devs); - if (old) - goto again; - } else { - pr_err("dwc3: no space for new device\n"); - id = -ENOMEM; - } - - return id; -} -EXPORT_SYMBOL_GPL(dwc3_get_device_id); - -void dwc3_put_device_id(int id) -{ - int ret; - - if (id < 0) - return; - - ret = test_bit(id, dwc3_devs); - WARN(!ret, "dwc3: ID %d not in use\n", id); - clear_bit(id, dwc3_devs); -} -EXPORT_SYMBOL_GPL(dwc3_put_device_id); - -void dwc3_set_mode(struct dwc3 *dwc, u32 mode) -{ - u32 reg; - - reg = dwc3_readl(dwc->regs, DWC3_GCTL); - reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); - reg |= DWC3_GCTL_PRTCAPDIR(mode); - dwc3_writel(dwc->regs, DWC3_GCTL, reg); -} - -/** - * dwc3_core_soft_reset - Issues core soft reset and PHY reset - * @dwc: pointer to our context structure - */ -static void dwc3_core_soft_reset(struct dwc3 *dwc) -{ - u32 reg; - - /* Before Resetting PHY, put Core in Reset */ - reg = dwc3_readl(dwc->regs, DWC3_GCTL); - reg |= DWC3_GCTL_CORESOFTRESET; - dwc3_writel(dwc->regs, DWC3_GCTL, reg); - - /* Assert USB3 PHY reset */ - reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); - reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST; - dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); - - /* Assert USB2 PHY reset */ - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); - reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST; - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); - - mdelay(100); - - /* Clear USB3 PHY reset */ - reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); - reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST; - dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); - - /* Clear USB2 PHY reset */ - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); - reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST; - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); - - /* After PHYs are stable we can take Core out of reset state */ - reg = dwc3_readl(dwc->regs, DWC3_GCTL); - reg &= ~DWC3_GCTL_CORESOFTRESET; - dwc3_writel(dwc->regs, DWC3_GCTL, reg); -} - -/** - * dwc3_free_one_event_buffer - Frees one event buffer - * @dwc: Pointer to our controller context structure - * @evt: Pointer to event buffer to be freed - */ -static void dwc3_free_one_event_buffer(struct dwc3 *dwc, - struct dwc3_event_buffer *evt) -{ - dma_free_coherent(dwc->dev, evt->length, evt->buf, evt->dma); - kfree(evt); -} - -/** - * dwc3_alloc_one_event_buffer - Allocates one event buffer structure - * @dwc: Pointer to our controller context structure - * @length: size of the event buffer - * - * Returns a pointer to the allocated event buffer structure on success - * otherwise ERR_PTR(errno). - */ -static struct dwc3_event_buffer *__devinit -dwc3_alloc_one_event_buffer(struct dwc3 *dwc, unsigned length) -{ - struct dwc3_event_buffer *evt; - - evt = kzalloc(sizeof(*evt), GFP_KERNEL); - if (!evt) - return ERR_PTR(-ENOMEM); - - evt->dwc = dwc; - evt->length = length; - evt->buf = dma_alloc_coherent(dwc->dev, length, - &evt->dma, GFP_KERNEL); - if (!evt->buf) { - kfree(evt); - return ERR_PTR(-ENOMEM); - } - - return evt; -} - -/** - * dwc3_free_event_buffers - frees all allocated event buffers - * @dwc: Pointer to our controller context structure - */ -static void dwc3_free_event_buffers(struct dwc3 *dwc) -{ - struct dwc3_event_buffer *evt; - int i; - - for (i = 0; i < dwc->num_event_buffers; i++) { - evt = dwc->ev_buffs[i]; - if (evt) - dwc3_free_one_event_buffer(dwc, evt); - } - - kfree(dwc->ev_buffs); -} - -/** - * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length - * @dwc: pointer to our controller context structure - * @length: size of event buffer - * - * Returns 0 on success otherwise negative errno. In the error case, dwc - * may contain some buffers allocated but not all which were requested. - */ -static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) -{ - int num; - int i; - - num = DWC3_NUM_INT(dwc->hwparams.hwparams1); - dwc->num_event_buffers = num; - - dwc->ev_buffs = kzalloc(sizeof(*dwc->ev_buffs) * num, GFP_KERNEL); - if (!dwc->ev_buffs) { - dev_err(dwc->dev, "can't allocate event buffers array\n"); - return -ENOMEM; - } - - for (i = 0; i < num; i++) { - struct dwc3_event_buffer *evt; - - evt = dwc3_alloc_one_event_buffer(dwc, length); - if (IS_ERR(evt)) { - dev_err(dwc->dev, "can't allocate event buffer\n"); - return PTR_ERR(evt); - } - dwc->ev_buffs[i] = evt; - } - - return 0; -} - -/** - * dwc3_event_buffers_setup - setup our allocated event buffers - * @dwc: pointer to our controller context structure - * - * Returns 0 on success otherwise negative errno. - */ -static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc) -{ - struct dwc3_event_buffer *evt; - int n; - - for (n = 0; n < dwc->num_event_buffers; n++) { - evt = dwc->ev_buffs[n]; - dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n", - evt->buf, (unsigned long long) evt->dma, - evt->length); - - dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), - lower_32_bits(evt->dma)); - dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), - upper_32_bits(evt->dma)); - dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), - evt->length & 0xffff); - dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0); - } - - return 0; -} - -static void dwc3_event_buffers_cleanup(struct dwc3 *dwc) -{ - struct dwc3_event_buffer *evt; - int n; - - for (n = 0; n < dwc->num_event_buffers; n++) { - evt = dwc->ev_buffs[n]; - dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0); - dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0); - dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 0); - dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0); - } -} - -static void __devinit dwc3_cache_hwparams(struct dwc3 *dwc) -{ - struct dwc3_hwparams *parms = &dwc->hwparams; - - parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0); - parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1); - parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2); - parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3); - parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4); - parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5); - parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6); - parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7); - parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8); -} - -/** - * dwc3_core_init - Low-level initialization of DWC3 Core - * @dwc: Pointer to our controller context structure - * - * Returns 0 on success otherwise negative errno. - */ -static int __devinit dwc3_core_init(struct dwc3 *dwc) -{ - unsigned long timeout; - u32 reg; - int ret; - - reg = dwc3_readl(dwc->regs, DWC3_GSNPSID); - /* This should read as U3 followed by revision number */ - if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) { - dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); - ret = -ENODEV; - goto err0; - } - dwc->revision = reg; - - dwc3_core_soft_reset(dwc); - - /* issue device SoftReset too */ - timeout = jiffies + msecs_to_jiffies(500); - dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST); - do { - reg = dwc3_readl(dwc->regs, DWC3_DCTL); - if (!(reg & DWC3_DCTL_CSFTRST)) - break; - - if (time_after(jiffies, timeout)) { - dev_err(dwc->dev, "Reset Timed Out\n"); - ret = -ETIMEDOUT; - goto err0; - } - - cpu_relax(); - } while (true); - - dwc3_cache_hwparams(dwc); - - reg = dwc3_readl(dwc->regs, DWC3_GCTL); - reg &= ~DWC3_GCTL_SCALEDOWN_MASK; - reg &= ~DWC3_GCTL_DISSCRAMBLE; - - switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) { - case DWC3_GHWPARAMS1_EN_PWROPT_CLK: - reg &= ~DWC3_GCTL_DSBLCLKGTNG; - break; - default: - dev_dbg(dwc->dev, "No power optimization available\n"); - } - - /* - * WORKAROUND: DWC3 revisions <1.90a have a bug - * where the device can fail to connect at SuperSpeed - * and falls back to high-speed mode which causes - * the device to enter a Connect/Disconnect loop - */ - if (dwc->revision < DWC3_REVISION_190A) - reg |= DWC3_GCTL_U2RSTECN; - - dwc3_writel(dwc->regs, DWC3_GCTL, reg); - - ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); - if (ret) { - dev_err(dwc->dev, "failed to allocate event buffers\n"); - ret = -ENOMEM; - goto err1; - } - - ret = dwc3_event_buffers_setup(dwc); - if (ret) { - dev_err(dwc->dev, "failed to setup event buffers\n"); - goto err1; - } - - return 0; - -err1: - dwc3_free_event_buffers(dwc); - -err0: - return ret; -} - -static void dwc3_core_exit(struct dwc3 *dwc) -{ - dwc3_event_buffers_cleanup(dwc); - dwc3_free_event_buffers(dwc); -} - -#define DWC3_ALIGN_MASK (16 - 1) - -static int __devinit dwc3_probe(struct platform_device *pdev) -{ - struct device_node *node = pdev->dev.of_node; - struct resource *res; - struct dwc3 *dwc; - struct device *dev = &pdev->dev; - - int ret = -ENOMEM; - int irq; - - void __iomem *regs; - void *mem; - - u8 mode; - - mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); - if (!mem) { - dev_err(dev, "not enough memory\n"); - return -ENOMEM; - } - dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1); - dwc->mem = mem; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "missing resource\n"); - return -ENODEV; - } - - dwc->res = res; - - res = devm_request_mem_region(dev, res->start, resource_size(res), - dev_name(dev)); - if (!res) { - dev_err(dev, "can't request mem region\n"); - return -ENOMEM; - } - - regs = devm_ioremap(dev, res->start, resource_size(res)); - if (!regs) { - dev_err(dev, "ioremap failed\n"); - return -ENOMEM; - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(dev, "missing IRQ\n"); - return -ENODEV; - } - - spin_lock_init(&dwc->lock); - platform_set_drvdata(pdev, dwc); - - dwc->regs = regs; - dwc->regs_size = resource_size(res); - dwc->dev = dev; - dwc->irq = irq; - - if (!strncmp("super", maximum_speed, 5)) - dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; - else if (!strncmp("high", maximum_speed, 4)) - dwc->maximum_speed = DWC3_DCFG_HIGHSPEED; - else if (!strncmp("full", maximum_speed, 4)) - dwc->maximum_speed = DWC3_DCFG_FULLSPEED1; - else if (!strncmp("low", maximum_speed, 3)) - dwc->maximum_speed = DWC3_DCFG_LOWSPEED; - else - dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; - - if (of_get_property(node, "tx-fifo-resize", NULL)) - dwc->needs_fifo_resize = true; - - pm_runtime_enable(dev); - pm_runtime_get_sync(dev); - pm_runtime_forbid(dev); - - ret = dwc3_core_init(dwc); - if (ret) { - dev_err(dev, "failed to initialize core\n"); - return ret; - } - - mode = DWC3_MODE(dwc->hwparams.hwparams0); - - switch (mode) { - case DWC3_MODE_DEVICE: - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); - ret = dwc3_gadget_init(dwc); - if (ret) { - dev_err(dev, "failed to initialize gadget\n"); - goto err1; - } - break; - case DWC3_MODE_HOST: - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); - ret = dwc3_host_init(dwc); - if (ret) { - dev_err(dev, "failed to initialize host\n"); - goto err1; - } - break; - case DWC3_MODE_DRD: - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); - ret = dwc3_host_init(dwc); - if (ret) { - dev_err(dev, "failed to initialize host\n"); - goto err1; - } - - ret = dwc3_gadget_init(dwc); - if (ret) { - dev_err(dev, "failed to initialize gadget\n"); - goto err1; - } - break; - default: - dev_err(dev, "Unsupported mode of operation %d\n", mode); - goto err1; - } - dwc->mode = mode; - - ret = dwc3_debugfs_init(dwc); - if (ret) { - dev_err(dev, "failed to initialize debugfs\n"); - goto err2; - } - - pm_runtime_allow(dev); - - return 0; - -err2: - switch (mode) { - case DWC3_MODE_DEVICE: - dwc3_gadget_exit(dwc); - break; - case DWC3_MODE_HOST: - dwc3_host_exit(dwc); - break; - case DWC3_MODE_DRD: - dwc3_host_exit(dwc); - dwc3_gadget_exit(dwc); - break; - default: - /* do nothing */ - break; - } - -err1: - dwc3_core_exit(dwc); - - return ret; -} - -static int __devexit dwc3_remove(struct platform_device *pdev) -{ - struct dwc3 *dwc = platform_get_drvdata(pdev); - struct resource *res; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - pm_runtime_put(&pdev->dev); - pm_runtime_disable(&pdev->dev); - - dwc3_debugfs_exit(dwc); - - switch (dwc->mode) { - case DWC3_MODE_DEVICE: - dwc3_gadget_exit(dwc); - break; - case DWC3_MODE_HOST: - dwc3_host_exit(dwc); - break; - case DWC3_MODE_DRD: - dwc3_host_exit(dwc); - dwc3_gadget_exit(dwc); - break; - default: - /* do nothing */ - break; - } - - dwc3_core_exit(dwc); - - return 0; -} - -static struct platform_driver dwc3_driver = { - .probe = dwc3_probe, - .remove = __devexit_p(dwc3_remove), - .driver = { - .name = "dwc3", - }, -}; - -module_platform_driver(dwc3_driver); - -MODULE_ALIAS("platform:dwc3"); -MODULE_AUTHOR("Felipe Balbi "); -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver"); diff --git a/ANDROID_3.4.5/drivers/usb/dwc3/core.h b/ANDROID_3.4.5/drivers/usb/dwc3/core.h deleted file mode 100644 index 6c7945b4..00000000 --- a/ANDROID_3.4.5/drivers/usb/dwc3/core.h +++ /dev/null @@ -1,784 +0,0 @@ -/** - * core.h - DesignWare USB3 DRD Core Header - * - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com - * - * Authors: Felipe Balbi , - * Sebastian Andrzej Siewior - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __DRIVERS_USB_DWC3_CORE_H -#define __DRIVERS_USB_DWC3_CORE_H - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* Global constants */ -#define DWC3_ENDPOINTS_NUM 32 - -#define DWC3_EVENT_BUFFERS_SIZE PAGE_SIZE -#define DWC3_EVENT_TYPE_MASK 0xfe - -#define DWC3_EVENT_TYPE_DEV 0 -#define DWC3_EVENT_TYPE_CARKIT 3 -#define DWC3_EVENT_TYPE_I2C 4 - -#define DWC3_DEVICE_EVENT_DISCONNECT 0 -#define DWC3_DEVICE_EVENT_RESET 1 -#define DWC3_DEVICE_EVENT_CONNECT_DONE 2 -#define DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE 3 -#define DWC3_DEVICE_EVENT_WAKEUP 4 -#define DWC3_DEVICE_EVENT_EOPF 6 -#define DWC3_DEVICE_EVENT_SOF 7 -#define DWC3_DEVICE_EVENT_ERRATIC_ERROR 9 -#define DWC3_DEVICE_EVENT_CMD_CMPL 10 -#define DWC3_DEVICE_EVENT_OVERFLOW 11 - -#define DWC3_GEVNTCOUNT_MASK 0xfffc -#define DWC3_GSNPSID_MASK 0xffff0000 -#define DWC3_GSNPSREV_MASK 0xffff - -/* Global Registers */ -#define DWC3_GSBUSCFG0 0xc100 -#define DWC3_GSBUSCFG1 0xc104 -#define DWC3_GTXTHRCFG 0xc108 -#define DWC3_GRXTHRCFG 0xc10c -#define DWC3_GCTL 0xc110 -#define DWC3_GEVTEN 0xc114 -#define DWC3_GSTS 0xc118 -#define DWC3_GSNPSID 0xc120 -#define DWC3_GGPIO 0xc124 -#define DWC3_GUID 0xc128 -#define DWC3_GUCTL 0xc12c -#define DWC3_GBUSERRADDR0 0xc130 -#define DWC3_GBUSERRADDR1 0xc134 -#define DWC3_GPRTBIMAP0 0xc138 -#define DWC3_GPRTBIMAP1 0xc13c -#define DWC3_GHWPARAMS0 0xc140 -#define DWC3_GHWPARAMS1 0xc144 -#define DWC3_GHWPARAMS2 0xc148 -#define DWC3_GHWPARAMS3 0xc14c -#define DWC3_GHWPARAMS4 0xc150 -#define DWC3_GHWPARAMS5 0xc154 -#define DWC3_GHWPARAMS6 0xc158 -#define DWC3_GHWPARAMS7 0xc15c -#define DWC3_GDBGFIFOSPACE 0xc160 -#define DWC3_GDBGLTSSM 0xc164 -#define DWC3_GPRTBIMAP_HS0 0xc180 -#define DWC3_GPRTBIMAP_HS1 0xc184 -#define DWC3_GPRTBIMAP_FS0 0xc188 -#define DWC3_GPRTBIMAP_FS1 0xc18c - -#define DWC3_GUSB2PHYCFG(n) (0xc200 + (n * 0x04)) -#define DWC3_GUSB2I2CCTL(n) (0xc240 + (n * 0x04)) - -#define DWC3_GUSB2PHYACC(n) (0xc280 + (n * 0x04)) - -#define DWC3_GUSB3PIPECTL(n) (0xc2c0 + (n * 0x04)) - -#define DWC3_GTXFIFOSIZ(n) (0xc300 + (n * 0x04)) -#define DWC3_GRXFIFOSIZ(n) (0xc380 + (n * 0x04)) - -#define DWC3_GEVNTADRLO(n) (0xc400 + (n * 0x10)) -#define DWC3_GEVNTADRHI(n) (0xc404 + (n * 0x10)) -#define DWC3_GEVNTSIZ(n) (0xc408 + (n * 0x10)) -#define DWC3_GEVNTCOUNT(n) (0xc40c + (n * 0x10)) - -#define DWC3_GHWPARAMS8 0xc600 - -/* Device Registers */ -#define DWC3_DCFG 0xc700 -#define DWC3_DCTL 0xc704 -#define DWC3_DEVTEN 0xc708 -#define DWC3_DSTS 0xc70c -#define DWC3_DGCMDPAR 0xc710 -#define DWC3_DGCMD 0xc714 -#define DWC3_DALEPENA 0xc720 -#define DWC3_DEPCMDPAR2(n) (0xc800 + (n * 0x10)) -#define DWC3_DEPCMDPAR1(n) (0xc804 + (n * 0x10)) -#define DWC3_DEPCMDPAR0(n) (0xc808 + (n * 0x10)) -#define DWC3_DEPCMD(n) (0xc80c + (n * 0x10)) - -/* OTG Registers */ -#define DWC3_OCFG 0xcc00 -#define DWC3_OCTL 0xcc04 -#define DWC3_OEVTEN 0xcc08 -#define DWC3_OSTS 0xcc0C - -/* Bit fields */ - -/* Global Configuration Register */ -#define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19) -#define DWC3_GCTL_U2RSTECN (1 << 16) -#define DWC3_GCTL_RAMCLKSEL(x) (((x) & DWC3_GCTL_CLK_MASK) << 6) -#define DWC3_GCTL_CLK_BUS (0) -#define DWC3_GCTL_CLK_PIPE (1) -#define DWC3_GCTL_CLK_PIPEHALF (2) -#define DWC3_GCTL_CLK_MASK (3) - -#define DWC3_GCTL_PRTCAP(n) (((n) & (3 << 12)) >> 12) -#define DWC3_GCTL_PRTCAPDIR(n) ((n) << 12) -#define DWC3_GCTL_PRTCAP_HOST 1 -#define DWC3_GCTL_PRTCAP_DEVICE 2 -#define DWC3_GCTL_PRTCAP_OTG 3 - -#define DWC3_GCTL_CORESOFTRESET (1 << 11) -#define DWC3_GCTL_SCALEDOWN(n) ((n) << 4) -#define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3) -#define DWC3_GCTL_DISSCRAMBLE (1 << 3) -#define DWC3_GCTL_DSBLCLKGTNG (1 << 0) - -/* Global USB2 PHY Configuration Register */ -#define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31) -#define DWC3_GUSB2PHYCFG_SUSPHY (1 << 6) - -/* Global USB3 PIPE Control Register */ -#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31) -#define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17) - -/* Global TX Fifo Size Register */ -#define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff) -#define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000) - -/* Global HWPARAMS1 Register */ -#define DWC3_GHWPARAMS1_EN_PWROPT(n) (((n) & (3 << 24)) >> 24) -#define DWC3_GHWPARAMS1_EN_PWROPT_NO 0 -#define DWC3_GHWPARAMS1_EN_PWROPT_CLK 1 - -/* Device Configuration Register */ -#define DWC3_DCFG_DEVADDR(addr) ((addr) << 3) -#define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f) - -#define DWC3_DCFG_SPEED_MASK (7 << 0) -#define DWC3_DCFG_SUPERSPEED (4 << 0) -#define DWC3_DCFG_HIGHSPEED (0 << 0) -#define DWC3_DCFG_FULLSPEED2 (1 << 0) -#define DWC3_DCFG_LOWSPEED (2 << 0) -#define DWC3_DCFG_FULLSPEED1 (3 << 0) - -/* Device Control Register */ -#define DWC3_DCTL_RUN_STOP (1 << 31) -#define DWC3_DCTL_CSFTRST (1 << 30) -#define DWC3_DCTL_LSFTRST (1 << 29) - -#define DWC3_DCTL_HIRD_THRES_MASK (0x1f << 24) -#define DWC3_DCTL_HIRD_THRES(n) (((n) & DWC3_DCTL_HIRD_THRES_MASK) >> 24) - -#define DWC3_DCTL_APPL1RES (1 << 23) - -#define DWC3_DCTL_TRGTULST_MASK (0x0f << 17) -#define DWC3_DCTL_TRGTULST(n) ((n) << 17) - -#define DWC3_DCTL_TRGTULST_U2 (DWC3_DCTL_TRGTULST(2)) -#define DWC3_DCTL_TRGTULST_U3 (DWC3_DCTL_TRGTULST(3)) -#define DWC3_DCTL_TRGTULST_SS_DIS (DWC3_DCTL_TRGTULST(4)) -#define DWC3_DCTL_TRGTULST_RX_DET (DWC3_DCTL_TRGTULST(5)) -#define DWC3_DCTL_TRGTULST_SS_INACT (DWC3_DCTL_TRGTULST(6)) - -#define DWC3_DCTL_INITU2ENA (1 << 12) -#define DWC3_DCTL_ACCEPTU2ENA (1 << 11) -#define DWC3_DCTL_INITU1ENA (1 << 10) -#define DWC3_DCTL_ACCEPTU1ENA (1 << 9) -#define DWC3_DCTL_TSTCTRL_MASK (0xf << 1) - -#define DWC3_DCTL_ULSTCHNGREQ_MASK (0x0f << 5) -#define DWC3_DCTL_ULSTCHNGREQ(n) (((n) << 5) & DWC3_DCTL_ULSTCHNGREQ_MASK) - -#define DWC3_DCTL_ULSTCHNG_NO_ACTION (DWC3_DCTL_ULSTCHNGREQ(0)) -#define DWC3_DCTL_ULSTCHNG_SS_DISABLED (DWC3_DCTL_ULSTCHNGREQ(4)) -#define DWC3_DCTL_ULSTCHNG_RX_DETECT (DWC3_DCTL_ULSTCHNGREQ(5)) -#define DWC3_DCTL_ULSTCHNG_SS_INACTIVE (DWC3_DCTL_ULSTCHNGREQ(6)) -#define DWC3_DCTL_ULSTCHNG_RECOVERY (DWC3_DCTL_ULSTCHNGREQ(8)) -#define DWC3_DCTL_ULSTCHNG_COMPLIANCE (DWC3_DCTL_ULSTCHNGREQ(10)) -#define DWC3_DCTL_ULSTCHNG_LOOPBACK (DWC3_DCTL_ULSTCHNGREQ(11)) - -/* Device Event Enable Register */ -#define DWC3_DEVTEN_VNDRDEVTSTRCVEDEN (1 << 12) -#define DWC3_DEVTEN_EVNTOVERFLOWEN (1 << 11) -#define DWC3_DEVTEN_CMDCMPLTEN (1 << 10) -#define DWC3_DEVTEN_ERRTICERREN (1 << 9) -#define DWC3_DEVTEN_SOFEN (1 << 7) -#define DWC3_DEVTEN_EOPFEN (1 << 6) -#define DWC3_DEVTEN_WKUPEVTEN (1 << 4) -#define DWC3_DEVTEN_ULSTCNGEN (1 << 3) -#define DWC3_DEVTEN_CONNECTDONEEN (1 << 2) -#define DWC3_DEVTEN_USBRSTEN (1 << 1) -#define DWC3_DEVTEN_DISCONNEVTEN (1 << 0) - -/* Device Status Register */ -#define DWC3_DSTS_PWRUPREQ (1 << 24) -#define DWC3_DSTS_COREIDLE (1 << 23) -#define DWC3_DSTS_DEVCTRLHLT (1 << 22) - -#define DWC3_DSTS_USBLNKST_MASK (0x0f << 18) -#define DWC3_DSTS_USBLNKST(n) (((n) & DWC3_DSTS_USBLNKST_MASK) >> 18) - -#define DWC3_DSTS_RXFIFOEMPTY (1 << 17) - -#define DWC3_DSTS_SOFFN_MASK (0x3ff << 3) -#define DWC3_DSTS_SOFFN(n) (((n) & DWC3_DSTS_SOFFN_MASK) >> 3) - -#define DWC3_DSTS_CONNECTSPD (7 << 0) - -#define DWC3_DSTS_SUPERSPEED (4 << 0) -#define DWC3_DSTS_HIGHSPEED (0 << 0) -#define DWC3_DSTS_FULLSPEED2 (1 << 0) -#define DWC3_DSTS_LOWSPEED (2 << 0) -#define DWC3_DSTS_FULLSPEED1 (3 << 0) - -/* Device Generic Command Register */ -#define DWC3_DGCMD_SET_LMP 0x01 -#define DWC3_DGCMD_SET_PERIODIC_PAR 0x02 -#define DWC3_DGCMD_XMIT_FUNCTION 0x03 -#define DWC3_DGCMD_SELECTED_FIFO_FLUSH 0x09 -#define DWC3_DGCMD_ALL_FIFO_FLUSH 0x0a -#define DWC3_DGCMD_SET_ENDPOINT_NRDY 0x0c -#define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK 0x10 - -/* Device Endpoint Command Register */ -#define DWC3_DEPCMD_PARAM_SHIFT 16 -#define DWC3_DEPCMD_PARAM(x) ((x) << DWC3_DEPCMD_PARAM_SHIFT) -#define DWC3_DEPCMD_GET_RSC_IDX(x) (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f) -#define DWC3_DEPCMD_STATUS_MASK (0x0f << 12) -#define DWC3_DEPCMD_STATUS(x) (((x) & DWC3_DEPCMD_STATUS_MASK) >> 12) -#define DWC3_DEPCMD_HIPRI_FORCERM (1 << 11) -#define DWC3_DEPCMD_CMDACT (1 << 10) -#define DWC3_DEPCMD_CMDIOC (1 << 8) - -#define DWC3_DEPCMD_DEPSTARTCFG (0x09 << 0) -#define DWC3_DEPCMD_ENDTRANSFER (0x08 << 0) -#define DWC3_DEPCMD_UPDATETRANSFER (0x07 << 0) -#define DWC3_DEPCMD_STARTTRANSFER (0x06 << 0) -#define DWC3_DEPCMD_CLEARSTALL (0x05 << 0) -#define DWC3_DEPCMD_SETSTALL (0x04 << 0) -#define DWC3_DEPCMD_GETSEQNUMBER (0x03 << 0) -#define DWC3_DEPCMD_SETTRANSFRESOURCE (0x02 << 0) -#define DWC3_DEPCMD_SETEPCONFIG (0x01 << 0) - -/* The EP number goes 0..31 so ep0 is always out and ep1 is always in */ -#define DWC3_DALEPENA_EP(n) (1 << n) - -#define DWC3_DEPCMD_TYPE_CONTROL 0 -#define DWC3_DEPCMD_TYPE_ISOC 1 -#define DWC3_DEPCMD_TYPE_BULK 2 -#define DWC3_DEPCMD_TYPE_INTR 3 - -/* Structures */ - -struct dwc3_trb; - -/** - * struct dwc3_event_buffer - Software event buffer representation - * @list: a list of event buffers - * @buf: _THE_ buffer - * @length: size of this buffer - * @dma: dma_addr_t - * @dwc: pointer to DWC controller - */ -struct dwc3_event_buffer { - void *buf; - unsigned length; - unsigned int lpos; - - dma_addr_t dma; - - struct dwc3 *dwc; -}; - -#define DWC3_EP_FLAG_STALLED (1 << 0) -#define DWC3_EP_FLAG_WEDGED (1 << 1) - -#define DWC3_EP_DIRECTION_TX true -#define DWC3_EP_DIRECTION_RX false - -#define DWC3_TRB_NUM 32 -#define DWC3_TRB_MASK (DWC3_TRB_NUM - 1) - -/** - * struct dwc3_ep - device side endpoint representation - * @endpoint: usb endpoint - * @request_list: list of requests for this endpoint - * @req_queued: list of requests on this ep which have TRBs setup - * @trb_pool: array of transaction buffers - * @trb_pool_dma: dma address of @trb_pool - * @free_slot: next slot which is going to be used - * @busy_slot: first slot which is owned by HW - * @desc: usb_endpoint_descriptor pointer - * @dwc: pointer to DWC controller - * @flags: endpoint flags (wedged, stalled, ...) - * @current_trb: index of current used trb - * @number: endpoint number (1 - 15) - * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK - * @res_trans_idx: Resource transfer index - * @interval: the intervall on which the ISOC transfer is started - * @name: a human readable name e.g. ep1out-bulk - * @direction: true for TX, false for RX - * @stream_capable: true when streams are enabled - */ -struct dwc3_ep { - struct usb_ep endpoint; - struct list_head request_list; - struct list_head req_queued; - - struct dwc3_trb *trb_pool; - dma_addr_t trb_pool_dma; - u32 free_slot; - u32 busy_slot; - const struct usb_endpoint_descriptor *desc; - const struct usb_ss_ep_comp_descriptor *comp_desc; - struct dwc3 *dwc; - - unsigned flags; -#define DWC3_EP_ENABLED (1 << 0) -#define DWC3_EP_STALL (1 << 1) -#define DWC3_EP_WEDGE (1 << 2) -#define DWC3_EP_BUSY (1 << 4) -#define DWC3_EP_PENDING_REQUEST (1 << 5) - - /* This last one is specific to EP0 */ -#define DWC3_EP0_DIR_IN (1 << 31) - - unsigned current_trb; - - u8 number; - u8 type; - u8 res_trans_idx; - u32 interval; - - char name[20]; - - unsigned direction:1; - unsigned stream_capable:1; -}; - -enum dwc3_phy { - DWC3_PHY_UNKNOWN = 0, - DWC3_PHY_USB3, - DWC3_PHY_USB2, -}; - -enum dwc3_ep0_next { - DWC3_EP0_UNKNOWN = 0, - DWC3_EP0_COMPLETE, - DWC3_EP0_NRDY_SETUP, - DWC3_EP0_NRDY_DATA, - DWC3_EP0_NRDY_STATUS, -}; - -enum dwc3_ep0_state { - EP0_UNCONNECTED = 0, - EP0_SETUP_PHASE, - EP0_DATA_PHASE, - EP0_STATUS_PHASE, -}; - -enum dwc3_link_state { - /* In SuperSpeed */ - DWC3_LINK_STATE_U0 = 0x00, /* in HS, means ON */ - DWC3_LINK_STATE_U1 = 0x01, - DWC3_LINK_STATE_U2 = 0x02, /* in HS, means SLEEP */ - DWC3_LINK_STATE_U3 = 0x03, /* in HS, means SUSPEND */ - DWC3_LINK_STATE_SS_DIS = 0x04, - DWC3_LINK_STATE_RX_DET = 0x05, /* in HS, means Early Suspend */ - DWC3_LINK_STATE_SS_INACT = 0x06, - DWC3_LINK_STATE_POLL = 0x07, - DWC3_LINK_STATE_RECOV = 0x08, - DWC3_LINK_STATE_HRESET = 0x09, - DWC3_LINK_STATE_CMPLY = 0x0a, - DWC3_LINK_STATE_LPBK = 0x0b, - DWC3_LINK_STATE_MASK = 0x0f, -}; - -enum dwc3_device_state { - DWC3_DEFAULT_STATE, - DWC3_ADDRESS_STATE, - DWC3_CONFIGURED_STATE, -}; - -/* TRB Length, PCM and Status */ -#define DWC3_TRB_SIZE_MASK (0x00ffffff) -#define DWC3_TRB_SIZE_LENGTH(n) ((n) & DWC3_TRB_SIZE_MASK) -#define DWC3_TRB_SIZE_PCM1(n) (((n) & 0x03) << 24) -#define DWC3_TRB_SIZE_TRBSTS(n) (((n) & (0x0f << 28) >> 28)) - -#define DWC3_TRBSTS_OK 0 -#define DWC3_TRBSTS_MISSED_ISOC 1 -#define DWC3_TRBSTS_SETUP_PENDING 2 - -/* TRB Control */ -#define DWC3_TRB_CTRL_HWO (1 << 0) -#define DWC3_TRB_CTRL_LST (1 << 1) -#define DWC3_TRB_CTRL_CHN (1 << 2) -#define DWC3_TRB_CTRL_CSP (1 << 3) -#define DWC3_TRB_CTRL_TRBCTL(n) (((n) & 0x3f) << 4) -#define DWC3_TRB_CTRL_ISP_IMI (1 << 10) -#define DWC3_TRB_CTRL_IOC (1 << 11) -#define DWC3_TRB_CTRL_SID_SOFN(n) (((n) & 0xffff) << 14) - -#define DWC3_TRBCTL_NORMAL DWC3_TRB_CTRL_TRBCTL(1) -#define DWC3_TRBCTL_CONTROL_SETUP DWC3_TRB_CTRL_TRBCTL(2) -#define DWC3_TRBCTL_CONTROL_STATUS2 DWC3_TRB_CTRL_TRBCTL(3) -#define DWC3_TRBCTL_CONTROL_STATUS3 DWC3_TRB_CTRL_TRBCTL(4) -#define DWC3_TRBCTL_CONTROL_DATA DWC3_TRB_CTRL_TRBCTL(5) -#define DWC3_TRBCTL_ISOCHRONOUS_FIRST DWC3_TRB_CTRL_TRBCTL(6) -#define DWC3_TRBCTL_ISOCHRONOUS DWC3_TRB_CTRL_TRBCTL(7) -#define DWC3_TRBCTL_LINK_TRB DWC3_TRB_CTRL_TRBCTL(8) - -/** - * struct dwc3_trb - transfer request block (hw format) - * @bpl: DW0-3 - * @bph: DW4-7 - * @size: DW8-B - * @trl: DWC-F - */ -struct dwc3_trb { - u32 bpl; - u32 bph; - u32 size; - u32 ctrl; -} __packed; - -/** - * dwc3_hwparams - copy of HWPARAMS registers - * @hwparams0 - GHWPARAMS0 - * @hwparams1 - GHWPARAMS1 - * @hwparams2 - GHWPARAMS2 - * @hwparams3 - GHWPARAMS3 - * @hwparams4 - GHWPARAMS4 - * @hwparams5 - GHWPARAMS5 - * @hwparams6 - GHWPARAMS6 - * @hwparams7 - GHWPARAMS7 - * @hwparams8 - GHWPARAMS8 - */ -struct dwc3_hwparams { - u32 hwparams0; - u32 hwparams1; - u32 hwparams2; - u32 hwparams3; - u32 hwparams4; - u32 hwparams5; - u32 hwparams6; - u32 hwparams7; - u32 hwparams8; -}; - -/* HWPARAMS0 */ -#define DWC3_MODE(n) ((n) & 0x7) - -#define DWC3_MODE_DEVICE 0 -#define DWC3_MODE_HOST 1 -#define DWC3_MODE_DRD 2 -#define DWC3_MODE_HUB 3 - -#define DWC3_MDWIDTH(n) (((n) & 0xff00) >> 8) - -/* HWPARAMS1 */ -#define DWC3_NUM_INT(n) (((n) & (0x3f << 15)) >> 15) - -/* HWPARAMS7 */ -#define DWC3_RAM1_DEPTH(n) ((n) & 0xffff) - -struct dwc3_request { - struct usb_request request; - struct list_head list; - struct dwc3_ep *dep; - - u8 epnum; - struct dwc3_trb *trb; - dma_addr_t trb_dma; - - unsigned direction:1; - unsigned mapped:1; - unsigned queued:1; -}; - -/** - * struct dwc3 - representation of our controller - * @ctrl_req: usb control request which is used for ep0 - * @ep0_trb: trb which is used for the ctrl_req - * @ep0_bounce: bounce buffer for ep0 - * @setup_buf: used while precessing STD USB requests - * @ctrl_req_addr: dma address of ctrl_req - * @ep0_trb: dma address of ep0_trb - * @ep0_usb_req: dummy req used while handling STD USB requests - * @ep0_bounce_addr: dma address of ep0_bounce - * @lock: for synchronizing - * @dev: pointer to our struct device - * @xhci: pointer to our xHCI child - * @event_buffer_list: a list of event buffers - * @gadget: device side representation of the peripheral controller - * @gadget_driver: pointer to the gadget driver - * @regs: base address for our registers - * @regs_size: address space size - * @irq: IRQ number - * @num_event_buffers: calculated number of event buffers - * @u1u2: only used on revisions <1.83a for workaround - * @maximum_speed: maximum speed requested (mainly for testing purposes) - * @revision: revision register contents - * @mode: mode of operation - * @is_selfpowered: true when we are selfpowered - * @three_stage_setup: set if we perform a three phase setup - * @ep0_bounced: true when we used bounce buffer - * @ep0_expect_in: true when we expect a DATA IN transfer - * @start_config_issued: true when StartConfig command has been issued - * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround - * @needs_fifo_resize: not all users might want fifo resizing, flag it - * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes. - * @ep0_next_event: hold the next expected event - * @ep0state: state of endpoint zero - * @link_state: link state - * @speed: device speed (super, high, full, low) - * @mem: points to start of memory which is used for this struct. - * @hwparams: copy of hwparams registers - * @root: debugfs root folder pointer - */ -struct dwc3 { - struct usb_ctrlrequest *ctrl_req; - struct dwc3_trb *ep0_trb; - void *ep0_bounce; - u8 *setup_buf; - dma_addr_t ctrl_req_addr; - dma_addr_t ep0_trb_addr; - dma_addr_t ep0_bounce_addr; - struct dwc3_request ep0_usb_req; - /* device lock */ - spinlock_t lock; - struct device *dev; - - struct platform_device *xhci; - struct resource *res; - - struct dwc3_event_buffer **ev_buffs; - struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM]; - - struct usb_gadget gadget; - struct usb_gadget_driver *gadget_driver; - - void __iomem *regs; - size_t regs_size; - - int irq; - - u32 num_event_buffers; - u32 u1u2; - u32 maximum_speed; - u32 revision; - u32 mode; - -#define DWC3_REVISION_173A 0x5533173a -#define DWC3_REVISION_175A 0x5533175a -#define DWC3_REVISION_180A 0x5533180a -#define DWC3_REVISION_183A 0x5533183a -#define DWC3_REVISION_185A 0x5533185a -#define DWC3_REVISION_188A 0x5533188a -#define DWC3_REVISION_190A 0x5533190a - - unsigned is_selfpowered:1; - unsigned three_stage_setup:1; - unsigned ep0_bounced:1; - unsigned ep0_expect_in:1; - unsigned start_config_issued:1; - unsigned setup_packet_pending:1; - unsigned delayed_status:1; - unsigned needs_fifo_resize:1; - unsigned resize_fifos:1; - - enum dwc3_ep0_next ep0_next_event; - enum dwc3_ep0_state ep0state; - enum dwc3_link_state link_state; - enum dwc3_device_state dev_state; - - u8 speed; - void *mem; - - struct dwc3_hwparams hwparams; - struct dentry *root; - - u8 test_mode; - u8 test_mode_nr; -}; - -/* -------------------------------------------------------------------------- */ - -/* -------------------------------------------------------------------------- */ - -struct dwc3_event_type { - u32 is_devspec:1; - u32 type:6; - u32 reserved8_31:25; -} __packed; - -#define DWC3_DEPEVT_XFERCOMPLETE 0x01 -#define DWC3_DEPEVT_XFERINPROGRESS 0x02 -#define DWC3_DEPEVT_XFERNOTREADY 0x03 -#define DWC3_DEPEVT_RXTXFIFOEVT 0x04 -#define DWC3_DEPEVT_STREAMEVT 0x06 -#define DWC3_DEPEVT_EPCMDCMPLT 0x07 - -/** - * struct dwc3_event_depvt - Device Endpoint Events - * @one_bit: indicates this is an endpoint event (not used) - * @endpoint_number: number of the endpoint - * @endpoint_event: The event we have: - * 0x00 - Reserved - * 0x01 - XferComplete - * 0x02 - XferInProgress - * 0x03 - XferNotReady - * 0x04 - RxTxFifoEvt (IN->Underrun, OUT->Overrun) - * 0x05 - Reserved - * 0x06 - StreamEvt - * 0x07 - EPCmdCmplt - * @reserved11_10: Reserved, don't use. - * @status: Indicates the status of the event. Refer to databook for - * more information. - * @parameters: Parameters of the current event. Refer to databook for - * more information. - */ -struct dwc3_event_depevt { - u32 one_bit:1; - u32 endpoint_number:5; - u32 endpoint_event:4; - u32 reserved11_10:2; - u32 status:4; - -/* Within XferNotReady */ -#define DEPEVT_STATUS_TRANSFER_ACTIVE (1 << 3) - -/* Within XferComplete */ -#define DEPEVT_STATUS_BUSERR (1 << 0) -#define DEPEVT_STATUS_SHORT (1 << 1) -#define DEPEVT_STATUS_IOC (1 << 2) -#define DEPEVT_STATUS_LST (1 << 3) - -/* Stream event only */ -#define DEPEVT_STREAMEVT_FOUND 1 -#define DEPEVT_STREAMEVT_NOTFOUND 2 - -/* Control-only Status */ -#define DEPEVT_STATUS_CONTROL_SETUP 0 -#define DEPEVT_STATUS_CONTROL_DATA 1 -#define DEPEVT_STATUS_CONTROL_STATUS 2 - - u32 parameters:16; -} __packed; - -/** - * struct dwc3_event_devt - Device Events - * @one_bit: indicates this is a non-endpoint event (not used) - * @device_event: indicates it's a device event. Should read as 0x00 - * @type: indicates the type of device event. - * 0 - DisconnEvt - * 1 - USBRst - * 2 - ConnectDone - * 3 - ULStChng - * 4 - WkUpEvt - * 5 - Reserved - * 6 - EOPF - * 7 - SOF - * 8 - Reserved - * 9 - ErrticErr - * 10 - CmdCmplt - * 11 - EvntOverflow - * 12 - VndrDevTstRcved - * @reserved15_12: Reserved, not used - * @event_info: Information about this event - * @reserved31_24: Reserved, not used - */ -struct dwc3_event_devt { - u32 one_bit:1; - u32 device_event:7; - u32 type:4; - u32 reserved15_12:4; - u32 event_info:8; - u32 reserved31_24:8; -} __packed; - -/** - * struct dwc3_event_gevt - Other Core Events - * @one_bit: indicates this is a non-endpoint event (not used) - * @device_event: indicates it's (0x03) Carkit or (0x04) I2C event. - * @phy_port_number: self-explanatory - * @reserved31_12: Reserved, not used. - */ -struct dwc3_event_gevt { - u32 one_bit:1; - u32 device_event:7; - u32 phy_port_number:4; - u32 reserved31_12:20; -} __packed; - -/** - * union dwc3_event - representation of Event Buffer contents - * @raw: raw 32-bit event - * @type: the type of the event - * @depevt: Device Endpoint Event - * @devt: Device Event - * @gevt: Global Event - */ -union dwc3_event { - u32 raw; - struct dwc3_event_type type; - struct dwc3_event_depevt depevt; - struct dwc3_event_devt devt; - struct dwc3_event_gevt gevt; -}; - -/* - * DWC3 Features to be used as Driver Data - */ - -#define DWC3_HAS_PERIPHERAL BIT(0) -#define DWC3_HAS_XHCI BIT(1) -#define DWC3_HAS_OTG BIT(3) - -/* prototypes */ -void dwc3_set_mode(struct dwc3 *dwc, u32 mode); -int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc); - -int dwc3_host_init(struct dwc3 *dwc); -void dwc3_host_exit(struct dwc3 *dwc); - -int dwc3_gadget_init(struct dwc3 *dwc); -void dwc3_gadget_exit(struct dwc3 *dwc); - -extern int dwc3_get_device_id(void); -extern void dwc3_put_device_id(int id); - -#endif /* __DRIVERS_USB_DWC3_CORE_H */ diff --git a/ANDROID_3.4.5/drivers/usb/dwc3/debug.h b/ANDROID_3.4.5/drivers/usb/dwc3/debug.h deleted file mode 100644 index 5894ee82..00000000 --- a/ANDROID_3.4.5/drivers/usb/dwc3/debug.h +++ /dev/null @@ -1,50 +0,0 @@ -/** - * debug.h - DesignWare USB3 DRD Controller Debug Header - * - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com - * - * Authors: Felipe Balbi , - * Sebastian Andrzej Siewior - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "core.h" - -#ifdef CONFIG_DEBUG_FS -extern int dwc3_debugfs_init(struct dwc3 *); -extern void dwc3_debugfs_exit(struct dwc3 *); -#else -static inline int dwc3_debugfs_init(struct dwc3 *d) -{ return 0; } -static inline void dwc3_debugfs_exit(struct dwc3 *d) -{ } -#endif - diff --git a/ANDROID_3.4.5/drivers/usb/dwc3/debugfs.c b/ANDROID_3.4.5/drivers/usb/dwc3/debugfs.c deleted file mode 100644 index d4a30f11..00000000 --- a/ANDROID_3.4.5/drivers/usb/dwc3/debugfs.c +++ /dev/null @@ -1,710 +0,0 @@ -/** - * debugfs.c - DesignWare USB3 DRD Controller DebugFS file - * - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com - * - * Authors: Felipe Balbi , - * Sebastian Andrzej Siewior - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "core.h" -#include "gadget.h" -#include "io.h" -#include "debug.h" - -#define dump_register(nm) \ -{ \ - .name = __stringify(nm), \ - .offset = DWC3_ ##nm, \ -} - -static const struct debugfs_reg32 dwc3_regs[] = { - dump_register(GSBUSCFG0), - dump_register(GSBUSCFG1), - dump_register(GTXTHRCFG), - dump_register(GRXTHRCFG), - dump_register(GCTL), - dump_register(GEVTEN), - dump_register(GSTS), - dump_register(GSNPSID), - dump_register(GGPIO), - dump_register(GUID), - dump_register(GUCTL), - dump_register(GBUSERRADDR0), - dump_register(GBUSERRADDR1), - dump_register(GPRTBIMAP0), - dump_register(GPRTBIMAP1), - dump_register(GHWPARAMS0), - dump_register(GHWPARAMS1), - dump_register(GHWPARAMS2), - dump_register(GHWPARAMS3), - dump_register(GHWPARAMS4), - dump_register(GHWPARAMS5), - dump_register(GHWPARAMS6), - dump_register(GHWPARAMS7), - dump_register(GDBGFIFOSPACE), - dump_register(GDBGLTSSM), - dump_register(GPRTBIMAP_HS0), - dump_register(GPRTBIMAP_HS1), - dump_register(GPRTBIMAP_FS0), - dump_register(GPRTBIMAP_FS1), - - dump_register(GUSB2PHYCFG(0)), - dump_register(GUSB2PHYCFG(1)), - dump_register(GUSB2PHYCFG(2)), - dump_register(GUSB2PHYCFG(3)), - dump_register(GUSB2PHYCFG(4)), - dump_register(GUSB2PHYCFG(5)), - dump_register(GUSB2PHYCFG(6)), - dump_register(GUSB2PHYCFG(7)), - dump_register(GUSB2PHYCFG(8)), - dump_register(GUSB2PHYCFG(9)), - dump_register(GUSB2PHYCFG(10)), - dump_register(GUSB2PHYCFG(11)), - dump_register(GUSB2PHYCFG(12)), - dump_register(GUSB2PHYCFG(13)), - dump_register(GUSB2PHYCFG(14)), - dump_register(GUSB2PHYCFG(15)), - - dump_register(GUSB2I2CCTL(0)), - dump_register(GUSB2I2CCTL(1)), - dump_register(GUSB2I2CCTL(2)), - dump_register(GUSB2I2CCTL(3)), - dump_register(GUSB2I2CCTL(4)), - dump_register(GUSB2I2CCTL(5)), - dump_register(GUSB2I2CCTL(6)), - dump_register(GUSB2I2CCTL(7)), - dump_register(GUSB2I2CCTL(8)), - dump_register(GUSB2I2CCTL(9)), - dump_register(GUSB2I2CCTL(10)), - dump_register(GUSB2I2CCTL(11)), - dump_register(GUSB2I2CCTL(12)), - dump_register(GUSB2I2CCTL(13)), - dump_register(GUSB2I2CCTL(14)), - dump_register(GUSB2I2CCTL(15)), - - dump_register(GUSB2PHYACC(0)), - dump_register(GUSB2PHYACC(1)), - dump_register(GUSB2PHYACC(2)), - dump_register(GUSB2PHYACC(3)), - dump_register(GUSB2PHYACC(4)), - dump_register(GUSB2PHYACC(5)), - dump_register(GUSB2PHYACC(6)), - dump_register(GUSB2PHYACC(7)), - dump_register(GUSB2PHYACC(8)), - dump_register(GUSB2PHYACC(9)), - dump_register(GUSB2PHYACC(10)), - dump_register(GUSB2PHYACC(11)), - dump_register(GUSB2PHYACC(12)), - dump_register(GUSB2PHYACC(13)), - dump_register(GUSB2PHYACC(14)), - dump_register(GUSB2PHYACC(15)), - - dump_register(GUSB3PIPECTL(0)), - dump_register(GUSB3PIPECTL(1)), - dump_register(GUSB3PIPECTL(2)), - dump_register(GUSB3PIPECTL(3)), - dump_register(GUSB3PIPECTL(4)), - dump_register(GUSB3PIPECTL(5)), - dump_register(GUSB3PIPECTL(6)), - dump_register(GUSB3PIPECTL(7)), - dump_register(GUSB3PIPECTL(8)), - dump_register(GUSB3PIPECTL(9)), - dump_register(GUSB3PIPECTL(10)), - dump_register(GUSB3PIPECTL(11)), - dump_register(GUSB3PIPECTL(12)), - dump_register(GUSB3PIPECTL(13)), - dump_register(GUSB3PIPECTL(14)), - dump_register(GUSB3PIPECTL(15)), - - dump_register(GTXFIFOSIZ(0)), - dump_register(GTXFIFOSIZ(1)), - dump_register(GTXFIFOSIZ(2)), - dump_register(GTXFIFOSIZ(3)), - dump_register(GTXFIFOSIZ(4)), - dump_register(GTXFIFOSIZ(5)), - dump_register(GTXFIFOSIZ(6)), - dump_register(GTXFIFOSIZ(7)), - dump_register(GTXFIFOSIZ(8)), - dump_register(GTXFIFOSIZ(9)), - dump_register(GTXFIFOSIZ(10)), - dump_register(GTXFIFOSIZ(11)), - dump_register(GTXFIFOSIZ(12)), - dump_register(GTXFIFOSIZ(13)), - dump_register(GTXFIFOSIZ(14)), - dump_register(GTXFIFOSIZ(15)), - dump_register(GTXFIFOSIZ(16)), - dump_register(GTXFIFOSIZ(17)), - dump_register(GTXFIFOSIZ(18)), - dump_register(GTXFIFOSIZ(19)), - dump_register(GTXFIFOSIZ(20)), - dump_register(GTXFIFOSIZ(21)), - dump_register(GTXFIFOSIZ(22)), - dump_register(GTXFIFOSIZ(23)), - dump_register(GTXFIFOSIZ(24)), - dump_register(GTXFIFOSIZ(25)), - dump_register(GTXFIFOSIZ(26)), - dump_register(GTXFIFOSIZ(27)), - dump_register(GTXFIFOSIZ(28)), - dump_register(GTXFIFOSIZ(29)), - dump_register(GTXFIFOSIZ(30)), - dump_register(GTXFIFOSIZ(31)), - - dump_register(GRXFIFOSIZ(0)), - dump_register(GRXFIFOSIZ(1)), - dump_register(GRXFIFOSIZ(2)), - dump_register(GRXFIFOSIZ(3)), - dump_register(GRXFIFOSIZ(4)), - dump_register(GRXFIFOSIZ(5)), - dump_register(GRXFIFOSIZ(6)), - dump_register(GRXFIFOSIZ(7)), - dump_register(GRXFIFOSIZ(8)), - dump_register(GRXFIFOSIZ(9)), - dump_register(GRXFIFOSIZ(10)), - dump_register(GRXFIFOSIZ(11)), - dump_register(GRXFIFOSIZ(12)), - dump_register(GRXFIFOSIZ(13)), - dump_register(GRXFIFOSIZ(14)), - dump_register(GRXFIFOSIZ(15)), - dump_register(GRXFIFOSIZ(16)), - dump_register(GRXFIFOSIZ(17)), - dump_register(GRXFIFOSIZ(18)), - dump_register(GRXFIFOSIZ(19)), - dump_register(GRXFIFOSIZ(20)), - dump_register(GRXFIFOSIZ(21)), - dump_register(GRXFIFOSIZ(22)), - dump_register(GRXFIFOSIZ(23)), - dump_register(GRXFIFOSIZ(24)), - dump_register(GRXFIFOSIZ(25)), - dump_register(GRXFIFOSIZ(26)), - dump_register(GRXFIFOSIZ(27)), - dump_register(GRXFIFOSIZ(28)), - dump_register(GRXFIFOSIZ(29)), - dump_register(GRXFIFOSIZ(30)), - dump_register(GRXFIFOSIZ(31)), - - dump_register(GEVNTADRLO(0)), - dump_register(GEVNTADRHI(0)), - dump_register(GEVNTSIZ(0)), - dump_register(GEVNTCOUNT(0)), - - dump_register(GHWPARAMS8), - dump_register(DCFG), - dump_register(DCTL), - dump_register(DEVTEN), - dump_register(DSTS), - dump_register(DGCMDPAR), - dump_register(DGCMD), - dump_register(DALEPENA), - - dump_register(DEPCMDPAR2(0)), - dump_register(DEPCMDPAR2(1)), - dump_register(DEPCMDPAR2(2)), - dump_register(DEPCMDPAR2(3)), - dump_register(DEPCMDPAR2(4)), - dump_register(DEPCMDPAR2(5)), - dump_register(DEPCMDPAR2(6)), - dump_register(DEPCMDPAR2(7)), - dump_register(DEPCMDPAR2(8)), - dump_register(DEPCMDPAR2(9)), - dump_register(DEPCMDPAR2(10)), - dump_register(DEPCMDPAR2(11)), - dump_register(DEPCMDPAR2(12)), - dump_register(DEPCMDPAR2(13)), - dump_register(DEPCMDPAR2(14)), - dump_register(DEPCMDPAR2(15)), - dump_register(DEPCMDPAR2(16)), - dump_register(DEPCMDPAR2(17)), - dump_register(DEPCMDPAR2(18)), - dump_register(DEPCMDPAR2(19)), - dump_register(DEPCMDPAR2(20)), - dump_register(DEPCMDPAR2(21)), - dump_register(DEPCMDPAR2(22)), - dump_register(DEPCMDPAR2(23)), - dump_register(DEPCMDPAR2(24)), - dump_register(DEPCMDPAR2(25)), - dump_register(DEPCMDPAR2(26)), - dump_register(DEPCMDPAR2(27)), - dump_register(DEPCMDPAR2(28)), - dump_register(DEPCMDPAR2(29)), - dump_register(DEPCMDPAR2(30)), - dump_register(DEPCMDPAR2(31)), - - dump_register(DEPCMDPAR1(0)), - dump_register(DEPCMDPAR1(1)), - dump_register(DEPCMDPAR1(2)), - dump_register(DEPCMDPAR1(3)), - dump_register(DEPCMDPAR1(4)), - dump_register(DEPCMDPAR1(5)), - dump_register(DEPCMDPAR1(6)), - dump_register(DEPCMDPAR1(7)), - dump_register(DEPCMDPAR1(8)), - dump_register(DEPCMDPAR1(9)), - dump_register(DEPCMDPAR1(10)), - dump_register(DEPCMDPAR1(11)), - dump_register(DEPCMDPAR1(12)), - dump_register(DEPCMDPAR1(13)), - dump_register(DEPCMDPAR1(14)), - dump_register(DEPCMDPAR1(15)), - dump_register(DEPCMDPAR1(16)), - dump_register(DEPCMDPAR1(17)), - dump_register(DEPCMDPAR1(18)), - dump_register(DEPCMDPAR1(19)), - dump_register(DEPCMDPAR1(20)), - dump_register(DEPCMDPAR1(21)), - dump_register(DEPCMDPAR1(22)), - dump_register(DEPCMDPAR1(23)), - dump_register(DEPCMDPAR1(24)), - dump_register(DEPCMDPAR1(25)), - dump_register(DEPCMDPAR1(26)), - dump_register(DEPCMDPAR1(27)), - dump_register(DEPCMDPAR1(28)), - dump_register(DEPCMDPAR1(29)), - dump_register(DEPCMDPAR1(30)), - dump_register(DEPCMDPAR1(31)), - - dump_register(DEPCMDPAR0(0)), - dump_register(DEPCMDPAR0(1)), - dump_register(DEPCMDPAR0(2)), - dump_register(DEPCMDPAR0(3)), - dump_register(DEPCMDPAR0(4)), - dump_register(DEPCMDPAR0(5)), - dump_register(DEPCMDPAR0(6)), - dump_register(DEPCMDPAR0(7)), - dump_register(DEPCMDPAR0(8)), - dump_register(DEPCMDPAR0(9)), - dump_register(DEPCMDPAR0(10)), - dump_register(DEPCMDPAR0(11)), - dump_register(DEPCMDPAR0(12)), - dump_register(DEPCMDPAR0(13)), - dump_register(DEPCMDPAR0(14)), - dump_register(DEPCMDPAR0(15)), - dump_register(DEPCMDPAR0(16)), - dump_register(DEPCMDPAR0(17)), - dump_register(DEPCMDPAR0(18)), - dump_register(DEPCMDPAR0(19)), - dump_register(DEPCMDPAR0(20)), - dump_register(DEPCMDPAR0(21)), - dump_register(DEPCMDPAR0(22)), - dump_register(DEPCMDPAR0(23)), - dump_register(DEPCMDPAR0(24)), - dump_register(DEPCMDPAR0(25)), - dump_register(DEPCMDPAR0(26)), - dump_register(DEPCMDPAR0(27)), - dump_register(DEPCMDPAR0(28)), - dump_register(DEPCMDPAR0(29)), - dump_register(DEPCMDPAR0(30)), - dump_register(DEPCMDPAR0(31)), - - dump_register(DEPCMD(0)), - dump_register(DEPCMD(1)), - dump_register(DEPCMD(2)), - dump_register(DEPCMD(3)), - dump_register(DEPCMD(4)), - dump_register(DEPCMD(5)), - dump_register(DEPCMD(6)), - dump_register(DEPCMD(7)), - dump_register(DEPCMD(8)), - dump_register(DEPCMD(9)), - dump_register(DEPCMD(10)), - dump_register(DEPCMD(11)), - dump_register(DEPCMD(12)), - dump_register(DEPCMD(13)), - dump_register(DEPCMD(14)), - dump_register(DEPCMD(15)), - dump_register(DEPCMD(16)), - dump_register(DEPCMD(17)), - dump_register(DEPCMD(18)), - dump_register(DEPCMD(19)), - dump_register(DEPCMD(20)), - dump_register(DEPCMD(21)), - dump_register(DEPCMD(22)), - dump_register(DEPCMD(23)), - dump_register(DEPCMD(24)), - dump_register(DEPCMD(25)), - dump_register(DEPCMD(26)), - dump_register(DEPCMD(27)), - dump_register(DEPCMD(28)), - dump_register(DEPCMD(29)), - dump_register(DEPCMD(30)), - dump_register(DEPCMD(31)), - - dump_register(OCFG), - dump_register(OCTL), - dump_register(OEVTEN), - dump_register(OSTS), -}; - -static int dwc3_regdump_show(struct seq_file *s, void *unused) -{ - struct dwc3 *dwc = s->private; - - seq_printf(s, "DesignWare USB3 Core Register Dump\n"); - debugfs_print_regs32(s, dwc3_regs, ARRAY_SIZE(dwc3_regs), - dwc->regs, ""); - return 0; -} - -static int dwc3_regdump_open(struct inode *inode, struct file *file) -{ - return single_open(file, dwc3_regdump_show, inode->i_private); -} - -static const struct file_operations dwc3_regdump_fops = { - .open = dwc3_regdump_open, - .read = seq_read, - .release = single_release, -}; - -static int dwc3_mode_show(struct seq_file *s, void *unused) -{ - struct dwc3 *dwc = s->private; - unsigned long flags; - u32 reg; - - spin_lock_irqsave(&dwc->lock, flags); - reg = dwc3_readl(dwc->regs, DWC3_GCTL); - spin_unlock_irqrestore(&dwc->lock, flags); - - switch (DWC3_GCTL_PRTCAP(reg)) { - case DWC3_GCTL_PRTCAP_HOST: - seq_printf(s, "host\n"); - break; - case DWC3_GCTL_PRTCAP_DEVICE: - seq_printf(s, "device\n"); - break; - case DWC3_GCTL_PRTCAP_OTG: - seq_printf(s, "OTG\n"); - break; - default: - seq_printf(s, "UNKNOWN %08x\n", DWC3_GCTL_PRTCAP(reg)); - } - - return 0; -} - -static int dwc3_mode_open(struct inode *inode, struct file *file) -{ - return single_open(file, dwc3_mode_show, inode->i_private); -} - -static ssize_t dwc3_mode_write(struct file *file, - const char __user *ubuf, size_t count, loff_t *ppos) -{ - struct seq_file *s = file->private_data; - struct dwc3 *dwc = s->private; - unsigned long flags; - u32 mode = 0; - char buf[32]; - - if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) - return -EFAULT; - - if (!strncmp(buf, "host", 4)) - mode |= DWC3_GCTL_PRTCAP_HOST; - - if (!strncmp(buf, "device", 6)) - mode |= DWC3_GCTL_PRTCAP_DEVICE; - - if (!strncmp(buf, "otg", 3)) - mode |= DWC3_GCTL_PRTCAP_OTG; - - if (mode) { - spin_lock_irqsave(&dwc->lock, flags); - dwc3_set_mode(dwc, mode); - spin_unlock_irqrestore(&dwc->lock, flags); - } - return count; -} - -static const struct file_operations dwc3_mode_fops = { - .open = dwc3_mode_open, - .write = dwc3_mode_write, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int dwc3_testmode_show(struct seq_file *s, void *unused) -{ - struct dwc3 *dwc = s->private; - unsigned long flags; - u32 reg; - - spin_lock_irqsave(&dwc->lock, flags); - reg = dwc3_readl(dwc->regs, DWC3_DCTL); - reg &= DWC3_DCTL_TSTCTRL_MASK; - reg >>= 1; - spin_unlock_irqrestore(&dwc->lock, flags); - - switch (reg) { - case 0: - seq_printf(s, "no test\n"); - break; - case TEST_J: - seq_printf(s, "test_j\n"); - break; - case TEST_K: - seq_printf(s, "test_k\n"); - break; - case TEST_SE0_NAK: - seq_printf(s, "test_se0_nak\n"); - break; - case TEST_PACKET: - seq_printf(s, "test_packet\n"); - break; - case TEST_FORCE_EN: - seq_printf(s, "test_force_enable\n"); - break; - default: - seq_printf(s, "UNKNOWN %d\n", reg); - } - - return 0; -} - -static int dwc3_testmode_open(struct inode *inode, struct file *file) -{ - return single_open(file, dwc3_testmode_show, inode->i_private); -} - -static ssize_t dwc3_testmode_write(struct file *file, - const char __user *ubuf, size_t count, loff_t *ppos) -{ - struct seq_file *s = file->private_data; - struct dwc3 *dwc = s->private; - unsigned long flags; - u32 testmode = 0; - char buf[32]; - - if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) - return -EFAULT; - - if (!strncmp(buf, "test_j", 6)) - testmode = TEST_J; - else if (!strncmp(buf, "test_k", 6)) - testmode = TEST_K; - else if (!strncmp(buf, "test_se0_nak", 12)) - testmode = TEST_SE0_NAK; - else if (!strncmp(buf, "test_packet", 11)) - testmode = TEST_PACKET; - else if (!strncmp(buf, "test_force_enable", 17)) - testmode = TEST_FORCE_EN; - else - testmode = 0; - - spin_lock_irqsave(&dwc->lock, flags); - dwc3_gadget_set_test_mode(dwc, testmode); - spin_unlock_irqrestore(&dwc->lock, flags); - - return count; -} - -static const struct file_operations dwc3_testmode_fops = { - .open = dwc3_testmode_open, - .write = dwc3_testmode_write, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int dwc3_link_state_show(struct seq_file *s, void *unused) -{ - struct dwc3 *dwc = s->private; - unsigned long flags; - enum dwc3_link_state state; - u32 reg; - - spin_lock_irqsave(&dwc->lock, flags); - reg = dwc3_readl(dwc->regs, DWC3_DSTS); - state = DWC3_DSTS_USBLNKST(reg); - spin_unlock_irqrestore(&dwc->lock, flags); - - switch (state) { - case DWC3_LINK_STATE_U0: - seq_printf(s, "U0\n"); - break; - case DWC3_LINK_STATE_U1: - seq_printf(s, "U1\n"); - break; - case DWC3_LINK_STATE_U2: - seq_printf(s, "U2\n"); - break; - case DWC3_LINK_STATE_U3: - seq_printf(s, "U3\n"); - break; - case DWC3_LINK_STATE_SS_DIS: - seq_printf(s, "SS.Disabled\n"); - break; - case DWC3_LINK_STATE_RX_DET: - seq_printf(s, "Rx.Detect\n"); - break; - case DWC3_LINK_STATE_SS_INACT: - seq_printf(s, "SS.Inactive\n"); - break; - case DWC3_LINK_STATE_POLL: - seq_printf(s, "Poll\n"); - break; - case DWC3_LINK_STATE_RECOV: - seq_printf(s, "Recovery\n"); - break; - case DWC3_LINK_STATE_HRESET: - seq_printf(s, "HRESET\n"); - break; - case DWC3_LINK_STATE_CMPLY: - seq_printf(s, "Compliance\n"); - break; - case DWC3_LINK_STATE_LPBK: - seq_printf(s, "Loopback\n"); - break; - default: - seq_printf(s, "UNKNOWN %d\n", reg); - } - - return 0; -} - -static int dwc3_link_state_open(struct inode *inode, struct file *file) -{ - return single_open(file, dwc3_link_state_show, inode->i_private); -} - -static ssize_t dwc3_link_state_write(struct file *file, - const char __user *ubuf, size_t count, loff_t *ppos) -{ - struct seq_file *s = file->private_data; - struct dwc3 *dwc = s->private; - unsigned long flags; - enum dwc3_link_state state = 0; - char buf[32]; - - if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) - return -EFAULT; - - if (!strncmp(buf, "SS.Disabled", 11)) - state = DWC3_LINK_STATE_SS_DIS; - else if (!strncmp(buf, "Rx.Detect", 9)) - state = DWC3_LINK_STATE_RX_DET; - else if (!strncmp(buf, "SS.Inactive", 11)) - state = DWC3_LINK_STATE_SS_INACT; - else if (!strncmp(buf, "Recovery", 8)) - state = DWC3_LINK_STATE_RECOV; - else if (!strncmp(buf, "Compliance", 10)) - state = DWC3_LINK_STATE_CMPLY; - else if (!strncmp(buf, "Loopback", 8)) - state = DWC3_LINK_STATE_LPBK; - else - return -EINVAL; - - spin_lock_irqsave(&dwc->lock, flags); - dwc3_gadget_set_link_state(dwc, state); - spin_unlock_irqrestore(&dwc->lock, flags); - - return count; -} - -static const struct file_operations dwc3_link_state_fops = { - .open = dwc3_link_state_open, - .write = dwc3_link_state_write, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -int __devinit dwc3_debugfs_init(struct dwc3 *dwc) -{ - struct dentry *root; - struct dentry *file; - int ret; - - root = debugfs_create_dir(dev_name(dwc->dev), NULL); - if (!root) { - ret = -ENOMEM; - goto err0; - } - - dwc->root = root; - - file = debugfs_create_file("regdump", S_IRUGO, root, dwc, - &dwc3_regdump_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root, - dwc, &dwc3_mode_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root, - dwc, &dwc3_testmode_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root, - dwc, &dwc3_link_state_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - return 0; - -err1: - debugfs_remove_recursive(root); - -err0: - return ret; -} - -void __devexit dwc3_debugfs_exit(struct dwc3 *dwc) -{ - debugfs_remove_recursive(dwc->root); - dwc->root = NULL; -} diff --git a/ANDROID_3.4.5/drivers/usb/dwc3/dwc3-exynos.c b/ANDROID_3.4.5/drivers/usb/dwc3/dwc3-exynos.c deleted file mode 100644 index d1903019..00000000 --- a/ANDROID_3.4.5/drivers/usb/dwc3/dwc3-exynos.c +++ /dev/null @@ -1,151 +0,0 @@ -/** - * dwc3-exynos.c - Samsung EXYNOS DWC3 Specific Glue layer - * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * Author: Anton Tikhomirov - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -#include "core.h" - -struct dwc3_exynos { - struct platform_device *dwc3; - struct device *dev; - - struct clk *clk; -}; - -static int __devinit dwc3_exynos_probe(struct platform_device *pdev) -{ - struct dwc3_exynos_data *pdata = pdev->dev.platform_data; - struct platform_device *dwc3; - struct dwc3_exynos *exynos; - struct clk *clk; - - int devid; - int ret = -ENOMEM; - - exynos = kzalloc(sizeof(*exynos), GFP_KERNEL); - if (!exynos) { - dev_err(&pdev->dev, "not enough memory\n"); - goto err0; - } - - platform_set_drvdata(pdev, exynos); - - devid = dwc3_get_device_id(); - if (devid < 0) - goto err1; - - dwc3 = platform_device_alloc("dwc3", devid); - if (!dwc3) { - dev_err(&pdev->dev, "couldn't allocate dwc3 device\n"); - goto err2; - } - - clk = clk_get(&pdev->dev, "usbdrd30"); - if (IS_ERR(clk)) { - dev_err(&pdev->dev, "couldn't get clock\n"); - ret = -EINVAL; - goto err3; - } - - dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask); - - dwc3->dev.parent = &pdev->dev; - dwc3->dev.dma_mask = pdev->dev.dma_mask; - dwc3->dev.dma_parms = pdev->dev.dma_parms; - exynos->dwc3 = dwc3; - exynos->dev = &pdev->dev; - exynos->clk = clk; - - clk_enable(exynos->clk); - - /* PHY initialization */ - if (!pdata) { - dev_dbg(&pdev->dev, "missing platform data\n"); - } else { - if (pdata->phy_init) - pdata->phy_init(pdev, pdata->phy_type); - } - - ret = platform_device_add_resources(dwc3, pdev->resource, - pdev->num_resources); - if (ret) { - dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n"); - goto err4; - } - - ret = platform_device_add(dwc3); - if (ret) { - dev_err(&pdev->dev, "failed to register dwc3 device\n"); - goto err4; - } - - return 0; - -err4: - if (pdata && pdata->phy_exit) - pdata->phy_exit(pdev, pdata->phy_type); - - clk_disable(clk); - clk_put(clk); -err3: - platform_device_put(dwc3); -err2: - dwc3_put_device_id(devid); -err1: - kfree(exynos); -err0: - return ret; -} - -static int __devexit dwc3_exynos_remove(struct platform_device *pdev) -{ - struct dwc3_exynos *exynos = platform_get_drvdata(pdev); - struct dwc3_exynos_data *pdata = pdev->dev.platform_data; - - platform_device_unregister(exynos->dwc3); - - dwc3_put_device_id(exynos->dwc3->id); - - if (pdata && pdata->phy_exit) - pdata->phy_exit(pdev, pdata->phy_type); - - clk_disable(exynos->clk); - clk_put(exynos->clk); - - kfree(exynos); - - return 0; -} - -static struct platform_driver dwc3_exynos_driver = { - .probe = dwc3_exynos_probe, - .remove = __devexit_p(dwc3_exynos_remove), - .driver = { - .name = "exynos-dwc3", - }, -}; - -module_platform_driver(dwc3_exynos_driver); - -MODULE_ALIAS("platform:exynos-dwc3"); -MODULE_AUTHOR("Anton Tikhomirov "); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("DesignWare USB3 EXYNOS Glue Layer"); diff --git a/ANDROID_3.4.5/drivers/usb/dwc3/dwc3-omap.c b/ANDROID_3.4.5/drivers/usb/dwc3/dwc3-omap.c deleted file mode 100644 index d7d9c0ec..00000000 --- a/ANDROID_3.4.5/drivers/usb/dwc3/dwc3-omap.c +++ /dev/null @@ -1,392 +0,0 @@ -/** - * dwc3-omap.c - OMAP Specific Glue layer - * - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com - * - * Authors: Felipe Balbi , - * Sebastian Andrzej Siewior - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "core.h" -#include "io.h" - -/* - * All these registers belong to OMAP's Wrapper around the - * DesignWare USB3 Core. - */ - -#define USBOTGSS_REVISION 0x0000 -#define USBOTGSS_SYSCONFIG 0x0010 -#define USBOTGSS_IRQ_EOI 0x0020 -#define USBOTGSS_IRQSTATUS_RAW_0 0x0024 -#define USBOTGSS_IRQSTATUS_0 0x0028 -#define USBOTGSS_IRQENABLE_SET_0 0x002c -#define USBOTGSS_IRQENABLE_CLR_0 0x0030 -#define USBOTGSS_IRQSTATUS_RAW_1 0x0034 -#define USBOTGSS_IRQSTATUS_1 0x0038 -#define USBOTGSS_IRQENABLE_SET_1 0x003c -#define USBOTGSS_IRQENABLE_CLR_1 0x0040 -#define USBOTGSS_UTMI_OTG_CTRL 0x0080 -#define USBOTGSS_UTMI_OTG_STATUS 0x0084 -#define USBOTGSS_MMRAM_OFFSET 0x0100 -#define USBOTGSS_FLADJ 0x0104 -#define USBOTGSS_DEBUG_CFG 0x0108 -#define USBOTGSS_DEBUG_DATA 0x010c - -/* SYSCONFIG REGISTER */ -#define USBOTGSS_SYSCONFIG_DMADISABLE (1 << 16) -#define USBOTGSS_SYSCONFIG_STANDBYMODE(x) ((x) << 4) - -#define USBOTGSS_STANDBYMODE_FORCE_STANDBY 0 -#define USBOTGSS_STANDBYMODE_NO_STANDBY 1 -#define USBOTGSS_STANDBYMODE_SMART_STANDBY 2 -#define USBOTGSS_STANDBYMODE_SMART_WAKEUP 3 - -#define USBOTGSS_STANDBYMODE_MASK (0x03 << 4) - -#define USBOTGSS_SYSCONFIG_IDLEMODE(x) ((x) << 2) - -#define USBOTGSS_IDLEMODE_FORCE_IDLE 0 -#define USBOTGSS_IDLEMODE_NO_IDLE 1 -#define USBOTGSS_IDLEMODE_SMART_IDLE 2 -#define USBOTGSS_IDLEMODE_SMART_WAKEUP 3 - -#define USBOTGSS_IDLEMODE_MASK (0x03 << 2) - -/* IRQ_EOI REGISTER */ -#define USBOTGSS_IRQ_EOI_LINE_NUMBER (1 << 0) - -/* IRQS0 BITS */ -#define USBOTGSS_IRQO_COREIRQ_ST (1 << 0) - -/* IRQ1 BITS */ -#define USBOTGSS_IRQ1_DMADISABLECLR (1 << 17) -#define USBOTGSS_IRQ1_OEVT (1 << 16) -#define USBOTGSS_IRQ1_DRVVBUS_RISE (1 << 13) -#define USBOTGSS_IRQ1_CHRGVBUS_RISE (1 << 12) -#define USBOTGSS_IRQ1_DISCHRGVBUS_RISE (1 << 11) -#define USBOTGSS_IRQ1_IDPULLUP_RISE (1 << 8) -#define USBOTGSS_IRQ1_DRVVBUS_FALL (1 << 5) -#define USBOTGSS_IRQ1_CHRGVBUS_FALL (1 << 4) -#define USBOTGSS_IRQ1_DISCHRGVBUS_FALL (1 << 3) -#define USBOTGSS_IRQ1_IDPULLUP_FALL (1 << 0) - -/* UTMI_OTG_CTRL REGISTER */ -#define USBOTGSS_UTMI_OTG_CTRL_DRVVBUS (1 << 5) -#define USBOTGSS_UTMI_OTG_CTRL_CHRGVBUS (1 << 4) -#define USBOTGSS_UTMI_OTG_CTRL_DISCHRGVBUS (1 << 3) -#define USBOTGSS_UTMI_OTG_CTRL_IDPULLUP (1 << 0) - -/* UTMI_OTG_STATUS REGISTER */ -#define USBOTGSS_UTMI_OTG_STATUS_SW_MODE (1 << 31) -#define USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT (1 << 9) -#define USBOTGSS_UTMI_OTG_STATUS_TXBITSTUFFENABLE (1 << 8) -#define USBOTGSS_UTMI_OTG_STATUS_IDDIG (1 << 4) -#define USBOTGSS_UTMI_OTG_STATUS_SESSEND (1 << 3) -#define USBOTGSS_UTMI_OTG_STATUS_SESSVALID (1 << 2) -#define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID (1 << 1) - -struct dwc3_omap { - /* device lock */ - spinlock_t lock; - - struct platform_device *dwc3; - struct device *dev; - - int irq; - void __iomem *base; - - void *context; - u32 resource_size; - - u32 dma_status:1; -}; - -static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap) -{ - struct dwc3_omap *omap = _omap; - u32 reg; - - spin_lock(&omap->lock); - - reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_1); - - if (reg & USBOTGSS_IRQ1_DMADISABLECLR) { - dev_dbg(omap->dev, "DMA Disable was Cleared\n"); - omap->dma_status = false; - } - - if (reg & USBOTGSS_IRQ1_OEVT) - dev_dbg(omap->dev, "OTG Event\n"); - - if (reg & USBOTGSS_IRQ1_DRVVBUS_RISE) - dev_dbg(omap->dev, "DRVVBUS Rise\n"); - - if (reg & USBOTGSS_IRQ1_CHRGVBUS_RISE) - dev_dbg(omap->dev, "CHRGVBUS Rise\n"); - - if (reg & USBOTGSS_IRQ1_DISCHRGVBUS_RISE) - dev_dbg(omap->dev, "DISCHRGVBUS Rise\n"); - - if (reg & USBOTGSS_IRQ1_IDPULLUP_RISE) - dev_dbg(omap->dev, "IDPULLUP Rise\n"); - - if (reg & USBOTGSS_IRQ1_DRVVBUS_FALL) - dev_dbg(omap->dev, "DRVVBUS Fall\n"); - - if (reg & USBOTGSS_IRQ1_CHRGVBUS_FALL) - dev_dbg(omap->dev, "CHRGVBUS Fall\n"); - - if (reg & USBOTGSS_IRQ1_DISCHRGVBUS_FALL) - dev_dbg(omap->dev, "DISCHRGVBUS Fall\n"); - - if (reg & USBOTGSS_IRQ1_IDPULLUP_FALL) - dev_dbg(omap->dev, "IDPULLUP Fall\n"); - - dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg); - - reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_0); - dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg); - - spin_unlock(&omap->lock); - - return IRQ_HANDLED; -} - -static int __devinit dwc3_omap_probe(struct platform_device *pdev) -{ - struct dwc3_omap_data *pdata = pdev->dev.platform_data; - struct device_node *node = pdev->dev.of_node; - - struct platform_device *dwc3; - struct dwc3_omap *omap; - struct resource *res; - struct device *dev = &pdev->dev; - - int devid; - int size; - int ret = -ENOMEM; - int irq; - - const u32 *utmi_mode; - u32 reg; - - void __iomem *base; - void *context; - - omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL); - if (!omap) { - dev_err(dev, "not enough memory\n"); - return -ENOMEM; - } - - platform_set_drvdata(pdev, omap); - - irq = platform_get_irq(pdev, 1); - if (irq < 0) { - dev_err(dev, "missing IRQ resource\n"); - return -EINVAL; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!res) { - dev_err(dev, "missing memory base resource\n"); - return -EINVAL; - } - - base = devm_ioremap_nocache(dev, res->start, resource_size(res)); - if (!base) { - dev_err(dev, "ioremap failed\n"); - return -ENOMEM; - } - - devid = dwc3_get_device_id(); - if (devid < 0) - return -ENODEV; - - dwc3 = platform_device_alloc("dwc3", devid); - if (!dwc3) { - dev_err(dev, "couldn't allocate dwc3 device\n"); - goto err1; - } - - context = devm_kzalloc(dev, resource_size(res), GFP_KERNEL); - if (!context) { - dev_err(dev, "couldn't allocate dwc3 context memory\n"); - goto err2; - } - - spin_lock_init(&omap->lock); - dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask); - - dwc3->dev.parent = dev; - dwc3->dev.dma_mask = dev->dma_mask; - dwc3->dev.dma_parms = dev->dma_parms; - omap->resource_size = resource_size(res); - omap->context = context; - omap->dev = dev; - omap->irq = irq; - omap->base = base; - omap->dwc3 = dwc3; - - reg = dwc3_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS); - - utmi_mode = of_get_property(node, "utmi-mode", &size); - if (utmi_mode && size == sizeof(*utmi_mode)) { - reg |= *utmi_mode; - } else { - if (!pdata) { - dev_dbg(dev, "missing platform data\n"); - } else { - switch (pdata->utmi_mode) { - case DWC3_OMAP_UTMI_MODE_SW: - reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE; - break; - case DWC3_OMAP_UTMI_MODE_HW: - reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE; - break; - default: - dev_dbg(dev, "UNKNOWN utmi mode %d\n", - pdata->utmi_mode); - } - } - } - - dwc3_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg); - - /* check the DMA Status */ - reg = dwc3_readl(omap->base, USBOTGSS_SYSCONFIG); - omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE); - - /* Set No-Idle and No-Standby */ - reg &= ~(USBOTGSS_STANDBYMODE_MASK - | USBOTGSS_IDLEMODE_MASK); - - reg |= (USBOTGSS_SYSCONFIG_STANDBYMODE(USBOTGSS_STANDBYMODE_NO_STANDBY) - | USBOTGSS_SYSCONFIG_IDLEMODE(USBOTGSS_IDLEMODE_NO_IDLE)); - - dwc3_writel(omap->base, USBOTGSS_SYSCONFIG, reg); - - ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0, - "dwc3-omap", omap); - if (ret) { - dev_err(dev, "failed to request IRQ #%d --> %d\n", - omap->irq, ret); - goto err2; - } - - /* enable all IRQs */ - reg = USBOTGSS_IRQO_COREIRQ_ST; - dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg); - - reg = (USBOTGSS_IRQ1_OEVT | - USBOTGSS_IRQ1_DRVVBUS_RISE | - USBOTGSS_IRQ1_CHRGVBUS_RISE | - USBOTGSS_IRQ1_DISCHRGVBUS_RISE | - USBOTGSS_IRQ1_IDPULLUP_RISE | - USBOTGSS_IRQ1_DRVVBUS_FALL | - USBOTGSS_IRQ1_CHRGVBUS_FALL | - USBOTGSS_IRQ1_DISCHRGVBUS_FALL | - USBOTGSS_IRQ1_IDPULLUP_FALL); - - dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg); - - ret = platform_device_add_resources(dwc3, pdev->resource, - pdev->num_resources); - if (ret) { - dev_err(dev, "couldn't add resources to dwc3 device\n"); - goto err2; - } - - ret = platform_device_add(dwc3); - if (ret) { - dev_err(dev, "failed to register dwc3 device\n"); - goto err2; - } - - return 0; - -err2: - platform_device_put(dwc3); - -err1: - dwc3_put_device_id(devid); - - return ret; -} - -static int __devexit dwc3_omap_remove(struct platform_device *pdev) -{ - struct dwc3_omap *omap = platform_get_drvdata(pdev); - - platform_device_unregister(omap->dwc3); - - dwc3_put_device_id(omap->dwc3->id); - - return 0; -} - -static const struct of_device_id of_dwc3_matach[] = { - { - "ti,dwc3", - }, - { }, -}; -MODULE_DEVICE_TABLE(of, of_dwc3_matach); - -static struct platform_driver dwc3_omap_driver = { - .probe = dwc3_omap_probe, - .remove = __devexit_p(dwc3_omap_remove), - .driver = { - .name = "omap-dwc3", - .of_match_table = of_dwc3_matach, - }, -}; - -module_platform_driver(dwc3_omap_driver); - -MODULE_ALIAS("platform:omap-dwc3"); -MODULE_AUTHOR("Felipe Balbi "); -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_DESCRIPTION("DesignWare USB3 OMAP Glue Layer"); diff --git a/ANDROID_3.4.5/drivers/usb/dwc3/dwc3-pci.c b/ANDROID_3.4.5/drivers/usb/dwc3/dwc3-pci.c deleted file mode 100644 index a9ca9adb..00000000 --- a/ANDROID_3.4.5/drivers/usb/dwc3/dwc3-pci.c +++ /dev/null @@ -1,173 +0,0 @@ -/** - * dwc3-pci.c - PCI Specific glue layer - * - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com - * - * Authors: Felipe Balbi , - * Sebastian Andrzej Siewior - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include - -#include "core.h" - -/* FIXME define these in */ -#define PCI_VENDOR_ID_SYNOPSYS 0x16c3 -#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd - -struct dwc3_pci { - struct device *dev; - struct platform_device *dwc3; -}; - -static int __devinit dwc3_pci_probe(struct pci_dev *pci, - const struct pci_device_id *id) -{ - struct resource res[2]; - struct platform_device *dwc3; - struct dwc3_pci *glue; - int ret = -ENOMEM; - int devid; - struct device *dev = &pci->dev; - - glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL); - if (!glue) { - dev_err(dev, "not enough memory\n"); - return -ENOMEM; - } - - glue->dev = dev; - - ret = pci_enable_device(pci); - if (ret) { - dev_err(dev, "failed to enable pci device\n"); - return -ENODEV; - } - - pci_set_power_state(pci, PCI_D0); - pci_set_master(pci); - - devid = dwc3_get_device_id(); - if (devid < 0) { - ret = -ENOMEM; - goto err1; - } - - dwc3 = platform_device_alloc("dwc3", devid); - if (!dwc3) { - dev_err(dev, "couldn't allocate dwc3 device\n"); - ret = -ENOMEM; - goto err1; - } - - memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res)); - - res[0].start = pci_resource_start(pci, 0); - res[0].end = pci_resource_end(pci, 0); - res[0].name = "dwc_usb3"; - res[0].flags = IORESOURCE_MEM; - - res[1].start = pci->irq; - res[1].name = "dwc_usb3"; - res[1].flags = IORESOURCE_IRQ; - - ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res)); - if (ret) { - dev_err(dev, "couldn't add resources to dwc3 device\n"); - goto err2; - } - - pci_set_drvdata(pci, glue); - - dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask); - - dwc3->dev.dma_mask = dev->dma_mask; - dwc3->dev.dma_parms = dev->dma_parms; - dwc3->dev.parent = dev; - glue->dwc3 = dwc3; - - ret = platform_device_add(dwc3); - if (ret) { - dev_err(dev, "failed to register dwc3 device\n"); - goto err3; - } - - return 0; - -err3: - pci_set_drvdata(pci, NULL); - platform_device_put(dwc3); - -err2: - dwc3_put_device_id(devid); - -err1: - pci_disable_device(pci); - - return ret; -} - -static void __devexit dwc3_pci_remove(struct pci_dev *pci) -{ - struct dwc3_pci *glue = pci_get_drvdata(pci); - - dwc3_put_device_id(glue->dwc3->id); - platform_device_unregister(glue->dwc3); - pci_set_drvdata(pci, NULL); - pci_disable_device(pci); -} - -static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = { - { - PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, - PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3), - }, - { } /* Terminating Entry */ -}; -MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table); - -static struct pci_driver dwc3_pci_driver = { - .name = "dwc3-pci", - .id_table = dwc3_pci_id_table, - .probe = dwc3_pci_probe, - .remove = __devexit_p(dwc3_pci_remove), -}; - -MODULE_AUTHOR("Felipe Balbi "); -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer"); - -module_pci_driver(dwc3_pci_driver); diff --git a/ANDROID_3.4.5/drivers/usb/dwc3/ep0.c b/ANDROID_3.4.5/drivers/usb/dwc3/ep0.c deleted file mode 100644 index 3584a169..00000000 --- a/ANDROID_3.4.5/drivers/usb/dwc3/ep0.c +++ /dev/null @@ -1,873 +0,0 @@ -/** - * ep0.c - DesignWare USB3 DRD Controller Endpoint 0 Handling - * - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com - * - * Authors: Felipe Balbi , - * Sebastian Andrzej Siewior - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "core.h" -#include "gadget.h" -#include "io.h" - -static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum); - -static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state) -{ - switch (state) { - case EP0_UNCONNECTED: - return "Unconnected"; - case EP0_SETUP_PHASE: - return "Setup Phase"; - case EP0_DATA_PHASE: - return "Data Phase"; - case EP0_STATUS_PHASE: - return "Status Phase"; - default: - return "UNKNOWN"; - } -} - -static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma, - u32 len, u32 type) -{ - struct dwc3_gadget_ep_cmd_params params; - struct dwc3_trb *trb; - struct dwc3_ep *dep; - - int ret; - - dep = dwc->eps[epnum]; - if (dep->flags & DWC3_EP_BUSY) { - dev_vdbg(dwc->dev, "%s: still busy\n", dep->name); - return 0; - } - - trb = dwc->ep0_trb; - - trb->bpl = lower_32_bits(buf_dma); - trb->bph = upper_32_bits(buf_dma); - trb->size = len; - trb->ctrl = type; - - trb->ctrl |= (DWC3_TRB_CTRL_HWO - | DWC3_TRB_CTRL_LST - | DWC3_TRB_CTRL_IOC - | DWC3_TRB_CTRL_ISP_IMI); - - memset(¶ms, 0, sizeof(params)); - params.param0 = upper_32_bits(dwc->ep0_trb_addr); - params.param1 = lower_32_bits(dwc->ep0_trb_addr); - - ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, - DWC3_DEPCMD_STARTTRANSFER, ¶ms); - if (ret < 0) { - dev_dbg(dwc->dev, "failed to send STARTTRANSFER command\n"); - return ret; - } - - dep->flags |= DWC3_EP_BUSY; - dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc, - dep->number); - - dwc->ep0_next_event = DWC3_EP0_COMPLETE; - - return 0; -} - -static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep, - struct dwc3_request *req) -{ - struct dwc3 *dwc = dep->dwc; - int ret = 0; - - req->request.actual = 0; - req->request.status = -EINPROGRESS; - req->epnum = dep->number; - - list_add_tail(&req->list, &dep->request_list); - - /* - * Gadget driver might not be quick enough to queue a request - * before we get a Transfer Not Ready event on this endpoint. - * - * In that case, we will set DWC3_EP_PENDING_REQUEST. When that - * flag is set, it's telling us that as soon as Gadget queues the - * required request, we should kick the transfer here because the - * IRQ we were waiting for is long gone. - */ - if (dep->flags & DWC3_EP_PENDING_REQUEST) { - unsigned direction; - - direction = !!(dep->flags & DWC3_EP0_DIR_IN); - - if (dwc->ep0state != EP0_DATA_PHASE) { - dev_WARN(dwc->dev, "Unexpected pending request\n"); - return 0; - } - - ret = dwc3_ep0_start_trans(dwc, direction, - req->request.dma, req->request.length, - DWC3_TRBCTL_CONTROL_DATA); - dep->flags &= ~(DWC3_EP_PENDING_REQUEST | - DWC3_EP0_DIR_IN); - } else if (dwc->delayed_status) { - dwc->delayed_status = false; - - if (dwc->ep0state == EP0_STATUS_PHASE) - dwc3_ep0_do_control_status(dwc, 1); - else - dev_dbg(dwc->dev, "too early for delayed status\n"); - } - - return ret; -} - -int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, - gfp_t gfp_flags) -{ - struct dwc3_request *req = to_dwc3_request(request); - struct dwc3_ep *dep = to_dwc3_ep(ep); - struct dwc3 *dwc = dep->dwc; - - unsigned long flags; - - int ret; - - spin_lock_irqsave(&dwc->lock, flags); - if (!dep->desc) { - dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n", - request, dep->name); - ret = -ESHUTDOWN; - goto out; - } - - /* we share one TRB for ep0/1 */ - if (!list_empty(&dep->request_list)) { - ret = -EBUSY; - goto out; - } - - dev_vdbg(dwc->dev, "queueing request %p to %s length %d, state '%s'\n", - request, dep->name, request->length, - dwc3_ep0_state_string(dwc->ep0state)); - - ret = __dwc3_gadget_ep0_queue(dep, req); - -out: - spin_unlock_irqrestore(&dwc->lock, flags); - - return ret; -} - -static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) -{ - struct dwc3_ep *dep = dwc->eps[0]; - - /* stall is always issued on EP0 */ - __dwc3_gadget_ep_set_halt(dep, 1); - dep->flags = DWC3_EP_ENABLED; - dwc->delayed_status = false; - - if (!list_empty(&dep->request_list)) { - struct dwc3_request *req; - - req = next_request(&dep->request_list); - dwc3_gadget_giveback(dep, req, -ECONNRESET); - } - - dwc->ep0state = EP0_SETUP_PHASE; - dwc3_ep0_out_start(dwc); -} - -void dwc3_ep0_out_start(struct dwc3 *dwc) -{ - int ret; - - ret = dwc3_ep0_start_trans(dwc, 0, dwc->ctrl_req_addr, 8, - DWC3_TRBCTL_CONTROL_SETUP); - WARN_ON(ret < 0); -} - -static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le) -{ - struct dwc3_ep *dep; - u32 windex = le16_to_cpu(wIndex_le); - u32 epnum; - - epnum = (windex & USB_ENDPOINT_NUMBER_MASK) << 1; - if ((windex & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) - epnum |= 1; - - dep = dwc->eps[epnum]; - if (dep->flags & DWC3_EP_ENABLED) - return dep; - - return NULL; -} - -static void dwc3_ep0_status_cmpl(struct usb_ep *ep, struct usb_request *req) -{ -} -/* - * ch 9.4.5 - */ -static int dwc3_ep0_handle_status(struct dwc3 *dwc, - struct usb_ctrlrequest *ctrl) -{ - struct dwc3_ep *dep; - u32 recip; - u16 usb_status = 0; - __le16 *response_pkt; - - recip = ctrl->bRequestType & USB_RECIP_MASK; - switch (recip) { - case USB_RECIP_DEVICE: - /* - * We are self-powered. U1/U2/LTM will be set later - * once we handle this states. RemoteWakeup is 0 on SS - */ - usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED; - break; - - case USB_RECIP_INTERFACE: - /* - * Function Remote Wake Capable D0 - * Function Remote Wakeup D1 - */ - break; - - case USB_RECIP_ENDPOINT: - dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex); - if (!dep) - return -EINVAL; - - if (dep->flags & DWC3_EP_STALL) - usb_status = 1 << USB_ENDPOINT_HALT; - break; - default: - return -EINVAL; - }; - - response_pkt = (__le16 *) dwc->setup_buf; - *response_pkt = cpu_to_le16(usb_status); - - dep = dwc->eps[0]; - dwc->ep0_usb_req.dep = dep; - dwc->ep0_usb_req.request.length = sizeof(*response_pkt); - dwc->ep0_usb_req.request.buf = dwc->setup_buf; - dwc->ep0_usb_req.request.complete = dwc3_ep0_status_cmpl; - - return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req); -} - -static int dwc3_ep0_handle_feature(struct dwc3 *dwc, - struct usb_ctrlrequest *ctrl, int set) -{ - struct dwc3_ep *dep; - u32 recip; - u32 wValue; - u32 wIndex; - int ret; - - wValue = le16_to_cpu(ctrl->wValue); - wIndex = le16_to_cpu(ctrl->wIndex); - recip = ctrl->bRequestType & USB_RECIP_MASK; - switch (recip) { - case USB_RECIP_DEVICE: - - /* - * 9.4.1 says only only for SS, in AddressState only for - * default control pipe - */ - switch (wValue) { - case USB_DEVICE_U1_ENABLE: - case USB_DEVICE_U2_ENABLE: - case USB_DEVICE_LTM_ENABLE: - if (dwc->dev_state != DWC3_CONFIGURED_STATE) - return -EINVAL; - if (dwc->speed != DWC3_DSTS_SUPERSPEED) - return -EINVAL; - } - - /* XXX add U[12] & LTM */ - switch (wValue) { - case USB_DEVICE_REMOTE_WAKEUP: - break; - case USB_DEVICE_U1_ENABLE: - break; - case USB_DEVICE_U2_ENABLE: - break; - case USB_DEVICE_LTM_ENABLE: - break; - - case USB_DEVICE_TEST_MODE: - if ((wIndex & 0xff) != 0) - return -EINVAL; - if (!set) - return -EINVAL; - - dwc->test_mode_nr = wIndex >> 8; - dwc->test_mode = true; - break; - default: - return -EINVAL; - } - break; - - case USB_RECIP_INTERFACE: - switch (wValue) { - case USB_INTRF_FUNC_SUSPEND: - if (wIndex & USB_INTRF_FUNC_SUSPEND_LP) - /* XXX enable Low power suspend */ - ; - if (wIndex & USB_INTRF_FUNC_SUSPEND_RW) - /* XXX enable remote wakeup */ - ; - break; - default: - return -EINVAL; - } - break; - - case USB_RECIP_ENDPOINT: - switch (wValue) { - case USB_ENDPOINT_HALT: - dep = dwc3_wIndex_to_dep(dwc, wIndex); - if (!dep) - return -EINVAL; - ret = __dwc3_gadget_ep_set_halt(dep, set); - if (ret) - return -EINVAL; - break; - default: - return -EINVAL; - } - break; - - default: - return -EINVAL; - }; - - return 0; -} - -static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) -{ - u32 addr; - u32 reg; - - addr = le16_to_cpu(ctrl->wValue); - if (addr > 127) { - dev_dbg(dwc->dev, "invalid device address %d\n", addr); - return -EINVAL; - } - - if (dwc->dev_state == DWC3_CONFIGURED_STATE) { - dev_dbg(dwc->dev, "trying to set address when configured\n"); - return -EINVAL; - } - - reg = dwc3_readl(dwc->regs, DWC3_DCFG); - reg &= ~(DWC3_DCFG_DEVADDR_MASK); - reg |= DWC3_DCFG_DEVADDR(addr); - dwc3_writel(dwc->regs, DWC3_DCFG, reg); - - if (addr) - dwc->dev_state = DWC3_ADDRESS_STATE; - else - dwc->dev_state = DWC3_DEFAULT_STATE; - - return 0; -} - -static int dwc3_ep0_delegate_req(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) -{ - int ret; - - spin_unlock(&dwc->lock); - ret = dwc->gadget_driver->setup(&dwc->gadget, ctrl); - spin_lock(&dwc->lock); - return ret; -} - -static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) -{ - u32 cfg; - int ret; - - dwc->start_config_issued = false; - cfg = le16_to_cpu(ctrl->wValue); - - switch (dwc->dev_state) { - case DWC3_DEFAULT_STATE: - return -EINVAL; - break; - - case DWC3_ADDRESS_STATE: - ret = dwc3_ep0_delegate_req(dwc, ctrl); - /* if the cfg matches and the cfg is non zero */ - if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) { - dwc->dev_state = DWC3_CONFIGURED_STATE; - dwc->resize_fifos = true; - dev_dbg(dwc->dev, "resize fifos flag SET\n"); - } - break; - - case DWC3_CONFIGURED_STATE: - ret = dwc3_ep0_delegate_req(dwc, ctrl); - if (!cfg) - dwc->dev_state = DWC3_ADDRESS_STATE; - break; - default: - ret = -EINVAL; - } - return ret; -} - -static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) -{ - int ret; - - switch (ctrl->bRequest) { - case USB_REQ_GET_STATUS: - dev_vdbg(dwc->dev, "USB_REQ_GET_STATUS\n"); - ret = dwc3_ep0_handle_status(dwc, ctrl); - break; - case USB_REQ_CLEAR_FEATURE: - dev_vdbg(dwc->dev, "USB_REQ_CLEAR_FEATURE\n"); - ret = dwc3_ep0_handle_feature(dwc, ctrl, 0); - break; - case USB_REQ_SET_FEATURE: - dev_vdbg(dwc->dev, "USB_REQ_SET_FEATURE\n"); - ret = dwc3_ep0_handle_feature(dwc, ctrl, 1); - break; - case USB_REQ_SET_ADDRESS: - dev_vdbg(dwc->dev, "USB_REQ_SET_ADDRESS\n"); - ret = dwc3_ep0_set_address(dwc, ctrl); - break; - case USB_REQ_SET_CONFIGURATION: - dev_vdbg(dwc->dev, "USB_REQ_SET_CONFIGURATION\n"); - ret = dwc3_ep0_set_config(dwc, ctrl); - break; - default: - dev_vdbg(dwc->dev, "Forwarding to gadget driver\n"); - ret = dwc3_ep0_delegate_req(dwc, ctrl); - break; - }; - - return ret; -} - -static void dwc3_ep0_inspect_setup(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) -{ - struct usb_ctrlrequest *ctrl = dwc->ctrl_req; - int ret; - u32 len; - - if (!dwc->gadget_driver) - goto err; - - len = le16_to_cpu(ctrl->wLength); - if (!len) { - dwc->three_stage_setup = false; - dwc->ep0_expect_in = false; - dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS; - } else { - dwc->three_stage_setup = true; - dwc->ep0_expect_in = !!(ctrl->bRequestType & USB_DIR_IN); - dwc->ep0_next_event = DWC3_EP0_NRDY_DATA; - } - - if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) - ret = dwc3_ep0_std_request(dwc, ctrl); - else - ret = dwc3_ep0_delegate_req(dwc, ctrl); - - if (ret == USB_GADGET_DELAYED_STATUS) - dwc->delayed_status = true; - - if (ret >= 0) - return; - -err: - dwc3_ep0_stall_and_restart(dwc); -} - -static void dwc3_ep0_complete_data(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) -{ - struct dwc3_request *r = NULL; - struct usb_request *ur; - struct dwc3_trb *trb; - struct dwc3_ep *ep0; - u32 transferred; - u32 length; - u8 epnum; - - epnum = event->endpoint_number; - ep0 = dwc->eps[0]; - - dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS; - - r = next_request(&ep0->request_list); - ur = &r->request; - - trb = dwc->ep0_trb; - length = trb->size & DWC3_TRB_SIZE_MASK; - - if (dwc->ep0_bounced) { - unsigned transfer_size = ur->length; - unsigned maxp = ep0->endpoint.maxpacket; - - transfer_size += (maxp - (transfer_size % maxp)); - transferred = min_t(u32, ur->length, - transfer_size - length); - memcpy(ur->buf, dwc->ep0_bounce, transferred); - dwc->ep0_bounced = false; - } else { - transferred = ur->length - length; - } - - ur->actual += transferred; - - if ((epnum & 1) && ur->actual < ur->length) { - /* for some reason we did not get everything out */ - - dwc3_ep0_stall_and_restart(dwc); - } else { - /* - * handle the case where we have to send a zero packet. This - * seems to be case when req.length > maxpacket. Could it be? - */ - if (r) - dwc3_gadget_giveback(ep0, r, 0); - } -} - -static void dwc3_ep0_complete_req(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) -{ - struct dwc3_request *r; - struct dwc3_ep *dep; - - dep = dwc->eps[0]; - - if (!list_empty(&dep->request_list)) { - r = next_request(&dep->request_list); - - dwc3_gadget_giveback(dep, r, 0); - } - - if (dwc->test_mode) { - int ret; - - ret = dwc3_gadget_set_test_mode(dwc, dwc->test_mode_nr); - if (ret < 0) { - dev_dbg(dwc->dev, "Invalid Test #%d\n", - dwc->test_mode_nr); - dwc3_ep0_stall_and_restart(dwc); - } - } - - dwc->ep0state = EP0_SETUP_PHASE; - dwc3_ep0_out_start(dwc); -} - -static void dwc3_ep0_xfer_complete(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) -{ - struct dwc3_ep *dep = dwc->eps[event->endpoint_number]; - - dep->flags &= ~DWC3_EP_BUSY; - dep->res_trans_idx = 0; - dwc->setup_packet_pending = false; - - switch (dwc->ep0state) { - case EP0_SETUP_PHASE: - dev_vdbg(dwc->dev, "Inspecting Setup Bytes\n"); - dwc3_ep0_inspect_setup(dwc, event); - break; - - case EP0_DATA_PHASE: - dev_vdbg(dwc->dev, "Data Phase\n"); - dwc3_ep0_complete_data(dwc, event); - break; - - case EP0_STATUS_PHASE: - dev_vdbg(dwc->dev, "Status Phase\n"); - dwc3_ep0_complete_req(dwc, event); - break; - default: - WARN(true, "UNKNOWN ep0state %d\n", dwc->ep0state); - } -} - -static void dwc3_ep0_do_control_setup(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) -{ - dwc3_ep0_out_start(dwc); -} - -static void dwc3_ep0_do_control_data(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) -{ - struct dwc3_ep *dep; - struct dwc3_request *req; - int ret; - - dep = dwc->eps[0]; - - if (list_empty(&dep->request_list)) { - dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n"); - dep->flags |= DWC3_EP_PENDING_REQUEST; - - if (event->endpoint_number) - dep->flags |= DWC3_EP0_DIR_IN; - return; - } - - req = next_request(&dep->request_list); - req->direction = !!event->endpoint_number; - - if (req->request.length == 0) { - ret = dwc3_ep0_start_trans(dwc, event->endpoint_number, - dwc->ctrl_req_addr, 0, - DWC3_TRBCTL_CONTROL_DATA); - } else if ((req->request.length % dep->endpoint.maxpacket) - && (event->endpoint_number == 0)) { - ret = usb_gadget_map_request(&dwc->gadget, &req->request, - event->endpoint_number); - if (ret) { - dev_dbg(dwc->dev, "failed to map request\n"); - return; - } - - WARN_ON(req->request.length > dep->endpoint.maxpacket); - - dwc->ep0_bounced = true; - - /* - * REVISIT in case request length is bigger than EP0 - * wMaxPacketSize, we will need two chained TRBs to handle - * the transfer. - */ - ret = dwc3_ep0_start_trans(dwc, event->endpoint_number, - dwc->ep0_bounce_addr, dep->endpoint.maxpacket, - DWC3_TRBCTL_CONTROL_DATA); - } else { - ret = usb_gadget_map_request(&dwc->gadget, &req->request, - event->endpoint_number); - if (ret) { - dev_dbg(dwc->dev, "failed to map request\n"); - return; - } - - ret = dwc3_ep0_start_trans(dwc, event->endpoint_number, - req->request.dma, req->request.length, - DWC3_TRBCTL_CONTROL_DATA); - } - - WARN_ON(ret < 0); -} - -static int dwc3_ep0_start_control_status(struct dwc3_ep *dep) -{ - struct dwc3 *dwc = dep->dwc; - u32 type; - - type = dwc->three_stage_setup ? DWC3_TRBCTL_CONTROL_STATUS3 - : DWC3_TRBCTL_CONTROL_STATUS2; - - return dwc3_ep0_start_trans(dwc, dep->number, - dwc->ctrl_req_addr, 0, type); -} - -static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum) -{ - struct dwc3_ep *dep = dwc->eps[epnum]; - - if (dwc->resize_fifos) { - dev_dbg(dwc->dev, "starting to resize fifos\n"); - dwc3_gadget_resize_tx_fifos(dwc); - dwc->resize_fifos = 0; - } - - WARN_ON(dwc3_ep0_start_control_status(dep)); -} - -static void dwc3_ep0_xfernotready(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) -{ - dwc->setup_packet_pending = true; - - /* - * This part is very tricky: If we has just handled - * XferNotReady(Setup) and we're now expecting a - * XferComplete but, instead, we receive another - * XferNotReady(Setup), we should STALL and restart - * the state machine. - * - * In all other cases, we just continue waiting - * for the XferComplete event. - * - * We are a little bit unsafe here because we're - * not trying to ensure that last event was, indeed, - * XferNotReady(Setup). - * - * Still, we don't expect any condition where that - * should happen and, even if it does, it would be - * another error condition. - */ - if (dwc->ep0_next_event == DWC3_EP0_COMPLETE) { - switch (event->status) { - case DEPEVT_STATUS_CONTROL_SETUP: - dev_vdbg(dwc->dev, "Unexpected XferNotReady(Setup)\n"); - dwc3_ep0_stall_and_restart(dwc); - break; - case DEPEVT_STATUS_CONTROL_DATA: - /* FALLTHROUGH */ - case DEPEVT_STATUS_CONTROL_STATUS: - /* FALLTHROUGH */ - default: - dev_vdbg(dwc->dev, "waiting for XferComplete\n"); - } - - return; - } - - switch (event->status) { - case DEPEVT_STATUS_CONTROL_SETUP: - dev_vdbg(dwc->dev, "Control Setup\n"); - - dwc->ep0state = EP0_SETUP_PHASE; - - dwc3_ep0_do_control_setup(dwc, event); - break; - - case DEPEVT_STATUS_CONTROL_DATA: - dev_vdbg(dwc->dev, "Control Data\n"); - - dwc->ep0state = EP0_DATA_PHASE; - - if (dwc->ep0_next_event != DWC3_EP0_NRDY_DATA) { - dev_vdbg(dwc->dev, "Expected %d got %d\n", - dwc->ep0_next_event, - DWC3_EP0_NRDY_DATA); - - dwc3_ep0_stall_and_restart(dwc); - return; - } - - /* - * One of the possible error cases is when Host _does_ - * request for Data Phase, but it does so on the wrong - * direction. - * - * Here, we already know ep0_next_event is DATA (see above), - * so we only need to check for direction. - */ - if (dwc->ep0_expect_in != event->endpoint_number) { - dev_vdbg(dwc->dev, "Wrong direction for Data phase\n"); - dwc3_ep0_stall_and_restart(dwc); - return; - } - - dwc3_ep0_do_control_data(dwc, event); - break; - - case DEPEVT_STATUS_CONTROL_STATUS: - dev_vdbg(dwc->dev, "Control Status\n"); - - dwc->ep0state = EP0_STATUS_PHASE; - - if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS) { - dev_vdbg(dwc->dev, "Expected %d got %d\n", - dwc->ep0_next_event, - DWC3_EP0_NRDY_STATUS); - - dwc3_ep0_stall_and_restart(dwc); - return; - } - - if (dwc->delayed_status) { - WARN_ON_ONCE(event->endpoint_number != 1); - dev_vdbg(dwc->dev, "Mass Storage delayed status\n"); - return; - } - - dwc3_ep0_do_control_status(dwc, event->endpoint_number); - } -} - -void dwc3_ep0_interrupt(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) -{ - u8 epnum = event->endpoint_number; - - dev_dbg(dwc->dev, "%s while ep%d%s in state '%s'\n", - dwc3_ep_event_string(event->endpoint_event), - epnum >> 1, (epnum & 1) ? "in" : "out", - dwc3_ep0_state_string(dwc->ep0state)); - - switch (event->endpoint_event) { - case DWC3_DEPEVT_XFERCOMPLETE: - dwc3_ep0_xfer_complete(dwc, event); - break; - - case DWC3_DEPEVT_XFERNOTREADY: - dwc3_ep0_xfernotready(dwc, event); - break; - - case DWC3_DEPEVT_XFERINPROGRESS: - case DWC3_DEPEVT_RXTXFIFOEVT: - case DWC3_DEPEVT_STREAMEVT: - case DWC3_DEPEVT_EPCMDCMPLT: - break; - } -} diff --git a/ANDROID_3.4.5/drivers/usb/dwc3/gadget.c b/ANDROID_3.4.5/drivers/usb/dwc3/gadget.c deleted file mode 100644 index 5255fe97..00000000 --- a/ANDROID_3.4.5/drivers/usb/dwc3/gadget.c +++ /dev/null @@ -1,2396 +0,0 @@ -/** - * gadget.c - DesignWare USB3 DRD Controller Gadget Framework Link - * - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com - * - * Authors: Felipe Balbi , - * Sebastian Andrzej Siewior - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "core.h" -#include "gadget.h" -#include "io.h" - -/** - * dwc3_gadget_set_test_mode - Enables USB2 Test Modes - * @dwc: pointer to our context structure - * @mode: the mode to set (J, K SE0 NAK, Force Enable) - * - * Caller should take care of locking. This function will - * return 0 on success or -EINVAL if wrong Test Selector - * is passed - */ -int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode) -{ - u32 reg; - - reg = dwc3_readl(dwc->regs, DWC3_DCTL); - reg &= ~DWC3_DCTL_TSTCTRL_MASK; - - switch (mode) { - case TEST_J: - case TEST_K: - case TEST_SE0_NAK: - case TEST_PACKET: - case TEST_FORCE_EN: - reg |= mode << 1; - break; - default: - return -EINVAL; - } - - dwc3_writel(dwc->regs, DWC3_DCTL, reg); - - return 0; -} - -/** - * dwc3_gadget_set_link_state - Sets USB Link to a particular State - * @dwc: pointer to our context structure - * @state: the state to put link into - * - * Caller should take care of locking. This function will - * return 0 on success or -ETIMEDOUT. - */ -int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) -{ - int retries = 10000; - u32 reg; - - reg = dwc3_readl(dwc->regs, DWC3_DCTL); - reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK; - - /* set requested state */ - reg |= DWC3_DCTL_ULSTCHNGREQ(state); - dwc3_writel(dwc->regs, DWC3_DCTL, reg); - - /* wait for a change in DSTS */ - while (--retries) { - reg = dwc3_readl(dwc->regs, DWC3_DSTS); - - if (DWC3_DSTS_USBLNKST(reg) == state) - return 0; - - udelay(5); - } - - dev_vdbg(dwc->dev, "link state change request timed out\n"); - - return -ETIMEDOUT; -} - -/** - * dwc3_gadget_resize_tx_fifos - reallocate fifo spaces for current use-case - * @dwc: pointer to our context structure - * - * This function will a best effort FIFO allocation in order - * to improve FIFO usage and throughput, while still allowing - * us to enable as many endpoints as possible. - * - * Keep in mind that this operation will be highly dependent - * on the configured size for RAM1 - which contains TxFifo -, - * the amount of endpoints enabled on coreConsultant tool, and - * the width of the Master Bus. - * - * In the ideal world, we would always be able to satisfy the - * following equation: - * - * ((512 + 2 * MDWIDTH-Bytes) + (Number of IN Endpoints - 1) * \ - * (3 * (1024 + MDWIDTH-Bytes) + MDWIDTH-Bytes)) / MDWIDTH-Bytes - * - * Unfortunately, due to many variables that's not always the case. - */ -int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc) -{ - int last_fifo_depth = 0; - int ram1_depth; - int fifo_size; - int mdwidth; - int num; - - if (!dwc->needs_fifo_resize) - return 0; - - ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7); - mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0); - - /* MDWIDTH is represented in bits, we need it in bytes */ - mdwidth >>= 3; - - /* - * FIXME For now we will only allocate 1 wMaxPacketSize space - * for each enabled endpoint, later patches will come to - * improve this algorithm so that we better use the internal - * FIFO space - */ - for (num = 0; num < DWC3_ENDPOINTS_NUM; num++) { - struct dwc3_ep *dep = dwc->eps[num]; - int fifo_number = dep->number >> 1; - int mult = 1; - int tmp; - - if (!(dep->number & 1)) - continue; - - if (!(dep->flags & DWC3_EP_ENABLED)) - continue; - - if (usb_endpoint_xfer_bulk(dep->desc) - || usb_endpoint_xfer_isoc(dep->desc)) - mult = 3; - - /* - * REVISIT: the following assumes we will always have enough - * space available on the FIFO RAM for all possible use cases. - * Make sure that's true somehow and change FIFO allocation - * accordingly. - * - * If we have Bulk or Isochronous endpoints, we want - * them to be able to be very, very fast. So we're giving - * those endpoints a fifo_size which is enough for 3 full - * packets - */ - tmp = mult * (dep->endpoint.maxpacket + mdwidth); - tmp += mdwidth; - - fifo_size = DIV_ROUND_UP(tmp, mdwidth); - - fifo_size |= (last_fifo_depth << 16); - - dev_vdbg(dwc->dev, "%s: Fifo Addr %04x Size %d\n", - dep->name, last_fifo_depth, fifo_size & 0xffff); - - dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(fifo_number), - fifo_size); - - last_fifo_depth += (fifo_size & 0xffff); - } - - return 0; -} - -void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, - int status) -{ - struct dwc3 *dwc = dep->dwc; - - if (req->queued) { - if (req->request.num_mapped_sgs) - dep->busy_slot += req->request.num_mapped_sgs; - else - dep->busy_slot++; - - /* - * Skip LINK TRB. We can't use req->trb and check for - * DWC3_TRBCTL_LINK_TRB because it points the TRB we just - * completed (not the LINK TRB). - */ - if (((dep->busy_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) && - usb_endpoint_xfer_isoc(dep->desc)) - dep->busy_slot++; - } - list_del(&req->list); - req->trb = NULL; - - if (req->request.status == -EINPROGRESS) - req->request.status = status; - - usb_gadget_unmap_request(&dwc->gadget, &req->request, - req->direction); - - dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n", - req, dep->name, req->request.actual, - req->request.length, status); - - spin_unlock(&dwc->lock); - req->request.complete(&dep->endpoint, &req->request); - spin_lock(&dwc->lock); -} - -static const char *dwc3_gadget_ep_cmd_string(u8 cmd) -{ - switch (cmd) { - case DWC3_DEPCMD_DEPSTARTCFG: - return "Start New Configuration"; - case DWC3_DEPCMD_ENDTRANSFER: - return "End Transfer"; - case DWC3_DEPCMD_UPDATETRANSFER: - return "Update Transfer"; - case DWC3_DEPCMD_STARTTRANSFER: - return "Start Transfer"; - case DWC3_DEPCMD_CLEARSTALL: - return "Clear Stall"; - case DWC3_DEPCMD_SETSTALL: - return "Set Stall"; - case DWC3_DEPCMD_GETSEQNUMBER: - return "Get Data Sequence Number"; - case DWC3_DEPCMD_SETTRANSFRESOURCE: - return "Set Endpoint Transfer Resource"; - case DWC3_DEPCMD_SETEPCONFIG: - return "Set Endpoint Configuration"; - default: - return "UNKNOWN command"; - } -} - -int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, - unsigned cmd, struct dwc3_gadget_ep_cmd_params *params) -{ - struct dwc3_ep *dep = dwc->eps[ep]; - u32 timeout = 500; - u32 reg; - - dev_vdbg(dwc->dev, "%s: cmd '%s' params %08x %08x %08x\n", - dep->name, - dwc3_gadget_ep_cmd_string(cmd), params->param0, - params->param1, params->param2); - - dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0); - dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1); - dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2); - - dwc3_writel(dwc->regs, DWC3_DEPCMD(ep), cmd | DWC3_DEPCMD_CMDACT); - do { - reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(ep)); - if (!(reg & DWC3_DEPCMD_CMDACT)) { - dev_vdbg(dwc->dev, "Command Complete --> %d\n", - DWC3_DEPCMD_STATUS(reg)); - return 0; - } - - /* - * We can't sleep here, because it is also called from - * interrupt context. - */ - timeout--; - if (!timeout) - return -ETIMEDOUT; - - udelay(1); - } while (1); -} - -static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep, - struct dwc3_trb *trb) -{ - u32 offset = (char *) trb - (char *) dep->trb_pool; - - return dep->trb_pool_dma + offset; -} - -static int dwc3_alloc_trb_pool(struct dwc3_ep *dep) -{ - struct dwc3 *dwc = dep->dwc; - - if (dep->trb_pool) - return 0; - - if (dep->number == 0 || dep->number == 1) - return 0; - - dep->trb_pool = dma_alloc_coherent(dwc->dev, - sizeof(struct dwc3_trb) * DWC3_TRB_NUM, - &dep->trb_pool_dma, GFP_KERNEL); - if (!dep->trb_pool) { - dev_err(dep->dwc->dev, "failed to allocate trb pool for %s\n", - dep->name); - return -ENOMEM; - } - - return 0; -} - -static void dwc3_free_trb_pool(struct dwc3_ep *dep) -{ - struct dwc3 *dwc = dep->dwc; - - dma_free_coherent(dwc->dev, sizeof(struct dwc3_trb) * DWC3_TRB_NUM, - dep->trb_pool, dep->trb_pool_dma); - - dep->trb_pool = NULL; - dep->trb_pool_dma = 0; -} - -static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep) -{ - struct dwc3_gadget_ep_cmd_params params; - u32 cmd; - - memset(¶ms, 0x00, sizeof(params)); - - if (dep->number != 1) { - cmd = DWC3_DEPCMD_DEPSTARTCFG; - /* XferRscIdx == 0 for ep0 and 2 for the remaining */ - if (dep->number > 1) { - if (dwc->start_config_issued) - return 0; - dwc->start_config_issued = true; - cmd |= DWC3_DEPCMD_PARAM(2); - } - - return dwc3_send_gadget_ep_cmd(dwc, 0, cmd, ¶ms); - } - - return 0; -} - -static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep, - const struct usb_endpoint_descriptor *desc, - const struct usb_ss_ep_comp_descriptor *comp_desc) -{ - struct dwc3_gadget_ep_cmd_params params; - - memset(¶ms, 0x00, sizeof(params)); - - params.param0 = DWC3_DEPCFG_EP_TYPE(usb_endpoint_type(desc)) - | DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc)) - | DWC3_DEPCFG_BURST_SIZE(dep->endpoint.maxburst); - - params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN - | DWC3_DEPCFG_XFER_NOT_READY_EN; - - if (usb_ss_max_streams(comp_desc) && usb_endpoint_xfer_bulk(desc)) { - params.param1 |= DWC3_DEPCFG_STREAM_CAPABLE - | DWC3_DEPCFG_STREAM_EVENT_EN; - dep->stream_capable = true; - } - - if (usb_endpoint_xfer_isoc(desc)) - params.param1 |= DWC3_DEPCFG_XFER_IN_PROGRESS_EN; - - /* - * We are doing 1:1 mapping for endpoints, meaning - * Physical Endpoints 2 maps to Logical Endpoint 2 and - * so on. We consider the direction bit as part of the physical - * endpoint number. So USB endpoint 0x81 is 0x03. - */ - params.param1 |= DWC3_DEPCFG_EP_NUMBER(dep->number); - - /* - * We must use the lower 16 TX FIFOs even though - * HW might have more - */ - if (dep->direction) - params.param0 |= DWC3_DEPCFG_FIFO_NUMBER(dep->number >> 1); - - if (desc->bInterval) { - params.param1 |= DWC3_DEPCFG_BINTERVAL_M1(desc->bInterval - 1); - dep->interval = 1 << (desc->bInterval - 1); - } - - return dwc3_send_gadget_ep_cmd(dwc, dep->number, - DWC3_DEPCMD_SETEPCONFIG, ¶ms); -} - -static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep) -{ - struct dwc3_gadget_ep_cmd_params params; - - memset(¶ms, 0x00, sizeof(params)); - - params.param0 = DWC3_DEPXFERCFG_NUM_XFER_RES(1); - - return dwc3_send_gadget_ep_cmd(dwc, dep->number, - DWC3_DEPCMD_SETTRANSFRESOURCE, ¶ms); -} - -/** - * __dwc3_gadget_ep_enable - Initializes a HW endpoint - * @dep: endpoint to be initialized - * @desc: USB Endpoint Descriptor - * - * Caller should take care of locking - */ -static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, - const struct usb_endpoint_descriptor *desc, - const struct usb_ss_ep_comp_descriptor *comp_desc) -{ - struct dwc3 *dwc = dep->dwc; - u32 reg; - int ret = -ENOMEM; - - if (!(dep->flags & DWC3_EP_ENABLED)) { - ret = dwc3_gadget_start_config(dwc, dep); - if (ret) - return ret; - } - - ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc); - if (ret) - return ret; - - if (!(dep->flags & DWC3_EP_ENABLED)) { - struct dwc3_trb *trb_st_hw; - struct dwc3_trb *trb_link; - - ret = dwc3_gadget_set_xfer_resource(dwc, dep); - if (ret) - return ret; - - dep->desc = desc; - dep->comp_desc = comp_desc; - dep->type = usb_endpoint_type(desc); - dep->flags |= DWC3_EP_ENABLED; - - reg = dwc3_readl(dwc->regs, DWC3_DALEPENA); - reg |= DWC3_DALEPENA_EP(dep->number); - dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); - - if (!usb_endpoint_xfer_isoc(desc)) - return 0; - - memset(&trb_link, 0, sizeof(trb_link)); - - /* Link TRB for ISOC. The HWO bit is never reset */ - trb_st_hw = &dep->trb_pool[0]; - - trb_link = &dep->trb_pool[DWC3_TRB_NUM - 1]; - - trb_link->bpl = lower_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw)); - trb_link->bph = upper_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw)); - trb_link->ctrl |= DWC3_TRBCTL_LINK_TRB; - trb_link->ctrl |= DWC3_TRB_CTRL_HWO; - } - - return 0; -} - -static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum); -static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep) -{ - struct dwc3_request *req; - - if (!list_empty(&dep->req_queued)) - dwc3_stop_active_transfer(dwc, dep->number); - - while (!list_empty(&dep->request_list)) { - req = next_request(&dep->request_list); - - dwc3_gadget_giveback(dep, req, -ESHUTDOWN); - } -} - -/** - * __dwc3_gadget_ep_disable - Disables a HW endpoint - * @dep: the endpoint to disable - * - * This function also removes requests which are currently processed ny the - * hardware and those which are not yet scheduled. - * Caller should take care of locking. - */ -static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) -{ - struct dwc3 *dwc = dep->dwc; - u32 reg; - - dwc3_remove_requests(dwc, dep); - - reg = dwc3_readl(dwc->regs, DWC3_DALEPENA); - reg &= ~DWC3_DALEPENA_EP(dep->number); - dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); - - dep->stream_capable = false; - dep->desc = NULL; - dep->endpoint.desc = NULL; - dep->comp_desc = NULL; - dep->type = 0; - dep->flags = 0; - - return 0; -} - -/* -------------------------------------------------------------------------- */ - -static int dwc3_gadget_ep0_enable(struct usb_ep *ep, - const struct usb_endpoint_descriptor *desc) -{ - return -EINVAL; -} - -static int dwc3_gadget_ep0_disable(struct usb_ep *ep) -{ - return -EINVAL; -} - -/* -------------------------------------------------------------------------- */ - -static int dwc3_gadget_ep_enable(struct usb_ep *ep, - const struct usb_endpoint_descriptor *desc) -{ - struct dwc3_ep *dep; - struct dwc3 *dwc; - unsigned long flags; - int ret; - - if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) { - pr_debug("dwc3: invalid parameters\n"); - return -EINVAL; - } - - if (!desc->wMaxPacketSize) { - pr_debug("dwc3: missing wMaxPacketSize\n"); - return -EINVAL; - } - - dep = to_dwc3_ep(ep); - dwc = dep->dwc; - - switch (usb_endpoint_type(desc)) { - case USB_ENDPOINT_XFER_CONTROL: - strlcat(dep->name, "-control", sizeof(dep->name)); - break; - case USB_ENDPOINT_XFER_ISOC: - strlcat(dep->name, "-isoc", sizeof(dep->name)); - break; - case USB_ENDPOINT_XFER_BULK: - strlcat(dep->name, "-bulk", sizeof(dep->name)); - break; - case USB_ENDPOINT_XFER_INT: - strlcat(dep->name, "-int", sizeof(dep->name)); - break; - default: - dev_err(dwc->dev, "invalid endpoint transfer type\n"); - } - - if (dep->flags & DWC3_EP_ENABLED) { - dev_WARN_ONCE(dwc->dev, true, "%s is already enabled\n", - dep->name); - return 0; - } - - dev_vdbg(dwc->dev, "Enabling %s\n", dep->name); - - spin_lock_irqsave(&dwc->lock, flags); - ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc); - spin_unlock_irqrestore(&dwc->lock, flags); - - return ret; -} - -static int dwc3_gadget_ep_disable(struct usb_ep *ep) -{ - struct dwc3_ep *dep; - struct dwc3 *dwc; - unsigned long flags; - int ret; - - if (!ep) { - pr_debug("dwc3: invalid parameters\n"); - return -EINVAL; - } - - dep = to_dwc3_ep(ep); - dwc = dep->dwc; - - if (!(dep->flags & DWC3_EP_ENABLED)) { - dev_WARN_ONCE(dwc->dev, true, "%s is already disabled\n", - dep->name); - return 0; - } - - snprintf(dep->name, sizeof(dep->name), "ep%d%s", - dep->number >> 1, - (dep->number & 1) ? "in" : "out"); - - spin_lock_irqsave(&dwc->lock, flags); - ret = __dwc3_gadget_ep_disable(dep); - spin_unlock_irqrestore(&dwc->lock, flags); - - return ret; -} - -static struct usb_request *dwc3_gadget_ep_alloc_request(struct usb_ep *ep, - gfp_t gfp_flags) -{ - struct dwc3_request *req; - struct dwc3_ep *dep = to_dwc3_ep(ep); - struct dwc3 *dwc = dep->dwc; - - req = kzalloc(sizeof(*req), gfp_flags); - if (!req) { - dev_err(dwc->dev, "not enough memory\n"); - return NULL; - } - - req->epnum = dep->number; - req->dep = dep; - - return &req->request; -} - -static void dwc3_gadget_ep_free_request(struct usb_ep *ep, - struct usb_request *request) -{ - struct dwc3_request *req = to_dwc3_request(request); - - kfree(req); -} - -/** - * dwc3_prepare_one_trb - setup one TRB from one request - * @dep: endpoint for which this request is prepared - * @req: dwc3_request pointer - */ -static void dwc3_prepare_one_trb(struct dwc3_ep *dep, - struct dwc3_request *req, dma_addr_t dma, - unsigned length, unsigned last, unsigned chain) -{ - struct dwc3 *dwc = dep->dwc; - struct dwc3_trb *trb; - - unsigned int cur_slot; - - dev_vdbg(dwc->dev, "%s: req %p dma %08llx length %d%s%s\n", - dep->name, req, (unsigned long long) dma, - length, last ? " last" : "", - chain ? " chain" : ""); - - trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK]; - cur_slot = dep->free_slot; - dep->free_slot++; - - /* Skip the LINK-TRB on ISOC */ - if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) && - usb_endpoint_xfer_isoc(dep->desc)) - return; - - if (!req->trb) { - dwc3_gadget_move_request_queued(req); - req->trb = trb; - req->trb_dma = dwc3_trb_dma_offset(dep, trb); - } - - trb->size = DWC3_TRB_SIZE_LENGTH(length); - trb->bpl = lower_32_bits(dma); - trb->bph = upper_32_bits(dma); - - switch (usb_endpoint_type(dep->desc)) { - case USB_ENDPOINT_XFER_CONTROL: - trb->ctrl = DWC3_TRBCTL_CONTROL_SETUP; - break; - - case USB_ENDPOINT_XFER_ISOC: - trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST; - - /* IOC every DWC3_TRB_NUM / 4 so we can refill */ - if (!(cur_slot % (DWC3_TRB_NUM / 4))) - trb->ctrl |= DWC3_TRB_CTRL_IOC; - break; - - case USB_ENDPOINT_XFER_BULK: - case USB_ENDPOINT_XFER_INT: - trb->ctrl = DWC3_TRBCTL_NORMAL; - break; - default: - /* - * This is only possible with faulty memory because we - * checked it already :) - */ - BUG(); - } - - if (usb_endpoint_xfer_isoc(dep->desc)) { - trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI; - trb->ctrl |= DWC3_TRB_CTRL_CSP; - } else { - if (chain) - trb->ctrl |= DWC3_TRB_CTRL_CHN; - - if (last) - trb->ctrl |= DWC3_TRB_CTRL_LST; - } - - if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable) - trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(req->request.stream_id); - - trb->ctrl |= DWC3_TRB_CTRL_HWO; -} - -/* - * dwc3_prepare_trbs - setup TRBs from requests - * @dep: endpoint for which requests are being prepared - * @starting: true if the endpoint is idle and no requests are queued. - * - * The function goes through the requests list and sets up TRBs for the - * transfers. The function returns once there are no more TRBs available or - * it runs out of requests. - */ -static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) -{ - struct dwc3_request *req, *n; - u32 trbs_left; - u32 max; - unsigned int last_one = 0; - - BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM); - - /* the first request must not be queued */ - trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK; - - /* Can't wrap around on a non-isoc EP since there's no link TRB */ - if (!usb_endpoint_xfer_isoc(dep->desc)) { - max = DWC3_TRB_NUM - (dep->free_slot & DWC3_TRB_MASK); - if (trbs_left > max) - trbs_left = max; - } - - /* - * If busy & slot are equal than it is either full or empty. If we are - * starting to process requests then we are empty. Otherwise we are - * full and don't do anything - */ - if (!trbs_left) { - if (!starting) - return; - trbs_left = DWC3_TRB_NUM; - /* - * In case we start from scratch, we queue the ISOC requests - * starting from slot 1. This is done because we use ring - * buffer and have no LST bit to stop us. Instead, we place - * IOC bit every TRB_NUM/4. We try to avoid having an interrupt - * after the first request so we start at slot 1 and have - * 7 requests proceed before we hit the first IOC. - * Other transfer types don't use the ring buffer and are - * processed from the first TRB until the last one. Since we - * don't wrap around we have to start at the beginning. - */ - if (usb_endpoint_xfer_isoc(dep->desc)) { - dep->busy_slot = 1; - dep->free_slot = 1; - } else { - dep->busy_slot = 0; - dep->free_slot = 0; - } - } - - /* The last TRB is a link TRB, not used for xfer */ - if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->desc)) - return; - - list_for_each_entry_safe(req, n, &dep->request_list, list) { - unsigned length; - dma_addr_t dma; - - if (req->request.num_mapped_sgs > 0) { - struct usb_request *request = &req->request; - struct scatterlist *sg = request->sg; - struct scatterlist *s; - int i; - - for_each_sg(sg, s, request->num_mapped_sgs, i) { - unsigned chain = true; - - length = sg_dma_len(s); - dma = sg_dma_address(s); - - if (i == (request->num_mapped_sgs - 1) || - sg_is_last(s)) { - last_one = true; - chain = false; - } - - trbs_left--; - if (!trbs_left) - last_one = true; - - if (last_one) - chain = false; - - dwc3_prepare_one_trb(dep, req, dma, length, - last_one, chain); - - if (last_one) - break; - } - } else { - dma = req->request.dma; - length = req->request.length; - trbs_left--; - - if (!trbs_left) - last_one = 1; - - /* Is this the last request? */ - if (list_is_last(&req->list, &dep->request_list)) - last_one = 1; - - dwc3_prepare_one_trb(dep, req, dma, length, - last_one, false); - - if (last_one) - break; - } - } -} - -static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param, - int start_new) -{ - struct dwc3_gadget_ep_cmd_params params; - struct dwc3_request *req; - struct dwc3 *dwc = dep->dwc; - int ret; - u32 cmd; - - if (start_new && (dep->flags & DWC3_EP_BUSY)) { - dev_vdbg(dwc->dev, "%s: endpoint busy\n", dep->name); - return -EBUSY; - } - dep->flags &= ~DWC3_EP_PENDING_REQUEST; - - /* - * If we are getting here after a short-out-packet we don't enqueue any - * new requests as we try to set the IOC bit only on the last request. - */ - if (start_new) { - if (list_empty(&dep->req_queued)) - dwc3_prepare_trbs(dep, start_new); - - /* req points to the first request which will be sent */ - req = next_request(&dep->req_queued); - } else { - dwc3_prepare_trbs(dep, start_new); - - /* - * req points to the first request where HWO changed from 0 to 1 - */ - req = next_request(&dep->req_queued); - } - if (!req) { - dep->flags |= DWC3_EP_PENDING_REQUEST; - return 0; - } - - memset(¶ms, 0, sizeof(params)); - params.param0 = upper_32_bits(req->trb_dma); - params.param1 = lower_32_bits(req->trb_dma); - - if (start_new) - cmd = DWC3_DEPCMD_STARTTRANSFER; - else - cmd = DWC3_DEPCMD_UPDATETRANSFER; - - cmd |= DWC3_DEPCMD_PARAM(cmd_param); - ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms); - if (ret < 0) { - dev_dbg(dwc->dev, "failed to send STARTTRANSFER command\n"); - - /* - * FIXME we need to iterate over the list of requests - * here and stop, unmap, free and del each of the linked - * requests instead of what we do now. - */ - usb_gadget_unmap_request(&dwc->gadget, &req->request, - req->direction); - list_del(&req->list); - return ret; - } - - dep->flags |= DWC3_EP_BUSY; - dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc, - dep->number); - - WARN_ON_ONCE(!dep->res_trans_idx); - - return 0; -} - -static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) -{ - struct dwc3 *dwc = dep->dwc; - int ret; - - req->request.actual = 0; - req->request.status = -EINPROGRESS; - req->direction = dep->direction; - req->epnum = dep->number; - - /* - * We only add to our list of requests now and - * start consuming the list once we get XferNotReady - * IRQ. - * - * That way, we avoid doing anything that we don't need - * to do now and defer it until the point we receive a - * particular token from the Host side. - * - * This will also avoid Host cancelling URBs due to too - * many NAKs. - */ - ret = usb_gadget_map_request(&dwc->gadget, &req->request, - dep->direction); - if (ret) - return ret; - - list_add_tail(&req->list, &dep->request_list); - - /* - * There is one special case: XferNotReady with - * empty list of requests. We need to kick the - * transfer here in that situation, otherwise - * we will be NAKing forever. - * - * If we get XferNotReady before gadget driver - * has a chance to queue a request, we will ACK - * the IRQ but won't be able to receive the data - * until the next request is queued. The following - * code is handling exactly that. - */ - if (dep->flags & DWC3_EP_PENDING_REQUEST) { - int ret; - int start_trans; - - start_trans = 1; - if (usb_endpoint_xfer_isoc(dep->desc) && - (dep->flags & DWC3_EP_BUSY)) - start_trans = 0; - - ret = __dwc3_gadget_kick_transfer(dep, 0, start_trans); - if (ret && ret != -EBUSY) { - struct dwc3 *dwc = dep->dwc; - - dev_dbg(dwc->dev, "%s: failed to kick transfers\n", - dep->name); - } - }; - - return 0; -} - -static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, - gfp_t gfp_flags) -{ - struct dwc3_request *req = to_dwc3_request(request); - struct dwc3_ep *dep = to_dwc3_ep(ep); - struct dwc3 *dwc = dep->dwc; - - unsigned long flags; - - int ret; - - if (!dep->desc) { - dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n", - request, ep->name); - return -ESHUTDOWN; - } - - dev_vdbg(dwc->dev, "queing request %p to %s length %d\n", - request, ep->name, request->length); - - spin_lock_irqsave(&dwc->lock, flags); - ret = __dwc3_gadget_ep_queue(dep, req); - spin_unlock_irqrestore(&dwc->lock, flags); - - return ret; -} - -static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, - struct usb_request *request) -{ - struct dwc3_request *req = to_dwc3_request(request); - struct dwc3_request *r = NULL; - - struct dwc3_ep *dep = to_dwc3_ep(ep); - struct dwc3 *dwc = dep->dwc; - - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&dwc->lock, flags); - - list_for_each_entry(r, &dep->request_list, list) { - if (r == req) - break; - } - - if (r != req) { - list_for_each_entry(r, &dep->req_queued, list) { - if (r == req) - break; - } - if (r == req) { - /* wait until it is processed */ - dwc3_stop_active_transfer(dwc, dep->number); - goto out0; - } - dev_err(dwc->dev, "request %p was not queued to %s\n", - request, ep->name); - ret = -EINVAL; - goto out0; - } - - /* giveback the request */ - dwc3_gadget_giveback(dep, req, -ECONNRESET); - -out0: - spin_unlock_irqrestore(&dwc->lock, flags); - - return ret; -} - -int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value) -{ - struct dwc3_gadget_ep_cmd_params params; - struct dwc3 *dwc = dep->dwc; - int ret; - - memset(¶ms, 0x00, sizeof(params)); - - if (value) { - if (dep->number == 0 || dep->number == 1) { - /* - * Whenever EP0 is stalled, we will restart - * the state machine, thus moving back to - * Setup Phase - */ - dwc->ep0state = EP0_SETUP_PHASE; - } - - ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, - DWC3_DEPCMD_SETSTALL, ¶ms); - if (ret) - dev_err(dwc->dev, "failed to %s STALL on %s\n", - value ? "set" : "clear", - dep->name); - else - dep->flags |= DWC3_EP_STALL; - } else { - if (dep->flags & DWC3_EP_WEDGE) - return 0; - - ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, - DWC3_DEPCMD_CLEARSTALL, ¶ms); - if (ret) - dev_err(dwc->dev, "failed to %s STALL on %s\n", - value ? "set" : "clear", - dep->name); - else - dep->flags &= ~DWC3_EP_STALL; - } - - return ret; -} - -static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value) -{ - struct dwc3_ep *dep = to_dwc3_ep(ep); - struct dwc3 *dwc = dep->dwc; - - unsigned long flags; - - int ret; - - spin_lock_irqsave(&dwc->lock, flags); - - if (usb_endpoint_xfer_isoc(dep->desc)) { - dev_err(dwc->dev, "%s is of Isochronous type\n", dep->name); - ret = -EINVAL; - goto out; - } - - ret = __dwc3_gadget_ep_set_halt(dep, value); -out: - spin_unlock_irqrestore(&dwc->lock, flags); - - return ret; -} - -static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep) -{ - struct dwc3_ep *dep = to_dwc3_ep(ep); - struct dwc3 *dwc = dep->dwc; - unsigned long flags; - - spin_lock_irqsave(&dwc->lock, flags); - dep->flags |= DWC3_EP_WEDGE; - spin_unlock_irqrestore(&dwc->lock, flags); - - return dwc3_gadget_ep_set_halt(ep, 1); -} - -/* -------------------------------------------------------------------------- */ - -static struct usb_endpoint_descriptor dwc3_gadget_ep0_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, -}; - -static const struct usb_ep_ops dwc3_gadget_ep0_ops = { - .enable = dwc3_gadget_ep0_enable, - .disable = dwc3_gadget_ep0_disable, - .alloc_request = dwc3_gadget_ep_alloc_request, - .free_request = dwc3_gadget_ep_free_request, - .queue = dwc3_gadget_ep0_queue, - .dequeue = dwc3_gadget_ep_dequeue, - .set_halt = dwc3_gadget_ep_set_halt, - .set_wedge = dwc3_gadget_ep_set_wedge, -}; - -static const struct usb_ep_ops dwc3_gadget_ep_ops = { - .enable = dwc3_gadget_ep_enable, - .disable = dwc3_gadget_ep_disable, - .alloc_request = dwc3_gadget_ep_alloc_request, - .free_request = dwc3_gadget_ep_free_request, - .queue = dwc3_gadget_ep_queue, - .dequeue = dwc3_gadget_ep_dequeue, - .set_halt = dwc3_gadget_ep_set_halt, - .set_wedge = dwc3_gadget_ep_set_wedge, -}; - -/* -------------------------------------------------------------------------- */ - -static int dwc3_gadget_get_frame(struct usb_gadget *g) -{ - struct dwc3 *dwc = gadget_to_dwc(g); - u32 reg; - - reg = dwc3_readl(dwc->regs, DWC3_DSTS); - return DWC3_DSTS_SOFFN(reg); -} - -static int dwc3_gadget_wakeup(struct usb_gadget *g) -{ - struct dwc3 *dwc = gadget_to_dwc(g); - - unsigned long timeout; - unsigned long flags; - - u32 reg; - - int ret = 0; - - u8 link_state; - u8 speed; - - spin_lock_irqsave(&dwc->lock, flags); - - /* - * According to the Databook Remote wakeup request should - * be issued only when the device is in early suspend state. - * - * We can check that via USB Link State bits in DSTS register. - */ - reg = dwc3_readl(dwc->regs, DWC3_DSTS); - - speed = reg & DWC3_DSTS_CONNECTSPD; - if (speed == DWC3_DSTS_SUPERSPEED) { - dev_dbg(dwc->dev, "no wakeup on SuperSpeed\n"); - ret = -EINVAL; - goto out; - } - - link_state = DWC3_DSTS_USBLNKST(reg); - - switch (link_state) { - case DWC3_LINK_STATE_RX_DET: /* in HS, means Early Suspend */ - case DWC3_LINK_STATE_U3: /* in HS, means SUSPEND */ - break; - default: - dev_dbg(dwc->dev, "can't wakeup from link state %d\n", - link_state); - ret = -EINVAL; - goto out; - } - - ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV); - if (ret < 0) { - dev_err(dwc->dev, "failed to put link in Recovery\n"); - goto out; - } - - /* write zeroes to Link Change Request */ - reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK; - dwc3_writel(dwc->regs, DWC3_DCTL, reg); - - /* poll until Link State changes to ON */ - timeout = jiffies + msecs_to_jiffies(100); - - while (!time_after(jiffies, timeout)) { - reg = dwc3_readl(dwc->regs, DWC3_DSTS); - - /* in HS, means ON */ - if (DWC3_DSTS_USBLNKST(reg) == DWC3_LINK_STATE_U0) - break; - } - - if (DWC3_DSTS_USBLNKST(reg) != DWC3_LINK_STATE_U0) { - dev_err(dwc->dev, "failed to send remote wakeup\n"); - ret = -EINVAL; - } - -out: - spin_unlock_irqrestore(&dwc->lock, flags); - - return ret; -} - -static int dwc3_gadget_set_selfpowered(struct usb_gadget *g, - int is_selfpowered) -{ - struct dwc3 *dwc = gadget_to_dwc(g); - unsigned long flags; - - spin_lock_irqsave(&dwc->lock, flags); - dwc->is_selfpowered = !!is_selfpowered; - spin_unlock_irqrestore(&dwc->lock, flags); - - return 0; -} - -static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on) -{ - u32 reg; - u32 timeout = 500; - - reg = dwc3_readl(dwc->regs, DWC3_DCTL); - if (is_on) { - reg &= ~DWC3_DCTL_TRGTULST_MASK; - reg |= (DWC3_DCTL_RUN_STOP - | DWC3_DCTL_TRGTULST_RX_DET); - } else { - reg &= ~DWC3_DCTL_RUN_STOP; - } - - dwc3_writel(dwc->regs, DWC3_DCTL, reg); - - do { - reg = dwc3_readl(dwc->regs, DWC3_DSTS); - if (is_on) { - if (!(reg & DWC3_DSTS_DEVCTRLHLT)) - break; - } else { - if (reg & DWC3_DSTS_DEVCTRLHLT) - break; - } - timeout--; - if (!timeout) - break; - udelay(1); - } while (1); - - dev_vdbg(dwc->dev, "gadget %s data soft-%s\n", - dwc->gadget_driver - ? dwc->gadget_driver->function : "no-function", - is_on ? "connect" : "disconnect"); -} - -static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) -{ - struct dwc3 *dwc = gadget_to_dwc(g); - unsigned long flags; - - is_on = !!is_on; - - spin_lock_irqsave(&dwc->lock, flags); - dwc3_gadget_run_stop(dwc, is_on); - spin_unlock_irqrestore(&dwc->lock, flags); - - return 0; -} - -static int dwc3_gadget_start(struct usb_gadget *g, - struct usb_gadget_driver *driver) -{ - struct dwc3 *dwc = gadget_to_dwc(g); - struct dwc3_ep *dep; - unsigned long flags; - int ret = 0; - u32 reg; - - spin_lock_irqsave(&dwc->lock, flags); - - if (dwc->gadget_driver) { - dev_err(dwc->dev, "%s is already bound to %s\n", - dwc->gadget.name, - dwc->gadget_driver->driver.name); - ret = -EBUSY; - goto err0; - } - - dwc->gadget_driver = driver; - dwc->gadget.dev.driver = &driver->driver; - - reg = dwc3_readl(dwc->regs, DWC3_DCFG); - reg &= ~(DWC3_DCFG_SPEED_MASK); - reg |= dwc->maximum_speed; - dwc3_writel(dwc->regs, DWC3_DCFG, reg); - - dwc->start_config_issued = false; - - /* Start with SuperSpeed Default */ - dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512); - - dep = dwc->eps[0]; - ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL); - if (ret) { - dev_err(dwc->dev, "failed to enable %s\n", dep->name); - goto err0; - } - - dep = dwc->eps[1]; - ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL); - if (ret) { - dev_err(dwc->dev, "failed to enable %s\n", dep->name); - goto err1; - } - - /* begin to receive SETUP packets */ - dwc->ep0state = EP0_SETUP_PHASE; - dwc3_ep0_out_start(dwc); - - spin_unlock_irqrestore(&dwc->lock, flags); - - return 0; - -err1: - __dwc3_gadget_ep_disable(dwc->eps[0]); - -err0: - spin_unlock_irqrestore(&dwc->lock, flags); - - return ret; -} - -static int dwc3_gadget_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver) -{ - struct dwc3 *dwc = gadget_to_dwc(g); - unsigned long flags; - - spin_lock_irqsave(&dwc->lock, flags); - - __dwc3_gadget_ep_disable(dwc->eps[0]); - __dwc3_gadget_ep_disable(dwc->eps[1]); - - dwc->gadget_driver = NULL; - dwc->gadget.dev.driver = NULL; - - spin_unlock_irqrestore(&dwc->lock, flags); - - return 0; -} -static const struct usb_gadget_ops dwc3_gadget_ops = { - .get_frame = dwc3_gadget_get_frame, - .wakeup = dwc3_gadget_wakeup, - .set_selfpowered = dwc3_gadget_set_selfpowered, - .pullup = dwc3_gadget_pullup, - .udc_start = dwc3_gadget_start, - .udc_stop = dwc3_gadget_stop, -}; - -/* -------------------------------------------------------------------------- */ - -static int __devinit dwc3_gadget_init_endpoints(struct dwc3 *dwc) -{ - struct dwc3_ep *dep; - u8 epnum; - - INIT_LIST_HEAD(&dwc->gadget.ep_list); - - for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) { - dep = kzalloc(sizeof(*dep), GFP_KERNEL); - if (!dep) { - dev_err(dwc->dev, "can't allocate endpoint %d\n", - epnum); - return -ENOMEM; - } - - dep->dwc = dwc; - dep->number = epnum; - dwc->eps[epnum] = dep; - - snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1, - (epnum & 1) ? "in" : "out"); - dep->endpoint.name = dep->name; - dep->direction = (epnum & 1); - - if (epnum == 0 || epnum == 1) { - dep->endpoint.maxpacket = 512; - dep->endpoint.ops = &dwc3_gadget_ep0_ops; - if (!epnum) - dwc->gadget.ep0 = &dep->endpoint; - } else { - int ret; - - dep->endpoint.maxpacket = 1024; - dep->endpoint.max_streams = 15; - dep->endpoint.ops = &dwc3_gadget_ep_ops; - list_add_tail(&dep->endpoint.ep_list, - &dwc->gadget.ep_list); - - ret = dwc3_alloc_trb_pool(dep); - if (ret) - return ret; - } - - INIT_LIST_HEAD(&dep->request_list); - INIT_LIST_HEAD(&dep->req_queued); - } - - return 0; -} - -static void dwc3_gadget_free_endpoints(struct dwc3 *dwc) -{ - struct dwc3_ep *dep; - u8 epnum; - - for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) { - dep = dwc->eps[epnum]; - dwc3_free_trb_pool(dep); - - if (epnum != 0 && epnum != 1) - list_del(&dep->endpoint.ep_list); - - kfree(dep); - } -} - -static void dwc3_gadget_release(struct device *dev) -{ - dev_dbg(dev, "%s\n", __func__); -} - -/* -------------------------------------------------------------------------- */ -static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, - const struct dwc3_event_depevt *event, int status) -{ - struct dwc3_request *req; - struct dwc3_trb *trb; - unsigned int count; - unsigned int s_pkt = 0; - - do { - req = next_request(&dep->req_queued); - if (!req) { - WARN_ON_ONCE(1); - return 1; - } - - trb = req->trb; - - if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN) - /* - * We continue despite the error. There is not much we - * can do. If we don't clean it up we loop forever. If - * we skip the TRB then it gets overwritten after a - * while since we use them in a ring buffer. A BUG() - * would help. Lets hope that if this occurs, someone - * fixes the root cause instead of looking away :) - */ - dev_err(dwc->dev, "%s's TRB (%p) still owned by HW\n", - dep->name, req->trb); - count = trb->size & DWC3_TRB_SIZE_MASK; - - if (dep->direction) { - if (count) { - dev_err(dwc->dev, "incomplete IN transfer %s\n", - dep->name); - status = -ECONNRESET; - } - } else { - if (count && (event->status & DEPEVT_STATUS_SHORT)) - s_pkt = 1; - } - - /* - * We assume here we will always receive the entire data block - * which we should receive. Meaning, if we program RX to - * receive 4K but we receive only 2K, we assume that's all we - * should receive and we simply bounce the request back to the - * gadget driver for further processing. - */ - req->request.actual += req->request.length - count; - dwc3_gadget_giveback(dep, req, status); - if (s_pkt) - break; - if ((event->status & DEPEVT_STATUS_LST) && - (trb->ctrl & DWC3_TRB_CTRL_LST)) - break; - if ((event->status & DEPEVT_STATUS_IOC) && - (trb->ctrl & DWC3_TRB_CTRL_IOC)) - break; - } while (1); - - if ((event->status & DEPEVT_STATUS_IOC) && - (trb->ctrl & DWC3_TRB_CTRL_IOC)) - return 0; - return 1; -} - -static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc, - struct dwc3_ep *dep, const struct dwc3_event_depevt *event, - int start_new) -{ - unsigned status = 0; - int clean_busy; - - if (event->status & DEPEVT_STATUS_BUSERR) - status = -ECONNRESET; - - clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status); - if (clean_busy) - dep->flags &= ~DWC3_EP_BUSY; - - /* - * WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround. - * See dwc3_gadget_linksts_change_interrupt() for 1st half. - */ - if (dwc->revision < DWC3_REVISION_183A) { - u32 reg; - int i; - - for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) { - struct dwc3_ep *dep = dwc->eps[i]; - - if (!(dep->flags & DWC3_EP_ENABLED)) - continue; - - if (!list_empty(&dep->req_queued)) - return; - } - - reg = dwc3_readl(dwc->regs, DWC3_DCTL); - reg |= dwc->u1u2; - dwc3_writel(dwc->regs, DWC3_DCTL, reg); - - dwc->u1u2 = 0; - } -} - -static void dwc3_gadget_start_isoc(struct dwc3 *dwc, - struct dwc3_ep *dep, const struct dwc3_event_depevt *event) -{ - u32 uf, mask; - - if (list_empty(&dep->request_list)) { - dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n", - dep->name); - return; - } - - mask = ~(dep->interval - 1); - uf = event->parameters & mask; - /* 4 micro frames in the future */ - uf += dep->interval * 4; - - __dwc3_gadget_kick_transfer(dep, uf, 1); -} - -static void dwc3_process_ep_cmd_complete(struct dwc3_ep *dep, - const struct dwc3_event_depevt *event) -{ - struct dwc3 *dwc = dep->dwc; - struct dwc3_event_depevt mod_ev = *event; - - /* - * We were asked to remove one request. It is possible that this - * request and a few others were started together and have the same - * transfer index. Since we stopped the complete endpoint we don't - * know how many requests were already completed (and not yet) - * reported and how could be done (later). We purge them all until - * the end of the list. - */ - mod_ev.status = DEPEVT_STATUS_LST; - dwc3_cleanup_done_reqs(dwc, dep, &mod_ev, -ESHUTDOWN); - dep->flags &= ~DWC3_EP_BUSY; - /* pending requests are ignored and are queued on XferNotReady */ -} - -static void dwc3_ep_cmd_compl(struct dwc3_ep *dep, - const struct dwc3_event_depevt *event) -{ - u32 param = event->parameters; - u32 cmd_type = (param >> 8) & ((1 << 5) - 1); - - switch (cmd_type) { - case DWC3_DEPCMD_ENDTRANSFER: - dwc3_process_ep_cmd_complete(dep, event); - break; - case DWC3_DEPCMD_STARTTRANSFER: - dep->res_trans_idx = param & 0x7f; - break; - default: - printk(KERN_ERR "%s() unknown /unexpected type: %d\n", - __func__, cmd_type); - break; - }; -} - -static void dwc3_endpoint_interrupt(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) -{ - struct dwc3_ep *dep; - u8 epnum = event->endpoint_number; - - dep = dwc->eps[epnum]; - - dev_vdbg(dwc->dev, "%s: %s\n", dep->name, - dwc3_ep_event_string(event->endpoint_event)); - - if (epnum == 0 || epnum == 1) { - dwc3_ep0_interrupt(dwc, event); - return; - } - - switch (event->endpoint_event) { - case DWC3_DEPEVT_XFERCOMPLETE: - dep->res_trans_idx = 0; - - if (usb_endpoint_xfer_isoc(dep->desc)) { - dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n", - dep->name); - return; - } - - dwc3_endpoint_transfer_complete(dwc, dep, event, 1); - break; - case DWC3_DEPEVT_XFERINPROGRESS: - if (!usb_endpoint_xfer_isoc(dep->desc)) { - dev_dbg(dwc->dev, "%s is not an Isochronous endpoint\n", - dep->name); - return; - } - - dwc3_endpoint_transfer_complete(dwc, dep, event, 0); - break; - case DWC3_DEPEVT_XFERNOTREADY: - if (usb_endpoint_xfer_isoc(dep->desc)) { - dwc3_gadget_start_isoc(dwc, dep, event); - } else { - int ret; - - dev_vdbg(dwc->dev, "%s: reason %s\n", - dep->name, event->status & - DEPEVT_STATUS_TRANSFER_ACTIVE - ? "Transfer Active" - : "Transfer Not Active"); - - ret = __dwc3_gadget_kick_transfer(dep, 0, 1); - if (!ret || ret == -EBUSY) - return; - - dev_dbg(dwc->dev, "%s: failed to kick transfers\n", - dep->name); - } - - break; - case DWC3_DEPEVT_STREAMEVT: - if (!usb_endpoint_xfer_bulk(dep->desc)) { - dev_err(dwc->dev, "Stream event for non-Bulk %s\n", - dep->name); - return; - } - - switch (event->status) { - case DEPEVT_STREAMEVT_FOUND: - dev_vdbg(dwc->dev, "Stream %d found and started\n", - event->parameters); - - break; - case DEPEVT_STREAMEVT_NOTFOUND: - /* FALLTHROUGH */ - default: - dev_dbg(dwc->dev, "Couldn't find suitable stream\n"); - } - break; - case DWC3_DEPEVT_RXTXFIFOEVT: - dev_dbg(dwc->dev, "%s FIFO Overrun\n", dep->name); - break; - case DWC3_DEPEVT_EPCMDCMPLT: - dwc3_ep_cmd_compl(dep, event); - break; - } -} - -static void dwc3_disconnect_gadget(struct dwc3 *dwc) -{ - if (dwc->gadget_driver && dwc->gadget_driver->disconnect) { - spin_unlock(&dwc->lock); - dwc->gadget_driver->disconnect(&dwc->gadget); - spin_lock(&dwc->lock); - } -} - -static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum) -{ - struct dwc3_ep *dep; - struct dwc3_gadget_ep_cmd_params params; - u32 cmd; - int ret; - - dep = dwc->eps[epnum]; - - WARN_ON(!dep->res_trans_idx); - if (dep->res_trans_idx) { - cmd = DWC3_DEPCMD_ENDTRANSFER; - cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC; - cmd |= DWC3_DEPCMD_PARAM(dep->res_trans_idx); - memset(¶ms, 0, sizeof(params)); - ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms); - WARN_ON_ONCE(ret); - dep->res_trans_idx = 0; - } -} - -static void dwc3_stop_active_transfers(struct dwc3 *dwc) -{ - u32 epnum; - - for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) { - struct dwc3_ep *dep; - - dep = dwc->eps[epnum]; - if (!(dep->flags & DWC3_EP_ENABLED)) - continue; - - dwc3_remove_requests(dwc, dep); - } -} - -static void dwc3_clear_stall_all_ep(struct dwc3 *dwc) -{ - u32 epnum; - - for (epnum = 1; epnum < DWC3_ENDPOINTS_NUM; epnum++) { - struct dwc3_ep *dep; - struct dwc3_gadget_ep_cmd_params params; - int ret; - - dep = dwc->eps[epnum]; - - if (!(dep->flags & DWC3_EP_STALL)) - continue; - - dep->flags &= ~DWC3_EP_STALL; - - memset(¶ms, 0, sizeof(params)); - ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, - DWC3_DEPCMD_CLEARSTALL, ¶ms); - WARN_ON_ONCE(ret); - } -} - -static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) -{ - dev_vdbg(dwc->dev, "%s\n", __func__); -#if 0 - XXX - U1/U2 is powersave optimization. Skip it for now. Anyway we need to - enable it before we can disable it. - - reg = dwc3_readl(dwc->regs, DWC3_DCTL); - reg &= ~DWC3_DCTL_INITU1ENA; - dwc3_writel(dwc->regs, DWC3_DCTL, reg); - - reg &= ~DWC3_DCTL_INITU2ENA; - dwc3_writel(dwc->regs, DWC3_DCTL, reg); -#endif - - dwc3_stop_active_transfers(dwc); - dwc3_disconnect_gadget(dwc); - dwc->start_config_issued = false; - - dwc->gadget.speed = USB_SPEED_UNKNOWN; - dwc->setup_packet_pending = false; -} - -static void dwc3_gadget_usb3_phy_power(struct dwc3 *dwc, int on) -{ - u32 reg; - - reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); - - if (on) - reg &= ~DWC3_GUSB3PIPECTL_SUSPHY; - else - reg |= DWC3_GUSB3PIPECTL_SUSPHY; - - dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg); -} - -static void dwc3_gadget_usb2_phy_power(struct dwc3 *dwc, int on) -{ - u32 reg; - - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); - - if (on) - reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; - else - reg |= DWC3_GUSB2PHYCFG_SUSPHY; - - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); -} - -static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) -{ - u32 reg; - - dev_vdbg(dwc->dev, "%s\n", __func__); - - /* - * WORKAROUND: DWC3 revisions <1.88a have an issue which - * would cause a missing Disconnect Event if there's a - * pending Setup Packet in the FIFO. - * - * There's no suggested workaround on the official Bug - * report, which states that "unless the driver/application - * is doing any special handling of a disconnect event, - * there is no functional issue". - * - * Unfortunately, it turns out that we _do_ some special - * handling of a disconnect event, namely complete all - * pending transfers, notify gadget driver of the - * disconnection, and so on. - * - * Our suggested workaround is to follow the Disconnect - * Event steps here, instead, based on a setup_packet_pending - * flag. Such flag gets set whenever we have a XferNotReady - * event on EP0 and gets cleared on XferComplete for the - * same endpoint. - * - * Refers to: - * - * STAR#9000466709: RTL: Device : Disconnect event not - * generated if setup packet pending in FIFO - */ - if (dwc->revision < DWC3_REVISION_188A) { - if (dwc->setup_packet_pending) - dwc3_gadget_disconnect_interrupt(dwc); - } - - /* after reset -> Default State */ - dwc->dev_state = DWC3_DEFAULT_STATE; - - /* Enable PHYs */ - dwc3_gadget_usb2_phy_power(dwc, true); - dwc3_gadget_usb3_phy_power(dwc, true); - - if (dwc->gadget.speed != USB_SPEED_UNKNOWN) - dwc3_disconnect_gadget(dwc); - - reg = dwc3_readl(dwc->regs, DWC3_DCTL); - reg &= ~DWC3_DCTL_TSTCTRL_MASK; - dwc3_writel(dwc->regs, DWC3_DCTL, reg); - dwc->test_mode = false; - - dwc3_stop_active_transfers(dwc); - dwc3_clear_stall_all_ep(dwc); - dwc->start_config_issued = false; - - /* Reset device address to zero */ - reg = dwc3_readl(dwc->regs, DWC3_DCFG); - reg &= ~(DWC3_DCFG_DEVADDR_MASK); - dwc3_writel(dwc->regs, DWC3_DCFG, reg); -} - -static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed) -{ - u32 reg; - u32 usb30_clock = DWC3_GCTL_CLK_BUS; - - /* - * We change the clock only at SS but I dunno why I would want to do - * this. Maybe it becomes part of the power saving plan. - */ - - if (speed != DWC3_DSTS_SUPERSPEED) - return; - - /* - * RAMClkSel is reset to 0 after USB reset, so it must be reprogrammed - * each time on Connect Done. - */ - if (!usb30_clock) - return; - - reg = dwc3_readl(dwc->regs, DWC3_GCTL); - reg |= DWC3_GCTL_RAMCLKSEL(usb30_clock); - dwc3_writel(dwc->regs, DWC3_GCTL, reg); -} - -static void dwc3_gadget_disable_phy(struct dwc3 *dwc, u8 speed) -{ - switch (speed) { - case USB_SPEED_SUPER: - dwc3_gadget_usb2_phy_power(dwc, false); - break; - case USB_SPEED_HIGH: - case USB_SPEED_FULL: - case USB_SPEED_LOW: - dwc3_gadget_usb3_phy_power(dwc, false); - break; - } -} - -static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) -{ - struct dwc3_gadget_ep_cmd_params params; - struct dwc3_ep *dep; - int ret; - u32 reg; - u8 speed; - - dev_vdbg(dwc->dev, "%s\n", __func__); - - memset(¶ms, 0x00, sizeof(params)); - - reg = dwc3_readl(dwc->regs, DWC3_DSTS); - speed = reg & DWC3_DSTS_CONNECTSPD; - dwc->speed = speed; - - dwc3_update_ram_clk_sel(dwc, speed); - - switch (speed) { - case DWC3_DCFG_SUPERSPEED: - /* - * WORKAROUND: DWC3 revisions <1.90a have an issue which - * would cause a missing USB3 Reset event. - * - * In such situations, we should force a USB3 Reset - * event by calling our dwc3_gadget_reset_interrupt() - * routine. - * - * Refers to: - * - * STAR#9000483510: RTL: SS : USB3 reset event may - * not be generated always when the link enters poll - */ - if (dwc->revision < DWC3_REVISION_190A) - dwc3_gadget_reset_interrupt(dwc); - - dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512); - dwc->gadget.ep0->maxpacket = 512; - dwc->gadget.speed = USB_SPEED_SUPER; - break; - case DWC3_DCFG_HIGHSPEED: - dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64); - dwc->gadget.ep0->maxpacket = 64; - dwc->gadget.speed = USB_SPEED_HIGH; - break; - case DWC3_DCFG_FULLSPEED2: - case DWC3_DCFG_FULLSPEED1: - dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64); - dwc->gadget.ep0->maxpacket = 64; - dwc->gadget.speed = USB_SPEED_FULL; - break; - case DWC3_DCFG_LOWSPEED: - dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(8); - dwc->gadget.ep0->maxpacket = 8; - dwc->gadget.speed = USB_SPEED_LOW; - break; - } - - /* Disable unneded PHY */ - dwc3_gadget_disable_phy(dwc, dwc->gadget.speed); - - dep = dwc->eps[0]; - ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL); - if (ret) { - dev_err(dwc->dev, "failed to enable %s\n", dep->name); - return; - } - - dep = dwc->eps[1]; - ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL); - if (ret) { - dev_err(dwc->dev, "failed to enable %s\n", dep->name); - return; - } - - /* - * Configure PHY via GUSB3PIPECTLn if required. - * - * Update GTXFIFOSIZn - * - * In both cases reset values should be sufficient. - */ -} - -static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc) -{ - dev_vdbg(dwc->dev, "%s\n", __func__); - - /* - * TODO take core out of low power mode when that's - * implemented. - */ - - dwc->gadget_driver->resume(&dwc->gadget); -} - -static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, - unsigned int evtinfo) -{ - enum dwc3_link_state next = evtinfo & DWC3_LINK_STATE_MASK; - - /* - * WORKAROUND: DWC3 Revisions <1.83a have an issue which, depending - * on the link partner, the USB session might do multiple entry/exit - * of low power states before a transfer takes place. - * - * Due to this problem, we might experience lower throughput. The - * suggested workaround is to disable DCTL[12:9] bits if we're - * transitioning from U1/U2 to U0 and enable those bits again - * after a transfer completes and there are no pending transfers - * on any of the enabled endpoints. - * - * This is the first half of that workaround. - * - * Refers to: - * - * STAR#9000446952: RTL: Device SS : if U1/U2 ->U0 takes >128us - * core send LGO_Ux entering U0 - */ - if (dwc->revision < DWC3_REVISION_183A) { - if (next == DWC3_LINK_STATE_U0) { - u32 u1u2; - u32 reg; - - switch (dwc->link_state) { - case DWC3_LINK_STATE_U1: - case DWC3_LINK_STATE_U2: - reg = dwc3_readl(dwc->regs, DWC3_DCTL); - u1u2 = reg & (DWC3_DCTL_INITU2ENA - | DWC3_DCTL_ACCEPTU2ENA - | DWC3_DCTL_INITU1ENA - | DWC3_DCTL_ACCEPTU1ENA); - - if (!dwc->u1u2) - dwc->u1u2 = reg & u1u2; - - reg &= ~u1u2; - - dwc3_writel(dwc->regs, DWC3_DCTL, reg); - break; - default: - /* do nothing */ - break; - } - } - } - - dwc->link_state = next; - - dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state); -} - -static void dwc3_gadget_interrupt(struct dwc3 *dwc, - const struct dwc3_event_devt *event) -{ - switch (event->type) { - case DWC3_DEVICE_EVENT_DISCONNECT: - dwc3_gadget_disconnect_interrupt(dwc); - break; - case DWC3_DEVICE_EVENT_RESET: - dwc3_gadget_reset_interrupt(dwc); - break; - case DWC3_DEVICE_EVENT_CONNECT_DONE: - dwc3_gadget_conndone_interrupt(dwc); - break; - case DWC3_DEVICE_EVENT_WAKEUP: - dwc3_gadget_wakeup_interrupt(dwc); - break; - case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE: - dwc3_gadget_linksts_change_interrupt(dwc, event->event_info); - break; - case DWC3_DEVICE_EVENT_EOPF: - dev_vdbg(dwc->dev, "End of Periodic Frame\n"); - break; - case DWC3_DEVICE_EVENT_SOF: - dev_vdbg(dwc->dev, "Start of Periodic Frame\n"); - break; - case DWC3_DEVICE_EVENT_ERRATIC_ERROR: - dev_vdbg(dwc->dev, "Erratic Error\n"); - break; - case DWC3_DEVICE_EVENT_CMD_CMPL: - dev_vdbg(dwc->dev, "Command Complete\n"); - break; - case DWC3_DEVICE_EVENT_OVERFLOW: - dev_vdbg(dwc->dev, "Overflow\n"); - break; - default: - dev_dbg(dwc->dev, "UNKNOWN IRQ %d\n", event->type); - } -} - -static void dwc3_process_event_entry(struct dwc3 *dwc, - const union dwc3_event *event) -{ - /* Endpoint IRQ, handle it and return early */ - if (event->type.is_devspec == 0) { - /* depevt */ - return dwc3_endpoint_interrupt(dwc, &event->depevt); - } - - switch (event->type.type) { - case DWC3_EVENT_TYPE_DEV: - dwc3_gadget_interrupt(dwc, &event->devt); - break; - /* REVISIT what to do with Carkit and I2C events ? */ - default: - dev_err(dwc->dev, "UNKNOWN IRQ type %d\n", event->raw); - } -} - -static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) -{ - struct dwc3_event_buffer *evt; - int left; - u32 count; - - count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf)); - count &= DWC3_GEVNTCOUNT_MASK; - if (!count) - return IRQ_NONE; - - evt = dwc->ev_buffs[buf]; - left = count; - - while (left > 0) { - union dwc3_event event; - - event.raw = *(u32 *) (evt->buf + evt->lpos); - - dwc3_process_event_entry(dwc, &event); - /* - * XXX we wrap around correctly to the next entry as almost all - * entries are 4 bytes in size. There is one entry which has 12 - * bytes which is a regular entry followed by 8 bytes data. ATM - * I don't know how things are organized if were get next to the - * a boundary so I worry about that once we try to handle that. - */ - evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE; - left -= 4; - - dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4); - } - - return IRQ_HANDLED; -} - -static irqreturn_t dwc3_interrupt(int irq, void *_dwc) -{ - struct dwc3 *dwc = _dwc; - int i; - irqreturn_t ret = IRQ_NONE; - - spin_lock(&dwc->lock); - - for (i = 0; i < dwc->num_event_buffers; i++) { - irqreturn_t status; - - status = dwc3_process_event_buf(dwc, i); - if (status == IRQ_HANDLED) - ret = status; - } - - spin_unlock(&dwc->lock); - - return ret; -} - -/** - * dwc3_gadget_init - Initializes gadget related registers - * @dwc: pointer to our controller context structure - * - * Returns 0 on success otherwise negative errno. - */ -int __devinit dwc3_gadget_init(struct dwc3 *dwc) -{ - u32 reg; - int ret; - int irq; - - dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req), - &dwc->ctrl_req_addr, GFP_KERNEL); - if (!dwc->ctrl_req) { - dev_err(dwc->dev, "failed to allocate ctrl request\n"); - ret = -ENOMEM; - goto err0; - } - - dwc->ep0_trb = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ep0_trb), - &dwc->ep0_trb_addr, GFP_KERNEL); - if (!dwc->ep0_trb) { - dev_err(dwc->dev, "failed to allocate ep0 trb\n"); - ret = -ENOMEM; - goto err1; - } - - dwc->setup_buf = kzalloc(sizeof(*dwc->setup_buf) * 2, - GFP_KERNEL); - if (!dwc->setup_buf) { - dev_err(dwc->dev, "failed to allocate setup buffer\n"); - ret = -ENOMEM; - goto err2; - } - - dwc->ep0_bounce = dma_alloc_coherent(dwc->dev, - 512, &dwc->ep0_bounce_addr, GFP_KERNEL); - if (!dwc->ep0_bounce) { - dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n"); - ret = -ENOMEM; - goto err3; - } - - dev_set_name(&dwc->gadget.dev, "gadget"); - - dwc->gadget.ops = &dwc3_gadget_ops; - dwc->gadget.max_speed = USB_SPEED_SUPER; - dwc->gadget.speed = USB_SPEED_UNKNOWN; - dwc->gadget.dev.parent = dwc->dev; - dwc->gadget.sg_supported = true; - - dma_set_coherent_mask(&dwc->gadget.dev, dwc->dev->coherent_dma_mask); - - dwc->gadget.dev.dma_parms = dwc->dev->dma_parms; - dwc->gadget.dev.dma_mask = dwc->dev->dma_mask; - dwc->gadget.dev.release = dwc3_gadget_release; - dwc->gadget.name = "dwc3-gadget"; - - /* - * REVISIT: Here we should clear all pending IRQs to be - * sure we're starting from a well known location. - */ - - ret = dwc3_gadget_init_endpoints(dwc); - if (ret) - goto err4; - - irq = platform_get_irq(to_platform_device(dwc->dev), 0); - - ret = request_irq(irq, dwc3_interrupt, IRQF_SHARED, - "dwc3", dwc); - if (ret) { - dev_err(dwc->dev, "failed to request irq #%d --> %d\n", - irq, ret); - goto err5; - } - - /* Enable all but Start and End of Frame IRQs */ - reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN | - DWC3_DEVTEN_EVNTOVERFLOWEN | - DWC3_DEVTEN_CMDCMPLTEN | - DWC3_DEVTEN_ERRTICERREN | - DWC3_DEVTEN_WKUPEVTEN | - DWC3_DEVTEN_ULSTCNGEN | - DWC3_DEVTEN_CONNECTDONEEN | - DWC3_DEVTEN_USBRSTEN | - DWC3_DEVTEN_DISCONNEVTEN); - dwc3_writel(dwc->regs, DWC3_DEVTEN, reg); - - ret = device_register(&dwc->gadget.dev); - if (ret) { - dev_err(dwc->dev, "failed to register gadget device\n"); - put_device(&dwc->gadget.dev); - goto err6; - } - - ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget); - if (ret) { - dev_err(dwc->dev, "failed to register udc\n"); - goto err7; - } - - return 0; - -err7: - device_unregister(&dwc->gadget.dev); - -err6: - dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00); - free_irq(irq, dwc); - -err5: - dwc3_gadget_free_endpoints(dwc); - -err4: - dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce, - dwc->ep0_bounce_addr); - -err3: - kfree(dwc->setup_buf); - -err2: - dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb), - dwc->ep0_trb, dwc->ep0_trb_addr); - -err1: - dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req), - dwc->ctrl_req, dwc->ctrl_req_addr); - -err0: - return ret; -} - -void dwc3_gadget_exit(struct dwc3 *dwc) -{ - int irq; - - usb_del_gadget_udc(&dwc->gadget); - irq = platform_get_irq(to_platform_device(dwc->dev), 0); - - dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00); - free_irq(irq, dwc); - - dwc3_gadget_free_endpoints(dwc); - - dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce, - dwc->ep0_bounce_addr); - - kfree(dwc->setup_buf); - - dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb), - dwc->ep0_trb, dwc->ep0_trb_addr); - - dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req), - dwc->ctrl_req, dwc->ctrl_req_addr); - - device_unregister(&dwc->gadget.dev); -} diff --git a/ANDROID_3.4.5/drivers/usb/dwc3/gadget.h b/ANDROID_3.4.5/drivers/usb/dwc3/gadget.h deleted file mode 100644 index a8600084..00000000 --- a/ANDROID_3.4.5/drivers/usb/dwc3/gadget.h +++ /dev/null @@ -1,187 +0,0 @@ -/** - * gadget.h - DesignWare USB3 DRD Gadget Header - * - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com - * - * Authors: Felipe Balbi , - * Sebastian Andrzej Siewior - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __DRIVERS_USB_DWC3_GADGET_H -#define __DRIVERS_USB_DWC3_GADGET_H - -#include -#include -#include "io.h" - -struct dwc3; -#define to_dwc3_ep(ep) (container_of(ep, struct dwc3_ep, endpoint)) -#define gadget_to_dwc(g) (container_of(g, struct dwc3, gadget)) - -/* DEPCFG parameter 1 */ -#define DWC3_DEPCFG_INT_NUM(n) ((n) << 0) -#define DWC3_DEPCFG_XFER_COMPLETE_EN (1 << 8) -#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN (1 << 9) -#define DWC3_DEPCFG_XFER_NOT_READY_EN (1 << 10) -#define DWC3_DEPCFG_FIFO_ERROR_EN (1 << 11) -#define DWC3_DEPCFG_STREAM_EVENT_EN (1 << 13) -#define DWC3_DEPCFG_BINTERVAL_M1(n) ((n) << 16) -#define DWC3_DEPCFG_STREAM_CAPABLE (1 << 24) -#define DWC3_DEPCFG_EP_NUMBER(n) ((n) << 25) -#define DWC3_DEPCFG_BULK_BASED (1 << 30) -#define DWC3_DEPCFG_FIFO_BASED (1 << 31) - -/* DEPCFG parameter 0 */ -#define DWC3_DEPCFG_EP_TYPE(n) ((n) << 1) -#define DWC3_DEPCFG_MAX_PACKET_SIZE(n) ((n) << 3) -#define DWC3_DEPCFG_FIFO_NUMBER(n) ((n) << 17) -#define DWC3_DEPCFG_BURST_SIZE(n) ((n) << 22) -#define DWC3_DEPCFG_DATA_SEQ_NUM(n) ((n) << 26) -#define DWC3_DEPCFG_IGN_SEQ_NUM (1 << 31) - -/* DEPXFERCFG parameter 0 */ -#define DWC3_DEPXFERCFG_NUM_XFER_RES(n) ((n) & 0xffff) - -struct dwc3_gadget_ep_cmd_params { - u32 param2; - u32 param1; - u32 param0; -}; - -/* -------------------------------------------------------------------------- */ - -#define to_dwc3_request(r) (container_of(r, struct dwc3_request, request)) - -static inline struct dwc3_request *next_request(struct list_head *list) -{ - if (list_empty(list)) - return NULL; - - return list_first_entry(list, struct dwc3_request, list); -} - -static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req) -{ - struct dwc3_ep *dep = req->dep; - - req->queued = true; - list_move_tail(&req->list, &dep->req_queued); -} - -void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, - int status); - -int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode); -int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state); - -void dwc3_ep0_interrupt(struct dwc3 *dwc, - const struct dwc3_event_depevt *event); -void dwc3_ep0_out_start(struct dwc3 *dwc); -int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, - gfp_t gfp_flags); -int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value); -int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, - unsigned cmd, struct dwc3_gadget_ep_cmd_params *params); - -/** - * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW - * @dwc: DesignWare USB3 Pointer - * @number: DWC endpoint number - * - * Caller should take care of locking - */ -static inline u32 dwc3_gadget_ep_get_transfer_index(struct dwc3 *dwc, u8 number) -{ - u32 res_id; - - res_id = dwc3_readl(dwc->regs, DWC3_DEPCMD(number)); - - return DWC3_DEPCMD_GET_RSC_IDX(res_id); -} - -/** - * dwc3_gadget_event_string - returns event name - * @event: the event code - */ -static inline const char *dwc3_gadget_event_string(u8 event) -{ - switch (event) { - case DWC3_DEVICE_EVENT_DISCONNECT: - return "Disconnect"; - case DWC3_DEVICE_EVENT_RESET: - return "Reset"; - case DWC3_DEVICE_EVENT_CONNECT_DONE: - return "Connection Done"; - case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE: - return "Link Status Change"; - case DWC3_DEVICE_EVENT_WAKEUP: - return "WakeUp"; - case DWC3_DEVICE_EVENT_EOPF: - return "End-Of-Frame"; - case DWC3_DEVICE_EVENT_SOF: - return "Start-Of-Frame"; - case DWC3_DEVICE_EVENT_ERRATIC_ERROR: - return "Erratic Error"; - case DWC3_DEVICE_EVENT_CMD_CMPL: - return "Command Complete"; - case DWC3_DEVICE_EVENT_OVERFLOW: - return "Overflow"; - } - - return "UNKNOWN"; -} - -/** - * dwc3_ep_event_string - returns event name - * @event: then event code - */ -static inline const char *dwc3_ep_event_string(u8 event) -{ - switch (event) { - case DWC3_DEPEVT_XFERCOMPLETE: - return "Transfer Complete"; - case DWC3_DEPEVT_XFERINPROGRESS: - return "Transfer In-Progress"; - case DWC3_DEPEVT_XFERNOTREADY: - return "Transfer Not Ready"; - case DWC3_DEPEVT_RXTXFIFOEVT: - return "FIFO"; - case DWC3_DEPEVT_STREAMEVT: - return "Stream"; - case DWC3_DEPEVT_EPCMDCMPLT: - return "Endpoint Command Complete"; - } - - return "UNKNOWN"; -} - -#endif /* __DRIVERS_USB_DWC3_GADGET_H */ diff --git a/ANDROID_3.4.5/drivers/usb/dwc3/host.c b/ANDROID_3.4.5/drivers/usb/dwc3/host.c deleted file mode 100644 index b108d18f..00000000 --- a/ANDROID_3.4.5/drivers/usb/dwc3/host.c +++ /dev/null @@ -1,102 +0,0 @@ -/** - * host.c - DesignWare USB3 DRD Controller Host Glue - * - * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com - * - * Authors: Felipe Balbi , - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -#include "core.h" - -static struct resource generic_resources[] = { - { - .flags = IORESOURCE_IRQ, - }, - { - .flags = IORESOURCE_MEM, - }, -}; - -int dwc3_host_init(struct dwc3 *dwc) -{ - struct platform_device *xhci; - int ret; - - xhci = platform_device_alloc("xhci-hcd", -1); - if (!xhci) { - dev_err(dwc->dev, "couldn't allocate xHCI device\n"); - ret = -ENOMEM; - goto err0; - } - - dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask); - - xhci->dev.parent = dwc->dev; - xhci->dev.dma_mask = dwc->dev->dma_mask; - xhci->dev.dma_parms = dwc->dev->dma_parms; - - dwc->xhci = xhci; - - /* setup resources */ - generic_resources[0].start = dwc->irq; - - generic_resources[1].start = dwc->res->start; - generic_resources[1].end = dwc->res->start + 0x7fff; - - ret = platform_device_add_resources(xhci, generic_resources, - ARRAY_SIZE(generic_resources)); - if (ret) { - dev_err(dwc->dev, "couldn't add resources to xHCI device\n"); - goto err1; - } - - ret = platform_device_add(xhci); - if (ret) { - dev_err(dwc->dev, "failed to register xHCI device\n"); - goto err1; - } - - return 0; - -err1: - platform_device_put(xhci); - -err0: - return ret; -} - -void dwc3_host_exit(struct dwc3 *dwc) -{ - platform_device_unregister(dwc->xhci); -} diff --git a/ANDROID_3.4.5/drivers/usb/dwc3/io.h b/ANDROID_3.4.5/drivers/usb/dwc3/io.h deleted file mode 100644 index 071d561f..00000000 --- a/ANDROID_3.4.5/drivers/usb/dwc3/io.h +++ /dev/null @@ -1,54 +0,0 @@ -/** - * io.h - DesignWare USB3 DRD IO Header - * - * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com - * - * Authors: Felipe Balbi , - * Sebastian Andrzej Siewior - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2, as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __DRIVERS_USB_DWC3_IO_H -#define __DRIVERS_USB_DWC3_IO_H - -#include - -static inline u32 dwc3_readl(void __iomem *base, u32 offset) -{ - return readl(base + offset); -} - -static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value) -{ - writel(value, base + offset); -} - -#endif /* __DRIVERS_USB_DWC3_IO_H */ diff --git a/ANDROID_3.4.5/drivers/usb/early/Makefile b/ANDROID_3.4.5/drivers/usb/early/Makefile deleted file mode 100644 index 24bbe519..00000000 --- a/ANDROID_3.4.5/drivers/usb/early/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# -# Makefile for early USB devices -# - -obj-$(CONFIG_EARLY_PRINTK_DBGP) += ehci-dbgp.o diff --git a/ANDROID_3.4.5/drivers/usb/early/ehci-dbgp.c b/ANDROID_3.4.5/drivers/usb/early/ehci-dbgp.c deleted file mode 100644 index 1fc8f124..00000000 --- a/ANDROID_3.4.5/drivers/usb/early/ehci-dbgp.c +++ /dev/null @@ -1,1089 +0,0 @@ -/* - * Standalone EHCI usb debug driver - * - * Originally written by: - * Eric W. Biederman" and - * Yinghai Lu - * - * Changes for early/late printk and HW errata: - * Jason Wessel - * Copyright (C) 2009 Wind River Systems, Inc. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* The code here is intended to talk directly to the EHCI debug port - * and does not require that you have any kind of USB host controller - * drivers or USB device drivers compiled into the kernel. - * - * If you make a change to anything in here, the following test cases - * need to pass where a USB debug device works in the following - * configurations. - * - * 1. boot args: earlyprintk=dbgp - * o kernel compiled with # CONFIG_USB_EHCI_HCD is not set - * o kernel compiled with CONFIG_USB_EHCI_HCD=y - * 2. boot args: earlyprintk=dbgp,keep - * o kernel compiled with # CONFIG_USB_EHCI_HCD is not set - * o kernel compiled with CONFIG_USB_EHCI_HCD=y - * 3. boot args: earlyprintk=dbgp console=ttyUSB0 - * o kernel has CONFIG_USB_EHCI_HCD=y and - * CONFIG_USB_SERIAL_DEBUG=y - * 4. boot args: earlyprintk=vga,dbgp - * o kernel compiled with # CONFIG_USB_EHCI_HCD is not set - * o kernel compiled with CONFIG_USB_EHCI_HCD=y - * - * For the 4th configuration you can turn on or off the DBGP_DEBUG - * such that you can debug the dbgp device's driver code. - */ - -static int dbgp_phys_port = 1; - -static struct ehci_caps __iomem *ehci_caps; -static struct ehci_regs __iomem *ehci_regs; -static struct ehci_dbg_port __iomem *ehci_debug; -static int dbgp_not_safe; /* Cannot use debug device during ehci reset */ -static unsigned int dbgp_endpoint_out; -static unsigned int dbgp_endpoint_in; - -struct ehci_dev { - u32 bus; - u32 slot; - u32 func; -}; - -static struct ehci_dev ehci_dev; - -#define USB_DEBUG_DEVNUM 127 - -#ifdef DBGP_DEBUG -#define dbgp_printk printk -static void dbgp_ehci_status(char *str) -{ - if (!ehci_debug) - return; - dbgp_printk("dbgp: %s\n", str); - dbgp_printk(" Debug control: %08x", readl(&ehci_debug->control)); - dbgp_printk(" ehci cmd : %08x", readl(&ehci_regs->command)); - dbgp_printk(" ehci conf flg: %08x\n", - readl(&ehci_regs->configured_flag)); - dbgp_printk(" ehci status : %08x", readl(&ehci_regs->status)); - dbgp_printk(" ehci portsc : %08x\n", - readl(&ehci_regs->port_status[dbgp_phys_port - 1])); -} -#else -static inline void dbgp_ehci_status(char *str) { } -static inline void dbgp_printk(const char *fmt, ...) { } -#endif - -static inline u32 dbgp_len_update(u32 x, u32 len) -{ - return (x & ~0x0f) | (len & 0x0f); -} - -#ifdef CONFIG_KGDB -static struct kgdb_io kgdbdbgp_io_ops; -#define dbgp_kgdb_mode (dbg_io_ops == &kgdbdbgp_io_ops) -#else -#define dbgp_kgdb_mode (0) -#endif - -/* Local version of HC_LENGTH macro as ehci struct is not available here */ -#define EARLY_HC_LENGTH(p) (0x00ff & (p)) /* bits 7 : 0 */ - -/* - * USB Packet IDs (PIDs) - */ - -/* token */ -#define USB_PID_OUT 0xe1 -#define USB_PID_IN 0x69 -#define USB_PID_SOF 0xa5 -#define USB_PID_SETUP 0x2d -/* handshake */ -#define USB_PID_ACK 0xd2 -#define USB_PID_NAK 0x5a -#define USB_PID_STALL 0x1e -#define USB_PID_NYET 0x96 -/* data */ -#define USB_PID_DATA0 0xc3 -#define USB_PID_DATA1 0x4b -#define USB_PID_DATA2 0x87 -#define USB_PID_MDATA 0x0f -/* Special */ -#define USB_PID_PREAMBLE 0x3c -#define USB_PID_ERR 0x3c -#define USB_PID_SPLIT 0x78 -#define USB_PID_PING 0xb4 -#define USB_PID_UNDEF_0 0xf0 - -#define USB_PID_DATA_TOGGLE 0x88 -#define DBGP_CLAIM (DBGP_OWNER | DBGP_ENABLED | DBGP_INUSE) - -#define PCI_CAP_ID_EHCI_DEBUG 0xa - -#define HUB_ROOT_RESET_TIME 50 /* times are in msec */ -#define HUB_SHORT_RESET_TIME 10 -#define HUB_LONG_RESET_TIME 200 -#define HUB_RESET_TIMEOUT 500 - -#define DBGP_MAX_PACKET 8 -#define DBGP_TIMEOUT (250 * 1000) -#define DBGP_LOOPS 1000 - -static inline u32 dbgp_pid_write_update(u32 x, u32 tok) -{ - static int data0 = USB_PID_DATA1; - data0 ^= USB_PID_DATA_TOGGLE; - return (x & 0xffff0000) | (data0 << 8) | (tok & 0xff); -} - -static inline u32 dbgp_pid_read_update(u32 x, u32 tok) -{ - return (x & 0xffff0000) | (USB_PID_DATA0 << 8) | (tok & 0xff); -} - -static int dbgp_wait_until_complete(void) -{ - u32 ctrl; - int loop = DBGP_TIMEOUT; - - do { - ctrl = readl(&ehci_debug->control); - /* Stop when the transaction is finished */ - if (ctrl & DBGP_DONE) - break; - udelay(1); - } while (--loop > 0); - - if (!loop) - return -DBGP_TIMEOUT; - - /* - * Now that we have observed the completed transaction, - * clear the done bit. - */ - writel(ctrl | DBGP_DONE, &ehci_debug->control); - return (ctrl & DBGP_ERROR) ? -DBGP_ERRCODE(ctrl) : DBGP_LEN(ctrl); -} - -static inline void dbgp_mdelay(int ms) -{ - int i; - - while (ms--) { - for (i = 0; i < 1000; i++) - outb(0x1, 0x80); - } -} - -static void dbgp_breath(void) -{ - /* Sleep to give the debug port a chance to breathe */ -} - -static int dbgp_wait_until_done(unsigned ctrl, int loop) -{ - u32 pids, lpid; - int ret; - -retry: - writel(ctrl | DBGP_GO, &ehci_debug->control); - ret = dbgp_wait_until_complete(); - pids = readl(&ehci_debug->pids); - lpid = DBGP_PID_GET(pids); - - if (ret < 0) { - /* A -DBGP_TIMEOUT failure here means the device has - * failed, perhaps because it was unplugged, in which - * case we do not want to hang the system so the dbgp - * will be marked as unsafe to use. EHCI reset is the - * only way to recover if you unplug the dbgp device. - */ - if (ret == -DBGP_TIMEOUT && !dbgp_not_safe) - dbgp_not_safe = 1; - if (ret == -DBGP_ERR_BAD && --loop > 0) - goto retry; - return ret; - } - - /* - * If the port is getting full or it has dropped data - * start pacing ourselves, not necessary but it's friendly. - */ - if ((lpid == USB_PID_NAK) || (lpid == USB_PID_NYET)) - dbgp_breath(); - - /* If I get a NACK reissue the transmission */ - if (lpid == USB_PID_NAK) { - if (--loop > 0) - goto retry; - } - - return ret; -} - -static inline void dbgp_set_data(const void *buf, int size) -{ - const unsigned char *bytes = buf; - u32 lo, hi; - int i; - - lo = hi = 0; - for (i = 0; i < 4 && i < size; i++) - lo |= bytes[i] << (8*i); - for (; i < 8 && i < size; i++) - hi |= bytes[i] << (8*(i - 4)); - writel(lo, &ehci_debug->data03); - writel(hi, &ehci_debug->data47); -} - -static inline void dbgp_get_data(void *buf, int size) -{ - unsigned char *bytes = buf; - u32 lo, hi; - int i; - - lo = readl(&ehci_debug->data03); - hi = readl(&ehci_debug->data47); - for (i = 0; i < 4 && i < size; i++) - bytes[i] = (lo >> (8*i)) & 0xff; - for (; i < 8 && i < size; i++) - bytes[i] = (hi >> (8*(i - 4))) & 0xff; -} - -static int dbgp_bulk_write(unsigned devnum, unsigned endpoint, - const char *bytes, int size) -{ - int ret; - u32 addr; - u32 pids, ctrl; - - if (size > DBGP_MAX_PACKET) - return -1; - - addr = DBGP_EPADDR(devnum, endpoint); - - pids = readl(&ehci_debug->pids); - pids = dbgp_pid_write_update(pids, USB_PID_OUT); - - ctrl = readl(&ehci_debug->control); - ctrl = dbgp_len_update(ctrl, size); - ctrl |= DBGP_OUT; - ctrl |= DBGP_GO; - - dbgp_set_data(bytes, size); - writel(addr, &ehci_debug->address); - writel(pids, &ehci_debug->pids); - ret = dbgp_wait_until_done(ctrl, DBGP_LOOPS); - - return ret; -} - -static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data, - int size, int loops) -{ - u32 pids, addr, ctrl; - int ret; - - if (size > DBGP_MAX_PACKET) - return -1; - - addr = DBGP_EPADDR(devnum, endpoint); - - pids = readl(&ehci_debug->pids); - pids = dbgp_pid_read_update(pids, USB_PID_IN); - - ctrl = readl(&ehci_debug->control); - ctrl = dbgp_len_update(ctrl, size); - ctrl &= ~DBGP_OUT; - ctrl |= DBGP_GO; - - writel(addr, &ehci_debug->address); - writel(pids, &ehci_debug->pids); - ret = dbgp_wait_until_done(ctrl, loops); - if (ret < 0) - return ret; - - if (size > ret) - size = ret; - dbgp_get_data(data, size); - return ret; -} - -static int dbgp_control_msg(unsigned devnum, int requesttype, - int request, int value, int index, void *data, int size) -{ - u32 pids, addr, ctrl; - struct usb_ctrlrequest req; - int read; - int ret; - - read = (requesttype & USB_DIR_IN) != 0; - if (size > (read ? DBGP_MAX_PACKET:0)) - return -1; - - /* Compute the control message */ - req.bRequestType = requesttype; - req.bRequest = request; - req.wValue = cpu_to_le16(value); - req.wIndex = cpu_to_le16(index); - req.wLength = cpu_to_le16(size); - - pids = DBGP_PID_SET(USB_PID_DATA0, USB_PID_SETUP); - addr = DBGP_EPADDR(devnum, 0); - - ctrl = readl(&ehci_debug->control); - ctrl = dbgp_len_update(ctrl, sizeof(req)); - ctrl |= DBGP_OUT; - ctrl |= DBGP_GO; - - /* Send the setup message */ - dbgp_set_data(&req, sizeof(req)); - writel(addr, &ehci_debug->address); - writel(pids, &ehci_debug->pids); - ret = dbgp_wait_until_done(ctrl, DBGP_LOOPS); - if (ret < 0) - return ret; - - /* Read the result */ - return dbgp_bulk_read(devnum, 0, data, size, DBGP_LOOPS); -} - -/* Find a PCI capability */ -static u32 __init find_cap(u32 num, u32 slot, u32 func, int cap) -{ - u8 pos; - int bytes; - - if (!(read_pci_config_16(num, slot, func, PCI_STATUS) & - PCI_STATUS_CAP_LIST)) - return 0; - - pos = read_pci_config_byte(num, slot, func, PCI_CAPABILITY_LIST); - for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) { - u8 id; - - pos &= ~3; - id = read_pci_config_byte(num, slot, func, pos+PCI_CAP_LIST_ID); - if (id == 0xff) - break; - if (id == cap) - return pos; - - pos = read_pci_config_byte(num, slot, func, - pos+PCI_CAP_LIST_NEXT); - } - return 0; -} - -static u32 __init __find_dbgp(u32 bus, u32 slot, u32 func) -{ - u32 class; - - class = read_pci_config(bus, slot, func, PCI_CLASS_REVISION); - if ((class >> 8) != PCI_CLASS_SERIAL_USB_EHCI) - return 0; - - return find_cap(bus, slot, func, PCI_CAP_ID_EHCI_DEBUG); -} - -static u32 __init find_dbgp(int ehci_num, u32 *rbus, u32 *rslot, u32 *rfunc) -{ - u32 bus, slot, func; - - for (bus = 0; bus < 256; bus++) { - for (slot = 0; slot < 32; slot++) { - for (func = 0; func < 8; func++) { - unsigned cap; - - cap = __find_dbgp(bus, slot, func); - - if (!cap) - continue; - if (ehci_num-- != 0) - continue; - *rbus = bus; - *rslot = slot; - *rfunc = func; - return cap; - } - } - } - return 0; -} - -static int dbgp_ehci_startup(void) -{ - u32 ctrl, cmd, status; - int loop; - - /* Claim ownership, but do not enable yet */ - ctrl = readl(&ehci_debug->control); - ctrl |= DBGP_OWNER; - ctrl &= ~(DBGP_ENABLED | DBGP_INUSE); - writel(ctrl, &ehci_debug->control); - udelay(1); - - dbgp_ehci_status("EHCI startup"); - /* Start the ehci running */ - cmd = readl(&ehci_regs->command); - cmd &= ~(CMD_LRESET | CMD_IAAD | CMD_PSE | CMD_ASE | CMD_RESET); - cmd |= CMD_RUN; - writel(cmd, &ehci_regs->command); - - /* Ensure everything is routed to the EHCI */ - writel(FLAG_CF, &ehci_regs->configured_flag); - - /* Wait until the controller is no longer halted */ - loop = 10; - do { - status = readl(&ehci_regs->status); - if (!(status & STS_HALT)) - break; - udelay(1); - } while (--loop > 0); - - if (!loop) { - dbgp_printk("ehci can not be started\n"); - return -ENODEV; - } - dbgp_printk("ehci started\n"); - return 0; -} - -static int dbgp_ehci_controller_reset(void) -{ - int loop = 250 * 1000; - u32 cmd; - - /* Reset the EHCI controller */ - cmd = readl(&ehci_regs->command); - cmd |= CMD_RESET; - writel(cmd, &ehci_regs->command); - do { - cmd = readl(&ehci_regs->command); - } while ((cmd & CMD_RESET) && (--loop > 0)); - - if (!loop) { - dbgp_printk("can not reset ehci\n"); - return -1; - } - dbgp_ehci_status("ehci reset done"); - return 0; -} -static int ehci_wait_for_port(int port); -/* Return 0 on success - * Return -ENODEV for any general failure - * Return -EIO if wait for port fails - */ -int dbgp_external_startup(void) -{ - int devnum; - struct usb_debug_descriptor dbgp_desc; - int ret; - u32 ctrl, portsc, cmd; - int dbg_port = dbgp_phys_port; - int tries = 3; - int reset_port_tries = 1; - int try_hard_once = 1; - -try_port_reset_again: - ret = dbgp_ehci_startup(); - if (ret) - return ret; - - /* Wait for a device to show up in the debug port */ - ret = ehci_wait_for_port(dbg_port); - if (ret < 0) { - portsc = readl(&ehci_regs->port_status[dbg_port - 1]); - if (!(portsc & PORT_CONNECT) && try_hard_once) { - /* Last ditch effort to try to force enable - * the debug device by using the packet test - * ehci command to try and wake it up. */ - try_hard_once = 0; - cmd = readl(&ehci_regs->command); - cmd &= ~CMD_RUN; - writel(cmd, &ehci_regs->command); - portsc = readl(&ehci_regs->port_status[dbg_port - 1]); - portsc |= PORT_TEST_PKT; - writel(portsc, &ehci_regs->port_status[dbg_port - 1]); - dbgp_ehci_status("Trying to force debug port online"); - mdelay(50); - dbgp_ehci_controller_reset(); - goto try_port_reset_again; - } else if (reset_port_tries--) { - goto try_port_reset_again; - } - dbgp_printk("No device found in debug port\n"); - return -EIO; - } - dbgp_ehci_status("wait for port done"); - - /* Enable the debug port */ - ctrl = readl(&ehci_debug->control); - ctrl |= DBGP_CLAIM; - writel(ctrl, &ehci_debug->control); - ctrl = readl(&ehci_debug->control); - if ((ctrl & DBGP_CLAIM) != DBGP_CLAIM) { - dbgp_printk("No device in debug port\n"); - writel(ctrl & ~DBGP_CLAIM, &ehci_debug->control); - return -ENODEV; - } - dbgp_ehci_status("debug ported enabled"); - - /* Completely transfer the debug device to the debug controller */ - portsc = readl(&ehci_regs->port_status[dbg_port - 1]); - portsc &= ~PORT_PE; - writel(portsc, &ehci_regs->port_status[dbg_port - 1]); - - dbgp_mdelay(100); - -try_again: - /* Find the debug device and make it device number 127 */ - for (devnum = 0; devnum <= 127; devnum++) { - ret = dbgp_control_msg(devnum, - USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE, - USB_REQ_GET_DESCRIPTOR, (USB_DT_DEBUG << 8), 0, - &dbgp_desc, sizeof(dbgp_desc)); - if (ret > 0) - break; - } - if (devnum > 127) { - dbgp_printk("Could not find attached debug device\n"); - goto err; - } - if (ret < 0) { - dbgp_printk("Attached device is not a debug device\n"); - goto err; - } - dbgp_endpoint_out = dbgp_desc.bDebugOutEndpoint; - dbgp_endpoint_in = dbgp_desc.bDebugInEndpoint; - - /* Move the device to 127 if it isn't already there */ - if (devnum != USB_DEBUG_DEVNUM) { - ret = dbgp_control_msg(devnum, - USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, - USB_REQ_SET_ADDRESS, USB_DEBUG_DEVNUM, 0, NULL, 0); - if (ret < 0) { - dbgp_printk("Could not move attached device to %d\n", - USB_DEBUG_DEVNUM); - goto err; - } - devnum = USB_DEBUG_DEVNUM; - dbgp_printk("debug device renamed to 127\n"); - } - - /* Enable the debug interface */ - ret = dbgp_control_msg(USB_DEBUG_DEVNUM, - USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, - USB_REQ_SET_FEATURE, USB_DEVICE_DEBUG_MODE, 0, NULL, 0); - if (ret < 0) { - dbgp_printk(" Could not enable the debug device\n"); - goto err; - } - dbgp_printk("debug interface enabled\n"); - /* Perform a small write to get the even/odd data state in sync - */ - ret = dbgp_bulk_write(USB_DEBUG_DEVNUM, dbgp_endpoint_out, " ", 1); - if (ret < 0) { - dbgp_printk("dbgp_bulk_write failed: %d\n", ret); - goto err; - } - dbgp_printk("small write done\n"); - dbgp_not_safe = 0; - - return 0; -err: - if (tries--) - goto try_again; - return -ENODEV; -} -EXPORT_SYMBOL_GPL(dbgp_external_startup); - -static int ehci_reset_port(int port) -{ - u32 portsc; - u32 delay_time, delay; - int loop; - - dbgp_ehci_status("reset port"); - /* Reset the usb debug port */ - portsc = readl(&ehci_regs->port_status[port - 1]); - portsc &= ~PORT_PE; - portsc |= PORT_RESET; - writel(portsc, &ehci_regs->port_status[port - 1]); - - delay = HUB_ROOT_RESET_TIME; - for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT; - delay_time += delay) { - dbgp_mdelay(delay); - portsc = readl(&ehci_regs->port_status[port - 1]); - if (!(portsc & PORT_RESET)) - break; - } - if (portsc & PORT_RESET) { - /* force reset to complete */ - loop = 100 * 1000; - writel(portsc & ~(PORT_RWC_BITS | PORT_RESET), - &ehci_regs->port_status[port - 1]); - do { - udelay(1); - portsc = readl(&ehci_regs->port_status[port-1]); - } while ((portsc & PORT_RESET) && (--loop > 0)); - } - - /* Device went away? */ - if (!(portsc & PORT_CONNECT)) - return -ENOTCONN; - - /* bomb out completely if something weird happened */ - if ((portsc & PORT_CSC)) - return -EINVAL; - - /* If we've finished resetting, then break out of the loop */ - if (!(portsc & PORT_RESET) && (portsc & PORT_PE)) - return 0; - return -EBUSY; -} - -static int ehci_wait_for_port(int port) -{ - u32 status; - int ret, reps; - - for (reps = 0; reps < 300; reps++) { - status = readl(&ehci_regs->status); - if (status & STS_PCD) - break; - dbgp_mdelay(1); - } - ret = ehci_reset_port(port); - if (ret == 0) - return 0; - return -ENOTCONN; -} - -typedef void (*set_debug_port_t)(int port); - -static void __init default_set_debug_port(int port) -{ -} - -static set_debug_port_t __initdata set_debug_port = default_set_debug_port; - -static void __init nvidia_set_debug_port(int port) -{ - u32 dword; - dword = read_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func, - 0x74); - dword &= ~(0x0f<<12); - dword |= ((port & 0x0f)<<12); - write_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func, 0x74, - dword); - dbgp_printk("set debug port to %d\n", port); -} - -static void __init detect_set_debug_port(void) -{ - u32 vendorid; - - vendorid = read_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func, - 0x00); - - if ((vendorid & 0xffff) == 0x10de) { - dbgp_printk("using nvidia set_debug_port\n"); - set_debug_port = nvidia_set_debug_port; - } -} - -/* The code in early_ehci_bios_handoff() is derived from the usb pci - * quirk initialization, but altered so as to use the early PCI - * routines. */ -#define EHCI_USBLEGSUP_BIOS (1 << 16) /* BIOS semaphore */ -#define EHCI_USBLEGCTLSTS 4 /* legacy control/status */ -static void __init early_ehci_bios_handoff(void) -{ - u32 hcc_params = readl(&ehci_caps->hcc_params); - int offset = (hcc_params >> 8) & 0xff; - u32 cap; - int msec; - - if (!offset) - return; - - cap = read_pci_config(ehci_dev.bus, ehci_dev.slot, - ehci_dev.func, offset); - dbgp_printk("dbgp: ehci BIOS state %08x\n", cap); - - if ((cap & 0xff) == 1 && (cap & EHCI_USBLEGSUP_BIOS)) { - dbgp_printk("dbgp: BIOS handoff\n"); - write_pci_config_byte(ehci_dev.bus, ehci_dev.slot, - ehci_dev.func, offset + 3, 1); - } - - /* if boot firmware now owns EHCI, spin till it hands it over. */ - msec = 1000; - while ((cap & EHCI_USBLEGSUP_BIOS) && (msec > 0)) { - mdelay(10); - msec -= 10; - cap = read_pci_config(ehci_dev.bus, ehci_dev.slot, - ehci_dev.func, offset); - } - - if (cap & EHCI_USBLEGSUP_BIOS) { - /* well, possibly buggy BIOS... try to shut it down, - * and hope nothing goes too wrong */ - dbgp_printk("dbgp: BIOS handoff failed: %08x\n", cap); - write_pci_config_byte(ehci_dev.bus, ehci_dev.slot, - ehci_dev.func, offset + 2, 0); - } - - /* just in case, always disable EHCI SMIs */ - write_pci_config_byte(ehci_dev.bus, ehci_dev.slot, ehci_dev.func, - offset + EHCI_USBLEGCTLSTS, 0); -} - -static int __init ehci_setup(void) -{ - u32 ctrl, portsc, hcs_params; - u32 debug_port, new_debug_port = 0, n_ports; - int ret, i; - int port_map_tried; - int playtimes = 3; - - early_ehci_bios_handoff(); - -try_next_time: - port_map_tried = 0; - -try_next_port: - - hcs_params = readl(&ehci_caps->hcs_params); - debug_port = HCS_DEBUG_PORT(hcs_params); - dbgp_phys_port = debug_port; - n_ports = HCS_N_PORTS(hcs_params); - - dbgp_printk("debug_port: %d\n", debug_port); - dbgp_printk("n_ports: %d\n", n_ports); - dbgp_ehci_status(""); - - for (i = 1; i <= n_ports; i++) { - portsc = readl(&ehci_regs->port_status[i-1]); - dbgp_printk("portstatus%d: %08x\n", i, portsc); - } - - if (port_map_tried && (new_debug_port != debug_port)) { - if (--playtimes) { - set_debug_port(new_debug_port); - goto try_next_time; - } - return -1; - } - - /* Only reset the controller if it is not already in the - * configured state */ - if (!(readl(&ehci_regs->configured_flag) & FLAG_CF)) { - if (dbgp_ehci_controller_reset() != 0) - return -1; - } else { - dbgp_ehci_status("ehci skip - already configured"); - } - - ret = dbgp_external_startup(); - if (ret == -EIO) - goto next_debug_port; - - if (ret < 0) { - /* Things didn't work so remove my claim */ - ctrl = readl(&ehci_debug->control); - ctrl &= ~(DBGP_CLAIM | DBGP_OUT); - writel(ctrl, &ehci_debug->control); - return -1; - } - return 0; - -next_debug_port: - port_map_tried |= (1<<(debug_port - 1)); - new_debug_port = ((debug_port-1+1)%n_ports) + 1; - if (port_map_tried != ((1<> 29) & 0x7; - bar = (bar * 4) + 0xc; - offset = (debug_port >> 16) & 0xfff; - dbgp_printk("bar: %02x offset: %03x\n", bar, offset); - if (bar != PCI_BASE_ADDRESS_0) { - dbgp_printk("only debug ports on bar 1 handled.\n"); - - return -1; - } - - bar_val = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0); - dbgp_printk("bar_val: %02x offset: %03x\n", bar_val, offset); - if (bar_val & ~PCI_BASE_ADDRESS_MEM_MASK) { - dbgp_printk("only simple 32bit mmio bars supported\n"); - - return -1; - } - - /* double check if the mem space is enabled */ - byte = read_pci_config_byte(bus, slot, func, 0x04); - if (!(byte & 0x2)) { - byte |= 0x02; - write_pci_config_byte(bus, slot, func, 0x04, byte); - dbgp_printk("mmio for ehci enabled\n"); - } - - /* - * FIXME I don't have the bar size so just guess PAGE_SIZE is more - * than enough. 1K is the biggest I have seen. - */ - set_fixmap_nocache(FIX_DBGP_BASE, bar_val & PAGE_MASK); - ehci_bar = (void __iomem *)__fix_to_virt(FIX_DBGP_BASE); - ehci_bar += bar_val & ~PAGE_MASK; - dbgp_printk("ehci_bar: %p\n", ehci_bar); - - ehci_caps = ehci_bar; - ehci_regs = ehci_bar + EARLY_HC_LENGTH(readl(&ehci_caps->hc_capbase)); - ehci_debug = ehci_bar + offset; - ehci_dev.bus = bus; - ehci_dev.slot = slot; - ehci_dev.func = func; - - detect_set_debug_port(); - - ret = ehci_setup(); - if (ret < 0) { - dbgp_printk("ehci_setup failed\n"); - ehci_debug = NULL; - - return -1; - } - dbgp_ehci_status("early_init_complete"); - - return 0; -} - -static void early_dbgp_write(struct console *con, const char *str, u32 n) -{ - int chunk, ret; - char buf[DBGP_MAX_PACKET]; - int use_cr = 0; - u32 cmd, ctrl; - int reset_run = 0; - - if (!ehci_debug || dbgp_not_safe) - return; - - cmd = readl(&ehci_regs->command); - if (unlikely(!(cmd & CMD_RUN))) { - /* If the ehci controller is not in the run state do extended - * checks to see if the acpi or some other initialization also - * reset the ehci debug port */ - ctrl = readl(&ehci_debug->control); - if (!(ctrl & DBGP_ENABLED)) { - dbgp_not_safe = 1; - dbgp_external_startup(); - } else { - cmd |= CMD_RUN; - writel(cmd, &ehci_regs->command); - reset_run = 1; - } - } - while (n > 0) { - for (chunk = 0; chunk < DBGP_MAX_PACKET && n > 0; - str++, chunk++, n--) { - if (!use_cr && *str == '\n') { - use_cr = 1; - buf[chunk] = '\r'; - str--; - n++; - continue; - } - if (use_cr) - use_cr = 0; - buf[chunk] = *str; - } - if (chunk > 0) { - ret = dbgp_bulk_write(USB_DEBUG_DEVNUM, - dbgp_endpoint_out, buf, chunk); - } - } - if (unlikely(reset_run)) { - cmd = readl(&ehci_regs->command); - cmd &= ~CMD_RUN; - writel(cmd, &ehci_regs->command); - } -} - -struct console early_dbgp_console = { - .name = "earlydbg", - .write = early_dbgp_write, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - -int dbgp_reset_prep(void) -{ - u32 ctrl; - - dbgp_not_safe = 1; - if (!ehci_debug) - return 0; - - if ((early_dbgp_console.index != -1 && - !(early_dbgp_console.flags & CON_BOOT)) || - dbgp_kgdb_mode) - return 1; - /* This means the console is not initialized, or should get - * shutdown so as to allow for reuse of the usb device, which - * means it is time to shutdown the usb debug port. */ - ctrl = readl(&ehci_debug->control); - if (ctrl & DBGP_ENABLED) { - ctrl &= ~(DBGP_CLAIM); - writel(ctrl, &ehci_debug->control); - } - return 0; -} -EXPORT_SYMBOL_GPL(dbgp_reset_prep); - -#ifdef CONFIG_KGDB - -static char kgdbdbgp_buf[DBGP_MAX_PACKET]; -static int kgdbdbgp_buf_sz; -static int kgdbdbgp_buf_idx; -static int kgdbdbgp_loop_cnt = DBGP_LOOPS; - -static int kgdbdbgp_read_char(void) -{ - int ret; - - if (kgdbdbgp_buf_idx < kgdbdbgp_buf_sz) { - char ch = kgdbdbgp_buf[kgdbdbgp_buf_idx++]; - return ch; - } - - ret = dbgp_bulk_read(USB_DEBUG_DEVNUM, dbgp_endpoint_in, - &kgdbdbgp_buf, DBGP_MAX_PACKET, - kgdbdbgp_loop_cnt); - if (ret <= 0) - return NO_POLL_CHAR; - kgdbdbgp_buf_sz = ret; - kgdbdbgp_buf_idx = 1; - return kgdbdbgp_buf[0]; -} - -static void kgdbdbgp_write_char(u8 chr) -{ - early_dbgp_write(NULL, &chr, 1); -} - -static struct kgdb_io kgdbdbgp_io_ops = { - .name = "kgdbdbgp", - .read_char = kgdbdbgp_read_char, - .write_char = kgdbdbgp_write_char, -}; - -static int kgdbdbgp_wait_time; - -static int __init kgdbdbgp_parse_config(char *str) -{ - char *ptr; - - if (!ehci_debug) { - if (early_dbgp_init(str)) - return -1; - } - ptr = strchr(str, ','); - if (ptr) { - ptr++; - kgdbdbgp_wait_time = simple_strtoul(ptr, &ptr, 10); - } - kgdb_register_io_module(&kgdbdbgp_io_ops); - kgdbdbgp_io_ops.is_console = early_dbgp_console.index != -1; - - return 0; -} -early_param("kgdbdbgp", kgdbdbgp_parse_config); - -static int kgdbdbgp_reader_thread(void *ptr) -{ - int ret; - - while (readl(&ehci_debug->control) & DBGP_ENABLED) { - kgdbdbgp_loop_cnt = 1; - ret = kgdbdbgp_read_char(); - kgdbdbgp_loop_cnt = DBGP_LOOPS; - if (ret != NO_POLL_CHAR) { - if (ret == 0x3 || ret == '$') { - if (ret == '$') - kgdbdbgp_buf_idx--; - kgdb_breakpoint(); - } - continue; - } - schedule_timeout_interruptible(kgdbdbgp_wait_time * HZ); - } - return 0; -} - -static int __init kgdbdbgp_start_thread(void) -{ - if (dbgp_kgdb_mode && kgdbdbgp_wait_time) - kthread_run(kgdbdbgp_reader_thread, NULL, "%s", "dbgp"); - - return 0; -} -module_init(kgdbdbgp_start_thread); -#endif /* CONFIG_KGDB */ diff --git a/ANDROID_3.4.5/drivers/usb/gadget/Kconfig b/ANDROID_3.4.5/drivers/usb/gadget/Kconfig deleted file mode 100644 index 21a5f4cd..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/Kconfig +++ /dev/null @@ -1,1000 +0,0 @@ -# -# USB Gadget support on a system involves -# (a) a peripheral controller, and -# (b) the gadget driver using it. -# -# NOTE: Gadget support ** DOES NOT ** depend on host-side CONFIG_USB !! -# -# - Host systems (like PCs) need CONFIG_USB (with "A" jacks). -# - Peripherals (like PDAs) need CONFIG_USB_GADGET (with "B" jacks). -# - Some systems have both kinds of controllers. -# -# With help from a special transceiver and a "Mini-AB" jack, systems with -# both kinds of controller can also support "USB On-the-Go" (CONFIG_USB_OTG). -# - -menuconfig USB_GADGET - tristate "USB Gadget Support" - select NLS - help - USB is a master/slave protocol, organized with one master - host (such as a PC) controlling up to 127 peripheral devices. - The USB hardware is asymmetric, which makes it easier to set up: - you can't connect a "to-the-host" connector to a peripheral. - - Linux can run in the host, or in the peripheral. In both cases - you need a low level bus controller driver, and some software - talking to it. Peripheral controllers are often discrete silicon, - or are integrated with the CPU in a microcontroller. The more - familiar host side controllers have names like "EHCI", "OHCI", - or "UHCI", and are usually integrated into southbridges on PC - motherboards. - - Enable this configuration option if you want to run Linux inside - a USB peripheral device. Configure one hardware driver for your - peripheral/device side bus controller, and a "gadget driver" for - your peripheral protocol. (If you use modular gadget drivers, - you may configure more than one.) - - If in doubt, say "N" and don't enable these drivers; most people - don't have this kind of hardware (except maybe inside Linux PDAs). - - For more information, see and - the kernel DocBook documentation for this API. - -if USB_GADGET - -config USB_GADGET_DEBUG - boolean "Debugging messages (DEVELOPMENT)" - depends on DEBUG_KERNEL - help - Many controller and gadget drivers will print some debugging - messages if you use this option to ask for those messages. - - Avoid enabling these messages, even if you're actively - debugging such a driver. Many drivers will emit so many - messages that the driver timings are affected, which will - either create new failure modes or remove the one you're - trying to track down. Never enable these messages for a - production build. - -config USB_GADGET_DEBUG_FILES - boolean "Debugging information files (DEVELOPMENT)" - depends on PROC_FS - help - Some of the drivers in the "gadget" framework can expose - debugging information in files such as /proc/driver/udc - (for a peripheral controller). The information in these - files may help when you're troubleshooting or bringing up a - driver on a new board. Enable these files by choosing "Y" - here. If in doubt, or to conserve kernel memory, say "N". - -config USB_GADGET_DEBUG_FS - boolean "Debugging information files in debugfs (DEVELOPMENT)" - depends on DEBUG_FS - help - Some of the drivers in the "gadget" framework can expose - debugging information in files under /sys/kernel/debug/. - The information in these files may help when you're - troubleshooting or bringing up a driver on a new board. - Enable these files by choosing "Y" here. If in doubt, or - to conserve kernel memory, say "N". - -config USB_GADGET_VBUS_DRAW - int "Maximum VBUS Power usage (2-500 mA)" - range 2 500 - default 2 - help - Some devices need to draw power from USB when they are - configured, perhaps to operate circuitry or to recharge - batteries. This is in addition to any local power supply, - such as an AC adapter or batteries. - - Enter the maximum power your device draws through USB, in - milliAmperes. The permitted range of values is 2 - 500 mA; - 0 mA would be legal, but can make some hosts misbehave. - - This value will be used except for system-specific gadget - drivers that have more specific information. - -config USB_GADGET_STORAGE_NUM_BUFFERS - int "Number of storage pipeline buffers" - range 2 4 - default 2 - help - Usually 2 buffers are enough to establish a good buffering - pipeline. The number may be increased in order to compensate - for a bursty VFS behaviour. For instance there may be CPU wake up - latencies that makes the VFS to appear bursty in a system with - an CPU on-demand governor. Especially if DMA is doing IO to - offload the CPU. In this case the CPU will go into power - save often and spin up occasionally to move data within VFS. - If selecting USB_GADGET_DEBUG_FILES this value may be set by - a module parameter as well. - If unsure, say 2. - -# -# USB Peripheral Controller Support -# -# The order here is alphabetical, except that integrated controllers go -# before discrete ones so they will be the initial/default value: -# - integrated/SOC controllers first -# - licensed IP used in both SOC and discrete versions -# - discrete ones (including all PCI-only controllers) -# - debug/dummy gadget+hcd is last. -# -choice - prompt "USB Peripheral Controller" - help - A USB device uses a controller to talk to its host. - Systems should have only one such upstream link. - Many controller drivers are platform-specific; these - often need board-specific hooks. - -# -# Integrated controllers -# - -config USB_GADGET_WMT - tristate "GADGET WMT" - select USB_GADGET_SELECTED - select USB_GADGET_DUALSPEED -# default USB_GADGET - -config USB_WMT - tristate "USB WMT" - depends on USB_GADGET_WMT -# default USB_GADGET - -config USB_AT91 - tristate "Atmel AT91 USB Device Port" - depends on ARCH_AT91 - help - Many Atmel AT91 processors (such as the AT91RM2000) have a - full speed USB Device Port with support for five configurable - endpoints (plus endpoint zero). - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "at91_udc" and force all - gadget drivers to also be dynamically linked. - -config USB_ATMEL_USBA - tristate "Atmel USBA" - select USB_GADGET_DUALSPEED - depends on AVR32 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 - help - USBA is the integrated high-speed USB Device controller on - the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel. - -config USB_FSL_USB2 - tristate "Freescale Highspeed USB DR Peripheral Controller" - depends on FSL_SOC || ARCH_MXC - select USB_GADGET_DUALSPEED - select USB_FSL_MPH_DR_OF if OF - help - Some of Freescale PowerPC processors have a High Speed - Dual-Role(DR) USB controller, which supports device mode. - - The number of programmable endpoints is different through - SOC revisions. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "fsl_usb2_udc" and force - all gadget drivers to also be dynamically linked. - -config USB_FUSB300 - tristate "Faraday FUSB300 USB Peripheral Controller" - depends on !PHYS_ADDR_T_64BIT - select USB_GADGET_DUALSPEED - help - Faraday usb device controller FUSB300 driver - -config USB_OMAP - tristate "OMAP USB Device Controller" - depends on ARCH_OMAP - select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG - select USB_OTG_UTILS if ARCH_OMAP - help - Many Texas Instruments OMAP processors have flexible full - speed USB device controllers, with support for up to 30 - endpoints (plus endpoint zero). This driver supports the - controller in the OMAP 1611, and should work with controllers - in other OMAP processors too, given minor tweaks. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "omap_udc" and force all - gadget drivers to also be dynamically linked. - -config USB_PXA25X - tristate "PXA 25x or IXP 4xx" - depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX - select USB_OTG_UTILS - help - Intel's PXA 25x series XScale ARM-5TE processors include - an integrated full speed USB 1.1 device controller. The - controller in the IXP 4xx series is register-compatible. - - It has fifteen fixed-function endpoints, as well as endpoint - zero (for control transfers). - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "pxa25x_udc" and force all - gadget drivers to also be dynamically linked. - -# if there's only one gadget driver, using only two bulk endpoints, -# don't waste memory for the other endpoints -config USB_PXA25X_SMALL - depends on USB_PXA25X - bool - default n if USB_ETH_RNDIS - default y if USB_ZERO - default y if USB_ETH - default y if USB_G_SERIAL - -config USB_R8A66597 - tristate "Renesas R8A66597 USB Peripheral Controller" - select USB_GADGET_DUALSPEED - help - R8A66597 is a discrete USB host and peripheral controller chip that - supports both full and high speed USB 2.0 data transfers. - It has nine configurable endpoints, and endpoint zero. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "r8a66597_udc" and force all - gadget drivers to also be dynamically linked. - -config USB_RENESAS_USBHS_UDC - tristate 'Renesas USBHS controller' - depends on USB_RENESAS_USBHS - select USB_GADGET_DUALSPEED - help - Renesas USBHS is a discrete USB host and peripheral controller chip - that supports both full and high speed USB 2.0 data transfers. - It has nine or more configurable endpoints, and endpoint zero. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "renesas_usbhs" and force all - gadget drivers to also be dynamically linked. - -config USB_PXA27X - tristate "PXA 27x" - depends on ARCH_PXA && (PXA27x || PXA3xx) - select USB_OTG_UTILS - help - Intel's PXA 27x series XScale ARM v5TE processors include - an integrated full speed USB 1.1 device controller. - - It has up to 23 endpoints, as well as endpoint zero (for - control transfers). - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "pxa27x_udc" and force all - gadget drivers to also be dynamically linked. - -config USB_S3C_HSOTG - tristate "S3C HS/OtG USB Device controller" - depends on S3C_DEV_USB_HSOTG - select USB_GADGET_DUALSPEED - help - The Samsung S3C64XX USB2.0 high-speed gadget controller - integrated into the S3C64XX series SoC. - -config USB_IMX - tristate "Freescale i.MX1 USB Peripheral Controller" - depends on ARCH_MXC - help - Freescale's i.MX1 includes an integrated full speed - USB 1.1 device controller. - - It has Six fixed-function endpoints, as well as endpoint - zero (for control transfers). - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "imx_udc" and force all - gadget drivers to also be dynamically linked. - -config USB_S3C2410 - tristate "S3C2410 USB Device Controller" - depends on ARCH_S3C24XX - help - Samsung's S3C2410 is an ARM-4 processor with an integrated - full speed USB 1.1 device controller. It has 4 configurable - endpoints, as well as endpoint zero (for control transfers). - - This driver has been tested on the S3C2410, S3C2412, and - S3C2440 processors. - -config USB_S3C2410_DEBUG - boolean "S3C2410 udc debug messages" - depends on USB_S3C2410 - -config USB_S3C_HSUDC - tristate "S3C2416, S3C2443 and S3C2450 USB Device Controller" - depends on ARCH_S3C24XX - select USB_GADGET_DUALSPEED - help - Samsung's S3C2416, S3C2443 and S3C2450 is an ARM9 based SoC - integrated with dual speed USB 2.0 device controller. It has - 8 endpoints, as well as endpoint zero. - - This driver has been tested on S3C2416 and S3C2450 processors. - -config USB_MV_UDC - tristate "Marvell USB2.0 Device Controller" - select USB_GADGET_DUALSPEED - help - Marvell Socs (including PXA and MMP series) include a high speed - USB2.0 OTG controller, which can be configured as high speed or - full speed USB peripheral. - -# -# Controllers available in both integrated and discrete versions -# - -# musb builds in ../musb along with host support -config USB_GADGET_MUSB_HDRC - tristate "Inventra HDRC USB Peripheral (TI, ADI, ...)" - depends on USB_MUSB_HDRC - select USB_GADGET_DUALSPEED - help - This OTG-capable silicon IP is used in dual designs including - the TI DaVinci, OMAP 243x, OMAP 343x, TUSB 6010, and ADI Blackfin - -config USB_M66592 - tristate "Renesas M66592 USB Peripheral Controller" - select USB_GADGET_DUALSPEED - help - M66592 is a discrete USB peripheral controller chip that - supports both full and high speed USB 2.0 data transfers. - It has seven configurable endpoints, and endpoint zero. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "m66592_udc" and force all - gadget drivers to also be dynamically linked. - -# -# Controllers available only in discrete form (and all PCI controllers) -# - -config USB_AMD5536UDC - tristate "AMD5536 UDC" - depends on PCI - select USB_GADGET_DUALSPEED - help - The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge. - It is a USB Highspeed DMA capable USB device controller. Beside ep0 - it provides 4 IN and 4 OUT endpoints (bulk or interrupt type). - The UDC port supports OTG operation, and may be used as a host port - if it's not being used to implement peripheral or OTG roles. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "amd5536udc" and force all - gadget drivers to also be dynamically linked. - -config USB_FSL_QE - tristate "Freescale QE/CPM USB Device Controller" - depends on FSL_SOC && (QUICC_ENGINE || CPM) - help - Some of Freescale PowerPC processors have a Full Speed - QE/CPM2 USB controller, which support device mode with 4 - programmable endpoints. This driver supports the - controller in the MPC8360 and MPC8272, and should work with - controllers having QE or CPM2, given minor tweaks. - - Set CONFIG_USB_GADGET to "m" to build this driver as a - dynamically linked module called "fsl_qe_udc". - -config USB_CI13XXX_PCI - tristate "MIPS USB CI13xxx PCI UDC" - depends on PCI - select USB_GADGET_DUALSPEED - help - MIPS USB IP core family device controller - Currently it only supports IP part number CI13412 - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "ci13xxx_udc" and force all - gadget drivers to also be dynamically linked. - -config USB_NET2272 - tristate "PLX NET2272" - select USB_GADGET_DUALSPEED - help - PLX NET2272 is a USB peripheral controller which supports - both full and high speed USB 2.0 data transfers. - - It has three configurable endpoints, as well as endpoint zero - (for control transfer). - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "net2272" and force all - gadget drivers to also be dynamically linked. - -config USB_NET2272_DMA - boolean "Support external DMA controller" - depends on USB_NET2272 - help - The NET2272 part can optionally support an external DMA - controller, but your board has to have support in the - driver itself. - - If unsure, say "N" here. The driver works fine in PIO mode. - -config USB_NET2280 - tristate "NetChip 228x" - depends on PCI - select USB_GADGET_DUALSPEED - help - NetChip 2280 / 2282 is a PCI based USB peripheral controller which - supports both full and high speed USB 2.0 data transfers. - - It has six configurable endpoints, as well as endpoint zero - (for control transfers) and several endpoints with dedicated - functions. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "net2280" and force all - gadget drivers to also be dynamically linked. - -config USB_GOKU - tristate "Toshiba TC86C001 'Goku-S'" - depends on PCI - help - The Toshiba TC86C001 is a PCI device which includes controllers - for full speed USB devices, IDE, I2C, SIO, plus a USB host (OHCI). - - The device controller has three configurable (bulk or interrupt) - endpoints, plus endpoint zero (for control transfers). - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "goku_udc" and to force all - gadget drivers to also be dynamically linked. - -config USB_LANGWELL - tristate "Intel Langwell USB Device Controller" - depends on PCI - depends on !PHYS_ADDR_T_64BIT - 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_EG20T - tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC" - depends on PCI - select USB_GADGET_DUALSPEED - help - This is a USB device driver for EG20T PCH. - EG20T PCH is the platform controller hub that is used in Intel's - general embedded platform. EG20T PCH has USB device interface. - Using this interface, it is able to access system devices connected - to USB device. - This driver enables USB device function. - USB device is a USB peripheral controller which - supports both full and high speed USB 2.0 data transfers. - This driver supports both control transfer and bulk transfer modes. - This driver dose not support interrupt transfer or isochronous - transfer modes. - - This driver also can be used for LAPIS Semiconductor's ML7213 which is - for IVI(In-Vehicle Infotainment) use. - ML7831 is for general purpose use. - ML7213/ML7831 is companion chip for Intel Atom E6xx series. - ML7213/ML7831 is completely compatible for Intel EG20T PCH. - -config USB_CI13XXX_MSM - tristate "MIPS USB CI13xxx for MSM" - depends on ARCH_MSM - select USB_GADGET_DUALSPEED - select USB_MSM_OTG - help - MSM SoC has chipidea USB controller. This driver uses - ci13xxx_udc core. - This driver depends on OTG driver for PHY initialization, - clock management, powering up VBUS, and power management. - This driver is not supported on boards like trout which - has an external PHY. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "ci13xxx_msm" and force all - gadget drivers to also be dynamically linked. - -# -# LAST -- dummy/emulated controller -# - -config USB_DUMMY_HCD - tristate "Dummy HCD (DEVELOPMENT)" - depends on USB=y || (USB=m && USB_GADGET=m) - select USB_GADGET_DUALSPEED - select USB_GADGET_SUPERSPEED - help - This host controller driver emulates USB, looping all data transfer - requests back to a USB "gadget driver" in the same host. The host - side is the master; the gadget side is the slave. Gadget drivers - can be high, full, or low speed; and they have access to endpoints - like those from NET2280, PXA2xx, or SA1100 hardware. - - This may help in some stages of creating a driver to embed in a - Linux device, since it lets you debug several parts of the gadget - driver without its hardware or drivers being involved. - - Since such a gadget side driver needs to interoperate with a host - side Linux-USB device driver, this may help to debug both sides - of a USB protocol stack. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "dummy_hcd" and force all - gadget drivers to also be dynamically linked. - -# NOTE: Please keep dummy_hcd LAST so that "real hardware" appears -# first and will be selected by default. - -endchoice - -# Selected by UDC drivers that support high-speed operation. -config USB_GADGET_DUALSPEED - bool - -# Selected by UDC drivers that support super-speed opperation -config USB_GADGET_SUPERSPEED - bool - depends on USB_GADGET_DUALSPEED - -# -# USB Gadget Drivers -# -choice - boolean "USB Gadget Drivers" - default USB_G_ANDROID - help - A Linux "Gadget Driver" talks to the USB Peripheral Controller - driver through the abstract "gadget" API. Some other operating - systems call these "client" drivers, of which "class drivers" - are a subset (implementing a USB device class specification). - A gadget driver implements one or more USB functions using - the peripheral hardware. - - Gadget drivers are hardware-neutral, or "platform independent", - except that they sometimes must understand quirks or limitations - of the particular controllers they work with. For example, when - a controller doesn't support alternate configurations or provide - enough of the right types of endpoints, the gadget driver might - not be able work with that controller, or might need to implement - a less common variant of a device class protocol. - -# this first set of drivers all depend on bulk-capable hardware. - -config USB_ZERO - tristate "Gadget Zero (DEVELOPMENT)" - help - Gadget Zero is a two-configuration device. It either sinks and - sources bulk data; or it loops back a configurable number of - transfers. It also implements control requests, for "chapter 9" - conformance. The driver needs only two bulk-capable endpoints, so - it can work on top of most device-side usb controllers. It's - useful for testing, and is also a working example showing how - USB "gadget drivers" can be written. - - Make this be the first driver you try using on top of any new - USB peripheral controller driver. Then you can use host-side - test software, like the "usbtest" driver, to put your hardware - and its driver through a basic set of functional tests. - - Gadget Zero also works with the host-side "usb-skeleton" driver, - and with many kinds of host-side test software. You may need - to tweak product and vendor IDs before host software knows about - this device, and arrange to select an appropriate configuration. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_zero". - -config USB_ZERO_HNPTEST - boolean "HNP Test Device" - depends on USB_ZERO && USB_OTG - help - You can configure this device to enumerate using the device - identifiers of the USB-OTG test device. That means that when - this gadget connects to another OTG device, with this one using - 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 - select SND_PCM - help - This Gadget Audio driver is compatible with USB Audio Class - specification 2.0. It implements 1 AudioControl interface, - 1 AudioStreaming Interface each for USB-OUT and USB-IN. - Number of channels, sample rate and sample size can be - specified as module parameters. - This driver doesn't expect any real Audio codec to be present - on the device - the audio streams are simply sinked to and - sourced from a virtual ALSA sound card created. The user-space - application may choose to do whatever it wants with the data - received from the USB Host and choose to provide whatever it - wants as audio data to the USB Host. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_audio". - -config GADGET_UAC1 - bool "UAC 1.0 (Legacy)" - depends on USB_AUDIO - help - If you instead want older UAC Spec-1.0 driver that also has audio - paths hardwired to the Audio codec chip on-board and doesn't work - without one. - -config USB_ETH - tristate "Ethernet Gadget (with CDC Ethernet support)" - depends on NET - select CRC32 - help - This driver implements Ethernet style communication, in one of - several ways: - - - The "Communication Device Class" (CDC) Ethernet Control Model. - That protocol is often avoided with pure Ethernet adapters, in - favor of simpler vendor-specific hardware, but is widely - supported by firmware for smart network devices. - - - On hardware can't implement that protocol, a simple CDC subset - is used, placing fewer demands on USB. - - - CDC Ethernet Emulation Model (EEM) is a newer standard that has - a simpler interface that can be used by more USB hardware. - - RNDIS support is an additional option, more demanding than than - subset. - - Within the USB device, this gadget driver exposes a network device - "usbX", where X depends on what other networking devices you have. - Treat it like a two-node Ethernet link: host, and gadget. - - The Linux-USB host-side "usbnet" driver interoperates with this - driver, so that deep I/O queues can be supported. On 2.4 kernels, - use "CDCEther" instead, if you're using the CDC option. That CDC - mode should also interoperate with standard CDC Ethernet class - drivers on other host operating systems. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_ether". - -config USB_ETH_RNDIS - bool "RNDIS support" - depends on USB_ETH - default y - help - Microsoft Windows XP bundles the "Remote NDIS" (RNDIS) protocol, - and Microsoft provides redistributable binary RNDIS drivers for - older versions of Windows. - - If you say "y" here, the Ethernet gadget driver will try to provide - a second device configuration, supporting RNDIS to talk to such - Microsoft USB hosts. - - To make MS-Windows work with this, use Documentation/usb/linux.inf - as the "driver info file". For versions of MS-Windows older than - XP, you'll need to download drivers from Microsoft's website; a URL - is given in comments found in that info file. - -config USB_ETH_EEM - bool "Ethernet Emulation Model (EEM) support" - depends on USB_ETH - default n - help - CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM - and therefore can be supported by more hardware. Technically ECM and - EEM are designed for different applications. The ECM model extends - the network interface to the target (e.g. a USB cable modem), and the - EEM model is for mobile devices to communicate with hosts using - ethernet over USB. For Linux gadgets, however, the interface with - the host is the same (a usbX device), so the differences are minimal. - - If you say "y" here, the Ethernet gadget driver will use the EEM - protocol rather than ECM. If unsure, say "n". - -config USB_G_NCM - tristate "Network Control Model (NCM) support" - depends on NET - select CRC32 - help - This driver implements USB CDC NCM subclass standard. NCM is - an advanced protocol for Ethernet encapsulation, allows grouping - of several ethernet frames into one USB transfer and different - alignment possibilities. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_ncm". - -config USB_GADGETFS - tristate "Gadget Filesystem (EXPERIMENTAL)" - depends on EXPERIMENTAL - help - This driver provides a filesystem based API that lets user mode - programs implement a single-configuration USB device, including - endpoint I/O and control requests that don't relate to enumeration. - All endpoints, transfer speeds, and transfer types supported by - the hardware are available, through read() and write() calls. - - Currently, this option is still labelled as EXPERIMENTAL because - of existing race conditions in the underlying in-kernel AIO core. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "gadgetfs". - -config USB_FUNCTIONFS - tristate "Function Filesystem (EXPERIMENTAL)" - depends on EXPERIMENTAL - select USB_FUNCTIONFS_GENERIC if !(USB_FUNCTIONFS_ETH || USB_FUNCTIONFS_RNDIS) - help - The Function Filesystem (FunctionFS) lets one create USB - composite functions in user space in the same way GadgetFS - lets one create USB gadgets in user space. This allows creation - of composite gadgets such that some of the functions are - implemented in kernel space (for instance Ethernet, serial or - mass storage) and other are implemented in user space. - - If you say "y" or "m" here you will be able what kind of - configurations the gadget will provide. - - Say "y" to link the driver statically, or "m" to build - a dynamically linked module called "g_ffs". - -config USB_FUNCTIONFS_ETH - bool "Include configuration with CDC ECM (Ethernet)" - depends on USB_FUNCTIONFS && NET - help - Include a configuration with CDC ECM function (Ethernet) and the - Function Filesystem. - -config USB_FUNCTIONFS_RNDIS - bool "Include configuration with RNDIS (Ethernet)" - depends on USB_FUNCTIONFS && NET - help - Include a configuration with RNDIS function (Ethernet) and the Filesystem. - -config USB_FUNCTIONFS_GENERIC - bool "Include 'pure' configuration" - depends on USB_FUNCTIONFS - help - Include a configuration with the Function Filesystem alone with - no Ethernet interface. - -config USB_FILE_STORAGE - tristate "File-backed Storage Gadget (DEPRECATED)" - depends on BLOCK - help - The File-backed Storage Gadget acts as a USB Mass Storage - disk drive. As its storage repository it can use a regular - file or a block device (in much the same way as the "loop" - device driver), specified as a module parameter. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_file_storage". - - NOTE: This driver is deprecated. Its replacement is the - Mass Storage Gadget. - -config USB_FILE_STORAGE_TEST - bool "File-backed Storage Gadget testing version" - depends on USB_FILE_STORAGE - default n - help - Say "y" to generate the larger testing version of the - File-backed Storage Gadget, useful for probing the - behavior of USB Mass Storage hosts. Not needed for - normal operation. - -config USB_MASS_STORAGE - tristate "Mass Storage Gadget" - depends on BLOCK - help - The Mass Storage Gadget acts as a USB Mass Storage disk drive. - As its storage repository it can use a regular file or a block - device (in much the same way as the "loop" device driver), - specified as a module parameter or sysfs option. - - This driver is an updated replacement for the deprecated - File-backed Storage Gadget (g_file_storage). - - Say "y" to link the driver statically, or "m" to build - a dynamically linked module called "g_mass_storage". - -config USB_G_SERIAL - tristate "Serial Gadget (with CDC ACM and CDC OBEX support)" - help - The Serial Gadget talks to the Linux-USB generic serial driver. - This driver supports a CDC-ACM module option, which can be used - to interoperate with MS-Windows hosts or with the Linux-USB - "cdc-acm" driver. - - This driver also supports a CDC-OBEX option. You will need a - user space OBEX server talking to /dev/ttyGS*, since the kernel - itself doesn't implement the OBEX protocol. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_serial". - - For more information, see Documentation/usb/gadget_serial.txt - which includes instructions and a "driver info file" needed to - make MS-Windows work with CDC ACM. - -config USB_MIDI_GADGET - tristate "MIDI Gadget (EXPERIMENTAL)" - depends on SND && EXPERIMENTAL - select SND_RAWMIDI - help - The MIDI Gadget acts as a USB Audio device, with one MIDI - input and one MIDI output. These MIDI jacks appear as - a sound "card" in the ALSA sound system. Other MIDI - connections can then be made on the gadget system, using - ALSA's aconnect utility etc. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_midi". - -config USB_G_PRINTER - tristate "Printer Gadget" - help - The Printer Gadget channels data between the USB host and a - userspace program driving the print engine. The user space - program reads and writes the device file /dev/g_printer to - receive or send printer data. It can use ioctl calls to - the device file to get or set printer status. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_printer". - - For more information, see Documentation/usb/gadget_printer.txt - which includes sample code for accessing the device file. - -config USB_G_ANDROID - boolean "Android Composite Gadget" - help - The Android Composite Gadget supports multiple USB - functions: adb, acm, mass storage, mtp, accessory - and rndis. - Each function can be configured and enabled/disabled - dynamically from userspace through a sysfs interface. - -config USB_CDC_COMPOSITE - tristate "CDC Composite Device (Ethernet and ACM)" - depends on NET - help - This driver provides two functions in one configuration: - a CDC Ethernet (ECM) link, and a CDC ACM (serial port) link. - - This driver requires four bulk and two interrupt endpoints, - plus the ability to handle altsettings. Not all peripheral - controllers are that capable. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module. - -config USB_G_NOKIA - tristate "Nokia composite gadget" - depends on PHONET - help - The Nokia composite gadget provides support for acm, obex - and phonet in only one composite gadget driver. - - It's only really useful for N900 hardware. If you're building - a kernel for N900, say Y or M here. If unsure, say N. - -config USB_G_ACM_MS - tristate "CDC Composite Device (ACM and mass storage)" - depends on BLOCK - help - This driver provides two functions in one configuration: - a mass storage, and a CDC ACM (serial port) link. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_acm_ms". - -config USB_G_MULTI - tristate "Multifunction Composite Gadget (EXPERIMENTAL)" - depends on BLOCK && NET - select USB_G_MULTI_CDC if !USB_G_MULTI_RNDIS - help - The Multifunction Composite Gadget provides Ethernet (RNDIS - and/or CDC Ethernet), mass storage and ACM serial link - interfaces. - - You will be asked to choose which of the two configurations is - to be available in the gadget. At least one configuration must - be chosen to make the gadget usable. Selecting more than one - configuration will prevent Windows from automatically detecting - the gadget as a composite gadget, so an INF file will be needed to - use the gadget. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_multi". - -config USB_G_MULTI_RNDIS - bool "RNDIS + CDC Serial + Storage configuration" - depends on USB_G_MULTI - default y - help - This option enables a configuration with RNDIS, CDC Serial and - Mass Storage functions available in the Multifunction Composite - Gadget. This is the configuration dedicated for Windows since RNDIS - is Microsoft's protocol. - - If unsure, say "y". - -config USB_G_MULTI_CDC - bool "CDC Ethernet + CDC Serial + Storage configuration" - depends on USB_G_MULTI - default n - help - This option enables a configuration with CDC Ethernet (ECM), CDC - Serial and Mass Storage functions available in the Multifunction - Composite Gadget. - - If unsure, say "y". - -config USB_G_HID - tristate "HID Gadget" - help - The HID gadget driver provides generic emulation of USB - Human Interface Devices (HID). - - For more information, see Documentation/usb/gadget_hid.txt which - includes sample code for accessing the device files. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_hid". - -config USB_G_DBGP - tristate "EHCI Debug Device Gadget" - help - This gadget emulates an EHCI Debug device. This is useful when you want - to interact with an EHCI Debug Port. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_dbgp". - -if USB_G_DBGP -choice - prompt "EHCI Debug Device mode" - default USB_G_DBGP_SERIAL - -config USB_G_DBGP_PRINTK - depends on USB_G_DBGP - bool "printk" - help - Directly printk() received data. No interaction. - -config USB_G_DBGP_SERIAL - depends on USB_G_DBGP - bool "serial" - help - Userland can interact using /dev/ttyGSxxx. -endchoice -endif - -# put drivers that need isochronous transfer support (for audio -# or video class gadget drivers), or specific hardware, here. -config USB_G_WEBCAM - tristate "USB Webcam Gadget" - depends on VIDEO_DEV - help - The Webcam Gadget acts as a composite USB Audio and Video Class - device. It provides a userspace API to process UVC control requests - and stream video data to the host. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_webcam". - -endchoice - -endif # USB_GADGET diff --git a/ANDROID_3.4.5/drivers/usb/gadget/Makefile b/ANDROID_3.4.5/drivers/usb/gadget/Makefile deleted file mode 100644 index 8df55f44..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/Makefile +++ /dev/null @@ -1,78 +0,0 @@ -# -# USB peripheral controller drivers -# -ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG - -obj-$(CONFIG_USB_GADGET) += udc-core.o -obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o -obj-$(CONFIG_USB_NET2272) += net2272.o -obj-$(CONFIG_USB_NET2280) += net2280.o -obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o -obj-$(CONFIG_USB_PXA25X) += pxa25x_udc.o -obj-$(CONFIG_USB_PXA27X) += pxa27x_udc.o -obj-$(CONFIG_USB_IMX) += imx_udc.o -obj-$(CONFIG_USB_GOKU) += goku_udc.o -obj-$(CONFIG_USB_OMAP) += omap_udc.o -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-y := fsl_udc_core.o -fsl_usb2_udc-$(CONFIG_ARCH_MXC) += fsl_mxc_udc.o -obj-$(CONFIG_USB_M66592) += m66592-udc.o -obj-$(CONFIG_USB_R8A66597) += r8a66597-udc.o -obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o -obj-$(CONFIG_USB_CI13XXX_PCI) += ci13xxx_pci.o -obj-$(CONFIG_USB_S3C_HSOTG) += s3c-hsotg.o -obj-$(CONFIG_USB_S3C_HSUDC) += s3c-hsudc.o -obj-$(CONFIG_USB_LANGWELL) += langwell_udc.o -obj-$(CONFIG_USB_EG20T) += pch_udc.o -obj-$(CONFIG_USB_MV_UDC) += mv_udc.o -mv_udc-y := mv_udc_core.o -obj-$(CONFIG_USB_CI13XXX_MSM) += ci13xxx_msm.o -obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o -obj-$(CONFIG_USB_WMT) += udc_wmt.o - -# -# USB gadget drivers -# -g_zero-y := zero.o -g_audio-y := audio.o -g_ether-y := ether.o -g_serial-y := serial.o -g_midi-y := gmidi.o -gadgetfs-y := inode.o -g_file_storage-y := file_storage.o -g_mass_storage-y := mass_storage.o -g_printer-y := printer.o -g_cdc-y := cdc2.o -g_multi-y := multi.o -g_hid-y := hid.o -g_dbgp-y := dbgp.o -g_nokia-y := nokia.o -g_webcam-y := webcam.o -g_ncm-y := ncm.o -g_acm_ms-y := acm_ms.o -g_android-y := android.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_FUNCTIONFS) += g_ffs.o -obj-$(CONFIG_USB_FILE_STORAGE) += g_file_storage.o -obj-$(CONFIG_USB_MASS_STORAGE) += g_mass_storage.o -obj-$(CONFIG_USB_G_SERIAL) += g_serial.o -obj-$(CONFIG_USB_G_PRINTER) += g_printer.o -obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o -obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o -obj-$(CONFIG_USB_G_HID) += g_hid.o -obj-$(CONFIG_USB_G_DBGP) += g_dbgp.o -obj-$(CONFIG_USB_G_MULTI) += g_multi.o -obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o -obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o -obj-$(CONFIG_USB_G_NCM) += g_ncm.o -obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o -obj-$(CONFIG_USB_G_ANDROID) += g_android.o -obj-y += rawbulk.o -obj-y += rawbulk_transfer.o diff --git a/ANDROID_3.4.5/drivers/usb/gadget/acm_ms.c b/ANDROID_3.4.5/drivers/usb/gadget/acm_ms.c deleted file mode 100644 index fdb7aec3..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/acm_ms.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * acm_ms.c -- Composite driver, with ACM and mass storage support - * - * Copyright (C) 2008 David Brownell - * Copyright (C) 2008 Nokia Corporation - * Author: David Brownell - * Modified: Klaus Schwarzkopf - * - * Heavily based on multi.c and cdc2.c - * - * 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 -#include - -#include "u_serial.h" - -#define DRIVER_DESC "Composite Gadget (ACM + MS)" -#define DRIVER_VERSION "2011/10/10" - -/*-------------------------------------------------------------------------*/ - -/* - * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! - * Instead: allocate your own, using normal USB-IF procedures. - */ -#define ACM_MS_VENDOR_NUM 0x1d6b /* Linux Foundation */ -#define ACM_MS_PRODUCT_NUM 0x0106 /* Composite Gadget: ACM + MS*/ - -/*-------------------------------------------------------------------------*/ - -/* - * 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_serial.c" -#include "f_acm.c" -#include "f_mass_storage.c" - -/*-------------------------------------------------------------------------*/ - -static struct usb_device_descriptor device_desc = { - .bLength = sizeof device_desc, - .bDescriptorType = USB_DT_DEVICE, - - .bcdUSB = cpu_to_le16(0x0200), - - .bDeviceClass = USB_CLASS_MISC /* 0xEF */, - .bDeviceSubClass = 2, - .bDeviceProtocol = 1, - - /* .bMaxPacketSize0 = f(hardware) */ - - /* Vendor and product id can be overridden by module parameters. */ - .idVendor = cpu_to_le16(ACM_MS_VENDOR_NUM), - .idProduct = cpu_to_le16(ACM_MS_PRODUCT_NUM), - /* .bcdDevice = f(hardware) */ - /* .iManufacturer = DYNAMIC */ - /* .iProduct = DYNAMIC */ - /* NO SERIAL NUMBER */ - /*.bNumConfigurations = DYNAMIC*/ -}; - -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, -}; - - -/* 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 *dev_strings[] = { - &stringtab_dev, - NULL, -}; - -/****************************** Configurations ******************************/ - -static struct fsg_module_parameters fsg_mod_data = { .stall = 1 }; -FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data); - -static struct fsg_common fsg_common; - -/*-------------------------------------------------------------------------*/ - -/* - * We _always_ have both ACM and mass storage functions. - */ -static int __init acm_ms_do_config(struct usb_configuration *c) -{ - int status; - - if (gadget_is_otg(c->cdev->gadget)) { - c->descriptors = otg_desc; - c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; - } - - - status = acm_bind_config(c, 0); - if (status < 0) - return status; - - status = fsg_bind_config(c->cdev, c, &fsg_common); - if (status < 0) - return status; - - return 0; -} - -static struct usb_configuration acm_ms_config_driver = { - .label = DRIVER_DESC, - .bConfigurationValue = 1, - /* .iConfiguration = DYNAMIC */ - .bmAttributes = USB_CONFIG_ATT_SELFPOWER, -}; - -/*-------------------------------------------------------------------------*/ - -static int __init acm_ms_bind(struct usb_composite_dev *cdev) -{ - int gcnum; - struct usb_gadget *gadget = cdev->gadget; - int status; - void *retp; - - /* set up serial link layer */ - status = gserial_setup(cdev->gadget, 1); - if (status < 0) - return status; - - /* set up mass storage function */ - retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data); - if (IS_ERR(retp)) { - status = PTR_ERR(retp); - goto fail0; - } - - /* set bcdDevice */ - gcnum = usb_gadget_controller_number(gadget); - if (gcnum >= 0) { - device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum); - } else { - WARNING(cdev, "controller '%s' not recognized; trying %s\n", - gadget->name, - acm_ms_config_driver.label); - device_desc.bcdDevice = - cpu_to_le16(0x0300 | 0x0099); - } - - /* - * Allocate string descriptor numbers ... note that string - * contents can be overridden by the composite_dev glue. - */ - - /* device descriptor strings: manufacturer, product */ - snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", - init_utsname()->sysname, init_utsname()->release, - gadget->name); - status = usb_string_id(cdev); - if (status < 0) - goto fail1; - strings_dev[STRING_MANUFACTURER_IDX].id = status; - device_desc.iManufacturer = status; - - status = usb_string_id(cdev); - if (status < 0) - goto fail1; - strings_dev[STRING_PRODUCT_IDX].id = status; - device_desc.iProduct = status; - - /* register our configuration */ - status = usb_add_config(cdev, &acm_ms_config_driver, acm_ms_do_config); - if (status < 0) - goto fail1; - - dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n", - DRIVER_DESC); - fsg_common_put(&fsg_common); - return 0; - - /* error recovery */ -fail1: - fsg_common_put(&fsg_common); -fail0: - gserial_cleanup(); - return status; -} - -static int __exit acm_ms_unbind(struct usb_composite_dev *cdev) -{ - gserial_cleanup(); - - return 0; -} - -static struct usb_composite_driver acm_ms_driver = { - .name = "g_acm_ms", - .dev = &device_desc, - .strings = dev_strings, - .unbind = __exit_p(acm_ms_unbind), -}; - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Klaus Schwarzkopf "); -MODULE_LICENSE("GPL v2"); - -static int __init init(void) -{ - return usb_composite_probe(&acm_ms_driver, acm_ms_bind); -} -module_init(init); - -static void __exit cleanup(void) -{ - usb_composite_unregister(&acm_ms_driver); -} -module_exit(cleanup); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/amd5536udc.c b/ANDROID_3.4.5/drivers/usb/gadget/amd5536udc.c deleted file mode 100644 index 77779271..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/amd5536udc.c +++ /dev/null @@ -1,3422 +0,0 @@ -/* - * amd5536.c -- AMD 5536 UDC high/full speed USB device controller - * - * Copyright (C) 2005-2007 AMD (http://www.amd.com) - * Author: Thomas Dahlmann - * - * 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. - */ - -/* - * The AMD5536 UDC is part of the x86 southbridge AMD Geode CS5536. - * It is a USB Highspeed DMA capable USB device controller. Beside ep0 it - * provides 4 IN and 4 OUT endpoints (bulk or interrupt type). - * - * Make sure that UDC is assigned to port 4 by BIOS settings (port can also - * be used as host port) and UOC bits PAD_EN and APU are set (should be done - * by BIOS init). - * - * UDC DMA requires 32-bit aligned buffers so DMA with gadget ether does not - * work without updating NET_IP_ALIGN. Or PIO mode (module param "use_dma=0") - * can be used with gadget ether. - */ - -/* debug control */ -/* #define UDC_VERBOSE */ - -/* Driver strings */ -#define UDC_MOD_DESCRIPTION "AMD 5536 UDC - USB Device Controller" -#define UDC_DRIVER_VERSION_STRING "01.00.0206" - -/* system */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* gadget stack */ -#include -#include - -/* udc specific */ -#include "amd5536udc.h" - - -static void udc_tasklet_disconnect(unsigned long); -static void empty_req_queue(struct udc_ep *); -static int udc_probe(struct udc *dev); -static void udc_basic_init(struct udc *dev); -static void udc_setup_endpoints(struct udc *dev); -static void udc_soft_reset(struct udc *dev); -static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep); -static void udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq); -static int udc_free_dma_chain(struct udc *dev, struct udc_request *req); -static int udc_create_dma_chain(struct udc_ep *ep, struct udc_request *req, - unsigned long buf_len, gfp_t gfp_flags); -static int udc_remote_wakeup(struct udc *dev); -static int udc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id); -static void udc_pci_remove(struct pci_dev *pdev); - -/* description */ -static const char mod_desc[] = UDC_MOD_DESCRIPTION; -static const char name[] = "amd5536udc"; - -/* structure to hold endpoint function pointers */ -static const struct usb_ep_ops udc_ep_ops; - -/* received setup data */ -static union udc_setup_data setup_data; - -/* pointer to device object */ -static struct udc *udc; - -/* irq spin lock for soft reset */ -static DEFINE_SPINLOCK(udc_irq_spinlock); -/* stall spin lock */ -static DEFINE_SPINLOCK(udc_stall_spinlock); - -/* -* slave mode: pending bytes in rx fifo after nyet, -* used if EPIN irq came but no req was available -*/ -static unsigned int udc_rxfifo_pending; - -/* count soft resets after suspend to avoid loop */ -static int soft_reset_occured; -static int soft_reset_after_usbreset_occured; - -/* timer */ -static struct timer_list udc_timer; -static int stop_timer; - -/* set_rde -- Is used to control enabling of RX DMA. Problem is - * that UDC has only one bit (RDE) to enable/disable RX DMA for - * all OUT endpoints. So we have to handle race conditions like - * when OUT data reaches the fifo but no request was queued yet. - * This cannot be solved by letting the RX DMA disabled until a - * request gets queued because there may be other OUT packets - * in the FIFO (important for not blocking control traffic). - * The value of set_rde controls the correspondig timer. - * - * set_rde -1 == not used, means it is alloed to be set to 0 or 1 - * set_rde 0 == do not touch RDE, do no start the RDE timer - * set_rde 1 == timer function will look whether FIFO has data - * set_rde 2 == set by timer function to enable RX DMA on next call - */ -static int set_rde = -1; - -static DECLARE_COMPLETION(on_exit); -static struct timer_list udc_pollstall_timer; -static int stop_pollstall_timer; -static DECLARE_COMPLETION(on_pollstall_exit); - -/* tasklet for usb disconnect */ -static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect, - (unsigned long) &udc); - - -/* endpoint names used for print */ -static const char ep0_string[] = "ep0in"; -static const char *const ep_string[] = { - ep0_string, - "ep1in-int", "ep2in-bulk", "ep3in-bulk", "ep4in-bulk", "ep5in-bulk", - "ep6in-bulk", "ep7in-bulk", "ep8in-bulk", "ep9in-bulk", "ep10in-bulk", - "ep11in-bulk", "ep12in-bulk", "ep13in-bulk", "ep14in-bulk", - "ep15in-bulk", "ep0out", "ep1out-bulk", "ep2out-bulk", "ep3out-bulk", - "ep4out-bulk", "ep5out-bulk", "ep6out-bulk", "ep7out-bulk", - "ep8out-bulk", "ep9out-bulk", "ep10out-bulk", "ep11out-bulk", - "ep12out-bulk", "ep13out-bulk", "ep14out-bulk", "ep15out-bulk" -}; - -/* DMA usage flag */ -static bool use_dma = 1; -/* packet per buffer dma */ -static bool use_dma_ppb = 1; -/* with per descr. update */ -static bool use_dma_ppb_du; -/* buffer fill mode */ -static int use_dma_bufferfill_mode; -/* full speed only mode */ -static bool use_fullspeed; -/* tx buffer size for high speed */ -static unsigned long hs_tx_buf = UDC_EPIN_BUFF_SIZE; - -/* module parameters */ -module_param(use_dma, bool, S_IRUGO); -MODULE_PARM_DESC(use_dma, "true for DMA"); -module_param(use_dma_ppb, bool, S_IRUGO); -MODULE_PARM_DESC(use_dma_ppb, "true for DMA in packet per buffer mode"); -module_param(use_dma_ppb_du, bool, S_IRUGO); -MODULE_PARM_DESC(use_dma_ppb_du, - "true for DMA in packet per buffer mode with descriptor update"); -module_param(use_fullspeed, bool, S_IRUGO); -MODULE_PARM_DESC(use_fullspeed, "true for fullspeed only"); - -/*---------------------------------------------------------------------------*/ -/* Prints UDC device registers and endpoint irq registers */ -static void print_regs(struct udc *dev) -{ - DBG(dev, "------- Device registers -------\n"); - DBG(dev, "dev config = %08x\n", readl(&dev->regs->cfg)); - DBG(dev, "dev control = %08x\n", readl(&dev->regs->ctl)); - DBG(dev, "dev status = %08x\n", readl(&dev->regs->sts)); - DBG(dev, "\n"); - DBG(dev, "dev int's = %08x\n", readl(&dev->regs->irqsts)); - DBG(dev, "dev intmask = %08x\n", readl(&dev->regs->irqmsk)); - DBG(dev, "\n"); - DBG(dev, "dev ep int's = %08x\n", readl(&dev->regs->ep_irqsts)); - DBG(dev, "dev ep intmask = %08x\n", readl(&dev->regs->ep_irqmsk)); - DBG(dev, "\n"); - DBG(dev, "USE DMA = %d\n", use_dma); - if (use_dma && use_dma_ppb && !use_dma_ppb_du) { - DBG(dev, "DMA mode = PPBNDU (packet per buffer " - "WITHOUT desc. update)\n"); - dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBNDU"); - } else if (use_dma && use_dma_ppb && use_dma_ppb_du) { - DBG(dev, "DMA mode = PPBDU (packet per buffer " - "WITH desc. update)\n"); - dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBDU"); - } - if (use_dma && use_dma_bufferfill_mode) { - DBG(dev, "DMA mode = BF (buffer fill mode)\n"); - dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "BF"); - } - if (!use_dma) - dev_info(&dev->pdev->dev, "FIFO mode\n"); - DBG(dev, "-------------------------------------------------------\n"); -} - -/* Masks unused interrupts */ -static int udc_mask_unused_interrupts(struct udc *dev) -{ - u32 tmp; - - /* mask all dev interrupts */ - tmp = AMD_BIT(UDC_DEVINT_SVC) | - AMD_BIT(UDC_DEVINT_ENUM) | - AMD_BIT(UDC_DEVINT_US) | - AMD_BIT(UDC_DEVINT_UR) | - AMD_BIT(UDC_DEVINT_ES) | - AMD_BIT(UDC_DEVINT_SI) | - AMD_BIT(UDC_DEVINT_SOF)| - AMD_BIT(UDC_DEVINT_SC); - writel(tmp, &dev->regs->irqmsk); - - /* mask all ep interrupts */ - writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqmsk); - - return 0; -} - -/* Enables endpoint 0 interrupts */ -static int udc_enable_ep0_interrupts(struct udc *dev) -{ - u32 tmp; - - DBG(dev, "udc_enable_ep0_interrupts()\n"); - - /* read irq mask */ - tmp = readl(&dev->regs->ep_irqmsk); - /* enable ep0 irq's */ - tmp &= AMD_UNMASK_BIT(UDC_EPINT_IN_EP0) - & AMD_UNMASK_BIT(UDC_EPINT_OUT_EP0); - writel(tmp, &dev->regs->ep_irqmsk); - - return 0; -} - -/* Enables device interrupts for SET_INTF and SET_CONFIG */ -static int udc_enable_dev_setup_interrupts(struct udc *dev) -{ - u32 tmp; - - DBG(dev, "enable device interrupts for setup data\n"); - - /* read irq mask */ - tmp = readl(&dev->regs->irqmsk); - - /* enable SET_INTERFACE, SET_CONFIG and other needed irq's */ - tmp &= AMD_UNMASK_BIT(UDC_DEVINT_SI) - & AMD_UNMASK_BIT(UDC_DEVINT_SC) - & AMD_UNMASK_BIT(UDC_DEVINT_UR) - & AMD_UNMASK_BIT(UDC_DEVINT_SVC) - & AMD_UNMASK_BIT(UDC_DEVINT_ENUM); - writel(tmp, &dev->regs->irqmsk); - - return 0; -} - -/* Calculates fifo start of endpoint based on preceding endpoints */ -static int udc_set_txfifo_addr(struct udc_ep *ep) -{ - struct udc *dev; - u32 tmp; - int i; - - if (!ep || !(ep->in)) - return -EINVAL; - - dev = ep->dev; - ep->txfifo = dev->txfifo; - - /* traverse ep's */ - for (i = 0; i < ep->num; i++) { - if (dev->ep[i].regs) { - /* read fifo size */ - tmp = readl(&dev->ep[i].regs->bufin_framenum); - tmp = AMD_GETBITS(tmp, UDC_EPIN_BUFF_SIZE); - ep->txfifo += tmp; - } - } - return 0; -} - -/* CNAK pending field: bit0 = ep0in, bit16 = ep0out */ -static u32 cnak_pending; - -static void UDC_QUEUE_CNAK(struct udc_ep *ep, unsigned num) -{ - if (readl(&ep->regs->ctl) & AMD_BIT(UDC_EPCTL_NAK)) { - DBG(ep->dev, "NAK could not be cleared for ep%d\n", num); - cnak_pending |= 1 << (num); - ep->naking = 1; - } else - cnak_pending = cnak_pending & (~(1 << (num))); -} - - -/* Enables endpoint, is called by gadget driver */ -static int -udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc) -{ - struct udc_ep *ep; - struct udc *dev; - u32 tmp; - unsigned long iflags; - u8 udc_csr_epix; - unsigned maxpacket; - - if (!usbep - || usbep->name == ep0_string - || !desc - || desc->bDescriptorType != USB_DT_ENDPOINT) - return -EINVAL; - - ep = container_of(usbep, struct udc_ep, ep); - dev = ep->dev; - - DBG(dev, "udc_ep_enable() ep %d\n", ep->num); - - if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - spin_lock_irqsave(&dev->lock, iflags); - ep->desc = desc; - - ep->halted = 0; - - /* set traffic type */ - tmp = readl(&dev->ep[ep->num].regs->ctl); - tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_EPCTL_ET); - writel(tmp, &dev->ep[ep->num].regs->ctl); - - /* set max packet size */ - maxpacket = usb_endpoint_maxp(desc); - tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt); - tmp = AMD_ADDBITS(tmp, maxpacket, UDC_EP_MAX_PKT_SIZE); - ep->ep.maxpacket = maxpacket; - writel(tmp, &dev->ep[ep->num].regs->bufout_maxpkt); - - /* IN ep */ - if (ep->in) { - - /* ep ix in UDC CSR register space */ - udc_csr_epix = ep->num; - - /* set buffer size (tx fifo entries) */ - tmp = readl(&dev->ep[ep->num].regs->bufin_framenum); - /* double buffering: fifo size = 2 x max packet size */ - tmp = AMD_ADDBITS( - tmp, - maxpacket * UDC_EPIN_BUFF_SIZE_MULT - / UDC_DWORD_BYTES, - UDC_EPIN_BUFF_SIZE); - writel(tmp, &dev->ep[ep->num].regs->bufin_framenum); - - /* calc. tx fifo base addr */ - udc_set_txfifo_addr(ep); - - /* flush fifo */ - tmp = readl(&ep->regs->ctl); - tmp |= AMD_BIT(UDC_EPCTL_F); - writel(tmp, &ep->regs->ctl); - - /* OUT ep */ - } else { - /* ep ix in UDC CSR register space */ - udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS; - - /* set max packet size UDC CSR */ - tmp = readl(&dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]); - tmp = AMD_ADDBITS(tmp, maxpacket, - UDC_CSR_NE_MAX_PKT); - writel(tmp, &dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]); - - if (use_dma && !ep->in) { - /* alloc and init BNA dummy request */ - ep->bna_dummy_req = udc_alloc_bna_dummy(ep); - ep->bna_occurred = 0; - } - - if (ep->num != UDC_EP0OUT_IX) - dev->data_ep_enabled = 1; - } - - /* set ep values */ - tmp = readl(&dev->csr->ne[udc_csr_epix]); - /* max packet */ - tmp = AMD_ADDBITS(tmp, maxpacket, UDC_CSR_NE_MAX_PKT); - /* ep number */ - tmp = AMD_ADDBITS(tmp, desc->bEndpointAddress, UDC_CSR_NE_NUM); - /* ep direction */ - tmp = AMD_ADDBITS(tmp, ep->in, UDC_CSR_NE_DIR); - /* ep type */ - tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_CSR_NE_TYPE); - /* ep config */ - tmp = AMD_ADDBITS(tmp, ep->dev->cur_config, UDC_CSR_NE_CFG); - /* ep interface */ - tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf, UDC_CSR_NE_INTF); - /* ep alt */ - tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt, UDC_CSR_NE_ALT); - /* write reg */ - writel(tmp, &dev->csr->ne[udc_csr_epix]); - - /* enable ep irq */ - tmp = readl(&dev->regs->ep_irqmsk); - tmp &= AMD_UNMASK_BIT(ep->num); - writel(tmp, &dev->regs->ep_irqmsk); - - /* - * clear NAK by writing CNAK - * avoid BNA for OUT DMA, don't clear NAK until DMA desc. written - */ - if (!use_dma || ep->in) { - tmp = readl(&ep->regs->ctl); - tmp |= AMD_BIT(UDC_EPCTL_CNAK); - writel(tmp, &ep->regs->ctl); - ep->naking = 0; - UDC_QUEUE_CNAK(ep, ep->num); - } - tmp = desc->bEndpointAddress; - DBG(dev, "%s enabled\n", usbep->name); - - spin_unlock_irqrestore(&dev->lock, iflags); - return 0; -} - -/* Resets endpoint */ -static void ep_init(struct udc_regs __iomem *regs, struct udc_ep *ep) -{ - u32 tmp; - - VDBG(ep->dev, "ep-%d reset\n", ep->num); - ep->desc = NULL; - ep->ep.desc = NULL; - ep->ep.ops = &udc_ep_ops; - INIT_LIST_HEAD(&ep->queue); - - ep->ep.maxpacket = (u16) ~0; - /* set NAK */ - tmp = readl(&ep->regs->ctl); - tmp |= AMD_BIT(UDC_EPCTL_SNAK); - writel(tmp, &ep->regs->ctl); - ep->naking = 1; - - /* disable interrupt */ - tmp = readl(®s->ep_irqmsk); - tmp |= AMD_BIT(ep->num); - writel(tmp, ®s->ep_irqmsk); - - if (ep->in) { - /* unset P and IN bit of potential former DMA */ - tmp = readl(&ep->regs->ctl); - tmp &= AMD_UNMASK_BIT(UDC_EPCTL_P); - writel(tmp, &ep->regs->ctl); - - tmp = readl(&ep->regs->sts); - tmp |= AMD_BIT(UDC_EPSTS_IN); - writel(tmp, &ep->regs->sts); - - /* flush the fifo */ - tmp = readl(&ep->regs->ctl); - tmp |= AMD_BIT(UDC_EPCTL_F); - writel(tmp, &ep->regs->ctl); - - } - /* reset desc pointer */ - writel(0, &ep->regs->desptr); -} - -/* Disables endpoint, is called by gadget driver */ -static int udc_ep_disable(struct usb_ep *usbep) -{ - struct udc_ep *ep = NULL; - unsigned long iflags; - - if (!usbep) - return -EINVAL; - - ep = container_of(usbep, struct udc_ep, ep); - if (usbep->name == ep0_string || !ep->desc) - return -EINVAL; - - DBG(ep->dev, "Disable ep-%d\n", ep->num); - - spin_lock_irqsave(&ep->dev->lock, iflags); - udc_free_request(&ep->ep, &ep->bna_dummy_req->req); - empty_req_queue(ep); - ep_init(ep->dev->regs, ep); - spin_unlock_irqrestore(&ep->dev->lock, iflags); - - return 0; -} - -/* Allocates request packet, called by gadget driver */ -static struct usb_request * -udc_alloc_request(struct usb_ep *usbep, gfp_t gfp) -{ - struct udc_request *req; - struct udc_data_dma *dma_desc; - struct udc_ep *ep; - - if (!usbep) - return NULL; - - ep = container_of(usbep, struct udc_ep, ep); - - VDBG(ep->dev, "udc_alloc_req(): ep%d\n", ep->num); - req = kzalloc(sizeof(struct udc_request), gfp); - if (!req) - return NULL; - - req->req.dma = DMA_DONT_USE; - INIT_LIST_HEAD(&req->queue); - - if (ep->dma) { - /* ep0 in requests are allocated from data pool here */ - dma_desc = pci_pool_alloc(ep->dev->data_requests, gfp, - &req->td_phys); - if (!dma_desc) { - kfree(req); - return NULL; - } - - VDBG(ep->dev, "udc_alloc_req: req = %p dma_desc = %p, " - "td_phys = %lx\n", - req, dma_desc, - (unsigned long)req->td_phys); - /* prevent from using desc. - set HOST BUSY */ - dma_desc->status = AMD_ADDBITS(dma_desc->status, - UDC_DMA_STP_STS_BS_HOST_BUSY, - UDC_DMA_STP_STS_BS); - dma_desc->bufptr = cpu_to_le32(DMA_DONT_USE); - req->td_data = dma_desc; - req->td_data_last = NULL; - req->chain_len = 1; - } - - return &req->req; -} - -/* Frees request packet, called by gadget driver */ -static void -udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq) -{ - struct udc_ep *ep; - struct udc_request *req; - - if (!usbep || !usbreq) - return; - - ep = container_of(usbep, struct udc_ep, ep); - req = container_of(usbreq, struct udc_request, req); - VDBG(ep->dev, "free_req req=%p\n", req); - BUG_ON(!list_empty(&req->queue)); - if (req->td_data) { - VDBG(ep->dev, "req->td_data=%p\n", req->td_data); - - /* free dma chain if created */ - if (req->chain_len > 1) - udc_free_dma_chain(ep->dev, req); - - pci_pool_free(ep->dev->data_requests, req->td_data, - req->td_phys); - } - kfree(req); -} - -/* Init BNA dummy descriptor for HOST BUSY and pointing to itself */ -static void udc_init_bna_dummy(struct udc_request *req) -{ - if (req) { - /* set last bit */ - req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L); - /* set next pointer to itself */ - req->td_data->next = req->td_phys; - /* set HOST BUSY */ - req->td_data->status - = AMD_ADDBITS(req->td_data->status, - UDC_DMA_STP_STS_BS_DMA_DONE, - UDC_DMA_STP_STS_BS); -#ifdef UDC_VERBOSE - pr_debug("bna desc = %p, sts = %08x\n", - req->td_data, req->td_data->status); -#endif - } -} - -/* Allocate BNA dummy descriptor */ -static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep) -{ - struct udc_request *req = NULL; - struct usb_request *_req = NULL; - - /* alloc the dummy request */ - _req = udc_alloc_request(&ep->ep, GFP_ATOMIC); - if (_req) { - req = container_of(_req, struct udc_request, req); - ep->bna_dummy_req = req; - udc_init_bna_dummy(req); - } - return req; -} - -/* Write data to TX fifo for IN packets */ -static void -udc_txfifo_write(struct udc_ep *ep, struct usb_request *req) -{ - u8 *req_buf; - u32 *buf; - int i, j; - unsigned bytes = 0; - unsigned remaining = 0; - - if (!req || !ep) - return; - - req_buf = req->buf + req->actual; - prefetch(req_buf); - remaining = req->length - req->actual; - - buf = (u32 *) req_buf; - - bytes = ep->ep.maxpacket; - if (bytes > remaining) - bytes = remaining; - - /* dwords first */ - for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) - writel(*(buf + i), ep->txfifo); - - /* remaining bytes must be written by byte access */ - for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) { - writeb((u8)(*(buf + i) >> (j << UDC_BITS_PER_BYTE_SHIFT)), - ep->txfifo); - } - - /* dummy write confirm */ - writel(0, &ep->regs->confirm); -} - -/* Read dwords from RX fifo for OUT transfers */ -static int udc_rxfifo_read_dwords(struct udc *dev, u32 *buf, int dwords) -{ - int i; - - VDBG(dev, "udc_read_dwords(): %d dwords\n", dwords); - - for (i = 0; i < dwords; i++) - *(buf + i) = readl(dev->rxfifo); - return 0; -} - -/* Read bytes from RX fifo for OUT transfers */ -static int udc_rxfifo_read_bytes(struct udc *dev, u8 *buf, int bytes) -{ - int i, j; - u32 tmp; - - VDBG(dev, "udc_read_bytes(): %d bytes\n", bytes); - - /* dwords first */ - for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) - *((u32 *)(buf + (i<<2))) = readl(dev->rxfifo); - - /* remaining bytes must be read by byte access */ - if (bytes % UDC_DWORD_BYTES) { - tmp = readl(dev->rxfifo); - for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) { - *(buf + (i<<2) + j) = (u8)(tmp & UDC_BYTE_MASK); - tmp = tmp >> UDC_BITS_PER_BYTE; - } - } - - return 0; -} - -/* Read data from RX fifo for OUT transfers */ -static int -udc_rxfifo_read(struct udc_ep *ep, struct udc_request *req) -{ - u8 *buf; - unsigned buf_space; - unsigned bytes = 0; - unsigned finished = 0; - - /* received number bytes */ - bytes = readl(&ep->regs->sts); - bytes = AMD_GETBITS(bytes, UDC_EPSTS_RX_PKT_SIZE); - - buf_space = req->req.length - req->req.actual; - buf = req->req.buf + req->req.actual; - if (bytes > buf_space) { - if ((buf_space % ep->ep.maxpacket) != 0) { - DBG(ep->dev, - "%s: rx %d bytes, rx-buf space = %d bytesn\n", - ep->ep.name, bytes, buf_space); - req->req.status = -EOVERFLOW; - } - bytes = buf_space; - } - req->req.actual += bytes; - - /* last packet ? */ - if (((bytes % ep->ep.maxpacket) != 0) || (!bytes) - || ((req->req.actual == req->req.length) && !req->req.zero)) - finished = 1; - - /* read rx fifo bytes */ - VDBG(ep->dev, "ep %s: rxfifo read %d bytes\n", ep->ep.name, bytes); - udc_rxfifo_read_bytes(ep->dev, buf, bytes); - - return finished; -} - -/* create/re-init a DMA descriptor or a DMA descriptor chain */ -static int prep_dma(struct udc_ep *ep, struct udc_request *req, gfp_t gfp) -{ - int retval = 0; - u32 tmp; - - VDBG(ep->dev, "prep_dma\n"); - VDBG(ep->dev, "prep_dma ep%d req->td_data=%p\n", - ep->num, req->td_data); - - /* set buffer pointer */ - req->td_data->bufptr = req->req.dma; - - /* set last bit */ - req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L); - - /* build/re-init dma chain if maxpkt scatter mode, not for EP0 */ - if (use_dma_ppb) { - - retval = udc_create_dma_chain(ep, req, ep->ep.maxpacket, gfp); - if (retval != 0) { - if (retval == -ENOMEM) - DBG(ep->dev, "Out of DMA memory\n"); - return retval; - } - if (ep->in) { - if (req->req.length == ep->ep.maxpacket) { - /* write tx bytes */ - req->td_data->status = - AMD_ADDBITS(req->td_data->status, - ep->ep.maxpacket, - UDC_DMA_IN_STS_TXBYTES); - - } - } - - } - - if (ep->in) { - VDBG(ep->dev, "IN: use_dma_ppb=%d req->req.len=%d " - "maxpacket=%d ep%d\n", - use_dma_ppb, req->req.length, - ep->ep.maxpacket, ep->num); - /* - * if bytes < max packet then tx bytes must - * be written in packet per buffer mode - */ - if (!use_dma_ppb || req->req.length < ep->ep.maxpacket - || ep->num == UDC_EP0OUT_IX - || ep->num == UDC_EP0IN_IX) { - /* write tx bytes */ - req->td_data->status = - AMD_ADDBITS(req->td_data->status, - req->req.length, - UDC_DMA_IN_STS_TXBYTES); - /* reset frame num */ - req->td_data->status = - AMD_ADDBITS(req->td_data->status, - 0, - UDC_DMA_IN_STS_FRAMENUM); - } - /* set HOST BUSY */ - req->td_data->status = - AMD_ADDBITS(req->td_data->status, - UDC_DMA_STP_STS_BS_HOST_BUSY, - UDC_DMA_STP_STS_BS); - } else { - VDBG(ep->dev, "OUT set host ready\n"); - /* set HOST READY */ - req->td_data->status = - AMD_ADDBITS(req->td_data->status, - UDC_DMA_STP_STS_BS_HOST_READY, - UDC_DMA_STP_STS_BS); - - - /* clear NAK by writing CNAK */ - if (ep->naking) { - tmp = readl(&ep->regs->ctl); - tmp |= AMD_BIT(UDC_EPCTL_CNAK); - writel(tmp, &ep->regs->ctl); - ep->naking = 0; - UDC_QUEUE_CNAK(ep, ep->num); - } - - } - - return retval; -} - -/* Completes request packet ... caller MUST hold lock */ -static void -complete_req(struct udc_ep *ep, struct udc_request *req, int sts) -__releases(ep->dev->lock) -__acquires(ep->dev->lock) -{ - struct udc *dev; - unsigned halted; - - VDBG(ep->dev, "complete_req(): ep%d\n", ep->num); - - dev = ep->dev; - /* unmap DMA */ - if (ep->dma) - usb_gadget_unmap_request(&dev->gadget, &req->req, ep->in); - - halted = ep->halted; - ep->halted = 1; - - /* set new status if pending */ - if (req->req.status == -EINPROGRESS) - req->req.status = sts; - - /* remove from ep queue */ - list_del_init(&req->queue); - - VDBG(ep->dev, "req %p => complete %d bytes at %s with sts %d\n", - &req->req, req->req.length, ep->ep.name, sts); - - spin_unlock(&dev->lock); - req->req.complete(&ep->ep, &req->req); - spin_lock(&dev->lock); - ep->halted = halted; -} - -/* frees pci pool descriptors of a DMA chain */ -static int udc_free_dma_chain(struct udc *dev, struct udc_request *req) -{ - - int ret_val = 0; - struct udc_data_dma *td; - struct udc_data_dma *td_last = NULL; - unsigned int i; - - DBG(dev, "free chain req = %p\n", req); - - /* do not free first desc., will be done by free for request */ - td_last = req->td_data; - td = phys_to_virt(td_last->next); - - for (i = 1; i < req->chain_len; i++) { - - pci_pool_free(dev->data_requests, td, - (dma_addr_t) td_last->next); - td_last = td; - td = phys_to_virt(td_last->next); - } - - return ret_val; -} - -/* Iterates to the end of a DMA chain and returns last descriptor */ -static struct udc_data_dma *udc_get_last_dma_desc(struct udc_request *req) -{ - struct udc_data_dma *td; - - td = req->td_data; - while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) - td = phys_to_virt(td->next); - - return td; - -} - -/* Iterates to the end of a DMA chain and counts bytes received */ -static u32 udc_get_ppbdu_rxbytes(struct udc_request *req) -{ - struct udc_data_dma *td; - u32 count; - - td = req->td_data; - /* received number bytes */ - count = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_RXBYTES); - - while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) { - td = phys_to_virt(td->next); - /* received number bytes */ - if (td) { - count += AMD_GETBITS(td->status, - UDC_DMA_OUT_STS_RXBYTES); - } - } - - return count; - -} - -/* Creates or re-inits a DMA chain */ -static int udc_create_dma_chain( - struct udc_ep *ep, - struct udc_request *req, - unsigned long buf_len, gfp_t gfp_flags -) -{ - unsigned long bytes = req->req.length; - unsigned int i; - dma_addr_t dma_addr; - struct udc_data_dma *td = NULL; - struct udc_data_dma *last = NULL; - unsigned long txbytes; - unsigned create_new_chain = 0; - unsigned len; - - VDBG(ep->dev, "udc_create_dma_chain: bytes=%ld buf_len=%ld\n", - bytes, buf_len); - dma_addr = DMA_DONT_USE; - - /* unset L bit in first desc for OUT */ - if (!ep->in) - req->td_data->status &= AMD_CLEAR_BIT(UDC_DMA_IN_STS_L); - - /* alloc only new desc's if not already available */ - len = req->req.length / ep->ep.maxpacket; - if (req->req.length % ep->ep.maxpacket) - len++; - - if (len > req->chain_len) { - /* shorter chain already allocated before */ - if (req->chain_len > 1) - udc_free_dma_chain(ep->dev, req); - req->chain_len = len; - create_new_chain = 1; - } - - td = req->td_data; - /* gen. required number of descriptors and buffers */ - for (i = buf_len; i < bytes; i += buf_len) { - /* create or determine next desc. */ - if (create_new_chain) { - - td = pci_pool_alloc(ep->dev->data_requests, - gfp_flags, &dma_addr); - if (!td) - return -ENOMEM; - - td->status = 0; - } else if (i == buf_len) { - /* first td */ - td = (struct udc_data_dma *) phys_to_virt( - req->td_data->next); - td->status = 0; - } else { - td = (struct udc_data_dma *) phys_to_virt(last->next); - td->status = 0; - } - - - if (td) - td->bufptr = req->req.dma + i; /* assign buffer */ - else - break; - - /* short packet ? */ - if ((bytes - i) >= buf_len) { - txbytes = buf_len; - } else { - /* short packet */ - txbytes = bytes - i; - } - - /* link td and assign tx bytes */ - if (i == buf_len) { - if (create_new_chain) - req->td_data->next = dma_addr; - /* - else - req->td_data->next = virt_to_phys(td); - */ - /* write tx bytes */ - if (ep->in) { - /* first desc */ - req->td_data->status = - AMD_ADDBITS(req->td_data->status, - ep->ep.maxpacket, - UDC_DMA_IN_STS_TXBYTES); - /* second desc */ - td->status = AMD_ADDBITS(td->status, - txbytes, - UDC_DMA_IN_STS_TXBYTES); - } - } else { - if (create_new_chain) - last->next = dma_addr; - /* - else - last->next = virt_to_phys(td); - */ - if (ep->in) { - /* write tx bytes */ - td->status = AMD_ADDBITS(td->status, - txbytes, - UDC_DMA_IN_STS_TXBYTES); - } - } - last = td; - } - /* set last bit */ - if (td) { - td->status |= AMD_BIT(UDC_DMA_IN_STS_L); - /* last desc. points to itself */ - req->td_data_last = td; - } - - return 0; -} - -/* Enabling RX DMA */ -static void udc_set_rde(struct udc *dev) -{ - u32 tmp; - - VDBG(dev, "udc_set_rde()\n"); - /* stop RDE timer */ - if (timer_pending(&udc_timer)) { - set_rde = 0; - mod_timer(&udc_timer, jiffies - 1); - } - /* set RDE */ - tmp = readl(&dev->regs->ctl); - tmp |= AMD_BIT(UDC_DEVCTL_RDE); - writel(tmp, &dev->regs->ctl); -} - -/* Queues a request packet, called by gadget driver */ -static int -udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp) -{ - int retval = 0; - u8 open_rxfifo = 0; - unsigned long iflags; - struct udc_ep *ep; - struct udc_request *req; - struct udc *dev; - u32 tmp; - - /* check the inputs */ - req = container_of(usbreq, struct udc_request, req); - - if (!usbep || !usbreq || !usbreq->complete || !usbreq->buf - || !list_empty(&req->queue)) - return -EINVAL; - - ep = container_of(usbep, struct udc_ep, ep); - if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX)) - return -EINVAL; - - VDBG(ep->dev, "udc_queue(): ep%d-in=%d\n", ep->num, ep->in); - dev = ep->dev; - - if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - /* map dma (usually done before) */ - if (ep->dma) { - VDBG(dev, "DMA map req %p\n", req); - retval = usb_gadget_map_request(&udc->gadget, usbreq, ep->in); - if (retval) - return retval; - } - - VDBG(dev, "%s queue req %p, len %d req->td_data=%p buf %p\n", - usbep->name, usbreq, usbreq->length, - req->td_data, usbreq->buf); - - spin_lock_irqsave(&dev->lock, iflags); - usbreq->actual = 0; - usbreq->status = -EINPROGRESS; - req->dma_done = 0; - - /* on empty queue just do first transfer */ - if (list_empty(&ep->queue)) { - /* zlp */ - if (usbreq->length == 0) { - /* IN zlp's are handled by hardware */ - complete_req(ep, req, 0); - VDBG(dev, "%s: zlp\n", ep->ep.name); - /* - * if set_config or set_intf is waiting for ack by zlp - * then set CSR_DONE - */ - if (dev->set_cfg_not_acked) { - tmp = readl(&dev->regs->ctl); - tmp |= AMD_BIT(UDC_DEVCTL_CSR_DONE); - writel(tmp, &dev->regs->ctl); - dev->set_cfg_not_acked = 0; - } - /* setup command is ACK'ed now by zlp */ - if (dev->waiting_zlp_ack_ep0in) { - /* clear NAK by writing CNAK in EP0_IN */ - tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl); - tmp |= AMD_BIT(UDC_EPCTL_CNAK); - writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl); - dev->ep[UDC_EP0IN_IX].naking = 0; - UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], - UDC_EP0IN_IX); - dev->waiting_zlp_ack_ep0in = 0; - } - goto finished; - } - if (ep->dma) { - retval = prep_dma(ep, req, gfp); - if (retval != 0) - goto finished; - /* write desc pointer to enable DMA */ - if (ep->in) { - /* set HOST READY */ - req->td_data->status = - AMD_ADDBITS(req->td_data->status, - UDC_DMA_IN_STS_BS_HOST_READY, - UDC_DMA_IN_STS_BS); - } - - /* disabled rx dma while descriptor update */ - if (!ep->in) { - /* stop RDE timer */ - if (timer_pending(&udc_timer)) { - set_rde = 0; - mod_timer(&udc_timer, jiffies - 1); - } - /* clear RDE */ - tmp = readl(&dev->regs->ctl); - tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE); - writel(tmp, &dev->regs->ctl); - open_rxfifo = 1; - - /* - * if BNA occurred then let BNA dummy desc. - * point to current desc. - */ - if (ep->bna_occurred) { - VDBG(dev, "copy to BNA dummy desc.\n"); - memcpy(ep->bna_dummy_req->td_data, - req->td_data, - sizeof(struct udc_data_dma)); - } - } - /* write desc pointer */ - writel(req->td_phys, &ep->regs->desptr); - - /* clear NAK by writing CNAK */ - if (ep->naking) { - tmp = readl(&ep->regs->ctl); - tmp |= AMD_BIT(UDC_EPCTL_CNAK); - writel(tmp, &ep->regs->ctl); - ep->naking = 0; - UDC_QUEUE_CNAK(ep, ep->num); - } - - if (ep->in) { - /* enable ep irq */ - tmp = readl(&dev->regs->ep_irqmsk); - tmp &= AMD_UNMASK_BIT(ep->num); - writel(tmp, &dev->regs->ep_irqmsk); - } - } else if (ep->in) { - /* enable ep irq */ - tmp = readl(&dev->regs->ep_irqmsk); - tmp &= AMD_UNMASK_BIT(ep->num); - writel(tmp, &dev->regs->ep_irqmsk); - } - - } else if (ep->dma) { - - /* - * prep_dma not used for OUT ep's, this is not possible - * for PPB modes, because of chain creation reasons - */ - if (ep->in) { - retval = prep_dma(ep, req, gfp); - if (retval != 0) - goto finished; - } - } - VDBG(dev, "list_add\n"); - /* add request to ep queue */ - if (req) { - - list_add_tail(&req->queue, &ep->queue); - - /* open rxfifo if out data queued */ - if (open_rxfifo) { - /* enable DMA */ - req->dma_going = 1; - udc_set_rde(dev); - if (ep->num != UDC_EP0OUT_IX) - dev->data_ep_queued = 1; - } - /* stop OUT naking */ - if (!ep->in) { - if (!use_dma && udc_rxfifo_pending) { - DBG(dev, "udc_queue(): pending bytes in " - "rxfifo after nyet\n"); - /* - * read pending bytes afer nyet: - * referring to isr - */ - if (udc_rxfifo_read(ep, req)) { - /* finish */ - complete_req(ep, req, 0); - } - udc_rxfifo_pending = 0; - - } - } - } - -finished: - spin_unlock_irqrestore(&dev->lock, iflags); - return retval; -} - -/* Empty request queue of an endpoint; caller holds spinlock */ -static void empty_req_queue(struct udc_ep *ep) -{ - struct udc_request *req; - - ep->halted = 1; - while (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, - struct udc_request, - queue); - complete_req(ep, req, -ESHUTDOWN); - } -} - -/* Dequeues a request packet, called by gadget driver */ -static int udc_dequeue(struct usb_ep *usbep, struct usb_request *usbreq) -{ - struct udc_ep *ep; - struct udc_request *req; - unsigned halted; - unsigned long iflags; - - ep = container_of(usbep, struct udc_ep, ep); - if (!usbep || !usbreq || (!ep->desc && (ep->num != 0 - && ep->num != UDC_EP0OUT_IX))) - return -EINVAL; - - req = container_of(usbreq, struct udc_request, req); - - spin_lock_irqsave(&ep->dev->lock, iflags); - halted = ep->halted; - ep->halted = 1; - /* request in processing or next one */ - if (ep->queue.next == &req->queue) { - if (ep->dma && req->dma_going) { - if (ep->in) - ep->cancel_transfer = 1; - else { - u32 tmp; - u32 dma_sts; - /* stop potential receive DMA */ - tmp = readl(&udc->regs->ctl); - writel(tmp & AMD_UNMASK_BIT(UDC_DEVCTL_RDE), - &udc->regs->ctl); - /* - * Cancel transfer later in ISR - * if descriptor was touched. - */ - dma_sts = AMD_GETBITS(req->td_data->status, - UDC_DMA_OUT_STS_BS); - if (dma_sts != UDC_DMA_OUT_STS_BS_HOST_READY) - ep->cancel_transfer = 1; - else { - udc_init_bna_dummy(ep->req); - writel(ep->bna_dummy_req->td_phys, - &ep->regs->desptr); - } - writel(tmp, &udc->regs->ctl); - } - } - } - complete_req(ep, req, -ECONNRESET); - ep->halted = halted; - - spin_unlock_irqrestore(&ep->dev->lock, iflags); - return 0; -} - -/* Halt or clear halt of endpoint */ -static int -udc_set_halt(struct usb_ep *usbep, int halt) -{ - struct udc_ep *ep; - u32 tmp; - unsigned long iflags; - int retval = 0; - - if (!usbep) - return -EINVAL; - - pr_debug("set_halt %s: halt=%d\n", usbep->name, halt); - - ep = container_of(usbep, struct udc_ep, ep); - if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX)) - return -EINVAL; - if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - spin_lock_irqsave(&udc_stall_spinlock, iflags); - /* halt or clear halt */ - if (halt) { - if (ep->num == 0) - ep->dev->stall_ep0in = 1; - else { - /* - * set STALL - * rxfifo empty not taken into acount - */ - tmp = readl(&ep->regs->ctl); - tmp |= AMD_BIT(UDC_EPCTL_S); - writel(tmp, &ep->regs->ctl); - ep->halted = 1; - - /* setup poll timer */ - if (!timer_pending(&udc_pollstall_timer)) { - udc_pollstall_timer.expires = jiffies + - HZ * UDC_POLLSTALL_TIMER_USECONDS - / (1000 * 1000); - if (!stop_pollstall_timer) { - DBG(ep->dev, "start polltimer\n"); - add_timer(&udc_pollstall_timer); - } - } - } - } else { - /* ep is halted by set_halt() before */ - if (ep->halted) { - tmp = readl(&ep->regs->ctl); - /* clear stall bit */ - tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S); - /* clear NAK by writing CNAK */ - tmp |= AMD_BIT(UDC_EPCTL_CNAK); - writel(tmp, &ep->regs->ctl); - ep->halted = 0; - UDC_QUEUE_CNAK(ep, ep->num); - } - } - spin_unlock_irqrestore(&udc_stall_spinlock, iflags); - return retval; -} - -/* gadget interface */ -static const struct usb_ep_ops udc_ep_ops = { - .enable = udc_ep_enable, - .disable = udc_ep_disable, - - .alloc_request = udc_alloc_request, - .free_request = udc_free_request, - - .queue = udc_queue, - .dequeue = udc_dequeue, - - .set_halt = udc_set_halt, - /* fifo ops not implemented */ -}; - -/*-------------------------------------------------------------------------*/ - -/* Get frame counter (not implemented) */ -static int udc_get_frame(struct usb_gadget *gadget) -{ - return -EOPNOTSUPP; -} - -/* Remote wakeup gadget interface */ -static int udc_wakeup(struct usb_gadget *gadget) -{ - struct udc *dev; - - if (!gadget) - return -EINVAL; - dev = container_of(gadget, struct udc, gadget); - udc_remote_wakeup(dev); - - return 0; -} - -static int amd5536_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int amd5536_stop(struct usb_gadget_driver *driver); -/* gadget operations */ -static const struct usb_gadget_ops udc_ops = { - .wakeup = udc_wakeup, - .get_frame = udc_get_frame, - .start = amd5536_start, - .stop = amd5536_stop, -}; - -/* Setups endpoint parameters, adds endpoints to linked list */ -static void make_ep_lists(struct udc *dev) -{ - /* make gadget ep lists */ - INIT_LIST_HEAD(&dev->gadget.ep_list); - list_add_tail(&dev->ep[UDC_EPIN_STATUS_IX].ep.ep_list, - &dev->gadget.ep_list); - list_add_tail(&dev->ep[UDC_EPIN_IX].ep.ep_list, - &dev->gadget.ep_list); - list_add_tail(&dev->ep[UDC_EPOUT_IX].ep.ep_list, - &dev->gadget.ep_list); - - /* fifo config */ - dev->ep[UDC_EPIN_STATUS_IX].fifo_depth = UDC_EPIN_SMALLINT_BUFF_SIZE; - if (dev->gadget.speed == USB_SPEED_FULL) - dev->ep[UDC_EPIN_IX].fifo_depth = UDC_FS_EPIN_BUFF_SIZE; - else if (dev->gadget.speed == USB_SPEED_HIGH) - dev->ep[UDC_EPIN_IX].fifo_depth = hs_tx_buf; - dev->ep[UDC_EPOUT_IX].fifo_depth = UDC_RXFIFO_SIZE; -} - -/* init registers at driver load time */ -static int startup_registers(struct udc *dev) -{ - u32 tmp; - - /* init controller by soft reset */ - udc_soft_reset(dev); - - /* mask not needed interrupts */ - udc_mask_unused_interrupts(dev); - - /* put into initial config */ - udc_basic_init(dev); - /* link up all endpoints */ - udc_setup_endpoints(dev); - - /* program speed */ - tmp = readl(&dev->regs->cfg); - if (use_fullspeed) - tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD); - else - tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_HS, UDC_DEVCFG_SPD); - writel(tmp, &dev->regs->cfg); - - return 0; -} - -/* Inits UDC context */ -static void udc_basic_init(struct udc *dev) -{ - u32 tmp; - - DBG(dev, "udc_basic_init()\n"); - - dev->gadget.speed = USB_SPEED_UNKNOWN; - - /* stop RDE timer */ - if (timer_pending(&udc_timer)) { - set_rde = 0; - mod_timer(&udc_timer, jiffies - 1); - } - /* stop poll stall timer */ - if (timer_pending(&udc_pollstall_timer)) - mod_timer(&udc_pollstall_timer, jiffies - 1); - /* disable DMA */ - tmp = readl(&dev->regs->ctl); - tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE); - tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_TDE); - writel(tmp, &dev->regs->ctl); - - /* enable dynamic CSR programming */ - tmp = readl(&dev->regs->cfg); - tmp |= AMD_BIT(UDC_DEVCFG_CSR_PRG); - /* set self powered */ - tmp |= AMD_BIT(UDC_DEVCFG_SP); - /* set remote wakeupable */ - tmp |= AMD_BIT(UDC_DEVCFG_RWKP); - writel(tmp, &dev->regs->cfg); - - make_ep_lists(dev); - - dev->data_ep_enabled = 0; - dev->data_ep_queued = 0; -} - -/* Sets initial endpoint parameters */ -static void udc_setup_endpoints(struct udc *dev) -{ - struct udc_ep *ep; - u32 tmp; - u32 reg; - - DBG(dev, "udc_setup_endpoints()\n"); - - /* read enum speed */ - tmp = readl(&dev->regs->sts); - tmp = AMD_GETBITS(tmp, UDC_DEVSTS_ENUM_SPEED); - if (tmp == UDC_DEVSTS_ENUM_SPEED_HIGH) - dev->gadget.speed = USB_SPEED_HIGH; - else if (tmp == UDC_DEVSTS_ENUM_SPEED_FULL) - dev->gadget.speed = USB_SPEED_FULL; - - /* set basic ep parameters */ - for (tmp = 0; tmp < UDC_EP_NUM; tmp++) { - ep = &dev->ep[tmp]; - ep->dev = dev; - ep->ep.name = ep_string[tmp]; - ep->num = tmp; - /* txfifo size is calculated at enable time */ - ep->txfifo = dev->txfifo; - - /* fifo size */ - if (tmp < UDC_EPIN_NUM) { - ep->fifo_depth = UDC_TXFIFO_SIZE; - ep->in = 1; - } else { - ep->fifo_depth = UDC_RXFIFO_SIZE; - ep->in = 0; - - } - ep->regs = &dev->ep_regs[tmp]; - /* - * ep will be reset only if ep was not enabled before to avoid - * disabling ep interrupts when ENUM interrupt occurs but ep is - * not enabled by gadget driver - */ - if (!ep->desc) - ep_init(dev->regs, ep); - - if (use_dma) { - /* - * ep->dma is not really used, just to indicate that - * DMA is active: remove this - * dma regs = dev control regs - */ - ep->dma = &dev->regs->ctl; - - /* nak OUT endpoints until enable - not for ep0 */ - if (tmp != UDC_EP0IN_IX && tmp != UDC_EP0OUT_IX - && tmp > UDC_EPIN_NUM) { - /* set NAK */ - reg = readl(&dev->ep[tmp].regs->ctl); - reg |= AMD_BIT(UDC_EPCTL_SNAK); - writel(reg, &dev->ep[tmp].regs->ctl); - dev->ep[tmp].naking = 1; - - } - } - } - /* EP0 max packet */ - if (dev->gadget.speed == USB_SPEED_FULL) { - dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_FS_EP0IN_MAX_PKT_SIZE; - dev->ep[UDC_EP0OUT_IX].ep.maxpacket = - UDC_FS_EP0OUT_MAX_PKT_SIZE; - } else if (dev->gadget.speed == USB_SPEED_HIGH) { - dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE; - dev->ep[UDC_EP0OUT_IX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE; - } - - /* - * with suspend bug workaround, ep0 params for gadget driver - * are set at gadget driver bind() call - */ - dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep; - dev->ep[UDC_EP0IN_IX].halted = 0; - INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); - - /* init cfg/alt/int */ - dev->cur_config = 0; - dev->cur_intf = 0; - dev->cur_alt = 0; -} - -/* Bringup after Connect event, initial bringup to be ready for ep0 events */ -static void usb_connect(struct udc *dev) -{ - - dev_info(&dev->pdev->dev, "USB Connect\n"); - - dev->connected = 1; - - /* put into initial config */ - udc_basic_init(dev); - - /* enable device setup interrupts */ - udc_enable_dev_setup_interrupts(dev); -} - -/* - * Calls gadget with disconnect event and resets the UDC and makes - * initial bringup to be ready for ep0 events - */ -static void usb_disconnect(struct udc *dev) -{ - - dev_info(&dev->pdev->dev, "USB Disconnect\n"); - - dev->connected = 0; - - /* mask interrupts */ - udc_mask_unused_interrupts(dev); - - /* REVISIT there doesn't seem to be a point to having this - * talk to a tasklet ... do it directly, we already hold - * the spinlock needed to process the disconnect. - */ - - tasklet_schedule(&disconnect_tasklet); -} - -/* Tasklet for disconnect to be outside of interrupt context */ -static void udc_tasklet_disconnect(unsigned long par) -{ - struct udc *dev = (struct udc *)(*((struct udc **) par)); - u32 tmp; - - DBG(dev, "Tasklet disconnect\n"); - spin_lock_irq(&dev->lock); - - if (dev->driver) { - spin_unlock(&dev->lock); - dev->driver->disconnect(&dev->gadget); - spin_lock(&dev->lock); - - /* empty queues */ - for (tmp = 0; tmp < UDC_EP_NUM; tmp++) - empty_req_queue(&dev->ep[tmp]); - - } - - /* disable ep0 */ - ep_init(dev->regs, - &dev->ep[UDC_EP0IN_IX]); - - - if (!soft_reset_occured) { - /* init controller by soft reset */ - udc_soft_reset(dev); - soft_reset_occured++; - } - - /* re-enable dev interrupts */ - udc_enable_dev_setup_interrupts(dev); - /* back to full speed ? */ - if (use_fullspeed) { - tmp = readl(&dev->regs->cfg); - tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD); - writel(tmp, &dev->regs->cfg); - } - - spin_unlock_irq(&dev->lock); -} - -/* Reset the UDC core */ -static void udc_soft_reset(struct udc *dev) -{ - unsigned long flags; - - DBG(dev, "Soft reset\n"); - /* - * reset possible waiting interrupts, because int. - * status is lost after soft reset, - * ep int. status reset - */ - writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqsts); - /* device int. status reset */ - writel(UDC_DEV_MSK_DISABLE, &dev->regs->irqsts); - - spin_lock_irqsave(&udc_irq_spinlock, flags); - writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg); - readl(&dev->regs->cfg); - spin_unlock_irqrestore(&udc_irq_spinlock, flags); - -} - -/* RDE timer callback to set RDE bit */ -static void udc_timer_function(unsigned long v) -{ - u32 tmp; - - spin_lock_irq(&udc_irq_spinlock); - - if (set_rde > 0) { - /* - * open the fifo if fifo was filled on last timer call - * conditionally - */ - if (set_rde > 1) { - /* set RDE to receive setup data */ - tmp = readl(&udc->regs->ctl); - tmp |= AMD_BIT(UDC_DEVCTL_RDE); - writel(tmp, &udc->regs->ctl); - set_rde = -1; - } else if (readl(&udc->regs->sts) - & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) { - /* - * if fifo empty setup polling, do not just - * open the fifo - */ - udc_timer.expires = jiffies + HZ/UDC_RDE_TIMER_DIV; - if (!stop_timer) - add_timer(&udc_timer); - } else { - /* - * fifo contains data now, setup timer for opening - * the fifo when timer expires to be able to receive - * setup packets, when data packets gets queued by - * gadget layer then timer will forced to expire with - * set_rde=0 (RDE is set in udc_queue()) - */ - set_rde++; - /* debug: lhadmot_timer_start = 221070 */ - udc_timer.expires = jiffies + HZ*UDC_RDE_TIMER_SECONDS; - if (!stop_timer) - add_timer(&udc_timer); - } - - } else - set_rde = -1; /* RDE was set by udc_queue() */ - spin_unlock_irq(&udc_irq_spinlock); - if (stop_timer) - complete(&on_exit); - -} - -/* Handle halt state, used in stall poll timer */ -static void udc_handle_halt_state(struct udc_ep *ep) -{ - u32 tmp; - /* set stall as long not halted */ - if (ep->halted == 1) { - tmp = readl(&ep->regs->ctl); - /* STALL cleared ? */ - if (!(tmp & AMD_BIT(UDC_EPCTL_S))) { - /* - * FIXME: MSC spec requires that stall remains - * even on receivng of CLEAR_FEATURE HALT. So - * we would set STALL again here to be compliant. - * But with current mass storage drivers this does - * not work (would produce endless host retries). - * So we clear halt on CLEAR_FEATURE. - * - DBG(ep->dev, "ep %d: set STALL again\n", ep->num); - tmp |= AMD_BIT(UDC_EPCTL_S); - writel(tmp, &ep->regs->ctl);*/ - - /* clear NAK by writing CNAK */ - tmp |= AMD_BIT(UDC_EPCTL_CNAK); - writel(tmp, &ep->regs->ctl); - ep->halted = 0; - UDC_QUEUE_CNAK(ep, ep->num); - } - } -} - -/* Stall timer callback to poll S bit and set it again after */ -static void udc_pollstall_timer_function(unsigned long v) -{ - struct udc_ep *ep; - int halted = 0; - - spin_lock_irq(&udc_stall_spinlock); - /* - * only one IN and OUT endpoints are handled - * IN poll stall - */ - ep = &udc->ep[UDC_EPIN_IX]; - udc_handle_halt_state(ep); - if (ep->halted) - halted = 1; - /* OUT poll stall */ - ep = &udc->ep[UDC_EPOUT_IX]; - udc_handle_halt_state(ep); - if (ep->halted) - halted = 1; - - /* setup timer again when still halted */ - if (!stop_pollstall_timer && halted) { - udc_pollstall_timer.expires = jiffies + - HZ * UDC_POLLSTALL_TIMER_USECONDS - / (1000 * 1000); - add_timer(&udc_pollstall_timer); - } - spin_unlock_irq(&udc_stall_spinlock); - - if (stop_pollstall_timer) - complete(&on_pollstall_exit); -} - -/* Inits endpoint 0 so that SETUP packets are processed */ -static void activate_control_endpoints(struct udc *dev) -{ - u32 tmp; - - DBG(dev, "activate_control_endpoints\n"); - - /* flush fifo */ - tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl); - tmp |= AMD_BIT(UDC_EPCTL_F); - writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl); - - /* set ep0 directions */ - dev->ep[UDC_EP0IN_IX].in = 1; - dev->ep[UDC_EP0OUT_IX].in = 0; - - /* set buffer size (tx fifo entries) of EP0_IN */ - tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufin_framenum); - if (dev->gadget.speed == USB_SPEED_FULL) - tmp = AMD_ADDBITS(tmp, UDC_FS_EPIN0_BUFF_SIZE, - UDC_EPIN_BUFF_SIZE); - else if (dev->gadget.speed == USB_SPEED_HIGH) - tmp = AMD_ADDBITS(tmp, UDC_EPIN0_BUFF_SIZE, - UDC_EPIN_BUFF_SIZE); - writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufin_framenum); - - /* set max packet size of EP0_IN */ - tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt); - if (dev->gadget.speed == USB_SPEED_FULL) - tmp = AMD_ADDBITS(tmp, UDC_FS_EP0IN_MAX_PKT_SIZE, - UDC_EP_MAX_PKT_SIZE); - else if (dev->gadget.speed == USB_SPEED_HIGH) - tmp = AMD_ADDBITS(tmp, UDC_EP0IN_MAX_PKT_SIZE, - UDC_EP_MAX_PKT_SIZE); - writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt); - - /* set max packet size of EP0_OUT */ - tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt); - if (dev->gadget.speed == USB_SPEED_FULL) - tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE, - UDC_EP_MAX_PKT_SIZE); - else if (dev->gadget.speed == USB_SPEED_HIGH) - tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE, - UDC_EP_MAX_PKT_SIZE); - writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt); - - /* set max packet size of EP0 in UDC CSR */ - tmp = readl(&dev->csr->ne[0]); - if (dev->gadget.speed == USB_SPEED_FULL) - tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE, - UDC_CSR_NE_MAX_PKT); - else if (dev->gadget.speed == USB_SPEED_HIGH) - tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE, - UDC_CSR_NE_MAX_PKT); - writel(tmp, &dev->csr->ne[0]); - - if (use_dma) { - dev->ep[UDC_EP0OUT_IX].td->status |= - AMD_BIT(UDC_DMA_OUT_STS_L); - /* write dma desc address */ - writel(dev->ep[UDC_EP0OUT_IX].td_stp_dma, - &dev->ep[UDC_EP0OUT_IX].regs->subptr); - writel(dev->ep[UDC_EP0OUT_IX].td_phys, - &dev->ep[UDC_EP0OUT_IX].regs->desptr); - /* stop RDE timer */ - if (timer_pending(&udc_timer)) { - set_rde = 0; - mod_timer(&udc_timer, jiffies - 1); - } - /* stop pollstall timer */ - if (timer_pending(&udc_pollstall_timer)) - mod_timer(&udc_pollstall_timer, jiffies - 1); - /* enable DMA */ - tmp = readl(&dev->regs->ctl); - tmp |= AMD_BIT(UDC_DEVCTL_MODE) - | AMD_BIT(UDC_DEVCTL_RDE) - | AMD_BIT(UDC_DEVCTL_TDE); - if (use_dma_bufferfill_mode) - tmp |= AMD_BIT(UDC_DEVCTL_BF); - else if (use_dma_ppb_du) - tmp |= AMD_BIT(UDC_DEVCTL_DU); - writel(tmp, &dev->regs->ctl); - } - - /* clear NAK by writing CNAK for EP0IN */ - tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl); - tmp |= AMD_BIT(UDC_EPCTL_CNAK); - writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl); - dev->ep[UDC_EP0IN_IX].naking = 0; - UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX); - - /* clear NAK by writing CNAK for EP0OUT */ - tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl); - tmp |= AMD_BIT(UDC_EPCTL_CNAK); - writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl); - dev->ep[UDC_EP0OUT_IX].naking = 0; - UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX); -} - -/* Make endpoint 0 ready for control traffic */ -static int setup_ep0(struct udc *dev) -{ - activate_control_endpoints(dev); - /* enable ep0 interrupts */ - udc_enable_ep0_interrupts(dev); - /* enable device setup interrupts */ - udc_enable_dev_setup_interrupts(dev); - - return 0; -} - -/* Called by gadget driver to register itself */ -static int amd5536_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) -{ - struct udc *dev = udc; - int retval; - u32 tmp; - - if (!driver || !bind || !driver->setup - || driver->max_speed < USB_SPEED_HIGH) - return -EINVAL; - if (!dev) - return -ENODEV; - if (dev->driver) - return -EBUSY; - - driver->driver.bus = NULL; - dev->driver = driver; - dev->gadget.dev.driver = &driver->driver; - - retval = bind(&dev->gadget); - - /* Some gadget drivers use both ep0 directions. - * NOTE: to gadget driver, ep0 is just one endpoint... - */ - dev->ep[UDC_EP0OUT_IX].ep.driver_data = - dev->ep[UDC_EP0IN_IX].ep.driver_data; - - if (retval) { - DBG(dev, "binding to %s returning %d\n", - driver->driver.name, retval); - dev->driver = NULL; - dev->gadget.dev.driver = NULL; - return retval; - } - - /* get ready for ep0 traffic */ - setup_ep0(dev); - - /* clear SD */ - tmp = readl(&dev->regs->ctl); - tmp = tmp & AMD_CLEAR_BIT(UDC_DEVCTL_SD); - writel(tmp, &dev->regs->ctl); - - usb_connect(dev); - - return 0; -} - -/* shutdown requests and disconnect from gadget */ -static void -shutdown(struct udc *dev, struct usb_gadget_driver *driver) -__releases(dev->lock) -__acquires(dev->lock) -{ - int tmp; - - if (dev->gadget.speed != USB_SPEED_UNKNOWN) { - spin_unlock(&dev->lock); - driver->disconnect(&dev->gadget); - spin_lock(&dev->lock); - } - - /* empty queues and init hardware */ - udc_basic_init(dev); - for (tmp = 0; tmp < UDC_EP_NUM; tmp++) - empty_req_queue(&dev->ep[tmp]); - - udc_setup_endpoints(dev); -} - -/* Called by gadget driver to unregister itself */ -static int amd5536_stop(struct usb_gadget_driver *driver) -{ - struct udc *dev = udc; - unsigned long flags; - u32 tmp; - - if (!dev) - return -ENODEV; - if (!driver || driver != dev->driver || !driver->unbind) - return -EINVAL; - - spin_lock_irqsave(&dev->lock, flags); - udc_mask_unused_interrupts(dev); - shutdown(dev, driver); - spin_unlock_irqrestore(&dev->lock, flags); - - driver->unbind(&dev->gadget); - dev->gadget.dev.driver = NULL; - dev->driver = NULL; - - /* set SD */ - tmp = readl(&dev->regs->ctl); - tmp |= AMD_BIT(UDC_DEVCTL_SD); - writel(tmp, &dev->regs->ctl); - - - DBG(dev, "%s: unregistered\n", driver->driver.name); - - return 0; -} - -/* Clear pending NAK bits */ -static void udc_process_cnak_queue(struct udc *dev) -{ - u32 tmp; - u32 reg; - - /* check epin's */ - DBG(dev, "CNAK pending queue processing\n"); - for (tmp = 0; tmp < UDC_EPIN_NUM_USED; tmp++) { - if (cnak_pending & (1 << tmp)) { - DBG(dev, "CNAK pending for ep%d\n", tmp); - /* clear NAK by writing CNAK */ - reg = readl(&dev->ep[tmp].regs->ctl); - reg |= AMD_BIT(UDC_EPCTL_CNAK); - writel(reg, &dev->ep[tmp].regs->ctl); - dev->ep[tmp].naking = 0; - UDC_QUEUE_CNAK(&dev->ep[tmp], dev->ep[tmp].num); - } - } - /* ... and ep0out */ - if (cnak_pending & (1 << UDC_EP0OUT_IX)) { - DBG(dev, "CNAK pending for ep%d\n", UDC_EP0OUT_IX); - /* clear NAK by writing CNAK */ - reg = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl); - reg |= AMD_BIT(UDC_EPCTL_CNAK); - writel(reg, &dev->ep[UDC_EP0OUT_IX].regs->ctl); - dev->ep[UDC_EP0OUT_IX].naking = 0; - UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], - dev->ep[UDC_EP0OUT_IX].num); - } -} - -/* Enabling RX DMA after setup packet */ -static void udc_ep0_set_rde(struct udc *dev) -{ - if (use_dma) { - /* - * only enable RXDMA when no data endpoint enabled - * or data is queued - */ - if (!dev->data_ep_enabled || dev->data_ep_queued) { - udc_set_rde(dev); - } else { - /* - * setup timer for enabling RDE (to not enable - * RXFIFO DMA for data endpoints to early) - */ - if (set_rde != 0 && !timer_pending(&udc_timer)) { - udc_timer.expires = - jiffies + HZ/UDC_RDE_TIMER_DIV; - set_rde = 1; - if (!stop_timer) - add_timer(&udc_timer); - } - } - } -} - - -/* Interrupt handler for data OUT traffic */ -static irqreturn_t udc_data_out_isr(struct udc *dev, int ep_ix) -{ - irqreturn_t ret_val = IRQ_NONE; - u32 tmp; - struct udc_ep *ep; - struct udc_request *req; - unsigned int count; - struct udc_data_dma *td = NULL; - unsigned dma_done; - - VDBG(dev, "ep%d irq\n", ep_ix); - ep = &dev->ep[ep_ix]; - - tmp = readl(&ep->regs->sts); - if (use_dma) { - /* BNA event ? */ - if (tmp & AMD_BIT(UDC_EPSTS_BNA)) { - DBG(dev, "BNA ep%dout occurred - DESPTR = %x\n", - ep->num, readl(&ep->regs->desptr)); - /* clear BNA */ - writel(tmp | AMD_BIT(UDC_EPSTS_BNA), &ep->regs->sts); - if (!ep->cancel_transfer) - ep->bna_occurred = 1; - else - ep->cancel_transfer = 0; - ret_val = IRQ_HANDLED; - goto finished; - } - } - /* HE event ? */ - if (tmp & AMD_BIT(UDC_EPSTS_HE)) { - dev_err(&dev->pdev->dev, "HE ep%dout occurred\n", ep->num); - - /* clear HE */ - writel(tmp | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts); - ret_val = IRQ_HANDLED; - goto finished; - } - - if (!list_empty(&ep->queue)) { - - /* next request */ - req = list_entry(ep->queue.next, - struct udc_request, queue); - } else { - req = NULL; - udc_rxfifo_pending = 1; - } - VDBG(dev, "req = %p\n", req); - /* fifo mode */ - if (!use_dma) { - - /* read fifo */ - if (req && udc_rxfifo_read(ep, req)) { - ret_val = IRQ_HANDLED; - - /* finish */ - complete_req(ep, req, 0); - /* next request */ - if (!list_empty(&ep->queue) && !ep->halted) { - req = list_entry(ep->queue.next, - struct udc_request, queue); - } else - req = NULL; - } - - /* DMA */ - } else if (!ep->cancel_transfer && req != NULL) { - ret_val = IRQ_HANDLED; - - /* check for DMA done */ - if (!use_dma_ppb) { - dma_done = AMD_GETBITS(req->td_data->status, - UDC_DMA_OUT_STS_BS); - /* packet per buffer mode - rx bytes */ - } else { - /* - * if BNA occurred then recover desc. from - * BNA dummy desc. - */ - if (ep->bna_occurred) { - VDBG(dev, "Recover desc. from BNA dummy\n"); - memcpy(req->td_data, ep->bna_dummy_req->td_data, - sizeof(struct udc_data_dma)); - ep->bna_occurred = 0; - udc_init_bna_dummy(ep->req); - } - td = udc_get_last_dma_desc(req); - dma_done = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_BS); - } - if (dma_done == UDC_DMA_OUT_STS_BS_DMA_DONE) { - /* buffer fill mode - rx bytes */ - if (!use_dma_ppb) { - /* received number bytes */ - count = AMD_GETBITS(req->td_data->status, - UDC_DMA_OUT_STS_RXBYTES); - VDBG(dev, "rx bytes=%u\n", count); - /* packet per buffer mode - rx bytes */ - } else { - VDBG(dev, "req->td_data=%p\n", req->td_data); - VDBG(dev, "last desc = %p\n", td); - /* received number bytes */ - if (use_dma_ppb_du) { - /* every desc. counts bytes */ - count = udc_get_ppbdu_rxbytes(req); - } else { - /* last desc. counts bytes */ - count = AMD_GETBITS(td->status, - UDC_DMA_OUT_STS_RXBYTES); - if (!count && req->req.length - == UDC_DMA_MAXPACKET) { - /* - * on 64k packets the RXBYTES - * field is zero - */ - count = UDC_DMA_MAXPACKET; - } - } - VDBG(dev, "last desc rx bytes=%u\n", count); - } - - tmp = req->req.length - req->req.actual; - if (count > tmp) { - if ((tmp % ep->ep.maxpacket) != 0) { - DBG(dev, "%s: rx %db, space=%db\n", - ep->ep.name, count, tmp); - req->req.status = -EOVERFLOW; - } - count = tmp; - } - req->req.actual += count; - req->dma_going = 0; - /* complete request */ - complete_req(ep, req, 0); - - /* next request */ - if (!list_empty(&ep->queue) && !ep->halted) { - req = list_entry(ep->queue.next, - struct udc_request, - queue); - /* - * DMA may be already started by udc_queue() - * called by gadget drivers completion - * routine. This happens when queue - * holds one request only. - */ - if (req->dma_going == 0) { - /* next dma */ - if (prep_dma(ep, req, GFP_ATOMIC) != 0) - goto finished; - /* write desc pointer */ - writel(req->td_phys, - &ep->regs->desptr); - req->dma_going = 1; - /* enable DMA */ - udc_set_rde(dev); - } - } else { - /* - * implant BNA dummy descriptor to allow - * RXFIFO opening by RDE - */ - if (ep->bna_dummy_req) { - /* write desc pointer */ - writel(ep->bna_dummy_req->td_phys, - &ep->regs->desptr); - ep->bna_occurred = 0; - } - - /* - * schedule timer for setting RDE if queue - * remains empty to allow ep0 packets pass - * through - */ - if (set_rde != 0 - && !timer_pending(&udc_timer)) { - udc_timer.expires = - jiffies - + HZ*UDC_RDE_TIMER_SECONDS; - set_rde = 1; - if (!stop_timer) - add_timer(&udc_timer); - } - if (ep->num != UDC_EP0OUT_IX) - dev->data_ep_queued = 0; - } - - } else { - /* - * RX DMA must be reenabled for each desc in PPBDU mode - * and must be enabled for PPBNDU mode in case of BNA - */ - udc_set_rde(dev); - } - - } else if (ep->cancel_transfer) { - ret_val = IRQ_HANDLED; - ep->cancel_transfer = 0; - } - - /* check pending CNAKS */ - if (cnak_pending) { - /* CNAk processing when rxfifo empty only */ - if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) - udc_process_cnak_queue(dev); - } - - /* clear OUT bits in ep status */ - writel(UDC_EPSTS_OUT_CLEAR, &ep->regs->sts); -finished: - return ret_val; -} - -/* Interrupt handler for data IN traffic */ -static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix) -{ - irqreturn_t ret_val = IRQ_NONE; - u32 tmp; - u32 epsts; - struct udc_ep *ep; - struct udc_request *req; - struct udc_data_dma *td; - unsigned dma_done; - unsigned len; - - ep = &dev->ep[ep_ix]; - - epsts = readl(&ep->regs->sts); - if (use_dma) { - /* BNA ? */ - if (epsts & AMD_BIT(UDC_EPSTS_BNA)) { - dev_err(&dev->pdev->dev, - "BNA ep%din occurred - DESPTR = %08lx\n", - ep->num, - (unsigned long) readl(&ep->regs->desptr)); - - /* clear BNA */ - writel(epsts, &ep->regs->sts); - ret_val = IRQ_HANDLED; - goto finished; - } - } - /* HE event ? */ - if (epsts & AMD_BIT(UDC_EPSTS_HE)) { - dev_err(&dev->pdev->dev, - "HE ep%dn occurred - DESPTR = %08lx\n", - ep->num, (unsigned long) readl(&ep->regs->desptr)); - - /* clear HE */ - writel(epsts | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts); - ret_val = IRQ_HANDLED; - goto finished; - } - - /* DMA completion */ - if (epsts & AMD_BIT(UDC_EPSTS_TDC)) { - VDBG(dev, "TDC set- completion\n"); - ret_val = IRQ_HANDLED; - if (!ep->cancel_transfer && !list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, - struct udc_request, queue); - /* - * length bytes transferred - * check dma done of last desc. in PPBDU mode - */ - if (use_dma_ppb_du) { - td = udc_get_last_dma_desc(req); - if (td) { - dma_done = - AMD_GETBITS(td->status, - UDC_DMA_IN_STS_BS); - /* don't care DMA done */ - req->req.actual = req->req.length; - } - } else { - /* assume all bytes transferred */ - req->req.actual = req->req.length; - } - - if (req->req.actual == req->req.length) { - /* complete req */ - complete_req(ep, req, 0); - req->dma_going = 0; - /* further request available ? */ - if (list_empty(&ep->queue)) { - /* disable interrupt */ - tmp = readl(&dev->regs->ep_irqmsk); - tmp |= AMD_BIT(ep->num); - writel(tmp, &dev->regs->ep_irqmsk); - } - } - } - ep->cancel_transfer = 0; - - } - /* - * status reg has IN bit set and TDC not set (if TDC was handled, - * IN must not be handled (UDC defect) ? - */ - if ((epsts & AMD_BIT(UDC_EPSTS_IN)) - && !(epsts & AMD_BIT(UDC_EPSTS_TDC))) { - ret_val = IRQ_HANDLED; - if (!list_empty(&ep->queue)) { - /* next request */ - req = list_entry(ep->queue.next, - struct udc_request, queue); - /* FIFO mode */ - if (!use_dma) { - /* write fifo */ - udc_txfifo_write(ep, &req->req); - len = req->req.length - req->req.actual; - if (len > ep->ep.maxpacket) - len = ep->ep.maxpacket; - req->req.actual += len; - if (req->req.actual == req->req.length - || (len != ep->ep.maxpacket)) { - /* complete req */ - complete_req(ep, req, 0); - } - /* DMA */ - } else if (req && !req->dma_going) { - VDBG(dev, "IN DMA : req=%p req->td_data=%p\n", - req, req->td_data); - if (req->td_data) { - - req->dma_going = 1; - - /* - * unset L bit of first desc. - * for chain - */ - if (use_dma_ppb && req->req.length > - ep->ep.maxpacket) { - req->td_data->status &= - AMD_CLEAR_BIT( - UDC_DMA_IN_STS_L); - } - - /* write desc pointer */ - writel(req->td_phys, &ep->regs->desptr); - - /* set HOST READY */ - req->td_data->status = - AMD_ADDBITS( - req->td_data->status, - UDC_DMA_IN_STS_BS_HOST_READY, - UDC_DMA_IN_STS_BS); - - /* set poll demand bit */ - tmp = readl(&ep->regs->ctl); - tmp |= AMD_BIT(UDC_EPCTL_P); - writel(tmp, &ep->regs->ctl); - } - } - - } else if (!use_dma && ep->in) { - /* disable interrupt */ - tmp = readl( - &dev->regs->ep_irqmsk); - tmp |= AMD_BIT(ep->num); - writel(tmp, - &dev->regs->ep_irqmsk); - } - } - /* clear status bits */ - writel(epsts, &ep->regs->sts); - -finished: - return ret_val; - -} - -/* Interrupt handler for Control OUT traffic */ -static irqreturn_t udc_control_out_isr(struct udc *dev) -__releases(dev->lock) -__acquires(dev->lock) -{ - irqreturn_t ret_val = IRQ_NONE; - u32 tmp; - int setup_supported; - u32 count; - int set = 0; - struct udc_ep *ep; - struct udc_ep *ep_tmp; - - ep = &dev->ep[UDC_EP0OUT_IX]; - - /* clear irq */ - writel(AMD_BIT(UDC_EPINT_OUT_EP0), &dev->regs->ep_irqsts); - - tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts); - /* check BNA and clear if set */ - if (tmp & AMD_BIT(UDC_EPSTS_BNA)) { - VDBG(dev, "ep0: BNA set\n"); - writel(AMD_BIT(UDC_EPSTS_BNA), - &dev->ep[UDC_EP0OUT_IX].regs->sts); - ep->bna_occurred = 1; - ret_val = IRQ_HANDLED; - goto finished; - } - - /* type of data: SETUP or DATA 0 bytes */ - tmp = AMD_GETBITS(tmp, UDC_EPSTS_OUT); - VDBG(dev, "data_typ = %x\n", tmp); - - /* setup data */ - if (tmp == UDC_EPSTS_OUT_SETUP) { - ret_val = IRQ_HANDLED; - - ep->dev->stall_ep0in = 0; - dev->waiting_zlp_ack_ep0in = 0; - - /* set NAK for EP0_IN */ - tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl); - tmp |= AMD_BIT(UDC_EPCTL_SNAK); - writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl); - dev->ep[UDC_EP0IN_IX].naking = 1; - /* get setup data */ - if (use_dma) { - - /* clear OUT bits in ep status */ - writel(UDC_EPSTS_OUT_CLEAR, - &dev->ep[UDC_EP0OUT_IX].regs->sts); - - setup_data.data[0] = - dev->ep[UDC_EP0OUT_IX].td_stp->data12; - setup_data.data[1] = - dev->ep[UDC_EP0OUT_IX].td_stp->data34; - /* set HOST READY */ - dev->ep[UDC_EP0OUT_IX].td_stp->status = - UDC_DMA_STP_STS_BS_HOST_READY; - } else { - /* read fifo */ - udc_rxfifo_read_dwords(dev, setup_data.data, 2); - } - - /* determine direction of control data */ - if ((setup_data.request.bRequestType & USB_DIR_IN) != 0) { - dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep; - /* enable RDE */ - udc_ep0_set_rde(dev); - set = 0; - } else { - dev->gadget.ep0 = &dev->ep[UDC_EP0OUT_IX].ep; - /* - * implant BNA dummy descriptor to allow RXFIFO opening - * by RDE - */ - if (ep->bna_dummy_req) { - /* write desc pointer */ - writel(ep->bna_dummy_req->td_phys, - &dev->ep[UDC_EP0OUT_IX].regs->desptr); - ep->bna_occurred = 0; - } - - set = 1; - dev->ep[UDC_EP0OUT_IX].naking = 1; - /* - * setup timer for enabling RDE (to not enable - * RXFIFO DMA for data to early) - */ - set_rde = 1; - if (!timer_pending(&udc_timer)) { - udc_timer.expires = jiffies + - HZ/UDC_RDE_TIMER_DIV; - if (!stop_timer) - add_timer(&udc_timer); - } - } - - /* - * mass storage reset must be processed here because - * next packet may be a CLEAR_FEATURE HALT which would not - * clear the stall bit when no STALL handshake was received - * before (autostall can cause this) - */ - if (setup_data.data[0] == UDC_MSCRES_DWORD0 - && setup_data.data[1] == UDC_MSCRES_DWORD1) { - DBG(dev, "MSC Reset\n"); - /* - * clear stall bits - * only one IN and OUT endpoints are handled - */ - ep_tmp = &udc->ep[UDC_EPIN_IX]; - udc_set_halt(&ep_tmp->ep, 0); - ep_tmp = &udc->ep[UDC_EPOUT_IX]; - udc_set_halt(&ep_tmp->ep, 0); - } - - /* call gadget with setup data received */ - spin_unlock(&dev->lock); - setup_supported = dev->driver->setup(&dev->gadget, - &setup_data.request); - spin_lock(&dev->lock); - - tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl); - /* ep0 in returns data (not zlp) on IN phase */ - if (setup_supported >= 0 && setup_supported < - UDC_EP0IN_MAXPACKET) { - /* clear NAK by writing CNAK in EP0_IN */ - tmp |= AMD_BIT(UDC_EPCTL_CNAK); - writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl); - dev->ep[UDC_EP0IN_IX].naking = 0; - UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX); - - /* if unsupported request then stall */ - } else if (setup_supported < 0) { - tmp |= AMD_BIT(UDC_EPCTL_S); - writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl); - } else - dev->waiting_zlp_ack_ep0in = 1; - - - /* clear NAK by writing CNAK in EP0_OUT */ - if (!set) { - tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl); - tmp |= AMD_BIT(UDC_EPCTL_CNAK); - writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl); - dev->ep[UDC_EP0OUT_IX].naking = 0; - UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX); - } - - if (!use_dma) { - /* clear OUT bits in ep status */ - writel(UDC_EPSTS_OUT_CLEAR, - &dev->ep[UDC_EP0OUT_IX].regs->sts); - } - - /* data packet 0 bytes */ - } else if (tmp == UDC_EPSTS_OUT_DATA) { - /* clear OUT bits in ep status */ - writel(UDC_EPSTS_OUT_CLEAR, &dev->ep[UDC_EP0OUT_IX].regs->sts); - - /* get setup data: only 0 packet */ - if (use_dma) { - /* no req if 0 packet, just reactivate */ - if (list_empty(&dev->ep[UDC_EP0OUT_IX].queue)) { - VDBG(dev, "ZLP\n"); - - /* set HOST READY */ - dev->ep[UDC_EP0OUT_IX].td->status = - AMD_ADDBITS( - dev->ep[UDC_EP0OUT_IX].td->status, - UDC_DMA_OUT_STS_BS_HOST_READY, - UDC_DMA_OUT_STS_BS); - /* enable RDE */ - udc_ep0_set_rde(dev); - ret_val = IRQ_HANDLED; - - } else { - /* control write */ - ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX); - /* re-program desc. pointer for possible ZLPs */ - writel(dev->ep[UDC_EP0OUT_IX].td_phys, - &dev->ep[UDC_EP0OUT_IX].regs->desptr); - /* enable RDE */ - udc_ep0_set_rde(dev); - } - } else { - - /* received number bytes */ - count = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts); - count = AMD_GETBITS(count, UDC_EPSTS_RX_PKT_SIZE); - /* out data for fifo mode not working */ - count = 0; - - /* 0 packet or real data ? */ - if (count != 0) { - ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX); - } else { - /* dummy read confirm */ - readl(&dev->ep[UDC_EP0OUT_IX].regs->confirm); - ret_val = IRQ_HANDLED; - } - } - } - - /* check pending CNAKS */ - if (cnak_pending) { - /* CNAk processing when rxfifo empty only */ - if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) - udc_process_cnak_queue(dev); - } - -finished: - return ret_val; -} - -/* Interrupt handler for Control IN traffic */ -static irqreturn_t udc_control_in_isr(struct udc *dev) -{ - irqreturn_t ret_val = IRQ_NONE; - u32 tmp; - struct udc_ep *ep; - struct udc_request *req; - unsigned len; - - ep = &dev->ep[UDC_EP0IN_IX]; - - /* clear irq */ - writel(AMD_BIT(UDC_EPINT_IN_EP0), &dev->regs->ep_irqsts); - - tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->sts); - /* DMA completion */ - if (tmp & AMD_BIT(UDC_EPSTS_TDC)) { - VDBG(dev, "isr: TDC clear\n"); - ret_val = IRQ_HANDLED; - - /* clear TDC bit */ - writel(AMD_BIT(UDC_EPSTS_TDC), - &dev->ep[UDC_EP0IN_IX].regs->sts); - - /* status reg has IN bit set ? */ - } else if (tmp & AMD_BIT(UDC_EPSTS_IN)) { - ret_val = IRQ_HANDLED; - - if (ep->dma) { - /* clear IN bit */ - writel(AMD_BIT(UDC_EPSTS_IN), - &dev->ep[UDC_EP0IN_IX].regs->sts); - } - if (dev->stall_ep0in) { - DBG(dev, "stall ep0in\n"); - /* halt ep0in */ - tmp = readl(&ep->regs->ctl); - tmp |= AMD_BIT(UDC_EPCTL_S); - writel(tmp, &ep->regs->ctl); - } else { - if (!list_empty(&ep->queue)) { - /* next request */ - req = list_entry(ep->queue.next, - struct udc_request, queue); - - if (ep->dma) { - /* write desc pointer */ - writel(req->td_phys, &ep->regs->desptr); - /* set HOST READY */ - req->td_data->status = - AMD_ADDBITS( - req->td_data->status, - UDC_DMA_STP_STS_BS_HOST_READY, - UDC_DMA_STP_STS_BS); - - /* set poll demand bit */ - tmp = - readl(&dev->ep[UDC_EP0IN_IX].regs->ctl); - tmp |= AMD_BIT(UDC_EPCTL_P); - writel(tmp, - &dev->ep[UDC_EP0IN_IX].regs->ctl); - - /* all bytes will be transferred */ - req->req.actual = req->req.length; - - /* complete req */ - complete_req(ep, req, 0); - - } else { - /* write fifo */ - udc_txfifo_write(ep, &req->req); - - /* lengh bytes transferred */ - len = req->req.length - req->req.actual; - if (len > ep->ep.maxpacket) - len = ep->ep.maxpacket; - - req->req.actual += len; - if (req->req.actual == req->req.length - || (len != ep->ep.maxpacket)) { - /* complete req */ - complete_req(ep, req, 0); - } - } - - } - } - ep->halted = 0; - dev->stall_ep0in = 0; - if (!ep->dma) { - /* clear IN bit */ - writel(AMD_BIT(UDC_EPSTS_IN), - &dev->ep[UDC_EP0IN_IX].regs->sts); - } - } - - return ret_val; -} - - -/* Interrupt handler for global device events */ -static irqreturn_t udc_dev_isr(struct udc *dev, u32 dev_irq) -__releases(dev->lock) -__acquires(dev->lock) -{ - irqreturn_t ret_val = IRQ_NONE; - u32 tmp; - u32 cfg; - struct udc_ep *ep; - u16 i; - u8 udc_csr_epix; - - /* SET_CONFIG irq ? */ - if (dev_irq & AMD_BIT(UDC_DEVINT_SC)) { - ret_val = IRQ_HANDLED; - - /* read config value */ - tmp = readl(&dev->regs->sts); - cfg = AMD_GETBITS(tmp, UDC_DEVSTS_CFG); - DBG(dev, "SET_CONFIG interrupt: config=%d\n", cfg); - dev->cur_config = cfg; - dev->set_cfg_not_acked = 1; - - /* make usb request for gadget driver */ - memset(&setup_data, 0 , sizeof(union udc_setup_data)); - setup_data.request.bRequest = USB_REQ_SET_CONFIGURATION; - setup_data.request.wValue = cpu_to_le16(dev->cur_config); - - /* programm the NE registers */ - for (i = 0; i < UDC_EP_NUM; i++) { - ep = &dev->ep[i]; - if (ep->in) { - - /* ep ix in UDC CSR register space */ - udc_csr_epix = ep->num; - - - /* OUT ep */ - } else { - /* ep ix in UDC CSR register space */ - udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS; - } - - tmp = readl(&dev->csr->ne[udc_csr_epix]); - /* ep cfg */ - tmp = AMD_ADDBITS(tmp, ep->dev->cur_config, - UDC_CSR_NE_CFG); - /* write reg */ - writel(tmp, &dev->csr->ne[udc_csr_epix]); - - /* clear stall bits */ - ep->halted = 0; - tmp = readl(&ep->regs->ctl); - tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S); - writel(tmp, &ep->regs->ctl); - } - /* call gadget zero with setup data received */ - spin_unlock(&dev->lock); - tmp = dev->driver->setup(&dev->gadget, &setup_data.request); - spin_lock(&dev->lock); - - } /* SET_INTERFACE ? */ - if (dev_irq & AMD_BIT(UDC_DEVINT_SI)) { - ret_val = IRQ_HANDLED; - - dev->set_cfg_not_acked = 1; - /* read interface and alt setting values */ - tmp = readl(&dev->regs->sts); - dev->cur_alt = AMD_GETBITS(tmp, UDC_DEVSTS_ALT); - dev->cur_intf = AMD_GETBITS(tmp, UDC_DEVSTS_INTF); - - /* make usb request for gadget driver */ - memset(&setup_data, 0 , sizeof(union udc_setup_data)); - setup_data.request.bRequest = USB_REQ_SET_INTERFACE; - setup_data.request.bRequestType = USB_RECIP_INTERFACE; - setup_data.request.wValue = cpu_to_le16(dev->cur_alt); - setup_data.request.wIndex = cpu_to_le16(dev->cur_intf); - - DBG(dev, "SET_INTERFACE interrupt: alt=%d intf=%d\n", - dev->cur_alt, dev->cur_intf); - - /* programm the NE registers */ - for (i = 0; i < UDC_EP_NUM; i++) { - ep = &dev->ep[i]; - if (ep->in) { - - /* ep ix in UDC CSR register space */ - udc_csr_epix = ep->num; - - - /* OUT ep */ - } else { - /* ep ix in UDC CSR register space */ - udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS; - } - - /* UDC CSR reg */ - /* set ep values */ - tmp = readl(&dev->csr->ne[udc_csr_epix]); - /* ep interface */ - tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf, - UDC_CSR_NE_INTF); - /* tmp = AMD_ADDBITS(tmp, 2, UDC_CSR_NE_INTF); */ - /* ep alt */ - tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt, - UDC_CSR_NE_ALT); - /* write reg */ - writel(tmp, &dev->csr->ne[udc_csr_epix]); - - /* clear stall bits */ - ep->halted = 0; - tmp = readl(&ep->regs->ctl); - tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S); - writel(tmp, &ep->regs->ctl); - } - - /* call gadget zero with setup data received */ - spin_unlock(&dev->lock); - tmp = dev->driver->setup(&dev->gadget, &setup_data.request); - spin_lock(&dev->lock); - - } /* USB reset */ - if (dev_irq & AMD_BIT(UDC_DEVINT_UR)) { - DBG(dev, "USB Reset interrupt\n"); - ret_val = IRQ_HANDLED; - - /* allow soft reset when suspend occurs */ - soft_reset_occured = 0; - - dev->waiting_zlp_ack_ep0in = 0; - dev->set_cfg_not_acked = 0; - - /* mask not needed interrupts */ - udc_mask_unused_interrupts(dev); - - /* call gadget to resume and reset configs etc. */ - spin_unlock(&dev->lock); - if (dev->sys_suspended && dev->driver->resume) { - dev->driver->resume(&dev->gadget); - dev->sys_suspended = 0; - } - dev->driver->disconnect(&dev->gadget); - spin_lock(&dev->lock); - - /* disable ep0 to empty req queue */ - empty_req_queue(&dev->ep[UDC_EP0IN_IX]); - ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]); - - /* soft reset when rxfifo not empty */ - tmp = readl(&dev->regs->sts); - if (!(tmp & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) - && !soft_reset_after_usbreset_occured) { - udc_soft_reset(dev); - soft_reset_after_usbreset_occured++; - } - - /* - * DMA reset to kill potential old DMA hw hang, - * POLL bit is already reset by ep_init() through - * disconnect() - */ - DBG(dev, "DMA machine reset\n"); - tmp = readl(&dev->regs->cfg); - writel(tmp | AMD_BIT(UDC_DEVCFG_DMARST), &dev->regs->cfg); - writel(tmp, &dev->regs->cfg); - - /* put into initial config */ - udc_basic_init(dev); - - /* enable device setup interrupts */ - udc_enable_dev_setup_interrupts(dev); - - /* enable suspend interrupt */ - tmp = readl(&dev->regs->irqmsk); - tmp &= AMD_UNMASK_BIT(UDC_DEVINT_US); - writel(tmp, &dev->regs->irqmsk); - - } /* USB suspend */ - if (dev_irq & AMD_BIT(UDC_DEVINT_US)) { - DBG(dev, "USB Suspend interrupt\n"); - ret_val = IRQ_HANDLED; - if (dev->driver->suspend) { - spin_unlock(&dev->lock); - dev->sys_suspended = 1; - dev->driver->suspend(&dev->gadget); - spin_lock(&dev->lock); - } - } /* new speed ? */ - if (dev_irq & AMD_BIT(UDC_DEVINT_ENUM)) { - DBG(dev, "ENUM interrupt\n"); - ret_val = IRQ_HANDLED; - soft_reset_after_usbreset_occured = 0; - - /* disable ep0 to empty req queue */ - empty_req_queue(&dev->ep[UDC_EP0IN_IX]); - ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]); - - /* link up all endpoints */ - udc_setup_endpoints(dev); - dev_info(&dev->pdev->dev, "Connect: %s\n", - usb_speed_string(dev->gadget.speed)); - - /* init ep 0 */ - activate_control_endpoints(dev); - - /* enable ep0 interrupts */ - udc_enable_ep0_interrupts(dev); - } - /* session valid change interrupt */ - if (dev_irq & AMD_BIT(UDC_DEVINT_SVC)) { - DBG(dev, "USB SVC interrupt\n"); - ret_val = IRQ_HANDLED; - - /* check that session is not valid to detect disconnect */ - tmp = readl(&dev->regs->sts); - if (!(tmp & AMD_BIT(UDC_DEVSTS_SESSVLD))) { - /* disable suspend interrupt */ - tmp = readl(&dev->regs->irqmsk); - tmp |= AMD_BIT(UDC_DEVINT_US); - writel(tmp, &dev->regs->irqmsk); - DBG(dev, "USB Disconnect (session valid low)\n"); - /* cleanup on disconnect */ - usb_disconnect(udc); - } - - } - - return ret_val; -} - -/* Interrupt Service Routine, see Linux Kernel Doc for parameters */ -static irqreturn_t udc_irq(int irq, void *pdev) -{ - struct udc *dev = pdev; - u32 reg; - u16 i; - u32 ep_irq; - irqreturn_t ret_val = IRQ_NONE; - - spin_lock(&dev->lock); - - /* check for ep irq */ - reg = readl(&dev->regs->ep_irqsts); - if (reg) { - if (reg & AMD_BIT(UDC_EPINT_OUT_EP0)) - ret_val |= udc_control_out_isr(dev); - if (reg & AMD_BIT(UDC_EPINT_IN_EP0)) - ret_val |= udc_control_in_isr(dev); - - /* - * data endpoint - * iterate ep's - */ - for (i = 1; i < UDC_EP_NUM; i++) { - ep_irq = 1 << i; - if (!(reg & ep_irq) || i == UDC_EPINT_OUT_EP0) - continue; - - /* clear irq status */ - writel(ep_irq, &dev->regs->ep_irqsts); - - /* irq for out ep ? */ - if (i > UDC_EPIN_NUM) - ret_val |= udc_data_out_isr(dev, i); - else - ret_val |= udc_data_in_isr(dev, i); - } - - } - - - /* check for dev irq */ - reg = readl(&dev->regs->irqsts); - if (reg) { - /* clear irq */ - writel(reg, &dev->regs->irqsts); - ret_val |= udc_dev_isr(dev, reg); - } - - - spin_unlock(&dev->lock); - return ret_val; -} - -/* Tears down device */ -static void gadget_release(struct device *pdev) -{ - struct amd5536udc *dev = dev_get_drvdata(pdev); - kfree(dev); -} - -/* Cleanup on device remove */ -static void udc_remove(struct udc *dev) -{ - /* remove timer */ - stop_timer++; - if (timer_pending(&udc_timer)) - wait_for_completion(&on_exit); - if (udc_timer.data) - del_timer_sync(&udc_timer); - /* remove pollstall timer */ - stop_pollstall_timer++; - if (timer_pending(&udc_pollstall_timer)) - wait_for_completion(&on_pollstall_exit); - if (udc_pollstall_timer.data) - del_timer_sync(&udc_pollstall_timer); - udc = NULL; -} - -/* Reset all pci context */ -static void udc_pci_remove(struct pci_dev *pdev) -{ - struct udc *dev; - - dev = pci_get_drvdata(pdev); - - usb_del_gadget_udc(&udc->gadget); - /* gadget driver must not be registered */ - BUG_ON(dev->driver != NULL); - - /* dma pool cleanup */ - if (dev->data_requests) - pci_pool_destroy(dev->data_requests); - - if (dev->stp_requests) { - /* cleanup DMA desc's for ep0in */ - pci_pool_free(dev->stp_requests, - dev->ep[UDC_EP0OUT_IX].td_stp, - dev->ep[UDC_EP0OUT_IX].td_stp_dma); - pci_pool_free(dev->stp_requests, - dev->ep[UDC_EP0OUT_IX].td, - dev->ep[UDC_EP0OUT_IX].td_phys); - - pci_pool_destroy(dev->stp_requests); - } - - /* reset controller */ - writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg); - if (dev->irq_registered) - free_irq(pdev->irq, dev); - if (dev->regs) - iounmap(dev->regs); - if (dev->mem_region) - release_mem_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - if (dev->active) - pci_disable_device(pdev); - - device_unregister(&dev->gadget.dev); - pci_set_drvdata(pdev, NULL); - - udc_remove(dev); -} - -/* create dma pools on init */ -static int init_dma_pools(struct udc *dev) -{ - struct udc_stp_dma *td_stp; - struct udc_data_dma *td_data; - int retval; - - /* consistent DMA mode setting ? */ - if (use_dma_ppb) { - use_dma_bufferfill_mode = 0; - } else { - use_dma_ppb_du = 0; - use_dma_bufferfill_mode = 1; - } - - /* DMA setup */ - dev->data_requests = dma_pool_create("data_requests", NULL, - sizeof(struct udc_data_dma), 0, 0); - if (!dev->data_requests) { - DBG(dev, "can't get request data pool\n"); - retval = -ENOMEM; - goto finished; - } - - /* EP0 in dma regs = dev control regs */ - dev->ep[UDC_EP0IN_IX].dma = &dev->regs->ctl; - - /* dma desc for setup data */ - dev->stp_requests = dma_pool_create("setup requests", NULL, - sizeof(struct udc_stp_dma), 0, 0); - if (!dev->stp_requests) { - DBG(dev, "can't get stp request pool\n"); - retval = -ENOMEM; - goto finished; - } - /* setup */ - td_stp = dma_pool_alloc(dev->stp_requests, GFP_KERNEL, - &dev->ep[UDC_EP0OUT_IX].td_stp_dma); - if (td_stp == NULL) { - retval = -ENOMEM; - goto finished; - } - dev->ep[UDC_EP0OUT_IX].td_stp = td_stp; - - /* data: 0 packets !? */ - td_data = dma_pool_alloc(dev->stp_requests, GFP_KERNEL, - &dev->ep[UDC_EP0OUT_IX].td_phys); - if (td_data == NULL) { - retval = -ENOMEM; - goto finished; - } - dev->ep[UDC_EP0OUT_IX].td = td_data; - return 0; - -finished: - return retval; -} - -/* Called by pci bus driver to init pci context */ -static int udc_pci_probe( - struct pci_dev *pdev, - const struct pci_device_id *id -) -{ - struct udc *dev; - unsigned long resource; - unsigned long len; - int retval = 0; - - /* one udc only */ - if (udc) { - dev_dbg(&pdev->dev, "already probed\n"); - return -EBUSY; - } - - /* init */ - dev = kzalloc(sizeof(struct udc), GFP_KERNEL); - if (!dev) { - retval = -ENOMEM; - goto finished; - } - - /* pci setup */ - if (pci_enable_device(pdev) < 0) { - kfree(dev); - dev = NULL; - retval = -ENODEV; - goto finished; - } - dev->active = 1; - - /* PCI resource allocation */ - resource = pci_resource_start(pdev, 0); - len = pci_resource_len(pdev, 0); - - if (!request_mem_region(resource, len, name)) { - dev_dbg(&pdev->dev, "pci device used already\n"); - kfree(dev); - dev = NULL; - retval = -EBUSY; - goto finished; - } - dev->mem_region = 1; - - dev->virt_addr = ioremap_nocache(resource, len); - if (dev->virt_addr == NULL) { - dev_dbg(&pdev->dev, "start address cannot be mapped\n"); - kfree(dev); - dev = NULL; - retval = -EFAULT; - goto finished; - } - - if (!pdev->irq) { - dev_err(&dev->pdev->dev, "irq not set\n"); - kfree(dev); - dev = NULL; - retval = -ENODEV; - goto finished; - } - - spin_lock_init(&dev->lock); - /* udc csr registers base */ - dev->csr = dev->virt_addr + UDC_CSR_ADDR; - /* dev registers base */ - dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR; - /* ep registers base */ - dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR; - /* fifo's base */ - dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR); - dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR); - - if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) { - dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq); - kfree(dev); - dev = NULL; - retval = -EBUSY; - goto finished; - } - dev->irq_registered = 1; - - pci_set_drvdata(pdev, dev); - - /* chip revision for Hs AMD5536 */ - dev->chiprev = pdev->revision; - - pci_set_master(pdev); - pci_try_set_mwi(pdev); - - /* init dma pools */ - if (use_dma) { - retval = init_dma_pools(dev); - if (retval != 0) - goto finished; - } - - dev->phys_addr = resource; - dev->irq = pdev->irq; - dev->pdev = pdev; - dev->gadget.dev.parent = &pdev->dev; - dev->gadget.dev.dma_mask = pdev->dev.dma_mask; - - /* general probing */ - if (udc_probe(dev) == 0) - return 0; - -finished: - if (dev) - udc_pci_remove(pdev); - return retval; -} - -/* general probe */ -static int udc_probe(struct udc *dev) -{ - char tmp[128]; - u32 reg; - int retval; - - /* mark timer as not initialized */ - udc_timer.data = 0; - udc_pollstall_timer.data = 0; - - /* device struct setup */ - dev->gadget.ops = &udc_ops; - - dev_set_name(&dev->gadget.dev, "gadget"); - dev->gadget.dev.release = gadget_release; - dev->gadget.name = name; - dev->gadget.max_speed = USB_SPEED_HIGH; - - /* init registers, interrupts, ... */ - startup_registers(dev); - - dev_info(&dev->pdev->dev, "%s\n", mod_desc); - - snprintf(tmp, sizeof tmp, "%d", dev->irq); - dev_info(&dev->pdev->dev, - "irq %s, pci mem %08lx, chip rev %02x(Geode5536 %s)\n", - tmp, dev->phys_addr, dev->chiprev, - (dev->chiprev == UDC_HSA0_REV) ? "A0" : "B1"); - strcpy(tmp, UDC_DRIVER_VERSION_STRING); - if (dev->chiprev == UDC_HSA0_REV) { - dev_err(&dev->pdev->dev, "chip revision is A0; too old\n"); - retval = -ENODEV; - goto finished; - } - dev_info(&dev->pdev->dev, - "driver version: %s(for Geode5536 B1)\n", tmp); - udc = dev; - - retval = usb_add_gadget_udc(&udc->pdev->dev, &dev->gadget); - if (retval) - goto finished; - - retval = device_register(&dev->gadget.dev); - if (retval) { - usb_del_gadget_udc(&dev->gadget); - put_device(&dev->gadget.dev); - goto finished; - } - - /* timer init */ - init_timer(&udc_timer); - udc_timer.function = udc_timer_function; - udc_timer.data = 1; - /* timer pollstall init */ - init_timer(&udc_pollstall_timer); - udc_pollstall_timer.function = udc_pollstall_timer_function; - udc_pollstall_timer.data = 1; - - /* set SD */ - reg = readl(&dev->regs->ctl); - reg |= AMD_BIT(UDC_DEVCTL_SD); - writel(reg, &dev->regs->ctl); - - /* print dev register info */ - print_regs(dev); - - return 0; - -finished: - return retval; -} - -/* Initiates a remote wakeup */ -static int udc_remote_wakeup(struct udc *dev) -{ - unsigned long flags; - u32 tmp; - - DBG(dev, "UDC initiates remote wakeup\n"); - - spin_lock_irqsave(&dev->lock, flags); - - tmp = readl(&dev->regs->ctl); - tmp |= AMD_BIT(UDC_DEVCTL_RES); - writel(tmp, &dev->regs->ctl); - tmp &= AMD_CLEAR_BIT(UDC_DEVCTL_RES); - writel(tmp, &dev->regs->ctl); - - spin_unlock_irqrestore(&dev->lock, flags); - return 0; -} - -/* PCI device parameters */ -static DEFINE_PCI_DEVICE_TABLE(pci_id) = { - { - PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x2096), - .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe, - .class_mask = 0xffffffff, - }, - {}, -}; -MODULE_DEVICE_TABLE(pci, pci_id); - -/* PCI functions */ -static struct pci_driver udc_pci_driver = { - .name = (char *) name, - .id_table = pci_id, - .probe = udc_pci_probe, - .remove = udc_pci_remove, -}; - -/* Inits driver */ -static int __init init(void) -{ - return pci_register_driver(&udc_pci_driver); -} -module_init(init); - -/* Cleans driver */ -static void __exit cleanup(void) -{ - pci_unregister_driver(&udc_pci_driver); -} -module_exit(cleanup); - -MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION); -MODULE_AUTHOR("Thomas Dahlmann"); -MODULE_LICENSE("GPL"); - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/amd5536udc.h b/ANDROID_3.4.5/drivers/usb/gadget/amd5536udc.h deleted file mode 100644 index f87e29c6..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/amd5536udc.h +++ /dev/null @@ -1,617 +0,0 @@ -/* - * amd5536.h -- header for AMD 5536 UDC high/full speed USB device controller - * - * Copyright (C) 2007 AMD (http://www.amd.com) - * Author: Thomas Dahlmann - * - * 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. - */ - -#ifndef AMD5536UDC_H -#define AMD5536UDC_H - -/* various constants */ -#define UDC_RDE_TIMER_SECONDS 1 -#define UDC_RDE_TIMER_DIV 10 -#define UDC_POLLSTALL_TIMER_USECONDS 500 - -/* Hs AMD5536 chip rev. */ -#define UDC_HSA0_REV 1 -#define UDC_HSB1_REV 2 - -/* - * SETUP usb commands - * needed, because some SETUP's are handled in hw, but must be passed to - * gadget driver above - * SET_CONFIG - */ -#define UDC_SETCONFIG_DWORD0 0x00000900 -#define UDC_SETCONFIG_DWORD0_VALUE_MASK 0xffff0000 -#define UDC_SETCONFIG_DWORD0_VALUE_OFS 16 - -#define UDC_SETCONFIG_DWORD1 0x00000000 - -/* SET_INTERFACE */ -#define UDC_SETINTF_DWORD0 0x00000b00 -#define UDC_SETINTF_DWORD0_ALT_MASK 0xffff0000 -#define UDC_SETINTF_DWORD0_ALT_OFS 16 - -#define UDC_SETINTF_DWORD1 0x00000000 -#define UDC_SETINTF_DWORD1_INTF_MASK 0x0000ffff -#define UDC_SETINTF_DWORD1_INTF_OFS 0 - -/* Mass storage reset */ -#define UDC_MSCRES_DWORD0 0x0000ff21 -#define UDC_MSCRES_DWORD1 0x00000000 - -/* Global CSR's -------------------------------------------------------------*/ -#define UDC_CSR_ADDR 0x500 - -/* EP NE bits */ -/* EP number */ -#define UDC_CSR_NE_NUM_MASK 0x0000000f -#define UDC_CSR_NE_NUM_OFS 0 -/* EP direction */ -#define UDC_CSR_NE_DIR_MASK 0x00000010 -#define UDC_CSR_NE_DIR_OFS 4 -/* EP type */ -#define UDC_CSR_NE_TYPE_MASK 0x00000060 -#define UDC_CSR_NE_TYPE_OFS 5 -/* EP config number */ -#define UDC_CSR_NE_CFG_MASK 0x00000780 -#define UDC_CSR_NE_CFG_OFS 7 -/* EP interface number */ -#define UDC_CSR_NE_INTF_MASK 0x00007800 -#define UDC_CSR_NE_INTF_OFS 11 -/* EP alt setting */ -#define UDC_CSR_NE_ALT_MASK 0x00078000 -#define UDC_CSR_NE_ALT_OFS 15 - -/* max pkt */ -#define UDC_CSR_NE_MAX_PKT_MASK 0x3ff80000 -#define UDC_CSR_NE_MAX_PKT_OFS 19 - -/* Device Config Register ---------------------------------------------------*/ -#define UDC_DEVCFG_ADDR 0x400 - -#define UDC_DEVCFG_SOFTRESET 31 -#define UDC_DEVCFG_HNPSFEN 30 -#define UDC_DEVCFG_DMARST 29 -#define UDC_DEVCFG_SET_DESC 18 -#define UDC_DEVCFG_CSR_PRG 17 -#define UDC_DEVCFG_STATUS 7 -#define UDC_DEVCFG_DIR 6 -#define UDC_DEVCFG_PI 5 -#define UDC_DEVCFG_SS 4 -#define UDC_DEVCFG_SP 3 -#define UDC_DEVCFG_RWKP 2 - -#define UDC_DEVCFG_SPD_MASK 0x3 -#define UDC_DEVCFG_SPD_OFS 0 -#define UDC_DEVCFG_SPD_HS 0x0 -#define UDC_DEVCFG_SPD_FS 0x1 -#define UDC_DEVCFG_SPD_LS 0x2 -/*#define UDC_DEVCFG_SPD_FS 0x3*/ - - -/* Device Control Register --------------------------------------------------*/ -#define UDC_DEVCTL_ADDR 0x404 - -#define UDC_DEVCTL_THLEN_MASK 0xff000000 -#define UDC_DEVCTL_THLEN_OFS 24 - -#define UDC_DEVCTL_BRLEN_MASK 0x00ff0000 -#define UDC_DEVCTL_BRLEN_OFS 16 - -#define UDC_DEVCTL_CSR_DONE 13 -#define UDC_DEVCTL_DEVNAK 12 -#define UDC_DEVCTL_SD 10 -#define UDC_DEVCTL_MODE 9 -#define UDC_DEVCTL_BREN 8 -#define UDC_DEVCTL_THE 7 -#define UDC_DEVCTL_BF 6 -#define UDC_DEVCTL_BE 5 -#define UDC_DEVCTL_DU 4 -#define UDC_DEVCTL_TDE 3 -#define UDC_DEVCTL_RDE 2 -#define UDC_DEVCTL_RES 0 - - -/* Device Status Register ---------------------------------------------------*/ -#define UDC_DEVSTS_ADDR 0x408 - -#define UDC_DEVSTS_TS_MASK 0xfffc0000 -#define UDC_DEVSTS_TS_OFS 18 - -#define UDC_DEVSTS_SESSVLD 17 -#define UDC_DEVSTS_PHY_ERROR 16 -#define UDC_DEVSTS_RXFIFO_EMPTY 15 - -#define UDC_DEVSTS_ENUM_SPEED_MASK 0x00006000 -#define UDC_DEVSTS_ENUM_SPEED_OFS 13 -#define UDC_DEVSTS_ENUM_SPEED_FULL 1 -#define UDC_DEVSTS_ENUM_SPEED_HIGH 0 - -#define UDC_DEVSTS_SUSP 12 - -#define UDC_DEVSTS_ALT_MASK 0x00000f00 -#define UDC_DEVSTS_ALT_OFS 8 - -#define UDC_DEVSTS_INTF_MASK 0x000000f0 -#define UDC_DEVSTS_INTF_OFS 4 - -#define UDC_DEVSTS_CFG_MASK 0x0000000f -#define UDC_DEVSTS_CFG_OFS 0 - - -/* Device Interrupt Register ------------------------------------------------*/ -#define UDC_DEVINT_ADDR 0x40c - -#define UDC_DEVINT_SVC 7 -#define UDC_DEVINT_ENUM 6 -#define UDC_DEVINT_SOF 5 -#define UDC_DEVINT_US 4 -#define UDC_DEVINT_UR 3 -#define UDC_DEVINT_ES 2 -#define UDC_DEVINT_SI 1 -#define UDC_DEVINT_SC 0 - -/* Device Interrupt Mask Register -------------------------------------------*/ -#define UDC_DEVINT_MSK_ADDR 0x410 - -#define UDC_DEVINT_MSK 0x7f - -/* Endpoint Interrupt Register ----------------------------------------------*/ -#define UDC_EPINT_ADDR 0x414 - -#define UDC_EPINT_OUT_MASK 0xffff0000 -#define UDC_EPINT_OUT_OFS 16 -#define UDC_EPINT_IN_MASK 0x0000ffff -#define UDC_EPINT_IN_OFS 0 - -#define UDC_EPINT_IN_EP0 0 -#define UDC_EPINT_IN_EP1 1 -#define UDC_EPINT_IN_EP2 2 -#define UDC_EPINT_IN_EP3 3 -#define UDC_EPINT_OUT_EP0 16 -#define UDC_EPINT_OUT_EP1 17 -#define UDC_EPINT_OUT_EP2 18 -#define UDC_EPINT_OUT_EP3 19 - -#define UDC_EPINT_EP0_ENABLE_MSK 0x001e001e - -/* Endpoint Interrupt Mask Register -----------------------------------------*/ -#define UDC_EPINT_MSK_ADDR 0x418 - -#define UDC_EPINT_OUT_MSK_MASK 0xffff0000 -#define UDC_EPINT_OUT_MSK_OFS 16 -#define UDC_EPINT_IN_MSK_MASK 0x0000ffff -#define UDC_EPINT_IN_MSK_OFS 0 - -#define UDC_EPINT_MSK_DISABLE_ALL 0xffffffff -/* mask non-EP0 endpoints */ -#define UDC_EPDATAINT_MSK_DISABLE 0xfffefffe -/* mask all dev interrupts */ -#define UDC_DEV_MSK_DISABLE 0x7f - -/* Endpoint-specific CSR's --------------------------------------------------*/ -#define UDC_EPREGS_ADDR 0x0 -#define UDC_EPIN_REGS_ADDR 0x0 -#define UDC_EPOUT_REGS_ADDR 0x200 - -#define UDC_EPCTL_ADDR 0x0 - -#define UDC_EPCTL_RRDY 9 -#define UDC_EPCTL_CNAK 8 -#define UDC_EPCTL_SNAK 7 -#define UDC_EPCTL_NAK 6 - -#define UDC_EPCTL_ET_MASK 0x00000030 -#define UDC_EPCTL_ET_OFS 4 -#define UDC_EPCTL_ET_CONTROL 0 -#define UDC_EPCTL_ET_ISO 1 -#define UDC_EPCTL_ET_BULK 2 -#define UDC_EPCTL_ET_INTERRUPT 3 - -#define UDC_EPCTL_P 3 -#define UDC_EPCTL_SN 2 -#define UDC_EPCTL_F 1 -#define UDC_EPCTL_S 0 - -/* Endpoint Status Registers ------------------------------------------------*/ -#define UDC_EPSTS_ADDR 0x4 - -#define UDC_EPSTS_RX_PKT_SIZE_MASK 0x007ff800 -#define UDC_EPSTS_RX_PKT_SIZE_OFS 11 - -#define UDC_EPSTS_TDC 10 -#define UDC_EPSTS_HE 9 -#define UDC_EPSTS_BNA 7 -#define UDC_EPSTS_IN 6 - -#define UDC_EPSTS_OUT_MASK 0x00000030 -#define UDC_EPSTS_OUT_OFS 4 -#define UDC_EPSTS_OUT_DATA 1 -#define UDC_EPSTS_OUT_DATA_CLEAR 0x10 -#define UDC_EPSTS_OUT_SETUP 2 -#define UDC_EPSTS_OUT_SETUP_CLEAR 0x20 -#define UDC_EPSTS_OUT_CLEAR 0x30 - -/* Endpoint Buffer Size IN/ Receive Packet Frame Number OUT Registers ------*/ -#define UDC_EPIN_BUFF_SIZE_ADDR 0x8 -#define UDC_EPOUT_FRAME_NUMBER_ADDR 0x8 - -#define UDC_EPIN_BUFF_SIZE_MASK 0x0000ffff -#define UDC_EPIN_BUFF_SIZE_OFS 0 -/* EP0in txfifo = 128 bytes*/ -#define UDC_EPIN0_BUFF_SIZE 32 -/* EP0in fullspeed txfifo = 128 bytes*/ -#define UDC_FS_EPIN0_BUFF_SIZE 32 - -/* fifo size mult = fifo size / max packet */ -#define UDC_EPIN_BUFF_SIZE_MULT 2 - -/* EPin data fifo size = 1024 bytes DOUBLE BUFFERING */ -#define UDC_EPIN_BUFF_SIZE 256 -/* EPin small INT data fifo size = 128 bytes */ -#define UDC_EPIN_SMALLINT_BUFF_SIZE 32 - -/* EPin fullspeed data fifo size = 128 bytes DOUBLE BUFFERING */ -#define UDC_FS_EPIN_BUFF_SIZE 32 - -#define UDC_EPOUT_FRAME_NUMBER_MASK 0x0000ffff -#define UDC_EPOUT_FRAME_NUMBER_OFS 0 - -/* Endpoint Buffer Size OUT/Max Packet Size Registers -----------------------*/ -#define UDC_EPOUT_BUFF_SIZE_ADDR 0x0c -#define UDC_EP_MAX_PKT_SIZE_ADDR 0x0c - -#define UDC_EPOUT_BUFF_SIZE_MASK 0xffff0000 -#define UDC_EPOUT_BUFF_SIZE_OFS 16 -#define UDC_EP_MAX_PKT_SIZE_MASK 0x0000ffff -#define UDC_EP_MAX_PKT_SIZE_OFS 0 -/* EP0in max packet size = 64 bytes */ -#define UDC_EP0IN_MAX_PKT_SIZE 64 -/* EP0out max packet size = 64 bytes */ -#define UDC_EP0OUT_MAX_PKT_SIZE 64 -/* EP0in fullspeed max packet size = 64 bytes */ -#define UDC_FS_EP0IN_MAX_PKT_SIZE 64 -/* EP0out fullspeed max packet size = 64 bytes */ -#define UDC_FS_EP0OUT_MAX_PKT_SIZE 64 - -/* - * Endpoint dma descriptors ------------------------------------------------ - * - * Setup data, Status dword - */ -#define UDC_DMA_STP_STS_CFG_MASK 0x0fff0000 -#define UDC_DMA_STP_STS_CFG_OFS 16 -#define UDC_DMA_STP_STS_CFG_ALT_MASK 0x000f0000 -#define UDC_DMA_STP_STS_CFG_ALT_OFS 16 -#define UDC_DMA_STP_STS_CFG_INTF_MASK 0x00f00000 -#define UDC_DMA_STP_STS_CFG_INTF_OFS 20 -#define UDC_DMA_STP_STS_CFG_NUM_MASK 0x0f000000 -#define UDC_DMA_STP_STS_CFG_NUM_OFS 24 -#define UDC_DMA_STP_STS_RX_MASK 0x30000000 -#define UDC_DMA_STP_STS_RX_OFS 28 -#define UDC_DMA_STP_STS_BS_MASK 0xc0000000 -#define UDC_DMA_STP_STS_BS_OFS 30 -#define UDC_DMA_STP_STS_BS_HOST_READY 0 -#define UDC_DMA_STP_STS_BS_DMA_BUSY 1 -#define UDC_DMA_STP_STS_BS_DMA_DONE 2 -#define UDC_DMA_STP_STS_BS_HOST_BUSY 3 -/* IN data, Status dword */ -#define UDC_DMA_IN_STS_TXBYTES_MASK 0x0000ffff -#define UDC_DMA_IN_STS_TXBYTES_OFS 0 -#define UDC_DMA_IN_STS_FRAMENUM_MASK 0x07ff0000 -#define UDC_DMA_IN_STS_FRAMENUM_OFS 0 -#define UDC_DMA_IN_STS_L 27 -#define UDC_DMA_IN_STS_TX_MASK 0x30000000 -#define UDC_DMA_IN_STS_TX_OFS 28 -#define UDC_DMA_IN_STS_BS_MASK 0xc0000000 -#define UDC_DMA_IN_STS_BS_OFS 30 -#define UDC_DMA_IN_STS_BS_HOST_READY 0 -#define UDC_DMA_IN_STS_BS_DMA_BUSY 1 -#define UDC_DMA_IN_STS_BS_DMA_DONE 2 -#define UDC_DMA_IN_STS_BS_HOST_BUSY 3 -/* OUT data, Status dword */ -#define UDC_DMA_OUT_STS_RXBYTES_MASK 0x0000ffff -#define UDC_DMA_OUT_STS_RXBYTES_OFS 0 -#define UDC_DMA_OUT_STS_FRAMENUM_MASK 0x07ff0000 -#define UDC_DMA_OUT_STS_FRAMENUM_OFS 0 -#define UDC_DMA_OUT_STS_L 27 -#define UDC_DMA_OUT_STS_RX_MASK 0x30000000 -#define UDC_DMA_OUT_STS_RX_OFS 28 -#define UDC_DMA_OUT_STS_BS_MASK 0xc0000000 -#define UDC_DMA_OUT_STS_BS_OFS 30 -#define UDC_DMA_OUT_STS_BS_HOST_READY 0 -#define UDC_DMA_OUT_STS_BS_DMA_BUSY 1 -#define UDC_DMA_OUT_STS_BS_DMA_DONE 2 -#define UDC_DMA_OUT_STS_BS_HOST_BUSY 3 -/* max ep0in packet */ -#define UDC_EP0IN_MAXPACKET 1000 -/* max dma packet */ -#define UDC_DMA_MAXPACKET 65536 - -/* un-usable DMA address */ -#define DMA_DONT_USE (~(dma_addr_t) 0 ) - -/* other Endpoint register addresses and values-----------------------------*/ -#define UDC_EP_SUBPTR_ADDR 0x10 -#define UDC_EP_DESPTR_ADDR 0x14 -#define UDC_EP_WRITE_CONFIRM_ADDR 0x1c - -/* EP number as layouted in AHB space */ -#define UDC_EP_NUM 32 -#define UDC_EPIN_NUM 16 -#define UDC_EPIN_NUM_USED 5 -#define UDC_EPOUT_NUM 16 -/* EP number of EP's really used = EP0 + 8 data EP's */ -#define UDC_USED_EP_NUM 9 -/* UDC CSR regs are aligned but AHB regs not - offset for OUT EP's */ -#define UDC_CSR_EP_OUT_IX_OFS 12 - -#define UDC_EP0OUT_IX 16 -#define UDC_EP0IN_IX 0 - -/* Rx fifo address and size = 1k -------------------------------------------*/ -#define UDC_RXFIFO_ADDR 0x800 -#define UDC_RXFIFO_SIZE 0x400 - -/* Tx fifo address and size = 1.5k -----------------------------------------*/ -#define UDC_TXFIFO_ADDR 0xc00 -#define UDC_TXFIFO_SIZE 0x600 - -/* default data endpoints --------------------------------------------------*/ -#define UDC_EPIN_STATUS_IX 1 -#define UDC_EPIN_IX 2 -#define UDC_EPOUT_IX 18 - -/* general constants -------------------------------------------------------*/ -#define UDC_DWORD_BYTES 4 -#define UDC_BITS_PER_BYTE_SHIFT 3 -#define UDC_BYTE_MASK 0xff -#define UDC_BITS_PER_BYTE 8 - -/*---------------------------------------------------------------------------*/ -/* UDC CSR's */ -struct udc_csrs { - - /* sca - setup command address */ - u32 sca; - - /* ep ne's */ - u32 ne[UDC_USED_EP_NUM]; -} __attribute__ ((packed)); - -/* AHB subsystem CSR registers */ -struct udc_regs { - - /* device configuration */ - u32 cfg; - - /* device control */ - u32 ctl; - - /* device status */ - u32 sts; - - /* device interrupt */ - u32 irqsts; - - /* device interrupt mask */ - u32 irqmsk; - - /* endpoint interrupt */ - u32 ep_irqsts; - - /* endpoint interrupt mask */ - u32 ep_irqmsk; -} __attribute__ ((packed)); - -/* endpoint specific registers */ -struct udc_ep_regs { - - /* endpoint control */ - u32 ctl; - - /* endpoint status */ - u32 sts; - - /* endpoint buffer size in/ receive packet frame number out */ - u32 bufin_framenum; - - /* endpoint buffer size out/max packet size */ - u32 bufout_maxpkt; - - /* endpoint setup buffer pointer */ - u32 subptr; - - /* endpoint data descriptor pointer */ - u32 desptr; - - /* reserverd */ - u32 reserved; - - /* write/read confirmation */ - u32 confirm; - -} __attribute__ ((packed)); - -/* control data DMA desc */ -struct udc_stp_dma { - /* status quadlet */ - u32 status; - /* reserved */ - u32 _reserved; - /* first setup word */ - u32 data12; - /* second setup word */ - u32 data34; -} __attribute__ ((aligned (16))); - -/* normal data DMA desc */ -struct udc_data_dma { - /* status quadlet */ - u32 status; - /* reserved */ - u32 _reserved; - /* buffer pointer */ - u32 bufptr; - /* next descriptor pointer */ - u32 next; -} __attribute__ ((aligned (16))); - -/* request packet */ -struct udc_request { - /* embedded gadget ep */ - struct usb_request req; - - /* flags */ - unsigned dma_going : 1, - dma_mapping : 1, - dma_done : 1; - /* phys. address */ - dma_addr_t td_phys; - /* first dma desc. of chain */ - struct udc_data_dma *td_data; - /* last dma desc. of chain */ - struct udc_data_dma *td_data_last; - struct list_head queue; - - /* chain length */ - unsigned chain_len; - -}; - -/* UDC specific endpoint parameters */ -struct udc_ep { - struct usb_ep ep; - struct udc_ep_regs __iomem *regs; - u32 __iomem *txfifo; - u32 __iomem *dma; - dma_addr_t td_phys; - dma_addr_t td_stp_dma; - struct udc_stp_dma *td_stp; - struct udc_data_dma *td; - /* temp request */ - struct udc_request *req; - unsigned req_used; - unsigned req_completed; - /* dummy DMA desc for BNA dummy */ - struct udc_request *bna_dummy_req; - unsigned bna_occurred; - - /* NAK state */ - unsigned naking; - - struct udc *dev; - - /* queue for requests */ - struct list_head queue; - const struct usb_endpoint_descriptor *desc; - unsigned halted; - unsigned cancel_transfer; - unsigned num : 5, - fifo_depth : 14, - in : 1; -}; - -/* device struct */ -struct udc { - struct usb_gadget gadget; - spinlock_t lock; /* protects all state */ - /* all endpoints */ - struct udc_ep ep[UDC_EP_NUM]; - struct usb_gadget_driver *driver; - /* operational flags */ - unsigned active : 1, - stall_ep0in : 1, - waiting_zlp_ack_ep0in : 1, - set_cfg_not_acked : 1, - irq_registered : 1, - data_ep_enabled : 1, - data_ep_queued : 1, - mem_region : 1, - sys_suspended : 1, - connected; - - u16 chiprev; - - /* registers */ - struct pci_dev *pdev; - struct udc_csrs __iomem *csr; - struct udc_regs __iomem *regs; - struct udc_ep_regs __iomem *ep_regs; - u32 __iomem *rxfifo; - u32 __iomem *txfifo; - - /* DMA desc pools */ - struct pci_pool *data_requests; - struct pci_pool *stp_requests; - - /* device data */ - unsigned long phys_addr; - void __iomem *virt_addr; - unsigned irq; - - /* states */ - u16 cur_config; - u16 cur_intf; - u16 cur_alt; -}; - -/* setup request data */ -union udc_setup_data { - u32 data[2]; - struct usb_ctrlrequest request; -}; - -/* - *--------------------------------------------------------------------------- - * SET and GET bitfields in u32 values - * via constants for mask/offset: - * is the text between - * UDC_ and _MASK|_OFS of appropriate - * constant - * - * set bitfield value in u32 u32Val - */ -#define AMD_ADDBITS(u32Val, bitfield_val, bitfield_stub_name) \ - (((u32Val) & (((u32) ~((u32) bitfield_stub_name##_MASK)))) \ - | (((bitfield_val) << ((u32) bitfield_stub_name##_OFS)) \ - & ((u32) bitfield_stub_name##_MASK))) - -/* - * set bitfield value in zero-initialized u32 u32Val - * => bitfield bits in u32Val are all zero - */ -#define AMD_INIT_SETBITS(u32Val, bitfield_val, bitfield_stub_name) \ - ((u32Val) \ - | (((bitfield_val) << ((u32) bitfield_stub_name##_OFS)) \ - & ((u32) bitfield_stub_name##_MASK))) - -/* get bitfield value from u32 u32Val */ -#define AMD_GETBITS(u32Val, bitfield_stub_name) \ - ((u32Val & ((u32) bitfield_stub_name##_MASK)) \ - >> ((u32) bitfield_stub_name##_OFS)) - -/* SET and GET bits in u32 values ------------------------------------------*/ -#define AMD_BIT(bit_stub_name) (1 << bit_stub_name) -#define AMD_UNMASK_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name)) -#define AMD_CLEAR_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name)) - -/* debug macros ------------------------------------------------------------*/ - -#define DBG(udc , args...) dev_dbg(&(udc)->pdev->dev, args) - -#ifdef UDC_VERBOSE -#define VDBG DBG -#else -#define VDBG(udc , args...) do {} while (0) -#endif - -#endif /* #ifdef AMD5536UDC_H */ diff --git a/ANDROID_3.4.5/drivers/usb/gadget/android.c b/ANDROID_3.4.5/drivers/usb/gadget/android.c deleted file mode 100644 index c5ce536a..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/android.c +++ /dev/null @@ -1,1691 +0,0 @@ -/* - * Gadget Driver for Android - * - * Copyright (C) 2008 Google, Inc. - * Author: Mike Lockwood - * Benoit Goby - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include "gadget_chips.h" - -/* - * 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 "usbstring.c" -#include "config.c" -#include "epautoconf.c" -#include "composite.c" - -#include "f_fs.c" -#include "f_audio_source.c" -#include "f_mass_storage.c" -#include "u_serial.c" -#include "f_acm.c" -#include "f_adb.c" -#include "f_mtp.c" -#include "f_accessory.c" -#define USB_ETH_RNDIS y -#include "f_rndis.c" -#include "rndis.c" -#include "u_ether.c" -#include "f_rawbulk.c" - -MODULE_AUTHOR("Mike Lockwood"); -MODULE_DESCRIPTION("Android Composite USB Driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION("1.0"); - -static const char longname[] = "Gadget Android"; - -extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); -extern int wmt_setsyspara(char *varname, char *varval); - -/* Default vendor and product IDs, overridden by userspace */ -#define VENDOR_ID 0x18D1 -#define PRODUCT_ID 0x0001 - -struct android_usb_function { - char *name; - void *config; - - struct device *dev; - char *dev_name; - struct device_attribute **attributes; - - /* for android_dev.enabled_functions */ - struct list_head enabled_list; - - /* Optional: initialization during gadget bind */ - int (*init)(struct android_usb_function *, struct usb_composite_dev *); - /* Optional: cleanup during gadget unbind */ - void (*cleanup)(struct android_usb_function *); - /* Optional: called when the function is added the list of - * enabled functions */ - void (*enable)(struct android_usb_function *); - /* Optional: called when it is removed */ - void (*disable)(struct android_usb_function *); - - int (*bind_config)(struct android_usb_function *, - struct usb_configuration *); - - /* Optional: called when the configuration is removed */ - void (*unbind_config)(struct android_usb_function *, - struct usb_configuration *); - /* Optional: handle ctrl requests before the device is configured */ - int (*ctrlrequest)(struct android_usb_function *, - struct usb_composite_dev *, - const struct usb_ctrlrequest *); -}; - -struct android_dev { - struct android_usb_function **functions; - struct list_head enabled_functions; - struct usb_composite_dev *cdev; - struct device *dev; - - bool enabled; - int disable_depth; - struct mutex mutex; - bool connected; - bool sw_connected; - struct work_struct work; - char ffs_aliases[256]; -}; - -static struct class *android_class; -static struct android_dev *_android_dev; -static int android_bind_config(struct usb_configuration *c); -static void android_unbind_config(struct usb_configuration *c); - -/* string IDs are assigned dynamically */ -#define STRING_MANUFACTURER_IDX 0 -#define STRING_PRODUCT_IDX 1 -#define STRING_SERIAL_IDX 2 - -static char manufacturer_string[256]; -static char product_string[256]; -static char serial_string[256]; - -/* String Table */ -static struct usb_string strings_dev[] = { - [STRING_MANUFACTURER_IDX].s = manufacturer_string, - [STRING_PRODUCT_IDX].s = product_string, - [STRING_SERIAL_IDX].s = serial_string, - { } /* end of list */ -}; - -static struct usb_gadget_strings stringtab_dev = { - .language = 0x0409, /* en-us */ - .strings = strings_dev, -}; - -static struct usb_gadget_strings *dev_strings[] = { - &stringtab_dev, - NULL, -}; - -static struct usb_device_descriptor device_desc = { - .bLength = sizeof(device_desc), - .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = __constant_cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_PER_INTERFACE, - .idVendor = __constant_cpu_to_le16(VENDOR_ID), - .idProduct = __constant_cpu_to_le16(PRODUCT_ID), - .bcdDevice = __constant_cpu_to_le16(0xffff), - .bNumConfigurations = 1, -}; - -static struct usb_configuration android_config_driver = { - .label = "android", - .unbind = android_unbind_config, - .bConfigurationValue = 1, - .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, - .bMaxPower = 0xFA, /* 500ma */ -}; - -static void android_work(struct work_struct *data) -{ - struct android_dev *dev = container_of(data, struct android_dev, work); - struct usb_composite_dev *cdev = dev->cdev; - char *disconnected[2] = { "USB_STATE=DISCONNECTED", NULL }; - char *connected[2] = { "USB_STATE=CONNECTED", NULL }; - char *configured[2] = { "USB_STATE=CONFIGURED", NULL }; - char **uevent_envp = NULL; - unsigned long flags; - - spin_lock_irqsave(&cdev->lock, flags); - if (cdev->config) - uevent_envp = configured; - else if (dev->connected != dev->sw_connected) - uevent_envp = dev->connected ? connected : disconnected; - dev->sw_connected = dev->connected; - spin_unlock_irqrestore(&cdev->lock, flags); - - if (uevent_envp) { - kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE, uevent_envp); - pr_info("%s: sent uevent %s\n", __func__, uevent_envp[0]); - } else { - pr_info("%s: did not send uevent (%d %d %p)\n", __func__, - dev->connected, dev->sw_connected, cdev->config); - } -} - -static void android_enable(struct android_dev *dev) -{ - struct usb_composite_dev *cdev = dev->cdev; - - if (WARN_ON(!dev->disable_depth)) - return; - - if (--dev->disable_depth == 0) { - usb_add_config(cdev, &android_config_driver, - android_bind_config); - usb_gadget_connect(cdev->gadget); - } -} - -static void android_disable(struct android_dev *dev) -{ - struct usb_composite_dev *cdev = dev->cdev; - - if (dev->disable_depth++ == 0) { - usb_gadget_disconnect(cdev->gadget); - /* Cancel pending control requests */ - usb_ep_dequeue(cdev->gadget->ep0, cdev->req); - usb_remove_config(cdev, &android_config_driver); - usb_ep_autoconfig_reset(cdev->gadget); - } -} - -/*-------------------------------------------------------------------------*/ -/* Supported functions initialization */ - -struct functionfs_config { - bool opened; - bool enabled; - struct ffs_data *data; -}; - -static int ffs_function_init(struct android_usb_function *f, - struct usb_composite_dev *cdev) -{ - f->config = kzalloc(sizeof(struct functionfs_config), GFP_KERNEL); - if (!f->config) - return -ENOMEM; - - return functionfs_init(); -} - -static void ffs_function_cleanup(struct android_usb_function *f) -{ - functionfs_cleanup(); - kfree(f->config); -} - -static void ffs_function_enable(struct android_usb_function *f) -{ - struct android_dev *dev = _android_dev; - struct functionfs_config *config = f->config; - - config->enabled = true; - - /* Disable the gadget until the function is ready */ - if (!config->opened) - android_disable(dev); -} - -static void ffs_function_disable(struct android_usb_function *f) -{ - struct android_dev *dev = _android_dev; - struct functionfs_config *config = f->config; - - config->enabled = false; - - /* Balance the disable that was called in closed_callback */ - if (!config->opened) - android_enable(dev); -} - -static int ffs_function_bind_config(struct android_usb_function *f, - struct usb_configuration *c) -{ - struct functionfs_config *config = f->config; - return functionfs_bind_config(c->cdev, c, config->data); -} - -static ssize_t -ffs_aliases_show(struct device *pdev, struct device_attribute *attr, char *buf) -{ - struct android_dev *dev = _android_dev; - int ret; - - mutex_lock(&dev->mutex); - ret = sprintf(buf, "%s\n", dev->ffs_aliases); - mutex_unlock(&dev->mutex); - - return ret; -} - -static ssize_t -ffs_aliases_store(struct device *pdev, struct device_attribute *attr, - const char *buf, size_t size) -{ - struct android_dev *dev = _android_dev; - char buff[256]; - - mutex_lock(&dev->mutex); - - if (dev->enabled) { - mutex_unlock(&dev->mutex); - return -EBUSY; - } - - strlcpy(buff, buf, sizeof(buff)); - strlcpy(dev->ffs_aliases, strim(buff), sizeof(dev->ffs_aliases)); - - mutex_unlock(&dev->mutex); - - return size; -} - -static DEVICE_ATTR(aliases, S_IRUGO | S_IWUSR, ffs_aliases_show, - ffs_aliases_store); -static struct device_attribute *ffs_function_attributes[] = { - &dev_attr_aliases, - NULL -}; - -static struct android_usb_function ffs_function = { - .name = "ffs", - .init = ffs_function_init, - .enable = ffs_function_enable, - .disable = ffs_function_disable, - .cleanup = ffs_function_cleanup, - .bind_config = ffs_function_bind_config, - .attributes = ffs_function_attributes, -}; - -static int functionfs_ready_callback(struct ffs_data *ffs) -{ - struct android_dev *dev = _android_dev; - struct functionfs_config *config = ffs_function.config; - int ret = 0; - - mutex_lock(&dev->mutex); - - ret = functionfs_bind(ffs, dev->cdev); - if (ret) - goto err; - - config->data = ffs; - config->opened = true; - - if (config->enabled) - android_enable(dev); - -err: - mutex_unlock(&dev->mutex); - return ret; -} - -static void functionfs_closed_callback(struct ffs_data *ffs) -{ - struct android_dev *dev = _android_dev; - struct functionfs_config *config = ffs_function.config; - - mutex_lock(&dev->mutex); - - if (config->enabled) - android_disable(dev); - - config->opened = false; - config->data = NULL; - - functionfs_unbind(ffs); - - mutex_unlock(&dev->mutex); -} - -static int functionfs_check_dev_callback(const char *dev_name) -{ - return 0; -} - - -struct adb_data { - bool opened; - bool enabled; -}; - -static int -adb_function_init(struct android_usb_function *f, - struct usb_composite_dev *cdev) -{ - f->config = kzalloc(sizeof(struct adb_data), GFP_KERNEL); - if (!f->config) - return -ENOMEM; - - return adb_setup(); -} - -static void adb_function_cleanup(struct android_usb_function *f) -{ - adb_cleanup(); - kfree(f->config); -} - -static int -adb_function_bind_config(struct android_usb_function *f, - struct usb_configuration *c) -{ - return adb_bind_config(c); -} - -static void adb_android_function_enable(struct android_usb_function *f) -{ - struct android_dev *dev = _android_dev; - struct adb_data *data = f->config; - - data->enabled = true; - - /* Disable the gadget until adbd is ready */ - if (!data->opened) - android_disable(dev); -} - -static void adb_android_function_disable(struct android_usb_function *f) -{ - struct android_dev *dev = _android_dev; - struct adb_data *data = f->config; - - data->enabled = false; - - /* Balance the disable that was called in closed_callback */ - if (!data->opened) - android_enable(dev); -} - -static struct android_usb_function adb_function = { - .name = "adb", - .enable = adb_android_function_enable, - .disable = adb_android_function_disable, - .init = adb_function_init, - .cleanup = adb_function_cleanup, - .bind_config = adb_function_bind_config, -}; - -static void adb_ready_callback(void) -{ - struct android_dev *dev = _android_dev; - struct adb_data *data = adb_function.config; - - mutex_lock(&dev->mutex); - - data->opened = true; - - if (data->enabled) - android_enable(dev); - - mutex_unlock(&dev->mutex); -} - -static void adb_closed_callback(void) -{ - struct android_dev *dev = _android_dev; - struct adb_data *data = adb_function.config; - - mutex_lock(&dev->mutex); - - data->opened = false; - - if (data->enabled) - android_disable(dev); - - mutex_unlock(&dev->mutex); -} - - -#define MAX_ACM_INSTANCES 4 -struct acm_function_config { - int instances; -}; - -static int -acm_function_init(struct android_usb_function *f, - struct usb_composite_dev *cdev) -{ - f->config = kzalloc(sizeof(struct acm_function_config), GFP_KERNEL); - if (!f->config) - return -ENOMEM; - - return gserial_setup(cdev->gadget, MAX_ACM_INSTANCES); -} - -static void acm_function_cleanup(struct android_usb_function *f) -{ - gserial_cleanup(); - kfree(f->config); - f->config = NULL; -} - -static int -acm_function_bind_config(struct android_usb_function *f, - struct usb_configuration *c) -{ - int i; - int ret = 0; - struct acm_function_config *config = f->config; - - for (i = 0; i < config->instances; i++) { - ret = acm_bind_config(c, i); - if (ret) { - pr_err("Could not bind acm%u config\n", i); - break; - } - } - - return ret; -} - -static ssize_t acm_instances_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct android_usb_function *f = dev_get_drvdata(dev); - struct acm_function_config *config = f->config; - return sprintf(buf, "%d\n", config->instances); -} - -static ssize_t acm_instances_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - struct android_usb_function *f = dev_get_drvdata(dev); - struct acm_function_config *config = f->config; - int value; - - sscanf(buf, "%d", &value); - if (value > MAX_ACM_INSTANCES) - value = MAX_ACM_INSTANCES; - config->instances = value; - return size; -} - -static DEVICE_ATTR(instances, S_IRUGO | S_IWUSR, acm_instances_show, - acm_instances_store); -static struct device_attribute *acm_function_attributes[] = { - &dev_attr_instances, - NULL -}; - -static struct android_usb_function acm_function = { - .name = "acm", - .init = acm_function_init, - .cleanup = acm_function_cleanup, - .bind_config = acm_function_bind_config, - .attributes = acm_function_attributes, -}; - - -static int -mtp_function_init(struct android_usb_function *f, - struct usb_composite_dev *cdev) -{ - return mtp_setup(); -} - -static void mtp_function_cleanup(struct android_usb_function *f) -{ - mtp_cleanup(); -} - -static int -mtp_function_bind_config(struct android_usb_function *f, - struct usb_configuration *c) -{ - return mtp_bind_config(c, false); -} - -static int -ptp_function_init(struct android_usb_function *f, - struct usb_composite_dev *cdev) -{ - /* nothing to do - initialization is handled by mtp_function_init */ - return 0; -} - -static void ptp_function_cleanup(struct android_usb_function *f) -{ - /* nothing to do - cleanup is handled by mtp_function_cleanup */ -} - -static int -ptp_function_bind_config(struct android_usb_function *f, - struct usb_configuration *c) -{ - return mtp_bind_config(c, true); -} - -static int mtp_function_ctrlrequest(struct android_usb_function *f, - struct usb_composite_dev *cdev, - const struct usb_ctrlrequest *c) -{ - return mtp_ctrlrequest(cdev, c); -} - -static struct android_usb_function mtp_function = { - .name = "mtp", - .init = mtp_function_init, - .cleanup = mtp_function_cleanup, - .bind_config = mtp_function_bind_config, - .ctrlrequest = mtp_function_ctrlrequest, -}; - -/* PTP function is same as MTP with slightly different interface descriptor */ -static struct android_usb_function ptp_function = { - .name = "ptp", - .init = ptp_function_init, - .cleanup = ptp_function_cleanup, - .bind_config = ptp_function_bind_config, -}; - - -struct rndis_function_config { - u8 ethaddr[ETH_ALEN]; - u32 vendorID; - char manufacturer[256]; - /* "Wireless" RNDIS; auto-detected by Windows */ - bool wceis; -}; - -static int -rndis_function_init(struct android_usb_function *f, - struct usb_composite_dev *cdev) -{ - f->config = kzalloc(sizeof(struct rndis_function_config), GFP_KERNEL); - if (!f->config) - return -ENOMEM; - return 0; -} - -static void rndis_function_cleanup(struct android_usb_function *f) -{ - kfree(f->config); - f->config = NULL; -} - -static int -rndis_function_bind_config(struct android_usb_function *f, - struct usb_configuration *c) -{ - int ret; - struct rndis_function_config *rndis = f->config; - - if (!rndis) { - pr_err("%s: rndis_pdata\n", __func__); - return -1; - } - - pr_info("%s MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", __func__, - rndis->ethaddr[0], rndis->ethaddr[1], rndis->ethaddr[2], - rndis->ethaddr[3], rndis->ethaddr[4], rndis->ethaddr[5]); - - ret = gether_setup_name(c->cdev->gadget, rndis->ethaddr, "rndis"); - if (ret) { - pr_err("%s: gether_setup failed\n", __func__); - return ret; - } - - if (rndis->wceis) { - /* "Wireless" RNDIS; auto-detected by Windows */ - rndis_iad_descriptor.bFunctionClass = - USB_CLASS_WIRELESS_CONTROLLER; - rndis_iad_descriptor.bFunctionSubClass = 0x01; - rndis_iad_descriptor.bFunctionProtocol = 0x03; - rndis_control_intf.bInterfaceClass = - USB_CLASS_WIRELESS_CONTROLLER; - rndis_control_intf.bInterfaceSubClass = 0x01; - rndis_control_intf.bInterfaceProtocol = 0x03; - } - - return rndis_bind_config_vendor(c, rndis->ethaddr, rndis->vendorID, - rndis->manufacturer); -} - -static void rndis_function_unbind_config(struct android_usb_function *f, - struct usb_configuration *c) -{ - gether_cleanup(); -} - -static ssize_t rndis_manufacturer_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct android_usb_function *f = dev_get_drvdata(dev); - struct rndis_function_config *config = f->config; - return sprintf(buf, "%s\n", config->manufacturer); -} - -static ssize_t rndis_manufacturer_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - struct android_usb_function *f = dev_get_drvdata(dev); - struct rndis_function_config *config = f->config; - - if (size >= sizeof(config->manufacturer)) - return -EINVAL; - if (sscanf(buf, "%s", config->manufacturer) == 1) - return size; - return -1; -} - -static DEVICE_ATTR(manufacturer, S_IRUGO | S_IWUSR, rndis_manufacturer_show, - rndis_manufacturer_store); - -static ssize_t rndis_wceis_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct android_usb_function *f = dev_get_drvdata(dev); - struct rndis_function_config *config = f->config; - return sprintf(buf, "%d\n", config->wceis); -} - -static ssize_t rndis_wceis_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - struct android_usb_function *f = dev_get_drvdata(dev); - struct rndis_function_config *config = f->config; - int value; - - if (sscanf(buf, "%d", &value) == 1) { - config->wceis = value; - return size; - } - return -EINVAL; -} - -static DEVICE_ATTR(wceis, S_IRUGO | S_IWUSR, rndis_wceis_show, - rndis_wceis_store); - -static ssize_t rndis_ethaddr_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct android_usb_function *f = dev_get_drvdata(dev); - struct rndis_function_config *rndis = f->config; - return sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n", - rndis->ethaddr[0], rndis->ethaddr[1], rndis->ethaddr[2], - rndis->ethaddr[3], rndis->ethaddr[4], rndis->ethaddr[5]); -} - -static ssize_t rndis_ethaddr_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - struct android_usb_function *f = dev_get_drvdata(dev); - struct rndis_function_config *rndis = f->config; - - if (sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n", - (int *)&rndis->ethaddr[0], (int *)&rndis->ethaddr[1], - (int *)&rndis->ethaddr[2], (int *)&rndis->ethaddr[3], - (int *)&rndis->ethaddr[4], (int *)&rndis->ethaddr[5]) == 6) - return size; - return -EINVAL; -} - -static DEVICE_ATTR(ethaddr, S_IRUGO | S_IWUSR, rndis_ethaddr_show, - rndis_ethaddr_store); - -static ssize_t rndis_vendorID_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct android_usb_function *f = dev_get_drvdata(dev); - struct rndis_function_config *config = f->config; - return sprintf(buf, "%04x\n", config->vendorID); -} - -static ssize_t rndis_vendorID_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - struct android_usb_function *f = dev_get_drvdata(dev); - struct rndis_function_config *config = f->config; - int value; - - if (sscanf(buf, "%04x", &value) == 1) { - config->vendorID = value; - return size; - } - return -EINVAL; -} - -static DEVICE_ATTR(vendorID, S_IRUGO | S_IWUSR, rndis_vendorID_show, - rndis_vendorID_store); - -static struct device_attribute *rndis_function_attributes[] = { - &dev_attr_manufacturer, - &dev_attr_wceis, - &dev_attr_ethaddr, - &dev_attr_vendorID, - NULL -}; - -static struct android_usb_function rndis_function = { - .name = "rndis", - .init = rndis_function_init, - .cleanup = rndis_function_cleanup, - .bind_config = rndis_function_bind_config, - .unbind_config = rndis_function_unbind_config, - .attributes = rndis_function_attributes, -}; - - -struct mass_storage_function_config { - struct fsg_config fsg; - struct fsg_common *common; -}; - -static int mass_storage_function_init(struct android_usb_function *f, - struct usb_composite_dev *cdev) -{ - struct mass_storage_function_config *config; - struct fsg_common *common; - int err; - - config = kzalloc(sizeof(struct mass_storage_function_config), - GFP_KERNEL); - if (!config) - return -ENOMEM; - - config->fsg.nluns = 1; - config->fsg.luns[0].removable = 1; - - common = fsg_common_init(NULL, cdev, &config->fsg); - if (IS_ERR(common)) { - kfree(config); - return PTR_ERR(common); - } - - err = sysfs_create_link(&f->dev->kobj, - &common->luns[0].dev.kobj, - "lun"); - if (err) { - kfree(config); - return err; - } - - config->common = common; - f->config = config; - return 0; -} - -static void mass_storage_function_cleanup(struct android_usb_function *f) -{ - kfree(f->config); - f->config = NULL; -} - -static int mass_storage_function_bind_config(struct android_usb_function *f, - struct usb_configuration *c) -{ - struct mass_storage_function_config *config = f->config; - return fsg_bind_config(c->cdev, c, config->common); -} - -static ssize_t mass_storage_inquiry_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct android_usb_function *f = dev_get_drvdata(dev); - struct mass_storage_function_config *config = f->config; - return sprintf(buf, "%s\n", config->common->inquiry_string); -} - -static ssize_t mass_storage_inquiry_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - struct android_usb_function *f = dev_get_drvdata(dev); - struct mass_storage_function_config *config = f->config; - if (size >= sizeof(config->common->inquiry_string)) - return -EINVAL; - if (sscanf(buf, "%s", config->common->inquiry_string) != 1) - return -EINVAL; - return size; -} - -static DEVICE_ATTR(inquiry_string, S_IRUGO | S_IWUSR, - mass_storage_inquiry_show, - mass_storage_inquiry_store); - -static struct device_attribute *mass_storage_function_attributes[] = { - &dev_attr_inquiry_string, - NULL -}; - -static struct android_usb_function mass_storage_function = { - .name = "mass_storage", - .init = mass_storage_function_init, - .cleanup = mass_storage_function_cleanup, - .bind_config = mass_storage_function_bind_config, - .attributes = mass_storage_function_attributes, -}; - - -static int accessory_function_init(struct android_usb_function *f, - struct usb_composite_dev *cdev) -{ - return acc_setup(); -} - -static void accessory_function_cleanup(struct android_usb_function *f) -{ - acc_cleanup(); -} - -static int accessory_function_bind_config(struct android_usb_function *f, - struct usb_configuration *c) -{ - return acc_bind_config(c); -} - -static int accessory_function_ctrlrequest(struct android_usb_function *f, - struct usb_composite_dev *cdev, - const struct usb_ctrlrequest *c) -{ - return acc_ctrlrequest(cdev, c); -} - -static struct android_usb_function accessory_function = { - .name = "accessory", - .init = accessory_function_init, - .cleanup = accessory_function_cleanup, - .bind_config = accessory_function_bind_config, - .ctrlrequest = accessory_function_ctrlrequest, -}; -#define CONFIG_USB_ANDROID_RAWBULK 1 - -/* VIA Rawbulk functions */ -#ifdef CONFIG_USB_ANDROID_RAWBULK -static int rawbulk_function_init(struct android_usb_function *f, - struct usb_composite_dev *cdev) -{ - return 0; -} - -static void rawbulk_function_cleanup(struct android_usb_function *f) -{ - ; -} - -static int rawbulk_function_bind_config(struct android_usb_function *f, - struct usb_configuration *c) -{ - char *i = f->name + strlen("via_"); - if (!strncmp(i, "modem", 5)) - return rawbulk_bind_config(c, RAWBULK_TID_MODEM); - else if (!strncmp(i, "ets", 3)) - return rawbulk_bind_config(c, RAWBULK_TID_ETS); - else if (!strncmp(i, "atc", 3)) - return rawbulk_bind_config(c, RAWBULK_TID_AT); - else if (!strncmp(i, "pcv", 3)) - return rawbulk_bind_config(c, RAWBULK_TID_PCV); - else if (!strncmp(i, "gps", 3)) - return rawbulk_bind_config(c, RAWBULK_TID_GPS); - return -EINVAL; -} - -static int rawbulk_function_modem_ctrlrequest(struct android_usb_function *f, - struct usb_composite_dev *cdev, - const struct usb_ctrlrequest *c) -{ - if ((c->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE && - (c->bRequestType & USB_TYPE_MASK) == USB_TYPE_VENDOR) { - struct rawbulk_function *fn = rawbulk_lookup_function(RAWBULK_TID_MODEM); - return rawbulk_function_setup(&fn->function, c); - } - return -1; -} - -static struct android_usb_function rawbulk_modem_function = { - .name = "via_modem", - .init = rawbulk_function_init, - .cleanup = rawbulk_function_cleanup, - .bind_config = rawbulk_function_bind_config, - .ctrlrequest = rawbulk_function_modem_ctrlrequest, -}; - -static struct android_usb_function rawbulk_ets_function = { - .name = "via_ets", - .init = rawbulk_function_init, - .cleanup = rawbulk_function_cleanup, - .bind_config = rawbulk_function_bind_config, -}; - -static struct android_usb_function rawbulk_atc_function = { - .name = "via_atc", - .init = rawbulk_function_init, - .cleanup = rawbulk_function_cleanup, - .bind_config = rawbulk_function_bind_config, -}; - -static struct android_usb_function rawbulk_pcv_function = { - .name = "via_pcv", - .init = rawbulk_function_init, - .cleanup = rawbulk_function_cleanup, - .bind_config = rawbulk_function_bind_config, -}; - -static struct android_usb_function rawbulk_gps_function = { - .name = "via_gps", - .init = rawbulk_function_init, - .cleanup = rawbulk_function_cleanup, - .bind_config = rawbulk_function_bind_config, -}; -#endif /* CONFIG_USB_ANDROID_RAWBULK */ - -static int audio_source_function_init(struct android_usb_function *f, - struct usb_composite_dev *cdev) -{ - struct audio_source_config *config; - - config = kzalloc(sizeof(struct audio_source_config), GFP_KERNEL); - if (!config) - return -ENOMEM; - config->card = -1; - config->device = -1; - f->config = config; - return 0; -} - -static void audio_source_function_cleanup(struct android_usb_function *f) -{ - kfree(f->config); -} - -static int audio_source_function_bind_config(struct android_usb_function *f, - struct usb_configuration *c) -{ - struct audio_source_config *config = f->config; - - return audio_source_bind_config(c, config); -} - -static void audio_source_function_unbind_config(struct android_usb_function *f, - struct usb_configuration *c) -{ - struct audio_source_config *config = f->config; - - config->card = -1; - config->device = -1; -} - -static ssize_t audio_source_pcm_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct android_usb_function *f = dev_get_drvdata(dev); - struct audio_source_config *config = f->config; - - /* print PCM card and device numbers */ - return sprintf(buf, "%d %d\n", config->card, config->device); -} - -static DEVICE_ATTR(pcm, S_IRUGO | S_IWUSR, audio_source_pcm_show, NULL); - -static struct device_attribute *audio_source_function_attributes[] = { - &dev_attr_pcm, - NULL -}; - -static struct android_usb_function audio_source_function = { - .name = "audio_source", - .init = audio_source_function_init, - .cleanup = audio_source_function_cleanup, - .bind_config = audio_source_function_bind_config, - .unbind_config = audio_source_function_unbind_config, - .attributes = audio_source_function_attributes, -}; - -static struct android_usb_function *supported_functions[] = { - &ffs_function, - &adb_function, - &acm_function, - &mtp_function, - &ptp_function, - &rndis_function, - &mass_storage_function, - &accessory_function, - &audio_source_function, - &rawbulk_modem_function, - &rawbulk_ets_function, - &rawbulk_atc_function, - &rawbulk_pcv_function, - &rawbulk_gps_function, - NULL -}; - - -static int android_init_functions(struct android_usb_function **functions, - struct usb_composite_dev *cdev) -{ - struct android_dev *dev = _android_dev; - struct android_usb_function *f; - struct device_attribute **attrs; - struct device_attribute *attr; - int err; - int index = 0; - - for (; (f = *functions++); index++) { - f->dev_name = kasprintf(GFP_KERNEL, "f_%s", f->name); - f->dev = device_create(android_class, dev->dev, - MKDEV(0, index), f, f->dev_name); - if (IS_ERR(f->dev)) { - pr_err("%s: Failed to create dev %s", __func__, - f->dev_name); - err = PTR_ERR(f->dev); - goto err_create; - } - - if (f->init) { - err = f->init(f, cdev); - if (err) { - pr_err("%s: Failed to init %s", __func__, - f->name); - goto err_out; - } - } - - attrs = f->attributes; - if (attrs) { - while ((attr = *attrs++) && !err) - err = device_create_file(f->dev, attr); - } - if (err) { - pr_err("%s: Failed to create function %s attributes", - __func__, f->name); - goto err_out; - } - } - return 0; - -err_out: - device_destroy(android_class, f->dev->devt); -err_create: - kfree(f->dev_name); - return err; -} - -static void android_cleanup_functions(struct android_usb_function **functions) -{ - struct android_usb_function *f; - - while (*functions) { - f = *functions++; - - if (f->dev) { - device_destroy(android_class, f->dev->devt); - kfree(f->dev_name); - } - - if (f->cleanup) - f->cleanup(f); - } -} - -static int -android_bind_enabled_functions(struct android_dev *dev, - struct usb_configuration *c) -{ - struct android_usb_function *f; - int ret; - - list_for_each_entry(f, &dev->enabled_functions, enabled_list) { - ret = f->bind_config(f, c); - if (ret) { - pr_err("%s: %s failed", __func__, f->name); - return ret; - } - } - return 0; -} - -static void -android_unbind_enabled_functions(struct android_dev *dev, - struct usb_configuration *c) -{ - struct android_usb_function *f; - - list_for_each_entry(f, &dev->enabled_functions, enabled_list) { - if (f->unbind_config) - f->unbind_config(f, c); - } -} - -static int android_enable_function(struct android_dev *dev, char *name) -{ - struct android_usb_function **functions = dev->functions; - struct android_usb_function *f; - while ((f = *functions++)) { - if (!strcmp(name, f->name)) { - list_add_tail(&f->enabled_list, - &dev->enabled_functions); - return 0; - } - } - return -EINVAL; -} - -/*-------------------------------------------------------------------------*/ -/* /sys/class/android_usb/android%d/ interface */ - -static ssize_t -functions_show(struct device *pdev, struct device_attribute *attr, char *buf) -{ - struct android_dev *dev = dev_get_drvdata(pdev); - struct android_usb_function *f; - char *buff = buf; - - mutex_lock(&dev->mutex); - - list_for_each_entry(f, &dev->enabled_functions, enabled_list) - buff += sprintf(buff, "%s,", f->name); - - mutex_unlock(&dev->mutex); - - if (buff != buf) - *(buff-1) = '\n'; - return buff - buf; -} - -static ssize_t -functions_store(struct device *pdev, struct device_attribute *attr, - const char *buff, size_t size) -{ - struct android_dev *dev = dev_get_drvdata(pdev); - char *name; - char buf[256], *b; - char aliases[256], *a; - int err; - int is_ffs; - int ffs_enabled = 0; - - mutex_lock(&dev->mutex); - - if (dev->enabled) { - mutex_unlock(&dev->mutex); - return -EBUSY; - } - - INIT_LIST_HEAD(&dev->enabled_functions); - - strlcpy(buf, buff, sizeof(buf)); - b = strim(buf); - - while (b) { - name = strsep(&b, ","); - if (!name) - continue; - - is_ffs = 0; - strlcpy(aliases, dev->ffs_aliases, sizeof(aliases)); - a = aliases; - - while (a) { - char *alias = strsep(&a, ","); - if (alias && !strcmp(name, alias)) { - is_ffs = 1; - break; - } - } - - if (is_ffs) { - if (ffs_enabled) - continue; - err = android_enable_function(dev, "ffs"); - if (err) - pr_err("android_usb: Cannot enable ffs (%d)", - err); - else - ffs_enabled = 1; - continue; - } - - err = android_enable_function(dev, name); - if (err) - pr_err("android_usb: Cannot enable '%s' (%d)", - name, err); - } - - mutex_unlock(&dev->mutex); - - return size; -} - -static ssize_t enable_show(struct device *pdev, struct device_attribute *attr, - char *buf) -{ - struct android_dev *dev = dev_get_drvdata(pdev); - return sprintf(buf, "%d\n", dev->enabled); -} - -static ssize_t enable_store(struct device *pdev, struct device_attribute *attr, - const char *buff, size_t size) -{ - struct android_dev *dev = dev_get_drvdata(pdev); - struct usb_composite_dev *cdev = dev->cdev; - struct android_usb_function *f; - int enabled = 0; - - - if (!cdev) - return -ENODEV; - - mutex_lock(&dev->mutex); - - sscanf(buff, "%d", &enabled); - if (enabled && !dev->enabled) { - /* - * Update values in composite driver's copy of - * device descriptor. - */ - cdev->desc.idVendor = device_desc.idVendor; - cdev->desc.idProduct = device_desc.idProduct; - cdev->desc.bcdDevice = device_desc.bcdDevice; - cdev->desc.bDeviceClass = device_desc.bDeviceClass; - cdev->desc.bDeviceSubClass = device_desc.bDeviceSubClass; - cdev->desc.bDeviceProtocol = device_desc.bDeviceProtocol; - list_for_each_entry(f, &dev->enabled_functions, enabled_list) { - if (f->enable) - f->enable(f); - } - android_enable(dev); - dev->enabled = true; - } else if (!enabled && dev->enabled) { - android_disable(dev); - list_for_each_entry(f, &dev->enabled_functions, enabled_list) { - if (f->disable) - f->disable(f); - } - dev->enabled = false; - } else { - pr_err("android_usb: already %s\n", - dev->enabled ? "enabled" : "disabled"); - } - - mutex_unlock(&dev->mutex); - return size; -} - -static ssize_t state_show(struct device *pdev, struct device_attribute *attr, - char *buf) -{ - struct android_dev *dev = dev_get_drvdata(pdev); - struct usb_composite_dev *cdev = dev->cdev; - char *state = "DISCONNECTED"; - unsigned long flags; - - if (!cdev) - goto out; - - spin_lock_irqsave(&cdev->lock, flags); - if (cdev->config) - state = "CONFIGURED"; - else if (dev->connected) - state = "CONNECTED"; - spin_unlock_irqrestore(&cdev->lock, flags); -out: - return sprintf(buf, "%s\n", state); -} - -#define DESCRIPTOR_ATTR(field, format_string) \ -static ssize_t \ -field ## _show(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return sprintf(buf, format_string, device_desc.field); \ -} \ -static ssize_t \ -field ## _store(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t size) \ -{ \ - int value; \ - if (sscanf(buf, format_string, &value) == 1) { \ - device_desc.field = value; \ - return size; \ - } \ - return -1; \ -} \ -static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, field ## _show, field ## _store); - -#define DESCRIPTOR_STRING_ATTR(field, buffer) \ -static ssize_t \ -field ## _show(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return sprintf(buf, "%s", buffer); \ -} \ -static ssize_t \ -field ## _store(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t size) \ -{ \ - if (size >= sizeof(buffer)) \ - return -EINVAL; \ - return strlcpy(buffer, buf, sizeof(buffer)); \ -} \ -static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, field ## _show, field ## _store); - - -DESCRIPTOR_ATTR(idVendor, "%04x\n") -DESCRIPTOR_ATTR(idProduct, "%04x\n") -DESCRIPTOR_ATTR(bcdDevice, "%04x\n") -DESCRIPTOR_ATTR(bDeviceClass, "%d\n") -DESCRIPTOR_ATTR(bDeviceSubClass, "%d\n") -DESCRIPTOR_ATTR(bDeviceProtocol, "%d\n") -DESCRIPTOR_STRING_ATTR(iManufacturer, manufacturer_string) -DESCRIPTOR_STRING_ATTR(iProduct, product_string) -DESCRIPTOR_STRING_ATTR(iSerial, serial_string) - -static DEVICE_ATTR(functions, S_IRUGO | S_IWUSR, functions_show, - functions_store); -static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store); -static DEVICE_ATTR(state, S_IRUGO, state_show, NULL); - -static struct device_attribute *android_usb_attributes[] = { - &dev_attr_idVendor, - &dev_attr_idProduct, - &dev_attr_bcdDevice, - &dev_attr_bDeviceClass, - &dev_attr_bDeviceSubClass, - &dev_attr_bDeviceProtocol, - &dev_attr_iManufacturer, - &dev_attr_iProduct, - &dev_attr_iSerial, - &dev_attr_functions, - &dev_attr_enable, - &dev_attr_state, - NULL -}; - -/*-------------------------------------------------------------------------*/ -/* Composite driver */ - -static int android_bind_config(struct usb_configuration *c) -{ - struct android_dev *dev = _android_dev; - int ret = 0; - - ret = android_bind_enabled_functions(dev, c); - if (ret) - return ret; - - return 0; -} - -static void android_unbind_config(struct usb_configuration *c) -{ - struct android_dev *dev = _android_dev; - - android_unbind_enabled_functions(dev, c); -} -unsigned char buf_android_serialno[32]; - -int get_android_serialno(void) -{ - int varlen =127; - int retval; - memset(buf_android_serialno,0,sizeof(buf_android_serialno)); - retval = wmt_getsyspara("androidboot.serialno", buf_android_serialno, &varlen); - if(!retval) - { - printk("androidboot.serialno=%s\n",buf_android_serialno); - return 0x0; - }else{ - printk("uboot variant androidboot.serialno do not exit\n"); - return -1; - } -} - -static int android_bind(struct usb_composite_dev *cdev) -{ - struct android_dev *dev = _android_dev; - struct usb_gadget *gadget = cdev->gadget; - int gcnum, id, ret; - - /* - * Start disconnected. Userspace will connect the gadget once - * it is done configuring the functions. - */ - usb_gadget_disconnect(gadget); - - ret = android_init_functions(dev->functions, cdev); - if (ret) - return ret; - - /* Allocate string descriptor numbers ... note that string - * contents can be overridden by the composite_dev glue. - */ - id = usb_string_id(cdev); - if (id < 0) - return id; - strings_dev[STRING_MANUFACTURER_IDX].id = id; - device_desc.iManufacturer = id; - - id = usb_string_id(cdev); - if (id < 0) - return id; - strings_dev[STRING_PRODUCT_IDX].id = id; - device_desc.iProduct = id; - - /* Default strings - should be updated by userspace */ - strncpy(manufacturer_string, "Android", sizeof(manufacturer_string)-1); - strncpy(product_string, "Android", sizeof(product_string) - 1); - - get_android_serialno(); - if(strlen(buf_android_serialno)==0){ - strncpy(serial_string, "0123456789ABCDEF", sizeof(serial_string) - 1); - printk("buf_android_serialno is null\n"); - }else{ - strncpy(serial_string, buf_android_serialno, sizeof(serial_string) - 1); - printk("buf_android_serialno:%s\n",buf_android_serialno); - } - - id = usb_string_id(cdev); - if (id < 0) - return id; - strings_dev[STRING_SERIAL_IDX].id = id; - device_desc.iSerialNumber = id; - - gcnum = usb_gadget_controller_number(gadget); - if (gcnum >= 0) - device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum); - else { - pr_warning("%s: controller '%s' not recognized\n", - longname, gadget->name); - device_desc.bcdDevice = __constant_cpu_to_le16(0x9999); - } - - usb_gadget_set_selfpowered(gadget); - dev->cdev = cdev; - - return 0; -} - -static int android_usb_unbind(struct usb_composite_dev *cdev) -{ - struct android_dev *dev = _android_dev; - - cancel_work_sync(&dev->work); - android_cleanup_functions(dev->functions); - return 0; -} - -static struct usb_composite_driver android_usb_driver = { - .name = "android_usb", - .dev = &device_desc, - .strings = dev_strings, - .unbind = android_usb_unbind, - .max_speed = USB_SPEED_HIGH, -}; - -static int -android_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *c) -{ - struct android_dev *dev = _android_dev; - struct usb_composite_dev *cdev = get_gadget_data(gadget); - struct usb_request *req = cdev->req; - struct android_usb_function *f; - int value = -EOPNOTSUPP; - unsigned long flags; - - req->zero = 0; - req->complete = composite_setup_complete; - req->length = 0; - gadget->ep0->driver_data = cdev; - - list_for_each_entry(f, &dev->enabled_functions, enabled_list) { - if (f->ctrlrequest) { - value = f->ctrlrequest(f, cdev, c); - if (value >= 0) - break; - } - } - - /* Special case the accessory function. - * It needs to handle control requests before it is enabled. - */ - if (value < 0) - value = acc_ctrlrequest(cdev, c); - - if (value < 0) - value = composite_setup(gadget, c); - - spin_lock_irqsave(&cdev->lock, flags); - if (!dev->connected) { - dev->connected = 1; - schedule_work(&dev->work); -#if defined(CONFIG_BATTERY_WMT) - wmt_do_pc_connected(); -#endif - } else if (c->bRequest == USB_REQ_SET_CONFIGURATION && - cdev->config) { - schedule_work(&dev->work); - } - spin_unlock_irqrestore(&cdev->lock, flags); - - return value; -} - -static void android_disconnect(struct usb_gadget *gadget) -{ - struct android_dev *dev = _android_dev; - struct usb_composite_dev *cdev = get_gadget_data(gadget); - unsigned long flags; - - composite_disconnect(gadget); - /* accessory HID support can be active while the - accessory function is not actually enabled, - so we need to inform it when we are disconnected. - */ - acc_disconnect(); - - spin_lock_irqsave(&cdev->lock, flags); - dev->connected = 0; - schedule_work(&dev->work); - spin_unlock_irqrestore(&cdev->lock, flags); -} - -static int android_create_device(struct android_dev *dev) -{ - struct device_attribute **attrs = android_usb_attributes; - struct device_attribute *attr; - int err; - - dev->dev = device_create(android_class, NULL, - MKDEV(0, 0), NULL, "android0"); - if (IS_ERR(dev->dev)) - return PTR_ERR(dev->dev); - - dev_set_drvdata(dev->dev, dev); - - while ((attr = *attrs++)) { - err = device_create_file(dev->dev, attr); - if (err) { - device_destroy(android_class, dev->dev->devt); - return err; - } - } - return 0; -} - -/* provide usb connected state for charger */ -int wmt_is_pc_connected(void) -{ - return _android_dev ? _android_dev->connected : 0; -} -EXPORT_SYMBOL(wmt_is_pc_connected); - -static int __init init(void) -{ - struct android_dev *dev; - int err; - - android_class = class_create(THIS_MODULE, "android_usb"); - if (IS_ERR(android_class)) - return PTR_ERR(android_class); - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - dev->disable_depth = 1; - dev->functions = supported_functions; - INIT_LIST_HEAD(&dev->enabled_functions); - INIT_WORK(&dev->work, android_work); - mutex_init(&dev->mutex); - - err = android_create_device(dev); - if (err) { - class_destroy(android_class); - kfree(dev); - return err; - } - - _android_dev = dev; - - /* Override composite driver functions */ - composite_driver.setup = android_setup; - composite_driver.disconnect = android_disconnect; - - return usb_composite_probe(&android_usb_driver, android_bind); -} -module_init(init); - -static void __exit cleanup(void) -{ - usb_composite_unregister(&android_usb_driver); - class_destroy(android_class); - kfree(_android_dev); - _android_dev = NULL; -} -module_exit(cleanup); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/at91_udc.c b/ANDROID_3.4.5/drivers/usb/gadget/at91_udc.c deleted file mode 100644 index 9d7bcd91..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/at91_udc.c +++ /dev/null @@ -1,2035 +0,0 @@ -/* - * at91_udc -- driver for at91-series USB peripheral controller - * - * Copyright (C) 2004 by Thomas Rathbone - * Copyright (C) 2005 by HP Labs - * Copyright (C) 2005 by David Brownell - * - * 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. - */ - -#undef VERBOSE_DEBUG -#undef PACKET_TRACE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "at91_udc.h" - - -/* - * This controller is simple and PIO-only. It's used in many AT91-series - * full speed USB controllers, including the at91rm9200 (arm920T, with MMU), - * at91sam926x (arm926ejs, with MMU), and several no-mmu versions. - * - * This driver expects the board has been wired with two GPIOs suppporting - * a VBUS sensing IRQ, and a D+ pullup. (They may be omitted, but the - * testing hasn't covered such cases.) - * - * The pullup is most important (so it's integrated on sam926x parts). It - * provides software control over whether the host enumerates the device. - * - * The VBUS sensing helps during enumeration, and allows both USB clocks - * (and the transceiver) to stay gated off until they're necessary, saving - * power. During USB suspend, the 48 MHz clock is gated off in hardware; - * it may also be gated off by software during some Linux sleep states. - */ - -#define DRIVER_VERSION "3 May 2006" - -static const char driver_name [] = "at91_udc"; -static const char ep0name[] = "ep0"; - -#define VBUS_POLL_TIMEOUT msecs_to_jiffies(1000) - -#define at91_udp_read(udc, reg) \ - __raw_readl((udc)->udp_baseaddr + (reg)) -#define at91_udp_write(udc, reg, val) \ - __raw_writel((val), (udc)->udp_baseaddr + (reg)) - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - -#include - -static const char debug_filename[] = "driver/udc"; - -#define FOURBITS "%s%s%s%s" -#define EIGHTBITS FOURBITS FOURBITS - -static void proc_ep_show(struct seq_file *s, struct at91_ep *ep) -{ - static char *types[] = { - "control", "out-iso", "out-bulk", "out-int", - "BOGUS", "in-iso", "in-bulk", "in-int"}; - - u32 csr; - struct at91_request *req; - unsigned long flags; - struct at91_udc *udc = ep->udc; - - spin_lock_irqsave(&udc->lock, flags); - - csr = __raw_readl(ep->creg); - - /* NOTE: not collecting per-endpoint irq statistics... */ - - seq_printf(s, "\n"); - seq_printf(s, "%s, maxpacket %d %s%s %s%s\n", - ep->ep.name, ep->ep.maxpacket, - ep->is_in ? "in" : "out", - ep->is_iso ? " iso" : "", - ep->is_pingpong - ? (ep->fifo_bank ? "pong" : "ping") - : "", - ep->stopped ? " stopped" : ""); - seq_printf(s, "csr %08x rxbytes=%d %s %s %s" EIGHTBITS "\n", - csr, - (csr & 0x07ff0000) >> 16, - (csr & (1 << 15)) ? "enabled" : "disabled", - (csr & (1 << 11)) ? "DATA1" : "DATA0", - types[(csr & 0x700) >> 8], - - /* iff type is control then print current direction */ - (!(csr & 0x700)) - ? ((csr & (1 << 7)) ? " IN" : " OUT") - : "", - (csr & (1 << 6)) ? " rxdatabk1" : "", - (csr & (1 << 5)) ? " forcestall" : "", - (csr & (1 << 4)) ? " txpktrdy" : "", - - (csr & (1 << 3)) ? " stallsent" : "", - (csr & (1 << 2)) ? " rxsetup" : "", - (csr & (1 << 1)) ? " rxdatabk0" : "", - (csr & (1 << 0)) ? " txcomp" : ""); - if (list_empty (&ep->queue)) - seq_printf(s, "\t(queue empty)\n"); - - else list_for_each_entry (req, &ep->queue, queue) { - unsigned length = req->req.actual; - - seq_printf(s, "\treq %p len %d/%d buf %p\n", - &req->req, length, - req->req.length, req->req.buf); - } - spin_unlock_irqrestore(&udc->lock, flags); -} - -static void proc_irq_show(struct seq_file *s, const char *label, u32 mask) -{ - int i; - - seq_printf(s, "%s %04x:%s%s" FOURBITS, label, mask, - (mask & (1 << 13)) ? " wakeup" : "", - (mask & (1 << 12)) ? " endbusres" : "", - - (mask & (1 << 11)) ? " sofint" : "", - (mask & (1 << 10)) ? " extrsm" : "", - (mask & (1 << 9)) ? " rxrsm" : "", - (mask & (1 << 8)) ? " rxsusp" : ""); - for (i = 0; i < 8; i++) { - if (mask & (1 << i)) - seq_printf(s, " ep%d", i); - } - seq_printf(s, "\n"); -} - -static int proc_udc_show(struct seq_file *s, void *unused) -{ - struct at91_udc *udc = s->private; - struct at91_ep *ep; - u32 tmp; - - seq_printf(s, "%s: version %s\n", driver_name, DRIVER_VERSION); - - seq_printf(s, "vbus %s, pullup %s, %s powered%s, gadget %s\n\n", - udc->vbus ? "present" : "off", - udc->enabled - ? (udc->vbus ? "active" : "enabled") - : "disabled", - udc->selfpowered ? "self" : "VBUS", - udc->suspended ? ", suspended" : "", - udc->driver ? udc->driver->driver.name : "(none)"); - - /* don't access registers when interface isn't clocked */ - if (!udc->clocked) { - seq_printf(s, "(not clocked)\n"); - return 0; - } - - tmp = at91_udp_read(udc, AT91_UDP_FRM_NUM); - seq_printf(s, "frame %05x:%s%s frame=%d\n", tmp, - (tmp & AT91_UDP_FRM_OK) ? " ok" : "", - (tmp & AT91_UDP_FRM_ERR) ? " err" : "", - (tmp & AT91_UDP_NUM)); - - tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT); - seq_printf(s, "glbstate %02x:%s" FOURBITS "\n", tmp, - (tmp & AT91_UDP_RMWUPE) ? " rmwupe" : "", - (tmp & AT91_UDP_RSMINPR) ? " rsminpr" : "", - (tmp & AT91_UDP_ESR) ? " esr" : "", - (tmp & AT91_UDP_CONFG) ? " confg" : "", - (tmp & AT91_UDP_FADDEN) ? " fadden" : ""); - - tmp = at91_udp_read(udc, AT91_UDP_FADDR); - seq_printf(s, "faddr %03x:%s fadd=%d\n", tmp, - (tmp & AT91_UDP_FEN) ? " fen" : "", - (tmp & AT91_UDP_FADD)); - - proc_irq_show(s, "imr ", at91_udp_read(udc, AT91_UDP_IMR)); - proc_irq_show(s, "isr ", at91_udp_read(udc, AT91_UDP_ISR)); - - if (udc->enabled && udc->vbus) { - proc_ep_show(s, &udc->ep[0]); - list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) { - if (ep->desc) - proc_ep_show(s, ep); - } - } - return 0; -} - -static int proc_udc_open(struct inode *inode, struct file *file) -{ - return single_open(file, proc_udc_show, PDE(inode)->data); -} - -static const struct file_operations proc_ops = { - .owner = THIS_MODULE, - .open = proc_udc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static void create_debug_file(struct at91_udc *udc) -{ - udc->pde = proc_create_data(debug_filename, 0, NULL, &proc_ops, udc); -} - -static void remove_debug_file(struct at91_udc *udc) -{ - if (udc->pde) - remove_proc_entry(debug_filename, NULL); -} - -#else - -static inline void create_debug_file(struct at91_udc *udc) {} -static inline void remove_debug_file(struct at91_udc *udc) {} - -#endif - - -/*-------------------------------------------------------------------------*/ - -static void done(struct at91_ep *ep, struct at91_request *req, int status) -{ - unsigned stopped = ep->stopped; - struct at91_udc *udc = ep->udc; - - list_del_init(&req->queue); - if (req->req.status == -EINPROGRESS) - req->req.status = status; - else - status = req->req.status; - if (status && status != -ESHUTDOWN) - VDBG("%s done %p, status %d\n", ep->ep.name, req, status); - - ep->stopped = 1; - spin_unlock(&udc->lock); - req->req.complete(&ep->ep, &req->req); - spin_lock(&udc->lock); - ep->stopped = stopped; - - /* ep0 is always ready; other endpoints need a non-empty queue */ - if (list_empty(&ep->queue) && ep->int_mask != (1 << 0)) - at91_udp_write(udc, AT91_UDP_IDR, ep->int_mask); -} - -/*-------------------------------------------------------------------------*/ - -/* bits indicating OUT fifo has data ready */ -#define RX_DATA_READY (AT91_UDP_RX_DATA_BK0 | AT91_UDP_RX_DATA_BK1) - -/* - * Endpoint FIFO CSR bits have a mix of bits, making it unsafe to just write - * back most of the value you just read (because of side effects, including - * bits that may change after reading and before writing). - * - * Except when changing a specific bit, always write values which: - * - clear SET_FX bits (setting them could change something) - * - set CLR_FX bits (clearing them could change something) - * - * There are also state bits like FORCESTALL, EPEDS, DIR, and EPTYPE - * that shouldn't normally be changed. - * - * NOTE at91sam9260 docs mention synch between UDPCK and MCK clock domains, - * implying a need to wait for one write to complete (test relevant bits) - * before starting the next write. This shouldn't be an issue given how - * infrequently we write, except maybe for write-then-read idioms. - */ -#define SET_FX (AT91_UDP_TXPKTRDY) -#define CLR_FX (RX_DATA_READY | AT91_UDP_RXSETUP \ - | AT91_UDP_STALLSENT | AT91_UDP_TXCOMP) - -/* pull OUT packet data from the endpoint's fifo */ -static int read_fifo (struct at91_ep *ep, struct at91_request *req) -{ - u32 __iomem *creg = ep->creg; - u8 __iomem *dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0)); - u32 csr; - u8 *buf; - unsigned int count, bufferspace, is_done; - - buf = req->req.buf + req->req.actual; - bufferspace = req->req.length - req->req.actual; - - /* - * there might be nothing to read if ep_queue() calls us, - * or if we already emptied both pingpong buffers - */ -rescan: - csr = __raw_readl(creg); - if ((csr & RX_DATA_READY) == 0) - return 0; - - count = (csr & AT91_UDP_RXBYTECNT) >> 16; - if (count > ep->ep.maxpacket) - count = ep->ep.maxpacket; - if (count > bufferspace) { - DBG("%s buffer overflow\n", ep->ep.name); - req->req.status = -EOVERFLOW; - count = bufferspace; - } - __raw_readsb(dreg, buf, count); - - /* release and swap pingpong mem bank */ - csr |= CLR_FX; - if (ep->is_pingpong) { - if (ep->fifo_bank == 0) { - csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0); - ep->fifo_bank = 1; - } else { - csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK1); - ep->fifo_bank = 0; - } - } else - csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0); - __raw_writel(csr, creg); - - req->req.actual += count; - is_done = (count < ep->ep.maxpacket); - if (count == bufferspace) - is_done = 1; - - PACKET("%s %p out/%d%s\n", ep->ep.name, &req->req, count, - is_done ? " (done)" : ""); - - /* - * avoid extra trips through IRQ logic for packets already in - * the fifo ... maybe preventing an extra (expensive) OUT-NAK - */ - if (is_done) - done(ep, req, 0); - else if (ep->is_pingpong) { - /* - * One dummy read to delay the code because of a HW glitch: - * CSR returns bad RXCOUNT when read too soon after updating - * RX_DATA_BK flags. - */ - csr = __raw_readl(creg); - - bufferspace -= count; - buf += count; - goto rescan; - } - - return is_done; -} - -/* load fifo for an IN packet */ -static int write_fifo(struct at91_ep *ep, struct at91_request *req) -{ - u32 __iomem *creg = ep->creg; - u32 csr = __raw_readl(creg); - u8 __iomem *dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0)); - unsigned total, count, is_last; - u8 *buf; - - /* - * TODO: allow for writing two packets to the fifo ... that'll - * reduce the amount of IN-NAKing, but probably won't affect - * throughput much. (Unlike preventing OUT-NAKing!) - */ - - /* - * If ep_queue() calls us, the queue is empty and possibly in - * odd states like TXCOMP not yet cleared (we do it, saving at - * least one IRQ) or the fifo not yet being free. Those aren't - * issues normally (IRQ handler fast path). - */ - if (unlikely(csr & (AT91_UDP_TXCOMP | AT91_UDP_TXPKTRDY))) { - if (csr & AT91_UDP_TXCOMP) { - csr |= CLR_FX; - csr &= ~(SET_FX | AT91_UDP_TXCOMP); - __raw_writel(csr, creg); - csr = __raw_readl(creg); - } - if (csr & AT91_UDP_TXPKTRDY) - return 0; - } - - buf = req->req.buf + req->req.actual; - prefetch(buf); - total = req->req.length - req->req.actual; - if (ep->ep.maxpacket < total) { - count = ep->ep.maxpacket; - is_last = 0; - } else { - count = total; - is_last = (count < ep->ep.maxpacket) || !req->req.zero; - } - - /* - * Write the packet, maybe it's a ZLP. - * - * NOTE: incrementing req->actual before we receive the ACK means - * gadget driver IN bytecounts can be wrong in fault cases. That's - * fixable with PIO drivers like this one (save "count" here, and - * do the increment later on TX irq), but not for most DMA hardware. - * - * So all gadget drivers must accept that potential error. Some - * hardware supports precise fifo status reporting, letting them - * recover when the actual bytecount matters (e.g. for USB Test - * and Measurement Class devices). - */ - __raw_writesb(dreg, buf, count); - csr &= ~SET_FX; - csr |= CLR_FX | AT91_UDP_TXPKTRDY; - __raw_writel(csr, creg); - req->req.actual += count; - - PACKET("%s %p in/%d%s\n", ep->ep.name, &req->req, count, - is_last ? " (done)" : ""); - if (is_last) - done(ep, req, 0); - return is_last; -} - -static void nuke(struct at91_ep *ep, int status) -{ - struct at91_request *req; - - /* terminate any request in the queue */ - ep->stopped = 1; - if (list_empty(&ep->queue)) - return; - - VDBG("%s %s\n", __func__, ep->ep.name); - while (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, struct at91_request, queue); - done(ep, req, status); - } -} - -/*-------------------------------------------------------------------------*/ - -static int at91_ep_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct at91_ep *ep = container_of(_ep, struct at91_ep, ep); - struct at91_udc *udc = ep->udc; - u16 maxpacket; - u32 tmp; - unsigned long flags; - - if (!_ep || !ep - || !desc || ep->desc - || _ep->name == ep0name - || desc->bDescriptorType != USB_DT_ENDPOINT - || (maxpacket = usb_endpoint_maxp(desc)) == 0 - || maxpacket > ep->maxpacket) { - DBG("bad ep or descriptor\n"); - return -EINVAL; - } - - if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) { - DBG("bogus device state\n"); - return -ESHUTDOWN; - } - - tmp = usb_endpoint_type(desc); - switch (tmp) { - case USB_ENDPOINT_XFER_CONTROL: - DBG("only one control endpoint\n"); - return -EINVAL; - case USB_ENDPOINT_XFER_INT: - if (maxpacket > 64) - goto bogus_max; - break; - case USB_ENDPOINT_XFER_BULK: - switch (maxpacket) { - case 8: - case 16: - case 32: - case 64: - goto ok; - } -bogus_max: - DBG("bogus maxpacket %d\n", maxpacket); - return -EINVAL; - case USB_ENDPOINT_XFER_ISOC: - if (!ep->is_pingpong) { - DBG("iso requires double buffering\n"); - return -EINVAL; - } - break; - } - -ok: - spin_lock_irqsave(&udc->lock, flags); - - /* initialize endpoint to match this descriptor */ - ep->is_in = usb_endpoint_dir_in(desc); - ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC); - ep->stopped = 0; - if (ep->is_in) - tmp |= 0x04; - tmp <<= 8; - tmp |= AT91_UDP_EPEDS; - __raw_writel(tmp, ep->creg); - - ep->desc = desc; - ep->ep.maxpacket = maxpacket; - - /* - * reset/init endpoint fifo. NOTE: leaves fifo_bank alone, - * since endpoint resets don't reset hw pingpong state. - */ - at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask); - at91_udp_write(udc, AT91_UDP_RST_EP, 0); - - spin_unlock_irqrestore(&udc->lock, flags); - return 0; -} - -static int at91_ep_disable (struct usb_ep * _ep) -{ - struct at91_ep *ep = container_of(_ep, struct at91_ep, ep); - struct at91_udc *udc = ep->udc; - unsigned long flags; - - if (ep == &ep->udc->ep[0]) - return -EINVAL; - - spin_lock_irqsave(&udc->lock, flags); - - nuke(ep, -ESHUTDOWN); - - /* restore the endpoint's pristine config */ - ep->desc = NULL; - ep->ep.desc = NULL; - ep->ep.maxpacket = ep->maxpacket; - - /* reset fifos and endpoint */ - if (ep->udc->clocked) { - at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask); - at91_udp_write(udc, AT91_UDP_RST_EP, 0); - __raw_writel(0, ep->creg); - } - - spin_unlock_irqrestore(&udc->lock, flags); - return 0; -} - -/* - * this is a PIO-only driver, so there's nothing - * interesting for request or buffer allocation. - */ - -static struct usb_request * -at91_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) -{ - struct at91_request *req; - - req = kzalloc(sizeof (struct at91_request), gfp_flags); - if (!req) - return NULL; - - INIT_LIST_HEAD(&req->queue); - return &req->req; -} - -static void at91_ep_free_request(struct usb_ep *_ep, struct usb_request *_req) -{ - struct at91_request *req; - - req = container_of(_req, struct at91_request, req); - BUG_ON(!list_empty(&req->queue)); - kfree(req); -} - -static int at91_ep_queue(struct usb_ep *_ep, - struct usb_request *_req, gfp_t gfp_flags) -{ - struct at91_request *req; - struct at91_ep *ep; - struct at91_udc *udc; - int status; - unsigned long flags; - - req = container_of(_req, struct at91_request, req); - ep = container_of(_ep, struct at91_ep, ep); - - if (!_req || !_req->complete - || !_req->buf || !list_empty(&req->queue)) { - DBG("invalid request\n"); - return -EINVAL; - } - - if (!_ep || (!ep->desc && ep->ep.name != ep0name)) { - DBG("invalid ep\n"); - return -EINVAL; - } - - udc = ep->udc; - - if (!udc || !udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) { - DBG("invalid device\n"); - return -EINVAL; - } - - _req->status = -EINPROGRESS; - _req->actual = 0; - - spin_lock_irqsave(&udc->lock, flags); - - /* try to kickstart any empty and idle queue */ - if (list_empty(&ep->queue) && !ep->stopped) { - int is_ep0; - - /* - * If this control request has a non-empty DATA stage, this - * will start that stage. It works just like a non-control - * request (until the status stage starts, maybe early). - * - * If the data stage is empty, then this starts a successful - * IN/STATUS stage. (Unsuccessful ones use set_halt.) - */ - is_ep0 = (ep->ep.name == ep0name); - if (is_ep0) { - u32 tmp; - - if (!udc->req_pending) { - status = -EINVAL; - goto done; - } - - /* - * defer changing CONFG until after the gadget driver - * reconfigures the endpoints. - */ - if (udc->wait_for_config_ack) { - tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT); - tmp ^= AT91_UDP_CONFG; - VDBG("toggle config\n"); - at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp); - } - if (req->req.length == 0) { -ep0_in_status: - PACKET("ep0 in/status\n"); - status = 0; - tmp = __raw_readl(ep->creg); - tmp &= ~SET_FX; - tmp |= CLR_FX | AT91_UDP_TXPKTRDY; - __raw_writel(tmp, ep->creg); - udc->req_pending = 0; - goto done; - } - } - - if (ep->is_in) - status = write_fifo(ep, req); - else { - status = read_fifo(ep, req); - - /* IN/STATUS stage is otherwise triggered by irq */ - if (status && is_ep0) - goto ep0_in_status; - } - } else - status = 0; - - if (req && !status) { - list_add_tail (&req->queue, &ep->queue); - at91_udp_write(udc, AT91_UDP_IER, ep->int_mask); - } -done: - spin_unlock_irqrestore(&udc->lock, flags); - return (status < 0) ? status : 0; -} - -static int at91_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct at91_ep *ep; - struct at91_request *req; - unsigned long flags; - struct at91_udc *udc; - - ep = container_of(_ep, struct at91_ep, ep); - if (!_ep || ep->ep.name == ep0name) - return -EINVAL; - - udc = ep->udc; - - spin_lock_irqsave(&udc->lock, flags); - - /* make sure it's actually queued on this endpoint */ - list_for_each_entry (req, &ep->queue, queue) { - if (&req->req == _req) - break; - } - if (&req->req != _req) { - spin_unlock_irqrestore(&udc->lock, flags); - return -EINVAL; - } - - done(ep, req, -ECONNRESET); - spin_unlock_irqrestore(&udc->lock, flags); - return 0; -} - -static int at91_ep_set_halt(struct usb_ep *_ep, int value) -{ - struct at91_ep *ep = container_of(_ep, struct at91_ep, ep); - struct at91_udc *udc = ep->udc; - u32 __iomem *creg; - u32 csr; - unsigned long flags; - int status = 0; - - if (!_ep || ep->is_iso || !ep->udc->clocked) - return -EINVAL; - - creg = ep->creg; - spin_lock_irqsave(&udc->lock, flags); - - csr = __raw_readl(creg); - - /* - * fail with still-busy IN endpoints, ensuring correct sequencing - * of data tx then stall. note that the fifo rx bytecount isn't - * completely accurate as a tx bytecount. - */ - if (ep->is_in && (!list_empty(&ep->queue) || (csr >> 16) != 0)) - status = -EAGAIN; - else { - csr |= CLR_FX; - csr &= ~SET_FX; - if (value) { - csr |= AT91_UDP_FORCESTALL; - VDBG("halt %s\n", ep->ep.name); - } else { - at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask); - at91_udp_write(udc, AT91_UDP_RST_EP, 0); - csr &= ~AT91_UDP_FORCESTALL; - } - __raw_writel(csr, creg); - } - - spin_unlock_irqrestore(&udc->lock, flags); - return status; -} - -static const struct usb_ep_ops at91_ep_ops = { - .enable = at91_ep_enable, - .disable = at91_ep_disable, - .alloc_request = at91_ep_alloc_request, - .free_request = at91_ep_free_request, - .queue = at91_ep_queue, - .dequeue = at91_ep_dequeue, - .set_halt = at91_ep_set_halt, - /* there's only imprecise fifo status reporting */ -}; - -/*-------------------------------------------------------------------------*/ - -static int at91_get_frame(struct usb_gadget *gadget) -{ - struct at91_udc *udc = to_udc(gadget); - - if (!to_udc(gadget)->clocked) - return -EINVAL; - return at91_udp_read(udc, AT91_UDP_FRM_NUM) & AT91_UDP_NUM; -} - -static int at91_wakeup(struct usb_gadget *gadget) -{ - struct at91_udc *udc = to_udc(gadget); - u32 glbstate; - int status = -EINVAL; - unsigned long flags; - - DBG("%s\n", __func__ ); - spin_lock_irqsave(&udc->lock, flags); - - if (!udc->clocked || !udc->suspended) - goto done; - - /* NOTE: some "early versions" handle ESR differently ... */ - - glbstate = at91_udp_read(udc, AT91_UDP_GLB_STAT); - if (!(glbstate & AT91_UDP_ESR)) - goto done; - glbstate |= AT91_UDP_ESR; - at91_udp_write(udc, AT91_UDP_GLB_STAT, glbstate); - -done: - spin_unlock_irqrestore(&udc->lock, flags); - return status; -} - -/* reinit == restore initial software state */ -static void udc_reinit(struct at91_udc *udc) -{ - u32 i; - - INIT_LIST_HEAD(&udc->gadget.ep_list); - INIT_LIST_HEAD(&udc->gadget.ep0->ep_list); - - for (i = 0; i < NUM_ENDPOINTS; i++) { - struct at91_ep *ep = &udc->ep[i]; - - if (i != 0) - list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); - ep->desc = NULL; - ep->stopped = 0; - ep->fifo_bank = 0; - ep->ep.maxpacket = ep->maxpacket; - ep->creg = (void __iomem *) udc->udp_baseaddr + AT91_UDP_CSR(i); - /* initialize one queue per endpoint */ - INIT_LIST_HEAD(&ep->queue); - } -} - -static void stop_activity(struct at91_udc *udc) -{ - struct usb_gadget_driver *driver = udc->driver; - int i; - - if (udc->gadget.speed == USB_SPEED_UNKNOWN) - driver = NULL; - udc->gadget.speed = USB_SPEED_UNKNOWN; - udc->suspended = 0; - - for (i = 0; i < NUM_ENDPOINTS; i++) { - struct at91_ep *ep = &udc->ep[i]; - ep->stopped = 1; - nuke(ep, -ESHUTDOWN); - } - if (driver) { - spin_unlock(&udc->lock); - driver->disconnect(&udc->gadget); - spin_lock(&udc->lock); - } - - udc_reinit(udc); -} - -static void clk_on(struct at91_udc *udc) -{ - if (udc->clocked) - return; - udc->clocked = 1; - clk_enable(udc->iclk); - clk_enable(udc->fclk); -} - -static void clk_off(struct at91_udc *udc) -{ - if (!udc->clocked) - return; - udc->clocked = 0; - udc->gadget.speed = USB_SPEED_UNKNOWN; - clk_disable(udc->fclk); - clk_disable(udc->iclk); -} - -/* - * activate/deactivate link with host; minimize power usage for - * inactive links by cutting clocks and transceiver power. - */ -static void pullup(struct at91_udc *udc, int is_on) -{ - int active = !udc->board.pullup_active_low; - - if (!udc->enabled || !udc->vbus) - is_on = 0; - DBG("%sactive\n", is_on ? "" : "in"); - - if (is_on) { - clk_on(udc); - at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM); - at91_udp_write(udc, AT91_UDP_TXVC, 0); - if (cpu_is_at91rm9200()) - gpio_set_value(udc->board.pullup_pin, active); - else if (cpu_is_at91sam9260() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) { - u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC); - - txvc |= AT91_UDP_TXVC_PUON; - at91_udp_write(udc, AT91_UDP_TXVC, txvc); - } else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) { - u32 usbpucr; - - usbpucr = at91_matrix_read(AT91_MATRIX_USBPUCR); - usbpucr |= AT91_MATRIX_USBPUCR_PUON; - at91_matrix_write(AT91_MATRIX_USBPUCR, usbpucr); - } - } else { - stop_activity(udc); - at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM); - at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); - if (cpu_is_at91rm9200()) - gpio_set_value(udc->board.pullup_pin, !active); - else if (cpu_is_at91sam9260() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) { - u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC); - - txvc &= ~AT91_UDP_TXVC_PUON; - at91_udp_write(udc, AT91_UDP_TXVC, txvc); - } else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) { - u32 usbpucr; - - usbpucr = at91_matrix_read(AT91_MATRIX_USBPUCR); - usbpucr &= ~AT91_MATRIX_USBPUCR_PUON; - at91_matrix_write(AT91_MATRIX_USBPUCR, usbpucr); - } - clk_off(udc); - } -} - -/* vbus is here! turn everything on that's ready */ -static int at91_vbus_session(struct usb_gadget *gadget, int is_active) -{ - struct at91_udc *udc = to_udc(gadget); - unsigned long flags; - - /* VDBG("vbus %s\n", is_active ? "on" : "off"); */ - spin_lock_irqsave(&udc->lock, flags); - udc->vbus = (is_active != 0); - if (udc->driver) - pullup(udc, is_active); - else - pullup(udc, 0); - spin_unlock_irqrestore(&udc->lock, flags); - return 0; -} - -static int at91_pullup(struct usb_gadget *gadget, int is_on) -{ - struct at91_udc *udc = to_udc(gadget); - unsigned long flags; - - spin_lock_irqsave(&udc->lock, flags); - udc->enabled = is_on = !!is_on; - pullup(udc, is_on); - spin_unlock_irqrestore(&udc->lock, flags); - return 0; -} - -static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on) -{ - struct at91_udc *udc = to_udc(gadget); - unsigned long flags; - - spin_lock_irqsave(&udc->lock, flags); - udc->selfpowered = (is_on != 0); - spin_unlock_irqrestore(&udc->lock, flags); - return 0; -} - -static int at91_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int at91_stop(struct usb_gadget_driver *driver); - -static const struct usb_gadget_ops at91_udc_ops = { - .get_frame = at91_get_frame, - .wakeup = at91_wakeup, - .set_selfpowered = at91_set_selfpowered, - .vbus_session = at91_vbus_session, - .pullup = at91_pullup, - .start = at91_start, - .stop = at91_stop, - - /* - * VBUS-powered devices may also also want to support bigger - * power budgets after an appropriate SET_CONFIGURATION. - */ - /* .vbus_power = at91_vbus_power, */ -}; - -/*-------------------------------------------------------------------------*/ - -static int handle_ep(struct at91_ep *ep) -{ - struct at91_request *req; - u32 __iomem *creg = ep->creg; - u32 csr = __raw_readl(creg); - - if (!list_empty(&ep->queue)) - req = list_entry(ep->queue.next, - struct at91_request, queue); - else - req = NULL; - - if (ep->is_in) { - if (csr & (AT91_UDP_STALLSENT | AT91_UDP_TXCOMP)) { - csr |= CLR_FX; - csr &= ~(SET_FX | AT91_UDP_STALLSENT | AT91_UDP_TXCOMP); - __raw_writel(csr, creg); - } - if (req) - return write_fifo(ep, req); - - } else { - if (csr & AT91_UDP_STALLSENT) { - /* STALLSENT bit == ISOERR */ - if (ep->is_iso && req) - req->req.status = -EILSEQ; - csr |= CLR_FX; - csr &= ~(SET_FX | AT91_UDP_STALLSENT); - __raw_writel(csr, creg); - csr = __raw_readl(creg); - } - if (req && (csr & RX_DATA_READY)) - return read_fifo(ep, req); - } - return 0; -} - -union setup { - u8 raw[8]; - struct usb_ctrlrequest r; -}; - -static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) -{ - u32 __iomem *creg = ep->creg; - u8 __iomem *dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0)); - unsigned rxcount, i = 0; - u32 tmp; - union setup pkt; - int status = 0; - - /* read and ack SETUP; hard-fail for bogus packets */ - rxcount = (csr & AT91_UDP_RXBYTECNT) >> 16; - if (likely(rxcount == 8)) { - while (rxcount--) - pkt.raw[i++] = __raw_readb(dreg); - if (pkt.r.bRequestType & USB_DIR_IN) { - csr |= AT91_UDP_DIR; - ep->is_in = 1; - } else { - csr &= ~AT91_UDP_DIR; - ep->is_in = 0; - } - } else { - /* REVISIT this happens sometimes under load; why?? */ - ERR("SETUP len %d, csr %08x\n", rxcount, csr); - status = -EINVAL; - } - csr |= CLR_FX; - csr &= ~(SET_FX | AT91_UDP_RXSETUP); - __raw_writel(csr, creg); - udc->wait_for_addr_ack = 0; - udc->wait_for_config_ack = 0; - ep->stopped = 0; - if (unlikely(status != 0)) - goto stall; - -#define w_index le16_to_cpu(pkt.r.wIndex) -#define w_value le16_to_cpu(pkt.r.wValue) -#define w_length le16_to_cpu(pkt.r.wLength) - - VDBG("SETUP %02x.%02x v%04x i%04x l%04x\n", - pkt.r.bRequestType, pkt.r.bRequest, - w_value, w_index, w_length); - - /* - * A few standard requests get handled here, ones that touch - * hardware ... notably for device and endpoint features. - */ - udc->req_pending = 1; - csr = __raw_readl(creg); - csr |= CLR_FX; - csr &= ~SET_FX; - switch ((pkt.r.bRequestType << 8) | pkt.r.bRequest) { - - case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8) - | USB_REQ_SET_ADDRESS: - __raw_writel(csr | AT91_UDP_TXPKTRDY, creg); - udc->addr = w_value; - udc->wait_for_addr_ack = 1; - udc->req_pending = 0; - /* FADDR is set later, when we ack host STATUS */ - return; - - case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8) - | USB_REQ_SET_CONFIGURATION: - tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_CONFG; - if (pkt.r.wValue) - udc->wait_for_config_ack = (tmp == 0); - else - udc->wait_for_config_ack = (tmp != 0); - if (udc->wait_for_config_ack) - VDBG("wait for config\n"); - /* CONFG is toggled later, if gadget driver succeeds */ - break; - - /* - * Hosts may set or clear remote wakeup status, and - * devices may report they're VBUS powered. - */ - case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8) - | USB_REQ_GET_STATUS: - tmp = (udc->selfpowered << USB_DEVICE_SELF_POWERED); - if (at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_ESR) - tmp |= (1 << USB_DEVICE_REMOTE_WAKEUP); - PACKET("get device status\n"); - __raw_writeb(tmp, dreg); - __raw_writeb(0, dreg); - goto write_in; - /* then STATUS starts later, automatically */ - case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8) - | USB_REQ_SET_FEATURE: - if (w_value != USB_DEVICE_REMOTE_WAKEUP) - goto stall; - tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT); - tmp |= AT91_UDP_ESR; - at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp); - goto succeed; - case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8) - | USB_REQ_CLEAR_FEATURE: - if (w_value != USB_DEVICE_REMOTE_WAKEUP) - goto stall; - tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT); - tmp &= ~AT91_UDP_ESR; - at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp); - goto succeed; - - /* - * Interfaces have no feature settings; this is pretty useless. - * we won't even insist the interface exists... - */ - case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8) - | USB_REQ_GET_STATUS: - PACKET("get interface status\n"); - __raw_writeb(0, dreg); - __raw_writeb(0, dreg); - goto write_in; - /* then STATUS starts later, automatically */ - case ((USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8) - | USB_REQ_SET_FEATURE: - case ((USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8) - | USB_REQ_CLEAR_FEATURE: - goto stall; - - /* - * Hosts may clear bulk/intr endpoint halt after the gadget - * driver sets it (not widely used); or set it (for testing) - */ - case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8) - | USB_REQ_GET_STATUS: - tmp = w_index & USB_ENDPOINT_NUMBER_MASK; - ep = &udc->ep[tmp]; - if (tmp >= NUM_ENDPOINTS || (tmp && !ep->desc)) - goto stall; - - if (tmp) { - if ((w_index & USB_DIR_IN)) { - if (!ep->is_in) - goto stall; - } else if (ep->is_in) - goto stall; - } - PACKET("get %s status\n", ep->ep.name); - if (__raw_readl(ep->creg) & AT91_UDP_FORCESTALL) - tmp = (1 << USB_ENDPOINT_HALT); - else - tmp = 0; - __raw_writeb(tmp, dreg); - __raw_writeb(0, dreg); - goto write_in; - /* then STATUS starts later, automatically */ - case ((USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8) - | USB_REQ_SET_FEATURE: - tmp = w_index & USB_ENDPOINT_NUMBER_MASK; - ep = &udc->ep[tmp]; - if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS) - goto stall; - if (!ep->desc || ep->is_iso) - goto stall; - if ((w_index & USB_DIR_IN)) { - if (!ep->is_in) - goto stall; - } else if (ep->is_in) - goto stall; - - tmp = __raw_readl(ep->creg); - tmp &= ~SET_FX; - tmp |= CLR_FX | AT91_UDP_FORCESTALL; - __raw_writel(tmp, ep->creg); - goto succeed; - case ((USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8) - | USB_REQ_CLEAR_FEATURE: - tmp = w_index & USB_ENDPOINT_NUMBER_MASK; - ep = &udc->ep[tmp]; - if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS) - goto stall; - if (tmp == 0) - goto succeed; - if (!ep->desc || ep->is_iso) - goto stall; - if ((w_index & USB_DIR_IN)) { - if (!ep->is_in) - goto stall; - } else if (ep->is_in) - goto stall; - - at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask); - at91_udp_write(udc, AT91_UDP_RST_EP, 0); - tmp = __raw_readl(ep->creg); - tmp |= CLR_FX; - tmp &= ~(SET_FX | AT91_UDP_FORCESTALL); - __raw_writel(tmp, ep->creg); - if (!list_empty(&ep->queue)) - handle_ep(ep); - goto succeed; - } - -#undef w_value -#undef w_index -#undef w_length - - /* pass request up to the gadget driver */ - if (udc->driver) { - spin_unlock(&udc->lock); - status = udc->driver->setup(&udc->gadget, &pkt.r); - spin_lock(&udc->lock); - } - else - status = -ENODEV; - if (status < 0) { -stall: - VDBG("req %02x.%02x protocol STALL; stat %d\n", - pkt.r.bRequestType, pkt.r.bRequest, status); - csr |= AT91_UDP_FORCESTALL; - __raw_writel(csr, creg); - udc->req_pending = 0; - } - return; - -succeed: - /* immediate successful (IN) STATUS after zero length DATA */ - PACKET("ep0 in/status\n"); -write_in: - csr |= AT91_UDP_TXPKTRDY; - __raw_writel(csr, creg); - udc->req_pending = 0; -} - -static void handle_ep0(struct at91_udc *udc) -{ - struct at91_ep *ep0 = &udc->ep[0]; - u32 __iomem *creg = ep0->creg; - u32 csr = __raw_readl(creg); - struct at91_request *req; - - if (unlikely(csr & AT91_UDP_STALLSENT)) { - nuke(ep0, -EPROTO); - udc->req_pending = 0; - csr |= CLR_FX; - csr &= ~(SET_FX | AT91_UDP_STALLSENT | AT91_UDP_FORCESTALL); - __raw_writel(csr, creg); - VDBG("ep0 stalled\n"); - csr = __raw_readl(creg); - } - if (csr & AT91_UDP_RXSETUP) { - nuke(ep0, 0); - udc->req_pending = 0; - handle_setup(udc, ep0, csr); - return; - } - - if (list_empty(&ep0->queue)) - req = NULL; - else - req = list_entry(ep0->queue.next, struct at91_request, queue); - - /* host ACKed an IN packet that we sent */ - if (csr & AT91_UDP_TXCOMP) { - csr |= CLR_FX; - csr &= ~(SET_FX | AT91_UDP_TXCOMP); - - /* write more IN DATA? */ - if (req && ep0->is_in) { - if (handle_ep(ep0)) - udc->req_pending = 0; - - /* - * Ack after: - * - last IN DATA packet (including GET_STATUS) - * - IN/STATUS for OUT DATA - * - IN/STATUS for any zero-length DATA stage - * except for the IN DATA case, the host should send - * an OUT status later, which we'll ack. - */ - } else { - udc->req_pending = 0; - __raw_writel(csr, creg); - - /* - * SET_ADDRESS takes effect only after the STATUS - * (to the original address) gets acked. - */ - if (udc->wait_for_addr_ack) { - u32 tmp; - - at91_udp_write(udc, AT91_UDP_FADDR, - AT91_UDP_FEN | udc->addr); - tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT); - tmp &= ~AT91_UDP_FADDEN; - if (udc->addr) - tmp |= AT91_UDP_FADDEN; - at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp); - - udc->wait_for_addr_ack = 0; - VDBG("address %d\n", udc->addr); - } - } - } - - /* OUT packet arrived ... */ - else if (csr & AT91_UDP_RX_DATA_BK0) { - csr |= CLR_FX; - csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0); - - /* OUT DATA stage */ - if (!ep0->is_in) { - if (req) { - if (handle_ep(ep0)) { - /* send IN/STATUS */ - PACKET("ep0 in/status\n"); - csr = __raw_readl(creg); - csr &= ~SET_FX; - csr |= CLR_FX | AT91_UDP_TXPKTRDY; - __raw_writel(csr, creg); - udc->req_pending = 0; - } - } else if (udc->req_pending) { - /* - * AT91 hardware has a hard time with this - * "deferred response" mode for control-OUT - * transfers. (For control-IN it's fine.) - * - * The normal solution leaves OUT data in the - * fifo until the gadget driver is ready. - * We couldn't do that here without disabling - * the IRQ that tells about SETUP packets, - * e.g. when the host gets impatient... - * - * Working around it by copying into a buffer - * would almost be a non-deferred response, - * except that it wouldn't permit reliable - * stalling of the request. Instead, demand - * that gadget drivers not use this mode. - */ - DBG("no control-OUT deferred responses!\n"); - __raw_writel(csr | AT91_UDP_FORCESTALL, creg); - udc->req_pending = 0; - } - - /* STATUS stage for control-IN; ack. */ - } else { - PACKET("ep0 out/status ACK\n"); - __raw_writel(csr, creg); - - /* "early" status stage */ - if (req) - done(ep0, req, 0); - } - } -} - -static irqreturn_t at91_udc_irq (int irq, void *_udc) -{ - struct at91_udc *udc = _udc; - u32 rescans = 5; - int disable_clock = 0; - unsigned long flags; - - spin_lock_irqsave(&udc->lock, flags); - - if (!udc->clocked) { - clk_on(udc); - disable_clock = 1; - } - - while (rescans--) { - u32 status; - - status = at91_udp_read(udc, AT91_UDP_ISR) - & at91_udp_read(udc, AT91_UDP_IMR); - if (!status) - break; - - /* USB reset irq: not maskable */ - if (status & AT91_UDP_ENDBUSRES) { - at91_udp_write(udc, AT91_UDP_IDR, ~MINIMUS_INTERRUPTUS); - at91_udp_write(udc, AT91_UDP_IER, MINIMUS_INTERRUPTUS); - /* Atmel code clears this irq twice */ - at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_ENDBUSRES); - at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_ENDBUSRES); - VDBG("end bus reset\n"); - udc->addr = 0; - stop_activity(udc); - - /* enable ep0 */ - at91_udp_write(udc, AT91_UDP_CSR(0), - AT91_UDP_EPEDS | AT91_UDP_EPTYPE_CTRL); - udc->gadget.speed = USB_SPEED_FULL; - udc->suspended = 0; - at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_EP(0)); - - /* - * NOTE: this driver keeps clocks off unless the - * USB host is present. That saves power, but for - * boards that don't support VBUS detection, both - * clocks need to be active most of the time. - */ - - /* host initiated suspend (3+ms bus idle) */ - } else if (status & AT91_UDP_RXSUSP) { - at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXSUSP); - at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_RXRSM); - at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXSUSP); - /* VDBG("bus suspend\n"); */ - if (udc->suspended) - continue; - udc->suspended = 1; - - /* - * NOTE: when suspending a VBUS-powered device, the - * gadget driver should switch into slow clock mode - * and then into standby to avoid drawing more than - * 500uA power (2500uA for some high-power configs). - */ - if (udc->driver && udc->driver->suspend) { - spin_unlock(&udc->lock); - udc->driver->suspend(&udc->gadget); - spin_lock(&udc->lock); - } - - /* host initiated resume */ - } else if (status & AT91_UDP_RXRSM) { - at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM); - at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_RXSUSP); - at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM); - /* VDBG("bus resume\n"); */ - if (!udc->suspended) - continue; - udc->suspended = 0; - - /* - * NOTE: for a VBUS-powered device, the gadget driver - * would normally want to switch out of slow clock - * mode into normal mode. - */ - if (udc->driver && udc->driver->resume) { - spin_unlock(&udc->lock); - udc->driver->resume(&udc->gadget); - spin_lock(&udc->lock); - } - - /* endpoint IRQs are cleared by handling them */ - } else { - int i; - unsigned mask = 1; - struct at91_ep *ep = &udc->ep[1]; - - if (status & mask) - handle_ep0(udc); - for (i = 1; i < NUM_ENDPOINTS; i++) { - mask <<= 1; - if (status & mask) - handle_ep(ep); - ep++; - } - } - } - - if (disable_clock) - clk_off(udc); - - spin_unlock_irqrestore(&udc->lock, flags); - - return IRQ_HANDLED; -} - -/*-------------------------------------------------------------------------*/ - -static void nop_release(struct device *dev) -{ - /* nothing to free */ -} - -static struct at91_udc controller = { - .gadget = { - .ops = &at91_udc_ops, - .ep0 = &controller.ep[0].ep, - .name = driver_name, - .dev = { - .init_name = "gadget", - .release = nop_release, - } - }, - .ep[0] = { - .ep = { - .name = ep0name, - .ops = &at91_ep_ops, - }, - .udc = &controller, - .maxpacket = 8, - .int_mask = 1 << 0, - }, - .ep[1] = { - .ep = { - .name = "ep1", - .ops = &at91_ep_ops, - }, - .udc = &controller, - .is_pingpong = 1, - .maxpacket = 64, - .int_mask = 1 << 1, - }, - .ep[2] = { - .ep = { - .name = "ep2", - .ops = &at91_ep_ops, - }, - .udc = &controller, - .is_pingpong = 1, - .maxpacket = 64, - .int_mask = 1 << 2, - }, - .ep[3] = { - .ep = { - /* could actually do bulk too */ - .name = "ep3-int", - .ops = &at91_ep_ops, - }, - .udc = &controller, - .maxpacket = 8, - .int_mask = 1 << 3, - }, - .ep[4] = { - .ep = { - .name = "ep4", - .ops = &at91_ep_ops, - }, - .udc = &controller, - .is_pingpong = 1, - .maxpacket = 256, - .int_mask = 1 << 4, - }, - .ep[5] = { - .ep = { - .name = "ep5", - .ops = &at91_ep_ops, - }, - .udc = &controller, - .is_pingpong = 1, - .maxpacket = 256, - .int_mask = 1 << 5, - }, - /* ep6 and ep7 are also reserved (custom silicon might use them) */ -}; - -static void at91_vbus_update(struct at91_udc *udc, unsigned value) -{ - value ^= udc->board.vbus_active_low; - if (value != udc->vbus) - at91_vbus_session(&udc->gadget, value); -} - -static irqreturn_t at91_vbus_irq(int irq, void *_udc) -{ - struct at91_udc *udc = _udc; - - /* vbus needs at least brief debouncing */ - udelay(10); - at91_vbus_update(udc, gpio_get_value(udc->board.vbus_pin)); - - return IRQ_HANDLED; -} - -static void at91_vbus_timer_work(struct work_struct *work) -{ - struct at91_udc *udc = container_of(work, struct at91_udc, - vbus_timer_work); - - at91_vbus_update(udc, gpio_get_value_cansleep(udc->board.vbus_pin)); - - if (!timer_pending(&udc->vbus_timer)) - mod_timer(&udc->vbus_timer, jiffies + VBUS_POLL_TIMEOUT); -} - -static void at91_vbus_timer(unsigned long data) -{ - struct at91_udc *udc = (struct at91_udc *)data; - - /* - * If we are polling vbus it is likely that the gpio is on an - * bus such as i2c or spi which may sleep, so schedule some work - * to read the vbus gpio - */ - if (!work_pending(&udc->vbus_timer_work)) - schedule_work(&udc->vbus_timer_work); -} - -static int at91_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) -{ - struct at91_udc *udc = &controller; - int retval; - unsigned long flags; - - if (!driver - || driver->max_speed < USB_SPEED_FULL - || !bind - || !driver->setup) { - DBG("bad parameter.\n"); - return -EINVAL; - } - - if (udc->driver) { - DBG("UDC already has a gadget driver\n"); - return -EBUSY; - } - - udc->driver = driver; - udc->gadget.dev.driver = &driver->driver; - dev_set_drvdata(&udc->gadget.dev, &driver->driver); - udc->enabled = 1; - udc->selfpowered = 1; - - retval = bind(&udc->gadget); - if (retval) { - DBG("bind() returned %d\n", retval); - udc->driver = NULL; - udc->gadget.dev.driver = NULL; - dev_set_drvdata(&udc->gadget.dev, NULL); - udc->enabled = 0; - udc->selfpowered = 0; - return retval; - } - - spin_lock_irqsave(&udc->lock, flags); - pullup(udc, 1); - spin_unlock_irqrestore(&udc->lock, flags); - - DBG("bound to %s\n", driver->driver.name); - return 0; -} - -static int at91_stop(struct usb_gadget_driver *driver) -{ - struct at91_udc *udc = &controller; - unsigned long flags; - - if (!driver || driver != udc->driver || !driver->unbind) - return -EINVAL; - - spin_lock_irqsave(&udc->lock, flags); - udc->enabled = 0; - at91_udp_write(udc, AT91_UDP_IDR, ~0); - pullup(udc, 0); - spin_unlock_irqrestore(&udc->lock, flags); - - driver->unbind(&udc->gadget); - udc->gadget.dev.driver = NULL; - dev_set_drvdata(&udc->gadget.dev, NULL); - udc->driver = NULL; - - DBG("unbound from %s\n", driver->driver.name); - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static void at91udc_shutdown(struct platform_device *dev) -{ - struct at91_udc *udc = platform_get_drvdata(dev); - unsigned long flags; - - /* force disconnect on reboot */ - spin_lock_irqsave(&udc->lock, flags); - pullup(platform_get_drvdata(dev), 0); - spin_unlock_irqrestore(&udc->lock, flags); -} - -static void __devinit at91udc_of_init(struct at91_udc *udc, - struct device_node *np) -{ - struct at91_udc_data *board = &udc->board; - u32 val; - enum of_gpio_flags flags; - - if (of_property_read_u32(np, "atmel,vbus-polled", &val) == 0) - board->vbus_polled = 1; - - board->vbus_pin = of_get_named_gpio_flags(np, "atmel,vbus-gpio", 0, - &flags); - board->vbus_active_low = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0; - - board->pullup_pin = of_get_named_gpio_flags(np, "atmel,pullup-gpio", 0, - &flags); - - board->pullup_active_low = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0; -} - -static int __devinit at91udc_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct at91_udc *udc; - int retval; - struct resource *res; - - if (!dev->platform_data) { - /* small (so we copy it) but critical! */ - DBG("missing platform_data\n"); - return -ENODEV; - } - - if (pdev->num_resources != 2) { - DBG("invalid num_resources\n"); - return -ENODEV; - } - if ((pdev->resource[0].flags != IORESOURCE_MEM) - || (pdev->resource[1].flags != IORESOURCE_IRQ)) { - DBG("invalid resource type\n"); - return -ENODEV; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENXIO; - - if (!request_mem_region(res->start, resource_size(res), driver_name)) { - DBG("someone's using UDC memory\n"); - return -EBUSY; - } - - /* init software state */ - udc = &controller; - udc->gadget.dev.parent = dev; - if (pdev->dev.of_node) - at91udc_of_init(udc, pdev->dev.of_node); - else - memcpy(&udc->board, dev->platform_data, - sizeof(struct at91_udc_data)); - udc->pdev = pdev; - udc->enabled = 0; - spin_lock_init(&udc->lock); - - /* rm9200 needs manual D+ pullup; off by default */ - if (cpu_is_at91rm9200()) { - if (gpio_is_valid(udc->board.pullup_pin)) { - DBG("no D+ pullup?\n"); - retval = -ENODEV; - goto fail0; - } - retval = gpio_request(udc->board.pullup_pin, "udc_pullup"); - if (retval) { - DBG("D+ pullup is busy\n"); - goto fail0; - } - gpio_direction_output(udc->board.pullup_pin, - udc->board.pullup_active_low); - } - - /* newer chips have more FIFO memory than rm9200 */ - if (cpu_is_at91sam9260() || cpu_is_at91sam9g20()) { - udc->ep[0].maxpacket = 64; - udc->ep[3].maxpacket = 64; - udc->ep[4].maxpacket = 512; - udc->ep[5].maxpacket = 512; - } else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) { - udc->ep[3].maxpacket = 64; - } else if (cpu_is_at91sam9263()) { - udc->ep[0].maxpacket = 64; - udc->ep[3].maxpacket = 64; - } - - udc->udp_baseaddr = ioremap(res->start, resource_size(res)); - if (!udc->udp_baseaddr) { - retval = -ENOMEM; - goto fail0a; - } - - udc_reinit(udc); - - /* get interface and function clocks */ - udc->iclk = clk_get(dev, "udc_clk"); - udc->fclk = clk_get(dev, "udpck"); - if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) { - DBG("clocks missing\n"); - retval = -ENODEV; - /* NOTE: we "know" here that refcounts on these are NOPs */ - goto fail0b; - } - - retval = device_register(&udc->gadget.dev); - if (retval < 0) { - put_device(&udc->gadget.dev); - goto fail0b; - } - - /* don't do anything until we have both gadget driver and VBUS */ - clk_enable(udc->iclk); - at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); - at91_udp_write(udc, AT91_UDP_IDR, 0xffffffff); - /* Clear all pending interrupts - UDP may be used by bootloader. */ - at91_udp_write(udc, AT91_UDP_ICR, 0xffffffff); - clk_disable(udc->iclk); - - /* request UDC and maybe VBUS irqs */ - udc->udp_irq = platform_get_irq(pdev, 0); - retval = request_irq(udc->udp_irq, at91_udc_irq, - 0, driver_name, udc); - if (retval < 0) { - DBG("request irq %d failed\n", udc->udp_irq); - goto fail1; - } - if (gpio_is_valid(udc->board.vbus_pin)) { - retval = gpio_request(udc->board.vbus_pin, "udc_vbus"); - if (retval < 0) { - DBG("request vbus pin failed\n"); - goto fail2; - } - gpio_direction_input(udc->board.vbus_pin); - - /* - * Get the initial state of VBUS - we cannot expect - * a pending interrupt. - */ - udc->vbus = gpio_get_value_cansleep(udc->board.vbus_pin) ^ - udc->board.vbus_active_low; - - if (udc->board.vbus_polled) { - INIT_WORK(&udc->vbus_timer_work, at91_vbus_timer_work); - setup_timer(&udc->vbus_timer, at91_vbus_timer, - (unsigned long)udc); - mod_timer(&udc->vbus_timer, - jiffies + VBUS_POLL_TIMEOUT); - } else { - if (request_irq(gpio_to_irq(udc->board.vbus_pin), - at91_vbus_irq, 0, driver_name, udc)) { - DBG("request vbus irq %d failed\n", - udc->board.vbus_pin); - retval = -EBUSY; - goto fail3; - } - } - } else { - DBG("no VBUS detection, assuming always-on\n"); - udc->vbus = 1; - } - retval = usb_add_gadget_udc(dev, &udc->gadget); - if (retval) - goto fail4; - dev_set_drvdata(dev, udc); - device_init_wakeup(dev, 1); - create_debug_file(udc); - - INFO("%s version %s\n", driver_name, DRIVER_VERSION); - return 0; -fail4: - if (gpio_is_valid(udc->board.vbus_pin) && !udc->board.vbus_polled) - free_irq(gpio_to_irq(udc->board.vbus_pin), udc); -fail3: - if (gpio_is_valid(udc->board.vbus_pin)) - gpio_free(udc->board.vbus_pin); -fail2: - free_irq(udc->udp_irq, udc); -fail1: - device_unregister(&udc->gadget.dev); -fail0b: - iounmap(udc->udp_baseaddr); -fail0a: - if (cpu_is_at91rm9200()) - gpio_free(udc->board.pullup_pin); -fail0: - release_mem_region(res->start, resource_size(res)); - DBG("%s probe failed, %d\n", driver_name, retval); - return retval; -} - -static int __exit at91udc_remove(struct platform_device *pdev) -{ - struct at91_udc *udc = platform_get_drvdata(pdev); - struct resource *res; - unsigned long flags; - - DBG("remove\n"); - - usb_del_gadget_udc(&udc->gadget); - if (udc->driver) - return -EBUSY; - - spin_lock_irqsave(&udc->lock, flags); - pullup(udc, 0); - spin_unlock_irqrestore(&udc->lock, flags); - - device_init_wakeup(&pdev->dev, 0); - remove_debug_file(udc); - if (gpio_is_valid(udc->board.vbus_pin)) { - free_irq(gpio_to_irq(udc->board.vbus_pin), udc); - gpio_free(udc->board.vbus_pin); - } - free_irq(udc->udp_irq, udc); - device_unregister(&udc->gadget.dev); - - iounmap(udc->udp_baseaddr); - - if (cpu_is_at91rm9200()) - gpio_free(udc->board.pullup_pin); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - - clk_put(udc->iclk); - clk_put(udc->fclk); - - return 0; -} - -#ifdef CONFIG_PM -static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg) -{ - struct at91_udc *udc = platform_get_drvdata(pdev); - int wake = udc->driver && device_may_wakeup(&pdev->dev); - unsigned long flags; - - /* Unless we can act normally to the host (letting it wake us up - * whenever it has work for us) force disconnect. Wakeup requires - * PLLB for USB events (signaling for reset, wakeup, or incoming - * tokens) and VBUS irqs (on systems which support them). - */ - if ((!udc->suspended && udc->addr) - || !wake - || at91_suspend_entering_slow_clock()) { - spin_lock_irqsave(&udc->lock, flags); - pullup(udc, 0); - wake = 0; - spin_unlock_irqrestore(&udc->lock, flags); - } else - enable_irq_wake(udc->udp_irq); - - udc->active_suspend = wake; - if (gpio_is_valid(udc->board.vbus_pin) && !udc->board.vbus_polled && wake) - enable_irq_wake(udc->board.vbus_pin); - return 0; -} - -static int at91udc_resume(struct platform_device *pdev) -{ - struct at91_udc *udc = platform_get_drvdata(pdev); - unsigned long flags; - - if (gpio_is_valid(udc->board.vbus_pin) && !udc->board.vbus_polled && - udc->active_suspend) - disable_irq_wake(udc->board.vbus_pin); - - /* maybe reconnect to host; if so, clocks on */ - if (udc->active_suspend) - disable_irq_wake(udc->udp_irq); - else { - spin_lock_irqsave(&udc->lock, flags); - pullup(udc, 1); - spin_unlock_irqrestore(&udc->lock, flags); - } - return 0; -} -#else -#define at91udc_suspend NULL -#define at91udc_resume NULL -#endif - -#if defined(CONFIG_OF) -static const struct of_device_id at91_udc_dt_ids[] = { - { .compatible = "atmel,at91rm9200-udc" }, - { /* sentinel */ } -}; - -MODULE_DEVICE_TABLE(of, at91_udc_dt_ids); -#endif - -static struct platform_driver at91_udc_driver = { - .remove = __exit_p(at91udc_remove), - .shutdown = at91udc_shutdown, - .suspend = at91udc_suspend, - .resume = at91udc_resume, - .driver = { - .name = (char *) driver_name, - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(at91_udc_dt_ids), - }, -}; - -static int __init udc_init_module(void) -{ - return platform_driver_probe(&at91_udc_driver, at91udc_probe); -} -module_init(udc_init_module); - -static void __exit udc_exit_module(void) -{ - platform_driver_unregister(&at91_udc_driver); -} -module_exit(udc_exit_module); - -MODULE_DESCRIPTION("AT91 udc driver"); -MODULE_AUTHOR("Thomas Rathbone, David Brownell"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:at91_udc"); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/at91_udc.h b/ANDROID_3.4.5/drivers/usb/gadget/at91_udc.h deleted file mode 100644 index 3c0315b8..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/at91_udc.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (C) 2004 by Thomas Rathbone, HP Labs - * Copyright (C) 2005 by Ivan Kokshaysky - * Copyright (C) 2006 by SAN People - * - * 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. - */ - -#ifndef AT91_UDC_H -#define AT91_UDC_H - -/* - * USB Device Port (UDP) registers. - * Based on AT91RM9200 datasheet revision E. - */ - -#define AT91_UDP_FRM_NUM 0x00 /* Frame Number Register */ -#define AT91_UDP_NUM (0x7ff << 0) /* Frame Number */ -#define AT91_UDP_FRM_ERR (1 << 16) /* Frame Error */ -#define AT91_UDP_FRM_OK (1 << 17) /* Frame OK */ - -#define AT91_UDP_GLB_STAT 0x04 /* Global State Register */ -#define AT91_UDP_FADDEN (1 << 0) /* Function Address Enable */ -#define AT91_UDP_CONFG (1 << 1) /* Configured */ -#define AT91_UDP_ESR (1 << 2) /* Enable Send Resume */ -#define AT91_UDP_RSMINPR (1 << 3) /* Resume has been sent */ -#define AT91_UDP_RMWUPE (1 << 4) /* Remote Wake Up Enable */ - -#define AT91_UDP_FADDR 0x08 /* Function Address Register */ -#define AT91_UDP_FADD (0x7f << 0) /* Function Address Value */ -#define AT91_UDP_FEN (1 << 8) /* Function Enable */ - -#define AT91_UDP_IER 0x10 /* Interrupt Enable Register */ -#define AT91_UDP_IDR 0x14 /* Interrupt Disable Register */ -#define AT91_UDP_IMR 0x18 /* Interrupt Mask Register */ - -#define AT91_UDP_ISR 0x1c /* Interrupt Status Register */ -#define AT91_UDP_EP(n) (1 << (n)) /* Endpoint Interrupt Status */ -#define AT91_UDP_RXSUSP (1 << 8) /* USB Suspend Interrupt Status */ -#define AT91_UDP_RXRSM (1 << 9) /* USB Resume Interrupt Status */ -#define AT91_UDP_EXTRSM (1 << 10) /* External Resume Interrupt Status [AT91RM9200 only] */ -#define AT91_UDP_SOFINT (1 << 11) /* Start of Frame Interrupt Status */ -#define AT91_UDP_ENDBUSRES (1 << 12) /* End of Bus Reset Interrupt Status */ -#define AT91_UDP_WAKEUP (1 << 13) /* USB Wakeup Interrupt Status [AT91RM9200 only] */ - -#define AT91_UDP_ICR 0x20 /* Interrupt Clear Register */ -#define AT91_UDP_RST_EP 0x28 /* Reset Endpoint Register */ - -#define AT91_UDP_CSR(n) (0x30+((n)*4)) /* Endpoint Control/Status Registers 0-7 */ -#define AT91_UDP_TXCOMP (1 << 0) /* Generates IN packet with data previously written in DPR */ -#define AT91_UDP_RX_DATA_BK0 (1 << 1) /* Receive Data Bank 0 */ -#define AT91_UDP_RXSETUP (1 << 2) /* Send STALL to the host */ -#define AT91_UDP_STALLSENT (1 << 3) /* Stall Sent / Isochronous error (Isochronous endpoints) */ -#define AT91_UDP_TXPKTRDY (1 << 4) /* Transmit Packet Ready */ -#define AT91_UDP_FORCESTALL (1 << 5) /* Force Stall */ -#define AT91_UDP_RX_DATA_BK1 (1 << 6) /* Receive Data Bank 1 */ -#define AT91_UDP_DIR (1 << 7) /* Transfer Direction */ -#define AT91_UDP_EPTYPE (7 << 8) /* Endpoint Type */ -#define AT91_UDP_EPTYPE_CTRL (0 << 8) -#define AT91_UDP_EPTYPE_ISO_OUT (1 << 8) -#define AT91_UDP_EPTYPE_BULK_OUT (2 << 8) -#define AT91_UDP_EPTYPE_INT_OUT (3 << 8) -#define AT91_UDP_EPTYPE_ISO_IN (5 << 8) -#define AT91_UDP_EPTYPE_BULK_IN (6 << 8) -#define AT91_UDP_EPTYPE_INT_IN (7 << 8) -#define AT91_UDP_DTGLE (1 << 11) /* Data Toggle */ -#define AT91_UDP_EPEDS (1 << 15) /* Endpoint Enable/Disable */ -#define AT91_UDP_RXBYTECNT (0x7ff << 16) /* Number of bytes in FIFO */ - -#define AT91_UDP_FDR(n) (0x50+((n)*4)) /* Endpoint FIFO Data Registers 0-7 */ - -#define AT91_UDP_TXVC 0x74 /* Transceiver Control Register */ -#define AT91_UDP_TXVC_TXVDIS (1 << 8) /* Transceiver Disable */ -#define AT91_UDP_TXVC_PUON (1 << 9) /* PullUp On [AT91SAM9260 only] */ - -/*-------------------------------------------------------------------------*/ - -/* - * controller driver data structures - */ - -#define NUM_ENDPOINTS 6 - -/* - * hardware won't disable bus reset, or resume while the controller - * is suspended ... watching suspend helps keep the logic symmetric. - */ -#define MINIMUS_INTERRUPTUS \ - (AT91_UDP_ENDBUSRES | AT91_UDP_RXRSM | AT91_UDP_RXSUSP) - -struct at91_ep { - struct usb_ep ep; - struct list_head queue; - struct at91_udc *udc; - void __iomem *creg; - - unsigned maxpacket:16; - u8 int_mask; - unsigned is_pingpong:1; - - unsigned stopped:1; - unsigned is_in:1; - unsigned is_iso:1; - unsigned fifo_bank:1; - - const struct usb_endpoint_descriptor - *desc; -}; - -/* - * driver is non-SMP, and just blocks IRQs whenever it needs - * access protection for chip registers or driver state - */ -struct at91_udc { - struct usb_gadget gadget; - struct at91_ep ep[NUM_ENDPOINTS]; - struct usb_gadget_driver *driver; - unsigned vbus:1; - unsigned enabled:1; - unsigned clocked:1; - unsigned suspended:1; - unsigned req_pending:1; - unsigned wait_for_addr_ack:1; - unsigned wait_for_config_ack:1; - unsigned selfpowered:1; - unsigned active_suspend:1; - u8 addr; - struct at91_udc_data board; - struct clk *iclk, *fclk; - struct platform_device *pdev; - struct proc_dir_entry *pde; - void __iomem *udp_baseaddr; - int udp_irq; - spinlock_t lock; - struct timer_list vbus_timer; - struct work_struct vbus_timer_work; -}; - -static inline struct at91_udc *to_udc(struct usb_gadget *g) -{ - return container_of(g, struct at91_udc, gadget); -} - -struct at91_request { - struct usb_request req; - struct list_head queue; -}; - -/*-------------------------------------------------------------------------*/ - -#ifdef VERBOSE_DEBUG -# define VDBG DBG -#else -# define VDBG(stuff...) do{}while(0) -#endif - -#ifdef PACKET_TRACE -# define PACKET VDBG -#else -# define PACKET(stuff...) do{}while(0) -#endif - -#define ERR(stuff...) pr_err("udc: " stuff) -#define WARNING(stuff...) pr_warning("udc: " stuff) -#define INFO(stuff...) pr_info("udc: " stuff) -#define DBG(stuff...) pr_debug("udc: " stuff) - -#endif - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/atmel_usba_udc.c b/ANDROID_3.4.5/drivers/usb/gadget/atmel_usba_udc.c deleted file mode 100644 index 9f985089..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/atmel_usba_udc.c +++ /dev/null @@ -1,2118 +0,0 @@ -/* - * Driver for the Atmel USBA high speed USB device controller - * - * Copyright (C) 2005-2007 Atmel Corporation - * - * 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. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "atmel_usba_udc.h" - - -static struct usba_udc the_udc; -static struct usba_ep *usba_ep; - -#ifdef CONFIG_USB_GADGET_DEBUG_FS -#include -#include - -static int queue_dbg_open(struct inode *inode, struct file *file) -{ - struct usba_ep *ep = inode->i_private; - struct usba_request *req, *req_copy; - struct list_head *queue_data; - - queue_data = kmalloc(sizeof(*queue_data), GFP_KERNEL); - if (!queue_data) - return -ENOMEM; - INIT_LIST_HEAD(queue_data); - - spin_lock_irq(&ep->udc->lock); - list_for_each_entry(req, &ep->queue, queue) { - req_copy = kmemdup(req, sizeof(*req_copy), GFP_ATOMIC); - if (!req_copy) - goto fail; - list_add_tail(&req_copy->queue, queue_data); - } - spin_unlock_irq(&ep->udc->lock); - - file->private_data = queue_data; - return 0; - -fail: - spin_unlock_irq(&ep->udc->lock); - list_for_each_entry_safe(req, req_copy, queue_data, queue) { - list_del(&req->queue); - kfree(req); - } - kfree(queue_data); - return -ENOMEM; -} - -/* - * bbbbbbbb llllllll IZS sssss nnnn FDL\n\0 - * - * b: buffer address - * l: buffer length - * I/i: interrupt/no interrupt - * Z/z: zero/no zero - * S/s: short ok/short not ok - * s: status - * n: nr_packets - * F/f: submitted/not submitted to FIFO - * D/d: using/not using DMA - * L/l: last transaction/not last transaction - */ -static ssize_t queue_dbg_read(struct file *file, char __user *buf, - size_t nbytes, loff_t *ppos) -{ - struct list_head *queue = file->private_data; - struct usba_request *req, *tmp_req; - size_t len, remaining, actual = 0; - char tmpbuf[38]; - - if (!access_ok(VERIFY_WRITE, buf, nbytes)) - return -EFAULT; - - mutex_lock(&file->f_dentry->d_inode->i_mutex); - list_for_each_entry_safe(req, tmp_req, queue, queue) { - len = snprintf(tmpbuf, sizeof(tmpbuf), - "%8p %08x %c%c%c %5d %c%c%c\n", - req->req.buf, req->req.length, - req->req.no_interrupt ? 'i' : 'I', - req->req.zero ? 'Z' : 'z', - req->req.short_not_ok ? 's' : 'S', - req->req.status, - req->submitted ? 'F' : 'f', - req->using_dma ? 'D' : 'd', - req->last_transaction ? 'L' : 'l'); - len = min(len, sizeof(tmpbuf)); - if (len > nbytes) - break; - - list_del(&req->queue); - kfree(req); - - remaining = __copy_to_user(buf, tmpbuf, len); - actual += len - remaining; - if (remaining) - break; - - nbytes -= len; - buf += len; - } - mutex_unlock(&file->f_dentry->d_inode->i_mutex); - - return actual; -} - -static int queue_dbg_release(struct inode *inode, struct file *file) -{ - struct list_head *queue_data = file->private_data; - struct usba_request *req, *tmp_req; - - list_for_each_entry_safe(req, tmp_req, queue_data, queue) { - list_del(&req->queue); - kfree(req); - } - kfree(queue_data); - return 0; -} - -static int regs_dbg_open(struct inode *inode, struct file *file) -{ - struct usba_udc *udc; - unsigned int i; - u32 *data; - int ret = -ENOMEM; - - mutex_lock(&inode->i_mutex); - udc = inode->i_private; - data = kmalloc(inode->i_size, GFP_KERNEL); - if (!data) - goto out; - - spin_lock_irq(&udc->lock); - for (i = 0; i < inode->i_size / 4; i++) - data[i] = __raw_readl(udc->regs + i * 4); - spin_unlock_irq(&udc->lock); - - file->private_data = data; - ret = 0; - -out: - mutex_unlock(&inode->i_mutex); - - return ret; -} - -static ssize_t regs_dbg_read(struct file *file, char __user *buf, - size_t nbytes, loff_t *ppos) -{ - struct inode *inode = file->f_dentry->d_inode; - int ret; - - mutex_lock(&inode->i_mutex); - ret = simple_read_from_buffer(buf, nbytes, ppos, - file->private_data, - file->f_dentry->d_inode->i_size); - mutex_unlock(&inode->i_mutex); - - return ret; -} - -static int regs_dbg_release(struct inode *inode, struct file *file) -{ - kfree(file->private_data); - return 0; -} - -const struct file_operations queue_dbg_fops = { - .owner = THIS_MODULE, - .open = queue_dbg_open, - .llseek = no_llseek, - .read = queue_dbg_read, - .release = queue_dbg_release, -}; - -const struct file_operations regs_dbg_fops = { - .owner = THIS_MODULE, - .open = regs_dbg_open, - .llseek = generic_file_llseek, - .read = regs_dbg_read, - .release = regs_dbg_release, -}; - -static void usba_ep_init_debugfs(struct usba_udc *udc, - struct usba_ep *ep) -{ - struct dentry *ep_root; - - ep_root = debugfs_create_dir(ep->ep.name, udc->debugfs_root); - if (!ep_root) - goto err_root; - ep->debugfs_dir = ep_root; - - ep->debugfs_queue = debugfs_create_file("queue", 0400, ep_root, - ep, &queue_dbg_fops); - if (!ep->debugfs_queue) - goto err_queue; - - if (ep->can_dma) { - ep->debugfs_dma_status - = debugfs_create_u32("dma_status", 0400, ep_root, - &ep->last_dma_status); - if (!ep->debugfs_dma_status) - goto err_dma_status; - } - if (ep_is_control(ep)) { - ep->debugfs_state - = debugfs_create_u32("state", 0400, ep_root, - &ep->state); - if (!ep->debugfs_state) - goto err_state; - } - - return; - -err_state: - if (ep->can_dma) - debugfs_remove(ep->debugfs_dma_status); -err_dma_status: - debugfs_remove(ep->debugfs_queue); -err_queue: - debugfs_remove(ep_root); -err_root: - dev_err(&ep->udc->pdev->dev, - "failed to create debugfs directory for %s\n", ep->ep.name); -} - -static void usba_ep_cleanup_debugfs(struct usba_ep *ep) -{ - debugfs_remove(ep->debugfs_queue); - debugfs_remove(ep->debugfs_dma_status); - debugfs_remove(ep->debugfs_state); - debugfs_remove(ep->debugfs_dir); - ep->debugfs_dma_status = NULL; - ep->debugfs_dir = NULL; -} - -static void usba_init_debugfs(struct usba_udc *udc) -{ - struct dentry *root, *regs; - struct resource *regs_resource; - - root = debugfs_create_dir(udc->gadget.name, NULL); - if (IS_ERR(root) || !root) - goto err_root; - udc->debugfs_root = root; - - regs = debugfs_create_file("regs", 0400, root, udc, ®s_dbg_fops); - if (!regs) - goto err_regs; - - regs_resource = platform_get_resource(udc->pdev, IORESOURCE_MEM, - CTRL_IOMEM_ID); - regs->d_inode->i_size = resource_size(regs_resource); - udc->debugfs_regs = regs; - - usba_ep_init_debugfs(udc, to_usba_ep(udc->gadget.ep0)); - - return; - -err_regs: - debugfs_remove(root); -err_root: - udc->debugfs_root = NULL; - dev_err(&udc->pdev->dev, "debugfs is not available\n"); -} - -static void usba_cleanup_debugfs(struct usba_udc *udc) -{ - usba_ep_cleanup_debugfs(to_usba_ep(udc->gadget.ep0)); - debugfs_remove(udc->debugfs_regs); - debugfs_remove(udc->debugfs_root); - udc->debugfs_regs = NULL; - udc->debugfs_root = NULL; -} -#else -static inline void usba_ep_init_debugfs(struct usba_udc *udc, - struct usba_ep *ep) -{ - -} - -static inline void usba_ep_cleanup_debugfs(struct usba_ep *ep) -{ - -} - -static inline void usba_init_debugfs(struct usba_udc *udc) -{ - -} - -static inline void usba_cleanup_debugfs(struct usba_udc *udc) -{ - -} -#endif - -static int vbus_is_present(struct usba_udc *udc) -{ - if (gpio_is_valid(udc->vbus_pin)) - return gpio_get_value(udc->vbus_pin) ^ udc->vbus_pin_inverted; - - /* No Vbus detection: Assume always present */ - return 1; -} - -#if defined(CONFIG_ARCH_AT91SAM9RL) - -#include - -static void toggle_bias(int is_on) -{ - unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR); - - if (is_on) - at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN); - else - at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN)); -} - -#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) -{ - unsigned int transaction_len; - - transaction_len = req->req.length - req->req.actual; - req->last_transaction = 1; - if (transaction_len > ep->ep.maxpacket) { - transaction_len = ep->ep.maxpacket; - req->last_transaction = 0; - } else if (transaction_len == ep->ep.maxpacket && req->req.zero) - req->last_transaction = 0; - - DBG(DBG_QUEUE, "%s: submit_transaction, req %p (length %d)%s\n", - ep->ep.name, req, transaction_len, - req->last_transaction ? ", done" : ""); - - memcpy_toio(ep->fifo, req->req.buf + req->req.actual, transaction_len); - usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); - req->req.actual += transaction_len; -} - -static void submit_request(struct usba_ep *ep, struct usba_request *req) -{ - DBG(DBG_QUEUE, "%s: submit_request: req %p (length %d)\n", - ep->ep.name, req, req->req.length); - - req->req.actual = 0; - req->submitted = 1; - - if (req->using_dma) { - if (req->req.length == 0) { - usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY); - return; - } - - if (req->req.zero) - usba_ep_writel(ep, CTL_ENB, USBA_SHORT_PACKET); - else - usba_ep_writel(ep, CTL_DIS, USBA_SHORT_PACKET); - - usba_dma_writel(ep, ADDRESS, req->req.dma); - usba_dma_writel(ep, CONTROL, req->ctrl); - } else { - next_fifo_transaction(ep, req); - if (req->last_transaction) { - usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); - usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); - } else { - usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); - usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY); - } - } -} - -static void submit_next_request(struct usba_ep *ep) -{ - struct usba_request *req; - - if (list_empty(&ep->queue)) { - usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY | USBA_RX_BK_RDY); - return; - } - - req = list_entry(ep->queue.next, struct usba_request, queue); - if (!req->submitted) - submit_request(ep, req); -} - -static void send_status(struct usba_udc *udc, struct usba_ep *ep) -{ - ep->state = STATUS_STAGE_IN; - usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); - usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); -} - -static void receive_data(struct usba_ep *ep) -{ - struct usba_udc *udc = ep->udc; - struct usba_request *req; - unsigned long status; - unsigned int bytecount, nr_busy; - int is_complete = 0; - - status = usba_ep_readl(ep, STA); - nr_busy = USBA_BFEXT(BUSY_BANKS, status); - - DBG(DBG_QUEUE, "receive data: nr_busy=%u\n", nr_busy); - - while (nr_busy > 0) { - if (list_empty(&ep->queue)) { - usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); - break; - } - req = list_entry(ep->queue.next, - struct usba_request, queue); - - bytecount = USBA_BFEXT(BYTE_COUNT, status); - - if (status & (1 << 31)) - is_complete = 1; - if (req->req.actual + bytecount >= req->req.length) { - is_complete = 1; - bytecount = req->req.length - req->req.actual; - } - - memcpy_fromio(req->req.buf + req->req.actual, - ep->fifo, bytecount); - req->req.actual += bytecount; - - usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); - - if (is_complete) { - DBG(DBG_QUEUE, "%s: request done\n", ep->ep.name); - req->req.status = 0; - list_del_init(&req->queue); - usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); - spin_unlock(&udc->lock); - req->req.complete(&ep->ep, &req->req); - spin_lock(&udc->lock); - } - - status = usba_ep_readl(ep, STA); - nr_busy = USBA_BFEXT(BUSY_BANKS, status); - - if (is_complete && ep_is_control(ep)) { - send_status(udc, ep); - break; - } - } -} - -static void -request_complete(struct usba_ep *ep, struct usba_request *req, int status) -{ - struct usba_udc *udc = ep->udc; - - WARN_ON(!list_empty(&req->queue)); - - if (req->req.status == -EINPROGRESS) - req->req.status = status; - - if (req->mapped) { - dma_unmap_single( - &udc->pdev->dev, req->req.dma, req->req.length, - ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - req->req.dma = DMA_ADDR_INVALID; - req->mapped = 0; - } - - DBG(DBG_GADGET | DBG_REQ, - "%s: req %p complete: status %d, actual %u\n", - ep->ep.name, req, req->req.status, req->req.actual); - - spin_unlock(&udc->lock); - req->req.complete(&ep->ep, &req->req); - spin_lock(&udc->lock); -} - -static void -request_complete_list(struct usba_ep *ep, struct list_head *list, int status) -{ - struct usba_request *req, *tmp_req; - - list_for_each_entry_safe(req, tmp_req, list, queue) { - list_del_init(&req->queue); - request_complete(ep, req, status); - } -} - -static int -usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) -{ - struct usba_ep *ep = to_usba_ep(_ep); - struct usba_udc *udc = ep->udc; - unsigned long flags, ept_cfg, maxpacket; - unsigned int nr_trans; - - DBG(DBG_GADGET, "%s: ep_enable: desc=%p\n", ep->ep.name, desc); - - maxpacket = usb_endpoint_maxp(desc) & 0x7ff; - - if (((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != ep->index) - || ep->index == 0 - || desc->bDescriptorType != USB_DT_ENDPOINT - || maxpacket == 0 - || maxpacket > ep->fifo_size) { - DBG(DBG_ERR, "ep_enable: Invalid argument"); - return -EINVAL; - } - - ep->is_isoc = 0; - ep->is_in = 0; - - if (maxpacket <= 8) - ept_cfg = USBA_BF(EPT_SIZE, USBA_EPT_SIZE_8); - else - /* LSB is bit 1, not 0 */ - ept_cfg = USBA_BF(EPT_SIZE, fls(maxpacket - 1) - 3); - - DBG(DBG_HW, "%s: EPT_SIZE = %lu (maxpacket = %lu)\n", - ep->ep.name, ept_cfg, maxpacket); - - if (usb_endpoint_dir_in(desc)) { - ep->is_in = 1; - ept_cfg |= USBA_EPT_DIR_IN; - } - - 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); - break; - case USB_ENDPOINT_XFER_ISOC: - if (!ep->can_isoc) { - DBG(DBG_ERR, "ep_enable: %s is not isoc capable\n", - ep->ep.name); - return -EINVAL; - } - - /* - * Bits 11:12 specify number of _additional_ - * transactions per microframe. - */ - nr_trans = ((usb_endpoint_maxp(desc) >> 11) & 3) + 1; - if (nr_trans > 3) - return -EINVAL; - - ep->is_isoc = 1; - ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_ISO); - - /* - * Do triple-buffering on high-bandwidth iso endpoints. - */ - if (nr_trans > 1 && ep->nr_banks == 3) - ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_TRIPLE); - else - ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE); - ept_cfg |= USBA_BF(NB_TRANS, nr_trans); - break; - case USB_ENDPOINT_XFER_BULK: - ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK); - ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE); - break; - case USB_ENDPOINT_XFER_INT: - ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_INT); - ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE); - break; - } - - spin_lock_irqsave(&ep->udc->lock, flags); - - if (ep->desc) { - spin_unlock_irqrestore(&ep->udc->lock, flags); - DBG(DBG_ERR, "ep%d already enabled\n", ep->index); - return -EBUSY; - } - - ep->desc = desc; - ep->ep.maxpacket = maxpacket; - - usba_ep_writel(ep, CFG, ept_cfg); - usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); - - if (ep->can_dma) { - u32 ctrl; - - usba_writel(udc, INT_ENB, - (usba_readl(udc, INT_ENB) - | USBA_BF(EPT_INT, 1 << ep->index) - | USBA_BF(DMA_INT, 1 << ep->index))); - ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA; - usba_ep_writel(ep, CTL_ENB, ctrl); - } else { - usba_writel(udc, INT_ENB, - (usba_readl(udc, INT_ENB) - | USBA_BF(EPT_INT, 1 << ep->index))); - } - - spin_unlock_irqrestore(&udc->lock, flags); - - DBG(DBG_HW, "EPT_CFG%d after init: %#08lx\n", ep->index, - (unsigned long)usba_ep_readl(ep, CFG)); - DBG(DBG_HW, "INT_ENB after init: %#08lx\n", - (unsigned long)usba_readl(udc, INT_ENB)); - - return 0; -} - -static int usba_ep_disable(struct usb_ep *_ep) -{ - struct usba_ep *ep = to_usba_ep(_ep); - struct usba_udc *udc = ep->udc; - LIST_HEAD(req_list); - unsigned long flags; - - DBG(DBG_GADGET, "ep_disable: %s\n", ep->ep.name); - - spin_lock_irqsave(&udc->lock, flags); - - if (!ep->desc) { - spin_unlock_irqrestore(&udc->lock, flags); - /* REVISIT because this driver disables endpoints in - * reset_all_endpoints() before calling disconnect(), - * most gadget drivers would trigger this non-error ... - */ - if (udc->gadget.speed != USB_SPEED_UNKNOWN) - DBG(DBG_ERR, "ep_disable: %s not enabled\n", - ep->ep.name); - return -EINVAL; - } - ep->desc = NULL; - ep->ep.desc = NULL; - - list_splice_init(&ep->queue, &req_list); - if (ep->can_dma) { - usba_dma_writel(ep, CONTROL, 0); - usba_dma_writel(ep, ADDRESS, 0); - usba_dma_readl(ep, STATUS); - } - usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE); - usba_writel(udc, INT_ENB, - usba_readl(udc, INT_ENB) - & ~USBA_BF(EPT_INT, 1 << ep->index)); - - request_complete_list(ep, &req_list, -ESHUTDOWN); - - spin_unlock_irqrestore(&udc->lock, flags); - - return 0; -} - -static struct usb_request * -usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) -{ - struct usba_request *req; - - DBG(DBG_GADGET, "ep_alloc_request: %p, 0x%x\n", _ep, gfp_flags); - - req = kzalloc(sizeof(*req), gfp_flags); - if (!req) - return NULL; - - INIT_LIST_HEAD(&req->queue); - req->req.dma = DMA_ADDR_INVALID; - - return &req->req; -} - -static void -usba_ep_free_request(struct usb_ep *_ep, struct usb_request *_req) -{ - struct usba_request *req = to_usba_req(_req); - - DBG(DBG_GADGET, "ep_free_request: %p, %p\n", _ep, _req); - - kfree(req); -} - -static int queue_dma(struct usba_udc *udc, struct usba_ep *ep, - struct usba_request *req, gfp_t gfp_flags) -{ - unsigned long flags; - int ret; - - DBG(DBG_DMA, "%s: req l/%u d/%08x %c%c%c\n", - ep->ep.name, req->req.length, req->req.dma, - req->req.zero ? 'Z' : 'z', - req->req.short_not_ok ? 'S' : 's', - req->req.no_interrupt ? 'I' : 'i'); - - if (req->req.length > 0x10000) { - /* Lengths from 0 to 65536 (inclusive) are supported */ - DBG(DBG_ERR, "invalid request length %u\n", req->req.length); - return -EINVAL; - } - - req->using_dma = 1; - - if (req->req.dma == DMA_ADDR_INVALID) { - req->req.dma = dma_map_single( - &udc->pdev->dev, req->req.buf, req->req.length, - ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - req->mapped = 1; - } else { - dma_sync_single_for_device( - &udc->pdev->dev, req->req.dma, req->req.length, - ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - req->mapped = 0; - } - - req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length) - | USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE - | USBA_DMA_END_TR_EN | USBA_DMA_END_TR_IE; - - if (ep->is_in) - req->ctrl |= USBA_DMA_END_BUF_EN; - - /* - * Add this request to the queue and submit for DMA if - * possible. Check if we're still alive first -- we may have - * received a reset since last time we checked. - */ - ret = -ESHUTDOWN; - spin_lock_irqsave(&udc->lock, flags); - if (ep->desc) { - if (list_empty(&ep->queue)) - submit_request(ep, req); - - list_add_tail(&req->queue, &ep->queue); - ret = 0; - } - spin_unlock_irqrestore(&udc->lock, flags); - - return ret; -} - -static int -usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) -{ - struct usba_request *req = to_usba_req(_req); - struct usba_ep *ep = to_usba_ep(_ep); - struct usba_udc *udc = ep->udc; - unsigned long flags; - int ret; - - DBG(DBG_GADGET | DBG_QUEUE | DBG_REQ, "%s: queue req %p, len %u\n", - ep->ep.name, req, _req->length); - - if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN || !ep->desc) - return -ESHUTDOWN; - - req->submitted = 0; - req->using_dma = 0; - req->last_transaction = 0; - - _req->status = -EINPROGRESS; - _req->actual = 0; - - if (ep->can_dma) - return queue_dma(udc, ep, req, gfp_flags); - - /* May have received a reset since last time we checked */ - ret = -ESHUTDOWN; - spin_lock_irqsave(&udc->lock, flags); - if (ep->desc) { - list_add_tail(&req->queue, &ep->queue); - - if ((!ep_is_control(ep) && ep->is_in) || - (ep_is_control(ep) - && (ep->state == DATA_STAGE_IN - || ep->state == STATUS_STAGE_IN))) - usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY); - else - usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY); - ret = 0; - } - spin_unlock_irqrestore(&udc->lock, flags); - - return ret; -} - -static void -usba_update_req(struct usba_ep *ep, struct usba_request *req, u32 status) -{ - req->req.actual = req->req.length - USBA_BFEXT(DMA_BUF_LEN, status); -} - -static int stop_dma(struct usba_ep *ep, u32 *pstatus) -{ - unsigned int timeout; - u32 status; - - /* - * Stop the DMA controller. When writing both CH_EN - * and LINK to 0, the other bits are not affected. - */ - usba_dma_writel(ep, CONTROL, 0); - - /* Wait for the FIFO to empty */ - for (timeout = 40; timeout; --timeout) { - status = usba_dma_readl(ep, STATUS); - if (!(status & USBA_DMA_CH_EN)) - break; - udelay(1); - } - - if (pstatus) - *pstatus = status; - - if (timeout == 0) { - dev_err(&ep->udc->pdev->dev, - "%s: timed out waiting for DMA FIFO to empty\n", - ep->ep.name); - return -ETIMEDOUT; - } - - return 0; -} - -static int usba_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct usba_ep *ep = to_usba_ep(_ep); - struct usba_udc *udc = ep->udc; - struct usba_request *req = to_usba_req(_req); - unsigned long flags; - u32 status; - - DBG(DBG_GADGET | DBG_QUEUE, "ep_dequeue: %s, req %p\n", - ep->ep.name, req); - - spin_lock_irqsave(&udc->lock, flags); - - if (req->using_dma) { - /* - * If this request is currently being transferred, - * stop the DMA controller and reset the FIFO. - */ - if (ep->queue.next == &req->queue) { - status = usba_dma_readl(ep, STATUS); - if (status & USBA_DMA_CH_EN) - stop_dma(ep, &status); - -#ifdef CONFIG_USB_GADGET_DEBUG_FS - ep->last_dma_status = status; -#endif - - usba_writel(udc, EPT_RST, 1 << ep->index); - - usba_update_req(ep, req, status); - } - } - - /* - * Errors should stop the queue from advancing until the - * completion function returns. - */ - list_del_init(&req->queue); - - request_complete(ep, req, -ECONNRESET); - - /* Process the next request if any */ - submit_next_request(ep); - spin_unlock_irqrestore(&udc->lock, flags); - - return 0; -} - -static int usba_ep_set_halt(struct usb_ep *_ep, int value) -{ - struct usba_ep *ep = to_usba_ep(_ep); - struct usba_udc *udc = ep->udc; - unsigned long flags; - int ret = 0; - - DBG(DBG_GADGET, "endpoint %s: %s HALT\n", ep->ep.name, - value ? "set" : "clear"); - - if (!ep->desc) { - DBG(DBG_ERR, "Attempted to halt uninitialized ep %s\n", - ep->ep.name); - return -ENODEV; - } - if (ep->is_isoc) { - DBG(DBG_ERR, "Attempted to halt isochronous ep %s\n", - ep->ep.name); - return -ENOTTY; - } - - spin_lock_irqsave(&udc->lock, flags); - - /* - * We can't halt IN endpoints while there are still data to be - * transferred - */ - if (!list_empty(&ep->queue) - || ((value && ep->is_in && (usba_ep_readl(ep, STA) - & USBA_BF(BUSY_BANKS, -1L))))) { - ret = -EAGAIN; - } else { - if (value) - usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL); - else - usba_ep_writel(ep, CLR_STA, - USBA_FORCE_STALL | USBA_TOGGLE_CLR); - usba_ep_readl(ep, STA); - } - - spin_unlock_irqrestore(&udc->lock, flags); - - return ret; -} - -static int usba_ep_fifo_status(struct usb_ep *_ep) -{ - struct usba_ep *ep = to_usba_ep(_ep); - - return USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA)); -} - -static void usba_ep_fifo_flush(struct usb_ep *_ep) -{ - struct usba_ep *ep = to_usba_ep(_ep); - struct usba_udc *udc = ep->udc; - - usba_writel(udc, EPT_RST, 1 << ep->index); -} - -static const struct usb_ep_ops usba_ep_ops = { - .enable = usba_ep_enable, - .disable = usba_ep_disable, - .alloc_request = usba_ep_alloc_request, - .free_request = usba_ep_free_request, - .queue = usba_ep_queue, - .dequeue = usba_ep_dequeue, - .set_halt = usba_ep_set_halt, - .fifo_status = usba_ep_fifo_status, - .fifo_flush = usba_ep_fifo_flush, -}; - -static int usba_udc_get_frame(struct usb_gadget *gadget) -{ - struct usba_udc *udc = to_usba_udc(gadget); - - return USBA_BFEXT(FRAME_NUMBER, usba_readl(udc, FNUM)); -} - -static int usba_udc_wakeup(struct usb_gadget *gadget) -{ - struct usba_udc *udc = to_usba_udc(gadget); - unsigned long flags; - u32 ctrl; - int ret = -EINVAL; - - spin_lock_irqsave(&udc->lock, flags); - if (udc->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { - ctrl = usba_readl(udc, CTRL); - usba_writel(udc, CTRL, ctrl | USBA_REMOTE_WAKE_UP); - ret = 0; - } - spin_unlock_irqrestore(&udc->lock, flags); - - return ret; -} - -static int -usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered) -{ - struct usba_udc *udc = to_usba_udc(gadget); - unsigned long flags; - - spin_lock_irqsave(&udc->lock, flags); - if (is_selfpowered) - udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED; - else - udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED); - spin_unlock_irqrestore(&udc->lock, flags); - - return 0; -} - -static int atmel_usba_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int atmel_usba_stop(struct usb_gadget_driver *driver); - -static const struct usb_gadget_ops usba_udc_ops = { - .get_frame = usba_udc_get_frame, - .wakeup = usba_udc_wakeup, - .set_selfpowered = usba_udc_set_selfpowered, - .start = atmel_usba_start, - .stop = atmel_usba_stop, -}; - -static struct usb_endpoint_descriptor usba_ep0_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 0, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, - .wMaxPacketSize = cpu_to_le16(64), - /* FIXME: I have no idea what to put here */ - .bInterval = 1, -}; - -static void nop_release(struct device *dev) -{ - -} - -static struct usba_udc the_udc = { - .gadget = { - .ops = &usba_udc_ops, - .ep_list = LIST_HEAD_INIT(the_udc.gadget.ep_list), - .max_speed = USB_SPEED_HIGH, - .name = "atmel_usba_udc", - .dev = { - .init_name = "gadget", - .release = nop_release, - }, - }, -}; - -/* - * Called with interrupts disabled and udc->lock held. - */ -static void reset_all_endpoints(struct usba_udc *udc) -{ - struct usba_ep *ep; - struct usba_request *req, *tmp_req; - - usba_writel(udc, EPT_RST, ~0UL); - - ep = to_usba_ep(udc->gadget.ep0); - list_for_each_entry_safe(req, tmp_req, &ep->queue, queue) { - list_del_init(&req->queue); - request_complete(ep, req, -ECONNRESET); - } - - /* NOTE: normally, the next call to the gadget driver is in - * charge of disabling endpoints... usually disconnect(). - * The exception would be entering a high speed test mode. - * - * FIXME remove this code ... and retest thoroughly. - */ - list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { - if (ep->desc) { - spin_unlock(&udc->lock); - usba_ep_disable(&ep->ep); - spin_lock(&udc->lock); - } - } -} - -static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex) -{ - struct usba_ep *ep; - - if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0) - return to_usba_ep(udc->gadget.ep0); - - list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) { - u8 bEndpointAddress; - - if (!ep->desc) - continue; - bEndpointAddress = ep->desc->bEndpointAddress; - if ((wIndex ^ bEndpointAddress) & USB_DIR_IN) - continue; - if ((bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) - == (wIndex & USB_ENDPOINT_NUMBER_MASK)) - return ep; - } - - return NULL; -} - -/* Called with interrupts disabled and udc->lock held */ -static inline void set_protocol_stall(struct usba_udc *udc, struct usba_ep *ep) -{ - usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL); - ep->state = WAIT_FOR_SETUP; -} - -static inline int is_stalled(struct usba_udc *udc, struct usba_ep *ep) -{ - if (usba_ep_readl(ep, STA) & USBA_FORCE_STALL) - return 1; - return 0; -} - -static inline void set_address(struct usba_udc *udc, unsigned int addr) -{ - u32 regval; - - DBG(DBG_BUS, "setting address %u...\n", addr); - regval = usba_readl(udc, CTRL); - regval = USBA_BFINS(DEV_ADDR, addr, regval); - usba_writel(udc, CTRL, regval); -} - -static int do_test_mode(struct usba_udc *udc) -{ - static const char test_packet_buffer[] = { - /* JKJKJKJK * 9 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* JJKKJJKK * 8 */ - 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, - /* JJKKJJKK * 8 */ - 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, - /* JJJJJJJKKKKKKK * 8 */ - 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - /* JJJJJJJK * 8 */ - 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, - /* {JKKKKKKK * 10}, JK */ - 0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0x7E - }; - struct usba_ep *ep; - struct device *dev = &udc->pdev->dev; - int test_mode; - - test_mode = udc->test_mode; - - /* Start from a clean slate */ - reset_all_endpoints(udc); - - switch (test_mode) { - case 0x0100: - /* Test_J */ - usba_writel(udc, TST, USBA_TST_J_MODE); - dev_info(dev, "Entering Test_J mode...\n"); - break; - case 0x0200: - /* Test_K */ - usba_writel(udc, TST, USBA_TST_K_MODE); - dev_info(dev, "Entering Test_K mode...\n"); - break; - case 0x0300: - /* - * Test_SE0_NAK: Force high-speed mode and set up ep0 - * for Bulk IN transfers - */ - ep = &usba_ep[0]; - usba_writel(udc, TST, - USBA_BF(SPEED_CFG, USBA_SPEED_CFG_FORCE_HIGH)); - usba_ep_writel(ep, CFG, - USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64) - | USBA_EPT_DIR_IN - | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK) - | USBA_BF(BK_NUMBER, 1)); - if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) { - set_protocol_stall(udc, ep); - dev_err(dev, "Test_SE0_NAK: ep0 not mapped\n"); - } else { - usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); - dev_info(dev, "Entering Test_SE0_NAK mode...\n"); - } - break; - case 0x0400: - /* Test_Packet */ - ep = &usba_ep[0]; - usba_ep_writel(ep, CFG, - USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64) - | USBA_EPT_DIR_IN - | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK) - | USBA_BF(BK_NUMBER, 1)); - if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) { - set_protocol_stall(udc, ep); - dev_err(dev, "Test_Packet: ep0 not mapped\n"); - } else { - usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); - usba_writel(udc, TST, USBA_TST_PKT_MODE); - memcpy_toio(ep->fifo, test_packet_buffer, - sizeof(test_packet_buffer)); - usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); - dev_info(dev, "Entering Test_Packet mode...\n"); - } - break; - default: - dev_err(dev, "Invalid test mode: 0x%04x\n", test_mode); - return -EINVAL; - } - - return 0; -} - -/* Avoid overly long expressions */ -static inline bool feature_is_dev_remote_wakeup(struct usb_ctrlrequest *crq) -{ - if (crq->wValue == cpu_to_le16(USB_DEVICE_REMOTE_WAKEUP)) - return true; - return false; -} - -static inline bool feature_is_dev_test_mode(struct usb_ctrlrequest *crq) -{ - if (crq->wValue == cpu_to_le16(USB_DEVICE_TEST_MODE)) - return true; - return false; -} - -static inline bool feature_is_ep_halt(struct usb_ctrlrequest *crq) -{ - if (crq->wValue == cpu_to_le16(USB_ENDPOINT_HALT)) - return true; - return false; -} - -static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep, - struct usb_ctrlrequest *crq) -{ - int retval = 0; - - switch (crq->bRequest) { - case USB_REQ_GET_STATUS: { - u16 status; - - if (crq->bRequestType == (USB_DIR_IN | USB_RECIP_DEVICE)) { - status = cpu_to_le16(udc->devstatus); - } else if (crq->bRequestType - == (USB_DIR_IN | USB_RECIP_INTERFACE)) { - status = cpu_to_le16(0); - } else if (crq->bRequestType - == (USB_DIR_IN | USB_RECIP_ENDPOINT)) { - struct usba_ep *target; - - target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex)); - if (!target) - goto stall; - - status = 0; - if (is_stalled(udc, target)) - status |= cpu_to_le16(1); - } else - goto delegate; - - /* Write directly to the FIFO. No queueing is done. */ - if (crq->wLength != cpu_to_le16(sizeof(status))) - goto stall; - ep->state = DATA_STAGE_IN; - __raw_writew(status, ep->fifo); - usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); - break; - } - - case USB_REQ_CLEAR_FEATURE: { - if (crq->bRequestType == USB_RECIP_DEVICE) { - if (feature_is_dev_remote_wakeup(crq)) - udc->devstatus - &= ~(1 << USB_DEVICE_REMOTE_WAKEUP); - else - /* Can't CLEAR_FEATURE TEST_MODE */ - goto stall; - } else if (crq->bRequestType == USB_RECIP_ENDPOINT) { - struct usba_ep *target; - - if (crq->wLength != cpu_to_le16(0) - || !feature_is_ep_halt(crq)) - goto stall; - target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex)); - if (!target) - goto stall; - - usba_ep_writel(target, CLR_STA, USBA_FORCE_STALL); - if (target->index != 0) - usba_ep_writel(target, CLR_STA, - USBA_TOGGLE_CLR); - } else { - goto delegate; - } - - send_status(udc, ep); - break; - } - - case USB_REQ_SET_FEATURE: { - if (crq->bRequestType == USB_RECIP_DEVICE) { - if (feature_is_dev_test_mode(crq)) { - send_status(udc, ep); - ep->state = STATUS_STAGE_TEST; - udc->test_mode = le16_to_cpu(crq->wIndex); - return 0; - } else if (feature_is_dev_remote_wakeup(crq)) { - udc->devstatus |= 1 << USB_DEVICE_REMOTE_WAKEUP; - } else { - goto stall; - } - } else if (crq->bRequestType == USB_RECIP_ENDPOINT) { - struct usba_ep *target; - - if (crq->wLength != cpu_to_le16(0) - || !feature_is_ep_halt(crq)) - goto stall; - - target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex)); - if (!target) - goto stall; - - usba_ep_writel(target, SET_STA, USBA_FORCE_STALL); - } else - goto delegate; - - send_status(udc, ep); - break; - } - - case USB_REQ_SET_ADDRESS: - if (crq->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE)) - goto delegate; - - set_address(udc, le16_to_cpu(crq->wValue)); - send_status(udc, ep); - ep->state = STATUS_STAGE_ADDR; - break; - - default: -delegate: - spin_unlock(&udc->lock); - retval = udc->driver->setup(&udc->gadget, crq); - spin_lock(&udc->lock); - } - - return retval; - -stall: - pr_err("udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, " - "halting endpoint...\n", - ep->ep.name, crq->bRequestType, crq->bRequest, - le16_to_cpu(crq->wValue), le16_to_cpu(crq->wIndex), - le16_to_cpu(crq->wLength)); - set_protocol_stall(udc, ep); - return -1; -} - -static void usba_control_irq(struct usba_udc *udc, struct usba_ep *ep) -{ - struct usba_request *req; - u32 epstatus; - u32 epctrl; - -restart: - epstatus = usba_ep_readl(ep, STA); - epctrl = usba_ep_readl(ep, CTL); - - DBG(DBG_INT, "%s [%d]: s/%08x c/%08x\n", - ep->ep.name, ep->state, epstatus, epctrl); - - req = NULL; - if (!list_empty(&ep->queue)) - req = list_entry(ep->queue.next, - struct usba_request, queue); - - if ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) { - if (req->submitted) - next_fifo_transaction(ep, req); - else - submit_request(ep, req); - - if (req->last_transaction) { - usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); - usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); - } - goto restart; - } - if ((epstatus & epctrl) & USBA_TX_COMPLETE) { - usba_ep_writel(ep, CLR_STA, USBA_TX_COMPLETE); - - switch (ep->state) { - case DATA_STAGE_IN: - usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY); - usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); - ep->state = STATUS_STAGE_OUT; - break; - case STATUS_STAGE_ADDR: - /* Activate our new address */ - usba_writel(udc, CTRL, (usba_readl(udc, CTRL) - | USBA_FADDR_EN)); - usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); - ep->state = WAIT_FOR_SETUP; - break; - case STATUS_STAGE_IN: - if (req) { - list_del_init(&req->queue); - request_complete(ep, req, 0); - submit_next_request(ep); - } - usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); - ep->state = WAIT_FOR_SETUP; - break; - case STATUS_STAGE_TEST: - usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); - ep->state = WAIT_FOR_SETUP; - if (do_test_mode(udc)) - set_protocol_stall(udc, ep); - break; - default: - pr_err("udc: %s: TXCOMP: Invalid endpoint state %d, " - "halting endpoint...\n", - ep->ep.name, ep->state); - set_protocol_stall(udc, ep); - break; - } - - goto restart; - } - if ((epstatus & epctrl) & USBA_RX_BK_RDY) { - switch (ep->state) { - case STATUS_STAGE_OUT: - usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); - usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); - - if (req) { - list_del_init(&req->queue); - request_complete(ep, req, 0); - } - ep->state = WAIT_FOR_SETUP; - break; - - case DATA_STAGE_OUT: - receive_data(ep); - break; - - default: - usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); - usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); - pr_err("udc: %s: RXRDY: Invalid endpoint state %d, " - "halting endpoint...\n", - ep->ep.name, ep->state); - set_protocol_stall(udc, ep); - break; - } - - goto restart; - } - if (epstatus & USBA_RX_SETUP) { - union { - struct usb_ctrlrequest crq; - unsigned long data[2]; - } crq; - unsigned int pkt_len; - int ret; - - if (ep->state != WAIT_FOR_SETUP) { - /* - * Didn't expect a SETUP packet at this - * point. Clean up any pending requests (which - * may be successful). - */ - int status = -EPROTO; - - /* - * RXRDY and TXCOMP are dropped when SETUP - * packets arrive. Just pretend we received - * the status packet. - */ - if (ep->state == STATUS_STAGE_OUT - || ep->state == STATUS_STAGE_IN) { - usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); - status = 0; - } - - if (req) { - list_del_init(&req->queue); - request_complete(ep, req, status); - } - } - - pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA)); - DBG(DBG_HW, "Packet length: %u\n", pkt_len); - if (pkt_len != sizeof(crq)) { - pr_warning("udc: Invalid packet length %u " - "(expected %zu)\n", pkt_len, sizeof(crq)); - set_protocol_stall(udc, ep); - return; - } - - DBG(DBG_FIFO, "Copying ctrl request from 0x%p:\n", ep->fifo); - memcpy_fromio(crq.data, ep->fifo, sizeof(crq)); - - /* Free up one bank in the FIFO so that we can - * generate or receive a reply right away. */ - usba_ep_writel(ep, CLR_STA, USBA_RX_SETUP); - - /* printk(KERN_DEBUG "setup: %d: %02x.%02x\n", - ep->state, crq.crq.bRequestType, - crq.crq.bRequest); */ - - if (crq.crq.bRequestType & USB_DIR_IN) { - /* - * The USB 2.0 spec states that "if wLength is - * zero, there is no data transfer phase." - * However, testusb #14 seems to actually - * expect a data phase even if wLength = 0... - */ - ep->state = DATA_STAGE_IN; - } else { - if (crq.crq.wLength != cpu_to_le16(0)) - ep->state = DATA_STAGE_OUT; - else - ep->state = STATUS_STAGE_IN; - } - - ret = -1; - if (ep->index == 0) - ret = handle_ep0_setup(udc, ep, &crq.crq); - else { - spin_unlock(&udc->lock); - ret = udc->driver->setup(&udc->gadget, &crq.crq); - spin_lock(&udc->lock); - } - - DBG(DBG_BUS, "req %02x.%02x, length %d, state %d, ret %d\n", - crq.crq.bRequestType, crq.crq.bRequest, - le16_to_cpu(crq.crq.wLength), ep->state, ret); - - if (ret < 0) { - /* Let the host know that we failed */ - set_protocol_stall(udc, ep); - } - } -} - -static void usba_ep_irq(struct usba_udc *udc, struct usba_ep *ep) -{ - struct usba_request *req; - u32 epstatus; - u32 epctrl; - - epstatus = usba_ep_readl(ep, STA); - epctrl = usba_ep_readl(ep, CTL); - - DBG(DBG_INT, "%s: interrupt, status: 0x%08x\n", ep->ep.name, epstatus); - - while ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) { - DBG(DBG_BUS, "%s: TX PK ready\n", ep->ep.name); - - if (list_empty(&ep->queue)) { - dev_warn(&udc->pdev->dev, "ep_irq: queue empty\n"); - usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); - return; - } - - req = list_entry(ep->queue.next, struct usba_request, queue); - - if (req->using_dma) { - /* Send a zero-length packet */ - usba_ep_writel(ep, SET_STA, - USBA_TX_PK_RDY); - usba_ep_writel(ep, CTL_DIS, - USBA_TX_PK_RDY); - list_del_init(&req->queue); - submit_next_request(ep); - request_complete(ep, req, 0); - } else { - if (req->submitted) - next_fifo_transaction(ep, req); - else - submit_request(ep, req); - - if (req->last_transaction) { - list_del_init(&req->queue); - submit_next_request(ep); - request_complete(ep, req, 0); - } - } - - epstatus = usba_ep_readl(ep, STA); - epctrl = usba_ep_readl(ep, CTL); - } - if ((epstatus & epctrl) & USBA_RX_BK_RDY) { - DBG(DBG_BUS, "%s: RX data ready\n", ep->ep.name); - receive_data(ep); - usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); - } -} - -static void usba_dma_irq(struct usba_udc *udc, struct usba_ep *ep) -{ - struct usba_request *req; - u32 status, control, pending; - - status = usba_dma_readl(ep, STATUS); - control = usba_dma_readl(ep, CONTROL); -#ifdef CONFIG_USB_GADGET_DEBUG_FS - ep->last_dma_status = status; -#endif - pending = status & control; - DBG(DBG_INT | DBG_DMA, "dma irq, s/%#08x, c/%#08x\n", status, control); - - if (status & USBA_DMA_CH_EN) { - dev_err(&udc->pdev->dev, - "DMA_CH_EN is set after transfer is finished!\n"); - dev_err(&udc->pdev->dev, - "status=%#08x, pending=%#08x, control=%#08x\n", - status, pending, control); - - /* - * try to pretend nothing happened. We might have to - * do something here... - */ - } - - if (list_empty(&ep->queue)) - /* Might happen if a reset comes along at the right moment */ - return; - - if (pending & (USBA_DMA_END_TR_ST | USBA_DMA_END_BUF_ST)) { - req = list_entry(ep->queue.next, struct usba_request, queue); - usba_update_req(ep, req, status); - - list_del_init(&req->queue); - submit_next_request(ep); - request_complete(ep, req, 0); - } -} - -static irqreturn_t usba_udc_irq(int irq, void *devid) -{ - struct usba_udc *udc = devid; - u32 status; - u32 dma_status; - u32 ep_status; - - spin_lock(&udc->lock); - - status = usba_readl(udc, INT_STA); - DBG(DBG_INT, "irq, status=%#08x\n", status); - - if (status & USBA_DET_SUSPEND) { - toggle_bias(0); - usba_writel(udc, INT_CLR, USBA_DET_SUSPEND); - DBG(DBG_BUS, "Suspend detected\n"); - if (udc->gadget.speed != USB_SPEED_UNKNOWN - && udc->driver && udc->driver->suspend) { - spin_unlock(&udc->lock); - udc->driver->suspend(&udc->gadget); - spin_lock(&udc->lock); - } - } - - if (status & USBA_WAKE_UP) { - toggle_bias(1); - usba_writel(udc, INT_CLR, USBA_WAKE_UP); - DBG(DBG_BUS, "Wake Up CPU detected\n"); - } - - if (status & USBA_END_OF_RESUME) { - usba_writel(udc, INT_CLR, USBA_END_OF_RESUME); - DBG(DBG_BUS, "Resume detected\n"); - if (udc->gadget.speed != USB_SPEED_UNKNOWN - && udc->driver && udc->driver->resume) { - spin_unlock(&udc->lock); - udc->driver->resume(&udc->gadget); - spin_lock(&udc->lock); - } - } - - dma_status = USBA_BFEXT(DMA_INT, status); - if (dma_status) { - int i; - - for (i = 1; i < USBA_NR_ENDPOINTS; i++) - if (dma_status & (1 << i)) - usba_dma_irq(udc, &usba_ep[i]); - } - - ep_status = USBA_BFEXT(EPT_INT, status); - if (ep_status) { - int i; - - for (i = 0; i < USBA_NR_ENDPOINTS; i++) - if (ep_status & (1 << i)) { - if (ep_is_control(&usba_ep[i])) - usba_control_irq(udc, &usba_ep[i]); - else - usba_ep_irq(udc, &usba_ep[i]); - } - } - - if (status & USBA_END_OF_RESET) { - struct usba_ep *ep0; - - usba_writel(udc, INT_CLR, USBA_END_OF_RESET); - reset_all_endpoints(udc); - - if (udc->gadget.speed != USB_SPEED_UNKNOWN - && udc->driver->disconnect) { - udc->gadget.speed = USB_SPEED_UNKNOWN; - spin_unlock(&udc->lock); - udc->driver->disconnect(&udc->gadget); - spin_lock(&udc->lock); - } - - if (status & USBA_HIGH_SPEED) - udc->gadget.speed = USB_SPEED_HIGH; - else - udc->gadget.speed = USB_SPEED_FULL; - DBG(DBG_BUS, "%s bus reset detected\n", - usb_speed_string(udc->gadget.speed)); - - ep0 = &usba_ep[0]; - ep0->desc = &usba_ep0_desc; - ep0->state = WAIT_FOR_SETUP; - usba_ep_writel(ep0, CFG, - (USBA_BF(EPT_SIZE, EP0_EPT_SIZE) - | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL) - | USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE))); - usba_ep_writel(ep0, CTL_ENB, - USBA_EPT_ENABLE | USBA_RX_SETUP); - usba_writel(udc, INT_ENB, - (usba_readl(udc, INT_ENB) - | USBA_BF(EPT_INT, 1) - | USBA_DET_SUSPEND - | USBA_END_OF_RESUME)); - - /* - * Unclear why we hit this irregularly, e.g. in usbtest, - * but it's clearly harmless... - */ - if (!(usba_ep_readl(ep0, CFG) & USBA_EPT_MAPPED)) - dev_dbg(&udc->pdev->dev, - "ODD: EP0 configuration is invalid!\n"); - } - - spin_unlock(&udc->lock); - - return IRQ_HANDLED; -} - -static irqreturn_t usba_vbus_irq(int irq, void *devid) -{ - struct usba_udc *udc = devid; - int vbus; - - /* debounce */ - udelay(10); - - spin_lock(&udc->lock); - - /* May happen if Vbus pin toggles during probe() */ - if (!udc->driver) - goto out; - - vbus = vbus_is_present(udc); - if (vbus != udc->vbus_prev) { - if (vbus) { - toggle_bias(1); - usba_writel(udc, CTRL, USBA_ENABLE_MASK); - usba_writel(udc, INT_ENB, USBA_END_OF_RESET); - } else { - udc->gadget.speed = USB_SPEED_UNKNOWN; - reset_all_endpoints(udc); - toggle_bias(0); - usba_writel(udc, CTRL, USBA_DISABLE_MASK); - if (udc->driver->disconnect) { - spin_unlock(&udc->lock); - udc->driver->disconnect(&udc->gadget); - spin_lock(&udc->lock); - } - } - udc->vbus_prev = vbus; - } - -out: - spin_unlock(&udc->lock); - - return IRQ_HANDLED; -} - -static int atmel_usba_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) -{ - struct usba_udc *udc = &the_udc; - unsigned long flags; - int ret; - - if (!udc->pdev) - return -ENODEV; - - spin_lock_irqsave(&udc->lock, flags); - if (udc->driver) { - spin_unlock_irqrestore(&udc->lock, flags); - return -EBUSY; - } - - udc->devstatus = 1 << USB_DEVICE_SELF_POWERED; - udc->driver = driver; - udc->gadget.dev.driver = &driver->driver; - spin_unlock_irqrestore(&udc->lock, flags); - - clk_enable(udc->pclk); - clk_enable(udc->hclk); - - ret = bind(&udc->gadget); - if (ret) { - DBG(DBG_ERR, "Could not bind to driver %s: error %d\n", - driver->driver.name, ret); - goto err_driver_bind; - } - - DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name); - - udc->vbus_prev = 0; - if (gpio_is_valid(udc->vbus_pin)) - enable_irq(gpio_to_irq(udc->vbus_pin)); - - /* If Vbus is present, enable the controller and wait for reset */ - spin_lock_irqsave(&udc->lock, flags); - if (vbus_is_present(udc) && udc->vbus_prev == 0) { - toggle_bias(1); - usba_writel(udc, CTRL, USBA_ENABLE_MASK); - usba_writel(udc, INT_ENB, USBA_END_OF_RESET); - } - spin_unlock_irqrestore(&udc->lock, flags); - - return 0; - -err_driver_bind: - udc->driver = NULL; - udc->gadget.dev.driver = NULL; - return ret; -} - -static int atmel_usba_stop(struct usb_gadget_driver *driver) -{ - struct usba_udc *udc = &the_udc; - unsigned long flags; - - if (!udc->pdev) - return -ENODEV; - if (driver != udc->driver || !driver->unbind) - return -EINVAL; - - if (gpio_is_valid(udc->vbus_pin)) - disable_irq(gpio_to_irq(udc->vbus_pin)); - - spin_lock_irqsave(&udc->lock, flags); - udc->gadget.speed = USB_SPEED_UNKNOWN; - reset_all_endpoints(udc); - spin_unlock_irqrestore(&udc->lock, flags); - - /* This will also disable the DP pullup */ - toggle_bias(0); - usba_writel(udc, CTRL, USBA_DISABLE_MASK); - - if (udc->driver->disconnect) - udc->driver->disconnect(&udc->gadget); - - driver->unbind(&udc->gadget); - udc->gadget.dev.driver = NULL; - udc->driver = NULL; - - clk_disable(udc->hclk); - clk_disable(udc->pclk); - - DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name); - - return 0; -} - -static int __init usba_udc_probe(struct platform_device *pdev) -{ - struct usba_platform_data *pdata = pdev->dev.platform_data; - struct resource *regs, *fifo; - struct clk *pclk, *hclk; - struct usba_udc *udc = &the_udc; - int irq, ret, i; - - regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID); - fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID); - if (!regs || !fifo || !pdata) - return -ENXIO; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - - pclk = clk_get(&pdev->dev, "pclk"); - if (IS_ERR(pclk)) - return PTR_ERR(pclk); - hclk = clk_get(&pdev->dev, "hclk"); - if (IS_ERR(hclk)) { - ret = PTR_ERR(hclk); - goto err_get_hclk; - } - - spin_lock_init(&udc->lock); - udc->pdev = pdev; - udc->pclk = pclk; - udc->hclk = hclk; - udc->vbus_pin = -ENODEV; - - ret = -ENOMEM; - udc->regs = ioremap(regs->start, resource_size(regs)); - if (!udc->regs) { - dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n"); - goto err_map_regs; - } - dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n", - (unsigned long)regs->start, udc->regs); - udc->fifo = ioremap(fifo->start, resource_size(fifo)); - if (!udc->fifo) { - dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n"); - goto err_map_fifo; - } - dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n", - (unsigned long)fifo->start, udc->fifo); - - device_initialize(&udc->gadget.dev); - udc->gadget.dev.parent = &pdev->dev; - udc->gadget.dev.dma_mask = pdev->dev.dma_mask; - - platform_set_drvdata(pdev, udc); - - /* Make sure we start from a clean slate */ - clk_enable(pclk); - toggle_bias(0); - usba_writel(udc, CTRL, USBA_DISABLE_MASK); - clk_disable(pclk); - - usba_ep = kzalloc(sizeof(struct usba_ep) * pdata->num_ep, - GFP_KERNEL); - if (!usba_ep) - goto err_alloc_ep; - - the_udc.gadget.ep0 = &usba_ep[0].ep; - - INIT_LIST_HEAD(&usba_ep[0].ep.ep_list); - usba_ep[0].ep_regs = udc->regs + USBA_EPT_BASE(0); - usba_ep[0].dma_regs = udc->regs + USBA_DMA_BASE(0); - usba_ep[0].fifo = udc->fifo + USBA_FIFO_BASE(0); - usba_ep[0].ep.ops = &usba_ep_ops; - usba_ep[0].ep.name = pdata->ep[0].name; - usba_ep[0].ep.maxpacket = pdata->ep[0].fifo_size; - usba_ep[0].udc = &the_udc; - INIT_LIST_HEAD(&usba_ep[0].queue); - usba_ep[0].fifo_size = pdata->ep[0].fifo_size; - usba_ep[0].nr_banks = pdata->ep[0].nr_banks; - usba_ep[0].index = pdata->ep[0].index; - usba_ep[0].can_dma = pdata->ep[0].can_dma; - usba_ep[0].can_isoc = pdata->ep[0].can_isoc; - - for (i = 1; i < pdata->num_ep; i++) { - struct usba_ep *ep = &usba_ep[i]; - - ep->ep_regs = udc->regs + USBA_EPT_BASE(i); - ep->dma_regs = udc->regs + USBA_DMA_BASE(i); - ep->fifo = udc->fifo + USBA_FIFO_BASE(i); - ep->ep.ops = &usba_ep_ops; - ep->ep.name = pdata->ep[i].name; - ep->ep.maxpacket = pdata->ep[i].fifo_size; - ep->udc = &the_udc; - INIT_LIST_HEAD(&ep->queue); - ep->fifo_size = pdata->ep[i].fifo_size; - ep->nr_banks = pdata->ep[i].nr_banks; - ep->index = pdata->ep[i].index; - ep->can_dma = pdata->ep[i].can_dma; - ep->can_isoc = pdata->ep[i].can_isoc; - - list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); - } - - ret = request_irq(irq, usba_udc_irq, 0, "atmel_usba_udc", udc); - if (ret) { - dev_err(&pdev->dev, "Cannot request irq %d (error %d)\n", - irq, ret); - goto err_request_irq; - } - udc->irq = irq; - - ret = device_add(&udc->gadget.dev); - if (ret) { - dev_dbg(&pdev->dev, "Could not add gadget: %d\n", ret); - goto err_device_add; - } - - if (gpio_is_valid(pdata->vbus_pin)) { - if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) { - udc->vbus_pin = pdata->vbus_pin; - udc->vbus_pin_inverted = pdata->vbus_pin_inverted; - - ret = request_irq(gpio_to_irq(udc->vbus_pin), - usba_vbus_irq, 0, - "atmel_usba_udc", udc); - if (ret) { - gpio_free(udc->vbus_pin); - udc->vbus_pin = -ENODEV; - dev_warn(&udc->pdev->dev, - "failed to request vbus irq; " - "assuming always on\n"); - } else { - disable_irq(gpio_to_irq(udc->vbus_pin)); - } - } else { - /* gpio_request fail so use -EINVAL for gpio_is_valid */ - udc->vbus_pin = -EINVAL; - } - } - - ret = usb_add_gadget_udc(&pdev->dev, &udc->gadget); - if (ret) - goto err_add_udc; - - usba_init_debugfs(udc); - for (i = 1; i < pdata->num_ep; i++) - usba_ep_init_debugfs(udc, &usba_ep[i]); - - return 0; - -err_add_udc: - if (gpio_is_valid(pdata->vbus_pin)) { - free_irq(gpio_to_irq(udc->vbus_pin), udc); - gpio_free(udc->vbus_pin); - } - - device_unregister(&udc->gadget.dev); - -err_device_add: - free_irq(irq, udc); -err_request_irq: - kfree(usba_ep); -err_alloc_ep: - iounmap(udc->fifo); -err_map_fifo: - iounmap(udc->regs); -err_map_regs: - clk_put(hclk); -err_get_hclk: - clk_put(pclk); - - platform_set_drvdata(pdev, NULL); - - return ret; -} - -static int __exit usba_udc_remove(struct platform_device *pdev) -{ - struct usba_udc *udc; - int i; - struct usba_platform_data *pdata = pdev->dev.platform_data; - - udc = platform_get_drvdata(pdev); - - usb_del_gadget_udc(&udc->gadget); - - for (i = 1; i < pdata->num_ep; i++) - usba_ep_cleanup_debugfs(&usba_ep[i]); - usba_cleanup_debugfs(udc); - - if (gpio_is_valid(udc->vbus_pin)) { - free_irq(gpio_to_irq(udc->vbus_pin), udc); - gpio_free(udc->vbus_pin); - } - - free_irq(udc->irq, udc); - kfree(usba_ep); - iounmap(udc->fifo); - iounmap(udc->regs); - clk_put(udc->hclk); - clk_put(udc->pclk); - - device_unregister(&udc->gadget.dev); - - return 0; -} - -static struct platform_driver udc_driver = { - .remove = __exit_p(usba_udc_remove), - .driver = { - .name = "atmel_usba_udc", - .owner = THIS_MODULE, - }, -}; - -static int __init udc_init(void) -{ - return platform_driver_probe(&udc_driver, usba_udc_probe); -} -module_init(udc_init); - -static void __exit udc_exit(void) -{ - platform_driver_unregister(&udc_driver); -} -module_exit(udc_exit); - -MODULE_DESCRIPTION("Atmel USBA UDC driver"); -MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:atmel_usba_udc"); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/atmel_usba_udc.h b/ANDROID_3.4.5/drivers/usb/gadget/atmel_usba_udc.h deleted file mode 100644 index 88a2e07a..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/atmel_usba_udc.h +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Driver for the Atmel USBA high speed USB device controller - * - * Copyright (C) 2005-2007 Atmel Corporation - * - * 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 __LINUX_USB_GADGET_USBA_UDC_H__ -#define __LINUX_USB_GADGET_USBA_UDC_H__ - -/* USB register offsets */ -#define USBA_CTRL 0x0000 -#define USBA_FNUM 0x0004 -#define USBA_INT_ENB 0x0010 -#define USBA_INT_STA 0x0014 -#define USBA_INT_CLR 0x0018 -#define USBA_EPT_RST 0x001c -#define USBA_TST 0x00e0 - -/* USB endpoint register offsets */ -#define USBA_EPT_CFG 0x0000 -#define USBA_EPT_CTL_ENB 0x0004 -#define USBA_EPT_CTL_DIS 0x0008 -#define USBA_EPT_CTL 0x000c -#define USBA_EPT_SET_STA 0x0014 -#define USBA_EPT_CLR_STA 0x0018 -#define USBA_EPT_STA 0x001c - -/* USB DMA register offsets */ -#define USBA_DMA_NXT_DSC 0x0000 -#define USBA_DMA_ADDRESS 0x0004 -#define USBA_DMA_CONTROL 0x0008 -#define USBA_DMA_STATUS 0x000c - -/* Bitfields in CTRL */ -#define USBA_DEV_ADDR_OFFSET 0 -#define USBA_DEV_ADDR_SIZE 7 -#define USBA_FADDR_EN (1 << 7) -#define USBA_EN_USBA (1 << 8) -#define USBA_DETACH (1 << 9) -#define USBA_REMOTE_WAKE_UP (1 << 10) -#define USBA_PULLD_DIS (1 << 11) - -#if defined(CONFIG_AVR32) -#define USBA_ENABLE_MASK USBA_EN_USBA -#define USBA_DISABLE_MASK 0 -#elif defined(CONFIG_ARCH_AT91) -#define USBA_ENABLE_MASK (USBA_EN_USBA | USBA_PULLD_DIS) -#define USBA_DISABLE_MASK USBA_DETACH -#endif /* CONFIG_ARCH_AT91 */ - -/* Bitfields in FNUM */ -#define USBA_MICRO_FRAME_NUM_OFFSET 0 -#define USBA_MICRO_FRAME_NUM_SIZE 3 -#define USBA_FRAME_NUMBER_OFFSET 3 -#define USBA_FRAME_NUMBER_SIZE 11 -#define USBA_FRAME_NUM_ERROR (1 << 31) - -/* Bitfields in INT_ENB/INT_STA/INT_CLR */ -#define USBA_HIGH_SPEED (1 << 0) -#define USBA_DET_SUSPEND (1 << 1) -#define USBA_MICRO_SOF (1 << 2) -#define USBA_SOF (1 << 3) -#define USBA_END_OF_RESET (1 << 4) -#define USBA_WAKE_UP (1 << 5) -#define USBA_END_OF_RESUME (1 << 6) -#define USBA_UPSTREAM_RESUME (1 << 7) -#define USBA_EPT_INT_OFFSET 8 -#define USBA_EPT_INT_SIZE 16 -#define USBA_DMA_INT_OFFSET 24 -#define USBA_DMA_INT_SIZE 8 - -/* Bitfields in EPT_RST */ -#define USBA_RST_OFFSET 0 -#define USBA_RST_SIZE 16 - -/* Bitfields in USBA_TST */ -#define USBA_SPEED_CFG_OFFSET 0 -#define USBA_SPEED_CFG_SIZE 2 -#define USBA_TST_J_MODE (1 << 2) -#define USBA_TST_K_MODE (1 << 3) -#define USBA_TST_PKT_MODE (1 << 4) -#define USBA_OPMODE2 (1 << 5) - -/* Bitfields in EPT_CFG */ -#define USBA_EPT_SIZE_OFFSET 0 -#define USBA_EPT_SIZE_SIZE 3 -#define USBA_EPT_DIR_IN (1 << 3) -#define USBA_EPT_TYPE_OFFSET 4 -#define USBA_EPT_TYPE_SIZE 2 -#define USBA_BK_NUMBER_OFFSET 6 -#define USBA_BK_NUMBER_SIZE 2 -#define USBA_NB_TRANS_OFFSET 8 -#define USBA_NB_TRANS_SIZE 2 -#define USBA_EPT_MAPPED (1 << 31) - -/* Bitfields in EPT_CTL/EPT_CTL_ENB/EPT_CTL_DIS */ -#define USBA_EPT_ENABLE (1 << 0) -#define USBA_AUTO_VALID (1 << 1) -#define USBA_INTDIS_DMA (1 << 3) -#define USBA_NYET_DIS (1 << 4) -#define USBA_DATAX_RX (1 << 6) -#define USBA_MDATA_RX (1 << 7) -/* Bits 8-15 and 31 enable interrupts for respective bits in EPT_STA */ -#define USBA_BUSY_BANK_IE (1 << 18) - -/* Bitfields in EPT_SET_STA/EPT_CLR_STA/EPT_STA */ -#define USBA_FORCE_STALL (1 << 5) -#define USBA_TOGGLE_CLR (1 << 6) -#define USBA_TOGGLE_SEQ_OFFSET 6 -#define USBA_TOGGLE_SEQ_SIZE 2 -#define USBA_ERR_OVFLW (1 << 8) -#define USBA_RX_BK_RDY (1 << 9) -#define USBA_KILL_BANK (1 << 9) -#define USBA_TX_COMPLETE (1 << 10) -#define USBA_TX_PK_RDY (1 << 11) -#define USBA_ISO_ERR_TRANS (1 << 11) -#define USBA_RX_SETUP (1 << 12) -#define USBA_ISO_ERR_FLOW (1 << 12) -#define USBA_STALL_SENT (1 << 13) -#define USBA_ISO_ERR_CRC (1 << 13) -#define USBA_ISO_ERR_NBTRANS (1 << 13) -#define USBA_NAK_IN (1 << 14) -#define USBA_ISO_ERR_FLUSH (1 << 14) -#define USBA_NAK_OUT (1 << 15) -#define USBA_CURRENT_BANK_OFFSET 16 -#define USBA_CURRENT_BANK_SIZE 2 -#define USBA_BUSY_BANKS_OFFSET 18 -#define USBA_BUSY_BANKS_SIZE 2 -#define USBA_BYTE_COUNT_OFFSET 20 -#define USBA_BYTE_COUNT_SIZE 11 -#define USBA_SHORT_PACKET (1 << 31) - -/* Bitfields in DMA_CONTROL */ -#define USBA_DMA_CH_EN (1 << 0) -#define USBA_DMA_LINK (1 << 1) -#define USBA_DMA_END_TR_EN (1 << 2) -#define USBA_DMA_END_BUF_EN (1 << 3) -#define USBA_DMA_END_TR_IE (1 << 4) -#define USBA_DMA_END_BUF_IE (1 << 5) -#define USBA_DMA_DESC_LOAD_IE (1 << 6) -#define USBA_DMA_BURST_LOCK (1 << 7) -#define USBA_DMA_BUF_LEN_OFFSET 16 -#define USBA_DMA_BUF_LEN_SIZE 16 - -/* Bitfields in DMA_STATUS */ -#define USBA_DMA_CH_ACTIVE (1 << 1) -#define USBA_DMA_END_TR_ST (1 << 4) -#define USBA_DMA_END_BUF_ST (1 << 5) -#define USBA_DMA_DESC_LOAD_ST (1 << 6) - -/* Constants for SPEED_CFG */ -#define USBA_SPEED_CFG_NORMAL 0 -#define USBA_SPEED_CFG_FORCE_HIGH 2 -#define USBA_SPEED_CFG_FORCE_FULL 3 - -/* Constants for EPT_SIZE */ -#define USBA_EPT_SIZE_8 0 -#define USBA_EPT_SIZE_16 1 -#define USBA_EPT_SIZE_32 2 -#define USBA_EPT_SIZE_64 3 -#define USBA_EPT_SIZE_128 4 -#define USBA_EPT_SIZE_256 5 -#define USBA_EPT_SIZE_512 6 -#define USBA_EPT_SIZE_1024 7 - -/* Constants for EPT_TYPE */ -#define USBA_EPT_TYPE_CONTROL 0 -#define USBA_EPT_TYPE_ISO 1 -#define USBA_EPT_TYPE_BULK 2 -#define USBA_EPT_TYPE_INT 3 - -/* Constants for BK_NUMBER */ -#define USBA_BK_NUMBER_ZERO 0 -#define USBA_BK_NUMBER_ONE 1 -#define USBA_BK_NUMBER_DOUBLE 2 -#define USBA_BK_NUMBER_TRIPLE 3 - -/* Bit manipulation macros */ -#define USBA_BF(name, value) \ - (((value) & ((1 << USBA_##name##_SIZE) - 1)) \ - << USBA_##name##_OFFSET) -#define USBA_BFEXT(name, value) \ - (((value) >> USBA_##name##_OFFSET) \ - & ((1 << USBA_##name##_SIZE) - 1)) -#define USBA_BFINS(name, value, old) \ - (((old) & ~(((1 << USBA_##name##_SIZE) - 1) \ - << USBA_##name##_OFFSET)) \ - | USBA_BF(name, value)) - -/* Register access macros */ -#define usba_readl(udc, reg) \ - __raw_readl((udc)->regs + USBA_##reg) -#define usba_writel(udc, reg, value) \ - __raw_writel((value), (udc)->regs + USBA_##reg) -#define usba_ep_readl(ep, reg) \ - __raw_readl((ep)->ep_regs + USBA_EPT_##reg) -#define usba_ep_writel(ep, reg, value) \ - __raw_writel((value), (ep)->ep_regs + USBA_EPT_##reg) -#define usba_dma_readl(ep, reg) \ - __raw_readl((ep)->dma_regs + USBA_DMA_##reg) -#define usba_dma_writel(ep, reg, value) \ - __raw_writel((value), (ep)->dma_regs + USBA_DMA_##reg) - -/* Calculate base address for a given endpoint or DMA controller */ -#define USBA_EPT_BASE(x) (0x100 + (x) * 0x20) -#define USBA_DMA_BASE(x) (0x300 + (x) * 0x10) -#define USBA_FIFO_BASE(x) ((x) << 16) - -/* Synth parameters */ -#define USBA_NR_ENDPOINTS 7 - -#define EP0_FIFO_SIZE 64 -#define EP0_EPT_SIZE USBA_EPT_SIZE_64 -#define EP0_NR_BANKS 1 - -/* - * REVISIT: Try to eliminate this value. Can we rely on req->mapped to - * provide this information? - */ -#define DMA_ADDR_INVALID (~(dma_addr_t)0) - -#define FIFO_IOMEM_ID 0 -#define CTRL_IOMEM_ID 1 - -#define DBG_ERR 0x0001 /* report all error returns */ -#define DBG_HW 0x0002 /* debug hardware initialization */ -#define DBG_GADGET 0x0004 /* calls to/from gadget driver */ -#define DBG_INT 0x0008 /* interrupts */ -#define DBG_BUS 0x0010 /* report changes in bus state */ -#define DBG_QUEUE 0x0020 /* debug request queue processing */ -#define DBG_FIFO 0x0040 /* debug FIFO contents */ -#define DBG_DMA 0x0080 /* debug DMA handling */ -#define DBG_REQ 0x0100 /* print out queued request length */ -#define DBG_ALL 0xffff -#define DBG_NONE 0x0000 - -#define DEBUG_LEVEL (DBG_ERR) - -#define DBG(level, fmt, ...) \ - do { \ - if ((level) & DEBUG_LEVEL) \ - pr_debug("udc: " fmt, ## __VA_ARGS__); \ - } while (0) - -enum usba_ctrl_state { - WAIT_FOR_SETUP, - DATA_STAGE_IN, - DATA_STAGE_OUT, - STATUS_STAGE_IN, - STATUS_STAGE_OUT, - STATUS_STAGE_ADDR, - STATUS_STAGE_TEST, -}; -/* - EP_STATE_IDLE, - EP_STATE_SETUP, - EP_STATE_IN_DATA, - EP_STATE_OUT_DATA, - EP_STATE_SET_ADDR_STATUS, - EP_STATE_RX_STATUS, - EP_STATE_TX_STATUS, - EP_STATE_HALT, -*/ - -struct usba_dma_desc { - dma_addr_t next; - dma_addr_t addr; - u32 ctrl; -}; - -struct usba_ep { - int state; - void __iomem *ep_regs; - void __iomem *dma_regs; - void __iomem *fifo; - struct usb_ep ep; - struct usba_udc *udc; - - struct list_head queue; - const struct usb_endpoint_descriptor *desc; - - u16 fifo_size; - u8 nr_banks; - u8 index; - unsigned int can_dma:1; - unsigned int can_isoc:1; - unsigned int is_isoc:1; - unsigned int is_in:1; - -#ifdef CONFIG_USB_GADGET_DEBUG_FS - u32 last_dma_status; - struct dentry *debugfs_dir; - struct dentry *debugfs_queue; - struct dentry *debugfs_dma_status; - struct dentry *debugfs_state; -#endif -}; - -struct usba_request { - struct usb_request req; - struct list_head queue; - - u32 ctrl; - - unsigned int submitted:1; - unsigned int last_transaction:1; - unsigned int using_dma:1; - unsigned int mapped:1; -}; - -struct usba_udc { - /* Protect hw registers from concurrent modifications */ - spinlock_t lock; - - void __iomem *regs; - void __iomem *fifo; - - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - struct platform_device *pdev; - int irq; - int vbus_pin; - int vbus_pin_inverted; - struct clk *pclk; - struct clk *hclk; - - u16 devstatus; - - u16 test_mode; - int vbus_prev; - -#ifdef CONFIG_USB_GADGET_DEBUG_FS - struct dentry *debugfs_root; - struct dentry *debugfs_regs; -#endif -}; - -static inline struct usba_ep *to_usba_ep(struct usb_ep *ep) -{ - return container_of(ep, struct usba_ep, ep); -} - -static inline struct usba_request *to_usba_req(struct usb_request *req) -{ - return container_of(req, struct usba_request, req); -} - -static inline struct usba_udc *to_usba_udc(struct usb_gadget *gadget) -{ - return container_of(gadget, struct usba_udc, gadget); -} - -#define ep_is_control(ep) ((ep)->index == 0) -#define ep_is_idle(ep) ((ep)->state == EP_STATE_IDLE) - -#endif /* __LINUX_USB_GADGET_USBA_UDC_H */ diff --git a/ANDROID_3.4.5/drivers/usb/gadget/audio.c b/ANDROID_3.4.5/drivers/usb/gadget/audio.c deleted file mode 100644 index 98899244..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/audio.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * audio.c -- Audio gadget driver - * - * Copyright (C) 2008 Bryan Wu - * Copyright (C) 2008 Analog Devices, Inc - * - * Enter bugs at http://blackfin.uclinux.org/ - * - * Licensed under the GPL-2 or later. - */ - -/* #define VERBOSE_DEBUG */ - -#include -#include - -#define DRIVER_DESC "Linux USB Audio Gadget" -#define DRIVER_VERSION "Feb 2, 2012" - -/*-------------------------------------------------------------------------*/ - -/* - * 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" - -/* 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, -}; - -#ifdef CONFIG_GADGET_UAC1 -#include "u_uac1.h" -#include "u_uac1.c" -#include "f_uac1.c" -#else -#include "f_uac2.c" -#endif - -/*-------------------------------------------------------------------------*/ - -/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! - * Instead: allocate your own, using normal USB-IF procedures. - */ - -/* Thanks to Linux Foundation for donating this product ID. */ -#define AUDIO_VENDOR_NUM 0x1d6b /* Linux Foundation */ -#define AUDIO_PRODUCT_NUM 0x0101 /* 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), - -#ifdef CONFIG_GADGET_UAC1 - .bDeviceClass = USB_CLASS_PER_INTERFACE, - .bDeviceSubClass = 0, - .bDeviceProtocol = 0, -#else - .bDeviceClass = USB_CLASS_MISC, - .bDeviceSubClass = 0x02, - .bDeviceProtocol = 0x01, -#endif - /* .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, -}; - -/*-------------------------------------------------------------------------*/ - -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, - .bConfigurationValue = 1, - /* .iConfiguration = DYNAMIC */ - .bmAttributes = USB_CONFIG_ATT_SELFPOWER, -#ifndef CONFIG_GADGET_UAC1 - .unbind = uac2_unbind_config, -#endif -}; - -/*-------------------------------------------------------------------------*/ - -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, audio_do_config); - 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) -{ -#ifdef CONFIG_GADGET_UAC1 - gaudio_cleanup(); -#endif - return 0; -} - -static struct usb_composite_driver audio_driver = { - .name = "g_audio", - .dev = &device_desc, - .strings = audio_strings, - .max_speed = USB_SPEED_HIGH, - .unbind = __exit_p(audio_unbind), -}; - -static int __init init(void) -{ - return usb_composite_probe(&audio_driver, audio_bind); -} -module_init(init); - -static void __exit cleanup(void) -{ - usb_composite_unregister(&audio_driver); -} -module_exit(cleanup); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Bryan Wu "); -MODULE_LICENSE("GPL"); - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/cdc2.c b/ANDROID_3.4.5/drivers/usb/gadget/cdc2.c deleted file mode 100644 index 725550f0..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/cdc2.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - * cdc2.c -- CDC Composite driver, with ECM and ACM support - * - * Copyright (C) 2008 David Brownell - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include - -#include "u_ether.h" -#include "u_serial.h" - - -#define DRIVER_DESC "CDC Composite Gadget" -#define DRIVER_VERSION "King Kamehameha Day 2008" - -/*-------------------------------------------------------------------------*/ - -/* 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. - * It's for devices with only this composite CDC configuration. - */ -#define CDC_VENDOR_NUM 0x0525 /* NetChip */ -#define CDC_PRODUCT_NUM 0xa4aa /* CDC Composite: ECM + ACM */ - -/*-------------------------------------------------------------------------*/ - -/* - * 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_serial.c" -#include "f_acm.c" -#include "f_ecm.c" -#include "u_ether.c" - -/*-------------------------------------------------------------------------*/ - -static struct usb_device_descriptor device_desc = { - .bLength = sizeof device_desc, - .bDescriptorType = USB_DT_DEVICE, - - .bcdUSB = cpu_to_le16(0x0200), - - .bDeviceClass = USB_CLASS_COMM, - .bDeviceSubClass = 0, - .bDeviceProtocol = 0, - /* .bMaxPacketSize0 = f(hardware) */ - - /* Vendor and product id can be overridden by module parameters. */ - .idVendor = cpu_to_le16(CDC_VENDOR_NUM), - .idProduct = cpu_to_le16(CDC_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, -}; - - -/* 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 *dev_strings[] = { - &stringtab_dev, - NULL, -}; - -static u8 hostaddr[ETH_ALEN]; - -/*-------------------------------------------------------------------------*/ - -/* - * We _always_ have both CDC ECM and CDC ACM functions. - */ -static int __init cdc_do_config(struct usb_configuration *c) -{ - int status; - - if (gadget_is_otg(c->cdev->gadget)) { - c->descriptors = otg_desc; - c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; - } - - status = ecm_bind_config(c, hostaddr); - if (status < 0) - return status; - - status = acm_bind_config(c, 0); - if (status < 0) - return status; - - return 0; -} - -static struct usb_configuration cdc_config_driver = { - .label = "CDC Composite (ECM + ACM)", - .bConfigurationValue = 1, - /* .iConfiguration = DYNAMIC */ - .bmAttributes = USB_CONFIG_ATT_SELFPOWER, -}; - -/*-------------------------------------------------------------------------*/ - -static int __init cdc_bind(struct usb_composite_dev *cdev) -{ - int gcnum; - struct usb_gadget *gadget = cdev->gadget; - int status; - - if (!can_support_ecm(cdev->gadget)) { - dev_err(&gadget->dev, "controller '%s' not usable\n", - gadget->name); - return -EINVAL; - } - - /* set up network link layer */ - status = gether_setup(cdev->gadget, hostaddr); - if (status < 0) - return status; - - /* set up serial link layer */ - status = gserial_setup(cdev->gadget, 1); - if (status < 0) - goto fail0; - - gcnum = usb_gadget_controller_number(gadget); - if (gcnum >= 0) - device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum); - else { - /* We assume that can_support_ecm() tells the truth; - * but if the controller isn't recognized at all then - * that assumption is a bit more likely to be wrong. - */ - WARNING(cdev, "controller '%s' not recognized; trying %s\n", - gadget->name, - cdc_config_driver.label); - device_desc.bcdDevice = - cpu_to_le16(0x0300 | 0x0099); - } - - - /* Allocate string descriptor numbers ... note that string - * contents can be overridden by the composite_dev glue. - */ - - /* device descriptor strings: manufacturer, product */ - snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", - init_utsname()->sysname, init_utsname()->release, - gadget->name); - status = usb_string_id(cdev); - if (status < 0) - goto fail1; - strings_dev[STRING_MANUFACTURER_IDX].id = status; - device_desc.iManufacturer = status; - - status = usb_string_id(cdev); - if (status < 0) - goto fail1; - strings_dev[STRING_PRODUCT_IDX].id = status; - device_desc.iProduct = status; - - /* register our configuration */ - status = usb_add_config(cdev, &cdc_config_driver, cdc_do_config); - if (status < 0) - goto fail1; - - dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n", - DRIVER_DESC); - - return 0; - -fail1: - gserial_cleanup(); -fail0: - gether_cleanup(); - return status; -} - -static int __exit cdc_unbind(struct usb_composite_dev *cdev) -{ - gserial_cleanup(); - gether_cleanup(); - return 0; -} - -static struct usb_composite_driver cdc_driver = { - .name = "g_cdc", - .dev = &device_desc, - .strings = dev_strings, - .max_speed = USB_SPEED_HIGH, - .unbind = __exit_p(cdc_unbind), -}; - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("David Brownell"); -MODULE_LICENSE("GPL"); - -static int __init init(void) -{ - return usb_composite_probe(&cdc_driver, cdc_bind); -} -module_init(init); - -static void __exit cleanup(void) -{ - usb_composite_unregister(&cdc_driver); -} -module_exit(cleanup); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/ci13xxx_msm.c b/ANDROID_3.4.5/drivers/usb/gadget/ci13xxx_msm.c deleted file mode 100644 index d07e44c0..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/ci13xxx_msm.c +++ /dev/null @@ -1,126 +0,0 @@ -/* Copyright (c) 2010, Code Aurora Forum. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include - -#include "ci13xxx_udc.c" - -#define MSM_USB_BASE (udc->regs) - -static irqreturn_t msm_udc_irq(int irq, void *data) -{ - return udc_irq(); -} - -static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event) -{ - struct device *dev = udc->gadget.dev.parent; - int val; - - switch (event) { - case CI13XXX_CONTROLLER_RESET_EVENT: - dev_dbg(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n"); - writel(0, USB_AHBBURST); - writel(0, USB_AHBMODE); - break; - case CI13XXX_CONTROLLER_STOPPED_EVENT: - dev_dbg(dev, "CI13XXX_CONTROLLER_STOPPED_EVENT received\n"); - /* - * Put the transceiver in non-driving mode. Otherwise host - * may not detect soft-disconnection. - */ - val = usb_phy_io_read(udc->transceiver, ULPI_FUNC_CTRL); - val &= ~ULPI_FUNC_CTRL_OPMODE_MASK; - val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING; - usb_phy_io_write(udc->transceiver, val, ULPI_FUNC_CTRL); - break; - default: - dev_dbg(dev, "unknown ci13xxx_udc event\n"); - break; - } -} - -static struct ci13xxx_udc_driver ci13xxx_msm_udc_driver = { - .name = "ci13xxx_msm", - .flags = CI13XXX_REGS_SHARED | - CI13XXX_REQUIRE_TRANSCEIVER | - CI13XXX_PULLUP_ON_VBUS | - CI13XXX_DISABLE_STREAMING, - - .notify_event = ci13xxx_msm_notify_event, -}; - -static int ci13xxx_msm_probe(struct platform_device *pdev) -{ - struct resource *res; - void __iomem *regs; - int irq; - int ret; - - dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n"); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "failed to get platform resource mem\n"); - return -ENXIO; - } - - regs = ioremap(res->start, resource_size(res)); - if (!regs) { - dev_err(&pdev->dev, "ioremap failed\n"); - return -ENOMEM; - } - - ret = udc_probe(&ci13xxx_msm_udc_driver, &pdev->dev, regs); - if (ret < 0) { - dev_err(&pdev->dev, "udc_probe failed\n"); - goto iounmap; - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "IRQ not found\n"); - ret = -ENXIO; - goto udc_remove; - } - - ret = request_irq(irq, msm_udc_irq, IRQF_SHARED, pdev->name, pdev); - if (ret < 0) { - dev_err(&pdev->dev, "request_irq failed\n"); - goto udc_remove; - } - - pm_runtime_no_callbacks(&pdev->dev); - pm_runtime_enable(&pdev->dev); - - return 0; - -udc_remove: - udc_remove(); -iounmap: - iounmap(regs); - - return ret; -} - -static struct platform_driver ci13xxx_msm_driver = { - .probe = ci13xxx_msm_probe, - .driver = { .name = "msm_hsusb", }, -}; -MODULE_ALIAS("platform:msm_hsusb"); - -static int __init ci13xxx_msm_init(void) -{ - return platform_driver_register(&ci13xxx_msm_driver); -} -module_init(ci13xxx_msm_init); - -MODULE_LICENSE("GPL v2"); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/ci13xxx_pci.c b/ANDROID_3.4.5/drivers/usb/gadget/ci13xxx_pci.c deleted file mode 100644 index 883ab5e8..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/ci13xxx_pci.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * ci13xxx_pci.c - MIPS USB IP core family device controller - * - * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. - * - * Author: David Lopo - * - * 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. - */ - -#include -#include - -#include "ci13xxx_udc.c" - -/* driver name */ -#define UDC_DRIVER_NAME "ci13xxx_pci" - -/****************************************************************************** - * PCI block - *****************************************************************************/ -/** - * ci13xxx_pci_irq: interrut handler - * @irq: irq number - * @pdev: USB Device Controller interrupt source - * - * This function returns IRQ_HANDLED if the IRQ has been handled - * This is an ISR don't trace, use attribute interface instead - */ -static irqreturn_t ci13xxx_pci_irq(int irq, void *pdev) -{ - if (irq == 0) { - dev_err(&((struct pci_dev *)pdev)->dev, "Invalid IRQ0 usage!"); - return IRQ_HANDLED; - } - return udc_irq(); -} - -static struct ci13xxx_udc_driver ci13xxx_pci_udc_driver = { - .name = UDC_DRIVER_NAME, -}; - -/** - * ci13xxx_pci_probe: PCI probe - * @pdev: USB device controller being probed - * @id: PCI hotplug ID connecting controller to UDC framework - * - * This function returns an error code - * Allocates basic PCI resources for this USB device controller, and then - * invokes the udc_probe() method to start the UDC associated with it - */ -static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - void __iomem *regs = NULL; - int retval = 0; - - if (id == NULL) - return -EINVAL; - - retval = pci_enable_device(pdev); - if (retval) - goto done; - - if (!pdev->irq) { - dev_err(&pdev->dev, "No IRQ, check BIOS/PCI setup!"); - retval = -ENODEV; - goto disable_device; - } - - retval = pci_request_regions(pdev, UDC_DRIVER_NAME); - if (retval) - goto disable_device; - - /* BAR 0 holds all the registers */ - regs = pci_iomap(pdev, 0, 0); - if (!regs) { - dev_err(&pdev->dev, "Error mapping memory!"); - retval = -EFAULT; - goto release_regions; - } - pci_set_drvdata(pdev, (__force void *)regs); - - pci_set_master(pdev); - pci_try_set_mwi(pdev); - - retval = udc_probe(&ci13xxx_pci_udc_driver, &pdev->dev, regs); - if (retval) - goto iounmap; - - /* our device does not have MSI capability */ - - retval = request_irq(pdev->irq, ci13xxx_pci_irq, IRQF_SHARED, - UDC_DRIVER_NAME, pdev); - if (retval) - goto gadget_remove; - - return 0; - - gadget_remove: - udc_remove(); - iounmap: - pci_iounmap(pdev, regs); - release_regions: - pci_release_regions(pdev); - disable_device: - pci_disable_device(pdev); - done: - return retval; -} - -/** - * ci13xxx_pci_remove: PCI remove - * @pdev: USB Device Controller being removed - * - * Reverses the effect of ci13xxx_pci_probe(), - * first invoking the udc_remove() and then releases - * all PCI resources allocated for this USB device controller - */ -static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev) -{ - free_irq(pdev->irq, pdev); - udc_remove(); - pci_iounmap(pdev, (__force void __iomem *)pci_get_drvdata(pdev)); - pci_release_regions(pdev); - pci_disable_device(pdev); -} - -/** - * PCI device table - * PCI device structure - * - * Check "pci.h" for details - */ -static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = { - { PCI_DEVICE(0x153F, 0x1004) }, - { PCI_DEVICE(0x153F, 0x1006) }, - { 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ } -}; -MODULE_DEVICE_TABLE(pci, ci13xxx_pci_id_table); - -static struct pci_driver ci13xxx_pci_driver = { - .name = UDC_DRIVER_NAME, - .id_table = ci13xxx_pci_id_table, - .probe = ci13xxx_pci_probe, - .remove = __devexit_p(ci13xxx_pci_remove), -}; - -/** - * ci13xxx_pci_init: module init - * - * Driver load - */ -static int __init ci13xxx_pci_init(void) -{ - return pci_register_driver(&ci13xxx_pci_driver); -} -module_init(ci13xxx_pci_init); - -/** - * ci13xxx_pci_exit: module exit - * - * Driver unload - */ -static void __exit ci13xxx_pci_exit(void) -{ - pci_unregister_driver(&ci13xxx_pci_driver); -} -module_exit(ci13xxx_pci_exit); - -MODULE_AUTHOR("MIPS - David Lopo "); -MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller"); -MODULE_LICENSE("GPL"); -MODULE_VERSION("June 2008"); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/ci13xxx_udc.c b/ANDROID_3.4.5/drivers/usb/gadget/ci13xxx_udc.c deleted file mode 100644 index 243ef1ad..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/ci13xxx_udc.c +++ /dev/null @@ -1,2996 +0,0 @@ -/* - * ci13xxx_udc.c - MIPS USB IP core family device controller - * - * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. - * - * Author: David Lopo - * - * 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. - */ - -/* - * Description: MIPS USB IP core family device controller - * Currently it only supports IP part number CI13412 - * - * This driver is composed of several blocks: - * - HW: hardware interface - * - DBG: debug facilities (optional) - * - UTIL: utilities - * - ISR: interrupts handling - * - ENDPT: endpoint operations (Gadget API) - * - GADGET: gadget operations (Gadget API) - * - BUS: bus glue code, bus abstraction layer - * - * Compile Options - * - CONFIG_USB_GADGET_DEBUG_FILES: enable debug facilities - * - STALL_IN: non-empty bulk-in pipes cannot be halted - * if defined mass storage compliance succeeds but with warnings - * => case 4: Hi > Dn - * => case 5: Hi > Di - * => case 8: Hi <> Do - * if undefined usbtest 13 fails - * - TRACE: enable function tracing (depends on DEBUG) - * - * Main Features - * - Chapter 9 & Mass Storage Compliance with Gadget File Storage - * - Chapter 9 Compliance with Gadget Zero (STALL_IN undefined) - * - Normal & LPM support - * - * USBTEST Report - * - OK: 0-12, 13 (STALL_IN defined) & 14 - * - Not Supported: 15 & 16 (ISO) - * - * TODO List - * - OTG - * - Isochronous & Interrupt Traffic - * - Handle requests which spawns into several TDs - * - GET_STATUS(device) - always reports 0 - * - Gadget API (majority of optional features) - * - Suspend & Remote Wakeup - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ci13xxx_udc.h" - - -/****************************************************************************** - * DEFINE - *****************************************************************************/ - -#define DMA_ADDR_INVALID (~(dma_addr_t)0) - -/* ctrl register bank access */ -static DEFINE_SPINLOCK(udc_lock); - -/* control endpoint description */ -static const struct usb_endpoint_descriptor -ctrl_endpt_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, - .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX), -}; - -static const struct usb_endpoint_descriptor -ctrl_endpt_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, - .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX), -}; - -/* UDC descriptor */ -static struct ci13xxx *_udc; - -/* Interrupt statistics */ -#define ISR_MASK 0x1F -static struct { - u32 test; - u32 ui; - u32 uei; - u32 pci; - u32 uri; - u32 sli; - u32 none; - struct { - u32 cnt; - u32 buf[ISR_MASK+1]; - u32 idx; - } hndl; -} isr_statistics; - -/** - * ffs_nr: find first (least significant) bit set - * @x: the word to search - * - * This function returns bit number (instead of position) - */ -static int ffs_nr(u32 x) -{ - int n = ffs(x); - - return n ? n-1 : 32; -} - -/****************************************************************************** - * HW block - *****************************************************************************/ -/* register bank descriptor */ -static struct { - unsigned lpm; /* is LPM? */ - void __iomem *abs; /* bus map offset */ - void __iomem *cap; /* bus map offset + CAP offset + CAP data */ - size_t size; /* bank size */ -} hw_bank; - -/* MSM specific */ -#define ABS_AHBBURST (0x0090UL) -#define ABS_AHBMODE (0x0098UL) -/* UDC register map */ -#define ABS_CAPLENGTH (0x100UL) -#define ABS_HCCPARAMS (0x108UL) -#define ABS_DCCPARAMS (0x124UL) -#define ABS_TESTMODE (hw_bank.lpm ? 0x0FCUL : 0x138UL) -/* offset to CAPLENTGH (addr + data) */ -#define CAP_USBCMD (0x000UL) -#define CAP_USBSTS (0x004UL) -#define CAP_USBINTR (0x008UL) -#define CAP_DEVICEADDR (0x014UL) -#define CAP_ENDPTLISTADDR (0x018UL) -#define CAP_PORTSC (0x044UL) -#define CAP_DEVLC (0x084UL) -#define CAP_USBMODE (hw_bank.lpm ? 0x0C8UL : 0x068UL) -#define CAP_ENDPTSETUPSTAT (hw_bank.lpm ? 0x0D8UL : 0x06CUL) -#define CAP_ENDPTPRIME (hw_bank.lpm ? 0x0DCUL : 0x070UL) -#define CAP_ENDPTFLUSH (hw_bank.lpm ? 0x0E0UL : 0x074UL) -#define CAP_ENDPTSTAT (hw_bank.lpm ? 0x0E4UL : 0x078UL) -#define CAP_ENDPTCOMPLETE (hw_bank.lpm ? 0x0E8UL : 0x07CUL) -#define CAP_ENDPTCTRL (hw_bank.lpm ? 0x0ECUL : 0x080UL) -#define CAP_LAST (hw_bank.lpm ? 0x12CUL : 0x0C0UL) - -/* maximum number of enpoints: valid only after hw_device_reset() */ -static unsigned hw_ep_max; - -/** - * hw_ep_bit: calculates the bit number - * @num: endpoint number - * @dir: endpoint direction - * - * This function returns bit number - */ -static inline int hw_ep_bit(int num, int dir) -{ - return num + (dir ? 16 : 0); -} - -static int ep_to_bit(int n) -{ - int fill = 16 - hw_ep_max / 2; - - if (n >= hw_ep_max / 2) - n += fill; - - return n; -} - -/** - * hw_aread: reads from register bitfield - * @addr: address relative to bus map - * @mask: bitfield mask - * - * This function returns register bitfield data - */ -static u32 hw_aread(u32 addr, u32 mask) -{ - return ioread32(addr + hw_bank.abs) & mask; -} - -/** - * hw_awrite: writes to register bitfield - * @addr: address relative to bus map - * @mask: bitfield mask - * @data: new data - */ -static void hw_awrite(u32 addr, u32 mask, u32 data) -{ - iowrite32(hw_aread(addr, ~mask) | (data & mask), - addr + hw_bank.abs); -} - -/** - * hw_cread: reads from register bitfield - * @addr: address relative to CAP offset plus content - * @mask: bitfield mask - * - * This function returns register bitfield data - */ -static u32 hw_cread(u32 addr, u32 mask) -{ - return ioread32(addr + hw_bank.cap) & mask; -} - -/** - * hw_cwrite: writes to register bitfield - * @addr: address relative to CAP offset plus content - * @mask: bitfield mask - * @data: new data - */ -static void hw_cwrite(u32 addr, u32 mask, u32 data) -{ - iowrite32(hw_cread(addr, ~mask) | (data & mask), - addr + hw_bank.cap); -} - -/** - * hw_ctest_and_clear: tests & clears register bitfield - * @addr: address relative to CAP offset plus content - * @mask: bitfield mask - * - * This function returns register bitfield data - */ -static u32 hw_ctest_and_clear(u32 addr, u32 mask) -{ - u32 reg = hw_cread(addr, mask); - - iowrite32(reg, addr + hw_bank.cap); - return reg; -} - -/** - * hw_ctest_and_write: tests & writes register bitfield - * @addr: address relative to CAP offset plus content - * @mask: bitfield mask - * @data: new data - * - * This function returns register bitfield data - */ -static u32 hw_ctest_and_write(u32 addr, u32 mask, u32 data) -{ - u32 reg = hw_cread(addr, ~0); - - iowrite32((reg & ~mask) | (data & mask), addr + hw_bank.cap); - return (reg & mask) >> ffs_nr(mask); -} - -static int hw_device_init(void __iomem *base) -{ - u32 reg; - - /* bank is a module variable */ - hw_bank.abs = base; - - hw_bank.cap = hw_bank.abs; - hw_bank.cap += ABS_CAPLENGTH; - hw_bank.cap += ioread8(hw_bank.cap); - - reg = hw_aread(ABS_HCCPARAMS, HCCPARAMS_LEN) >> ffs_nr(HCCPARAMS_LEN); - hw_bank.lpm = reg; - hw_bank.size = hw_bank.cap - hw_bank.abs; - hw_bank.size += CAP_LAST; - hw_bank.size /= sizeof(u32); - - reg = hw_aread(ABS_DCCPARAMS, DCCPARAMS_DEN) >> ffs_nr(DCCPARAMS_DEN); - hw_ep_max = reg * 2; /* cache hw ENDPT_MAX */ - - if (hw_ep_max == 0 || hw_ep_max > ENDPT_MAX) - return -ENODEV; - - /* setup lock mode ? */ - - /* ENDPTSETUPSTAT is '0' by default */ - - /* HCSPARAMS.bf.ppc SHOULD BE zero for device */ - - return 0; -} -/** - * hw_device_reset: resets chip (execute without interruption) - * @base: register base address - * - * This function returns an error code - */ -static int hw_device_reset(struct ci13xxx *udc) -{ - /* should flush & stop before reset */ - hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0); - hw_cwrite(CAP_USBCMD, USBCMD_RS, 0); - - hw_cwrite(CAP_USBCMD, USBCMD_RST, USBCMD_RST); - while (hw_cread(CAP_USBCMD, USBCMD_RST)) - udelay(10); /* not RTOS friendly */ - - - if (udc->udc_driver->notify_event) - udc->udc_driver->notify_event(udc, - CI13XXX_CONTROLLER_RESET_EVENT); - - if (udc->udc_driver->flags & CI13XXX_DISABLE_STREAMING) - hw_cwrite(CAP_USBMODE, USBMODE_SDIS, USBMODE_SDIS); - - /* USBMODE should be configured step by step */ - hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE); - hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_DEVICE); - hw_cwrite(CAP_USBMODE, USBMODE_SLOM, USBMODE_SLOM); /* HW >= 2.3 */ - - if (hw_cread(CAP_USBMODE, USBMODE_CM) != USBMODE_CM_DEVICE) { - pr_err("cannot enter in device mode"); - pr_err("lpm = %i", hw_bank.lpm); - return -ENODEV; - } - - return 0; -} - -/** - * hw_device_state: enables/disables interrupts & starts/stops device (execute - * without interruption) - * @dma: 0 => disable, !0 => enable and set dma engine - * - * This function returns an error code - */ -static int hw_device_state(u32 dma) -{ - if (dma) { - hw_cwrite(CAP_ENDPTLISTADDR, ~0, dma); - /* interrupt, error, port change, reset, sleep/suspend */ - hw_cwrite(CAP_USBINTR, ~0, - USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI); - hw_cwrite(CAP_USBCMD, USBCMD_RS, USBCMD_RS); - } else { - hw_cwrite(CAP_USBCMD, USBCMD_RS, 0); - hw_cwrite(CAP_USBINTR, ~0, 0); - } - return 0; -} - -/** - * hw_ep_flush: flush endpoint fifo (execute without interruption) - * @num: endpoint number - * @dir: endpoint direction - * - * This function returns an error code - */ -static int hw_ep_flush(int num, int dir) -{ - int n = hw_ep_bit(num, dir); - - do { - /* flush any pending transfer */ - hw_cwrite(CAP_ENDPTFLUSH, BIT(n), BIT(n)); - while (hw_cread(CAP_ENDPTFLUSH, BIT(n))) - cpu_relax(); - } while (hw_cread(CAP_ENDPTSTAT, BIT(n))); - - return 0; -} - -/** - * hw_ep_disable: disables endpoint (execute without interruption) - * @num: endpoint number - * @dir: endpoint direction - * - * This function returns an error code - */ -static int hw_ep_disable(int num, int dir) -{ - hw_ep_flush(num, dir); - hw_cwrite(CAP_ENDPTCTRL + num * sizeof(u32), - dir ? ENDPTCTRL_TXE : ENDPTCTRL_RXE, 0); - return 0; -} - -/** - * hw_ep_enable: enables endpoint (execute without interruption) - * @num: endpoint number - * @dir: endpoint direction - * @type: endpoint type - * - * This function returns an error code - */ -static int hw_ep_enable(int num, int dir, int type) -{ - u32 mask, data; - - if (dir) { - mask = ENDPTCTRL_TXT; /* type */ - data = type << ffs_nr(mask); - - mask |= ENDPTCTRL_TXS; /* unstall */ - mask |= ENDPTCTRL_TXR; /* reset data toggle */ - data |= ENDPTCTRL_TXR; - mask |= ENDPTCTRL_TXE; /* enable */ - data |= ENDPTCTRL_TXE; - } else { - mask = ENDPTCTRL_RXT; /* type */ - data = type << ffs_nr(mask); - - mask |= ENDPTCTRL_RXS; /* unstall */ - mask |= ENDPTCTRL_RXR; /* reset data toggle */ - data |= ENDPTCTRL_RXR; - mask |= ENDPTCTRL_RXE; /* enable */ - data |= ENDPTCTRL_RXE; - } - hw_cwrite(CAP_ENDPTCTRL + num * sizeof(u32), mask, data); - return 0; -} - -/** - * hw_ep_get_halt: return endpoint halt status - * @num: endpoint number - * @dir: endpoint direction - * - * This function returns 1 if endpoint halted - */ -static int hw_ep_get_halt(int num, int dir) -{ - u32 mask = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS; - - return hw_cread(CAP_ENDPTCTRL + num * sizeof(u32), mask) ? 1 : 0; -} - -/** - * hw_test_and_clear_setup_status: test & clear setup status (execute without - * interruption) - * @n: endpoint number - * - * This function returns setup status - */ -static int hw_test_and_clear_setup_status(int n) -{ - n = ep_to_bit(n); - return hw_ctest_and_clear(CAP_ENDPTSETUPSTAT, BIT(n)); -} - -/** - * hw_ep_prime: primes endpoint (execute without interruption) - * @num: endpoint number - * @dir: endpoint direction - * @is_ctrl: true if control endpoint - * - * This function returns an error code - */ -static int hw_ep_prime(int num, int dir, int is_ctrl) -{ - int n = hw_ep_bit(num, dir); - - if (is_ctrl && dir == RX && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num))) - return -EAGAIN; - - hw_cwrite(CAP_ENDPTPRIME, BIT(n), BIT(n)); - - while (hw_cread(CAP_ENDPTPRIME, BIT(n))) - cpu_relax(); - if (is_ctrl && dir == RX && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num))) - return -EAGAIN; - - /* status shoult be tested according with manual but it doesn't work */ - return 0; -} - -/** - * hw_ep_set_halt: configures ep halt & resets data toggle after clear (execute - * without interruption) - * @num: endpoint number - * @dir: endpoint direction - * @value: true => stall, false => unstall - * - * This function returns an error code - */ -static int hw_ep_set_halt(int num, int dir, int value) -{ - if (value != 0 && value != 1) - return -EINVAL; - - do { - u32 addr = CAP_ENDPTCTRL + num * sizeof(u32); - u32 mask_xs = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS; - u32 mask_xr = dir ? ENDPTCTRL_TXR : ENDPTCTRL_RXR; - - /* data toggle - reserved for EP0 but it's in ESS */ - hw_cwrite(addr, mask_xs|mask_xr, value ? mask_xs : mask_xr); - - } while (value != hw_ep_get_halt(num, dir)); - - return 0; -} - -/** - * hw_intr_clear: disables interrupt & clears interrupt status (execute without - * interruption) - * @n: interrupt bit - * - * This function returns an error code - */ -static int hw_intr_clear(int n) -{ - if (n >= REG_BITS) - return -EINVAL; - - hw_cwrite(CAP_USBINTR, BIT(n), 0); - hw_cwrite(CAP_USBSTS, BIT(n), BIT(n)); - return 0; -} - -/** - * hw_intr_force: enables interrupt & forces interrupt status (execute without - * interruption) - * @n: interrupt bit - * - * This function returns an error code - */ -static int hw_intr_force(int n) -{ - if (n >= REG_BITS) - return -EINVAL; - - hw_awrite(ABS_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE); - hw_cwrite(CAP_USBINTR, BIT(n), BIT(n)); - hw_cwrite(CAP_USBSTS, BIT(n), BIT(n)); - hw_awrite(ABS_TESTMODE, TESTMODE_FORCE, 0); - return 0; -} - -/** - * hw_is_port_high_speed: test if port is high speed - * - * This function returns true if high speed port - */ -static int hw_port_is_high_speed(void) -{ - return hw_bank.lpm ? hw_cread(CAP_DEVLC, DEVLC_PSPD) : - hw_cread(CAP_PORTSC, PORTSC_HSP); -} - -/** - * hw_port_test_get: reads port test mode value - * - * This function returns port test mode value - */ -static u8 hw_port_test_get(void) -{ - return hw_cread(CAP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC); -} - -/** - * hw_port_test_set: writes port test mode (execute without interruption) - * @mode: new value - * - * This function returns an error code - */ -static int hw_port_test_set(u8 mode) -{ - const u8 TEST_MODE_MAX = 7; - - if (mode > TEST_MODE_MAX) - return -EINVAL; - - hw_cwrite(CAP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC)); - return 0; -} - -/** - * hw_read_intr_enable: returns interrupt enable register - * - * This function returns register data - */ -static u32 hw_read_intr_enable(void) -{ - return hw_cread(CAP_USBINTR, ~0); -} - -/** - * hw_read_intr_status: returns interrupt status register - * - * This function returns register data - */ -static u32 hw_read_intr_status(void) -{ - return hw_cread(CAP_USBSTS, ~0); -} - -/** - * hw_register_read: reads all device registers (execute without interruption) - * @buf: destination buffer - * @size: buffer size - * - * This function returns number of registers read - */ -static size_t hw_register_read(u32 *buf, size_t size) -{ - unsigned i; - - if (size > hw_bank.size) - size = hw_bank.size; - - for (i = 0; i < size; i++) - buf[i] = hw_aread(i * sizeof(u32), ~0); - - return size; -} - -/** - * hw_register_write: writes to register - * @addr: register address - * @data: register value - * - * This function returns an error code - */ -static int hw_register_write(u16 addr, u32 data) -{ - /* align */ - addr /= sizeof(u32); - - if (addr >= hw_bank.size) - return -EINVAL; - - /* align */ - addr *= sizeof(u32); - - hw_awrite(addr, ~0, data); - return 0; -} - -/** - * hw_test_and_clear_complete: test & clear complete status (execute without - * interruption) - * @n: endpoint number - * - * This function returns complete status - */ -static int hw_test_and_clear_complete(int n) -{ - n = ep_to_bit(n); - return hw_ctest_and_clear(CAP_ENDPTCOMPLETE, BIT(n)); -} - -/** - * hw_test_and_clear_intr_active: test & clear active interrupts (execute - * without interruption) - * - * This function returns active interrutps - */ -static u32 hw_test_and_clear_intr_active(void) -{ - u32 reg = hw_read_intr_status() & hw_read_intr_enable(); - - hw_cwrite(CAP_USBSTS, ~0, reg); - return reg; -} - -/** - * hw_test_and_clear_setup_guard: test & clear setup guard (execute without - * interruption) - * - * This function returns guard value - */ -static int hw_test_and_clear_setup_guard(void) -{ - return hw_ctest_and_write(CAP_USBCMD, USBCMD_SUTW, 0); -} - -/** - * hw_test_and_set_setup_guard: test & set setup guard (execute without - * interruption) - * - * This function returns guard value - */ -static int hw_test_and_set_setup_guard(void) -{ - return hw_ctest_and_write(CAP_USBCMD, USBCMD_SUTW, USBCMD_SUTW); -} - -/** - * hw_usb_set_address: configures USB address (execute without interruption) - * @value: new USB address - * - * This function returns an error code - */ -static int hw_usb_set_address(u8 value) -{ - /* advance */ - hw_cwrite(CAP_DEVICEADDR, DEVICEADDR_USBADR | DEVICEADDR_USBADRA, - value << ffs_nr(DEVICEADDR_USBADR) | DEVICEADDR_USBADRA); - return 0; -} - -/** - * hw_usb_reset: restart device after a bus reset (execute without - * interruption) - * - * This function returns an error code - */ -static int hw_usb_reset(void) -{ - hw_usb_set_address(0); - - /* ESS flushes only at end?!? */ - hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0); /* flush all EPs */ - - /* clear setup token semaphores */ - hw_cwrite(CAP_ENDPTSETUPSTAT, 0, 0); /* writes its content */ - - /* clear complete status */ - hw_cwrite(CAP_ENDPTCOMPLETE, 0, 0); /* writes its content */ - - /* wait until all bits cleared */ - while (hw_cread(CAP_ENDPTPRIME, ~0)) - udelay(10); /* not RTOS friendly */ - - /* reset all endpoints ? */ - - /* reset internal status and wait for further instructions - no need to verify the port reset status (ESS does it) */ - - return 0; -} - -/****************************************************************************** - * DBG block - *****************************************************************************/ -/** - * show_device: prints information about device capabilities and status - * - * Check "device.h" for details - */ -static ssize_t show_device(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - struct usb_gadget *gadget = &udc->gadget; - int n = 0; - - dbg_trace("[%s] %p\n", __func__, buf); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - return 0; - } - - n += scnprintf(buf + n, PAGE_SIZE - n, "speed = %d\n", - gadget->speed); - n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed = %d\n", - gadget->max_speed); - /* TODO: Scheduled for removal in 3.8. */ - n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed = %d\n", - gadget_is_dualspeed(gadget)); - n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg = %d\n", - gadget->is_otg); - n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral = %d\n", - gadget->is_a_peripheral); - n += scnprintf(buf + n, PAGE_SIZE - n, "b_hnp_enable = %d\n", - gadget->b_hnp_enable); - n += scnprintf(buf + n, PAGE_SIZE - n, "a_hnp_support = %d\n", - gadget->a_hnp_support); - n += scnprintf(buf + n, PAGE_SIZE - n, "a_alt_hnp_support = %d\n", - gadget->a_alt_hnp_support); - n += scnprintf(buf + n, PAGE_SIZE - n, "name = %s\n", - (gadget->name ? gadget->name : "")); - - return n; -} -static DEVICE_ATTR(device, S_IRUSR, show_device, NULL); - -/** - * show_driver: prints information about attached gadget (if any) - * - * Check "device.h" for details - */ -static ssize_t show_driver(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - struct usb_gadget_driver *driver = udc->driver; - int n = 0; - - dbg_trace("[%s] %p\n", __func__, buf); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - return 0; - } - - if (driver == NULL) - return scnprintf(buf, PAGE_SIZE, - "There is no gadget attached!\n"); - - n += scnprintf(buf + n, PAGE_SIZE - n, "function = %s\n", - (driver->function ? driver->function : "")); - n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n", - driver->max_speed); - - return n; -} -static DEVICE_ATTR(driver, S_IRUSR, show_driver, NULL); - -/* Maximum event message length */ -#define DBG_DATA_MSG 64UL - -/* Maximum event messages */ -#define DBG_DATA_MAX 128UL - -/* Event buffer descriptor */ -static struct { - char (buf[DBG_DATA_MAX])[DBG_DATA_MSG]; /* buffer */ - unsigned idx; /* index */ - unsigned tty; /* print to console? */ - rwlock_t lck; /* lock */ -} dbg_data = { - .idx = 0, - .tty = 0, - .lck = __RW_LOCK_UNLOCKED(lck) -}; - -/** - * dbg_dec: decrements debug event index - * @idx: buffer index - */ -static void dbg_dec(unsigned *idx) -{ - *idx = (*idx - 1) & (DBG_DATA_MAX-1); -} - -/** - * dbg_inc: increments debug event index - * @idx: buffer index - */ -static void dbg_inc(unsigned *idx) -{ - *idx = (*idx + 1) & (DBG_DATA_MAX-1); -} - -/** - * dbg_print: prints the common part of the event - * @addr: endpoint address - * @name: event name - * @status: status - * @extra: extra information - */ -static void dbg_print(u8 addr, const char *name, int status, const char *extra) -{ - struct timeval tval; - unsigned int stamp; - unsigned long flags; - - write_lock_irqsave(&dbg_data.lck, flags); - - do_gettimeofday(&tval); - stamp = tval.tv_sec & 0xFFFF; /* 2^32 = 4294967296. Limit to 4096s */ - stamp = stamp * 1000000 + tval.tv_usec; - - scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG, - "%04X\t? %02X %-7.7s %4i ?\t%s\n", - stamp, addr, name, status, extra); - - dbg_inc(&dbg_data.idx); - - write_unlock_irqrestore(&dbg_data.lck, flags); - - if (dbg_data.tty != 0) - pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n", - stamp, addr, name, status, extra); -} - -/** - * dbg_done: prints a DONE event - * @addr: endpoint address - * @td: transfer descriptor - * @status: status - */ -static void dbg_done(u8 addr, const u32 token, int status) -{ - char msg[DBG_DATA_MSG]; - - scnprintf(msg, sizeof(msg), "%d %02X", - (int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES), - (int)(token & TD_STATUS) >> ffs_nr(TD_STATUS)); - dbg_print(addr, "DONE", status, msg); -} - -/** - * dbg_event: prints a generic event - * @addr: endpoint address - * @name: event name - * @status: status - */ -static void dbg_event(u8 addr, const char *name, int status) -{ - if (name != NULL) - dbg_print(addr, name, status, ""); -} - -/* - * dbg_queue: prints a QUEUE event - * @addr: endpoint address - * @req: USB request - * @status: status - */ -static void dbg_queue(u8 addr, const struct usb_request *req, int status) -{ - char msg[DBG_DATA_MSG]; - - if (req != NULL) { - scnprintf(msg, sizeof(msg), - "%d %d", !req->no_interrupt, req->length); - dbg_print(addr, "QUEUE", status, msg); - } -} - -/** - * dbg_setup: prints a SETUP event - * @addr: endpoint address - * @req: setup request - */ -static void dbg_setup(u8 addr, const struct usb_ctrlrequest *req) -{ - char msg[DBG_DATA_MSG]; - - if (req != NULL) { - scnprintf(msg, sizeof(msg), - "%02X %02X %04X %04X %d", req->bRequestType, - req->bRequest, le16_to_cpu(req->wValue), - le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength)); - dbg_print(addr, "SETUP", 0, msg); - } -} - -/** - * show_events: displays the event buffer - * - * Check "device.h" for details - */ -static ssize_t show_events(struct device *dev, struct device_attribute *attr, - char *buf) -{ - unsigned long flags; - unsigned i, j, n = 0; - - dbg_trace("[%s] %p\n", __func__, buf); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - return 0; - } - - read_lock_irqsave(&dbg_data.lck, flags); - - i = dbg_data.idx; - for (dbg_dec(&i); i != dbg_data.idx; dbg_dec(&i)) { - n += strlen(dbg_data.buf[i]); - if (n >= PAGE_SIZE) { - n -= strlen(dbg_data.buf[i]); - break; - } - } - for (j = 0, dbg_inc(&i); j < n; dbg_inc(&i)) - j += scnprintf(buf + j, PAGE_SIZE - j, - "%s", dbg_data.buf[i]); - - read_unlock_irqrestore(&dbg_data.lck, flags); - - return n; -} - -/** - * store_events: configure if events are going to be also printed to console - * - * Check "device.h" for details - */ -static ssize_t store_events(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - unsigned tty; - - dbg_trace("[%s] %p, %d\n", __func__, buf, count); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - goto done; - } - - if (sscanf(buf, "%u", &tty) != 1 || tty > 1) { - dev_err(dev, "<1|0>: enable|disable console log\n"); - goto done; - } - - dbg_data.tty = tty; - dev_info(dev, "tty = %u", dbg_data.tty); - - done: - return count; -} -static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events); - -/** - * show_inters: interrupt status, enable status and historic - * - * Check "device.h" for details - */ -static ssize_t show_inters(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long flags; - u32 intr; - unsigned i, j, n = 0; - - dbg_trace("[%s] %p\n", __func__, buf); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - return 0; - } - - spin_lock_irqsave(udc->lock, flags); - - n += scnprintf(buf + n, PAGE_SIZE - n, - "status = %08x\n", hw_read_intr_status()); - n += scnprintf(buf + n, PAGE_SIZE - n, - "enable = %08x\n", hw_read_intr_enable()); - - n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n", - isr_statistics.test); - n += scnprintf(buf + n, PAGE_SIZE - n, "? ui = %d\n", - isr_statistics.ui); - n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n", - isr_statistics.uei); - n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n", - isr_statistics.pci); - n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n", - isr_statistics.uri); - n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n", - isr_statistics.sli); - n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n", - isr_statistics.none); - n += scnprintf(buf + n, PAGE_SIZE - n, "*hndl = %d\n", - isr_statistics.hndl.cnt); - - for (i = isr_statistics.hndl.idx, j = 0; j <= ISR_MASK; j++, i++) { - i &= ISR_MASK; - intr = isr_statistics.hndl.buf[i]; - - if (USBi_UI & intr) - n += scnprintf(buf + n, PAGE_SIZE - n, "ui "); - intr &= ~USBi_UI; - if (USBi_UEI & intr) - n += scnprintf(buf + n, PAGE_SIZE - n, "uei "); - intr &= ~USBi_UEI; - if (USBi_PCI & intr) - n += scnprintf(buf + n, PAGE_SIZE - n, "pci "); - intr &= ~USBi_PCI; - if (USBi_URI & intr) - n += scnprintf(buf + n, PAGE_SIZE - n, "uri "); - intr &= ~USBi_URI; - if (USBi_SLI & intr) - n += scnprintf(buf + n, PAGE_SIZE - n, "sli "); - intr &= ~USBi_SLI; - if (intr) - n += scnprintf(buf + n, PAGE_SIZE - n, "??? "); - if (isr_statistics.hndl.buf[i]) - n += scnprintf(buf + n, PAGE_SIZE - n, "\n"); - } - - spin_unlock_irqrestore(udc->lock, flags); - - return n; -} - -/** - * store_inters: enable & force or disable an individual interrutps - * (to be used for test purposes only) - * - * Check "device.h" for details - */ -static ssize_t store_inters(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long flags; - unsigned en, bit; - - dbg_trace("[%s] %p, %d\n", __func__, buf, count); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - goto done; - } - - if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) { - dev_err(dev, "<1|0> : enable|disable interrupt"); - goto done; - } - - spin_lock_irqsave(udc->lock, flags); - if (en) { - if (hw_intr_force(bit)) - dev_err(dev, "invalid bit number\n"); - else - isr_statistics.test++; - } else { - if (hw_intr_clear(bit)) - dev_err(dev, "invalid bit number\n"); - } - spin_unlock_irqrestore(udc->lock, flags); - - done: - return count; -} -static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters); - -/** - * show_port_test: reads port test mode - * - * Check "device.h" for details - */ -static ssize_t show_port_test(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long flags; - unsigned mode; - - dbg_trace("[%s] %p\n", __func__, buf); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - return 0; - } - - spin_lock_irqsave(udc->lock, flags); - mode = hw_port_test_get(); - spin_unlock_irqrestore(udc->lock, flags); - - return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode); -} - -/** - * store_port_test: writes port test mode - * - * Check "device.h" for details - */ -static ssize_t store_port_test(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long flags; - unsigned mode; - - dbg_trace("[%s] %p, %d\n", __func__, buf, count); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - goto done; - } - - if (sscanf(buf, "%u", &mode) != 1) { - dev_err(dev, ": set port test mode"); - goto done; - } - - spin_lock_irqsave(udc->lock, flags); - if (hw_port_test_set(mode)) - dev_err(dev, "invalid mode\n"); - spin_unlock_irqrestore(udc->lock, flags); - - done: - return count; -} -static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR, - show_port_test, store_port_test); - -/** - * show_qheads: DMA contents of all queue heads - * - * Check "device.h" for details - */ -static ssize_t show_qheads(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long flags; - unsigned i, j, n = 0; - - dbg_trace("[%s] %p\n", __func__, buf); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - return 0; - } - - spin_lock_irqsave(udc->lock, flags); - for (i = 0; i < hw_ep_max/2; i++) { - struct ci13xxx_ep *mEpRx = &udc->ci13xxx_ep[i]; - struct ci13xxx_ep *mEpTx = &udc->ci13xxx_ep[i + hw_ep_max/2]; - n += scnprintf(buf + n, PAGE_SIZE - n, - "EP=%02i: RX=%08X TX=%08X\n", - i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma); - for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) { - n += scnprintf(buf + n, PAGE_SIZE - n, - " %04X: %08X %08X\n", j, - *((u32 *)mEpRx->qh.ptr + j), - *((u32 *)mEpTx->qh.ptr + j)); - } - } - spin_unlock_irqrestore(udc->lock, flags); - - return n; -} -static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL); - -/** - * show_registers: dumps all registers - * - * Check "device.h" for details - */ -#define DUMP_ENTRIES 512 -static ssize_t show_registers(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long flags; - u32 *dump; - unsigned i, k, n = 0; - - dbg_trace("[%s] %p\n", __func__, buf); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - return 0; - } - - dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL); - if (!dump) { - dev_err(dev, "%s: out of memory\n", __func__); - return 0; - } - - spin_lock_irqsave(udc->lock, flags); - k = hw_register_read(dump, DUMP_ENTRIES); - spin_unlock_irqrestore(udc->lock, flags); - - for (i = 0; i < k; i++) { - n += scnprintf(buf + n, PAGE_SIZE - n, - "reg[0x%04X] = 0x%08X\n", - i * (unsigned)sizeof(u32), dump[i]); - } - kfree(dump); - - return n; -} - -/** - * store_registers: writes value to register address - * - * Check "device.h" for details - */ -static ssize_t store_registers(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long addr, data, flags; - - dbg_trace("[%s] %p, %d\n", __func__, buf, count); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - goto done; - } - - if (sscanf(buf, "%li %li", &addr, &data) != 2) { - dev_err(dev, " : write data to register address"); - goto done; - } - - spin_lock_irqsave(udc->lock, flags); - if (hw_register_write(addr, data)) - dev_err(dev, "invalid address range\n"); - spin_unlock_irqrestore(udc->lock, flags); - - done: - return count; -} -static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR, - show_registers, store_registers); - -/** - * show_requests: DMA contents of all requests currently queued (all endpts) - * - * Check "device.h" for details - */ -static ssize_t show_requests(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long flags; - struct list_head *ptr = NULL; - struct ci13xxx_req *req = NULL; - unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32); - - dbg_trace("[%s] %p\n", __func__, buf); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - return 0; - } - - spin_lock_irqsave(udc->lock, flags); - for (i = 0; i < hw_ep_max; i++) - list_for_each(ptr, &udc->ci13xxx_ep[i].qh.queue) - { - req = list_entry(ptr, struct ci13xxx_req, queue); - - n += scnprintf(buf + n, PAGE_SIZE - n, - "EP=%02i: TD=%08X %s\n", - i % hw_ep_max/2, (u32)req->dma, - ((i < hw_ep_max/2) ? "RX" : "TX")); - - for (j = 0; j < qSize; j++) - n += scnprintf(buf + n, PAGE_SIZE - n, - " %04X: %08X\n", j, - *((u32 *)req->ptr + j)); - } - spin_unlock_irqrestore(udc->lock, flags); - - return n; -} -static DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL); - -/** - * dbg_create_files: initializes the attribute interface - * @dev: device - * - * This function returns an error code - */ -__maybe_unused static int dbg_create_files(struct device *dev) -{ - int retval = 0; - - if (dev == NULL) - return -EINVAL; - retval = device_create_file(dev, &dev_attr_device); - if (retval) - goto done; - retval = device_create_file(dev, &dev_attr_driver); - if (retval) - goto rm_device; - retval = device_create_file(dev, &dev_attr_events); - if (retval) - goto rm_driver; - retval = device_create_file(dev, &dev_attr_inters); - if (retval) - goto rm_events; - retval = device_create_file(dev, &dev_attr_port_test); - if (retval) - goto rm_inters; - retval = device_create_file(dev, &dev_attr_qheads); - if (retval) - goto rm_port_test; - retval = device_create_file(dev, &dev_attr_registers); - if (retval) - goto rm_qheads; - retval = device_create_file(dev, &dev_attr_requests); - if (retval) - goto rm_registers; - return 0; - - rm_registers: - device_remove_file(dev, &dev_attr_registers); - rm_qheads: - device_remove_file(dev, &dev_attr_qheads); - rm_port_test: - device_remove_file(dev, &dev_attr_port_test); - rm_inters: - device_remove_file(dev, &dev_attr_inters); - rm_events: - device_remove_file(dev, &dev_attr_events); - rm_driver: - device_remove_file(dev, &dev_attr_driver); - rm_device: - device_remove_file(dev, &dev_attr_device); - done: - return retval; -} - -/** - * dbg_remove_files: destroys the attribute interface - * @dev: device - * - * This function returns an error code - */ -__maybe_unused static int dbg_remove_files(struct device *dev) -{ - if (dev == NULL) - return -EINVAL; - device_remove_file(dev, &dev_attr_requests); - device_remove_file(dev, &dev_attr_registers); - device_remove_file(dev, &dev_attr_qheads); - device_remove_file(dev, &dev_attr_port_test); - device_remove_file(dev, &dev_attr_inters); - device_remove_file(dev, &dev_attr_events); - device_remove_file(dev, &dev_attr_driver); - device_remove_file(dev, &dev_attr_device); - return 0; -} - -/****************************************************************************** - * UTIL block - *****************************************************************************/ -/** - * _usb_addr: calculates endpoint address from direction & number - * @ep: endpoint - */ -static inline u8 _usb_addr(struct ci13xxx_ep *ep) -{ - return ((ep->dir == TX) ? USB_ENDPOINT_DIR_MASK : 0) | ep->num; -} - -/** - * _hardware_queue: configures a request at hardware level - * @gadget: gadget - * @mEp: endpoint - * - * This function returns an error code - */ -static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) -{ - unsigned i; - int ret = 0; - unsigned length = mReq->req.length; - - trace("%p, %p", mEp, mReq); - - /* don't queue twice */ - if (mReq->req.status == -EALREADY) - return -EALREADY; - - mReq->req.status = -EALREADY; - if (length && mReq->req.dma == DMA_ADDR_INVALID) { - mReq->req.dma = \ - dma_map_single(mEp->device, mReq->req.buf, - length, mEp->dir ? DMA_TO_DEVICE : - DMA_FROM_DEVICE); - if (mReq->req.dma == 0) - return -ENOMEM; - - mReq->map = 1; - } - - if (mReq->req.zero && length && (length % mEp->ep.maxpacket == 0)) { - mReq->zptr = dma_pool_alloc(mEp->td_pool, GFP_ATOMIC, - &mReq->zdma); - if (mReq->zptr == NULL) { - if (mReq->map) { - dma_unmap_single(mEp->device, mReq->req.dma, - length, mEp->dir ? DMA_TO_DEVICE : - DMA_FROM_DEVICE); - mReq->req.dma = DMA_ADDR_INVALID; - mReq->map = 0; - } - return -ENOMEM; - } - memset(mReq->zptr, 0, sizeof(*mReq->zptr)); - mReq->zptr->next = TD_TERMINATE; - mReq->zptr->token = TD_STATUS_ACTIVE; - if (!mReq->req.no_interrupt) - mReq->zptr->token |= TD_IOC; - } - /* - * TD configuration - * TODO - handle requests which spawns into several TDs - */ - memset(mReq->ptr, 0, sizeof(*mReq->ptr)); - mReq->ptr->token = length << ffs_nr(TD_TOTAL_BYTES); - mReq->ptr->token &= TD_TOTAL_BYTES; - mReq->ptr->token |= TD_STATUS_ACTIVE; - if (mReq->zptr) { - mReq->ptr->next = mReq->zdma; - } else { - mReq->ptr->next = TD_TERMINATE; - if (!mReq->req.no_interrupt) - mReq->ptr->token |= TD_IOC; - } - mReq->ptr->page[0] = mReq->req.dma; - for (i = 1; i < 5; i++) - mReq->ptr->page[i] = - (mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK; - - if (!list_empty(&mEp->qh.queue)) { - struct ci13xxx_req *mReqPrev; - int n = hw_ep_bit(mEp->num, mEp->dir); - int tmp_stat; - - mReqPrev = list_entry(mEp->qh.queue.prev, - struct ci13xxx_req, queue); - if (mReqPrev->zptr) - mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK; - else - mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK; - wmb(); - if (hw_cread(CAP_ENDPTPRIME, BIT(n))) - goto done; - do { - hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, USBCMD_ATDTW); - tmp_stat = hw_cread(CAP_ENDPTSTAT, BIT(n)); - } while (!hw_cread(CAP_USBCMD, USBCMD_ATDTW)); - hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, 0); - if (tmp_stat) - goto done; - } - - /* QH configuration */ - mEp->qh.ptr->td.next = mReq->dma; /* TERMINATE = 0 */ - mEp->qh.ptr->td.token &= ~TD_STATUS; /* clear status */ - mEp->qh.ptr->cap |= QH_ZLT; - - wmb(); /* synchronize before ep prime */ - - ret = hw_ep_prime(mEp->num, mEp->dir, - mEp->type == USB_ENDPOINT_XFER_CONTROL); -done: - return ret; -} - -/** - * _hardware_dequeue: handles a request at hardware level - * @gadget: gadget - * @mEp: endpoint - * - * This function returns an error code - */ -static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) -{ - trace("%p, %p", mEp, mReq); - - if (mReq->req.status != -EALREADY) - return -EINVAL; - - if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0) - return -EBUSY; - - if (mReq->zptr) { - if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0) - return -EBUSY; - dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma); - mReq->zptr = NULL; - } - - mReq->req.status = 0; - - if (mReq->map) { - dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length, - mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - mReq->req.dma = DMA_ADDR_INVALID; - mReq->map = 0; - } - - mReq->req.status = mReq->ptr->token & TD_STATUS; - if ((TD_STATUS_HALTED & mReq->req.status) != 0) - mReq->req.status = -1; - else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0) - mReq->req.status = -1; - else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0) - mReq->req.status = -1; - - mReq->req.actual = mReq->ptr->token & TD_TOTAL_BYTES; - mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES); - mReq->req.actual = mReq->req.length - mReq->req.actual; - mReq->req.actual = mReq->req.status ? 0 : mReq->req.actual; - - return mReq->req.actual; -} - -/** - * _ep_nuke: dequeues all endpoint requests - * @mEp: endpoint - * - * This function returns an error code - * Caller must hold lock - */ -static int _ep_nuke(struct ci13xxx_ep *mEp) -__releases(mEp->lock) -__acquires(mEp->lock) -{ - trace("%p", mEp); - - if (mEp == NULL) - return -EINVAL; - - hw_ep_flush(mEp->num, mEp->dir); - - while (!list_empty(&mEp->qh.queue)) { - - /* pop oldest request */ - struct ci13xxx_req *mReq = \ - list_entry(mEp->qh.queue.next, - struct ci13xxx_req, queue); - list_del_init(&mReq->queue); - mReq->req.status = -ESHUTDOWN; - - if (mReq->req.complete != NULL) { - spin_unlock(mEp->lock); - mReq->req.complete(&mEp->ep, &mReq->req); - spin_lock(mEp->lock); - } - } - return 0; -} - -/** - * _gadget_stop_activity: stops all USB activity, flushes & disables all endpts - * @gadget: gadget - * - * This function returns an error code - */ -static int _gadget_stop_activity(struct usb_gadget *gadget) -{ - struct usb_ep *ep; - struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget); - unsigned long flags; - - trace("%p", gadget); - - if (gadget == NULL) - return -EINVAL; - - spin_lock_irqsave(udc->lock, flags); - udc->gadget.speed = USB_SPEED_UNKNOWN; - udc->remote_wakeup = 0; - udc->suspended = 0; - spin_unlock_irqrestore(udc->lock, flags); - - /* flush all endpoints */ - gadget_for_each_ep(ep, gadget) { - usb_ep_fifo_flush(ep); - } - usb_ep_fifo_flush(&udc->ep0out.ep); - usb_ep_fifo_flush(&udc->ep0in.ep); - - udc->driver->disconnect(gadget); - - /* make sure to disable all endpoints */ - gadget_for_each_ep(ep, gadget) { - usb_ep_disable(ep); - } - - if (udc->status != NULL) { - usb_ep_free_request(&udc->ep0in.ep, udc->status); - udc->status = NULL; - } - - return 0; -} - -/****************************************************************************** - * ISR block - *****************************************************************************/ -/** - * isr_reset_handler: USB reset interrupt handler - * @udc: UDC device - * - * This function resets USB engine after a bus reset occurred - */ -static void isr_reset_handler(struct ci13xxx *udc) -__releases(udc->lock) -__acquires(udc->lock) -{ - int retval; - - trace("%p", udc); - - if (udc == NULL) { - err("EINVAL"); - return; - } - - dbg_event(0xFF, "BUS RST", 0); - - spin_unlock(udc->lock); - retval = _gadget_stop_activity(&udc->gadget); - if (retval) - goto done; - - retval = hw_usb_reset(); - if (retval) - goto done; - - udc->status = usb_ep_alloc_request(&udc->ep0in.ep, GFP_ATOMIC); - if (udc->status == NULL) - retval = -ENOMEM; - - spin_lock(udc->lock); - - done: - if (retval) - err("error: %i", retval); -} - -/** - * isr_get_status_complete: get_status request complete function - * @ep: endpoint - * @req: request handled - * - * Caller must release lock - */ -static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req) -{ - trace("%p, %p", ep, req); - - if (ep == NULL || req == NULL) { - err("EINVAL"); - return; - } - - kfree(req->buf); - usb_ep_free_request(ep, req); -} - -/** - * isr_get_status_response: get_status request response - * @udc: udc struct - * @setup: setup request packet - * - * This function returns an error code - */ -static int isr_get_status_response(struct ci13xxx *udc, - struct usb_ctrlrequest *setup) -__releases(mEp->lock) -__acquires(mEp->lock) -{ - struct ci13xxx_ep *mEp = &udc->ep0in; - struct usb_request *req = NULL; - gfp_t gfp_flags = GFP_ATOMIC; - int dir, num, retval; - - trace("%p, %p", mEp, setup); - - if (mEp == NULL || setup == NULL) - return -EINVAL; - - spin_unlock(mEp->lock); - req = usb_ep_alloc_request(&mEp->ep, gfp_flags); - spin_lock(mEp->lock); - if (req == NULL) - return -ENOMEM; - - req->complete = isr_get_status_complete; - req->length = 2; - req->buf = kzalloc(req->length, gfp_flags); - if (req->buf == NULL) { - retval = -ENOMEM; - goto err_free_req; - } - - if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) { - /* Assume that device is bus powered for now. */ - *((u16 *)req->buf) = _udc->remote_wakeup << 1; - retval = 0; - } else if ((setup->bRequestType & USB_RECIP_MASK) \ - == USB_RECIP_ENDPOINT) { - dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ? - TX : RX; - num = le16_to_cpu(setup->wIndex) & USB_ENDPOINT_NUMBER_MASK; - *((u16 *)req->buf) = hw_ep_get_halt(num, dir); - } - /* else do nothing; reserved for future use */ - - spin_unlock(mEp->lock); - retval = usb_ep_queue(&mEp->ep, req, gfp_flags); - spin_lock(mEp->lock); - if (retval) - goto err_free_buf; - - return 0; - - err_free_buf: - kfree(req->buf); - err_free_req: - spin_unlock(mEp->lock); - usb_ep_free_request(&mEp->ep, req); - spin_lock(mEp->lock); - return retval; -} - -/** - * isr_setup_status_complete: setup_status request complete function - * @ep: endpoint - * @req: request handled - * - * Caller must release lock. Put the port in test mode if test mode - * feature is selected. - */ -static void -isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct ci13xxx *udc = req->context; - unsigned long flags; - - trace("%p, %p", ep, req); - - spin_lock_irqsave(udc->lock, flags); - if (udc->test_mode) - hw_port_test_set(udc->test_mode); - spin_unlock_irqrestore(udc->lock, flags); -} - -/** - * isr_setup_status_phase: queues the status phase of a setup transation - * @udc: udc struct - * - * This function returns an error code - */ -static int isr_setup_status_phase(struct ci13xxx *udc) -__releases(mEp->lock) -__acquires(mEp->lock) -{ - int retval; - struct ci13xxx_ep *mEp; - - trace("%p", udc); - - mEp = (udc->ep0_dir == TX) ? &udc->ep0out : &udc->ep0in; - udc->status->context = udc; - udc->status->complete = isr_setup_status_complete; - - spin_unlock(mEp->lock); - retval = usb_ep_queue(&mEp->ep, udc->status, GFP_ATOMIC); - spin_lock(mEp->lock); - - return retval; -} - -/** - * isr_tr_complete_low: transaction complete low level handler - * @mEp: endpoint - * - * This function returns an error code - * Caller must hold lock - */ -static int isr_tr_complete_low(struct ci13xxx_ep *mEp) -__releases(mEp->lock) -__acquires(mEp->lock) -{ - struct ci13xxx_req *mReq, *mReqTemp; - struct ci13xxx_ep *mEpTemp = mEp; - int uninitialized_var(retval); - - trace("%p", mEp); - - if (list_empty(&mEp->qh.queue)) - return -EINVAL; - - list_for_each_entry_safe(mReq, mReqTemp, &mEp->qh.queue, - queue) { - retval = _hardware_dequeue(mEp, mReq); - if (retval < 0) - break; - list_del_init(&mReq->queue); - dbg_done(_usb_addr(mEp), mReq->ptr->token, retval); - if (mReq->req.complete != NULL) { - spin_unlock(mEp->lock); - if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) && - mReq->req.length) - mEpTemp = &_udc->ep0in; - mReq->req.complete(&mEpTemp->ep, &mReq->req); - spin_lock(mEp->lock); - } - } - - if (retval == -EBUSY) - retval = 0; - if (retval < 0) - dbg_event(_usb_addr(mEp), "DONE", retval); - - return retval; -} - -/** - * isr_tr_complete_handler: transaction complete interrupt handler - * @udc: UDC descriptor - * - * This function handles traffic events - */ -static void isr_tr_complete_handler(struct ci13xxx *udc) -__releases(udc->lock) -__acquires(udc->lock) -{ - unsigned i; - u8 tmode = 0; - - trace("%p", udc); - - if (udc == NULL) { - err("EINVAL"); - return; - } - - for (i = 0; i < hw_ep_max; i++) { - struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i]; - int type, num, dir, err = -EINVAL; - struct usb_ctrlrequest req; - - if (mEp->desc == NULL) - continue; /* not configured */ - - if (hw_test_and_clear_complete(i)) { - err = isr_tr_complete_low(mEp); - if (mEp->type == USB_ENDPOINT_XFER_CONTROL) { - if (err > 0) /* needs status phase */ - err = isr_setup_status_phase(udc); - if (err < 0) { - dbg_event(_usb_addr(mEp), - "ERROR", err); - spin_unlock(udc->lock); - if (usb_ep_set_halt(&mEp->ep)) - err("error: ep_set_halt"); - spin_lock(udc->lock); - } - } - } - - if (mEp->type != USB_ENDPOINT_XFER_CONTROL || - !hw_test_and_clear_setup_status(i)) - continue; - - if (i != 0) { - warn("ctrl traffic received at endpoint"); - continue; - } - - /* - * Flush data and handshake transactions of previous - * setup packet. - */ - _ep_nuke(&udc->ep0out); - _ep_nuke(&udc->ep0in); - - /* read_setup_packet */ - do { - hw_test_and_set_setup_guard(); - memcpy(&req, &mEp->qh.ptr->setup, sizeof(req)); - } while (!hw_test_and_clear_setup_guard()); - - type = req.bRequestType; - - udc->ep0_dir = (type & USB_DIR_IN) ? TX : RX; - - dbg_setup(_usb_addr(mEp), &req); - - switch (req.bRequest) { - case USB_REQ_CLEAR_FEATURE: - if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) && - le16_to_cpu(req.wValue) == - USB_ENDPOINT_HALT) { - if (req.wLength != 0) - break; - num = le16_to_cpu(req.wIndex); - dir = num & USB_ENDPOINT_DIR_MASK; - num &= USB_ENDPOINT_NUMBER_MASK; - if (dir) /* TX */ - num += hw_ep_max/2; - if (!udc->ci13xxx_ep[num].wedge) { - spin_unlock(udc->lock); - err = usb_ep_clear_halt( - &udc->ci13xxx_ep[num].ep); - spin_lock(udc->lock); - if (err) - break; - } - err = isr_setup_status_phase(udc); - } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) && - le16_to_cpu(req.wValue) == - USB_DEVICE_REMOTE_WAKEUP) { - if (req.wLength != 0) - break; - udc->remote_wakeup = 0; - err = isr_setup_status_phase(udc); - } else { - goto delegate; - } - break; - case USB_REQ_GET_STATUS: - if (type != (USB_DIR_IN|USB_RECIP_DEVICE) && - type != (USB_DIR_IN|USB_RECIP_ENDPOINT) && - type != (USB_DIR_IN|USB_RECIP_INTERFACE)) - goto delegate; - if (le16_to_cpu(req.wLength) != 2 || - le16_to_cpu(req.wValue) != 0) - break; - err = isr_get_status_response(udc, &req); - break; - case USB_REQ_SET_ADDRESS: - if (type != (USB_DIR_OUT|USB_RECIP_DEVICE)) - goto delegate; - if (le16_to_cpu(req.wLength) != 0 || - le16_to_cpu(req.wIndex) != 0) - break; - err = hw_usb_set_address((u8)le16_to_cpu(req.wValue)); - if (err) - break; - err = isr_setup_status_phase(udc); - break; - case USB_REQ_SET_FEATURE: - if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) && - le16_to_cpu(req.wValue) == - USB_ENDPOINT_HALT) { - if (req.wLength != 0) - break; - num = le16_to_cpu(req.wIndex); - dir = num & USB_ENDPOINT_DIR_MASK; - num &= USB_ENDPOINT_NUMBER_MASK; - if (dir) /* TX */ - num += hw_ep_max/2; - - spin_unlock(udc->lock); - err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep); - spin_lock(udc->lock); - if (!err) - isr_setup_status_phase(udc); - } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE)) { - if (req.wLength != 0) - break; - switch (le16_to_cpu(req.wValue)) { - case USB_DEVICE_REMOTE_WAKEUP: - udc->remote_wakeup = 1; - err = isr_setup_status_phase(udc); - break; - case USB_DEVICE_TEST_MODE: - tmode = le16_to_cpu(req.wIndex) >> 8; - switch (tmode) { - case TEST_J: - case TEST_K: - case TEST_SE0_NAK: - case TEST_PACKET: - case TEST_FORCE_EN: - udc->test_mode = tmode; - err = isr_setup_status_phase( - udc); - break; - default: - break; - } - default: - goto delegate; - } - } else { - goto delegate; - } - break; - default: -delegate: - if (req.wLength == 0) /* no data phase */ - udc->ep0_dir = TX; - - spin_unlock(udc->lock); - err = udc->driver->setup(&udc->gadget, &req); - spin_lock(udc->lock); - break; - } - - if (err < 0) { - dbg_event(_usb_addr(mEp), "ERROR", err); - - spin_unlock(udc->lock); - if (usb_ep_set_halt(&mEp->ep)) - err("error: ep_set_halt"); - spin_lock(udc->lock); - } - } -} - -/****************************************************************************** - * ENDPT block - *****************************************************************************/ -/** - * ep_enable: configure endpoint, making it usable - * - * Check usb_ep_enable() at "usb_gadget.h" for details - */ -static int ep_enable(struct usb_ep *ep, - const struct usb_endpoint_descriptor *desc) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - int retval = 0; - unsigned long flags; - - trace("%p, %p", ep, desc); - - if (ep == NULL || desc == NULL) - return -EINVAL; - - spin_lock_irqsave(mEp->lock, flags); - - /* only internal SW should enable ctrl endpts */ - - mEp->desc = desc; - - if (!list_empty(&mEp->qh.queue)) - warn("enabling a non-empty endpoint!"); - - mEp->dir = usb_endpoint_dir_in(desc) ? TX : RX; - mEp->num = usb_endpoint_num(desc); - mEp->type = usb_endpoint_type(desc); - - mEp->ep.maxpacket = usb_endpoint_maxp(desc); - - dbg_event(_usb_addr(mEp), "ENABLE", 0); - - mEp->qh.ptr->cap = 0; - - if (mEp->type == USB_ENDPOINT_XFER_CONTROL) - mEp->qh.ptr->cap |= QH_IOS; - else if (mEp->type == USB_ENDPOINT_XFER_ISOC) - mEp->qh.ptr->cap &= ~QH_MULT; - else - mEp->qh.ptr->cap &= ~QH_ZLT; - - mEp->qh.ptr->cap |= - (mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT; - mEp->qh.ptr->td.next |= TD_TERMINATE; /* needed? */ - - /* - * Enable endpoints in the HW other than ep0 as ep0 - * is always enabled - */ - if (mEp->num) - retval |= hw_ep_enable(mEp->num, mEp->dir, mEp->type); - - spin_unlock_irqrestore(mEp->lock, flags); - return retval; -} - -/** - * ep_disable: endpoint is no longer usable - * - * Check usb_ep_disable() at "usb_gadget.h" for details - */ -static int ep_disable(struct usb_ep *ep) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - int direction, retval = 0; - unsigned long flags; - - trace("%p", ep); - - if (ep == NULL) - return -EINVAL; - else if (mEp->desc == NULL) - return -EBUSY; - - spin_lock_irqsave(mEp->lock, flags); - - /* only internal SW should disable ctrl endpts */ - - direction = mEp->dir; - do { - dbg_event(_usb_addr(mEp), "DISABLE", 0); - - retval |= _ep_nuke(mEp); - retval |= hw_ep_disable(mEp->num, mEp->dir); - - if (mEp->type == USB_ENDPOINT_XFER_CONTROL) - mEp->dir = (mEp->dir == TX) ? RX : TX; - - } while (mEp->dir != direction); - - mEp->desc = NULL; - mEp->ep.desc = NULL; - - spin_unlock_irqrestore(mEp->lock, flags); - return retval; -} - -/** - * ep_alloc_request: allocate a request object to use with this endpoint - * - * Check usb_ep_alloc_request() at "usb_gadget.h" for details - */ -static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - struct ci13xxx_req *mReq = NULL; - - trace("%p, %i", ep, gfp_flags); - - if (ep == NULL) { - err("EINVAL"); - return NULL; - } - - mReq = kzalloc(sizeof(struct ci13xxx_req), gfp_flags); - if (mReq != NULL) { - INIT_LIST_HEAD(&mReq->queue); - mReq->req.dma = DMA_ADDR_INVALID; - - mReq->ptr = dma_pool_alloc(mEp->td_pool, gfp_flags, - &mReq->dma); - if (mReq->ptr == NULL) { - kfree(mReq); - mReq = NULL; - } - } - - dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL); - - return (mReq == NULL) ? NULL : &mReq->req; -} - -/** - * ep_free_request: frees a request object - * - * Check usb_ep_free_request() at "usb_gadget.h" for details - */ -static void ep_free_request(struct usb_ep *ep, struct usb_request *req) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); - unsigned long flags; - - trace("%p, %p", ep, req); - - if (ep == NULL || req == NULL) { - err("EINVAL"); - return; - } else if (!list_empty(&mReq->queue)) { - err("EBUSY"); - return; - } - - spin_lock_irqsave(mEp->lock, flags); - - if (mReq->ptr) - dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma); - kfree(mReq); - - dbg_event(_usb_addr(mEp), "FREE", 0); - - spin_unlock_irqrestore(mEp->lock, flags); -} - -/** - * ep_queue: queues (submits) an I/O request to an endpoint - * - * Check usb_ep_queue()* at usb_gadget.h" for details - */ -static int ep_queue(struct usb_ep *ep, struct usb_request *req, - gfp_t __maybe_unused gfp_flags) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); - int retval = 0; - unsigned long flags; - - trace("%p, %p, %X", ep, req, gfp_flags); - - if (ep == NULL || req == NULL || mEp->desc == NULL) - return -EINVAL; - - spin_lock_irqsave(mEp->lock, flags); - - if (mEp->type == USB_ENDPOINT_XFER_CONTROL) { - if (req->length) - mEp = (_udc->ep0_dir == RX) ? - &_udc->ep0out : &_udc->ep0in; - if (!list_empty(&mEp->qh.queue)) { - _ep_nuke(mEp); - retval = -EOVERFLOW; - warn("endpoint ctrl %X nuked", _usb_addr(mEp)); - } - } - - /* first nuke then test link, e.g. previous status has not sent */ - if (!list_empty(&mReq->queue)) { - retval = -EBUSY; - err("request already in queue"); - goto done; - } - - if (req->length > (4 * CI13XXX_PAGE_SIZE)) { - req->length = (4 * CI13XXX_PAGE_SIZE); - retval = -EMSGSIZE; - warn("request length truncated"); - } - - dbg_queue(_usb_addr(mEp), req, retval); - - /* push request */ - mReq->req.status = -EINPROGRESS; - mReq->req.actual = 0; - - retval = _hardware_enqueue(mEp, mReq); - - if (retval == -EALREADY) { - dbg_event(_usb_addr(mEp), "QUEUE", retval); - retval = 0; - } - if (!retval) - list_add_tail(&mReq->queue, &mEp->qh.queue); - - done: - spin_unlock_irqrestore(mEp->lock, flags); - return retval; -} - -/** - * ep_dequeue: dequeues (cancels, unlinks) an I/O request from an endpoint - * - * Check usb_ep_dequeue() at "usb_gadget.h" for details - */ -static int ep_dequeue(struct usb_ep *ep, struct usb_request *req) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); - unsigned long flags; - - trace("%p, %p", ep, req); - - if (ep == NULL || req == NULL || mReq->req.status != -EALREADY || - mEp->desc == NULL || list_empty(&mReq->queue) || - list_empty(&mEp->qh.queue)) - return -EINVAL; - - spin_lock_irqsave(mEp->lock, flags); - - dbg_event(_usb_addr(mEp), "DEQUEUE", 0); - - hw_ep_flush(mEp->num, mEp->dir); - - /* pop request */ - list_del_init(&mReq->queue); - if (mReq->map) { - dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length, - mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - mReq->req.dma = DMA_ADDR_INVALID; - mReq->map = 0; - } - req->status = -ECONNRESET; - - if (mReq->req.complete != NULL) { - spin_unlock(mEp->lock); - mReq->req.complete(&mEp->ep, &mReq->req); - spin_lock(mEp->lock); - } - - spin_unlock_irqrestore(mEp->lock, flags); - return 0; -} - -/** - * ep_set_halt: sets the endpoint halt feature - * - * Check usb_ep_set_halt() at "usb_gadget.h" for details - */ -static int ep_set_halt(struct usb_ep *ep, int value) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - int direction, retval = 0; - unsigned long flags; - - trace("%p, %i", ep, value); - - if (ep == NULL || mEp->desc == NULL) - return -EINVAL; - - spin_lock_irqsave(mEp->lock, flags); - -#ifndef STALL_IN - /* g_file_storage MS compliant but g_zero fails chapter 9 compliance */ - if (value && mEp->type == USB_ENDPOINT_XFER_BULK && mEp->dir == TX && - !list_empty(&mEp->qh.queue)) { - spin_unlock_irqrestore(mEp->lock, flags); - return -EAGAIN; - } -#endif - - direction = mEp->dir; - do { - dbg_event(_usb_addr(mEp), "HALT", value); - retval |= hw_ep_set_halt(mEp->num, mEp->dir, value); - - if (!value) - mEp->wedge = 0; - - if (mEp->type == USB_ENDPOINT_XFER_CONTROL) - mEp->dir = (mEp->dir == TX) ? RX : TX; - - } while (mEp->dir != direction); - - spin_unlock_irqrestore(mEp->lock, flags); - return retval; -} - -/** - * ep_set_wedge: sets the halt feature and ignores clear requests - * - * Check usb_ep_set_wedge() at "usb_gadget.h" for details - */ -static int ep_set_wedge(struct usb_ep *ep) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - unsigned long flags; - - trace("%p", ep); - - if (ep == NULL || mEp->desc == NULL) - return -EINVAL; - - spin_lock_irqsave(mEp->lock, flags); - - dbg_event(_usb_addr(mEp), "WEDGE", 0); - mEp->wedge = 1; - - spin_unlock_irqrestore(mEp->lock, flags); - - return usb_ep_set_halt(ep); -} - -/** - * ep_fifo_flush: flushes contents of a fifo - * - * Check usb_ep_fifo_flush() at "usb_gadget.h" for details - */ -static void ep_fifo_flush(struct usb_ep *ep) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - unsigned long flags; - - trace("%p", ep); - - if (ep == NULL) { - err("%02X: -EINVAL", _usb_addr(mEp)); - return; - } - - spin_lock_irqsave(mEp->lock, flags); - - dbg_event(_usb_addr(mEp), "FFLUSH", 0); - hw_ep_flush(mEp->num, mEp->dir); - - spin_unlock_irqrestore(mEp->lock, flags); -} - -/** - * Endpoint-specific part of the API to the USB controller hardware - * Check "usb_gadget.h" for details - */ -static const struct usb_ep_ops usb_ep_ops = { - .enable = ep_enable, - .disable = ep_disable, - .alloc_request = ep_alloc_request, - .free_request = ep_free_request, - .queue = ep_queue, - .dequeue = ep_dequeue, - .set_halt = ep_set_halt, - .set_wedge = ep_set_wedge, - .fifo_flush = ep_fifo_flush, -}; - -/****************************************************************************** - * GADGET block - *****************************************************************************/ -static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active) -{ - struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget); - unsigned long flags; - int gadget_ready = 0; - - if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS)) - return -EOPNOTSUPP; - - spin_lock_irqsave(udc->lock, flags); - udc->vbus_active = is_active; - if (udc->driver) - gadget_ready = 1; - spin_unlock_irqrestore(udc->lock, flags); - - if (gadget_ready) { - if (is_active) { - pm_runtime_get_sync(&_gadget->dev); - hw_device_reset(udc); - hw_device_state(udc->ep0out.qh.dma); - } else { - hw_device_state(0); - if (udc->udc_driver->notify_event) - udc->udc_driver->notify_event(udc, - CI13XXX_CONTROLLER_STOPPED_EVENT); - _gadget_stop_activity(&udc->gadget); - pm_runtime_put_sync(&_gadget->dev); - } - } - - return 0; -} - -static int ci13xxx_wakeup(struct usb_gadget *_gadget) -{ - struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget); - unsigned long flags; - int ret = 0; - - trace(); - - spin_lock_irqsave(udc->lock, flags); - if (!udc->remote_wakeup) { - ret = -EOPNOTSUPP; - trace("remote wakeup feature is not enabled\n"); - goto out; - } - if (!hw_cread(CAP_PORTSC, PORTSC_SUSP)) { - ret = -EINVAL; - trace("port is not suspended\n"); - goto out; - } - hw_cwrite(CAP_PORTSC, PORTSC_FPR, PORTSC_FPR); -out: - spin_unlock_irqrestore(udc->lock, flags); - return ret; -} - -static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA) -{ - struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget); - - if (udc->transceiver) - return usb_phy_set_power(udc->transceiver, mA); - return -ENOTSUPP; -} - -static int ci13xxx_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int ci13xxx_stop(struct usb_gadget_driver *driver); -/** - * Device operations part of the API to the USB controller hardware, - * which don't involve endpoints (or i/o) - * Check "usb_gadget.h" for details - */ -static const struct usb_gadget_ops usb_gadget_ops = { - .vbus_session = ci13xxx_vbus_session, - .wakeup = ci13xxx_wakeup, - .vbus_draw = ci13xxx_vbus_draw, - .start = ci13xxx_start, - .stop = ci13xxx_stop, -}; - -/** - * ci13xxx_start: register a gadget driver - * @driver: the driver being registered - * @bind: the driver's bind callback - * - * Check ci13xxx_start() at for details. - * Interrupts are enabled here. - */ -static int ci13xxx_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) -{ - struct ci13xxx *udc = _udc; - unsigned long flags; - int i, j; - int retval = -ENOMEM; - - trace("%p", driver); - - if (driver == NULL || - bind == NULL || - driver->setup == NULL || - driver->disconnect == NULL) - return -EINVAL; - else if (udc == NULL) - return -ENODEV; - else if (udc->driver != NULL) - return -EBUSY; - - /* alloc resources */ - udc->qh_pool = dma_pool_create("ci13xxx_qh", &udc->gadget.dev, - sizeof(struct ci13xxx_qh), - 64, CI13XXX_PAGE_SIZE); - if (udc->qh_pool == NULL) - return -ENOMEM; - - udc->td_pool = dma_pool_create("ci13xxx_td", &udc->gadget.dev, - sizeof(struct ci13xxx_td), - 64, CI13XXX_PAGE_SIZE); - if (udc->td_pool == NULL) { - dma_pool_destroy(udc->qh_pool); - udc->qh_pool = NULL; - return -ENOMEM; - } - - spin_lock_irqsave(udc->lock, flags); - - info("hw_ep_max = %d", hw_ep_max); - - udc->gadget.dev.driver = NULL; - - retval = 0; - for (i = 0; i < hw_ep_max/2; i++) { - for (j = RX; j <= TX; j++) { - int k = i + j * hw_ep_max/2; - struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[k]; - - scnprintf(mEp->name, sizeof(mEp->name), "ep%i%s", i, - (j == TX) ? "in" : "out"); - - mEp->lock = udc->lock; - mEp->device = &udc->gadget.dev; - mEp->td_pool = udc->td_pool; - - mEp->ep.name = mEp->name; - mEp->ep.ops = &usb_ep_ops; - mEp->ep.maxpacket = CTRL_PAYLOAD_MAX; - - INIT_LIST_HEAD(&mEp->qh.queue); - spin_unlock_irqrestore(udc->lock, flags); - mEp->qh.ptr = dma_pool_alloc(udc->qh_pool, GFP_KERNEL, - &mEp->qh.dma); - spin_lock_irqsave(udc->lock, flags); - if (mEp->qh.ptr == NULL) - retval = -ENOMEM; - else - memset(mEp->qh.ptr, 0, sizeof(*mEp->qh.ptr)); - - /* skip ep0 out and in endpoints */ - if (i == 0) - continue; - - list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list); - } - } - if (retval) - goto done; - spin_unlock_irqrestore(udc->lock, flags); - udc->ep0out.ep.desc = &ctrl_endpt_out_desc; - retval = usb_ep_enable(&udc->ep0out.ep); - if (retval) - return retval; - - udc->ep0in.ep.desc = &ctrl_endpt_in_desc; - retval = usb_ep_enable(&udc->ep0in.ep); - if (retval) - return retval; - spin_lock_irqsave(udc->lock, flags); - - udc->gadget.ep0 = &udc->ep0in.ep; - /* bind gadget */ - driver->driver.bus = NULL; - udc->gadget.dev.driver = &driver->driver; - - spin_unlock_irqrestore(udc->lock, flags); - retval = bind(&udc->gadget); /* MAY SLEEP */ - spin_lock_irqsave(udc->lock, flags); - - if (retval) { - udc->gadget.dev.driver = NULL; - goto done; - } - - udc->driver = driver; - pm_runtime_get_sync(&udc->gadget.dev); - if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) { - if (udc->vbus_active) { - if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) - hw_device_reset(udc); - } else { - pm_runtime_put_sync(&udc->gadget.dev); - goto done; - } - } - - retval = hw_device_state(udc->ep0out.qh.dma); - if (retval) - pm_runtime_put_sync(&udc->gadget.dev); - - done: - spin_unlock_irqrestore(udc->lock, flags); - return retval; -} - -/** - * ci13xxx_stop: unregister a gadget driver - * - * Check usb_gadget_unregister_driver() at "usb_gadget.h" for details - */ -static int ci13xxx_stop(struct usb_gadget_driver *driver) -{ - struct ci13xxx *udc = _udc; - unsigned long i, flags; - - trace("%p", driver); - - if (driver == NULL || - driver->unbind == NULL || - driver->setup == NULL || - driver->disconnect == NULL || - driver != udc->driver) - return -EINVAL; - - spin_lock_irqsave(udc->lock, flags); - - if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) || - udc->vbus_active) { - hw_device_state(0); - if (udc->udc_driver->notify_event) - udc->udc_driver->notify_event(udc, - CI13XXX_CONTROLLER_STOPPED_EVENT); - spin_unlock_irqrestore(udc->lock, flags); - _gadget_stop_activity(&udc->gadget); - spin_lock_irqsave(udc->lock, flags); - pm_runtime_put(&udc->gadget.dev); - } - - /* unbind gadget */ - spin_unlock_irqrestore(udc->lock, flags); - driver->unbind(&udc->gadget); /* MAY SLEEP */ - spin_lock_irqsave(udc->lock, flags); - - udc->gadget.dev.driver = NULL; - - /* free resources */ - for (i = 0; i < hw_ep_max; i++) { - struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i]; - - if (!list_empty(&mEp->ep.ep_list)) - list_del_init(&mEp->ep.ep_list); - - if (mEp->qh.ptr != NULL) - dma_pool_free(udc->qh_pool, mEp->qh.ptr, mEp->qh.dma); - } - - udc->gadget.ep0 = NULL; - udc->driver = NULL; - - spin_unlock_irqrestore(udc->lock, flags); - - if (udc->td_pool != NULL) { - dma_pool_destroy(udc->td_pool); - udc->td_pool = NULL; - } - if (udc->qh_pool != NULL) { - dma_pool_destroy(udc->qh_pool); - udc->qh_pool = NULL; - } - - return 0; -} - -/****************************************************************************** - * BUS block - *****************************************************************************/ -/** - * udc_irq: global interrupt handler - * - * This function returns IRQ_HANDLED if the IRQ has been handled - * It locks access to registers - */ -static irqreturn_t udc_irq(void) -{ - struct ci13xxx *udc = _udc; - irqreturn_t retval; - u32 intr; - - trace(); - - if (udc == NULL) { - err("ENODEV"); - return IRQ_HANDLED; - } - - spin_lock(udc->lock); - - if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) { - if (hw_cread(CAP_USBMODE, USBMODE_CM) != - USBMODE_CM_DEVICE) { - spin_unlock(udc->lock); - return IRQ_NONE; - } - } - intr = hw_test_and_clear_intr_active(); - if (intr) { - isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intr; - isr_statistics.hndl.idx &= ISR_MASK; - isr_statistics.hndl.cnt++; - - /* order defines priority - do NOT change it */ - if (USBi_URI & intr) { - isr_statistics.uri++; - isr_reset_handler(udc); - } - if (USBi_PCI & intr) { - isr_statistics.pci++; - udc->gadget.speed = hw_port_is_high_speed() ? - USB_SPEED_HIGH : USB_SPEED_FULL; - if (udc->suspended && udc->driver->resume) { - spin_unlock(udc->lock); - udc->driver->resume(&udc->gadget); - spin_lock(udc->lock); - udc->suspended = 0; - } - } - if (USBi_UEI & intr) - isr_statistics.uei++; - if (USBi_UI & intr) { - isr_statistics.ui++; - isr_tr_complete_handler(udc); - } - if (USBi_SLI & intr) { - if (udc->gadget.speed != USB_SPEED_UNKNOWN && - udc->driver->suspend) { - udc->suspended = 1; - spin_unlock(udc->lock); - udc->driver->suspend(&udc->gadget); - spin_lock(udc->lock); - } - isr_statistics.sli++; - } - retval = IRQ_HANDLED; - } else { - isr_statistics.none++; - retval = IRQ_NONE; - } - spin_unlock(udc->lock); - - return retval; -} - -/** - * udc_release: driver release function - * @dev: device - * - * Currently does nothing - */ -static void udc_release(struct device *dev) -{ - trace("%p", dev); - - if (dev == NULL) - err("EINVAL"); -} - -/** - * udc_probe: parent probe must call this to initialize UDC - * @dev: parent device - * @regs: registers base address - * @name: driver name - * - * This function returns an error code - * No interrupts active, the IRQ has not been requested yet - * Kernel assumes 32-bit DMA operations by default, no need to dma_set_mask - */ -static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev, - void __iomem *regs) -{ - struct ci13xxx *udc; - int retval = 0; - - trace("%p, %p, %p", dev, regs, driver->name); - - if (dev == NULL || regs == NULL || driver == NULL || - driver->name == NULL) - return -EINVAL; - - udc = kzalloc(sizeof(struct ci13xxx), GFP_KERNEL); - if (udc == NULL) - return -ENOMEM; - - udc->lock = &udc_lock; - udc->regs = regs; - udc->udc_driver = driver; - - udc->gadget.ops = &usb_gadget_ops; - udc->gadget.speed = USB_SPEED_UNKNOWN; - udc->gadget.max_speed = USB_SPEED_HIGH; - udc->gadget.is_otg = 0; - udc->gadget.name = driver->name; - - INIT_LIST_HEAD(&udc->gadget.ep_list); - udc->gadget.ep0 = NULL; - - dev_set_name(&udc->gadget.dev, "gadget"); - udc->gadget.dev.dma_mask = dev->dma_mask; - udc->gadget.dev.coherent_dma_mask = dev->coherent_dma_mask; - udc->gadget.dev.parent = dev; - udc->gadget.dev.release = udc_release; - - retval = hw_device_init(regs); - if (retval < 0) - goto free_udc; - - udc->transceiver = usb_get_transceiver(); - - if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) { - if (udc->transceiver == NULL) { - retval = -ENODEV; - goto free_udc; - } - } - - if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) { - retval = hw_device_reset(udc); - if (retval) - goto put_transceiver; - } - - retval = device_register(&udc->gadget.dev); - if (retval) { - put_device(&udc->gadget.dev); - goto put_transceiver; - } - -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - retval = dbg_create_files(&udc->gadget.dev); -#endif - if (retval) - goto unreg_device; - - if (udc->transceiver) { - retval = otg_set_peripheral(udc->transceiver->otg, - &udc->gadget); - if (retval) - goto remove_dbg; - } - - retval = usb_add_gadget_udc(dev, &udc->gadget); - if (retval) - goto remove_trans; - - pm_runtime_no_callbacks(&udc->gadget.dev); - pm_runtime_enable(&udc->gadget.dev); - - _udc = udc; - return retval; - -remove_trans: - if (udc->transceiver) { - otg_set_peripheral(udc->transceiver->otg, &udc->gadget); - usb_put_transceiver(udc->transceiver); - } - - err("error = %i", retval); -remove_dbg: -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - dbg_remove_files(&udc->gadget.dev); -#endif -unreg_device: - device_unregister(&udc->gadget.dev); -put_transceiver: - if (udc->transceiver) - usb_put_transceiver(udc->transceiver); -free_udc: - kfree(udc); - _udc = NULL; - return retval; -} - -/** - * udc_remove: parent remove must call this to remove UDC - * - * No interrupts active, the IRQ has been released - */ -static void udc_remove(void) -{ - struct ci13xxx *udc = _udc; - - if (udc == NULL) { - err("EINVAL"); - return; - } - usb_del_gadget_udc(&udc->gadget); - - if (udc->transceiver) { - otg_set_peripheral(udc->transceiver->otg, &udc->gadget); - usb_put_transceiver(udc->transceiver); - } -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - dbg_remove_files(&udc->gadget.dev); -#endif - device_unregister(&udc->gadget.dev); - - kfree(udc); - _udc = NULL; -} diff --git a/ANDROID_3.4.5/drivers/usb/gadget/ci13xxx_udc.h b/ANDROID_3.4.5/drivers/usb/gadget/ci13xxx_udc.h deleted file mode 100644 index 0d31af56..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/ci13xxx_udc.h +++ /dev/null @@ -1,227 +0,0 @@ -/* - * ci13xxx_udc.h - structures, registers, and macros MIPS USB IP core - * - * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. - * - * Author: David Lopo - * - * 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. - * - * Description: MIPS USB IP core family device controller - * Structures, registers and logging macros - */ - -#ifndef _CI13XXX_h_ -#define _CI13XXX_h_ - -/****************************************************************************** - * DEFINE - *****************************************************************************/ -#define CI13XXX_PAGE_SIZE 4096ul /* page size for TD's */ -#define ENDPT_MAX (32) -#define CTRL_PAYLOAD_MAX (64) -#define RX (0) /* similar to USB_DIR_OUT but can be used as an index */ -#define TX (1) /* similar to USB_DIR_IN but can be used as an index */ - -/****************************************************************************** - * STRUCTURES - *****************************************************************************/ -/* DMA layout of transfer descriptors */ -struct ci13xxx_td { - /* 0 */ - u32 next; -#define TD_TERMINATE BIT(0) -#define TD_ADDR_MASK (0xFFFFFFEUL << 5) - /* 1 */ - u32 token; -#define TD_STATUS (0x00FFUL << 0) -#define TD_STATUS_TR_ERR BIT(3) -#define TD_STATUS_DT_ERR BIT(5) -#define TD_STATUS_HALTED BIT(6) -#define TD_STATUS_ACTIVE BIT(7) -#define TD_MULTO (0x0003UL << 10) -#define TD_IOC BIT(15) -#define TD_TOTAL_BYTES (0x7FFFUL << 16) - /* 2 */ - u32 page[5]; -#define TD_CURR_OFFSET (0x0FFFUL << 0) -#define TD_FRAME_NUM (0x07FFUL << 0) -#define TD_RESERVED_MASK (0x0FFFUL << 0) -} __attribute__ ((packed)); - -/* DMA layout of queue heads */ -struct ci13xxx_qh { - /* 0 */ - u32 cap; -#define QH_IOS BIT(15) -#define QH_MAX_PKT (0x07FFUL << 16) -#define QH_ZLT BIT(29) -#define QH_MULT (0x0003UL << 30) - /* 1 */ - u32 curr; - /* 2 - 8 */ - struct ci13xxx_td td; - /* 9 */ - u32 RESERVED; - struct usb_ctrlrequest setup; -} __attribute__ ((packed)); - -/* Extension of usb_request */ -struct ci13xxx_req { - struct usb_request req; - unsigned map; - struct list_head queue; - struct ci13xxx_td *ptr; - dma_addr_t dma; - struct ci13xxx_td *zptr; - dma_addr_t zdma; -}; - -/* Extension of usb_ep */ -struct ci13xxx_ep { - struct usb_ep ep; - const struct usb_endpoint_descriptor *desc; - u8 dir; - u8 num; - u8 type; - char name[16]; - struct { - struct list_head queue; - struct ci13xxx_qh *ptr; - dma_addr_t dma; - } qh; - int wedge; - - /* global resources */ - spinlock_t *lock; - struct device *device; - struct dma_pool *td_pool; -}; - -struct ci13xxx; -struct ci13xxx_udc_driver { - const char *name; - unsigned long flags; -#define CI13XXX_REGS_SHARED BIT(0) -#define CI13XXX_REQUIRE_TRANSCEIVER BIT(1) -#define CI13XXX_PULLUP_ON_VBUS BIT(2) -#define CI13XXX_DISABLE_STREAMING BIT(3) - -#define CI13XXX_CONTROLLER_RESET_EVENT 0 -#define CI13XXX_CONTROLLER_STOPPED_EVENT 1 - void (*notify_event) (struct ci13xxx *udc, unsigned event); -}; - -/* CI13XXX UDC descriptor & global resources */ -struct ci13xxx { - spinlock_t *lock; /* ctrl register bank access */ - void __iomem *regs; /* registers address space */ - - struct dma_pool *qh_pool; /* DMA pool for queue heads */ - struct dma_pool *td_pool; /* DMA pool for transfer descs */ - struct usb_request *status; /* ep0 status request */ - - struct usb_gadget gadget; /* USB slave device */ - struct ci13xxx_ep ci13xxx_ep[ENDPT_MAX]; /* extended endpts */ - u32 ep0_dir; /* ep0 direction */ -#define ep0out ci13xxx_ep[0] -#define ep0in ci13xxx_ep[hw_ep_max / 2] - u8 remote_wakeup; /* Is remote wakeup feature - enabled by the host? */ - u8 suspended; /* suspended by the host */ - u8 test_mode; /* the selected test mode */ - - struct usb_gadget_driver *driver; /* 3rd party gadget driver */ - struct ci13xxx_udc_driver *udc_driver; /* device controller driver */ - int vbus_active; /* is VBUS active */ - struct usb_phy *transceiver; /* Transceiver struct */ -}; - -/****************************************************************************** - * REGISTERS - *****************************************************************************/ -/* register size */ -#define REG_BITS (32) - -/* HCCPARAMS */ -#define HCCPARAMS_LEN BIT(17) - -/* DCCPARAMS */ -#define DCCPARAMS_DEN (0x1F << 0) -#define DCCPARAMS_DC BIT(7) - -/* TESTMODE */ -#define TESTMODE_FORCE BIT(0) - -/* USBCMD */ -#define USBCMD_RS BIT(0) -#define USBCMD_RST BIT(1) -#define USBCMD_SUTW BIT(13) -#define USBCMD_ATDTW BIT(14) - -/* USBSTS & USBINTR */ -#define USBi_UI BIT(0) -#define USBi_UEI BIT(1) -#define USBi_PCI BIT(2) -#define USBi_URI BIT(6) -#define USBi_SLI BIT(8) - -/* DEVICEADDR */ -#define DEVICEADDR_USBADRA BIT(24) -#define DEVICEADDR_USBADR (0x7FUL << 25) - -/* PORTSC */ -#define PORTSC_FPR BIT(6) -#define PORTSC_SUSP BIT(7) -#define PORTSC_HSP BIT(9) -#define PORTSC_PTC (0x0FUL << 16) - -/* DEVLC */ -#define DEVLC_PSPD (0x03UL << 25) -#define DEVLC_PSPD_HS (0x02UL << 25) - -/* USBMODE */ -#define USBMODE_CM (0x03UL << 0) -#define USBMODE_CM_IDLE (0x00UL << 0) -#define USBMODE_CM_DEVICE (0x02UL << 0) -#define USBMODE_CM_HOST (0x03UL << 0) -#define USBMODE_SLOM BIT(3) -#define USBMODE_SDIS BIT(4) - -/* ENDPTCTRL */ -#define ENDPTCTRL_RXS BIT(0) -#define ENDPTCTRL_RXT (0x03UL << 2) -#define ENDPTCTRL_RXR BIT(6) /* reserved for port 0 */ -#define ENDPTCTRL_RXE BIT(7) -#define ENDPTCTRL_TXS BIT(16) -#define ENDPTCTRL_TXT (0x03UL << 18) -#define ENDPTCTRL_TXR BIT(22) /* reserved for port 0 */ -#define ENDPTCTRL_TXE BIT(23) - -/****************************************************************************** - * LOGGING - *****************************************************************************/ -#define ci13xxx_printk(level, format, args...) \ -do { \ - if (_udc == NULL) \ - printk(level "[%s] " format "\n", __func__, ## args); \ - else \ - dev_printk(level, _udc->gadget.dev.parent, \ - "[%s] " format "\n", __func__, ## args); \ -} while (0) - -#define err(format, args...) ci13xxx_printk(KERN_ERR, format, ## args) -#define warn(format, args...) ci13xxx_printk(KERN_WARNING, format, ## args) -#define info(format, args...) ci13xxx_printk(KERN_INFO, format, ## args) - -#ifdef TRACE -#define trace(format, args...) ci13xxx_printk(KERN_DEBUG, format, ## args) -#define dbg_trace(format, args...) dev_dbg(dev, format, ##args) -#else -#define trace(format, args...) do {} while (0) -#define dbg_trace(format, args...) do {} while (0) -#endif - -#endif /* _CI13XXX_h_ */ diff --git a/ANDROID_3.4.5/drivers/usb/gadget/composite.c b/ANDROID_3.4.5/drivers/usb/gadget/composite.c deleted file mode 100644 index 6cfe5f24..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/composite.c +++ /dev/null @@ -1,1674 +0,0 @@ -/* - * composite.c - infrastructure for Composite USB Gadgets - * - * Copyright (C) 2006-2008 David Brownell - * - * 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. - */ - -/* #define VERBOSE_DEBUG */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -/* - * The code in this file is utility code, used to build a gadget driver - * from one or more "function" drivers, one or more "configuration" - * objects, and a "usb_composite_driver" by gluing them together along - * with the relevant device-wide data. - */ - -/* big enough to hold our biggest descriptor */ -#define USB_BUFSIZ 1024 - -static struct usb_composite_driver *composite; -static int (*composite_gadget_bind)(struct usb_composite_dev *cdev); - -/* Some systems will need runtime overrides for the product identifiers - * published in the device descriptor, either numbers or strings or both. - * String parameters are in UTF-8 (superset of ASCII's 7 bit characters). - */ - -static ushort idVendor; -module_param(idVendor, ushort, 0); -MODULE_PARM_DESC(idVendor, "USB Vendor ID"); - -static ushort idProduct; -module_param(idProduct, ushort, 0); -MODULE_PARM_DESC(idProduct, "USB Product ID"); - -static ushort bcdDevice; -module_param(bcdDevice, ushort, 0); -MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)"); - -static char *iManufacturer; -module_param(iManufacturer, charp, 0); -MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string"); - -static char *iProduct; -module_param(iProduct, charp, 0); -MODULE_PARM_DESC(iProduct, "USB Product string"); - -static char *iSerialNumber; -module_param(iSerialNumber, charp, 0); -MODULE_PARM_DESC(iSerialNumber, "SerialNumber string"); - -static char composite_manufacturer[50]; - -/*-------------------------------------------------------------------------*/ -/** - * next_ep_desc() - advance to the next EP descriptor - * @t: currect pointer within descriptor array - * - * Return: next EP descriptor or NULL - * - * Iterate over @t until either EP descriptor found or - * NULL (that indicates end of list) encountered - */ -static struct usb_descriptor_header** -next_ep_desc(struct usb_descriptor_header **t) -{ - for (; *t; t++) { - if ((*t)->bDescriptorType == USB_DT_ENDPOINT) - return t; - } - return NULL; -} - -/* - * for_each_ep_desc()- iterate over endpoint descriptors in the - * descriptors list - * @start: pointer within descriptor array. - * @ep_desc: endpoint descriptor to use as the loop cursor - */ -#define for_each_ep_desc(start, ep_desc) \ - for (ep_desc = next_ep_desc(start); \ - ep_desc; ep_desc = next_ep_desc(ep_desc+1)) - -/** - * config_ep_by_speed() - configures the given endpoint - * according to gadget speed. - * @g: pointer to the gadget - * @f: usb function - * @_ep: the endpoint to configure - * - * Return: error code, 0 on success - * - * This function chooses the right descriptors for a given - * endpoint according to gadget speed and saves it in the - * endpoint desc field. If the endpoint already has a descriptor - * assigned to it - overwrites it with currently corresponding - * descriptor. The endpoint maxpacket field is updated according - * to the chosen descriptor. - * Note: the supplied function should hold all the descriptors - * for supported speeds - */ -int config_ep_by_speed(struct usb_gadget *g, - struct usb_function *f, - struct usb_ep *_ep) -{ - struct usb_endpoint_descriptor *chosen_desc = NULL; - struct usb_descriptor_header **speed_desc = NULL; - - struct usb_ss_ep_comp_descriptor *comp_desc = NULL; - int want_comp_desc = 0; - - struct usb_descriptor_header **d_spd; /* cursor for speed desc */ - - if (!g || !f || !_ep) - return -EIO; - - /* select desired speed */ - switch (g->speed) { - case USB_SPEED_SUPER: - if (gadget_is_superspeed(g)) { - speed_desc = f->ss_descriptors; - want_comp_desc = 1; - break; - } - /* else: Fall trough */ - case USB_SPEED_HIGH: - if (gadget_is_dualspeed(g)) { - speed_desc = f->hs_descriptors; - break; - } - /* else: fall through */ - default: - speed_desc = f->descriptors; - } - /* find descriptors */ - for_each_ep_desc(speed_desc, d_spd) { - chosen_desc = (struct usb_endpoint_descriptor *)*d_spd; - if (chosen_desc->bEndpointAddress == _ep->address) - goto ep_found; - } - return -EIO; - -ep_found: - /* commit results */ - _ep->maxpacket = usb_endpoint_maxp(chosen_desc); - _ep->desc = chosen_desc; - _ep->comp_desc = NULL; - _ep->maxburst = 0; - _ep->mult = 0; - if (!want_comp_desc) - return 0; - - /* - * Companion descriptor should follow EP descriptor - * USB 3.0 spec, #9.6.7 - */ - comp_desc = (struct usb_ss_ep_comp_descriptor *)*(++d_spd); - if (!comp_desc || - (comp_desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP)) - return -EIO; - _ep->comp_desc = comp_desc; - if (g->speed == USB_SPEED_SUPER) { - switch (usb_endpoint_type(_ep->desc)) { - case USB_ENDPOINT_XFER_ISOC: - /* mult: bits 1:0 of bmAttributes */ - _ep->mult = comp_desc->bmAttributes & 0x3; - case USB_ENDPOINT_XFER_BULK: - case USB_ENDPOINT_XFER_INT: - _ep->maxburst = comp_desc->bMaxBurst; - break; - default: - /* Do nothing for control endpoints */ - break; - } - } - return 0; -} - -/** - * usb_add_function() - add a function to a configuration - * @config: the configuration - * @function: the function being added - * Context: single threaded during gadget setup - * - * After initialization, each configuration must have one or more - * functions added to it. Adding a function involves calling its @bind() - * method to allocate resources such as interface and string identifiers - * and endpoints. - * - * This function returns the value of the function's bind(), which is - * zero for success else a negative errno value. - */ -int usb_add_function(struct usb_configuration *config, - struct usb_function *function) -{ - int value = -EINVAL; - - DBG(config->cdev, "adding '%s'/%p to config '%s'/%p\n", - function->name, function, - config->label, config); - - if (!function->set_alt || !function->disable) - goto done; - - function->config = config; - list_add_tail(&function->list, &config->functions); - - /* REVISIT *require* function->bind? */ - if (function->bind) { - value = function->bind(config, function); - if (value < 0) { - list_del(&function->list); - function->config = NULL; - } - } else - value = 0; - - /* We allow configurations that don't work at both speeds. - * If we run into a lowspeed Linux system, treat it the same - * as full speed ... it's the function drivers that will need - * to avoid bulk and ISO transfers. - */ - if (!config->fullspeed && function->descriptors) - config->fullspeed = true; - if (!config->highspeed && function->hs_descriptors) - config->highspeed = true; - if (!config->superspeed && function->ss_descriptors) - config->superspeed = true; - -done: - if (value) - DBG(config->cdev, "adding '%s'/%p --> %d\n", - function->name, function, value); - return value; -} - -/** - * usb_function_deactivate - prevent function and gadget enumeration - * @function: the function that isn't yet ready to respond - * - * Blocks response of the gadget driver to host enumeration by - * preventing the data line pullup from being activated. This is - * normally called during @bind() processing to change from the - * initial "ready to respond" state, or when a required resource - * becomes available. - * - * For example, drivers that serve as a passthrough to a userspace - * daemon can block enumeration unless that daemon (such as an OBEX, - * MTP, or print server) is ready to handle host requests. - * - * Not all systems support software control of their USB peripheral - * data pullups. - * - * Returns zero on success, else negative errno. - */ -int usb_function_deactivate(struct usb_function *function) -{ - struct usb_composite_dev *cdev = function->config->cdev; - unsigned long flags; - int status = 0; - - spin_lock_irqsave(&cdev->lock, flags); - - if (cdev->deactivations == 0) - status = usb_gadget_disconnect(cdev->gadget); - if (status == 0) - cdev->deactivations++; - - spin_unlock_irqrestore(&cdev->lock, flags); - return status; -} - -/** - * usb_function_activate - allow function and gadget enumeration - * @function: function on which usb_function_activate() was called - * - * Reverses effect of usb_function_deactivate(). If no more functions - * are delaying their activation, the gadget driver will respond to - * host enumeration procedures. - * - * Returns zero on success, else negative errno. - */ -int usb_function_activate(struct usb_function *function) -{ - struct usb_composite_dev *cdev = function->config->cdev; - int status = 0; - - spin_lock(&cdev->lock); - - if (WARN_ON(cdev->deactivations == 0)) - status = -EINVAL; - else { - cdev->deactivations--; - if (cdev->deactivations == 0) - status = usb_gadget_connect(cdev->gadget); - } - - spin_unlock(&cdev->lock); - return status; -} - -/** - * usb_interface_id() - allocate an unused interface ID - * @config: configuration associated with the interface - * @function: function handling the interface - * Context: single threaded during gadget setup - * - * usb_interface_id() is called from usb_function.bind() callbacks to - * allocate new interface IDs. The function driver will then store that - * ID in interface, association, CDC union, and other descriptors. It - * will also handle any control requests targeted at that interface, - * particularly changing its altsetting via set_alt(). There may - * also be class-specific or vendor-specific requests to handle. - * - * All interface identifier should be allocated using this routine, to - * ensure that for example different functions don't wrongly assign - * different meanings to the same identifier. Note that since interface - * identifiers are configuration-specific, functions used in more than - * one configuration (or more than once in a given configuration) need - * multiple versions of the relevant descriptors. - * - * Returns the interface ID which was allocated; or -ENODEV if no - * more interface IDs can be allocated. - */ -int usb_interface_id(struct usb_configuration *config, - struct usb_function *function) -{ - unsigned id = config->next_interface_id; - - if (id < MAX_CONFIG_INTERFACES) { - config->interface[id] = function; - config->next_interface_id = id + 1; - return id; - } - return -ENODEV; -} - -static int config_buf(struct usb_configuration *config, - enum usb_device_speed speed, void *buf, u8 type) -{ - struct usb_config_descriptor *c = buf; - void *next = buf + USB_DT_CONFIG_SIZE; - int len = USB_BUFSIZ - USB_DT_CONFIG_SIZE; - struct usb_function *f; - int status; - - /* write the config descriptor */ - c = buf; - c->bLength = USB_DT_CONFIG_SIZE; - c->bDescriptorType = type; - /* wTotalLength is written later */ - c->bNumInterfaces = config->next_interface_id; - c->bConfigurationValue = config->bConfigurationValue; - c->iConfiguration = config->iConfiguration; - c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes; - c->bMaxPower = config->bMaxPower ? : (CONFIG_USB_GADGET_VBUS_DRAW / 2); - - /* There may be e.g. OTG descriptors */ - if (config->descriptors) { - status = usb_descriptor_fillbuf(next, len, - config->descriptors); - if (status < 0) - return status; - len -= status; - next += status; - } - - /* add each function's descriptors */ - list_for_each_entry(f, &config->functions, list) { - struct usb_descriptor_header **descriptors; - - switch (speed) { - case USB_SPEED_SUPER: - descriptors = f->ss_descriptors; - break; - case USB_SPEED_HIGH: - descriptors = f->hs_descriptors; - break; - default: - descriptors = f->descriptors; - } - - if (!descriptors) - continue; - status = usb_descriptor_fillbuf(next, len, - (const struct usb_descriptor_header **) descriptors); - if (status < 0) - return status; - len -= status; - next += status; - } - - len = next - buf; - c->wTotalLength = cpu_to_le16(len); - return len; -} - -static int config_desc(struct usb_composite_dev *cdev, unsigned w_value) -{ - struct usb_gadget *gadget = cdev->gadget; - struct usb_configuration *c; - u8 type = w_value >> 8; - enum usb_device_speed speed = USB_SPEED_UNKNOWN; - - if (gadget->speed == USB_SPEED_SUPER) - speed = gadget->speed; - else if (gadget_is_dualspeed(gadget)) { - int hs = 0; - if (gadget->speed == USB_SPEED_HIGH) - hs = 1; - if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; - if (hs) - speed = USB_SPEED_HIGH; - - } - - /* This is a lookup by config *INDEX* */ - w_value &= 0xff; - list_for_each_entry(c, &cdev->configs, list) { - /* ignore configs that won't work at this speed */ - switch (speed) { - case USB_SPEED_SUPER: - if (!c->superspeed) - continue; - break; - case USB_SPEED_HIGH: - if (!c->highspeed) - continue; - break; - default: - if (!c->fullspeed) - continue; - } - - if (w_value == 0) - return config_buf(c, speed, cdev->req->buf, type); - w_value--; - } - return -EINVAL; -} - -static int count_configs(struct usb_composite_dev *cdev, unsigned type) -{ - struct usb_gadget *gadget = cdev->gadget; - struct usb_configuration *c; - unsigned count = 0; - int hs = 0; - int ss = 0; - - if (gadget_is_dualspeed(gadget)) { - if (gadget->speed == USB_SPEED_HIGH) - hs = 1; - if (gadget->speed == USB_SPEED_SUPER) - ss = 1; - if (type == USB_DT_DEVICE_QUALIFIER) - hs = !hs; - } - list_for_each_entry(c, &cdev->configs, list) { - /* ignore configs that won't work at this speed */ - if (ss) { - if (!c->superspeed) - continue; - } else if (hs) { - if (!c->highspeed) - continue; - } else { - if (!c->fullspeed) - continue; - } - count++; - } - return count; -} - -/** - * bos_desc() - prepares the BOS descriptor. - * @cdev: pointer to usb_composite device to generate the bos - * descriptor for - * - * This function generates the BOS (Binary Device Object) - * descriptor and its device capabilities descriptors. The BOS - * descriptor should be supported by a SuperSpeed device. - */ -static int bos_desc(struct usb_composite_dev *cdev) -{ - struct usb_ext_cap_descriptor *usb_ext; - struct usb_ss_cap_descriptor *ss_cap; - struct usb_dcd_config_params dcd_config_params; - struct usb_bos_descriptor *bos = cdev->req->buf; - - bos->bLength = USB_DT_BOS_SIZE; - bos->bDescriptorType = USB_DT_BOS; - - bos->wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE); - bos->bNumDeviceCaps = 0; - - /* - * A SuperSpeed device shall include the USB2.0 extension descriptor - * and shall support LPM when operating in USB2.0 HS mode. - */ - usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength); - bos->bNumDeviceCaps++; - le16_add_cpu(&bos->wTotalLength, USB_DT_USB_EXT_CAP_SIZE); - usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE; - usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY; - usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT; - usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT); - - /* - * The Superspeed USB Capability descriptor shall be implemented by all - * SuperSpeed devices. - */ - ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength); - bos->bNumDeviceCaps++; - le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE); - ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE; - ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY; - ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE; - ss_cap->bmAttributes = 0; /* LTM is not supported yet */ - ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION | - USB_FULL_SPEED_OPERATION | - USB_HIGH_SPEED_OPERATION | - USB_5GBPS_OPERATION); - ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION; - - /* Get Controller configuration */ - if (cdev->gadget->ops->get_config_params) - cdev->gadget->ops->get_config_params(&dcd_config_params); - else { - dcd_config_params.bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT; - dcd_config_params.bU2DevExitLat = - cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT); - } - ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat; - ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat; - - return le16_to_cpu(bos->wTotalLength); -} - -static void device_qual(struct usb_composite_dev *cdev) -{ - struct usb_qualifier_descriptor *qual = cdev->req->buf; - - qual->bLength = sizeof(*qual); - qual->bDescriptorType = USB_DT_DEVICE_QUALIFIER; - /* POLICY: same bcdUSB and device type info at both speeds */ - qual->bcdUSB = cdev->desc.bcdUSB; - qual->bDeviceClass = cdev->desc.bDeviceClass; - qual->bDeviceSubClass = cdev->desc.bDeviceSubClass; - qual->bDeviceProtocol = cdev->desc.bDeviceProtocol; - /* ASSUME same EP0 fifo size at both speeds */ - qual->bMaxPacketSize0 = cdev->gadget->ep0->maxpacket; - qual->bNumConfigurations = count_configs(cdev, USB_DT_DEVICE_QUALIFIER); - qual->bRESERVED = 0; -} - -/*-------------------------------------------------------------------------*/ - -static void reset_config(struct usb_composite_dev *cdev) -{ - struct usb_function *f; - - DBG(cdev, "reset config\n"); - - list_for_each_entry(f, &cdev->config->functions, list) { - if (f->disable) - f->disable(f); - - bitmap_zero(f->endpoints, 32); - } - cdev->config = NULL; -} - -static int set_config(struct usb_composite_dev *cdev, - const struct usb_ctrlrequest *ctrl, unsigned number) -{ - struct usb_gadget *gadget = cdev->gadget; - struct usb_configuration *c = NULL; - int result = -EINVAL; - unsigned power = gadget_is_otg(gadget) ? 8 : 100; - int tmp; - - if (number) { - list_for_each_entry(c, &cdev->configs, list) { - if (c->bConfigurationValue == number) { - /* - * We disable the FDs of the previous - * configuration only if the new configuration - * is a valid one - */ - if (cdev->config) - reset_config(cdev); - result = 0; - break; - } - } - if (result < 0) - goto done; - } else { /* Zero configuration value - need to reset the config */ - if (cdev->config) - reset_config(cdev); - result = 0; - } - - INFO(cdev, "%s config #%d: %s\n", - usb_speed_string(gadget->speed), - number, c ? c->label : "unconfigured"); - - if (!c) - goto done; - - cdev->config = c; - - /* Initialize all interfaces by setting them to altsetting zero. */ - for (tmp = 0; tmp < MAX_CONFIG_INTERFACES; tmp++) { - struct usb_function *f = c->interface[tmp]; - struct usb_descriptor_header **descriptors; - - if (!f) - break; - - /* - * Record which endpoints are used by the function. This is used - * to dispatch control requests targeted at that endpoint to the - * function's setup callback instead of the current - * configuration's setup callback. - */ - switch (gadget->speed) { - case USB_SPEED_SUPER: - descriptors = f->ss_descriptors; - break; - case USB_SPEED_HIGH: - descriptors = f->hs_descriptors; - break; - default: - descriptors = f->descriptors; - } - - for (; *descriptors; ++descriptors) { - struct usb_endpoint_descriptor *ep; - int addr; - - if ((*descriptors)->bDescriptorType != USB_DT_ENDPOINT) - continue; - - ep = (struct usb_endpoint_descriptor *)*descriptors; - addr = ((ep->bEndpointAddress & 0x80) >> 3) - | (ep->bEndpointAddress & 0x0f); - set_bit(addr, f->endpoints); - } - - result = f->set_alt(f, tmp, 0); - if (result < 0) { - DBG(cdev, "interface %d (%s/%p) alt 0 --> %d\n", - tmp, f->name, f, result); - - reset_config(cdev); - goto done; - } - - if (result == USB_GADGET_DELAYED_STATUS) { - DBG(cdev, - "%s: interface %d (%s) requested delayed status\n", - __func__, tmp, f->name); - cdev->delayed_status++; - DBG(cdev, "delayed_status count %d\n", - cdev->delayed_status); - } - } - - /* when we return, be sure our power usage is valid */ - power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW; -done: - usb_gadget_vbus_draw(gadget, power); - if (result >= 0 && cdev->delayed_status) - result = USB_GADGET_DELAYED_STATUS; - return result; -} - -/** - * usb_add_config() - add a configuration to a device. - * @cdev: wraps the USB gadget - * @config: the configuration, with bConfigurationValue assigned - * @bind: the configuration's bind function - * Context: single threaded during gadget setup - * - * One of the main tasks of a composite @bind() routine is to - * add each of the configurations it supports, using this routine. - * - * This function returns the value of the configuration's @bind(), which - * is zero for success else a negative errno value. Binding configurations - * assigns global resources including string IDs, and per-configuration - * resources such as interface IDs and endpoints. - */ -int usb_add_config(struct usb_composite_dev *cdev, - struct usb_configuration *config, - int (*bind)(struct usb_configuration *)) -{ - int status = -EINVAL; - struct usb_configuration *c; - - DBG(cdev, "adding config #%u '%s'/%p\n", - config->bConfigurationValue, - config->label, config); - - if (!config->bConfigurationValue || !bind) - goto done; - - /* Prevent duplicate configuration identifiers */ - list_for_each_entry(c, &cdev->configs, list) { - if (c->bConfigurationValue == config->bConfigurationValue) { - status = -EBUSY; - goto done; - } - } - - config->cdev = cdev; - list_add_tail(&config->list, &cdev->configs); - - INIT_LIST_HEAD(&config->functions); - config->next_interface_id = 0; - memset(config->interface, 0, sizeof(config->interface)); - - status = bind(config); - if (status < 0) { - list_del(&config->list); - config->cdev = NULL; - } else { - unsigned i; - - DBG(cdev, "cfg %d/%p speeds:%s%s%s\n", - config->bConfigurationValue, config, - config->superspeed ? " super" : "", - config->highspeed ? " high" : "", - config->fullspeed - ? (gadget_is_dualspeed(cdev->gadget) - ? " full" - : " full/low") - : ""); - - for (i = 0; i < MAX_CONFIG_INTERFACES; i++) { - struct usb_function *f = config->interface[i]; - - if (!f) - continue; - DBG(cdev, " interface %d = %s/%p\n", - i, f->name, f); - } - } - - /* set_alt(), or next bind(), sets up - * ep->driver_data as needed. - */ - usb_ep_autoconfig_reset(cdev->gadget); - -done: - if (status) - DBG(cdev, "added config '%s'/%u --> %d\n", config->label, - config->bConfigurationValue, status); - return status; -} - -static int unbind_config(struct usb_composite_dev *cdev, - struct usb_configuration *config) -{ - while (!list_empty(&config->functions)) { - struct usb_function *f; - - f = list_first_entry(&config->functions, - struct usb_function, list); - list_del(&f->list); - if (f->unbind) { - DBG(cdev, "unbind function '%s'/%p\n", f->name, f); - f->unbind(config, f); - /* may free memory for "f" */ - } - } - if (config->unbind) { - DBG(cdev, "unbind config '%s'/%p\n", config->label, config); - config->unbind(config); - /* may free memory for "c" */ - } - return 0; -} - -extern void wmt_cleanup_done_thread(int number); -/** - * usb_remove_config() - remove a configuration from a device. - * @cdev: wraps the USB gadget - * @config: the configuration - * - * Drivers must call usb_gadget_disconnect before calling this function - * to disconnect the device from the host and make sure the host will not - * try to enumerate the device while we are changing the config list. - */ -int usb_remove_config(struct usb_composite_dev *cdev, - struct usb_configuration *config) -{ - unsigned long flags; - //wmt_cleanup_done_thread(1); - spin_lock_irqsave(&cdev->lock, flags); - if (cdev->config == config) - reset_config(cdev); - - list_del(&config->list); - - spin_unlock_irqrestore(&cdev->lock, flags); - return unbind_config(cdev, config); -} - -/*-------------------------------------------------------------------------*/ - -/* We support strings in multiple languages ... string descriptor zero - * says which languages are supported. The typical case will be that - * only one language (probably English) is used, with I18N handled on - * the host side. - */ - -static void collect_langs(struct usb_gadget_strings **sp, __le16 *buf) -{ - const struct usb_gadget_strings *s; - u16 language; - __le16 *tmp; - - while (*sp) { - s = *sp; - language = cpu_to_le16(s->language); - for (tmp = buf; *tmp && tmp < &buf[126]; tmp++) { - if (*tmp == language) - goto repeat; - } - *tmp++ = language; -repeat: - sp++; - } -} - -static int lookup_string( - struct usb_gadget_strings **sp, - void *buf, - u16 language, - int id -) -{ - struct usb_gadget_strings *s; - int value; - - while (*sp) { - s = *sp++; - if (s->language != language) - continue; - value = usb_gadget_get_string(s, id, buf); - if (value > 0) - return value; - } - return -EINVAL; -} - -static int get_string(struct usb_composite_dev *cdev, - void *buf, u16 language, int id) -{ - struct usb_configuration *c; - struct usb_function *f; - int len; - const char *str; - - /* Yes, not only is USB's I18N support probably more than most - * folk will ever care about ... also, it's all supported here. - * (Except for UTF8 support for Unicode's "Astral Planes".) - */ - - /* 0 == report all available language codes */ - if (id == 0) { - struct usb_string_descriptor *s = buf; - struct usb_gadget_strings **sp; - - memset(s, 0, 256); - s->bDescriptorType = USB_DT_STRING; - - sp = composite->strings; - if (sp) - collect_langs(sp, s->wData); - - list_for_each_entry(c, &cdev->configs, list) { - sp = c->strings; - if (sp) - collect_langs(sp, s->wData); - - list_for_each_entry(f, &c->functions, list) { - sp = f->strings; - if (sp) - collect_langs(sp, s->wData); - } - } - - for (len = 0; len <= 126 && s->wData[len]; len++) - continue; - if (!len) - return -EINVAL; - - s->bLength = 2 * (len + 1); - return s->bLength; - } - - /* Otherwise, look up and return a specified string. First - * check if the string has not been overridden. - */ - if (cdev->manufacturer_override == id) - str = iManufacturer ?: composite->iManufacturer ?: - composite_manufacturer; - else if (cdev->product_override == id) - str = iProduct ?: composite->iProduct; - else if (cdev->serial_override == id) - str = iSerialNumber; - else - str = NULL; - if (str) { - struct usb_gadget_strings strings = { - .language = language, - .strings = &(struct usb_string) { 0xff, str } - }; - return usb_gadget_get_string(&strings, 0xff, buf); - } - - /* String IDs are device-scoped, so we look up each string - * table we're told about. These lookups are infrequent; - * simpler-is-better here. - */ - if (composite->strings) { - len = lookup_string(composite->strings, buf, language, id); - if (len > 0) - return len; - } - list_for_each_entry(c, &cdev->configs, list) { - if (c->strings) { - len = lookup_string(c->strings, buf, language, id); - if (len > 0) - return len; - } - list_for_each_entry(f, &c->functions, list) { - if (!f->strings) - continue; - len = lookup_string(f->strings, buf, language, id); - if (len > 0) - return len; - } - } - return -EINVAL; -} - -/** - * usb_string_id() - allocate an unused string ID - * @cdev: the device whose string descriptor IDs are being allocated - * Context: single threaded during gadget setup - * - * @usb_string_id() is called from bind() callbacks to allocate - * string IDs. Drivers for functions, configurations, or gadgets will - * then store that ID in the appropriate descriptors and string table. - * - * All string identifier should be allocated using this, - * @usb_string_ids_tab() or @usb_string_ids_n() routine, to ensure - * that for example different functions don't wrongly assign different - * meanings to the same identifier. - */ -int usb_string_id(struct usb_composite_dev *cdev) -{ - if (cdev->next_string_id < 254) { - /* string id 0 is reserved by USB spec for list of - * supported languages */ - /* 255 reserved as well? -- mina86 */ - cdev->next_string_id++; - return cdev->next_string_id; - } - return -ENODEV; -} - -/** - * usb_string_ids() - allocate unused string IDs in batch - * @cdev: the device whose string descriptor IDs are being allocated - * @str: an array of usb_string objects to assign numbers to - * Context: single threaded during gadget setup - * - * @usb_string_ids() is called from bind() callbacks to allocate - * string IDs. Drivers for functions, configurations, or gadgets will - * then copy IDs from the string table to the appropriate descriptors - * and string table for other languages. - * - * All string identifier should be allocated using this, - * @usb_string_id() or @usb_string_ids_n() routine, to ensure that for - * example different functions don't wrongly assign different meanings - * to the same identifier. - */ -int usb_string_ids_tab(struct usb_composite_dev *cdev, struct usb_string *str) -{ - int next = cdev->next_string_id; - - for (; str->s; ++str) { - if (unlikely(next >= 254)) - return -ENODEV; - str->id = ++next; - } - - cdev->next_string_id = next; - - return 0; -} - -/** - * usb_string_ids_n() - allocate unused string IDs in batch - * @c: the device whose string descriptor IDs are being allocated - * @n: number of string IDs to allocate - * Context: single threaded during gadget setup - * - * Returns the first requested ID. This ID and next @n-1 IDs are now - * valid IDs. At least provided that @n is non-zero because if it - * is, returns last requested ID which is now very useful information. - * - * @usb_string_ids_n() is called from bind() callbacks to allocate - * string IDs. Drivers for functions, configurations, or gadgets will - * then store that ID in the appropriate descriptors and string table. - * - * All string identifier should be allocated using this, - * @usb_string_id() or @usb_string_ids_n() routine, to ensure that for - * example different functions don't wrongly assign different meanings - * to the same identifier. - */ -int usb_string_ids_n(struct usb_composite_dev *c, unsigned n) -{ - unsigned next = c->next_string_id; - if (unlikely(n > 254 || (unsigned)next + n > 254)) - return -ENODEV; - c->next_string_id += n; - return next + 1; -} - - -/*-------------------------------------------------------------------------*/ - -static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req) -{ - if (req->status || req->actual != req->length) - DBG((struct usb_composite_dev *) ep->driver_data, - "setup complete --> %d, %d/%d\n", - req->status, req->actual, req->length); -} - -/* - * The setup() callback implements all the ep0 functionality that's - * not handled lower down, in hardware or the hardware driver(like - * device and endpoint feature flags, and their status). It's all - * housekeeping for the gadget function we're implementing. Most of - * the work is in config and function specific setup. - */ -static int -composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) -{ - struct usb_composite_dev *cdev = get_gadget_data(gadget); - struct usb_request *req = cdev->req; - int value = -EOPNOTSUPP; - int status = 0; - u16 w_index = le16_to_cpu(ctrl->wIndex); - u8 intf = w_index & 0xFF; - u16 w_value = le16_to_cpu(ctrl->wValue); - u16 w_length = le16_to_cpu(ctrl->wLength); - struct usb_function *f = NULL; - u8 endp; - - /* partial re-init of the response message; the function or the - * gadget might need to intercept e.g. a control-OUT completion - * when we delegate to it. - */ - req->zero = 0; - req->complete = composite_setup_complete; - req->length = 0; - gadget->ep0->driver_data = cdev; - - switch (ctrl->bRequest) { - - /* we handle all standard USB descriptors */ - case USB_REQ_GET_DESCRIPTOR: - if (ctrl->bRequestType != USB_DIR_IN) - goto unknown; - switch (w_value >> 8) { - - case USB_DT_DEVICE: - cdev->desc.bNumConfigurations = - count_configs(cdev, USB_DT_DEVICE); - cdev->desc.bMaxPacketSize0 = - cdev->gadget->ep0->maxpacket; - if (gadget_is_superspeed(gadget)) { - if (gadget->speed >= USB_SPEED_SUPER) { - cdev->desc.bcdUSB = cpu_to_le16(0x0300); - cdev->desc.bMaxPacketSize0 = 9; - } else { - cdev->desc.bcdUSB = cpu_to_le16(0x0210); - } - } - - value = min(w_length, (u16) sizeof cdev->desc); - memcpy(req->buf, &cdev->desc, value); - break; - case USB_DT_DEVICE_QUALIFIER: - if (!gadget_is_dualspeed(gadget) || - gadget->speed >= USB_SPEED_SUPER) - break; - device_qual(cdev); - value = min_t(int, w_length, - sizeof(struct usb_qualifier_descriptor)); - break; - case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget_is_dualspeed(gadget) || - gadget->speed >= USB_SPEED_SUPER) - break; - /* FALLTHROUGH */ - case USB_DT_CONFIG: - value = config_desc(cdev, w_value); - if (value >= 0) - value = min(w_length, (u16) value); - break; - case USB_DT_STRING: - value = get_string(cdev, req->buf, - w_index, w_value & 0xff); - if (value >= 0) - value = min(w_length, (u16) value); - break; - case USB_DT_BOS: - if (gadget_is_superspeed(gadget)) { - value = bos_desc(cdev); - value = min(w_length, (u16) value); - } - break; - } - break; - - /* any number of configs can work */ - case USB_REQ_SET_CONFIGURATION: - if (ctrl->bRequestType != 0) - goto unknown; - if (gadget_is_otg(gadget)) { - if (gadget->a_hnp_support) - DBG(cdev, "HNP available\n"); - else if (gadget->a_alt_hnp_support) - DBG(cdev, "HNP on another port\n"); - else - VDBG(cdev, "HNP inactive\n"); - } - spin_lock(&cdev->lock); - value = set_config(cdev, ctrl, w_value); - spin_unlock(&cdev->lock); - break; - case USB_REQ_GET_CONFIGURATION: - if (ctrl->bRequestType != USB_DIR_IN) - goto unknown; - if (cdev->config) - *(u8 *)req->buf = cdev->config->bConfigurationValue; - else - *(u8 *)req->buf = 0; - value = min(w_length, (u16) 1); - break; - - /* function drivers must handle get/set altsetting; if there's - * no get() method, we know only altsetting zero works. - */ - case USB_REQ_SET_INTERFACE: - if (ctrl->bRequestType != USB_RECIP_INTERFACE) - goto unknown; - if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) - break; - f = cdev->config->interface[intf]; - if (!f) - break; - if (w_value && !f->set_alt) - break; - value = f->set_alt(f, w_index, w_value); - if (value == USB_GADGET_DELAYED_STATUS) { - DBG(cdev, - "%s: interface %d (%s) requested delayed status\n", - __func__, intf, f->name); - cdev->delayed_status++; - DBG(cdev, "delayed_status count %d\n", - cdev->delayed_status); - } - break; - case USB_REQ_GET_INTERFACE: - if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) - goto unknown; - if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) - break; - f = cdev->config->interface[intf]; - if (!f) - break; - /* lots of interfaces only need altsetting zero... */ - value = f->get_alt ? f->get_alt(f, w_index) : 0; - if (value < 0) - break; - *((u8 *)req->buf) = value; - value = min(w_length, (u16) 1); - break; - - /* - * USB 3.0 additions: - * Function driver should handle get_status request. If such cb - * wasn't supplied we respond with default value = 0 - * Note: function driver should supply such cb only for the first - * interface of the function - */ - case USB_REQ_GET_STATUS: - if (!gadget_is_superspeed(gadget)) - goto unknown; - if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE)) - goto unknown; - value = 2; /* This is the length of the get_status reply */ - put_unaligned_le16(0, req->buf); - if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) - break; - f = cdev->config->interface[intf]; - if (!f) - break; - status = f->get_status ? f->get_status(f) : 0; - if (status < 0) - break; - put_unaligned_le16(status & 0x0000ffff, req->buf); - break; - /* - * Function drivers should handle SetFeature/ClearFeature - * (FUNCTION_SUSPEND) request. function_suspend cb should be supplied - * only for the first interface of the function - */ - case USB_REQ_CLEAR_FEATURE: - case USB_REQ_SET_FEATURE: - if (!gadget_is_superspeed(gadget)) - goto unknown; - if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE)) - goto unknown; - switch (w_value) { - case USB_INTRF_FUNC_SUSPEND: - if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) - break; - f = cdev->config->interface[intf]; - if (!f) - break; - value = 0; - if (f->func_suspend) - value = f->func_suspend(f, w_index >> 8); - if (value < 0) { - ERROR(cdev, - "func_suspend() returned error %d\n", - value); - value = 0; - } - break; - } - break; - default: -unknown: - VDBG(cdev, - "non-core control req%02x.%02x v%04x i%04x l%d\n", - ctrl->bRequestType, ctrl->bRequest, - w_value, w_index, w_length); - - /* functions always handle their interfaces and endpoints... - * punt other recipients (other, WUSB, ...) to the current - * configuration code. - * - * REVISIT it could make sense to let the composite device - * take such requests too, if that's ever needed: to work - * in config 0, etc. - */ - switch (ctrl->bRequestType & USB_RECIP_MASK) { - case USB_RECIP_INTERFACE: - if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) - break; - f = cdev->config->interface[intf]; - break; - - case USB_RECIP_ENDPOINT: - endp = ((w_index & 0x80) >> 3) | (w_index & 0x0f); - list_for_each_entry(f, &cdev->config->functions, list) { - if (test_bit(endp, f->endpoints)) - break; - } - if (&f->list == &cdev->config->functions) - f = NULL; - break; - } - - if (f && f->setup) - value = f->setup(f, ctrl); - else { - struct usb_configuration *c; - - c = cdev->config; - if (c && c->setup) - value = c->setup(c, ctrl); - } - - goto done; - } - - /* respond with data transfer before status phase? */ - if (value >= 0 && value != USB_GADGET_DELAYED_STATUS) { - req->length = value; - req->zero = value < w_length; - value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); - if (value < 0) { - DBG(cdev, "ep_queue --> %d\n", value); - req->status = 0; - composite_setup_complete(gadget->ep0, req); - } - } else if (value == USB_GADGET_DELAYED_STATUS && w_length != 0) { - WARN(cdev, - "%s: Delayed status not supported for w_length != 0", - __func__); - } - -done: - /* device either stalls (value < 0) or reports success */ - return value; -} - -static void composite_disconnect(struct usb_gadget *gadget) -{ - struct usb_composite_dev *cdev = get_gadget_data(gadget); - unsigned long flags; - - /* REVISIT: should we have config and device level - * disconnect callbacks? - */ - spin_lock_irqsave(&cdev->lock, flags); - if (cdev->config) - reset_config(cdev); - if (composite->disconnect) - composite->disconnect(cdev); - spin_unlock_irqrestore(&cdev->lock, flags); -} - -/*-------------------------------------------------------------------------*/ - -static ssize_t composite_show_suspended(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct usb_gadget *gadget = dev_to_usb_gadget(dev); - struct usb_composite_dev *cdev = get_gadget_data(gadget); - - return sprintf(buf, "%d\n", cdev->suspended); -} - -static DEVICE_ATTR(suspended, 0444, composite_show_suspended, NULL); - -static void -composite_unbind(struct usb_gadget *gadget) -{ - struct usb_composite_dev *cdev = get_gadget_data(gadget); - - /* composite_disconnect() must already have been called - * by the underlying peripheral controller driver! - * so there's no i/o concurrency that could affect the - * state protected by cdev->lock. - */ - WARN_ON(cdev->config); - - while (!list_empty(&cdev->configs)) { - struct usb_configuration *c; - c = list_first_entry(&cdev->configs, - struct usb_configuration, list); - list_del(&c->list); - unbind_config(cdev, c); - } - if (composite->unbind) - composite->unbind(cdev); - - if (cdev->req) { - kfree(cdev->req->buf); - usb_ep_free_request(gadget->ep0, cdev->req); - } - device_remove_file(&gadget->dev, &dev_attr_suspended); - kfree(cdev); - set_gadget_data(gadget, NULL); - composite = NULL; -} - -static u8 override_id(struct usb_composite_dev *cdev, u8 *desc) -{ - if (!*desc) { - int ret = usb_string_id(cdev); - if (unlikely(ret < 0)) - WARNING(cdev, "failed to override string ID\n"); - else - *desc = ret; - } - - return *desc; -} - -static int composite_bind(struct usb_gadget *gadget) -{ - struct usb_composite_dev *cdev; - int status = -ENOMEM; - - cdev = kzalloc(sizeof *cdev, GFP_KERNEL); - if (!cdev) - return status; - - spin_lock_init(&cdev->lock); - cdev->gadget = gadget; - set_gadget_data(gadget, cdev); - INIT_LIST_HEAD(&cdev->configs); - - /* preallocate control response and buffer */ - cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); - if (!cdev->req) - goto fail; - cdev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL); - if (!cdev->req->buf) - goto fail; - cdev->req->complete = composite_setup_complete; - gadget->ep0->driver_data = cdev; - - cdev->bufsiz = USB_BUFSIZ; - cdev->driver = composite; - - /* - * As per USB compliance update, a device that is actively drawing - * more than 100mA from USB must report itself as bus-powered in - * the GetStatus(DEVICE) call. - */ - if (CONFIG_USB_GADGET_VBUS_DRAW <= USB_SELF_POWER_VBUS_MAX_DRAW) - usb_gadget_set_selfpowered(gadget); - - /* interface and string IDs start at zero via kzalloc. - * we force endpoints to start unassigned; few controller - * drivers will zero ep->driver_data. - */ - usb_ep_autoconfig_reset(cdev->gadget); - - /* composite gadget needs to assign strings for whole device (like - * serial number), register function drivers, potentially update - * power state and consumption, etc - */ - status = composite_gadget_bind(cdev); - if (status < 0) - goto fail; - - cdev->desc = *composite->dev; - - /* standardized runtime overrides for device ID data */ - if (idVendor) - cdev->desc.idVendor = cpu_to_le16(idVendor); - if (idProduct) - cdev->desc.idProduct = cpu_to_le16(idProduct); - if (bcdDevice) - cdev->desc.bcdDevice = cpu_to_le16(bcdDevice); - - /* string overrides */ - if (iManufacturer || !cdev->desc.iManufacturer) { - if (!iManufacturer && !composite->iManufacturer && - !*composite_manufacturer) - snprintf(composite_manufacturer, - sizeof composite_manufacturer, - "%s %s with %s", - init_utsname()->sysname, - init_utsname()->release, - gadget->name); - - cdev->manufacturer_override = - override_id(cdev, &cdev->desc.iManufacturer); - } - - if (iProduct || (!cdev->desc.iProduct && composite->iProduct)) - cdev->product_override = - override_id(cdev, &cdev->desc.iProduct); - - if (iSerialNumber) - cdev->serial_override = - override_id(cdev, &cdev->desc.iSerialNumber); - - /* has userspace failed to provide a serial number? */ - if (composite->needs_serial && !cdev->desc.iSerialNumber) - WARNING(cdev, "userspace failed to provide iSerialNumber\n"); - - /* finish up */ - status = device_create_file(&gadget->dev, &dev_attr_suspended); - if (status) - goto fail; - - INFO(cdev, "%s ready\n", composite->name); - return 0; - -fail: - composite_unbind(gadget); - return status; -} - -/*-------------------------------------------------------------------------*/ - -static void -composite_suspend(struct usb_gadget *gadget) -{ - struct usb_composite_dev *cdev = get_gadget_data(gadget); - struct usb_function *f; - - /* REVISIT: should we have config level - * suspend/resume callbacks? - */ - DBG(cdev, "suspend\n"); - if (cdev->config) { - list_for_each_entry(f, &cdev->config->functions, list) { - if (f->suspend) - f->suspend(f); - } - } - if (composite->suspend) - composite->suspend(cdev); - - cdev->suspended = 1; - - usb_gadget_vbus_draw(gadget, 2); -} - -static void -composite_resume(struct usb_gadget *gadget) -{ - struct usb_composite_dev *cdev = get_gadget_data(gadget); - struct usb_function *f; - u8 maxpower; - - /* REVISIT: should we have config level - * suspend/resume callbacks? - */ - DBG(cdev, "resume\n"); - if (composite->resume) - composite->resume(cdev); - if (cdev->config) { - list_for_each_entry(f, &cdev->config->functions, list) { - if (f->resume) - f->resume(f); - } - - maxpower = cdev->config->bMaxPower; - - usb_gadget_vbus_draw(gadget, maxpower ? - (2 * maxpower) : CONFIG_USB_GADGET_VBUS_DRAW); - } - - cdev->suspended = 0; -} - -/*-------------------------------------------------------------------------*/ - -static struct usb_gadget_driver composite_driver = { -#ifdef CONFIG_USB_GADGET_SUPERSPEED - .max_speed = USB_SPEED_SUPER, -#else - .max_speed = USB_SPEED_HIGH, -#endif - - .unbind = composite_unbind, - - .setup = composite_setup, - .disconnect = composite_disconnect, - - .suspend = composite_suspend, - .resume = composite_resume, - - .driver = { - .owner = THIS_MODULE, - }, -}; - -/** - * usb_composite_probe() - register a composite driver - * @driver: the driver to register - * @bind: the callback used to allocate resources that are shared across the - * whole device, such as string IDs, and add its configurations using - * @usb_add_config(). This may fail by returning a negative errno - * value; it should return zero on successful initialization. - * Context: single threaded during gadget setup - * - * This function is used to register drivers using the composite driver - * framework. The return value is zero, or a negative errno value. - * Those values normally come from the driver's @bind method, which does - * all the work of setting up the driver to match the hardware. - * - * On successful return, the gadget is ready to respond to requests from - * the host, unless one of its components invokes usb_gadget_disconnect() - * while it was binding. That would usually be done in order to wait for - * some userspace participation. - */ -int usb_composite_probe(struct usb_composite_driver *driver, - int (*bind)(struct usb_composite_dev *cdev)) -{ - if (!driver || !driver->dev || !bind || composite) - return -EINVAL; - - if (!driver->name) - driver->name = "composite"; - if (!driver->iProduct) - driver->iProduct = driver->name; - composite_driver.function = (char *) driver->name; - composite_driver.driver.name = driver->name; - composite_driver.max_speed = - min_t(u8, composite_driver.max_speed, driver->max_speed); - composite = driver; - composite_gadget_bind = bind; - - return usb_gadget_probe_driver(&composite_driver, composite_bind); -} - -/** - * usb_composite_unregister() - unregister a composite driver - * @driver: the driver to unregister - * - * This function is used to unregister drivers using the composite - * driver framework. - */ -void usb_composite_unregister(struct usb_composite_driver *driver) -{ - if (composite != driver) - return; - usb_gadget_unregister_driver(&composite_driver); -} - -/** - * usb_composite_setup_continue() - Continue with the control transfer - * @cdev: the composite device who's control transfer was kept waiting - * - * This function must be called by the USB function driver to continue - * with the control transfer's data/status stage in case it had requested to - * delay the data/status stages. A USB function's setup handler (e.g. set_alt()) - * can request the composite framework to delay the setup request's data/status - * stages by returning USB_GADGET_DELAYED_STATUS. - */ -void usb_composite_setup_continue(struct usb_composite_dev *cdev) -{ - int value; - struct usb_request *req = cdev->req; - unsigned long flags; - - DBG(cdev, "%s\n", __func__); - spin_lock_irqsave(&cdev->lock, flags); - - if (cdev->delayed_status == 0) { - WARN(cdev, "%s: Unexpected call\n", __func__); - - } else if (--cdev->delayed_status == 0) { - DBG(cdev, "%s: Completing delayed status\n", __func__); - req->length = 0; - value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); - if (value < 0) { - DBG(cdev, "ep_queue --> %d\n", value); - req->status = 0; - composite_setup_complete(cdev->gadget->ep0, req); - } - } - - spin_unlock_irqrestore(&cdev->lock, flags); -} - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/config.c b/ANDROID_3.4.5/drivers/usb/gadget/config.c deleted file mode 100644 index 7542a72c..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/config.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * usb/gadget/config.c -- simplify building config descriptors - * - * Copyright (C) 2003 David Brownell - * - * 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 -#include -#include -#include -#include -#include - -#include -#include - - -/** - * usb_descriptor_fillbuf - fill buffer with descriptors - * @buf: Buffer to be filled - * @buflen: Size of buf - * @src: Array of descriptor pointers, terminated by null pointer. - * - * Copies descriptors into the buffer, returning the length or a - * negative error code if they can't all be copied. Useful when - * assembling descriptors for an associated set of interfaces used - * as part of configuring a composite device; or in other cases where - * sets of descriptors need to be marshaled. - */ -int -usb_descriptor_fillbuf(void *buf, unsigned buflen, - const struct usb_descriptor_header **src) -{ - u8 *dest = buf; - - if (!src) - return -EINVAL; - - /* fill buffer from src[] until null descriptor ptr */ - for (; NULL != *src; src++) { - unsigned len = (*src)->bLength; - - if (len > buflen) - return -EINVAL; - memcpy(dest, *src, len); - buflen -= len; - dest += len; - } - return dest - (u8 *)buf; -} - - -/** - * usb_gadget_config_buf - builts a complete configuration descriptor - * @config: Header for the descriptor, including characteristics such - * as power requirements and number of interfaces. - * @desc: Null-terminated vector of pointers to the descriptors (interface, - * endpoint, etc) defining all functions in this device configuration. - * @buf: Buffer for the resulting configuration descriptor. - * @length: Length of buffer. If this is not big enough to hold the - * entire configuration descriptor, an error code will be returned. - * - * This copies descriptors into the response buffer, building a descriptor - * for that configuration. It returns the buffer length or a negative - * status code. The config.wTotalLength field is set to match the length - * of the result, but other descriptor fields (including power usage and - * interface count) must be set by the caller. - * - * Gadget drivers could use this when constructing a config descriptor - * in response to USB_REQ_GET_DESCRIPTOR. They will need to patch the - * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed. - */ -int usb_gadget_config_buf( - const struct usb_config_descriptor *config, - void *buf, - unsigned length, - const struct usb_descriptor_header **desc -) -{ - struct usb_config_descriptor *cp = buf; - int len; - - /* config descriptor first */ - if (length < USB_DT_CONFIG_SIZE || !desc) - return -EINVAL; - *cp = *config; - - /* then interface/endpoint/class/vendor/... */ - len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8*)buf, - length - USB_DT_CONFIG_SIZE, desc); - if (len < 0) - return len; - len += USB_DT_CONFIG_SIZE; - if (len > 0xffff) - return -EINVAL; - - /* patch up the config descriptor */ - cp->bLength = USB_DT_CONFIG_SIZE; - cp->bDescriptorType = USB_DT_CONFIG; - cp->wTotalLength = cpu_to_le16(len); - cp->bmAttributes |= USB_CONFIG_ATT_ONE; - return len; -} - -/** - * usb_copy_descriptors - copy a vector of USB descriptors - * @src: null-terminated vector to copy - * Context: initialization code, which may sleep - * - * This makes a copy of a vector of USB descriptors. Its primary use - * is to support usb_function objects which can have multiple copies, - * each needing different descriptors. Functions may have static - * tables of descriptors, which are used as templates and customized - * with identifiers (for interfaces, strings, endpoints, and more) - * as needed by a given function instance. - */ -struct usb_descriptor_header ** -usb_copy_descriptors(struct usb_descriptor_header **src) -{ - struct usb_descriptor_header **tmp; - unsigned bytes; - unsigned n_desc; - void *mem; - struct usb_descriptor_header **ret; - - /* count descriptors and their sizes; then add vector size */ - for (bytes = 0, n_desc = 0, tmp = src; *tmp; tmp++, n_desc++) - bytes += (*tmp)->bLength; - bytes += (n_desc + 1) * sizeof(*tmp); - - mem = kmalloc(bytes, GFP_KERNEL); - if (!mem) - return NULL; - - /* fill in pointers starting at "tmp", - * to descriptors copied starting at "mem"; - * and return "ret" - */ - tmp = mem; - ret = mem; - mem += (n_desc + 1) * sizeof(*tmp); - while (*src) { - memcpy(mem, *src, (*src)->bLength); - *tmp = mem; - tmp++; - mem += (*src)->bLength; - src++; - } - *tmp = NULL; - - return ret; -} - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/dbgp.c b/ANDROID_3.4.5/drivers/usb/gadget/dbgp.c deleted file mode 100644 index 19d7bb0d..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/dbgp.c +++ /dev/null @@ -1,433 +0,0 @@ -/* - * dbgp.c -- EHCI Debug Port device gadget - * - * Copyright (C) 2010 Stephane Duverger - * - * Released under the GPLv2. - */ - -/* verbose messages */ -#include -#include -#include -#include -#include - -/* See comments in "zero.c" */ -#include "epautoconf.c" - -#ifdef CONFIG_USB_G_DBGP_SERIAL -#include "u_serial.c" -#endif - -#define DRIVER_VENDOR_ID 0x0525 /* NetChip */ -#define DRIVER_PRODUCT_ID 0xc0de /* undefined */ - -#define USB_DEBUG_MAX_PACKET_SIZE 8 -#define DBGP_REQ_EP0_LEN 128 -#define DBGP_REQ_LEN 512 - -static struct dbgp { - struct usb_gadget *gadget; - struct usb_request *req; - struct usb_ep *i_ep; - struct usb_ep *o_ep; -#ifdef CONFIG_USB_G_DBGP_SERIAL - struct gserial *serial; -#endif -} dbgp; - -static struct usb_device_descriptor device_desc = { - .bLength = sizeof device_desc, - .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = __constant_cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_VENDOR_SPEC, - .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_ID), - .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_ID), - .bNumConfigurations = 1, -}; - -static struct usb_debug_descriptor dbg_desc = { - .bLength = sizeof dbg_desc, - .bDescriptorType = USB_DT_DEBUG, -}; - -static struct usb_endpoint_descriptor i_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .bEndpointAddress = USB_DIR_IN, -}; - -static struct usb_endpoint_descriptor o_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .bEndpointAddress = USB_DIR_OUT, -}; - -#ifdef CONFIG_USB_G_DBGP_PRINTK -static int dbgp_consume(char *buf, unsigned len) -{ - char c; - - if (!len) - return 0; - - c = buf[len-1]; - if (c != 0) - buf[len-1] = 0; - - printk(KERN_NOTICE "%s%c", buf, c); - return 0; -} - -static void __disable_ep(struct usb_ep *ep) -{ - if (ep && ep->driver_data == dbgp.gadget) { - usb_ep_disable(ep); - ep->driver_data = NULL; - } -} - -static void dbgp_disable_ep(void) -{ - __disable_ep(dbgp.i_ep); - __disable_ep(dbgp.o_ep); -} - -static void dbgp_complete(struct usb_ep *ep, struct usb_request *req) -{ - int stp; - int err = 0; - int status = req->status; - - if (ep == dbgp.i_ep) { - stp = 1; - goto fail; - } - - if (status != 0) { - stp = 2; - goto release_req; - } - - dbgp_consume(req->buf, req->actual); - - req->length = DBGP_REQ_LEN; - err = usb_ep_queue(ep, req, GFP_ATOMIC); - if (err < 0) { - stp = 3; - goto release_req; - } - - return; - -release_req: - kfree(req->buf); - usb_ep_free_request(dbgp.o_ep, req); - dbgp_disable_ep(); -fail: - dev_dbg(&dbgp.gadget->dev, - "complete: failure (%d:%d) ==> %d\n", stp, err, status); -} - -static int dbgp_enable_ep_req(struct usb_ep *ep) -{ - int err, stp; - struct usb_request *req; - - req = usb_ep_alloc_request(ep, GFP_KERNEL); - if (!req) { - err = -ENOMEM; - stp = 1; - goto fail_1; - } - - req->buf = kmalloc(DBGP_REQ_LEN, GFP_KERNEL); - if (!req->buf) { - err = -ENOMEM; - stp = 2; - goto fail_2; - } - - req->complete = dbgp_complete; - req->length = DBGP_REQ_LEN; - err = usb_ep_queue(ep, req, GFP_ATOMIC); - if (err < 0) { - stp = 3; - goto fail_3; - } - - return 0; - -fail_3: - kfree(req->buf); -fail_2: - usb_ep_free_request(dbgp.o_ep, req); -fail_1: - dev_dbg(&dbgp.gadget->dev, - "enable ep req: failure (%d:%d)\n", stp, err); - return err; -} - -static int __enable_ep(struct usb_ep *ep, struct usb_endpoint_descriptor *desc) -{ - int err; - ep->desc = desc; - err = usb_ep_enable(ep); - ep->driver_data = dbgp.gadget; - return err; -} - -static int dbgp_enable_ep(void) -{ - int err, stp; - - err = __enable_ep(dbgp.i_ep, &i_desc); - if (err < 0) { - stp = 1; - goto fail_1; - } - - err = __enable_ep(dbgp.o_ep, &o_desc); - if (err < 0) { - stp = 2; - goto fail_2; - } - - err = dbgp_enable_ep_req(dbgp.o_ep); - if (err < 0) { - stp = 3; - goto fail_3; - } - - return 0; - -fail_3: - __disable_ep(dbgp.o_ep); -fail_2: - __disable_ep(dbgp.i_ep); -fail_1: - dev_dbg(&dbgp.gadget->dev, "enable ep: failure (%d:%d)\n", stp, err); - return err; -} -#endif - -static void dbgp_disconnect(struct usb_gadget *gadget) -{ -#ifdef CONFIG_USB_G_DBGP_PRINTK - dbgp_disable_ep(); -#else - gserial_disconnect(dbgp.serial); -#endif -} - -static void dbgp_unbind(struct usb_gadget *gadget) -{ -#ifdef CONFIG_USB_G_DBGP_SERIAL - kfree(dbgp.serial); -#endif - if (dbgp.req) { - kfree(dbgp.req->buf); - usb_ep_free_request(gadget->ep0, dbgp.req); - } - - gadget->ep0->driver_data = NULL; -} - -static int __init dbgp_configure_endpoints(struct usb_gadget *gadget) -{ - int stp; - - usb_ep_autoconfig_reset(gadget); - - dbgp.i_ep = usb_ep_autoconfig(gadget, &i_desc); - if (!dbgp.i_ep) { - stp = 1; - goto fail_1; - } - - dbgp.i_ep->driver_data = gadget; - i_desc.wMaxPacketSize = - __constant_cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE); - - dbgp.o_ep = usb_ep_autoconfig(gadget, &o_desc); - if (!dbgp.o_ep) { - dbgp.i_ep->driver_data = NULL; - stp = 2; - goto fail_2; - } - - dbgp.o_ep->driver_data = gadget; - o_desc.wMaxPacketSize = - __constant_cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE); - - dbg_desc.bDebugInEndpoint = i_desc.bEndpointAddress; - dbg_desc.bDebugOutEndpoint = o_desc.bEndpointAddress; - -#ifdef CONFIG_USB_G_DBGP_SERIAL - dbgp.serial->in = dbgp.i_ep; - dbgp.serial->out = dbgp.o_ep; - - dbgp.serial->in->desc = &i_desc; - dbgp.serial->out->desc = &o_desc; - - if (gserial_setup(gadget, 1) < 0) { - stp = 3; - goto fail_3; - } - - return 0; - -fail_3: - dbgp.o_ep->driver_data = NULL; -#else - return 0; -#endif -fail_2: - dbgp.i_ep->driver_data = NULL; -fail_1: - dev_dbg(&dbgp.gadget->dev, "ep config: failure (%d)\n", stp); - return -ENODEV; -} - -static int __init dbgp_bind(struct usb_gadget *gadget) -{ - int err, stp; - - dbgp.gadget = gadget; - - dbgp.req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); - if (!dbgp.req) { - err = -ENOMEM; - stp = 1; - goto fail; - } - - dbgp.req->buf = kmalloc(DBGP_REQ_EP0_LEN, GFP_KERNEL); - if (!dbgp.req->buf) { - err = -ENOMEM; - stp = 2; - goto fail; - } - - dbgp.req->length = DBGP_REQ_EP0_LEN; - gadget->ep0->driver_data = gadget; - -#ifdef CONFIG_USB_G_DBGP_SERIAL - dbgp.serial = kzalloc(sizeof(struct gserial), GFP_KERNEL); - if (!dbgp.serial) { - stp = 3; - err = -ENOMEM; - goto fail; - } -#endif - err = dbgp_configure_endpoints(gadget); - if (err < 0) { - stp = 4; - goto fail; - } - - dev_dbg(&dbgp.gadget->dev, "bind: success\n"); - return 0; - -fail: - dev_dbg(&gadget->dev, "bind: failure (%d:%d)\n", stp, err); - dbgp_unbind(gadget); - return err; -} - -static void dbgp_setup_complete(struct usb_ep *ep, - struct usb_request *req) -{ - dev_dbg(&dbgp.gadget->dev, "setup complete: %d, %d/%d\n", - req->status, req->actual, req->length); -} - -static int dbgp_setup(struct usb_gadget *gadget, - const struct usb_ctrlrequest *ctrl) -{ - struct usb_request *req = dbgp.req; - u8 request = ctrl->bRequest; - u16 value = le16_to_cpu(ctrl->wValue); - u16 length = le16_to_cpu(ctrl->wLength); - int err = -EOPNOTSUPP; - void *data = NULL; - u16 len = 0; - - gadget->ep0->driver_data = gadget; - - if (request == USB_REQ_GET_DESCRIPTOR) { - switch (value>>8) { - case USB_DT_DEVICE: - dev_dbg(&dbgp.gadget->dev, "setup: desc device\n"); - len = sizeof device_desc; - data = &device_desc; - device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; - break; - case USB_DT_DEBUG: - dev_dbg(&dbgp.gadget->dev, "setup: desc debug\n"); - len = sizeof dbg_desc; - data = &dbg_desc; - break; - default: - goto fail; - } - err = 0; - } else if (request == USB_REQ_SET_FEATURE && - value == USB_DEVICE_DEBUG_MODE) { - dev_dbg(&dbgp.gadget->dev, "setup: feat debug\n"); -#ifdef CONFIG_USB_G_DBGP_PRINTK - err = dbgp_enable_ep(); -#else - err = gserial_connect(dbgp.serial, 0); -#endif - if (err < 0) - goto fail; - } else - goto fail; - - req->length = min(length, len); - req->zero = len < req->length; - if (data && req->length) - memcpy(req->buf, data, req->length); - - req->complete = dbgp_setup_complete; - return usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); - -fail: - dev_dbg(&dbgp.gadget->dev, - "setup: failure req %x v %x\n", request, value); - return err; -} - -static struct usb_gadget_driver dbgp_driver = { - .function = "dbgp", - .max_speed = USB_SPEED_HIGH, - .unbind = dbgp_unbind, - .setup = dbgp_setup, - .disconnect = dbgp_disconnect, - .driver = { - .owner = THIS_MODULE, - .name = "dbgp" - }, -}; - -static int __init dbgp_init(void) -{ - return usb_gadget_probe_driver(&dbgp_driver, dbgp_bind); -} - -static void __exit dbgp_exit(void) -{ - usb_gadget_unregister_driver(&dbgp_driver); -#ifdef CONFIG_USB_G_DBGP_SERIAL - gserial_cleanup(); -#endif -} - -MODULE_AUTHOR("Stephane Duverger"); -MODULE_LICENSE("GPL"); -module_init(dbgp_init); -module_exit(dbgp_exit); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/dummy_hcd.c b/ANDROID_3.4.5/drivers/usb/gadget/dummy_hcd.c deleted file mode 100644 index 170cbe89..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/dummy_hcd.c +++ /dev/null @@ -1,2673 +0,0 @@ -/* - * dummy_hcd.c -- Dummy/Loopback USB host and device emulator driver. - * - * Maintainer: Alan Stern - * - * Copyright (C) 2003 David Brownell - * Copyright (C) 2003-2005 Alan Stern - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - - -/* - * This exposes a device side "USB gadget" API, driven by requests to a - * Linux-USB host controller driver. USB traffic is simulated; there's - * no need for USB hardware. Use this with two other drivers: - * - * - Gadget driver, responding to requests (slave); - * - Host-side device driver, as already familiar in Linux. - * - * Having this all in one kernel can help some stages of development, - * bypassing some hardware (and driver) issues. UML could help too. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define DRIVER_DESC "USB Host+Gadget Emulator" -#define DRIVER_VERSION "02 May 2005" - -#define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */ - -static const char driver_name[] = "dummy_hcd"; -static const char driver_desc[] = "USB Host+Gadget Emulator"; - -static const char gadget_name[] = "dummy_udc"; - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("David Brownell"); -MODULE_LICENSE("GPL"); - -struct dummy_hcd_module_parameters { - bool is_super_speed; - bool is_high_speed; -}; - -static struct dummy_hcd_module_parameters mod_data = { - .is_super_speed = false, - .is_high_speed = true, -}; -module_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO); -MODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection"); -module_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO); -MODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection"); -/*-------------------------------------------------------------------------*/ - -/* gadget side driver data structres */ -struct dummy_ep { - struct list_head queue; - unsigned long last_io; /* jiffies timestamp */ - struct usb_gadget *gadget; - const struct usb_endpoint_descriptor *desc; - struct usb_ep ep; - unsigned halted:1; - unsigned wedged:1; - unsigned already_seen:1; - unsigned setup_stage:1; - unsigned stream_en:1; -}; - -struct dummy_request { - struct list_head queue; /* ep's requests */ - struct usb_request req; -}; - -static inline struct dummy_ep *usb_ep_to_dummy_ep(struct usb_ep *_ep) -{ - return container_of(_ep, struct dummy_ep, ep); -} - -static inline struct dummy_request *usb_request_to_dummy_request - (struct usb_request *_req) -{ - return container_of(_req, struct dummy_request, req); -} - -/*-------------------------------------------------------------------------*/ - -/* - * Every device has ep0 for control requests, plus up to 30 more endpoints, - * in one of two types: - * - * - Configurable: direction (in/out), type (bulk, iso, etc), and endpoint - * number can be changed. Names like "ep-a" are used for this type. - * - * - Fixed Function: in other cases. some characteristics may be mutable; - * that'd be hardware-specific. Names like "ep12out-bulk" are used. - * - * Gadget drivers are responsible for not setting up conflicting endpoint - * configurations, illegal or unsupported packet lengths, and so on. - */ - -static const char ep0name[] = "ep0"; - -static const char *const ep_name[] = { - ep0name, /* everyone has ep0 */ - - /* act like a net2280: high speed, six configurable endpoints */ - "ep-a", "ep-b", "ep-c", "ep-d", "ep-e", "ep-f", - - /* or like pxa250: fifteen fixed function endpoints */ - "ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int", - "ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int", - "ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso", - "ep15in-int", - - /* or like sa1100: two fixed function endpoints */ - "ep1out-bulk", "ep2in-bulk", -}; -#define DUMMY_ENDPOINTS ARRAY_SIZE(ep_name) - -/*-------------------------------------------------------------------------*/ - -#define FIFO_SIZE 64 - -struct urbp { - struct urb *urb; - struct list_head urbp_list; - struct sg_mapping_iter miter; - u32 miter_started; -}; - - -enum dummy_rh_state { - DUMMY_RH_RESET, - DUMMY_RH_SUSPENDED, - DUMMY_RH_RUNNING -}; - -struct dummy_hcd { - struct dummy *dum; - enum dummy_rh_state rh_state; - struct timer_list timer; - u32 port_status; - u32 old_status; - unsigned long re_timeout; - - struct usb_device *udev; - struct list_head urbp_list; - u32 stream_en_ep; - u8 num_stream[30 / 2]; - - unsigned active:1; - unsigned old_active:1; - unsigned resuming:1; -}; - -struct dummy { - spinlock_t lock; - - /* - * SLAVE/GADGET side support - */ - struct dummy_ep ep[DUMMY_ENDPOINTS]; - int address; - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - struct dummy_request fifo_req; - u8 fifo_buf[FIFO_SIZE]; - u16 devstatus; - unsigned udc_suspended:1; - unsigned pullup:1; - - /* - * MASTER/HOST side support - */ - struct dummy_hcd *hs_hcd; - struct dummy_hcd *ss_hcd; -}; - -static inline struct dummy_hcd *hcd_to_dummy_hcd(struct usb_hcd *hcd) -{ - return (struct dummy_hcd *) (hcd->hcd_priv); -} - -static inline struct usb_hcd *dummy_hcd_to_hcd(struct dummy_hcd *dum) -{ - return container_of((void *) dum, struct usb_hcd, hcd_priv); -} - -static inline struct device *dummy_dev(struct dummy_hcd *dum) -{ - return dummy_hcd_to_hcd(dum)->self.controller; -} - -static inline struct device *udc_dev(struct dummy *dum) -{ - return dum->gadget.dev.parent; -} - -static inline struct dummy *ep_to_dummy(struct dummy_ep *ep) -{ - return container_of(ep->gadget, struct dummy, gadget); -} - -static inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget) -{ - struct dummy *dum = container_of(gadget, struct dummy, gadget); - if (dum->gadget.speed == USB_SPEED_SUPER) - return dum->ss_hcd; - else - return dum->hs_hcd; -} - -static inline struct dummy *gadget_dev_to_dummy(struct device *dev) -{ - return container_of(dev, struct dummy, gadget.dev); -} - -static struct dummy the_controller; - -/*-------------------------------------------------------------------------*/ - -/* SLAVE/GADGET SIDE UTILITY ROUTINES */ - -/* called with spinlock held */ -static void nuke(struct dummy *dum, struct dummy_ep *ep) -{ - while (!list_empty(&ep->queue)) { - struct dummy_request *req; - - req = list_entry(ep->queue.next, struct dummy_request, queue); - list_del_init(&req->queue); - req->req.status = -ESHUTDOWN; - - spin_unlock(&dum->lock); - req->req.complete(&ep->ep, &req->req); - spin_lock(&dum->lock); - } -} - -/* caller must hold lock */ -static void stop_activity(struct dummy *dum) -{ - struct dummy_ep *ep; - - /* prevent any more requests */ - dum->address = 0; - - /* The timer is left running so that outstanding URBs can fail */ - - /* nuke any pending requests first, so driver i/o is quiesced */ - list_for_each_entry(ep, &dum->gadget.ep_list, ep.ep_list) - nuke(dum, ep); - - /* driver now does any non-usb quiescing necessary */ -} - -/** - * set_link_state_by_speed() - Sets the current state of the link according to - * the hcd speed - * @dum_hcd: pointer to the dummy_hcd structure to update the link state for - * - * This function updates the port_status according to the link state and the - * speed of the hcd. - */ -static void set_link_state_by_speed(struct dummy_hcd *dum_hcd) -{ - struct dummy *dum = dum_hcd->dum; - - if (dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3) { - if ((dum_hcd->port_status & USB_SS_PORT_STAT_POWER) == 0) { - dum_hcd->port_status = 0; - } else if (!dum->pullup || dum->udc_suspended) { - /* UDC suspend must cause a disconnect */ - dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION | - USB_PORT_STAT_ENABLE); - if ((dum_hcd->old_status & - USB_PORT_STAT_CONNECTION) != 0) - dum_hcd->port_status |= - (USB_PORT_STAT_C_CONNECTION << 16); - } else { - /* device is connected and not suspended */ - dum_hcd->port_status |= (USB_PORT_STAT_CONNECTION | - USB_PORT_STAT_SPEED_5GBPS) ; - if ((dum_hcd->old_status & - USB_PORT_STAT_CONNECTION) == 0) - dum_hcd->port_status |= - (USB_PORT_STAT_C_CONNECTION << 16); - if ((dum_hcd->port_status & - USB_PORT_STAT_ENABLE) == 1 && - (dum_hcd->port_status & - USB_SS_PORT_LS_U0) == 1 && - dum_hcd->rh_state != DUMMY_RH_SUSPENDED) - dum_hcd->active = 1; - } - } else { - if ((dum_hcd->port_status & USB_PORT_STAT_POWER) == 0) { - dum_hcd->port_status = 0; - } else if (!dum->pullup || dum->udc_suspended) { - /* UDC suspend must cause a disconnect */ - dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION | - USB_PORT_STAT_ENABLE | - USB_PORT_STAT_LOW_SPEED | - USB_PORT_STAT_HIGH_SPEED | - USB_PORT_STAT_SUSPEND); - if ((dum_hcd->old_status & - USB_PORT_STAT_CONNECTION) != 0) - dum_hcd->port_status |= - (USB_PORT_STAT_C_CONNECTION << 16); - } else { - dum_hcd->port_status |= USB_PORT_STAT_CONNECTION; - if ((dum_hcd->old_status & - USB_PORT_STAT_CONNECTION) == 0) - dum_hcd->port_status |= - (USB_PORT_STAT_C_CONNECTION << 16); - if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0) - dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND; - else if ((dum_hcd->port_status & - USB_PORT_STAT_SUSPEND) == 0 && - dum_hcd->rh_state != DUMMY_RH_SUSPENDED) - dum_hcd->active = 1; - } - } -} - -/* caller must hold lock */ -static void set_link_state(struct dummy_hcd *dum_hcd) -{ - struct dummy *dum = dum_hcd->dum; - - dum_hcd->active = 0; - if (dum->pullup) - if ((dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3 && - dum->gadget.speed != USB_SPEED_SUPER) || - (dummy_hcd_to_hcd(dum_hcd)->speed != HCD_USB3 && - dum->gadget.speed == USB_SPEED_SUPER)) - return; - - set_link_state_by_speed(dum_hcd); - - if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 || - dum_hcd->active) - dum_hcd->resuming = 0; - - /* if !connected or reset */ - if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 || - (dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) { - /* - * We're connected and not reset (reset occurred now), - * and driver attached - disconnect! - */ - if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0 && - (dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 && - dum->driver) { - stop_activity(dum); - spin_unlock(&dum->lock); - dum->driver->disconnect(&dum->gadget); - spin_lock(&dum->lock); - } - } else if (dum_hcd->active != dum_hcd->old_active) { - if (dum_hcd->old_active && dum->driver->suspend) { - spin_unlock(&dum->lock); - dum->driver->suspend(&dum->gadget); - spin_lock(&dum->lock); - } else if (!dum_hcd->old_active && dum->driver->resume) { - spin_unlock(&dum->lock); - dum->driver->resume(&dum->gadget); - spin_lock(&dum->lock); - } - } - - dum_hcd->old_status = dum_hcd->port_status; - dum_hcd->old_active = dum_hcd->active; -} - -/*-------------------------------------------------------------------------*/ - -/* SLAVE/GADGET SIDE DRIVER - * - * This only tracks gadget state. All the work is done when the host - * side tries some (emulated) i/o operation. Real device controller - * drivers would do real i/o using dma, fifos, irqs, timers, etc. - */ - -#define is_enabled(dum) \ - (dum->port_status & USB_PORT_STAT_ENABLE) - -static int dummy_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct dummy *dum; - struct dummy_hcd *dum_hcd; - struct dummy_ep *ep; - unsigned max; - int retval; - - ep = usb_ep_to_dummy_ep(_ep); - if (!_ep || !desc || ep->desc || _ep->name == ep0name - || desc->bDescriptorType != USB_DT_ENDPOINT) - return -EINVAL; - dum = ep_to_dummy(ep); - if (!dum->driver) - return -ESHUTDOWN; - - dum_hcd = gadget_to_dummy_hcd(&dum->gadget); - if (!is_enabled(dum_hcd)) - return -ESHUTDOWN; - - /* - * For HS/FS devices only bits 0..10 of the wMaxPacketSize represent the - * maximum packet size. - * For SS devices the wMaxPacketSize is limited by 1024. - */ - max = usb_endpoint_maxp(desc) & 0x7ff; - - /* drivers must not request bad settings, since lower levels - * (hardware or its drivers) may not check. some endpoints - * can't do iso, many have maxpacket limitations, etc. - * - * since this "hardware" driver is here to help debugging, we - * have some extra sanity checks. (there could be more though, - * especially for "ep9out" style fixed function ones.) - */ - retval = -EINVAL; - switch (usb_endpoint_type(desc)) { - case USB_ENDPOINT_XFER_BULK: - if (strstr(ep->ep.name, "-iso") - || strstr(ep->ep.name, "-int")) { - goto done; - } - switch (dum->gadget.speed) { - case USB_SPEED_SUPER: - if (max == 1024) - break; - goto done; - case USB_SPEED_HIGH: - if (max == 512) - break; - goto done; - case USB_SPEED_FULL: - if (max == 8 || max == 16 || max == 32 || max == 64) - /* we'll fake any legal size */ - break; - /* save a return statement */ - default: - goto done; - } - break; - case USB_ENDPOINT_XFER_INT: - if (strstr(ep->ep.name, "-iso")) /* bulk is ok */ - goto done; - /* real hardware might not handle all packet sizes */ - switch (dum->gadget.speed) { - case USB_SPEED_SUPER: - case USB_SPEED_HIGH: - if (max <= 1024) - break; - /* save a return statement */ - case USB_SPEED_FULL: - if (max <= 64) - break; - /* save a return statement */ - default: - if (max <= 8) - break; - goto done; - } - break; - case USB_ENDPOINT_XFER_ISOC: - if (strstr(ep->ep.name, "-bulk") - || strstr(ep->ep.name, "-int")) - goto done; - /* real hardware might not handle all packet sizes */ - switch (dum->gadget.speed) { - case USB_SPEED_SUPER: - case USB_SPEED_HIGH: - if (max <= 1024) - break; - /* save a return statement */ - case USB_SPEED_FULL: - if (max <= 1023) - break; - /* save a return statement */ - default: - goto done; - } - break; - default: - /* few chips support control except on ep0 */ - goto done; - } - - _ep->maxpacket = max; - if (usb_ss_max_streams(_ep->comp_desc)) { - if (!usb_endpoint_xfer_bulk(desc)) { - dev_err(udc_dev(dum), "Can't enable stream support on " - "non-bulk ep %s\n", _ep->name); - return -EINVAL; - } - ep->stream_en = 1; - } - ep->desc = desc; - - dev_dbg(udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d stream %s\n", - _ep->name, - desc->bEndpointAddress & 0x0f, - (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out", - ({ char *val; - switch (usb_endpoint_type(desc)) { - case USB_ENDPOINT_XFER_BULK: - val = "bulk"; - break; - case USB_ENDPOINT_XFER_ISOC: - val = "iso"; - break; - case USB_ENDPOINT_XFER_INT: - val = "intr"; - break; - default: - val = "ctrl"; - break; - }; val; }), - max, ep->stream_en ? "enabled" : "disabled"); - - /* at this point real hardware should be NAKing transfers - * to that endpoint, until a buffer is queued to it. - */ - ep->halted = ep->wedged = 0; - retval = 0; -done: - return retval; -} - -static int dummy_disable(struct usb_ep *_ep) -{ - struct dummy_ep *ep; - struct dummy *dum; - unsigned long flags; - int retval; - - ep = usb_ep_to_dummy_ep(_ep); - if (!_ep || !ep->desc || _ep->name == ep0name) - return -EINVAL; - dum = ep_to_dummy(ep); - - spin_lock_irqsave(&dum->lock, flags); - ep->desc = NULL; - ep->stream_en = 0; - retval = 0; - nuke(dum, ep); - spin_unlock_irqrestore(&dum->lock, flags); - - dev_dbg(udc_dev(dum), "disabled %s\n", _ep->name); - return retval; -} - -static struct usb_request *dummy_alloc_request(struct usb_ep *_ep, - gfp_t mem_flags) -{ - struct dummy_ep *ep; - struct dummy_request *req; - - if (!_ep) - return NULL; - ep = usb_ep_to_dummy_ep(_ep); - - req = kzalloc(sizeof(*req), mem_flags); - if (!req) - return NULL; - INIT_LIST_HEAD(&req->queue); - return &req->req; -} - -static void dummy_free_request(struct usb_ep *_ep, struct usb_request *_req) -{ - struct dummy_ep *ep; - struct dummy_request *req; - - if (!_ep || !_req) - return; - ep = usb_ep_to_dummy_ep(_ep); - if (!ep->desc && _ep->name != ep0name) - return; - - req = usb_request_to_dummy_request(_req); - WARN_ON(!list_empty(&req->queue)); - kfree(req); -} - -static void fifo_complete(struct usb_ep *ep, struct usb_request *req) -{ -} - -static int dummy_queue(struct usb_ep *_ep, struct usb_request *_req, - gfp_t mem_flags) -{ - struct dummy_ep *ep; - struct dummy_request *req; - struct dummy *dum; - struct dummy_hcd *dum_hcd; - unsigned long flags; - - req = usb_request_to_dummy_request(_req); - if (!_req || !list_empty(&req->queue) || !_req->complete) - return -EINVAL; - - ep = usb_ep_to_dummy_ep(_ep); - if (!_ep || (!ep->desc && _ep->name != ep0name)) - return -EINVAL; - - dum = ep_to_dummy(ep); - dum_hcd = gadget_to_dummy_hcd(&dum->gadget); - if (!dum->driver || !is_enabled(dum_hcd)) - return -ESHUTDOWN; - -#if 0 - dev_dbg(udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n", - ep, _req, _ep->name, _req->length, _req->buf); -#endif - _req->status = -EINPROGRESS; - _req->actual = 0; - spin_lock_irqsave(&dum->lock, flags); - - /* implement an emulated single-request FIFO */ - if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) && - list_empty(&dum->fifo_req.queue) && - list_empty(&ep->queue) && - _req->length <= FIFO_SIZE) { - req = &dum->fifo_req; - req->req = *_req; - req->req.buf = dum->fifo_buf; - memcpy(dum->fifo_buf, _req->buf, _req->length); - req->req.context = dum; - req->req.complete = fifo_complete; - - list_add_tail(&req->queue, &ep->queue); - spin_unlock(&dum->lock); - _req->actual = _req->length; - _req->status = 0; - _req->complete(_ep, _req); - spin_lock(&dum->lock); - } else - list_add_tail(&req->queue, &ep->queue); - spin_unlock_irqrestore(&dum->lock, flags); - - /* real hardware would likely enable transfers here, in case - * it'd been left NAKing. - */ - return 0; -} - -static int dummy_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct dummy_ep *ep; - struct dummy *dum; - int retval = -EINVAL; - unsigned long flags; - struct dummy_request *req = NULL; - - if (!_ep || !_req) - return retval; - ep = usb_ep_to_dummy_ep(_ep); - dum = ep_to_dummy(ep); - - if (!dum->driver) - return -ESHUTDOWN; - - local_irq_save(flags); - spin_lock(&dum->lock); - list_for_each_entry(req, &ep->queue, queue) { - if (&req->req == _req) { - list_del_init(&req->queue); - _req->status = -ECONNRESET; - retval = 0; - break; - } - } - spin_unlock(&dum->lock); - - if (retval == 0) { - dev_dbg(udc_dev(dum), - "dequeued req %p from %s, len %d buf %p\n", - req, _ep->name, _req->length, _req->buf); - _req->complete(_ep, _req); - } - local_irq_restore(flags); - return retval; -} - -static int -dummy_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged) -{ - struct dummy_ep *ep; - struct dummy *dum; - - if (!_ep) - return -EINVAL; - ep = usb_ep_to_dummy_ep(_ep); - dum = ep_to_dummy(ep); - if (!dum->driver) - return -ESHUTDOWN; - if (!value) - ep->halted = ep->wedged = 0; - else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) && - !list_empty(&ep->queue)) - return -EAGAIN; - else { - ep->halted = 1; - if (wedged) - ep->wedged = 1; - } - /* FIXME clear emulated data toggle too */ - return 0; -} - -static int -dummy_set_halt(struct usb_ep *_ep, int value) -{ - return dummy_set_halt_and_wedge(_ep, value, 0); -} - -static int dummy_set_wedge(struct usb_ep *_ep) -{ - if (!_ep || _ep->name == ep0name) - return -EINVAL; - return dummy_set_halt_and_wedge(_ep, 1, 1); -} - -static const struct usb_ep_ops dummy_ep_ops = { - .enable = dummy_enable, - .disable = dummy_disable, - - .alloc_request = dummy_alloc_request, - .free_request = dummy_free_request, - - .queue = dummy_queue, - .dequeue = dummy_dequeue, - - .set_halt = dummy_set_halt, - .set_wedge = dummy_set_wedge, -}; - -/*-------------------------------------------------------------------------*/ - -/* there are both host and device side versions of this call ... */ -static int dummy_g_get_frame(struct usb_gadget *_gadget) -{ - struct timeval tv; - - do_gettimeofday(&tv); - return tv.tv_usec / 1000; -} - -static int dummy_wakeup(struct usb_gadget *_gadget) -{ - struct dummy_hcd *dum_hcd; - - dum_hcd = gadget_to_dummy_hcd(_gadget); - if (!(dum_hcd->dum->devstatus & ((1 << USB_DEVICE_B_HNP_ENABLE) - | (1 << USB_DEVICE_REMOTE_WAKEUP)))) - return -EINVAL; - if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0) - return -ENOLINK; - if ((dum_hcd->port_status & USB_PORT_STAT_SUSPEND) == 0 && - dum_hcd->rh_state != DUMMY_RH_SUSPENDED) - return -EIO; - - /* FIXME: What if the root hub is suspended but the port isn't? */ - - /* hub notices our request, issues downstream resume, etc */ - dum_hcd->resuming = 1; - dum_hcd->re_timeout = jiffies + msecs_to_jiffies(20); - mod_timer(&dummy_hcd_to_hcd(dum_hcd)->rh_timer, dum_hcd->re_timeout); - return 0; -} - -static int dummy_set_selfpowered(struct usb_gadget *_gadget, int value) -{ - struct dummy *dum; - - dum = gadget_to_dummy_hcd(_gadget)->dum; - if (value) - dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED); - else - dum->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED); - return 0; -} - -static void dummy_udc_update_ep0(struct dummy *dum) -{ - if (dum->gadget.speed == USB_SPEED_SUPER) - dum->ep[0].ep.maxpacket = 9; - else - dum->ep[0].ep.maxpacket = 64; -} - -static int dummy_pullup(struct usb_gadget *_gadget, int value) -{ - struct dummy_hcd *dum_hcd; - struct dummy *dum; - unsigned long flags; - - dum = gadget_dev_to_dummy(&_gadget->dev); - - if (value && dum->driver) { - if (mod_data.is_super_speed) - dum->gadget.speed = dum->driver->max_speed; - else if (mod_data.is_high_speed) - dum->gadget.speed = min_t(u8, USB_SPEED_HIGH, - dum->driver->max_speed); - else - dum->gadget.speed = USB_SPEED_FULL; - dummy_udc_update_ep0(dum); - - if (dum->gadget.speed < dum->driver->max_speed) - dev_dbg(udc_dev(dum), "This device can perform faster" - " if you connect it to a %s port...\n", - usb_speed_string(dum->driver->max_speed)); - } - dum_hcd = gadget_to_dummy_hcd(_gadget); - - spin_lock_irqsave(&dum->lock, flags); - dum->pullup = (value != 0); - set_link_state(dum_hcd); - spin_unlock_irqrestore(&dum->lock, flags); - - usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd)); - return 0; -} - -static int dummy_udc_start(struct usb_gadget *g, - struct usb_gadget_driver *driver); -static int dummy_udc_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver); - -static const struct usb_gadget_ops dummy_ops = { - .get_frame = dummy_g_get_frame, - .wakeup = dummy_wakeup, - .set_selfpowered = dummy_set_selfpowered, - .pullup = dummy_pullup, - .udc_start = dummy_udc_start, - .udc_stop = dummy_udc_stop, -}; - -/*-------------------------------------------------------------------------*/ - -/* "function" sysfs attribute */ -static ssize_t show_function(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct dummy *dum = gadget_dev_to_dummy(dev); - - if (!dum->driver || !dum->driver->function) - return 0; - return scnprintf(buf, PAGE_SIZE, "%s\n", dum->driver->function); -} -static DEVICE_ATTR(function, S_IRUGO, show_function, NULL); - -/*-------------------------------------------------------------------------*/ - -/* - * Driver registration/unregistration. - * - * This is basically hardware-specific; there's usually only one real USB - * device (not host) controller since that's how USB devices are intended - * to work. So most implementations of these api calls will rely on the - * fact that only one driver will ever bind to the hardware. But curious - * hardware can be built with discrete components, so the gadget API doesn't - * require that assumption. - * - * For this emulator, it might be convenient to create a usb slave device - * for each driver that registers: just add to a big root hub. - */ - -static int dummy_udc_start(struct usb_gadget *g, - struct usb_gadget_driver *driver) -{ - struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(g); - struct dummy *dum = dum_hcd->dum; - - if (driver->max_speed == USB_SPEED_UNKNOWN) - return -EINVAL; - - /* - * SLAVE side init ... the layer above hardware, which - * can't enumerate without help from the driver we're binding. - */ - - dum->devstatus = 0; - - dum->driver = driver; - dev_dbg(udc_dev(dum), "binding gadget driver '%s'\n", - driver->driver.name); - return 0; -} - -static int dummy_udc_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver) -{ - struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(g); - struct dummy *dum = dum_hcd->dum; - - dev_dbg(udc_dev(dum), "unregister gadget driver '%s'\n", - driver->driver.name); - - dum->driver = NULL; - - return 0; -} - -#undef is_enabled - -/* The gadget structure is stored inside the hcd structure and will be - * released along with it. */ -static void dummy_gadget_release(struct device *dev) -{ - return; -} - -static void init_dummy_udc_hw(struct dummy *dum) -{ - int i; - - INIT_LIST_HEAD(&dum->gadget.ep_list); - for (i = 0; i < DUMMY_ENDPOINTS; i++) { - struct dummy_ep *ep = &dum->ep[i]; - - if (!ep_name[i]) - break; - ep->ep.name = ep_name[i]; - ep->ep.ops = &dummy_ep_ops; - list_add_tail(&ep->ep.ep_list, &dum->gadget.ep_list); - ep->halted = ep->wedged = ep->already_seen = - ep->setup_stage = 0; - ep->ep.maxpacket = ~0; - ep->ep.max_streams = 16; - ep->last_io = jiffies; - ep->gadget = &dum->gadget; - ep->desc = NULL; - INIT_LIST_HEAD(&ep->queue); - } - - dum->gadget.ep0 = &dum->ep[0].ep; - list_del_init(&dum->ep[0].ep.ep_list); - INIT_LIST_HEAD(&dum->fifo_req.queue); - -#ifdef CONFIG_USB_OTG - dum->gadget.is_otg = 1; -#endif -} - -static int dummy_udc_probe(struct platform_device *pdev) -{ - struct dummy *dum = &the_controller; - int rc; - - dum->gadget.name = gadget_name; - dum->gadget.ops = &dummy_ops; - dum->gadget.max_speed = USB_SPEED_SUPER; - - dev_set_name(&dum->gadget.dev, "gadget"); - dum->gadget.dev.parent = &pdev->dev; - dum->gadget.dev.release = dummy_gadget_release; - rc = device_register(&dum->gadget.dev); - if (rc < 0) { - put_device(&dum->gadget.dev); - return rc; - } - - init_dummy_udc_hw(dum); - - rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget); - if (rc < 0) - goto err_udc; - - rc = device_create_file(&dum->gadget.dev, &dev_attr_function); - if (rc < 0) - goto err_dev; - platform_set_drvdata(pdev, dum); - return rc; - -err_dev: - usb_del_gadget_udc(&dum->gadget); -err_udc: - device_unregister(&dum->gadget.dev); - return rc; -} - -static int dummy_udc_remove(struct platform_device *pdev) -{ - struct dummy *dum = platform_get_drvdata(pdev); - - usb_del_gadget_udc(&dum->gadget); - platform_set_drvdata(pdev, NULL); - device_remove_file(&dum->gadget.dev, &dev_attr_function); - device_unregister(&dum->gadget.dev); - return 0; -} - -static void dummy_udc_pm(struct dummy *dum, struct dummy_hcd *dum_hcd, - int suspend) -{ - spin_lock_irq(&dum->lock); - dum->udc_suspended = suspend; - set_link_state(dum_hcd); - spin_unlock_irq(&dum->lock); -} - -static int dummy_udc_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct dummy *dum = platform_get_drvdata(pdev); - struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(&dum->gadget); - - dev_dbg(&pdev->dev, "%s\n", __func__); - dummy_udc_pm(dum, dum_hcd, 1); - usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd)); - return 0; -} - -static int dummy_udc_resume(struct platform_device *pdev) -{ - struct dummy *dum = platform_get_drvdata(pdev); - struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(&dum->gadget); - - dev_dbg(&pdev->dev, "%s\n", __func__); - dummy_udc_pm(dum, dum_hcd, 0); - usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd)); - return 0; -} - -static struct platform_driver dummy_udc_driver = { - .probe = dummy_udc_probe, - .remove = dummy_udc_remove, - .suspend = dummy_udc_suspend, - .resume = dummy_udc_resume, - .driver = { - .name = (char *) gadget_name, - .owner = THIS_MODULE, - }, -}; - -/*-------------------------------------------------------------------------*/ - -static unsigned int dummy_get_ep_idx(const struct usb_endpoint_descriptor *desc) -{ - unsigned int index; - - index = usb_endpoint_num(desc) << 1; - if (usb_endpoint_dir_in(desc)) - index |= 1; - return index; -} - -/* MASTER/HOST SIDE DRIVER - * - * this uses the hcd framework to hook up to host side drivers. - * its root hub will only have one device, otherwise it acts like - * a normal host controller. - * - * when urbs are queued, they're just stuck on a list that we - * scan in a timer callback. that callback connects writes from - * the host with reads from the device, and so on, based on the - * usb 2.0 rules. - */ - -static int dummy_ep_stream_en(struct dummy_hcd *dum_hcd, struct urb *urb) -{ - const struct usb_endpoint_descriptor *desc = &urb->ep->desc; - u32 index; - - if (!usb_endpoint_xfer_bulk(desc)) - return 0; - - index = dummy_get_ep_idx(desc); - return (1 << index) & dum_hcd->stream_en_ep; -} - -/* - * The max stream number is saved as a nibble so for the 30 possible endpoints - * we only 15 bytes of memory. Therefore we are limited to max 16 streams (0 - * means we use only 1 stream). The maximum according to the spec is 16bit so - * if the 16 stream limit is about to go, the array size should be incremented - * to 30 elements of type u16. - */ -static int get_max_streams_for_pipe(struct dummy_hcd *dum_hcd, - unsigned int pipe) -{ - int max_streams; - - max_streams = dum_hcd->num_stream[usb_pipeendpoint(pipe)]; - if (usb_pipeout(pipe)) - max_streams >>= 4; - else - max_streams &= 0xf; - max_streams++; - return max_streams; -} - -static void set_max_streams_for_pipe(struct dummy_hcd *dum_hcd, - unsigned int pipe, unsigned int streams) -{ - int max_streams; - - streams--; - max_streams = dum_hcd->num_stream[usb_pipeendpoint(pipe)]; - if (usb_pipeout(pipe)) { - streams <<= 4; - max_streams &= 0xf; - } else { - max_streams &= 0xf0; - } - max_streams |= streams; - dum_hcd->num_stream[usb_pipeendpoint(pipe)] = max_streams; -} - -static int dummy_validate_stream(struct dummy_hcd *dum_hcd, struct urb *urb) -{ - unsigned int max_streams; - int enabled; - - enabled = dummy_ep_stream_en(dum_hcd, urb); - if (!urb->stream_id) { - if (enabled) - return -EINVAL; - return 0; - } - if (!enabled) - return -EINVAL; - - max_streams = get_max_streams_for_pipe(dum_hcd, - usb_pipeendpoint(urb->pipe)); - if (urb->stream_id > max_streams) { - dev_err(dummy_dev(dum_hcd), "Stream id %d is out of range.\n", - urb->stream_id); - BUG(); - return -EINVAL; - } - return 0; -} - -static int dummy_urb_enqueue( - struct usb_hcd *hcd, - struct urb *urb, - gfp_t mem_flags -) { - struct dummy_hcd *dum_hcd; - struct urbp *urbp; - unsigned long flags; - int rc; - - urbp = kmalloc(sizeof *urbp, mem_flags); - if (!urbp) - return -ENOMEM; - urbp->urb = urb; - urbp->miter_started = 0; - - dum_hcd = hcd_to_dummy_hcd(hcd); - spin_lock_irqsave(&dum_hcd->dum->lock, flags); - - rc = dummy_validate_stream(dum_hcd, urb); - if (rc) { - kfree(urbp); - goto done; - } - - rc = usb_hcd_link_urb_to_ep(hcd, urb); - if (rc) { - kfree(urbp); - goto done; - } - - if (!dum_hcd->udev) { - dum_hcd->udev = urb->dev; - usb_get_dev(dum_hcd->udev); - } else if (unlikely(dum_hcd->udev != urb->dev)) - dev_err(dummy_dev(dum_hcd), "usb_device address has changed!\n"); - - list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list); - urb->hcpriv = urbp; - if (usb_pipetype(urb->pipe) == PIPE_CONTROL) - urb->error_count = 1; /* mark as a new urb */ - - /* kick the scheduler, it'll do the rest */ - if (!timer_pending(&dum_hcd->timer)) - mod_timer(&dum_hcd->timer, jiffies + 1); - - done: - spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); - return rc; -} - -static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) -{ - struct dummy_hcd *dum_hcd; - unsigned long flags; - int rc; - - /* giveback happens automatically in timer callback, - * so make sure the callback happens */ - dum_hcd = hcd_to_dummy_hcd(hcd); - spin_lock_irqsave(&dum_hcd->dum->lock, flags); - - rc = usb_hcd_check_unlink_urb(hcd, urb, status); - if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING && - !list_empty(&dum_hcd->urbp_list)) - mod_timer(&dum_hcd->timer, jiffies); - - spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); - return rc; -} - -static int dummy_perform_transfer(struct urb *urb, struct dummy_request *req, - u32 len) -{ - void *ubuf, *rbuf; - struct urbp *urbp = urb->hcpriv; - int to_host; - struct sg_mapping_iter *miter = &urbp->miter; - u32 trans = 0; - u32 this_sg; - bool next_sg; - - to_host = usb_pipein(urb->pipe); - rbuf = req->req.buf + req->req.actual; - - if (!urb->num_sgs) { - ubuf = urb->transfer_buffer + urb->actual_length; - if (to_host) - memcpy(ubuf, rbuf, len); - else - memcpy(rbuf, ubuf, len); - return len; - } - - if (!urbp->miter_started) { - u32 flags = SG_MITER_ATOMIC; - - if (to_host) - flags |= SG_MITER_TO_SG; - else - flags |= SG_MITER_FROM_SG; - - sg_miter_start(miter, urb->sg, urb->num_sgs, flags); - urbp->miter_started = 1; - } - next_sg = sg_miter_next(miter); - if (next_sg == false) { - WARN_ON_ONCE(1); - return -EINVAL; - } - do { - ubuf = miter->addr; - this_sg = min_t(u32, len, miter->length); - miter->consumed = this_sg; - trans += this_sg; - - if (to_host) - memcpy(ubuf, rbuf, this_sg); - else - memcpy(rbuf, ubuf, this_sg); - len -= this_sg; - - if (!len) - break; - next_sg = sg_miter_next(miter); - if (next_sg == false) { - WARN_ON_ONCE(1); - return -EINVAL; - } - - rbuf += this_sg; - } while (1); - - sg_miter_stop(miter); - return trans; -} - -/* transfer up to a frame's worth; caller must own lock */ -static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb, - struct dummy_ep *ep, int limit, int *status) -{ - struct dummy *dum = dum_hcd->dum; - struct dummy_request *req; - -top: - /* if there's no request queued, the device is NAKing; return */ - list_for_each_entry(req, &ep->queue, queue) { - unsigned host_len, dev_len, len; - int is_short, to_host; - int rescan = 0; - - if (dummy_ep_stream_en(dum_hcd, urb)) { - if ((urb->stream_id != req->req.stream_id)) - continue; - } - - /* 1..N packets of ep->ep.maxpacket each ... the last one - * may be short (including zero length). - * - * writer can send a zlp explicitly (length 0) or implicitly - * (length mod maxpacket zero, and 'zero' flag); they always - * terminate reads. - */ - host_len = urb->transfer_buffer_length - urb->actual_length; - dev_len = req->req.length - req->req.actual; - len = min(host_len, dev_len); - - /* FIXME update emulated data toggle too */ - - to_host = usb_pipein(urb->pipe); - if (unlikely(len == 0)) - is_short = 1; - else { - /* not enough bandwidth left? */ - if (limit < ep->ep.maxpacket && limit < len) - break; - len = min_t(unsigned, len, limit); - if (len == 0) - break; - - /* use an extra pass for the final short packet */ - if (len > ep->ep.maxpacket) { - rescan = 1; - len -= (len % ep->ep.maxpacket); - } - is_short = (len % ep->ep.maxpacket) != 0; - - len = dummy_perform_transfer(urb, req, len); - - ep->last_io = jiffies; - if ((int)len < 0) { - req->req.status = len; - } else { - limit -= len; - urb->actual_length += len; - req->req.actual += len; - } - } - - /* short packets terminate, maybe with overflow/underflow. - * it's only really an error to write too much. - * - * partially filling a buffer optionally blocks queue advances - * (so completion handlers can clean up the queue) but we don't - * need to emulate such data-in-flight. - */ - if (is_short) { - if (host_len == dev_len) { - req->req.status = 0; - *status = 0; - } else if (to_host) { - req->req.status = 0; - if (dev_len > host_len) - *status = -EOVERFLOW; - else - *status = 0; - } else if (!to_host) { - *status = 0; - if (host_len > dev_len) - req->req.status = -EOVERFLOW; - else - req->req.status = 0; - } - - /* many requests terminate without a short packet */ - } else { - if (req->req.length == req->req.actual - && !req->req.zero) - req->req.status = 0; - if (urb->transfer_buffer_length == urb->actual_length - && !(urb->transfer_flags - & URB_ZERO_PACKET)) - *status = 0; - } - - /* device side completion --> continuable */ - if (req->req.status != -EINPROGRESS) { - list_del_init(&req->queue); - - spin_unlock(&dum->lock); - req->req.complete(&ep->ep, &req->req); - spin_lock(&dum->lock); - - /* requests might have been unlinked... */ - rescan = 1; - } - - /* host side completion --> terminate */ - if (*status != -EINPROGRESS) - break; - - /* rescan to continue with any other queued i/o */ - if (rescan) - goto top; - } - return limit; -} - -static int periodic_bytes(struct dummy *dum, struct dummy_ep *ep) -{ - int limit = ep->ep.maxpacket; - - if (dum->gadget.speed == USB_SPEED_HIGH) { - int tmp; - - /* high bandwidth mode */ - tmp = usb_endpoint_maxp(ep->desc); - tmp = (tmp >> 11) & 0x03; - tmp *= 8 /* applies to entire frame */; - limit += limit * tmp; - } - if (dum->gadget.speed == USB_SPEED_SUPER) { - switch (usb_endpoint_type(ep->desc)) { - case USB_ENDPOINT_XFER_ISOC: - /* Sec. 4.4.8.2 USB3.0 Spec */ - limit = 3 * 16 * 1024 * 8; - break; - case USB_ENDPOINT_XFER_INT: - /* Sec. 4.4.7.2 USB3.0 Spec */ - limit = 3 * 1024 * 8; - break; - case USB_ENDPOINT_XFER_BULK: - default: - break; - } - } - return limit; -} - -#define is_active(dum_hcd) ((dum_hcd->port_status & \ - (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \ - USB_PORT_STAT_SUSPEND)) \ - == (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE)) - -static struct dummy_ep *find_endpoint(struct dummy *dum, u8 address) -{ - int i; - - if (!is_active((dum->gadget.speed == USB_SPEED_SUPER ? - dum->ss_hcd : dum->hs_hcd))) - return NULL; - if ((address & ~USB_DIR_IN) == 0) - return &dum->ep[0]; - for (i = 1; i < DUMMY_ENDPOINTS; i++) { - struct dummy_ep *ep = &dum->ep[i]; - - if (!ep->desc) - continue; - if (ep->desc->bEndpointAddress == address) - return ep; - } - return NULL; -} - -#undef is_active - -#define Dev_Request (USB_TYPE_STANDARD | USB_RECIP_DEVICE) -#define Dev_InRequest (Dev_Request | USB_DIR_IN) -#define Intf_Request (USB_TYPE_STANDARD | USB_RECIP_INTERFACE) -#define Intf_InRequest (Intf_Request | USB_DIR_IN) -#define Ep_Request (USB_TYPE_STANDARD | USB_RECIP_ENDPOINT) -#define Ep_InRequest (Ep_Request | USB_DIR_IN) - - -/** - * handle_control_request() - handles all control transfers - * @dum: pointer to dummy (the_controller) - * @urb: the urb request to handle - * @setup: pointer to the setup data for a USB device control - * request - * @status: pointer to request handling status - * - * Return 0 - if the request was handled - * 1 - if the request wasn't handles - * error code on error - */ -static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb, - struct usb_ctrlrequest *setup, - int *status) -{ - struct dummy_ep *ep2; - struct dummy *dum = dum_hcd->dum; - int ret_val = 1; - unsigned w_index; - unsigned w_value; - - w_index = le16_to_cpu(setup->wIndex); - w_value = le16_to_cpu(setup->wValue); - switch (setup->bRequest) { - case USB_REQ_SET_ADDRESS: - if (setup->bRequestType != Dev_Request) - break; - dum->address = w_value; - *status = 0; - dev_dbg(udc_dev(dum), "set_address = %d\n", - w_value); - ret_val = 0; - break; - case USB_REQ_SET_FEATURE: - if (setup->bRequestType == Dev_Request) { - ret_val = 0; - switch (w_value) { - case USB_DEVICE_REMOTE_WAKEUP: - break; - case USB_DEVICE_B_HNP_ENABLE: - dum->gadget.b_hnp_enable = 1; - break; - case USB_DEVICE_A_HNP_SUPPORT: - dum->gadget.a_hnp_support = 1; - break; - case USB_DEVICE_A_ALT_HNP_SUPPORT: - dum->gadget.a_alt_hnp_support = 1; - break; - case USB_DEVICE_U1_ENABLE: - if (dummy_hcd_to_hcd(dum_hcd)->speed == - HCD_USB3) - w_value = USB_DEV_STAT_U1_ENABLED; - else - ret_val = -EOPNOTSUPP; - break; - case USB_DEVICE_U2_ENABLE: - if (dummy_hcd_to_hcd(dum_hcd)->speed == - HCD_USB3) - w_value = USB_DEV_STAT_U2_ENABLED; - else - ret_val = -EOPNOTSUPP; - break; - case USB_DEVICE_LTM_ENABLE: - if (dummy_hcd_to_hcd(dum_hcd)->speed == - HCD_USB3) - w_value = USB_DEV_STAT_LTM_ENABLED; - else - ret_val = -EOPNOTSUPP; - break; - default: - ret_val = -EOPNOTSUPP; - } - if (ret_val == 0) { - dum->devstatus |= (1 << w_value); - *status = 0; - } - } else if (setup->bRequestType == Ep_Request) { - /* endpoint halt */ - ep2 = find_endpoint(dum, w_index); - if (!ep2 || ep2->ep.name == ep0name) { - ret_val = -EOPNOTSUPP; - break; - } - ep2->halted = 1; - ret_val = 0; - *status = 0; - } - break; - case USB_REQ_CLEAR_FEATURE: - if (setup->bRequestType == Dev_Request) { - ret_val = 0; - switch (w_value) { - case USB_DEVICE_REMOTE_WAKEUP: - w_value = USB_DEVICE_REMOTE_WAKEUP; - break; - case USB_DEVICE_U1_ENABLE: - if (dummy_hcd_to_hcd(dum_hcd)->speed == - HCD_USB3) - w_value = USB_DEV_STAT_U1_ENABLED; - else - ret_val = -EOPNOTSUPP; - break; - case USB_DEVICE_U2_ENABLE: - if (dummy_hcd_to_hcd(dum_hcd)->speed == - HCD_USB3) - w_value = USB_DEV_STAT_U2_ENABLED; - else - ret_val = -EOPNOTSUPP; - break; - case USB_DEVICE_LTM_ENABLE: - if (dummy_hcd_to_hcd(dum_hcd)->speed == - HCD_USB3) - w_value = USB_DEV_STAT_LTM_ENABLED; - else - ret_val = -EOPNOTSUPP; - break; - default: - ret_val = -EOPNOTSUPP; - break; - } - if (ret_val == 0) { - dum->devstatus &= ~(1 << w_value); - *status = 0; - } - } else if (setup->bRequestType == Ep_Request) { - /* endpoint halt */ - ep2 = find_endpoint(dum, w_index); - if (!ep2) { - ret_val = -EOPNOTSUPP; - break; - } - if (!ep2->wedged) - ep2->halted = 0; - ret_val = 0; - *status = 0; - } - break; - case USB_REQ_GET_STATUS: - if (setup->bRequestType == Dev_InRequest - || setup->bRequestType == Intf_InRequest - || setup->bRequestType == Ep_InRequest) { - char *buf; - /* - * device: remote wakeup, selfpowered - * interface: nothing - * endpoint: halt - */ - buf = (char *)urb->transfer_buffer; - if (urb->transfer_buffer_length > 0) { - if (setup->bRequestType == Ep_InRequest) { - ep2 = find_endpoint(dum, w_index); - if (!ep2) { - ret_val = -EOPNOTSUPP; - break; - } - buf[0] = ep2->halted; - } else if (setup->bRequestType == - Dev_InRequest) { - buf[0] = (u8)dum->devstatus; - } else - buf[0] = 0; - } - if (urb->transfer_buffer_length > 1) - buf[1] = 0; - urb->actual_length = min_t(u32, 2, - urb->transfer_buffer_length); - ret_val = 0; - *status = 0; - } - break; - } - return ret_val; -} - -/* drive both sides of the transfers; looks like irq handlers to - * both drivers except the callbacks aren't in_irq(). - */ -static void dummy_timer(unsigned long _dum_hcd) -{ - struct dummy_hcd *dum_hcd = (struct dummy_hcd *) _dum_hcd; - struct dummy *dum = dum_hcd->dum; - struct urbp *urbp, *tmp; - unsigned long flags; - int limit, total; - int i; - - /* simplistic model for one frame's bandwidth */ - switch (dum->gadget.speed) { - case USB_SPEED_LOW: - total = 8/*bytes*/ * 12/*packets*/; - break; - case USB_SPEED_FULL: - total = 64/*bytes*/ * 19/*packets*/; - break; - case USB_SPEED_HIGH: - total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/; - break; - case USB_SPEED_SUPER: - /* Bus speed is 500000 bytes/ms, so use a little less */ - total = 490000; - break; - default: - dev_err(dummy_dev(dum_hcd), "bogus device speed\n"); - return; - } - - /* FIXME if HZ != 1000 this will probably misbehave ... */ - - /* look at each urb queued by the host side driver */ - spin_lock_irqsave(&dum->lock, flags); - - if (!dum_hcd->udev) { - dev_err(dummy_dev(dum_hcd), - "timer fired with no URBs pending?\n"); - spin_unlock_irqrestore(&dum->lock, flags); - return; - } - - for (i = 0; i < DUMMY_ENDPOINTS; i++) { - if (!ep_name[i]) - break; - dum->ep[i].already_seen = 0; - } - -restart: - list_for_each_entry_safe(urbp, tmp, &dum_hcd->urbp_list, urbp_list) { - struct urb *urb; - struct dummy_request *req; - u8 address; - struct dummy_ep *ep = NULL; - int type; - int status = -EINPROGRESS; - - urb = urbp->urb; - if (urb->unlinked) - goto return_urb; - else if (dum_hcd->rh_state != DUMMY_RH_RUNNING) - continue; - type = usb_pipetype(urb->pipe); - - /* used up this frame's non-periodic bandwidth? - * FIXME there's infinite bandwidth for control and - * periodic transfers ... unrealistic. - */ - if (total <= 0 && type == PIPE_BULK) - continue; - - /* find the gadget's ep for this request (if configured) */ - address = usb_pipeendpoint (urb->pipe); - if (usb_pipein(urb->pipe)) - address |= USB_DIR_IN; - ep = find_endpoint(dum, address); - if (!ep) { - /* set_configuration() disagreement */ - dev_dbg(dummy_dev(dum_hcd), - "no ep configured for urb %p\n", - urb); - status = -EPROTO; - goto return_urb; - } - - if (ep->already_seen) - continue; - ep->already_seen = 1; - if (ep == &dum->ep[0] && urb->error_count) { - ep->setup_stage = 1; /* a new urb */ - urb->error_count = 0; - } - if (ep->halted && !ep->setup_stage) { - /* NOTE: must not be iso! */ - dev_dbg(dummy_dev(dum_hcd), "ep %s halted, urb %p\n", - ep->ep.name, urb); - status = -EPIPE; - goto return_urb; - } - /* FIXME make sure both ends agree on maxpacket */ - - /* handle control requests */ - if (ep == &dum->ep[0] && ep->setup_stage) { - struct usb_ctrlrequest setup; - int value = 1; - - setup = *(struct usb_ctrlrequest *) urb->setup_packet; - /* paranoia, in case of stale queued data */ - list_for_each_entry(req, &ep->queue, queue) { - list_del_init(&req->queue); - req->req.status = -EOVERFLOW; - dev_dbg(udc_dev(dum), "stale req = %p\n", - req); - - spin_unlock(&dum->lock); - req->req.complete(&ep->ep, &req->req); - spin_lock(&dum->lock); - ep->already_seen = 0; - goto restart; - } - - /* gadget driver never sees set_address or operations - * on standard feature flags. some hardware doesn't - * even expose them. - */ - ep->last_io = jiffies; - ep->setup_stage = 0; - ep->halted = 0; - - value = handle_control_request(dum_hcd, urb, &setup, - &status); - - /* gadget driver handles all other requests. block - * until setup() returns; no reentrancy issues etc. - */ - if (value > 0) { - spin_unlock(&dum->lock); - value = dum->driver->setup(&dum->gadget, - &setup); - spin_lock(&dum->lock); - - if (value >= 0) { - /* no delays (max 64KB data stage) */ - limit = 64*1024; - goto treat_control_like_bulk; - } - /* error, see below */ - } - - if (value < 0) { - if (value != -EOPNOTSUPP) - dev_dbg(udc_dev(dum), - "setup --> %d\n", - value); - status = -EPIPE; - urb->actual_length = 0; - } - - goto return_urb; - } - - /* non-control requests */ - limit = total; - switch (usb_pipetype(urb->pipe)) { - case PIPE_ISOCHRONOUS: - /* FIXME is it urb->interval since the last xfer? - * use urb->iso_frame_desc[i]. - * complete whether or not ep has requests queued. - * report random errors, to debug drivers. - */ - limit = max(limit, periodic_bytes(dum, ep)); - status = -ENOSYS; - break; - - case PIPE_INTERRUPT: - /* FIXME is it urb->interval since the last xfer? - * this almost certainly polls too fast. - */ - limit = max(limit, periodic_bytes(dum, ep)); - /* FALLTHROUGH */ - - default: -treat_control_like_bulk: - ep->last_io = jiffies; - total = transfer(dum_hcd, urb, ep, limit, &status); - break; - } - - /* incomplete transfer? */ - if (status == -EINPROGRESS) - continue; - -return_urb: - list_del(&urbp->urbp_list); - kfree(urbp); - if (ep) - ep->already_seen = ep->setup_stage = 0; - - usb_hcd_unlink_urb_from_ep(dummy_hcd_to_hcd(dum_hcd), urb); - spin_unlock(&dum->lock); - usb_hcd_giveback_urb(dummy_hcd_to_hcd(dum_hcd), urb, status); - spin_lock(&dum->lock); - - goto restart; - } - - if (list_empty(&dum_hcd->urbp_list)) { - usb_put_dev(dum_hcd->udev); - dum_hcd->udev = NULL; - } else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) { - /* want a 1 msec delay here */ - mod_timer(&dum_hcd->timer, jiffies + msecs_to_jiffies(1)); - } - - spin_unlock_irqrestore(&dum->lock, flags); -} - -/*-------------------------------------------------------------------------*/ - -#define PORT_C_MASK \ - ((USB_PORT_STAT_C_CONNECTION \ - | USB_PORT_STAT_C_ENABLE \ - | USB_PORT_STAT_C_SUSPEND \ - | USB_PORT_STAT_C_OVERCURRENT \ - | USB_PORT_STAT_C_RESET) << 16) - -static int dummy_hub_status(struct usb_hcd *hcd, char *buf) -{ - struct dummy_hcd *dum_hcd; - unsigned long flags; - int retval = 0; - - dum_hcd = hcd_to_dummy_hcd(hcd); - - spin_lock_irqsave(&dum_hcd->dum->lock, flags); - if (!HCD_HW_ACCESSIBLE(hcd)) - goto done; - - if (dum_hcd->resuming && time_after_eq(jiffies, dum_hcd->re_timeout)) { - dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); - dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND; - set_link_state(dum_hcd); - } - - if ((dum_hcd->port_status & PORT_C_MASK) != 0) { - *buf = (1 << 1); - dev_dbg(dummy_dev(dum_hcd), "port status 0x%08x has changes\n", - dum_hcd->port_status); - retval = 1; - if (dum_hcd->rh_state == DUMMY_RH_SUSPENDED) - usb_hcd_resume_root_hub(hcd); - } -done: - spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); - return retval; -} - -static inline void -ss_hub_descriptor(struct usb_hub_descriptor *desc) -{ - memset(desc, 0, sizeof *desc); - desc->bDescriptorType = 0x2a; - desc->bDescLength = 12; - desc->wHubCharacteristics = cpu_to_le16(0x0001); - desc->bNbrPorts = 1; - desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/ - desc->u.ss.DeviceRemovable = 0xffff; -} - -static inline void hub_descriptor(struct usb_hub_descriptor *desc) -{ - memset(desc, 0, sizeof *desc); - desc->bDescriptorType = 0x29; - desc->bDescLength = 9; - desc->wHubCharacteristics = cpu_to_le16(0x0001); - desc->bNbrPorts = 1; - desc->u.hs.DeviceRemovable[0] = 0xff; - desc->u.hs.DeviceRemovable[1] = 0xff; -} - -static int dummy_hub_control( - struct usb_hcd *hcd, - u16 typeReq, - u16 wValue, - u16 wIndex, - char *buf, - u16 wLength -) { - struct dummy_hcd *dum_hcd; - int retval = 0; - unsigned long flags; - - if (!HCD_HW_ACCESSIBLE(hcd)) - return -ETIMEDOUT; - - dum_hcd = hcd_to_dummy_hcd(hcd); - - spin_lock_irqsave(&dum_hcd->dum->lock, flags); - switch (typeReq) { - case ClearHubFeature: - break; - case ClearPortFeature: - switch (wValue) { - case USB_PORT_FEAT_SUSPEND: - if (hcd->speed == HCD_USB3) { - dev_dbg(dummy_dev(dum_hcd), - "USB_PORT_FEAT_SUSPEND req not " - "supported for USB 3.0 roothub\n"); - goto error; - } - if (dum_hcd->port_status & USB_PORT_STAT_SUSPEND) { - /* 20msec resume signaling */ - dum_hcd->resuming = 1; - dum_hcd->re_timeout = jiffies + - msecs_to_jiffies(20); - } - break; - case USB_PORT_FEAT_POWER: - if (hcd->speed == HCD_USB3) { - if (dum_hcd->port_status & USB_PORT_STAT_POWER) - dev_dbg(dummy_dev(dum_hcd), - "power-off\n"); - } else - if (dum_hcd->port_status & - USB_SS_PORT_STAT_POWER) - dev_dbg(dummy_dev(dum_hcd), - "power-off\n"); - /* FALLS THROUGH */ - default: - dum_hcd->port_status &= ~(1 << wValue); - set_link_state(dum_hcd); - } - break; - case GetHubDescriptor: - if (hcd->speed == HCD_USB3 && - (wLength < USB_DT_SS_HUB_SIZE || - wValue != (USB_DT_SS_HUB << 8))) { - dev_dbg(dummy_dev(dum_hcd), - "Wrong hub descriptor type for " - "USB 3.0 roothub.\n"); - goto error; - } - if (hcd->speed == HCD_USB3) - ss_hub_descriptor((struct usb_hub_descriptor *) buf); - else - hub_descriptor((struct usb_hub_descriptor *) buf); - break; - case GetHubStatus: - *(__le32 *) buf = cpu_to_le32(0); - break; - case GetPortStatus: - if (wIndex != 1) - retval = -EPIPE; - - /* whoever resets or resumes must GetPortStatus to - * complete it!! - */ - if (dum_hcd->resuming && - time_after_eq(jiffies, dum_hcd->re_timeout)) { - dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); - dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND; - } - if ((dum_hcd->port_status & USB_PORT_STAT_RESET) != 0 && - time_after_eq(jiffies, dum_hcd->re_timeout)) { - dum_hcd->port_status |= (USB_PORT_STAT_C_RESET << 16); - dum_hcd->port_status &= ~USB_PORT_STAT_RESET; - if (dum_hcd->dum->pullup) { - dum_hcd->port_status |= USB_PORT_STAT_ENABLE; - - if (hcd->speed < HCD_USB3) { - switch (dum_hcd->dum->gadget.speed) { - case USB_SPEED_HIGH: - dum_hcd->port_status |= - USB_PORT_STAT_HIGH_SPEED; - break; - case USB_SPEED_LOW: - dum_hcd->dum->gadget.ep0-> - maxpacket = 8; - dum_hcd->port_status |= - USB_PORT_STAT_LOW_SPEED; - break; - default: - dum_hcd->dum->gadget.speed = - USB_SPEED_FULL; - break; - } - } - } - } - set_link_state(dum_hcd); - ((__le16 *) buf)[0] = cpu_to_le16(dum_hcd->port_status); - ((__le16 *) buf)[1] = cpu_to_le16(dum_hcd->port_status >> 16); - break; - case SetHubFeature: - retval = -EPIPE; - break; - case SetPortFeature: - switch (wValue) { - case USB_PORT_FEAT_LINK_STATE: - if (hcd->speed != HCD_USB3) { - dev_dbg(dummy_dev(dum_hcd), - "USB_PORT_FEAT_LINK_STATE req not " - "supported for USB 2.0 roothub\n"); - goto error; - } - /* - * Since this is dummy we don't have an actual link so - * there is nothing to do for the SET_LINK_STATE cmd - */ - break; - case USB_PORT_FEAT_U1_TIMEOUT: - case USB_PORT_FEAT_U2_TIMEOUT: - /* TODO: add suspend/resume support! */ - if (hcd->speed != HCD_USB3) { - dev_dbg(dummy_dev(dum_hcd), - "USB_PORT_FEAT_U1/2_TIMEOUT req not " - "supported for USB 2.0 roothub\n"); - goto error; - } - break; - case USB_PORT_FEAT_SUSPEND: - /* Applicable only for USB2.0 hub */ - if (hcd->speed == HCD_USB3) { - dev_dbg(dummy_dev(dum_hcd), - "USB_PORT_FEAT_SUSPEND req not " - "supported for USB 3.0 roothub\n"); - goto error; - } - if (dum_hcd->active) { - dum_hcd->port_status |= USB_PORT_STAT_SUSPEND; - - /* HNP would happen here; for now we - * assume b_bus_req is always true. - */ - set_link_state(dum_hcd); - if (((1 << USB_DEVICE_B_HNP_ENABLE) - & dum_hcd->dum->devstatus) != 0) - dev_dbg(dummy_dev(dum_hcd), - "no HNP yet!\n"); - } - break; - case USB_PORT_FEAT_POWER: - if (hcd->speed == HCD_USB3) - dum_hcd->port_status |= USB_SS_PORT_STAT_POWER; - else - dum_hcd->port_status |= USB_PORT_STAT_POWER; - set_link_state(dum_hcd); - break; - case USB_PORT_FEAT_BH_PORT_RESET: - /* Applicable only for USB3.0 hub */ - if (hcd->speed != HCD_USB3) { - dev_dbg(dummy_dev(dum_hcd), - "USB_PORT_FEAT_BH_PORT_RESET req not " - "supported for USB 2.0 roothub\n"); - goto error; - } - /* FALLS THROUGH */ - case USB_PORT_FEAT_RESET: - /* if it's already enabled, disable */ - if (hcd->speed == HCD_USB3) { - dum_hcd->port_status = 0; - dum_hcd->port_status = - (USB_SS_PORT_STAT_POWER | - USB_PORT_STAT_CONNECTION | - USB_PORT_STAT_RESET); - } else - dum_hcd->port_status &= ~(USB_PORT_STAT_ENABLE - | USB_PORT_STAT_LOW_SPEED - | USB_PORT_STAT_HIGH_SPEED); - /* - * We want to reset device status. All but the - * Self powered feature - */ - dum_hcd->dum->devstatus &= - (1 << USB_DEVICE_SELF_POWERED); - /* - * FIXME USB3.0: what is the correct reset signaling - * interval? Is it still 50msec as for HS? - */ - dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50); - /* FALLS THROUGH */ - default: - if (hcd->speed == HCD_USB3) { - if ((dum_hcd->port_status & - USB_SS_PORT_STAT_POWER) != 0) { - dum_hcd->port_status |= (1 << wValue); - set_link_state(dum_hcd); - } - } else - if ((dum_hcd->port_status & - USB_PORT_STAT_POWER) != 0) { - dum_hcd->port_status |= (1 << wValue); - set_link_state(dum_hcd); - } - } - break; - case GetPortErrorCount: - if (hcd->speed != HCD_USB3) { - dev_dbg(dummy_dev(dum_hcd), - "GetPortErrorCount req not " - "supported for USB 2.0 roothub\n"); - goto error; - } - /* We'll always return 0 since this is a dummy hub */ - *(__le32 *) buf = cpu_to_le32(0); - break; - case SetHubDepth: - if (hcd->speed != HCD_USB3) { - dev_dbg(dummy_dev(dum_hcd), - "SetHubDepth req not supported for " - "USB 2.0 roothub\n"); - goto error; - } - break; - default: - dev_dbg(dummy_dev(dum_hcd), - "hub control req%04x v%04x i%04x l%d\n", - typeReq, wValue, wIndex, wLength); -error: - /* "protocol stall" on error */ - retval = -EPIPE; - } - spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); - - if ((dum_hcd->port_status & PORT_C_MASK) != 0) - usb_hcd_poll_rh_status(hcd); - return retval; -} - -static int dummy_bus_suspend(struct usb_hcd *hcd) -{ - struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd); - - dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__); - - spin_lock_irq(&dum_hcd->dum->lock); - dum_hcd->rh_state = DUMMY_RH_SUSPENDED; - set_link_state(dum_hcd); - hcd->state = HC_STATE_SUSPENDED; - spin_unlock_irq(&dum_hcd->dum->lock); - return 0; -} - -static int dummy_bus_resume(struct usb_hcd *hcd) -{ - struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd); - int rc = 0; - - dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__); - - spin_lock_irq(&dum_hcd->dum->lock); - if (!HCD_HW_ACCESSIBLE(hcd)) { - rc = -ESHUTDOWN; - } else { - dum_hcd->rh_state = DUMMY_RH_RUNNING; - set_link_state(dum_hcd); - if (!list_empty(&dum_hcd->urbp_list)) - mod_timer(&dum_hcd->timer, jiffies); - hcd->state = HC_STATE_RUNNING; - } - spin_unlock_irq(&dum_hcd->dum->lock); - return rc; -} - -/*-------------------------------------------------------------------------*/ - -static inline ssize_t show_urb(char *buf, size_t size, struct urb *urb) -{ - int ep = usb_pipeendpoint(urb->pipe); - - return snprintf(buf, size, - "urb/%p %s ep%d%s%s len %d/%d\n", - urb, - ({ char *s; - switch (urb->dev->speed) { - case USB_SPEED_LOW: - s = "ls"; - break; - case USB_SPEED_FULL: - s = "fs"; - break; - case USB_SPEED_HIGH: - s = "hs"; - break; - case USB_SPEED_SUPER: - s = "ss"; - break; - default: - s = "?"; - break; - }; s; }), - ep, ep ? (usb_pipein(urb->pipe) ? "in" : "out") : "", - ({ char *s; \ - switch (usb_pipetype(urb->pipe)) { \ - case PIPE_CONTROL: \ - s = ""; \ - break; \ - case PIPE_BULK: \ - s = "-bulk"; \ - break; \ - case PIPE_INTERRUPT: \ - s = "-int"; \ - break; \ - default: \ - s = "-iso"; \ - break; \ - }; s; }), - urb->actual_length, urb->transfer_buffer_length); -} - -static ssize_t show_urbs(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd); - struct urbp *urbp; - size_t size = 0; - unsigned long flags; - - spin_lock_irqsave(&dum_hcd->dum->lock, flags); - list_for_each_entry(urbp, &dum_hcd->urbp_list, urbp_list) { - size_t temp; - - temp = show_urb(buf, PAGE_SIZE - size, urbp->urb); - buf += temp; - size += temp; - } - spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); - - return size; -} -static DEVICE_ATTR(urbs, S_IRUGO, show_urbs, NULL); - -static int dummy_start_ss(struct dummy_hcd *dum_hcd) -{ - init_timer(&dum_hcd->timer); - dum_hcd->timer.function = dummy_timer; - dum_hcd->timer.data = (unsigned long)dum_hcd; - dum_hcd->rh_state = DUMMY_RH_RUNNING; - dum_hcd->stream_en_ep = 0; - INIT_LIST_HEAD(&dum_hcd->urbp_list); - dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET; - dummy_hcd_to_hcd(dum_hcd)->state = HC_STATE_RUNNING; - dummy_hcd_to_hcd(dum_hcd)->uses_new_polling = 1; -#ifdef CONFIG_USB_OTG - dummy_hcd_to_hcd(dum_hcd)->self.otg_port = 1; -#endif - return 0; - - /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */ - return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs); -} - -static int dummy_start(struct usb_hcd *hcd) -{ - struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd); - - /* - * MASTER side init ... we emulate a root hub that'll only ever - * talk to one device (the slave side). Also appears in sysfs, - * just like more familiar pci-based HCDs. - */ - if (!usb_hcd_is_primary_hcd(hcd)) - return dummy_start_ss(dum_hcd); - - spin_lock_init(&dum_hcd->dum->lock); - init_timer(&dum_hcd->timer); - dum_hcd->timer.function = dummy_timer; - dum_hcd->timer.data = (unsigned long)dum_hcd; - dum_hcd->rh_state = DUMMY_RH_RUNNING; - - INIT_LIST_HEAD(&dum_hcd->urbp_list); - - hcd->power_budget = POWER_BUDGET; - hcd->state = HC_STATE_RUNNING; - hcd->uses_new_polling = 1; - -#ifdef CONFIG_USB_OTG - hcd->self.otg_port = 1; -#endif - - /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */ - return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs); -} - -static void dummy_stop(struct usb_hcd *hcd) -{ - struct dummy *dum; - - dum = hcd_to_dummy_hcd(hcd)->dum; - device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs); - usb_gadget_unregister_driver(dum->driver); - dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n"); -} - -/*-------------------------------------------------------------------------*/ - -static int dummy_h_get_frame(struct usb_hcd *hcd) -{ - return dummy_g_get_frame(NULL); -} - -static int dummy_setup(struct usb_hcd *hcd) -{ - hcd->self.sg_tablesize = ~0; - if (usb_hcd_is_primary_hcd(hcd)) { - the_controller.hs_hcd = hcd_to_dummy_hcd(hcd); - the_controller.hs_hcd->dum = &the_controller; - /* - * Mark the first roothub as being USB 2.0. - * The USB 3.0 roothub will be registered later by - * dummy_hcd_probe() - */ - hcd->speed = HCD_USB2; - hcd->self.root_hub->speed = USB_SPEED_HIGH; - } else { - the_controller.ss_hcd = hcd_to_dummy_hcd(hcd); - the_controller.ss_hcd->dum = &the_controller; - hcd->speed = HCD_USB3; - hcd->self.root_hub->speed = USB_SPEED_SUPER; - } - return 0; -} - -/* Change a group of bulk endpoints to support multiple stream IDs */ -static int dummy_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, - struct usb_host_endpoint **eps, unsigned int num_eps, - unsigned int num_streams, gfp_t mem_flags) -{ - struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd); - unsigned long flags; - int max_stream; - int ret_streams = num_streams; - unsigned int index; - unsigned int i; - - if (!num_eps) - return -EINVAL; - - spin_lock_irqsave(&dum_hcd->dum->lock, flags); - for (i = 0; i < num_eps; i++) { - index = dummy_get_ep_idx(&eps[i]->desc); - if ((1 << index) & dum_hcd->stream_en_ep) { - ret_streams = -EINVAL; - goto out; - } - max_stream = usb_ss_max_streams(&eps[i]->ss_ep_comp); - if (!max_stream) { - ret_streams = -EINVAL; - goto out; - } - if (max_stream < ret_streams) { - dev_dbg(dummy_dev(dum_hcd), "Ep 0x%x only supports %u " - "stream IDs.\n", - eps[i]->desc.bEndpointAddress, - max_stream); - ret_streams = max_stream; - } - } - - for (i = 0; i < num_eps; i++) { - index = dummy_get_ep_idx(&eps[i]->desc); - dum_hcd->stream_en_ep |= 1 << index; - set_max_streams_for_pipe(dum_hcd, - usb_endpoint_num(&eps[i]->desc), ret_streams); - } -out: - spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); - return ret_streams; -} - -/* Reverts a group of bulk endpoints back to not using stream IDs. */ -static int dummy_free_streams(struct usb_hcd *hcd, struct usb_device *udev, - struct usb_host_endpoint **eps, unsigned int num_eps, - gfp_t mem_flags) -{ - struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd); - unsigned long flags; - int ret; - unsigned int index; - unsigned int i; - - spin_lock_irqsave(&dum_hcd->dum->lock, flags); - for (i = 0; i < num_eps; i++) { - index = dummy_get_ep_idx(&eps[i]->desc); - if (!((1 << index) & dum_hcd->stream_en_ep)) { - ret = -EINVAL; - goto out; - } - } - - for (i = 0; i < num_eps; i++) { - index = dummy_get_ep_idx(&eps[i]->desc); - dum_hcd->stream_en_ep &= ~(1 << index); - set_max_streams_for_pipe(dum_hcd, - usb_endpoint_num(&eps[i]->desc), 0); - } - ret = 0; -out: - spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); - return ret; -} - -static struct hc_driver dummy_hcd = { - .description = (char *) driver_name, - .product_desc = "Dummy host controller", - .hcd_priv_size = sizeof(struct dummy_hcd), - - .flags = HCD_USB3 | HCD_SHARED, - - .reset = dummy_setup, - .start = dummy_start, - .stop = dummy_stop, - - .urb_enqueue = dummy_urb_enqueue, - .urb_dequeue = dummy_urb_dequeue, - - .get_frame_number = dummy_h_get_frame, - - .hub_status_data = dummy_hub_status, - .hub_control = dummy_hub_control, - .bus_suspend = dummy_bus_suspend, - .bus_resume = dummy_bus_resume, - - .alloc_streams = dummy_alloc_streams, - .free_streams = dummy_free_streams, -}; - -static int dummy_hcd_probe(struct platform_device *pdev) -{ - struct usb_hcd *hs_hcd; - struct usb_hcd *ss_hcd; - int retval; - - dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc); - - if (!mod_data.is_super_speed) - dummy_hcd.flags = HCD_USB2; - hs_hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev)); - if (!hs_hcd) - return -ENOMEM; - hs_hcd->has_tt = 1; - - retval = usb_add_hcd(hs_hcd, 0, 0); - if (retval != 0) { - usb_put_hcd(hs_hcd); - return retval; - } - - if (mod_data.is_super_speed) { - ss_hcd = usb_create_shared_hcd(&dummy_hcd, &pdev->dev, - dev_name(&pdev->dev), hs_hcd); - if (!ss_hcd) { - retval = -ENOMEM; - goto dealloc_usb2_hcd; - } - - retval = usb_add_hcd(ss_hcd, 0, 0); - if (retval) - goto put_usb3_hcd; - } - return 0; - -put_usb3_hcd: - usb_put_hcd(ss_hcd); -dealloc_usb2_hcd: - usb_put_hcd(hs_hcd); - the_controller.hs_hcd = the_controller.ss_hcd = NULL; - return retval; -} - -static int dummy_hcd_remove(struct platform_device *pdev) -{ - struct dummy *dum; - - dum = hcd_to_dummy_hcd(platform_get_drvdata(pdev))->dum; - - if (dum->ss_hcd) { - usb_remove_hcd(dummy_hcd_to_hcd(dum->ss_hcd)); - usb_put_hcd(dummy_hcd_to_hcd(dum->ss_hcd)); - } - - usb_remove_hcd(dummy_hcd_to_hcd(dum->hs_hcd)); - usb_put_hcd(dummy_hcd_to_hcd(dum->hs_hcd)); - - the_controller.hs_hcd = NULL; - the_controller.ss_hcd = NULL; - - return 0; -} - -static int dummy_hcd_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct usb_hcd *hcd; - struct dummy_hcd *dum_hcd; - int rc = 0; - - dev_dbg(&pdev->dev, "%s\n", __func__); - - hcd = platform_get_drvdata(pdev); - dum_hcd = hcd_to_dummy_hcd(hcd); - if (dum_hcd->rh_state == DUMMY_RH_RUNNING) { - dev_warn(&pdev->dev, "Root hub isn't suspended!\n"); - rc = -EBUSY; - } else - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - return rc; -} - -static int dummy_hcd_resume(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - - dev_dbg(&pdev->dev, "%s\n", __func__); - - hcd = platform_get_drvdata(pdev); - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - usb_hcd_poll_rh_status(hcd); - return 0; -} - -static struct platform_driver dummy_hcd_driver = { - .probe = dummy_hcd_probe, - .remove = dummy_hcd_remove, - .suspend = dummy_hcd_suspend, - .resume = dummy_hcd_resume, - .driver = { - .name = (char *) driver_name, - .owner = THIS_MODULE, - }, -}; - -/*-------------------------------------------------------------------------*/ - -static struct platform_device *the_udc_pdev; -static struct platform_device *the_hcd_pdev; - -static int __init init(void) -{ - int retval = -ENOMEM; - - if (usb_disabled()) - return -ENODEV; - - if (!mod_data.is_high_speed && mod_data.is_super_speed) - return -EINVAL; - - the_hcd_pdev = platform_device_alloc(driver_name, -1); - if (!the_hcd_pdev) - return retval; - the_udc_pdev = platform_device_alloc(gadget_name, -1); - if (!the_udc_pdev) - goto err_alloc_udc; - - retval = platform_driver_register(&dummy_hcd_driver); - if (retval < 0) - goto err_register_hcd_driver; - retval = platform_driver_register(&dummy_udc_driver); - if (retval < 0) - goto err_register_udc_driver; - - retval = platform_device_add(the_hcd_pdev); - if (retval < 0) - goto err_add_hcd; - if (!the_controller.hs_hcd || - (!the_controller.ss_hcd && mod_data.is_super_speed)) { - /* - * The hcd was added successfully but its probe function failed - * for some reason. - */ - retval = -EINVAL; - goto err_add_udc; - } - retval = platform_device_add(the_udc_pdev); - if (retval < 0) - goto err_add_udc; - if (!platform_get_drvdata(the_udc_pdev)) { - /* - * The udc was added successfully but its probe function failed - * for some reason. - */ - retval = -EINVAL; - goto err_probe_udc; - } - return retval; - -err_probe_udc: - platform_device_del(the_udc_pdev); -err_add_udc: - platform_device_del(the_hcd_pdev); -err_add_hcd: - platform_driver_unregister(&dummy_udc_driver); -err_register_udc_driver: - platform_driver_unregister(&dummy_hcd_driver); -err_register_hcd_driver: - platform_device_put(the_udc_pdev); -err_alloc_udc: - platform_device_put(the_hcd_pdev); - return retval; -} -module_init(init); - -static void __exit cleanup(void) -{ - platform_device_unregister(the_udc_pdev); - platform_device_unregister(the_hcd_pdev); - platform_driver_unregister(&dummy_udc_driver); - platform_driver_unregister(&dummy_hcd_driver); -} -module_exit(cleanup); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/epautoconf.c b/ANDROID_3.4.5/drivers/usb/gadget/epautoconf.c deleted file mode 100644 index fc5eb804..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/epautoconf.c +++ /dev/null @@ -1,430 +0,0 @@ -/* - * epautoconf.c -- endpoint autoconfiguration for usb gadget drivers - * - * Copyright (C) 2004 David Brownell - * - * 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 -#include -#include -#include - -#include -#include - -#include -#include - -#include "gadget_chips.h" - - -/* we must assign addresses for configurable endpoints (like net2280) */ -static unsigned epnum; - -// #define MANY_ENDPOINTS -#ifdef MANY_ENDPOINTS -/* more than 15 configurable endpoints */ -static unsigned in_epnum; -#endif - - -/* - * This should work with endpoints from controller drivers sharing the - * same endpoint naming convention. By example: - * - * - ep1, ep2, ... address is fixed, not direction or type - * - ep1in, ep2out, ... address and direction are fixed, not type - * - ep1-bulk, ep2-bulk, ... address and type are fixed, not direction - * - ep1in-bulk, ep2out-iso, ... all three are fixed - * - ep-* ... no functionality restrictions - * - * Type suffixes are "-bulk", "-iso", or "-int". Numbers are decimal. - * Less common restrictions are implied by gadget_is_*(). - * - * NOTE: each endpoint is unidirectional, as specified by its USB - * descriptor; and isn't specific to a configuration or altsetting. - */ -static int -ep_matches ( - struct usb_gadget *gadget, - struct usb_ep *ep, - struct usb_endpoint_descriptor *desc, - struct usb_ss_ep_comp_descriptor *ep_comp -) -{ - u8 type; - const char *tmp; - u16 max; - - int num_req_streams = 0; - - /* endpoint already claimed? */ - if (NULL != ep->driver_data) - return 0; - - /* only support ep0 for portable CONTROL traffic */ - type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; - if (USB_ENDPOINT_XFER_CONTROL == type) - return 0; - - /* some other naming convention */ - if ('e' != ep->name[0]) - return 0; - - /* type-restriction: "-iso", "-bulk", or "-int". - * direction-restriction: "in", "out". - */ - if ('-' != ep->name[2]) { - tmp = strrchr (ep->name, '-'); - if (tmp) { - switch (type) { - case USB_ENDPOINT_XFER_INT: - /* bulk endpoints handle interrupt transfers, - * except the toggle-quirky iso-synch kind - */ - if ('s' == tmp[2]) // == "-iso" - return 0; - /* for now, avoid PXA "interrupt-in"; - * it's documented as never using DATA1. - */ - if (gadget_is_pxa (gadget) - && 'i' == tmp [1]) - return 0; - break; - case USB_ENDPOINT_XFER_BULK: - if ('b' != tmp[1]) // != "-bulk" - return 0; - break; - case USB_ENDPOINT_XFER_ISOC: - if ('s' != tmp[2]) // != "-iso" - return 0; - } - } else { - tmp = ep->name + strlen (ep->name); - } - - /* direction-restriction: "..in-..", "out-.." */ - tmp--; - if (!isdigit (*tmp)) { - if (desc->bEndpointAddress & USB_DIR_IN) { - if ('n' != *tmp) - return 0; - } else { - if ('t' != *tmp) - return 0; - } - } - } - - /* - * Get the number of required streams from the EP companion - * descriptor and see if the EP matches it - */ - if (usb_endpoint_xfer_bulk(desc)) { - if (ep_comp && gadget->max_speed >= USB_SPEED_SUPER) { - num_req_streams = ep_comp->bmAttributes & 0x1f; - if (num_req_streams > ep->max_streams) - return 0; - } - - } - - /* - * If the protocol driver hasn't yet decided on wMaxPacketSize - * and wants to know the maximum possible, provide the info. - */ - if (desc->wMaxPacketSize == 0) - desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket); - - /* endpoint maxpacket size is an input parameter, except for bulk - * where it's an output parameter representing the full speed limit. - * the usb spec fixes high speed bulk maxpacket at 512 bytes. - */ - max = 0x7ff & usb_endpoint_maxp(desc); - switch (type) { - case USB_ENDPOINT_XFER_INT: - /* INT: limit 64 bytes full speed, 1024 high/super speed */ - if (!gadget_is_dualspeed(gadget) && max > 64) - return 0; - /* FALLTHROUGH */ - - case USB_ENDPOINT_XFER_ISOC: - /* ISO: limit 1023 bytes full speed, 1024 high/super speed */ - if (ep->maxpacket < max) - return 0; - if (!gadget_is_dualspeed(gadget) && max > 1023) - return 0; - - /* BOTH: "high bandwidth" works only at high speed */ - if ((desc->wMaxPacketSize & cpu_to_le16(3<<11))) { - if (!gadget_is_dualspeed(gadget)) - return 0; - /* configure your hardware with enough buffering!! */ - } - break; - } - - /* MATCH!! */ - - /* report address */ - desc->bEndpointAddress &= USB_DIR_IN; - if (isdigit (ep->name [2])) { - u8 num = simple_strtoul (&ep->name [2], NULL, 10); - desc->bEndpointAddress |= num; -#ifdef MANY_ENDPOINTS - } else if (desc->bEndpointAddress & USB_DIR_IN) { - if (++in_epnum > 15) - return 0; - desc->bEndpointAddress = USB_DIR_IN | in_epnum; -#endif - } else { - if (++epnum > 15) - return 0; - desc->bEndpointAddress |= epnum; - } - - /* report (variable) full speed bulk maxpacket */ - if ((USB_ENDPOINT_XFER_BULK == type) && !ep_comp) { - int size = ep->maxpacket; - - /* min() doesn't work on bitfields with gcc-3.5 */ - if (size > 64) - size = 64; - desc->wMaxPacketSize = cpu_to_le16(size); - } - ep->address = desc->bEndpointAddress; - return 1; -} - -static struct usb_ep * -find_ep (struct usb_gadget *gadget, const char *name) -{ - struct usb_ep *ep; - - list_for_each_entry (ep, &gadget->ep_list, ep_list) { - if (0 == strcmp (ep->name, name)) - return ep; - } - return NULL; -} - -/** - * usb_ep_autoconfig_ss() - choose an endpoint matching the ep - * descriptor and ep companion descriptor - * @gadget: The device to which the endpoint must belong. - * @desc: Endpoint descriptor, with endpoint direction and transfer mode - * initialized. For periodic transfers, the maximum packet - * size must also be initialized. This is modified on - * success. - * @ep_comp: Endpoint companion descriptor, with the required - * number of streams. Will be modified when the chosen EP - * supports a different number of streams. - * - * This routine replaces the usb_ep_autoconfig when needed - * superspeed enhancments. If such enhancemnets are required, - * the FD should call usb_ep_autoconfig_ss directly and provide - * the additional ep_comp parameter. - * - * By choosing an endpoint to use with the specified descriptor, - * this routine simplifies writing gadget drivers that work with - * multiple USB device controllers. The endpoint would be - * passed later to usb_ep_enable(), along with some descriptor. - * - * That second descriptor won't always be the same as the first one. - * For example, isochronous endpoints can be autoconfigured for high - * bandwidth, and then used in several lower bandwidth altsettings. - * Also, high and full speed descriptors will be different. - * - * Be sure to examine and test the results of autoconfiguration - * on your hardware. This code may not make the best choices - * about how to use the USB controller, and it can't know all - * the restrictions that may apply. Some combinations of driver - * and hardware won't be able to autoconfigure. - * - * On success, this returns an un-claimed usb_ep, and modifies the endpoint - * descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value - * is initialized as if the endpoint were used at full speed and - * the bmAttribute field in the ep companion descriptor is - * updated with the assigned number of streams if it is - * different from the original value. To prevent the endpoint - * from being returned by a later autoconfig call, claim it by - * assigning ep->driver_data to some non-null value. - * - * On failure, this returns a null endpoint descriptor. - */ -struct usb_ep *usb_ep_autoconfig_ss( - struct usb_gadget *gadget, - struct usb_endpoint_descriptor *desc, - struct usb_ss_ep_comp_descriptor *ep_comp -) -{ - struct usb_ep *ep; - u8 type; - - type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; - - /* First, apply chip-specific "best usage" knowledge. - * This might make a good usb_gadget_ops hook ... - */ - if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) { - /* ep-e, ep-f are PIO with only 64 byte fifos */ - ep = find_ep (gadget, "ep-e"); - if (ep && ep_matches(gadget, ep, desc, ep_comp)) - goto found_ep; - ep = find_ep (gadget, "ep-f"); - if (ep && ep_matches(gadget, ep, desc, ep_comp)) - goto found_ep; - - } else if (gadget_is_wmt (gadget)) { - //printk(KERN_INFO "usb_ep_autoconfig find wmt_gadget \n"); - if (USB_ENDPOINT_XFER_INT == type) { - /* single buffering is enough */ - //printk(KERN_INFO "usb_ep_autoconfig try to find ep3in-int \n"); - ep = find_ep (gadget, "ep3in-int"); - if (ep && ep_matches (gadget, ep, desc, ep_comp)){ - //printk(KERN_INFO "usb_ep_autoconfig found ep3in-int \n"); - goto found_ep; - } - } else if (USB_ENDPOINT_XFER_BULK == type - && (USB_DIR_IN & desc->bEndpointAddress)) { - /* DMA may be available */ - //printk(KERN_INFO "usb_ep_autoconfig try to find ep1in-bulk \n"); - ep = find_ep (gadget, "ep1in-bulk"); - if (ep && ep_matches (gadget, ep, desc, ep_comp)){ - //printk(KERN_INFO "usb_ep_autoconfig found ep1in-bulk \n"); - goto found_ep; - } - } else if (USB_ENDPOINT_XFER_BULK == type) { - /* DMA may be available */ - //printk(KERN_INFO "usb_ep_autoconfig try to find ep2out-bulk \n"); - ep = find_ep (gadget, "ep2out-bulk"); - if (ep && ep_matches (gadget, ep, desc, ep_comp)){ - //printk(KERN_INFO "usb_ep_autoconfig found ep2out-bulk \n"); - goto found_ep; - } - } else if (USB_ENDPOINT_XFER_ISOC == type - && (USB_DIR_IN & desc->bEndpointAddress)) { - /* DMA may be available */ - //printk(KERN_INFO "usb_ep_autoconfig try to find ep1in-bulk \n"); - ep = find_ep (gadget, "ep4in-iso"); - if (ep && ep_matches (gadget, ep, desc, ep_comp)){ - //printk(KERN_INFO "usb_ep_autoconfig found ep1in-bulk \n"); - goto found_ep; - } - } - } else if (gadget_is_goku (gadget)) { - if (USB_ENDPOINT_XFER_INT == type) { - /* single buffering is enough */ - ep = find_ep(gadget, "ep3-bulk"); - if (ep && ep_matches(gadget, ep, desc, ep_comp)) - goto found_ep; - } else if (USB_ENDPOINT_XFER_BULK == type - && (USB_DIR_IN & desc->bEndpointAddress)) { - /* DMA may be available */ - ep = find_ep(gadget, "ep2-bulk"); - if (ep && ep_matches(gadget, ep, desc, - ep_comp)) - goto found_ep; - } - -#ifdef CONFIG_BLACKFIN - } else if (gadget_is_musbhdrc(gadget)) { - if ((USB_ENDPOINT_XFER_BULK == type) || - (USB_ENDPOINT_XFER_ISOC == type)) { - if (USB_DIR_IN & desc->bEndpointAddress) - ep = find_ep (gadget, "ep5in"); - else - ep = find_ep (gadget, "ep6out"); - } else if (USB_ENDPOINT_XFER_INT == type) { - if (USB_DIR_IN & desc->bEndpointAddress) - ep = find_ep(gadget, "ep1in"); - else - ep = find_ep(gadget, "ep2out"); - } else - ep = NULL; - if (ep && ep_matches(gadget, ep, desc, ep_comp)) - goto found_ep; -#endif - } - - /* Second, look at endpoints until an unclaimed one looks usable */ - list_for_each_entry (ep, &gadget->ep_list, ep_list) { - if (ep_matches(gadget, ep, desc, ep_comp)) - goto found_ep; - } - - /* Fail */ - return NULL; -found_ep: - ep->desc = NULL; - ep->comp_desc = NULL; - return ep; -} - -/** - * usb_ep_autoconfig() - choose an endpoint matching the - * descriptor - * @gadget: The device to which the endpoint must belong. - * @desc: Endpoint descriptor, with endpoint direction and transfer mode - * initialized. For periodic transfers, the maximum packet - * size must also be initialized. This is modified on success. - * - * By choosing an endpoint to use with the specified descriptor, this - * routine simplifies writing gadget drivers that work with multiple - * USB device controllers. The endpoint would be passed later to - * usb_ep_enable(), along with some descriptor. - * - * That second descriptor won't always be the same as the first one. - * For example, isochronous endpoints can be autoconfigured for high - * bandwidth, and then used in several lower bandwidth altsettings. - * Also, high and full speed descriptors will be different. - * - * Be sure to examine and test the results of autoconfiguration on your - * hardware. This code may not make the best choices about how to use the - * USB controller, and it can't know all the restrictions that may apply. - * Some combinations of driver and hardware won't be able to autoconfigure. - * - * On success, this returns an un-claimed usb_ep, and modifies the endpoint - * descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value - * is initialized as if the endpoint were used at full speed. To prevent - * the endpoint from being returned by a later autoconfig call, claim it - * by assigning ep->driver_data to some non-null value. - * - * On failure, this returns a null endpoint descriptor. - */ -struct usb_ep *usb_ep_autoconfig( - struct usb_gadget *gadget, - struct usb_endpoint_descriptor *desc -) -{ - return usb_ep_autoconfig_ss(gadget, desc, NULL); -} - - -/** - * usb_ep_autoconfig_reset - reset endpoint autoconfig state - * @gadget: device for which autoconfig state will be reset - * - * Use this for devices where one configuration may need to assign - * endpoint resources very differently from the next one. It clears - * state such as ep->driver_data and the record of assigned endpoints - * used by usb_ep_autoconfig(). - */ -void usb_ep_autoconfig_reset (struct usb_gadget *gadget) -{ - struct usb_ep *ep; - - list_for_each_entry (ep, &gadget->ep_list, ep_list) { - ep->driver_data = NULL; - } -#ifdef MANY_ENDPOINTS - in_epnum = 0; -#endif - epnum = 0; -} - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/ether.c b/ANDROID_3.4.5/drivers/usb/gadget/ether.c deleted file mode 100644 index a28f6ffc..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/ether.c +++ /dev/null @@ -1,413 +0,0 @@ -/* - * ether.c -- Ethernet gadget driver, with CDC and non-CDC options - * - * Copyright (C) 2003-2005,2008 David Brownell - * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -/* #define VERBOSE_DEBUG */ - -#include -#include - - -#if defined USB_ETH_RNDIS -# undef USB_ETH_RNDIS -#endif -#ifdef CONFIG_USB_ETH_RNDIS -# define USB_ETH_RNDIS y -#endif - -#include "u_ether.h" - - -/* - * Ethernet gadget driver -- with CDC and non-CDC options - * Builds on hardware support for a full duplex link. - * - * CDC Ethernet is the standard USB solution for sending Ethernet frames - * using USB. Real hardware tends to use the same framing protocol but look - * different for control features. This driver strongly prefers to use - * this USB-IF standard as its open-systems interoperability solution; - * most host side USB stacks (except from Microsoft) support it. - * - * This is sometimes called "CDC ECM" (Ethernet Control Model) to support - * TLA-soup. "CDC ACM" (Abstract Control Model) is for modems, and a new - * "CDC EEM" (Ethernet Emulation Model) is starting to spread. - * - * There's some hardware that can't talk CDC ECM. We make that hardware - * implement a "minimalist" vendor-agnostic CDC core: same framing, but - * link-level setup only requires activating the configuration. Only the - * endpoint descriptors, and product/vendor IDs, are relevant; no control - * operations are available. Linux supports it, but other host operating - * systems may not. (This is a subset of CDC Ethernet.) - * - * It turns out that if you add a few descriptors to that "CDC Subset", - * (Windows) host side drivers from MCCI can treat it as one submode of - * a proprietary scheme called "SAFE" ... without needing to know about - * specific product/vendor IDs. So we do that, making it easier to use - * those MS-Windows drivers. Those added descriptors make it resemble a - * CDC MDLM device, but they don't change device behavior at all. (See - * MCCI Engineering report 950198 "SAFE Networking Functions".) - * - * A third option is also in use. Rather than CDC Ethernet, or something - * simpler, Microsoft pushes their own approach: RNDIS. The published - * RNDIS specs are ambiguous and appear to be incomplete, and are also - * needlessly complex. They borrow more from CDC ACM than CDC ECM. - */ - -#define DRIVER_DESC "Ethernet Gadget" -#define DRIVER_VERSION "Memorial Day 2008" - -#ifdef USB_ETH_RNDIS -#define PREFIX "RNDIS/" -#else -#define PREFIX "" -#endif - -/* - * This driver aims for interoperability by using CDC ECM unless - * - * can_support_ecm() - * - * returns false, in which case it supports the CDC Subset. By default, - * that returns true; most hardware has no problems with CDC ECM, that's - * a good default. Previous versions of this driver had no default; this - * version changes that, removing overhead for new controller support. - * - * IF YOUR HARDWARE CAN'T SUPPORT CDC ECM, UPDATE THAT ROUTINE! - */ - -static inline bool has_rndis(void) -{ -#ifdef USB_ETH_RNDIS - return true; -#else - return false; -#endif -} - -/*-------------------------------------------------------------------------*/ - -/* - * 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 "f_ecm.c" -#include "f_subset.c" -#ifdef USB_ETH_RNDIS -#include "f_rndis.c" -#include "rndis.c" -#endif -#include "f_eem.c" -#include "u_ether.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. - * It's for devices with only CDC Ethernet configurations. - */ -#define CDC_VENDOR_NUM 0x0525 /* NetChip */ -#define CDC_PRODUCT_NUM 0xa4a1 /* Linux-USB Ethernet Gadget */ - -/* For hardware that can't talk CDC, we use the same vendor ID that - * ARM Linux has used for ethernet-over-usb, both with sa1100 and - * with pxa250. We're protocol-compatible, if the host-side drivers - * use the endpoint descriptors. bcdDevice (version) is nonzero, so - * drivers that need to hard-wire endpoint numbers have a hook. - * - * The protocol is a minimal subset of CDC Ether, which works on any bulk - * hardware that's not deeply broken ... even on hardware that can't talk - * RNDIS (like SA-1100, with no interrupt endpoint, or anything that - * doesn't handle control-OUT). - */ -#define SIMPLE_VENDOR_NUM 0x049f -#define SIMPLE_PRODUCT_NUM 0x505a - -/* For hardware that can talk RNDIS and either of the above protocols, - * use this ID ... the windows INF files will know it. Unless it's - * used with CDC Ethernet, Linux 2.4 hosts will need updates to choose - * the non-RNDIS configuration. - */ -#define RNDIS_VENDOR_NUM 0x0525 /* NetChip */ -#define RNDIS_PRODUCT_NUM 0xa4a2 /* Ethernet/RNDIS Gadget */ - -/* For EEM gadgets */ -#define EEM_VENDOR_NUM 0x1d6b /* Linux Foundation */ -#define EEM_PRODUCT_NUM 0x0102 /* EEM Gadget */ - -/*-------------------------------------------------------------------------*/ - -static struct usb_device_descriptor device_desc = { - .bLength = sizeof device_desc, - .bDescriptorType = USB_DT_DEVICE, - - .bcdUSB = cpu_to_le16 (0x0200), - - .bDeviceClass = USB_CLASS_COMM, - .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 = cpu_to_le16 (CDC_VENDOR_NUM), - .idProduct = cpu_to_le16 (CDC_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, -}; - - -/* 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 = PREFIX DRIVER_DESC, - { } /* end of list */ -}; - -static struct usb_gadget_strings stringtab_dev = { - .language = 0x0409, /* en-us */ - .strings = strings_dev, -}; - -static struct usb_gadget_strings *dev_strings[] = { - &stringtab_dev, - NULL, -}; - -static u8 hostaddr[ETH_ALEN]; - -/*-------------------------------------------------------------------------*/ - -/* - * We may not have an RNDIS configuration, but if we do it needs to be - * the first one present. That's to make Microsoft's drivers happy, - * and to follow DOCSIS 1.0 (cable modem standard). - */ -static int __init rndis_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; - } - - return rndis_bind_config(c, hostaddr); -} - -static struct usb_configuration rndis_config_driver = { - .label = "RNDIS", - .bConfigurationValue = 2, - /* .iConfiguration = DYNAMIC */ - .bmAttributes = USB_CONFIG_ATT_SELFPOWER, -}; - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_USB_ETH_EEM -static bool use_eem = 1; -#else -static bool use_eem; -#endif -module_param(use_eem, bool, 0); -MODULE_PARM_DESC(use_eem, "use CDC EEM mode"); - -/* - * We _always_ have an ECM, CDC Subset, or EEM configuration. - */ -static int __init eth_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; - } - - if (use_eem) - return eem_bind_config(c); - else if (can_support_ecm(c->cdev->gadget)) - return ecm_bind_config(c, hostaddr); - else - return geth_bind_config(c, hostaddr); -} - -static struct usb_configuration eth_config_driver = { - /* .label = f(hardware) */ - .bConfigurationValue = 1, - /* .iConfiguration = DYNAMIC */ - .bmAttributes = USB_CONFIG_ATT_SELFPOWER, -}; - -/*-------------------------------------------------------------------------*/ - -static int __init eth_bind(struct usb_composite_dev *cdev) -{ - int gcnum; - struct usb_gadget *gadget = cdev->gadget; - int status; - - /* set up network link layer */ - status = gether_setup(cdev->gadget, hostaddr); - if (status < 0) - return status; - - /* set up main config label and device descriptor */ - if (use_eem) { - /* EEM */ - eth_config_driver.label = "CDC Ethernet (EEM)"; - device_desc.idVendor = cpu_to_le16(EEM_VENDOR_NUM); - device_desc.idProduct = cpu_to_le16(EEM_PRODUCT_NUM); - } else if (can_support_ecm(cdev->gadget)) { - /* ECM */ - eth_config_driver.label = "CDC Ethernet (ECM)"; - } else { - /* CDC Subset */ - eth_config_driver.label = "CDC Subset/SAFE"; - - device_desc.idVendor = cpu_to_le16(SIMPLE_VENDOR_NUM); - device_desc.idProduct = cpu_to_le16(SIMPLE_PRODUCT_NUM); - if (!has_rndis()) - device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC; - } - - if (has_rndis()) { - /* RNDIS plus ECM-or-Subset */ - device_desc.idVendor = cpu_to_le16(RNDIS_VENDOR_NUM); - device_desc.idProduct = cpu_to_le16(RNDIS_PRODUCT_NUM); - device_desc.bNumConfigurations = 2; - } - - gcnum = usb_gadget_controller_number(gadget); - if (gcnum >= 0) - device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum); - else { - /* We assume that can_support_ecm() tells the truth; - * but if the controller isn't recognized at all then - * that assumption is a bit more likely to be wrong. - */ - dev_warn(&gadget->dev, - "controller '%s' not recognized; trying %s\n", - gadget->name, - eth_config_driver.label); - device_desc.bcdDevice = - cpu_to_le16(0x0300 | 0x0099); - } - - - /* Allocate string descriptor numbers ... note that string - * contents can be overridden by the composite_dev glue. - */ - - /* device descriptor strings: manufacturer, product */ - snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", - init_utsname()->sysname, init_utsname()->release, - 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; - - /* register our configuration(s); RNDIS first, if it's used */ - if (has_rndis()) { - status = usb_add_config(cdev, &rndis_config_driver, - rndis_do_config); - if (status < 0) - goto fail; - } - - status = usb_add_config(cdev, ð_config_driver, eth_do_config); - if (status < 0) - goto fail; - - dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n", - DRIVER_DESC); - - return 0; - -fail: - gether_cleanup(); - return status; -} - -static int __exit eth_unbind(struct usb_composite_dev *cdev) -{ - gether_cleanup(); - return 0; -} - -static struct usb_composite_driver eth_driver = { - .name = "g_ether", - .dev = &device_desc, - .strings = dev_strings, - .max_speed = USB_SPEED_SUPER, - .unbind = __exit_p(eth_unbind), -}; - -MODULE_DESCRIPTION(PREFIX DRIVER_DESC); -MODULE_AUTHOR("David Brownell, Benedikt Spanger"); -MODULE_LICENSE("GPL"); - -static int __init init(void) -{ - return usb_composite_probe(ð_driver, eth_bind); -} -module_init(init); - -static void __exit cleanup(void) -{ - usb_composite_unregister(ð_driver); -} -module_exit(cleanup); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_accessory.c b/ANDROID_3.4.5/drivers/usb/gadget/f_accessory.c deleted file mode 100644 index bfb3a777..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_accessory.c +++ /dev/null @@ -1,1190 +0,0 @@ -/* - * Gadget Function Driver for Android USB accessories - * - * Copyright (C) 2011 Google, Inc. - * Author: Mike Lockwood - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - * - */ - -/* #define DEBUG */ -/* #define VERBOSE_DEBUG */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#define BULK_BUFFER_SIZE 16384 -#define ACC_STRING_SIZE 256 - -#define PROTOCOL_VERSION 2 - -/* String IDs */ -#define INTERFACE_STRING_INDEX 0 - -/* number of tx and rx requests to allocate */ -#define TX_REQ_MAX 4 -#define RX_REQ_MAX 2 - -struct acc_hid_dev { - struct list_head list; - struct hid_device *hid; - struct acc_dev *dev; - /* accessory defined ID */ - int id; - /* HID report descriptor */ - u8 *report_desc; - /* length of HID report descriptor */ - int report_desc_len; - /* number of bytes of report_desc we have received so far */ - int report_desc_offset; -}; - -struct acc_dev { - struct usb_function function; - struct usb_composite_dev *cdev; - spinlock_t lock; - - struct usb_ep *ep_in; - struct usb_ep *ep_out; - - /* set to 1 when we connect */ - int online:1; - /* Set to 1 when we disconnect. - * Not cleared until our file is closed. - */ - int disconnected:1; - - /* strings sent by the host */ - char manufacturer[ACC_STRING_SIZE]; - char model[ACC_STRING_SIZE]; - char description[ACC_STRING_SIZE]; - char version[ACC_STRING_SIZE]; - char uri[ACC_STRING_SIZE]; - char serial[ACC_STRING_SIZE]; - - /* for acc_complete_set_string */ - int string_index; - - /* set to 1 if we have a pending start request */ - int start_requested; - - int audio_mode; - - /* synchronize access to our device file */ - atomic_t open_excl; - - struct list_head tx_idle; - - wait_queue_head_t read_wq; - wait_queue_head_t write_wq; - struct usb_request *rx_req[RX_REQ_MAX]; - int rx_done; - - /* delayed work for handling ACCESSORY_START */ - struct delayed_work start_work; - - /* worker for registering and unregistering hid devices */ - struct work_struct hid_work; - - /* list of active HID devices */ - struct list_head hid_list; - - /* list of new HID devices to register */ - struct list_head new_hid_list; - - /* list of dead HID devices to unregister */ - struct list_head dead_hid_list; -}; - -static struct usb_interface_descriptor acc_interface_desc = { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = USB_SUBCLASS_VENDOR_SPEC, - .bInterfaceProtocol = 0, -}; - -static struct usb_endpoint_descriptor acc_highspeed_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(512), -}; - -static struct usb_endpoint_descriptor acc_highspeed_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(512), -}; - -static struct usb_endpoint_descriptor acc_fullspeed_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_endpoint_descriptor acc_fullspeed_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_descriptor_header *fs_acc_descs[] = { - (struct usb_descriptor_header *) &acc_interface_desc, - (struct usb_descriptor_header *) &acc_fullspeed_in_desc, - (struct usb_descriptor_header *) &acc_fullspeed_out_desc, - NULL, -}; - -static struct usb_descriptor_header *hs_acc_descs[] = { - (struct usb_descriptor_header *) &acc_interface_desc, - (struct usb_descriptor_header *) &acc_highspeed_in_desc, - (struct usb_descriptor_header *) &acc_highspeed_out_desc, - NULL, -}; - -static struct usb_string acc_string_defs[] = { - [INTERFACE_STRING_INDEX].s = "Android Accessory Interface", - { }, /* end of list */ -}; - -static struct usb_gadget_strings acc_string_table = { - .language = 0x0409, /* en-US */ - .strings = acc_string_defs, -}; - -static struct usb_gadget_strings *acc_strings[] = { - &acc_string_table, - NULL, -}; - -/* temporary variable used between acc_open() and acc_gadget_bind() */ -static struct acc_dev *_acc_dev; - -static inline struct acc_dev *func_to_dev(struct usb_function *f) -{ - return container_of(f, struct acc_dev, function); -} - -static struct usb_request *acc_request_new(struct usb_ep *ep, int buffer_size) -{ - struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL); - if (!req) - return NULL; - - /* now allocate buffers for the requests */ - req->buf = kmalloc(buffer_size, GFP_KERNEL); - if (!req->buf) { - usb_ep_free_request(ep, req); - return NULL; - } - - return req; -} - -static void acc_request_free(struct usb_request *req, struct usb_ep *ep) -{ - if (req) { - kfree(req->buf); - usb_ep_free_request(ep, req); - } -} - -/* add a request to the tail of a list */ -static void req_put(struct acc_dev *dev, struct list_head *head, - struct usb_request *req) -{ - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - list_add_tail(&req->list, head); - spin_unlock_irqrestore(&dev->lock, flags); -} - -/* remove a request from the head of a list */ -static struct usb_request *req_get(struct acc_dev *dev, struct list_head *head) -{ - unsigned long flags; - struct usb_request *req; - - spin_lock_irqsave(&dev->lock, flags); - if (list_empty(head)) { - req = 0; - } else { - req = list_first_entry(head, struct usb_request, list); - list_del(&req->list); - } - spin_unlock_irqrestore(&dev->lock, flags); - return req; -} - -static void acc_set_disconnected(struct acc_dev *dev) -{ - dev->online = 0; - dev->disconnected = 1; -} - -static void acc_complete_in(struct usb_ep *ep, struct usb_request *req) -{ - struct acc_dev *dev = _acc_dev; - - if (req->status != 0) - acc_set_disconnected(dev); - - req_put(dev, &dev->tx_idle, req); - - wake_up(&dev->write_wq); -} - -static void acc_complete_out(struct usb_ep *ep, struct usb_request *req) -{ - struct acc_dev *dev = _acc_dev; - - dev->rx_done = 1; - if (req->status != 0) - acc_set_disconnected(dev); - - wake_up(&dev->read_wq); -} - -static void acc_complete_set_string(struct usb_ep *ep, struct usb_request *req) -{ - struct acc_dev *dev = ep->driver_data; - char *string_dest = NULL; - int length = req->actual; - - if (req->status != 0) { - pr_err("acc_complete_set_string, err %d\n", req->status); - return; - } - - switch (dev->string_index) { - case ACCESSORY_STRING_MANUFACTURER: - string_dest = dev->manufacturer; - break; - case ACCESSORY_STRING_MODEL: - string_dest = dev->model; - break; - case ACCESSORY_STRING_DESCRIPTION: - string_dest = dev->description; - break; - case ACCESSORY_STRING_VERSION: - string_dest = dev->version; - break; - case ACCESSORY_STRING_URI: - string_dest = dev->uri; - break; - case ACCESSORY_STRING_SERIAL: - string_dest = dev->serial; - break; - } - if (string_dest) { - unsigned long flags; - - if (length >= ACC_STRING_SIZE) - length = ACC_STRING_SIZE - 1; - - spin_lock_irqsave(&dev->lock, flags); - memcpy(string_dest, req->buf, length); - /* ensure zero termination */ - string_dest[length] = 0; - spin_unlock_irqrestore(&dev->lock, flags); - } else { - pr_err("unknown accessory string index %d\n", - dev->string_index); - } -} - -static void acc_complete_set_hid_report_desc(struct usb_ep *ep, - struct usb_request *req) -{ - struct acc_hid_dev *hid = req->context; - struct acc_dev *dev = hid->dev; - int length = req->actual; - - if (req->status != 0) { - pr_err("acc_complete_set_hid_report_desc, err %d\n", - req->status); - return; - } - - memcpy(hid->report_desc + hid->report_desc_offset, req->buf, length); - hid->report_desc_offset += length; - if (hid->report_desc_offset == hid->report_desc_len) { - /* After we have received the entire report descriptor - * we schedule work to initialize the HID device - */ - schedule_work(&dev->hid_work); - } -} - -static void acc_complete_send_hid_event(struct usb_ep *ep, - struct usb_request *req) -{ - struct acc_hid_dev *hid = req->context; - int length = req->actual; - - if (req->status != 0) { - pr_err("acc_complete_send_hid_event, err %d\n", req->status); - return; - } - - hid_report_raw_event(hid->hid, HID_INPUT_REPORT, req->buf, length, 1); -} - -static int acc_hid_parse(struct hid_device *hid) -{ - struct acc_hid_dev *hdev = hid->driver_data; - - hid_parse_report(hid, hdev->report_desc, hdev->report_desc_len); - return 0; -} - -static int acc_hid_start(struct hid_device *hid) -{ - return 0; -} - -static void acc_hid_stop(struct hid_device *hid) -{ -} - -static int acc_hid_open(struct hid_device *hid) -{ - return 0; -} - -static void acc_hid_close(struct hid_device *hid) -{ -} - -static struct hid_ll_driver acc_hid_ll_driver = { - .parse = acc_hid_parse, - .start = acc_hid_start, - .stop = acc_hid_stop, - .open = acc_hid_open, - .close = acc_hid_close, -}; - -static struct acc_hid_dev *acc_hid_new(struct acc_dev *dev, - int id, int desc_len) -{ - struct acc_hid_dev *hdev; - - hdev = kzalloc(sizeof(*hdev), GFP_ATOMIC); - if (!hdev) - return NULL; - hdev->report_desc = kzalloc(desc_len, GFP_ATOMIC); - if (!hdev->report_desc) { - kfree(hdev); - return NULL; - } - hdev->dev = dev; - hdev->id = id; - hdev->report_desc_len = desc_len; - - return hdev; -} - -static struct acc_hid_dev *acc_hid_get(struct list_head *list, int id) -{ - struct acc_hid_dev *hid; - - list_for_each_entry(hid, list, list) { - if (hid->id == id) - return hid; - } - return NULL; -} - -static int acc_register_hid(struct acc_dev *dev, int id, int desc_length) -{ - struct acc_hid_dev *hid; - unsigned long flags; - - /* report descriptor length must be > 0 */ - if (desc_length <= 0) - return -EINVAL; - - spin_lock_irqsave(&dev->lock, flags); - /* replace HID if one already exists with this ID */ - hid = acc_hid_get(&dev->hid_list, id); - if (!hid) - hid = acc_hid_get(&dev->new_hid_list, id); - if (hid) - list_move(&hid->list, &dev->dead_hid_list); - - hid = acc_hid_new(dev, id, desc_length); - if (!hid) { - spin_unlock_irqrestore(&dev->lock, flags); - return -ENOMEM; - } - - list_add(&hid->list, &dev->new_hid_list); - spin_unlock_irqrestore(&dev->lock, flags); - - /* schedule work to register the HID device */ - schedule_work(&dev->hid_work); - return 0; -} - -static int acc_unregister_hid(struct acc_dev *dev, int id) -{ - struct acc_hid_dev *hid; - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - hid = acc_hid_get(&dev->hid_list, id); - if (!hid) - hid = acc_hid_get(&dev->new_hid_list, id); - if (!hid) { - spin_unlock_irqrestore(&dev->lock, flags); - return -EINVAL; - } - - list_move(&hid->list, &dev->dead_hid_list); - spin_unlock_irqrestore(&dev->lock, flags); - - schedule_work(&dev->hid_work); - return 0; -} - -static int create_bulk_endpoints(struct acc_dev *dev, - struct usb_endpoint_descriptor *in_desc, - struct usb_endpoint_descriptor *out_desc) -{ - struct usb_composite_dev *cdev = dev->cdev; - struct usb_request *req; - struct usb_ep *ep; - int i; - - DBG(cdev, "create_bulk_endpoints dev: %p\n", dev); - - ep = usb_ep_autoconfig(cdev->gadget, in_desc); - if (!ep) { - DBG(cdev, "usb_ep_autoconfig for ep_in failed\n"); - return -ENODEV; - } - DBG(cdev, "usb_ep_autoconfig for ep_in got %s\n", ep->name); - ep->driver_data = dev; /* claim the endpoint */ - dev->ep_in = ep; - -#if 0 - ep = usb_ep_autoconfig(cdev->gadget, out_desc); - if (!ep) { - DBG(cdev, "usb_ep_autoconfig for ep_out failed\n"); - return -ENODEV; - } - DBG(cdev, "usb_ep_autoconfig for ep_out got %s\n", ep->name); - ep->driver_data = dev; /* claim the endpoint */ - dev->ep_out = ep; -#endif - - ep = usb_ep_autoconfig(cdev->gadget, out_desc); - if (!ep) { - DBG(cdev, "usb_ep_autoconfig for ep_out failed\n"); - return -ENODEV; - } - DBG(cdev, "usb_ep_autoconfig for ep_out got %s\n", ep->name); - ep->driver_data = dev; /* claim the endpoint */ - dev->ep_out = ep; - - /* now allocate requests for our endpoints */ - for (i = 0; i < TX_REQ_MAX; i++) { - req = acc_request_new(dev->ep_in, BULK_BUFFER_SIZE); - if (!req) - goto fail; - req->complete = acc_complete_in; - req_put(dev, &dev->tx_idle, req); - } - for (i = 0; i < RX_REQ_MAX; i++) { - req = acc_request_new(dev->ep_out, BULK_BUFFER_SIZE); - if (!req) - goto fail; - req->complete = acc_complete_out; - dev->rx_req[i] = req; - } - - return 0; - -fail: - pr_err("acc_bind() could not allocate requests\n"); - while ((req = req_get(dev, &dev->tx_idle))) - acc_request_free(req, dev->ep_in); - for (i = 0; i < RX_REQ_MAX; i++) - acc_request_free(dev->rx_req[i], dev->ep_out); - return -1; -} - -static ssize_t acc_read(struct file *fp, char __user *buf, - size_t count, loff_t *pos) -{ - struct acc_dev *dev = fp->private_data; - struct usb_request *req; - int r = count, xfer; - int ret = 0; - - pr_debug("acc_read(%d)\n", count); - - if (dev->disconnected) - return -ENODEV; - - if (count > BULK_BUFFER_SIZE) - count = BULK_BUFFER_SIZE; - - /* we will block until we're online */ - pr_debug("acc_read: waiting for online\n"); - ret = wait_event_interruptible(dev->read_wq, dev->online); - if (ret < 0) { - r = ret; - if (r == -ERESTARTSYS){ - r = -EIO; - } - - goto done; - } - -requeue_req: - /* queue a request */ - req = dev->rx_req[0]; - req->length = count; - dev->rx_done = 0; - ret = usb_ep_queue(dev->ep_out, req, GFP_KERNEL); - if (ret < 0) { - r = -EIO; - goto done; - } else { - pr_debug("rx %p queue\n", req); - } - - /* wait for a request to complete */ - ret = wait_event_interruptible(dev->read_wq, dev->rx_done); - if (ret < 0) { - r = ret; - if (r == -ERESTARTSYS){ - r = -EIO; - } - - usb_ep_dequeue(dev->ep_out, req); - goto done; - } - if (dev->online) { - /* If we got a 0-len packet, throw it back and try again. */ - if (req->actual == 0) - goto requeue_req; - - pr_debug("rx %p %d\n", req, req->actual); - xfer = (req->actual < count) ? req->actual : count; - r = xfer; - if (copy_to_user(buf, req->buf, xfer)) - r = -EFAULT; - } else - r = -EIO; - -done: - pr_debug("acc_read returning %d\n", r); - return r; -} - -static ssize_t acc_write(struct file *fp, const char __user *buf, - size_t count, loff_t *pos) -{ - struct acc_dev *dev = fp->private_data; - struct usb_request *req = 0; - int r = count, xfer; - int ret; - - pr_debug("acc_write(%d)\n", count); - - if (!dev->online || dev->disconnected) - return -ENODEV; - - while (count > 0) { - if (!dev->online) { - pr_debug("acc_write dev->error\n"); - r = -EIO; - break; - } - - /* get an idle tx request to use */ - req = 0; - ret = wait_event_interruptible(dev->write_wq, - ((req = req_get(dev, &dev->tx_idle)) || !dev->online)); - if (!req) { - r = ret; - break; - } - - if (count > BULK_BUFFER_SIZE) - xfer = BULK_BUFFER_SIZE; - else - xfer = count; - if (copy_from_user(req->buf, buf, xfer)) { - r = -EFAULT; - break; - } - - req->length = xfer; - ret = usb_ep_queue(dev->ep_in, req, GFP_KERNEL); - if (ret < 0) { - pr_debug("acc_write: xfer error %d\n", ret); - r = -EIO; - break; - } - - buf += xfer; - count -= xfer; - - /* zero this so we don't try to free it on error exit */ - req = 0; - } - - if (req) - req_put(dev, &dev->tx_idle, req); - - pr_debug("acc_write returning %d\n", r); - return r; -} - -static long acc_ioctl(struct file *fp, unsigned code, unsigned long value) -{ - struct acc_dev *dev = fp->private_data; - char *src = NULL; - int ret; - - switch (code) { - case ACCESSORY_GET_STRING_MANUFACTURER: - src = dev->manufacturer; - break; - case ACCESSORY_GET_STRING_MODEL: - src = dev->model; - break; - case ACCESSORY_GET_STRING_DESCRIPTION: - src = dev->description; - break; - case ACCESSORY_GET_STRING_VERSION: - src = dev->version; - break; - case ACCESSORY_GET_STRING_URI: - src = dev->uri; - break; - case ACCESSORY_GET_STRING_SERIAL: - src = dev->serial; - break; - case ACCESSORY_IS_START_REQUESTED: - return dev->start_requested; - case ACCESSORY_GET_AUDIO_MODE: - return dev->audio_mode; - } - if (!src) - return -EINVAL; - - ret = strlen(src) + 1; - if (copy_to_user((void __user *)value, src, ret)) - ret = -EFAULT; - return ret; -} - -static int acc_open(struct inode *ip, struct file *fp) -{ - printk(KERN_INFO "acc_open\n"); - if (atomic_xchg(&_acc_dev->open_excl, 1)) - return -EBUSY; - - _acc_dev->disconnected = 0; - fp->private_data = _acc_dev; - return 0; -} - -static int acc_release(struct inode *ip, struct file *fp) -{ - printk(KERN_INFO "acc_release\n"); - - WARN_ON(!atomic_xchg(&_acc_dev->open_excl, 0)); - _acc_dev->disconnected = 0; - return 0; -} - -/* file operations for /dev/usb_accessory */ -static const struct file_operations acc_fops = { - .owner = THIS_MODULE, - .read = acc_read, - .write = acc_write, - .unlocked_ioctl = acc_ioctl, - .open = acc_open, - .release = acc_release, -}; - -static int acc_hid_probe(struct hid_device *hdev, - const struct hid_device_id *id) -{ - int ret; - - ret = hid_parse(hdev); - if (ret) - return ret; - return hid_hw_start(hdev, HID_CONNECT_DEFAULT); -} - -static struct miscdevice acc_device = { - .minor = MISC_DYNAMIC_MINOR, - .name = "usb_accessory", - .fops = &acc_fops, -}; - -static const struct hid_device_id acc_hid_table[] = { - { HID_USB_DEVICE(HID_ANY_ID, HID_ANY_ID) }, - { } -}; - -static struct hid_driver acc_hid_driver = { - .name = "USB accessory", - .id_table = acc_hid_table, - .probe = acc_hid_probe, -}; - -static int acc_ctrlrequest(struct usb_composite_dev *cdev, - const struct usb_ctrlrequest *ctrl) -{ - struct acc_dev *dev = _acc_dev; - int value = -EOPNOTSUPP; - struct acc_hid_dev *hid; - int offset; - u8 b_requestType = ctrl->bRequestType; - u8 b_request = ctrl->bRequest; - u16 w_index = le16_to_cpu(ctrl->wIndex); - u16 w_value = le16_to_cpu(ctrl->wValue); - u16 w_length = le16_to_cpu(ctrl->wLength); - unsigned long flags; - -/* - printk(KERN_INFO "acc_ctrlrequest " - "%02x.%02x v%04x i%04x l%u\n", - b_requestType, b_request, - w_value, w_index, w_length); -*/ - - if (b_requestType == (USB_DIR_OUT | USB_TYPE_VENDOR)) { - if (b_request == ACCESSORY_START) { - dev->start_requested = 1; - schedule_delayed_work( - &dev->start_work, msecs_to_jiffies(10)); - value = 0; - } else if (b_request == ACCESSORY_SEND_STRING) { - dev->string_index = w_index; - cdev->gadget->ep0->driver_data = dev; - cdev->req->complete = acc_complete_set_string; - value = w_length; - } else if (b_request == ACCESSORY_SET_AUDIO_MODE && - w_index == 0 && w_length == 0) { - dev->audio_mode = w_value; - value = 0; - } else if (b_request == ACCESSORY_REGISTER_HID) { - value = acc_register_hid(dev, w_value, w_index); - } else if (b_request == ACCESSORY_UNREGISTER_HID) { - value = acc_unregister_hid(dev, w_value); - } else if (b_request == ACCESSORY_SET_HID_REPORT_DESC) { - spin_lock_irqsave(&dev->lock, flags); - hid = acc_hid_get(&dev->new_hid_list, w_value); - spin_unlock_irqrestore(&dev->lock, flags); - if (!hid) { - value = -EINVAL; - goto err; - } - offset = w_index; - if (offset != hid->report_desc_offset - || offset + w_length > hid->report_desc_len) { - value = -EINVAL; - goto err; - } - cdev->req->context = hid; - cdev->req->complete = acc_complete_set_hid_report_desc; - value = w_length; - } else if (b_request == ACCESSORY_SEND_HID_EVENT) { - spin_lock_irqsave(&dev->lock, flags); - hid = acc_hid_get(&dev->hid_list, w_value); - spin_unlock_irqrestore(&dev->lock, flags); - if (!hid) { - value = -EINVAL; - goto err; - } - cdev->req->context = hid; - cdev->req->complete = acc_complete_send_hid_event; - value = w_length; - } - } else if (b_requestType == (USB_DIR_IN | USB_TYPE_VENDOR)) { - if (b_request == ACCESSORY_GET_PROTOCOL) { - *((u16 *)cdev->req->buf) = PROTOCOL_VERSION; - value = sizeof(u16); - - /* clear any string left over from a previous session */ - memset(dev->manufacturer, 0, sizeof(dev->manufacturer)); - memset(dev->model, 0, sizeof(dev->model)); - memset(dev->description, 0, sizeof(dev->description)); - memset(dev->version, 0, sizeof(dev->version)); - memset(dev->uri, 0, sizeof(dev->uri)); - memset(dev->serial, 0, sizeof(dev->serial)); - dev->start_requested = 0; - dev->audio_mode = 0; - } - } - - if (value >= 0) { - cdev->req->zero = 0; - cdev->req->length = value; - value = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC); - if (value < 0) - ERROR(cdev, "%s setup response queue error\n", - __func__); - } - -err: - if (value == -EOPNOTSUPP) - VDBG(cdev, - "unknown class-specific control req " - "%02x.%02x v%04x i%04x l%u\n", - ctrl->bRequestType, ctrl->bRequest, - w_value, w_index, w_length); - return value; -} - -static int -acc_function_bind(struct usb_configuration *c, struct usb_function *f) -{ - struct usb_composite_dev *cdev = c->cdev; - struct acc_dev *dev = func_to_dev(f); - int id; - int ret; - - DBG(cdev, "acc_function_bind dev: %p\n", dev); - - ret = hid_register_driver(&acc_hid_driver); - if (ret) - return ret; - - dev->start_requested = 0; - - /* allocate interface ID(s) */ - id = usb_interface_id(c, f); - if (id < 0) - return id; - acc_interface_desc.bInterfaceNumber = id; - - /* allocate endpoints */ - ret = create_bulk_endpoints(dev, &acc_fullspeed_in_desc, - &acc_fullspeed_out_desc); - if (ret) - return ret; - - /* support high speed hardware */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - acc_highspeed_in_desc.bEndpointAddress = - acc_fullspeed_in_desc.bEndpointAddress; - acc_highspeed_out_desc.bEndpointAddress = - acc_fullspeed_out_desc.bEndpointAddress; - } - - DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", - gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", - f->name, dev->ep_in->name, dev->ep_out->name); - return 0; -} - -static void -kill_all_hid_devices(struct acc_dev *dev) -{ - struct acc_hid_dev *hid; - struct list_head *entry, *temp; - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - list_for_each_safe(entry, temp, &dev->hid_list) { - hid = list_entry(entry, struct acc_hid_dev, list); - list_del(&hid->list); - list_add(&hid->list, &dev->dead_hid_list); - } - list_for_each_safe(entry, temp, &dev->new_hid_list) { - hid = list_entry(entry, struct acc_hid_dev, list); - list_del(&hid->list); - list_add(&hid->list, &dev->dead_hid_list); - } - spin_unlock_irqrestore(&dev->lock, flags); - - schedule_work(&dev->hid_work); -} - -static void -acc_hid_unbind(struct acc_dev *dev) -{ - hid_unregister_driver(&acc_hid_driver); - kill_all_hid_devices(dev); -} - -static void -acc_function_unbind(struct usb_configuration *c, struct usb_function *f) -{ - struct acc_dev *dev = func_to_dev(f); - struct usb_request *req; - int i; - - while ((req = req_get(dev, &dev->tx_idle))) - acc_request_free(req, dev->ep_in); - for (i = 0; i < RX_REQ_MAX; i++) - acc_request_free(dev->rx_req[i], dev->ep_out); - - acc_hid_unbind(dev); -} - -static void acc_start_work(struct work_struct *data) -{ - char *envp[2] = { "ACCESSORY=START", NULL }; - kobject_uevent_env(&acc_device.this_device->kobj, KOBJ_CHANGE, envp); -} - -static int acc_hid_init(struct acc_hid_dev *hdev) -{ - struct hid_device *hid; - int ret; - - hid = hid_allocate_device(); - if (IS_ERR(hid)) - return PTR_ERR(hid); - - hid->ll_driver = &acc_hid_ll_driver; - hid->dev.parent = acc_device.this_device; - - hid->bus = BUS_USB; - hid->vendor = HID_ANY_ID; - hid->product = HID_ANY_ID; - hid->driver_data = hdev; - ret = hid_add_device(hid); - if (ret) { - pr_err("can't add hid device: %d\n", ret); - hid_destroy_device(hid); - return ret; - } - - hdev->hid = hid; - return 0; -} - -static void acc_hid_delete(struct acc_hid_dev *hid) -{ - kfree(hid->report_desc); - kfree(hid); -} - -static void acc_hid_work(struct work_struct *data) -{ - struct acc_dev *dev = _acc_dev; - struct list_head *entry, *temp; - struct acc_hid_dev *hid; - struct list_head new_list, dead_list; - unsigned long flags; - - INIT_LIST_HEAD(&new_list); - - spin_lock_irqsave(&dev->lock, flags); - - /* copy hids that are ready for initialization to new_list */ - list_for_each_safe(entry, temp, &dev->new_hid_list) { - hid = list_entry(entry, struct acc_hid_dev, list); - if (hid->report_desc_offset == hid->report_desc_len) - list_move(&hid->list, &new_list); - } - - if (list_empty(&dev->dead_hid_list)) { - INIT_LIST_HEAD(&dead_list); - } else { - /* move all of dev->dead_hid_list to dead_list */ - dead_list.prev = dev->dead_hid_list.prev; - dead_list.next = dev->dead_hid_list.next; - dead_list.next->prev = &dead_list; - dead_list.prev->next = &dead_list; - INIT_LIST_HEAD(&dev->dead_hid_list); - } - - spin_unlock_irqrestore(&dev->lock, flags); - - /* register new HID devices */ - list_for_each_safe(entry, temp, &new_list) { - hid = list_entry(entry, struct acc_hid_dev, list); - if (acc_hid_init(hid)) { - pr_err("can't add HID device %p\n", hid); - acc_hid_delete(hid); - } else { - spin_lock_irqsave(&dev->lock, flags); - list_move(&hid->list, &dev->hid_list); - spin_unlock_irqrestore(&dev->lock, flags); - } - } - - /* remove dead HID devices */ - list_for_each_safe(entry, temp, &dead_list) { - hid = list_entry(entry, struct acc_hid_dev, list); - list_del(&hid->list); - if (hid->hid) - hid_destroy_device(hid->hid); - acc_hid_delete(hid); - } -} - -static int acc_function_set_alt(struct usb_function *f, - unsigned intf, unsigned alt) -{ - struct acc_dev *dev = func_to_dev(f); - struct usb_composite_dev *cdev = f->config->cdev; - int ret; - - DBG(cdev, "acc_function_set_alt intf: %d alt: %d\n", intf, alt); - - ret = config_ep_by_speed(cdev->gadget, f, dev->ep_in); - if (ret) - return ret; - - ret = usb_ep_enable(dev->ep_in); - if (ret) - return ret; - - ret = config_ep_by_speed(cdev->gadget, f, dev->ep_out); - if (ret) - return ret; - - ret = usb_ep_enable(dev->ep_out); - if (ret) { - usb_ep_disable(dev->ep_in); - return ret; - } - - dev->online = 1; - - /* readers may be blocked waiting for us to go online */ - wake_up(&dev->read_wq); - return 0; -} - -static void acc_function_disable(struct usb_function *f) -{ - struct acc_dev *dev = func_to_dev(f); - struct usb_composite_dev *cdev = dev->cdev; - - DBG(cdev, "acc_function_disable\n"); - acc_set_disconnected(dev); - usb_ep_disable(dev->ep_in); - usb_ep_disable(dev->ep_out); - - /* readers may be blocked waiting for us to go online */ - wake_up(&dev->read_wq); - - VDBG(cdev, "%s disabled\n", dev->function.name); -} - -static int acc_bind_config(struct usb_configuration *c) -{ - struct acc_dev *dev = _acc_dev; - int ret; - - printk(KERN_INFO "acc_bind_config\n"); - - /* allocate a string ID for our interface */ - if (acc_string_defs[INTERFACE_STRING_INDEX].id == 0) { - ret = usb_string_id(c->cdev); - if (ret < 0) - return ret; - acc_string_defs[INTERFACE_STRING_INDEX].id = ret; - acc_interface_desc.iInterface = ret; - } - - dev->cdev = c->cdev; - dev->function.name = "accessory"; - dev->function.strings = acc_strings, - dev->function.descriptors = fs_acc_descs; - dev->function.hs_descriptors = hs_acc_descs; - dev->function.bind = acc_function_bind; - dev->function.unbind = acc_function_unbind; - dev->function.set_alt = acc_function_set_alt; - dev->function.disable = acc_function_disable; - - return usb_add_function(c, &dev->function); -} - -static int acc_setup(void) -{ - struct acc_dev *dev; - int ret; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - spin_lock_init(&dev->lock); - init_waitqueue_head(&dev->read_wq); - init_waitqueue_head(&dev->write_wq); - atomic_set(&dev->open_excl, 0); - INIT_LIST_HEAD(&dev->tx_idle); - INIT_LIST_HEAD(&dev->hid_list); - INIT_LIST_HEAD(&dev->new_hid_list); - INIT_LIST_HEAD(&dev->dead_hid_list); - INIT_DELAYED_WORK(&dev->start_work, acc_start_work); - INIT_WORK(&dev->hid_work, acc_hid_work); - - /* _acc_dev must be set before calling usb_gadget_register_driver */ - _acc_dev = dev; - - ret = misc_register(&acc_device); - if (ret) - goto err; - - return 0; - -err: - kfree(dev); - pr_err("USB accessory gadget driver failed to initialize\n"); - return ret; -} - -static void acc_disconnect(void) -{ - /* unregister all HID devices if USB is disconnected */ - kill_all_hid_devices(_acc_dev); -} - -static void acc_cleanup(void) -{ - misc_deregister(&acc_device); - kfree(_acc_dev); - _acc_dev = NULL; -} diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_acm.c b/ANDROID_3.4.5/drivers/usb/gadget/f_acm.c deleted file mode 100644 index d672250a..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_acm.c +++ /dev/null @@ -1,814 +0,0 @@ -/* - * f_acm.c -- USB CDC serial (ACM) function driver - * - * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com) - * Copyright (C) 2008 by David Brownell - * Copyright (C) 2008 by Nokia Corporation - * Copyright (C) 2009 by Samsung Electronics - * Author: Michal Nazarewicz (mina86@mina86.com) - * - * This software is distributed under the terms of the GNU General - * Public License ("GPL") as published by the Free Software Foundation, - * either version 2 of that License or (at your option) any later version. - */ - -/* #define VERBOSE_DEBUG */ - -#include -#include -#include - -#include "u_serial.h" -#include "gadget_chips.h" - - -/* - * This CDC ACM function support just wraps control functions and - * notifications around the generic serial-over-usb code. - * - * Because CDC ACM is standardized by the USB-IF, many host operating - * systems have drivers for it. Accordingly, ACM is the preferred - * interop solution for serial-port type connections. The control - * models are often not necessary, and in any case don't do much in - * this bare-bones implementation. - * - * Note that even MS-Windows has some support for ACM. However, that - * support is somewhat broken because when you use ACM in a composite - * device, having multiple interfaces confuses the poor OS. It doesn't - * seem to understand CDC Union descriptors. The new "association" - * descriptors (roughly equivalent to CDC Unions) may sometimes help. - */ - -struct f_acm { - struct gserial port; - u8 ctrl_id, data_id; - u8 port_num; - - u8 pending; - - /* lock is mostly for pending and notify_req ... they get accessed - * by callbacks both from tty (open/close/break) under its spinlock, - * and notify_req.complete() which can't use that lock. - */ - spinlock_t lock; - - struct usb_ep *notify; - struct usb_request *notify_req; - - struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */ - - /* SetControlLineState request -- CDC 1.1 section 6.2.14 (INPUT) */ - u16 port_handshake_bits; -#define ACM_CTRL_RTS (1 << 1) /* unused with full duplex */ -#define ACM_CTRL_DTR (1 << 0) /* host is ready for data r/w */ - - /* SerialState notification -- CDC 1.1 section 6.3.5 (OUTPUT) */ - u16 serial_state; -#define ACM_CTRL_OVERRUN (1 << 6) -#define ACM_CTRL_PARITY (1 << 5) -#define ACM_CTRL_FRAMING (1 << 4) -#define ACM_CTRL_RI (1 << 3) -#define ACM_CTRL_BRK (1 << 2) -#define ACM_CTRL_DSR (1 << 1) -#define ACM_CTRL_DCD (1 << 0) -}; - -static inline struct f_acm *func_to_acm(struct usb_function *f) -{ - return container_of(f, struct f_acm, port.func); -} - -static inline struct f_acm *port_to_acm(struct gserial *p) -{ - return container_of(p, struct f_acm, port); -} - -/*-------------------------------------------------------------------------*/ - -/* notification endpoint uses smallish and infrequent fixed-size messages */ - -#define GS_LOG2_NOTIFY_INTERVAL 5 /* 1 << 5 == 32 msec */ -#define GS_NOTIFY_MAXPACKET 10 /* notification + 2 bytes */ - -/* interface and class descriptors: */ - -static struct usb_interface_assoc_descriptor -acm_iad_descriptor = { - .bLength = sizeof acm_iad_descriptor, - .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, - - /* .bFirstInterface = DYNAMIC, */ - .bInterfaceCount = 2, // control + data - .bFunctionClass = USB_CLASS_COMM, - .bFunctionSubClass = USB_CDC_SUBCLASS_ACM, - .bFunctionProtocol = USB_CDC_ACM_PROTO_AT_V25TER, - /* .iFunction = DYNAMIC */ -}; - - -static struct usb_interface_descriptor acm_control_interface_desc = { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - /* .bInterfaceNumber = DYNAMIC */ - .bNumEndpoints = 1, - .bInterfaceClass = USB_CLASS_COMM, - .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, - .bInterfaceProtocol = USB_CDC_ACM_PROTO_AT_V25TER, - /* .iInterface = DYNAMIC */ -}; - -static struct usb_interface_descriptor acm_data_interface_desc = { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - /* .bInterfaceNumber = DYNAMIC */ - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_CDC_DATA, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - /* .iInterface = DYNAMIC */ -}; - -static struct usb_cdc_header_desc acm_header_desc = { - .bLength = sizeof(acm_header_desc), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_HEADER_TYPE, - .bcdCDC = cpu_to_le16(0x0110), -}; - -static struct usb_cdc_call_mgmt_descriptor -acm_call_mgmt_descriptor = { - .bLength = sizeof(acm_call_mgmt_descriptor), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, - .bmCapabilities = 0, - /* .bDataInterface = DYNAMIC */ -}; - -static struct usb_cdc_acm_descriptor acm_descriptor = { - .bLength = sizeof(acm_descriptor), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_ACM_TYPE, - .bmCapabilities = USB_CDC_CAP_LINE, -}; - -static struct usb_cdc_union_desc acm_union_desc = { - .bLength = sizeof(acm_union_desc), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_UNION_TYPE, - /* .bMasterInterface0 = DYNAMIC */ - /* .bSlaveInterface0 = DYNAMIC */ -}; - -/* full speed support: */ - -static struct usb_endpoint_descriptor acm_fs_notify_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(GS_NOTIFY_MAXPACKET), - .bInterval = 1 << GS_LOG2_NOTIFY_INTERVAL, -}; - -static struct usb_endpoint_descriptor acm_fs_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_endpoint_descriptor acm_fs_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_descriptor_header *acm_fs_function[] = { - (struct usb_descriptor_header *) &acm_iad_descriptor, - (struct usb_descriptor_header *) &acm_control_interface_desc, - (struct usb_descriptor_header *) &acm_header_desc, - (struct usb_descriptor_header *) &acm_call_mgmt_descriptor, - (struct usb_descriptor_header *) &acm_descriptor, - (struct usb_descriptor_header *) &acm_union_desc, - (struct usb_descriptor_header *) &acm_fs_notify_desc, - (struct usb_descriptor_header *) &acm_data_interface_desc, - (struct usb_descriptor_header *) &acm_fs_in_desc, - (struct usb_descriptor_header *) &acm_fs_out_desc, - NULL, -}; - -/* high speed support: */ - -static struct usb_endpoint_descriptor acm_hs_notify_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(GS_NOTIFY_MAXPACKET), - .bInterval = GS_LOG2_NOTIFY_INTERVAL+4, -}; - -static struct usb_endpoint_descriptor acm_hs_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), -}; - -static struct usb_endpoint_descriptor acm_hs_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), -}; - -static struct usb_descriptor_header *acm_hs_function[] = { - (struct usb_descriptor_header *) &acm_iad_descriptor, - (struct usb_descriptor_header *) &acm_control_interface_desc, - (struct usb_descriptor_header *) &acm_header_desc, - (struct usb_descriptor_header *) &acm_call_mgmt_descriptor, - (struct usb_descriptor_header *) &acm_descriptor, - (struct usb_descriptor_header *) &acm_union_desc, - (struct usb_descriptor_header *) &acm_hs_notify_desc, - (struct usb_descriptor_header *) &acm_data_interface_desc, - (struct usb_descriptor_header *) &acm_hs_in_desc, - (struct usb_descriptor_header *) &acm_hs_out_desc, - NULL, -}; - -static struct usb_endpoint_descriptor acm_ss_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(1024), -}; - -static struct usb_endpoint_descriptor acm_ss_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(1024), -}; - -static struct usb_ss_ep_comp_descriptor acm_ss_bulk_comp_desc = { - .bLength = sizeof acm_ss_bulk_comp_desc, - .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, -}; - -static struct usb_descriptor_header *acm_ss_function[] = { - (struct usb_descriptor_header *) &acm_iad_descriptor, - (struct usb_descriptor_header *) &acm_control_interface_desc, - (struct usb_descriptor_header *) &acm_header_desc, - (struct usb_descriptor_header *) &acm_call_mgmt_descriptor, - (struct usb_descriptor_header *) &acm_descriptor, - (struct usb_descriptor_header *) &acm_union_desc, - (struct usb_descriptor_header *) &acm_hs_notify_desc, - (struct usb_descriptor_header *) &acm_ss_bulk_comp_desc, - (struct usb_descriptor_header *) &acm_data_interface_desc, - (struct usb_descriptor_header *) &acm_ss_in_desc, - (struct usb_descriptor_header *) &acm_ss_bulk_comp_desc, - (struct usb_descriptor_header *) &acm_ss_out_desc, - (struct usb_descriptor_header *) &acm_ss_bulk_comp_desc, - NULL, -}; - -/* string descriptors: */ - -#define ACM_CTRL_IDX 0 -#define ACM_DATA_IDX 1 -#define ACM_IAD_IDX 2 - -/* static strings, in UTF-8 */ -static struct usb_string acm_string_defs[] = { - [ACM_CTRL_IDX].s = "CDC Abstract Control Model (ACM)", - [ACM_DATA_IDX].s = "CDC ACM Data", - [ACM_IAD_IDX ].s = "CDC Serial", - { /* ZEROES END LIST */ }, -}; - -static struct usb_gadget_strings acm_string_table = { - .language = 0x0409, /* en-us */ - .strings = acm_string_defs, -}; - -static struct usb_gadget_strings *acm_strings[] = { - &acm_string_table, - NULL, -}; - -/*-------------------------------------------------------------------------*/ - -/* ACM control ... data handling is delegated to tty library code. - * The main task of this function is to activate and deactivate - * that code based on device state; track parameters like line - * speed, handshake state, and so on; and issue notifications. - */ - -static void acm_complete_set_line_coding(struct usb_ep *ep, - struct usb_request *req) -{ - struct f_acm *acm = ep->driver_data; - struct usb_composite_dev *cdev = acm->port.func.config->cdev; - - if (req->status != 0) { - DBG(cdev, "acm ttyGS%d completion, err %d\n", - acm->port_num, req->status); - return; - } - - /* normal completion */ - if (req->actual != sizeof(acm->port_line_coding)) { - DBG(cdev, "acm ttyGS%d short resp, len %d\n", - acm->port_num, req->actual); - usb_ep_set_halt(ep); - } else { - struct usb_cdc_line_coding *value = req->buf; - - /* REVISIT: we currently just remember this data. - * If we change that, (a) validate it first, then - * (b) update whatever hardware needs updating, - * (c) worry about locking. This is information on - * the order of 9600-8-N-1 ... most of which means - * nothing unless we control a real RS232 line. - */ - acm->port_line_coding = *value; - } -} - -static int acm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) -{ - struct f_acm *acm = func_to_acm(f); - 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 - * CDC class messages; interface activation uses set_alt(). - * - * Note CDC spec table 4 lists the ACM request profile. It requires - * encapsulated command support ... we don't handle any, and respond - * to them by stalling. Options include get/set/clear comm features - * (not that useful) and SEND_BREAK. - */ - switch ((ctrl->bRequestType << 8) | ctrl->bRequest) { - - /* SET_LINE_CODING ... just read and save what the host sends */ - case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) - | USB_CDC_REQ_SET_LINE_CODING: - if (w_length != sizeof(struct usb_cdc_line_coding) - || w_index != acm->ctrl_id) - goto invalid; - - value = w_length; - cdev->gadget->ep0->driver_data = acm; - req->complete = acm_complete_set_line_coding; - break; - - /* GET_LINE_CODING ... return what host sent, or initial value */ - case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) - | USB_CDC_REQ_GET_LINE_CODING: - if (w_index != acm->ctrl_id) - goto invalid; - - value = min_t(unsigned, w_length, - sizeof(struct usb_cdc_line_coding)); - memcpy(req->buf, &acm->port_line_coding, value); - break; - - /* SET_CONTROL_LINE_STATE ... save what the host sent */ - case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) - | USB_CDC_REQ_SET_CONTROL_LINE_STATE: - if (w_index != acm->ctrl_id) - goto invalid; - - value = 0; - - /* FIXME we should not allow data to flow until the - * host sets the ACM_CTRL_DTR bit; and when it clears - * that bit, we should return to that no-flow state. - */ - acm->port_handshake_bits = w_value; - break; - - default: -invalid: - VDBG(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, "acm ttyGS%d req%02x.%02x v%04x i%04x l%d\n", - acm->port_num, 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, "acm response on ttyGS%d, err %d\n", - acm->port_num, value); - } - - /* device either stalls (value < 0) or reports success */ - return value; -} - -static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) -{ - struct f_acm *acm = func_to_acm(f); - struct usb_composite_dev *cdev = f->config->cdev; - - /* we know alt == 0, so this is an activation or a reset */ - - if (intf == acm->ctrl_id) { - if (acm->notify->driver_data) { - VDBG(cdev, "reset acm control interface %d\n", intf); - usb_ep_disable(acm->notify); - } else { - VDBG(cdev, "init acm ctrl interface %d\n", intf); - if (config_ep_by_speed(cdev->gadget, f, acm->notify)) - return -EINVAL; - } - usb_ep_enable(acm->notify); - acm->notify->driver_data = acm; - - } else if (intf == acm->data_id) { - if (acm->port.in->driver_data) { - DBG(cdev, "reset acm ttyGS%d\n", acm->port_num); - gserial_disconnect(&acm->port); - } - if (!acm->port.in->desc || !acm->port.out->desc) { - DBG(cdev, "activate acm ttyGS%d\n", acm->port_num); - if (config_ep_by_speed(cdev->gadget, f, - acm->port.in) || - config_ep_by_speed(cdev->gadget, f, - acm->port.out)) { - acm->port.in->desc = NULL; - acm->port.out->desc = NULL; - return -EINVAL; - } - } - gserial_connect(&acm->port, acm->port_num); - - } else - return -EINVAL; - - return 0; -} - -static void acm_disable(struct usb_function *f) -{ - struct f_acm *acm = func_to_acm(f); - struct usb_composite_dev *cdev = f->config->cdev; - - DBG(cdev, "acm ttyGS%d deactivated\n", acm->port_num); - gserial_disconnect(&acm->port); - usb_ep_disable(acm->notify); - acm->notify->driver_data = NULL; -} - -/*-------------------------------------------------------------------------*/ - -/** - * acm_cdc_notify - issue CDC notification to host - * @acm: wraps host to be notified - * @type: notification type - * @value: Refer to cdc specs, wValue field. - * @data: data to be sent - * @length: size of data - * Context: irqs blocked, acm->lock held, acm_notify_req non-null - * - * Returns zero on success or a negative errno. - * - * See section 6.3.5 of the CDC 1.1 specification for information - * about the only notification we issue: SerialState change. - */ -static int acm_cdc_notify(struct f_acm *acm, u8 type, u16 value, - void *data, unsigned length) -{ - struct usb_ep *ep = acm->notify; - struct usb_request *req; - struct usb_cdc_notification *notify; - const unsigned len = sizeof(*notify) + length; - void *buf; - int status; - - req = acm->notify_req; - acm->notify_req = NULL; - acm->pending = false; - - req->length = len; - notify = req->buf; - buf = notify + 1; - - notify->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS - | USB_RECIP_INTERFACE; - notify->bNotificationType = type; - notify->wValue = cpu_to_le16(value); - notify->wIndex = cpu_to_le16(acm->ctrl_id); - notify->wLength = cpu_to_le16(length); - memcpy(buf, data, length); - - /* ep_queue() can complete immediately if it fills the fifo... */ - spin_unlock(&acm->lock); - status = usb_ep_queue(ep, req, GFP_ATOMIC); - spin_lock(&acm->lock); - - if (status < 0) { - ERROR(acm->port.func.config->cdev, - "acm ttyGS%d can't notify serial state, %d\n", - acm->port_num, status); - acm->notify_req = req; - } - - return status; -} - -static int acm_notify_serial_state(struct f_acm *acm) -{ - struct usb_composite_dev *cdev = acm->port.func.config->cdev; - int status; - - spin_lock(&acm->lock); - if (acm->notify_req) { - DBG(cdev, "acm ttyGS%d serial state %04x\n", - acm->port_num, acm->serial_state); - status = acm_cdc_notify(acm, USB_CDC_NOTIFY_SERIAL_STATE, - 0, &acm->serial_state, sizeof(acm->serial_state)); - } else { - acm->pending = true; - status = 0; - } - spin_unlock(&acm->lock); - return status; -} - -static void acm_cdc_notify_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct f_acm *acm = req->context; - u8 doit = false; - - /* on this call path we do NOT hold the port spinlock, - * which is why ACM needs its own spinlock - */ - spin_lock(&acm->lock); - if (req->status != -ESHUTDOWN) - doit = acm->pending; - acm->notify_req = req; - spin_unlock(&acm->lock); - - if (doit) - acm_notify_serial_state(acm); -} - -/* connect == the TTY link is open */ - -static void acm_connect(struct gserial *port) -{ - struct f_acm *acm = port_to_acm(port); - - acm->serial_state |= ACM_CTRL_DSR | ACM_CTRL_DCD; - acm_notify_serial_state(acm); -} - -static void acm_disconnect(struct gserial *port) -{ - struct f_acm *acm = port_to_acm(port); - - acm->serial_state &= ~(ACM_CTRL_DSR | ACM_CTRL_DCD); - acm_notify_serial_state(acm); -} - -static int acm_send_break(struct gserial *port, int duration) -{ - struct f_acm *acm = port_to_acm(port); - u16 state; - - state = acm->serial_state; - state &= ~ACM_CTRL_BRK; - if (duration) - state |= ACM_CTRL_BRK; - - acm->serial_state = state; - return acm_notify_serial_state(acm); -} - -/*-------------------------------------------------------------------------*/ - -/* ACM function driver setup/binding */ -static int -acm_bind(struct usb_configuration *c, struct usb_function *f) -{ - struct usb_composite_dev *cdev = c->cdev; - struct f_acm *acm = func_to_acm(f); - int status; - struct usb_ep *ep; - - /* allocate instance-specific interface IDs, and patch descriptors */ - status = usb_interface_id(c, f); - if (status < 0) - goto fail; - acm->ctrl_id = status; - acm_iad_descriptor.bFirstInterface = status; - - acm_control_interface_desc.bInterfaceNumber = status; - acm_union_desc .bMasterInterface0 = status; - - status = usb_interface_id(c, f); - if (status < 0) - goto fail; - acm->data_id = status; - - acm_data_interface_desc.bInterfaceNumber = status; - acm_union_desc.bSlaveInterface0 = status; - acm_call_mgmt_descriptor.bDataInterface = status; - - status = -ENODEV; - - /* allocate instance-specific endpoints */ - ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_in_desc); - if (!ep) - goto fail; - acm->port.in = ep; - ep->driver_data = cdev; /* claim */ - - ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_out_desc); - if (!ep) - goto fail; - acm->port.out = ep; - ep->driver_data = cdev; /* claim */ - - ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_notify_desc); - if (!ep) - goto fail; - acm->notify = ep; - ep->driver_data = cdev; /* claim */ - - /* allocate notification */ - acm->notify_req = gs_alloc_req(ep, - sizeof(struct usb_cdc_notification) + 2, - GFP_KERNEL); - if (!acm->notify_req) - goto fail; - - acm->notify_req->complete = acm_cdc_notify_complete; - acm->notify_req->context = acm; - - /* copy descriptors */ - f->descriptors = usb_copy_descriptors(acm_fs_function); - if (!f->descriptors) - goto fail; - - /* support all relevant hardware speeds... we expect that when - * hardware is dual speed, all bulk-capable endpoints work at - * both speeds - */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - acm_hs_in_desc.bEndpointAddress = - acm_fs_in_desc.bEndpointAddress; - acm_hs_out_desc.bEndpointAddress = - acm_fs_out_desc.bEndpointAddress; - acm_hs_notify_desc.bEndpointAddress = - acm_fs_notify_desc.bEndpointAddress; - - /* copy descriptors */ - f->hs_descriptors = usb_copy_descriptors(acm_hs_function); - } - if (gadget_is_superspeed(c->cdev->gadget)) { - acm_ss_in_desc.bEndpointAddress = - acm_fs_in_desc.bEndpointAddress; - acm_ss_out_desc.bEndpointAddress = - acm_fs_out_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->ss_descriptors = usb_copy_descriptors(acm_ss_function); - if (!f->ss_descriptors) - goto fail; - } - - DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n", - acm->port_num, - gadget_is_superspeed(c->cdev->gadget) ? "super" : - gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", - acm->port.in->name, acm->port.out->name, - acm->notify->name); - return 0; - -fail: - if (acm->notify_req) - gs_free_req(acm->notify, acm->notify_req); - - /* we might as well release our claims on endpoints */ - if (acm->notify) - acm->notify->driver_data = NULL; - if (acm->port.out) - acm->port.out->driver_data = NULL; - if (acm->port.in) - acm->port.in->driver_data = NULL; - - ERROR(cdev, "%s/%p: can't bind, err %d\n", f->name, f, status); - - return status; -} - -static void -acm_unbind(struct usb_configuration *c, struct usb_function *f) -{ - struct f_acm *acm = func_to_acm(f); - - if (gadget_is_dualspeed(c->cdev->gadget)) - usb_free_descriptors(f->hs_descriptors); - if (gadget_is_superspeed(c->cdev->gadget)) - usb_free_descriptors(f->ss_descriptors); - usb_free_descriptors(f->descriptors); - gs_free_req(acm->notify, acm->notify_req); - kfree(acm); -} - -/* Some controllers can't support CDC ACM ... */ -static inline bool can_support_cdc(struct usb_configuration *c) -{ - /* everything else is *probably* fine ... */ - return true; -} - -/** - * acm_bind_config - add a CDC ACM function to a configuration - * @c: the configuration to support the CDC ACM instance - * @port_num: /dev/ttyGS* port this interface will use - * Context: single threaded during gadget setup - * - * Returns zero on success, else negative errno. - * - * Caller must have called @gserial_setup() with enough ports to - * handle all the ones it binds. Caller is also responsible - * for calling @gserial_cleanup() before module unload. - */ -int acm_bind_config(struct usb_configuration *c, u8 port_num) -{ - struct f_acm *acm; - int status; - - if (!can_support_cdc(c)) - return -EINVAL; - - /* REVISIT might want instance-specific strings to help - * distinguish instances ... - */ - - /* maybe allocate device-global string IDs, and patch descriptors */ - if (acm_string_defs[ACM_CTRL_IDX].id == 0) { - status = usb_string_id(c->cdev); - if (status < 0) - return status; - acm_string_defs[ACM_CTRL_IDX].id = status; - - acm_control_interface_desc.iInterface = status; - - status = usb_string_id(c->cdev); - if (status < 0) - return status; - acm_string_defs[ACM_DATA_IDX].id = status; - - acm_data_interface_desc.iInterface = status; - - status = usb_string_id(c->cdev); - if (status < 0) - return status; - acm_string_defs[ACM_IAD_IDX].id = status; - - acm_iad_descriptor.iFunction = status; - } - - /* allocate and initialize one new instance */ - acm = kzalloc(sizeof *acm, GFP_KERNEL); - if (!acm) - return -ENOMEM; - - spin_lock_init(&acm->lock); - - acm->port_num = port_num; - - acm->port.connect = acm_connect; - acm->port.disconnect = acm_disconnect; - acm->port.send_break = acm_send_break; - - acm->port.func.name = "acm"; - acm->port.func.strings = acm_strings; - /* descriptors are per-instance copies */ - acm->port.func.bind = acm_bind; - acm->port.func.unbind = acm_unbind; - acm->port.func.set_alt = acm_set_alt; - acm->port.func.setup = acm_setup; - acm->port.func.disable = acm_disable; - - status = usb_add_function(c, &acm->port.func); - if (status) - kfree(acm); - return status; -} diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_adb.c b/ANDROID_3.4.5/drivers/usb/gadget/f_adb.c deleted file mode 100644 index 0eea2191..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_adb.c +++ /dev/null @@ -1,620 +0,0 @@ -/* - * Gadget Driver for Android ADB - * - * Copyright (C) 2008 Google, Inc. - * Author: Mike Lockwood - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ADB_BULK_BUFFER_SIZE 4096 - -/* number of tx requests to allocate */ -#define TX_REQ_MAX 4 - -static const char adb_shortname[] = "android_adb"; - -struct adb_dev { - struct usb_function function; - struct usb_composite_dev *cdev; - spinlock_t lock; - - struct usb_ep *ep_in; - struct usb_ep *ep_out; - - int online; - int error; - - atomic_t read_excl; - atomic_t write_excl; - atomic_t open_excl; - - struct list_head tx_idle; - - wait_queue_head_t read_wq; - wait_queue_head_t write_wq; - struct usb_request *rx_req; - int rx_done; -}; - -static struct usb_interface_descriptor adb_interface_desc = { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, - .bNumEndpoints = 2, - .bInterfaceClass = 0xFF, - .bInterfaceSubClass = 0x42, - .bInterfaceProtocol = 1, -}; - -static struct usb_endpoint_descriptor adb_highspeed_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(512), -}; - -static struct usb_endpoint_descriptor adb_highspeed_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(512), -}; - -static struct usb_endpoint_descriptor adb_fullspeed_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_endpoint_descriptor adb_fullspeed_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_descriptor_header *fs_adb_descs[] = { - (struct usb_descriptor_header *) &adb_interface_desc, - (struct usb_descriptor_header *) &adb_fullspeed_in_desc, - (struct usb_descriptor_header *) &adb_fullspeed_out_desc, - NULL, -}; - -static struct usb_descriptor_header *hs_adb_descs[] = { - (struct usb_descriptor_header *) &adb_interface_desc, - (struct usb_descriptor_header *) &adb_highspeed_in_desc, - (struct usb_descriptor_header *) &adb_highspeed_out_desc, - NULL, -}; - -static void adb_ready_callback(void); -static void adb_closed_callback(void); - -/* temporary variable used between adb_open() and adb_gadget_bind() */ -static struct adb_dev *_adb_dev; - -static inline struct adb_dev *func_to_adb(struct usb_function *f) -{ - return container_of(f, struct adb_dev, function); -} - - -static struct usb_request *adb_request_new(struct usb_ep *ep, int buffer_size) -{ - struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL); - if (!req) - return NULL; - - /* now allocate buffers for the requests */ - req->buf = kmalloc(buffer_size, GFP_KERNEL); - if (!req->buf) { - usb_ep_free_request(ep, req); - return NULL; - } - - return req; -} - -static void adb_request_free(struct usb_request *req, struct usb_ep *ep) -{ - if (req) { - kfree(req->buf); - usb_ep_free_request(ep, req); - } -} - -static inline int adb_lock(atomic_t *excl) -{ - if (atomic_inc_return(excl) == 1) { - return 0; - } else { - atomic_dec(excl); - return -1; - } -} - -static inline void adb_unlock(atomic_t *excl) -{ - atomic_dec(excl); -} - -/* add a request to the tail of a list */ -void adb_req_put(struct adb_dev *dev, struct list_head *head, - struct usb_request *req) -{ - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - list_add_tail(&req->list, head); - spin_unlock_irqrestore(&dev->lock, flags); -} - -/* remove a request from the head of a list */ -struct usb_request *adb_req_get(struct adb_dev *dev, struct list_head *head) -{ - unsigned long flags; - struct usb_request *req; - - spin_lock_irqsave(&dev->lock, flags); - if (list_empty(head)) { - req = 0; - } else { - req = list_first_entry(head, struct usb_request, list); - list_del(&req->list); - } - spin_unlock_irqrestore(&dev->lock, flags); - return req; -} - -static void adb_complete_in(struct usb_ep *ep, struct usb_request *req) -{ - struct adb_dev *dev = _adb_dev; - - if (req->status != 0) - dev->error = 1; - - adb_req_put(dev, &dev->tx_idle, req); - - wake_up(&dev->write_wq); -} - -static void adb_complete_out(struct usb_ep *ep, struct usb_request *req) -{ - struct adb_dev *dev = _adb_dev; - - dev->rx_done = 1; - if (req->status != 0 && req->status != -ECONNRESET) - dev->error = 1; - - wake_up(&dev->read_wq); -} - -static int adb_create_bulk_endpoints(struct adb_dev *dev, - struct usb_endpoint_descriptor *in_desc, - struct usb_endpoint_descriptor *out_desc) -{ - struct usb_composite_dev *cdev = dev->cdev; - struct usb_request *req; - struct usb_ep *ep; - int i; - - DBG(cdev, "create_bulk_endpoints dev: %p\n", dev); - - ep = usb_ep_autoconfig(cdev->gadget, in_desc); - if (!ep) { - DBG(cdev, "usb_ep_autoconfig for ep_in failed\n"); - return -ENODEV; - } - DBG(cdev, "usb_ep_autoconfig for ep_in got %s\n", ep->name); - ep->driver_data = dev; /* claim the endpoint */ - dev->ep_in = ep; - - ep = usb_ep_autoconfig(cdev->gadget, out_desc); - if (!ep) { - DBG(cdev, "usb_ep_autoconfig for ep_out failed\n"); - return -ENODEV; - } - DBG(cdev, "usb_ep_autoconfig for adb ep_out got %s\n", ep->name); - ep->driver_data = dev; /* claim the endpoint */ - dev->ep_out = ep; - - /* now allocate requests for our endpoints */ - req = adb_request_new(dev->ep_out, ADB_BULK_BUFFER_SIZE); - if (!req) - goto fail; - req->complete = adb_complete_out; - dev->rx_req = req; - - for (i = 0; i < TX_REQ_MAX; i++) { - req = adb_request_new(dev->ep_in, ADB_BULK_BUFFER_SIZE); - if (!req) - goto fail; - req->complete = adb_complete_in; - adb_req_put(dev, &dev->tx_idle, req); - } - - return 0; - -fail: - printk(KERN_ERR "adb_bind() could not allocate requests\n"); - return -1; -} - -static ssize_t adb_read(struct file *fp, char __user *buf, - size_t count, loff_t *pos) -{ - struct adb_dev *dev = fp->private_data; - struct usb_request *req; - int r = count, xfer; - int ret; - - pr_debug("adb_read(%d)\n", count); - if (!_adb_dev) - return -ENODEV; - - if (count > ADB_BULK_BUFFER_SIZE) - return -EINVAL; - - if (adb_lock(&dev->read_excl)) - return -EBUSY; - - /* we will block until we're online */ - while (!(dev->online || dev->error)) { - pr_debug("adb_read: waiting for online state\n"); - ret = wait_event_interruptible(dev->read_wq, - (dev->online || dev->error)); - if (ret < 0) { - adb_unlock(&dev->read_excl); - return ret; - } - } - if (dev->error) { - r = -EIO; - goto done; - } - -requeue_req: - /* queue a request */ - req = dev->rx_req; - req->length = count; - dev->rx_done = 0; - ret = usb_ep_queue(dev->ep_out, req, GFP_ATOMIC); - if (ret < 0) { - pr_debug("adb_read: failed to queue req %p (%d)\n", req, ret); - r = -EIO; - dev->error = 1; - goto done; - } else { - pr_debug("rx %p queue\n", req); - } - - /* wait for a request to complete */ - ret = wait_event_interruptible(dev->read_wq, dev->rx_done); - if (ret < 0) { - if (ret != -ERESTARTSYS) - dev->error = 1; - r = ret; - usb_ep_dequeue(dev->ep_out, req); - goto done; - } - if (!dev->error) { - /* If we got a 0-len packet, throw it back and try again. */ - if (req->actual == 0) - goto requeue_req; - - pr_debug("rx %p %d\n", req, req->actual); - xfer = (req->actual < count) ? req->actual : count; - if (copy_to_user(buf, req->buf, xfer)) - r = -EFAULT; - - } else - r = -EIO; - -done: - adb_unlock(&dev->read_excl); - pr_debug("adb_read returning %d\n", r); - return r; -} - -static ssize_t adb_write(struct file *fp, const char __user *buf, - size_t count, loff_t *pos) -{ - struct adb_dev *dev = fp->private_data; - struct usb_request *req = 0; - int r = count, xfer; - int ret; - - if (!_adb_dev) - return -ENODEV; - pr_debug("adb_write(%d)\n", count); - - if (adb_lock(&dev->write_excl)) - return -EBUSY; - - while (count > 0) { - if (dev->error) { - pr_debug("adb_write dev->error\n"); - r = -EIO; - break; - } - - /* get an idle tx request to use */ - req = 0; - ret = wait_event_interruptible(dev->write_wq, - (req = adb_req_get(dev, &dev->tx_idle)) || dev->error); - - if (ret < 0) { - r = ret; - break; - } - - if (req != 0) { - if (count > ADB_BULK_BUFFER_SIZE) - xfer = ADB_BULK_BUFFER_SIZE; - else - xfer = count; - if (copy_from_user(req->buf, buf, xfer)) { - r = -EFAULT; - break; - } - - req->length = xfer; - ret = usb_ep_queue(dev->ep_in, req, GFP_ATOMIC); - if (ret < 0) { - pr_debug("adb_write: xfer error %d\n", ret); - dev->error = 1; - r = -EIO; - break; - } - - buf += xfer; - count -= xfer; - - /* zero this so we don't try to free it on error exit */ - req = 0; - } - } - - if (req) - adb_req_put(dev, &dev->tx_idle, req); - - adb_unlock(&dev->write_excl); - pr_debug("adb_write returning %d\n", r); - return r; -} - -static int adb_open(struct inode *ip, struct file *fp) -{ - pr_info("adb_open\n"); - if (!_adb_dev) - return -ENODEV; - - if (adb_lock(&_adb_dev->open_excl)) - return -EBUSY; - - fp->private_data = _adb_dev; - - /* clear the error latch */ - _adb_dev->error = 0; - - adb_ready_callback(); - - return 0; -} - -static int adb_release(struct inode *ip, struct file *fp) -{ - pr_info("adb_release\n"); - - adb_closed_callback(); - - adb_unlock(&_adb_dev->open_excl); - return 0; -} - -/* file operations for ADB device /dev/android_adb */ -static const struct file_operations adb_fops = { - .owner = THIS_MODULE, - .read = adb_read, - .write = adb_write, - .open = adb_open, - .release = adb_release, -}; - -static struct miscdevice adb_device = { - .minor = MISC_DYNAMIC_MINOR, - .name = adb_shortname, - .fops = &adb_fops, -}; - - - - -static int -adb_function_bind(struct usb_configuration *c, struct usb_function *f) -{ - struct usb_composite_dev *cdev = c->cdev; - struct adb_dev *dev = func_to_adb(f); - int id; - int ret; - - dev->cdev = cdev; - DBG(cdev, "adb_function_bind dev: %p\n", dev); - - /* allocate interface ID(s) */ - id = usb_interface_id(c, f); - if (id < 0) - return id; - adb_interface_desc.bInterfaceNumber = id; - - /* allocate endpoints */ - ret = adb_create_bulk_endpoints(dev, &adb_fullspeed_in_desc, - &adb_fullspeed_out_desc); - if (ret) - return ret; - - /* support high speed hardware */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - adb_highspeed_in_desc.bEndpointAddress = - adb_fullspeed_in_desc.bEndpointAddress; - adb_highspeed_out_desc.bEndpointAddress = - adb_fullspeed_out_desc.bEndpointAddress; - } - - DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", - gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", - f->name, dev->ep_in->name, dev->ep_out->name); - return 0; -} - -static void -adb_function_unbind(struct usb_configuration *c, struct usb_function *f) -{ - struct adb_dev *dev = func_to_adb(f); - struct usb_request *req; - - - dev->online = 0; - dev->error = 1; - - wake_up(&dev->read_wq); - extern void wmt_cleanup_done_thread(int number); - wmt_cleanup_done_thread(1); - adb_request_free(dev->rx_req, dev->ep_out); - while ((req = adb_req_get(dev, &dev->tx_idle))) - adb_request_free(req, dev->ep_in); -} - -static int adb_function_set_alt(struct usb_function *f, - unsigned intf, unsigned alt) -{ - struct adb_dev *dev = func_to_adb(f); - struct usb_composite_dev *cdev = f->config->cdev; - int ret; - - DBG(cdev, "adb_function_set_alt intf: %d alt: %d\n", intf, alt); - - ret = config_ep_by_speed(cdev->gadget, f, dev->ep_in); - if (ret) - return ret; - - ret = usb_ep_enable(dev->ep_in); - if (ret) - return ret; - - ret = config_ep_by_speed(cdev->gadget, f, dev->ep_out); - if (ret) - return ret; - - ret = usb_ep_enable(dev->ep_out); - if (ret) { - usb_ep_disable(dev->ep_in); - return ret; - } - dev->online = 1; - - /* readers may be blocked waiting for us to go online */ - wake_up(&dev->read_wq); - return 0; -} - -static void adb_function_disable(struct usb_function *f) -{ - struct adb_dev *dev = func_to_adb(f); - struct usb_composite_dev *cdev = dev->cdev; - - DBG(cdev, "adb_function_disable cdev %p\n", cdev); - dev->online = 0; - dev->error = 1; - usb_ep_disable(dev->ep_in); - usb_ep_disable(dev->ep_out); - - /* readers may be blocked waiting for us to go online */ - wake_up(&dev->read_wq); - - VDBG(cdev, "%s disabled\n", dev->function.name); -} - -static int adb_bind_config(struct usb_configuration *c) -{ - struct adb_dev *dev = _adb_dev; - - printk(KERN_INFO "adb_bind_config\n"); - - dev->cdev = c->cdev; - dev->function.name = "adb"; - dev->function.descriptors = fs_adb_descs; - dev->function.hs_descriptors = hs_adb_descs; - dev->function.bind = adb_function_bind; - dev->function.unbind = adb_function_unbind; - dev->function.set_alt = adb_function_set_alt; - dev->function.disable = adb_function_disable; - - return usb_add_function(c, &dev->function); -} - -static int adb_setup(void) -{ - struct adb_dev *dev; - int ret; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - spin_lock_init(&dev->lock); - - init_waitqueue_head(&dev->read_wq); - init_waitqueue_head(&dev->write_wq); - - atomic_set(&dev->open_excl, 0); - atomic_set(&dev->read_excl, 0); - atomic_set(&dev->write_excl, 0); - - INIT_LIST_HEAD(&dev->tx_idle); - - _adb_dev = dev; - - ret = misc_register(&adb_device); - if (ret) - goto err; - - return 0; - -err: - kfree(dev); - printk(KERN_ERR "adb gadget driver failed to initialize\n"); - return ret; -} - -static void adb_cleanup(void) -{ - misc_deregister(&adb_device); - - kfree(_adb_dev); - _adb_dev = NULL; -} diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_audio_source.c b/ANDROID_3.4.5/drivers/usb/gadget/f_audio_source.c deleted file mode 100644 index c757409e..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_audio_source.c +++ /dev/null @@ -1,828 +0,0 @@ -/* - * Gadget Function Driver for USB audio source device - * - * Copyright (C) 2012 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - * - */ - -#include -#include -#include -#include -#include -#include - -#define SAMPLE_RATE 44100 -#define FRAMES_PER_MSEC (SAMPLE_RATE / 1000) - -#define IN_EP_MAX_PACKET_SIZE 384 - -/* Number of requests to allocate */ -#define IN_EP_REQ_COUNT 4 - -#define AUDIO_AC_INTERFACE 0 -#define AUDIO_AS_INTERFACE 1 -#define AUDIO_NUM_INTERFACES 2 - -/* B.3.1 Standard AC Interface Descriptor */ -static struct usb_interface_descriptor ac_interface_desc = { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bNumEndpoints = 0, - .bInterfaceClass = USB_CLASS_AUDIO, - .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, -}; - -DECLARE_UAC_AC_HEADER_DESCRIPTOR(2); - -#define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(AUDIO_NUM_INTERFACES) -/* 1 input terminal, 1 output terminal and 1 feature unit */ -#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH \ - + UAC_DT_INPUT_TERMINAL_SIZE + UAC_DT_OUTPUT_TERMINAL_SIZE \ - + UAC_DT_FEATURE_UNIT_SIZE(0)) -/* B.3.2 Class-Specific AC Interface Descriptor */ -static struct uac1_ac_header_descriptor_2 ac_header_desc = { - .bLength = UAC_DT_AC_HEADER_LENGTH, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = UAC_HEADER, - .bcdADC = __constant_cpu_to_le16(0x0100), - .wTotalLength = __constant_cpu_to_le16(UAC_DT_TOTAL_LENGTH), - .bInCollection = AUDIO_NUM_INTERFACES, - .baInterfaceNr = { - [0] = AUDIO_AC_INTERFACE, - [1] = AUDIO_AS_INTERFACE, - } -}; - -#define INPUT_TERMINAL_ID 1 -static struct uac_input_terminal_descriptor input_terminal_desc = { - .bLength = UAC_DT_INPUT_TERMINAL_SIZE, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = UAC_INPUT_TERMINAL, - .bTerminalID = INPUT_TERMINAL_ID, - .wTerminalType = UAC_INPUT_TERMINAL_MICROPHONE, - .bAssocTerminal = 0, - .wChannelConfig = 0x3, -}; - -DECLARE_UAC_FEATURE_UNIT_DESCRIPTOR(0); - -#define FEATURE_UNIT_ID 2 -static struct uac_feature_unit_descriptor_0 feature_unit_desc = { - .bLength = UAC_DT_FEATURE_UNIT_SIZE(0), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = UAC_FEATURE_UNIT, - .bUnitID = FEATURE_UNIT_ID, - .bSourceID = INPUT_TERMINAL_ID, - .bControlSize = 2, -}; - -#define OUTPUT_TERMINAL_ID 3 -static struct uac1_output_terminal_descriptor output_terminal_desc = { - .bLength = UAC_DT_OUTPUT_TERMINAL_SIZE, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, - .bTerminalID = OUTPUT_TERMINAL_ID, - .wTerminalType = UAC_TERMINAL_STREAMING, - .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 uac1_as_header_descriptor as_header_desc = { - .bLength = UAC_DT_AS_HEADER_SIZE, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = UAC_AS_GENERAL, - .bTerminalLink = INPUT_TERMINAL_ID, - .bDelay = 1, - .wFormatTag = UAC_FORMAT_TYPE_I_PCM, -}; - -DECLARE_UAC_FORMAT_TYPE_I_DISCRETE_DESC(1); - -static struct uac_format_type_i_discrete_descriptor_1 as_type_i_desc = { - .bLength = UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = UAC_FORMAT_TYPE, - .bFormatType = UAC_FORMAT_TYPE_I, - .bSubframeSize = 2, - .bBitResolution = 16, - .bSamFreqType = 1, -}; - -/* Standard ISO IN Endpoint Descriptor for highspeed */ -static struct usb_endpoint_descriptor hs_as_in_ep_desc = { - .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_SYNC_SYNC - | USB_ENDPOINT_XFER_ISOC, - .wMaxPacketSize = __constant_cpu_to_le16(IN_EP_MAX_PACKET_SIZE), - .bInterval = 4, /* poll 1 per millisecond */ -}; - -/* Standard ISO IN Endpoint Descriptor for highspeed */ -static struct usb_endpoint_descriptor fs_as_in_ep_desc = { - .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_SYNC_SYNC - | USB_ENDPOINT_XFER_ISOC, - .wMaxPacketSize = __constant_cpu_to_le16(IN_EP_MAX_PACKET_SIZE), - .bInterval = 1, /* poll 1 per millisecond */ -}; - -/* Class-specific AS ISO OUT Endpoint Descriptor */ -static struct uac_iso_endpoint_descriptor as_iso_in_desc = { - .bLength = UAC_ISO_ENDPOINT_DESC_SIZE, - .bDescriptorType = USB_DT_CS_ENDPOINT, - .bDescriptorSubtype = UAC_EP_GENERAL, - .bmAttributes = 1, - .bLockDelayUnits = 1, - .wLockDelay = __constant_cpu_to_le16(1), -}; - -static struct usb_descriptor_header *hs_audio_desc[] = { - (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 *)&hs_as_in_ep_desc, - (struct usb_descriptor_header *)&as_iso_in_desc, - NULL, -}; - -static struct usb_descriptor_header *fs_audio_desc[] = { - (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 *)&fs_as_in_ep_desc, - (struct usb_descriptor_header *)&as_iso_in_desc, - NULL, -}; - -static struct snd_pcm_hardware audio_hw_info = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_BATCH | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER, - - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .channels_min = 2, - .channels_max = 2, - .rate_min = SAMPLE_RATE, - .rate_max = SAMPLE_RATE, - - .buffer_bytes_max = 1024 * 1024, - .period_bytes_min = 64, - .period_bytes_max = 512 * 1024, - .periods_min = 2, - .periods_max = 1024, -}; - -/*-------------------------------------------------------------------------*/ - -struct audio_source_config { - int card; - int device; -}; - -struct audio_dev { - struct usb_function func; - struct snd_card *card; - struct snd_pcm *pcm; - struct snd_pcm_substream *substream; - - struct list_head idle_reqs; - struct usb_ep *in_ep; - - spinlock_t lock; - - /* beginning, end and current position in our buffer */ - void *buffer_start; - void *buffer_end; - void *buffer_pos; - - /* byte size of a "period" */ - unsigned int period; - /* bytes sent since last call to snd_pcm_period_elapsed */ - unsigned int period_offset; - /* time we started playing */ - ktime_t start_time; - /* number of frames sent since start_time */ - s64 frames_sent; -}; - -static inline struct audio_dev *func_to_audio(struct usb_function *f) -{ - return container_of(f, struct audio_dev, func); -} - -/*-------------------------------------------------------------------------*/ - -static struct usb_request *audio_request_new(struct usb_ep *ep, int buffer_size) -{ - struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL); - if (!req) - return NULL; - - req->buf = kmalloc(buffer_size, GFP_KERNEL); - if (!req->buf) { - usb_ep_free_request(ep, req); - return NULL; - } - req->length = buffer_size; - return req; -} - -static void audio_request_free(struct usb_request *req, struct usb_ep *ep) -{ - if (req) { - kfree(req->buf); - usb_ep_free_request(ep, req); - } -} - -static void audio_req_put(struct audio_dev *audio, struct usb_request *req) -{ - unsigned long flags; - - spin_lock_irqsave(&audio->lock, flags); - list_add_tail(&req->list, &audio->idle_reqs); - spin_unlock_irqrestore(&audio->lock, flags); -} - -static struct usb_request *audio_req_get(struct audio_dev *audio) -{ - unsigned long flags; - struct usb_request *req; - - spin_lock_irqsave(&audio->lock, flags); - if (list_empty(&audio->idle_reqs)) { - req = 0; - } else { - req = list_first_entry(&audio->idle_reqs, struct usb_request, - list); - list_del(&req->list); - } - spin_unlock_irqrestore(&audio->lock, flags); - return req; -} - -/* send the appropriate number of packets to match our bitrate */ -static void audio_send(struct audio_dev *audio) -{ - struct snd_pcm_runtime *runtime; - struct usb_request *req; - int length, length1, length2, ret; - s64 msecs; - s64 frames; - ktime_t now; - - /* audio->substream will be null if we have been closed */ - if (!audio->substream) - return; - /* audio->buffer_pos will be null if we have been stopped */ - if (!audio->buffer_pos) - return; - - runtime = audio->substream->runtime; - - /* compute number of frames to send */ - now = ktime_get(); - msecs = ktime_to_ns(now) - ktime_to_ns(audio->start_time); - do_div(msecs, 1000000); - frames = msecs * SAMPLE_RATE; - do_div(frames, 1000); - - /* Readjust our frames_sent if we fall too far behind. - * If we get too far behind it is better to drop some frames than - * to keep sending data too fast in an attempt to catch up. - */ - if (frames - audio->frames_sent > 10 * FRAMES_PER_MSEC) - audio->frames_sent = frames - FRAMES_PER_MSEC; - - frames -= audio->frames_sent; - - /* We need to send something to keep the pipeline going */ - if (frames <= 0) - frames = FRAMES_PER_MSEC; - - while (frames > 0) { - req = audio_req_get(audio); - if (!req) - break; - - length = frames_to_bytes(runtime, frames); - if (length > IN_EP_MAX_PACKET_SIZE) - length = IN_EP_MAX_PACKET_SIZE; - - if (audio->buffer_pos + length > audio->buffer_end) - length1 = audio->buffer_end - audio->buffer_pos; - else - length1 = length; - memcpy(req->buf, audio->buffer_pos, length1); - if (length1 < length) { - /* Wrap around and copy remaining length - * at beginning of buffer. - */ - length2 = length - length1; - memcpy(req->buf + length1, audio->buffer_start, - length2); - audio->buffer_pos = audio->buffer_start + length2; - } else { - audio->buffer_pos += length1; - if (audio->buffer_pos >= audio->buffer_end) - audio->buffer_pos = audio->buffer_start; - } - - req->length = length; - ret = usb_ep_queue(audio->in_ep, req, GFP_ATOMIC); - if (ret < 0) { - pr_err("usb_ep_queue failed ret: %d\n", ret); - audio_req_put(audio, req); - break; - } - - frames -= bytes_to_frames(runtime, length); - audio->frames_sent += bytes_to_frames(runtime, length); - } -} - -static void audio_control_complete(struct usb_ep *ep, struct usb_request *req) -{ - /* nothing to do here */ -} - -static void audio_data_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct audio_dev *audio = req->context; - - pr_debug("audio_data_complete req->status %d req->actual %d\n", - req->status, req->actual); - - audio_req_put(audio, req); - - if (!audio->buffer_start || req->status) - return; - - audio->period_offset += req->actual; - if (audio->period_offset >= audio->period) { - snd_pcm_period_elapsed(audio->substream); - audio->period_offset = 0; - } - audio_send(audio); -} - -static int audio_set_endpoint_req(struct usb_function *f, - const struct usb_ctrlrequest *ctrl) -{ - 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); - - pr_debug("bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n", - ctrl->bRequest, w_value, len, ep); - - switch (ctrl->bRequest) { - case UAC_SET_CUR: - case UAC_SET_MIN: - case UAC_SET_MAX: - case UAC_SET_RES: - value = len; - break; - default: - break; - } - - return value; -} - -static int audio_get_endpoint_req(struct usb_function *f, - const struct usb_ctrlrequest *ctrl) -{ - struct usb_composite_dev *cdev = f->config->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); - u8 *buf = cdev->req->buf; - - pr_debug("bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n", - ctrl->bRequest, w_value, len, ep); - - if (w_value == UAC_EP_CS_ATTR_SAMPLE_RATE << 8) { - switch (ctrl->bRequest) { - case UAC_GET_CUR: - case UAC_GET_MIN: - case UAC_GET_MAX: - case UAC_GET_RES: - /* return our sample rate */ - buf[0] = (u8)SAMPLE_RATE; - buf[1] = (u8)(SAMPLE_RATE >> 8); - buf[2] = (u8)(SAMPLE_RATE >> 16); - value = 3; - break; - default: - break; - } - } - - return value; -} - -static int -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; interface - * activation uses set_alt(). - */ - switch (ctrl->bRequestType) { - case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT: - value = audio_set_endpoint_req(f, ctrl); - break; - - case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT: - value = audio_get_endpoint_req(f, ctrl); - break; - } - - /* respond with data transfer or status phase? */ - if (value >= 0) { - pr_debug("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; - req->complete = audio_control_complete; - value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); - if (value < 0) - pr_err("audio response on err %d\n", value); - } - - /* device either stalls (value < 0) or reports success */ - return value; -} - -static int audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt) -{ - struct audio_dev *audio = func_to_audio(f); - struct usb_composite_dev *cdev = f->config->cdev; - int ret; - - pr_debug("audio_set_alt intf %d, alt %d\n", intf, alt); - - ret = config_ep_by_speed(cdev->gadget, f, audio->in_ep); - if (ret) - return ret; - - usb_ep_enable(audio->in_ep); - return 0; -} - -static void audio_disable(struct usb_function *f) -{ - struct audio_dev *audio = func_to_audio(f); - - pr_debug("audio_disable\n"); - usb_ep_disable(audio->in_ep); -} - -/*-------------------------------------------------------------------------*/ - -static void audio_build_desc(struct audio_dev *audio) -{ - u8 *sam_freq; - int rate; - - /* Set channel numbers */ - input_terminal_desc.bNrChannels = 2; - as_type_i_desc.bNrChannels = 2; - - /* Set sample rates */ - rate = SAMPLE_RATE; - sam_freq = as_type_i_desc.tSamFreq[0]; - memcpy(sam_freq, &rate, 3); -} - -/* audio function driver setup/binding */ -static int -audio_bind(struct usb_configuration *c, struct usb_function *f) -{ - struct usb_composite_dev *cdev = c->cdev; - struct audio_dev *audio = func_to_audio(f); - int status; - struct usb_ep *ep; - struct usb_request *req; - int i; - - 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 our endpoint */ - ep = usb_ep_autoconfig(cdev->gadget, &fs_as_in_ep_desc); - if (!ep) - goto fail; - audio->in_ep = ep; - ep->driver_data = audio; /* claim */ - - if (gadget_is_dualspeed(c->cdev->gadget)) - hs_as_in_ep_desc.bEndpointAddress = - fs_as_in_ep_desc.bEndpointAddress; - - f->descriptors = fs_audio_desc; - f->hs_descriptors = hs_audio_desc; - - for (i = 0, status = 0; i < IN_EP_REQ_COUNT && status == 0; i++) { - req = audio_request_new(ep, IN_EP_MAX_PACKET_SIZE); - if (req) { - req->context = audio; - req->complete = audio_data_complete; - audio_req_put(audio, req); - } else - status = -ENOMEM; - } - -fail: - return status; -} - -static void -audio_unbind(struct usb_configuration *c, struct usb_function *f) -{ - struct audio_dev *audio = func_to_audio(f); - struct usb_request *req; - - while ((req = audio_req_get(audio))) - audio_request_free(req, audio->in_ep); - - snd_card_free_when_closed(audio->card); - audio->card = NULL; - audio->pcm = NULL; - audio->substream = NULL; - audio->in_ep = NULL; -} - -static void audio_pcm_playback_start(struct audio_dev *audio) -{ - audio->start_time = ktime_get(); - audio->frames_sent = 0; - audio_send(audio); -} - -static void audio_pcm_playback_stop(struct audio_dev *audio) -{ - unsigned long flags; - - spin_lock_irqsave(&audio->lock, flags); - audio->buffer_start = 0; - audio->buffer_end = 0; - audio->buffer_pos = 0; - spin_unlock_irqrestore(&audio->lock, flags); -} - -static int audio_pcm_open(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct audio_dev *audio = substream->private_data; - - runtime->private_data = audio; - runtime->hw = audio_hw_info; - snd_pcm_limit_hw_rates(runtime); - runtime->hw.channels_max = 2; - - audio->substream = substream; - return 0; -} - -static int audio_pcm_close(struct snd_pcm_substream *substream) -{ - struct audio_dev *audio = substream->private_data; - unsigned long flags; - - spin_lock_irqsave(&audio->lock, flags); - audio->substream = NULL; - spin_unlock_irqrestore(&audio->lock, flags); - - return 0; -} - -static int audio_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - unsigned int channels = params_channels(params); - unsigned int rate = params_rate(params); - - if (rate != SAMPLE_RATE) - return -EINVAL; - if (channels != 2) - return -EINVAL; - - return snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(params)); -} - -static int audio_pcm_hw_free(struct snd_pcm_substream *substream) -{ - return snd_pcm_lib_free_vmalloc_buffer(substream); -} - -static int audio_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct audio_dev *audio = runtime->private_data; - - audio->period = snd_pcm_lib_period_bytes(substream); - audio->period_offset = 0; - audio->buffer_start = runtime->dma_area; - audio->buffer_end = audio->buffer_start - + snd_pcm_lib_buffer_bytes(substream); - audio->buffer_pos = audio->buffer_start; - - return 0; -} - -static snd_pcm_uframes_t audio_pcm_pointer(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct audio_dev *audio = runtime->private_data; - ssize_t bytes = audio->buffer_pos - audio->buffer_start; - - /* return offset of next frame to fill in our buffer */ - return bytes_to_frames(runtime, bytes); -} - -static int audio_pcm_playback_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct audio_dev *audio = substream->runtime->private_data; - int ret = 0; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - audio_pcm_playback_start(audio); - break; - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - audio_pcm_playback_stop(audio); - break; - - default: - ret = -EINVAL; - } - - return ret; -} - -static struct audio_dev _audio_dev = { - .func = { - .name = "audio_source", - .bind = audio_bind, - .unbind = audio_unbind, - .set_alt = audio_set_alt, - .setup = audio_setup, - .disable = audio_disable, - }, - .lock = __SPIN_LOCK_UNLOCKED(_audio_dev.lock), - .idle_reqs = LIST_HEAD_INIT(_audio_dev.idle_reqs), -}; - -static struct snd_pcm_ops audio_playback_ops = { - .open = audio_pcm_open, - .close = audio_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = audio_pcm_hw_params, - .hw_free = audio_pcm_hw_free, - .prepare = audio_pcm_prepare, - .trigger = audio_pcm_playback_trigger, - .pointer = audio_pcm_pointer, -}; - -int audio_source_bind_config(struct usb_configuration *c, - struct audio_source_config *config) -{ - struct audio_dev *audio; - struct snd_card *card; - struct snd_pcm *pcm; - int err; - - config->card = -1; - config->device = -1; - - audio = &_audio_dev; - - err = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, - THIS_MODULE, 0, &card); - if (err) - return err; - - snd_card_set_dev(card, &c->cdev->gadget->dev); - - err = snd_pcm_new(card, "USB audio source", 0, 1, 0, &pcm); - if (err) - goto pcm_fail; - pcm->private_data = audio; - pcm->info_flags = 0; - audio->pcm = pcm; - - strlcpy(pcm->name, "USB gadget audio", sizeof(pcm->name)); - - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &audio_playback_ops); - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - NULL, 0, 64 * 1024); - - strlcpy(card->driver, "audio_source", sizeof(card->driver)); - strlcpy(card->shortname, card->driver, sizeof(card->shortname)); - strlcpy(card->longname, "USB accessory audio source", - sizeof(card->longname)); - - err = snd_card_register(card); - if (err) - goto register_fail; - - err = usb_add_function(c, &audio->func); - if (err) - goto add_fail; - - config->card = pcm->card->number; - config->device = pcm->device; - audio->card = card; - return 0; - -add_fail: -register_fail: -pcm_fail: - snd_card_free(audio->card); - return err; -} diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_ecm.c b/ANDROID_3.4.5/drivers/usb/gadget/f_ecm.c deleted file mode 100644 index 30b908f2..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_ecm.c +++ /dev/null @@ -1,924 +0,0 @@ -/* - * f_ecm.c -- USB CDC Ethernet (ECM) link function driver - * - * Copyright (C) 2003-2005,2008 David Brownell - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -/* #define VERBOSE_DEBUG */ - -#include -#include -#include -#include - -#include "u_ether.h" - - -/* - * This function is a "CDC Ethernet Networking Control Model" (CDC ECM) - * Ethernet link. The data transfer model is simple (packets sent and - * received over bulk endpoints using normal short packet termination), - * and the control model exposes various data and optional notifications. - * - * ECM is well standardized and (except for Microsoft) supported by most - * operating systems with USB host support. It's the preferred interop - * solution for Ethernet over USB, at least for firmware based solutions. - * (Hardware solutions tend to be more minimalist.) A newer and simpler - * "Ethernet Emulation Model" (CDC EEM) hasn't yet caught on. - * - * Note that ECM requires the use of "alternate settings" for its data - * interface. This means that the set_alt() method has real work to do, - * and also means that a get_alt() method is required. - */ - - -enum ecm_notify_state { - ECM_NOTIFY_NONE, /* don't notify */ - ECM_NOTIFY_CONNECT, /* issue CONNECT next */ - ECM_NOTIFY_SPEED, /* issue SPEED_CHANGE next */ -}; - -struct f_ecm { - struct gether port; - u8 ctrl_id, data_id; - - char ethaddr[14]; - - struct usb_ep *notify; - struct usb_request *notify_req; - u8 notify_state; - bool is_open; - - /* FIXME is_open needs some irq-ish locking - * ... possibly the same as port.ioport - */ -}; - -static inline struct f_ecm *func_to_ecm(struct usb_function *f) -{ - return container_of(f, struct f_ecm, port.func); -} - -/* peak (theoretical) bulk transfer rate in bits-per-second */ -static inline unsigned ecm_bitrate(struct usb_gadget *g) -{ - if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER) - return 13 * 1024 * 8 * 1000 * 8; - else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) - return 13 * 512 * 8 * 1000 * 8; - else - return 19 * 64 * 1 * 1000 * 8; -} - -/*-------------------------------------------------------------------------*/ - -/* - * Include the status endpoint if we can, even though it's optional. - * - * Use wMaxPacketSize big enough to fit CDC_NOTIFY_SPEED_CHANGE in one - * packet, to simplify cancellation; and a big transfer interval, to - * waste less bandwidth. - * - * Some drivers (like Linux 2.4 cdc-ether!) "need" it to exist even - * if they ignore the connect/disconnect notifications that real aether - * can provide. More advanced cdc configurations might want to support - * encapsulated commands (vendor-specific, using control-OUT). - */ - -#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */ -#define ECM_STATUS_BYTECOUNT 16 /* 8 byte header + data */ - - -/* interface descriptor: */ - -static struct usb_interface_assoc_descriptor -ecm_iad_descriptor = { - .bLength = sizeof ecm_iad_descriptor, - .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, - - /* .bFirstInterface = DYNAMIC, */ - .bInterfaceCount = 2, /* control + data */ - .bFunctionClass = USB_CLASS_COMM, - .bFunctionSubClass = USB_CDC_SUBCLASS_ETHERNET, - .bFunctionProtocol = USB_CDC_PROTO_NONE, - /* .iFunction = DYNAMIC */ -}; - - -static struct usb_interface_descriptor ecm_control_intf = { - .bLength = sizeof ecm_control_intf, - .bDescriptorType = USB_DT_INTERFACE, - - /* .bInterfaceNumber = DYNAMIC */ - /* status endpoint is optional; this could be patched later */ - .bNumEndpoints = 1, - .bInterfaceClass = USB_CLASS_COMM, - .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, - .bInterfaceProtocol = USB_CDC_PROTO_NONE, - /* .iInterface = DYNAMIC */ -}; - -static struct usb_cdc_header_desc ecm_header_desc = { - .bLength = sizeof ecm_header_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_HEADER_TYPE, - - .bcdCDC = cpu_to_le16(0x0110), -}; - -static struct usb_cdc_union_desc ecm_union_desc = { - .bLength = sizeof(ecm_union_desc), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_UNION_TYPE, - /* .bMasterInterface0 = DYNAMIC */ - /* .bSlaveInterface0 = DYNAMIC */ -}; - -static struct usb_cdc_ether_desc ecm_desc = { - .bLength = sizeof ecm_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_ETHERNET_TYPE, - - /* this descriptor actually adds value, surprise! */ - /* .iMACAddress = DYNAMIC */ - .bmEthernetStatistics = cpu_to_le32(0), /* no statistics */ - .wMaxSegmentSize = cpu_to_le16(ETH_FRAME_LEN), - .wNumberMCFilters = cpu_to_le16(0), - .bNumberPowerFilters = 0, -}; - -/* the default data interface has no endpoints ... */ - -static struct usb_interface_descriptor ecm_data_nop_intf = { - .bLength = sizeof ecm_data_nop_intf, - .bDescriptorType = USB_DT_INTERFACE, - - .bInterfaceNumber = 1, - .bAlternateSetting = 0, - .bNumEndpoints = 0, - .bInterfaceClass = USB_CLASS_CDC_DATA, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - /* .iInterface = DYNAMIC */ -}; - -/* ... but the "real" data interface has two bulk endpoints */ - -static struct usb_interface_descriptor ecm_data_intf = { - .bLength = sizeof ecm_data_intf, - .bDescriptorType = USB_DT_INTERFACE, - - .bInterfaceNumber = 1, - .bAlternateSetting = 1, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_CDC_DATA, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - /* .iInterface = DYNAMIC */ -}; - -/* full speed support: */ - -static struct usb_endpoint_descriptor fs_ecm_notify_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT), - .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC, -}; - -static struct usb_endpoint_descriptor fs_ecm_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_endpoint_descriptor fs_ecm_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_descriptor_header *ecm_fs_function[] = { - /* CDC ECM control descriptors */ - (struct usb_descriptor_header *) &ecm_iad_descriptor, - (struct usb_descriptor_header *) &ecm_control_intf, - (struct usb_descriptor_header *) &ecm_header_desc, - (struct usb_descriptor_header *) &ecm_union_desc, - (struct usb_descriptor_header *) &ecm_desc, - - /* NOTE: status endpoint might need to be removed */ - (struct usb_descriptor_header *) &fs_ecm_notify_desc, - - /* data interface, altsettings 0 and 1 */ - (struct usb_descriptor_header *) &ecm_data_nop_intf, - (struct usb_descriptor_header *) &ecm_data_intf, - (struct usb_descriptor_header *) &fs_ecm_in_desc, - (struct usb_descriptor_header *) &fs_ecm_out_desc, - NULL, -}; - -/* high speed support: */ - -static struct usb_endpoint_descriptor hs_ecm_notify_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT), - .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, -}; - -static struct usb_endpoint_descriptor hs_ecm_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), -}; - -static struct usb_endpoint_descriptor hs_ecm_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), -}; - -static struct usb_descriptor_header *ecm_hs_function[] = { - /* CDC ECM control descriptors */ - (struct usb_descriptor_header *) &ecm_iad_descriptor, - (struct usb_descriptor_header *) &ecm_control_intf, - (struct usb_descriptor_header *) &ecm_header_desc, - (struct usb_descriptor_header *) &ecm_union_desc, - (struct usb_descriptor_header *) &ecm_desc, - - /* NOTE: status endpoint might need to be removed */ - (struct usb_descriptor_header *) &hs_ecm_notify_desc, - - /* data interface, altsettings 0 and 1 */ - (struct usb_descriptor_header *) &ecm_data_nop_intf, - (struct usb_descriptor_header *) &ecm_data_intf, - (struct usb_descriptor_header *) &hs_ecm_in_desc, - (struct usb_descriptor_header *) &hs_ecm_out_desc, - NULL, -}; - -/* super speed support: */ - -static struct usb_endpoint_descriptor ss_ecm_notify_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT), - .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, -}; - -static struct usb_ss_ep_comp_descriptor ss_ecm_intr_comp_desc = { - .bLength = sizeof ss_ecm_intr_comp_desc, - .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, - - /* the following 3 values can be tweaked if necessary */ - /* .bMaxBurst = 0, */ - /* .bmAttributes = 0, */ - .wBytesPerInterval = cpu_to_le16(ECM_STATUS_BYTECOUNT), -}; - -static struct usb_endpoint_descriptor ss_ecm_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(1024), -}; - -static struct usb_endpoint_descriptor ss_ecm_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(1024), -}; - -static struct usb_ss_ep_comp_descriptor ss_ecm_bulk_comp_desc = { - .bLength = sizeof ss_ecm_bulk_comp_desc, - .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, - - /* the following 2 values can be tweaked if necessary */ - /* .bMaxBurst = 0, */ - /* .bmAttributes = 0, */ -}; - -static struct usb_descriptor_header *ecm_ss_function[] = { - /* CDC ECM control descriptors */ - (struct usb_descriptor_header *) &ecm_control_intf, - (struct usb_descriptor_header *) &ecm_header_desc, - (struct usb_descriptor_header *) &ecm_union_desc, - (struct usb_descriptor_header *) &ecm_desc, - - /* NOTE: status endpoint might need to be removed */ - (struct usb_descriptor_header *) &ss_ecm_notify_desc, - (struct usb_descriptor_header *) &ss_ecm_intr_comp_desc, - - /* data interface, altsettings 0 and 1 */ - (struct usb_descriptor_header *) &ecm_data_nop_intf, - (struct usb_descriptor_header *) &ecm_data_intf, - (struct usb_descriptor_header *) &ss_ecm_in_desc, - (struct usb_descriptor_header *) &ss_ecm_bulk_comp_desc, - (struct usb_descriptor_header *) &ss_ecm_out_desc, - (struct usb_descriptor_header *) &ss_ecm_bulk_comp_desc, - NULL, -}; - -/* string descriptors: */ - -static struct usb_string ecm_string_defs[] = { - [0].s = "CDC Ethernet Control Model (ECM)", - [1].s = NULL /* DYNAMIC */, - [2].s = "CDC Ethernet Data", - [3].s = "CDC ECM", - { } /* end of list */ -}; - -static struct usb_gadget_strings ecm_string_table = { - .language = 0x0409, /* en-us */ - .strings = ecm_string_defs, -}; - -static struct usb_gadget_strings *ecm_strings[] = { - &ecm_string_table, - NULL, -}; - -/*-------------------------------------------------------------------------*/ - -static void ecm_do_notify(struct f_ecm *ecm) -{ - struct usb_request *req = ecm->notify_req; - struct usb_cdc_notification *event; - struct usb_composite_dev *cdev = ecm->port.func.config->cdev; - __le32 *data; - int status; - - /* notification already in flight? */ - if (!req) - return; - - event = req->buf; - switch (ecm->notify_state) { - case ECM_NOTIFY_NONE: - return; - - case ECM_NOTIFY_CONNECT: - event->bNotificationType = USB_CDC_NOTIFY_NETWORK_CONNECTION; - if (ecm->is_open) - event->wValue = cpu_to_le16(1); - else - event->wValue = cpu_to_le16(0); - event->wLength = 0; - req->length = sizeof *event; - - DBG(cdev, "notify connect %s\n", - ecm->is_open ? "true" : "false"); - ecm->notify_state = ECM_NOTIFY_SPEED; - break; - - case ECM_NOTIFY_SPEED: - event->bNotificationType = USB_CDC_NOTIFY_SPEED_CHANGE; - event->wValue = cpu_to_le16(0); - event->wLength = cpu_to_le16(8); - req->length = ECM_STATUS_BYTECOUNT; - - /* SPEED_CHANGE data is up/down speeds in bits/sec */ - data = req->buf + sizeof *event; - data[0] = cpu_to_le32(ecm_bitrate(cdev->gadget)); - data[1] = data[0]; - - DBG(cdev, "notify speed %d\n", ecm_bitrate(cdev->gadget)); - ecm->notify_state = ECM_NOTIFY_NONE; - break; - } - event->bmRequestType = 0xA1; - event->wIndex = cpu_to_le16(ecm->ctrl_id); - - ecm->notify_req = NULL; - status = usb_ep_queue(ecm->notify, req, GFP_ATOMIC); - if (status < 0) { - ecm->notify_req = req; - DBG(cdev, "notify --> %d\n", status); - } -} - -static void ecm_notify(struct f_ecm *ecm) -{ - /* NOTE on most versions of Linux, host side cdc-ethernet - * won't listen for notifications until its netdevice opens. - * The first notification then sits in the FIFO for a long - * time, and the second one is queued. - */ - ecm->notify_state = ECM_NOTIFY_CONNECT; - ecm_do_notify(ecm); -} - -static void ecm_notify_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct f_ecm *ecm = req->context; - struct usb_composite_dev *cdev = ecm->port.func.config->cdev; - struct usb_cdc_notification *event = req->buf; - - switch (req->status) { - case 0: - /* no fault */ - break; - case -ECONNRESET: - case -ESHUTDOWN: - ecm->notify_state = ECM_NOTIFY_NONE; - break; - default: - DBG(cdev, "event %02x --> %d\n", - event->bNotificationType, req->status); - break; - } - ecm->notify_req = req; - ecm_do_notify(ecm); -} - -static int ecm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) -{ - struct f_ecm *ecm = func_to_ecm(f); - 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 - * CDC class messages; interface activation uses set_alt(). - */ - switch ((ctrl->bRequestType << 8) | ctrl->bRequest) { - case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) - | USB_CDC_SET_ETHERNET_PACKET_FILTER: - /* see 6.2.30: no data, wIndex = interface, - * wValue = packet filter bitmap - */ - if (w_length != 0 || w_index != ecm->ctrl_id) - goto invalid; - DBG(cdev, "packet filter %02x\n", w_value); - /* REVISIT locking of cdc_filter. This assumes the UDC - * driver won't have a concurrent packet TX irq running on - * another CPU; or that if it does, this write is atomic... - */ - ecm->port.cdc_filter = w_value; - value = 0; - break; - - /* and optionally: - * case USB_CDC_SEND_ENCAPSULATED_COMMAND: - * case USB_CDC_GET_ENCAPSULATED_RESPONSE: - * case USB_CDC_SET_ETHERNET_MULTICAST_FILTERS: - * case USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER: - * case USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER: - * case USB_CDC_GET_ETHERNET_STATISTIC: - */ - - default: -invalid: - DBG(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, "ecm 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, "ecm req %02x.%02x response err %d\n", - ctrl->bRequestType, ctrl->bRequest, - value); - } - - /* device either stalls (value < 0) or reports success */ - return value; -} - - -static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) -{ - struct f_ecm *ecm = func_to_ecm(f); - struct usb_composite_dev *cdev = f->config->cdev; - - /* Control interface has only altsetting 0 */ - if (intf == ecm->ctrl_id) { - if (alt != 0) - goto fail; - - if (ecm->notify->driver_data) { - VDBG(cdev, "reset ecm control %d\n", intf); - usb_ep_disable(ecm->notify); - } - if (!(ecm->notify->desc)) { - VDBG(cdev, "init ecm ctrl %d\n", intf); - if (config_ep_by_speed(cdev->gadget, f, ecm->notify)) - goto fail; - } - usb_ep_enable(ecm->notify); - ecm->notify->driver_data = ecm; - - /* Data interface has two altsettings, 0 and 1 */ - } else if (intf == ecm->data_id) { - if (alt > 1) - goto fail; - - if (ecm->port.in_ep->driver_data) { - DBG(cdev, "reset ecm\n"); - gether_disconnect(&ecm->port); - } - - if (!ecm->port.in_ep->desc || - !ecm->port.out_ep->desc) { - DBG(cdev, "init ecm\n"); - if (config_ep_by_speed(cdev->gadget, f, - ecm->port.in_ep) || - config_ep_by_speed(cdev->gadget, f, - ecm->port.out_ep)) { - ecm->port.in_ep->desc = NULL; - ecm->port.out_ep->desc = NULL; - goto fail; - } - } - - /* CDC Ethernet only sends data in non-default altsettings. - * Changing altsettings resets filters, statistics, etc. - */ - if (alt == 1) { - struct net_device *net; - - /* Enable zlps by default for ECM conformance; - * override for musb_hdrc (avoids txdma ovhead). - */ - ecm->port.is_zlp_ok = !(gadget_is_musbhdrc(cdev->gadget) - ); - ecm->port.cdc_filter = DEFAULT_FILTER; - DBG(cdev, "activate ecm\n"); - net = gether_connect(&ecm->port); - if (IS_ERR(net)) - return PTR_ERR(net); - } - - /* NOTE this can be a minor disagreement with the ECM spec, - * which says speed notifications will "always" follow - * connection notifications. But we allow one connect to - * follow another (if the first is in flight), and instead - * just guarantee that a speed notification is always sent. - */ - ecm_notify(ecm); - } else - goto fail; - - return 0; -fail: - return -EINVAL; -} - -/* Because the data interface supports multiple altsettings, - * this ECM function *MUST* implement a get_alt() method. - */ -static int ecm_get_alt(struct usb_function *f, unsigned intf) -{ - struct f_ecm *ecm = func_to_ecm(f); - - if (intf == ecm->ctrl_id) - return 0; - return ecm->port.in_ep->driver_data ? 1 : 0; -} - -static void ecm_disable(struct usb_function *f) -{ - struct f_ecm *ecm = func_to_ecm(f); - struct usb_composite_dev *cdev = f->config->cdev; - - DBG(cdev, "ecm deactivated\n"); - - if (ecm->port.in_ep->driver_data) - gether_disconnect(&ecm->port); - - if (ecm->notify->driver_data) { - usb_ep_disable(ecm->notify); - ecm->notify->driver_data = NULL; - ecm->notify->desc = NULL; - } -} - -/*-------------------------------------------------------------------------*/ - -/* - * Callbacks let us notify the host about connect/disconnect when the - * net device is opened or closed. - * - * For testing, note that link states on this side include both opened - * and closed variants of: - * - * - disconnected/unconfigured - * - configured but inactive (data alt 0) - * - configured and active (data alt 1) - * - * Each needs to be tested with unplug, rmmod, SET_CONFIGURATION, and - * SET_INTERFACE (altsetting). Remember also that "configured" doesn't - * imply the host is actually polling the notification endpoint, and - * likewise that "active" doesn't imply it's actually using the data - * endpoints for traffic. - */ - -static void ecm_open(struct gether *geth) -{ - struct f_ecm *ecm = func_to_ecm(&geth->func); - - DBG(ecm->port.func.config->cdev, "%s\n", __func__); - - ecm->is_open = true; - ecm_notify(ecm); -} - -static void ecm_close(struct gether *geth) -{ - struct f_ecm *ecm = func_to_ecm(&geth->func); - - DBG(ecm->port.func.config->cdev, "%s\n", __func__); - - ecm->is_open = false; - ecm_notify(ecm); -} - -/*-------------------------------------------------------------------------*/ - -/* ethernet function driver setup/binding */ - -static int -ecm_bind(struct usb_configuration *c, struct usb_function *f) -{ - struct usb_composite_dev *cdev = c->cdev; - struct f_ecm *ecm = func_to_ecm(f); - int status; - struct usb_ep *ep; - - /* allocate instance-specific interface IDs */ - status = usb_interface_id(c, f); - if (status < 0) - goto fail; - ecm->ctrl_id = status; - ecm_iad_descriptor.bFirstInterface = status; - - ecm_control_intf.bInterfaceNumber = status; - ecm_union_desc.bMasterInterface0 = status; - - status = usb_interface_id(c, f); - if (status < 0) - goto fail; - ecm->data_id = status; - - ecm_data_nop_intf.bInterfaceNumber = status; - ecm_data_intf.bInterfaceNumber = status; - ecm_union_desc.bSlaveInterface0 = status; - - status = -ENODEV; - - /* allocate instance-specific endpoints */ - ep = usb_ep_autoconfig(cdev->gadget, &fs_ecm_in_desc); - if (!ep) - goto fail; - ecm->port.in_ep = ep; - ep->driver_data = cdev; /* claim */ - - ep = usb_ep_autoconfig(cdev->gadget, &fs_ecm_out_desc); - if (!ep) - goto fail; - ecm->port.out_ep = ep; - ep->driver_data = cdev; /* claim */ - - /* NOTE: a status/notification endpoint is *OPTIONAL* but we - * don't treat it that way. It's simpler, and some newer CDC - * profiles (wireless handsets) no longer treat it as optional. - */ - ep = usb_ep_autoconfig(cdev->gadget, &fs_ecm_notify_desc); - if (!ep) - goto fail; - ecm->notify = ep; - ep->driver_data = cdev; /* claim */ - - status = -ENOMEM; - - /* allocate notification request and buffer */ - ecm->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL); - if (!ecm->notify_req) - goto fail; - ecm->notify_req->buf = kmalloc(ECM_STATUS_BYTECOUNT, GFP_KERNEL); - if (!ecm->notify_req->buf) - goto fail; - ecm->notify_req->context = ecm; - ecm->notify_req->complete = ecm_notify_complete; - - /* copy descriptors, and track endpoint copies */ - f->descriptors = usb_copy_descriptors(ecm_fs_function); - if (!f->descriptors) - goto fail; - - /* support all relevant hardware speeds... we expect that when - * hardware is dual speed, all bulk-capable endpoints work at - * both speeds - */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - hs_ecm_in_desc.bEndpointAddress = - fs_ecm_in_desc.bEndpointAddress; - hs_ecm_out_desc.bEndpointAddress = - fs_ecm_out_desc.bEndpointAddress; - hs_ecm_notify_desc.bEndpointAddress = - fs_ecm_notify_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->hs_descriptors = usb_copy_descriptors(ecm_hs_function); - if (!f->hs_descriptors) - goto fail; - } - - if (gadget_is_superspeed(c->cdev->gadget)) { - ss_ecm_in_desc.bEndpointAddress = - fs_ecm_in_desc.bEndpointAddress; - ss_ecm_out_desc.bEndpointAddress = - fs_ecm_out_desc.bEndpointAddress; - ss_ecm_notify_desc.bEndpointAddress = - fs_ecm_notify_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->ss_descriptors = usb_copy_descriptors(ecm_ss_function); - if (!f->ss_descriptors) - goto fail; - } - - /* NOTE: all that is done without knowing or caring about - * the network link ... which is unavailable to this code - * until we're activated via set_alt(). - */ - - ecm->port.open = ecm_open; - ecm->port.close = ecm_close; - - DBG(cdev, "CDC Ethernet: %s speed IN/%s OUT/%s NOTIFY/%s\n", - gadget_is_superspeed(c->cdev->gadget) ? "super" : - gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", - ecm->port.in_ep->name, ecm->port.out_ep->name, - ecm->notify->name); - return 0; - -fail: - if (f->descriptors) - usb_free_descriptors(f->descriptors); - if (f->hs_descriptors) - usb_free_descriptors(f->hs_descriptors); - - if (ecm->notify_req) { - kfree(ecm->notify_req->buf); - usb_ep_free_request(ecm->notify, ecm->notify_req); - } - - /* we might as well release our claims on endpoints */ - if (ecm->notify) - ecm->notify->driver_data = NULL; - if (ecm->port.out_ep->desc) - ecm->port.out_ep->driver_data = NULL; - if (ecm->port.in_ep->desc) - ecm->port.in_ep->driver_data = NULL; - - ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); - - return status; -} - -static void -ecm_unbind(struct usb_configuration *c, struct usb_function *f) -{ - struct f_ecm *ecm = func_to_ecm(f); - - DBG(c->cdev, "ecm unbind\n"); - - if (gadget_is_superspeed(c->cdev->gadget)) - usb_free_descriptors(f->ss_descriptors); - if (gadget_is_dualspeed(c->cdev->gadget)) - usb_free_descriptors(f->hs_descriptors); - usb_free_descriptors(f->descriptors); - - kfree(ecm->notify_req->buf); - usb_ep_free_request(ecm->notify, ecm->notify_req); - - ecm_string_defs[1].s = NULL; - kfree(ecm); -} - -/** - * ecm_bind_config - add CDC Ethernet network link to a configuration - * @c: the configuration to support the network link - * @ethaddr: a buffer in which the ethernet address of the host side - * side of the link was recorded - * Context: single threaded during gadget setup - * - * Returns zero on success, else negative errno. - * - * Caller must have called @gether_setup(). Caller is also responsible - * for calling @gether_cleanup() before module unload. - */ -int -ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) -{ - struct f_ecm *ecm; - int status; - - if (!can_support_ecm(c->cdev->gadget) || !ethaddr) - return -EINVAL; - - /* maybe allocate device-global string IDs */ - if (ecm_string_defs[0].id == 0) { - - /* control interface label */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - ecm_string_defs[0].id = status; - ecm_control_intf.iInterface = status; - - /* data interface label */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - ecm_string_defs[2].id = status; - ecm_data_intf.iInterface = status; - - /* MAC address */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - ecm_string_defs[1].id = status; - ecm_desc.iMACAddress = status; - - /* IAD label */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - ecm_string_defs[3].id = status; - ecm_iad_descriptor.iFunction = status; - } - - /* allocate and initialize one new instance */ - ecm = kzalloc(sizeof *ecm, GFP_KERNEL); - if (!ecm) - return -ENOMEM; - - /* export host's Ethernet address in CDC format */ - snprintf(ecm->ethaddr, sizeof ecm->ethaddr, - "%02X%02X%02X%02X%02X%02X", - ethaddr[0], ethaddr[1], ethaddr[2], - ethaddr[3], ethaddr[4], ethaddr[5]); - ecm_string_defs[1].s = ecm->ethaddr; - - ecm->port.cdc_filter = DEFAULT_FILTER; - - ecm->port.func.name = "cdc_ethernet"; - ecm->port.func.strings = ecm_strings; - /* descriptors are per-instance copies */ - ecm->port.func.bind = ecm_bind; - ecm->port.func.unbind = ecm_unbind; - ecm->port.func.set_alt = ecm_set_alt; - ecm->port.func.get_alt = ecm_get_alt; - ecm->port.func.setup = ecm_setup; - ecm->port.func.disable = ecm_disable; - - status = usb_add_function(c, &ecm->port.func); - if (status) { - ecm_string_defs[1].s = NULL; - kfree(ecm); - } - return status; -} diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_eem.c b/ANDROID_3.4.5/drivers/usb/gadget/f_eem.c deleted file mode 100644 index 1a7b2dd7..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_eem.c +++ /dev/null @@ -1,598 +0,0 @@ -/* - * f_eem.c -- USB CDC Ethernet (EEM) link function driver - * - * Copyright (C) 2003-2005,2008 David Brownell - * Copyright (C) 2008 Nokia Corporation - * Copyright (C) 2009 EF Johnson Technologies - * - * 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 -#include -#include -#include -#include - -#include "u_ether.h" - -#define EEM_HLEN 2 - -/* - * This function is a "CDC Ethernet Emulation Model" (CDC EEM) - * Ethernet link. - */ - -struct f_eem { - struct gether port; - u8 ctrl_id; -}; - -static inline struct f_eem *func_to_eem(struct usb_function *f) -{ - return container_of(f, struct f_eem, port.func); -} - -/*-------------------------------------------------------------------------*/ - -/* interface descriptor: */ - -static struct usb_interface_descriptor eem_intf __initdata = { - .bLength = sizeof eem_intf, - .bDescriptorType = USB_DT_INTERFACE, - - /* .bInterfaceNumber = DYNAMIC */ - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_COMM, - .bInterfaceSubClass = USB_CDC_SUBCLASS_EEM, - .bInterfaceProtocol = USB_CDC_PROTO_EEM, - /* .iInterface = DYNAMIC */ -}; - -/* full speed support: */ - -static struct usb_endpoint_descriptor eem_fs_in_desc __initdata = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_endpoint_descriptor eem_fs_out_desc __initdata = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_descriptor_header *eem_fs_function[] __initdata = { - /* CDC EEM control descriptors */ - (struct usb_descriptor_header *) &eem_intf, - (struct usb_descriptor_header *) &eem_fs_in_desc, - (struct usb_descriptor_header *) &eem_fs_out_desc, - NULL, -}; - -/* high speed support: */ - -static struct usb_endpoint_descriptor eem_hs_in_desc __initdata = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), -}; - -static struct usb_endpoint_descriptor eem_hs_out_desc __initdata = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), -}; - -static struct usb_descriptor_header *eem_hs_function[] __initdata = { - /* CDC EEM control descriptors */ - (struct usb_descriptor_header *) &eem_intf, - (struct usb_descriptor_header *) &eem_hs_in_desc, - (struct usb_descriptor_header *) &eem_hs_out_desc, - NULL, -}; - -/* super speed support: */ - -static struct usb_endpoint_descriptor eem_ss_in_desc __initdata = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(1024), -}; - -static struct usb_endpoint_descriptor eem_ss_out_desc __initdata = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(1024), -}; - -static struct usb_ss_ep_comp_descriptor eem_ss_bulk_comp_desc __initdata = { - .bLength = sizeof eem_ss_bulk_comp_desc, - .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, - - /* the following 2 values can be tweaked if necessary */ - /* .bMaxBurst = 0, */ - /* .bmAttributes = 0, */ -}; - -static struct usb_descriptor_header *eem_ss_function[] __initdata = { - /* CDC EEM control descriptors */ - (struct usb_descriptor_header *) &eem_intf, - (struct usb_descriptor_header *) &eem_ss_in_desc, - (struct usb_descriptor_header *) &eem_ss_bulk_comp_desc, - (struct usb_descriptor_header *) &eem_ss_out_desc, - (struct usb_descriptor_header *) &eem_ss_bulk_comp_desc, - NULL, -}; - -/* string descriptors: */ - -static struct usb_string eem_string_defs[] = { - [0].s = "CDC Ethernet Emulation Model (EEM)", - { } /* end of list */ -}; - -static struct usb_gadget_strings eem_string_table = { - .language = 0x0409, /* en-us */ - .strings = eem_string_defs, -}; - -static struct usb_gadget_strings *eem_strings[] = { - &eem_string_table, - NULL, -}; - -/*-------------------------------------------------------------------------*/ - -static int eem_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) -{ - struct usb_composite_dev *cdev = f->config->cdev; - 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); - - DBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n", - ctrl->bRequestType, ctrl->bRequest, - w_value, w_index, w_length); - - /* device either stalls (value < 0) or reports success */ - return value; -} - - -static int eem_set_alt(struct usb_function *f, unsigned intf, unsigned alt) -{ - struct f_eem *eem = func_to_eem(f); - struct usb_composite_dev *cdev = f->config->cdev; - struct net_device *net; - - /* we know alt == 0, so this is an activation or a reset */ - if (alt != 0) - goto fail; - - if (intf == eem->ctrl_id) { - - if (eem->port.in_ep->driver_data) { - DBG(cdev, "reset eem\n"); - gether_disconnect(&eem->port); - } - - if (!eem->port.in_ep->desc || !eem->port.out_ep->desc) { - DBG(cdev, "init eem\n"); - if (config_ep_by_speed(cdev->gadget, f, - eem->port.in_ep) || - config_ep_by_speed(cdev->gadget, f, - eem->port.out_ep)) { - eem->port.in_ep->desc = NULL; - eem->port.out_ep->desc = NULL; - goto fail; - } - } - - /* zlps should not occur because zero-length EEM packets - * will be inserted in those cases where they would occur - */ - eem->port.is_zlp_ok = 1; - eem->port.cdc_filter = DEFAULT_FILTER; - DBG(cdev, "activate eem\n"); - net = gether_connect(&eem->port); - if (IS_ERR(net)) - return PTR_ERR(net); - } else - goto fail; - - return 0; -fail: - return -EINVAL; -} - -static void eem_disable(struct usb_function *f) -{ - struct f_eem *eem = func_to_eem(f); - struct usb_composite_dev *cdev = f->config->cdev; - - DBG(cdev, "eem deactivated\n"); - - if (eem->port.in_ep->driver_data) - gether_disconnect(&eem->port); -} - -/*-------------------------------------------------------------------------*/ - -/* EEM function driver setup/binding */ - -static int __init -eem_bind(struct usb_configuration *c, struct usb_function *f) -{ - struct usb_composite_dev *cdev = c->cdev; - struct f_eem *eem = func_to_eem(f); - int status; - struct usb_ep *ep; - - /* allocate instance-specific interface IDs */ - status = usb_interface_id(c, f); - if (status < 0) - goto fail; - eem->ctrl_id = status; - eem_intf.bInterfaceNumber = status; - - status = -ENODEV; - - /* allocate instance-specific endpoints */ - ep = usb_ep_autoconfig(cdev->gadget, &eem_fs_in_desc); - if (!ep) - goto fail; - eem->port.in_ep = ep; - ep->driver_data = cdev; /* claim */ - - ep = usb_ep_autoconfig(cdev->gadget, &eem_fs_out_desc); - if (!ep) - goto fail; - eem->port.out_ep = ep; - ep->driver_data = cdev; /* claim */ - - status = -ENOMEM; - - /* copy descriptors, and track endpoint copies */ - f->descriptors = usb_copy_descriptors(eem_fs_function); - if (!f->descriptors) - goto fail; - - /* support all relevant hardware speeds... we expect that when - * hardware is dual speed, all bulk-capable endpoints work at - * both speeds - */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - eem_hs_in_desc.bEndpointAddress = - eem_fs_in_desc.bEndpointAddress; - eem_hs_out_desc.bEndpointAddress = - eem_fs_out_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->hs_descriptors = usb_copy_descriptors(eem_hs_function); - if (!f->hs_descriptors) - goto fail; - } - - if (gadget_is_superspeed(c->cdev->gadget)) { - eem_ss_in_desc.bEndpointAddress = - eem_fs_in_desc.bEndpointAddress; - eem_ss_out_desc.bEndpointAddress = - eem_fs_out_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->ss_descriptors = usb_copy_descriptors(eem_ss_function); - if (!f->ss_descriptors) - goto fail; - } - - DBG(cdev, "CDC Ethernet (EEM): %s speed IN/%s OUT/%s\n", - gadget_is_superspeed(c->cdev->gadget) ? "super" : - gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", - eem->port.in_ep->name, eem->port.out_ep->name); - return 0; - -fail: - if (f->descriptors) - usb_free_descriptors(f->descriptors); - if (f->hs_descriptors) - usb_free_descriptors(f->hs_descriptors); - - /* we might as well release our claims on endpoints */ - if (eem->port.out_ep->desc) - eem->port.out_ep->driver_data = NULL; - if (eem->port.in_ep->desc) - eem->port.in_ep->driver_data = NULL; - - ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); - - return status; -} - -static void -eem_unbind(struct usb_configuration *c, struct usb_function *f) -{ - struct f_eem *eem = func_to_eem(f); - - DBG(c->cdev, "eem unbind\n"); - - if (gadget_is_superspeed(c->cdev->gadget)) - usb_free_descriptors(f->ss_descriptors); - if (gadget_is_dualspeed(c->cdev->gadget)) - usb_free_descriptors(f->hs_descriptors); - usb_free_descriptors(f->descriptors); - kfree(eem); -} - -static void eem_cmd_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct sk_buff *skb = (struct sk_buff *)req->context; - - dev_kfree_skb_any(skb); -} - -/* - * Add the EEM header and ethernet checksum. - * We currently do not attempt to put multiple ethernet frames - * into a single USB transfer - */ -static struct sk_buff *eem_wrap(struct gether *port, struct sk_buff *skb) -{ - struct sk_buff *skb2 = NULL; - struct usb_ep *in = port->in_ep; - int padlen = 0; - u16 len = skb->len; - - if (!skb_cloned(skb)) { - int headroom = skb_headroom(skb); - int tailroom = skb_tailroom(skb); - - /* When (len + EEM_HLEN + ETH_FCS_LEN) % in->maxpacket) is 0, - * stick two bytes of zero-length EEM packet on the end. - */ - if (((len + EEM_HLEN + ETH_FCS_LEN) % in->maxpacket) == 0) - padlen += 2; - - if ((tailroom >= (ETH_FCS_LEN + padlen)) && - (headroom >= EEM_HLEN)) - goto done; - } - - skb2 = skb_copy_expand(skb, EEM_HLEN, ETH_FCS_LEN + padlen, GFP_ATOMIC); - dev_kfree_skb_any(skb); - skb = skb2; - if (!skb) - return skb; - -done: - /* use the "no CRC" option */ - put_unaligned_be32(0xdeadbeef, skb_put(skb, 4)); - - /* EEM packet header format: - * b0..13: length of ethernet frame - * b14: bmCRC (0 == sentinel CRC) - * b15: bmType (0 == data) - */ - len = skb->len; - put_unaligned_le16(len & 0x3FFF, skb_push(skb, 2)); - - /* add a zero-length EEM packet, if needed */ - if (padlen) - put_unaligned_le16(0, skb_put(skb, 2)); - - return skb; -} - -/* - * Remove the EEM header. Note that there can be many EEM packets in a single - * USB transfer, so we need to break them out and handle them independently. - */ -static int eem_unwrap(struct gether *port, - struct sk_buff *skb, - struct sk_buff_head *list) -{ - struct usb_composite_dev *cdev = port->func.config->cdev; - int status = 0; - - do { - struct sk_buff *skb2; - u16 header; - u16 len = 0; - - if (skb->len < EEM_HLEN) { - status = -EINVAL; - DBG(cdev, "invalid EEM header\n"); - goto error; - } - - /* remove the EEM header */ - header = get_unaligned_le16(skb->data); - skb_pull(skb, EEM_HLEN); - - /* EEM packet header format: - * b0..14: EEM type dependent (data or command) - * b15: bmType (0 == data, 1 == command) - */ - if (header & BIT(15)) { - struct usb_request *req = cdev->req; - u16 bmEEMCmd; - - /* EEM command packet format: - * b0..10: bmEEMCmdParam - * b11..13: bmEEMCmd - * b14: reserved (must be zero) - * b15: bmType (1 == command) - */ - if (header & BIT(14)) - continue; - - bmEEMCmd = (header >> 11) & 0x7; - switch (bmEEMCmd) { - case 0: /* echo */ - len = header & 0x7FF; - if (skb->len < len) { - status = -EOVERFLOW; - goto error; - } - - skb2 = skb_clone(skb, GFP_ATOMIC); - if (unlikely(!skb2)) { - DBG(cdev, "EEM echo response error\n"); - goto next; - } - skb_trim(skb2, len); - put_unaligned_le16(BIT(15) | BIT(11) | len, - skb_push(skb2, 2)); - skb_copy_bits(skb2, 0, req->buf, skb2->len); - req->length = skb2->len; - req->complete = eem_cmd_complete; - req->zero = 1; - req->context = skb2; - if (usb_ep_queue(port->in_ep, req, GFP_ATOMIC)) - DBG(cdev, "echo response queue fail\n"); - break; - - case 1: /* echo response */ - case 2: /* suspend hint */ - case 3: /* response hint */ - case 4: /* response complete hint */ - case 5: /* tickle */ - default: /* reserved */ - continue; - } - } else { - u32 crc, crc2; - struct sk_buff *skb3; - - /* check for zero-length EEM packet */ - if (header == 0) - continue; - - /* EEM data packet format: - * b0..13: length of ethernet frame - * b14: bmCRC (0 == sentinel, 1 == calculated) - * b15: bmType (0 == data) - */ - len = header & 0x3FFF; - if ((skb->len < len) - || (len < (ETH_HLEN + ETH_FCS_LEN))) { - status = -EINVAL; - goto error; - } - - /* validate CRC */ - if (header & BIT(14)) { - crc = get_unaligned_le32(skb->data + len - - ETH_FCS_LEN); - crc2 = ~crc32_le(~0, - skb->data, len - ETH_FCS_LEN); - } else { - crc = get_unaligned_be32(skb->data + len - - ETH_FCS_LEN); - crc2 = 0xdeadbeef; - } - if (crc != crc2) { - DBG(cdev, "invalid EEM CRC\n"); - goto next; - } - - skb2 = skb_clone(skb, GFP_ATOMIC); - if (unlikely(!skb2)) { - DBG(cdev, "unable to unframe EEM packet\n"); - continue; - } - skb_trim(skb2, len - ETH_FCS_LEN); - - skb3 = skb_copy_expand(skb2, - NET_IP_ALIGN, - 0, - GFP_ATOMIC); - if (unlikely(!skb3)) { - DBG(cdev, "unable to realign EEM packet\n"); - dev_kfree_skb_any(skb2); - continue; - } - dev_kfree_skb_any(skb2); - skb_queue_tail(list, skb3); - } -next: - skb_pull(skb, len); - } while (skb->len); - -error: - dev_kfree_skb_any(skb); - return status; -} - -/** - * eem_bind_config - add CDC Ethernet (EEM) network link to a configuration - * @c: the configuration to support the network link - * Context: single threaded during gadget setup - * - * Returns zero on success, else negative errno. - * - * Caller must have called @gether_setup(). Caller is also responsible - * for calling @gether_cleanup() before module unload. - */ -int __init eem_bind_config(struct usb_configuration *c) -{ - struct f_eem *eem; - int status; - - /* maybe allocate device-global string IDs */ - if (eem_string_defs[0].id == 0) { - - /* control interface label */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - eem_string_defs[0].id = status; - eem_intf.iInterface = status; - } - - /* allocate and initialize one new instance */ - eem = kzalloc(sizeof *eem, GFP_KERNEL); - if (!eem) - return -ENOMEM; - - eem->port.cdc_filter = DEFAULT_FILTER; - - eem->port.func.name = "cdc_eem"; - eem->port.func.strings = eem_strings; - /* descriptors are per-instance copies */ - eem->port.func.bind = eem_bind; - eem->port.func.unbind = eem_unbind; - eem->port.func.set_alt = eem_set_alt; - eem->port.func.setup = eem_setup; - eem->port.func.disable = eem_disable; - eem->port.wrap = eem_wrap; - eem->port.unwrap = eem_unwrap; - eem->port.header_len = EEM_HLEN; - - status = usb_add_function(c, &eem->port.func); - if (status) - kfree(eem); - return status; -} - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_fs.c b/ANDROID_3.4.5/drivers/usb/gadget/f_fs.c deleted file mode 100644 index 7a86f350..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_fs.c +++ /dev/null @@ -1,2415 +0,0 @@ -/* - * f_fs.c -- user mode file system API for USB composite function controllers - * - * Copyright (C) 2010 Samsung Electronics - * Author: Michal Nazarewicz - * - * Based on inode.c (GadgetFS) which was: - * Copyright (C) 2003-2004 David Brownell - * Copyright (C) 2003 Agilent Technologies - * - * 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. - */ - - -/* #define DEBUG */ -/* #define VERBOSE_DEBUG */ - -#include -#include -#include -#include - -#include -#include - - -#define FUNCTIONFS_MAGIC 0xa647361 /* Chosen by a honest dice roll ;) */ - - -/* Debugging ****************************************************************/ - -#ifdef VERBOSE_DEBUG -# define pr_vdebug pr_debug -# define ffs_dump_mem(prefix, ptr, len) \ - print_hex_dump_bytes(pr_fmt(prefix ": "), DUMP_PREFIX_NONE, ptr, len) -#else -# define pr_vdebug(...) do { } while (0) -# define ffs_dump_mem(prefix, ptr, len) do { } while (0) -#endif /* VERBOSE_DEBUG */ - -#define ENTER() pr_vdebug("%s()\n", __func__) - - -/* The data structure and setup file ****************************************/ - -enum ffs_state { - /* - * Waiting for descriptors and strings. - * - * In this state no open(2), read(2) or write(2) on epfiles - * may succeed (which should not be the problem as there - * should be no such files opened in the first place). - */ - FFS_READ_DESCRIPTORS, - FFS_READ_STRINGS, - - /* - * We've got descriptors and strings. We are or have called - * functionfs_ready_callback(). functionfs_bind() may have - * been called but we don't know. - * - * This is the only state in which operations on epfiles may - * succeed. - */ - FFS_ACTIVE, - - /* - * All endpoints have been closed. This state is also set if - * we encounter an unrecoverable error. The only - * unrecoverable error is situation when after reading strings - * from user space we fail to initialise epfiles or - * functionfs_ready_callback() returns with error (<0). - * - * In this state no open(2), read(2) or write(2) (both on ep0 - * as well as epfile) may succeed (at this point epfiles are - * unlinked and all closed so this is not a problem; ep0 is - * also closed but ep0 file exists and so open(2) on ep0 must - * fail). - */ - FFS_CLOSING -}; - - -enum ffs_setup_state { - /* There is no setup request pending. */ - FFS_NO_SETUP, - /* - * User has read events and there was a setup request event - * there. The next read/write on ep0 will handle the - * request. - */ - FFS_SETUP_PENDING, - /* - * There was event pending but before user space handled it - * some other event was introduced which canceled existing - * setup. If this state is set read/write on ep0 return - * -EIDRM. This state is only set when adding event. - */ - FFS_SETUP_CANCELED -}; - - - -struct ffs_epfile; -struct ffs_function; - -struct ffs_data { - struct usb_gadget *gadget; - - /* - * Protect access read/write operations, only one read/write - * at a time. As a consequence protects ep0req and company. - * While setup request is being processed (queued) this is - * held. - */ - struct mutex mutex; - - /* - * Protect access to endpoint related structures (basically - * usb_ep_queue(), usb_ep_dequeue(), etc. calls) except for - * endpoint zero. - */ - spinlock_t eps_lock; - - /* - * XXX REVISIT do we need our own request? Since we are not - * handling setup requests immediately user space may be so - * slow that another setup will be sent to the gadget but this - * time not to us but another function and then there could be - * a race. Is that the case? Or maybe we can use cdev->req - * after all, maybe we just need some spinlock for that? - */ - struct usb_request *ep0req; /* P: mutex */ - struct completion ep0req_completion; /* P: mutex */ - int ep0req_status; /* P: mutex */ - - /* reference counter */ - atomic_t ref; - /* how many files are opened (EP0 and others) */ - atomic_t opened; - - /* EP0 state */ - enum ffs_state state; - - /* - * Possible transitions: - * + FFS_NO_SETUP -> FFS_SETUP_PENDING -- P: ev.waitq.lock - * happens only in ep0 read which is P: mutex - * + FFS_SETUP_PENDING -> FFS_NO_SETUP -- P: ev.waitq.lock - * happens only in ep0 i/o which is P: mutex - * + FFS_SETUP_PENDING -> FFS_SETUP_CANCELED -- P: ev.waitq.lock - * + FFS_SETUP_CANCELED -> FFS_NO_SETUP -- cmpxchg - */ - enum ffs_setup_state setup_state; - -#define FFS_SETUP_STATE(ffs) \ - ((enum ffs_setup_state)cmpxchg(&(ffs)->setup_state, \ - FFS_SETUP_CANCELED, FFS_NO_SETUP)) - - /* Events & such. */ - struct { - u8 types[4]; - unsigned short count; - /* XXX REVISIT need to update it in some places, or do we? */ - unsigned short can_stall; - struct usb_ctrlrequest setup; - - wait_queue_head_t waitq; - } ev; /* the whole structure, P: ev.waitq.lock */ - - /* Flags */ - unsigned long flags; -#define FFS_FL_CALL_CLOSED_CALLBACK 0 -#define FFS_FL_BOUND 1 - - /* Active function */ - struct ffs_function *func; - - /* - * Device name, write once when file system is mounted. - * Intended for user to read if she wants. - */ - const char *dev_name; - /* Private data for our user (ie. gadget). Managed by user. */ - void *private_data; - - /* filled by __ffs_data_got_descs() */ - /* - * Real descriptors are 16 bytes after raw_descs (so you need - * to skip 16 bytes (ie. ffs->raw_descs + 16) to get to the - * first full speed descriptor). raw_descs_length and - * raw_fs_descs_length do not have those 16 bytes added. - */ - const void *raw_descs; - unsigned raw_descs_length; - unsigned raw_fs_descs_length; - unsigned fs_descs_count; - unsigned hs_descs_count; - - unsigned short strings_count; - unsigned short interfaces_count; - unsigned short eps_count; - unsigned short _pad1; - - /* filled by __ffs_data_got_strings() */ - /* ids in stringtabs are set in functionfs_bind() */ - const void *raw_strings; - struct usb_gadget_strings **stringtabs; - - /* - * File system's super block, write once when file system is - * mounted. - */ - struct super_block *sb; - - /* File permissions, written once when fs is mounted */ - struct ffs_file_perms { - umode_t mode; - uid_t uid; - gid_t gid; - } file_perms; - - /* - * The endpoint files, filled by ffs_epfiles_create(), - * destroyed by ffs_epfiles_destroy(). - */ - struct ffs_epfile *epfiles; -}; - -/* Reference counter handling */ -static void ffs_data_get(struct ffs_data *ffs); -static void ffs_data_put(struct ffs_data *ffs); -/* Creates new ffs_data object. */ -static struct ffs_data *__must_check ffs_data_new(void) __attribute__((malloc)); - -/* Opened counter handling. */ -static void ffs_data_opened(struct ffs_data *ffs); -static void ffs_data_closed(struct ffs_data *ffs); - -/* Called with ffs->mutex held; take over ownership of data. */ -static int __must_check -__ffs_data_got_descs(struct ffs_data *ffs, char *data, size_t len); -static int __must_check -__ffs_data_got_strings(struct ffs_data *ffs, char *data, size_t len); - - -/* The function structure ***************************************************/ - -struct ffs_ep; - -struct ffs_function { - struct usb_configuration *conf; - struct usb_gadget *gadget; - struct ffs_data *ffs; - - struct ffs_ep *eps; - u8 eps_revmap[16]; - short *interfaces_nums; - - struct usb_function function; -}; - - -static struct ffs_function *ffs_func_from_usb(struct usb_function *f) -{ - return container_of(f, struct ffs_function, function); -} - -static void ffs_func_free(struct ffs_function *func); - -static void ffs_func_eps_disable(struct ffs_function *func); -static int __must_check ffs_func_eps_enable(struct ffs_function *func); - -static int ffs_func_bind(struct usb_configuration *, - struct usb_function *); -static void ffs_func_unbind(struct usb_configuration *, - struct usb_function *); -static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned); -static void ffs_func_disable(struct usb_function *); -static int ffs_func_setup(struct usb_function *, - const struct usb_ctrlrequest *); -static void ffs_func_suspend(struct usb_function *); -static void ffs_func_resume(struct usb_function *); - - -static int ffs_func_revmap_ep(struct ffs_function *func, u8 num); -static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf); - - -/* The endpoints structures *************************************************/ - -struct ffs_ep { - struct usb_ep *ep; /* P: ffs->eps_lock */ - struct usb_request *req; /* P: epfile->mutex */ - - /* [0]: full speed, [1]: high speed */ - struct usb_endpoint_descriptor *descs[2]; - - u8 num; - - int status; /* P: epfile->mutex */ -}; - -struct ffs_epfile { - /* Protects ep->ep and ep->req. */ - struct mutex mutex; - wait_queue_head_t wait; - - struct ffs_data *ffs; - struct ffs_ep *ep; /* P: ffs->eps_lock */ - - struct dentry *dentry; - - char name[5]; - - unsigned char in; /* P: ffs->eps_lock */ - unsigned char isoc; /* P: ffs->eps_lock */ - - unsigned char _pad; -}; - -static int __must_check ffs_epfiles_create(struct ffs_data *ffs); -static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count); - -static struct inode *__must_check -ffs_sb_create_file(struct super_block *sb, const char *name, void *data, - const struct file_operations *fops, - struct dentry **dentry_p); - - -/* Misc helper functions ****************************************************/ - -static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock) - __attribute__((warn_unused_result, nonnull)); -static char *ffs_prepare_buffer(const char * __user buf, size_t len) - __attribute__((warn_unused_result, nonnull)); - - -/* Control file aka ep0 *****************************************************/ - -static void ffs_ep0_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct ffs_data *ffs = req->context; - - complete_all(&ffs->ep0req_completion); -} - -static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len) -{ - struct usb_request *req = ffs->ep0req; - int ret; - - req->zero = len < le16_to_cpu(ffs->ev.setup.wLength); - - spin_unlock_irq(&ffs->ev.waitq.lock); - - req->buf = data; - req->length = len; - - /* - * UDC layer requires to provide a buffer even for ZLP, but should - * not use it at all. Let's provide some poisoned pointer to catch - * possible bug in the driver. - */ - if (req->buf == NULL) - req->buf = (void *)0xDEADBABE; - - INIT_COMPLETION(ffs->ep0req_completion); - - ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC); - if (unlikely(ret < 0)) - return ret; - - ret = wait_for_completion_interruptible(&ffs->ep0req_completion); - if (unlikely(ret)) { - usb_ep_dequeue(ffs->gadget->ep0, req); - return -EINTR; - } - - ffs->setup_state = FFS_NO_SETUP; - return ffs->ep0req_status; -} - -static int __ffs_ep0_stall(struct ffs_data *ffs) -{ - if (ffs->ev.can_stall) { - pr_vdebug("ep0 stall\n"); - usb_ep_set_halt(ffs->gadget->ep0); - ffs->setup_state = FFS_NO_SETUP; - return -EL2HLT; - } else { - pr_debug("bogus ep0 stall!\n"); - return -ESRCH; - } -} - -static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, - size_t len, loff_t *ptr) -{ - struct ffs_data *ffs = file->private_data; - ssize_t ret; - char *data; - - ENTER(); - - /* Fast check if setup was canceled */ - if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) - return -EIDRM; - - /* Acquire mutex */ - ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); - if (unlikely(ret < 0)) - return ret; - - /* Check state */ - switch (ffs->state) { - case FFS_READ_DESCRIPTORS: - case FFS_READ_STRINGS: - /* Copy data */ - if (unlikely(len < 16)) { - ret = -EINVAL; - break; - } - - data = ffs_prepare_buffer(buf, len); - if (IS_ERR(data)) { - ret = PTR_ERR(data); - break; - } - - /* Handle data */ - if (ffs->state == FFS_READ_DESCRIPTORS) { - pr_info("read descriptors\n"); - ret = __ffs_data_got_descs(ffs, data, len); - if (unlikely(ret < 0)) - break; - - ffs->state = FFS_READ_STRINGS; - ret = len; - } else { - pr_info("read strings\n"); - ret = __ffs_data_got_strings(ffs, data, len); - if (unlikely(ret < 0)) - break; - - ret = ffs_epfiles_create(ffs); - if (unlikely(ret)) { - ffs->state = FFS_CLOSING; - break; - } - - ffs->state = FFS_ACTIVE; - mutex_unlock(&ffs->mutex); - - ret = functionfs_ready_callback(ffs); - if (unlikely(ret < 0)) { - ffs->state = FFS_CLOSING; - return ret; - } - - set_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags); - return len; - } - break; - - case FFS_ACTIVE: - data = NULL; - /* - * We're called from user space, we can use _irq - * rather then _irqsave - */ - spin_lock_irq(&ffs->ev.waitq.lock); - switch (FFS_SETUP_STATE(ffs)) { - case FFS_SETUP_CANCELED: - ret = -EIDRM; - goto done_spin; - - case FFS_NO_SETUP: - ret = -ESRCH; - goto done_spin; - - case FFS_SETUP_PENDING: - break; - } - - /* FFS_SETUP_PENDING */ - if (!(ffs->ev.setup.bRequestType & USB_DIR_IN)) { - spin_unlock_irq(&ffs->ev.waitq.lock); - ret = __ffs_ep0_stall(ffs); - break; - } - - /* FFS_SETUP_PENDING and not stall */ - len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength)); - - spin_unlock_irq(&ffs->ev.waitq.lock); - - data = ffs_prepare_buffer(buf, len); - if (IS_ERR(data)) { - ret = PTR_ERR(data); - break; - } - - spin_lock_irq(&ffs->ev.waitq.lock); - - /* - * We are guaranteed to be still in FFS_ACTIVE state - * but the state of setup could have changed from - * FFS_SETUP_PENDING to FFS_SETUP_CANCELED so we need - * to check for that. If that happened we copied data - * from user space in vain but it's unlikely. - * - * For sure we are not in FFS_NO_SETUP since this is - * the only place FFS_SETUP_PENDING -> FFS_NO_SETUP - * transition can be performed and it's protected by - * mutex. - */ - if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) { - ret = -EIDRM; -done_spin: - spin_unlock_irq(&ffs->ev.waitq.lock); - } else { - /* unlocks spinlock */ - ret = __ffs_ep0_queue_wait(ffs, data, len); - } - kfree(data); - break; - - default: - ret = -EBADFD; - break; - } - - mutex_unlock(&ffs->mutex); - return ret; -} - -static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf, - size_t n) -{ - /* - * We are holding ffs->ev.waitq.lock and ffs->mutex and we need - * to release them. - */ - struct usb_functionfs_event events[n]; - unsigned i = 0; - - memset(events, 0, sizeof events); - - do { - events[i].type = ffs->ev.types[i]; - if (events[i].type == FUNCTIONFS_SETUP) { - events[i].u.setup = ffs->ev.setup; - ffs->setup_state = FFS_SETUP_PENDING; - } - } while (++i < n); - - if (n < ffs->ev.count) { - ffs->ev.count -= n; - memmove(ffs->ev.types, ffs->ev.types + n, - ffs->ev.count * sizeof *ffs->ev.types); - } else { - ffs->ev.count = 0; - } - - spin_unlock_irq(&ffs->ev.waitq.lock); - mutex_unlock(&ffs->mutex); - - return unlikely(__copy_to_user(buf, events, sizeof events)) - ? -EFAULT : sizeof events; -} - -static ssize_t ffs_ep0_read(struct file *file, char __user *buf, - size_t len, loff_t *ptr) -{ - struct ffs_data *ffs = file->private_data; - char *data = NULL; - size_t n; - int ret; - - ENTER(); - - /* Fast check if setup was canceled */ - if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) - return -EIDRM; - - /* Acquire mutex */ - ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); - if (unlikely(ret < 0)) - return ret; - - /* Check state */ - if (ffs->state != FFS_ACTIVE) { - ret = -EBADFD; - goto done_mutex; - } - - /* - * We're called from user space, we can use _irq rather then - * _irqsave - */ - spin_lock_irq(&ffs->ev.waitq.lock); - - switch (FFS_SETUP_STATE(ffs)) { - case FFS_SETUP_CANCELED: - ret = -EIDRM; - break; - - case FFS_NO_SETUP: - n = len / sizeof(struct usb_functionfs_event); - if (unlikely(!n)) { - ret = -EINVAL; - break; - } - - if ((file->f_flags & O_NONBLOCK) && !ffs->ev.count) { - ret = -EAGAIN; - break; - } - - if (wait_event_interruptible_exclusive_locked_irq(ffs->ev.waitq, - ffs->ev.count)) { - ret = -EINTR; - break; - } - - return __ffs_ep0_read_events(ffs, buf, - min(n, (size_t)ffs->ev.count)); - - case FFS_SETUP_PENDING: - if (ffs->ev.setup.bRequestType & USB_DIR_IN) { - spin_unlock_irq(&ffs->ev.waitq.lock); - ret = __ffs_ep0_stall(ffs); - goto done_mutex; - } - - len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength)); - - spin_unlock_irq(&ffs->ev.waitq.lock); - - if (likely(len)) { - data = kmalloc(len, GFP_KERNEL); - if (unlikely(!data)) { - ret = -ENOMEM; - goto done_mutex; - } - } - - spin_lock_irq(&ffs->ev.waitq.lock); - - /* See ffs_ep0_write() */ - if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) { - ret = -EIDRM; - break; - } - - /* unlocks spinlock */ - ret = __ffs_ep0_queue_wait(ffs, data, len); - if (likely(ret > 0) && unlikely(__copy_to_user(buf, data, len))) - ret = -EFAULT; - goto done_mutex; - - default: - ret = -EBADFD; - break; - } - - spin_unlock_irq(&ffs->ev.waitq.lock); -done_mutex: - mutex_unlock(&ffs->mutex); - kfree(data); - return ret; -} - -static int ffs_ep0_open(struct inode *inode, struct file *file) -{ - struct ffs_data *ffs = inode->i_private; - - ENTER(); - - if (unlikely(ffs->state == FFS_CLOSING)) - return -EBUSY; - - file->private_data = ffs; - ffs_data_opened(ffs); - - return 0; -} - -static int ffs_ep0_release(struct inode *inode, struct file *file) -{ - struct ffs_data *ffs = file->private_data; - - ENTER(); - - ffs_data_closed(ffs); - - return 0; -} - -static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value) -{ - struct ffs_data *ffs = file->private_data; - struct usb_gadget *gadget = ffs->gadget; - long ret; - - ENTER(); - - if (code == FUNCTIONFS_INTERFACE_REVMAP) { - struct ffs_function *func = ffs->func; - ret = func ? ffs_func_revmap_intf(func, value) : -ENODEV; - } else if (gadget && gadget->ops->ioctl) { - ret = gadget->ops->ioctl(gadget, code, value); - } else { - ret = -ENOTTY; - } - - return ret; -} - -static const struct file_operations ffs_ep0_operations = { - .owner = THIS_MODULE, - .llseek = no_llseek, - - .open = ffs_ep0_open, - .write = ffs_ep0_write, - .read = ffs_ep0_read, - .release = ffs_ep0_release, - .unlocked_ioctl = ffs_ep0_ioctl, -}; - - -/* "Normal" endpoints operations ********************************************/ - -static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req) -{ - ENTER(); - if (likely(req->context)) { - struct ffs_ep *ep = _ep->driver_data; - ep->status = req->status ? req->status : req->actual; - complete(req->context); - } -} - -static ssize_t ffs_epfile_io(struct file *file, - char __user *buf, size_t len, int read) -{ - struct ffs_epfile *epfile = file->private_data; - struct ffs_ep *ep; - char *data = NULL; - ssize_t ret; - int halt; - - goto first_try; - do { - spin_unlock_irq(&epfile->ffs->eps_lock); - mutex_unlock(&epfile->mutex); - -first_try: - /* Are we still active? */ - if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) { - ret = -ENODEV; - goto error; - } - - /* Wait for endpoint to be enabled */ - ep = epfile->ep; - if (!ep) { - if (file->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - goto error; - } - - if (wait_event_interruptible(epfile->wait, - (ep = epfile->ep))) { - ret = -EINTR; - goto error; - } - } - - /* Do we halt? */ - halt = !read == !epfile->in; - if (halt && epfile->isoc) { - ret = -EINVAL; - goto error; - } - - /* Allocate & copy */ - if (!halt && !data) { - data = kzalloc(len, GFP_KERNEL); - if (unlikely(!data)) - return -ENOMEM; - - if (!read && - unlikely(__copy_from_user(data, buf, len))) { - ret = -EFAULT; - goto error; - } - } - - /* We will be using request */ - ret = ffs_mutex_lock(&epfile->mutex, - file->f_flags & O_NONBLOCK); - if (unlikely(ret)) - goto error; - - /* - * We're called from user space, we can use _irq rather then - * _irqsave - */ - spin_lock_irq(&epfile->ffs->eps_lock); - - /* - * While we were acquiring mutex endpoint got disabled - * or changed? - */ - } while (unlikely(epfile->ep != ep)); - - /* Halt */ - if (unlikely(halt)) { - if (likely(epfile->ep == ep) && !WARN_ON(!ep->ep)) - usb_ep_set_halt(ep->ep); - spin_unlock_irq(&epfile->ffs->eps_lock); - ret = -EBADMSG; - } else { - /* Fire the request */ - DECLARE_COMPLETION_ONSTACK(done); - - struct usb_request *req = ep->req; - req->context = &done; - req->complete = ffs_epfile_io_complete; - req->buf = data; - req->length = len; - - ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); - - spin_unlock_irq(&epfile->ffs->eps_lock); - - if (unlikely(ret < 0)) { - /* nop */ - } else if (unlikely(wait_for_completion_interruptible(&done))) { - ret = -EINTR; - usb_ep_dequeue(ep->ep, req); - } else { - ret = ep->status; - if (read && ret > 0 && - unlikely(copy_to_user(buf, data, ret))) - ret = -EFAULT; - } - } - - mutex_unlock(&epfile->mutex); -error: - kfree(data); - return ret; -} - -static ssize_t -ffs_epfile_write(struct file *file, const char __user *buf, size_t len, - loff_t *ptr) -{ - ENTER(); - - return ffs_epfile_io(file, (char __user *)buf, len, 0); -} - -static ssize_t -ffs_epfile_read(struct file *file, char __user *buf, size_t len, loff_t *ptr) -{ - ENTER(); - - return ffs_epfile_io(file, buf, len, 1); -} - -static int -ffs_epfile_open(struct inode *inode, struct file *file) -{ - struct ffs_epfile *epfile = inode->i_private; - - ENTER(); - - if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) - return -ENODEV; - - file->private_data = epfile; - ffs_data_opened(epfile->ffs); - - return 0; -} - -static int -ffs_epfile_release(struct inode *inode, struct file *file) -{ - struct ffs_epfile *epfile = inode->i_private; - - ENTER(); - - ffs_data_closed(epfile->ffs); - - return 0; -} - -static long ffs_epfile_ioctl(struct file *file, unsigned code, - unsigned long value) -{ - struct ffs_epfile *epfile = file->private_data; - int ret; - - ENTER(); - - if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) - return -ENODEV; - - spin_lock_irq(&epfile->ffs->eps_lock); - if (likely(epfile->ep)) { - switch (code) { - case FUNCTIONFS_FIFO_STATUS: - ret = usb_ep_fifo_status(epfile->ep->ep); - break; - case FUNCTIONFS_FIFO_FLUSH: - usb_ep_fifo_flush(epfile->ep->ep); - ret = 0; - break; - case FUNCTIONFS_CLEAR_HALT: - ret = usb_ep_clear_halt(epfile->ep->ep); - break; - case FUNCTIONFS_ENDPOINT_REVMAP: - ret = epfile->ep->num; - break; - default: - ret = -ENOTTY; - } - } else { - ret = -ENODEV; - } - spin_unlock_irq(&epfile->ffs->eps_lock); - - return ret; -} - -static const struct file_operations ffs_epfile_operations = { - .owner = THIS_MODULE, - .llseek = no_llseek, - - .open = ffs_epfile_open, - .write = ffs_epfile_write, - .read = ffs_epfile_read, - .release = ffs_epfile_release, - .unlocked_ioctl = ffs_epfile_ioctl, -}; - - -/* File system and super block operations ***********************************/ - -/* - * Mounting the file system creates a controller file, used first for - * function configuration then later for event monitoring. - */ - -static struct inode *__must_check -ffs_sb_make_inode(struct super_block *sb, void *data, - const struct file_operations *fops, - const struct inode_operations *iops, - struct ffs_file_perms *perms) -{ - struct inode *inode; - - ENTER(); - - inode = new_inode(sb); - - if (likely(inode)) { - struct timespec current_time = CURRENT_TIME; - - inode->i_ino = get_next_ino(); - inode->i_mode = perms->mode; - inode->i_uid = perms->uid; - inode->i_gid = perms->gid; - inode->i_atime = current_time; - inode->i_mtime = current_time; - inode->i_ctime = current_time; - inode->i_private = data; - if (fops) - inode->i_fop = fops; - if (iops) - inode->i_op = iops; - } - - return inode; -} - -/* Create "regular" file */ -static struct inode *ffs_sb_create_file(struct super_block *sb, - const char *name, void *data, - const struct file_operations *fops, - struct dentry **dentry_p) -{ - struct ffs_data *ffs = sb->s_fs_info; - struct dentry *dentry; - struct inode *inode; - - ENTER(); - - dentry = d_alloc_name(sb->s_root, name); - if (unlikely(!dentry)) - return NULL; - - inode = ffs_sb_make_inode(sb, data, fops, NULL, &ffs->file_perms); - if (unlikely(!inode)) { - dput(dentry); - return NULL; - } - - d_add(dentry, inode); - if (dentry_p) - *dentry_p = dentry; - - return inode; -} - -/* Super block */ -static const struct super_operations ffs_sb_operations = { - .statfs = simple_statfs, - .drop_inode = generic_delete_inode, -}; - -struct ffs_sb_fill_data { - struct ffs_file_perms perms; - umode_t root_mode; - const char *dev_name; -}; - -static int ffs_sb_fill(struct super_block *sb, void *_data, int silent) -{ - struct ffs_sb_fill_data *data = _data; - struct inode *inode; - struct ffs_data *ffs; - - ENTER(); - - /* Initialise data */ - ffs = ffs_data_new(); - if (unlikely(!ffs)) - goto Enomem; - - ffs->sb = sb; - ffs->dev_name = data->dev_name; - ffs->file_perms = data->perms; - - sb->s_fs_info = ffs; - sb->s_blocksize = PAGE_CACHE_SIZE; - sb->s_blocksize_bits = PAGE_CACHE_SHIFT; - sb->s_magic = FUNCTIONFS_MAGIC; - sb->s_op = &ffs_sb_operations; - sb->s_time_gran = 1; - - /* Root inode */ - data->perms.mode = data->root_mode; - inode = ffs_sb_make_inode(sb, NULL, - &simple_dir_operations, - &simple_dir_inode_operations, - &data->perms); - sb->s_root = d_make_root(inode); - if (unlikely(!sb->s_root)) - goto Enomem; - - /* EP0 file */ - if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs, - &ffs_ep0_operations, NULL))) - goto Enomem; - - return 0; - -Enomem: - return -ENOMEM; -} - -static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts) -{ - ENTER(); - - if (!opts || !*opts) - return 0; - - for (;;) { - char *end, *eq, *comma; - unsigned long value; - - /* Option limit */ - comma = strchr(opts, ','); - if (comma) - *comma = 0; - - /* Value limit */ - eq = strchr(opts, '='); - if (unlikely(!eq)) { - pr_err("'=' missing in %s\n", opts); - return -EINVAL; - } - *eq = 0; - - /* Parse value */ - value = simple_strtoul(eq + 1, &end, 0); - if (unlikely(*end != ',' && *end != 0)) { - pr_err("%s: invalid value: %s\n", opts, eq + 1); - return -EINVAL; - } - - /* Interpret option */ - switch (eq - opts) { - case 5: - if (!memcmp(opts, "rmode", 5)) - data->root_mode = (value & 0555) | S_IFDIR; - else if (!memcmp(opts, "fmode", 5)) - data->perms.mode = (value & 0666) | S_IFREG; - else - goto invalid; - break; - - case 4: - if (!memcmp(opts, "mode", 4)) { - data->root_mode = (value & 0555) | S_IFDIR; - data->perms.mode = (value & 0666) | S_IFREG; - } else { - goto invalid; - } - break; - - case 3: - if (!memcmp(opts, "uid", 3)) - data->perms.uid = value; - else if (!memcmp(opts, "gid", 3)) - data->perms.gid = value; - else - goto invalid; - break; - - default: -invalid: - pr_err("%s: invalid option\n", opts); - return -EINVAL; - } - - /* Next iteration */ - if (!comma) - break; - opts = comma + 1; - } - - return 0; -} - -/* "mount -t functionfs dev_name /dev/function" ends up here */ - -static struct dentry * -ffs_fs_mount(struct file_system_type *t, int flags, - const char *dev_name, void *opts) -{ - struct ffs_sb_fill_data data = { - .perms = { - .mode = S_IFREG | 0600, - .uid = 0, - .gid = 0 - }, - .root_mode = S_IFDIR | 0500, - }; - int ret; - - ENTER(); - - ret = functionfs_check_dev_callback(dev_name); - if (unlikely(ret < 0)) - return ERR_PTR(ret); - - ret = ffs_fs_parse_opts(&data, opts); - if (unlikely(ret < 0)) - return ERR_PTR(ret); - - data.dev_name = dev_name; - return mount_single(t, flags, &data, ffs_sb_fill); -} - -static void -ffs_fs_kill_sb(struct super_block *sb) -{ - ENTER(); - - kill_litter_super(sb); - if (sb->s_fs_info) - ffs_data_put(sb->s_fs_info); -} - -static struct file_system_type ffs_fs_type = { - .owner = THIS_MODULE, - .name = "functionfs", - .mount = ffs_fs_mount, - .kill_sb = ffs_fs_kill_sb, -}; - - -/* Driver's main init/cleanup functions *************************************/ - -static int functionfs_init(void) -{ - int ret; - - ENTER(); - - ret = register_filesystem(&ffs_fs_type); - if (likely(!ret)) - pr_info("file system registered\n"); - else - pr_err("failed registering file system (%d)\n", ret); - - return ret; -} - -static void functionfs_cleanup(void) -{ - ENTER(); - - pr_info("unloading\n"); - unregister_filesystem(&ffs_fs_type); -} - - -/* ffs_data and ffs_function construction and destruction code **************/ - -static void ffs_data_clear(struct ffs_data *ffs); -static void ffs_data_reset(struct ffs_data *ffs); - -static void ffs_data_get(struct ffs_data *ffs) -{ - ENTER(); - - atomic_inc(&ffs->ref); -} - -static void ffs_data_opened(struct ffs_data *ffs) -{ - ENTER(); - - atomic_inc(&ffs->ref); - atomic_inc(&ffs->opened); -} - -static void ffs_data_put(struct ffs_data *ffs) -{ - ENTER(); - - if (unlikely(atomic_dec_and_test(&ffs->ref))) { - pr_info("%s(): freeing\n", __func__); - ffs_data_clear(ffs); - BUG_ON(waitqueue_active(&ffs->ev.waitq) || - waitqueue_active(&ffs->ep0req_completion.wait)); - kfree(ffs); - } -} - -static void ffs_data_closed(struct ffs_data *ffs) -{ - ENTER(); - - if (atomic_dec_and_test(&ffs->opened)) { - ffs->state = FFS_CLOSING; - ffs_data_reset(ffs); - } - - ffs_data_put(ffs); -} - -static struct ffs_data *ffs_data_new(void) -{ - struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL); - if (unlikely(!ffs)) - return 0; - - ENTER(); - - atomic_set(&ffs->ref, 1); - atomic_set(&ffs->opened, 0); - ffs->state = FFS_READ_DESCRIPTORS; - mutex_init(&ffs->mutex); - spin_lock_init(&ffs->eps_lock); - init_waitqueue_head(&ffs->ev.waitq); - init_completion(&ffs->ep0req_completion); - - /* XXX REVISIT need to update it in some places, or do we? */ - ffs->ev.can_stall = 1; - - return ffs; -} - -static void ffs_data_clear(struct ffs_data *ffs) -{ - ENTER(); - - if (test_and_clear_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags)) - functionfs_closed_callback(ffs); - - BUG_ON(ffs->gadget); - - if (ffs->epfiles) - ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count); - - kfree(ffs->raw_descs); - kfree(ffs->raw_strings); - kfree(ffs->stringtabs); -} - -static void ffs_data_reset(struct ffs_data *ffs) -{ - ENTER(); - - ffs_data_clear(ffs); - - ffs->epfiles = NULL; - ffs->raw_descs = NULL; - ffs->raw_strings = NULL; - ffs->stringtabs = NULL; - - ffs->raw_descs_length = 0; - ffs->raw_fs_descs_length = 0; - ffs->fs_descs_count = 0; - ffs->hs_descs_count = 0; - - ffs->strings_count = 0; - ffs->interfaces_count = 0; - ffs->eps_count = 0; - - ffs->ev.count = 0; - - ffs->state = FFS_READ_DESCRIPTORS; - ffs->setup_state = FFS_NO_SETUP; - ffs->flags = 0; -} - - -static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev) -{ - struct usb_gadget_strings **lang; - int first_id; - - ENTER(); - - if (WARN_ON(ffs->state != FFS_ACTIVE - || test_and_set_bit(FFS_FL_BOUND, &ffs->flags))) - return -EBADFD; - - first_id = usb_string_ids_n(cdev, ffs->strings_count); - if (unlikely(first_id < 0)) - return first_id; - - ffs->ep0req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL); - if (unlikely(!ffs->ep0req)) - return -ENOMEM; - ffs->ep0req->complete = ffs_ep0_complete; - ffs->ep0req->context = ffs; - - lang = ffs->stringtabs; - for (lang = ffs->stringtabs; *lang; ++lang) { - struct usb_string *str = (*lang)->strings; - int id = first_id; - for (; str->s; ++id, ++str) - str->id = id; - } - - ffs->gadget = cdev->gadget; - ffs_data_get(ffs); - return 0; -} - -static void functionfs_unbind(struct ffs_data *ffs) -{ - ENTER(); - - if (!WARN_ON(!ffs->gadget)) { - usb_ep_free_request(ffs->gadget->ep0, ffs->ep0req); - ffs->ep0req = NULL; - ffs->gadget = NULL; - ffs_data_put(ffs); - clear_bit(FFS_FL_BOUND, &ffs->flags); - } -} - -static int ffs_epfiles_create(struct ffs_data *ffs) -{ - struct ffs_epfile *epfile, *epfiles; - unsigned i, count; - - ENTER(); - - count = ffs->eps_count; - epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL); - if (!epfiles) - return -ENOMEM; - - epfile = epfiles; - for (i = 1; i <= count; ++i, ++epfile) { - epfile->ffs = ffs; - mutex_init(&epfile->mutex); - init_waitqueue_head(&epfile->wait); - sprintf(epfiles->name, "ep%u", i); - if (!unlikely(ffs_sb_create_file(ffs->sb, epfiles->name, epfile, - &ffs_epfile_operations, - &epfile->dentry))) { - ffs_epfiles_destroy(epfiles, i - 1); - return -ENOMEM; - } - } - - ffs->epfiles = epfiles; - return 0; -} - -static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count) -{ - struct ffs_epfile *epfile = epfiles; - - ENTER(); - - for (; count; --count, ++epfile) { - BUG_ON(mutex_is_locked(&epfile->mutex) || - waitqueue_active(&epfile->wait)); - if (epfile->dentry) { - d_delete(epfile->dentry); - dput(epfile->dentry); - epfile->dentry = NULL; - } - } - - kfree(epfiles); -} - -static int functionfs_bind_config(struct usb_composite_dev *cdev, - struct usb_configuration *c, - struct ffs_data *ffs) -{ - struct ffs_function *func; - int ret; - - ENTER(); - - func = kzalloc(sizeof *func, GFP_KERNEL); - if (unlikely(!func)) - return -ENOMEM; - - func->function.name = "Function FS Gadget"; - func->function.strings = ffs->stringtabs; - - func->function.bind = ffs_func_bind; - func->function.unbind = ffs_func_unbind; - func->function.set_alt = ffs_func_set_alt; - func->function.disable = ffs_func_disable; - func->function.setup = ffs_func_setup; - func->function.suspend = ffs_func_suspend; - func->function.resume = ffs_func_resume; - - func->conf = c; - func->gadget = cdev->gadget; - func->ffs = ffs; - ffs_data_get(ffs); - - ret = usb_add_function(c, &func->function); - if (unlikely(ret)) - ffs_func_free(func); - - return ret; -} - -static void ffs_func_free(struct ffs_function *func) -{ - ENTER(); - - ffs_data_put(func->ffs); - - kfree(func->eps); - /* - * eps and interfaces_nums are allocated in the same chunk so - * only one free is required. Descriptors are also allocated - * in the same chunk. - */ - - kfree(func); -} - -static void ffs_func_eps_disable(struct ffs_function *func) -{ - struct ffs_ep *ep = func->eps; - struct ffs_epfile *epfile = func->ffs->epfiles; - unsigned count = func->ffs->eps_count; - unsigned long flags; - - spin_lock_irqsave(&func->ffs->eps_lock, flags); - do { - /* pending requests get nuked */ - if (likely(ep->ep)) - usb_ep_disable(ep->ep); - epfile->ep = NULL; - - ++ep; - ++epfile; - } while (--count); - spin_unlock_irqrestore(&func->ffs->eps_lock, flags); -} - -static int ffs_func_eps_enable(struct ffs_function *func) -{ - struct ffs_data *ffs = func->ffs; - struct ffs_ep *ep = func->eps; - struct ffs_epfile *epfile = ffs->epfiles; - unsigned count = ffs->eps_count; - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&func->ffs->eps_lock, flags); - do { - struct usb_endpoint_descriptor *ds; - int desc_idx = ffs->gadget->speed == USB_SPEED_HIGH ? 1 : 0; - ds = ep->descs[desc_idx]; - if (!ds) { - ret = -EINVAL; - break; - } - - ep->ep->driver_data = ep; - ep->ep->desc = ds; - ret = usb_ep_enable(ep->ep); - if (likely(!ret)) { - epfile->ep = ep; - epfile->in = usb_endpoint_dir_in(ds); - epfile->isoc = usb_endpoint_xfer_isoc(ds); - } else { - break; - } - - wake_up(&epfile->wait); - - ++ep; - ++epfile; - } while (--count); - spin_unlock_irqrestore(&func->ffs->eps_lock, flags); - - return ret; -} - - -/* Parsing and building descriptors and strings *****************************/ - -/* - * This validates if data pointed by data is a valid USB descriptor as - * well as record how many interfaces, endpoints and strings are - * required by given configuration. Returns address after the - * descriptor or NULL if data is invalid. - */ - -enum ffs_entity_type { - FFS_DESCRIPTOR, FFS_INTERFACE, FFS_STRING, FFS_ENDPOINT -}; - -typedef int (*ffs_entity_callback)(enum ffs_entity_type entity, - u8 *valuep, - struct usb_descriptor_header *desc, - void *priv); - -static int __must_check ffs_do_desc(char *data, unsigned len, - ffs_entity_callback entity, void *priv) -{ - struct usb_descriptor_header *_ds = (void *)data; - u8 length; - int ret; - - ENTER(); - - /* At least two bytes are required: length and type */ - if (len < 2) { - pr_vdebug("descriptor too short\n"); - return -EINVAL; - } - - /* If we have at least as many bytes as the descriptor takes? */ - length = _ds->bLength; - if (len < length) { - pr_vdebug("descriptor longer then available data\n"); - return -EINVAL; - } - -#define __entity_check_INTERFACE(val) 1 -#define __entity_check_STRING(val) (val) -#define __entity_check_ENDPOINT(val) ((val) & USB_ENDPOINT_NUMBER_MASK) -#define __entity(type, val) do { \ - pr_vdebug("entity " #type "(%02x)\n", (val)); \ - if (unlikely(!__entity_check_ ##type(val))) { \ - pr_vdebug("invalid entity's value\n"); \ - return -EINVAL; \ - } \ - ret = entity(FFS_ ##type, &val, _ds, priv); \ - if (unlikely(ret < 0)) { \ - pr_debug("entity " #type "(%02x); ret = %d\n", \ - (val), ret); \ - return ret; \ - } \ - } while (0) - - /* Parse descriptor depending on type. */ - switch (_ds->bDescriptorType) { - case USB_DT_DEVICE: - case USB_DT_CONFIG: - case USB_DT_STRING: - case USB_DT_DEVICE_QUALIFIER: - /* function can't have any of those */ - pr_vdebug("descriptor reserved for gadget: %d\n", - _ds->bDescriptorType); - return -EINVAL; - - case USB_DT_INTERFACE: { - struct usb_interface_descriptor *ds = (void *)_ds; - pr_vdebug("interface descriptor\n"); - if (length != sizeof *ds) - goto inv_length; - - __entity(INTERFACE, ds->bInterfaceNumber); - if (ds->iInterface) - __entity(STRING, ds->iInterface); - } - break; - - case USB_DT_ENDPOINT: { - struct usb_endpoint_descriptor *ds = (void *)_ds; - pr_vdebug("endpoint descriptor\n"); - if (length != USB_DT_ENDPOINT_SIZE && - length != USB_DT_ENDPOINT_AUDIO_SIZE) - goto inv_length; - __entity(ENDPOINT, ds->bEndpointAddress); - } - break; - - case USB_DT_OTG: - if (length != sizeof(struct usb_otg_descriptor)) - goto inv_length; - break; - - case USB_DT_INTERFACE_ASSOCIATION: { - struct usb_interface_assoc_descriptor *ds = (void *)_ds; - pr_vdebug("interface association descriptor\n"); - if (length != sizeof *ds) - goto inv_length; - if (ds->iFunction) - __entity(STRING, ds->iFunction); - } - break; - - case USB_DT_OTHER_SPEED_CONFIG: - case USB_DT_INTERFACE_POWER: - case USB_DT_DEBUG: - case USB_DT_SECURITY: - case USB_DT_CS_RADIO_CONTROL: - /* TODO */ - pr_vdebug("unimplemented descriptor: %d\n", _ds->bDescriptorType); - return -EINVAL; - - default: - /* We should never be here */ - pr_vdebug("unknown descriptor: %d\n", _ds->bDescriptorType); - return -EINVAL; - -inv_length: - pr_vdebug("invalid length: %d (descriptor %d)\n", - _ds->bLength, _ds->bDescriptorType); - return -EINVAL; - } - -#undef __entity -#undef __entity_check_DESCRIPTOR -#undef __entity_check_INTERFACE -#undef __entity_check_STRING -#undef __entity_check_ENDPOINT - - return length; -} - -static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len, - ffs_entity_callback entity, void *priv) -{ - const unsigned _len = len; - unsigned long num = 0; - - ENTER(); - - for (;;) { - int ret; - - if (num == count) - data = NULL; - - /* Record "descriptor" entity */ - ret = entity(FFS_DESCRIPTOR, (u8 *)num, (void *)data, priv); - if (unlikely(ret < 0)) { - pr_debug("entity DESCRIPTOR(%02lx); ret = %d\n", - num, ret); - return ret; - } - - if (!data) - return _len - len; - - ret = ffs_do_desc(data, len, entity, priv); - if (unlikely(ret < 0)) { - pr_debug("%s returns %d\n", __func__, ret); - return ret; - } - - len -= ret; - data += ret; - ++num; - } -} - -static int __ffs_data_do_entity(enum ffs_entity_type type, - u8 *valuep, struct usb_descriptor_header *desc, - void *priv) -{ - struct ffs_data *ffs = priv; - - ENTER(); - - switch (type) { - case FFS_DESCRIPTOR: - break; - - case FFS_INTERFACE: - /* - * Interfaces are indexed from zero so if we - * encountered interface "n" then there are at least - * "n+1" interfaces. - */ - if (*valuep >= ffs->interfaces_count) - ffs->interfaces_count = *valuep + 1; - break; - - case FFS_STRING: - /* - * Strings are indexed from 1 (0 is magic ;) reserved - * for languages list or some such) - */ - if (*valuep > ffs->strings_count) - ffs->strings_count = *valuep; - break; - - case FFS_ENDPOINT: - /* Endpoints are indexed from 1 as well. */ - if ((*valuep & USB_ENDPOINT_NUMBER_MASK) > ffs->eps_count) - ffs->eps_count = (*valuep & USB_ENDPOINT_NUMBER_MASK); - break; - } - - return 0; -} - -static int __ffs_data_got_descs(struct ffs_data *ffs, - char *const _data, size_t len) -{ - unsigned fs_count, hs_count; - int fs_len, ret = -EINVAL; - char *data = _data; - - ENTER(); - - if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_DESCRIPTORS_MAGIC || - get_unaligned_le32(data + 4) != len)) - goto error; - fs_count = get_unaligned_le32(data + 8); - hs_count = get_unaligned_le32(data + 12); - - if (!fs_count && !hs_count) - goto einval; - - data += 16; - len -= 16; - - if (likely(fs_count)) { - fs_len = ffs_do_descs(fs_count, data, len, - __ffs_data_do_entity, ffs); - if (unlikely(fs_len < 0)) { - ret = fs_len; - goto error; - } - - data += fs_len; - len -= fs_len; - } else { - fs_len = 0; - } - - if (likely(hs_count)) { - ret = ffs_do_descs(hs_count, data, len, - __ffs_data_do_entity, ffs); - if (unlikely(ret < 0)) - goto error; - } else { - ret = 0; - } - - if (unlikely(len != ret)) - goto einval; - - ffs->raw_fs_descs_length = fs_len; - ffs->raw_descs_length = fs_len + ret; - ffs->raw_descs = _data; - ffs->fs_descs_count = fs_count; - ffs->hs_descs_count = hs_count; - - return 0; - -einval: - ret = -EINVAL; -error: - kfree(_data); - return ret; -} - -static int __ffs_data_got_strings(struct ffs_data *ffs, - char *const _data, size_t len) -{ - u32 str_count, needed_count, lang_count; - struct usb_gadget_strings **stringtabs, *t; - struct usb_string *strings, *s; - const char *data = _data; - - ENTER(); - - if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC || - get_unaligned_le32(data + 4) != len)) - goto error; - str_count = get_unaligned_le32(data + 8); - lang_count = get_unaligned_le32(data + 12); - - /* if one is zero the other must be zero */ - if (unlikely(!str_count != !lang_count)) - goto error; - - /* Do we have at least as many strings as descriptors need? */ - needed_count = ffs->strings_count; - if (unlikely(str_count < needed_count)) - goto error; - - /* - * If we don't need any strings just return and free all - * memory. - */ - if (!needed_count) { - kfree(_data); - return 0; - } - - /* Allocate everything in one chunk so there's less maintenance. */ - { - struct { - struct usb_gadget_strings *stringtabs[lang_count + 1]; - struct usb_gadget_strings stringtab[lang_count]; - struct usb_string strings[lang_count*(needed_count+1)]; - } *d; - unsigned i = 0; - - d = kmalloc(sizeof *d, GFP_KERNEL); - if (unlikely(!d)) { - kfree(_data); - return -ENOMEM; - } - - stringtabs = d->stringtabs; - t = d->stringtab; - i = lang_count; - do { - *stringtabs++ = t++; - } while (--i); - *stringtabs = NULL; - - stringtabs = d->stringtabs; - t = d->stringtab; - s = d->strings; - strings = s; - } - - /* For each language */ - data += 16; - len -= 16; - - do { /* lang_count > 0 so we can use do-while */ - unsigned needed = needed_count; - - if (unlikely(len < 3)) - goto error_free; - t->language = get_unaligned_le16(data); - t->strings = s; - ++t; - - data += 2; - len -= 2; - - /* For each string */ - do { /* str_count > 0 so we can use do-while */ - size_t length = strnlen(data, len); - - if (unlikely(length == len)) - goto error_free; - - /* - * User may provide more strings then we need, - * if that's the case we simply ignore the - * rest - */ - if (likely(needed)) { - /* - * s->id will be set while adding - * function to configuration so for - * now just leave garbage here. - */ - s->s = data; - --needed; - ++s; - } - - data += length + 1; - len -= length + 1; - } while (--str_count); - - s->id = 0; /* terminator */ - s->s = NULL; - ++s; - - } while (--lang_count); - - /* Some garbage left? */ - if (unlikely(len)) - goto error_free; - - /* Done! */ - ffs->stringtabs = stringtabs; - ffs->raw_strings = _data; - - return 0; - -error_free: - kfree(stringtabs); -error: - kfree(_data); - return -EINVAL; -} - - -/* Events handling and management *******************************************/ - -static void __ffs_event_add(struct ffs_data *ffs, - enum usb_functionfs_event_type type) -{ - enum usb_functionfs_event_type rem_type1, rem_type2 = type; - int neg = 0; - - /* - * Abort any unhandled setup - * - * We do not need to worry about some cmpxchg() changing value - * of ffs->setup_state without holding the lock because when - * state is FFS_SETUP_PENDING cmpxchg() in several places in - * the source does nothing. - */ - if (ffs->setup_state == FFS_SETUP_PENDING) - ffs->setup_state = FFS_SETUP_CANCELED; - - switch (type) { - case FUNCTIONFS_RESUME: - rem_type2 = FUNCTIONFS_SUSPEND; - /* FALL THROUGH */ - case FUNCTIONFS_SUSPEND: - case FUNCTIONFS_SETUP: - rem_type1 = type; - /* Discard all similar events */ - break; - - case FUNCTIONFS_BIND: - case FUNCTIONFS_UNBIND: - case FUNCTIONFS_DISABLE: - case FUNCTIONFS_ENABLE: - /* Discard everything other then power management. */ - rem_type1 = FUNCTIONFS_SUSPEND; - rem_type2 = FUNCTIONFS_RESUME; - neg = 1; - break; - - default: - BUG(); - } - - { - u8 *ev = ffs->ev.types, *out = ev; - unsigned n = ffs->ev.count; - for (; n; --n, ++ev) - if ((*ev == rem_type1 || *ev == rem_type2) == neg) - *out++ = *ev; - else - pr_vdebug("purging event %d\n", *ev); - ffs->ev.count = out - ffs->ev.types; - } - - pr_vdebug("adding event %d\n", type); - ffs->ev.types[ffs->ev.count++] = type; - wake_up_locked(&ffs->ev.waitq); -} - -static void ffs_event_add(struct ffs_data *ffs, - enum usb_functionfs_event_type type) -{ - unsigned long flags; - spin_lock_irqsave(&ffs->ev.waitq.lock, flags); - __ffs_event_add(ffs, type); - spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags); -} - - -/* Bind/unbind USB function hooks *******************************************/ - -static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep, - struct usb_descriptor_header *desc, - void *priv) -{ - struct usb_endpoint_descriptor *ds = (void *)desc; - struct ffs_function *func = priv; - struct ffs_ep *ffs_ep; - - /* - * If hs_descriptors is not NULL then we are reading hs - * descriptors now - */ - const int isHS = func->function.hs_descriptors != NULL; - unsigned idx; - - if (type != FFS_DESCRIPTOR) - return 0; - - if (isHS) - func->function.hs_descriptors[(long)valuep] = desc; - else - func->function.descriptors[(long)valuep] = desc; - - if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT) - return 0; - - idx = (ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) - 1; - ffs_ep = func->eps + idx; - - if (unlikely(ffs_ep->descs[isHS])) { - pr_vdebug("two %sspeed descriptors for EP %d\n", - isHS ? "high" : "full", - ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); - return -EINVAL; - } - ffs_ep->descs[isHS] = ds; - - ffs_dump_mem(": Original ep desc", ds, ds->bLength); - if (ffs_ep->ep) { - ds->bEndpointAddress = ffs_ep->descs[0]->bEndpointAddress; - if (!ds->wMaxPacketSize) - ds->wMaxPacketSize = ffs_ep->descs[0]->wMaxPacketSize; - } else { - struct usb_request *req; - struct usb_ep *ep; - - pr_vdebug("autoconfig\n"); - ep = usb_ep_autoconfig(func->gadget, ds); - if (unlikely(!ep)) - return -ENOTSUPP; - ep->driver_data = func->eps + idx; - - req = usb_ep_alloc_request(ep, GFP_KERNEL); - if (unlikely(!req)) - return -ENOMEM; - - ffs_ep->ep = ep; - ffs_ep->req = req; - func->eps_revmap[ds->bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK] = idx + 1; - } - ffs_dump_mem(": Rewritten ep desc", ds, ds->bLength); - - return 0; -} - -static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep, - struct usb_descriptor_header *desc, - void *priv) -{ - struct ffs_function *func = priv; - unsigned idx; - u8 newValue; - - switch (type) { - default: - case FFS_DESCRIPTOR: - /* Handled in previous pass by __ffs_func_bind_do_descs() */ - return 0; - - case FFS_INTERFACE: - idx = *valuep; - if (func->interfaces_nums[idx] < 0) { - int id = usb_interface_id(func->conf, &func->function); - if (unlikely(id < 0)) - return id; - func->interfaces_nums[idx] = id; - } - newValue = func->interfaces_nums[idx]; - break; - - case FFS_STRING: - /* String' IDs are allocated when fsf_data is bound to cdev */ - newValue = func->ffs->stringtabs[0]->strings[*valuep - 1].id; - break; - - case FFS_ENDPOINT: - /* - * USB_DT_ENDPOINT are handled in - * __ffs_func_bind_do_descs(). - */ - if (desc->bDescriptorType == USB_DT_ENDPOINT) - return 0; - - idx = (*valuep & USB_ENDPOINT_NUMBER_MASK) - 1; - if (unlikely(!func->eps[idx].ep)) - return -EINVAL; - - { - struct usb_endpoint_descriptor **descs; - descs = func->eps[idx].descs; - newValue = descs[descs[0] ? 0 : 1]->bEndpointAddress; - } - break; - } - - pr_vdebug("%02x -> %02x\n", *valuep, newValue); - *valuep = newValue; - return 0; -} - -static int ffs_func_bind(struct usb_configuration *c, - struct usb_function *f) -{ - struct ffs_function *func = ffs_func_from_usb(f); - struct ffs_data *ffs = func->ffs; - - const int full = !!func->ffs->fs_descs_count; - const int high = gadget_is_dualspeed(func->gadget) && - func->ffs->hs_descs_count; - - int ret; - - /* Make it a single chunk, less management later on */ - struct { - struct ffs_ep eps[ffs->eps_count]; - struct usb_descriptor_header - *fs_descs[full ? ffs->fs_descs_count + 1 : 0]; - struct usb_descriptor_header - *hs_descs[high ? ffs->hs_descs_count + 1 : 0]; - short inums[ffs->interfaces_count]; - char raw_descs[high ? ffs->raw_descs_length - : ffs->raw_fs_descs_length]; - } *data; - - ENTER(); - - /* Only high speed but not supported by gadget? */ - if (unlikely(!(full | high))) - return -ENOTSUPP; - - /* Allocate */ - data = kmalloc(sizeof *data, GFP_KERNEL); - if (unlikely(!data)) - return -ENOMEM; - - /* Zero */ - memset(data->eps, 0, sizeof data->eps); - memcpy(data->raw_descs, ffs->raw_descs + 16, sizeof data->raw_descs); - memset(data->inums, 0xff, sizeof data->inums); - for (ret = ffs->eps_count; ret; --ret) - data->eps[ret].num = -1; - - /* Save pointers */ - func->eps = data->eps; - func->interfaces_nums = data->inums; - - /* - * Go through all the endpoint descriptors and allocate - * endpoints first, so that later we can rewrite the endpoint - * numbers without worrying that it may be described later on. - */ - if (likely(full)) { - func->function.descriptors = data->fs_descs; - ret = ffs_do_descs(ffs->fs_descs_count, - data->raw_descs, - sizeof data->raw_descs, - __ffs_func_bind_do_descs, func); - if (unlikely(ret < 0)) - goto error; - } else { - ret = 0; - } - - if (likely(high)) { - func->function.hs_descriptors = data->hs_descs; - ret = ffs_do_descs(ffs->hs_descs_count, - data->raw_descs + ret, - (sizeof data->raw_descs) - ret, - __ffs_func_bind_do_descs, func); - } - - /* - * Now handle interface numbers allocation and interface and - * endpoint numbers rewriting. We can do that in one go - * now. - */ - ret = ffs_do_descs(ffs->fs_descs_count + - (high ? ffs->hs_descs_count : 0), - data->raw_descs, sizeof data->raw_descs, - __ffs_func_bind_do_nums, func); - if (unlikely(ret < 0)) - goto error; - - /* And we're done */ - ffs_event_add(ffs, FUNCTIONFS_BIND); - return 0; - -error: - /* XXX Do we need to release all claimed endpoints here? */ - return ret; -} - - -/* Other USB function hooks *************************************************/ - -static void ffs_func_unbind(struct usb_configuration *c, - struct usb_function *f) -{ - struct ffs_function *func = ffs_func_from_usb(f); - struct ffs_data *ffs = func->ffs; - - ENTER(); - - if (ffs->func == func) { - ffs_func_eps_disable(func); - ffs->func = NULL; - } - - ffs_event_add(ffs, FUNCTIONFS_UNBIND); - - ffs_func_free(func); -} - -static int ffs_func_set_alt(struct usb_function *f, - unsigned interface, unsigned alt) -{ - struct ffs_function *func = ffs_func_from_usb(f); - struct ffs_data *ffs = func->ffs; - int ret = 0, intf; - - if (alt != (unsigned)-1) { - intf = ffs_func_revmap_intf(func, interface); - if (unlikely(intf < 0)) - return intf; - } - - if (ffs->func) - ffs_func_eps_disable(ffs->func); - - if (ffs->state != FFS_ACTIVE) - return -ENODEV; - - if (alt == (unsigned)-1) { - ffs->func = NULL; - ffs_event_add(ffs, FUNCTIONFS_DISABLE); - return 0; - } - - ffs->func = func; - ret = ffs_func_eps_enable(func); - if (likely(ret >= 0)) - ffs_event_add(ffs, FUNCTIONFS_ENABLE); - return ret; -} - -static void ffs_func_disable(struct usb_function *f) -{ - ffs_func_set_alt(f, 0, (unsigned)-1); -} - -static int ffs_func_setup(struct usb_function *f, - const struct usb_ctrlrequest *creq) -{ - struct ffs_function *func = ffs_func_from_usb(f); - struct ffs_data *ffs = func->ffs; - unsigned long flags; - int ret; - - ENTER(); - - pr_vdebug("creq->bRequestType = %02x\n", creq->bRequestType); - pr_vdebug("creq->bRequest = %02x\n", creq->bRequest); - pr_vdebug("creq->wValue = %04x\n", le16_to_cpu(creq->wValue)); - pr_vdebug("creq->wIndex = %04x\n", le16_to_cpu(creq->wIndex)); - pr_vdebug("creq->wLength = %04x\n", le16_to_cpu(creq->wLength)); - - /* - * Most requests directed to interface go through here - * (notable exceptions are set/get interface) so we need to - * handle them. All other either handled by composite or - * passed to usb_configuration->setup() (if one is set). No - * matter, we will handle requests directed to endpoint here - * as well (as it's straightforward) but what to do with any - * other request? - */ - if (ffs->state != FFS_ACTIVE) - return -ENODEV; - - switch (creq->bRequestType & USB_RECIP_MASK) { - case USB_RECIP_INTERFACE: - ret = ffs_func_revmap_intf(func, le16_to_cpu(creq->wIndex)); - if (unlikely(ret < 0)) - return ret; - break; - - case USB_RECIP_ENDPOINT: - ret = ffs_func_revmap_ep(func, le16_to_cpu(creq->wIndex)); - if (unlikely(ret < 0)) - return ret; - break; - - default: - return -EOPNOTSUPP; - } - - spin_lock_irqsave(&ffs->ev.waitq.lock, flags); - ffs->ev.setup = *creq; - ffs->ev.setup.wIndex = cpu_to_le16(ret); - __ffs_event_add(ffs, FUNCTIONFS_SETUP); - spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags); - - return 0; -} - -static void ffs_func_suspend(struct usb_function *f) -{ - ENTER(); - ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_SUSPEND); -} - -static void ffs_func_resume(struct usb_function *f) -{ - ENTER(); - ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_RESUME); -} - - -/* Endpoint and interface numbers reverse mapping ***************************/ - -static int ffs_func_revmap_ep(struct ffs_function *func, u8 num) -{ - num = func->eps_revmap[num & USB_ENDPOINT_NUMBER_MASK]; - return num ? num : -EDOM; -} - -static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf) -{ - short *nums = func->interfaces_nums; - unsigned count = func->ffs->interfaces_count; - - for (; count; --count, ++nums) { - if (*nums >= 0 && *nums == intf) - return nums - func->interfaces_nums; - } - - return -EDOM; -} - - -/* Misc helper functions ****************************************************/ - -static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock) -{ - return nonblock - ? likely(mutex_trylock(mutex)) ? 0 : -EAGAIN - : mutex_lock_interruptible(mutex); -} - -static char *ffs_prepare_buffer(const char * __user buf, size_t len) -{ - char *data; - - if (unlikely(!len)) - return NULL; - - data = kmalloc(len, GFP_KERNEL); - if (unlikely(!data)) - return ERR_PTR(-ENOMEM); - - if (unlikely(__copy_from_user(data, buf, len))) { - kfree(data); - return ERR_PTR(-EFAULT); - } - - pr_vdebug("Buffer from user space:\n"); - ffs_dump_mem("", data, len); - - return data; -} diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_hid.c b/ANDROID_3.4.5/drivers/usb/gadget/f_hid.c deleted file mode 100644 index b2113420..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_hid.c +++ /dev/null @@ -1,659 +0,0 @@ -/* - * f_hid.c -- USB HID function driver - * - * Copyright (C) 2010 Fabien Chouteau - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int major, minors; -static struct class *hidg_class; - -/*-------------------------------------------------------------------------*/ -/* HID gadget struct */ - -struct f_hidg { - /* configuration */ - unsigned char bInterfaceSubClass; - unsigned char bInterfaceProtocol; - unsigned short report_desc_length; - char *report_desc; - unsigned short report_length; - - /* recv report */ - char *set_report_buff; - unsigned short set_report_length; - spinlock_t spinlock; - wait_queue_head_t read_queue; - - /* send report */ - struct mutex lock; - bool write_pending; - wait_queue_head_t write_queue; - struct usb_request *req; - - int minor; - struct cdev cdev; - struct usb_function func; - struct usb_ep *in_ep; -}; - -static inline struct f_hidg *func_to_hidg(struct usb_function *f) -{ - return container_of(f, struct f_hidg, func); -} - -/*-------------------------------------------------------------------------*/ -/* Static descriptors */ - -static struct usb_interface_descriptor hidg_interface_desc = { - .bLength = sizeof hidg_interface_desc, - .bDescriptorType = USB_DT_INTERFACE, - /* .bInterfaceNumber = DYNAMIC */ - .bAlternateSetting = 0, - .bNumEndpoints = 1, - .bInterfaceClass = USB_CLASS_HID, - /* .bInterfaceSubClass = DYNAMIC */ - /* .bInterfaceProtocol = DYNAMIC */ - /* .iInterface = DYNAMIC */ -}; - -static struct hid_descriptor hidg_desc = { - .bLength = sizeof hidg_desc, - .bDescriptorType = HID_DT_HID, - .bcdHID = 0x0101, - .bCountryCode = 0x00, - .bNumDescriptors = 0x1, - /*.desc[0].bDescriptorType = DYNAMIC */ - /*.desc[0].wDescriptorLenght = DYNAMIC */ -}; - -/* High-Speed Support */ - -static struct usb_endpoint_descriptor hidg_hs_in_ep_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_INT, - /*.wMaxPacketSize = DYNAMIC */ - .bInterval = 4, /* FIXME: Add this field in the - * HID gadget configuration? - * (struct hidg_func_descriptor) - */ -}; - -static struct usb_descriptor_header *hidg_hs_descriptors[] = { - (struct usb_descriptor_header *)&hidg_interface_desc, - (struct usb_descriptor_header *)&hidg_desc, - (struct usb_descriptor_header *)&hidg_hs_in_ep_desc, - NULL, -}; - -/* Full-Speed Support */ - -static struct usb_endpoint_descriptor hidg_fs_in_ep_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_INT, - /*.wMaxPacketSize = DYNAMIC */ - .bInterval = 10, /* FIXME: Add this field in the - * HID gadget configuration? - * (struct hidg_func_descriptor) - */ -}; - -static struct usb_descriptor_header *hidg_fs_descriptors[] = { - (struct usb_descriptor_header *)&hidg_interface_desc, - (struct usb_descriptor_header *)&hidg_desc, - (struct usb_descriptor_header *)&hidg_fs_in_ep_desc, - NULL, -}; - -/*-------------------------------------------------------------------------*/ -/* Char Device */ - -static ssize_t f_hidg_read(struct file *file, char __user *buffer, - size_t count, loff_t *ptr) -{ - struct f_hidg *hidg = file->private_data; - char *tmp_buff = NULL; - unsigned long flags; - - if (!count) - return 0; - - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - - spin_lock_irqsave(&hidg->spinlock, flags); - -#define READ_COND (hidg->set_report_buff != NULL) - - while (!READ_COND) { - spin_unlock_irqrestore(&hidg->spinlock, flags); - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - - if (wait_event_interruptible(hidg->read_queue, READ_COND)) - return -ERESTARTSYS; - - spin_lock_irqsave(&hidg->spinlock, flags); - } - - - count = min_t(unsigned, count, hidg->set_report_length); - tmp_buff = hidg->set_report_buff; - hidg->set_report_buff = NULL; - - spin_unlock_irqrestore(&hidg->spinlock, flags); - - if (tmp_buff != NULL) { - /* copy to user outside spinlock */ - count -= copy_to_user(buffer, tmp_buff, count); - kfree(tmp_buff); - } else - count = -ENOMEM; - - return count; -} - -static void f_hidg_req_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct f_hidg *hidg = (struct f_hidg *)ep->driver_data; - - if (req->status != 0) { - ERROR(hidg->func.config->cdev, - "End Point Request ERROR: %d\n", req->status); - } - - hidg->write_pending = 0; - wake_up(&hidg->write_queue); -} - -static ssize_t f_hidg_write(struct file *file, const char __user *buffer, - size_t count, loff_t *offp) -{ - struct f_hidg *hidg = file->private_data; - ssize_t status = -ENOMEM; - - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - - mutex_lock(&hidg->lock); - -#define WRITE_COND (!hidg->write_pending) - - /* write queue */ - while (!WRITE_COND) { - mutex_unlock(&hidg->lock); - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - - if (wait_event_interruptible_exclusive( - hidg->write_queue, WRITE_COND)) - return -ERESTARTSYS; - - mutex_lock(&hidg->lock); - } - - count = min_t(unsigned, count, hidg->report_length); - status = copy_from_user(hidg->req->buf, buffer, count); - - if (status != 0) { - ERROR(hidg->func.config->cdev, - "copy_from_user error\n"); - mutex_unlock(&hidg->lock); - return -EINVAL; - } - - hidg->req->status = 0; - hidg->req->zero = 0; - hidg->req->length = count; - hidg->req->complete = f_hidg_req_complete; - hidg->req->context = hidg; - hidg->write_pending = 1; - - status = usb_ep_queue(hidg->in_ep, hidg->req, GFP_ATOMIC); - if (status < 0) { - ERROR(hidg->func.config->cdev, - "usb_ep_queue error on int endpoint %zd\n", status); - hidg->write_pending = 0; - wake_up(&hidg->write_queue); - } else { - status = count; - } - - mutex_unlock(&hidg->lock); - - return status; -} - -static unsigned int f_hidg_poll(struct file *file, poll_table *wait) -{ - struct f_hidg *hidg = file->private_data; - unsigned int ret = 0; - - poll_wait(file, &hidg->read_queue, wait); - poll_wait(file, &hidg->write_queue, wait); - - if (WRITE_COND) - ret |= POLLOUT | POLLWRNORM; - - if (READ_COND) - ret |= POLLIN | POLLRDNORM; - - return ret; -} - -#undef WRITE_COND -#undef READ_COND - -static int f_hidg_release(struct inode *inode, struct file *fd) -{ - fd->private_data = NULL; - return 0; -} - -static int f_hidg_open(struct inode *inode, struct file *fd) -{ - struct f_hidg *hidg = - container_of(inode->i_cdev, struct f_hidg, cdev); - - fd->private_data = hidg; - - return 0; -} - -/*-------------------------------------------------------------------------*/ -/* usb_function */ - -static void hidg_set_report_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct f_hidg *hidg = (struct f_hidg *)req->context; - - if (req->status != 0 || req->buf == NULL || req->actual == 0) { - ERROR(hidg->func.config->cdev, "%s FAILED\n", __func__); - return; - } - - spin_lock(&hidg->spinlock); - - hidg->set_report_buff = krealloc(hidg->set_report_buff, - req->actual, GFP_ATOMIC); - - if (hidg->set_report_buff == NULL) { - spin_unlock(&hidg->spinlock); - return; - } - hidg->set_report_length = req->actual; - memcpy(hidg->set_report_buff, req->buf, req->actual); - - spin_unlock(&hidg->spinlock); - - wake_up(&hidg->read_queue); -} - -static int hidg_setup(struct usb_function *f, - const struct usb_ctrlrequest *ctrl) -{ - struct f_hidg *hidg = func_to_hidg(f); - struct usb_composite_dev *cdev = f->config->cdev; - struct usb_request *req = cdev->req; - int status = 0; - __u16 value, length; - - value = __le16_to_cpu(ctrl->wValue); - length = __le16_to_cpu(ctrl->wLength); - - VDBG(cdev, "hid_setup crtl_request : bRequestType:0x%x bRequest:0x%x " - "Value:0x%x\n", ctrl->bRequestType, ctrl->bRequest, value); - - switch ((ctrl->bRequestType << 8) | ctrl->bRequest) { - case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 - | HID_REQ_GET_REPORT): - VDBG(cdev, "get_report\n"); - - /* send an empty report */ - length = min_t(unsigned, length, hidg->report_length); - memset(req->buf, 0x0, length); - - goto respond; - break; - - case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 - | HID_REQ_GET_PROTOCOL): - VDBG(cdev, "get_protocol\n"); - goto stall; - break; - - case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 - | HID_REQ_SET_REPORT): - VDBG(cdev, "set_report | wLenght=%d\n", ctrl->wLength); - req->context = hidg; - req->complete = hidg_set_report_complete; - goto respond; - break; - - case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 - | HID_REQ_SET_PROTOCOL): - VDBG(cdev, "set_protocol\n"); - goto stall; - break; - - case ((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8 - | USB_REQ_GET_DESCRIPTOR): - switch (value >> 8) { - case HID_DT_HID: - VDBG(cdev, "USB_REQ_GET_DESCRIPTOR: HID\n"); - length = min_t(unsigned short, length, - hidg_desc.bLength); - memcpy(req->buf, &hidg_desc, length); - goto respond; - break; - case HID_DT_REPORT: - VDBG(cdev, "USB_REQ_GET_DESCRIPTOR: REPORT\n"); - length = min_t(unsigned short, length, - hidg->report_desc_length); - memcpy(req->buf, hidg->report_desc, length); - goto respond; - break; - - default: - VDBG(cdev, "Unknown decriptor request 0x%x\n", - value >> 8); - goto stall; - break; - } - break; - - default: - VDBG(cdev, "Unknown request 0x%x\n", - ctrl->bRequest); - goto stall; - break; - } - -stall: - return -EOPNOTSUPP; - -respond: - req->zero = 0; - req->length = length; - status = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); - if (status < 0) - ERROR(cdev, "usb_ep_queue error on ep0 %d\n", value); - return status; -} - -static void hidg_disable(struct usb_function *f) -{ - struct f_hidg *hidg = func_to_hidg(f); - - usb_ep_disable(hidg->in_ep); - hidg->in_ep->driver_data = NULL; -} - -static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) -{ - struct usb_composite_dev *cdev = f->config->cdev; - struct f_hidg *hidg = func_to_hidg(f); - int status = 0; - - VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt); - - if (hidg->in_ep != NULL) { - /* restart endpoint */ - if (hidg->in_ep->driver_data != NULL) - usb_ep_disable(hidg->in_ep); - - status = config_ep_by_speed(f->config->cdev->gadget, f, - hidg->in_ep); - if (status) { - ERROR(cdev, "config_ep_by_speed FAILED!\n"); - goto fail; - } - status = usb_ep_enable(hidg->in_ep); - if (status < 0) { - ERROR(cdev, "Enable endpoint FAILED!\n"); - goto fail; - } - hidg->in_ep->driver_data = hidg; - } -fail: - return status; -} - -const struct file_operations f_hidg_fops = { - .owner = THIS_MODULE, - .open = f_hidg_open, - .release = f_hidg_release, - .write = f_hidg_write, - .read = f_hidg_read, - .poll = f_hidg_poll, - .llseek = noop_llseek, -}; - -static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f) -{ - struct usb_ep *ep; - struct f_hidg *hidg = func_to_hidg(f); - int status; - dev_t dev; - - /* allocate instance-specific interface IDs, and patch descriptors */ - status = usb_interface_id(c, f); - if (status < 0) - goto fail; - hidg_interface_desc.bInterfaceNumber = status; - - - /* allocate instance-specific endpoints */ - status = -ENODEV; - ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_in_ep_desc); - if (!ep) - goto fail; - ep->driver_data = c->cdev; /* claim */ - hidg->in_ep = ep; - - /* preallocate request and buffer */ - status = -ENOMEM; - hidg->req = usb_ep_alloc_request(hidg->in_ep, GFP_KERNEL); - if (!hidg->req) - goto fail; - - - hidg->req->buf = kmalloc(hidg->report_length, GFP_KERNEL); - if (!hidg->req->buf) - goto fail; - - /* set descriptor dynamic values */ - hidg_interface_desc.bInterfaceSubClass = hidg->bInterfaceSubClass; - hidg_interface_desc.bInterfaceProtocol = hidg->bInterfaceProtocol; - hidg_hs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length); - hidg_fs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length); - hidg_desc.desc[0].bDescriptorType = HID_DT_REPORT; - hidg_desc.desc[0].wDescriptorLength = - cpu_to_le16(hidg->report_desc_length); - - hidg->set_report_buff = NULL; - - /* copy descriptors */ - f->descriptors = usb_copy_descriptors(hidg_fs_descriptors); - if (!f->descriptors) - goto fail; - - if (gadget_is_dualspeed(c->cdev->gadget)) { - hidg_hs_in_ep_desc.bEndpointAddress = - hidg_fs_in_ep_desc.bEndpointAddress; - f->hs_descriptors = usb_copy_descriptors(hidg_hs_descriptors); - if (!f->hs_descriptors) - goto fail; - } - - mutex_init(&hidg->lock); - spin_lock_init(&hidg->spinlock); - init_waitqueue_head(&hidg->write_queue); - init_waitqueue_head(&hidg->read_queue); - - /* create char device */ - cdev_init(&hidg->cdev, &f_hidg_fops); - dev = MKDEV(major, hidg->minor); - status = cdev_add(&hidg->cdev, dev, 1); - if (status) - goto fail; - - device_create(hidg_class, NULL, dev, NULL, "%s%d", "hidg", hidg->minor); - - return 0; - -fail: - ERROR(f->config->cdev, "hidg_bind FAILED\n"); - if (hidg->req != NULL) { - kfree(hidg->req->buf); - if (hidg->in_ep != NULL) - usb_ep_free_request(hidg->in_ep, hidg->req); - } - - usb_free_descriptors(f->hs_descriptors); - usb_free_descriptors(f->descriptors); - - return status; -} - -static void hidg_unbind(struct usb_configuration *c, struct usb_function *f) -{ - struct f_hidg *hidg = func_to_hidg(f); - - device_destroy(hidg_class, MKDEV(major, hidg->minor)); - cdev_del(&hidg->cdev); - - /* disable/free request and end point */ - usb_ep_disable(hidg->in_ep); - usb_ep_dequeue(hidg->in_ep, hidg->req); - kfree(hidg->req->buf); - usb_ep_free_request(hidg->in_ep, hidg->req); - - /* free descriptors copies */ - usb_free_descriptors(f->hs_descriptors); - usb_free_descriptors(f->descriptors); - - kfree(hidg->report_desc); - kfree(hidg->set_report_buff); - kfree(hidg); -} - -/*-------------------------------------------------------------------------*/ -/* Strings */ - -#define CT_FUNC_HID_IDX 0 - -static struct usb_string ct_func_string_defs[] = { - [CT_FUNC_HID_IDX].s = "HID Interface", - {}, /* end of list */ -}; - -static struct usb_gadget_strings ct_func_string_table = { - .language = 0x0409, /* en-US */ - .strings = ct_func_string_defs, -}; - -static struct usb_gadget_strings *ct_func_strings[] = { - &ct_func_string_table, - NULL, -}; - -/*-------------------------------------------------------------------------*/ -/* usb_configuration */ - -int __init hidg_bind_config(struct usb_configuration *c, - struct hidg_func_descriptor *fdesc, int index) -{ - struct f_hidg *hidg; - int status; - - if (index >= minors) - return -ENOENT; - - /* maybe allocate device-global string IDs, and patch descriptors */ - if (ct_func_string_defs[CT_FUNC_HID_IDX].id == 0) { - status = usb_string_id(c->cdev); - if (status < 0) - return status; - ct_func_string_defs[CT_FUNC_HID_IDX].id = status; - hidg_interface_desc.iInterface = status; - } - - /* allocate and initialize one new instance */ - hidg = kzalloc(sizeof *hidg, GFP_KERNEL); - if (!hidg) - return -ENOMEM; - - hidg->minor = index; - hidg->bInterfaceSubClass = fdesc->subclass; - hidg->bInterfaceProtocol = fdesc->protocol; - hidg->report_length = fdesc->report_length; - hidg->report_desc_length = fdesc->report_desc_length; - hidg->report_desc = kmemdup(fdesc->report_desc, - fdesc->report_desc_length, - GFP_KERNEL); - if (!hidg->report_desc) { - kfree(hidg); - return -ENOMEM; - } - - hidg->func.name = "hid"; - hidg->func.strings = ct_func_strings; - hidg->func.bind = hidg_bind; - hidg->func.unbind = hidg_unbind; - hidg->func.set_alt = hidg_set_alt; - hidg->func.disable = hidg_disable; - hidg->func.setup = hidg_setup; - - status = usb_add_function(c, &hidg->func); - if (status) - kfree(hidg); - - return status; -} - -int __init ghid_setup(struct usb_gadget *g, int count) -{ - int status; - dev_t dev; - - hidg_class = class_create(THIS_MODULE, "hidg"); - - status = alloc_chrdev_region(&dev, 0, count, "hidg"); - if (!status) { - major = MAJOR(dev); - minors = count; - } - - return status; -} - -void ghid_cleanup(void) -{ - if (major) { - unregister_chrdev_region(MKDEV(major, 0), minors); - major = minors = 0; - } - - class_destroy(hidg_class); - hidg_class = NULL; -} diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_loopback.c b/ANDROID_3.4.5/drivers/usb/gadget/f_loopback.c deleted file mode 100644 index 2c0cd824..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_loopback.c +++ /dev/null @@ -1,430 +0,0 @@ -/* - * f_loopback.c - USB peripheral loopback configuration driver - * - * Copyright (C) 2003-2008 David Brownell - * Copyright (C) 2008 by Nokia Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -/* #define VERBOSE_DEBUG */ - -#include -#include -#include - -#include "g_zero.h" -#include "gadget_chips.h" - - -/* - * LOOPBACK FUNCTION ... a testing vehicle for USB peripherals, - * - * This takes messages of various sizes written OUT to a device, and loops - * them back so they can be read IN from it. It has been used by certain - * test applications. It supports limited testing of data queueing logic. - * - * - * This is currently packaged as a configuration driver, which can't be - * combined with other functions to make composite devices. However, it - * can be combined with other independent configurations. - */ -struct f_loopback { - struct usb_function function; - - struct usb_ep *in_ep; - struct usb_ep *out_ep; -}; - -static inline struct f_loopback *func_to_loop(struct usb_function *f) -{ - return container_of(f, struct f_loopback, function); -} - -static unsigned qlen = 32; -module_param(qlen, uint, 0); -MODULE_PARM_DESC(qlenn, "depth of loopback queue"); - -/*-------------------------------------------------------------------------*/ - -static struct usb_interface_descriptor loopback_intf = { - .bLength = sizeof loopback_intf, - .bDescriptorType = USB_DT_INTERFACE, - - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - /* .iInterface = DYNAMIC */ -}; - -/* full speed support: */ - -static struct usb_endpoint_descriptor fs_loop_source_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_endpoint_descriptor fs_loop_sink_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_descriptor_header *fs_loopback_descs[] = { - (struct usb_descriptor_header *) &loopback_intf, - (struct usb_descriptor_header *) &fs_loop_sink_desc, - (struct usb_descriptor_header *) &fs_loop_source_desc, - NULL, -}; - -/* high speed support: */ - -static struct usb_endpoint_descriptor hs_loop_source_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), -}; - -static struct usb_endpoint_descriptor hs_loop_sink_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), -}; - -static struct usb_descriptor_header *hs_loopback_descs[] = { - (struct usb_descriptor_header *) &loopback_intf, - (struct usb_descriptor_header *) &hs_loop_source_desc, - (struct usb_descriptor_header *) &hs_loop_sink_desc, - NULL, -}; - -/* super speed support: */ - -static struct usb_endpoint_descriptor ss_loop_source_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(1024), -}; - -struct usb_ss_ep_comp_descriptor ss_loop_source_comp_desc = { - .bLength = USB_DT_SS_EP_COMP_SIZE, - .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, - .bMaxBurst = 0, - .bmAttributes = 0, - .wBytesPerInterval = 0, -}; - -static struct usb_endpoint_descriptor ss_loop_sink_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(1024), -}; - -struct usb_ss_ep_comp_descriptor ss_loop_sink_comp_desc = { - .bLength = USB_DT_SS_EP_COMP_SIZE, - .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, - .bMaxBurst = 0, - .bmAttributes = 0, - .wBytesPerInterval = 0, -}; - -static struct usb_descriptor_header *ss_loopback_descs[] = { - (struct usb_descriptor_header *) &loopback_intf, - (struct usb_descriptor_header *) &ss_loop_source_desc, - (struct usb_descriptor_header *) &ss_loop_source_comp_desc, - (struct usb_descriptor_header *) &ss_loop_sink_desc, - (struct usb_descriptor_header *) &ss_loop_sink_comp_desc, - NULL, -}; - -/* function-specific strings: */ - -static struct usb_string strings_loopback[] = { - [0].s = "loop input to output", - { } /* end of list */ -}; - -static struct usb_gadget_strings stringtab_loop = { - .language = 0x0409, /* en-us */ - .strings = strings_loopback, -}; - -static struct usb_gadget_strings *loopback_strings[] = { - &stringtab_loop, - NULL, -}; - -/*-------------------------------------------------------------------------*/ - -static int __init -loopback_bind(struct usb_configuration *c, struct usb_function *f) -{ - struct usb_composite_dev *cdev = c->cdev; - struct f_loopback *loop = func_to_loop(f); - int id; - - /* allocate interface ID(s) */ - id = usb_interface_id(c, f); - if (id < 0) - return id; - loopback_intf.bInterfaceNumber = id; - - /* allocate endpoints */ - - loop->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_source_desc); - if (!loop->in_ep) { -autoconf_fail: - ERROR(cdev, "%s: can't autoconfigure on %s\n", - f->name, cdev->gadget->name); - return -ENODEV; - } - loop->in_ep->driver_data = cdev; /* claim */ - - loop->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_sink_desc); - if (!loop->out_ep) - goto autoconf_fail; - loop->out_ep->driver_data = cdev; /* claim */ - - /* support high speed hardware */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - hs_loop_source_desc.bEndpointAddress = - fs_loop_source_desc.bEndpointAddress; - hs_loop_sink_desc.bEndpointAddress = - fs_loop_sink_desc.bEndpointAddress; - f->hs_descriptors = hs_loopback_descs; - } - - /* support super speed hardware */ - if (gadget_is_superspeed(c->cdev->gadget)) { - ss_loop_source_desc.bEndpointAddress = - fs_loop_source_desc.bEndpointAddress; - ss_loop_sink_desc.bEndpointAddress = - fs_loop_sink_desc.bEndpointAddress; - f->ss_descriptors = ss_loopback_descs; - } - - DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", - (gadget_is_superspeed(c->cdev->gadget) ? "super" : - (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")), - f->name, loop->in_ep->name, loop->out_ep->name); - return 0; -} - -static void -loopback_unbind(struct usb_configuration *c, struct usb_function *f) -{ - kfree(func_to_loop(f)); -} - -static void loopback_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct f_loopback *loop = ep->driver_data; - struct usb_composite_dev *cdev = loop->function.config->cdev; - int status = req->status; - - switch (status) { - - case 0: /* normal completion? */ - if (ep == loop->out_ep) { - /* loop this OUT packet back IN to the host */ - req->zero = (req->actual < req->length); - req->length = req->actual; - status = usb_ep_queue(loop->in_ep, req, GFP_ATOMIC); - if (status == 0) - return; - - /* "should never get here" */ - ERROR(cdev, "can't loop %s to %s: %d\n", - ep->name, loop->in_ep->name, - status); - } - - /* queue the buffer for some later OUT packet */ - req->length = buflen; - status = usb_ep_queue(loop->out_ep, req, GFP_ATOMIC); - if (status == 0) - return; - - /* "should never get here" */ - /* FALLTHROUGH */ - - default: - ERROR(cdev, "%s loop complete --> %d, %d/%d\n", ep->name, - status, req->actual, req->length); - /* FALLTHROUGH */ - - /* NOTE: since this driver doesn't maintain an explicit record - * of requests it submitted (just maintains qlen count), we - * rely on the hardware driver to clean up on disconnect or - * endpoint disable. - */ - case -ECONNABORTED: /* hardware forced ep reset */ - case -ECONNRESET: /* request dequeued */ - case -ESHUTDOWN: /* disconnect from host */ - free_ep_req(ep, req); - return; - } -} - -static void disable_loopback(struct f_loopback *loop) -{ - struct usb_composite_dev *cdev; - - cdev = loop->function.config->cdev; - disable_endpoints(cdev, loop->in_ep, loop->out_ep); - VDBG(cdev, "%s disabled\n", loop->function.name); -} - -static int -enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop) -{ - int result = 0; - struct usb_ep *ep; - struct usb_request *req; - unsigned i; - - /* one endpoint writes data back IN to the host */ - ep = loop->in_ep; - result = config_ep_by_speed(cdev->gadget, &(loop->function), ep); - if (result) - return result; - result = usb_ep_enable(ep); - if (result < 0) - return result; - ep->driver_data = loop; - - /* one endpoint just reads OUT packets */ - ep = loop->out_ep; - result = config_ep_by_speed(cdev->gadget, &(loop->function), ep); - if (result) - goto fail0; - - result = usb_ep_enable(ep); - if (result < 0) { -fail0: - ep = loop->in_ep; - usb_ep_disable(ep); - ep->driver_data = NULL; - return result; - } - ep->driver_data = loop; - - /* allocate a bunch of read buffers and queue them all at once. - * we buffer at most 'qlen' transfers; fewer if any need more - * than 'buflen' bytes each. - */ - for (i = 0; i < qlen && result == 0; i++) { - req = alloc_ep_req(ep); - if (req) { - req->complete = loopback_complete; - result = usb_ep_queue(ep, req, GFP_ATOMIC); - if (result) - ERROR(cdev, "%s queue req --> %d\n", - ep->name, result); - } else { - usb_ep_disable(ep); - ep->driver_data = NULL; - result = -ENOMEM; - goto fail0; - } - } - - DBG(cdev, "%s enabled\n", loop->function.name); - return result; -} - -static int loopback_set_alt(struct usb_function *f, - unsigned intf, unsigned alt) -{ - struct f_loopback *loop = func_to_loop(f); - struct usb_composite_dev *cdev = f->config->cdev; - - /* we know alt is zero */ - if (loop->in_ep->driver_data) - disable_loopback(loop); - return enable_loopback(cdev, loop); -} - -static void loopback_disable(struct usb_function *f) -{ - struct f_loopback *loop = func_to_loop(f); - - disable_loopback(loop); -} - -/*-------------------------------------------------------------------------*/ - -static int __init loopback_bind_config(struct usb_configuration *c) -{ - struct f_loopback *loop; - int status; - - loop = kzalloc(sizeof *loop, GFP_KERNEL); - if (!loop) - return -ENOMEM; - - loop->function.name = "loopback"; - loop->function.descriptors = fs_loopback_descs; - loop->function.bind = loopback_bind; - loop->function.unbind = loopback_unbind; - loop->function.set_alt = loopback_set_alt; - loop->function.disable = loopback_disable; - - status = usb_add_function(c, &loop->function); - if (status) - kfree(loop); - return status; -} - -static struct usb_configuration loopback_driver = { - .label = "loopback", - .strings = loopback_strings, - .bConfigurationValue = 2, - .bmAttributes = USB_CONFIG_ATT_SELFPOWER, - /* .iConfiguration = DYNAMIC */ -}; - -/** - * loopback_add - add a loopback testing configuration to a device - * @cdev: the device to support the loopback configuration - */ -int __init loopback_add(struct usb_composite_dev *cdev, bool autoresume) -{ - int id; - - /* allocate string ID(s) */ - id = usb_string_id(cdev); - if (id < 0) - return id; - strings_loopback[0].id = id; - - loopback_intf.iInterface = id; - loopback_driver.iConfiguration = id; - - /* support autoresume for remote wakeup testing */ - if (autoresume) - loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; - - /* support OTG systems */ - if (gadget_is_otg(cdev->gadget)) { - loopback_driver.descriptors = otg_desc; - loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; - } - - return usb_add_config(cdev, &loopback_driver, loopback_bind_config); -} diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_mass_storage.c b/ANDROID_3.4.5/drivers/usb/gadget/f_mass_storage.c deleted file mode 100644 index 68c3d9f6..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_mass_storage.c +++ /dev/null @@ -1,3218 +0,0 @@ -/* - * f_mass_storage.c -- Mass Storage USB Composite Function - * - * Copyright (C) 2003-2008 Alan Stern - * Copyright (C) 2009 Samsung Electronics - * Author: Michal Nazarewicz - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * The Mass Storage Function acts as a USB Mass Storage device, - * appearing to the host as a disk drive or as a CD-ROM drive. In - * addition to providing an example of a genuinely useful composite - * function for a USB device, it also illustrates a technique of - * double-buffering for increased throughput. - * - * Function supports multiple logical units (LUNs). Backing storage - * for each LUN is provided by a regular file or a block device. - * Access for each LUN can be limited to read-only. Moreover, the - * function can indicate that LUN is removable and/or CD-ROM. (The - * later implies read-only access.) - * - * MSF is configured by specifying a fsg_config structure. It has the - * following fields: - * - * nluns Number of LUNs function have (anywhere from 1 - * to FSG_MAX_LUNS which is 8). - * luns An array of LUN configuration values. This - * should be filled for each LUN that - * function will include (ie. for "nluns" - * LUNs). Each element of the array has - * the following fields: - * ->filename The path to the backing file for the LUN. - * Required if LUN is not marked as - * removable. - * ->ro Flag specifying access to the LUN shall be - * read-only. This is implied if CD-ROM - * emulation is enabled as well as when - * it was impossible to open "filename" - * in R/W mode. - * ->removable Flag specifying that LUN shall be indicated as - * being removable. - * ->cdrom Flag specifying that LUN shall be reported as - * being a CD-ROM. - * ->nofua Flag specifying that FUA flag in SCSI WRITE(10,12) - * commands for this LUN shall be ignored. - * - * lun_name_format A printf-like format for names of the LUN - * devices. This determines how the - * directory in sysfs will be named. - * Unless you are using several MSFs in - * a single gadget (as opposed to single - * MSF in many configurations) you may - * leave it as NULL (in which case - * "lun%d" will be used). In the format - * you can use "%d" to index LUNs for - * MSF's with more than one LUN. (Beware - * that there is only one integer given - * as an argument for the format and - * specifying invalid format may cause - * unspecified behaviour.) - * thread_name Name of the kernel thread process used by the - * MSF. You can safely set it to NULL - * (in which case default "file-storage" - * will be used). - * - * vendor_name - * product_name - * release Information used as a reply to INQUIRY - * request. To use default set to NULL, - * NULL, 0xffff respectively. The first - * field should be 8 and the second 16 - * characters or less. - * - * can_stall Set to permit function to halt bulk endpoints. - * Disabled on some USB devices known not - * to work correctly. You should set it - * to true. - * - * If "removable" is not set for a LUN then a backing file must be - * specified. If it is set, then NULL filename means the LUN's medium - * is not loaded (an empty string as "filename" in the fsg_config - * structure causes error). The CD-ROM emulation includes a single - * data track and no audio tracks; hence there need be only one - * backing file per LUN. - * - * - * MSF includes support for module parameters. If gadget using it - * decides to use it, the following module parameters will be - * available: - * - * file=filename[,filename...] - * Names of the files or block devices used for - * backing storage. - * ro=b[,b...] Default false, boolean for read-only access. - * removable=b[,b...] - * Default true, boolean for removable media. - * cdrom=b[,b...] Default false, boolean for whether to emulate - * a CD-ROM drive. - * nofua=b[,b...] Default false, booleans for ignore FUA flag - * in SCSI WRITE(10,12) commands - * luns=N Default N = number of filenames, number of - * LUNs to support. - * stall Default determined according to the type of - * USB device controller (usually true), - * boolean to permit the driver to halt - * bulk endpoints. - * - * The module parameters may be prefixed with some string. You need - * to consult gadget's documentation or source to verify whether it is - * using those module parameters and if it does what are the prefixes - * (look for FSG_MODULE_PARAMETERS() macro usage, what's inside it is - * the prefix). - * - * - * Requirements are modest; only a bulk-in and a bulk-out endpoint are - * needed. The memory requirement amounts to two 16K buffers, size - * configurable by a parameter. Support is included for both - * full-speed and high-speed operation. - * - * Note that the driver is slightly non-portable in that it assumes a - * single memory/DMA buffer will be useable for bulk-in, bulk-out, and - * interrupt-in endpoints. With most device controllers this isn't an - * issue, but there may be some with hardware restrictions that prevent - * a buffer from being used by more than one endpoint. - * - * - * The pathnames of the backing files and the ro settings are - * available in the attribute files "file" and "ro" in the lun (or - * to be more precise in a directory which name comes from - * "lun_name_format" option!) subdirectory of the gadget's sysfs - * directory. If the "removable" option is set, writing to these - * files will simulate ejecting/loading the medium (writing an empty - * line means eject) and adjusting a write-enable tab. Changes to the - * ro setting are not allowed when the medium is loaded or if CD-ROM - * emulation is being used. - * - * When a LUN receive an "eject" SCSI request (Start/Stop Unit), - * if the LUN is removable, the backing file is released to simulate - * ejection. - * - * - * This function is heavily based on "File-backed Storage Gadget" by - * Alan Stern which in turn is heavily based on "Gadget Zero" by David - * Brownell. The driver's SCSI command interface was based on the - * "Information technology - Small Computer System Interface - 2" - * document from X3T9.2 Project 375D, Revision 10L, 7-SEP-93, - * available at . - * The single exception is opcode 0x23 (READ FORMAT CAPACITIES), which - * was based on the "Universal Serial Bus Mass Storage Class UFI - * Command Specification" document, Revision 1.0, December 14, 1998, - * available at - * . - */ - -/* - * Driver Design - * - * The MSF is fairly straightforward. There is a main kernel - * thread that handles most of the work. Interrupt routines field - * callbacks from the controller driver: bulk- and interrupt-request - * completion notifications, endpoint-0 events, and disconnect events. - * Completion events are passed to the main thread by wakeup calls. Many - * ep0 requests are handled at interrupt time, but SetInterface, - * SetConfiguration, and device reset requests are forwarded to the - * thread in the form of "exceptions" using SIGUSR1 signals (since they - * should interrupt any ongoing file I/O operations). - * - * The thread's main routine implements the standard command/data/status - * parts of a SCSI interaction. It and its subroutines are full of tests - * for pending signals/exceptions -- all this polling is necessary since - * the kernel has no setjmp/longjmp equivalents. (Maybe this is an - * indication that the driver really wants to be running in userspace.) - * An important point is that so long as the thread is alive it keeps an - * open reference to the backing file. This will prevent unmounting - * the backing file's underlying filesystem and could cause problems - * during system shutdown, for example. To prevent such problems, the - * thread catches INT, TERM, and KILL signals and converts them into - * an EXIT exception. - * - * In normal operation the main thread is started during the gadget's - * fsg_bind() callback and stopped during fsg_unbind(). But it can - * also exit when it receives a signal, and there's no point leaving - * the gadget running when the thread is dead. At of this moment, MSF - * provides no way to deregister the gadget when thread dies -- maybe - * a callback functions is needed. - * - * To provide maximum throughput, the driver uses a circular pipeline of - * buffer heads (struct fsg_buffhd). In principle the pipeline can be - * arbitrarily long; in practice the benefits don't justify having more - * than 2 stages (i.e., double buffering). But it helps to think of the - * pipeline as being a long one. Each buffer head contains a bulk-in and - * a bulk-out request pointer (since the buffer can be used for both - * output and input -- directions always are given from the host's - * point of view) as well as a pointer to the buffer and various state - * variables. - * - * Use of the pipeline follows a simple protocol. There is a variable - * (fsg->next_buffhd_to_fill) that points to the next buffer head to use. - * At any time that buffer head may still be in use from an earlier - * request, so each buffer head has a state variable indicating whether - * it is EMPTY, FULL, or BUSY. Typical use involves waiting for the - * buffer head to be EMPTY, filling the buffer either by file I/O or by - * USB I/O (during which the buffer head is BUSY), and marking the buffer - * head FULL when the I/O is complete. Then the buffer will be emptied - * (again possibly by USB I/O, during which it is marked BUSY) and - * finally marked EMPTY again (possibly by a completion routine). - * - * A module parameter tells the driver to avoid stalling the bulk - * endpoints wherever the transport specification allows. This is - * necessary for some UDCs like the SuperH, which cannot reliably clear a - * halt on a bulk endpoint. However, under certain circumstances the - * Bulk-only specification requires a stall. In such cases the driver - * will halt the endpoint and set a flag indicating that it should clear - * the halt in software during the next device reset. Hopefully this - * will permit everything to work correctly. Furthermore, although the - * specification allows the bulk-out endpoint to halt when the host sends - * too much data, implementing this would cause an unavoidable race. - * The driver will always use the "no-stall" approach for OUT transfers. - * - * One subtle point concerns sending status-stage responses for ep0 - * requests. Some of these requests, such as device reset, can involve - * interrupting an ongoing file I/O operation, which might take an - * arbitrarily long time. During that delay the host might give up on - * the original ep0 request and issue a new one. When that happens the - * driver should not notify the host about completion of the original - * request, as the host will no longer be waiting for it. So the driver - * assigns to each ep0 request a unique tag, and it keeps track of the - * tag value of the request associated with a long-running exception - * (device-reset, interface-change, or configuration-change). When the - * exception handler is finished, the status-stage response is submitted - * only if the current ep0 request tag is equal to the exception request - * tag. Thus only the most recently received ep0 request will get a - * status-stage response. - * - * Warning: This driver source file is too long. It ought to be split up - * into a header file plus about 3 separate .c files, to handle the details - * of the Gadget, USB Mass Storage, and SCSI protocols. - */ - - -/* #define VERBOSE_DEBUG */ -/* #define DUMP_MSGS */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "gadget_chips.h" - - -/*------------------------------------------------------------------------*/ - -#define FSG_DRIVER_DESC "Mass Storage Function" -#define FSG_DRIVER_VERSION "2009/09/11" - -static const char fsg_string_interface[] = "Mass Storage"; - -#define FSG_NO_DEVICE_STRINGS 1 -#define FSG_NO_OTG 1 -#define FSG_NO_INTR_EP 1 - -#include "storage_common.c" - - -/*-------------------------------------------------------------------------*/ - -struct fsg_dev; -struct fsg_common; - -/* FSF callback functions */ -struct fsg_operations { - /* - * Callback function to call when thread exits. If no - * callback is set or it returns value lower then zero MSF - * will force eject all LUNs it operates on (including those - * marked as non-removable or with prevent_medium_removal flag - * set). - */ - int (*thread_exits)(struct fsg_common *common); - - /* - * Called prior to ejection. Negative return means error, - * zero means to continue with ejection, positive means not to - * eject. - */ - int (*pre_eject)(struct fsg_common *common, - struct fsg_lun *lun, int num); - /* - * Called after ejection. Negative return means error, zero - * or positive is just a success. - */ - int (*post_eject)(struct fsg_common *common, - struct fsg_lun *lun, int num); -}; - -/* Data shared by all the FSG instances. */ -struct fsg_common { - struct usb_gadget *gadget; - struct usb_composite_dev *cdev; - struct fsg_dev *fsg, *new_fsg; - wait_queue_head_t fsg_wait; - - /* filesem protects: backing files in use */ - struct rw_semaphore filesem; - - /* lock protects: state, all the req_busy's */ - spinlock_t lock; - - struct usb_ep *ep0; /* Copy of gadget->ep0 */ - struct usb_request *ep0req; /* Copy of cdev->req */ - unsigned int ep0_req_tag; - - struct fsg_buffhd *next_buffhd_to_fill; - struct fsg_buffhd *next_buffhd_to_drain; - struct fsg_buffhd *buffhds; - - int cmnd_size; - u8 cmnd[MAX_COMMAND_SIZE]; - - unsigned int nluns; - unsigned int lun; - struct fsg_lun *luns; - struct fsg_lun *curlun; - - unsigned int bulk_out_maxpacket; - enum fsg_state state; /* For exception handling */ - unsigned int exception_req_tag; - - enum data_direction data_dir; - u32 data_size; - u32 data_size_from_cmnd; - u32 tag; - u32 residue; - u32 usb_amount_left; - - unsigned int can_stall:1; - unsigned int free_storage_on_release:1; - unsigned int phase_error:1; - unsigned int short_packet_received:1; - unsigned int bad_lun_okay:1; - unsigned int running:1; - - int thread_wakeup_needed; - struct completion thread_notifier; - struct task_struct *thread_task; - - /* Callback functions. */ - const struct fsg_operations *ops; - /* Gadget's private data. */ - void *private_data; - - /* - * Vendor (8 chars), product (16 chars), release (4 - * hexadecimal digits) and NUL byte - */ - char inquiry_string[8 + 16 + 4 + 1]; - - struct kref ref; -}; - -struct fsg_config { - unsigned nluns; - struct fsg_lun_config { - const char *filename; - char ro; - char removable; - char cdrom; - char nofua; - } luns[FSG_MAX_LUNS]; - - const char *lun_name_format; - const char *thread_name; - - /* Callback functions. */ - const struct fsg_operations *ops; - /* Gadget's private data. */ - void *private_data; - - const char *vendor_name; /* 8 characters or less */ - const char *product_name; /* 16 characters or less */ - u16 release; - - char can_stall; -}; - -struct fsg_dev { - struct usb_function function; - struct usb_gadget *gadget; /* Copy of cdev->gadget */ - struct fsg_common *common; - - u16 interface_number; - - unsigned int bulk_in_enabled:1; - unsigned int bulk_out_enabled:1; - - unsigned long atomic_bitflags; -#define IGNORE_BULK_OUT 0 - - struct usb_ep *bulk_in; - struct usb_ep *bulk_out; -}; - -static inline int __fsg_is_set(struct fsg_common *common, - const char *func, unsigned line) -{ - if (common->fsg) - return 1; - ERROR(common, "common->fsg is NULL in %s at %u\n", func, line); - WARN_ON(1); - return 0; -} - -#define fsg_is_set(common) likely(__fsg_is_set(common, __func__, __LINE__)) - -static inline struct fsg_dev *fsg_from_func(struct usb_function *f) -{ - return container_of(f, struct fsg_dev, function); -} - -typedef void (*fsg_routine_t)(struct fsg_dev *); - -static int exception_in_progress(struct fsg_common *common) -{ - return common->state > FSG_STATE_IDLE; -} - -/* Make bulk-out requests be divisible by the maxpacket size */ -static void set_bulk_out_req_length(struct fsg_common *common, - struct fsg_buffhd *bh, unsigned int length) -{ - unsigned int rem; - - bh->bulk_out_intended_length = length; - rem = length % common->bulk_out_maxpacket; - if (rem > 0) - length += common->bulk_out_maxpacket - rem; - bh->outreq->length = length; -} - - -/*-------------------------------------------------------------------------*/ - -static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) -{ - const char *name; - - if (ep == fsg->bulk_in) - name = "bulk-in"; - else if (ep == fsg->bulk_out) - name = "bulk-out"; - else - name = ep->name; - DBG(fsg, "%s set halt\n", name); - return usb_ep_set_halt(ep); -} - - -/*-------------------------------------------------------------------------*/ - -/* These routines may be called in process context or in_irq */ - -/* Caller must hold fsg->lock */ -static void wakeup_thread(struct fsg_common *common) -{ - /* Tell the main thread that something has happened */ - common->thread_wakeup_needed = 1; - if (common->thread_task) - wake_up_process(common->thread_task); -} - -static void raise_exception(struct fsg_common *common, enum fsg_state new_state) -{ - unsigned long flags; - - /* - * Do nothing if a higher-priority exception is already in progress. - * If a lower-or-equal priority exception is in progress, preempt it - * and notify the main thread by sending it a signal. - */ - spin_lock_irqsave(&common->lock, flags); - if (common->state <= new_state) { - common->exception_req_tag = common->ep0_req_tag; - common->state = new_state; - if (common->thread_task) - send_sig_info(SIGUSR1, SEND_SIG_FORCED, - common->thread_task); - } - spin_unlock_irqrestore(&common->lock, flags); -} - - -/*-------------------------------------------------------------------------*/ - -static int ep0_queue(struct fsg_common *common) -{ - int rc; - - rc = usb_ep_queue(common->ep0, common->ep0req, GFP_ATOMIC); - common->ep0->driver_data = common; - if (rc != 0 && rc != -ESHUTDOWN) { - /* We can't do much more than wait for a reset */ - WARNING(common, "error in submission: %s --> %d\n", - common->ep0->name, rc); - } - return rc; -} - - -/*-------------------------------------------------------------------------*/ - -/* Completion handlers. These always run in_irq. */ - -static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct fsg_common *common = ep->driver_data; - struct fsg_buffhd *bh = req->context; - - if (req->status || req->actual != req->length) - DBG(common, "%s --> %d, %u/%u\n", __func__, - req->status, req->actual, req->length); - if (req->status == -ECONNRESET) /* Request was cancelled */ - usb_ep_fifo_flush(ep); - - /* Hold the lock while we update the request and buffer states */ - smp_wmb(); - spin_lock(&common->lock); - bh->inreq_busy = 0; - bh->state = BUF_STATE_EMPTY; - wakeup_thread(common); - spin_unlock(&common->lock); -} - -static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct fsg_common *common = ep->driver_data; - struct fsg_buffhd *bh = req->context; - - dump_msg(common, "bulk-out", req->buf, req->actual); - if (req->status || req->actual != bh->bulk_out_intended_length) - DBG(common, "%s --> %d, %u/%u\n", __func__, - req->status, req->actual, bh->bulk_out_intended_length); - if (req->status == -ECONNRESET) /* Request was cancelled */ - usb_ep_fifo_flush(ep); - - /* Hold the lock while we update the request and buffer states */ - smp_wmb(); - spin_lock(&common->lock); - bh->outreq_busy = 0; - bh->state = BUF_STATE_FULL; - wakeup_thread(common); - spin_unlock(&common->lock); -} - -static int fsg_setup(struct usb_function *f, - const struct usb_ctrlrequest *ctrl) -{ - struct fsg_dev *fsg = fsg_from_func(f); - struct usb_request *req = fsg->common->ep0req; - u16 w_index = le16_to_cpu(ctrl->wIndex); - u16 w_value = le16_to_cpu(ctrl->wValue); - u16 w_length = le16_to_cpu(ctrl->wLength); - - if (!fsg_is_set(fsg->common)) - return -EOPNOTSUPP; - - ++fsg->common->ep0_req_tag; /* Record arrival of a new request */ - req->context = NULL; - req->length = 0; - dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl)); - - switch (ctrl->bRequest) { - - case US_BULK_RESET_REQUEST: - if (ctrl->bRequestType != - (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) - break; - if (w_index != fsg->interface_number || w_value != 0 || - w_length != 0) - return -EDOM; - - /* - * Raise an exception to stop the current operation - * and reinitialize our state. - */ - DBG(fsg, "bulk reset request\n"); - raise_exception(fsg->common, FSG_STATE_RESET); - return DELAYED_STATUS; - - case US_BULK_GET_MAX_LUN: - if (ctrl->bRequestType != - (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) - break; - if (w_index != fsg->interface_number || w_value != 0 || - w_length != 1) - return -EDOM; - VDBG(fsg, "get max LUN\n"); - *(u8 *)req->buf = fsg->common->nluns - 1; - - /* Respond with data/status */ - req->length = min((u16)1, w_length); - return ep0_queue(fsg->common); - } - - VDBG(fsg, - "unknown class-specific control req %02x.%02x v%04x i%04x l%u\n", - ctrl->bRequestType, ctrl->bRequest, - le16_to_cpu(ctrl->wValue), w_index, w_length); - return -EOPNOTSUPP; -} - - -/*-------------------------------------------------------------------------*/ - -/* All the following routines run in process context */ - -/* Use this for bulk or interrupt transfers, not ep0 */ -static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep, - struct usb_request *req, int *pbusy, - enum fsg_buffer_state *state) -{ - int rc; - - if (ep == fsg->bulk_in) - dump_msg(fsg, "bulk-in", req->buf, req->length); - - spin_lock_irq(&fsg->common->lock); - *pbusy = 1; - *state = BUF_STATE_BUSY; - spin_unlock_irq(&fsg->common->lock); - rc = usb_ep_queue(ep, req, GFP_KERNEL); - if (rc != 0) { - *pbusy = 0; - *state = BUF_STATE_EMPTY; - - /* We can't do much more than wait for a reset */ - - /* - * Note: currently the net2280 driver fails zero-length - * submissions if DMA is enabled. - */ - if (rc != -ESHUTDOWN && - !(rc == -EOPNOTSUPP && req->length == 0)) - WARNING(fsg, "error in submission: %s --> %d\n", - ep->name, rc); - } -} - -static bool start_in_transfer(struct fsg_common *common, struct fsg_buffhd *bh) -{ - if (!fsg_is_set(common)) - return false; - start_transfer(common->fsg, common->fsg->bulk_in, - bh->inreq, &bh->inreq_busy, &bh->state); - return true; -} - -static bool start_out_transfer(struct fsg_common *common, struct fsg_buffhd *bh) -{ - if (!fsg_is_set(common)) - return false; - start_transfer(common->fsg, common->fsg->bulk_out, - bh->outreq, &bh->outreq_busy, &bh->state); - return true; -} - -static int sleep_thread(struct fsg_common *common) -{ - int rc = 0; - - /* Wait until a signal arrives or we are woken up */ - for (;;) { - try_to_freeze(); - set_current_state(TASK_INTERRUPTIBLE); - if (signal_pending(current)) { - rc = -EINTR; - break; - } - if (common->thread_wakeup_needed) - break; - schedule(); - } - __set_current_state(TASK_RUNNING); - common->thread_wakeup_needed = 0; - return rc; -} - - -/*-------------------------------------------------------------------------*/ - -static int do_read(struct fsg_common *common) -{ - struct fsg_lun *curlun = common->curlun; - u32 lba; - struct fsg_buffhd *bh; - int rc; - u32 amount_left; - loff_t file_offset, file_offset_tmp; - unsigned int amount; - ssize_t nread; - - /* - * Get the starting Logical Block Address and check that it's - * not too big. - */ - if (common->cmnd[0] == READ_6) - lba = get_unaligned_be24(&common->cmnd[1]); - else { - lba = get_unaligned_be32(&common->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 - * cache), but we don't implement them. - */ - if ((common->cmnd[1] & ~0x18) != 0) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - } - if (lba >= curlun->num_sectors) { - curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - return -EINVAL; - } - file_offset = ((loff_t) lba) << curlun->blkbits; - - /* Carry out the file reads */ - amount_left = common->data_size_from_cmnd; - if (unlikely(amount_left == 0)) - return -EIO; /* No default reply */ - - for (;;) { - /* - * Figure out how much we need to read: - * Try to read the remaining amount. - * But don't read more than the buffer size. - * And don't try to read past the end of the file. - */ - amount = min(amount_left, FSG_BUFLEN); - amount = min((loff_t)amount, - curlun->file_length - file_offset); - - /* Wait for the next buffer to become available */ - bh = common->next_buffhd_to_fill; - while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(common); - if (rc) - return rc; - } - - /* - * If we were asked to read past the end of file, - * end with an empty buffer. - */ - if (amount == 0) { - curlun->sense_data = - SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->sense_data_info = - file_offset >> curlun->blkbits; - curlun->info_valid = 1; - bh->inreq->length = 0; - bh->state = BUF_STATE_FULL; - break; - } - - /* Perform the read */ - file_offset_tmp = file_offset; - nread = vfs_read(curlun->filp, - (char __user *)bh->buf, - amount, &file_offset_tmp); - VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, - (unsigned long long)file_offset, (int)nread); - if (signal_pending(current)) - return -EINTR; - - if (nread < 0) { - LDBG(curlun, "error in file read: %d\n", (int)nread); - nread = 0; - } else if (nread < amount) { - LDBG(curlun, "partial file read: %d/%u\n", - (int)nread, amount); - nread = round_down(nread, curlun->blksize); - } - file_offset += nread; - amount_left -= nread; - common->residue -= nread; - - /* - * Except at the end of the transfer, nread will be - * equal to the buffer size, which is divisible by the - * bulk-in maxpacket size. - */ - bh->inreq->length = nread; - bh->state = BUF_STATE_FULL; - - /* If an error occurred, report it and its position */ - if (nread < amount) { - curlun->sense_data = SS_UNRECOVERED_READ_ERROR; - curlun->sense_data_info = - file_offset >> curlun->blkbits; - curlun->info_valid = 1; - break; - } - - if (amount_left == 0) - break; /* No more left to read */ - - /* Send this buffer and go read some more */ - bh->inreq->zero = 0; - if (!start_in_transfer(common, bh)) - /* Don't know what to do if common->fsg is NULL */ - return -EIO; - common->next_buffhd_to_fill = bh->next; - } - - return -EIO; /* No default reply */ -} - - -/*-------------------------------------------------------------------------*/ - -static int do_write(struct fsg_common *common) -{ - struct fsg_lun *curlun = common->curlun; - u32 lba; - struct fsg_buffhd *bh; - int get_some_more; - u32 amount_left_to_req, amount_left_to_write; - loff_t usb_offset, file_offset, file_offset_tmp; - unsigned int amount; - ssize_t nwritten; - int rc; - - if (curlun->ro) { - curlun->sense_data = SS_WRITE_PROTECTED; - return -EINVAL; - } - spin_lock(&curlun->filp->f_lock); - curlun->filp->f_flags &= ~O_SYNC; /* Default is not to wait */ - spin_unlock(&curlun->filp->f_lock); - - /* - * Get the starting Logical Block Address and check that it's - * not too big - */ - if (common->cmnd[0] == WRITE_6) - lba = get_unaligned_be24(&common->cmnd[1]); - else { - lba = get_unaligned_be32(&common->cmnd[2]); - - /* - * We allow DPO (Disable Page Out = don't save data in the - * cache) and FUA (Force Unit Access = write directly to the - * medium). We don't implement DPO; we implement FUA by - * performing synchronous output. - */ - if (common->cmnd[1] & ~0x18) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - if (!curlun->nofua && (common->cmnd[1] & 0x08)) { /* FUA */ - spin_lock(&curlun->filp->f_lock); - curlun->filp->f_flags |= O_SYNC; - spin_unlock(&curlun->filp->f_lock); - } - } - if (lba >= curlun->num_sectors) { - curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - return -EINVAL; - } - - /* Carry out the file writes */ - get_some_more = 1; - file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits; - amount_left_to_req = common->data_size_from_cmnd; - amount_left_to_write = common->data_size_from_cmnd; - - while (amount_left_to_write > 0) { - - /* Queue a request for more data from the host */ - bh = common->next_buffhd_to_fill; - if (bh->state == BUF_STATE_EMPTY && get_some_more) { - - /* - * Figure out how much we want to get: - * Try to get the remaining amount, - * but not more than the buffer size. - */ - amount = min(amount_left_to_req, FSG_BUFLEN); - - /* Beyond the end of the backing file? */ - if (usb_offset >= curlun->file_length) { - get_some_more = 0; - curlun->sense_data = - SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->sense_data_info = - usb_offset >> curlun->blkbits; - curlun->info_valid = 1; - continue; - } - - /* Get the next buffer */ - usb_offset += amount; - common->usb_amount_left -= amount; - amount_left_to_req -= amount; - if (amount_left_to_req == 0) - get_some_more = 0; - - /* - * Except at the end of the transfer, amount will be - * equal to the buffer size, which is divisible by - * the bulk-out maxpacket size. - */ - set_bulk_out_req_length(common, bh, amount); - if (!start_out_transfer(common, bh)) - /* Dunno what to do if common->fsg is NULL */ - return -EIO; - common->next_buffhd_to_fill = bh->next; - continue; - } - - /* Write the received data to the backing file */ - bh = common->next_buffhd_to_drain; - if (bh->state == BUF_STATE_EMPTY && !get_some_more) - break; /* We stopped early */ - if (bh->state == BUF_STATE_FULL) { - smp_rmb(); - common->next_buffhd_to_drain = bh->next; - bh->state = BUF_STATE_EMPTY; - - /* Did something go wrong with the transfer? */ - if (bh->outreq->status != 0) { - curlun->sense_data = SS_COMMUNICATION_FAILURE; - curlun->sense_data_info = - file_offset >> curlun->blkbits; - curlun->info_valid = 1; - break; - } - - amount = bh->outreq->actual; - if (curlun->file_length - file_offset < amount) { - LERROR(curlun, - "write %u @ %llu beyond end %llu\n", - amount, (unsigned long long)file_offset, - (unsigned long long)curlun->file_length); - amount = curlun->file_length - file_offset; - } - - /* Don't accept excess data. The spec doesn't say - * what to do in this case. We'll ignore the error. - */ - amount = min(amount, bh->bulk_out_intended_length); - - /* Don't write a partial block */ - amount = round_down(amount, curlun->blksize); - if (amount == 0) - goto empty_write; - - /* Perform the write */ - file_offset_tmp = file_offset; - nwritten = vfs_write(curlun->filp, - (char __user *)bh->buf, - amount, &file_offset_tmp); - VLDBG(curlun, "file write %u @ %llu -> %d\n", amount, - (unsigned long long)file_offset, (int)nwritten); - if (signal_pending(current)) - return -EINTR; /* Interrupted! */ - - if (nwritten < 0) { - LDBG(curlun, "error in file write: %d\n", - (int)nwritten); - nwritten = 0; - } else if (nwritten < amount) { - LDBG(curlun, "partial file write: %d/%u\n", - (int)nwritten, amount); - nwritten = round_down(nwritten, curlun->blksize); - } - file_offset += nwritten; - amount_left_to_write -= nwritten; - common->residue -= nwritten; - - /* If an error occurred, report it and its position */ - if (nwritten < amount) { - curlun->sense_data = SS_WRITE_ERROR; - curlun->sense_data_info = - file_offset >> curlun->blkbits; - curlun->info_valid = 1; - break; - } - - empty_write: - /* Did the host decide to stop early? */ - if (bh->outreq->actual < bh->bulk_out_intended_length) { - common->short_packet_received = 1; - break; - } - continue; - } - - /* Wait for something to happen */ - rc = sleep_thread(common); - if (rc) - return rc; - } - - return -EIO; /* No default reply */ -} - - -/*-------------------------------------------------------------------------*/ - -static int do_synchronize_cache(struct fsg_common *common) -{ - struct fsg_lun *curlun = common->curlun; - int rc; - - /* We ignore the requested LBA and write out all file's - * dirty data buffers. */ - rc = fsg_lun_fsync_sub(curlun); - if (rc) - curlun->sense_data = SS_WRITE_ERROR; - return 0; -} - - -/*-------------------------------------------------------------------------*/ - -static void invalidate_sub(struct fsg_lun *curlun) -{ - struct file *filp = curlun->filp; - struct inode *inode = filp->f_path.dentry->d_inode; - unsigned long rc; - - rc = invalidate_mapping_pages(inode->i_mapping, 0, -1); - VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc); -} - -static int do_verify(struct fsg_common *common) -{ - struct fsg_lun *curlun = common->curlun; - u32 lba; - u32 verification_length; - struct fsg_buffhd *bh = common->next_buffhd_to_fill; - loff_t file_offset, file_offset_tmp; - u32 amount_left; - unsigned int amount; - ssize_t nread; - - /* - * Get the starting Logical Block Address and check that it's - * not too big. - */ - lba = get_unaligned_be32(&common->cmnd[2]); - if (lba >= curlun->num_sectors) { - curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - return -EINVAL; - } - - /* - * We allow DPO (Disable Page Out = don't save data in the - * cache) but we don't implement it. - */ - if (common->cmnd[1] & ~0x10) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - verification_length = get_unaligned_be16(&common->cmnd[7]); - if (unlikely(verification_length == 0)) - return -EIO; /* No default reply */ - - /* Prepare to carry out the file verify */ - amount_left = verification_length << curlun->blkbits; - file_offset = ((loff_t) lba) << curlun->blkbits; - - /* Write out all the dirty buffers before invalidating them */ - fsg_lun_fsync_sub(curlun); - if (signal_pending(current)) - return -EINTR; - - invalidate_sub(curlun); - if (signal_pending(current)) - return -EINTR; - - /* Just try to read the requested blocks */ - while (amount_left > 0) { - /* - * Figure out how much we need to read: - * Try to read the remaining amount, but not more than - * the buffer size. - * And don't try to read past the end of the file. - */ - amount = min(amount_left, FSG_BUFLEN); - amount = min((loff_t)amount, - curlun->file_length - file_offset); - if (amount == 0) { - curlun->sense_data = - SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->sense_data_info = - file_offset >> curlun->blkbits; - curlun->info_valid = 1; - break; - } - - /* Perform the read */ - file_offset_tmp = file_offset; - nread = vfs_read(curlun->filp, - (char __user *) bh->buf, - amount, &file_offset_tmp); - VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, - (unsigned long long) file_offset, - (int) nread); - if (signal_pending(current)) - return -EINTR; - - if (nread < 0) { - LDBG(curlun, "error in file verify: %d\n", (int)nread); - nread = 0; - } else if (nread < amount) { - LDBG(curlun, "partial file verify: %d/%u\n", - (int)nread, amount); - nread = round_down(nread, curlun->blksize); - } - if (nread == 0) { - curlun->sense_data = SS_UNRECOVERED_READ_ERROR; - curlun->sense_data_info = - file_offset >> curlun->blkbits; - curlun->info_valid = 1; - break; - } - file_offset += nread; - amount_left -= nread; - } - return 0; -} - - -/*-------------------------------------------------------------------------*/ - -static int do_inquiry(struct fsg_common *common, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = common->curlun; - u8 *buf = (u8 *) bh->buf; - - if (!curlun) { /* Unsupported LUNs are okay */ - common->bad_lun_okay = 1; - memset(buf, 0, 36); - buf[0] = 0x7f; /* Unsupported, no device-type */ - buf[4] = 31; /* Additional length */ - return 36; - } - - buf[0] = curlun->cdrom ? TYPE_ROM : TYPE_DISK; - buf[1] = curlun->removable ? 0x80 : 0; - buf[2] = 2; /* ANSI SCSI level 2 */ - buf[3] = 2; /* SCSI-2 INQUIRY data format */ - buf[4] = 31; /* Additional length */ - buf[5] = 0; /* No special options */ - buf[6] = 0; - buf[7] = 0; - memcpy(buf + 8, common->inquiry_string, sizeof common->inquiry_string); - return 36; -} - -static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = common->curlun; - u8 *buf = (u8 *) bh->buf; - u32 sd, sdinfo; - int valid; - - /* - * From the SCSI-2 spec., section 7.9 (Unit attention condition): - * - * If a REQUEST SENSE command is received from an initiator - * with a pending unit attention condition (before the target - * generates the contingent allegiance condition), then the - * target shall either: - * a) report any pending sense data and preserve the unit - * attention condition on the logical unit, or, - * b) report the unit attention condition, may discard any - * pending sense data, and clear the unit attention - * condition on the logical unit for that initiator. - * - * FSG normally uses option a); enable this code to use option b). - */ -#if 0 - if (curlun && curlun->unit_attention_data != SS_NO_SENSE) { - curlun->sense_data = curlun->unit_attention_data; - curlun->unit_attention_data = SS_NO_SENSE; - } -#endif - - if (!curlun) { /* Unsupported LUNs are okay */ - common->bad_lun_okay = 1; - sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; - sdinfo = 0; - valid = 0; - } else { - sd = curlun->sense_data; - sdinfo = curlun->sense_data_info; - valid = curlun->info_valid << 7; - curlun->sense_data = SS_NO_SENSE; - curlun->sense_data_info = 0; - curlun->info_valid = 0; - } - - memset(buf, 0, 18); - buf[0] = valid | 0x70; /* Valid, current error */ - buf[2] = SK(sd); - put_unaligned_be32(sdinfo, &buf[3]); /* Sense information */ - buf[7] = 18 - 8; /* Additional sense length */ - buf[12] = ASC(sd); - buf[13] = ASCQ(sd); - return 18; -} - -static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = common->curlun; - u32 lba = get_unaligned_be32(&common->cmnd[2]); - int pmi = common->cmnd[8]; - u8 *buf = (u8 *)bh->buf; - - /* Check the PMI and LBA fields */ - if (pmi > 1 || (pmi == 0 && lba != 0)) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - put_unaligned_be32(curlun->num_sectors - 1, &buf[0]); - /* Max logical block */ - put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */ - return 8; -} - -static int do_read_header(struct fsg_common *common, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = common->curlun; - int msf = common->cmnd[1] & 0x02; - u32 lba = get_unaligned_be32(&common->cmnd[2]); - u8 *buf = (u8 *)bh->buf; - - if (common->cmnd[1] & ~0x02) { /* Mask away MSF */ - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - if (lba >= curlun->num_sectors) { - curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - return -EINVAL; - } - - memset(buf, 0, 8); - buf[0] = 0x01; /* 2048 bytes of user data, rest is EC */ - store_cdrom_address(&buf[4], msf, lba); - return 8; -} - -static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = common->curlun; - int msf = common->cmnd[1] & 0x02; - int start_track = common->cmnd[6]; - u8 *buf = (u8 *)bh->buf; - - if ((common->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */ - start_track > 1) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - memset(buf, 0, 20); - buf[1] = (20-2); /* TOC data length */ - buf[2] = 1; /* First track number */ - buf[3] = 1; /* Last track number */ - buf[5] = 0x16; /* Data track, copying allowed */ - buf[6] = 0x01; /* Only track is number 1 */ - store_cdrom_address(&buf[8], msf, 0); - - buf[13] = 0x16; /* Lead-out track is data */ - buf[14] = 0xAA; /* Lead-out track number */ - store_cdrom_address(&buf[16], msf, curlun->num_sectors); - return 20; -} - -static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = common->curlun; - int mscmnd = common->cmnd[0]; - u8 *buf = (u8 *) bh->buf; - u8 *buf0 = buf; - int pc, page_code; - int changeable_values, all_pages; - int valid_page = 0; - int len, limit; - - if ((common->cmnd[1] & ~0x08) != 0) { /* Mask away DBD */ - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - pc = common->cmnd[2] >> 6; - page_code = common->cmnd[2] & 0x3f; - if (pc == 3) { - curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED; - return -EINVAL; - } - changeable_values = (pc == 1); - all_pages = (page_code == 0x3f); - - /* - * Write the mode parameter header. Fixed values are: default - * medium type, no cache control (DPOFUA), and no block descriptors. - * The only variable value is the WriteProtect bit. We will fill in - * the mode data length later. - */ - memset(buf, 0, 8); - if (mscmnd == MODE_SENSE) { - buf[2] = (curlun->ro ? 0x80 : 0x00); /* WP, DPOFUA */ - buf += 4; - limit = 255; - } else { /* MODE_SENSE_10 */ - buf[3] = (curlun->ro ? 0x80 : 0x00); /* WP, DPOFUA */ - buf += 8; - limit = 65535; /* Should really be FSG_BUFLEN */ - } - - /* No block descriptors */ - - /* - * The mode pages, in numerical order. The only page we support - * is the Caching page. - */ - if (page_code == 0x08 || all_pages) { - valid_page = 1; - buf[0] = 0x08; /* Page code */ - buf[1] = 10; /* Page length */ - memset(buf+2, 0, 10); /* None of the fields are changeable */ - - if (!changeable_values) { - buf[2] = 0x04; /* Write cache enable, */ - /* Read cache not disabled */ - /* No cache retention priorities */ - 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; - } - - /* - * Check that a valid page was requested and the mode data length - * isn't too long. - */ - len = buf - buf0; - if (!valid_page || len > limit) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - /* Store the mode data length */ - if (mscmnd == MODE_SENSE) - buf0[0] = len - 1; - else - put_unaligned_be16(len - 2, buf0); - return len; -} - -static int do_start_stop(struct fsg_common *common) -{ - struct fsg_lun *curlun = common->curlun; - int loej, start; - - if (!curlun) { - return -EINVAL; - } else if (!curlun->removable) { - curlun->sense_data = SS_INVALID_COMMAND; - return -EINVAL; - } else if ((common->cmnd[1] & ~0x01) != 0 || /* Mask away Immed */ - (common->cmnd[4] & ~0x03) != 0) { /* Mask LoEj, Start */ - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - loej = common->cmnd[4] & 0x02; - start = common->cmnd[4] & 0x01; - - /* - * Our emulation doesn't support mounting; the medium is - * available for use as soon as it is loaded. - */ - if (start) { - if (!fsg_lun_is_open(curlun)) { - curlun->sense_data = SS_MEDIUM_NOT_PRESENT; - return -EINVAL; - } - return 0; - } - - /* Are we allowed to unload the media? */ - if (curlun->prevent_medium_removal) { - LDBG(curlun, "unload attempt prevented\n"); - curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED; - return -EINVAL; - } - - if (!loej) - return 0; - - /* Simulate an unload/eject */ - if (common->ops && common->ops->pre_eject) { - int r = common->ops->pre_eject(common, curlun, - curlun - common->luns); - if (unlikely(r < 0)) - return r; - else if (r) - return 0; - } - - up_read(&common->filesem); - down_write(&common->filesem); - fsg_lun_close(curlun); - up_write(&common->filesem); - down_read(&common->filesem); - - return common->ops && common->ops->post_eject - ? min(0, common->ops->post_eject(common, curlun, - curlun - common->luns)) - : 0; -} - -static int do_prevent_allow(struct fsg_common *common) -{ - struct fsg_lun *curlun = common->curlun; - int prevent; - - if (!common->curlun) { - return -EINVAL; - } else if (!common->curlun->removable) { - common->curlun->sense_data = SS_INVALID_COMMAND; - return -EINVAL; - } - - prevent = common->cmnd[4] & 0x01; - if ((common->cmnd[4] & ~0x01) != 0) { /* Mask away Prevent */ - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - if (curlun->prevent_medium_removal && !prevent) - fsg_lun_fsync_sub(curlun); - curlun->prevent_medium_removal = prevent; - return 0; -} - -static int do_read_format_capacities(struct fsg_common *common, - struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = common->curlun; - u8 *buf = (u8 *) bh->buf; - - buf[0] = buf[1] = buf[2] = 0; - buf[3] = 8; /* Only the Current/Maximum Capacity Descriptor */ - buf += 4; - - put_unaligned_be32(curlun->num_sectors, &buf[0]); - /* Number of blocks */ - put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */ - buf[4] = 0x02; /* Current capacity */ - return 12; -} - -static int do_mode_select(struct fsg_common *common, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = common->curlun; - - /* We don't support MODE SELECT */ - if (curlun) - curlun->sense_data = SS_INVALID_COMMAND; - return -EINVAL; -} - - -/*-------------------------------------------------------------------------*/ - -static int halt_bulk_in_endpoint(struct fsg_dev *fsg) -{ - int rc; - - rc = fsg_set_halt(fsg, fsg->bulk_in); - if (rc == -EAGAIN) - VDBG(fsg, "delayed bulk-in endpoint halt\n"); - while (rc != 0) { - if (rc != -EAGAIN) { - WARNING(fsg, "usb_ep_set_halt -> %d\n", rc); - rc = 0; - break; - } - - /* Wait for a short time and then try again */ - if (msleep_interruptible(100) != 0) - return -EINTR; - rc = usb_ep_set_halt(fsg->bulk_in); - } - return rc; -} - -static int wedge_bulk_in_endpoint(struct fsg_dev *fsg) -{ - int rc; - - DBG(fsg, "bulk-in set wedge\n"); - rc = usb_ep_set_wedge(fsg->bulk_in); - if (rc == -EAGAIN) - VDBG(fsg, "delayed bulk-in endpoint wedge\n"); - while (rc != 0) { - if (rc != -EAGAIN) { - WARNING(fsg, "usb_ep_set_wedge -> %d\n", rc); - rc = 0; - break; - } - - /* Wait for a short time and then try again */ - if (msleep_interruptible(100) != 0) - return -EINTR; - rc = usb_ep_set_wedge(fsg->bulk_in); - } - return rc; -} - -static int throw_away_data(struct fsg_common *common) -{ - struct fsg_buffhd *bh; - u32 amount; - int rc; - - for (bh = common->next_buffhd_to_drain; - bh->state != BUF_STATE_EMPTY || common->usb_amount_left > 0; - bh = common->next_buffhd_to_drain) { - - /* Throw away the data in a filled buffer */ - if (bh->state == BUF_STATE_FULL) { - smp_rmb(); - bh->state = BUF_STATE_EMPTY; - common->next_buffhd_to_drain = bh->next; - - /* A short packet or an error ends everything */ - if (bh->outreq->actual < bh->bulk_out_intended_length || - bh->outreq->status != 0) { - raise_exception(common, - FSG_STATE_ABORT_BULK_OUT); - return -EINTR; - } - continue; - } - - /* Try to submit another request if we need one */ - bh = common->next_buffhd_to_fill; - if (bh->state == BUF_STATE_EMPTY - && common->usb_amount_left > 0) { - amount = min(common->usb_amount_left, FSG_BUFLEN); - - /* - * Except at the end of the transfer, amount will be - * equal to the buffer size, which is divisible by - * the bulk-out maxpacket size. - */ - set_bulk_out_req_length(common, bh, amount); - if (!start_out_transfer(common, bh)) - /* Dunno what to do if common->fsg is NULL */ - return -EIO; - common->next_buffhd_to_fill = bh->next; - common->usb_amount_left -= amount; - continue; - } - - /* Otherwise wait for something to happen */ - rc = sleep_thread(common); - if (rc) - return rc; - } - return 0; -} - -static int finish_reply(struct fsg_common *common) -{ - struct fsg_buffhd *bh = common->next_buffhd_to_fill; - int rc = 0; - - switch (common->data_dir) { - case DATA_DIR_NONE: - break; /* Nothing to send */ - - /* - * If we don't know whether the host wants to read or write, - * this must be CB or CBI with an unknown command. We mustn't - * try to send or receive any data. So stall both bulk pipes - * if we can and wait for a reset. - */ - case DATA_DIR_UNKNOWN: - if (!common->can_stall) { - /* Nothing */ - } else if (fsg_is_set(common)) { - fsg_set_halt(common->fsg, common->fsg->bulk_out); - rc = halt_bulk_in_endpoint(common->fsg); - } else { - /* Don't know what to do if common->fsg is NULL */ - rc = -EIO; - } - break; - - /* All but the last buffer of data must have already been sent */ - case DATA_DIR_TO_HOST: - if (common->data_size == 0) { - /* Nothing to send */ - - /* Don't know what to do if common->fsg is NULL */ - } else if (!fsg_is_set(common)) { - rc = -EIO; - - /* If there's no residue, simply send the last buffer */ - } else if (common->residue == 0) { - bh->inreq->zero = 0; - if (!start_in_transfer(common, bh)) - return -EIO; - common->next_buffhd_to_fill = bh->next; - - /* - * For Bulk-only, mark the end of the data with a short - * packet. If we are allowed to stall, halt the bulk-in - * endpoint. (Note: This violates the Bulk-Only Transport - * specification, which requires us to pad the data if we - * don't halt the endpoint. Presumably nobody will mind.) - */ - } else { - bh->inreq->zero = 1; - if (!start_in_transfer(common, bh)) - rc = -EIO; - common->next_buffhd_to_fill = bh->next; - if (common->can_stall) - rc = halt_bulk_in_endpoint(common->fsg); - } - break; - - /* - * We have processed all we want from the data the host has sent. - * There may still be outstanding bulk-out requests. - */ - case DATA_DIR_FROM_HOST: - if (common->residue == 0) { - /* Nothing to receive */ - - /* Did the host stop sending unexpectedly early? */ - } else if (common->short_packet_received) { - raise_exception(common, FSG_STATE_ABORT_BULK_OUT); - rc = -EINTR; - - /* - * We haven't processed all the incoming data. Even though - * we may be allowed to stall, doing so would cause a race. - * The controller may already have ACK'ed all the remaining - * bulk-out packets, in which case the host wouldn't see a - * STALL. Not realizing the endpoint was halted, it wouldn't - * clear the halt -- leading to problems later on. - */ -#if 0 - } else if (common->can_stall) { - if (fsg_is_set(common)) - fsg_set_halt(common->fsg, - common->fsg->bulk_out); - raise_exception(common, FSG_STATE_ABORT_BULK_OUT); - rc = -EINTR; -#endif - - /* - * We can't stall. Read in the excess data and throw it - * all away. - */ - } else { - rc = throw_away_data(common); - } - break; - } - return rc; -} - -static int send_status(struct fsg_common *common) -{ - struct fsg_lun *curlun = common->curlun; - struct fsg_buffhd *bh; - struct bulk_cs_wrap *csw; - int rc; - u8 status = US_BULK_STAT_OK; - u32 sd, sdinfo = 0; - - /* Wait for the next buffer to become available */ - bh = common->next_buffhd_to_fill; - while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(common); - if (rc) - return rc; - } - - if (curlun) { - sd = curlun->sense_data; - sdinfo = curlun->sense_data_info; - } else if (common->bad_lun_okay) - sd = SS_NO_SENSE; - else - sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; - - if (common->phase_error) { - DBG(common, "sending phase-error status\n"); - status = US_BULK_STAT_PHASE; - sd = SS_INVALID_COMMAND; - } else if (sd != SS_NO_SENSE) { - DBG(common, "sending command-failure status\n"); - status = US_BULK_STAT_FAIL; - VDBG(common, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;" - " info x%x\n", - SK(sd), ASC(sd), ASCQ(sd), sdinfo); - } - - /* Store and send the Bulk-only CSW */ - csw = (void *)bh->buf; - - csw->Signature = cpu_to_le32(US_BULK_CS_SIGN); - csw->Tag = common->tag; - csw->Residue = cpu_to_le32(common->residue); - csw->Status = status; - - bh->inreq->length = US_BULK_CS_WRAP_LEN; - bh->inreq->zero = 0; - if (!start_in_transfer(common, bh)) - /* Don't know what to do if common->fsg is NULL */ - return -EIO; - - common->next_buffhd_to_fill = bh->next; - return 0; -} - - -/*-------------------------------------------------------------------------*/ - -/* - * Check whether the command is properly formed and whether its data size - * and direction agree with the values we already have. - */ -static int check_command(struct fsg_common *common, int cmnd_size, - enum data_direction data_dir, unsigned int mask, - int needs_medium, const char *name) -{ - int i; - int lun = common->cmnd[1] >> 5; - static const char dirletter[4] = {'u', 'o', 'i', 'n'}; - char hdlen[20]; - struct fsg_lun *curlun; - - hdlen[0] = 0; - if (common->data_dir != DATA_DIR_UNKNOWN) - sprintf(hdlen, ", H%c=%u", dirletter[(int) common->data_dir], - common->data_size); - VDBG(common, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n", - name, cmnd_size, dirletter[(int) data_dir], - common->data_size_from_cmnd, common->cmnd_size, hdlen); - - /* - * We can't reply at all until we know the correct data direction - * and size. - */ - if (common->data_size_from_cmnd == 0) - data_dir = DATA_DIR_NONE; - if (common->data_size < common->data_size_from_cmnd) { - /* - * Host data size < Device data size is a phase error. - * Carry out the command, but only transfer as much as - * we are allowed. - */ - common->data_size_from_cmnd = common->data_size; - common->phase_error = 1; - } - common->residue = common->data_size; - common->usb_amount_left = common->data_size; - - /* Conflicting data directions is a phase error */ - if (common->data_dir != data_dir && common->data_size_from_cmnd > 0) { - common->phase_error = 1; - return -EINVAL; - } - - /* Verify the length of the command itself */ - if (cmnd_size != common->cmnd_size) { - - /* - * Special case workaround: There are plenty of buggy SCSI - * implementations. Many have issues with cbw->Length - * field passing a wrong command size. For those cases we - * always try to work around the problem by using the length - * sent by the host side provided it is at least as large - * as the correct command length. - * Examples of such cases would be MS-Windows, which issues - * REQUEST SENSE with cbw->Length == 12 where it should - * be 6, and xbox360 issuing INQUIRY, TEST UNIT READY and - * REQUEST SENSE with cbw->Length == 10 where it should - * be 6 as well. - */ - if (cmnd_size <= common->cmnd_size) { - DBG(common, "%s is buggy! Expected length %d " - "but we got %d\n", name, - cmnd_size, common->cmnd_size); - cmnd_size = common->cmnd_size; - } else { - common->phase_error = 1; - return -EINVAL; - } - } - - /* Check that the LUN values are consistent */ - if (common->lun != lun) - DBG(common, "using LUN %d from CBW, not LUN %d from CDB\n", - common->lun, lun); - - /* Check the LUN */ - curlun = common->curlun; - if (curlun) { - if (common->cmnd[0] != REQUEST_SENSE) { - curlun->sense_data = SS_NO_SENSE; - curlun->sense_data_info = 0; - curlun->info_valid = 0; - } - } else { - common->bad_lun_okay = 0; - - /* - * INQUIRY and REQUEST SENSE commands are explicitly allowed - * to use unsupported LUNs; all others may not. - */ - if (common->cmnd[0] != INQUIRY && - common->cmnd[0] != REQUEST_SENSE) { - DBG(common, "unsupported LUN %d\n", common->lun); - return -EINVAL; - } - } - - /* - * If a unit attention condition exists, only INQUIRY and - * REQUEST SENSE commands are allowed; anything else must fail. - */ - if (curlun && curlun->unit_attention_data != SS_NO_SENSE && - common->cmnd[0] != INQUIRY && - common->cmnd[0] != REQUEST_SENSE) { - curlun->sense_data = curlun->unit_attention_data; - curlun->unit_attention_data = SS_NO_SENSE; - return -EINVAL; - } - - /* Check that only command bytes listed in the mask are non-zero */ - common->cmnd[1] &= 0x1f; /* Mask away the LUN */ - for (i = 1; i < cmnd_size; ++i) { - if (common->cmnd[i] && !(mask & (1 << i))) { - if (curlun) - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - } - - /* If the medium isn't mounted and the command needs to access - * it, return an error. */ - if (curlun && !fsg_lun_is_open(curlun) && needs_medium) { - curlun->sense_data = SS_MEDIUM_NOT_PRESENT; - return -EINVAL; - } - - return 0; -} - -/* wrapper of check_command for data size in blocks handling */ -static int check_command_size_in_blocks(struct fsg_common *common, - int cmnd_size, enum data_direction data_dir, - unsigned int mask, int needs_medium, const char *name) -{ - if (common->curlun) - common->data_size_from_cmnd <<= common->curlun->blkbits; - return check_command(common, cmnd_size, data_dir, - mask, needs_medium, name); -} - -static int do_scsi_command(struct fsg_common *common) -{ - struct fsg_buffhd *bh; - int rc; - int reply = -EINVAL; - int i; - static char unknown[16]; - - dump_cdb(common); - - /* Wait for the next buffer to become available for data or status */ - bh = common->next_buffhd_to_fill; - common->next_buffhd_to_drain = bh; - while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(common); - if (rc) - return rc; - } - common->phase_error = 0; - common->short_packet_received = 0; - - down_read(&common->filesem); /* We're using the backing file */ - switch (common->cmnd[0]) { - - case INQUIRY: - common->data_size_from_cmnd = common->cmnd[4]; - reply = check_command(common, 6, DATA_DIR_TO_HOST, - (1<<4), 0, - "INQUIRY"); - if (reply == 0) - reply = do_inquiry(common, bh); - break; - - case MODE_SELECT: - common->data_size_from_cmnd = common->cmnd[4]; - reply = check_command(common, 6, DATA_DIR_FROM_HOST, - (1<<1) | (1<<4), 0, - "MODE SELECT(6)"); - if (reply == 0) - reply = do_mode_select(common, bh); - break; - - case MODE_SELECT_10: - common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]); - reply = check_command(common, 10, DATA_DIR_FROM_HOST, - (1<<1) | (3<<7), 0, - "MODE SELECT(10)"); - if (reply == 0) - reply = do_mode_select(common, bh); - break; - - case MODE_SENSE: - common->data_size_from_cmnd = common->cmnd[4]; - reply = check_command(common, 6, DATA_DIR_TO_HOST, - (1<<1) | (1<<2) | (1<<4), 0, - "MODE SENSE(6)"); - if (reply == 0) - reply = do_mode_sense(common, bh); - break; - - case MODE_SENSE_10: - common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]); - reply = check_command(common, 10, DATA_DIR_TO_HOST, - (1<<1) | (1<<2) | (3<<7), 0, - "MODE SENSE(10)"); - if (reply == 0) - reply = do_mode_sense(common, bh); - break; - - case ALLOW_MEDIUM_REMOVAL: - common->data_size_from_cmnd = 0; - reply = check_command(common, 6, DATA_DIR_NONE, - (1<<4), 0, - "PREVENT-ALLOW MEDIUM REMOVAL"); - if (reply == 0) - reply = do_prevent_allow(common); - break; - - case READ_6: - i = common->cmnd[4]; - common->data_size_from_cmnd = (i == 0) ? 256 : i; - reply = check_command_size_in_blocks(common, 6, - DATA_DIR_TO_HOST, - (7<<1) | (1<<4), 1, - "READ(6)"); - if (reply == 0) - reply = do_read(common); - break; - - case READ_10: - common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]); - reply = check_command_size_in_blocks(common, 10, - DATA_DIR_TO_HOST, - (1<<1) | (0xf<<2) | (3<<7), 1, - "READ(10)"); - if (reply == 0) - reply = do_read(common); - break; - - case READ_12: - common->data_size_from_cmnd = - get_unaligned_be32(&common->cmnd[6]); - reply = check_command_size_in_blocks(common, 12, - DATA_DIR_TO_HOST, - (1<<1) | (0xf<<2) | (0xf<<6), 1, - "READ(12)"); - if (reply == 0) - reply = do_read(common); - break; - - case READ_CAPACITY: - common->data_size_from_cmnd = 8; - reply = check_command(common, 10, DATA_DIR_TO_HOST, - (0xf<<2) | (1<<8), 1, - "READ CAPACITY"); - if (reply == 0) - reply = do_read_capacity(common, bh); - break; - - case READ_HEADER: - if (!common->curlun || !common->curlun->cdrom) - goto unknown_cmnd; - common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]); - reply = check_command(common, 10, DATA_DIR_TO_HOST, - (3<<7) | (0x1f<<1), 1, - "READ HEADER"); - if (reply == 0) - reply = do_read_header(common, bh); - break; - - case READ_TOC: - if (!common->curlun || !common->curlun->cdrom) - goto unknown_cmnd; - common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]); - reply = check_command(common, 10, DATA_DIR_TO_HOST, - (7<<6) | (1<<1), 1, - "READ TOC"); - if (reply == 0) - reply = do_read_toc(common, bh); - break; - - case READ_FORMAT_CAPACITIES: - common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]); - reply = check_command(common, 10, DATA_DIR_TO_HOST, - (3<<7), 1, - "READ FORMAT CAPACITIES"); - if (reply == 0) - reply = do_read_format_capacities(common, bh); - break; - - case REQUEST_SENSE: - common->data_size_from_cmnd = common->cmnd[4]; - reply = check_command(common, 6, DATA_DIR_TO_HOST, - (1<<4), 0, - "REQUEST SENSE"); - if (reply == 0) - reply = do_request_sense(common, bh); - break; - - case START_STOP: - common->data_size_from_cmnd = 0; - reply = check_command(common, 6, DATA_DIR_NONE, - (1<<1) | (1<<4), 0, - "START-STOP UNIT"); - if (reply == 0) - reply = do_start_stop(common); - break; - - case SYNCHRONIZE_CACHE: - common->data_size_from_cmnd = 0; - reply = check_command(common, 10, DATA_DIR_NONE, - (0xf<<2) | (3<<7), 1, - "SYNCHRONIZE CACHE"); - if (reply == 0) - reply = do_synchronize_cache(common); - break; - - case TEST_UNIT_READY: - common->data_size_from_cmnd = 0; - reply = check_command(common, 6, DATA_DIR_NONE, - 0, 1, - "TEST UNIT READY"); - break; - - /* - * Although optional, this command is used by MS-Windows. We - * support a minimal version: BytChk must be 0. - */ - case VERIFY: - common->data_size_from_cmnd = 0; - reply = check_command(common, 10, DATA_DIR_NONE, - (1<<1) | (0xf<<2) | (3<<7), 1, - "VERIFY"); - if (reply == 0) - reply = do_verify(common); - break; - - case WRITE_6: - i = common->cmnd[4]; - common->data_size_from_cmnd = (i == 0) ? 256 : i; - reply = check_command_size_in_blocks(common, 6, - DATA_DIR_FROM_HOST, - (7<<1) | (1<<4), 1, - "WRITE(6)"); - if (reply == 0) - reply = do_write(common); - break; - - case WRITE_10: - common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]); - reply = check_command_size_in_blocks(common, 10, - DATA_DIR_FROM_HOST, - (1<<1) | (0xf<<2) | (3<<7), 1, - "WRITE(10)"); - if (reply == 0) - reply = do_write(common); - break; - - case WRITE_12: - common->data_size_from_cmnd = - get_unaligned_be32(&common->cmnd[6]); - reply = check_command_size_in_blocks(common, 12, - DATA_DIR_FROM_HOST, - (1<<1) | (0xf<<2) | (0xf<<6), 1, - "WRITE(12)"); - if (reply == 0) - reply = do_write(common); - break; - - /* - * Some mandatory commands that we recognize but don't implement. - * They don't mean much in this setting. It's left as an exercise - * for anyone interested to implement RESERVE and RELEASE in terms - * of Posix locks. - */ - case FORMAT_UNIT: - case RELEASE: - case RESERVE: - case SEND_DIAGNOSTIC: - /* Fall through */ - - default: -unknown_cmnd: - common->data_size_from_cmnd = 0; - sprintf(unknown, "Unknown x%02x", common->cmnd[0]); - reply = check_command(common, common->cmnd_size, - DATA_DIR_UNKNOWN, ~0, 0, unknown); - if (reply == 0) { - common->curlun->sense_data = SS_INVALID_COMMAND; - reply = -EINVAL; - } - break; - } - up_read(&common->filesem); - - if (reply == -EINTR || signal_pending(current)) - return -EINTR; - - /* Set up the single reply buffer for finish_reply() */ - if (reply == -EINVAL) - reply = 0; /* Error reply length */ - if (reply >= 0 && common->data_dir == DATA_DIR_TO_HOST) { - reply = min((u32)reply, common->data_size_from_cmnd); - bh->inreq->length = reply; - bh->state = BUF_STATE_FULL; - common->residue -= reply; - } /* Otherwise it's already set */ - - return 0; -} - - -/*-------------------------------------------------------------------------*/ - -static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct usb_request *req = bh->outreq; - struct bulk_cb_wrap *cbw = req->buf; - struct fsg_common *common = fsg->common; - - /* Was this a real packet? Should it be ignored? */ - if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags)) - return -EINVAL; - - /* Is the CBW valid? */ - if (req->actual != US_BULK_CB_WRAP_LEN || - cbw->Signature != cpu_to_le32( - US_BULK_CB_SIGN)) { - DBG(fsg, "invalid CBW: len %u sig 0x%x\n", - req->actual, - le32_to_cpu(cbw->Signature)); - - /* - * The Bulk-only spec says we MUST stall the IN endpoint - * (6.6.1), so it's unavoidable. It also says we must - * retain this state until the next reset, but there's - * no way to tell the controller driver it should ignore - * Clear-Feature(HALT) requests. - * - * We aren't required to halt the OUT endpoint; instead - * we can simply accept and discard any data received - * until the next reset. - */ - wedge_bulk_in_endpoint(fsg); - set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); - return -EINVAL; - } - - /* Is the CBW meaningful? */ - if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN || - cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) { - DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, " - "cmdlen %u\n", - cbw->Lun, cbw->Flags, cbw->Length); - - /* - * We can do anything we want here, so let's stall the - * bulk pipes if we are allowed to. - */ - if (common->can_stall) { - fsg_set_halt(fsg, fsg->bulk_out); - halt_bulk_in_endpoint(fsg); - } - return -EINVAL; - } - - /* Save the command for later */ - common->cmnd_size = cbw->Length; - memcpy(common->cmnd, cbw->CDB, common->cmnd_size); - if (cbw->Flags & US_BULK_FLAG_IN) - common->data_dir = DATA_DIR_TO_HOST; - else - common->data_dir = DATA_DIR_FROM_HOST; - common->data_size = le32_to_cpu(cbw->DataTransferLength); - if (common->data_size == 0) - common->data_dir = DATA_DIR_NONE; - common->lun = cbw->Lun; - if (common->lun >= 0 && common->lun < common->nluns) - common->curlun = &common->luns[common->lun]; - else - common->curlun = NULL; - common->tag = cbw->Tag; - return 0; -} - -static int get_next_command(struct fsg_common *common) -{ - struct fsg_buffhd *bh; - int rc = 0; - - /* Wait for the next buffer to become available */ - bh = common->next_buffhd_to_fill; - while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(common); - if (rc) - return rc; - } - - /* Queue a request to read a Bulk-only CBW */ - set_bulk_out_req_length(common, bh, US_BULK_CB_WRAP_LEN); - if (!start_out_transfer(common, bh)) - /* Don't know what to do if common->fsg is NULL */ - return -EIO; - - /* - * We will drain the buffer in software, which means we - * can reuse it for the next filling. No need to advance - * next_buffhd_to_fill. - */ - - /* Wait for the CBW to arrive */ - while (bh->state != BUF_STATE_FULL) { - rc = sleep_thread(common); - if (rc) - return rc; - } - smp_rmb(); - rc = fsg_is_set(common) ? received_cbw(common->fsg, bh) : -EIO; - bh->state = BUF_STATE_EMPTY; - - return rc; -} - - -/*-------------------------------------------------------------------------*/ - -static int alloc_request(struct fsg_common *common, struct usb_ep *ep, - struct usb_request **preq) -{ - *preq = usb_ep_alloc_request(ep, GFP_ATOMIC); - if (*preq) - return 0; - ERROR(common, "can't allocate request for %s\n", ep->name); - return -ENOMEM; -} - -/* Reset interface setting and re-init endpoint state (toggle etc). */ -static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg) -{ - struct fsg_dev *fsg; - int i, rc = 0; - - if (common->running) - DBG(common, "reset interface\n"); - -reset: - /* Deallocate the requests */ - if (common->fsg) { - fsg = common->fsg; - - for (i = 0; i < fsg_num_buffers; ++i) { - struct fsg_buffhd *bh = &common->buffhds[i]; - - if (bh->inreq) { - usb_ep_free_request(fsg->bulk_in, bh->inreq); - bh->inreq = NULL; - } - if (bh->outreq) { - usb_ep_free_request(fsg->bulk_out, bh->outreq); - bh->outreq = NULL; - } - } - - /* Disable the endpoints */ - if (fsg->bulk_in_enabled) { - usb_ep_disable(fsg->bulk_in); - fsg->bulk_in_enabled = 0; - } - if (fsg->bulk_out_enabled) { - usb_ep_disable(fsg->bulk_out); - fsg->bulk_out_enabled = 0; - } - - common->fsg = NULL; - wake_up(&common->fsg_wait); - } - - common->running = 0; - if (!new_fsg || rc) - return rc; - - common->fsg = new_fsg; - fsg = common->fsg; - - /* Enable the endpoints */ - rc = config_ep_by_speed(common->gadget, &(fsg->function), fsg->bulk_in); - if (rc) - goto reset; - rc = usb_ep_enable(fsg->bulk_in); - if (rc) - goto reset; - fsg->bulk_in->driver_data = common; - fsg->bulk_in_enabled = 1; - - rc = config_ep_by_speed(common->gadget, &(fsg->function), - fsg->bulk_out); - if (rc) - goto reset; - rc = usb_ep_enable(fsg->bulk_out); - if (rc) - goto reset; - fsg->bulk_out->driver_data = common; - fsg->bulk_out_enabled = 1; - common->bulk_out_maxpacket = usb_endpoint_maxp(fsg->bulk_out->desc); - clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); - - /* Allocate the requests */ - for (i = 0; i < fsg_num_buffers; ++i) { - struct fsg_buffhd *bh = &common->buffhds[i]; - - rc = alloc_request(common, fsg->bulk_in, &bh->inreq); - if (rc) - goto reset; - rc = alloc_request(common, fsg->bulk_out, &bh->outreq); - if (rc) - goto reset; - bh->inreq->buf = bh->outreq->buf = bh->buf; - bh->inreq->context = bh->outreq->context = bh; - bh->inreq->complete = bulk_in_complete; - bh->outreq->complete = bulk_out_complete; - } - - common->running = 1; - for (i = 0; i < common->nluns; ++i) - common->luns[i].unit_attention_data = SS_RESET_OCCURRED; - return rc; -} - - -/****************************** ALT CONFIGS ******************************/ - -static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) -{ - struct fsg_dev *fsg = fsg_from_func(f); - fsg->common->new_fsg = fsg; - raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); - return USB_GADGET_DELAYED_STATUS; -} - -static void fsg_disable(struct usb_function *f) -{ - struct fsg_dev *fsg = fsg_from_func(f); - fsg->common->new_fsg = NULL; - raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); -} - - -/*-------------------------------------------------------------------------*/ - -static void handle_exception(struct fsg_common *common) -{ - siginfo_t info; - int i; - struct fsg_buffhd *bh; - enum fsg_state old_state; - struct fsg_lun *curlun; - unsigned int exception_req_tag; - - /* - * Clear the existing signals. Anything but SIGUSR1 is converted - * into a high-priority EXIT exception. - */ - for (;;) { - int sig = - dequeue_signal_lock(current, ¤t->blocked, &info); - if (!sig) - break; - if (sig != SIGUSR1) { - if (common->state < FSG_STATE_EXIT) - DBG(common, "Main thread exiting on signal\n"); - raise_exception(common, FSG_STATE_EXIT); - } - } - - /* Cancel all the pending transfers */ - if (likely(common->fsg)) { - for (i = 0; i < fsg_num_buffers; ++i) { - bh = &common->buffhds[i]; - if (bh->inreq_busy) - usb_ep_dequeue(common->fsg->bulk_in, bh->inreq); - if (bh->outreq_busy) - usb_ep_dequeue(common->fsg->bulk_out, - bh->outreq); - } - - /* Wait until everything is idle */ - for (;;) { - int num_active = 0; - for (i = 0; i < fsg_num_buffers; ++i) { - bh = &common->buffhds[i]; - num_active += bh->inreq_busy + bh->outreq_busy; - } - if (num_active == 0) - break; - if (sleep_thread(common)) - return; - } - - /* Clear out the controller's fifos */ - if (common->fsg->bulk_in_enabled) - usb_ep_fifo_flush(common->fsg->bulk_in); - if (common->fsg->bulk_out_enabled) - usb_ep_fifo_flush(common->fsg->bulk_out); - } - - /* - * Reset the I/O buffer states and pointers, the SCSI - * state, and the exception. Then invoke the handler. - */ - spin_lock_irq(&common->lock); - - for (i = 0; i < fsg_num_buffers; ++i) { - bh = &common->buffhds[i]; - bh->state = BUF_STATE_EMPTY; - } - common->next_buffhd_to_fill = &common->buffhds[0]; - common->next_buffhd_to_drain = &common->buffhds[0]; - exception_req_tag = common->exception_req_tag; - old_state = common->state; - - if (old_state == FSG_STATE_ABORT_BULK_OUT) - common->state = FSG_STATE_STATUS_PHASE; - else { - for (i = 0; i < common->nluns; ++i) { - curlun = &common->luns[i]; - curlun->prevent_medium_removal = 0; - curlun->sense_data = SS_NO_SENSE; - curlun->unit_attention_data = SS_NO_SENSE; - curlun->sense_data_info = 0; - curlun->info_valid = 0; - } - common->state = FSG_STATE_IDLE; - } - spin_unlock_irq(&common->lock); - - /* Carry out any extra actions required for the exception */ - switch (old_state) { - case FSG_STATE_ABORT_BULK_OUT: - send_status(common); - spin_lock_irq(&common->lock); - if (common->state == FSG_STATE_STATUS_PHASE) - common->state = FSG_STATE_IDLE; - spin_unlock_irq(&common->lock); - break; - - case FSG_STATE_RESET: - /* - * In case we were forced against our will to halt a - * bulk endpoint, clear the halt now. (The SuperH UDC - * requires this.) - */ - if (!fsg_is_set(common)) - break; - if (test_and_clear_bit(IGNORE_BULK_OUT, - &common->fsg->atomic_bitflags)) - usb_ep_clear_halt(common->fsg->bulk_in); - - if (common->ep0_req_tag == exception_req_tag) - ep0_queue(common); /* Complete the status stage */ - - /* - * Technically this should go here, but it would only be - * a waste of time. Ditto for the INTERFACE_CHANGE and - * CONFIG_CHANGE cases. - */ - /* for (i = 0; i < common->nluns; ++i) */ - /* common->luns[i].unit_attention_data = */ - /* SS_RESET_OCCURRED; */ - break; - - case FSG_STATE_CONFIG_CHANGE: - do_set_interface(common, common->new_fsg); - if (common->new_fsg) - usb_composite_setup_continue(common->cdev); - break; - - case FSG_STATE_EXIT: - case FSG_STATE_TERMINATED: - do_set_interface(common, NULL); /* Free resources */ - spin_lock_irq(&common->lock); - common->state = FSG_STATE_TERMINATED; /* Stop the thread */ - spin_unlock_irq(&common->lock); - break; - - case FSG_STATE_INTERFACE_CHANGE: - case FSG_STATE_DISCONNECT: - case FSG_STATE_COMMAND_PHASE: - case FSG_STATE_DATA_PHASE: - case FSG_STATE_STATUS_PHASE: - case FSG_STATE_IDLE: - break; - } -} - - -/*-------------------------------------------------------------------------*/ - -static int fsg_main_thread(void *common_) -{ - struct fsg_common *common = common_; - - /* - * Allow the thread to be killed by a signal, but set the signal mask - * to block everything but INT, TERM, KILL, and USR1. - */ - allow_signal(SIGINT); - allow_signal(SIGTERM); - allow_signal(SIGKILL); - allow_signal(SIGUSR1); - - /* Allow the thread to be frozen */ - set_freezable(); - - /* - * Arrange for userspace references to be interpreted as kernel - * pointers. That way we can pass a kernel pointer to a routine - * that expects a __user pointer and it will work okay. - */ - set_fs(get_ds()); - - /* The main loop */ - while (common->state != FSG_STATE_TERMINATED) { - if (exception_in_progress(common) || signal_pending(current)) { - handle_exception(common); - continue; - } - - if (!common->running) { - sleep_thread(common); - continue; - } - - if (get_next_command(common)) - continue; - - spin_lock_irq(&common->lock); - if (!exception_in_progress(common)) - common->state = FSG_STATE_DATA_PHASE; - spin_unlock_irq(&common->lock); - - if (do_scsi_command(common) || finish_reply(common)) - continue; - - spin_lock_irq(&common->lock); - if (!exception_in_progress(common)) - common->state = FSG_STATE_STATUS_PHASE; - spin_unlock_irq(&common->lock); - - if (send_status(common)) - continue; - - spin_lock_irq(&common->lock); - if (!exception_in_progress(common)) - common->state = FSG_STATE_IDLE; - spin_unlock_irq(&common->lock); - } - - spin_lock_irq(&common->lock); - common->thread_task = NULL; - spin_unlock_irq(&common->lock); - - if (!common->ops || !common->ops->thread_exits - || common->ops->thread_exits(common) < 0) { - struct fsg_lun *curlun = common->luns; - unsigned i = common->nluns; - - down_write(&common->filesem); - for (; i--; ++curlun) { - if (!fsg_lun_is_open(curlun)) - continue; - - fsg_lun_close(curlun); - curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT; - } - up_write(&common->filesem); - } - - /* Let fsg_unbind() know the thread has exited */ - complete_and_exit(&common->thread_notifier, 0); -} - - -/*************************** DEVICE ATTRIBUTES ***************************/ - -/* Write permission is checked per LUN in store_*() functions. */ -static DEVICE_ATTR(ro, 0644, fsg_show_ro, fsg_store_ro); -static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, fsg_store_nofua); -static DEVICE_ATTR(file, 0644, fsg_show_file, fsg_store_file); -static DEVICE_ATTR(cdrom, 0644, fsg_show_cdrom, fsg_store_cdrom); - - - -/****************************** FSG COMMON ******************************/ - -static void fsg_common_release(struct kref *ref); - -static void fsg_lun_release(struct device *dev) -{ - /* Nothing needs to be done */ -} - -static inline void fsg_common_get(struct fsg_common *common) -{ - kref_get(&common->ref); -} - -static inline void fsg_common_put(struct fsg_common *common) -{ - kref_put(&common->ref, fsg_common_release); -} - -static struct fsg_common *fsg_common_init(struct fsg_common *common, - struct usb_composite_dev *cdev, - struct fsg_config *cfg) -{ - struct usb_gadget *gadget = cdev->gadget; - struct fsg_buffhd *bh; - struct fsg_lun *curlun; - struct fsg_lun_config *lcfg; - int nluns, i, rc; - char *pathbuf; - - rc = fsg_num_buffers_validate(); - if (rc != 0) - return ERR_PTR(rc); - - /* Find out how many LUNs there should be */ - nluns = cfg->nluns; - if (nluns < 1 || nluns > FSG_MAX_LUNS) { - dev_err(&gadget->dev, "invalid number of LUNs: %u\n", nluns); - return ERR_PTR(-EINVAL); - } - - /* Allocate? */ - if (!common) { - common = kzalloc(sizeof *common, GFP_KERNEL); - if (!common) - return ERR_PTR(-ENOMEM); - common->free_storage_on_release = 1; - } else { - memset(common, 0, sizeof *common); - common->free_storage_on_release = 0; - } - - common->buffhds = kcalloc(fsg_num_buffers, - sizeof *(common->buffhds), GFP_KERNEL); - if (!common->buffhds) { - if (common->free_storage_on_release) - kfree(common); - return ERR_PTR(-ENOMEM); - } - - common->ops = cfg->ops; - common->private_data = cfg->private_data; - - common->gadget = gadget; - common->ep0 = gadget->ep0; - common->ep0req = cdev->req; - common->cdev = cdev; - - /* Maybe allocate device-global string IDs, and patch descriptors */ - if (fsg_strings[FSG_STRING_INTERFACE].id == 0) { - rc = usb_string_id(cdev); - if (unlikely(rc < 0)) - goto error_release; - fsg_strings[FSG_STRING_INTERFACE].id = rc; - fsg_intf_desc.iInterface = rc; - } - - /* - * Create the LUNs, open their backing files, and register the - * LUN devices in sysfs. - */ - curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL); - if (unlikely(!curlun)) { - rc = -ENOMEM; - goto error_release; - } - common->luns = curlun; - - init_rwsem(&common->filesem); - - for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun, ++lcfg) { - curlun->cdrom = !!lcfg->cdrom; - curlun->ro = lcfg->cdrom || lcfg->ro; - curlun->initially_ro = curlun->ro; - curlun->removable = lcfg->removable; - curlun->dev.release = fsg_lun_release; - curlun->dev.parent = &gadget->dev; - /* curlun->dev.driver = &fsg_driver.driver; XXX */ - dev_set_drvdata(&curlun->dev, &common->filesem); - dev_set_name(&curlun->dev, - cfg->lun_name_format - ? cfg->lun_name_format - : "lun%d", - i); - - rc = device_register(&curlun->dev); - if (rc) { - INFO(common, "failed to register LUN%d: %d\n", i, rc); - common->nluns = i; - put_device(&curlun->dev); - goto error_release; - } - - rc = device_create_file(&curlun->dev, &dev_attr_ro); - if (rc) - goto error_luns; - rc = device_create_file(&curlun->dev, &dev_attr_file); - if (rc) - goto error_luns; - rc = device_create_file(&curlun->dev, &dev_attr_nofua); - if (rc) - goto error_luns; - rc = device_create_file(&curlun->dev, &dev_attr_cdrom); - if (rc) - goto error_luns; - if (lcfg->filename) { - rc = fsg_lun_open(curlun, lcfg->filename); - if (rc) - goto error_luns; - } else if (!curlun->removable) { - ERROR(common, "no file given for LUN%d\n", i); - rc = -EINVAL; - goto error_luns; - } - } - common->nluns = nluns; - - /* Data buffers cyclic list */ - bh = common->buffhds; - i = fsg_num_buffers; - goto buffhds_first_it; - do { - bh->next = bh + 1; - ++bh; -buffhds_first_it: - bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL); - if (unlikely(!bh->buf)) { - rc = -ENOMEM; - goto error_release; - } - } while (--i); - bh->next = common->buffhds; - - /* Prepare inquiryString */ - if (cfg->release != 0xffff) { - i = cfg->release; - } else { - i = usb_gadget_controller_number(gadget); - if (i >= 0) { - i = 0x0300 + i; - } else { - WARNING(common, "controller '%s' not recognized\n", - gadget->name); - i = 0x0399; - } - } - snprintf(common->inquiry_string, sizeof common->inquiry_string, - "%-8s%-16s%04x", cfg->vendor_name ?: "Linux", - /* Assume product name dependent on the first LUN */ - cfg->product_name ?: (common->luns->cdrom - ? "File-Stor Gadget" - : "File-CD Gadget"), - i); - - /* - * Some peripheral controllers are known not to be able to - * halt bulk endpoints correctly. If one of them is present, - * disable stalls. - */ - common->can_stall = cfg->can_stall && - !(gadget_is_at91(common->gadget)); - - spin_lock_init(&common->lock); - kref_init(&common->ref); - - /* Tell the thread to start working */ - common->thread_task = - kthread_create(fsg_main_thread, common, - cfg->thread_name ?: "file-storage"); - if (IS_ERR(common->thread_task)) { - rc = PTR_ERR(common->thread_task); - goto error_release; - } - init_completion(&common->thread_notifier); - init_waitqueue_head(&common->fsg_wait); - - /* Information */ - INFO(common, FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n"); - INFO(common, "Number of LUNs=%d\n", common->nluns); - - pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); - for (i = 0, nluns = common->nluns, curlun = common->luns; - i < nluns; - ++curlun, ++i) { - char *p = "(no medium)"; - if (fsg_lun_is_open(curlun)) { - p = "(error)"; - if (pathbuf) { - p = d_path(&curlun->filp->f_path, - pathbuf, PATH_MAX); - if (IS_ERR(p)) - p = "(error)"; - } - } - LINFO(curlun, "LUN: %s%s%sfile: %s\n", - curlun->removable ? "removable " : "", - curlun->ro ? "read only " : "", - curlun->cdrom ? "CD-ROM " : "", - p); - } - kfree(pathbuf); - - DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task)); - - wake_up_process(common->thread_task); - - return common; - -error_luns: - common->nluns = i + 1; -error_release: - common->state = FSG_STATE_TERMINATED; /* The thread is dead */ - /* Call fsg_common_release() directly, ref might be not initialised. */ - fsg_common_release(&common->ref); - return ERR_PTR(rc); -} - -static void fsg_common_release(struct kref *ref) -{ - struct fsg_common *common = container_of(ref, struct fsg_common, ref); - - /* If the thread isn't already dead, tell it to exit now */ - if (common->state != FSG_STATE_TERMINATED) { - raise_exception(common, FSG_STATE_EXIT); - wait_for_completion(&common->thread_notifier); - } - - if (likely(common->luns)) { - struct fsg_lun *lun = common->luns; - unsigned i = common->nluns; - - /* In error recovery common->nluns may be zero. */ - for (; i; --i, ++lun) { - device_remove_file(&lun->dev, &dev_attr_nofua); - device_remove_file(&lun->dev, &dev_attr_ro); - device_remove_file(&lun->dev, &dev_attr_file); - device_remove_file(&lun->dev, &dev_attr_cdrom); - fsg_lun_close(lun); - device_unregister(&lun->dev); - } - - kfree(common->luns); - } - - { - struct fsg_buffhd *bh = common->buffhds; - unsigned i = fsg_num_buffers; - do { - kfree(bh->buf); - } while (++bh, --i); - } - - kfree(common->buffhds); - if (common->free_storage_on_release) - kfree(common); -} - - -/*-------------------------------------------------------------------------*/ - -static void fsg_unbind(struct usb_configuration *c, struct usb_function *f) -{ - struct fsg_dev *fsg = fsg_from_func(f); - struct fsg_common *common = fsg->common; - - DBG(fsg, "unbind\n"); - if (fsg->common->fsg == fsg) { - fsg->common->new_fsg = NULL; - raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); - /* FIXME: make interruptible or killable somehow? */ - wait_event(common->fsg_wait, common->fsg != fsg); - } - - fsg_common_put(common); - usb_free_descriptors(fsg->function.descriptors); - usb_free_descriptors(fsg->function.hs_descriptors); - usb_free_descriptors(fsg->function.ss_descriptors); - kfree(fsg); -} - -static int fsg_bind(struct usb_configuration *c, struct usb_function *f) -{ - struct fsg_dev *fsg = fsg_from_func(f); - struct usb_gadget *gadget = c->cdev->gadget; - int i; - struct usb_ep *ep; - - fsg->gadget = gadget; - - /* New interface */ - i = usb_interface_id(c, f); - if (i < 0) - return i; - fsg_intf_desc.bInterfaceNumber = i; - fsg->interface_number = i; - - /* Find all the endpoints we will use */ - ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc); - if (!ep) - goto autoconf_fail; - ep->driver_data = fsg->common; /* claim the endpoint */ - fsg->bulk_in = ep; - - ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc); - if (!ep) - goto autoconf_fail; - ep->driver_data = fsg->common; /* claim the endpoint */ - fsg->bulk_out = ep; - - /* Copy descriptors */ - f->descriptors = usb_copy_descriptors(fsg_fs_function); - if (unlikely(!f->descriptors)) - return -ENOMEM; - - if (gadget_is_dualspeed(gadget)) { - /* Assume endpoint addresses are the same for both speeds */ - fsg_hs_bulk_in_desc.bEndpointAddress = - fsg_fs_bulk_in_desc.bEndpointAddress; - fsg_hs_bulk_out_desc.bEndpointAddress = - fsg_fs_bulk_out_desc.bEndpointAddress; - f->hs_descriptors = usb_copy_descriptors(fsg_hs_function); - if (unlikely(!f->hs_descriptors)) { - usb_free_descriptors(f->descriptors); - return -ENOMEM; - } - } - - if (gadget_is_superspeed(gadget)) { - unsigned max_burst; - - /* Calculate bMaxBurst, we know packet size is 1024 */ - max_burst = min_t(unsigned, FSG_BUFLEN / 1024, 15); - - fsg_ss_bulk_in_desc.bEndpointAddress = - fsg_fs_bulk_in_desc.bEndpointAddress; - fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst; - - fsg_ss_bulk_out_desc.bEndpointAddress = - fsg_fs_bulk_out_desc.bEndpointAddress; - fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst; - - f->ss_descriptors = usb_copy_descriptors(fsg_ss_function); - if (unlikely(!f->ss_descriptors)) { - usb_free_descriptors(f->hs_descriptors); - usb_free_descriptors(f->descriptors); - return -ENOMEM; - } - } - - return 0; - -autoconf_fail: - ERROR(fsg, "unable to autoconfigure all endpoints\n"); - return -ENOTSUPP; -} - - -/****************************** ADD FUNCTION ******************************/ - -static struct usb_gadget_strings *fsg_strings_array[] = { - &fsg_stringtab, - NULL, -}; - -static int fsg_bind_config(struct usb_composite_dev *cdev, - struct usb_configuration *c, - struct fsg_common *common) -{ - struct fsg_dev *fsg; - int rc; - - fsg = kzalloc(sizeof *fsg, GFP_KERNEL); - if (unlikely(!fsg)) - return -ENOMEM; - - fsg->function.name = FSG_DRIVER_DESC; - fsg->function.strings = fsg_strings_array; - fsg->function.bind = fsg_bind; - fsg->function.unbind = fsg_unbind; - fsg->function.setup = fsg_setup; - fsg->function.set_alt = fsg_set_alt; - fsg->function.disable = fsg_disable; - - fsg->common = common; - /* - * Our caller holds a reference to common structure so we - * don't have to be worry about it being freed until we return - * from this function. So instead of incrementing counter now - * and decrement in error recovery we increment it only when - * call to usb_add_function() was successful. - */ - - rc = usb_add_function(c, &fsg->function); - if (unlikely(rc)) - kfree(fsg); - else - fsg_common_get(fsg->common); - return rc; -} - -static inline int __deprecated __maybe_unused -fsg_add(struct usb_composite_dev *cdev, struct usb_configuration *c, - struct fsg_common *common) -{ - return fsg_bind_config(cdev, c, common); -} - - -/************************* Module parameters *************************/ - -struct fsg_module_parameters { - char *file[FSG_MAX_LUNS]; - bool ro[FSG_MAX_LUNS]; - bool removable[FSG_MAX_LUNS]; - bool cdrom[FSG_MAX_LUNS]; - bool nofua[FSG_MAX_LUNS]; - - unsigned int file_count, ro_count, removable_count, cdrom_count; - unsigned int nofua_count; - unsigned int luns; /* nluns */ - bool stall; /* can_stall */ -}; - -#define _FSG_MODULE_PARAM_ARRAY(prefix, params, name, type, desc) \ - module_param_array_named(prefix ## name, params.name, type, \ - &prefix ## params.name ## _count, \ - S_IRUGO); \ - MODULE_PARM_DESC(prefix ## name, desc) - -#define _FSG_MODULE_PARAM(prefix, params, name, type, desc) \ - module_param_named(prefix ## name, params.name, type, \ - S_IRUGO); \ - MODULE_PARM_DESC(prefix ## name, desc) - -#define FSG_MODULE_PARAMETERS(prefix, params) \ - _FSG_MODULE_PARAM_ARRAY(prefix, params, file, charp, \ - "names of backing files or devices"); \ - _FSG_MODULE_PARAM_ARRAY(prefix, params, ro, bool, \ - "true to force read-only"); \ - _FSG_MODULE_PARAM_ARRAY(prefix, params, removable, bool, \ - "true to simulate removable media"); \ - _FSG_MODULE_PARAM_ARRAY(prefix, params, cdrom, bool, \ - "true to simulate CD-ROM instead of disk"); \ - _FSG_MODULE_PARAM_ARRAY(prefix, params, nofua, bool, \ - "true to ignore SCSI WRITE(10,12) FUA bit"); \ - _FSG_MODULE_PARAM(prefix, params, luns, uint, \ - "number of LUNs"); \ - _FSG_MODULE_PARAM(prefix, params, stall, bool, \ - "false to prevent bulk stalls") - -static void -fsg_config_from_params(struct fsg_config *cfg, - const struct fsg_module_parameters *params) -{ - struct fsg_lun_config *lun; - unsigned i; - - /* Configure LUNs */ - cfg->nluns = - min(params->luns ?: (params->file_count ?: 1u), - (unsigned)FSG_MAX_LUNS); - for (i = 0, lun = cfg->luns; i < cfg->nluns; ++i, ++lun) { - lun->ro = !!params->ro[i]; - lun->cdrom = !!params->cdrom[i]; - lun->removable = /* Removable by default */ - params->removable_count <= i || params->removable[i]; - lun->filename = - params->file_count > i && params->file[i][0] - ? params->file[i] - : 0; - } - - /* Let MSF use defaults */ - cfg->lun_name_format = 0; - cfg->thread_name = 0; - cfg->vendor_name = 0; - cfg->product_name = 0; - cfg->release = 0xffff; - - cfg->ops = NULL; - cfg->private_data = NULL; - - /* Finalise */ - cfg->can_stall = params->stall; -} - -static inline struct fsg_common * -fsg_common_from_params(struct fsg_common *common, - struct usb_composite_dev *cdev, - const struct fsg_module_parameters *params) - __attribute__((unused)); -static inline struct fsg_common * -fsg_common_from_params(struct fsg_common *common, - struct usb_composite_dev *cdev, - const struct fsg_module_parameters *params) -{ - struct fsg_config cfg; - fsg_config_from_params(&cfg, params); - return fsg_common_init(common, cdev, &cfg); -} - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_midi.c b/ANDROID_3.4.5/drivers/usb/gadget/f_midi.c deleted file mode 100644 index 2f7e8f29..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_midi.c +++ /dev/null @@ -1,990 +0,0 @@ -/* - * f_midi.c -- USB MIDI class function driver - * - * Copyright (C) 2006 Thumtronics Pty Ltd. - * Developed for Thumtronics by Grey Innovation - * Ben Williamson - * - * Rewritten for the composite framework - * Copyright (C) 2011 Daniel Mack - * - * Based on drivers/usb/gadget/f_audio.c, - * Copyright (C) 2008 Bryan Wu - * Copyright (C) 2008 Analog Devices, Inc - * - * and drivers/usb/gadget/midi.c, - * Copyright (C) 2006 Thumtronics Pty Ltd. - * Ben Williamson - * - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -MODULE_AUTHOR("Ben Williamson"); -MODULE_LICENSE("GPL v2"); - -static const char f_midi_shortname[] = "f_midi"; -static const char f_midi_longname[] = "MIDI Gadget"; - -/* - * We can only handle 16 cables on one single endpoint, as cable numbers are - * stored in 4-bit fields. And as the interface currently only holds one - * single endpoint, this is the maximum number of ports we can allow. - */ -#define MAX_PORTS 16 - -/* - * This is a gadget, and the IN/OUT naming is from the host's perspective. - * USB -> OUT endpoint -> rawmidi - * USB <- IN endpoint <- rawmidi - */ -struct gmidi_in_port { - struct f_midi *midi; - int active; - uint8_t cable; - uint8_t state; -#define STATE_UNKNOWN 0 -#define STATE_1PARAM 1 -#define STATE_2PARAM_1 2 -#define STATE_2PARAM_2 3 -#define STATE_SYSEX_0 4 -#define STATE_SYSEX_1 5 -#define STATE_SYSEX_2 6 - uint8_t data[2]; -}; - -struct f_midi { - struct usb_function func; - struct usb_gadget *gadget; - struct usb_ep *in_ep, *out_ep; - struct snd_card *card; - struct snd_rawmidi *rmidi; - - struct snd_rawmidi_substream *in_substream[MAX_PORTS]; - struct snd_rawmidi_substream *out_substream[MAX_PORTS]; - struct gmidi_in_port *in_port[MAX_PORTS]; - - unsigned long out_triggered; - struct tasklet_struct tasklet; - unsigned int in_ports; - unsigned int out_ports; - int index; - char *id; - unsigned int buflen, qlen; -}; - -static inline struct f_midi *func_to_midi(struct usb_function *f) -{ - return container_of(f, struct f_midi, func); -} - -static void f_midi_transmit(struct f_midi *midi, struct usb_request *req); - -DECLARE_UAC_AC_HEADER_DESCRIPTOR(1); -DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1); -DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(16); - -/* 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, - /* .bInterfaceNumber = DYNAMIC */ - /* .bNumEndpoints = DYNAMIC */ - .bInterfaceClass = USB_CLASS_AUDIO, - .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, - /* .iInterface = DYNAMIC */ -}; - -/* B.3.2 Class-Specific AC Interface Descriptor */ -static struct uac1_ac_header_descriptor_1 ac_header_desc __initdata = { - .bLength = UAC_DT_AC_HEADER_SIZE(1), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = USB_MS_HEADER, - .bcdADC = cpu_to_le16(0x0100), - .wTotalLength = cpu_to_le16(UAC_DT_AC_HEADER_SIZE(1)), - .bInCollection = 1, - /* .baInterfaceNr = DYNAMIC */ -}; - -/* B.4.1 Standard MS Interface Descriptor */ -static struct usb_interface_descriptor ms_interface_desc __initdata = { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - /* .bInterfaceNumber = DYNAMIC */ - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_AUDIO, - .bInterfaceSubClass = USB_SUBCLASS_MIDISTREAMING, - /* .iInterface = DYNAMIC */ -}; - -/* B.4.2 Class-Specific MS Interface Descriptor */ -static struct usb_ms_header_descriptor ms_header_desc __initdata = { - .bLength = USB_DT_MS_HEADER_SIZE, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = USB_MS_HEADER, - .bcdMSC = cpu_to_le16(0x0100), - /* .wTotalLength = DYNAMIC */ -}; - -/* B.5.1 Standard Bulk OUT Endpoint Descriptor */ -static struct usb_endpoint_descriptor bulk_out_desc = { - .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -/* B.5.2 Class-specific MS Bulk OUT Endpoint Descriptor */ -static struct usb_ms_endpoint_descriptor_16 ms_out_desc = { - /* .bLength = DYNAMIC */ - .bDescriptorType = USB_DT_CS_ENDPOINT, - .bDescriptorSubtype = USB_MS_GENERAL, - /* .bNumEmbMIDIJack = DYNAMIC */ - /* .baAssocJackID = DYNAMIC */ -}; - -/* B.6.1 Standard Bulk IN Endpoint Descriptor */ -static struct usb_endpoint_descriptor bulk_in_desc = { - .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -/* B.6.2 Class-specific MS Bulk IN Endpoint Descriptor */ -static struct usb_ms_endpoint_descriptor_16 ms_in_desc = { - /* .bLength = DYNAMIC */ - .bDescriptorType = USB_DT_CS_ENDPOINT, - .bDescriptorSubtype = USB_MS_GENERAL, - /* .bNumEmbMIDIJack = DYNAMIC */ - /* .baAssocJackID = DYNAMIC */ -}; - -/* string IDs are assigned dynamically */ - -#define STRING_FUNC_IDX 0 - -static struct usb_string midi_string_defs[] = { - [STRING_FUNC_IDX].s = "MIDI function", - { } /* end of list */ -}; - -static struct usb_gadget_strings midi_stringtab = { - .language = 0x0409, /* en-us */ - .strings = midi_string_defs, -}; - -static struct usb_gadget_strings *midi_strings[] = { - &midi_stringtab, - NULL, -}; - -static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length) -{ - struct usb_request *req; - - req = usb_ep_alloc_request(ep, GFP_ATOMIC); - if (req) { - req->length = length; - req->buf = kmalloc(length, GFP_ATOMIC); - if (!req->buf) { - usb_ep_free_request(ep, req); - req = NULL; - } - } - return req; -} - -static void free_ep_req(struct usb_ep *ep, struct usb_request *req) -{ - kfree(req->buf); - usb_ep_free_request(ep, req); -} - -static const uint8_t f_midi_cin_length[] = { - 0, 0, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1 -}; - -/* - * Receives a chunk of MIDI data. - */ -static void f_midi_read_data(struct usb_ep *ep, int cable, - uint8_t *data, int length) -{ - struct f_midi *midi = ep->driver_data; - struct snd_rawmidi_substream *substream = midi->out_substream[cable]; - - if (!substream) - /* Nobody is listening - throw it on the floor. */ - return; - - if (!test_bit(cable, &midi->out_triggered)) - return; - - snd_rawmidi_receive(substream, data, length); -} - -static void f_midi_handle_out_data(struct usb_ep *ep, struct usb_request *req) -{ - unsigned int i; - u8 *buf = req->buf; - - for (i = 0; i + 3 < req->actual; i += 4) - if (buf[i] != 0) { - int cable = buf[i] >> 4; - int length = f_midi_cin_length[buf[i] & 0x0f]; - f_midi_read_data(ep, cable, &buf[i + 1], length); - } -} - -static void -f_midi_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct f_midi *midi = ep->driver_data; - struct usb_composite_dev *cdev = midi->func.config->cdev; - int status = req->status; - - switch (status) { - case 0: /* normal completion */ - if (ep == midi->out_ep) { - /* We received stuff. req is queued again, below */ - f_midi_handle_out_data(ep, req); - } else if (ep == midi->in_ep) { - /* Our transmit completed. See if there's more to go. - * f_midi_transmit eats req, don't queue it again. */ - f_midi_transmit(midi, req); - return; - } - break; - - /* this endpoint is normally active while we're configured */ - case -ECONNABORTED: /* hardware forced ep reset */ - case -ECONNRESET: /* request dequeued */ - case -ESHUTDOWN: /* disconnect from host */ - VDBG(cdev, "%s gone (%d), %d/%d\n", ep->name, status, - req->actual, req->length); - if (ep == midi->out_ep) - f_midi_handle_out_data(ep, req); - - free_ep_req(ep, req); - return; - - case -EOVERFLOW: /* buffer overrun on read means that - * we didn't provide a big enough buffer. - */ - default: - DBG(cdev, "%s complete --> %d, %d/%d\n", ep->name, - status, req->actual, req->length); - break; - case -EREMOTEIO: /* short read */ - break; - } - - status = usb_ep_queue(ep, req, GFP_ATOMIC); - if (status) { - ERROR(cdev, "kill %s: resubmit %d bytes --> %d\n", - ep->name, req->length, status); - usb_ep_set_halt(ep); - /* FIXME recover later ... somehow */ - } -} - -static int f_midi_start_ep(struct f_midi *midi, - struct usb_function *f, - struct usb_ep *ep) -{ - int err; - struct usb_composite_dev *cdev = f->config->cdev; - - if (ep->driver_data) - usb_ep_disable(ep); - - err = config_ep_by_speed(midi->gadget, f, ep); - if (err) { - ERROR(cdev, "can't configure %s: %d\n", ep->name, err); - return err; - } - - err = usb_ep_enable(ep); - if (err) { - ERROR(cdev, "can't start %s: %d\n", ep->name, err); - return err; - } - - ep->driver_data = midi; - - return 0; -} - -static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt) -{ - struct f_midi *midi = func_to_midi(f); - struct usb_composite_dev *cdev = f->config->cdev; - unsigned i; - int err; - - err = f_midi_start_ep(midi, f, midi->in_ep); - if (err) - return err; - - err = f_midi_start_ep(midi, f, midi->out_ep); - if (err) - return err; - - if (midi->out_ep->driver_data) - usb_ep_disable(midi->out_ep); - - err = config_ep_by_speed(midi->gadget, f, midi->out_ep); - if (err) { - ERROR(cdev, "can't configure %s: %d\n", - midi->out_ep->name, err); - return err; - } - - err = usb_ep_enable(midi->out_ep); - if (err) { - ERROR(cdev, "can't start %s: %d\n", - midi->out_ep->name, err); - return err; - } - - midi->out_ep->driver_data = midi; - - /* allocate a bunch of read buffers and queue them all at once. */ - for (i = 0; i < midi->qlen && err == 0; i++) { - struct usb_request *req = - alloc_ep_req(midi->out_ep, midi->buflen); - if (req == NULL) - return -ENOMEM; - - req->complete = f_midi_complete; - err = usb_ep_queue(midi->out_ep, req, GFP_ATOMIC); - if (err) { - ERROR(midi, "%s queue req: %d\n", - midi->out_ep->name, err); - } - } - - return 0; -} - -static void f_midi_disable(struct usb_function *f) -{ - struct f_midi *midi = func_to_midi(f); - struct usb_composite_dev *cdev = f->config->cdev; - - DBG(cdev, "disable\n"); - - /* - * just disable endpoints, forcing completion of pending i/o. - * all our completion handlers free their requests in this case. - */ - usb_ep_disable(midi->in_ep); - usb_ep_disable(midi->out_ep); -} - -static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f) -{ - struct usb_composite_dev *cdev = f->config->cdev; - struct f_midi *midi = func_to_midi(f); - struct snd_card *card; - - DBG(cdev, "unbind\n"); - - /* just to be sure */ - f_midi_disable(f); - - card = midi->card; - midi->card = NULL; - if (card) - snd_card_free(card); - - kfree(midi->id); - midi->id = NULL; - - usb_free_descriptors(f->descriptors); - kfree(midi); -} - -static int f_midi_snd_free(struct snd_device *device) -{ - return 0; -} - -static void f_midi_transmit_packet(struct usb_request *req, uint8_t p0, - uint8_t p1, uint8_t p2, uint8_t p3) -{ - unsigned length = req->length; - u8 *buf = (u8 *)req->buf + length; - - buf[0] = p0; - buf[1] = p1; - buf[2] = p2; - buf[3] = p3; - req->length = length + 4; -} - -/* - * Converts MIDI commands to USB MIDI packets. - */ -static void f_midi_transmit_byte(struct usb_request *req, - struct gmidi_in_port *port, uint8_t b) -{ - uint8_t p0 = port->cable << 4; - - if (b >= 0xf8) { - f_midi_transmit_packet(req, p0 | 0x0f, b, 0, 0); - } else if (b >= 0xf0) { - switch (b) { - case 0xf0: - port->data[0] = b; - port->state = STATE_SYSEX_1; - break; - case 0xf1: - case 0xf3: - port->data[0] = b; - port->state = STATE_1PARAM; - break; - case 0xf2: - port->data[0] = b; - port->state = STATE_2PARAM_1; - break; - case 0xf4: - case 0xf5: - port->state = STATE_UNKNOWN; - break; - case 0xf6: - f_midi_transmit_packet(req, p0 | 0x05, 0xf6, 0, 0); - port->state = STATE_UNKNOWN; - break; - case 0xf7: - switch (port->state) { - case STATE_SYSEX_0: - f_midi_transmit_packet(req, - p0 | 0x05, 0xf7, 0, 0); - break; - case STATE_SYSEX_1: - f_midi_transmit_packet(req, - p0 | 0x06, port->data[0], 0xf7, 0); - break; - case STATE_SYSEX_2: - f_midi_transmit_packet(req, - p0 | 0x07, port->data[0], - port->data[1], 0xf7); - break; - } - port->state = STATE_UNKNOWN; - break; - } - } else if (b >= 0x80) { - port->data[0] = b; - if (b >= 0xc0 && b <= 0xdf) - port->state = STATE_1PARAM; - else - port->state = STATE_2PARAM_1; - } else { /* b < 0x80 */ - switch (port->state) { - case STATE_1PARAM: - if (port->data[0] < 0xf0) { - p0 |= port->data[0] >> 4; - } else { - p0 |= 0x02; - port->state = STATE_UNKNOWN; - } - f_midi_transmit_packet(req, p0, port->data[0], b, 0); - break; - case STATE_2PARAM_1: - port->data[1] = b; - port->state = STATE_2PARAM_2; - break; - case STATE_2PARAM_2: - if (port->data[0] < 0xf0) { - p0 |= port->data[0] >> 4; - port->state = STATE_2PARAM_1; - } else { - p0 |= 0x03; - port->state = STATE_UNKNOWN; - } - f_midi_transmit_packet(req, - p0, port->data[0], port->data[1], b); - break; - case STATE_SYSEX_0: - port->data[0] = b; - port->state = STATE_SYSEX_1; - break; - case STATE_SYSEX_1: - port->data[1] = b; - port->state = STATE_SYSEX_2; - break; - case STATE_SYSEX_2: - f_midi_transmit_packet(req, - p0 | 0x04, port->data[0], port->data[1], b); - port->state = STATE_SYSEX_0; - break; - } - } -} - -static void f_midi_transmit(struct f_midi *midi, struct usb_request *req) -{ - struct usb_ep *ep = midi->in_ep; - int i; - - if (!ep) - return; - - if (!req) - req = alloc_ep_req(ep, midi->buflen); - - if (!req) { - ERROR(midi, "gmidi_transmit: alloc_ep_request failed\n"); - return; - } - req->length = 0; - req->complete = f_midi_complete; - - for (i = 0; i < MAX_PORTS; i++) { - struct gmidi_in_port *port = midi->in_port[i]; - struct snd_rawmidi_substream *substream = midi->in_substream[i]; - - if (!port || !port->active || !substream) - continue; - - while (req->length + 3 < midi->buflen) { - uint8_t b; - if (snd_rawmidi_transmit(substream, &b, 1) != 1) { - port->active = 0; - break; - } - f_midi_transmit_byte(req, port, b); - } - } - - if (req->length > 0) - usb_ep_queue(ep, req, GFP_ATOMIC); - else - free_ep_req(ep, req); -} - -static void f_midi_in_tasklet(unsigned long data) -{ - struct f_midi *midi = (struct f_midi *) data; - f_midi_transmit(midi, NULL); -} - -static int f_midi_in_open(struct snd_rawmidi_substream *substream) -{ - struct f_midi *midi = substream->rmidi->private_data; - - if (!midi->in_port[substream->number]) - return -EINVAL; - - VDBG(midi, "%s()\n", __func__); - midi->in_substream[substream->number] = substream; - midi->in_port[substream->number]->state = STATE_UNKNOWN; - return 0; -} - -static int f_midi_in_close(struct snd_rawmidi_substream *substream) -{ - struct f_midi *midi = substream->rmidi->private_data; - - VDBG(midi, "%s()\n", __func__); - return 0; -} - -static void f_midi_in_trigger(struct snd_rawmidi_substream *substream, int up) -{ - struct f_midi *midi = substream->rmidi->private_data; - - if (!midi->in_port[substream->number]) - return; - - VDBG(midi, "%s() %d\n", __func__, up); - midi->in_port[substream->number]->active = up; - if (up) - tasklet_hi_schedule(&midi->tasklet); -} - -static int f_midi_out_open(struct snd_rawmidi_substream *substream) -{ - struct f_midi *midi = substream->rmidi->private_data; - - if (substream->number >= MAX_PORTS) - return -EINVAL; - - VDBG(midi, "%s()\n", __func__); - midi->out_substream[substream->number] = substream; - return 0; -} - -static int f_midi_out_close(struct snd_rawmidi_substream *substream) -{ - struct f_midi *midi = substream->rmidi->private_data; - - VDBG(midi, "%s()\n", __func__); - return 0; -} - -static void f_midi_out_trigger(struct snd_rawmidi_substream *substream, int up) -{ - struct f_midi *midi = substream->rmidi->private_data; - - VDBG(midi, "%s()\n", __func__); - - if (up) - set_bit(substream->number, &midi->out_triggered); - else - clear_bit(substream->number, &midi->out_triggered); -} - -static struct snd_rawmidi_ops gmidi_in_ops = { - .open = f_midi_in_open, - .close = f_midi_in_close, - .trigger = f_midi_in_trigger, -}; - -static struct snd_rawmidi_ops gmidi_out_ops = { - .open = f_midi_out_open, - .close = f_midi_out_close, - .trigger = f_midi_out_trigger -}; - -/* register as a sound "card" */ -static int f_midi_register_card(struct f_midi *midi) -{ - struct snd_card *card; - struct snd_rawmidi *rmidi; - int err; - static struct snd_device_ops ops = { - .dev_free = f_midi_snd_free, - }; - - err = snd_card_create(midi->index, midi->id, THIS_MODULE, 0, &card); - if (err < 0) { - ERROR(midi, "snd_card_create() failed\n"); - goto fail; - } - midi->card = card; - - err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, midi, &ops); - if (err < 0) { - ERROR(midi, "snd_device_new() failed: error %d\n", err); - goto fail; - } - - strcpy(card->driver, f_midi_longname); - strcpy(card->longname, f_midi_longname); - strcpy(card->shortname, f_midi_shortname); - - /* Set up rawmidi */ - snd_component_add(card, "MIDI"); - err = snd_rawmidi_new(card, card->longname, 0, - midi->out_ports, midi->in_ports, &rmidi); - if (err < 0) { - ERROR(midi, "snd_rawmidi_new() failed: error %d\n", err); - goto fail; - } - midi->rmidi = rmidi; - strcpy(rmidi->name, card->shortname); - rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | - SNDRV_RAWMIDI_INFO_INPUT | - SNDRV_RAWMIDI_INFO_DUPLEX; - rmidi->private_data = midi; - - /* - * Yes, rawmidi OUTPUT = USB IN, and rawmidi INPUT = USB OUT. - * It's an upside-down world being a gadget. - */ - snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &gmidi_in_ops); - snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &gmidi_out_ops); - - snd_card_set_dev(card, &midi->gadget->dev); - - /* register it - we're ready to go */ - err = snd_card_register(card); - if (err < 0) { - ERROR(midi, "snd_card_register() failed\n"); - goto fail; - } - - VDBG(midi, "%s() finished ok\n", __func__); - return 0; - -fail: - if (midi->card) { - snd_card_free(midi->card); - midi->card = NULL; - } - return err; -} - -/* MIDI function driver setup/binding */ - -static int __init -f_midi_bind(struct usb_configuration *c, struct usb_function *f) -{ - struct usb_descriptor_header **midi_function; - struct usb_midi_in_jack_descriptor jack_in_ext_desc[MAX_PORTS]; - struct usb_midi_in_jack_descriptor jack_in_emb_desc[MAX_PORTS]; - struct usb_midi_out_jack_descriptor_1 jack_out_ext_desc[MAX_PORTS]; - struct usb_midi_out_jack_descriptor_1 jack_out_emb_desc[MAX_PORTS]; - struct usb_composite_dev *cdev = c->cdev; - struct f_midi *midi = func_to_midi(f); - int status, n, jack = 1, i = 0; - - /* maybe allocate device-global string ID */ - if (midi_string_defs[0].id == 0) { - status = usb_string_id(c->cdev); - if (status < 0) - goto fail; - midi_string_defs[0].id = status; - } - - /* We have two interfaces, AudioControl and MIDIStreaming */ - 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; - ms_interface_desc.bInterfaceNumber = status; - ac_header_desc.baInterfaceNr[0] = status; - - status = -ENODEV; - - /* allocate instance-specific endpoints */ - midi->in_ep = usb_ep_autoconfig(cdev->gadget, &bulk_in_desc); - if (!midi->in_ep) - goto fail; - midi->in_ep->driver_data = cdev; /* claim */ - - midi->out_ep = usb_ep_autoconfig(cdev->gadget, &bulk_out_desc); - if (!midi->out_ep) - goto fail; - midi->out_ep->driver_data = cdev; /* claim */ - - /* allocate temporary function list */ - midi_function = kcalloc((MAX_PORTS * 4) + 9, sizeof(*midi_function), - GFP_KERNEL); - if (!midi_function) { - status = -ENOMEM; - goto fail; - } - - /* - * construct the function's descriptor set. As the number of - * input and output MIDI ports is configurable, we have to do - * it that way. - */ - - /* add the headers - these are always the same */ - midi_function[i++] = (struct usb_descriptor_header *) &ac_interface_desc; - midi_function[i++] = (struct usb_descriptor_header *) &ac_header_desc; - midi_function[i++] = (struct usb_descriptor_header *) &ms_interface_desc; - - /* calculate the header's wTotalLength */ - n = USB_DT_MS_HEADER_SIZE - + (midi->in_ports + midi->out_ports) * - (USB_DT_MIDI_IN_SIZE + USB_DT_MIDI_OUT_SIZE(1)); - ms_header_desc.wTotalLength = cpu_to_le16(n); - - midi_function[i++] = (struct usb_descriptor_header *) &ms_header_desc; - - /* configure the external IN jacks, each linked to an embedded OUT jack */ - for (n = 0; n < midi->in_ports; n++) { - struct usb_midi_in_jack_descriptor *in_ext = &jack_in_ext_desc[n]; - struct usb_midi_out_jack_descriptor_1 *out_emb = &jack_out_emb_desc[n]; - - in_ext->bLength = USB_DT_MIDI_IN_SIZE; - in_ext->bDescriptorType = USB_DT_CS_INTERFACE; - in_ext->bDescriptorSubtype = USB_MS_MIDI_IN_JACK; - in_ext->bJackType = USB_MS_EXTERNAL; - in_ext->bJackID = jack++; - in_ext->iJack = 0; - midi_function[i++] = (struct usb_descriptor_header *) in_ext; - - out_emb->bLength = USB_DT_MIDI_OUT_SIZE(1); - out_emb->bDescriptorType = USB_DT_CS_INTERFACE; - out_emb->bDescriptorSubtype = USB_MS_MIDI_OUT_JACK; - out_emb->bJackType = USB_MS_EMBEDDED; - out_emb->bJackID = jack++; - out_emb->bNrInputPins = 1; - out_emb->pins[0].baSourcePin = 1; - out_emb->pins[0].baSourceID = in_ext->bJackID; - out_emb->iJack = 0; - midi_function[i++] = (struct usb_descriptor_header *) out_emb; - - /* link it to the endpoint */ - ms_in_desc.baAssocJackID[n] = out_emb->bJackID; - } - - /* configure the external OUT jacks, each linked to an embedded IN jack */ - for (n = 0; n < midi->out_ports; n++) { - struct usb_midi_in_jack_descriptor *in_emb = &jack_in_emb_desc[n]; - struct usb_midi_out_jack_descriptor_1 *out_ext = &jack_out_ext_desc[n]; - - in_emb->bLength = USB_DT_MIDI_IN_SIZE; - in_emb->bDescriptorType = USB_DT_CS_INTERFACE; - in_emb->bDescriptorSubtype = USB_MS_MIDI_IN_JACK; - in_emb->bJackType = USB_MS_EMBEDDED; - in_emb->bJackID = jack++; - in_emb->iJack = 0; - midi_function[i++] = (struct usb_descriptor_header *) in_emb; - - out_ext->bLength = USB_DT_MIDI_OUT_SIZE(1); - out_ext->bDescriptorType = USB_DT_CS_INTERFACE; - out_ext->bDescriptorSubtype = USB_MS_MIDI_OUT_JACK; - out_ext->bJackType = USB_MS_EXTERNAL; - out_ext->bJackID = jack++; - out_ext->bNrInputPins = 1; - out_ext->iJack = 0; - out_ext->pins[0].baSourceID = in_emb->bJackID; - out_ext->pins[0].baSourcePin = 1; - midi_function[i++] = (struct usb_descriptor_header *) out_ext; - - /* link it to the endpoint */ - ms_out_desc.baAssocJackID[n] = in_emb->bJackID; - } - - /* configure the endpoint descriptors ... */ - ms_out_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->in_ports); - ms_out_desc.bNumEmbMIDIJack = midi->in_ports; - - ms_in_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->out_ports); - ms_in_desc.bNumEmbMIDIJack = midi->out_ports; - - /* ... and add them to the list */ - midi_function[i++] = (struct usb_descriptor_header *) &bulk_out_desc; - midi_function[i++] = (struct usb_descriptor_header *) &ms_out_desc; - midi_function[i++] = (struct usb_descriptor_header *) &bulk_in_desc; - midi_function[i++] = (struct usb_descriptor_header *) &ms_in_desc; - midi_function[i++] = NULL; - - /* - * support 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; - bulk_in_desc.wMaxPacketSize = cpu_to_le16(512); - bulk_out_desc.wMaxPacketSize = cpu_to_le16(512); - f->hs_descriptors = usb_copy_descriptors(midi_function); - } else { - f->descriptors = usb_copy_descriptors(midi_function); - } - - kfree(midi_function); - - return 0; - -fail: - /* we might as well release our claims on endpoints */ - if (midi->out_ep) - midi->out_ep->driver_data = NULL; - if (midi->in_ep) - midi->in_ep->driver_data = NULL; - - ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); - - return status; -} - -/** - * f_midi_bind_config - add USB MIDI function to a configuration - * @c: the configuration to supcard the USB audio function - * @index: the soundcard index to use for the ALSA device creation - * @id: the soundcard id to use for the ALSA device creation - * @buflen: the buffer length to use - * @qlen the number of read requests to pre-allocate - * Context: single threaded during gadget setup - * - * Returns zero on success, else negative errno. - */ -int __init f_midi_bind_config(struct usb_configuration *c, - int index, char *id, - unsigned int in_ports, - unsigned int out_ports, - unsigned int buflen, - unsigned int qlen) -{ - struct f_midi *midi; - int status, i; - - /* sanity check */ - if (in_ports > MAX_PORTS || out_ports > MAX_PORTS) - return -EINVAL; - - /* allocate and initialize one new instance */ - midi = kzalloc(sizeof *midi, GFP_KERNEL); - if (!midi) { - status = -ENOMEM; - goto fail; - } - - for (i = 0; i < in_ports; i++) { - struct gmidi_in_port *port = kzalloc(sizeof(*port), GFP_KERNEL); - if (!port) { - status = -ENOMEM; - goto setup_fail; - } - - port->midi = midi; - port->active = 0; - port->cable = i; - midi->in_port[i] = port; - } - - midi->gadget = c->cdev->gadget; - tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi); - - /* set up ALSA midi devices */ - midi->in_ports = in_ports; - midi->out_ports = out_ports; - status = f_midi_register_card(midi); - if (status < 0) - goto setup_fail; - - midi->func.name = "gmidi function"; - midi->func.strings = midi_strings; - midi->func.bind = f_midi_bind; - midi->func.unbind = f_midi_unbind; - midi->func.set_alt = f_midi_set_alt; - midi->func.disable = f_midi_disable; - - midi->id = kstrdup(id, GFP_KERNEL); - midi->index = index; - midi->buflen = buflen; - midi->qlen = qlen; - - status = usb_add_function(c, &midi->func); - if (status) - goto setup_fail; - - return 0; - -setup_fail: - for (--i; i >= 0; i--) - kfree(midi->in_port[i]); - kfree(midi); -fail: - return status; -} - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_mtp.c b/ANDROID_3.4.5/drivers/usb/gadget/f_mtp.c deleted file mode 100644 index 6279bfb0..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_mtp.c +++ /dev/null @@ -1,1295 +0,0 @@ -/* - * Gadget Function Driver for MTP - * - * Copyright (C) 2010 Google, Inc. - * Author: Mike Lockwood - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - * - */ - -/* #define DEBUG */ -/* #define VERBOSE_DEBUG */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#define MTP_BULK_BUFFER_SIZE 16384 -#define INTR_BUFFER_SIZE 28 - -/* String IDs */ -#define INTERFACE_STRING_INDEX 0 - -/* values for mtp_dev.state */ -#define STATE_OFFLINE 0 /* initial state, disconnected */ -#define STATE_READY 1 /* ready for userspace calls */ -#define STATE_BUSY 2 /* processing userspace calls */ -#define STATE_CANCELED 3 /* transaction canceled by host */ -#define STATE_ERROR 4 /* error from completion routine */ - -/* number of tx and rx requests to allocate */ -#define TX_REQ_MAX 4 -#define RX_REQ_MAX 2 -#define INTR_REQ_MAX 5 - -/* ID for Microsoft MTP OS String */ -#define MTP_OS_STRING_ID 0xEE - -/* MTP class reqeusts */ -#define MTP_REQ_CANCEL 0x64 -#define MTP_REQ_GET_EXT_EVENT_DATA 0x65 -#define MTP_REQ_RESET 0x66 -#define MTP_REQ_GET_DEVICE_STATUS 0x67 - -/* constants for device status */ -#define MTP_RESPONSE_OK 0x2001 -#define MTP_RESPONSE_DEVICE_BUSY 0x2019 - -static const char mtp_shortname[] = "mtp_usb"; - -struct mtp_dev { - struct usb_function function; - struct usb_composite_dev *cdev; - spinlock_t lock; - - struct usb_ep *ep_in; - struct usb_ep *ep_out; - struct usb_ep *ep_intr; - - int state; - - /* synchronize access to our device file */ - atomic_t open_excl; - /* to enforce only one ioctl at a time */ - atomic_t ioctl_excl; - - struct list_head tx_idle; - struct list_head intr_idle; - - wait_queue_head_t read_wq; - wait_queue_head_t write_wq; - wait_queue_head_t intr_wq; - struct usb_request *rx_req[RX_REQ_MAX]; - int rx_done; - - /* for processing MTP_SEND_FILE, MTP_RECEIVE_FILE and - * MTP_SEND_FILE_WITH_HEADER ioctls on a work queue - */ - struct workqueue_struct *wq; - struct work_struct send_file_work; - struct work_struct receive_file_work; - struct file *xfer_file; - loff_t xfer_file_offset; - int64_t xfer_file_length; - unsigned xfer_send_header; - uint16_t xfer_command; - uint32_t xfer_transaction_id; - int xfer_result; -}; - -static struct usb_interface_descriptor mtp_interface_desc = { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, - .bNumEndpoints = 3, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = USB_SUBCLASS_VENDOR_SPEC, - .bInterfaceProtocol = 0, -}; - -static struct usb_interface_descriptor ptp_interface_desc = { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, - .bNumEndpoints = 3, - .bInterfaceClass = USB_CLASS_STILL_IMAGE, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 1, -}; - -static struct usb_endpoint_descriptor mtp_highspeed_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(512), -}; - -static struct usb_endpoint_descriptor mtp_highspeed_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(512), -}; - -static struct usb_endpoint_descriptor mtp_fullspeed_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_endpoint_descriptor mtp_fullspeed_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_endpoint_descriptor mtp_intr_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = __constant_cpu_to_le16(INTR_BUFFER_SIZE), - .bInterval = 6, -}; - -static struct usb_descriptor_header *fs_mtp_descs[] = { - (struct usb_descriptor_header *) &mtp_interface_desc, - (struct usb_descriptor_header *) &mtp_fullspeed_in_desc, - (struct usb_descriptor_header *) &mtp_fullspeed_out_desc, - (struct usb_descriptor_header *) &mtp_intr_desc, - NULL, -}; - -static struct usb_descriptor_header *hs_mtp_descs[] = { - (struct usb_descriptor_header *) &mtp_interface_desc, - (struct usb_descriptor_header *) &mtp_highspeed_in_desc, - (struct usb_descriptor_header *) &mtp_highspeed_out_desc, - (struct usb_descriptor_header *) &mtp_intr_desc, - NULL, -}; - -static struct usb_descriptor_header *fs_ptp_descs[] = { - (struct usb_descriptor_header *) &ptp_interface_desc, - (struct usb_descriptor_header *) &mtp_fullspeed_in_desc, - (struct usb_descriptor_header *) &mtp_fullspeed_out_desc, - (struct usb_descriptor_header *) &mtp_intr_desc, - NULL, -}; - -static struct usb_descriptor_header *hs_ptp_descs[] = { - (struct usb_descriptor_header *) &ptp_interface_desc, - (struct usb_descriptor_header *) &mtp_highspeed_in_desc, - (struct usb_descriptor_header *) &mtp_highspeed_out_desc, - (struct usb_descriptor_header *) &mtp_intr_desc, - NULL, -}; - -static struct usb_string mtp_string_defs[] = { - /* Naming interface "MTP" so libmtp will recognize us */ - [INTERFACE_STRING_INDEX].s = "MTP", - { }, /* end of list */ -}; - -static struct usb_gadget_strings mtp_string_table = { - .language = 0x0409, /* en-US */ - .strings = mtp_string_defs, -}; - -static struct usb_gadget_strings *mtp_strings[] = { - &mtp_string_table, - NULL, -}; - -/* Microsoft MTP OS String */ -static u8 mtp_os_string[] = { - 18, /* sizeof(mtp_os_string) */ - USB_DT_STRING, - /* Signature field: "MSFT100" */ - 'M', 0, 'S', 0, 'F', 0, 'T', 0, '1', 0, '0', 0, '0', 0, - /* vendor code */ - 1, - /* padding */ - 0 -}; - -/* Microsoft Extended Configuration Descriptor Header Section */ -struct mtp_ext_config_desc_header { - __le32 dwLength; - __u16 bcdVersion; - __le16 wIndex; - __u8 bCount; - __u8 reserved[7]; -}; - -/* Microsoft Extended Configuration Descriptor Function Section */ -struct mtp_ext_config_desc_function { - __u8 bFirstInterfaceNumber; - __u8 bInterfaceCount; - __u8 compatibleID[8]; - __u8 subCompatibleID[8]; - __u8 reserved[6]; -}; - -/* MTP Extended Configuration Descriptor */ -struct { - struct mtp_ext_config_desc_header header; - struct mtp_ext_config_desc_function function; -} mtp_ext_config_desc = { - .header = { - .dwLength = __constant_cpu_to_le32(sizeof(mtp_ext_config_desc)), - .bcdVersion = __constant_cpu_to_le16(0x0100), - .wIndex = __constant_cpu_to_le16(4), - .bCount = __constant_cpu_to_le16(1), - }, - .function = { - .bFirstInterfaceNumber = 0, - .bInterfaceCount = 1, - .compatibleID = { 'M', 'T', 'P' }, - }, -}; - -struct mtp_device_status { - __le16 wLength; - __le16 wCode; -}; - -/* temporary variable used between mtp_open() and mtp_gadget_bind() */ -static struct mtp_dev *_mtp_dev; - -static inline struct mtp_dev *func_to_mtp(struct usb_function *f) -{ - return container_of(f, struct mtp_dev, function); -} - -static struct usb_request *mtp_request_new(struct usb_ep *ep, int buffer_size) -{ - struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL); - if (!req) - return NULL; - - /* now allocate buffers for the requests */ - req->buf = kmalloc(buffer_size, GFP_KERNEL); - if (!req->buf) { - usb_ep_free_request(ep, req); - return NULL; - } - - return req; -} - -static void mtp_request_free(struct usb_request *req, struct usb_ep *ep) -{ - if (req) { - kfree(req->buf); - usb_ep_free_request(ep, req); - } -} - -static inline int mtp_lock(atomic_t *excl) -{ - if (atomic_inc_return(excl) == 1) { - return 0; - } else { - atomic_dec(excl); - return -1; - } -} - -static inline void mtp_unlock(atomic_t *excl) -{ - atomic_dec(excl); -} - -/* add a request to the tail of a list */ -static void mtp_req_put(struct mtp_dev *dev, struct list_head *head, - struct usb_request *req) -{ - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - list_add_tail(&req->list, head); - spin_unlock_irqrestore(&dev->lock, flags); -} - -/* remove a request from the head of a list */ -static struct usb_request -*mtp_req_get(struct mtp_dev *dev, struct list_head *head) -{ - unsigned long flags; - struct usb_request *req; - - spin_lock_irqsave(&dev->lock, flags); - if (list_empty(head)) { - req = 0; - } else { - req = list_first_entry(head, struct usb_request, list); - list_del(&req->list); - } - spin_unlock_irqrestore(&dev->lock, flags); - return req; -} - -static void mtp_complete_in(struct usb_ep *ep, struct usb_request *req) -{ - struct mtp_dev *dev = _mtp_dev; - - if (req->status != 0) - dev->state = STATE_ERROR; - - mtp_req_put(dev, &dev->tx_idle, req); - - wake_up(&dev->write_wq); -} - -static void mtp_complete_out(struct usb_ep *ep, struct usb_request *req) -{ - struct mtp_dev *dev = _mtp_dev; - - dev->rx_done = 1; - if (req->status != 0) - dev->state = STATE_ERROR; - - wake_up(&dev->read_wq); -} - -static void mtp_complete_intr(struct usb_ep *ep, struct usb_request *req) -{ - struct mtp_dev *dev = _mtp_dev; - - if (req->status != 0) - dev->state = STATE_ERROR; - - mtp_req_put(dev, &dev->intr_idle, req); - - wake_up(&dev->intr_wq); -} - -static int mtp_create_bulk_endpoints(struct mtp_dev *dev, - struct usb_endpoint_descriptor *in_desc, - struct usb_endpoint_descriptor *out_desc, - struct usb_endpoint_descriptor *intr_desc) -{ - struct usb_composite_dev *cdev = dev->cdev; - struct usb_request *req; - struct usb_ep *ep; - int i; - - DBG(cdev, "create_bulk_endpoints dev: %p\n", dev); - - ep = usb_ep_autoconfig(cdev->gadget, in_desc); - if (!ep) { - DBG(cdev, "usb_ep_autoconfig for ep_in failed\n"); - return -ENODEV; - } - DBG(cdev, "usb_ep_autoconfig for ep_in got %s\n", ep->name); - ep->driver_data = dev; /* claim the endpoint */ - dev->ep_in = ep; - - ep = usb_ep_autoconfig(cdev->gadget, out_desc); - if (!ep) { - DBG(cdev, "usb_ep_autoconfig for ep_out failed\n"); - return -ENODEV; - } - DBG(cdev, "usb_ep_autoconfig for mtp ep_out got %s\n", ep->name); - ep->driver_data = dev; /* claim the endpoint */ - dev->ep_out = ep; - -#if 0 - ep = usb_ep_autoconfig(cdev->gadget, out_desc); - if (!ep) { - DBG(cdev, "usb_ep_autoconfig for ep_out failed\n"); - return -ENODEV; - } - DBG(cdev, "usb_ep_autoconfig for mtp ep_out got %s\n", ep->name); - ep->driver_data = dev; /* claim the endpoint */ - dev->ep_out = ep; -#endif - - ep = usb_ep_autoconfig(cdev->gadget, intr_desc); - if (!ep) { - DBG(cdev, "usb_ep_autoconfig for ep_intr failed\n"); - return -ENODEV; - } - DBG(cdev, "usb_ep_autoconfig for mtp ep_intr got %s\n", ep->name); - ep->driver_data = dev; /* claim the endpoint */ - dev->ep_intr = ep; - - /* now allocate requests for our endpoints */ - for (i = 0; i < TX_REQ_MAX; i++) { - req = mtp_request_new(dev->ep_in, MTP_BULK_BUFFER_SIZE); - if (!req) - goto fail; - req->complete = mtp_complete_in; - mtp_req_put(dev, &dev->tx_idle, req); - } - for (i = 0; i < RX_REQ_MAX; i++) { - req = mtp_request_new(dev->ep_out, MTP_BULK_BUFFER_SIZE); - if (!req) - goto fail; - req->complete = mtp_complete_out; - dev->rx_req[i] = req; - } - for (i = 0; i < INTR_REQ_MAX; i++) { - req = mtp_request_new(dev->ep_intr, INTR_BUFFER_SIZE); - if (!req) - goto fail; - req->complete = mtp_complete_intr; - mtp_req_put(dev, &dev->intr_idle, req); - } - - return 0; - -fail: - printk(KERN_ERR "mtp_bind() could not allocate requests\n"); - return -1; -} - -static ssize_t mtp_read(struct file *fp, char __user *buf, - size_t count, loff_t *pos) -{ - struct mtp_dev *dev = fp->private_data; - struct usb_composite_dev *cdev = dev->cdev; - struct usb_request *req; - int r = count, xfer; - int ret = 0; - - DBG(cdev, "mtp_read(%d)\n", count); - - if (count > MTP_BULK_BUFFER_SIZE) - return -EINVAL; - - /* we will block until we're online */ - DBG(cdev, "mtp_read: waiting for online state\n"); - ret = wait_event_interruptible(dev->read_wq, - dev->state != STATE_OFFLINE); - if (ret < 0) { - r = ret; - if (r == -ERESTARTSYS){ - r = -EIO; - } - - goto done; - } - spin_lock_irq(&dev->lock); - if (dev->state == STATE_CANCELED) { - /* report cancelation to userspace */ - dev->state = STATE_READY; - spin_unlock_irq(&dev->lock); - return -ECANCELED; - } - dev->state = STATE_BUSY; - spin_unlock_irq(&dev->lock); - -requeue_req: - /* queue a request */ - req = dev->rx_req[0]; - req->length = count; - dev->rx_done = 0; - ret = usb_ep_queue(dev->ep_out, req, GFP_KERNEL); - if (ret < 0) { - r = -EIO; - goto done; - } else { - DBG(cdev, "rx %p queue\n", req); - } - - /* wait for a request to complete */ - ret = wait_event_interruptible(dev->read_wq, dev->rx_done); - if (ret < 0) { - r = ret; - if (r == -ERESTARTSYS){ - r = -EIO; - } - - usb_ep_dequeue(dev->ep_out, req); - goto done; - } - if (dev->state == STATE_BUSY) { - /* If we got a 0-len packet, throw it back and try again. */ - if (req->actual == 0) - goto requeue_req; - - DBG(cdev, "rx %p %d\n", req, req->actual); - xfer = (req->actual < count) ? req->actual : count; - r = xfer; - if (copy_to_user(buf, req->buf, xfer)) - r = -EFAULT; - } else - r = -EIO; - -done: - spin_lock_irq(&dev->lock); - if (dev->state == STATE_CANCELED) - r = -ECANCELED; - else if (dev->state != STATE_OFFLINE) - dev->state = STATE_READY; - spin_unlock_irq(&dev->lock); - - DBG(cdev, "mtp_read returning %d\n", r); - return r; -} - -static ssize_t mtp_write(struct file *fp, const char __user *buf, - size_t count, loff_t *pos) -{ - struct mtp_dev *dev = fp->private_data; - struct usb_composite_dev *cdev = dev->cdev; - struct usb_request *req = 0; - int r = count, xfer; - int sendZLP = 0; - int ret; - - DBG(cdev, "mtp_write(%d)\n", count); - - spin_lock_irq(&dev->lock); - if (dev->state == STATE_CANCELED) { - /* report cancelation to userspace */ - dev->state = STATE_READY; - spin_unlock_irq(&dev->lock); - return -ECANCELED; - } - if (dev->state == STATE_OFFLINE) { - spin_unlock_irq(&dev->lock); - return -ENODEV; - } - dev->state = STATE_BUSY; - spin_unlock_irq(&dev->lock); - - /* we need to send a zero length packet to signal the end of transfer - * if the transfer size is aligned to a packet boundary. - */ - if ((count & (dev->ep_in->maxpacket - 1)) == 0) - sendZLP = 1; - - while (count > 0 || sendZLP) { - /* so we exit after sending ZLP */ - if (count == 0) - sendZLP = 0; - - if (dev->state != STATE_BUSY) { - DBG(cdev, "mtp_write dev->error\n"); - r = -EIO; - break; - } - - /* get an idle tx request to use */ - req = 0; - ret = wait_event_interruptible(dev->write_wq, - ((req = mtp_req_get(dev, &dev->tx_idle)) - || dev->state != STATE_BUSY)); - if (!req) { - r = ret; - break; - } - - if (count > MTP_BULK_BUFFER_SIZE) - xfer = MTP_BULK_BUFFER_SIZE; - else - xfer = count; - if (xfer && copy_from_user(req->buf, buf, xfer)) { - r = -EFAULT; - break; - } - - req->length = xfer; - ret = usb_ep_queue(dev->ep_in, req, GFP_KERNEL); - if (ret < 0) { - DBG(cdev, "mtp_write: xfer error %d\n", ret); - r = -EIO; - break; - } - - buf += xfer; - count -= xfer; - - /* zero this so we don't try to free it on error exit */ - req = 0; - } - - if (req) - mtp_req_put(dev, &dev->tx_idle, req); - - spin_lock_irq(&dev->lock); - if (dev->state == STATE_CANCELED) - r = -ECANCELED; - else if (dev->state != STATE_OFFLINE) - dev->state = STATE_READY; - spin_unlock_irq(&dev->lock); - - DBG(cdev, "mtp_write returning %d\n", r); - return r; -} - -/* read from a local file and write to USB */ -static void send_file_work(struct work_struct *data) -{ - struct mtp_dev *dev = container_of(data, struct mtp_dev, - send_file_work); - struct usb_composite_dev *cdev = dev->cdev; - struct usb_request *req = 0; - struct mtp_data_header *header; - struct file *filp; - loff_t offset; - int64_t count; - int xfer, ret, hdr_size; - int r = 0; - int sendZLP = 0; - - /* read our parameters */ - smp_rmb(); - filp = dev->xfer_file; - offset = dev->xfer_file_offset; - count = dev->xfer_file_length; - - DBG(cdev, "send_file_work(%lld %lld)\n", offset, count); - - if (dev->xfer_send_header) { - hdr_size = sizeof(struct mtp_data_header); - count += hdr_size; - } else { - hdr_size = 0; - } - - /* we need to send a zero length packet to signal the end of transfer - * if the transfer size is aligned to a packet boundary. - */ - if ((count & (dev->ep_in->maxpacket - 1)) == 0) - sendZLP = 1; - - while (count > 0 || sendZLP) { - /* so we exit after sending ZLP */ - if (count == 0) - sendZLP = 0; - - /* get an idle tx request to use */ - req = 0; - ret = wait_event_interruptible(dev->write_wq, - (req = mtp_req_get(dev, &dev->tx_idle)) - || dev->state != STATE_BUSY); - if (dev->state == STATE_CANCELED) { - r = -ECANCELED; - break; - } - if (!req) { - r = ret; - break; - } - - if (count > MTP_BULK_BUFFER_SIZE) - xfer = MTP_BULK_BUFFER_SIZE; - else - xfer = count; - - if (hdr_size) { - /* prepend MTP data header */ - header = (struct mtp_data_header *)req->buf; - header->length = __cpu_to_le32(count); - header->type = __cpu_to_le16(2); /* data packet */ - header->command = __cpu_to_le16(dev->xfer_command); - header->transaction_id = - __cpu_to_le32(dev->xfer_transaction_id); - } - - ret = vfs_read(filp, req->buf + hdr_size, xfer - hdr_size, - &offset); - if (ret < 0) { - r = ret; - break; - } - xfer = ret + hdr_size; - hdr_size = 0; - - req->length = xfer; - ret = usb_ep_queue(dev->ep_in, req, GFP_KERNEL); - if (ret < 0) { - DBG(cdev, "send_file_work: xfer error %d\n", ret); - dev->state = STATE_ERROR; - r = -EIO; - break; - } - - count -= xfer; - - /* zero this so we don't try to free it on error exit */ - req = 0; - } - - if (req) - mtp_req_put(dev, &dev->tx_idle, req); - - DBG(cdev, "send_file_work returning %d\n", r); - /* write the result */ - dev->xfer_result = r; - smp_wmb(); -} - -/* read from USB and write to a local file */ -static void receive_file_work(struct work_struct *data) -{ - struct mtp_dev *dev = container_of(data, struct mtp_dev, - receive_file_work); - struct usb_composite_dev *cdev = dev->cdev; - struct usb_request *read_req = NULL, *write_req = NULL; - struct file *filp; - loff_t offset; - int64_t count; - int ret, cur_buf = 0; - int r = 0; - - /* read our parameters */ - smp_rmb(); - filp = dev->xfer_file; - offset = dev->xfer_file_offset; - count = dev->xfer_file_length; - - DBG(cdev, "receive_file_work(%lld)\n", count); - - while (count > 0 || write_req) { - if (count > 0) { - /* queue a request */ - read_req = dev->rx_req[cur_buf]; - cur_buf = (cur_buf + 1) % RX_REQ_MAX; - - read_req->length = (count > MTP_BULK_BUFFER_SIZE - ? MTP_BULK_BUFFER_SIZE : count); - dev->rx_done = 0; - ret = usb_ep_queue(dev->ep_out, read_req, GFP_KERNEL); - if (ret < 0) { - r = -EIO; - dev->state = STATE_ERROR; - break; - } - } - - if (write_req) { - DBG(cdev, "rx %p %d\n", write_req, write_req->actual); - ret = vfs_write(filp, write_req->buf, write_req->actual, - &offset); - DBG(cdev, "vfs_write %d\n", ret); - if (ret != write_req->actual) { - r = -EIO; - dev->state = STATE_ERROR; - break; - } - write_req = NULL; - } - - if (read_req) { - /* wait for our last read to complete */ - ret = wait_event_interruptible(dev->read_wq, - dev->rx_done || dev->state != STATE_BUSY); - if (dev->state == STATE_CANCELED) { - r = -ECANCELED; - if (!dev->rx_done) - usb_ep_dequeue(dev->ep_out, read_req); - break; - } - /* if xfer_file_length is 0xFFFFFFFF, then we read until - * we get a zero length packet - */ - if (count != 0xFFFFFFFF) - count -= read_req->actual; - if (read_req->actual < read_req->length) { - /* - * short packet is used to signal EOF for - * sizes > 4 gig - */ - DBG(cdev, "got short packet\n"); - count = 0; - } - - write_req = read_req; - read_req = NULL; - } - } - - DBG(cdev, "receive_file_work returning %d\n", r); - /* write the result */ - dev->xfer_result = r; - smp_wmb(); -} - -static int mtp_send_event(struct mtp_dev *dev, struct mtp_event *event) -{ - struct usb_request *req = NULL; - int ret; - int length = event->length; - - DBG(dev->cdev, "mtp_send_event(%d)\n", event->length); - - if (length < 0 || length > INTR_BUFFER_SIZE) - return -EINVAL; - if (dev->state == STATE_OFFLINE) - return -ENODEV; - - ret = wait_event_interruptible_timeout(dev->intr_wq, - (req = mtp_req_get(dev, &dev->intr_idle)), - msecs_to_jiffies(1000)); - if (!req) - return -ETIME; - - if (copy_from_user(req->buf, (void __user *)event->data, length)) { - mtp_req_put(dev, &dev->intr_idle, req); - return -EFAULT; - } - req->length = length; - ret = usb_ep_queue(dev->ep_intr, req, GFP_KERNEL); - if (ret) - mtp_req_put(dev, &dev->intr_idle, req); - - return ret; -} - -static long mtp_ioctl(struct file *fp, unsigned code, unsigned long value) -{ - struct mtp_dev *dev = fp->private_data; - struct file *filp = NULL; - int ret = -EINVAL; - - if (mtp_lock(&dev->ioctl_excl)) - return -EBUSY; - - switch (code) { - case MTP_SEND_FILE: - case MTP_RECEIVE_FILE: - case MTP_SEND_FILE_WITH_HEADER: - { - struct mtp_file_range mfr; - struct work_struct *work; - - spin_lock_irq(&dev->lock); - if (dev->state == STATE_CANCELED) { - /* report cancelation to userspace */ - dev->state = STATE_READY; - spin_unlock_irq(&dev->lock); - ret = -ECANCELED; - goto out; - } - if (dev->state == STATE_OFFLINE) { - spin_unlock_irq(&dev->lock); - ret = -ENODEV; - goto out; - } - dev->state = STATE_BUSY; - spin_unlock_irq(&dev->lock); - - if (copy_from_user(&mfr, (void __user *)value, sizeof(mfr))) { - ret = -EFAULT; - goto fail; - } - /* hold a reference to the file while we are working with it */ - filp = fget(mfr.fd); - if (!filp) { - ret = -EBADF; - goto fail; - } - - /* write the parameters */ - dev->xfer_file = filp; - dev->xfer_file_offset = mfr.offset; - dev->xfer_file_length = mfr.length; - smp_wmb(); - - if (code == MTP_SEND_FILE_WITH_HEADER) { - work = &dev->send_file_work; - dev->xfer_send_header = 1; - dev->xfer_command = mfr.command; - dev->xfer_transaction_id = mfr.transaction_id; - } else if (code == MTP_SEND_FILE) { - work = &dev->send_file_work; - dev->xfer_send_header = 0; - } else { - work = &dev->receive_file_work; - } - - /* We do the file transfer on a work queue so it will run - * in kernel context, which is necessary for vfs_read and - * vfs_write to use our buffers in the kernel address space. - */ - queue_work(dev->wq, work); - /* wait for operation to complete */ - flush_workqueue(dev->wq); - fput(filp); - - /* read the result */ - smp_rmb(); - ret = dev->xfer_result; - break; - } - case MTP_SEND_EVENT: - { - struct mtp_event event; - /* return here so we don't change dev->state below, - * which would interfere with bulk transfer state. - */ - if (copy_from_user(&event, (void __user *)value, sizeof(event))) - ret = -EFAULT; - else - ret = mtp_send_event(dev, &event); - goto out; - } - } - -fail: - spin_lock_irq(&dev->lock); - if (dev->state == STATE_CANCELED) - ret = -ECANCELED; - else if (dev->state != STATE_OFFLINE) - dev->state = STATE_READY; - spin_unlock_irq(&dev->lock); -out: - mtp_unlock(&dev->ioctl_excl); - DBG(dev->cdev, "ioctl returning %d\n", ret); - return ret; -} - -static int mtp_open(struct inode *ip, struct file *fp) -{ - printk(KERN_INFO "mtp_open\n"); - if (mtp_lock(&_mtp_dev->open_excl)) - return -EBUSY; - - /* clear any error condition */ - if (_mtp_dev->state != STATE_OFFLINE) - _mtp_dev->state = STATE_READY; - - fp->private_data = _mtp_dev; - return 0; -} - -static int mtp_release(struct inode *ip, struct file *fp) -{ - printk(KERN_INFO "mtp_release\n"); - - mtp_unlock(&_mtp_dev->open_excl); - return 0; -} - -/* file operations for /dev/mtp_usb */ -static const struct file_operations mtp_fops = { - .owner = THIS_MODULE, - .read = mtp_read, - .write = mtp_write, - .unlocked_ioctl = mtp_ioctl, - .open = mtp_open, - .release = mtp_release, -}; - -static struct miscdevice mtp_device = { - .minor = MISC_DYNAMIC_MINOR, - .name = mtp_shortname, - .fops = &mtp_fops, -}; - -static int mtp_ctrlrequest(struct usb_composite_dev *cdev, - const struct usb_ctrlrequest *ctrl) -{ - struct mtp_dev *dev = _mtp_dev; - 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); - unsigned long flags; - - VDBG(cdev, "mtp_ctrlrequest " - "%02x.%02x v%04x i%04x l%u\n", - ctrl->bRequestType, ctrl->bRequest, - w_value, w_index, w_length); - - /* Handle MTP OS string */ - if (ctrl->bRequestType == - (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE) - && ctrl->bRequest == USB_REQ_GET_DESCRIPTOR - && (w_value >> 8) == USB_DT_STRING - && (w_value & 0xFF) == MTP_OS_STRING_ID) { - value = (w_length < sizeof(mtp_os_string) - ? w_length : sizeof(mtp_os_string)); - memcpy(cdev->req->buf, mtp_os_string, value); - } else if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_VENDOR) { - /* Handle MTP OS descriptor */ - DBG(cdev, "vendor request: %d index: %d value: %d length: %d\n", - ctrl->bRequest, w_index, w_value, w_length); - - if (ctrl->bRequest == 1 - && (ctrl->bRequestType & USB_DIR_IN) - && (w_index == 4 || w_index == 5)) { - value = (w_length < sizeof(mtp_ext_config_desc) ? - w_length : sizeof(mtp_ext_config_desc)); - memcpy(cdev->req->buf, &mtp_ext_config_desc, value); - } - } else if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) { - DBG(cdev, "class request: %d index: %d value: %d length: %d\n", - ctrl->bRequest, w_index, w_value, w_length); - - if (ctrl->bRequest == MTP_REQ_CANCEL && w_index == 0 - && w_value == 0) { - DBG(cdev, "MTP_REQ_CANCEL\n"); - - spin_lock_irqsave(&dev->lock, flags); - if (dev->state == STATE_BUSY) { - dev->state = STATE_CANCELED; - wake_up(&dev->read_wq); - wake_up(&dev->write_wq); - } - spin_unlock_irqrestore(&dev->lock, flags); - - /* We need to queue a request to read the remaining - * bytes, but we don't actually need to look at - * the contents. - */ - value = w_length; - } else if (ctrl->bRequest == MTP_REQ_GET_DEVICE_STATUS - && w_index == 0 && w_value == 0) { - struct mtp_device_status *status = cdev->req->buf; - status->wLength = - __constant_cpu_to_le16(sizeof(*status)); - - DBG(cdev, "MTP_REQ_GET_DEVICE_STATUS\n"); - spin_lock_irqsave(&dev->lock, flags); - /* device status is "busy" until we report - * the cancelation to userspace - */ - if (dev->state == STATE_CANCELED) - status->wCode = - __cpu_to_le16(MTP_RESPONSE_DEVICE_BUSY); - else - status->wCode = - __cpu_to_le16(MTP_RESPONSE_OK); - spin_unlock_irqrestore(&dev->lock, flags); - value = sizeof(*status); - } - } - - /* respond with data transfer or status phase? */ - if (value >= 0) { - int rc; - cdev->req->zero = value < w_length; - cdev->req->length = value; - rc = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC); - if (rc < 0) - ERROR(cdev, "%s: response queue error\n", __func__); - } - return value; -} - -static int -mtp_function_bind(struct usb_configuration *c, struct usb_function *f) -{ - struct usb_composite_dev *cdev = c->cdev; - struct mtp_dev *dev = func_to_mtp(f); - int id; - int ret; - - dev->cdev = cdev; - DBG(cdev, "mtp_function_bind dev: %p\n", dev); - - /* allocate interface ID(s) */ - id = usb_interface_id(c, f); - if (id < 0) - return id; - mtp_interface_desc.bInterfaceNumber = id; - - /* allocate endpoints */ - ret = mtp_create_bulk_endpoints(dev, &mtp_fullspeed_in_desc, - &mtp_fullspeed_out_desc, &mtp_intr_desc); - if (ret) - return ret; - - /* support high speed hardware */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - mtp_highspeed_in_desc.bEndpointAddress = - mtp_fullspeed_in_desc.bEndpointAddress; - mtp_highspeed_out_desc.bEndpointAddress = - mtp_fullspeed_out_desc.bEndpointAddress; - } - - DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", - gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", - f->name, dev->ep_in->name, dev->ep_out->name); - return 0; -} - -static void -mtp_function_unbind(struct usb_configuration *c, struct usb_function *f) -{ - struct mtp_dev *dev = func_to_mtp(f); - struct usb_request *req; - int i; - extern void wmt_cleanup_done_thread(int number); - wmt_cleanup_done_thread(1); - while ((req = mtp_req_get(dev, &dev->tx_idle))) - mtp_request_free(req, dev->ep_in); - for (i = 0; i < RX_REQ_MAX; i++) - mtp_request_free(dev->rx_req[i], dev->ep_out); - while ((req = mtp_req_get(dev, &dev->intr_idle))) - mtp_request_free(req, dev->ep_intr); - dev->state = STATE_OFFLINE; -} - -static int mtp_function_set_alt(struct usb_function *f, - unsigned intf, unsigned alt) -{ - struct mtp_dev *dev = func_to_mtp(f); - struct usb_composite_dev *cdev = f->config->cdev; - int ret; - - DBG(cdev, "mtp_function_set_alt intf: %d alt: %d\n", intf, alt); - - ret = config_ep_by_speed(cdev->gadget, f, dev->ep_in); - if (ret) - return ret; - - ret = usb_ep_enable(dev->ep_in); - if (ret) - return ret; - - ret = config_ep_by_speed(cdev->gadget, f, dev->ep_out); - if (ret) - return ret; - - ret = usb_ep_enable(dev->ep_out); - if (ret) { - usb_ep_disable(dev->ep_in); - return ret; - } - - ret = config_ep_by_speed(cdev->gadget, f, dev->ep_intr); - if (ret) - return ret; - - ret = usb_ep_enable(dev->ep_intr); - if (ret) { - usb_ep_disable(dev->ep_out); - usb_ep_disable(dev->ep_in); - return ret; - } - dev->state = STATE_READY; - - /* readers may be blocked waiting for us to go online */ - wake_up(&dev->read_wq); - return 0; -} - - -static void mtp_function_disable(struct usb_function *f) -{ - struct mtp_dev *dev = func_to_mtp(f); - struct usb_composite_dev *cdev = dev->cdev; - - printk("mtp_function_disable\n"); - dev->state = STATE_OFFLINE; - usb_ep_disable(dev->ep_in); - usb_ep_disable(dev->ep_out); - usb_ep_disable(dev->ep_intr); -// wmt_cleanup_done_thread(1); - /* readers may be blocked waiting for us to go online */ - wake_up(&dev->read_wq); - - printk("%s disabled\n", dev->function.name); -} - -static int mtp_bind_config(struct usb_configuration *c, bool ptp_config) -{ - struct mtp_dev *dev = _mtp_dev; - int ret = 0; - - printk(KERN_INFO "mtp_bind_config\n"); - - /* allocate a string ID for our interface */ - if (mtp_string_defs[INTERFACE_STRING_INDEX].id == 0) { - ret = usb_string_id(c->cdev); - if (ret < 0) - return ret; - mtp_string_defs[INTERFACE_STRING_INDEX].id = ret; - mtp_interface_desc.iInterface = ret; - } - - dev->cdev = c->cdev; - dev->function.name = "mtp"; - dev->function.strings = mtp_strings; - if (ptp_config) { - dev->function.descriptors = fs_ptp_descs; - dev->function.hs_descriptors = hs_ptp_descs; - } else { - dev->function.descriptors = fs_mtp_descs; - dev->function.hs_descriptors = hs_mtp_descs; - } - dev->function.bind = mtp_function_bind; - dev->function.unbind = mtp_function_unbind; - dev->function.set_alt = mtp_function_set_alt; - dev->function.disable = mtp_function_disable; - - return usb_add_function(c, &dev->function); -} - -static int mtp_setup(void) -{ - struct mtp_dev *dev; - int ret; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - spin_lock_init(&dev->lock); - init_waitqueue_head(&dev->read_wq); - init_waitqueue_head(&dev->write_wq); - init_waitqueue_head(&dev->intr_wq); - atomic_set(&dev->open_excl, 0); - atomic_set(&dev->ioctl_excl, 0); - INIT_LIST_HEAD(&dev->tx_idle); - INIT_LIST_HEAD(&dev->intr_idle); - - dev->wq = create_singlethread_workqueue("f_mtp"); - if (!dev->wq) { - ret = -ENOMEM; - goto err1; - } - INIT_WORK(&dev->send_file_work, send_file_work); - INIT_WORK(&dev->receive_file_work, receive_file_work); - - _mtp_dev = dev; - - ret = misc_register(&mtp_device); - if (ret) - goto err2; - - return 0; - -err2: - destroy_workqueue(dev->wq); -err1: - _mtp_dev = NULL; - kfree(dev); - printk(KERN_ERR "mtp gadget driver failed to initialize\n"); - return ret; -} - -static void mtp_cleanup(void) -{ - struct mtp_dev *dev = _mtp_dev; - - if (!dev) - return; - - misc_deregister(&mtp_device); - destroy_workqueue(dev->wq); - _mtp_dev = NULL; - kfree(dev); -} diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_ncm.c b/ANDROID_3.4.5/drivers/usb/gadget/f_ncm.c deleted file mode 100644 index aab8eded..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_ncm.c +++ /dev/null @@ -1,1378 +0,0 @@ -/* - * f_ncm.c -- USB CDC Network (NCM) link function driver - * - * Copyright (C) 2010 Nokia Corporation - * Contact: Yauheni Kaliuta - * - * The driver borrows from f_ecm.c which is: - * - * Copyright (C) 2003-2005,2008 David Brownell - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include - -#include - -#include "u_ether.h" - -/* - * This function is a "CDC Network Control Model" (CDC NCM) Ethernet link. - * NCM is intended to be used with high-speed network attachments. - * - * Note that NCM requires the use of "alternate settings" for its data - * interface. This means that the set_alt() method has real work to do, - * and also means that a get_alt() method is required. - */ - -/* to trigger crc/non-crc ndp signature */ - -#define NCM_NDP_HDR_CRC_MASK 0x01000000 -#define NCM_NDP_HDR_CRC 0x01000000 -#define NCM_NDP_HDR_NOCRC 0x00000000 - -enum ncm_notify_state { - NCM_NOTIFY_NONE, /* don't notify */ - NCM_NOTIFY_CONNECT, /* issue CONNECT next */ - NCM_NOTIFY_SPEED, /* issue SPEED_CHANGE next */ -}; - -struct f_ncm { - struct gether port; - u8 ctrl_id, data_id; - - char ethaddr[14]; - - struct usb_ep *notify; - struct usb_request *notify_req; - u8 notify_state; - bool is_open; - - struct ndp_parser_opts *parser_opts; - bool is_crc; - - /* - * for notification, it is accessed from both - * callback and ethernet open/close - */ - spinlock_t lock; -}; - -static inline struct f_ncm *func_to_ncm(struct usb_function *f) -{ - return container_of(f, struct f_ncm, port.func); -} - -/* peak (theoretical) bulk transfer rate in bits-per-second */ -static inline unsigned ncm_bitrate(struct usb_gadget *g) -{ - if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) - return 13 * 512 * 8 * 1000 * 8; - else - return 19 * 64 * 1 * 1000 * 8; -} - -/*-------------------------------------------------------------------------*/ - -/* - * We cannot group frames so use just the minimal size which ok to put - * one max-size ethernet frame. - * If the host can group frames, allow it to do that, 16K is selected, - * because it's used by default by the current linux host driver - */ -#define NTB_DEFAULT_IN_SIZE USB_CDC_NCM_NTB_MIN_IN_SIZE -#define NTB_OUT_SIZE 16384 - -/* - * skbs of size less than that will not be aligned - * to NCM's dwNtbInMaxSize to save bus bandwidth - */ - -#define MAX_TX_NONFIXED (512 * 3) - -#define FORMATS_SUPPORTED (USB_CDC_NCM_NTB16_SUPPORTED | \ - USB_CDC_NCM_NTB32_SUPPORTED) - -static struct usb_cdc_ncm_ntb_parameters ntb_parameters = { - .wLength = sizeof ntb_parameters, - .bmNtbFormatsSupported = cpu_to_le16(FORMATS_SUPPORTED), - .dwNtbInMaxSize = cpu_to_le32(NTB_DEFAULT_IN_SIZE), - .wNdpInDivisor = cpu_to_le16(4), - .wNdpInPayloadRemainder = cpu_to_le16(0), - .wNdpInAlignment = cpu_to_le16(4), - - .dwNtbOutMaxSize = cpu_to_le32(NTB_OUT_SIZE), - .wNdpOutDivisor = cpu_to_le16(4), - .wNdpOutPayloadRemainder = cpu_to_le16(0), - .wNdpOutAlignment = cpu_to_le16(4), -}; - -/* - * Use wMaxPacketSize big enough to fit CDC_NOTIFY_SPEED_CHANGE in one - * packet, to simplify cancellation; and a big transfer interval, to - * waste less bandwidth. - */ - -#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */ -#define NCM_STATUS_BYTECOUNT 16 /* 8 byte header + data */ - -static struct usb_interface_assoc_descriptor ncm_iad_desc __initdata = { - .bLength = sizeof ncm_iad_desc, - .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, - - /* .bFirstInterface = DYNAMIC, */ - .bInterfaceCount = 2, /* control + data */ - .bFunctionClass = USB_CLASS_COMM, - .bFunctionSubClass = USB_CDC_SUBCLASS_NCM, - .bFunctionProtocol = USB_CDC_PROTO_NONE, - /* .iFunction = DYNAMIC */ -}; - -/* interface descriptor: */ - -static struct usb_interface_descriptor ncm_control_intf __initdata = { - .bLength = sizeof ncm_control_intf, - .bDescriptorType = USB_DT_INTERFACE, - - /* .bInterfaceNumber = DYNAMIC */ - .bNumEndpoints = 1, - .bInterfaceClass = USB_CLASS_COMM, - .bInterfaceSubClass = USB_CDC_SUBCLASS_NCM, - .bInterfaceProtocol = USB_CDC_PROTO_NONE, - /* .iInterface = DYNAMIC */ -}; - -static struct usb_cdc_header_desc ncm_header_desc __initdata = { - .bLength = sizeof ncm_header_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_HEADER_TYPE, - - .bcdCDC = cpu_to_le16(0x0110), -}; - -static struct usb_cdc_union_desc ncm_union_desc __initdata = { - .bLength = sizeof(ncm_union_desc), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_UNION_TYPE, - /* .bMasterInterface0 = DYNAMIC */ - /* .bSlaveInterface0 = DYNAMIC */ -}; - -static struct usb_cdc_ether_desc ecm_desc __initdata = { - .bLength = sizeof ecm_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_ETHERNET_TYPE, - - /* this descriptor actually adds value, surprise! */ - /* .iMACAddress = DYNAMIC */ - .bmEthernetStatistics = cpu_to_le32(0), /* no statistics */ - .wMaxSegmentSize = cpu_to_le16(ETH_FRAME_LEN), - .wNumberMCFilters = cpu_to_le16(0), - .bNumberPowerFilters = 0, -}; - -#define NCAPS (USB_CDC_NCM_NCAP_ETH_FILTER | USB_CDC_NCM_NCAP_CRC_MODE) - -static struct usb_cdc_ncm_desc ncm_desc __initdata = { - .bLength = sizeof ncm_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_NCM_TYPE, - - .bcdNcmVersion = cpu_to_le16(0x0100), - /* can process SetEthernetPacketFilter */ - .bmNetworkCapabilities = NCAPS, -}; - -/* the default data interface has no endpoints ... */ - -static struct usb_interface_descriptor ncm_data_nop_intf __initdata = { - .bLength = sizeof ncm_data_nop_intf, - .bDescriptorType = USB_DT_INTERFACE, - - .bInterfaceNumber = 1, - .bAlternateSetting = 0, - .bNumEndpoints = 0, - .bInterfaceClass = USB_CLASS_CDC_DATA, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = USB_CDC_NCM_PROTO_NTB, - /* .iInterface = DYNAMIC */ -}; - -/* ... but the "real" data interface has two bulk endpoints */ - -static struct usb_interface_descriptor ncm_data_intf __initdata = { - .bLength = sizeof ncm_data_intf, - .bDescriptorType = USB_DT_INTERFACE, - - .bInterfaceNumber = 1, - .bAlternateSetting = 1, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_CDC_DATA, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = USB_CDC_NCM_PROTO_NTB, - /* .iInterface = DYNAMIC */ -}; - -/* full speed support: */ - -static struct usb_endpoint_descriptor fs_ncm_notify_desc __initdata = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(NCM_STATUS_BYTECOUNT), - .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC, -}; - -static struct usb_endpoint_descriptor fs_ncm_in_desc __initdata = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_endpoint_descriptor fs_ncm_out_desc __initdata = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_descriptor_header *ncm_fs_function[] __initdata = { - (struct usb_descriptor_header *) &ncm_iad_desc, - /* CDC NCM control descriptors */ - (struct usb_descriptor_header *) &ncm_control_intf, - (struct usb_descriptor_header *) &ncm_header_desc, - (struct usb_descriptor_header *) &ncm_union_desc, - (struct usb_descriptor_header *) &ecm_desc, - (struct usb_descriptor_header *) &ncm_desc, - (struct usb_descriptor_header *) &fs_ncm_notify_desc, - /* data interface, altsettings 0 and 1 */ - (struct usb_descriptor_header *) &ncm_data_nop_intf, - (struct usb_descriptor_header *) &ncm_data_intf, - (struct usb_descriptor_header *) &fs_ncm_in_desc, - (struct usb_descriptor_header *) &fs_ncm_out_desc, - NULL, -}; - -/* high speed support: */ - -static struct usb_endpoint_descriptor hs_ncm_notify_desc __initdata = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(NCM_STATUS_BYTECOUNT), - .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, -}; -static struct usb_endpoint_descriptor hs_ncm_in_desc __initdata = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), -}; - -static struct usb_endpoint_descriptor hs_ncm_out_desc __initdata = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), -}; - -static struct usb_descriptor_header *ncm_hs_function[] __initdata = { - (struct usb_descriptor_header *) &ncm_iad_desc, - /* CDC NCM control descriptors */ - (struct usb_descriptor_header *) &ncm_control_intf, - (struct usb_descriptor_header *) &ncm_header_desc, - (struct usb_descriptor_header *) &ncm_union_desc, - (struct usb_descriptor_header *) &ecm_desc, - (struct usb_descriptor_header *) &ncm_desc, - (struct usb_descriptor_header *) &hs_ncm_notify_desc, - /* data interface, altsettings 0 and 1 */ - (struct usb_descriptor_header *) &ncm_data_nop_intf, - (struct usb_descriptor_header *) &ncm_data_intf, - (struct usb_descriptor_header *) &hs_ncm_in_desc, - (struct usb_descriptor_header *) &hs_ncm_out_desc, - NULL, -}; - -/* string descriptors: */ - -#define STRING_CTRL_IDX 0 -#define STRING_MAC_IDX 1 -#define STRING_DATA_IDX 2 -#define STRING_IAD_IDX 3 - -static struct usb_string ncm_string_defs[] = { - [STRING_CTRL_IDX].s = "CDC Network Control Model (NCM)", - [STRING_MAC_IDX].s = NULL /* DYNAMIC */, - [STRING_DATA_IDX].s = "CDC Network Data", - [STRING_IAD_IDX].s = "CDC NCM", - { } /* end of list */ -}; - -static struct usb_gadget_strings ncm_string_table = { - .language = 0x0409, /* en-us */ - .strings = ncm_string_defs, -}; - -static struct usb_gadget_strings *ncm_strings[] = { - &ncm_string_table, - NULL, -}; - -/* - * Here are options for NCM Datagram Pointer table (NDP) parser. - * There are 2 different formats: NDP16 and NDP32 in the spec (ch. 3), - * in NDP16 offsets and sizes fields are 1 16bit word wide, - * in NDP32 -- 2 16bit words wide. Also signatures are different. - * To make the parser code the same, put the differences in the structure, - * and switch pointers to the structures when the format is changed. - */ - -struct ndp_parser_opts { - u32 nth_sign; - u32 ndp_sign; - unsigned nth_size; - unsigned ndp_size; - unsigned ndplen_align; - /* sizes in u16 units */ - unsigned dgram_item_len; /* index or length */ - unsigned block_length; - unsigned fp_index; - unsigned reserved1; - unsigned reserved2; - unsigned next_fp_index; -}; - -#define INIT_NDP16_OPTS { \ - .nth_sign = USB_CDC_NCM_NTH16_SIGN, \ - .ndp_sign = USB_CDC_NCM_NDP16_NOCRC_SIGN, \ - .nth_size = sizeof(struct usb_cdc_ncm_nth16), \ - .ndp_size = sizeof(struct usb_cdc_ncm_ndp16), \ - .ndplen_align = 4, \ - .dgram_item_len = 1, \ - .block_length = 1, \ - .fp_index = 1, \ - .reserved1 = 0, \ - .reserved2 = 0, \ - .next_fp_index = 1, \ - } - - -#define INIT_NDP32_OPTS { \ - .nth_sign = USB_CDC_NCM_NTH32_SIGN, \ - .ndp_sign = USB_CDC_NCM_NDP32_NOCRC_SIGN, \ - .nth_size = sizeof(struct usb_cdc_ncm_nth32), \ - .ndp_size = sizeof(struct usb_cdc_ncm_ndp32), \ - .ndplen_align = 8, \ - .dgram_item_len = 2, \ - .block_length = 2, \ - .fp_index = 2, \ - .reserved1 = 1, \ - .reserved2 = 2, \ - .next_fp_index = 2, \ - } - -static struct ndp_parser_opts ndp16_opts = INIT_NDP16_OPTS; -static struct ndp_parser_opts ndp32_opts = INIT_NDP32_OPTS; - -static inline void put_ncm(__le16 **p, unsigned size, unsigned val) -{ - switch (size) { - case 1: - put_unaligned_le16((u16)val, *p); - break; - case 2: - put_unaligned_le32((u32)val, *p); - - break; - default: - BUG(); - } - - *p += size; -} - -static inline unsigned get_ncm(__le16 **p, unsigned size) -{ - unsigned tmp; - - switch (size) { - case 1: - tmp = get_unaligned_le16(*p); - break; - case 2: - tmp = get_unaligned_le32(*p); - break; - default: - BUG(); - } - - *p += size; - return tmp; -} - -/*-------------------------------------------------------------------------*/ - -static inline void ncm_reset_values(struct f_ncm *ncm) -{ - ncm->parser_opts = &ndp16_opts; - ncm->is_crc = false; - ncm->port.cdc_filter = DEFAULT_FILTER; - - /* doesn't make sense for ncm, fixed size used */ - ncm->port.header_len = 0; - - ncm->port.fixed_out_len = le32_to_cpu(ntb_parameters.dwNtbOutMaxSize); - ncm->port.fixed_in_len = NTB_DEFAULT_IN_SIZE; -} - -/* - * Context: ncm->lock held - */ -static void ncm_do_notify(struct f_ncm *ncm) -{ - struct usb_request *req = ncm->notify_req; - struct usb_cdc_notification *event; - struct usb_composite_dev *cdev = ncm->port.func.config->cdev; - __le32 *data; - int status; - - /* notification already in flight? */ - if (!req) - return; - - event = req->buf; - switch (ncm->notify_state) { - case NCM_NOTIFY_NONE: - return; - - case NCM_NOTIFY_CONNECT: - event->bNotificationType = USB_CDC_NOTIFY_NETWORK_CONNECTION; - if (ncm->is_open) - event->wValue = cpu_to_le16(1); - else - event->wValue = cpu_to_le16(0); - event->wLength = 0; - req->length = sizeof *event; - - DBG(cdev, "notify connect %s\n", - ncm->is_open ? "true" : "false"); - ncm->notify_state = NCM_NOTIFY_NONE; - break; - - case NCM_NOTIFY_SPEED: - event->bNotificationType = USB_CDC_NOTIFY_SPEED_CHANGE; - event->wValue = cpu_to_le16(0); - event->wLength = cpu_to_le16(8); - req->length = NCM_STATUS_BYTECOUNT; - - /* SPEED_CHANGE data is up/down speeds in bits/sec */ - data = req->buf + sizeof *event; - data[0] = cpu_to_le32(ncm_bitrate(cdev->gadget)); - data[1] = data[0]; - - DBG(cdev, "notify speed %d\n", ncm_bitrate(cdev->gadget)); - ncm->notify_state = NCM_NOTIFY_CONNECT; - break; - } - event->bmRequestType = 0xA1; - event->wIndex = cpu_to_le16(ncm->ctrl_id); - - ncm->notify_req = NULL; - /* - * In double buffering if there is a space in FIFO, - * completion callback can be called right after the call, - * so unlocking - */ - spin_unlock(&ncm->lock); - status = usb_ep_queue(ncm->notify, req, GFP_ATOMIC); - spin_lock(&ncm->lock); - if (status < 0) { - ncm->notify_req = req; - DBG(cdev, "notify --> %d\n", status); - } -} - -/* - * Context: ncm->lock held - */ -static void ncm_notify(struct f_ncm *ncm) -{ - /* - * NOTE on most versions of Linux, host side cdc-ethernet - * won't listen for notifications until its netdevice opens. - * The first notification then sits in the FIFO for a long - * time, and the second one is queued. - * - * If ncm_notify() is called before the second (CONNECT) - * notification is sent, then it will reset to send the SPEED - * notificaion again (and again, and again), but it's not a problem - */ - ncm->notify_state = NCM_NOTIFY_SPEED; - ncm_do_notify(ncm); -} - -static void ncm_notify_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct f_ncm *ncm = req->context; - struct usb_composite_dev *cdev = ncm->port.func.config->cdev; - struct usb_cdc_notification *event = req->buf; - - spin_lock(&ncm->lock); - switch (req->status) { - case 0: - VDBG(cdev, "Notification %02x sent\n", - event->bNotificationType); - break; - case -ECONNRESET: - case -ESHUTDOWN: - ncm->notify_state = NCM_NOTIFY_NONE; - break; - default: - DBG(cdev, "event %02x --> %d\n", - event->bNotificationType, req->status); - break; - } - ncm->notify_req = req; - ncm_do_notify(ncm); - spin_unlock(&ncm->lock); -} - -static void ncm_ep0out_complete(struct usb_ep *ep, struct usb_request *req) -{ - /* now for SET_NTB_INPUT_SIZE only */ - unsigned in_size; - struct usb_function *f = req->context; - struct f_ncm *ncm = func_to_ncm(f); - struct usb_composite_dev *cdev = ep->driver_data; - - req->context = NULL; - if (req->status || req->actual != req->length) { - DBG(cdev, "Bad control-OUT transfer\n"); - goto invalid; - } - - in_size = get_unaligned_le32(req->buf); - if (in_size < USB_CDC_NCM_NTB_MIN_IN_SIZE || - in_size > le32_to_cpu(ntb_parameters.dwNtbInMaxSize)) { - DBG(cdev, "Got wrong INPUT SIZE (%d) from host\n", in_size); - goto invalid; - } - - ncm->port.fixed_in_len = in_size; - VDBG(cdev, "Set NTB INPUT SIZE %d\n", in_size); - return; - -invalid: - usb_ep_set_halt(ep); - return; -} - -static int ncm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) -{ - struct f_ncm *ncm = func_to_ncm(f); - 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 - * CDC class messages; interface activation uses set_alt(). - */ - switch ((ctrl->bRequestType << 8) | ctrl->bRequest) { - case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) - | USB_CDC_SET_ETHERNET_PACKET_FILTER: - /* - * see 6.2.30: no data, wIndex = interface, - * wValue = packet filter bitmap - */ - if (w_length != 0 || w_index != ncm->ctrl_id) - goto invalid; - DBG(cdev, "packet filter %02x\n", w_value); - /* - * REVISIT locking of cdc_filter. This assumes the UDC - * driver won't have a concurrent packet TX irq running on - * another CPU; or that if it does, this write is atomic... - */ - ncm->port.cdc_filter = w_value; - value = 0; - break; - /* - * and optionally: - * case USB_CDC_SEND_ENCAPSULATED_COMMAND: - * case USB_CDC_GET_ENCAPSULATED_RESPONSE: - * case USB_CDC_SET_ETHERNET_MULTICAST_FILTERS: - * case USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER: - * case USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER: - * case USB_CDC_GET_ETHERNET_STATISTIC: - */ - - case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) - | USB_CDC_GET_NTB_PARAMETERS: - - if (w_length == 0 || w_value != 0 || w_index != ncm->ctrl_id) - goto invalid; - value = w_length > sizeof ntb_parameters ? - sizeof ntb_parameters : w_length; - memcpy(req->buf, &ntb_parameters, value); - VDBG(cdev, "Host asked NTB parameters\n"); - break; - - case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) - | USB_CDC_GET_NTB_INPUT_SIZE: - - if (w_length < 4 || w_value != 0 || w_index != ncm->ctrl_id) - goto invalid; - put_unaligned_le32(ncm->port.fixed_in_len, req->buf); - value = 4; - VDBG(cdev, "Host asked INPUT SIZE, sending %d\n", - ncm->port.fixed_in_len); - break; - - case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) - | USB_CDC_SET_NTB_INPUT_SIZE: - { - if (w_length != 4 || w_value != 0 || w_index != ncm->ctrl_id) - goto invalid; - req->complete = ncm_ep0out_complete; - req->length = w_length; - req->context = f; - - value = req->length; - break; - } - - case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) - | USB_CDC_GET_NTB_FORMAT: - { - uint16_t format; - - if (w_length < 2 || w_value != 0 || w_index != ncm->ctrl_id) - goto invalid; - format = (ncm->parser_opts == &ndp16_opts) ? 0x0000 : 0x0001; - put_unaligned_le16(format, req->buf); - value = 2; - VDBG(cdev, "Host asked NTB FORMAT, sending %d\n", format); - break; - } - - case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) - | USB_CDC_SET_NTB_FORMAT: - { - if (w_length != 0 || w_index != ncm->ctrl_id) - goto invalid; - switch (w_value) { - case 0x0000: - ncm->parser_opts = &ndp16_opts; - DBG(cdev, "NCM16 selected\n"); - break; - case 0x0001: - ncm->parser_opts = &ndp32_opts; - DBG(cdev, "NCM32 selected\n"); - break; - default: - goto invalid; - } - value = 0; - break; - } - case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) - | USB_CDC_GET_CRC_MODE: - { - uint16_t is_crc; - - if (w_length < 2 || w_value != 0 || w_index != ncm->ctrl_id) - goto invalid; - is_crc = ncm->is_crc ? 0x0001 : 0x0000; - put_unaligned_le16(is_crc, req->buf); - value = 2; - VDBG(cdev, "Host asked CRC MODE, sending %d\n", is_crc); - break; - } - - case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) - | USB_CDC_SET_CRC_MODE: - { - int ndp_hdr_crc = 0; - - if (w_length != 0 || w_index != ncm->ctrl_id) - goto invalid; - switch (w_value) { - case 0x0000: - ncm->is_crc = false; - ndp_hdr_crc = NCM_NDP_HDR_NOCRC; - DBG(cdev, "non-CRC mode selected\n"); - break; - case 0x0001: - ncm->is_crc = true; - ndp_hdr_crc = NCM_NDP_HDR_CRC; - DBG(cdev, "CRC mode selected\n"); - break; - default: - goto invalid; - } - ncm->parser_opts->ndp_sign &= ~NCM_NDP_HDR_CRC_MASK; - ncm->parser_opts->ndp_sign |= ndp_hdr_crc; - value = 0; - break; - } - - /* and disabled in ncm descriptor: */ - /* case USB_CDC_GET_NET_ADDRESS: */ - /* case USB_CDC_SET_NET_ADDRESS: */ - /* case USB_CDC_GET_MAX_DATAGRAM_SIZE: */ - /* case USB_CDC_SET_MAX_DATAGRAM_SIZE: */ - - default: -invalid: - DBG(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, "ncm 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, "ncm req %02x.%02x response err %d\n", - ctrl->bRequestType, ctrl->bRequest, - value); - } - - /* device either stalls (value < 0) or reports success */ - return value; -} - - -static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) -{ - struct f_ncm *ncm = func_to_ncm(f); - struct usb_composite_dev *cdev = f->config->cdev; - - /* Control interface has only altsetting 0 */ - if (intf == ncm->ctrl_id) { - if (alt != 0) - goto fail; - - if (ncm->notify->driver_data) { - DBG(cdev, "reset ncm control %d\n", intf); - usb_ep_disable(ncm->notify); - } - - if (!(ncm->notify->desc)) { - DBG(cdev, "init ncm ctrl %d\n", intf); - if (config_ep_by_speed(cdev->gadget, f, ncm->notify)) - goto fail; - } - usb_ep_enable(ncm->notify); - ncm->notify->driver_data = ncm; - - /* Data interface has two altsettings, 0 and 1 */ - } else if (intf == ncm->data_id) { - if (alt > 1) - goto fail; - - if (ncm->port.in_ep->driver_data) { - DBG(cdev, "reset ncm\n"); - gether_disconnect(&ncm->port); - ncm_reset_values(ncm); - } - - /* - * CDC Network only sends data in non-default altsettings. - * Changing altsettings resets filters, statistics, etc. - */ - if (alt == 1) { - struct net_device *net; - - if (!ncm->port.in_ep->desc || - !ncm->port.out_ep->desc) { - DBG(cdev, "init ncm\n"); - if (config_ep_by_speed(cdev->gadget, f, - ncm->port.in_ep) || - config_ep_by_speed(cdev->gadget, f, - ncm->port.out_ep)) { - ncm->port.in_ep->desc = NULL; - ncm->port.out_ep->desc = NULL; - goto fail; - } - } - - /* TODO */ - /* Enable zlps by default for NCM conformance; - * override for musb_hdrc (avoids txdma ovhead) - */ - ncm->port.is_zlp_ok = !( - gadget_is_musbhdrc(cdev->gadget) - ); - ncm->port.cdc_filter = DEFAULT_FILTER; - DBG(cdev, "activate ncm\n"); - net = gether_connect(&ncm->port); - if (IS_ERR(net)) - return PTR_ERR(net); - } - - spin_lock(&ncm->lock); - ncm_notify(ncm); - spin_unlock(&ncm->lock); - } else - goto fail; - - return 0; -fail: - return -EINVAL; -} - -/* - * Because the data interface supports multiple altsettings, - * this NCM function *MUST* implement a get_alt() method. - */ -static int ncm_get_alt(struct usb_function *f, unsigned intf) -{ - struct f_ncm *ncm = func_to_ncm(f); - - if (intf == ncm->ctrl_id) - return 0; - return ncm->port.in_ep->driver_data ? 1 : 0; -} - -static struct sk_buff *ncm_wrap_ntb(struct gether *port, - struct sk_buff *skb) -{ - struct f_ncm *ncm = func_to_ncm(&port->func); - struct sk_buff *skb2; - int ncb_len = 0; - __le16 *tmp; - int div = ntb_parameters.wNdpInDivisor; - int rem = ntb_parameters.wNdpInPayloadRemainder; - int pad; - int ndp_align = ntb_parameters.wNdpInAlignment; - int ndp_pad; - unsigned max_size = ncm->port.fixed_in_len; - struct ndp_parser_opts *opts = ncm->parser_opts; - unsigned crc_len = ncm->is_crc ? sizeof(uint32_t) : 0; - - ncb_len += opts->nth_size; - ndp_pad = ALIGN(ncb_len, ndp_align) - ncb_len; - ncb_len += ndp_pad; - ncb_len += opts->ndp_size; - ncb_len += 2 * 2 * opts->dgram_item_len; /* Datagram entry */ - ncb_len += 2 * 2 * opts->dgram_item_len; /* Zero datagram entry */ - pad = ALIGN(ncb_len, div) + rem - ncb_len; - ncb_len += pad; - - if (ncb_len + skb->len + crc_len > max_size) { - dev_kfree_skb_any(skb); - return NULL; - } - - skb2 = skb_copy_expand(skb, ncb_len, - max_size - skb->len - ncb_len - crc_len, - GFP_ATOMIC); - dev_kfree_skb_any(skb); - if (!skb2) - return NULL; - - skb = skb2; - - tmp = (void *) skb_push(skb, ncb_len); - memset(tmp, 0, ncb_len); - - put_unaligned_le32(opts->nth_sign, tmp); /* dwSignature */ - tmp += 2; - /* wHeaderLength */ - put_unaligned_le16(opts->nth_size, tmp++); - tmp++; /* skip wSequence */ - put_ncm(&tmp, opts->block_length, skb->len); /* (d)wBlockLength */ - /* (d)wFpIndex */ - /* the first pointer is right after the NTH + align */ - put_ncm(&tmp, opts->fp_index, opts->nth_size + ndp_pad); - - tmp = (void *)tmp + ndp_pad; - - /* NDP */ - put_unaligned_le32(opts->ndp_sign, tmp); /* dwSignature */ - tmp += 2; - /* wLength */ - put_unaligned_le16(ncb_len - opts->nth_size - pad, tmp++); - - tmp += opts->reserved1; - tmp += opts->next_fp_index; /* skip reserved (d)wNextFpIndex */ - tmp += opts->reserved2; - - if (ncm->is_crc) { - uint32_t crc; - - crc = ~crc32_le(~0, - skb->data + ncb_len, - skb->len - ncb_len); - put_unaligned_le32(crc, skb->data + skb->len); - skb_put(skb, crc_len); - } - - /* (d)wDatagramIndex[0] */ - put_ncm(&tmp, opts->dgram_item_len, ncb_len); - /* (d)wDatagramLength[0] */ - put_ncm(&tmp, opts->dgram_item_len, skb->len - ncb_len); - /* (d)wDatagramIndex[1] and (d)wDatagramLength[1] already zeroed */ - - if (skb->len > MAX_TX_NONFIXED) - memset(skb_put(skb, max_size - skb->len), - 0, max_size - skb->len); - - return skb; -} - -static int ncm_unwrap_ntb(struct gether *port, - struct sk_buff *skb, - struct sk_buff_head *list) -{ - struct f_ncm *ncm = func_to_ncm(&port->func); - __le16 *tmp = (void *) skb->data; - unsigned index, index2; - unsigned dg_len, dg_len2; - unsigned ndp_len; - struct sk_buff *skb2; - int ret = -EINVAL; - unsigned max_size = le32_to_cpu(ntb_parameters.dwNtbOutMaxSize); - struct ndp_parser_opts *opts = ncm->parser_opts; - unsigned crc_len = ncm->is_crc ? sizeof(uint32_t) : 0; - int dgram_counter; - - /* dwSignature */ - if (get_unaligned_le32(tmp) != opts->nth_sign) { - INFO(port->func.config->cdev, "Wrong NTH SIGN, skblen %d\n", - skb->len); - print_hex_dump(KERN_INFO, "HEAD:", DUMP_PREFIX_ADDRESS, 32, 1, - skb->data, 32, false); - - goto err; - } - tmp += 2; - /* wHeaderLength */ - if (get_unaligned_le16(tmp++) != opts->nth_size) { - INFO(port->func.config->cdev, "Wrong NTB headersize\n"); - goto err; - } - tmp++; /* skip wSequence */ - - /* (d)wBlockLength */ - if (get_ncm(&tmp, opts->block_length) > max_size) { - INFO(port->func.config->cdev, "OUT size exceeded\n"); - goto err; - } - - index = get_ncm(&tmp, opts->fp_index); - /* NCM 3.2 */ - if (((index % 4) != 0) && (index < opts->nth_size)) { - INFO(port->func.config->cdev, "Bad index: %x\n", - index); - goto err; - } - - /* walk through NDP */ - tmp = ((void *)skb->data) + index; - if (get_unaligned_le32(tmp) != opts->ndp_sign) { - INFO(port->func.config->cdev, "Wrong NDP SIGN\n"); - goto err; - } - tmp += 2; - - ndp_len = get_unaligned_le16(tmp++); - /* - * NCM 3.3.1 - * entry is 2 items - * item size is 16/32 bits, opts->dgram_item_len * 2 bytes - * minimal: struct usb_cdc_ncm_ndpX + normal entry + zero entry - */ - if ((ndp_len < opts->ndp_size + 2 * 2 * (opts->dgram_item_len * 2)) - || (ndp_len % opts->ndplen_align != 0)) { - INFO(port->func.config->cdev, "Bad NDP length: %x\n", ndp_len); - goto err; - } - tmp += opts->reserved1; - tmp += opts->next_fp_index; /* skip reserved (d)wNextFpIndex */ - tmp += opts->reserved2; - - ndp_len -= opts->ndp_size; - index2 = get_ncm(&tmp, opts->dgram_item_len); - dg_len2 = get_ncm(&tmp, opts->dgram_item_len); - dgram_counter = 0; - - do { - index = index2; - dg_len = dg_len2; - if (dg_len < 14 + crc_len) { /* ethernet header + crc */ - INFO(port->func.config->cdev, "Bad dgram length: %x\n", - dg_len); - goto err; - } - if (ncm->is_crc) { - uint32_t crc, crc2; - - crc = get_unaligned_le32(skb->data + - index + dg_len - crc_len); - crc2 = ~crc32_le(~0, - skb->data + index, - dg_len - crc_len); - if (crc != crc2) { - INFO(port->func.config->cdev, "Bad CRC\n"); - goto err; - } - } - - index2 = get_ncm(&tmp, opts->dgram_item_len); - dg_len2 = get_ncm(&tmp, opts->dgram_item_len); - - if (index2 == 0 || dg_len2 == 0) { - skb2 = skb; - } else { - skb2 = skb_clone(skb, GFP_ATOMIC); - if (skb2 == NULL) - goto err; - } - - if (!skb_pull(skb2, index)) { - ret = -EOVERFLOW; - goto err; - } - - skb_trim(skb2, dg_len - crc_len); - skb_queue_tail(list, skb2); - - ndp_len -= 2 * (opts->dgram_item_len * 2); - - dgram_counter++; - - if (index2 == 0 || dg_len2 == 0) - break; - } while (ndp_len > 2 * (opts->dgram_item_len * 2)); /* zero entry */ - - VDBG(port->func.config->cdev, - "Parsed NTB with %d frames\n", dgram_counter); - return 0; -err: - skb_queue_purge(list); - dev_kfree_skb_any(skb); - return ret; -} - -static void ncm_disable(struct usb_function *f) -{ - struct f_ncm *ncm = func_to_ncm(f); - struct usb_composite_dev *cdev = f->config->cdev; - - DBG(cdev, "ncm deactivated\n"); - - if (ncm->port.in_ep->driver_data) - gether_disconnect(&ncm->port); - - if (ncm->notify->driver_data) { - usb_ep_disable(ncm->notify); - ncm->notify->driver_data = NULL; - ncm->notify->desc = NULL; - } -} - -/*-------------------------------------------------------------------------*/ - -/* - * Callbacks let us notify the host about connect/disconnect when the - * net device is opened or closed. - * - * For testing, note that link states on this side include both opened - * and closed variants of: - * - * - disconnected/unconfigured - * - configured but inactive (data alt 0) - * - configured and active (data alt 1) - * - * Each needs to be tested with unplug, rmmod, SET_CONFIGURATION, and - * SET_INTERFACE (altsetting). Remember also that "configured" doesn't - * imply the host is actually polling the notification endpoint, and - * likewise that "active" doesn't imply it's actually using the data - * endpoints for traffic. - */ - -static void ncm_open(struct gether *geth) -{ - struct f_ncm *ncm = func_to_ncm(&geth->func); - - DBG(ncm->port.func.config->cdev, "%s\n", __func__); - - spin_lock(&ncm->lock); - ncm->is_open = true; - ncm_notify(ncm); - spin_unlock(&ncm->lock); -} - -static void ncm_close(struct gether *geth) -{ - struct f_ncm *ncm = func_to_ncm(&geth->func); - - DBG(ncm->port.func.config->cdev, "%s\n", __func__); - - spin_lock(&ncm->lock); - ncm->is_open = false; - ncm_notify(ncm); - spin_unlock(&ncm->lock); -} - -/*-------------------------------------------------------------------------*/ - -/* ethernet function driver setup/binding */ - -static int __init -ncm_bind(struct usb_configuration *c, struct usb_function *f) -{ - struct usb_composite_dev *cdev = c->cdev; - struct f_ncm *ncm = func_to_ncm(f); - int status; - struct usb_ep *ep; - - /* allocate instance-specific interface IDs */ - status = usb_interface_id(c, f); - if (status < 0) - goto fail; - ncm->ctrl_id = status; - ncm_iad_desc.bFirstInterface = status; - - ncm_control_intf.bInterfaceNumber = status; - ncm_union_desc.bMasterInterface0 = status; - - status = usb_interface_id(c, f); - if (status < 0) - goto fail; - ncm->data_id = status; - - ncm_data_nop_intf.bInterfaceNumber = status; - ncm_data_intf.bInterfaceNumber = status; - ncm_union_desc.bSlaveInterface0 = status; - - status = -ENODEV; - - /* allocate instance-specific endpoints */ - ep = usb_ep_autoconfig(cdev->gadget, &fs_ncm_in_desc); - if (!ep) - goto fail; - ncm->port.in_ep = ep; - ep->driver_data = cdev; /* claim */ - - ep = usb_ep_autoconfig(cdev->gadget, &fs_ncm_out_desc); - if (!ep) - goto fail; - ncm->port.out_ep = ep; - ep->driver_data = cdev; /* claim */ - - ep = usb_ep_autoconfig(cdev->gadget, &fs_ncm_notify_desc); - if (!ep) - goto fail; - ncm->notify = ep; - ep->driver_data = cdev; /* claim */ - - status = -ENOMEM; - - /* allocate notification request and buffer */ - ncm->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL); - if (!ncm->notify_req) - goto fail; - ncm->notify_req->buf = kmalloc(NCM_STATUS_BYTECOUNT, GFP_KERNEL); - if (!ncm->notify_req->buf) - goto fail; - ncm->notify_req->context = ncm; - ncm->notify_req->complete = ncm_notify_complete; - - /* copy descriptors, and track endpoint copies */ - f->descriptors = usb_copy_descriptors(ncm_fs_function); - if (!f->descriptors) - goto fail; - - /* - * support all relevant hardware speeds... we expect that when - * hardware is dual speed, all bulk-capable endpoints work at - * both speeds - */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - hs_ncm_in_desc.bEndpointAddress = - fs_ncm_in_desc.bEndpointAddress; - hs_ncm_out_desc.bEndpointAddress = - fs_ncm_out_desc.bEndpointAddress; - hs_ncm_notify_desc.bEndpointAddress = - fs_ncm_notify_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->hs_descriptors = usb_copy_descriptors(ncm_hs_function); - if (!f->hs_descriptors) - goto fail; - } - - /* - * NOTE: all that is done without knowing or caring about - * the network link ... which is unavailable to this code - * until we're activated via set_alt(). - */ - - ncm->port.open = ncm_open; - ncm->port.close = ncm_close; - - DBG(cdev, "CDC Network: %s speed IN/%s OUT/%s NOTIFY/%s\n", - gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", - ncm->port.in_ep->name, ncm->port.out_ep->name, - ncm->notify->name); - return 0; - -fail: - if (f->descriptors) - usb_free_descriptors(f->descriptors); - - if (ncm->notify_req) { - kfree(ncm->notify_req->buf); - usb_ep_free_request(ncm->notify, ncm->notify_req); - } - - /* we might as well release our claims on endpoints */ - if (ncm->notify) - ncm->notify->driver_data = NULL; - if (ncm->port.out_ep->desc) - ncm->port.out_ep->driver_data = NULL; - if (ncm->port.in_ep->desc) - ncm->port.in_ep->driver_data = NULL; - - ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); - - return status; -} - -static void -ncm_unbind(struct usb_configuration *c, struct usb_function *f) -{ - struct f_ncm *ncm = func_to_ncm(f); - - DBG(c->cdev, "ncm unbind\n"); - - if (gadget_is_dualspeed(c->cdev->gadget)) - usb_free_descriptors(f->hs_descriptors); - usb_free_descriptors(f->descriptors); - - kfree(ncm->notify_req->buf); - usb_ep_free_request(ncm->notify, ncm->notify_req); - - ncm_string_defs[1].s = NULL; - kfree(ncm); -} - -/** - * ncm_bind_config - add CDC Network link to a configuration - * @c: the configuration to support the network link - * @ethaddr: a buffer in which the ethernet address of the host side - * side of the link was recorded - * Context: single threaded during gadget setup - * - * Returns zero on success, else negative errno. - * - * Caller must have called @gether_setup(). Caller is also responsible - * for calling @gether_cleanup() before module unload. - */ -int __init ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) -{ - struct f_ncm *ncm; - int status; - - if (!can_support_ecm(c->cdev->gadget) || !ethaddr) - return -EINVAL; - - /* maybe allocate device-global string IDs */ - if (ncm_string_defs[0].id == 0) { - - /* control interface label */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - ncm_string_defs[STRING_CTRL_IDX].id = status; - ncm_control_intf.iInterface = status; - - /* data interface label */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - ncm_string_defs[STRING_DATA_IDX].id = status; - ncm_data_nop_intf.iInterface = status; - ncm_data_intf.iInterface = status; - - /* MAC address */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - ncm_string_defs[STRING_MAC_IDX].id = status; - ecm_desc.iMACAddress = status; - - /* IAD */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - ncm_string_defs[STRING_IAD_IDX].id = status; - ncm_iad_desc.iFunction = status; - } - - /* allocate and initialize one new instance */ - ncm = kzalloc(sizeof *ncm, GFP_KERNEL); - if (!ncm) - return -ENOMEM; - - /* export host's Ethernet address in CDC format */ - snprintf(ncm->ethaddr, sizeof ncm->ethaddr, - "%02X%02X%02X%02X%02X%02X", - ethaddr[0], ethaddr[1], ethaddr[2], - ethaddr[3], ethaddr[4], ethaddr[5]); - ncm_string_defs[1].s = ncm->ethaddr; - - spin_lock_init(&ncm->lock); - ncm_reset_values(ncm); - ncm->port.is_fixed = true; - - ncm->port.func.name = "cdc_network"; - ncm->port.func.strings = ncm_strings; - /* descriptors are per-instance copies */ - ncm->port.func.bind = ncm_bind; - ncm->port.func.unbind = ncm_unbind; - ncm->port.func.set_alt = ncm_set_alt; - ncm->port.func.get_alt = ncm_get_alt; - ncm->port.func.setup = ncm_setup; - ncm->port.func.disable = ncm_disable; - - ncm->port.wrap = ncm_wrap_ntb; - ncm->port.unwrap = ncm_unwrap_ntb; - - status = usb_add_function(c, &ncm->port.func); - if (status) { - ncm_string_defs[1].s = NULL; - kfree(ncm); - } - return status; -} diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_obex.c b/ANDROID_3.4.5/drivers/usb/gadget/f_obex.c deleted file mode 100644 index 5f400f66..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_obex.c +++ /dev/null @@ -1,471 +0,0 @@ -/* - * f_obex.c -- USB CDC OBEX function driver - * - * Copyright (C) 2008 Nokia Corporation - * Contact: Felipe Balbi - * - * Based on f_acm.c by Al Borchers and David Brownell. - * - * 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. - */ - -/* #define VERBOSE_DEBUG */ - -#include -#include -#include -#include - -#include "u_serial.h" -#include "gadget_chips.h" - - -/* - * This CDC OBEX function support just packages a TTY-ish byte stream. - * A user mode server will put it into "raw" mode and handle all the - * relevant protocol details ... this is just a kernel passthrough. - * When possible, we prevent gadget enumeration until that server is - * ready to handle the commands. - */ - -struct f_obex { - struct gserial port; - u8 ctrl_id; - u8 data_id; - u8 port_num; - u8 can_activate; -}; - -static inline struct f_obex *func_to_obex(struct usb_function *f) -{ - return container_of(f, struct f_obex, port.func); -} - -static inline struct f_obex *port_to_obex(struct gserial *p) -{ - return container_of(p, struct f_obex, port); -} - -/*-------------------------------------------------------------------------*/ - -#define OBEX_CTRL_IDX 0 -#define OBEX_DATA_IDX 1 - -static struct usb_string obex_string_defs[] = { - [OBEX_CTRL_IDX].s = "CDC Object Exchange (OBEX)", - [OBEX_DATA_IDX].s = "CDC OBEX Data", - { }, /* end of list */ -}; - -static struct usb_gadget_strings obex_string_table = { - .language = 0x0409, /* en-US */ - .strings = obex_string_defs, -}; - -static struct usb_gadget_strings *obex_strings[] = { - &obex_string_table, - NULL, -}; - -/*-------------------------------------------------------------------------*/ - -static struct usb_interface_descriptor obex_control_intf __initdata = { - .bLength = sizeof(obex_control_intf), - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, - - .bAlternateSetting = 0, - .bNumEndpoints = 0, - .bInterfaceClass = USB_CLASS_COMM, - .bInterfaceSubClass = USB_CDC_SUBCLASS_OBEX, -}; - -static struct usb_interface_descriptor obex_data_nop_intf __initdata = { - .bLength = sizeof(obex_data_nop_intf), - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 1, - - .bAlternateSetting = 0, - .bNumEndpoints = 0, - .bInterfaceClass = USB_CLASS_CDC_DATA, -}; - -static struct usb_interface_descriptor obex_data_intf __initdata = { - .bLength = sizeof(obex_data_intf), - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 2, - - .bAlternateSetting = 1, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_CDC_DATA, -}; - -static struct usb_cdc_header_desc obex_cdc_header_desc __initdata = { - .bLength = sizeof(obex_cdc_header_desc), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_HEADER_TYPE, - .bcdCDC = cpu_to_le16(0x0120), -}; - -static struct usb_cdc_union_desc obex_cdc_union_desc __initdata = { - .bLength = sizeof(obex_cdc_union_desc), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_UNION_TYPE, - .bMasterInterface0 = 1, - .bSlaveInterface0 = 2, -}; - -static struct usb_cdc_obex_desc obex_desc __initdata = { - .bLength = sizeof(obex_desc), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_OBEX_TYPE, - .bcdVersion = cpu_to_le16(0x0100), -}; - -/* High-Speed Support */ - -static struct usb_endpoint_descriptor obex_hs_ep_out_desc __initdata = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), -}; - -static struct usb_endpoint_descriptor obex_hs_ep_in_desc __initdata = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), -}; - -static struct usb_descriptor_header *hs_function[] __initdata = { - (struct usb_descriptor_header *) &obex_control_intf, - (struct usb_descriptor_header *) &obex_cdc_header_desc, - (struct usb_descriptor_header *) &obex_desc, - (struct usb_descriptor_header *) &obex_cdc_union_desc, - - (struct usb_descriptor_header *) &obex_data_nop_intf, - (struct usb_descriptor_header *) &obex_data_intf, - (struct usb_descriptor_header *) &obex_hs_ep_in_desc, - (struct usb_descriptor_header *) &obex_hs_ep_out_desc, - NULL, -}; - -/* Full-Speed Support */ - -static struct usb_endpoint_descriptor obex_fs_ep_in_desc __initdata = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_endpoint_descriptor obex_fs_ep_out_desc __initdata = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_descriptor_header *fs_function[] __initdata = { - (struct usb_descriptor_header *) &obex_control_intf, - (struct usb_descriptor_header *) &obex_cdc_header_desc, - (struct usb_descriptor_header *) &obex_desc, - (struct usb_descriptor_header *) &obex_cdc_union_desc, - - (struct usb_descriptor_header *) &obex_data_nop_intf, - (struct usb_descriptor_header *) &obex_data_intf, - (struct usb_descriptor_header *) &obex_fs_ep_in_desc, - (struct usb_descriptor_header *) &obex_fs_ep_out_desc, - NULL, -}; - -/*-------------------------------------------------------------------------*/ - -static int obex_set_alt(struct usb_function *f, unsigned intf, unsigned alt) -{ - struct f_obex *obex = func_to_obex(f); - struct usb_composite_dev *cdev = f->config->cdev; - - if (intf == obex->ctrl_id) { - if (alt != 0) - goto fail; - /* NOP */ - DBG(cdev, "reset obex ttyGS%d control\n", obex->port_num); - - } else if (intf == obex->data_id) { - if (alt > 1) - goto fail; - - if (obex->port.in->driver_data) { - DBG(cdev, "reset obex ttyGS%d\n", obex->port_num); - gserial_disconnect(&obex->port); - } - - if (!obex->port.in->desc || !obex->port.out->desc) { - DBG(cdev, "init obex ttyGS%d\n", obex->port_num); - if (config_ep_by_speed(cdev->gadget, f, - obex->port.in) || - config_ep_by_speed(cdev->gadget, f, - obex->port.out)) { - obex->port.out->desc = NULL; - obex->port.in->desc = NULL; - goto fail; - } - } - - if (alt == 1) { - DBG(cdev, "activate obex ttyGS%d\n", obex->port_num); - gserial_connect(&obex->port, obex->port_num); - } - - } else - goto fail; - - return 0; - -fail: - return -EINVAL; -} - -static int obex_get_alt(struct usb_function *f, unsigned intf) -{ - struct f_obex *obex = func_to_obex(f); - - if (intf == obex->ctrl_id) - return 0; - - return obex->port.in->driver_data ? 1 : 0; -} - -static void obex_disable(struct usb_function *f) -{ - struct f_obex *obex = func_to_obex(f); - struct usb_composite_dev *cdev = f->config->cdev; - - DBG(cdev, "obex ttyGS%d disable\n", obex->port_num); - gserial_disconnect(&obex->port); -} - -/*-------------------------------------------------------------------------*/ - -static void obex_connect(struct gserial *g) -{ - struct f_obex *obex = port_to_obex(g); - struct usb_composite_dev *cdev = g->func.config->cdev; - int status; - - if (!obex->can_activate) - return; - - status = usb_function_activate(&g->func); - if (status) - DBG(cdev, "obex ttyGS%d function activate --> %d\n", - obex->port_num, status); -} - -static void obex_disconnect(struct gserial *g) -{ - struct f_obex *obex = port_to_obex(g); - struct usb_composite_dev *cdev = g->func.config->cdev; - int status; - - if (!obex->can_activate) - return; - - status = usb_function_deactivate(&g->func); - if (status) - DBG(cdev, "obex ttyGS%d function deactivate --> %d\n", - obex->port_num, status); -} - -/*-------------------------------------------------------------------------*/ - -static int __init -obex_bind(struct usb_configuration *c, struct usb_function *f) -{ - struct usb_composite_dev *cdev = c->cdev; - struct f_obex *obex = func_to_obex(f); - int status; - struct usb_ep *ep; - - /* allocate instance-specific interface IDs, and patch descriptors */ - - status = usb_interface_id(c, f); - if (status < 0) - goto fail; - obex->ctrl_id = status; - - obex_control_intf.bInterfaceNumber = status; - obex_cdc_union_desc.bMasterInterface0 = status; - - status = usb_interface_id(c, f); - if (status < 0) - goto fail; - obex->data_id = status; - - obex_data_nop_intf.bInterfaceNumber = status; - obex_data_intf.bInterfaceNumber = status; - obex_cdc_union_desc.bSlaveInterface0 = status; - - /* allocate instance-specific endpoints */ - - ep = usb_ep_autoconfig(cdev->gadget, &obex_fs_ep_in_desc); - if (!ep) - goto fail; - obex->port.in = ep; - ep->driver_data = cdev; /* claim */ - - ep = usb_ep_autoconfig(cdev->gadget, &obex_fs_ep_out_desc); - if (!ep) - goto fail; - obex->port.out = ep; - ep->driver_data = cdev; /* claim */ - - /* copy descriptors, and track endpoint copies */ - f->descriptors = usb_copy_descriptors(fs_function); - - /* support all relevant hardware speeds... we expect that when - * hardware is dual speed, all bulk-capable endpoints work at - * both speeds - */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - - obex_hs_ep_in_desc.bEndpointAddress = - obex_fs_ep_in_desc.bEndpointAddress; - obex_hs_ep_out_desc.bEndpointAddress = - obex_fs_ep_out_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->hs_descriptors = usb_copy_descriptors(hs_function); - } - - /* Avoid letting this gadget enumerate until the userspace - * OBEX server is active. - */ - status = usb_function_deactivate(f); - if (status < 0) - WARNING(cdev, "obex ttyGS%d: can't prevent enumeration, %d\n", - obex->port_num, status); - else - obex->can_activate = true; - - - DBG(cdev, "obex ttyGS%d: %s speed IN/%s OUT/%s\n", - obex->port_num, - gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", - obex->port.in->name, obex->port.out->name); - - return 0; - -fail: - /* we might as well release our claims on endpoints */ - if (obex->port.out) - obex->port.out->driver_data = NULL; - if (obex->port.in) - obex->port.in->driver_data = NULL; - - ERROR(cdev, "%s/%p: can't bind, err %d\n", f->name, f, status); - - return status; -} - -static void -obex_unbind(struct usb_configuration *c, struct usb_function *f) -{ - if (gadget_is_dualspeed(c->cdev->gadget)) - usb_free_descriptors(f->hs_descriptors); - usb_free_descriptors(f->descriptors); - kfree(func_to_obex(f)); -} - -/* Some controllers can't support CDC OBEX ... */ -static inline bool can_support_obex(struct usb_configuration *c) -{ - /* Since the first interface is a NOP, we can ignore the - * issue of multi-interface support on most controllers. - * - * Altsettings are mandatory, however... - */ - if (!gadget_supports_altsettings(c->cdev->gadget)) - return false; - - /* everything else is *probably* fine ... */ - return true; -} - -/** - * obex_bind_config - add a CDC OBEX function to a configuration - * @c: the configuration to support the CDC OBEX instance - * @port_num: /dev/ttyGS* port this interface will use - * Context: single threaded during gadget setup - * - * Returns zero on success, else negative errno. - * - * Caller must have called @gserial_setup() with enough ports to - * handle all the ones it binds. Caller is also responsible - * for calling @gserial_cleanup() before module unload. - */ -int __init obex_bind_config(struct usb_configuration *c, u8 port_num) -{ - struct f_obex *obex; - int status; - - if (!can_support_obex(c)) - return -EINVAL; - - /* maybe allocate device-global string IDs, and patch descriptors */ - if (obex_string_defs[OBEX_CTRL_IDX].id == 0) { - status = usb_string_id(c->cdev); - if (status < 0) - return status; - obex_string_defs[OBEX_CTRL_IDX].id = status; - - obex_control_intf.iInterface = status; - - status = usb_string_id(c->cdev); - if (status < 0) - return status; - obex_string_defs[OBEX_DATA_IDX].id = status; - - obex_data_nop_intf.iInterface = - obex_data_intf.iInterface = status; - } - - /* allocate and initialize one new instance */ - obex = kzalloc(sizeof *obex, GFP_KERNEL); - if (!obex) - return -ENOMEM; - - obex->port_num = port_num; - - obex->port.connect = obex_connect; - obex->port.disconnect = obex_disconnect; - - obex->port.func.name = "obex"; - obex->port.func.strings = obex_strings; - /* descriptors are per-instance copies */ - obex->port.func.bind = obex_bind; - obex->port.func.unbind = obex_unbind; - obex->port.func.set_alt = obex_set_alt; - obex->port.func.get_alt = obex_get_alt; - obex->port.func.disable = obex_disable; - - status = usb_add_function(c, &obex->port.func); - if (status) - kfree(obex); - - return status; -} - -MODULE_AUTHOR("Felipe Balbi"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_phonet.c b/ANDROID_3.4.5/drivers/usb/gadget/f_phonet.c deleted file mode 100644 index 965a6293..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_phonet.c +++ /dev/null @@ -1,629 +0,0 @@ -/* - * f_phonet.c -- USB CDC Phonet function - * - * Copyright (C) 2007-2008 Nokia Corporation. All rights reserved. - * - * Author: Rémi Denis-Courmont - * - * 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. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include "u_phonet.h" - -#define PN_MEDIA_USB 0x1B -#define MAXPACKET 512 -#if (PAGE_SIZE % MAXPACKET) -#error MAXPACKET must divide PAGE_SIZE! -#endif - -/*-------------------------------------------------------------------------*/ - -struct phonet_port { - struct f_phonet *usb; - spinlock_t lock; -}; - -struct f_phonet { - struct usb_function function; - struct { - struct sk_buff *skb; - spinlock_t lock; - } rx; - struct net_device *dev; - struct usb_ep *in_ep, *out_ep; - - struct usb_request *in_req; - struct usb_request *out_reqv[0]; -}; - -static int phonet_rxq_size = 17; - -static inline struct f_phonet *func_to_pn(struct usb_function *f) -{ - return container_of(f, struct f_phonet, function); -} - -/*-------------------------------------------------------------------------*/ - -#define USB_CDC_SUBCLASS_PHONET 0xfe -#define USB_CDC_PHONET_TYPE 0xab - -static struct usb_interface_descriptor -pn_control_intf_desc = { - .bLength = sizeof pn_control_intf_desc, - .bDescriptorType = USB_DT_INTERFACE, - - /* .bInterfaceNumber = DYNAMIC, */ - .bInterfaceClass = USB_CLASS_COMM, - .bInterfaceSubClass = USB_CDC_SUBCLASS_PHONET, -}; - -static const struct usb_cdc_header_desc -pn_header_desc = { - .bLength = sizeof pn_header_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_HEADER_TYPE, - .bcdCDC = cpu_to_le16(0x0110), -}; - -static const struct usb_cdc_header_desc -pn_phonet_desc = { - .bLength = sizeof pn_phonet_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_PHONET_TYPE, - .bcdCDC = cpu_to_le16(0x1505), /* ??? */ -}; - -static struct usb_cdc_union_desc -pn_union_desc = { - .bLength = sizeof pn_union_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_UNION_TYPE, - - /* .bMasterInterface0 = DYNAMIC, */ - /* .bSlaveInterface0 = DYNAMIC, */ -}; - -static struct usb_interface_descriptor -pn_data_nop_intf_desc = { - .bLength = sizeof pn_data_nop_intf_desc, - .bDescriptorType = USB_DT_INTERFACE, - - /* .bInterfaceNumber = DYNAMIC, */ - .bAlternateSetting = 0, - .bNumEndpoints = 0, - .bInterfaceClass = USB_CLASS_CDC_DATA, -}; - -static struct usb_interface_descriptor -pn_data_intf_desc = { - .bLength = sizeof pn_data_intf_desc, - .bDescriptorType = USB_DT_INTERFACE, - - /* .bInterfaceNumber = DYNAMIC, */ - .bAlternateSetting = 1, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_CDC_DATA, -}; - -static struct usb_endpoint_descriptor -pn_fs_sink_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_endpoint_descriptor -pn_hs_sink_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(MAXPACKET), -}; - -static struct usb_endpoint_descriptor -pn_fs_source_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_endpoint_descriptor -pn_hs_source_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), -}; - -static struct usb_descriptor_header *fs_pn_function[] = { - (struct usb_descriptor_header *) &pn_control_intf_desc, - (struct usb_descriptor_header *) &pn_header_desc, - (struct usb_descriptor_header *) &pn_phonet_desc, - (struct usb_descriptor_header *) &pn_union_desc, - (struct usb_descriptor_header *) &pn_data_nop_intf_desc, - (struct usb_descriptor_header *) &pn_data_intf_desc, - (struct usb_descriptor_header *) &pn_fs_sink_desc, - (struct usb_descriptor_header *) &pn_fs_source_desc, - NULL, -}; - -static struct usb_descriptor_header *hs_pn_function[] = { - (struct usb_descriptor_header *) &pn_control_intf_desc, - (struct usb_descriptor_header *) &pn_header_desc, - (struct usb_descriptor_header *) &pn_phonet_desc, - (struct usb_descriptor_header *) &pn_union_desc, - (struct usb_descriptor_header *) &pn_data_nop_intf_desc, - (struct usb_descriptor_header *) &pn_data_intf_desc, - (struct usb_descriptor_header *) &pn_hs_sink_desc, - (struct usb_descriptor_header *) &pn_hs_source_desc, - NULL, -}; - -/*-------------------------------------------------------------------------*/ - -static int pn_net_open(struct net_device *dev) -{ - netif_wake_queue(dev); - return 0; -} - -static int pn_net_close(struct net_device *dev) -{ - netif_stop_queue(dev); - return 0; -} - -static void pn_tx_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct f_phonet *fp = ep->driver_data; - struct net_device *dev = fp->dev; - struct sk_buff *skb = req->context; - - switch (req->status) { - case 0: - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; - break; - - case -ESHUTDOWN: /* disconnected */ - case -ECONNRESET: /* disabled */ - dev->stats.tx_aborted_errors++; - default: - dev->stats.tx_errors++; - } - - dev_kfree_skb_any(skb); - netif_wake_queue(dev); -} - -static int pn_net_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct phonet_port *port = netdev_priv(dev); - struct f_phonet *fp; - struct usb_request *req; - unsigned long flags; - - if (skb->protocol != htons(ETH_P_PHONET)) - goto out; - - spin_lock_irqsave(&port->lock, flags); - fp = port->usb; - if (unlikely(!fp)) /* race with carrier loss */ - goto out_unlock; - - req = fp->in_req; - req->buf = skb->data; - req->length = skb->len; - req->complete = pn_tx_complete; - req->zero = 1; - req->context = skb; - - if (unlikely(usb_ep_queue(fp->in_ep, req, GFP_ATOMIC))) - goto out_unlock; - - netif_stop_queue(dev); - skb = NULL; - -out_unlock: - spin_unlock_irqrestore(&port->lock, flags); -out: - if (unlikely(skb)) { - dev_kfree_skb(skb); - dev->stats.tx_dropped++; - } - return NETDEV_TX_OK; -} - -static int pn_net_mtu(struct net_device *dev, int new_mtu) -{ - if ((new_mtu < PHONET_MIN_MTU) || (new_mtu > PHONET_MAX_MTU)) - return -EINVAL; - dev->mtu = new_mtu; - return 0; -} - -static const struct net_device_ops pn_netdev_ops = { - .ndo_open = pn_net_open, - .ndo_stop = pn_net_close, - .ndo_start_xmit = pn_net_xmit, - .ndo_change_mtu = pn_net_mtu, -}; - -static void pn_net_setup(struct net_device *dev) -{ - dev->features = 0; - dev->type = ARPHRD_PHONET; - dev->flags = IFF_POINTOPOINT | IFF_NOARP; - dev->mtu = PHONET_DEV_MTU; - dev->hard_header_len = 1; - dev->dev_addr[0] = PN_MEDIA_USB; - dev->addr_len = 1; - dev->tx_queue_len = 1; - - dev->netdev_ops = &pn_netdev_ops; - dev->destructor = free_netdev; - dev->header_ops = &phonet_header_ops; -} - -/*-------------------------------------------------------------------------*/ - -/* - * Queue buffer for data from the host - */ -static int -pn_rx_submit(struct f_phonet *fp, struct usb_request *req, gfp_t gfp_flags) -{ - struct page *page; - int err; - - page = alloc_page(gfp_flags); - if (!page) - return -ENOMEM; - - req->buf = page_address(page); - req->length = PAGE_SIZE; - req->context = page; - - err = usb_ep_queue(fp->out_ep, req, gfp_flags); - if (unlikely(err)) - put_page(page); - return err; -} - -static void pn_rx_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct f_phonet *fp = ep->driver_data; - struct net_device *dev = fp->dev; - struct page *page = req->context; - struct sk_buff *skb; - unsigned long flags; - int status = req->status; - - switch (status) { - case 0: - spin_lock_irqsave(&fp->rx.lock, flags); - skb = fp->rx.skb; - if (!skb) - skb = fp->rx.skb = netdev_alloc_skb(dev, 12); - if (req->actual < req->length) /* Last fragment */ - fp->rx.skb = NULL; - spin_unlock_irqrestore(&fp->rx.lock, flags); - - if (unlikely(!skb)) - break; - - if (skb->len == 0) { /* First fragment */ - skb->protocol = htons(ETH_P_PHONET); - skb_reset_mac_header(skb); - /* Can't use pskb_pull() on page in IRQ */ - memcpy(skb_put(skb, 1), page_address(page), 1); - } - - skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, - skb->len <= 1, req->actual, PAGE_SIZE); - page = NULL; - - if (req->actual < req->length) { /* Last fragment */ - skb->dev = dev; - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; - - netif_rx(skb); - } - break; - - /* Do not resubmit in these cases: */ - case -ESHUTDOWN: /* disconnect */ - case -ECONNABORTED: /* hw reset */ - case -ECONNRESET: /* dequeued (unlink or netif down) */ - req = NULL; - break; - - /* Do resubmit in these cases: */ - case -EOVERFLOW: /* request buffer overflow */ - dev->stats.rx_over_errors++; - default: - dev->stats.rx_errors++; - break; - } - - if (page) - put_page(page); - if (req) - pn_rx_submit(fp, req, GFP_ATOMIC | __GFP_COLD); -} - -/*-------------------------------------------------------------------------*/ - -static void __pn_reset(struct usb_function *f) -{ - struct f_phonet *fp = func_to_pn(f); - struct net_device *dev = fp->dev; - struct phonet_port *port = netdev_priv(dev); - - netif_carrier_off(dev); - port->usb = NULL; - - usb_ep_disable(fp->out_ep); - usb_ep_disable(fp->in_ep); - if (fp->rx.skb) { - dev_kfree_skb_irq(fp->rx.skb); - fp->rx.skb = NULL; - } -} - -static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt) -{ - struct f_phonet *fp = func_to_pn(f); - struct usb_gadget *gadget = fp->function.config->cdev->gadget; - - if (intf == pn_control_intf_desc.bInterfaceNumber) - /* control interface, no altsetting */ - return (alt > 0) ? -EINVAL : 0; - - if (intf == pn_data_intf_desc.bInterfaceNumber) { - struct net_device *dev = fp->dev; - struct phonet_port *port = netdev_priv(dev); - - /* data intf (0: inactive, 1: active) */ - if (alt > 1) - return -EINVAL; - - spin_lock(&port->lock); - __pn_reset(f); - if (alt == 1) { - int i; - - if (config_ep_by_speed(gadget, f, fp->in_ep) || - config_ep_by_speed(gadget, f, fp->out_ep)) { - fp->in_ep->desc = NULL; - fp->out_ep->desc = NULL; - spin_unlock(&port->lock); - return -EINVAL; - } - usb_ep_enable(fp->out_ep); - usb_ep_enable(fp->in_ep); - - port->usb = fp; - fp->out_ep->driver_data = fp; - fp->in_ep->driver_data = fp; - - netif_carrier_on(dev); - for (i = 0; i < phonet_rxq_size; i++) - pn_rx_submit(fp, fp->out_reqv[i], GFP_ATOMIC | __GFP_COLD); - } - spin_unlock(&port->lock); - return 0; - } - - return -EINVAL; -} - -static int pn_get_alt(struct usb_function *f, unsigned intf) -{ - struct f_phonet *fp = func_to_pn(f); - - if (intf == pn_control_intf_desc.bInterfaceNumber) - return 0; - - if (intf == pn_data_intf_desc.bInterfaceNumber) { - struct phonet_port *port = netdev_priv(fp->dev); - u8 alt; - - spin_lock(&port->lock); - alt = port->usb != NULL; - spin_unlock(&port->lock); - return alt; - } - - return -EINVAL; -} - -static void pn_disconnect(struct usb_function *f) -{ - struct f_phonet *fp = func_to_pn(f); - struct phonet_port *port = netdev_priv(fp->dev); - unsigned long flags; - - /* remain disabled until set_alt */ - spin_lock_irqsave(&port->lock, flags); - __pn_reset(f); - spin_unlock_irqrestore(&port->lock, flags); -} - -/*-------------------------------------------------------------------------*/ - -static __init -int pn_bind(struct usb_configuration *c, struct usb_function *f) -{ - struct usb_composite_dev *cdev = c->cdev; - struct usb_gadget *gadget = cdev->gadget; - struct f_phonet *fp = func_to_pn(f); - struct usb_ep *ep; - int status, i; - - /* Reserve interface IDs */ - status = usb_interface_id(c, f); - if (status < 0) - goto err; - pn_control_intf_desc.bInterfaceNumber = status; - pn_union_desc.bMasterInterface0 = status; - - status = usb_interface_id(c, f); - if (status < 0) - goto err; - pn_data_nop_intf_desc.bInterfaceNumber = status; - pn_data_intf_desc.bInterfaceNumber = status; - pn_union_desc.bSlaveInterface0 = status; - - /* Reserve endpoints */ - status = -ENODEV; - ep = usb_ep_autoconfig(gadget, &pn_fs_sink_desc); - if (!ep) - goto err; - fp->out_ep = ep; - ep->driver_data = fp; /* Claim */ - - ep = usb_ep_autoconfig(gadget, &pn_fs_source_desc); - if (!ep) - goto err; - fp->in_ep = ep; - ep->driver_data = fp; /* Claim */ - - pn_hs_sink_desc.bEndpointAddress = - pn_fs_sink_desc.bEndpointAddress; - pn_hs_source_desc.bEndpointAddress = - pn_fs_source_desc.bEndpointAddress; - - /* Do not try to bind Phonet twice... */ - fp->function.descriptors = fs_pn_function; - fp->function.hs_descriptors = hs_pn_function; - - /* Incoming USB requests */ - status = -ENOMEM; - for (i = 0; i < phonet_rxq_size; i++) { - struct usb_request *req; - - req = usb_ep_alloc_request(fp->out_ep, GFP_KERNEL); - if (!req) - goto err; - - req->complete = pn_rx_complete; - fp->out_reqv[i] = req; - } - - /* Outgoing USB requests */ - fp->in_req = usb_ep_alloc_request(fp->in_ep, GFP_KERNEL); - if (!fp->in_req) - goto err; - - INFO(cdev, "USB CDC Phonet function\n"); - INFO(cdev, "using %s, OUT %s, IN %s\n", cdev->gadget->name, - fp->out_ep->name, fp->in_ep->name); - return 0; - -err: - if (fp->out_ep) - fp->out_ep->driver_data = NULL; - if (fp->in_ep) - fp->in_ep->driver_data = NULL; - ERROR(cdev, "USB CDC Phonet: cannot autoconfigure\n"); - return status; -} - -static void -pn_unbind(struct usb_configuration *c, struct usb_function *f) -{ - struct f_phonet *fp = func_to_pn(f); - int i; - - /* We are already disconnected */ - if (fp->in_req) - usb_ep_free_request(fp->in_ep, fp->in_req); - for (i = 0; i < phonet_rxq_size; i++) - if (fp->out_reqv[i]) - usb_ep_free_request(fp->out_ep, fp->out_reqv[i]); - - kfree(fp); -} - -/*-------------------------------------------------------------------------*/ - -static struct net_device *dev; - -int __init phonet_bind_config(struct usb_configuration *c) -{ - struct f_phonet *fp; - int err, size; - - size = sizeof(*fp) + (phonet_rxq_size * sizeof(struct usb_request *)); - fp = kzalloc(size, GFP_KERNEL); - if (!fp) - return -ENOMEM; - - fp->dev = dev; - fp->function.name = "phonet"; - fp->function.bind = pn_bind; - fp->function.unbind = pn_unbind; - fp->function.set_alt = pn_set_alt; - fp->function.get_alt = pn_get_alt; - fp->function.disable = pn_disconnect; - spin_lock_init(&fp->rx.lock); - - err = usb_add_function(c, &fp->function); - if (err) - kfree(fp); - return err; -} - -int __init gphonet_setup(struct usb_gadget *gadget) -{ - struct phonet_port *port; - int err; - - /* Create net device */ - BUG_ON(dev); - dev = alloc_netdev(sizeof(*port), "upnlink%d", pn_net_setup); - if (!dev) - return -ENOMEM; - - port = netdev_priv(dev); - spin_lock_init(&port->lock); - netif_carrier_off(dev); - SET_NETDEV_DEV(dev, &gadget->dev); - - err = register_netdev(dev); - if (err) - free_netdev(dev); - return err; -} - -void gphonet_cleanup(void) -{ - unregister_netdev(dev); -} diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_rawbulk.c b/ANDROID_3.4.5/drivers/usb/gadget/f_rawbulk.c deleted file mode 100755 index 92bce0fb..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_rawbulk.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Rawbulk Gadget Function Driver from VIA Telecom - * - * Copyright (C) 2011 VIA Telecom, Inc. - * Author: Karfield Chen (kfchen@via-telecom.com) - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - * - */ - -/* #define DEBUG */ -/* #define VERBOSE_DEBUG */ - -#define DRIVER_AUTHOR "Karfield Chen " -#define DRIVER_DESC "Rawbulk Gadget - transport data from CP to Gadget" -#define DRIVER_VERSION "1.0.1" -#define DRIVER_NAME "usb_rawbulk" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -struct usb_composite_dev * wmt_cdev; -#define function_to_rawbulk(f) container_of(f, struct rawbulk_function, function) - -static void simple_setup_complete(struct usb_ep *ep, - struct usb_request *req) { - ;//DO NOTHING -} - -unsigned int dump_mask = 0; -static int rawbulk_function_setup(struct usb_function *f, const struct - usb_ctrlrequest *ctrl) { - int rc; - struct rawbulk_function *fn = function_to_rawbulk(f); - struct usb_composite_dev *cdev = f->config->cdev; - struct usb_request *req = cdev->req; - - if (rawbulk_transfer_state(fn->transfer_id) < 0) - return -EOPNOTSUPP; - - if (dump_mask & (1 << RAWBULK_TID_MODEM)) - printk(KERN_DEBUG "DUMP ctrl: bRequestType = %02X, bRequest = %02X, " \ - "wValue = %04X, wIndex = %04X, wLength = %d\n", - ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, ctrl->wIndex, - ctrl->wLength); - - if (ctrl->bRequestType == 0xc0 && ctrl->bRequest == 0x02) { - /* Query CD109 Status */ - if (rawbulk_check_enable(fn)) - goto forwarding; - *(unsigned char *)req->buf = 0x02; /* Test!!! */ - req->length = 1; - req->complete = simple_setup_complete; - req->zero = 0; - return usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); - } else if (ctrl->bRequestType == 0x40 && ctrl->bRequest == 0x01) { - /* Set/Clear DTR */ - if (rawbulk_check_enable(fn)) - goto forwarding; - req->zero = 0; - return usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); - } else if (ctrl->bRequestType == 0xc0 && ctrl->bRequest == 0x04) { - /* Request CBP Product Name */ - req->length = sprintf(req->buf, "CBP_KUNLUN"); - req->zero = 0; - return usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); - } - - return -EOPNOTSUPP; -forwarding: - rc = rawbulk_forward_ctrlrequest(ctrl); - if (rc < 0) { - printk(KERN_DEBUG "rawbulk forwarding failed %d\n", rc); - return rc; - } - return 256 + 999;//USB_GADGET_DELAYED_STATUS; -} - -static void rawbulk_auto_reconnect(int transfer_id) { - int rc; - struct rawbulk_function *fn = rawbulk_lookup_function(transfer_id); - if (!fn || fn->autoreconn == 0) - return; - - if (rawbulk_check_enable(fn) && fn->activated) { - printk(KERN_DEBUG "start %s again automatically.\n", fn->longname); - rc = rawbulk_start_transactions(transfer_id, fn->nups, - fn->ndowns, fn->upsz, fn->downsz, fn->splitsz, fn->pushable); - if (rc < 0) { - rawbulk_disable_function(fn); - rawbulk_tty_start_io(fn); - } - } -} - -static struct usb_ep *match_ep(struct usb_configuration *c, - struct rawbulk_function *fn, int in) { - struct usb_gadget *gadget = c->cdev->gadget; - struct usb_ep *ep; - struct usb_endpoint_descriptor *desc = - (struct usb_endpoint_descriptor *)(in? fn->fs_descs[BULKIN_DESC]: - fn->fs_descs[BULKOUT_DESC]); - return usb_ep_autoconfig(gadget, desc); -} - -static int rawbulk_function_bind(struct usb_configuration *c, struct - usb_function *f) { - int rc, ifnum; - struct rawbulk_function *fn = function_to_rawbulk(f); - struct usb_gadget *gadget = c->cdev->gadget; - struct usb_ep *ep_out, *ep_in; - - rc = usb_interface_id(c, f); - if (rc < 0) - return rc; - ifnum = rc; - - fn->interface.bInterfaceNumber = cpu_to_le16(ifnum); - - - - usb_ep_autoconfig_reset(c->cdev->gadget); //added by griffen - - - if (!(ep_out = match_ep(c, fn, 0))) { - printk(KERN_DEBUG "unfortunately, we could not find endpoint(OUT) for %s", - fn->longname); - return -ENOMEM; - } - - if (!(ep_in = match_ep(c, fn, 1))) { - printk(KERN_DEBUG "unfortunately, we could not find endpoint(IN) for %s", - fn->longname); - return -ENOMEM; - } - - ep_out->driver_data = fn; - ep_in->driver_data = fn; - fn->bulk_out = ep_out; - fn->bulk_in = ep_in; - - f->descriptors = usb_copy_descriptors(fn->fs_descs); - if (unlikely(!f->descriptors)) - return -ENOMEM; - - if (gadget_is_dualspeed(gadget)) { - fn->hs_bulkin_endpoint.bEndpointAddress = - fn->fs_bulkin_endpoint.bEndpointAddress; - fn->hs_bulkout_endpoint.bEndpointAddress = - fn->fs_bulkout_endpoint.bEndpointAddress; - f->hs_descriptors = usb_copy_descriptors(fn->hs_descs); - if (unlikely(!f->hs_descriptors)) { - usb_free_descriptors(f->descriptors); - return -ENOMEM; - } - } - - fn->cdev = c->cdev; - fn->activated = 0; - - /* - rc = rawbulk_register_tty(fn); - if (rc < 0) - printk(KERN_ERR "failed to register tty for %s\n", fn->longname); - */ - - return rawbulk_bind_function(fn->transfer_id, f, ep_out, ep_in, - rawbulk_auto_reconnect); -} - -static void rawbulk_function_unbind(struct usb_configuration *c, struct - usb_function *f) { - struct rawbulk_function *fn = function_to_rawbulk(f); - - printk(KERN_DEBUG "%s - unbind %s.\n", __func__, fn->longname); - //rawbulk_unregister_tty(fn); - rawbulk_unbind_function(fn->transfer_id); -} - -static void do_activate(struct work_struct *data) { - struct rawbulk_function *fn = container_of(data, struct rawbulk_function, - activator); - int rc; - printk(KERN_DEBUG "%s rawbulk %s channel (enabled? %s).\n", - fn->activated? "activte": "detach", fn->shortname, - rawbulk_check_enable(fn)? "yes": "no"); - if (fn->activated) { /* enumerated */ - int ret; - ret = config_ep_by_speed(wmt_cdev->gadget, &(fn->function), fn->bulk_out); - if (ret) - return ; - - /* enabled endpoints */ - rc = usb_ep_enable(fn->bulk_out); - if (rc < 0) { - printk(KERN_ERR "failed to enable rawbulk %s %d\n", - fn->bulk_out->name, rc); - return; - } - - - ret = config_ep_by_speed(wmt_cdev->gadget, &(fn->function), fn->bulk_in); - if (ret) - return ; - - rc = usb_ep_enable(fn->bulk_in); - if (rc < 0) { - printk(KERN_ERR "failed to enable rawbulk %s %d\n", - fn->bulk_in->name, rc); - usb_ep_disable(fn->bulk_out); - return; - } - - /* start rawbulk if enabled */ - if (rawbulk_check_enable(fn)) { - wake_lock(&fn->keep_awake); - rc = rawbulk_start_transactions(fn->transfer_id, fn->nups, - fn->ndowns, fn->upsz, fn->downsz, fn->splitsz, fn->pushable); - if (rc < 0) - rawbulk_disable_function(fn); - } - - /* start tty io */ - rc = rawbulk_tty_alloc_request(fn); - if (rc < 0) - return; - if (!rawbulk_check_enable(fn)) - rawbulk_tty_start_io(fn); - } else { /* disconnect */ - if (rawbulk_check_enable(fn)) { - if (fn->transfer_id == RAWBULK_TID_MODEM) { - /* this in interrupt, but DTR need be set firstly then clear it - * */ - //control_dtr(0); - } - rawbulk_stop_transactions(fn->transfer_id); - /* keep the enable state, so we can enable again in next time */ - //set_enable_state(fn, 0); - wake_unlock(&fn->keep_awake); - } else - rawbulk_tty_stop_io(fn); - - rawbulk_tty_free_request(fn); - - usb_ep_disable(fn->bulk_out); - usb_ep_disable(fn->bulk_in); - - fn->bulk_out->driver_data = NULL; - fn->bulk_in->driver_data = NULL; - } -} - -static int rawbulk_function_setalt(struct usb_function *f, unsigned intf, - unsigned alt) { - struct rawbulk_function *fn = function_to_rawbulk(f); - fn->activated = 1; - schedule_work(&fn->activator); - return 0; -} - -static void rawbulk_function_disable(struct usb_function *f) { - struct rawbulk_function *fn = function_to_rawbulk(f); - fn->activated = 0; - schedule_work(&fn->activator); -} - -static int rawbulk_bind_config(struct usb_configuration *c, int transfer_id) { - int rc; - struct rawbulk_function *fn = rawbulk_lookup_function(transfer_id); - - printk(KERN_DEBUG "add %s to config.\n", fn->longname); - - if (!fn) - return -ENOMEM; - - if (fn->string_defs[0].id == 0) { - rc = usb_string_id(c->cdev); - if (rc < 0) - return rc; - fn->string_defs[0].id = rc; - fn->interface.iInterface = rc; - } - wmt_cdev = c->cdev; - - fn->function.name = fn->longname; - fn->function.setup = rawbulk_function_setup; - fn->function.bind = rawbulk_function_bind; - fn->function.unbind = rawbulk_function_unbind; - fn->function.set_alt = rawbulk_function_setalt; - fn->function.disable = rawbulk_function_disable; - - INIT_WORK(&fn->activator, do_activate); - - rc = usb_add_function(c, &fn->function); - if (rc < 0) - printk(KERN_DEBUG "%s - failed to config %d.\n", __func__, rc); - - return rc; -} diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_rndis.c b/ANDROID_3.4.5/drivers/usb/gadget/f_rndis.c deleted file mode 100644 index 5a4fdbc7..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_rndis.c +++ /dev/null @@ -1,936 +0,0 @@ -/* - * f_rndis.c -- RNDIS link function driver - * - * Copyright (C) 2003-2005,2008 David Brownell - * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger - * Copyright (C) 2008 Nokia Corporation - * Copyright (C) 2009 Samsung Electronics - * Author: Michal Nazarewicz (mina86@mina86.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -/* #define VERBOSE_DEBUG */ - -#include -#include -#include -#include - -#include - -#include "u_ether.h" -#include "rndis.h" - - -/* - * This function is an RNDIS Ethernet port -- a Microsoft protocol that's - * been promoted instead of the standard CDC Ethernet. The published RNDIS - * spec is ambiguous, incomplete, and needlessly complex. Variants such as - * ActiveSync have even worse status in terms of specification. - * - * In short: it's a protocol controlled by (and for) Microsoft, not for an - * Open ecosystem or markets. Linux supports it *only* because Microsoft - * doesn't support the CDC Ethernet standard. - * - * The RNDIS data transfer model is complex, with multiple Ethernet packets - * per USB message, and out of band data. The control model is built around - * what's essentially an "RNDIS RPC" protocol. It's all wrapped in a CDC ACM - * (modem, not Ethernet) veneer, with those ACM descriptors being entirely - * useless (they're ignored). RNDIS expects to be the only function in its - * configuration, so it's no real help if you need composite devices; and - * it expects to be the first configuration too. - * - * There is a single technical advantage of RNDIS over CDC Ethernet, if you - * discount the fluff that its RPC can be made to deliver: it doesn't need - * a NOP altsetting for the data interface. That lets it work on some of the - * "so smart it's stupid" hardware which takes over configuration changes - * from the software, and adds restrictions like "no altsettings". - * - * Unfortunately MSFT's RNDIS drivers are buggy. They hang or oops, and - * have all sorts of contrary-to-specification oddities that can prevent - * them from working sanely. Since bugfixes (or accurate specs, letting - * Linux work around those bugs) are unlikely to ever come from MSFT, you - * may want to avoid using RNDIS on purely operational grounds. - * - * Omissions from the RNDIS 1.0 specification include: - * - * - Power management ... references data that's scattered around lots - * of other documentation, which is incorrect/incomplete there too. - * - * - There are various undocumented protocol requirements, like the need - * to send garbage in some control-OUT messages. - * - * - MS-Windows drivers sometimes emit undocumented requests. - */ - -struct f_rndis { - struct gether port; - u8 ctrl_id, data_id; - u8 ethaddr[ETH_ALEN]; - u32 vendorID; - const char *manufacturer; - int config; - - struct usb_ep *notify; - struct usb_request *notify_req; - atomic_t notify_count; -}; - -static inline struct f_rndis *func_to_rndis(struct usb_function *f) -{ - return container_of(f, struct f_rndis, port.func); -} - -/* peak (theoretical) bulk transfer rate in bits-per-second */ -static unsigned int bitrate(struct usb_gadget *g) -{ - if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER) - return 13 * 1024 * 8 * 1000 * 8; - else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) - return 13 * 512 * 8 * 1000 * 8; - else - return 19 * 64 * 1 * 1000 * 8; -} - -/*-------------------------------------------------------------------------*/ - -/* - */ - -#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */ -#define STATUS_BYTECOUNT 8 /* 8 bytes data */ - - -/* interface descriptor: */ - -static struct usb_interface_descriptor rndis_control_intf = { - .bLength = sizeof rndis_control_intf, - .bDescriptorType = USB_DT_INTERFACE, - - /* .bInterfaceNumber = DYNAMIC */ - /* status endpoint is optional; this could be patched later */ - .bNumEndpoints = 1, - .bInterfaceClass = USB_CLASS_COMM, - .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, - .bInterfaceProtocol = USB_CDC_ACM_PROTO_VENDOR, - /* .iInterface = DYNAMIC */ -}; - -static struct usb_cdc_header_desc header_desc = { - .bLength = sizeof header_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_HEADER_TYPE, - - .bcdCDC = cpu_to_le16(0x0110), -}; - -static struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = { - .bLength = sizeof call_mgmt_descriptor, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, - - .bmCapabilities = 0x00, - .bDataInterface = 0x01, -}; - -static struct usb_cdc_acm_descriptor rndis_acm_descriptor = { - .bLength = sizeof rndis_acm_descriptor, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_ACM_TYPE, - - .bmCapabilities = 0x00, -}; - -static struct usb_cdc_union_desc rndis_union_desc = { - .bLength = sizeof(rndis_union_desc), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_UNION_TYPE, - /* .bMasterInterface0 = DYNAMIC */ - /* .bSlaveInterface0 = DYNAMIC */ -}; - -/* the data interface has two bulk endpoints */ - -static struct usb_interface_descriptor rndis_data_intf = { - .bLength = sizeof rndis_data_intf, - .bDescriptorType = USB_DT_INTERFACE, - - /* .bInterfaceNumber = DYNAMIC */ - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_CDC_DATA, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - /* .iInterface = DYNAMIC */ -}; - - -static struct usb_interface_assoc_descriptor -rndis_iad_descriptor = { - .bLength = sizeof rndis_iad_descriptor, - .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, - - .bFirstInterface = 0, /* XXX, hardcoded */ - .bInterfaceCount = 2, // control + data - .bFunctionClass = USB_CLASS_COMM, - .bFunctionSubClass = USB_CDC_SUBCLASS_ETHERNET, - .bFunctionProtocol = USB_CDC_PROTO_NONE, - /* .iFunction = DYNAMIC */ -}; - -/* full speed support: */ - -static struct usb_endpoint_descriptor fs_notify_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), - .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC, -}; - -static struct usb_endpoint_descriptor fs_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_endpoint_descriptor fs_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_descriptor_header *eth_fs_function[] = { - (struct usb_descriptor_header *) &rndis_iad_descriptor, - - /* control interface matches ACM, not Ethernet */ - (struct usb_descriptor_header *) &rndis_control_intf, - (struct usb_descriptor_header *) &header_desc, - (struct usb_descriptor_header *) &call_mgmt_descriptor, - (struct usb_descriptor_header *) &rndis_acm_descriptor, - (struct usb_descriptor_header *) &rndis_union_desc, - (struct usb_descriptor_header *) &fs_notify_desc, - - /* data interface has no altsetting */ - (struct usb_descriptor_header *) &rndis_data_intf, - (struct usb_descriptor_header *) &fs_in_desc, - (struct usb_descriptor_header *) &fs_out_desc, - NULL, -}; - -/* high speed support: */ - -static struct usb_endpoint_descriptor hs_notify_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), - .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, -}; - -static struct usb_endpoint_descriptor hs_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), -}; - -static struct usb_endpoint_descriptor hs_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), -}; - -static struct usb_descriptor_header *eth_hs_function[] = { - (struct usb_descriptor_header *) &rndis_iad_descriptor, - - /* control interface matches ACM, not Ethernet */ - (struct usb_descriptor_header *) &rndis_control_intf, - (struct usb_descriptor_header *) &header_desc, - (struct usb_descriptor_header *) &call_mgmt_descriptor, - (struct usb_descriptor_header *) &rndis_acm_descriptor, - (struct usb_descriptor_header *) &rndis_union_desc, - (struct usb_descriptor_header *) &hs_notify_desc, - - /* data interface has no altsetting */ - (struct usb_descriptor_header *) &rndis_data_intf, - (struct usb_descriptor_header *) &hs_in_desc, - (struct usb_descriptor_header *) &hs_out_desc, - NULL, -}; - -/* super speed support: */ - -static struct usb_endpoint_descriptor ss_notify_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), - .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, -}; - -static struct usb_ss_ep_comp_descriptor ss_intr_comp_desc = { - .bLength = sizeof ss_intr_comp_desc, - .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, - - /* the following 3 values can be tweaked if necessary */ - /* .bMaxBurst = 0, */ - /* .bmAttributes = 0, */ - .wBytesPerInterval = cpu_to_le16(STATUS_BYTECOUNT), -}; - -static struct usb_endpoint_descriptor ss_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(1024), -}; - -static struct usb_endpoint_descriptor ss_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(1024), -}; - -static struct usb_ss_ep_comp_descriptor ss_bulk_comp_desc = { - .bLength = sizeof ss_bulk_comp_desc, - .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, - - /* the following 2 values can be tweaked if necessary */ - /* .bMaxBurst = 0, */ - /* .bmAttributes = 0, */ -}; - -static struct usb_descriptor_header *eth_ss_function[] = { - (struct usb_descriptor_header *) &rndis_iad_descriptor, - - /* control interface matches ACM, not Ethernet */ - (struct usb_descriptor_header *) &rndis_control_intf, - (struct usb_descriptor_header *) &header_desc, - (struct usb_descriptor_header *) &call_mgmt_descriptor, - (struct usb_descriptor_header *) &rndis_acm_descriptor, - (struct usb_descriptor_header *) &rndis_union_desc, - (struct usb_descriptor_header *) &ss_notify_desc, - (struct usb_descriptor_header *) &ss_intr_comp_desc, - - /* data interface has no altsetting */ - (struct usb_descriptor_header *) &rndis_data_intf, - (struct usb_descriptor_header *) &ss_in_desc, - (struct usb_descriptor_header *) &ss_bulk_comp_desc, - (struct usb_descriptor_header *) &ss_out_desc, - (struct usb_descriptor_header *) &ss_bulk_comp_desc, - NULL, -}; - -/* string descriptors: */ - -static struct usb_string rndis_string_defs[] = { - [0].s = "RNDIS Communications Control", - [1].s = "RNDIS Ethernet Data", - [2].s = "RNDIS", - { } /* end of list */ -}; - -static struct usb_gadget_strings rndis_string_table = { - .language = 0x0409, /* en-us */ - .strings = rndis_string_defs, -}; - -static struct usb_gadget_strings *rndis_strings[] = { - &rndis_string_table, - NULL, -}; - -/*-------------------------------------------------------------------------*/ - -static struct sk_buff *rndis_add_header(struct gether *port, - struct sk_buff *skb) -{ - struct sk_buff *skb2; - - skb2 = skb_realloc_headroom(skb, sizeof(struct rndis_packet_msg_type)); - if (skb2) - rndis_add_hdr(skb2); - - dev_kfree_skb_any(skb); - return skb2; -} - -static void rndis_response_available(void *_rndis) -{ - struct f_rndis *rndis = _rndis; - struct usb_request *req = rndis->notify_req; - struct usb_composite_dev *cdev = rndis->port.func.config->cdev; - __le32 *data = req->buf; - int status; - - if (atomic_inc_return(&rndis->notify_count) != 1) - return; - - /* Send RNDIS RESPONSE_AVAILABLE notification; a - * USB_CDC_NOTIFY_RESPONSE_AVAILABLE "should" work too - * - * This is the only notification defined by RNDIS. - */ - data[0] = cpu_to_le32(1); - data[1] = cpu_to_le32(0); - - status = usb_ep_queue(rndis->notify, req, GFP_ATOMIC); - if (status) { - atomic_dec(&rndis->notify_count); - DBG(cdev, "notify/0 --> %d\n", status); - } -} - -static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct f_rndis *rndis = req->context; - struct usb_composite_dev *cdev = rndis->port.func.config->cdev; - int status = req->status; - - /* after TX: - * - USB_CDC_GET_ENCAPSULATED_RESPONSE (ep0/control) - * - RNDIS_RESPONSE_AVAILABLE (status/irq) - */ - switch (status) { - case -ECONNRESET: - case -ESHUTDOWN: - /* connection gone */ - atomic_set(&rndis->notify_count, 0); - break; - default: - DBG(cdev, "RNDIS %s response error %d, %d/%d\n", - ep->name, status, - req->actual, req->length); - /* FALLTHROUGH */ - case 0: - if (ep != rndis->notify) - break; - - /* handle multiple pending RNDIS_RESPONSE_AVAILABLE - * notifications by resending until we're done - */ - if (atomic_dec_and_test(&rndis->notify_count)) - break; - status = usb_ep_queue(rndis->notify, req, GFP_ATOMIC); - if (status) { - atomic_dec(&rndis->notify_count); - DBG(cdev, "notify/1 --> %d\n", status); - } - break; - } -} - -static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct f_rndis *rndis = req->context; - struct usb_composite_dev *cdev = rndis->port.func.config->cdev; - int status; - - /* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */ -// spin_lock(&dev->lock); - status = rndis_msg_parser(rndis->config, (u8 *) req->buf); - if (status < 0) - ERROR(cdev, "RNDIS command error %d, %d/%d\n", - status, req->actual, req->length); -// spin_unlock(&dev->lock); -} -extern bool get_rndis_initialized(void); -static int -rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) -{ - struct f_rndis *rndis = func_to_rndis(f); - 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); - if(!get_rndis_initialized()) - return; - /* composite driver infrastructure handles everything except - * CDC class messages; interface activation uses set_alt(). - */ - switch ((ctrl->bRequestType << 8) | ctrl->bRequest) { - - /* RNDIS uses the CDC command encapsulation mechanism to implement - * an RPC scheme, with much getting/setting of attributes by OID. - */ - case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) - | USB_CDC_SEND_ENCAPSULATED_COMMAND: - if (w_value || w_index != rndis->ctrl_id) - goto invalid; - /* read the request; process it later */ - value = w_length; - req->complete = rndis_command_complete; - req->context = rndis; - /* later, rndis_response_available() sends a notification */ - break; - - case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) - | USB_CDC_GET_ENCAPSULATED_RESPONSE: - if (w_value || w_index != rndis->ctrl_id) - goto invalid; - else { - u8 *buf; - u32 n; - - /* return the result */ - buf = rndis_get_next_response(rndis->config, &n); - if (buf) { - memcpy(req->buf, buf, n); - req->complete = rndis_response_complete; - req->context = rndis; - rndis_free_response(rndis->config, buf); - value = n; - } - /* else stalls ... spec says to avoid that */ - } - break; - - default: -invalid: - VDBG(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, "rndis req%02x.%02x v%04x i%04x l%d\n", - ctrl->bRequestType, ctrl->bRequest, - w_value, w_index, w_length); - req->zero = (value < w_length); - req->length = value; - value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); - if (value < 0) - ERROR(cdev, "rndis response on err %d\n", value); - } - - /* device either stalls (value < 0) or reports success */ - return value; -} - - -static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt) -{ - struct f_rndis *rndis = func_to_rndis(f); - struct usb_composite_dev *cdev = f->config->cdev; - - /* we know alt == 0 */ - - if (intf == rndis->ctrl_id) { - if (rndis->notify->driver_data) { - VDBG(cdev, "reset rndis control %d\n", intf); - usb_ep_disable(rndis->notify); - } - if (!rndis->notify->desc) { - VDBG(cdev, "init rndis ctrl %d\n", intf); - if (config_ep_by_speed(cdev->gadget, f, rndis->notify)) - goto fail; - } - usb_ep_enable(rndis->notify); - rndis->notify->driver_data = rndis; - - } else if (intf == rndis->data_id) { - struct net_device *net; - - if (rndis->port.in_ep->driver_data) { - DBG(cdev, "reset rndis\n"); - gether_disconnect(&rndis->port); - } - - if (!rndis->port.in_ep->desc || !rndis->port.out_ep->desc) { - DBG(cdev, "init rndis\n"); - if (config_ep_by_speed(cdev->gadget, f, - rndis->port.in_ep) || - config_ep_by_speed(cdev->gadget, f, - rndis->port.out_ep)) { - rndis->port.in_ep->desc = NULL; - rndis->port.out_ep->desc = NULL; - goto fail; - } - } - - /* Avoid ZLPs; they can be troublesome. */ - rndis->port.is_zlp_ok = false; - - /* RNDIS should be in the "RNDIS uninitialized" state, - * either never activated or after rndis_uninit(). - * - * We don't want data to flow here until a nonzero packet - * filter is set, at which point it enters "RNDIS data - * initialized" state ... but we do want the endpoints - * to be activated. It's a strange little state. - * - * REVISIT the RNDIS gadget code has done this wrong for a - * very long time. We need another call to the link layer - * code -- gether_updown(...bool) maybe -- to do it right. - */ - rndis->port.cdc_filter = 0; - - DBG(cdev, "RNDIS RX/TX early activation ... \n"); - net = gether_connect(&rndis->port); - if (IS_ERR(net)) - return PTR_ERR(net); - - rndis_set_param_dev(rndis->config, net, - &rndis->port.cdc_filter); - } else - goto fail; - - return 0; -fail: - return -EINVAL; -} - -static void rndis_disable(struct usb_function *f) -{ - struct f_rndis *rndis = func_to_rndis(f); - struct usb_composite_dev *cdev = f->config->cdev; - - if (!rndis->notify->driver_data) - return; - - printk("rndis deactivated\n"); - - rndis_uninit(rndis->config); - gether_disconnect(&rndis->port); - - usb_ep_disable(rndis->notify); - rndis->notify->driver_data = NULL; -} - -/*-------------------------------------------------------------------------*/ - -/* - * This isn't quite the same mechanism as CDC Ethernet, since the - * notification scheme passes less data, but the same set of link - * states must be tested. A key difference is that altsettings are - * not used to tell whether the link should send packets or not. - */ - -static void rndis_open(struct gether *geth) -{ - struct f_rndis *rndis = func_to_rndis(&geth->func); - struct usb_composite_dev *cdev = geth->func.config->cdev; - - DBG(cdev, "%s\n", __func__); - - rndis_set_param_medium(rndis->config, NDIS_MEDIUM_802_3, - bitrate(cdev->gadget) / 100); - rndis_signal_connect(rndis->config); -} - -static void rndis_close(struct gether *geth) -{ - struct f_rndis *rndis = func_to_rndis(&geth->func); - - DBG(geth->func.config->cdev, "%s\n", __func__); - - rndis_set_param_medium(rndis->config, NDIS_MEDIUM_802_3, 0); - rndis_signal_disconnect(rndis->config); -} - -/*-------------------------------------------------------------------------*/ - -/* ethernet function driver setup/binding */ - -static int -rndis_bind(struct usb_configuration *c, struct usb_function *f) -{ - struct usb_composite_dev *cdev = c->cdev; - struct f_rndis *rndis = func_to_rndis(f); - int status; - struct usb_ep *ep; - - /* allocate instance-specific interface IDs */ - status = usb_interface_id(c, f); - if (status < 0) - goto fail; - rndis->ctrl_id = status; - rndis_iad_descriptor.bFirstInterface = status; - - rndis_control_intf.bInterfaceNumber = status; - rndis_union_desc.bMasterInterface0 = status; - - status = usb_interface_id(c, f); - if (status < 0) - goto fail; - rndis->data_id = status; - - rndis_data_intf.bInterfaceNumber = status; - rndis_union_desc.bSlaveInterface0 = status; - - status = -ENODEV; - - /* allocate instance-specific endpoints */ - ep = usb_ep_autoconfig(cdev->gadget, &fs_in_desc); - if (!ep) - goto fail; - rndis->port.in_ep = ep; - ep->driver_data = cdev; /* claim */ - - ep = usb_ep_autoconfig(cdev->gadget, &fs_out_desc); - if (!ep) - goto fail; - rndis->port.out_ep = ep; - ep->driver_data = cdev; /* claim */ - - /* NOTE: a status/notification endpoint is, strictly speaking, - * optional. We don't treat it that way though! It's simpler, - * and some newer profiles don't treat it as optional. - */ - ep = usb_ep_autoconfig(cdev->gadget, &fs_notify_desc); - if (!ep) - goto fail; - rndis->notify = ep; - ep->driver_data = cdev; /* claim */ - - status = -ENOMEM; - - /* allocate notification request and buffer */ - rndis->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL); - if (!rndis->notify_req) - goto fail; - rndis->notify_req->buf = kmalloc(STATUS_BYTECOUNT, GFP_KERNEL); - if (!rndis->notify_req->buf) - goto fail; - rndis->notify_req->length = STATUS_BYTECOUNT; - rndis->notify_req->context = rndis; - rndis->notify_req->complete = rndis_response_complete; - - /* copy descriptors, and track endpoint copies */ - f->descriptors = usb_copy_descriptors(eth_fs_function); - if (!f->descriptors) - goto fail; - - /* support all relevant hardware speeds... we expect that when - * hardware is dual speed, all bulk-capable endpoints work at - * both speeds - */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - hs_in_desc.bEndpointAddress = - fs_in_desc.bEndpointAddress; - hs_out_desc.bEndpointAddress = - fs_out_desc.bEndpointAddress; - hs_notify_desc.bEndpointAddress = - fs_notify_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->hs_descriptors = usb_copy_descriptors(eth_hs_function); - if (!f->hs_descriptors) - goto fail; - } - - if (gadget_is_superspeed(c->cdev->gadget)) { - ss_in_desc.bEndpointAddress = - fs_in_desc.bEndpointAddress; - ss_out_desc.bEndpointAddress = - fs_out_desc.bEndpointAddress; - ss_notify_desc.bEndpointAddress = - fs_notify_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->ss_descriptors = usb_copy_descriptors(eth_ss_function); - if (!f->ss_descriptors) - goto fail; - } - - rndis->port.open = rndis_open; - rndis->port.close = rndis_close; - - status = rndis_register(rndis_response_available, rndis); - if (status < 0) - goto fail; - rndis->config = status; - - rndis_set_param_medium(rndis->config, NDIS_MEDIUM_802_3, 0); - rndis_set_host_mac(rndis->config, rndis->ethaddr); - - if (rndis->manufacturer && rndis->vendorID && - rndis_set_param_vendor(rndis->config, rndis->vendorID, - rndis->manufacturer)) - goto fail; - - /* NOTE: all that is done without knowing or caring about - * the network link ... which is unavailable to this code - * until we're activated via set_alt(). - */ - - DBG(cdev, "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n", - gadget_is_superspeed(c->cdev->gadget) ? "super" : - gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", - rndis->port.in_ep->name, rndis->port.out_ep->name, - rndis->notify->name); - return 0; - -fail: - if (gadget_is_superspeed(c->cdev->gadget) && f->ss_descriptors) - usb_free_descriptors(f->ss_descriptors); - if (gadget_is_dualspeed(c->cdev->gadget) && f->hs_descriptors) - usb_free_descriptors(f->hs_descriptors); - if (f->descriptors) - usb_free_descriptors(f->descriptors); - - if (rndis->notify_req) { - kfree(rndis->notify_req->buf); - usb_ep_free_request(rndis->notify, rndis->notify_req); - } - - /* we might as well release our claims on endpoints */ - if (rndis->notify) - rndis->notify->driver_data = NULL; - if (rndis->port.out_ep->desc) - rndis->port.out_ep->driver_data = NULL; - if (rndis->port.in_ep->desc) - rndis->port.in_ep->driver_data = NULL; - - ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); - - return status; -} - -static void -rndis_unbind(struct usb_configuration *c, struct usb_function *f) -{ - struct f_rndis *rndis = func_to_rndis(f); - - rndis_deregister(rndis->config); - rndis_exit(); - - if (gadget_is_superspeed(c->cdev->gadget)) - usb_free_descriptors(f->ss_descriptors); - if (gadget_is_dualspeed(c->cdev->gadget)) - usb_free_descriptors(f->hs_descriptors); - usb_free_descriptors(f->descriptors); - - kfree(rndis->notify_req->buf); - usb_ep_free_request(rndis->notify, rndis->notify_req); - - kfree(rndis); -} - -/* Some controllers can't support RNDIS ... */ -static inline bool can_support_rndis(struct usb_configuration *c) -{ - /* everything else is *presumably* fine */ - return true; -} - -/** - * rndis_bind_config - add RNDIS network link to a configuration - * @c: the configuration to support the network link - * @ethaddr: a buffer in which the ethernet address of the host side - * side of the link was recorded - * Context: single threaded during gadget setup - * - * Returns zero on success, else negative errno. - * - * Caller must have called @gether_setup(). Caller is also responsible - * for calling @gether_cleanup() before module unload. - */ -int -rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) -{ - return rndis_bind_config_vendor(c, ethaddr, 0, NULL); -} - -int -rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], - u32 vendorID, const char *manufacturer) -{ - struct f_rndis *rndis; - int status; - - if (!can_support_rndis(c) || !ethaddr) - return -EINVAL; - - /* setup RNDIS itself */ - status = rndis_init(); - if (status < 0) - return status; - - /* maybe allocate device-global string IDs */ - if (rndis_string_defs[0].id == 0) { - - /* control interface label */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - rndis_string_defs[0].id = status; - rndis_control_intf.iInterface = status; - - /* data interface label */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - rndis_string_defs[1].id = status; - rndis_data_intf.iInterface = status; - - /* IAD iFunction label */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - rndis_string_defs[2].id = status; - rndis_iad_descriptor.iFunction = status; - } - - /* allocate and initialize one new instance */ - status = -ENOMEM; - rndis = kzalloc(sizeof *rndis, GFP_KERNEL); - if (!rndis) - goto fail; - - memcpy(rndis->ethaddr, ethaddr, ETH_ALEN); - rndis->vendorID = vendorID; - rndis->manufacturer = manufacturer; - - /* RNDIS activates when the host changes this filter */ - rndis->port.cdc_filter = 0; - - /* RNDIS has special (and complex) framing */ - rndis->port.header_len = sizeof(struct rndis_packet_msg_type); - rndis->port.wrap = rndis_add_header; - rndis->port.unwrap = rndis_rm_hdr; - - rndis->port.func.name = "rndis"; - rndis->port.func.strings = rndis_strings; - /* descriptors are per-instance copies */ - rndis->port.func.bind = rndis_bind; - rndis->port.func.unbind = rndis_unbind; - rndis->port.func.set_alt = rndis_set_alt; - rndis->port.func.setup = rndis_setup; - rndis->port.func.disable = rndis_disable; - - status = usb_add_function(c, &rndis->port.func); - if (status) { - kfree(rndis); -fail: - rndis_exit(); - } - return status; -} diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_serial.c b/ANDROID_3.4.5/drivers/usb/gadget/f_serial.c deleted file mode 100644 index 07197d63..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_serial.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - * f_serial.c - generic USB serial function driver - * - * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com) - * Copyright (C) 2008 by David Brownell - * Copyright (C) 2008 by Nokia Corporation - * - * This software is distributed under the terms of the GNU General - * Public License ("GPL") as published by the Free Software Foundation, - * either version 2 of that License or (at your option) any later version. - */ - -#include -#include -#include - -#include "u_serial.h" -#include "gadget_chips.h" - - -/* - * This function packages a simple "generic serial" port with no real - * control mechanisms, just raw data transfer over two bulk endpoints. - * - * Because it's not standardized, this isn't as interoperable as the - * CDC ACM driver. However, for many purposes it's just as functional - * if you can arrange appropriate host side drivers. - */ - -struct f_gser { - struct gserial port; - u8 data_id; - u8 port_num; -}; - -static inline struct f_gser *func_to_gser(struct usb_function *f) -{ - return container_of(f, struct f_gser, port.func); -} - -/*-------------------------------------------------------------------------*/ - -/* interface descriptor: */ - -static struct usb_interface_descriptor gser_interface_desc __initdata = { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - /* .bInterfaceNumber = DYNAMIC */ - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - /* .iInterface = DYNAMIC */ -}; - -/* full speed support: */ - -static struct usb_endpoint_descriptor gser_fs_in_desc __initdata = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_endpoint_descriptor gser_fs_out_desc __initdata = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_descriptor_header *gser_fs_function[] __initdata = { - (struct usb_descriptor_header *) &gser_interface_desc, - (struct usb_descriptor_header *) &gser_fs_in_desc, - (struct usb_descriptor_header *) &gser_fs_out_desc, - NULL, -}; - -/* high speed support: */ - -static struct usb_endpoint_descriptor gser_hs_in_desc __initdata = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), -}; - -static struct usb_endpoint_descriptor gser_hs_out_desc __initdata = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), -}; - -static struct usb_descriptor_header *gser_hs_function[] __initdata = { - (struct usb_descriptor_header *) &gser_interface_desc, - (struct usb_descriptor_header *) &gser_hs_in_desc, - (struct usb_descriptor_header *) &gser_hs_out_desc, - NULL, -}; - -static struct usb_endpoint_descriptor gser_ss_in_desc __initdata = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(1024), -}; - -static struct usb_endpoint_descriptor gser_ss_out_desc __initdata = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(1024), -}; - -static struct usb_ss_ep_comp_descriptor gser_ss_bulk_comp_desc __initdata = { - .bLength = sizeof gser_ss_bulk_comp_desc, - .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, -}; - -static struct usb_descriptor_header *gser_ss_function[] __initdata = { - (struct usb_descriptor_header *) &gser_interface_desc, - (struct usb_descriptor_header *) &gser_ss_in_desc, - (struct usb_descriptor_header *) &gser_ss_bulk_comp_desc, - (struct usb_descriptor_header *) &gser_ss_out_desc, - (struct usb_descriptor_header *) &gser_ss_bulk_comp_desc, - NULL, -}; - -/* string descriptors: */ - -static struct usb_string gser_string_defs[] = { - [0].s = "Generic Serial", - { } /* end of list */ -}; - -static struct usb_gadget_strings gser_string_table = { - .language = 0x0409, /* en-us */ - .strings = gser_string_defs, -}; - -static struct usb_gadget_strings *gser_strings[] = { - &gser_string_table, - NULL, -}; - -/*-------------------------------------------------------------------------*/ - -static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt) -{ - struct f_gser *gser = func_to_gser(f); - struct usb_composite_dev *cdev = f->config->cdev; - - /* we know alt == 0, so this is an activation or a reset */ - - if (gser->port.in->driver_data) { - DBG(cdev, "reset generic ttyGS%d\n", gser->port_num); - gserial_disconnect(&gser->port); - } - if (!gser->port.in->desc || !gser->port.out->desc) { - DBG(cdev, "activate generic ttyGS%d\n", gser->port_num); - if (config_ep_by_speed(cdev->gadget, f, gser->port.in) || - config_ep_by_speed(cdev->gadget, f, gser->port.out)) { - gser->port.in->desc = NULL; - gser->port.out->desc = NULL; - return -EINVAL; - } - } - gserial_connect(&gser->port, gser->port_num); - return 0; -} - -static void gser_disable(struct usb_function *f) -{ - struct f_gser *gser = func_to_gser(f); - struct usb_composite_dev *cdev = f->config->cdev; - - DBG(cdev, "generic ttyGS%d deactivated\n", gser->port_num); - gserial_disconnect(&gser->port); -} - -/*-------------------------------------------------------------------------*/ - -/* serial function driver setup/binding */ - -static int __init -gser_bind(struct usb_configuration *c, struct usb_function *f) -{ - struct usb_composite_dev *cdev = c->cdev; - struct f_gser *gser = func_to_gser(f); - int status; - struct usb_ep *ep; - - /* allocate instance-specific interface IDs */ - status = usb_interface_id(c, f); - if (status < 0) - goto fail; - gser->data_id = status; - gser_interface_desc.bInterfaceNumber = status; - - status = -ENODEV; - - /* allocate instance-specific endpoints */ - ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_in_desc); - if (!ep) - goto fail; - gser->port.in = ep; - ep->driver_data = cdev; /* claim */ - - ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_out_desc); - if (!ep) - goto fail; - gser->port.out = ep; - ep->driver_data = cdev; /* claim */ - - /* copy descriptors, and track endpoint copies */ - f->descriptors = usb_copy_descriptors(gser_fs_function); - - /* support all relevant hardware speeds... we expect that when - * hardware is dual speed, all bulk-capable endpoints work at - * both speeds - */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - gser_hs_in_desc.bEndpointAddress = - gser_fs_in_desc.bEndpointAddress; - gser_hs_out_desc.bEndpointAddress = - gser_fs_out_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->hs_descriptors = usb_copy_descriptors(gser_hs_function); - } - if (gadget_is_superspeed(c->cdev->gadget)) { - gser_ss_in_desc.bEndpointAddress = - gser_fs_in_desc.bEndpointAddress; - gser_ss_out_desc.bEndpointAddress = - gser_fs_out_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->ss_descriptors = usb_copy_descriptors(gser_ss_function); - if (!f->ss_descriptors) - goto fail; - } - - DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n", - gser->port_num, - gadget_is_superspeed(c->cdev->gadget) ? "super" : - gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", - gser->port.in->name, gser->port.out->name); - return 0; - -fail: - /* we might as well release our claims on endpoints */ - if (gser->port.out) - gser->port.out->driver_data = NULL; - if (gser->port.in) - gser->port.in->driver_data = NULL; - - ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); - - return status; -} - -static void -gser_unbind(struct usb_configuration *c, struct usb_function *f) -{ - if (gadget_is_dualspeed(c->cdev->gadget)) - usb_free_descriptors(f->hs_descriptors); - if (gadget_is_superspeed(c->cdev->gadget)) - usb_free_descriptors(f->ss_descriptors); - usb_free_descriptors(f->descriptors); - kfree(func_to_gser(f)); -} - -/** - * gser_bind_config - add a generic serial function to a configuration - * @c: the configuration to support the serial instance - * @port_num: /dev/ttyGS* port this interface will use - * Context: single threaded during gadget setup - * - * Returns zero on success, else negative errno. - * - * Caller must have called @gserial_setup() with enough ports to - * handle all the ones it binds. Caller is also responsible - * for calling @gserial_cleanup() before module unload. - */ -int __init gser_bind_config(struct usb_configuration *c, u8 port_num) -{ - struct f_gser *gser; - int status; - - /* REVISIT might want instance-specific strings to help - * distinguish instances ... - */ - - /* maybe allocate device-global string ID */ - if (gser_string_defs[0].id == 0) { - status = usb_string_id(c->cdev); - if (status < 0) - return status; - gser_string_defs[0].id = status; - } - - /* allocate and initialize one new instance */ - gser = kzalloc(sizeof *gser, GFP_KERNEL); - if (!gser) - return -ENOMEM; - - gser->port_num = port_num; - - gser->port.func.name = "gser"; - gser->port.func.strings = gser_strings; - gser->port.func.bind = gser_bind; - gser->port.func.unbind = gser_unbind; - gser->port.func.set_alt = gser_set_alt; - gser->port.func.disable = gser_disable; - - status = usb_add_function(c, &gser->port.func); - if (status) - kfree(gser); - return status; -} diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_sourcesink.c b/ANDROID_3.4.5/drivers/usb/gadget/f_sourcesink.c deleted file mode 100644 index 7aa7ac82..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_sourcesink.c +++ /dev/null @@ -1,584 +0,0 @@ -/* - * f_sourcesink.c - USB peripheral source/sink configuration driver - * - * Copyright (C) 2003-2008 David Brownell - * Copyright (C) 2008 by Nokia Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -/* #define VERBOSE_DEBUG */ - -#include -#include -#include -#include - -#include "g_zero.h" -#include "gadget_chips.h" - - -/* - * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripheral - * controller drivers. - * - * This just sinks bulk packets OUT to the peripheral and sources them IN - * to the host, optionally with specific data patterns for integrity tests. - * As such it supports basic functionality and load tests. - * - * In terms of control messaging, this supports all the standard requests - * plus two that support control-OUT tests. If the optional "autoresume" - * mode is enabled, it provides good functional coverage for the "USBCV" - * test harness from USB-IF. - * - * Note that because this doesn't queue more than one request at a time, - * some other function must be used to test queueing logic. The network - * link (g_ether) is the best overall option for that, since its TX and RX - * queues are relatively independent, will receive a range of packet sizes, - * and can often be made to run out completely. Those issues are important - * when stress testing peripheral controller drivers. - * - * - * This is currently packaged as a configuration driver, which can't be - * combined with other functions to make composite devices. However, it - * can be combined with other independent configurations. - */ -struct f_sourcesink { - struct usb_function function; - - struct usb_ep *in_ep; - struct usb_ep *out_ep; -}; - -static inline struct f_sourcesink *func_to_ss(struct usb_function *f) -{ - return container_of(f, struct f_sourcesink, function); -} - -static unsigned pattern; -module_param(pattern, uint, 0); -MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63 "); - -/*-------------------------------------------------------------------------*/ - -static struct usb_interface_descriptor source_sink_intf = { - .bLength = sizeof source_sink_intf, - .bDescriptorType = USB_DT_INTERFACE, - - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - /* .iInterface = DYNAMIC */ -}; - -/* full speed support: */ - -static struct usb_endpoint_descriptor fs_source_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_endpoint_descriptor fs_sink_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_descriptor_header *fs_source_sink_descs[] = { - (struct usb_descriptor_header *) &source_sink_intf, - (struct usb_descriptor_header *) &fs_sink_desc, - (struct usb_descriptor_header *) &fs_source_desc, - NULL, -}; - -/* high speed support: */ - -static struct usb_endpoint_descriptor hs_source_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), -}; - -static struct usb_endpoint_descriptor hs_sink_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), -}; - -static struct usb_descriptor_header *hs_source_sink_descs[] = { - (struct usb_descriptor_header *) &source_sink_intf, - (struct usb_descriptor_header *) &hs_source_desc, - (struct usb_descriptor_header *) &hs_sink_desc, - NULL, -}; - -/* super speed support: */ - -static struct usb_endpoint_descriptor ss_source_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(1024), -}; - -struct usb_ss_ep_comp_descriptor ss_source_comp_desc = { - .bLength = USB_DT_SS_EP_COMP_SIZE, - .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, - .bMaxBurst = 0, - .bmAttributes = 0, - .wBytesPerInterval = 0, -}; - -static struct usb_endpoint_descriptor ss_sink_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(1024), -}; - -struct usb_ss_ep_comp_descriptor ss_sink_comp_desc = { - .bLength = USB_DT_SS_EP_COMP_SIZE, - .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, - .bMaxBurst = 0, - .bmAttributes = 0, - .wBytesPerInterval = 0, -}; - -static struct usb_descriptor_header *ss_source_sink_descs[] = { - (struct usb_descriptor_header *) &source_sink_intf, - (struct usb_descriptor_header *) &ss_source_desc, - (struct usb_descriptor_header *) &ss_source_comp_desc, - (struct usb_descriptor_header *) &ss_sink_desc, - (struct usb_descriptor_header *) &ss_sink_comp_desc, - NULL, -}; - -/* function-specific strings: */ - -static struct usb_string strings_sourcesink[] = { - [0].s = "source and sink data", - { } /* end of list */ -}; - -static struct usb_gadget_strings stringtab_sourcesink = { - .language = 0x0409, /* en-us */ - .strings = strings_sourcesink, -}; - -static struct usb_gadget_strings *sourcesink_strings[] = { - &stringtab_sourcesink, - NULL, -}; - -/*-------------------------------------------------------------------------*/ - -static int __init -sourcesink_bind(struct usb_configuration *c, struct usb_function *f) -{ - struct usb_composite_dev *cdev = c->cdev; - struct f_sourcesink *ss = func_to_ss(f); - int id; - - /* allocate interface ID(s) */ - id = usb_interface_id(c, f); - if (id < 0) - return id; - source_sink_intf.bInterfaceNumber = id; - - /* allocate endpoints */ - ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc); - if (!ss->in_ep) { -autoconf_fail: - ERROR(cdev, "%s: can't autoconfigure on %s\n", - f->name, cdev->gadget->name); - return -ENODEV; - } - ss->in_ep->driver_data = cdev; /* claim */ - - ss->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_sink_desc); - if (!ss->out_ep) - goto autoconf_fail; - ss->out_ep->driver_data = cdev; /* claim */ - - /* support high speed hardware */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - hs_source_desc.bEndpointAddress = - fs_source_desc.bEndpointAddress; - hs_sink_desc.bEndpointAddress = - fs_sink_desc.bEndpointAddress; - f->hs_descriptors = hs_source_sink_descs; - } - - /* support super speed hardware */ - if (gadget_is_superspeed(c->cdev->gadget)) { - ss_source_desc.bEndpointAddress = - fs_source_desc.bEndpointAddress; - ss_sink_desc.bEndpointAddress = - fs_sink_desc.bEndpointAddress; - f->ss_descriptors = ss_source_sink_descs; - } - - DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", - (gadget_is_superspeed(c->cdev->gadget) ? "super" : - (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")), - f->name, ss->in_ep->name, ss->out_ep->name); - return 0; -} - -static void -sourcesink_unbind(struct usb_configuration *c, struct usb_function *f) -{ - kfree(func_to_ss(f)); -} - -/* optionally require specific source/sink data patterns */ -static int check_read_data(struct f_sourcesink *ss, struct usb_request *req) -{ - unsigned i; - u8 *buf = req->buf; - struct usb_composite_dev *cdev = ss->function.config->cdev; - - for (i = 0; i < req->actual; i++, buf++) { - switch (pattern) { - - /* all-zeroes has no synchronization issues */ - case 0: - if (*buf == 0) - continue; - break; - - /* "mod63" stays in sync with short-terminated transfers, - * OR otherwise when host and gadget agree on how large - * each usb transfer request should be. Resync is done - * with set_interface or set_config. (We *WANT* it to - * get quickly out of sync if controllers or their drivers - * stutter for any reason, including buffer duplcation...) - */ - case 1: - if (*buf == (u8)(i % 63)) - continue; - break; - } - ERROR(cdev, "bad OUT byte, buf[%d] = %d\n", i, *buf); - usb_ep_set_halt(ss->out_ep); - return -EINVAL; - } - return 0; -} - -static void reinit_write_data(struct usb_ep *ep, struct usb_request *req) -{ - unsigned i; - u8 *buf = req->buf; - - switch (pattern) { - case 0: - memset(req->buf, 0, req->length); - break; - case 1: - for (i = 0; i < req->length; i++) - *buf++ = (u8) (i % 63); - break; - } -} - -static void source_sink_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct f_sourcesink *ss = ep->driver_data; - struct usb_composite_dev *cdev = ss->function.config->cdev; - int status = req->status; - - switch (status) { - - case 0: /* normal completion? */ - if (ep == ss->out_ep) { - check_read_data(ss, req); - memset(req->buf, 0x55, req->length); - } else - reinit_write_data(ep, req); - break; - - /* this endpoint is normally active while we're configured */ - case -ECONNABORTED: /* hardware forced ep reset */ - case -ECONNRESET: /* request dequeued */ - case -ESHUTDOWN: /* disconnect from host */ - VDBG(cdev, "%s gone (%d), %d/%d\n", ep->name, status, - req->actual, req->length); - if (ep == ss->out_ep) - check_read_data(ss, req); - free_ep_req(ep, req); - return; - - case -EOVERFLOW: /* buffer overrun on read means that - * we didn't provide a big enough - * buffer. - */ - default: -#if 1 - DBG(cdev, "%s complete --> %d, %d/%d\n", ep->name, - status, req->actual, req->length); -#endif - case -EREMOTEIO: /* short read */ - break; - } - - status = usb_ep_queue(ep, req, GFP_ATOMIC); - if (status) { - ERROR(cdev, "kill %s: resubmit %d bytes --> %d\n", - ep->name, req->length, status); - usb_ep_set_halt(ep); - /* FIXME recover later ... somehow */ - } -} - -static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in) -{ - struct usb_ep *ep; - struct usb_request *req; - int status; - - ep = is_in ? ss->in_ep : ss->out_ep; - req = alloc_ep_req(ep); - if (!req) - return -ENOMEM; - - req->complete = source_sink_complete; - if (is_in) - reinit_write_data(ep, req); - else - memset(req->buf, 0x55, req->length); - - status = usb_ep_queue(ep, req, GFP_ATOMIC); - if (status) { - struct usb_composite_dev *cdev; - - cdev = ss->function.config->cdev; - ERROR(cdev, "start %s %s --> %d\n", - is_in ? "IN" : "OUT", - ep->name, status); - free_ep_req(ep, req); - } - - return status; -} - -static void disable_source_sink(struct f_sourcesink *ss) -{ - struct usb_composite_dev *cdev; - - cdev = ss->function.config->cdev; - disable_endpoints(cdev, ss->in_ep, ss->out_ep); - VDBG(cdev, "%s disabled\n", ss->function.name); -} - -static int -enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss) -{ - int result = 0; - struct usb_ep *ep; - - /* one endpoint writes (sources) zeroes IN (to the host) */ - ep = ss->in_ep; - result = config_ep_by_speed(cdev->gadget, &(ss->function), ep); - if (result) - return result; - result = usb_ep_enable(ep); - if (result < 0) - return result; - ep->driver_data = ss; - - result = source_sink_start_ep(ss, true); - if (result < 0) { -fail: - ep = ss->in_ep; - usb_ep_disable(ep); - ep->driver_data = NULL; - return result; - } - - /* one endpoint reads (sinks) anything OUT (from the host) */ - ep = ss->out_ep; - result = config_ep_by_speed(cdev->gadget, &(ss->function), ep); - if (result) - goto fail; - result = usb_ep_enable(ep); - if (result < 0) - goto fail; - ep->driver_data = ss; - - result = source_sink_start_ep(ss, false); - if (result < 0) { - usb_ep_disable(ep); - ep->driver_data = NULL; - goto fail; - } - - DBG(cdev, "%s enabled\n", ss->function.name); - return result; -} - -static int sourcesink_set_alt(struct usb_function *f, - unsigned intf, unsigned alt) -{ - struct f_sourcesink *ss = func_to_ss(f); - struct usb_composite_dev *cdev = f->config->cdev; - - /* we know alt is zero */ - if (ss->in_ep->driver_data) - disable_source_sink(ss); - return enable_source_sink(cdev, ss); -} - -static void sourcesink_disable(struct usb_function *f) -{ - struct f_sourcesink *ss = func_to_ss(f); - - disable_source_sink(ss); -} - -/*-------------------------------------------------------------------------*/ - -static int __init sourcesink_bind_config(struct usb_configuration *c) -{ - struct f_sourcesink *ss; - int status; - - ss = kzalloc(sizeof *ss, GFP_KERNEL); - if (!ss) - return -ENOMEM; - - ss->function.name = "source/sink"; - ss->function.descriptors = fs_source_sink_descs; - ss->function.bind = sourcesink_bind; - ss->function.unbind = sourcesink_unbind; - ss->function.set_alt = sourcesink_set_alt; - ss->function.disable = sourcesink_disable; - - status = usb_add_function(c, &ss->function); - if (status) - kfree(ss); - return status; -} - -static int sourcesink_setup(struct usb_configuration *c, - const struct usb_ctrlrequest *ctrl) -{ - struct usb_request *req = c->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); - - req->length = USB_BUFSIZ; - - /* composite driver infrastructure handles everything except - * the two control test requests. - */ - switch (ctrl->bRequest) { - - /* - * These are the same vendor-specific requests supported by - * Intel's USB 2.0 compliance test devices. We exceed that - * device spec by allowing multiple-packet requests. - * - * NOTE: the Control-OUT data stays in req->buf ... better - * would be copying it into a scratch buffer, so that other - * requests may safely intervene. - */ - case 0x5b: /* control WRITE test -- fill the buffer */ - if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR)) - goto unknown; - if (w_value || w_index) - break; - /* just read that many bytes into the buffer */ - if (w_length > req->length) - break; - value = w_length; - break; - case 0x5c: /* control READ test -- return the buffer */ - if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR)) - goto unknown; - if (w_value || w_index) - break; - /* expect those bytes are still in the buffer; send back */ - if (w_length > req->length) - break; - value = w_length; - break; - - default: -unknown: - VDBG(c->cdev, - "unknown 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) { - VDBG(c->cdev, "source/sink 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(c->cdev->gadget->ep0, req, GFP_ATOMIC); - if (value < 0) - ERROR(c->cdev, "source/sinkc response, err %d\n", - value); - } - - /* device either stalls (value < 0) or reports success */ - return value; -} - -static struct usb_configuration sourcesink_driver = { - .label = "source/sink", - .strings = sourcesink_strings, - .setup = sourcesink_setup, - .bConfigurationValue = 3, - .bmAttributes = USB_CONFIG_ATT_SELFPOWER, - /* .iConfiguration = DYNAMIC */ -}; - -/** - * sourcesink_add - add a source/sink testing configuration to a device - * @cdev: the device to support the configuration - */ -int __init sourcesink_add(struct usb_composite_dev *cdev, bool autoresume) -{ - int id; - - /* allocate string ID(s) */ - id = usb_string_id(cdev); - if (id < 0) - return id; - strings_sourcesink[0].id = id; - - source_sink_intf.iInterface = id; - sourcesink_driver.iConfiguration = id; - - /* support autoresume for remote wakeup testing */ - if (autoresume) - sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; - - /* support OTG systems */ - if (gadget_is_otg(cdev->gadget)) { - sourcesink_driver.descriptors = otg_desc; - sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; - } - - return usb_add_config(cdev, &sourcesink_driver, sourcesink_bind_config); -} diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_subset.c b/ANDROID_3.4.5/drivers/usb/gadget/f_subset.c deleted file mode 100644 index 21ab474a..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_subset.c +++ /dev/null @@ -1,460 +0,0 @@ -/* - * f_subset.c -- "CDC Subset" Ethernet link function driver - * - * Copyright (C) 2003-2005,2008 David Brownell - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include - -#include "u_ether.h" - - -/* - * This function packages a simple "CDC Subset" Ethernet port with no real - * control mechanisms; just raw data transfer over two bulk endpoints. - * The data transfer model is exactly that of CDC Ethernet, which is - * why we call it the "CDC Subset". - * - * Because it's not standardized, this has some interoperability issues. - * They mostly relate to driver binding, since the data transfer model is - * so simple (CDC Ethernet). The original versions of this protocol used - * specific product/vendor IDs: byteswapped IDs for Digital Equipment's - * SA-1100 "Itsy" board, which could run Linux 2.4 kernels and supported - * daughtercards with USB peripheral connectors. (It was used more often - * with other boards, using the Itsy identifiers.) Linux hosts recognized - * this with CONFIG_USB_ARMLINUX; these devices have only one configuration - * and one interface. - * - * At some point, MCCI defined a (nonconformant) CDC MDLM variant called - * "SAFE", which happens to have a mode which is identical to the "CDC - * Subset" in terms of data transfer and lack of control model. This was - * adopted by later Sharp Zaurus models, and by some other software which - * Linux hosts recognize with CONFIG_USB_NET_ZAURUS. - * - * Because Microsoft's RNDIS drivers are far from robust, we added a few - * descriptors to the CDC Subset code, making this code look like a SAFE - * implementation. This lets you use MCCI's host side MS-Windows drivers - * if you get fed up with RNDIS. It also makes it easier for composite - * drivers to work, since they can use class based binding instead of - * caring about specific product and vendor IDs. - */ - -struct f_gether { - struct gether port; - - char ethaddr[14]; -}; - -static inline struct f_gether *func_to_geth(struct usb_function *f) -{ - return container_of(f, struct f_gether, port.func); -} - -/*-------------------------------------------------------------------------*/ - -/* - * "Simple" CDC-subset option is a simple vendor-neutral model that most - * full speed controllers can handle: one interface, two bulk endpoints. - * To assist host side drivers, we fancy it up a bit, and add descriptors so - * some host side drivers will understand it as a "SAFE" variant. - * - * "SAFE" loosely follows CDC WMC MDLM, violating the spec in various ways. - * Data endpoints live in the control interface, there's no data interface. - * And it's not used to talk to a cell phone radio. - */ - -/* interface descriptor: */ - -static struct usb_interface_descriptor subset_data_intf = { - .bLength = sizeof subset_data_intf, - .bDescriptorType = USB_DT_INTERFACE, - - /* .bInterfaceNumber = DYNAMIC */ - .bAlternateSetting = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_COMM, - .bInterfaceSubClass = USB_CDC_SUBCLASS_MDLM, - .bInterfaceProtocol = 0, - /* .iInterface = DYNAMIC */ -}; - -static struct usb_cdc_header_desc mdlm_header_desc = { - .bLength = sizeof mdlm_header_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_HEADER_TYPE, - - .bcdCDC = cpu_to_le16(0x0110), -}; - -static struct usb_cdc_mdlm_desc mdlm_desc = { - .bLength = sizeof mdlm_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_MDLM_TYPE, - - .bcdVersion = cpu_to_le16(0x0100), - .bGUID = { - 0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6, - 0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f, - }, -}; - -/* since "usb_cdc_mdlm_detail_desc" is a variable length structure, we - * can't really use its struct. All we do here is say that we're using - * the submode of "SAFE" which directly matches the CDC Subset. - */ -static u8 mdlm_detail_desc[] = { - 6, - USB_DT_CS_INTERFACE, - USB_CDC_MDLM_DETAIL_TYPE, - - 0, /* "SAFE" */ - 0, /* network control capabilities (none) */ - 0, /* network data capabilities ("raw" encapsulation) */ -}; - -static struct usb_cdc_ether_desc ether_desc = { - .bLength = sizeof ether_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_ETHERNET_TYPE, - - /* this descriptor actually adds value, surprise! */ - /* .iMACAddress = DYNAMIC */ - .bmEthernetStatistics = cpu_to_le32(0), /* no statistics */ - .wMaxSegmentSize = cpu_to_le16(ETH_FRAME_LEN), - .wNumberMCFilters = cpu_to_le16(0), - .bNumberPowerFilters = 0, -}; - -/* full speed support: */ - -static struct usb_endpoint_descriptor fs_subset_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_endpoint_descriptor fs_subset_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_descriptor_header *fs_eth_function[] = { - (struct usb_descriptor_header *) &subset_data_intf, - (struct usb_descriptor_header *) &mdlm_header_desc, - (struct usb_descriptor_header *) &mdlm_desc, - (struct usb_descriptor_header *) &mdlm_detail_desc, - (struct usb_descriptor_header *) ðer_desc, - (struct usb_descriptor_header *) &fs_subset_in_desc, - (struct usb_descriptor_header *) &fs_subset_out_desc, - NULL, -}; - -/* high speed support: */ - -static struct usb_endpoint_descriptor hs_subset_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), -}; - -static struct usb_endpoint_descriptor hs_subset_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), -}; - -static struct usb_descriptor_header *hs_eth_function[] = { - (struct usb_descriptor_header *) &subset_data_intf, - (struct usb_descriptor_header *) &mdlm_header_desc, - (struct usb_descriptor_header *) &mdlm_desc, - (struct usb_descriptor_header *) &mdlm_detail_desc, - (struct usb_descriptor_header *) ðer_desc, - (struct usb_descriptor_header *) &hs_subset_in_desc, - (struct usb_descriptor_header *) &hs_subset_out_desc, - NULL, -}; - -/* super speed support: */ - -static struct usb_endpoint_descriptor ss_subset_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(1024), -}; - -static struct usb_endpoint_descriptor ss_subset_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(1024), -}; - -static struct usb_ss_ep_comp_descriptor ss_subset_bulk_comp_desc = { - .bLength = sizeof ss_subset_bulk_comp_desc, - .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, - - /* the following 2 values can be tweaked if necessary */ - /* .bMaxBurst = 0, */ - /* .bmAttributes = 0, */ -}; - -static struct usb_descriptor_header *ss_eth_function[] = { - (struct usb_descriptor_header *) &subset_data_intf, - (struct usb_descriptor_header *) &mdlm_header_desc, - (struct usb_descriptor_header *) &mdlm_desc, - (struct usb_descriptor_header *) &mdlm_detail_desc, - (struct usb_descriptor_header *) ðer_desc, - (struct usb_descriptor_header *) &ss_subset_in_desc, - (struct usb_descriptor_header *) &ss_subset_bulk_comp_desc, - (struct usb_descriptor_header *) &ss_subset_out_desc, - (struct usb_descriptor_header *) &ss_subset_bulk_comp_desc, - NULL, -}; - -/* string descriptors: */ - -static struct usb_string geth_string_defs[] = { - [0].s = "CDC Ethernet Subset/SAFE", - [1].s = NULL /* DYNAMIC */, - { } /* end of list */ -}; - -static struct usb_gadget_strings geth_string_table = { - .language = 0x0409, /* en-us */ - .strings = geth_string_defs, -}; - -static struct usb_gadget_strings *geth_strings[] = { - &geth_string_table, - NULL, -}; - -/*-------------------------------------------------------------------------*/ - -static int geth_set_alt(struct usb_function *f, unsigned intf, unsigned alt) -{ - struct f_gether *geth = func_to_geth(f); - struct usb_composite_dev *cdev = f->config->cdev; - struct net_device *net; - - /* we know alt == 0, so this is an activation or a reset */ - - if (geth->port.in_ep->driver_data) { - DBG(cdev, "reset cdc subset\n"); - gether_disconnect(&geth->port); - } - - DBG(cdev, "init + activate cdc subset\n"); - if (config_ep_by_speed(cdev->gadget, f, geth->port.in_ep) || - config_ep_by_speed(cdev->gadget, f, geth->port.out_ep)) { - geth->port.in_ep->desc = NULL; - geth->port.out_ep->desc = NULL; - return -EINVAL; - } - - net = gether_connect(&geth->port); - return IS_ERR(net) ? PTR_ERR(net) : 0; -} - -static void geth_disable(struct usb_function *f) -{ - struct f_gether *geth = func_to_geth(f); - struct usb_composite_dev *cdev = f->config->cdev; - - DBG(cdev, "net deactivated\n"); - gether_disconnect(&geth->port); -} - -/*-------------------------------------------------------------------------*/ - -/* serial function driver setup/binding */ - -static int -geth_bind(struct usb_configuration *c, struct usb_function *f) -{ - struct usb_composite_dev *cdev = c->cdev; - struct f_gether *geth = func_to_geth(f); - int status; - struct usb_ep *ep; - - /* allocate instance-specific interface IDs */ - status = usb_interface_id(c, f); - if (status < 0) - goto fail; - subset_data_intf.bInterfaceNumber = status; - - status = -ENODEV; - - /* allocate instance-specific endpoints */ - ep = usb_ep_autoconfig(cdev->gadget, &fs_subset_in_desc); - if (!ep) - goto fail; - geth->port.in_ep = ep; - ep->driver_data = cdev; /* claim */ - - ep = usb_ep_autoconfig(cdev->gadget, &fs_subset_out_desc); - if (!ep) - goto fail; - geth->port.out_ep = ep; - ep->driver_data = cdev; /* claim */ - - /* copy descriptors, and track endpoint copies */ - f->descriptors = usb_copy_descriptors(fs_eth_function); - if (!f->descriptors) - goto fail; - - /* support all relevant hardware speeds... we expect that when - * hardware is dual speed, all bulk-capable endpoints work at - * both speeds - */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - hs_subset_in_desc.bEndpointAddress = - fs_subset_in_desc.bEndpointAddress; - hs_subset_out_desc.bEndpointAddress = - fs_subset_out_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->hs_descriptors = usb_copy_descriptors(hs_eth_function); - if (!f->hs_descriptors) - goto fail; - } - - if (gadget_is_superspeed(c->cdev->gadget)) { - ss_subset_in_desc.bEndpointAddress = - fs_subset_in_desc.bEndpointAddress; - ss_subset_out_desc.bEndpointAddress = - fs_subset_out_desc.bEndpointAddress; - - /* copy descriptors, and track endpoint copies */ - f->ss_descriptors = usb_copy_descriptors(ss_eth_function); - if (!f->ss_descriptors) - goto fail; - } - - /* NOTE: all that is done without knowing or caring about - * the network link ... which is unavailable to this code - * until we're activated via set_alt(). - */ - - DBG(cdev, "CDC Subset: %s speed IN/%s OUT/%s\n", - gadget_is_superspeed(c->cdev->gadget) ? "super" : - gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", - geth->port.in_ep->name, geth->port.out_ep->name); - return 0; - -fail: - if (f->descriptors) - usb_free_descriptors(f->descriptors); - if (f->hs_descriptors) - usb_free_descriptors(f->hs_descriptors); - - /* we might as well release our claims on endpoints */ - if (geth->port.out_ep->desc) - geth->port.out_ep->driver_data = NULL; - if (geth->port.in_ep->desc) - geth->port.in_ep->driver_data = NULL; - - ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); - - return status; -} - -static void -geth_unbind(struct usb_configuration *c, struct usb_function *f) -{ - if (gadget_is_superspeed(c->cdev->gadget)) - usb_free_descriptors(f->ss_descriptors); - if (gadget_is_dualspeed(c->cdev->gadget)) - usb_free_descriptors(f->hs_descriptors); - usb_free_descriptors(f->descriptors); - geth_string_defs[1].s = NULL; - kfree(func_to_geth(f)); -} - -/** - * geth_bind_config - add CDC Subset network link to a configuration - * @c: the configuration to support the network link - * @ethaddr: a buffer in which the ethernet address of the host side - * side of the link was recorded - * Context: single threaded during gadget setup - * - * Returns zero on success, else negative errno. - * - * Caller must have called @gether_setup(). Caller is also responsible - * for calling @gether_cleanup() before module unload. - */ -int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) -{ - struct f_gether *geth; - int status; - - if (!ethaddr) - return -EINVAL; - - /* maybe allocate device-global string IDs */ - if (geth_string_defs[0].id == 0) { - - /* interface label */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - geth_string_defs[0].id = status; - subset_data_intf.iInterface = status; - - /* MAC address */ - status = usb_string_id(c->cdev); - if (status < 0) - return status; - geth_string_defs[1].id = status; - ether_desc.iMACAddress = status; - } - - /* allocate and initialize one new instance */ - geth = kzalloc(sizeof *geth, GFP_KERNEL); - if (!geth) - return -ENOMEM; - - /* export host's Ethernet address in CDC format */ - snprintf(geth->ethaddr, sizeof geth->ethaddr, - "%02X%02X%02X%02X%02X%02X", - ethaddr[0], ethaddr[1], ethaddr[2], - ethaddr[3], ethaddr[4], ethaddr[5]); - geth_string_defs[1].s = geth->ethaddr; - - geth->port.cdc_filter = DEFAULT_FILTER; - - geth->port.func.name = "cdc_subset"; - geth->port.func.strings = geth_strings; - geth->port.func.bind = geth_bind; - geth->port.func.unbind = geth_unbind; - geth->port.func.set_alt = geth_set_alt; - geth->port.func.disable = geth_disable; - - status = usb_add_function(c, &geth->port.func); - if (status) { - geth_string_defs[1].s = NULL; - kfree(geth); - } - return status; -} diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_uac1.c b/ANDROID_3.4.5/drivers/usb/gadget/f_uac1.c deleted file mode 100644 index 1a5dcd55..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_uac1.c +++ /dev/null @@ -1,776 +0,0 @@ -/* - * f_audio.c -- USB Audio class function driver - * - * Copyright (C) 2008 Bryan Wu - * Copyright (C) 2008 Analog Devices, Inc - * - * Enter bugs at http://blackfin.uclinux.org/ - * - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include -#include - -#include "u_uac1.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"); - -static int generic_set_cmd(struct usb_audio_control *con, u8 cmd, int value); -static int generic_get_cmd(struct usb_audio_control *con, u8 cmd); - -/* - * 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_UAC_AC_HEADER_DESCRIPTOR(2); - -#define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES) -/* 1 input terminal, 1 output terminal and 1 feature unit */ -#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH + UAC_DT_INPUT_TERMINAL_SIZE \ - + UAC_DT_OUTPUT_TERMINAL_SIZE + UAC_DT_FEATURE_UNIT_SIZE(0)) -/* B.3.2 Class-Specific AC Interface Descriptor */ -static struct uac1_ac_header_descriptor_2 ac_header_desc = { - .bLength = UAC_DT_AC_HEADER_LENGTH, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = UAC_HEADER, - .bcdADC = __constant_cpu_to_le16(0x0100), - .wTotalLength = __constant_cpu_to_le16(UAC_DT_TOTAL_LENGTH), - .bInCollection = F_AUDIO_NUM_INTERFACES, - .baInterfaceNr = { - [0] = F_AUDIO_AC_INTERFACE, - [1] = F_AUDIO_AS_INTERFACE, - } -}; - -#define INPUT_TERMINAL_ID 1 -static struct uac_input_terminal_descriptor input_terminal_desc = { - .bLength = UAC_DT_INPUT_TERMINAL_SIZE, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = UAC_INPUT_TERMINAL, - .bTerminalID = INPUT_TERMINAL_ID, - .wTerminalType = UAC_TERMINAL_STREAMING, - .bAssocTerminal = 0, - .wChannelConfig = 0x3, -}; - -DECLARE_UAC_FEATURE_UNIT_DESCRIPTOR(0); - -#define FEATURE_UNIT_ID 2 -static struct uac_feature_unit_descriptor_0 feature_unit_desc = { - .bLength = UAC_DT_FEATURE_UNIT_SIZE(0), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = UAC_FEATURE_UNIT, - .bUnitID = FEATURE_UNIT_ID, - .bSourceID = INPUT_TERMINAL_ID, - .bControlSize = 2, - .bmaControls[0] = (UAC_FU_MUTE | UAC_FU_VOLUME), -}; - -static struct usb_audio_control mute_control = { - .list = LIST_HEAD_INIT(mute_control.list), - .name = "Mute Control", - .type = UAC_FU_MUTE, - /* 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 = UAC_FU_VOLUME, - /* 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 = UAC_FEATURE_UNIT, - .desc = (struct usb_descriptor_header *)&feature_unit_desc, -}; - -#define OUTPUT_TERMINAL_ID 3 -static struct uac1_output_terminal_descriptor output_terminal_desc = { - .bLength = UAC_DT_OUTPUT_TERMINAL_SIZE, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, - .bTerminalID = OUTPUT_TERMINAL_ID, - .wTerminalType = UAC_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 uac1_as_header_descriptor as_header_desc = { - .bLength = UAC_DT_AS_HEADER_SIZE, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = UAC_AS_GENERAL, - .bTerminalLink = INPUT_TERMINAL_ID, - .bDelay = 1, - .wFormatTag = UAC_FORMAT_TYPE_I_PCM, -}; - -DECLARE_UAC_FORMAT_TYPE_I_DISCRETE_DESC(1); - -static struct uac_format_type_i_discrete_descriptor_1 as_type_i_desc = { - .bLength = UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = UAC_FORMAT_TYPE, - .bFormatType = UAC_FORMAT_TYPE_I, - .bSubframeSize = 2, - .bBitResolution = 16, - .bSamFreqType = 1, -}; - -/* Standard ISO OUT Endpoint Descriptor */ -static struct usb_endpoint_descriptor as_out_ep_desc = { - .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_SYNC_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 uac_iso_endpoint_descriptor as_iso_out_desc __initdata = { - .bLength = UAC_ISO_ENDPOINT_DESC_SIZE, - .bDescriptorType = USB_DT_CS_ENDPOINT, - .bDescriptorSubtype = UAC_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, -}; - -/* - * 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 ERR_PTR(-ENOMEM); - - copy_buf->buf = kzalloc(buf_size, GFP_ATOMIC); - if (!copy_buf->buf) { - kfree(copy_buf); - return ERR_PTR(-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; - - 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); -} - -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(©_buf->list, &audio->play_queue); - schedule_work(&audio->playback_work); - copy_buf = f_audio_buffer_alloc(audio_buf_size); - if (IS_ERR(copy_buf)) - 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 audio_set_endpoint_req(struct usb_function *f, - const struct usb_ctrlrequest *ctrl) -{ - struct usb_composite_dev *cdev = f->config->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 UAC_SET_CUR: - value = len; - break; - - case UAC_SET_MIN: - break; - - case UAC_SET_MAX: - break; - - case UAC_SET_RES: - break; - - case UAC_SET_MEM: - break; - - default: - break; - } - - return value; -} - -static int audio_get_endpoint_req(struct usb_function *f, - const struct usb_ctrlrequest *ctrl) -{ - struct usb_composite_dev *cdev = f->config->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 UAC_GET_CUR: - case UAC_GET_MIN: - case UAC_GET_MAX: - case UAC_GET_RES: - value = len; - break; - case UAC_GET_MEM: - break; - default: - break; - } - - return value; -} - -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; interface - * activation uses set_alt(). - */ - switch (ctrl->bRequestType) { - case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE: - value = audio_set_intf_req(f, ctrl); - break; - - case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE: - value = audio_get_intf_req(f, ctrl); - break; - - case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT: - value = audio_set_endpoint_req(f, ctrl); - break; - - case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT: - value = audio_get_endpoint_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); - out_ep->driver_data = audio; - audio->copy_buf = f_audio_buffer_alloc(audio_buf_size); - if (IS_ERR(audio->copy_buf)) - return -ENOMEM; - - /* - * 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(©_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; - audio->out_ep->desc = &as_out_ep_desc; - ep->driver_data = cdev; /* claim */ - - status = -ENOMEM; - - /* copy descriptors, and track endpoint copies */ - f->descriptors = usb_copy_descriptors(f_audio_desc); - - /* - * support all relevant hardware speeds... we expect that when - * hardware is dual speed, all bulk-capable endpoints work at - * both speeds - */ - if (gadget_is_dualspeed(c->cdev->gadget)) { - c->highspeed = true; - f->hs_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); - usb_free_descriptors(f->hs_descriptors); - kfree(audio); -} - -/*-------------------------------------------------------------------------*/ - -static int generic_set_cmd(struct usb_audio_control *con, u8 cmd, int value) -{ - con->data[cmd] = value; - - return 0; -} - -static int generic_get_cmd(struct usb_audio_control *con, u8 cmd) -{ - return con->data[cmd]; -} - -/* 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[UAC__CUR] = 0xffc0; - volume_control.data[UAC__MIN] = 0xe3a0; - volume_control.data[UAC__MAX] = 0xfff0; - volume_control.data[UAC__RES] = 0x0030; - - return 0; -} - -/** - * audio_bind_config - add USB audio function 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; - - 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(); -setup_fail: - kfree(audio); - return status; -} diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_uac2.c b/ANDROID_3.4.5/drivers/usb/gadget/f_uac2.c deleted file mode 100644 index e7cc4de9..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_uac2.c +++ /dev/null @@ -1,1449 +0,0 @@ -/* - * f_uac2.c -- USB Audio Class 2.0 Function - * - * Copyright (C) 2011 - * Yadwinder Singh (yadi.brar01@gmail.com) - * Jaswinder Singh (jaswinder.singh@linaro.org) - * - * 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 -#include -#include -#include - -#include -#include -#include - -/* Playback(USB-IN) Default Stereo - Fl/Fr */ -static int p_chmask = 0x3; -module_param(p_chmask, uint, S_IRUGO); -MODULE_PARM_DESC(p_chmask, "Playback Channel Mask"); - -/* Playback Default 48 KHz */ -static int p_srate = 48000; -module_param(p_srate, uint, S_IRUGO); -MODULE_PARM_DESC(p_srate, "Playback Sampling Rate"); - -/* Playback Default 16bits/sample */ -static int p_ssize = 2; -module_param(p_ssize, uint, S_IRUGO); -MODULE_PARM_DESC(p_ssize, "Playback Sample Size(bytes)"); - -/* Capture(USB-OUT) Default Stereo - Fl/Fr */ -static int c_chmask = 0x3; -module_param(c_chmask, uint, S_IRUGO); -MODULE_PARM_DESC(c_chmask, "Capture Channel Mask"); - -/* Capture Default 64 KHz */ -static int c_srate = 64000; -module_param(c_srate, uint, S_IRUGO); -MODULE_PARM_DESC(c_srate, "Capture Sampling Rate"); - -/* Capture Default 16bits/sample */ -static int c_ssize = 2; -module_param(c_ssize, uint, S_IRUGO); -MODULE_PARM_DESC(c_ssize, "Capture Sample Size(bytes)"); - -#define DMA_ADDR_INVALID (~(dma_addr_t)0) - -#define ALT_SET(x, a) do {(x) &= ~0xff; (x) |= (a); } while (0) -#define ALT_GET(x) ((x) & 0xff) -#define INTF_SET(x, i) do {(x) &= 0xff; (x) |= ((i) << 8); } while (0) -#define INTF_GET(x) ((x >> 8) & 0xff) - -/* Keep everyone on toes */ -#define USB_XFERS 2 - -/* - * The driver implements a simple UAC_2 topology. - * USB-OUT -> IT_1 -> OT_3 -> ALSA_Capture - * ALSA_Playback -> IT_2 -> OT_4 -> USB-IN - * Capture and Playback sampling rates are independently - * controlled by two clock sources : - * CLK_5 := c_srate, and CLK_6 := p_srate - */ -#define USB_OUT_IT_ID 1 -#define IO_IN_IT_ID 2 -#define IO_OUT_OT_ID 3 -#define USB_IN_OT_ID 4 -#define USB_OUT_CLK_ID 5 -#define USB_IN_CLK_ID 6 - -#define CONTROL_ABSENT 0 -#define CONTROL_RDONLY 1 -#define CONTROL_RDWR 3 - -#define CLK_FREQ_CTRL 0 -#define CLK_VLD_CTRL 2 - -#define COPY_CTRL 0 -#define CONN_CTRL 2 -#define OVRLD_CTRL 4 -#define CLSTR_CTRL 6 -#define UNFLW_CTRL 8 -#define OVFLW_CTRL 10 - -const char *uac2_name = "snd_uac2"; - -struct uac2_req { - struct uac2_rtd_params *pp; /* parent param */ - struct usb_request *req; -}; - -struct uac2_rtd_params { - bool ep_enabled; /* if the ep is enabled */ - /* Size of the ring buffer */ - size_t dma_bytes; - unsigned char *dma_area; - - struct snd_pcm_substream *ss; - - /* Ring buffer */ - ssize_t hw_ptr; - - void *rbuf; - - size_t period_size; - - unsigned max_psize; - struct uac2_req ureq[USB_XFERS]; - - spinlock_t lock; -}; - -struct snd_uac2_chip { - struct platform_device pdev; - struct platform_driver pdrv; - - struct uac2_rtd_params p_prm; - struct uac2_rtd_params c_prm; - - struct snd_card *card; - struct snd_pcm *pcm; -}; - -#define BUFF_SIZE_MAX (PAGE_SIZE * 16) -#define PRD_SIZE_MAX PAGE_SIZE -#define MIN_PERIODS 4 - -static struct snd_pcm_hardware uac2_pcm_hardware = { - .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER - | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID - | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, - .rates = SNDRV_PCM_RATE_CONTINUOUS, - .periods_max = BUFF_SIZE_MAX / PRD_SIZE_MAX, - .buffer_bytes_max = BUFF_SIZE_MAX, - .period_bytes_max = PRD_SIZE_MAX, - .periods_min = MIN_PERIODS, -}; - -struct audio_dev { - /* Currently active {Interface[15:8] | AltSettings[7:0]} */ - __u16 ac_alt, as_out_alt, as_in_alt; - - struct usb_ep *in_ep, *out_ep; - struct usb_function func; - - /* The ALSA Sound Card it represents on the USB-Client side */ - struct snd_uac2_chip uac2; -}; - -static struct audio_dev *agdev_g; - -static inline -struct audio_dev *func_to_agdev(struct usb_function *f) -{ - return container_of(f, struct audio_dev, func); -} - -static inline -struct audio_dev *uac2_to_agdev(struct snd_uac2_chip *u) -{ - return container_of(u, struct audio_dev, uac2); -} - -static inline -struct snd_uac2_chip *pdev_to_uac2(struct platform_device *p) -{ - return container_of(p, struct snd_uac2_chip, pdev); -} - -static inline -struct snd_uac2_chip *prm_to_uac2(struct uac2_rtd_params *r) -{ - struct snd_uac2_chip *uac2 = container_of(r, - struct snd_uac2_chip, c_prm); - - if (&uac2->c_prm != r) - uac2 = container_of(r, struct snd_uac2_chip, p_prm); - - return uac2; -} - -static inline -uint num_channels(uint chanmask) -{ - uint num = 0; - - while (chanmask) { - num += (chanmask & 1); - chanmask >>= 1; - } - - return num; -} - -static void -agdev_iso_complete(struct usb_ep *ep, struct usb_request *req) -{ - unsigned pending; - unsigned long flags; - bool update_alsa = false; - unsigned char *src, *dst; - int status = req->status; - struct uac2_req *ur = req->context; - struct snd_pcm_substream *substream; - struct uac2_rtd_params *prm = ur->pp; - struct snd_uac2_chip *uac2 = prm_to_uac2(prm); - - /* i/f shutting down */ - if (!prm->ep_enabled) - return; - - /* - * We can't really do much about bad xfers. - * Afterall, the ISOCH xfers could fail legitimately. - */ - if (status) - pr_debug("%s: iso_complete status(%d) %d/%d\n", - __func__, status, req->actual, req->length); - - substream = prm->ss; - - /* Do nothing if ALSA isn't active */ - if (!substream) - goto exit; - - spin_lock_irqsave(&prm->lock, flags); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - src = prm->dma_area + prm->hw_ptr; - req->actual = req->length; - dst = req->buf; - } else { - dst = prm->dma_area + prm->hw_ptr; - src = req->buf; - } - - pending = prm->hw_ptr % prm->period_size; - pending += req->actual; - if (pending >= prm->period_size) - update_alsa = true; - - prm->hw_ptr = (prm->hw_ptr + req->actual) % prm->dma_bytes; - - spin_unlock_irqrestore(&prm->lock, flags); - - /* Pack USB load in ALSA ring buffer */ - memcpy(dst, src, req->actual); -exit: - if (usb_ep_queue(ep, req, GFP_ATOMIC)) - dev_err(&uac2->pdev.dev, "%d Error!\n", __LINE__); - - if (update_alsa) - snd_pcm_period_elapsed(substream); - - return; -} - -static int -uac2_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream); - struct audio_dev *agdev = uac2_to_agdev(uac2); - struct uac2_rtd_params *prm; - unsigned long flags; - struct usb_ep *ep; - int err = 0; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - ep = agdev->in_ep; - prm = &uac2->p_prm; - } else { - ep = agdev->out_ep; - prm = &uac2->c_prm; - } - - spin_lock_irqsave(&prm->lock, flags); - - /* Reset */ - prm->hw_ptr = 0; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - prm->ss = substream; - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - prm->ss = NULL; - break; - default: - err = -EINVAL; - } - - spin_unlock_irqrestore(&prm->lock, flags); - - /* Clear buffer after Play stops */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && !prm->ss) - memset(prm->rbuf, 0, prm->max_psize * USB_XFERS); - - return err; -} - -static snd_pcm_uframes_t uac2_pcm_pointer(struct snd_pcm_substream *substream) -{ - struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream); - struct uac2_rtd_params *prm; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - prm = &uac2->p_prm; - else - prm = &uac2->c_prm; - - return bytes_to_frames(substream->runtime, prm->hw_ptr); -} - -static int uac2_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream); - struct uac2_rtd_params *prm; - int err; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - prm = &uac2->p_prm; - else - prm = &uac2->c_prm; - - err = snd_pcm_lib_malloc_pages(substream, - params_buffer_bytes(hw_params)); - if (err >= 0) { - prm->dma_bytes = substream->runtime->dma_bytes; - prm->dma_area = substream->runtime->dma_area; - prm->period_size = params_period_bytes(hw_params); - } - - return err; -} - -static int uac2_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream); - struct uac2_rtd_params *prm; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - prm = &uac2->p_prm; - else - prm = &uac2->c_prm; - - prm->dma_area = NULL; - prm->dma_bytes = 0; - prm->period_size = 0; - - return snd_pcm_lib_free_pages(substream); -} - -static int uac2_pcm_open(struct snd_pcm_substream *substream) -{ - struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw = uac2_pcm_hardware; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - spin_lock_init(&uac2->p_prm.lock); - runtime->hw.rate_min = p_srate; - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; /* ! p_ssize ! */ - runtime->hw.channels_min = num_channels(p_chmask); - runtime->hw.period_bytes_min = 2 * uac2->p_prm.max_psize - / runtime->hw.periods_min; - } else { - spin_lock_init(&uac2->c_prm.lock); - runtime->hw.rate_min = c_srate; - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; /* ! c_ssize ! */ - runtime->hw.channels_min = num_channels(c_chmask); - runtime->hw.period_bytes_min = 2 * uac2->c_prm.max_psize - / runtime->hw.periods_min; - } - - runtime->hw.rate_max = runtime->hw.rate_min; - runtime->hw.channels_max = runtime->hw.channels_min; - - snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - - return 0; -} - -/* ALSA cries without these function pointers */ -static int uac2_pcm_null(struct snd_pcm_substream *substream) -{ - return 0; -} - -static struct snd_pcm_ops uac2_pcm_ops = { - .open = uac2_pcm_open, - .close = uac2_pcm_null, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = uac2_pcm_hw_params, - .hw_free = uac2_pcm_hw_free, - .trigger = uac2_pcm_trigger, - .pointer = uac2_pcm_pointer, - .prepare = uac2_pcm_null, -}; - -static int __devinit snd_uac2_probe(struct platform_device *pdev) -{ - struct snd_uac2_chip *uac2 = pdev_to_uac2(pdev); - struct snd_card *card; - struct snd_pcm *pcm; - int err; - - /* Choose any slot, with no id */ - err = snd_card_create(-1, NULL, THIS_MODULE, 0, &card); - if (err < 0) - return err; - - uac2->card = card; - - /* - * Create first PCM device - * Create a substream only for non-zero channel streams - */ - err = snd_pcm_new(uac2->card, "UAC2 PCM", 0, - p_chmask ? 1 : 0, c_chmask ? 1 : 0, &pcm); - if (err < 0) - goto snd_fail; - - strcpy(pcm->name, "UAC2 PCM"); - pcm->private_data = uac2; - - uac2->pcm = pcm; - - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &uac2_pcm_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &uac2_pcm_ops); - - strcpy(card->driver, "UAC2_Gadget"); - strcpy(card->shortname, "UAC2_Gadget"); - sprintf(card->longname, "UAC2_Gadget %i", pdev->id); - - snd_card_set_dev(card, &pdev->dev); - - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), 0, BUFF_SIZE_MAX); - - err = snd_card_register(card); - if (!err) { - platform_set_drvdata(pdev, card); - return 0; - } - -snd_fail: - snd_card_free(card); - - uac2->pcm = NULL; - uac2->card = NULL; - - return err; -} - -static int __devexit snd_uac2_remove(struct platform_device *pdev) -{ - struct snd_card *card = platform_get_drvdata(pdev); - - platform_set_drvdata(pdev, NULL); - - if (card) - return snd_card_free(card); - - return 0; -} - -static int alsa_uac2_init(struct audio_dev *agdev) -{ - struct snd_uac2_chip *uac2 = &agdev->uac2; - int err; - - uac2->pdrv.probe = snd_uac2_probe; - uac2->pdrv.remove = snd_uac2_remove; - uac2->pdrv.driver.name = uac2_name; - - uac2->pdev.id = 0; - uac2->pdev.name = uac2_name; - - /* Register snd_uac2 driver */ - err = platform_driver_register(&uac2->pdrv); - if (err) - return err; - - /* Register snd_uac2 device */ - err = platform_device_register(&uac2->pdev); - if (err) - platform_driver_unregister(&uac2->pdrv); - - return err; -} - -static void alsa_uac2_exit(struct audio_dev *agdev) -{ - struct snd_uac2_chip *uac2 = &agdev->uac2; - - platform_driver_unregister(&uac2->pdrv); - platform_device_unregister(&uac2->pdev); -} - - -/* --------- USB Function Interface ------------- */ - -enum { - STR_ASSOC, - STR_IF_CTRL, - STR_CLKSRC_IN, - STR_CLKSRC_OUT, - STR_USB_IT, - STR_IO_IT, - STR_USB_OT, - STR_IO_OT, - STR_AS_OUT_ALT0, - STR_AS_OUT_ALT1, - STR_AS_IN_ALT0, - STR_AS_IN_ALT1, -}; - -static const char ifassoc[] = "Source/Sink"; -static const char ifctrl[] = "Topology Control"; -static char clksrc_in[8]; -static char clksrc_out[8]; -static const char usb_it[] = "USBH Out"; -static const char io_it[] = "USBD Out"; -static const char usb_ot[] = "USBH In"; -static const char io_ot[] = "USBD In"; -static const char out_alt0[] = "Playback Inactive"; -static const char out_alt1[] = "Playback Active"; -static const char in_alt0[] = "Capture Inactive"; -static const char in_alt1[] = "Capture Active"; - -static struct usb_string strings_fn[] = { - [STR_ASSOC].s = ifassoc, - [STR_IF_CTRL].s = ifctrl, - [STR_CLKSRC_IN].s = clksrc_in, - [STR_CLKSRC_OUT].s = clksrc_out, - [STR_USB_IT].s = usb_it, - [STR_IO_IT].s = io_it, - [STR_USB_OT].s = usb_ot, - [STR_IO_OT].s = io_ot, - [STR_AS_OUT_ALT0].s = out_alt0, - [STR_AS_OUT_ALT1].s = out_alt1, - [STR_AS_IN_ALT0].s = in_alt0, - [STR_AS_IN_ALT1].s = in_alt1, - { }, -}; - -static struct usb_gadget_strings str_fn = { - .language = 0x0409, /* en-us */ - .strings = strings_fn, -}; - -static struct usb_gadget_strings *fn_strings[] = { - &str_fn, - NULL, -}; - -static struct usb_qualifier_descriptor devqual_desc = { - .bLength = sizeof devqual_desc, - .bDescriptorType = USB_DT_DEVICE_QUALIFIER, - - .bcdUSB = cpu_to_le16(0x200), - .bDeviceClass = USB_CLASS_MISC, - .bDeviceSubClass = 0x02, - .bDeviceProtocol = 0x01, - .bNumConfigurations = 1, - .bRESERVED = 0, -}; - -static struct usb_interface_assoc_descriptor iad_desc = { - .bLength = sizeof iad_desc, - .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, - - .bFirstInterface = 0, - .bInterfaceCount = 3, - .bFunctionClass = USB_CLASS_AUDIO, - .bFunctionSubClass = UAC2_FUNCTION_SUBCLASS_UNDEFINED, - .bFunctionProtocol = UAC_VERSION_2, -}; - -/* Audio Control Interface */ -static struct usb_interface_descriptor std_ac_if_desc = { - .bLength = sizeof std_ac_if_desc, - .bDescriptorType = USB_DT_INTERFACE, - - .bAlternateSetting = 0, - .bNumEndpoints = 0, - .bInterfaceClass = USB_CLASS_AUDIO, - .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, - .bInterfaceProtocol = UAC_VERSION_2, -}; - -/* Clock source for IN traffic */ -struct uac_clock_source_descriptor in_clk_src_desc = { - .bLength = sizeof in_clk_src_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - - .bDescriptorSubtype = UAC2_CLOCK_SOURCE, - .bClockID = USB_IN_CLK_ID, - .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED, - .bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL), - .bAssocTerminal = 0, -}; - -/* Clock source for OUT traffic */ -struct uac_clock_source_descriptor out_clk_src_desc = { - .bLength = sizeof out_clk_src_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - - .bDescriptorSubtype = UAC2_CLOCK_SOURCE, - .bClockID = USB_OUT_CLK_ID, - .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED, - .bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL), - .bAssocTerminal = 0, -}; - -/* Input Terminal for USB_OUT */ -struct uac2_input_terminal_descriptor usb_out_it_desc = { - .bLength = sizeof usb_out_it_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - - .bDescriptorSubtype = UAC_INPUT_TERMINAL, - .bTerminalID = USB_OUT_IT_ID, - .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), - .bAssocTerminal = 0, - .bCSourceID = USB_OUT_CLK_ID, - .iChannelNames = 0, - .bmControls = (CONTROL_RDWR << COPY_CTRL), -}; - -/* Input Terminal for I/O-In */ -struct uac2_input_terminal_descriptor io_in_it_desc = { - .bLength = sizeof io_in_it_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - - .bDescriptorSubtype = UAC_INPUT_TERMINAL, - .bTerminalID = IO_IN_IT_ID, - .wTerminalType = cpu_to_le16(UAC_INPUT_TERMINAL_UNDEFINED), - .bAssocTerminal = 0, - .bCSourceID = USB_IN_CLK_ID, - .iChannelNames = 0, - .bmControls = (CONTROL_RDWR << COPY_CTRL), -}; - -/* Ouput Terminal for USB_IN */ -struct uac2_output_terminal_descriptor usb_in_ot_desc = { - .bLength = sizeof usb_in_ot_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - - .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, - .bTerminalID = USB_IN_OT_ID, - .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING), - .bAssocTerminal = 0, - .bSourceID = IO_IN_IT_ID, - .bCSourceID = USB_IN_CLK_ID, - .bmControls = (CONTROL_RDWR << COPY_CTRL), -}; - -/* Ouput Terminal for I/O-Out */ -struct uac2_output_terminal_descriptor io_out_ot_desc = { - .bLength = sizeof io_out_ot_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - - .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, - .bTerminalID = IO_OUT_OT_ID, - .wTerminalType = cpu_to_le16(UAC_OUTPUT_TERMINAL_UNDEFINED), - .bAssocTerminal = 0, - .bSourceID = USB_OUT_IT_ID, - .bCSourceID = USB_OUT_CLK_ID, - .bmControls = (CONTROL_RDWR << COPY_CTRL), -}; - -struct uac2_ac_header_descriptor ac_hdr_desc = { - .bLength = sizeof ac_hdr_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - - .bDescriptorSubtype = UAC_MS_HEADER, - .bcdADC = cpu_to_le16(0x200), - .bCategory = UAC2_FUNCTION_IO_BOX, - .wTotalLength = sizeof in_clk_src_desc + sizeof out_clk_src_desc - + sizeof usb_out_it_desc + sizeof io_in_it_desc - + sizeof usb_in_ot_desc + sizeof io_out_ot_desc, - .bmControls = 0, -}; - -/* Audio Streaming OUT Interface - Alt0 */ -static struct usb_interface_descriptor std_as_out_if0_desc = { - .bLength = sizeof std_as_out_if0_desc, - .bDescriptorType = USB_DT_INTERFACE, - - .bAlternateSetting = 0, - .bNumEndpoints = 0, - .bInterfaceClass = USB_CLASS_AUDIO, - .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, - .bInterfaceProtocol = UAC_VERSION_2, -}; - -/* Audio Streaming OUT Interface - Alt1 */ -static struct usb_interface_descriptor std_as_out_if1_desc = { - .bLength = sizeof std_as_out_if1_desc, - .bDescriptorType = USB_DT_INTERFACE, - - .bAlternateSetting = 1, - .bNumEndpoints = 1, - .bInterfaceClass = USB_CLASS_AUDIO, - .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, - .bInterfaceProtocol = UAC_VERSION_2, -}; - -/* Audio Stream OUT Intface Desc */ -struct uac2_as_header_descriptor as_out_hdr_desc = { - .bLength = sizeof as_out_hdr_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - - .bDescriptorSubtype = UAC_AS_GENERAL, - .bTerminalLink = USB_OUT_IT_ID, - .bmControls = 0, - .bFormatType = UAC_FORMAT_TYPE_I, - .bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM), - .iChannelNames = 0, -}; - -/* Audio USB_OUT Format */ -struct uac2_format_type_i_descriptor as_out_fmt1_desc = { - .bLength = sizeof as_out_fmt1_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = UAC_FORMAT_TYPE, - .bFormatType = UAC_FORMAT_TYPE_I, -}; - -/* STD AS ISO OUT Endpoint */ -struct usb_endpoint_descriptor fs_epout_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, - .bInterval = 1, -}; - -struct usb_endpoint_descriptor hs_epout_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, - .bInterval = 4, -}; - -/* CS AS ISO OUT Endpoint */ -static struct uac2_iso_endpoint_descriptor as_iso_out_desc = { - .bLength = sizeof as_iso_out_desc, - .bDescriptorType = USB_DT_CS_ENDPOINT, - - .bDescriptorSubtype = UAC_EP_GENERAL, - .bmAttributes = 0, - .bmControls = 0, - .bLockDelayUnits = 0, - .wLockDelay = 0, -}; - -/* Audio Streaming IN Interface - Alt0 */ -static struct usb_interface_descriptor std_as_in_if0_desc = { - .bLength = sizeof std_as_in_if0_desc, - .bDescriptorType = USB_DT_INTERFACE, - - .bAlternateSetting = 0, - .bNumEndpoints = 0, - .bInterfaceClass = USB_CLASS_AUDIO, - .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, - .bInterfaceProtocol = UAC_VERSION_2, -}; - -/* Audio Streaming IN Interface - Alt1 */ -static struct usb_interface_descriptor std_as_in_if1_desc = { - .bLength = sizeof std_as_in_if1_desc, - .bDescriptorType = USB_DT_INTERFACE, - - .bAlternateSetting = 1, - .bNumEndpoints = 1, - .bInterfaceClass = USB_CLASS_AUDIO, - .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING, - .bInterfaceProtocol = UAC_VERSION_2, -}; - -/* Audio Stream IN Intface Desc */ -struct uac2_as_header_descriptor as_in_hdr_desc = { - .bLength = sizeof as_in_hdr_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - - .bDescriptorSubtype = UAC_AS_GENERAL, - .bTerminalLink = USB_IN_OT_ID, - .bmControls = 0, - .bFormatType = UAC_FORMAT_TYPE_I, - .bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM), - .iChannelNames = 0, -}; - -/* Audio USB_IN Format */ -struct uac2_format_type_i_descriptor as_in_fmt1_desc = { - .bLength = sizeof as_in_fmt1_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = UAC_FORMAT_TYPE, - .bFormatType = UAC_FORMAT_TYPE_I, -}; - -/* STD AS ISO IN Endpoint */ -struct usb_endpoint_descriptor fs_epin_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, - .bInterval = 1, -}; - -struct usb_endpoint_descriptor hs_epin_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC, - .bInterval = 4, -}; - -/* CS AS ISO IN Endpoint */ -static struct uac2_iso_endpoint_descriptor as_iso_in_desc = { - .bLength = sizeof as_iso_in_desc, - .bDescriptorType = USB_DT_CS_ENDPOINT, - - .bDescriptorSubtype = UAC_EP_GENERAL, - .bmAttributes = 0, - .bmControls = 0, - .bLockDelayUnits = 0, - .wLockDelay = 0, -}; - -static struct usb_descriptor_header *fs_audio_desc[] = { - (struct usb_descriptor_header *)&iad_desc, - (struct usb_descriptor_header *)&std_ac_if_desc, - - (struct usb_descriptor_header *)&ac_hdr_desc, - (struct usb_descriptor_header *)&in_clk_src_desc, - (struct usb_descriptor_header *)&out_clk_src_desc, - (struct usb_descriptor_header *)&usb_out_it_desc, - (struct usb_descriptor_header *)&io_in_it_desc, - (struct usb_descriptor_header *)&usb_in_ot_desc, - (struct usb_descriptor_header *)&io_out_ot_desc, - - (struct usb_descriptor_header *)&std_as_out_if0_desc, - (struct usb_descriptor_header *)&std_as_out_if1_desc, - - (struct usb_descriptor_header *)&as_out_hdr_desc, - (struct usb_descriptor_header *)&as_out_fmt1_desc, - (struct usb_descriptor_header *)&fs_epout_desc, - (struct usb_descriptor_header *)&as_iso_out_desc, - - (struct usb_descriptor_header *)&std_as_in_if0_desc, - (struct usb_descriptor_header *)&std_as_in_if1_desc, - - (struct usb_descriptor_header *)&as_in_hdr_desc, - (struct usb_descriptor_header *)&as_in_fmt1_desc, - (struct usb_descriptor_header *)&fs_epin_desc, - (struct usb_descriptor_header *)&as_iso_in_desc, - NULL, -}; - -static struct usb_descriptor_header *hs_audio_desc[] = { - (struct usb_descriptor_header *)&iad_desc, - (struct usb_descriptor_header *)&std_ac_if_desc, - - (struct usb_descriptor_header *)&ac_hdr_desc, - (struct usb_descriptor_header *)&in_clk_src_desc, - (struct usb_descriptor_header *)&out_clk_src_desc, - (struct usb_descriptor_header *)&usb_out_it_desc, - (struct usb_descriptor_header *)&io_in_it_desc, - (struct usb_descriptor_header *)&usb_in_ot_desc, - (struct usb_descriptor_header *)&io_out_ot_desc, - - (struct usb_descriptor_header *)&std_as_out_if0_desc, - (struct usb_descriptor_header *)&std_as_out_if1_desc, - - (struct usb_descriptor_header *)&as_out_hdr_desc, - (struct usb_descriptor_header *)&as_out_fmt1_desc, - (struct usb_descriptor_header *)&hs_epout_desc, - (struct usb_descriptor_header *)&as_iso_out_desc, - - (struct usb_descriptor_header *)&std_as_in_if0_desc, - (struct usb_descriptor_header *)&std_as_in_if1_desc, - - (struct usb_descriptor_header *)&as_in_hdr_desc, - (struct usb_descriptor_header *)&as_in_fmt1_desc, - (struct usb_descriptor_header *)&hs_epin_desc, - (struct usb_descriptor_header *)&as_iso_in_desc, - NULL, -}; - -struct cntrl_cur_lay3 { - __u32 dCUR; -}; - -struct cntrl_range_lay3 { - __u16 wNumSubRanges; - __u32 dMIN; - __u32 dMAX; - __u32 dRES; -} __packed; - -static inline void -free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep) -{ - struct snd_uac2_chip *uac2 = prm_to_uac2(prm); - int i; - - prm->ep_enabled = false; - - for (i = 0; i < USB_XFERS; i++) { - if (prm->ureq[i].req) { - usb_ep_dequeue(ep, prm->ureq[i].req); - usb_ep_free_request(ep, prm->ureq[i].req); - prm->ureq[i].req = NULL; - } - } - - if (usb_ep_disable(ep)) - dev_err(&uac2->pdev.dev, - "%s:%d Error!\n", __func__, __LINE__); -} - -static int __init -afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) -{ - struct audio_dev *agdev = func_to_agdev(fn); - struct snd_uac2_chip *uac2 = &agdev->uac2; - struct usb_composite_dev *cdev = cfg->cdev; - struct usb_gadget *gadget = cdev->gadget; - struct uac2_rtd_params *prm; - int ret; - - ret = usb_interface_id(cfg, fn); - if (ret < 0) { - dev_err(&uac2->pdev.dev, - "%s:%d Error!\n", __func__, __LINE__); - return ret; - } - std_ac_if_desc.bInterfaceNumber = ret; - ALT_SET(agdev->ac_alt, 0); - INTF_SET(agdev->ac_alt, ret); - - ret = usb_interface_id(cfg, fn); - if (ret < 0) { - dev_err(&uac2->pdev.dev, - "%s:%d Error!\n", __func__, __LINE__); - return ret; - } - std_as_out_if0_desc.bInterfaceNumber = ret; - std_as_out_if1_desc.bInterfaceNumber = ret; - ALT_SET(agdev->as_out_alt, 0); - INTF_SET(agdev->as_out_alt, ret); - - ret = usb_interface_id(cfg, fn); - if (ret < 0) { - dev_err(&uac2->pdev.dev, - "%s:%d Error!\n", __func__, __LINE__); - return ret; - } - std_as_in_if0_desc.bInterfaceNumber = ret; - std_as_in_if1_desc.bInterfaceNumber = ret; - ALT_SET(agdev->as_in_alt, 0); - INTF_SET(agdev->as_in_alt, ret); - - agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc); - if (!agdev->out_ep) - dev_err(&uac2->pdev.dev, - "%s:%d Error!\n", __func__, __LINE__); - agdev->out_ep->driver_data = agdev; - - agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc); - if (!agdev->in_ep) - dev_err(&uac2->pdev.dev, - "%s:%d Error!\n", __func__, __LINE__); - agdev->in_ep->driver_data = agdev; - - hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress; - hs_epout_desc.wMaxPacketSize = fs_epout_desc.wMaxPacketSize; - hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress; - hs_epin_desc.wMaxPacketSize = fs_epin_desc.wMaxPacketSize; - - fn->descriptors = usb_copy_descriptors(fs_audio_desc); - if (gadget_is_dualspeed(gadget)) - fn->hs_descriptors = usb_copy_descriptors(hs_audio_desc); - - prm = &agdev->uac2.c_prm; - prm->max_psize = hs_epout_desc.wMaxPacketSize; - prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL); - if (!prm->rbuf) { - prm->max_psize = 0; - dev_err(&uac2->pdev.dev, - "%s:%d Error!\n", __func__, __LINE__); - } - - prm = &agdev->uac2.p_prm; - prm->max_psize = hs_epin_desc.wMaxPacketSize; - prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL); - if (!prm->rbuf) { - prm->max_psize = 0; - dev_err(&uac2->pdev.dev, - "%s:%d Error!\n", __func__, __LINE__); - } - - return alsa_uac2_init(agdev); -} - -static void -afunc_unbind(struct usb_configuration *cfg, struct usb_function *fn) -{ - struct audio_dev *agdev = func_to_agdev(fn); - struct usb_composite_dev *cdev = cfg->cdev; - struct usb_gadget *gadget = cdev->gadget; - struct uac2_rtd_params *prm; - - alsa_uac2_exit(agdev); - - prm = &agdev->uac2.p_prm; - kfree(prm->rbuf); - - prm = &agdev->uac2.c_prm; - kfree(prm->rbuf); - - if (gadget_is_dualspeed(gadget)) - usb_free_descriptors(fn->hs_descriptors); - usb_free_descriptors(fn->descriptors); - - if (agdev->in_ep) - agdev->in_ep->driver_data = NULL; - if (agdev->out_ep) - agdev->out_ep->driver_data = NULL; -} - -static int -afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt) -{ - struct usb_composite_dev *cdev = fn->config->cdev; - struct audio_dev *agdev = func_to_agdev(fn); - struct snd_uac2_chip *uac2 = &agdev->uac2; - struct usb_gadget *gadget = cdev->gadget; - struct usb_request *req; - struct usb_ep *ep; - struct uac2_rtd_params *prm; - int i; - - /* No i/f has more than 2 alt settings */ - if (alt > 1) { - dev_err(&uac2->pdev.dev, - "%s:%d Error!\n", __func__, __LINE__); - return -EINVAL; - } - - if (intf == INTF_GET(agdev->ac_alt)) { - /* Control I/f has only 1 AltSetting - 0 */ - if (alt) { - dev_err(&uac2->pdev.dev, - "%s:%d Error!\n", __func__, __LINE__); - return -EINVAL; - } - return 0; - } - - if (intf == INTF_GET(agdev->as_out_alt)) { - ep = agdev->out_ep; - prm = &uac2->c_prm; - config_ep_by_speed(gadget, fn, ep); - ALT_SET(agdev->as_out_alt, alt); - } else if (intf == INTF_GET(agdev->as_in_alt)) { - ep = agdev->in_ep; - prm = &uac2->p_prm; - config_ep_by_speed(gadget, fn, ep); - ALT_SET(agdev->as_in_alt, alt); - } else { - dev_err(&uac2->pdev.dev, - "%s:%d Error!\n", __func__, __LINE__); - return -EINVAL; - } - - if (alt == 0) { - free_ep(prm, ep); - return 0; - } - - prm->ep_enabled = true; - usb_ep_enable(ep); - - for (i = 0; i < USB_XFERS; i++) { - if (prm->ureq[i].req) { - if (usb_ep_queue(ep, prm->ureq[i].req, GFP_ATOMIC)) - dev_err(&uac2->pdev.dev, "%d Error!\n", - __LINE__); - continue; - } - - req = usb_ep_alloc_request(ep, GFP_ATOMIC); - if (req == NULL) { - dev_err(&uac2->pdev.dev, - "%s:%d Error!\n", __func__, __LINE__); - return -EINVAL; - } - - prm->ureq[i].req = req; - prm->ureq[i].pp = prm; - - req->zero = 0; - req->dma = DMA_ADDR_INVALID; - req->context = &prm->ureq[i]; - req->length = prm->max_psize; - req->complete = agdev_iso_complete; - req->buf = prm->rbuf + i * req->length; - - if (usb_ep_queue(ep, req, GFP_ATOMIC)) - dev_err(&uac2->pdev.dev, "%d Error!\n", __LINE__); - } - - return 0; -} - -static int -afunc_get_alt(struct usb_function *fn, unsigned intf) -{ - struct audio_dev *agdev = func_to_agdev(fn); - struct snd_uac2_chip *uac2 = &agdev->uac2; - - if (intf == INTF_GET(agdev->ac_alt)) - return ALT_GET(agdev->ac_alt); - else if (intf == INTF_GET(agdev->as_out_alt)) - return ALT_GET(agdev->as_out_alt); - else if (intf == INTF_GET(agdev->as_in_alt)) - return ALT_GET(agdev->as_in_alt); - else - dev_err(&uac2->pdev.dev, - "%s:%d Invalid Interface %d!\n", - __func__, __LINE__, intf); - - return -EINVAL; -} - -static void -afunc_disable(struct usb_function *fn) -{ - struct audio_dev *agdev = func_to_agdev(fn); - struct snd_uac2_chip *uac2 = &agdev->uac2; - - free_ep(&uac2->p_prm, agdev->in_ep); - ALT_SET(agdev->as_in_alt, 0); - - free_ep(&uac2->c_prm, agdev->out_ep); - ALT_SET(agdev->as_out_alt, 0); -} - -static int -in_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr) -{ - struct usb_request *req = fn->config->cdev->req; - struct audio_dev *agdev = func_to_agdev(fn); - struct snd_uac2_chip *uac2 = &agdev->uac2; - u16 w_length = le16_to_cpu(cr->wLength); - u16 w_index = le16_to_cpu(cr->wIndex); - u16 w_value = le16_to_cpu(cr->wValue); - u8 entity_id = (w_index >> 8) & 0xff; - u8 control_selector = w_value >> 8; - int value = -EOPNOTSUPP; - - if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) { - struct cntrl_cur_lay3 c; - - if (entity_id == USB_IN_CLK_ID) - c.dCUR = p_srate; - else if (entity_id == USB_OUT_CLK_ID) - c.dCUR = c_srate; - - value = min_t(unsigned, w_length, sizeof c); - memcpy(req->buf, &c, value); - } else if (control_selector == UAC2_CS_CONTROL_CLOCK_VALID) { - *(u8 *)req->buf = 1; - value = min_t(unsigned, w_length, 1); - } else { - dev_err(&uac2->pdev.dev, - "%s:%d control_selector=%d TODO!\n", - __func__, __LINE__, control_selector); - } - - return value; -} - -static int -in_rq_range(struct usb_function *fn, const struct usb_ctrlrequest *cr) -{ - struct usb_request *req = fn->config->cdev->req; - struct audio_dev *agdev = func_to_agdev(fn); - struct snd_uac2_chip *uac2 = &agdev->uac2; - u16 w_length = le16_to_cpu(cr->wLength); - u16 w_index = le16_to_cpu(cr->wIndex); - u16 w_value = le16_to_cpu(cr->wValue); - u8 entity_id = (w_index >> 8) & 0xff; - u8 control_selector = w_value >> 8; - struct cntrl_range_lay3 r; - int value = -EOPNOTSUPP; - - if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) { - if (entity_id == USB_IN_CLK_ID) - r.dMIN = p_srate; - else if (entity_id == USB_OUT_CLK_ID) - r.dMIN = c_srate; - else - return -EOPNOTSUPP; - - r.dMAX = r.dMIN; - r.dRES = 0; - r.wNumSubRanges = 1; - - value = min_t(unsigned, w_length, sizeof r); - memcpy(req->buf, &r, value); - } else { - dev_err(&uac2->pdev.dev, - "%s:%d control_selector=%d TODO!\n", - __func__, __LINE__, control_selector); - } - - return value; -} - -static int -ac_rq_in(struct usb_function *fn, const struct usb_ctrlrequest *cr) -{ - if (cr->bRequest == UAC2_CS_CUR) - return in_rq_cur(fn, cr); - else if (cr->bRequest == UAC2_CS_RANGE) - return in_rq_range(fn, cr); - else - return -EOPNOTSUPP; -} - -static int -out_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr) -{ - u16 w_length = le16_to_cpu(cr->wLength); - u16 w_value = le16_to_cpu(cr->wValue); - u8 control_selector = w_value >> 8; - - if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) - return w_length; - - return -EOPNOTSUPP; -} - -static int -setup_rq_inf(struct usb_function *fn, const struct usb_ctrlrequest *cr) -{ - struct audio_dev *agdev = func_to_agdev(fn); - struct snd_uac2_chip *uac2 = &agdev->uac2; - u16 w_index = le16_to_cpu(cr->wIndex); - u8 intf = w_index & 0xff; - - if (intf != INTF_GET(agdev->ac_alt)) { - dev_err(&uac2->pdev.dev, - "%s:%d Error!\n", __func__, __LINE__); - return -EOPNOTSUPP; - } - - if (cr->bRequestType & USB_DIR_IN) - return ac_rq_in(fn, cr); - else if (cr->bRequest == UAC2_CS_CUR) - return out_rq_cur(fn, cr); - - return -EOPNOTSUPP; -} - -static int -afunc_setup(struct usb_function *fn, const struct usb_ctrlrequest *cr) -{ - struct usb_composite_dev *cdev = fn->config->cdev; - struct audio_dev *agdev = func_to_agdev(fn); - struct snd_uac2_chip *uac2 = &agdev->uac2; - struct usb_request *req = cdev->req; - u16 w_length = le16_to_cpu(cr->wLength); - int value = -EOPNOTSUPP; - - /* Only Class specific requests are supposed to reach here */ - if ((cr->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS) - return -EOPNOTSUPP; - - if ((cr->bRequestType & USB_RECIP_MASK) == USB_RECIP_INTERFACE) - value = setup_rq_inf(fn, cr); - else - dev_err(&uac2->pdev.dev, "%s:%d Error!\n", __func__, __LINE__); - - if (value >= 0) { - req->length = value; - req->zero = value < w_length; - value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); - if (value < 0) { - dev_err(&uac2->pdev.dev, - "%s:%d Error!\n", __func__, __LINE__); - req->status = 0; - } - } - - return value; -} - -static int audio_bind_config(struct usb_configuration *cfg) -{ - int id, res; - - agdev_g = kzalloc(sizeof *agdev_g, GFP_KERNEL); - if (agdev_g == NULL) { - printk(KERN_ERR "Unable to allocate audio gadget\n"); - return -ENOMEM; - } - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_ASSOC].id = id; - iad_desc.iFunction = id, - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_IF_CTRL].id = id; - std_ac_if_desc.iInterface = id, - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_CLKSRC_IN].id = id; - in_clk_src_desc.iClockSource = id, - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_CLKSRC_OUT].id = id; - out_clk_src_desc.iClockSource = id, - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_USB_IT].id = id; - usb_out_it_desc.iTerminal = id, - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_IO_IT].id = id; - io_in_it_desc.iTerminal = id; - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_USB_OT].id = id; - usb_in_ot_desc.iTerminal = id; - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_IO_OT].id = id; - io_out_ot_desc.iTerminal = id; - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_AS_OUT_ALT0].id = id; - std_as_out_if0_desc.iInterface = id; - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_AS_OUT_ALT1].id = id; - std_as_out_if1_desc.iInterface = id; - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_AS_IN_ALT0].id = id; - std_as_in_if0_desc.iInterface = id; - - id = usb_string_id(cfg->cdev); - if (id < 0) - return id; - - strings_fn[STR_AS_IN_ALT1].id = id; - std_as_in_if1_desc.iInterface = id; - - agdev_g->func.name = "uac2_func"; - agdev_g->func.strings = fn_strings; - agdev_g->func.bind = afunc_bind; - agdev_g->func.unbind = afunc_unbind; - agdev_g->func.set_alt = afunc_set_alt; - agdev_g->func.get_alt = afunc_get_alt; - agdev_g->func.disable = afunc_disable; - agdev_g->func.setup = afunc_setup; - - /* Initialize the configurable parameters */ - usb_out_it_desc.bNrChannels = num_channels(c_chmask); - usb_out_it_desc.bmChannelConfig = cpu_to_le32(c_chmask); - io_in_it_desc.bNrChannels = num_channels(p_chmask); - io_in_it_desc.bmChannelConfig = cpu_to_le32(p_chmask); - as_out_hdr_desc.bNrChannels = num_channels(c_chmask); - as_out_hdr_desc.bmChannelConfig = cpu_to_le32(c_chmask); - as_in_hdr_desc.bNrChannels = num_channels(p_chmask); - as_in_hdr_desc.bmChannelConfig = cpu_to_le32(p_chmask); - as_out_fmt1_desc.bSubslotSize = c_ssize; - as_out_fmt1_desc.bBitResolution = c_ssize * 8; - as_in_fmt1_desc.bSubslotSize = p_ssize; - as_in_fmt1_desc.bBitResolution = p_ssize * 8; - - snprintf(clksrc_in, sizeof(clksrc_in), "%uHz", p_srate); - snprintf(clksrc_out, sizeof(clksrc_out), "%uHz", c_srate); - - res = usb_add_function(cfg, &agdev_g->func); - if (res < 0) - kfree(agdev_g); - - return res; -} - -static void -uac2_unbind_config(struct usb_configuration *cfg) -{ - kfree(agdev_g); - agdev_g = NULL; -} diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_uvc.c b/ANDROID_3.4.5/drivers/usb/gadget/f_uvc.c deleted file mode 100644 index 2022fe49..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_uvc.c +++ /dev/null @@ -1,662 +0,0 @@ -/* - * uvc_gadget.c -- USB Video Class Gadget driver - * - * Copyright (C) 2009-2010 - * Laurent Pinchart (laurent.pinchart@ideasonboard.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "uvc.h" - -unsigned int uvc_gadget_trace_param; - -/* -------------------------------------------------------------------------- - * Function descriptors - */ - -/* string IDs are assigned dynamically */ - -#define UVC_STRING_ASSOCIATION_IDX 0 -#define UVC_STRING_CONTROL_IDX 1 -#define UVC_STRING_STREAMING_IDX 2 - -static struct usb_string uvc_en_us_strings[] = { - [UVC_STRING_ASSOCIATION_IDX].s = "UVC Camera", - [UVC_STRING_CONTROL_IDX].s = "Video Control", - [UVC_STRING_STREAMING_IDX].s = "Video Streaming", - { } -}; - -static struct usb_gadget_strings uvc_stringtab = { - .language = 0x0409, /* en-us */ - .strings = uvc_en_us_strings, -}; - -static struct usb_gadget_strings *uvc_function_strings[] = { - &uvc_stringtab, - NULL, -}; - -#define UVC_INTF_VIDEO_CONTROL 0 -#define UVC_INTF_VIDEO_STREAMING 1 - -static struct usb_interface_assoc_descriptor uvc_iad __initdata = { - .bLength = sizeof(uvc_iad), - .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, - .bFirstInterface = 0, - .bInterfaceCount = 2, - .bFunctionClass = USB_CLASS_VIDEO, - .bFunctionSubClass = UVC_SC_VIDEO_INTERFACE_COLLECTION, - .bFunctionProtocol = 0x00, - .iFunction = 0, -}; - -static struct usb_interface_descriptor uvc_control_intf __initdata = { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = UVC_INTF_VIDEO_CONTROL, - .bAlternateSetting = 0, - .bNumEndpoints = 1, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = UVC_SC_VIDEOCONTROL, - .bInterfaceProtocol = 0x00, - .iInterface = 0, -}; - -static struct usb_endpoint_descriptor uvc_control_ep __initdata = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(16), - .bInterval = 8, -}; - -static struct uvc_control_endpoint_descriptor uvc_control_cs_ep __initdata = { - .bLength = UVC_DT_CONTROL_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_CS_ENDPOINT, - .bDescriptorSubType = UVC_EP_INTERRUPT, - .wMaxTransferSize = cpu_to_le16(16), -}; - -static struct usb_interface_descriptor uvc_streaming_intf_alt0 __initdata = { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = UVC_INTF_VIDEO_STREAMING, - .bAlternateSetting = 0, - .bNumEndpoints = 0, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = UVC_SC_VIDEOSTREAMING, - .bInterfaceProtocol = 0x00, - .iInterface = 0, -}; - -static struct usb_interface_descriptor uvc_streaming_intf_alt1 __initdata = { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = UVC_INTF_VIDEO_STREAMING, - .bAlternateSetting = 1, - .bNumEndpoints = 1, - .bInterfaceClass = USB_CLASS_VIDEO, - .bInterfaceSubClass = UVC_SC_VIDEOSTREAMING, - .bInterfaceProtocol = 0x00, - .iInterface = 0, -}; - -static struct usb_endpoint_descriptor uvc_streaming_ep = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_ISOC, - .wMaxPacketSize = cpu_to_le16(512), - .bInterval = 1, -}; - -static const struct usb_descriptor_header * const uvc_fs_streaming[] = { - (struct usb_descriptor_header *) &uvc_streaming_intf_alt1, - (struct usb_descriptor_header *) &uvc_streaming_ep, - NULL, -}; - -static const struct usb_descriptor_header * const uvc_hs_streaming[] = { - (struct usb_descriptor_header *) &uvc_streaming_intf_alt1, - (struct usb_descriptor_header *) &uvc_streaming_ep, - NULL, -}; - -/* -------------------------------------------------------------------------- - * Control requests - */ - -static void -uvc_function_ep0_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct uvc_device *uvc = req->context; - struct v4l2_event v4l2_event; - struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; - - if (uvc->event_setup_out) { - uvc->event_setup_out = 0; - - memset(&v4l2_event, 0, sizeof(v4l2_event)); - v4l2_event.type = UVC_EVENT_DATA; - uvc_event->data.length = req->actual; - memcpy(&uvc_event->data.data, req->buf, req->actual); - v4l2_event_queue(uvc->vdev, &v4l2_event); - } -} - -static int -uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) -{ - struct uvc_device *uvc = to_uvc(f); - struct v4l2_event v4l2_event; - struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; - - /* printk(KERN_INFO "setup request %02x %02x value %04x index %04x %04x\n", - * ctrl->bRequestType, ctrl->bRequest, le16_to_cpu(ctrl->wValue), - * le16_to_cpu(ctrl->wIndex), le16_to_cpu(ctrl->wLength)); - */ - - if ((ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS) { - INFO(f->config->cdev, "invalid request type\n"); - return -EINVAL; - } - - /* Stall too big requests. */ - if (le16_to_cpu(ctrl->wLength) > UVC_MAX_REQUEST_SIZE) - return -EINVAL; - - memset(&v4l2_event, 0, sizeof(v4l2_event)); - v4l2_event.type = UVC_EVENT_SETUP; - memcpy(&uvc_event->req, ctrl, sizeof(uvc_event->req)); - v4l2_event_queue(uvc->vdev, &v4l2_event); - - return 0; -} - -static int -uvc_function_get_alt(struct usb_function *f, unsigned interface) -{ - struct uvc_device *uvc = to_uvc(f); - - INFO(f->config->cdev, "uvc_function_get_alt(%u)\n", interface); - - if (interface == uvc->control_intf) - return 0; - else if (interface != uvc->streaming_intf) - return -EINVAL; - else - return uvc->state == UVC_STATE_STREAMING ? 1 : 0; -} - -static int -uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) -{ - struct uvc_device *uvc = to_uvc(f); - struct v4l2_event v4l2_event; - struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; - - INFO(f->config->cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt); - - if (interface == uvc->control_intf) { - if (alt) - return -EINVAL; - - if (uvc->state == UVC_STATE_DISCONNECTED) { - memset(&v4l2_event, 0, sizeof(v4l2_event)); - v4l2_event.type = UVC_EVENT_CONNECT; - uvc_event->speed = f->config->cdev->gadget->speed; - v4l2_event_queue(uvc->vdev, &v4l2_event); - - uvc->state = UVC_STATE_CONNECTED; - } - - return 0; - } - - if (interface != uvc->streaming_intf) - return -EINVAL; - - /* TODO - if (usb_endpoint_xfer_bulk(&uvc->desc.vs_ep)) - return alt ? -EINVAL : 0; - */ - - switch (alt) { - case 0: - if (uvc->state != UVC_STATE_STREAMING) - return 0; - - if (uvc->video.ep) - usb_ep_disable(uvc->video.ep); - - memset(&v4l2_event, 0, sizeof(v4l2_event)); - v4l2_event.type = UVC_EVENT_STREAMOFF; - v4l2_event_queue(uvc->vdev, &v4l2_event); - - uvc->state = UVC_STATE_CONNECTED; - break; - - case 1: - if (uvc->state != UVC_STATE_CONNECTED) - return 0; - - if (uvc->video.ep) { - uvc->video.ep->desc = &uvc_streaming_ep; - usb_ep_enable(uvc->video.ep); - } - - memset(&v4l2_event, 0, sizeof(v4l2_event)); - v4l2_event.type = UVC_EVENT_STREAMON; - v4l2_event_queue(uvc->vdev, &v4l2_event); - - uvc->state = UVC_STATE_STREAMING; - break; - - default: - return -EINVAL; - } - - return 0; -} - -static void -uvc_function_disable(struct usb_function *f) -{ - struct uvc_device *uvc = to_uvc(f); - struct v4l2_event v4l2_event; - - INFO(f->config->cdev, "uvc_function_disable\n"); - - memset(&v4l2_event, 0, sizeof(v4l2_event)); - v4l2_event.type = UVC_EVENT_DISCONNECT; - v4l2_event_queue(uvc->vdev, &v4l2_event); - - uvc->state = UVC_STATE_DISCONNECTED; -} - -/* -------------------------------------------------------------------------- - * Connection / disconnection - */ - -void -uvc_function_connect(struct uvc_device *uvc) -{ - struct usb_composite_dev *cdev = uvc->func.config->cdev; - int ret; - - if ((ret = usb_function_activate(&uvc->func)) < 0) - INFO(cdev, "UVC connect failed with %d\n", ret); -} - -void -uvc_function_disconnect(struct uvc_device *uvc) -{ - struct usb_composite_dev *cdev = uvc->func.config->cdev; - int ret; - - if ((ret = usb_function_deactivate(&uvc->func)) < 0) - INFO(cdev, "UVC disconnect failed with %d\n", ret); -} - -/* -------------------------------------------------------------------------- - * USB probe and disconnect - */ - -static int -uvc_register_video(struct uvc_device *uvc) -{ - struct usb_composite_dev *cdev = uvc->func.config->cdev; - struct video_device *video; - - /* TODO reference counting. */ - video = video_device_alloc(); - if (video == NULL) - return -ENOMEM; - - video->parent = &cdev->gadget->dev; - video->minor = -1; - video->fops = &uvc_v4l2_fops; - video->release = video_device_release; - strncpy(video->name, cdev->gadget->name, sizeof(video->name)); - - uvc->vdev = video; - video_set_drvdata(video, uvc); - - return video_register_device(video, VFL_TYPE_GRABBER, -1); -} - -#define UVC_COPY_DESCRIPTOR(mem, dst, desc) \ - do { \ - memcpy(mem, desc, (desc)->bLength); \ - *(dst)++ = mem; \ - mem += (desc)->bLength; \ - } while (0); - -#define UVC_COPY_DESCRIPTORS(mem, dst, src) \ - do { \ - const struct usb_descriptor_header * const *__src; \ - for (__src = src; *__src; ++__src) { \ - memcpy(mem, *__src, (*__src)->bLength); \ - *dst++ = mem; \ - mem += (*__src)->bLength; \ - } \ - } while (0) - -static struct usb_descriptor_header ** __init -uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) -{ - struct uvc_input_header_descriptor *uvc_streaming_header; - struct uvc_header_descriptor *uvc_control_header; - const struct uvc_descriptor_header * const *uvc_streaming_cls; - const struct usb_descriptor_header * const *uvc_streaming_std; - const struct usb_descriptor_header * const *src; - struct usb_descriptor_header **dst; - struct usb_descriptor_header **hdr; - unsigned int control_size; - unsigned int streaming_size; - unsigned int n_desc; - unsigned int bytes; - void *mem; - - uvc_streaming_cls = (speed == USB_SPEED_FULL) - ? uvc->desc.fs_streaming : uvc->desc.hs_streaming; - uvc_streaming_std = (speed == USB_SPEED_FULL) - ? uvc_fs_streaming : uvc_hs_streaming; - - /* Descriptors layout - * - * uvc_iad - * uvc_control_intf - * Class-specific UVC control descriptors - * uvc_control_ep - * uvc_control_cs_ep - * uvc_streaming_intf_alt0 - * Class-specific UVC streaming descriptors - * uvc_{fs|hs}_streaming - */ - - /* Count descriptors and compute their size. */ - control_size = 0; - streaming_size = 0; - bytes = uvc_iad.bLength + uvc_control_intf.bLength - + uvc_control_ep.bLength + uvc_control_cs_ep.bLength - + uvc_streaming_intf_alt0.bLength; - n_desc = 5; - - for (src = (const struct usb_descriptor_header**)uvc->desc.control; *src; ++src) { - control_size += (*src)->bLength; - bytes += (*src)->bLength; - n_desc++; - } - for (src = (const struct usb_descriptor_header**)uvc_streaming_cls; *src; ++src) { - streaming_size += (*src)->bLength; - bytes += (*src)->bLength; - n_desc++; - } - for (src = uvc_streaming_std; *src; ++src) { - bytes += (*src)->bLength; - n_desc++; - } - - mem = kmalloc((n_desc + 1) * sizeof(*src) + bytes, GFP_KERNEL); - if (mem == NULL) - return NULL; - - hdr = mem; - dst = mem; - mem += (n_desc + 1) * sizeof(*src); - - /* Copy the descriptors. */ - UVC_COPY_DESCRIPTOR(mem, dst, &uvc_iad); - UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_intf); - - uvc_control_header = mem; - UVC_COPY_DESCRIPTORS(mem, dst, - (const struct usb_descriptor_header**)uvc->desc.control); - uvc_control_header->wTotalLength = cpu_to_le16(control_size); - uvc_control_header->bInCollection = 1; - uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf; - - UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_ep); - UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_cs_ep); - UVC_COPY_DESCRIPTOR(mem, dst, &uvc_streaming_intf_alt0); - - uvc_streaming_header = mem; - UVC_COPY_DESCRIPTORS(mem, dst, - (const struct usb_descriptor_header**)uvc_streaming_cls); - uvc_streaming_header->wTotalLength = cpu_to_le16(streaming_size); - uvc_streaming_header->bEndpointAddress = uvc_streaming_ep.bEndpointAddress; - - UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std); - - *dst = NULL; - return hdr; -} - -static void -uvc_function_unbind(struct usb_configuration *c, struct usb_function *f) -{ - struct usb_composite_dev *cdev = c->cdev; - struct uvc_device *uvc = to_uvc(f); - - INFO(cdev, "uvc_function_unbind\n"); - - if (uvc->vdev) { - if (uvc->vdev->minor == -1) - video_device_release(uvc->vdev); - else - video_unregister_device(uvc->vdev); - uvc->vdev = NULL; - } - - if (uvc->control_ep) - uvc->control_ep->driver_data = NULL; - if (uvc->video.ep) - uvc->video.ep->driver_data = NULL; - - if (uvc->control_req) { - usb_ep_free_request(cdev->gadget->ep0, uvc->control_req); - kfree(uvc->control_buf); - } - - kfree(f->descriptors); - kfree(f->hs_descriptors); - - kfree(uvc); -} - -static int __init -uvc_function_bind(struct usb_configuration *c, struct usb_function *f) -{ - struct usb_composite_dev *cdev = c->cdev; - struct uvc_device *uvc = to_uvc(f); - struct usb_ep *ep; - int ret = -EINVAL; - - INFO(cdev, "uvc_function_bind\n"); - - /* Allocate endpoints. */ - ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep); - if (!ep) { - INFO(cdev, "Unable to allocate control EP\n"); - goto error; - } - uvc->control_ep = ep; - ep->driver_data = uvc; - - ep = usb_ep_autoconfig(cdev->gadget, &uvc_streaming_ep); - if (!ep) { - INFO(cdev, "Unable to allocate streaming EP\n"); - goto error; - } - uvc->video.ep = ep; - ep->driver_data = uvc; - - /* Allocate interface IDs. */ - if ((ret = usb_interface_id(c, f)) < 0) - goto error; - uvc_iad.bFirstInterface = ret; - uvc_control_intf.bInterfaceNumber = ret; - uvc->control_intf = ret; - - if ((ret = usb_interface_id(c, f)) < 0) - goto error; - uvc_streaming_intf_alt0.bInterfaceNumber = ret; - uvc_streaming_intf_alt1.bInterfaceNumber = ret; - uvc->streaming_intf = ret; - - /* Copy descriptors. */ - f->descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL); - f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH); - - /* Preallocate control endpoint request. */ - uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL); - uvc->control_buf = kmalloc(UVC_MAX_REQUEST_SIZE, GFP_KERNEL); - if (uvc->control_req == NULL || uvc->control_buf == NULL) { - ret = -ENOMEM; - goto error; - } - - uvc->control_req->buf = uvc->control_buf; - uvc->control_req->complete = uvc_function_ep0_complete; - uvc->control_req->context = uvc; - - /* Avoid letting this gadget enumerate until the userspace server is - * active. - */ - if ((ret = usb_function_deactivate(f)) < 0) - goto error; - - /* Initialise video. */ - ret = uvc_video_init(&uvc->video); - if (ret < 0) - goto error; - - /* Register a V4L2 device. */ - ret = uvc_register_video(uvc); - if (ret < 0) { - printk(KERN_INFO "Unable to register video device\n"); - goto error; - } - - return 0; - -error: - uvc_function_unbind(c, f); - return ret; -} - -/* -------------------------------------------------------------------------- - * USB gadget function - */ - -/** - * uvc_bind_config - add a UVC function to a configuration - * @c: the configuration to support the UVC instance - * Context: single threaded during gadget setup - * - * Returns zero on success, else negative errno. - * - * Caller must have called @uvc_setup(). Caller is also responsible for - * calling @uvc_cleanup() before module unload. - */ -int __init -uvc_bind_config(struct usb_configuration *c, - const struct uvc_descriptor_header * const *control, - const struct uvc_descriptor_header * const *fs_streaming, - const struct uvc_descriptor_header * const *hs_streaming) -{ - struct uvc_device *uvc; - int ret = 0; - - /* TODO Check if the USB device controller supports the required - * features. - */ - if (!gadget_is_dualspeed(c->cdev->gadget)) - return -EINVAL; - - uvc = kzalloc(sizeof(*uvc), GFP_KERNEL); - if (uvc == NULL) - return -ENOMEM; - - uvc->state = UVC_STATE_DISCONNECTED; - - /* Validate the descriptors. */ - if (control == NULL || control[0] == NULL || - control[0]->bDescriptorSubType != UVC_VC_HEADER) - goto error; - - if (fs_streaming == NULL || fs_streaming[0] == NULL || - fs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER) - goto error; - - if (hs_streaming == NULL || hs_streaming[0] == NULL || - hs_streaming[0]->bDescriptorSubType != UVC_VS_INPUT_HEADER) - goto error; - - uvc->desc.control = control; - uvc->desc.fs_streaming = fs_streaming; - uvc->desc.hs_streaming = hs_streaming; - - /* Allocate string descriptor numbers. */ - if ((ret = usb_string_id(c->cdev)) < 0) - goto error; - uvc_en_us_strings[UVC_STRING_ASSOCIATION_IDX].id = ret; - uvc_iad.iFunction = ret; - - if ((ret = usb_string_id(c->cdev)) < 0) - goto error; - uvc_en_us_strings[UVC_STRING_CONTROL_IDX].id = ret; - uvc_control_intf.iInterface = ret; - - if ((ret = usb_string_id(c->cdev)) < 0) - goto error; - uvc_en_us_strings[UVC_STRING_STREAMING_IDX].id = ret; - uvc_streaming_intf_alt0.iInterface = ret; - uvc_streaming_intf_alt1.iInterface = ret; - - /* Register the function. */ - uvc->func.name = "uvc"; - uvc->func.strings = uvc_function_strings; - uvc->func.bind = uvc_function_bind; - uvc->func.unbind = uvc_function_unbind; - uvc->func.get_alt = uvc_function_get_alt; - uvc->func.set_alt = uvc_function_set_alt; - uvc->func.disable = uvc_function_disable; - uvc->func.setup = uvc_function_setup; - - ret = usb_add_function(c, &uvc->func); - if (ret) - kfree(uvc); - - return ret; - -error: - kfree(uvc); - return ret; -} - -module_param_named(trace, uvc_gadget_trace_param, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(trace, "Trace level bitmask"); - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/f_uvc.h b/ANDROID_3.4.5/drivers/usb/gadget/f_uvc.h deleted file mode 100644 index abf83293..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/f_uvc.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * f_uvc.h -- USB Video Class Gadget driver - * - * Copyright (C) 2009-2010 - * Laurent Pinchart (laurent.pinchart@ideasonboard.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef _F_UVC_H_ -#define _F_UVC_H_ - -#include -#include - -extern int uvc_bind_config(struct usb_configuration *c, - const struct uvc_descriptor_header * const *control, - const struct uvc_descriptor_header * const *fs_streaming, - const struct uvc_descriptor_header * const *hs_streaming); - -#endif /* _F_UVC_H_ */ - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/file_storage.c b/ANDROID_3.4.5/drivers/usb/gadget/file_storage.c deleted file mode 100644 index a896d73f..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/file_storage.c +++ /dev/null @@ -1,3676 +0,0 @@ -/* - * file_storage.c -- File-backed USB Storage Gadget, for USB development - * - * Copyright (C) 2003-2008 Alan Stern - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The names of the above-listed copyright holders may not be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - -/* - * The File-backed Storage Gadget acts as a USB Mass Storage device, - * appearing to the host as a disk drive or as a CD-ROM drive. In addition - * to providing an example of a genuinely useful gadget driver for a USB - * device, it also illustrates a technique of double-buffering for increased - * throughput. Last but not least, it gives an easy way to probe the - * behavior of the Mass Storage drivers in a USB host. - * - * Backing storage is provided by a regular file or a block device, specified - * by the "file" module parameter. Access can be limited to read-only by - * setting the optional "ro" module parameter. (For CD-ROM emulation, - * access is always read-only.) The gadget will indicate that it has - * removable media if the optional "removable" module parameter is set. - * - * The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI), - * and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected - * by the optional "transport" module parameter. It also supports the - * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03), - * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by - * the optional "protocol" module parameter. In addition, the default - * Vendor ID, Product ID, release number and serial number can be overridden. - * - * There is support for multiple logical units (LUNs), each of which has - * its own backing file. The number of LUNs can be set using the optional - * "luns" module parameter (anywhere from 1 to 8), and the corresponding - * files are specified using comma-separated lists for "file" and "ro". - * The default number of LUNs is taken from the number of "file" elements; - * it is 1 if "file" is not given. If "removable" is not set then a backing - * file must be specified for each LUN. If it is set, then an unspecified - * or empty backing filename means the LUN's medium is not loaded. Ideally - * each LUN would be settable independently as a disk drive or a CD-ROM - * drive, but currently all LUNs have to be the same type. The CD-ROM - * emulation includes a single data track and no audio tracks; hence there - * need be only one backing file per LUN. - * - * Requirements are modest; only a bulk-in and a bulk-out endpoint are - * needed (an interrupt-out endpoint is also needed for CBI). The memory - * requirement amounts to two 16K buffers, size configurable by a parameter. - * Support is included for both full-speed and high-speed operation. - * - * Note that the driver is slightly non-portable in that it assumes a - * single memory/DMA buffer will be useable for bulk-in, bulk-out, and - * interrupt-in endpoints. With most device controllers this isn't an - * issue, but there may be some with hardware restrictions that prevent - * a buffer from being used by more than one endpoint. - * - * Module options: - * - * file=filename[,filename...] - * Required if "removable" is not set, names of - * the files or block devices used for - * backing storage - * serial=HHHH... Required serial number (string of hex chars) - * ro=b[,b...] Default false, booleans for read-only access - * removable Default false, boolean for removable media - * luns=N Default N = number of filenames, number of - * LUNs to support - * nofua=b[,b...] Default false, booleans for ignore FUA flag - * in SCSI WRITE(10,12) commands - * stall Default determined according to the type of - * USB device controller (usually true), - * boolean to permit the driver to halt - * bulk endpoints - * cdrom Default false, boolean for whether to emulate - * a CD-ROM drive - * transport=XXX Default BBB, transport name (CB, CBI, or BBB) - * protocol=YYY Default SCSI, protocol name (RBC, 8020 or - * ATAPI, QIC, UFI, 8070, or SCSI; - * also 1 - 6) - * vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID - * product=0xPPPP Default 0xa4a5 (FSG), USB Product ID - * release=0xRRRR Override the USB release number (bcdDevice) - * buflen=N Default N=16384, buffer size used (will be - * rounded down to a multiple of - * PAGE_CACHE_SIZE) - * - * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "serial", "ro", - * "removable", "luns", "nofua", "stall", and "cdrom" options are available; - * default values are used for everything else. - * - * The pathnames of the backing files and the ro settings are available in - * the attribute files "file", "nofua", and "ro" in the lun subdirectory of - * the gadget's sysfs directory. If the "removable" option is set, writing to - * these files will simulate ejecting/loading the medium (writing an empty - * line means eject) and adjusting a write-enable tab. Changes to the ro - * setting are not allowed when the medium is loaded or if CD-ROM emulation - * is being used. - * - * This gadget driver is heavily based on "Gadget Zero" by David Brownell. - * The driver's SCSI command interface was based on the "Information - * technology - Small Computer System Interface - 2" document from - * X3T9.2 Project 375D, Revision 10L, 7-SEP-93, available at - * . The single exception - * is opcode 0x23 (READ FORMAT CAPACITIES), which was based on the - * "Universal Serial Bus Mass Storage Class UFI Command Specification" - * document, Revision 1.0, December 14, 1998, available at - * . - */ - - -/* - * Driver Design - * - * The FSG driver is fairly straightforward. There is a main kernel - * thread that handles most of the work. Interrupt routines field - * callbacks from the controller driver: bulk- and interrupt-request - * completion notifications, endpoint-0 events, and disconnect events. - * Completion events are passed to the main thread by wakeup calls. Many - * ep0 requests are handled at interrupt time, but SetInterface, - * SetConfiguration, and device reset requests are forwarded to the - * thread in the form of "exceptions" using SIGUSR1 signals (since they - * should interrupt any ongoing file I/O operations). - * - * The thread's main routine implements the standard command/data/status - * parts of a SCSI interaction. It and its subroutines are full of tests - * for pending signals/exceptions -- all this polling is necessary since - * the kernel has no setjmp/longjmp equivalents. (Maybe this is an - * indication that the driver really wants to be running in userspace.) - * An important point is that so long as the thread is alive it keeps an - * open reference to the backing file. This will prevent unmounting - * the backing file's underlying filesystem and could cause problems - * during system shutdown, for example. To prevent such problems, the - * thread catches INT, TERM, and KILL signals and converts them into - * an EXIT exception. - * - * In normal operation the main thread is started during the gadget's - * fsg_bind() callback and stopped during fsg_unbind(). But it can also - * exit when it receives a signal, and there's no point leaving the - * gadget running when the thread is dead. So just before the thread - * exits, it deregisters the gadget driver. This makes things a little - * tricky: The driver is deregistered at two places, and the exiting - * thread can indirectly call fsg_unbind() which in turn can tell the - * thread to exit. The first problem is resolved through the use of the - * REGISTERED atomic bitflag; the driver will only be deregistered once. - * The second problem is resolved by having fsg_unbind() check - * fsg->state; it won't try to stop the thread if the state is already - * FSG_STATE_TERMINATED. - * - * To provide maximum throughput, the driver uses a circular pipeline of - * buffer heads (struct fsg_buffhd). In principle the pipeline can be - * arbitrarily long; in practice the benefits don't justify having more - * than 2 stages (i.e., double buffering). But it helps to think of the - * pipeline as being a long one. Each buffer head contains a bulk-in and - * a bulk-out request pointer (since the buffer can be used for both - * output and input -- directions always are given from the host's - * point of view) as well as a pointer to the buffer and various state - * variables. - * - * Use of the pipeline follows a simple protocol. There is a variable - * (fsg->next_buffhd_to_fill) that points to the next buffer head to use. - * At any time that buffer head may still be in use from an earlier - * request, so each buffer head has a state variable indicating whether - * it is EMPTY, FULL, or BUSY. Typical use involves waiting for the - * buffer head to be EMPTY, filling the buffer either by file I/O or by - * USB I/O (during which the buffer head is BUSY), and marking the buffer - * head FULL when the I/O is complete. Then the buffer will be emptied - * (again possibly by USB I/O, during which it is marked BUSY) and - * finally marked EMPTY again (possibly by a completion routine). - * - * A module parameter tells the driver to avoid stalling the bulk - * endpoints wherever the transport specification allows. This is - * necessary for some UDCs like the SuperH, which cannot reliably clear a - * halt on a bulk endpoint. However, under certain circumstances the - * Bulk-only specification requires a stall. In such cases the driver - * will halt the endpoint and set a flag indicating that it should clear - * the halt in software during the next device reset. Hopefully this - * will permit everything to work correctly. Furthermore, although the - * specification allows the bulk-out endpoint to halt when the host sends - * too much data, implementing this would cause an unavoidable race. - * The driver will always use the "no-stall" approach for OUT transfers. - * - * One subtle point concerns sending status-stage responses for ep0 - * requests. Some of these requests, such as device reset, can involve - * interrupting an ongoing file I/O operation, which might take an - * arbitrarily long time. During that delay the host might give up on - * the original ep0 request and issue a new one. When that happens the - * driver should not notify the host about completion of the original - * request, as the host will no longer be waiting for it. So the driver - * assigns to each ep0 request a unique tag, and it keeps track of the - * tag value of the request associated with a long-running exception - * (device-reset, interface-change, or configuration-change). When the - * exception handler is finished, the status-stage response is submitted - * only if the current ep0 request tag is equal to the exception request - * tag. Thus only the most recently received ep0 request will get a - * status-stage response. - * - * Warning: This driver source file is too long. It ought to be split up - * into a header file plus about 3 separate .c files, to handle the details - * of the Gadget, USB Mass Storage, and SCSI protocols. - */ - - -/* #define VERBOSE_DEBUG */ -/* #define DUMP_MSGS */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "gadget_chips.h" - - - -/* - * 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 "usbstring.c" -#include "config.c" -#include "epautoconf.c" - -/*-------------------------------------------------------------------------*/ - -#define DRIVER_DESC "File-backed Storage Gadget" -#define DRIVER_NAME "g_file_storage" -#define DRIVER_VERSION "1 September 2010" - -static char fsg_string_manufacturer[64]; -static const char fsg_string_product[] = DRIVER_DESC; -static const char fsg_string_config[] = "Self-powered"; -static const char fsg_string_interface[] = "Mass Storage"; - - -#include "storage_common.c" - - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Alan Stern"); -MODULE_LICENSE("Dual BSD/GPL"); - -/* - * This driver assumes self-powered hardware and has no way for users to - * trigger remote wakeup. It uses autoconfiguration to select endpoints - * and endpoint addresses. - */ - - -/*-------------------------------------------------------------------------*/ - - -/* Encapsulate the module parameter settings */ - -static struct { - char *file[FSG_MAX_LUNS]; - char *serial; - bool ro[FSG_MAX_LUNS]; - bool nofua[FSG_MAX_LUNS]; - unsigned int num_filenames; - unsigned int num_ros; - unsigned int num_nofuas; - unsigned int nluns; - - bool removable; - bool can_stall; - bool cdrom; - - char *transport_parm; - char *protocol_parm; - unsigned short vendor; - unsigned short product; - unsigned short release; - unsigned int buflen; - - int transport_type; - char *transport_name; - int protocol_type; - char *protocol_name; - -} mod_data = { // Default values - .transport_parm = "BBB", - .protocol_parm = "SCSI", - .removable = 0, - .can_stall = 1, - .cdrom = 0, - .vendor = FSG_VENDOR_ID, - .product = FSG_PRODUCT_ID, - .release = 0xffff, // Use controller chip type - .buflen = 16384, - }; - - -module_param_array_named(file, mod_data.file, charp, &mod_data.num_filenames, - S_IRUGO); -MODULE_PARM_DESC(file, "names of backing files or devices"); - -module_param_named(serial, mod_data.serial, charp, S_IRUGO); -MODULE_PARM_DESC(serial, "USB serial number"); - -module_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO); -MODULE_PARM_DESC(ro, "true to force read-only"); - -module_param_array_named(nofua, mod_data.nofua, bool, &mod_data.num_nofuas, - S_IRUGO); -MODULE_PARM_DESC(nofua, "true to ignore SCSI WRITE(10,12) FUA bit"); - -module_param_named(luns, mod_data.nluns, uint, S_IRUGO); -MODULE_PARM_DESC(luns, "number of LUNs"); - -module_param_named(removable, mod_data.removable, bool, S_IRUGO); -MODULE_PARM_DESC(removable, "true to simulate removable media"); - -module_param_named(stall, mod_data.can_stall, bool, S_IRUGO); -MODULE_PARM_DESC(stall, "false to prevent bulk stalls"); - -module_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO); -MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk"); - -/* In the non-TEST version, only the module parameters listed above - * are available. */ -#ifdef CONFIG_USB_FILE_STORAGE_TEST - -module_param_named(transport, mod_data.transport_parm, charp, S_IRUGO); -MODULE_PARM_DESC(transport, "type of transport (BBB, CBI, or CB)"); - -module_param_named(protocol, mod_data.protocol_parm, charp, S_IRUGO); -MODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, " - "8070, or SCSI)"); - -module_param_named(vendor, mod_data.vendor, ushort, S_IRUGO); -MODULE_PARM_DESC(vendor, "USB Vendor ID"); - -module_param_named(product, mod_data.product, ushort, S_IRUGO); -MODULE_PARM_DESC(product, "USB Product ID"); - -module_param_named(release, mod_data.release, ushort, S_IRUGO); -MODULE_PARM_DESC(release, "USB release number"); - -module_param_named(buflen, mod_data.buflen, uint, S_IRUGO); -MODULE_PARM_DESC(buflen, "I/O buffer size"); - -#endif /* CONFIG_USB_FILE_STORAGE_TEST */ - - -/* - * These definitions will permit the compiler to avoid generating code for - * parts of the driver that aren't used in the non-TEST version. Even gcc - * can recognize when a test of a constant expression yields a dead code - * path. - */ - -#ifdef CONFIG_USB_FILE_STORAGE_TEST - -#define transport_is_bbb() (mod_data.transport_type == USB_PR_BULK) -#define transport_is_cbi() (mod_data.transport_type == USB_PR_CBI) -#define protocol_is_scsi() (mod_data.protocol_type == USB_SC_SCSI) - -#else - -#define transport_is_bbb() 1 -#define transport_is_cbi() 0 -#define protocol_is_scsi() 1 - -#endif /* CONFIG_USB_FILE_STORAGE_TEST */ - - -/*-------------------------------------------------------------------------*/ - - -struct fsg_dev { - /* lock protects: state, all the req_busy's, and cbbuf_cmnd */ - spinlock_t lock; - struct usb_gadget *gadget; - - /* filesem protects: backing files in use */ - struct rw_semaphore filesem; - - /* reference counting: wait until all LUNs are released */ - struct kref ref; - - struct usb_ep *ep0; // Handy copy of gadget->ep0 - struct usb_request *ep0req; // For control responses - unsigned int ep0_req_tag; - const char *ep0req_name; - - struct usb_request *intreq; // For interrupt responses - int intreq_busy; - struct fsg_buffhd *intr_buffhd; - - unsigned int bulk_out_maxpacket; - enum fsg_state state; // For exception handling - unsigned int exception_req_tag; - - u8 config, new_config; - - unsigned int running : 1; - unsigned int bulk_in_enabled : 1; - unsigned int bulk_out_enabled : 1; - unsigned int intr_in_enabled : 1; - unsigned int phase_error : 1; - unsigned int short_packet_received : 1; - unsigned int bad_lun_okay : 1; - - unsigned long atomic_bitflags; -#define REGISTERED 0 -#define IGNORE_BULK_OUT 1 -#define SUSPENDED 2 - - struct usb_ep *bulk_in; - struct usb_ep *bulk_out; - struct usb_ep *intr_in; - - struct fsg_buffhd *next_buffhd_to_fill; - struct fsg_buffhd *next_buffhd_to_drain; - - int thread_wakeup_needed; - struct completion thread_notifier; - struct task_struct *thread_task; - - int cmnd_size; - u8 cmnd[MAX_COMMAND_SIZE]; - enum data_direction data_dir; - u32 data_size; - u32 data_size_from_cmnd; - u32 tag; - unsigned int lun; - u32 residue; - u32 usb_amount_left; - - /* The CB protocol offers no way for a host to know when a command - * has completed. As a result the next command may arrive early, - * and we will still have to handle it. For that reason we need - * a buffer to store new commands when using CB (or CBI, which - * does not oblige a host to wait for command completion either). */ - int cbbuf_cmnd_size; - u8 cbbuf_cmnd[MAX_COMMAND_SIZE]; - - unsigned int nluns; - struct fsg_lun *luns; - struct fsg_lun *curlun; - /* Must be the last entry */ - struct fsg_buffhd buffhds[]; -}; - -typedef void (*fsg_routine_t)(struct fsg_dev *); - -static int exception_in_progress(struct fsg_dev *fsg) -{ - return (fsg->state > FSG_STATE_IDLE); -} - -/* Make bulk-out requests be divisible by the maxpacket size */ -static void set_bulk_out_req_length(struct fsg_dev *fsg, - struct fsg_buffhd *bh, unsigned int length) -{ - unsigned int rem; - - bh->bulk_out_intended_length = length; - rem = length % fsg->bulk_out_maxpacket; - if (rem > 0) - length += fsg->bulk_out_maxpacket - rem; - bh->outreq->length = length; -} - -static struct fsg_dev *the_fsg; -static struct usb_gadget_driver fsg_driver; - - -/*-------------------------------------------------------------------------*/ - -static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) -{ - const char *name; - - if (ep == fsg->bulk_in) - name = "bulk-in"; - else if (ep == fsg->bulk_out) - name = "bulk-out"; - else - name = ep->name; - DBG(fsg, "%s set halt\n", name); - return usb_ep_set_halt(ep); -} - - -/*-------------------------------------------------------------------------*/ - -/* - * DESCRIPTORS ... most are static, but strings and (full) configuration - * descriptors are built on demand. Also the (static) config and interface - * descriptors are adjusted during fsg_bind(). - */ - -/* There is only one configuration. */ -#define CONFIG_VALUE 1 - -static struct usb_device_descriptor -device_desc = { - .bLength = sizeof device_desc, - .bDescriptorType = USB_DT_DEVICE, - - .bcdUSB = cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_PER_INTERFACE, - - /* The next three values can be overridden by module parameters */ - .idVendor = cpu_to_le16(FSG_VENDOR_ID), - .idProduct = cpu_to_le16(FSG_PRODUCT_ID), - .bcdDevice = cpu_to_le16(0xffff), - - .iManufacturer = FSG_STRING_MANUFACTURER, - .iProduct = FSG_STRING_PRODUCT, - .iSerialNumber = FSG_STRING_SERIAL, - .bNumConfigurations = 1, -}; - -static struct usb_config_descriptor -config_desc = { - .bLength = sizeof config_desc, - .bDescriptorType = USB_DT_CONFIG, - - /* wTotalLength computed by usb_gadget_config_buf() */ - .bNumInterfaces = 1, - .bConfigurationValue = CONFIG_VALUE, - .iConfiguration = FSG_STRING_CONFIG, - .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, - .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2, -}; - - -static struct usb_qualifier_descriptor -dev_qualifier = { - .bLength = sizeof dev_qualifier, - .bDescriptorType = USB_DT_DEVICE_QUALIFIER, - - .bcdUSB = cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_PER_INTERFACE, - - .bNumConfigurations = 1, -}; - -static int populate_bos(struct fsg_dev *fsg, u8 *buf) -{ - memcpy(buf, &fsg_bos_desc, USB_DT_BOS_SIZE); - buf += USB_DT_BOS_SIZE; - - memcpy(buf, &fsg_ext_cap_desc, USB_DT_USB_EXT_CAP_SIZE); - buf += USB_DT_USB_EXT_CAP_SIZE; - - memcpy(buf, &fsg_ss_cap_desc, USB_DT_USB_SS_CAP_SIZE); - - return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE - + USB_DT_USB_EXT_CAP_SIZE; -} - -/* - * Config descriptors must agree with the code that sets configurations - * and with code managing interfaces and their altsettings. They must - * also handle different speeds and other-speed requests. - */ -static int populate_config_buf(struct usb_gadget *gadget, - u8 *buf, u8 type, unsigned index) -{ - enum usb_device_speed speed = gadget->speed; - int len; - const struct usb_descriptor_header **function; - - if (index > 0) - return -EINVAL; - - if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG) - speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed; - function = gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH - ? (const struct usb_descriptor_header **)fsg_hs_function - : (const struct usb_descriptor_header **)fsg_fs_function; - - /* for now, don't advertise srp-only devices */ - if (!gadget_is_otg(gadget)) - function++; - - len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function); - ((struct usb_config_descriptor *) buf)->bDescriptorType = type; - return len; -} - - -/*-------------------------------------------------------------------------*/ - -/* These routines may be called in process context or in_irq */ - -/* Caller must hold fsg->lock */ -static void wakeup_thread(struct fsg_dev *fsg) -{ - /* Tell the main thread that something has happened */ - fsg->thread_wakeup_needed = 1; - if (fsg->thread_task) - wake_up_process(fsg->thread_task); -} - - -static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state) -{ - unsigned long flags; - - /* Do nothing if a higher-priority exception is already in progress. - * If a lower-or-equal priority exception is in progress, preempt it - * and notify the main thread by sending it a signal. */ - spin_lock_irqsave(&fsg->lock, flags); - if (fsg->state <= new_state) { - fsg->exception_req_tag = fsg->ep0_req_tag; - fsg->state = new_state; - if (fsg->thread_task) - send_sig_info(SIGUSR1, SEND_SIG_FORCED, - fsg->thread_task); - } - spin_unlock_irqrestore(&fsg->lock, flags); -} - - -/*-------------------------------------------------------------------------*/ - -/* The disconnect callback and ep0 routines. These always run in_irq, - * except that ep0_queue() is called in the main thread to acknowledge - * completion of various requests: set config, set interface, and - * Bulk-only device reset. */ - -static void fsg_disconnect(struct usb_gadget *gadget) -{ - struct fsg_dev *fsg = get_gadget_data(gadget); - - DBG(fsg, "disconnect or port reset\n"); - raise_exception(fsg, FSG_STATE_DISCONNECT); -} - - -static int ep0_queue(struct fsg_dev *fsg) -{ - int rc; - - rc = usb_ep_queue(fsg->ep0, fsg->ep0req, GFP_ATOMIC); - if (rc != 0 && rc != -ESHUTDOWN) { - - /* We can't do much more than wait for a reset */ - WARNING(fsg, "error in submission: %s --> %d\n", - fsg->ep0->name, rc); - } - return rc; -} - -static void ep0_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct fsg_dev *fsg = ep->driver_data; - - if (req->actual > 0) - dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual); - if (req->status || req->actual != req->length) - DBG(fsg, "%s --> %d, %u/%u\n", __func__, - req->status, req->actual, req->length); - if (req->status == -ECONNRESET) // Request was cancelled - usb_ep_fifo_flush(ep); - - if (req->status == 0 && req->context) - ((fsg_routine_t) (req->context))(fsg); -} - - -/*-------------------------------------------------------------------------*/ - -/* Bulk and interrupt endpoint completion handlers. - * These always run in_irq. */ - -static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct fsg_dev *fsg = ep->driver_data; - struct fsg_buffhd *bh = req->context; - - if (req->status || req->actual != req->length) - DBG(fsg, "%s --> %d, %u/%u\n", __func__, - req->status, req->actual, req->length); - if (req->status == -ECONNRESET) // Request was cancelled - usb_ep_fifo_flush(ep); - - /* Hold the lock while we update the request and buffer states */ - smp_wmb(); - spin_lock(&fsg->lock); - bh->inreq_busy = 0; - bh->state = BUF_STATE_EMPTY; - wakeup_thread(fsg); - spin_unlock(&fsg->lock); -} - -static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct fsg_dev *fsg = ep->driver_data; - struct fsg_buffhd *bh = req->context; - - dump_msg(fsg, "bulk-out", req->buf, req->actual); - if (req->status || req->actual != bh->bulk_out_intended_length) - DBG(fsg, "%s --> %d, %u/%u\n", __func__, - req->status, req->actual, - bh->bulk_out_intended_length); - if (req->status == -ECONNRESET) // Request was cancelled - usb_ep_fifo_flush(ep); - - /* Hold the lock while we update the request and buffer states */ - smp_wmb(); - spin_lock(&fsg->lock); - bh->outreq_busy = 0; - bh->state = BUF_STATE_FULL; - wakeup_thread(fsg); - spin_unlock(&fsg->lock); -} - - -#ifdef CONFIG_USB_FILE_STORAGE_TEST -static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct fsg_dev *fsg = ep->driver_data; - struct fsg_buffhd *bh = req->context; - - if (req->status || req->actual != req->length) - DBG(fsg, "%s --> %d, %u/%u\n", __func__, - req->status, req->actual, req->length); - if (req->status == -ECONNRESET) // Request was cancelled - usb_ep_fifo_flush(ep); - - /* Hold the lock while we update the request and buffer states */ - smp_wmb(); - spin_lock(&fsg->lock); - fsg->intreq_busy = 0; - bh->state = BUF_STATE_EMPTY; - wakeup_thread(fsg); - spin_unlock(&fsg->lock); -} - -#else -static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) -{} -#endif /* CONFIG_USB_FILE_STORAGE_TEST */ - - -/*-------------------------------------------------------------------------*/ - -/* Ep0 class-specific handlers. These always run in_irq. */ - -#ifdef CONFIG_USB_FILE_STORAGE_TEST -static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct usb_request *req = fsg->ep0req; - static u8 cbi_reset_cmnd[6] = { - SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff}; - - /* Error in command transfer? */ - if (req->status || req->length != req->actual || - req->actual < 6 || req->actual > MAX_COMMAND_SIZE) { - - /* Not all controllers allow a protocol stall after - * receiving control-out data, but we'll try anyway. */ - fsg_set_halt(fsg, fsg->ep0); - return; // Wait for reset - } - - /* Is it the special reset command? */ - if (req->actual >= sizeof cbi_reset_cmnd && - memcmp(req->buf, cbi_reset_cmnd, - sizeof cbi_reset_cmnd) == 0) { - - /* Raise an exception to stop the current operation - * and reinitialize our state. */ - DBG(fsg, "cbi reset request\n"); - raise_exception(fsg, FSG_STATE_RESET); - return; - } - - VDBG(fsg, "CB[I] accept device-specific command\n"); - spin_lock(&fsg->lock); - - /* Save the command for later */ - if (fsg->cbbuf_cmnd_size) - WARNING(fsg, "CB[I] overwriting previous command\n"); - fsg->cbbuf_cmnd_size = req->actual; - memcpy(fsg->cbbuf_cmnd, req->buf, fsg->cbbuf_cmnd_size); - - wakeup_thread(fsg); - spin_unlock(&fsg->lock); -} - -#else -static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{} -#endif /* CONFIG_USB_FILE_STORAGE_TEST */ - - -static int class_setup_req(struct fsg_dev *fsg, - const struct usb_ctrlrequest *ctrl) -{ - struct usb_request *req = fsg->ep0req; - 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); - - if (!fsg->config) - return value; - - /* Handle Bulk-only class-specific requests */ - if (transport_is_bbb()) { - switch (ctrl->bRequest) { - - case US_BULK_RESET_REQUEST: - if (ctrl->bRequestType != (USB_DIR_OUT | - USB_TYPE_CLASS | USB_RECIP_INTERFACE)) - break; - if (w_index != 0 || w_value != 0 || w_length != 0) { - value = -EDOM; - break; - } - - /* Raise an exception to stop the current operation - * and reinitialize our state. */ - DBG(fsg, "bulk reset request\n"); - raise_exception(fsg, FSG_STATE_RESET); - value = DELAYED_STATUS; - break; - - case US_BULK_GET_MAX_LUN: - if (ctrl->bRequestType != (USB_DIR_IN | - USB_TYPE_CLASS | USB_RECIP_INTERFACE)) - break; - if (w_index != 0 || w_value != 0 || w_length != 1) { - value = -EDOM; - break; - } - VDBG(fsg, "get max LUN\n"); - *(u8 *) req->buf = fsg->nluns - 1; - value = 1; - break; - } - } - - /* Handle CBI class-specific requests */ - else { - switch (ctrl->bRequest) { - - case USB_CBI_ADSC_REQUEST: - if (ctrl->bRequestType != (USB_DIR_OUT | - USB_TYPE_CLASS | USB_RECIP_INTERFACE)) - break; - if (w_index != 0 || w_value != 0) { - value = -EDOM; - break; - } - if (w_length > MAX_COMMAND_SIZE) { - value = -EOVERFLOW; - break; - } - value = w_length; - fsg->ep0req->context = received_cbi_adsc; - break; - } - } - - if (value == -EOPNOTSUPP) - VDBG(fsg, - "unknown class-specific control req " - "%02x.%02x v%04x i%04x l%u\n", - ctrl->bRequestType, ctrl->bRequest, - le16_to_cpu(ctrl->wValue), w_index, w_length); - return value; -} - - -/*-------------------------------------------------------------------------*/ - -/* Ep0 standard request handlers. These always run in_irq. */ - -static int standard_setup_req(struct fsg_dev *fsg, - const struct usb_ctrlrequest *ctrl) -{ - struct usb_request *req = fsg->ep0req; - int value = -EOPNOTSUPP; - u16 w_index = le16_to_cpu(ctrl->wIndex); - u16 w_value = le16_to_cpu(ctrl->wValue); - - /* Usually this just stores reply data in the pre-allocated ep0 buffer, - * but config change events will also reconfigure hardware. */ - switch (ctrl->bRequest) { - - case USB_REQ_GET_DESCRIPTOR: - if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | - USB_RECIP_DEVICE)) - break; - switch (w_value >> 8) { - - case USB_DT_DEVICE: - VDBG(fsg, "get device descriptor\n"); - device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket; - value = sizeof device_desc; - memcpy(req->buf, &device_desc, value); - break; - case USB_DT_DEVICE_QUALIFIER: - VDBG(fsg, "get device qualifier\n"); - if (!gadget_is_dualspeed(fsg->gadget) || - fsg->gadget->speed == USB_SPEED_SUPER) - break; - /* - * Assume ep0 uses the same maxpacket value for both - * speeds - */ - dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; - value = sizeof dev_qualifier; - memcpy(req->buf, &dev_qualifier, value); - break; - - case USB_DT_OTHER_SPEED_CONFIG: - VDBG(fsg, "get other-speed config descriptor\n"); - if (!gadget_is_dualspeed(fsg->gadget) || - fsg->gadget->speed == USB_SPEED_SUPER) - break; - goto get_config; - case USB_DT_CONFIG: - VDBG(fsg, "get configuration descriptor\n"); -get_config: - value = populate_config_buf(fsg->gadget, - req->buf, - w_value >> 8, - w_value & 0xff); - break; - - case USB_DT_STRING: - VDBG(fsg, "get string descriptor\n"); - - /* wIndex == language code */ - value = usb_gadget_get_string(&fsg_stringtab, - w_value & 0xff, req->buf); - break; - - case USB_DT_BOS: - VDBG(fsg, "get bos descriptor\n"); - - if (gadget_is_superspeed(fsg->gadget)) - value = populate_bos(fsg, req->buf); - break; - } - - break; - - /* One config, two speeds */ - case USB_REQ_SET_CONFIGURATION: - if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD | - USB_RECIP_DEVICE)) - break; - VDBG(fsg, "set configuration\n"); - if (w_value == CONFIG_VALUE || w_value == 0) { - fsg->new_config = w_value; - - /* Raise an exception to wipe out previous transaction - * state (queued bufs, etc) and set the new config. */ - raise_exception(fsg, FSG_STATE_CONFIG_CHANGE); - value = DELAYED_STATUS; - } - break; - case USB_REQ_GET_CONFIGURATION: - if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | - USB_RECIP_DEVICE)) - break; - VDBG(fsg, "get configuration\n"); - *(u8 *) req->buf = fsg->config; - value = 1; - break; - - case USB_REQ_SET_INTERFACE: - if (ctrl->bRequestType != (USB_DIR_OUT| USB_TYPE_STANDARD | - USB_RECIP_INTERFACE)) - break; - if (fsg->config && w_index == 0) { - - /* Raise an exception to wipe out previous transaction - * state (queued bufs, etc) and install the new - * interface altsetting. */ - raise_exception(fsg, FSG_STATE_INTERFACE_CHANGE); - value = DELAYED_STATUS; - } - break; - case USB_REQ_GET_INTERFACE: - if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | - USB_RECIP_INTERFACE)) - break; - if (!fsg->config) - break; - if (w_index != 0) { - value = -EDOM; - break; - } - VDBG(fsg, "get interface\n"); - *(u8 *) req->buf = 0; - value = 1; - break; - - default: - VDBG(fsg, - "unknown control req %02x.%02x v%04x i%04x l%u\n", - ctrl->bRequestType, ctrl->bRequest, - w_value, w_index, le16_to_cpu(ctrl->wLength)); - } - - return value; -} - - -static int fsg_setup(struct usb_gadget *gadget, - const struct usb_ctrlrequest *ctrl) -{ - struct fsg_dev *fsg = get_gadget_data(gadget); - int rc; - int w_length = le16_to_cpu(ctrl->wLength); - - ++fsg->ep0_req_tag; // Record arrival of a new request - fsg->ep0req->context = NULL; - fsg->ep0req->length = 0; - dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl)); - - if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) - rc = class_setup_req(fsg, ctrl); - else - rc = standard_setup_req(fsg, ctrl); - - /* Respond with data/status or defer until later? */ - if (rc >= 0 && rc != DELAYED_STATUS) { - rc = min(rc, w_length); - fsg->ep0req->length = rc; - fsg->ep0req->zero = rc < w_length; - fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ? - "ep0-in" : "ep0-out"); - rc = ep0_queue(fsg); - } - - /* Device either stalls (rc < 0) or reports success */ - return rc; -} - - -/*-------------------------------------------------------------------------*/ - -/* All the following routines run in process context */ - - -/* Use this for bulk or interrupt transfers, not ep0 */ -static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep, - struct usb_request *req, int *pbusy, - enum fsg_buffer_state *state) -{ - int rc; - - if (ep == fsg->bulk_in) - dump_msg(fsg, "bulk-in", req->buf, req->length); - else if (ep == fsg->intr_in) - dump_msg(fsg, "intr-in", req->buf, req->length); - - spin_lock_irq(&fsg->lock); - *pbusy = 1; - *state = BUF_STATE_BUSY; - spin_unlock_irq(&fsg->lock); - rc = usb_ep_queue(ep, req, GFP_KERNEL); - if (rc != 0) { - *pbusy = 0; - *state = BUF_STATE_EMPTY; - - /* We can't do much more than wait for a reset */ - - /* Note: currently the net2280 driver fails zero-length - * submissions if DMA is enabled. */ - if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP && - req->length == 0)) - WARNING(fsg, "error in submission: %s --> %d\n", - ep->name, rc); - } -} - - -static int sleep_thread(struct fsg_dev *fsg) -{ - int rc = 0; - - /* Wait until a signal arrives or we are woken up */ - for (;;) { - try_to_freeze(); - set_current_state(TASK_INTERRUPTIBLE); - if (signal_pending(current)) { - rc = -EINTR; - break; - } - if (fsg->thread_wakeup_needed) - break; - schedule(); - } - __set_current_state(TASK_RUNNING); - fsg->thread_wakeup_needed = 0; - return rc; -} - - -/*-------------------------------------------------------------------------*/ - -static int do_read(struct fsg_dev *fsg) -{ - struct fsg_lun *curlun = fsg->curlun; - u32 lba; - struct fsg_buffhd *bh; - int rc; - u32 amount_left; - loff_t file_offset, file_offset_tmp; - unsigned int amount; - ssize_t nread; - - /* Get the starting Logical Block Address and check that it's - * not too big */ - if (fsg->cmnd[0] == READ_6) - lba = get_unaligned_be24(&fsg->cmnd[1]); - else { - 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 - * cache), but we don't implement them. */ - if ((fsg->cmnd[1] & ~0x18) != 0) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - } - if (lba >= curlun->num_sectors) { - curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - return -EINVAL; - } - file_offset = ((loff_t) lba) << curlun->blkbits; - - /* Carry out the file reads */ - amount_left = fsg->data_size_from_cmnd; - if (unlikely(amount_left == 0)) - return -EIO; // No default reply - - for (;;) { - - /* Figure out how much we need to read: - * Try to read the remaining amount. - * But don't read more than the buffer size. - * And don't try to read past the end of the file. - */ - amount = min((unsigned int) amount_left, mod_data.buflen); - amount = min((loff_t) amount, - curlun->file_length - file_offset); - - /* Wait for the next buffer to become available */ - bh = fsg->next_buffhd_to_fill; - while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(fsg); - if (rc) - return rc; - } - - /* If we were asked to read past the end of file, - * end with an empty buffer. */ - if (amount == 0) { - curlun->sense_data = - SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->sense_data_info = file_offset >> curlun->blkbits; - curlun->info_valid = 1; - bh->inreq->length = 0; - bh->state = BUF_STATE_FULL; - break; - } - - /* Perform the read */ - file_offset_tmp = file_offset; - nread = vfs_read(curlun->filp, - (char __user *) bh->buf, - amount, &file_offset_tmp); - VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, - (unsigned long long) file_offset, - (int) nread); - if (signal_pending(current)) - return -EINTR; - - if (nread < 0) { - LDBG(curlun, "error in file read: %d\n", - (int) nread); - nread = 0; - } else if (nread < amount) { - LDBG(curlun, "partial file read: %d/%u\n", - (int) nread, amount); - nread = round_down(nread, curlun->blksize); - } - file_offset += nread; - amount_left -= nread; - fsg->residue -= nread; - - /* Except at the end of the transfer, nread will be - * equal to the buffer size, which is divisible by the - * bulk-in maxpacket size. - */ - bh->inreq->length = nread; - bh->state = BUF_STATE_FULL; - - /* If an error occurred, report it and its position */ - if (nread < amount) { - curlun->sense_data = SS_UNRECOVERED_READ_ERROR; - curlun->sense_data_info = file_offset >> curlun->blkbits; - curlun->info_valid = 1; - break; - } - - if (amount_left == 0) - break; // No more left to read - - /* Send this buffer and go read some more */ - bh->inreq->zero = 0; - start_transfer(fsg, fsg->bulk_in, bh->inreq, - &bh->inreq_busy, &bh->state); - fsg->next_buffhd_to_fill = bh->next; - } - - return -EIO; // No default reply -} - - -/*-------------------------------------------------------------------------*/ - -static int do_write(struct fsg_dev *fsg) -{ - struct fsg_lun *curlun = fsg->curlun; - u32 lba; - struct fsg_buffhd *bh; - int get_some_more; - u32 amount_left_to_req, amount_left_to_write; - loff_t usb_offset, file_offset, file_offset_tmp; - unsigned int amount; - ssize_t nwritten; - int rc; - - if (curlun->ro) { - curlun->sense_data = SS_WRITE_PROTECTED; - return -EINVAL; - } - spin_lock(&curlun->filp->f_lock); - curlun->filp->f_flags &= ~O_SYNC; // Default is not to wait - spin_unlock(&curlun->filp->f_lock); - - /* Get the starting Logical Block Address and check that it's - * not too big */ - if (fsg->cmnd[0] == WRITE_6) - lba = get_unaligned_be24(&fsg->cmnd[1]); - else { - 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 - * medium). We don't implement DPO; we implement FUA by - * performing synchronous output. */ - if ((fsg->cmnd[1] & ~0x18) != 0) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - /* FUA */ - if (!curlun->nofua && (fsg->cmnd[1] & 0x08)) { - spin_lock(&curlun->filp->f_lock); - curlun->filp->f_flags |= O_DSYNC; - spin_unlock(&curlun->filp->f_lock); - } - } - if (lba >= curlun->num_sectors) { - curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - return -EINVAL; - } - - /* Carry out the file writes */ - get_some_more = 1; - file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits; - amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd; - - while (amount_left_to_write > 0) { - - /* Queue a request for more data from the host */ - bh = fsg->next_buffhd_to_fill; - if (bh->state == BUF_STATE_EMPTY && get_some_more) { - - /* Figure out how much we want to get: - * Try to get the remaining amount, - * but not more than the buffer size. - */ - amount = min(amount_left_to_req, mod_data.buflen); - - /* Beyond the end of the backing file? */ - if (usb_offset >= curlun->file_length) { - get_some_more = 0; - curlun->sense_data = - SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->sense_data_info = usb_offset >> curlun->blkbits; - curlun->info_valid = 1; - continue; - } - - /* Get the next buffer */ - usb_offset += amount; - fsg->usb_amount_left -= amount; - amount_left_to_req -= amount; - if (amount_left_to_req == 0) - get_some_more = 0; - - /* Except at the end of the transfer, amount will be - * equal to the buffer size, which is divisible by - * the bulk-out maxpacket size. - */ - set_bulk_out_req_length(fsg, bh, amount); - start_transfer(fsg, fsg->bulk_out, bh->outreq, - &bh->outreq_busy, &bh->state); - fsg->next_buffhd_to_fill = bh->next; - continue; - } - - /* Write the received data to the backing file */ - bh = fsg->next_buffhd_to_drain; - if (bh->state == BUF_STATE_EMPTY && !get_some_more) - break; // We stopped early - if (bh->state == BUF_STATE_FULL) { - smp_rmb(); - fsg->next_buffhd_to_drain = bh->next; - bh->state = BUF_STATE_EMPTY; - - /* Did something go wrong with the transfer? */ - if (bh->outreq->status != 0) { - curlun->sense_data = SS_COMMUNICATION_FAILURE; - curlun->sense_data_info = file_offset >> curlun->blkbits; - curlun->info_valid = 1; - break; - } - - amount = bh->outreq->actual; - if (curlun->file_length - file_offset < amount) { - LERROR(curlun, - "write %u @ %llu beyond end %llu\n", - amount, (unsigned long long) file_offset, - (unsigned long long) curlun->file_length); - amount = curlun->file_length - file_offset; - } - - /* Don't accept excess data. The spec doesn't say - * what to do in this case. We'll ignore the error. - */ - amount = min(amount, bh->bulk_out_intended_length); - - /* Don't write a partial block */ - amount = round_down(amount, curlun->blksize); - if (amount == 0) - goto empty_write; - - /* Perform the write */ - file_offset_tmp = file_offset; - nwritten = vfs_write(curlun->filp, - (char __user *) bh->buf, - amount, &file_offset_tmp); - VLDBG(curlun, "file write %u @ %llu -> %d\n", amount, - (unsigned long long) file_offset, - (int) nwritten); - if (signal_pending(current)) - return -EINTR; // Interrupted! - - if (nwritten < 0) { - LDBG(curlun, "error in file write: %d\n", - (int) nwritten); - nwritten = 0; - } else if (nwritten < amount) { - LDBG(curlun, "partial file write: %d/%u\n", - (int) nwritten, amount); - nwritten = round_down(nwritten, curlun->blksize); - } - file_offset += nwritten; - amount_left_to_write -= nwritten; - fsg->residue -= nwritten; - - /* If an error occurred, report it and its position */ - if (nwritten < amount) { - curlun->sense_data = SS_WRITE_ERROR; - curlun->sense_data_info = file_offset >> curlun->blkbits; - curlun->info_valid = 1; - break; - } - - empty_write: - /* Did the host decide to stop early? */ - if (bh->outreq->actual < bh->bulk_out_intended_length) { - fsg->short_packet_received = 1; - break; - } - continue; - } - - /* Wait for something to happen */ - rc = sleep_thread(fsg); - if (rc) - return rc; - } - - return -EIO; // No default reply -} - - -/*-------------------------------------------------------------------------*/ - -static int do_synchronize_cache(struct fsg_dev *fsg) -{ - struct fsg_lun *curlun = fsg->curlun; - int rc; - - /* We ignore the requested LBA and write out all file's - * dirty data buffers. */ - rc = fsg_lun_fsync_sub(curlun); - if (rc) - curlun->sense_data = SS_WRITE_ERROR; - return 0; -} - - -/*-------------------------------------------------------------------------*/ - -static void invalidate_sub(struct fsg_lun *curlun) -{ - struct file *filp = curlun->filp; - struct inode *inode = filp->f_path.dentry->d_inode; - unsigned long rc; - - rc = invalidate_mapping_pages(inode->i_mapping, 0, -1); - VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc); -} - -static int do_verify(struct fsg_dev *fsg) -{ - struct fsg_lun *curlun = fsg->curlun; - u32 lba; - u32 verification_length; - struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; - loff_t file_offset, file_offset_tmp; - u32 amount_left; - unsigned int amount; - ssize_t nread; - - /* Get the starting Logical Block Address and check that it's - * not too big */ - lba = get_unaligned_be32(&fsg->cmnd[2]); - if (lba >= curlun->num_sectors) { - curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - return -EINVAL; - } - - /* We allow DPO (Disable Page Out = don't save data in the - * cache) but we don't implement it. */ - if ((fsg->cmnd[1] & ~0x10) != 0) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - verification_length = get_unaligned_be16(&fsg->cmnd[7]); - if (unlikely(verification_length == 0)) - return -EIO; // No default reply - - /* Prepare to carry out the file verify */ - amount_left = verification_length << curlun->blkbits; - file_offset = ((loff_t) lba) << curlun->blkbits; - - /* Write out all the dirty buffers before invalidating them */ - fsg_lun_fsync_sub(curlun); - if (signal_pending(current)) - return -EINTR; - - invalidate_sub(curlun); - if (signal_pending(current)) - return -EINTR; - - /* Just try to read the requested blocks */ - while (amount_left > 0) { - - /* Figure out how much we need to read: - * Try to read the remaining amount, but not more than - * the buffer size. - * And don't try to read past the end of the file. - */ - amount = min((unsigned int) amount_left, mod_data.buflen); - amount = min((loff_t) amount, - curlun->file_length - file_offset); - if (amount == 0) { - curlun->sense_data = - SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->sense_data_info = file_offset >> curlun->blkbits; - curlun->info_valid = 1; - break; - } - - /* Perform the read */ - file_offset_tmp = file_offset; - nread = vfs_read(curlun->filp, - (char __user *) bh->buf, - amount, &file_offset_tmp); - VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, - (unsigned long long) file_offset, - (int) nread); - if (signal_pending(current)) - return -EINTR; - - if (nread < 0) { - LDBG(curlun, "error in file verify: %d\n", - (int) nread); - nread = 0; - } else if (nread < amount) { - LDBG(curlun, "partial file verify: %d/%u\n", - (int) nread, amount); - nread = round_down(nread, curlun->blksize); - } - if (nread == 0) { - curlun->sense_data = SS_UNRECOVERED_READ_ERROR; - curlun->sense_data_info = file_offset >> curlun->blkbits; - curlun->info_valid = 1; - break; - } - file_offset += nread; - amount_left -= nread; - } - return 0; -} - - -/*-------------------------------------------------------------------------*/ - -static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - u8 *buf = (u8 *) bh->buf; - - static char vendor_id[] = "Linux "; - static char product_disk_id[] = "File-Stor Gadget"; - static char product_cdrom_id[] = "File-CD Gadget "; - - if (!fsg->curlun) { // Unsupported LUNs are okay - fsg->bad_lun_okay = 1; - memset(buf, 0, 36); - buf[0] = 0x7f; // Unsupported, no device-type - buf[4] = 31; // Additional length - return 36; - } - - memset(buf, 0, 8); - buf[0] = (mod_data.cdrom ? TYPE_ROM : TYPE_DISK); - if (mod_data.removable) - buf[1] = 0x80; - buf[2] = 2; // ANSI SCSI level 2 - buf[3] = 2; // SCSI-2 INQUIRY data format - buf[4] = 31; // Additional length - // No special options - sprintf(buf + 8, "%-8s%-16s%04x", vendor_id, - (mod_data.cdrom ? product_cdrom_id : - product_disk_id), - mod_data.release); - return 36; -} - - -static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = fsg->curlun; - u8 *buf = (u8 *) bh->buf; - u32 sd, sdinfo; - int valid; - - /* - * From the SCSI-2 spec., section 7.9 (Unit attention condition): - * - * If a REQUEST SENSE command is received from an initiator - * with a pending unit attention condition (before the target - * generates the contingent allegiance condition), then the - * target shall either: - * a) report any pending sense data and preserve the unit - * attention condition on the logical unit, or, - * b) report the unit attention condition, may discard any - * pending sense data, and clear the unit attention - * condition on the logical unit for that initiator. - * - * FSG normally uses option a); enable this code to use option b). - */ -#if 0 - if (curlun && curlun->unit_attention_data != SS_NO_SENSE) { - curlun->sense_data = curlun->unit_attention_data; - curlun->unit_attention_data = SS_NO_SENSE; - } -#endif - - if (!curlun) { // Unsupported LUNs are okay - fsg->bad_lun_okay = 1; - sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; - sdinfo = 0; - valid = 0; - } else { - sd = curlun->sense_data; - sdinfo = curlun->sense_data_info; - valid = curlun->info_valid << 7; - curlun->sense_data = SS_NO_SENSE; - curlun->sense_data_info = 0; - curlun->info_valid = 0; - } - - memset(buf, 0, 18); - buf[0] = valid | 0x70; // Valid, current error - buf[2] = SK(sd); - put_unaligned_be32(sdinfo, &buf[3]); /* Sense information */ - buf[7] = 18 - 8; // Additional sense length - buf[12] = ASC(sd); - buf[13] = ASCQ(sd); - return 18; -} - - -static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = fsg->curlun; - u32 lba = get_unaligned_be32(&fsg->cmnd[2]); - int pmi = fsg->cmnd[8]; - u8 *buf = (u8 *) bh->buf; - - /* Check the PMI and LBA fields */ - if (pmi > 1 || (pmi == 0 && lba != 0)) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - put_unaligned_be32(curlun->num_sectors - 1, &buf[0]); - /* Max logical block */ - put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */ - return 8; -} - - -static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = fsg->curlun; - int msf = fsg->cmnd[1] & 0x02; - u32 lba = get_unaligned_be32(&fsg->cmnd[2]); - u8 *buf = (u8 *) bh->buf; - - if ((fsg->cmnd[1] & ~0x02) != 0) { /* Mask away MSF */ - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - if (lba >= curlun->num_sectors) { - curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - return -EINVAL; - } - - memset(buf, 0, 8); - buf[0] = 0x01; /* 2048 bytes of user data, rest is EC */ - store_cdrom_address(&buf[4], msf, lba); - return 8; -} - - -static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = fsg->curlun; - int msf = fsg->cmnd[1] & 0x02; - int start_track = fsg->cmnd[6]; - u8 *buf = (u8 *) bh->buf; - - if ((fsg->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */ - start_track > 1) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - memset(buf, 0, 20); - buf[1] = (20-2); /* TOC data length */ - buf[2] = 1; /* First track number */ - buf[3] = 1; /* Last track number */ - buf[5] = 0x16; /* Data track, copying allowed */ - buf[6] = 0x01; /* Only track is number 1 */ - store_cdrom_address(&buf[8], msf, 0); - - buf[13] = 0x16; /* Lead-out track is data */ - buf[14] = 0xAA; /* Lead-out track number */ - store_cdrom_address(&buf[16], msf, curlun->num_sectors); - return 20; -} - - -static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = fsg->curlun; - int mscmnd = fsg->cmnd[0]; - u8 *buf = (u8 *) bh->buf; - u8 *buf0 = buf; - int pc, page_code; - int changeable_values, all_pages; - int valid_page = 0; - int len, limit; - - if ((fsg->cmnd[1] & ~0x08) != 0) { // Mask away DBD - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - pc = fsg->cmnd[2] >> 6; - page_code = fsg->cmnd[2] & 0x3f; - if (pc == 3) { - curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED; - return -EINVAL; - } - changeable_values = (pc == 1); - all_pages = (page_code == 0x3f); - - /* Write the mode parameter header. Fixed values are: default - * medium type, no cache control (DPOFUA), and no block descriptors. - * The only variable value is the WriteProtect bit. We will fill in - * the mode data length later. */ - memset(buf, 0, 8); - if (mscmnd == MODE_SENSE) { - buf[2] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA - buf += 4; - limit = 255; - } else { // MODE_SENSE_10 - buf[3] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA - buf += 8; - limit = 65535; // Should really be mod_data.buflen - } - - /* No block descriptors */ - - /* The mode pages, in numerical order. The only page we support - * is the Caching page. */ - if (page_code == 0x08 || all_pages) { - valid_page = 1; - buf[0] = 0x08; // Page code - buf[1] = 10; // Page length - memset(buf+2, 0, 10); // None of the fields are changeable - - if (!changeable_values) { - buf[2] = 0x04; // Write cache enable, - // Read cache not disabled - // No cache retention priorities - 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; - } - - /* Check that a valid page was requested and the mode data length - * isn't too long. */ - len = buf - buf0; - if (!valid_page || len > limit) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - /* Store the mode data length */ - if (mscmnd == MODE_SENSE) - buf0[0] = len - 1; - else - put_unaligned_be16(len - 2, buf0); - return len; -} - - -static int do_start_stop(struct fsg_dev *fsg) -{ - struct fsg_lun *curlun = fsg->curlun; - int loej, start; - - if (!mod_data.removable) { - curlun->sense_data = SS_INVALID_COMMAND; - return -EINVAL; - } - - // int immed = fsg->cmnd[1] & 0x01; - loej = fsg->cmnd[4] & 0x02; - start = fsg->cmnd[4] & 0x01; - -#ifdef CONFIG_USB_FILE_STORAGE_TEST - if ((fsg->cmnd[1] & ~0x01) != 0 || // Mask away Immed - (fsg->cmnd[4] & ~0x03) != 0) { // Mask LoEj, Start - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - if (!start) { - - /* Are we allowed to unload the media? */ - if (curlun->prevent_medium_removal) { - LDBG(curlun, "unload attempt prevented\n"); - curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED; - return -EINVAL; - } - if (loej) { // Simulate an unload/eject - up_read(&fsg->filesem); - down_write(&fsg->filesem); - fsg_lun_close(curlun); - up_write(&fsg->filesem); - down_read(&fsg->filesem); - } - } else { - - /* Our emulation doesn't support mounting; the medium is - * available for use as soon as it is loaded. */ - if (!fsg_lun_is_open(curlun)) { - curlun->sense_data = SS_MEDIUM_NOT_PRESENT; - return -EINVAL; - } - } -#endif - return 0; -} - - -static int do_prevent_allow(struct fsg_dev *fsg) -{ - struct fsg_lun *curlun = fsg->curlun; - int prevent; - - if (!mod_data.removable) { - curlun->sense_data = SS_INVALID_COMMAND; - return -EINVAL; - } - - prevent = fsg->cmnd[4] & 0x01; - if ((fsg->cmnd[4] & ~0x01) != 0) { // Mask away Prevent - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - if (curlun->prevent_medium_removal && !prevent) - fsg_lun_fsync_sub(curlun); - curlun->prevent_medium_removal = prevent; - return 0; -} - - -static int do_read_format_capacities(struct fsg_dev *fsg, - struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = fsg->curlun; - u8 *buf = (u8 *) bh->buf; - - buf[0] = buf[1] = buf[2] = 0; - buf[3] = 8; // Only the Current/Maximum Capacity Descriptor - buf += 4; - - put_unaligned_be32(curlun->num_sectors, &buf[0]); - /* Number of blocks */ - put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */ - buf[4] = 0x02; /* Current capacity */ - return 12; -} - - -static int do_mode_select(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = fsg->curlun; - - /* We don't support MODE SELECT */ - curlun->sense_data = SS_INVALID_COMMAND; - return -EINVAL; -} - - -/*-------------------------------------------------------------------------*/ - -static int halt_bulk_in_endpoint(struct fsg_dev *fsg) -{ - int rc; - - rc = fsg_set_halt(fsg, fsg->bulk_in); - if (rc == -EAGAIN) - VDBG(fsg, "delayed bulk-in endpoint halt\n"); - while (rc != 0) { - if (rc != -EAGAIN) { - WARNING(fsg, "usb_ep_set_halt -> %d\n", rc); - rc = 0; - break; - } - - /* Wait for a short time and then try again */ - if (msleep_interruptible(100) != 0) - return -EINTR; - rc = usb_ep_set_halt(fsg->bulk_in); - } - return rc; -} - -static int wedge_bulk_in_endpoint(struct fsg_dev *fsg) -{ - int rc; - - DBG(fsg, "bulk-in set wedge\n"); - rc = usb_ep_set_wedge(fsg->bulk_in); - if (rc == -EAGAIN) - VDBG(fsg, "delayed bulk-in endpoint wedge\n"); - while (rc != 0) { - if (rc != -EAGAIN) { - WARNING(fsg, "usb_ep_set_wedge -> %d\n", rc); - rc = 0; - break; - } - - /* Wait for a short time and then try again */ - if (msleep_interruptible(100) != 0) - return -EINTR; - rc = usb_ep_set_wedge(fsg->bulk_in); - } - return rc; -} - -static int throw_away_data(struct fsg_dev *fsg) -{ - struct fsg_buffhd *bh; - u32 amount; - int rc; - - while ((bh = fsg->next_buffhd_to_drain)->state != BUF_STATE_EMPTY || - fsg->usb_amount_left > 0) { - - /* Throw away the data in a filled buffer */ - if (bh->state == BUF_STATE_FULL) { - smp_rmb(); - bh->state = BUF_STATE_EMPTY; - fsg->next_buffhd_to_drain = bh->next; - - /* A short packet or an error ends everything */ - if (bh->outreq->actual < bh->bulk_out_intended_length || - bh->outreq->status != 0) { - raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); - return -EINTR; - } - continue; - } - - /* Try to submit another request if we need one */ - bh = fsg->next_buffhd_to_fill; - if (bh->state == BUF_STATE_EMPTY && fsg->usb_amount_left > 0) { - amount = min(fsg->usb_amount_left, - (u32) mod_data.buflen); - - /* Except at the end of the transfer, amount will be - * equal to the buffer size, which is divisible by - * the bulk-out maxpacket size. - */ - set_bulk_out_req_length(fsg, bh, amount); - start_transfer(fsg, fsg->bulk_out, bh->outreq, - &bh->outreq_busy, &bh->state); - fsg->next_buffhd_to_fill = bh->next; - fsg->usb_amount_left -= amount; - continue; - } - - /* Otherwise wait for something to happen */ - rc = sleep_thread(fsg); - if (rc) - return rc; - } - return 0; -} - - -static int finish_reply(struct fsg_dev *fsg) -{ - struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; - int rc = 0; - - switch (fsg->data_dir) { - case DATA_DIR_NONE: - break; // Nothing to send - - /* If we don't know whether the host wants to read or write, - * this must be CB or CBI with an unknown command. We mustn't - * try to send or receive any data. So stall both bulk pipes - * if we can and wait for a reset. */ - case DATA_DIR_UNKNOWN: - if (mod_data.can_stall) { - fsg_set_halt(fsg, fsg->bulk_out); - rc = halt_bulk_in_endpoint(fsg); - } - break; - - /* All but the last buffer of data must have already been sent */ - case DATA_DIR_TO_HOST: - if (fsg->data_size == 0) - ; // Nothing to send - - /* If there's no residue, simply send the last buffer */ - else if (fsg->residue == 0) { - bh->inreq->zero = 0; - start_transfer(fsg, fsg->bulk_in, bh->inreq, - &bh->inreq_busy, &bh->state); - fsg->next_buffhd_to_fill = bh->next; - } - - /* There is a residue. For CB and CBI, simply mark the end - * of the data with a short packet. However, if we are - * allowed to stall, there was no data at all (residue == - * data_size), and the command failed (invalid LUN or - * sense data is set), then halt the bulk-in endpoint - * instead. */ - else if (!transport_is_bbb()) { - if (mod_data.can_stall && - fsg->residue == fsg->data_size && - (!fsg->curlun || fsg->curlun->sense_data != SS_NO_SENSE)) { - bh->state = BUF_STATE_EMPTY; - rc = halt_bulk_in_endpoint(fsg); - } else { - bh->inreq->zero = 1; - start_transfer(fsg, fsg->bulk_in, bh->inreq, - &bh->inreq_busy, &bh->state); - fsg->next_buffhd_to_fill = bh->next; - } - } - - /* - * For Bulk-only, mark the end of the data with a short - * packet. If we are allowed to stall, halt the bulk-in - * endpoint. (Note: This violates the Bulk-Only Transport - * specification, which requires us to pad the data if we - * don't halt the endpoint. Presumably nobody will mind.) - */ - else { - bh->inreq->zero = 1; - start_transfer(fsg, fsg->bulk_in, bh->inreq, - &bh->inreq_busy, &bh->state); - fsg->next_buffhd_to_fill = bh->next; - if (mod_data.can_stall) - rc = halt_bulk_in_endpoint(fsg); - } - break; - - /* We have processed all we want from the data the host has sent. - * There may still be outstanding bulk-out requests. */ - case DATA_DIR_FROM_HOST: - if (fsg->residue == 0) - ; // Nothing to receive - - /* Did the host stop sending unexpectedly early? */ - else if (fsg->short_packet_received) { - raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); - rc = -EINTR; - } - - /* We haven't processed all the incoming data. Even though - * we may be allowed to stall, doing so would cause a race. - * The controller may already have ACK'ed all the remaining - * bulk-out packets, in which case the host wouldn't see a - * STALL. Not realizing the endpoint was halted, it wouldn't - * clear the halt -- leading to problems later on. */ -#if 0 - else if (mod_data.can_stall) { - fsg_set_halt(fsg, fsg->bulk_out); - raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); - rc = -EINTR; - } -#endif - - /* We can't stall. Read in the excess data and throw it - * all away. */ - else - rc = throw_away_data(fsg); - break; - } - return rc; -} - - -static int send_status(struct fsg_dev *fsg) -{ - struct fsg_lun *curlun = fsg->curlun; - struct fsg_buffhd *bh; - int rc; - u8 status = US_BULK_STAT_OK; - u32 sd, sdinfo = 0; - - /* Wait for the next buffer to become available */ - bh = fsg->next_buffhd_to_fill; - while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(fsg); - if (rc) - return rc; - } - - if (curlun) { - sd = curlun->sense_data; - sdinfo = curlun->sense_data_info; - } else if (fsg->bad_lun_okay) - sd = SS_NO_SENSE; - else - sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; - - if (fsg->phase_error) { - DBG(fsg, "sending phase-error status\n"); - status = US_BULK_STAT_PHASE; - sd = SS_INVALID_COMMAND; - } else if (sd != SS_NO_SENSE) { - DBG(fsg, "sending command-failure status\n"); - status = US_BULK_STAT_FAIL; - VDBG(fsg, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;" - " info x%x\n", - SK(sd), ASC(sd), ASCQ(sd), sdinfo); - } - - if (transport_is_bbb()) { - struct bulk_cs_wrap *csw = bh->buf; - - /* Store and send the Bulk-only CSW */ - csw->Signature = cpu_to_le32(US_BULK_CS_SIGN); - csw->Tag = fsg->tag; - csw->Residue = cpu_to_le32(fsg->residue); - csw->Status = status; - - bh->inreq->length = US_BULK_CS_WRAP_LEN; - bh->inreq->zero = 0; - start_transfer(fsg, fsg->bulk_in, bh->inreq, - &bh->inreq_busy, &bh->state); - - } else if (mod_data.transport_type == USB_PR_CB) { - - /* Control-Bulk transport has no status phase! */ - return 0; - - } else { // USB_PR_CBI - struct interrupt_data *buf = bh->buf; - - /* Store and send the Interrupt data. UFI sends the ASC - * and ASCQ bytes. Everything else sends a Type (which - * is always 0) and the status Value. */ - if (mod_data.protocol_type == USB_SC_UFI) { - buf->bType = ASC(sd); - buf->bValue = ASCQ(sd); - } else { - buf->bType = 0; - buf->bValue = status; - } - fsg->intreq->length = CBI_INTERRUPT_DATA_LEN; - - fsg->intr_buffhd = bh; // Point to the right buffhd - fsg->intreq->buf = bh->inreq->buf; - fsg->intreq->context = bh; - start_transfer(fsg, fsg->intr_in, fsg->intreq, - &fsg->intreq_busy, &bh->state); - } - - fsg->next_buffhd_to_fill = bh->next; - return 0; -} - - -/*-------------------------------------------------------------------------*/ - -/* Check whether the command is properly formed and whether its data size - * and direction agree with the values we already have. */ -static int check_command(struct fsg_dev *fsg, int cmnd_size, - enum data_direction data_dir, unsigned int mask, - int needs_medium, const char *name) -{ - int i; - int lun = fsg->cmnd[1] >> 5; - static const char dirletter[4] = {'u', 'o', 'i', 'n'}; - char hdlen[20]; - struct fsg_lun *curlun; - - /* Adjust the expected cmnd_size for protocol encapsulation padding. - * Transparent SCSI doesn't pad. */ - if (protocol_is_scsi()) - ; - - /* There's some disagreement as to whether RBC pads commands or not. - * We'll play it safe and accept either form. */ - else if (mod_data.protocol_type == USB_SC_RBC) { - if (fsg->cmnd_size == 12) - cmnd_size = 12; - - /* All the other protocols pad to 12 bytes */ - } else - cmnd_size = 12; - - hdlen[0] = 0; - if (fsg->data_dir != DATA_DIR_UNKNOWN) - sprintf(hdlen, ", H%c=%u", dirletter[(int) fsg->data_dir], - fsg->data_size); - VDBG(fsg, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n", - name, cmnd_size, dirletter[(int) data_dir], - fsg->data_size_from_cmnd, fsg->cmnd_size, hdlen); - - /* We can't reply at all until we know the correct data direction - * and size. */ - if (fsg->data_size_from_cmnd == 0) - data_dir = DATA_DIR_NONE; - if (fsg->data_dir == DATA_DIR_UNKNOWN) { // CB or CBI - fsg->data_dir = data_dir; - fsg->data_size = fsg->data_size_from_cmnd; - - } else { // Bulk-only - if (fsg->data_size < fsg->data_size_from_cmnd) { - - /* Host data size < Device data size is a phase error. - * Carry out the command, but only transfer as much - * as we are allowed. */ - fsg->data_size_from_cmnd = fsg->data_size; - fsg->phase_error = 1; - } - } - fsg->residue = fsg->usb_amount_left = fsg->data_size; - - /* Conflicting data directions is a phase error */ - if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) { - fsg->phase_error = 1; - return -EINVAL; - } - - /* Verify the length of the command itself */ - if (cmnd_size != fsg->cmnd_size) { - - /* Special case workaround: There are plenty of buggy SCSI - * implementations. Many have issues with cbw->Length - * field passing a wrong command size. For those cases we - * always try to work around the problem by using the length - * sent by the host side provided it is at least as large - * as the correct command length. - * Examples of such cases would be MS-Windows, which issues - * REQUEST SENSE with cbw->Length == 12 where it should - * be 6, and xbox360 issuing INQUIRY, TEST UNIT READY and - * REQUEST SENSE with cbw->Length == 10 where it should - * be 6 as well. - */ - if (cmnd_size <= fsg->cmnd_size) { - DBG(fsg, "%s is buggy! Expected length %d " - "but we got %d\n", name, - cmnd_size, fsg->cmnd_size); - cmnd_size = fsg->cmnd_size; - } else { - fsg->phase_error = 1; - return -EINVAL; - } - } - - /* Check that the LUN values are consistent */ - if (transport_is_bbb()) { - if (fsg->lun != lun) - DBG(fsg, "using LUN %d from CBW, " - "not LUN %d from CDB\n", - fsg->lun, lun); - } - - /* Check the LUN */ - curlun = fsg->curlun; - if (curlun) { - if (fsg->cmnd[0] != REQUEST_SENSE) { - curlun->sense_data = SS_NO_SENSE; - curlun->sense_data_info = 0; - curlun->info_valid = 0; - } - } else { - fsg->bad_lun_okay = 0; - - /* INQUIRY and REQUEST SENSE commands are explicitly allowed - * to use unsupported LUNs; all others may not. */ - if (fsg->cmnd[0] != INQUIRY && - fsg->cmnd[0] != REQUEST_SENSE) { - DBG(fsg, "unsupported LUN %d\n", fsg->lun); - return -EINVAL; - } - } - - /* If a unit attention condition exists, only INQUIRY and - * REQUEST SENSE commands are allowed; anything else must fail. */ - if (curlun && curlun->unit_attention_data != SS_NO_SENSE && - fsg->cmnd[0] != INQUIRY && - fsg->cmnd[0] != REQUEST_SENSE) { - curlun->sense_data = curlun->unit_attention_data; - curlun->unit_attention_data = SS_NO_SENSE; - return -EINVAL; - } - - /* Check that only command bytes listed in the mask are non-zero */ - fsg->cmnd[1] &= 0x1f; // Mask away the LUN - for (i = 1; i < cmnd_size; ++i) { - if (fsg->cmnd[i] && !(mask & (1 << i))) { - if (curlun) - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - } - - /* If the medium isn't mounted and the command needs to access - * it, return an error. */ - if (curlun && !fsg_lun_is_open(curlun) && needs_medium) { - curlun->sense_data = SS_MEDIUM_NOT_PRESENT; - return -EINVAL; - } - - return 0; -} - -/* wrapper of check_command for data size in blocks handling */ -static int check_command_size_in_blocks(struct fsg_dev *fsg, int cmnd_size, - enum data_direction data_dir, unsigned int mask, - int needs_medium, const char *name) -{ - if (fsg->curlun) - fsg->data_size_from_cmnd <<= fsg->curlun->blkbits; - return check_command(fsg, cmnd_size, data_dir, - mask, needs_medium, name); -} - -static int do_scsi_command(struct fsg_dev *fsg) -{ - struct fsg_buffhd *bh; - int rc; - int reply = -EINVAL; - int i; - static char unknown[16]; - - dump_cdb(fsg); - - /* Wait for the next buffer to become available for data or status */ - bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill; - while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(fsg); - if (rc) - return rc; - } - fsg->phase_error = 0; - fsg->short_packet_received = 0; - - down_read(&fsg->filesem); // We're using the backing file - switch (fsg->cmnd[0]) { - - case INQUIRY: - fsg->data_size_from_cmnd = fsg->cmnd[4]; - if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, - (1<<4), 0, - "INQUIRY")) == 0) - reply = do_inquiry(fsg, bh); - break; - - case MODE_SELECT: - fsg->data_size_from_cmnd = fsg->cmnd[4]; - if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST, - (1<<1) | (1<<4), 0, - "MODE SELECT(6)")) == 0) - reply = do_mode_select(fsg, bh); - break; - - case MODE_SELECT_10: - 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) - reply = do_mode_select(fsg, bh); - break; - - case MODE_SENSE: - fsg->data_size_from_cmnd = fsg->cmnd[4]; - if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, - (1<<1) | (1<<2) | (1<<4), 0, - "MODE SENSE(6)")) == 0) - reply = do_mode_sense(fsg, bh); - break; - - case MODE_SENSE_10: - 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) - reply = do_mode_sense(fsg, bh); - break; - - case ALLOW_MEDIUM_REMOVAL: - fsg->data_size_from_cmnd = 0; - if ((reply = check_command(fsg, 6, DATA_DIR_NONE, - (1<<4), 0, - "PREVENT-ALLOW MEDIUM REMOVAL")) == 0) - reply = do_prevent_allow(fsg); - break; - - case READ_6: - i = fsg->cmnd[4]; - fsg->data_size_from_cmnd = (i == 0) ? 256 : i; - if ((reply = check_command_size_in_blocks(fsg, 6, - DATA_DIR_TO_HOST, - (7<<1) | (1<<4), 1, - "READ(6)")) == 0) - reply = do_read(fsg); - break; - - case READ_10: - fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); - if ((reply = check_command_size_in_blocks(fsg, 10, - DATA_DIR_TO_HOST, - (1<<1) | (0xf<<2) | (3<<7), 1, - "READ(10)")) == 0) - reply = do_read(fsg); - break; - - case READ_12: - fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]); - if ((reply = check_command_size_in_blocks(fsg, 12, - DATA_DIR_TO_HOST, - (1<<1) | (0xf<<2) | (0xf<<6), 1, - "READ(12)")) == 0) - reply = do_read(fsg); - break; - - case READ_CAPACITY: - fsg->data_size_from_cmnd = 8; - if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, - (0xf<<2) | (1<<8), 1, - "READ CAPACITY")) == 0) - reply = do_read_capacity(fsg, bh); - break; - - case READ_HEADER: - if (!mod_data.cdrom) - goto unknown_cmnd; - 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) - reply = do_read_header(fsg, bh); - break; - - case READ_TOC: - if (!mod_data.cdrom) - goto unknown_cmnd; - 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) - reply = do_read_toc(fsg, bh); - break; - - case READ_FORMAT_CAPACITIES: - 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) - reply = do_read_format_capacities(fsg, bh); - break; - - case REQUEST_SENSE: - fsg->data_size_from_cmnd = fsg->cmnd[4]; - if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, - (1<<4), 0, - "REQUEST SENSE")) == 0) - reply = do_request_sense(fsg, bh); - break; - - case START_STOP: - fsg->data_size_from_cmnd = 0; - if ((reply = check_command(fsg, 6, DATA_DIR_NONE, - (1<<1) | (1<<4), 0, - "START-STOP UNIT")) == 0) - reply = do_start_stop(fsg); - break; - - case SYNCHRONIZE_CACHE: - fsg->data_size_from_cmnd = 0; - if ((reply = check_command(fsg, 10, DATA_DIR_NONE, - (0xf<<2) | (3<<7), 1, - "SYNCHRONIZE CACHE")) == 0) - reply = do_synchronize_cache(fsg); - break; - - case TEST_UNIT_READY: - fsg->data_size_from_cmnd = 0; - reply = check_command(fsg, 6, DATA_DIR_NONE, - 0, 1, - "TEST UNIT READY"); - break; - - /* Although optional, this command is used by MS-Windows. We - * support a minimal version: BytChk must be 0. */ - case VERIFY: - fsg->data_size_from_cmnd = 0; - if ((reply = check_command(fsg, 10, DATA_DIR_NONE, - (1<<1) | (0xf<<2) | (3<<7), 1, - "VERIFY")) == 0) - reply = do_verify(fsg); - break; - - case WRITE_6: - i = fsg->cmnd[4]; - fsg->data_size_from_cmnd = (i == 0) ? 256 : i; - if ((reply = check_command_size_in_blocks(fsg, 6, - DATA_DIR_FROM_HOST, - (7<<1) | (1<<4), 1, - "WRITE(6)")) == 0) - reply = do_write(fsg); - break; - - case WRITE_10: - fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); - if ((reply = check_command_size_in_blocks(fsg, 10, - DATA_DIR_FROM_HOST, - (1<<1) | (0xf<<2) | (3<<7), 1, - "WRITE(10)")) == 0) - reply = do_write(fsg); - break; - - case WRITE_12: - fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]); - if ((reply = check_command_size_in_blocks(fsg, 12, - DATA_DIR_FROM_HOST, - (1<<1) | (0xf<<2) | (0xf<<6), 1, - "WRITE(12)")) == 0) - reply = do_write(fsg); - break; - - /* Some mandatory commands that we recognize but don't implement. - * They don't mean much in this setting. It's left as an exercise - * for anyone interested to implement RESERVE and RELEASE in terms - * of Posix locks. */ - case FORMAT_UNIT: - case RELEASE: - case RESERVE: - case SEND_DIAGNOSTIC: - // Fall through - - default: - unknown_cmnd: - fsg->data_size_from_cmnd = 0; - sprintf(unknown, "Unknown x%02x", fsg->cmnd[0]); - if ((reply = check_command(fsg, fsg->cmnd_size, - DATA_DIR_UNKNOWN, ~0, 0, unknown)) == 0) { - fsg->curlun->sense_data = SS_INVALID_COMMAND; - reply = -EINVAL; - } - break; - } - up_read(&fsg->filesem); - - if (reply == -EINTR || signal_pending(current)) - return -EINTR; - - /* Set up the single reply buffer for finish_reply() */ - if (reply == -EINVAL) - reply = 0; // Error reply length - if (reply >= 0 && fsg->data_dir == DATA_DIR_TO_HOST) { - reply = min((u32) reply, fsg->data_size_from_cmnd); - bh->inreq->length = reply; - bh->state = BUF_STATE_FULL; - fsg->residue -= reply; - } // Otherwise it's already set - - return 0; -} - - -/*-------------------------------------------------------------------------*/ - -static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct usb_request *req = bh->outreq; - struct bulk_cb_wrap *cbw = req->buf; - - /* Was this a real packet? Should it be ignored? */ - if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags)) - return -EINVAL; - - /* Is the CBW valid? */ - if (req->actual != US_BULK_CB_WRAP_LEN || - cbw->Signature != cpu_to_le32( - US_BULK_CB_SIGN)) { - DBG(fsg, "invalid CBW: len %u sig 0x%x\n", - req->actual, - le32_to_cpu(cbw->Signature)); - - /* The Bulk-only spec says we MUST stall the IN endpoint - * (6.6.1), so it's unavoidable. It also says we must - * retain this state until the next reset, but there's - * no way to tell the controller driver it should ignore - * Clear-Feature(HALT) requests. - * - * We aren't required to halt the OUT endpoint; instead - * we can simply accept and discard any data received - * until the next reset. */ - wedge_bulk_in_endpoint(fsg); - set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); - return -EINVAL; - } - - /* Is the CBW meaningful? */ - if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN || - cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) { - DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, " - "cmdlen %u\n", - cbw->Lun, cbw->Flags, cbw->Length); - - /* We can do anything we want here, so let's stall the - * bulk pipes if we are allowed to. */ - if (mod_data.can_stall) { - fsg_set_halt(fsg, fsg->bulk_out); - halt_bulk_in_endpoint(fsg); - } - return -EINVAL; - } - - /* Save the command for later */ - fsg->cmnd_size = cbw->Length; - memcpy(fsg->cmnd, cbw->CDB, fsg->cmnd_size); - if (cbw->Flags & US_BULK_FLAG_IN) - fsg->data_dir = DATA_DIR_TO_HOST; - else - fsg->data_dir = DATA_DIR_FROM_HOST; - fsg->data_size = le32_to_cpu(cbw->DataTransferLength); - if (fsg->data_size == 0) - fsg->data_dir = DATA_DIR_NONE; - fsg->lun = cbw->Lun; - fsg->tag = cbw->Tag; - return 0; -} - - -static int get_next_command(struct fsg_dev *fsg) -{ - struct fsg_buffhd *bh; - int rc = 0; - - if (transport_is_bbb()) { - - /* Wait for the next buffer to become available */ - bh = fsg->next_buffhd_to_fill; - while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(fsg); - if (rc) - return rc; - } - - /* Queue a request to read a Bulk-only CBW */ - set_bulk_out_req_length(fsg, bh, US_BULK_CB_WRAP_LEN); - start_transfer(fsg, fsg->bulk_out, bh->outreq, - &bh->outreq_busy, &bh->state); - - /* We will drain the buffer in software, which means we - * can reuse it for the next filling. No need to advance - * next_buffhd_to_fill. */ - - /* Wait for the CBW to arrive */ - while (bh->state != BUF_STATE_FULL) { - rc = sleep_thread(fsg); - if (rc) - return rc; - } - smp_rmb(); - rc = received_cbw(fsg, bh); - bh->state = BUF_STATE_EMPTY; - - } else { // USB_PR_CB or USB_PR_CBI - - /* Wait for the next command to arrive */ - while (fsg->cbbuf_cmnd_size == 0) { - rc = sleep_thread(fsg); - if (rc) - return rc; - } - - /* Is the previous status interrupt request still busy? - * The host is allowed to skip reading the status, - * so we must cancel it. */ - if (fsg->intreq_busy) - usb_ep_dequeue(fsg->intr_in, fsg->intreq); - - /* Copy the command and mark the buffer empty */ - fsg->data_dir = DATA_DIR_UNKNOWN; - spin_lock_irq(&fsg->lock); - fsg->cmnd_size = fsg->cbbuf_cmnd_size; - memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size); - fsg->cbbuf_cmnd_size = 0; - spin_unlock_irq(&fsg->lock); - - /* Use LUN from the command */ - fsg->lun = fsg->cmnd[1] >> 5; - } - - /* Update current lun */ - if (fsg->lun >= 0 && fsg->lun < fsg->nluns) - fsg->curlun = &fsg->luns[fsg->lun]; - else - fsg->curlun = NULL; - - return rc; -} - - -/*-------------------------------------------------------------------------*/ - -static int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep, - const struct usb_endpoint_descriptor *d) -{ - int rc; - - ep->driver_data = fsg; - ep->desc = d; - rc = usb_ep_enable(ep); - if (rc) - ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc); - return rc; -} - -static int alloc_request(struct fsg_dev *fsg, struct usb_ep *ep, - struct usb_request **preq) -{ - *preq = usb_ep_alloc_request(ep, GFP_ATOMIC); - if (*preq) - return 0; - ERROR(fsg, "can't allocate request for %s\n", ep->name); - return -ENOMEM; -} - -/* - * Reset interface setting and re-init endpoint state (toggle etc). - * Call with altsetting < 0 to disable the interface. The only other - * available altsetting is 0, which enables the interface. - */ -static int do_set_interface(struct fsg_dev *fsg, int altsetting) -{ - int rc = 0; - int i; - const struct usb_endpoint_descriptor *d; - - if (fsg->running) - DBG(fsg, "reset interface\n"); - -reset: - /* Deallocate the requests */ - for (i = 0; i < fsg_num_buffers; ++i) { - struct fsg_buffhd *bh = &fsg->buffhds[i]; - - if (bh->inreq) { - usb_ep_free_request(fsg->bulk_in, bh->inreq); - bh->inreq = NULL; - } - if (bh->outreq) { - usb_ep_free_request(fsg->bulk_out, bh->outreq); - bh->outreq = NULL; - } - } - if (fsg->intreq) { - usb_ep_free_request(fsg->intr_in, fsg->intreq); - fsg->intreq = NULL; - } - - /* Disable the endpoints */ - if (fsg->bulk_in_enabled) { - usb_ep_disable(fsg->bulk_in); - fsg->bulk_in_enabled = 0; - } - if (fsg->bulk_out_enabled) { - usb_ep_disable(fsg->bulk_out); - fsg->bulk_out_enabled = 0; - } - if (fsg->intr_in_enabled) { - usb_ep_disable(fsg->intr_in); - fsg->intr_in_enabled = 0; - } - - fsg->running = 0; - if (altsetting < 0 || rc != 0) - return rc; - - DBG(fsg, "set interface %d\n", altsetting); - - /* Enable the endpoints */ - d = fsg_ep_desc(fsg->gadget, - &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc, - &fsg_ss_bulk_in_desc); - if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0) - goto reset; - fsg->bulk_in_enabled = 1; - - d = fsg_ep_desc(fsg->gadget, - &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc, - &fsg_ss_bulk_out_desc); - if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0) - goto reset; - fsg->bulk_out_enabled = 1; - fsg->bulk_out_maxpacket = usb_endpoint_maxp(d); - clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); - - if (transport_is_cbi()) { - d = fsg_ep_desc(fsg->gadget, - &fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc, - &fsg_ss_intr_in_desc); - if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0) - goto reset; - fsg->intr_in_enabled = 1; - } - - /* Allocate the requests */ - for (i = 0; i < fsg_num_buffers; ++i) { - struct fsg_buffhd *bh = &fsg->buffhds[i]; - - if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0) - goto reset; - if ((rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq)) != 0) - goto reset; - bh->inreq->buf = bh->outreq->buf = bh->buf; - bh->inreq->context = bh->outreq->context = bh; - bh->inreq->complete = bulk_in_complete; - bh->outreq->complete = bulk_out_complete; - } - if (transport_is_cbi()) { - if ((rc = alloc_request(fsg, fsg->intr_in, &fsg->intreq)) != 0) - goto reset; - fsg->intreq->complete = intr_in_complete; - } - - fsg->running = 1; - for (i = 0; i < fsg->nluns; ++i) - fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED; - return rc; -} - - -/* - * Change our operational configuration. This code must agree with the code - * that returns config descriptors, and with interface altsetting code. - * - * It's also responsible for power management interactions. Some - * configurations might not work with our current power sources. - * For now we just assume the gadget is always self-powered. - */ -static int do_set_config(struct fsg_dev *fsg, u8 new_config) -{ - int rc = 0; - - /* Disable the single interface */ - if (fsg->config != 0) { - DBG(fsg, "reset config\n"); - fsg->config = 0; - rc = do_set_interface(fsg, -1); - } - - /* Enable the interface */ - if (new_config != 0) { - fsg->config = new_config; - if ((rc = do_set_interface(fsg, 0)) != 0) - fsg->config = 0; // Reset on errors - else - INFO(fsg, "%s config #%d\n", - usb_speed_string(fsg->gadget->speed), - fsg->config); - } - return rc; -} - - -/*-------------------------------------------------------------------------*/ - -static void handle_exception(struct fsg_dev *fsg) -{ - siginfo_t info; - int sig; - int i; - int num_active; - struct fsg_buffhd *bh; - enum fsg_state old_state; - u8 new_config; - struct fsg_lun *curlun; - unsigned int exception_req_tag; - int rc; - - /* Clear the existing signals. Anything but SIGUSR1 is converted - * into a high-priority EXIT exception. */ - for (;;) { - sig = dequeue_signal_lock(current, ¤t->blocked, &info); - if (!sig) - break; - if (sig != SIGUSR1) { - if (fsg->state < FSG_STATE_EXIT) - DBG(fsg, "Main thread exiting on signal\n"); - raise_exception(fsg, FSG_STATE_EXIT); - } - } - - /* Cancel all the pending transfers */ - if (fsg->intreq_busy) - usb_ep_dequeue(fsg->intr_in, fsg->intreq); - for (i = 0; i < fsg_num_buffers; ++i) { - bh = &fsg->buffhds[i]; - if (bh->inreq_busy) - usb_ep_dequeue(fsg->bulk_in, bh->inreq); - if (bh->outreq_busy) - usb_ep_dequeue(fsg->bulk_out, bh->outreq); - } - - /* Wait until everything is idle */ - for (;;) { - num_active = fsg->intreq_busy; - for (i = 0; i < fsg_num_buffers; ++i) { - bh = &fsg->buffhds[i]; - num_active += bh->inreq_busy + bh->outreq_busy; - } - if (num_active == 0) - break; - if (sleep_thread(fsg)) - return; - } - - /* Clear out the controller's fifos */ - if (fsg->bulk_in_enabled) - usb_ep_fifo_flush(fsg->bulk_in); - if (fsg->bulk_out_enabled) - usb_ep_fifo_flush(fsg->bulk_out); - if (fsg->intr_in_enabled) - usb_ep_fifo_flush(fsg->intr_in); - - /* Reset the I/O buffer states and pointers, the SCSI - * state, and the exception. Then invoke the handler. */ - spin_lock_irq(&fsg->lock); - - for (i = 0; i < fsg_num_buffers; ++i) { - bh = &fsg->buffhds[i]; - bh->state = BUF_STATE_EMPTY; - } - fsg->next_buffhd_to_fill = fsg->next_buffhd_to_drain = - &fsg->buffhds[0]; - - exception_req_tag = fsg->exception_req_tag; - new_config = fsg->new_config; - old_state = fsg->state; - - if (old_state == FSG_STATE_ABORT_BULK_OUT) - fsg->state = FSG_STATE_STATUS_PHASE; - else { - for (i = 0; i < fsg->nluns; ++i) { - curlun = &fsg->luns[i]; - curlun->prevent_medium_removal = 0; - curlun->sense_data = curlun->unit_attention_data = - SS_NO_SENSE; - curlun->sense_data_info = 0; - curlun->info_valid = 0; - } - fsg->state = FSG_STATE_IDLE; - } - spin_unlock_irq(&fsg->lock); - - /* Carry out any extra actions required for the exception */ - switch (old_state) { - default: - break; - - case FSG_STATE_ABORT_BULK_OUT: - send_status(fsg); - spin_lock_irq(&fsg->lock); - if (fsg->state == FSG_STATE_STATUS_PHASE) - fsg->state = FSG_STATE_IDLE; - spin_unlock_irq(&fsg->lock); - break; - - case FSG_STATE_RESET: - /* In case we were forced against our will to halt a - * bulk endpoint, clear the halt now. (The SuperH UDC - * requires this.) */ - if (test_and_clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags)) - usb_ep_clear_halt(fsg->bulk_in); - - if (transport_is_bbb()) { - if (fsg->ep0_req_tag == exception_req_tag) - ep0_queue(fsg); // Complete the status stage - - } else if (transport_is_cbi()) - send_status(fsg); // Status by interrupt pipe - - /* Technically this should go here, but it would only be - * a waste of time. Ditto for the INTERFACE_CHANGE and - * CONFIG_CHANGE cases. */ - // for (i = 0; i < fsg->nluns; ++i) - // fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED; - break; - - case FSG_STATE_INTERFACE_CHANGE: - rc = do_set_interface(fsg, 0); - if (fsg->ep0_req_tag != exception_req_tag) - break; - if (rc != 0) // STALL on errors - fsg_set_halt(fsg, fsg->ep0); - else // Complete the status stage - ep0_queue(fsg); - break; - - case FSG_STATE_CONFIG_CHANGE: - rc = do_set_config(fsg, new_config); - if (fsg->ep0_req_tag != exception_req_tag) - break; - if (rc != 0) // STALL on errors - fsg_set_halt(fsg, fsg->ep0); - else // Complete the status stage - ep0_queue(fsg); - break; - - case FSG_STATE_DISCONNECT: - for (i = 0; i < fsg->nluns; ++i) - fsg_lun_fsync_sub(fsg->luns + i); - do_set_config(fsg, 0); // Unconfigured state - break; - - case FSG_STATE_EXIT: - case FSG_STATE_TERMINATED: - do_set_config(fsg, 0); // Free resources - spin_lock_irq(&fsg->lock); - fsg->state = FSG_STATE_TERMINATED; // Stop the thread - spin_unlock_irq(&fsg->lock); - break; - } -} - - -/*-------------------------------------------------------------------------*/ - -static int fsg_main_thread(void *fsg_) -{ - struct fsg_dev *fsg = fsg_; - - /* Allow the thread to be killed by a signal, but set the signal mask - * to block everything but INT, TERM, KILL, and USR1. */ - allow_signal(SIGINT); - allow_signal(SIGTERM); - allow_signal(SIGKILL); - allow_signal(SIGUSR1); - - /* Allow the thread to be frozen */ - set_freezable(); - - /* Arrange for userspace references to be interpreted as kernel - * pointers. That way we can pass a kernel pointer to a routine - * that expects a __user pointer and it will work okay. */ - set_fs(get_ds()); - - /* The main loop */ - while (fsg->state != FSG_STATE_TERMINATED) { - if (exception_in_progress(fsg) || signal_pending(current)) { - handle_exception(fsg); - continue; - } - - if (!fsg->running) { - sleep_thread(fsg); - continue; - } - - if (get_next_command(fsg)) - continue; - - spin_lock_irq(&fsg->lock); - if (!exception_in_progress(fsg)) - fsg->state = FSG_STATE_DATA_PHASE; - spin_unlock_irq(&fsg->lock); - - if (do_scsi_command(fsg) || finish_reply(fsg)) - continue; - - spin_lock_irq(&fsg->lock); - if (!exception_in_progress(fsg)) - fsg->state = FSG_STATE_STATUS_PHASE; - spin_unlock_irq(&fsg->lock); - - if (send_status(fsg)) - continue; - - spin_lock_irq(&fsg->lock); - if (!exception_in_progress(fsg)) - fsg->state = FSG_STATE_IDLE; - spin_unlock_irq(&fsg->lock); - } - - spin_lock_irq(&fsg->lock); - fsg->thread_task = NULL; - spin_unlock_irq(&fsg->lock); - - /* If we are exiting because of a signal, unregister the - * gadget driver. */ - if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) - usb_gadget_unregister_driver(&fsg_driver); - - /* Let the unbind and cleanup routines know the thread has exited */ - complete_and_exit(&fsg->thread_notifier, 0); -} - - -/*-------------------------------------------------------------------------*/ - - -/* The write permissions and store_xxx pointers are set in fsg_bind() */ -static DEVICE_ATTR(ro, 0444, fsg_show_ro, NULL); -static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, NULL); -static DEVICE_ATTR(file, 0444, fsg_show_file, NULL); - - -/*-------------------------------------------------------------------------*/ - -static void fsg_release(struct kref *ref) -{ - struct fsg_dev *fsg = container_of(ref, struct fsg_dev, ref); - - kfree(fsg->luns); - kfree(fsg); -} - -static void lun_release(struct device *dev) -{ - struct rw_semaphore *filesem = dev_get_drvdata(dev); - struct fsg_dev *fsg = - container_of(filesem, struct fsg_dev, filesem); - - kref_put(&fsg->ref, fsg_release); -} - -static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) -{ - struct fsg_dev *fsg = get_gadget_data(gadget); - int i; - struct fsg_lun *curlun; - struct usb_request *req = fsg->ep0req; - - DBG(fsg, "unbind\n"); - clear_bit(REGISTERED, &fsg->atomic_bitflags); - - /* If the thread isn't already dead, tell it to exit now */ - if (fsg->state != FSG_STATE_TERMINATED) { - raise_exception(fsg, FSG_STATE_EXIT); - wait_for_completion(&fsg->thread_notifier); - - /* The cleanup routine waits for this completion also */ - complete(&fsg->thread_notifier); - } - - /* Unregister the sysfs attribute files and the LUNs */ - for (i = 0; i < fsg->nluns; ++i) { - curlun = &fsg->luns[i]; - if (curlun->registered) { - device_remove_file(&curlun->dev, &dev_attr_nofua); - device_remove_file(&curlun->dev, &dev_attr_ro); - device_remove_file(&curlun->dev, &dev_attr_file); - fsg_lun_close(curlun); - device_unregister(&curlun->dev); - curlun->registered = 0; - } - } - - /* Free the data buffers */ - for (i = 0; i < fsg_num_buffers; ++i) - kfree(fsg->buffhds[i].buf); - - /* Free the request and buffer for endpoint 0 */ - if (req) { - kfree(req->buf); - usb_ep_free_request(fsg->ep0, req); - } - - set_gadget_data(gadget, NULL); -} - - -static int __init check_parameters(struct fsg_dev *fsg) -{ - int prot; - int gcnum; - - /* Store the default values */ - mod_data.transport_type = USB_PR_BULK; - mod_data.transport_name = "Bulk-only"; - mod_data.protocol_type = USB_SC_SCSI; - mod_data.protocol_name = "Transparent SCSI"; - - /* Some peripheral controllers are known not to be able to - * halt bulk endpoints correctly. If one of them is present, - * disable stalls. - */ - if (gadget_is_at91(fsg->gadget)) - mod_data.can_stall = 0; - - if (mod_data.release == 0xffff) { // Parameter wasn't set - gcnum = usb_gadget_controller_number(fsg->gadget); - if (gcnum >= 0) - mod_data.release = 0x0300 + gcnum; - else { - WARNING(fsg, "controller '%s' not recognized\n", - fsg->gadget->name); - mod_data.release = 0x0399; - } - } - - prot = simple_strtol(mod_data.protocol_parm, NULL, 0); - -#ifdef CONFIG_USB_FILE_STORAGE_TEST - if (strnicmp(mod_data.transport_parm, "BBB", 10) == 0) { - ; // Use default setting - } else if (strnicmp(mod_data.transport_parm, "CB", 10) == 0) { - mod_data.transport_type = USB_PR_CB; - mod_data.transport_name = "Control-Bulk"; - } else if (strnicmp(mod_data.transport_parm, "CBI", 10) == 0) { - mod_data.transport_type = USB_PR_CBI; - mod_data.transport_name = "Control-Bulk-Interrupt"; - } else { - ERROR(fsg, "invalid transport: %s\n", mod_data.transport_parm); - return -EINVAL; - } - - if (strnicmp(mod_data.protocol_parm, "SCSI", 10) == 0 || - prot == USB_SC_SCSI) { - ; // Use default setting - } else if (strnicmp(mod_data.protocol_parm, "RBC", 10) == 0 || - prot == USB_SC_RBC) { - mod_data.protocol_type = USB_SC_RBC; - mod_data.protocol_name = "RBC"; - } else if (strnicmp(mod_data.protocol_parm, "8020", 4) == 0 || - strnicmp(mod_data.protocol_parm, "ATAPI", 10) == 0 || - prot == USB_SC_8020) { - mod_data.protocol_type = USB_SC_8020; - mod_data.protocol_name = "8020i (ATAPI)"; - } else if (strnicmp(mod_data.protocol_parm, "QIC", 3) == 0 || - prot == USB_SC_QIC) { - mod_data.protocol_type = USB_SC_QIC; - mod_data.protocol_name = "QIC-157"; - } else if (strnicmp(mod_data.protocol_parm, "UFI", 10) == 0 || - prot == USB_SC_UFI) { - mod_data.protocol_type = USB_SC_UFI; - mod_data.protocol_name = "UFI"; - } else if (strnicmp(mod_data.protocol_parm, "8070", 4) == 0 || - prot == USB_SC_8070) { - mod_data.protocol_type = USB_SC_8070; - mod_data.protocol_name = "8070i"; - } else { - ERROR(fsg, "invalid protocol: %s\n", mod_data.protocol_parm); - return -EINVAL; - } - - mod_data.buflen &= PAGE_CACHE_MASK; - if (mod_data.buflen <= 0) { - ERROR(fsg, "invalid buflen\n"); - return -ETOOSMALL; - } - -#endif /* CONFIG_USB_FILE_STORAGE_TEST */ - - /* Serial string handling. - * On a real device, the serial string would be loaded - * from permanent storage. */ - if (mod_data.serial) { - const char *ch; - unsigned len = 0; - - /* Sanity check : - * The CB[I] specification limits the serial string to - * 12 uppercase hexadecimal characters. - * BBB need at least 12 uppercase hexadecimal characters, - * with a maximum of 126. */ - for (ch = mod_data.serial; *ch; ++ch) { - ++len; - if ((*ch < '0' || *ch > '9') && - (*ch < 'A' || *ch > 'F')) { /* not uppercase hex */ - WARNING(fsg, - "Invalid serial string character: %c\n", - *ch); - goto no_serial; - } - } - if (len > 126 || - (mod_data.transport_type == USB_PR_BULK && len < 12) || - (mod_data.transport_type != USB_PR_BULK && len > 12)) { - WARNING(fsg, "Invalid serial string length!\n"); - goto no_serial; - } - fsg_strings[FSG_STRING_SERIAL - 1].s = mod_data.serial; - } else { - WARNING(fsg, "No serial-number string provided!\n"); - no_serial: - device_desc.iSerialNumber = 0; - } - - return 0; -} - - -static int __init fsg_bind(struct usb_gadget *gadget) -{ - struct fsg_dev *fsg = the_fsg; - int rc; - int i; - struct fsg_lun *curlun; - struct usb_ep *ep; - struct usb_request *req; - char *pathbuf, *p; - - fsg->gadget = gadget; - set_gadget_data(gadget, fsg); - fsg->ep0 = gadget->ep0; - fsg->ep0->driver_data = fsg; - - if ((rc = check_parameters(fsg)) != 0) - goto out; - - if (mod_data.removable) { // Enable the store_xxx attributes - dev_attr_file.attr.mode = 0644; - dev_attr_file.store = fsg_store_file; - if (!mod_data.cdrom) { - dev_attr_ro.attr.mode = 0644; - dev_attr_ro.store = fsg_store_ro; - } - } - - /* Only for removable media? */ - dev_attr_nofua.attr.mode = 0644; - dev_attr_nofua.store = fsg_store_nofua; - - /* Find out how many LUNs there should be */ - i = mod_data.nluns; - if (i == 0) - i = max(mod_data.num_filenames, 1u); - if (i > FSG_MAX_LUNS) { - ERROR(fsg, "invalid number of LUNs: %d\n", i); - rc = -EINVAL; - goto out; - } - - /* Create the LUNs, open their backing files, and register the - * LUN devices in sysfs. */ - fsg->luns = kzalloc(i * sizeof(struct fsg_lun), GFP_KERNEL); - if (!fsg->luns) { - rc = -ENOMEM; - goto out; - } - fsg->nluns = i; - - for (i = 0; i < fsg->nluns; ++i) { - curlun = &fsg->luns[i]; - curlun->cdrom = !!mod_data.cdrom; - curlun->ro = mod_data.cdrom || mod_data.ro[i]; - curlun->initially_ro = curlun->ro; - curlun->removable = mod_data.removable; - curlun->nofua = mod_data.nofua[i]; - curlun->dev.release = lun_release; - curlun->dev.parent = &gadget->dev; - curlun->dev.driver = &fsg_driver.driver; - dev_set_drvdata(&curlun->dev, &fsg->filesem); - dev_set_name(&curlun->dev,"%s-lun%d", - dev_name(&gadget->dev), i); - - kref_get(&fsg->ref); - rc = device_register(&curlun->dev); - if (rc) { - INFO(fsg, "failed to register LUN%d: %d\n", i, rc); - put_device(&curlun->dev); - goto out; - } - curlun->registered = 1; - - rc = device_create_file(&curlun->dev, &dev_attr_ro); - if (rc) - goto out; - rc = device_create_file(&curlun->dev, &dev_attr_nofua); - if (rc) - goto out; - rc = device_create_file(&curlun->dev, &dev_attr_file); - if (rc) - goto out; - - if (mod_data.file[i] && *mod_data.file[i]) { - rc = fsg_lun_open(curlun, mod_data.file[i]); - if (rc) - goto out; - } else if (!mod_data.removable) { - ERROR(fsg, "no file given for LUN%d\n", i); - rc = -EINVAL; - goto out; - } - } - - /* Find all the endpoints we will use */ - usb_ep_autoconfig_reset(gadget); - ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc); - if (!ep) - goto autoconf_fail; - ep->driver_data = fsg; // claim the endpoint - fsg->bulk_in = ep; - - ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc); - if (!ep) - goto autoconf_fail; - ep->driver_data = fsg; // claim the endpoint - fsg->bulk_out = ep; - - if (transport_is_cbi()) { - ep = usb_ep_autoconfig(gadget, &fsg_fs_intr_in_desc); - if (!ep) - goto autoconf_fail; - ep->driver_data = fsg; // claim the endpoint - fsg->intr_in = ep; - } - - /* Fix up the descriptors */ - device_desc.idVendor = cpu_to_le16(mod_data.vendor); - device_desc.idProduct = cpu_to_le16(mod_data.product); - device_desc.bcdDevice = cpu_to_le16(mod_data.release); - - i = (transport_is_cbi() ? 3 : 2); // Number of endpoints - fsg_intf_desc.bNumEndpoints = i; - fsg_intf_desc.bInterfaceSubClass = mod_data.protocol_type; - fsg_intf_desc.bInterfaceProtocol = mod_data.transport_type; - fsg_fs_function[i + FSG_FS_FUNCTION_PRE_EP_ENTRIES] = NULL; - - if (gadget_is_dualspeed(gadget)) { - fsg_hs_function[i + FSG_HS_FUNCTION_PRE_EP_ENTRIES] = NULL; - - /* Assume endpoint addresses are the same for both speeds */ - fsg_hs_bulk_in_desc.bEndpointAddress = - fsg_fs_bulk_in_desc.bEndpointAddress; - fsg_hs_bulk_out_desc.bEndpointAddress = - fsg_fs_bulk_out_desc.bEndpointAddress; - fsg_hs_intr_in_desc.bEndpointAddress = - fsg_fs_intr_in_desc.bEndpointAddress; - } - - if (gadget_is_superspeed(gadget)) { - unsigned max_burst; - - fsg_ss_function[i + FSG_SS_FUNCTION_PRE_EP_ENTRIES] = NULL; - - /* Calculate bMaxBurst, we know packet size is 1024 */ - max_burst = min_t(unsigned, mod_data.buflen / 1024, 15); - - /* Assume endpoint addresses are the same for both speeds */ - fsg_ss_bulk_in_desc.bEndpointAddress = - fsg_fs_bulk_in_desc.bEndpointAddress; - fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst; - - fsg_ss_bulk_out_desc.bEndpointAddress = - fsg_fs_bulk_out_desc.bEndpointAddress; - fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst; - } - - if (gadget_is_otg(gadget)) - fsg_otg_desc.bmAttributes |= USB_OTG_HNP; - - rc = -ENOMEM; - - /* Allocate the request and buffer for endpoint 0 */ - fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL); - if (!req) - goto out; - req->buf = kmalloc(EP0_BUFSIZE, GFP_KERNEL); - if (!req->buf) - goto out; - req->complete = ep0_complete; - - /* Allocate the data buffers */ - for (i = 0; i < fsg_num_buffers; ++i) { - struct fsg_buffhd *bh = &fsg->buffhds[i]; - - /* Allocate for the bulk-in endpoint. We assume that - * the buffer will also work with the bulk-out (and - * interrupt-in) endpoint. */ - bh->buf = kmalloc(mod_data.buflen, GFP_KERNEL); - if (!bh->buf) - goto out; - bh->next = bh + 1; - } - fsg->buffhds[fsg_num_buffers - 1].next = &fsg->buffhds[0]; - - /* This should reflect the actual gadget power source */ - usb_gadget_set_selfpowered(gadget); - - snprintf(fsg_string_manufacturer, sizeof fsg_string_manufacturer, - "%s %s with %s", - init_utsname()->sysname, init_utsname()->release, - gadget->name); - - fsg->thread_task = kthread_create(fsg_main_thread, fsg, - "file-storage-gadget"); - if (IS_ERR(fsg->thread_task)) { - rc = PTR_ERR(fsg->thread_task); - goto out; - } - - INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n"); - INFO(fsg, "NOTE: This driver is deprecated. " - "Consider using g_mass_storage instead.\n"); - INFO(fsg, "Number of LUNs=%d\n", fsg->nluns); - - pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); - for (i = 0; i < fsg->nluns; ++i) { - curlun = &fsg->luns[i]; - if (fsg_lun_is_open(curlun)) { - p = NULL; - if (pathbuf) { - p = d_path(&curlun->filp->f_path, - pathbuf, PATH_MAX); - if (IS_ERR(p)) - p = NULL; - } - LINFO(curlun, "ro=%d, nofua=%d, file: %s\n", - curlun->ro, curlun->nofua, (p ? p : "(error)")); - } - } - kfree(pathbuf); - - DBG(fsg, "transport=%s (x%02x)\n", - mod_data.transport_name, mod_data.transport_type); - DBG(fsg, "protocol=%s (x%02x)\n", - mod_data.protocol_name, mod_data.protocol_type); - DBG(fsg, "VendorID=x%04x, ProductID=x%04x, Release=x%04x\n", - mod_data.vendor, mod_data.product, mod_data.release); - DBG(fsg, "removable=%d, stall=%d, cdrom=%d, buflen=%u\n", - mod_data.removable, mod_data.can_stall, - mod_data.cdrom, mod_data.buflen); - DBG(fsg, "I/O thread pid: %d\n", task_pid_nr(fsg->thread_task)); - - set_bit(REGISTERED, &fsg->atomic_bitflags); - - /* Tell the thread to start working */ - wake_up_process(fsg->thread_task); - return 0; - -autoconf_fail: - ERROR(fsg, "unable to autoconfigure all endpoints\n"); - rc = -ENOTSUPP; - -out: - fsg->state = FSG_STATE_TERMINATED; // The thread is dead - fsg_unbind(gadget); - complete(&fsg->thread_notifier); - return rc; -} - - -/*-------------------------------------------------------------------------*/ - -static void fsg_suspend(struct usb_gadget *gadget) -{ - struct fsg_dev *fsg = get_gadget_data(gadget); - - DBG(fsg, "suspend\n"); - set_bit(SUSPENDED, &fsg->atomic_bitflags); -} - -static void fsg_resume(struct usb_gadget *gadget) -{ - struct fsg_dev *fsg = get_gadget_data(gadget); - - DBG(fsg, "resume\n"); - clear_bit(SUSPENDED, &fsg->atomic_bitflags); -} - - -/*-------------------------------------------------------------------------*/ - -static struct usb_gadget_driver fsg_driver = { - .max_speed = USB_SPEED_SUPER, - .function = (char *) fsg_string_product, - .unbind = fsg_unbind, - .disconnect = fsg_disconnect, - .setup = fsg_setup, - .suspend = fsg_suspend, - .resume = fsg_resume, - - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - // .release = ... - // .suspend = ... - // .resume = ... - }, -}; - - -static int __init fsg_alloc(void) -{ - struct fsg_dev *fsg; - - fsg = kzalloc(sizeof *fsg + - fsg_num_buffers * sizeof *(fsg->buffhds), GFP_KERNEL); - - if (!fsg) - return -ENOMEM; - spin_lock_init(&fsg->lock); - init_rwsem(&fsg->filesem); - kref_init(&fsg->ref); - init_completion(&fsg->thread_notifier); - - the_fsg = fsg; - return 0; -} - - -static int __init fsg_init(void) -{ - int rc; - struct fsg_dev *fsg; - - rc = fsg_num_buffers_validate(); - if (rc != 0) - return rc; - - if ((rc = fsg_alloc()) != 0) - return rc; - fsg = the_fsg; - if ((rc = usb_gadget_probe_driver(&fsg_driver, fsg_bind)) != 0) - kref_put(&fsg->ref, fsg_release); - return rc; -} -module_init(fsg_init); - - -static void __exit fsg_cleanup(void) -{ - struct fsg_dev *fsg = the_fsg; - - /* Unregister the driver iff the thread hasn't already done so */ - if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) - usb_gadget_unregister_driver(&fsg_driver); - - /* Wait for the thread to finish up */ - wait_for_completion(&fsg->thread_notifier); - - kref_put(&fsg->ref, fsg_release); -} -module_exit(fsg_cleanup); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/fsl_mxc_udc.c b/ANDROID_3.4.5/drivers/usb/gadget/fsl_mxc_udc.c deleted file mode 100644 index dcbc0a2e..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/fsl_mxc_udc.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2009 - * Guennadi Liakhovetski, DENX Software Engineering, - * - * 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 -#include -#include -#include -#include -#include - -#include - -static struct clk *mxc_ahb_clk; -static struct clk *mxc_usb_clk; - -/* workaround ENGcm09152 for i.MX35 */ -#define USBPHYCTRL_OTGBASE_OFFSET 0x608 -#define USBPHYCTRL_EVDO (1 << 23) - -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; - - if (!cpu_is_mx35() && !cpu_is_mx25()) { - 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; - } - - if (!cpu_is_mx51()) { - 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); - ret = -EINVAL; - 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: - if (!cpu_is_mx35()) - clk_disable(mxc_ahb_clk); -eenahb: - if (!cpu_is_mx35()) - 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; - if (cpu_is_mx35()) { - unsigned int v; - - /* workaround ENGcm09152 for i.MX35 */ - if (pdata->workaround & FLS_USB2_WORKAROUND_ENGCM09152) { - v = readl(MX35_IO_ADDRESS(MX35_USB_BASE_ADDR + - USBPHYCTRL_OTGBASE_OFFSET)); - writel(v | USBPHYCTRL_EVDO, - MX35_IO_ADDRESS(MX35_USB_BASE_ADDR + - USBPHYCTRL_OTGBASE_OFFSET)); - } - } - - /* 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); - } - if (!cpu_is_mx35()) { - clk_disable(mxc_ahb_clk); - clk_put(mxc_ahb_clk); - } -} diff --git a/ANDROID_3.4.5/drivers/usb/gadget/fsl_qe_udc.c b/ANDROID_3.4.5/drivers/usb/gadget/fsl_qe_udc.c deleted file mode 100644 index 877a2c46..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/fsl_qe_udc.c +++ /dev/null @@ -1,2823 +0,0 @@ -/* - * driver/usb/gadget/fsl_qe_udc.c - * - * Copyright (c) 2006-2008 Freescale Semiconductor, Inc. All rights reserved. - * - * Xie Xiaobo - * Li Yang - * Based on bareboard code from Shlomi Gridish. - * - * Description: - * Freescle QE/CPM USB Pheripheral Controller Driver - * The controller can be found on MPC8360, MPC8272, and etc. - * MPC8360 Rev 1.1 may need QE mircocode update - * - * 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. - */ - -#undef USB_TRACE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "fsl_qe_udc.h" - -#define DRIVER_DESC "Freescale QE/CPM USB Device Controller driver" -#define DRIVER_AUTHOR "Xie XiaoBo" -#define DRIVER_VERSION "1.0" - -#define DMA_ADDR_INVALID (~(dma_addr_t)0) - -static const char driver_name[] = "fsl_qe_udc"; -static const char driver_desc[] = DRIVER_DESC; - -/*ep name is important in gadget, it should obey the convention of ep_match()*/ -static const char *const ep_name[] = { - "ep0-control", /* everyone has ep0 */ - /* 3 configurable endpoints */ - "ep1", - "ep2", - "ep3", -}; - -static struct usb_endpoint_descriptor qe_ep0_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = 0, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, - .wMaxPacketSize = USB_MAX_CTRL_PAYLOAD, -}; - -/* it is initialized in probe() */ -static struct qe_udc *udc_controller; - -/******************************************************************** - * Internal Used Function Start -********************************************************************/ -/*----------------------------------------------------------------- - * done() - retire a request; caller blocked irqs - *--------------------------------------------------------------*/ -static void done(struct qe_ep *ep, struct qe_req *req, int status) -{ - struct qe_udc *udc = ep->udc; - unsigned char stopped = ep->stopped; - - /* the req->queue pointer is used by ep_queue() func, in which - * the request will be added into a udc_ep->queue 'd tail - * so here the req will be dropped from the ep->queue - */ - list_del_init(&req->queue); - - /* req.status should be set as -EINPROGRESS in ep_queue() */ - if (req->req.status == -EINPROGRESS) - req->req.status = status; - else - status = req->req.status; - - if (req->mapped) { - dma_unmap_single(udc->gadget.dev.parent, - req->req.dma, req->req.length, - ep_is_in(ep) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - req->req.dma = DMA_ADDR_INVALID; - req->mapped = 0; - } else - dma_sync_single_for_cpu(udc->gadget.dev.parent, - req->req.dma, req->req.length, - ep_is_in(ep) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - - if (status && (status != -ESHUTDOWN)) - dev_vdbg(udc->dev, "complete %s req %p stat %d len %u/%u\n", - ep->ep.name, &req->req, status, - req->req.actual, req->req.length); - - /* don't modify queue heads during completion callback */ - ep->stopped = 1; - spin_unlock(&udc->lock); - - /* this complete() should a func implemented by gadget layer, - * eg fsg->bulk_in_complete() */ - if (req->req.complete) - req->req.complete(&ep->ep, &req->req); - - spin_lock(&udc->lock); - - ep->stopped = stopped; -} - -/*----------------------------------------------------------------- - * nuke(): delete all requests related to this ep - *--------------------------------------------------------------*/ -static void nuke(struct qe_ep *ep, int status) -{ - /* Whether this eq has request linked */ - while (!list_empty(&ep->queue)) { - struct qe_req *req = NULL; - req = list_entry(ep->queue.next, struct qe_req, queue); - - done(ep, req, status); - } -} - -/*---------------------------------------------------------------------------* - * USB and Endpoint manipulate process, include parameter and register * - *---------------------------------------------------------------------------*/ -/* @value: 1--set stall 0--clean stall */ -static int qe_eprx_stall_change(struct qe_ep *ep, int value) -{ - u16 tem_usep; - u8 epnum = ep->epnum; - struct qe_udc *udc = ep->udc; - - tem_usep = in_be16(&udc->usb_regs->usb_usep[epnum]); - tem_usep = tem_usep & ~USB_RHS_MASK; - if (value == 1) - tem_usep |= USB_RHS_STALL; - else if (ep->dir == USB_DIR_IN) - tem_usep |= USB_RHS_IGNORE_OUT; - - out_be16(&udc->usb_regs->usb_usep[epnum], tem_usep); - return 0; -} - -static int qe_eptx_stall_change(struct qe_ep *ep, int value) -{ - u16 tem_usep; - u8 epnum = ep->epnum; - struct qe_udc *udc = ep->udc; - - tem_usep = in_be16(&udc->usb_regs->usb_usep[epnum]); - tem_usep = tem_usep & ~USB_THS_MASK; - if (value == 1) - tem_usep |= USB_THS_STALL; - else if (ep->dir == USB_DIR_OUT) - tem_usep |= USB_THS_IGNORE_IN; - - out_be16(&udc->usb_regs->usb_usep[epnum], tem_usep); - - return 0; -} - -static int qe_ep0_stall(struct qe_udc *udc) -{ - qe_eptx_stall_change(&udc->eps[0], 1); - qe_eprx_stall_change(&udc->eps[0], 1); - udc_controller->ep0_state = WAIT_FOR_SETUP; - udc_controller->ep0_dir = 0; - return 0; -} - -static int qe_eprx_nack(struct qe_ep *ep) -{ - u8 epnum = ep->epnum; - struct qe_udc *udc = ep->udc; - - if (ep->state == EP_STATE_IDLE) { - /* Set the ep's nack */ - clrsetbits_be16(&udc->usb_regs->usb_usep[epnum], - USB_RHS_MASK, USB_RHS_NACK); - - /* Mask Rx and Busy interrupts */ - clrbits16(&udc->usb_regs->usb_usbmr, - (USB_E_RXB_MASK | USB_E_BSY_MASK)); - - ep->state = EP_STATE_NACK; - } - return 0; -} - -static int qe_eprx_normal(struct qe_ep *ep) -{ - struct qe_udc *udc = ep->udc; - - if (ep->state == EP_STATE_NACK) { - clrsetbits_be16(&udc->usb_regs->usb_usep[ep->epnum], - USB_RTHS_MASK, USB_THS_IGNORE_IN); - - /* Unmask RX interrupts */ - out_be16(&udc->usb_regs->usb_usber, - USB_E_BSY_MASK | USB_E_RXB_MASK); - setbits16(&udc->usb_regs->usb_usbmr, - (USB_E_RXB_MASK | USB_E_BSY_MASK)); - - ep->state = EP_STATE_IDLE; - ep->has_data = 0; - } - - return 0; -} - -static int qe_ep_cmd_stoptx(struct qe_ep *ep) -{ - if (ep->udc->soc_type == PORT_CPM) - cpm_command(CPM_USB_STOP_TX | (ep->epnum << CPM_USB_EP_SHIFT), - CPM_USB_STOP_TX_OPCODE); - else - qe_issue_cmd(QE_USB_STOP_TX, QE_CR_SUBBLOCK_USB, - ep->epnum, 0); - - return 0; -} - -static int qe_ep_cmd_restarttx(struct qe_ep *ep) -{ - if (ep->udc->soc_type == PORT_CPM) - cpm_command(CPM_USB_RESTART_TX | (ep->epnum << - CPM_USB_EP_SHIFT), CPM_USB_RESTART_TX_OPCODE); - else - qe_issue_cmd(QE_USB_RESTART_TX, QE_CR_SUBBLOCK_USB, - ep->epnum, 0); - - return 0; -} - -static int qe_ep_flushtxfifo(struct qe_ep *ep) -{ - struct qe_udc *udc = ep->udc; - int i; - - i = (int)ep->epnum; - - qe_ep_cmd_stoptx(ep); - out_8(&udc->usb_regs->usb_uscom, - USB_CMD_FLUSH_FIFO | (USB_CMD_EP_MASK & (ep->epnum))); - out_be16(&udc->ep_param[i]->tbptr, in_be16(&udc->ep_param[i]->tbase)); - out_be32(&udc->ep_param[i]->tstate, 0); - out_be16(&udc->ep_param[i]->tbcnt, 0); - - ep->c_txbd = ep->txbase; - ep->n_txbd = ep->txbase; - qe_ep_cmd_restarttx(ep); - return 0; -} - -static int qe_ep_filltxfifo(struct qe_ep *ep) -{ - struct qe_udc *udc = ep->udc; - - out_8(&udc->usb_regs->usb_uscom, - USB_CMD_STR_FIFO | (USB_CMD_EP_MASK & (ep->epnum))); - return 0; -} - -static int qe_epbds_reset(struct qe_udc *udc, int pipe_num) -{ - struct qe_ep *ep; - u32 bdring_len; - struct qe_bd __iomem *bd; - int i; - - ep = &udc->eps[pipe_num]; - - if (ep->dir == USB_DIR_OUT) - bdring_len = USB_BDRING_LEN_RX; - else - bdring_len = USB_BDRING_LEN; - - bd = ep->rxbase; - for (i = 0; i < (bdring_len - 1); i++) { - out_be32((u32 __iomem *)bd, R_E | R_I); - bd++; - } - out_be32((u32 __iomem *)bd, R_E | R_I | R_W); - - bd = ep->txbase; - for (i = 0; i < USB_BDRING_LEN_TX - 1; i++) { - out_be32(&bd->buf, 0); - out_be32((u32 __iomem *)bd, 0); - bd++; - } - out_be32((u32 __iomem *)bd, T_W); - - return 0; -} - -static int qe_ep_reset(struct qe_udc *udc, int pipe_num) -{ - struct qe_ep *ep; - u16 tmpusep; - - ep = &udc->eps[pipe_num]; - tmpusep = in_be16(&udc->usb_regs->usb_usep[pipe_num]); - tmpusep &= ~USB_RTHS_MASK; - - switch (ep->dir) { - case USB_DIR_BOTH: - qe_ep_flushtxfifo(ep); - break; - case USB_DIR_OUT: - tmpusep |= USB_THS_IGNORE_IN; - break; - case USB_DIR_IN: - qe_ep_flushtxfifo(ep); - tmpusep |= USB_RHS_IGNORE_OUT; - break; - default: - break; - } - out_be16(&udc->usb_regs->usb_usep[pipe_num], tmpusep); - - qe_epbds_reset(udc, pipe_num); - - return 0; -} - -static int qe_ep_toggledata01(struct qe_ep *ep) -{ - ep->data01 ^= 0x1; - return 0; -} - -static int qe_ep_bd_init(struct qe_udc *udc, unsigned char pipe_num) -{ - struct qe_ep *ep = &udc->eps[pipe_num]; - unsigned long tmp_addr = 0; - struct usb_ep_para __iomem *epparam; - int i; - struct qe_bd __iomem *bd; - int bdring_len; - - if (ep->dir == USB_DIR_OUT) - bdring_len = USB_BDRING_LEN_RX; - else - bdring_len = USB_BDRING_LEN; - - epparam = udc->ep_param[pipe_num]; - /* alloc multi-ram for BD rings and set the ep parameters */ - tmp_addr = cpm_muram_alloc(sizeof(struct qe_bd) * (bdring_len + - USB_BDRING_LEN_TX), QE_ALIGNMENT_OF_BD); - if (IS_ERR_VALUE(tmp_addr)) - return -ENOMEM; - - out_be16(&epparam->rbase, (u16)tmp_addr); - out_be16(&epparam->tbase, (u16)(tmp_addr + - (sizeof(struct qe_bd) * bdring_len))); - - out_be16(&epparam->rbptr, in_be16(&epparam->rbase)); - out_be16(&epparam->tbptr, in_be16(&epparam->tbase)); - - ep->rxbase = cpm_muram_addr(tmp_addr); - ep->txbase = cpm_muram_addr(tmp_addr + (sizeof(struct qe_bd) - * bdring_len)); - ep->n_rxbd = ep->rxbase; - ep->e_rxbd = ep->rxbase; - ep->n_txbd = ep->txbase; - ep->c_txbd = ep->txbase; - ep->data01 = 0; /* data0 */ - - /* Init TX and RX bds */ - bd = ep->rxbase; - for (i = 0; i < bdring_len - 1; i++) { - out_be32(&bd->buf, 0); - out_be32((u32 __iomem *)bd, 0); - bd++; - } - out_be32(&bd->buf, 0); - out_be32((u32 __iomem *)bd, R_W); - - bd = ep->txbase; - for (i = 0; i < USB_BDRING_LEN_TX - 1; i++) { - out_be32(&bd->buf, 0); - out_be32((u32 __iomem *)bd, 0); - bd++; - } - out_be32(&bd->buf, 0); - out_be32((u32 __iomem *)bd, T_W); - - return 0; -} - -static int qe_ep_rxbd_update(struct qe_ep *ep) -{ - unsigned int size; - int i; - unsigned int tmp; - struct qe_bd __iomem *bd; - unsigned int bdring_len; - - if (ep->rxbase == NULL) - return -EINVAL; - - bd = ep->rxbase; - - ep->rxframe = kmalloc(sizeof(*ep->rxframe), GFP_ATOMIC); - if (ep->rxframe == NULL) { - dev_err(ep->udc->dev, "malloc rxframe failed\n"); - return -ENOMEM; - } - - qe_frame_init(ep->rxframe); - - if (ep->dir == USB_DIR_OUT) - bdring_len = USB_BDRING_LEN_RX; - else - bdring_len = USB_BDRING_LEN; - - size = (ep->ep.maxpacket + USB_CRC_SIZE + 2) * (bdring_len + 1); - ep->rxbuffer = kzalloc(size, GFP_ATOMIC); - if (ep->rxbuffer == NULL) { - dev_err(ep->udc->dev, "malloc rxbuffer failed,size=%d\n", - size); - kfree(ep->rxframe); - return -ENOMEM; - } - - ep->rxbuf_d = virt_to_phys((void *)ep->rxbuffer); - if (ep->rxbuf_d == DMA_ADDR_INVALID) { - ep->rxbuf_d = dma_map_single(udc_controller->gadget.dev.parent, - ep->rxbuffer, - size, - DMA_FROM_DEVICE); - ep->rxbufmap = 1; - } else { - dma_sync_single_for_device(udc_controller->gadget.dev.parent, - ep->rxbuf_d, size, - DMA_FROM_DEVICE); - ep->rxbufmap = 0; - } - - size = ep->ep.maxpacket + USB_CRC_SIZE + 2; - tmp = ep->rxbuf_d; - tmp = (u32)(((tmp >> 2) << 2) + 4); - - for (i = 0; i < bdring_len - 1; i++) { - out_be32(&bd->buf, tmp); - out_be32((u32 __iomem *)bd, (R_E | R_I)); - tmp = tmp + size; - bd++; - } - out_be32(&bd->buf, tmp); - out_be32((u32 __iomem *)bd, (R_E | R_I | R_W)); - - return 0; -} - -static int qe_ep_register_init(struct qe_udc *udc, unsigned char pipe_num) -{ - struct qe_ep *ep = &udc->eps[pipe_num]; - struct usb_ep_para __iomem *epparam; - u16 usep, logepnum; - u16 tmp; - u8 rtfcr = 0; - - epparam = udc->ep_param[pipe_num]; - - usep = 0; - logepnum = (ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); - usep |= (logepnum << USB_EPNUM_SHIFT); - - switch (ep->desc->bmAttributes & 0x03) { - case USB_ENDPOINT_XFER_BULK: - usep |= USB_TRANS_BULK; - break; - case USB_ENDPOINT_XFER_ISOC: - usep |= USB_TRANS_ISO; - break; - case USB_ENDPOINT_XFER_INT: - usep |= USB_TRANS_INT; - break; - default: - usep |= USB_TRANS_CTR; - break; - } - - switch (ep->dir) { - case USB_DIR_OUT: - usep |= USB_THS_IGNORE_IN; - break; - case USB_DIR_IN: - usep |= USB_RHS_IGNORE_OUT; - break; - default: - break; - } - out_be16(&udc->usb_regs->usb_usep[pipe_num], usep); - - rtfcr = 0x30; - out_8(&epparam->rbmr, rtfcr); - out_8(&epparam->tbmr, rtfcr); - - tmp = (u16)(ep->ep.maxpacket + USB_CRC_SIZE); - /* MRBLR must be divisble by 4 */ - tmp = (u16)(((tmp >> 2) << 2) + 4); - out_be16(&epparam->mrblr, tmp); - - return 0; -} - -static int qe_ep_init(struct qe_udc *udc, - unsigned char pipe_num, - const struct usb_endpoint_descriptor *desc) -{ - struct qe_ep *ep = &udc->eps[pipe_num]; - unsigned long flags; - int reval = 0; - u16 max = 0; - - max = usb_endpoint_maxp(desc); - - /* check the max package size validate for this endpoint */ - /* Refer to USB2.0 spec table 9-13, - */ - if (pipe_num != 0) { - switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { - case USB_ENDPOINT_XFER_BULK: - if (strstr(ep->ep.name, "-iso") - || strstr(ep->ep.name, "-int")) - goto en_done; - switch (udc->gadget.speed) { - case USB_SPEED_HIGH: - if ((max == 128) || (max == 256) || (max == 512)) - break; - default: - switch (max) { - case 4: - case 8: - case 16: - case 32: - case 64: - break; - default: - case USB_SPEED_LOW: - goto en_done; - } - } - break; - case USB_ENDPOINT_XFER_INT: - if (strstr(ep->ep.name, "-iso")) /* bulk is ok */ - goto en_done; - switch (udc->gadget.speed) { - case USB_SPEED_HIGH: - if (max <= 1024) - break; - case USB_SPEED_FULL: - if (max <= 64) - break; - default: - if (max <= 8) - break; - goto en_done; - } - break; - case USB_ENDPOINT_XFER_ISOC: - if (strstr(ep->ep.name, "-bulk") - || strstr(ep->ep.name, "-int")) - goto en_done; - switch (udc->gadget.speed) { - case USB_SPEED_HIGH: - if (max <= 1024) - break; - case USB_SPEED_FULL: - if (max <= 1023) - break; - default: - goto en_done; - } - break; - case USB_ENDPOINT_XFER_CONTROL: - if (strstr(ep->ep.name, "-iso") - || strstr(ep->ep.name, "-int")) - goto en_done; - switch (udc->gadget.speed) { - case USB_SPEED_HIGH: - case USB_SPEED_FULL: - switch (max) { - case 1: - case 2: - case 4: - case 8: - case 16: - case 32: - case 64: - break; - default: - goto en_done; - } - case USB_SPEED_LOW: - switch (max) { - case 1: - case 2: - case 4: - case 8: - break; - default: - goto en_done; - } - default: - goto en_done; - } - break; - - default: - goto en_done; - } - } /* if ep0*/ - - spin_lock_irqsave(&udc->lock, flags); - - /* initialize ep structure */ - ep->ep.maxpacket = max; - ep->tm = (u8)(desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); - ep->desc = desc; - ep->stopped = 0; - ep->init = 1; - - if (pipe_num == 0) { - ep->dir = USB_DIR_BOTH; - udc->ep0_dir = USB_DIR_OUT; - udc->ep0_state = WAIT_FOR_SETUP; - } else { - switch (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) { - case USB_DIR_OUT: - ep->dir = USB_DIR_OUT; - break; - case USB_DIR_IN: - ep->dir = USB_DIR_IN; - default: - break; - } - } - - /* hardware special operation */ - qe_ep_bd_init(udc, pipe_num); - if ((ep->tm == USBP_TM_CTL) || (ep->dir == USB_DIR_OUT)) { - reval = qe_ep_rxbd_update(ep); - if (reval) - goto en_done1; - } - - if ((ep->tm == USBP_TM_CTL) || (ep->dir == USB_DIR_IN)) { - ep->txframe = kmalloc(sizeof(*ep->txframe), GFP_ATOMIC); - if (ep->txframe == NULL) { - dev_err(udc->dev, "malloc txframe failed\n"); - goto en_done2; - } - qe_frame_init(ep->txframe); - } - - qe_ep_register_init(udc, pipe_num); - - /* Now HW will be NAKing transfers to that EP, - * until a buffer is queued to it. */ - spin_unlock_irqrestore(&udc->lock, flags); - - return 0; -en_done2: - kfree(ep->rxbuffer); - kfree(ep->rxframe); -en_done1: - spin_unlock_irqrestore(&udc->lock, flags); -en_done: - dev_err(udc->dev, "failed to initialize %s\n", ep->ep.name); - return -ENODEV; -} - -static inline void qe_usb_enable(void) -{ - setbits8(&udc_controller->usb_regs->usb_usmod, USB_MODE_EN); -} - -static inline void qe_usb_disable(void) -{ - clrbits8(&udc_controller->usb_regs->usb_usmod, USB_MODE_EN); -} - -/*----------------------------------------------------------------------------* - * USB and EP basic manipulate function end * - *----------------------------------------------------------------------------*/ - - -/****************************************************************************** - UDC transmit and receive process - ******************************************************************************/ -static void recycle_one_rxbd(struct qe_ep *ep) -{ - u32 bdstatus; - - bdstatus = in_be32((u32 __iomem *)ep->e_rxbd); - bdstatus = R_I | R_E | (bdstatus & R_W); - out_be32((u32 __iomem *)ep->e_rxbd, bdstatus); - - if (bdstatus & R_W) - ep->e_rxbd = ep->rxbase; - else - ep->e_rxbd++; -} - -static void recycle_rxbds(struct qe_ep *ep, unsigned char stopatnext) -{ - u32 bdstatus; - struct qe_bd __iomem *bd, *nextbd; - unsigned char stop = 0; - - nextbd = ep->n_rxbd; - bd = ep->e_rxbd; - bdstatus = in_be32((u32 __iomem *)bd); - - while (!(bdstatus & R_E) && !(bdstatus & BD_LENGTH_MASK) && !stop) { - bdstatus = R_E | R_I | (bdstatus & R_W); - out_be32((u32 __iomem *)bd, bdstatus); - - if (bdstatus & R_W) - bd = ep->rxbase; - else - bd++; - - bdstatus = in_be32((u32 __iomem *)bd); - if (stopatnext && (bd == nextbd)) - stop = 1; - } - - ep->e_rxbd = bd; -} - -static void ep_recycle_rxbds(struct qe_ep *ep) -{ - struct qe_bd __iomem *bd = ep->n_rxbd; - u32 bdstatus; - u8 epnum = ep->epnum; - struct qe_udc *udc = ep->udc; - - bdstatus = in_be32((u32 __iomem *)bd); - if (!(bdstatus & R_E) && !(bdstatus & BD_LENGTH_MASK)) { - bd = ep->rxbase + - ((in_be16(&udc->ep_param[epnum]->rbptr) - - in_be16(&udc->ep_param[epnum]->rbase)) - >> 3); - bdstatus = in_be32((u32 __iomem *)bd); - - if (bdstatus & R_W) - bd = ep->rxbase; - else - bd++; - - ep->e_rxbd = bd; - recycle_rxbds(ep, 0); - ep->e_rxbd = ep->n_rxbd; - } else - recycle_rxbds(ep, 1); - - if (in_be16(&udc->usb_regs->usb_usber) & USB_E_BSY_MASK) - out_be16(&udc->usb_regs->usb_usber, USB_E_BSY_MASK); - - if (ep->has_data <= 0 && (!list_empty(&ep->queue))) - qe_eprx_normal(ep); - - ep->localnack = 0; -} - -static void setup_received_handle(struct qe_udc *udc, - struct usb_ctrlrequest *setup); -static int qe_ep_rxframe_handle(struct qe_ep *ep); -static void ep0_req_complete(struct qe_udc *udc, struct qe_req *req); -/* when BD PID is setup, handle the packet */ -static int ep0_setup_handle(struct qe_udc *udc) -{ - struct qe_ep *ep = &udc->eps[0]; - struct qe_frame *pframe; - unsigned int fsize; - u8 *cp; - - pframe = ep->rxframe; - if ((frame_get_info(pframe) & PID_SETUP) - && (udc->ep0_state == WAIT_FOR_SETUP)) { - fsize = frame_get_length(pframe); - if (unlikely(fsize != 8)) - return -EINVAL; - cp = (u8 *)&udc->local_setup_buff; - memcpy(cp, pframe->data, fsize); - ep->data01 = 1; - - /* handle the usb command base on the usb_ctrlrequest */ - setup_received_handle(udc, &udc->local_setup_buff); - return 0; - } - return -EINVAL; -} - -static int qe_ep0_rx(struct qe_udc *udc) -{ - struct qe_ep *ep = &udc->eps[0]; - struct qe_frame *pframe; - struct qe_bd __iomem *bd; - u32 bdstatus, length; - u32 vaddr; - - pframe = ep->rxframe; - - if (ep->dir == USB_DIR_IN) { - dev_err(udc->dev, "ep0 not a control endpoint\n"); - return -EINVAL; - } - - bd = ep->n_rxbd; - bdstatus = in_be32((u32 __iomem *)bd); - length = bdstatus & BD_LENGTH_MASK; - - while (!(bdstatus & R_E) && length) { - if ((bdstatus & R_F) && (bdstatus & R_L) - && !(bdstatus & R_ERROR)) { - if (length == USB_CRC_SIZE) { - udc->ep0_state = WAIT_FOR_SETUP; - dev_vdbg(udc->dev, - "receive a ZLP in status phase\n"); - } else { - qe_frame_clean(pframe); - vaddr = (u32)phys_to_virt(in_be32(&bd->buf)); - frame_set_data(pframe, (u8 *)vaddr); - frame_set_length(pframe, - (length - USB_CRC_SIZE)); - frame_set_status(pframe, FRAME_OK); - switch (bdstatus & R_PID) { - case R_PID_SETUP: - frame_set_info(pframe, PID_SETUP); - break; - case R_PID_DATA1: - frame_set_info(pframe, PID_DATA1); - break; - default: - frame_set_info(pframe, PID_DATA0); - break; - } - - if ((bdstatus & R_PID) == R_PID_SETUP) - ep0_setup_handle(udc); - else - qe_ep_rxframe_handle(ep); - } - } else { - dev_err(udc->dev, "The receive frame with error!\n"); - } - - /* note: don't clear the rxbd's buffer address */ - recycle_one_rxbd(ep); - - /* Get next BD */ - if (bdstatus & R_W) - bd = ep->rxbase; - else - bd++; - - bdstatus = in_be32((u32 __iomem *)bd); - length = bdstatus & BD_LENGTH_MASK; - - } - - ep->n_rxbd = bd; - - return 0; -} - -static int qe_ep_rxframe_handle(struct qe_ep *ep) -{ - struct qe_frame *pframe; - u8 framepid = 0; - unsigned int fsize; - u8 *cp; - struct qe_req *req; - - pframe = ep->rxframe; - - if (frame_get_info(pframe) & PID_DATA1) - framepid = 0x1; - - if (framepid != ep->data01) { - dev_err(ep->udc->dev, "the data01 error!\n"); - return -EIO; - } - - fsize = frame_get_length(pframe); - if (list_empty(&ep->queue)) { - dev_err(ep->udc->dev, "the %s have no requeue!\n", ep->name); - } else { - req = list_entry(ep->queue.next, struct qe_req, queue); - - cp = (u8 *)(req->req.buf) + req->req.actual; - if (cp) { - memcpy(cp, pframe->data, fsize); - req->req.actual += fsize; - if ((fsize < ep->ep.maxpacket) || - (req->req.actual >= req->req.length)) { - if (ep->epnum == 0) - ep0_req_complete(ep->udc, req); - else - done(ep, req, 0); - if (list_empty(&ep->queue) && ep->epnum != 0) - qe_eprx_nack(ep); - } - } - } - - qe_ep_toggledata01(ep); - - return 0; -} - -static void ep_rx_tasklet(unsigned long data) -{ - struct qe_udc *udc = (struct qe_udc *)data; - struct qe_ep *ep; - struct qe_frame *pframe; - struct qe_bd __iomem *bd; - unsigned long flags; - u32 bdstatus, length; - u32 vaddr, i; - - spin_lock_irqsave(&udc->lock, flags); - - for (i = 1; i < USB_MAX_ENDPOINTS; i++) { - ep = &udc->eps[i]; - - if (ep->dir == USB_DIR_IN || ep->enable_tasklet == 0) { - dev_dbg(udc->dev, - "This is a transmit ep or disable tasklet!\n"); - continue; - } - - pframe = ep->rxframe; - bd = ep->n_rxbd; - bdstatus = in_be32((u32 __iomem *)bd); - length = bdstatus & BD_LENGTH_MASK; - - while (!(bdstatus & R_E) && length) { - if (list_empty(&ep->queue)) { - qe_eprx_nack(ep); - dev_dbg(udc->dev, - "The rxep have noreq %d\n", - ep->has_data); - break; - } - - if ((bdstatus & R_F) && (bdstatus & R_L) - && !(bdstatus & R_ERROR)) { - qe_frame_clean(pframe); - vaddr = (u32)phys_to_virt(in_be32(&bd->buf)); - frame_set_data(pframe, (u8 *)vaddr); - frame_set_length(pframe, - (length - USB_CRC_SIZE)); - frame_set_status(pframe, FRAME_OK); - switch (bdstatus & R_PID) { - case R_PID_DATA1: - frame_set_info(pframe, PID_DATA1); - break; - case R_PID_SETUP: - frame_set_info(pframe, PID_SETUP); - break; - default: - frame_set_info(pframe, PID_DATA0); - break; - } - /* handle the rx frame */ - qe_ep_rxframe_handle(ep); - } else { - dev_err(udc->dev, - "error in received frame\n"); - } - /* note: don't clear the rxbd's buffer address */ - /*clear the length */ - out_be32((u32 __iomem *)bd, bdstatus & BD_STATUS_MASK); - ep->has_data--; - if (!(ep->localnack)) - recycle_one_rxbd(ep); - - /* Get next BD */ - if (bdstatus & R_W) - bd = ep->rxbase; - else - bd++; - - bdstatus = in_be32((u32 __iomem *)bd); - length = bdstatus & BD_LENGTH_MASK; - } - - ep->n_rxbd = bd; - - if (ep->localnack) - ep_recycle_rxbds(ep); - - ep->enable_tasklet = 0; - } /* for i=1 */ - - spin_unlock_irqrestore(&udc->lock, flags); -} - -static int qe_ep_rx(struct qe_ep *ep) -{ - struct qe_udc *udc; - struct qe_frame *pframe; - struct qe_bd __iomem *bd; - u16 swoffs, ucoffs, emptybds; - - udc = ep->udc; - pframe = ep->rxframe; - - if (ep->dir == USB_DIR_IN) { - dev_err(udc->dev, "transmit ep in rx function\n"); - return -EINVAL; - } - - bd = ep->n_rxbd; - - swoffs = (u16)(bd - ep->rxbase); - ucoffs = (u16)((in_be16(&udc->ep_param[ep->epnum]->rbptr) - - in_be16(&udc->ep_param[ep->epnum]->rbase)) >> 3); - if (swoffs < ucoffs) - emptybds = USB_BDRING_LEN_RX - ucoffs + swoffs; - else - emptybds = swoffs - ucoffs; - - if (emptybds < MIN_EMPTY_BDS) { - qe_eprx_nack(ep); - ep->localnack = 1; - dev_vdbg(udc->dev, "%d empty bds, send NACK\n", emptybds); - } - ep->has_data = USB_BDRING_LEN_RX - emptybds; - - if (list_empty(&ep->queue)) { - qe_eprx_nack(ep); - dev_vdbg(udc->dev, "The rxep have no req queued with %d BDs\n", - ep->has_data); - return 0; - } - - tasklet_schedule(&udc->rx_tasklet); - ep->enable_tasklet = 1; - - return 0; -} - -/* send data from a frame, no matter what tx_req */ -static int qe_ep_tx(struct qe_ep *ep, struct qe_frame *frame) -{ - struct qe_udc *udc = ep->udc; - struct qe_bd __iomem *bd; - u16 saveusbmr; - u32 bdstatus, pidmask; - u32 paddr; - - if (ep->dir == USB_DIR_OUT) { - dev_err(udc->dev, "receive ep passed to tx function\n"); - return -EINVAL; - } - - /* Disable the Tx interrupt */ - saveusbmr = in_be16(&udc->usb_regs->usb_usbmr); - out_be16(&udc->usb_regs->usb_usbmr, - saveusbmr & ~(USB_E_TXB_MASK | USB_E_TXE_MASK)); - - bd = ep->n_txbd; - bdstatus = in_be32((u32 __iomem *)bd); - - if (!(bdstatus & (T_R | BD_LENGTH_MASK))) { - if (frame_get_length(frame) == 0) { - frame_set_data(frame, udc->nullbuf); - frame_set_length(frame, 2); - frame->info |= (ZLP | NO_CRC); - dev_vdbg(udc->dev, "the frame size = 0\n"); - } - paddr = virt_to_phys((void *)frame->data); - out_be32(&bd->buf, paddr); - bdstatus = (bdstatus&T_W); - if (!(frame_get_info(frame) & NO_CRC)) - bdstatus |= T_R | T_I | T_L | T_TC - | frame_get_length(frame); - else - bdstatus |= T_R | T_I | T_L | frame_get_length(frame); - - /* if the packet is a ZLP in status phase */ - if ((ep->epnum == 0) && (udc->ep0_state == DATA_STATE_NEED_ZLP)) - ep->data01 = 0x1; - - if (ep->data01) { - pidmask = T_PID_DATA1; - frame->info |= PID_DATA1; - } else { - pidmask = T_PID_DATA0; - frame->info |= PID_DATA0; - } - bdstatus |= T_CNF; - bdstatus |= pidmask; - out_be32((u32 __iomem *)bd, bdstatus); - qe_ep_filltxfifo(ep); - - /* enable the TX interrupt */ - out_be16(&udc->usb_regs->usb_usbmr, saveusbmr); - - qe_ep_toggledata01(ep); - if (bdstatus & T_W) - ep->n_txbd = ep->txbase; - else - ep->n_txbd++; - - return 0; - } else { - out_be16(&udc->usb_regs->usb_usbmr, saveusbmr); - dev_vdbg(udc->dev, "The tx bd is not ready!\n"); - return -EBUSY; - } -} - -/* when a bd was transmitted, the function can - * handle the tx_req, not include ep0 */ -static int txcomplete(struct qe_ep *ep, unsigned char restart) -{ - if (ep->tx_req != NULL) { - struct qe_req *req = ep->tx_req; - unsigned zlp = 0, last_len = 0; - - last_len = min_t(unsigned, req->req.length - ep->sent, - ep->ep.maxpacket); - - if (!restart) { - int asent = ep->last; - ep->sent += asent; - ep->last -= asent; - } else { - ep->last = 0; - } - - /* zlp needed when req->re.zero is set */ - if (req->req.zero) { - if (last_len == 0 || - (req->req.length % ep->ep.maxpacket) != 0) - zlp = 0; - else - zlp = 1; - } else - zlp = 0; - - /* a request already were transmitted completely */ - if (((ep->tx_req->req.length - ep->sent) <= 0) && !zlp) { - done(ep, ep->tx_req, 0); - ep->tx_req = NULL; - ep->last = 0; - ep->sent = 0; - } - } - - /* we should gain a new tx_req fot this endpoint */ - if (ep->tx_req == NULL) { - if (!list_empty(&ep->queue)) { - ep->tx_req = list_entry(ep->queue.next, struct qe_req, - queue); - ep->last = 0; - ep->sent = 0; - } - } - - return 0; -} - -/* give a frame and a tx_req, send some data */ -static int qe_usb_senddata(struct qe_ep *ep, struct qe_frame *frame) -{ - unsigned int size; - u8 *buf; - - qe_frame_clean(frame); - size = min_t(u32, (ep->tx_req->req.length - ep->sent), - ep->ep.maxpacket); - buf = (u8 *)ep->tx_req->req.buf + ep->sent; - if (buf && size) { - ep->last = size; - ep->tx_req->req.actual += size; - frame_set_data(frame, buf); - frame_set_length(frame, size); - frame_set_status(frame, FRAME_OK); - frame_set_info(frame, 0); - return qe_ep_tx(ep, frame); - } - return -EIO; -} - -/* give a frame struct,send a ZLP */ -static int sendnulldata(struct qe_ep *ep, struct qe_frame *frame, uint infor) -{ - struct qe_udc *udc = ep->udc; - - if (frame == NULL) - return -ENODEV; - - qe_frame_clean(frame); - frame_set_data(frame, (u8 *)udc->nullbuf); - frame_set_length(frame, 2); - frame_set_status(frame, FRAME_OK); - frame_set_info(frame, (ZLP | NO_CRC | infor)); - - return qe_ep_tx(ep, frame); -} - -static int frame_create_tx(struct qe_ep *ep, struct qe_frame *frame) -{ - struct qe_req *req = ep->tx_req; - int reval; - - if (req == NULL) - return -ENODEV; - - if ((req->req.length - ep->sent) > 0) - reval = qe_usb_senddata(ep, frame); - else - reval = sendnulldata(ep, frame, 0); - - return reval; -} - -/* if direction is DIR_IN, the status is Device->Host - * if direction is DIR_OUT, the status transaction is Device<-Host - * in status phase, udc create a request and gain status */ -static int ep0_prime_status(struct qe_udc *udc, int direction) -{ - - struct qe_ep *ep = &udc->eps[0]; - - if (direction == USB_DIR_IN) { - udc->ep0_state = DATA_STATE_NEED_ZLP; - udc->ep0_dir = USB_DIR_IN; - sendnulldata(ep, ep->txframe, SETUP_STATUS | NO_REQ); - } else { - udc->ep0_dir = USB_DIR_OUT; - udc->ep0_state = WAIT_FOR_OUT_STATUS; - } - - return 0; -} - -/* a request complete in ep0, whether gadget request or udc request */ -static void ep0_req_complete(struct qe_udc *udc, struct qe_req *req) -{ - struct qe_ep *ep = &udc->eps[0]; - /* because usb and ep's status already been set in ch9setaddress() */ - - switch (udc->ep0_state) { - case DATA_STATE_XMIT: - done(ep, req, 0); - /* receive status phase */ - if (ep0_prime_status(udc, USB_DIR_OUT)) - qe_ep0_stall(udc); - break; - - case DATA_STATE_NEED_ZLP: - done(ep, req, 0); - udc->ep0_state = WAIT_FOR_SETUP; - break; - - case DATA_STATE_RECV: - done(ep, req, 0); - /* send status phase */ - if (ep0_prime_status(udc, USB_DIR_IN)) - qe_ep0_stall(udc); - break; - - case WAIT_FOR_OUT_STATUS: - done(ep, req, 0); - udc->ep0_state = WAIT_FOR_SETUP; - break; - - case WAIT_FOR_SETUP: - dev_vdbg(udc->dev, "Unexpected interrupt\n"); - break; - - default: - qe_ep0_stall(udc); - break; - } -} - -static int ep0_txcomplete(struct qe_ep *ep, unsigned char restart) -{ - struct qe_req *tx_req = NULL; - struct qe_frame *frame = ep->txframe; - - if ((frame_get_info(frame) & (ZLP | NO_REQ)) == (ZLP | NO_REQ)) { - if (!restart) - ep->udc->ep0_state = WAIT_FOR_SETUP; - else - sendnulldata(ep, ep->txframe, SETUP_STATUS | NO_REQ); - return 0; - } - - tx_req = ep->tx_req; - if (tx_req != NULL) { - if (!restart) { - int asent = ep->last; - ep->sent += asent; - ep->last -= asent; - } else { - ep->last = 0; - } - - /* a request already were transmitted completely */ - if ((ep->tx_req->req.length - ep->sent) <= 0) { - ep->tx_req->req.actual = (unsigned int)ep->sent; - ep0_req_complete(ep->udc, ep->tx_req); - ep->tx_req = NULL; - ep->last = 0; - ep->sent = 0; - } - } else { - dev_vdbg(ep->udc->dev, "the ep0_controller have no req\n"); - } - - return 0; -} - -static int ep0_txframe_handle(struct qe_ep *ep) -{ - /* if have error, transmit again */ - if (frame_get_status(ep->txframe) & FRAME_ERROR) { - qe_ep_flushtxfifo(ep); - dev_vdbg(ep->udc->dev, "The EP0 transmit data have error!\n"); - if (frame_get_info(ep->txframe) & PID_DATA0) - ep->data01 = 0; - else - ep->data01 = 1; - - ep0_txcomplete(ep, 1); - } else - ep0_txcomplete(ep, 0); - - frame_create_tx(ep, ep->txframe); - return 0; -} - -static int qe_ep0_txconf(struct qe_ep *ep) -{ - struct qe_bd __iomem *bd; - struct qe_frame *pframe; - u32 bdstatus; - - bd = ep->c_txbd; - bdstatus = in_be32((u32 __iomem *)bd); - while (!(bdstatus & T_R) && (bdstatus & ~T_W)) { - pframe = ep->txframe; - - /* clear and recycle the BD */ - out_be32((u32 __iomem *)bd, bdstatus & T_W); - out_be32(&bd->buf, 0); - if (bdstatus & T_W) - ep->c_txbd = ep->txbase; - else - ep->c_txbd++; - - if (ep->c_txbd == ep->n_txbd) { - if (bdstatus & DEVICE_T_ERROR) { - frame_set_status(pframe, FRAME_ERROR); - if (bdstatus & T_TO) - pframe->status |= TX_ER_TIMEOUT; - if (bdstatus & T_UN) - pframe->status |= TX_ER_UNDERUN; - } - ep0_txframe_handle(ep); - } - - bd = ep->c_txbd; - bdstatus = in_be32((u32 __iomem *)bd); - } - - return 0; -} - -static int ep_txframe_handle(struct qe_ep *ep) -{ - if (frame_get_status(ep->txframe) & FRAME_ERROR) { - qe_ep_flushtxfifo(ep); - dev_vdbg(ep->udc->dev, "The EP0 transmit data have error!\n"); - if (frame_get_info(ep->txframe) & PID_DATA0) - ep->data01 = 0; - else - ep->data01 = 1; - - txcomplete(ep, 1); - } else - txcomplete(ep, 0); - - frame_create_tx(ep, ep->txframe); /* send the data */ - return 0; -} - -/* confirm the already trainsmited bd */ -static int qe_ep_txconf(struct qe_ep *ep) -{ - struct qe_bd __iomem *bd; - struct qe_frame *pframe = NULL; - u32 bdstatus; - unsigned char breakonrxinterrupt = 0; - - bd = ep->c_txbd; - bdstatus = in_be32((u32 __iomem *)bd); - while (!(bdstatus & T_R) && (bdstatus & ~T_W)) { - pframe = ep->txframe; - if (bdstatus & DEVICE_T_ERROR) { - frame_set_status(pframe, FRAME_ERROR); - if (bdstatus & T_TO) - pframe->status |= TX_ER_TIMEOUT; - if (bdstatus & T_UN) - pframe->status |= TX_ER_UNDERUN; - } - - /* clear and recycle the BD */ - out_be32((u32 __iomem *)bd, bdstatus & T_W); - out_be32(&bd->buf, 0); - if (bdstatus & T_W) - ep->c_txbd = ep->txbase; - else - ep->c_txbd++; - - /* handle the tx frame */ - ep_txframe_handle(ep); - bd = ep->c_txbd; - bdstatus = in_be32((u32 __iomem *)bd); - } - if (breakonrxinterrupt) - return -EIO; - else - return 0; -} - -/* Add a request in queue, and try to transmit a packet */ -static int ep_req_send(struct qe_ep *ep, struct qe_req *req) -{ - int reval = 0; - - if (ep->tx_req == NULL) { - ep->sent = 0; - ep->last = 0; - txcomplete(ep, 0); /* can gain a new tx_req */ - reval = frame_create_tx(ep, ep->txframe); - } - return reval; -} - -/* Maybe this is a good ideal */ -static int ep_req_rx(struct qe_ep *ep, struct qe_req *req) -{ - struct qe_udc *udc = ep->udc; - struct qe_frame *pframe = NULL; - struct qe_bd __iomem *bd; - u32 bdstatus, length; - u32 vaddr, fsize; - u8 *cp; - u8 finish_req = 0; - u8 framepid; - - if (list_empty(&ep->queue)) { - dev_vdbg(udc->dev, "the req already finish!\n"); - return 0; - } - pframe = ep->rxframe; - - bd = ep->n_rxbd; - bdstatus = in_be32((u32 __iomem *)bd); - length = bdstatus & BD_LENGTH_MASK; - - while (!(bdstatus & R_E) && length) { - if (finish_req) - break; - if ((bdstatus & R_F) && (bdstatus & R_L) - && !(bdstatus & R_ERROR)) { - qe_frame_clean(pframe); - vaddr = (u32)phys_to_virt(in_be32(&bd->buf)); - frame_set_data(pframe, (u8 *)vaddr); - frame_set_length(pframe, (length - USB_CRC_SIZE)); - frame_set_status(pframe, FRAME_OK); - switch (bdstatus & R_PID) { - case R_PID_DATA1: - frame_set_info(pframe, PID_DATA1); break; - default: - frame_set_info(pframe, PID_DATA0); break; - } - /* handle the rx frame */ - - if (frame_get_info(pframe) & PID_DATA1) - framepid = 0x1; - else - framepid = 0; - - if (framepid != ep->data01) { - dev_vdbg(udc->dev, "the data01 error!\n"); - } else { - fsize = frame_get_length(pframe); - - cp = (u8 *)(req->req.buf) + req->req.actual; - if (cp) { - memcpy(cp, pframe->data, fsize); - req->req.actual += fsize; - if ((fsize < ep->ep.maxpacket) - || (req->req.actual >= - req->req.length)) { - finish_req = 1; - done(ep, req, 0); - if (list_empty(&ep->queue)) - qe_eprx_nack(ep); - } - } - qe_ep_toggledata01(ep); - } - } else { - dev_err(udc->dev, "The receive frame with error!\n"); - } - - /* note: don't clear the rxbd's buffer address * - * only Clear the length */ - out_be32((u32 __iomem *)bd, (bdstatus & BD_STATUS_MASK)); - ep->has_data--; - - /* Get next BD */ - if (bdstatus & R_W) - bd = ep->rxbase; - else - bd++; - - bdstatus = in_be32((u32 __iomem *)bd); - length = bdstatus & BD_LENGTH_MASK; - } - - ep->n_rxbd = bd; - ep_recycle_rxbds(ep); - - return 0; -} - -/* only add the request in queue */ -static int ep_req_receive(struct qe_ep *ep, struct qe_req *req) -{ - if (ep->state == EP_STATE_NACK) { - if (ep->has_data <= 0) { - /* Enable rx and unmask rx interrupt */ - qe_eprx_normal(ep); - } else { - /* Copy the exist BD data */ - ep_req_rx(ep, req); - } - } - - return 0; -} - -/******************************************************************** - Internal Used Function End -********************************************************************/ - -/*----------------------------------------------------------------------- - Endpoint Management Functions For Gadget - -----------------------------------------------------------------------*/ -static int qe_ep_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct qe_udc *udc; - struct qe_ep *ep; - int retval = 0; - unsigned char epnum; - - ep = container_of(_ep, struct qe_ep, ep); - - /* catch various bogus parameters */ - if (!_ep || !desc || ep->desc || _ep->name == ep_name[0] || - (desc->bDescriptorType != USB_DT_ENDPOINT)) - return -EINVAL; - - udc = ep->udc; - if (!udc->driver || (udc->gadget.speed == USB_SPEED_UNKNOWN)) - return -ESHUTDOWN; - - epnum = (u8)desc->bEndpointAddress & 0xF; - - retval = qe_ep_init(udc, epnum, desc); - if (retval != 0) { - cpm_muram_free(cpm_muram_offset(ep->rxbase)); - dev_dbg(udc->dev, "enable ep%d failed\n", ep->epnum); - return -EINVAL; - } - dev_dbg(udc->dev, "enable ep%d successful\n", ep->epnum); - return 0; -} - -static int qe_ep_disable(struct usb_ep *_ep) -{ - struct qe_udc *udc; - struct qe_ep *ep; - unsigned long flags; - unsigned int size; - - ep = container_of(_ep, struct qe_ep, ep); - udc = ep->udc; - - if (!_ep || !ep->desc) { - dev_dbg(udc->dev, "%s not enabled\n", _ep ? ep->ep.name : NULL); - return -EINVAL; - } - - spin_lock_irqsave(&udc->lock, flags); - /* Nuke all pending requests (does flush) */ - nuke(ep, -ESHUTDOWN); - ep->desc = NULL; - ep->ep.desc = NULL; - ep->stopped = 1; - ep->tx_req = NULL; - qe_ep_reset(udc, ep->epnum); - spin_unlock_irqrestore(&udc->lock, flags); - - cpm_muram_free(cpm_muram_offset(ep->rxbase)); - - if (ep->dir == USB_DIR_OUT) - size = (ep->ep.maxpacket + USB_CRC_SIZE + 2) * - (USB_BDRING_LEN_RX + 1); - else - size = (ep->ep.maxpacket + USB_CRC_SIZE + 2) * - (USB_BDRING_LEN + 1); - - if (ep->dir != USB_DIR_IN) { - kfree(ep->rxframe); - if (ep->rxbufmap) { - dma_unmap_single(udc_controller->gadget.dev.parent, - ep->rxbuf_d, size, - DMA_FROM_DEVICE); - ep->rxbuf_d = DMA_ADDR_INVALID; - } else { - dma_sync_single_for_cpu( - udc_controller->gadget.dev.parent, - ep->rxbuf_d, size, - DMA_FROM_DEVICE); - } - kfree(ep->rxbuffer); - } - - if (ep->dir != USB_DIR_OUT) - kfree(ep->txframe); - - dev_dbg(udc->dev, "disabled %s OK\n", _ep->name); - return 0; -} - -static struct usb_request *qe_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) -{ - struct qe_req *req; - - req = kzalloc(sizeof(*req), gfp_flags); - if (!req) - return NULL; - - req->req.dma = DMA_ADDR_INVALID; - - INIT_LIST_HEAD(&req->queue); - - return &req->req; -} - -static void qe_free_request(struct usb_ep *_ep, struct usb_request *_req) -{ - struct qe_req *req; - - req = container_of(_req, struct qe_req, req); - - if (_req) - kfree(req); -} - -static int __qe_ep_queue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct qe_ep *ep = container_of(_ep, struct qe_ep, ep); - struct qe_req *req = container_of(_req, struct qe_req, req); - struct qe_udc *udc; - int reval; - - udc = ep->udc; - /* catch various bogus parameters */ - if (!_req || !req->req.complete || !req->req.buf - || !list_empty(&req->queue)) { - dev_dbg(udc->dev, "bad params\n"); - return -EINVAL; - } - if (!_ep || (!ep->desc && ep_index(ep))) { - dev_dbg(udc->dev, "bad ep\n"); - return -EINVAL; - } - - if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - req->ep = ep; - - /* map virtual address to hardware */ - if (req->req.dma == DMA_ADDR_INVALID) { - req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, - req->req.buf, - req->req.length, - ep_is_in(ep) - ? DMA_TO_DEVICE : - DMA_FROM_DEVICE); - req->mapped = 1; - } else { - dma_sync_single_for_device(ep->udc->gadget.dev.parent, - req->req.dma, req->req.length, - ep_is_in(ep) - ? DMA_TO_DEVICE : - DMA_FROM_DEVICE); - req->mapped = 0; - } - - req->req.status = -EINPROGRESS; - req->req.actual = 0; - - list_add_tail(&req->queue, &ep->queue); - dev_vdbg(udc->dev, "gadget have request in %s! %d\n", - ep->name, req->req.length); - - /* push the request to device */ - if (ep_is_in(ep)) - reval = ep_req_send(ep, req); - - /* EP0 */ - if (ep_index(ep) == 0 && req->req.length > 0) { - if (ep_is_in(ep)) - udc->ep0_state = DATA_STATE_XMIT; - else - udc->ep0_state = DATA_STATE_RECV; - } - - if (ep->dir == USB_DIR_OUT) - reval = ep_req_receive(ep, req); - - return 0; -} - -/* queues (submits) an I/O request to an endpoint */ -static int qe_ep_queue(struct usb_ep *_ep, struct usb_request *_req, - gfp_t gfp_flags) -{ - struct qe_ep *ep = container_of(_ep, struct qe_ep, ep); - struct qe_udc *udc = ep->udc; - unsigned long flags; - int ret; - - spin_lock_irqsave(&udc->lock, flags); - ret = __qe_ep_queue(_ep, _req); - spin_unlock_irqrestore(&udc->lock, flags); - return ret; -} - -/* dequeues (cancels, unlinks) an I/O request from an endpoint */ -static int qe_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct qe_ep *ep = container_of(_ep, struct qe_ep, ep); - struct qe_req *req; - unsigned long flags; - - if (!_ep || !_req) - return -EINVAL; - - spin_lock_irqsave(&ep->udc->lock, flags); - - /* make sure it's actually queued on this endpoint */ - list_for_each_entry(req, &ep->queue, queue) { - if (&req->req == _req) - break; - } - - if (&req->req != _req) { - spin_unlock_irqrestore(&ep->udc->lock, flags); - return -EINVAL; - } - - done(ep, req, -ECONNRESET); - - spin_unlock_irqrestore(&ep->udc->lock, flags); - return 0; -} - -/*----------------------------------------------------------------- - * modify the endpoint halt feature - * @ep: the non-isochronous endpoint being stalled - * @value: 1--set halt 0--clear halt - * Returns zero, or a negative error code. -*----------------------------------------------------------------*/ -static int qe_ep_set_halt(struct usb_ep *_ep, int value) -{ - struct qe_ep *ep; - unsigned long flags; - int status = -EOPNOTSUPP; - struct qe_udc *udc; - - ep = container_of(_ep, struct qe_ep, ep); - if (!_ep || !ep->desc) { - status = -EINVAL; - goto out; - } - - udc = ep->udc; - /* Attempt to halt IN ep will fail if any transfer requests - * are still queue */ - if (value && ep_is_in(ep) && !list_empty(&ep->queue)) { - status = -EAGAIN; - goto out; - } - - status = 0; - spin_lock_irqsave(&ep->udc->lock, flags); - qe_eptx_stall_change(ep, value); - qe_eprx_stall_change(ep, value); - spin_unlock_irqrestore(&ep->udc->lock, flags); - - if (ep->epnum == 0) { - udc->ep0_state = WAIT_FOR_SETUP; - udc->ep0_dir = 0; - } - - /* set data toggle to DATA0 on clear halt */ - if (value == 0) - ep->data01 = 0; -out: - dev_vdbg(udc->dev, "%s %s halt stat %d\n", ep->ep.name, - value ? "set" : "clear", status); - - return status; -} - -static struct usb_ep_ops qe_ep_ops = { - .enable = qe_ep_enable, - .disable = qe_ep_disable, - - .alloc_request = qe_alloc_request, - .free_request = qe_free_request, - - .queue = qe_ep_queue, - .dequeue = qe_ep_dequeue, - - .set_halt = qe_ep_set_halt, -}; - -/*------------------------------------------------------------------------ - Gadget Driver Layer Operations - ------------------------------------------------------------------------*/ - -/* Get the current frame number */ -static int qe_get_frame(struct usb_gadget *gadget) -{ - u16 tmp; - - tmp = in_be16(&udc_controller->usb_param->frame_n); - if (tmp & 0x8000) - tmp = tmp & 0x07ff; - else - tmp = -EINVAL; - - return (int)tmp; -} - -/* Tries to wake up the host connected to this gadget - * - * Return : 0-success - * Negative-this feature not enabled by host or not supported by device hw - */ -static int qe_wakeup(struct usb_gadget *gadget) -{ - return -ENOTSUPP; -} - -/* Notify controller that VBUS is powered, Called by whatever - detects VBUS sessions */ -static int qe_vbus_session(struct usb_gadget *gadget, int is_active) -{ - return -ENOTSUPP; -} - -/* constrain controller's VBUS power usage - * This call is used by gadget drivers during SET_CONFIGURATION calls, - * reporting how much power the device may consume. For example, this - * could affect how quickly batteries are recharged. - * - * Returns zero on success, else negative errno. - */ -static int qe_vbus_draw(struct usb_gadget *gadget, unsigned mA) -{ - return -ENOTSUPP; -} - -/* Change Data+ pullup status - * this func is used by usb_gadget_connect/disconnect - */ -static int qe_pullup(struct usb_gadget *gadget, int is_on) -{ - return -ENOTSUPP; -} - -static int fsl_qe_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int fsl_qe_stop(struct usb_gadget_driver *driver); - -/* defined in usb_gadget.h */ -static struct usb_gadget_ops qe_gadget_ops = { - .get_frame = qe_get_frame, - .wakeup = qe_wakeup, -/* .set_selfpowered = qe_set_selfpowered,*/ /* always selfpowered */ - .vbus_session = qe_vbus_session, - .vbus_draw = qe_vbus_draw, - .pullup = qe_pullup, - .start = fsl_qe_start, - .stop = fsl_qe_stop, -}; - -/*------------------------------------------------------------------------- - USB ep0 Setup process in BUS Enumeration - -------------------------------------------------------------------------*/ -static int udc_reset_ep_queue(struct qe_udc *udc, u8 pipe) -{ - struct qe_ep *ep = &udc->eps[pipe]; - - nuke(ep, -ECONNRESET); - ep->tx_req = NULL; - return 0; -} - -static int reset_queues(struct qe_udc *udc) -{ - u8 pipe; - - for (pipe = 0; pipe < USB_MAX_ENDPOINTS; pipe++) - udc_reset_ep_queue(udc, pipe); - - /* report disconnect; the driver is already quiesced */ - spin_unlock(&udc->lock); - udc->driver->disconnect(&udc->gadget); - spin_lock(&udc->lock); - - return 0; -} - -static void ch9setaddress(struct qe_udc *udc, u16 value, u16 index, - u16 length) -{ - /* Save the new address to device struct */ - udc->device_address = (u8) value; - /* Update usb state */ - udc->usb_state = USB_STATE_ADDRESS; - - /* Status phase , send a ZLP */ - if (ep0_prime_status(udc, USB_DIR_IN)) - qe_ep0_stall(udc); -} - -static void ownercomplete(struct usb_ep *_ep, struct usb_request *_req) -{ - struct qe_req *req = container_of(_req, struct qe_req, req); - - req->req.buf = NULL; - kfree(req); -} - -static void ch9getstatus(struct qe_udc *udc, u8 request_type, u16 value, - u16 index, u16 length) -{ - u16 usb_status = 0; - struct qe_req *req; - struct qe_ep *ep; - int status = 0; - - ep = &udc->eps[0]; - if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) { - /* Get device status */ - usb_status = 1 << USB_DEVICE_SELF_POWERED; - } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) { - /* Get interface status */ - /* We don't have interface information in udc driver */ - usb_status = 0; - } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) { - /* Get endpoint status */ - int pipe = index & USB_ENDPOINT_NUMBER_MASK; - struct qe_ep *target_ep = &udc->eps[pipe]; - u16 usep; - - /* stall if endpoint doesn't exist */ - if (!target_ep->desc) - goto stall; - - usep = in_be16(&udc->usb_regs->usb_usep[pipe]); - if (index & USB_DIR_IN) { - if (target_ep->dir != USB_DIR_IN) - goto stall; - if ((usep & USB_THS_MASK) == USB_THS_STALL) - usb_status = 1 << USB_ENDPOINT_HALT; - } else { - if (target_ep->dir != USB_DIR_OUT) - goto stall; - if ((usep & USB_RHS_MASK) == USB_RHS_STALL) - usb_status = 1 << USB_ENDPOINT_HALT; - } - } - - req = container_of(qe_alloc_request(&ep->ep, GFP_KERNEL), - struct qe_req, req); - req->req.length = 2; - req->req.buf = udc->statusbuf; - *(u16 *)req->req.buf = cpu_to_le16(usb_status); - req->req.status = -EINPROGRESS; - req->req.actual = 0; - req->req.complete = ownercomplete; - - udc->ep0_dir = USB_DIR_IN; - - /* data phase */ - status = __qe_ep_queue(&ep->ep, &req->req); - - if (status == 0) - return; -stall: - dev_err(udc->dev, "Can't respond to getstatus request \n"); - qe_ep0_stall(udc); -} - -/* only handle the setup request, suppose the device in normal status */ -static void setup_received_handle(struct qe_udc *udc, - struct usb_ctrlrequest *setup) -{ - /* Fix Endian (udc->local_setup_buff is cpu Endian now)*/ - u16 wValue = le16_to_cpu(setup->wValue); - u16 wIndex = le16_to_cpu(setup->wIndex); - u16 wLength = le16_to_cpu(setup->wLength); - - /* clear the previous request in the ep0 */ - udc_reset_ep_queue(udc, 0); - - if (setup->bRequestType & USB_DIR_IN) - udc->ep0_dir = USB_DIR_IN; - else - udc->ep0_dir = USB_DIR_OUT; - - switch (setup->bRequest) { - case USB_REQ_GET_STATUS: - /* Data+Status phase form udc */ - if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK)) - != (USB_DIR_IN | USB_TYPE_STANDARD)) - break; - ch9getstatus(udc, setup->bRequestType, wValue, wIndex, - wLength); - return; - - case USB_REQ_SET_ADDRESS: - /* Status phase from udc */ - if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD | - USB_RECIP_DEVICE)) - break; - ch9setaddress(udc, wValue, wIndex, wLength); - return; - - case USB_REQ_CLEAR_FEATURE: - case USB_REQ_SET_FEATURE: - /* Requests with no data phase, status phase from udc */ - if ((setup->bRequestType & USB_TYPE_MASK) - != USB_TYPE_STANDARD) - break; - - if ((setup->bRequestType & USB_RECIP_MASK) - == USB_RECIP_ENDPOINT) { - int pipe = wIndex & USB_ENDPOINT_NUMBER_MASK; - struct qe_ep *ep; - - if (wValue != 0 || wLength != 0 - || pipe > USB_MAX_ENDPOINTS) - break; - ep = &udc->eps[pipe]; - - spin_unlock(&udc->lock); - qe_ep_set_halt(&ep->ep, - (setup->bRequest == USB_REQ_SET_FEATURE) - ? 1 : 0); - spin_lock(&udc->lock); - } - - ep0_prime_status(udc, USB_DIR_IN); - - return; - - default: - break; - } - - if (wLength) { - /* Data phase from gadget, status phase from udc */ - if (setup->bRequestType & USB_DIR_IN) { - udc->ep0_state = DATA_STATE_XMIT; - udc->ep0_dir = USB_DIR_IN; - } else { - udc->ep0_state = DATA_STATE_RECV; - udc->ep0_dir = USB_DIR_OUT; - } - spin_unlock(&udc->lock); - if (udc->driver->setup(&udc->gadget, - &udc->local_setup_buff) < 0) - qe_ep0_stall(udc); - spin_lock(&udc->lock); - } else { - /* No data phase, IN status from gadget */ - udc->ep0_dir = USB_DIR_IN; - spin_unlock(&udc->lock); - if (udc->driver->setup(&udc->gadget, - &udc->local_setup_buff) < 0) - qe_ep0_stall(udc); - spin_lock(&udc->lock); - udc->ep0_state = DATA_STATE_NEED_ZLP; - } -} - -/*------------------------------------------------------------------------- - USB Interrupt handlers - -------------------------------------------------------------------------*/ -static void suspend_irq(struct qe_udc *udc) -{ - udc->resume_state = udc->usb_state; - udc->usb_state = USB_STATE_SUSPENDED; - - /* report suspend to the driver ,serial.c not support this*/ - if (udc->driver->suspend) - udc->driver->suspend(&udc->gadget); -} - -static void resume_irq(struct qe_udc *udc) -{ - udc->usb_state = udc->resume_state; - udc->resume_state = 0; - - /* report resume to the driver , serial.c not support this*/ - if (udc->driver->resume) - udc->driver->resume(&udc->gadget); -} - -static void idle_irq(struct qe_udc *udc) -{ - u8 usbs; - - usbs = in_8(&udc->usb_regs->usb_usbs); - if (usbs & USB_IDLE_STATUS_MASK) { - if ((udc->usb_state) != USB_STATE_SUSPENDED) - suspend_irq(udc); - } else { - if (udc->usb_state == USB_STATE_SUSPENDED) - resume_irq(udc); - } -} - -static int reset_irq(struct qe_udc *udc) -{ - unsigned char i; - - if (udc->usb_state == USB_STATE_DEFAULT) - return 0; - - qe_usb_disable(); - out_8(&udc->usb_regs->usb_usadr, 0); - - for (i = 0; i < USB_MAX_ENDPOINTS; i++) { - if (udc->eps[i].init) - qe_ep_reset(udc, i); - } - - reset_queues(udc); - udc->usb_state = USB_STATE_DEFAULT; - udc->ep0_state = WAIT_FOR_SETUP; - udc->ep0_dir = USB_DIR_OUT; - qe_usb_enable(); - return 0; -} - -static int bsy_irq(struct qe_udc *udc) -{ - return 0; -} - -static int txe_irq(struct qe_udc *udc) -{ - return 0; -} - -/* ep0 tx interrupt also in here */ -static int tx_irq(struct qe_udc *udc) -{ - struct qe_ep *ep; - struct qe_bd __iomem *bd; - int i, res = 0; - - if ((udc->usb_state == USB_STATE_ADDRESS) - && (in_8(&udc->usb_regs->usb_usadr) == 0)) - out_8(&udc->usb_regs->usb_usadr, udc->device_address); - - for (i = (USB_MAX_ENDPOINTS-1); ((i >= 0) && (res == 0)); i--) { - ep = &udc->eps[i]; - if (ep && ep->init && (ep->dir != USB_DIR_OUT)) { - bd = ep->c_txbd; - if (!(in_be32((u32 __iomem *)bd) & T_R) - && (in_be32(&bd->buf))) { - /* confirm the transmitted bd */ - if (ep->epnum == 0) - res = qe_ep0_txconf(ep); - else - res = qe_ep_txconf(ep); - } - } - } - return res; -} - - -/* setup packect's rx is handle in the function too */ -static void rx_irq(struct qe_udc *udc) -{ - struct qe_ep *ep; - struct qe_bd __iomem *bd; - int i; - - for (i = 0; i < USB_MAX_ENDPOINTS; i++) { - ep = &udc->eps[i]; - if (ep && ep->init && (ep->dir != USB_DIR_IN)) { - bd = ep->n_rxbd; - if (!(in_be32((u32 __iomem *)bd) & R_E) - && (in_be32(&bd->buf))) { - if (ep->epnum == 0) { - qe_ep0_rx(udc); - } else { - /*non-setup package receive*/ - qe_ep_rx(ep); - } - } - } - } -} - -static irqreturn_t qe_udc_irq(int irq, void *_udc) -{ - struct qe_udc *udc = (struct qe_udc *)_udc; - u16 irq_src; - irqreturn_t status = IRQ_NONE; - unsigned long flags; - - spin_lock_irqsave(&udc->lock, flags); - - irq_src = in_be16(&udc->usb_regs->usb_usber) & - in_be16(&udc->usb_regs->usb_usbmr); - /* Clear notification bits */ - out_be16(&udc->usb_regs->usb_usber, irq_src); - /* USB Interrupt */ - if (irq_src & USB_E_IDLE_MASK) { - idle_irq(udc); - irq_src &= ~USB_E_IDLE_MASK; - status = IRQ_HANDLED; - } - - if (irq_src & USB_E_TXB_MASK) { - tx_irq(udc); - irq_src &= ~USB_E_TXB_MASK; - status = IRQ_HANDLED; - } - - if (irq_src & USB_E_RXB_MASK) { - rx_irq(udc); - irq_src &= ~USB_E_RXB_MASK; - status = IRQ_HANDLED; - } - - if (irq_src & USB_E_RESET_MASK) { - reset_irq(udc); - irq_src &= ~USB_E_RESET_MASK; - status = IRQ_HANDLED; - } - - if (irq_src & USB_E_BSY_MASK) { - bsy_irq(udc); - irq_src &= ~USB_E_BSY_MASK; - status = IRQ_HANDLED; - } - - if (irq_src & USB_E_TXE_MASK) { - txe_irq(udc); - irq_src &= ~USB_E_TXE_MASK; - status = IRQ_HANDLED; - } - - spin_unlock_irqrestore(&udc->lock, flags); - - return status; -} - -/*------------------------------------------------------------------------- - Gadget driver probe and unregister. - --------------------------------------------------------------------------*/ -static int fsl_qe_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) -{ - int retval; - unsigned long flags = 0; - - /* standard operations */ - if (!udc_controller) - return -ENODEV; - - if (!driver || driver->max_speed < USB_SPEED_FULL - || !bind || !driver->disconnect || !driver->setup) - return -EINVAL; - - if (udc_controller->driver) - return -EBUSY; - - /* lock is needed but whether should use this lock or another */ - spin_lock_irqsave(&udc_controller->lock, flags); - - driver->driver.bus = NULL; - /* hook up the driver */ - udc_controller->driver = driver; - udc_controller->gadget.dev.driver = &driver->driver; - udc_controller->gadget.speed = driver->max_speed; - spin_unlock_irqrestore(&udc_controller->lock, flags); - - retval = bind(&udc_controller->gadget); - if (retval) { - dev_err(udc_controller->dev, "bind to %s --> %d", - driver->driver.name, retval); - udc_controller->gadget.dev.driver = NULL; - udc_controller->driver = NULL; - return retval; - } - - /* Enable IRQ reg and Set usbcmd reg EN bit */ - qe_usb_enable(); - - out_be16(&udc_controller->usb_regs->usb_usber, 0xffff); - out_be16(&udc_controller->usb_regs->usb_usbmr, USB_E_DEFAULT_DEVICE); - udc_controller->usb_state = USB_STATE_ATTACHED; - udc_controller->ep0_state = WAIT_FOR_SETUP; - udc_controller->ep0_dir = USB_DIR_OUT; - dev_info(udc_controller->dev, "%s bind to driver %s \n", - udc_controller->gadget.name, driver->driver.name); - return 0; -} - -static int fsl_qe_stop(struct usb_gadget_driver *driver) -{ - struct qe_ep *loop_ep; - unsigned long flags; - - if (!udc_controller) - return -ENODEV; - - if (!driver || driver != udc_controller->driver) - return -EINVAL; - - /* stop usb controller, disable intr */ - qe_usb_disable(); - - /* in fact, no needed */ - udc_controller->usb_state = USB_STATE_ATTACHED; - udc_controller->ep0_state = WAIT_FOR_SETUP; - udc_controller->ep0_dir = 0; - - /* stand operation */ - spin_lock_irqsave(&udc_controller->lock, flags); - udc_controller->gadget.speed = USB_SPEED_UNKNOWN; - nuke(&udc_controller->eps[0], -ESHUTDOWN); - list_for_each_entry(loop_ep, &udc_controller->gadget.ep_list, - ep.ep_list) - nuke(loop_ep, -ESHUTDOWN); - spin_unlock_irqrestore(&udc_controller->lock, flags); - - /* report disconnect; the controller is already quiesced */ - driver->disconnect(&udc_controller->gadget); - - /* unbind gadget and unhook driver. */ - driver->unbind(&udc_controller->gadget); - udc_controller->gadget.dev.driver = NULL; - udc_controller->driver = NULL; - - dev_info(udc_controller->dev, "unregistered gadget driver '%s'\r\n", - driver->driver.name); - return 0; -} - -/* udc structure's alloc and setup, include ep-param alloc */ -static struct qe_udc __devinit *qe_udc_config(struct platform_device *ofdev) -{ - struct qe_udc *udc; - struct device_node *np = ofdev->dev.of_node; - unsigned int tmp_addr = 0; - struct usb_device_para __iomem *usbpram; - unsigned int i; - u64 size; - u32 offset; - - udc = kzalloc(sizeof(*udc), GFP_KERNEL); - if (udc == NULL) { - dev_err(&ofdev->dev, "malloc udc failed\n"); - goto cleanup; - } - - udc->dev = &ofdev->dev; - - /* get default address of usb parameter in MURAM from device tree */ - offset = *of_get_address(np, 1, &size, NULL); - udc->usb_param = cpm_muram_addr(offset); - memset_io(udc->usb_param, 0, size); - - usbpram = udc->usb_param; - out_be16(&usbpram->frame_n, 0); - out_be32(&usbpram->rstate, 0); - - tmp_addr = cpm_muram_alloc((USB_MAX_ENDPOINTS * - sizeof(struct usb_ep_para)), - USB_EP_PARA_ALIGNMENT); - if (IS_ERR_VALUE(tmp_addr)) - goto cleanup; - - for (i = 0; i < USB_MAX_ENDPOINTS; i++) { - out_be16(&usbpram->epptr[i], (u16)tmp_addr); - udc->ep_param[i] = cpm_muram_addr(tmp_addr); - tmp_addr += 32; - } - - memset_io(udc->ep_param[0], 0, - USB_MAX_ENDPOINTS * sizeof(struct usb_ep_para)); - - udc->resume_state = USB_STATE_NOTATTACHED; - udc->usb_state = USB_STATE_POWERED; - udc->ep0_dir = 0; - - spin_lock_init(&udc->lock); - return udc; - -cleanup: - kfree(udc); - return NULL; -} - -/* USB Controller register init */ -static int __devinit qe_udc_reg_init(struct qe_udc *udc) -{ - struct usb_ctlr __iomem *qe_usbregs; - qe_usbregs = udc->usb_regs; - - /* Spec says that we must enable the USB controller to change mode. */ - out_8(&qe_usbregs->usb_usmod, 0x01); - /* Mode changed, now disable it, since muram isn't initialized yet. */ - out_8(&qe_usbregs->usb_usmod, 0x00); - - /* Initialize the rest. */ - out_be16(&qe_usbregs->usb_usbmr, 0); - out_8(&qe_usbregs->usb_uscom, 0); - out_be16(&qe_usbregs->usb_usber, USBER_ALL_CLEAR); - - return 0; -} - -static int __devinit qe_ep_config(struct qe_udc *udc, unsigned char pipe_num) -{ - struct qe_ep *ep = &udc->eps[pipe_num]; - - ep->udc = udc; - strcpy(ep->name, ep_name[pipe_num]); - ep->ep.name = ep_name[pipe_num]; - - ep->ep.ops = &qe_ep_ops; - ep->stopped = 1; - ep->ep.maxpacket = (unsigned short) ~0; - ep->desc = NULL; - ep->dir = 0xff; - ep->epnum = (u8)pipe_num; - ep->sent = 0; - ep->last = 0; - ep->init = 0; - ep->rxframe = NULL; - ep->txframe = NULL; - ep->tx_req = NULL; - ep->state = EP_STATE_IDLE; - ep->has_data = 0; - - /* the queue lists any req for this ep */ - INIT_LIST_HEAD(&ep->queue); - - /* gagdet.ep_list used for ep_autoconfig so no ep0*/ - if (pipe_num != 0) - list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); - - ep->gadget = &udc->gadget; - - return 0; -} - -/*----------------------------------------------------------------------- - * UDC device Driver operation functions * - *----------------------------------------------------------------------*/ -static void qe_udc_release(struct device *dev) -{ - int i = 0; - - complete(udc_controller->done); - cpm_muram_free(cpm_muram_offset(udc_controller->ep_param[0])); - for (i = 0; i < USB_MAX_ENDPOINTS; i++) - udc_controller->ep_param[i] = NULL; - - kfree(udc_controller); - udc_controller = NULL; -} - -/* Driver probe functions */ -static const struct of_device_id qe_udc_match[]; -static int __devinit qe_udc_probe(struct platform_device *ofdev) -{ - const struct of_device_id *match; - struct device_node *np = ofdev->dev.of_node; - struct qe_ep *ep; - unsigned int ret = 0; - unsigned int i; - const void *prop; - - match = of_match_device(qe_udc_match, &ofdev->dev); - if (!match) - return -EINVAL; - - prop = of_get_property(np, "mode", NULL); - if (!prop || strcmp(prop, "peripheral")) - return -ENODEV; - - /* Initialize the udc structure including QH member and other member */ - udc_controller = qe_udc_config(ofdev); - if (!udc_controller) { - dev_err(&ofdev->dev, "failed to initialize\n"); - return -ENOMEM; - } - - udc_controller->soc_type = (unsigned long)match->data; - udc_controller->usb_regs = of_iomap(np, 0); - if (!udc_controller->usb_regs) { - ret = -ENOMEM; - goto err1; - } - - /* initialize usb hw reg except for regs for EP, - * leave usbintr reg untouched*/ - qe_udc_reg_init(udc_controller); - - /* here comes the stand operations for probe - * set the qe_udc->gadget.xxx */ - udc_controller->gadget.ops = &qe_gadget_ops; - - /* gadget.ep0 is a pointer */ - udc_controller->gadget.ep0 = &udc_controller->eps[0].ep; - - INIT_LIST_HEAD(&udc_controller->gadget.ep_list); - - /* modify in register gadget process */ - udc_controller->gadget.speed = USB_SPEED_UNKNOWN; - - /* name: Identifies the controller hardware type. */ - udc_controller->gadget.name = driver_name; - - device_initialize(&udc_controller->gadget.dev); - - dev_set_name(&udc_controller->gadget.dev, "gadget"); - - udc_controller->gadget.dev.release = qe_udc_release; - udc_controller->gadget.dev.parent = &ofdev->dev; - - /* initialize qe_ep struct */ - for (i = 0; i < USB_MAX_ENDPOINTS ; i++) { - /* because the ep type isn't decide here so - * qe_ep_init() should be called in ep_enable() */ - - /* setup the qe_ep struct and link ep.ep.list - * into gadget.ep_list */ - qe_ep_config(udc_controller, (unsigned char)i); - } - - /* ep0 initialization in here */ - ret = qe_ep_init(udc_controller, 0, &qe_ep0_desc); - if (ret) - goto err2; - - /* create a buf for ZLP send, need to remain zeroed */ - udc_controller->nullbuf = kzalloc(256, GFP_KERNEL); - if (udc_controller->nullbuf == NULL) { - dev_err(udc_controller->dev, "cannot alloc nullbuf\n"); - ret = -ENOMEM; - goto err3; - } - - /* buffer for data of get_status request */ - udc_controller->statusbuf = kzalloc(2, GFP_KERNEL); - if (udc_controller->statusbuf == NULL) { - ret = -ENOMEM; - goto err4; - } - - udc_controller->nullp = virt_to_phys((void *)udc_controller->nullbuf); - if (udc_controller->nullp == DMA_ADDR_INVALID) { - udc_controller->nullp = dma_map_single( - udc_controller->gadget.dev.parent, - udc_controller->nullbuf, - 256, - DMA_TO_DEVICE); - udc_controller->nullmap = 1; - } else { - dma_sync_single_for_device(udc_controller->gadget.dev.parent, - udc_controller->nullp, 256, - DMA_TO_DEVICE); - } - - tasklet_init(&udc_controller->rx_tasklet, ep_rx_tasklet, - (unsigned long)udc_controller); - /* request irq and disable DR */ - udc_controller->usb_irq = irq_of_parse_and_map(np, 0); - if (!udc_controller->usb_irq) { - ret = -EINVAL; - goto err_noirq; - } - - ret = request_irq(udc_controller->usb_irq, qe_udc_irq, 0, - driver_name, udc_controller); - if (ret) { - dev_err(udc_controller->dev, "cannot request irq %d err %d \n", - udc_controller->usb_irq, ret); - goto err5; - } - - ret = device_add(&udc_controller->gadget.dev); - if (ret) - goto err6; - - ret = usb_add_gadget_udc(&ofdev->dev, &udc_controller->gadget); - if (ret) - goto err7; - - dev_info(udc_controller->dev, - "%s USB controller initialized as device\n", - (udc_controller->soc_type == PORT_QE) ? "QE" : "CPM"); - return 0; - -err7: - device_unregister(&udc_controller->gadget.dev); -err6: - free_irq(udc_controller->usb_irq, udc_controller); -err5: - irq_dispose_mapping(udc_controller->usb_irq); -err_noirq: - if (udc_controller->nullmap) { - dma_unmap_single(udc_controller->gadget.dev.parent, - udc_controller->nullp, 256, - DMA_TO_DEVICE); - udc_controller->nullp = DMA_ADDR_INVALID; - } else { - dma_sync_single_for_cpu(udc_controller->gadget.dev.parent, - udc_controller->nullp, 256, - DMA_TO_DEVICE); - } - kfree(udc_controller->statusbuf); -err4: - kfree(udc_controller->nullbuf); -err3: - ep = &udc_controller->eps[0]; - cpm_muram_free(cpm_muram_offset(ep->rxbase)); - kfree(ep->rxframe); - kfree(ep->rxbuffer); - kfree(ep->txframe); -err2: - iounmap(udc_controller->usb_regs); -err1: - kfree(udc_controller); - udc_controller = NULL; - return ret; -} - -#ifdef CONFIG_PM -static int qe_udc_suspend(struct platform_device *dev, pm_message_t state) -{ - return -ENOTSUPP; -} - -static int qe_udc_resume(struct platform_device *dev) -{ - return -ENOTSUPP; -} -#endif - -static int __devexit qe_udc_remove(struct platform_device *ofdev) -{ - struct qe_ep *ep; - unsigned int size; - - DECLARE_COMPLETION(done); - - if (!udc_controller) - return -ENODEV; - - usb_del_gadget_udc(&udc_controller->gadget); - - udc_controller->done = &done; - tasklet_disable(&udc_controller->rx_tasklet); - - if (udc_controller->nullmap) { - dma_unmap_single(udc_controller->gadget.dev.parent, - udc_controller->nullp, 256, - DMA_TO_DEVICE); - udc_controller->nullp = DMA_ADDR_INVALID; - } else { - dma_sync_single_for_cpu(udc_controller->gadget.dev.parent, - udc_controller->nullp, 256, - DMA_TO_DEVICE); - } - kfree(udc_controller->statusbuf); - kfree(udc_controller->nullbuf); - - ep = &udc_controller->eps[0]; - cpm_muram_free(cpm_muram_offset(ep->rxbase)); - size = (ep->ep.maxpacket + USB_CRC_SIZE + 2) * (USB_BDRING_LEN + 1); - - kfree(ep->rxframe); - if (ep->rxbufmap) { - dma_unmap_single(udc_controller->gadget.dev.parent, - ep->rxbuf_d, size, - DMA_FROM_DEVICE); - ep->rxbuf_d = DMA_ADDR_INVALID; - } else { - dma_sync_single_for_cpu(udc_controller->gadget.dev.parent, - ep->rxbuf_d, size, - DMA_FROM_DEVICE); - } - - kfree(ep->rxbuffer); - kfree(ep->txframe); - - free_irq(udc_controller->usb_irq, udc_controller); - irq_dispose_mapping(udc_controller->usb_irq); - - tasklet_kill(&udc_controller->rx_tasklet); - - iounmap(udc_controller->usb_regs); - - device_unregister(&udc_controller->gadget.dev); - /* wait for release() of gadget.dev to free udc */ - wait_for_completion(&done); - - return 0; -} - -/*-------------------------------------------------------------------------*/ -static const struct of_device_id qe_udc_match[] __devinitconst = { - { - .compatible = "fsl,mpc8323-qe-usb", - .data = (void *)PORT_QE, - }, - { - .compatible = "fsl,mpc8360-qe-usb", - .data = (void *)PORT_QE, - }, - { - .compatible = "fsl,mpc8272-cpm-usb", - .data = (void *)PORT_CPM, - }, - {}, -}; - -MODULE_DEVICE_TABLE(of, qe_udc_match); - -static struct platform_driver udc_driver = { - .driver = { - .name = (char *)driver_name, - .owner = THIS_MODULE, - .of_match_table = qe_udc_match, - }, - .probe = qe_udc_probe, - .remove = __devexit_p(qe_udc_remove), -#ifdef CONFIG_PM - .suspend = qe_udc_suspend, - .resume = qe_udc_resume, -#endif -}; - -module_platform_driver(udc_driver); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_LICENSE("GPL"); - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/fsl_qe_udc.h b/ANDROID_3.4.5/drivers/usb/gadget/fsl_qe_udc.h deleted file mode 100644 index 1da5fb03..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/fsl_qe_udc.h +++ /dev/null @@ -1,422 +0,0 @@ -/* - * drivers/usb/gadget/qe_udc.h - * - * Copyright (C) 2006-2008 Freescale Semiconductor, Inc. All rights reserved. - * - * Xiaobo Xie - * Li Yang - * - * Description: - * Freescale USB device/endpoint management registers - * - * 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. - */ - -#ifndef __FSL_QE_UDC_H -#define __FSL_QE_UDC_H - -/* SoC type */ -#define PORT_CPM 0 -#define PORT_QE 1 - -#define USB_MAX_ENDPOINTS 4 -#define USB_MAX_PIPES USB_MAX_ENDPOINTS -#define USB_EP0_MAX_SIZE 64 -#define USB_MAX_CTRL_PAYLOAD 0x4000 -#define USB_BDRING_LEN 16 -#define USB_BDRING_LEN_RX 256 -#define USB_BDRING_LEN_TX 16 -#define MIN_EMPTY_BDS 128 -#define MAX_DATA_BDS 8 -#define USB_CRC_SIZE 2 -#define USB_DIR_BOTH 0x88 -#define R_BUF_MAXSIZE 0x800 -#define USB_EP_PARA_ALIGNMENT 32 - -/* USB Mode Register bit define */ -#define USB_MODE_EN 0x01 -#define USB_MODE_HOST 0x02 -#define USB_MODE_TEST 0x04 -#define USB_MODE_SFTE 0x08 -#define USB_MODE_RESUME 0x40 -#define USB_MODE_LSS 0x80 - -/* USB Slave Address Register Mask */ -#define USB_SLVADDR_MASK 0x7F - -/* USB Endpoint register define */ -#define USB_EPNUM_MASK 0xF000 -#define USB_EPNUM_SHIFT 12 - -#define USB_TRANS_MODE_SHIFT 8 -#define USB_TRANS_CTR 0x0000 -#define USB_TRANS_INT 0x0100 -#define USB_TRANS_BULK 0x0200 -#define USB_TRANS_ISO 0x0300 - -#define USB_EP_MF 0x0020 -#define USB_EP_RTE 0x0010 - -#define USB_THS_SHIFT 2 -#define USB_THS_MASK 0x000c -#define USB_THS_NORMAL 0x0 -#define USB_THS_IGNORE_IN 0x0004 -#define USB_THS_NACK 0x0008 -#define USB_THS_STALL 0x000c - -#define USB_RHS_SHIFT 0 -#define USB_RHS_MASK 0x0003 -#define USB_RHS_NORMAL 0x0 -#define USB_RHS_IGNORE_OUT 0x0001 -#define USB_RHS_NACK 0x0002 -#define USB_RHS_STALL 0x0003 - -#define USB_RTHS_MASK 0x000f - -/* USB Command Register define */ -#define USB_CMD_STR_FIFO 0x80 -#define USB_CMD_FLUSH_FIFO 0x40 -#define USB_CMD_ISFT 0x20 -#define USB_CMD_DSFT 0x10 -#define USB_CMD_EP_MASK 0x03 - -/* USB Event and Mask Register define */ -#define USB_E_MSF_MASK 0x0800 -#define USB_E_SFT_MASK 0x0400 -#define USB_E_RESET_MASK 0x0200 -#define USB_E_IDLE_MASK 0x0100 -#define USB_E_TXE4_MASK 0x0080 -#define USB_E_TXE3_MASK 0x0040 -#define USB_E_TXE2_MASK 0x0020 -#define USB_E_TXE1_MASK 0x0010 -#define USB_E_SOF_MASK 0x0008 -#define USB_E_BSY_MASK 0x0004 -#define USB_E_TXB_MASK 0x0002 -#define USB_E_RXB_MASK 0x0001 -#define USBER_ALL_CLEAR 0x0fff - -#define USB_E_DEFAULT_DEVICE (USB_E_RESET_MASK | USB_E_TXE4_MASK | \ - USB_E_TXE3_MASK | USB_E_TXE2_MASK | \ - USB_E_TXE1_MASK | USB_E_BSY_MASK | \ - USB_E_TXB_MASK | USB_E_RXB_MASK) - -#define USB_E_TXE_MASK (USB_E_TXE4_MASK | USB_E_TXE3_MASK|\ - USB_E_TXE2_MASK | USB_E_TXE1_MASK) -/* USB Status Register define */ -#define USB_IDLE_STATUS_MASK 0x01 - -/* USB Start of Frame Timer */ -#define USB_USSFT_MASK 0x3FFF - -/* USB Frame Number Register */ -#define USB_USFRN_MASK 0xFFFF - -struct usb_device_para{ - u16 epptr[4]; - u32 rstate; - u32 rptr; - u16 frame_n; - u16 rbcnt; - u32 rtemp; - u32 rxusb_data; - u16 rxuptr; - u8 reso[2]; - u32 softbl; - u8 sofucrctemp; -}; - -struct usb_ep_para{ - u16 rbase; - u16 tbase; - u8 rbmr; - u8 tbmr; - u16 mrblr; - u16 rbptr; - u16 tbptr; - u32 tstate; - u32 tptr; - u16 tcrc; - u16 tbcnt; - u32 ttemp; - u16 txusbu_ptr; - u8 reserve[2]; -}; - -#define USB_BUSMODE_GBL 0x20 -#define USB_BUSMODE_BO_MASK 0x18 -#define USB_BUSMODE_BO_SHIFT 0x3 -#define USB_BUSMODE_BE 0x2 -#define USB_BUSMODE_CETM 0x04 -#define USB_BUSMODE_DTB 0x02 - -/* Endpoint basic handle */ -#define ep_index(EP) ((EP)->desc->bEndpointAddress & 0xF) -#define ep_maxpacket(EP) ((EP)->ep.maxpacket) -#define ep_is_in(EP) ((ep_index(EP) == 0) ? (EP->udc->ep0_dir == \ - USB_DIR_IN) : ((EP)->desc->bEndpointAddress \ - & USB_DIR_IN) == USB_DIR_IN) - -/* ep0 transfer state */ -#define WAIT_FOR_SETUP 0 -#define DATA_STATE_XMIT 1 -#define DATA_STATE_NEED_ZLP 2 -#define WAIT_FOR_OUT_STATUS 3 -#define DATA_STATE_RECV 4 - -/* ep tramsfer mode */ -#define USBP_TM_CTL 0 -#define USBP_TM_ISO 1 -#define USBP_TM_BULK 2 -#define USBP_TM_INT 3 - -/*----------------------------------------------------------------------------- - USB RX And TX DATA Frame - -----------------------------------------------------------------------------*/ -struct qe_frame{ - u8 *data; - u32 len; - u32 status; - u32 info; - - void *privdata; - struct list_head node; -}; - -/* Frame structure, info field. */ -#define PID_DATA0 0x80000000 /* Data toggle zero */ -#define PID_DATA1 0x40000000 /* Data toggle one */ -#define PID_SETUP 0x20000000 /* setup bit */ -#define SETUP_STATUS 0x10000000 /* setup status bit */ -#define SETADDR_STATUS 0x08000000 /* setupup address status bit */ -#define NO_REQ 0x04000000 /* Frame without request */ -#define HOST_DATA 0x02000000 /* Host data frame */ -#define FIRST_PACKET_IN_FRAME 0x01000000 /* first packet in the frame */ -#define TOKEN_FRAME 0x00800000 /* Host token frame */ -#define ZLP 0x00400000 /* Zero length packet */ -#define IN_TOKEN_FRAME 0x00200000 /* In token package */ -#define OUT_TOKEN_FRAME 0x00100000 /* Out token package */ -#define SETUP_TOKEN_FRAME 0x00080000 /* Setup token package */ -#define STALL_FRAME 0x00040000 /* Stall handshake */ -#define NACK_FRAME 0x00020000 /* Nack handshake */ -#define NO_PID 0x00010000 /* No send PID */ -#define NO_CRC 0x00008000 /* No send CRC */ -#define HOST_COMMAND 0x00004000 /* Host command frame */ - -/* Frame status field */ -/* Receive side */ -#define FRAME_OK 0x00000000 /* Frame transmitted or received OK */ -#define FRAME_ERROR 0x80000000 /* Error occurred on frame */ -#define START_FRAME_LOST 0x40000000 /* START_FRAME_LOST */ -#define END_FRAME_LOST 0x20000000 /* END_FRAME_LOST */ -#define RX_ER_NONOCT 0x10000000 /* Rx Non Octet Aligned Packet */ -#define RX_ER_BITSTUFF 0x08000000 /* Frame Aborted --Received packet - with bit stuff error */ -#define RX_ER_CRC 0x04000000 /* Received packet with CRC error */ -#define RX_ER_OVERUN 0x02000000 /* Over-run occurred on reception */ -#define RX_ER_PID 0x01000000 /* Wrong PID received */ -/* Tranmit side */ -#define TX_ER_NAK 0x00800000 /* Received NAK handshake */ -#define TX_ER_STALL 0x00400000 /* Received STALL handshake */ -#define TX_ER_TIMEOUT 0x00200000 /* Transmit time out */ -#define TX_ER_UNDERUN 0x00100000 /* Transmit underrun */ -#define FRAME_INPROGRESS 0x00080000 /* Frame is being transmitted */ -#define ER_DATA_UNDERUN 0x00040000 /* Frame is shorter then expected */ -#define ER_DATA_OVERUN 0x00020000 /* Frame is longer then expected */ - -/* QE USB frame operation functions */ -#define frame_get_length(frm) (frm->len) -#define frame_set_length(frm, leng) (frm->len = leng) -#define frame_get_data(frm) (frm->data) -#define frame_set_data(frm, dat) (frm->data = dat) -#define frame_get_info(frm) (frm->info) -#define frame_set_info(frm, inf) (frm->info = inf) -#define frame_get_status(frm) (frm->status) -#define frame_set_status(frm, stat) (frm->status = stat) -#define frame_get_privdata(frm) (frm->privdata) -#define frame_set_privdata(frm, dat) (frm->privdata = dat) - -static inline void qe_frame_clean(struct qe_frame *frm) -{ - frame_set_data(frm, NULL); - frame_set_length(frm, 0); - frame_set_status(frm, FRAME_OK); - frame_set_info(frm, 0); - frame_set_privdata(frm, NULL); -} - -static inline void qe_frame_init(struct qe_frame *frm) -{ - qe_frame_clean(frm); - INIT_LIST_HEAD(&(frm->node)); -} - -struct qe_req { - struct usb_request req; - struct list_head queue; - /* ep_queue() func will add - a request->queue into a udc_ep->queue 'd tail */ - struct qe_ep *ep; - unsigned mapped:1; -}; - -struct qe_ep { - struct usb_ep ep; - struct list_head queue; - struct qe_udc *udc; - const struct usb_endpoint_descriptor *desc; - struct usb_gadget *gadget; - - u8 state; - - struct qe_bd __iomem *rxbase; - struct qe_bd __iomem *n_rxbd; - struct qe_bd __iomem *e_rxbd; - - struct qe_bd __iomem *txbase; - struct qe_bd __iomem *n_txbd; - struct qe_bd __iomem *c_txbd; - - struct qe_frame *rxframe; - u8 *rxbuffer; - dma_addr_t rxbuf_d; - u8 rxbufmap; - unsigned char localnack; - int has_data; - - struct qe_frame *txframe; - struct qe_req *tx_req; - int sent; /*data already sent */ - int last; /*data sent in the last time*/ - - u8 dir; - u8 epnum; - u8 tm; /* transfer mode */ - u8 data01; - u8 init; - - u8 already_seen; - u8 enable_tasklet; - u8 setup_stage; - u32 last_io; /* timestamp */ - - char name[14]; - - unsigned double_buf:1; - unsigned stopped:1; - unsigned fnf:1; - unsigned has_dma:1; - - u8 ackwait; - u8 dma_channel; - u16 dma_counter; - int lch; - - struct timer_list timer; -}; - -struct qe_udc { - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - struct device *dev; - struct qe_ep eps[USB_MAX_ENDPOINTS]; - struct usb_ctrlrequest local_setup_buff; - spinlock_t lock; /* lock for set/config qe_udc */ - unsigned long soc_type; /* QE or CPM soc */ - - struct qe_req *status_req; /* ep0 status request */ - - /* USB and EP Parameter Block pointer */ - struct usb_device_para __iomem *usb_param; - struct usb_ep_para __iomem *ep_param[4]; - - u32 max_pipes; /* Device max pipes */ - u32 max_use_endpts; /* Max endpointes to be used */ - u32 bus_reset; /* Device is bus reseting */ - u32 resume_state; /* USB state to resume*/ - u32 usb_state; /* USB current state */ - u32 usb_next_state; /* USB next state */ - u32 ep0_state; /* Enpoint zero state */ - u32 ep0_dir; /* Enpoint zero direction: can be - USB_DIR_IN or USB_DIR_OUT*/ - u32 usb_sof_count; /* SOF count */ - u32 errors; /* USB ERRORs count */ - - u8 *tmpbuf; - u32 c_start; - u32 c_end; - - u8 *nullbuf; - u8 *statusbuf; - dma_addr_t nullp; - u8 nullmap; - u8 device_address; /* Device USB address */ - - unsigned int usb_clock; - unsigned int usb_irq; - struct usb_ctlr __iomem *usb_regs; - - struct tasklet_struct rx_tasklet; - - struct completion *done; /* to make sure release() is done */ -}; - -#define EP_STATE_IDLE 0 -#define EP_STATE_NACK 1 -#define EP_STATE_STALL 2 - -/* - * transmit BD's status - */ -#define T_R 0x80000000 /* ready bit */ -#define T_W 0x20000000 /* wrap bit */ -#define T_I 0x10000000 /* interrupt on completion */ -#define T_L 0x08000000 /* last */ -#define T_TC 0x04000000 /* transmit CRC */ -#define T_CNF 0x02000000 /* wait for transmit confirm */ -#define T_LSP 0x01000000 /* Low-speed transaction */ -#define T_PID 0x00c00000 /* packet id */ -#define T_NAK 0x00100000 /* No ack. */ -#define T_STAL 0x00080000 /* Stall received */ -#define T_TO 0x00040000 /* time out */ -#define T_UN 0x00020000 /* underrun */ - -#define DEVICE_T_ERROR (T_UN | T_TO) -#define HOST_T_ERROR (T_UN | T_TO | T_NAK | T_STAL) -#define DEVICE_T_BD_MASK DEVICE_T_ERROR -#define HOST_T_BD_MASK HOST_T_ERROR - -#define T_PID_SHIFT 6 -#define T_PID_DATA0 0x00800000 /* Data 0 toggle */ -#define T_PID_DATA1 0x00c00000 /* Data 1 toggle */ - -/* - * receive BD's status - */ -#define R_E 0x80000000 /* buffer empty */ -#define R_W 0x20000000 /* wrap bit */ -#define R_I 0x10000000 /* interrupt on reception */ -#define R_L 0x08000000 /* last */ -#define R_F 0x04000000 /* first */ -#define R_PID 0x00c00000 /* packet id */ -#define R_NO 0x00100000 /* Rx Non Octet Aligned Packet */ -#define R_AB 0x00080000 /* Frame Aborted */ -#define R_CR 0x00040000 /* CRC Error */ -#define R_OV 0x00020000 /* Overrun */ - -#define R_ERROR (R_NO | R_AB | R_CR | R_OV) -#define R_BD_MASK R_ERROR - -#define R_PID_DATA0 0x00000000 -#define R_PID_DATA1 0x00400000 -#define R_PID_SETUP 0x00800000 - -#define CPM_USB_STOP_TX 0x2e600000 -#define CPM_USB_RESTART_TX 0x2e600000 -#define CPM_USB_STOP_TX_OPCODE 0x0a -#define CPM_USB_RESTART_TX_OPCODE 0x0b -#define CPM_USB_EP_SHIFT 5 - -#endif /* __FSL_QE_UDC_H */ diff --git a/ANDROID_3.4.5/drivers/usb/gadget/fsl_udc_core.c b/ANDROID_3.4.5/drivers/usb/gadget/fsl_udc_core.c deleted file mode 100644 index 188a89f9..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/fsl_udc_core.c +++ /dev/null @@ -1,2778 +0,0 @@ -/* - * Copyright (C) 2004-2007,2011 Freescale Semiconductor, Inc. - * All rights reserved. - * - * Author: Li Yang - * Jiang Bo - * - * Description: - * Freescale high-speed USB SOC DR module device controller driver. - * This can be found on MPC8349E/MPC8313E/MPC5121E cpus. - * The driver is previously named as mpc_udc. Based on bare board - * code from Dave Liu and Shlomi Gridish. - * - * 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. - */ - -#undef VERBOSE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "fsl_usb2_udc.h" - -#define DRIVER_DESC "Freescale High-Speed USB SOC Device Controller driver" -#define DRIVER_AUTHOR "Li Yang/Jiang Bo" -#define DRIVER_VERSION "Apr 20, 2007" - -#define DMA_ADDR_INVALID (~(dma_addr_t)0) - -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; - -static const struct usb_endpoint_descriptor -fsl_ep0_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 0, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, - .wMaxPacketSize = USB_MAX_CTRL_PAYLOAD, -}; - -static void fsl_ep_fifo_flush(struct usb_ep *_ep); - -#ifdef CONFIG_PPC32 -/* - * On some SoCs, the USB controller registers can be big or little endian, - * depending on the version of the chip. In order to be able to run the - * same kernel binary on 2 different versions of an SoC, the BE/LE decision - * must be made at run time. _fsl_readl and fsl_writel are pointers to the - * BE or LE readl() and writel() functions, and fsl_readl() and fsl_writel() - * call through those pointers. Platform code for SoCs that have BE USB - * registers should set pdata->big_endian_mmio flag. - * - * This also applies to controller-to-cpu accessors for the USB descriptors, - * since their endianness is also SoC dependant. Platform code for SoCs that - * have BE USB descriptors should set pdata->big_endian_desc flag. - */ -static u32 _fsl_readl_be(const unsigned __iomem *p) -{ - return in_be32(p); -} - -static u32 _fsl_readl_le(const unsigned __iomem *p) -{ - return in_le32(p); -} - -static void _fsl_writel_be(u32 v, unsigned __iomem *p) -{ - out_be32(p, v); -} - -static void _fsl_writel_le(u32 v, unsigned __iomem *p) -{ - out_le32(p, v); -} - -static u32 (*_fsl_readl)(const unsigned __iomem *p); -static void (*_fsl_writel)(u32 v, unsigned __iomem *p); - -#define fsl_readl(p) (*_fsl_readl)((p)) -#define fsl_writel(v, p) (*_fsl_writel)((v), (p)) - -static inline void fsl_set_accessors(struct fsl_usb2_platform_data *pdata) -{ - if (pdata->big_endian_mmio) { - _fsl_readl = _fsl_readl_be; - _fsl_writel = _fsl_writel_be; - } else { - _fsl_readl = _fsl_readl_le; - _fsl_writel = _fsl_writel_le; - } -} - -static inline u32 cpu_to_hc32(const u32 x) -{ - return udc_controller->pdata->big_endian_desc - ? (__force u32)cpu_to_be32(x) - : (__force u32)cpu_to_le32(x); -} - -static inline u32 hc32_to_cpu(const u32 x) -{ - return udc_controller->pdata->big_endian_desc - ? be32_to_cpu((__force __be32)x) - : le32_to_cpu((__force __le32)x); -} -#else /* !CONFIG_PPC32 */ -static inline void fsl_set_accessors(struct fsl_usb2_platform_data *pdata) {} - -#define fsl_readl(addr) readl(addr) -#define fsl_writel(val32, addr) writel(val32, addr) -#define cpu_to_hc32(x) cpu_to_le32(x) -#define hc32_to_cpu(x) le32_to_cpu(x) -#endif /* CONFIG_PPC32 */ - -/******************************************************************** - * Internal Used Function -********************************************************************/ -/*----------------------------------------------------------------- - * done() - retire a request; caller blocked irqs - * @status : request status to be set, only works when - * request is still in progress. - *--------------------------------------------------------------*/ -static void done(struct fsl_ep *ep, struct fsl_req *req, int status) -{ - struct fsl_udc *udc = NULL; - unsigned char stopped = ep->stopped; - struct ep_td_struct *curr_td, *next_td; - int j; - - udc = (struct fsl_udc *)ep->udc; - /* Removed the req from fsl_ep->queue */ - list_del_init(&req->queue); - - /* req.status should be set as -EINPROGRESS in ep_queue() */ - if (req->req.status == -EINPROGRESS) - req->req.status = status; - else - status = req->req.status; - - /* Free dtd for the request */ - next_td = req->head; - for (j = 0; j < req->dtd_count; j++) { - curr_td = next_td; - if (j != req->dtd_count - 1) { - next_td = curr_td->next_td_virt; - } - dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma); - } - - if (req->mapped) { - dma_unmap_single(ep->udc->gadget.dev.parent, - req->req.dma, req->req.length, - ep_is_in(ep) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - req->req.dma = DMA_ADDR_INVALID; - req->mapped = 0; - } else - dma_sync_single_for_cpu(ep->udc->gadget.dev.parent, - req->req.dma, req->req.length, - ep_is_in(ep) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - - if (status && (status != -ESHUTDOWN)) - VDBG("complete %s req %p stat %d len %u/%u", - ep->ep.name, &req->req, status, - req->req.actual, req->req.length); - - ep->stopped = 1; - - spin_unlock(&ep->udc->lock); - /* complete() is from gadget layer, - * eg fsg->bulk_in_complete() */ - if (req->req.complete) - req->req.complete(&ep->ep, &req->req); - - spin_lock(&ep->udc->lock); - ep->stopped = stopped; -} - -/*----------------------------------------------------------------- - * nuke(): delete all requests related to this ep - * called with spinlock held - *--------------------------------------------------------------*/ -static void nuke(struct fsl_ep *ep, int status) -{ - ep->stopped = 1; - - /* Flush fifo */ - fsl_ep_fifo_flush(&ep->ep); - - /* Whether this eq has request linked */ - while (!list_empty(&ep->queue)) { - struct fsl_req *req = NULL; - - req = list_entry(ep->queue.next, struct fsl_req, queue); - done(ep, req, status); - } -} - -/*------------------------------------------------------------------ - Internal Hardware related function - ------------------------------------------------------------------*/ - -static int dr_controller_setup(struct fsl_udc *udc) -{ - unsigned int tmp, portctrl, ep_num; - unsigned int max_no_of_ep; -#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; - fsl_writel(tmp, &dr_regs->usbcmd); - - tmp = fsl_readl(&dr_regs->usbcmd); - tmp |= USB_CMD_CTRL_RESET; - fsl_writel(tmp, &dr_regs->usbcmd); - - /* Wait for reset to complete */ - timeout = jiffies + FSL_UDC_RESET_TIMEOUT; - while (fsl_readl(&dr_regs->usbcmd) & USB_CMD_CTRL_RESET) { - if (time_after(jiffies, timeout)) { - ERR("udc reset timeout!\n"); - return -ETIMEDOUT; - } - cpu_relax(); - } - - /* Set the controller as device mode */ - tmp = fsl_readl(&dr_regs->usbmode); - tmp &= ~USB_MODE_CTRL_MODE_MASK; /* clear mode bits */ - tmp |= USB_MODE_CTRL_MODE_DEVICE; - /* Disable Setup Lockout */ - tmp |= USB_MODE_SETUP_LOCK_OFF; - if (udc->pdata->es) - tmp |= USB_MODE_ES; - fsl_writel(tmp, &dr_regs->usbmode); - - /* Clear the setup status */ - fsl_writel(0, &dr_regs->usbsts); - - tmp = udc->ep_qh_dma; - tmp &= USB_EP_LIST_ADDRESS_MASK; - fsl_writel(tmp, &dr_regs->endpointlistaddr); - - VDBG("vir[qh_base] is %p phy[qh_base] is 0x%8x reg is 0x%8x", - udc->ep_qh, (int)tmp, - fsl_readl(&dr_regs->endpointlistaddr)); - - max_no_of_ep = (0x0000001F & fsl_readl(&dr_regs->dccparams)); - for (ep_num = 1; ep_num < max_no_of_ep; ep_num++) { - tmp = fsl_readl(&dr_regs->endptctrl[ep_num]); - tmp &= ~(EPCTRL_TX_TYPE | EPCTRL_RX_TYPE); - tmp |= (EPCTRL_EP_TYPE_BULK << EPCTRL_TX_EP_TYPE_SHIFT) - | (EPCTRL_EP_TYPE_BULK << EPCTRL_RX_EP_TYPE_SHIFT); - fsl_writel(tmp, &dr_regs->endptctrl[ep_num]); - } - /* Config control enable i/o output, cpu endian register */ -#ifndef CONFIG_ARCH_MXC - if (udc->pdata->have_sysif_regs) { - 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 - * wholly rely on hardware to deal with cache coherent. */ - - if (udc->pdata->have_sysif_regs) { - /* Setup Snooping for all the 4GB space */ - tmp = SNOOP_SIZE_2GB; /* starts from 0x0, size 2G */ - __raw_writel(tmp, &usb_sys_regs->snoop1); - tmp |= 0x80000000; /* starts from 0x8000000, size 2G */ - __raw_writel(tmp, &usb_sys_regs->snoop2); - } -#endif - - return 0; -} - -/* Enable DR irq and set controller to run state */ -static void dr_controller_run(struct fsl_udc *udc) -{ - u32 temp; - - /* Enable DR irq reg */ - temp = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN - | USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN - | USB_INTR_DEVICE_SUSPEND | USB_INTR_SYS_ERR_EN; - - fsl_writel(temp, &dr_regs->usbintr); - - /* Clear stopped bit */ - udc->stopped = 0; - - /* Set the controller as device mode */ - temp = fsl_readl(&dr_regs->usbmode); - temp |= USB_MODE_CTRL_MODE_DEVICE; - fsl_writel(temp, &dr_regs->usbmode); - - /* Set controller to Run */ - temp = fsl_readl(&dr_regs->usbcmd); - temp |= USB_CMD_RUN_STOP; - fsl_writel(temp, &dr_regs->usbcmd); -} - -static void dr_controller_stop(struct fsl_udc *udc) -{ - unsigned int tmp; - - pr_debug("%s\n", __func__); - - /* if we're in OTG mode, and the Host is currently using the port, - * stop now and don't rip the controller out from under the - * ehci driver - */ - if (udc->gadget.is_otg) { - if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) { - pr_debug("udc: Leaving early\n"); - return; - } - } - - /* disable all INTR */ - fsl_writel(0, &dr_regs->usbintr); - - /* Set stopped bit for isr */ - udc->stopped = 1; - - /* disable IO output */ -/* usb_sys_regs->control = 0; */ - - /* set controller to Stop */ - tmp = fsl_readl(&dr_regs->usbcmd); - tmp &= ~USB_CMD_RUN_STOP; - fsl_writel(tmp, &dr_regs->usbcmd); -} - -static void dr_ep_setup(unsigned char ep_num, unsigned char dir, - unsigned char ep_type) -{ - unsigned int tmp_epctrl = 0; - - tmp_epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); - if (dir) { - if (ep_num) - tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST; - tmp_epctrl |= EPCTRL_TX_ENABLE; - tmp_epctrl &= ~EPCTRL_TX_TYPE; - tmp_epctrl |= ((unsigned int)(ep_type) - << EPCTRL_TX_EP_TYPE_SHIFT); - } else { - if (ep_num) - tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST; - tmp_epctrl |= EPCTRL_RX_ENABLE; - tmp_epctrl &= ~EPCTRL_RX_TYPE; - tmp_epctrl |= ((unsigned int)(ep_type) - << EPCTRL_RX_EP_TYPE_SHIFT); - } - - fsl_writel(tmp_epctrl, &dr_regs->endptctrl[ep_num]); -} - -static void -dr_ep_change_stall(unsigned char ep_num, unsigned char dir, int value) -{ - u32 tmp_epctrl = 0; - - tmp_epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); - - if (value) { - /* set the stall bit */ - if (dir) - tmp_epctrl |= EPCTRL_TX_EP_STALL; - else - tmp_epctrl |= EPCTRL_RX_EP_STALL; - } else { - /* clear the stall bit and reset data toggle */ - if (dir) { - tmp_epctrl &= ~EPCTRL_TX_EP_STALL; - tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST; - } else { - tmp_epctrl &= ~EPCTRL_RX_EP_STALL; - tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST; - } - } - fsl_writel(tmp_epctrl, &dr_regs->endptctrl[ep_num]); -} - -/* Get stall status of a specific ep - Return: 0: not stalled; 1:stalled */ -static int dr_ep_get_stall(unsigned char ep_num, unsigned char dir) -{ - u32 epctrl; - - epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); - if (dir) - return (epctrl & EPCTRL_TX_EP_STALL) ? 1 : 0; - else - return (epctrl & EPCTRL_RX_EP_STALL) ? 1 : 0; -} - -/******************************************************************** - Internal Structure Build up functions -********************************************************************/ - -/*------------------------------------------------------------------ -* struct_ep_qh_setup(): set the Endpoint Capabilites field of QH - * @zlt: Zero Length Termination Select (1: disable; 0: enable) - * @mult: Mult field - ------------------------------------------------------------------*/ -static void struct_ep_qh_setup(struct fsl_udc *udc, unsigned char ep_num, - unsigned char dir, unsigned char ep_type, - unsigned int max_pkt_len, - unsigned int zlt, unsigned char mult) -{ - struct ep_queue_head *p_QH = &udc->ep_qh[2 * ep_num + dir]; - unsigned int tmp = 0; - - /* set the Endpoint Capabilites in QH */ - switch (ep_type) { - case USB_ENDPOINT_XFER_CONTROL: - /* Interrupt On Setup (IOS). for control ep */ - tmp = (max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS) - | EP_QUEUE_HEAD_IOS; - break; - case USB_ENDPOINT_XFER_ISOC: - tmp = (max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS) - | (mult << EP_QUEUE_HEAD_MULT_POS); - break; - case USB_ENDPOINT_XFER_BULK: - case USB_ENDPOINT_XFER_INT: - tmp = max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS; - break; - default: - VDBG("error ep type is %d", ep_type); - return; - } - if (zlt) - tmp |= EP_QUEUE_HEAD_ZLT_SEL; - - p_QH->max_pkt_length = cpu_to_hc32(tmp); - p_QH->next_dtd_ptr = 1; - p_QH->size_ioc_int_sts = 0; -} - -/* Setup qh structure and ep register for ep0. */ -static void ep0_setup(struct fsl_udc *udc) -{ - /* the intialization of an ep includes: fields in QH, Regs, - * fsl_ep struct */ - struct_ep_qh_setup(udc, 0, USB_RECV, USB_ENDPOINT_XFER_CONTROL, - USB_MAX_CTRL_PAYLOAD, 0, 0); - struct_ep_qh_setup(udc, 0, USB_SEND, USB_ENDPOINT_XFER_CONTROL, - USB_MAX_CTRL_PAYLOAD, 0, 0); - dr_ep_setup(0, USB_RECV, USB_ENDPOINT_XFER_CONTROL); - dr_ep_setup(0, USB_SEND, USB_ENDPOINT_XFER_CONTROL); - - return; - -} - -/*********************************************************************** - Endpoint Management Functions -***********************************************************************/ - -/*------------------------------------------------------------------------- - * when configurations are set, or when interface settings change - * for example the do_set_interface() in gadget layer, - * the driver will enable or disable the relevant endpoints - * ep0 doesn't use this routine. It is always enabled. --------------------------------------------------------------------------*/ -static int fsl_ep_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct fsl_udc *udc = NULL; - struct fsl_ep *ep = NULL; - unsigned short max = 0; - unsigned char mult = 0, zlt; - int retval = -EINVAL; - unsigned long flags = 0; - - ep = container_of(_ep, struct fsl_ep, ep); - - /* catch various bogus parameters */ - if (!_ep || !desc || ep->desc - || (desc->bDescriptorType != USB_DT_ENDPOINT)) - return -EINVAL; - - udc = ep->udc; - - if (!udc->driver || (udc->gadget.speed == USB_SPEED_UNKNOWN)) - return -ESHUTDOWN; - - max = usb_endpoint_maxp(desc); - - /* Disable automatic zlp generation. Driver is responsible to indicate - * explicitly through req->req.zero. This is needed to enable multi-td - * request. */ - zlt = 1; - - /* Assume the max packet size from gadget is always correct */ - switch (desc->bmAttributes & 0x03) { - case USB_ENDPOINT_XFER_CONTROL: - case USB_ENDPOINT_XFER_BULK: - case USB_ENDPOINT_XFER_INT: - /* mult = 0. Execute N Transactions as demonstrated by - * the USB variable length packet protocol where N is - * computed using the Maximum Packet Length (dQH) and - * the Total Bytes field (dTD) */ - mult = 0; - break; - case USB_ENDPOINT_XFER_ISOC: - /* Calculate transactions needed for high bandwidth iso */ - mult = (unsigned char)(1 + ((max >> 11) & 0x03)); - max = max & 0x7ff; /* bit 0~10 */ - /* 3 transactions at most */ - if (mult > 3) - goto en_done; - break; - default: - goto en_done; - } - - spin_lock_irqsave(&udc->lock, flags); - ep->ep.maxpacket = max; - ep->desc = desc; - ep->stopped = 0; - - /* Controller related setup */ - /* Init EPx Queue Head (Ep Capabilites field in QH - * according to max, zlt, mult) */ - struct_ep_qh_setup(udc, (unsigned char) ep_index(ep), - (unsigned char) ((desc->bEndpointAddress & USB_DIR_IN) - ? USB_SEND : USB_RECV), - (unsigned char) (desc->bmAttributes - & USB_ENDPOINT_XFERTYPE_MASK), - max, zlt, mult); - - /* Init endpoint ctrl register */ - dr_ep_setup((unsigned char) ep_index(ep), - (unsigned char) ((desc->bEndpointAddress & USB_DIR_IN) - ? USB_SEND : USB_RECV), - (unsigned char) (desc->bmAttributes - & USB_ENDPOINT_XFERTYPE_MASK)); - - spin_unlock_irqrestore(&udc->lock, flags); - retval = 0; - - VDBG("enabled %s (ep%d%s) maxpacket %d",ep->ep.name, - ep->desc->bEndpointAddress & 0x0f, - (desc->bEndpointAddress & USB_DIR_IN) - ? "in" : "out", max); -en_done: - return retval; -} - -/*--------------------------------------------------------------------- - * @ep : the ep being unconfigured. May not be ep0 - * Any pending and uncomplete req will complete with status (-ESHUTDOWN) -*---------------------------------------------------------------------*/ -static int fsl_ep_disable(struct usb_ep *_ep) -{ - struct fsl_udc *udc = NULL; - struct fsl_ep *ep = NULL; - unsigned long flags = 0; - u32 epctrl; - int ep_num; - - ep = container_of(_ep, struct fsl_ep, ep); - if (!_ep || !ep->desc) { - VDBG("%s not enabled", _ep ? ep->ep.name : NULL); - return -EINVAL; - } - - /* disable ep on controller */ - ep_num = ep_index(ep); - epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); - if (ep_is_in(ep)) { - epctrl &= ~(EPCTRL_TX_ENABLE | EPCTRL_TX_TYPE); - epctrl |= EPCTRL_EP_TYPE_BULK << EPCTRL_TX_EP_TYPE_SHIFT; - } else { - epctrl &= ~(EPCTRL_RX_ENABLE | EPCTRL_TX_TYPE); - epctrl |= EPCTRL_EP_TYPE_BULK << EPCTRL_RX_EP_TYPE_SHIFT; - } - fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]); - - udc = (struct fsl_udc *)ep->udc; - spin_lock_irqsave(&udc->lock, flags); - - /* nuke all pending requests (does flush) */ - nuke(ep, -ESHUTDOWN); - - ep->desc = NULL; - ep->ep.desc = NULL; - ep->stopped = 1; - spin_unlock_irqrestore(&udc->lock, flags); - - VDBG("disabled %s OK", _ep->name); - return 0; -} - -/*--------------------------------------------------------------------- - * allocate a request object used by this endpoint - * the main operation is to insert the req->queue to the eq->queue - * Returns the request, or null if one could not be allocated -*---------------------------------------------------------------------*/ -static struct usb_request * -fsl_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) -{ - struct fsl_req *req = NULL; - - req = kzalloc(sizeof *req, gfp_flags); - if (!req) - return NULL; - - req->req.dma = DMA_ADDR_INVALID; - INIT_LIST_HEAD(&req->queue); - - return &req->req; -} - -static void fsl_free_request(struct usb_ep *_ep, struct usb_request *_req) -{ - struct fsl_req *req = NULL; - - req = container_of(_req, struct fsl_req, req); - - if (_req) - kfree(req); -} - -/* Actually add a dTD chain to an empty dQH and let go */ -static void fsl_prime_ep(struct fsl_ep *ep, struct ep_td_struct *td) -{ - struct ep_queue_head *qh = get_qh_by_ep(ep); - - /* Write dQH next pointer and terminate bit to 0 */ - qh->next_dtd_ptr = cpu_to_hc32(td->td_dma - & EP_QUEUE_HEAD_NEXT_POINTER_MASK); - - /* Clear active and halt bit */ - qh->size_ioc_int_sts &= cpu_to_hc32(~(EP_QUEUE_HEAD_STATUS_ACTIVE - | EP_QUEUE_HEAD_STATUS_HALT)); - - /* Ensure that updates to the QH will occur before priming. */ - wmb(); - - /* Prime endpoint by writing correct bit to ENDPTPRIME */ - fsl_writel(ep_is_in(ep) ? (1 << (ep_index(ep) + 16)) - : (1 << (ep_index(ep))), &dr_regs->endpointprime); -} - -/* Add dTD chain to the dQH of an EP */ -static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req) -{ - u32 temp, bitmask, tmp_stat; - - /* VDBG("QH addr Register 0x%8x", dr_regs->endpointlistaddr); - VDBG("ep_qh[%d] addr is 0x%8x", i, (u32)&(ep->udc->ep_qh[i])); */ - - bitmask = ep_is_in(ep) - ? (1 << (ep_index(ep) + 16)) - : (1 << (ep_index(ep))); - - /* check if the pipe is empty */ - if (!(list_empty(&ep->queue)) && !(ep_index(ep) == 0)) { - /* Add td to the end */ - struct fsl_req *lastreq; - lastreq = list_entry(ep->queue.prev, struct fsl_req, queue); - lastreq->tail->next_td_ptr = - cpu_to_hc32(req->head->td_dma & DTD_ADDR_MASK); - /* Ensure dTD's next dtd pointer to be updated */ - wmb(); - /* Read prime bit, if 1 goto done */ - if (fsl_readl(&dr_regs->endpointprime) & bitmask) - return; - - do { - /* Set ATDTW bit in USBCMD */ - temp = fsl_readl(&dr_regs->usbcmd); - fsl_writel(temp | USB_CMD_ATDTW, &dr_regs->usbcmd); - - /* Read correct status bit */ - tmp_stat = fsl_readl(&dr_regs->endptstatus) & bitmask; - - } while (!(fsl_readl(&dr_regs->usbcmd) & USB_CMD_ATDTW)); - - /* Write ATDTW bit to 0 */ - temp = fsl_readl(&dr_regs->usbcmd); - fsl_writel(temp & ~USB_CMD_ATDTW, &dr_regs->usbcmd); - - if (tmp_stat) - return; - } - - fsl_prime_ep(ep, req->head); -} - -/* Fill in the dTD structure - * @req: request that the transfer belongs to - * @length: return actually data length of the dTD - * @dma: return dma address of the dTD - * @is_last: return flag if it is the last dTD of the request - * return: pointer to the built dTD */ -static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length, - dma_addr_t *dma, int *is_last, gfp_t gfp_flags) -{ - u32 swap_temp; - struct ep_td_struct *dtd; - - /* how big will this transfer be? */ - *length = min(req->req.length - req->req.actual, - (unsigned)EP_MAX_LENGTH_TRANSFER); - - dtd = dma_pool_alloc(udc_controller->td_pool, gfp_flags, dma); - if (dtd == NULL) - return dtd; - - dtd->td_dma = *dma; - /* Clear reserved field */ - swap_temp = hc32_to_cpu(dtd->size_ioc_sts); - swap_temp &= ~DTD_RESERVED_FIELDS; - dtd->size_ioc_sts = cpu_to_hc32(swap_temp); - - /* Init all of buffer page pointers */ - swap_temp = (u32) (req->req.dma + req->req.actual); - dtd->buff_ptr0 = cpu_to_hc32(swap_temp); - dtd->buff_ptr1 = cpu_to_hc32(swap_temp + 0x1000); - dtd->buff_ptr2 = cpu_to_hc32(swap_temp + 0x2000); - dtd->buff_ptr3 = cpu_to_hc32(swap_temp + 0x3000); - dtd->buff_ptr4 = cpu_to_hc32(swap_temp + 0x4000); - - req->req.actual += *length; - - /* zlp is needed if req->req.zero is set */ - if (req->req.zero) { - if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0) - *is_last = 1; - else - *is_last = 0; - } else if (req->req.length == req->req.actual) - *is_last = 1; - else - *is_last = 0; - - if ((*is_last) == 0) - VDBG("multi-dtd request!"); - /* Fill in the transfer size; set active bit */ - swap_temp = ((*length << DTD_LENGTH_BIT_POS) | DTD_STATUS_ACTIVE); - - /* Enable interrupt for the last dtd of a request */ - if (*is_last && !req->req.no_interrupt) - swap_temp |= DTD_IOC; - - dtd->size_ioc_sts = cpu_to_hc32(swap_temp); - - mb(); - - VDBG("length = %d address= 0x%x", *length, (int)*dma); - - return dtd; -} - -/* Generate dtd chain for a request */ -static int fsl_req_to_dtd(struct fsl_req *req, gfp_t gfp_flags) -{ - unsigned count; - int is_last; - int is_first =1; - struct ep_td_struct *last_dtd = NULL, *dtd; - dma_addr_t dma; - - do { - dtd = fsl_build_dtd(req, &count, &dma, &is_last, gfp_flags); - if (dtd == NULL) - return -ENOMEM; - - if (is_first) { - is_first = 0; - req->head = dtd; - } else { - last_dtd->next_td_ptr = cpu_to_hc32(dma); - last_dtd->next_td_virt = dtd; - } - last_dtd = dtd; - - req->dtd_count++; - } while (!is_last); - - dtd->next_td_ptr = cpu_to_hc32(DTD_NEXT_TERMINATE); - - req->tail = dtd; - - return 0; -} - -/* queues (submits) an I/O request to an endpoint */ -static int -fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) -{ - struct fsl_ep *ep = container_of(_ep, struct fsl_ep, ep); - struct fsl_req *req = container_of(_req, struct fsl_req, req); - struct fsl_udc *udc; - unsigned long flags; - - /* catch various bogus parameters */ - if (!_req || !req->req.complete || !req->req.buf - || !list_empty(&req->queue)) { - VDBG("%s, bad params", __func__); - return -EINVAL; - } - if (unlikely(!_ep || !ep->desc)) { - VDBG("%s, bad ep", __func__); - return -EINVAL; - } - if (usb_endpoint_xfer_isoc(ep->desc)) { - if (req->req.length > ep->ep.maxpacket) - return -EMSGSIZE; - } - - udc = ep->udc; - if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - req->ep = ep; - - /* map virtual address to hardware */ - if (req->req.dma == DMA_ADDR_INVALID) { - req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, - req->req.buf, - req->req.length, ep_is_in(ep) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - req->mapped = 1; - } else { - dma_sync_single_for_device(ep->udc->gadget.dev.parent, - req->req.dma, req->req.length, - ep_is_in(ep) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - req->mapped = 0; - } - - req->req.status = -EINPROGRESS; - req->req.actual = 0; - req->dtd_count = 0; - - /* build dtds and push them to device queue */ - if (!fsl_req_to_dtd(req, gfp_flags)) { - spin_lock_irqsave(&udc->lock, flags); - fsl_queue_td(ep, req); - } else { - return -ENOMEM; - } - - /* irq handler advances the queue */ - if (req != NULL) - list_add_tail(&req->queue, &ep->queue); - spin_unlock_irqrestore(&udc->lock, flags); - - return 0; -} - -/* dequeues (cancels, unlinks) an I/O request from an endpoint */ -static int fsl_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct fsl_ep *ep = container_of(_ep, struct fsl_ep, ep); - struct fsl_req *req; - unsigned long flags; - int ep_num, stopped, ret = 0; - u32 epctrl; - - if (!_ep || !_req) - return -EINVAL; - - spin_lock_irqsave(&ep->udc->lock, flags); - stopped = ep->stopped; - - /* Stop the ep before we deal with the queue */ - ep->stopped = 1; - ep_num = ep_index(ep); - epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); - if (ep_is_in(ep)) - epctrl &= ~EPCTRL_TX_ENABLE; - else - epctrl &= ~EPCTRL_RX_ENABLE; - fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]); - - /* make sure it's actually queued on this endpoint */ - list_for_each_entry(req, &ep->queue, queue) { - if (&req->req == _req) - break; - } - if (&req->req != _req) { - ret = -EINVAL; - goto out; - } - - /* The request is in progress, or completed but not dequeued */ - if (ep->queue.next == &req->queue) { - _req->status = -ECONNRESET; - fsl_ep_fifo_flush(_ep); /* flush current transfer */ - - /* The request isn't the last request in this ep queue */ - if (req->queue.next != &ep->queue) { - struct fsl_req *next_req; - - next_req = list_entry(req->queue.next, struct fsl_req, - queue); - - /* prime with dTD of next request */ - fsl_prime_ep(ep, next_req->head); - } - /* The request hasn't been processed, patch up the TD chain */ - } else { - struct fsl_req *prev_req; - - prev_req = list_entry(req->queue.prev, struct fsl_req, queue); - prev_req->tail->next_td_ptr = req->tail->next_td_ptr; - } - - done(ep, req, -ECONNRESET); - - /* Enable EP */ -out: epctrl = fsl_readl(&dr_regs->endptctrl[ep_num]); - if (ep_is_in(ep)) - epctrl |= EPCTRL_TX_ENABLE; - else - epctrl |= EPCTRL_RX_ENABLE; - fsl_writel(epctrl, &dr_regs->endptctrl[ep_num]); - ep->stopped = stopped; - - spin_unlock_irqrestore(&ep->udc->lock, flags); - return ret; -} - -/*-------------------------------------------------------------------------*/ - -/*----------------------------------------------------------------- - * modify the endpoint halt feature - * @ep: the non-isochronous endpoint being stalled - * @value: 1--set halt 0--clear halt - * Returns zero, or a negative error code. -*----------------------------------------------------------------*/ -static int fsl_ep_set_halt(struct usb_ep *_ep, int value) -{ - struct fsl_ep *ep = NULL; - unsigned long flags = 0; - int status = -EOPNOTSUPP; /* operation not supported */ - unsigned char ep_dir = 0, ep_num = 0; - struct fsl_udc *udc = NULL; - - ep = container_of(_ep, struct fsl_ep, ep); - udc = ep->udc; - if (!_ep || !ep->desc) { - status = -EINVAL; - goto out; - } - - if (usb_endpoint_xfer_isoc(ep->desc)) { - status = -EOPNOTSUPP; - goto out; - } - - /* Attempt to halt IN ep will fail if any transfer requests - * are still queue */ - if (value && ep_is_in(ep) && !list_empty(&ep->queue)) { - status = -EAGAIN; - goto out; - } - - status = 0; - ep_dir = ep_is_in(ep) ? USB_SEND : USB_RECV; - ep_num = (unsigned char)(ep_index(ep)); - spin_lock_irqsave(&ep->udc->lock, flags); - dr_ep_change_stall(ep_num, ep_dir, value); - spin_unlock_irqrestore(&ep->udc->lock, flags); - - if (ep_index(ep) == 0) { - udc->ep0_state = WAIT_FOR_SETUP; - udc->ep0_dir = 0; - } -out: - VDBG(" %s %s halt stat %d", ep->ep.name, - value ? "set" : "clear", status); - - return status; -} - -static int fsl_ep_fifo_status(struct usb_ep *_ep) -{ - struct fsl_ep *ep; - struct fsl_udc *udc; - int size = 0; - u32 bitmask; - struct ep_queue_head *qh; - - ep = container_of(_ep, struct fsl_ep, ep); - if (!_ep || (!ep->desc && ep_index(ep) != 0)) - return -ENODEV; - - udc = (struct fsl_udc *)ep->udc; - - if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - qh = get_qh_by_ep(ep); - - bitmask = (ep_is_in(ep)) ? (1 << (ep_index(ep) + 16)) : - (1 << (ep_index(ep))); - - if (fsl_readl(&dr_regs->endptstatus) & bitmask) - size = (qh->size_ioc_int_sts & DTD_PACKET_SIZE) - >> DTD_LENGTH_BIT_POS; - - pr_debug("%s %u\n", __func__, size); - return size; -} - -static void fsl_ep_fifo_flush(struct usb_ep *_ep) -{ - struct fsl_ep *ep; - int ep_num, ep_dir; - u32 bits; - unsigned long timeout; -#define FSL_UDC_FLUSH_TIMEOUT 1000 - - if (!_ep) { - return; - } else { - ep = container_of(_ep, struct fsl_ep, ep); - if (!ep->desc) - return; - } - ep_num = ep_index(ep); - ep_dir = ep_is_in(ep) ? USB_SEND : USB_RECV; - - if (ep_num == 0) - bits = (1 << 16) | 1; - else if (ep_dir == USB_SEND) - bits = 1 << (16 + ep_num); - else - bits = 1 << ep_num; - - timeout = jiffies + FSL_UDC_FLUSH_TIMEOUT; - do { - fsl_writel(bits, &dr_regs->endptflush); - - /* Wait until flush complete */ - while (fsl_readl(&dr_regs->endptflush)) { - if (time_after(jiffies, timeout)) { - ERR("ep flush timeout\n"); - return; - } - cpu_relax(); - } - /* See if we need to flush again */ - } while (fsl_readl(&dr_regs->endptstatus) & bits); -} - -static struct usb_ep_ops fsl_ep_ops = { - .enable = fsl_ep_enable, - .disable = fsl_ep_disable, - - .alloc_request = fsl_alloc_request, - .free_request = fsl_free_request, - - .queue = fsl_ep_queue, - .dequeue = fsl_ep_dequeue, - - .set_halt = fsl_ep_set_halt, - .fifo_status = fsl_ep_fifo_status, - .fifo_flush = fsl_ep_fifo_flush, /* flush fifo */ -}; - -/*------------------------------------------------------------------------- - Gadget Driver Layer Operations --------------------------------------------------------------------------*/ - -/*---------------------------------------------------------------------- - * Get the current frame number (from DR frame_index Reg ) - *----------------------------------------------------------------------*/ -static int fsl_get_frame(struct usb_gadget *gadget) -{ - return (int)(fsl_readl(&dr_regs->frindex) & USB_FRINDEX_MASKS); -} - -/*----------------------------------------------------------------------- - * Tries to wake up the host connected to this gadget - -----------------------------------------------------------------------*/ -static int fsl_wakeup(struct usb_gadget *gadget) -{ - struct fsl_udc *udc = container_of(gadget, struct fsl_udc, gadget); - u32 portsc; - - /* Remote wakeup feature not enabled by host */ - if (!udc->remote_wakeup) - return -ENOTSUPP; - - portsc = fsl_readl(&dr_regs->portsc1); - /* not suspended? */ - if (!(portsc & PORTSCX_PORT_SUSPEND)) - return 0; - /* trigger force resume */ - portsc |= PORTSCX_PORT_FORCE_RESUME; - fsl_writel(portsc, &dr_regs->portsc1); - return 0; -} - -static int can_pullup(struct fsl_udc *udc) -{ - return udc->driver && udc->softconnect && udc->vbus_active; -} - -/* Notify controller that VBUS is powered, Called by whatever - detects VBUS sessions */ -static int fsl_vbus_session(struct usb_gadget *gadget, int is_active) -{ - struct fsl_udc *udc; - unsigned long flags; - - udc = container_of(gadget, struct fsl_udc, gadget); - spin_lock_irqsave(&udc->lock, flags); - VDBG("VBUS %s", is_active ? "on" : "off"); - udc->vbus_active = (is_active != 0); - if (can_pullup(udc)) - fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP), - &dr_regs->usbcmd); - else - fsl_writel((fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP), - &dr_regs->usbcmd); - spin_unlock_irqrestore(&udc->lock, flags); - return 0; -} - -/* constrain controller's VBUS power usage - * This call is used by gadget drivers during SET_CONFIGURATION calls, - * reporting how much power the device may consume. For example, this - * could affect how quickly batteries are recharged. - * - * Returns zero on success, else negative errno. - */ -static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA) -{ - struct fsl_udc *udc; - - udc = container_of(gadget, struct fsl_udc, gadget); - if (udc->transceiver) - return usb_phy_set_power(udc->transceiver, mA); - return -ENOTSUPP; -} - -/* Change Data+ pullup status - * this func is used by usb_gadget_connect/disconnet - */ -static int fsl_pullup(struct usb_gadget *gadget, int is_on) -{ - struct fsl_udc *udc; - - udc = container_of(gadget, struct fsl_udc, gadget); - udc->softconnect = (is_on != 0); - if (can_pullup(udc)) - fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP), - &dr_regs->usbcmd); - else - fsl_writel((fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP), - &dr_regs->usbcmd); - - return 0; -} - -static int fsl_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int fsl_stop(struct usb_gadget_driver *driver); -/* defined in gadget.h */ -static struct usb_gadget_ops fsl_gadget_ops = { - .get_frame = fsl_get_frame, - .wakeup = fsl_wakeup, -/* .set_selfpowered = fsl_set_selfpowered, */ /* Always selfpowered */ - .vbus_session = fsl_vbus_session, - .vbus_draw = fsl_vbus_draw, - .pullup = fsl_pullup, - .start = fsl_start, - .stop = fsl_stop, -}; - -/* Set protocol stall on ep0, protocol stall will automatically be cleared - on new transaction */ -static void ep0stall(struct fsl_udc *udc) -{ - u32 tmp; - - /* must set tx and rx to stall at the same time */ - tmp = fsl_readl(&dr_regs->endptctrl[0]); - tmp |= EPCTRL_TX_EP_STALL | EPCTRL_RX_EP_STALL; - fsl_writel(tmp, &dr_regs->endptctrl[0]); - udc->ep0_state = WAIT_FOR_SETUP; - udc->ep0_dir = 0; -} - -/* Prime a status phase for ep0 */ -static int ep0_prime_status(struct fsl_udc *udc, int direction) -{ - struct fsl_req *req = udc->status_req; - struct fsl_ep *ep; - - if (direction == EP_DIR_IN) - udc->ep0_dir = USB_DIR_IN; - else - udc->ep0_dir = USB_DIR_OUT; - - ep = &udc->eps[0]; - if (udc->ep0_state != DATA_STATE_XMIT) - udc->ep0_state = WAIT_FOR_OUT_STATUS; - - req->ep = ep; - req->req.length = 0; - req->req.status = -EINPROGRESS; - req->req.actual = 0; - req->req.complete = NULL; - req->dtd_count = 0; - - req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, - req->req.buf, req->req.length, - ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - req->mapped = 1; - - if (fsl_req_to_dtd(req, GFP_ATOMIC) == 0) - fsl_queue_td(ep, req); - else - return -ENOMEM; - - list_add_tail(&req->queue, &ep->queue); - - return 0; -} - -static void udc_reset_ep_queue(struct fsl_udc *udc, u8 pipe) -{ - struct fsl_ep *ep = get_ep_by_pipe(udc, pipe); - - if (ep->name) - nuke(ep, -ESHUTDOWN); -} - -/* - * ch9 Set address - */ -static void ch9setaddress(struct fsl_udc *udc, u16 value, u16 index, u16 length) -{ - /* Save the new address to device struct */ - udc->device_address = (u8) value; - /* Update usb state */ - udc->usb_state = USB_STATE_ADDRESS; - /* Status phase */ - if (ep0_prime_status(udc, EP_DIR_IN)) - ep0stall(udc); -} - -/* - * ch9 Get status - */ -static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value, - u16 index, u16 length) -{ - u16 tmp = 0; /* Status, cpu endian */ - struct fsl_req *req; - struct fsl_ep *ep; - - ep = &udc->eps[0]; - - if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) { - /* Get device status */ - tmp = 1 << USB_DEVICE_SELF_POWERED; - tmp |= udc->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP; - } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) { - /* Get interface status */ - /* We don't have interface information in udc driver */ - tmp = 0; - } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) { - /* Get endpoint status */ - struct fsl_ep *target_ep; - - target_ep = get_ep_by_pipe(udc, get_pipe_by_windex(index)); - - /* stall if endpoint doesn't exist */ - if (!target_ep->desc) - goto stall; - tmp = dr_ep_get_stall(ep_index(target_ep), ep_is_in(target_ep)) - << USB_ENDPOINT_HALT; - } - - udc->ep0_dir = USB_DIR_IN; - /* Borrow the per device status_req */ - req = udc->status_req; - /* Fill in the reqest structure */ - *((u16 *) req->req.buf) = cpu_to_le16(tmp); - - req->ep = ep; - req->req.length = 2; - req->req.status = -EINPROGRESS; - req->req.actual = 0; - req->req.complete = NULL; - req->dtd_count = 0; - - req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, - req->req.buf, req->req.length, - ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - req->mapped = 1; - - /* prime the data phase */ - if ((fsl_req_to_dtd(req, GFP_ATOMIC) == 0)) - fsl_queue_td(ep, req); - else /* no mem */ - goto stall; - - list_add_tail(&req->queue, &ep->queue); - udc->ep0_state = DATA_STATE_XMIT; - if (ep0_prime_status(udc, EP_DIR_OUT)) - ep0stall(udc); - - return; -stall: - ep0stall(udc); -} - -static void setup_received_irq(struct fsl_udc *udc, - struct usb_ctrlrequest *setup) -{ - u16 wValue = le16_to_cpu(setup->wValue); - u16 wIndex = le16_to_cpu(setup->wIndex); - u16 wLength = le16_to_cpu(setup->wLength); - - udc_reset_ep_queue(udc, 0); - - /* We process some stardard setup requests here */ - switch (setup->bRequest) { - case USB_REQ_GET_STATUS: - /* Data+Status phase from udc */ - if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK)) - != (USB_DIR_IN | USB_TYPE_STANDARD)) - break; - ch9getstatus(udc, setup->bRequestType, wValue, wIndex, wLength); - return; - - case USB_REQ_SET_ADDRESS: - /* Status phase from udc */ - if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD - | USB_RECIP_DEVICE)) - break; - ch9setaddress(udc, wValue, wIndex, wLength); - return; - - case USB_REQ_CLEAR_FEATURE: - case USB_REQ_SET_FEATURE: - /* Status phase from udc */ - { - int rc = -EOPNOTSUPP; - u16 ptc = 0; - - if ((setup->bRequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) - == (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) { - int pipe = get_pipe_by_windex(wIndex); - struct fsl_ep *ep; - - if (wValue != 0 || wLength != 0 || pipe >= udc->max_ep) - break; - ep = get_ep_by_pipe(udc, pipe); - - spin_unlock(&udc->lock); - rc = fsl_ep_set_halt(&ep->ep, - (setup->bRequest == USB_REQ_SET_FEATURE) - ? 1 : 0); - spin_lock(&udc->lock); - - } else if ((setup->bRequestType & (USB_RECIP_MASK - | USB_TYPE_MASK)) == (USB_RECIP_DEVICE - | USB_TYPE_STANDARD)) { - /* Note: The driver has not include OTG support yet. - * This will be set when OTG support is added */ - if (wValue == USB_DEVICE_TEST_MODE) - ptc = wIndex >> 8; - else if (gadget_is_otg(&udc->gadget)) { - if (setup->bRequest == - USB_DEVICE_B_HNP_ENABLE) - udc->gadget.b_hnp_enable = 1; - else if (setup->bRequest == - USB_DEVICE_A_HNP_SUPPORT) - udc->gadget.a_hnp_support = 1; - else if (setup->bRequest == - USB_DEVICE_A_ALT_HNP_SUPPORT) - udc->gadget.a_alt_hnp_support = 1; - } - rc = 0; - } else - break; - - if (rc == 0) { - if (ep0_prime_status(udc, EP_DIR_IN)) - ep0stall(udc); - } - if (ptc) { - u32 tmp; - - mdelay(10); - tmp = fsl_readl(&dr_regs->portsc1) | (ptc << 16); - fsl_writel(tmp, &dr_regs->portsc1); - printk(KERN_INFO "udc: switch to test mode %d.\n", ptc); - } - - return; - } - - default: - break; - } - - /* Requests handled by gadget */ - if (wLength) { - /* Data phase from gadget, status phase from udc */ - udc->ep0_dir = (setup->bRequestType & USB_DIR_IN) - ? USB_DIR_IN : USB_DIR_OUT; - spin_unlock(&udc->lock); - if (udc->driver->setup(&udc->gadget, - &udc->local_setup_buff) < 0) - ep0stall(udc); - spin_lock(&udc->lock); - udc->ep0_state = (setup->bRequestType & USB_DIR_IN) - ? DATA_STATE_XMIT : DATA_STATE_RECV; - /* - * If the data stage is IN, send status prime immediately. - * See 2.0 Spec chapter 8.5.3.3 for detail. - */ - if (udc->ep0_state == DATA_STATE_XMIT) - if (ep0_prime_status(udc, EP_DIR_OUT)) - ep0stall(udc); - - } else { - /* No data phase, IN status from gadget */ - udc->ep0_dir = USB_DIR_IN; - spin_unlock(&udc->lock); - if (udc->driver->setup(&udc->gadget, - &udc->local_setup_buff) < 0) - ep0stall(udc); - spin_lock(&udc->lock); - udc->ep0_state = WAIT_FOR_OUT_STATUS; - } -} - -/* Process request for Data or Status phase of ep0 - * prime status phase if needed */ -static void ep0_req_complete(struct fsl_udc *udc, struct fsl_ep *ep0, - struct fsl_req *req) -{ - if (udc->usb_state == USB_STATE_ADDRESS) { - /* Set the new address */ - u32 new_address = (u32) udc->device_address; - fsl_writel(new_address << USB_DEVICE_ADDRESS_BIT_POS, - &dr_regs->deviceaddr); - } - - done(ep0, req, 0); - - switch (udc->ep0_state) { - case DATA_STATE_XMIT: - /* already primed at setup_received_irq */ - udc->ep0_state = WAIT_FOR_OUT_STATUS; - break; - case DATA_STATE_RECV: - /* send status phase */ - if (ep0_prime_status(udc, EP_DIR_IN)) - ep0stall(udc); - break; - case WAIT_FOR_OUT_STATUS: - udc->ep0_state = WAIT_FOR_SETUP; - break; - case WAIT_FOR_SETUP: - ERR("Unexpect ep0 packets\n"); - break; - default: - ep0stall(udc); - break; - } -} - -/* Tripwire mechanism to ensure a setup packet payload is extracted without - * being corrupted by another incoming setup packet */ -static void tripwire_handler(struct fsl_udc *udc, u8 ep_num, u8 *buffer_ptr) -{ - u32 temp; - struct ep_queue_head *qh; - struct fsl_usb2_platform_data *pdata = udc->pdata; - - qh = &udc->ep_qh[ep_num * 2 + EP_DIR_OUT]; - - /* Clear bit in ENDPTSETUPSTAT */ - temp = fsl_readl(&dr_regs->endptsetupstat); - fsl_writel(temp | (1 << ep_num), &dr_regs->endptsetupstat); - - /* while a hazard exists when setup package arrives */ - do { - /* Set Setup Tripwire */ - temp = fsl_readl(&dr_regs->usbcmd); - fsl_writel(temp | USB_CMD_SUTW, &dr_regs->usbcmd); - - /* Copy the setup packet to local buffer */ - if (pdata->le_setup_buf) { - u32 *p = (u32 *)buffer_ptr; - u32 *s = (u32 *)qh->setup_buffer; - - /* Convert little endian setup buffer to CPU endian */ - *p++ = le32_to_cpu(*s++); - *p = le32_to_cpu(*s); - } else { - memcpy(buffer_ptr, (u8 *) qh->setup_buffer, 8); - } - } while (!(fsl_readl(&dr_regs->usbcmd) & USB_CMD_SUTW)); - - /* Clear Setup Tripwire */ - temp = fsl_readl(&dr_regs->usbcmd); - fsl_writel(temp & ~USB_CMD_SUTW, &dr_regs->usbcmd); -} - -/* process-ep_req(): free the completed Tds for this req */ -static int process_ep_req(struct fsl_udc *udc, int pipe, - struct fsl_req *curr_req) -{ - struct ep_td_struct *curr_td; - int td_complete, actual, remaining_length, j, tmp; - int status = 0; - int errors = 0; - struct ep_queue_head *curr_qh = &udc->ep_qh[pipe]; - int direction = pipe % 2; - - curr_td = curr_req->head; - td_complete = 0; - actual = curr_req->req.length; - - for (j = 0; j < curr_req->dtd_count; j++) { - remaining_length = (hc32_to_cpu(curr_td->size_ioc_sts) - & DTD_PACKET_SIZE) - >> DTD_LENGTH_BIT_POS; - actual -= remaining_length; - - errors = hc32_to_cpu(curr_td->size_ioc_sts); - if (errors & DTD_ERROR_MASK) { - if (errors & DTD_STATUS_HALTED) { - ERR("dTD error %08x QH=%d\n", errors, pipe); - /* Clear the errors and Halt condition */ - tmp = hc32_to_cpu(curr_qh->size_ioc_int_sts); - tmp &= ~errors; - curr_qh->size_ioc_int_sts = cpu_to_hc32(tmp); - status = -EPIPE; - /* FIXME: continue with next queued TD? */ - - break; - } - if (errors & DTD_STATUS_DATA_BUFF_ERR) { - VDBG("Transfer overflow"); - status = -EPROTO; - break; - } else if (errors & DTD_STATUS_TRANSACTION_ERR) { - VDBG("ISO error"); - status = -EILSEQ; - break; - } else - ERR("Unknown error has occurred (0x%x)!\n", - errors); - - } else if (hc32_to_cpu(curr_td->size_ioc_sts) - & DTD_STATUS_ACTIVE) { - VDBG("Request not complete"); - status = REQ_UNCOMPLETE; - return status; - } else if (remaining_length) { - if (direction) { - VDBG("Transmit dTD remaining length not zero"); - status = -EPROTO; - break; - } else { - td_complete++; - break; - } - } else { - td_complete++; - VDBG("dTD transmitted successful"); - } - - if (j != curr_req->dtd_count - 1) - curr_td = (struct ep_td_struct *)curr_td->next_td_virt; - } - - if (status) - return status; - - curr_req->req.actual = actual; - - return 0; -} - -/* Process a DTD completion interrupt */ -static void dtd_complete_irq(struct fsl_udc *udc) -{ - u32 bit_pos; - int i, ep_num, direction, bit_mask, status; - struct fsl_ep *curr_ep; - struct fsl_req *curr_req, *temp_req; - - /* Clear the bits in the register */ - bit_pos = fsl_readl(&dr_regs->endptcomplete); - fsl_writel(bit_pos, &dr_regs->endptcomplete); - - if (!bit_pos) - return; - - for (i = 0; i < udc->max_ep; i++) { - ep_num = i >> 1; - direction = i % 2; - - bit_mask = 1 << (ep_num + 16 * direction); - - if (!(bit_pos & bit_mask)) - continue; - - curr_ep = get_ep_by_pipe(udc, i); - - /* If the ep is configured */ - if (curr_ep->name == NULL) { - WARNING("Invalid EP?"); - continue; - } - - /* process the req queue until an uncomplete request */ - list_for_each_entry_safe(curr_req, temp_req, &curr_ep->queue, - queue) { - status = process_ep_req(udc, i, curr_req); - - VDBG("status of process_ep_req= %d, ep = %d", - status, ep_num); - if (status == REQ_UNCOMPLETE) - break; - /* write back status to req */ - curr_req->req.status = status; - - if (ep_num == 0) { - ep0_req_complete(udc, curr_ep, curr_req); - break; - } else - done(curr_ep, curr_req, status); - } - } -} - -static inline enum usb_device_speed portscx_device_speed(u32 reg) -{ - switch (reg & PORTSCX_PORT_SPEED_MASK) { - case PORTSCX_PORT_SPEED_HIGH: - return USB_SPEED_HIGH; - case PORTSCX_PORT_SPEED_FULL: - return USB_SPEED_FULL; - case PORTSCX_PORT_SPEED_LOW: - return USB_SPEED_LOW; - default: - return USB_SPEED_UNKNOWN; - } -} - -/* Process a port change interrupt */ -static void port_change_irq(struct fsl_udc *udc) -{ - if (udc->bus_reset) - udc->bus_reset = 0; - - /* Bus resetting is finished */ - if (!(fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET)) - /* Get the speed */ - udc->gadget.speed = - portscx_device_speed(fsl_readl(&dr_regs->portsc1)); - - /* Update USB state */ - if (!udc->resume_state) - udc->usb_state = USB_STATE_DEFAULT; -} - -/* Process suspend interrupt */ -static void suspend_irq(struct fsl_udc *udc) -{ - udc->resume_state = udc->usb_state; - udc->usb_state = USB_STATE_SUSPENDED; - - /* report suspend to the driver, serial.c does not support this */ - if (udc->driver->suspend) - udc->driver->suspend(&udc->gadget); -} - -static void bus_resume(struct fsl_udc *udc) -{ - udc->usb_state = udc->resume_state; - udc->resume_state = 0; - - /* report resume to the driver, serial.c does not support this */ - if (udc->driver->resume) - udc->driver->resume(&udc->gadget); -} - -/* Clear up all ep queues */ -static int reset_queues(struct fsl_udc *udc) -{ - u8 pipe; - - for (pipe = 0; pipe < udc->max_pipes; pipe++) - udc_reset_ep_queue(udc, pipe); - - /* report disconnect; the driver is already quiesced */ - spin_unlock(&udc->lock); - udc->driver->disconnect(&udc->gadget); - spin_lock(&udc->lock); - - return 0; -} - -/* Process reset interrupt */ -static void reset_irq(struct fsl_udc *udc) -{ - u32 temp; - unsigned long timeout; - - /* Clear the device address */ - temp = fsl_readl(&dr_regs->deviceaddr); - fsl_writel(temp & ~USB_DEVICE_ADDRESS_MASK, &dr_regs->deviceaddr); - - udc->device_address = 0; - - /* Clear usb state */ - udc->resume_state = 0; - udc->ep0_dir = 0; - udc->ep0_state = WAIT_FOR_SETUP; - udc->remote_wakeup = 0; /* default to 0 on reset */ - udc->gadget.b_hnp_enable = 0; - udc->gadget.a_hnp_support = 0; - udc->gadget.a_alt_hnp_support = 0; - - /* Clear all the setup token semaphores */ - temp = fsl_readl(&dr_regs->endptsetupstat); - fsl_writel(temp, &dr_regs->endptsetupstat); - - /* Clear all the endpoint complete status bits */ - temp = fsl_readl(&dr_regs->endptcomplete); - fsl_writel(temp, &dr_regs->endptcomplete); - - timeout = jiffies + 100; - while (fsl_readl(&dr_regs->endpointprime)) { - /* Wait until all endptprime bits cleared */ - if (time_after(jiffies, timeout)) { - ERR("Timeout for reset\n"); - break; - } - cpu_relax(); - } - - /* Write 1s to the flush register */ - fsl_writel(0xffffffff, &dr_regs->endptflush); - - if (fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET) { - VDBG("Bus reset"); - /* Bus is reseting */ - udc->bus_reset = 1; - /* Reset all the queues, include XD, dTD, EP queue - * head and TR Queue */ - reset_queues(udc); - udc->usb_state = USB_STATE_DEFAULT; - } else { - VDBG("Controller reset"); - /* initialize usb hw reg except for regs for EP, not - * touch usbintr reg */ - dr_controller_setup(udc); - - /* Reset all internal used Queues */ - reset_queues(udc); - - ep0_setup(udc); - - /* Enable DR IRQ reg, Set Run bit, change udc state */ - dr_controller_run(udc); - udc->usb_state = USB_STATE_ATTACHED; - } -} - -/* - * USB device controller interrupt handler - */ -static irqreturn_t fsl_udc_irq(int irq, void *_udc) -{ - struct fsl_udc *udc = _udc; - u32 irq_src; - irqreturn_t status = IRQ_NONE; - unsigned long flags; - - /* Disable ISR for OTG host mode */ - if (udc->stopped) - return IRQ_NONE; - spin_lock_irqsave(&udc->lock, flags); - irq_src = fsl_readl(&dr_regs->usbsts) & fsl_readl(&dr_regs->usbintr); - /* Clear notification bits */ - fsl_writel(irq_src, &dr_regs->usbsts); - - /* VDBG("irq_src [0x%8x]", irq_src); */ - - /* Need to resume? */ - if (udc->usb_state == USB_STATE_SUSPENDED) - if ((fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_SUSPEND) == 0) - bus_resume(udc); - - /* USB Interrupt */ - if (irq_src & USB_STS_INT) { - VDBG("Packet int"); - /* Setup package, we only support ep0 as control ep */ - if (fsl_readl(&dr_regs->endptsetupstat) & EP_SETUP_STATUS_EP0) { - tripwire_handler(udc, 0, - (u8 *) (&udc->local_setup_buff)); - setup_received_irq(udc, &udc->local_setup_buff); - status = IRQ_HANDLED; - } - - /* completion of dtd */ - if (fsl_readl(&dr_regs->endptcomplete)) { - dtd_complete_irq(udc); - status = IRQ_HANDLED; - } - } - - /* SOF (for ISO transfer) */ - if (irq_src & USB_STS_SOF) { - status = IRQ_HANDLED; - } - - /* Port Change */ - if (irq_src & USB_STS_PORT_CHANGE) { - port_change_irq(udc); - status = IRQ_HANDLED; - } - - /* Reset Received */ - if (irq_src & USB_STS_RESET) { - VDBG("reset int"); - reset_irq(udc); - status = IRQ_HANDLED; - } - - /* Sleep Enable (Suspend) */ - if (irq_src & USB_STS_SUSPEND) { - suspend_irq(udc); - status = IRQ_HANDLED; - } - - if (irq_src & (USB_STS_ERR | USB_STS_SYS_ERR)) { - VDBG("Error IRQ %x", irq_src); - } - - spin_unlock_irqrestore(&udc->lock, flags); - return status; -} - -/*----------------------------------------------------------------* - * Hook to gadget drivers - * Called by initialization code of gadget drivers -*----------------------------------------------------------------*/ -static int fsl_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) -{ - int retval = -ENODEV; - unsigned long flags = 0; - - if (!udc_controller) - return -ENODEV; - - if (!driver || driver->max_speed < USB_SPEED_FULL - || !bind || !driver->disconnect || !driver->setup) - return -EINVAL; - - if (udc_controller->driver) - return -EBUSY; - - /* lock is needed but whether should use this lock or another */ - spin_lock_irqsave(&udc_controller->lock, flags); - - driver->driver.bus = NULL; - /* hook up the driver */ - udc_controller->driver = driver; - udc_controller->gadget.dev.driver = &driver->driver; - spin_unlock_irqrestore(&udc_controller->lock, flags); - - /* bind udc driver to gadget driver */ - retval = bind(&udc_controller->gadget); - if (retval) { - VDBG("bind to %s --> %d", driver->driver.name, retval); - udc_controller->gadget.dev.driver = NULL; - udc_controller->driver = NULL; - goto out; - } - - if (udc_controller->transceiver) { - /* Suspend the controller until OTG enable it */ - udc_controller->stopped = 1; - printk(KERN_INFO "Suspend udc for OTG auto detect\n"); - - /* connect to bus through transceiver */ - if (udc_controller->transceiver) { - retval = otg_set_peripheral( - udc_controller->transceiver->otg, - &udc_controller->gadget); - if (retval < 0) { - ERR("can't bind to transceiver\n"); - driver->unbind(&udc_controller->gadget); - udc_controller->gadget.dev.driver = 0; - udc_controller->driver = 0; - return retval; - } - } - } else { - /* Enable DR IRQ reg and set USBCMD reg Run bit */ - dr_controller_run(udc_controller); - udc_controller->usb_state = USB_STATE_ATTACHED; - udc_controller->ep0_state = WAIT_FOR_SETUP; - udc_controller->ep0_dir = 0; - } - printk(KERN_INFO "%s: bind to driver %s\n", - udc_controller->gadget.name, driver->driver.name); - -out: - if (retval) - printk(KERN_WARNING "gadget driver register failed %d\n", - retval); - return retval; -} - -/* Disconnect from gadget driver */ -static int fsl_stop(struct usb_gadget_driver *driver) -{ - struct fsl_ep *loop_ep; - unsigned long flags; - - if (!udc_controller) - return -ENODEV; - - if (!driver || driver != udc_controller->driver || !driver->unbind) - return -EINVAL; - - if (udc_controller->transceiver) - otg_set_peripheral(udc_controller->transceiver->otg, NULL); - - /* stop DR, disable intr */ - dr_controller_stop(udc_controller); - - /* in fact, no needed */ - udc_controller->usb_state = USB_STATE_ATTACHED; - udc_controller->ep0_state = WAIT_FOR_SETUP; - udc_controller->ep0_dir = 0; - - /* stand operation */ - spin_lock_irqsave(&udc_controller->lock, flags); - udc_controller->gadget.speed = USB_SPEED_UNKNOWN; - nuke(&udc_controller->eps[0], -ESHUTDOWN); - list_for_each_entry(loop_ep, &udc_controller->gadget.ep_list, - ep.ep_list) - nuke(loop_ep, -ESHUTDOWN); - spin_unlock_irqrestore(&udc_controller->lock, flags); - - /* report disconnect; the controller is already quiesced */ - driver->disconnect(&udc_controller->gadget); - - /* unbind gadget and unhook driver. */ - driver->unbind(&udc_controller->gadget); - udc_controller->gadget.dev.driver = NULL; - udc_controller->driver = NULL; - - printk(KERN_WARNING "unregistered gadget driver '%s'\n", - driver->driver.name); - return 0; -} - -/*------------------------------------------------------------------------- - PROC File System Support --------------------------------------------------------------------------*/ -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - -#include - -static const char proc_filename[] = "driver/fsl_usb2_udc"; - -static int fsl_proc_read(char *page, char **start, off_t off, int count, - int *eof, void *_dev) -{ - char *buf = page; - char *next = buf; - unsigned size = count; - unsigned long flags; - int t, i; - u32 tmp_reg; - struct fsl_ep *ep = NULL; - struct fsl_req *req; - - struct fsl_udc *udc = udc_controller; - if (off != 0) - return 0; - - spin_lock_irqsave(&udc->lock, flags); - - /* ------basic driver information ---- */ - t = scnprintf(next, size, - DRIVER_DESC "\n" - "%s version: %s\n" - "Gadget driver: %s\n\n", - driver_name, DRIVER_VERSION, - udc->driver ? udc->driver->driver.name : "(none)"); - size -= t; - next += t; - - /* ------ DR Registers ----- */ - tmp_reg = fsl_readl(&dr_regs->usbcmd); - t = scnprintf(next, size, - "USBCMD reg:\n" - "SetupTW: %d\n" - "Run/Stop: %s\n\n", - (tmp_reg & USB_CMD_SUTW) ? 1 : 0, - (tmp_reg & USB_CMD_RUN_STOP) ? "Run" : "Stop"); - size -= t; - next += t; - - tmp_reg = fsl_readl(&dr_regs->usbsts); - t = scnprintf(next, size, - "USB Status Reg:\n" - "Dr Suspend: %d Reset Received: %d System Error: %s " - "USB Error Interrupt: %s\n\n", - (tmp_reg & USB_STS_SUSPEND) ? 1 : 0, - (tmp_reg & USB_STS_RESET) ? 1 : 0, - (tmp_reg & USB_STS_SYS_ERR) ? "Err" : "Normal", - (tmp_reg & USB_STS_ERR) ? "Err detected" : "No err"); - size -= t; - next += t; - - tmp_reg = fsl_readl(&dr_regs->usbintr); - t = scnprintf(next, size, - "USB Intrrupt Enable Reg:\n" - "Sleep Enable: %d SOF Received Enable: %d " - "Reset Enable: %d\n" - "System Error Enable: %d " - "Port Change Dectected Enable: %d\n" - "USB Error Intr Enable: %d USB Intr Enable: %d\n\n", - (tmp_reg & USB_INTR_DEVICE_SUSPEND) ? 1 : 0, - (tmp_reg & USB_INTR_SOF_EN) ? 1 : 0, - (tmp_reg & USB_INTR_RESET_EN) ? 1 : 0, - (tmp_reg & USB_INTR_SYS_ERR_EN) ? 1 : 0, - (tmp_reg & USB_INTR_PTC_DETECT_EN) ? 1 : 0, - (tmp_reg & USB_INTR_ERR_INT_EN) ? 1 : 0, - (tmp_reg & USB_INTR_INT_EN) ? 1 : 0); - size -= t; - next += t; - - tmp_reg = fsl_readl(&dr_regs->frindex); - t = scnprintf(next, size, - "USB Frame Index Reg: Frame Number is 0x%x\n\n", - (tmp_reg & USB_FRINDEX_MASKS)); - size -= t; - next += t; - - tmp_reg = fsl_readl(&dr_regs->deviceaddr); - t = scnprintf(next, size, - "USB Device Address Reg: Device Addr is 0x%x\n\n", - (tmp_reg & USB_DEVICE_ADDRESS_MASK)); - size -= t; - next += t; - - tmp_reg = fsl_readl(&dr_regs->endpointlistaddr); - t = scnprintf(next, size, - "USB Endpoint List Address Reg: " - "Device Addr is 0x%x\n\n", - (tmp_reg & USB_EP_LIST_ADDRESS_MASK)); - size -= t; - next += t; - - tmp_reg = fsl_readl(&dr_regs->portsc1); - t = scnprintf(next, size, - "USB Port Status&Control Reg:\n" - "Port Transceiver Type : %s Port Speed: %s\n" - "PHY Low Power Suspend: %s Port Reset: %s " - "Port Suspend Mode: %s\n" - "Over-current Change: %s " - "Port Enable/Disable Change: %s\n" - "Port Enabled/Disabled: %s " - "Current Connect Status: %s\n\n", ( { - char *s; - switch (tmp_reg & PORTSCX_PTS_FSLS) { - case PORTSCX_PTS_UTMI: - s = "UTMI"; break; - case PORTSCX_PTS_ULPI: - s = "ULPI "; break; - case PORTSCX_PTS_FSLS: - s = "FS/LS Serial"; break; - default: - s = "None"; break; - } - s;} ), - usb_speed_string(portscx_device_speed(tmp_reg)), - (tmp_reg & PORTSCX_PHY_LOW_POWER_SPD) ? - "Normal PHY mode" : "Low power mode", - (tmp_reg & PORTSCX_PORT_RESET) ? "In Reset" : - "Not in Reset", - (tmp_reg & PORTSCX_PORT_SUSPEND) ? "In " : "Not in", - (tmp_reg & PORTSCX_OVER_CURRENT_CHG) ? "Dected" : - "No", - (tmp_reg & PORTSCX_PORT_EN_DIS_CHANGE) ? "Disable" : - "Not change", - (tmp_reg & PORTSCX_PORT_ENABLE) ? "Enable" : - "Not correct", - (tmp_reg & PORTSCX_CURRENT_CONNECT_STATUS) ? - "Attached" : "Not-Att"); - size -= t; - next += t; - - tmp_reg = fsl_readl(&dr_regs->usbmode); - t = scnprintf(next, size, - "USB Mode Reg: Controller Mode is: %s\n\n", ( { - char *s; - switch (tmp_reg & USB_MODE_CTRL_MODE_HOST) { - case USB_MODE_CTRL_MODE_IDLE: - s = "Idle"; break; - case USB_MODE_CTRL_MODE_DEVICE: - s = "Device Controller"; break; - case USB_MODE_CTRL_MODE_HOST: - s = "Host Controller"; break; - default: - s = "None"; break; - } - s; - } )); - size -= t; - next += t; - - tmp_reg = fsl_readl(&dr_regs->endptsetupstat); - t = scnprintf(next, size, - "Endpoint Setup Status Reg: SETUP on ep 0x%x\n\n", - (tmp_reg & EP_SETUP_STATUS_MASK)); - size -= t; - next += t; - - for (i = 0; i < udc->max_ep / 2; i++) { - tmp_reg = fsl_readl(&dr_regs->endptctrl[i]); - t = scnprintf(next, size, "EP Ctrl Reg [0x%x]: = [0x%x]\n", - i, tmp_reg); - size -= t; - next += t; - } - tmp_reg = fsl_readl(&dr_regs->endpointprime); - t = scnprintf(next, size, "EP Prime Reg = [0x%x]\n\n", tmp_reg); - size -= t; - next += t; - -#ifndef CONFIG_ARCH_MXC - if (udc->pdata->have_sysif_regs) { - tmp_reg = usb_sys_regs->snoop1; - t = scnprintf(next, size, "Snoop1 Reg : = [0x%x]\n\n", tmp_reg); - size -= t; - next += t; - - tmp_reg = usb_sys_regs->control; - t = scnprintf(next, size, "General Control Reg : = [0x%x]\n\n", - tmp_reg); - size -= t; - next += t; - } -#endif - - /* ------fsl_udc, fsl_ep, fsl_request structure information ----- */ - ep = &udc->eps[0]; - t = scnprintf(next, size, "For %s Maxpkt is 0x%x index is 0x%x\n", - ep->ep.name, ep_maxpacket(ep), ep_index(ep)); - size -= t; - next += t; - - if (list_empty(&ep->queue)) { - t = scnprintf(next, size, "its req queue is empty\n\n"); - size -= t; - next += t; - } else { - list_for_each_entry(req, &ep->queue, queue) { - t = scnprintf(next, size, - "req %p actual 0x%x length 0x%x buf %p\n", - &req->req, req->req.actual, - req->req.length, req->req.buf); - size -= t; - next += t; - } - } - /* other gadget->eplist ep */ - list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { - if (ep->desc) { - t = scnprintf(next, size, - "\nFor %s Maxpkt is 0x%x " - "index is 0x%x\n", - ep->ep.name, ep_maxpacket(ep), - ep_index(ep)); - size -= t; - next += t; - - if (list_empty(&ep->queue)) { - t = scnprintf(next, size, - "its req queue is empty\n\n"); - size -= t; - next += t; - } else { - list_for_each_entry(req, &ep->queue, queue) { - t = scnprintf(next, size, - "req %p actual 0x%x length " - "0x%x buf %p\n", - &req->req, req->req.actual, - req->req.length, req->req.buf); - size -= t; - next += t; - } /* end for each_entry of ep req */ - } /* end for else */ - } /* end for if(ep->queue) */ - } /* end (ep->desc) */ - - spin_unlock_irqrestore(&udc->lock, flags); - - *eof = 1; - return count - size; -} - -#define create_proc_file() create_proc_read_entry(proc_filename, \ - 0, NULL, fsl_proc_read, NULL) - -#define remove_proc_file() remove_proc_entry(proc_filename, NULL) - -#else /* !CONFIG_USB_GADGET_DEBUG_FILES */ - -#define create_proc_file() do {} while (0) -#define remove_proc_file() do {} while (0) - -#endif /* CONFIG_USB_GADGET_DEBUG_FILES */ - -/*-------------------------------------------------------------------------*/ - -/* Release udc structures */ -static void fsl_udc_release(struct device *dev) -{ - complete(udc_controller->done); - dma_free_coherent(dev->parent, udc_controller->ep_qh_size, - udc_controller->ep_qh, udc_controller->ep_qh_dma); - kfree(udc_controller); -} - -/****************************************************************** - Internal structure setup functions -*******************************************************************/ -/*------------------------------------------------------------------ - * init resource for globle controller - * Return the udc handle on success or NULL on failure - ------------------------------------------------------------------*/ -static int __init struct_udc_setup(struct fsl_udc *udc, - struct platform_device *pdev) -{ - struct fsl_usb2_platform_data *pdata; - size_t size; - - pdata = pdev->dev.platform_data; - udc->phy_mode = pdata->phy_mode; - - udc->eps = kzalloc(sizeof(struct fsl_ep) * udc->max_ep, GFP_KERNEL); - if (!udc->eps) { - ERR("malloc fsl_ep failed\n"); - return -1; - } - - /* initialized QHs, take care of alignment */ - size = udc->max_ep * sizeof(struct ep_queue_head); - if (size < QH_ALIGNMENT) - size = QH_ALIGNMENT; - else if ((size % QH_ALIGNMENT) != 0) { - size += QH_ALIGNMENT + 1; - size &= ~(QH_ALIGNMENT - 1); - } - udc->ep_qh = dma_alloc_coherent(&pdev->dev, size, - &udc->ep_qh_dma, GFP_KERNEL); - if (!udc->ep_qh) { - ERR("malloc QHs for udc failed\n"); - kfree(udc->eps); - return -1; - } - - udc->ep_qh_size = size; - - /* Initialize ep0 status request structure */ - /* FIXME: fsl_alloc_request() ignores ep argument */ - udc->status_req = container_of(fsl_alloc_request(NULL, GFP_KERNEL), - struct fsl_req, req); - /* allocate a small amount of memory to get valid address */ - udc->status_req->req.buf = kmalloc(8, GFP_KERNEL); - - udc->resume_state = USB_STATE_NOTATTACHED; - udc->usb_state = USB_STATE_POWERED; - udc->ep0_dir = 0; - udc->remote_wakeup = 0; /* default to 0 on reset */ - - return 0; -} - -/*---------------------------------------------------------------- - * Setup the fsl_ep struct for eps - * Link fsl_ep->ep to gadget->ep_list - * ep0out is not used so do nothing here - * ep0in should be taken care - *--------------------------------------------------------------*/ -static int __init struct_ep_setup(struct fsl_udc *udc, unsigned char index, - char *name, int link) -{ - struct fsl_ep *ep = &udc->eps[index]; - - ep->udc = udc; - strcpy(ep->name, name); - ep->ep.name = ep->name; - - ep->ep.ops = &fsl_ep_ops; - ep->stopped = 0; - - /* for ep0: maxP defined in desc - * for other eps, maxP is set by epautoconfig() called by gadget layer - */ - ep->ep.maxpacket = (unsigned short) ~0; - - /* the queue lists any req for this ep */ - INIT_LIST_HEAD(&ep->queue); - - /* gagdet.ep_list used for ep_autoconfig so no ep0 */ - if (link) - list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); - ep->gadget = &udc->gadget; - ep->qh = &udc->ep_qh[index]; - - return 0; -} - -/* Driver probe function - * all intialization operations implemented here except enabling usb_intr reg - * board setup should have been done in the platform code - */ -static int __init fsl_udc_probe(struct platform_device *pdev) -{ - struct fsl_usb2_platform_data *pdata; - struct resource *res; - int ret = -ENODEV; - unsigned int i; - u32 dccparams; - - if (strcmp(pdev->name, driver_name)) { - VDBG("Wrong device"); - return -ENODEV; - } - - udc_controller = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL); - if (udc_controller == NULL) { - ERR("malloc udc failed\n"); - return -ENOMEM; - } - - pdata = pdev->dev.platform_data; - udc_controller->pdata = pdata; - spin_lock_init(&udc_controller->lock); - udc_controller->stopped = 1; - -#ifdef CONFIG_USB_OTG - if (pdata->operating_mode == FSL_USB2_DR_OTG) { - udc_controller->transceiver = usb_get_transceiver(); - if (!udc_controller->transceiver) { - ERR("Can't find OTG driver!\n"); - ret = -ENODEV; - goto err_kfree; - } - } -#endif - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENXIO; - goto err_kfree; - } - - if (pdata->operating_mode == FSL_USB2_DR_DEVICE) { - if (!request_mem_region(res->start, resource_size(res), - driver_name)) { - ERR("request mem region for %s failed\n", pdev->name); - ret = -EBUSY; - goto err_kfree; - } - } - - dr_regs = ioremap(res->start, resource_size(res)); - if (!dr_regs) { - ret = -ENOMEM; - goto err_release_mem_region; - } - - pdata->regs = (void *)dr_regs; - - /* - * do platform specific init: check the clock, grab/config pins, etc. - */ - if (pdata->init && pdata->init(pdev)) { - ret = -ENODEV; - goto err_iounmap_noclk; - } - - /* Set accessors only after pdata->init() ! */ - fsl_set_accessors(pdata); - -#ifndef CONFIG_ARCH_MXC - if (pdata->have_sysif_regs) - usb_sys_regs = (void *)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); - if (!(dccparams & DCCPARAMS_DC)) { - ERR("This SOC doesn't support device role\n"); - ret = -ENODEV; - goto err_iounmap; - } - /* Get max device endpoints */ - /* DEN is bidirectional ep number, max_ep doubles the number */ - udc_controller->max_ep = (dccparams & DCCPARAMS_DEN_MASK) * 2; - - udc_controller->irq = platform_get_irq(pdev, 0); - if (!udc_controller->irq) { - ret = -ENODEV; - goto err_iounmap; - } - - ret = request_irq(udc_controller->irq, fsl_udc_irq, IRQF_SHARED, - driver_name, udc_controller); - if (ret != 0) { - ERR("cannot request irq %d err %d\n", - udc_controller->irq, ret); - goto err_iounmap; - } - - /* Initialize the udc structure including QH member and other member */ - if (struct_udc_setup(udc_controller, pdev)) { - ERR("Can't initialize udc data structure\n"); - ret = -ENOMEM; - goto err_free_irq; - } - - if (!udc_controller->transceiver) { - /* initialize usb hw reg except for regs for EP, - * 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.max_speed = USB_SPEED_HIGH; - udc_controller->gadget.ep0 = &udc_controller->eps[0].ep; - INIT_LIST_HEAD(&udc_controller->gadget.ep_list); - udc_controller->gadget.speed = USB_SPEED_UNKNOWN; - udc_controller->gadget.name = driver_name; - - /* Setup gadget.dev and register with kernel */ - dev_set_name(&udc_controller->gadget.dev, "gadget"); - udc_controller->gadget.dev.release = fsl_udc_release; - udc_controller->gadget.dev.parent = &pdev->dev; - ret = device_register(&udc_controller->gadget.dev); - if (ret < 0) - goto err_free_irq; - - if (udc_controller->transceiver) - udc_controller->gadget.is_otg = 1; - - /* setup QH and epctrl for ep0 */ - ep0_setup(udc_controller); - - /* setup udc->eps[] for ep0 */ - struct_ep_setup(udc_controller, 0, "ep0", 0); - /* for ep0: the desc defined here; - * for other eps, gadget layer called ep_enable with defined desc - */ - udc_controller->eps[0].desc = &fsl_ep0_desc; - udc_controller->eps[0].ep.maxpacket = USB_MAX_CTRL_PAYLOAD; - - /* setup the udc->eps[] for non-control endpoints and link - * to gadget.ep_list */ - for (i = 1; i < (int)(udc_controller->max_ep / 2); i++) { - char name[14]; - - sprintf(name, "ep%dout", i); - struct_ep_setup(udc_controller, i * 2, name, 1); - sprintf(name, "ep%din", i); - struct_ep_setup(udc_controller, i * 2 + 1, name, 1); - } - - /* use dma_pool for TD management */ - udc_controller->td_pool = dma_pool_create("udc_td", &pdev->dev, - sizeof(struct ep_td_struct), - DTD_ALIGNMENT, UDC_DMA_BOUNDARY); - if (udc_controller->td_pool == NULL) { - ret = -ENOMEM; - goto err_unregister; - } - - ret = usb_add_gadget_udc(&pdev->dev, &udc_controller->gadget); - if (ret) - goto err_del_udc; - - create_proc_file(); - return 0; - -err_del_udc: - dma_pool_destroy(udc_controller->td_pool); -err_unregister: - device_unregister(&udc_controller->gadget.dev); -err_free_irq: - free_irq(udc_controller->irq, udc_controller); -err_iounmap: - if (pdata->exit) - pdata->exit(pdev); - fsl_udc_clk_release(); -err_iounmap_noclk: - iounmap(dr_regs); -err_release_mem_region: - if (pdata->operating_mode == FSL_USB2_DR_DEVICE) - release_mem_region(res->start, resource_size(res)); -err_kfree: - kfree(udc_controller); - udc_controller = NULL; - return ret; -} - -/* Driver removal function - * Free resources and finish pending transactions - */ -static int __exit fsl_udc_remove(struct platform_device *pdev) -{ - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; - - DECLARE_COMPLETION(done); - - if (!udc_controller) - return -ENODEV; - - usb_del_gadget_udc(&udc_controller->gadget); - udc_controller->done = &done; - - fsl_udc_clk_release(); - - /* DR has been stopped in usb_gadget_unregister_driver() */ - remove_proc_file(); - - /* Free allocated memory */ - kfree(udc_controller->status_req->req.buf); - kfree(udc_controller->status_req); - kfree(udc_controller->eps); - - dma_pool_destroy(udc_controller->td_pool); - free_irq(udc_controller->irq, udc_controller); - iounmap(dr_regs); - if (pdata->operating_mode == FSL_USB2_DR_DEVICE) - release_mem_region(res->start, resource_size(res)); - - device_unregister(&udc_controller->gadget.dev); - /* free udc --wait for the release() finished */ - wait_for_completion(&done); - - /* - * do platform specific un-initialization: - * release iomux pins, etc. - */ - if (pdata->exit) - pdata->exit(pdev); - - return 0; -} - -/*----------------------------------------------------------------- - * Modify Power management attributes - * Used by OTG statemachine to disable gadget temporarily - -----------------------------------------------------------------*/ -static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state) -{ - dr_controller_stop(udc_controller); - return 0; -} - -/*----------------------------------------------------------------- - * Invoked on USB resume. May be called in_interrupt. - * Here we start the DR controller and enable the irq - *-----------------------------------------------------------------*/ -static int fsl_udc_resume(struct platform_device *pdev) -{ - /* Enable DR irq reg and set controller Run */ - if (udc_controller->stopped) { - dr_controller_setup(udc_controller); - dr_controller_run(udc_controller); - } - udc_controller->usb_state = USB_STATE_ATTACHED; - udc_controller->ep0_state = WAIT_FOR_SETUP; - udc_controller->ep0_dir = 0; - return 0; -} - -static int fsl_udc_otg_suspend(struct device *dev, pm_message_t state) -{ - struct fsl_udc *udc = udc_controller; - u32 mode, usbcmd; - - mode = fsl_readl(&dr_regs->usbmode) & USB_MODE_CTRL_MODE_MASK; - - pr_debug("%s(): mode 0x%x stopped %d\n", __func__, mode, udc->stopped); - - /* - * If the controller is already stopped, then this must be a - * PM suspend. Remember this fact, so that we will leave the - * controller stopped at PM resume time. - */ - if (udc->stopped) { - pr_debug("gadget already stopped, leaving early\n"); - udc->already_stopped = 1; - return 0; - } - - if (mode != USB_MODE_CTRL_MODE_DEVICE) { - pr_debug("gadget not in device mode, leaving early\n"); - return 0; - } - - /* stop the controller */ - usbcmd = fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP; - fsl_writel(usbcmd, &dr_regs->usbcmd); - - udc->stopped = 1; - - pr_info("USB Gadget suspended\n"); - - return 0; -} - -static int fsl_udc_otg_resume(struct device *dev) -{ - pr_debug("%s(): stopped %d already_stopped %d\n", __func__, - udc_controller->stopped, udc_controller->already_stopped); - - /* - * If the controller was stopped at suspend time, then - * don't resume it now. - */ - if (udc_controller->already_stopped) { - udc_controller->already_stopped = 0; - pr_debug("gadget was already stopped, leaving early\n"); - return 0; - } - - pr_info("USB Gadget resume\n"); - - return fsl_udc_resume(NULL); -} - -/*------------------------------------------------------------------------- - Register entry point for the peripheral controller driver ---------------------------------------------------------------------------*/ - -static struct platform_driver udc_driver = { - .remove = __exit_p(fsl_udc_remove), - /* these suspend and resume are not usb suspend and resume */ - .suspend = fsl_udc_suspend, - .resume = fsl_udc_resume, - .driver = { - .name = (char *)driver_name, - .owner = THIS_MODULE, - /* udc suspend/resume called from OTG driver */ - .suspend = fsl_udc_otg_suspend, - .resume = fsl_udc_otg_resume, - }, -}; - -static int __init udc_init(void) -{ - printk(KERN_INFO "%s (%s)\n", driver_desc, DRIVER_VERSION); - return platform_driver_probe(&udc_driver, fsl_udc_probe); -} - -module_init(udc_init); - -static void __exit udc_exit(void) -{ - platform_driver_unregister(&udc_driver); - printk(KERN_WARNING "%s unregistered\n", driver_desc); -} - -module_exit(udc_exit); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:fsl-usb2-udc"); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/fsl_usb2_udc.h b/ANDROID_3.4.5/drivers/usb/gadget/fsl_usb2_udc.h deleted file mode 100644 index e651469f..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/fsl_usb2_udc.h +++ /dev/null @@ -1,600 +0,0 @@ -/* - * Freescale USB device/endpoint management registers - */ -#ifndef __FSL_USB2_UDC_H -#define __FSL_USB2_UDC_H - -/* ### define USB registers here - */ -#define USB_MAX_CTRL_PAYLOAD 64 -#define USB_DR_SYS_OFFSET 0x400 - - /* USB DR device mode registers (Little Endian) */ -struct usb_dr_device { - /* Capability register */ - u8 res1[256]; - u16 caplength; /* Capability Register Length */ - u16 hciversion; /* Host Controller Interface Version */ - u32 hcsparams; /* Host Controller Structural Parameters */ - u32 hccparams; /* Host Controller Capability Parameters */ - u8 res2[20]; - u32 dciversion; /* Device Controller Interface Version */ - u32 dccparams; /* Device Controller Capability Parameters */ - u8 res3[24]; - /* Operation register */ - u32 usbcmd; /* USB Command Register */ - u32 usbsts; /* USB Status Register */ - u32 usbintr; /* USB Interrupt Enable Register */ - u32 frindex; /* Frame Index Register */ - u8 res4[4]; - u32 deviceaddr; /* Device Address */ - u32 endpointlistaddr; /* Endpoint List Address Register */ - u8 res5[4]; - u32 burstsize; /* Master Interface Data Burst Size Register */ - u32 txttfilltuning; /* Transmit FIFO Tuning Controls Register */ - u8 res6[24]; - u32 configflag; /* Configure Flag Register */ - u32 portsc1; /* Port 1 Status and Control Register */ - u8 res7[28]; - u32 otgsc; /* On-The-Go Status and Control */ - u32 usbmode; /* USB Mode Register */ - u32 endptsetupstat; /* Endpoint Setup Status Register */ - u32 endpointprime; /* Endpoint Initialization Register */ - u32 endptflush; /* Endpoint Flush Register */ - u32 endptstatus; /* Endpoint Status Register */ - u32 endptcomplete; /* Endpoint Complete Register */ - u32 endptctrl[6]; /* Endpoint Control Registers */ -}; - - /* USB DR host mode registers (Little Endian) */ -struct usb_dr_host { - /* Capability register */ - u8 res1[256]; - u16 caplength; /* Capability Register Length */ - u16 hciversion; /* Host Controller Interface Version */ - u32 hcsparams; /* Host Controller Structural Parameters */ - u32 hccparams; /* Host Controller Capability Parameters */ - u8 res2[20]; - u32 dciversion; /* Device Controller Interface Version */ - u32 dccparams; /* Device Controller Capability Parameters */ - u8 res3[24]; - /* Operation register */ - u32 usbcmd; /* USB Command Register */ - u32 usbsts; /* USB Status Register */ - u32 usbintr; /* USB Interrupt Enable Register */ - u32 frindex; /* Frame Index Register */ - u8 res4[4]; - u32 periodiclistbase; /* Periodic Frame List Base Address Register */ - u32 asynclistaddr; /* Current Asynchronous List Address Register */ - u8 res5[4]; - u32 burstsize; /* Master Interface Data Burst Size Register */ - u32 txttfilltuning; /* Transmit FIFO Tuning Controls Register */ - u8 res6[24]; - u32 configflag; /* Configure Flag Register */ - u32 portsc1; /* Port 1 Status and Control Register */ - u8 res7[28]; - u32 otgsc; /* On-The-Go Status and Control */ - u32 usbmode; /* USB Mode Register */ - u32 endptsetupstat; /* Endpoint Setup Status Register */ - u32 endpointprime; /* Endpoint Initialization Register */ - u32 endptflush; /* Endpoint Flush Register */ - u32 endptstatus; /* Endpoint Status Register */ - u32 endptcomplete; /* Endpoint Complete Register */ - u32 endptctrl[6]; /* Endpoint Control Registers */ -}; - - /* non-EHCI USB system interface registers (Big Endian) */ -struct usb_sys_interface { - u32 snoop1; - u32 snoop2; - u32 age_cnt_thresh; /* Age Count Threshold Register */ - u32 pri_ctrl; /* Priority Control Register */ - u32 si_ctrl; /* System Interface Control Register */ - u8 res[236]; - u32 control; /* General Purpose Control Register */ -}; - -/* ep0 transfer state */ -#define WAIT_FOR_SETUP 0 -#define DATA_STATE_XMIT 1 -#define DATA_STATE_NEED_ZLP 2 -#define WAIT_FOR_OUT_STATUS 3 -#define DATA_STATE_RECV 4 - -/* Device Controller Capability Parameter register */ -#define DCCPARAMS_DC 0x00000080 -#define DCCPARAMS_DEN_MASK 0x0000001f - -/* Frame Index Register Bit Masks */ -#define USB_FRINDEX_MASKS 0x3fff -/* USB CMD Register Bit Masks */ -#define USB_CMD_RUN_STOP 0x00000001 -#define USB_CMD_CTRL_RESET 0x00000002 -#define USB_CMD_PERIODIC_SCHEDULE_EN 0x00000010 -#define USB_CMD_ASYNC_SCHEDULE_EN 0x00000020 -#define USB_CMD_INT_AA_DOORBELL 0x00000040 -#define USB_CMD_ASP 0x00000300 -#define USB_CMD_ASYNC_SCH_PARK_EN 0x00000800 -#define USB_CMD_SUTW 0x00002000 -#define USB_CMD_ATDTW 0x00004000 -#define USB_CMD_ITC 0x00FF0000 - -/* bit 15,3,2 are frame list size */ -#define USB_CMD_FRAME_SIZE_1024 0x00000000 -#define USB_CMD_FRAME_SIZE_512 0x00000004 -#define USB_CMD_FRAME_SIZE_256 0x00000008 -#define USB_CMD_FRAME_SIZE_128 0x0000000C -#define USB_CMD_FRAME_SIZE_64 0x00008000 -#define USB_CMD_FRAME_SIZE_32 0x00008004 -#define USB_CMD_FRAME_SIZE_16 0x00008008 -#define USB_CMD_FRAME_SIZE_8 0x0000800C - -/* bit 9-8 are async schedule park mode count */ -#define USB_CMD_ASP_00 0x00000000 -#define USB_CMD_ASP_01 0x00000100 -#define USB_CMD_ASP_10 0x00000200 -#define USB_CMD_ASP_11 0x00000300 -#define USB_CMD_ASP_BIT_POS 8 - -/* bit 23-16 are interrupt threshold control */ -#define USB_CMD_ITC_NO_THRESHOLD 0x00000000 -#define USB_CMD_ITC_1_MICRO_FRM 0x00010000 -#define USB_CMD_ITC_2_MICRO_FRM 0x00020000 -#define USB_CMD_ITC_4_MICRO_FRM 0x00040000 -#define USB_CMD_ITC_8_MICRO_FRM 0x00080000 -#define USB_CMD_ITC_16_MICRO_FRM 0x00100000 -#define USB_CMD_ITC_32_MICRO_FRM 0x00200000 -#define USB_CMD_ITC_64_MICRO_FRM 0x00400000 -#define USB_CMD_ITC_BIT_POS 16 - -/* USB STS Register Bit Masks */ -#define USB_STS_INT 0x00000001 -#define USB_STS_ERR 0x00000002 -#define USB_STS_PORT_CHANGE 0x00000004 -#define USB_STS_FRM_LST_ROLL 0x00000008 -#define USB_STS_SYS_ERR 0x00000010 -#define USB_STS_IAA 0x00000020 -#define USB_STS_RESET 0x00000040 -#define USB_STS_SOF 0x00000080 -#define USB_STS_SUSPEND 0x00000100 -#define USB_STS_HC_HALTED 0x00001000 -#define USB_STS_RCL 0x00002000 -#define USB_STS_PERIODIC_SCHEDULE 0x00004000 -#define USB_STS_ASYNC_SCHEDULE 0x00008000 - -/* USB INTR Register Bit Masks */ -#define USB_INTR_INT_EN 0x00000001 -#define USB_INTR_ERR_INT_EN 0x00000002 -#define USB_INTR_PTC_DETECT_EN 0x00000004 -#define USB_INTR_FRM_LST_ROLL_EN 0x00000008 -#define USB_INTR_SYS_ERR_EN 0x00000010 -#define USB_INTR_ASYN_ADV_EN 0x00000020 -#define USB_INTR_RESET_EN 0x00000040 -#define USB_INTR_SOF_EN 0x00000080 -#define USB_INTR_DEVICE_SUSPEND 0x00000100 - -/* Device Address bit masks */ -#define USB_DEVICE_ADDRESS_MASK 0xFE000000 -#define USB_DEVICE_ADDRESS_BIT_POS 25 - -/* endpoint list address bit masks */ -#define USB_EP_LIST_ADDRESS_MASK 0xfffff800 - -/* PORTSCX Register Bit Masks */ -#define PORTSCX_CURRENT_CONNECT_STATUS 0x00000001 -#define PORTSCX_CONNECT_STATUS_CHANGE 0x00000002 -#define PORTSCX_PORT_ENABLE 0x00000004 -#define PORTSCX_PORT_EN_DIS_CHANGE 0x00000008 -#define PORTSCX_OVER_CURRENT_ACT 0x00000010 -#define PORTSCX_OVER_CURRENT_CHG 0x00000020 -#define PORTSCX_PORT_FORCE_RESUME 0x00000040 -#define PORTSCX_PORT_SUSPEND 0x00000080 -#define PORTSCX_PORT_RESET 0x00000100 -#define PORTSCX_LINE_STATUS_BITS 0x00000C00 -#define PORTSCX_PORT_POWER 0x00001000 -#define PORTSCX_PORT_INDICTOR_CTRL 0x0000C000 -#define PORTSCX_PORT_TEST_CTRL 0x000F0000 -#define PORTSCX_WAKE_ON_CONNECT_EN 0x00100000 -#define PORTSCX_WAKE_ON_CONNECT_DIS 0x00200000 -#define PORTSCX_WAKE_ON_OVER_CURRENT 0x00400000 -#define PORTSCX_PHY_LOW_POWER_SPD 0x00800000 -#define PORTSCX_PORT_FORCE_FULL_SPEED 0x01000000 -#define PORTSCX_PORT_SPEED_MASK 0x0C000000 -#define PORTSCX_PORT_WIDTH 0x10000000 -#define PORTSCX_PHY_TYPE_SEL 0xC0000000 - -/* bit 11-10 are line status */ -#define PORTSCX_LINE_STATUS_SE0 0x00000000 -#define PORTSCX_LINE_STATUS_JSTATE 0x00000400 -#define PORTSCX_LINE_STATUS_KSTATE 0x00000800 -#define PORTSCX_LINE_STATUS_UNDEF 0x00000C00 -#define PORTSCX_LINE_STATUS_BIT_POS 10 - -/* bit 15-14 are port indicator control */ -#define PORTSCX_PIC_OFF 0x00000000 -#define PORTSCX_PIC_AMBER 0x00004000 -#define PORTSCX_PIC_GREEN 0x00008000 -#define PORTSCX_PIC_UNDEF 0x0000C000 -#define PORTSCX_PIC_BIT_POS 14 - -/* bit 19-16 are port test control */ -#define PORTSCX_PTC_DISABLE 0x00000000 -#define PORTSCX_PTC_JSTATE 0x00010000 -#define PORTSCX_PTC_KSTATE 0x00020000 -#define PORTSCX_PTC_SEQNAK 0x00030000 -#define PORTSCX_PTC_PACKET 0x00040000 -#define PORTSCX_PTC_FORCE_EN 0x00050000 -#define PORTSCX_PTC_BIT_POS 16 - -/* bit 27-26 are port speed */ -#define PORTSCX_PORT_SPEED_FULL 0x00000000 -#define PORTSCX_PORT_SPEED_LOW 0x04000000 -#define PORTSCX_PORT_SPEED_HIGH 0x08000000 -#define PORTSCX_PORT_SPEED_UNDEF 0x0C000000 -#define PORTSCX_SPEED_BIT_POS 26 - -/* bit 28 is parallel transceiver width for UTMI interface */ -#define PORTSCX_PTW 0x10000000 -#define PORTSCX_PTW_8BIT 0x00000000 -#define PORTSCX_PTW_16BIT 0x10000000 - -/* bit 31-30 are port transceiver select */ -#define PORTSCX_PTS_UTMI 0x00000000 -#define PORTSCX_PTS_ULPI 0x80000000 -#define PORTSCX_PTS_FSLS 0xC0000000 -#define PORTSCX_PTS_BIT_POS 30 - -/* otgsc Register Bit Masks */ -#define OTGSC_CTRL_VUSB_DISCHARGE 0x00000001 -#define OTGSC_CTRL_VUSB_CHARGE 0x00000002 -#define OTGSC_CTRL_OTG_TERM 0x00000008 -#define OTGSC_CTRL_DATA_PULSING 0x00000010 -#define OTGSC_STS_USB_ID 0x00000100 -#define OTGSC_STS_A_VBUS_VALID 0x00000200 -#define OTGSC_STS_A_SESSION_VALID 0x00000400 -#define OTGSC_STS_B_SESSION_VALID 0x00000800 -#define OTGSC_STS_B_SESSION_END 0x00001000 -#define OTGSC_STS_1MS_TOGGLE 0x00002000 -#define OTGSC_STS_DATA_PULSING 0x00004000 -#define OTGSC_INTSTS_USB_ID 0x00010000 -#define OTGSC_INTSTS_A_VBUS_VALID 0x00020000 -#define OTGSC_INTSTS_A_SESSION_VALID 0x00040000 -#define OTGSC_INTSTS_B_SESSION_VALID 0x00080000 -#define OTGSC_INTSTS_B_SESSION_END 0x00100000 -#define OTGSC_INTSTS_1MS 0x00200000 -#define OTGSC_INTSTS_DATA_PULSING 0x00400000 -#define OTGSC_INTR_USB_ID 0x01000000 -#define OTGSC_INTR_A_VBUS_VALID 0x02000000 -#define OTGSC_INTR_A_SESSION_VALID 0x04000000 -#define OTGSC_INTR_B_SESSION_VALID 0x08000000 -#define OTGSC_INTR_B_SESSION_END 0x10000000 -#define OTGSC_INTR_1MS_TIMER 0x20000000 -#define OTGSC_INTR_DATA_PULSING 0x40000000 - -/* USB MODE Register Bit Masks */ -#define USB_MODE_CTRL_MODE_IDLE 0x00000000 -#define USB_MODE_CTRL_MODE_DEVICE 0x00000002 -#define USB_MODE_CTRL_MODE_HOST 0x00000003 -#define USB_MODE_CTRL_MODE_MASK 0x00000003 -#define USB_MODE_CTRL_MODE_RSV 0x00000001 -#define USB_MODE_ES 0x00000004 /* Endian Select */ -#define USB_MODE_SETUP_LOCK_OFF 0x00000008 -#define USB_MODE_STREAM_DISABLE 0x00000010 -/* Endpoint Flush Register */ -#define EPFLUSH_TX_OFFSET 0x00010000 -#define EPFLUSH_RX_OFFSET 0x00000000 - -/* Endpoint Setup Status bit masks */ -#define EP_SETUP_STATUS_MASK 0x0000003F -#define EP_SETUP_STATUS_EP0 0x00000001 - -/* ENDPOINTCTRLx Register Bit Masks */ -#define EPCTRL_TX_ENABLE 0x00800000 -#define EPCTRL_TX_DATA_TOGGLE_RST 0x00400000 /* Not EP0 */ -#define EPCTRL_TX_DATA_TOGGLE_INH 0x00200000 /* Not EP0 */ -#define EPCTRL_TX_TYPE 0x000C0000 -#define EPCTRL_TX_DATA_SOURCE 0x00020000 /* Not EP0 */ -#define EPCTRL_TX_EP_STALL 0x00010000 -#define EPCTRL_RX_ENABLE 0x00000080 -#define EPCTRL_RX_DATA_TOGGLE_RST 0x00000040 /* Not EP0 */ -#define EPCTRL_RX_DATA_TOGGLE_INH 0x00000020 /* Not EP0 */ -#define EPCTRL_RX_TYPE 0x0000000C -#define EPCTRL_RX_DATA_SINK 0x00000002 /* Not EP0 */ -#define EPCTRL_RX_EP_STALL 0x00000001 - -/* bit 19-18 and 3-2 are endpoint type */ -#define EPCTRL_EP_TYPE_CONTROL 0 -#define EPCTRL_EP_TYPE_ISO 1 -#define EPCTRL_EP_TYPE_BULK 2 -#define EPCTRL_EP_TYPE_INTERRUPT 3 -#define EPCTRL_TX_EP_TYPE_SHIFT 18 -#define EPCTRL_RX_EP_TYPE_SHIFT 2 - -/* SNOOPn Register Bit Masks */ -#define SNOOP_ADDRESS_MASK 0xFFFFF000 -#define SNOOP_SIZE_ZERO 0x00 /* snooping disable */ -#define SNOOP_SIZE_4KB 0x0B /* 4KB snoop size */ -#define SNOOP_SIZE_8KB 0x0C -#define SNOOP_SIZE_16KB 0x0D -#define SNOOP_SIZE_32KB 0x0E -#define SNOOP_SIZE_64KB 0x0F -#define SNOOP_SIZE_128KB 0x10 -#define SNOOP_SIZE_256KB 0x11 -#define SNOOP_SIZE_512KB 0x12 -#define SNOOP_SIZE_1MB 0x13 -#define SNOOP_SIZE_2MB 0x14 -#define SNOOP_SIZE_4MB 0x15 -#define SNOOP_SIZE_8MB 0x16 -#define SNOOP_SIZE_16MB 0x17 -#define SNOOP_SIZE_32MB 0x18 -#define SNOOP_SIZE_64MB 0x19 -#define SNOOP_SIZE_128MB 0x1A -#define SNOOP_SIZE_256MB 0x1B -#define SNOOP_SIZE_512MB 0x1C -#define SNOOP_SIZE_1GB 0x1D -#define SNOOP_SIZE_2GB 0x1E /* 2GB snoop size */ - -/* pri_ctrl Register Bit Masks */ -#define PRI_CTRL_PRI_LVL1 0x0000000C -#define PRI_CTRL_PRI_LVL0 0x00000003 - -/* si_ctrl Register Bit Masks */ -#define SI_CTRL_ERR_DISABLE 0x00000010 -#define SI_CTRL_IDRC_DISABLE 0x00000008 -#define SI_CTRL_RD_SAFE_EN 0x00000004 -#define SI_CTRL_RD_PREFETCH_DISABLE 0x00000002 -#define SI_CTRL_RD_PREFEFETCH_VAL 0x00000001 - -/* control Register Bit Masks */ -#define USB_CTRL_IOENB 0x00000004 -#define USB_CTRL_ULPI_INT0EN 0x00000001 - -/* Endpoint Queue Head data struct - * Rem: all the variables of qh are LittleEndian Mode - * and NEXT_POINTER_MASK should operate on a LittleEndian, Phy Addr - */ -struct ep_queue_head { - u32 max_pkt_length; /* Mult(31-30) , Zlt(29) , Max Pkt len - and IOS(15) */ - u32 curr_dtd_ptr; /* Current dTD Pointer(31-5) */ - u32 next_dtd_ptr; /* Next dTD Pointer(31-5), T(0) */ - u32 size_ioc_int_sts; /* Total bytes (30-16), IOC (15), - MultO(11-10), STS (7-0) */ - u32 buff_ptr0; /* Buffer pointer Page 0 (31-12) */ - u32 buff_ptr1; /* Buffer pointer Page 1 (31-12) */ - u32 buff_ptr2; /* Buffer pointer Page 2 (31-12) */ - u32 buff_ptr3; /* Buffer pointer Page 3 (31-12) */ - u32 buff_ptr4; /* Buffer pointer Page 4 (31-12) */ - u32 res1; - u8 setup_buffer[8]; /* Setup data 8 bytes */ - u32 res2[4]; -}; - -/* Endpoint Queue Head Bit Masks */ -#define EP_QUEUE_HEAD_MULT_POS 30 -#define EP_QUEUE_HEAD_ZLT_SEL 0x20000000 -#define EP_QUEUE_HEAD_MAX_PKT_LEN_POS 16 -#define EP_QUEUE_HEAD_MAX_PKT_LEN(ep_info) (((ep_info)>>16)&0x07ff) -#define EP_QUEUE_HEAD_IOS 0x00008000 -#define EP_QUEUE_HEAD_NEXT_TERMINATE 0x00000001 -#define EP_QUEUE_HEAD_IOC 0x00008000 -#define EP_QUEUE_HEAD_MULTO 0x00000C00 -#define EP_QUEUE_HEAD_STATUS_HALT 0x00000040 -#define EP_QUEUE_HEAD_STATUS_ACTIVE 0x00000080 -#define EP_QUEUE_CURRENT_OFFSET_MASK 0x00000FFF -#define EP_QUEUE_HEAD_NEXT_POINTER_MASK 0xFFFFFFE0 -#define EP_QUEUE_FRINDEX_MASK 0x000007FF -#define EP_MAX_LENGTH_TRANSFER 0x4000 - -/* Endpoint Transfer Descriptor data struct */ -/* Rem: all the variables of td are LittleEndian Mode */ -struct ep_td_struct { - u32 next_td_ptr; /* Next TD pointer(31-5), T(0) set - indicate invalid */ - u32 size_ioc_sts; /* Total bytes (30-16), IOC (15), - MultO(11-10), STS (7-0) */ - u32 buff_ptr0; /* Buffer pointer Page 0 */ - u32 buff_ptr1; /* Buffer pointer Page 1 */ - u32 buff_ptr2; /* Buffer pointer Page 2 */ - u32 buff_ptr3; /* Buffer pointer Page 3 */ - u32 buff_ptr4; /* Buffer pointer Page 4 */ - u32 res; - /* 32 bytes */ - dma_addr_t td_dma; /* dma address for this td */ - /* virtual address of next td specified in next_td_ptr */ - struct ep_td_struct *next_td_virt; -}; - -/* Endpoint Transfer Descriptor bit Masks */ -#define DTD_NEXT_TERMINATE 0x00000001 -#define DTD_IOC 0x00008000 -#define DTD_STATUS_ACTIVE 0x00000080 -#define DTD_STATUS_HALTED 0x00000040 -#define DTD_STATUS_DATA_BUFF_ERR 0x00000020 -#define DTD_STATUS_TRANSACTION_ERR 0x00000008 -#define DTD_RESERVED_FIELDS 0x80007300 -#define DTD_ADDR_MASK 0xFFFFFFE0 -#define DTD_PACKET_SIZE 0x7FFF0000 -#define DTD_LENGTH_BIT_POS 16 -#define DTD_ERROR_MASK (DTD_STATUS_HALTED | \ - DTD_STATUS_DATA_BUFF_ERR | \ - DTD_STATUS_TRANSACTION_ERR) -/* Alignment requirements; must be a power of two */ -#define DTD_ALIGNMENT 0x20 -#define QH_ALIGNMENT 2048 - -/* Controller dma boundary */ -#define UDC_DMA_BOUNDARY 0x1000 - -/*-------------------------------------------------------------------------*/ - -/* ### driver private data - */ -struct fsl_req { - struct usb_request req; - struct list_head queue; - /* ep_queue() func will add - a request->queue into a udc_ep->queue 'd tail */ - struct fsl_ep *ep; - unsigned mapped:1; - - struct ep_td_struct *head, *tail; /* For dTD List - cpu endian Virtual addr */ - unsigned int dtd_count; -}; - -#define REQ_UNCOMPLETE 1 - -struct fsl_ep { - struct usb_ep ep; - struct list_head queue; - struct fsl_udc *udc; - struct ep_queue_head *qh; - const struct usb_endpoint_descriptor *desc; - struct usb_gadget *gadget; - - char name[14]; - unsigned stopped:1; -}; - -#define EP_DIR_IN 1 -#define EP_DIR_OUT 0 - -struct fsl_udc { - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - struct fsl_usb2_platform_data *pdata; - struct completion *done; /* to make sure release() is done */ - struct fsl_ep *eps; - unsigned int max_ep; - unsigned int irq; - - struct usb_ctrlrequest local_setup_buff; - spinlock_t lock; - struct usb_phy *transceiver; - unsigned softconnect:1; - unsigned vbus_active:1; - unsigned stopped:1; - unsigned remote_wakeup:1; - unsigned already_stopped:1; - unsigned big_endian_desc:1; - - struct ep_queue_head *ep_qh; /* Endpoints Queue-Head */ - struct fsl_req *status_req; /* ep0 status request */ - struct dma_pool *td_pool; /* dma pool for DTD */ - enum fsl_usb2_phy_modes phy_mode; - - size_t ep_qh_size; /* size after alignment adjustment*/ - dma_addr_t ep_qh_dma; /* dma address of QH */ - - u32 max_pipes; /* Device max pipes */ - u32 bus_reset; /* Device is bus resetting */ - u32 resume_state; /* USB state to resume */ - u32 usb_state; /* USB current state */ - u32 ep0_state; /* Endpoint zero state */ - u32 ep0_dir; /* Endpoint zero direction: can be - USB_DIR_IN or USB_DIR_OUT */ - u8 device_address; /* Device USB address */ -}; - -/*-------------------------------------------------------------------------*/ - -#ifdef DEBUG -#define DBG(fmt, args...) printk(KERN_DEBUG "[%s] " fmt "\n", \ - __func__, ## args) -#else -#define DBG(fmt, args...) do{}while(0) -#endif - -#if 0 -static void dump_msg(const char *label, const u8 * buf, unsigned int length) -{ - unsigned int start, num, i; - char line[52], *p; - - if (length >= 512) - return; - DBG("%s, length %u:\n", label, length); - start = 0; - while (length > 0) { - num = min(length, 16u); - p = line; - for (i = 0; i < num; ++i) { - if (i == 8) - *p++ = ' '; - sprintf(p, " %02x", buf[i]); - p += 3; - } - *p = 0; - printk(KERN_DEBUG "%6x: %s\n", start, line); - buf += num; - start += num; - length -= num; - } -} -#endif - -#ifdef VERBOSE -#define VDBG DBG -#else -#define VDBG(stuff...) do{}while(0) -#endif - -#define ERR(stuff...) pr_err("udc: " stuff) -#define WARNING(stuff...) pr_warning("udc: " stuff) -#define INFO(stuff...) pr_info("udc: " stuff) - -/*-------------------------------------------------------------------------*/ - -/* ### Add board specific defines here - */ - -/* - * ### pipe direction macro from device view - */ -#define USB_RECV 0 /* OUT EP */ -#define USB_SEND 1 /* IN EP */ - -/* - * ### internal used help routines. - */ -#define ep_index(EP) ((EP)->desc->bEndpointAddress&0xF) -#define ep_maxpacket(EP) ((EP)->ep.maxpacket) -#define ep_is_in(EP) ( (ep_index(EP) == 0) ? (EP->udc->ep0_dir == \ - USB_DIR_IN ):((EP)->desc->bEndpointAddress \ - & USB_DIR_IN)==USB_DIR_IN) -#define get_ep_by_pipe(udc, pipe) ((pipe == 1)? &udc->eps[0]: \ - &udc->eps[pipe]) -#define get_pipe_by_windex(windex) ((windex & USB_ENDPOINT_NUMBER_MASK) \ - * 2 + ((windex & USB_DIR_IN) ? 1 : 0)) -#define get_pipe_by_ep(EP) (ep_index(EP) * 2 + ep_is_in(EP)) - -static inline struct ep_queue_head *get_qh_by_ep(struct fsl_ep *ep) -{ - /* we only have one ep0 structure but two queue heads */ - if (ep_index(ep) != 0) - return ep->qh; - else - return &ep->udc->ep_qh[(ep->udc->ep0_dir == - USB_DIR_IN) ? 1 : 0]; -} - -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 diff --git a/ANDROID_3.4.5/drivers/usb/gadget/fusb300_udc.c b/ANDROID_3.4.5/drivers/usb/gadget/fusb300_udc.c deleted file mode 100644 index 5831cb4a..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/fusb300_udc.c +++ /dev/null @@ -1,1561 +0,0 @@ -/* - * Fusb300 UDC (USB gadget) - * - * Copyright (C) 2010 Faraday Technology Corp. - * - * Author : Yuan-hsin Chen - * - * 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; version 2 of the License. - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "fusb300_udc.h" - -MODULE_DESCRIPTION("FUSB300 USB gadget driver"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Yuan Hsin Chen "); -MODULE_ALIAS("platform:fusb300_udc"); - -#define DRIVER_VERSION "20 October 2010" - -static const char udc_name[] = "fusb300_udc"; -static const char * const fusb300_ep_name[] = { - "ep0", "ep1", "ep2", "ep3", "ep4", "ep5", "ep6", "ep7", "ep8", "ep9", - "ep10", "ep11", "ep12", "ep13", "ep14", "ep15" -}; - -static void done(struct fusb300_ep *ep, struct fusb300_request *req, - int status); - -static void fusb300_enable_bit(struct fusb300 *fusb300, u32 offset, - u32 value) -{ - u32 reg = ioread32(fusb300->reg + offset); - - reg |= value; - iowrite32(reg, fusb300->reg + offset); -} - -static void fusb300_disable_bit(struct fusb300 *fusb300, u32 offset, - u32 value) -{ - u32 reg = ioread32(fusb300->reg + offset); - - reg &= ~value; - iowrite32(reg, fusb300->reg + offset); -} - - -static void fusb300_ep_setting(struct fusb300_ep *ep, - struct fusb300_ep_info info) -{ - ep->epnum = info.epnum; - ep->type = info.type; -} - -static int fusb300_ep_release(struct fusb300_ep *ep) -{ - if (!ep->epnum) - return 0; - ep->epnum = 0; - ep->stall = 0; - ep->wedged = 0; - return 0; -} - -static void fusb300_set_fifo_entry(struct fusb300 *fusb300, - u32 ep) -{ - u32 val = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(ep)); - - val &= ~FUSB300_EPSET1_FIFOENTRY_MSK; - val |= FUSB300_EPSET1_FIFOENTRY(FUSB300_FIFO_ENTRY_NUM); - iowrite32(val, fusb300->reg + FUSB300_OFFSET_EPSET1(ep)); -} - -static void fusb300_set_start_entry(struct fusb300 *fusb300, - u8 ep) -{ - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(ep)); - u32 start_entry = fusb300->fifo_entry_num * FUSB300_FIFO_ENTRY_NUM; - - reg &= ~FUSB300_EPSET1_START_ENTRY_MSK ; - reg |= FUSB300_EPSET1_START_ENTRY(start_entry); - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(ep)); - if (fusb300->fifo_entry_num == FUSB300_MAX_FIFO_ENTRY) { - fusb300->fifo_entry_num = 0; - fusb300->addrofs = 0; - pr_err("fifo entry is over the maximum number!\n"); - } else - fusb300->fifo_entry_num++; -} - -/* set fusb300_set_start_entry first before fusb300_set_epaddrofs */ -static void fusb300_set_epaddrofs(struct fusb300 *fusb300, - struct fusb300_ep_info info) -{ - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum)); - - reg &= ~FUSB300_EPSET2_ADDROFS_MSK; - reg |= FUSB300_EPSET2_ADDROFS(fusb300->addrofs); - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum)); - fusb300->addrofs += (info.maxpacket + 7) / 8 * FUSB300_FIFO_ENTRY_NUM; -} - -static void ep_fifo_setting(struct fusb300 *fusb300, - struct fusb300_ep_info info) -{ - fusb300_set_fifo_entry(fusb300, info.epnum); - fusb300_set_start_entry(fusb300, info.epnum); - fusb300_set_epaddrofs(fusb300, info); -} - -static void fusb300_set_eptype(struct fusb300 *fusb300, - struct fusb300_ep_info info) -{ - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); - - reg &= ~FUSB300_EPSET1_TYPE_MSK; - reg |= FUSB300_EPSET1_TYPE(info.type); - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); -} - -static void fusb300_set_epdir(struct fusb300 *fusb300, - struct fusb300_ep_info info) -{ - u32 reg; - - if (!info.dir_in) - return; - reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); - reg &= ~FUSB300_EPSET1_DIR_MSK; - reg |= FUSB300_EPSET1_DIRIN; - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); -} - -static void fusb300_set_ep_active(struct fusb300 *fusb300, - u8 ep) -{ - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(ep)); - - reg |= FUSB300_EPSET1_ACTEN; - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(ep)); -} - -static void fusb300_set_epmps(struct fusb300 *fusb300, - struct fusb300_ep_info info) -{ - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum)); - - reg &= ~FUSB300_EPSET2_MPS_MSK; - reg |= FUSB300_EPSET2_MPS(info.maxpacket); - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET2(info.epnum)); -} - -static void fusb300_set_interval(struct fusb300 *fusb300, - struct fusb300_ep_info info) -{ - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); - - reg &= ~FUSB300_EPSET1_INTERVAL(0x7); - reg |= FUSB300_EPSET1_INTERVAL(info.interval); - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); -} - -static void fusb300_set_bwnum(struct fusb300 *fusb300, - struct fusb300_ep_info info) -{ - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); - - reg &= ~FUSB300_EPSET1_BWNUM(0x3); - reg |= FUSB300_EPSET1_BWNUM(info.bw_num); - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET1(info.epnum)); -} - -static void set_ep_reg(struct fusb300 *fusb300, - struct fusb300_ep_info info) -{ - fusb300_set_eptype(fusb300, info); - fusb300_set_epdir(fusb300, info); - fusb300_set_epmps(fusb300, info); - - if (info.interval) - fusb300_set_interval(fusb300, info); - - if (info.bw_num) - fusb300_set_bwnum(fusb300, info); - - fusb300_set_ep_active(fusb300, info.epnum); -} - -static int config_ep(struct fusb300_ep *ep, - const struct usb_endpoint_descriptor *desc) -{ - struct fusb300 *fusb300 = ep->fusb300; - struct fusb300_ep_info info; - - ep->desc = desc; - - info.interval = 0; - info.addrofs = 0; - info.bw_num = 0; - - info.type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; - info.dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0; - info.maxpacket = usb_endpoint_maxp(desc); - info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - - if ((info.type == USB_ENDPOINT_XFER_INT) || - (info.type == USB_ENDPOINT_XFER_ISOC)) { - info.interval = desc->bInterval; - if (info.type == USB_ENDPOINT_XFER_ISOC) - info.bw_num = ((desc->wMaxPacketSize & 0x1800) >> 11); - } - - ep_fifo_setting(fusb300, info); - - set_ep_reg(fusb300, info); - - fusb300_ep_setting(ep, info); - - fusb300->ep[info.epnum] = ep; - - return 0; -} - -static int fusb300_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct fusb300_ep *ep; - - ep = container_of(_ep, struct fusb300_ep, ep); - - if (ep->fusb300->reenum) { - ep->fusb300->fifo_entry_num = 0; - ep->fusb300->addrofs = 0; - ep->fusb300->reenum = 0; - } - - return config_ep(ep, desc); -} - -static int fusb300_disable(struct usb_ep *_ep) -{ - struct fusb300_ep *ep; - struct fusb300_request *req; - unsigned long flags; - - ep = container_of(_ep, struct fusb300_ep, ep); - - BUG_ON(!ep); - - while (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, struct fusb300_request, queue); - spin_lock_irqsave(&ep->fusb300->lock, flags); - done(ep, req, -ECONNRESET); - spin_unlock_irqrestore(&ep->fusb300->lock, flags); - } - - return fusb300_ep_release(ep); -} - -static struct usb_request *fusb300_alloc_request(struct usb_ep *_ep, - gfp_t gfp_flags) -{ - struct fusb300_request *req; - - req = kzalloc(sizeof(struct fusb300_request), gfp_flags); - if (!req) - return NULL; - INIT_LIST_HEAD(&req->queue); - - return &req->req; -} - -static void fusb300_free_request(struct usb_ep *_ep, struct usb_request *_req) -{ - struct fusb300_request *req; - - req = container_of(_req, struct fusb300_request, req); - kfree(req); -} - -static int enable_fifo_int(struct fusb300_ep *ep) -{ - struct fusb300 *fusb300 = ep->fusb300; - - if (ep->epnum) { - fusb300_enable_bit(fusb300, FUSB300_OFFSET_IGER0, - FUSB300_IGER0_EEPn_FIFO_INT(ep->epnum)); - } else { - pr_err("can't enable_fifo_int ep0\n"); - return -EINVAL; - } - - return 0; -} - -static int disable_fifo_int(struct fusb300_ep *ep) -{ - struct fusb300 *fusb300 = ep->fusb300; - - if (ep->epnum) { - fusb300_disable_bit(fusb300, FUSB300_OFFSET_IGER0, - FUSB300_IGER0_EEPn_FIFO_INT(ep->epnum)); - } else { - pr_err("can't disable_fifo_int ep0\n"); - return -EINVAL; - } - - return 0; -} - -static void fusb300_set_cxlen(struct fusb300 *fusb300, u32 length) -{ - u32 reg; - - reg = ioread32(fusb300->reg + FUSB300_OFFSET_CSR); - reg &= ~FUSB300_CSR_LEN_MSK; - reg |= FUSB300_CSR_LEN(length); - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_CSR); -} - -/* write data to cx fifo */ -static void fusb300_wrcxf(struct fusb300_ep *ep, - struct fusb300_request *req) -{ - int i = 0; - u8 *tmp; - u32 data; - struct fusb300 *fusb300 = ep->fusb300; - u32 length = req->req.length - req->req.actual; - - tmp = req->req.buf + req->req.actual; - - if (length > SS_CTL_MAX_PACKET_SIZE) { - fusb300_set_cxlen(fusb300, SS_CTL_MAX_PACKET_SIZE); - for (i = (SS_CTL_MAX_PACKET_SIZE >> 2); i > 0; i--) { - data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16 | - *(tmp + 3) << 24; - iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT); - tmp += 4; - } - req->req.actual += SS_CTL_MAX_PACKET_SIZE; - } else { /* length is less than max packet size */ - fusb300_set_cxlen(fusb300, length); - for (i = length >> 2; i > 0; i--) { - data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16 | - *(tmp + 3) << 24; - printk(KERN_DEBUG " 0x%x\n", data); - iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT); - tmp = tmp + 4; - } - switch (length % 4) { - case 1: - data = *tmp; - printk(KERN_DEBUG " 0x%x\n", data); - iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT); - break; - case 2: - data = *tmp | *(tmp + 1) << 8; - printk(KERN_DEBUG " 0x%x\n", data); - iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT); - break; - case 3: - data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16; - printk(KERN_DEBUG " 0x%x\n", data); - iowrite32(data, fusb300->reg + FUSB300_OFFSET_CXPORT); - break; - default: - break; - } - req->req.actual += length; - } -} - -static void fusb300_set_epnstall(struct fusb300 *fusb300, u8 ep) -{ - fusb300_enable_bit(fusb300, FUSB300_OFFSET_EPSET0(ep), - FUSB300_EPSET0_STL); -} - -static void fusb300_clear_epnstall(struct fusb300 *fusb300, u8 ep) -{ - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET0(ep)); - - if (reg & FUSB300_EPSET0_STL) { - printk(KERN_DEBUG "EP%d stall... Clear!!\n", ep); - reg &= ~FUSB300_EPSET0_STL; - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPSET0(ep)); - } -} - -static void ep0_queue(struct fusb300_ep *ep, struct fusb300_request *req) -{ - if (ep->fusb300->ep0_dir) { /* if IN */ - if (req->req.length) { - fusb300_wrcxf(ep, req); - } else - printk(KERN_DEBUG "%s : req->req.length = 0x%x\n", - __func__, req->req.length); - if ((req->req.length == req->req.actual) || - (req->req.actual < ep->ep.maxpacket)) - done(ep, req, 0); - } else { /* OUT */ - if (!req->req.length) - done(ep, req, 0); - else - fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER1, - FUSB300_IGER1_CX_OUT_INT); - } -} - -static int fusb300_queue(struct usb_ep *_ep, struct usb_request *_req, - gfp_t gfp_flags) -{ - struct fusb300_ep *ep; - struct fusb300_request *req; - unsigned long flags; - int request = 0; - - ep = container_of(_ep, struct fusb300_ep, ep); - req = container_of(_req, struct fusb300_request, req); - - if (ep->fusb300->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - spin_lock_irqsave(&ep->fusb300->lock, flags); - - if (list_empty(&ep->queue)) - request = 1; - - list_add_tail(&req->queue, &ep->queue); - - req->req.actual = 0; - req->req.status = -EINPROGRESS; - - if (ep->desc == NULL) /* ep0 */ - ep0_queue(ep, req); - else if (request && !ep->stall) - enable_fifo_int(ep); - - spin_unlock_irqrestore(&ep->fusb300->lock, flags); - - return 0; -} - -static int fusb300_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct fusb300_ep *ep; - struct fusb300_request *req; - unsigned long flags; - - ep = container_of(_ep, struct fusb300_ep, ep); - req = container_of(_req, struct fusb300_request, req); - - spin_lock_irqsave(&ep->fusb300->lock, flags); - if (!list_empty(&ep->queue)) - done(ep, req, -ECONNRESET); - spin_unlock_irqrestore(&ep->fusb300->lock, flags); - - return 0; -} - -static int fusb300_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedge) -{ - struct fusb300_ep *ep; - struct fusb300 *fusb300; - unsigned long flags; - int ret = 0; - - ep = container_of(_ep, struct fusb300_ep, ep); - - fusb300 = ep->fusb300; - - spin_lock_irqsave(&ep->fusb300->lock, flags); - - if (!list_empty(&ep->queue)) { - ret = -EAGAIN; - goto out; - } - - if (value) { - fusb300_set_epnstall(fusb300, ep->epnum); - ep->stall = 1; - if (wedge) - ep->wedged = 1; - } else { - fusb300_clear_epnstall(fusb300, ep->epnum); - ep->stall = 0; - ep->wedged = 0; - } - -out: - spin_unlock_irqrestore(&ep->fusb300->lock, flags); - return ret; -} - -static int fusb300_set_halt(struct usb_ep *_ep, int value) -{ - return fusb300_set_halt_and_wedge(_ep, value, 0); -} - -static int fusb300_set_wedge(struct usb_ep *_ep) -{ - return fusb300_set_halt_and_wedge(_ep, 1, 1); -} - -static void fusb300_fifo_flush(struct usb_ep *_ep) -{ -} - -static struct usb_ep_ops fusb300_ep_ops = { - .enable = fusb300_enable, - .disable = fusb300_disable, - - .alloc_request = fusb300_alloc_request, - .free_request = fusb300_free_request, - - .queue = fusb300_queue, - .dequeue = fusb300_dequeue, - - .set_halt = fusb300_set_halt, - .fifo_flush = fusb300_fifo_flush, - .set_wedge = fusb300_set_wedge, -}; - -/*****************************************************************************/ -static void fusb300_clear_int(struct fusb300 *fusb300, u32 offset, - u32 value) -{ - iowrite32(value, fusb300->reg + offset); -} - -static void fusb300_reset(void) -{ -} - -static void fusb300_set_cxstall(struct fusb300 *fusb300) -{ - fusb300_enable_bit(fusb300, FUSB300_OFFSET_CSR, - FUSB300_CSR_STL); -} - -static void fusb300_set_cxdone(struct fusb300 *fusb300) -{ - fusb300_enable_bit(fusb300, FUSB300_OFFSET_CSR, - FUSB300_CSR_DONE); -} - -/* read data from cx fifo */ -void fusb300_rdcxf(struct fusb300 *fusb300, - u8 *buffer, u32 length) -{ - int i = 0; - u8 *tmp; - u32 data; - - tmp = buffer; - - for (i = (length >> 2); i > 0; i--) { - data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT); - printk(KERN_DEBUG " 0x%x\n", data); - *tmp = data & 0xFF; - *(tmp + 1) = (data >> 8) & 0xFF; - *(tmp + 2) = (data >> 16) & 0xFF; - *(tmp + 3) = (data >> 24) & 0xFF; - tmp = tmp + 4; - } - - switch (length % 4) { - case 1: - data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT); - printk(KERN_DEBUG " 0x%x\n", data); - *tmp = data & 0xFF; - break; - case 2: - data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT); - printk(KERN_DEBUG " 0x%x\n", data); - *tmp = data & 0xFF; - *(tmp + 1) = (data >> 8) & 0xFF; - break; - case 3: - data = ioread32(fusb300->reg + FUSB300_OFFSET_CXPORT); - printk(KERN_DEBUG " 0x%x\n", data); - *tmp = data & 0xFF; - *(tmp + 1) = (data >> 8) & 0xFF; - *(tmp + 2) = (data >> 16) & 0xFF; - break; - default: - break; - } -} - -static void fusb300_rdfifo(struct fusb300_ep *ep, - struct fusb300_request *req, - u32 length) -{ - int i = 0; - u8 *tmp; - u32 data, reg; - struct fusb300 *fusb300 = ep->fusb300; - - tmp = req->req.buf + req->req.actual; - req->req.actual += length; - - if (req->req.actual > req->req.length) - printk(KERN_DEBUG "req->req.actual > req->req.length\n"); - - for (i = (length >> 2); i > 0; i--) { - data = ioread32(fusb300->reg + - FUSB300_OFFSET_EPPORT(ep->epnum)); - *tmp = data & 0xFF; - *(tmp + 1) = (data >> 8) & 0xFF; - *(tmp + 2) = (data >> 16) & 0xFF; - *(tmp + 3) = (data >> 24) & 0xFF; - tmp = tmp + 4; - } - - switch (length % 4) { - case 1: - data = ioread32(fusb300->reg + - FUSB300_OFFSET_EPPORT(ep->epnum)); - *tmp = data & 0xFF; - break; - case 2: - data = ioread32(fusb300->reg + - FUSB300_OFFSET_EPPORT(ep->epnum)); - *tmp = data & 0xFF; - *(tmp + 1) = (data >> 8) & 0xFF; - break; - case 3: - data = ioread32(fusb300->reg + - FUSB300_OFFSET_EPPORT(ep->epnum)); - *tmp = data & 0xFF; - *(tmp + 1) = (data >> 8) & 0xFF; - *(tmp + 2) = (data >> 16) & 0xFF; - break; - default: - break; - } - - do { - reg = ioread32(fusb300->reg + FUSB300_OFFSET_IGR1); - reg &= FUSB300_IGR1_SYNF0_EMPTY_INT; - if (i) - printk(KERN_INFO "sync fifo is not empty!\n"); - i++; - } while (!reg); -} - -static u8 fusb300_get_epnstall(struct fusb300 *fusb300, u8 ep) -{ - u8 value; - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPSET0(ep)); - - value = reg & FUSB300_EPSET0_STL; - - return value; -} - -static u8 fusb300_get_cxstall(struct fusb300 *fusb300) -{ - u8 value; - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_CSR); - - value = (reg & FUSB300_CSR_STL) >> 1; - - return value; -} - -static void request_error(struct fusb300 *fusb300) -{ - fusb300_set_cxstall(fusb300); - printk(KERN_DEBUG "request error!!\n"); -} - -static void get_status(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl) -__releases(fusb300->lock) -__acquires(fusb300->lock) -{ - u8 ep; - u16 status = 0; - u16 w_index = ctrl->wIndex; - - switch (ctrl->bRequestType & USB_RECIP_MASK) { - case USB_RECIP_DEVICE: - status = 1 << USB_DEVICE_SELF_POWERED; - break; - case USB_RECIP_INTERFACE: - status = 0; - break; - case USB_RECIP_ENDPOINT: - ep = w_index & USB_ENDPOINT_NUMBER_MASK; - if (ep) { - if (fusb300_get_epnstall(fusb300, ep)) - status = 1 << USB_ENDPOINT_HALT; - } else { - if (fusb300_get_cxstall(fusb300)) - status = 0; - } - break; - - default: - request_error(fusb300); - return; /* exit */ - } - - fusb300->ep0_data = cpu_to_le16(status); - fusb300->ep0_req->buf = &fusb300->ep0_data; - fusb300->ep0_req->length = 2; - - spin_unlock(&fusb300->lock); - fusb300_queue(fusb300->gadget.ep0, fusb300->ep0_req, GFP_KERNEL); - spin_lock(&fusb300->lock); -} - -static void set_feature(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl) -{ - u8 ep; - - switch (ctrl->bRequestType & USB_RECIP_MASK) { - case USB_RECIP_DEVICE: - fusb300_set_cxdone(fusb300); - break; - case USB_RECIP_INTERFACE: - fusb300_set_cxdone(fusb300); - break; - case USB_RECIP_ENDPOINT: { - u16 w_index = le16_to_cpu(ctrl->wIndex); - - ep = w_index & USB_ENDPOINT_NUMBER_MASK; - if (ep) - fusb300_set_epnstall(fusb300, ep); - else - fusb300_set_cxstall(fusb300); - fusb300_set_cxdone(fusb300); - } - break; - default: - request_error(fusb300); - break; - } -} - -static void fusb300_clear_seqnum(struct fusb300 *fusb300, u8 ep) -{ - fusb300_enable_bit(fusb300, FUSB300_OFFSET_EPSET0(ep), - FUSB300_EPSET0_CLRSEQNUM); -} - -static void clear_feature(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl) -{ - struct fusb300_ep *ep = - fusb300->ep[ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK]; - - switch (ctrl->bRequestType & USB_RECIP_MASK) { - case USB_RECIP_DEVICE: - fusb300_set_cxdone(fusb300); - break; - case USB_RECIP_INTERFACE: - fusb300_set_cxdone(fusb300); - break; - case USB_RECIP_ENDPOINT: - if (ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK) { - if (ep->wedged) { - fusb300_set_cxdone(fusb300); - break; - } - if (ep->stall) { - ep->stall = 0; - fusb300_clear_seqnum(fusb300, ep->epnum); - fusb300_clear_epnstall(fusb300, ep->epnum); - if (!list_empty(&ep->queue)) - enable_fifo_int(ep); - } - } - fusb300_set_cxdone(fusb300); - break; - default: - request_error(fusb300); - break; - } -} - -static void fusb300_set_dev_addr(struct fusb300 *fusb300, u16 addr) -{ - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_DAR); - - reg &= ~FUSB300_DAR_DRVADDR_MSK; - reg |= FUSB300_DAR_DRVADDR(addr); - - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_DAR); -} - -static void set_address(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl) -{ - if (ctrl->wValue >= 0x0100) - request_error(fusb300); - else { - fusb300_set_dev_addr(fusb300, ctrl->wValue); - fusb300_set_cxdone(fusb300); - } -} - -#define UVC_COPY_DESCRIPTORS(mem, src) \ - do { \ - const struct usb_descriptor_header * const *__src; \ - for (__src = src; *__src; ++__src) { \ - memcpy(mem, *__src, (*__src)->bLength); \ - mem += (*__src)->bLength; \ - } \ - } while (0) - -static int setup_packet(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl) -{ - u8 *p = (u8 *)ctrl; - u8 ret = 0; - u8 i = 0; - - fusb300_rdcxf(fusb300, p, 8); - fusb300->ep0_dir = ctrl->bRequestType & USB_DIR_IN; - fusb300->ep0_length = ctrl->wLength; - - /* check request */ - if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { - switch (ctrl->bRequest) { - case USB_REQ_GET_STATUS: - get_status(fusb300, ctrl); - break; - case USB_REQ_CLEAR_FEATURE: - clear_feature(fusb300, ctrl); - break; - case USB_REQ_SET_FEATURE: - set_feature(fusb300, ctrl); - break; - case USB_REQ_SET_ADDRESS: - set_address(fusb300, ctrl); - break; - case USB_REQ_SET_CONFIGURATION: - fusb300_enable_bit(fusb300, FUSB300_OFFSET_DAR, - FUSB300_DAR_SETCONFG); - /* clear sequence number */ - for (i = 1; i <= FUSB300_MAX_NUM_EP; i++) - fusb300_clear_seqnum(fusb300, i); - fusb300->reenum = 1; - ret = 1; - break; - default: - ret = 1; - break; - } - } else - ret = 1; - - return ret; -} - -static void done(struct fusb300_ep *ep, struct fusb300_request *req, - int status) -{ - list_del_init(&req->queue); - - /* don't modify queue heads during completion callback */ - if (ep->fusb300->gadget.speed == USB_SPEED_UNKNOWN) - req->req.status = -ESHUTDOWN; - else - req->req.status = status; - - spin_unlock(&ep->fusb300->lock); - req->req.complete(&ep->ep, &req->req); - spin_lock(&ep->fusb300->lock); - - if (ep->epnum) { - disable_fifo_int(ep); - if (!list_empty(&ep->queue)) - enable_fifo_int(ep); - } else - fusb300_set_cxdone(ep->fusb300); -} - -static void fusb300_fill_idma_prdtbl(struct fusb300_ep *ep, dma_addr_t d, - u32 len) -{ - u32 value; - u32 reg; - - /* wait SW owner */ - do { - reg = ioread32(ep->fusb300->reg + - FUSB300_OFFSET_EPPRD_W0(ep->epnum)); - reg &= FUSB300_EPPRD0_H; - } while (reg); - - iowrite32(d, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W1(ep->epnum)); - - value = FUSB300_EPPRD0_BTC(len) | FUSB300_EPPRD0_H | - FUSB300_EPPRD0_F | FUSB300_EPPRD0_L | FUSB300_EPPRD0_I; - iowrite32(value, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W0(ep->epnum)); - - iowrite32(0x0, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W2(ep->epnum)); - - fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_EPPRDRDY, - FUSB300_EPPRDR_EP_PRD_RDY(ep->epnum)); -} - -static void fusb300_wait_idma_finished(struct fusb300_ep *ep) -{ - u32 reg; - - do { - reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_IGR1); - if ((reg & FUSB300_IGR1_VBUS_CHG_INT) || - (reg & FUSB300_IGR1_WARM_RST_INT) || - (reg & FUSB300_IGR1_HOT_RST_INT) || - (reg & FUSB300_IGR1_USBRST_INT) - ) - goto IDMA_RESET; - reg = ioread32(ep->fusb300->reg + FUSB300_OFFSET_IGR0); - reg &= FUSB300_IGR0_EPn_PRD_INT(ep->epnum); - } while (!reg); - - fusb300_clear_int(ep->fusb300, FUSB300_OFFSET_IGR0, - FUSB300_IGR0_EPn_PRD_INT(ep->epnum)); -IDMA_RESET: - fusb300_clear_int(ep->fusb300, FUSB300_OFFSET_IGER0, - FUSB300_IGER0_EEPn_PRD_INT(ep->epnum)); -} - -static void fusb300_set_idma(struct fusb300_ep *ep, - struct fusb300_request *req) -{ - dma_addr_t d; - - d = dma_map_single(NULL, req->req.buf, req->req.length, DMA_TO_DEVICE); - - if (dma_mapping_error(NULL, d)) { - printk(KERN_DEBUG "dma_mapping_error\n"); - return; - } - - dma_sync_single_for_device(NULL, d, req->req.length, DMA_TO_DEVICE); - - fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER0, - FUSB300_IGER0_EEPn_PRD_INT(ep->epnum)); - - fusb300_fill_idma_prdtbl(ep, d, req->req.length); - /* check idma is done */ - fusb300_wait_idma_finished(ep); - - dma_unmap_single(NULL, d, req->req.length, DMA_TO_DEVICE); -} - -static void in_ep_fifo_handler(struct fusb300_ep *ep) -{ - struct fusb300_request *req = list_entry(ep->queue.next, - struct fusb300_request, queue); - - if (req->req.length) - fusb300_set_idma(ep, req); - done(ep, req, 0); -} - -static void out_ep_fifo_handler(struct fusb300_ep *ep) -{ - struct fusb300 *fusb300 = ep->fusb300; - struct fusb300_request *req = list_entry(ep->queue.next, - struct fusb300_request, queue); - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPFFR(ep->epnum)); - u32 length = reg & FUSB300_FFR_BYCNT; - - fusb300_rdfifo(ep, req, length); - - /* finish out transfer */ - if ((req->req.length == req->req.actual) || (length < ep->ep.maxpacket)) - done(ep, req, 0); -} - -static void check_device_mode(struct fusb300 *fusb300) -{ - u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_GCR); - - switch (reg & FUSB300_GCR_DEVEN_MSK) { - case FUSB300_GCR_DEVEN_SS: - fusb300->gadget.speed = USB_SPEED_SUPER; - break; - case FUSB300_GCR_DEVEN_HS: - fusb300->gadget.speed = USB_SPEED_HIGH; - break; - case FUSB300_GCR_DEVEN_FS: - fusb300->gadget.speed = USB_SPEED_FULL; - break; - default: - fusb300->gadget.speed = USB_SPEED_UNKNOWN; - break; - } - printk(KERN_INFO "dev_mode = %d\n", (reg & FUSB300_GCR_DEVEN_MSK)); -} - - -static void fusb300_ep0out(struct fusb300 *fusb300) -{ - struct fusb300_ep *ep = fusb300->ep[0]; - u32 reg; - - if (!list_empty(&ep->queue)) { - struct fusb300_request *req; - - req = list_first_entry(&ep->queue, - struct fusb300_request, queue); - if (req->req.length) - fusb300_rdcxf(ep->fusb300, req->req.buf, - req->req.length); - done(ep, req, 0); - reg = ioread32(fusb300->reg + FUSB300_OFFSET_IGER1); - reg &= ~FUSB300_IGER1_CX_OUT_INT; - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_IGER1); - } else - pr_err("%s : empty queue\n", __func__); -} - -static void fusb300_ep0in(struct fusb300 *fusb300) -{ - struct fusb300_request *req; - struct fusb300_ep *ep = fusb300->ep[0]; - - if ((!list_empty(&ep->queue)) && (fusb300->ep0_dir)) { - req = list_entry(ep->queue.next, - struct fusb300_request, queue); - if (req->req.length) - fusb300_wrcxf(ep, req); - if ((req->req.length - req->req.actual) < ep->ep.maxpacket) - done(ep, req, 0); - } else - fusb300_set_cxdone(fusb300); -} - -static void fusb300_grp2_handler(void) -{ -} - -static void fusb300_grp3_handler(void) -{ -} - -static void fusb300_grp4_handler(void) -{ -} - -static void fusb300_grp5_handler(void) -{ -} - -static irqreturn_t fusb300_irq(int irq, void *_fusb300) -{ - struct fusb300 *fusb300 = _fusb300; - u32 int_grp1 = ioread32(fusb300->reg + FUSB300_OFFSET_IGR1); - u32 int_grp1_en = ioread32(fusb300->reg + FUSB300_OFFSET_IGER1); - u32 int_grp0 = ioread32(fusb300->reg + FUSB300_OFFSET_IGR0); - u32 int_grp0_en = ioread32(fusb300->reg + FUSB300_OFFSET_IGER0); - struct usb_ctrlrequest ctrl; - u8 in; - u32 reg; - int i; - - spin_lock(&fusb300->lock); - - int_grp1 &= int_grp1_en; - int_grp0 &= int_grp0_en; - - if (int_grp1 & FUSB300_IGR1_WARM_RST_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_WARM_RST_INT); - printk(KERN_INFO"fusb300_warmreset\n"); - fusb300_reset(); - } - - if (int_grp1 & FUSB300_IGR1_HOT_RST_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_HOT_RST_INT); - printk(KERN_INFO"fusb300_hotreset\n"); - fusb300_reset(); - } - - if (int_grp1 & FUSB300_IGR1_USBRST_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_USBRST_INT); - fusb300_reset(); - } - /* COMABT_INT has a highest priority */ - - if (int_grp1 & FUSB300_IGR1_CX_COMABT_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_CX_COMABT_INT); - printk(KERN_INFO"fusb300_ep0abt\n"); - } - - if (int_grp1 & FUSB300_IGR1_VBUS_CHG_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_VBUS_CHG_INT); - printk(KERN_INFO"fusb300_vbus_change\n"); - } - - if (int_grp1 & FUSB300_IGR1_U3_EXIT_FAIL_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_U3_EXIT_FAIL_INT); - } - - if (int_grp1 & FUSB300_IGR1_U2_EXIT_FAIL_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_U2_EXIT_FAIL_INT); - } - - if (int_grp1 & FUSB300_IGR1_U1_EXIT_FAIL_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_U1_EXIT_FAIL_INT); - } - - if (int_grp1 & FUSB300_IGR1_U2_ENTRY_FAIL_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_U2_ENTRY_FAIL_INT); - } - - if (int_grp1 & FUSB300_IGR1_U1_ENTRY_FAIL_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_U1_ENTRY_FAIL_INT); - } - - if (int_grp1 & FUSB300_IGR1_U3_EXIT_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_U3_EXIT_INT); - printk(KERN_INFO "FUSB300_IGR1_U3_EXIT_INT\n"); - } - - if (int_grp1 & FUSB300_IGR1_U2_EXIT_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_U2_EXIT_INT); - printk(KERN_INFO "FUSB300_IGR1_U2_EXIT_INT\n"); - } - - if (int_grp1 & FUSB300_IGR1_U1_EXIT_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_U1_EXIT_INT); - printk(KERN_INFO "FUSB300_IGR1_U1_EXIT_INT\n"); - } - - if (int_grp1 & FUSB300_IGR1_U3_ENTRY_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_U3_ENTRY_INT); - printk(KERN_INFO "FUSB300_IGR1_U3_ENTRY_INT\n"); - fusb300_enable_bit(fusb300, FUSB300_OFFSET_SSCR1, - FUSB300_SSCR1_GO_U3_DONE); - } - - if (int_grp1 & FUSB300_IGR1_U2_ENTRY_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_U2_ENTRY_INT); - printk(KERN_INFO "FUSB300_IGR1_U2_ENTRY_INT\n"); - } - - if (int_grp1 & FUSB300_IGR1_U1_ENTRY_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_U1_ENTRY_INT); - printk(KERN_INFO "FUSB300_IGR1_U1_ENTRY_INT\n"); - } - - if (int_grp1 & FUSB300_IGR1_RESM_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_RESM_INT); - printk(KERN_INFO "fusb300_resume\n"); - } - - if (int_grp1 & FUSB300_IGR1_SUSP_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_SUSP_INT); - printk(KERN_INFO "fusb300_suspend\n"); - } - - if (int_grp1 & FUSB300_IGR1_HS_LPM_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_HS_LPM_INT); - printk(KERN_INFO "fusb300_HS_LPM_INT\n"); - } - - if (int_grp1 & FUSB300_IGR1_DEV_MODE_CHG_INT) { - fusb300_clear_int(fusb300, FUSB300_OFFSET_IGR1, - FUSB300_IGR1_DEV_MODE_CHG_INT); - check_device_mode(fusb300); - } - - if (int_grp1 & FUSB300_IGR1_CX_COMFAIL_INT) { - fusb300_set_cxstall(fusb300); - printk(KERN_INFO "fusb300_ep0fail\n"); - } - - if (int_grp1 & FUSB300_IGR1_CX_SETUP_INT) { - printk(KERN_INFO "fusb300_ep0setup\n"); - if (setup_packet(fusb300, &ctrl)) { - spin_unlock(&fusb300->lock); - if (fusb300->driver->setup(&fusb300->gadget, &ctrl) < 0) - fusb300_set_cxstall(fusb300); - spin_lock(&fusb300->lock); - } - } - - if (int_grp1 & FUSB300_IGR1_CX_CMDEND_INT) - printk(KERN_INFO "fusb300_cmdend\n"); - - - if (int_grp1 & FUSB300_IGR1_CX_OUT_INT) { - printk(KERN_INFO "fusb300_cxout\n"); - fusb300_ep0out(fusb300); - } - - if (int_grp1 & FUSB300_IGR1_CX_IN_INT) { - printk(KERN_INFO "fusb300_cxin\n"); - fusb300_ep0in(fusb300); - } - - if (int_grp1 & FUSB300_IGR1_INTGRP5) - fusb300_grp5_handler(); - - if (int_grp1 & FUSB300_IGR1_INTGRP4) - fusb300_grp4_handler(); - - if (int_grp1 & FUSB300_IGR1_INTGRP3) - fusb300_grp3_handler(); - - if (int_grp1 & FUSB300_IGR1_INTGRP2) - fusb300_grp2_handler(); - - if (int_grp0) { - for (i = 1; i < FUSB300_MAX_NUM_EP; i++) { - if (int_grp0 & FUSB300_IGR0_EPn_FIFO_INT(i)) { - reg = ioread32(fusb300->reg + - FUSB300_OFFSET_EPSET1(i)); - in = (reg & FUSB300_EPSET1_DIRIN) ? 1 : 0; - if (in) - in_ep_fifo_handler(fusb300->ep[i]); - else - out_ep_fifo_handler(fusb300->ep[i]); - } - } - } - - spin_unlock(&fusb300->lock); - - return IRQ_HANDLED; -} - -static void fusb300_set_u2_timeout(struct fusb300 *fusb300, - u32 time) -{ - u32 reg; - - reg = ioread32(fusb300->reg + FUSB300_OFFSET_TT); - reg &= ~0xff; - reg |= FUSB300_SSCR2_U2TIMEOUT(time); - - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_TT); -} - -static void fusb300_set_u1_timeout(struct fusb300 *fusb300, - u32 time) -{ - u32 reg; - - reg = ioread32(fusb300->reg + FUSB300_OFFSET_TT); - reg &= ~(0xff << 8); - reg |= FUSB300_SSCR2_U1TIMEOUT(time); - - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_TT); -} - -static void init_controller(struct fusb300 *fusb300) -{ - u32 reg; - u32 mask = 0; - u32 val = 0; - - /* split on */ - mask = val = FUSB300_AHBBCR_S0_SPLIT_ON | FUSB300_AHBBCR_S1_SPLIT_ON; - reg = ioread32(fusb300->reg + FUSB300_OFFSET_AHBCR); - reg &= ~mask; - reg |= val; - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_AHBCR); - - /* enable high-speed LPM */ - mask = val = FUSB300_HSCR_HS_LPM_PERMIT; - reg = ioread32(fusb300->reg + FUSB300_OFFSET_HSCR); - reg &= ~mask; - reg |= val; - iowrite32(reg, fusb300->reg + FUSB300_OFFSET_HSCR); - - /*set u1 u2 timmer*/ - fusb300_set_u2_timeout(fusb300, 0xff); - fusb300_set_u1_timeout(fusb300, 0xff); - - /* enable all grp1 interrupt */ - iowrite32(0xcfffff9f, fusb300->reg + FUSB300_OFFSET_IGER1); -} -/*------------------------------------------------------------------------*/ -static struct fusb300 *the_controller; - -static int fusb300_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) -{ - struct fusb300 *fusb300 = the_controller; - int retval; - - if (!driver - || driver->max_speed < USB_SPEED_FULL - || !bind - || !driver->setup) - return -EINVAL; - - if (!fusb300) - return -ENODEV; - - if (fusb300->driver) - return -EBUSY; - - /* hook up the driver */ - driver->driver.bus = NULL; - fusb300->driver = driver; - fusb300->gadget.dev.driver = &driver->driver; - - retval = device_add(&fusb300->gadget.dev); - if (retval) { - pr_err("device_add error (%d)\n", retval); - goto error; - } - - retval = bind(&fusb300->gadget); - if (retval) { - pr_err("bind to driver error (%d)\n", retval); - device_del(&fusb300->gadget.dev); - goto error; - } - - return 0; - -error: - fusb300->driver = NULL; - fusb300->gadget.dev.driver = NULL; - - return retval; -} - -static int fusb300_udc_stop(struct usb_gadget_driver *driver) -{ - struct fusb300 *fusb300 = the_controller; - - if (driver != fusb300->driver || !driver->unbind) - return -EINVAL; - - driver->unbind(&fusb300->gadget); - fusb300->gadget.dev.driver = NULL; - - init_controller(fusb300); - device_del(&fusb300->gadget.dev); - fusb300->driver = NULL; - - return 0; -} -/*--------------------------------------------------------------------------*/ - -static int fusb300_udc_pullup(struct usb_gadget *_gadget, int is_active) -{ - return 0; -} - -static struct usb_gadget_ops fusb300_gadget_ops = { - .pullup = fusb300_udc_pullup, - .start = fusb300_udc_start, - .stop = fusb300_udc_stop, -}; - -static int __exit fusb300_remove(struct platform_device *pdev) -{ - struct fusb300 *fusb300 = dev_get_drvdata(&pdev->dev); - - usb_del_gadget_udc(&fusb300->gadget); - iounmap(fusb300->reg); - free_irq(platform_get_irq(pdev, 0), fusb300); - - fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req); - kfree(fusb300); - - return 0; -} - -static int __init fusb300_probe(struct platform_device *pdev) -{ - struct resource *res, *ires, *ires1; - void __iomem *reg = NULL; - struct fusb300 *fusb300 = NULL; - struct fusb300_ep *_ep[FUSB300_MAX_NUM_EP]; - int ret = 0; - int i; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENODEV; - pr_err("platform_get_resource error.\n"); - goto clean_up; - } - - ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!ires) { - ret = -ENODEV; - dev_err(&pdev->dev, - "platform_get_resource IORESOURCE_IRQ error.\n"); - goto clean_up; - } - - ires1 = platform_get_resource(pdev, IORESOURCE_IRQ, 1); - if (!ires1) { - ret = -ENODEV; - dev_err(&pdev->dev, - "platform_get_resource IORESOURCE_IRQ 1 error.\n"); - goto clean_up; - } - - reg = ioremap(res->start, resource_size(res)); - if (reg == NULL) { - ret = -ENOMEM; - pr_err("ioremap error.\n"); - goto clean_up; - } - - /* initialize udc */ - fusb300 = kzalloc(sizeof(struct fusb300), GFP_KERNEL); - if (fusb300 == NULL) { - pr_err("kzalloc error\n"); - goto clean_up; - } - - for (i = 0; i < FUSB300_MAX_NUM_EP; i++) { - _ep[i] = kzalloc(sizeof(struct fusb300_ep), GFP_KERNEL); - if (_ep[i] == NULL) { - pr_err("_ep kzalloc error\n"); - goto clean_up; - } - fusb300->ep[i] = _ep[i]; - } - - spin_lock_init(&fusb300->lock); - - dev_set_drvdata(&pdev->dev, fusb300); - - fusb300->gadget.ops = &fusb300_gadget_ops; - - device_initialize(&fusb300->gadget.dev); - - dev_set_name(&fusb300->gadget.dev, "gadget"); - - fusb300->gadget.max_speed = USB_SPEED_HIGH; - fusb300->gadget.dev.parent = &pdev->dev; - fusb300->gadget.dev.dma_mask = pdev->dev.dma_mask; - fusb300->gadget.dev.release = pdev->dev.release; - fusb300->gadget.name = udc_name; - fusb300->reg = reg; - - ret = request_irq(ires->start, fusb300_irq, IRQF_SHARED, - udc_name, fusb300); - if (ret < 0) { - pr_err("request_irq error (%d)\n", ret); - goto clean_up; - } - - ret = request_irq(ires1->start, fusb300_irq, - IRQF_SHARED, udc_name, fusb300); - if (ret < 0) { - pr_err("request_irq1 error (%d)\n", ret); - goto clean_up; - } - - INIT_LIST_HEAD(&fusb300->gadget.ep_list); - - for (i = 0; i < FUSB300_MAX_NUM_EP ; i++) { - struct fusb300_ep *ep = fusb300->ep[i]; - - if (i != 0) { - INIT_LIST_HEAD(&fusb300->ep[i]->ep.ep_list); - list_add_tail(&fusb300->ep[i]->ep.ep_list, - &fusb300->gadget.ep_list); - } - ep->fusb300 = fusb300; - INIT_LIST_HEAD(&ep->queue); - ep->ep.name = fusb300_ep_name[i]; - ep->ep.ops = &fusb300_ep_ops; - ep->ep.maxpacket = HS_BULK_MAX_PACKET_SIZE; - } - fusb300->ep[0]->ep.maxpacket = HS_CTL_MAX_PACKET_SIZE; - fusb300->ep[0]->epnum = 0; - fusb300->gadget.ep0 = &fusb300->ep[0]->ep; - INIT_LIST_HEAD(&fusb300->gadget.ep0->ep_list); - - the_controller = fusb300; - - fusb300->ep0_req = fusb300_alloc_request(&fusb300->ep[0]->ep, - GFP_KERNEL); - if (fusb300->ep0_req == NULL) - goto clean_up3; - - init_controller(fusb300); - ret = usb_add_gadget_udc(&pdev->dev, &fusb300->gadget); - if (ret) - goto err_add_udc; - - dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION); - - return 0; -err_add_udc: - fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req); - -clean_up3: - free_irq(ires->start, fusb300); - -clean_up: - if (fusb300) { - if (fusb300->ep0_req) - fusb300_free_request(&fusb300->ep[0]->ep, - fusb300->ep0_req); - kfree(fusb300); - } - if (reg) - iounmap(reg); - - return ret; -} - -static struct platform_driver fusb300_driver = { - .remove = __exit_p(fusb300_remove), - .driver = { - .name = (char *) udc_name, - .owner = THIS_MODULE, - }, -}; - -static int __init fusb300_udc_init(void) -{ - return platform_driver_probe(&fusb300_driver, fusb300_probe); -} - -module_init(fusb300_udc_init); - -static void __exit fusb300_udc_cleanup(void) -{ - platform_driver_unregister(&fusb300_driver); -} -module_exit(fusb300_udc_cleanup); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/fusb300_udc.h b/ANDROID_3.4.5/drivers/usb/gadget/fusb300_udc.h deleted file mode 100644 index 92745bd0..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/fusb300_udc.h +++ /dev/null @@ -1,677 +0,0 @@ -/* - * Fusb300 UDC (USB gadget) - * - * Copyright (C) 2010 Faraday Technology Corp. - * - * Author : Yuan-hsin Chen - * - * 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; version 2 of the License. - */ - - -#ifndef __FUSB300_UDC_H__ -#define __FUSB300_UDC_H_ - -#include - -#define FUSB300_OFFSET_GCR 0x00 -#define FUSB300_OFFSET_GTM 0x04 -#define FUSB300_OFFSET_DAR 0x08 -#define FUSB300_OFFSET_CSR 0x0C -#define FUSB300_OFFSET_CXPORT 0x10 -#define FUSB300_OFFSET_EPSET0(n) (0x20 + (n - 1) * 0x30) -#define FUSB300_OFFSET_EPSET1(n) (0x24 + (n - 1) * 0x30) -#define FUSB300_OFFSET_EPSET2(n) (0x28 + (n - 1) * 0x30) -#define FUSB300_OFFSET_EPFFR(n) (0x2c + (n - 1) * 0x30) -#define FUSB300_OFFSET_EPSTRID(n) (0x40 + (n - 1) * 0x30) -#define FUSB300_OFFSET_HSPTM 0x300 -#define FUSB300_OFFSET_HSCR 0x304 -#define FUSB300_OFFSET_SSCR0 0x308 -#define FUSB300_OFFSET_SSCR1 0x30C -#define FUSB300_OFFSET_TT 0x310 -#define FUSB300_OFFSET_DEVNOTF 0x314 -#define FUSB300_OFFSET_DNC1 0x318 -#define FUSB300_OFFSET_CS 0x31C -#define FUSB300_OFFSET_SOF 0x324 -#define FUSB300_OFFSET_EFCS 0x328 -#define FUSB300_OFFSET_IGR0 0x400 -#define FUSB300_OFFSET_IGR1 0x404 -#define FUSB300_OFFSET_IGR2 0x408 -#define FUSB300_OFFSET_IGR3 0x40C -#define FUSB300_OFFSET_IGR4 0x410 -#define FUSB300_OFFSET_IGR5 0x414 -#define FUSB300_OFFSET_IGER0 0x420 -#define FUSB300_OFFSET_IGER1 0x424 -#define FUSB300_OFFSET_IGER2 0x428 -#define FUSB300_OFFSET_IGER3 0x42C -#define FUSB300_OFFSET_IGER4 0x430 -#define FUSB300_OFFSET_IGER5 0x434 -#define FUSB300_OFFSET_DMAHMER 0x500 -#define FUSB300_OFFSET_EPPRDRDY 0x504 -#define FUSB300_OFFSET_DMAEPMR 0x508 -#define FUSB300_OFFSET_DMAENR 0x50C -#define FUSB300_OFFSET_DMAAPR 0x510 -#define FUSB300_OFFSET_AHBCR 0x514 -#define FUSB300_OFFSET_EPPRD_W0(n) (0x520 + (n - 1) * 0x10) -#define FUSB300_OFFSET_EPPRD_W1(n) (0x524 + (n - 1) * 0x10) -#define FUSB300_OFFSET_EPPRD_W2(n) (0x528 + (n - 1) * 0x10) -#define FUSB300_OFFSET_EPRD_PTR(n) (0x52C + (n - 1) * 0x10) -#define FUSB300_OFFSET_BUFDBG_START 0x800 -#define FUSB300_OFFSET_BUFDBG_END 0xBFC -#define FUSB300_OFFSET_EPPORT(n) (0x1010 + (n - 1) * 0x10) - -/* - * * Global Control Register (offset = 000H) - * */ -#define FUSB300_GCR_SF_RST (1 << 8) -#define FUSB300_GCR_VBUS_STATUS (1 << 7) -#define FUSB300_GCR_FORCE_HS_SUSP (1 << 6) -#define FUSB300_GCR_SYNC_FIFO1_CLR (1 << 5) -#define FUSB300_GCR_SYNC_FIFO0_CLR (1 << 4) -#define FUSB300_GCR_FIFOCLR (1 << 3) -#define FUSB300_GCR_GLINTEN (1 << 2) -#define FUSB300_GCR_DEVEN_FS 0x3 -#define FUSB300_GCR_DEVEN_HS 0x2 -#define FUSB300_GCR_DEVEN_SS 0x1 -#define FUSB300_GCR_DEVDIS 0x0 -#define FUSB300_GCR_DEVEN_MSK 0x3 - - -/* - * *Global Test Mode (offset = 004H) - * */ -#define FUSB300_GTM_TST_DIS_SOFGEN (1 << 16) -#define FUSB300_GTM_TST_CUR_EP_ENTRY(n) ((n & 0xF) << 12) -#define FUSB300_GTM_TST_EP_ENTRY(n) ((n & 0xF) << 8) -#define FUSB300_GTM_TST_EP_NUM(n) ((n & 0xF) << 4) -#define FUSB300_GTM_TST_FIFO_DEG (1 << 1) -#define FUSB300_GTM_TSTMODE (1 << 0) - -/* - * * Device Address Register (offset = 008H) - * */ -#define FUSB300_DAR_SETCONFG (1 << 7) -#define FUSB300_DAR_DRVADDR(x) (x & 0x7F) -#define FUSB300_DAR_DRVADDR_MSK 0x7F - -/* - * *Control Transfer Configuration and Status Register - * (CX_Config_Status, offset = 00CH) - * */ -#define FUSB300_CSR_LEN(x) ((x & 0xFFFF) << 8) -#define FUSB300_CSR_LEN_MSK (0xFFFF << 8) -#define FUSB300_CSR_EMP (1 << 4) -#define FUSB300_CSR_FUL (1 << 3) -#define FUSB300_CSR_CLR (1 << 2) -#define FUSB300_CSR_STL (1 << 1) -#define FUSB300_CSR_DONE (1 << 0) - -/* - * * EPn Setting 0 (EPn_SET0, offset = 020H+(n-1)*30H, n=1~15 ) - * */ -#define FUSB300_EPSET0_CLRSEQNUM (1 << 2) -#define FUSB300_EPSET0_EPn_TX0BYTE (1 << 1) -#define FUSB300_EPSET0_STL (1 << 0) - -/* - * * EPn Setting 1 (EPn_SET1, offset = 024H+(n-1)*30H, n=1~15) - * */ -#define FUSB300_EPSET1_START_ENTRY(x) ((x & 0xFF) << 24) -#define FUSB300_EPSET1_START_ENTRY_MSK (0xFF << 24) -#define FUSB300_EPSET1_FIFOENTRY(x) ((x & 0x1F) << 12) -#define FUSB300_EPSET1_FIFOENTRY_MSK (0x1f << 12) -#define FUSB300_EPSET1_INTERVAL(x) ((x & 0x7) << 6) -#define FUSB300_EPSET1_BWNUM(x) ((x & 0x3) << 4) -#define FUSB300_EPSET1_TYPEISO (1 << 2) -#define FUSB300_EPSET1_TYPEBLK (2 << 2) -#define FUSB300_EPSET1_TYPEINT (3 << 2) -#define FUSB300_EPSET1_TYPE(x) ((x & 0x3) << 2) -#define FUSB300_EPSET1_TYPE_MSK (0x3 << 2) -#define FUSB300_EPSET1_DIROUT (0 << 1) -#define FUSB300_EPSET1_DIRIN (1 << 1) -#define FUSB300_EPSET1_DIR(x) ((x & 0x1) << 1) -#define FUSB300_EPSET1_DIRIN (1 << 1) -#define FUSB300_EPSET1_DIR_MSK ((0x1) << 1) -#define FUSB300_EPSET1_ACTDIS 0 -#define FUSB300_EPSET1_ACTEN 1 - -/* - * *EPn Setting 2 (EPn_SET2, offset = 028H+(n-1)*30H, n=1~15) - * */ -#define FUSB300_EPSET2_ADDROFS(x) ((x & 0x7FFF) << 16) -#define FUSB300_EPSET2_ADDROFS_MSK (0x7fff << 16) -#define FUSB300_EPSET2_MPS(x) (x & 0x7FF) -#define FUSB300_EPSET2_MPS_MSK 0x7FF - -/* - * * EPn FIFO Register (offset = 2cH+(n-1)*30H) - * */ -#define FUSB300_FFR_RST (1 << 31) -#define FUSB300_FF_FUL (1 << 30) -#define FUSB300_FF_EMPTY (1 << 29) -#define FUSB300_FFR_BYCNT 0x1FFFF - -/* - * *EPn Stream ID (EPn_STR_ID, offset = 040H+(n-1)*30H, n=1~15) - * */ -#define FUSB300_STRID_STREN (1 << 16) -#define FUSB300_STRID_STRID(x) (x & 0xFFFF) - -/* - * *HS PHY Test Mode (offset = 300H) - * */ -#define FUSB300_HSPTM_TSTPKDONE (1 << 4) -#define FUSB300_HSPTM_TSTPKT (1 << 3) -#define FUSB300_HSPTM_TSTSET0NAK (1 << 2) -#define FUSB300_HSPTM_TSTKSTA (1 << 1) -#define FUSB300_HSPTM_TSTJSTA (1 << 0) - -/* - * *HS Control Register (offset = 304H) - * */ -#define FUSB300_HSCR_HS_LPM_PERMIT (1 << 8) -#define FUSB300_HSCR_HS_LPM_RMWKUP (1 << 7) -#define FUSB300_HSCR_CAP_LPM_RMWKUP (1 << 6) -#define FUSB300_HSCR_HS_GOSUSP (1 << 5) -#define FUSB300_HSCR_HS_GORMWKU (1 << 4) -#define FUSB300_HSCR_CAP_RMWKUP (1 << 3) -#define FUSB300_HSCR_IDLECNT_0MS 0 -#define FUSB300_HSCR_IDLECNT_1MS 1 -#define FUSB300_HSCR_IDLECNT_2MS 2 -#define FUSB300_HSCR_IDLECNT_3MS 3 -#define FUSB300_HSCR_IDLECNT_4MS 4 -#define FUSB300_HSCR_IDLECNT_5MS 5 -#define FUSB300_HSCR_IDLECNT_6MS 6 -#define FUSB300_HSCR_IDLECNT_7MS 7 - -/* - * * SS Controller Register 0 (offset = 308H) - * */ -#define FUSB300_SSCR0_MAX_INTERVAL(x) ((x & 0x7) << 4) -#define FUSB300_SSCR0_U2_FUN_EN (1 << 1) -#define FUSB300_SSCR0_U1_FUN_EN (1 << 0) - -/* - * * SS Controller Register 1 (offset = 30CH) - * */ -#define FUSB300_SSCR1_GO_U3_DONE (1 << 8) -#define FUSB300_SSCR1_TXDEEMPH_LEVEL (1 << 7) -#define FUSB300_SSCR1_DIS_SCRMB (1 << 6) -#define FUSB300_SSCR1_FORCE_RECOVERY (1 << 5) -#define FUSB300_SSCR1_U3_WAKEUP_EN (1 << 4) -#define FUSB300_SSCR1_U2_EXIT_EN (1 << 3) -#define FUSB300_SSCR1_U1_EXIT_EN (1 << 2) -#define FUSB300_SSCR1_U2_ENTRY_EN (1 << 1) -#define FUSB300_SSCR1_U1_ENTRY_EN (1 << 0) - -/* - * *SS Controller Register 2 (offset = 310H) - * */ -#define FUSB300_SSCR2_SS_TX_SWING (1 << 25) -#define FUSB300_SSCR2_FORCE_LINKPM_ACCEPT (1 << 24) -#define FUSB300_SSCR2_U2_INACT_TIMEOUT(x) ((x & 0xFF) << 16) -#define FUSB300_SSCR2_U1TIMEOUT(x) ((x & 0xFF) << 8) -#define FUSB300_SSCR2_U2TIMEOUT(x) (x & 0xFF) - -/* - * *SS Device Notification Control (DEV_NOTF, offset = 314H) - * */ -#define FUSB300_DEVNOTF_CONTEXT0(x) ((x & 0xFFFFFF) << 8) -#define FUSB300_DEVNOTF_TYPE_DIS 0 -#define FUSB300_DEVNOTF_TYPE_FUNCWAKE 1 -#define FUSB300_DEVNOTF_TYPE_LTM 2 -#define FUSB300_DEVNOTF_TYPE_BUSINT_ADJMSG 3 - -/* - * *BFM Arbiter Priority Register (BFM_ARB offset = 31CH) - * */ -#define FUSB300_BFMARB_ARB_M1 (1 << 3) -#define FUSB300_BFMARB_ARB_M0 (1 << 2) -#define FUSB300_BFMARB_ARB_S1 (1 << 1) -#define FUSB300_BFMARB_ARB_S0 1 - -/* - * *Vendor Specific IO Control Register (offset = 320H) - * */ -#define FUSB300_VSIC_VCTLOAD_N (1 << 8) -#define FUSB300_VSIC_VCTL(x) (x & 0x3F) - -/* - * *SOF Mask Timer (offset = 324H) - * */ -#define FUSB300_SOF_MASK_TIMER_HS 0x044c -#define FUSB300_SOF_MASK_TIMER_FS 0x2710 - -/* - * *Error Flag and Control Status (offset = 328H) - * */ -#define FUSB300_EFCS_PM_STATE_U3 3 -#define FUSB300_EFCS_PM_STATE_U2 2 -#define FUSB300_EFCS_PM_STATE_U1 1 -#define FUSB300_EFCS_PM_STATE_U0 0 - -/* - * *Interrupt Group 0 Register (offset = 400H) - * */ -#define FUSB300_IGR0_EP15_PRD_INT (1 << 31) -#define FUSB300_IGR0_EP14_PRD_INT (1 << 30) -#define FUSB300_IGR0_EP13_PRD_INT (1 << 29) -#define FUSB300_IGR0_EP12_PRD_INT (1 << 28) -#define FUSB300_IGR0_EP11_PRD_INT (1 << 27) -#define FUSB300_IGR0_EP10_PRD_INT (1 << 26) -#define FUSB300_IGR0_EP9_PRD_INT (1 << 25) -#define FUSB300_IGR0_EP8_PRD_INT (1 << 24) -#define FUSB300_IGR0_EP7_PRD_INT (1 << 23) -#define FUSB300_IGR0_EP6_PRD_INT (1 << 22) -#define FUSB300_IGR0_EP5_PRD_INT (1 << 21) -#define FUSB300_IGR0_EP4_PRD_INT (1 << 20) -#define FUSB300_IGR0_EP3_PRD_INT (1 << 19) -#define FUSB300_IGR0_EP2_PRD_INT (1 << 18) -#define FUSB300_IGR0_EP1_PRD_INT (1 << 17) -#define FUSB300_IGR0_EPn_PRD_INT(n) (1 << (n + 16)) - -#define FUSB300_IGR0_EP15_FIFO_INT (1 << 15) -#define FUSB300_IGR0_EP14_FIFO_INT (1 << 14) -#define FUSB300_IGR0_EP13_FIFO_INT (1 << 13) -#define FUSB300_IGR0_EP12_FIFO_INT (1 << 12) -#define FUSB300_IGR0_EP11_FIFO_INT (1 << 11) -#define FUSB300_IGR0_EP10_FIFO_INT (1 << 10) -#define FUSB300_IGR0_EP9_FIFO_INT (1 << 9) -#define FUSB300_IGR0_EP8_FIFO_INT (1 << 8) -#define FUSB300_IGR0_EP7_FIFO_INT (1 << 7) -#define FUSB300_IGR0_EP6_FIFO_INT (1 << 6) -#define FUSB300_IGR0_EP5_FIFO_INT (1 << 5) -#define FUSB300_IGR0_EP4_FIFO_INT (1 << 4) -#define FUSB300_IGR0_EP3_FIFO_INT (1 << 3) -#define FUSB300_IGR0_EP2_FIFO_INT (1 << 2) -#define FUSB300_IGR0_EP1_FIFO_INT (1 << 1) -#define FUSB300_IGR0_EPn_FIFO_INT(n) (1 << n) - -/* - * *Interrupt Group 1 Register (offset = 404H) - * */ -#define FUSB300_IGR1_INTGRP5 (1 << 31) -#define FUSB300_IGR1_VBUS_CHG_INT (1 << 30) -#define FUSB300_IGR1_SYNF1_EMPTY_INT (1 << 29) -#define FUSB300_IGR1_SYNF0_EMPTY_INT (1 << 28) -#define FUSB300_IGR1_U3_EXIT_FAIL_INT (1 << 27) -#define FUSB300_IGR1_U2_EXIT_FAIL_INT (1 << 26) -#define FUSB300_IGR1_U1_EXIT_FAIL_INT (1 << 25) -#define FUSB300_IGR1_U2_ENTRY_FAIL_INT (1 << 24) -#define FUSB300_IGR1_U1_ENTRY_FAIL_INT (1 << 23) -#define FUSB300_IGR1_U3_EXIT_INT (1 << 22) -#define FUSB300_IGR1_U2_EXIT_INT (1 << 21) -#define FUSB300_IGR1_U1_EXIT_INT (1 << 20) -#define FUSB300_IGR1_U3_ENTRY_INT (1 << 19) -#define FUSB300_IGR1_U2_ENTRY_INT (1 << 18) -#define FUSB300_IGR1_U1_ENTRY_INT (1 << 17) -#define FUSB300_IGR1_HOT_RST_INT (1 << 16) -#define FUSB300_IGR1_WARM_RST_INT (1 << 15) -#define FUSB300_IGR1_RESM_INT (1 << 14) -#define FUSB300_IGR1_SUSP_INT (1 << 13) -#define FUSB300_IGR1_HS_LPM_INT (1 << 12) -#define FUSB300_IGR1_USBRST_INT (1 << 11) -#define FUSB300_IGR1_DEV_MODE_CHG_INT (1 << 9) -#define FUSB300_IGR1_CX_COMABT_INT (1 << 8) -#define FUSB300_IGR1_CX_COMFAIL_INT (1 << 7) -#define FUSB300_IGR1_CX_CMDEND_INT (1 << 6) -#define FUSB300_IGR1_CX_OUT_INT (1 << 5) -#define FUSB300_IGR1_CX_IN_INT (1 << 4) -#define FUSB300_IGR1_CX_SETUP_INT (1 << 3) -#define FUSB300_IGR1_INTGRP4 (1 << 2) -#define FUSB300_IGR1_INTGRP3 (1 << 1) -#define FUSB300_IGR1_INTGRP2 (1 << 0) - -/* - * *Interrupt Group 2 Register (offset = 408H) - * */ -#define FUSB300_IGR2_EP6_STR_ACCEPT_INT (1 << 29) -#define FUSB300_IGR2_EP6_STR_RESUME_INT (1 << 28) -#define FUSB300_IGR2_EP6_STR_REQ_INT (1 << 27) -#define FUSB300_IGR2_EP6_STR_NOTRDY_INT (1 << 26) -#define FUSB300_IGR2_EP6_STR_PRIME_INT (1 << 25) -#define FUSB300_IGR2_EP5_STR_ACCEPT_INT (1 << 24) -#define FUSB300_IGR2_EP5_STR_RESUME_INT (1 << 23) -#define FUSB300_IGR2_EP5_STR_REQ_INT (1 << 22) -#define FUSB300_IGR2_EP5_STR_NOTRDY_INT (1 << 21) -#define FUSB300_IGR2_EP5_STR_PRIME_INT (1 << 20) -#define FUSB300_IGR2_EP4_STR_ACCEPT_INT (1 << 19) -#define FUSB300_IGR2_EP4_STR_RESUME_INT (1 << 18) -#define FUSB300_IGR2_EP4_STR_REQ_INT (1 << 17) -#define FUSB300_IGR2_EP4_STR_NOTRDY_INT (1 << 16) -#define FUSB300_IGR2_EP4_STR_PRIME_INT (1 << 15) -#define FUSB300_IGR2_EP3_STR_ACCEPT_INT (1 << 14) -#define FUSB300_IGR2_EP3_STR_RESUME_INT (1 << 13) -#define FUSB300_IGR2_EP3_STR_REQ_INT (1 << 12) -#define FUSB300_IGR2_EP3_STR_NOTRDY_INT (1 << 11) -#define FUSB300_IGR2_EP3_STR_PRIME_INT (1 << 10) -#define FUSB300_IGR2_EP2_STR_ACCEPT_INT (1 << 9) -#define FUSB300_IGR2_EP2_STR_RESUME_INT (1 << 8) -#define FUSB300_IGR2_EP2_STR_REQ_INT (1 << 7) -#define FUSB300_IGR2_EP2_STR_NOTRDY_INT (1 << 6) -#define FUSB300_IGR2_EP2_STR_PRIME_INT (1 << 5) -#define FUSB300_IGR2_EP1_STR_ACCEPT_INT (1 << 4) -#define FUSB300_IGR2_EP1_STR_RESUME_INT (1 << 3) -#define FUSB300_IGR2_EP1_STR_REQ_INT (1 << 2) -#define FUSB300_IGR2_EP1_STR_NOTRDY_INT (1 << 1) -#define FUSB300_IGR2_EP1_STR_PRIME_INT (1 << 0) - -#define FUSB300_IGR2_EP_STR_ACCEPT_INT(n) (1 << (5 * n - 1)) -#define FUSB300_IGR2_EP_STR_RESUME_INT(n) (1 << (5 * n - 2)) -#define FUSB300_IGR2_EP_STR_REQ_INT(n) (1 << (5 * n - 3)) -#define FUSB300_IGR2_EP_STR_NOTRDY_INT(n) (1 << (5 * n - 4)) -#define FUSB300_IGR2_EP_STR_PRIME_INT(n) (1 << (5 * n - 5)) - -/* - * *Interrupt Group 3 Register (offset = 40CH) - * */ -#define FUSB300_IGR3_EP12_STR_ACCEPT_INT (1 << 29) -#define FUSB300_IGR3_EP12_STR_RESUME_INT (1 << 28) -#define FUSB300_IGR3_EP12_STR_REQ_INT (1 << 27) -#define FUSB300_IGR3_EP12_STR_NOTRDY_INT (1 << 26) -#define FUSB300_IGR3_EP12_STR_PRIME_INT (1 << 25) -#define FUSB300_IGR3_EP11_STR_ACCEPT_INT (1 << 24) -#define FUSB300_IGR3_EP11_STR_RESUME_INT (1 << 23) -#define FUSB300_IGR3_EP11_STR_REQ_INT (1 << 22) -#define FUSB300_IGR3_EP11_STR_NOTRDY_INT (1 << 21) -#define FUSB300_IGR3_EP11_STR_PRIME_INT (1 << 20) -#define FUSB300_IGR3_EP10_STR_ACCEPT_INT (1 << 19) -#define FUSB300_IGR3_EP10_STR_RESUME_INT (1 << 18) -#define FUSB300_IGR3_EP10_STR_REQ_INT (1 << 17) -#define FUSB300_IGR3_EP10_STR_NOTRDY_INT (1 << 16) -#define FUSB300_IGR3_EP10_STR_PRIME_INT (1 << 15) -#define FUSB300_IGR3_EP9_STR_ACCEPT_INT (1 << 14) -#define FUSB300_IGR3_EP9_STR_RESUME_INT (1 << 13) -#define FUSB300_IGR3_EP9_STR_REQ_INT (1 << 12) -#define FUSB300_IGR3_EP9_STR_NOTRDY_INT (1 << 11) -#define FUSB300_IGR3_EP9_STR_PRIME_INT (1 << 10) -#define FUSB300_IGR3_EP8_STR_ACCEPT_INT (1 << 9) -#define FUSB300_IGR3_EP8_STR_RESUME_INT (1 << 8) -#define FUSB300_IGR3_EP8_STR_REQ_INT (1 << 7) -#define FUSB300_IGR3_EP8_STR_NOTRDY_INT (1 << 6) -#define FUSB300_IGR3_EP8_STR_PRIME_INT (1 << 5) -#define FUSB300_IGR3_EP7_STR_ACCEPT_INT (1 << 4) -#define FUSB300_IGR3_EP7_STR_RESUME_INT (1 << 3) -#define FUSB300_IGR3_EP7_STR_REQ_INT (1 << 2) -#define FUSB300_IGR3_EP7_STR_NOTRDY_INT (1 << 1) -#define FUSB300_IGR3_EP7_STR_PRIME_INT (1 << 0) - -#define FUSB300_IGR3_EP_STR_ACCEPT_INT(n) (1 << (5 * (n - 6) - 1)) -#define FUSB300_IGR3_EP_STR_RESUME_INT(n) (1 << (5 * (n - 6) - 2)) -#define FUSB300_IGR3_EP_STR_REQ_INT(n) (1 << (5 * (n - 6) - 3)) -#define FUSB300_IGR3_EP_STR_NOTRDY_INT(n) (1 << (5 * (n - 6) - 4)) -#define FUSB300_IGR3_EP_STR_PRIME_INT(n) (1 << (5 * (n - 6) - 5)) - -/* - * *Interrupt Group 4 Register (offset = 410H) - * */ -#define FUSB300_IGR4_EP15_RX0_INT (1 << 31) -#define FUSB300_IGR4_EP14_RX0_INT (1 << 30) -#define FUSB300_IGR4_EP13_RX0_INT (1 << 29) -#define FUSB300_IGR4_EP12_RX0_INT (1 << 28) -#define FUSB300_IGR4_EP11_RX0_INT (1 << 27) -#define FUSB300_IGR4_EP10_RX0_INT (1 << 26) -#define FUSB300_IGR4_EP9_RX0_INT (1 << 25) -#define FUSB300_IGR4_EP8_RX0_INT (1 << 24) -#define FUSB300_IGR4_EP7_RX0_INT (1 << 23) -#define FUSB300_IGR4_EP6_RX0_INT (1 << 22) -#define FUSB300_IGR4_EP5_RX0_INT (1 << 21) -#define FUSB300_IGR4_EP4_RX0_INT (1 << 20) -#define FUSB300_IGR4_EP3_RX0_INT (1 << 19) -#define FUSB300_IGR4_EP2_RX0_INT (1 << 18) -#define FUSB300_IGR4_EP1_RX0_INT (1 << 17) -#define FUSB300_IGR4_EP_RX0_INT(x) (1 << (x + 16)) -#define FUSB300_IGR4_EP15_STR_ACCEPT_INT (1 << 14) -#define FUSB300_IGR4_EP15_STR_RESUME_INT (1 << 13) -#define FUSB300_IGR4_EP15_STR_REQ_INT (1 << 12) -#define FUSB300_IGR4_EP15_STR_NOTRDY_INT (1 << 11) -#define FUSB300_IGR4_EP15_STR_PRIME_INT (1 << 10) -#define FUSB300_IGR4_EP14_STR_ACCEPT_INT (1 << 9) -#define FUSB300_IGR4_EP14_STR_RESUME_INT (1 << 8) -#define FUSB300_IGR4_EP14_STR_REQ_INT (1 << 7) -#define FUSB300_IGR4_EP14_STR_NOTRDY_INT (1 << 6) -#define FUSB300_IGR4_EP14_STR_PRIME_INT (1 << 5) -#define FUSB300_IGR4_EP13_STR_ACCEPT_INT (1 << 4) -#define FUSB300_IGR4_EP13_STR_RESUME_INT (1 << 3) -#define FUSB300_IGR4_EP13_STR_REQ_INT (1 << 2) -#define FUSB300_IGR4_EP13_STR_NOTRDY_INT (1 << 1) -#define FUSB300_IGR4_EP13_STR_PRIME_INT (1 << 0) - -#define FUSB300_IGR4_EP_STR_ACCEPT_INT(n) (1 << (5 * (n - 12) - 1)) -#define FUSB300_IGR4_EP_STR_RESUME_INT(n) (1 << (5 * (n - 12) - 2)) -#define FUSB300_IGR4_EP_STR_REQ_INT(n) (1 << (5 * (n - 12) - 3)) -#define FUSB300_IGR4_EP_STR_NOTRDY_INT(n) (1 << (5 * (n - 12) - 4)) -#define FUSB300_IGR4_EP_STR_PRIME_INT(n) (1 << (5 * (n - 12) - 5)) - -/* - * *Interrupt Group 5 Register (offset = 414H) - * */ -#define FUSB300_IGR5_EP_STL_INT(n) (1 << n) - -/* - * *Interrupt Enable Group 0 Register (offset = 420H) - * */ -#define FUSB300_IGER0_EEP15_PRD_INT (1 << 31) -#define FUSB300_IGER0_EEP14_PRD_INT (1 << 30) -#define FUSB300_IGER0_EEP13_PRD_INT (1 << 29) -#define FUSB300_IGER0_EEP12_PRD_INT (1 << 28) -#define FUSB300_IGER0_EEP11_PRD_INT (1 << 27) -#define FUSB300_IGER0_EEP10_PRD_INT (1 << 26) -#define FUSB300_IGER0_EEP9_PRD_INT (1 << 25) -#define FUSB300_IGER0_EP8_PRD_INT (1 << 24) -#define FUSB300_IGER0_EEP7_PRD_INT (1 << 23) -#define FUSB300_IGER0_EEP6_PRD_INT (1 << 22) -#define FUSB300_IGER0_EEP5_PRD_INT (1 << 21) -#define FUSB300_IGER0_EEP4_PRD_INT (1 << 20) -#define FUSB300_IGER0_EEP3_PRD_INT (1 << 19) -#define FUSB300_IGER0_EEP2_PRD_INT (1 << 18) -#define FUSB300_IGER0_EEP1_PRD_INT (1 << 17) -#define FUSB300_IGER0_EEPn_PRD_INT(n) (1 << (n + 16)) - -#define FUSB300_IGER0_EEP15_FIFO_INT (1 << 15) -#define FUSB300_IGER0_EEP14_FIFO_INT (1 << 14) -#define FUSB300_IGER0_EEP13_FIFO_INT (1 << 13) -#define FUSB300_IGER0_EEP12_FIFO_INT (1 << 12) -#define FUSB300_IGER0_EEP11_FIFO_INT (1 << 11) -#define FUSB300_IGER0_EEP10_FIFO_INT (1 << 10) -#define FUSB300_IGER0_EEP9_FIFO_INT (1 << 9) -#define FUSB300_IGER0_EEP8_FIFO_INT (1 << 8) -#define FUSB300_IGER0_EEP7_FIFO_INT (1 << 7) -#define FUSB300_IGER0_EEP6_FIFO_INT (1 << 6) -#define FUSB300_IGER0_EEP5_FIFO_INT (1 << 5) -#define FUSB300_IGER0_EEP4_FIFO_INT (1 << 4) -#define FUSB300_IGER0_EEP3_FIFO_INT (1 << 3) -#define FUSB300_IGER0_EEP2_FIFO_INT (1 << 2) -#define FUSB300_IGER0_EEP1_FIFO_INT (1 << 1) -#define FUSB300_IGER0_EEPn_FIFO_INT(n) (1 << n) - -/* - * *Interrupt Enable Group 1 Register (offset = 424H) - * */ -#define FUSB300_IGER1_EINT_GRP5 (1 << 31) -#define FUSB300_IGER1_VBUS_CHG_INT (1 << 30) -#define FUSB300_IGER1_SYNF1_EMPTY_INT (1 << 29) -#define FUSB300_IGER1_SYNF0_EMPTY_INT (1 << 28) -#define FUSB300_IGER1_U3_EXIT_FAIL_INT (1 << 27) -#define FUSB300_IGER1_U2_EXIT_FAIL_INT (1 << 26) -#define FUSB300_IGER1_U1_EXIT_FAIL_INT (1 << 25) -#define FUSB300_IGER1_U2_ENTRY_FAIL_INT (1 << 24) -#define FUSB300_IGER1_U1_ENTRY_FAIL_INT (1 << 23) -#define FUSB300_IGER1_U3_EXIT_INT (1 << 22) -#define FUSB300_IGER1_U2_EXIT_INT (1 << 21) -#define FUSB300_IGER1_U1_EXIT_INT (1 << 20) -#define FUSB300_IGER1_U3_ENTRY_INT (1 << 19) -#define FUSB300_IGER1_U2_ENTRY_INT (1 << 18) -#define FUSB300_IGER1_U1_ENTRY_INT (1 << 17) -#define FUSB300_IGER1_HOT_RST_INT (1 << 16) -#define FUSB300_IGER1_WARM_RST_INT (1 << 15) -#define FUSB300_IGER1_RESM_INT (1 << 14) -#define FUSB300_IGER1_SUSP_INT (1 << 13) -#define FUSB300_IGER1_LPM_INT (1 << 12) -#define FUSB300_IGER1_HS_RST_INT (1 << 11) -#define FUSB300_IGER1_EDEV_MODE_CHG_INT (1 << 9) -#define FUSB300_IGER1_CX_COMABT_INT (1 << 8) -#define FUSB300_IGER1_CX_COMFAIL_INT (1 << 7) -#define FUSB300_IGER1_CX_CMDEND_INT (1 << 6) -#define FUSB300_IGER1_CX_OUT_INT (1 << 5) -#define FUSB300_IGER1_CX_IN_INT (1 << 4) -#define FUSB300_IGER1_CX_SETUP_INT (1 << 3) -#define FUSB300_IGER1_INTGRP4 (1 << 2) -#define FUSB300_IGER1_INTGRP3 (1 << 1) -#define FUSB300_IGER1_INTGRP2 (1 << 0) - -/* - * *Interrupt Enable Group 2 Register (offset = 428H) - * */ -#define FUSB300_IGER2_EEP_STR_ACCEPT_INT(n) (1 << (5 * n - 1)) -#define FUSB300_IGER2_EEP_STR_RESUME_INT(n) (1 << (5 * n - 2)) -#define FUSB300_IGER2_EEP_STR_REQ_INT(n) (1 << (5 * n - 3)) -#define FUSB300_IGER2_EEP_STR_NOTRDY_INT(n) (1 << (5 * n - 4)) -#define FUSB300_IGER2_EEP_STR_PRIME_INT(n) (1 << (5 * n - 5)) - -/* - * *Interrupt Enable Group 3 Register (offset = 42CH) - * */ - -#define FUSB300_IGER3_EEP_STR_ACCEPT_INT(n) (1 << (5 * (n - 6) - 1)) -#define FUSB300_IGER3_EEP_STR_RESUME_INT(n) (1 << (5 * (n - 6) - 2)) -#define FUSB300_IGER3_EEP_STR_REQ_INT(n) (1 << (5 * (n - 6) - 3)) -#define FUSB300_IGER3_EEP_STR_NOTRDY_INT(n) (1 << (5 * (n - 6) - 4)) -#define FUSB300_IGER3_EEP_STR_PRIME_INT(n) (1 << (5 * (n - 6) - 5)) - -/* - * *Interrupt Enable Group 4 Register (offset = 430H) - * */ - -#define FUSB300_IGER4_EEP_RX0_INT(n) (1 << (n + 16)) -#define FUSB300_IGER4_EEP_STR_ACCEPT_INT(n) (1 << (5 * (n - 6) - 1)) -#define FUSB300_IGER4_EEP_STR_RESUME_INT(n) (1 << (5 * (n - 6) - 2)) -#define FUSB300_IGER4_EEP_STR_REQ_INT(n) (1 << (5 * (n - 6) - 3)) -#define FUSB300_IGER4_EEP_STR_NOTRDY_INT(n) (1 << (5 * (n - 6) - 4)) -#define FUSB300_IGER4_EEP_STR_PRIME_INT(n) (1 << (5 * (n - 6) - 5)) - -/* EP PRD Ready (EP_PRD_RDY, offset = 504H) */ - -#define FUSB300_EPPRDR_EP15_PRD_RDY (1 << 15) -#define FUSB300_EPPRDR_EP14_PRD_RDY (1 << 14) -#define FUSB300_EPPRDR_EP13_PRD_RDY (1 << 13) -#define FUSB300_EPPRDR_EP12_PRD_RDY (1 << 12) -#define FUSB300_EPPRDR_EP11_PRD_RDY (1 << 11) -#define FUSB300_EPPRDR_EP10_PRD_RDY (1 << 10) -#define FUSB300_EPPRDR_EP9_PRD_RDY (1 << 9) -#define FUSB300_EPPRDR_EP8_PRD_RDY (1 << 8) -#define FUSB300_EPPRDR_EP7_PRD_RDY (1 << 7) -#define FUSB300_EPPRDR_EP6_PRD_RDY (1 << 6) -#define FUSB300_EPPRDR_EP5_PRD_RDY (1 << 5) -#define FUSB300_EPPRDR_EP4_PRD_RDY (1 << 4) -#define FUSB300_EPPRDR_EP3_PRD_RDY (1 << 3) -#define FUSB300_EPPRDR_EP2_PRD_RDY (1 << 2) -#define FUSB300_EPPRDR_EP1_PRD_RDY (1 << 1) -#define FUSB300_EPPRDR_EP_PRD_RDY(n) (1 << n) - -/* AHB Bus Control Register (offset = 514H) */ -#define FUSB300_AHBBCR_S1_SPLIT_ON (1 << 17) -#define FUSB300_AHBBCR_S0_SPLIT_ON (1 << 16) -#define FUSB300_AHBBCR_S1_1entry (0 << 12) -#define FUSB300_AHBBCR_S1_4entry (3 << 12) -#define FUSB300_AHBBCR_S1_8entry (5 << 12) -#define FUSB300_AHBBCR_S1_16entry (7 << 12) -#define FUSB300_AHBBCR_S0_1entry (0 << 8) -#define FUSB300_AHBBCR_S0_4entry (3 << 8) -#define FUSB300_AHBBCR_S0_8entry (5 << 8) -#define FUSB300_AHBBCR_S0_16entry (7 << 8) -#define FUSB300_AHBBCR_M1_BURST_SINGLE (0 << 4) -#define FUSB300_AHBBCR_M1_BURST_INCR (1 << 4) -#define FUSB300_AHBBCR_M1_BURST_INCR4 (3 << 4) -#define FUSB300_AHBBCR_M1_BURST_INCR8 (5 << 4) -#define FUSB300_AHBBCR_M1_BURST_INCR16 (7 << 4) -#define FUSB300_AHBBCR_M0_BURST_SINGLE 0 -#define FUSB300_AHBBCR_M0_BURST_INCR 1 -#define FUSB300_AHBBCR_M0_BURST_INCR4 3 -#define FUSB300_AHBBCR_M0_BURST_INCR8 5 -#define FUSB300_AHBBCR_M0_BURST_INCR16 7 -#define FUSB300_IGER5_EEP_STL_INT(n) (1 << n) - -/* WORD 0 Data Structure of PRD Table */ -#define FUSB300_EPPRD0_M (1 << 30) -#define FUSB300_EPPRD0_O (1 << 29) -/* The finished prd */ -#define FUSB300_EPPRD0_F (1 << 28) -#define FUSB300_EPPRD0_I (1 << 27) -#define FUSB300_EPPRD0_A (1 << 26) -/* To decide HW point to first prd at next time */ -#define FUSB300_EPPRD0_L (1 << 25) -#define FUSB300_EPPRD0_H (1 << 24) -#define FUSB300_EPPRD0_BTC(n) (n & 0xFFFFFF) - -/*----------------------------------------------------------------------*/ -#define FUSB300_MAX_NUM_EP 16 - -#define FUSB300_FIFO_ENTRY_NUM 8 -#define FUSB300_MAX_FIFO_ENTRY 8 - -#define SS_CTL_MAX_PACKET_SIZE 0x200 -#define SS_BULK_MAX_PACKET_SIZE 0x400 -#define SS_INT_MAX_PACKET_SIZE 0x400 -#define SS_ISO_MAX_PACKET_SIZE 0x400 - -#define HS_BULK_MAX_PACKET_SIZE 0x200 -#define HS_CTL_MAX_PACKET_SIZE 0x40 -#define HS_INT_MAX_PACKET_SIZE 0x400 -#define HS_ISO_MAX_PACKET_SIZE 0x400 - -struct fusb300_ep_info { - u8 epnum; - u8 type; - u8 interval; - u8 dir_in; - u16 maxpacket; - u16 addrofs; - u16 bw_num; -}; - -struct fusb300_request { - - struct usb_request req; - struct list_head queue; -}; - - -struct fusb300_ep { - struct usb_ep ep; - struct fusb300 *fusb300; - - struct list_head queue; - unsigned stall:1; - unsigned wedged:1; - unsigned use_dma:1; - - unsigned char epnum; - unsigned char type; - const struct usb_endpoint_descriptor *desc; -}; - -struct fusb300 { - spinlock_t lock; - void __iomem *reg; - - unsigned long irq_trigger; - - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - - struct fusb300_ep *ep[FUSB300_MAX_NUM_EP]; - - struct usb_request *ep0_req; /* for internal request */ - __le16 ep0_data; - u32 ep0_length; /* for internal request */ - u8 ep0_dir; /* 0/0x80 out/in */ - - u8 fifo_entry_num; /* next start fifo entry */ - u32 addrofs; /* next fifo address offset */ - u8 reenum; /* if re-enumeration */ -}; - -#endif diff --git a/ANDROID_3.4.5/drivers/usb/gadget/g_ffs.c b/ANDROID_3.4.5/drivers/usb/gadget/g_ffs.c deleted file mode 100644 index a85eaf40..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/g_ffs.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - * g_ffs.c -- user mode file system API for USB composite function controllers - * - * Copyright (C) 2010 Samsung Electronics - * Author: Michal Nazarewicz - * - * 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. - */ - -#define pr_fmt(fmt) "g_ffs: " fmt - -#include -#include - -/* - * 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" - -#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS -# if defined USB_ETH_RNDIS -# undef USB_ETH_RNDIS -# endif -# ifdef CONFIG_USB_FUNCTIONFS_RNDIS -# define USB_ETH_RNDIS y -# endif - -# include "f_ecm.c" -# include "f_subset.c" -# ifdef USB_ETH_RNDIS -# include "f_rndis.c" -# include "rndis.c" -# endif -# include "u_ether.c" - -static u8 gfs_hostaddr[ETH_ALEN]; -# ifdef CONFIG_USB_FUNCTIONFS_ETH -static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]); -# endif -#else -# define gether_cleanup() do { } while (0) -# define gether_setup(gadget, hostaddr) ((int)0) -# define gfs_hostaddr NULL -#endif - -#include "f_fs.c" - -#define DRIVER_NAME "g_ffs" -#define DRIVER_DESC "USB Function Filesystem" -#define DRIVER_VERSION "24 Aug 2004" - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Michal Nazarewicz"); -MODULE_LICENSE("GPL"); - -#define GFS_VENDOR_ID 0x1d6b /* Linux Foundation */ -#define GFS_PRODUCT_ID 0x0105 /* FunctionFS Gadget */ - -static struct usb_device_descriptor gfs_dev_desc = { - .bLength = sizeof gfs_dev_desc, - .bDescriptorType = USB_DT_DEVICE, - - .bcdUSB = cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_PER_INTERFACE, - - .idVendor = cpu_to_le16(GFS_VENDOR_ID), - .idProduct = cpu_to_le16(GFS_PRODUCT_ID), -}; - -module_param_named(bDeviceClass, gfs_dev_desc.bDeviceClass, byte, 0644); -MODULE_PARM_DESC(bDeviceClass, "USB Device class"); -module_param_named(bDeviceSubClass, gfs_dev_desc.bDeviceSubClass, byte, 0644); -MODULE_PARM_DESC(bDeviceSubClass, "USB Device subclass"); -module_param_named(bDeviceProtocol, gfs_dev_desc.bDeviceProtocol, byte, 0644); -MODULE_PARM_DESC(bDeviceProtocol, "USB Device protocol"); - -static const struct usb_descriptor_header *gfs_otg_desc[] = { - (const struct usb_descriptor_header *) - &(const struct usb_otg_descriptor) { - .bLength = sizeof(struct usb_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, - }, - - NULL -}; - -/* String IDs are assigned dynamically */ -static struct usb_string gfs_strings[] = { -#ifdef CONFIG_USB_FUNCTIONFS_RNDIS - { .s = "FunctionFS + RNDIS" }, -#endif -#ifdef CONFIG_USB_FUNCTIONFS_ETH - { .s = "FunctionFS + ECM" }, -#endif -#ifdef CONFIG_USB_FUNCTIONFS_GENERIC - { .s = "FunctionFS" }, -#endif - { } /* end of list */ -}; - -static struct usb_gadget_strings *gfs_dev_strings[] = { - &(struct usb_gadget_strings) { - .language = 0x0409, /* en-us */ - .strings = gfs_strings, - }, - NULL, -}; - -struct gfs_configuration { - struct usb_configuration c; - int (*eth)(struct usb_configuration *c, u8 *ethaddr); -} gfs_configurations[] = { -#ifdef CONFIG_USB_FUNCTIONFS_RNDIS - { - .eth = rndis_bind_config, - }, -#endif - -#ifdef CONFIG_USB_FUNCTIONFS_ETH - { - .eth = eth_bind_config, - }, -#endif - -#ifdef CONFIG_USB_FUNCTIONFS_GENERIC - { - }, -#endif -}; - -static int gfs_bind(struct usb_composite_dev *cdev); -static int gfs_unbind(struct usb_composite_dev *cdev); -static int gfs_do_config(struct usb_configuration *c); - -static struct usb_composite_driver gfs_driver = { - .name = DRIVER_NAME, - .dev = &gfs_dev_desc, - .strings = gfs_dev_strings, - .max_speed = USB_SPEED_HIGH, - .unbind = gfs_unbind, - .iProduct = DRIVER_DESC, -}; - -static struct ffs_data *gfs_ffs_data; -static unsigned long gfs_registered; - -static int __init gfs_init(void) -{ - ENTER(); - - return functionfs_init(); -} -module_init(gfs_init); - -static void __exit gfs_exit(void) -{ - ENTER(); - - if (test_and_clear_bit(0, &gfs_registered)) - usb_composite_unregister(&gfs_driver); - - functionfs_cleanup(); -} -module_exit(gfs_exit); - -static int functionfs_ready_callback(struct ffs_data *ffs) -{ - int ret; - - ENTER(); - - if (WARN_ON(test_and_set_bit(0, &gfs_registered))) - return -EBUSY; - - gfs_ffs_data = ffs; - ret = usb_composite_probe(&gfs_driver, gfs_bind); - if (unlikely(ret < 0)) - clear_bit(0, &gfs_registered); - return ret; -} - -static void functionfs_closed_callback(struct ffs_data *ffs) -{ - ENTER(); - - if (test_and_clear_bit(0, &gfs_registered)) - usb_composite_unregister(&gfs_driver); -} - -static int functionfs_check_dev_callback(const char *dev_name) -{ - return 0; -} - -static int gfs_bind(struct usb_composite_dev *cdev) -{ - int ret, i; - - ENTER(); - - if (WARN_ON(!gfs_ffs_data)) - return -ENODEV; - - ret = gether_setup(cdev->gadget, gfs_hostaddr); - if (unlikely(ret < 0)) - goto error_quick; - - ret = usb_string_ids_tab(cdev, gfs_strings); - if (unlikely(ret < 0)) - goto error; - - ret = functionfs_bind(gfs_ffs_data, cdev); - if (unlikely(ret < 0)) - goto error; - - for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) { - struct gfs_configuration *c = gfs_configurations + i; - - c->c.label = gfs_strings[i].s; - c->c.iConfiguration = gfs_strings[i].id; - c->c.bConfigurationValue = 1 + i; - c->c.bmAttributes = USB_CONFIG_ATT_SELFPOWER; - - ret = usb_add_config(cdev, &c->c, gfs_do_config); - if (unlikely(ret < 0)) - goto error_unbind; - } - - return 0; - -error_unbind: - functionfs_unbind(gfs_ffs_data); -error: - gether_cleanup(); -error_quick: - gfs_ffs_data = NULL; - return ret; -} - -static int gfs_unbind(struct usb_composite_dev *cdev) -{ - ENTER(); - - /* - * We may have been called in an error recovery from - * composite_bind() after gfs_unbind() failure so we need to - * check if gfs_ffs_data is not NULL since gfs_bind() handles - * all error recovery itself. I'd rather we werent called - * from composite on orror recovery, but what you're gonna - * do...? - */ - if (gfs_ffs_data) { - gether_cleanup(); - functionfs_unbind(gfs_ffs_data); - gfs_ffs_data = NULL; - } - - return 0; -} - -static int gfs_do_config(struct usb_configuration *c) -{ - struct gfs_configuration *gc = - container_of(c, struct gfs_configuration, c); - int ret; - - if (WARN_ON(!gfs_ffs_data)) - return -ENODEV; - - if (gadget_is_otg(c->cdev->gadget)) { - c->descriptors = gfs_otg_desc; - c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; - } - - if (gc->eth) { - ret = gc->eth(c, gfs_hostaddr); - if (unlikely(ret < 0)) - return ret; - } - - ret = functionfs_bind_config(c->cdev, c, gfs_ffs_data); - if (unlikely(ret < 0)) - return ret; - - /* - * After previous do_configs there may be some invalid - * pointers in c->interface array. This happens every time - * a user space function with fewer interfaces than a user - * space function that was run before the new one is run. The - * compasit's set_config() assumes that if there is no more - * then MAX_CONFIG_INTERFACES interfaces in a configuration - * then there is a NULL pointer after the last interface in - * c->interface array. We need to make sure this is true. - */ - if (c->next_interface_id < ARRAY_SIZE(c->interface)) - c->interface[c->next_interface_id] = NULL; - - return 0; -} - -#ifdef CONFIG_USB_FUNCTIONFS_ETH - -static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) -{ - return can_support_ecm(c->cdev->gadget) - ? ecm_bind_config(c, ethaddr) - : geth_bind_config(c, ethaddr); -} - -#endif diff --git a/ANDROID_3.4.5/drivers/usb/gadget/g_zero.h b/ANDROID_3.4.5/drivers/usb/gadget/g_zero.h deleted file mode 100644 index e84b3c47..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/g_zero.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * This header declares the utility functions used by "Gadget Zero", plus - * interfaces to its two single-configuration function drivers. - */ - -#ifndef __G_ZERO_H -#define __G_ZERO_H - -#include - -/* global state */ -extern unsigned buflen; -extern const struct usb_descriptor_header *otg_desc[]; - -/* common utilities */ -struct usb_request *alloc_ep_req(struct usb_ep *ep); -void free_ep_req(struct usb_ep *ep, struct usb_request *req); -void disable_endpoints(struct usb_composite_dev *cdev, - struct usb_ep *in, struct usb_ep *out); - -/* configuration-specific linkup */ -int sourcesink_add(struct usb_composite_dev *cdev, bool autoresume); -int loopback_add(struct usb_composite_dev *cdev, bool autoresume); - -#endif /* __G_ZERO_H */ diff --git a/ANDROID_3.4.5/drivers/usb/gadget/gadget_chips.h b/ANDROID_3.4.5/drivers/usb/gadget/gadget_chips.h deleted file mode 100644 index 30fad3e8..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/gadget_chips.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * USB device controllers have lots of quirks. Use these macros in - * gadget drivers or other code that needs to deal with them, and which - * autoconfigures instead of using early binding to the hardware. - * - * This SHOULD eventually work like the ARM mach_is_*() stuff, driven by - * some config file that gets updated as new hardware is supported. - * (And avoiding all runtime comparisons in typical one-choice configs!) - * - * NOTE: some of these controller drivers may not be available yet. - * Some are available on 2.4 kernels; several are available, but not - * yet pushed in the 2.6 mainline tree. - */ - -#ifndef __GADGET_CHIPS_H -#define __GADGET_CHIPS_H - -/* - * NOTICE: the entries below are alphabetical and should be kept - * that way. - * - * Always be sure to add new entries to the correct position or - * accept the bashing later. - * - * If you have forgotten the alphabetical order let VIM/EMACS - * do that for you. - */ -#define gadget_is_amd5536udc(g) (!strcmp("amd5536udc", (g)->name)) -#define gadget_is_wmt(g) (!strcmp("wmotgdev", (g)->name)) -#define gadget_is_at91(g) (!strcmp("at91_udc", (g)->name)) -#define gadget_is_atmel_usba(g) (!strcmp("atmel_usba_udc", (g)->name)) -#define gadget_is_ci13xxx_msm(g) (!strcmp("ci13xxx_msm", (g)->name)) -#define gadget_is_ci13xxx_pci(g) (!strcmp("ci13xxx_pci", (g)->name)) -#define gadget_is_dummy(g) (!strcmp("dummy_udc", (g)->name)) -#define gadget_is_dwc3(g) (!strcmp("dwc3-gadget", (g)->name)) -#define gadget_is_fsl_qe(g) (!strcmp("fsl_qe_udc", (g)->name)) -#define gadget_is_fsl_usb2(g) (!strcmp("fsl-usb2-udc", (g)->name)) -#define gadget_is_goku(g) (!strcmp("goku_udc", (g)->name)) -#define gadget_is_imx(g) (!strcmp("imx_udc", (g)->name)) -#define gadget_is_langwell(g) (!strcmp("langwell_udc", (g)->name)) -#define gadget_is_m66592(g) (!strcmp("m66592_udc", (g)->name)) -#define gadget_is_musbhdrc(g) (!strcmp("musb-hdrc", (g)->name)) -#define gadget_is_net2272(g) (!strcmp("net2272", (g)->name)) -#define gadget_is_net2280(g) (!strcmp("net2280", (g)->name)) -#define gadget_is_omap(g) (!strcmp("omap_udc", (g)->name)) -#define gadget_is_pch(g) (!strcmp("pch_udc", (g)->name)) -#define gadget_is_pxa(g) (!strcmp("pxa25x_udc", (g)->name)) -#define gadget_is_pxa27x(g) (!strcmp("pxa27x_udc", (g)->name)) -#define gadget_is_r8a66597(g) (!strcmp("r8a66597_udc", (g)->name)) -#define gadget_is_renesas_usbhs(g) (!strcmp("renesas_usbhs_udc", (g)->name)) -#define gadget_is_s3c2410(g) (!strcmp("s3c2410_udc", (g)->name)) -#define gadget_is_s3c_hsotg(g) (!strcmp("s3c-hsotg", (g)->name)) -#define gadget_is_s3c_hsudc(g) (!strcmp("s3c-hsudc", (g)->name)) - -/** - * usb_gadget_controller_number - support bcdDevice id convention - * @gadget: the controller being driven - * - * Return a 2-digit BCD value associated with the peripheral controller, - * suitable for use as part of a bcdDevice value, or a negative error code. - * - * NOTE: this convention is purely optional, and has no meaning in terms of - * any USB specification. If you want to use a different convention in your - * gadget driver firmware -- maybe a more formal revision ID -- feel free. - * - * Hosts see these bcdDevice numbers, and are allowed (but not encouraged!) - * to change their behavior accordingly. For example it might help avoiding - * some chip bug. - */ -static inline int usb_gadget_controller_number(struct usb_gadget *gadget) -{ - if (gadget_is_net2280(gadget)) - return 0x01; - else if (gadget_is_dummy(gadget)) - return 0x02; - else if (gadget_is_pxa(gadget)) - return 0x03; - else if (gadget_is_goku(gadget)) - return 0x06; - else if (gadget_is_omap(gadget)) - return 0x08; - else if (gadget_is_pxa27x(gadget)) - return 0x11; - else if (gadget_is_s3c2410(gadget)) - return 0x12; - else if (gadget_is_at91(gadget)) - return 0x13; - else if (gadget_is_imx(gadget)) - return 0x14; - else if (gadget_is_musbhdrc(gadget)) - return 0x16; - else if (gadget_is_atmel_usba(gadget)) - return 0x18; - else if (gadget_is_fsl_usb2(gadget)) - return 0x19; - else if (gadget_is_amd5536udc(gadget)) - return 0x20; - else if (gadget_is_m66592(gadget)) - return 0x21; - else if (gadget_is_fsl_qe(gadget)) - return 0x22; - else if (gadget_is_ci13xxx_pci(gadget)) - return 0x23; - else if (gadget_is_langwell(gadget)) - return 0x24; - else if (gadget_is_r8a66597(gadget)) - return 0x25; - else if (gadget_is_s3c_hsotg(gadget)) - return 0x26; - else if (gadget_is_pch(gadget)) - return 0x27; - else if (gadget_is_ci13xxx_msm(gadget)) - return 0x28; - else if (gadget_is_renesas_usbhs(gadget)) - return 0x29; - else if (gadget_is_s3c_hsudc(gadget)) - return 0x30; - else if (gadget_is_net2272(gadget)) - return 0x31; - else if (gadget_is_dwc3(gadget)) - return 0x32; - else if (gadget_is_wmt(gadget)) - return 0x33; - - return -ENOENT; -} - - -/** - * gadget_supports_altsettings - return true if altsettings work - * @gadget: the gadget in question - */ -static inline bool gadget_supports_altsettings(struct usb_gadget *gadget) -{ - /* PXA 21x/25x/26x has no altsettings at all */ - if (gadget_is_pxa(gadget)) - return false; - - /* PXA 27x and 3xx have *broken* altsetting support */ - if (gadget_is_pxa27x(gadget)) - return false; - - /* Everything else is *presumably* fine ... */ - return true; -} - -#endif /* __GADGET_CHIPS_H */ diff --git a/ANDROID_3.4.5/drivers/usb/gadget/gmidi.c b/ANDROID_3.4.5/drivers/usb/gadget/gmidi.c deleted file mode 100644 index 681bd038..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/gmidi.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * gmidi.c -- USB MIDI Gadget Driver - * - * Copyright (C) 2006 Thumtronics Pty Ltd. - * Developed for Thumtronics by Grey Innovation - * Ben Williamson - * - * This software is distributed under the terms of the GNU General Public - * License ("GPL") version 2, as published by the Free Software Foundation. - * - * This code is based in part on: - * - * Gadget Zero driver, Copyright (C) 2003-2004 David Brownell. - * USB Audio driver, Copyright (C) 2002 by Takashi Iwai. - * USB MIDI driver, Copyright (C) 2002-2005 Clemens Ladisch. - * - * Refer to the USB Device Class Definition for MIDI Devices: - * http://www.usb.org/developers/devclass_docs/midi10.pdf - */ - -/* #define VERBOSE_DEBUG */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include "gadget_chips.h" - -#include "composite.c" -#include "usbstring.c" -#include "config.c" -#include "epautoconf.c" -#include "f_midi.c" - -/*-------------------------------------------------------------------------*/ - -MODULE_AUTHOR("Ben Williamson"); -MODULE_LICENSE("GPL v2"); - -static const char shortname[] = "g_midi"; -static const char longname[] = "MIDI Gadget"; - -static int index = SNDRV_DEFAULT_IDX1; -module_param(index, int, S_IRUGO); -MODULE_PARM_DESC(index, "Index value for the USB MIDI Gadget adapter."); - -static char *id = SNDRV_DEFAULT_STR1; -module_param(id, charp, S_IRUGO); -MODULE_PARM_DESC(id, "ID string for the USB MIDI Gadget adapter."); - -static unsigned int buflen = 256; -module_param(buflen, uint, S_IRUGO); -MODULE_PARM_DESC(buflen, "MIDI buffer length"); - -static unsigned int qlen = 32; -module_param(qlen, uint, S_IRUGO); -MODULE_PARM_DESC(qlen, "USB read request queue length"); - -static unsigned int in_ports = 1; -module_param(in_ports, uint, S_IRUGO); -MODULE_PARM_DESC(in_ports, "Number of MIDI input ports"); - -static unsigned int out_ports = 1; -module_param(out_ports, uint, S_IRUGO); -MODULE_PARM_DESC(out_ports, "Number of MIDI output ports"); - -/* Thanks to Grey Innovation for donating this product ID. - * - * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! - * Instead: allocate your own, using normal USB-IF procedures. - */ -#define DRIVER_VENDOR_NUM 0x17b3 /* Grey Innovation */ -#define DRIVER_PRODUCT_NUM 0x0004 /* Linux-USB "MIDI Gadget" */ - -/* string IDs are assigned dynamically */ - -#define STRING_MANUFACTURER_IDX 0 -#define STRING_PRODUCT_IDX 1 -#define STRING_DESCRIPTION_IDX 2 - -static struct usb_device_descriptor device_desc = { - .bLength = USB_DT_DEVICE_SIZE, - .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = __constant_cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_PER_INTERFACE, - .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_NUM), - .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_NUM), - /* .iManufacturer = DYNAMIC */ - /* .iProduct = DYNAMIC */ - .bNumConfigurations = 1, -}; - -static struct usb_string strings_dev[] = { - [STRING_MANUFACTURER_IDX].s = "Grey Innovation", - [STRING_PRODUCT_IDX].s = "MIDI Gadget", - [STRING_DESCRIPTION_IDX].s = "MIDI", - { } /* end of list */ -}; - -static struct usb_gadget_strings stringtab_dev = { - .language = 0x0409, /* en-us */ - .strings = strings_dev, -}; - -static struct usb_gadget_strings *dev_strings[] = { - &stringtab_dev, - NULL, -}; - -static int __exit midi_unbind(struct usb_composite_dev *dev) -{ - return 0; -} - -static struct usb_configuration midi_config = { - .label = "MIDI Gadget", - .bConfigurationValue = 1, - /* .iConfiguration = DYNAMIC */ - .bmAttributes = USB_CONFIG_ATT_ONE, - .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2, -}; - -static int __init midi_bind_config(struct usb_configuration *c) -{ - return f_midi_bind_config(c, index, id, - in_ports, out_ports, - buflen, qlen); -} - -static int __init midi_bind(struct usb_composite_dev *cdev) -{ - struct usb_gadget *gadget = cdev->gadget; - int gcnum, status; - - status = usb_string_id(cdev); - if (status < 0) - return status; - strings_dev[STRING_MANUFACTURER_IDX].id = status; - device_desc.iManufacturer = status; - - status = usb_string_id(cdev); - if (status < 0) - return status; - strings_dev[STRING_PRODUCT_IDX].id = status; - device_desc.iProduct = status; - - /* config description */ - status = usb_string_id(cdev); - if (status < 0) - return status; - strings_dev[STRING_DESCRIPTION_IDX].id = status; - - midi_config.iConfiguration = status; - - gcnum = usb_gadget_controller_number(gadget); - if (gcnum < 0) { - /* gmidi is so simple (no altsettings) that - * it SHOULD NOT have problems with bulk-capable hardware. - * so warn about unrecognized controllers, don't panic. - */ - pr_warning("%s: controller '%s' not recognized\n", - __func__, gadget->name); - device_desc.bcdDevice = cpu_to_le16(0x9999); - } else { - device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum); - } - - status = usb_add_config(cdev, &midi_config, midi_bind_config); - if (status < 0) - return status; - - pr_info("%s\n", longname); - return 0; -} - -static struct usb_composite_driver midi_driver = { - .name = (char *) longname, - .dev = &device_desc, - .strings = dev_strings, - .max_speed = USB_SPEED_HIGH, - .unbind = __exit_p(midi_unbind), -}; - -static int __init midi_init(void) -{ - return usb_composite_probe(&midi_driver, midi_bind); -} -module_init(midi_init); - -static void __exit midi_cleanup(void) -{ - usb_composite_unregister(&midi_driver); -} -module_exit(midi_cleanup); - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/goku_udc.c b/ANDROID_3.4.5/drivers/usb/gadget/goku_udc.c deleted file mode 100644 index e151d6b8..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/goku_udc.c +++ /dev/null @@ -1,1908 +0,0 @@ -/* - * Toshiba TC86C001 ("Goku-S") USB Device Controller driver - * - * Copyright (C) 2000-2002 Lineo - * by Stuart Lynne, Tom Rushworth, and Bruce Balden - * Copyright (C) 2002 Toshiba Corporation - * Copyright (C) 2003 MontaVista Software (source@mvista.com) - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -/* - * This device has ep0 and three semi-configurable bulk/interrupt endpoints. - * - * - Endpoint numbering is fixed: ep{1,2,3}-bulk - * - Gadget drivers can choose ep maxpacket (8/16/32/64) - * - Gadget drivers can choose direction (IN, OUT) - * - DMA works with ep1 (OUT transfers) and ep2 (IN transfers). - */ - -// #define VERBOSE /* extra debug messages (success too) */ -// #define USB_TRACE /* packet-level success messages */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - - -#include "goku_udc.h" - -#define DRIVER_DESC "TC86C001 USB Device Controller" -#define DRIVER_VERSION "30-Oct 2003" - -#define DMA_ADDR_INVALID (~(dma_addr_t)0) - -static const char driver_name [] = "goku_udc"; -static const char driver_desc [] = DRIVER_DESC; - -MODULE_AUTHOR("source@mvista.com"); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - - -/* - * IN dma behaves ok under testing, though the IN-dma abort paths don't - * seem to behave quite as expected. Used by default. - * - * OUT dma documents design problems handling the common "short packet" - * transfer termination policy; it couldn't be enabled by default, even - * if the OUT-dma abort problems had a resolution. - */ -static unsigned use_dma = 1; - -#if 0 -//#include -/* "modprobe goku_udc use_dma=1" etc - * 0 to disable dma - * 1 to use IN dma only (normal operation) - * 2 to use IN and OUT dma - */ -module_param(use_dma, uint, S_IRUGO); -#endif - -/*-------------------------------------------------------------------------*/ - -static void nuke(struct goku_ep *, int status); - -static inline void -command(struct goku_udc_regs __iomem *regs, int command, unsigned epnum) -{ - writel(COMMAND_EP(epnum) | command, ®s->Command); - udelay(300); -} - -static int -goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) -{ - struct goku_udc *dev; - struct goku_ep *ep; - u32 mode; - u16 max; - unsigned long flags; - - ep = container_of(_ep, struct goku_ep, ep); - if (!_ep || !desc || ep->desc - || desc->bDescriptorType != USB_DT_ENDPOINT) - return -EINVAL; - dev = ep->dev; - if (ep == &dev->ep[0]) - return -EINVAL; - if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - if (ep->num != usb_endpoint_num(desc)) - return -EINVAL; - - switch (usb_endpoint_type(desc)) { - case USB_ENDPOINT_XFER_BULK: - case USB_ENDPOINT_XFER_INT: - break; - default: - return -EINVAL; - } - - if ((readl(ep->reg_status) & EPxSTATUS_EP_MASK) - != EPxSTATUS_EP_INVALID) - return -EBUSY; - - /* enabling the no-toggle interrupt mode would need an api hook */ - mode = 0; - max = get_unaligned_le16(&desc->wMaxPacketSize); - switch (max) { - case 64: mode++; - case 32: mode++; - case 16: mode++; - case 8: mode <<= 3; - break; - default: - return -EINVAL; - } - mode |= 2 << 1; /* bulk, or intr-with-toggle */ - - /* ep1/ep2 dma direction is chosen early; it works in the other - * direction, with pio. be cautious with out-dma. - */ - ep->is_in = usb_endpoint_dir_in(desc); - if (ep->is_in) { - mode |= 1; - ep->dma = (use_dma != 0) && (ep->num == UDC_MSTRD_ENDPOINT); - } else { - ep->dma = (use_dma == 2) && (ep->num == UDC_MSTWR_ENDPOINT); - if (ep->dma) - DBG(dev, "%s out-dma hides short packets\n", - ep->ep.name); - } - - spin_lock_irqsave(&ep->dev->lock, flags); - - /* ep1 and ep2 can do double buffering and/or dma */ - if (ep->num < 3) { - struct goku_udc_regs __iomem *regs = ep->dev->regs; - u32 tmp; - - /* double buffer except (for now) with pio in */ - tmp = ((ep->dma || !ep->is_in) - ? 0x10 /* double buffered */ - : 0x11 /* single buffer */ - ) << ep->num; - tmp |= readl(®s->EPxSingle); - writel(tmp, ®s->EPxSingle); - - tmp = (ep->dma ? 0x10/*dma*/ : 0x11/*pio*/) << ep->num; - tmp |= readl(®s->EPxBCS); - writel(tmp, ®s->EPxBCS); - } - writel(mode, ep->reg_mode); - command(ep->dev->regs, COMMAND_RESET, ep->num); - ep->ep.maxpacket = max; - ep->stopped = 0; - ep->desc = desc; - spin_unlock_irqrestore(&ep->dev->lock, flags); - - DBG(dev, "enable %s %s %s maxpacket %u\n", ep->ep.name, - ep->is_in ? "IN" : "OUT", - ep->dma ? "dma" : "pio", - max); - - return 0; -} - -static void ep_reset(struct goku_udc_regs __iomem *regs, struct goku_ep *ep) -{ - struct goku_udc *dev = ep->dev; - - if (regs) { - command(regs, COMMAND_INVALID, ep->num); - if (ep->num) { - if (ep->num == UDC_MSTWR_ENDPOINT) - dev->int_enable &= ~(INT_MSTWREND - |INT_MSTWRTMOUT); - else if (ep->num == UDC_MSTRD_ENDPOINT) - dev->int_enable &= ~INT_MSTRDEND; - dev->int_enable &= ~INT_EPxDATASET (ep->num); - } else - dev->int_enable &= ~INT_EP0; - writel(dev->int_enable, ®s->int_enable); - readl(®s->int_enable); - if (ep->num < 3) { - struct goku_udc_regs __iomem *r = ep->dev->regs; - u32 tmp; - - tmp = readl(&r->EPxSingle); - tmp &= ~(0x11 << ep->num); - writel(tmp, &r->EPxSingle); - - tmp = readl(&r->EPxBCS); - tmp &= ~(0x11 << ep->num); - writel(tmp, &r->EPxBCS); - } - /* reset dma in case we're still using it */ - if (ep->dma) { - u32 master; - - master = readl(®s->dma_master) & MST_RW_BITS; - if (ep->num == UDC_MSTWR_ENDPOINT) { - master &= ~MST_W_BITS; - master |= MST_WR_RESET; - } else { - master &= ~MST_R_BITS; - master |= MST_RD_RESET; - } - writel(master, ®s->dma_master); - } - } - - ep->ep.maxpacket = MAX_FIFO_SIZE; - ep->desc = NULL; - ep->ep.desc = NULL; - ep->stopped = 1; - ep->irqs = 0; - ep->dma = 0; -} - -static int goku_ep_disable(struct usb_ep *_ep) -{ - struct goku_ep *ep; - struct goku_udc *dev; - unsigned long flags; - - ep = container_of(_ep, struct goku_ep, ep); - if (!_ep || !ep->desc) - return -ENODEV; - dev = ep->dev; - if (dev->ep0state == EP0_SUSPEND) - return -EBUSY; - - VDBG(dev, "disable %s\n", _ep->name); - - spin_lock_irqsave(&dev->lock, flags); - nuke(ep, -ESHUTDOWN); - ep_reset(dev->regs, ep); - spin_unlock_irqrestore(&dev->lock, flags); - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static struct usb_request * -goku_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) -{ - struct goku_request *req; - - if (!_ep) - return NULL; - req = kzalloc(sizeof *req, gfp_flags); - if (!req) - return NULL; - - req->req.dma = DMA_ADDR_INVALID; - INIT_LIST_HEAD(&req->queue); - return &req->req; -} - -static void -goku_free_request(struct usb_ep *_ep, struct usb_request *_req) -{ - struct goku_request *req; - - if (!_ep || !_req) - return; - - req = container_of(_req, struct goku_request, req); - WARN_ON(!list_empty(&req->queue)); - kfree(req); -} - -/*-------------------------------------------------------------------------*/ - -static void -done(struct goku_ep *ep, struct goku_request *req, int status) -{ - struct goku_udc *dev; - unsigned stopped = ep->stopped; - - list_del_init(&req->queue); - - if (likely(req->req.status == -EINPROGRESS)) - req->req.status = status; - else - status = req->req.status; - - dev = ep->dev; - - if (ep->dma) - usb_gadget_unmap_request(&dev->gadget, &req->req, ep->is_in); - -#ifndef USB_TRACE - if (status && status != -ESHUTDOWN) -#endif - VDBG(dev, "complete %s req %p stat %d len %u/%u\n", - ep->ep.name, &req->req, status, - req->req.actual, req->req.length); - - /* don't modify queue heads during completion callback */ - ep->stopped = 1; - spin_unlock(&dev->lock); - req->req.complete(&ep->ep, &req->req); - spin_lock(&dev->lock); - ep->stopped = stopped; -} - -/*-------------------------------------------------------------------------*/ - -static inline int -write_packet(u32 __iomem *fifo, u8 *buf, struct goku_request *req, unsigned max) -{ - unsigned length, count; - - length = min(req->req.length - req->req.actual, max); - req->req.actual += length; - - count = length; - while (likely(count--)) - writel(*buf++, fifo); - return length; -} - -// return: 0 = still running, 1 = completed, negative = errno -static int write_fifo(struct goku_ep *ep, struct goku_request *req) -{ - struct goku_udc *dev = ep->dev; - u32 tmp; - u8 *buf; - unsigned count; - int is_last; - - tmp = readl(&dev->regs->DataSet); - buf = req->req.buf + req->req.actual; - prefetch(buf); - - dev = ep->dev; - if (unlikely(ep->num == 0 && dev->ep0state != EP0_IN)) - return -EL2HLT; - - /* NOTE: just single-buffered PIO-IN for now. */ - if (unlikely((tmp & DATASET_A(ep->num)) != 0)) - return 0; - - /* clear our "packet available" irq */ - if (ep->num != 0) - writel(~INT_EPxDATASET(ep->num), &dev->regs->int_status); - - count = write_packet(ep->reg_fifo, buf, req, ep->ep.maxpacket); - - /* last packet often short (sometimes a zlp, especially on ep0) */ - if (unlikely(count != ep->ep.maxpacket)) { - writel(~(1<num), &dev->regs->EOP); - if (ep->num == 0) { - dev->ep[0].stopped = 1; - dev->ep0state = EP0_STATUS; - } - is_last = 1; - } else { - if (likely(req->req.length != req->req.actual) - || req->req.zero) - is_last = 0; - else - is_last = 1; - } -#if 0 /* printk seemed to trash is_last...*/ -//#ifdef USB_TRACE - VDBG(dev, "wrote %s %u bytes%s IN %u left %p\n", - ep->ep.name, count, is_last ? "/last" : "", - req->req.length - req->req.actual, req); -#endif - - /* requests complete when all IN data is in the FIFO, - * or sometimes later, if a zlp was needed. - */ - if (is_last) { - done(ep, req, 0); - return 1; - } - - return 0; -} - -static int read_fifo(struct goku_ep *ep, struct goku_request *req) -{ - struct goku_udc_regs __iomem *regs; - u32 size, set; - u8 *buf; - unsigned bufferspace, is_short, dbuff; - - regs = ep->dev->regs; -top: - buf = req->req.buf + req->req.actual; - prefetchw(buf); - - if (unlikely(ep->num == 0 && ep->dev->ep0state != EP0_OUT)) - return -EL2HLT; - - dbuff = (ep->num == 1 || ep->num == 2); - do { - /* ack dataset irq matching the status we'll handle */ - if (ep->num != 0) - writel(~INT_EPxDATASET(ep->num), ®s->int_status); - - set = readl(®s->DataSet) & DATASET_AB(ep->num); - size = readl(®s->EPxSizeLA[ep->num]); - bufferspace = req->req.length - req->req.actual; - - /* usually do nothing without an OUT packet */ - if (likely(ep->num != 0 || bufferspace != 0)) { - if (unlikely(set == 0)) - break; - /* use ep1/ep2 double-buffering for OUT */ - if (!(size & PACKET_ACTIVE)) - size = readl(®s->EPxSizeLB[ep->num]); - if (!(size & PACKET_ACTIVE)) /* "can't happen" */ - break; - size &= DATASIZE; /* EPxSizeH == 0 */ - - /* ep0out no-out-data case for set_config, etc */ - } else - size = 0; - - /* read all bytes from this packet */ - req->req.actual += size; - is_short = (size < ep->ep.maxpacket); -#ifdef USB_TRACE - VDBG(ep->dev, "read %s %u bytes%s OUT req %p %u/%u\n", - ep->ep.name, size, is_short ? "/S" : "", - req, req->req.actual, req->req.length); -#endif - while (likely(size-- != 0)) { - u8 byte = (u8) readl(ep->reg_fifo); - - if (unlikely(bufferspace == 0)) { - /* this happens when the driver's buffer - * is smaller than what the host sent. - * discard the extra data in this packet. - */ - if (req->req.status != -EOVERFLOW) - DBG(ep->dev, "%s overflow %u\n", - ep->ep.name, size); - req->req.status = -EOVERFLOW; - } else { - *buf++ = byte; - bufferspace--; - } - } - - /* completion */ - if (unlikely(is_short || req->req.actual == req->req.length)) { - if (unlikely(ep->num == 0)) { - /* non-control endpoints now usable? */ - if (ep->dev->req_config) - writel(ep->dev->configured - ? USBSTATE_CONFIGURED - : 0, - ®s->UsbState); - /* ep0out status stage */ - writel(~(1<<0), ®s->EOP); - ep->stopped = 1; - ep->dev->ep0state = EP0_STATUS; - } - done(ep, req, 0); - - /* empty the second buffer asap */ - if (dbuff && !list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, - struct goku_request, queue); - goto top; - } - return 1; - } - } while (dbuff); - return 0; -} - -static inline void -pio_irq_enable(struct goku_udc *dev, - struct goku_udc_regs __iomem *regs, int epnum) -{ - dev->int_enable |= INT_EPxDATASET (epnum); - writel(dev->int_enable, ®s->int_enable); - /* write may still be posted */ -} - -static inline void -pio_irq_disable(struct goku_udc *dev, - struct goku_udc_regs __iomem *regs, int epnum) -{ - dev->int_enable &= ~INT_EPxDATASET (epnum); - writel(dev->int_enable, ®s->int_enable); - /* write may still be posted */ -} - -static inline void -pio_advance(struct goku_ep *ep) -{ - struct goku_request *req; - - if (unlikely(list_empty (&ep->queue))) - return; - req = list_entry(ep->queue.next, struct goku_request, queue); - (ep->is_in ? write_fifo : read_fifo)(ep, req); -} - - -/*-------------------------------------------------------------------------*/ - -// return: 0 = q running, 1 = q stopped, negative = errno -static int start_dma(struct goku_ep *ep, struct goku_request *req) -{ - struct goku_udc_regs __iomem *regs = ep->dev->regs; - u32 master; - u32 start = req->req.dma; - u32 end = start + req->req.length - 1; - - master = readl(®s->dma_master) & MST_RW_BITS; - - /* re-init the bits affecting IN dma; careful with zlps */ - if (likely(ep->is_in)) { - if (unlikely(master & MST_RD_ENA)) { - DBG (ep->dev, "start, IN active dma %03x!!\n", - master); -// return -EL2HLT; - } - writel(end, ®s->in_dma_end); - writel(start, ®s->in_dma_start); - - master &= ~MST_R_BITS; - if (unlikely(req->req.length == 0)) - master = MST_RD_ENA | MST_RD_EOPB; - else if ((req->req.length % ep->ep.maxpacket) != 0 - || req->req.zero) - master = MST_RD_ENA | MST_EOPB_ENA; - else - master = MST_RD_ENA | MST_EOPB_DIS; - - ep->dev->int_enable |= INT_MSTRDEND; - - /* Goku DMA-OUT merges short packets, which plays poorly with - * protocols where short packets mark the transfer boundaries. - * The chip supports a nonstandard policy with INT_MSTWRTMOUT, - * ending transfers after 3 SOFs; we don't turn it on. - */ - } else { - if (unlikely(master & MST_WR_ENA)) { - DBG (ep->dev, "start, OUT active dma %03x!!\n", - master); -// return -EL2HLT; - } - writel(end, ®s->out_dma_end); - writel(start, ®s->out_dma_start); - - master &= ~MST_W_BITS; - master |= MST_WR_ENA | MST_TIMEOUT_DIS; - - ep->dev->int_enable |= INT_MSTWREND|INT_MSTWRTMOUT; - } - - writel(master, ®s->dma_master); - writel(ep->dev->int_enable, ®s->int_enable); - return 0; -} - -static void dma_advance(struct goku_udc *dev, struct goku_ep *ep) -{ - struct goku_request *req; - struct goku_udc_regs __iomem *regs = ep->dev->regs; - u32 master; - - master = readl(®s->dma_master); - - if (unlikely(list_empty(&ep->queue))) { -stop: - if (ep->is_in) - dev->int_enable &= ~INT_MSTRDEND; - else - dev->int_enable &= ~(INT_MSTWREND|INT_MSTWRTMOUT); - writel(dev->int_enable, ®s->int_enable); - return; - } - req = list_entry(ep->queue.next, struct goku_request, queue); - - /* normal hw dma completion (not abort) */ - if (likely(ep->is_in)) { - if (unlikely(master & MST_RD_ENA)) - return; - req->req.actual = readl(®s->in_dma_current); - } else { - if (unlikely(master & MST_WR_ENA)) - return; - - /* hardware merges short packets, and also hides packet - * overruns. a partial packet MAY be in the fifo here. - */ - req->req.actual = readl(®s->out_dma_current); - } - req->req.actual -= req->req.dma; - req->req.actual++; - -#ifdef USB_TRACE - VDBG(dev, "done %s %s dma, %u/%u bytes, req %p\n", - ep->ep.name, ep->is_in ? "IN" : "OUT", - req->req.actual, req->req.length, req); -#endif - done(ep, req, 0); - if (list_empty(&ep->queue)) - goto stop; - req = list_entry(ep->queue.next, struct goku_request, queue); - (void) start_dma(ep, req); -} - -static void abort_dma(struct goku_ep *ep, int status) -{ - struct goku_udc_regs __iomem *regs = ep->dev->regs; - struct goku_request *req; - u32 curr, master; - - /* NAK future host requests, hoping the implicit delay lets the - * dma engine finish reading (or writing) its latest packet and - * empty the dma buffer (up to 16 bytes). - * - * This avoids needing to clean up a partial packet in the fifo; - * we can't do that for IN without side effects to HALT and TOGGLE. - */ - command(regs, COMMAND_FIFO_DISABLE, ep->num); - req = list_entry(ep->queue.next, struct goku_request, queue); - master = readl(®s->dma_master) & MST_RW_BITS; - - /* FIXME using these resets isn't usably documented. this may - * not work unless it's followed by disabling the endpoint. - * - * FIXME the OUT reset path doesn't even behave consistently. - */ - if (ep->is_in) { - if (unlikely((readl(®s->dma_master) & MST_RD_ENA) == 0)) - goto finished; - curr = readl(®s->in_dma_current); - - writel(curr, ®s->in_dma_end); - writel(curr, ®s->in_dma_start); - - master &= ~MST_R_BITS; - master |= MST_RD_RESET; - writel(master, ®s->dma_master); - - if (readl(®s->dma_master) & MST_RD_ENA) - DBG(ep->dev, "IN dma active after reset!\n"); - - } else { - if (unlikely((readl(®s->dma_master) & MST_WR_ENA) == 0)) - goto finished; - curr = readl(®s->out_dma_current); - - writel(curr, ®s->out_dma_end); - writel(curr, ®s->out_dma_start); - - master &= ~MST_W_BITS; - master |= MST_WR_RESET; - writel(master, ®s->dma_master); - - if (readl(®s->dma_master) & MST_WR_ENA) - DBG(ep->dev, "OUT dma active after reset!\n"); - } - req->req.actual = (curr - req->req.dma) + 1; - req->req.status = status; - - VDBG(ep->dev, "%s %s %s %d/%d\n", __func__, ep->ep.name, - ep->is_in ? "IN" : "OUT", - req->req.actual, req->req.length); - - command(regs, COMMAND_FIFO_ENABLE, ep->num); - - return; - -finished: - /* dma already completed; no abort needed */ - command(regs, COMMAND_FIFO_ENABLE, ep->num); - req->req.actual = req->req.length; - req->req.status = 0; -} - -/*-------------------------------------------------------------------------*/ - -static int -goku_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) -{ - struct goku_request *req; - struct goku_ep *ep; - struct goku_udc *dev; - unsigned long flags; - int status; - - /* always require a cpu-view buffer so pio works */ - req = container_of(_req, struct goku_request, req); - if (unlikely(!_req || !_req->complete - || !_req->buf || !list_empty(&req->queue))) - return -EINVAL; - ep = container_of(_ep, struct goku_ep, ep); - if (unlikely(!_ep || (!ep->desc && ep->num != 0))) - return -EINVAL; - dev = ep->dev; - if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) - return -ESHUTDOWN; - - /* can't touch registers when suspended */ - if (dev->ep0state == EP0_SUSPEND) - return -EBUSY; - - /* set up dma mapping in case the caller didn't */ - if (ep->dma) { - status = usb_gadget_map_request(&dev->gadget, &req->req, - ep->is_in); - if (status) - return status; - } - -#ifdef USB_TRACE - VDBG(dev, "%s queue req %p, len %u buf %p\n", - _ep->name, _req, _req->length, _req->buf); -#endif - - spin_lock_irqsave(&dev->lock, flags); - - _req->status = -EINPROGRESS; - _req->actual = 0; - - /* for ep0 IN without premature status, zlp is required and - * writing EOP starts the status stage (OUT). - */ - if (unlikely(ep->num == 0 && ep->is_in)) - _req->zero = 1; - - /* kickstart this i/o queue? */ - status = 0; - if (list_empty(&ep->queue) && likely(!ep->stopped)) { - /* dma: done after dma completion IRQ (or error) - * pio: done after last fifo operation - */ - if (ep->dma) - status = start_dma(ep, req); - else - status = (ep->is_in ? write_fifo : read_fifo)(ep, req); - - if (unlikely(status != 0)) { - if (status > 0) - status = 0; - req = NULL; - } - - } /* else pio or dma irq handler advances the queue. */ - - if (likely(req != 0)) - list_add_tail(&req->queue, &ep->queue); - - if (likely(!list_empty(&ep->queue)) - && likely(ep->num != 0) - && !ep->dma - && !(dev->int_enable & INT_EPxDATASET (ep->num))) - pio_irq_enable(dev, dev->regs, ep->num); - - spin_unlock_irqrestore(&dev->lock, flags); - - /* pci writes may still be posted */ - return status; -} - -/* dequeue ALL requests */ -static void nuke(struct goku_ep *ep, int status) -{ - struct goku_request *req; - - ep->stopped = 1; - if (list_empty(&ep->queue)) - return; - if (ep->dma) - abort_dma(ep, status); - while (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, struct goku_request, queue); - done(ep, req, status); - } -} - -/* dequeue JUST ONE request */ -static int goku_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct goku_request *req; - struct goku_ep *ep; - struct goku_udc *dev; - unsigned long flags; - - ep = container_of(_ep, struct goku_ep, ep); - if (!_ep || !_req || (!ep->desc && ep->num != 0)) - return -EINVAL; - dev = ep->dev; - if (!dev->driver) - return -ESHUTDOWN; - - /* we can't touch (dma) registers when suspended */ - if (dev->ep0state == EP0_SUSPEND) - return -EBUSY; - - VDBG(dev, "%s %s %s %s %p\n", __func__, _ep->name, - ep->is_in ? "IN" : "OUT", - ep->dma ? "dma" : "pio", - _req); - - spin_lock_irqsave(&dev->lock, flags); - - /* make sure it's actually queued on this endpoint */ - list_for_each_entry (req, &ep->queue, queue) { - if (&req->req == _req) - break; - } - if (&req->req != _req) { - spin_unlock_irqrestore (&dev->lock, flags); - return -EINVAL; - } - - if (ep->dma && ep->queue.next == &req->queue && !ep->stopped) { - abort_dma(ep, -ECONNRESET); - done(ep, req, -ECONNRESET); - dma_advance(dev, ep); - } else if (!list_empty(&req->queue)) - done(ep, req, -ECONNRESET); - else - req = NULL; - spin_unlock_irqrestore(&dev->lock, flags); - - return req ? 0 : -EOPNOTSUPP; -} - -/*-------------------------------------------------------------------------*/ - -static void goku_clear_halt(struct goku_ep *ep) -{ - // assert (ep->num !=0) - VDBG(ep->dev, "%s clear halt\n", ep->ep.name); - command(ep->dev->regs, COMMAND_SETDATA0, ep->num); - command(ep->dev->regs, COMMAND_STALL_CLEAR, ep->num); - if (ep->stopped) { - ep->stopped = 0; - if (ep->dma) { - struct goku_request *req; - - if (list_empty(&ep->queue)) - return; - req = list_entry(ep->queue.next, struct goku_request, - queue); - (void) start_dma(ep, req); - } else - pio_advance(ep); - } -} - -static int goku_set_halt(struct usb_ep *_ep, int value) -{ - struct goku_ep *ep; - unsigned long flags; - int retval = 0; - - if (!_ep) - return -ENODEV; - ep = container_of (_ep, struct goku_ep, ep); - - if (ep->num == 0) { - if (value) { - ep->dev->ep0state = EP0_STALL; - ep->dev->ep[0].stopped = 1; - } else - return -EINVAL; - - /* don't change EPxSTATUS_EP_INVALID to READY */ - } else if (!ep->desc) { - DBG(ep->dev, "%s %s inactive?\n", __func__, ep->ep.name); - return -EINVAL; - } - - spin_lock_irqsave(&ep->dev->lock, flags); - if (!list_empty(&ep->queue)) - retval = -EAGAIN; - else if (ep->is_in && value - /* data in (either) packet buffer? */ - && (readl(&ep->dev->regs->DataSet) - & DATASET_AB(ep->num))) - retval = -EAGAIN; - else if (!value) - goku_clear_halt(ep); - else { - ep->stopped = 1; - VDBG(ep->dev, "%s set halt\n", ep->ep.name); - command(ep->dev->regs, COMMAND_STALL, ep->num); - readl(ep->reg_status); - } - spin_unlock_irqrestore(&ep->dev->lock, flags); - return retval; -} - -static int goku_fifo_status(struct usb_ep *_ep) -{ - struct goku_ep *ep; - struct goku_udc_regs __iomem *regs; - u32 size; - - if (!_ep) - return -ENODEV; - ep = container_of(_ep, struct goku_ep, ep); - - /* size is only reported sanely for OUT */ - if (ep->is_in) - return -EOPNOTSUPP; - - /* ignores 16-byte dma buffer; SizeH == 0 */ - regs = ep->dev->regs; - size = readl(®s->EPxSizeLA[ep->num]) & DATASIZE; - size += readl(®s->EPxSizeLB[ep->num]) & DATASIZE; - VDBG(ep->dev, "%s %s %u\n", __func__, ep->ep.name, size); - return size; -} - -static void goku_fifo_flush(struct usb_ep *_ep) -{ - struct goku_ep *ep; - struct goku_udc_regs __iomem *regs; - u32 size; - - if (!_ep) - return; - ep = container_of(_ep, struct goku_ep, ep); - VDBG(ep->dev, "%s %s\n", __func__, ep->ep.name); - - /* don't change EPxSTATUS_EP_INVALID to READY */ - if (!ep->desc && ep->num != 0) { - DBG(ep->dev, "%s %s inactive?\n", __func__, ep->ep.name); - return; - } - - regs = ep->dev->regs; - size = readl(®s->EPxSizeLA[ep->num]); - size &= DATASIZE; - - /* Non-desirable behavior: FIFO_CLEAR also clears the - * endpoint halt feature. For OUT, we _could_ just read - * the bytes out (PIO, if !ep->dma); for in, no choice. - */ - if (size) - command(regs, COMMAND_FIFO_CLEAR, ep->num); -} - -static struct usb_ep_ops goku_ep_ops = { - .enable = goku_ep_enable, - .disable = goku_ep_disable, - - .alloc_request = goku_alloc_request, - .free_request = goku_free_request, - - .queue = goku_queue, - .dequeue = goku_dequeue, - - .set_halt = goku_set_halt, - .fifo_status = goku_fifo_status, - .fifo_flush = goku_fifo_flush, -}; - -/*-------------------------------------------------------------------------*/ - -static int goku_get_frame(struct usb_gadget *_gadget) -{ - return -EOPNOTSUPP; -} - -static int goku_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int goku_stop(struct usb_gadget_driver *driver); - -static const struct usb_gadget_ops goku_ops = { - .get_frame = goku_get_frame, - .start = goku_start, - .stop = goku_stop, - // no remote wakeup - // not selfpowered -}; - -/*-------------------------------------------------------------------------*/ - -static inline char *dmastr(void) -{ - if (use_dma == 0) - return "(dma disabled)"; - else if (use_dma == 2) - return "(dma IN and OUT)"; - else - return "(dma IN)"; -} - -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - -static const char proc_node_name [] = "driver/udc"; - -#define FOURBITS "%s%s%s%s" -#define EIGHTBITS FOURBITS FOURBITS - -static void -dump_intmask(const char *label, u32 mask, char **next, unsigned *size) -{ - int t; - - /* int_status is the same format ... */ - t = scnprintf(*next, *size, - "%s %05X =" FOURBITS EIGHTBITS EIGHTBITS "\n", - label, mask, - (mask & INT_PWRDETECT) ? " power" : "", - (mask & INT_SYSERROR) ? " sys" : "", - (mask & INT_MSTRDEND) ? " in-dma" : "", - (mask & INT_MSTWRTMOUT) ? " wrtmo" : "", - - (mask & INT_MSTWREND) ? " out-dma" : "", - (mask & INT_MSTWRSET) ? " wrset" : "", - (mask & INT_ERR) ? " err" : "", - (mask & INT_SOF) ? " sof" : "", - - (mask & INT_EP3NAK) ? " ep3nak" : "", - (mask & INT_EP2NAK) ? " ep2nak" : "", - (mask & INT_EP1NAK) ? " ep1nak" : "", - (mask & INT_EP3DATASET) ? " ep3" : "", - - (mask & INT_EP2DATASET) ? " ep2" : "", - (mask & INT_EP1DATASET) ? " ep1" : "", - (mask & INT_STATUSNAK) ? " ep0snak" : "", - (mask & INT_STATUS) ? " ep0status" : "", - - (mask & INT_SETUP) ? " setup" : "", - (mask & INT_ENDPOINT0) ? " ep0" : "", - (mask & INT_USBRESET) ? " reset" : "", - (mask & INT_SUSPEND) ? " suspend" : ""); - *size -= t; - *next += t; -} - - -static int -udc_proc_read(char *buffer, char **start, off_t off, int count, - int *eof, void *_dev) -{ - char *buf = buffer; - struct goku_udc *dev = _dev; - struct goku_udc_regs __iomem *regs = dev->regs; - char *next = buf; - unsigned size = count; - unsigned long flags; - int i, t, is_usb_connected; - u32 tmp; - - if (off != 0) - return 0; - - local_irq_save(flags); - - /* basic device status */ - tmp = readl(®s->power_detect); - is_usb_connected = tmp & PW_DETECT; - t = scnprintf(next, size, - "%s - %s\n" - "%s version: %s %s\n" - "Gadget driver: %s\n" - "Host %s, %s\n" - "\n", - pci_name(dev->pdev), driver_desc, - driver_name, DRIVER_VERSION, dmastr(), - dev->driver ? dev->driver->driver.name : "(none)", - is_usb_connected - ? ((tmp & PW_PULLUP) ? "full speed" : "powered") - : "disconnected", - ({char *state; - switch(dev->ep0state){ - case EP0_DISCONNECT: state = "ep0_disconnect"; break; - case EP0_IDLE: state = "ep0_idle"; break; - case EP0_IN: state = "ep0_in"; break; - case EP0_OUT: state = "ep0_out"; break; - case EP0_STATUS: state = "ep0_status"; break; - case EP0_STALL: state = "ep0_stall"; break; - case EP0_SUSPEND: state = "ep0_suspend"; break; - default: state = "ep0_?"; break; - } state; }) - ); - size -= t; - next += t; - - dump_intmask("int_status", readl(®s->int_status), &next, &size); - dump_intmask("int_enable", readl(®s->int_enable), &next, &size); - - if (!is_usb_connected || !dev->driver || (tmp & PW_PULLUP) == 0) - goto done; - - /* registers for (active) device and ep0 */ - t = scnprintf(next, size, "\nirqs %lu\ndataset %02x " - "single.bcs %02x.%02x state %x addr %u\n", - dev->irqs, readl(®s->DataSet), - readl(®s->EPxSingle), readl(®s->EPxBCS), - readl(®s->UsbState), - readl(®s->address)); - size -= t; - next += t; - - tmp = readl(®s->dma_master); - t = scnprintf(next, size, - "dma %03X =" EIGHTBITS "%s %s\n", tmp, - (tmp & MST_EOPB_DIS) ? " eopb-" : "", - (tmp & MST_EOPB_ENA) ? " eopb+" : "", - (tmp & MST_TIMEOUT_DIS) ? " tmo-" : "", - (tmp & MST_TIMEOUT_ENA) ? " tmo+" : "", - - (tmp & MST_RD_EOPB) ? " eopb" : "", - (tmp & MST_RD_RESET) ? " in_reset" : "", - (tmp & MST_WR_RESET) ? " out_reset" : "", - (tmp & MST_RD_ENA) ? " IN" : "", - - (tmp & MST_WR_ENA) ? " OUT" : "", - (tmp & MST_CONNECTION) - ? "ep1in/ep2out" - : "ep1out/ep2in"); - size -= t; - next += t; - - /* dump endpoint queues */ - for (i = 0; i < 4; i++) { - struct goku_ep *ep = &dev->ep [i]; - struct goku_request *req; - - if (i && !ep->desc) - continue; - - tmp = readl(ep->reg_status); - t = scnprintf(next, size, - "%s %s max %u %s, irqs %lu, " - "status %02x (%s) " FOURBITS "\n", - ep->ep.name, - ep->is_in ? "in" : "out", - ep->ep.maxpacket, - ep->dma ? "dma" : "pio", - ep->irqs, - tmp, ({ char *s; - switch (tmp & EPxSTATUS_EP_MASK) { - case EPxSTATUS_EP_READY: - s = "ready"; break; - case EPxSTATUS_EP_DATAIN: - s = "packet"; break; - case EPxSTATUS_EP_FULL: - s = "full"; break; - case EPxSTATUS_EP_TX_ERR: // host will retry - s = "tx_err"; break; - case EPxSTATUS_EP_RX_ERR: - s = "rx_err"; break; - case EPxSTATUS_EP_BUSY: /* ep0 only */ - s = "busy"; break; - case EPxSTATUS_EP_STALL: - s = "stall"; break; - case EPxSTATUS_EP_INVALID: // these "can't happen" - s = "invalid"; break; - default: - s = "?"; break; - }; s; }), - (tmp & EPxSTATUS_TOGGLE) ? "data1" : "data0", - (tmp & EPxSTATUS_SUSPEND) ? " suspend" : "", - (tmp & EPxSTATUS_FIFO_DISABLE) ? " disable" : "", - (tmp & EPxSTATUS_STAGE_ERROR) ? " ep0stat" : "" - ); - if (t <= 0 || t > size) - goto done; - size -= t; - next += t; - - if (list_empty(&ep->queue)) { - t = scnprintf(next, size, "\t(nothing queued)\n"); - if (t <= 0 || t > size) - goto done; - size -= t; - next += t; - continue; - } - list_for_each_entry(req, &ep->queue, queue) { - if (ep->dma && req->queue.prev == &ep->queue) { - if (i == UDC_MSTRD_ENDPOINT) - tmp = readl(®s->in_dma_current); - else - tmp = readl(®s->out_dma_current); - tmp -= req->req.dma; - tmp++; - } else - tmp = req->req.actual; - - t = scnprintf(next, size, - "\treq %p len %u/%u buf %p\n", - &req->req, tmp, req->req.length, - req->req.buf); - if (t <= 0 || t > size) - goto done; - size -= t; - next += t; - } - } - -done: - local_irq_restore(flags); - *eof = 1; - return count - size; -} - -#endif /* CONFIG_USB_GADGET_DEBUG_FILES */ - -/*-------------------------------------------------------------------------*/ - -static void udc_reinit (struct goku_udc *dev) -{ - static char *names [] = { "ep0", "ep1-bulk", "ep2-bulk", "ep3-bulk" }; - - unsigned i; - - INIT_LIST_HEAD (&dev->gadget.ep_list); - dev->gadget.ep0 = &dev->ep [0].ep; - dev->gadget.speed = USB_SPEED_UNKNOWN; - dev->ep0state = EP0_DISCONNECT; - dev->irqs = 0; - - for (i = 0; i < 4; i++) { - struct goku_ep *ep = &dev->ep[i]; - - ep->num = i; - ep->ep.name = names[i]; - ep->reg_fifo = &dev->regs->ep_fifo [i]; - ep->reg_status = &dev->regs->ep_status [i]; - ep->reg_mode = &dev->regs->ep_mode[i]; - - ep->ep.ops = &goku_ep_ops; - list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list); - ep->dev = dev; - INIT_LIST_HEAD (&ep->queue); - - ep_reset(NULL, ep); - } - - dev->ep[0].reg_mode = NULL; - dev->ep[0].ep.maxpacket = MAX_EP0_SIZE; - list_del_init (&dev->ep[0].ep.ep_list); -} - -static void udc_reset(struct goku_udc *dev) -{ - struct goku_udc_regs __iomem *regs = dev->regs; - - writel(0, ®s->power_detect); - writel(0, ®s->int_enable); - readl(®s->int_enable); - dev->int_enable = 0; - - /* deassert reset, leave USB D+ at hi-Z (no pullup) - * don't let INT_PWRDETECT sequence begin - */ - udelay(250); - writel(PW_RESETB, ®s->power_detect); - readl(®s->int_enable); -} - -static void ep0_start(struct goku_udc *dev) -{ - struct goku_udc_regs __iomem *regs = dev->regs; - unsigned i; - - VDBG(dev, "%s\n", __func__); - - udc_reset(dev); - udc_reinit (dev); - //writel(MST_EOPB_ENA | MST_TIMEOUT_ENA, ®s->dma_master); - - /* hw handles set_address, set_feature, get_status; maybe more */ - writel( G_REQMODE_SET_INTF | G_REQMODE_GET_INTF - | G_REQMODE_SET_CONF | G_REQMODE_GET_CONF - | G_REQMODE_GET_DESC - | G_REQMODE_CLEAR_FEAT - , ®s->reqmode); - - for (i = 0; i < 4; i++) - dev->ep[i].irqs = 0; - - /* can't modify descriptors after writing UsbReady */ - for (i = 0; i < DESC_LEN; i++) - writel(0, ®s->descriptors[i]); - writel(0, ®s->UsbReady); - - /* expect ep0 requests when the host drops reset */ - writel(PW_RESETB | PW_PULLUP, ®s->power_detect); - dev->int_enable = INT_DEVWIDE | INT_EP0; - writel(dev->int_enable, &dev->regs->int_enable); - readl(®s->int_enable); - dev->gadget.speed = USB_SPEED_FULL; - dev->ep0state = EP0_IDLE; -} - -static void udc_enable(struct goku_udc *dev) -{ - /* start enumeration now, or after power detect irq */ - if (readl(&dev->regs->power_detect) & PW_DETECT) - ep0_start(dev); - else { - DBG(dev, "%s\n", __func__); - dev->int_enable = INT_PWRDETECT; - writel(dev->int_enable, &dev->regs->int_enable); - } -} - -/*-------------------------------------------------------------------------*/ - -/* keeping it simple: - * - one bus driver, initted first; - * - one function driver, initted second - */ - -static struct goku_udc *the_controller; - -/* when a driver is successfully registered, it will receive - * control requests including set_configuration(), which enables - * non-control requests. then usb traffic follows until a - * disconnect is reported. then a host may connect again, or - * the driver might get unbound. - */ -static int goku_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) -{ - struct goku_udc *dev = the_controller; - int retval; - - if (!driver - || driver->max_speed < USB_SPEED_FULL - || !bind - || !driver->disconnect - || !driver->setup) - return -EINVAL; - if (!dev) - return -ENODEV; - if (dev->driver) - return -EBUSY; - - /* hook up the driver */ - driver->driver.bus = NULL; - dev->driver = driver; - dev->gadget.dev.driver = &driver->driver; - retval = bind(&dev->gadget); - if (retval) { - DBG(dev, "bind to driver %s --> error %d\n", - driver->driver.name, retval); - dev->driver = NULL; - dev->gadget.dev.driver = NULL; - return retval; - } - - /* then enable host detection and ep0; and we're ready - * for set_configuration as well as eventual disconnect. - */ - udc_enable(dev); - - DBG(dev, "registered gadget driver '%s'\n", driver->driver.name); - return 0; -} - -static void -stop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver) -{ - unsigned i; - - DBG (dev, "%s\n", __func__); - - if (dev->gadget.speed == USB_SPEED_UNKNOWN) - driver = NULL; - - /* disconnect gadget driver after quiesceing hw and the driver */ - udc_reset (dev); - for (i = 0; i < 4; i++) - nuke(&dev->ep [i], -ESHUTDOWN); - if (driver) { - spin_unlock(&dev->lock); - driver->disconnect(&dev->gadget); - spin_lock(&dev->lock); - } - - if (dev->driver) - udc_enable(dev); -} - -static int goku_stop(struct usb_gadget_driver *driver) -{ - struct goku_udc *dev = the_controller; - unsigned long flags; - - if (!dev) - return -ENODEV; - if (!driver || driver != dev->driver || !driver->unbind) - return -EINVAL; - - spin_lock_irqsave(&dev->lock, flags); - dev->driver = NULL; - stop_activity(dev, driver); - spin_unlock_irqrestore(&dev->lock, flags); - - driver->unbind(&dev->gadget); - dev->gadget.dev.driver = NULL; - - DBG(dev, "unregistered driver '%s'\n", driver->driver.name); - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static void ep0_setup(struct goku_udc *dev) -{ - struct goku_udc_regs __iomem *regs = dev->regs; - struct usb_ctrlrequest ctrl; - int tmp; - - /* read SETUP packet and enter DATA stage */ - ctrl.bRequestType = readl(®s->bRequestType); - ctrl.bRequest = readl(®s->bRequest); - ctrl.wValue = cpu_to_le16((readl(®s->wValueH) << 8) - | readl(®s->wValueL)); - ctrl.wIndex = cpu_to_le16((readl(®s->wIndexH) << 8) - | readl(®s->wIndexL)); - ctrl.wLength = cpu_to_le16((readl(®s->wLengthH) << 8) - | readl(®s->wLengthL)); - writel(0, ®s->SetupRecv); - - nuke(&dev->ep[0], 0); - dev->ep[0].stopped = 0; - if (likely(ctrl.bRequestType & USB_DIR_IN)) { - dev->ep[0].is_in = 1; - dev->ep0state = EP0_IN; - /* detect early status stages */ - writel(ICONTROL_STATUSNAK, &dev->regs->IntControl); - } else { - dev->ep[0].is_in = 0; - dev->ep0state = EP0_OUT; - - /* NOTE: CLEAR_FEATURE is done in software so that we can - * synchronize transfer restarts after bulk IN stalls. data - * won't even enter the fifo until the halt is cleared. - */ - switch (ctrl.bRequest) { - case USB_REQ_CLEAR_FEATURE: - switch (ctrl.bRequestType) { - case USB_RECIP_ENDPOINT: - tmp = le16_to_cpu(ctrl.wIndex) & 0x0f; - /* active endpoint */ - if (tmp > 3 || (!dev->ep[tmp].desc && tmp != 0)) - goto stall; - if (ctrl.wIndex & cpu_to_le16( - USB_DIR_IN)) { - if (!dev->ep[tmp].is_in) - goto stall; - } else { - if (dev->ep[tmp].is_in) - goto stall; - } - if (ctrl.wValue != cpu_to_le16( - USB_ENDPOINT_HALT)) - goto stall; - if (tmp) - goku_clear_halt(&dev->ep[tmp]); -succeed: - /* start ep0out status stage */ - writel(~(1<<0), ®s->EOP); - dev->ep[0].stopped = 1; - dev->ep0state = EP0_STATUS; - return; - case USB_RECIP_DEVICE: - /* device remote wakeup: always clear */ - if (ctrl.wValue != cpu_to_le16(1)) - goto stall; - VDBG(dev, "clear dev remote wakeup\n"); - goto succeed; - case USB_RECIP_INTERFACE: - goto stall; - default: /* pass to gadget driver */ - break; - } - break; - default: - break; - } - } - -#ifdef USB_TRACE - VDBG(dev, "SETUP %02x.%02x v%04x i%04x l%04x\n", - ctrl.bRequestType, ctrl.bRequest, - le16_to_cpu(ctrl.wValue), le16_to_cpu(ctrl.wIndex), - le16_to_cpu(ctrl.wLength)); -#endif - - /* hw wants to know when we're configured (or not) */ - dev->req_config = (ctrl.bRequest == USB_REQ_SET_CONFIGURATION - && ctrl.bRequestType == USB_RECIP_DEVICE); - if (unlikely(dev->req_config)) - dev->configured = (ctrl.wValue != cpu_to_le16(0)); - - /* delegate everything to the gadget driver. - * it may respond after this irq handler returns. - */ - spin_unlock (&dev->lock); - tmp = dev->driver->setup(&dev->gadget, &ctrl); - spin_lock (&dev->lock); - if (unlikely(tmp < 0)) { -stall: -#ifdef USB_TRACE - VDBG(dev, "req %02x.%02x protocol STALL; err %d\n", - ctrl.bRequestType, ctrl.bRequest, tmp); -#endif - command(regs, COMMAND_STALL, 0); - dev->ep[0].stopped = 1; - dev->ep0state = EP0_STALL; - } - - /* expect at least one data or status stage irq */ -} - -#define ACK(irqbit) { \ - stat &= ~irqbit; \ - writel(~irqbit, ®s->int_status); \ - handled = 1; \ - } - -static irqreturn_t goku_irq(int irq, void *_dev) -{ - struct goku_udc *dev = _dev; - struct goku_udc_regs __iomem *regs = dev->regs; - struct goku_ep *ep; - u32 stat, handled = 0; - unsigned i, rescans = 5; - - spin_lock(&dev->lock); - -rescan: - stat = readl(®s->int_status) & dev->int_enable; - if (!stat) - goto done; - dev->irqs++; - - /* device-wide irqs */ - if (unlikely(stat & INT_DEVWIDE)) { - if (stat & INT_SYSERROR) { - ERROR(dev, "system error\n"); - stop_activity(dev, dev->driver); - stat = 0; - handled = 1; - // FIXME have a neater way to prevent re-enumeration - dev->driver = NULL; - goto done; - } - if (stat & INT_PWRDETECT) { - writel(~stat, ®s->int_status); - if (readl(&dev->regs->power_detect) & PW_DETECT) { - VDBG(dev, "connect\n"); - ep0_start(dev); - } else { - DBG(dev, "disconnect\n"); - if (dev->gadget.speed == USB_SPEED_FULL) - stop_activity(dev, dev->driver); - dev->ep0state = EP0_DISCONNECT; - dev->int_enable = INT_DEVWIDE; - writel(dev->int_enable, &dev->regs->int_enable); - } - stat = 0; - handled = 1; - goto done; - } - if (stat & INT_SUSPEND) { - ACK(INT_SUSPEND); - if (readl(®s->ep_status[0]) & EPxSTATUS_SUSPEND) { - switch (dev->ep0state) { - case EP0_DISCONNECT: - case EP0_SUSPEND: - goto pm_next; - default: - break; - } - DBG(dev, "USB suspend\n"); - dev->ep0state = EP0_SUSPEND; - if (dev->gadget.speed != USB_SPEED_UNKNOWN - && dev->driver - && dev->driver->suspend) { - spin_unlock(&dev->lock); - dev->driver->suspend(&dev->gadget); - spin_lock(&dev->lock); - } - } else { - if (dev->ep0state != EP0_SUSPEND) { - DBG(dev, "bogus USB resume %d\n", - dev->ep0state); - goto pm_next; - } - DBG(dev, "USB resume\n"); - dev->ep0state = EP0_IDLE; - if (dev->gadget.speed != USB_SPEED_UNKNOWN - && dev->driver - && dev->driver->resume) { - spin_unlock(&dev->lock); - dev->driver->resume(&dev->gadget); - spin_lock(&dev->lock); - } - } - } -pm_next: - if (stat & INT_USBRESET) { /* hub reset done */ - ACK(INT_USBRESET); - INFO(dev, "USB reset done, gadget %s\n", - dev->driver->driver.name); - } - // and INT_ERR on some endpoint's crc/bitstuff/... problem - } - - /* progress ep0 setup, data, or status stages. - * no transition {EP0_STATUS, EP0_STALL} --> EP0_IDLE; saves irqs - */ - if (stat & INT_SETUP) { - ACK(INT_SETUP); - dev->ep[0].irqs++; - ep0_setup(dev); - } - if (stat & INT_STATUSNAK) { - ACK(INT_STATUSNAK|INT_ENDPOINT0); - if (dev->ep0state == EP0_IN) { - ep = &dev->ep[0]; - ep->irqs++; - nuke(ep, 0); - writel(~(1<<0), ®s->EOP); - dev->ep0state = EP0_STATUS; - } - } - if (stat & INT_ENDPOINT0) { - ACK(INT_ENDPOINT0); - ep = &dev->ep[0]; - ep->irqs++; - pio_advance(ep); - } - - /* dma completion */ - if (stat & INT_MSTRDEND) { /* IN */ - ACK(INT_MSTRDEND); - ep = &dev->ep[UDC_MSTRD_ENDPOINT]; - ep->irqs++; - dma_advance(dev, ep); - } - if (stat & INT_MSTWREND) { /* OUT */ - ACK(INT_MSTWREND); - ep = &dev->ep[UDC_MSTWR_ENDPOINT]; - ep->irqs++; - dma_advance(dev, ep); - } - if (stat & INT_MSTWRTMOUT) { /* OUT */ - ACK(INT_MSTWRTMOUT); - ep = &dev->ep[UDC_MSTWR_ENDPOINT]; - ep->irqs++; - ERROR(dev, "%s write timeout ?\n", ep->ep.name); - // reset dma? then dma_advance() - } - - /* pio */ - for (i = 1; i < 4; i++) { - u32 tmp = INT_EPxDATASET(i); - - if (!(stat & tmp)) - continue; - ep = &dev->ep[i]; - pio_advance(ep); - if (list_empty (&ep->queue)) - pio_irq_disable(dev, regs, i); - stat &= ~tmp; - handled = 1; - ep->irqs++; - } - - if (rescans--) - goto rescan; - -done: - (void)readl(®s->int_enable); - spin_unlock(&dev->lock); - if (stat) - DBG(dev, "unhandled irq status: %05x (%05x, %05x)\n", stat, - readl(®s->int_status), dev->int_enable); - return IRQ_RETVAL(handled); -} - -#undef ACK - -/*-------------------------------------------------------------------------*/ - -static void gadget_release(struct device *_dev) -{ - struct goku_udc *dev = dev_get_drvdata(_dev); - - kfree(dev); -} - -/* tear down the binding between this driver and the pci device */ - -static void goku_remove(struct pci_dev *pdev) -{ - struct goku_udc *dev = pci_get_drvdata(pdev); - - DBG(dev, "%s\n", __func__); - - usb_del_gadget_udc(&dev->gadget); - - BUG_ON(dev->driver); - -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - remove_proc_entry(proc_node_name, NULL); -#endif - if (dev->regs) - udc_reset(dev); - if (dev->got_irq) - free_irq(pdev->irq, dev); - if (dev->regs) - iounmap(dev->regs); - if (dev->got_region) - release_mem_region(pci_resource_start (pdev, 0), - pci_resource_len (pdev, 0)); - if (dev->enabled) - pci_disable_device(pdev); - if (dev->registered) - device_unregister(&dev->gadget.dev); - - pci_set_drvdata(pdev, NULL); - dev->regs = NULL; - the_controller = NULL; - - INFO(dev, "unbind\n"); -} - -/* wrap this driver around the specified pci device, but - * don't respond over USB until a gadget driver binds to us. - */ - -static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - struct goku_udc *dev = NULL; - unsigned long resource, len; - void __iomem *base = NULL; - int retval; - - /* if you want to support more than one controller in a system, - * usb_gadget_driver_{register,unregister}() must change. - */ - if (the_controller) { - pr_warning("ignoring %s\n", pci_name(pdev)); - return -EBUSY; - } - if (!pdev->irq) { - printk(KERN_ERR "Check PCI %s IRQ setup!\n", pci_name(pdev)); - retval = -ENODEV; - goto err; - } - - /* alloc, and start init */ - dev = kzalloc (sizeof *dev, GFP_KERNEL); - if (dev == NULL){ - pr_debug("enomem %s\n", pci_name(pdev)); - retval = -ENOMEM; - goto err; - } - - spin_lock_init(&dev->lock); - dev->pdev = pdev; - dev->gadget.ops = &goku_ops; - dev->gadget.max_speed = USB_SPEED_FULL; - - /* the "gadget" abstracts/virtualizes the controller */ - dev_set_name(&dev->gadget.dev, "gadget"); - dev->gadget.dev.parent = &pdev->dev; - dev->gadget.dev.dma_mask = pdev->dev.dma_mask; - dev->gadget.dev.release = gadget_release; - dev->gadget.name = driver_name; - - /* now all the pci goodies ... */ - retval = pci_enable_device(pdev); - if (retval < 0) { - DBG(dev, "can't enable, %d\n", retval); - goto err; - } - dev->enabled = 1; - - resource = pci_resource_start(pdev, 0); - len = pci_resource_len(pdev, 0); - if (!request_mem_region(resource, len, driver_name)) { - DBG(dev, "controller already in use\n"); - retval = -EBUSY; - goto err; - } - dev->got_region = 1; - - base = ioremap_nocache(resource, len); - if (base == NULL) { - DBG(dev, "can't map memory\n"); - retval = -EFAULT; - goto err; - } - dev->regs = (struct goku_udc_regs __iomem *) base; - - pci_set_drvdata(pdev, dev); - INFO(dev, "%s\n", driver_desc); - INFO(dev, "version: " DRIVER_VERSION " %s\n", dmastr()); - INFO(dev, "irq %d, pci mem %p\n", pdev->irq, base); - - /* init to known state, then setup irqs */ - udc_reset(dev); - udc_reinit (dev); - if (request_irq(pdev->irq, goku_irq, IRQF_SHARED/*|IRQF_SAMPLE_RANDOM*/, - driver_name, dev) != 0) { - DBG(dev, "request interrupt %d failed\n", pdev->irq); - retval = -EBUSY; - goto err; - } - dev->got_irq = 1; - if (use_dma) - pci_set_master(pdev); - - -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev); -#endif - - the_controller = dev; - retval = device_register(&dev->gadget.dev); - if (retval) { - put_device(&dev->gadget.dev); - goto err; - } - dev->registered = 1; - retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); - if (retval) - goto err; - - return 0; - -err: - if (dev) - goku_remove (pdev); - return retval; -} - - -/*-------------------------------------------------------------------------*/ - -static const struct pci_device_id pci_ids[] = { { - .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), - .class_mask = ~0, - .vendor = 0x102f, /* Toshiba */ - .device = 0x0107, /* this UDC */ - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - -}, { /* end: all zeroes */ } -}; -MODULE_DEVICE_TABLE (pci, pci_ids); - -static struct pci_driver goku_pci_driver = { - .name = (char *) driver_name, - .id_table = pci_ids, - - .probe = goku_probe, - .remove = goku_remove, - - /* FIXME add power management support */ -}; - -static int __init init (void) -{ - return pci_register_driver (&goku_pci_driver); -} -module_init (init); - -static void __exit cleanup (void) -{ - pci_unregister_driver (&goku_pci_driver); -} -module_exit (cleanup); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/goku_udc.h b/ANDROID_3.4.5/drivers/usb/gadget/goku_udc.h deleted file mode 100644 index e7e0c69d..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/goku_udc.h +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Toshiba TC86C001 ("Goku-S") USB Device Controller driver - * - * Copyright (C) 2000-2002 Lineo - * by Stuart Lynne, Tom Rushworth, and Bruce Balden - * Copyright (C) 2002 Toshiba Corporation - * Copyright (C) 2003 MontaVista Software (source@mvista.com) - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -/* - * PCI BAR 0 points to these registers. - */ -struct goku_udc_regs { - /* irq management */ - u32 int_status; /* 0x000 */ - u32 int_enable; -#define INT_SUSPEND 0x00001 /* or resume */ -#define INT_USBRESET 0x00002 -#define INT_ENDPOINT0 0x00004 -#define INT_SETUP 0x00008 -#define INT_STATUS 0x00010 -#define INT_STATUSNAK 0x00020 -#define INT_EPxDATASET(n) (0x00020 << (n)) /* 0 < n < 4 */ -# define INT_EP1DATASET 0x00040 -# define INT_EP2DATASET 0x00080 -# define INT_EP3DATASET 0x00100 -#define INT_EPnNAK(n) (0x00100 < (n)) /* 0 < n < 4 */ -# define INT_EP1NAK 0x00200 -# define INT_EP2NAK 0x00400 -# define INT_EP3NAK 0x00800 -#define INT_SOF 0x01000 -#define INT_ERR 0x02000 -#define INT_MSTWRSET 0x04000 -#define INT_MSTWREND 0x08000 -#define INT_MSTWRTMOUT 0x10000 -#define INT_MSTRDEND 0x20000 -#define INT_SYSERROR 0x40000 -#define INT_PWRDETECT 0x80000 - -#define INT_DEVWIDE \ - (INT_PWRDETECT|INT_SYSERROR/*|INT_ERR*/|INT_USBRESET|INT_SUSPEND) -#define INT_EP0 \ - (INT_SETUP|INT_ENDPOINT0/*|INT_STATUS*/|INT_STATUSNAK) - - u32 dma_master; -#define MST_EOPB_DIS 0x0800 -#define MST_EOPB_ENA 0x0400 -#define MST_TIMEOUT_DIS 0x0200 -#define MST_TIMEOUT_ENA 0x0100 -#define MST_RD_EOPB 0x0080 /* write-only */ -#define MST_RD_RESET 0x0040 -#define MST_WR_RESET 0x0020 -#define MST_RD_ENA 0x0004 /* 1:start, 0:ignore */ -#define MST_WR_ENA 0x0002 /* 1:start, 0:ignore */ -#define MST_CONNECTION 0x0001 /* 0 for ep1out/ep2in */ - -#define MST_R_BITS (MST_EOPB_DIS|MST_EOPB_ENA \ - |MST_RD_ENA|MST_RD_RESET) -#define MST_W_BITS (MST_TIMEOUT_DIS|MST_TIMEOUT_ENA \ - |MST_WR_ENA|MST_WR_RESET) -#define MST_RW_BITS (MST_R_BITS|MST_W_BITS \ - |MST_CONNECTION) - -/* these values assume (dma_master & MST_CONNECTION) == 0 */ -#define UDC_MSTWR_ENDPOINT 1 -#define UDC_MSTRD_ENDPOINT 2 - - /* dma master write */ - u32 out_dma_start; - u32 out_dma_end; - u32 out_dma_current; - - /* dma master read */ - u32 in_dma_start; - u32 in_dma_end; - u32 in_dma_current; - - u32 power_detect; -#define PW_DETECT 0x04 -#define PW_RESETB 0x02 -#define PW_PULLUP 0x01 - - u8 _reserved0 [0x1d8]; - - /* endpoint registers */ - u32 ep_fifo [4]; /* 0x200 */ - u8 _reserved1 [0x10]; - u32 ep_mode [4]; /* only 1-3 valid */ - u8 _reserved2 [0x10]; - - u32 ep_status [4]; -#define EPxSTATUS_TOGGLE 0x40 -#define EPxSTATUS_SUSPEND 0x20 -#define EPxSTATUS_EP_MASK (0x07<<2) -# define EPxSTATUS_EP_READY (0<<2) -# define EPxSTATUS_EP_DATAIN (1<<2) -# define EPxSTATUS_EP_FULL (2<<2) -# define EPxSTATUS_EP_TX_ERR (3<<2) -# define EPxSTATUS_EP_RX_ERR (4<<2) -# define EPxSTATUS_EP_BUSY (5<<2) -# define EPxSTATUS_EP_STALL (6<<2) -# define EPxSTATUS_EP_INVALID (7<<2) -#define EPxSTATUS_FIFO_DISABLE 0x02 -#define EPxSTATUS_STAGE_ERROR 0x01 - - u8 _reserved3 [0x10]; - u32 EPxSizeLA[4]; -#define PACKET_ACTIVE (1<<7) -#define DATASIZE 0x7f - u8 _reserved3a [0x10]; - u32 EPxSizeLB[4]; /* only 1,2 valid */ - u8 _reserved3b [0x10]; - u32 EPxSizeHA[4]; /* only 1-3 valid */ - u8 _reserved3c [0x10]; - u32 EPxSizeHB[4]; /* only 1,2 valid */ - u8 _reserved4[0x30]; - - /* SETUP packet contents */ - u32 bRequestType; /* 0x300 */ - u32 bRequest; - u32 wValueL; - u32 wValueH; - u32 wIndexL; - u32 wIndexH; - u32 wLengthL; - u32 wLengthH; - - /* command interaction/handshaking */ - u32 SetupRecv; /* 0x320 */ - u32 CurrConfig; - u32 StdRequest; - u32 Request; - u32 DataSet; -#define DATASET_A(epnum) (1<<(2*(epnum))) -#define DATASET_B(epnum) (2<<(2*(epnum))) -#define DATASET_AB(epnum) (3<<(2*(epnum))) - u8 _reserved5[4]; - - u32 UsbState; -#define USBSTATE_CONFIGURED 0x04 -#define USBSTATE_ADDRESSED 0x02 -#define USBSTATE_DEFAULT 0x01 - - u32 EOP; - - u32 Command; /* 0x340 */ -#define COMMAND_SETDATA0 2 -#define COMMAND_RESET 3 -#define COMMAND_STALL 4 -#define COMMAND_INVALID 5 -#define COMMAND_FIFO_DISABLE 7 -#define COMMAND_FIFO_ENABLE 8 -#define COMMAND_INIT_DESCRIPTOR 9 -#define COMMAND_FIFO_CLEAR 10 /* also stall */ -#define COMMAND_STALL_CLEAR 11 -#define COMMAND_EP(n) ((n) << 4) - - u32 EPxSingle; - u8 _reserved6[4]; - u32 EPxBCS; - u8 _reserved7[8]; - u32 IntControl; -#define ICONTROL_STATUSNAK 1 - u8 _reserved8[4]; - - u32 reqmode; // 0x360 standard request mode, low 8 bits -#define G_REQMODE_SET_INTF (1<<7) -#define G_REQMODE_GET_INTF (1<<6) -#define G_REQMODE_SET_CONF (1<<5) -#define G_REQMODE_GET_CONF (1<<4) -#define G_REQMODE_GET_DESC (1<<3) -#define G_REQMODE_SET_FEAT (1<<2) -#define G_REQMODE_CLEAR_FEAT (1<<1) -#define G_REQMODE_GET_STATUS (1<<0) - - u32 ReqMode; - u8 _reserved9[0x18]; - u32 PortStatus; /* 0x380 */ - u8 _reserved10[8]; - u32 address; - u32 buff_test; - u8 _reserved11[4]; - u32 UsbReady; - u8 _reserved12[4]; - u32 SetDescStall; /* 0x3a0 */ - u8 _reserved13[0x45c]; - - /* hardware could handle limited GET_DESCRIPTOR duties */ -#define DESC_LEN 0x80 - u32 descriptors[DESC_LEN]; /* 0x800 */ - u8 _reserved14[0x600]; - -} __attribute__ ((packed)); - -#define MAX_FIFO_SIZE 64 -#define MAX_EP0_SIZE 8 /* ep0 fifo is bigger, though */ - - -/*-------------------------------------------------------------------------*/ - -/* DRIVER DATA STRUCTURES and UTILITIES */ - -struct goku_ep { - struct usb_ep ep; - struct goku_udc *dev; - unsigned long irqs; - - unsigned num:8, - dma:1, - is_in:1, - stopped:1; - - /* analogous to a host-side qh */ - struct list_head queue; - const struct usb_endpoint_descriptor *desc; - - u32 __iomem *reg_fifo; - u32 __iomem *reg_mode; - u32 __iomem *reg_status; -}; - -struct goku_request { - struct usb_request req; - struct list_head queue; - - unsigned mapped:1; -}; - -enum ep0state { - EP0_DISCONNECT, /* no host */ - EP0_IDLE, /* between STATUS ack and SETUP report */ - EP0_IN, EP0_OUT, /* data stage */ - EP0_STATUS, /* status stage */ - EP0_STALL, /* data or status stages */ - EP0_SUSPEND, /* usb suspend */ -}; - -struct goku_udc { - /* each pci device provides one gadget, several endpoints */ - struct usb_gadget gadget; - spinlock_t lock; - struct goku_ep ep[4]; - struct usb_gadget_driver *driver; - - enum ep0state ep0state; - unsigned got_irq:1, - got_region:1, - req_config:1, - configured:1, - enabled:1, - registered:1; - - /* pci state used to access those endpoints */ - struct pci_dev *pdev; - struct goku_udc_regs __iomem *regs; - u32 int_enable; - - /* statistics... */ - unsigned long irqs; -}; - -/*-------------------------------------------------------------------------*/ - -#define xprintk(dev,level,fmt,args...) \ - printk(level "%s %s: " fmt , driver_name , \ - pci_name(dev->pdev) , ## args) - -#ifdef DEBUG -#define DBG(dev,fmt,args...) \ - xprintk(dev , KERN_DEBUG , fmt , ## args) -#else -#define DBG(dev,fmt,args...) \ - do { } while (0) -#endif /* DEBUG */ - -#ifdef VERBOSE -#define VDBG DBG -#else -#define VDBG(dev,fmt,args...) \ - do { } while (0) -#endif /* VERBOSE */ - -#define ERROR(dev,fmt,args...) \ - xprintk(dev , KERN_ERR , fmt , ## args) -#define WARNING(dev,fmt,args...) \ - xprintk(dev , KERN_WARNING , fmt , ## args) -#define INFO(dev,fmt,args...) \ - xprintk(dev , KERN_INFO , fmt , ## args) - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/hid.c b/ANDROID_3.4.5/drivers/usb/gadget/hid.c deleted file mode 100644 index 3493adf0..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/hid.c +++ /dev/null @@ -1,288 +0,0 @@ -/* - * hid.c -- HID Composite driver - * - * Based on multi.c - * - * Copyright (C) 2010 Fabien Chouteau - * - * 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 -#include -#include - -#define DRIVER_DESC "HID Gadget" -#define DRIVER_VERSION "2010/03/16" - -/*-------------------------------------------------------------------------*/ - -#define HIDG_VENDOR_NUM 0x0525 /* XXX NetChip */ -#define HIDG_PRODUCT_NUM 0xa4ac /* Linux-USB HID gadget */ - -/*-------------------------------------------------------------------------*/ - -/* - * 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 "f_hid.c" - - -struct hidg_func_node { - struct list_head node; - struct hidg_func_descriptor *func; -}; - -static LIST_HEAD(hidg_func_list); - -/*-------------------------------------------------------------------------*/ - -static struct usb_device_descriptor device_desc = { - .bLength = sizeof device_desc, - .bDescriptorType = USB_DT_DEVICE, - - .bcdUSB = cpu_to_le16(0x0200), - - /* .bDeviceClass = USB_CLASS_COMM, */ - /* .bDeviceSubClass = 0, */ - /* .bDeviceProtocol = 0, */ - .bDeviceClass = USB_CLASS_PER_INTERFACE, - .bDeviceSubClass = 0, - .bDeviceProtocol = 0, - /* .bMaxPacketSize0 = f(hardware) */ - - /* Vendor and product id can be overridden by module parameters. */ - .idVendor = cpu_to_le16(HIDG_VENDOR_NUM), - .idProduct = cpu_to_le16(HIDG_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, -}; - - -/* 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 *dev_strings[] = { - &stringtab_dev, - NULL, -}; - - - -/****************************** Configurations ******************************/ - -static int __init do_config(struct usb_configuration *c) -{ - struct hidg_func_node *e; - int func = 0, status = 0; - - if (gadget_is_otg(c->cdev->gadget)) { - c->descriptors = otg_desc; - c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; - } - - list_for_each_entry(e, &hidg_func_list, node) { - status = hidg_bind_config(c, e->func, func++); - if (status) - break; - } - - return status; -} - -static struct usb_configuration config_driver = { - .label = "HID Gadget", - .bConfigurationValue = 1, - /* .iConfiguration = DYNAMIC */ - .bmAttributes = USB_CONFIG_ATT_SELFPOWER, -}; - -/****************************** Gadget Bind ******************************/ - -static int __init hid_bind(struct usb_composite_dev *cdev) -{ - struct usb_gadget *gadget = cdev->gadget; - struct list_head *tmp; - int status, gcnum, funcs = 0; - - list_for_each(tmp, &hidg_func_list) - funcs++; - - if (!funcs) - return -ENODEV; - - /* set up HID */ - status = ghid_setup(cdev->gadget, funcs); - if (status < 0) - return status; - - gcnum = usb_gadget_controller_number(gadget); - if (gcnum >= 0) - device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum); - else - device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099); - - - /* Allocate string descriptor numbers ... note that string - * contents can be overridden by the composite_dev glue. - */ - - /* device descriptor strings: manufacturer, product */ - snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", - init_utsname()->sysname, init_utsname()->release, - gadget->name); - status = usb_string_id(cdev); - if (status < 0) - return status; - strings_dev[STRING_MANUFACTURER_IDX].id = status; - device_desc.iManufacturer = status; - - status = usb_string_id(cdev); - if (status < 0) - return status; - strings_dev[STRING_PRODUCT_IDX].id = status; - device_desc.iProduct = status; - - /* register our configuration */ - status = usb_add_config(cdev, &config_driver, do_config); - if (status < 0) - return status; - - dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n"); - - return 0; -} - -static int __exit hid_unbind(struct usb_composite_dev *cdev) -{ - ghid_cleanup(); - return 0; -} - -static int __init hidg_plat_driver_probe(struct platform_device *pdev) -{ - struct hidg_func_descriptor *func = pdev->dev.platform_data; - struct hidg_func_node *entry; - - if (!func) { - dev_err(&pdev->dev, "Platform data missing\n"); - return -ENODEV; - } - - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) - return -ENOMEM; - - entry->func = func; - list_add_tail(&entry->node, &hidg_func_list); - - return 0; -} - -static int __devexit hidg_plat_driver_remove(struct platform_device *pdev) -{ - struct hidg_func_node *e, *n; - - list_for_each_entry_safe(e, n, &hidg_func_list, node) { - list_del(&e->node); - kfree(e); - } - - return 0; -} - - -/****************************** Some noise ******************************/ - - -static struct usb_composite_driver hidg_driver = { - .name = "g_hid", - .dev = &device_desc, - .strings = dev_strings, - .max_speed = USB_SPEED_HIGH, - .unbind = __exit_p(hid_unbind), -}; - -static struct platform_driver hidg_plat_driver = { - .remove = __devexit_p(hidg_plat_driver_remove), - .driver = { - .owner = THIS_MODULE, - .name = "hidg", - }, -}; - - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Fabien Chouteau, Peter Korsgaard"); -MODULE_LICENSE("GPL"); - -static int __init hidg_init(void) -{ - int status; - - status = platform_driver_probe(&hidg_plat_driver, - hidg_plat_driver_probe); - if (status < 0) - return status; - - status = usb_composite_probe(&hidg_driver, hid_bind); - if (status < 0) - platform_driver_unregister(&hidg_plat_driver); - - return status; -} -module_init(hidg_init); - -static void __exit hidg_cleanup(void) -{ - platform_driver_unregister(&hidg_plat_driver); - usb_composite_unregister(&hidg_driver); -} -module_exit(hidg_cleanup); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/imx_udc.c b/ANDROID_3.4.5/drivers/usb/gadget/imx_udc.c deleted file mode 100644 index 8d1c75ab..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/imx_udc.c +++ /dev/null @@ -1,1595 +0,0 @@ -/* - * driver/usb/gadget/imx_udc.c - * - * Copyright (C) 2005 Mike Lee - * Copyright (C) 2008 Darius Augulis - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "imx_udc.h" - -static const char driver_name[] = "imx_udc"; -static const char ep0name[] = "ep0"; - -void ep0_chg_stat(const char *label, struct imx_udc_struct *imx_usb, - enum ep0_state stat); - -/******************************************************************************* - * IMX UDC hardware related functions - ******************************************************************************* - */ - -void imx_udc_enable(struct imx_udc_struct *imx_usb) -{ - int temp = __raw_readl(imx_usb->base + USB_CTRL); - __raw_writel(temp | CTRL_FE_ENA | CTRL_AFE_ENA, - imx_usb->base + USB_CTRL); - imx_usb->gadget.speed = USB_SPEED_FULL; -} - -void imx_udc_disable(struct imx_udc_struct *imx_usb) -{ - int temp = __raw_readl(imx_usb->base + USB_CTRL); - - __raw_writel(temp & ~(CTRL_FE_ENA | CTRL_AFE_ENA), - imx_usb->base + USB_CTRL); - - ep0_chg_stat(__func__, imx_usb, EP0_IDLE); - imx_usb->gadget.speed = USB_SPEED_UNKNOWN; -} - -void imx_udc_reset(struct imx_udc_struct *imx_usb) -{ - int temp = __raw_readl(imx_usb->base + USB_ENAB); - - /* set RST bit */ - __raw_writel(temp | ENAB_RST, imx_usb->base + USB_ENAB); - - /* wait RST bit to clear */ - do {} while (__raw_readl(imx_usb->base + USB_ENAB) & ENAB_RST); - - /* wait CFG bit to assert */ - do {} while (!(__raw_readl(imx_usb->base + USB_DADR) & DADR_CFG)); - - /* udc module is now ready */ -} - -void imx_udc_config(struct imx_udc_struct *imx_usb) -{ - u8 ep_conf[5]; - u8 i, j, cfg; - struct imx_ep_struct *imx_ep; - - /* wait CFG bit to assert */ - do {} while (!(__raw_readl(imx_usb->base + USB_DADR) & DADR_CFG)); - - /* Download the endpoint buffer for endpoint 0. */ - for (j = 0; j < 5; j++) { - i = (j == 2 ? imx_usb->imx_ep[0].fifosize : 0x00); - __raw_writeb(i, imx_usb->base + USB_DDAT); - do {} while (__raw_readl(imx_usb->base + USB_DADR) & DADR_BSY); - } - - /* Download the endpoint buffers for endpoints 1-5. - * We specify two configurations, one interface - */ - for (cfg = 1; cfg < 3; cfg++) { - for (i = 1; i < IMX_USB_NB_EP; i++) { - imx_ep = &imx_usb->imx_ep[i]; - /* EP no | Config no */ - ep_conf[0] = (i << 4) | (cfg << 2); - /* Type | Direction */ - ep_conf[1] = (imx_ep->bmAttributes << 3) | - (EP_DIR(imx_ep) << 2); - /* Max packet size */ - ep_conf[2] = imx_ep->fifosize; - /* TRXTYP */ - ep_conf[3] = 0xC0; - /* FIFO no */ - ep_conf[4] = i; - - D_INI(imx_usb->dev, - "<%s> ep%d_conf[%d]:" - "[%02x-%02x-%02x-%02x-%02x]\n", - __func__, i, cfg, - ep_conf[0], ep_conf[1], ep_conf[2], - ep_conf[3], ep_conf[4]); - - for (j = 0; j < 5; j++) { - __raw_writeb(ep_conf[j], - imx_usb->base + USB_DDAT); - do {} while (__raw_readl(imx_usb->base - + USB_DADR) - & DADR_BSY); - } - } - } - - /* wait CFG bit to clear */ - do {} while (__raw_readl(imx_usb->base + USB_DADR) & DADR_CFG); -} - -void imx_udc_init_irq(struct imx_udc_struct *imx_usb) -{ - int i; - - /* Mask and clear all irqs */ - __raw_writel(0xFFFFFFFF, imx_usb->base + USB_MASK); - __raw_writel(0xFFFFFFFF, imx_usb->base + USB_INTR); - for (i = 0; i < IMX_USB_NB_EP; i++) { - __raw_writel(0x1FF, imx_usb->base + USB_EP_MASK(i)); - __raw_writel(0x1FF, imx_usb->base + USB_EP_INTR(i)); - } - - /* Enable USB irqs */ - __raw_writel(INTR_MSOF | INTR_FRAME_MATCH, imx_usb->base + USB_MASK); - - /* Enable EP0 irqs */ - __raw_writel(0x1FF & ~(EPINTR_DEVREQ | EPINTR_MDEVREQ | EPINTR_EOT - | EPINTR_EOF | EPINTR_FIFO_EMPTY | EPINTR_FIFO_FULL), - imx_usb->base + USB_EP_MASK(0)); -} - -void imx_udc_init_ep(struct imx_udc_struct *imx_usb) -{ - int i, max, temp; - struct imx_ep_struct *imx_ep; - for (i = 0; i < IMX_USB_NB_EP; i++) { - imx_ep = &imx_usb->imx_ep[i]; - switch (imx_ep->fifosize) { - case 8: - max = 0; - break; - case 16: - max = 1; - break; - case 32: - max = 2; - break; - case 64: - max = 3; - break; - default: - max = 1; - break; - } - temp = (EP_DIR(imx_ep) << 7) | (max << 5) - | (imx_ep->bmAttributes << 3); - __raw_writel(temp, imx_usb->base + USB_EP_STAT(i)); - __raw_writel(temp | EPSTAT_FLUSH, - imx_usb->base + USB_EP_STAT(i)); - D_INI(imx_usb->dev, "<%s> ep%d_stat %08x\n", __func__, i, - __raw_readl(imx_usb->base + USB_EP_STAT(i))); - } -} - -void imx_udc_init_fifo(struct imx_udc_struct *imx_usb) -{ - int i, temp; - struct imx_ep_struct *imx_ep; - for (i = 0; i < IMX_USB_NB_EP; i++) { - imx_ep = &imx_usb->imx_ep[i]; - - /* Fifo control */ - temp = EP_DIR(imx_ep) ? 0x0B000000 : 0x0F000000; - __raw_writel(temp, imx_usb->base + USB_EP_FCTRL(i)); - D_INI(imx_usb->dev, "<%s> ep%d_fctrl %08x\n", __func__, i, - __raw_readl(imx_usb->base + USB_EP_FCTRL(i))); - - /* Fifo alarm */ - temp = (i ? imx_ep->fifosize / 2 : 0); - __raw_writel(temp, imx_usb->base + USB_EP_FALRM(i)); - D_INI(imx_usb->dev, "<%s> ep%d_falrm %08x\n", __func__, i, - __raw_readl(imx_usb->base + USB_EP_FALRM(i))); - } -} - -static void imx_udc_init(struct imx_udc_struct *imx_usb) -{ - /* Reset UDC */ - imx_udc_reset(imx_usb); - - /* Download config to enpoint buffer */ - imx_udc_config(imx_usb); - - /* Setup interrups */ - imx_udc_init_irq(imx_usb); - - /* Setup endpoints */ - imx_udc_init_ep(imx_usb); - - /* Setup fifos */ - imx_udc_init_fifo(imx_usb); -} - -void imx_ep_irq_enable(struct imx_ep_struct *imx_ep) -{ - - int i = EP_NO(imx_ep); - - __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_MASK(i)); - __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_INTR(i)); - __raw_writel(0x1FF & ~(EPINTR_EOT | EPINTR_EOF), - imx_ep->imx_usb->base + USB_EP_MASK(i)); -} - -void imx_ep_irq_disable(struct imx_ep_struct *imx_ep) -{ - - int i = EP_NO(imx_ep); - - __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_MASK(i)); - __raw_writel(0x1FF, imx_ep->imx_usb->base + USB_EP_INTR(i)); -} - -int imx_ep_empty(struct imx_ep_struct *imx_ep) -{ - struct imx_udc_struct *imx_usb = imx_ep->imx_usb; - - return __raw_readl(imx_usb->base + USB_EP_FSTAT(EP_NO(imx_ep))) - & FSTAT_EMPTY; -} - -unsigned imx_fifo_bcount(struct imx_ep_struct *imx_ep) -{ - struct imx_udc_struct *imx_usb = imx_ep->imx_usb; - - return (__raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))) - & EPSTAT_BCOUNT) >> 16; -} - -void imx_flush(struct imx_ep_struct *imx_ep) -{ - struct imx_udc_struct *imx_usb = imx_ep->imx_usb; - - int temp = __raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))); - __raw_writel(temp | EPSTAT_FLUSH, - imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))); -} - -void imx_ep_stall(struct imx_ep_struct *imx_ep) -{ - struct imx_udc_struct *imx_usb = imx_ep->imx_usb; - int temp, i; - - D_ERR(imx_usb->dev, - "<%s> Forced stall on %s\n", __func__, imx_ep->ep.name); - - imx_flush(imx_ep); - - /* Special care for ep0 */ - if (!EP_NO(imx_ep)) { - temp = __raw_readl(imx_usb->base + USB_CTRL); - __raw_writel(temp | CTRL_CMDOVER | CTRL_CMDERROR, - imx_usb->base + USB_CTRL); - do { } while (__raw_readl(imx_usb->base + USB_CTRL) - & CTRL_CMDOVER); - temp = __raw_readl(imx_usb->base + USB_CTRL); - __raw_writel(temp & ~CTRL_CMDERROR, imx_usb->base + USB_CTRL); - } - else { - temp = __raw_readl(imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))); - __raw_writel(temp | EPSTAT_STALL, - imx_usb->base + USB_EP_STAT(EP_NO(imx_ep))); - - for (i = 0; i < 100; i ++) { - temp = __raw_readl(imx_usb->base - + USB_EP_STAT(EP_NO(imx_ep))); - if (!(temp & EPSTAT_STALL)) - break; - udelay(20); - } - if (i == 100) - D_ERR(imx_usb->dev, "<%s> Non finished stall on %s\n", - __func__, imx_ep->ep.name); - } -} - -static int imx_udc_get_frame(struct usb_gadget *_gadget) -{ - struct imx_udc_struct *imx_usb = container_of(_gadget, - struct imx_udc_struct, gadget); - - return __raw_readl(imx_usb->base + USB_FRAME) & 0x7FF; -} - -static int imx_udc_wakeup(struct usb_gadget *_gadget) -{ - return 0; -} - -/******************************************************************************* - * USB request control functions - ******************************************************************************* - */ - -static void ep_add_request(struct imx_ep_struct *imx_ep, - struct imx_request *req) -{ - if (unlikely(!req)) - return; - - req->in_use = 1; - list_add_tail(&req->queue, &imx_ep->queue); -} - -static void ep_del_request(struct imx_ep_struct *imx_ep, - struct imx_request *req) -{ - if (unlikely(!req)) - return; - - list_del_init(&req->queue); - req->in_use = 0; -} - -static void done(struct imx_ep_struct *imx_ep, - struct imx_request *req, int status) -{ - ep_del_request(imx_ep, req); - - if (likely(req->req.status == -EINPROGRESS)) - req->req.status = status; - else - status = req->req.status; - - if (status && status != -ESHUTDOWN) - D_ERR(imx_ep->imx_usb->dev, - "<%s> complete %s req %p stat %d len %u/%u\n", __func__, - imx_ep->ep.name, &req->req, status, - req->req.actual, req->req.length); - - req->req.complete(&imx_ep->ep, &req->req); -} - -static void nuke(struct imx_ep_struct *imx_ep, int status) -{ - struct imx_request *req; - - while (!list_empty(&imx_ep->queue)) { - req = list_entry(imx_ep->queue.next, struct imx_request, queue); - done(imx_ep, req, status); - } -} - -/******************************************************************************* - * Data tansfer over USB functions - ******************************************************************************* - */ -static int read_packet(struct imx_ep_struct *imx_ep, struct imx_request *req) -{ - u8 *buf; - int bytes_ep, bufferspace, count, i; - - bytes_ep = imx_fifo_bcount(imx_ep); - bufferspace = req->req.length - req->req.actual; - - buf = req->req.buf + req->req.actual; - prefetchw(buf); - - if (unlikely(imx_ep_empty(imx_ep))) - count = 0; /* zlp */ - else - count = min(bytes_ep, bufferspace); - - for (i = count; i > 0; i--) - *buf++ = __raw_readb(imx_ep->imx_usb->base - + USB_EP_FDAT0(EP_NO(imx_ep))); - req->req.actual += count; - - return count; -} - -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); - - length = min(req->req.length - req->req.actual, (u32)imx_ep->fifosize); - - if (imx_fifo_bcount(imx_ep) + length > imx_ep->fifosize) { - D_TRX(imx_ep->imx_usb->dev, "<%s> packet overfill %s fifo\n", - __func__, imx_ep->ep.name); - return -1; - } - - req->req.actual += length; - count = length; - - if (!count && req->req.zero) { /* zlp */ - temp = __raw_readl(imx_ep->imx_usb->base - + USB_EP_STAT(EP_NO(imx_ep))); - __raw_writel(temp | EPSTAT_ZLPS, imx_ep->imx_usb->base - + USB_EP_STAT(EP_NO(imx_ep))); - D_TRX(imx_ep->imx_usb->dev, "<%s> zero packet\n", __func__); - return 0; - } - - while (count--) { - if (count == 0) { /* last byte */ - temp = __raw_readl(imx_ep->imx_usb->base - + USB_EP_FCTRL(EP_NO(imx_ep))); - __raw_writel(temp | FCTRL_WFR, imx_ep->imx_usb->base - + USB_EP_FCTRL(EP_NO(imx_ep))); - } - __raw_writeb(*buf++, - imx_ep->imx_usb->base + USB_EP_FDAT0(EP_NO(imx_ep))); - } - - return length; -} - -static int read_fifo(struct imx_ep_struct *imx_ep, struct imx_request *req) -{ - int bytes = 0, - count, - completed = 0; - - while (__raw_readl(imx_ep->imx_usb->base + USB_EP_FSTAT(EP_NO(imx_ep))) - & FSTAT_FR) { - count = read_packet(imx_ep, req); - bytes += count; - - completed = (count != imx_ep->fifosize); - if (completed || req->req.actual == req->req.length) { - completed = 1; - break; - } - } - - if (completed || !req->req.length) { - done(imx_ep, req, 0); - D_REQ(imx_ep->imx_usb->dev, "<%s> %s req<%p> %s\n", - __func__, imx_ep->ep.name, req, - completed ? "completed" : "not completed"); - if (!EP_NO(imx_ep)) - ep0_chg_stat(__func__, imx_ep->imx_usb, EP0_IDLE); - } - - D_TRX(imx_ep->imx_usb->dev, "<%s> bytes read: %d\n", __func__, bytes); - - return completed; -} - -static int write_fifo(struct imx_ep_struct *imx_ep, struct imx_request *req) -{ - int bytes = 0, - count, - completed = 0; - - while (!completed) { - count = write_packet(imx_ep, req); - if (count < 0) - break; /* busy */ - bytes += count; - - /* last packet "must be" short (or a zlp) */ - completed = (count != imx_ep->fifosize); - - if (unlikely(completed)) { - done(imx_ep, req, 0); - D_REQ(imx_ep->imx_usb->dev, "<%s> %s req<%p> %s\n", - __func__, imx_ep->ep.name, req, - completed ? "completed" : "not completed"); - if (!EP_NO(imx_ep)) - ep0_chg_stat(__func__, - imx_ep->imx_usb, EP0_IDLE); - } - } - - D_TRX(imx_ep->imx_usb->dev, "<%s> bytes sent: %d\n", __func__, bytes); - - return completed; -} - -/******************************************************************************* - * Endpoint handlers - ******************************************************************************* - */ -static int handle_ep(struct imx_ep_struct *imx_ep) -{ - struct imx_request *req; - int completed = 0; - - do { - if (!list_empty(&imx_ep->queue)) - req = list_entry(imx_ep->queue.next, - struct imx_request, queue); - else { - D_REQ(imx_ep->imx_usb->dev, "<%s> no request on %s\n", - __func__, imx_ep->ep.name); - return 0; - } - - if (EP_DIR(imx_ep)) /* to host */ - completed = write_fifo(imx_ep, req); - else /* to device */ - completed = read_fifo(imx_ep, req); - - dump_ep_stat(__func__, imx_ep); - - } while (completed); - - return 0; -} - -static int handle_ep0(struct imx_ep_struct *imx_ep) -{ - struct imx_request *req = NULL; - int ret = 0; - - if (!list_empty(&imx_ep->queue)) { - req = list_entry(imx_ep->queue.next, struct imx_request, queue); - - switch (imx_ep->imx_usb->ep0state) { - - case EP0_IN_DATA_PHASE: /* GET_DESCRIPTOR */ - write_fifo(imx_ep, req); - break; - case EP0_OUT_DATA_PHASE: /* SET_DESCRIPTOR */ - read_fifo(imx_ep, req); - break; - default: - D_EP0(imx_ep->imx_usb->dev, - "<%s> ep0 i/o, odd state %d\n", - __func__, imx_ep->imx_usb->ep0state); - ep_del_request(imx_ep, req); - ret = -EL2HLT; - break; - } - } - - else - D_ERR(imx_ep->imx_usb->dev, "<%s> no request on %s\n", - __func__, imx_ep->ep.name); - - return ret; -} - -static void handle_ep0_devreq(struct imx_udc_struct *imx_usb) -{ - struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[0]; - union { - struct usb_ctrlrequest r; - u8 raw[8]; - u32 word[2]; - } u; - int temp, i; - - nuke(imx_ep, -EPROTO); - - /* read SETUP packet */ - for (i = 0; i < 2; i++) { - if (imx_ep_empty(imx_ep)) { - D_ERR(imx_usb->dev, - "<%s> no setup packet received\n", __func__); - goto stall; - } - u.word[i] = __raw_readl(imx_usb->base - + USB_EP_FDAT(EP_NO(imx_ep))); - } - - temp = imx_ep_empty(imx_ep); - while (!imx_ep_empty(imx_ep)) { - i = __raw_readl(imx_usb->base + USB_EP_FDAT(EP_NO(imx_ep))); - D_ERR(imx_usb->dev, - "<%s> wrong to have extra bytes for setup : 0x%08x\n", - __func__, i); - } - if (!temp) - goto stall; - - le16_to_cpus(&u.r.wValue); - le16_to_cpus(&u.r.wIndex); - le16_to_cpus(&u.r.wLength); - - D_REQ(imx_usb->dev, "<%s> SETUP %02x.%02x v%04x i%04x l%04x\n", - __func__, u.r.bRequestType, u.r.bRequest, - u.r.wValue, u.r.wIndex, u.r.wLength); - - if (imx_usb->set_config) { - /* NACK the host by using CMDOVER */ - temp = __raw_readl(imx_usb->base + USB_CTRL); - __raw_writel(temp | CTRL_CMDOVER, imx_usb->base + USB_CTRL); - - D_ERR(imx_usb->dev, - "<%s> set config req is pending, NACK the host\n", - __func__); - return; - } - - if (u.r.bRequestType & USB_DIR_IN) - ep0_chg_stat(__func__, imx_usb, EP0_IN_DATA_PHASE); - else - ep0_chg_stat(__func__, imx_usb, EP0_OUT_DATA_PHASE); - - i = imx_usb->driver->setup(&imx_usb->gadget, &u.r); - if (i < 0) { - D_ERR(imx_usb->dev, "<%s> device setup error %d\n", - __func__, i); - goto stall; - } - - return; -stall: - D_ERR(imx_usb->dev, "<%s> protocol STALL\n", __func__); - imx_ep_stall(imx_ep); - ep0_chg_stat(__func__, imx_usb, EP0_STALL); - return; -} - -/******************************************************************************* - * USB gadget callback functions - ******************************************************************************* - */ - -static int imx_ep_enable(struct usb_ep *usb_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct imx_ep_struct *imx_ep = container_of(usb_ep, - struct imx_ep_struct, ep); - struct imx_udc_struct *imx_usb = imx_ep->imx_usb; - unsigned long flags; - - if (!usb_ep - || !desc - || !EP_NO(imx_ep) - || desc->bDescriptorType != USB_DT_ENDPOINT - || imx_ep->bEndpointAddress != desc->bEndpointAddress) { - D_ERR(imx_usb->dev, - "<%s> bad ep or descriptor\n", __func__); - return -EINVAL; - } - - if (imx_ep->bmAttributes != desc->bmAttributes) { - D_ERR(imx_usb->dev, - "<%s> %s type mismatch\n", __func__, usb_ep->name); - return -EINVAL; - } - - if (imx_ep->fifosize < usb_endpoint_maxp(desc)) { - D_ERR(imx_usb->dev, - "<%s> bad %s maxpacket\n", __func__, usb_ep->name); - return -ERANGE; - } - - if (!imx_usb->driver || imx_usb->gadget.speed == USB_SPEED_UNKNOWN) { - D_ERR(imx_usb->dev, "<%s> bogus device state\n", __func__); - return -ESHUTDOWN; - } - - local_irq_save(flags); - - imx_ep->stopped = 0; - imx_flush(imx_ep); - imx_ep_irq_enable(imx_ep); - - local_irq_restore(flags); - - D_EPX(imx_usb->dev, "<%s> ENABLED %s\n", __func__, usb_ep->name); - return 0; -} - -static int imx_ep_disable(struct usb_ep *usb_ep) -{ - struct imx_ep_struct *imx_ep = container_of(usb_ep, - struct imx_ep_struct, ep); - unsigned long flags; - - if (!usb_ep || !EP_NO(imx_ep) || !list_empty(&imx_ep->queue)) { - D_ERR(imx_ep->imx_usb->dev, "<%s> %s can not be disabled\n", - __func__, usb_ep ? imx_ep->ep.name : NULL); - return -EINVAL; - } - - local_irq_save(flags); - - imx_ep->stopped = 1; - nuke(imx_ep, -ESHUTDOWN); - imx_flush(imx_ep); - imx_ep_irq_disable(imx_ep); - - local_irq_restore(flags); - - D_EPX(imx_ep->imx_usb->dev, - "<%s> DISABLED %s\n", __func__, usb_ep->name); - return 0; -} - -static struct usb_request *imx_ep_alloc_request - (struct usb_ep *usb_ep, gfp_t gfp_flags) -{ - struct imx_request *req; - - if (!usb_ep) - return NULL; - - req = kzalloc(sizeof *req, gfp_flags); - if (!req) - return NULL; - - INIT_LIST_HEAD(&req->queue); - req->in_use = 0; - - return &req->req; -} - -static void imx_ep_free_request - (struct usb_ep *usb_ep, struct usb_request *usb_req) -{ - struct imx_request *req; - - req = container_of(usb_req, struct imx_request, req); - WARN_ON(!list_empty(&req->queue)); - kfree(req); -} - -static int imx_ep_queue - (struct usb_ep *usb_ep, struct usb_request *usb_req, gfp_t gfp_flags) -{ - struct imx_ep_struct *imx_ep; - struct imx_udc_struct *imx_usb; - struct imx_request *req; - unsigned long flags; - int ret = 0; - - imx_ep = container_of(usb_ep, struct imx_ep_struct, ep); - imx_usb = imx_ep->imx_usb; - req = container_of(usb_req, struct imx_request, req); - - /* - Special care on IMX udc. - Ignore enqueue when after set configuration from the - host. This assume all gadget drivers reply set - configuration with the next ep0 req enqueue. - */ - if (imx_usb->set_config && !EP_NO(imx_ep)) { - imx_usb->set_config = 0; - D_ERR(imx_usb->dev, - "<%s> gadget reply set config\n", __func__); - return 0; - } - - if (unlikely(!usb_req || !req || !usb_req->complete || !usb_req->buf)) { - D_ERR(imx_usb->dev, "<%s> bad params\n", __func__); - return -EINVAL; - } - - if (unlikely(!usb_ep || !imx_ep)) { - D_ERR(imx_usb->dev, "<%s> bad ep\n", __func__); - return -EINVAL; - } - - if (!imx_usb->driver || imx_usb->gadget.speed == USB_SPEED_UNKNOWN) { - D_ERR(imx_usb->dev, "<%s> bogus device state\n", __func__); - return -ESHUTDOWN; - } - - /* Debug */ - D_REQ(imx_usb->dev, "<%s> ep%d %s request for [%d] bytes\n", - __func__, EP_NO(imx_ep), - ((!EP_NO(imx_ep) && imx_ep->imx_usb->ep0state - == EP0_IN_DATA_PHASE) - || (EP_NO(imx_ep) && EP_DIR(imx_ep))) - ? "IN" : "OUT", usb_req->length); - dump_req(__func__, imx_ep, usb_req); - - if (imx_ep->stopped) { - usb_req->status = -ESHUTDOWN; - return -ESHUTDOWN; - } - - if (req->in_use) { - D_ERR(imx_usb->dev, - "<%s> refusing to queue req %p (already queued)\n", - __func__, req); - return 0; - } - - local_irq_save(flags); - - usb_req->status = -EINPROGRESS; - usb_req->actual = 0; - - ep_add_request(imx_ep, req); - - if (!EP_NO(imx_ep)) - ret = handle_ep0(imx_ep); - else - ret = handle_ep(imx_ep); - - local_irq_restore(flags); - return ret; -} - -static int imx_ep_dequeue(struct usb_ep *usb_ep, struct usb_request *usb_req) -{ - - struct imx_ep_struct *imx_ep = container_of - (usb_ep, struct imx_ep_struct, ep); - struct imx_request *req; - unsigned long flags; - - if (unlikely(!usb_ep || !EP_NO(imx_ep))) { - D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__); - return -EINVAL; - } - - local_irq_save(flags); - - /* make sure it's actually queued on this endpoint */ - list_for_each_entry(req, &imx_ep->queue, queue) { - if (&req->req == usb_req) - break; - } - if (&req->req != usb_req) { - local_irq_restore(flags); - return -EINVAL; - } - - done(imx_ep, req, -ECONNRESET); - - local_irq_restore(flags); - return 0; -} - -static int imx_ep_set_halt(struct usb_ep *usb_ep, int value) -{ - struct imx_ep_struct *imx_ep = container_of - (usb_ep, struct imx_ep_struct, ep); - unsigned long flags; - - if (unlikely(!usb_ep || !EP_NO(imx_ep))) { - D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__); - return -EINVAL; - } - - local_irq_save(flags); - - if ((imx_ep->bEndpointAddress & USB_DIR_IN) - && !list_empty(&imx_ep->queue)) { - local_irq_restore(flags); - return -EAGAIN; - } - - imx_ep_stall(imx_ep); - - local_irq_restore(flags); - - D_EPX(imx_ep->imx_usb->dev, "<%s> %s halt\n", __func__, usb_ep->name); - return 0; -} - -static int imx_ep_fifo_status(struct usb_ep *usb_ep) -{ - struct imx_ep_struct *imx_ep = container_of - (usb_ep, struct imx_ep_struct, ep); - - if (!usb_ep) { - D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__); - return -ENODEV; - } - - if (imx_ep->imx_usb->gadget.speed == USB_SPEED_UNKNOWN) - return 0; - else - return imx_fifo_bcount(imx_ep); -} - -static void imx_ep_fifo_flush(struct usb_ep *usb_ep) -{ - struct imx_ep_struct *imx_ep = container_of - (usb_ep, struct imx_ep_struct, ep); - unsigned long flags; - - local_irq_save(flags); - - if (!usb_ep || !EP_NO(imx_ep) || !list_empty(&imx_ep->queue)) { - D_ERR(imx_ep->imx_usb->dev, "<%s> bad ep\n", __func__); - local_irq_restore(flags); - return; - } - - /* toggle and halt bits stay unchanged */ - imx_flush(imx_ep); - - local_irq_restore(flags); -} - -static struct usb_ep_ops imx_ep_ops = { - .enable = imx_ep_enable, - .disable = imx_ep_disable, - - .alloc_request = imx_ep_alloc_request, - .free_request = imx_ep_free_request, - - .queue = imx_ep_queue, - .dequeue = imx_ep_dequeue, - - .set_halt = imx_ep_set_halt, - .fifo_status = imx_ep_fifo_status, - .fifo_flush = imx_ep_fifo_flush, -}; - -/******************************************************************************* - * USB endpoint control functions - ******************************************************************************* - */ - -void ep0_chg_stat(const char *label, - struct imx_udc_struct *imx_usb, enum ep0_state stat) -{ - D_EP0(imx_usb->dev, "<%s> from %15s to %15s\n", - label, state_name[imx_usb->ep0state], state_name[stat]); - - if (imx_usb->ep0state == stat) - return; - - imx_usb->ep0state = stat; -} - -static void usb_init_data(struct imx_udc_struct *imx_usb) -{ - struct imx_ep_struct *imx_ep; - u8 i; - - /* device/ep0 records init */ - INIT_LIST_HEAD(&imx_usb->gadget.ep_list); - INIT_LIST_HEAD(&imx_usb->gadget.ep0->ep_list); - ep0_chg_stat(__func__, imx_usb, EP0_IDLE); - - /* basic endpoint records init */ - for (i = 0; i < IMX_USB_NB_EP; i++) { - imx_ep = &imx_usb->imx_ep[i]; - - if (i) { - list_add_tail(&imx_ep->ep.ep_list, - &imx_usb->gadget.ep_list); - imx_ep->stopped = 1; - } else - imx_ep->stopped = 0; - - INIT_LIST_HEAD(&imx_ep->queue); - } -} - -static void udc_stop_activity(struct imx_udc_struct *imx_usb, - struct usb_gadget_driver *driver) -{ - struct imx_ep_struct *imx_ep; - int i; - - if (imx_usb->gadget.speed == USB_SPEED_UNKNOWN) - driver = NULL; - - /* prevent new request submissions, kill any outstanding requests */ - for (i = 1; i < IMX_USB_NB_EP; i++) { - imx_ep = &imx_usb->imx_ep[i]; - imx_flush(imx_ep); - imx_ep->stopped = 1; - imx_ep_irq_disable(imx_ep); - nuke(imx_ep, -ESHUTDOWN); - } - - imx_usb->cfg = 0; - imx_usb->intf = 0; - imx_usb->alt = 0; - - if (driver) - driver->disconnect(&imx_usb->gadget); -} - -/******************************************************************************* - * Interrupt handlers - ******************************************************************************* - */ - -/* - * Called when timer expires. - * Timer is started when CFG_CHG is received. - */ -static void handle_config(unsigned long data) -{ - struct imx_udc_struct *imx_usb = (void *)data; - struct usb_ctrlrequest u; - int temp, cfg, intf, alt; - - local_irq_disable(); - - temp = __raw_readl(imx_usb->base + USB_STAT); - cfg = (temp & STAT_CFG) >> 5; - intf = (temp & STAT_INTF) >> 3; - alt = temp & STAT_ALTSET; - - D_REQ(imx_usb->dev, - "<%s> orig config C=%d, I=%d, A=%d / " - "req config C=%d, I=%d, A=%d\n", - __func__, imx_usb->cfg, imx_usb->intf, imx_usb->alt, - cfg, intf, alt); - - if (cfg == 1 || cfg == 2) { - - if (imx_usb->cfg != cfg) { - u.bRequest = USB_REQ_SET_CONFIGURATION; - u.bRequestType = USB_DIR_OUT | - USB_TYPE_STANDARD | - USB_RECIP_DEVICE; - u.wValue = cfg; - u.wIndex = 0; - u.wLength = 0; - imx_usb->cfg = cfg; - imx_usb->driver->setup(&imx_usb->gadget, &u); - - } - if (imx_usb->intf != intf || imx_usb->alt != alt) { - u.bRequest = USB_REQ_SET_INTERFACE; - u.bRequestType = USB_DIR_OUT | - USB_TYPE_STANDARD | - USB_RECIP_INTERFACE; - u.wValue = alt; - u.wIndex = intf; - u.wLength = 0; - imx_usb->intf = intf; - imx_usb->alt = alt; - imx_usb->driver->setup(&imx_usb->gadget, &u); - } - } - - imx_usb->set_config = 0; - - local_irq_enable(); -} - -static irqreturn_t imx_udc_irq(int irq, void *dev) -{ - struct imx_udc_struct *imx_usb = dev; - int intr = __raw_readl(imx_usb->base + USB_INTR); - int temp; - - if (intr & (INTR_WAKEUP | INTR_SUSPEND | INTR_RESUME | INTR_RESET_START - | INTR_RESET_STOP | INTR_CFG_CHG)) { - dump_intr(__func__, intr, imx_usb->dev); - dump_usb_stat(__func__, imx_usb); - } - - if (!imx_usb->driver) - goto end_irq; - - if (intr & INTR_SOF) { - /* Copy from Freescale BSP. - We must enable SOF intr and set CMDOVER. - Datasheet don't specifiy this action, but it - is done in Freescale BSP, so just copy it. - */ - if (imx_usb->ep0state == EP0_IDLE) { - temp = __raw_readl(imx_usb->base + USB_CTRL); - __raw_writel(temp | CTRL_CMDOVER, - imx_usb->base + USB_CTRL); - } - } - - if (intr & INTR_CFG_CHG) { - /* A workaround of serious IMX UDC bug. - Handling of CFG_CHG should be delayed for some time, because - IMX does not NACK the host when CFG_CHG interrupt is pending. - There is no time to handle current CFG_CHG - if next CFG_CHG or SETUP packed is send immediately. - We have to clear CFG_CHG, start the timer and - NACK the host by setting CTRL_CMDOVER - if it sends any SETUP packet. - When timer expires, handler is called to handle configuration - changes. While CFG_CHG is not handled (set_config=1), - we must NACK the host to every SETUP packed. - This delay prevents from going out of sync with host. - */ - __raw_writel(INTR_CFG_CHG, imx_usb->base + USB_INTR); - imx_usb->set_config = 1; - mod_timer(&imx_usb->timer, jiffies + 5); - goto end_irq; - } - - if (intr & INTR_WAKEUP) { - if (imx_usb->gadget.speed == USB_SPEED_UNKNOWN - && imx_usb->driver && imx_usb->driver->resume) - imx_usb->driver->resume(&imx_usb->gadget); - imx_usb->set_config = 0; - del_timer(&imx_usb->timer); - imx_usb->gadget.speed = USB_SPEED_FULL; - } - - if (intr & INTR_SUSPEND) { - if (imx_usb->gadget.speed != USB_SPEED_UNKNOWN - && imx_usb->driver && imx_usb->driver->suspend) - imx_usb->driver->suspend(&imx_usb->gadget); - imx_usb->set_config = 0; - del_timer(&imx_usb->timer); - imx_usb->gadget.speed = USB_SPEED_UNKNOWN; - } - - if (intr & INTR_RESET_START) { - __raw_writel(intr, imx_usb->base + USB_INTR); - udc_stop_activity(imx_usb, imx_usb->driver); - imx_usb->set_config = 0; - del_timer(&imx_usb->timer); - imx_usb->gadget.speed = USB_SPEED_UNKNOWN; - } - - if (intr & INTR_RESET_STOP) - imx_usb->gadget.speed = USB_SPEED_FULL; - -end_irq: - __raw_writel(intr, imx_usb->base + USB_INTR); - return IRQ_HANDLED; -} - -static irqreturn_t imx_udc_ctrl_irq(int irq, void *dev) -{ - struct imx_udc_struct *imx_usb = dev; - struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[0]; - int intr = __raw_readl(imx_usb->base + USB_EP_INTR(0)); - - dump_ep_intr(__func__, 0, intr, imx_usb->dev); - - if (!imx_usb->driver) { - __raw_writel(intr, imx_usb->base + USB_EP_INTR(0)); - return IRQ_HANDLED; - } - - /* DEVREQ has highest priority */ - if (intr & (EPINTR_DEVREQ | EPINTR_MDEVREQ)) - handle_ep0_devreq(imx_usb); - /* Seem i.MX is missing EOF interrupt sometimes. - * Therefore we don't monitor EOF. - * We call handle_ep0() only if a request is queued for ep0. - */ - else if (!list_empty(&imx_ep->queue)) - handle_ep0(imx_ep); - - __raw_writel(intr, imx_usb->base + USB_EP_INTR(0)); - - return IRQ_HANDLED; -} - -#ifndef MX1_INT_USBD0 -#define MX1_INT_USBD0 MX1_USBD_INT0 -#endif - -static irqreturn_t imx_udc_bulk_irq(int irq, void *dev) -{ - struct imx_udc_struct *imx_usb = dev; - struct imx_ep_struct *imx_ep = &imx_usb->imx_ep[irq - MX1_INT_USBD0]; - int intr = __raw_readl(imx_usb->base + USB_EP_INTR(EP_NO(imx_ep))); - - dump_ep_intr(__func__, irq - MX1_INT_USBD0, intr, imx_usb->dev); - - if (!imx_usb->driver) { - __raw_writel(intr, imx_usb->base + USB_EP_INTR(EP_NO(imx_ep))); - return IRQ_HANDLED; - } - - handle_ep(imx_ep); - - __raw_writel(intr, imx_usb->base + USB_EP_INTR(EP_NO(imx_ep))); - - return IRQ_HANDLED; -} - -irq_handler_t intr_handler(int i) -{ - switch (i) { - case 0: - return imx_udc_ctrl_irq; - case 1: - case 2: - case 3: - case 4: - case 5: - return imx_udc_bulk_irq; - default: - return imx_udc_irq; - } -} - -/******************************************************************************* - * Static defined IMX UDC structure - ******************************************************************************* - */ - -static int imx_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int imx_udc_stop(struct usb_gadget_driver *driver); -static const struct usb_gadget_ops imx_udc_ops = { - .get_frame = imx_udc_get_frame, - .wakeup = imx_udc_wakeup, - .start = imx_udc_start, - .stop = imx_udc_stop, -}; - -static struct imx_udc_struct controller = { - .gadget = { - .ops = &imx_udc_ops, - .ep0 = &controller.imx_ep[0].ep, - .name = driver_name, - .dev = { - .init_name = "gadget", - }, - }, - - .imx_ep[0] = { - .ep = { - .name = ep0name, - .ops = &imx_ep_ops, - .maxpacket = 32, - }, - .imx_usb = &controller, - .fifosize = 32, - .bEndpointAddress = 0, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, - }, - .imx_ep[1] = { - .ep = { - .name = "ep1in-bulk", - .ops = &imx_ep_ops, - .maxpacket = 64, - }, - .imx_usb = &controller, - .fifosize = 64, - .bEndpointAddress = USB_DIR_IN | 1, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - }, - .imx_ep[2] = { - .ep = { - .name = "ep2out-bulk", - .ops = &imx_ep_ops, - .maxpacket = 64, - }, - .imx_usb = &controller, - .fifosize = 64, - .bEndpointAddress = USB_DIR_OUT | 2, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - }, - .imx_ep[3] = { - .ep = { - .name = "ep3out-bulk", - .ops = &imx_ep_ops, - .maxpacket = 32, - }, - .imx_usb = &controller, - .fifosize = 32, - .bEndpointAddress = USB_DIR_OUT | 3, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - }, - .imx_ep[4] = { - .ep = { - .name = "ep4in-int", - .ops = &imx_ep_ops, - .maxpacket = 32, - }, - .imx_usb = &controller, - .fifosize = 32, - .bEndpointAddress = USB_DIR_IN | 4, - .bmAttributes = USB_ENDPOINT_XFER_INT, - }, - .imx_ep[5] = { - .ep = { - .name = "ep5out-int", - .ops = &imx_ep_ops, - .maxpacket = 32, - }, - .imx_usb = &controller, - .fifosize = 32, - .bEndpointAddress = USB_DIR_OUT | 5, - .bmAttributes = USB_ENDPOINT_XFER_INT, - }, -}; - -/******************************************************************************* - * USB gadget driver functions - ******************************************************************************* - */ -static int imx_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) -{ - struct imx_udc_struct *imx_usb = &controller; - int retval; - - if (!driver - || driver->max_speed < USB_SPEED_FULL - || !bind - || !driver->disconnect - || !driver->setup) - return -EINVAL; - if (!imx_usb) - return -ENODEV; - if (imx_usb->driver) - return -EBUSY; - - /* first hook up the driver ... */ - imx_usb->driver = driver; - imx_usb->gadget.dev.driver = &driver->driver; - - retval = device_add(&imx_usb->gadget.dev); - if (retval) - goto fail; - retval = bind(&imx_usb->gadget); - if (retval) { - D_ERR(imx_usb->dev, "<%s> bind to driver %s --> error %d\n", - __func__, driver->driver.name, retval); - device_del(&imx_usb->gadget.dev); - - goto fail; - } - - D_INI(imx_usb->dev, "<%s> registered gadget driver '%s'\n", - __func__, driver->driver.name); - - imx_udc_enable(imx_usb); - - return 0; -fail: - imx_usb->driver = NULL; - imx_usb->gadget.dev.driver = NULL; - return retval; -} - -static int imx_udc_stop(struct usb_gadget_driver *driver) -{ - struct imx_udc_struct *imx_usb = &controller; - - if (!imx_usb) - return -ENODEV; - if (!driver || driver != imx_usb->driver || !driver->unbind) - return -EINVAL; - - udc_stop_activity(imx_usb, driver); - imx_udc_disable(imx_usb); - del_timer(&imx_usb->timer); - - driver->unbind(&imx_usb->gadget); - imx_usb->gadget.dev.driver = NULL; - imx_usb->driver = NULL; - - device_del(&imx_usb->gadget.dev); - - D_INI(imx_usb->dev, "<%s> unregistered gadget driver '%s'\n", - __func__, driver->driver.name); - - return 0; -} - -/******************************************************************************* - * Module functions - ******************************************************************************* - */ - -static int __init imx_udc_probe(struct platform_device *pdev) -{ - struct imx_udc_struct *imx_usb = &controller; - struct resource *res; - struct imxusb_platform_data *pdata; - struct clk *clk; - void __iomem *base; - int ret = 0; - int i; - resource_size_t res_size; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "can't get device resources\n"); - return -ENODEV; - } - - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "driver needs platform data\n"); - return -ENODEV; - } - - res_size = resource_size(res); - if (!request_mem_region(res->start, res_size, res->name)) { - dev_err(&pdev->dev, "can't allocate %d bytes at %d address\n", - res_size, res->start); - return -ENOMEM; - } - - if (pdata->init) { - ret = pdata->init(&pdev->dev); - if (ret) - goto fail0; - } - - base = ioremap(res->start, res_size); - if (!base) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -EIO; - goto fail1; - } - - clk = clk_get(NULL, "usbd_clk"); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - dev_err(&pdev->dev, "can't get USB clock\n"); - goto fail2; - } - clk_enable(clk); - - if (clk_get_rate(clk) != 48000000) { - D_INI(&pdev->dev, - "Bad USB clock (%d Hz), changing to 48000000 Hz\n", - (int)clk_get_rate(clk)); - if (clk_set_rate(clk, 48000000)) { - dev_err(&pdev->dev, - "Unable to set correct USB clock (48MHz)\n"); - ret = -EIO; - goto fail3; - } - } - - for (i = 0; i < IMX_USB_NB_EP + 1; i++) { - imx_usb->usbd_int[i] = platform_get_irq(pdev, i); - if (imx_usb->usbd_int[i] < 0) { - dev_err(&pdev->dev, "can't get irq number\n"); - ret = -ENODEV; - goto fail3; - } - } - - for (i = 0; i < IMX_USB_NB_EP + 1; i++) { - ret = request_irq(imx_usb->usbd_int[i], intr_handler(i), - 0, driver_name, imx_usb); - if (ret) { - dev_err(&pdev->dev, "can't get irq %i, err %d\n", - imx_usb->usbd_int[i], ret); - for (--i; i >= 0; i--) - free_irq(imx_usb->usbd_int[i], imx_usb); - goto fail3; - } - } - - imx_usb->res = res; - imx_usb->base = base; - imx_usb->clk = clk; - imx_usb->dev = &pdev->dev; - - device_initialize(&imx_usb->gadget.dev); - - imx_usb->gadget.dev.parent = &pdev->dev; - imx_usb->gadget.dev.dma_mask = pdev->dev.dma_mask; - - platform_set_drvdata(pdev, imx_usb); - - usb_init_data(imx_usb); - imx_udc_init(imx_usb); - - init_timer(&imx_usb->timer); - imx_usb->timer.function = handle_config; - imx_usb->timer.data = (unsigned long)imx_usb; - - ret = usb_add_gadget_udc(&pdev->dev, &imx_usb->gadget); - if (ret) - goto fail4; - - return 0; -fail4: - for (i = 0; i < IMX_USB_NB_EP + 1; i++) - free_irq(imx_usb->usbd_int[i], imx_usb); -fail3: - clk_put(clk); - clk_disable(clk); -fail2: - iounmap(base); -fail1: - if (pdata->exit) - pdata->exit(&pdev->dev); -fail0: - release_mem_region(res->start, res_size); - return ret; -} - -static int __exit imx_udc_remove(struct platform_device *pdev) -{ - struct imx_udc_struct *imx_usb = platform_get_drvdata(pdev); - struct imxusb_platform_data *pdata = pdev->dev.platform_data; - int i; - - usb_del_gadget_udc(&imx_usb->gadget); - imx_udc_disable(imx_usb); - del_timer(&imx_usb->timer); - - for (i = 0; i < IMX_USB_NB_EP + 1; i++) - free_irq(imx_usb->usbd_int[i], imx_usb); - - clk_put(imx_usb->clk); - clk_disable(imx_usb->clk); - iounmap(imx_usb->base); - - release_mem_region(imx_usb->res->start, resource_size(imx_usb->res)); - - if (pdata->exit) - pdata->exit(&pdev->dev); - - platform_set_drvdata(pdev, NULL); - - return 0; -} - -/*----------------------------------------------------------------------------*/ - -#ifdef CONFIG_PM -#define imx_udc_suspend NULL -#define imx_udc_resume NULL -#else -#define imx_udc_suspend NULL -#define imx_udc_resume NULL -#endif - -/*----------------------------------------------------------------------------*/ - -static struct platform_driver udc_driver = { - .driver = { - .name = driver_name, - .owner = THIS_MODULE, - }, - .remove = __exit_p(imx_udc_remove), - .suspend = imx_udc_suspend, - .resume = imx_udc_resume, -}; - -static int __init udc_init(void) -{ - return platform_driver_probe(&udc_driver, imx_udc_probe); -} -module_init(udc_init); - -static void __exit udc_exit(void) -{ - platform_driver_unregister(&udc_driver); -} -module_exit(udc_exit); - -MODULE_DESCRIPTION("IMX USB Device Controller driver"); -MODULE_AUTHOR("Darius Augulis "); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:imx_udc"); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/imx_udc.h b/ANDROID_3.4.5/drivers/usb/gadget/imx_udc.h deleted file mode 100644 index d118fb77..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/imx_udc.h +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Copyright (C) 2005 Mike Lee(eemike@gmail.com) - * - * This udc driver is now under testing and code is based on pxa2xx_udc.h - * Please use it with your own risk! - * - * 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. - */ - -#ifndef __LINUX_USB_GADGET_IMX_H -#define __LINUX_USB_GADGET_IMX_H - -#include - -/* Helper macros */ -#define EP_NO(ep) ((ep->bEndpointAddress) & ~USB_DIR_IN) /* IN:1, OUT:0 */ -#define EP_DIR(ep) ((ep->bEndpointAddress) & USB_DIR_IN ? 1 : 0) -#define IMX_USB_NB_EP 6 - -/* Driver structures */ -struct imx_request { - struct usb_request req; - struct list_head queue; - unsigned int in_use; -}; - -enum ep0_state { - EP0_IDLE, - EP0_IN_DATA_PHASE, - EP0_OUT_DATA_PHASE, - EP0_CONFIG, - EP0_STALL, -}; - -struct imx_ep_struct { - struct usb_ep ep; - struct imx_udc_struct *imx_usb; - struct list_head queue; - unsigned char stopped; - unsigned char fifosize; - unsigned char bEndpointAddress; - unsigned char bmAttributes; -}; - -struct imx_udc_struct { - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - struct device *dev; - struct imx_ep_struct imx_ep[IMX_USB_NB_EP]; - struct clk *clk; - struct timer_list timer; - enum ep0_state ep0state; - struct resource *res; - void __iomem *base; - unsigned char set_config; - int cfg, - intf, - alt, - usbd_int[7]; -}; - -/* USB registers */ -#define USB_FRAME (0x00) /* USB frame */ -#define USB_SPEC (0x04) /* USB Spec */ -#define USB_STAT (0x08) /* USB Status */ -#define USB_CTRL (0x0C) /* USB Control */ -#define USB_DADR (0x10) /* USB Desc RAM addr */ -#define USB_DDAT (0x14) /* USB Desc RAM/EP buffer data */ -#define USB_INTR (0x18) /* USB interrupt */ -#define USB_MASK (0x1C) /* USB Mask */ -#define USB_ENAB (0x24) /* USB Enable */ -#define USB_EP_STAT(x) (0x30 + (x*0x30)) /* USB status/control */ -#define USB_EP_INTR(x) (0x34 + (x*0x30)) /* USB interrupt */ -#define USB_EP_MASK(x) (0x38 + (x*0x30)) /* USB mask */ -#define USB_EP_FDAT(x) (0x3C + (x*0x30)) /* USB FIFO data */ -#define USB_EP_FDAT0(x) (0x3C + (x*0x30)) /* USB FIFO data */ -#define USB_EP_FDAT1(x) (0x3D + (x*0x30)) /* USB FIFO data */ -#define USB_EP_FDAT2(x) (0x3E + (x*0x30)) /* USB FIFO data */ -#define USB_EP_FDAT3(x) (0x3F + (x*0x30)) /* USB FIFO data */ -#define USB_EP_FSTAT(x) (0x40 + (x*0x30)) /* USB FIFO status */ -#define USB_EP_FCTRL(x) (0x44 + (x*0x30)) /* USB FIFO control */ -#define USB_EP_LRFP(x) (0x48 + (x*0x30)) /* USB last rd f. pointer */ -#define USB_EP_LWFP(x) (0x4C + (x*0x30)) /* USB last wr f. pointer */ -#define USB_EP_FALRM(x) (0x50 + (x*0x30)) /* USB FIFO alarm */ -#define USB_EP_FRDP(x) (0x54 + (x*0x30)) /* USB FIFO read pointer */ -#define USB_EP_FWRP(x) (0x58 + (x*0x30)) /* USB FIFO write pointer */ -/* USB Control Register Bit Fields.*/ -#define CTRL_CMDOVER (1<<6) /* UDC status */ -#define CTRL_CMDERROR (1<<5) /* UDC status */ -#define CTRL_FE_ENA (1<<3) /* Enable Font End logic */ -#define CTRL_UDC_RST (1<<2) /* UDC reset */ -#define CTRL_AFE_ENA (1<<1) /* Analog Font end enable */ -#define CTRL_RESUME (1<<0) /* UDC resume */ -/* USB Status Register Bit Fields.*/ -#define STAT_RST (1<<8) -#define STAT_SUSP (1<<7) -#define STAT_CFG (3<<5) -#define STAT_INTF (3<<3) -#define STAT_ALTSET (7<<0) -/* USB Interrupt Status/Mask Registers Bit fields */ -#define INTR_WAKEUP (1<<31) /* Wake up Interrupt */ -#define INTR_MSOF (1<<7) /* Missed Start of Frame */ -#define INTR_SOF (1<<6) /* Start of Frame */ -#define INTR_RESET_STOP (1<<5) /* Reset Signaling stop */ -#define INTR_RESET_START (1<<4) /* Reset Signaling start */ -#define INTR_RESUME (1<<3) /* Suspend to resume */ -#define INTR_SUSPEND (1<<2) /* Active to suspend */ -#define INTR_FRAME_MATCH (1<<1) /* Frame matched */ -#define INTR_CFG_CHG (1<<0) /* Configuration change occurred */ -/* USB Enable Register Bit Fields.*/ -#define ENAB_RST (1<<31) /* Reset USB modules */ -#define ENAB_ENAB (1<<30) /* Enable USB modules*/ -#define ENAB_SUSPEND (1<<29) /* Suspend USB modules */ -#define ENAB_ENDIAN (1<<28) /* Endian of USB modules */ -#define ENAB_PWRMD (1<<0) /* Power mode of USB modules */ -/* USB Descriptor Ram Address Register bit fields */ -#define DADR_CFG (1<<31) /* Configuration */ -#define DADR_BSY (1<<30) /* Busy status */ -#define DADR_DADR (0x1FF) /* Descriptor Ram Address */ -/* USB Descriptor RAM/Endpoint Buffer Data Register bit fields */ -#define DDAT_DDAT (0xFF) /* Descriptor Endpoint Buffer */ -/* USB Endpoint Status Register bit fields */ -#define EPSTAT_BCOUNT (0x7F<<16) /* Endpoint FIFO byte count */ -#define EPSTAT_SIP (1<<8) /* Endpoint setup in progress */ -#define EPSTAT_DIR (1<<7) /* Endpoint transfer direction */ -#define EPSTAT_MAX (3<<5) /* Endpoint Max packet size */ -#define EPSTAT_TYP (3<<3) /* Endpoint type */ -#define EPSTAT_ZLPS (1<<2) /* Send zero length packet */ -#define EPSTAT_FLUSH (1<<1) /* Endpoint FIFO Flush */ -#define EPSTAT_STALL (1<<0) /* Force stall */ -/* USB Endpoint FIFO Status Register bit fields */ -#define FSTAT_FRAME_STAT (0xF<<24) /* Frame status bit [0-3] */ -#define FSTAT_ERR (1<<22) /* FIFO error */ -#define FSTAT_UF (1<<21) /* FIFO underflow */ -#define FSTAT_OF (1<<20) /* FIFO overflow */ -#define FSTAT_FR (1<<19) /* FIFO frame ready */ -#define FSTAT_FULL (1<<18) /* FIFO full */ -#define FSTAT_ALRM (1<<17) /* FIFO alarm */ -#define FSTAT_EMPTY (1<<16) /* FIFO empty */ -/* USB Endpoint FIFO Control Register bit fields */ -#define FCTRL_WFR (1<<29) /* Write frame end */ -/* USB Endpoint Interrupt Status Regsiter bit fields */ -#define EPINTR_FIFO_FULL (1<<8) /* fifo full */ -#define EPINTR_FIFO_EMPTY (1<<7) /* fifo empty */ -#define EPINTR_FIFO_ERROR (1<<6) /* fifo error */ -#define EPINTR_FIFO_HIGH (1<<5) /* fifo high */ -#define EPINTR_FIFO_LOW (1<<4) /* fifo low */ -#define EPINTR_MDEVREQ (1<<3) /* multi Device request */ -#define EPINTR_EOT (1<<2) /* fifo end of transfer */ -#define EPINTR_DEVREQ (1<<1) /* Device request */ -#define EPINTR_EOF (1<<0) /* fifo end of frame */ - -/* Debug macros */ -#ifdef DEBUG - -/* #define DEBUG_REQ */ -/* #define DEBUG_TRX */ -/* #define DEBUG_INIT */ -/* #define DEBUG_EP0 */ -/* #define DEBUG_EPX */ -/* #define DEBUG_IRQ */ -/* #define DEBUG_EPIRQ */ -/* #define DEBUG_DUMP */ -/* #define DEBUG_ERR */ - -#ifdef DEBUG_REQ - #define D_REQ(dev, args...) dev_dbg(dev, ## args) -#else - #define D_REQ(dev, args...) do {} while (0) -#endif /* DEBUG_REQ */ - -#ifdef DEBUG_TRX - #define D_TRX(dev, args...) dev_dbg(dev, ## args) -#else - #define D_TRX(dev, args...) do {} while (0) -#endif /* DEBUG_TRX */ - -#ifdef DEBUG_INIT - #define D_INI(dev, args...) dev_dbg(dev, ## args) -#else - #define D_INI(dev, args...) do {} while (0) -#endif /* DEBUG_INIT */ - -#ifdef DEBUG_EP0 - static const char *state_name[] = { - "EP0_IDLE", - "EP0_IN_DATA_PHASE", - "EP0_OUT_DATA_PHASE", - "EP0_CONFIG", - "EP0_STALL" - }; - #define D_EP0(dev, args...) dev_dbg(dev, ## args) -#else - #define D_EP0(dev, args...) do {} while (0) -#endif /* DEBUG_EP0 */ - -#ifdef DEBUG_EPX - #define D_EPX(dev, args...) dev_dbg(dev, ## args) -#else - #define D_EPX(dev, args...) do {} while (0) -#endif /* DEBUG_EP0 */ - -#ifdef DEBUG_IRQ - static void dump_intr(const char *label, int irqreg, struct device *dev) - { - dev_dbg(dev, "<%s> USB_INTR=[%s%s%s%s%s%s%s%s%s]\n", label, - (irqreg & INTR_WAKEUP) ? " wake" : "", - (irqreg & INTR_MSOF) ? " msof" : "", - (irqreg & INTR_SOF) ? " sof" : "", - (irqreg & INTR_RESUME) ? " resume" : "", - (irqreg & INTR_SUSPEND) ? " suspend" : "", - (irqreg & INTR_RESET_STOP) ? " noreset" : "", - (irqreg & INTR_RESET_START) ? " reset" : "", - (irqreg & INTR_FRAME_MATCH) ? " fmatch" : "", - (irqreg & INTR_CFG_CHG) ? " config" : ""); - } -#else - #define dump_intr(x, y, z) do {} while (0) -#endif /* DEBUG_IRQ */ - -#ifdef DEBUG_EPIRQ - static void dump_ep_intr(const char *label, int nr, int irqreg, - struct device *dev) - { - dev_dbg(dev, "<%s> EP%d_INTR=[%s%s%s%s%s%s%s%s%s]\n", label, nr, - (irqreg & EPINTR_FIFO_FULL) ? " full" : "", - (irqreg & EPINTR_FIFO_EMPTY) ? " fempty" : "", - (irqreg & EPINTR_FIFO_ERROR) ? " ferr" : "", - (irqreg & EPINTR_FIFO_HIGH) ? " fhigh" : "", - (irqreg & EPINTR_FIFO_LOW) ? " flow" : "", - (irqreg & EPINTR_MDEVREQ) ? " mreq" : "", - (irqreg & EPINTR_EOF) ? " eof" : "", - (irqreg & EPINTR_DEVREQ) ? " devreq" : "", - (irqreg & EPINTR_EOT) ? " eot" : ""); - } -#else - #define dump_ep_intr(x, y, z, i) do {} while (0) -#endif /* DEBUG_IRQ */ - -#ifdef DEBUG_DUMP - static void dump_usb_stat(const char *label, - struct imx_udc_struct *imx_usb) - { - int temp = __raw_readl(imx_usb->base + USB_STAT); - - dev_dbg(imx_usb->dev, - "<%s> USB_STAT=[%s%s CFG=%d, INTF=%d, ALTR=%d]\n", label, - (temp & STAT_RST) ? " reset" : "", - (temp & STAT_SUSP) ? " suspend" : "", - (temp & STAT_CFG) >> 5, - (temp & STAT_INTF) >> 3, - (temp & STAT_ALTSET)); - } - - static void dump_ep_stat(const char *label, - struct imx_ep_struct *imx_ep) - { - int temp = __raw_readl(imx_ep->imx_usb->base - + USB_EP_INTR(EP_NO(imx_ep))); - - dev_dbg(imx_ep->imx_usb->dev, - "<%s> EP%d_INTR=[%s%s%s%s%s%s%s%s%s]\n", - label, EP_NO(imx_ep), - (temp & EPINTR_FIFO_FULL) ? " full" : "", - (temp & EPINTR_FIFO_EMPTY) ? " fempty" : "", - (temp & EPINTR_FIFO_ERROR) ? " ferr" : "", - (temp & EPINTR_FIFO_HIGH) ? " fhigh" : "", - (temp & EPINTR_FIFO_LOW) ? " flow" : "", - (temp & EPINTR_MDEVREQ) ? " mreq" : "", - (temp & EPINTR_EOF) ? " eof" : "", - (temp & EPINTR_DEVREQ) ? " devreq" : "", - (temp & EPINTR_EOT) ? " eot" : ""); - - temp = __raw_readl(imx_ep->imx_usb->base - + USB_EP_STAT(EP_NO(imx_ep))); - - dev_dbg(imx_ep->imx_usb->dev, - "<%s> EP%d_STAT=[%s%s bcount=%d]\n", - label, EP_NO(imx_ep), - (temp & EPSTAT_SIP) ? " sip" : "", - (temp & EPSTAT_STALL) ? " stall" : "", - (temp & EPSTAT_BCOUNT) >> 16); - - temp = __raw_readl(imx_ep->imx_usb->base - + USB_EP_FSTAT(EP_NO(imx_ep))); - - dev_dbg(imx_ep->imx_usb->dev, - "<%s> EP%d_FSTAT=[%s%s%s%s%s%s%s]\n", - label, EP_NO(imx_ep), - (temp & FSTAT_ERR) ? " ferr" : "", - (temp & FSTAT_UF) ? " funder" : "", - (temp & FSTAT_OF) ? " fover" : "", - (temp & FSTAT_FR) ? " fready" : "", - (temp & FSTAT_FULL) ? " ffull" : "", - (temp & FSTAT_ALRM) ? " falarm" : "", - (temp & FSTAT_EMPTY) ? " fempty" : ""); - } - - static void dump_req(const char *label, struct imx_ep_struct *imx_ep, - struct usb_request *req) - { - int i; - - if (!req || !req->buf) { - dev_dbg(imx_ep->imx_usb->dev, - "<%s> req or req buf is free\n", label); - return; - } - - if ((!EP_NO(imx_ep) && imx_ep->imx_usb->ep0state - == EP0_IN_DATA_PHASE) - || (EP_NO(imx_ep) && EP_DIR(imx_ep))) { - - dev_dbg(imx_ep->imx_usb->dev, - "<%s> request dump <", label); - for (i = 0; i < req->length; i++) - printk("%02x-", *((u8 *)req->buf + i)); - printk(">\n"); - } - } - -#else - #define dump_ep_stat(x, y) do {} while (0) - #define dump_usb_stat(x, y) do {} while (0) - #define dump_req(x, y, z) do {} while (0) -#endif /* DEBUG_DUMP */ - -#ifdef DEBUG_ERR - #define D_ERR(dev, args...) dev_dbg(dev, ## args) -#else - #define D_ERR(dev, args...) do {} while (0) -#endif - -#else - #define D_REQ(dev, args...) do {} while (0) - #define D_TRX(dev, args...) do {} while (0) - #define D_INI(dev, args...) do {} while (0) - #define D_EP0(dev, args...) do {} while (0) - #define D_EPX(dev, args...) do {} while (0) - #define dump_ep_intr(x, y, z, i) do {} while (0) - #define dump_intr(x, y, z) do {} while (0) - #define dump_ep_stat(x, y) do {} while (0) - #define dump_usb_stat(x, y) do {} while (0) - #define dump_req(x, y, z) do {} while (0) - #define D_ERR(dev, args...) do {} while (0) -#endif /* DEBUG */ - -#endif /* __LINUX_USB_GADGET_IMX_H */ diff --git a/ANDROID_3.4.5/drivers/usb/gadget/inode.c b/ANDROID_3.4.5/drivers/usb/gadget/inode.c deleted file mode 100644 index e58b1644..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/inode.c +++ /dev/null @@ -1,2135 +0,0 @@ -/* - * inode.c -- user mode filesystem api for usb gadget controllers - * - * Copyright (C) 2003-2004 David Brownell - * Copyright (C) 2003 Agilent Technologies - * - * 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. - */ - - -/* #define VERBOSE_DEBUG */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - - -/* - * The gadgetfs API maps each endpoint to a file descriptor so that you - * can use standard synchronous read/write calls for I/O. There's some - * O_NONBLOCK and O_ASYNC/FASYNC style i/o support. Example usermode - * drivers show how this works in practice. You can also use AIO to - * eliminate I/O gaps between requests, to help when streaming data. - * - * Key parts that must be USB-specific are protocols defining how the - * read/write operations relate to the hardware state machines. There - * are two types of files. One type is for the device, implementing ep0. - * The other type is for each IN or OUT endpoint. In both cases, the - * user mode driver must configure the hardware before using it. - * - * - First, dev_config() is called when /dev/gadget/$CHIP is configured - * (by writing configuration and device descriptors). Afterwards it - * may serve as a source of device events, used to handle all control - * requests other than basic enumeration. - * - * - Then, after a SET_CONFIGURATION control request, ep_config() is - * called when each /dev/gadget/ep* file is configured (by writing - * endpoint descriptors). Afterwards these files are used to write() - * IN data or to read() OUT data. To halt the endpoint, a "wrong - * direction" request is issued (like reading an IN endpoint). - * - * Unlike "usbfs" the only ioctl()s are for things that are rare, and maybe - * not possible on all hardware. For example, precise fault handling with - * respect to data left in endpoint fifos after aborted operations; or - * selective clearing of endpoint halts, to implement SET_INTERFACE. - */ - -#define DRIVER_DESC "USB Gadget filesystem" -#define DRIVER_VERSION "24 Aug 2004" - -static const char driver_desc [] = DRIVER_DESC; -static const char shortname [] = "gadgetfs"; - -MODULE_DESCRIPTION (DRIVER_DESC); -MODULE_AUTHOR ("David Brownell"); -MODULE_LICENSE ("GPL"); - - -/*----------------------------------------------------------------------*/ - -#define GADGETFS_MAGIC 0xaee71ee7 -#define DMA_ADDR_INVALID (~(dma_addr_t)0) - -/* /dev/gadget/$CHIP represents ep0 and the whole device */ -enum ep0_state { - /* DISBLED is the initial state. - */ - STATE_DEV_DISABLED = 0, - - /* Only one open() of /dev/gadget/$CHIP; only one file tracks - * ep0/device i/o modes and binding to the controller. Driver - * must always write descriptors to initialize the device, then - * the device becomes UNCONNECTED until enumeration. - */ - STATE_DEV_OPENED, - - /* From then on, ep0 fd is in either of two basic modes: - * - (UN)CONNECTED: read usb_gadgetfs_event(s) from it - * - SETUP: read/write will transfer control data and succeed; - * or if "wrong direction", performs protocol stall - */ - STATE_DEV_UNCONNECTED, - STATE_DEV_CONNECTED, - STATE_DEV_SETUP, - - /* UNBOUND means the driver closed ep0, so the device won't be - * accessible again (DEV_DISABLED) until all fds are closed. - */ - STATE_DEV_UNBOUND, -}; - -/* enough for the whole queue: most events invalidate others */ -#define N_EVENT 5 - -struct dev_data { - spinlock_t lock; - atomic_t count; - enum ep0_state state; /* P: lock */ - struct usb_gadgetfs_event event [N_EVENT]; - unsigned ev_next; - struct fasync_struct *fasync; - u8 current_config; - - /* drivers reading ep0 MUST handle control requests (SETUP) - * reported that way; else the host will time out. - */ - unsigned usermode_setup : 1, - setup_in : 1, - setup_can_stall : 1, - setup_out_ready : 1, - setup_out_error : 1, - setup_abort : 1; - unsigned setup_wLength; - - /* the rest is basically write-once */ - struct usb_config_descriptor *config, *hs_config; - struct usb_device_descriptor *dev; - struct usb_request *req; - struct usb_gadget *gadget; - struct list_head epfiles; - void *buf; - wait_queue_head_t wait; - struct super_block *sb; - struct dentry *dentry; - - /* except this scratch i/o buffer for ep0 */ - u8 rbuf [256]; -}; - -static inline void get_dev (struct dev_data *data) -{ - atomic_inc (&data->count); -} - -static void put_dev (struct dev_data *data) -{ - if (likely (!atomic_dec_and_test (&data->count))) - return; - /* needs no more cleanup */ - BUG_ON (waitqueue_active (&data->wait)); - kfree (data); -} - -static struct dev_data *dev_new (void) -{ - struct dev_data *dev; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return NULL; - dev->state = STATE_DEV_DISABLED; - atomic_set (&dev->count, 1); - spin_lock_init (&dev->lock); - INIT_LIST_HEAD (&dev->epfiles); - init_waitqueue_head (&dev->wait); - return dev; -} - -/*----------------------------------------------------------------------*/ - -/* other /dev/gadget/$ENDPOINT files represent endpoints */ -enum ep_state { - STATE_EP_DISABLED = 0, - STATE_EP_READY, - STATE_EP_ENABLED, - STATE_EP_UNBOUND, -}; - -struct ep_data { - struct mutex lock; - enum ep_state state; - atomic_t count; - struct dev_data *dev; - /* must hold dev->lock before accessing ep or req */ - struct usb_ep *ep; - struct usb_request *req; - ssize_t status; - char name [16]; - struct usb_endpoint_descriptor desc, hs_desc; - struct list_head epfiles; - wait_queue_head_t wait; - struct dentry *dentry; - struct inode *inode; -}; - -static inline void get_ep (struct ep_data *data) -{ - atomic_inc (&data->count); -} - -static void put_ep (struct ep_data *data) -{ - if (likely (!atomic_dec_and_test (&data->count))) - return; - put_dev (data->dev); - /* needs no more cleanup */ - BUG_ON (!list_empty (&data->epfiles)); - BUG_ON (waitqueue_active (&data->wait)); - kfree (data); -} - -/*----------------------------------------------------------------------*/ - -/* most "how to use the hardware" policy choices are in userspace: - * mapping endpoint roles (which the driver needs) to the capabilities - * which the usb controller has. most of those capabilities are exposed - * implicitly, starting with the driver name and then endpoint names. - */ - -static const char *CHIP; - -/*----------------------------------------------------------------------*/ - -/* NOTE: don't use dev_printk calls before binding to the gadget - * at the end of ep0 configuration, or after unbind. - */ - -/* too wordy: dev_printk(level , &(d)->gadget->dev , fmt , ## args) */ -#define xprintk(d,level,fmt,args...) \ - printk(level "%s: " fmt , shortname , ## args) - -#ifdef DEBUG -#define DBG(dev,fmt,args...) \ - xprintk(dev , KERN_DEBUG , fmt , ## args) -#else -#define DBG(dev,fmt,args...) \ - do { } while (0) -#endif /* DEBUG */ - -#ifdef VERBOSE_DEBUG -#define VDEBUG DBG -#else -#define VDEBUG(dev,fmt,args...) \ - do { } while (0) -#endif /* DEBUG */ - -#define ERROR(dev,fmt,args...) \ - xprintk(dev , KERN_ERR , fmt , ## args) -#define INFO(dev,fmt,args...) \ - xprintk(dev , KERN_INFO , fmt , ## args) - - -/*----------------------------------------------------------------------*/ - -/* SYNCHRONOUS ENDPOINT OPERATIONS (bulk/intr/iso) - * - * After opening, configure non-control endpoints. Then use normal - * stream read() and write() requests; and maybe ioctl() to get more - * precise FIFO status when recovering from cancellation. - */ - -static void epio_complete (struct usb_ep *ep, struct usb_request *req) -{ - struct ep_data *epdata = ep->driver_data; - - if (!req->context) - return; - if (req->status) - epdata->status = req->status; - else - epdata->status = req->actual; - complete ((struct completion *)req->context); -} - -/* tasklock endpoint, returning when it's connected. - * still need dev->lock to use epdata->ep. - */ -static int -get_ready_ep (unsigned f_flags, struct ep_data *epdata) -{ - int val; - - if (f_flags & O_NONBLOCK) { - if (!mutex_trylock(&epdata->lock)) - goto nonblock; - if (epdata->state != STATE_EP_ENABLED) { - mutex_unlock(&epdata->lock); -nonblock: - val = -EAGAIN; - } else - val = 0; - return val; - } - - val = mutex_lock_interruptible(&epdata->lock); - if (val < 0) - return val; - - switch (epdata->state) { - case STATE_EP_ENABLED: - break; - // case STATE_EP_DISABLED: /* "can't happen" */ - // case STATE_EP_READY: /* "can't happen" */ - default: /* error! */ - pr_debug ("%s: ep %p not available, state %d\n", - shortname, epdata, epdata->state); - // FALLTHROUGH - case STATE_EP_UNBOUND: /* clean disconnect */ - val = -ENODEV; - mutex_unlock(&epdata->lock); - } - return val; -} - -static ssize_t -ep_io (struct ep_data *epdata, void *buf, unsigned len) -{ - DECLARE_COMPLETION_ONSTACK (done); - int value; - - spin_lock_irq (&epdata->dev->lock); - if (likely (epdata->ep != NULL)) { - struct usb_request *req = epdata->req; - - req->context = &done; - req->complete = epio_complete; - req->buf = buf; - req->length = len; - value = usb_ep_queue (epdata->ep, req, GFP_ATOMIC); - } else - value = -ENODEV; - spin_unlock_irq (&epdata->dev->lock); - - if (likely (value == 0)) { - value = wait_event_interruptible (done.wait, done.done); - if (value != 0) { - spin_lock_irq (&epdata->dev->lock); - if (likely (epdata->ep != NULL)) { - DBG (epdata->dev, "%s i/o interrupted\n", - epdata->name); - usb_ep_dequeue (epdata->ep, epdata->req); - spin_unlock_irq (&epdata->dev->lock); - - wait_event (done.wait, done.done); - if (epdata->status == -ECONNRESET) - epdata->status = -EINTR; - } else { - spin_unlock_irq (&epdata->dev->lock); - - DBG (epdata->dev, "endpoint gone\n"); - epdata->status = -ENODEV; - } - } - return epdata->status; - } - return value; -} - - -/* handle a synchronous OUT bulk/intr/iso transfer */ -static ssize_t -ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) -{ - struct ep_data *data = fd->private_data; - void *kbuf; - ssize_t value; - - if ((value = get_ready_ep (fd->f_flags, data)) < 0) - return value; - - /* halt any endpoint by doing a "wrong direction" i/o call */ - if (usb_endpoint_dir_in(&data->desc)) { - if (usb_endpoint_xfer_isoc(&data->desc)) { - mutex_unlock(&data->lock); - return -EINVAL; - } - DBG (data->dev, "%s halt\n", data->name); - spin_lock_irq (&data->dev->lock); - if (likely (data->ep != NULL)) - usb_ep_set_halt (data->ep); - spin_unlock_irq (&data->dev->lock); - mutex_unlock(&data->lock); - return -EBADMSG; - } - - /* FIXME readahead for O_NONBLOCK and poll(); careful with ZLPs */ - - value = -ENOMEM; - kbuf = kmalloc (len, GFP_KERNEL); - if (unlikely (!kbuf)) - goto free1; - - value = ep_io (data, kbuf, len); - VDEBUG (data->dev, "%s read %zu OUT, status %d\n", - data->name, len, (int) value); - if (value >= 0 && copy_to_user (buf, kbuf, value)) - value = -EFAULT; - -free1: - mutex_unlock(&data->lock); - kfree (kbuf); - return value; -} - -/* handle a synchronous IN bulk/intr/iso transfer */ -static ssize_t -ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) -{ - struct ep_data *data = fd->private_data; - void *kbuf; - ssize_t value; - - if ((value = get_ready_ep (fd->f_flags, data)) < 0) - return value; - - /* halt any endpoint by doing a "wrong direction" i/o call */ - if (!usb_endpoint_dir_in(&data->desc)) { - if (usb_endpoint_xfer_isoc(&data->desc)) { - mutex_unlock(&data->lock); - return -EINVAL; - } - DBG (data->dev, "%s halt\n", data->name); - spin_lock_irq (&data->dev->lock); - if (likely (data->ep != NULL)) - usb_ep_set_halt (data->ep); - spin_unlock_irq (&data->dev->lock); - mutex_unlock(&data->lock); - return -EBADMSG; - } - - /* FIXME writebehind for O_NONBLOCK and poll(), qlen = 1 */ - - value = -ENOMEM; - kbuf = kmalloc (len, GFP_KERNEL); - if (!kbuf) - goto free1; - if (copy_from_user (kbuf, buf, len)) { - value = -EFAULT; - goto free1; - } - - value = ep_io (data, kbuf, len); - VDEBUG (data->dev, "%s write %zu IN, status %d\n", - data->name, len, (int) value); -free1: - mutex_unlock(&data->lock); - kfree (kbuf); - return value; -} - -static int -ep_release (struct inode *inode, struct file *fd) -{ - struct ep_data *data = fd->private_data; - int value; - - value = mutex_lock_interruptible(&data->lock); - if (value < 0) - return value; - - /* clean up if this can be reopened */ - if (data->state != STATE_EP_UNBOUND) { - data->state = STATE_EP_DISABLED; - data->desc.bDescriptorType = 0; - data->hs_desc.bDescriptorType = 0; - usb_ep_disable(data->ep); - } - mutex_unlock(&data->lock); - put_ep (data); - return 0; -} - -static long ep_ioctl(struct file *fd, unsigned code, unsigned long value) -{ - struct ep_data *data = fd->private_data; - int status; - - if ((status = get_ready_ep (fd->f_flags, data)) < 0) - return status; - - spin_lock_irq (&data->dev->lock); - if (likely (data->ep != NULL)) { - switch (code) { - case GADGETFS_FIFO_STATUS: - status = usb_ep_fifo_status (data->ep); - break; - case GADGETFS_FIFO_FLUSH: - usb_ep_fifo_flush (data->ep); - break; - case GADGETFS_CLEAR_HALT: - status = usb_ep_clear_halt (data->ep); - break; - default: - status = -ENOTTY; - } - } else - status = -ENODEV; - spin_unlock_irq (&data->dev->lock); - mutex_unlock(&data->lock); - return status; -} - -/*----------------------------------------------------------------------*/ - -/* ASYNCHRONOUS ENDPOINT I/O OPERATIONS (bulk/intr/iso) */ - -struct kiocb_priv { - struct usb_request *req; - struct ep_data *epdata; - void *buf; - const struct iovec *iv; - unsigned long nr_segs; - unsigned actual; -}; - -static int ep_aio_cancel(struct kiocb *iocb, struct io_event *e) -{ - struct kiocb_priv *priv = iocb->private; - struct ep_data *epdata; - int value; - - local_irq_disable(); - epdata = priv->epdata; - // spin_lock(&epdata->dev->lock); - kiocbSetCancelled(iocb); - if (likely(epdata && epdata->ep && priv->req)) - value = usb_ep_dequeue (epdata->ep, priv->req); - else - value = -EINVAL; - // spin_unlock(&epdata->dev->lock); - local_irq_enable(); - - aio_put_req(iocb); - return value; -} - -static ssize_t ep_aio_read_retry(struct kiocb *iocb) -{ - struct kiocb_priv *priv = iocb->private; - ssize_t len, total; - void *to_copy; - int i; - - /* we "retry" to get the right mm context for this: */ - - /* copy stuff into user buffers */ - total = priv->actual; - len = 0; - to_copy = priv->buf; - for (i=0; i < priv->nr_segs; i++) { - ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total); - - if (copy_to_user(priv->iv[i].iov_base, to_copy, this)) { - if (len == 0) - len = -EFAULT; - break; - } - - total -= this; - len += this; - to_copy += this; - if (total == 0) - break; - } - kfree(priv->buf); - kfree(priv); - return len; -} - -static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct kiocb *iocb = req->context; - struct kiocb_priv *priv = iocb->private; - struct ep_data *epdata = priv->epdata; - - /* lock against disconnect (and ideally, cancel) */ - spin_lock(&epdata->dev->lock); - priv->req = NULL; - priv->epdata = NULL; - - /* if this was a write or a read returning no data then we - * don't need to copy anything to userspace, so we can - * complete the aio request immediately. - */ - if (priv->iv == NULL || unlikely(req->actual == 0)) { - kfree(req->buf); - kfree(priv); - iocb->private = NULL; - /* aio_complete() reports bytes-transferred _and_ faults */ - aio_complete(iocb, req->actual ? req->actual : req->status, - req->status); - } else { - /* retry() won't report both; so we hide some faults */ - if (unlikely(0 != req->status)) - DBG(epdata->dev, "%s fault %d len %d\n", - ep->name, req->status, req->actual); - - priv->buf = req->buf; - priv->actual = req->actual; - kick_iocb(iocb); - } - spin_unlock(&epdata->dev->lock); - - usb_ep_free_request(ep, req); - put_ep(epdata); -} - -static ssize_t -ep_aio_rwtail( - struct kiocb *iocb, - char *buf, - size_t len, - struct ep_data *epdata, - const struct iovec *iv, - unsigned long nr_segs -) -{ - struct kiocb_priv *priv; - struct usb_request *req; - ssize_t value; - - priv = kmalloc(sizeof *priv, GFP_KERNEL); - if (!priv) { - value = -ENOMEM; -fail: - kfree(buf); - return value; - } - iocb->private = priv; - priv->iv = iv; - priv->nr_segs = nr_segs; - - value = get_ready_ep(iocb->ki_filp->f_flags, epdata); - if (unlikely(value < 0)) { - kfree(priv); - goto fail; - } - - iocb->ki_cancel = ep_aio_cancel; - get_ep(epdata); - priv->epdata = epdata; - priv->actual = 0; - - /* each kiocb is coupled to one usb_request, but we can't - * allocate or submit those if the host disconnected. - */ - spin_lock_irq(&epdata->dev->lock); - if (likely(epdata->ep)) { - req = usb_ep_alloc_request(epdata->ep, GFP_ATOMIC); - if (likely(req)) { - priv->req = req; - req->buf = buf; - req->length = len; - req->complete = ep_aio_complete; - req->context = iocb; - value = usb_ep_queue(epdata->ep, req, GFP_ATOMIC); - if (unlikely(0 != value)) - usb_ep_free_request(epdata->ep, req); - } else - value = -EAGAIN; - } else - value = -ENODEV; - spin_unlock_irq(&epdata->dev->lock); - - mutex_unlock(&epdata->lock); - - if (unlikely(value)) { - kfree(priv); - put_ep(epdata); - } else - value = (iv ? -EIOCBRETRY : -EIOCBQUEUED); - return value; -} - -static ssize_t -ep_aio_read(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t o) -{ - struct ep_data *epdata = iocb->ki_filp->private_data; - char *buf; - - if (unlikely(usb_endpoint_dir_in(&epdata->desc))) - return -EINVAL; - - buf = kmalloc(iocb->ki_left, GFP_KERNEL); - if (unlikely(!buf)) - return -ENOMEM; - - iocb->ki_retry = ep_aio_read_retry; - return ep_aio_rwtail(iocb, buf, iocb->ki_left, epdata, iov, nr_segs); -} - -static ssize_t -ep_aio_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t o) -{ - struct ep_data *epdata = iocb->ki_filp->private_data; - char *buf; - size_t len = 0; - int i = 0; - - if (unlikely(!usb_endpoint_dir_in(&epdata->desc))) - return -EINVAL; - - buf = kmalloc(iocb->ki_left, GFP_KERNEL); - if (unlikely(!buf)) - return -ENOMEM; - - for (i=0; i < nr_segs; i++) { - if (unlikely(copy_from_user(&buf[len], iov[i].iov_base, - iov[i].iov_len) != 0)) { - kfree(buf); - return -EFAULT; - } - len += iov[i].iov_len; - } - return ep_aio_rwtail(iocb, buf, len, epdata, NULL, 0); -} - -/*----------------------------------------------------------------------*/ - -/* used after endpoint configuration */ -static const struct file_operations ep_io_operations = { - .owner = THIS_MODULE, - .llseek = no_llseek, - - .read = ep_read, - .write = ep_write, - .unlocked_ioctl = ep_ioctl, - .release = ep_release, - - .aio_read = ep_aio_read, - .aio_write = ep_aio_write, -}; - -/* ENDPOINT INITIALIZATION - * - * fd = open ("/dev/gadget/$ENDPOINT", O_RDWR) - * status = write (fd, descriptors, sizeof descriptors) - * - * That write establishes the endpoint configuration, configuring - * the controller to process bulk, interrupt, or isochronous transfers - * at the right maxpacket size, and so on. - * - * The descriptors are message type 1, identified by a host order u32 - * at the beginning of what's written. Descriptor order is: full/low - * speed descriptor, then optional high speed descriptor. - */ -static ssize_t -ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) -{ - struct ep_data *data = fd->private_data; - struct usb_ep *ep; - u32 tag; - int value, length = len; - - value = mutex_lock_interruptible(&data->lock); - if (value < 0) - return value; - - if (data->state != STATE_EP_READY) { - value = -EL2HLT; - goto fail; - } - - value = len; - if (len < USB_DT_ENDPOINT_SIZE + 4) - goto fail0; - - /* we might need to change message format someday */ - if (copy_from_user (&tag, buf, 4)) { - goto fail1; - } - if (tag != 1) { - DBG(data->dev, "config %s, bad tag %d\n", data->name, tag); - goto fail0; - } - buf += 4; - len -= 4; - - /* NOTE: audio endpoint extensions not accepted here; - * just don't include the extra bytes. - */ - - /* full/low speed descriptor, then high speed */ - if (copy_from_user (&data->desc, buf, USB_DT_ENDPOINT_SIZE)) { - goto fail1; - } - if (data->desc.bLength != USB_DT_ENDPOINT_SIZE - || data->desc.bDescriptorType != USB_DT_ENDPOINT) - goto fail0; - if (len != USB_DT_ENDPOINT_SIZE) { - if (len != 2 * USB_DT_ENDPOINT_SIZE) - goto fail0; - if (copy_from_user (&data->hs_desc, buf + USB_DT_ENDPOINT_SIZE, - USB_DT_ENDPOINT_SIZE)) { - goto fail1; - } - if (data->hs_desc.bLength != USB_DT_ENDPOINT_SIZE - || data->hs_desc.bDescriptorType - != USB_DT_ENDPOINT) { - DBG(data->dev, "config %s, bad hs length or type\n", - data->name); - goto fail0; - } - } - - spin_lock_irq (&data->dev->lock); - if (data->dev->state == STATE_DEV_UNBOUND) { - value = -ENOENT; - goto gone; - } else if ((ep = data->ep) == NULL) { - value = -ENODEV; - goto gone; - } - switch (data->dev->gadget->speed) { - case USB_SPEED_LOW: - case USB_SPEED_FULL: - ep->desc = &data->desc; - value = usb_ep_enable(ep); - if (value == 0) - data->state = STATE_EP_ENABLED; - break; -#ifdef CONFIG_USB_GADGET_DUALSPEED - case USB_SPEED_HIGH: - /* fails if caller didn't provide that descriptor... */ - ep->desc = &data->hs_desc; - value = usb_ep_enable(ep); - if (value == 0) - data->state = STATE_EP_ENABLED; - break; -#endif - default: - DBG(data->dev, "unconnected, %s init abandoned\n", - data->name); - value = -EINVAL; - } - if (value == 0) { - fd->f_op = &ep_io_operations; - value = length; - } -gone: - spin_unlock_irq (&data->dev->lock); - if (value < 0) { -fail: - data->desc.bDescriptorType = 0; - data->hs_desc.bDescriptorType = 0; - } - mutex_unlock(&data->lock); - return value; -fail0: - value = -EINVAL; - goto fail; -fail1: - value = -EFAULT; - goto fail; -} - -static int -ep_open (struct inode *inode, struct file *fd) -{ - struct ep_data *data = inode->i_private; - int value = -EBUSY; - - if (mutex_lock_interruptible(&data->lock) != 0) - return -EINTR; - spin_lock_irq (&data->dev->lock); - if (data->dev->state == STATE_DEV_UNBOUND) - value = -ENOENT; - else if (data->state == STATE_EP_DISABLED) { - value = 0; - data->state = STATE_EP_READY; - get_ep (data); - fd->private_data = data; - VDEBUG (data->dev, "%s ready\n", data->name); - } else - DBG (data->dev, "%s state %d\n", - data->name, data->state); - spin_unlock_irq (&data->dev->lock); - mutex_unlock(&data->lock); - return value; -} - -/* used before endpoint configuration */ -static const struct file_operations ep_config_operations = { - .owner = THIS_MODULE, - .llseek = no_llseek, - - .open = ep_open, - .write = ep_config, - .release = ep_release, -}; - -/*----------------------------------------------------------------------*/ - -/* EP0 IMPLEMENTATION can be partly in userspace. - * - * Drivers that use this facility receive various events, including - * control requests the kernel doesn't handle. Drivers that don't - * use this facility may be too simple-minded for real applications. - */ - -static inline void ep0_readable (struct dev_data *dev) -{ - wake_up (&dev->wait); - kill_fasync (&dev->fasync, SIGIO, POLL_IN); -} - -static void clean_req (struct usb_ep *ep, struct usb_request *req) -{ - struct dev_data *dev = ep->driver_data; - - if (req->buf != dev->rbuf) { - kfree(req->buf); - req->buf = dev->rbuf; - req->dma = DMA_ADDR_INVALID; - } - req->complete = epio_complete; - dev->setup_out_ready = 0; -} - -static void ep0_complete (struct usb_ep *ep, struct usb_request *req) -{ - struct dev_data *dev = ep->driver_data; - unsigned long flags; - int free = 1; - - /* for control OUT, data must still get to userspace */ - spin_lock_irqsave(&dev->lock, flags); - if (!dev->setup_in) { - dev->setup_out_error = (req->status != 0); - if (!dev->setup_out_error) - free = 0; - dev->setup_out_ready = 1; - ep0_readable (dev); - } - - /* clean up as appropriate */ - if (free && req->buf != &dev->rbuf) - clean_req (ep, req); - req->complete = epio_complete; - spin_unlock_irqrestore(&dev->lock, flags); -} - -static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len) -{ - struct dev_data *dev = ep->driver_data; - - if (dev->setup_out_ready) { - DBG (dev, "ep0 request busy!\n"); - return -EBUSY; - } - if (len > sizeof (dev->rbuf)) - req->buf = kmalloc(len, GFP_ATOMIC); - if (req->buf == NULL) { - req->buf = dev->rbuf; - return -ENOMEM; - } - req->complete = ep0_complete; - req->length = len; - req->zero = 0; - return 0; -} - -static ssize_t -ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) -{ - struct dev_data *dev = fd->private_data; - ssize_t retval; - enum ep0_state state; - - spin_lock_irq (&dev->lock); - - /* report fd mode change before acting on it */ - if (dev->setup_abort) { - dev->setup_abort = 0; - retval = -EIDRM; - goto done; - } - - /* control DATA stage */ - if ((state = dev->state) == STATE_DEV_SETUP) { - - if (dev->setup_in) { /* stall IN */ - VDEBUG(dev, "ep0in stall\n"); - (void) usb_ep_set_halt (dev->gadget->ep0); - retval = -EL2HLT; - dev->state = STATE_DEV_CONNECTED; - - } else if (len == 0) { /* ack SET_CONFIGURATION etc */ - struct usb_ep *ep = dev->gadget->ep0; - struct usb_request *req = dev->req; - - if ((retval = setup_req (ep, req, 0)) == 0) - retval = usb_ep_queue (ep, req, GFP_ATOMIC); - dev->state = STATE_DEV_CONNECTED; - - /* assume that was SET_CONFIGURATION */ - if (dev->current_config) { - unsigned power; - - if (gadget_is_dualspeed(dev->gadget) - && (dev->gadget->speed - == USB_SPEED_HIGH)) - power = dev->hs_config->bMaxPower; - else - power = dev->config->bMaxPower; - usb_gadget_vbus_draw(dev->gadget, 2 * power); - } - - } else { /* collect OUT data */ - if ((fd->f_flags & O_NONBLOCK) != 0 - && !dev->setup_out_ready) { - retval = -EAGAIN; - goto done; - } - spin_unlock_irq (&dev->lock); - retval = wait_event_interruptible (dev->wait, - dev->setup_out_ready != 0); - - /* FIXME state could change from under us */ - spin_lock_irq (&dev->lock); - if (retval) - goto done; - - if (dev->state != STATE_DEV_SETUP) { - retval = -ECANCELED; - goto done; - } - dev->state = STATE_DEV_CONNECTED; - - if (dev->setup_out_error) - retval = -EIO; - else { - len = min (len, (size_t)dev->req->actual); -// FIXME don't call this with the spinlock held ... - if (copy_to_user (buf, dev->req->buf, len)) - retval = -EFAULT; - else - retval = len; - clean_req (dev->gadget->ep0, dev->req); - /* NOTE userspace can't yet choose to stall */ - } - } - goto done; - } - - /* else normal: return event data */ - if (len < sizeof dev->event [0]) { - retval = -EINVAL; - goto done; - } - len -= len % sizeof (struct usb_gadgetfs_event); - dev->usermode_setup = 1; - -scan: - /* return queued events right away */ - if (dev->ev_next != 0) { - unsigned i, n; - - n = len / sizeof (struct usb_gadgetfs_event); - if (dev->ev_next < n) - n = dev->ev_next; - - /* ep0 i/o has special semantics during STATE_DEV_SETUP */ - for (i = 0; i < n; i++) { - if (dev->event [i].type == GADGETFS_SETUP) { - dev->state = STATE_DEV_SETUP; - n = i + 1; - break; - } - } - spin_unlock_irq (&dev->lock); - len = n * sizeof (struct usb_gadgetfs_event); - if (copy_to_user (buf, &dev->event, len)) - retval = -EFAULT; - else - retval = len; - if (len > 0) { - /* NOTE this doesn't guard against broken drivers; - * concurrent ep0 readers may lose events. - */ - spin_lock_irq (&dev->lock); - if (dev->ev_next > n) { - memmove(&dev->event[0], &dev->event[n], - sizeof (struct usb_gadgetfs_event) - * (dev->ev_next - n)); - } - dev->ev_next -= n; - spin_unlock_irq (&dev->lock); - } - return retval; - } - if (fd->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - goto done; - } - - switch (state) { - default: - DBG (dev, "fail %s, state %d\n", __func__, state); - retval = -ESRCH; - break; - case STATE_DEV_UNCONNECTED: - case STATE_DEV_CONNECTED: - spin_unlock_irq (&dev->lock); - DBG (dev, "%s wait\n", __func__); - - /* wait for events */ - retval = wait_event_interruptible (dev->wait, - dev->ev_next != 0); - if (retval < 0) - return retval; - spin_lock_irq (&dev->lock); - goto scan; - } - -done: - spin_unlock_irq (&dev->lock); - return retval; -} - -static struct usb_gadgetfs_event * -next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type) -{ - struct usb_gadgetfs_event *event; - unsigned i; - - switch (type) { - /* these events purge the queue */ - case GADGETFS_DISCONNECT: - if (dev->state == STATE_DEV_SETUP) - dev->setup_abort = 1; - // FALL THROUGH - case GADGETFS_CONNECT: - dev->ev_next = 0; - break; - case GADGETFS_SETUP: /* previous request timed out */ - case GADGETFS_SUSPEND: /* same effect */ - /* these events can't be repeated */ - for (i = 0; i != dev->ev_next; i++) { - if (dev->event [i].type != type) - continue; - DBG(dev, "discard old event[%d] %d\n", i, type); - dev->ev_next--; - if (i == dev->ev_next) - break; - /* indices start at zero, for simplicity */ - memmove (&dev->event [i], &dev->event [i + 1], - sizeof (struct usb_gadgetfs_event) - * (dev->ev_next - i)); - } - break; - default: - BUG (); - } - VDEBUG(dev, "event[%d] = %d\n", dev->ev_next, type); - event = &dev->event [dev->ev_next++]; - BUG_ON (dev->ev_next > N_EVENT); - memset (event, 0, sizeof *event); - event->type = type; - return event; -} - -static ssize_t -ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) -{ - struct dev_data *dev = fd->private_data; - ssize_t retval = -ESRCH; - - spin_lock_irq (&dev->lock); - - /* report fd mode change before acting on it */ - if (dev->setup_abort) { - dev->setup_abort = 0; - retval = -EIDRM; - - /* data and/or status stage for control request */ - } else if (dev->state == STATE_DEV_SETUP) { - - /* IN DATA+STATUS caller makes len <= wLength */ - if (dev->setup_in) { - retval = setup_req (dev->gadget->ep0, dev->req, len); - if (retval == 0) { - dev->state = STATE_DEV_CONNECTED; - spin_unlock_irq (&dev->lock); - if (copy_from_user (dev->req->buf, buf, len)) - retval = -EFAULT; - else { - if (len < dev->setup_wLength) - dev->req->zero = 1; - retval = usb_ep_queue ( - dev->gadget->ep0, dev->req, - GFP_KERNEL); - } - if (retval < 0) { - spin_lock_irq (&dev->lock); - clean_req (dev->gadget->ep0, dev->req); - spin_unlock_irq (&dev->lock); - } else - retval = len; - - return retval; - } - - /* can stall some OUT transfers */ - } else if (dev->setup_can_stall) { - VDEBUG(dev, "ep0out stall\n"); - (void) usb_ep_set_halt (dev->gadget->ep0); - retval = -EL2HLT; - dev->state = STATE_DEV_CONNECTED; - } else { - DBG(dev, "bogus ep0out stall!\n"); - } - } else - DBG (dev, "fail %s, state %d\n", __func__, dev->state); - - spin_unlock_irq (&dev->lock); - return retval; -} - -static int -ep0_fasync (int f, struct file *fd, int on) -{ - struct dev_data *dev = fd->private_data; - // caller must F_SETOWN before signal delivery happens - VDEBUG (dev, "%s %s\n", __func__, on ? "on" : "off"); - return fasync_helper (f, fd, on, &dev->fasync); -} - -static struct usb_gadget_driver gadgetfs_driver; - -static int -dev_release (struct inode *inode, struct file *fd) -{ - struct dev_data *dev = fd->private_data; - - /* closing ep0 === shutdown all */ - - usb_gadget_unregister_driver (&gadgetfs_driver); - - /* at this point "good" hardware has disconnected the - * device from USB; the host won't see it any more. - * alternatively, all host requests will time out. - */ - - kfree (dev->buf); - dev->buf = NULL; - put_dev (dev); - - /* other endpoints were all decoupled from this device */ - spin_lock_irq(&dev->lock); - dev->state = STATE_DEV_DISABLED; - spin_unlock_irq(&dev->lock); - return 0; -} - -static unsigned int -ep0_poll (struct file *fd, poll_table *wait) -{ - struct dev_data *dev = fd->private_data; - int mask = 0; - - poll_wait(fd, &dev->wait, wait); - - spin_lock_irq (&dev->lock); - - /* report fd mode change before acting on it */ - if (dev->setup_abort) { - dev->setup_abort = 0; - mask = POLLHUP; - goto out; - } - - if (dev->state == STATE_DEV_SETUP) { - if (dev->setup_in || dev->setup_can_stall) - mask = POLLOUT; - } else { - if (dev->ev_next != 0) - mask = POLLIN; - } -out: - spin_unlock_irq(&dev->lock); - return mask; -} - -static long dev_ioctl (struct file *fd, unsigned code, unsigned long value) -{ - struct dev_data *dev = fd->private_data; - struct usb_gadget *gadget = dev->gadget; - long ret = -ENOTTY; - - if (gadget->ops->ioctl) - ret = gadget->ops->ioctl (gadget, code, value); - - return ret; -} - -/* used after device configuration */ -static const struct file_operations ep0_io_operations = { - .owner = THIS_MODULE, - .llseek = no_llseek, - - .read = ep0_read, - .write = ep0_write, - .fasync = ep0_fasync, - .poll = ep0_poll, - .unlocked_ioctl = dev_ioctl, - .release = dev_release, -}; - -/*----------------------------------------------------------------------*/ - -/* The in-kernel gadget driver handles most ep0 issues, in particular - * enumerating the single configuration (as provided from user space). - * - * Unrecognized ep0 requests may be handled in user space. - */ - -#ifdef CONFIG_USB_GADGET_DUALSPEED -static void make_qualifier (struct dev_data *dev) -{ - struct usb_qualifier_descriptor qual; - struct usb_device_descriptor *desc; - - qual.bLength = sizeof qual; - qual.bDescriptorType = USB_DT_DEVICE_QUALIFIER; - qual.bcdUSB = cpu_to_le16 (0x0200); - - desc = dev->dev; - qual.bDeviceClass = desc->bDeviceClass; - qual.bDeviceSubClass = desc->bDeviceSubClass; - qual.bDeviceProtocol = desc->bDeviceProtocol; - - /* assumes ep0 uses the same value for both speeds ... */ - qual.bMaxPacketSize0 = dev->gadget->ep0->maxpacket; - - qual.bNumConfigurations = 1; - qual.bRESERVED = 0; - - memcpy (dev->rbuf, &qual, sizeof qual); -} -#endif - -static int -config_buf (struct dev_data *dev, u8 type, unsigned index) -{ - int len; - int hs = 0; - - /* only one configuration */ - if (index > 0) - return -EINVAL; - - if (gadget_is_dualspeed(dev->gadget)) { - hs = (dev->gadget->speed == USB_SPEED_HIGH); - if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; - } - if (hs) { - dev->req->buf = dev->hs_config; - len = le16_to_cpu(dev->hs_config->wTotalLength); - } else { - dev->req->buf = dev->config; - len = le16_to_cpu(dev->config->wTotalLength); - } - ((u8 *)dev->req->buf) [1] = type; - return len; -} - -static int -gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) -{ - struct dev_data *dev = get_gadget_data (gadget); - struct usb_request *req = dev->req; - int value = -EOPNOTSUPP; - struct usb_gadgetfs_event *event; - u16 w_value = le16_to_cpu(ctrl->wValue); - u16 w_length = le16_to_cpu(ctrl->wLength); - - spin_lock (&dev->lock); - dev->setup_abort = 0; - if (dev->state == STATE_DEV_UNCONNECTED) { - if (gadget_is_dualspeed(gadget) - && gadget->speed == USB_SPEED_HIGH - && dev->hs_config == NULL) { - spin_unlock(&dev->lock); - ERROR (dev, "no high speed config??\n"); - return -EINVAL; - } - - dev->state = STATE_DEV_CONNECTED; - - INFO (dev, "connected\n"); - event = next_event (dev, GADGETFS_CONNECT); - event->u.speed = gadget->speed; - ep0_readable (dev); - - /* host may have given up waiting for response. we can miss control - * requests handled lower down (device/endpoint status and features); - * then ep0_{read,write} will report the wrong status. controller - * driver will have aborted pending i/o. - */ - } else if (dev->state == STATE_DEV_SETUP) - dev->setup_abort = 1; - - req->buf = dev->rbuf; - req->dma = DMA_ADDR_INVALID; - req->context = NULL; - value = -EOPNOTSUPP; - switch (ctrl->bRequest) { - - case USB_REQ_GET_DESCRIPTOR: - if (ctrl->bRequestType != USB_DIR_IN) - goto unrecognized; - switch (w_value >> 8) { - - case USB_DT_DEVICE: - value = min (w_length, (u16) sizeof *dev->dev); - dev->dev->bMaxPacketSize0 = dev->gadget->ep0->maxpacket; - req->buf = dev->dev; - break; -#ifdef CONFIG_USB_GADGET_DUALSPEED - case USB_DT_DEVICE_QUALIFIER: - if (!dev->hs_config) - break; - value = min (w_length, (u16) - sizeof (struct usb_qualifier_descriptor)); - make_qualifier (dev); - break; - case USB_DT_OTHER_SPEED_CONFIG: - // FALLTHROUGH -#endif - case USB_DT_CONFIG: - value = config_buf (dev, - w_value >> 8, - w_value & 0xff); - if (value >= 0) - value = min (w_length, (u16) value); - break; - case USB_DT_STRING: - goto unrecognized; - - default: // all others are errors - break; - } - break; - - /* currently one config, two speeds */ - case USB_REQ_SET_CONFIGURATION: - if (ctrl->bRequestType != 0) - goto unrecognized; - if (0 == (u8) w_value) { - value = 0; - dev->current_config = 0; - usb_gadget_vbus_draw(gadget, 8 /* mA */ ); - // user mode expected to disable endpoints - } else { - u8 config, power; - - if (gadget_is_dualspeed(gadget) - && gadget->speed == USB_SPEED_HIGH) { - config = dev->hs_config->bConfigurationValue; - power = dev->hs_config->bMaxPower; - } else { - config = dev->config->bConfigurationValue; - power = dev->config->bMaxPower; - } - - if (config == (u8) w_value) { - value = 0; - dev->current_config = config; - usb_gadget_vbus_draw(gadget, 2 * power); - } - } - - /* report SET_CONFIGURATION like any other control request, - * except that usermode may not stall this. the next - * request mustn't be allowed start until this finishes: - * endpoints and threads set up, etc. - * - * NOTE: older PXA hardware (before PXA 255: without UDCCFR) - * has bad/racey automagic that prevents synchronizing here. - * even kernel mode drivers often miss them. - */ - if (value == 0) { - INFO (dev, "configuration #%d\n", dev->current_config); - if (dev->usermode_setup) { - dev->setup_can_stall = 0; - goto delegate; - } - } - break; - -#ifndef CONFIG_USB_GADGET_PXA25X - /* PXA automagically handles this request too */ - case USB_REQ_GET_CONFIGURATION: - if (ctrl->bRequestType != 0x80) - goto unrecognized; - *(u8 *)req->buf = dev->current_config; - value = min (w_length, (u16) 1); - break; -#endif - - default: -unrecognized: - VDEBUG (dev, "%s req%02x.%02x v%04x i%04x l%d\n", - dev->usermode_setup ? "delegate" : "fail", - ctrl->bRequestType, ctrl->bRequest, - w_value, le16_to_cpu(ctrl->wIndex), w_length); - - /* if there's an ep0 reader, don't stall */ - if (dev->usermode_setup) { - dev->setup_can_stall = 1; -delegate: - dev->setup_in = (ctrl->bRequestType & USB_DIR_IN) - ? 1 : 0; - dev->setup_wLength = w_length; - dev->setup_out_ready = 0; - dev->setup_out_error = 0; - value = 0; - - /* read DATA stage for OUT right away */ - if (unlikely (!dev->setup_in && w_length)) { - value = setup_req (gadget->ep0, dev->req, - w_length); - if (value < 0) - break; - value = usb_ep_queue (gadget->ep0, dev->req, - GFP_ATOMIC); - if (value < 0) { - clean_req (gadget->ep0, dev->req); - break; - } - - /* we can't currently stall these */ - dev->setup_can_stall = 0; - } - - /* state changes when reader collects event */ - event = next_event (dev, GADGETFS_SETUP); - event->u.setup = *ctrl; - ep0_readable (dev); - spin_unlock (&dev->lock); - return 0; - } - } - - /* proceed with data transfer and status phases? */ - if (value >= 0 && dev->state != STATE_DEV_SETUP) { - req->length = value; - req->zero = value < w_length; - value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC); - if (value < 0) { - DBG (dev, "ep_queue --> %d\n", value); - req->status = 0; - } - } - - /* device stalls when value < 0 */ - spin_unlock (&dev->lock); - return value; -} - -static void destroy_ep_files (struct dev_data *dev) -{ - DBG (dev, "%s %d\n", __func__, dev->state); - - /* dev->state must prevent interference */ - spin_lock_irq (&dev->lock); - while (!list_empty(&dev->epfiles)) { - struct ep_data *ep; - struct inode *parent; - struct dentry *dentry; - - /* break link to FS */ - ep = list_first_entry (&dev->epfiles, struct ep_data, epfiles); - list_del_init (&ep->epfiles); - dentry = ep->dentry; - ep->dentry = NULL; - parent = dentry->d_parent->d_inode; - - /* break link to controller */ - if (ep->state == STATE_EP_ENABLED) - (void) usb_ep_disable (ep->ep); - ep->state = STATE_EP_UNBOUND; - usb_ep_free_request (ep->ep, ep->req); - ep->ep = NULL; - wake_up (&ep->wait); - put_ep (ep); - - spin_unlock_irq (&dev->lock); - - /* break link to dcache */ - mutex_lock (&parent->i_mutex); - d_delete (dentry); - dput (dentry); - mutex_unlock (&parent->i_mutex); - - spin_lock_irq (&dev->lock); - } - spin_unlock_irq (&dev->lock); -} - - -static struct inode * -gadgetfs_create_file (struct super_block *sb, char const *name, - void *data, const struct file_operations *fops, - struct dentry **dentry_p); - -static int activate_ep_files (struct dev_data *dev) -{ - struct usb_ep *ep; - struct ep_data *data; - - gadget_for_each_ep (ep, dev->gadget) { - - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) - goto enomem0; - data->state = STATE_EP_DISABLED; - mutex_init(&data->lock); - init_waitqueue_head (&data->wait); - - strncpy (data->name, ep->name, sizeof (data->name) - 1); - atomic_set (&data->count, 1); - data->dev = dev; - get_dev (dev); - - data->ep = ep; - ep->driver_data = data; - - data->req = usb_ep_alloc_request (ep, GFP_KERNEL); - if (!data->req) - goto enomem1; - - data->inode = gadgetfs_create_file (dev->sb, data->name, - data, &ep_config_operations, - &data->dentry); - if (!data->inode) - goto enomem2; - list_add_tail (&data->epfiles, &dev->epfiles); - } - return 0; - -enomem2: - usb_ep_free_request (ep, data->req); -enomem1: - put_dev (dev); - kfree (data); -enomem0: - DBG (dev, "%s enomem\n", __func__); - destroy_ep_files (dev); - return -ENOMEM; -} - -static void -gadgetfs_unbind (struct usb_gadget *gadget) -{ - struct dev_data *dev = get_gadget_data (gadget); - - DBG (dev, "%s\n", __func__); - - spin_lock_irq (&dev->lock); - dev->state = STATE_DEV_UNBOUND; - spin_unlock_irq (&dev->lock); - - destroy_ep_files (dev); - gadget->ep0->driver_data = NULL; - set_gadget_data (gadget, NULL); - - /* we've already been disconnected ... no i/o is active */ - if (dev->req) - usb_ep_free_request (gadget->ep0, dev->req); - DBG (dev, "%s done\n", __func__); - put_dev (dev); -} - -static struct dev_data *the_device; - -static int -gadgetfs_bind (struct usb_gadget *gadget) -{ - struct dev_data *dev = the_device; - - if (!dev) - return -ESRCH; - if (0 != strcmp (CHIP, gadget->name)) { - pr_err("%s expected %s controller not %s\n", - shortname, CHIP, gadget->name); - return -ENODEV; - } - - set_gadget_data (gadget, dev); - dev->gadget = gadget; - gadget->ep0->driver_data = dev; - - /* preallocate control response and buffer */ - dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL); - if (!dev->req) - goto enomem; - dev->req->context = NULL; - dev->req->complete = epio_complete; - - if (activate_ep_files (dev) < 0) - goto enomem; - - INFO (dev, "bound to %s driver\n", gadget->name); - spin_lock_irq(&dev->lock); - dev->state = STATE_DEV_UNCONNECTED; - spin_unlock_irq(&dev->lock); - get_dev (dev); - return 0; - -enomem: - gadgetfs_unbind (gadget); - return -ENOMEM; -} - -static void -gadgetfs_disconnect (struct usb_gadget *gadget) -{ - struct dev_data *dev = get_gadget_data (gadget); - unsigned long flags; - - spin_lock_irqsave (&dev->lock, flags); - if (dev->state == STATE_DEV_UNCONNECTED) - goto exit; - dev->state = STATE_DEV_UNCONNECTED; - - INFO (dev, "disconnected\n"); - next_event (dev, GADGETFS_DISCONNECT); - ep0_readable (dev); -exit: - spin_unlock_irqrestore (&dev->lock, flags); -} - -static void -gadgetfs_suspend (struct usb_gadget *gadget) -{ - struct dev_data *dev = get_gadget_data (gadget); - - INFO (dev, "suspended from state %d\n", dev->state); - spin_lock (&dev->lock); - switch (dev->state) { - case STATE_DEV_SETUP: // VERY odd... host died?? - case STATE_DEV_CONNECTED: - case STATE_DEV_UNCONNECTED: - next_event (dev, GADGETFS_SUSPEND); - ep0_readable (dev); - /* FALLTHROUGH */ - default: - break; - } - spin_unlock (&dev->lock); -} - -static struct usb_gadget_driver gadgetfs_driver = { -#ifdef CONFIG_USB_GADGET_DUALSPEED - .max_speed = USB_SPEED_HIGH, -#else - .max_speed = USB_SPEED_FULL, -#endif - .function = (char *) driver_desc, - .unbind = gadgetfs_unbind, - .setup = gadgetfs_setup, - .disconnect = gadgetfs_disconnect, - .suspend = gadgetfs_suspend, - - .driver = { - .name = (char *) shortname, - }, -}; - -/*----------------------------------------------------------------------*/ - -static void gadgetfs_nop(struct usb_gadget *arg) { } - -static int gadgetfs_probe (struct usb_gadget *gadget) -{ - CHIP = gadget->name; - return -EISNAM; -} - -static struct usb_gadget_driver probe_driver = { - .max_speed = USB_SPEED_HIGH, - .unbind = gadgetfs_nop, - .setup = (void *)gadgetfs_nop, - .disconnect = gadgetfs_nop, - .driver = { - .name = "nop", - }, -}; - - -/* DEVICE INITIALIZATION - * - * fd = open ("/dev/gadget/$CHIP", O_RDWR) - * status = write (fd, descriptors, sizeof descriptors) - * - * That write establishes the device configuration, so the kernel can - * bind to the controller ... guaranteeing it can handle enumeration - * at all necessary speeds. Descriptor order is: - * - * . message tag (u32, host order) ... for now, must be zero; it - * would change to support features like multi-config devices - * . full/low speed config ... all wTotalLength bytes (with interface, - * class, altsetting, endpoint, and other descriptors) - * . high speed config ... all descriptors, for high speed operation; - * this one's optional except for high-speed hardware - * . device descriptor - * - * Endpoints are not yet enabled. Drivers must wait until device - * configuration and interface altsetting changes create - * the need to configure (or unconfigure) them. - * - * After initialization, the device stays active for as long as that - * $CHIP file is open. Events must then be read from that descriptor, - * such as configuration notifications. - */ - -static int is_valid_config (struct usb_config_descriptor *config) -{ - return config->bDescriptorType == USB_DT_CONFIG - && config->bLength == USB_DT_CONFIG_SIZE - && config->bConfigurationValue != 0 - && (config->bmAttributes & USB_CONFIG_ATT_ONE) != 0 - && (config->bmAttributes & USB_CONFIG_ATT_WAKEUP) == 0; - /* FIXME if gadget->is_otg, _must_ include an otg descriptor */ - /* FIXME check lengths: walk to end */ -} - -static ssize_t -dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) -{ - struct dev_data *dev = fd->private_data; - ssize_t value = len, length = len; - unsigned total; - u32 tag; - char *kbuf; - - if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4)) - return -EINVAL; - - /* we might need to change message format someday */ - if (copy_from_user (&tag, buf, 4)) - return -EFAULT; - if (tag != 0) - return -EINVAL; - buf += 4; - length -= 4; - - kbuf = memdup_user(buf, length); - if (IS_ERR(kbuf)) - return PTR_ERR(kbuf); - - spin_lock_irq (&dev->lock); - value = -EINVAL; - if (dev->buf) - goto fail; - dev->buf = kbuf; - - /* full or low speed config */ - dev->config = (void *) kbuf; - total = le16_to_cpu(dev->config->wTotalLength); - if (!is_valid_config (dev->config) || total >= length) - goto fail; - kbuf += total; - length -= total; - - /* optional high speed config */ - if (kbuf [1] == USB_DT_CONFIG) { - dev->hs_config = (void *) kbuf; - total = le16_to_cpu(dev->hs_config->wTotalLength); - if (!is_valid_config (dev->hs_config) || total >= length) - goto fail; - kbuf += total; - length -= total; - } - - /* could support multiple configs, using another encoding! */ - - /* device descriptor (tweaked for paranoia) */ - if (length != USB_DT_DEVICE_SIZE) - goto fail; - dev->dev = (void *)kbuf; - if (dev->dev->bLength != USB_DT_DEVICE_SIZE - || dev->dev->bDescriptorType != USB_DT_DEVICE - || dev->dev->bNumConfigurations != 1) - goto fail; - dev->dev->bNumConfigurations = 1; - dev->dev->bcdUSB = cpu_to_le16 (0x0200); - - /* triggers gadgetfs_bind(); then we can enumerate. */ - spin_unlock_irq (&dev->lock); - value = usb_gadget_probe_driver(&gadgetfs_driver, gadgetfs_bind); - if (value != 0) { - kfree (dev->buf); - dev->buf = NULL; - } else { - /* at this point "good" hardware has for the first time - * let the USB the host see us. alternatively, if users - * unplug/replug that will clear all the error state. - * - * note: everything running before here was guaranteed - * to choke driver model style diagnostics. from here - * on, they can work ... except in cleanup paths that - * kick in after the ep0 descriptor is closed. - */ - fd->f_op = &ep0_io_operations; - value = len; - } - return value; - -fail: - spin_unlock_irq (&dev->lock); - pr_debug ("%s: %s fail %Zd, %p\n", shortname, __func__, value, dev); - kfree (dev->buf); - dev->buf = NULL; - return value; -} - -static int -dev_open (struct inode *inode, struct file *fd) -{ - struct dev_data *dev = inode->i_private; - int value = -EBUSY; - - spin_lock_irq(&dev->lock); - if (dev->state == STATE_DEV_DISABLED) { - dev->ev_next = 0; - dev->state = STATE_DEV_OPENED; - fd->private_data = dev; - get_dev (dev); - value = 0; - } - spin_unlock_irq(&dev->lock); - return value; -} - -static const struct file_operations dev_init_operations = { - .owner = THIS_MODULE, - .llseek = no_llseek, - - .open = dev_open, - .write = dev_config, - .fasync = ep0_fasync, - .unlocked_ioctl = dev_ioctl, - .release = dev_release, -}; - -/*----------------------------------------------------------------------*/ - -/* FILESYSTEM AND SUPERBLOCK OPERATIONS - * - * Mounting the filesystem creates a controller file, used first for - * device configuration then later for event monitoring. - */ - - -/* FIXME PAM etc could set this security policy without mount options - * if epfiles inherited ownership and permissons from ep0 ... - */ - -static unsigned default_uid; -static unsigned default_gid; -static unsigned default_perm = S_IRUSR | S_IWUSR; - -module_param (default_uid, uint, 0644); -module_param (default_gid, uint, 0644); -module_param (default_perm, uint, 0644); - - -static struct inode * -gadgetfs_make_inode (struct super_block *sb, - void *data, const struct file_operations *fops, - int mode) -{ - struct inode *inode = new_inode (sb); - - if (inode) { - inode->i_ino = get_next_ino(); - inode->i_mode = mode; - inode->i_uid = default_uid; - inode->i_gid = default_gid; - inode->i_atime = inode->i_mtime = inode->i_ctime - = CURRENT_TIME; - inode->i_private = data; - inode->i_fop = fops; - } - return inode; -} - -/* creates in fs root directory, so non-renamable and non-linkable. - * so inode and dentry are paired, until device reconfig. - */ -static struct inode * -gadgetfs_create_file (struct super_block *sb, char const *name, - void *data, const struct file_operations *fops, - struct dentry **dentry_p) -{ - struct dentry *dentry; - struct inode *inode; - - dentry = d_alloc_name(sb->s_root, name); - if (!dentry) - return NULL; - - inode = gadgetfs_make_inode (sb, data, fops, - S_IFREG | (default_perm & S_IRWXUGO)); - if (!inode) { - dput(dentry); - return NULL; - } - d_add (dentry, inode); - *dentry_p = dentry; - return inode; -} - -static const struct super_operations gadget_fs_operations = { - .statfs = simple_statfs, - .drop_inode = generic_delete_inode, -}; - -static int -gadgetfs_fill_super (struct super_block *sb, void *opts, int silent) -{ - struct inode *inode; - struct dev_data *dev; - - if (the_device) - return -ESRCH; - - /* fake probe to determine $CHIP */ - (void) usb_gadget_probe_driver(&probe_driver, gadgetfs_probe); - if (!CHIP) - return -ENODEV; - - /* superblock */ - sb->s_blocksize = PAGE_CACHE_SIZE; - sb->s_blocksize_bits = PAGE_CACHE_SHIFT; - sb->s_magic = GADGETFS_MAGIC; - sb->s_op = &gadget_fs_operations; - sb->s_time_gran = 1; - - /* root inode */ - inode = gadgetfs_make_inode (sb, - NULL, &simple_dir_operations, - S_IFDIR | S_IRUGO | S_IXUGO); - if (!inode) - goto Enomem; - inode->i_op = &simple_dir_inode_operations; - if (!(sb->s_root = d_make_root (inode))) - goto Enomem; - - /* the ep0 file is named after the controller we expect; - * user mode code can use it for sanity checks, like we do. - */ - dev = dev_new (); - if (!dev) - goto Enomem; - - dev->sb = sb; - if (!gadgetfs_create_file (sb, CHIP, - dev, &dev_init_operations, - &dev->dentry)) { - put_dev(dev); - goto Enomem; - } - - /* other endpoint files are available after hardware setup, - * from binding to a controller. - */ - the_device = dev; - return 0; - -Enomem: - return -ENOMEM; -} - -/* "mount -t gadgetfs path /dev/gadget" ends up here */ -static struct dentry * -gadgetfs_mount (struct file_system_type *t, int flags, - const char *path, void *opts) -{ - return mount_single (t, flags, opts, gadgetfs_fill_super); -} - -static void -gadgetfs_kill_sb (struct super_block *sb) -{ - kill_litter_super (sb); - if (the_device) { - put_dev (the_device); - the_device = NULL; - } -} - -/*----------------------------------------------------------------------*/ - -static struct file_system_type gadgetfs_type = { - .owner = THIS_MODULE, - .name = shortname, - .mount = gadgetfs_mount, - .kill_sb = gadgetfs_kill_sb, -}; - -/*----------------------------------------------------------------------*/ - -static int __init init (void) -{ - int status; - - status = register_filesystem (&gadgetfs_type); - if (status == 0) - pr_info ("%s: %s, version " DRIVER_VERSION "\n", - shortname, driver_desc); - return status; -} -module_init (init); - -static void __exit cleanup (void) -{ - pr_debug ("unregister %s\n", shortname); - unregister_filesystem (&gadgetfs_type); -} -module_exit (cleanup); - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/langwell_udc.c b/ANDROID_3.4.5/drivers/usb/gadget/langwell_udc.c deleted file mode 100644 index f9cedd52..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/langwell_udc.c +++ /dev/null @@ -1,3434 +0,0 @@ -/* - * 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. - */ - - -/* #undef DEBUG */ -/* #undef VERBOSE_DEBUG */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "langwell_udc.h" - - -#define DRIVER_DESC "Intel Langwell USB Device Controller driver" -#define DRIVER_VERSION "16 May 2009" - -static const char driver_name[] = "langwell_udc"; -static const char driver_desc[] = DRIVER_DESC; - - -/* for endpoint 0 operations */ -static const struct usb_endpoint_descriptor -langwell_ep0_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 0, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, - .wMaxPacketSize = EP0_MAX_PKT_SIZE, -}; - - -/*-------------------------------------------------------------------------*/ -/* debugging */ - -#ifdef VERBOSE_DEBUG -static inline void print_all_registers(struct langwell_udc *dev) -{ - int i; - - /* Capability Registers */ - dev_dbg(&dev->pdev->dev, - "Capability Registers (offset: 0x%04x, length: 0x%08x)\n", - CAP_REG_OFFSET, (u32)sizeof(struct langwell_cap_regs)); - dev_dbg(&dev->pdev->dev, "caplength=0x%02x\n", - readb(&dev->cap_regs->caplength)); - dev_dbg(&dev->pdev->dev, "hciversion=0x%04x\n", - readw(&dev->cap_regs->hciversion)); - dev_dbg(&dev->pdev->dev, "hcsparams=0x%08x\n", - readl(&dev->cap_regs->hcsparams)); - dev_dbg(&dev->pdev->dev, "hccparams=0x%08x\n", - readl(&dev->cap_regs->hccparams)); - dev_dbg(&dev->pdev->dev, "dciversion=0x%04x\n", - readw(&dev->cap_regs->dciversion)); - dev_dbg(&dev->pdev->dev, "dccparams=0x%08x\n", - readl(&dev->cap_regs->dccparams)); - - /* Operational Registers */ - dev_dbg(&dev->pdev->dev, - "Operational Registers (offset: 0x%04x, length: 0x%08x)\n", - OP_REG_OFFSET, (u32)sizeof(struct langwell_op_regs)); - dev_dbg(&dev->pdev->dev, "extsts=0x%08x\n", - readl(&dev->op_regs->extsts)); - dev_dbg(&dev->pdev->dev, "extintr=0x%08x\n", - readl(&dev->op_regs->extintr)); - dev_dbg(&dev->pdev->dev, "usbcmd=0x%08x\n", - readl(&dev->op_regs->usbcmd)); - dev_dbg(&dev->pdev->dev, "usbsts=0x%08x\n", - readl(&dev->op_regs->usbsts)); - dev_dbg(&dev->pdev->dev, "usbintr=0x%08x\n", - readl(&dev->op_regs->usbintr)); - dev_dbg(&dev->pdev->dev, "frindex=0x%08x\n", - readl(&dev->op_regs->frindex)); - dev_dbg(&dev->pdev->dev, "ctrldssegment=0x%08x\n", - readl(&dev->op_regs->ctrldssegment)); - dev_dbg(&dev->pdev->dev, "deviceaddr=0x%08x\n", - readl(&dev->op_regs->deviceaddr)); - dev_dbg(&dev->pdev->dev, "endpointlistaddr=0x%08x\n", - readl(&dev->op_regs->endpointlistaddr)); - dev_dbg(&dev->pdev->dev, "ttctrl=0x%08x\n", - readl(&dev->op_regs->ttctrl)); - dev_dbg(&dev->pdev->dev, "burstsize=0x%08x\n", - readl(&dev->op_regs->burstsize)); - dev_dbg(&dev->pdev->dev, "txfilltuning=0x%08x\n", - readl(&dev->op_regs->txfilltuning)); - dev_dbg(&dev->pdev->dev, "txttfilltuning=0x%08x\n", - readl(&dev->op_regs->txttfilltuning)); - dev_dbg(&dev->pdev->dev, "ic_usb=0x%08x\n", - readl(&dev->op_regs->ic_usb)); - dev_dbg(&dev->pdev->dev, "ulpi_viewport=0x%08x\n", - readl(&dev->op_regs->ulpi_viewport)); - dev_dbg(&dev->pdev->dev, "configflag=0x%08x\n", - readl(&dev->op_regs->configflag)); - dev_dbg(&dev->pdev->dev, "portsc1=0x%08x\n", - readl(&dev->op_regs->portsc1)); - dev_dbg(&dev->pdev->dev, "devlc=0x%08x\n", - readl(&dev->op_regs->devlc)); - dev_dbg(&dev->pdev->dev, "otgsc=0x%08x\n", - readl(&dev->op_regs->otgsc)); - dev_dbg(&dev->pdev->dev, "usbmode=0x%08x\n", - readl(&dev->op_regs->usbmode)); - dev_dbg(&dev->pdev->dev, "endptnak=0x%08x\n", - readl(&dev->op_regs->endptnak)); - dev_dbg(&dev->pdev->dev, "endptnaken=0x%08x\n", - readl(&dev->op_regs->endptnaken)); - dev_dbg(&dev->pdev->dev, "endptsetupstat=0x%08x\n", - readl(&dev->op_regs->endptsetupstat)); - dev_dbg(&dev->pdev->dev, "endptprime=0x%08x\n", - readl(&dev->op_regs->endptprime)); - dev_dbg(&dev->pdev->dev, "endptflush=0x%08x\n", - readl(&dev->op_regs->endptflush)); - dev_dbg(&dev->pdev->dev, "endptstat=0x%08x\n", - readl(&dev->op_regs->endptstat)); - dev_dbg(&dev->pdev->dev, "endptcomplete=0x%08x\n", - readl(&dev->op_regs->endptcomplete)); - - for (i = 0; i < dev->ep_max / 2; i++) { - dev_dbg(&dev->pdev->dev, "endptctrl[%d]=0x%08x\n", - i, readl(&dev->op_regs->endptctrl[i])); - } -} -#else - -#define print_all_registers(dev) do { } while (0) - -#endif /* VERBOSE_DEBUG */ - - -/*-------------------------------------------------------------------------*/ - -#define is_in(ep) (((ep)->ep_num == 0) ? ((ep)->dev->ep0_dir == \ - USB_DIR_IN) : (usb_endpoint_dir_in((ep)->desc))) - -#define DIR_STRING(ep) (is_in(ep) ? "in" : "out") - - -static char *type_string(const struct usb_endpoint_descriptor *desc) -{ - switch (usb_endpoint_type(desc)) { - case USB_ENDPOINT_XFER_BULK: - return "bulk"; - case USB_ENDPOINT_XFER_ISOC: - return "iso"; - case USB_ENDPOINT_XFER_INT: - return "int"; - }; - - return "control"; -} - - -/* configure endpoint control registers */ -static void ep_reset(struct langwell_ep *ep, unsigned char ep_num, - unsigned char is_in, unsigned char ep_type) -{ - struct langwell_udc *dev; - u32 endptctrl; - - dev = ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - endptctrl = readl(&dev->op_regs->endptctrl[ep_num]); - if (is_in) { /* TX */ - if (ep_num) - endptctrl |= EPCTRL_TXR; - endptctrl |= EPCTRL_TXE; - endptctrl |= ep_type << EPCTRL_TXT_SHIFT; - } else { /* RX */ - if (ep_num) - endptctrl |= EPCTRL_RXR; - endptctrl |= EPCTRL_RXE; - endptctrl |= ep_type << EPCTRL_RXT_SHIFT; - } - - writel(endptctrl, &dev->op_regs->endptctrl[ep_num]); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* reset ep0 dQH and endptctrl */ -static void ep0_reset(struct langwell_udc *dev) -{ - struct langwell_ep *ep; - int i; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* ep0 in and out */ - for (i = 0; i < 2; i++) { - ep = &dev->ep[i]; - ep->dev = dev; - - /* ep0 dQH */ - ep->dqh = &dev->ep_dqh[i]; - - /* configure ep0 endpoint capabilities in dQH */ - ep->dqh->dqh_ios = 1; - ep->dqh->dqh_mpl = EP0_MAX_PKT_SIZE; - - /* enable ep0-in HW zero length termination select */ - if (is_in(ep)) - ep->dqh->dqh_zlt = 0; - ep->dqh->dqh_mult = 0; - - ep->dqh->dtd_next = DTD_TERM; - - /* configure ep0 control registers */ - ep_reset(&dev->ep[0], 0, i, USB_ENDPOINT_XFER_CONTROL); - } - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/*-------------------------------------------------------------------------*/ - -/* endpoints operations */ - -/* configure endpoint, making it usable */ -static int langwell_ep_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct langwell_udc *dev; - struct langwell_ep *ep; - u16 max = 0; - unsigned long flags; - int i, retval = 0; - unsigned char zlt, ios = 0, mult = 0; - - ep = container_of(_ep, struct langwell_ep, ep); - dev = ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (!_ep || !desc || ep->desc - || desc->bDescriptorType != USB_DT_ENDPOINT) - return -EINVAL; - - if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - max = usb_endpoint_maxp(desc); - - /* - * disable HW zero length termination select - * driver handles zero length packet through req->req.zero - */ - zlt = 1; - - /* - * sanity check type, direction, address, and then - * initialize the endpoint capabilities fields in dQH - */ - switch (usb_endpoint_type(desc)) { - case USB_ENDPOINT_XFER_CONTROL: - ios = 1; - break; - case USB_ENDPOINT_XFER_BULK: - if ((dev->gadget.speed == USB_SPEED_HIGH - && max != 512) - || (dev->gadget.speed == USB_SPEED_FULL - && max > 64)) { - goto done; - } - break; - case USB_ENDPOINT_XFER_INT: - if (strstr(ep->ep.name, "-iso")) /* bulk is ok */ - goto done; - - switch (dev->gadget.speed) { - case USB_SPEED_HIGH: - if (max <= 1024) - break; - case USB_SPEED_FULL: - if (max <= 64) - break; - default: - if (max <= 8) - break; - goto done; - } - break; - case USB_ENDPOINT_XFER_ISOC: - if (strstr(ep->ep.name, "-bulk") - || strstr(ep->ep.name, "-int")) - goto done; - - switch (dev->gadget.speed) { - case USB_SPEED_HIGH: - if (max <= 1024) - break; - case USB_SPEED_FULL: - if (max <= 1023) - break; - default: - goto done; - } - /* - * FIXME: - * calculate transactions needed for high bandwidth iso - */ - mult = (unsigned char)(1 + ((max >> 11) & 0x03)); - max = max & 0x8ff; /* bit 0~10 */ - /* 3 transactions at most */ - if (mult > 3) - goto done; - break; - default: - goto done; - } - - spin_lock_irqsave(&dev->lock, flags); - - ep->ep.maxpacket = max; - ep->desc = desc; - ep->stopped = 0; - ep->ep_num = usb_endpoint_num(desc); - - /* ep_type */ - ep->ep_type = usb_endpoint_type(desc); - - /* configure endpoint control registers */ - ep_reset(ep, ep->ep_num, is_in(ep), ep->ep_type); - - /* configure endpoint capabilities in dQH */ - i = ep->ep_num * 2 + is_in(ep); - ep->dqh = &dev->ep_dqh[i]; - ep->dqh->dqh_ios = ios; - ep->dqh->dqh_mpl = cpu_to_le16(max); - ep->dqh->dqh_zlt = zlt; - ep->dqh->dqh_mult = mult; - ep->dqh->dtd_next = DTD_TERM; - - dev_dbg(&dev->pdev->dev, "enabled %s (ep%d%s-%s), max %04x\n", - _ep->name, - ep->ep_num, - DIR_STRING(ep), - type_string(desc), - max); - - spin_unlock_irqrestore(&dev->lock, flags); -done: - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return retval; -} - - -/*-------------------------------------------------------------------------*/ - -/* retire a request */ -static void done(struct langwell_ep *ep, struct langwell_request *req, - int status) -{ - struct langwell_udc *dev = ep->dev; - unsigned stopped = ep->stopped; - struct langwell_dtd *curr_dtd, *next_dtd; - int i; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* remove the req from ep->queue */ - list_del_init(&req->queue); - - if (req->req.status == -EINPROGRESS) - req->req.status = status; - else - status = req->req.status; - - /* free dTD for the request */ - next_dtd = req->head; - for (i = 0; i < req->dtd_count; i++) { - curr_dtd = next_dtd; - if (i != req->dtd_count - 1) - next_dtd = curr_dtd->next_dtd_virt; - dma_pool_free(dev->dtd_pool, curr_dtd, curr_dtd->dtd_dma); - } - - usb_gadget_unmap_request(&dev->gadget, &req->req, is_in(ep)); - - if (status != -ESHUTDOWN) - dev_dbg(&dev->pdev->dev, - "complete %s, req %p, stat %d, len %u/%u\n", - ep->ep.name, &req->req, status, - req->req.actual, req->req.length); - - /* don't modify queue heads during completion callback */ - ep->stopped = 1; - - spin_unlock(&dev->lock); - /* complete routine from gadget driver */ - if (req->req.complete) - req->req.complete(&ep->ep, &req->req); - - spin_lock(&dev->lock); - ep->stopped = stopped; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -static void langwell_ep_fifo_flush(struct usb_ep *_ep); - -/* delete all endpoint requests, called with spinlock held */ -static void nuke(struct langwell_ep *ep, int status) -{ - /* called with spinlock held */ - ep->stopped = 1; - - /* endpoint fifo flush */ - if (&ep->ep && ep->desc) - langwell_ep_fifo_flush(&ep->ep); - - while (!list_empty(&ep->queue)) { - struct langwell_request *req = NULL; - req = list_entry(ep->queue.next, struct langwell_request, - queue); - done(ep, req, status); - } -} - - -/*-------------------------------------------------------------------------*/ - -/* endpoint is no longer usable */ -static int langwell_ep_disable(struct usb_ep *_ep) -{ - struct langwell_ep *ep; - unsigned long flags; - struct langwell_udc *dev; - int ep_num; - u32 endptctrl; - - ep = container_of(_ep, struct langwell_ep, ep); - dev = ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (!_ep || !ep->desc) - return -EINVAL; - - spin_lock_irqsave(&dev->lock, flags); - - /* disable endpoint control register */ - ep_num = ep->ep_num; - endptctrl = readl(&dev->op_regs->endptctrl[ep_num]); - if (is_in(ep)) - endptctrl &= ~EPCTRL_TXE; - else - endptctrl &= ~EPCTRL_RXE; - writel(endptctrl, &dev->op_regs->endptctrl[ep_num]); - - /* nuke all pending requests (does flush) */ - nuke(ep, -ESHUTDOWN); - - ep->desc = NULL; - ep->ep.desc = NULL; - ep->stopped = 1; - - spin_unlock_irqrestore(&dev->lock, flags); - - dev_dbg(&dev->pdev->dev, "disabled %s\n", _ep->name); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - - return 0; -} - - -/* allocate a request object to use with this endpoint */ -static struct usb_request *langwell_alloc_request(struct usb_ep *_ep, - gfp_t gfp_flags) -{ - struct langwell_ep *ep; - struct langwell_udc *dev; - struct langwell_request *req = NULL; - - if (!_ep) - return NULL; - - ep = container_of(_ep, struct langwell_ep, ep); - dev = ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - req = kzalloc(sizeof(*req), gfp_flags); - if (!req) - return NULL; - - req->req.dma = DMA_ADDR_INVALID; - INIT_LIST_HEAD(&req->queue); - - dev_vdbg(&dev->pdev->dev, "alloc request for %s\n", _ep->name); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return &req->req; -} - - -/* free a request object */ -static void langwell_free_request(struct usb_ep *_ep, - struct usb_request *_req) -{ - struct langwell_ep *ep; - struct langwell_udc *dev; - struct langwell_request *req = NULL; - - ep = container_of(_ep, struct langwell_ep, ep); - dev = ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (!_ep || !_req) - return; - - req = container_of(_req, struct langwell_request, req); - WARN_ON(!list_empty(&req->queue)); - - if (_req) - kfree(req); - - dev_vdbg(&dev->pdev->dev, "free request for %s\n", _ep->name); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/*-------------------------------------------------------------------------*/ - -/* queue dTD and PRIME endpoint */ -static int queue_dtd(struct langwell_ep *ep, struct langwell_request *req) -{ - u32 bit_mask, usbcmd, endptstat, dtd_dma; - u8 dtd_status; - int i; - struct langwell_dqh *dqh; - struct langwell_udc *dev; - - dev = ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - i = ep->ep_num * 2 + is_in(ep); - dqh = &dev->ep_dqh[i]; - - if (ep->ep_num) - dev_vdbg(&dev->pdev->dev, "%s\n", ep->name); - else - /* ep0 */ - dev_vdbg(&dev->pdev->dev, "%s-%s\n", ep->name, DIR_STRING(ep)); - - dev_vdbg(&dev->pdev->dev, "ep_dqh[%d] addr: 0x%p\n", - i, &(dev->ep_dqh[i])); - - bit_mask = is_in(ep) ? - (1 << (ep->ep_num + 16)) : (1 << (ep->ep_num)); - - dev_vdbg(&dev->pdev->dev, "bit_mask = 0x%08x\n", bit_mask); - - /* check if the pipe is empty */ - if (!(list_empty(&ep->queue))) { - /* add dTD to the end of linked list */ - struct langwell_request *lastreq; - lastreq = list_entry(ep->queue.prev, - struct langwell_request, queue); - - lastreq->tail->dtd_next = - cpu_to_le32(req->head->dtd_dma & DTD_NEXT_MASK); - - /* read prime bit, if 1 goto out */ - if (readl(&dev->op_regs->endptprime) & bit_mask) - goto out; - - do { - /* set ATDTW bit in USBCMD */ - usbcmd = readl(&dev->op_regs->usbcmd); - writel(usbcmd | CMD_ATDTW, &dev->op_regs->usbcmd); - - /* read correct status bit */ - endptstat = readl(&dev->op_regs->endptstat) & bit_mask; - - } while (!(readl(&dev->op_regs->usbcmd) & CMD_ATDTW)); - - /* write ATDTW bit to 0 */ - usbcmd = readl(&dev->op_regs->usbcmd); - writel(usbcmd & ~CMD_ATDTW, &dev->op_regs->usbcmd); - - if (endptstat) - goto out; - } - - /* write dQH next pointer and terminate bit to 0 */ - dtd_dma = req->head->dtd_dma & DTD_NEXT_MASK; - dqh->dtd_next = cpu_to_le32(dtd_dma); - - /* clear active and halt bit */ - dtd_status = (u8) ~(DTD_STS_ACTIVE | DTD_STS_HALTED); - dqh->dtd_status &= dtd_status; - dev_vdbg(&dev->pdev->dev, "dqh->dtd_status = 0x%x\n", dqh->dtd_status); - - /* ensure that updates to the dQH will occur before priming */ - wmb(); - - /* write 1 to endptprime register to PRIME endpoint */ - bit_mask = is_in(ep) ? (1 << (ep->ep_num + 16)) : (1 << ep->ep_num); - dev_vdbg(&dev->pdev->dev, "endprime bit_mask = 0x%08x\n", bit_mask); - writel(bit_mask, &dev->op_regs->endptprime); -out: - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* fill in the dTD structure to build a transfer descriptor */ -static struct langwell_dtd *build_dtd(struct langwell_request *req, - unsigned *length, dma_addr_t *dma, int *is_last) -{ - u32 buf_ptr; - struct langwell_dtd *dtd; - struct langwell_udc *dev; - int i; - - dev = req->ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* the maximum transfer length, up to 16k bytes */ - *length = min(req->req.length - req->req.actual, - (unsigned)DTD_MAX_TRANSFER_LENGTH); - - /* create dTD dma_pool resource */ - dtd = dma_pool_alloc(dev->dtd_pool, GFP_KERNEL, dma); - if (dtd == NULL) - return dtd; - dtd->dtd_dma = *dma; - - /* initialize buffer page pointers */ - buf_ptr = (u32)(req->req.dma + req->req.actual); - for (i = 0; i < 5; i++) - dtd->dtd_buf[i] = cpu_to_le32(buf_ptr + i * PAGE_SIZE); - - req->req.actual += *length; - - /* fill in total bytes with transfer size */ - dtd->dtd_total = cpu_to_le16(*length); - dev_vdbg(&dev->pdev->dev, "dtd->dtd_total = %d\n", dtd->dtd_total); - - /* set is_last flag if req->req.zero is set or not */ - if (req->req.zero) { - if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0) - *is_last = 1; - else - *is_last = 0; - } else if (req->req.length == req->req.actual) { - *is_last = 1; - } else - *is_last = 0; - - if (*is_last == 0) - dev_vdbg(&dev->pdev->dev, "multi-dtd request!\n"); - - /* set interrupt on complete bit for the last dTD */ - if (*is_last && !req->req.no_interrupt) - dtd->dtd_ioc = 1; - - /* set multiplier override 0 for non-ISO and non-TX endpoint */ - dtd->dtd_multo = 0; - - /* set the active bit of status field to 1 */ - dtd->dtd_status = DTD_STS_ACTIVE; - dev_vdbg(&dev->pdev->dev, "dtd->dtd_status = 0x%02x\n", - dtd->dtd_status); - - dev_vdbg(&dev->pdev->dev, "length = %d, dma addr= 0x%08x\n", - *length, (int)*dma); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return dtd; -} - - -/* generate dTD linked list for a request */ -static int req_to_dtd(struct langwell_request *req) -{ - unsigned count; - int is_last, is_first = 1; - struct langwell_dtd *dtd, *last_dtd = NULL; - struct langwell_udc *dev; - dma_addr_t dma; - - dev = req->ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - do { - dtd = build_dtd(req, &count, &dma, &is_last); - if (dtd == NULL) - return -ENOMEM; - - if (is_first) { - is_first = 0; - req->head = dtd; - } else { - last_dtd->dtd_next = cpu_to_le32(dma); - last_dtd->next_dtd_virt = dtd; - } - last_dtd = dtd; - req->dtd_count++; - } while (!is_last); - - /* set terminate bit to 1 for the last dTD */ - dtd->dtd_next = DTD_TERM; - - req->tail = dtd; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* queue (submits) an I/O requests to an endpoint */ -static int langwell_ep_queue(struct usb_ep *_ep, struct usb_request *_req, - gfp_t gfp_flags) -{ - struct langwell_request *req; - struct langwell_ep *ep; - struct langwell_udc *dev; - unsigned long flags; - int is_iso = 0; - int ret; - - /* always require a cpu-view buffer */ - req = container_of(_req, struct langwell_request, req); - ep = container_of(_ep, struct langwell_ep, ep); - - if (!_req || !_req->complete || !_req->buf - || !list_empty(&req->queue)) { - return -EINVAL; - } - - if (unlikely(!_ep || !ep->desc)) - return -EINVAL; - - dev = ep->dev; - req->ep = ep; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (usb_endpoint_xfer_isoc(ep->desc)) { - if (req->req.length > ep->ep.maxpacket) - return -EMSGSIZE; - is_iso = 1; - } - - if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) - return -ESHUTDOWN; - - /* set up dma mapping */ - ret = usb_gadget_map_request(&dev->gadget, &req->req, is_in(ep)); - if (ret) - return ret; - - dev_dbg(&dev->pdev->dev, - "%s queue req %p, len %u, buf %p, dma 0x%08x\n", - _ep->name, - _req, _req->length, _req->buf, (int)_req->dma); - - _req->status = -EINPROGRESS; - _req->actual = 0; - req->dtd_count = 0; - - spin_lock_irqsave(&dev->lock, flags); - - /* build and put dTDs to endpoint queue */ - if (!req_to_dtd(req)) { - queue_dtd(ep, req); - } else { - spin_unlock_irqrestore(&dev->lock, flags); - return -ENOMEM; - } - - /* update ep0 state */ - if (ep->ep_num == 0) - dev->ep0_state = DATA_STATE_XMIT; - - if (likely(req != NULL)) { - list_add_tail(&req->queue, &ep->queue); - dev_vdbg(&dev->pdev->dev, "list_add_tail()\n"); - } - - spin_unlock_irqrestore(&dev->lock, flags); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* dequeue (cancels, unlinks) an I/O request from an endpoint */ -static int langwell_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct langwell_ep *ep; - struct langwell_udc *dev; - struct langwell_request *req; - unsigned long flags; - int stopped, ep_num, retval = 0; - u32 endptctrl; - - ep = container_of(_ep, struct langwell_ep, ep); - dev = ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (!_ep || !ep->desc || !_req) - return -EINVAL; - - if (!dev->driver) - return -ESHUTDOWN; - - spin_lock_irqsave(&dev->lock, flags); - stopped = ep->stopped; - - /* quiesce dma while we patch the queue */ - ep->stopped = 1; - ep_num = ep->ep_num; - - /* disable endpoint control register */ - endptctrl = readl(&dev->op_regs->endptctrl[ep_num]); - if (is_in(ep)) - endptctrl &= ~EPCTRL_TXE; - else - endptctrl &= ~EPCTRL_RXE; - writel(endptctrl, &dev->op_regs->endptctrl[ep_num]); - - /* make sure it's still queued on this endpoint */ - list_for_each_entry(req, &ep->queue, queue) { - if (&req->req == _req) - break; - } - - if (&req->req != _req) { - retval = -EINVAL; - goto done; - } - - /* queue head may be partially complete. */ - if (ep->queue.next == &req->queue) { - dev_dbg(&dev->pdev->dev, "unlink (%s) dma\n", _ep->name); - _req->status = -ECONNRESET; - langwell_ep_fifo_flush(&ep->ep); - - /* not the last request in endpoint queue */ - if (likely(ep->queue.next == &req->queue)) { - struct langwell_dqh *dqh; - struct langwell_request *next_req; - - dqh = ep->dqh; - next_req = list_entry(req->queue.next, - struct langwell_request, queue); - - /* point the dQH to the first dTD of next request */ - writel((u32) next_req->head, &dqh->dqh_current); - } - } else { - struct langwell_request *prev_req; - - prev_req = list_entry(req->queue.prev, - struct langwell_request, queue); - writel(readl(&req->tail->dtd_next), - &prev_req->tail->dtd_next); - } - - done(ep, req, -ECONNRESET); - -done: - /* enable endpoint again */ - endptctrl = readl(&dev->op_regs->endptctrl[ep_num]); - if (is_in(ep)) - endptctrl |= EPCTRL_TXE; - else - endptctrl |= EPCTRL_RXE; - writel(endptctrl, &dev->op_regs->endptctrl[ep_num]); - - ep->stopped = stopped; - spin_unlock_irqrestore(&dev->lock, flags); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return retval; -} - - -/*-------------------------------------------------------------------------*/ - -/* endpoint set/clear halt */ -static void ep_set_halt(struct langwell_ep *ep, int value) -{ - u32 endptctrl = 0; - int ep_num; - struct langwell_udc *dev = ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - ep_num = ep->ep_num; - endptctrl = readl(&dev->op_regs->endptctrl[ep_num]); - - /* value: 1 - set halt, 0 - clear halt */ - if (value) { - /* set the stall bit */ - if (is_in(ep)) - endptctrl |= EPCTRL_TXS; - else - endptctrl |= EPCTRL_RXS; - } else { - /* clear the stall bit and reset data toggle */ - if (is_in(ep)) { - endptctrl &= ~EPCTRL_TXS; - endptctrl |= EPCTRL_TXR; - } else { - endptctrl &= ~EPCTRL_RXS; - endptctrl |= EPCTRL_RXR; - } - } - - writel(endptctrl, &dev->op_regs->endptctrl[ep_num]); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* set the endpoint halt feature */ -static int langwell_ep_set_halt(struct usb_ep *_ep, int value) -{ - struct langwell_ep *ep; - struct langwell_udc *dev; - unsigned long flags; - int retval = 0; - - ep = container_of(_ep, struct langwell_ep, ep); - dev = ep->dev; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (!_ep || !ep->desc) - return -EINVAL; - - if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - if (usb_endpoint_xfer_isoc(ep->desc)) - return -EOPNOTSUPP; - - spin_lock_irqsave(&dev->lock, flags); - - /* - * attempt to halt IN ep will fail if any transfer requests - * are still queue - */ - if (!list_empty(&ep->queue) && is_in(ep) && value) { - /* IN endpoint FIFO holds bytes */ - dev_dbg(&dev->pdev->dev, "%s FIFO holds bytes\n", _ep->name); - retval = -EAGAIN; - goto done; - } - - /* endpoint set/clear halt */ - if (ep->ep_num) { - ep_set_halt(ep, value); - } else { /* endpoint 0 */ - dev->ep0_state = WAIT_FOR_SETUP; - dev->ep0_dir = USB_DIR_OUT; - } -done: - spin_unlock_irqrestore(&dev->lock, flags); - dev_dbg(&dev->pdev->dev, "%s %s halt\n", - _ep->name, value ? "set" : "clear"); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return retval; -} - - -/* set the halt feature and ignores clear requests */ -static int langwell_ep_set_wedge(struct usb_ep *_ep) -{ - struct langwell_ep *ep; - struct langwell_udc *dev; - - ep = container_of(_ep, struct langwell_ep, ep); - dev = ep->dev; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (!_ep || !ep->desc) - return -EINVAL; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return usb_ep_set_halt(_ep); -} - - -/* flush contents of a fifo */ -static void langwell_ep_fifo_flush(struct usb_ep *_ep) -{ - struct langwell_ep *ep; - struct langwell_udc *dev; - u32 flush_bit; - unsigned long timeout; - - ep = container_of(_ep, struct langwell_ep, ep); - dev = ep->dev; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (!_ep || !ep->desc) { - dev_vdbg(&dev->pdev->dev, "ep or ep->desc is NULL\n"); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return; - } - - dev_vdbg(&dev->pdev->dev, "%s-%s fifo flush\n", - _ep->name, DIR_STRING(ep)); - - /* flush endpoint buffer */ - if (ep->ep_num == 0) - flush_bit = (1 << 16) | 1; - else if (is_in(ep)) - flush_bit = 1 << (ep->ep_num + 16); /* TX */ - else - flush_bit = 1 << ep->ep_num; /* RX */ - - /* wait until flush complete */ - timeout = jiffies + FLUSH_TIMEOUT; - do { - writel(flush_bit, &dev->op_regs->endptflush); - while (readl(&dev->op_regs->endptflush)) { - if (time_after(jiffies, timeout)) { - dev_err(&dev->pdev->dev, "ep flush timeout\n"); - goto done; - } - cpu_relax(); - } - } while (readl(&dev->op_regs->endptstat) & flush_bit); -done: - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* endpoints operations structure */ -static const struct usb_ep_ops langwell_ep_ops = { - - /* configure endpoint, making it usable */ - .enable = langwell_ep_enable, - - /* endpoint is no longer usable */ - .disable = langwell_ep_disable, - - /* allocate a request object to use with this endpoint */ - .alloc_request = langwell_alloc_request, - - /* free a request object */ - .free_request = langwell_free_request, - - /* queue (submits) an I/O requests to an endpoint */ - .queue = langwell_ep_queue, - - /* dequeue (cancels, unlinks) an I/O request from an endpoint */ - .dequeue = langwell_ep_dequeue, - - /* set the endpoint halt feature */ - .set_halt = langwell_ep_set_halt, - - /* set the halt feature and ignores clear requests */ - .set_wedge = langwell_ep_set_wedge, - - /* flush contents of a fifo */ - .fifo_flush = langwell_ep_fifo_flush, -}; - - -/*-------------------------------------------------------------------------*/ - -/* device controller usb_gadget_ops structure */ - -/* returns the current frame number */ -static int langwell_get_frame(struct usb_gadget *_gadget) -{ - struct langwell_udc *dev; - u16 retval; - - if (!_gadget) - return -ENODEV; - - dev = container_of(_gadget, struct langwell_udc, gadget); - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - retval = readl(&dev->op_regs->frindex) & FRINDEX_MASK; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return retval; -} - - -/* enter or exit PHY low power state */ -static void langwell_phy_low_power(struct langwell_udc *dev, bool flag) -{ - u32 devlc; - u8 devlc_byte2; - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - devlc = readl(&dev->op_regs->devlc); - dev_vdbg(&dev->pdev->dev, "devlc = 0x%08x\n", devlc); - - if (flag) - devlc |= LPM_PHCD; - else - devlc &= ~LPM_PHCD; - - /* FIXME: workaround for Langwell A1/A2/A3 sighting */ - devlc_byte2 = (devlc >> 16) & 0xff; - writeb(devlc_byte2, (u8 *)&dev->op_regs->devlc + 2); - - devlc = readl(&dev->op_regs->devlc); - dev_vdbg(&dev->pdev->dev, - "%s PHY low power suspend, devlc = 0x%08x\n", - flag ? "enter" : "exit", devlc); -} - - -/* tries to wake up the host connected to this gadget */ -static int langwell_wakeup(struct usb_gadget *_gadget) -{ - struct langwell_udc *dev; - u32 portsc1; - unsigned long flags; - - if (!_gadget) - return 0; - - dev = container_of(_gadget, struct langwell_udc, gadget); - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* remote wakeup feature not enabled by host */ - if (!dev->remote_wakeup) { - dev_info(&dev->pdev->dev, "remote wakeup is disabled\n"); - return -ENOTSUPP; - } - - spin_lock_irqsave(&dev->lock, flags); - - portsc1 = readl(&dev->op_regs->portsc1); - if (!(portsc1 & PORTS_SUSP)) { - spin_unlock_irqrestore(&dev->lock, flags); - return 0; - } - - /* LPM L1 to L0 or legacy remote wakeup */ - if (dev->lpm && dev->lpm_state == LPM_L1) - dev_info(&dev->pdev->dev, "LPM L1 to L0 remote wakeup\n"); - else - dev_info(&dev->pdev->dev, "device remote wakeup\n"); - - /* exit PHY low power suspend */ - if (dev->pdev->device != 0x0829) - langwell_phy_low_power(dev, 0); - - /* force port resume */ - portsc1 |= PORTS_FPR; - writel(portsc1, &dev->op_regs->portsc1); - - spin_unlock_irqrestore(&dev->lock, flags); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* notify controller that VBUS is powered or not */ -static int langwell_vbus_session(struct usb_gadget *_gadget, int is_active) -{ - struct langwell_udc *dev; - unsigned long flags; - u32 usbcmd; - - if (!_gadget) - return -ENODEV; - - dev = container_of(_gadget, struct langwell_udc, gadget); - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - spin_lock_irqsave(&dev->lock, flags); - dev_vdbg(&dev->pdev->dev, "VBUS status: %s\n", - is_active ? "on" : "off"); - - dev->vbus_active = (is_active != 0); - if (dev->driver && dev->softconnected && dev->vbus_active) { - usbcmd = readl(&dev->op_regs->usbcmd); - usbcmd |= CMD_RUNSTOP; - writel(usbcmd, &dev->op_regs->usbcmd); - } else { - usbcmd = readl(&dev->op_regs->usbcmd); - usbcmd &= ~CMD_RUNSTOP; - writel(usbcmd, &dev->op_regs->usbcmd); - } - - spin_unlock_irqrestore(&dev->lock, flags); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* constrain controller's VBUS power usage */ -static int langwell_vbus_draw(struct usb_gadget *_gadget, unsigned mA) -{ - struct langwell_udc *dev; - - if (!_gadget) - return -ENODEV; - - dev = container_of(_gadget, struct langwell_udc, gadget); - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (dev->transceiver) { - dev_vdbg(&dev->pdev->dev, "usb_phy_set_power\n"); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return usb_phy_set_power(dev->transceiver, mA); - } - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return -ENOTSUPP; -} - - -/* D+ pullup, software-controlled connect/disconnect to USB host */ -static int langwell_pullup(struct usb_gadget *_gadget, int is_on) -{ - struct langwell_udc *dev; - u32 usbcmd; - unsigned long flags; - - if (!_gadget) - return -ENODEV; - - dev = container_of(_gadget, struct langwell_udc, gadget); - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - spin_lock_irqsave(&dev->lock, flags); - dev->softconnected = (is_on != 0); - - if (dev->driver && dev->softconnected && dev->vbus_active) { - usbcmd = readl(&dev->op_regs->usbcmd); - usbcmd |= CMD_RUNSTOP; - writel(usbcmd, &dev->op_regs->usbcmd); - } else { - usbcmd = readl(&dev->op_regs->usbcmd); - usbcmd &= ~CMD_RUNSTOP; - writel(usbcmd, &dev->op_regs->usbcmd); - } - spin_unlock_irqrestore(&dev->lock, flags); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - -static int langwell_start(struct usb_gadget *g, - struct usb_gadget_driver *driver); - -static int langwell_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver); - -/* device controller usb_gadget_ops structure */ -static const struct usb_gadget_ops langwell_ops = { - - /* returns the current frame number */ - .get_frame = langwell_get_frame, - - /* tries to wake up the host connected to this gadget */ - .wakeup = langwell_wakeup, - - /* set the device selfpowered feature, always selfpowered */ - /* .set_selfpowered = langwell_set_selfpowered, */ - - /* notify controller that VBUS is powered or not */ - .vbus_session = langwell_vbus_session, - - /* constrain controller's VBUS power usage */ - .vbus_draw = langwell_vbus_draw, - - /* D+ pullup, software-controlled connect/disconnect to USB host */ - .pullup = langwell_pullup, - - .udc_start = langwell_start, - .udc_stop = langwell_stop, -}; - - -/*-------------------------------------------------------------------------*/ - -/* device controller operations */ - -/* reset device controller */ -static int langwell_udc_reset(struct langwell_udc *dev) -{ - u32 usbcmd, usbmode, devlc, endpointlistaddr; - u8 devlc_byte0, devlc_byte2; - unsigned long timeout; - - if (!dev) - return -EINVAL; - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* set controller to stop state */ - usbcmd = readl(&dev->op_regs->usbcmd); - usbcmd &= ~CMD_RUNSTOP; - writel(usbcmd, &dev->op_regs->usbcmd); - - /* reset device controller */ - usbcmd = readl(&dev->op_regs->usbcmd); - usbcmd |= CMD_RST; - writel(usbcmd, &dev->op_regs->usbcmd); - - /* wait for reset to complete */ - timeout = jiffies + RESET_TIMEOUT; - while (readl(&dev->op_regs->usbcmd) & CMD_RST) { - if (time_after(jiffies, timeout)) { - dev_err(&dev->pdev->dev, "device reset timeout\n"); - return -ETIMEDOUT; - } - cpu_relax(); - } - - /* set controller to device mode */ - usbmode = readl(&dev->op_regs->usbmode); - usbmode |= MODE_DEVICE; - - /* turn setup lockout off, require setup tripwire in usbcmd */ - usbmode |= MODE_SLOM; - - writel(usbmode, &dev->op_regs->usbmode); - usbmode = readl(&dev->op_regs->usbmode); - dev_vdbg(&dev->pdev->dev, "usbmode=0x%08x\n", usbmode); - - /* Write-Clear setup status */ - writel(0, &dev->op_regs->usbsts); - - /* if support USB LPM, ACK all LPM token */ - if (dev->lpm) { - devlc = readl(&dev->op_regs->devlc); - dev_vdbg(&dev->pdev->dev, "devlc = 0x%08x\n", devlc); - /* FIXME: workaround for Langwell A1/A2/A3 sighting */ - devlc &= ~LPM_STL; /* don't STALL LPM token */ - devlc &= ~LPM_NYT_ACK; /* ACK LPM token */ - devlc_byte0 = devlc & 0xff; - devlc_byte2 = (devlc >> 16) & 0xff; - writeb(devlc_byte0, (u8 *)&dev->op_regs->devlc); - writeb(devlc_byte2, (u8 *)&dev->op_regs->devlc + 2); - devlc = readl(&dev->op_regs->devlc); - dev_vdbg(&dev->pdev->dev, - "ACK LPM token, devlc = 0x%08x\n", devlc); - } - - /* fill endpointlistaddr register */ - endpointlistaddr = dev->ep_dqh_dma; - endpointlistaddr &= ENDPOINTLISTADDR_MASK; - writel(endpointlistaddr, &dev->op_regs->endpointlistaddr); - - dev_vdbg(&dev->pdev->dev, - "dQH base (vir: %p, phy: 0x%08x), endpointlistaddr=0x%08x\n", - dev->ep_dqh, endpointlistaddr, - readl(&dev->op_regs->endpointlistaddr)); - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* reinitialize device controller endpoints */ -static int eps_reinit(struct langwell_udc *dev) -{ - struct langwell_ep *ep; - char name[14]; - int i; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* initialize ep0 */ - ep = &dev->ep[0]; - ep->dev = dev; - strncpy(ep->name, "ep0", sizeof(ep->name)); - ep->ep.name = ep->name; - ep->ep.ops = &langwell_ep_ops; - ep->stopped = 0; - ep->ep.maxpacket = EP0_MAX_PKT_SIZE; - ep->ep_num = 0; - ep->desc = &langwell_ep0_desc; - INIT_LIST_HEAD(&ep->queue); - - ep->ep_type = USB_ENDPOINT_XFER_CONTROL; - - /* initialize other endpoints */ - for (i = 2; i < dev->ep_max; i++) { - ep = &dev->ep[i]; - if (i % 2) - snprintf(name, sizeof(name), "ep%din", i / 2); - else - snprintf(name, sizeof(name), "ep%dout", i / 2); - ep->dev = dev; - strncpy(ep->name, name, sizeof(ep->name)); - ep->ep.name = ep->name; - - ep->ep.ops = &langwell_ep_ops; - ep->stopped = 0; - ep->ep.maxpacket = (unsigned short) ~0; - ep->ep_num = i / 2; - - INIT_LIST_HEAD(&ep->queue); - list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); - } - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* enable interrupt and set controller to run state */ -static void langwell_udc_start(struct langwell_udc *dev) -{ - u32 usbintr, usbcmd; - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* enable interrupts */ - usbintr = INTR_ULPIE /* ULPI */ - | INTR_SLE /* suspend */ - /* | INTR_SRE SOF received */ - | INTR_URE /* USB reset */ - | INTR_AAE /* async advance */ - | INTR_SEE /* system error */ - | INTR_FRE /* frame list rollover */ - | INTR_PCE /* port change detect */ - | INTR_UEE /* USB error interrupt */ - | INTR_UE; /* USB interrupt */ - writel(usbintr, &dev->op_regs->usbintr); - - /* clear stopped bit */ - dev->stopped = 0; - - /* set controller to run */ - usbcmd = readl(&dev->op_regs->usbcmd); - usbcmd |= CMD_RUNSTOP; - writel(usbcmd, &dev->op_regs->usbcmd); - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* disable interrupt and set controller to stop state */ -static void langwell_udc_stop(struct langwell_udc *dev) -{ - u32 usbcmd; - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* disable all interrupts */ - writel(0, &dev->op_regs->usbintr); - - /* set stopped bit */ - dev->stopped = 1; - - /* set controller to stop state */ - usbcmd = readl(&dev->op_regs->usbcmd); - usbcmd &= ~CMD_RUNSTOP; - writel(usbcmd, &dev->op_regs->usbcmd); - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* stop all USB activities */ -static void stop_activity(struct langwell_udc *dev) -{ - struct langwell_ep *ep; - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - nuke(&dev->ep[0], -ESHUTDOWN); - - list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) { - nuke(ep, -ESHUTDOWN); - } - - /* report disconnect; the driver is already quiesced */ - if (dev->driver) { - spin_unlock(&dev->lock); - dev->driver->disconnect(&dev->gadget); - spin_lock(&dev->lock); - } - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/*-------------------------------------------------------------------------*/ - -/* device "function" sysfs attribute file */ -static ssize_t show_function(struct device *_dev, - struct device_attribute *attr, char *buf) -{ - struct langwell_udc *dev = dev_get_drvdata(_dev); - - if (!dev->driver || !dev->driver->function - || strlen(dev->driver->function) > PAGE_SIZE) - return 0; - - return scnprintf(buf, PAGE_SIZE, "%s\n", dev->driver->function); -} -static DEVICE_ATTR(function, S_IRUGO, show_function, NULL); - - -static inline enum usb_device_speed lpm_device_speed(u32 reg) -{ - switch (LPM_PSPD(reg)) { - case LPM_SPEED_HIGH: - return USB_SPEED_HIGH; - case LPM_SPEED_FULL: - return USB_SPEED_FULL; - case LPM_SPEED_LOW: - return USB_SPEED_LOW; - default: - return USB_SPEED_UNKNOWN; - } -} - -/* device "langwell_udc" sysfs attribute file */ -static ssize_t show_langwell_udc(struct device *_dev, - struct device_attribute *attr, char *buf) -{ - struct langwell_udc *dev = dev_get_drvdata(_dev); - struct langwell_request *req; - struct langwell_ep *ep = NULL; - char *next; - unsigned size; - unsigned t; - unsigned i; - unsigned long flags; - u32 tmp_reg; - - next = buf; - size = PAGE_SIZE; - spin_lock_irqsave(&dev->lock, flags); - - /* driver basic information */ - t = scnprintf(next, size, - DRIVER_DESC "\n" - "%s version: %s\n" - "Gadget driver: %s\n\n", - driver_name, DRIVER_VERSION, - dev->driver ? dev->driver->driver.name : "(none)"); - size -= t; - next += t; - - /* device registers */ - tmp_reg = readl(&dev->op_regs->usbcmd); - t = scnprintf(next, size, - "USBCMD reg:\n" - "SetupTW: %d\n" - "Run/Stop: %s\n\n", - (tmp_reg & CMD_SUTW) ? 1 : 0, - (tmp_reg & CMD_RUNSTOP) ? "Run" : "Stop"); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->usbsts); - t = scnprintf(next, size, - "USB Status Reg:\n" - "Device Suspend: %d\n" - "Reset Received: %d\n" - "System Error: %s\n" - "USB Error Interrupt: %s\n\n", - (tmp_reg & STS_SLI) ? 1 : 0, - (tmp_reg & STS_URI) ? 1 : 0, - (tmp_reg & STS_SEI) ? "Error" : "No error", - (tmp_reg & STS_UEI) ? "Error detected" : "No error"); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->usbintr); - t = scnprintf(next, size, - "USB Intrrupt Enable Reg:\n" - "Sleep Enable: %d\n" - "SOF Received Enable: %d\n" - "Reset Enable: %d\n" - "System Error Enable: %d\n" - "Port Change Dectected Enable: %d\n" - "USB Error Intr Enable: %d\n" - "USB Intr Enable: %d\n\n", - (tmp_reg & INTR_SLE) ? 1 : 0, - (tmp_reg & INTR_SRE) ? 1 : 0, - (tmp_reg & INTR_URE) ? 1 : 0, - (tmp_reg & INTR_SEE) ? 1 : 0, - (tmp_reg & INTR_PCE) ? 1 : 0, - (tmp_reg & INTR_UEE) ? 1 : 0, - (tmp_reg & INTR_UE) ? 1 : 0); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->frindex); - t = scnprintf(next, size, - "USB Frame Index Reg:\n" - "Frame Number is 0x%08x\n\n", - (tmp_reg & FRINDEX_MASK)); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->deviceaddr); - t = scnprintf(next, size, - "USB Device Address Reg:\n" - "Device Addr is 0x%x\n\n", - USBADR(tmp_reg)); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->endpointlistaddr); - t = scnprintf(next, size, - "USB Endpoint List Address Reg:\n" - "Endpoint List Pointer is 0x%x\n\n", - EPBASE(tmp_reg)); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->portsc1); - t = scnprintf(next, size, - "USB Port Status & Control Reg:\n" - "Port Reset: %s\n" - "Port Suspend Mode: %s\n" - "Over-current Change: %s\n" - "Port Enable/Disable Change: %s\n" - "Port Enabled/Disabled: %s\n" - "Current Connect Status: %s\n" - "LPM Suspend Status: %s\n\n", - (tmp_reg & PORTS_PR) ? "Reset" : "Not Reset", - (tmp_reg & PORTS_SUSP) ? "Suspend " : "Not Suspend", - (tmp_reg & PORTS_OCC) ? "Detected" : "No", - (tmp_reg & PORTS_PEC) ? "Changed" : "Not Changed", - (tmp_reg & PORTS_PE) ? "Enable" : "Not Correct", - (tmp_reg & PORTS_CCS) ? "Attached" : "Not Attached", - (tmp_reg & PORTS_SLP) ? "LPM L1" : "LPM L0"); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->devlc); - t = scnprintf(next, size, - "Device LPM Control Reg:\n" - "Parallel Transceiver : %d\n" - "Serial Transceiver : %d\n" - "Port Speed: %s\n" - "Port Force Full Speed Connenct: %s\n" - "PHY Low Power Suspend Clock: %s\n" - "BmAttributes: %d\n\n", - LPM_PTS(tmp_reg), - (tmp_reg & LPM_STS) ? 1 : 0, - usb_speed_string(lpm_device_speed(tmp_reg)), - (tmp_reg & LPM_PFSC) ? "Force Full Speed" : "Not Force", - (tmp_reg & LPM_PHCD) ? "Disabled" : "Enabled", - LPM_BA(tmp_reg)); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->usbmode); - t = scnprintf(next, size, - "USB Mode Reg:\n" - "Controller Mode is : %s\n\n", ({ - char *s; - switch (MODE_CM(tmp_reg)) { - case MODE_IDLE: - s = "Idle"; break; - case MODE_DEVICE: - s = "Device Controller"; break; - case MODE_HOST: - s = "Host Controller"; break; - default: - s = "None"; break; - } - s; - })); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->endptsetupstat); - t = scnprintf(next, size, - "Endpoint Setup Status Reg:\n" - "SETUP on ep 0x%04x\n\n", - tmp_reg & SETUPSTAT_MASK); - size -= t; - next += t; - - for (i = 0; i < dev->ep_max / 2; i++) { - tmp_reg = readl(&dev->op_regs->endptctrl[i]); - t = scnprintf(next, size, "EP Ctrl Reg [%d]: 0x%08x\n", - i, tmp_reg); - size -= t; - next += t; - } - tmp_reg = readl(&dev->op_regs->endptprime); - t = scnprintf(next, size, "EP Prime Reg: 0x%08x\n\n", tmp_reg); - size -= t; - next += t; - - /* langwell_udc, langwell_ep, langwell_request structure information */ - ep = &dev->ep[0]; - t = scnprintf(next, size, "%s MaxPacketSize: 0x%x, ep_num: %d\n", - ep->ep.name, ep->ep.maxpacket, ep->ep_num); - size -= t; - next += t; - - if (list_empty(&ep->queue)) { - t = scnprintf(next, size, "its req queue is empty\n\n"); - size -= t; - next += t; - } else { - list_for_each_entry(req, &ep->queue, queue) { - t = scnprintf(next, size, - "req %p actual 0x%x length 0x%x buf %p\n", - &req->req, req->req.actual, - req->req.length, req->req.buf); - size -= t; - next += t; - } - } - /* other gadget->eplist ep */ - list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) { - if (ep->desc) { - t = scnprintf(next, size, - "\n%s MaxPacketSize: 0x%x, " - "ep_num: %d\n", - ep->ep.name, ep->ep.maxpacket, - ep->ep_num); - size -= t; - next += t; - - if (list_empty(&ep->queue)) { - t = scnprintf(next, size, - "its req queue is empty\n\n"); - size -= t; - next += t; - } else { - list_for_each_entry(req, &ep->queue, queue) { - t = scnprintf(next, size, - "req %p actual 0x%x length " - "0x%x buf %p\n", - &req->req, req->req.actual, - req->req.length, req->req.buf); - size -= t; - next += t; - } - } - } - } - - spin_unlock_irqrestore(&dev->lock, flags); - return PAGE_SIZE - size; -} -static DEVICE_ATTR(langwell_udc, S_IRUGO, show_langwell_udc, NULL); - - -/* device "remote_wakeup" sysfs attribute file */ -static ssize_t store_remote_wakeup(struct device *_dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct langwell_udc *dev = dev_get_drvdata(_dev); - unsigned long flags; - ssize_t rc = count; - - if (count > 2) - return -EINVAL; - - if (count > 0 && buf[count-1] == '\n') - ((char *) buf)[count-1] = 0; - - if (buf[0] != '1') - return -EINVAL; - - /* force remote wakeup enabled in case gadget driver doesn't support */ - spin_lock_irqsave(&dev->lock, flags); - dev->remote_wakeup = 1; - dev->dev_status |= (1 << USB_DEVICE_REMOTE_WAKEUP); - spin_unlock_irqrestore(&dev->lock, flags); - - langwell_wakeup(&dev->gadget); - - return rc; -} -static DEVICE_ATTR(remote_wakeup, S_IWUSR, NULL, store_remote_wakeup); - - -/*-------------------------------------------------------------------------*/ - -/* - * when a driver is successfully registered, it will receive - * control requests including set_configuration(), which enables - * non-control requests. then usb traffic follows until a - * disconnect is reported. then a host may connect again, or - * the driver might get unbound. - */ - -static int langwell_start(struct usb_gadget *g, - struct usb_gadget_driver *driver) -{ - struct langwell_udc *dev = gadget_to_langwell(g); - unsigned long flags; - int retval; - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - spin_lock_irqsave(&dev->lock, flags); - - /* hook up the driver ... */ - driver->driver.bus = NULL; - dev->driver = driver; - dev->gadget.dev.driver = &driver->driver; - - spin_unlock_irqrestore(&dev->lock, flags); - - retval = device_create_file(&dev->pdev->dev, &dev_attr_function); - if (retval) - goto err; - - dev->usb_state = USB_STATE_ATTACHED; - dev->ep0_state = WAIT_FOR_SETUP; - dev->ep0_dir = USB_DIR_OUT; - - /* enable interrupt and set controller to run state */ - if (dev->got_irq) - langwell_udc_start(dev); - - dev_vdbg(&dev->pdev->dev, - "After langwell_udc_start(), print all registers:\n"); - print_all_registers(dev); - - dev_info(&dev->pdev->dev, "register driver: %s\n", - driver->driver.name); - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - - return 0; - -err: - dev->gadget.dev.driver = NULL; - dev->driver = NULL; - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - - return retval; -} - -/* unregister gadget driver */ -static int langwell_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver) -{ - struct langwell_udc *dev = gadget_to_langwell(g); - unsigned long flags; - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* exit PHY low power suspend */ - if (dev->pdev->device != 0x0829) - langwell_phy_low_power(dev, 0); - - /* unbind OTG transceiver */ - if (dev->transceiver) - (void)otg_set_peripheral(dev->transceiver->otg, 0); - - /* disable interrupt and set controller to stop state */ - langwell_udc_stop(dev); - - dev->usb_state = USB_STATE_ATTACHED; - dev->ep0_state = WAIT_FOR_SETUP; - dev->ep0_dir = USB_DIR_OUT; - - spin_lock_irqsave(&dev->lock, flags); - - /* stop all usb activities */ - dev->gadget.speed = USB_SPEED_UNKNOWN; - dev->gadget.dev.driver = NULL; - dev->driver = NULL; - stop_activity(dev); - spin_unlock_irqrestore(&dev->lock, flags); - - device_remove_file(&dev->pdev->dev, &dev_attr_function); - - dev_info(&dev->pdev->dev, "unregistered driver '%s'\n", - driver->driver.name); - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* - * setup tripwire is used as a semaphore to ensure that the setup data - * payload is extracted from a dQH without being corrupted - */ -static void setup_tripwire(struct langwell_udc *dev) -{ - u32 usbcmd, - endptsetupstat; - unsigned long timeout; - struct langwell_dqh *dqh; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* ep0 OUT dQH */ - dqh = &dev->ep_dqh[EP_DIR_OUT]; - - /* Write-Clear endptsetupstat */ - endptsetupstat = readl(&dev->op_regs->endptsetupstat); - writel(endptsetupstat, &dev->op_regs->endptsetupstat); - - /* wait until endptsetupstat is cleared */ - timeout = jiffies + SETUPSTAT_TIMEOUT; - while (readl(&dev->op_regs->endptsetupstat)) { - if (time_after(jiffies, timeout)) { - dev_err(&dev->pdev->dev, "setup_tripwire timeout\n"); - break; - } - cpu_relax(); - } - - /* while a hazard exists when setup packet arrives */ - do { - /* set setup tripwire bit */ - usbcmd = readl(&dev->op_regs->usbcmd); - writel(usbcmd | CMD_SUTW, &dev->op_regs->usbcmd); - - /* copy the setup packet to local buffer */ - memcpy(&dev->local_setup_buff, &dqh->dqh_setup, 8); - } while (!(readl(&dev->op_regs->usbcmd) & CMD_SUTW)); - - /* Write-Clear setup tripwire bit */ - usbcmd = readl(&dev->op_regs->usbcmd); - writel(usbcmd & ~CMD_SUTW, &dev->op_regs->usbcmd); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* protocol ep0 stall, will automatically be cleared on new transaction */ -static void ep0_stall(struct langwell_udc *dev) -{ - u32 endptctrl; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* set TX and RX to stall */ - endptctrl = readl(&dev->op_regs->endptctrl[0]); - endptctrl |= EPCTRL_TXS | EPCTRL_RXS; - writel(endptctrl, &dev->op_regs->endptctrl[0]); - - /* update ep0 state */ - dev->ep0_state = WAIT_FOR_SETUP; - dev->ep0_dir = USB_DIR_OUT; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* PRIME a status phase for ep0 */ -static int prime_status_phase(struct langwell_udc *dev, int dir) -{ - struct langwell_request *req; - struct langwell_ep *ep; - int status = 0; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (dir == EP_DIR_IN) - dev->ep0_dir = USB_DIR_IN; - else - dev->ep0_dir = USB_DIR_OUT; - - ep = &dev->ep[0]; - dev->ep0_state = WAIT_FOR_OUT_STATUS; - - req = dev->status_req; - - req->ep = ep; - req->req.length = 0; - req->req.status = -EINPROGRESS; - req->req.actual = 0; - req->req.complete = NULL; - req->dtd_count = 0; - - if (!req_to_dtd(req)) - status = queue_dtd(ep, req); - else - return -ENOMEM; - - if (status) - dev_err(&dev->pdev->dev, "can't queue ep0 status request\n"); - - list_add_tail(&req->queue, &ep->queue); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return status; -} - - -/* SET_ADDRESS request routine */ -static void set_address(struct langwell_udc *dev, u16 value, - u16 index, u16 length) -{ - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* save the new address to device struct */ - dev->dev_addr = (u8) value; - dev_vdbg(&dev->pdev->dev, "dev->dev_addr = %d\n", dev->dev_addr); - - /* update usb state */ - dev->usb_state = USB_STATE_ADDRESS; - - /* STATUS phase */ - if (prime_status_phase(dev, EP_DIR_IN)) - ep0_stall(dev); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* return endpoint by windex */ -static struct langwell_ep *get_ep_by_windex(struct langwell_udc *dev, - u16 wIndex) -{ - struct langwell_ep *ep; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0) - return &dev->ep[0]; - - list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) { - u8 bEndpointAddress; - if (!ep->desc) - continue; - - bEndpointAddress = ep->desc->bEndpointAddress; - if ((wIndex ^ bEndpointAddress) & USB_DIR_IN) - continue; - - if ((wIndex & USB_ENDPOINT_NUMBER_MASK) - == (bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)) - return ep; - } - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return NULL; -} - - -/* return whether endpoint is stalled, 0: not stalled; 1: stalled */ -static int ep_is_stall(struct langwell_ep *ep) -{ - struct langwell_udc *dev = ep->dev; - u32 endptctrl; - int retval; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - endptctrl = readl(&dev->op_regs->endptctrl[ep->ep_num]); - if (is_in(ep)) - retval = endptctrl & EPCTRL_TXS ? 1 : 0; - else - retval = endptctrl & EPCTRL_RXS ? 1 : 0; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return retval; -} - - -/* GET_STATUS request routine */ -static void get_status(struct langwell_udc *dev, u8 request_type, u16 value, - u16 index, u16 length) -{ - struct langwell_request *req; - struct langwell_ep *ep; - u16 status_data = 0; /* 16 bits cpu view status data */ - int status = 0; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - ep = &dev->ep[0]; - - if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) { - /* get device status */ - status_data = dev->dev_status; - } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) { - /* get interface status */ - status_data = 0; - } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) { - /* get endpoint status */ - struct langwell_ep *epn; - epn = get_ep_by_windex(dev, index); - /* stall if endpoint doesn't exist */ - if (!epn) - goto stall; - - status_data = ep_is_stall(epn) << USB_ENDPOINT_HALT; - } - - dev_dbg(&dev->pdev->dev, "get status data: 0x%04x\n", status_data); - - dev->ep0_dir = USB_DIR_IN; - - /* borrow the per device status_req */ - req = dev->status_req; - - /* fill in the reqest structure */ - *((u16 *) req->req.buf) = cpu_to_le16(status_data); - req->ep = ep; - req->req.length = 2; - req->req.status = -EINPROGRESS; - req->req.actual = 0; - req->req.complete = NULL; - req->dtd_count = 0; - - /* prime the data phase */ - if (!req_to_dtd(req)) - status = queue_dtd(ep, req); - else /* no mem */ - goto stall; - - if (status) { - dev_err(&dev->pdev->dev, - "response error on GET_STATUS request\n"); - goto stall; - } - - list_add_tail(&req->queue, &ep->queue); - dev->ep0_state = DATA_STATE_XMIT; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return; -stall: - ep0_stall(dev); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* setup packet interrupt handler */ -static void handle_setup_packet(struct langwell_udc *dev, - struct usb_ctrlrequest *setup) -{ - u16 wValue = le16_to_cpu(setup->wValue); - u16 wIndex = le16_to_cpu(setup->wIndex); - u16 wLength = le16_to_cpu(setup->wLength); - u32 portsc1; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* ep0 fifo flush */ - nuke(&dev->ep[0], -ESHUTDOWN); - - dev_dbg(&dev->pdev->dev, "SETUP %02x.%02x v%04x i%04x l%04x\n", - setup->bRequestType, setup->bRequest, - wValue, wIndex, wLength); - - /* RNDIS gadget delegate */ - if ((setup->bRequestType == 0x21) && (setup->bRequest == 0x00)) { - /* USB_CDC_SEND_ENCAPSULATED_COMMAND */ - goto delegate; - } - - /* USB_CDC_GET_ENCAPSULATED_RESPONSE */ - if ((setup->bRequestType == 0xa1) && (setup->bRequest == 0x01)) { - /* USB_CDC_GET_ENCAPSULATED_RESPONSE */ - goto delegate; - } - - /* We process some stardard setup requests here */ - switch (setup->bRequest) { - case USB_REQ_GET_STATUS: - dev_dbg(&dev->pdev->dev, "SETUP: USB_REQ_GET_STATUS\n"); - /* get status, DATA and STATUS phase */ - if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK)) - != (USB_DIR_IN | USB_TYPE_STANDARD)) - break; - get_status(dev, setup->bRequestType, wValue, wIndex, wLength); - goto end; - - case USB_REQ_SET_ADDRESS: - dev_dbg(&dev->pdev->dev, "SETUP: USB_REQ_SET_ADDRESS\n"); - /* STATUS phase */ - if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD - | USB_RECIP_DEVICE)) - break; - set_address(dev, wValue, wIndex, wLength); - goto end; - - case USB_REQ_CLEAR_FEATURE: - case USB_REQ_SET_FEATURE: - /* STATUS phase */ - { - int rc = -EOPNOTSUPP; - if (setup->bRequest == USB_REQ_SET_FEATURE) - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_SET_FEATURE\n"); - else if (setup->bRequest == USB_REQ_CLEAR_FEATURE) - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_CLEAR_FEATURE\n"); - - if ((setup->bRequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) - == (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) { - struct langwell_ep *epn; - epn = get_ep_by_windex(dev, wIndex); - /* stall if endpoint doesn't exist */ - if (!epn) { - ep0_stall(dev); - goto end; - } - - if (wValue != 0 || wLength != 0 - || epn->ep_num > dev->ep_max) - break; - - spin_unlock(&dev->lock); - rc = langwell_ep_set_halt(&epn->ep, - (setup->bRequest == USB_REQ_SET_FEATURE) - ? 1 : 0); - spin_lock(&dev->lock); - - } else if ((setup->bRequestType & (USB_RECIP_MASK - | USB_TYPE_MASK)) == (USB_RECIP_DEVICE - | USB_TYPE_STANDARD)) { - rc = 0; - switch (wValue) { - case USB_DEVICE_REMOTE_WAKEUP: - if (setup->bRequest == USB_REQ_SET_FEATURE) { - dev->remote_wakeup = 1; - dev->dev_status |= (1 << wValue); - } else { - dev->remote_wakeup = 0; - dev->dev_status &= ~(1 << wValue); - } - break; - case USB_DEVICE_TEST_MODE: - dev_dbg(&dev->pdev->dev, "SETUP: TEST MODE\n"); - if ((wIndex & 0xff) || - (dev->gadget.speed != USB_SPEED_HIGH)) - ep0_stall(dev); - - switch (wIndex >> 8) { - case TEST_J: - case TEST_K: - case TEST_SE0_NAK: - case TEST_PACKET: - case TEST_FORCE_EN: - if (prime_status_phase(dev, EP_DIR_IN)) - ep0_stall(dev); - portsc1 = readl(&dev->op_regs->portsc1); - portsc1 |= (wIndex & 0xf00) << 8; - writel(portsc1, &dev->op_regs->portsc1); - goto end; - default: - rc = -EOPNOTSUPP; - } - break; - default: - rc = -EOPNOTSUPP; - break; - } - - if (!gadget_is_otg(&dev->gadget)) - break; - else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE) - dev->gadget.b_hnp_enable = 1; - else if (setup->bRequest == USB_DEVICE_A_HNP_SUPPORT) - dev->gadget.a_hnp_support = 1; - else if (setup->bRequest == - USB_DEVICE_A_ALT_HNP_SUPPORT) - dev->gadget.a_alt_hnp_support = 1; - else - break; - } else - break; - - if (rc == 0) { - if (prime_status_phase(dev, EP_DIR_IN)) - ep0_stall(dev); - } - goto end; - } - - case USB_REQ_GET_DESCRIPTOR: - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_GET_DESCRIPTOR\n"); - goto delegate; - - case USB_REQ_SET_DESCRIPTOR: - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_SET_DESCRIPTOR unsupported\n"); - goto delegate; - - case USB_REQ_GET_CONFIGURATION: - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_GET_CONFIGURATION\n"); - goto delegate; - - case USB_REQ_SET_CONFIGURATION: - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_SET_CONFIGURATION\n"); - goto delegate; - - case USB_REQ_GET_INTERFACE: - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_GET_INTERFACE\n"); - goto delegate; - - case USB_REQ_SET_INTERFACE: - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_SET_INTERFACE\n"); - goto delegate; - - case USB_REQ_SYNCH_FRAME: - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_SYNCH_FRAME unsupported\n"); - goto delegate; - - default: - /* delegate USB standard requests to the gadget driver */ - goto delegate; -delegate: - /* USB requests handled by gadget */ - if (wLength) { - /* DATA phase from gadget, STATUS phase from udc */ - dev->ep0_dir = (setup->bRequestType & USB_DIR_IN) - ? USB_DIR_IN : USB_DIR_OUT; - dev_vdbg(&dev->pdev->dev, - "dev->ep0_dir = 0x%x, wLength = %d\n", - dev->ep0_dir, wLength); - spin_unlock(&dev->lock); - if (dev->driver->setup(&dev->gadget, - &dev->local_setup_buff) < 0) - ep0_stall(dev); - spin_lock(&dev->lock); - dev->ep0_state = (setup->bRequestType & USB_DIR_IN) - ? DATA_STATE_XMIT : DATA_STATE_RECV; - } else { - /* no DATA phase, IN STATUS phase from gadget */ - dev->ep0_dir = USB_DIR_IN; - dev_vdbg(&dev->pdev->dev, - "dev->ep0_dir = 0x%x, wLength = %d\n", - dev->ep0_dir, wLength); - spin_unlock(&dev->lock); - if (dev->driver->setup(&dev->gadget, - &dev->local_setup_buff) < 0) - ep0_stall(dev); - spin_lock(&dev->lock); - dev->ep0_state = WAIT_FOR_OUT_STATUS; - } - break; - } -end: - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* transfer completion, process endpoint request and free the completed dTDs - * for this request - */ -static int process_ep_req(struct langwell_udc *dev, int index, - struct langwell_request *curr_req) -{ - struct langwell_dtd *curr_dtd; - struct langwell_dqh *curr_dqh; - int td_complete, actual, remaining_length; - int i, dir; - u8 dtd_status = 0; - int retval = 0; - - curr_dqh = &dev->ep_dqh[index]; - dir = index % 2; - - curr_dtd = curr_req->head; - td_complete = 0; - actual = curr_req->req.length; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - for (i = 0; i < curr_req->dtd_count; i++) { - - /* command execution states by dTD */ - dtd_status = curr_dtd->dtd_status; - - barrier(); - remaining_length = le16_to_cpu(curr_dtd->dtd_total); - actual -= remaining_length; - - if (!dtd_status) { - /* transfers completed successfully */ - if (!remaining_length) { - td_complete++; - dev_vdbg(&dev->pdev->dev, - "dTD transmitted successfully\n"); - } else { - if (dir) { - dev_vdbg(&dev->pdev->dev, - "TX dTD remains data\n"); - retval = -EPROTO; - break; - - } else { - td_complete++; - break; - } - } - } else { - /* transfers completed with errors */ - if (dtd_status & DTD_STS_ACTIVE) { - dev_dbg(&dev->pdev->dev, - "dTD status ACTIVE dQH[%d]\n", index); - retval = 1; - return retval; - } else if (dtd_status & DTD_STS_HALTED) { - dev_err(&dev->pdev->dev, - "dTD error %08x dQH[%d]\n", - dtd_status, index); - /* clear the errors and halt condition */ - curr_dqh->dtd_status = 0; - retval = -EPIPE; - break; - } else if (dtd_status & DTD_STS_DBE) { - dev_dbg(&dev->pdev->dev, - "data buffer (overflow) error\n"); - retval = -EPROTO; - break; - } else if (dtd_status & DTD_STS_TRE) { - dev_dbg(&dev->pdev->dev, - "transaction(ISO) error\n"); - retval = -EILSEQ; - break; - } else - dev_err(&dev->pdev->dev, - "unknown error (0x%x)!\n", - dtd_status); - } - - if (i != curr_req->dtd_count - 1) - curr_dtd = (struct langwell_dtd *) - curr_dtd->next_dtd_virt; - } - - if (retval) - return retval; - - curr_req->req.actual = actual; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* complete DATA or STATUS phase of ep0 prime status phase if needed */ -static void ep0_req_complete(struct langwell_udc *dev, - struct langwell_ep *ep0, struct langwell_request *req) -{ - u32 new_addr; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (dev->usb_state == USB_STATE_ADDRESS) { - /* set the new address */ - new_addr = (u32)dev->dev_addr; - writel(new_addr << USBADR_SHIFT, &dev->op_regs->deviceaddr); - - new_addr = USBADR(readl(&dev->op_regs->deviceaddr)); - dev_vdbg(&dev->pdev->dev, "new_addr = %d\n", new_addr); - } - - done(ep0, req, 0); - - switch (dev->ep0_state) { - case DATA_STATE_XMIT: - /* receive status phase */ - if (prime_status_phase(dev, EP_DIR_OUT)) - ep0_stall(dev); - break; - case DATA_STATE_RECV: - /* send status phase */ - if (prime_status_phase(dev, EP_DIR_IN)) - ep0_stall(dev); - break; - case WAIT_FOR_OUT_STATUS: - dev->ep0_state = WAIT_FOR_SETUP; - break; - case WAIT_FOR_SETUP: - dev_err(&dev->pdev->dev, "unexpect ep0 packets\n"); - break; - default: - ep0_stall(dev); - break; - } - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* USB transfer completion interrupt */ -static void handle_trans_complete(struct langwell_udc *dev) -{ - u32 complete_bits; - int i, ep_num, dir, bit_mask, status; - struct langwell_ep *epn; - struct langwell_request *curr_req, *temp_req; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - complete_bits = readl(&dev->op_regs->endptcomplete); - dev_vdbg(&dev->pdev->dev, "endptcomplete register: 0x%08x\n", - complete_bits); - - /* Write-Clear the bits in endptcomplete register */ - writel(complete_bits, &dev->op_regs->endptcomplete); - - if (!complete_bits) { - dev_dbg(&dev->pdev->dev, "complete_bits = 0\n"); - goto done; - } - - for (i = 0; i < dev->ep_max; i++) { - ep_num = i / 2; - dir = i % 2; - - bit_mask = 1 << (ep_num + 16 * dir); - - if (!(complete_bits & bit_mask)) - continue; - - /* ep0 */ - if (i == 1) - epn = &dev->ep[0]; - else - epn = &dev->ep[i]; - - if (epn->name == NULL) { - dev_warn(&dev->pdev->dev, "invalid endpoint\n"); - continue; - } - - if (i < 2) - /* ep0 in and out */ - dev_dbg(&dev->pdev->dev, "%s-%s transfer completed\n", - epn->name, - is_in(epn) ? "in" : "out"); - else - dev_dbg(&dev->pdev->dev, "%s transfer completed\n", - epn->name); - - /* process the req queue until an uncomplete request */ - list_for_each_entry_safe(curr_req, temp_req, - &epn->queue, queue) { - status = process_ep_req(dev, i, curr_req); - dev_vdbg(&dev->pdev->dev, "%s req status: %d\n", - epn->name, status); - - if (status) - break; - - /* write back status to req */ - curr_req->req.status = status; - - /* ep0 request completion */ - if (ep_num == 0) { - ep0_req_complete(dev, epn, curr_req); - break; - } else { - done(epn, curr_req, status); - } - } - } -done: - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - -/* port change detect interrupt handler */ -static void handle_port_change(struct langwell_udc *dev) -{ - u32 portsc1, devlc; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (dev->bus_reset) - dev->bus_reset = 0; - - portsc1 = readl(&dev->op_regs->portsc1); - devlc = readl(&dev->op_regs->devlc); - dev_vdbg(&dev->pdev->dev, "portsc1 = 0x%08x, devlc = 0x%08x\n", - portsc1, devlc); - - /* bus reset is finished */ - if (!(portsc1 & PORTS_PR)) { - /* get the speed */ - dev->gadget.speed = lpm_device_speed(devlc); - dev_vdbg(&dev->pdev->dev, "dev->gadget.speed = %d\n", - dev->gadget.speed); - } - - /* LPM L0 to L1 */ - if (dev->lpm && dev->lpm_state == LPM_L0) - if (portsc1 & PORTS_SUSP && portsc1 & PORTS_SLP) { - dev_info(&dev->pdev->dev, "LPM L0 to L1\n"); - dev->lpm_state = LPM_L1; - } - - /* LPM L1 to L0, force resume or remote wakeup finished */ - if (dev->lpm && dev->lpm_state == LPM_L1) - if (!(portsc1 & PORTS_SUSP)) { - dev_info(&dev->pdev->dev, "LPM L1 to L0\n"); - dev->lpm_state = LPM_L0; - } - - /* update USB state */ - if (!dev->resume_state) - dev->usb_state = USB_STATE_DEFAULT; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* USB reset interrupt handler */ -static void handle_usb_reset(struct langwell_udc *dev) -{ - u32 deviceaddr, - endptsetupstat, - endptcomplete; - unsigned long timeout; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* Write-Clear the device address */ - deviceaddr = readl(&dev->op_regs->deviceaddr); - writel(deviceaddr & ~USBADR_MASK, &dev->op_regs->deviceaddr); - - dev->dev_addr = 0; - - /* clear usb state */ - dev->resume_state = 0; - - /* LPM L1 to L0, reset */ - if (dev->lpm) - dev->lpm_state = LPM_L0; - - dev->ep0_dir = USB_DIR_OUT; - dev->ep0_state = WAIT_FOR_SETUP; - - /* remote wakeup reset to 0 when the device is reset */ - dev->remote_wakeup = 0; - dev->dev_status = 1 << USB_DEVICE_SELF_POWERED; - dev->gadget.b_hnp_enable = 0; - dev->gadget.a_hnp_support = 0; - dev->gadget.a_alt_hnp_support = 0; - - /* Write-Clear all the setup token semaphores */ - endptsetupstat = readl(&dev->op_regs->endptsetupstat); - writel(endptsetupstat, &dev->op_regs->endptsetupstat); - - /* Write-Clear all the endpoint complete status bits */ - endptcomplete = readl(&dev->op_regs->endptcomplete); - writel(endptcomplete, &dev->op_regs->endptcomplete); - - /* wait until all endptprime bits cleared */ - timeout = jiffies + PRIME_TIMEOUT; - while (readl(&dev->op_regs->endptprime)) { - if (time_after(jiffies, timeout)) { - dev_err(&dev->pdev->dev, "USB reset timeout\n"); - break; - } - cpu_relax(); - } - - /* write 1s to endptflush register to clear any primed buffers */ - writel((u32) ~0, &dev->op_regs->endptflush); - - if (readl(&dev->op_regs->portsc1) & PORTS_PR) { - dev_vdbg(&dev->pdev->dev, "USB bus reset\n"); - /* bus is reseting */ - dev->bus_reset = 1; - - /* reset all the queues, stop all USB activities */ - stop_activity(dev); - dev->usb_state = USB_STATE_DEFAULT; - } else { - dev_vdbg(&dev->pdev->dev, "device controller reset\n"); - /* controller reset */ - langwell_udc_reset(dev); - - /* reset all the queues, stop all USB activities */ - stop_activity(dev); - - /* reset ep0 dQH and endptctrl */ - ep0_reset(dev); - - /* enable interrupt and set controller to run state */ - langwell_udc_start(dev); - - dev->usb_state = USB_STATE_ATTACHED; - } - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* USB bus suspend/resume interrupt */ -static void handle_bus_suspend(struct langwell_udc *dev) -{ - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - dev->resume_state = dev->usb_state; - dev->usb_state = USB_STATE_SUSPENDED; - - /* report suspend to the driver */ - if (dev->driver) { - if (dev->driver->suspend) { - spin_unlock(&dev->lock); - dev->driver->suspend(&dev->gadget); - spin_lock(&dev->lock); - dev_dbg(&dev->pdev->dev, "suspend %s\n", - dev->driver->driver.name); - } - } - - /* enter PHY low power suspend */ - if (dev->pdev->device != 0x0829) - langwell_phy_low_power(dev, 0); - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -static void handle_bus_resume(struct langwell_udc *dev) -{ - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - dev->usb_state = dev->resume_state; - dev->resume_state = 0; - - /* exit PHY low power suspend */ - if (dev->pdev->device != 0x0829) - langwell_phy_low_power(dev, 0); - - /* report resume to the driver */ - if (dev->driver) { - if (dev->driver->resume) { - spin_unlock(&dev->lock); - dev->driver->resume(&dev->gadget); - spin_lock(&dev->lock); - dev_dbg(&dev->pdev->dev, "resume %s\n", - dev->driver->driver.name); - } - } - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* USB device controller interrupt handler */ -static irqreturn_t langwell_irq(int irq, void *_dev) -{ - struct langwell_udc *dev = _dev; - u32 usbsts, - usbintr, - irq_sts, - portsc1; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (dev->stopped) { - dev_vdbg(&dev->pdev->dev, "handle IRQ_NONE\n"); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return IRQ_NONE; - } - - spin_lock(&dev->lock); - - /* USB status */ - usbsts = readl(&dev->op_regs->usbsts); - - /* USB interrupt enable */ - usbintr = readl(&dev->op_regs->usbintr); - - irq_sts = usbsts & usbintr; - dev_vdbg(&dev->pdev->dev, - "usbsts = 0x%08x, usbintr = 0x%08x, irq_sts = 0x%08x\n", - usbsts, usbintr, irq_sts); - - if (!irq_sts) { - dev_vdbg(&dev->pdev->dev, "handle IRQ_NONE\n"); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - spin_unlock(&dev->lock); - return IRQ_NONE; - } - - /* Write-Clear interrupt status bits */ - writel(irq_sts, &dev->op_regs->usbsts); - - /* resume from suspend */ - portsc1 = readl(&dev->op_regs->portsc1); - if (dev->usb_state == USB_STATE_SUSPENDED) - if (!(portsc1 & PORTS_SUSP)) - handle_bus_resume(dev); - - /* USB interrupt */ - if (irq_sts & STS_UI) { - dev_vdbg(&dev->pdev->dev, "USB interrupt\n"); - - /* setup packet received from ep0 */ - if (readl(&dev->op_regs->endptsetupstat) - & EP0SETUPSTAT_MASK) { - dev_vdbg(&dev->pdev->dev, - "USB SETUP packet received interrupt\n"); - /* setup tripwire semaphone */ - setup_tripwire(dev); - handle_setup_packet(dev, &dev->local_setup_buff); - } - - /* USB transfer completion */ - if (readl(&dev->op_regs->endptcomplete)) { - dev_vdbg(&dev->pdev->dev, - "USB transfer completion interrupt\n"); - handle_trans_complete(dev); - } - } - - /* SOF received interrupt (for ISO transfer) */ - if (irq_sts & STS_SRI) { - /* FIXME */ - /* dev_vdbg(&dev->pdev->dev, "SOF received interrupt\n"); */ - } - - /* port change detect interrupt */ - if (irq_sts & STS_PCI) { - dev_vdbg(&dev->pdev->dev, "port change detect interrupt\n"); - handle_port_change(dev); - } - - /* suspend interrupt */ - if (irq_sts & STS_SLI) { - dev_vdbg(&dev->pdev->dev, "suspend interrupt\n"); - handle_bus_suspend(dev); - } - - /* USB reset interrupt */ - if (irq_sts & STS_URI) { - dev_vdbg(&dev->pdev->dev, "USB reset interrupt\n"); - handle_usb_reset(dev); - } - - /* USB error or system error interrupt */ - if (irq_sts & (STS_UEI | STS_SEI)) { - /* FIXME */ - dev_warn(&dev->pdev->dev, "error IRQ, irq_sts: %x\n", irq_sts); - } - - spin_unlock(&dev->lock); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return IRQ_HANDLED; -} - - -/*-------------------------------------------------------------------------*/ - -/* release device structure */ -static void gadget_release(struct device *_dev) -{ - struct langwell_udc *dev = dev_get_drvdata(_dev); - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - complete(dev->done); - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - kfree(dev); -} - - -/* enable SRAM caching if SRAM detected */ -static void sram_init(struct langwell_udc *dev) -{ - struct pci_dev *pdev = dev->pdev; - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - dev->sram_addr = pci_resource_start(pdev, 1); - dev->sram_size = pci_resource_len(pdev, 1); - dev_info(&dev->pdev->dev, "Found private SRAM at %x size:%x\n", - dev->sram_addr, dev->sram_size); - dev->got_sram = 1; - - if (pci_request_region(pdev, 1, kobject_name(&pdev->dev.kobj))) { - dev_warn(&dev->pdev->dev, "SRAM request failed\n"); - dev->got_sram = 0; - } else if (!dma_declare_coherent_memory(&pdev->dev, dev->sram_addr, - dev->sram_addr, dev->sram_size, DMA_MEMORY_MAP)) { - dev_warn(&dev->pdev->dev, "SRAM DMA declare failed\n"); - pci_release_region(pdev, 1); - dev->got_sram = 0; - } - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* release SRAM caching */ -static void sram_deinit(struct langwell_udc *dev) -{ - struct pci_dev *pdev = dev->pdev; - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - dma_release_declared_memory(&pdev->dev); - pci_release_region(pdev, 1); - - dev->got_sram = 0; - - dev_info(&dev->pdev->dev, "release SRAM caching\n"); - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* tear down the binding between this driver and the pci device */ -static void langwell_udc_remove(struct pci_dev *pdev) -{ - struct langwell_udc *dev = pci_get_drvdata(pdev); - - DECLARE_COMPLETION(done); - - BUG_ON(dev->driver); - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - dev->done = &done; - - /* free dTD dma_pool and dQH */ - if (dev->dtd_pool) - dma_pool_destroy(dev->dtd_pool); - - if (dev->ep_dqh) - dma_free_coherent(&pdev->dev, dev->ep_dqh_size, - dev->ep_dqh, dev->ep_dqh_dma); - - /* release SRAM caching */ - if (dev->has_sram && dev->got_sram) - sram_deinit(dev); - - if (dev->status_req) { - kfree(dev->status_req->req.buf); - kfree(dev->status_req); - } - - kfree(dev->ep); - - /* disable IRQ handler */ - if (dev->got_irq) - free_irq(pdev->irq, dev); - - if (dev->cap_regs) - iounmap(dev->cap_regs); - - if (dev->region) - release_mem_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - - if (dev->enabled) - pci_disable_device(pdev); - - dev->cap_regs = NULL; - - dev_info(&dev->pdev->dev, "unbind\n"); - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - - device_unregister(&dev->gadget.dev); - device_remove_file(&pdev->dev, &dev_attr_langwell_udc); - device_remove_file(&pdev->dev, &dev_attr_remote_wakeup); - - pci_set_drvdata(pdev, NULL); - - /* free dev, wait for the release() finished */ - wait_for_completion(&done); -} - - -/* - * wrap this driver around the specified device, but - * don't respond over USB until a gadget driver binds to us. - */ -static int langwell_udc_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - struct langwell_udc *dev; - unsigned long resource, len; - void __iomem *base = NULL; - size_t size; - int retval; - - /* alloc, and start init */ - dev = kzalloc(sizeof *dev, GFP_KERNEL); - if (dev == NULL) { - retval = -ENOMEM; - goto error; - } - - /* initialize device spinlock */ - spin_lock_init(&dev->lock); - - dev->pdev = pdev; - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - pci_set_drvdata(pdev, dev); - - /* now all the pci goodies ... */ - if (pci_enable_device(pdev) < 0) { - retval = -ENODEV; - goto error; - } - dev->enabled = 1; - - /* control register: BAR 0 */ - resource = pci_resource_start(pdev, 0); - len = pci_resource_len(pdev, 0); - if (!request_mem_region(resource, len, driver_name)) { - dev_err(&dev->pdev->dev, "controller already in use\n"); - retval = -EBUSY; - goto error; - } - dev->region = 1; - - base = ioremap_nocache(resource, len); - if (base == NULL) { - dev_err(&dev->pdev->dev, "can't map memory\n"); - retval = -EFAULT; - goto error; - } - - dev->cap_regs = (struct langwell_cap_regs __iomem *) base; - dev_vdbg(&dev->pdev->dev, "dev->cap_regs: %p\n", dev->cap_regs); - dev->op_regs = (struct langwell_op_regs __iomem *) - (base + OP_REG_OFFSET); - dev_vdbg(&dev->pdev->dev, "dev->op_regs: %p\n", dev->op_regs); - - /* irq setup after old hardware is cleaned up */ - if (!pdev->irq) { - dev_err(&dev->pdev->dev, "No IRQ. Check PCI setup!\n"); - retval = -ENODEV; - goto error; - } - - dev->has_sram = 1; - dev->got_sram = 0; - dev_vdbg(&dev->pdev->dev, "dev->has_sram: %d\n", dev->has_sram); - - /* enable SRAM caching if detected */ - if (dev->has_sram && !dev->got_sram) - sram_init(dev); - - dev_info(&dev->pdev->dev, - "irq %d, io mem: 0x%08lx, len: 0x%08lx, pci mem 0x%p\n", - pdev->irq, resource, len, base); - /* enables bus-mastering for device dev */ - pci_set_master(pdev); - - if (request_irq(pdev->irq, langwell_irq, IRQF_SHARED, - driver_name, dev) != 0) { - dev_err(&dev->pdev->dev, - "request interrupt %d failed\n", pdev->irq); - retval = -EBUSY; - goto error; - } - dev->got_irq = 1; - - /* set stopped bit */ - dev->stopped = 1; - - /* capabilities and endpoint number */ - dev->lpm = (readl(&dev->cap_regs->hccparams) & HCC_LEN) ? 1 : 0; - dev->dciversion = readw(&dev->cap_regs->dciversion); - dev->devcap = (readl(&dev->cap_regs->dccparams) & DEVCAP) ? 1 : 0; - dev_vdbg(&dev->pdev->dev, "dev->lpm: %d\n", dev->lpm); - dev_vdbg(&dev->pdev->dev, "dev->dciversion: 0x%04x\n", - dev->dciversion); - dev_vdbg(&dev->pdev->dev, "dccparams: 0x%08x\n", - readl(&dev->cap_regs->dccparams)); - dev_vdbg(&dev->pdev->dev, "dev->devcap: %d\n", dev->devcap); - if (!dev->devcap) { - dev_err(&dev->pdev->dev, "can't support device mode\n"); - retval = -ENODEV; - goto error; - } - - /* a pair of endpoints (out/in) for each address */ - dev->ep_max = DEN(readl(&dev->cap_regs->dccparams)) * 2; - dev_vdbg(&dev->pdev->dev, "dev->ep_max: %d\n", dev->ep_max); - - /* allocate endpoints memory */ - dev->ep = kzalloc(sizeof(struct langwell_ep) * dev->ep_max, - GFP_KERNEL); - if (!dev->ep) { - dev_err(&dev->pdev->dev, "allocate endpoints memory failed\n"); - retval = -ENOMEM; - goto error; - } - - /* allocate device dQH memory */ - size = dev->ep_max * sizeof(struct langwell_dqh); - dev_vdbg(&dev->pdev->dev, "orig size = %zd\n", size); - if (size < DQH_ALIGNMENT) - size = DQH_ALIGNMENT; - else if ((size % DQH_ALIGNMENT) != 0) { - size += DQH_ALIGNMENT + 1; - size &= ~(DQH_ALIGNMENT - 1); - } - dev->ep_dqh = dma_alloc_coherent(&pdev->dev, size, - &dev->ep_dqh_dma, GFP_KERNEL); - if (!dev->ep_dqh) { - dev_err(&dev->pdev->dev, "allocate dQH memory failed\n"); - retval = -ENOMEM; - goto error; - } - dev->ep_dqh_size = size; - dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %zd\n", dev->ep_dqh_size); - - /* initialize ep0 status request structure */ - dev->status_req = kzalloc(sizeof(struct langwell_request), GFP_KERNEL); - if (!dev->status_req) { - dev_err(&dev->pdev->dev, - "allocate status_req memory failed\n"); - retval = -ENOMEM; - goto error; - } - INIT_LIST_HEAD(&dev->status_req->queue); - - /* allocate a small amount of memory to get valid address */ - dev->status_req->req.buf = kmalloc(8, GFP_KERNEL); - dev->status_req->req.dma = virt_to_phys(dev->status_req->req.buf); - - dev->resume_state = USB_STATE_NOTATTACHED; - dev->usb_state = USB_STATE_POWERED; - dev->ep0_dir = USB_DIR_OUT; - - /* remote wakeup reset to 0 when the device is reset */ - dev->remote_wakeup = 0; - dev->dev_status = 1 << USB_DEVICE_SELF_POWERED; - - /* reset device controller */ - langwell_udc_reset(dev); - - /* initialize gadget structure */ - dev->gadget.ops = &langwell_ops; /* usb_gadget_ops */ - dev->gadget.ep0 = &dev->ep[0].ep; /* gadget ep0 */ - INIT_LIST_HEAD(&dev->gadget.ep_list); /* ep_list */ - dev->gadget.speed = USB_SPEED_UNKNOWN; /* speed */ - dev->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */ - - /* the "gadget" abstracts/virtualizes the controller */ - dev_set_name(&dev->gadget.dev, "gadget"); - dev->gadget.dev.parent = &pdev->dev; - dev->gadget.dev.dma_mask = pdev->dev.dma_mask; - dev->gadget.dev.release = gadget_release; - dev->gadget.name = driver_name; /* gadget name */ - - /* controller endpoints reinit */ - eps_reinit(dev); - - /* reset ep0 dQH and endptctrl */ - ep0_reset(dev); - - /* create dTD dma_pool resource */ - dev->dtd_pool = dma_pool_create("langwell_dtd", - &dev->pdev->dev, - sizeof(struct langwell_dtd), - DTD_ALIGNMENT, - DMA_BOUNDARY); - - if (!dev->dtd_pool) { - retval = -ENOMEM; - goto error; - } - - /* done */ - dev_info(&dev->pdev->dev, "%s\n", driver_desc); - dev_info(&dev->pdev->dev, "irq %d, pci mem %p\n", pdev->irq, base); - dev_info(&dev->pdev->dev, "Driver version: " DRIVER_VERSION "\n"); - dev_info(&dev->pdev->dev, "Support (max) %d endpoints\n", dev->ep_max); - dev_info(&dev->pdev->dev, "Device interface version: 0x%04x\n", - dev->dciversion); - dev_info(&dev->pdev->dev, "Controller mode: %s\n", - dev->devcap ? "Device" : "Host"); - dev_info(&dev->pdev->dev, "Support USB LPM: %s\n", - dev->lpm ? "Yes" : "No"); - - dev_vdbg(&dev->pdev->dev, - "After langwell_udc_probe(), print all registers:\n"); - print_all_registers(dev); - - retval = device_register(&dev->gadget.dev); - if (retval) - goto error; - - retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); - if (retval) - goto error; - - retval = device_create_file(&pdev->dev, &dev_attr_langwell_udc); - if (retval) - goto error; - - retval = device_create_file(&pdev->dev, &dev_attr_remote_wakeup); - if (retval) - goto error_attr1; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; - -error_attr1: - device_remove_file(&pdev->dev, &dev_attr_langwell_udc); -error: - if (dev) { - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - langwell_udc_remove(pdev); - } - - return retval; -} - - -/* device controller suspend */ -static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct langwell_udc *dev = pci_get_drvdata(pdev); - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - usb_del_gadget_udc(&dev->gadget); - /* disable interrupt and set controller to stop state */ - langwell_udc_stop(dev); - - /* disable IRQ handler */ - if (dev->got_irq) - free_irq(pdev->irq, dev); - dev->got_irq = 0; - - /* save PCI state */ - pci_save_state(pdev); - - spin_lock_irq(&dev->lock); - /* stop all usb activities */ - stop_activity(dev); - spin_unlock_irq(&dev->lock); - - /* free dTD dma_pool and dQH */ - if (dev->dtd_pool) - dma_pool_destroy(dev->dtd_pool); - - if (dev->ep_dqh) - dma_free_coherent(&pdev->dev, dev->ep_dqh_size, - dev->ep_dqh, dev->ep_dqh_dma); - - /* release SRAM caching */ - if (dev->has_sram && dev->got_sram) - sram_deinit(dev); - - /* set device power state */ - pci_set_power_state(pdev, PCI_D3hot); - - /* enter PHY low power suspend */ - if (dev->pdev->device != 0x0829) - langwell_phy_low_power(dev, 1); - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* device controller resume */ -static int langwell_udc_resume(struct pci_dev *pdev) -{ - struct langwell_udc *dev = pci_get_drvdata(pdev); - size_t size; - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* exit PHY low power suspend */ - if (dev->pdev->device != 0x0829) - langwell_phy_low_power(dev, 0); - - /* set device D0 power state */ - pci_set_power_state(pdev, PCI_D0); - - /* enable SRAM caching if detected */ - if (dev->has_sram && !dev->got_sram) - sram_init(dev); - - /* allocate device dQH memory */ - size = dev->ep_max * sizeof(struct langwell_dqh); - dev_vdbg(&dev->pdev->dev, "orig size = %zd\n", size); - if (size < DQH_ALIGNMENT) - size = DQH_ALIGNMENT; - else if ((size % DQH_ALIGNMENT) != 0) { - size += DQH_ALIGNMENT + 1; - size &= ~(DQH_ALIGNMENT - 1); - } - dev->ep_dqh = dma_alloc_coherent(&pdev->dev, size, - &dev->ep_dqh_dma, GFP_KERNEL); - if (!dev->ep_dqh) { - dev_err(&dev->pdev->dev, "allocate dQH memory failed\n"); - return -ENOMEM; - } - dev->ep_dqh_size = size; - dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %zd\n", dev->ep_dqh_size); - - /* create dTD dma_pool resource */ - dev->dtd_pool = dma_pool_create("langwell_dtd", - &dev->pdev->dev, - sizeof(struct langwell_dtd), - DTD_ALIGNMENT, - DMA_BOUNDARY); - - if (!dev->dtd_pool) - return -ENOMEM; - - /* restore PCI state */ - pci_restore_state(pdev); - - /* enable IRQ handler */ - if (request_irq(pdev->irq, langwell_irq, IRQF_SHARED, - driver_name, dev) != 0) { - dev_err(&dev->pdev->dev, "request interrupt %d failed\n", - pdev->irq); - return -EBUSY; - } - dev->got_irq = 1; - - /* reset and start controller to run state */ - if (dev->stopped) { - /* reset device controller */ - langwell_udc_reset(dev); - - /* reset ep0 dQH and endptctrl */ - ep0_reset(dev); - - /* start device if gadget is loaded */ - if (dev->driver) - langwell_udc_start(dev); - } - - /* reset USB status */ - dev->usb_state = USB_STATE_ATTACHED; - dev->ep0_state = WAIT_FOR_SETUP; - dev->ep0_dir = USB_DIR_OUT; - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* pci driver shutdown */ -static void langwell_udc_shutdown(struct pci_dev *pdev) -{ - struct langwell_udc *dev = pci_get_drvdata(pdev); - u32 usbmode; - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* reset controller mode to IDLE */ - usbmode = readl(&dev->op_regs->usbmode); - dev_dbg(&dev->pdev->dev, "usbmode = 0x%08x\n", usbmode); - usbmode &= (~3 | MODE_IDLE); - writel(usbmode, &dev->op_regs->usbmode); - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - -/*-------------------------------------------------------------------------*/ - -static const struct pci_device_id pci_ids[] = { { - .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), - .class_mask = ~0, - .vendor = 0x8086, - .device = 0x0811, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, -}, { /* end: all zeroes */ } -}; - -MODULE_DEVICE_TABLE(pci, pci_ids); - - -static struct pci_driver langwell_pci_driver = { - .name = (char *) driver_name, - .id_table = pci_ids, - - .probe = langwell_udc_probe, - .remove = langwell_udc_remove, - - /* device controller suspend/resume */ - .suspend = langwell_udc_suspend, - .resume = langwell_udc_resume, - - .shutdown = langwell_udc_shutdown, -}; - - -static int __init init(void) -{ - return pci_register_driver(&langwell_pci_driver); -} -module_init(init); - - -static void __exit cleanup(void) -{ - pci_unregister_driver(&langwell_pci_driver); -} -module_exit(cleanup); - - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Xiaochen Shen "); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/langwell_udc.h b/ANDROID_3.4.5/drivers/usb/gadget/langwell_udc.h deleted file mode 100644 index 8c8087ab..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/langwell_udc.h +++ /dev/null @@ -1,224 +0,0 @@ -/* - * 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. - */ - -#include - -/*-------------------------------------------------------------------------*/ - -/* 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 usb_phy *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 */ - has_sram:1, /* SRAM caching */ - got_sram:1; - - /* 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; - - /* for private SRAM caching */ - unsigned int sram_addr; - unsigned int sram_size; - - /* device status data for get_status request */ - u16 dev_status; -}; - -#define gadget_to_langwell(g) container_of((g), struct langwell_udc, gadget) - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/m66592-udc.c b/ANDROID_3.4.5/drivers/usb/gadget/m66592-udc.c deleted file mode 100644 index 3608b3bd..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/m66592-udc.c +++ /dev/null @@ -1,1773 +0,0 @@ -/* - * M66592 UDC (USB gadget) - * - * Copyright (C) 2006-2007 Renesas Solutions Corp. - * - * Author : Yoshihiro Shimoda - * - * 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; version 2 of the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "m66592-udc.h" - -MODULE_DESCRIPTION("M66592 USB gadget driver"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Yoshihiro Shimoda"); -MODULE_ALIAS("platform:m66592_udc"); - -#define DRIVER_VERSION "21 July 2009" - -static const char udc_name[] = "m66592_udc"; -static const char *m66592_ep_name[] = { - "ep0", "ep1", "ep2", "ep3", "ep4", "ep5", "ep6", "ep7" -}; - -static void disable_controller(struct m66592 *m66592); -static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req); -static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req); -static int m66592_queue(struct usb_ep *_ep, struct usb_request *_req, - gfp_t gfp_flags); - -static void transfer_complete(struct m66592_ep *ep, - struct m66592_request *req, int status); - -/*-------------------------------------------------------------------------*/ -static inline u16 get_usb_speed(struct m66592 *m66592) -{ - return (m66592_read(m66592, M66592_DVSTCTR) & M66592_RHST); -} - -static void enable_pipe_irq(struct m66592 *m66592, u16 pipenum, - unsigned long reg) -{ - u16 tmp; - - tmp = m66592_read(m66592, M66592_INTENB0); - m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE, - M66592_INTENB0); - m66592_bset(m66592, (1 << pipenum), reg); - m66592_write(m66592, tmp, M66592_INTENB0); -} - -static void disable_pipe_irq(struct m66592 *m66592, u16 pipenum, - unsigned long reg) -{ - u16 tmp; - - tmp = m66592_read(m66592, M66592_INTENB0); - m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE, - M66592_INTENB0); - m66592_bclr(m66592, (1 << pipenum), reg); - m66592_write(m66592, tmp, M66592_INTENB0); -} - -static void m66592_usb_connect(struct m66592 *m66592) -{ - m66592_bset(m66592, M66592_CTRE, M66592_INTENB0); - m66592_bset(m66592, M66592_WDST | M66592_RDST | M66592_CMPL, - M66592_INTENB0); - m66592_bset(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0); - - m66592_bset(m66592, M66592_DPRPU, M66592_SYSCFG); -} - -static void m66592_usb_disconnect(struct m66592 *m66592) -__releases(m66592->lock) -__acquires(m66592->lock) -{ - m66592_bclr(m66592, M66592_CTRE, M66592_INTENB0); - m66592_bclr(m66592, M66592_WDST | M66592_RDST | M66592_CMPL, - M66592_INTENB0); - m66592_bclr(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0); - m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG); - - m66592->gadget.speed = USB_SPEED_UNKNOWN; - spin_unlock(&m66592->lock); - m66592->driver->disconnect(&m66592->gadget); - spin_lock(&m66592->lock); - - disable_controller(m66592); - INIT_LIST_HEAD(&m66592->ep[0].queue); -} - -static inline u16 control_reg_get_pid(struct m66592 *m66592, u16 pipenum) -{ - u16 pid = 0; - unsigned long offset; - - if (pipenum == 0) - pid = m66592_read(m66592, M66592_DCPCTR) & M66592_PID; - else if (pipenum < M66592_MAX_NUM_PIPE) { - offset = get_pipectr_addr(pipenum); - pid = m66592_read(m66592, offset) & M66592_PID; - } else - pr_err("unexpect pipe num (%d)\n", pipenum); - - return pid; -} - -static inline void control_reg_set_pid(struct m66592 *m66592, u16 pipenum, - u16 pid) -{ - unsigned long offset; - - if (pipenum == 0) - m66592_mdfy(m66592, pid, M66592_PID, M66592_DCPCTR); - else if (pipenum < M66592_MAX_NUM_PIPE) { - offset = get_pipectr_addr(pipenum); - m66592_mdfy(m66592, pid, M66592_PID, offset); - } else - pr_err("unexpect pipe num (%d)\n", pipenum); -} - -static inline void pipe_start(struct m66592 *m66592, u16 pipenum) -{ - control_reg_set_pid(m66592, pipenum, M66592_PID_BUF); -} - -static inline void pipe_stop(struct m66592 *m66592, u16 pipenum) -{ - control_reg_set_pid(m66592, pipenum, M66592_PID_NAK); -} - -static inline void pipe_stall(struct m66592 *m66592, u16 pipenum) -{ - control_reg_set_pid(m66592, pipenum, M66592_PID_STALL); -} - -static inline u16 control_reg_get(struct m66592 *m66592, u16 pipenum) -{ - u16 ret = 0; - unsigned long offset; - - if (pipenum == 0) - ret = m66592_read(m66592, M66592_DCPCTR); - else if (pipenum < M66592_MAX_NUM_PIPE) { - offset = get_pipectr_addr(pipenum); - ret = m66592_read(m66592, offset); - } else - pr_err("unexpect pipe num (%d)\n", pipenum); - - return ret; -} - -static inline void control_reg_sqclr(struct m66592 *m66592, u16 pipenum) -{ - unsigned long offset; - - pipe_stop(m66592, pipenum); - - if (pipenum == 0) - m66592_bset(m66592, M66592_SQCLR, M66592_DCPCTR); - else if (pipenum < M66592_MAX_NUM_PIPE) { - offset = get_pipectr_addr(pipenum); - m66592_bset(m66592, M66592_SQCLR, offset); - } else - pr_err("unexpect pipe num(%d)\n", pipenum); -} - -static inline int get_buffer_size(struct m66592 *m66592, u16 pipenum) -{ - u16 tmp; - int size; - - if (pipenum == 0) { - tmp = m66592_read(m66592, M66592_DCPCFG); - if ((tmp & M66592_CNTMD) != 0) - size = 256; - else { - tmp = m66592_read(m66592, M66592_DCPMAXP); - size = tmp & M66592_MAXP; - } - } else { - m66592_write(m66592, pipenum, M66592_PIPESEL); - tmp = m66592_read(m66592, M66592_PIPECFG); - if ((tmp & M66592_CNTMD) != 0) { - tmp = m66592_read(m66592, M66592_PIPEBUF); - size = ((tmp >> 10) + 1) * 64; - } else { - tmp = m66592_read(m66592, M66592_PIPEMAXP); - size = tmp & M66592_MXPS; - } - } - - return size; -} - -static inline void pipe_change(struct m66592 *m66592, u16 pipenum) -{ - struct m66592_ep *ep = m66592->pipenum2ep[pipenum]; - unsigned short mbw; - - if (ep->use_dma) - return; - - m66592_mdfy(m66592, pipenum, M66592_CURPIPE, ep->fifosel); - - ndelay(450); - - if (m66592->pdata->on_chip) - mbw = M66592_MBW_32; - else - mbw = M66592_MBW_16; - - m66592_bset(m66592, mbw, ep->fifosel); -} - -static int pipe_buffer_setting(struct m66592 *m66592, - struct m66592_pipe_info *info) -{ - u16 bufnum = 0, buf_bsize = 0; - u16 pipecfg = 0; - - if (info->pipe == 0) - return -EINVAL; - - m66592_write(m66592, info->pipe, M66592_PIPESEL); - - if (info->dir_in) - pipecfg |= M66592_DIR; - pipecfg |= info->type; - pipecfg |= info->epnum; - switch (info->type) { - case M66592_INT: - bufnum = 4 + (info->pipe - M66592_BASE_PIPENUM_INT); - buf_bsize = 0; - break; - case M66592_BULK: - /* isochronous pipes may be used as bulk pipes */ - if (info->pipe >= M66592_BASE_PIPENUM_BULK) - bufnum = info->pipe - M66592_BASE_PIPENUM_BULK; - else - bufnum = info->pipe - M66592_BASE_PIPENUM_ISOC; - - bufnum = M66592_BASE_BUFNUM + (bufnum * 16); - buf_bsize = 7; - pipecfg |= M66592_DBLB; - if (!info->dir_in) - pipecfg |= M66592_SHTNAK; - break; - case M66592_ISO: - bufnum = M66592_BASE_BUFNUM + - (info->pipe - M66592_BASE_PIPENUM_ISOC) * 16; - buf_bsize = 7; - break; - } - - if (buf_bsize && ((bufnum + 16) >= M66592_MAX_BUFNUM)) { - pr_err("m66592 pipe memory is insufficient\n"); - return -ENOMEM; - } - - m66592_write(m66592, pipecfg, M66592_PIPECFG); - m66592_write(m66592, (buf_bsize << 10) | (bufnum), M66592_PIPEBUF); - m66592_write(m66592, info->maxpacket, M66592_PIPEMAXP); - if (info->interval) - info->interval--; - m66592_write(m66592, info->interval, M66592_PIPEPERI); - - return 0; -} - -static void pipe_buffer_release(struct m66592 *m66592, - struct m66592_pipe_info *info) -{ - if (info->pipe == 0) - return; - - if (is_bulk_pipe(info->pipe)) { - m66592->bulk--; - } else if (is_interrupt_pipe(info->pipe)) - m66592->interrupt--; - else if (is_isoc_pipe(info->pipe)) { - m66592->isochronous--; - if (info->type == M66592_BULK) - m66592->bulk--; - } else - pr_err("ep_release: unexpect pipenum (%d)\n", - info->pipe); -} - -static void pipe_initialize(struct m66592_ep *ep) -{ - struct m66592 *m66592 = ep->m66592; - unsigned short mbw; - - m66592_mdfy(m66592, 0, M66592_CURPIPE, ep->fifosel); - - m66592_write(m66592, M66592_ACLRM, ep->pipectr); - m66592_write(m66592, 0, ep->pipectr); - m66592_write(m66592, M66592_SQCLR, ep->pipectr); - if (ep->use_dma) { - m66592_mdfy(m66592, ep->pipenum, M66592_CURPIPE, ep->fifosel); - - ndelay(450); - - if (m66592->pdata->on_chip) - mbw = M66592_MBW_32; - else - mbw = M66592_MBW_16; - - m66592_bset(m66592, mbw, ep->fifosel); - } -} - -static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep, - const struct usb_endpoint_descriptor *desc, - u16 pipenum, int dma) -{ - if ((pipenum != 0) && dma) { - if (m66592->num_dma == 0) { - m66592->num_dma++; - ep->use_dma = 1; - ep->fifoaddr = M66592_D0FIFO; - ep->fifosel = M66592_D0FIFOSEL; - ep->fifoctr = M66592_D0FIFOCTR; - ep->fifotrn = M66592_D0FIFOTRN; - } else if (!m66592->pdata->on_chip && m66592->num_dma == 1) { - m66592->num_dma++; - ep->use_dma = 1; - ep->fifoaddr = M66592_D1FIFO; - ep->fifosel = M66592_D1FIFOSEL; - ep->fifoctr = M66592_D1FIFOCTR; - ep->fifotrn = M66592_D1FIFOTRN; - } else { - ep->use_dma = 0; - ep->fifoaddr = M66592_CFIFO; - ep->fifosel = M66592_CFIFOSEL; - ep->fifoctr = M66592_CFIFOCTR; - ep->fifotrn = 0; - } - } else { - ep->use_dma = 0; - ep->fifoaddr = M66592_CFIFO; - ep->fifosel = M66592_CFIFOSEL; - ep->fifoctr = M66592_CFIFOCTR; - ep->fifotrn = 0; - } - - ep->pipectr = get_pipectr_addr(pipenum); - ep->pipenum = pipenum; - ep->ep.maxpacket = usb_endpoint_maxp(desc); - m66592->pipenum2ep[pipenum] = ep; - m66592->epaddr2ep[desc->bEndpointAddress&USB_ENDPOINT_NUMBER_MASK] = ep; - INIT_LIST_HEAD(&ep->queue); -} - -static void m66592_ep_release(struct m66592_ep *ep) -{ - struct m66592 *m66592 = ep->m66592; - u16 pipenum = ep->pipenum; - - if (pipenum == 0) - return; - - if (ep->use_dma) - m66592->num_dma--; - ep->pipenum = 0; - ep->busy = 0; - ep->use_dma = 0; -} - -static int alloc_pipe_config(struct m66592_ep *ep, - const struct usb_endpoint_descriptor *desc) -{ - struct m66592 *m66592 = ep->m66592; - struct m66592_pipe_info info; - int dma = 0; - int *counter; - int ret; - - ep->desc = desc; - - BUG_ON(ep->pipenum); - - switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { - case USB_ENDPOINT_XFER_BULK: - if (m66592->bulk >= M66592_MAX_NUM_BULK) { - if (m66592->isochronous >= M66592_MAX_NUM_ISOC) { - pr_err("bulk pipe is insufficient\n"); - return -ENODEV; - } else { - info.pipe = M66592_BASE_PIPENUM_ISOC - + m66592->isochronous; - counter = &m66592->isochronous; - } - } else { - info.pipe = M66592_BASE_PIPENUM_BULK + m66592->bulk; - counter = &m66592->bulk; - } - info.type = M66592_BULK; - dma = 1; - break; - case USB_ENDPOINT_XFER_INT: - if (m66592->interrupt >= M66592_MAX_NUM_INT) { - pr_err("interrupt pipe is insufficient\n"); - return -ENODEV; - } - info.pipe = M66592_BASE_PIPENUM_INT + m66592->interrupt; - info.type = M66592_INT; - counter = &m66592->interrupt; - break; - case USB_ENDPOINT_XFER_ISOC: - if (m66592->isochronous >= M66592_MAX_NUM_ISOC) { - pr_err("isochronous pipe is insufficient\n"); - return -ENODEV; - } - info.pipe = M66592_BASE_PIPENUM_ISOC + m66592->isochronous; - info.type = M66592_ISO; - counter = &m66592->isochronous; - break; - default: - pr_err("unexpect xfer type\n"); - return -EINVAL; - } - ep->type = info.type; - - info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - info.maxpacket = usb_endpoint_maxp(desc); - info.interval = desc->bInterval; - if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) - info.dir_in = 1; - else - info.dir_in = 0; - - ret = pipe_buffer_setting(m66592, &info); - if (ret < 0) { - pr_err("pipe_buffer_setting fail\n"); - return ret; - } - - (*counter)++; - if ((counter == &m66592->isochronous) && info.type == M66592_BULK) - m66592->bulk++; - - m66592_ep_setting(m66592, ep, desc, info.pipe, dma); - pipe_initialize(ep); - - return 0; -} - -static int free_pipe_config(struct m66592_ep *ep) -{ - struct m66592 *m66592 = ep->m66592; - struct m66592_pipe_info info; - - info.pipe = ep->pipenum; - info.type = ep->type; - pipe_buffer_release(m66592, &info); - m66592_ep_release(ep); - - return 0; -} - -/*-------------------------------------------------------------------------*/ -static void pipe_irq_enable(struct m66592 *m66592, u16 pipenum) -{ - enable_irq_ready(m66592, pipenum); - enable_irq_nrdy(m66592, pipenum); -} - -static void pipe_irq_disable(struct m66592 *m66592, u16 pipenum) -{ - disable_irq_ready(m66592, pipenum); - disable_irq_nrdy(m66592, pipenum); -} - -/* if complete is true, gadget driver complete function is not call */ -static void control_end(struct m66592 *m66592, unsigned ccpl) -{ - m66592->ep[0].internal_ccpl = ccpl; - pipe_start(m66592, 0); - m66592_bset(m66592, M66592_CCPL, M66592_DCPCTR); -} - -static void start_ep0_write(struct m66592_ep *ep, struct m66592_request *req) -{ - struct m66592 *m66592 = ep->m66592; - - pipe_change(m66592, ep->pipenum); - m66592_mdfy(m66592, M66592_ISEL | M66592_PIPE0, - (M66592_ISEL | M66592_CURPIPE), - M66592_CFIFOSEL); - m66592_write(m66592, M66592_BCLR, ep->fifoctr); - if (req->req.length == 0) { - m66592_bset(m66592, M66592_BVAL, ep->fifoctr); - pipe_start(m66592, 0); - transfer_complete(ep, req, 0); - } else { - m66592_write(m66592, ~M66592_BEMP0, M66592_BEMPSTS); - irq_ep0_write(ep, req); - } -} - -static void start_packet_write(struct m66592_ep *ep, struct m66592_request *req) -{ - struct m66592 *m66592 = ep->m66592; - u16 tmp; - - pipe_change(m66592, ep->pipenum); - disable_irq_empty(m66592, ep->pipenum); - pipe_start(m66592, ep->pipenum); - - tmp = m66592_read(m66592, ep->fifoctr); - if (unlikely((tmp & M66592_FRDY) == 0)) - pipe_irq_enable(m66592, ep->pipenum); - else - irq_packet_write(ep, req); -} - -static void start_packet_read(struct m66592_ep *ep, struct m66592_request *req) -{ - struct m66592 *m66592 = ep->m66592; - u16 pipenum = ep->pipenum; - - if (ep->pipenum == 0) { - m66592_mdfy(m66592, M66592_PIPE0, - (M66592_ISEL | M66592_CURPIPE), - M66592_CFIFOSEL); - m66592_write(m66592, M66592_BCLR, ep->fifoctr); - pipe_start(m66592, pipenum); - pipe_irq_enable(m66592, pipenum); - } else { - if (ep->use_dma) { - m66592_bset(m66592, M66592_TRCLR, ep->fifosel); - pipe_change(m66592, pipenum); - m66592_bset(m66592, M66592_TRENB, ep->fifosel); - m66592_write(m66592, - (req->req.length + ep->ep.maxpacket - 1) - / ep->ep.maxpacket, - ep->fifotrn); - } - pipe_start(m66592, pipenum); /* trigger once */ - pipe_irq_enable(m66592, pipenum); - } -} - -static void start_packet(struct m66592_ep *ep, struct m66592_request *req) -{ - if (ep->desc->bEndpointAddress & USB_DIR_IN) - start_packet_write(ep, req); - else - start_packet_read(ep, req); -} - -static void start_ep0(struct m66592_ep *ep, struct m66592_request *req) -{ - u16 ctsq; - - ctsq = m66592_read(ep->m66592, M66592_INTSTS0) & M66592_CTSQ; - - switch (ctsq) { - case M66592_CS_RDDS: - start_ep0_write(ep, req); - break; - case M66592_CS_WRDS: - start_packet_read(ep, req); - break; - - case M66592_CS_WRND: - control_end(ep->m66592, 0); - break; - default: - pr_err("start_ep0: unexpect ctsq(%x)\n", ctsq); - break; - } -} - -static void init_controller(struct m66592 *m66592) -{ - unsigned int endian; - - if (m66592->pdata->on_chip) { - if (m66592->pdata->endian) - endian = 0; /* big endian */ - else - endian = M66592_LITTLE; /* little endian */ - - m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */ - m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG); - m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG); - m66592_bset(m66592, M66592_USBE, M66592_SYSCFG); - - /* This is a workaound for SH7722 2nd cut */ - m66592_bset(m66592, 0x8000, M66592_DVSTCTR); - m66592_bset(m66592, 0x1000, M66592_TESTMODE); - m66592_bclr(m66592, 0x8000, M66592_DVSTCTR); - - m66592_bset(m66592, M66592_INTL, M66592_INTENB1); - - m66592_write(m66592, 0, M66592_CFBCFG); - m66592_write(m66592, 0, M66592_D0FBCFG); - m66592_bset(m66592, endian, M66592_CFBCFG); - m66592_bset(m66592, endian, M66592_D0FBCFG); - } else { - unsigned int clock, vif, irq_sense; - - if (m66592->pdata->endian) - endian = M66592_BIGEND; /* big endian */ - else - endian = 0; /* little endian */ - - if (m66592->pdata->vif) - vif = M66592_LDRV; /* 3.3v */ - else - vif = 0; /* 1.5v */ - - switch (m66592->pdata->xtal) { - case M66592_PLATDATA_XTAL_12MHZ: - clock = M66592_XTAL12; - break; - case M66592_PLATDATA_XTAL_24MHZ: - clock = M66592_XTAL24; - break; - case M66592_PLATDATA_XTAL_48MHZ: - clock = M66592_XTAL48; - break; - default: - pr_warning("m66592-udc: xtal configuration error\n"); - clock = 0; - } - - switch (m66592->irq_trigger) { - case IRQF_TRIGGER_LOW: - irq_sense = M66592_INTL; - break; - case IRQF_TRIGGER_FALLING: - irq_sense = 0; - break; - default: - pr_warning("m66592-udc: irq trigger config error\n"); - irq_sense = 0; - } - - m66592_bset(m66592, - (vif & M66592_LDRV) | (endian & M66592_BIGEND), - M66592_PINCFG); - m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */ - m66592_mdfy(m66592, clock & M66592_XTAL, M66592_XTAL, - M66592_SYSCFG); - m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG); - m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG); - m66592_bset(m66592, M66592_USBE, M66592_SYSCFG); - - m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG); - - msleep(3); - - m66592_bset(m66592, M66592_RCKE | M66592_PLLC, M66592_SYSCFG); - - msleep(1); - - m66592_bset(m66592, M66592_SCKE, M66592_SYSCFG); - - m66592_bset(m66592, irq_sense & M66592_INTL, M66592_INTENB1); - m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR, - M66592_DMA0CFG); - } -} - -static void disable_controller(struct m66592 *m66592) -{ - m66592_bclr(m66592, M66592_UTST, M66592_TESTMODE); - if (!m66592->pdata->on_chip) { - m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG); - udelay(1); - m66592_bclr(m66592, M66592_PLLC, M66592_SYSCFG); - udelay(1); - m66592_bclr(m66592, M66592_RCKE, M66592_SYSCFG); - udelay(1); - m66592_bclr(m66592, M66592_XCKE, M66592_SYSCFG); - } -} - -static void m66592_start_xclock(struct m66592 *m66592) -{ - u16 tmp; - - if (!m66592->pdata->on_chip) { - tmp = m66592_read(m66592, M66592_SYSCFG); - if (!(tmp & M66592_XCKE)) - m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG); - } -} - -/*-------------------------------------------------------------------------*/ -static void transfer_complete(struct m66592_ep *ep, - struct m66592_request *req, int status) -__releases(m66592->lock) -__acquires(m66592->lock) -{ - int restart = 0; - - if (unlikely(ep->pipenum == 0)) { - if (ep->internal_ccpl) { - ep->internal_ccpl = 0; - return; - } - } - - list_del_init(&req->queue); - if (ep->m66592->gadget.speed == USB_SPEED_UNKNOWN) - req->req.status = -ESHUTDOWN; - else - req->req.status = status; - - if (!list_empty(&ep->queue)) - restart = 1; - - spin_unlock(&ep->m66592->lock); - req->req.complete(&ep->ep, &req->req); - spin_lock(&ep->m66592->lock); - - if (restart) { - req = list_entry(ep->queue.next, struct m66592_request, queue); - if (ep->desc) - start_packet(ep, req); - } -} - -static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req) -{ - int i; - u16 tmp; - unsigned bufsize; - size_t size; - void *buf; - u16 pipenum = ep->pipenum; - struct m66592 *m66592 = ep->m66592; - - pipe_change(m66592, pipenum); - m66592_bset(m66592, M66592_ISEL, ep->fifosel); - - i = 0; - do { - tmp = m66592_read(m66592, ep->fifoctr); - if (i++ > 100000) { - pr_err("pipe0 is busy. maybe cpu i/o bus " - "conflict. please power off this controller."); - return; - } - ndelay(1); - } while ((tmp & M66592_FRDY) == 0); - - /* prepare parameters */ - bufsize = get_buffer_size(m66592, pipenum); - buf = req->req.buf + req->req.actual; - size = min(bufsize, req->req.length - req->req.actual); - - /* write fifo */ - if (req->req.buf) { - if (size > 0) - m66592_write_fifo(m66592, ep, buf, size); - if ((size == 0) || ((size % ep->ep.maxpacket) != 0)) - m66592_bset(m66592, M66592_BVAL, ep->fifoctr); - } - - /* update parameters */ - req->req.actual += size; - - /* check transfer finish */ - if ((!req->req.zero && (req->req.actual == req->req.length)) - || (size % ep->ep.maxpacket) - || (size == 0)) { - disable_irq_ready(m66592, pipenum); - disable_irq_empty(m66592, pipenum); - } else { - disable_irq_ready(m66592, pipenum); - enable_irq_empty(m66592, pipenum); - } - pipe_start(m66592, pipenum); -} - -static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req) -{ - u16 tmp; - unsigned bufsize; - size_t size; - void *buf; - u16 pipenum = ep->pipenum; - struct m66592 *m66592 = ep->m66592; - - pipe_change(m66592, pipenum); - tmp = m66592_read(m66592, ep->fifoctr); - if (unlikely((tmp & M66592_FRDY) == 0)) { - pipe_stop(m66592, pipenum); - pipe_irq_disable(m66592, pipenum); - pr_err("write fifo not ready. pipnum=%d\n", pipenum); - return; - } - - /* prepare parameters */ - bufsize = get_buffer_size(m66592, pipenum); - buf = req->req.buf + req->req.actual; - size = min(bufsize, req->req.length - req->req.actual); - - /* write fifo */ - if (req->req.buf) { - m66592_write_fifo(m66592, ep, buf, size); - if ((size == 0) - || ((size % ep->ep.maxpacket) != 0) - || ((bufsize != ep->ep.maxpacket) - && (bufsize > size))) - m66592_bset(m66592, M66592_BVAL, ep->fifoctr); - } - - /* update parameters */ - req->req.actual += size; - /* check transfer finish */ - if ((!req->req.zero && (req->req.actual == req->req.length)) - || (size % ep->ep.maxpacket) - || (size == 0)) { - disable_irq_ready(m66592, pipenum); - enable_irq_empty(m66592, pipenum); - } else { - disable_irq_empty(m66592, pipenum); - pipe_irq_enable(m66592, pipenum); - } -} - -static void irq_packet_read(struct m66592_ep *ep, struct m66592_request *req) -{ - u16 tmp; - int rcv_len, bufsize, req_len; - int size; - void *buf; - u16 pipenum = ep->pipenum; - struct m66592 *m66592 = ep->m66592; - int finish = 0; - - pipe_change(m66592, pipenum); - tmp = m66592_read(m66592, ep->fifoctr); - if (unlikely((tmp & M66592_FRDY) == 0)) { - req->req.status = -EPIPE; - pipe_stop(m66592, pipenum); - pipe_irq_disable(m66592, pipenum); - pr_err("read fifo not ready"); - return; - } - - /* prepare parameters */ - rcv_len = tmp & M66592_DTLN; - bufsize = get_buffer_size(m66592, pipenum); - - buf = req->req.buf + req->req.actual; - req_len = req->req.length - req->req.actual; - if (rcv_len < bufsize) - size = min(rcv_len, req_len); - else - size = min(bufsize, req_len); - - /* update parameters */ - req->req.actual += size; - - /* check transfer finish */ - if ((!req->req.zero && (req->req.actual == req->req.length)) - || (size % ep->ep.maxpacket) - || (size == 0)) { - pipe_stop(m66592, pipenum); - pipe_irq_disable(m66592, pipenum); - finish = 1; - } - - /* read fifo */ - if (req->req.buf) { - if (size == 0) - m66592_write(m66592, M66592_BCLR, ep->fifoctr); - else - m66592_read_fifo(m66592, ep->fifoaddr, buf, size); - } - - if ((ep->pipenum != 0) && finish) - transfer_complete(ep, req, 0); -} - -static void irq_pipe_ready(struct m66592 *m66592, u16 status, u16 enb) -{ - u16 check; - u16 pipenum; - struct m66592_ep *ep; - struct m66592_request *req; - - if ((status & M66592_BRDY0) && (enb & M66592_BRDY0)) { - m66592_write(m66592, ~M66592_BRDY0, M66592_BRDYSTS); - m66592_mdfy(m66592, M66592_PIPE0, M66592_CURPIPE, - M66592_CFIFOSEL); - - ep = &m66592->ep[0]; - req = list_entry(ep->queue.next, struct m66592_request, queue); - irq_packet_read(ep, req); - } else { - for (pipenum = 1; pipenum < M66592_MAX_NUM_PIPE; pipenum++) { - check = 1 << pipenum; - if ((status & check) && (enb & check)) { - m66592_write(m66592, ~check, M66592_BRDYSTS); - ep = m66592->pipenum2ep[pipenum]; - req = list_entry(ep->queue.next, - struct m66592_request, queue); - if (ep->desc->bEndpointAddress & USB_DIR_IN) - irq_packet_write(ep, req); - else - irq_packet_read(ep, req); - } - } - } -} - -static void irq_pipe_empty(struct m66592 *m66592, u16 status, u16 enb) -{ - u16 tmp; - u16 check; - u16 pipenum; - struct m66592_ep *ep; - struct m66592_request *req; - - if ((status & M66592_BEMP0) && (enb & M66592_BEMP0)) { - m66592_write(m66592, ~M66592_BEMP0, M66592_BEMPSTS); - - ep = &m66592->ep[0]; - req = list_entry(ep->queue.next, struct m66592_request, queue); - irq_ep0_write(ep, req); - } else { - for (pipenum = 1; pipenum < M66592_MAX_NUM_PIPE; pipenum++) { - check = 1 << pipenum; - if ((status & check) && (enb & check)) { - m66592_write(m66592, ~check, M66592_BEMPSTS); - tmp = control_reg_get(m66592, pipenum); - if ((tmp & M66592_INBUFM) == 0) { - disable_irq_empty(m66592, pipenum); - pipe_irq_disable(m66592, pipenum); - pipe_stop(m66592, pipenum); - ep = m66592->pipenum2ep[pipenum]; - req = list_entry(ep->queue.next, - struct m66592_request, - queue); - if (!list_empty(&ep->queue)) - transfer_complete(ep, req, 0); - } - } - } - } -} - -static void get_status(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) -__releases(m66592->lock) -__acquires(m66592->lock) -{ - struct m66592_ep *ep; - u16 pid; - u16 status = 0; - u16 w_index = le16_to_cpu(ctrl->wIndex); - - switch (ctrl->bRequestType & USB_RECIP_MASK) { - case USB_RECIP_DEVICE: - status = 1 << USB_DEVICE_SELF_POWERED; - break; - case USB_RECIP_INTERFACE: - status = 0; - break; - case USB_RECIP_ENDPOINT: - ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK]; - pid = control_reg_get_pid(m66592, ep->pipenum); - if (pid == M66592_PID_STALL) - status = 1 << USB_ENDPOINT_HALT; - else - status = 0; - break; - default: - pipe_stall(m66592, 0); - return; /* exit */ - } - - m66592->ep0_data = cpu_to_le16(status); - m66592->ep0_req->buf = &m66592->ep0_data; - m66592->ep0_req->length = 2; - /* AV: what happens if we get called again before that gets through? */ - spin_unlock(&m66592->lock); - m66592_queue(m66592->gadget.ep0, m66592->ep0_req, GFP_KERNEL); - spin_lock(&m66592->lock); -} - -static void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) -{ - switch (ctrl->bRequestType & USB_RECIP_MASK) { - case USB_RECIP_DEVICE: - control_end(m66592, 1); - break; - case USB_RECIP_INTERFACE: - control_end(m66592, 1); - break; - case USB_RECIP_ENDPOINT: { - struct m66592_ep *ep; - struct m66592_request *req; - u16 w_index = le16_to_cpu(ctrl->wIndex); - - ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK]; - pipe_stop(m66592, ep->pipenum); - control_reg_sqclr(m66592, ep->pipenum); - - control_end(m66592, 1); - - req = list_entry(ep->queue.next, - struct m66592_request, queue); - if (ep->busy) { - ep->busy = 0; - if (list_empty(&ep->queue)) - break; - start_packet(ep, req); - } else if (!list_empty(&ep->queue)) - pipe_start(m66592, ep->pipenum); - } - break; - default: - pipe_stall(m66592, 0); - break; - } -} - -static void set_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) -{ - u16 tmp; - int timeout = 3000; - - switch (ctrl->bRequestType & USB_RECIP_MASK) { - case USB_RECIP_DEVICE: - switch (le16_to_cpu(ctrl->wValue)) { - case USB_DEVICE_TEST_MODE: - control_end(m66592, 1); - /* Wait for the completion of status stage */ - do { - tmp = m66592_read(m66592, M66592_INTSTS0) & - M66592_CTSQ; - udelay(1); - } while (tmp != M66592_CS_IDST || timeout-- > 0); - - if (tmp == M66592_CS_IDST) - m66592_bset(m66592, - le16_to_cpu(ctrl->wIndex >> 8), - M66592_TESTMODE); - break; - default: - pipe_stall(m66592, 0); - break; - } - break; - case USB_RECIP_INTERFACE: - control_end(m66592, 1); - break; - case USB_RECIP_ENDPOINT: { - struct m66592_ep *ep; - u16 w_index = le16_to_cpu(ctrl->wIndex); - - ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK]; - pipe_stall(m66592, ep->pipenum); - - control_end(m66592, 1); - } - break; - default: - pipe_stall(m66592, 0); - break; - } -} - -/* if return value is true, call class driver's setup() */ -static int setup_packet(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) -{ - u16 *p = (u16 *)ctrl; - unsigned long offset = M66592_USBREQ; - int i, ret = 0; - - /* read fifo */ - m66592_write(m66592, ~M66592_VALID, M66592_INTSTS0); - - for (i = 0; i < 4; i++) - p[i] = m66592_read(m66592, offset + i*2); - - /* check request */ - if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { - switch (ctrl->bRequest) { - case USB_REQ_GET_STATUS: - get_status(m66592, ctrl); - break; - case USB_REQ_CLEAR_FEATURE: - clear_feature(m66592, ctrl); - break; - case USB_REQ_SET_FEATURE: - set_feature(m66592, ctrl); - break; - default: - ret = 1; - break; - } - } else - ret = 1; - return ret; -} - -static void m66592_update_usb_speed(struct m66592 *m66592) -{ - u16 speed = get_usb_speed(m66592); - - switch (speed) { - case M66592_HSMODE: - m66592->gadget.speed = USB_SPEED_HIGH; - break; - case M66592_FSMODE: - m66592->gadget.speed = USB_SPEED_FULL; - break; - default: - m66592->gadget.speed = USB_SPEED_UNKNOWN; - pr_err("USB speed unknown\n"); - } -} - -static void irq_device_state(struct m66592 *m66592) -{ - u16 dvsq; - - dvsq = m66592_read(m66592, M66592_INTSTS0) & M66592_DVSQ; - m66592_write(m66592, ~M66592_DVST, M66592_INTSTS0); - - if (dvsq == M66592_DS_DFLT) { /* bus reset */ - m66592->driver->disconnect(&m66592->gadget); - m66592_update_usb_speed(m66592); - } - if (m66592->old_dvsq == M66592_DS_CNFG && dvsq != M66592_DS_CNFG) - m66592_update_usb_speed(m66592); - if ((dvsq == M66592_DS_CNFG || dvsq == M66592_DS_ADDS) - && m66592->gadget.speed == USB_SPEED_UNKNOWN) - m66592_update_usb_speed(m66592); - - m66592->old_dvsq = dvsq; -} - -static void irq_control_stage(struct m66592 *m66592) -__releases(m66592->lock) -__acquires(m66592->lock) -{ - struct usb_ctrlrequest ctrl; - u16 ctsq; - - ctsq = m66592_read(m66592, M66592_INTSTS0) & M66592_CTSQ; - m66592_write(m66592, ~M66592_CTRT, M66592_INTSTS0); - - switch (ctsq) { - case M66592_CS_IDST: { - struct m66592_ep *ep; - struct m66592_request *req; - ep = &m66592->ep[0]; - req = list_entry(ep->queue.next, struct m66592_request, queue); - transfer_complete(ep, req, 0); - } - break; - - case M66592_CS_RDDS: - case M66592_CS_WRDS: - case M66592_CS_WRND: - if (setup_packet(m66592, &ctrl)) { - spin_unlock(&m66592->lock); - if (m66592->driver->setup(&m66592->gadget, &ctrl) < 0) - pipe_stall(m66592, 0); - spin_lock(&m66592->lock); - } - break; - case M66592_CS_RDSS: - case M66592_CS_WRSS: - control_end(m66592, 0); - break; - default: - pr_err("ctrl_stage: unexpect ctsq(%x)\n", ctsq); - break; - } -} - -static irqreturn_t m66592_irq(int irq, void *_m66592) -{ - struct m66592 *m66592 = _m66592; - u16 intsts0; - u16 intenb0; - u16 brdysts, nrdysts, bempsts; - u16 brdyenb, nrdyenb, bempenb; - u16 savepipe; - u16 mask0; - - spin_lock(&m66592->lock); - - intsts0 = m66592_read(m66592, M66592_INTSTS0); - intenb0 = m66592_read(m66592, M66592_INTENB0); - - if (m66592->pdata->on_chip && !intsts0 && !intenb0) { - /* - * When USB clock stops, it cannot read register. Even if a - * clock stops, the interrupt occurs. So this driver turn on - * a clock by this timing and do re-reading of register. - */ - m66592_start_xclock(m66592); - intsts0 = m66592_read(m66592, M66592_INTSTS0); - intenb0 = m66592_read(m66592, M66592_INTENB0); - } - - savepipe = m66592_read(m66592, M66592_CFIFOSEL); - - mask0 = intsts0 & intenb0; - if (mask0) { - brdysts = m66592_read(m66592, M66592_BRDYSTS); - nrdysts = m66592_read(m66592, M66592_NRDYSTS); - bempsts = m66592_read(m66592, M66592_BEMPSTS); - brdyenb = m66592_read(m66592, M66592_BRDYENB); - nrdyenb = m66592_read(m66592, M66592_NRDYENB); - bempenb = m66592_read(m66592, M66592_BEMPENB); - - if (mask0 & M66592_VBINT) { - m66592_write(m66592, 0xffff & ~M66592_VBINT, - M66592_INTSTS0); - m66592_start_xclock(m66592); - - /* start vbus sampling */ - m66592->old_vbus = m66592_read(m66592, M66592_INTSTS0) - & M66592_VBSTS; - m66592->scount = M66592_MAX_SAMPLING; - - mod_timer(&m66592->timer, - jiffies + msecs_to_jiffies(50)); - } - if (intsts0 & M66592_DVSQ) - irq_device_state(m66592); - - if ((intsts0 & M66592_BRDY) && (intenb0 & M66592_BRDYE) - && (brdysts & brdyenb)) { - irq_pipe_ready(m66592, brdysts, brdyenb); - } - if ((intsts0 & M66592_BEMP) && (intenb0 & M66592_BEMPE) - && (bempsts & bempenb)) { - irq_pipe_empty(m66592, bempsts, bempenb); - } - - if (intsts0 & M66592_CTRT) - irq_control_stage(m66592); - } - - m66592_write(m66592, savepipe, M66592_CFIFOSEL); - - spin_unlock(&m66592->lock); - return IRQ_HANDLED; -} - -static void m66592_timer(unsigned long _m66592) -{ - struct m66592 *m66592 = (struct m66592 *)_m66592; - unsigned long flags; - u16 tmp; - - spin_lock_irqsave(&m66592->lock, flags); - tmp = m66592_read(m66592, M66592_SYSCFG); - if (!(tmp & M66592_RCKE)) { - m66592_bset(m66592, M66592_RCKE | M66592_PLLC, M66592_SYSCFG); - udelay(10); - m66592_bset(m66592, M66592_SCKE, M66592_SYSCFG); - } - if (m66592->scount > 0) { - tmp = m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS; - if (tmp == m66592->old_vbus) { - m66592->scount--; - if (m66592->scount == 0) { - if (tmp == M66592_VBSTS) - m66592_usb_connect(m66592); - else - m66592_usb_disconnect(m66592); - } else { - mod_timer(&m66592->timer, - jiffies + msecs_to_jiffies(50)); - } - } else { - m66592->scount = M66592_MAX_SAMPLING; - m66592->old_vbus = tmp; - mod_timer(&m66592->timer, - jiffies + msecs_to_jiffies(50)); - } - } - spin_unlock_irqrestore(&m66592->lock, flags); -} - -/*-------------------------------------------------------------------------*/ -static int m66592_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct m66592_ep *ep; - - ep = container_of(_ep, struct m66592_ep, ep); - return alloc_pipe_config(ep, desc); -} - -static int m66592_disable(struct usb_ep *_ep) -{ - struct m66592_ep *ep; - struct m66592_request *req; - unsigned long flags; - - ep = container_of(_ep, struct m66592_ep, ep); - BUG_ON(!ep); - - while (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, struct m66592_request, queue); - spin_lock_irqsave(&ep->m66592->lock, flags); - transfer_complete(ep, req, -ECONNRESET); - spin_unlock_irqrestore(&ep->m66592->lock, flags); - } - - pipe_irq_disable(ep->m66592, ep->pipenum); - return free_pipe_config(ep); -} - -static struct usb_request *m66592_alloc_request(struct usb_ep *_ep, - gfp_t gfp_flags) -{ - struct m66592_request *req; - - req = kzalloc(sizeof(struct m66592_request), gfp_flags); - if (!req) - return NULL; - - INIT_LIST_HEAD(&req->queue); - - return &req->req; -} - -static void m66592_free_request(struct usb_ep *_ep, struct usb_request *_req) -{ - struct m66592_request *req; - - req = container_of(_req, struct m66592_request, req); - kfree(req); -} - -static int m66592_queue(struct usb_ep *_ep, struct usb_request *_req, - gfp_t gfp_flags) -{ - struct m66592_ep *ep; - struct m66592_request *req; - unsigned long flags; - int request = 0; - - ep = container_of(_ep, struct m66592_ep, ep); - req = container_of(_req, struct m66592_request, req); - - if (ep->m66592->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - spin_lock_irqsave(&ep->m66592->lock, flags); - - if (list_empty(&ep->queue)) - request = 1; - - list_add_tail(&req->queue, &ep->queue); - req->req.actual = 0; - req->req.status = -EINPROGRESS; - - if (ep->desc == NULL) /* control */ - start_ep0(ep, req); - else { - if (request && !ep->busy) - start_packet(ep, req); - } - - spin_unlock_irqrestore(&ep->m66592->lock, flags); - - return 0; -} - -static int m66592_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct m66592_ep *ep; - struct m66592_request *req; - unsigned long flags; - - ep = container_of(_ep, struct m66592_ep, ep); - req = container_of(_req, struct m66592_request, req); - - spin_lock_irqsave(&ep->m66592->lock, flags); - if (!list_empty(&ep->queue)) - transfer_complete(ep, req, -ECONNRESET); - spin_unlock_irqrestore(&ep->m66592->lock, flags); - - return 0; -} - -static int m66592_set_halt(struct usb_ep *_ep, int value) -{ - struct m66592_ep *ep; - struct m66592_request *req; - unsigned long flags; - int ret = 0; - - ep = container_of(_ep, struct m66592_ep, ep); - req = list_entry(ep->queue.next, struct m66592_request, queue); - - spin_lock_irqsave(&ep->m66592->lock, flags); - if (!list_empty(&ep->queue)) { - ret = -EAGAIN; - goto out; - } - if (value) { - ep->busy = 1; - pipe_stall(ep->m66592, ep->pipenum); - } else { - ep->busy = 0; - pipe_stop(ep->m66592, ep->pipenum); - } - -out: - spin_unlock_irqrestore(&ep->m66592->lock, flags); - return ret; -} - -static void m66592_fifo_flush(struct usb_ep *_ep) -{ - struct m66592_ep *ep; - unsigned long flags; - - ep = container_of(_ep, struct m66592_ep, ep); - spin_lock_irqsave(&ep->m66592->lock, flags); - if (list_empty(&ep->queue) && !ep->busy) { - pipe_stop(ep->m66592, ep->pipenum); - m66592_bclr(ep->m66592, M66592_BCLR, ep->fifoctr); - } - spin_unlock_irqrestore(&ep->m66592->lock, flags); -} - -static struct usb_ep_ops m66592_ep_ops = { - .enable = m66592_enable, - .disable = m66592_disable, - - .alloc_request = m66592_alloc_request, - .free_request = m66592_free_request, - - .queue = m66592_queue, - .dequeue = m66592_dequeue, - - .set_halt = m66592_set_halt, - .fifo_flush = m66592_fifo_flush, -}; - -/*-------------------------------------------------------------------------*/ -static struct m66592 *the_controller; - -static int m66592_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) -{ - struct m66592 *m66592 = the_controller; - int retval; - - if (!driver - || driver->max_speed < USB_SPEED_HIGH - || !bind - || !driver->setup) - return -EINVAL; - if (!m66592) - return -ENODEV; - if (m66592->driver) - return -EBUSY; - - /* hook up the driver */ - driver->driver.bus = NULL; - m66592->driver = driver; - m66592->gadget.dev.driver = &driver->driver; - - retval = device_add(&m66592->gadget.dev); - if (retval) { - pr_err("device_add error (%d)\n", retval); - goto error; - } - - retval = bind(&m66592->gadget); - if (retval) { - pr_err("bind to driver error (%d)\n", retval); - device_del(&m66592->gadget.dev); - goto error; - } - - m66592_bset(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0); - if (m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS) { - m66592_start_xclock(m66592); - /* start vbus sampling */ - m66592->old_vbus = m66592_read(m66592, - M66592_INTSTS0) & M66592_VBSTS; - m66592->scount = M66592_MAX_SAMPLING; - mod_timer(&m66592->timer, jiffies + msecs_to_jiffies(50)); - } - - return 0; - -error: - m66592->driver = NULL; - m66592->gadget.dev.driver = NULL; - - return retval; -} - -static int m66592_stop(struct usb_gadget_driver *driver) -{ - struct m66592 *m66592 = the_controller; - unsigned long flags; - - if (driver != m66592->driver || !driver->unbind) - return -EINVAL; - - spin_lock_irqsave(&m66592->lock, flags); - if (m66592->gadget.speed != USB_SPEED_UNKNOWN) - m66592_usb_disconnect(m66592); - spin_unlock_irqrestore(&m66592->lock, flags); - - m66592_bclr(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0); - - driver->unbind(&m66592->gadget); - m66592->gadget.dev.driver = NULL; - - init_controller(m66592); - disable_controller(m66592); - - device_del(&m66592->gadget.dev); - m66592->driver = NULL; - return 0; -} - -/*-------------------------------------------------------------------------*/ -static int m66592_get_frame(struct usb_gadget *_gadget) -{ - struct m66592 *m66592 = gadget_to_m66592(_gadget); - return m66592_read(m66592, M66592_FRMNUM) & 0x03FF; -} - -static int m66592_pullup(struct usb_gadget *gadget, int is_on) -{ - struct m66592 *m66592 = gadget_to_m66592(gadget); - unsigned long flags; - - spin_lock_irqsave(&m66592->lock, flags); - if (is_on) - m66592_bset(m66592, M66592_DPRPU, M66592_SYSCFG); - else - m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG); - spin_unlock_irqrestore(&m66592->lock, flags); - - return 0; -} - -static struct usb_gadget_ops m66592_gadget_ops = { - .get_frame = m66592_get_frame, - .start = m66592_start, - .stop = m66592_stop, - .pullup = m66592_pullup, -}; - -static int __exit m66592_remove(struct platform_device *pdev) -{ - struct m66592 *m66592 = dev_get_drvdata(&pdev->dev); - - usb_del_gadget_udc(&m66592->gadget); - - del_timer_sync(&m66592->timer); - iounmap(m66592->reg); - free_irq(platform_get_irq(pdev, 0), m66592); - m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req); -#ifdef CONFIG_HAVE_CLK - if (m66592->pdata->on_chip) { - clk_disable(m66592->clk); - clk_put(m66592->clk); - } -#endif - kfree(m66592); - return 0; -} - -static void nop_completion(struct usb_ep *ep, struct usb_request *r) -{ -} - -static int __init m66592_probe(struct platform_device *pdev) -{ - struct resource *res, *ires; - void __iomem *reg = NULL; - struct m66592 *m66592 = NULL; -#ifdef CONFIG_HAVE_CLK - char clk_name[8]; -#endif - int ret = 0; - int i; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENODEV; - pr_err("platform_get_resource error.\n"); - goto clean_up; - } - - ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!ires) { - ret = -ENODEV; - dev_err(&pdev->dev, - "platform_get_resource IORESOURCE_IRQ error.\n"); - goto clean_up; - } - - reg = ioremap(res->start, resource_size(res)); - if (reg == NULL) { - ret = -ENOMEM; - pr_err("ioremap error.\n"); - goto clean_up; - } - - if (pdev->dev.platform_data == NULL) { - dev_err(&pdev->dev, "no platform data\n"); - ret = -ENODEV; - goto clean_up; - } - - /* initialize ucd */ - m66592 = kzalloc(sizeof(struct m66592), GFP_KERNEL); - if (m66592 == NULL) { - ret = -ENOMEM; - pr_err("kzalloc error\n"); - goto clean_up; - } - - m66592->pdata = pdev->dev.platform_data; - m66592->irq_trigger = ires->flags & IRQF_TRIGGER_MASK; - - spin_lock_init(&m66592->lock); - dev_set_drvdata(&pdev->dev, m66592); - - m66592->gadget.ops = &m66592_gadget_ops; - device_initialize(&m66592->gadget.dev); - dev_set_name(&m66592->gadget.dev, "gadget"); - m66592->gadget.max_speed = USB_SPEED_HIGH; - m66592->gadget.dev.parent = &pdev->dev; - m66592->gadget.dev.dma_mask = pdev->dev.dma_mask; - m66592->gadget.dev.release = pdev->dev.release; - m66592->gadget.name = udc_name; - - init_timer(&m66592->timer); - m66592->timer.function = m66592_timer; - m66592->timer.data = (unsigned long)m66592; - m66592->reg = reg; - - ret = request_irq(ires->start, m66592_irq, IRQF_SHARED, - udc_name, m66592); - if (ret < 0) { - pr_err("request_irq error (%d)\n", ret); - goto clean_up; - } - -#ifdef CONFIG_HAVE_CLK - if (m66592->pdata->on_chip) { - snprintf(clk_name, sizeof(clk_name), "usbf%d", pdev->id); - m66592->clk = clk_get(&pdev->dev, clk_name); - if (IS_ERR(m66592->clk)) { - dev_err(&pdev->dev, "cannot get clock \"%s\"\n", - clk_name); - ret = PTR_ERR(m66592->clk); - goto clean_up2; - } - clk_enable(m66592->clk); - } -#endif - INIT_LIST_HEAD(&m66592->gadget.ep_list); - m66592->gadget.ep0 = &m66592->ep[0].ep; - INIT_LIST_HEAD(&m66592->gadget.ep0->ep_list); - for (i = 0; i < M66592_MAX_NUM_PIPE; i++) { - struct m66592_ep *ep = &m66592->ep[i]; - - if (i != 0) { - INIT_LIST_HEAD(&m66592->ep[i].ep.ep_list); - list_add_tail(&m66592->ep[i].ep.ep_list, - &m66592->gadget.ep_list); - } - ep->m66592 = m66592; - INIT_LIST_HEAD(&ep->queue); - ep->ep.name = m66592_ep_name[i]; - ep->ep.ops = &m66592_ep_ops; - ep->ep.maxpacket = 512; - } - m66592->ep[0].ep.maxpacket = 64; - m66592->ep[0].pipenum = 0; - m66592->ep[0].fifoaddr = M66592_CFIFO; - m66592->ep[0].fifosel = M66592_CFIFOSEL; - m66592->ep[0].fifoctr = M66592_CFIFOCTR; - m66592->ep[0].fifotrn = 0; - m66592->ep[0].pipectr = get_pipectr_addr(0); - m66592->pipenum2ep[0] = &m66592->ep[0]; - m66592->epaddr2ep[0] = &m66592->ep[0]; - - the_controller = m66592; - - m66592->ep0_req = m66592_alloc_request(&m66592->ep[0].ep, GFP_KERNEL); - if (m66592->ep0_req == NULL) - goto clean_up3; - m66592->ep0_req->complete = nop_completion; - - init_controller(m66592); - - ret = usb_add_gadget_udc(&pdev->dev, &m66592->gadget); - if (ret) - goto err_add_udc; - - dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION); - return 0; - -err_add_udc: - m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req); - -clean_up3: -#ifdef CONFIG_HAVE_CLK - if (m66592->pdata->on_chip) { - clk_disable(m66592->clk); - clk_put(m66592->clk); - } -clean_up2: -#endif - free_irq(ires->start, m66592); -clean_up: - if (m66592) { - if (m66592->ep0_req) - m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req); - kfree(m66592); - } - if (reg) - iounmap(reg); - - return ret; -} - -/*-------------------------------------------------------------------------*/ -static struct platform_driver m66592_driver = { - .remove = __exit_p(m66592_remove), - .driver = { - .name = (char *) udc_name, - .owner = THIS_MODULE, - }, -}; - -static int __init m66592_udc_init(void) -{ - return platform_driver_probe(&m66592_driver, m66592_probe); -} -module_init(m66592_udc_init); - -static void __exit m66592_udc_cleanup(void) -{ - platform_driver_unregister(&m66592_driver); -} -module_exit(m66592_udc_cleanup); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/m66592-udc.h b/ANDROID_3.4.5/drivers/usb/gadget/m66592-udc.h deleted file mode 100644 index 9d9f7e39..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/m66592-udc.h +++ /dev/null @@ -1,610 +0,0 @@ -/* - * M66592 UDC (USB gadget) - * - * Copyright (C) 2006-2007 Renesas Solutions Corp. - * - * Author : Yoshihiro Shimoda - * - * 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; version 2 of the License. - */ - -#ifndef __M66592_UDC_H__ -#define __M66592_UDC_H__ - -#ifdef CONFIG_HAVE_CLK -#include -#endif - -#include - -#define M66592_SYSCFG 0x00 -#define M66592_XTAL 0xC000 /* b15-14: Crystal selection */ -#define M66592_XTAL48 0x8000 /* 48MHz */ -#define M66592_XTAL24 0x4000 /* 24MHz */ -#define M66592_XTAL12 0x0000 /* 12MHz */ -#define M66592_XCKE 0x2000 /* b13: External clock enable */ -#define M66592_RCKE 0x1000 /* b12: Register clock enable */ -#define M66592_PLLC 0x0800 /* b11: PLL control */ -#define M66592_SCKE 0x0400 /* b10: USB clock enable */ -#define M66592_ATCKM 0x0100 /* b8: Automatic clock supply */ -#define M66592_HSE 0x0080 /* b7: Hi-speed enable */ -#define M66592_DCFM 0x0040 /* b6: Controller function select */ -#define M66592_DMRPD 0x0020 /* b5: D- pull down control */ -#define M66592_DPRPU 0x0010 /* b4: D+ pull up control */ -#define M66592_FSRPC 0x0004 /* b2: Full-speed receiver enable */ -#define M66592_PCUT 0x0002 /* b1: Low power sleep enable */ -#define M66592_USBE 0x0001 /* b0: USB module operation enable */ - -#define M66592_SYSSTS 0x02 -#define M66592_LNST 0x0003 /* b1-0: D+, D- line status */ -#define M66592_SE1 0x0003 /* SE1 */ -#define M66592_KSTS 0x0002 /* K State */ -#define M66592_JSTS 0x0001 /* J State */ -#define M66592_SE0 0x0000 /* SE0 */ - -#define M66592_DVSTCTR 0x04 -#define M66592_WKUP 0x0100 /* b8: Remote wakeup */ -#define M66592_RWUPE 0x0080 /* b7: Remote wakeup sense */ -#define M66592_USBRST 0x0040 /* b6: USB reset enable */ -#define M66592_RESUME 0x0020 /* b5: Resume enable */ -#define M66592_UACT 0x0010 /* b4: USB bus enable */ -#define M66592_RHST 0x0003 /* b1-0: Reset handshake status */ -#define M66592_HSMODE 0x0003 /* Hi-Speed mode */ -#define M66592_FSMODE 0x0002 /* Full-Speed mode */ -#define M66592_HSPROC 0x0001 /* HS handshake is processing */ - -#define M66592_TESTMODE 0x06 -#define M66592_UTST 0x000F /* b4-0: Test select */ -#define M66592_H_TST_PACKET 0x000C /* HOST TEST Packet */ -#define M66592_H_TST_SE0_NAK 0x000B /* HOST TEST SE0 NAK */ -#define M66592_H_TST_K 0x000A /* HOST TEST K */ -#define M66592_H_TST_J 0x0009 /* HOST TEST J */ -#define M66592_H_TST_NORMAL 0x0000 /* HOST Normal Mode */ -#define M66592_P_TST_PACKET 0x0004 /* PERI TEST Packet */ -#define M66592_P_TST_SE0_NAK 0x0003 /* PERI TEST SE0 NAK */ -#define M66592_P_TST_K 0x0002 /* PERI TEST K */ -#define M66592_P_TST_J 0x0001 /* PERI TEST J */ -#define M66592_P_TST_NORMAL 0x0000 /* PERI Normal Mode */ - -/* built-in registers */ -#define M66592_CFBCFG 0x0A -#define M66592_D0FBCFG 0x0C -#define M66592_LITTLE 0x0100 /* b8: Little endian mode */ -/* external chip case */ -#define M66592_PINCFG 0x0A -#define M66592_LDRV 0x8000 /* b15: Drive Current Adjust */ -#define M66592_BIGEND 0x0100 /* b8: Big endian mode */ - -#define M66592_DMA0CFG 0x0C -#define M66592_DMA1CFG 0x0E -#define M66592_DREQA 0x4000 /* b14: Dreq active select */ -#define M66592_BURST 0x2000 /* b13: Burst mode */ -#define M66592_DACKA 0x0400 /* b10: Dack active select */ -#define M66592_DFORM 0x0380 /* b9-7: DMA mode select */ -#define M66592_CPU_ADR_RD_WR 0x0000 /* Address + RD/WR mode (CPU bus) */ -#define M66592_CPU_DACK_RD_WR 0x0100 /* DACK + RD/WR mode (CPU bus) */ -#define M66592_CPU_DACK_ONLY 0x0180 /* DACK only mode (CPU bus) */ -#define M66592_SPLIT_DACK_ONLY 0x0200 /* DACK only mode (SPLIT bus) */ -#define M66592_SPLIT_DACK_DSTB 0x0300 /* DACK + DSTB0 mode (SPLIT bus) */ -#define M66592_DENDA 0x0040 /* b6: Dend active select */ -#define M66592_PKTM 0x0020 /* b5: Packet mode */ -#define M66592_DENDE 0x0010 /* b4: Dend enable */ -#define M66592_OBUS 0x0004 /* b2: OUTbus mode */ - -/* common case */ -#define M66592_CFIFO 0x10 -#define M66592_D0FIFO 0x14 -#define M66592_D1FIFO 0x18 - -#define M66592_CFIFOSEL 0x1E -#define M66592_D0FIFOSEL 0x24 -#define M66592_D1FIFOSEL 0x2A -#define M66592_RCNT 0x8000 /* b15: Read count mode */ -#define M66592_REW 0x4000 /* b14: Buffer rewind */ -#define M66592_DCLRM 0x2000 /* b13: DMA buffer clear mode */ -#define M66592_DREQE 0x1000 /* b12: DREQ output enable */ -#define M66592_MBW_8 0x0000 /* 8bit */ -#define M66592_MBW_16 0x0400 /* 16bit */ -#define M66592_MBW_32 0x0800 /* 32bit */ -#define M66592_TRENB 0x0200 /* b9: Transaction counter enable */ -#define M66592_TRCLR 0x0100 /* b8: Transaction counter clear */ -#define M66592_DEZPM 0x0080 /* b7: Zero-length packet mode */ -#define M66592_ISEL 0x0020 /* b5: DCP FIFO port direction select */ -#define M66592_CURPIPE 0x0007 /* b2-0: PIPE select */ - -#define M66592_CFIFOCTR 0x20 -#define M66592_D0FIFOCTR 0x26 -#define M66592_D1FIFOCTR 0x2c -#define M66592_BVAL 0x8000 /* b15: Buffer valid flag */ -#define M66592_BCLR 0x4000 /* b14: Buffer clear */ -#define M66592_FRDY 0x2000 /* b13: FIFO ready */ -#define M66592_DTLN 0x0FFF /* b11-0: FIFO received data length */ - -#define M66592_CFIFOSIE 0x22 -#define M66592_TGL 0x8000 /* b15: Buffer toggle */ -#define M66592_SCLR 0x4000 /* b14: Buffer clear */ -#define M66592_SBUSY 0x2000 /* b13: SIE_FIFO busy */ - -#define M66592_D0FIFOTRN 0x28 -#define M66592_D1FIFOTRN 0x2E -#define M66592_TRNCNT 0xFFFF /* b15-0: Transaction counter */ - -#define M66592_INTENB0 0x30 -#define M66592_VBSE 0x8000 /* b15: VBUS interrupt */ -#define M66592_RSME 0x4000 /* b14: Resume interrupt */ -#define M66592_SOFE 0x2000 /* b13: Frame update interrupt */ -#define M66592_DVSE 0x1000 /* b12: Device state transition interrupt */ -#define M66592_CTRE 0x0800 /* b11: Control transfer stage transition irq */ -#define M66592_BEMPE 0x0400 /* b10: Buffer empty interrupt */ -#define M66592_NRDYE 0x0200 /* b9: Buffer not ready interrupt */ -#define M66592_BRDYE 0x0100 /* b8: Buffer ready interrupt */ -#define M66592_URST 0x0080 /* b7: USB reset detected interrupt */ -#define M66592_SADR 0x0040 /* b6: Set address executed interrupt */ -#define M66592_SCFG 0x0020 /* b5: Set configuration executed interrupt */ -#define M66592_SUSP 0x0010 /* b4: Suspend detected interrupt */ -#define M66592_WDST 0x0008 /* b3: Control write data stage completed irq */ -#define M66592_RDST 0x0004 /* b2: Control read data stage completed irq */ -#define M66592_CMPL 0x0002 /* b1: Control transfer complete interrupt */ -#define M66592_SERR 0x0001 /* b0: Sequence error interrupt */ - -#define M66592_INTENB1 0x32 -#define M66592_BCHGE 0x4000 /* b14: USB us chenge interrupt */ -#define M66592_DTCHE 0x1000 /* b12: Detach sense interrupt */ -#define M66592_SIGNE 0x0020 /* b5: SETUP IGNORE interrupt */ -#define M66592_SACKE 0x0010 /* b4: SETUP ACK interrupt */ -#define M66592_BRDYM 0x0004 /* b2: BRDY clear timing */ -#define M66592_INTL 0x0002 /* b1: Interrupt sense select */ -#define M66592_PCSE 0x0001 /* b0: PCUT enable by CS assert */ - -#define M66592_BRDYENB 0x36 -#define M66592_BRDYSTS 0x46 -#define M66592_BRDY7 0x0080 /* b7: PIPE7 */ -#define M66592_BRDY6 0x0040 /* b6: PIPE6 */ -#define M66592_BRDY5 0x0020 /* b5: PIPE5 */ -#define M66592_BRDY4 0x0010 /* b4: PIPE4 */ -#define M66592_BRDY3 0x0008 /* b3: PIPE3 */ -#define M66592_BRDY2 0x0004 /* b2: PIPE2 */ -#define M66592_BRDY1 0x0002 /* b1: PIPE1 */ -#define M66592_BRDY0 0x0001 /* b1: PIPE0 */ - -#define M66592_NRDYENB 0x38 -#define M66592_NRDYSTS 0x48 -#define M66592_NRDY7 0x0080 /* b7: PIPE7 */ -#define M66592_NRDY6 0x0040 /* b6: PIPE6 */ -#define M66592_NRDY5 0x0020 /* b5: PIPE5 */ -#define M66592_NRDY4 0x0010 /* b4: PIPE4 */ -#define M66592_NRDY3 0x0008 /* b3: PIPE3 */ -#define M66592_NRDY2 0x0004 /* b2: PIPE2 */ -#define M66592_NRDY1 0x0002 /* b1: PIPE1 */ -#define M66592_NRDY0 0x0001 /* b1: PIPE0 */ - -#define M66592_BEMPENB 0x3A -#define M66592_BEMPSTS 0x4A -#define M66592_BEMP7 0x0080 /* b7: PIPE7 */ -#define M66592_BEMP6 0x0040 /* b6: PIPE6 */ -#define M66592_BEMP5 0x0020 /* b5: PIPE5 */ -#define M66592_BEMP4 0x0010 /* b4: PIPE4 */ -#define M66592_BEMP3 0x0008 /* b3: PIPE3 */ -#define M66592_BEMP2 0x0004 /* b2: PIPE2 */ -#define M66592_BEMP1 0x0002 /* b1: PIPE1 */ -#define M66592_BEMP0 0x0001 /* b0: PIPE0 */ - -#define M66592_SOFCFG 0x3C -#define M66592_SOFM 0x000C /* b3-2: SOF palse mode */ -#define M66592_SOF_125US 0x0008 /* SOF OUT 125us uFrame Signal */ -#define M66592_SOF_1MS 0x0004 /* SOF OUT 1ms Frame Signal */ -#define M66592_SOF_DISABLE 0x0000 /* SOF OUT Disable */ - -#define M66592_INTSTS0 0x40 -#define M66592_VBINT 0x8000 /* b15: VBUS interrupt */ -#define M66592_RESM 0x4000 /* b14: Resume interrupt */ -#define M66592_SOFR 0x2000 /* b13: SOF frame update interrupt */ -#define M66592_DVST 0x1000 /* b12: Device state transition */ -#define M66592_CTRT 0x0800 /* b11: Control stage transition */ -#define M66592_BEMP 0x0400 /* b10: Buffer empty interrupt */ -#define M66592_NRDY 0x0200 /* b9: Buffer not ready interrupt */ -#define M66592_BRDY 0x0100 /* b8: Buffer ready interrupt */ -#define M66592_VBSTS 0x0080 /* b7: VBUS input port */ -#define M66592_DVSQ 0x0070 /* b6-4: Device state */ -#define M66592_DS_SPD_CNFG 0x0070 /* Suspend Configured */ -#define M66592_DS_SPD_ADDR 0x0060 /* Suspend Address */ -#define M66592_DS_SPD_DFLT 0x0050 /* Suspend Default */ -#define M66592_DS_SPD_POWR 0x0040 /* Suspend Powered */ -#define M66592_DS_SUSP 0x0040 /* Suspend */ -#define M66592_DS_CNFG 0x0030 /* Configured */ -#define M66592_DS_ADDS 0x0020 /* Address */ -#define M66592_DS_DFLT 0x0010 /* Default */ -#define M66592_DS_POWR 0x0000 /* Powered */ -#define M66592_DVSQS 0x0030 /* b5-4: Device state */ -#define M66592_VALID 0x0008 /* b3: Setup packet detected flag */ -#define M66592_CTSQ 0x0007 /* b2-0: Control transfer stage */ -#define M66592_CS_SQER 0x0006 /* Sequence error */ -#define M66592_CS_WRND 0x0005 /* Control write nodata status */ -#define M66592_CS_WRSS 0x0004 /* Control write status stage */ -#define M66592_CS_WRDS 0x0003 /* Control write data stage */ -#define M66592_CS_RDSS 0x0002 /* Control read status stage */ -#define M66592_CS_RDDS 0x0001 /* Control read data stage */ -#define M66592_CS_IDST 0x0000 /* Idle or setup stage */ - -#define M66592_INTSTS1 0x42 -#define M66592_BCHG 0x4000 /* b14: USB bus chenge interrupt */ -#define M66592_DTCH 0x1000 /* b12: Detach sense interrupt */ -#define M66592_SIGN 0x0020 /* b5: SETUP IGNORE interrupt */ -#define M66592_SACK 0x0010 /* b4: SETUP ACK interrupt */ - -#define M66592_FRMNUM 0x4C -#define M66592_OVRN 0x8000 /* b15: Overrun error */ -#define M66592_CRCE 0x4000 /* b14: Received data error */ -#define M66592_SOFRM 0x0800 /* b11: SOF output mode */ -#define M66592_FRNM 0x07FF /* b10-0: Frame number */ - -#define M66592_UFRMNUM 0x4E -#define M66592_UFRNM 0x0007 /* b2-0: Micro frame number */ - -#define M66592_RECOVER 0x50 -#define M66592_STSRECOV 0x0700 /* Status recovery */ -#define M66592_STSR_HI 0x0400 /* FULL(0) or HI(1) Speed */ -#define M66592_STSR_DEFAULT 0x0100 /* Default state */ -#define M66592_STSR_ADDRESS 0x0200 /* Address state */ -#define M66592_STSR_CONFIG 0x0300 /* Configured state */ -#define M66592_USBADDR 0x007F /* b6-0: USB address */ - -#define M66592_USBREQ 0x54 -#define M66592_bRequest 0xFF00 /* b15-8: bRequest */ -#define M66592_GET_STATUS 0x0000 -#define M66592_CLEAR_FEATURE 0x0100 -#define M66592_ReqRESERVED 0x0200 -#define M66592_SET_FEATURE 0x0300 -#define M66592_ReqRESERVED1 0x0400 -#define M66592_SET_ADDRESS 0x0500 -#define M66592_GET_DESCRIPTOR 0x0600 -#define M66592_SET_DESCRIPTOR 0x0700 -#define M66592_GET_CONFIGURATION 0x0800 -#define M66592_SET_CONFIGURATION 0x0900 -#define M66592_GET_INTERFACE 0x0A00 -#define M66592_SET_INTERFACE 0x0B00 -#define M66592_SYNCH_FRAME 0x0C00 -#define M66592_bmRequestType 0x00FF /* b7-0: bmRequestType */ -#define M66592_bmRequestTypeDir 0x0080 /* b7 : Data direction */ -#define M66592_HOST_TO_DEVICE 0x0000 -#define M66592_DEVICE_TO_HOST 0x0080 -#define M66592_bmRequestTypeType 0x0060 /* b6-5: Type */ -#define M66592_STANDARD 0x0000 -#define M66592_CLASS 0x0020 -#define M66592_VENDOR 0x0040 -#define M66592_bmRequestTypeRecip 0x001F /* b4-0: Recipient */ -#define M66592_DEVICE 0x0000 -#define M66592_INTERFACE 0x0001 -#define M66592_ENDPOINT 0x0002 - -#define M66592_USBVAL 0x56 -#define M66592_wValue 0xFFFF /* b15-0: wValue */ -/* Standard Feature Selector */ -#define M66592_ENDPOINT_HALT 0x0000 -#define M66592_DEVICE_REMOTE_WAKEUP 0x0001 -#define M66592_TEST_MODE 0x0002 -/* Descriptor Types */ -#define M66592_DT_TYPE 0xFF00 -#define M66592_GET_DT_TYPE(v) (((v) & DT_TYPE) >> 8) -#define M66592_DT_DEVICE 0x01 -#define M66592_DT_CONFIGURATION 0x02 -#define M66592_DT_STRING 0x03 -#define M66592_DT_INTERFACE 0x04 -#define M66592_DT_ENDPOINT 0x05 -#define M66592_DT_DEVICE_QUALIFIER 0x06 -#define M66592_DT_OTHER_SPEED_CONFIGURATION 0x07 -#define M66592_DT_INTERFACE_POWER 0x08 -#define M66592_DT_INDEX 0x00FF -#define M66592_CONF_NUM 0x00FF -#define M66592_ALT_SET 0x00FF - -#define M66592_USBINDEX 0x58 -#define M66592_wIndex 0xFFFF /* b15-0: wIndex */ -#define M66592_TEST_SELECT 0xFF00 /* b15-b8: Test Mode */ -#define M66592_TEST_J 0x0100 /* Test_J */ -#define M66592_TEST_K 0x0200 /* Test_K */ -#define M66592_TEST_SE0_NAK 0x0300 /* Test_SE0_NAK */ -#define M66592_TEST_PACKET 0x0400 /* Test_Packet */ -#define M66592_TEST_FORCE_ENABLE 0x0500 /* Test_Force_Enable */ -#define M66592_TEST_STSelectors 0x0600 /* Standard test selectors */ -#define M66592_TEST_Reserved 0x4000 /* Reserved */ -#define M66592_TEST_VSTModes 0xC000 /* Vendor-specific tests */ -#define M66592_EP_DIR 0x0080 /* b7: Endpoint Direction */ -#define M66592_EP_DIR_IN 0x0080 -#define M66592_EP_DIR_OUT 0x0000 - -#define M66592_USBLENG 0x5A -#define M66592_wLength 0xFFFF /* b15-0: wLength */ - -#define M66592_DCPCFG 0x5C -#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode */ -#define M66592_DIR 0x0010 /* b4: Control transfer DIR select */ - -#define M66592_DCPMAXP 0x5E -#define M66592_DEVSEL 0xC000 /* b15-14: Device address select */ -#define M66592_DEVICE_0 0x0000 /* Device address 0 */ -#define M66592_DEVICE_1 0x4000 /* Device address 1 */ -#define M66592_DEVICE_2 0x8000 /* Device address 2 */ -#define M66592_DEVICE_3 0xC000 /* Device address 3 */ -#define M66592_MAXP 0x007F /* b6-0: Maxpacket size of ep0 */ - -#define M66592_DCPCTR 0x60 -#define M66592_BSTS 0x8000 /* b15: Buffer status */ -#define M66592_SUREQ 0x4000 /* b14: Send USB request */ -#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */ -#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */ -#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */ -#define M66592_CCPL 0x0004 /* b2: control transfer complete */ -#define M66592_PID 0x0003 /* b1-0: Response PID */ -#define M66592_PID_STALL 0x0002 /* STALL */ -#define M66592_PID_BUF 0x0001 /* BUF */ -#define M66592_PID_NAK 0x0000 /* NAK */ - -#define M66592_PIPESEL 0x64 -#define M66592_PIPENM 0x0007 /* b2-0: Pipe select */ -#define M66592_PIPE0 0x0000 /* PIPE 0 */ -#define M66592_PIPE1 0x0001 /* PIPE 1 */ -#define M66592_PIPE2 0x0002 /* PIPE 2 */ -#define M66592_PIPE3 0x0003 /* PIPE 3 */ -#define M66592_PIPE4 0x0004 /* PIPE 4 */ -#define M66592_PIPE5 0x0005 /* PIPE 5 */ -#define M66592_PIPE6 0x0006 /* PIPE 6 */ -#define M66592_PIPE7 0x0007 /* PIPE 7 */ - -#define M66592_PIPECFG 0x66 -#define M66592_TYP 0xC000 /* b15-14: Transfer type */ -#define M66592_ISO 0xC000 /* Isochronous */ -#define M66592_INT 0x8000 /* Interrupt */ -#define M66592_BULK 0x4000 /* Bulk */ -#define M66592_BFRE 0x0400 /* b10: Buffer ready interrupt mode */ -#define M66592_DBLB 0x0200 /* b9: Double buffer mode select */ -#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode */ -#define M66592_SHTNAK 0x0080 /* b7: Transfer end NAK */ -#define M66592_DIR 0x0010 /* b4: Transfer direction select */ -#define M66592_DIR_H_OUT 0x0010 /* HOST OUT */ -#define M66592_DIR_P_IN 0x0010 /* PERI IN */ -#define M66592_DIR_H_IN 0x0000 /* HOST IN */ -#define M66592_DIR_P_OUT 0x0000 /* PERI OUT */ -#define M66592_EPNUM 0x000F /* b3-0: Eendpoint number select */ -#define M66592_EP1 0x0001 -#define M66592_EP2 0x0002 -#define M66592_EP3 0x0003 -#define M66592_EP4 0x0004 -#define M66592_EP5 0x0005 -#define M66592_EP6 0x0006 -#define M66592_EP7 0x0007 -#define M66592_EP8 0x0008 -#define M66592_EP9 0x0009 -#define M66592_EP10 0x000A -#define M66592_EP11 0x000B -#define M66592_EP12 0x000C -#define M66592_EP13 0x000D -#define M66592_EP14 0x000E -#define M66592_EP15 0x000F - -#define M66592_PIPEBUF 0x68 -#define M66592_BUFSIZE 0x7C00 /* b14-10: Pipe buffer size */ -#define M66592_BUF_SIZE(x) ((((x) / 64) - 1) << 10) -#define M66592_BUFNMB 0x00FF /* b7-0: Pipe buffer number */ - -#define M66592_PIPEMAXP 0x6A -#define M66592_MXPS 0x07FF /* b10-0: Maxpacket size */ - -#define M66592_PIPEPERI 0x6C -#define M66592_IFIS 0x1000 /* b12: ISO in-buffer flush mode */ -#define M66592_IITV 0x0007 /* b2-0: ISO interval */ - -#define M66592_PIPE1CTR 0x70 -#define M66592_PIPE2CTR 0x72 -#define M66592_PIPE3CTR 0x74 -#define M66592_PIPE4CTR 0x76 -#define M66592_PIPE5CTR 0x78 -#define M66592_PIPE6CTR 0x7A -#define M66592_PIPE7CTR 0x7C -#define M66592_BSTS 0x8000 /* b15: Buffer status */ -#define M66592_INBUFM 0x4000 /* b14: IN buffer monitor (PIPE 1-5) */ -#define M66592_ACLRM 0x0200 /* b9: Out buffer auto clear mode */ -#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */ -#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */ -#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */ -#define M66592_PID 0x0003 /* b1-0: Response PID */ - -#define M66592_INVALID_REG 0x7E - - -#define get_pipectr_addr(pipenum) (M66592_PIPE1CTR + (pipenum - 1) * 2) - -#define M66592_MAX_SAMPLING 10 - -#define M66592_MAX_NUM_PIPE 8 -#define M66592_MAX_NUM_BULK 3 -#define M66592_MAX_NUM_ISOC 2 -#define M66592_MAX_NUM_INT 2 - -#define M66592_BASE_PIPENUM_BULK 3 -#define M66592_BASE_PIPENUM_ISOC 1 -#define M66592_BASE_PIPENUM_INT 6 - -#define M66592_BASE_BUFNUM 6 -#define M66592_MAX_BUFNUM 0x4F - -struct m66592_pipe_info { - u16 pipe; - u16 epnum; - u16 maxpacket; - u16 type; - u16 interval; - u16 dir_in; -}; - -struct m66592_request { - struct usb_request req; - struct list_head queue; -}; - -struct m66592_ep { - struct usb_ep ep; - struct m66592 *m66592; - - struct list_head queue; - unsigned busy:1; - unsigned internal_ccpl:1; /* use only control */ - - /* this member can able to after m66592_enable */ - unsigned use_dma:1; - u16 pipenum; - u16 type; - const struct usb_endpoint_descriptor *desc; - /* register address */ - unsigned long fifoaddr; - unsigned long fifosel; - unsigned long fifoctr; - unsigned long fifotrn; - unsigned long pipectr; -}; - -struct m66592 { - spinlock_t lock; - void __iomem *reg; -#ifdef CONFIG_HAVE_CLK - struct clk *clk; -#endif - struct m66592_platdata *pdata; - unsigned long irq_trigger; - - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - - struct m66592_ep ep[M66592_MAX_NUM_PIPE]; - struct m66592_ep *pipenum2ep[M66592_MAX_NUM_PIPE]; - struct m66592_ep *epaddr2ep[16]; - - struct usb_request *ep0_req; /* for internal request */ - __le16 ep0_data; /* for internal request */ - u16 old_vbus; - - struct timer_list timer; - - int scount; - - int old_dvsq; - - /* pipe config */ - int bulk; - int interrupt; - int isochronous; - int num_dma; -}; - -#define gadget_to_m66592(_gadget) container_of(_gadget, struct m66592, gadget) -#define m66592_to_gadget(m66592) (&m66592->gadget) - -#define is_bulk_pipe(pipenum) \ - ((pipenum >= M66592_BASE_PIPENUM_BULK) && \ - (pipenum < (M66592_BASE_PIPENUM_BULK + M66592_MAX_NUM_BULK))) -#define is_interrupt_pipe(pipenum) \ - ((pipenum >= M66592_BASE_PIPENUM_INT) && \ - (pipenum < (M66592_BASE_PIPENUM_INT + M66592_MAX_NUM_INT))) -#define is_isoc_pipe(pipenum) \ - ((pipenum >= M66592_BASE_PIPENUM_ISOC) && \ - (pipenum < (M66592_BASE_PIPENUM_ISOC + M66592_MAX_NUM_ISOC))) - -#define enable_irq_ready(m66592, pipenum) \ - enable_pipe_irq(m66592, pipenum, M66592_BRDYENB) -#define disable_irq_ready(m66592, pipenum) \ - disable_pipe_irq(m66592, pipenum, M66592_BRDYENB) -#define enable_irq_empty(m66592, pipenum) \ - enable_pipe_irq(m66592, pipenum, M66592_BEMPENB) -#define disable_irq_empty(m66592, pipenum) \ - disable_pipe_irq(m66592, pipenum, M66592_BEMPENB) -#define enable_irq_nrdy(m66592, pipenum) \ - enable_pipe_irq(m66592, pipenum, M66592_NRDYENB) -#define disable_irq_nrdy(m66592, pipenum) \ - disable_pipe_irq(m66592, pipenum, M66592_NRDYENB) - -/*-------------------------------------------------------------------------*/ -static inline u16 m66592_read(struct m66592 *m66592, unsigned long offset) -{ - return ioread16(m66592->reg + offset); -} - -static inline void m66592_read_fifo(struct m66592 *m66592, - unsigned long offset, - void *buf, unsigned long len) -{ - void __iomem *fifoaddr = m66592->reg + offset; - - if (m66592->pdata->on_chip) { - len = (len + 3) / 4; - ioread32_rep(fifoaddr, buf, len); - } else { - len = (len + 1) / 2; - ioread16_rep(fifoaddr, buf, len); - } -} - -static inline void m66592_write(struct m66592 *m66592, u16 val, - unsigned long offset) -{ - iowrite16(val, m66592->reg + offset); -} - -static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat, - unsigned long offset) -{ - u16 tmp; - tmp = m66592_read(m66592, offset); - tmp = tmp & (~pat); - tmp = tmp | val; - m66592_write(m66592, tmp, offset); -} - -#define m66592_bclr(m66592, val, offset) \ - m66592_mdfy(m66592, 0, val, offset) -#define m66592_bset(m66592, val, offset) \ - m66592_mdfy(m66592, val, 0, offset) - -static inline void m66592_write_fifo(struct m66592 *m66592, - struct m66592_ep *ep, - void *buf, unsigned long len) -{ - void __iomem *fifoaddr = m66592->reg + ep->fifoaddr; - - if (m66592->pdata->on_chip) { - unsigned long count; - unsigned char *pb; - int i; - - count = len / 4; - iowrite32_rep(fifoaddr, buf, count); - - if (len & 0x00000003) { - pb = buf + count * 4; - for (i = 0; i < (len & 0x00000003); i++) { - if (m66592_read(m66592, M66592_CFBCFG)) /* le */ - iowrite8(pb[i], fifoaddr + (3 - i)); - else - iowrite8(pb[i], fifoaddr + i); - } - } - } else { - unsigned long odd = len & 0x0001; - - len = len / 2; - iowrite16_rep(fifoaddr, buf, len); - if (odd) { - unsigned char *p = buf + len*2; - if (m66592->pdata->wr0_shorted_to_wr1) - m66592_bclr(m66592, M66592_MBW_16, ep->fifosel); - iowrite8(*p, fifoaddr); - if (m66592->pdata->wr0_shorted_to_wr1) - m66592_bset(m66592, M66592_MBW_16, ep->fifosel); - } - } -} - -#endif /* ifndef __M66592_UDC_H__ */ - - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/mass_storage.c b/ANDROID_3.4.5/drivers/usb/gadget/mass_storage.c deleted file mode 100644 index 1f376eba..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/mass_storage.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * mass_storage.c -- Mass Storage USB Gadget - * - * Copyright (C) 2003-2008 Alan Stern - * Copyright (C) 2009 Samsung Electronics - * Author: Michal Nazarewicz - * All rights reserved. - * - * 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. - */ - - -/* - * The Mass Storage Gadget acts as a USB Mass Storage device, - * appearing to the host as a disk drive or as a CD-ROM drive. In - * addition to providing an example of a genuinely useful gadget - * driver for a USB device, it also illustrates a technique of - * double-buffering for increased throughput. Last but not least, it - * gives an easy way to probe the behavior of the Mass Storage drivers - * in a USB host. - * - * Since this file serves only administrative purposes and all the - * business logic is implemented in f_mass_storage.* file. Read - * comments in this file for more detailed description. - */ - - -#include -#include -#include - - -/*-------------------------------------------------------------------------*/ - -#define DRIVER_DESC "Mass Storage Gadget" -#define DRIVER_VERSION "2009/09/11" - -/*-------------------------------------------------------------------------*/ - -/* - * 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 "f_mass_storage.c" - -/*-------------------------------------------------------------------------*/ - -static struct usb_device_descriptor msg_device_desc = { - .bLength = sizeof msg_device_desc, - .bDescriptorType = USB_DT_DEVICE, - - .bcdUSB = cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_PER_INTERFACE, - - /* Vendor and product id can be overridden by module parameters. */ - .idVendor = cpu_to_le16(FSG_VENDOR_ID), - .idProduct = cpu_to_le16(FSG_PRODUCT_ID), - .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, -}; - - -/****************************** Configurations ******************************/ - -static struct fsg_module_parameters mod_data = { - .stall = 1 -}; -FSG_MODULE_PARAMETERS(/* no prefix */, mod_data); - -static unsigned long msg_registered; -static void msg_cleanup(void); - -static int msg_thread_exits(struct fsg_common *common) -{ - msg_cleanup(); - return 0; -} - -static int __init msg_do_config(struct usb_configuration *c) -{ - static const struct fsg_operations ops = { - .thread_exits = msg_thread_exits, - }; - static struct fsg_common common; - - struct fsg_common *retp; - struct fsg_config config; - int ret; - - if (gadget_is_otg(c->cdev->gadget)) { - c->descriptors = otg_desc; - c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; - } - - fsg_config_from_params(&config, &mod_data); - config.ops = &ops; - - retp = fsg_common_init(&common, c->cdev, &config); - if (IS_ERR(retp)) - return PTR_ERR(retp); - - ret = fsg_bind_config(c->cdev, c, &common); - fsg_common_put(&common); - return ret; -} - -static struct usb_configuration msg_config_driver = { - .label = "Linux File-Backed Storage", - .bConfigurationValue = 1, - .bmAttributes = USB_CONFIG_ATT_SELFPOWER, -}; - - -/****************************** Gadget Bind ******************************/ - -static int __init msg_bind(struct usb_composite_dev *cdev) -{ - int status; - - status = usb_add_config(cdev, &msg_config_driver, msg_do_config); - if (status < 0) - return status; - - dev_info(&cdev->gadget->dev, - DRIVER_DESC ", version: " DRIVER_VERSION "\n"); - set_bit(0, &msg_registered); - return 0; -} - - -/****************************** Some noise ******************************/ - -static struct usb_composite_driver msg_driver = { - .name = "g_mass_storage", - .dev = &msg_device_desc, - .iProduct = DRIVER_DESC, - .max_speed = USB_SPEED_SUPER, - .needs_serial = 1, -}; - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Michal Nazarewicz"); -MODULE_LICENSE("GPL"); - -static int __init msg_init(void) -{ - return usb_composite_probe(&msg_driver, msg_bind); -} -module_init(msg_init); - -static void msg_cleanup(void) -{ - if (test_and_clear_bit(0, &msg_registered)) - usb_composite_unregister(&msg_driver); -} -module_exit(msg_cleanup); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/multi.c b/ANDROID_3.4.5/drivers/usb/gadget/multi.c deleted file mode 100644 index c37fb33a..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/multi.c +++ /dev/null @@ -1,362 +0,0 @@ -/* - * multi.c -- Multifunction Composite driver - * - * Copyright (C) 2008 David Brownell - * Copyright (C) 2008 Nokia Corporation - * Copyright (C) 2009 Samsung Electronics - * Author: Michal Nazarewicz (mina86@mina86.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - - -#include -#include -#include - - -#if defined USB_ETH_RNDIS -# undef USB_ETH_RNDIS -#endif -#ifdef CONFIG_USB_G_MULTI_RNDIS -# define USB_ETH_RNDIS y -#endif - - -#define DRIVER_DESC "Multifunction Composite Gadget" - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Michal Nazarewicz"); -MODULE_LICENSE("GPL"); - - -/***************************** All the files... *****************************/ - -/* - * 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 "f_mass_storage.c" - -#include "u_serial.c" -#include "f_acm.c" - -#include "f_ecm.c" -#include "f_subset.c" -#ifdef USB_ETH_RNDIS -# include "f_rndis.c" -# include "rndis.c" -#endif -#include "u_ether.c" - - - -/***************************** Device Descriptor ****************************/ - -#define MULTI_VENDOR_NUM 0x1d6b /* Linux Foundation */ -#define MULTI_PRODUCT_NUM 0x0104 /* Multifunction Composite Gadget */ - - -enum { - __MULTI_NO_CONFIG, -#ifdef CONFIG_USB_G_MULTI_RNDIS - MULTI_RNDIS_CONFIG_NUM, -#endif -#ifdef CONFIG_USB_G_MULTI_CDC - MULTI_CDC_CONFIG_NUM, -#endif -}; - - -static struct usb_device_descriptor device_desc = { - .bLength = sizeof device_desc, - .bDescriptorType = USB_DT_DEVICE, - - .bcdUSB = cpu_to_le16(0x0200), - - .bDeviceClass = USB_CLASS_MISC /* 0xEF */, - .bDeviceSubClass = 2, - .bDeviceProtocol = 1, - - /* Vendor and product id can be overridden by module parameters. */ - .idVendor = cpu_to_le16(MULTI_VENDOR_NUM), - .idProduct = cpu_to_le16(MULTI_PRODUCT_NUM), -}; - - -static const struct usb_descriptor_header *otg_desc[] = { - (struct usb_descriptor_header *) &(struct usb_otg_descriptor){ - .bLength = sizeof(struct usb_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, - }, - NULL, -}; - - -enum { -#ifdef CONFIG_USB_G_MULTI_RNDIS - MULTI_STRING_RNDIS_CONFIG_IDX, -#endif -#ifdef CONFIG_USB_G_MULTI_CDC - MULTI_STRING_CDC_CONFIG_IDX, -#endif -}; - -static struct usb_string strings_dev[] = { -#ifdef CONFIG_USB_G_MULTI_RNDIS - [MULTI_STRING_RNDIS_CONFIG_IDX].s = "Multifunction with RNDIS", -#endif -#ifdef CONFIG_USB_G_MULTI_CDC - [MULTI_STRING_CDC_CONFIG_IDX].s = "Multifunction with CDC ECM", -#endif - { } /* end of list */ -}; - -static struct usb_gadget_strings *dev_strings[] = { - &(struct usb_gadget_strings){ - .language = 0x0409, /* en-us */ - .strings = strings_dev, - }, - NULL, -}; - - - - -/****************************** Configurations ******************************/ - -static struct fsg_module_parameters fsg_mod_data = { .stall = 1 }; -FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data); - -static struct fsg_common fsg_common; - -static u8 hostaddr[ETH_ALEN]; - - -/********** RNDIS **********/ - -#ifdef USB_ETH_RNDIS - -static __init int rndis_do_config(struct usb_configuration *c) -{ - int ret; - - if (gadget_is_otg(c->cdev->gadget)) { - c->descriptors = otg_desc; - c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; - } - - ret = rndis_bind_config(c, hostaddr); - if (ret < 0) - return ret; - - ret = acm_bind_config(c, 0); - if (ret < 0) - return ret; - - ret = fsg_bind_config(c->cdev, c, &fsg_common); - if (ret < 0) - return ret; - - return 0; -} - -static int rndis_config_register(struct usb_composite_dev *cdev) -{ - static struct usb_configuration config = { - .bConfigurationValue = MULTI_RNDIS_CONFIG_NUM, - .bmAttributes = USB_CONFIG_ATT_SELFPOWER, - }; - - config.label = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].s; - config.iConfiguration = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].id; - - return usb_add_config(cdev, &config, rndis_do_config); -} - -#else - -static int rndis_config_register(struct usb_composite_dev *cdev) -{ - return 0; -} - -#endif - - -/********** CDC ECM **********/ - -#ifdef CONFIG_USB_G_MULTI_CDC - -static __init int cdc_do_config(struct usb_configuration *c) -{ - int ret; - - if (gadget_is_otg(c->cdev->gadget)) { - c->descriptors = otg_desc; - c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; - } - - ret = ecm_bind_config(c, hostaddr); - if (ret < 0) - return ret; - - ret = acm_bind_config(c, 0); - if (ret < 0) - return ret; - - ret = fsg_bind_config(c->cdev, c, &fsg_common); - if (ret < 0) - return ret; - - return 0; -} - -static int cdc_config_register(struct usb_composite_dev *cdev) -{ - static struct usb_configuration config = { - .bConfigurationValue = MULTI_CDC_CONFIG_NUM, - .bmAttributes = USB_CONFIG_ATT_SELFPOWER, - }; - - config.label = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].s; - config.iConfiguration = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].id; - - return usb_add_config(cdev, &config, cdc_do_config); -} - -#else - -static int cdc_config_register(struct usb_composite_dev *cdev) -{ - return 0; -} - -#endif - - - -/****************************** Gadget Bind ******************************/ - - -static int __ref multi_bind(struct usb_composite_dev *cdev) -{ - struct usb_gadget *gadget = cdev->gadget; - int status, gcnum; - - if (!can_support_ecm(cdev->gadget)) { - dev_err(&gadget->dev, "controller '%s' not usable\n", - gadget->name); - return -EINVAL; - } - - /* set up network link layer */ - status = gether_setup(cdev->gadget, hostaddr); - if (status < 0) - return status; - - /* set up serial link layer */ - status = gserial_setup(cdev->gadget, 1); - if (status < 0) - goto fail0; - - /* set up mass storage function */ - { - void *retp; - retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data); - if (IS_ERR(retp)) { - status = PTR_ERR(retp); - goto fail1; - } - } - - /* set bcdDevice */ - gcnum = usb_gadget_controller_number(gadget); - if (gcnum >= 0) { - device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum); - } else { - WARNING(cdev, "controller '%s' not recognized\n", gadget->name); - device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099); - } - - /* allocate string IDs */ - status = usb_string_ids_tab(cdev, strings_dev); - if (unlikely(status < 0)) - goto fail2; - - /* register configurations */ - status = rndis_config_register(cdev); - if (unlikely(status < 0)) - goto fail2; - - status = cdc_config_register(cdev); - if (unlikely(status < 0)) - goto fail2; - - /* we're done */ - dev_info(&gadget->dev, DRIVER_DESC "\n"); - fsg_common_put(&fsg_common); - return 0; - - - /* error recovery */ -fail2: - fsg_common_put(&fsg_common); -fail1: - gserial_cleanup(); -fail0: - gether_cleanup(); - return status; -} - -static int __exit multi_unbind(struct usb_composite_dev *cdev) -{ - gserial_cleanup(); - gether_cleanup(); - return 0; -} - - -/****************************** Some noise ******************************/ - - -static struct usb_composite_driver multi_driver = { - .name = "g_multi", - .dev = &device_desc, - .strings = dev_strings, - .max_speed = USB_SPEED_HIGH, - .unbind = __exit_p(multi_unbind), - .iProduct = DRIVER_DESC, - .needs_serial = 1, -}; - - -static int __init multi_init(void) -{ - return usb_composite_probe(&multi_driver, multi_bind); -} -module_init(multi_init); - -static void __exit multi_exit(void) -{ - usb_composite_unregister(&multi_driver); -} -module_exit(multi_exit); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/mv_udc.h b/ANDROID_3.4.5/drivers/usb/gadget/mv_udc.h deleted file mode 100644 index e2be9519..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/mv_udc.h +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (C) 2011 Marvell International Ltd. All rights reserved. - * - * 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. - */ - -#ifndef __MV_UDC_H -#define __MV_UDC_H - -#define VUSBHS_MAX_PORTS 8 - -#define DQH_ALIGNMENT 2048 -#define DTD_ALIGNMENT 64 -#define DMA_BOUNDARY 4096 - -#define EP_DIR_IN 1 -#define EP_DIR_OUT 0 - -#define DMA_ADDR_INVALID (~(dma_addr_t)0) - -#define EP0_MAX_PKT_SIZE 64 -/* ep0 transfer state */ -#define WAIT_FOR_SETUP 0 -#define DATA_STATE_XMIT 1 -#define DATA_STATE_NEED_ZLP 2 -#define WAIT_FOR_OUT_STATUS 3 -#define DATA_STATE_RECV 4 - -#define CAPLENGTH_MASK (0xff) -#define DCCPARAMS_DEN_MASK (0x1f) - -#define HCSPARAMS_PPC (0x10) - -/* Frame Index Register Bit Masks */ -#define USB_FRINDEX_MASKS 0x3fff - -/* Command Register Bit Masks */ -#define USBCMD_RUN_STOP (0x00000001) -#define USBCMD_CTRL_RESET (0x00000002) -#define USBCMD_SETUP_TRIPWIRE_SET (0x00002000) -#define USBCMD_SETUP_TRIPWIRE_CLEAR (~USBCMD_SETUP_TRIPWIRE_SET) - -#define USBCMD_ATDTW_TRIPWIRE_SET (0x00004000) -#define USBCMD_ATDTW_TRIPWIRE_CLEAR (~USBCMD_ATDTW_TRIPWIRE_SET) - -/* bit 15,3,2 are for frame list size */ -#define USBCMD_FRAME_SIZE_1024 (0x00000000) /* 000 */ -#define USBCMD_FRAME_SIZE_512 (0x00000004) /* 001 */ -#define USBCMD_FRAME_SIZE_256 (0x00000008) /* 010 */ -#define USBCMD_FRAME_SIZE_128 (0x0000000C) /* 011 */ -#define USBCMD_FRAME_SIZE_64 (0x00008000) /* 100 */ -#define USBCMD_FRAME_SIZE_32 (0x00008004) /* 101 */ -#define USBCMD_FRAME_SIZE_16 (0x00008008) /* 110 */ -#define USBCMD_FRAME_SIZE_8 (0x0000800C) /* 111 */ - -#define EPCTRL_TX_ALL_MASK (0xFFFF0000) -#define EPCTRL_RX_ALL_MASK (0x0000FFFF) - -#define EPCTRL_TX_DATA_TOGGLE_RST (0x00400000) -#define EPCTRL_TX_EP_STALL (0x00010000) -#define EPCTRL_RX_EP_STALL (0x00000001) -#define EPCTRL_RX_DATA_TOGGLE_RST (0x00000040) -#define EPCTRL_RX_ENABLE (0x00000080) -#define EPCTRL_TX_ENABLE (0x00800000) -#define EPCTRL_CONTROL (0x00000000) -#define EPCTRL_ISOCHRONOUS (0x00040000) -#define EPCTRL_BULK (0x00080000) -#define EPCTRL_INT (0x000C0000) -#define EPCTRL_TX_TYPE (0x000C0000) -#define EPCTRL_RX_TYPE (0x0000000C) -#define EPCTRL_DATA_TOGGLE_INHIBIT (0x00000020) -#define EPCTRL_TX_EP_TYPE_SHIFT (18) -#define EPCTRL_RX_EP_TYPE_SHIFT (2) - -#define EPCOMPLETE_MAX_ENDPOINTS (16) - -/* endpoint list address bit masks */ -#define USB_EP_LIST_ADDRESS_MASK 0xfffff800 - -#define PORTSCX_W1C_BITS 0x2a -#define PORTSCX_PORT_RESET 0x00000100 -#define PORTSCX_PORT_POWER 0x00001000 -#define PORTSCX_FORCE_FULL_SPEED_CONNECT 0x01000000 -#define PORTSCX_PAR_XCVR_SELECT 0xC0000000 -#define PORTSCX_PORT_FORCE_RESUME 0x00000040 -#define PORTSCX_PORT_SUSPEND 0x00000080 -#define PORTSCX_PORT_SPEED_FULL 0x00000000 -#define PORTSCX_PORT_SPEED_LOW 0x04000000 -#define PORTSCX_PORT_SPEED_HIGH 0x08000000 -#define PORTSCX_PORT_SPEED_MASK 0x0C000000 - -/* USB MODE Register Bit Masks */ -#define USBMODE_CTRL_MODE_IDLE 0x00000000 -#define USBMODE_CTRL_MODE_DEVICE 0x00000002 -#define USBMODE_CTRL_MODE_HOST 0x00000003 -#define USBMODE_CTRL_MODE_RSV 0x00000001 -#define USBMODE_SETUP_LOCK_OFF 0x00000008 -#define USBMODE_STREAM_DISABLE 0x00000010 - -/* USB STS Register Bit Masks */ -#define USBSTS_INT 0x00000001 -#define USBSTS_ERR 0x00000002 -#define USBSTS_PORT_CHANGE 0x00000004 -#define USBSTS_FRM_LST_ROLL 0x00000008 -#define USBSTS_SYS_ERR 0x00000010 -#define USBSTS_IAA 0x00000020 -#define USBSTS_RESET 0x00000040 -#define USBSTS_SOF 0x00000080 -#define USBSTS_SUSPEND 0x00000100 -#define USBSTS_HC_HALTED 0x00001000 -#define USBSTS_RCL 0x00002000 -#define USBSTS_PERIODIC_SCHEDULE 0x00004000 -#define USBSTS_ASYNC_SCHEDULE 0x00008000 - - -/* Interrupt Enable Register Bit Masks */ -#define USBINTR_INT_EN (0x00000001) -#define USBINTR_ERR_INT_EN (0x00000002) -#define USBINTR_PORT_CHANGE_DETECT_EN (0x00000004) - -#define USBINTR_ASYNC_ADV_AAE (0x00000020) -#define USBINTR_ASYNC_ADV_AAE_ENABLE (0x00000020) -#define USBINTR_ASYNC_ADV_AAE_DISABLE (0xFFFFFFDF) - -#define USBINTR_RESET_EN (0x00000040) -#define USBINTR_SOF_UFRAME_EN (0x00000080) -#define USBINTR_DEVICE_SUSPEND (0x00000100) - -#define USB_DEVICE_ADDRESS_MASK (0xfe000000) -#define USB_DEVICE_ADDRESS_BIT_SHIFT (25) - -struct mv_cap_regs { - u32 caplength_hciversion; - u32 hcsparams; /* HC structural parameters */ - u32 hccparams; /* HC Capability Parameters*/ - u32 reserved[5]; - u32 dciversion; /* DC version number and reserved 16 bits */ - u32 dccparams; /* DC Capability Parameters */ -}; - -struct mv_op_regs { - u32 usbcmd; /* Command register */ - u32 usbsts; /* Status register */ - u32 usbintr; /* Interrupt enable */ - u32 frindex; /* Frame index */ - u32 reserved1[1]; - u32 deviceaddr; /* Device Address */ - u32 eplistaddr; /* Endpoint List Address */ - u32 ttctrl; /* HOST TT status and control */ - u32 burstsize; /* Programmable Burst Size */ - u32 txfilltuning; /* Host Transmit Pre-Buffer Packet Tuning */ - u32 reserved[4]; - u32 epnak; /* Endpoint NAK */ - u32 epnaken; /* Endpoint NAK Enable */ - u32 configflag; /* Configured Flag register */ - u32 portsc[VUSBHS_MAX_PORTS]; /* Port Status/Control x, x = 1..8 */ - u32 otgsc; - u32 usbmode; /* USB Host/Device mode */ - u32 epsetupstat; /* Endpoint Setup Status */ - u32 epprime; /* Endpoint Initialize */ - u32 epflush; /* Endpoint De-initialize */ - u32 epstatus; /* Endpoint Status */ - u32 epcomplete; /* Endpoint Interrupt On Complete */ - u32 epctrlx[16]; /* Endpoint Control, where x = 0.. 15 */ - u32 mcr; /* Mux Control */ - u32 isr; /* Interrupt Status */ - u32 ier; /* Interrupt Enable */ -}; - -struct mv_udc { - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - spinlock_t lock; - struct completion *done; - struct platform_device *dev; - int irq; - - struct mv_cap_regs __iomem *cap_regs; - struct mv_op_regs __iomem *op_regs; - void __iomem *phy_regs; - unsigned int max_eps; - struct mv_dqh *ep_dqh; - size_t ep_dqh_size; - dma_addr_t ep_dqh_dma; - - struct dma_pool *dtd_pool; - struct mv_ep *eps; - - struct mv_dtd *dtd_head; - struct mv_dtd *dtd_tail; - unsigned int dtd_entries; - - struct mv_req *status_req; - struct usb_ctrlrequest local_setup_buff; - - unsigned int resume_state; /* USB state to resume */ - unsigned int usb_state; /* USB current state */ - unsigned int ep0_state; /* Endpoint zero state */ - unsigned int ep0_dir; - - unsigned int dev_addr; - unsigned int test_mode; - - int errors; - unsigned softconnect:1, - vbus_active:1, - remote_wakeup:1, - softconnected:1, - force_fs:1, - clock_gating:1, - active:1, - stopped:1; /* stop bit is setted */ - - struct work_struct vbus_work; - struct workqueue_struct *qwork; - - struct usb_phy *transceiver; - - struct mv_usb_platform_data *pdata; - - /* some SOC has mutiple clock sources for USB*/ - unsigned int clknum; - struct clk *clk[0]; -}; - -/* endpoint data structure */ -struct mv_ep { - struct usb_ep ep; - struct mv_udc *udc; - struct list_head queue; - struct mv_dqh *dqh; - const struct usb_endpoint_descriptor *desc; - u32 direction; - char name[14]; - unsigned stopped:1, - wedge:1, - ep_type:2, - ep_num:8; -}; - -/* request data structure */ -struct mv_req { - struct usb_request req; - struct mv_dtd *dtd, *head, *tail; - struct mv_ep *ep; - struct list_head queue; - unsigned int test_mode; - unsigned dtd_count; - unsigned mapped:1; -}; - -#define EP_QUEUE_HEAD_MULT_POS 30 -#define EP_QUEUE_HEAD_ZLT_SEL 0x20000000 -#define EP_QUEUE_HEAD_MAX_PKT_LEN_POS 16 -#define EP_QUEUE_HEAD_MAX_PKT_LEN(ep_info) (((ep_info)>>16)&0x07ff) -#define EP_QUEUE_HEAD_IOS 0x00008000 -#define EP_QUEUE_HEAD_NEXT_TERMINATE 0x00000001 -#define EP_QUEUE_HEAD_IOC 0x00008000 -#define EP_QUEUE_HEAD_MULTO 0x00000C00 -#define EP_QUEUE_HEAD_STATUS_HALT 0x00000040 -#define EP_QUEUE_HEAD_STATUS_ACTIVE 0x00000080 -#define EP_QUEUE_CURRENT_OFFSET_MASK 0x00000FFF -#define EP_QUEUE_HEAD_NEXT_POINTER_MASK 0xFFFFFFE0 -#define EP_QUEUE_FRINDEX_MASK 0x000007FF -#define EP_MAX_LENGTH_TRANSFER 0x4000 - -struct mv_dqh { - /* Bits 16..26 Bit 15 is Interrupt On Setup */ - u32 max_packet_length; - u32 curr_dtd_ptr; /* Current dTD Pointer */ - u32 next_dtd_ptr; /* Next dTD Pointer */ - /* Total bytes (16..30), IOC (15), INT (8), STS (0-7) */ - u32 size_ioc_int_sts; - u32 buff_ptr0; /* Buffer pointer Page 0 (12-31) */ - u32 buff_ptr1; /* Buffer pointer Page 1 (12-31) */ - u32 buff_ptr2; /* Buffer pointer Page 2 (12-31) */ - u32 buff_ptr3; /* Buffer pointer Page 3 (12-31) */ - u32 buff_ptr4; /* Buffer pointer Page 4 (12-31) */ - u32 reserved1; - /* 8 bytes of setup data that follows the Setup PID */ - u8 setup_buffer[8]; - u32 reserved2[4]; -}; - - -#define DTD_NEXT_TERMINATE (0x00000001) -#define DTD_IOC (0x00008000) -#define DTD_STATUS_ACTIVE (0x00000080) -#define DTD_STATUS_HALTED (0x00000040) -#define DTD_STATUS_DATA_BUFF_ERR (0x00000020) -#define DTD_STATUS_TRANSACTION_ERR (0x00000008) -#define DTD_RESERVED_FIELDS (0x00007F00) -#define DTD_ERROR_MASK (0x68) -#define DTD_ADDR_MASK (0xFFFFFFE0) -#define DTD_PACKET_SIZE 0x7FFF0000 -#define DTD_LENGTH_BIT_POS (16) - -struct mv_dtd { - u32 dtd_next; - u32 size_ioc_sts; - u32 buff_ptr0; /* Buffer pointer Page 0 */ - u32 buff_ptr1; /* Buffer pointer Page 1 */ - u32 buff_ptr2; /* Buffer pointer Page 2 */ - u32 buff_ptr3; /* Buffer pointer Page 3 */ - u32 buff_ptr4; /* Buffer pointer Page 4 */ - u32 scratch_ptr; - /* 32 bytes */ - dma_addr_t td_dma; /* dma address for this td */ - struct mv_dtd *next_dtd_virt; -}; - -#endif diff --git a/ANDROID_3.4.5/drivers/usb/gadget/mv_udc_core.c b/ANDROID_3.4.5/drivers/usb/gadget/mv_udc_core.c deleted file mode 100644 index a73cf406..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/mv_udc_core.c +++ /dev/null @@ -1,2494 +0,0 @@ -/* - * Copyright (C) 2011 Marvell International Ltd. All rights reserved. - * Author: Chao Xie - * Neil Zhang - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mv_udc.h" - -#define DRIVER_DESC "Marvell PXA USB Device Controller driver" -#define DRIVER_VERSION "8 Nov 2010" - -#define ep_dir(ep) (((ep)->ep_num == 0) ? \ - ((ep)->udc->ep0_dir) : ((ep)->direction)) - -/* timeout value -- usec */ -#define RESET_TIMEOUT 10000 -#define FLUSH_TIMEOUT 10000 -#define EPSTATUS_TIMEOUT 10000 -#define PRIME_TIMEOUT 10000 -#define READSAFE_TIMEOUT 1000 -#define DTD_TIMEOUT 1000 - -#define LOOPS_USEC_SHIFT 4 -#define LOOPS_USEC (1 << LOOPS_USEC_SHIFT) -#define LOOPS(timeout) ((timeout) >> LOOPS_USEC_SHIFT) - -static DECLARE_COMPLETION(release_done); - -static const char driver_name[] = "mv_udc"; -static const char driver_desc[] = DRIVER_DESC; - -/* controller device global variable */ -static struct mv_udc *the_controller; -int mv_usb_otgsc; - -static void nuke(struct mv_ep *ep, int status); -static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver); - -/* for endpoint 0 operations */ -static const struct usb_endpoint_descriptor mv_ep0_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 0, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, - .wMaxPacketSize = EP0_MAX_PKT_SIZE, -}; - -static void ep0_reset(struct mv_udc *udc) -{ - struct mv_ep *ep; - u32 epctrlx; - int i = 0; - - /* ep0 in and out */ - for (i = 0; i < 2; i++) { - ep = &udc->eps[i]; - ep->udc = udc; - - /* ep0 dQH */ - ep->dqh = &udc->ep_dqh[i]; - - /* configure ep0 endpoint capabilities in dQH */ - ep->dqh->max_packet_length = - (EP0_MAX_PKT_SIZE << EP_QUEUE_HEAD_MAX_PKT_LEN_POS) - | EP_QUEUE_HEAD_IOS; - - ep->dqh->next_dtd_ptr = EP_QUEUE_HEAD_NEXT_TERMINATE; - - epctrlx = readl(&udc->op_regs->epctrlx[0]); - if (i) { /* TX */ - epctrlx |= EPCTRL_TX_ENABLE - | (USB_ENDPOINT_XFER_CONTROL - << EPCTRL_TX_EP_TYPE_SHIFT); - - } else { /* RX */ - epctrlx |= EPCTRL_RX_ENABLE - | (USB_ENDPOINT_XFER_CONTROL - << EPCTRL_RX_EP_TYPE_SHIFT); - } - - writel(epctrlx, &udc->op_regs->epctrlx[0]); - } -} - -/* protocol ep0 stall, will automatically be cleared on new transaction */ -static void ep0_stall(struct mv_udc *udc) -{ - u32 epctrlx; - - /* set TX and RX to stall */ - epctrlx = readl(&udc->op_regs->epctrlx[0]); - epctrlx |= EPCTRL_RX_EP_STALL | EPCTRL_TX_EP_STALL; - writel(epctrlx, &udc->op_regs->epctrlx[0]); - - /* update ep0 state */ - udc->ep0_state = WAIT_FOR_SETUP; - udc->ep0_dir = EP_DIR_OUT; -} - -static int process_ep_req(struct mv_udc *udc, int index, - struct mv_req *curr_req) -{ - struct mv_dtd *curr_dtd; - struct mv_dqh *curr_dqh; - int td_complete, actual, remaining_length; - int i, direction; - int retval = 0; - u32 errors; - u32 bit_pos; - - curr_dqh = &udc->ep_dqh[index]; - direction = index % 2; - - curr_dtd = curr_req->head; - td_complete = 0; - actual = curr_req->req.length; - - for (i = 0; i < curr_req->dtd_count; i++) { - if (curr_dtd->size_ioc_sts & DTD_STATUS_ACTIVE) { - dev_dbg(&udc->dev->dev, "%s, dTD not completed\n", - udc->eps[index].name); - return 1; - } - - errors = curr_dtd->size_ioc_sts & DTD_ERROR_MASK; - if (!errors) { - remaining_length = - (curr_dtd->size_ioc_sts & DTD_PACKET_SIZE) - >> DTD_LENGTH_BIT_POS; - actual -= remaining_length; - - if (remaining_length) { - if (direction) { - dev_dbg(&udc->dev->dev, - "TX dTD remains data\n"); - retval = -EPROTO; - break; - } else - break; - } - } else { - dev_info(&udc->dev->dev, - "complete_tr error: ep=%d %s: error = 0x%x\n", - index >> 1, direction ? "SEND" : "RECV", - errors); - if (errors & DTD_STATUS_HALTED) { - /* Clear the errors and Halt condition */ - curr_dqh->size_ioc_int_sts &= ~errors; - retval = -EPIPE; - } else if (errors & DTD_STATUS_DATA_BUFF_ERR) { - retval = -EPROTO; - } else if (errors & DTD_STATUS_TRANSACTION_ERR) { - retval = -EILSEQ; - } - } - if (i != curr_req->dtd_count - 1) - curr_dtd = (struct mv_dtd *)curr_dtd->next_dtd_virt; - } - if (retval) - return retval; - - if (direction == EP_DIR_OUT) - bit_pos = 1 << curr_req->ep->ep_num; - else - bit_pos = 1 << (16 + curr_req->ep->ep_num); - - while ((curr_dqh->curr_dtd_ptr == curr_dtd->td_dma)) { - if (curr_dtd->dtd_next == EP_QUEUE_HEAD_NEXT_TERMINATE) { - while (readl(&udc->op_regs->epstatus) & bit_pos) - udelay(1); - break; - } - udelay(1); - } - - curr_req->req.actual = actual; - - return 0; -} - -/* - * done() - retire a request; caller blocked irqs - * @status : request status to be set, only works when - * request is still in progress. - */ -static void done(struct mv_ep *ep, struct mv_req *req, int status) -{ - struct mv_udc *udc = NULL; - unsigned char stopped = ep->stopped; - struct mv_dtd *curr_td, *next_td; - int j; - - udc = (struct mv_udc *)ep->udc; - /* Removed the req from fsl_ep->queue */ - list_del_init(&req->queue); - - /* req.status should be set as -EINPROGRESS in ep_queue() */ - if (req->req.status == -EINPROGRESS) - req->req.status = status; - else - status = req->req.status; - - /* Free dtd for the request */ - next_td = req->head; - for (j = 0; j < req->dtd_count; j++) { - curr_td = next_td; - if (j != req->dtd_count - 1) - next_td = curr_td->next_dtd_virt; - dma_pool_free(udc->dtd_pool, curr_td, curr_td->td_dma); - } - - if (req->mapped) { - dma_unmap_single(ep->udc->gadget.dev.parent, - req->req.dma, req->req.length, - ((ep_dir(ep) == EP_DIR_IN) ? - DMA_TO_DEVICE : DMA_FROM_DEVICE)); - req->req.dma = DMA_ADDR_INVALID; - req->mapped = 0; - } else - dma_sync_single_for_cpu(ep->udc->gadget.dev.parent, - req->req.dma, req->req.length, - ((ep_dir(ep) == EP_DIR_IN) ? - DMA_TO_DEVICE : DMA_FROM_DEVICE)); - - if (status && (status != -ESHUTDOWN)) - dev_info(&udc->dev->dev, "complete %s req %p stat %d len %u/%u", - ep->ep.name, &req->req, status, - req->req.actual, req->req.length); - - ep->stopped = 1; - - spin_unlock(&ep->udc->lock); - /* - * complete() is from gadget layer, - * eg fsg->bulk_in_complete() - */ - if (req->req.complete) - req->req.complete(&ep->ep, &req->req); - - spin_lock(&ep->udc->lock); - ep->stopped = stopped; -} - -static int queue_dtd(struct mv_ep *ep, struct mv_req *req) -{ - struct mv_udc *udc; - struct mv_dqh *dqh; - u32 bit_pos, direction; - u32 usbcmd, epstatus; - unsigned int loops; - int retval = 0; - - udc = ep->udc; - direction = ep_dir(ep); - dqh = &(udc->ep_dqh[ep->ep_num * 2 + direction]); - bit_pos = 1 << (((direction == EP_DIR_OUT) ? 0 : 16) + ep->ep_num); - - /* check if the pipe is empty */ - if (!(list_empty(&ep->queue))) { - struct mv_req *lastreq; - lastreq = list_entry(ep->queue.prev, struct mv_req, queue); - lastreq->tail->dtd_next = - req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK; - - wmb(); - - if (readl(&udc->op_regs->epprime) & bit_pos) - goto done; - - loops = LOOPS(READSAFE_TIMEOUT); - while (1) { - /* start with setting the semaphores */ - usbcmd = readl(&udc->op_regs->usbcmd); - usbcmd |= USBCMD_ATDTW_TRIPWIRE_SET; - writel(usbcmd, &udc->op_regs->usbcmd); - - /* read the endpoint status */ - epstatus = readl(&udc->op_regs->epstatus) & bit_pos; - - /* - * Reread the ATDTW semaphore bit to check if it is - * cleared. When hardware see a hazard, it will clear - * the bit or else we remain set to 1 and we can - * proceed with priming of endpoint if not already - * primed. - */ - if (readl(&udc->op_regs->usbcmd) - & USBCMD_ATDTW_TRIPWIRE_SET) - break; - - loops--; - if (loops == 0) { - dev_err(&udc->dev->dev, - "Timeout for ATDTW_TRIPWIRE...\n"); - retval = -ETIME; - goto done; - } - udelay(LOOPS_USEC); - } - - /* Clear the semaphore */ - usbcmd = readl(&udc->op_regs->usbcmd); - usbcmd &= USBCMD_ATDTW_TRIPWIRE_CLEAR; - writel(usbcmd, &udc->op_regs->usbcmd); - - if (epstatus) - goto done; - } - - /* Write dQH next pointer and terminate bit to 0 */ - dqh->next_dtd_ptr = req->head->td_dma - & EP_QUEUE_HEAD_NEXT_POINTER_MASK; - - /* clear active and halt bit, in case set from a previous error */ - dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED); - - /* Ensure that updates to the QH will occure before priming. */ - wmb(); - - /* Prime the Endpoint */ - writel(bit_pos, &udc->op_regs->epprime); - -done: - return retval; -} - - -static struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length, - dma_addr_t *dma, int *is_last) -{ - u32 temp; - struct mv_dtd *dtd; - struct mv_udc *udc; - - /* how big will this transfer be? */ - *length = min(req->req.length - req->req.actual, - (unsigned)EP_MAX_LENGTH_TRANSFER); - - udc = req->ep->udc; - - /* - * Be careful that no _GFP_HIGHMEM is set, - * or we can not use dma_to_virt - */ - dtd = dma_pool_alloc(udc->dtd_pool, GFP_KERNEL, dma); - if (dtd == NULL) - return dtd; - - dtd->td_dma = *dma; - /* initialize buffer page pointers */ - temp = (u32)(req->req.dma + req->req.actual); - dtd->buff_ptr0 = cpu_to_le32(temp); - temp &= ~0xFFF; - dtd->buff_ptr1 = cpu_to_le32(temp + 0x1000); - dtd->buff_ptr2 = cpu_to_le32(temp + 0x2000); - dtd->buff_ptr3 = cpu_to_le32(temp + 0x3000); - dtd->buff_ptr4 = cpu_to_le32(temp + 0x4000); - - req->req.actual += *length; - - /* zlp is needed if req->req.zero is set */ - if (req->req.zero) { - if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0) - *is_last = 1; - else - *is_last = 0; - } else if (req->req.length == req->req.actual) - *is_last = 1; - else - *is_last = 0; - - /* Fill in the transfer size; set active bit */ - temp = ((*length << DTD_LENGTH_BIT_POS) | DTD_STATUS_ACTIVE); - - /* Enable interrupt for the last dtd of a request */ - if (*is_last && !req->req.no_interrupt) - temp |= DTD_IOC; - - dtd->size_ioc_sts = temp; - - mb(); - - return dtd; -} - -/* generate dTD linked list for a request */ -static int req_to_dtd(struct mv_req *req) -{ - unsigned count; - int is_last, is_first = 1; - struct mv_dtd *dtd, *last_dtd = NULL; - struct mv_udc *udc; - dma_addr_t dma; - - udc = req->ep->udc; - - do { - dtd = build_dtd(req, &count, &dma, &is_last); - if (dtd == NULL) - return -ENOMEM; - - if (is_first) { - is_first = 0; - req->head = dtd; - } else { - last_dtd->dtd_next = dma; - last_dtd->next_dtd_virt = dtd; - } - last_dtd = dtd; - req->dtd_count++; - } while (!is_last); - - /* set terminate bit to 1 for the last dTD */ - dtd->dtd_next = DTD_NEXT_TERMINATE; - - req->tail = dtd; - - return 0; -} - -static int mv_ep_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct mv_udc *udc; - struct mv_ep *ep; - struct mv_dqh *dqh; - u16 max = 0; - u32 bit_pos, epctrlx, direction; - unsigned char zlt = 0, ios = 0, mult = 0; - unsigned long flags; - - ep = container_of(_ep, struct mv_ep, ep); - udc = ep->udc; - - if (!_ep || !desc || ep->desc - || desc->bDescriptorType != USB_DT_ENDPOINT) - return -EINVAL; - - if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - direction = ep_dir(ep); - max = usb_endpoint_maxp(desc); - - /* - * disable HW zero length termination select - * driver handles zero length packet through req->req.zero - */ - zlt = 1; - - bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num); - - /* Check if the Endpoint is Primed */ - if ((readl(&udc->op_regs->epprime) & bit_pos) - || (readl(&udc->op_regs->epstatus) & bit_pos)) { - dev_info(&udc->dev->dev, - "ep=%d %s: Init ERROR: ENDPTPRIME=0x%x," - " ENDPTSTATUS=0x%x, bit_pos=0x%x\n", - (unsigned)ep->ep_num, direction ? "SEND" : "RECV", - (unsigned)readl(&udc->op_regs->epprime), - (unsigned)readl(&udc->op_regs->epstatus), - (unsigned)bit_pos); - goto en_done; - } - /* Set the max packet length, interrupt on Setup and Mult fields */ - switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { - case USB_ENDPOINT_XFER_BULK: - zlt = 1; - mult = 0; - break; - case USB_ENDPOINT_XFER_CONTROL: - ios = 1; - case USB_ENDPOINT_XFER_INT: - mult = 0; - break; - case USB_ENDPOINT_XFER_ISOC: - /* Calculate transactions needed for high bandwidth iso */ - mult = (unsigned char)(1 + ((max >> 11) & 0x03)); - max = max & 0x7ff; /* bit 0~10 */ - /* 3 transactions at most */ - if (mult > 3) - goto en_done; - break; - default: - goto en_done; - } - - spin_lock_irqsave(&udc->lock, flags); - /* Get the endpoint queue head address */ - dqh = ep->dqh; - dqh->max_packet_length = (max << EP_QUEUE_HEAD_MAX_PKT_LEN_POS) - | (mult << EP_QUEUE_HEAD_MULT_POS) - | (zlt ? EP_QUEUE_HEAD_ZLT_SEL : 0) - | (ios ? EP_QUEUE_HEAD_IOS : 0); - dqh->next_dtd_ptr = 1; - dqh->size_ioc_int_sts = 0; - - ep->ep.maxpacket = max; - ep->desc = desc; - ep->stopped = 0; - - /* Enable the endpoint for Rx or Tx and set the endpoint type */ - epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]); - if (direction == EP_DIR_IN) { - epctrlx &= ~EPCTRL_TX_ALL_MASK; - epctrlx |= EPCTRL_TX_ENABLE | EPCTRL_TX_DATA_TOGGLE_RST - | ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - << EPCTRL_TX_EP_TYPE_SHIFT); - } else { - epctrlx &= ~EPCTRL_RX_ALL_MASK; - epctrlx |= EPCTRL_RX_ENABLE | EPCTRL_RX_DATA_TOGGLE_RST - | ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - << EPCTRL_RX_EP_TYPE_SHIFT); - } - writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]); - - /* - * Implement Guideline (GL# USB-7) The unused endpoint type must - * be programmed to bulk. - */ - epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]); - if ((epctrlx & EPCTRL_RX_ENABLE) == 0) { - epctrlx |= (USB_ENDPOINT_XFER_BULK - << EPCTRL_RX_EP_TYPE_SHIFT); - writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]); - } - - epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]); - if ((epctrlx & EPCTRL_TX_ENABLE) == 0) { - epctrlx |= (USB_ENDPOINT_XFER_BULK - << EPCTRL_TX_EP_TYPE_SHIFT); - writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]); - } - - spin_unlock_irqrestore(&udc->lock, flags); - - return 0; -en_done: - return -EINVAL; -} - -static int mv_ep_disable(struct usb_ep *_ep) -{ - struct mv_udc *udc; - struct mv_ep *ep; - struct mv_dqh *dqh; - u32 bit_pos, epctrlx, direction; - unsigned long flags; - - ep = container_of(_ep, struct mv_ep, ep); - if ((_ep == NULL) || !ep->desc) - return -EINVAL; - - udc = ep->udc; - - /* Get the endpoint queue head address */ - dqh = ep->dqh; - - spin_lock_irqsave(&udc->lock, flags); - - direction = ep_dir(ep); - bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num); - - /* Reset the max packet length and the interrupt on Setup */ - dqh->max_packet_length = 0; - - /* Disable the endpoint for Rx or Tx and reset the endpoint type */ - epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]); - epctrlx &= ~((direction == EP_DIR_IN) - ? (EPCTRL_TX_ENABLE | EPCTRL_TX_TYPE) - : (EPCTRL_RX_ENABLE | EPCTRL_RX_TYPE)); - writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]); - - /* nuke all pending requests (does flush) */ - nuke(ep, -ESHUTDOWN); - - ep->desc = NULL; - ep->ep.desc = NULL; - ep->stopped = 1; - - spin_unlock_irqrestore(&udc->lock, flags); - - return 0; -} - -static struct usb_request * -mv_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) -{ - struct mv_req *req = NULL; - - req = kzalloc(sizeof *req, gfp_flags); - if (!req) - return NULL; - - req->req.dma = DMA_ADDR_INVALID; - INIT_LIST_HEAD(&req->queue); - - return &req->req; -} - -static void mv_free_request(struct usb_ep *_ep, struct usb_request *_req) -{ - struct mv_req *req = NULL; - - req = container_of(_req, struct mv_req, req); - - if (_req) - kfree(req); -} - -static void mv_ep_fifo_flush(struct usb_ep *_ep) -{ - struct mv_udc *udc; - u32 bit_pos, direction; - struct mv_ep *ep; - unsigned int loops; - - if (!_ep) - return; - - ep = container_of(_ep, struct mv_ep, ep); - if (!ep->desc) - return; - - udc = ep->udc; - direction = ep_dir(ep); - - if (ep->ep_num == 0) - bit_pos = (1 << 16) | 1; - else if (direction == EP_DIR_OUT) - bit_pos = 1 << ep->ep_num; - else - bit_pos = 1 << (16 + ep->ep_num); - - loops = LOOPS(EPSTATUS_TIMEOUT); - do { - unsigned int inter_loops; - - if (loops == 0) { - dev_err(&udc->dev->dev, - "TIMEOUT for ENDPTSTATUS=0x%x, bit_pos=0x%x\n", - (unsigned)readl(&udc->op_regs->epstatus), - (unsigned)bit_pos); - return; - } - /* Write 1 to the Flush register */ - writel(bit_pos, &udc->op_regs->epflush); - - /* Wait until flushing completed */ - inter_loops = LOOPS(FLUSH_TIMEOUT); - while (readl(&udc->op_regs->epflush)) { - /* - * ENDPTFLUSH bit should be cleared to indicate this - * operation is complete - */ - if (inter_loops == 0) { - dev_err(&udc->dev->dev, - "TIMEOUT for ENDPTFLUSH=0x%x," - "bit_pos=0x%x\n", - (unsigned)readl(&udc->op_regs->epflush), - (unsigned)bit_pos); - return; - } - inter_loops--; - udelay(LOOPS_USEC); - } - loops--; - } while (readl(&udc->op_regs->epstatus) & bit_pos); -} - -/* queues (submits) an I/O request to an endpoint */ -static int -mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) -{ - struct mv_ep *ep = container_of(_ep, struct mv_ep, ep); - struct mv_req *req = container_of(_req, struct mv_req, req); - struct mv_udc *udc = ep->udc; - unsigned long flags; - - /* catch various bogus parameters */ - if (!_req || !req->req.complete || !req->req.buf - || !list_empty(&req->queue)) { - dev_err(&udc->dev->dev, "%s, bad params", __func__); - return -EINVAL; - } - if (unlikely(!_ep || !ep->desc)) { - dev_err(&udc->dev->dev, "%s, bad ep", __func__); - return -EINVAL; - } - if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { - if (req->req.length > ep->ep.maxpacket) - return -EMSGSIZE; - } - - udc = ep->udc; - if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - req->ep = ep; - - /* map virtual address to hardware */ - if (req->req.dma == DMA_ADDR_INVALID) { - req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, - req->req.buf, - req->req.length, ep_dir(ep) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - req->mapped = 1; - } else { - dma_sync_single_for_device(ep->udc->gadget.dev.parent, - req->req.dma, req->req.length, - ep_dir(ep) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - req->mapped = 0; - } - - req->req.status = -EINPROGRESS; - req->req.actual = 0; - req->dtd_count = 0; - - spin_lock_irqsave(&udc->lock, flags); - - /* build dtds and push them to device queue */ - if (!req_to_dtd(req)) { - int retval; - retval = queue_dtd(ep, req); - if (retval) { - spin_unlock_irqrestore(&udc->lock, flags); - return retval; - } - } else { - spin_unlock_irqrestore(&udc->lock, flags); - return -ENOMEM; - } - - /* Update ep0 state */ - if (ep->ep_num == 0) - udc->ep0_state = DATA_STATE_XMIT; - - /* irq handler advances the queue */ - list_add_tail(&req->queue, &ep->queue); - spin_unlock_irqrestore(&udc->lock, flags); - - return 0; -} - -static void mv_prime_ep(struct mv_ep *ep, struct mv_req *req) -{ - struct mv_dqh *dqh = ep->dqh; - u32 bit_pos; - - /* Write dQH next pointer and terminate bit to 0 */ - dqh->next_dtd_ptr = req->head->td_dma - & EP_QUEUE_HEAD_NEXT_POINTER_MASK; - - /* clear active and halt bit, in case set from a previous error */ - dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED); - - /* Ensure that updates to the QH will occure before priming. */ - wmb(); - - bit_pos = 1 << (((ep_dir(ep) == EP_DIR_OUT) ? 0 : 16) + ep->ep_num); - - /* Prime the Endpoint */ - writel(bit_pos, &ep->udc->op_regs->epprime); -} - -/* dequeues (cancels, unlinks) an I/O request from an endpoint */ -static int mv_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct mv_ep *ep = container_of(_ep, struct mv_ep, ep); - struct mv_req *req; - struct mv_udc *udc = ep->udc; - unsigned long flags; - int stopped, ret = 0; - u32 epctrlx; - - if (!_ep || !_req) - return -EINVAL; - - spin_lock_irqsave(&ep->udc->lock, flags); - stopped = ep->stopped; - - /* Stop the ep before we deal with the queue */ - ep->stopped = 1; - epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]); - if (ep_dir(ep) == EP_DIR_IN) - epctrlx &= ~EPCTRL_TX_ENABLE; - else - epctrlx &= ~EPCTRL_RX_ENABLE; - writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]); - - /* make sure it's actually queued on this endpoint */ - list_for_each_entry(req, &ep->queue, queue) { - if (&req->req == _req) - break; - } - if (&req->req != _req) { - ret = -EINVAL; - goto out; - } - - /* The request is in progress, or completed but not dequeued */ - if (ep->queue.next == &req->queue) { - _req->status = -ECONNRESET; - mv_ep_fifo_flush(_ep); /* flush current transfer */ - - /* The request isn't the last request in this ep queue */ - if (req->queue.next != &ep->queue) { - struct mv_req *next_req; - - next_req = list_entry(req->queue.next, - struct mv_req, queue); - - /* Point the QH to the first TD of next request */ - mv_prime_ep(ep, next_req); - } else { - struct mv_dqh *qh; - - qh = ep->dqh; - qh->next_dtd_ptr = 1; - qh->size_ioc_int_sts = 0; - } - - /* The request hasn't been processed, patch up the TD chain */ - } else { - struct mv_req *prev_req; - - prev_req = list_entry(req->queue.prev, struct mv_req, queue); - writel(readl(&req->tail->dtd_next), - &prev_req->tail->dtd_next); - - } - - done(ep, req, -ECONNRESET); - - /* Enable EP */ -out: - epctrlx = readl(&udc->op_regs->epctrlx[ep->ep_num]); - if (ep_dir(ep) == EP_DIR_IN) - epctrlx |= EPCTRL_TX_ENABLE; - else - epctrlx |= EPCTRL_RX_ENABLE; - writel(epctrlx, &udc->op_regs->epctrlx[ep->ep_num]); - ep->stopped = stopped; - - spin_unlock_irqrestore(&ep->udc->lock, flags); - return ret; -} - -static void ep_set_stall(struct mv_udc *udc, u8 ep_num, u8 direction, int stall) -{ - u32 epctrlx; - - epctrlx = readl(&udc->op_regs->epctrlx[ep_num]); - - if (stall) { - if (direction == EP_DIR_IN) - epctrlx |= EPCTRL_TX_EP_STALL; - else - epctrlx |= EPCTRL_RX_EP_STALL; - } else { - if (direction == EP_DIR_IN) { - epctrlx &= ~EPCTRL_TX_EP_STALL; - epctrlx |= EPCTRL_TX_DATA_TOGGLE_RST; - } else { - epctrlx &= ~EPCTRL_RX_EP_STALL; - epctrlx |= EPCTRL_RX_DATA_TOGGLE_RST; - } - } - writel(epctrlx, &udc->op_regs->epctrlx[ep_num]); -} - -static int ep_is_stall(struct mv_udc *udc, u8 ep_num, u8 direction) -{ - u32 epctrlx; - - epctrlx = readl(&udc->op_regs->epctrlx[ep_num]); - - if (direction == EP_DIR_OUT) - return (epctrlx & EPCTRL_RX_EP_STALL) ? 1 : 0; - else - return (epctrlx & EPCTRL_TX_EP_STALL) ? 1 : 0; -} - -static int mv_ep_set_halt_wedge(struct usb_ep *_ep, int halt, int wedge) -{ - struct mv_ep *ep; - unsigned long flags = 0; - int status = 0; - struct mv_udc *udc; - - ep = container_of(_ep, struct mv_ep, ep); - udc = ep->udc; - if (!_ep || !ep->desc) { - status = -EINVAL; - goto out; - } - - if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { - status = -EOPNOTSUPP; - goto out; - } - - /* - * Attempt to halt IN ep will fail if any transfer requests - * are still queue - */ - if (halt && (ep_dir(ep) == EP_DIR_IN) && !list_empty(&ep->queue)) { - status = -EAGAIN; - goto out; - } - - spin_lock_irqsave(&ep->udc->lock, flags); - ep_set_stall(udc, ep->ep_num, ep_dir(ep), halt); - if (halt && wedge) - ep->wedge = 1; - else if (!halt) - ep->wedge = 0; - spin_unlock_irqrestore(&ep->udc->lock, flags); - - if (ep->ep_num == 0) { - udc->ep0_state = WAIT_FOR_SETUP; - udc->ep0_dir = EP_DIR_OUT; - } -out: - return status; -} - -static int mv_ep_set_halt(struct usb_ep *_ep, int halt) -{ - return mv_ep_set_halt_wedge(_ep, halt, 0); -} - -static int mv_ep_set_wedge(struct usb_ep *_ep) -{ - return mv_ep_set_halt_wedge(_ep, 1, 1); -} - -static struct usb_ep_ops mv_ep_ops = { - .enable = mv_ep_enable, - .disable = mv_ep_disable, - - .alloc_request = mv_alloc_request, - .free_request = mv_free_request, - - .queue = mv_ep_queue, - .dequeue = mv_ep_dequeue, - - .set_wedge = mv_ep_set_wedge, - .set_halt = mv_ep_set_halt, - .fifo_flush = mv_ep_fifo_flush, /* flush fifo */ -}; - -static void udc_clock_enable(struct mv_udc *udc) -{ - unsigned int i; - - for (i = 0; i < udc->clknum; i++) - clk_enable(udc->clk[i]); -} - -static void udc_clock_disable(struct mv_udc *udc) -{ - unsigned int i; - - for (i = 0; i < udc->clknum; i++) - clk_disable(udc->clk[i]); -} - -static void udc_stop(struct mv_udc *udc) -{ - u32 tmp; - - /* Disable interrupts */ - tmp = readl(&udc->op_regs->usbintr); - tmp &= ~(USBINTR_INT_EN | USBINTR_ERR_INT_EN | - USBINTR_PORT_CHANGE_DETECT_EN | USBINTR_RESET_EN); - writel(tmp, &udc->op_regs->usbintr); - - udc->stopped = 1; - - /* Reset the Run the bit in the command register to stop VUSB */ - tmp = readl(&udc->op_regs->usbcmd); - tmp &= ~USBCMD_RUN_STOP; - writel(tmp, &udc->op_regs->usbcmd); -} - -static void udc_start(struct mv_udc *udc) -{ - u32 usbintr; - - usbintr = USBINTR_INT_EN | USBINTR_ERR_INT_EN - | USBINTR_PORT_CHANGE_DETECT_EN - | USBINTR_RESET_EN | USBINTR_DEVICE_SUSPEND; - /* Enable interrupts */ - writel(usbintr, &udc->op_regs->usbintr); - - udc->stopped = 0; - - /* Set the Run bit in the command register */ - writel(USBCMD_RUN_STOP, &udc->op_regs->usbcmd); -} - -static int udc_reset(struct mv_udc *udc) -{ - unsigned int loops; - u32 tmp, portsc; - - /* Stop the controller */ - tmp = readl(&udc->op_regs->usbcmd); - tmp &= ~USBCMD_RUN_STOP; - writel(tmp, &udc->op_regs->usbcmd); - - /* Reset the controller to get default values */ - writel(USBCMD_CTRL_RESET, &udc->op_regs->usbcmd); - - /* wait for reset to complete */ - loops = LOOPS(RESET_TIMEOUT); - while (readl(&udc->op_regs->usbcmd) & USBCMD_CTRL_RESET) { - if (loops == 0) { - dev_err(&udc->dev->dev, - "Wait for RESET completed TIMEOUT\n"); - return -ETIMEDOUT; - } - loops--; - udelay(LOOPS_USEC); - } - - /* set controller to device mode */ - tmp = readl(&udc->op_regs->usbmode); - tmp |= USBMODE_CTRL_MODE_DEVICE; - - /* turn setup lockout off, require setup tripwire in usbcmd */ - tmp |= USBMODE_SETUP_LOCK_OFF | USBMODE_STREAM_DISABLE; - - writel(tmp, &udc->op_regs->usbmode); - - writel(0x0, &udc->op_regs->epsetupstat); - - /* Configure the Endpoint List Address */ - writel(udc->ep_dqh_dma & USB_EP_LIST_ADDRESS_MASK, - &udc->op_regs->eplistaddr); - - portsc = readl(&udc->op_regs->portsc[0]); - if (readl(&udc->cap_regs->hcsparams) & HCSPARAMS_PPC) - portsc &= (~PORTSCX_W1C_BITS | ~PORTSCX_PORT_POWER); - - if (udc->force_fs) - portsc |= PORTSCX_FORCE_FULL_SPEED_CONNECT; - else - portsc &= (~PORTSCX_FORCE_FULL_SPEED_CONNECT); - - writel(portsc, &udc->op_regs->portsc[0]); - - tmp = readl(&udc->op_regs->epctrlx[0]); - tmp &= ~(EPCTRL_TX_EP_STALL | EPCTRL_RX_EP_STALL); - writel(tmp, &udc->op_regs->epctrlx[0]); - - return 0; -} - -static int mv_udc_enable_internal(struct mv_udc *udc) -{ - int retval; - - if (udc->active) - return 0; - - dev_dbg(&udc->dev->dev, "enable udc\n"); - udc_clock_enable(udc); - if (udc->pdata->phy_init) { - retval = udc->pdata->phy_init(udc->phy_regs); - if (retval) { - dev_err(&udc->dev->dev, - "init phy error %d\n", retval); - udc_clock_disable(udc); - return retval; - } - } - udc->active = 1; - - return 0; -} - -static int mv_udc_enable(struct mv_udc *udc) -{ - if (udc->clock_gating) - return mv_udc_enable_internal(udc); - - return 0; -} - -static void mv_udc_disable_internal(struct mv_udc *udc) -{ - if (udc->active) { - dev_dbg(&udc->dev->dev, "disable udc\n"); - if (udc->pdata->phy_deinit) - udc->pdata->phy_deinit(udc->phy_regs); - udc_clock_disable(udc); - udc->active = 0; - } -} - -static void mv_udc_disable(struct mv_udc *udc) -{ - if (udc->clock_gating) - mv_udc_disable_internal(udc); -} - -static int mv_udc_get_frame(struct usb_gadget *gadget) -{ - struct mv_udc *udc; - u16 retval; - - if (!gadget) - return -ENODEV; - - udc = container_of(gadget, struct mv_udc, gadget); - - retval = readl(&udc->op_regs->frindex) & USB_FRINDEX_MASKS; - - return retval; -} - -/* Tries to wake up the host connected to this gadget */ -static int mv_udc_wakeup(struct usb_gadget *gadget) -{ - struct mv_udc *udc = container_of(gadget, struct mv_udc, gadget); - u32 portsc; - - /* Remote wakeup feature not enabled by host */ - if (!udc->remote_wakeup) - return -ENOTSUPP; - - portsc = readl(&udc->op_regs->portsc); - /* not suspended? */ - if (!(portsc & PORTSCX_PORT_SUSPEND)) - return 0; - /* trigger force resume */ - portsc |= PORTSCX_PORT_FORCE_RESUME; - writel(portsc, &udc->op_regs->portsc[0]); - return 0; -} - -static int mv_udc_vbus_session(struct usb_gadget *gadget, int is_active) -{ - struct mv_udc *udc; - unsigned long flags; - int retval = 0; - - udc = container_of(gadget, struct mv_udc, gadget); - spin_lock_irqsave(&udc->lock, flags); - - udc->vbus_active = (is_active != 0); - - dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n", - __func__, udc->softconnect, udc->vbus_active); - - if (udc->driver && udc->softconnect && udc->vbus_active) { - retval = mv_udc_enable(udc); - if (retval == 0) { - /* Clock is disabled, need re-init registers */ - udc_reset(udc); - ep0_reset(udc); - udc_start(udc); - } - } else if (udc->driver && udc->softconnect) { - /* stop all the transfer in queue*/ - stop_activity(udc, udc->driver); - udc_stop(udc); - mv_udc_disable(udc); - } - - spin_unlock_irqrestore(&udc->lock, flags); - return retval; -} - -static int mv_udc_pullup(struct usb_gadget *gadget, int is_on) -{ - struct mv_udc *udc; - unsigned long flags; - int retval = 0; - - udc = container_of(gadget, struct mv_udc, gadget); - spin_lock_irqsave(&udc->lock, flags); - - udc->softconnect = (is_on != 0); - - dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n", - __func__, udc->softconnect, udc->vbus_active); - - if (udc->driver && udc->softconnect && udc->vbus_active) { - retval = mv_udc_enable(udc); - if (retval == 0) { - /* Clock is disabled, need re-init registers */ - udc_reset(udc); - ep0_reset(udc); - udc_start(udc); - } - } else if (udc->driver && udc->vbus_active) { - /* stop all the transfer in queue*/ - stop_activity(udc, udc->driver); - udc_stop(udc); - mv_udc_disable(udc); - } - - spin_unlock_irqrestore(&udc->lock, flags); - return retval; -} - -static int mv_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int mv_udc_stop(struct usb_gadget_driver *driver); -/* device controller usb_gadget_ops structure */ -static const struct usb_gadget_ops mv_ops = { - - /* returns the current frame number */ - .get_frame = mv_udc_get_frame, - - /* tries to wake up the host connected to this gadget */ - .wakeup = mv_udc_wakeup, - - /* notify controller that VBUS is powered or not */ - .vbus_session = mv_udc_vbus_session, - - /* D+ pullup, software-controlled connect/disconnect to USB host */ - .pullup = mv_udc_pullup, - .start = mv_udc_start, - .stop = mv_udc_stop, -}; - -static int eps_init(struct mv_udc *udc) -{ - struct mv_ep *ep; - char name[14]; - int i; - - /* initialize ep0 */ - ep = &udc->eps[0]; - ep->udc = udc; - strncpy(ep->name, "ep0", sizeof(ep->name)); - ep->ep.name = ep->name; - ep->ep.ops = &mv_ep_ops; - ep->wedge = 0; - ep->stopped = 0; - ep->ep.maxpacket = EP0_MAX_PKT_SIZE; - ep->ep_num = 0; - ep->desc = &mv_ep0_desc; - INIT_LIST_HEAD(&ep->queue); - - ep->ep_type = USB_ENDPOINT_XFER_CONTROL; - - /* initialize other endpoints */ - for (i = 2; i < udc->max_eps * 2; i++) { - ep = &udc->eps[i]; - if (i % 2) { - snprintf(name, sizeof(name), "ep%din", i / 2); - ep->direction = EP_DIR_IN; - } else { - snprintf(name, sizeof(name), "ep%dout", i / 2); - ep->direction = EP_DIR_OUT; - } - ep->udc = udc; - strncpy(ep->name, name, sizeof(ep->name)); - ep->ep.name = ep->name; - - ep->ep.ops = &mv_ep_ops; - ep->stopped = 0; - ep->ep.maxpacket = (unsigned short) ~0; - ep->ep_num = i / 2; - - INIT_LIST_HEAD(&ep->queue); - list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); - - ep->dqh = &udc->ep_dqh[i]; - } - - return 0; -} - -/* delete all endpoint requests, called with spinlock held */ -static void nuke(struct mv_ep *ep, int status) -{ - /* called with spinlock held */ - ep->stopped = 1; - - /* endpoint fifo flush */ - mv_ep_fifo_flush(&ep->ep); - - while (!list_empty(&ep->queue)) { - struct mv_req *req = NULL; - req = list_entry(ep->queue.next, struct mv_req, queue); - done(ep, req, status); - } -} - -/* stop all USB activities */ -static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver) -{ - struct mv_ep *ep; - - nuke(&udc->eps[0], -ESHUTDOWN); - - list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { - nuke(ep, -ESHUTDOWN); - } - - /* report disconnect; the driver is already quiesced */ - if (driver) { - spin_unlock(&udc->lock); - driver->disconnect(&udc->gadget); - spin_lock(&udc->lock); - } -} - -static int mv_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) -{ - struct mv_udc *udc = the_controller; - int retval = 0; - unsigned long flags; - - if (!udc) - return -ENODEV; - - if (udc->driver) - return -EBUSY; - - spin_lock_irqsave(&udc->lock, flags); - - /* hook up the driver ... */ - driver->driver.bus = NULL; - udc->driver = driver; - udc->gadget.dev.driver = &driver->driver; - - udc->usb_state = USB_STATE_ATTACHED; - udc->ep0_state = WAIT_FOR_SETUP; - udc->ep0_dir = EP_DIR_OUT; - - spin_unlock_irqrestore(&udc->lock, flags); - - retval = bind(&udc->gadget); - if (retval) { - dev_err(&udc->dev->dev, "bind to driver %s --> %d\n", - driver->driver.name, retval); - udc->driver = NULL; - udc->gadget.dev.driver = NULL; - return retval; - } - - if (udc->transceiver) { - retval = otg_set_peripheral(udc->transceiver->otg, - &udc->gadget); - if (retval) { - dev_err(&udc->dev->dev, - "unable to register peripheral to otg\n"); - if (driver->unbind) { - driver->unbind(&udc->gadget); - udc->gadget.dev.driver = NULL; - udc->driver = NULL; - } - return retval; - } - } - - /* pullup is always on */ - mv_udc_pullup(&udc->gadget, 1); - - /* When boot with cable attached, there will be no vbus irq occurred */ - if (udc->qwork) - queue_work(udc->qwork, &udc->vbus_work); - - return 0; -} - -static int mv_udc_stop(struct usb_gadget_driver *driver) -{ - struct mv_udc *udc = the_controller; - unsigned long flags; - - if (!udc) - return -ENODEV; - - spin_lock_irqsave(&udc->lock, flags); - - mv_udc_enable(udc); - udc_stop(udc); - - /* stop all usb activities */ - udc->gadget.speed = USB_SPEED_UNKNOWN; - stop_activity(udc, driver); - mv_udc_disable(udc); - - spin_unlock_irqrestore(&udc->lock, flags); - - /* unbind gadget driver */ - driver->unbind(&udc->gadget); - udc->gadget.dev.driver = NULL; - udc->driver = NULL; - - return 0; -} - -static void mv_set_ptc(struct mv_udc *udc, u32 mode) -{ - u32 portsc; - - portsc = readl(&udc->op_regs->portsc[0]); - portsc |= mode << 16; - writel(portsc, &udc->op_regs->portsc[0]); -} - -static void prime_status_complete(struct usb_ep *ep, struct usb_request *_req) -{ - struct mv_udc *udc = the_controller; - struct mv_req *req = container_of(_req, struct mv_req, req); - unsigned long flags; - - dev_info(&udc->dev->dev, "switch to test mode %d\n", req->test_mode); - - spin_lock_irqsave(&udc->lock, flags); - if (req->test_mode) { - mv_set_ptc(udc, req->test_mode); - req->test_mode = 0; - } - spin_unlock_irqrestore(&udc->lock, flags); -} - -static int -udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty) -{ - int retval = 0; - struct mv_req *req; - struct mv_ep *ep; - - ep = &udc->eps[0]; - udc->ep0_dir = direction; - udc->ep0_state = WAIT_FOR_OUT_STATUS; - - req = udc->status_req; - - /* fill in the reqest structure */ - if (empty == false) { - *((u16 *) req->req.buf) = cpu_to_le16(status); - req->req.length = 2; - } else - req->req.length = 0; - - req->ep = ep; - req->req.status = -EINPROGRESS; - req->req.actual = 0; - if (udc->test_mode) { - req->req.complete = prime_status_complete; - req->test_mode = udc->test_mode; - udc->test_mode = 0; - } else - req->req.complete = NULL; - req->dtd_count = 0; - - if (req->req.dma == DMA_ADDR_INVALID) { - req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, - req->req.buf, req->req.length, - ep_dir(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - req->mapped = 1; - } - - /* prime the data phase */ - if (!req_to_dtd(req)) - retval = queue_dtd(ep, req); - else{ /* no mem */ - retval = -ENOMEM; - goto out; - } - - if (retval) { - dev_err(&udc->dev->dev, "response error on GET_STATUS request\n"); - goto out; - } - - list_add_tail(&req->queue, &ep->queue); - - return 0; -out: - return retval; -} - -static void mv_udc_testmode(struct mv_udc *udc, u16 index) -{ - if (index <= TEST_FORCE_EN) { - udc->test_mode = index; - if (udc_prime_status(udc, EP_DIR_IN, 0, true)) - ep0_stall(udc); - } else - dev_err(&udc->dev->dev, - "This test mode(%d) is not supported\n", index); -} - -static void ch9setaddress(struct mv_udc *udc, struct usb_ctrlrequest *setup) -{ - udc->dev_addr = (u8)setup->wValue; - - /* update usb state */ - udc->usb_state = USB_STATE_ADDRESS; - - if (udc_prime_status(udc, EP_DIR_IN, 0, true)) - ep0_stall(udc); -} - -static void ch9getstatus(struct mv_udc *udc, u8 ep_num, - struct usb_ctrlrequest *setup) -{ - u16 status = 0; - int retval; - - if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK)) - != (USB_DIR_IN | USB_TYPE_STANDARD)) - return; - - if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) { - status = 1 << USB_DEVICE_SELF_POWERED; - status |= udc->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP; - } else if ((setup->bRequestType & USB_RECIP_MASK) - == USB_RECIP_INTERFACE) { - /* get interface status */ - status = 0; - } else if ((setup->bRequestType & USB_RECIP_MASK) - == USB_RECIP_ENDPOINT) { - u8 ep_num, direction; - - ep_num = setup->wIndex & USB_ENDPOINT_NUMBER_MASK; - direction = (setup->wIndex & USB_ENDPOINT_DIR_MASK) - ? EP_DIR_IN : EP_DIR_OUT; - status = ep_is_stall(udc, ep_num, direction) - << USB_ENDPOINT_HALT; - } - - retval = udc_prime_status(udc, EP_DIR_IN, status, false); - if (retval) - ep0_stall(udc); - else - udc->ep0_state = DATA_STATE_XMIT; -} - -static void ch9clearfeature(struct mv_udc *udc, struct usb_ctrlrequest *setup) -{ - u8 ep_num; - u8 direction; - struct mv_ep *ep; - - if ((setup->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK)) - == ((USB_TYPE_STANDARD | USB_RECIP_DEVICE))) { - switch (setup->wValue) { - case USB_DEVICE_REMOTE_WAKEUP: - udc->remote_wakeup = 0; - break; - default: - goto out; - } - } else if ((setup->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK)) - == ((USB_TYPE_STANDARD | USB_RECIP_ENDPOINT))) { - switch (setup->wValue) { - case USB_ENDPOINT_HALT: - ep_num = setup->wIndex & USB_ENDPOINT_NUMBER_MASK; - direction = (setup->wIndex & USB_ENDPOINT_DIR_MASK) - ? EP_DIR_IN : EP_DIR_OUT; - if (setup->wValue != 0 || setup->wLength != 0 - || ep_num > udc->max_eps) - goto out; - ep = &udc->eps[ep_num * 2 + direction]; - if (ep->wedge == 1) - break; - spin_unlock(&udc->lock); - ep_set_stall(udc, ep_num, direction, 0); - spin_lock(&udc->lock); - break; - default: - goto out; - } - } else - goto out; - - if (udc_prime_status(udc, EP_DIR_IN, 0, true)) - ep0_stall(udc); -out: - return; -} - -static void ch9setfeature(struct mv_udc *udc, struct usb_ctrlrequest *setup) -{ - u8 ep_num; - u8 direction; - - if ((setup->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK)) - == ((USB_TYPE_STANDARD | USB_RECIP_DEVICE))) { - switch (setup->wValue) { - case USB_DEVICE_REMOTE_WAKEUP: - udc->remote_wakeup = 1; - break; - case USB_DEVICE_TEST_MODE: - if (setup->wIndex & 0xFF - || udc->gadget.speed != USB_SPEED_HIGH) - ep0_stall(udc); - - if (udc->usb_state != USB_STATE_CONFIGURED - && udc->usb_state != USB_STATE_ADDRESS - && udc->usb_state != USB_STATE_DEFAULT) - ep0_stall(udc); - - mv_udc_testmode(udc, (setup->wIndex >> 8)); - goto out; - default: - goto out; - } - } else if ((setup->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK)) - == ((USB_TYPE_STANDARD | USB_RECIP_ENDPOINT))) { - switch (setup->wValue) { - case USB_ENDPOINT_HALT: - ep_num = setup->wIndex & USB_ENDPOINT_NUMBER_MASK; - direction = (setup->wIndex & USB_ENDPOINT_DIR_MASK) - ? EP_DIR_IN : EP_DIR_OUT; - if (setup->wValue != 0 || setup->wLength != 0 - || ep_num > udc->max_eps) - goto out; - spin_unlock(&udc->lock); - ep_set_stall(udc, ep_num, direction, 1); - spin_lock(&udc->lock); - break; - default: - goto out; - } - } else - goto out; - - if (udc_prime_status(udc, EP_DIR_IN, 0, true)) - ep0_stall(udc); -out: - return; -} - -static void handle_setup_packet(struct mv_udc *udc, u8 ep_num, - struct usb_ctrlrequest *setup) -{ - bool delegate = false; - - nuke(&udc->eps[ep_num * 2 + EP_DIR_OUT], -ESHUTDOWN); - - dev_dbg(&udc->dev->dev, "SETUP %02x.%02x v%04x i%04x l%04x\n", - setup->bRequestType, setup->bRequest, - setup->wValue, setup->wIndex, setup->wLength); - /* We process some stardard setup requests here */ - if ((setup->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { - switch (setup->bRequest) { - case USB_REQ_GET_STATUS: - ch9getstatus(udc, ep_num, setup); - break; - - case USB_REQ_SET_ADDRESS: - ch9setaddress(udc, setup); - break; - - case USB_REQ_CLEAR_FEATURE: - ch9clearfeature(udc, setup); - break; - - case USB_REQ_SET_FEATURE: - ch9setfeature(udc, setup); - break; - - default: - delegate = true; - } - } else - delegate = true; - - /* delegate USB standard requests to the gadget driver */ - if (delegate == true) { - /* USB requests handled by gadget */ - if (setup->wLength) { - /* DATA phase from gadget, STATUS phase from udc */ - udc->ep0_dir = (setup->bRequestType & USB_DIR_IN) - ? EP_DIR_IN : EP_DIR_OUT; - spin_unlock(&udc->lock); - if (udc->driver->setup(&udc->gadget, - &udc->local_setup_buff) < 0) - ep0_stall(udc); - spin_lock(&udc->lock); - udc->ep0_state = (setup->bRequestType & USB_DIR_IN) - ? DATA_STATE_XMIT : DATA_STATE_RECV; - } else { - /* no DATA phase, IN STATUS phase from gadget */ - udc->ep0_dir = EP_DIR_IN; - spin_unlock(&udc->lock); - if (udc->driver->setup(&udc->gadget, - &udc->local_setup_buff) < 0) - ep0_stall(udc); - spin_lock(&udc->lock); - udc->ep0_state = WAIT_FOR_OUT_STATUS; - } - } -} - -/* complete DATA or STATUS phase of ep0 prime status phase if needed */ -static void ep0_req_complete(struct mv_udc *udc, - struct mv_ep *ep0, struct mv_req *req) -{ - u32 new_addr; - - if (udc->usb_state == USB_STATE_ADDRESS) { - /* set the new address */ - new_addr = (u32)udc->dev_addr; - writel(new_addr << USB_DEVICE_ADDRESS_BIT_SHIFT, - &udc->op_regs->deviceaddr); - } - - done(ep0, req, 0); - - switch (udc->ep0_state) { - case DATA_STATE_XMIT: - /* receive status phase */ - if (udc_prime_status(udc, EP_DIR_OUT, 0, true)) - ep0_stall(udc); - break; - case DATA_STATE_RECV: - /* send status phase */ - if (udc_prime_status(udc, EP_DIR_IN, 0 , true)) - ep0_stall(udc); - break; - case WAIT_FOR_OUT_STATUS: - udc->ep0_state = WAIT_FOR_SETUP; - break; - case WAIT_FOR_SETUP: - dev_err(&udc->dev->dev, "unexpect ep0 packets\n"); - break; - default: - ep0_stall(udc); - break; - } -} - -static void get_setup_data(struct mv_udc *udc, u8 ep_num, u8 *buffer_ptr) -{ - u32 temp; - struct mv_dqh *dqh; - - dqh = &udc->ep_dqh[ep_num * 2 + EP_DIR_OUT]; - - /* Clear bit in ENDPTSETUPSTAT */ - writel((1 << ep_num), &udc->op_regs->epsetupstat); - - /* while a hazard exists when setup package arrives */ - do { - /* Set Setup Tripwire */ - temp = readl(&udc->op_regs->usbcmd); - writel(temp | USBCMD_SETUP_TRIPWIRE_SET, &udc->op_regs->usbcmd); - - /* Copy the setup packet to local buffer */ - memcpy(buffer_ptr, (u8 *) dqh->setup_buffer, 8); - } while (!(readl(&udc->op_regs->usbcmd) & USBCMD_SETUP_TRIPWIRE_SET)); - - /* Clear Setup Tripwire */ - temp = readl(&udc->op_regs->usbcmd); - writel(temp & ~USBCMD_SETUP_TRIPWIRE_SET, &udc->op_regs->usbcmd); -} - -static void irq_process_tr_complete(struct mv_udc *udc) -{ - u32 tmp, bit_pos; - int i, ep_num = 0, direction = 0; - struct mv_ep *curr_ep; - struct mv_req *curr_req, *temp_req; - int status; - - /* - * We use separate loops for ENDPTSETUPSTAT and ENDPTCOMPLETE - * because the setup packets are to be read ASAP - */ - - /* Process all Setup packet received interrupts */ - tmp = readl(&udc->op_regs->epsetupstat); - - if (tmp) { - for (i = 0; i < udc->max_eps; i++) { - if (tmp & (1 << i)) { - get_setup_data(udc, i, - (u8 *)(&udc->local_setup_buff)); - handle_setup_packet(udc, i, - &udc->local_setup_buff); - } - } - } - - /* Don't clear the endpoint setup status register here. - * It is cleared as a setup packet is read out of the buffer - */ - - /* Process non-setup transaction complete interrupts */ - tmp = readl(&udc->op_regs->epcomplete); - - if (!tmp) - return; - - writel(tmp, &udc->op_regs->epcomplete); - - for (i = 0; i < udc->max_eps * 2; i++) { - ep_num = i >> 1; - direction = i % 2; - - bit_pos = 1 << (ep_num + 16 * direction); - - if (!(bit_pos & tmp)) - continue; - - if (i == 1) - curr_ep = &udc->eps[0]; - else - curr_ep = &udc->eps[i]; - /* process the req queue until an uncomplete request */ - list_for_each_entry_safe(curr_req, temp_req, - &curr_ep->queue, queue) { - status = process_ep_req(udc, i, curr_req); - if (status) - break; - - /* write back status to req */ - curr_req->req.status = status; - - /* ep0 request completion */ - if (ep_num == 0) { - ep0_req_complete(udc, curr_ep, curr_req); - break; - } else { - done(curr_ep, curr_req, status); - } - } - } -} - -void irq_process_reset(struct mv_udc *udc) -{ - u32 tmp; - unsigned int loops; - - udc->ep0_dir = EP_DIR_OUT; - udc->ep0_state = WAIT_FOR_SETUP; - udc->remote_wakeup = 0; /* default to 0 on reset */ - - /* The address bits are past bit 25-31. Set the address */ - tmp = readl(&udc->op_regs->deviceaddr); - tmp &= ~(USB_DEVICE_ADDRESS_MASK); - writel(tmp, &udc->op_regs->deviceaddr); - - /* Clear all the setup token semaphores */ - tmp = readl(&udc->op_regs->epsetupstat); - writel(tmp, &udc->op_regs->epsetupstat); - - /* Clear all the endpoint complete status bits */ - tmp = readl(&udc->op_regs->epcomplete); - writel(tmp, &udc->op_regs->epcomplete); - - /* wait until all endptprime bits cleared */ - loops = LOOPS(PRIME_TIMEOUT); - while (readl(&udc->op_regs->epprime) & 0xFFFFFFFF) { - if (loops == 0) { - dev_err(&udc->dev->dev, - "Timeout for ENDPTPRIME = 0x%x\n", - readl(&udc->op_regs->epprime)); - break; - } - loops--; - udelay(LOOPS_USEC); - } - - /* Write 1s to the Flush register */ - writel((u32)~0, &udc->op_regs->epflush); - - if (readl(&udc->op_regs->portsc[0]) & PORTSCX_PORT_RESET) { - dev_info(&udc->dev->dev, "usb bus reset\n"); - udc->usb_state = USB_STATE_DEFAULT; - /* reset all the queues, stop all USB activities */ - stop_activity(udc, udc->driver); - } else { - dev_info(&udc->dev->dev, "USB reset portsc 0x%x\n", - readl(&udc->op_regs->portsc)); - - /* - * re-initialize - * controller reset - */ - udc_reset(udc); - - /* reset all the queues, stop all USB activities */ - stop_activity(udc, udc->driver); - - /* reset ep0 dQH and endptctrl */ - ep0_reset(udc); - - /* enable interrupt and set controller to run state */ - udc_start(udc); - - udc->usb_state = USB_STATE_ATTACHED; - } -} - -static void handle_bus_resume(struct mv_udc *udc) -{ - udc->usb_state = udc->resume_state; - udc->resume_state = 0; - - /* report resume to the driver */ - if (udc->driver) { - if (udc->driver->resume) { - spin_unlock(&udc->lock); - udc->driver->resume(&udc->gadget); - spin_lock(&udc->lock); - } - } -} - -static void irq_process_suspend(struct mv_udc *udc) -{ - udc->resume_state = udc->usb_state; - udc->usb_state = USB_STATE_SUSPENDED; - - if (udc->driver->suspend) { - spin_unlock(&udc->lock); - udc->driver->suspend(&udc->gadget); - spin_lock(&udc->lock); - } -} - -static void irq_process_port_change(struct mv_udc *udc) -{ - u32 portsc; - - portsc = readl(&udc->op_regs->portsc[0]); - if (!(portsc & PORTSCX_PORT_RESET)) { - /* Get the speed */ - u32 speed = portsc & PORTSCX_PORT_SPEED_MASK; - switch (speed) { - case PORTSCX_PORT_SPEED_HIGH: - udc->gadget.speed = USB_SPEED_HIGH; - break; - case PORTSCX_PORT_SPEED_FULL: - udc->gadget.speed = USB_SPEED_FULL; - break; - case PORTSCX_PORT_SPEED_LOW: - udc->gadget.speed = USB_SPEED_LOW; - break; - default: - udc->gadget.speed = USB_SPEED_UNKNOWN; - break; - } - } - - if (portsc & PORTSCX_PORT_SUSPEND) { - udc->resume_state = udc->usb_state; - udc->usb_state = USB_STATE_SUSPENDED; - if (udc->driver->suspend) { - spin_unlock(&udc->lock); - udc->driver->suspend(&udc->gadget); - spin_lock(&udc->lock); - } - } - - if (!(portsc & PORTSCX_PORT_SUSPEND) - && udc->usb_state == USB_STATE_SUSPENDED) { - handle_bus_resume(udc); - } - - if (!udc->resume_state) - udc->usb_state = USB_STATE_DEFAULT; -} - -static void irq_process_error(struct mv_udc *udc) -{ - /* Increment the error count */ - udc->errors++; -} - -static irqreturn_t mv_udc_irq(int irq, void *dev) -{ - struct mv_udc *udc = (struct mv_udc *)dev; - u32 status, intr; - - /* Disable ISR when stopped bit is set */ - if (udc->stopped) - return IRQ_NONE; - - spin_lock(&udc->lock); - - status = readl(&udc->op_regs->usbsts); - intr = readl(&udc->op_regs->usbintr); - status &= intr; - - if (status == 0) { - spin_unlock(&udc->lock); - return IRQ_NONE; - } - - /* Clear all the interrupts occurred */ - writel(status, &udc->op_regs->usbsts); - - if (status & USBSTS_ERR) - irq_process_error(udc); - - if (status & USBSTS_RESET) - irq_process_reset(udc); - - if (status & USBSTS_PORT_CHANGE) - irq_process_port_change(udc); - - if (status & USBSTS_INT) - irq_process_tr_complete(udc); - - if (status & USBSTS_SUSPEND) - irq_process_suspend(udc); - - spin_unlock(&udc->lock); - - return IRQ_HANDLED; -} - -static irqreturn_t mv_udc_vbus_irq(int irq, void *dev) -{ - struct mv_udc *udc = (struct mv_udc *)dev; - - /* polling VBUS and init phy may cause too much time*/ - if (udc->qwork) - queue_work(udc->qwork, &udc->vbus_work); - - return IRQ_HANDLED; -} - -static void mv_udc_vbus_work(struct work_struct *work) -{ - struct mv_udc *udc; - unsigned int vbus; - - udc = container_of(work, struct mv_udc, vbus_work); - if (!udc->pdata->vbus) - return; - - vbus = udc->pdata->vbus->poll(); - dev_info(&udc->dev->dev, "vbus is %d\n", vbus); - - if (vbus == VBUS_HIGH) - mv_udc_vbus_session(&udc->gadget, 1); - else if (vbus == VBUS_LOW) - mv_udc_vbus_session(&udc->gadget, 0); -} - -/* release device structure */ -static void gadget_release(struct device *_dev) -{ - struct mv_udc *udc = the_controller; - - complete(udc->done); -} - -static int __devexit mv_udc_remove(struct platform_device *dev) -{ - struct mv_udc *udc = the_controller; - int clk_i; - - usb_del_gadget_udc(&udc->gadget); - - if (udc->qwork) { - flush_workqueue(udc->qwork); - destroy_workqueue(udc->qwork); - } - - /* - * If we have transceiver inited, - * then vbus irq will not be requested in udc driver. - */ - if (udc->pdata && udc->pdata->vbus - && udc->clock_gating && udc->transceiver == NULL) - free_irq(udc->pdata->vbus->irq, &dev->dev); - - /* free memory allocated in probe */ - if (udc->dtd_pool) - dma_pool_destroy(udc->dtd_pool); - - if (udc->ep_dqh) - dma_free_coherent(&dev->dev, udc->ep_dqh_size, - udc->ep_dqh, udc->ep_dqh_dma); - - kfree(udc->eps); - - if (udc->irq) - free_irq(udc->irq, &dev->dev); - - mv_udc_disable(udc); - - if (udc->cap_regs) - iounmap(udc->cap_regs); - - if (udc->phy_regs) - iounmap(udc->phy_regs); - - if (udc->status_req) { - kfree(udc->status_req->req.buf); - kfree(udc->status_req); - } - - for (clk_i = 0; clk_i <= udc->clknum; clk_i++) - clk_put(udc->clk[clk_i]); - - device_unregister(&udc->gadget.dev); - - /* free dev, wait for the release() finished */ - wait_for_completion(udc->done); - kfree(udc); - - the_controller = NULL; - - return 0; -} - -static int __devinit mv_udc_probe(struct platform_device *dev) -{ - struct mv_usb_platform_data *pdata = dev->dev.platform_data; - struct mv_udc *udc; - int retval = 0; - int clk_i = 0; - struct resource *r; - size_t size; - - if (pdata == NULL) { - dev_err(&dev->dev, "missing platform_data\n"); - return -ENODEV; - } - - size = sizeof(*udc) + sizeof(struct clk *) * pdata->clknum; - udc = kzalloc(size, GFP_KERNEL); - if (udc == NULL) { - dev_err(&dev->dev, "failed to allocate memory for udc\n"); - return -ENOMEM; - } - - the_controller = udc; - udc->done = &release_done; - udc->pdata = dev->dev.platform_data; - spin_lock_init(&udc->lock); - - udc->dev = dev; - -#ifdef CONFIG_USB_OTG_UTILS - if (pdata->mode == MV_USB_MODE_OTG) - udc->transceiver = usb_get_transceiver(); -#endif - - udc->clknum = pdata->clknum; - for (clk_i = 0; clk_i < udc->clknum; clk_i++) { - udc->clk[clk_i] = clk_get(&dev->dev, pdata->clkname[clk_i]); - if (IS_ERR(udc->clk[clk_i])) { - retval = PTR_ERR(udc->clk[clk_i]); - goto err_put_clk; - } - } - - r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "capregs"); - if (r == NULL) { - dev_err(&dev->dev, "no I/O memory resource defined\n"); - retval = -ENODEV; - goto err_put_clk; - } - - udc->cap_regs = (struct mv_cap_regs __iomem *) - ioremap(r->start, resource_size(r)); - if (udc->cap_regs == NULL) { - dev_err(&dev->dev, "failed to map I/O memory\n"); - retval = -EBUSY; - goto err_put_clk; - } - - r = platform_get_resource_byname(udc->dev, IORESOURCE_MEM, "phyregs"); - if (r == NULL) { - dev_err(&dev->dev, "no phy I/O memory resource defined\n"); - retval = -ENODEV; - goto err_iounmap_capreg; - } - - udc->phy_regs = ioremap(r->start, resource_size(r)); - if (udc->phy_regs == NULL) { - dev_err(&dev->dev, "failed to map phy I/O memory\n"); - retval = -EBUSY; - goto err_iounmap_capreg; - } - - /* we will acces controller register, so enable the clk */ - retval = mv_udc_enable_internal(udc); - if (retval) - goto err_iounmap_phyreg; - - udc->op_regs = - (struct mv_op_regs __iomem *)((unsigned long)udc->cap_regs - + (readl(&udc->cap_regs->caplength_hciversion) - & CAPLENGTH_MASK)); - udc->max_eps = readl(&udc->cap_regs->dccparams) & DCCPARAMS_DEN_MASK; - - /* - * some platform will use usb to download image, it may not disconnect - * usb gadget before loading kernel. So first stop udc here. - */ - udc_stop(udc); - writel(0xFFFFFFFF, &udc->op_regs->usbsts); - - size = udc->max_eps * sizeof(struct mv_dqh) *2; - size = (size + DQH_ALIGNMENT - 1) & ~(DQH_ALIGNMENT - 1); - udc->ep_dqh = dma_alloc_coherent(&dev->dev, size, - &udc->ep_dqh_dma, GFP_KERNEL); - - if (udc->ep_dqh == NULL) { - dev_err(&dev->dev, "allocate dQH memory failed\n"); - retval = -ENOMEM; - goto err_disable_clock; - } - udc->ep_dqh_size = size; - - /* create dTD dma_pool resource */ - udc->dtd_pool = dma_pool_create("mv_dtd", - &dev->dev, - sizeof(struct mv_dtd), - DTD_ALIGNMENT, - DMA_BOUNDARY); - - if (!udc->dtd_pool) { - retval = -ENOMEM; - goto err_free_dma; - } - - size = udc->max_eps * sizeof(struct mv_ep) *2; - udc->eps = kzalloc(size, GFP_KERNEL); - if (udc->eps == NULL) { - dev_err(&dev->dev, "allocate ep memory failed\n"); - retval = -ENOMEM; - goto err_destroy_dma; - } - - /* initialize ep0 status request structure */ - udc->status_req = kzalloc(sizeof(struct mv_req), GFP_KERNEL); - if (!udc->status_req) { - dev_err(&dev->dev, "allocate status_req memory failed\n"); - retval = -ENOMEM; - goto err_free_eps; - } - INIT_LIST_HEAD(&udc->status_req->queue); - - /* allocate a small amount of memory to get valid address */ - udc->status_req->req.buf = kzalloc(8, GFP_KERNEL); - udc->status_req->req.dma = DMA_ADDR_INVALID; - - udc->resume_state = USB_STATE_NOTATTACHED; - udc->usb_state = USB_STATE_POWERED; - udc->ep0_dir = EP_DIR_OUT; - udc->remote_wakeup = 0; - - r = platform_get_resource(udc->dev, IORESOURCE_IRQ, 0); - if (r == NULL) { - dev_err(&dev->dev, "no IRQ resource defined\n"); - retval = -ENODEV; - goto err_free_status_req; - } - udc->irq = r->start; - if (request_irq(udc->irq, mv_udc_irq, - IRQF_SHARED, driver_name, udc)) { - dev_err(&dev->dev, "Request irq %d for UDC failed\n", - udc->irq); - retval = -ENODEV; - goto err_free_status_req; - } - - /* initialize gadget structure */ - udc->gadget.ops = &mv_ops; /* usb_gadget_ops */ - udc->gadget.ep0 = &udc->eps[0].ep; /* gadget ep0 */ - INIT_LIST_HEAD(&udc->gadget.ep_list); /* ep_list */ - udc->gadget.speed = USB_SPEED_UNKNOWN; /* speed */ - udc->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */ - - /* the "gadget" abstracts/virtualizes the controller */ - dev_set_name(&udc->gadget.dev, "gadget"); - udc->gadget.dev.parent = &dev->dev; - udc->gadget.dev.dma_mask = dev->dev.dma_mask; - udc->gadget.dev.release = gadget_release; - udc->gadget.name = driver_name; /* gadget name */ - - retval = device_register(&udc->gadget.dev); - if (retval) - goto err_free_irq; - - eps_init(udc); - - /* VBUS detect: we can disable/enable clock on demand.*/ - if (udc->transceiver) - udc->clock_gating = 1; - else if (pdata->vbus) { - udc->clock_gating = 1; - retval = request_threaded_irq(pdata->vbus->irq, NULL, - mv_udc_vbus_irq, IRQF_ONESHOT, "vbus", udc); - if (retval) { - dev_info(&dev->dev, - "Can not request irq for VBUS, " - "disable clock gating\n"); - udc->clock_gating = 0; - } - - udc->qwork = create_singlethread_workqueue("mv_udc_queue"); - if (!udc->qwork) { - dev_err(&dev->dev, "cannot create workqueue\n"); - retval = -ENOMEM; - goto err_unregister; - } - - INIT_WORK(&udc->vbus_work, mv_udc_vbus_work); - } - - /* - * When clock gating is supported, we can disable clk and phy. - * If not, it means that VBUS detection is not supported, we - * have to enable vbus active all the time to let controller work. - */ - if (udc->clock_gating) - mv_udc_disable_internal(udc); - else - udc->vbus_active = 1; - - retval = usb_add_gadget_udc(&dev->dev, &udc->gadget); - if (retval) - goto err_unregister; - - dev_info(&dev->dev, "successful probe UDC device %s clock gating.\n", - udc->clock_gating ? "with" : "without"); - - return 0; - -err_unregister: - if (udc->pdata && udc->pdata->vbus - && udc->clock_gating && udc->transceiver == NULL) - free_irq(pdata->vbus->irq, &dev->dev); - device_unregister(&udc->gadget.dev); -err_free_irq: - free_irq(udc->irq, &dev->dev); -err_free_status_req: - kfree(udc->status_req->req.buf); - kfree(udc->status_req); -err_free_eps: - kfree(udc->eps); -err_destroy_dma: - dma_pool_destroy(udc->dtd_pool); -err_free_dma: - dma_free_coherent(&dev->dev, udc->ep_dqh_size, - udc->ep_dqh, udc->ep_dqh_dma); -err_disable_clock: - mv_udc_disable_internal(udc); -err_iounmap_phyreg: - iounmap(udc->phy_regs); -err_iounmap_capreg: - iounmap(udc->cap_regs); -err_put_clk: - for (clk_i--; clk_i >= 0; clk_i--) - clk_put(udc->clk[clk_i]); - the_controller = NULL; - kfree(udc); - return retval; -} - -#ifdef CONFIG_PM -static int mv_udc_suspend(struct device *_dev) -{ - struct mv_udc *udc = the_controller; - - /* if OTG is enabled, the following will be done in OTG driver*/ - if (udc->transceiver) - return 0; - - if (udc->pdata->vbus && udc->pdata->vbus->poll) - if (udc->pdata->vbus->poll() == VBUS_HIGH) { - dev_info(&udc->dev->dev, "USB cable is connected!\n"); - return -EAGAIN; - } - - /* - * only cable is unplugged, udc can suspend. - * So do not care about clock_gating == 1. - */ - if (!udc->clock_gating) { - udc_stop(udc); - - spin_lock_irq(&udc->lock); - /* stop all usb activities */ - stop_activity(udc, udc->driver); - spin_unlock_irq(&udc->lock); - - mv_udc_disable_internal(udc); - } - - return 0; -} - -static int mv_udc_resume(struct device *_dev) -{ - struct mv_udc *udc = the_controller; - int retval; - - /* if OTG is enabled, the following will be done in OTG driver*/ - if (udc->transceiver) - return 0; - - if (!udc->clock_gating) { - retval = mv_udc_enable_internal(udc); - if (retval) - return retval; - - if (udc->driver && udc->softconnect) { - udc_reset(udc); - ep0_reset(udc); - udc_start(udc); - } - } - - return 0; -} - -static const struct dev_pm_ops mv_udc_pm_ops = { - .suspend = mv_udc_suspend, - .resume = mv_udc_resume, -}; -#endif - -static void mv_udc_shutdown(struct platform_device *dev) -{ - struct mv_udc *udc = the_controller; - u32 mode; - - /* reset controller mode to IDLE */ - mode = readl(&udc->op_regs->usbmode); - mode &= ~3; - writel(mode, &udc->op_regs->usbmode); -} - -static struct platform_driver udc_driver = { - .probe = mv_udc_probe, - .remove = __exit_p(mv_udc_remove), - .shutdown = mv_udc_shutdown, - .driver = { - .owner = THIS_MODULE, - .name = "mv-udc", -#ifdef CONFIG_PM - .pm = &mv_udc_pm_ops, -#endif - }, -}; - -module_platform_driver(udc_driver); -MODULE_ALIAS("platform:mv-udc"); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Chao Xie "); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/ncm.c b/ANDROID_3.4.5/drivers/usb/gadget/ncm.c deleted file mode 100644 index 89530034..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/ncm.c +++ /dev/null @@ -1,240 +0,0 @@ -/* - * ncm.c -- NCM gadget driver - * - * Copyright (C) 2010 Nokia Corporation - * Contact: Yauheni Kaliuta - * - * The driver borrows from ether.c which is: - * - * Copyright (C) 2003-2005,2008 David Brownell - * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -/* #define DEBUG */ -/* #define VERBOSE_DEBUG */ - -#include -#include - - -#include "u_ether.h" - -#define DRIVER_DESC "NCM Gadget" - -/*-------------------------------------------------------------------------*/ - -/* - * 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 "f_ncm.c" -#include "u_ether.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. - * It's for devices with only CDC Ethernet configurations. - */ -#define CDC_VENDOR_NUM 0x0525 /* NetChip */ -#define CDC_PRODUCT_NUM 0xa4a1 /* Linux-USB Ethernet Gadget */ - -/*-------------------------------------------------------------------------*/ - -static struct usb_device_descriptor device_desc = { - .bLength = sizeof device_desc, - .bDescriptorType = USB_DT_DEVICE, - - .bcdUSB = cpu_to_le16 (0x0200), - - .bDeviceClass = USB_CLASS_COMM, - .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 = cpu_to_le16 (CDC_VENDOR_NUM), - .idProduct = cpu_to_le16 (CDC_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, -}; - - -/* 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 *dev_strings[] = { - &stringtab_dev, - NULL, -}; - -static u8 hostaddr[ETH_ALEN]; - -/*-------------------------------------------------------------------------*/ - -static int __init ncm_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; - } - - return ncm_bind_config(c, hostaddr); -} - -static struct usb_configuration ncm_config_driver = { - /* .label = f(hardware) */ - .label = "CDC Ethernet (NCM)", - .bConfigurationValue = 1, - /* .iConfiguration = DYNAMIC */ - .bmAttributes = USB_CONFIG_ATT_SELFPOWER, -}; - -/*-------------------------------------------------------------------------*/ - -static int __init gncm_bind(struct usb_composite_dev *cdev) -{ - int gcnum; - struct usb_gadget *gadget = cdev->gadget; - int status; - - /* set up network link layer */ - status = gether_setup(cdev->gadget, hostaddr); - if (status < 0) - return status; - - gcnum = usb_gadget_controller_number(gadget); - if (gcnum >= 0) - device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum); - else { - /* We assume that can_support_ecm() tells the truth; - * but if the controller isn't recognized at all then - * that assumption is a bit more likely to be wrong. - */ - dev_warn(&gadget->dev, - "controller '%s' not recognized; trying %s\n", - gadget->name, - ncm_config_driver.label); - device_desc.bcdDevice = - cpu_to_le16(0x0300 | 0x0099); - } - - - /* Allocate string descriptor numbers ... note that string - * contents can be overridden by the composite_dev glue. - */ - - /* device descriptor strings: manufacturer, product */ - snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", - init_utsname()->sysname, init_utsname()->release, - 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, &ncm_config_driver, - ncm_do_config); - if (status < 0) - goto fail; - - dev_info(&gadget->dev, "%s\n", DRIVER_DESC); - - return 0; - -fail: - gether_cleanup(); - return status; -} - -static int __exit gncm_unbind(struct usb_composite_dev *cdev) -{ - gether_cleanup(); - return 0; -} - -static struct usb_composite_driver ncm_driver = { - .name = "g_ncm", - .dev = &device_desc, - .strings = dev_strings, - .max_speed = USB_SPEED_HIGH, - .unbind = __exit_p(gncm_unbind), -}; - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Yauheni Kaliuta"); -MODULE_LICENSE("GPL"); - -static int __init init(void) -{ - return usb_composite_probe(&ncm_driver, gncm_bind); -} -module_init(init); - -static void __exit cleanup(void) -{ - usb_composite_unregister(&ncm_driver); -} -module_exit(cleanup); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/ndis.h b/ANDROID_3.4.5/drivers/usb/gadget/ndis.h deleted file mode 100644 index b0e52fc2..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/ndis.h +++ /dev/null @@ -1,211 +0,0 @@ -/* - * ndis.h - * - * ntddndis.h modified by Benedikt Spranger - * - * Thanks to the cygwin development team, - * espacially to Casper S. Hornstrup - * - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. - */ - -#ifndef _LINUX_NDIS_H -#define _LINUX_NDIS_H - - -#define NDIS_STATUS_MULTICAST_FULL 0xC0010009 -#define NDIS_STATUS_MULTICAST_EXISTS 0xC001000A -#define NDIS_STATUS_MULTICAST_NOT_FOUND 0xC001000B - -enum NDIS_DEVICE_POWER_STATE { - NdisDeviceStateUnspecified = 0, - NdisDeviceStateD0, - NdisDeviceStateD1, - NdisDeviceStateD2, - NdisDeviceStateD3, - NdisDeviceStateMaximum -}; - -struct NDIS_PM_WAKE_UP_CAPABILITIES { - enum NDIS_DEVICE_POWER_STATE MinMagicPacketWakeUp; - enum NDIS_DEVICE_POWER_STATE MinPatternWakeUp; - enum NDIS_DEVICE_POWER_STATE MinLinkChangeWakeUp; -}; - -/* NDIS_PNP_CAPABILITIES.Flags constants */ -#define NDIS_DEVICE_WAKE_UP_ENABLE 0x00000001 -#define NDIS_DEVICE_WAKE_ON_PATTERN_MATCH_ENABLE 0x00000002 -#define NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE 0x00000004 - -struct NDIS_PNP_CAPABILITIES { - __le32 Flags; - struct NDIS_PM_WAKE_UP_CAPABILITIES WakeUpCapabilities; -}; - -struct NDIS_PM_PACKET_PATTERN { - __le32 Priority; - __le32 Reserved; - __le32 MaskSize; - __le32 PatternOffset; - __le32 PatternSize; - __le32 PatternFlags; -}; - - -/* Required Object IDs (OIDs) */ -#define OID_GEN_SUPPORTED_LIST 0x00010101 -#define OID_GEN_HARDWARE_STATUS 0x00010102 -#define OID_GEN_MEDIA_SUPPORTED 0x00010103 -#define OID_GEN_MEDIA_IN_USE 0x00010104 -#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105 -#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106 -#define OID_GEN_LINK_SPEED 0x00010107 -#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108 -#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109 -#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A -#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B -#define OID_GEN_VENDOR_ID 0x0001010C -#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D -#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E -#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F -#define OID_GEN_DRIVER_VERSION 0x00010110 -#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111 -#define OID_GEN_PROTOCOL_OPTIONS 0x00010112 -#define OID_GEN_MAC_OPTIONS 0x00010113 -#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114 -#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115 -#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116 -#define OID_GEN_SUPPORTED_GUIDS 0x00010117 -#define OID_GEN_NETWORK_LAYER_ADDRESSES 0x00010118 -#define OID_GEN_TRANSPORT_HEADER_OFFSET 0x00010119 -#define OID_GEN_MACHINE_NAME 0x0001021A -#define OID_GEN_RNDIS_CONFIG_PARAMETER 0x0001021B -#define OID_GEN_VLAN_ID 0x0001021C - -/* Optional OIDs */ -#define OID_GEN_MEDIA_CAPABILITIES 0x00010201 -#define OID_GEN_PHYSICAL_MEDIUM 0x00010202 - -/* Required statistics OIDs */ -#define OID_GEN_XMIT_OK 0x00020101 -#define OID_GEN_RCV_OK 0x00020102 -#define OID_GEN_XMIT_ERROR 0x00020103 -#define OID_GEN_RCV_ERROR 0x00020104 -#define OID_GEN_RCV_NO_BUFFER 0x00020105 - -/* Optional statistics OIDs */ -#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201 -#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202 -#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203 -#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204 -#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205 -#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206 -#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207 -#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208 -#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209 -#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A -#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B -#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C -#define OID_GEN_RCV_CRC_ERROR 0x0002020D -#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E -#define OID_GEN_GET_TIME_CAPS 0x0002020F -#define OID_GEN_GET_NETCARD_TIME 0x00020210 -#define OID_GEN_NETCARD_LOAD 0x00020211 -#define OID_GEN_DEVICE_PROFILE 0x00020212 -#define OID_GEN_INIT_TIME_MS 0x00020213 -#define OID_GEN_RESET_COUNTS 0x00020214 -#define OID_GEN_MEDIA_SENSE_COUNTS 0x00020215 -#define OID_GEN_FRIENDLY_NAME 0x00020216 -#define OID_GEN_MINIPORT_INFO 0x00020217 -#define OID_GEN_RESET_VERIFY_PARAMETERS 0x00020218 - -/* IEEE 802.3 (Ethernet) OIDs */ -#define NDIS_802_3_MAC_OPTION_PRIORITY 0x00000001 - -#define OID_802_3_PERMANENT_ADDRESS 0x01010101 -#define OID_802_3_CURRENT_ADDRESS 0x01010102 -#define OID_802_3_MULTICAST_LIST 0x01010103 -#define OID_802_3_MAXIMUM_LIST_SIZE 0x01010104 -#define OID_802_3_MAC_OPTIONS 0x01010105 -#define OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101 -#define OID_802_3_XMIT_ONE_COLLISION 0x01020102 -#define OID_802_3_XMIT_MORE_COLLISIONS 0x01020103 -#define OID_802_3_XMIT_DEFERRED 0x01020201 -#define OID_802_3_XMIT_MAX_COLLISIONS 0x01020202 -#define OID_802_3_RCV_OVERRUN 0x01020203 -#define OID_802_3_XMIT_UNDERRUN 0x01020204 -#define OID_802_3_XMIT_HEARTBEAT_FAILURE 0x01020205 -#define OID_802_3_XMIT_TIMES_CRS_LOST 0x01020206 -#define OID_802_3_XMIT_LATE_COLLISIONS 0x01020207 - -/* OID_GEN_MINIPORT_INFO constants */ -#define NDIS_MINIPORT_BUS_MASTER 0x00000001 -#define NDIS_MINIPORT_WDM_DRIVER 0x00000002 -#define NDIS_MINIPORT_SG_LIST 0x00000004 -#define NDIS_MINIPORT_SUPPORTS_MEDIA_QUERY 0x00000008 -#define NDIS_MINIPORT_INDICATES_PACKETS 0x00000010 -#define NDIS_MINIPORT_IGNORE_PACKET_QUEUE 0x00000020 -#define NDIS_MINIPORT_IGNORE_REQUEST_QUEUE 0x00000040 -#define NDIS_MINIPORT_IGNORE_TOKEN_RING_ERRORS 0x00000080 -#define NDIS_MINIPORT_INTERMEDIATE_DRIVER 0x00000100 -#define NDIS_MINIPORT_IS_NDIS_5 0x00000200 -#define NDIS_MINIPORT_IS_CO 0x00000400 -#define NDIS_MINIPORT_DESERIALIZE 0x00000800 -#define NDIS_MINIPORT_REQUIRES_MEDIA_POLLING 0x00001000 -#define NDIS_MINIPORT_SUPPORTS_MEDIA_SENSE 0x00002000 -#define NDIS_MINIPORT_NETBOOT_CARD 0x00004000 -#define NDIS_MINIPORT_PM_SUPPORTED 0x00008000 -#define NDIS_MINIPORT_SUPPORTS_MAC_ADDRESS_OVERWRITE 0x00010000 -#define NDIS_MINIPORT_USES_SAFE_BUFFER_APIS 0x00020000 -#define NDIS_MINIPORT_HIDDEN 0x00040000 -#define NDIS_MINIPORT_SWENUM 0x00080000 -#define NDIS_MINIPORT_SURPRISE_REMOVE_OK 0x00100000 -#define NDIS_MINIPORT_NO_HALT_ON_SUSPEND 0x00200000 -#define NDIS_MINIPORT_HARDWARE_DEVICE 0x00400000 -#define NDIS_MINIPORT_SUPPORTS_CANCEL_SEND_PACKETS 0x00800000 -#define NDIS_MINIPORT_64BITS_DMA 0x01000000 - -#define NDIS_MEDIUM_802_3 0x00000000 -#define NDIS_MEDIUM_802_5 0x00000001 -#define NDIS_MEDIUM_FDDI 0x00000002 -#define NDIS_MEDIUM_WAN 0x00000003 -#define NDIS_MEDIUM_LOCAL_TALK 0x00000004 -#define NDIS_MEDIUM_DIX 0x00000005 -#define NDIS_MEDIUM_ARCENT_RAW 0x00000006 -#define NDIS_MEDIUM_ARCENT_878_2 0x00000007 -#define NDIS_MEDIUM_ATM 0x00000008 -#define NDIS_MEDIUM_WIRELESS_LAN 0x00000009 -#define NDIS_MEDIUM_IRDA 0x0000000A -#define NDIS_MEDIUM_BPC 0x0000000B -#define NDIS_MEDIUM_CO_WAN 0x0000000C -#define NDIS_MEDIUM_1394 0x0000000D - -#define NDIS_PACKET_TYPE_DIRECTED 0x00000001 -#define NDIS_PACKET_TYPE_MULTICAST 0x00000002 -#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004 -#define NDIS_PACKET_TYPE_BROADCAST 0x00000008 -#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010 -#define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020 -#define NDIS_PACKET_TYPE_SMT 0x00000040 -#define NDIS_PACKET_TYPE_ALL_LOCAL 0x00000080 -#define NDIS_PACKET_TYPE_GROUP 0x00000100 -#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x00000200 -#define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400 -#define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800 - -#define NDIS_MEDIA_STATE_CONNECTED 0x00000000 -#define NDIS_MEDIA_STATE_DISCONNECTED 0x00000001 - -#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA 0x00000001 -#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED 0x00000002 -#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND 0x00000004 -#define NDIS_MAC_OPTION_NO_LOOPBACK 0x00000008 -#define NDIS_MAC_OPTION_FULL_DUPLEX 0x00000010 -#define NDIS_MAC_OPTION_EOTX_INDICATION 0x00000020 -#define NDIS_MAC_OPTION_8021P_PRIORITY 0x00000040 -#define NDIS_MAC_OPTION_RESERVED 0x80000000 - -#endif /* _LINUX_NDIS_H */ diff --git a/ANDROID_3.4.5/drivers/usb/gadget/net2272.c b/ANDROID_3.4.5/drivers/usb/gadget/net2272.c deleted file mode 100644 index 43ac7482..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/net2272.c +++ /dev/null @@ -1,2715 +0,0 @@ -/* - * Driver for PLX NET2272 USB device controller - * - * Copyright (C) 2005-2006 PLX Technology, Inc. - * Copyright (C) 2006-2011 Analog Devices, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "net2272.h" - -#define DRIVER_DESC "PLX NET2272 USB Peripheral Controller" - -static const char driver_name[] = "net2272"; -static const char driver_vers[] = "2006 October 17/mainline"; -static const char driver_desc[] = DRIVER_DESC; - -static const char ep0name[] = "ep0"; -static const char * const ep_name[] = { - ep0name, - "ep-a", "ep-b", "ep-c", -}; - -#define DMA_ADDR_INVALID (~(dma_addr_t)0) -#ifdef CONFIG_USB_GADGET_NET2272_DMA -/* - * use_dma: the NET2272 can use an external DMA controller. - * Note that since there is no generic DMA api, some functions, - * notably request_dma, start_dma, and cancel_dma will need to be - * modified for your platform's particular dma controller. - * - * If use_dma is disabled, pio will be used instead. - */ -static bool use_dma = 0; -module_param(use_dma, bool, 0644); - -/* - * dma_ep: selects the endpoint for use with dma (1=ep-a, 2=ep-b) - * The NET2272 can only use dma for a single endpoint at a time. - * At some point this could be modified to allow either endpoint - * to take control of dma as it becomes available. - * - * Note that DMA should not be used on OUT endpoints unless it can - * be guaranteed that no short packets will arrive on an IN endpoint - * while the DMA operation is pending. Otherwise the OUT DMA will - * terminate prematurely (See NET2272 Errata 630-0213-0101) - */ -static ushort dma_ep = 1; -module_param(dma_ep, ushort, 0644); - -/* - * dma_mode: net2272 dma mode setting (see LOCCTL1 definiton): - * mode 0 == Slow DREQ mode - * mode 1 == Fast DREQ mode - * mode 2 == Burst mode - */ -static ushort dma_mode = 2; -module_param(dma_mode, ushort, 0644); -#else -#define use_dma 0 -#define dma_ep 1 -#define dma_mode 2 -#endif - -/* - * fifo_mode: net2272 buffer configuration: - * mode 0 == ep-{a,b,c} 512db each - * mode 1 == ep-a 1k, ep-{b,c} 512db - * mode 2 == ep-a 1k, ep-b 1k, ep-c 512db - * mode 3 == ep-a 1k, ep-b disabled, ep-c 512db - */ -static ushort fifo_mode = 0; -module_param(fifo_mode, ushort, 0644); - -/* - * enable_suspend: When enabled, the driver will respond to - * USB suspend requests by powering down the NET2272. Otherwise, - * USB suspend requests will be ignored. This is acceptible for - * self-powered devices. For bus powered devices set this to 1. - */ -static ushort enable_suspend = 0; -module_param(enable_suspend, ushort, 0644); - -static void assert_out_naking(struct net2272_ep *ep, const char *where) -{ - u8 tmp; - -#ifndef DEBUG - return; -#endif - - tmp = net2272_ep_read(ep, EP_STAT0); - if ((tmp & (1 << NAK_OUT_PACKETS)) == 0) { - dev_dbg(ep->dev->dev, "%s %s %02x !NAK\n", - ep->ep.name, where, tmp); - net2272_ep_write(ep, EP_RSPSET, 1 << ALT_NAK_OUT_PACKETS); - } -} -#define ASSERT_OUT_NAKING(ep) assert_out_naking(ep, __func__) - -static void stop_out_naking(struct net2272_ep *ep) -{ - u8 tmp = net2272_ep_read(ep, EP_STAT0); - - if ((tmp & (1 << NAK_OUT_PACKETS)) != 0) - net2272_ep_write(ep, EP_RSPCLR, 1 << ALT_NAK_OUT_PACKETS); -} - -#define PIPEDIR(bAddress) (usb_pipein(bAddress) ? "in" : "out") - -static char *type_string(u8 bmAttributes) -{ - switch ((bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK) { - case USB_ENDPOINT_XFER_BULK: return "bulk"; - case USB_ENDPOINT_XFER_ISOC: return "iso"; - case USB_ENDPOINT_XFER_INT: return "intr"; - default: return "control"; - } -} - -static char *buf_state_string(unsigned state) -{ - switch (state) { - case BUFF_FREE: return "free"; - case BUFF_VALID: return "valid"; - case BUFF_LCL: return "local"; - case BUFF_USB: return "usb"; - default: return "unknown"; - } -} - -static char *dma_mode_string(void) -{ - if (!use_dma) - return "PIO"; - switch (dma_mode) { - case 0: return "SLOW DREQ"; - case 1: return "FAST DREQ"; - case 2: return "BURST"; - default: return "invalid"; - } -} - -static void net2272_dequeue_all(struct net2272_ep *); -static int net2272_kick_dma(struct net2272_ep *, struct net2272_request *); -static int net2272_fifo_status(struct usb_ep *); - -static struct usb_ep_ops net2272_ep_ops; - -/*---------------------------------------------------------------------------*/ - -static int -net2272_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) -{ - struct net2272 *dev; - struct net2272_ep *ep; - u32 max; - u8 tmp; - unsigned long flags; - - ep = container_of(_ep, struct net2272_ep, ep); - if (!_ep || !desc || ep->desc || _ep->name == ep0name - || desc->bDescriptorType != USB_DT_ENDPOINT) - return -EINVAL; - dev = ep->dev; - if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - max = usb_endpoint_maxp(desc) & 0x1fff; - - spin_lock_irqsave(&dev->lock, flags); - _ep->maxpacket = max & 0x7fff; - ep->desc = desc; - - /* net2272_ep_reset() has already been called */ - ep->stopped = 0; - ep->wedged = 0; - - /* set speed-dependent max packet */ - net2272_ep_write(ep, EP_MAXPKT0, max & 0xff); - net2272_ep_write(ep, EP_MAXPKT1, (max & 0xff00) >> 8); - - /* set type, direction, address; reset fifo counters */ - net2272_ep_write(ep, EP_STAT1, 1 << BUFFER_FLUSH); - tmp = usb_endpoint_type(desc); - if (usb_endpoint_xfer_bulk(desc)) { - /* catch some particularly blatant driver bugs */ - if ((dev->gadget.speed == USB_SPEED_HIGH && max != 512) || - (dev->gadget.speed == USB_SPEED_FULL && max > 64)) { - spin_unlock_irqrestore(&dev->lock, flags); - return -ERANGE; - } - } - ep->is_iso = usb_endpoint_xfer_isoc(desc) ? 1 : 0; - tmp <<= ENDPOINT_TYPE; - tmp |= ((desc->bEndpointAddress & 0x0f) << ENDPOINT_NUMBER); - tmp |= usb_endpoint_dir_in(desc) << ENDPOINT_DIRECTION; - tmp |= (1 << ENDPOINT_ENABLE); - - /* for OUT transfers, block the rx fifo until a read is posted */ - ep->is_in = usb_endpoint_dir_in(desc); - if (!ep->is_in) - net2272_ep_write(ep, EP_RSPSET, 1 << ALT_NAK_OUT_PACKETS); - - net2272_ep_write(ep, EP_CFG, tmp); - - /* enable irqs */ - tmp = (1 << ep->num) | net2272_read(dev, IRQENB0); - net2272_write(dev, IRQENB0, tmp); - - tmp = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE) - | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE) - | net2272_ep_read(ep, EP_IRQENB); - net2272_ep_write(ep, EP_IRQENB, tmp); - - tmp = desc->bEndpointAddress; - dev_dbg(dev->dev, "enabled %s (ep%d%s-%s) max %04x cfg %02x\n", - _ep->name, tmp & 0x0f, PIPEDIR(tmp), - type_string(desc->bmAttributes), max, - net2272_ep_read(ep, EP_CFG)); - - spin_unlock_irqrestore(&dev->lock, flags); - return 0; -} - -static void net2272_ep_reset(struct net2272_ep *ep) -{ - u8 tmp; - - ep->desc = NULL; - INIT_LIST_HEAD(&ep->queue); - - ep->ep.maxpacket = ~0; - ep->ep.ops = &net2272_ep_ops; - - /* disable irqs, endpoint */ - net2272_ep_write(ep, EP_IRQENB, 0); - - /* init to our chosen defaults, notably so that we NAK OUT - * packets until the driver queues a read. - */ - tmp = (1 << NAK_OUT_PACKETS_MODE) | (1 << ALT_NAK_OUT_PACKETS); - net2272_ep_write(ep, EP_RSPSET, tmp); - - tmp = (1 << INTERRUPT_MODE) | (1 << HIDE_STATUS_PHASE); - if (ep->num != 0) - tmp |= (1 << ENDPOINT_TOGGLE) | (1 << ENDPOINT_HALT); - - net2272_ep_write(ep, EP_RSPCLR, tmp); - - /* scrub most status bits, and flush any fifo state */ - net2272_ep_write(ep, EP_STAT0, - (1 << DATA_IN_TOKEN_INTERRUPT) - | (1 << DATA_OUT_TOKEN_INTERRUPT) - | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT) - | (1 << DATA_PACKET_RECEIVED_INTERRUPT) - | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)); - - net2272_ep_write(ep, EP_STAT1, - (1 << TIMEOUT) - | (1 << USB_OUT_ACK_SENT) - | (1 << USB_OUT_NAK_SENT) - | (1 << USB_IN_ACK_RCVD) - | (1 << USB_IN_NAK_SENT) - | (1 << USB_STALL_SENT) - | (1 << LOCAL_OUT_ZLP) - | (1 << BUFFER_FLUSH)); - - /* fifo size is handled seperately */ -} - -static int net2272_disable(struct usb_ep *_ep) -{ - struct net2272_ep *ep; - unsigned long flags; - - ep = container_of(_ep, struct net2272_ep, ep); - if (!_ep || !ep->desc || _ep->name == ep0name) - return -EINVAL; - - spin_lock_irqsave(&ep->dev->lock, flags); - net2272_dequeue_all(ep); - net2272_ep_reset(ep); - - dev_vdbg(ep->dev->dev, "disabled %s\n", _ep->name); - - spin_unlock_irqrestore(&ep->dev->lock, flags); - return 0; -} - -/*---------------------------------------------------------------------------*/ - -static struct usb_request * -net2272_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) -{ - struct net2272_ep *ep; - struct net2272_request *req; - - if (!_ep) - return NULL; - ep = container_of(_ep, struct net2272_ep, ep); - - req = kzalloc(sizeof(*req), gfp_flags); - if (!req) - return NULL; - - req->req.dma = DMA_ADDR_INVALID; - INIT_LIST_HEAD(&req->queue); - - return &req->req; -} - -static void -net2272_free_request(struct usb_ep *_ep, struct usb_request *_req) -{ - struct net2272_ep *ep; - struct net2272_request *req; - - ep = container_of(_ep, struct net2272_ep, ep); - if (!_ep || !_req) - return; - - req = container_of(_req, struct net2272_request, req); - WARN_ON(!list_empty(&req->queue)); - kfree(req); -} - -static void -net2272_done(struct net2272_ep *ep, struct net2272_request *req, int status) -{ - struct net2272 *dev; - unsigned stopped = ep->stopped; - - if (ep->num == 0) { - if (ep->dev->protocol_stall) { - ep->stopped = 1; - set_halt(ep); - } - allow_status(ep); - } - - list_del_init(&req->queue); - - if (req->req.status == -EINPROGRESS) - req->req.status = status; - else - status = req->req.status; - - dev = ep->dev; - if (use_dma && ep->dma) - usb_gadget_unmap_request(&dev->gadget, &req->req, - ep->is_in); - - if (status && status != -ESHUTDOWN) - dev_vdbg(dev->dev, "complete %s req %p stat %d len %u/%u buf %p\n", - ep->ep.name, &req->req, status, - req->req.actual, req->req.length, req->req.buf); - - /* don't modify queue heads during completion callback */ - ep->stopped = 1; - spin_unlock(&dev->lock); - req->req.complete(&ep->ep, &req->req); - spin_lock(&dev->lock); - ep->stopped = stopped; -} - -static int -net2272_write_packet(struct net2272_ep *ep, u8 *buf, - struct net2272_request *req, unsigned max) -{ - u16 __iomem *ep_data = net2272_reg_addr(ep->dev, EP_DATA); - u16 *bufp; - unsigned length, count; - u8 tmp; - - length = min(req->req.length - req->req.actual, max); - req->req.actual += length; - - dev_vdbg(ep->dev->dev, "write packet %s req %p max %u len %u avail %u\n", - ep->ep.name, req, max, length, - (net2272_ep_read(ep, EP_AVAIL1) << 8) | net2272_ep_read(ep, EP_AVAIL0)); - - count = length; - bufp = (u16 *)buf; - - while (likely(count >= 2)) { - /* no byte-swap required; chip endian set during init */ - writew(*bufp++, ep_data); - count -= 2; - } - buf = (u8 *)bufp; - - /* write final byte by placing the NET2272 into 8-bit mode */ - if (unlikely(count)) { - tmp = net2272_read(ep->dev, LOCCTL); - net2272_write(ep->dev, LOCCTL, tmp & ~(1 << DATA_WIDTH)); - writeb(*buf, ep_data); - net2272_write(ep->dev, LOCCTL, tmp); - } - return length; -} - -/* returns: 0: still running, 1: completed, negative: errno */ -static int -net2272_write_fifo(struct net2272_ep *ep, struct net2272_request *req) -{ - u8 *buf; - unsigned count, max; - int status; - - dev_vdbg(ep->dev->dev, "write_fifo %s actual %d len %d\n", - ep->ep.name, req->req.actual, req->req.length); - - /* - * Keep loading the endpoint until the final packet is loaded, - * or the endpoint buffer is full. - */ - top: - /* - * Clear interrupt status - * - Packet Transmitted interrupt will become set again when the - * host successfully takes another packet - */ - net2272_ep_write(ep, EP_STAT0, (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)); - while (!(net2272_ep_read(ep, EP_STAT0) & (1 << BUFFER_FULL))) { - buf = req->req.buf + req->req.actual; - prefetch(buf); - - /* force pagesel */ - net2272_ep_read(ep, EP_STAT0); - - max = (net2272_ep_read(ep, EP_AVAIL1) << 8) | - (net2272_ep_read(ep, EP_AVAIL0)); - - if (max < ep->ep.maxpacket) - max = (net2272_ep_read(ep, EP_AVAIL1) << 8) - | (net2272_ep_read(ep, EP_AVAIL0)); - - count = net2272_write_packet(ep, buf, req, max); - /* see if we are done */ - if (req->req.length == req->req.actual) { - /* validate short or zlp packet */ - if (count < ep->ep.maxpacket) - set_fifo_bytecount(ep, 0); - net2272_done(ep, req, 0); - - if (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, - struct net2272_request, - queue); - status = net2272_kick_dma(ep, req); - - if (status < 0) - if ((net2272_ep_read(ep, EP_STAT0) - & (1 << BUFFER_EMPTY))) - goto top; - } - return 1; - } - net2272_ep_write(ep, EP_STAT0, (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)); - } - return 0; -} - -static void -net2272_out_flush(struct net2272_ep *ep) -{ - ASSERT_OUT_NAKING(ep); - - net2272_ep_write(ep, EP_STAT0, (1 << DATA_OUT_TOKEN_INTERRUPT) - | (1 << DATA_PACKET_RECEIVED_INTERRUPT)); - net2272_ep_write(ep, EP_STAT1, 1 << BUFFER_FLUSH); -} - -static int -net2272_read_packet(struct net2272_ep *ep, u8 *buf, - struct net2272_request *req, unsigned avail) -{ - u16 __iomem *ep_data = net2272_reg_addr(ep->dev, EP_DATA); - unsigned is_short; - u16 *bufp; - - req->req.actual += avail; - - dev_vdbg(ep->dev->dev, "read packet %s req %p len %u avail %u\n", - ep->ep.name, req, avail, - (net2272_ep_read(ep, EP_AVAIL1) << 8) | net2272_ep_read(ep, EP_AVAIL0)); - - is_short = (avail < ep->ep.maxpacket); - - if (unlikely(avail == 0)) { - /* remove any zlp from the buffer */ - (void)readw(ep_data); - return is_short; - } - - /* Ensure we get the final byte */ - if (unlikely(avail % 2)) - avail++; - bufp = (u16 *)buf; - - do { - *bufp++ = readw(ep_data); - avail -= 2; - } while (avail); - - /* - * To avoid false endpoint available race condition must read - * ep stat0 twice in the case of a short transfer - */ - if (net2272_ep_read(ep, EP_STAT0) & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)) - net2272_ep_read(ep, EP_STAT0); - - return is_short; -} - -static int -net2272_read_fifo(struct net2272_ep *ep, struct net2272_request *req) -{ - u8 *buf; - unsigned is_short; - int count; - int tmp; - int cleanup = 0; - int status = -1; - - dev_vdbg(ep->dev->dev, "read_fifo %s actual %d len %d\n", - ep->ep.name, req->req.actual, req->req.length); - - top: - do { - buf = req->req.buf + req->req.actual; - prefetchw(buf); - - count = (net2272_ep_read(ep, EP_AVAIL1) << 8) - | net2272_ep_read(ep, EP_AVAIL0); - - net2272_ep_write(ep, EP_STAT0, - (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT) | - (1 << DATA_PACKET_RECEIVED_INTERRUPT)); - - tmp = req->req.length - req->req.actual; - - if (count > tmp) { - if ((tmp % ep->ep.maxpacket) != 0) { - dev_err(ep->dev->dev, - "%s out fifo %d bytes, expected %d\n", - ep->ep.name, count, tmp); - cleanup = 1; - } - count = (tmp > 0) ? tmp : 0; - } - - is_short = net2272_read_packet(ep, buf, req, count); - - /* completion */ - if (unlikely(cleanup || is_short || - ((req->req.actual == req->req.length) - && !req->req.zero))) { - - if (cleanup) { - net2272_out_flush(ep); - net2272_done(ep, req, -EOVERFLOW); - } else - net2272_done(ep, req, 0); - - /* re-initialize endpoint transfer registers - * otherwise they may result in erroneous pre-validation - * for subsequent control reads - */ - if (unlikely(ep->num == 0)) { - net2272_ep_write(ep, EP_TRANSFER2, 0); - net2272_ep_write(ep, EP_TRANSFER1, 0); - net2272_ep_write(ep, EP_TRANSFER0, 0); - } - - if (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, - struct net2272_request, queue); - status = net2272_kick_dma(ep, req); - if ((status < 0) && - !(net2272_ep_read(ep, EP_STAT0) & (1 << BUFFER_EMPTY))) - goto top; - } - return 1; - } - } while (!(net2272_ep_read(ep, EP_STAT0) & (1 << BUFFER_EMPTY))); - - return 0; -} - -static void -net2272_pio_advance(struct net2272_ep *ep) -{ - struct net2272_request *req; - - if (unlikely(list_empty(&ep->queue))) - return; - - req = list_entry(ep->queue.next, struct net2272_request, queue); - (ep->is_in ? net2272_write_fifo : net2272_read_fifo)(ep, req); -} - -/* returns 0 on success, else negative errno */ -static int -net2272_request_dma(struct net2272 *dev, unsigned ep, u32 buf, - unsigned len, unsigned dir) -{ - dev_vdbg(dev->dev, "request_dma ep %d buf %08x len %d dir %d\n", - ep, buf, len, dir); - - /* The NET2272 only supports a single dma channel */ - if (dev->dma_busy) - return -EBUSY; - /* - * EP_TRANSFER (used to determine the number of bytes received - * in an OUT transfer) is 24 bits wide; don't ask for more than that. - */ - if ((dir == 1) && (len > 0x1000000)) - return -EINVAL; - - dev->dma_busy = 1; - - /* initialize platform's dma */ -#ifdef CONFIG_PCI - /* NET2272 addr, buffer addr, length, etc. */ - switch (dev->dev_id) { - case PCI_DEVICE_ID_RDK1: - /* Setup PLX 9054 DMA mode */ - writel((1 << LOCAL_BUS_WIDTH) | - (1 << TA_READY_INPUT_ENABLE) | - (0 << LOCAL_BURST_ENABLE) | - (1 << DONE_INTERRUPT_ENABLE) | - (1 << LOCAL_ADDRESSING_MODE) | - (1 << DEMAND_MODE) | - (1 << DMA_EOT_ENABLE) | - (1 << FAST_SLOW_TERMINATE_MODE_SELECT) | - (1 << DMA_CHANNEL_INTERRUPT_SELECT), - dev->rdk1.plx9054_base_addr + DMAMODE0); - - writel(0x100000, dev->rdk1.plx9054_base_addr + DMALADR0); - writel(buf, dev->rdk1.plx9054_base_addr + DMAPADR0); - writel(len, dev->rdk1.plx9054_base_addr + DMASIZ0); - writel((dir << DIRECTION_OF_TRANSFER) | - (1 << INTERRUPT_AFTER_TERMINAL_COUNT), - dev->rdk1.plx9054_base_addr + DMADPR0); - writel((1 << LOCAL_DMA_CHANNEL_0_INTERRUPT_ENABLE) | - readl(dev->rdk1.plx9054_base_addr + INTCSR), - dev->rdk1.plx9054_base_addr + INTCSR); - - break; - } -#endif - - net2272_write(dev, DMAREQ, - (0 << DMA_BUFFER_VALID) | - (1 << DMA_REQUEST_ENABLE) | - (1 << DMA_CONTROL_DACK) | - (dev->dma_eot_polarity << EOT_POLARITY) | - (dev->dma_dack_polarity << DACK_POLARITY) | - (dev->dma_dreq_polarity << DREQ_POLARITY) | - ((ep >> 1) << DMA_ENDPOINT_SELECT)); - - (void) net2272_read(dev, SCRATCH); - - return 0; -} - -static void -net2272_start_dma(struct net2272 *dev) -{ - /* start platform's dma controller */ -#ifdef CONFIG_PCI - switch (dev->dev_id) { - case PCI_DEVICE_ID_RDK1: - writeb((1 << CHANNEL_ENABLE) | (1 << CHANNEL_START), - dev->rdk1.plx9054_base_addr + DMACSR0); - break; - } -#endif -} - -/* returns 0 on success, else negative errno */ -static int -net2272_kick_dma(struct net2272_ep *ep, struct net2272_request *req) -{ - unsigned size; - u8 tmp; - - if (!use_dma || (ep->num < 1) || (ep->num > 2) || !ep->dma) - return -EINVAL; - - /* don't use dma for odd-length transfers - * otherwise, we'd need to deal with the last byte with pio - */ - if (req->req.length & 1) - return -EINVAL; - - dev_vdbg(ep->dev->dev, "kick_dma %s req %p dma %08llx\n", - ep->ep.name, req, (unsigned long long) req->req.dma); - - net2272_ep_write(ep, EP_RSPSET, 1 << ALT_NAK_OUT_PACKETS); - - /* The NET2272 can only use DMA on one endpoint at a time */ - if (ep->dev->dma_busy) - return -EBUSY; - - /* Make sure we only DMA an even number of bytes (we'll use - * pio to complete the transfer) - */ - size = req->req.length; - size &= ~1; - - /* device-to-host transfer */ - if (ep->is_in) { - /* initialize platform's dma controller */ - if (net2272_request_dma(ep->dev, ep->num, req->req.dma, size, 0)) - /* unable to obtain DMA channel; return error and use pio mode */ - return -EBUSY; - req->req.actual += size; - - /* host-to-device transfer */ - } else { - tmp = net2272_ep_read(ep, EP_STAT0); - - /* initialize platform's dma controller */ - if (net2272_request_dma(ep->dev, ep->num, req->req.dma, size, 1)) - /* unable to obtain DMA channel; return error and use pio mode */ - return -EBUSY; - - if (!(tmp & (1 << BUFFER_EMPTY))) - ep->not_empty = 1; - else - ep->not_empty = 0; - - - /* allow the endpoint's buffer to fill */ - net2272_ep_write(ep, EP_RSPCLR, 1 << ALT_NAK_OUT_PACKETS); - - /* this transfer completed and data's already in the fifo - * return error so pio gets used. - */ - if (tmp & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)) { - - /* deassert dreq */ - net2272_write(ep->dev, DMAREQ, - (0 << DMA_BUFFER_VALID) | - (0 << DMA_REQUEST_ENABLE) | - (1 << DMA_CONTROL_DACK) | - (ep->dev->dma_eot_polarity << EOT_POLARITY) | - (ep->dev->dma_dack_polarity << DACK_POLARITY) | - (ep->dev->dma_dreq_polarity << DREQ_POLARITY) | - ((ep->num >> 1) << DMA_ENDPOINT_SELECT)); - - return -EBUSY; - } - } - - /* Don't use per-packet interrupts: use dma interrupts only */ - net2272_ep_write(ep, EP_IRQENB, 0); - - net2272_start_dma(ep->dev); - - return 0; -} - -static void net2272_cancel_dma(struct net2272 *dev) -{ -#ifdef CONFIG_PCI - switch (dev->dev_id) { - case PCI_DEVICE_ID_RDK1: - writeb(0, dev->rdk1.plx9054_base_addr + DMACSR0); - writeb(1 << CHANNEL_ABORT, dev->rdk1.plx9054_base_addr + DMACSR0); - while (!(readb(dev->rdk1.plx9054_base_addr + DMACSR0) & - (1 << CHANNEL_DONE))) - continue; /* wait for dma to stabalize */ - - /* dma abort generates an interrupt */ - writeb(1 << CHANNEL_CLEAR_INTERRUPT, - dev->rdk1.plx9054_base_addr + DMACSR0); - break; - } -#endif - - dev->dma_busy = 0; -} - -/*---------------------------------------------------------------------------*/ - -static int -net2272_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) -{ - struct net2272_request *req; - struct net2272_ep *ep; - struct net2272 *dev; - unsigned long flags; - int status = -1; - u8 s; - - req = container_of(_req, struct net2272_request, req); - if (!_req || !_req->complete || !_req->buf - || !list_empty(&req->queue)) - return -EINVAL; - ep = container_of(_ep, struct net2272_ep, ep); - if (!_ep || (!ep->desc && ep->num != 0)) - return -EINVAL; - dev = ep->dev; - if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - /* set up dma mapping in case the caller didn't */ - if (use_dma && ep->dma) { - status = usb_gadget_map_request(&dev->gadget, _req, - ep->is_in); - if (status) - return status; - } - - dev_vdbg(dev->dev, "%s queue req %p, len %d buf %p dma %08llx %s\n", - _ep->name, _req, _req->length, _req->buf, - (unsigned long long) _req->dma, _req->zero ? "zero" : "!zero"); - - spin_lock_irqsave(&dev->lock, flags); - - _req->status = -EINPROGRESS; - _req->actual = 0; - - /* kickstart this i/o queue? */ - if (list_empty(&ep->queue) && !ep->stopped) { - /* maybe there's no control data, just status ack */ - if (ep->num == 0 && _req->length == 0) { - net2272_done(ep, req, 0); - dev_vdbg(dev->dev, "%s status ack\n", ep->ep.name); - goto done; - } - - /* Return zlp, don't let it block subsequent packets */ - s = net2272_ep_read(ep, EP_STAT0); - if (s & (1 << BUFFER_EMPTY)) { - /* Buffer is empty check for a blocking zlp, handle it */ - if ((s & (1 << NAK_OUT_PACKETS)) && - net2272_ep_read(ep, EP_STAT1) & (1 << LOCAL_OUT_ZLP)) { - dev_dbg(dev->dev, "WARNING: returning ZLP short packet termination!\n"); - /* - * Request is going to terminate with a short packet ... - * hope the client is ready for it! - */ - status = net2272_read_fifo(ep, req); - /* clear short packet naking */ - net2272_ep_write(ep, EP_STAT0, (1 << NAK_OUT_PACKETS)); - goto done; - } - } - - /* try dma first */ - status = net2272_kick_dma(ep, req); - - if (status < 0) { - /* dma failed (most likely in use by another endpoint) - * fallback to pio - */ - status = 0; - - if (ep->is_in) - status = net2272_write_fifo(ep, req); - else { - s = net2272_ep_read(ep, EP_STAT0); - if ((s & (1 << BUFFER_EMPTY)) == 0) - status = net2272_read_fifo(ep, req); - } - - if (unlikely(status != 0)) { - if (status > 0) - status = 0; - req = NULL; - } - } - } - if (likely(req != 0)) - list_add_tail(&req->queue, &ep->queue); - - if (likely(!list_empty(&ep->queue))) - net2272_ep_write(ep, EP_RSPCLR, 1 << ALT_NAK_OUT_PACKETS); - done: - spin_unlock_irqrestore(&dev->lock, flags); - - return 0; -} - -/* dequeue ALL requests */ -static void -net2272_dequeue_all(struct net2272_ep *ep) -{ - struct net2272_request *req; - - /* called with spinlock held */ - ep->stopped = 1; - - while (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, - struct net2272_request, - queue); - net2272_done(ep, req, -ESHUTDOWN); - } -} - -/* dequeue JUST ONE request */ -static int -net2272_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct net2272_ep *ep; - struct net2272_request *req; - unsigned long flags; - int stopped; - - ep = container_of(_ep, struct net2272_ep, ep); - if (!_ep || (!ep->desc && ep->num != 0) || !_req) - return -EINVAL; - - spin_lock_irqsave(&ep->dev->lock, flags); - stopped = ep->stopped; - ep->stopped = 1; - - /* make sure it's still queued on this endpoint */ - list_for_each_entry(req, &ep->queue, queue) { - if (&req->req == _req) - break; - } - if (&req->req != _req) { - spin_unlock_irqrestore(&ep->dev->lock, flags); - return -EINVAL; - } - - /* queue head may be partially complete */ - if (ep->queue.next == &req->queue) { - dev_dbg(ep->dev->dev, "unlink (%s) pio\n", _ep->name); - net2272_done(ep, req, -ECONNRESET); - } - req = NULL; - ep->stopped = stopped; - - spin_unlock_irqrestore(&ep->dev->lock, flags); - return 0; -} - -/*---------------------------------------------------------------------------*/ - -static int -net2272_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged) -{ - struct net2272_ep *ep; - unsigned long flags; - int ret = 0; - - ep = container_of(_ep, struct net2272_ep, ep); - if (!_ep || (!ep->desc && ep->num != 0)) - return -EINVAL; - if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - if (ep->desc /* not ep0 */ && usb_endpoint_xfer_isoc(ep->desc)) - return -EINVAL; - - spin_lock_irqsave(&ep->dev->lock, flags); - if (!list_empty(&ep->queue)) - ret = -EAGAIN; - else if (ep->is_in && value && net2272_fifo_status(_ep) != 0) - ret = -EAGAIN; - else { - dev_vdbg(ep->dev->dev, "%s %s %s\n", _ep->name, - value ? "set" : "clear", - wedged ? "wedge" : "halt"); - /* set/clear */ - if (value) { - if (ep->num == 0) - ep->dev->protocol_stall = 1; - else - set_halt(ep); - if (wedged) - ep->wedged = 1; - } else { - clear_halt(ep); - ep->wedged = 0; - } - } - spin_unlock_irqrestore(&ep->dev->lock, flags); - - return ret; -} - -static int -net2272_set_halt(struct usb_ep *_ep, int value) -{ - return net2272_set_halt_and_wedge(_ep, value, 0); -} - -static int -net2272_set_wedge(struct usb_ep *_ep) -{ - if (!_ep || _ep->name == ep0name) - return -EINVAL; - return net2272_set_halt_and_wedge(_ep, 1, 1); -} - -static int -net2272_fifo_status(struct usb_ep *_ep) -{ - struct net2272_ep *ep; - u16 avail; - - ep = container_of(_ep, struct net2272_ep, ep); - if (!_ep || (!ep->desc && ep->num != 0)) - return -ENODEV; - if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - avail = net2272_ep_read(ep, EP_AVAIL1) << 8; - avail |= net2272_ep_read(ep, EP_AVAIL0); - if (avail > ep->fifo_size) - return -EOVERFLOW; - if (ep->is_in) - avail = ep->fifo_size - avail; - return avail; -} - -static void -net2272_fifo_flush(struct usb_ep *_ep) -{ - struct net2272_ep *ep; - - ep = container_of(_ep, struct net2272_ep, ep); - if (!_ep || (!ep->desc && ep->num != 0)) - return; - if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) - return; - - net2272_ep_write(ep, EP_STAT1, 1 << BUFFER_FLUSH); -} - -static struct usb_ep_ops net2272_ep_ops = { - .enable = net2272_enable, - .disable = net2272_disable, - - .alloc_request = net2272_alloc_request, - .free_request = net2272_free_request, - - .queue = net2272_queue, - .dequeue = net2272_dequeue, - - .set_halt = net2272_set_halt, - .set_wedge = net2272_set_wedge, - .fifo_status = net2272_fifo_status, - .fifo_flush = net2272_fifo_flush, -}; - -/*---------------------------------------------------------------------------*/ - -static int -net2272_get_frame(struct usb_gadget *_gadget) -{ - struct net2272 *dev; - unsigned long flags; - u16 ret; - - if (!_gadget) - return -ENODEV; - dev = container_of(_gadget, struct net2272, gadget); - spin_lock_irqsave(&dev->lock, flags); - - ret = net2272_read(dev, FRAME1) << 8; - ret |= net2272_read(dev, FRAME0); - - spin_unlock_irqrestore(&dev->lock, flags); - return ret; -} - -static int -net2272_wakeup(struct usb_gadget *_gadget) -{ - struct net2272 *dev; - u8 tmp; - unsigned long flags; - - if (!_gadget) - return 0; - dev = container_of(_gadget, struct net2272, gadget); - - spin_lock_irqsave(&dev->lock, flags); - tmp = net2272_read(dev, USBCTL0); - if (tmp & (1 << IO_WAKEUP_ENABLE)) - net2272_write(dev, USBCTL1, (1 << GENERATE_RESUME)); - - spin_unlock_irqrestore(&dev->lock, flags); - - return 0; -} - -static int -net2272_set_selfpowered(struct usb_gadget *_gadget, int value) -{ - struct net2272 *dev; - - if (!_gadget) - return -ENODEV; - dev = container_of(_gadget, struct net2272, gadget); - - dev->is_selfpowered = value; - - return 0; -} - -static int -net2272_pullup(struct usb_gadget *_gadget, int is_on) -{ - struct net2272 *dev; - u8 tmp; - unsigned long flags; - - if (!_gadget) - return -ENODEV; - dev = container_of(_gadget, struct net2272, gadget); - - spin_lock_irqsave(&dev->lock, flags); - tmp = net2272_read(dev, USBCTL0); - dev->softconnect = (is_on != 0); - if (is_on) - tmp |= (1 << USB_DETECT_ENABLE); - else - tmp &= ~(1 << USB_DETECT_ENABLE); - net2272_write(dev, USBCTL0, tmp); - spin_unlock_irqrestore(&dev->lock, flags); - - return 0; -} - -static int net2272_start(struct usb_gadget *_gadget, - struct usb_gadget_driver *driver); -static int net2272_stop(struct usb_gadget *_gadget, - struct usb_gadget_driver *driver); - -static const struct usb_gadget_ops net2272_ops = { - .get_frame = net2272_get_frame, - .wakeup = net2272_wakeup, - .set_selfpowered = net2272_set_selfpowered, - .pullup = net2272_pullup, - .udc_start = net2272_start, - .udc_stop = net2272_stop, -}; - -/*---------------------------------------------------------------------------*/ - -static ssize_t -net2272_show_registers(struct device *_dev, struct device_attribute *attr, char *buf) -{ - struct net2272 *dev; - char *next; - unsigned size, t; - unsigned long flags; - u8 t1, t2; - int i; - const char *s; - - dev = dev_get_drvdata(_dev); - next = buf; - size = PAGE_SIZE; - spin_lock_irqsave(&dev->lock, flags); - - if (dev->driver) - s = dev->driver->driver.name; - else - s = "(none)"; - - /* Main Control Registers */ - t = scnprintf(next, size, "%s version %s," - "chiprev %02x, locctl %02x\n" - "irqenb0 %02x irqenb1 %02x " - "irqstat0 %02x irqstat1 %02x\n", - driver_name, driver_vers, dev->chiprev, - net2272_read(dev, LOCCTL), - net2272_read(dev, IRQENB0), - net2272_read(dev, IRQENB1), - net2272_read(dev, IRQSTAT0), - net2272_read(dev, IRQSTAT1)); - size -= t; - next += t; - - /* DMA */ - t1 = net2272_read(dev, DMAREQ); - t = scnprintf(next, size, "\ndmareq %02x: %s %s%s%s%s\n", - t1, ep_name[(t1 & 0x01) + 1], - t1 & (1 << DMA_CONTROL_DACK) ? "dack " : "", - t1 & (1 << DMA_REQUEST_ENABLE) ? "reqenb " : "", - t1 & (1 << DMA_REQUEST) ? "req " : "", - t1 & (1 << DMA_BUFFER_VALID) ? "valid " : ""); - size -= t; - next += t; - - /* USB Control Registers */ - t1 = net2272_read(dev, USBCTL1); - if (t1 & (1 << VBUS_PIN)) { - if (t1 & (1 << USB_HIGH_SPEED)) - s = "high speed"; - else if (dev->gadget.speed == USB_SPEED_UNKNOWN) - s = "powered"; - else - s = "full speed"; - } else - s = "not attached"; - t = scnprintf(next, size, - "usbctl0 %02x usbctl1 %02x addr 0x%02x (%s)\n", - net2272_read(dev, USBCTL0), t1, - net2272_read(dev, OURADDR), s); - size -= t; - next += t; - - /* Endpoint Registers */ - for (i = 0; i < 4; ++i) { - struct net2272_ep *ep; - - ep = &dev->ep[i]; - if (i && !ep->desc) - continue; - - t1 = net2272_ep_read(ep, EP_CFG); - t2 = net2272_ep_read(ep, EP_RSPSET); - t = scnprintf(next, size, - "\n%s\tcfg %02x rsp (%02x) %s%s%s%s%s%s%s%s" - "irqenb %02x\n", - ep->ep.name, t1, t2, - (t2 & (1 << ALT_NAK_OUT_PACKETS)) ? "NAK " : "", - (t2 & (1 << HIDE_STATUS_PHASE)) ? "hide " : "", - (t2 & (1 << AUTOVALIDATE)) ? "auto " : "", - (t2 & (1 << INTERRUPT_MODE)) ? "interrupt " : "", - (t2 & (1 << CONTROL_STATUS_PHASE_HANDSHAKE)) ? "status " : "", - (t2 & (1 << NAK_OUT_PACKETS_MODE)) ? "NAKmode " : "", - (t2 & (1 << ENDPOINT_TOGGLE)) ? "DATA1 " : "DATA0 ", - (t2 & (1 << ENDPOINT_HALT)) ? "HALT " : "", - net2272_ep_read(ep, EP_IRQENB)); - size -= t; - next += t; - - t = scnprintf(next, size, - "\tstat0 %02x stat1 %02x avail %04x " - "(ep%d%s-%s)%s\n", - net2272_ep_read(ep, EP_STAT0), - net2272_ep_read(ep, EP_STAT1), - (net2272_ep_read(ep, EP_AVAIL1) << 8) | net2272_ep_read(ep, EP_AVAIL0), - t1 & 0x0f, - ep->is_in ? "in" : "out", - type_string(t1 >> 5), - ep->stopped ? "*" : ""); - size -= t; - next += t; - - t = scnprintf(next, size, - "\tep_transfer %06x\n", - ((net2272_ep_read(ep, EP_TRANSFER2) & 0xff) << 16) | - ((net2272_ep_read(ep, EP_TRANSFER1) & 0xff) << 8) | - ((net2272_ep_read(ep, EP_TRANSFER0) & 0xff))); - size -= t; - next += t; - - t1 = net2272_ep_read(ep, EP_BUFF_STATES) & 0x03; - t2 = (net2272_ep_read(ep, EP_BUFF_STATES) >> 2) & 0x03; - t = scnprintf(next, size, - "\tbuf-a %s buf-b %s\n", - buf_state_string(t1), - buf_state_string(t2)); - size -= t; - next += t; - } - - spin_unlock_irqrestore(&dev->lock, flags); - - return PAGE_SIZE - size; -} -static DEVICE_ATTR(registers, S_IRUGO, net2272_show_registers, NULL); - -/*---------------------------------------------------------------------------*/ - -static void -net2272_set_fifo_mode(struct net2272 *dev, int mode) -{ - u8 tmp; - - tmp = net2272_read(dev, LOCCTL) & 0x3f; - tmp |= (mode << 6); - net2272_write(dev, LOCCTL, tmp); - - INIT_LIST_HEAD(&dev->gadget.ep_list); - - /* always ep-a, ep-c ... maybe not ep-b */ - list_add_tail(&dev->ep[1].ep.ep_list, &dev->gadget.ep_list); - - switch (mode) { - case 0: - list_add_tail(&dev->ep[2].ep.ep_list, &dev->gadget.ep_list); - dev->ep[1].fifo_size = dev->ep[2].fifo_size = 512; - break; - case 1: - list_add_tail(&dev->ep[2].ep.ep_list, &dev->gadget.ep_list); - dev->ep[1].fifo_size = 1024; - dev->ep[2].fifo_size = 512; - break; - case 2: - list_add_tail(&dev->ep[2].ep.ep_list, &dev->gadget.ep_list); - dev->ep[1].fifo_size = dev->ep[2].fifo_size = 1024; - break; - case 3: - dev->ep[1].fifo_size = 1024; - break; - } - - /* ep-c is always 2 512 byte buffers */ - list_add_tail(&dev->ep[3].ep.ep_list, &dev->gadget.ep_list); - dev->ep[3].fifo_size = 512; -} - -/*---------------------------------------------------------------------------*/ - -static void -net2272_usb_reset(struct net2272 *dev) -{ - dev->gadget.speed = USB_SPEED_UNKNOWN; - - net2272_cancel_dma(dev); - - net2272_write(dev, IRQENB0, 0); - net2272_write(dev, IRQENB1, 0); - - /* clear irq state */ - net2272_write(dev, IRQSTAT0, 0xff); - net2272_write(dev, IRQSTAT1, ~(1 << SUSPEND_REQUEST_INTERRUPT)); - - net2272_write(dev, DMAREQ, - (0 << DMA_BUFFER_VALID) | - (0 << DMA_REQUEST_ENABLE) | - (1 << DMA_CONTROL_DACK) | - (dev->dma_eot_polarity << EOT_POLARITY) | - (dev->dma_dack_polarity << DACK_POLARITY) | - (dev->dma_dreq_polarity << DREQ_POLARITY) | - ((dma_ep >> 1) << DMA_ENDPOINT_SELECT)); - - net2272_cancel_dma(dev); - net2272_set_fifo_mode(dev, (fifo_mode <= 3) ? fifo_mode : 0); - - /* Set the NET2272 ep fifo data width to 16-bit mode and for correct byte swapping - * note that the higher level gadget drivers are expected to convert data to little endian. - * Enable byte swap for your local bus/cpu if needed by setting BYTE_SWAP in LOCCTL here - */ - net2272_write(dev, LOCCTL, net2272_read(dev, LOCCTL) | (1 << DATA_WIDTH)); - net2272_write(dev, LOCCTL1, (dma_mode << DMA_MODE)); -} - -static void -net2272_usb_reinit(struct net2272 *dev) -{ - int i; - - /* basic endpoint init */ - for (i = 0; i < 4; ++i) { - struct net2272_ep *ep = &dev->ep[i]; - - ep->ep.name = ep_name[i]; - ep->dev = dev; - ep->num = i; - ep->not_empty = 0; - - if (use_dma && ep->num == dma_ep) - ep->dma = 1; - - if (i > 0 && i <= 3) - ep->fifo_size = 512; - else - ep->fifo_size = 64; - net2272_ep_reset(ep); - } - dev->ep[0].ep.maxpacket = 64; - - dev->gadget.ep0 = &dev->ep[0].ep; - dev->ep[0].stopped = 0; - INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); -} - -static void -net2272_ep0_start(struct net2272 *dev) -{ - struct net2272_ep *ep0 = &dev->ep[0]; - - net2272_ep_write(ep0, EP_RSPSET, - (1 << NAK_OUT_PACKETS_MODE) | - (1 << ALT_NAK_OUT_PACKETS)); - net2272_ep_write(ep0, EP_RSPCLR, - (1 << HIDE_STATUS_PHASE) | - (1 << CONTROL_STATUS_PHASE_HANDSHAKE)); - net2272_write(dev, USBCTL0, - (dev->softconnect << USB_DETECT_ENABLE) | - (1 << USB_ROOT_PORT_WAKEUP_ENABLE) | - (1 << IO_WAKEUP_ENABLE)); - net2272_write(dev, IRQENB0, - (1 << SETUP_PACKET_INTERRUPT_ENABLE) | - (1 << ENDPOINT_0_INTERRUPT_ENABLE) | - (1 << DMA_DONE_INTERRUPT_ENABLE)); - net2272_write(dev, IRQENB1, - (1 << VBUS_INTERRUPT_ENABLE) | - (1 << ROOT_PORT_RESET_INTERRUPT_ENABLE) | - (1 << SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE)); -} - -/* when a driver is successfully registered, it will receive - * control requests including set_configuration(), which enables - * non-control requests. then usb traffic follows until a - * disconnect is reported. then a host may connect again, or - * the driver might get unbound. - */ -static int net2272_start(struct usb_gadget *_gadget, - struct usb_gadget_driver *driver) -{ - struct net2272 *dev; - unsigned i; - - if (!driver || !driver->unbind || !driver->setup || - driver->max_speed != USB_SPEED_HIGH) - return -EINVAL; - - dev = container_of(_gadget, struct net2272, gadget); - - for (i = 0; i < 4; ++i) - dev->ep[i].irqs = 0; - /* hook up the driver ... */ - dev->softconnect = 1; - driver->driver.bus = NULL; - dev->driver = driver; - dev->gadget.dev.driver = &driver->driver; - - /* ... then enable host detection and ep0; and we're ready - * for set_configuration as well as eventual disconnect. - */ - net2272_ep0_start(dev); - - dev_dbg(dev->dev, "%s ready\n", driver->driver.name); - - return 0; -} - -static void -stop_activity(struct net2272 *dev, struct usb_gadget_driver *driver) -{ - int i; - - /* don't disconnect if it's not connected */ - if (dev->gadget.speed == USB_SPEED_UNKNOWN) - driver = NULL; - - /* stop hardware; prevent new request submissions; - * and kill any outstanding requests. - */ - net2272_usb_reset(dev); - for (i = 0; i < 4; ++i) - net2272_dequeue_all(&dev->ep[i]); - - net2272_usb_reinit(dev); -} - -static int net2272_stop(struct usb_gadget *_gadget, - struct usb_gadget_driver *driver) -{ - struct net2272 *dev; - unsigned long flags; - - dev = container_of(_gadget, struct net2272, gadget); - - spin_lock_irqsave(&dev->lock, flags); - stop_activity(dev, driver); - spin_unlock_irqrestore(&dev->lock, flags); - - dev->gadget.dev.driver = NULL; - dev->driver = NULL; - - dev_dbg(dev->dev, "unregistered driver '%s'\n", driver->driver.name); - return 0; -} - -/*---------------------------------------------------------------------------*/ -/* handle ep-a/ep-b dma completions */ -static void -net2272_handle_dma(struct net2272_ep *ep) -{ - struct net2272_request *req; - unsigned len; - int status; - - if (!list_empty(&ep->queue)) - req = list_entry(ep->queue.next, - struct net2272_request, queue); - else - req = NULL; - - dev_vdbg(ep->dev->dev, "handle_dma %s req %p\n", ep->ep.name, req); - - /* Ensure DREQ is de-asserted */ - net2272_write(ep->dev, DMAREQ, - (0 << DMA_BUFFER_VALID) - | (0 << DMA_REQUEST_ENABLE) - | (1 << DMA_CONTROL_DACK) - | (ep->dev->dma_eot_polarity << EOT_POLARITY) - | (ep->dev->dma_dack_polarity << DACK_POLARITY) - | (ep->dev->dma_dreq_polarity << DREQ_POLARITY) - | ((ep->dma >> 1) << DMA_ENDPOINT_SELECT)); - - ep->dev->dma_busy = 0; - - net2272_ep_write(ep, EP_IRQENB, - (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE) - | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE) - | net2272_ep_read(ep, EP_IRQENB)); - - /* device-to-host transfer completed */ - if (ep->is_in) { - /* validate a short packet or zlp if necessary */ - if ((req->req.length % ep->ep.maxpacket != 0) || - req->req.zero) - set_fifo_bytecount(ep, 0); - - net2272_done(ep, req, 0); - if (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, - struct net2272_request, queue); - status = net2272_kick_dma(ep, req); - if (status < 0) - net2272_pio_advance(ep); - } - - /* host-to-device transfer completed */ - } else { - /* terminated with a short packet? */ - if (net2272_read(ep->dev, IRQSTAT0) & - (1 << DMA_DONE_INTERRUPT)) { - /* abort system dma */ - net2272_cancel_dma(ep->dev); - } - - /* EP_TRANSFER will contain the number of bytes - * actually received. - * NOTE: There is no overflow detection on EP_TRANSFER: - * We can't deal with transfers larger than 2^24 bytes! - */ - len = (net2272_ep_read(ep, EP_TRANSFER2) << 16) - | (net2272_ep_read(ep, EP_TRANSFER1) << 8) - | (net2272_ep_read(ep, EP_TRANSFER0)); - - if (ep->not_empty) - len += 4; - - req->req.actual += len; - - /* get any remaining data */ - net2272_pio_advance(ep); - } -} - -/*---------------------------------------------------------------------------*/ - -static void -net2272_handle_ep(struct net2272_ep *ep) -{ - struct net2272_request *req; - u8 stat0, stat1; - - if (!list_empty(&ep->queue)) - req = list_entry(ep->queue.next, - struct net2272_request, queue); - else - req = NULL; - - /* ack all, and handle what we care about */ - stat0 = net2272_ep_read(ep, EP_STAT0); - stat1 = net2272_ep_read(ep, EP_STAT1); - ep->irqs++; - - dev_vdbg(ep->dev->dev, "%s ack ep_stat0 %02x, ep_stat1 %02x, req %p\n", - ep->ep.name, stat0, stat1, req ? &req->req : 0); - - net2272_ep_write(ep, EP_STAT0, stat0 & - ~((1 << NAK_OUT_PACKETS) - | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT))); - net2272_ep_write(ep, EP_STAT1, stat1); - - /* data packet(s) received (in the fifo, OUT) - * direction must be validated, otherwise control read status phase - * could be interpreted as a valid packet - */ - if (!ep->is_in && (stat0 & (1 << DATA_PACKET_RECEIVED_INTERRUPT))) - net2272_pio_advance(ep); - /* data packet(s) transmitted (IN) */ - else if (stat0 & (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)) - net2272_pio_advance(ep); -} - -static struct net2272_ep * -net2272_get_ep_by_addr(struct net2272 *dev, u16 wIndex) -{ - struct net2272_ep *ep; - - if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0) - return &dev->ep[0]; - - list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) { - u8 bEndpointAddress; - - if (!ep->desc) - continue; - bEndpointAddress = ep->desc->bEndpointAddress; - if ((wIndex ^ bEndpointAddress) & USB_DIR_IN) - continue; - if ((wIndex & 0x0f) == (bEndpointAddress & 0x0f)) - return ep; - } - return NULL; -} - -/* - * USB Test Packet: - * JKJKJKJK * 9 - * JJKKJJKK * 8 - * JJJJKKKK * 8 - * JJJJJJJKKKKKKK * 8 - * JJJJJJJK * 8 - * {JKKKKKKK * 10}, JK - */ -static const u8 net2272_test_packet[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, - 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, - 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, - 0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFD, 0x7E -}; - -static void -net2272_set_test_mode(struct net2272 *dev, int mode) -{ - int i; - - /* Disable all net2272 interrupts: - * Nothing but a power cycle should stop the test. - */ - net2272_write(dev, IRQENB0, 0x00); - net2272_write(dev, IRQENB1, 0x00); - - /* Force tranceiver to high-speed */ - net2272_write(dev, XCVRDIAG, 1 << FORCE_HIGH_SPEED); - - net2272_write(dev, PAGESEL, 0); - net2272_write(dev, EP_STAT0, 1 << DATA_PACKET_TRANSMITTED_INTERRUPT); - net2272_write(dev, EP_RSPCLR, - (1 << CONTROL_STATUS_PHASE_HANDSHAKE) - | (1 << HIDE_STATUS_PHASE)); - net2272_write(dev, EP_CFG, 1 << ENDPOINT_DIRECTION); - net2272_write(dev, EP_STAT1, 1 << BUFFER_FLUSH); - - /* wait for status phase to complete */ - while (!(net2272_read(dev, EP_STAT0) & - (1 << DATA_PACKET_TRANSMITTED_INTERRUPT))) - ; - - /* Enable test mode */ - net2272_write(dev, USBTEST, mode); - - /* load test packet */ - if (mode == TEST_PACKET) { - /* switch to 8 bit mode */ - net2272_write(dev, LOCCTL, net2272_read(dev, LOCCTL) & - ~(1 << DATA_WIDTH)); - - for (i = 0; i < sizeof(net2272_test_packet); ++i) - net2272_write(dev, EP_DATA, net2272_test_packet[i]); - - /* Validate test packet */ - net2272_write(dev, EP_TRANSFER0, 0); - } -} - -static void -net2272_handle_stat0_irqs(struct net2272 *dev, u8 stat) -{ - struct net2272_ep *ep; - u8 num, scratch; - - /* starting a control request? */ - if (unlikely(stat & (1 << SETUP_PACKET_INTERRUPT))) { - union { - u8 raw[8]; - struct usb_ctrlrequest r; - } u; - int tmp = 0; - struct net2272_request *req; - - if (dev->gadget.speed == USB_SPEED_UNKNOWN) { - if (net2272_read(dev, USBCTL1) & (1 << USB_HIGH_SPEED)) - dev->gadget.speed = USB_SPEED_HIGH; - else - dev->gadget.speed = USB_SPEED_FULL; - dev_dbg(dev->dev, "%s\n", - usb_speed_string(dev->gadget.speed)); - } - - ep = &dev->ep[0]; - ep->irqs++; - - /* make sure any leftover interrupt state is cleared */ - stat &= ~(1 << ENDPOINT_0_INTERRUPT); - while (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, - struct net2272_request, queue); - net2272_done(ep, req, - (req->req.actual == req->req.length) ? 0 : -EPROTO); - } - ep->stopped = 0; - dev->protocol_stall = 0; - net2272_ep_write(ep, EP_STAT0, - (1 << DATA_IN_TOKEN_INTERRUPT) - | (1 << DATA_OUT_TOKEN_INTERRUPT) - | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT) - | (1 << DATA_PACKET_RECEIVED_INTERRUPT) - | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)); - net2272_ep_write(ep, EP_STAT1, - (1 << TIMEOUT) - | (1 << USB_OUT_ACK_SENT) - | (1 << USB_OUT_NAK_SENT) - | (1 << USB_IN_ACK_RCVD) - | (1 << USB_IN_NAK_SENT) - | (1 << USB_STALL_SENT) - | (1 << LOCAL_OUT_ZLP)); - - /* - * Ensure Control Read pre-validation setting is beyond maximum size - * - Control Writes can leave non-zero values in EP_TRANSFER. If - * an EP0 transfer following the Control Write is a Control Read, - * the NET2272 sees the non-zero EP_TRANSFER as an unexpected - * pre-validation count. - * - Setting EP_TRANSFER beyond the maximum EP0 transfer size ensures - * the pre-validation count cannot cause an unexpected validatation - */ - net2272_write(dev, PAGESEL, 0); - net2272_write(dev, EP_TRANSFER2, 0xff); - net2272_write(dev, EP_TRANSFER1, 0xff); - net2272_write(dev, EP_TRANSFER0, 0xff); - - u.raw[0] = net2272_read(dev, SETUP0); - u.raw[1] = net2272_read(dev, SETUP1); - u.raw[2] = net2272_read(dev, SETUP2); - u.raw[3] = net2272_read(dev, SETUP3); - u.raw[4] = net2272_read(dev, SETUP4); - u.raw[5] = net2272_read(dev, SETUP5); - u.raw[6] = net2272_read(dev, SETUP6); - u.raw[7] = net2272_read(dev, SETUP7); - /* - * If you have a big endian cpu make sure le16_to_cpus - * performs the proper byte swapping here... - */ - le16_to_cpus(&u.r.wValue); - le16_to_cpus(&u.r.wIndex); - le16_to_cpus(&u.r.wLength); - - /* ack the irq */ - net2272_write(dev, IRQSTAT0, 1 << SETUP_PACKET_INTERRUPT); - stat ^= (1 << SETUP_PACKET_INTERRUPT); - - /* watch control traffic at the token level, and force - * synchronization before letting the status phase happen. - */ - ep->is_in = (u.r.bRequestType & USB_DIR_IN) != 0; - if (ep->is_in) { - scratch = (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE) - | (1 << DATA_OUT_TOKEN_INTERRUPT_ENABLE) - | (1 << DATA_IN_TOKEN_INTERRUPT_ENABLE); - stop_out_naking(ep); - } else - scratch = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE) - | (1 << DATA_OUT_TOKEN_INTERRUPT_ENABLE) - | (1 << DATA_IN_TOKEN_INTERRUPT_ENABLE); - net2272_ep_write(ep, EP_IRQENB, scratch); - - if ((u.r.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD) - goto delegate; - switch (u.r.bRequest) { - case USB_REQ_GET_STATUS: { - struct net2272_ep *e; - u16 status = 0; - - switch (u.r.bRequestType & USB_RECIP_MASK) { - case USB_RECIP_ENDPOINT: - e = net2272_get_ep_by_addr(dev, u.r.wIndex); - if (!e || u.r.wLength > 2) - goto do_stall; - if (net2272_ep_read(e, EP_RSPSET) & (1 << ENDPOINT_HALT)) - status = __constant_cpu_to_le16(1); - else - status = __constant_cpu_to_le16(0); - - /* don't bother with a request object! */ - net2272_ep_write(&dev->ep[0], EP_IRQENB, 0); - writew(status, net2272_reg_addr(dev, EP_DATA)); - set_fifo_bytecount(&dev->ep[0], 0); - allow_status(ep); - dev_vdbg(dev->dev, "%s stat %02x\n", - ep->ep.name, status); - goto next_endpoints; - case USB_RECIP_DEVICE: - if (u.r.wLength > 2) - goto do_stall; - if (dev->is_selfpowered) - status = (1 << USB_DEVICE_SELF_POWERED); - - /* don't bother with a request object! */ - net2272_ep_write(&dev->ep[0], EP_IRQENB, 0); - writew(status, net2272_reg_addr(dev, EP_DATA)); - set_fifo_bytecount(&dev->ep[0], 0); - allow_status(ep); - dev_vdbg(dev->dev, "device stat %02x\n", status); - goto next_endpoints; - case USB_RECIP_INTERFACE: - if (u.r.wLength > 2) - goto do_stall; - - /* don't bother with a request object! */ - net2272_ep_write(&dev->ep[0], EP_IRQENB, 0); - writew(status, net2272_reg_addr(dev, EP_DATA)); - set_fifo_bytecount(&dev->ep[0], 0); - allow_status(ep); - dev_vdbg(dev->dev, "interface status %02x\n", status); - goto next_endpoints; - } - - break; - } - case USB_REQ_CLEAR_FEATURE: { - struct net2272_ep *e; - - if (u.r.bRequestType != USB_RECIP_ENDPOINT) - goto delegate; - if (u.r.wValue != USB_ENDPOINT_HALT || - u.r.wLength != 0) - goto do_stall; - e = net2272_get_ep_by_addr(dev, u.r.wIndex); - if (!e) - goto do_stall; - if (e->wedged) { - dev_vdbg(dev->dev, "%s wedged, halt not cleared\n", - ep->ep.name); - } else { - dev_vdbg(dev->dev, "%s clear halt\n", ep->ep.name); - clear_halt(e); - } - allow_status(ep); - goto next_endpoints; - } - case USB_REQ_SET_FEATURE: { - struct net2272_ep *e; - - if (u.r.bRequestType == USB_RECIP_DEVICE) { - if (u.r.wIndex != NORMAL_OPERATION) - net2272_set_test_mode(dev, (u.r.wIndex >> 8)); - allow_status(ep); - dev_vdbg(dev->dev, "test mode: %d\n", u.r.wIndex); - goto next_endpoints; - } else if (u.r.bRequestType != USB_RECIP_ENDPOINT) - goto delegate; - if (u.r.wValue != USB_ENDPOINT_HALT || - u.r.wLength != 0) - goto do_stall; - e = net2272_get_ep_by_addr(dev, u.r.wIndex); - if (!e) - goto do_stall; - set_halt(e); - allow_status(ep); - dev_vdbg(dev->dev, "%s set halt\n", ep->ep.name); - goto next_endpoints; - } - case USB_REQ_SET_ADDRESS: { - net2272_write(dev, OURADDR, u.r.wValue & 0xff); - allow_status(ep); - break; - } - default: - delegate: - dev_vdbg(dev->dev, "setup %02x.%02x v%04x i%04x " - "ep_cfg %08x\n", - u.r.bRequestType, u.r.bRequest, - u.r.wValue, u.r.wIndex, - net2272_ep_read(ep, EP_CFG)); - spin_unlock(&dev->lock); - tmp = dev->driver->setup(&dev->gadget, &u.r); - spin_lock(&dev->lock); - } - - /* stall ep0 on error */ - if (tmp < 0) { - do_stall: - dev_vdbg(dev->dev, "req %02x.%02x protocol STALL; stat %d\n", - u.r.bRequestType, u.r.bRequest, tmp); - dev->protocol_stall = 1; - } - /* endpoint dma irq? */ - } else if (stat & (1 << DMA_DONE_INTERRUPT)) { - net2272_cancel_dma(dev); - net2272_write(dev, IRQSTAT0, 1 << DMA_DONE_INTERRUPT); - stat &= ~(1 << DMA_DONE_INTERRUPT); - num = (net2272_read(dev, DMAREQ) & (1 << DMA_ENDPOINT_SELECT)) - ? 2 : 1; - - ep = &dev->ep[num]; - net2272_handle_dma(ep); - } - - next_endpoints: - /* endpoint data irq? */ - scratch = stat & 0x0f; - stat &= ~0x0f; - for (num = 0; scratch; num++) { - u8 t; - - /* does this endpoint's FIFO and queue need tending? */ - t = 1 << num; - if ((scratch & t) == 0) - continue; - scratch ^= t; - - ep = &dev->ep[num]; - net2272_handle_ep(ep); - } - - /* some interrupts we can just ignore */ - stat &= ~(1 << SOF_INTERRUPT); - - if (stat) - dev_dbg(dev->dev, "unhandled irqstat0 %02x\n", stat); -} - -static void -net2272_handle_stat1_irqs(struct net2272 *dev, u8 stat) -{ - u8 tmp, mask; - - /* after disconnect there's nothing else to do! */ - tmp = (1 << VBUS_INTERRUPT) | (1 << ROOT_PORT_RESET_INTERRUPT); - mask = (1 << USB_HIGH_SPEED) | (1 << USB_FULL_SPEED); - - if (stat & tmp) { - net2272_write(dev, IRQSTAT1, tmp); - if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) && - ((net2272_read(dev, USBCTL1) & mask) == 0)) - || ((net2272_read(dev, USBCTL1) & (1 << VBUS_PIN)) - == 0)) - && (dev->gadget.speed != USB_SPEED_UNKNOWN)) { - dev_dbg(dev->dev, "disconnect %s\n", - dev->driver->driver.name); - stop_activity(dev, dev->driver); - net2272_ep0_start(dev); - return; - } - stat &= ~tmp; - - if (!stat) - return; - } - - tmp = (1 << SUSPEND_REQUEST_CHANGE_INTERRUPT); - if (stat & tmp) { - net2272_write(dev, IRQSTAT1, tmp); - if (stat & (1 << SUSPEND_REQUEST_INTERRUPT)) { - if (dev->driver->suspend) - dev->driver->suspend(&dev->gadget); - if (!enable_suspend) { - stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT); - dev_dbg(dev->dev, "Suspend disabled, ignoring\n"); - } - } else { - if (dev->driver->resume) - dev->driver->resume(&dev->gadget); - } - stat &= ~tmp; - } - - /* clear any other status/irqs */ - if (stat) - net2272_write(dev, IRQSTAT1, stat); - - /* some status we can just ignore */ - stat &= ~((1 << CONTROL_STATUS_INTERRUPT) - | (1 << SUSPEND_REQUEST_INTERRUPT) - | (1 << RESUME_INTERRUPT)); - if (!stat) - return; - else - dev_dbg(dev->dev, "unhandled irqstat1 %02x\n", stat); -} - -static irqreturn_t net2272_irq(int irq, void *_dev) -{ - struct net2272 *dev = _dev; -#if defined(PLX_PCI_RDK) || defined(PLX_PCI_RDK2) - u32 intcsr; -#endif -#if defined(PLX_PCI_RDK) - u8 dmareq; -#endif - spin_lock(&dev->lock); -#if defined(PLX_PCI_RDK) - intcsr = readl(dev->rdk1.plx9054_base_addr + INTCSR); - - if ((intcsr & LOCAL_INTERRUPT_TEST) == LOCAL_INTERRUPT_TEST) { - writel(intcsr & ~(1 << PCI_INTERRUPT_ENABLE), - dev->rdk1.plx9054_base_addr + INTCSR); - net2272_handle_stat1_irqs(dev, net2272_read(dev, IRQSTAT1)); - net2272_handle_stat0_irqs(dev, net2272_read(dev, IRQSTAT0)); - intcsr = readl(dev->rdk1.plx9054_base_addr + INTCSR); - writel(intcsr | (1 << PCI_INTERRUPT_ENABLE), - dev->rdk1.plx9054_base_addr + INTCSR); - } - if ((intcsr & DMA_CHANNEL_0_TEST) == DMA_CHANNEL_0_TEST) { - writeb((1 << CHANNEL_CLEAR_INTERRUPT | (0 << CHANNEL_ENABLE)), - dev->rdk1.plx9054_base_addr + DMACSR0); - - dmareq = net2272_read(dev, DMAREQ); - if (dmareq & 0x01) - net2272_handle_dma(&dev->ep[2]); - else - net2272_handle_dma(&dev->ep[1]); - } -#endif -#if defined(PLX_PCI_RDK2) - /* see if PCI int for us by checking irqstat */ - intcsr = readl(dev->rdk2.fpga_base_addr + RDK2_IRQSTAT); - if (!intcsr & (1 << NET2272_PCI_IRQ)) - return IRQ_NONE; - /* check dma interrupts */ -#endif - /* Platform/devcice interrupt handler */ -#if !defined(PLX_PCI_RDK) - net2272_handle_stat1_irqs(dev, net2272_read(dev, IRQSTAT1)); - net2272_handle_stat0_irqs(dev, net2272_read(dev, IRQSTAT0)); -#endif - spin_unlock(&dev->lock); - - return IRQ_HANDLED; -} - -static int net2272_present(struct net2272 *dev) -{ - /* - * Quick test to see if CPU can communicate properly with the NET2272. - * Verifies connection using writes and reads to write/read and - * read-only registers. - * - * This routine is strongly recommended especially during early bring-up - * of new hardware, however for designs that do not apply Power On System - * Tests (POST) it may discarded (or perhaps minimized). - */ - unsigned int ii; - u8 val, refval; - - /* Verify NET2272 write/read SCRATCH register can write and read */ - refval = net2272_read(dev, SCRATCH); - for (ii = 0; ii < 0x100; ii += 7) { - net2272_write(dev, SCRATCH, ii); - val = net2272_read(dev, SCRATCH); - if (val != ii) { - dev_dbg(dev->dev, - "%s: write/read SCRATCH register test failed: " - "wrote:0x%2.2x, read:0x%2.2x\n", - __func__, ii, val); - return -EINVAL; - } - } - /* To be nice, we write the original SCRATCH value back: */ - net2272_write(dev, SCRATCH, refval); - - /* Verify NET2272 CHIPREV register is read-only: */ - refval = net2272_read(dev, CHIPREV_2272); - for (ii = 0; ii < 0x100; ii += 7) { - net2272_write(dev, CHIPREV_2272, ii); - val = net2272_read(dev, CHIPREV_2272); - if (val != refval) { - dev_dbg(dev->dev, - "%s: write/read CHIPREV register test failed: " - "wrote 0x%2.2x, read:0x%2.2x expected:0x%2.2x\n", - __func__, ii, val, refval); - return -EINVAL; - } - } - - /* - * Verify NET2272's "NET2270 legacy revision" register - * - NET2272 has two revision registers. The NET2270 legacy revision - * register should read the same value, regardless of the NET2272 - * silicon revision. The legacy register applies to NET2270 - * firmware being applied to the NET2272. - */ - val = net2272_read(dev, CHIPREV_LEGACY); - if (val != NET2270_LEGACY_REV) { - /* - * Unexpected legacy revision value - * - Perhaps the chip is a NET2270? - */ - dev_dbg(dev->dev, - "%s: WARNING: UNEXPECTED NET2272 LEGACY REGISTER VALUE:\n" - " - CHIPREV_LEGACY: expected 0x%2.2x, got:0x%2.2x. (Not NET2272?)\n", - __func__, NET2270_LEGACY_REV, val); - return -EINVAL; - } - - /* - * Verify NET2272 silicon revision - * - This revision register is appropriate for the silicon version - * of the NET2272 - */ - val = net2272_read(dev, CHIPREV_2272); - switch (val) { - case CHIPREV_NET2272_R1: - /* - * NET2272 Rev 1 has DMA related errata: - * - Newer silicon (Rev 1A or better) required - */ - dev_dbg(dev->dev, - "%s: Rev 1 detected: newer silicon recommended for DMA support\n", - __func__); - break; - case CHIPREV_NET2272_R1A: - break; - default: - /* NET2272 silicon version *may* not work with this firmware */ - dev_dbg(dev->dev, - "%s: unexpected silicon revision register value: " - " CHIPREV_2272: 0x%2.2x\n", - __func__, val); - /* - * Return Success, even though the chip rev is not an expected value - * - Older, pre-built firmware can attempt to operate on newer silicon - * - Often, new silicon is perfectly compatible - */ - } - - /* Success: NET2272 checks out OK */ - return 0; -} - -static void -net2272_gadget_release(struct device *_dev) -{ - struct net2272 *dev = dev_get_drvdata(_dev); - kfree(dev); -} - -/*---------------------------------------------------------------------------*/ - -static void __devexit -net2272_remove(struct net2272 *dev) -{ - usb_del_gadget_udc(&dev->gadget); - - /* start with the driver above us */ - if (dev->driver) { - /* should have been done already by driver model core */ - dev_warn(dev->dev, "pci remove, driver '%s' is still registered\n", - dev->driver->driver.name); - usb_gadget_unregister_driver(dev->driver); - } - - free_irq(dev->irq, dev); - iounmap(dev->base_addr); - - device_unregister(&dev->gadget.dev); - device_remove_file(dev->dev, &dev_attr_registers); - - dev_info(dev->dev, "unbind\n"); -} - -static struct net2272 * __devinit -net2272_probe_init(struct device *dev, unsigned int irq) -{ - struct net2272 *ret; - - if (!irq) { - dev_dbg(dev, "No IRQ!\n"); - return ERR_PTR(-ENODEV); - } - - /* alloc, and start init */ - ret = kzalloc(sizeof(*ret), GFP_KERNEL); - if (!ret) - return ERR_PTR(-ENOMEM); - - spin_lock_init(&ret->lock); - ret->irq = irq; - ret->dev = dev; - ret->gadget.ops = &net2272_ops; - ret->gadget.max_speed = USB_SPEED_HIGH; - - /* the "gadget" abstracts/virtualizes the controller */ - dev_set_name(&ret->gadget.dev, "gadget"); - ret->gadget.dev.parent = dev; - ret->gadget.dev.dma_mask = dev->dma_mask; - ret->gadget.dev.release = net2272_gadget_release; - ret->gadget.name = driver_name; - - return ret; -} - -static int __devinit -net2272_probe_fin(struct net2272 *dev, unsigned int irqflags) -{ - int ret; - - /* See if there... */ - if (net2272_present(dev)) { - dev_warn(dev->dev, "2272 not found!\n"); - ret = -ENODEV; - goto err; - } - - net2272_usb_reset(dev); - net2272_usb_reinit(dev); - - ret = request_irq(dev->irq, net2272_irq, irqflags, driver_name, dev); - if (ret) { - dev_err(dev->dev, "request interrupt %i failed\n", dev->irq); - goto err; - } - - dev->chiprev = net2272_read(dev, CHIPREV_2272); - - /* done */ - dev_info(dev->dev, "%s\n", driver_desc); - dev_info(dev->dev, "irq %i, mem %p, chip rev %04x, dma %s\n", - dev->irq, dev->base_addr, dev->chiprev, - dma_mode_string()); - dev_info(dev->dev, "version: %s\n", driver_vers); - - ret = device_register(&dev->gadget.dev); - if (ret) - goto err_irq; - ret = device_create_file(dev->dev, &dev_attr_registers); - if (ret) - goto err_dev_reg; - - ret = usb_add_gadget_udc(dev->dev, &dev->gadget); - if (ret) - goto err_add_udc; - - return 0; - -err_add_udc: - device_remove_file(dev->dev, &dev_attr_registers); - err_dev_reg: - device_unregister(&dev->gadget.dev); - err_irq: - free_irq(dev->irq, dev); - err: - return ret; -} - -#ifdef CONFIG_PCI - -/* - * wrap this driver around the specified device, but - * don't respond over USB until a gadget driver binds to us - */ - -static int __devinit -net2272_rdk1_probe(struct pci_dev *pdev, struct net2272 *dev) -{ - unsigned long resource, len, tmp; - void __iomem *mem_mapped_addr[4]; - int ret, i; - - /* - * BAR 0 holds PLX 9054 config registers - * BAR 1 is i/o memory; unused here - * BAR 2 holds EPLD config registers - * BAR 3 holds NET2272 registers - */ - - /* Find and map all address spaces */ - for (i = 0; i < 4; ++i) { - if (i == 1) - continue; /* BAR1 unused */ - - resource = pci_resource_start(pdev, i); - len = pci_resource_len(pdev, i); - - if (!request_mem_region(resource, len, driver_name)) { - dev_dbg(dev->dev, "controller already in use\n"); - ret = -EBUSY; - goto err; - } - - mem_mapped_addr[i] = ioremap_nocache(resource, len); - if (mem_mapped_addr[i] == NULL) { - release_mem_region(resource, len); - dev_dbg(dev->dev, "can't map memory\n"); - ret = -EFAULT; - goto err; - } - } - - dev->rdk1.plx9054_base_addr = mem_mapped_addr[0]; - dev->rdk1.epld_base_addr = mem_mapped_addr[2]; - dev->base_addr = mem_mapped_addr[3]; - - /* Set PLX 9054 bus width (16 bits) */ - tmp = readl(dev->rdk1.plx9054_base_addr + LBRD1); - writel((tmp & ~(3 << MEMORY_SPACE_LOCAL_BUS_WIDTH)) | W16_BIT, - dev->rdk1.plx9054_base_addr + LBRD1); - - /* Enable PLX 9054 Interrupts */ - writel(readl(dev->rdk1.plx9054_base_addr + INTCSR) | - (1 << PCI_INTERRUPT_ENABLE) | - (1 << LOCAL_INTERRUPT_INPUT_ENABLE), - dev->rdk1.plx9054_base_addr + INTCSR); - - writeb((1 << CHANNEL_CLEAR_INTERRUPT | (0 << CHANNEL_ENABLE)), - dev->rdk1.plx9054_base_addr + DMACSR0); - - /* reset */ - writeb((1 << EPLD_DMA_ENABLE) | - (1 << DMA_CTL_DACK) | - (1 << DMA_TIMEOUT_ENABLE) | - (1 << USER) | - (0 << MPX_MODE) | - (1 << BUSWIDTH) | - (1 << NET2272_RESET), - dev->base_addr + EPLD_IO_CONTROL_REGISTER); - - mb(); - writeb(readb(dev->base_addr + EPLD_IO_CONTROL_REGISTER) & - ~(1 << NET2272_RESET), - dev->base_addr + EPLD_IO_CONTROL_REGISTER); - udelay(200); - - return 0; - - err: - while (--i >= 0) { - iounmap(mem_mapped_addr[i]); - release_mem_region(pci_resource_start(pdev, i), - pci_resource_len(pdev, i)); - } - - return ret; -} - -static int __devinit -net2272_rdk2_probe(struct pci_dev *pdev, struct net2272 *dev) -{ - unsigned long resource, len; - void __iomem *mem_mapped_addr[2]; - int ret, i; - - /* - * BAR 0 holds FGPA config registers - * BAR 1 holds NET2272 registers - */ - - /* Find and map all address spaces, bar2-3 unused in rdk 2 */ - for (i = 0; i < 2; ++i) { - resource = pci_resource_start(pdev, i); - len = pci_resource_len(pdev, i); - - if (!request_mem_region(resource, len, driver_name)) { - dev_dbg(dev->dev, "controller already in use\n"); - ret = -EBUSY; - goto err; - } - - mem_mapped_addr[i] = ioremap_nocache(resource, len); - if (mem_mapped_addr[i] == NULL) { - release_mem_region(resource, len); - dev_dbg(dev->dev, "can't map memory\n"); - ret = -EFAULT; - goto err; - } - } - - dev->rdk2.fpga_base_addr = mem_mapped_addr[0]; - dev->base_addr = mem_mapped_addr[1]; - - mb(); - /* Set 2272 bus width (16 bits) and reset */ - writel((1 << CHIP_RESET), dev->rdk2.fpga_base_addr + RDK2_LOCCTLRDK); - udelay(200); - writel((1 << BUS_WIDTH), dev->rdk2.fpga_base_addr + RDK2_LOCCTLRDK); - /* Print fpga version number */ - dev_info(dev->dev, "RDK2 FPGA version %08x\n", - readl(dev->rdk2.fpga_base_addr + RDK2_FPGAREV)); - /* Enable FPGA Interrupts */ - writel((1 << NET2272_PCI_IRQ), dev->rdk2.fpga_base_addr + RDK2_IRQENB); - - return 0; - - err: - while (--i >= 0) { - iounmap(mem_mapped_addr[i]); - release_mem_region(pci_resource_start(pdev, i), - pci_resource_len(pdev, i)); - } - - return ret; -} - -static int __devinit -net2272_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - struct net2272 *dev; - int ret; - - dev = net2272_probe_init(&pdev->dev, pdev->irq); - if (IS_ERR(dev)) - return PTR_ERR(dev); - dev->dev_id = pdev->device; - - if (pci_enable_device(pdev) < 0) { - ret = -ENODEV; - goto err_free; - } - - pci_set_master(pdev); - - switch (pdev->device) { - case PCI_DEVICE_ID_RDK1: ret = net2272_rdk1_probe(pdev, dev); break; - case PCI_DEVICE_ID_RDK2: ret = net2272_rdk2_probe(pdev, dev); break; - default: BUG(); - } - if (ret) - goto err_pci; - - ret = net2272_probe_fin(dev, 0); - if (ret) - goto err_pci; - - pci_set_drvdata(pdev, dev); - - return 0; - - err_pci: - pci_disable_device(pdev); - err_free: - kfree(dev); - - return ret; -} - -static void __devexit -net2272_rdk1_remove(struct pci_dev *pdev, struct net2272 *dev) -{ - int i; - - /* disable PLX 9054 interrupts */ - writel(readl(dev->rdk1.plx9054_base_addr + INTCSR) & - ~(1 << PCI_INTERRUPT_ENABLE), - dev->rdk1.plx9054_base_addr + INTCSR); - - /* clean up resources allocated during probe() */ - iounmap(dev->rdk1.plx9054_base_addr); - iounmap(dev->rdk1.epld_base_addr); - - for (i = 0; i < 4; ++i) { - if (i == 1) - continue; /* BAR1 unused */ - release_mem_region(pci_resource_start(pdev, i), - pci_resource_len(pdev, i)); - } -} - -static void __devexit -net2272_rdk2_remove(struct pci_dev *pdev, struct net2272 *dev) -{ - int i; - - /* disable fpga interrupts - writel(readl(dev->rdk1.plx9054_base_addr + INTCSR) & - ~(1 << PCI_INTERRUPT_ENABLE), - dev->rdk1.plx9054_base_addr + INTCSR); - */ - - /* clean up resources allocated during probe() */ - iounmap(dev->rdk2.fpga_base_addr); - - for (i = 0; i < 2; ++i) - release_mem_region(pci_resource_start(pdev, i), - pci_resource_len(pdev, i)); -} - -static void __devexit -net2272_pci_remove(struct pci_dev *pdev) -{ - struct net2272 *dev = pci_get_drvdata(pdev); - - net2272_remove(dev); - - switch (pdev->device) { - case PCI_DEVICE_ID_RDK1: net2272_rdk1_remove(pdev, dev); break; - case PCI_DEVICE_ID_RDK2: net2272_rdk2_remove(pdev, dev); break; - default: BUG(); - } - - pci_disable_device(pdev); - - kfree(dev); -} - -/* Table of matching PCI IDs */ -static struct pci_device_id __devinitdata pci_ids[] = { - { /* RDK 1 card */ - .class = ((PCI_CLASS_BRIDGE_OTHER << 8) | 0xfe), - .class_mask = 0, - .vendor = PCI_VENDOR_ID_PLX, - .device = PCI_DEVICE_ID_RDK1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { /* RDK 2 card */ - .class = ((PCI_CLASS_BRIDGE_OTHER << 8) | 0xfe), - .class_mask = 0, - .vendor = PCI_VENDOR_ID_PLX, - .device = PCI_DEVICE_ID_RDK2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { } -}; -MODULE_DEVICE_TABLE(pci, pci_ids); - -static struct pci_driver net2272_pci_driver = { - .name = driver_name, - .id_table = pci_ids, - - .probe = net2272_pci_probe, - .remove = __devexit_p(net2272_pci_remove), -}; - -static int net2272_pci_register(void) -{ - return pci_register_driver(&net2272_pci_driver); -} - -static void net2272_pci_unregister(void) -{ - pci_unregister_driver(&net2272_pci_driver); -} - -#else -static inline int net2272_pci_register(void) { return 0; } -static inline void net2272_pci_unregister(void) { } -#endif - -/*---------------------------------------------------------------------------*/ - -static int __devinit -net2272_plat_probe(struct platform_device *pdev) -{ - struct net2272 *dev; - int ret; - unsigned int irqflags; - resource_size_t base, len; - struct resource *iomem, *iomem_bus, *irq_res; - - irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - iomem_bus = platform_get_resource(pdev, IORESOURCE_BUS, 0); - if (!irq_res || !iomem) { - dev_err(&pdev->dev, "must provide irq/base addr"); - return -EINVAL; - } - - dev = net2272_probe_init(&pdev->dev, irq_res->start); - if (IS_ERR(dev)) - return PTR_ERR(dev); - - irqflags = 0; - if (irq_res->flags & IORESOURCE_IRQ_HIGHEDGE) - irqflags |= IRQF_TRIGGER_RISING; - if (irq_res->flags & IORESOURCE_IRQ_LOWEDGE) - irqflags |= IRQF_TRIGGER_FALLING; - if (irq_res->flags & IORESOURCE_IRQ_HIGHLEVEL) - irqflags |= IRQF_TRIGGER_HIGH; - if (irq_res->flags & IORESOURCE_IRQ_LOWLEVEL) - irqflags |= IRQF_TRIGGER_LOW; - - base = iomem->start; - len = resource_size(iomem); - if (iomem_bus) - dev->base_shift = iomem_bus->start; - - if (!request_mem_region(base, len, driver_name)) { - dev_dbg(dev->dev, "get request memory region!\n"); - ret = -EBUSY; - goto err; - } - dev->base_addr = ioremap_nocache(base, len); - if (!dev->base_addr) { - dev_dbg(dev->dev, "can't map memory\n"); - ret = -EFAULT; - goto err_req; - } - - ret = net2272_probe_fin(dev, IRQF_TRIGGER_LOW); - if (ret) - goto err_io; - - platform_set_drvdata(pdev, dev); - dev_info(&pdev->dev, "running in 16-bit, %sbyte swap local bus mode\n", - (net2272_read(dev, LOCCTL) & (1 << BYTE_SWAP)) ? "" : "no "); - - return 0; - - err_io: - iounmap(dev->base_addr); - err_req: - release_mem_region(base, len); - err: - return ret; -} - -static int __devexit -net2272_plat_remove(struct platform_device *pdev) -{ - struct net2272 *dev = platform_get_drvdata(pdev); - - net2272_remove(dev); - - release_mem_region(pdev->resource[0].start, - resource_size(&pdev->resource[0])); - - kfree(dev); - - return 0; -} - -static struct platform_driver net2272_plat_driver = { - .probe = net2272_plat_probe, - .remove = __devexit_p(net2272_plat_remove), - .driver = { - .name = driver_name, - .owner = THIS_MODULE, - }, - /* FIXME .suspend, .resume */ -}; -MODULE_ALIAS("platform:net2272"); - -static int __init net2272_init(void) -{ - int ret; - - ret = net2272_pci_register(); - if (ret) - return ret; - ret = platform_driver_register(&net2272_plat_driver); - if (ret) - goto err_pci; - return ret; - -err_pci: - net2272_pci_unregister(); - return ret; -} -module_init(net2272_init); - -static void __exit net2272_cleanup(void) -{ - net2272_pci_unregister(); - platform_driver_unregister(&net2272_plat_driver); -} -module_exit(net2272_cleanup); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("PLX Technology, Inc."); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/net2272.h b/ANDROID_3.4.5/drivers/usb/gadget/net2272.h deleted file mode 100644 index e5950578..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/net2272.h +++ /dev/null @@ -1,601 +0,0 @@ -/* - * PLX NET2272 high/full speed USB device controller - * - * Copyright (C) 2005-2006 PLX Technology, Inc. - * Copyright (C) 2006-2011 Analog Devices, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __NET2272_H__ -#define __NET2272_H__ - -/* Main Registers */ -#define REGADDRPTR 0x00 -#define REGDATA 0x01 -#define IRQSTAT0 0x02 -#define ENDPOINT_0_INTERRUPT 0 -#define ENDPOINT_A_INTERRUPT 1 -#define ENDPOINT_B_INTERRUPT 2 -#define ENDPOINT_C_INTERRUPT 3 -#define VIRTUALIZED_ENDPOINT_INTERRUPT 4 -#define SETUP_PACKET_INTERRUPT 5 -#define DMA_DONE_INTERRUPT 6 -#define SOF_INTERRUPT 7 -#define IRQSTAT1 0x03 -#define CONTROL_STATUS_INTERRUPT 1 -#define VBUS_INTERRUPT 2 -#define SUSPEND_REQUEST_INTERRUPT 3 -#define SUSPEND_REQUEST_CHANGE_INTERRUPT 4 -#define RESUME_INTERRUPT 5 -#define ROOT_PORT_RESET_INTERRUPT 6 -#define RESET_STATUS 7 -#define PAGESEL 0x04 -#define DMAREQ 0x1c -#define DMA_ENDPOINT_SELECT 0 -#define DREQ_POLARITY 1 -#define DACK_POLARITY 2 -#define EOT_POLARITY 3 -#define DMA_CONTROL_DACK 4 -#define DMA_REQUEST_ENABLE 5 -#define DMA_REQUEST 6 -#define DMA_BUFFER_VALID 7 -#define SCRATCH 0x1d -#define IRQENB0 0x20 -#define ENDPOINT_0_INTERRUPT_ENABLE 0 -#define ENDPOINT_A_INTERRUPT_ENABLE 1 -#define ENDPOINT_B_INTERRUPT_ENABLE 2 -#define ENDPOINT_C_INTERRUPT_ENABLE 3 -#define VIRTUALIZED_ENDPOINT_INTERRUPT_ENABLE 4 -#define SETUP_PACKET_INTERRUPT_ENABLE 5 -#define DMA_DONE_INTERRUPT_ENABLE 6 -#define SOF_INTERRUPT_ENABLE 7 -#define IRQENB1 0x21 -#define VBUS_INTERRUPT_ENABLE 2 -#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 -#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 4 -#define RESUME_INTERRUPT_ENABLE 5 -#define ROOT_PORT_RESET_INTERRUPT_ENABLE 6 -#define LOCCTL 0x22 -#define DATA_WIDTH 0 -#define LOCAL_CLOCK_OUTPUT 1 -#define LOCAL_CLOCK_OUTPUT_OFF 0 -#define LOCAL_CLOCK_OUTPUT_3_75MHZ 1 -#define LOCAL_CLOCK_OUTPUT_7_5MHZ 2 -#define LOCAL_CLOCK_OUTPUT_15MHZ 3 -#define LOCAL_CLOCK_OUTPUT_30MHZ 4 -#define LOCAL_CLOCK_OUTPUT_60MHZ 5 -#define DMA_SPLIT_BUS_MODE 4 -#define BYTE_SWAP 5 -#define BUFFER_CONFIGURATION 6 -#define BUFFER_CONFIGURATION_EPA512_EPB512 0 -#define BUFFER_CONFIGURATION_EPA1024_EPB512 1 -#define BUFFER_CONFIGURATION_EPA1024_EPB1024 2 -#define BUFFER_CONFIGURATION_EPA1024DB 3 -#define CHIPREV_LEGACY 0x23 -#define NET2270_LEGACY_REV 0x40 -#define LOCCTL1 0x24 -#define DMA_MODE 0 -#define SLOW_DREQ 0 -#define FAST_DREQ 1 -#define BURST_MODE 2 -#define DMA_DACK_ENABLE 2 -#define CHIPREV_2272 0x25 -#define CHIPREV_NET2272_R1 0x10 -#define CHIPREV_NET2272_R1A 0x11 -/* USB Registers */ -#define USBCTL0 0x18 -#define IO_WAKEUP_ENABLE 1 -#define USB_DETECT_ENABLE 3 -#define USB_ROOT_PORT_WAKEUP_ENABLE 5 -#define USBCTL1 0x19 -#define VBUS_PIN 0 -#define USB_FULL_SPEED 1 -#define USB_HIGH_SPEED 2 -#define GENERATE_RESUME 3 -#define VIRTUAL_ENDPOINT_ENABLE 4 -#define FRAME0 0x1a -#define FRAME1 0x1b -#define OURADDR 0x30 -#define FORCE_IMMEDIATE 7 -#define USBDIAG 0x31 -#define FORCE_TRANSMIT_CRC_ERROR 0 -#define PREVENT_TRANSMIT_BIT_STUFF 1 -#define FORCE_RECEIVE_ERROR 2 -#define FAST_TIMES 4 -#define USBTEST 0x32 -#define TEST_MODE_SELECT 0 -#define NORMAL_OPERATION 0 -#define TEST_J 1 -#define TEST_K 2 -#define TEST_SE0_NAK 3 -#define TEST_PACKET 4 -#define TEST_FORCE_ENABLE 5 -#define XCVRDIAG 0x33 -#define FORCE_FULL_SPEED 2 -#define FORCE_HIGH_SPEED 3 -#define OPMODE 4 -#define NORMAL_OPERATION 0 -#define NON_DRIVING 1 -#define DISABLE_BITSTUFF_AND_NRZI_ENCODE 2 -#define LINESTATE 6 -#define SE0_STATE 0 -#define J_STATE 1 -#define K_STATE 2 -#define SE1_STATE 3 -#define VIRTOUT0 0x34 -#define VIRTOUT1 0x35 -#define VIRTIN0 0x36 -#define VIRTIN1 0x37 -#define SETUP0 0x40 -#define SETUP1 0x41 -#define SETUP2 0x42 -#define SETUP3 0x43 -#define SETUP4 0x44 -#define SETUP5 0x45 -#define SETUP6 0x46 -#define SETUP7 0x47 -/* Endpoint Registers (Paged via PAGESEL) */ -#define EP_DATA 0x05 -#define EP_STAT0 0x06 -#define DATA_IN_TOKEN_INTERRUPT 0 -#define DATA_OUT_TOKEN_INTERRUPT 1 -#define DATA_PACKET_TRANSMITTED_INTERRUPT 2 -#define DATA_PACKET_RECEIVED_INTERRUPT 3 -#define SHORT_PACKET_TRANSFERRED_INTERRUPT 4 -#define NAK_OUT_PACKETS 5 -#define BUFFER_EMPTY 6 -#define BUFFER_FULL 7 -#define EP_STAT1 0x07 -#define TIMEOUT 0 -#define USB_OUT_ACK_SENT 1 -#define USB_OUT_NAK_SENT 2 -#define USB_IN_ACK_RCVD 3 -#define USB_IN_NAK_SENT 4 -#define USB_STALL_SENT 5 -#define LOCAL_OUT_ZLP 6 -#define BUFFER_FLUSH 7 -#define EP_TRANSFER0 0x08 -#define EP_TRANSFER1 0x09 -#define EP_TRANSFER2 0x0a -#define EP_IRQENB 0x0b -#define DATA_IN_TOKEN_INTERRUPT_ENABLE 0 -#define DATA_OUT_TOKEN_INTERRUPT_ENABLE 1 -#define DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE 2 -#define DATA_PACKET_RECEIVED_INTERRUPT_ENABLE 3 -#define SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE 4 -#define EP_AVAIL0 0x0c -#define EP_AVAIL1 0x0d -#define EP_RSPCLR 0x0e -#define EP_RSPSET 0x0f -#define ENDPOINT_HALT 0 -#define ENDPOINT_TOGGLE 1 -#define NAK_OUT_PACKETS_MODE 2 -#define CONTROL_STATUS_PHASE_HANDSHAKE 3 -#define INTERRUPT_MODE 4 -#define AUTOVALIDATE 5 -#define HIDE_STATUS_PHASE 6 -#define ALT_NAK_OUT_PACKETS 7 -#define EP_MAXPKT0 0x28 -#define EP_MAXPKT1 0x29 -#define ADDITIONAL_TRANSACTION_OPPORTUNITIES 3 -#define NONE_ADDITIONAL_TRANSACTION 0 -#define ONE_ADDITIONAL_TRANSACTION 1 -#define TWO_ADDITIONAL_TRANSACTION 2 -#define EP_CFG 0x2a -#define ENDPOINT_NUMBER 0 -#define ENDPOINT_DIRECTION 4 -#define ENDPOINT_TYPE 5 -#define ENDPOINT_ENABLE 7 -#define EP_HBW 0x2b -#define HIGH_BANDWIDTH_OUT_TRANSACTION_PID 0 -#define DATA0_PID 0 -#define DATA1_PID 1 -#define DATA2_PID 2 -#define MDATA_PID 3 -#define EP_BUFF_STATES 0x2c -#define BUFFER_A_STATE 0 -#define BUFFER_B_STATE 2 -#define BUFF_FREE 0 -#define BUFF_VALID 1 -#define BUFF_LCL 2 -#define BUFF_USB 3 - -/*---------------------------------------------------------------------------*/ - -#define PCI_DEVICE_ID_RDK1 0x9054 - -/* PCI-RDK EPLD Registers */ -#define RDK_EPLD_IO_REGISTER1 0x00000000 -#define RDK_EPLD_USB_RESET 0 -#define RDK_EPLD_USB_POWERDOWN 1 -#define RDK_EPLD_USB_WAKEUP 2 -#define RDK_EPLD_USB_EOT 3 -#define RDK_EPLD_DPPULL 4 -#define RDK_EPLD_IO_REGISTER2 0x00000004 -#define RDK_EPLD_BUSWIDTH 0 -#define RDK_EPLD_USER 2 -#define RDK_EPLD_RESET_INTERRUPT_ENABLE 3 -#define RDK_EPLD_DMA_TIMEOUT_ENABLE 4 -#define RDK_EPLD_STATUS_REGISTER 0x00000008 -#define RDK_EPLD_USB_LRESET 0 -#define RDK_EPLD_REVISION_REGISTER 0x0000000c - -/* PCI-RDK PLX 9054 Registers */ -#define INTCSR 0x68 -#define PCI_INTERRUPT_ENABLE 8 -#define LOCAL_INTERRUPT_INPUT_ENABLE 11 -#define LOCAL_INPUT_INTERRUPT_ACTIVE 15 -#define LOCAL_DMA_CHANNEL_0_INTERRUPT_ENABLE 18 -#define LOCAL_DMA_CHANNEL_1_INTERRUPT_ENABLE 19 -#define DMA_CHANNEL_0_INTERRUPT_ACTIVE 21 -#define DMA_CHANNEL_1_INTERRUPT_ACTIVE 22 -#define CNTRL 0x6C -#define RELOAD_CONFIGURATION_REGISTERS 29 -#define PCI_ADAPTER_SOFTWARE_RESET 30 -#define DMAMODE0 0x80 -#define LOCAL_BUS_WIDTH 0 -#define INTERNAL_WAIT_STATES 2 -#define TA_READY_INPUT_ENABLE 6 -#define LOCAL_BURST_ENABLE 8 -#define SCATTER_GATHER_MODE 9 -#define DONE_INTERRUPT_ENABLE 10 -#define LOCAL_ADDRESSING_MODE 11 -#define DEMAND_MODE 12 -#define DMA_EOT_ENABLE 14 -#define FAST_SLOW_TERMINATE_MODE_SELECT 15 -#define DMA_CHANNEL_INTERRUPT_SELECT 17 -#define DMAPADR0 0x84 -#define DMALADR0 0x88 -#define DMASIZ0 0x8c -#define DMADPR0 0x90 -#define DESCRIPTOR_LOCATION 0 -#define END_OF_CHAIN 1 -#define INTERRUPT_AFTER_TERMINAL_COUNT 2 -#define DIRECTION_OF_TRANSFER 3 -#define DMACSR0 0xa8 -#define CHANNEL_ENABLE 0 -#define CHANNEL_START 1 -#define CHANNEL_ABORT 2 -#define CHANNEL_CLEAR_INTERRUPT 3 -#define CHANNEL_DONE 4 -#define DMATHR 0xb0 -#define LBRD1 0xf8 -#define MEMORY_SPACE_LOCAL_BUS_WIDTH 0 -#define W8_BIT 0 -#define W16_BIT 1 - -/* Special OR'ing of INTCSR bits */ -#define LOCAL_INTERRUPT_TEST \ - ((1 << LOCAL_INPUT_INTERRUPT_ACTIVE) | \ - (1 << LOCAL_INTERRUPT_INPUT_ENABLE)) - -#define DMA_CHANNEL_0_TEST \ - ((1 << DMA_CHANNEL_0_INTERRUPT_ACTIVE) | \ - (1 << LOCAL_DMA_CHANNEL_0_INTERRUPT_ENABLE)) - -#define DMA_CHANNEL_1_TEST \ - ((1 << DMA_CHANNEL_1_INTERRUPT_ACTIVE) | \ - (1 << LOCAL_DMA_CHANNEL_1_INTERRUPT_ENABLE)) - -/* EPLD Registers */ -#define RDK_EPLD_IO_REGISTER1 0x00000000 -#define RDK_EPLD_USB_RESET 0 -#define RDK_EPLD_USB_POWERDOWN 1 -#define RDK_EPLD_USB_WAKEUP 2 -#define RDK_EPLD_USB_EOT 3 -#define RDK_EPLD_DPPULL 4 -#define RDK_EPLD_IO_REGISTER2 0x00000004 -#define RDK_EPLD_BUSWIDTH 0 -#define RDK_EPLD_USER 2 -#define RDK_EPLD_RESET_INTERRUPT_ENABLE 3 -#define RDK_EPLD_DMA_TIMEOUT_ENABLE 4 -#define RDK_EPLD_STATUS_REGISTER 0x00000008 -#define RDK_EPLD_USB_LRESET 0 -#define RDK_EPLD_REVISION_REGISTER 0x0000000c - -#define EPLD_IO_CONTROL_REGISTER 0x400 -#define NET2272_RESET 0 -#define BUSWIDTH 1 -#define MPX_MODE 3 -#define USER 4 -#define DMA_TIMEOUT_ENABLE 5 -#define DMA_CTL_DACK 6 -#define EPLD_DMA_ENABLE 7 -#define EPLD_DMA_CONTROL_REGISTER 0x800 -#define SPLIT_DMA_MODE 0 -#define SPLIT_DMA_DIRECTION 1 -#define SPLIT_DMA_ENABLE 2 -#define SPLIT_DMA_INTERRUPT_ENABLE 3 -#define SPLIT_DMA_INTERRUPT 4 -#define EPLD_DMA_MODE 5 -#define EPLD_DMA_CONTROLLER_ENABLE 7 -#define SPLIT_DMA_ADDRESS_LOW 0xc00 -#define SPLIT_DMA_ADDRESS_HIGH 0x1000 -#define SPLIT_DMA_BYTE_COUNT_LOW 0x1400 -#define SPLIT_DMA_BYTE_COUNT_HIGH 0x1800 -#define EPLD_REVISION_REGISTER 0x1c00 -#define SPLIT_DMA_RAM 0x4000 -#define DMA_RAM_SIZE 0x1000 - -/*---------------------------------------------------------------------------*/ - -#define PCI_DEVICE_ID_RDK2 0x3272 - -/* PCI-RDK version 2 registers */ - -/* Main Control Registers */ - -#define RDK2_IRQENB 0x00 -#define RDK2_IRQSTAT 0x04 -#define PB7 23 -#define PB6 22 -#define PB5 21 -#define PB4 20 -#define PB3 19 -#define PB2 18 -#define PB1 17 -#define PB0 16 -#define GP3 23 -#define GP2 23 -#define GP1 23 -#define GP0 23 -#define DMA_RETRY_ABORT 6 -#define DMA_PAUSE_DONE 5 -#define DMA_ABORT_DONE 4 -#define DMA_OUT_FIFO_TRANSFER_DONE 3 -#define DMA_LOCAL_DONE 2 -#define DMA_PCI_DONE 1 -#define NET2272_PCI_IRQ 0 - -#define RDK2_LOCCTLRDK 0x08 -#define CHIP_RESET 3 -#define SPLIT_DMA 2 -#define MULTIPLEX_MODE 1 -#define BUS_WIDTH 0 - -#define RDK2_GPIOCTL 0x10 -#define GP3_OUT_ENABLE 7 -#define GP2_OUT_ENABLE 6 -#define GP1_OUT_ENABLE 5 -#define GP0_OUT_ENABLE 4 -#define GP3_DATA 3 -#define GP2_DATA 2 -#define GP1_DATA 1 -#define GP0_DATA 0 - -#define RDK2_LEDSW 0x14 -#define LED3 27 -#define LED2 26 -#define LED1 25 -#define LED0 24 -#define PBUTTON 16 -#define DIPSW 0 - -#define RDK2_DIAG 0x18 -#define RDK2_FAST_TIMES 2 -#define FORCE_PCI_SERR 1 -#define FORCE_PCI_INT 0 -#define RDK2_FPGAREV 0x1C - -/* Dma Control registers */ -#define RDK2_DMACTL 0x80 -#define ADDR_HOLD 24 -#define RETRY_COUNT 16 /* 23:16 */ -#define FIFO_THRESHOLD 11 /* 15:11 */ -#define MEM_WRITE_INVALIDATE 10 -#define READ_MULTIPLE 9 -#define READ_LINE 8 -#define RDK2_DMA_MODE 6 /* 7:6 */ -#define CONTROL_DACK 5 -#define EOT_ENABLE 4 -#define EOT_POLARITY 3 -#define DACK_POLARITY 2 -#define DREQ_POLARITY 1 -#define DMA_ENABLE 0 - -#define RDK2_DMASTAT 0x84 -#define GATHER_COUNT 12 /* 14:12 */ -#define FIFO_COUNT 6 /* 11:6 */ -#define FIFO_FLUSH 5 -#define FIFO_TRANSFER 4 -#define PAUSE_DONE 3 -#define ABORT_DONE 2 -#define DMA_ABORT 1 -#define DMA_START 0 - -#define RDK2_DMAPCICOUNT 0x88 -#define DMA_DIRECTION 31 -#define DMA_PCI_BYTE_COUNT 0 /* 0:23 */ - -#define RDK2_DMALOCCOUNT 0x8C /* 0:23 dma local byte count */ - -#define RDK2_DMAADDR 0x90 /* 2:31 PCI bus starting address */ - -/*---------------------------------------------------------------------------*/ - -#define REG_INDEXED_THRESHOLD (1 << 5) - -/* DRIVER DATA STRUCTURES and UTILITIES */ -struct net2272_ep { - struct usb_ep ep; - struct net2272 *dev; - unsigned long irqs; - - /* analogous to a host-side qh */ - struct list_head queue; - const struct usb_endpoint_descriptor *desc; - unsigned num:8, - fifo_size:12, - stopped:1, - wedged:1, - is_in:1, - is_iso:1, - dma:1, - not_empty:1; -}; - -struct net2272 { - /* each device provides one gadget, several endpoints */ - struct usb_gadget gadget; - struct device *dev; - unsigned short dev_id; - - spinlock_t lock; - struct net2272_ep ep[4]; - struct usb_gadget_driver *driver; - unsigned protocol_stall:1, - softconnect:1, - is_selfpowered:1, - wakeup:1, - dma_eot_polarity:1, - dma_dack_polarity:1, - dma_dreq_polarity:1, - dma_busy:1; - u16 chiprev; - u8 pagesel; - - unsigned int irq; - unsigned short fifo_mode; - - unsigned int base_shift; - u16 __iomem *base_addr; - union { -#ifdef CONFIG_PCI - struct { - void __iomem *plx9054_base_addr; - void __iomem *epld_base_addr; - } rdk1; - struct { - /* Bar0, Bar1 is base_addr both mem-mapped */ - void __iomem *fpga_base_addr; - } rdk2; -#endif - }; -}; - -static void __iomem * -net2272_reg_addr(struct net2272 *dev, unsigned int reg) -{ - return dev->base_addr + (reg << dev->base_shift); -} - -static void -net2272_write(struct net2272 *dev, unsigned int reg, u8 value) -{ - if (reg >= REG_INDEXED_THRESHOLD) { - /* - * Indexed register; use REGADDRPTR/REGDATA - * - Save and restore REGADDRPTR. This prevents REGADDRPTR from - * changes between other code sections, but it is time consuming. - * - Performance tips: either do not save and restore REGADDRPTR (if it - * is safe) or do save/restore operations only in critical sections. - u8 tmp = readb(dev->base_addr + REGADDRPTR); - */ - writeb((u8)reg, net2272_reg_addr(dev, REGADDRPTR)); - writeb(value, net2272_reg_addr(dev, REGDATA)); - /* writeb(tmp, net2272_reg_addr(dev, REGADDRPTR)); */ - } else - writeb(value, net2272_reg_addr(dev, reg)); -} - -static u8 -net2272_read(struct net2272 *dev, unsigned int reg) -{ - u8 ret; - - if (reg >= REG_INDEXED_THRESHOLD) { - /* - * Indexed register; use REGADDRPTR/REGDATA - * - Save and restore REGADDRPTR. This prevents REGADDRPTR from - * changes between other code sections, but it is time consuming. - * - Performance tips: either do not save and restore REGADDRPTR (if it - * is safe) or do save/restore operations only in critical sections. - u8 tmp = readb(dev->base_addr + REGADDRPTR); - */ - writeb((u8)reg, net2272_reg_addr(dev, REGADDRPTR)); - ret = readb(net2272_reg_addr(dev, REGDATA)); - /* writeb(tmp, net2272_reg_addr(dev, REGADDRPTR)); */ - } else - ret = readb(net2272_reg_addr(dev, reg)); - - return ret; -} - -static void -net2272_ep_write(struct net2272_ep *ep, unsigned int reg, u8 value) -{ - struct net2272 *dev = ep->dev; - - if (dev->pagesel != ep->num) { - net2272_write(dev, PAGESEL, ep->num); - dev->pagesel = ep->num; - } - net2272_write(dev, reg, value); -} - -static u8 -net2272_ep_read(struct net2272_ep *ep, unsigned int reg) -{ - struct net2272 *dev = ep->dev; - - if (dev->pagesel != ep->num) { - net2272_write(dev, PAGESEL, ep->num); - dev->pagesel = ep->num; - } - return net2272_read(dev, reg); -} - -static void allow_status(struct net2272_ep *ep) -{ - /* ep0 only */ - net2272_ep_write(ep, EP_RSPCLR, - (1 << CONTROL_STATUS_PHASE_HANDSHAKE) | - (1 << ALT_NAK_OUT_PACKETS) | - (1 << NAK_OUT_PACKETS_MODE)); - ep->stopped = 1; -} - -static void set_halt(struct net2272_ep *ep) -{ - /* ep0 and bulk/intr endpoints */ - net2272_ep_write(ep, EP_RSPCLR, 1 << CONTROL_STATUS_PHASE_HANDSHAKE); - net2272_ep_write(ep, EP_RSPSET, 1 << ENDPOINT_HALT); -} - -static void clear_halt(struct net2272_ep *ep) -{ - /* ep0 and bulk/intr endpoints */ - net2272_ep_write(ep, EP_RSPCLR, - (1 << ENDPOINT_HALT) | (1 << ENDPOINT_TOGGLE)); -} - -/* count (<= 4) bytes in the next fifo write will be valid */ -static void set_fifo_bytecount(struct net2272_ep *ep, unsigned count) -{ - /* net2272_ep_write will truncate to u8 for us */ - net2272_ep_write(ep, EP_TRANSFER2, count >> 16); - net2272_ep_write(ep, EP_TRANSFER1, count >> 8); - net2272_ep_write(ep, EP_TRANSFER0, count); -} - -struct net2272_request { - struct usb_request req; - struct list_head queue; - unsigned mapped:1, - valid:1; -}; - -#endif diff --git a/ANDROID_3.4.5/drivers/usb/gadget/net2280.c b/ANDROID_3.4.5/drivers/usb/gadget/net2280.c deleted file mode 100644 index ac335af1..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/net2280.c +++ /dev/null @@ -1,2896 +0,0 @@ -/* - * Driver for the PLX NET2280 USB device controller. - * Specs and errata are available from . - * - * PLX Technology Inc. (formerly NetChip Technology) supported the - * development of this driver. - * - * - * CODE STATUS HIGHLIGHTS - * - * This driver should work well with most "gadget" drivers, including - * the File Storage, Serial, and Ethernet/RNDIS gadget drivers - * as well as Gadget Zero and Gadgetfs. - * - * DMA is enabled by default. Drivers using transfer queues might use - * DMA chaining to remove IRQ latencies between transfers. (Except when - * short OUT transfers happen.) Drivers can use the req->no_interrupt - * hint to completely eliminate some IRQs, if a later IRQ is guaranteed - * and DMA chaining is enabled. - * - * Note that almost all the errata workarounds here are only needed for - * rev1 chips. Rev1a silicon (0110) fixes almost all of them. - */ - -/* - * Copyright (C) 2003 David Brownell - * Copyright (C) 2003-2005 PLX Technology, Inc. - * - * Modified Seth Levy 2005 PLX Technology, Inc. to provide compatibility - * with 2282 chip - * - * 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. - */ - -#undef DEBUG /* messages on error and most fault paths */ -#undef VERBOSE /* extra debug messages (success too) */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - - -#define DRIVER_DESC "PLX NET228x USB Peripheral Controller" -#define DRIVER_VERSION "2005 Sept 27" - -#define DMA_ADDR_INVALID (~(dma_addr_t)0) -#define EP_DONTUSE 13 /* nonzero */ - -#define USE_RDK_LEDS /* GPIO pins control three LEDs */ - - -static const char driver_name [] = "net2280"; -static const char driver_desc [] = DRIVER_DESC; - -static const char ep0name [] = "ep0"; -static const char *const ep_name [] = { - ep0name, - "ep-a", "ep-b", "ep-c", "ep-d", - "ep-e", "ep-f", -}; - -/* use_dma -- general goodness, fewer interrupts, less cpu load (vs PIO) - * use_dma_chaining -- dma descriptor queueing gives even more irq reduction - * - * The net2280 DMA engines are not tightly integrated with their FIFOs; - * not all cases are (yet) handled well in this driver or the silicon. - * Some gadget drivers work better with the dma support here than others. - * These two parameters let you use PIO or more aggressive DMA. - */ -static bool use_dma = 1; -static bool use_dma_chaining = 0; - -/* "modprobe net2280 use_dma=n" etc */ -module_param (use_dma, bool, S_IRUGO); -module_param (use_dma_chaining, bool, S_IRUGO); - - -/* mode 0 == ep-{a,b,c,d} 1K fifo each - * mode 1 == ep-{a,b} 2K fifo each, ep-{c,d} unavailable - * mode 2 == ep-a 2K fifo, ep-{b,c} 1K each, ep-d unavailable - */ -static ushort fifo_mode = 0; - -/* "modprobe net2280 fifo_mode=1" etc */ -module_param (fifo_mode, ushort, 0644); - -/* enable_suspend -- When enabled, the driver will respond to - * USB suspend requests by powering down the NET2280. Otherwise, - * USB suspend requests will be ignored. This is acceptable for - * self-powered devices - */ -static bool enable_suspend = 0; - -/* "modprobe net2280 enable_suspend=1" etc */ -module_param (enable_suspend, bool, S_IRUGO); - - -#define DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out") - -#if defined(CONFIG_USB_GADGET_DEBUG_FILES) || defined (DEBUG) -static char *type_string (u8 bmAttributes) -{ - switch ((bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK) { - case USB_ENDPOINT_XFER_BULK: return "bulk"; - case USB_ENDPOINT_XFER_ISOC: return "iso"; - case USB_ENDPOINT_XFER_INT: return "intr"; - }; - return "control"; -} -#endif - -#include "net2280.h" - -#define valid_bit cpu_to_le32 (1 << VALID_BIT) -#define dma_done_ie cpu_to_le32 (1 << DMA_DONE_INTERRUPT_ENABLE) - -/*-------------------------------------------------------------------------*/ - -static int -net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) -{ - struct net2280 *dev; - struct net2280_ep *ep; - u32 max, tmp; - unsigned long flags; - - ep = container_of (_ep, struct net2280_ep, ep); - if (!_ep || !desc || ep->desc || _ep->name == ep0name - || desc->bDescriptorType != USB_DT_ENDPOINT) - return -EINVAL; - dev = ep->dev; - if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - /* erratum 0119 workaround ties up an endpoint number */ - if ((desc->bEndpointAddress & 0x0f) == EP_DONTUSE) - return -EDOM; - - /* sanity check ep-e/ep-f since their fifos are small */ - max = usb_endpoint_maxp (desc) & 0x1fff; - if (ep->num > 4 && max > 64) - return -ERANGE; - - spin_lock_irqsave (&dev->lock, flags); - _ep->maxpacket = max & 0x7ff; - ep->desc = desc; - - /* ep_reset() has already been called */ - ep->stopped = 0; - ep->wedged = 0; - ep->out_overflow = 0; - - /* set speed-dependent max packet; may kick in high bandwidth */ - set_idx_reg (dev->regs, REG_EP_MAXPKT (dev, ep->num), max); - - /* FIFO lines can't go to different packets. PIO is ok, so - * use it instead of troublesome (non-bulk) multi-packet DMA. - */ - if (ep->dma && (max % 4) != 0 && use_dma_chaining) { - DEBUG (ep->dev, "%s, no dma for maxpacket %d\n", - ep->ep.name, ep->ep.maxpacket); - ep->dma = NULL; - } - - /* set type, direction, address; reset fifo counters */ - writel ((1 << FIFO_FLUSH), &ep->regs->ep_stat); - tmp = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); - if (tmp == USB_ENDPOINT_XFER_INT) { - /* erratum 0105 workaround prevents hs NYET */ - if (dev->chiprev == 0100 - && dev->gadget.speed == USB_SPEED_HIGH - && !(desc->bEndpointAddress & USB_DIR_IN)) - writel ((1 << CLEAR_NAK_OUT_PACKETS_MODE), - &ep->regs->ep_rsp); - } else if (tmp == USB_ENDPOINT_XFER_BULK) { - /* catch some particularly blatant driver bugs */ - if ((dev->gadget.speed == USB_SPEED_HIGH - && max != 512) - || (dev->gadget.speed == USB_SPEED_FULL - && max > 64)) { - spin_unlock_irqrestore (&dev->lock, flags); - return -ERANGE; - } - } - ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC) ? 1 : 0; - tmp <<= ENDPOINT_TYPE; - tmp |= desc->bEndpointAddress; - tmp |= (4 << ENDPOINT_BYTE_COUNT); /* default full fifo lines */ - tmp |= 1 << ENDPOINT_ENABLE; - wmb (); - - /* for OUT transfers, block the rx fifo until a read is posted */ - ep->is_in = (tmp & USB_DIR_IN) != 0; - if (!ep->is_in) - writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp); - else if (dev->pdev->device != 0x2280) { - /* Added for 2282, Don't use nak packets on an in endpoint, - * this was ignored on 2280 - */ - writel ((1 << CLEAR_NAK_OUT_PACKETS) - | (1 << CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp); - } - - writel (tmp, &ep->regs->ep_cfg); - - /* enable irqs */ - if (!ep->dma) { /* pio, per-packet */ - tmp = (1 << ep->num) | readl (&dev->regs->pciirqenb0); - writel (tmp, &dev->regs->pciirqenb0); - - tmp = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE) - | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE); - if (dev->pdev->device == 0x2280) - tmp |= readl (&ep->regs->ep_irqenb); - writel (tmp, &ep->regs->ep_irqenb); - } else { /* dma, per-request */ - tmp = (1 << (8 + ep->num)); /* completion */ - tmp |= readl (&dev->regs->pciirqenb1); - writel (tmp, &dev->regs->pciirqenb1); - - /* for short OUT transfers, dma completions can't - * advance the queue; do it pio-style, by hand. - * NOTE erratum 0112 workaround #2 - */ - if ((desc->bEndpointAddress & USB_DIR_IN) == 0) { - tmp = (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE); - writel (tmp, &ep->regs->ep_irqenb); - - tmp = (1 << ep->num) | readl (&dev->regs->pciirqenb0); - writel (tmp, &dev->regs->pciirqenb0); - } - } - - tmp = desc->bEndpointAddress; - DEBUG (dev, "enabled %s (ep%d%s-%s) %s max %04x\n", - _ep->name, tmp & 0x0f, DIR_STRING (tmp), - type_string (desc->bmAttributes), - ep->dma ? "dma" : "pio", max); - - /* pci writes may still be posted */ - spin_unlock_irqrestore (&dev->lock, flags); - return 0; -} - -static int handshake (u32 __iomem *ptr, u32 mask, u32 done, int usec) -{ - u32 result; - - do { - result = readl (ptr); - if (result == ~(u32)0) /* "device unplugged" */ - return -ENODEV; - result &= mask; - if (result == done) - return 0; - udelay (1); - usec--; - } while (usec > 0); - return -ETIMEDOUT; -} - -static const struct usb_ep_ops net2280_ep_ops; - -static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep) -{ - u32 tmp; - - ep->desc = NULL; - INIT_LIST_HEAD (&ep->queue); - - ep->ep.maxpacket = ~0; - ep->ep.ops = &net2280_ep_ops; - - /* disable the dma, irqs, endpoint... */ - if (ep->dma) { - writel (0, &ep->dma->dmactl); - writel ( (1 << DMA_SCATTER_GATHER_DONE_INTERRUPT) - | (1 << DMA_TRANSACTION_DONE_INTERRUPT) - | (1 << DMA_ABORT) - , &ep->dma->dmastat); - - tmp = readl (®s->pciirqenb0); - tmp &= ~(1 << ep->num); - writel (tmp, ®s->pciirqenb0); - } else { - tmp = readl (®s->pciirqenb1); - tmp &= ~(1 << (8 + ep->num)); /* completion */ - writel (tmp, ®s->pciirqenb1); - } - writel (0, &ep->regs->ep_irqenb); - - /* init to our chosen defaults, notably so that we NAK OUT - * packets until the driver queues a read (+note erratum 0112) - */ - if (!ep->is_in || ep->dev->pdev->device == 0x2280) { - tmp = (1 << SET_NAK_OUT_PACKETS_MODE) - | (1 << SET_NAK_OUT_PACKETS) - | (1 << CLEAR_EP_HIDE_STATUS_PHASE) - | (1 << CLEAR_INTERRUPT_MODE); - } else { - /* added for 2282 */ - tmp = (1 << CLEAR_NAK_OUT_PACKETS_MODE) - | (1 << CLEAR_NAK_OUT_PACKETS) - | (1 << CLEAR_EP_HIDE_STATUS_PHASE) - | (1 << CLEAR_INTERRUPT_MODE); - } - - if (ep->num != 0) { - tmp |= (1 << CLEAR_ENDPOINT_TOGGLE) - | (1 << CLEAR_ENDPOINT_HALT); - } - writel (tmp, &ep->regs->ep_rsp); - - /* scrub most status bits, and flush any fifo state */ - if (ep->dev->pdev->device == 0x2280) - tmp = (1 << FIFO_OVERFLOW) - | (1 << FIFO_UNDERFLOW); - else - tmp = 0; - - writel (tmp | (1 << TIMEOUT) - | (1 << USB_STALL_SENT) - | (1 << USB_IN_NAK_SENT) - | (1 << USB_IN_ACK_RCVD) - | (1 << USB_OUT_PING_NAK_SENT) - | (1 << USB_OUT_ACK_SENT) - | (1 << FIFO_FLUSH) - | (1 << SHORT_PACKET_OUT_DONE_INTERRUPT) - | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT) - | (1 << DATA_PACKET_RECEIVED_INTERRUPT) - | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT) - | (1 << DATA_OUT_PING_TOKEN_INTERRUPT) - | (1 << DATA_IN_TOKEN_INTERRUPT) - , &ep->regs->ep_stat); - - /* fifo size is handled separately */ -} - -static void nuke (struct net2280_ep *); - -static int net2280_disable (struct usb_ep *_ep) -{ - struct net2280_ep *ep; - unsigned long flags; - - ep = container_of (_ep, struct net2280_ep, ep); - if (!_ep || !ep->desc || _ep->name == ep0name) - return -EINVAL; - - spin_lock_irqsave (&ep->dev->lock, flags); - nuke (ep); - ep_reset (ep->dev->regs, ep); - - VDEBUG (ep->dev, "disabled %s %s\n", - ep->dma ? "dma" : "pio", _ep->name); - - /* synch memory views with the device */ - (void) readl (&ep->regs->ep_cfg); - - if (use_dma && !ep->dma && ep->num >= 1 && ep->num <= 4) - ep->dma = &ep->dev->dma [ep->num - 1]; - - spin_unlock_irqrestore (&ep->dev->lock, flags); - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static struct usb_request * -net2280_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags) -{ - struct net2280_ep *ep; - struct net2280_request *req; - - if (!_ep) - return NULL; - ep = container_of (_ep, struct net2280_ep, ep); - - req = kzalloc(sizeof(*req), gfp_flags); - if (!req) - return NULL; - - req->req.dma = DMA_ADDR_INVALID; - INIT_LIST_HEAD (&req->queue); - - /* this dma descriptor may be swapped with the previous dummy */ - if (ep->dma) { - struct net2280_dma *td; - - td = pci_pool_alloc (ep->dev->requests, gfp_flags, - &req->td_dma); - if (!td) { - kfree (req); - return NULL; - } - td->dmacount = 0; /* not VALID */ - td->dmaaddr = cpu_to_le32 (DMA_ADDR_INVALID); - td->dmadesc = td->dmaaddr; - req->td = td; - } - return &req->req; -} - -static void -net2280_free_request (struct usb_ep *_ep, struct usb_request *_req) -{ - struct net2280_ep *ep; - struct net2280_request *req; - - ep = container_of (_ep, struct net2280_ep, ep); - if (!_ep || !_req) - return; - - req = container_of (_req, struct net2280_request, req); - WARN_ON (!list_empty (&req->queue)); - if (req->td) - pci_pool_free (ep->dev->requests, req->td, req->td_dma); - kfree (req); -} - -/*-------------------------------------------------------------------------*/ - -/* load a packet into the fifo we use for usb IN transfers. - * works for all endpoints. - * - * NOTE: pio with ep-a..ep-d could stuff multiple packets into the fifo - * at a time, but this code is simpler because it knows it only writes - * one packet. ep-a..ep-d should use dma instead. - */ -static void -write_fifo (struct net2280_ep *ep, struct usb_request *req) -{ - struct net2280_ep_regs __iomem *regs = ep->regs; - u8 *buf; - u32 tmp; - unsigned count, total; - - /* INVARIANT: fifo is currently empty. (testable) */ - - if (req) { - buf = req->buf + req->actual; - prefetch (buf); - total = req->length - req->actual; - } else { - total = 0; - buf = NULL; - } - - /* write just one packet at a time */ - count = ep->ep.maxpacket; - if (count > total) /* min() cannot be used on a bitfield */ - count = total; - - VDEBUG (ep->dev, "write %s fifo (IN) %d bytes%s req %p\n", - ep->ep.name, count, - (count != ep->ep.maxpacket) ? " (short)" : "", - req); - while (count >= 4) { - /* NOTE be careful if you try to align these. fifo lines - * should normally be full (4 bytes) and successive partial - * lines are ok only in certain cases. - */ - tmp = get_unaligned ((u32 *)buf); - cpu_to_le32s (&tmp); - writel (tmp, ®s->ep_data); - buf += 4; - count -= 4; - } - - /* last fifo entry is "short" unless we wrote a full packet. - * also explicitly validate last word in (periodic) transfers - * when maxpacket is not a multiple of 4 bytes. - */ - if (count || total < ep->ep.maxpacket) { - tmp = count ? get_unaligned ((u32 *)buf) : count; - cpu_to_le32s (&tmp); - set_fifo_bytecount (ep, count & 0x03); - writel (tmp, ®s->ep_data); - } - - /* pci writes may still be posted */ -} - -/* work around erratum 0106: PCI and USB race over the OUT fifo. - * caller guarantees chiprev 0100, out endpoint is NAKing, and - * there's no real data in the fifo. - * - * NOTE: also used in cases where that erratum doesn't apply: - * where the host wrote "too much" data to us. - */ -static void out_flush (struct net2280_ep *ep) -{ - u32 __iomem *statp; - u32 tmp; - - ASSERT_OUT_NAKING (ep); - - statp = &ep->regs->ep_stat; - writel ( (1 << DATA_OUT_PING_TOKEN_INTERRUPT) - | (1 << DATA_PACKET_RECEIVED_INTERRUPT) - , statp); - writel ((1 << FIFO_FLUSH), statp); - mb (); - tmp = readl (statp); - if (tmp & (1 << DATA_OUT_PING_TOKEN_INTERRUPT) - /* high speed did bulk NYET; fifo isn't filling */ - && ep->dev->gadget.speed == USB_SPEED_FULL) { - unsigned usec; - - usec = 50; /* 64 byte bulk/interrupt */ - handshake (statp, (1 << USB_OUT_PING_NAK_SENT), - (1 << USB_OUT_PING_NAK_SENT), usec); - /* NAK done; now CLEAR_NAK_OUT_PACKETS is safe */ - } -} - -/* unload packet(s) from the fifo we use for usb OUT transfers. - * returns true iff the request completed, because of short packet - * or the request buffer having filled with full packets. - * - * for ep-a..ep-d this will read multiple packets out when they - * have been accepted. - */ -static int -read_fifo (struct net2280_ep *ep, struct net2280_request *req) -{ - struct net2280_ep_regs __iomem *regs = ep->regs; - u8 *buf = req->req.buf + req->req.actual; - unsigned count, tmp, is_short; - unsigned cleanup = 0, prevent = 0; - - /* erratum 0106 ... packets coming in during fifo reads might - * be incompletely rejected. not all cases have workarounds. - */ - if (ep->dev->chiprev == 0x0100 - && ep->dev->gadget.speed == USB_SPEED_FULL) { - udelay (1); - tmp = readl (&ep->regs->ep_stat); - if ((tmp & (1 << NAK_OUT_PACKETS))) - cleanup = 1; - else if ((tmp & (1 << FIFO_FULL))) { - start_out_naking (ep); - prevent = 1; - } - /* else: hope we don't see the problem */ - } - - /* never overflow the rx buffer. the fifo reads packets until - * it sees a short one; we might not be ready for them all. - */ - prefetchw (buf); - count = readl (®s->ep_avail); - if (unlikely (count == 0)) { - udelay (1); - tmp = readl (&ep->regs->ep_stat); - count = readl (®s->ep_avail); - /* handled that data already? */ - if (count == 0 && (tmp & (1 << NAK_OUT_PACKETS)) == 0) - return 0; - } - - tmp = req->req.length - req->req.actual; - if (count > tmp) { - /* as with DMA, data overflow gets flushed */ - if ((tmp % ep->ep.maxpacket) != 0) { - ERROR (ep->dev, - "%s out fifo %d bytes, expected %d\n", - ep->ep.name, count, tmp); - req->req.status = -EOVERFLOW; - cleanup = 1; - /* NAK_OUT_PACKETS will be set, so flushing is safe; - * the next read will start with the next packet - */ - } /* else it's a ZLP, no worries */ - count = tmp; - } - req->req.actual += count; - - is_short = (count == 0) || ((count % ep->ep.maxpacket) != 0); - - VDEBUG (ep->dev, "read %s fifo (OUT) %d bytes%s%s%s req %p %d/%d\n", - ep->ep.name, count, is_short ? " (short)" : "", - cleanup ? " flush" : "", prevent ? " nak" : "", - req, req->req.actual, req->req.length); - - while (count >= 4) { - tmp = readl (®s->ep_data); - cpu_to_le32s (&tmp); - put_unaligned (tmp, (u32 *)buf); - buf += 4; - count -= 4; - } - if (count) { - tmp = readl (®s->ep_data); - /* LE conversion is implicit here: */ - do { - *buf++ = (u8) tmp; - tmp >>= 8; - } while (--count); - } - if (cleanup) - out_flush (ep); - if (prevent) { - writel ((1 << CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp); - (void) readl (&ep->regs->ep_rsp); - } - - return is_short || ((req->req.actual == req->req.length) - && !req->req.zero); -} - -/* fill out dma descriptor to match a given request */ -static void -fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid) -{ - struct net2280_dma *td = req->td; - u32 dmacount = req->req.length; - - /* don't let DMA continue after a short OUT packet, - * so overruns can't affect the next transfer. - * in case of overruns on max-size packets, we can't - * stop the fifo from filling but we can flush it. - */ - if (ep->is_in) - dmacount |= (1 << DMA_DIRECTION); - if ((!ep->is_in && (dmacount % ep->ep.maxpacket) != 0) - || ep->dev->pdev->device != 0x2280) - dmacount |= (1 << END_OF_CHAIN); - - req->valid = valid; - if (valid) - dmacount |= (1 << VALID_BIT); - if (likely(!req->req.no_interrupt || !use_dma_chaining)) - dmacount |= (1 << DMA_DONE_INTERRUPT_ENABLE); - - /* td->dmadesc = previously set by caller */ - td->dmaaddr = cpu_to_le32 (req->req.dma); - - /* 2280 may be polling VALID_BIT through ep->dma->dmadesc */ - wmb (); - td->dmacount = cpu_to_le32(dmacount); -} - -static const u32 dmactl_default = - (1 << DMA_SCATTER_GATHER_DONE_INTERRUPT) - | (1 << DMA_CLEAR_COUNT_ENABLE) - /* erratum 0116 workaround part 1 (use POLLING) */ - | (POLL_100_USEC << DESCRIPTOR_POLLING_RATE) - | (1 << DMA_VALID_BIT_POLLING_ENABLE) - | (1 << DMA_VALID_BIT_ENABLE) - | (1 << DMA_SCATTER_GATHER_ENABLE) - /* erratum 0116 workaround part 2 (no AUTOSTART) */ - | (1 << DMA_ENABLE); - -static inline void spin_stop_dma (struct net2280_dma_regs __iomem *dma) -{ - handshake (&dma->dmactl, (1 << DMA_ENABLE), 0, 50); -} - -static inline void stop_dma (struct net2280_dma_regs __iomem *dma) -{ - writel (readl (&dma->dmactl) & ~(1 << DMA_ENABLE), &dma->dmactl); - spin_stop_dma (dma); -} - -static void start_queue (struct net2280_ep *ep, u32 dmactl, u32 td_dma) -{ - struct net2280_dma_regs __iomem *dma = ep->dma; - unsigned int tmp = (1 << VALID_BIT) | (ep->is_in << DMA_DIRECTION); - - if (ep->dev->pdev->device != 0x2280) - tmp |= (1 << END_OF_CHAIN); - - writel (tmp, &dma->dmacount); - writel (readl (&dma->dmastat), &dma->dmastat); - - writel (td_dma, &dma->dmadesc); - writel (dmactl, &dma->dmactl); - - /* erratum 0116 workaround part 3: pci arbiter away from net2280 */ - (void) readl (&ep->dev->pci->pcimstctl); - - writel ((1 << DMA_START), &dma->dmastat); - - if (!ep->is_in) - stop_out_naking (ep); -} - -static void start_dma (struct net2280_ep *ep, struct net2280_request *req) -{ - u32 tmp; - struct net2280_dma_regs __iomem *dma = ep->dma; - - /* FIXME can't use DMA for ZLPs */ - - /* on this path we "know" there's no dma active (yet) */ - WARN_ON (readl (&dma->dmactl) & (1 << DMA_ENABLE)); - writel (0, &ep->dma->dmactl); - - /* previous OUT packet might have been short */ - if (!ep->is_in && ((tmp = readl (&ep->regs->ep_stat)) - & (1 << NAK_OUT_PACKETS)) != 0) { - writel ((1 << SHORT_PACKET_TRANSFERRED_INTERRUPT), - &ep->regs->ep_stat); - - tmp = readl (&ep->regs->ep_avail); - if (tmp) { - writel (readl (&dma->dmastat), &dma->dmastat); - - /* transfer all/some fifo data */ - writel (req->req.dma, &dma->dmaaddr); - tmp = min (tmp, req->req.length); - - /* dma irq, faking scatterlist status */ - req->td->dmacount = cpu_to_le32 (req->req.length - tmp); - writel ((1 << DMA_DONE_INTERRUPT_ENABLE) - | tmp, &dma->dmacount); - req->td->dmadesc = 0; - req->valid = 1; - - writel ((1 << DMA_ENABLE), &dma->dmactl); - writel ((1 << DMA_START), &dma->dmastat); - return; - } - } - - tmp = dmactl_default; - - /* force packet boundaries between dma requests, but prevent the - * controller from automagically writing a last "short" packet - * (zero length) unless the driver explicitly said to do that. - */ - if (ep->is_in) { - if (likely ((req->req.length % ep->ep.maxpacket) != 0 - || req->req.zero)) { - tmp |= (1 << DMA_FIFO_VALIDATE); - ep->in_fifo_validate = 1; - } else - ep->in_fifo_validate = 0; - } - - /* init req->td, pointing to the current dummy */ - req->td->dmadesc = cpu_to_le32 (ep->td_dma); - fill_dma_desc (ep, req, 1); - - if (!use_dma_chaining) - req->td->dmacount |= cpu_to_le32 (1 << END_OF_CHAIN); - - start_queue (ep, tmp, req->td_dma); -} - -static inline void -queue_dma (struct net2280_ep *ep, struct net2280_request *req, int valid) -{ - struct net2280_dma *end; - dma_addr_t tmp; - - /* swap new dummy for old, link; fill and maybe activate */ - end = ep->dummy; - ep->dummy = req->td; - req->td = end; - - tmp = ep->td_dma; - ep->td_dma = req->td_dma; - req->td_dma = tmp; - - end->dmadesc = cpu_to_le32 (ep->td_dma); - - fill_dma_desc (ep, req, valid); -} - -static void -done (struct net2280_ep *ep, struct net2280_request *req, int status) -{ - struct net2280 *dev; - unsigned stopped = ep->stopped; - - list_del_init (&req->queue); - - if (req->req.status == -EINPROGRESS) - req->req.status = status; - else - status = req->req.status; - - dev = ep->dev; - if (ep->dma) - usb_gadget_unmap_request(&dev->gadget, &req->req, ep->is_in); - - if (status && status != -ESHUTDOWN) - VDEBUG (dev, "complete %s req %p stat %d len %u/%u\n", - ep->ep.name, &req->req, status, - req->req.actual, req->req.length); - - /* don't modify queue heads during completion callback */ - ep->stopped = 1; - spin_unlock (&dev->lock); - req->req.complete (&ep->ep, &req->req); - spin_lock (&dev->lock); - ep->stopped = stopped; -} - -/*-------------------------------------------------------------------------*/ - -static int -net2280_queue (struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) -{ - struct net2280_request *req; - struct net2280_ep *ep; - struct net2280 *dev; - unsigned long flags; - - /* we always require a cpu-view buffer, so that we can - * always use pio (as fallback or whatever). - */ - req = container_of (_req, struct net2280_request, req); - if (!_req || !_req->complete || !_req->buf - || !list_empty (&req->queue)) - return -EINVAL; - if (_req->length > (~0 & DMA_BYTE_COUNT_MASK)) - return -EDOM; - ep = container_of (_ep, struct net2280_ep, ep); - if (!_ep || (!ep->desc && ep->num != 0)) - return -EINVAL; - dev = ep->dev; - if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - /* FIXME implement PIO fallback for ZLPs with DMA */ - if (ep->dma && _req->length == 0) - return -EOPNOTSUPP; - - /* set up dma mapping in case the caller didn't */ - if (ep->dma) { - int ret; - - ret = usb_gadget_map_request(&dev->gadget, _req, - ep->is_in); - if (ret) - return ret; - } - -#if 0 - VDEBUG (dev, "%s queue req %p, len %d buf %p\n", - _ep->name, _req, _req->length, _req->buf); -#endif - - spin_lock_irqsave (&dev->lock, flags); - - _req->status = -EINPROGRESS; - _req->actual = 0; - - /* kickstart this i/o queue? */ - if (list_empty (&ep->queue) && !ep->stopped) { - /* use DMA if the endpoint supports it, else pio */ - if (ep->dma) - start_dma (ep, req); - else { - /* maybe there's no control data, just status ack */ - if (ep->num == 0 && _req->length == 0) { - allow_status (ep); - done (ep, req, 0); - VDEBUG (dev, "%s status ack\n", ep->ep.name); - goto done; - } - - /* PIO ... stuff the fifo, or unblock it. */ - if (ep->is_in) - write_fifo (ep, _req); - else if (list_empty (&ep->queue)) { - u32 s; - - /* OUT FIFO might have packet(s) buffered */ - s = readl (&ep->regs->ep_stat); - if ((s & (1 << FIFO_EMPTY)) == 0) { - /* note: _req->short_not_ok is - * ignored here since PIO _always_ - * stops queue advance here, and - * _req->status doesn't change for - * short reads (only _req->actual) - */ - if (read_fifo (ep, req)) { - done (ep, req, 0); - if (ep->num == 0) - allow_status (ep); - /* don't queue it */ - req = NULL; - } else - s = readl (&ep->regs->ep_stat); - } - - /* don't NAK, let the fifo fill */ - if (req && (s & (1 << NAK_OUT_PACKETS))) - writel ((1 << CLEAR_NAK_OUT_PACKETS), - &ep->regs->ep_rsp); - } - } - - } else if (ep->dma) { - int valid = 1; - - if (ep->is_in) { - int expect; - - /* preventing magic zlps is per-engine state, not - * per-transfer; irq logic must recover hiccups. - */ - expect = likely (req->req.zero - || (req->req.length % ep->ep.maxpacket) != 0); - if (expect != ep->in_fifo_validate) - valid = 0; - } - queue_dma (ep, req, valid); - - } /* else the irq handler advances the queue. */ - - ep->responded = 1; - if (req) - list_add_tail (&req->queue, &ep->queue); -done: - spin_unlock_irqrestore (&dev->lock, flags); - - /* pci writes may still be posted */ - return 0; -} - -static inline void -dma_done ( - struct net2280_ep *ep, - struct net2280_request *req, - u32 dmacount, - int status -) -{ - req->req.actual = req->req.length - (DMA_BYTE_COUNT_MASK & dmacount); - done (ep, req, status); -} - -static void restart_dma (struct net2280_ep *ep); - -static void scan_dma_completions (struct net2280_ep *ep) -{ - /* only look at descriptors that were "naturally" retired, - * so fifo and list head state won't matter - */ - while (!list_empty (&ep->queue)) { - struct net2280_request *req; - u32 tmp; - - req = list_entry (ep->queue.next, - struct net2280_request, queue); - if (!req->valid) - break; - rmb (); - tmp = le32_to_cpup (&req->td->dmacount); - if ((tmp & (1 << VALID_BIT)) != 0) - break; - - /* SHORT_PACKET_TRANSFERRED_INTERRUPT handles "usb-short" - * cases where DMA must be aborted; this code handles - * all non-abort DMA completions. - */ - if (unlikely (req->td->dmadesc == 0)) { - /* paranoia */ - tmp = readl (&ep->dma->dmacount); - if (tmp & DMA_BYTE_COUNT_MASK) - break; - /* single transfer mode */ - dma_done (ep, req, tmp, 0); - break; - } else if (!ep->is_in - && (req->req.length % ep->ep.maxpacket) != 0) { - tmp = readl (&ep->regs->ep_stat); - - /* AVOID TROUBLE HERE by not issuing short reads from - * your gadget driver. That helps avoids errata 0121, - * 0122, and 0124; not all cases trigger the warning. - */ - if ((tmp & (1 << NAK_OUT_PACKETS)) == 0) { - WARNING (ep->dev, "%s lost packet sync!\n", - ep->ep.name); - req->req.status = -EOVERFLOW; - } else if ((tmp = readl (&ep->regs->ep_avail)) != 0) { - /* fifo gets flushed later */ - ep->out_overflow = 1; - DEBUG (ep->dev, "%s dma, discard %d len %d\n", - ep->ep.name, tmp, - req->req.length); - req->req.status = -EOVERFLOW; - } - } - dma_done (ep, req, tmp, 0); - } -} - -static void restart_dma (struct net2280_ep *ep) -{ - struct net2280_request *req; - u32 dmactl = dmactl_default; - - if (ep->stopped) - return; - req = list_entry (ep->queue.next, struct net2280_request, queue); - - if (!use_dma_chaining) { - start_dma (ep, req); - return; - } - - /* the 2280 will be processing the queue unless queue hiccups after - * the previous transfer: - * IN: wanted automagic zlp, head doesn't (or vice versa) - * DMA_FIFO_VALIDATE doesn't init from dma descriptors. - * OUT: was "usb-short", we must restart. - */ - if (ep->is_in && !req->valid) { - struct net2280_request *entry, *prev = NULL; - int reqmode, done = 0; - - DEBUG (ep->dev, "%s dma hiccup td %p\n", ep->ep.name, req->td); - ep->in_fifo_validate = likely (req->req.zero - || (req->req.length % ep->ep.maxpacket) != 0); - if (ep->in_fifo_validate) - dmactl |= (1 << DMA_FIFO_VALIDATE); - list_for_each_entry (entry, &ep->queue, queue) { - __le32 dmacount; - - if (entry == req) - continue; - dmacount = entry->td->dmacount; - if (!done) { - reqmode = likely (entry->req.zero - || (entry->req.length - % ep->ep.maxpacket) != 0); - if (reqmode == ep->in_fifo_validate) { - entry->valid = 1; - dmacount |= valid_bit; - entry->td->dmacount = dmacount; - prev = entry; - continue; - } else { - /* force a hiccup */ - prev->td->dmacount |= dma_done_ie; - done = 1; - } - } - - /* walk the rest of the queue so unlinks behave */ - entry->valid = 0; - dmacount &= ~valid_bit; - entry->td->dmacount = dmacount; - prev = entry; - } - } - - writel (0, &ep->dma->dmactl); - start_queue (ep, dmactl, req->td_dma); -} - -static void abort_dma (struct net2280_ep *ep) -{ - /* abort the current transfer */ - if (likely (!list_empty (&ep->queue))) { - /* FIXME work around errata 0121, 0122, 0124 */ - writel ((1 << DMA_ABORT), &ep->dma->dmastat); - spin_stop_dma (ep->dma); - } else - stop_dma (ep->dma); - scan_dma_completions (ep); -} - -/* dequeue ALL requests */ -static void nuke (struct net2280_ep *ep) -{ - struct net2280_request *req; - - /* called with spinlock held */ - ep->stopped = 1; - if (ep->dma) - abort_dma (ep); - while (!list_empty (&ep->queue)) { - req = list_entry (ep->queue.next, - struct net2280_request, - queue); - done (ep, req, -ESHUTDOWN); - } -} - -/* dequeue JUST ONE request */ -static int net2280_dequeue (struct usb_ep *_ep, struct usb_request *_req) -{ - struct net2280_ep *ep; - struct net2280_request *req; - unsigned long flags; - u32 dmactl; - int stopped; - - ep = container_of (_ep, struct net2280_ep, ep); - if (!_ep || (!ep->desc && ep->num != 0) || !_req) - return -EINVAL; - - spin_lock_irqsave (&ep->dev->lock, flags); - stopped = ep->stopped; - - /* quiesce dma while we patch the queue */ - dmactl = 0; - ep->stopped = 1; - if (ep->dma) { - dmactl = readl (&ep->dma->dmactl); - /* WARNING erratum 0127 may kick in ... */ - stop_dma (ep->dma); - scan_dma_completions (ep); - } - - /* make sure it's still queued on this endpoint */ - list_for_each_entry (req, &ep->queue, queue) { - if (&req->req == _req) - break; - } - if (&req->req != _req) { - spin_unlock_irqrestore (&ep->dev->lock, flags); - return -EINVAL; - } - - /* queue head may be partially complete. */ - if (ep->queue.next == &req->queue) { - if (ep->dma) { - DEBUG (ep->dev, "unlink (%s) dma\n", _ep->name); - _req->status = -ECONNRESET; - abort_dma (ep); - if (likely (ep->queue.next == &req->queue)) { - // NOTE: misreports single-transfer mode - req->td->dmacount = 0; /* invalidate */ - dma_done (ep, req, - readl (&ep->dma->dmacount), - -ECONNRESET); - } - } else { - DEBUG (ep->dev, "unlink (%s) pio\n", _ep->name); - done (ep, req, -ECONNRESET); - } - req = NULL; - - /* patch up hardware chaining data */ - } else if (ep->dma && use_dma_chaining) { - if (req->queue.prev == ep->queue.next) { - writel (le32_to_cpu (req->td->dmadesc), - &ep->dma->dmadesc); - if (req->td->dmacount & dma_done_ie) - writel (readl (&ep->dma->dmacount) - | le32_to_cpu(dma_done_ie), - &ep->dma->dmacount); - } else { - struct net2280_request *prev; - - prev = list_entry (req->queue.prev, - struct net2280_request, queue); - prev->td->dmadesc = req->td->dmadesc; - if (req->td->dmacount & dma_done_ie) - prev->td->dmacount |= dma_done_ie; - } - } - - if (req) - done (ep, req, -ECONNRESET); - ep->stopped = stopped; - - if (ep->dma) { - /* turn off dma on inactive queues */ - if (list_empty (&ep->queue)) - stop_dma (ep->dma); - else if (!ep->stopped) { - /* resume current request, or start new one */ - if (req) - writel (dmactl, &ep->dma->dmactl); - else - start_dma (ep, list_entry (ep->queue.next, - struct net2280_request, queue)); - } - } - - spin_unlock_irqrestore (&ep->dev->lock, flags); - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static int net2280_fifo_status (struct usb_ep *_ep); - -static int -net2280_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged) -{ - struct net2280_ep *ep; - unsigned long flags; - int retval = 0; - - ep = container_of (_ep, struct net2280_ep, ep); - if (!_ep || (!ep->desc && ep->num != 0)) - return -EINVAL; - if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - if (ep->desc /* not ep0 */ && (ep->desc->bmAttributes & 0x03) - == USB_ENDPOINT_XFER_ISOC) - return -EINVAL; - - spin_lock_irqsave (&ep->dev->lock, flags); - if (!list_empty (&ep->queue)) - retval = -EAGAIN; - else if (ep->is_in && value && net2280_fifo_status (_ep) != 0) - retval = -EAGAIN; - else { - VDEBUG (ep->dev, "%s %s %s\n", _ep->name, - value ? "set" : "clear", - wedged ? "wedge" : "halt"); - /* set/clear, then synch memory views with the device */ - if (value) { - if (ep->num == 0) - ep->dev->protocol_stall = 1; - else - set_halt (ep); - if (wedged) - ep->wedged = 1; - } else { - clear_halt (ep); - ep->wedged = 0; - } - (void) readl (&ep->regs->ep_rsp); - } - spin_unlock_irqrestore (&ep->dev->lock, flags); - - return retval; -} - -static int -net2280_set_halt(struct usb_ep *_ep, int value) -{ - return net2280_set_halt_and_wedge(_ep, value, 0); -} - -static int -net2280_set_wedge(struct usb_ep *_ep) -{ - if (!_ep || _ep->name == ep0name) - return -EINVAL; - return net2280_set_halt_and_wedge(_ep, 1, 1); -} - -static int -net2280_fifo_status (struct usb_ep *_ep) -{ - struct net2280_ep *ep; - u32 avail; - - ep = container_of (_ep, struct net2280_ep, ep); - if (!_ep || (!ep->desc && ep->num != 0)) - return -ENODEV; - if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - avail = readl (&ep->regs->ep_avail) & ((1 << 12) - 1); - if (avail > ep->fifo_size) - return -EOVERFLOW; - if (ep->is_in) - avail = ep->fifo_size - avail; - return avail; -} - -static void -net2280_fifo_flush (struct usb_ep *_ep) -{ - struct net2280_ep *ep; - - ep = container_of (_ep, struct net2280_ep, ep); - if (!_ep || (!ep->desc && ep->num != 0)) - return; - if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) - return; - - writel ((1 << FIFO_FLUSH), &ep->regs->ep_stat); - (void) readl (&ep->regs->ep_rsp); -} - -static const struct usb_ep_ops net2280_ep_ops = { - .enable = net2280_enable, - .disable = net2280_disable, - - .alloc_request = net2280_alloc_request, - .free_request = net2280_free_request, - - .queue = net2280_queue, - .dequeue = net2280_dequeue, - - .set_halt = net2280_set_halt, - .set_wedge = net2280_set_wedge, - .fifo_status = net2280_fifo_status, - .fifo_flush = net2280_fifo_flush, -}; - -/*-------------------------------------------------------------------------*/ - -static int net2280_get_frame (struct usb_gadget *_gadget) -{ - struct net2280 *dev; - unsigned long flags; - u16 retval; - - if (!_gadget) - return -ENODEV; - dev = container_of (_gadget, struct net2280, gadget); - spin_lock_irqsave (&dev->lock, flags); - retval = get_idx_reg (dev->regs, REG_FRAME) & 0x03ff; - spin_unlock_irqrestore (&dev->lock, flags); - return retval; -} - -static int net2280_wakeup (struct usb_gadget *_gadget) -{ - struct net2280 *dev; - u32 tmp; - unsigned long flags; - - if (!_gadget) - return 0; - dev = container_of (_gadget, struct net2280, gadget); - - spin_lock_irqsave (&dev->lock, flags); - tmp = readl (&dev->usb->usbctl); - if (tmp & (1 << DEVICE_REMOTE_WAKEUP_ENABLE)) - writel (1 << GENERATE_RESUME, &dev->usb->usbstat); - spin_unlock_irqrestore (&dev->lock, flags); - - /* pci writes may still be posted */ - return 0; -} - -static int net2280_set_selfpowered (struct usb_gadget *_gadget, int value) -{ - struct net2280 *dev; - u32 tmp; - unsigned long flags; - - if (!_gadget) - return 0; - dev = container_of (_gadget, struct net2280, gadget); - - spin_lock_irqsave (&dev->lock, flags); - tmp = readl (&dev->usb->usbctl); - if (value) - tmp |= (1 << SELF_POWERED_STATUS); - else - tmp &= ~(1 << SELF_POWERED_STATUS); - writel (tmp, &dev->usb->usbctl); - spin_unlock_irqrestore (&dev->lock, flags); - - return 0; -} - -static int net2280_pullup(struct usb_gadget *_gadget, int is_on) -{ - struct net2280 *dev; - u32 tmp; - unsigned long flags; - - if (!_gadget) - return -ENODEV; - dev = container_of (_gadget, struct net2280, gadget); - - spin_lock_irqsave (&dev->lock, flags); - tmp = readl (&dev->usb->usbctl); - dev->softconnect = (is_on != 0); - if (is_on) - tmp |= (1 << USB_DETECT_ENABLE); - else - tmp &= ~(1 << USB_DETECT_ENABLE); - writel (tmp, &dev->usb->usbctl); - spin_unlock_irqrestore (&dev->lock, flags); - - return 0; -} - -static int net2280_start(struct usb_gadget *_gadget, - struct usb_gadget_driver *driver); -static int net2280_stop(struct usb_gadget *_gadget, - struct usb_gadget_driver *driver); - -static const struct usb_gadget_ops net2280_ops = { - .get_frame = net2280_get_frame, - .wakeup = net2280_wakeup, - .set_selfpowered = net2280_set_selfpowered, - .pullup = net2280_pullup, - .udc_start = net2280_start, - .udc_stop = net2280_stop, -}; - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - -/* FIXME move these into procfs, and use seq_file. - * Sysfs _still_ doesn't behave for arbitrarily sized files, - * and also doesn't help products using this with 2.4 kernels. - */ - -/* "function" sysfs attribute */ -static ssize_t -show_function (struct device *_dev, struct device_attribute *attr, char *buf) -{ - struct net2280 *dev = dev_get_drvdata (_dev); - - if (!dev->driver - || !dev->driver->function - || strlen (dev->driver->function) > PAGE_SIZE) - return 0; - return scnprintf (buf, PAGE_SIZE, "%s\n", dev->driver->function); -} -static DEVICE_ATTR (function, S_IRUGO, show_function, NULL); - -static ssize_t net2280_show_registers(struct device *_dev, - struct device_attribute *attr, char *buf) -{ - struct net2280 *dev; - char *next; - unsigned size, t; - unsigned long flags; - int i; - u32 t1, t2; - const char *s; - - dev = dev_get_drvdata (_dev); - next = buf; - size = PAGE_SIZE; - spin_lock_irqsave (&dev->lock, flags); - - if (dev->driver) - s = dev->driver->driver.name; - else - s = "(none)"; - - /* Main Control Registers */ - t = scnprintf (next, size, "%s version " DRIVER_VERSION - ", chiprev %04x, dma %s\n\n" - "devinit %03x fifoctl %08x gadget '%s'\n" - "pci irqenb0 %02x irqenb1 %08x " - "irqstat0 %04x irqstat1 %08x\n", - driver_name, dev->chiprev, - use_dma - ? (use_dma_chaining ? "chaining" : "enabled") - : "disabled", - readl (&dev->regs->devinit), - readl (&dev->regs->fifoctl), - s, - readl (&dev->regs->pciirqenb0), - readl (&dev->regs->pciirqenb1), - readl (&dev->regs->irqstat0), - readl (&dev->regs->irqstat1)); - size -= t; - next += t; - - /* USB Control Registers */ - t1 = readl (&dev->usb->usbctl); - t2 = readl (&dev->usb->usbstat); - if (t1 & (1 << VBUS_PIN)) { - if (t2 & (1 << HIGH_SPEED)) - s = "high speed"; - else if (dev->gadget.speed == USB_SPEED_UNKNOWN) - s = "powered"; - else - s = "full speed"; - /* full speed bit (6) not working?? */ - } else - s = "not attached"; - t = scnprintf (next, size, - "stdrsp %08x usbctl %08x usbstat %08x " - "addr 0x%02x (%s)\n", - readl (&dev->usb->stdrsp), t1, t2, - readl (&dev->usb->ouraddr), s); - size -= t; - next += t; - - /* PCI Master Control Registers */ - - /* DMA Control Registers */ - - /* Configurable EP Control Registers */ - for (i = 0; i < 7; i++) { - struct net2280_ep *ep; - - ep = &dev->ep [i]; - if (i && !ep->desc) - continue; - - t1 = readl (&ep->regs->ep_cfg); - t2 = readl (&ep->regs->ep_rsp) & 0xff; - t = scnprintf (next, size, - "\n%s\tcfg %05x rsp (%02x) %s%s%s%s%s%s%s%s" - "irqenb %02x\n", - ep->ep.name, t1, t2, - (t2 & (1 << CLEAR_NAK_OUT_PACKETS)) - ? "NAK " : "", - (t2 & (1 << CLEAR_EP_HIDE_STATUS_PHASE)) - ? "hide " : "", - (t2 & (1 << CLEAR_EP_FORCE_CRC_ERROR)) - ? "CRC " : "", - (t2 & (1 << CLEAR_INTERRUPT_MODE)) - ? "interrupt " : "", - (t2 & (1<regs->ep_irqenb)); - size -= t; - next += t; - - t = scnprintf (next, size, - "\tstat %08x avail %04x " - "(ep%d%s-%s)%s\n", - readl (&ep->regs->ep_stat), - readl (&ep->regs->ep_avail), - t1 & 0x0f, DIR_STRING (t1), - type_string (t1 >> 8), - ep->stopped ? "*" : ""); - size -= t; - next += t; - - if (!ep->dma) - continue; - - t = scnprintf (next, size, - " dma\tctl %08x stat %08x count %08x\n" - "\taddr %08x desc %08x\n", - readl (&ep->dma->dmactl), - readl (&ep->dma->dmastat), - readl (&ep->dma->dmacount), - readl (&ep->dma->dmaaddr), - readl (&ep->dma->dmadesc)); - size -= t; - next += t; - - } - - /* Indexed Registers */ - // none yet - - /* Statistics */ - t = scnprintf (next, size, "\nirqs: "); - size -= t; - next += t; - for (i = 0; i < 7; i++) { - struct net2280_ep *ep; - - ep = &dev->ep [i]; - if (i && !ep->irqs) - continue; - t = scnprintf (next, size, " %s/%lu", ep->ep.name, ep->irqs); - size -= t; - next += t; - - } - t = scnprintf (next, size, "\n"); - size -= t; - next += t; - - spin_unlock_irqrestore (&dev->lock, flags); - - return PAGE_SIZE - size; -} -static DEVICE_ATTR(registers, S_IRUGO, net2280_show_registers, NULL); - -static ssize_t -show_queues (struct device *_dev, struct device_attribute *attr, char *buf) -{ - struct net2280 *dev; - char *next; - unsigned size; - unsigned long flags; - int i; - - dev = dev_get_drvdata (_dev); - next = buf; - size = PAGE_SIZE; - spin_lock_irqsave (&dev->lock, flags); - - for (i = 0; i < 7; i++) { - struct net2280_ep *ep = &dev->ep [i]; - struct net2280_request *req; - int t; - - if (i != 0) { - const struct usb_endpoint_descriptor *d; - - d = ep->desc; - if (!d) - continue; - t = d->bEndpointAddress; - t = scnprintf (next, size, - "\n%s (ep%d%s-%s) max %04x %s fifo %d\n", - ep->ep.name, t & USB_ENDPOINT_NUMBER_MASK, - (t & USB_DIR_IN) ? "in" : "out", - ({ char *val; - switch (d->bmAttributes & 0x03) { - case USB_ENDPOINT_XFER_BULK: - val = "bulk"; break; - case USB_ENDPOINT_XFER_INT: - val = "intr"; break; - default: - val = "iso"; break; - }; val; }), - usb_endpoint_maxp (d) & 0x1fff, - ep->dma ? "dma" : "pio", ep->fifo_size - ); - } else /* ep0 should only have one transfer queued */ - t = scnprintf (next, size, "ep0 max 64 pio %s\n", - ep->is_in ? "in" : "out"); - if (t <= 0 || t > size) - goto done; - size -= t; - next += t; - - if (list_empty (&ep->queue)) { - t = scnprintf (next, size, "\t(nothing queued)\n"); - if (t <= 0 || t > size) - goto done; - size -= t; - next += t; - continue; - } - list_for_each_entry (req, &ep->queue, queue) { - if (ep->dma && req->td_dma == readl (&ep->dma->dmadesc)) - t = scnprintf (next, size, - "\treq %p len %d/%d " - "buf %p (dmacount %08x)\n", - &req->req, req->req.actual, - req->req.length, req->req.buf, - readl (&ep->dma->dmacount)); - else - t = scnprintf (next, size, - "\treq %p len %d/%d buf %p\n", - &req->req, req->req.actual, - req->req.length, req->req.buf); - if (t <= 0 || t > size) - goto done; - size -= t; - next += t; - - if (ep->dma) { - struct net2280_dma *td; - - td = req->td; - t = scnprintf (next, size, "\t td %08x " - " count %08x buf %08x desc %08x\n", - (u32) req->td_dma, - le32_to_cpu (td->dmacount), - le32_to_cpu (td->dmaaddr), - le32_to_cpu (td->dmadesc)); - if (t <= 0 || t > size) - goto done; - size -= t; - next += t; - } - } - } - -done: - spin_unlock_irqrestore (&dev->lock, flags); - return PAGE_SIZE - size; -} -static DEVICE_ATTR (queues, S_IRUGO, show_queues, NULL); - - -#else - -#define device_create_file(a,b) (0) -#define device_remove_file(a,b) do { } while (0) - -#endif - -/*-------------------------------------------------------------------------*/ - -/* another driver-specific mode might be a request type doing dma - * to/from another device fifo instead of to/from memory. - */ - -static void set_fifo_mode (struct net2280 *dev, int mode) -{ - /* keeping high bits preserves BAR2 */ - writel ((0xffff << PCI_BASE2_RANGE) | mode, &dev->regs->fifoctl); - - /* always ep-{a,b,e,f} ... maybe not ep-c or ep-d */ - INIT_LIST_HEAD (&dev->gadget.ep_list); - list_add_tail (&dev->ep [1].ep.ep_list, &dev->gadget.ep_list); - list_add_tail (&dev->ep [2].ep.ep_list, &dev->gadget.ep_list); - switch (mode) { - case 0: - list_add_tail (&dev->ep [3].ep.ep_list, &dev->gadget.ep_list); - list_add_tail (&dev->ep [4].ep.ep_list, &dev->gadget.ep_list); - dev->ep [1].fifo_size = dev->ep [2].fifo_size = 1024; - break; - case 1: - dev->ep [1].fifo_size = dev->ep [2].fifo_size = 2048; - break; - case 2: - list_add_tail (&dev->ep [3].ep.ep_list, &dev->gadget.ep_list); - dev->ep [1].fifo_size = 2048; - dev->ep [2].fifo_size = 1024; - break; - } - /* fifo sizes for ep0, ep-c, ep-d, ep-e, and ep-f never change */ - list_add_tail (&dev->ep [5].ep.ep_list, &dev->gadget.ep_list); - list_add_tail (&dev->ep [6].ep.ep_list, &dev->gadget.ep_list); -} - -/* keeping it simple: - * - one bus driver, initted first; - * - one function driver, initted second - * - * most of the work to support multiple net2280 controllers would - * be to associate this gadget driver (yes?) with all of them, or - * perhaps to bind specific drivers to specific devices. - */ - -static void usb_reset (struct net2280 *dev) -{ - u32 tmp; - - dev->gadget.speed = USB_SPEED_UNKNOWN; - (void) readl (&dev->usb->usbctl); - - net2280_led_init (dev); - - /* disable automatic responses, and irqs */ - writel (0, &dev->usb->stdrsp); - writel (0, &dev->regs->pciirqenb0); - writel (0, &dev->regs->pciirqenb1); - - /* clear old dma and irq state */ - for (tmp = 0; tmp < 4; tmp++) { - struct net2280_ep *ep = &dev->ep [tmp + 1]; - - if (ep->dma) - abort_dma (ep); - } - writel (~0, &dev->regs->irqstat0), - writel (~(1 << SUSPEND_REQUEST_INTERRUPT), &dev->regs->irqstat1), - - /* reset, and enable pci */ - tmp = readl (&dev->regs->devinit) - | (1 << PCI_ENABLE) - | (1 << FIFO_SOFT_RESET) - | (1 << USB_SOFT_RESET) - | (1 << M8051_RESET); - writel (tmp, &dev->regs->devinit); - - /* standard fifo and endpoint allocations */ - set_fifo_mode (dev, (fifo_mode <= 2) ? fifo_mode : 0); -} - -static void usb_reinit (struct net2280 *dev) -{ - u32 tmp; - int init_dma; - - /* use_dma changes are ignored till next device re-init */ - init_dma = use_dma; - - /* basic endpoint init */ - for (tmp = 0; tmp < 7; tmp++) { - struct net2280_ep *ep = &dev->ep [tmp]; - - ep->ep.name = ep_name [tmp]; - ep->dev = dev; - ep->num = tmp; - - if (tmp > 0 && tmp <= 4) { - ep->fifo_size = 1024; - if (init_dma) - ep->dma = &dev->dma [tmp - 1]; - } else - ep->fifo_size = 64; - ep->regs = &dev->epregs [tmp]; - ep_reset (dev->regs, ep); - } - dev->ep [0].ep.maxpacket = 64; - dev->ep [5].ep.maxpacket = 64; - dev->ep [6].ep.maxpacket = 64; - - dev->gadget.ep0 = &dev->ep [0].ep; - dev->ep [0].stopped = 0; - INIT_LIST_HEAD (&dev->gadget.ep0->ep_list); - - /* we want to prevent lowlevel/insecure access from the USB host, - * but erratum 0119 means this enable bit is ignored - */ - for (tmp = 0; tmp < 5; tmp++) - writel (EP_DONTUSE, &dev->dep [tmp].dep_cfg); -} - -static void ep0_start (struct net2280 *dev) -{ - writel ( (1 << CLEAR_EP_HIDE_STATUS_PHASE) - | (1 << CLEAR_NAK_OUT_PACKETS) - | (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) - , &dev->epregs [0].ep_rsp); - - /* - * hardware optionally handles a bunch of standard requests - * that the API hides from drivers anyway. have it do so. - * endpoint status/features are handled in software, to - * help pass tests for some dubious behavior. - */ - writel ( (1 << SET_TEST_MODE) - | (1 << SET_ADDRESS) - | (1 << DEVICE_SET_CLEAR_DEVICE_REMOTE_WAKEUP) - | (1 << GET_DEVICE_STATUS) - | (1 << GET_INTERFACE_STATUS) - , &dev->usb->stdrsp); - writel ( (1 << USB_ROOT_PORT_WAKEUP_ENABLE) - | (1 << SELF_POWERED_USB_DEVICE) - | (1 << REMOTE_WAKEUP_SUPPORT) - | (dev->softconnect << USB_DETECT_ENABLE) - | (1 << SELF_POWERED_STATUS) - , &dev->usb->usbctl); - - /* enable irqs so we can see ep0 and general operation */ - writel ( (1 << SETUP_PACKET_INTERRUPT_ENABLE) - | (1 << ENDPOINT_0_INTERRUPT_ENABLE) - , &dev->regs->pciirqenb0); - writel ( (1 << PCI_INTERRUPT_ENABLE) - | (1 << PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE) - | (1 << PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE) - | (1 << PCI_RETRY_ABORT_INTERRUPT_ENABLE) - | (1 << VBUS_INTERRUPT_ENABLE) - | (1 << ROOT_PORT_RESET_INTERRUPT_ENABLE) - | (1 << SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE) - , &dev->regs->pciirqenb1); - - /* don't leave any writes posted */ - (void) readl (&dev->usb->usbctl); -} - -/* when a driver is successfully registered, it will receive - * control requests including set_configuration(), which enables - * non-control requests. then usb traffic follows until a - * disconnect is reported. then a host may connect again, or - * the driver might get unbound. - */ -static int net2280_start(struct usb_gadget *_gadget, - struct usb_gadget_driver *driver) -{ - struct net2280 *dev; - int retval; - unsigned i; - - /* insist on high speed support from the driver, since - * (dev->usb->xcvrdiag & FORCE_FULL_SPEED_MODE) - * "must not be used in normal operation" - */ - if (!driver || driver->max_speed < USB_SPEED_HIGH - || !driver->setup) - return -EINVAL; - - dev = container_of (_gadget, struct net2280, gadget); - - for (i = 0; i < 7; i++) - dev->ep [i].irqs = 0; - - /* hook up the driver ... */ - dev->softconnect = 1; - driver->driver.bus = NULL; - dev->driver = driver; - dev->gadget.dev.driver = &driver->driver; - - retval = device_create_file (&dev->pdev->dev, &dev_attr_function); - if (retval) goto err_unbind; - retval = device_create_file (&dev->pdev->dev, &dev_attr_queues); - if (retval) goto err_func; - - /* ... then enable host detection and ep0; and we're ready - * for set_configuration as well as eventual disconnect. - */ - net2280_led_active (dev, 1); - ep0_start (dev); - - DEBUG (dev, "%s ready, usbctl %08x stdrsp %08x\n", - driver->driver.name, - readl (&dev->usb->usbctl), - readl (&dev->usb->stdrsp)); - - /* pci writes may still be posted */ - return 0; - -err_func: - device_remove_file (&dev->pdev->dev, &dev_attr_function); -err_unbind: - driver->unbind (&dev->gadget); - dev->gadget.dev.driver = NULL; - dev->driver = NULL; - return retval; -} - -static void -stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver) -{ - int i; - - /* don't disconnect if it's not connected */ - if (dev->gadget.speed == USB_SPEED_UNKNOWN) - driver = NULL; - - /* stop hardware; prevent new request submissions; - * and kill any outstanding requests. - */ - usb_reset (dev); - for (i = 0; i < 7; i++) - nuke (&dev->ep [i]); - - usb_reinit (dev); -} - -static int net2280_stop(struct usb_gadget *_gadget, - struct usb_gadget_driver *driver) -{ - struct net2280 *dev; - unsigned long flags; - - dev = container_of (_gadget, struct net2280, gadget); - - spin_lock_irqsave (&dev->lock, flags); - stop_activity (dev, driver); - spin_unlock_irqrestore (&dev->lock, flags); - - dev->gadget.dev.driver = NULL; - dev->driver = NULL; - - net2280_led_active (dev, 0); - device_remove_file (&dev->pdev->dev, &dev_attr_function); - device_remove_file (&dev->pdev->dev, &dev_attr_queues); - - DEBUG (dev, "unregistered driver '%s'\n", driver->driver.name); - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* handle ep0, ep-e, ep-f with 64 byte packets: packet per irq. - * also works for dma-capable endpoints, in pio mode or just - * to manually advance the queue after short OUT transfers. - */ -static void handle_ep_small (struct net2280_ep *ep) -{ - struct net2280_request *req; - u32 t; - /* 0 error, 1 mid-data, 2 done */ - int mode = 1; - - if (!list_empty (&ep->queue)) - req = list_entry (ep->queue.next, - struct net2280_request, queue); - else - req = NULL; - - /* ack all, and handle what we care about */ - t = readl (&ep->regs->ep_stat); - ep->irqs++; -#if 0 - VDEBUG (ep->dev, "%s ack ep_stat %08x, req %p\n", - ep->ep.name, t, req ? &req->req : 0); -#endif - if (!ep->is_in || ep->dev->pdev->device == 0x2280) - writel (t & ~(1 << NAK_OUT_PACKETS), &ep->regs->ep_stat); - else - /* Added for 2282 */ - writel (t, &ep->regs->ep_stat); - - /* for ep0, monitor token irqs to catch data stage length errors - * and to synchronize on status. - * - * also, to defer reporting of protocol stalls ... here's where - * data or status first appears, handling stalls here should never - * cause trouble on the host side.. - * - * control requests could be slightly faster without token synch for - * status, but status can jam up that way. - */ - if (unlikely (ep->num == 0)) { - if (ep->is_in) { - /* status; stop NAKing */ - if (t & (1 << DATA_OUT_PING_TOKEN_INTERRUPT)) { - if (ep->dev->protocol_stall) { - ep->stopped = 1; - set_halt (ep); - } - if (!req) - allow_status (ep); - mode = 2; - /* reply to extra IN data tokens with a zlp */ - } else if (t & (1 << DATA_IN_TOKEN_INTERRUPT)) { - if (ep->dev->protocol_stall) { - ep->stopped = 1; - set_halt (ep); - mode = 2; - } else if (ep->responded && - !req && !ep->stopped) - write_fifo (ep, NULL); - } - } else { - /* status; stop NAKing */ - if (t & (1 << DATA_IN_TOKEN_INTERRUPT)) { - if (ep->dev->protocol_stall) { - ep->stopped = 1; - set_halt (ep); - } - mode = 2; - /* an extra OUT token is an error */ - } else if (((t & (1 << DATA_OUT_PING_TOKEN_INTERRUPT)) - && req - && req->req.actual == req->req.length) - || (ep->responded && !req)) { - ep->dev->protocol_stall = 1; - set_halt (ep); - ep->stopped = 1; - if (req) - done (ep, req, -EOVERFLOW); - req = NULL; - } - } - } - - if (unlikely (!req)) - return; - - /* manual DMA queue advance after short OUT */ - if (likely (ep->dma != 0)) { - if (t & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)) { - u32 count; - int stopped = ep->stopped; - - /* TRANSFERRED works around OUT_DONE erratum 0112. - * we expect (N <= maxpacket) bytes; host wrote M. - * iff (M < N) we won't ever see a DMA interrupt. - */ - ep->stopped = 1; - for (count = 0; ; t = readl (&ep->regs->ep_stat)) { - - /* any preceding dma transfers must finish. - * dma handles (M >= N), may empty the queue - */ - scan_dma_completions (ep); - if (unlikely (list_empty (&ep->queue) - || ep->out_overflow)) { - req = NULL; - break; - } - req = list_entry (ep->queue.next, - struct net2280_request, queue); - - /* here either (M < N), a "real" short rx; - * or (M == N) and the queue didn't empty - */ - if (likely (t & (1 << FIFO_EMPTY))) { - count = readl (&ep->dma->dmacount); - count &= DMA_BYTE_COUNT_MASK; - if (readl (&ep->dma->dmadesc) - != req->td_dma) - req = NULL; - break; - } - udelay(1); - } - - /* stop DMA, leave ep NAKing */ - writel ((1 << DMA_ABORT), &ep->dma->dmastat); - spin_stop_dma (ep->dma); - - if (likely (req)) { - req->td->dmacount = 0; - t = readl (&ep->regs->ep_avail); - dma_done (ep, req, count, - (ep->out_overflow || t) - ? -EOVERFLOW : 0); - } - - /* also flush to prevent erratum 0106 trouble */ - if (unlikely (ep->out_overflow - || (ep->dev->chiprev == 0x0100 - && ep->dev->gadget.speed - == USB_SPEED_FULL))) { - out_flush (ep); - ep->out_overflow = 0; - } - - /* (re)start dma if needed, stop NAKing */ - ep->stopped = stopped; - if (!list_empty (&ep->queue)) - restart_dma (ep); - } else - DEBUG (ep->dev, "%s dma ep_stat %08x ??\n", - ep->ep.name, t); - return; - - /* data packet(s) received (in the fifo, OUT) */ - } else if (t & (1 << DATA_PACKET_RECEIVED_INTERRUPT)) { - if (read_fifo (ep, req) && ep->num != 0) - mode = 2; - - /* data packet(s) transmitted (IN) */ - } else if (t & (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)) { - unsigned len; - - len = req->req.length - req->req.actual; - if (len > ep->ep.maxpacket) - len = ep->ep.maxpacket; - req->req.actual += len; - - /* if we wrote it all, we're usually done */ - if (req->req.actual == req->req.length) { - if (ep->num == 0) { - /* send zlps until the status stage */ - } else if (!req->req.zero || len != ep->ep.maxpacket) - mode = 2; - } - - /* there was nothing to do ... */ - } else if (mode == 1) - return; - - /* done */ - if (mode == 2) { - /* stream endpoints often resubmit/unlink in completion */ - done (ep, req, 0); - - /* maybe advance queue to next request */ - if (ep->num == 0) { - /* NOTE: net2280 could let gadget driver start the - * status stage later. since not all controllers let - * them control that, the api doesn't (yet) allow it. - */ - if (!ep->stopped) - allow_status (ep); - req = NULL; - } else { - if (!list_empty (&ep->queue) && !ep->stopped) - req = list_entry (ep->queue.next, - struct net2280_request, queue); - else - req = NULL; - if (req && !ep->is_in) - stop_out_naking (ep); - } - } - - /* is there a buffer for the next packet? - * for best streaming performance, make sure there is one. - */ - if (req && !ep->stopped) { - - /* load IN fifo with next packet (may be zlp) */ - if (t & (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)) - write_fifo (ep, &req->req); - } -} - -static struct net2280_ep * -get_ep_by_addr (struct net2280 *dev, u16 wIndex) -{ - struct net2280_ep *ep; - - if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0) - return &dev->ep [0]; - list_for_each_entry (ep, &dev->gadget.ep_list, ep.ep_list) { - u8 bEndpointAddress; - - if (!ep->desc) - continue; - bEndpointAddress = ep->desc->bEndpointAddress; - if ((wIndex ^ bEndpointAddress) & USB_DIR_IN) - continue; - if ((wIndex & 0x0f) == (bEndpointAddress & 0x0f)) - return ep; - } - return NULL; -} - -static void handle_stat0_irqs (struct net2280 *dev, u32 stat) -{ - struct net2280_ep *ep; - u32 num, scratch; - - /* most of these don't need individual acks */ - stat &= ~(1 << INTA_ASSERTED); - if (!stat) - return; - // DEBUG (dev, "irqstat0 %04x\n", stat); - - /* starting a control request? */ - if (unlikely (stat & (1 << SETUP_PACKET_INTERRUPT))) { - union { - u32 raw [2]; - struct usb_ctrlrequest r; - } u; - int tmp; - struct net2280_request *req; - - if (dev->gadget.speed == USB_SPEED_UNKNOWN) { - if (readl (&dev->usb->usbstat) & (1 << HIGH_SPEED)) - dev->gadget.speed = USB_SPEED_HIGH; - else - dev->gadget.speed = USB_SPEED_FULL; - net2280_led_speed (dev, dev->gadget.speed); - DEBUG(dev, "%s\n", usb_speed_string(dev->gadget.speed)); - } - - ep = &dev->ep [0]; - ep->irqs++; - - /* make sure any leftover request state is cleared */ - stat &= ~(1 << ENDPOINT_0_INTERRUPT); - while (!list_empty (&ep->queue)) { - req = list_entry (ep->queue.next, - struct net2280_request, queue); - done (ep, req, (req->req.actual == req->req.length) - ? 0 : -EPROTO); - } - ep->stopped = 0; - dev->protocol_stall = 0; - - if (ep->dev->pdev->device == 0x2280) - tmp = (1 << FIFO_OVERFLOW) - | (1 << FIFO_UNDERFLOW); - else - tmp = 0; - - writel (tmp | (1 << TIMEOUT) - | (1 << USB_STALL_SENT) - | (1 << USB_IN_NAK_SENT) - | (1 << USB_IN_ACK_RCVD) - | (1 << USB_OUT_PING_NAK_SENT) - | (1 << USB_OUT_ACK_SENT) - | (1 << SHORT_PACKET_OUT_DONE_INTERRUPT) - | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT) - | (1 << DATA_PACKET_RECEIVED_INTERRUPT) - | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT) - | (1 << DATA_OUT_PING_TOKEN_INTERRUPT) - | (1 << DATA_IN_TOKEN_INTERRUPT) - , &ep->regs->ep_stat); - u.raw [0] = readl (&dev->usb->setup0123); - u.raw [1] = readl (&dev->usb->setup4567); - - cpu_to_le32s (&u.raw [0]); - cpu_to_le32s (&u.raw [1]); - - tmp = 0; - -#define w_value le16_to_cpu(u.r.wValue) -#define w_index le16_to_cpu(u.r.wIndex) -#define w_length le16_to_cpu(u.r.wLength) - - /* ack the irq */ - writel (1 << SETUP_PACKET_INTERRUPT, &dev->regs->irqstat0); - stat ^= (1 << SETUP_PACKET_INTERRUPT); - - /* watch control traffic at the token level, and force - * synchronization before letting the status stage happen. - * FIXME ignore tokens we'll NAK, until driver responds. - * that'll mean a lot less irqs for some drivers. - */ - ep->is_in = (u.r.bRequestType & USB_DIR_IN) != 0; - if (ep->is_in) { - scratch = (1 << DATA_PACKET_TRANSMITTED_INTERRUPT) - | (1 << DATA_OUT_PING_TOKEN_INTERRUPT) - | (1 << DATA_IN_TOKEN_INTERRUPT); - stop_out_naking (ep); - } else - scratch = (1 << DATA_PACKET_RECEIVED_INTERRUPT) - | (1 << DATA_OUT_PING_TOKEN_INTERRUPT) - | (1 << DATA_IN_TOKEN_INTERRUPT); - writel (scratch, &dev->epregs [0].ep_irqenb); - - /* we made the hardware handle most lowlevel requests; - * everything else goes uplevel to the gadget code. - */ - ep->responded = 1; - switch (u.r.bRequest) { - case USB_REQ_GET_STATUS: { - struct net2280_ep *e; - __le32 status; - - /* hw handles device and interface status */ - if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT)) - goto delegate; - if ((e = get_ep_by_addr (dev, w_index)) == 0 - || w_length > 2) - goto do_stall; - - if (readl (&e->regs->ep_rsp) - & (1 << SET_ENDPOINT_HALT)) - status = cpu_to_le32 (1); - else - status = cpu_to_le32 (0); - - /* don't bother with a request object! */ - writel (0, &dev->epregs [0].ep_irqenb); - set_fifo_bytecount (ep, w_length); - writel ((__force u32)status, &dev->epregs [0].ep_data); - allow_status (ep); - VDEBUG (dev, "%s stat %02x\n", ep->ep.name, status); - goto next_endpoints; - } - break; - case USB_REQ_CLEAR_FEATURE: { - struct net2280_ep *e; - - /* hw handles device features */ - if (u.r.bRequestType != USB_RECIP_ENDPOINT) - goto delegate; - if (w_value != USB_ENDPOINT_HALT - || w_length != 0) - goto do_stall; - if ((e = get_ep_by_addr (dev, w_index)) == 0) - goto do_stall; - if (e->wedged) { - VDEBUG(dev, "%s wedged, halt not cleared\n", - ep->ep.name); - } else { - VDEBUG(dev, "%s clear halt\n", ep->ep.name); - clear_halt(e); - } - allow_status (ep); - goto next_endpoints; - } - break; - case USB_REQ_SET_FEATURE: { - struct net2280_ep *e; - - /* hw handles device features */ - if (u.r.bRequestType != USB_RECIP_ENDPOINT) - goto delegate; - if (w_value != USB_ENDPOINT_HALT - || w_length != 0) - goto do_stall; - if ((e = get_ep_by_addr (dev, w_index)) == 0) - goto do_stall; - if (e->ep.name == ep0name) - goto do_stall; - set_halt (e); - allow_status (ep); - VDEBUG (dev, "%s set halt\n", ep->ep.name); - goto next_endpoints; - } - break; - default: -delegate: - VDEBUG (dev, "setup %02x.%02x v%04x i%04x l%04x " - "ep_cfg %08x\n", - u.r.bRequestType, u.r.bRequest, - w_value, w_index, w_length, - readl (&ep->regs->ep_cfg)); - ep->responded = 0; - spin_unlock (&dev->lock); - tmp = dev->driver->setup (&dev->gadget, &u.r); - spin_lock (&dev->lock); - } - - /* stall ep0 on error */ - if (tmp < 0) { -do_stall: - VDEBUG (dev, "req %02x.%02x protocol STALL; stat %d\n", - u.r.bRequestType, u.r.bRequest, tmp); - dev->protocol_stall = 1; - } - - /* some in/out token irq should follow; maybe stall then. - * driver must queue a request (even zlp) or halt ep0 - * before the host times out. - */ - } - -#undef w_value -#undef w_index -#undef w_length - -next_endpoints: - /* endpoint data irq ? */ - scratch = stat & 0x7f; - stat &= ~0x7f; - for (num = 0; scratch; num++) { - u32 t; - - /* do this endpoint's FIFO and queue need tending? */ - t = 1 << num; - if ((scratch & t) == 0) - continue; - scratch ^= t; - - ep = &dev->ep [num]; - handle_ep_small (ep); - } - - if (stat) - DEBUG (dev, "unhandled irqstat0 %08x\n", stat); -} - -#define DMA_INTERRUPTS ( \ - (1 << DMA_D_INTERRUPT) \ - | (1 << DMA_C_INTERRUPT) \ - | (1 << DMA_B_INTERRUPT) \ - | (1 << DMA_A_INTERRUPT)) -#define PCI_ERROR_INTERRUPTS ( \ - (1 << PCI_MASTER_ABORT_RECEIVED_INTERRUPT) \ - | (1 << PCI_TARGET_ABORT_RECEIVED_INTERRUPT) \ - | (1 << PCI_RETRY_ABORT_INTERRUPT)) - -static void handle_stat1_irqs (struct net2280 *dev, u32 stat) -{ - struct net2280_ep *ep; - u32 tmp, num, mask, scratch; - - /* after disconnect there's nothing else to do! */ - tmp = (1 << VBUS_INTERRUPT) | (1 << ROOT_PORT_RESET_INTERRUPT); - mask = (1 << HIGH_SPEED) | (1 << FULL_SPEED); - - /* VBUS disconnect is indicated by VBUS_PIN and VBUS_INTERRUPT set. - * Root Port Reset is indicated by ROOT_PORT_RESET_INTERRUPT set and - * both HIGH_SPEED and FULL_SPEED clear (as ROOT_PORT_RESET_INTERRUPT - * only indicates a change in the reset state). - */ - if (stat & tmp) { - writel (tmp, &dev->regs->irqstat1); - if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) - && ((readl (&dev->usb->usbstat) & mask) - == 0)) - || ((readl (&dev->usb->usbctl) - & (1 << VBUS_PIN)) == 0) - ) && ( dev->gadget.speed != USB_SPEED_UNKNOWN)) { - DEBUG (dev, "disconnect %s\n", - dev->driver->driver.name); - stop_activity (dev, dev->driver); - ep0_start (dev); - return; - } - stat &= ~tmp; - - /* vBUS can bounce ... one of many reasons to ignore the - * notion of hotplug events on bus connect/disconnect! - */ - if (!stat) - return; - } - - /* NOTE: chip stays in PCI D0 state for now, but it could - * enter D1 to save more power - */ - tmp = (1 << SUSPEND_REQUEST_CHANGE_INTERRUPT); - if (stat & tmp) { - writel (tmp, &dev->regs->irqstat1); - if (stat & (1 << SUSPEND_REQUEST_INTERRUPT)) { - if (dev->driver->suspend) - dev->driver->suspend (&dev->gadget); - if (!enable_suspend) - stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT); - } else { - if (dev->driver->resume) - dev->driver->resume (&dev->gadget); - /* at high speed, note erratum 0133 */ - } - stat &= ~tmp; - } - - /* clear any other status/irqs */ - if (stat) - writel (stat, &dev->regs->irqstat1); - - /* some status we can just ignore */ - if (dev->pdev->device == 0x2280) - stat &= ~((1 << CONTROL_STATUS_INTERRUPT) - | (1 << SUSPEND_REQUEST_INTERRUPT) - | (1 << RESUME_INTERRUPT) - | (1 << SOF_INTERRUPT)); - else - stat &= ~((1 << CONTROL_STATUS_INTERRUPT) - | (1 << RESUME_INTERRUPT) - | (1 << SOF_DOWN_INTERRUPT) - | (1 << SOF_INTERRUPT)); - - if (!stat) - return; - // DEBUG (dev, "irqstat1 %08x\n", stat); - - /* DMA status, for ep-{a,b,c,d} */ - scratch = stat & DMA_INTERRUPTS; - stat &= ~DMA_INTERRUPTS; - scratch >>= 9; - for (num = 0; scratch; num++) { - struct net2280_dma_regs __iomem *dma; - - tmp = 1 << num; - if ((tmp & scratch) == 0) - continue; - scratch ^= tmp; - - ep = &dev->ep [num + 1]; - dma = ep->dma; - - if (!dma) - continue; - - /* clear ep's dma status */ - tmp = readl (&dma->dmastat); - writel (tmp, &dma->dmastat); - - /* chaining should stop on abort, short OUT from fifo, - * or (stat0 codepath) short OUT transfer. - */ - if (!use_dma_chaining) { - if ((tmp & (1 << DMA_TRANSACTION_DONE_INTERRUPT)) - == 0) { - DEBUG (ep->dev, "%s no xact done? %08x\n", - ep->ep.name, tmp); - continue; - } - stop_dma (ep->dma); - } - - /* OUT transfers terminate when the data from the - * host is in our memory. Process whatever's done. - * On this path, we know transfer's last packet wasn't - * less than req->length. NAK_OUT_PACKETS may be set, - * or the FIFO may already be holding new packets. - * - * IN transfers can linger in the FIFO for a very - * long time ... we ignore that for now, accounting - * precisely (like PIO does) needs per-packet irqs - */ - scan_dma_completions (ep); - - /* disable dma on inactive queues; else maybe restart */ - if (list_empty (&ep->queue)) { - if (use_dma_chaining) - stop_dma (ep->dma); - } else { - tmp = readl (&dma->dmactl); - if (!use_dma_chaining - || (tmp & (1 << DMA_ENABLE)) == 0) - restart_dma (ep); - else if (ep->is_in && use_dma_chaining) { - struct net2280_request *req; - __le32 dmacount; - - /* the descriptor at the head of the chain - * may still have VALID_BIT clear; that's - * used to trigger changing DMA_FIFO_VALIDATE - * (affects automagic zlp writes). - */ - req = list_entry (ep->queue.next, - struct net2280_request, queue); - dmacount = req->td->dmacount; - dmacount &= cpu_to_le32 ( - (1 << VALID_BIT) - | DMA_BYTE_COUNT_MASK); - if (dmacount && (dmacount & valid_bit) == 0) - restart_dma (ep); - } - } - ep->irqs++; - } - - /* NOTE: there are other PCI errors we might usefully notice. - * if they appear very often, here's where to try recovering. - */ - if (stat & PCI_ERROR_INTERRUPTS) { - ERROR (dev, "pci dma error; stat %08x\n", stat); - stat &= ~PCI_ERROR_INTERRUPTS; - /* these are fatal errors, but "maybe" they won't - * happen again ... - */ - stop_activity (dev, dev->driver); - ep0_start (dev); - stat = 0; - } - - if (stat) - DEBUG (dev, "unhandled irqstat1 %08x\n", stat); -} - -static irqreturn_t net2280_irq (int irq, void *_dev) -{ - struct net2280 *dev = _dev; - - /* shared interrupt, not ours */ - if (!(readl(&dev->regs->irqstat0) & (1 << INTA_ASSERTED))) - return IRQ_NONE; - - spin_lock (&dev->lock); - - /* handle disconnect, dma, and more */ - handle_stat1_irqs (dev, readl (&dev->regs->irqstat1)); - - /* control requests and PIO */ - handle_stat0_irqs (dev, readl (&dev->regs->irqstat0)); - - spin_unlock (&dev->lock); - - return IRQ_HANDLED; -} - -/*-------------------------------------------------------------------------*/ - -static void gadget_release (struct device *_dev) -{ - struct net2280 *dev = dev_get_drvdata (_dev); - - kfree (dev); -} - -/* tear down the binding between this driver and the pci device */ - -static void net2280_remove (struct pci_dev *pdev) -{ - struct net2280 *dev = pci_get_drvdata (pdev); - - usb_del_gadget_udc(&dev->gadget); - - BUG_ON(dev->driver); - - /* then clean up the resources we allocated during probe() */ - net2280_led_shutdown (dev); - if (dev->requests) { - int i; - for (i = 1; i < 5; i++) { - if (!dev->ep [i].dummy) - continue; - pci_pool_free (dev->requests, dev->ep [i].dummy, - dev->ep [i].td_dma); - } - pci_pool_destroy (dev->requests); - } - if (dev->got_irq) - free_irq (pdev->irq, dev); - if (dev->regs) - iounmap (dev->regs); - if (dev->region) - release_mem_region (pci_resource_start (pdev, 0), - pci_resource_len (pdev, 0)); - if (dev->enabled) - pci_disable_device (pdev); - device_unregister (&dev->gadget.dev); - device_remove_file (&pdev->dev, &dev_attr_registers); - pci_set_drvdata (pdev, NULL); - - INFO (dev, "unbind\n"); -} - -/* wrap this driver around the specified device, but - * don't respond over USB until a gadget driver binds to us. - */ - -static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) -{ - struct net2280 *dev; - unsigned long resource, len; - void __iomem *base = NULL; - int retval, i; - - /* alloc, and start init */ - dev = kzalloc (sizeof *dev, GFP_KERNEL); - if (dev == NULL){ - retval = -ENOMEM; - goto done; - } - - pci_set_drvdata (pdev, dev); - spin_lock_init (&dev->lock); - dev->pdev = pdev; - dev->gadget.ops = &net2280_ops; - dev->gadget.max_speed = USB_SPEED_HIGH; - - /* the "gadget" abstracts/virtualizes the controller */ - dev_set_name(&dev->gadget.dev, "gadget"); - dev->gadget.dev.parent = &pdev->dev; - dev->gadget.dev.dma_mask = pdev->dev.dma_mask; - dev->gadget.dev.release = gadget_release; - dev->gadget.name = driver_name; - - /* now all the pci goodies ... */ - if (pci_enable_device (pdev) < 0) { - retval = -ENODEV; - goto done; - } - dev->enabled = 1; - - /* BAR 0 holds all the registers - * BAR 1 is 8051 memory; unused here (note erratum 0103) - * BAR 2 is fifo memory; unused here - */ - resource = pci_resource_start (pdev, 0); - len = pci_resource_len (pdev, 0); - if (!request_mem_region (resource, len, driver_name)) { - DEBUG (dev, "controller already in use\n"); - retval = -EBUSY; - goto done; - } - dev->region = 1; - - /* FIXME provide firmware download interface to put - * 8051 code into the chip, e.g. to turn on PCI PM. - */ - - base = ioremap_nocache (resource, len); - if (base == NULL) { - DEBUG (dev, "can't map memory\n"); - retval = -EFAULT; - goto done; - } - dev->regs = (struct net2280_regs __iomem *) base; - dev->usb = (struct net2280_usb_regs __iomem *) (base + 0x0080); - dev->pci = (struct net2280_pci_regs __iomem *) (base + 0x0100); - dev->dma = (struct net2280_dma_regs __iomem *) (base + 0x0180); - dev->dep = (struct net2280_dep_regs __iomem *) (base + 0x0200); - dev->epregs = (struct net2280_ep_regs __iomem *) (base + 0x0300); - - /* put into initial config, link up all endpoints */ - writel (0, &dev->usb->usbctl); - usb_reset (dev); - usb_reinit (dev); - - /* irq setup after old hardware is cleaned up */ - if (!pdev->irq) { - ERROR (dev, "No IRQ. Check PCI setup!\n"); - retval = -ENODEV; - goto done; - } - - if (request_irq (pdev->irq, net2280_irq, IRQF_SHARED, driver_name, dev) - != 0) { - ERROR (dev, "request interrupt %d failed\n", pdev->irq); - retval = -EBUSY; - goto done; - } - dev->got_irq = 1; - - /* DMA setup */ - /* NOTE: we know only the 32 LSBs of dma addresses may be nonzero */ - dev->requests = pci_pool_create ("requests", pdev, - sizeof (struct net2280_dma), - 0 /* no alignment requirements */, - 0 /* or page-crossing issues */); - if (!dev->requests) { - DEBUG (dev, "can't get request pool\n"); - retval = -ENOMEM; - goto done; - } - for (i = 1; i < 5; i++) { - struct net2280_dma *td; - - td = pci_pool_alloc (dev->requests, GFP_KERNEL, - &dev->ep [i].td_dma); - if (!td) { - DEBUG (dev, "can't get dummy %d\n", i); - retval = -ENOMEM; - goto done; - } - td->dmacount = 0; /* not VALID */ - td->dmaaddr = cpu_to_le32 (DMA_ADDR_INVALID); - td->dmadesc = td->dmaaddr; - dev->ep [i].dummy = td; - } - - /* enable lower-overhead pci memory bursts during DMA */ - writel ( (1 << DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE) - // 256 write retries may not be enough... - // | (1 << PCI_RETRY_ABORT_ENABLE) - | (1 << DMA_READ_MULTIPLE_ENABLE) - | (1 << DMA_READ_LINE_ENABLE) - , &dev->pci->pcimstctl); - /* erratum 0115 shouldn't appear: Linux inits PCI_LATENCY_TIMER */ - pci_set_master (pdev); - pci_try_set_mwi (pdev); - - /* ... also flushes any posted pci writes */ - dev->chiprev = get_idx_reg (dev->regs, REG_CHIPREV) & 0xffff; - - /* done */ - INFO (dev, "%s\n", driver_desc); - INFO (dev, "irq %d, pci mem %p, chip rev %04x\n", - pdev->irq, base, dev->chiprev); - INFO (dev, "version: " DRIVER_VERSION "; dma %s\n", - use_dma - ? (use_dma_chaining ? "chaining" : "enabled") - : "disabled"); - retval = device_register (&dev->gadget.dev); - if (retval) goto done; - retval = device_create_file (&pdev->dev, &dev_attr_registers); - if (retval) goto done; - - retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); - if (retval) - goto done; - return 0; - -done: - if (dev) - net2280_remove (pdev); - return retval; -} - -/* make sure the board is quiescent; otherwise it will continue - * generating IRQs across the upcoming reboot. - */ - -static void net2280_shutdown (struct pci_dev *pdev) -{ - struct net2280 *dev = pci_get_drvdata (pdev); - - /* disable IRQs */ - writel (0, &dev->regs->pciirqenb0); - writel (0, &dev->regs->pciirqenb1); - - /* disable the pullup so the host will think we're gone */ - writel (0, &dev->usb->usbctl); -} - - -/*-------------------------------------------------------------------------*/ - -static const struct pci_device_id pci_ids [] = { { - .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), - .class_mask = ~0, - .vendor = 0x17cc, - .device = 0x2280, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, -}, { - .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), - .class_mask = ~0, - .vendor = 0x17cc, - .device = 0x2282, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - -}, { /* end: all zeroes */ } -}; -MODULE_DEVICE_TABLE (pci, pci_ids); - -/* pci driver glue; this is a "new style" PCI driver module */ -static struct pci_driver net2280_pci_driver = { - .name = (char *) driver_name, - .id_table = pci_ids, - - .probe = net2280_probe, - .remove = net2280_remove, - .shutdown = net2280_shutdown, - - /* FIXME add power management support */ -}; - -MODULE_DESCRIPTION (DRIVER_DESC); -MODULE_AUTHOR ("David Brownell"); -MODULE_LICENSE ("GPL"); - -static int __init init (void) -{ - if (!use_dma) - use_dma_chaining = 0; - return pci_register_driver (&net2280_pci_driver); -} -module_init (init); - -static void __exit cleanup (void) -{ - pci_unregister_driver (&net2280_pci_driver); -} -module_exit (cleanup); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/net2280.h b/ANDROID_3.4.5/drivers/usb/gadget/net2280.h deleted file mode 100644 index a844be0d..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/net2280.h +++ /dev/null @@ -1,308 +0,0 @@ -/* - * NetChip 2280 high/full speed USB device controller. - * Unlike many such controllers, this one talks PCI. - */ - -/* - * Copyright (C) 2002 NetChip Technology, Inc. (http://www.netchip.com) - * Copyright (C) 2003 David Brownell - * - * 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 - -/*-------------------------------------------------------------------------*/ - -#ifdef __KERNEL__ - -/* indexed registers [11.10] are accessed indirectly - * caller must own the device lock. - */ - -static inline u32 -get_idx_reg (struct net2280_regs __iomem *regs, u32 index) -{ - writel (index, ®s->idxaddr); - /* NOTE: synchs device/cpu memory views */ - return readl (®s->idxdata); -} - -static inline void -set_idx_reg (struct net2280_regs __iomem *regs, u32 index, u32 value) -{ - writel (index, ®s->idxaddr); - writel (value, ®s->idxdata); - /* posted, may not be visible yet */ -} - -#endif /* __KERNEL__ */ - - -#define REG_DIAG 0x0 -#define RETRY_COUNTER 16 -#define FORCE_PCI_SERR 11 -#define FORCE_PCI_INTERRUPT 10 -#define FORCE_USB_INTERRUPT 9 -#define FORCE_CPU_INTERRUPT 8 -#define ILLEGAL_BYTE_ENABLES 5 -#define FAST_TIMES 4 -#define FORCE_RECEIVE_ERROR 2 -#define FORCE_TRANSMIT_CRC_ERROR 0 -#define REG_FRAME 0x02 /* from last sof */ -#define REG_CHIPREV 0x03 /* in bcd */ -#define REG_HS_NAK_RATE 0x0a /* NAK per N uframes */ - -#define CHIPREV_1 0x0100 -#define CHIPREV_1A 0x0110 - -#ifdef __KERNEL__ - -/* ep a-f highspeed and fullspeed maxpacket, addresses - * computed from ep->num - */ -#define REG_EP_MAXPKT(dev,num) (((num) + 1) * 0x10 + \ - (((dev)->gadget.speed == USB_SPEED_HIGH) ? 0 : 1)) - -/*-------------------------------------------------------------------------*/ - -/* [8.3] for scatter/gather i/o - * use struct net2280_dma_regs bitfields - */ -struct net2280_dma { - __le32 dmacount; - __le32 dmaaddr; /* the buffer */ - __le32 dmadesc; /* next dma descriptor */ - __le32 _reserved; -} __attribute__ ((aligned (16))); - -/*-------------------------------------------------------------------------*/ - -/* DRIVER DATA STRUCTURES and UTILITIES */ - -struct net2280_ep { - struct usb_ep ep; - struct net2280_ep_regs __iomem *regs; - struct net2280_dma_regs __iomem *dma; - struct net2280_dma *dummy; - dma_addr_t td_dma; /* of dummy */ - struct net2280 *dev; - unsigned long irqs; - - /* analogous to a host-side qh */ - struct list_head queue; - const struct usb_endpoint_descriptor *desc; - unsigned num : 8, - fifo_size : 12, - in_fifo_validate : 1, - out_overflow : 1, - stopped : 1, - wedged : 1, - is_in : 1, - is_iso : 1, - responded : 1; -}; - -static inline void allow_status (struct net2280_ep *ep) -{ - /* ep0 only */ - writel ( (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) - | (1 << CLEAR_NAK_OUT_PACKETS) - | (1 << CLEAR_NAK_OUT_PACKETS_MODE) - , &ep->regs->ep_rsp); - ep->stopped = 1; -} - -/* count (<= 4) bytes in the next fifo write will be valid */ -static inline void set_fifo_bytecount (struct net2280_ep *ep, unsigned count) -{ - writeb (count, 2 + (u8 __iomem *) &ep->regs->ep_cfg); -} - -struct net2280_request { - struct usb_request req; - struct net2280_dma *td; - dma_addr_t td_dma; - struct list_head queue; - unsigned mapped : 1, - valid : 1; -}; - -struct net2280 { - /* each pci device provides one gadget, several endpoints */ - struct usb_gadget gadget; - spinlock_t lock; - struct net2280_ep ep [7]; - struct usb_gadget_driver *driver; - unsigned enabled : 1, - protocol_stall : 1, - softconnect : 1, - got_irq : 1, - region : 1; - u16 chiprev; - - /* pci state used to access those endpoints */ - struct pci_dev *pdev; - struct net2280_regs __iomem *regs; - struct net2280_usb_regs __iomem *usb; - struct net2280_pci_regs __iomem *pci; - struct net2280_dma_regs __iomem *dma; - struct net2280_dep_regs __iomem *dep; - struct net2280_ep_regs __iomem *epregs; - - struct pci_pool *requests; - // statistics... -}; - -static inline void set_halt (struct net2280_ep *ep) -{ - /* ep0 and bulk/intr endpoints */ - writel ( (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE) - /* set NAK_OUT for erratum 0114 */ - | ((ep->dev->chiprev == CHIPREV_1) << SET_NAK_OUT_PACKETS) - | (1 << SET_ENDPOINT_HALT) - , &ep->regs->ep_rsp); -} - -static inline void clear_halt (struct net2280_ep *ep) -{ - /* ep0 and bulk/intr endpoints */ - writel ( (1 << CLEAR_ENDPOINT_HALT) - | (1 << CLEAR_ENDPOINT_TOGGLE) - /* unless the gadget driver left a short packet in the - * fifo, this reverses the erratum 0114 workaround. - */ - | ((ep->dev->chiprev == CHIPREV_1) << CLEAR_NAK_OUT_PACKETS) - , &ep->regs->ep_rsp); -} - -#ifdef USE_RDK_LEDS - -static inline void net2280_led_init (struct net2280 *dev) -{ - /* LED3 (green) is on during USB activity. note erratum 0113. */ - writel ((1 << GPIO3_LED_SELECT) - | (1 << GPIO3_OUTPUT_ENABLE) - | (1 << GPIO2_OUTPUT_ENABLE) - | (1 << GPIO1_OUTPUT_ENABLE) - | (1 << GPIO0_OUTPUT_ENABLE) - , &dev->regs->gpioctl); -} - -/* indicate speed with bi-color LED 0/1 */ -static inline -void net2280_led_speed (struct net2280 *dev, enum usb_device_speed speed) -{ - u32 val = readl (&dev->regs->gpioctl); - switch (speed) { - case USB_SPEED_HIGH: /* green */ - val &= ~(1 << GPIO0_DATA); - val |= (1 << GPIO1_DATA); - break; - case USB_SPEED_FULL: /* red */ - val &= ~(1 << GPIO1_DATA); - val |= (1 << GPIO0_DATA); - break; - default: /* (off/black) */ - val &= ~((1 << GPIO1_DATA) | (1 << GPIO0_DATA)); - break; - } - writel (val, &dev->regs->gpioctl); -} - -/* indicate power with LED 2 */ -static inline void net2280_led_active (struct net2280 *dev, int is_active) -{ - u32 val = readl (&dev->regs->gpioctl); - - // FIXME this LED never seems to turn on. - if (is_active) - val |= GPIO2_DATA; - else - val &= ~GPIO2_DATA; - writel (val, &dev->regs->gpioctl); -} -static inline void net2280_led_shutdown (struct net2280 *dev) -{ - /* turn off all four GPIO*_DATA bits */ - writel (readl (&dev->regs->gpioctl) & ~0x0f, - &dev->regs->gpioctl); -} - -#else - -#define net2280_led_init(dev) do { } while (0) -#define net2280_led_speed(dev, speed) do { } while (0) -#define net2280_led_shutdown(dev) do { } while (0) - -#endif - -/*-------------------------------------------------------------------------*/ - -#define xprintk(dev,level,fmt,args...) \ - printk(level "%s %s: " fmt , driver_name , \ - pci_name(dev->pdev) , ## args) - -#ifdef DEBUG -#undef DEBUG -#define DEBUG(dev,fmt,args...) \ - xprintk(dev , KERN_DEBUG , fmt , ## args) -#else -#define DEBUG(dev,fmt,args...) \ - do { } while (0) -#endif /* DEBUG */ - -#ifdef VERBOSE -#define VDEBUG DEBUG -#else -#define VDEBUG(dev,fmt,args...) \ - do { } while (0) -#endif /* VERBOSE */ - -#define ERROR(dev,fmt,args...) \ - xprintk(dev , KERN_ERR , fmt , ## args) -#define WARNING(dev,fmt,args...) \ - xprintk(dev , KERN_WARNING , fmt , ## args) -#define INFO(dev,fmt,args...) \ - xprintk(dev , KERN_INFO , fmt , ## args) - -/*-------------------------------------------------------------------------*/ - -static inline void start_out_naking (struct net2280_ep *ep) -{ - /* NOTE: hardware races lurk here, and PING protocol issues */ - writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp); - /* synch with device */ - readl (&ep->regs->ep_rsp); -} - -#ifdef DEBUG -static inline void assert_out_naking (struct net2280_ep *ep, const char *where) -{ - u32 tmp = readl (&ep->regs->ep_stat); - - if ((tmp & (1 << NAK_OUT_PACKETS)) == 0) { - DEBUG (ep->dev, "%s %s %08x !NAK\n", - ep->ep.name, where, tmp); - writel ((1 << SET_NAK_OUT_PACKETS), - &ep->regs->ep_rsp); - } -} -#define ASSERT_OUT_NAKING(ep) assert_out_naking(ep,__func__) -#else -#define ASSERT_OUT_NAKING(ep) do {} while (0) -#endif - -static inline void stop_out_naking (struct net2280_ep *ep) -{ - u32 tmp; - - tmp = readl (&ep->regs->ep_stat); - if ((tmp & (1 << NAK_OUT_PACKETS)) != 0) - writel ((1 << CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp); -} - -#endif /* __KERNEL__ */ diff --git a/ANDROID_3.4.5/drivers/usb/gadget/nokia.c b/ANDROID_3.4.5/drivers/usb/gadget/nokia.c deleted file mode 100644 index c7fb7723..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/nokia.c +++ /dev/null @@ -1,259 +0,0 @@ -/* - * nokia.c -- Nokia Composite Gadget Driver - * - * Copyright (C) 2008-2010 Nokia Corporation - * Contact: Felipe Balbi - * - * This gadget driver borrows from serial.c which is: - * - * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com) - * Copyright (C) 2008 by David Brownell - * Copyright (C) 2008 by Nokia Corporation - * - * This software is distributed under the terms of the GNU General - * Public License ("GPL") as published by the Free Software Foundation, - * version 2 of that License. - */ - -#include -#include -#include - -#include "u_serial.h" -#include "u_ether.h" -#include "u_phonet.h" -#include "gadget_chips.h" - -/* Defines */ - -#define NOKIA_VERSION_NUM 0x0211 -#define NOKIA_LONG_NAME "N900 (PC-Suite Mode)" - -/*-------------------------------------------------------------------------*/ - -/* - * 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_serial.c" -#include "f_acm.c" -#include "f_ecm.c" -#include "f_obex.c" -#include "f_serial.c" -#include "f_phonet.c" -#include "u_ether.c" - -/*-------------------------------------------------------------------------*/ - -#define NOKIA_VENDOR_ID 0x0421 /* Nokia */ -#define NOKIA_PRODUCT_ID 0x01c8 /* Nokia Gadget */ - -/* string IDs are assigned dynamically */ - -#define STRING_MANUFACTURER_IDX 0 -#define STRING_PRODUCT_IDX 1 -#define STRING_DESCRIPTION_IDX 2 - -static char manufacturer_nokia[] = "Nokia"; -static const char product_nokia[] = NOKIA_LONG_NAME; -static const char description_nokia[] = "PC-Suite Configuration"; - -static struct usb_string strings_dev[] = { - [STRING_MANUFACTURER_IDX].s = manufacturer_nokia, - [STRING_PRODUCT_IDX].s = NOKIA_LONG_NAME, - [STRING_DESCRIPTION_IDX].s = description_nokia, - { } /* end of list */ -}; - -static struct usb_gadget_strings stringtab_dev = { - .language = 0x0409, /* en-us */ - .strings = strings_dev, -}; - -static struct usb_gadget_strings *dev_strings[] = { - &stringtab_dev, - NULL, -}; - -static struct usb_device_descriptor device_desc = { - .bLength = USB_DT_DEVICE_SIZE, - .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = __constant_cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_COMM, - .idVendor = __constant_cpu_to_le16(NOKIA_VENDOR_ID), - .idProduct = __constant_cpu_to_le16(NOKIA_PRODUCT_ID), - /* .iManufacturer = DYNAMIC */ - /* .iProduct = DYNAMIC */ - .bNumConfigurations = 1, -}; - -/*-------------------------------------------------------------------------*/ - -/* Module */ -MODULE_DESCRIPTION("Nokia composite gadget driver for N900"); -MODULE_AUTHOR("Felipe Balbi"); -MODULE_LICENSE("GPL"); - -/*-------------------------------------------------------------------------*/ - -static u8 hostaddr[ETH_ALEN]; - -static int __init nokia_bind_config(struct usb_configuration *c) -{ - int status = 0; - - status = phonet_bind_config(c); - if (status) - printk(KERN_DEBUG "could not bind phonet config\n"); - - status = obex_bind_config(c, 0); - if (status) - printk(KERN_DEBUG "could not bind obex config %d\n", 0); - - status = obex_bind_config(c, 1); - if (status) - printk(KERN_DEBUG "could not bind obex config %d\n", 0); - - status = acm_bind_config(c, 2); - if (status) - printk(KERN_DEBUG "could not bind acm config\n"); - - status = ecm_bind_config(c, hostaddr); - if (status) - printk(KERN_DEBUG "could not bind ecm config\n"); - - return status; -} - -static struct usb_configuration nokia_config_500ma_driver = { - .label = "Bus Powered", - .bConfigurationValue = 1, - /* .iConfiguration = DYNAMIC */ - .bmAttributes = USB_CONFIG_ATT_ONE, - .bMaxPower = 250, /* 500mA */ -}; - -static struct usb_configuration nokia_config_100ma_driver = { - .label = "Self Powered", - .bConfigurationValue = 2, - /* .iConfiguration = DYNAMIC */ - .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, - .bMaxPower = 50, /* 100 mA */ -}; - -static int __init nokia_bind(struct usb_composite_dev *cdev) -{ - int gcnum; - struct usb_gadget *gadget = cdev->gadget; - int status; - - status = gphonet_setup(cdev->gadget); - if (status < 0) - goto err_phonet; - - status = gserial_setup(cdev->gadget, 3); - if (status < 0) - goto err_serial; - - status = gether_setup(cdev->gadget, hostaddr); - if (status < 0) - goto err_ether; - - status = usb_string_id(cdev); - if (status < 0) - goto err_usb; - strings_dev[STRING_MANUFACTURER_IDX].id = status; - - device_desc.iManufacturer = status; - - status = usb_string_id(cdev); - if (status < 0) - goto err_usb; - strings_dev[STRING_PRODUCT_IDX].id = status; - - device_desc.iProduct = status; - - /* config description */ - status = usb_string_id(cdev); - if (status < 0) - goto err_usb; - strings_dev[STRING_DESCRIPTION_IDX].id = status; - - nokia_config_500ma_driver.iConfiguration = status; - nokia_config_100ma_driver.iConfiguration = status; - - /* set up other descriptors */ - gcnum = usb_gadget_controller_number(gadget); - if (gcnum >= 0) - device_desc.bcdDevice = cpu_to_le16(NOKIA_VERSION_NUM); - else { - /* this should only work with hw that supports altsettings - * and several endpoints, anything else, panic. - */ - pr_err("nokia_bind: controller '%s' not recognized\n", - gadget->name); - goto err_usb; - } - - /* finally register the configuration */ - status = usb_add_config(cdev, &nokia_config_500ma_driver, - nokia_bind_config); - if (status < 0) - goto err_usb; - - status = usb_add_config(cdev, &nokia_config_100ma_driver, - nokia_bind_config); - if (status < 0) - goto err_usb; - - dev_info(&gadget->dev, "%s\n", NOKIA_LONG_NAME); - - return 0; - -err_usb: - gether_cleanup(); -err_ether: - gserial_cleanup(); -err_serial: - gphonet_cleanup(); -err_phonet: - return status; -} - -static int __exit nokia_unbind(struct usb_composite_dev *cdev) -{ - gphonet_cleanup(); - gserial_cleanup(); - gether_cleanup(); - - return 0; -} - -static struct usb_composite_driver nokia_driver = { - .name = "g_nokia", - .dev = &device_desc, - .strings = dev_strings, - .max_speed = USB_SPEED_HIGH, - .unbind = __exit_p(nokia_unbind), -}; - -static int __init nokia_init(void) -{ - return usb_composite_probe(&nokia_driver, nokia_bind); -} -module_init(nokia_init); - -static void __exit nokia_cleanup(void) -{ - usb_composite_unregister(&nokia_driver); -} -module_exit(nokia_cleanup); - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/omap_udc.c b/ANDROID_3.4.5/drivers/usb/gadget/omap_udc.c deleted file mode 100644 index 3b4b6dd0..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/omap_udc.c +++ /dev/null @@ -1,3148 +0,0 @@ -/* - * omap_udc.c -- for OMAP full speed udc; most chips support OTG. - * - * Copyright (C) 2004 Texas Instruments, Inc. - * Copyright (C) 2004-2005 David Brownell - * - * OMAP2 & DMA support by Kyungmin Park - * - * 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. - */ - -#undef DEBUG -#undef VERBOSE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "omap_udc.h" - -#undef USB_TRACE - -/* bulk DMA seems to be behaving for both IN and OUT */ -#define USE_DMA - -/* ISO too */ -#define USE_ISO - -#define DRIVER_DESC "OMAP UDC driver" -#define DRIVER_VERSION "4 October 2004" - -#define DMA_ADDR_INVALID (~(dma_addr_t)0) - -#define OMAP2_DMA_CH(ch) (((ch) - 1) << 1) -#define OMAP24XX_DMA(name, ch) (OMAP24XX_DMA_##name + OMAP2_DMA_CH(ch)) - -/* - * The OMAP UDC needs _very_ early endpoint setup: before enabling the - * D+ pullup to allow enumeration. That's too early for the gadget - * framework to use from usb_endpoint_enable(), which happens after - * enumeration as part of activating an interface. (But if we add an - * optional new "UDC not yet running" state to the gadget driver model, - * even just during driver binding, the endpoint autoconfig logic is the - * natural spot to manufacture new endpoints.) - * - * So instead of using endpoint enable calls to control the hardware setup, - * this driver defines a "fifo mode" parameter. It's used during driver - * initialization to choose among a set of pre-defined endpoint configs. - * See omap_udc_setup() for available modes, or to add others. That code - * lives in an init section, so use this driver as a module if you need - * to change the fifo mode after the kernel boots. - * - * Gadget drivers normally ignore endpoints they don't care about, and - * won't include them in configuration descriptors. That means only - * misbehaving hosts would even notice they exist. - */ -#ifdef USE_ISO -static unsigned fifo_mode = 3; -#else -static unsigned fifo_mode = 0; -#endif - -/* "modprobe omap_udc fifo_mode=42", or else as a kernel - * boot parameter "omap_udc:fifo_mode=42" - */ -module_param (fifo_mode, uint, 0); -MODULE_PARM_DESC (fifo_mode, "endpoint configuration"); - -#ifdef USE_DMA -static bool use_dma = 1; - -/* "modprobe omap_udc use_dma=y", or else as a kernel - * boot parameter "omap_udc:use_dma=y" - */ -module_param (use_dma, bool, 0); -MODULE_PARM_DESC (use_dma, "enable/disable DMA"); -#else /* !USE_DMA */ - -/* save a bit of code */ -#define use_dma 0 -#endif /* !USE_DMA */ - - -static const char driver_name [] = "omap_udc"; -static const char driver_desc [] = DRIVER_DESC; - -/*-------------------------------------------------------------------------*/ - -/* there's a notion of "current endpoint" for modifying endpoint - * state, and PIO access to its FIFO. - */ - -static void use_ep(struct omap_ep *ep, u16 select) -{ - u16 num = ep->bEndpointAddress & 0x0f; - - if (ep->bEndpointAddress & USB_DIR_IN) - num |= UDC_EP_DIR; - omap_writew(num | select, UDC_EP_NUM); - /* when select, MUST deselect later !! */ -} - -static inline void deselect_ep(void) -{ - u16 w; - - w = omap_readw(UDC_EP_NUM); - w &= ~UDC_EP_SEL; - omap_writew(w, UDC_EP_NUM); - /* 6 wait states before TX will happen */ -} - -static void dma_channel_claim(struct omap_ep *ep, unsigned preferred); - -/*-------------------------------------------------------------------------*/ - -static int omap_ep_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct omap_ep *ep = container_of(_ep, struct omap_ep, ep); - struct omap_udc *udc; - unsigned long flags; - u16 maxp; - - /* catch various bogus parameters */ - if (!_ep || !desc || ep->desc - || desc->bDescriptorType != USB_DT_ENDPOINT - || ep->bEndpointAddress != desc->bEndpointAddress - || ep->maxpacket < usb_endpoint_maxp(desc)) { - DBG("%s, bad ep or descriptor\n", __func__); - return -EINVAL; - } - maxp = usb_endpoint_maxp(desc); - if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK - && maxp != ep->maxpacket) - || usb_endpoint_maxp(desc) > ep->maxpacket - || !desc->wMaxPacketSize) { - DBG("%s, bad %s maxpacket\n", __func__, _ep->name); - return -ERANGE; - } - -#ifdef USE_ISO - if ((desc->bmAttributes == USB_ENDPOINT_XFER_ISOC - && desc->bInterval != 1)) { - /* hardware wants period = 1; USB allows 2^(Interval-1) */ - DBG("%s, unsupported ISO period %dms\n", _ep->name, - 1 << (desc->bInterval - 1)); - return -EDOM; - } -#else - if (desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { - DBG("%s, ISO nyet\n", _ep->name); - return -EDOM; - } -#endif - - /* xfer types must match, except that interrupt ~= bulk */ - if (ep->bmAttributes != desc->bmAttributes - && ep->bmAttributes != USB_ENDPOINT_XFER_BULK - && desc->bmAttributes != USB_ENDPOINT_XFER_INT) { - DBG("%s, %s type mismatch\n", __func__, _ep->name); - return -EINVAL; - } - - udc = ep->udc; - if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) { - DBG("%s, bogus device state\n", __func__); - return -ESHUTDOWN; - } - - spin_lock_irqsave(&udc->lock, flags); - - ep->desc = desc; - ep->irqs = 0; - ep->stopped = 0; - ep->ep.maxpacket = maxp; - - /* set endpoint to initial state */ - ep->dma_channel = 0; - ep->has_dma = 0; - ep->lch = -1; - use_ep(ep, UDC_EP_SEL); - omap_writew(udc->clr_halt, UDC_CTRL); - ep->ackwait = 0; - deselect_ep(); - - if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) - list_add(&ep->iso, &udc->iso); - - /* maybe assign a DMA channel to this endpoint */ - if (use_dma && desc->bmAttributes == USB_ENDPOINT_XFER_BULK) - /* FIXME ISO can dma, but prefers first channel */ - dma_channel_claim(ep, 0); - - /* PIO OUT may RX packets */ - if (desc->bmAttributes != USB_ENDPOINT_XFER_ISOC - && !ep->has_dma - && !(ep->bEndpointAddress & USB_DIR_IN)) { - omap_writew(UDC_SET_FIFO_EN, UDC_CTRL); - ep->ackwait = 1 + ep->double_buf; - } - - spin_unlock_irqrestore(&udc->lock, flags); - VDBG("%s enabled\n", _ep->name); - return 0; -} - -static void nuke(struct omap_ep *, int status); - -static int omap_ep_disable(struct usb_ep *_ep) -{ - struct omap_ep *ep = container_of(_ep, struct omap_ep, ep); - unsigned long flags; - - if (!_ep || !ep->desc) { - DBG("%s, %s not enabled\n", __func__, - _ep ? ep->ep.name : NULL); - return -EINVAL; - } - - spin_lock_irqsave(&ep->udc->lock, flags); - ep->desc = NULL; - ep->ep.desc = NULL; - nuke (ep, -ESHUTDOWN); - ep->ep.maxpacket = ep->maxpacket; - ep->has_dma = 0; - omap_writew(UDC_SET_HALT, UDC_CTRL); - list_del_init(&ep->iso); - del_timer(&ep->timer); - - spin_unlock_irqrestore(&ep->udc->lock, flags); - - VDBG("%s disabled\n", _ep->name); - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static struct usb_request * -omap_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) -{ - struct omap_req *req; - - req = kzalloc(sizeof(*req), gfp_flags); - if (req) { - req->req.dma = DMA_ADDR_INVALID; - INIT_LIST_HEAD (&req->queue); - } - return &req->req; -} - -static void -omap_free_request(struct usb_ep *ep, struct usb_request *_req) -{ - struct omap_req *req = container_of(_req, struct omap_req, req); - - if (_req) - kfree (req); -} - -/*-------------------------------------------------------------------------*/ - -static void -done(struct omap_ep *ep, struct omap_req *req, int status) -{ - unsigned stopped = ep->stopped; - - list_del_init(&req->queue); - - if (req->req.status == -EINPROGRESS) - req->req.status = status; - else - status = req->req.status; - - if (use_dma && ep->has_dma) { - if (req->mapped) { - dma_unmap_single(ep->udc->gadget.dev.parent, - req->req.dma, req->req.length, - (ep->bEndpointAddress & USB_DIR_IN) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - req->req.dma = DMA_ADDR_INVALID; - req->mapped = 0; - } else - dma_sync_single_for_cpu(ep->udc->gadget.dev.parent, - req->req.dma, req->req.length, - (ep->bEndpointAddress & USB_DIR_IN) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - } - -#ifndef USB_TRACE - if (status && status != -ESHUTDOWN) -#endif - VDBG("complete %s req %p stat %d len %u/%u\n", - ep->ep.name, &req->req, status, - req->req.actual, req->req.length); - - /* don't modify queue heads during completion callback */ - ep->stopped = 1; - spin_unlock(&ep->udc->lock); - req->req.complete(&ep->ep, &req->req); - spin_lock(&ep->udc->lock); - ep->stopped = stopped; -} - -/*-------------------------------------------------------------------------*/ - -#define UDC_FIFO_FULL (UDC_NON_ISO_FIFO_FULL | UDC_ISO_FIFO_FULL) -#define UDC_FIFO_UNWRITABLE (UDC_EP_HALTED | UDC_FIFO_FULL) - -#define FIFO_EMPTY (UDC_NON_ISO_FIFO_EMPTY | UDC_ISO_FIFO_EMPTY) -#define FIFO_UNREADABLE (UDC_EP_HALTED | FIFO_EMPTY) - -static inline int -write_packet(u8 *buf, struct omap_req *req, unsigned max) -{ - unsigned len; - u16 *wp; - - len = min(req->req.length - req->req.actual, max); - req->req.actual += len; - - max = len; - if (likely((((int)buf) & 1) == 0)) { - wp = (u16 *)buf; - while (max >= 2) { - omap_writew(*wp++, UDC_DATA); - max -= 2; - } - buf = (u8 *)wp; - } - while (max--) - omap_writeb(*buf++, UDC_DATA); - return len; -} - -// FIXME change r/w fifo calling convention - - -// return: 0 = still running, 1 = completed, negative = errno -static int write_fifo(struct omap_ep *ep, struct omap_req *req) -{ - u8 *buf; - unsigned count; - int is_last; - u16 ep_stat; - - buf = req->req.buf + req->req.actual; - prefetch(buf); - - /* PIO-IN isn't double buffered except for iso */ - ep_stat = omap_readw(UDC_STAT_FLG); - if (ep_stat & UDC_FIFO_UNWRITABLE) - return 0; - - count = ep->ep.maxpacket; - count = write_packet(buf, req, count); - omap_writew(UDC_SET_FIFO_EN, UDC_CTRL); - ep->ackwait = 1; - - /* last packet is often short (sometimes a zlp) */ - if (count != ep->ep.maxpacket) - is_last = 1; - else if (req->req.length == req->req.actual - && !req->req.zero) - is_last = 1; - else - is_last = 0; - - /* NOTE: requests complete when all IN data is in a - * FIFO (or sometimes later, if a zlp was needed). - * Use usb_ep_fifo_status() where needed. - */ - if (is_last) - done(ep, req, 0); - return is_last; -} - -static inline int -read_packet(u8 *buf, struct omap_req *req, unsigned avail) -{ - unsigned len; - u16 *wp; - - len = min(req->req.length - req->req.actual, avail); - req->req.actual += len; - avail = len; - - if (likely((((int)buf) & 1) == 0)) { - wp = (u16 *)buf; - while (avail >= 2) { - *wp++ = omap_readw(UDC_DATA); - avail -= 2; - } - buf = (u8 *)wp; - } - while (avail--) - *buf++ = omap_readb(UDC_DATA); - return len; -} - -// return: 0 = still running, 1 = queue empty, negative = errno -static int read_fifo(struct omap_ep *ep, struct omap_req *req) -{ - u8 *buf; - unsigned count, avail; - int is_last; - - buf = req->req.buf + req->req.actual; - prefetchw(buf); - - for (;;) { - u16 ep_stat = omap_readw(UDC_STAT_FLG); - - is_last = 0; - if (ep_stat & FIFO_EMPTY) { - if (!ep->double_buf) - break; - ep->fnf = 1; - } - if (ep_stat & UDC_EP_HALTED) - break; - - if (ep_stat & UDC_FIFO_FULL) - avail = ep->ep.maxpacket; - else { - avail = omap_readw(UDC_RXFSTAT); - ep->fnf = ep->double_buf; - } - count = read_packet(buf, req, avail); - - /* partial packet reads may not be errors */ - if (count < ep->ep.maxpacket) { - is_last = 1; - /* overflowed this request? flush extra data */ - if (count != avail) { - req->req.status = -EOVERFLOW; - avail -= count; - while (avail--) - omap_readw(UDC_DATA); - } - } else if (req->req.length == req->req.actual) - is_last = 1; - else - is_last = 0; - - if (!ep->bEndpointAddress) - break; - if (is_last) - done(ep, req, 0); - break; - } - return is_last; -} - -/*-------------------------------------------------------------------------*/ - -static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start) -{ - dma_addr_t end; - - /* IN-DMA needs this on fault/cancel paths, so 15xx misreports - * the last transfer's bytecount by more than a FIFO's worth. - */ - if (cpu_is_omap15xx()) - return 0; - - end = omap_get_dma_src_pos(ep->lch); - if (end == ep->dma_counter) - return 0; - - end |= start & (0xffff << 16); - if (end < start) - end += 0x10000; - return end - start; -} - -static u16 dma_dest_len(struct omap_ep *ep, dma_addr_t start) -{ - dma_addr_t end; - - end = omap_get_dma_dst_pos(ep->lch); - if (end == ep->dma_counter) - return 0; - - end |= start & (0xffff << 16); - if (cpu_is_omap15xx()) - end++; - if (end < start) - end += 0x10000; - return end - start; -} - - -/* Each USB transfer request using DMA maps to one or more DMA transfers. - * When DMA completion isn't request completion, the UDC continues with - * the next DMA transfer for that USB transfer. - */ - -static void next_in_dma(struct omap_ep *ep, struct omap_req *req) -{ - u16 txdma_ctrl, w; - unsigned length = req->req.length - req->req.actual; - const int sync_mode = cpu_is_omap15xx() - ? OMAP_DMA_SYNC_FRAME - : OMAP_DMA_SYNC_ELEMENT; - int dma_trigger = 0; - - if (cpu_is_omap24xx()) - dma_trigger = OMAP24XX_DMA(USB_W2FC_TX0, ep->dma_channel); - - /* measure length in either bytes or packets */ - if ((cpu_is_omap16xx() && length <= UDC_TXN_TSC) - || (cpu_is_omap24xx() && length < ep->maxpacket) - || (cpu_is_omap15xx() && length < ep->maxpacket)) { - txdma_ctrl = UDC_TXN_EOT | length; - omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, - length, 1, sync_mode, dma_trigger, 0); - } else { - length = min(length / ep->maxpacket, - (unsigned) UDC_TXN_TSC + 1); - txdma_ctrl = length; - omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16, - ep->ep.maxpacket >> 1, length, sync_mode, - dma_trigger, 0); - length *= ep->maxpacket; - } - omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF, - OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual, - 0, 0); - - omap_start_dma(ep->lch); - ep->dma_counter = omap_get_dma_src_pos(ep->lch); - w = omap_readw(UDC_DMA_IRQ_EN); - w |= UDC_TX_DONE_IE(ep->dma_channel); - omap_writew(w, UDC_DMA_IRQ_EN); - omap_writew(UDC_TXN_START | txdma_ctrl, UDC_TXDMA(ep->dma_channel)); - req->dma_bytes = length; -} - -static void finish_in_dma(struct omap_ep *ep, struct omap_req *req, int status) -{ - u16 w; - - if (status == 0) { - req->req.actual += req->dma_bytes; - - /* return if this request needs to send data or zlp */ - if (req->req.actual < req->req.length) - return; - if (req->req.zero - && req->dma_bytes != 0 - && (req->req.actual % ep->maxpacket) == 0) - return; - } else - req->req.actual += dma_src_len(ep, req->req.dma - + req->req.actual); - - /* tx completion */ - omap_stop_dma(ep->lch); - w = omap_readw(UDC_DMA_IRQ_EN); - w &= ~UDC_TX_DONE_IE(ep->dma_channel); - omap_writew(w, UDC_DMA_IRQ_EN); - done(ep, req, status); -} - -static void next_out_dma(struct omap_ep *ep, struct omap_req *req) -{ - unsigned packets = req->req.length - req->req.actual; - int dma_trigger = 0; - u16 w; - - if (cpu_is_omap24xx()) - dma_trigger = OMAP24XX_DMA(USB_W2FC_RX0, ep->dma_channel); - - /* NOTE: we filtered out "short reads" before, so we know - * the buffer has only whole numbers of packets. - * except MODE SELECT(6) sent the 24 bytes data in OMAP24XX DMA mode - */ - if (cpu_is_omap24xx() && packets < ep->maxpacket) { - omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8, - packets, 1, OMAP_DMA_SYNC_ELEMENT, - dma_trigger, 0); - req->dma_bytes = packets; - } else { - /* set up this DMA transfer, enable the fifo, start */ - packets /= ep->ep.maxpacket; - packets = min(packets, (unsigned)UDC_RXN_TC + 1); - req->dma_bytes = packets * ep->ep.maxpacket; - omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16, - ep->ep.maxpacket >> 1, packets, - OMAP_DMA_SYNC_ELEMENT, - dma_trigger, 0); - } - omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF, - OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual, - 0, 0); - ep->dma_counter = omap_get_dma_dst_pos(ep->lch); - - omap_writew(UDC_RXN_STOP | (packets - 1), UDC_RXDMA(ep->dma_channel)); - w = omap_readw(UDC_DMA_IRQ_EN); - w |= UDC_RX_EOT_IE(ep->dma_channel); - omap_writew(w, UDC_DMA_IRQ_EN); - omap_writew(ep->bEndpointAddress & 0xf, UDC_EP_NUM); - omap_writew(UDC_SET_FIFO_EN, UDC_CTRL); - - omap_start_dma(ep->lch); -} - -static void -finish_out_dma(struct omap_ep *ep, struct omap_req *req, int status, int one) -{ - u16 count, w; - - if (status == 0) - ep->dma_counter = (u16) (req->req.dma + req->req.actual); - count = dma_dest_len(ep, req->req.dma + req->req.actual); - count += req->req.actual; - if (one) - count--; - if (count <= req->req.length) - req->req.actual = count; - - if (count != req->dma_bytes || status) - omap_stop_dma(ep->lch); - - /* if this wasn't short, request may need another transfer */ - else if (req->req.actual < req->req.length) - return; - - /* rx completion */ - w = omap_readw(UDC_DMA_IRQ_EN); - w &= ~UDC_RX_EOT_IE(ep->dma_channel); - omap_writew(w, UDC_DMA_IRQ_EN); - done(ep, req, status); -} - -static void dma_irq(struct omap_udc *udc, u16 irq_src) -{ - u16 dman_stat = omap_readw(UDC_DMAN_STAT); - struct omap_ep *ep; - struct omap_req *req; - - /* IN dma: tx to host */ - if (irq_src & UDC_TXN_DONE) { - ep = &udc->ep[16 + UDC_DMA_TX_SRC(dman_stat)]; - ep->irqs++; - /* can see TXN_DONE after dma abort */ - if (!list_empty(&ep->queue)) { - req = container_of(ep->queue.next, - struct omap_req, queue); - finish_in_dma(ep, req, 0); - } - omap_writew(UDC_TXN_DONE, UDC_IRQ_SRC); - - if (!list_empty (&ep->queue)) { - req = container_of(ep->queue.next, - struct omap_req, queue); - next_in_dma(ep, req); - } - } - - /* OUT dma: rx from host */ - if (irq_src & UDC_RXN_EOT) { - ep = &udc->ep[UDC_DMA_RX_SRC(dman_stat)]; - ep->irqs++; - /* can see RXN_EOT after dma abort */ - if (!list_empty(&ep->queue)) { - req = container_of(ep->queue.next, - struct omap_req, queue); - finish_out_dma(ep, req, 0, dman_stat & UDC_DMA_RX_SB); - } - omap_writew(UDC_RXN_EOT, UDC_IRQ_SRC); - - if (!list_empty (&ep->queue)) { - req = container_of(ep->queue.next, - struct omap_req, queue); - next_out_dma(ep, req); - } - } - - if (irq_src & UDC_RXN_CNT) { - ep = &udc->ep[UDC_DMA_RX_SRC(dman_stat)]; - ep->irqs++; - /* omap15xx does this unasked... */ - VDBG("%s, RX_CNT irq?\n", ep->ep.name); - omap_writew(UDC_RXN_CNT, UDC_IRQ_SRC); - } -} - -static void dma_error(int lch, u16 ch_status, void *data) -{ - struct omap_ep *ep = data; - - /* if ch_status & OMAP_DMA_DROP_IRQ ... */ - /* if ch_status & OMAP1_DMA_TOUT_IRQ ... */ - ERR("%s dma error, lch %d status %02x\n", ep->ep.name, lch, ch_status); - - /* complete current transfer ... */ -} - -static void dma_channel_claim(struct omap_ep *ep, unsigned channel) -{ - u16 reg; - int status, restart, is_in; - int dma_channel; - - is_in = ep->bEndpointAddress & USB_DIR_IN; - if (is_in) - reg = omap_readw(UDC_TXDMA_CFG); - else - reg = omap_readw(UDC_RXDMA_CFG); - reg |= UDC_DMA_REQ; /* "pulse" activated */ - - ep->dma_channel = 0; - ep->lch = -1; - if (channel == 0 || channel > 3) { - if ((reg & 0x0f00) == 0) - channel = 3; - else if ((reg & 0x00f0) == 0) - channel = 2; - else if ((reg & 0x000f) == 0) /* preferred for ISO */ - channel = 1; - else { - status = -EMLINK; - goto just_restart; - } - } - reg |= (0x0f & ep->bEndpointAddress) << (4 * (channel - 1)); - ep->dma_channel = channel; - - if (is_in) { - if (cpu_is_omap24xx()) - dma_channel = OMAP24XX_DMA(USB_W2FC_TX0, channel); - else - dma_channel = OMAP_DMA_USB_W2FC_TX0 - 1 + channel; - status = omap_request_dma(dma_channel, - ep->ep.name, dma_error, ep, &ep->lch); - if (status == 0) { - omap_writew(reg, UDC_TXDMA_CFG); - /* EMIFF or SDRC */ - omap_set_dma_src_burst_mode(ep->lch, - OMAP_DMA_DATA_BURST_4); - omap_set_dma_src_data_pack(ep->lch, 1); - /* TIPB */ - omap_set_dma_dest_params(ep->lch, - OMAP_DMA_PORT_TIPB, - OMAP_DMA_AMODE_CONSTANT, - UDC_DATA_DMA, - 0, 0); - } - } else { - if (cpu_is_omap24xx()) - dma_channel = OMAP24XX_DMA(USB_W2FC_RX0, channel); - else - dma_channel = OMAP_DMA_USB_W2FC_RX0 - 1 + channel; - - status = omap_request_dma(dma_channel, - ep->ep.name, dma_error, ep, &ep->lch); - if (status == 0) { - omap_writew(reg, UDC_RXDMA_CFG); - /* TIPB */ - omap_set_dma_src_params(ep->lch, - OMAP_DMA_PORT_TIPB, - OMAP_DMA_AMODE_CONSTANT, - UDC_DATA_DMA, - 0, 0); - /* EMIFF or SDRC */ - omap_set_dma_dest_burst_mode(ep->lch, - OMAP_DMA_DATA_BURST_4); - omap_set_dma_dest_data_pack(ep->lch, 1); - } - } - if (status) - ep->dma_channel = 0; - else { - ep->has_dma = 1; - omap_disable_dma_irq(ep->lch, OMAP_DMA_BLOCK_IRQ); - - /* channel type P: hw synch (fifo) */ - if (cpu_class_is_omap1() && !cpu_is_omap15xx()) - omap_set_dma_channel_mode(ep->lch, OMAP_DMA_LCH_P); - } - -just_restart: - /* restart any queue, even if the claim failed */ - restart = !ep->stopped && !list_empty(&ep->queue); - - if (status) - DBG("%s no dma channel: %d%s\n", ep->ep.name, status, - restart ? " (restart)" : ""); - else - DBG("%s claimed %cxdma%d lch %d%s\n", ep->ep.name, - is_in ? 't' : 'r', - ep->dma_channel - 1, ep->lch, - restart ? " (restart)" : ""); - - if (restart) { - struct omap_req *req; - req = container_of(ep->queue.next, struct omap_req, queue); - if (ep->has_dma) - (is_in ? next_in_dma : next_out_dma)(ep, req); - else { - use_ep(ep, UDC_EP_SEL); - (is_in ? write_fifo : read_fifo)(ep, req); - deselect_ep(); - if (!is_in) { - omap_writew(UDC_SET_FIFO_EN, UDC_CTRL); - ep->ackwait = 1 + ep->double_buf; - } - /* IN: 6 wait states before it'll tx */ - } - } -} - -static void dma_channel_release(struct omap_ep *ep) -{ - int shift = 4 * (ep->dma_channel - 1); - u16 mask = 0x0f << shift; - struct omap_req *req; - int active; - - /* abort any active usb transfer request */ - if (!list_empty(&ep->queue)) - req = container_of(ep->queue.next, struct omap_req, queue); - else - req = NULL; - - active = omap_get_dma_active_status(ep->lch); - - DBG("%s release %s %cxdma%d %p\n", ep->ep.name, - active ? "active" : "idle", - (ep->bEndpointAddress & USB_DIR_IN) ? 't' : 'r', - ep->dma_channel - 1, req); - - /* NOTE: re-setting RX_REQ/TX_REQ because of a chip bug (before - * OMAP 1710 ES2.0) where reading the DMA_CFG can clear them. - */ - - /* wait till current packet DMA finishes, and fifo empties */ - if (ep->bEndpointAddress & USB_DIR_IN) { - omap_writew((omap_readw(UDC_TXDMA_CFG) & ~mask) | UDC_DMA_REQ, - UDC_TXDMA_CFG); - - if (req) { - finish_in_dma(ep, req, -ECONNRESET); - - /* clear FIFO; hosts probably won't empty it */ - use_ep(ep, UDC_EP_SEL); - omap_writew(UDC_CLR_EP, UDC_CTRL); - deselect_ep(); - } - while (omap_readw(UDC_TXDMA_CFG) & mask) - udelay(10); - } else { - omap_writew((omap_readw(UDC_RXDMA_CFG) & ~mask) | UDC_DMA_REQ, - UDC_RXDMA_CFG); - - /* dma empties the fifo */ - while (omap_readw(UDC_RXDMA_CFG) & mask) - udelay(10); - if (req) - finish_out_dma(ep, req, -ECONNRESET, 0); - } - omap_free_dma(ep->lch); - ep->dma_channel = 0; - ep->lch = -1; - /* has_dma still set, till endpoint is fully quiesced */ -} - - -/*-------------------------------------------------------------------------*/ - -static int -omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) -{ - struct omap_ep *ep = container_of(_ep, struct omap_ep, ep); - struct omap_req *req = container_of(_req, struct omap_req, req); - struct omap_udc *udc; - unsigned long flags; - int is_iso = 0; - - /* catch various bogus parameters */ - if (!_req || !req->req.complete || !req->req.buf - || !list_empty(&req->queue)) { - DBG("%s, bad params\n", __func__); - return -EINVAL; - } - if (!_ep || (!ep->desc && ep->bEndpointAddress)) { - DBG("%s, bad ep\n", __func__); - return -EINVAL; - } - if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) { - if (req->req.length > ep->ep.maxpacket) - return -EMSGSIZE; - is_iso = 1; - } - - /* this isn't bogus, but OMAP DMA isn't the only hardware to - * have a hard time with partial packet reads... reject it. - * Except OMAP2 can handle the small packets. - */ - if (use_dma - && ep->has_dma - && ep->bEndpointAddress != 0 - && (ep->bEndpointAddress & USB_DIR_IN) == 0 - && !cpu_class_is_omap2() - && (req->req.length % ep->ep.maxpacket) != 0) { - DBG("%s, no partial packet OUT reads\n", __func__); - return -EMSGSIZE; - } - - udc = ep->udc; - if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - if (use_dma && ep->has_dma) { - if (req->req.dma == DMA_ADDR_INVALID) { - req->req.dma = dma_map_single( - ep->udc->gadget.dev.parent, - req->req.buf, - req->req.length, - (ep->bEndpointAddress & USB_DIR_IN) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - req->mapped = 1; - } else { - dma_sync_single_for_device( - ep->udc->gadget.dev.parent, - req->req.dma, req->req.length, - (ep->bEndpointAddress & USB_DIR_IN) - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - req->mapped = 0; - } - } - - VDBG("%s queue req %p, len %d buf %p\n", - ep->ep.name, _req, _req->length, _req->buf); - - spin_lock_irqsave(&udc->lock, flags); - - req->req.status = -EINPROGRESS; - req->req.actual = 0; - - /* maybe kickstart non-iso i/o queues */ - if (is_iso) { - u16 w; - - w = omap_readw(UDC_IRQ_EN); - w |= UDC_SOF_IE; - omap_writew(w, UDC_IRQ_EN); - } else if (list_empty(&ep->queue) && !ep->stopped && !ep->ackwait) { - int is_in; - - if (ep->bEndpointAddress == 0) { - if (!udc->ep0_pending || !list_empty (&ep->queue)) { - spin_unlock_irqrestore(&udc->lock, flags); - return -EL2HLT; - } - - /* empty DATA stage? */ - is_in = udc->ep0_in; - if (!req->req.length) { - - /* chip became CONFIGURED or ADDRESSED - * earlier; drivers may already have queued - * requests to non-control endpoints - */ - if (udc->ep0_set_config) { - u16 irq_en = omap_readw(UDC_IRQ_EN); - - irq_en |= UDC_DS_CHG_IE | UDC_EP0_IE; - if (!udc->ep0_reset_config) - irq_en |= UDC_EPN_RX_IE - | UDC_EPN_TX_IE; - omap_writew(irq_en, UDC_IRQ_EN); - } - - /* STATUS for zero length DATA stages is - * always an IN ... even for IN transfers, - * a weird case which seem to stall OMAP. - */ - omap_writew(UDC_EP_SEL | UDC_EP_DIR, UDC_EP_NUM); - omap_writew(UDC_CLR_EP, UDC_CTRL); - omap_writew(UDC_SET_FIFO_EN, UDC_CTRL); - omap_writew(UDC_EP_DIR, UDC_EP_NUM); - - /* cleanup */ - udc->ep0_pending = 0; - done(ep, req, 0); - req = NULL; - - /* non-empty DATA stage */ - } else if (is_in) { - omap_writew(UDC_EP_SEL | UDC_EP_DIR, UDC_EP_NUM); - } else { - if (udc->ep0_setup) - goto irq_wait; - omap_writew(UDC_EP_SEL, UDC_EP_NUM); - } - } else { - is_in = ep->bEndpointAddress & USB_DIR_IN; - if (!ep->has_dma) - use_ep(ep, UDC_EP_SEL); - /* if ISO: SOF IRQs must be enabled/disabled! */ - } - - if (ep->has_dma) - (is_in ? next_in_dma : next_out_dma)(ep, req); - else if (req) { - if ((is_in ? write_fifo : read_fifo)(ep, req) == 1) - req = NULL; - deselect_ep(); - if (!is_in) { - omap_writew(UDC_SET_FIFO_EN, UDC_CTRL); - ep->ackwait = 1 + ep->double_buf; - } - /* IN: 6 wait states before it'll tx */ - } - } - -irq_wait: - /* irq handler advances the queue */ - if (req != NULL) - list_add_tail(&req->queue, &ep->queue); - spin_unlock_irqrestore(&udc->lock, flags); - - return 0; -} - -static int omap_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct omap_ep *ep = container_of(_ep, struct omap_ep, ep); - struct omap_req *req; - unsigned long flags; - - if (!_ep || !_req) - return -EINVAL; - - spin_lock_irqsave(&ep->udc->lock, flags); - - /* make sure it's actually queued on this endpoint */ - list_for_each_entry (req, &ep->queue, queue) { - if (&req->req == _req) - break; - } - if (&req->req != _req) { - spin_unlock_irqrestore(&ep->udc->lock, flags); - return -EINVAL; - } - - if (use_dma && ep->dma_channel && ep->queue.next == &req->queue) { - int channel = ep->dma_channel; - - /* releasing the channel cancels the request, - * reclaiming the channel restarts the queue - */ - dma_channel_release(ep); - dma_channel_claim(ep, channel); - } else - done(ep, req, -ECONNRESET); - spin_unlock_irqrestore(&ep->udc->lock, flags); - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static int omap_ep_set_halt(struct usb_ep *_ep, int value) -{ - struct omap_ep *ep = container_of(_ep, struct omap_ep, ep); - unsigned long flags; - int status = -EOPNOTSUPP; - - spin_lock_irqsave(&ep->udc->lock, flags); - - /* just use protocol stalls for ep0; real halts are annoying */ - if (ep->bEndpointAddress == 0) { - if (!ep->udc->ep0_pending) - status = -EINVAL; - else if (value) { - if (ep->udc->ep0_set_config) { - WARNING("error changing config?\n"); - omap_writew(UDC_CLR_CFG, UDC_SYSCON2); - } - omap_writew(UDC_STALL_CMD, UDC_SYSCON2); - ep->udc->ep0_pending = 0; - status = 0; - } else /* NOP */ - status = 0; - - /* otherwise, all active non-ISO endpoints can halt */ - } else if (ep->bmAttributes != USB_ENDPOINT_XFER_ISOC && ep->desc) { - - /* IN endpoints must already be idle */ - if ((ep->bEndpointAddress & USB_DIR_IN) - && !list_empty(&ep->queue)) { - status = -EAGAIN; - goto done; - } - - if (value) { - int channel; - - if (use_dma && ep->dma_channel - && !list_empty(&ep->queue)) { - channel = ep->dma_channel; - dma_channel_release(ep); - } else - channel = 0; - - use_ep(ep, UDC_EP_SEL); - if (omap_readw(UDC_STAT_FLG) & UDC_NON_ISO_FIFO_EMPTY) { - omap_writew(UDC_SET_HALT, UDC_CTRL); - status = 0; - } else - status = -EAGAIN; - deselect_ep(); - - if (channel) - dma_channel_claim(ep, channel); - } else { - use_ep(ep, 0); - omap_writew(ep->udc->clr_halt, UDC_CTRL); - ep->ackwait = 0; - if (!(ep->bEndpointAddress & USB_DIR_IN)) { - omap_writew(UDC_SET_FIFO_EN, UDC_CTRL); - ep->ackwait = 1 + ep->double_buf; - } - } - } -done: - VDBG("%s %s halt stat %d\n", ep->ep.name, - value ? "set" : "clear", status); - - spin_unlock_irqrestore(&ep->udc->lock, flags); - return status; -} - -static struct usb_ep_ops omap_ep_ops = { - .enable = omap_ep_enable, - .disable = omap_ep_disable, - - .alloc_request = omap_alloc_request, - .free_request = omap_free_request, - - .queue = omap_ep_queue, - .dequeue = omap_ep_dequeue, - - .set_halt = omap_ep_set_halt, - // fifo_status ... report bytes in fifo - // fifo_flush ... flush fifo -}; - -/*-------------------------------------------------------------------------*/ - -static int omap_get_frame(struct usb_gadget *gadget) -{ - u16 sof = omap_readw(UDC_SOF); - return (sof & UDC_TS_OK) ? (sof & UDC_TS) : -EL2NSYNC; -} - -static int omap_wakeup(struct usb_gadget *gadget) -{ - struct omap_udc *udc; - unsigned long flags; - int retval = -EHOSTUNREACH; - - udc = container_of(gadget, struct omap_udc, gadget); - - spin_lock_irqsave(&udc->lock, flags); - if (udc->devstat & UDC_SUS) { - /* NOTE: OTG spec erratum says that OTG devices may - * issue wakeups without host enable. - */ - if (udc->devstat & (UDC_B_HNP_ENABLE|UDC_R_WK_OK)) { - DBG("remote wakeup...\n"); - omap_writew(UDC_RMT_WKP, UDC_SYSCON2); - retval = 0; - } - - /* NOTE: non-OTG systems may use SRP TOO... */ - } else if (!(udc->devstat & UDC_ATT)) { - if (udc->transceiver) - retval = otg_start_srp(udc->transceiver->otg); - } - spin_unlock_irqrestore(&udc->lock, flags); - - return retval; -} - -static int -omap_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered) -{ - struct omap_udc *udc; - unsigned long flags; - u16 syscon1; - - udc = container_of(gadget, struct omap_udc, gadget); - spin_lock_irqsave(&udc->lock, flags); - syscon1 = omap_readw(UDC_SYSCON1); - if (is_selfpowered) - syscon1 |= UDC_SELF_PWR; - else - syscon1 &= ~UDC_SELF_PWR; - omap_writew(syscon1, UDC_SYSCON1); - spin_unlock_irqrestore(&udc->lock, flags); - - return 0; -} - -static int can_pullup(struct omap_udc *udc) -{ - return udc->driver && udc->softconnect && udc->vbus_active; -} - -static void pullup_enable(struct omap_udc *udc) -{ - u16 w; - - w = omap_readw(UDC_SYSCON1); - w |= UDC_PULLUP_EN; - omap_writew(w, UDC_SYSCON1); - if (!gadget_is_otg(&udc->gadget) && !cpu_is_omap15xx()) { - u32 l; - - l = omap_readl(OTG_CTRL); - l |= OTG_BSESSVLD; - omap_writel(l, OTG_CTRL); - } - omap_writew(UDC_DS_CHG_IE, UDC_IRQ_EN); -} - -static void pullup_disable(struct omap_udc *udc) -{ - u16 w; - - if (!gadget_is_otg(&udc->gadget) && !cpu_is_omap15xx()) { - u32 l; - - l = omap_readl(OTG_CTRL); - l &= ~OTG_BSESSVLD; - omap_writel(l, OTG_CTRL); - } - omap_writew(UDC_DS_CHG_IE, UDC_IRQ_EN); - w = omap_readw(UDC_SYSCON1); - w &= ~UDC_PULLUP_EN; - omap_writew(w, UDC_SYSCON1); -} - -static struct omap_udc *udc; - -static void omap_udc_enable_clock(int enable) -{ - if (udc == NULL || udc->dc_clk == NULL || udc->hhc_clk == NULL) - return; - - if (enable) { - clk_enable(udc->dc_clk); - clk_enable(udc->hhc_clk); - udelay(100); - } else { - clk_disable(udc->hhc_clk); - clk_disable(udc->dc_clk); - } -} - -/* - * Called by whatever detects VBUS sessions: external transceiver - * driver, or maybe GPIO0 VBUS IRQ. May request 48 MHz clock. - */ -static int omap_vbus_session(struct usb_gadget *gadget, int is_active) -{ - struct omap_udc *udc; - unsigned long flags; - u32 l; - - udc = container_of(gadget, struct omap_udc, gadget); - spin_lock_irqsave(&udc->lock, flags); - VDBG("VBUS %s\n", is_active ? "on" : "off"); - udc->vbus_active = (is_active != 0); - if (cpu_is_omap15xx()) { - /* "software" detect, ignored if !VBUS_MODE_1510 */ - l = omap_readl(FUNC_MUX_CTRL_0); - if (is_active) - l |= VBUS_CTRL_1510; - else - l &= ~VBUS_CTRL_1510; - omap_writel(l, FUNC_MUX_CTRL_0); - } - if (udc->dc_clk != NULL && is_active) { - if (!udc->clk_requested) { - omap_udc_enable_clock(1); - udc->clk_requested = 1; - } - } - if (can_pullup(udc)) - pullup_enable(udc); - else - pullup_disable(udc); - if (udc->dc_clk != NULL && !is_active) { - if (udc->clk_requested) { - omap_udc_enable_clock(0); - udc->clk_requested = 0; - } - } - spin_unlock_irqrestore(&udc->lock, flags); - return 0; -} - -static int omap_vbus_draw(struct usb_gadget *gadget, unsigned mA) -{ - struct omap_udc *udc; - - udc = container_of(gadget, struct omap_udc, gadget); - if (udc->transceiver) - return usb_phy_set_power(udc->transceiver, mA); - return -EOPNOTSUPP; -} - -static int omap_pullup(struct usb_gadget *gadget, int is_on) -{ - struct omap_udc *udc; - unsigned long flags; - - udc = container_of(gadget, struct omap_udc, gadget); - spin_lock_irqsave(&udc->lock, flags); - udc->softconnect = (is_on != 0); - if (can_pullup(udc)) - pullup_enable(udc); - else - pullup_disable(udc); - spin_unlock_irqrestore(&udc->lock, flags); - return 0; -} - -static int omap_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int omap_udc_stop(struct usb_gadget_driver *driver); - -static struct usb_gadget_ops omap_gadget_ops = { - .get_frame = omap_get_frame, - .wakeup = omap_wakeup, - .set_selfpowered = omap_set_selfpowered, - .vbus_session = omap_vbus_session, - .vbus_draw = omap_vbus_draw, - .pullup = omap_pullup, - .start = omap_udc_start, - .stop = omap_udc_stop, -}; - -/*-------------------------------------------------------------------------*/ - -/* dequeue ALL requests; caller holds udc->lock */ -static void nuke(struct omap_ep *ep, int status) -{ - struct omap_req *req; - - ep->stopped = 1; - - if (use_dma && ep->dma_channel) - dma_channel_release(ep); - - use_ep(ep, 0); - omap_writew(UDC_CLR_EP, UDC_CTRL); - if (ep->bEndpointAddress && ep->bmAttributes != USB_ENDPOINT_XFER_ISOC) - omap_writew(UDC_SET_HALT, UDC_CTRL); - - while (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, struct omap_req, queue); - done(ep, req, status); - } -} - -/* caller holds udc->lock */ -static void udc_quiesce(struct omap_udc *udc) -{ - struct omap_ep *ep; - - udc->gadget.speed = USB_SPEED_UNKNOWN; - nuke(&udc->ep[0], -ESHUTDOWN); - list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) - nuke(ep, -ESHUTDOWN); -} - -/*-------------------------------------------------------------------------*/ - -static void update_otg(struct omap_udc *udc) -{ - u16 devstat; - - if (!gadget_is_otg(&udc->gadget)) - return; - - if (omap_readl(OTG_CTRL) & OTG_ID) - devstat = omap_readw(UDC_DEVSTAT); - else - devstat = 0; - - udc->gadget.b_hnp_enable = !!(devstat & UDC_B_HNP_ENABLE); - udc->gadget.a_hnp_support = !!(devstat & UDC_A_HNP_SUPPORT); - udc->gadget.a_alt_hnp_support = !!(devstat & UDC_A_ALT_HNP_SUPPORT); - - /* Enable HNP early, avoiding races on suspend irq path. - * ASSUMES OTG state machine B_BUS_REQ input is true. - */ - if (udc->gadget.b_hnp_enable) { - u32 l; - - l = omap_readl(OTG_CTRL); - l |= OTG_B_HNPEN | OTG_B_BUSREQ; - l &= ~OTG_PULLUP; - omap_writel(l, OTG_CTRL); - } -} - -static void ep0_irq(struct omap_udc *udc, u16 irq_src) -{ - struct omap_ep *ep0 = &udc->ep[0]; - struct omap_req *req = NULL; - - ep0->irqs++; - - /* Clear any pending requests and then scrub any rx/tx state - * before starting to handle the SETUP request. - */ - if (irq_src & UDC_SETUP) { - u16 ack = irq_src & (UDC_EP0_TX|UDC_EP0_RX); - - nuke(ep0, 0); - if (ack) { - omap_writew(ack, UDC_IRQ_SRC); - irq_src = UDC_SETUP; - } - } - - /* IN/OUT packets mean we're in the DATA or STATUS stage. - * This driver uses only uses protocol stalls (ep0 never halts), - * and if we got this far the gadget driver already had a - * chance to stall. Tries to be forgiving of host oddities. - * - * NOTE: the last chance gadget drivers have to stall control - * requests is during their request completion callback. - */ - if (!list_empty(&ep0->queue)) - req = container_of(ep0->queue.next, struct omap_req, queue); - - /* IN == TX to host */ - if (irq_src & UDC_EP0_TX) { - int stat; - - omap_writew(UDC_EP0_TX, UDC_IRQ_SRC); - omap_writew(UDC_EP_SEL|UDC_EP_DIR, UDC_EP_NUM); - stat = omap_readw(UDC_STAT_FLG); - if (stat & UDC_ACK) { - if (udc->ep0_in) { - /* write next IN packet from response, - * or set up the status stage. - */ - if (req) - stat = write_fifo(ep0, req); - omap_writew(UDC_EP_DIR, UDC_EP_NUM); - if (!req && udc->ep0_pending) { - omap_writew(UDC_EP_SEL, UDC_EP_NUM); - omap_writew(UDC_CLR_EP, UDC_CTRL); - omap_writew(UDC_SET_FIFO_EN, UDC_CTRL); - omap_writew(0, UDC_EP_NUM); - udc->ep0_pending = 0; - } /* else: 6 wait states before it'll tx */ - } else { - /* ack status stage of OUT transfer */ - omap_writew(UDC_EP_DIR, UDC_EP_NUM); - if (req) - done(ep0, req, 0); - } - req = NULL; - } else if (stat & UDC_STALL) { - omap_writew(UDC_CLR_HALT, UDC_CTRL); - omap_writew(UDC_EP_DIR, UDC_EP_NUM); - } else { - omap_writew(UDC_EP_DIR, UDC_EP_NUM); - } - } - - /* OUT == RX from host */ - if (irq_src & UDC_EP0_RX) { - int stat; - - omap_writew(UDC_EP0_RX, UDC_IRQ_SRC); - omap_writew(UDC_EP_SEL, UDC_EP_NUM); - stat = omap_readw(UDC_STAT_FLG); - if (stat & UDC_ACK) { - if (!udc->ep0_in) { - stat = 0; - /* read next OUT packet of request, maybe - * reactiviting the fifo; stall on errors. - */ - if (!req || (stat = read_fifo(ep0, req)) < 0) { - omap_writew(UDC_STALL_CMD, UDC_SYSCON2); - udc->ep0_pending = 0; - stat = 0; - } else if (stat == 0) - omap_writew(UDC_SET_FIFO_EN, UDC_CTRL); - omap_writew(0, UDC_EP_NUM); - - /* activate status stage */ - if (stat == 1) { - done(ep0, req, 0); - /* that may have STALLed ep0... */ - omap_writew(UDC_EP_SEL | UDC_EP_DIR, - UDC_EP_NUM); - omap_writew(UDC_CLR_EP, UDC_CTRL); - omap_writew(UDC_SET_FIFO_EN, UDC_CTRL); - omap_writew(UDC_EP_DIR, UDC_EP_NUM); - udc->ep0_pending = 0; - } - } else { - /* ack status stage of IN transfer */ - omap_writew(0, UDC_EP_NUM); - if (req) - done(ep0, req, 0); - } - } else if (stat & UDC_STALL) { - omap_writew(UDC_CLR_HALT, UDC_CTRL); - omap_writew(0, UDC_EP_NUM); - } else { - omap_writew(0, UDC_EP_NUM); - } - } - - /* SETUP starts all control transfers */ - if (irq_src & UDC_SETUP) { - union u { - u16 word[4]; - struct usb_ctrlrequest r; - } u; - int status = -EINVAL; - struct omap_ep *ep; - - /* read the (latest) SETUP message */ - do { - omap_writew(UDC_SETUP_SEL, UDC_EP_NUM); - /* two bytes at a time */ - u.word[0] = omap_readw(UDC_DATA); - u.word[1] = omap_readw(UDC_DATA); - u.word[2] = omap_readw(UDC_DATA); - u.word[3] = omap_readw(UDC_DATA); - omap_writew(0, UDC_EP_NUM); - } while (omap_readw(UDC_IRQ_SRC) & UDC_SETUP); - -#define w_value le16_to_cpu(u.r.wValue) -#define w_index le16_to_cpu(u.r.wIndex) -#define w_length le16_to_cpu(u.r.wLength) - - /* Delegate almost all control requests to the gadget driver, - * except for a handful of ch9 status/feature requests that - * hardware doesn't autodecode _and_ the gadget API hides. - */ - udc->ep0_in = (u.r.bRequestType & USB_DIR_IN) != 0; - udc->ep0_set_config = 0; - udc->ep0_pending = 1; - ep0->stopped = 0; - ep0->ackwait = 0; - switch (u.r.bRequest) { - case USB_REQ_SET_CONFIGURATION: - /* udc needs to know when ep != 0 is valid */ - if (u.r.bRequestType != USB_RECIP_DEVICE) - goto delegate; - if (w_length != 0) - goto do_stall; - udc->ep0_set_config = 1; - udc->ep0_reset_config = (w_value == 0); - VDBG("set config %d\n", w_value); - - /* update udc NOW since gadget driver may start - * queueing requests immediately; clear config - * later if it fails the request. - */ - if (udc->ep0_reset_config) - omap_writew(UDC_CLR_CFG, UDC_SYSCON2); - else - omap_writew(UDC_DEV_CFG, UDC_SYSCON2); - update_otg(udc); - goto delegate; - case USB_REQ_CLEAR_FEATURE: - /* clear endpoint halt */ - if (u.r.bRequestType != USB_RECIP_ENDPOINT) - goto delegate; - if (w_value != USB_ENDPOINT_HALT - || w_length != 0) - goto do_stall; - ep = &udc->ep[w_index & 0xf]; - if (ep != ep0) { - if (w_index & USB_DIR_IN) - ep += 16; - if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC - || !ep->desc) - goto do_stall; - use_ep(ep, 0); - omap_writew(udc->clr_halt, UDC_CTRL); - ep->ackwait = 0; - if (!(ep->bEndpointAddress & USB_DIR_IN)) { - omap_writew(UDC_SET_FIFO_EN, UDC_CTRL); - ep->ackwait = 1 + ep->double_buf; - } - /* NOTE: assumes the host behaves sanely, - * only clearing real halts. Else we may - * need to kill pending transfers and then - * restart the queue... very messy for DMA! - */ - } - VDBG("%s halt cleared by host\n", ep->name); - goto ep0out_status_stage; - case USB_REQ_SET_FEATURE: - /* set endpoint halt */ - if (u.r.bRequestType != USB_RECIP_ENDPOINT) - goto delegate; - if (w_value != USB_ENDPOINT_HALT - || w_length != 0) - goto do_stall; - ep = &udc->ep[w_index & 0xf]; - if (w_index & USB_DIR_IN) - ep += 16; - if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC - || ep == ep0 || !ep->desc) - goto do_stall; - if (use_dma && ep->has_dma) { - /* this has rude side-effects (aborts) and - * can't really work if DMA-IN is active - */ - DBG("%s host set_halt, NYET \n", ep->name); - goto do_stall; - } - use_ep(ep, 0); - /* can't halt if fifo isn't empty... */ - omap_writew(UDC_CLR_EP, UDC_CTRL); - omap_writew(UDC_SET_HALT, UDC_CTRL); - VDBG("%s halted by host\n", ep->name); -ep0out_status_stage: - status = 0; - omap_writew(UDC_EP_SEL|UDC_EP_DIR, UDC_EP_NUM); - omap_writew(UDC_CLR_EP, UDC_CTRL); - omap_writew(UDC_SET_FIFO_EN, UDC_CTRL); - omap_writew(UDC_EP_DIR, UDC_EP_NUM); - udc->ep0_pending = 0; - break; - case USB_REQ_GET_STATUS: - /* USB_ENDPOINT_HALT status? */ - if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT)) - goto intf_status; - - /* ep0 never stalls */ - if (!(w_index & 0xf)) - goto zero_status; - - /* only active endpoints count */ - ep = &udc->ep[w_index & 0xf]; - if (w_index & USB_DIR_IN) - ep += 16; - if (!ep->desc) - goto do_stall; - - /* iso never stalls */ - if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) - goto zero_status; - - /* FIXME don't assume non-halted endpoints!! */ - ERR("%s status, can't report\n", ep->ep.name); - goto do_stall; - -intf_status: - /* return interface status. if we were pedantic, - * we'd detect non-existent interfaces, and stall. - */ - if (u.r.bRequestType - != (USB_DIR_IN|USB_RECIP_INTERFACE)) - goto delegate; - -zero_status: - /* return two zero bytes */ - omap_writew(UDC_EP_SEL|UDC_EP_DIR, UDC_EP_NUM); - omap_writew(0, UDC_DATA); - omap_writew(UDC_SET_FIFO_EN, UDC_CTRL); - omap_writew(UDC_EP_DIR, UDC_EP_NUM); - status = 0; - VDBG("GET_STATUS, interface %d\n", w_index); - /* next, status stage */ - break; - default: -delegate: - /* activate the ep0out fifo right away */ - if (!udc->ep0_in && w_length) { - omap_writew(0, UDC_EP_NUM); - omap_writew(UDC_SET_FIFO_EN, UDC_CTRL); - } - - /* gadget drivers see class/vendor specific requests, - * {SET,GET}_{INTERFACE,DESCRIPTOR,CONFIGURATION}, - * and more - */ - VDBG("SETUP %02x.%02x v%04x i%04x l%04x\n", - u.r.bRequestType, u.r.bRequest, - w_value, w_index, w_length); - -#undef w_value -#undef w_index -#undef w_length - - /* The gadget driver may return an error here, - * causing an immediate protocol stall. - * - * Else it must issue a response, either queueing a - * response buffer for the DATA stage, or halting ep0 - * (causing a protocol stall, not a real halt). A - * zero length buffer means no DATA stage. - * - * It's fine to issue that response after the setup() - * call returns, and this IRQ was handled. - */ - udc->ep0_setup = 1; - spin_unlock(&udc->lock); - status = udc->driver->setup (&udc->gadget, &u.r); - spin_lock(&udc->lock); - udc->ep0_setup = 0; - } - - if (status < 0) { -do_stall: - VDBG("req %02x.%02x protocol STALL; stat %d\n", - u.r.bRequestType, u.r.bRequest, status); - if (udc->ep0_set_config) { - if (udc->ep0_reset_config) - WARNING("error resetting config?\n"); - else - omap_writew(UDC_CLR_CFG, UDC_SYSCON2); - } - omap_writew(UDC_STALL_CMD, UDC_SYSCON2); - udc->ep0_pending = 0; - } - } -} - -/*-------------------------------------------------------------------------*/ - -#define OTG_FLAGS (UDC_B_HNP_ENABLE|UDC_A_HNP_SUPPORT|UDC_A_ALT_HNP_SUPPORT) - -static void devstate_irq(struct omap_udc *udc, u16 irq_src) -{ - u16 devstat, change; - - devstat = omap_readw(UDC_DEVSTAT); - change = devstat ^ udc->devstat; - udc->devstat = devstat; - - if (change & (UDC_USB_RESET|UDC_ATT)) { - udc_quiesce(udc); - - if (change & UDC_ATT) { - /* driver for any external transceiver will - * have called omap_vbus_session() already - */ - if (devstat & UDC_ATT) { - udc->gadget.speed = USB_SPEED_FULL; - VDBG("connect\n"); - if (!udc->transceiver) - pullup_enable(udc); - // if (driver->connect) call it - } else if (udc->gadget.speed != USB_SPEED_UNKNOWN) { - udc->gadget.speed = USB_SPEED_UNKNOWN; - if (!udc->transceiver) - pullup_disable(udc); - DBG("disconnect, gadget %s\n", - udc->driver->driver.name); - if (udc->driver->disconnect) { - spin_unlock(&udc->lock); - udc->driver->disconnect(&udc->gadget); - spin_lock(&udc->lock); - } - } - change &= ~UDC_ATT; - } - - if (change & UDC_USB_RESET) { - if (devstat & UDC_USB_RESET) { - VDBG("RESET=1\n"); - } else { - udc->gadget.speed = USB_SPEED_FULL; - INFO("USB reset done, gadget %s\n", - udc->driver->driver.name); - /* ep0 traffic is legal from now on */ - omap_writew(UDC_DS_CHG_IE | UDC_EP0_IE, - UDC_IRQ_EN); - } - change &= ~UDC_USB_RESET; - } - } - if (change & UDC_SUS) { - if (udc->gadget.speed != USB_SPEED_UNKNOWN) { - // FIXME tell isp1301 to suspend/resume (?) - if (devstat & UDC_SUS) { - VDBG("suspend\n"); - update_otg(udc); - /* HNP could be under way already */ - if (udc->gadget.speed == USB_SPEED_FULL - && udc->driver->suspend) { - spin_unlock(&udc->lock); - udc->driver->suspend(&udc->gadget); - spin_lock(&udc->lock); - } - if (udc->transceiver) - usb_phy_set_suspend( - udc->transceiver, 1); - } else { - VDBG("resume\n"); - if (udc->transceiver) - usb_phy_set_suspend( - udc->transceiver, 0); - if (udc->gadget.speed == USB_SPEED_FULL - && udc->driver->resume) { - spin_unlock(&udc->lock); - udc->driver->resume(&udc->gadget); - spin_lock(&udc->lock); - } - } - } - change &= ~UDC_SUS; - } - if (!cpu_is_omap15xx() && (change & OTG_FLAGS)) { - update_otg(udc); - change &= ~OTG_FLAGS; - } - - change &= ~(UDC_CFG|UDC_DEF|UDC_ADD); - if (change) - VDBG("devstat %03x, ignore change %03x\n", - devstat, change); - - omap_writew(UDC_DS_CHG, UDC_IRQ_SRC); -} - -static irqreturn_t omap_udc_irq(int irq, void *_udc) -{ - struct omap_udc *udc = _udc; - u16 irq_src; - irqreturn_t status = IRQ_NONE; - unsigned long flags; - - spin_lock_irqsave(&udc->lock, flags); - irq_src = omap_readw(UDC_IRQ_SRC); - - /* Device state change (usb ch9 stuff) */ - if (irq_src & UDC_DS_CHG) { - devstate_irq(_udc, irq_src); - status = IRQ_HANDLED; - irq_src &= ~UDC_DS_CHG; - } - - /* EP0 control transfers */ - if (irq_src & (UDC_EP0_RX|UDC_SETUP|UDC_EP0_TX)) { - ep0_irq(_udc, irq_src); - status = IRQ_HANDLED; - irq_src &= ~(UDC_EP0_RX|UDC_SETUP|UDC_EP0_TX); - } - - /* DMA transfer completion */ - if (use_dma && (irq_src & (UDC_TXN_DONE|UDC_RXN_CNT|UDC_RXN_EOT))) { - dma_irq(_udc, irq_src); - status = IRQ_HANDLED; - irq_src &= ~(UDC_TXN_DONE|UDC_RXN_CNT|UDC_RXN_EOT); - } - - irq_src &= ~(UDC_IRQ_SOF | UDC_EPN_TX|UDC_EPN_RX); - if (irq_src) - DBG("udc_irq, unhandled %03x\n", irq_src); - spin_unlock_irqrestore(&udc->lock, flags); - - return status; -} - -/* workaround for seemingly-lost IRQs for RX ACKs... */ -#define PIO_OUT_TIMEOUT (jiffies + HZ/3) -#define HALF_FULL(f) (!((f)&(UDC_NON_ISO_FIFO_FULL|UDC_NON_ISO_FIFO_EMPTY))) - -static void pio_out_timer(unsigned long _ep) -{ - struct omap_ep *ep = (void *) _ep; - unsigned long flags; - u16 stat_flg; - - spin_lock_irqsave(&ep->udc->lock, flags); - if (!list_empty(&ep->queue) && ep->ackwait) { - use_ep(ep, UDC_EP_SEL); - stat_flg = omap_readw(UDC_STAT_FLG); - - if ((stat_flg & UDC_ACK) && (!(stat_flg & UDC_FIFO_EN) - || (ep->double_buf && HALF_FULL(stat_flg)))) { - struct omap_req *req; - - VDBG("%s: lose, %04x\n", ep->ep.name, stat_flg); - req = container_of(ep->queue.next, - struct omap_req, queue); - (void) read_fifo(ep, req); - omap_writew(ep->bEndpointAddress, UDC_EP_NUM); - omap_writew(UDC_SET_FIFO_EN, UDC_CTRL); - ep->ackwait = 1 + ep->double_buf; - } else - deselect_ep(); - } - mod_timer(&ep->timer, PIO_OUT_TIMEOUT); - spin_unlock_irqrestore(&ep->udc->lock, flags); -} - -static irqreturn_t omap_udc_pio_irq(int irq, void *_dev) -{ - u16 epn_stat, irq_src; - irqreturn_t status = IRQ_NONE; - struct omap_ep *ep; - int epnum; - struct omap_udc *udc = _dev; - struct omap_req *req; - unsigned long flags; - - spin_lock_irqsave(&udc->lock, flags); - epn_stat = omap_readw(UDC_EPN_STAT); - irq_src = omap_readw(UDC_IRQ_SRC); - - /* handle OUT first, to avoid some wasteful NAKs */ - if (irq_src & UDC_EPN_RX) { - epnum = (epn_stat >> 8) & 0x0f; - omap_writew(UDC_EPN_RX, UDC_IRQ_SRC); - status = IRQ_HANDLED; - ep = &udc->ep[epnum]; - ep->irqs++; - - omap_writew(epnum | UDC_EP_SEL, UDC_EP_NUM); - ep->fnf = 0; - if (omap_readw(UDC_STAT_FLG) & UDC_ACK) { - ep->ackwait--; - if (!list_empty(&ep->queue)) { - int stat; - req = container_of(ep->queue.next, - struct omap_req, queue); - stat = read_fifo(ep, req); - if (!ep->double_buf) - ep->fnf = 1; - } - } - /* min 6 clock delay before clearing EP_SEL ... */ - epn_stat = omap_readw(UDC_EPN_STAT); - epn_stat = omap_readw(UDC_EPN_STAT); - omap_writew(epnum, UDC_EP_NUM); - - /* enabling fifo _after_ clearing ACK, contrary to docs, - * reduces lossage; timer still needed though (sigh). - */ - if (ep->fnf) { - omap_writew(UDC_SET_FIFO_EN, UDC_CTRL); - ep->ackwait = 1 + ep->double_buf; - } - mod_timer(&ep->timer, PIO_OUT_TIMEOUT); - } - - /* then IN transfers */ - else if (irq_src & UDC_EPN_TX) { - epnum = epn_stat & 0x0f; - omap_writew(UDC_EPN_TX, UDC_IRQ_SRC); - status = IRQ_HANDLED; - ep = &udc->ep[16 + epnum]; - ep->irqs++; - - omap_writew(epnum | UDC_EP_DIR | UDC_EP_SEL, UDC_EP_NUM); - if (omap_readw(UDC_STAT_FLG) & UDC_ACK) { - ep->ackwait = 0; - if (!list_empty(&ep->queue)) { - req = container_of(ep->queue.next, - struct omap_req, queue); - (void) write_fifo(ep, req); - } - } - /* min 6 clock delay before clearing EP_SEL ... */ - epn_stat = omap_readw(UDC_EPN_STAT); - epn_stat = omap_readw(UDC_EPN_STAT); - omap_writew(epnum | UDC_EP_DIR, UDC_EP_NUM); - /* then 6 clocks before it'd tx */ - } - - spin_unlock_irqrestore(&udc->lock, flags); - return status; -} - -#ifdef USE_ISO -static irqreturn_t omap_udc_iso_irq(int irq, void *_dev) -{ - struct omap_udc *udc = _dev; - struct omap_ep *ep; - int pending = 0; - unsigned long flags; - - spin_lock_irqsave(&udc->lock, flags); - - /* handle all non-DMA ISO transfers */ - list_for_each_entry (ep, &udc->iso, iso) { - u16 stat; - struct omap_req *req; - - if (ep->has_dma || list_empty(&ep->queue)) - continue; - req = list_entry(ep->queue.next, struct omap_req, queue); - - use_ep(ep, UDC_EP_SEL); - stat = omap_readw(UDC_STAT_FLG); - - /* NOTE: like the other controller drivers, this isn't - * currently reporting lost or damaged frames. - */ - if (ep->bEndpointAddress & USB_DIR_IN) { - if (stat & UDC_MISS_IN) - /* done(ep, req, -EPROTO) */; - else - write_fifo(ep, req); - } else { - int status = 0; - - if (stat & UDC_NO_RXPACKET) - status = -EREMOTEIO; - else if (stat & UDC_ISO_ERR) - status = -EILSEQ; - else if (stat & UDC_DATA_FLUSH) - status = -ENOSR; - - if (status) - /* done(ep, req, status) */; - else - read_fifo(ep, req); - } - deselect_ep(); - /* 6 wait states before next EP */ - - ep->irqs++; - if (!list_empty(&ep->queue)) - pending = 1; - } - if (!pending) { - u16 w; - - w = omap_readw(UDC_IRQ_EN); - w &= ~UDC_SOF_IE; - omap_writew(w, UDC_IRQ_EN); - } - omap_writew(UDC_IRQ_SOF, UDC_IRQ_SRC); - - spin_unlock_irqrestore(&udc->lock, flags); - return IRQ_HANDLED; -} -#endif - -/*-------------------------------------------------------------------------*/ - -static inline int machine_without_vbus_sense(void) -{ - return (machine_is_omap_innovator() - || machine_is_omap_osk() - || machine_is_omap_apollon() -#ifndef CONFIG_MACH_OMAP_H4_OTG - || machine_is_omap_h4() -#endif - || machine_is_sx1() - || cpu_is_omap7xx() /* No known omap7xx boards with vbus sense */ - ); -} - -static int omap_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) -{ - int status = -ENODEV; - struct omap_ep *ep; - unsigned long flags; - - /* basic sanity tests */ - if (!udc) - return -ENODEV; - if (!driver - // FIXME if otg, check: driver->is_otg - || driver->max_speed < USB_SPEED_FULL - || !bind || !driver->setup) - return -EINVAL; - - spin_lock_irqsave(&udc->lock, flags); - if (udc->driver) { - spin_unlock_irqrestore(&udc->lock, flags); - return -EBUSY; - } - - /* reset state */ - list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) { - ep->irqs = 0; - if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) - continue; - use_ep(ep, 0); - omap_writew(UDC_SET_HALT, UDC_CTRL); - } - udc->ep0_pending = 0; - udc->ep[0].irqs = 0; - udc->softconnect = 1; - - /* hook up the driver */ - driver->driver.bus = NULL; - udc->driver = driver; - udc->gadget.dev.driver = &driver->driver; - spin_unlock_irqrestore(&udc->lock, flags); - - if (udc->dc_clk != NULL) - omap_udc_enable_clock(1); - - status = bind(&udc->gadget); - if (status) { - DBG("bind to %s --> %d\n", driver->driver.name, status); - udc->gadget.dev.driver = NULL; - udc->driver = NULL; - goto done; - } - DBG("bound to driver %s\n", driver->driver.name); - - omap_writew(UDC_IRQ_SRC_MASK, UDC_IRQ_SRC); - - /* connect to bus through transceiver */ - if (udc->transceiver) { - status = otg_set_peripheral(udc->transceiver->otg, - &udc->gadget); - if (status < 0) { - ERR("can't bind to transceiver\n"); - if (driver->unbind) { - driver->unbind (&udc->gadget); - udc->gadget.dev.driver = NULL; - udc->driver = NULL; - } - goto done; - } - } else { - if (can_pullup(udc)) - pullup_enable (udc); - else - pullup_disable (udc); - } - - /* boards that don't have VBUS sensing can't autogate 48MHz; - * can't enter deep sleep while a gadget driver is active. - */ - if (machine_without_vbus_sense()) - omap_vbus_session(&udc->gadget, 1); - -done: - if (udc->dc_clk != NULL) - omap_udc_enable_clock(0); - return status; -} - -static int omap_udc_stop(struct usb_gadget_driver *driver) -{ - unsigned long flags; - int status = -ENODEV; - - if (!udc) - return -ENODEV; - if (!driver || driver != udc->driver || !driver->unbind) - return -EINVAL; - - if (udc->dc_clk != NULL) - omap_udc_enable_clock(1); - - if (machine_without_vbus_sense()) - omap_vbus_session(&udc->gadget, 0); - - if (udc->transceiver) - (void) otg_set_peripheral(udc->transceiver->otg, NULL); - else - pullup_disable(udc); - - spin_lock_irqsave(&udc->lock, flags); - udc_quiesce(udc); - spin_unlock_irqrestore(&udc->lock, flags); - - driver->unbind(&udc->gadget); - udc->gadget.dev.driver = NULL; - udc->driver = NULL; - - if (udc->dc_clk != NULL) - omap_udc_enable_clock(0); - DBG("unregistered driver '%s'\n", driver->driver.name); - return status; -} - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - -#include - -static const char proc_filename[] = "driver/udc"; - -#define FOURBITS "%s%s%s%s" -#define EIGHTBITS FOURBITS FOURBITS - -static void proc_ep_show(struct seq_file *s, struct omap_ep *ep) -{ - u16 stat_flg; - struct omap_req *req; - char buf[20]; - - use_ep(ep, 0); - - if (use_dma && ep->has_dma) - snprintf(buf, sizeof buf, "(%cxdma%d lch%d) ", - (ep->bEndpointAddress & USB_DIR_IN) ? 't' : 'r', - ep->dma_channel - 1, ep->lch); - else - buf[0] = 0; - - stat_flg = omap_readw(UDC_STAT_FLG); - seq_printf(s, - "\n%s %s%s%sirqs %ld stat %04x " EIGHTBITS FOURBITS "%s\n", - ep->name, buf, - ep->double_buf ? "dbuf " : "", - ({char *s; switch(ep->ackwait){ - case 0: s = ""; break; - case 1: s = "(ackw) "; break; - case 2: s = "(ackw2) "; break; - default: s = "(?) "; break; - } s;}), - ep->irqs, stat_flg, - (stat_flg & UDC_NO_RXPACKET) ? "no_rxpacket " : "", - (stat_flg & UDC_MISS_IN) ? "miss_in " : "", - (stat_flg & UDC_DATA_FLUSH) ? "data_flush " : "", - (stat_flg & UDC_ISO_ERR) ? "iso_err " : "", - (stat_flg & UDC_ISO_FIFO_EMPTY) ? "iso_fifo_empty " : "", - (stat_flg & UDC_ISO_FIFO_FULL) ? "iso_fifo_full " : "", - (stat_flg & UDC_EP_HALTED) ? "HALT " : "", - (stat_flg & UDC_STALL) ? "STALL " : "", - (stat_flg & UDC_NAK) ? "NAK " : "", - (stat_flg & UDC_ACK) ? "ACK " : "", - (stat_flg & UDC_FIFO_EN) ? "fifo_en " : "", - (stat_flg & UDC_NON_ISO_FIFO_EMPTY) ? "fifo_empty " : "", - (stat_flg & UDC_NON_ISO_FIFO_FULL) ? "fifo_full " : ""); - - if (list_empty (&ep->queue)) - seq_printf(s, "\t(queue empty)\n"); - else - list_for_each_entry (req, &ep->queue, queue) { - unsigned length = req->req.actual; - - if (use_dma && buf[0]) { - length += ((ep->bEndpointAddress & USB_DIR_IN) - ? dma_src_len : dma_dest_len) - (ep, req->req.dma + length); - buf[0] = 0; - } - seq_printf(s, "\treq %p len %d/%d buf %p\n", - &req->req, length, - req->req.length, req->req.buf); - } -} - -static char *trx_mode(unsigned m, int enabled) -{ - switch (m) { - case 0: return enabled ? "*6wire" : "unused"; - case 1: return "4wire"; - case 2: return "3wire"; - case 3: return "6wire"; - default: return "unknown"; - } -} - -static int proc_otg_show(struct seq_file *s) -{ - u32 tmp; - u32 trans = 0; - char *ctrl_name = "(UNKNOWN)"; - - /* XXX This needs major revision for OMAP2+ */ - tmp = omap_readl(OTG_REV); - if (cpu_class_is_omap1()) { - ctrl_name = "tranceiver_ctrl"; - trans = omap_readw(USB_TRANSCEIVER_CTRL); - } - seq_printf(s, "\nOTG rev %d.%d, %s %05x\n", - tmp >> 4, tmp & 0xf, ctrl_name, trans); - tmp = omap_readw(OTG_SYSCON_1); - seq_printf(s, "otg_syscon1 %08x usb2 %s, usb1 %s, usb0 %s," - FOURBITS "\n", tmp, - trx_mode(USB2_TRX_MODE(tmp), trans & CONF_USB2_UNI_R), - trx_mode(USB1_TRX_MODE(tmp), trans & CONF_USB1_UNI_R), - (USB0_TRX_MODE(tmp) == 0 && !cpu_is_omap1710()) - ? "internal" - : trx_mode(USB0_TRX_MODE(tmp), 1), - (tmp & OTG_IDLE_EN) ? " !otg" : "", - (tmp & HST_IDLE_EN) ? " !host" : "", - (tmp & DEV_IDLE_EN) ? " !dev" : "", - (tmp & OTG_RESET_DONE) ? " reset_done" : " reset_active"); - tmp = omap_readl(OTG_SYSCON_2); - seq_printf(s, "otg_syscon2 %08x%s" EIGHTBITS - " b_ase_brst=%d hmc=%d\n", tmp, - (tmp & OTG_EN) ? " otg_en" : "", - (tmp & USBX_SYNCHRO) ? " synchro" : "", - // much more SRP stuff - (tmp & SRP_DATA) ? " srp_data" : "", - (tmp & SRP_VBUS) ? " srp_vbus" : "", - (tmp & OTG_PADEN) ? " otg_paden" : "", - (tmp & HMC_PADEN) ? " hmc_paden" : "", - (tmp & UHOST_EN) ? " uhost_en" : "", - (tmp & HMC_TLLSPEED) ? " tllspeed" : "", - (tmp & HMC_TLLATTACH) ? " tllattach" : "", - B_ASE_BRST(tmp), - OTG_HMC(tmp)); - tmp = omap_readl(OTG_CTRL); - seq_printf(s, "otg_ctrl %06x" EIGHTBITS EIGHTBITS "%s\n", tmp, - (tmp & OTG_ASESSVLD) ? " asess" : "", - (tmp & OTG_BSESSEND) ? " bsess_end" : "", - (tmp & OTG_BSESSVLD) ? " bsess" : "", - (tmp & OTG_VBUSVLD) ? " vbus" : "", - (tmp & OTG_ID) ? " id" : "", - (tmp & OTG_DRIVER_SEL) ? " DEVICE" : " HOST", - (tmp & OTG_A_SETB_HNPEN) ? " a_setb_hnpen" : "", - (tmp & OTG_A_BUSREQ) ? " a_bus" : "", - (tmp & OTG_B_HNPEN) ? " b_hnpen" : "", - (tmp & OTG_B_BUSREQ) ? " b_bus" : "", - (tmp & OTG_BUSDROP) ? " busdrop" : "", - (tmp & OTG_PULLDOWN) ? " down" : "", - (tmp & OTG_PULLUP) ? " up" : "", - (tmp & OTG_DRV_VBUS) ? " drv" : "", - (tmp & OTG_PD_VBUS) ? " pd_vb" : "", - (tmp & OTG_PU_VBUS) ? " pu_vb" : "", - (tmp & OTG_PU_ID) ? " pu_id" : "" - ); - tmp = omap_readw(OTG_IRQ_EN); - seq_printf(s, "otg_irq_en %04x" "\n", tmp); - tmp = omap_readw(OTG_IRQ_SRC); - seq_printf(s, "otg_irq_src %04x" "\n", tmp); - tmp = omap_readw(OTG_OUTCTRL); - seq_printf(s, "otg_outctrl %04x" "\n", tmp); - tmp = omap_readw(OTG_TEST); - seq_printf(s, "otg_test %04x" "\n", tmp); - return 0; -} - -static int proc_udc_show(struct seq_file *s, void *_) -{ - u32 tmp; - struct omap_ep *ep; - unsigned long flags; - - spin_lock_irqsave(&udc->lock, flags); - - seq_printf(s, "%s, version: " DRIVER_VERSION -#ifdef USE_ISO - " (iso)" -#endif - "%s\n", - driver_desc, - use_dma ? " (dma)" : ""); - - tmp = omap_readw(UDC_REV) & 0xff; - seq_printf(s, - "UDC rev %d.%d, fifo mode %d, gadget %s\n" - "hmc %d, transceiver %s\n", - tmp >> 4, tmp & 0xf, - fifo_mode, - udc->driver ? udc->driver->driver.name : "(none)", - HMC, - udc->transceiver - ? udc->transceiver->label - : ((cpu_is_omap1710() || cpu_is_omap24xx()) - ? "external" : "(none)")); - if (cpu_class_is_omap1()) { - seq_printf(s, "ULPD control %04x req %04x status %04x\n", - omap_readw(ULPD_CLOCK_CTRL), - omap_readw(ULPD_SOFT_REQ), - omap_readw(ULPD_STATUS_REQ)); - } - - /* OTG controller registers */ - if (!cpu_is_omap15xx()) - proc_otg_show(s); - - tmp = omap_readw(UDC_SYSCON1); - seq_printf(s, "\nsyscon1 %04x" EIGHTBITS "\n", tmp, - (tmp & UDC_CFG_LOCK) ? " cfg_lock" : "", - (tmp & UDC_DATA_ENDIAN) ? " data_endian" : "", - (tmp & UDC_DMA_ENDIAN) ? " dma_endian" : "", - (tmp & UDC_NAK_EN) ? " nak" : "", - (tmp & UDC_AUTODECODE_DIS) ? " autodecode_dis" : "", - (tmp & UDC_SELF_PWR) ? " self_pwr" : "", - (tmp & UDC_SOFF_DIS) ? " soff_dis" : "", - (tmp & UDC_PULLUP_EN) ? " PULLUP" : ""); - // syscon2 is write-only - - /* UDC controller registers */ - if (!(tmp & UDC_PULLUP_EN)) { - seq_printf(s, "(suspended)\n"); - spin_unlock_irqrestore(&udc->lock, flags); - return 0; - } - - tmp = omap_readw(UDC_DEVSTAT); - seq_printf(s, "devstat %04x" EIGHTBITS "%s%s\n", tmp, - (tmp & UDC_B_HNP_ENABLE) ? " b_hnp" : "", - (tmp & UDC_A_HNP_SUPPORT) ? " a_hnp" : "", - (tmp & UDC_A_ALT_HNP_SUPPORT) ? " a_alt_hnp" : "", - (tmp & UDC_R_WK_OK) ? " r_wk_ok" : "", - (tmp & UDC_USB_RESET) ? " usb_reset" : "", - (tmp & UDC_SUS) ? " SUS" : "", - (tmp & UDC_CFG) ? " CFG" : "", - (tmp & UDC_ADD) ? " ADD" : "", - (tmp & UDC_DEF) ? " DEF" : "", - (tmp & UDC_ATT) ? " ATT" : ""); - seq_printf(s, "sof %04x\n", omap_readw(UDC_SOF)); - tmp = omap_readw(UDC_IRQ_EN); - seq_printf(s, "irq_en %04x" FOURBITS "%s\n", tmp, - (tmp & UDC_SOF_IE) ? " sof" : "", - (tmp & UDC_EPN_RX_IE) ? " epn_rx" : "", - (tmp & UDC_EPN_TX_IE) ? " epn_tx" : "", - (tmp & UDC_DS_CHG_IE) ? " ds_chg" : "", - (tmp & UDC_EP0_IE) ? " ep0" : ""); - tmp = omap_readw(UDC_IRQ_SRC); - seq_printf(s, "irq_src %04x" EIGHTBITS "%s%s\n", tmp, - (tmp & UDC_TXN_DONE) ? " txn_done" : "", - (tmp & UDC_RXN_CNT) ? " rxn_cnt" : "", - (tmp & UDC_RXN_EOT) ? " rxn_eot" : "", - (tmp & UDC_IRQ_SOF) ? " sof" : "", - (tmp & UDC_EPN_RX) ? " epn_rx" : "", - (tmp & UDC_EPN_TX) ? " epn_tx" : "", - (tmp & UDC_DS_CHG) ? " ds_chg" : "", - (tmp & UDC_SETUP) ? " setup" : "", - (tmp & UDC_EP0_RX) ? " ep0out" : "", - (tmp & UDC_EP0_TX) ? " ep0in" : ""); - if (use_dma) { - unsigned i; - - tmp = omap_readw(UDC_DMA_IRQ_EN); - seq_printf(s, "dma_irq_en %04x%s" EIGHTBITS "\n", tmp, - (tmp & UDC_TX_DONE_IE(3)) ? " tx2_done" : "", - (tmp & UDC_RX_CNT_IE(3)) ? " rx2_cnt" : "", - (tmp & UDC_RX_EOT_IE(3)) ? " rx2_eot" : "", - - (tmp & UDC_TX_DONE_IE(2)) ? " tx1_done" : "", - (tmp & UDC_RX_CNT_IE(2)) ? " rx1_cnt" : "", - (tmp & UDC_RX_EOT_IE(2)) ? " rx1_eot" : "", - - (tmp & UDC_TX_DONE_IE(1)) ? " tx0_done" : "", - (tmp & UDC_RX_CNT_IE(1)) ? " rx0_cnt" : "", - (tmp & UDC_RX_EOT_IE(1)) ? " rx0_eot" : ""); - - tmp = omap_readw(UDC_RXDMA_CFG); - seq_printf(s, "rxdma_cfg %04x\n", tmp); - if (tmp) { - for (i = 0; i < 3; i++) { - if ((tmp & (0x0f << (i * 4))) == 0) - continue; - seq_printf(s, "rxdma[%d] %04x\n", i, - omap_readw(UDC_RXDMA(i + 1))); - } - } - tmp = omap_readw(UDC_TXDMA_CFG); - seq_printf(s, "txdma_cfg %04x\n", tmp); - if (tmp) { - for (i = 0; i < 3; i++) { - if (!(tmp & (0x0f << (i * 4)))) - continue; - seq_printf(s, "txdma[%d] %04x\n", i, - omap_readw(UDC_TXDMA(i + 1))); - } - } - } - - tmp = omap_readw(UDC_DEVSTAT); - if (tmp & UDC_ATT) { - proc_ep_show(s, &udc->ep[0]); - if (tmp & UDC_ADD) { - list_for_each_entry (ep, &udc->gadget.ep_list, - ep.ep_list) { - if (ep->desc) - proc_ep_show(s, ep); - } - } - } - spin_unlock_irqrestore(&udc->lock, flags); - return 0; -} - -static int proc_udc_open(struct inode *inode, struct file *file) -{ - return single_open(file, proc_udc_show, NULL); -} - -static const struct file_operations proc_ops = { - .owner = THIS_MODULE, - .open = proc_udc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static void create_proc_file(void) -{ - proc_create(proc_filename, 0, NULL, &proc_ops); -} - -static void remove_proc_file(void) -{ - remove_proc_entry(proc_filename, NULL); -} - -#else - -static inline void create_proc_file(void) {} -static inline void remove_proc_file(void) {} - -#endif - -/*-------------------------------------------------------------------------*/ - -/* Before this controller can enumerate, we need to pick an endpoint - * configuration, or "fifo_mode" That involves allocating 2KB of packet - * buffer space among the endpoints we'll be operating. - * - * NOTE: as of OMAP 1710 ES2.0, writing a new endpoint config when - * UDC_SYSCON_1.CFG_LOCK is set can now work. We won't use that - * capability yet though. - */ -static unsigned __init -omap_ep_setup(char *name, u8 addr, u8 type, - unsigned buf, unsigned maxp, int dbuf) -{ - struct omap_ep *ep; - u16 epn_rxtx = 0; - - /* OUT endpoints first, then IN */ - ep = &udc->ep[addr & 0xf]; - if (addr & USB_DIR_IN) - ep += 16; - - /* in case of ep init table bugs */ - BUG_ON(ep->name[0]); - - /* chip setup ... bit values are same for IN, OUT */ - if (type == USB_ENDPOINT_XFER_ISOC) { - switch (maxp) { - case 8: epn_rxtx = 0 << 12; break; - case 16: epn_rxtx = 1 << 12; break; - case 32: epn_rxtx = 2 << 12; break; - case 64: epn_rxtx = 3 << 12; break; - case 128: epn_rxtx = 4 << 12; break; - case 256: epn_rxtx = 5 << 12; break; - case 512: epn_rxtx = 6 << 12; break; - default: BUG(); - } - epn_rxtx |= UDC_EPN_RX_ISO; - dbuf = 1; - } else { - /* double-buffering "not supported" on 15xx, - * and ignored for PIO-IN on newer chips - * (for more reliable behavior) - */ - if (!use_dma || cpu_is_omap15xx() || cpu_is_omap24xx()) - dbuf = 0; - - switch (maxp) { - case 8: epn_rxtx = 0 << 12; break; - case 16: epn_rxtx = 1 << 12; break; - case 32: epn_rxtx = 2 << 12; break; - case 64: epn_rxtx = 3 << 12; break; - default: BUG(); - } - if (dbuf && addr) - epn_rxtx |= UDC_EPN_RX_DB; - init_timer(&ep->timer); - ep->timer.function = pio_out_timer; - ep->timer.data = (unsigned long) ep; - } - if (addr) - epn_rxtx |= UDC_EPN_RX_VALID; - BUG_ON(buf & 0x07); - epn_rxtx |= buf >> 3; - - DBG("%s addr %02x rxtx %04x maxp %d%s buf %d\n", - name, addr, epn_rxtx, maxp, dbuf ? "x2" : "", buf); - - if (addr & USB_DIR_IN) - omap_writew(epn_rxtx, UDC_EP_TX(addr & 0xf)); - else - omap_writew(epn_rxtx, UDC_EP_RX(addr)); - - /* next endpoint's buffer starts after this one's */ - buf += maxp; - if (dbuf) - buf += maxp; - BUG_ON(buf > 2048); - - /* set up driver data structures */ - BUG_ON(strlen(name) >= sizeof ep->name); - strlcpy(ep->name, name, sizeof ep->name); - INIT_LIST_HEAD(&ep->queue); - INIT_LIST_HEAD(&ep->iso); - ep->bEndpointAddress = addr; - ep->bmAttributes = type; - ep->double_buf = dbuf; - ep->udc = udc; - - ep->ep.name = ep->name; - ep->ep.ops = &omap_ep_ops; - ep->ep.maxpacket = ep->maxpacket = maxp; - list_add_tail (&ep->ep.ep_list, &udc->gadget.ep_list); - - return buf; -} - -static void omap_udc_release(struct device *dev) -{ - complete(udc->done); - kfree (udc); - udc = NULL; -} - -static int __init -omap_udc_setup(struct platform_device *odev, struct usb_phy *xceiv) -{ - unsigned tmp, buf; - - /* abolish any previous hardware state */ - omap_writew(0, UDC_SYSCON1); - omap_writew(0, UDC_IRQ_EN); - omap_writew(UDC_IRQ_SRC_MASK, UDC_IRQ_SRC); - omap_writew(0, UDC_DMA_IRQ_EN); - omap_writew(0, UDC_RXDMA_CFG); - omap_writew(0, UDC_TXDMA_CFG); - - /* UDC_PULLUP_EN gates the chip clock */ - // OTG_SYSCON_1 |= DEV_IDLE_EN; - - udc = kzalloc(sizeof(*udc), GFP_KERNEL); - if (!udc) - return -ENOMEM; - - spin_lock_init (&udc->lock); - - udc->gadget.ops = &omap_gadget_ops; - udc->gadget.ep0 = &udc->ep[0].ep; - INIT_LIST_HEAD(&udc->gadget.ep_list); - INIT_LIST_HEAD(&udc->iso); - udc->gadget.speed = USB_SPEED_UNKNOWN; - udc->gadget.max_speed = USB_SPEED_FULL; - udc->gadget.name = driver_name; - - device_initialize(&udc->gadget.dev); - dev_set_name(&udc->gadget.dev, "gadget"); - udc->gadget.dev.release = omap_udc_release; - udc->gadget.dev.parent = &odev->dev; - if (use_dma) - udc->gadget.dev.dma_mask = odev->dev.dma_mask; - - udc->transceiver = xceiv; - - /* ep0 is special; put it right after the SETUP buffer */ - buf = omap_ep_setup("ep0", 0, USB_ENDPOINT_XFER_CONTROL, - 8 /* after SETUP */, 64 /* maxpacket */, 0); - list_del_init(&udc->ep[0].ep.ep_list); - - /* initially disable all non-ep0 endpoints */ - for (tmp = 1; tmp < 15; tmp++) { - omap_writew(0, UDC_EP_RX(tmp)); - omap_writew(0, UDC_EP_TX(tmp)); - } - -#define OMAP_BULK_EP(name,addr) \ - buf = omap_ep_setup(name "-bulk", addr, \ - USB_ENDPOINT_XFER_BULK, buf, 64, 1); -#define OMAP_INT_EP(name,addr, maxp) \ - buf = omap_ep_setup(name "-int", addr, \ - USB_ENDPOINT_XFER_INT, buf, maxp, 0); -#define OMAP_ISO_EP(name,addr, maxp) \ - buf = omap_ep_setup(name "-iso", addr, \ - USB_ENDPOINT_XFER_ISOC, buf, maxp, 1); - - switch (fifo_mode) { - case 0: - OMAP_BULK_EP("ep1in", USB_DIR_IN | 1); - OMAP_BULK_EP("ep2out", USB_DIR_OUT | 2); - OMAP_INT_EP("ep3in", USB_DIR_IN | 3, 16); - break; - case 1: - OMAP_BULK_EP("ep1in", USB_DIR_IN | 1); - OMAP_BULK_EP("ep2out", USB_DIR_OUT | 2); - OMAP_INT_EP("ep9in", USB_DIR_IN | 9, 16); - - OMAP_BULK_EP("ep3in", USB_DIR_IN | 3); - OMAP_BULK_EP("ep4out", USB_DIR_OUT | 4); - OMAP_INT_EP("ep10in", USB_DIR_IN | 10, 16); - - OMAP_BULK_EP("ep5in", USB_DIR_IN | 5); - OMAP_BULK_EP("ep5out", USB_DIR_OUT | 5); - OMAP_INT_EP("ep11in", USB_DIR_IN | 11, 16); - - OMAP_BULK_EP("ep6in", USB_DIR_IN | 6); - OMAP_BULK_EP("ep6out", USB_DIR_OUT | 6); - OMAP_INT_EP("ep12in", USB_DIR_IN | 12, 16); - - OMAP_BULK_EP("ep7in", USB_DIR_IN | 7); - OMAP_BULK_EP("ep7out", USB_DIR_OUT | 7); - OMAP_INT_EP("ep13in", USB_DIR_IN | 13, 16); - OMAP_INT_EP("ep13out", USB_DIR_OUT | 13, 16); - - OMAP_BULK_EP("ep8in", USB_DIR_IN | 8); - OMAP_BULK_EP("ep8out", USB_DIR_OUT | 8); - OMAP_INT_EP("ep14in", USB_DIR_IN | 14, 16); - OMAP_INT_EP("ep14out", USB_DIR_OUT | 14, 16); - - OMAP_BULK_EP("ep15in", USB_DIR_IN | 15); - OMAP_BULK_EP("ep15out", USB_DIR_OUT | 15); - - break; - -#ifdef USE_ISO - case 2: /* mixed iso/bulk */ - OMAP_ISO_EP("ep1in", USB_DIR_IN | 1, 256); - OMAP_ISO_EP("ep2out", USB_DIR_OUT | 2, 256); - OMAP_ISO_EP("ep3in", USB_DIR_IN | 3, 128); - OMAP_ISO_EP("ep4out", USB_DIR_OUT | 4, 128); - - OMAP_INT_EP("ep5in", USB_DIR_IN | 5, 16); - - OMAP_BULK_EP("ep6in", USB_DIR_IN | 6); - OMAP_BULK_EP("ep7out", USB_DIR_OUT | 7); - OMAP_INT_EP("ep8in", USB_DIR_IN | 8, 16); - break; - case 3: /* mixed bulk/iso */ - OMAP_BULK_EP("ep1in", USB_DIR_IN | 1); - OMAP_BULK_EP("ep2out", USB_DIR_OUT | 2); - OMAP_INT_EP("ep3in", USB_DIR_IN | 3, 16); - - OMAP_BULK_EP("ep4in", USB_DIR_IN | 4); - OMAP_BULK_EP("ep5out", USB_DIR_OUT | 5); - OMAP_INT_EP("ep6in", USB_DIR_IN | 6, 16); - - OMAP_ISO_EP("ep7in", USB_DIR_IN | 7, 256); - OMAP_ISO_EP("ep8out", USB_DIR_OUT | 8, 256); - OMAP_INT_EP("ep9in", USB_DIR_IN | 9, 16); - break; -#endif - - /* add more modes as needed */ - - default: - ERR("unsupported fifo_mode #%d\n", fifo_mode); - return -ENODEV; - } - omap_writew(UDC_CFG_LOCK|UDC_SELF_PWR, UDC_SYSCON1); - INFO("fifo mode %d, %d bytes not used\n", fifo_mode, 2048 - buf); - return 0; -} - -static int __init omap_udc_probe(struct platform_device *pdev) -{ - int status = -ENODEV; - int hmc; - struct usb_phy *xceiv = NULL; - const char *type = NULL; - struct omap_usb_config *config = pdev->dev.platform_data; - struct clk *dc_clk; - struct clk *hhc_clk; - - /* NOTE: "knows" the order of the resources! */ - if (!request_mem_region(pdev->resource[0].start, - pdev->resource[0].end - pdev->resource[0].start + 1, - driver_name)) { - DBG("request_mem_region failed\n"); - return -EBUSY; - } - - if (cpu_is_omap16xx()) { - dc_clk = clk_get(&pdev->dev, "usb_dc_ck"); - hhc_clk = clk_get(&pdev->dev, "usb_hhc_ck"); - BUG_ON(IS_ERR(dc_clk) || IS_ERR(hhc_clk)); - /* can't use omap_udc_enable_clock yet */ - clk_enable(dc_clk); - clk_enable(hhc_clk); - udelay(100); - } - - if (cpu_is_omap24xx()) { - dc_clk = clk_get(&pdev->dev, "usb_fck"); - hhc_clk = clk_get(&pdev->dev, "usb_l4_ick"); - BUG_ON(IS_ERR(dc_clk) || IS_ERR(hhc_clk)); - /* can't use omap_udc_enable_clock yet */ - clk_enable(dc_clk); - clk_enable(hhc_clk); - udelay(100); - } - - if (cpu_is_omap7xx()) { - dc_clk = clk_get(&pdev->dev, "usb_dc_ck"); - hhc_clk = clk_get(&pdev->dev, "l3_ocpi_ck"); - BUG_ON(IS_ERR(dc_clk) || IS_ERR(hhc_clk)); - /* can't use omap_udc_enable_clock yet */ - clk_enable(dc_clk); - clk_enable(hhc_clk); - udelay(100); - } - - INFO("OMAP UDC rev %d.%d%s\n", - omap_readw(UDC_REV) >> 4, omap_readw(UDC_REV) & 0xf, - config->otg ? ", Mini-AB" : ""); - - /* use the mode given to us by board init code */ - if (cpu_is_omap15xx()) { - hmc = HMC_1510; - type = "(unknown)"; - - if (machine_without_vbus_sense()) { - /* just set up software VBUS detect, and then - * later rig it so we always report VBUS. - * FIXME without really sensing VBUS, we can't - * know when to turn PULLUP_EN on/off; and that - * means we always "need" the 48MHz clock. - */ - u32 tmp = omap_readl(FUNC_MUX_CTRL_0); - tmp &= ~VBUS_CTRL_1510; - omap_writel(tmp, FUNC_MUX_CTRL_0); - tmp |= VBUS_MODE_1510; - tmp &= ~VBUS_CTRL_1510; - omap_writel(tmp, FUNC_MUX_CTRL_0); - } - } else { - /* The transceiver may package some GPIO logic or handle - * loopback and/or transceiverless setup; if we find one, - * use it. Except for OTG, we don't _need_ to talk to one; - * but not having one probably means no VBUS detection. - */ - xceiv = usb_get_transceiver(); - if (xceiv) - type = xceiv->label; - else if (config->otg) { - DBG("OTG requires external transceiver!\n"); - goto cleanup0; - } - - hmc = HMC_1610; - - if (cpu_is_omap24xx()) { - /* this could be transceiverless in one of the - * "we don't need to know" modes. - */ - type = "external"; - goto known; - } - - switch (hmc) { - case 0: /* POWERUP DEFAULT == 0 */ - case 4: - case 12: - case 20: - if (!cpu_is_omap1710()) { - type = "integrated"; - break; - } - /* FALL THROUGH */ - case 3: - case 11: - case 16: - case 19: - case 25: - if (!xceiv) { - DBG("external transceiver not registered!\n"); - type = "unknown"; - } - break; - case 21: /* internal loopback */ - type = "loopback"; - break; - case 14: /* transceiverless */ - if (cpu_is_omap1710()) - goto bad_on_1710; - /* FALL THROUGH */ - case 13: - case 15: - type = "no"; - break; - - default: -bad_on_1710: - ERR("unrecognized UDC HMC mode %d\n", hmc); - goto cleanup0; - } - } -known: - INFO("hmc mode %d, %s transceiver\n", hmc, type); - - /* a "gadget" abstracts/virtualizes the controller */ - status = omap_udc_setup(pdev, xceiv); - if (status) { - goto cleanup0; - } - xceiv = NULL; - // "udc" is now valid - pullup_disable(udc); -#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) - udc->gadget.is_otg = (config->otg != 0); -#endif - - /* starting with omap1710 es2.0, clear toggle is a separate bit */ - if (omap_readw(UDC_REV) >= 0x61) - udc->clr_halt = UDC_RESET_EP | UDC_CLRDATA_TOGGLE; - else - udc->clr_halt = UDC_RESET_EP; - - /* USB general purpose IRQ: ep0, state changes, dma, etc */ - status = request_irq(pdev->resource[1].start, omap_udc_irq, - IRQF_SAMPLE_RANDOM, driver_name, udc); - if (status != 0) { - ERR("can't get irq %d, err %d\n", - (int) pdev->resource[1].start, status); - goto cleanup1; - } - - /* USB "non-iso" IRQ (PIO for all but ep0) */ - status = request_irq(pdev->resource[2].start, omap_udc_pio_irq, - IRQF_SAMPLE_RANDOM, "omap_udc pio", udc); - if (status != 0) { - ERR("can't get irq %d, err %d\n", - (int) pdev->resource[2].start, status); - goto cleanup2; - } -#ifdef USE_ISO - status = request_irq(pdev->resource[3].start, omap_udc_iso_irq, - 0, "omap_udc iso", udc); - if (status != 0) { - ERR("can't get irq %d, err %d\n", - (int) pdev->resource[3].start, status); - goto cleanup3; - } -#endif - if (cpu_is_omap16xx() || cpu_is_omap7xx()) { - udc->dc_clk = dc_clk; - udc->hhc_clk = hhc_clk; - clk_disable(hhc_clk); - clk_disable(dc_clk); - } - - if (cpu_is_omap24xx()) { - udc->dc_clk = dc_clk; - udc->hhc_clk = hhc_clk; - /* FIXME OMAP2 don't release hhc & dc clock */ -#if 0 - clk_disable(hhc_clk); - clk_disable(dc_clk); -#endif - } - - create_proc_file(); - status = device_add(&udc->gadget.dev); - if (status) - goto cleanup4; - - status = usb_add_gadget_udc(&pdev->dev, &udc->gadget); - if (!status) - return status; - /* If fail, fall through */ -cleanup4: - remove_proc_file(); - -#ifdef USE_ISO -cleanup3: - free_irq(pdev->resource[2].start, udc); -#endif - -cleanup2: - free_irq(pdev->resource[1].start, udc); - -cleanup1: - kfree (udc); - udc = NULL; - -cleanup0: - if (xceiv) - usb_put_transceiver(xceiv); - - if (cpu_is_omap16xx() || cpu_is_omap24xx() || cpu_is_omap7xx()) { - clk_disable(hhc_clk); - clk_disable(dc_clk); - clk_put(hhc_clk); - clk_put(dc_clk); - } - - release_mem_region(pdev->resource[0].start, - pdev->resource[0].end - pdev->resource[0].start + 1); - - return status; -} - -static int __exit omap_udc_remove(struct platform_device *pdev) -{ - DECLARE_COMPLETION_ONSTACK(done); - - if (!udc) - return -ENODEV; - - usb_del_gadget_udc(&udc->gadget); - if (udc->driver) - return -EBUSY; - - udc->done = &done; - - pullup_disable(udc); - if (udc->transceiver) { - usb_put_transceiver(udc->transceiver); - udc->transceiver = NULL; - } - omap_writew(0, UDC_SYSCON1); - - remove_proc_file(); - -#ifdef USE_ISO - free_irq(pdev->resource[3].start, udc); -#endif - free_irq(pdev->resource[2].start, udc); - free_irq(pdev->resource[1].start, udc); - - if (udc->dc_clk) { - if (udc->clk_requested) - omap_udc_enable_clock(0); - clk_put(udc->hhc_clk); - clk_put(udc->dc_clk); - } - - release_mem_region(pdev->resource[0].start, - pdev->resource[0].end - pdev->resource[0].start + 1); - - device_unregister(&udc->gadget.dev); - wait_for_completion(&done); - - return 0; -} - -/* suspend/resume/wakeup from sysfs (echo > power/state) or when the - * system is forced into deep sleep - * - * REVISIT we should probably reject suspend requests when there's a host - * session active, rather than disconnecting, at least on boards that can - * report VBUS irqs (UDC_DEVSTAT.UDC_ATT). And in any case, we need to - * make host resumes and VBUS detection trigger OMAP wakeup events; that - * may involve talking to an external transceiver (e.g. isp1301). - */ - -static int omap_udc_suspend(struct platform_device *dev, pm_message_t message) -{ - u32 devstat; - - devstat = omap_readw(UDC_DEVSTAT); - - /* we're requesting 48 MHz clock if the pullup is enabled - * (== we're attached to the host) and we're not suspended, - * which would prevent entry to deep sleep... - */ - if ((devstat & UDC_ATT) != 0 && (devstat & UDC_SUS) == 0) { - WARNING("session active; suspend requires disconnect\n"); - omap_pullup(&udc->gadget, 0); - } - - return 0; -} - -static int omap_udc_resume(struct platform_device *dev) -{ - DBG("resume + wakeup/SRP\n"); - omap_pullup(&udc->gadget, 1); - - /* maybe the host would enumerate us if we nudged it */ - msleep(100); - return omap_wakeup(&udc->gadget); -} - -/*-------------------------------------------------------------------------*/ - -static struct platform_driver udc_driver = { - .remove = __exit_p(omap_udc_remove), - .suspend = omap_udc_suspend, - .resume = omap_udc_resume, - .driver = { - .owner = THIS_MODULE, - .name = (char *) driver_name, - }, -}; - -static int __init udc_init(void) -{ - /* Disable DMA for omap7xx -- it doesn't work right. */ - if (cpu_is_omap7xx()) - use_dma = 0; - - INFO("%s, version: " DRIVER_VERSION -#ifdef USE_ISO - " (iso)" -#endif - "%s\n", driver_desc, - use_dma ? " (dma)" : ""); - return platform_driver_probe(&udc_driver, omap_udc_probe); -} -module_init(udc_init); - -static void __exit udc_exit(void) -{ - platform_driver_unregister(&udc_driver); -} -module_exit(udc_exit); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:omap_udc"); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/omap_udc.h b/ANDROID_3.4.5/drivers/usb/gadget/omap_udc.h deleted file mode 100644 index 59d3b221..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/omap_udc.h +++ /dev/null @@ -1,207 +0,0 @@ -/* - * omap_udc.h -- for omap 3.2 udc, with OTG support - * - * 2004 (C) Texas Instruments, Inc. - * 2004 (C) David Brownell - */ - -/* - * USB device/endpoint management registers - */ - -#define UDC_REV (UDC_BASE + 0x0) /* Revision */ -#define UDC_EP_NUM (UDC_BASE + 0x4) /* Which endpoint */ -# define UDC_SETUP_SEL (1 << 6) -# define UDC_EP_SEL (1 << 5) -# define UDC_EP_DIR (1 << 4) - /* low 4 bits for endpoint number */ -#define UDC_DATA (UDC_BASE + 0x08) /* Endpoint FIFO */ -#define UDC_CTRL (UDC_BASE + 0x0C) /* Endpoint control */ -# define UDC_CLR_HALT (1 << 7) -# define UDC_SET_HALT (1 << 6) -# define UDC_CLRDATA_TOGGLE (1 << 3) -# define UDC_SET_FIFO_EN (1 << 2) -# define UDC_CLR_EP (1 << 1) -# define UDC_RESET_EP (1 << 0) -#define UDC_STAT_FLG (UDC_BASE + 0x10) /* Endpoint status */ -# define UDC_NO_RXPACKET (1 << 15) -# define UDC_MISS_IN (1 << 14) -# define UDC_DATA_FLUSH (1 << 13) -# define UDC_ISO_ERR (1 << 12) -# define UDC_ISO_FIFO_EMPTY (1 << 9) -# define UDC_ISO_FIFO_FULL (1 << 8) -# define UDC_EP_HALTED (1 << 6) -# define UDC_STALL (1 << 5) -# define UDC_NAK (1 << 4) -# define UDC_ACK (1 << 3) -# define UDC_FIFO_EN (1 << 2) -# define UDC_NON_ISO_FIFO_EMPTY (1 << 1) -# define UDC_NON_ISO_FIFO_FULL (1 << 0) -#define UDC_RXFSTAT (UDC_BASE + 0x14) /* OUT bytecount */ -#define UDC_SYSCON1 (UDC_BASE + 0x18) /* System config 1 */ -# define UDC_CFG_LOCK (1 << 8) -# define UDC_DATA_ENDIAN (1 << 7) -# define UDC_DMA_ENDIAN (1 << 6) -# define UDC_NAK_EN (1 << 4) -# define UDC_AUTODECODE_DIS (1 << 3) -# define UDC_SELF_PWR (1 << 2) -# define UDC_SOFF_DIS (1 << 1) -# define UDC_PULLUP_EN (1 << 0) -#define UDC_SYSCON2 (UDC_BASE + 0x1C) /* System config 2 */ -# define UDC_RMT_WKP (1 << 6) -# define UDC_STALL_CMD (1 << 5) -# define UDC_DEV_CFG (1 << 3) -# define UDC_CLR_CFG (1 << 2) -#define UDC_DEVSTAT (UDC_BASE + 0x20) /* Device status */ -# define UDC_B_HNP_ENABLE (1 << 9) -# define UDC_A_HNP_SUPPORT (1 << 8) -# define UDC_A_ALT_HNP_SUPPORT (1 << 7) -# define UDC_R_WK_OK (1 << 6) -# define UDC_USB_RESET (1 << 5) -# define UDC_SUS (1 << 4) -# define UDC_CFG (1 << 3) -# define UDC_ADD (1 << 2) -# define UDC_DEF (1 << 1) -# define UDC_ATT (1 << 0) -#define UDC_SOF (UDC_BASE + 0x24) /* Start of frame */ -# define UDC_FT_LOCK (1 << 12) -# define UDC_TS_OK (1 << 11) -# define UDC_TS 0x03ff -#define UDC_IRQ_EN (UDC_BASE + 0x28) /* Interrupt enable */ -# define UDC_SOF_IE (1 << 7) -# define UDC_EPN_RX_IE (1 << 5) -# define UDC_EPN_TX_IE (1 << 4) -# define UDC_DS_CHG_IE (1 << 3) -# define UDC_EP0_IE (1 << 0) -#define UDC_DMA_IRQ_EN (UDC_BASE + 0x2C) /* DMA irq enable */ - /* rx/tx dma channels numbered 1-3 not 0-2 */ -# define UDC_TX_DONE_IE(n) (1 << (4 * (n) - 2)) -# define UDC_RX_CNT_IE(n) (1 << (4 * (n) - 3)) -# define UDC_RX_EOT_IE(n) (1 << (4 * (n) - 4)) -#define UDC_IRQ_SRC (UDC_BASE + 0x30) /* Interrupt source */ -# define UDC_TXN_DONE (1 << 10) -# define UDC_RXN_CNT (1 << 9) -# define UDC_RXN_EOT (1 << 8) -# define UDC_IRQ_SOF (1 << 7) -# define UDC_EPN_RX (1 << 5) -# define UDC_EPN_TX (1 << 4) -# define UDC_DS_CHG (1 << 3) -# define UDC_SETUP (1 << 2) -# define UDC_EP0_RX (1 << 1) -# define UDC_EP0_TX (1 << 0) -# define UDC_IRQ_SRC_MASK 0x7bf -#define UDC_EPN_STAT (UDC_BASE + 0x34) /* EP irq status */ -#define UDC_DMAN_STAT (UDC_BASE + 0x38) /* DMA irq status */ -# define UDC_DMA_RX_SB (1 << 12) -# define UDC_DMA_RX_SRC(x) (((x)>>8) & 0xf) -# define UDC_DMA_TX_SRC(x) (((x)>>0) & 0xf) - - -/* DMA configuration registers: up to three channels in each direction. */ -#define UDC_RXDMA_CFG (UDC_BASE + 0x40) /* 3 eps for RX DMA */ -# define UDC_DMA_REQ (1 << 12) -#define UDC_TXDMA_CFG (UDC_BASE + 0x44) /* 3 eps for TX DMA */ -#define UDC_DATA_DMA (UDC_BASE + 0x48) /* rx/tx fifo addr */ - -/* rx/tx dma control, numbering channels 1-3 not 0-2 */ -#define UDC_TXDMA(chan) (UDC_BASE + 0x50 - 4 + 4 * (chan)) -# define UDC_TXN_EOT (1 << 15) /* bytes vs packets */ -# define UDC_TXN_START (1 << 14) /* start transfer */ -# define UDC_TXN_TSC 0x03ff /* units in xfer */ -#define UDC_RXDMA(chan) (UDC_BASE + 0x60 - 4 + 4 * (chan)) -# define UDC_RXN_STOP (1 << 15) /* enable EOT irq */ -# define UDC_RXN_TC 0x00ff /* packets in xfer */ - - -/* - * Endpoint configuration registers (used before CFG_LOCK is set) - * UDC_EP_TX(0) is unused - */ -#define UDC_EP_RX(endpoint) (UDC_BASE + 0x80 + (endpoint)*4) -# define UDC_EPN_RX_VALID (1 << 15) -# define UDC_EPN_RX_DB (1 << 14) - /* buffer size in bits 13, 12 */ -# define UDC_EPN_RX_ISO (1 << 11) - /* buffer pointer in low 11 bits */ -#define UDC_EP_TX(endpoint) (UDC_BASE + 0xc0 + (endpoint)*4) - /* same bitfields as in RX */ - -/*-------------------------------------------------------------------------*/ - -struct omap_req { - struct usb_request req; - struct list_head queue; - unsigned dma_bytes; - unsigned mapped:1; -}; - -struct omap_ep { - struct usb_ep ep; - struct list_head queue; - unsigned long irqs; - struct list_head iso; - const struct usb_endpoint_descriptor *desc; - char name[14]; - u16 maxpacket; - u8 bEndpointAddress; - u8 bmAttributes; - unsigned double_buf:1; - unsigned stopped:1; - unsigned fnf:1; - unsigned has_dma:1; - u8 ackwait; - u8 dma_channel; - u16 dma_counter; - int lch; - struct omap_udc *udc; - struct timer_list timer; -}; - -struct omap_udc { - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - spinlock_t lock; - struct omap_ep ep[32]; - u16 devstat; - u16 clr_halt; - struct usb_phy *transceiver; - struct list_head iso; - unsigned softconnect:1; - unsigned vbus_active:1; - unsigned ep0_pending:1; - unsigned ep0_in:1; - unsigned ep0_set_config:1; - unsigned ep0_reset_config:1; - unsigned ep0_setup:1; - struct completion *done; - struct clk *dc_clk; - struct clk *hhc_clk; - unsigned clk_requested:1; -}; - -/*-------------------------------------------------------------------------*/ - -#ifdef VERBOSE -# define VDBG DBG -#else -# define VDBG(stuff...) do{}while(0) -#endif - -#define ERR(stuff...) pr_err("udc: " stuff) -#define WARNING(stuff...) pr_warning("udc: " stuff) -#define INFO(stuff...) pr_info("udc: " stuff) -#define DBG(stuff...) pr_debug("udc: " stuff) - -/*-------------------------------------------------------------------------*/ - -/* MOD_CONF_CTRL_0 */ -#define VBUS_W2FC_1510 (1 << 17) /* 0 gpio0, 1 dvdd2 pin */ - -/* FUNC_MUX_CTRL_0 */ -#define VBUS_CTRL_1510 (1 << 19) /* 1 connected (software) */ -#define VBUS_MODE_1510 (1 << 18) /* 0 hardware, 1 software */ - -#define HMC_1510 ((omap_readl(MOD_CONF_CTRL_0) >> 1) & 0x3f) -#define HMC_1610 (omap_readl(OTG_SYSCON_2) & 0x3f) -#define HMC (cpu_is_omap15xx() ? HMC_1510 : HMC_1610) - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/pch_udc.c b/ANDROID_3.4.5/drivers/usb/gadget/pch_udc.c deleted file mode 100644 index 65307064..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/pch_udc.c +++ /dev/null @@ -1,3310 +0,0 @@ -/* - * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd. - * - * 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; version 2 of the License. - */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* GPIO port for VBUS detecting */ -static int vbus_gpio_port = -1; /* GPIO port number (-1:Not used) */ - -#define PCH_VBUS_PERIOD 3000 /* VBUS polling period (msec) */ -#define PCH_VBUS_INTERVAL 10 /* VBUS polling interval (msec) */ - -/* Address offset of Registers */ -#define UDC_EP_REG_SHIFT 0x20 /* Offset to next EP */ - -#define UDC_EPCTL_ADDR 0x00 /* Endpoint control */ -#define UDC_EPSTS_ADDR 0x04 /* Endpoint status */ -#define UDC_BUFIN_FRAMENUM_ADDR 0x08 /* buffer size in / frame number out */ -#define UDC_BUFOUT_MAXPKT_ADDR 0x0C /* buffer size out / maxpkt in */ -#define UDC_SUBPTR_ADDR 0x10 /* setup buffer pointer */ -#define UDC_DESPTR_ADDR 0x14 /* Data descriptor pointer */ -#define UDC_CONFIRM_ADDR 0x18 /* Write/Read confirmation */ - -#define UDC_DEVCFG_ADDR 0x400 /* Device configuration */ -#define UDC_DEVCTL_ADDR 0x404 /* Device control */ -#define UDC_DEVSTS_ADDR 0x408 /* Device status */ -#define UDC_DEVIRQSTS_ADDR 0x40C /* Device irq status */ -#define UDC_DEVIRQMSK_ADDR 0x410 /* Device irq mask */ -#define UDC_EPIRQSTS_ADDR 0x414 /* Endpoint irq status */ -#define UDC_EPIRQMSK_ADDR 0x418 /* Endpoint irq mask */ -#define UDC_DEVLPM_ADDR 0x41C /* LPM control / status */ -#define UDC_CSR_BUSY_ADDR 0x4f0 /* UDC_CSR_BUSY Status register */ -#define UDC_SRST_ADDR 0x4fc /* SOFT RESET register */ -#define UDC_CSR_ADDR 0x500 /* USB_DEVICE endpoint register */ - -/* Endpoint control register */ -/* Bit position */ -#define UDC_EPCTL_MRXFLUSH (1 << 12) -#define UDC_EPCTL_RRDY (1 << 9) -#define UDC_EPCTL_CNAK (1 << 8) -#define UDC_EPCTL_SNAK (1 << 7) -#define UDC_EPCTL_NAK (1 << 6) -#define UDC_EPCTL_P (1 << 3) -#define UDC_EPCTL_F (1 << 1) -#define UDC_EPCTL_S (1 << 0) -#define UDC_EPCTL_ET_SHIFT 4 -/* Mask patern */ -#define UDC_EPCTL_ET_MASK 0x00000030 -/* Value for ET field */ -#define UDC_EPCTL_ET_CONTROL 0 -#define UDC_EPCTL_ET_ISO 1 -#define UDC_EPCTL_ET_BULK 2 -#define UDC_EPCTL_ET_INTERRUPT 3 - -/* Endpoint status register */ -/* Bit position */ -#define UDC_EPSTS_XFERDONE (1 << 27) -#define UDC_EPSTS_RSS (1 << 26) -#define UDC_EPSTS_RCS (1 << 25) -#define UDC_EPSTS_TXEMPTY (1 << 24) -#define UDC_EPSTS_TDC (1 << 10) -#define UDC_EPSTS_HE (1 << 9) -#define UDC_EPSTS_MRXFIFO_EMP (1 << 8) -#define UDC_EPSTS_BNA (1 << 7) -#define UDC_EPSTS_IN (1 << 6) -#define UDC_EPSTS_OUT_SHIFT 4 -/* Mask patern */ -#define UDC_EPSTS_OUT_MASK 0x00000030 -#define UDC_EPSTS_ALL_CLR_MASK 0x1F0006F0 -/* Value for OUT field */ -#define UDC_EPSTS_OUT_SETUP 2 -#define UDC_EPSTS_OUT_DATA 1 - -/* Device configuration register */ -/* Bit position */ -#define UDC_DEVCFG_CSR_PRG (1 << 17) -#define UDC_DEVCFG_SP (1 << 3) -/* SPD Valee */ -#define UDC_DEVCFG_SPD_HS 0x0 -#define UDC_DEVCFG_SPD_FS 0x1 -#define UDC_DEVCFG_SPD_LS 0x2 - -/* Device control register */ -/* Bit position */ -#define UDC_DEVCTL_THLEN_SHIFT 24 -#define UDC_DEVCTL_BRLEN_SHIFT 16 -#define UDC_DEVCTL_CSR_DONE (1 << 13) -#define UDC_DEVCTL_SD (1 << 10) -#define UDC_DEVCTL_MODE (1 << 9) -#define UDC_DEVCTL_BREN (1 << 8) -#define UDC_DEVCTL_THE (1 << 7) -#define UDC_DEVCTL_DU (1 << 4) -#define UDC_DEVCTL_TDE (1 << 3) -#define UDC_DEVCTL_RDE (1 << 2) -#define UDC_DEVCTL_RES (1 << 0) - -/* Device status register */ -/* Bit position */ -#define UDC_DEVSTS_TS_SHIFT 18 -#define UDC_DEVSTS_ENUM_SPEED_SHIFT 13 -#define UDC_DEVSTS_ALT_SHIFT 8 -#define UDC_DEVSTS_INTF_SHIFT 4 -#define UDC_DEVSTS_CFG_SHIFT 0 -/* Mask patern */ -#define UDC_DEVSTS_TS_MASK 0xfffc0000 -#define UDC_DEVSTS_ENUM_SPEED_MASK 0x00006000 -#define UDC_DEVSTS_ALT_MASK 0x00000f00 -#define UDC_DEVSTS_INTF_MASK 0x000000f0 -#define UDC_DEVSTS_CFG_MASK 0x0000000f -/* value for maximum speed for SPEED field */ -#define UDC_DEVSTS_ENUM_SPEED_FULL 1 -#define UDC_DEVSTS_ENUM_SPEED_HIGH 0 -#define UDC_DEVSTS_ENUM_SPEED_LOW 2 -#define UDC_DEVSTS_ENUM_SPEED_FULLX 3 - -/* Device irq register */ -/* Bit position */ -#define UDC_DEVINT_RWKP (1 << 7) -#define UDC_DEVINT_ENUM (1 << 6) -#define UDC_DEVINT_SOF (1 << 5) -#define UDC_DEVINT_US (1 << 4) -#define UDC_DEVINT_UR (1 << 3) -#define UDC_DEVINT_ES (1 << 2) -#define UDC_DEVINT_SI (1 << 1) -#define UDC_DEVINT_SC (1 << 0) -/* Mask patern */ -#define UDC_DEVINT_MSK 0x7f - -/* Endpoint irq register */ -/* Bit position */ -#define UDC_EPINT_IN_SHIFT 0 -#define UDC_EPINT_OUT_SHIFT 16 -#define UDC_EPINT_IN_EP0 (1 << 0) -#define UDC_EPINT_OUT_EP0 (1 << 16) -/* Mask patern */ -#define UDC_EPINT_MSK_DISABLE_ALL 0xffffffff - -/* UDC_CSR_BUSY Status register */ -/* Bit position */ -#define UDC_CSR_BUSY (1 << 0) - -/* SOFT RESET register */ -/* Bit position */ -#define UDC_PSRST (1 << 1) -#define UDC_SRST (1 << 0) - -/* USB_DEVICE endpoint register */ -/* Bit position */ -#define UDC_CSR_NE_NUM_SHIFT 0 -#define UDC_CSR_NE_DIR_SHIFT 4 -#define UDC_CSR_NE_TYPE_SHIFT 5 -#define UDC_CSR_NE_CFG_SHIFT 7 -#define UDC_CSR_NE_INTF_SHIFT 11 -#define UDC_CSR_NE_ALT_SHIFT 15 -#define UDC_CSR_NE_MAX_PKT_SHIFT 19 -/* Mask patern */ -#define UDC_CSR_NE_NUM_MASK 0x0000000f -#define UDC_CSR_NE_DIR_MASK 0x00000010 -#define UDC_CSR_NE_TYPE_MASK 0x00000060 -#define UDC_CSR_NE_CFG_MASK 0x00000780 -#define UDC_CSR_NE_INTF_MASK 0x00007800 -#define UDC_CSR_NE_ALT_MASK 0x00078000 -#define UDC_CSR_NE_MAX_PKT_MASK 0x3ff80000 - -#define PCH_UDC_CSR(ep) (UDC_CSR_ADDR + ep*4) -#define PCH_UDC_EPINT(in, num)\ - (1 << (num + (in ? UDC_EPINT_IN_SHIFT : UDC_EPINT_OUT_SHIFT))) - -/* Index of endpoint */ -#define UDC_EP0IN_IDX 0 -#define UDC_EP0OUT_IDX 1 -#define UDC_EPIN_IDX(ep) (ep * 2) -#define UDC_EPOUT_IDX(ep) (ep * 2 + 1) -#define PCH_UDC_EP0 0 -#define PCH_UDC_EP1 1 -#define PCH_UDC_EP2 2 -#define PCH_UDC_EP3 3 - -/* Number of endpoint */ -#define PCH_UDC_EP_NUM 32 /* Total number of EPs (16 IN,16 OUT) */ -#define PCH_UDC_USED_EP_NUM 4 /* EP number of EP's really used */ -/* Length Value */ -#define PCH_UDC_BRLEN 0x0F /* Burst length */ -#define PCH_UDC_THLEN 0x1F /* Threshold length */ -/* Value of EP Buffer Size */ -#define UDC_EP0IN_BUFF_SIZE 16 -#define UDC_EPIN_BUFF_SIZE 256 -#define UDC_EP0OUT_BUFF_SIZE 16 -#define UDC_EPOUT_BUFF_SIZE 256 -/* Value of EP maximum packet size */ -#define UDC_EP0IN_MAX_PKT_SIZE 64 -#define UDC_EP0OUT_MAX_PKT_SIZE 64 -#define UDC_BULK_MAX_PKT_SIZE 512 - -/* DMA */ -#define DMA_DIR_RX 1 /* DMA for data receive */ -#define DMA_DIR_TX 2 /* DMA for data transmit */ -#define DMA_ADDR_INVALID (~(dma_addr_t)0) -#define UDC_DMA_MAXPACKET 65536 /* maximum packet size for DMA */ - -/** - * struct pch_udc_data_dma_desc - Structure to hold DMA descriptor information - * for data - * @status: Status quadlet - * @reserved: Reserved - * @dataptr: Buffer descriptor - * @next: Next descriptor - */ -struct pch_udc_data_dma_desc { - u32 status; - u32 reserved; - u32 dataptr; - u32 next; -}; - -/** - * struct pch_udc_stp_dma_desc - Structure to hold DMA descriptor information - * for control data - * @status: Status - * @reserved: Reserved - * @data12: First setup word - * @data34: Second setup word - */ -struct pch_udc_stp_dma_desc { - u32 status; - u32 reserved; - struct usb_ctrlrequest request; -} __attribute((packed)); - -/* DMA status definitions */ -/* Buffer status */ -#define PCH_UDC_BUFF_STS 0xC0000000 -#define PCH_UDC_BS_HST_RDY 0x00000000 -#define PCH_UDC_BS_DMA_BSY 0x40000000 -#define PCH_UDC_BS_DMA_DONE 0x80000000 -#define PCH_UDC_BS_HST_BSY 0xC0000000 -/* Rx/Tx Status */ -#define PCH_UDC_RXTX_STS 0x30000000 -#define PCH_UDC_RTS_SUCC 0x00000000 -#define PCH_UDC_RTS_DESERR 0x10000000 -#define PCH_UDC_RTS_BUFERR 0x30000000 -/* Last Descriptor Indication */ -#define PCH_UDC_DMA_LAST 0x08000000 -/* Number of Rx/Tx Bytes Mask */ -#define PCH_UDC_RXTX_BYTES 0x0000ffff - -/** - * struct pch_udc_cfg_data - Structure to hold current configuration - * and interface information - * @cur_cfg: current configuration in use - * @cur_intf: current interface in use - * @cur_alt: current alt interface in use - */ -struct pch_udc_cfg_data { - u16 cur_cfg; - u16 cur_intf; - u16 cur_alt; -}; - -/** - * struct pch_udc_ep - Structure holding a PCH USB device Endpoint information - * @ep: embedded ep request - * @td_stp_phys: for setup request - * @td_data_phys: for data request - * @td_stp: for setup request - * @td_data: for data request - * @dev: reference to device struct - * @offset_addr: offset address of ep register - * @desc: for this ep - * @queue: queue for requests - * @num: endpoint number - * @in: endpoint is IN - * @halted: endpoint halted? - * @epsts: Endpoint status - */ -struct pch_udc_ep { - struct usb_ep ep; - dma_addr_t td_stp_phys; - dma_addr_t td_data_phys; - struct pch_udc_stp_dma_desc *td_stp; - struct pch_udc_data_dma_desc *td_data; - struct pch_udc_dev *dev; - unsigned long offset_addr; - const struct usb_endpoint_descriptor *desc; - struct list_head queue; - unsigned num:5, - in:1, - halted:1; - unsigned long epsts; -}; - -/** - * struct pch_vbus_gpio_data - Structure holding GPIO informaton - * for detecting VBUS - * @port: gpio port number - * @intr: gpio interrupt number - * @irq_work_fall Structure for WorkQueue - * @irq_work_rise Structure for WorkQueue - */ -struct pch_vbus_gpio_data { - int port; - int intr; - struct work_struct irq_work_fall; - struct work_struct irq_work_rise; -}; - -/** - * struct pch_udc_dev - Structure holding complete information - * of the PCH USB device - * @gadget: gadget driver data - * @driver: reference to gadget driver bound - * @pdev: reference to the PCI device - * @ep: array of endpoints - * @lock: protects all state - * @active: enabled the PCI device - * @stall: stall requested - * @prot_stall: protcol stall requested - * @irq_registered: irq registered with system - * @mem_region: device memory mapped - * @registered: driver regsitered with system - * @suspended: driver in suspended state - * @connected: gadget driver associated - * @vbus_session: required vbus_session state - * @set_cfg_not_acked: pending acknowledgement 4 setup - * @waiting_zlp_ack: pending acknowledgement 4 ZLP - * @data_requests: DMA pool for data requests - * @stp_requests: DMA pool for setup requests - * @dma_addr: DMA pool for received - * @ep0out_buf: Buffer for DMA - * @setup_data: Received setup data - * @phys_addr: of device memory - * @base_addr: for mapped device memory - * @irq: IRQ line for the device - * @cfg_data: current cfg, intf, and alt in use - * @vbus_gpio: GPIO informaton for detecting VBUS - */ -struct pch_udc_dev { - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - struct pci_dev *pdev; - struct pch_udc_ep ep[PCH_UDC_EP_NUM]; - spinlock_t lock; /* protects all state */ - unsigned active:1, - stall:1, - prot_stall:1, - irq_registered:1, - mem_region:1, - registered:1, - suspended:1, - connected:1, - vbus_session:1, - set_cfg_not_acked:1, - waiting_zlp_ack:1; - struct pci_pool *data_requests; - struct pci_pool *stp_requests; - dma_addr_t dma_addr; - void *ep0out_buf; - struct usb_ctrlrequest setup_data; - unsigned long phys_addr; - void __iomem *base_addr; - unsigned irq; - struct pch_udc_cfg_data cfg_data; - struct pch_vbus_gpio_data vbus_gpio; -}; - -#define PCH_UDC_PCI_BAR 1 -#define PCI_DEVICE_ID_INTEL_EG20T_UDC 0x8808 -#define PCI_VENDOR_ID_ROHM 0x10DB -#define PCI_DEVICE_ID_ML7213_IOH_UDC 0x801D -#define PCI_DEVICE_ID_ML7831_IOH_UDC 0x8808 - -static const char ep0_string[] = "ep0in"; -static DEFINE_SPINLOCK(udc_stall_spinlock); /* stall spin lock */ -struct pch_udc_dev *pch_udc; /* pointer to device object */ -static bool speed_fs; -module_param_named(speed_fs, speed_fs, bool, S_IRUGO); -MODULE_PARM_DESC(speed_fs, "true for Full speed operation"); - -/** - * struct pch_udc_request - Structure holding a PCH USB device request packet - * @req: embedded ep request - * @td_data_phys: phys. address - * @td_data: first dma desc. of chain - * @td_data_last: last dma desc. of chain - * @queue: associated queue - * @dma_going: DMA in progress for request - * @dma_mapped: DMA memory mapped for request - * @dma_done: DMA completed for request - * @chain_len: chain length - * @buf: Buffer memory for align adjustment - * @dma: DMA memory for align adjustment - */ -struct pch_udc_request { - struct usb_request req; - dma_addr_t td_data_phys; - struct pch_udc_data_dma_desc *td_data; - struct pch_udc_data_dma_desc *td_data_last; - struct list_head queue; - unsigned dma_going:1, - dma_mapped:1, - dma_done:1; - unsigned chain_len; - void *buf; - dma_addr_t dma; -}; - -static inline u32 pch_udc_readl(struct pch_udc_dev *dev, unsigned long reg) -{ - return ioread32(dev->base_addr + reg); -} - -static inline void pch_udc_writel(struct pch_udc_dev *dev, - unsigned long val, unsigned long reg) -{ - iowrite32(val, dev->base_addr + reg); -} - -static inline void pch_udc_bit_set(struct pch_udc_dev *dev, - unsigned long reg, - unsigned long bitmask) -{ - pch_udc_writel(dev, pch_udc_readl(dev, reg) | bitmask, reg); -} - -static inline void pch_udc_bit_clr(struct pch_udc_dev *dev, - unsigned long reg, - unsigned long bitmask) -{ - pch_udc_writel(dev, pch_udc_readl(dev, reg) & ~(bitmask), reg); -} - -static inline u32 pch_udc_ep_readl(struct pch_udc_ep *ep, unsigned long reg) -{ - return ioread32(ep->dev->base_addr + ep->offset_addr + reg); -} - -static inline void pch_udc_ep_writel(struct pch_udc_ep *ep, - unsigned long val, unsigned long reg) -{ - iowrite32(val, ep->dev->base_addr + ep->offset_addr + reg); -} - -static inline void pch_udc_ep_bit_set(struct pch_udc_ep *ep, - unsigned long reg, - unsigned long bitmask) -{ - pch_udc_ep_writel(ep, pch_udc_ep_readl(ep, reg) | bitmask, reg); -} - -static inline void pch_udc_ep_bit_clr(struct pch_udc_ep *ep, - unsigned long reg, - unsigned long bitmask) -{ - pch_udc_ep_writel(ep, pch_udc_ep_readl(ep, reg) & ~(bitmask), reg); -} - -/** - * pch_udc_csr_busy() - Wait till idle. - * @dev: Reference to pch_udc_dev structure - */ -static void pch_udc_csr_busy(struct pch_udc_dev *dev) -{ - unsigned int count = 200; - - /* Wait till idle */ - while ((pch_udc_readl(dev, UDC_CSR_BUSY_ADDR) & UDC_CSR_BUSY) - && --count) - cpu_relax(); - if (!count) - dev_err(&dev->pdev->dev, "%s: wait error\n", __func__); -} - -/** - * pch_udc_write_csr() - Write the command and status registers. - * @dev: Reference to pch_udc_dev structure - * @val: value to be written to CSR register - * @addr: address of CSR register - */ -static void pch_udc_write_csr(struct pch_udc_dev *dev, unsigned long val, - unsigned int ep) -{ - unsigned long reg = PCH_UDC_CSR(ep); - - pch_udc_csr_busy(dev); /* Wait till idle */ - pch_udc_writel(dev, val, reg); - pch_udc_csr_busy(dev); /* Wait till idle */ -} - -/** - * pch_udc_read_csr() - Read the command and status registers. - * @dev: Reference to pch_udc_dev structure - * @addr: address of CSR register - * - * Return codes: content of CSR register - */ -static u32 pch_udc_read_csr(struct pch_udc_dev *dev, unsigned int ep) -{ - unsigned long reg = PCH_UDC_CSR(ep); - - pch_udc_csr_busy(dev); /* Wait till idle */ - pch_udc_readl(dev, reg); /* Dummy read */ - pch_udc_csr_busy(dev); /* Wait till idle */ - return pch_udc_readl(dev, reg); -} - -/** - * pch_udc_rmt_wakeup() - Initiate for remote wakeup - * @dev: Reference to pch_udc_dev structure - */ -static inline void pch_udc_rmt_wakeup(struct pch_udc_dev *dev) -{ - pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES); - mdelay(1); - pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES); -} - -/** - * pch_udc_get_frame() - Get the current frame from device status register - * @dev: Reference to pch_udc_dev structure - * Retern current frame - */ -static inline int pch_udc_get_frame(struct pch_udc_dev *dev) -{ - u32 frame = pch_udc_readl(dev, UDC_DEVSTS_ADDR); - return (frame & UDC_DEVSTS_TS_MASK) >> UDC_DEVSTS_TS_SHIFT; -} - -/** - * pch_udc_clear_selfpowered() - Clear the self power control - * @dev: Reference to pch_udc_regs structure - */ -static inline void pch_udc_clear_selfpowered(struct pch_udc_dev *dev) -{ - pch_udc_bit_clr(dev, UDC_DEVCFG_ADDR, UDC_DEVCFG_SP); -} - -/** - * pch_udc_set_selfpowered() - Set the self power control - * @dev: Reference to pch_udc_regs structure - */ -static inline void pch_udc_set_selfpowered(struct pch_udc_dev *dev) -{ - pch_udc_bit_set(dev, UDC_DEVCFG_ADDR, UDC_DEVCFG_SP); -} - -/** - * pch_udc_set_disconnect() - Set the disconnect status. - * @dev: Reference to pch_udc_regs structure - */ -static inline void pch_udc_set_disconnect(struct pch_udc_dev *dev) -{ - pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_SD); -} - -/** - * pch_udc_clear_disconnect() - Clear the disconnect status. - * @dev: Reference to pch_udc_regs structure - */ -static void pch_udc_clear_disconnect(struct pch_udc_dev *dev) -{ - /* Clear the disconnect */ - pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES); - pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_SD); - mdelay(1); - /* Resume USB signalling */ - pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES); -} - -/** - * pch_udc_reconnect() - This API initializes usb device controller, - * and clear the disconnect status. - * @dev: Reference to pch_udc_regs structure - */ -static void pch_udc_init(struct pch_udc_dev *dev); -static void pch_udc_reconnect(struct pch_udc_dev *dev) -{ - pch_udc_init(dev); - - /* enable device interrupts */ - /* pch_udc_enable_interrupts() */ - pch_udc_bit_clr(dev, UDC_DEVIRQMSK_ADDR, - UDC_DEVINT_UR | UDC_DEVINT_ENUM); - - /* Clear the disconnect */ - pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES); - pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_SD); - mdelay(1); - /* Resume USB signalling */ - pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES); -} - -/** - * pch_udc_vbus_session() - set or clearr the disconnect status. - * @dev: Reference to pch_udc_regs structure - * @is_active: Parameter specifying the action - * 0: indicating VBUS power is ending - * !0: indicating VBUS power is starting - */ -static inline void pch_udc_vbus_session(struct pch_udc_dev *dev, - int is_active) -{ - if (is_active) { - pch_udc_reconnect(dev); - dev->vbus_session = 1; - } else { - if (dev->driver && dev->driver->disconnect) { - spin_unlock(&dev->lock); - dev->driver->disconnect(&dev->gadget); - spin_lock(&dev->lock); - } - pch_udc_set_disconnect(dev); - dev->vbus_session = 0; - } -} - -/** - * pch_udc_ep_set_stall() - Set the stall of endpoint - * @ep: Reference to structure of type pch_udc_ep_regs - */ -static void pch_udc_ep_set_stall(struct pch_udc_ep *ep) -{ - if (ep->in) { - pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_F); - pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_S); - } else { - pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_S); - } -} - -/** - * pch_udc_ep_clear_stall() - Clear the stall of endpoint - * @ep: Reference to structure of type pch_udc_ep_regs - */ -static inline void pch_udc_ep_clear_stall(struct pch_udc_ep *ep) -{ - /* Clear the stall */ - pch_udc_ep_bit_clr(ep, UDC_EPCTL_ADDR, UDC_EPCTL_S); - /* Clear NAK by writing CNAK */ - pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_CNAK); -} - -/** - * pch_udc_ep_set_trfr_type() - Set the transfer type of endpoint - * @ep: Reference to structure of type pch_udc_ep_regs - * @type: Type of endpoint - */ -static inline void pch_udc_ep_set_trfr_type(struct pch_udc_ep *ep, - u8 type) -{ - pch_udc_ep_writel(ep, ((type << UDC_EPCTL_ET_SHIFT) & - UDC_EPCTL_ET_MASK), UDC_EPCTL_ADDR); -} - -/** - * pch_udc_ep_set_bufsz() - Set the maximum packet size for the endpoint - * @ep: Reference to structure of type pch_udc_ep_regs - * @buf_size: The buffer word size - */ -static void pch_udc_ep_set_bufsz(struct pch_udc_ep *ep, - u32 buf_size, u32 ep_in) -{ - u32 data; - if (ep_in) { - data = pch_udc_ep_readl(ep, UDC_BUFIN_FRAMENUM_ADDR); - data = (data & 0xffff0000) | (buf_size & 0xffff); - pch_udc_ep_writel(ep, data, UDC_BUFIN_FRAMENUM_ADDR); - } else { - data = pch_udc_ep_readl(ep, UDC_BUFOUT_MAXPKT_ADDR); - data = (buf_size << 16) | (data & 0xffff); - pch_udc_ep_writel(ep, data, UDC_BUFOUT_MAXPKT_ADDR); - } -} - -/** - * pch_udc_ep_set_maxpkt() - Set the Max packet size for the endpoint - * @ep: Reference to structure of type pch_udc_ep_regs - * @pkt_size: The packet byte size - */ -static void pch_udc_ep_set_maxpkt(struct pch_udc_ep *ep, u32 pkt_size) -{ - u32 data = pch_udc_ep_readl(ep, UDC_BUFOUT_MAXPKT_ADDR); - data = (data & 0xffff0000) | (pkt_size & 0xffff); - pch_udc_ep_writel(ep, data, UDC_BUFOUT_MAXPKT_ADDR); -} - -/** - * pch_udc_ep_set_subptr() - Set the Setup buffer pointer for the endpoint - * @ep: Reference to structure of type pch_udc_ep_regs - * @addr: Address of the register - */ -static inline void pch_udc_ep_set_subptr(struct pch_udc_ep *ep, u32 addr) -{ - pch_udc_ep_writel(ep, addr, UDC_SUBPTR_ADDR); -} - -/** - * pch_udc_ep_set_ddptr() - Set the Data descriptor pointer for the endpoint - * @ep: Reference to structure of type pch_udc_ep_regs - * @addr: Address of the register - */ -static inline void pch_udc_ep_set_ddptr(struct pch_udc_ep *ep, u32 addr) -{ - pch_udc_ep_writel(ep, addr, UDC_DESPTR_ADDR); -} - -/** - * pch_udc_ep_set_pd() - Set the poll demand bit for the endpoint - * @ep: Reference to structure of type pch_udc_ep_regs - */ -static inline void pch_udc_ep_set_pd(struct pch_udc_ep *ep) -{ - pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_P); -} - -/** - * pch_udc_ep_set_rrdy() - Set the receive ready bit for the endpoint - * @ep: Reference to structure of type pch_udc_ep_regs - */ -static inline void pch_udc_ep_set_rrdy(struct pch_udc_ep *ep) -{ - pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_RRDY); -} - -/** - * pch_udc_ep_clear_rrdy() - Clear the receive ready bit for the endpoint - * @ep: Reference to structure of type pch_udc_ep_regs - */ -static inline void pch_udc_ep_clear_rrdy(struct pch_udc_ep *ep) -{ - pch_udc_ep_bit_clr(ep, UDC_EPCTL_ADDR, UDC_EPCTL_RRDY); -} - -/** - * pch_udc_set_dma() - Set the 'TDE' or RDE bit of device control - * register depending on the direction specified - * @dev: Reference to structure of type pch_udc_regs - * @dir: whether Tx or Rx - * DMA_DIR_RX: Receive - * DMA_DIR_TX: Transmit - */ -static inline void pch_udc_set_dma(struct pch_udc_dev *dev, int dir) -{ - if (dir == DMA_DIR_RX) - pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RDE); - else if (dir == DMA_DIR_TX) - pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_TDE); -} - -/** - * pch_udc_clear_dma() - Clear the 'TDE' or RDE bit of device control - * register depending on the direction specified - * @dev: Reference to structure of type pch_udc_regs - * @dir: Whether Tx or Rx - * DMA_DIR_RX: Receive - * DMA_DIR_TX: Transmit - */ -static inline void pch_udc_clear_dma(struct pch_udc_dev *dev, int dir) -{ - if (dir == DMA_DIR_RX) - pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RDE); - else if (dir == DMA_DIR_TX) - pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_TDE); -} - -/** - * pch_udc_set_csr_done() - Set the device control register - * CSR done field (bit 13) - * @dev: reference to structure of type pch_udc_regs - */ -static inline void pch_udc_set_csr_done(struct pch_udc_dev *dev) -{ - pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_CSR_DONE); -} - -/** - * pch_udc_disable_interrupts() - Disables the specified interrupts - * @dev: Reference to structure of type pch_udc_regs - * @mask: Mask to disable interrupts - */ -static inline void pch_udc_disable_interrupts(struct pch_udc_dev *dev, - u32 mask) -{ - pch_udc_bit_set(dev, UDC_DEVIRQMSK_ADDR, mask); -} - -/** - * pch_udc_enable_interrupts() - Enable the specified interrupts - * @dev: Reference to structure of type pch_udc_regs - * @mask: Mask to enable interrupts - */ -static inline void pch_udc_enable_interrupts(struct pch_udc_dev *dev, - u32 mask) -{ - pch_udc_bit_clr(dev, UDC_DEVIRQMSK_ADDR, mask); -} - -/** - * pch_udc_disable_ep_interrupts() - Disable endpoint interrupts - * @dev: Reference to structure of type pch_udc_regs - * @mask: Mask to disable interrupts - */ -static inline void pch_udc_disable_ep_interrupts(struct pch_udc_dev *dev, - u32 mask) -{ - pch_udc_bit_set(dev, UDC_EPIRQMSK_ADDR, mask); -} - -/** - * pch_udc_enable_ep_interrupts() - Enable endpoint interrupts - * @dev: Reference to structure of type pch_udc_regs - * @mask: Mask to enable interrupts - */ -static inline void pch_udc_enable_ep_interrupts(struct pch_udc_dev *dev, - u32 mask) -{ - pch_udc_bit_clr(dev, UDC_EPIRQMSK_ADDR, mask); -} - -/** - * pch_udc_read_device_interrupts() - Read the device interrupts - * @dev: Reference to structure of type pch_udc_regs - * Retern The device interrupts - */ -static inline u32 pch_udc_read_device_interrupts(struct pch_udc_dev *dev) -{ - return pch_udc_readl(dev, UDC_DEVIRQSTS_ADDR); -} - -/** - * pch_udc_write_device_interrupts() - Write device interrupts - * @dev: Reference to structure of type pch_udc_regs - * @val: The value to be written to interrupt register - */ -static inline void pch_udc_write_device_interrupts(struct pch_udc_dev *dev, - u32 val) -{ - pch_udc_writel(dev, val, UDC_DEVIRQSTS_ADDR); -} - -/** - * pch_udc_read_ep_interrupts() - Read the endpoint interrupts - * @dev: Reference to structure of type pch_udc_regs - * Retern The endpoint interrupt - */ -static inline u32 pch_udc_read_ep_interrupts(struct pch_udc_dev *dev) -{ - return pch_udc_readl(dev, UDC_EPIRQSTS_ADDR); -} - -/** - * pch_udc_write_ep_interrupts() - Clear endpoint interupts - * @dev: Reference to structure of type pch_udc_regs - * @val: The value to be written to interrupt register - */ -static inline void pch_udc_write_ep_interrupts(struct pch_udc_dev *dev, - u32 val) -{ - pch_udc_writel(dev, val, UDC_EPIRQSTS_ADDR); -} - -/** - * pch_udc_read_device_status() - Read the device status - * @dev: Reference to structure of type pch_udc_regs - * Retern The device status - */ -static inline u32 pch_udc_read_device_status(struct pch_udc_dev *dev) -{ - return pch_udc_readl(dev, UDC_DEVSTS_ADDR); -} - -/** - * pch_udc_read_ep_control() - Read the endpoint control - * @ep: Reference to structure of type pch_udc_ep_regs - * Retern The endpoint control register value - */ -static inline u32 pch_udc_read_ep_control(struct pch_udc_ep *ep) -{ - return pch_udc_ep_readl(ep, UDC_EPCTL_ADDR); -} - -/** - * pch_udc_clear_ep_control() - Clear the endpoint control register - * @ep: Reference to structure of type pch_udc_ep_regs - * Retern The endpoint control register value - */ -static inline void pch_udc_clear_ep_control(struct pch_udc_ep *ep) -{ - return pch_udc_ep_writel(ep, 0, UDC_EPCTL_ADDR); -} - -/** - * pch_udc_read_ep_status() - Read the endpoint status - * @ep: Reference to structure of type pch_udc_ep_regs - * Retern The endpoint status - */ -static inline u32 pch_udc_read_ep_status(struct pch_udc_ep *ep) -{ - return pch_udc_ep_readl(ep, UDC_EPSTS_ADDR); -} - -/** - * pch_udc_clear_ep_status() - Clear the endpoint status - * @ep: Reference to structure of type pch_udc_ep_regs - * @stat: Endpoint status - */ -static inline void pch_udc_clear_ep_status(struct pch_udc_ep *ep, - u32 stat) -{ - return pch_udc_ep_writel(ep, stat, UDC_EPSTS_ADDR); -} - -/** - * pch_udc_ep_set_nak() - Set the bit 7 (SNAK field) - * of the endpoint control register - * @ep: Reference to structure of type pch_udc_ep_regs - */ -static inline void pch_udc_ep_set_nak(struct pch_udc_ep *ep) -{ - pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_SNAK); -} - -/** - * pch_udc_ep_clear_nak() - Set the bit 8 (CNAK field) - * of the endpoint control register - * @ep: reference to structure of type pch_udc_ep_regs - */ -static void pch_udc_ep_clear_nak(struct pch_udc_ep *ep) -{ - unsigned int loopcnt = 0; - struct pch_udc_dev *dev = ep->dev; - - if (!(pch_udc_ep_readl(ep, UDC_EPCTL_ADDR) & UDC_EPCTL_NAK)) - return; - if (!ep->in) { - loopcnt = 10000; - while (!(pch_udc_read_ep_status(ep) & UDC_EPSTS_MRXFIFO_EMP) && - --loopcnt) - udelay(5); - if (!loopcnt) - dev_err(&dev->pdev->dev, "%s: RxFIFO not Empty\n", - __func__); - } - loopcnt = 10000; - while ((pch_udc_read_ep_control(ep) & UDC_EPCTL_NAK) && --loopcnt) { - pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_CNAK); - udelay(5); - } - if (!loopcnt) - dev_err(&dev->pdev->dev, "%s: Clear NAK not set for ep%d%s\n", - __func__, ep->num, (ep->in ? "in" : "out")); -} - -/** - * pch_udc_ep_fifo_flush() - Flush the endpoint fifo - * @ep: reference to structure of type pch_udc_ep_regs - * @dir: direction of endpoint - * 0: endpoint is OUT - * !0: endpoint is IN - */ -static void pch_udc_ep_fifo_flush(struct pch_udc_ep *ep, int dir) -{ - if (dir) { /* IN ep */ - pch_udc_ep_bit_set(ep, UDC_EPCTL_ADDR, UDC_EPCTL_F); - return; - } -} - -/** - * pch_udc_ep_enable() - This api enables endpoint - * @regs: Reference to structure pch_udc_ep_regs - * @desc: endpoint descriptor - */ -static void pch_udc_ep_enable(struct pch_udc_ep *ep, - struct pch_udc_cfg_data *cfg, - const struct usb_endpoint_descriptor *desc) -{ - u32 val = 0; - u32 buff_size = 0; - - pch_udc_ep_set_trfr_type(ep, desc->bmAttributes); - if (ep->in) - buff_size = UDC_EPIN_BUFF_SIZE; - else - buff_size = UDC_EPOUT_BUFF_SIZE; - pch_udc_ep_set_bufsz(ep, buff_size, ep->in); - pch_udc_ep_set_maxpkt(ep, usb_endpoint_maxp(desc)); - pch_udc_ep_set_nak(ep); - pch_udc_ep_fifo_flush(ep, ep->in); - /* Configure the endpoint */ - val = ep->num << UDC_CSR_NE_NUM_SHIFT | ep->in << UDC_CSR_NE_DIR_SHIFT | - ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) << - UDC_CSR_NE_TYPE_SHIFT) | - (cfg->cur_cfg << UDC_CSR_NE_CFG_SHIFT) | - (cfg->cur_intf << UDC_CSR_NE_INTF_SHIFT) | - (cfg->cur_alt << UDC_CSR_NE_ALT_SHIFT) | - usb_endpoint_maxp(desc) << UDC_CSR_NE_MAX_PKT_SHIFT; - - if (ep->in) - pch_udc_write_csr(ep->dev, val, UDC_EPIN_IDX(ep->num)); - else - pch_udc_write_csr(ep->dev, val, UDC_EPOUT_IDX(ep->num)); -} - -/** - * pch_udc_ep_disable() - This api disables endpoint - * @regs: Reference to structure pch_udc_ep_regs - */ -static void pch_udc_ep_disable(struct pch_udc_ep *ep) -{ - if (ep->in) { - /* flush the fifo */ - pch_udc_ep_writel(ep, UDC_EPCTL_F, UDC_EPCTL_ADDR); - /* set NAK */ - pch_udc_ep_writel(ep, UDC_EPCTL_SNAK, UDC_EPCTL_ADDR); - pch_udc_ep_bit_set(ep, UDC_EPSTS_ADDR, UDC_EPSTS_IN); - } else { - /* set NAK */ - pch_udc_ep_writel(ep, UDC_EPCTL_SNAK, UDC_EPCTL_ADDR); - } - /* reset desc pointer */ - pch_udc_ep_writel(ep, 0, UDC_DESPTR_ADDR); -} - -/** - * pch_udc_wait_ep_stall() - Wait EP stall. - * @dev: Reference to pch_udc_dev structure - */ -static void pch_udc_wait_ep_stall(struct pch_udc_ep *ep) -{ - unsigned int count = 10000; - - /* Wait till idle */ - while ((pch_udc_read_ep_control(ep) & UDC_EPCTL_S) && --count) - udelay(5); - if (!count) - dev_err(&ep->dev->pdev->dev, "%s: wait error\n", __func__); -} - -/** - * pch_udc_init() - This API initializes usb device controller - * @dev: Rreference to pch_udc_regs structure - */ -static void pch_udc_init(struct pch_udc_dev *dev) -{ - if (NULL == dev) { - pr_err("%s: Invalid address\n", __func__); - return; - } - /* Soft Reset and Reset PHY */ - pch_udc_writel(dev, UDC_SRST, UDC_SRST_ADDR); - pch_udc_writel(dev, UDC_SRST | UDC_PSRST, UDC_SRST_ADDR); - mdelay(1); - pch_udc_writel(dev, UDC_SRST, UDC_SRST_ADDR); - pch_udc_writel(dev, 0x00, UDC_SRST_ADDR); - mdelay(1); - /* mask and clear all device interrupts */ - pch_udc_bit_set(dev, UDC_DEVIRQMSK_ADDR, UDC_DEVINT_MSK); - pch_udc_bit_set(dev, UDC_DEVIRQSTS_ADDR, UDC_DEVINT_MSK); - - /* mask and clear all ep interrupts */ - pch_udc_bit_set(dev, UDC_EPIRQMSK_ADDR, UDC_EPINT_MSK_DISABLE_ALL); - pch_udc_bit_set(dev, UDC_EPIRQSTS_ADDR, UDC_EPINT_MSK_DISABLE_ALL); - - /* enable dynamic CSR programmingi, self powered and device speed */ - if (speed_fs) - pch_udc_bit_set(dev, UDC_DEVCFG_ADDR, UDC_DEVCFG_CSR_PRG | - UDC_DEVCFG_SP | UDC_DEVCFG_SPD_FS); - else /* defaul high speed */ - pch_udc_bit_set(dev, UDC_DEVCFG_ADDR, UDC_DEVCFG_CSR_PRG | - UDC_DEVCFG_SP | UDC_DEVCFG_SPD_HS); - pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, - (PCH_UDC_THLEN << UDC_DEVCTL_THLEN_SHIFT) | - (PCH_UDC_BRLEN << UDC_DEVCTL_BRLEN_SHIFT) | - UDC_DEVCTL_MODE | UDC_DEVCTL_BREN | - UDC_DEVCTL_THE); -} - -/** - * pch_udc_exit() - This API exit usb device controller - * @dev: Reference to pch_udc_regs structure - */ -static void pch_udc_exit(struct pch_udc_dev *dev) -{ - /* mask all device interrupts */ - pch_udc_bit_set(dev, UDC_DEVIRQMSK_ADDR, UDC_DEVINT_MSK); - /* mask all ep interrupts */ - pch_udc_bit_set(dev, UDC_EPIRQMSK_ADDR, UDC_EPINT_MSK_DISABLE_ALL); - /* put device in disconnected state */ - pch_udc_set_disconnect(dev); -} - -/** - * pch_udc_pcd_get_frame() - This API is invoked to get the current frame number - * @gadget: Reference to the gadget driver - * - * Return codes: - * 0: Success - * -EINVAL: If the gadget passed is NULL - */ -static int pch_udc_pcd_get_frame(struct usb_gadget *gadget) -{ - struct pch_udc_dev *dev; - - if (!gadget) - return -EINVAL; - dev = container_of(gadget, struct pch_udc_dev, gadget); - return pch_udc_get_frame(dev); -} - -/** - * pch_udc_pcd_wakeup() - This API is invoked to initiate a remote wakeup - * @gadget: Reference to the gadget driver - * - * Return codes: - * 0: Success - * -EINVAL: If the gadget passed is NULL - */ -static int pch_udc_pcd_wakeup(struct usb_gadget *gadget) -{ - struct pch_udc_dev *dev; - unsigned long flags; - - if (!gadget) - return -EINVAL; - dev = container_of(gadget, struct pch_udc_dev, gadget); - spin_lock_irqsave(&dev->lock, flags); - pch_udc_rmt_wakeup(dev); - spin_unlock_irqrestore(&dev->lock, flags); - return 0; -} - -/** - * pch_udc_pcd_selfpowered() - This API is invoked to specify whether the device - * is self powered or not - * @gadget: Reference to the gadget driver - * @value: Specifies self powered or not - * - * Return codes: - * 0: Success - * -EINVAL: If the gadget passed is NULL - */ -static int pch_udc_pcd_selfpowered(struct usb_gadget *gadget, int value) -{ - struct pch_udc_dev *dev; - - if (!gadget) - return -EINVAL; - dev = container_of(gadget, struct pch_udc_dev, gadget); - if (value) - pch_udc_set_selfpowered(dev); - else - pch_udc_clear_selfpowered(dev); - return 0; -} - -/** - * pch_udc_pcd_pullup() - This API is invoked to make the device - * visible/invisible to the host - * @gadget: Reference to the gadget driver - * @is_on: Specifies whether the pull up is made active or inactive - * - * Return codes: - * 0: Success - * -EINVAL: If the gadget passed is NULL - */ -static int pch_udc_pcd_pullup(struct usb_gadget *gadget, int is_on) -{ - struct pch_udc_dev *dev; - - if (!gadget) - return -EINVAL; - dev = container_of(gadget, struct pch_udc_dev, gadget); - if (is_on) { - pch_udc_reconnect(dev); - } else { - if (dev->driver && dev->driver->disconnect) { - spin_unlock(&dev->lock); - dev->driver->disconnect(&dev->gadget); - spin_lock(&dev->lock); - } - pch_udc_set_disconnect(dev); - } - - return 0; -} - -/** - * pch_udc_pcd_vbus_session() - This API is used by a driver for an external - * transceiver (or GPIO) that - * detects a VBUS power session starting/ending - * @gadget: Reference to the gadget driver - * @is_active: specifies whether the session is starting or ending - * - * Return codes: - * 0: Success - * -EINVAL: If the gadget passed is NULL - */ -static int pch_udc_pcd_vbus_session(struct usb_gadget *gadget, int is_active) -{ - struct pch_udc_dev *dev; - - if (!gadget) - return -EINVAL; - dev = container_of(gadget, struct pch_udc_dev, gadget); - pch_udc_vbus_session(dev, is_active); - return 0; -} - -/** - * pch_udc_pcd_vbus_draw() - This API is used by gadget drivers during - * SET_CONFIGURATION calls to - * specify how much power the device can consume - * @gadget: Reference to the gadget driver - * @mA: specifies the current limit in 2mA unit - * - * Return codes: - * -EINVAL: If the gadget passed is NULL - * -EOPNOTSUPP: - */ -static int pch_udc_pcd_vbus_draw(struct usb_gadget *gadget, unsigned int mA) -{ - return -EOPNOTSUPP; -} - -static int pch_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int pch_udc_stop(struct usb_gadget_driver *driver); -static const struct usb_gadget_ops pch_udc_ops = { - .get_frame = pch_udc_pcd_get_frame, - .wakeup = pch_udc_pcd_wakeup, - .set_selfpowered = pch_udc_pcd_selfpowered, - .pullup = pch_udc_pcd_pullup, - .vbus_session = pch_udc_pcd_vbus_session, - .vbus_draw = pch_udc_pcd_vbus_draw, - .start = pch_udc_start, - .stop = pch_udc_stop, -}; - -/** - * pch_vbus_gpio_get_value() - This API gets value of GPIO port as VBUS status. - * @dev: Reference to the driver structure - * - * Return value: - * 1: VBUS is high - * 0: VBUS is low - * -1: It is not enable to detect VBUS using GPIO - */ -static int pch_vbus_gpio_get_value(struct pch_udc_dev *dev) -{ - int vbus = 0; - - if (dev->vbus_gpio.port) - vbus = gpio_get_value(dev->vbus_gpio.port) ? 1 : 0; - else - vbus = -1; - - return vbus; -} - -/** - * pch_vbus_gpio_work_fall() - This API keeps watch on VBUS becoming Low. - * If VBUS is Low, disconnect is processed - * @irq_work: Structure for WorkQueue - * - */ -static void pch_vbus_gpio_work_fall(struct work_struct *irq_work) -{ - struct pch_vbus_gpio_data *vbus_gpio = container_of(irq_work, - struct pch_vbus_gpio_data, irq_work_fall); - struct pch_udc_dev *dev = - container_of(vbus_gpio, struct pch_udc_dev, vbus_gpio); - int vbus_saved = -1; - int vbus; - int count; - - if (!dev->vbus_gpio.port) - return; - - for (count = 0; count < (PCH_VBUS_PERIOD / PCH_VBUS_INTERVAL); - count++) { - vbus = pch_vbus_gpio_get_value(dev); - - if ((vbus_saved == vbus) && (vbus == 0)) { - dev_dbg(&dev->pdev->dev, "VBUS fell"); - if (dev->driver - && dev->driver->disconnect) { - dev->driver->disconnect( - &dev->gadget); - } - if (dev->vbus_gpio.intr) - pch_udc_init(dev); - else - pch_udc_reconnect(dev); - return; - } - vbus_saved = vbus; - mdelay(PCH_VBUS_INTERVAL); - } -} - -/** - * pch_vbus_gpio_work_rise() - This API checks VBUS is High. - * If VBUS is High, connect is processed - * @irq_work: Structure for WorkQueue - * - */ -static void pch_vbus_gpio_work_rise(struct work_struct *irq_work) -{ - struct pch_vbus_gpio_data *vbus_gpio = container_of(irq_work, - struct pch_vbus_gpio_data, irq_work_rise); - struct pch_udc_dev *dev = - container_of(vbus_gpio, struct pch_udc_dev, vbus_gpio); - int vbus; - - if (!dev->vbus_gpio.port) - return; - - mdelay(PCH_VBUS_INTERVAL); - vbus = pch_vbus_gpio_get_value(dev); - - if (vbus == 1) { - dev_dbg(&dev->pdev->dev, "VBUS rose"); - pch_udc_reconnect(dev); - return; - } -} - -/** - * pch_vbus_gpio_irq() - IRQ handler for GPIO intrerrupt for changing VBUS - * @irq: Interrupt request number - * @dev: Reference to the device structure - * - * Return codes: - * 0: Success - * -EINVAL: GPIO port is invalid or can't be initialized. - */ -static irqreturn_t pch_vbus_gpio_irq(int irq, void *data) -{ - struct pch_udc_dev *dev = (struct pch_udc_dev *)data; - - if (!dev->vbus_gpio.port || !dev->vbus_gpio.intr) - return IRQ_NONE; - - if (pch_vbus_gpio_get_value(dev)) - schedule_work(&dev->vbus_gpio.irq_work_rise); - else - schedule_work(&dev->vbus_gpio.irq_work_fall); - - return IRQ_HANDLED; -} - -/** - * pch_vbus_gpio_init() - This API initializes GPIO port detecting VBUS. - * @dev: Reference to the driver structure - * @vbus_gpio Number of GPIO port to detect gpio - * - * Return codes: - * 0: Success - * -EINVAL: GPIO port is invalid or can't be initialized. - */ -static int pch_vbus_gpio_init(struct pch_udc_dev *dev, int vbus_gpio_port) -{ - int err; - int irq_num = 0; - - dev->vbus_gpio.port = 0; - dev->vbus_gpio.intr = 0; - - if (vbus_gpio_port <= -1) - return -EINVAL; - - err = gpio_is_valid(vbus_gpio_port); - if (!err) { - pr_err("%s: gpio port %d is invalid\n", - __func__, vbus_gpio_port); - return -EINVAL; - } - - err = gpio_request(vbus_gpio_port, "pch_vbus"); - if (err) { - pr_err("%s: can't request gpio port %d, err: %d\n", - __func__, vbus_gpio_port, err); - return -EINVAL; - } - - dev->vbus_gpio.port = vbus_gpio_port; - gpio_direction_input(vbus_gpio_port); - INIT_WORK(&dev->vbus_gpio.irq_work_fall, pch_vbus_gpio_work_fall); - - irq_num = gpio_to_irq(vbus_gpio_port); - if (irq_num > 0) { - irq_set_irq_type(irq_num, IRQ_TYPE_EDGE_BOTH); - err = request_irq(irq_num, pch_vbus_gpio_irq, 0, - "vbus_detect", dev); - if (!err) { - dev->vbus_gpio.intr = irq_num; - INIT_WORK(&dev->vbus_gpio.irq_work_rise, - pch_vbus_gpio_work_rise); - } else { - pr_err("%s: can't request irq %d, err: %d\n", - __func__, irq_num, err); - } - } - - return 0; -} - -/** - * pch_vbus_gpio_free() - This API frees resources of GPIO port - * @dev: Reference to the driver structure - */ -static void pch_vbus_gpio_free(struct pch_udc_dev *dev) -{ - if (dev->vbus_gpio.intr) - free_irq(dev->vbus_gpio.intr, dev); - - if (dev->vbus_gpio.port) - gpio_free(dev->vbus_gpio.port); -} - -/** - * complete_req() - This API is invoked from the driver when processing - * of a request is complete - * @ep: Reference to the endpoint structure - * @req: Reference to the request structure - * @status: Indicates the success/failure of completion - */ -static void complete_req(struct pch_udc_ep *ep, struct pch_udc_request *req, - int status) -{ - struct pch_udc_dev *dev; - unsigned halted = ep->halted; - - list_del_init(&req->queue); - - /* set new status if pending */ - if (req->req.status == -EINPROGRESS) - req->req.status = status; - else - status = req->req.status; - - dev = ep->dev; - if (req->dma_mapped) { - if (req->dma == DMA_ADDR_INVALID) { - if (ep->in) - dma_unmap_single(&dev->pdev->dev, req->req.dma, - req->req.length, - DMA_TO_DEVICE); - else - dma_unmap_single(&dev->pdev->dev, req->req.dma, - req->req.length, - DMA_FROM_DEVICE); - req->req.dma = DMA_ADDR_INVALID; - } else { - if (ep->in) - dma_unmap_single(&dev->pdev->dev, req->dma, - req->req.length, - DMA_TO_DEVICE); - else { - dma_unmap_single(&dev->pdev->dev, req->dma, - req->req.length, - DMA_FROM_DEVICE); - memcpy(req->req.buf, req->buf, req->req.length); - } - kfree(req->buf); - req->dma = DMA_ADDR_INVALID; - } - req->dma_mapped = 0; - } - ep->halted = 1; - spin_unlock(&dev->lock); - if (!ep->in) - pch_udc_ep_clear_rrdy(ep); - req->req.complete(&ep->ep, &req->req); - spin_lock(&dev->lock); - ep->halted = halted; -} - -/** - * empty_req_queue() - This API empties the request queue of an endpoint - * @ep: Reference to the endpoint structure - */ -static void empty_req_queue(struct pch_udc_ep *ep) -{ - struct pch_udc_request *req; - - ep->halted = 1; - while (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, struct pch_udc_request, queue); - complete_req(ep, req, -ESHUTDOWN); /* Remove from list */ - } -} - -/** - * pch_udc_free_dma_chain() - This function frees the DMA chain created - * for the request - * @dev Reference to the driver structure - * @req Reference to the request to be freed - * - * Return codes: - * 0: Success - */ -static void pch_udc_free_dma_chain(struct pch_udc_dev *dev, - struct pch_udc_request *req) -{ - struct pch_udc_data_dma_desc *td = req->td_data; - unsigned i = req->chain_len; - - dma_addr_t addr2; - dma_addr_t addr = (dma_addr_t)td->next; - td->next = 0x00; - for (; i > 1; --i) { - /* do not free first desc., will be done by free for request */ - td = phys_to_virt(addr); - addr2 = (dma_addr_t)td->next; - pci_pool_free(dev->data_requests, td, addr); - td->next = 0x00; - addr = addr2; - } - req->chain_len = 1; -} - -/** - * pch_udc_create_dma_chain() - This function creates or reinitializes - * a DMA chain - * @ep: Reference to the endpoint structure - * @req: Reference to the request - * @buf_len: The buffer length - * @gfp_flags: Flags to be used while mapping the data buffer - * - * Return codes: - * 0: success, - * -ENOMEM: pci_pool_alloc invocation fails - */ -static int pch_udc_create_dma_chain(struct pch_udc_ep *ep, - struct pch_udc_request *req, - unsigned long buf_len, - gfp_t gfp_flags) -{ - struct pch_udc_data_dma_desc *td = req->td_data, *last; - unsigned long bytes = req->req.length, i = 0; - dma_addr_t dma_addr; - unsigned len = 1; - - if (req->chain_len > 1) - pch_udc_free_dma_chain(ep->dev, req); - - if (req->dma == DMA_ADDR_INVALID) - td->dataptr = req->req.dma; - else - td->dataptr = req->dma; - - td->status = PCH_UDC_BS_HST_BSY; - for (; ; bytes -= buf_len, ++len) { - td->status = PCH_UDC_BS_HST_BSY | min(buf_len, bytes); - if (bytes <= buf_len) - break; - last = td; - td = pci_pool_alloc(ep->dev->data_requests, gfp_flags, - &dma_addr); - if (!td) - goto nomem; - i += buf_len; - td->dataptr = req->td_data->dataptr + i; - last->next = dma_addr; - } - - req->td_data_last = td; - td->status |= PCH_UDC_DMA_LAST; - td->next = req->td_data_phys; - req->chain_len = len; - return 0; - -nomem: - if (len > 1) { - req->chain_len = len; - pch_udc_free_dma_chain(ep->dev, req); - } - req->chain_len = 1; - return -ENOMEM; -} - -/** - * prepare_dma() - This function creates and initializes the DMA chain - * for the request - * @ep: Reference to the endpoint structure - * @req: Reference to the request - * @gfp: Flag to be used while mapping the data buffer - * - * Return codes: - * 0: Success - * Other 0: linux error number on failure - */ -static int prepare_dma(struct pch_udc_ep *ep, struct pch_udc_request *req, - gfp_t gfp) -{ - int retval; - - /* Allocate and create a DMA chain */ - retval = pch_udc_create_dma_chain(ep, req, ep->ep.maxpacket, gfp); - if (retval) { - pr_err("%s: could not create DMA chain:%d\n", __func__, retval); - return retval; - } - if (ep->in) - req->td_data->status = (req->td_data->status & - ~PCH_UDC_BUFF_STS) | PCH_UDC_BS_HST_RDY; - return 0; -} - -/** - * process_zlp() - This function process zero length packets - * from the gadget driver - * @ep: Reference to the endpoint structure - * @req: Reference to the request - */ -static void process_zlp(struct pch_udc_ep *ep, struct pch_udc_request *req) -{ - struct pch_udc_dev *dev = ep->dev; - - /* IN zlp's are handled by hardware */ - complete_req(ep, req, 0); - - /* if set_config or set_intf is waiting for ack by zlp - * then set CSR_DONE - */ - if (dev->set_cfg_not_acked) { - pch_udc_set_csr_done(dev); - dev->set_cfg_not_acked = 0; - } - /* setup command is ACK'ed now by zlp */ - if (!dev->stall && dev->waiting_zlp_ack) { - pch_udc_ep_clear_nak(&(dev->ep[UDC_EP0IN_IDX])); - dev->waiting_zlp_ack = 0; - } -} - -/** - * pch_udc_start_rxrequest() - This function starts the receive requirement. - * @ep: Reference to the endpoint structure - * @req: Reference to the request structure - */ -static void pch_udc_start_rxrequest(struct pch_udc_ep *ep, - struct pch_udc_request *req) -{ - struct pch_udc_data_dma_desc *td_data; - - pch_udc_clear_dma(ep->dev, DMA_DIR_RX); - td_data = req->td_data; - /* Set the status bits for all descriptors */ - while (1) { - td_data->status = (td_data->status & ~PCH_UDC_BUFF_STS) | - PCH_UDC_BS_HST_RDY; - if ((td_data->status & PCH_UDC_DMA_LAST) == PCH_UDC_DMA_LAST) - break; - td_data = phys_to_virt(td_data->next); - } - /* Write the descriptor pointer */ - pch_udc_ep_set_ddptr(ep, req->td_data_phys); - req->dma_going = 1; - pch_udc_enable_ep_interrupts(ep->dev, UDC_EPINT_OUT_EP0 << ep->num); - pch_udc_set_dma(ep->dev, DMA_DIR_RX); - pch_udc_ep_clear_nak(ep); - pch_udc_ep_set_rrdy(ep); -} - -/** - * pch_udc_pcd_ep_enable() - This API enables the endpoint. It is called - * from gadget driver - * @usbep: Reference to the USB endpoint structure - * @desc: Reference to the USB endpoint descriptor structure - * - * Return codes: - * 0: Success - * -EINVAL: - * -ESHUTDOWN: - */ -static int pch_udc_pcd_ep_enable(struct usb_ep *usbep, - const struct usb_endpoint_descriptor *desc) -{ - struct pch_udc_ep *ep; - struct pch_udc_dev *dev; - unsigned long iflags; - - if (!usbep || (usbep->name == ep0_string) || !desc || - (desc->bDescriptorType != USB_DT_ENDPOINT) || !desc->wMaxPacketSize) - return -EINVAL; - - ep = container_of(usbep, struct pch_udc_ep, ep); - dev = ep->dev; - if (!dev->driver || (dev->gadget.speed == USB_SPEED_UNKNOWN)) - return -ESHUTDOWN; - spin_lock_irqsave(&dev->lock, iflags); - ep->desc = desc; - ep->halted = 0; - pch_udc_ep_enable(ep, &ep->dev->cfg_data, desc); - ep->ep.maxpacket = usb_endpoint_maxp(desc); - pch_udc_enable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num)); - spin_unlock_irqrestore(&dev->lock, iflags); - return 0; -} - -/** - * pch_udc_pcd_ep_disable() - This API disables endpoint and is called - * from gadget driver - * @usbep Reference to the USB endpoint structure - * - * Return codes: - * 0: Success - * -EINVAL: - */ -static int pch_udc_pcd_ep_disable(struct usb_ep *usbep) -{ - struct pch_udc_ep *ep; - struct pch_udc_dev *dev; - unsigned long iflags; - - if (!usbep) - return -EINVAL; - - ep = container_of(usbep, struct pch_udc_ep, ep); - dev = ep->dev; - if ((usbep->name == ep0_string) || !ep->desc) - return -EINVAL; - - spin_lock_irqsave(&ep->dev->lock, iflags); - empty_req_queue(ep); - ep->halted = 1; - pch_udc_ep_disable(ep); - pch_udc_disable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num)); - ep->desc = NULL; - ep->ep.desc = NULL; - INIT_LIST_HEAD(&ep->queue); - spin_unlock_irqrestore(&ep->dev->lock, iflags); - return 0; -} - -/** - * pch_udc_alloc_request() - This function allocates request structure. - * It is called by gadget driver - * @usbep: Reference to the USB endpoint structure - * @gfp: Flag to be used while allocating memory - * - * Return codes: - * NULL: Failure - * Allocated address: Success - */ -static struct usb_request *pch_udc_alloc_request(struct usb_ep *usbep, - gfp_t gfp) -{ - struct pch_udc_request *req; - struct pch_udc_ep *ep; - struct pch_udc_data_dma_desc *dma_desc; - struct pch_udc_dev *dev; - - if (!usbep) - return NULL; - ep = container_of(usbep, struct pch_udc_ep, ep); - dev = ep->dev; - req = kzalloc(sizeof *req, gfp); - if (!req) - return NULL; - req->req.dma = DMA_ADDR_INVALID; - req->dma = DMA_ADDR_INVALID; - INIT_LIST_HEAD(&req->queue); - if (!ep->dev->dma_addr) - return &req->req; - /* ep0 in requests are allocated from data pool here */ - dma_desc = pci_pool_alloc(ep->dev->data_requests, gfp, - &req->td_data_phys); - if (NULL == dma_desc) { - kfree(req); - return NULL; - } - /* prevent from using desc. - set HOST BUSY */ - dma_desc->status |= PCH_UDC_BS_HST_BSY; - dma_desc->dataptr = __constant_cpu_to_le32(DMA_ADDR_INVALID); - req->td_data = dma_desc; - req->td_data_last = dma_desc; - req->chain_len = 1; - return &req->req; -} - -/** - * pch_udc_free_request() - This function frees request structure. - * It is called by gadget driver - * @usbep: Reference to the USB endpoint structure - * @usbreq: Reference to the USB request - */ -static void pch_udc_free_request(struct usb_ep *usbep, - struct usb_request *usbreq) -{ - struct pch_udc_ep *ep; - struct pch_udc_request *req; - struct pch_udc_dev *dev; - - if (!usbep || !usbreq) - return; - ep = container_of(usbep, struct pch_udc_ep, ep); - req = container_of(usbreq, struct pch_udc_request, req); - dev = ep->dev; - if (!list_empty(&req->queue)) - dev_err(&dev->pdev->dev, "%s: %s req=0x%p queue not empty\n", - __func__, usbep->name, req); - if (req->td_data != NULL) { - if (req->chain_len > 1) - pch_udc_free_dma_chain(ep->dev, req); - pci_pool_free(ep->dev->data_requests, req->td_data, - req->td_data_phys); - } - kfree(req); -} - -/** - * pch_udc_pcd_queue() - This function queues a request packet. It is called - * by gadget driver - * @usbep: Reference to the USB endpoint structure - * @usbreq: Reference to the USB request - * @gfp: Flag to be used while mapping the data buffer - * - * Return codes: - * 0: Success - * linux error number: Failure - */ -static int pch_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq, - gfp_t gfp) -{ - int retval = 0; - struct pch_udc_ep *ep; - struct pch_udc_dev *dev; - struct pch_udc_request *req; - unsigned long iflags; - - if (!usbep || !usbreq || !usbreq->complete || !usbreq->buf) - return -EINVAL; - ep = container_of(usbep, struct pch_udc_ep, ep); - dev = ep->dev; - if (!ep->desc && ep->num) - return -EINVAL; - req = container_of(usbreq, struct pch_udc_request, req); - if (!list_empty(&req->queue)) - return -EINVAL; - if (!dev->driver || (dev->gadget.speed == USB_SPEED_UNKNOWN)) - return -ESHUTDOWN; - spin_lock_irqsave(&dev->lock, iflags); - /* map the buffer for dma */ - if (usbreq->length && - ((usbreq->dma == DMA_ADDR_INVALID) || !usbreq->dma)) { - if (!((unsigned long)(usbreq->buf) & 0x03)) { - if (ep->in) - usbreq->dma = dma_map_single(&dev->pdev->dev, - usbreq->buf, - usbreq->length, - DMA_TO_DEVICE); - else - usbreq->dma = dma_map_single(&dev->pdev->dev, - usbreq->buf, - usbreq->length, - DMA_FROM_DEVICE); - } else { - req->buf = kzalloc(usbreq->length, GFP_ATOMIC); - if (!req->buf) { - retval = -ENOMEM; - goto probe_end; - } - if (ep->in) { - memcpy(req->buf, usbreq->buf, usbreq->length); - req->dma = dma_map_single(&dev->pdev->dev, - req->buf, - usbreq->length, - DMA_TO_DEVICE); - } else - req->dma = dma_map_single(&dev->pdev->dev, - req->buf, - usbreq->length, - DMA_FROM_DEVICE); - } - req->dma_mapped = 1; - } - if (usbreq->length > 0) { - retval = prepare_dma(ep, req, GFP_ATOMIC); - if (retval) - goto probe_end; - } - usbreq->actual = 0; - usbreq->status = -EINPROGRESS; - req->dma_done = 0; - if (list_empty(&ep->queue) && !ep->halted) { - /* no pending transfer, so start this req */ - if (!usbreq->length) { - process_zlp(ep, req); - retval = 0; - goto probe_end; - } - if (!ep->in) { - pch_udc_start_rxrequest(ep, req); - } else { - /* - * For IN trfr the descriptors will be programmed and - * P bit will be set when - * we get an IN token - */ - pch_udc_wait_ep_stall(ep); - pch_udc_ep_clear_nak(ep); - pch_udc_enable_ep_interrupts(ep->dev, (1 << ep->num)); - } - } - /* Now add this request to the ep's pending requests */ - if (req != NULL) - list_add_tail(&req->queue, &ep->queue); - -probe_end: - spin_unlock_irqrestore(&dev->lock, iflags); - return retval; -} - -/** - * pch_udc_pcd_dequeue() - This function de-queues a request packet. - * It is called by gadget driver - * @usbep: Reference to the USB endpoint structure - * @usbreq: Reference to the USB request - * - * Return codes: - * 0: Success - * linux error number: Failure - */ -static int pch_udc_pcd_dequeue(struct usb_ep *usbep, - struct usb_request *usbreq) -{ - struct pch_udc_ep *ep; - struct pch_udc_request *req; - struct pch_udc_dev *dev; - unsigned long flags; - int ret = -EINVAL; - - ep = container_of(usbep, struct pch_udc_ep, ep); - dev = ep->dev; - if (!usbep || !usbreq || (!ep->desc && ep->num)) - return ret; - req = container_of(usbreq, struct pch_udc_request, req); - spin_lock_irqsave(&ep->dev->lock, flags); - /* make sure it's still queued on this endpoint */ - list_for_each_entry(req, &ep->queue, queue) { - if (&req->req == usbreq) { - pch_udc_ep_set_nak(ep); - if (!list_empty(&req->queue)) - complete_req(ep, req, -ECONNRESET); - ret = 0; - break; - } - } - spin_unlock_irqrestore(&ep->dev->lock, flags); - return ret; -} - -/** - * pch_udc_pcd_set_halt() - This function Sets or clear the endpoint halt - * feature - * @usbep: Reference to the USB endpoint structure - * @halt: Specifies whether to set or clear the feature - * - * Return codes: - * 0: Success - * linux error number: Failure - */ -static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt) -{ - struct pch_udc_ep *ep; - struct pch_udc_dev *dev; - unsigned long iflags; - int ret; - - if (!usbep) - return -EINVAL; - ep = container_of(usbep, struct pch_udc_ep, ep); - dev = ep->dev; - if (!ep->desc && !ep->num) - return -EINVAL; - if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN)) - return -ESHUTDOWN; - spin_lock_irqsave(&udc_stall_spinlock, iflags); - if (list_empty(&ep->queue)) { - if (halt) { - if (ep->num == PCH_UDC_EP0) - ep->dev->stall = 1; - pch_udc_ep_set_stall(ep); - pch_udc_enable_ep_interrupts(ep->dev, - PCH_UDC_EPINT(ep->in, - ep->num)); - } else { - pch_udc_ep_clear_stall(ep); - } - ret = 0; - } else { - ret = -EAGAIN; - } - spin_unlock_irqrestore(&udc_stall_spinlock, iflags); - return ret; -} - -/** - * pch_udc_pcd_set_wedge() - This function Sets or clear the endpoint - * halt feature - * @usbep: Reference to the USB endpoint structure - * @halt: Specifies whether to set or clear the feature - * - * Return codes: - * 0: Success - * linux error number: Failure - */ -static int pch_udc_pcd_set_wedge(struct usb_ep *usbep) -{ - struct pch_udc_ep *ep; - struct pch_udc_dev *dev; - unsigned long iflags; - int ret; - - if (!usbep) - return -EINVAL; - ep = container_of(usbep, struct pch_udc_ep, ep); - dev = ep->dev; - if (!ep->desc && !ep->num) - return -EINVAL; - if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN)) - return -ESHUTDOWN; - spin_lock_irqsave(&udc_stall_spinlock, iflags); - if (!list_empty(&ep->queue)) { - ret = -EAGAIN; - } else { - if (ep->num == PCH_UDC_EP0) - ep->dev->stall = 1; - pch_udc_ep_set_stall(ep); - pch_udc_enable_ep_interrupts(ep->dev, - PCH_UDC_EPINT(ep->in, ep->num)); - ep->dev->prot_stall = 1; - ret = 0; - } - spin_unlock_irqrestore(&udc_stall_spinlock, iflags); - return ret; -} - -/** - * pch_udc_pcd_fifo_flush() - This function Flush the FIFO of specified endpoint - * @usbep: Reference to the USB endpoint structure - */ -static void pch_udc_pcd_fifo_flush(struct usb_ep *usbep) -{ - struct pch_udc_ep *ep; - - if (!usbep) - return; - - ep = container_of(usbep, struct pch_udc_ep, ep); - if (ep->desc || !ep->num) - pch_udc_ep_fifo_flush(ep, ep->in); -} - -static const struct usb_ep_ops pch_udc_ep_ops = { - .enable = pch_udc_pcd_ep_enable, - .disable = pch_udc_pcd_ep_disable, - .alloc_request = pch_udc_alloc_request, - .free_request = pch_udc_free_request, - .queue = pch_udc_pcd_queue, - .dequeue = pch_udc_pcd_dequeue, - .set_halt = pch_udc_pcd_set_halt, - .set_wedge = pch_udc_pcd_set_wedge, - .fifo_status = NULL, - .fifo_flush = pch_udc_pcd_fifo_flush, -}; - -/** - * pch_udc_init_setup_buff() - This function initializes the SETUP buffer - * @td_stp: Reference to the SETP buffer structure - */ -static void pch_udc_init_setup_buff(struct pch_udc_stp_dma_desc *td_stp) -{ - static u32 pky_marker; - - if (!td_stp) - return; - td_stp->reserved = ++pky_marker; - memset(&td_stp->request, 0xFF, sizeof td_stp->request); - td_stp->status = PCH_UDC_BS_HST_RDY; -} - -/** - * pch_udc_start_next_txrequest() - This function starts - * the next transmission requirement - * @ep: Reference to the endpoint structure - */ -static void pch_udc_start_next_txrequest(struct pch_udc_ep *ep) -{ - struct pch_udc_request *req; - struct pch_udc_data_dma_desc *td_data; - - if (pch_udc_read_ep_control(ep) & UDC_EPCTL_P) - return; - - if (list_empty(&ep->queue)) - return; - - /* next request */ - req = list_entry(ep->queue.next, struct pch_udc_request, queue); - if (req->dma_going) - return; - if (!req->td_data) - return; - pch_udc_wait_ep_stall(ep); - req->dma_going = 1; - pch_udc_ep_set_ddptr(ep, 0); - td_data = req->td_data; - while (1) { - td_data->status = (td_data->status & ~PCH_UDC_BUFF_STS) | - PCH_UDC_BS_HST_RDY; - if ((td_data->status & PCH_UDC_DMA_LAST) == PCH_UDC_DMA_LAST) - break; - td_data = phys_to_virt(td_data->next); - } - pch_udc_ep_set_ddptr(ep, req->td_data_phys); - pch_udc_set_dma(ep->dev, DMA_DIR_TX); - pch_udc_ep_set_pd(ep); - pch_udc_enable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num)); - pch_udc_ep_clear_nak(ep); -} - -/** - * pch_udc_complete_transfer() - This function completes a transfer - * @ep: Reference to the endpoint structure - */ -static void pch_udc_complete_transfer(struct pch_udc_ep *ep) -{ - struct pch_udc_request *req; - struct pch_udc_dev *dev = ep->dev; - - if (list_empty(&ep->queue)) - return; - req = list_entry(ep->queue.next, struct pch_udc_request, queue); - if ((req->td_data_last->status & PCH_UDC_BUFF_STS) != - PCH_UDC_BS_DMA_DONE) - return; - if ((req->td_data_last->status & PCH_UDC_RXTX_STS) != - PCH_UDC_RTS_SUCC) { - dev_err(&dev->pdev->dev, "Invalid RXTX status (0x%08x) " - "epstatus=0x%08x\n", - (req->td_data_last->status & PCH_UDC_RXTX_STS), - (int)(ep->epsts)); - return; - } - - req->req.actual = req->req.length; - req->td_data_last->status = PCH_UDC_BS_HST_BSY | PCH_UDC_DMA_LAST; - req->td_data->status = PCH_UDC_BS_HST_BSY | PCH_UDC_DMA_LAST; - complete_req(ep, req, 0); - req->dma_going = 0; - if (!list_empty(&ep->queue)) { - pch_udc_wait_ep_stall(ep); - pch_udc_ep_clear_nak(ep); - pch_udc_enable_ep_interrupts(ep->dev, - PCH_UDC_EPINT(ep->in, ep->num)); - } else { - pch_udc_disable_ep_interrupts(ep->dev, - PCH_UDC_EPINT(ep->in, ep->num)); - } -} - -/** - * pch_udc_complete_receiver() - This function completes a receiver - * @ep: Reference to the endpoint structure - */ -static void pch_udc_complete_receiver(struct pch_udc_ep *ep) -{ - struct pch_udc_request *req; - struct pch_udc_dev *dev = ep->dev; - unsigned int count; - struct pch_udc_data_dma_desc *td; - dma_addr_t addr; - - if (list_empty(&ep->queue)) - return; - /* next request */ - req = list_entry(ep->queue.next, struct pch_udc_request, queue); - pch_udc_clear_dma(ep->dev, DMA_DIR_RX); - pch_udc_ep_set_ddptr(ep, 0); - if ((req->td_data_last->status & PCH_UDC_BUFF_STS) == - PCH_UDC_BS_DMA_DONE) - td = req->td_data_last; - else - td = req->td_data; - - while (1) { - if ((td->status & PCH_UDC_RXTX_STS) != PCH_UDC_RTS_SUCC) { - dev_err(&dev->pdev->dev, "Invalid RXTX status=0x%08x " - "epstatus=0x%08x\n", - (req->td_data->status & PCH_UDC_RXTX_STS), - (int)(ep->epsts)); - return; - } - if ((td->status & PCH_UDC_BUFF_STS) == PCH_UDC_BS_DMA_DONE) - if (td->status | PCH_UDC_DMA_LAST) { - count = td->status & PCH_UDC_RXTX_BYTES; - break; - } - if (td == req->td_data_last) { - dev_err(&dev->pdev->dev, "Not complete RX descriptor"); - return; - } - addr = (dma_addr_t)td->next; - td = phys_to_virt(addr); - } - /* on 64k packets the RXBYTES field is zero */ - if (!count && (req->req.length == UDC_DMA_MAXPACKET)) - count = UDC_DMA_MAXPACKET; - req->td_data->status |= PCH_UDC_DMA_LAST; - td->status |= PCH_UDC_BS_HST_BSY; - - req->dma_going = 0; - req->req.actual = count; - complete_req(ep, req, 0); - /* If there is a new/failed requests try that now */ - if (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, struct pch_udc_request, queue); - pch_udc_start_rxrequest(ep, req); - } -} - -/** - * pch_udc_svc_data_in() - This function process endpoint interrupts - * for IN endpoints - * @dev: Reference to the device structure - * @ep_num: Endpoint that generated the interrupt - */ -static void pch_udc_svc_data_in(struct pch_udc_dev *dev, int ep_num) -{ - u32 epsts; - struct pch_udc_ep *ep; - - ep = &dev->ep[UDC_EPIN_IDX(ep_num)]; - epsts = ep->epsts; - ep->epsts = 0; - - if (!(epsts & (UDC_EPSTS_IN | UDC_EPSTS_BNA | UDC_EPSTS_HE | - UDC_EPSTS_TDC | UDC_EPSTS_RCS | UDC_EPSTS_TXEMPTY | - UDC_EPSTS_RSS | UDC_EPSTS_XFERDONE))) - return; - if ((epsts & UDC_EPSTS_BNA)) - return; - if (epsts & UDC_EPSTS_HE) - return; - if (epsts & UDC_EPSTS_RSS) { - pch_udc_ep_set_stall(ep); - pch_udc_enable_ep_interrupts(ep->dev, - PCH_UDC_EPINT(ep->in, ep->num)); - } - if (epsts & UDC_EPSTS_RCS) { - if (!dev->prot_stall) { - pch_udc_ep_clear_stall(ep); - } else { - pch_udc_ep_set_stall(ep); - pch_udc_enable_ep_interrupts(ep->dev, - PCH_UDC_EPINT(ep->in, ep->num)); - } - } - if (epsts & UDC_EPSTS_TDC) - pch_udc_complete_transfer(ep); - /* On IN interrupt, provide data if we have any */ - if ((epsts & UDC_EPSTS_IN) && !(epsts & UDC_EPSTS_RSS) && - !(epsts & UDC_EPSTS_TDC) && !(epsts & UDC_EPSTS_TXEMPTY)) - pch_udc_start_next_txrequest(ep); -} - -/** - * pch_udc_svc_data_out() - Handles interrupts from OUT endpoint - * @dev: Reference to the device structure - * @ep_num: Endpoint that generated the interrupt - */ -static void pch_udc_svc_data_out(struct pch_udc_dev *dev, int ep_num) -{ - u32 epsts; - struct pch_udc_ep *ep; - struct pch_udc_request *req = NULL; - - ep = &dev->ep[UDC_EPOUT_IDX(ep_num)]; - epsts = ep->epsts; - ep->epsts = 0; - - if ((epsts & UDC_EPSTS_BNA) && (!list_empty(&ep->queue))) { - /* next request */ - req = list_entry(ep->queue.next, struct pch_udc_request, - queue); - if ((req->td_data_last->status & PCH_UDC_BUFF_STS) != - PCH_UDC_BS_DMA_DONE) { - if (!req->dma_going) - pch_udc_start_rxrequest(ep, req); - return; - } - } - if (epsts & UDC_EPSTS_HE) - return; - if (epsts & UDC_EPSTS_RSS) { - pch_udc_ep_set_stall(ep); - pch_udc_enable_ep_interrupts(ep->dev, - PCH_UDC_EPINT(ep->in, ep->num)); - } - if (epsts & UDC_EPSTS_RCS) { - if (!dev->prot_stall) { - pch_udc_ep_clear_stall(ep); - } else { - pch_udc_ep_set_stall(ep); - pch_udc_enable_ep_interrupts(ep->dev, - PCH_UDC_EPINT(ep->in, ep->num)); - } - } - if (((epsts & UDC_EPSTS_OUT_MASK) >> UDC_EPSTS_OUT_SHIFT) == - UDC_EPSTS_OUT_DATA) { - if (ep->dev->prot_stall == 1) { - pch_udc_ep_set_stall(ep); - pch_udc_enable_ep_interrupts(ep->dev, - PCH_UDC_EPINT(ep->in, ep->num)); - } else { - pch_udc_complete_receiver(ep); - } - } - if (list_empty(&ep->queue)) - pch_udc_set_dma(dev, DMA_DIR_RX); -} - -/** - * pch_udc_svc_control_in() - Handle Control IN endpoint interrupts - * @dev: Reference to the device structure - */ -static void pch_udc_svc_control_in(struct pch_udc_dev *dev) -{ - u32 epsts; - struct pch_udc_ep *ep; - struct pch_udc_ep *ep_out; - - ep = &dev->ep[UDC_EP0IN_IDX]; - ep_out = &dev->ep[UDC_EP0OUT_IDX]; - epsts = ep->epsts; - ep->epsts = 0; - - if (!(epsts & (UDC_EPSTS_IN | UDC_EPSTS_BNA | UDC_EPSTS_HE | - UDC_EPSTS_TDC | UDC_EPSTS_RCS | UDC_EPSTS_TXEMPTY | - UDC_EPSTS_XFERDONE))) - return; - if ((epsts & UDC_EPSTS_BNA)) - return; - if (epsts & UDC_EPSTS_HE) - return; - if ((epsts & UDC_EPSTS_TDC) && (!dev->stall)) { - pch_udc_complete_transfer(ep); - pch_udc_clear_dma(dev, DMA_DIR_RX); - ep_out->td_data->status = (ep_out->td_data->status & - ~PCH_UDC_BUFF_STS) | - PCH_UDC_BS_HST_RDY; - pch_udc_ep_clear_nak(ep_out); - pch_udc_set_dma(dev, DMA_DIR_RX); - pch_udc_ep_set_rrdy(ep_out); - } - /* On IN interrupt, provide data if we have any */ - if ((epsts & UDC_EPSTS_IN) && !(epsts & UDC_EPSTS_TDC) && - !(epsts & UDC_EPSTS_TXEMPTY)) - pch_udc_start_next_txrequest(ep); -} - -/** - * pch_udc_svc_control_out() - Routine that handle Control - * OUT endpoint interrupts - * @dev: Reference to the device structure - */ -static void pch_udc_svc_control_out(struct pch_udc_dev *dev) -{ - u32 stat; - int setup_supported; - struct pch_udc_ep *ep; - - ep = &dev->ep[UDC_EP0OUT_IDX]; - stat = ep->epsts; - ep->epsts = 0; - - /* If setup data */ - if (((stat & UDC_EPSTS_OUT_MASK) >> UDC_EPSTS_OUT_SHIFT) == - UDC_EPSTS_OUT_SETUP) { - dev->stall = 0; - dev->ep[UDC_EP0IN_IDX].halted = 0; - dev->ep[UDC_EP0OUT_IDX].halted = 0; - dev->setup_data = ep->td_stp->request; - pch_udc_init_setup_buff(ep->td_stp); - pch_udc_clear_dma(dev, DMA_DIR_RX); - pch_udc_ep_fifo_flush(&(dev->ep[UDC_EP0IN_IDX]), - dev->ep[UDC_EP0IN_IDX].in); - if ((dev->setup_data.bRequestType & USB_DIR_IN)) - dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IDX].ep; - else /* OUT */ - dev->gadget.ep0 = &ep->ep; - spin_unlock(&dev->lock); - /* If Mass storage Reset */ - if ((dev->setup_data.bRequestType == 0x21) && - (dev->setup_data.bRequest == 0xFF)) - dev->prot_stall = 0; - /* call gadget with setup data received */ - setup_supported = dev->driver->setup(&dev->gadget, - &dev->setup_data); - spin_lock(&dev->lock); - - if (dev->setup_data.bRequestType & USB_DIR_IN) { - ep->td_data->status = (ep->td_data->status & - ~PCH_UDC_BUFF_STS) | - PCH_UDC_BS_HST_RDY; - pch_udc_ep_set_ddptr(ep, ep->td_data_phys); - } - /* ep0 in returns data on IN phase */ - if (setup_supported >= 0 && setup_supported < - UDC_EP0IN_MAX_PKT_SIZE) { - pch_udc_ep_clear_nak(&(dev->ep[UDC_EP0IN_IDX])); - /* Gadget would have queued a request when - * we called the setup */ - if (!(dev->setup_data.bRequestType & USB_DIR_IN)) { - pch_udc_set_dma(dev, DMA_DIR_RX); - pch_udc_ep_clear_nak(ep); - } - } else if (setup_supported < 0) { - /* if unsupported request, then stall */ - pch_udc_ep_set_stall(&(dev->ep[UDC_EP0IN_IDX])); - pch_udc_enable_ep_interrupts(ep->dev, - PCH_UDC_EPINT(ep->in, ep->num)); - dev->stall = 0; - pch_udc_set_dma(dev, DMA_DIR_RX); - } else { - dev->waiting_zlp_ack = 1; - } - } else if ((((stat & UDC_EPSTS_OUT_MASK) >> UDC_EPSTS_OUT_SHIFT) == - UDC_EPSTS_OUT_DATA) && !dev->stall) { - pch_udc_clear_dma(dev, DMA_DIR_RX); - pch_udc_ep_set_ddptr(ep, 0); - if (!list_empty(&ep->queue)) { - ep->epsts = stat; - pch_udc_svc_data_out(dev, PCH_UDC_EP0); - } - pch_udc_set_dma(dev, DMA_DIR_RX); - } - pch_udc_ep_set_rrdy(ep); -} - - -/** - * pch_udc_postsvc_epinters() - This function enables end point interrupts - * and clears NAK status - * @dev: Reference to the device structure - * @ep_num: End point number - */ -static void pch_udc_postsvc_epinters(struct pch_udc_dev *dev, int ep_num) -{ - struct pch_udc_ep *ep; - struct pch_udc_request *req; - - ep = &dev->ep[UDC_EPIN_IDX(ep_num)]; - if (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, struct pch_udc_request, queue); - pch_udc_enable_ep_interrupts(ep->dev, - PCH_UDC_EPINT(ep->in, ep->num)); - pch_udc_ep_clear_nak(ep); - } -} - -/** - * pch_udc_read_all_epstatus() - This function read all endpoint status - * @dev: Reference to the device structure - * @ep_intr: Status of endpoint interrupt - */ -static void pch_udc_read_all_epstatus(struct pch_udc_dev *dev, u32 ep_intr) -{ - int i; - struct pch_udc_ep *ep; - - for (i = 0; i < PCH_UDC_USED_EP_NUM; i++) { - /* IN */ - if (ep_intr & (0x1 << i)) { - ep = &dev->ep[UDC_EPIN_IDX(i)]; - ep->epsts = pch_udc_read_ep_status(ep); - pch_udc_clear_ep_status(ep, ep->epsts); - } - /* OUT */ - if (ep_intr & (0x10000 << i)) { - ep = &dev->ep[UDC_EPOUT_IDX(i)]; - ep->epsts = pch_udc_read_ep_status(ep); - pch_udc_clear_ep_status(ep, ep->epsts); - } - } -} - -/** - * pch_udc_activate_control_ep() - This function enables the control endpoints - * for traffic after a reset - * @dev: Reference to the device structure - */ -static void pch_udc_activate_control_ep(struct pch_udc_dev *dev) -{ - struct pch_udc_ep *ep; - u32 val; - - /* Setup the IN endpoint */ - ep = &dev->ep[UDC_EP0IN_IDX]; - pch_udc_clear_ep_control(ep); - pch_udc_ep_fifo_flush(ep, ep->in); - pch_udc_ep_set_bufsz(ep, UDC_EP0IN_BUFF_SIZE, ep->in); - pch_udc_ep_set_maxpkt(ep, UDC_EP0IN_MAX_PKT_SIZE); - /* Initialize the IN EP Descriptor */ - ep->td_data = NULL; - ep->td_stp = NULL; - ep->td_data_phys = 0; - ep->td_stp_phys = 0; - - /* Setup the OUT endpoint */ - ep = &dev->ep[UDC_EP0OUT_IDX]; - pch_udc_clear_ep_control(ep); - pch_udc_ep_fifo_flush(ep, ep->in); - pch_udc_ep_set_bufsz(ep, UDC_EP0OUT_BUFF_SIZE, ep->in); - pch_udc_ep_set_maxpkt(ep, UDC_EP0OUT_MAX_PKT_SIZE); - val = UDC_EP0OUT_MAX_PKT_SIZE << UDC_CSR_NE_MAX_PKT_SHIFT; - pch_udc_write_csr(ep->dev, val, UDC_EP0OUT_IDX); - - /* Initialize the SETUP buffer */ - pch_udc_init_setup_buff(ep->td_stp); - /* Write the pointer address of dma descriptor */ - pch_udc_ep_set_subptr(ep, ep->td_stp_phys); - /* Write the pointer address of Setup descriptor */ - pch_udc_ep_set_ddptr(ep, ep->td_data_phys); - - /* Initialize the dma descriptor */ - ep->td_data->status = PCH_UDC_DMA_LAST; - ep->td_data->dataptr = dev->dma_addr; - ep->td_data->next = ep->td_data_phys; - - pch_udc_ep_clear_nak(ep); -} - - -/** - * pch_udc_svc_ur_interrupt() - This function handles a USB reset interrupt - * @dev: Reference to driver structure - */ -static void pch_udc_svc_ur_interrupt(struct pch_udc_dev *dev) -{ - struct pch_udc_ep *ep; - int i; - - pch_udc_clear_dma(dev, DMA_DIR_TX); - pch_udc_clear_dma(dev, DMA_DIR_RX); - /* Mask all endpoint interrupts */ - pch_udc_disable_ep_interrupts(dev, UDC_EPINT_MSK_DISABLE_ALL); - /* clear all endpoint interrupts */ - pch_udc_write_ep_interrupts(dev, UDC_EPINT_MSK_DISABLE_ALL); - - for (i = 0; i < PCH_UDC_EP_NUM; i++) { - ep = &dev->ep[i]; - pch_udc_clear_ep_status(ep, UDC_EPSTS_ALL_CLR_MASK); - pch_udc_clear_ep_control(ep); - pch_udc_ep_set_ddptr(ep, 0); - pch_udc_write_csr(ep->dev, 0x00, i); - } - dev->stall = 0; - dev->prot_stall = 0; - dev->waiting_zlp_ack = 0; - dev->set_cfg_not_acked = 0; - - /* disable ep to empty req queue. Skip the control EP's */ - for (i = 0; i < (PCH_UDC_USED_EP_NUM*2); i++) { - ep = &dev->ep[i]; - pch_udc_ep_set_nak(ep); - pch_udc_ep_fifo_flush(ep, ep->in); - /* Complete request queue */ - empty_req_queue(ep); - } - if (dev->driver && dev->driver->disconnect) { - spin_unlock(&dev->lock); - dev->driver->disconnect(&dev->gadget); - spin_lock(&dev->lock); - } -} - -/** - * pch_udc_svc_enum_interrupt() - This function handles a USB speed enumeration - * done interrupt - * @dev: Reference to driver structure - */ -static void pch_udc_svc_enum_interrupt(struct pch_udc_dev *dev) -{ - u32 dev_stat, dev_speed; - u32 speed = USB_SPEED_FULL; - - dev_stat = pch_udc_read_device_status(dev); - dev_speed = (dev_stat & UDC_DEVSTS_ENUM_SPEED_MASK) >> - UDC_DEVSTS_ENUM_SPEED_SHIFT; - switch (dev_speed) { - case UDC_DEVSTS_ENUM_SPEED_HIGH: - speed = USB_SPEED_HIGH; - break; - case UDC_DEVSTS_ENUM_SPEED_FULL: - speed = USB_SPEED_FULL; - break; - case UDC_DEVSTS_ENUM_SPEED_LOW: - speed = USB_SPEED_LOW; - break; - default: - BUG(); - } - dev->gadget.speed = speed; - pch_udc_activate_control_ep(dev); - pch_udc_enable_ep_interrupts(dev, UDC_EPINT_IN_EP0 | UDC_EPINT_OUT_EP0); - pch_udc_set_dma(dev, DMA_DIR_TX); - pch_udc_set_dma(dev, DMA_DIR_RX); - pch_udc_ep_set_rrdy(&(dev->ep[UDC_EP0OUT_IDX])); - - /* enable device interrupts */ - pch_udc_enable_interrupts(dev, UDC_DEVINT_UR | UDC_DEVINT_US | - UDC_DEVINT_ES | UDC_DEVINT_ENUM | - UDC_DEVINT_SI | UDC_DEVINT_SC); -} - -/** - * pch_udc_svc_intf_interrupt() - This function handles a set interface - * interrupt - * @dev: Reference to driver structure - */ -static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev) -{ - u32 reg, dev_stat = 0; - int i, ret; - - dev_stat = pch_udc_read_device_status(dev); - dev->cfg_data.cur_intf = (dev_stat & UDC_DEVSTS_INTF_MASK) >> - UDC_DEVSTS_INTF_SHIFT; - dev->cfg_data.cur_alt = (dev_stat & UDC_DEVSTS_ALT_MASK) >> - UDC_DEVSTS_ALT_SHIFT; - dev->set_cfg_not_acked = 1; - /* Construct the usb request for gadget driver and inform it */ - memset(&dev->setup_data, 0 , sizeof dev->setup_data); - dev->setup_data.bRequest = USB_REQ_SET_INTERFACE; - dev->setup_data.bRequestType = USB_RECIP_INTERFACE; - dev->setup_data.wValue = cpu_to_le16(dev->cfg_data.cur_alt); - dev->setup_data.wIndex = cpu_to_le16(dev->cfg_data.cur_intf); - /* programm the Endpoint Cfg registers */ - /* Only one end point cfg register */ - reg = pch_udc_read_csr(dev, UDC_EP0OUT_IDX); - reg = (reg & ~UDC_CSR_NE_INTF_MASK) | - (dev->cfg_data.cur_intf << UDC_CSR_NE_INTF_SHIFT); - reg = (reg & ~UDC_CSR_NE_ALT_MASK) | - (dev->cfg_data.cur_alt << UDC_CSR_NE_ALT_SHIFT); - pch_udc_write_csr(dev, reg, UDC_EP0OUT_IDX); - for (i = 0; i < PCH_UDC_USED_EP_NUM * 2; i++) { - /* clear stall bits */ - pch_udc_ep_clear_stall(&(dev->ep[i])); - dev->ep[i].halted = 0; - } - dev->stall = 0; - spin_unlock(&dev->lock); - ret = dev->driver->setup(&dev->gadget, &dev->setup_data); - spin_lock(&dev->lock); -} - -/** - * pch_udc_svc_cfg_interrupt() - This function handles a set configuration - * interrupt - * @dev: Reference to driver structure - */ -static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev) -{ - int i, ret; - u32 reg, dev_stat = 0; - - dev_stat = pch_udc_read_device_status(dev); - dev->set_cfg_not_acked = 1; - dev->cfg_data.cur_cfg = (dev_stat & UDC_DEVSTS_CFG_MASK) >> - UDC_DEVSTS_CFG_SHIFT; - /* make usb request for gadget driver */ - memset(&dev->setup_data, 0 , sizeof dev->setup_data); - dev->setup_data.bRequest = USB_REQ_SET_CONFIGURATION; - dev->setup_data.wValue = cpu_to_le16(dev->cfg_data.cur_cfg); - /* program the NE registers */ - /* Only one end point cfg register */ - reg = pch_udc_read_csr(dev, UDC_EP0OUT_IDX); - reg = (reg & ~UDC_CSR_NE_CFG_MASK) | - (dev->cfg_data.cur_cfg << UDC_CSR_NE_CFG_SHIFT); - pch_udc_write_csr(dev, reg, UDC_EP0OUT_IDX); - for (i = 0; i < PCH_UDC_USED_EP_NUM * 2; i++) { - /* clear stall bits */ - pch_udc_ep_clear_stall(&(dev->ep[i])); - dev->ep[i].halted = 0; - } - dev->stall = 0; - - /* call gadget zero with setup data received */ - spin_unlock(&dev->lock); - ret = dev->driver->setup(&dev->gadget, &dev->setup_data); - spin_lock(&dev->lock); -} - -/** - * pch_udc_dev_isr() - This function services device interrupts - * by invoking appropriate routines. - * @dev: Reference to the device structure - * @dev_intr: The Device interrupt status. - */ -static void pch_udc_dev_isr(struct pch_udc_dev *dev, u32 dev_intr) -{ - int vbus; - - /* USB Reset Interrupt */ - if (dev_intr & UDC_DEVINT_UR) { - pch_udc_svc_ur_interrupt(dev); - dev_dbg(&dev->pdev->dev, "USB_RESET\n"); - } - /* Enumeration Done Interrupt */ - if (dev_intr & UDC_DEVINT_ENUM) { - pch_udc_svc_enum_interrupt(dev); - dev_dbg(&dev->pdev->dev, "USB_ENUM\n"); - } - /* Set Interface Interrupt */ - if (dev_intr & UDC_DEVINT_SI) - pch_udc_svc_intf_interrupt(dev); - /* Set Config Interrupt */ - if (dev_intr & UDC_DEVINT_SC) - pch_udc_svc_cfg_interrupt(dev); - /* USB Suspend interrupt */ - if (dev_intr & UDC_DEVINT_US) { - if (dev->driver - && dev->driver->suspend) { - spin_unlock(&dev->lock); - dev->driver->suspend(&dev->gadget); - spin_lock(&dev->lock); - } - - vbus = pch_vbus_gpio_get_value(dev); - if ((dev->vbus_session == 0) - && (vbus != 1)) { - if (dev->driver && dev->driver->disconnect) { - spin_unlock(&dev->lock); - dev->driver->disconnect(&dev->gadget); - spin_lock(&dev->lock); - } - pch_udc_reconnect(dev); - } else if ((dev->vbus_session == 0) - && (vbus == 1) - && !dev->vbus_gpio.intr) - schedule_work(&dev->vbus_gpio.irq_work_fall); - - dev_dbg(&dev->pdev->dev, "USB_SUSPEND\n"); - } - /* Clear the SOF interrupt, if enabled */ - if (dev_intr & UDC_DEVINT_SOF) - dev_dbg(&dev->pdev->dev, "SOF\n"); - /* ES interrupt, IDLE > 3ms on the USB */ - if (dev_intr & UDC_DEVINT_ES) - dev_dbg(&dev->pdev->dev, "ES\n"); - /* RWKP interrupt */ - if (dev_intr & UDC_DEVINT_RWKP) - dev_dbg(&dev->pdev->dev, "RWKP\n"); -} - -/** - * pch_udc_isr() - This function handles interrupts from the PCH USB Device - * @irq: Interrupt request number - * @dev: Reference to the device structure - */ -static irqreturn_t pch_udc_isr(int irq, void *pdev) -{ - struct pch_udc_dev *dev = (struct pch_udc_dev *) pdev; - u32 dev_intr, ep_intr; - int i; - - dev_intr = pch_udc_read_device_interrupts(dev); - ep_intr = pch_udc_read_ep_interrupts(dev); - - /* For a hot plug, this find that the controller is hung up. */ - if (dev_intr == ep_intr) - if (dev_intr == pch_udc_readl(dev, UDC_DEVCFG_ADDR)) { - dev_dbg(&dev->pdev->dev, "UDC: Hung up\n"); - /* The controller is reset */ - pch_udc_writel(dev, UDC_SRST, UDC_SRST_ADDR); - return IRQ_HANDLED; - } - if (dev_intr) - /* Clear device interrupts */ - pch_udc_write_device_interrupts(dev, dev_intr); - if (ep_intr) - /* Clear ep interrupts */ - pch_udc_write_ep_interrupts(dev, ep_intr); - if (!dev_intr && !ep_intr) - return IRQ_NONE; - spin_lock(&dev->lock); - if (dev_intr) - pch_udc_dev_isr(dev, dev_intr); - if (ep_intr) { - pch_udc_read_all_epstatus(dev, ep_intr); - /* Process Control In interrupts, if present */ - if (ep_intr & UDC_EPINT_IN_EP0) { - pch_udc_svc_control_in(dev); - pch_udc_postsvc_epinters(dev, 0); - } - /* Process Control Out interrupts, if present */ - if (ep_intr & UDC_EPINT_OUT_EP0) - pch_udc_svc_control_out(dev); - /* Process data in end point interrupts */ - for (i = 1; i < PCH_UDC_USED_EP_NUM; i++) { - if (ep_intr & (1 << i)) { - pch_udc_svc_data_in(dev, i); - pch_udc_postsvc_epinters(dev, i); - } - } - /* Process data out end point interrupts */ - for (i = UDC_EPINT_OUT_SHIFT + 1; i < (UDC_EPINT_OUT_SHIFT + - PCH_UDC_USED_EP_NUM); i++) - if (ep_intr & (1 << i)) - pch_udc_svc_data_out(dev, i - - UDC_EPINT_OUT_SHIFT); - } - spin_unlock(&dev->lock); - return IRQ_HANDLED; -} - -/** - * pch_udc_setup_ep0() - This function enables control endpoint for traffic - * @dev: Reference to the device structure - */ -static void pch_udc_setup_ep0(struct pch_udc_dev *dev) -{ - /* enable ep0 interrupts */ - pch_udc_enable_ep_interrupts(dev, UDC_EPINT_IN_EP0 | - UDC_EPINT_OUT_EP0); - /* enable device interrupts */ - pch_udc_enable_interrupts(dev, UDC_DEVINT_UR | UDC_DEVINT_US | - UDC_DEVINT_ES | UDC_DEVINT_ENUM | - UDC_DEVINT_SI | UDC_DEVINT_SC); -} - -/** - * gadget_release() - Free the gadget driver private data - * @pdev reference to struct pci_dev - */ -static void gadget_release(struct device *pdev) -{ - struct pch_udc_dev *dev = dev_get_drvdata(pdev); - - kfree(dev); -} - -/** - * pch_udc_pcd_reinit() - This API initializes the endpoint structures - * @dev: Reference to the driver structure - */ -static void pch_udc_pcd_reinit(struct pch_udc_dev *dev) -{ - const char *const ep_string[] = { - ep0_string, "ep0out", "ep1in", "ep1out", "ep2in", "ep2out", - "ep3in", "ep3out", "ep4in", "ep4out", "ep5in", "ep5out", - "ep6in", "ep6out", "ep7in", "ep7out", "ep8in", "ep8out", - "ep9in", "ep9out", "ep10in", "ep10out", "ep11in", "ep11out", - "ep12in", "ep12out", "ep13in", "ep13out", "ep14in", "ep14out", - "ep15in", "ep15out", - }; - int i; - - dev->gadget.speed = USB_SPEED_UNKNOWN; - INIT_LIST_HEAD(&dev->gadget.ep_list); - - /* Initialize the endpoints structures */ - memset(dev->ep, 0, sizeof dev->ep); - for (i = 0; i < PCH_UDC_EP_NUM; i++) { - struct pch_udc_ep *ep = &dev->ep[i]; - ep->dev = dev; - ep->halted = 1; - ep->num = i / 2; - ep->in = ~i & 1; - ep->ep.name = ep_string[i]; - ep->ep.ops = &pch_udc_ep_ops; - if (ep->in) - ep->offset_addr = ep->num * UDC_EP_REG_SHIFT; - else - ep->offset_addr = (UDC_EPINT_OUT_SHIFT + ep->num) * - UDC_EP_REG_SHIFT; - /* need to set ep->ep.maxpacket and set Default Configuration?*/ - ep->ep.maxpacket = UDC_BULK_MAX_PKT_SIZE; - list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); - INIT_LIST_HEAD(&ep->queue); - } - dev->ep[UDC_EP0IN_IDX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE; - dev->ep[UDC_EP0OUT_IDX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE; - - /* remove ep0 in and out from the list. They have own pointer */ - list_del_init(&dev->ep[UDC_EP0IN_IDX].ep.ep_list); - list_del_init(&dev->ep[UDC_EP0OUT_IDX].ep.ep_list); - - dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IDX].ep; - INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); -} - -/** - * pch_udc_pcd_init() - This API initializes the driver structure - * @dev: Reference to the driver structure - * - * Return codes: - * 0: Success - */ -static int pch_udc_pcd_init(struct pch_udc_dev *dev) -{ - pch_udc_init(dev); - pch_udc_pcd_reinit(dev); - pch_vbus_gpio_init(dev, vbus_gpio_port); - return 0; -} - -/** - * init_dma_pools() - create dma pools during initialization - * @pdev: reference to struct pci_dev - */ -static int init_dma_pools(struct pch_udc_dev *dev) -{ - struct pch_udc_stp_dma_desc *td_stp; - struct pch_udc_data_dma_desc *td_data; - - /* DMA setup */ - dev->data_requests = pci_pool_create("data_requests", dev->pdev, - sizeof(struct pch_udc_data_dma_desc), 0, 0); - if (!dev->data_requests) { - dev_err(&dev->pdev->dev, "%s: can't get request data pool\n", - __func__); - return -ENOMEM; - } - - /* dma desc for setup data */ - dev->stp_requests = pci_pool_create("setup requests", dev->pdev, - sizeof(struct pch_udc_stp_dma_desc), 0, 0); - if (!dev->stp_requests) { - dev_err(&dev->pdev->dev, "%s: can't get setup request pool\n", - __func__); - return -ENOMEM; - } - /* setup */ - td_stp = pci_pool_alloc(dev->stp_requests, GFP_KERNEL, - &dev->ep[UDC_EP0OUT_IDX].td_stp_phys); - if (!td_stp) { - dev_err(&dev->pdev->dev, - "%s: can't allocate setup dma descriptor\n", __func__); - return -ENOMEM; - } - dev->ep[UDC_EP0OUT_IDX].td_stp = td_stp; - - /* data: 0 packets !? */ - td_data = pci_pool_alloc(dev->data_requests, GFP_KERNEL, - &dev->ep[UDC_EP0OUT_IDX].td_data_phys); - if (!td_data) { - dev_err(&dev->pdev->dev, - "%s: can't allocate data dma descriptor\n", __func__); - return -ENOMEM; - } - dev->ep[UDC_EP0OUT_IDX].td_data = td_data; - dev->ep[UDC_EP0IN_IDX].td_stp = NULL; - dev->ep[UDC_EP0IN_IDX].td_stp_phys = 0; - dev->ep[UDC_EP0IN_IDX].td_data = NULL; - dev->ep[UDC_EP0IN_IDX].td_data_phys = 0; - - dev->ep0out_buf = kzalloc(UDC_EP0OUT_BUFF_SIZE * 4, GFP_KERNEL); - if (!dev->ep0out_buf) - return -ENOMEM; - dev->dma_addr = dma_map_single(&dev->pdev->dev, dev->ep0out_buf, - UDC_EP0OUT_BUFF_SIZE * 4, - DMA_FROM_DEVICE); - return 0; -} - -static int pch_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) -{ - struct pch_udc_dev *dev = pch_udc; - int retval; - - if (!driver || (driver->max_speed == USB_SPEED_UNKNOWN) || !bind || - !driver->setup || !driver->unbind || !driver->disconnect) { - dev_err(&dev->pdev->dev, - "%s: invalid driver parameter\n", __func__); - return -EINVAL; - } - - if (!dev) - return -ENODEV; - - if (dev->driver) { - dev_err(&dev->pdev->dev, "%s: already bound\n", __func__); - return -EBUSY; - } - driver->driver.bus = NULL; - dev->driver = driver; - dev->gadget.dev.driver = &driver->driver; - - /* Invoke the bind routine of the gadget driver */ - retval = bind(&dev->gadget); - - if (retval) { - dev_err(&dev->pdev->dev, "%s: binding to %s returning %d\n", - __func__, driver->driver.name, retval); - dev->driver = NULL; - dev->gadget.dev.driver = NULL; - return retval; - } - /* get ready for ep0 traffic */ - pch_udc_setup_ep0(dev); - - /* clear SD */ - if ((pch_vbus_gpio_get_value(dev) != 0) || !dev->vbus_gpio.intr) - pch_udc_clear_disconnect(dev); - - dev->connected = 1; - return 0; -} - -static int pch_udc_stop(struct usb_gadget_driver *driver) -{ - struct pch_udc_dev *dev = pch_udc; - - if (!dev) - return -ENODEV; - - if (!driver || (driver != dev->driver)) { - dev_err(&dev->pdev->dev, - "%s: invalid driver parameter\n", __func__); - return -EINVAL; - } - - pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK); - - /* Assures that there are no pending requests with this driver */ - driver->disconnect(&dev->gadget); - driver->unbind(&dev->gadget); - dev->gadget.dev.driver = NULL; - dev->driver = NULL; - dev->connected = 0; - - /* set SD */ - pch_udc_set_disconnect(dev); - return 0; -} - -static void pch_udc_shutdown(struct pci_dev *pdev) -{ - struct pch_udc_dev *dev = pci_get_drvdata(pdev); - - pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK); - pch_udc_disable_ep_interrupts(dev, UDC_EPINT_MSK_DISABLE_ALL); - - /* disable the pullup so the host will think we're gone */ - pch_udc_set_disconnect(dev); -} - -static void pch_udc_remove(struct pci_dev *pdev) -{ - struct pch_udc_dev *dev = pci_get_drvdata(pdev); - - usb_del_gadget_udc(&dev->gadget); - - /* gadget driver must not be registered */ - if (dev->driver) - dev_err(&pdev->dev, - "%s: gadget driver still bound!!!\n", __func__); - /* dma pool cleanup */ - if (dev->data_requests) - pci_pool_destroy(dev->data_requests); - - if (dev->stp_requests) { - /* cleanup DMA desc's for ep0in */ - if (dev->ep[UDC_EP0OUT_IDX].td_stp) { - pci_pool_free(dev->stp_requests, - dev->ep[UDC_EP0OUT_IDX].td_stp, - dev->ep[UDC_EP0OUT_IDX].td_stp_phys); - } - if (dev->ep[UDC_EP0OUT_IDX].td_data) { - pci_pool_free(dev->stp_requests, - dev->ep[UDC_EP0OUT_IDX].td_data, - dev->ep[UDC_EP0OUT_IDX].td_data_phys); - } - pci_pool_destroy(dev->stp_requests); - } - - if (dev->dma_addr) - dma_unmap_single(&dev->pdev->dev, dev->dma_addr, - UDC_EP0OUT_BUFF_SIZE * 4, DMA_FROM_DEVICE); - kfree(dev->ep0out_buf); - - pch_vbus_gpio_free(dev); - - pch_udc_exit(dev); - - if (dev->irq_registered) - free_irq(pdev->irq, dev); - if (dev->base_addr) - iounmap(dev->base_addr); - if (dev->mem_region) - release_mem_region(dev->phys_addr, - pci_resource_len(pdev, PCH_UDC_PCI_BAR)); - if (dev->active) - pci_disable_device(pdev); - if (dev->registered) - device_unregister(&dev->gadget.dev); - kfree(dev); - pci_set_drvdata(pdev, NULL); -} - -#ifdef CONFIG_PM -static int pch_udc_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct pch_udc_dev *dev = pci_get_drvdata(pdev); - - pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK); - pch_udc_disable_ep_interrupts(dev, UDC_EPINT_MSK_DISABLE_ALL); - - pci_disable_device(pdev); - pci_enable_wake(pdev, PCI_D3hot, 0); - - if (pci_save_state(pdev)) { - dev_err(&pdev->dev, - "%s: could not save PCI config state\n", __func__); - return -ENOMEM; - } - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return 0; -} - -static int pch_udc_resume(struct pci_dev *pdev) -{ - int ret; - - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - ret = pci_enable_device(pdev); - if (ret) { - dev_err(&pdev->dev, "%s: pci_enable_device failed\n", __func__); - return ret; - } - pci_enable_wake(pdev, PCI_D3hot, 0); - return 0; -} -#else -#define pch_udc_suspend NULL -#define pch_udc_resume NULL -#endif /* CONFIG_PM */ - -static int pch_udc_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - unsigned long resource; - unsigned long len; - int retval; - struct pch_udc_dev *dev; - - /* one udc only */ - if (pch_udc) { - pr_err("%s: already probed\n", __func__); - return -EBUSY; - } - /* init */ - dev = kzalloc(sizeof *dev, GFP_KERNEL); - if (!dev) { - pr_err("%s: no memory for device structure\n", __func__); - return -ENOMEM; - } - /* pci setup */ - if (pci_enable_device(pdev) < 0) { - kfree(dev); - pr_err("%s: pci_enable_device failed\n", __func__); - return -ENODEV; - } - dev->active = 1; - pci_set_drvdata(pdev, dev); - - /* PCI resource allocation */ - resource = pci_resource_start(pdev, 1); - len = pci_resource_len(pdev, 1); - - if (!request_mem_region(resource, len, KBUILD_MODNAME)) { - dev_err(&pdev->dev, "%s: pci device used already\n", __func__); - retval = -EBUSY; - goto finished; - } - dev->phys_addr = resource; - dev->mem_region = 1; - - dev->base_addr = ioremap_nocache(resource, len); - if (!dev->base_addr) { - pr_err("%s: device memory cannot be mapped\n", __func__); - retval = -ENOMEM; - goto finished; - } - if (!pdev->irq) { - dev_err(&pdev->dev, "%s: irq not set\n", __func__); - retval = -ENODEV; - goto finished; - } - pch_udc = dev; - /* initialize the hardware */ - if (pch_udc_pcd_init(dev)) { - retval = -ENODEV; - goto finished; - } - if (request_irq(pdev->irq, pch_udc_isr, IRQF_SHARED, KBUILD_MODNAME, - dev)) { - dev_err(&pdev->dev, "%s: request_irq(%d) fail\n", __func__, - pdev->irq); - retval = -ENODEV; - goto finished; - } - dev->irq = pdev->irq; - dev->irq_registered = 1; - - pci_set_master(pdev); - pci_try_set_mwi(pdev); - - /* device struct setup */ - spin_lock_init(&dev->lock); - dev->pdev = pdev; - dev->gadget.ops = &pch_udc_ops; - - retval = init_dma_pools(dev); - if (retval) - goto finished; - - dev_set_name(&dev->gadget.dev, "gadget"); - dev->gadget.dev.parent = &pdev->dev; - dev->gadget.dev.dma_mask = pdev->dev.dma_mask; - dev->gadget.dev.release = gadget_release; - dev->gadget.name = KBUILD_MODNAME; - dev->gadget.max_speed = USB_SPEED_HIGH; - - retval = device_register(&dev->gadget.dev); - if (retval) - goto finished; - dev->registered = 1; - - /* Put the device in disconnected state till a driver is bound */ - pch_udc_set_disconnect(dev); - retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); - if (retval) - goto finished; - return 0; - -finished: - pch_udc_remove(pdev); - return retval; -} - -static DEFINE_PCI_DEVICE_TABLE(pch_udc_pcidev_id) = { - { - PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EG20T_UDC), - .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe, - .class_mask = 0xffffffff, - }, - { - PCI_DEVICE(PCI_VENDOR_ID_ROHM, PCI_DEVICE_ID_ML7213_IOH_UDC), - .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe, - .class_mask = 0xffffffff, - }, - { - PCI_DEVICE(PCI_VENDOR_ID_ROHM, PCI_DEVICE_ID_ML7831_IOH_UDC), - .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe, - .class_mask = 0xffffffff, - }, - { 0 }, -}; - -MODULE_DEVICE_TABLE(pci, pch_udc_pcidev_id); - - -static struct pci_driver pch_udc_driver = { - .name = KBUILD_MODNAME, - .id_table = pch_udc_pcidev_id, - .probe = pch_udc_probe, - .remove = pch_udc_remove, - .suspend = pch_udc_suspend, - .resume = pch_udc_resume, - .shutdown = pch_udc_shutdown, -}; - -static int __init pch_udc_pci_init(void) -{ - return pci_register_driver(&pch_udc_driver); -} -module_init(pch_udc_pci_init); - -static void __exit pch_udc_pci_exit(void) -{ - pci_unregister_driver(&pch_udc_driver); -} -module_exit(pch_udc_pci_exit); - -MODULE_DESCRIPTION("Intel EG20T USB Device Controller"); -MODULE_AUTHOR("LAPIS Semiconductor, "); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/printer.c b/ANDROID_3.4.5/drivers/usb/gadget/printer.c deleted file mode 100644 index 4e4dc1f5..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/printer.c +++ /dev/null @@ -1,1600 +0,0 @@ -/* - * printer.c -- Printer gadget driver - * - * Copyright (C) 2003-2005 David Brownell - * Copyright (C) 2006 Craig W. Nadler - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "gadget_chips.h" - - -/* - * 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 "usbstring.c" -#include "config.c" -#include "epautoconf.c" - -/*-------------------------------------------------------------------------*/ - -#define DRIVER_DESC "Printer Gadget" -#define DRIVER_VERSION "2007 OCT 06" - -static DEFINE_MUTEX(printer_mutex); -static const char shortname [] = "printer"; -static const char driver_desc [] = DRIVER_DESC; - -static dev_t g_printer_devno; - -static struct class *usb_gadget_class; - -/*-------------------------------------------------------------------------*/ - -struct printer_dev { - spinlock_t lock; /* lock this structure */ - /* lock buffer lists during read/write calls */ - struct mutex lock_printer_io; - struct usb_gadget *gadget; - struct usb_request *req; /* for control responses */ - u8 config; - s8 interface; - struct usb_ep *in_ep, *out_ep; - - struct list_head rx_reqs; /* List of free RX structs */ - struct list_head rx_reqs_active; /* List of Active RX xfers */ - struct list_head rx_buffers; /* List of completed xfers */ - /* wait until there is data to be read. */ - wait_queue_head_t rx_wait; - struct list_head tx_reqs; /* List of free TX structs */ - struct list_head tx_reqs_active; /* List of Active TX xfers */ - /* Wait until there are write buffers available to use. */ - wait_queue_head_t tx_wait; - /* Wait until all write buffers have been sent. */ - wait_queue_head_t tx_flush_wait; - struct usb_request *current_rx_req; - size_t current_rx_bytes; - u8 *current_rx_buf; - u8 printer_status; - u8 reset_printer; - struct cdev printer_cdev; - struct device *pdev; - u8 printer_cdev_open; - wait_queue_head_t wait; -}; - -static struct printer_dev usb_printer_gadget; - -/*-------------------------------------------------------------------------*/ - -/* 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 PRINTER_VENDOR_NUM 0x0525 /* NetChip */ -#define PRINTER_PRODUCT_NUM 0xa4a8 /* Linux-USB Printer Gadget */ - -/* Some systems will want different product identifiers published in the - * device descriptor, either numbers or strings or both. These string - * parameters are in UTF-8 (superset of ASCII's 7 bit characters). - */ - -static ushort idVendor; -module_param(idVendor, ushort, S_IRUGO); -MODULE_PARM_DESC(idVendor, "USB Vendor ID"); - -static ushort idProduct; -module_param(idProduct, ushort, S_IRUGO); -MODULE_PARM_DESC(idProduct, "USB Product ID"); - -static ushort bcdDevice; -module_param(bcdDevice, ushort, S_IRUGO); -MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)"); - -static char *iManufacturer; -module_param(iManufacturer, charp, S_IRUGO); -MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string"); - -static char *iProduct; -module_param(iProduct, charp, S_IRUGO); -MODULE_PARM_DESC(iProduct, "USB Product string"); - -static char *iSerialNum; -module_param(iSerialNum, charp, S_IRUGO); -MODULE_PARM_DESC(iSerialNum, "1"); - -static char *iPNPstring; -module_param(iPNPstring, charp, S_IRUGO); -MODULE_PARM_DESC(iPNPstring, "MFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;"); - -/* Number of requests to allocate per endpoint, not used for ep0. */ -static unsigned qlen = 10; -module_param(qlen, uint, S_IRUGO|S_IWUSR); - -#define QLEN qlen - -#ifdef CONFIG_USB_GADGET_DUALSPEED -#define DEVSPEED USB_SPEED_HIGH -#else /* full speed (low speed doesn't do bulk) */ -#define DEVSPEED USB_SPEED_FULL -#endif - -/*-------------------------------------------------------------------------*/ - -#define xprintk(d, level, fmt, args...) \ - printk(level "%s: " fmt, DRIVER_DESC, ## args) - -#ifdef DEBUG -#define DBG(dev, fmt, args...) \ - xprintk(dev, KERN_DEBUG, fmt, ## args) -#else -#define DBG(dev, fmt, args...) \ - do { } while (0) -#endif /* DEBUG */ - -#ifdef VERBOSE -#define VDBG(dev, fmt, args...) \ - xprintk(dev, KERN_DEBUG, fmt, ## args) -#else -#define VDBG(dev, fmt, args...) \ - do { } while (0) -#endif /* VERBOSE */ - -#define ERROR(dev, fmt, args...) \ - xprintk(dev, KERN_ERR, fmt, ## args) -#define WARNING(dev, fmt, args...) \ - xprintk(dev, KERN_WARNING, fmt, ## args) -#define INFO(dev, fmt, args...) \ - xprintk(dev, KERN_INFO, fmt, ## args) - -/*-------------------------------------------------------------------------*/ - -/* USB DRIVER HOOKUP (to the hardware driver, below us), mostly - * ep0 implementation: descriptors, config management, setup(). - * also optional class-specific notification interrupt transfer. - */ - -/* - * DESCRIPTORS ... most are static, but strings and (full) configuration - * descriptors are built on demand. - */ - -#define STRING_MANUFACTURER 1 -#define STRING_PRODUCT 2 -#define STRING_SERIALNUM 3 - -/* holds our biggest descriptor */ -#define USB_DESC_BUFSIZE 256 -#define USB_BUFSIZE 8192 - -/* This device advertises one configuration. */ -#define DEV_CONFIG_VALUE 1 -#define PRINTER_INTERFACE 0 - -static struct usb_device_descriptor device_desc = { - .bLength = sizeof device_desc, - .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_PER_INTERFACE, - .bDeviceSubClass = 0, - .bDeviceProtocol = 0, - .idVendor = cpu_to_le16(PRINTER_VENDOR_NUM), - .idProduct = cpu_to_le16(PRINTER_PRODUCT_NUM), - .iManufacturer = STRING_MANUFACTURER, - .iProduct = STRING_PRODUCT, - .iSerialNumber = STRING_SERIALNUM, - .bNumConfigurations = 1 -}; - -static struct usb_otg_descriptor otg_desc = { - .bLength = sizeof otg_desc, - .bDescriptorType = USB_DT_OTG, - .bmAttributes = USB_OTG_SRP -}; - -static struct usb_config_descriptor config_desc = { - .bLength = sizeof config_desc, - .bDescriptorType = USB_DT_CONFIG, - - /* compute wTotalLength on the fly */ - .bNumInterfaces = 1, - .bConfigurationValue = DEV_CONFIG_VALUE, - .iConfiguration = 0, - .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, - .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2, -}; - -static struct usb_interface_descriptor intf_desc = { - .bLength = sizeof intf_desc, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = PRINTER_INTERFACE, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_PRINTER, - .bInterfaceSubClass = 1, /* Printer Sub-Class */ - .bInterfaceProtocol = 2, /* Bi-Directional */ - .iInterface = 0 -}; - -static struct usb_endpoint_descriptor fs_ep_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK -}; - -static struct usb_endpoint_descriptor fs_ep_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK -}; - -static const struct usb_descriptor_header *fs_printer_function [11] = { - (struct usb_descriptor_header *) &otg_desc, - (struct usb_descriptor_header *) &intf_desc, - (struct usb_descriptor_header *) &fs_ep_in_desc, - (struct usb_descriptor_header *) &fs_ep_out_desc, - NULL -}; - -#ifdef CONFIG_USB_GADGET_DUALSPEED - -/* - * usb 2.0 devices need to expose both high speed and full speed - * descriptors, unless they only run at full speed. - */ - -static struct usb_endpoint_descriptor hs_ep_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512) -}; - -static struct usb_endpoint_descriptor hs_ep_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512) -}; - -static struct usb_qualifier_descriptor dev_qualifier = { - .bLength = sizeof dev_qualifier, - .bDescriptorType = USB_DT_DEVICE_QUALIFIER, - .bcdUSB = cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_PRINTER, - .bNumConfigurations = 1 -}; - -static const struct usb_descriptor_header *hs_printer_function [11] = { - (struct usb_descriptor_header *) &otg_desc, - (struct usb_descriptor_header *) &intf_desc, - (struct usb_descriptor_header *) &hs_ep_in_desc, - (struct usb_descriptor_header *) &hs_ep_out_desc, - NULL -}; - -/* maxpacket and other transfer characteristics vary by speed. */ -#define ep_desc(g, hs, fs) (((g)->speed == USB_SPEED_HIGH)?(hs):(fs)) - -#else - -/* if there's no high speed support, maxpacket doesn't change. */ -#define ep_desc(g, hs, fs) (((void)(g)), (fs)) - -#endif /* !CONFIG_USB_GADGET_DUALSPEED */ - -/*-------------------------------------------------------------------------*/ - -/* descriptors that are built on-demand */ - -static char manufacturer [50]; -static char product_desc [40] = DRIVER_DESC; -static char serial_num [40] = "1"; -static char pnp_string [1024] = - "XXMFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;"; - -/* static strings, in UTF-8 */ -static struct usb_string strings [] = { - { STRING_MANUFACTURER, manufacturer, }, - { STRING_PRODUCT, product_desc, }, - { STRING_SERIALNUM, serial_num, }, - { } /* end of list */ -}; - -static struct usb_gadget_strings stringtab = { - .language = 0x0409, /* en-us */ - .strings = strings, -}; - -/*-------------------------------------------------------------------------*/ - -static struct usb_request * -printer_req_alloc(struct usb_ep *ep, unsigned len, gfp_t gfp_flags) -{ - struct usb_request *req; - - req = usb_ep_alloc_request(ep, gfp_flags); - - if (req != NULL) { - req->length = len; - req->buf = kmalloc(len, gfp_flags); - if (req->buf == NULL) { - usb_ep_free_request(ep, req); - return NULL; - } - } - - return req; -} - -static void -printer_req_free(struct usb_ep *ep, struct usb_request *req) -{ - if (ep != NULL && req != NULL) { - kfree(req->buf); - usb_ep_free_request(ep, req); - } -} - -/*-------------------------------------------------------------------------*/ - -static void rx_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct printer_dev *dev = ep->driver_data; - int status = req->status; - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - - list_del_init(&req->list); /* Remode from Active List */ - - switch (status) { - - /* normal completion */ - case 0: - if (req->actual > 0) { - list_add_tail(&req->list, &dev->rx_buffers); - DBG(dev, "G_Printer : rx length %d\n", req->actual); - } else { - list_add(&req->list, &dev->rx_reqs); - } - break; - - /* software-driven interface shutdown */ - case -ECONNRESET: /* unlink */ - case -ESHUTDOWN: /* disconnect etc */ - VDBG(dev, "rx shutdown, code %d\n", status); - list_add(&req->list, &dev->rx_reqs); - break; - - /* for hardware automagic (such as pxa) */ - case -ECONNABORTED: /* endpoint reset */ - DBG(dev, "rx %s reset\n", ep->name); - list_add(&req->list, &dev->rx_reqs); - break; - - /* data overrun */ - case -EOVERFLOW: - /* FALLTHROUGH */ - - default: - DBG(dev, "rx status %d\n", status); - list_add(&req->list, &dev->rx_reqs); - break; - } - - wake_up_interruptible(&dev->rx_wait); - spin_unlock_irqrestore(&dev->lock, flags); -} - -static void tx_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct printer_dev *dev = ep->driver_data; - - switch (req->status) { - default: - VDBG(dev, "tx err %d\n", req->status); - /* FALLTHROUGH */ - case -ECONNRESET: /* unlink */ - case -ESHUTDOWN: /* disconnect etc */ - break; - case 0: - break; - } - - spin_lock(&dev->lock); - /* Take the request struct off the active list and put it on the - * free list. - */ - list_del_init(&req->list); - list_add(&req->list, &dev->tx_reqs); - wake_up_interruptible(&dev->tx_wait); - if (likely(list_empty(&dev->tx_reqs_active))) - wake_up_interruptible(&dev->tx_flush_wait); - - spin_unlock(&dev->lock); -} - -/*-------------------------------------------------------------------------*/ - -static int -printer_open(struct inode *inode, struct file *fd) -{ - struct printer_dev *dev; - unsigned long flags; - int ret = -EBUSY; - - mutex_lock(&printer_mutex); - dev = container_of(inode->i_cdev, struct printer_dev, printer_cdev); - - spin_lock_irqsave(&dev->lock, flags); - - if (!dev->printer_cdev_open) { - dev->printer_cdev_open = 1; - fd->private_data = dev; - ret = 0; - /* Change the printer status to show that it's on-line. */ - dev->printer_status |= PRINTER_SELECTED; - } - - spin_unlock_irqrestore(&dev->lock, flags); - - DBG(dev, "printer_open returned %x\n", ret); - mutex_unlock(&printer_mutex); - return ret; -} - -static int -printer_close(struct inode *inode, struct file *fd) -{ - struct printer_dev *dev = fd->private_data; - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - dev->printer_cdev_open = 0; - fd->private_data = NULL; - /* Change printer status to show that the printer is off-line. */ - dev->printer_status &= ~PRINTER_SELECTED; - spin_unlock_irqrestore(&dev->lock, flags); - - DBG(dev, "printer_close\n"); - - return 0; -} - -/* This function must be called with interrupts turned off. */ -static void -setup_rx_reqs(struct printer_dev *dev) -{ - struct usb_request *req; - - while (likely(!list_empty(&dev->rx_reqs))) { - int error; - - req = container_of(dev->rx_reqs.next, - struct usb_request, list); - list_del_init(&req->list); - - /* The USB Host sends us whatever amount of data it wants to - * so we always set the length field to the full USB_BUFSIZE. - * If the amount of data is more than the read() caller asked - * for it will be stored in the request buffer until it is - * asked for by read(). - */ - req->length = USB_BUFSIZE; - req->complete = rx_complete; - - error = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC); - if (error) { - DBG(dev, "rx submit --> %d\n", error); - list_add(&req->list, &dev->rx_reqs); - break; - } else { - list_add(&req->list, &dev->rx_reqs_active); - } - } -} - -static ssize_t -printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr) -{ - struct printer_dev *dev = fd->private_data; - unsigned long flags; - size_t size; - size_t bytes_copied; - struct usb_request *req; - /* This is a pointer to the current USB rx request. */ - struct usb_request *current_rx_req; - /* This is the number of bytes in the current rx buffer. */ - size_t current_rx_bytes; - /* This is a pointer to the current rx buffer. */ - u8 *current_rx_buf; - - if (len == 0) - return -EINVAL; - - DBG(dev, "printer_read trying to read %d bytes\n", (int)len); - - mutex_lock(&dev->lock_printer_io); - spin_lock_irqsave(&dev->lock, flags); - - /* We will use this flag later to check if a printer reset happened - * after we turn interrupts back on. - */ - dev->reset_printer = 0; - - setup_rx_reqs(dev); - - bytes_copied = 0; - current_rx_req = dev->current_rx_req; - current_rx_bytes = dev->current_rx_bytes; - current_rx_buf = dev->current_rx_buf; - dev->current_rx_req = NULL; - dev->current_rx_bytes = 0; - dev->current_rx_buf = NULL; - - /* Check if there is any data in the read buffers. Please note that - * current_rx_bytes is the number of bytes in the current rx buffer. - * If it is zero then check if there are any other rx_buffers that - * are on the completed list. We are only out of data if all rx - * buffers are empty. - */ - if ((current_rx_bytes == 0) && - (likely(list_empty(&dev->rx_buffers)))) { - /* Turn interrupts back on before sleeping. */ - spin_unlock_irqrestore(&dev->lock, flags); - - /* - * If no data is available check if this is a NON-Blocking - * call or not. - */ - if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) { - mutex_unlock(&dev->lock_printer_io); - return -EAGAIN; - } - - /* Sleep until data is available */ - wait_event_interruptible(dev->rx_wait, - (likely(!list_empty(&dev->rx_buffers)))); - spin_lock_irqsave(&dev->lock, flags); - } - - /* We have data to return then copy it to the caller's buffer.*/ - while ((current_rx_bytes || likely(!list_empty(&dev->rx_buffers))) - && len) { - if (current_rx_bytes == 0) { - req = container_of(dev->rx_buffers.next, - struct usb_request, list); - list_del_init(&req->list); - - if (req->actual && req->buf) { - current_rx_req = req; - current_rx_bytes = req->actual; - current_rx_buf = req->buf; - } else { - list_add(&req->list, &dev->rx_reqs); - continue; - } - } - - /* Don't leave irqs off while doing memory copies */ - spin_unlock_irqrestore(&dev->lock, flags); - - if (len > current_rx_bytes) - size = current_rx_bytes; - else - size = len; - - size -= copy_to_user(buf, current_rx_buf, size); - bytes_copied += size; - len -= size; - buf += size; - - spin_lock_irqsave(&dev->lock, flags); - - /* We've disconnected or reset so return. */ - if (dev->reset_printer) { - list_add(¤t_rx_req->list, &dev->rx_reqs); - spin_unlock_irqrestore(&dev->lock, flags); - mutex_unlock(&dev->lock_printer_io); - return -EAGAIN; - } - - /* If we not returning all the data left in this RX request - * buffer then adjust the amount of data left in the buffer. - * Othewise if we are done with this RX request buffer then - * requeue it to get any incoming data from the USB host. - */ - if (size < current_rx_bytes) { - current_rx_bytes -= size; - current_rx_buf += size; - } else { - list_add(¤t_rx_req->list, &dev->rx_reqs); - current_rx_bytes = 0; - current_rx_buf = NULL; - current_rx_req = NULL; - } - } - - dev->current_rx_req = current_rx_req; - dev->current_rx_bytes = current_rx_bytes; - dev->current_rx_buf = current_rx_buf; - - spin_unlock_irqrestore(&dev->lock, flags); - mutex_unlock(&dev->lock_printer_io); - - DBG(dev, "printer_read returned %d bytes\n", (int)bytes_copied); - - if (bytes_copied) - return bytes_copied; - else - return -EAGAIN; -} - -static ssize_t -printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr) -{ - struct printer_dev *dev = fd->private_data; - unsigned long flags; - size_t size; /* Amount of data in a TX request. */ - size_t bytes_copied = 0; - struct usb_request *req; - - DBG(dev, "printer_write trying to send %d bytes\n", (int)len); - - if (len == 0) - return -EINVAL; - - mutex_lock(&dev->lock_printer_io); - spin_lock_irqsave(&dev->lock, flags); - - /* Check if a printer reset happens while we have interrupts on */ - dev->reset_printer = 0; - - /* Check if there is any available write buffers */ - if (likely(list_empty(&dev->tx_reqs))) { - /* Turn interrupts back on before sleeping. */ - spin_unlock_irqrestore(&dev->lock, flags); - - /* - * If write buffers are available check if this is - * a NON-Blocking call or not. - */ - if (fd->f_flags & (O_NONBLOCK|O_NDELAY)) { - mutex_unlock(&dev->lock_printer_io); - return -EAGAIN; - } - - /* Sleep until a write buffer is available */ - wait_event_interruptible(dev->tx_wait, - (likely(!list_empty(&dev->tx_reqs)))); - spin_lock_irqsave(&dev->lock, flags); - } - - while (likely(!list_empty(&dev->tx_reqs)) && len) { - - if (len > USB_BUFSIZE) - size = USB_BUFSIZE; - else - size = len; - - req = container_of(dev->tx_reqs.next, struct usb_request, - list); - list_del_init(&req->list); - - req->complete = tx_complete; - req->length = size; - - /* Check if we need to send a zero length packet. */ - if (len > size) - /* They will be more TX requests so no yet. */ - req->zero = 0; - else - /* If the data amount is not a multple of the - * maxpacket size then send a zero length packet. - */ - req->zero = ((len % dev->in_ep->maxpacket) == 0); - - /* Don't leave irqs off while doing memory copies */ - spin_unlock_irqrestore(&dev->lock, flags); - - if (copy_from_user(req->buf, buf, size)) { - list_add(&req->list, &dev->tx_reqs); - mutex_unlock(&dev->lock_printer_io); - return bytes_copied; - } - - bytes_copied += size; - len -= size; - buf += size; - - spin_lock_irqsave(&dev->lock, flags); - - /* We've disconnected or reset so free the req and buffer */ - if (dev->reset_printer) { - list_add(&req->list, &dev->tx_reqs); - spin_unlock_irqrestore(&dev->lock, flags); - mutex_unlock(&dev->lock_printer_io); - return -EAGAIN; - } - - if (usb_ep_queue(dev->in_ep, req, GFP_ATOMIC)) { - list_add(&req->list, &dev->tx_reqs); - spin_unlock_irqrestore(&dev->lock, flags); - mutex_unlock(&dev->lock_printer_io); - return -EAGAIN; - } - - list_add(&req->list, &dev->tx_reqs_active); - - } - - spin_unlock_irqrestore(&dev->lock, flags); - mutex_unlock(&dev->lock_printer_io); - - DBG(dev, "printer_write sent %d bytes\n", (int)bytes_copied); - - if (bytes_copied) { - return bytes_copied; - } else { - return -EAGAIN; - } -} - -static int -printer_fsync(struct file *fd, loff_t start, loff_t end, int datasync) -{ - struct printer_dev *dev = fd->private_data; - struct inode *inode = fd->f_path.dentry->d_inode; - unsigned long flags; - int tx_list_empty; - - mutex_lock(&inode->i_mutex); - spin_lock_irqsave(&dev->lock, flags); - tx_list_empty = (likely(list_empty(&dev->tx_reqs))); - spin_unlock_irqrestore(&dev->lock, flags); - - if (!tx_list_empty) { - /* Sleep until all data has been sent */ - wait_event_interruptible(dev->tx_flush_wait, - (likely(list_empty(&dev->tx_reqs_active)))); - } - mutex_unlock(&inode->i_mutex); - - return 0; -} - -static unsigned int -printer_poll(struct file *fd, poll_table *wait) -{ - struct printer_dev *dev = fd->private_data; - unsigned long flags; - int status = 0; - - mutex_lock(&dev->lock_printer_io); - spin_lock_irqsave(&dev->lock, flags); - setup_rx_reqs(dev); - spin_unlock_irqrestore(&dev->lock, flags); - mutex_unlock(&dev->lock_printer_io); - - poll_wait(fd, &dev->rx_wait, wait); - poll_wait(fd, &dev->tx_wait, wait); - - spin_lock_irqsave(&dev->lock, flags); - if (likely(!list_empty(&dev->tx_reqs))) - status |= POLLOUT | POLLWRNORM; - - if (likely(dev->current_rx_bytes) || - likely(!list_empty(&dev->rx_buffers))) - status |= POLLIN | POLLRDNORM; - - spin_unlock_irqrestore(&dev->lock, flags); - - return status; -} - -static long -printer_ioctl(struct file *fd, unsigned int code, unsigned long arg) -{ - struct printer_dev *dev = fd->private_data; - unsigned long flags; - int status = 0; - - DBG(dev, "printer_ioctl: cmd=0x%4.4x, arg=%lu\n", code, arg); - - /* handle ioctls */ - - spin_lock_irqsave(&dev->lock, flags); - - switch (code) { - case GADGET_GET_PRINTER_STATUS: - status = (int)dev->printer_status; - break; - case GADGET_SET_PRINTER_STATUS: - dev->printer_status = (u8)arg; - break; - default: - /* could not handle ioctl */ - DBG(dev, "printer_ioctl: ERROR cmd=0x%4.4xis not supported\n", - code); - status = -ENOTTY; - } - - spin_unlock_irqrestore(&dev->lock, flags); - - return status; -} - -/* used after endpoint configuration */ -static const struct file_operations printer_io_operations = { - .owner = THIS_MODULE, - .open = printer_open, - .read = printer_read, - .write = printer_write, - .fsync = printer_fsync, - .poll = printer_poll, - .unlocked_ioctl = printer_ioctl, - .release = printer_close, - .llseek = noop_llseek, -}; - -/*-------------------------------------------------------------------------*/ - -static int -set_printer_interface(struct printer_dev *dev) -{ - int result = 0; - - dev->in_ep->desc = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc); - dev->in_ep->driver_data = dev; - - dev->out_ep->desc = ep_desc(dev->gadget, &hs_ep_out_desc, - &fs_ep_out_desc); - dev->out_ep->driver_data = dev; - - result = usb_ep_enable(dev->in_ep); - if (result != 0) { - DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result); - goto done; - } - - result = usb_ep_enable(dev->out_ep); - if (result != 0) { - DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result); - goto done; - } - -done: - /* on error, disable any endpoints */ - if (result != 0) { - (void) usb_ep_disable(dev->in_ep); - (void) usb_ep_disable(dev->out_ep); - dev->in_ep->desc = NULL; - dev->out_ep->desc = NULL; - } - - /* caller is responsible for cleanup on error */ - return result; -} - -static void printer_reset_interface(struct printer_dev *dev) -{ - if (dev->interface < 0) - return; - - DBG(dev, "%s\n", __func__); - - if (dev->in_ep->desc) - usb_ep_disable(dev->in_ep); - - if (dev->out_ep->desc) - usb_ep_disable(dev->out_ep); - - dev->in_ep->desc = NULL; - dev->out_ep->desc = NULL; - dev->interface = -1; -} - -/* change our operational config. must agree with the code - * that returns config descriptors, and altsetting code. - */ -static int -printer_set_config(struct printer_dev *dev, unsigned number) -{ - int result = 0; - struct usb_gadget *gadget = dev->gadget; - - switch (number) { - case DEV_CONFIG_VALUE: - result = 0; - break; - default: - result = -EINVAL; - /* FALL THROUGH */ - case 0: - break; - } - - if (result) { - usb_gadget_vbus_draw(dev->gadget, - dev->gadget->is_otg ? 8 : 100); - } else { - unsigned power; - - power = 2 * config_desc.bMaxPower; - usb_gadget_vbus_draw(dev->gadget, power); - - dev->config = number; - INFO(dev, "%s config #%d: %d mA, %s\n", - usb_speed_string(gadget->speed), - number, power, driver_desc); - } - return result; -} - -static int -config_buf(enum usb_device_speed speed, u8 *buf, u8 type, unsigned index, - int is_otg) -{ - int len; - const struct usb_descriptor_header **function; -#ifdef CONFIG_USB_GADGET_DUALSPEED - int hs = (speed == USB_SPEED_HIGH); - - if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; - - if (hs) { - function = hs_printer_function; - } else { - function = fs_printer_function; - } -#else - function = fs_printer_function; -#endif - - if (index >= device_desc.bNumConfigurations) - return -EINVAL; - - /* for now, don't advertise srp-only devices */ - if (!is_otg) - function++; - - len = usb_gadget_config_buf(&config_desc, buf, USB_DESC_BUFSIZE, - function); - if (len < 0) - return len; - ((struct usb_config_descriptor *) buf)->bDescriptorType = type; - return len; -} - -/* Change our operational Interface. */ -static int -set_interface(struct printer_dev *dev, unsigned number) -{ - int result = 0; - - /* Free the current interface */ - switch (dev->interface) { - case PRINTER_INTERFACE: - printer_reset_interface(dev); - break; - } - - switch (number) { - case PRINTER_INTERFACE: - result = set_printer_interface(dev); - if (result) { - printer_reset_interface(dev); - } else { - dev->interface = PRINTER_INTERFACE; - } - break; - default: - result = -EINVAL; - /* FALL THROUGH */ - } - - if (!result) - INFO(dev, "Using interface %x\n", number); - - return result; -} - -static void printer_setup_complete(struct usb_ep *ep, struct usb_request *req) -{ - if (req->status || req->actual != req->length) - DBG((struct printer_dev *) ep->driver_data, - "setup complete --> %d, %d/%d\n", - req->status, req->actual, req->length); -} - -static void printer_soft_reset(struct printer_dev *dev) -{ - struct usb_request *req; - - INFO(dev, "Received Printer Reset Request\n"); - - if (usb_ep_disable(dev->in_ep)) - DBG(dev, "Failed to disable USB in_ep\n"); - if (usb_ep_disable(dev->out_ep)) - DBG(dev, "Failed to disable USB out_ep\n"); - - if (dev->current_rx_req != NULL) { - list_add(&dev->current_rx_req->list, &dev->rx_reqs); - dev->current_rx_req = NULL; - } - dev->current_rx_bytes = 0; - dev->current_rx_buf = NULL; - dev->reset_printer = 1; - - while (likely(!(list_empty(&dev->rx_buffers)))) { - req = container_of(dev->rx_buffers.next, struct usb_request, - list); - list_del_init(&req->list); - list_add(&req->list, &dev->rx_reqs); - } - - while (likely(!(list_empty(&dev->rx_reqs_active)))) { - req = container_of(dev->rx_buffers.next, struct usb_request, - list); - list_del_init(&req->list); - list_add(&req->list, &dev->rx_reqs); - } - - while (likely(!(list_empty(&dev->tx_reqs_active)))) { - req = container_of(dev->tx_reqs_active.next, - struct usb_request, list); - list_del_init(&req->list); - list_add(&req->list, &dev->tx_reqs); - } - - if (usb_ep_enable(dev->in_ep)) - DBG(dev, "Failed to enable USB in_ep\n"); - if (usb_ep_enable(dev->out_ep)) - DBG(dev, "Failed to enable USB out_ep\n"); - - wake_up_interruptible(&dev->rx_wait); - wake_up_interruptible(&dev->tx_wait); - wake_up_interruptible(&dev->tx_flush_wait); -} - -/*-------------------------------------------------------------------------*/ - -/* - * The setup() callback implements all the ep0 functionality that's not - * handled lower down. - */ -static int -printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) -{ - struct printer_dev *dev = get_gadget_data(gadget); - struct usb_request *req = dev->req; - int value = -EOPNOTSUPP; - u16 wIndex = le16_to_cpu(ctrl->wIndex); - u16 wValue = le16_to_cpu(ctrl->wValue); - u16 wLength = le16_to_cpu(ctrl->wLength); - - DBG(dev, "ctrl req%02x.%02x v%04x i%04x l%d\n", - ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength); - - req->complete = printer_setup_complete; - - switch (ctrl->bRequestType&USB_TYPE_MASK) { - - case USB_TYPE_STANDARD: - switch (ctrl->bRequest) { - - case USB_REQ_GET_DESCRIPTOR: - if (ctrl->bRequestType != USB_DIR_IN) - break; - switch (wValue >> 8) { - - case USB_DT_DEVICE: - device_desc.bMaxPacketSize0 = - gadget->ep0->maxpacket; - value = min(wLength, (u16) sizeof device_desc); - memcpy(req->buf, &device_desc, value); - break; -#ifdef CONFIG_USB_GADGET_DUALSPEED - case USB_DT_DEVICE_QUALIFIER: - if (!gadget_is_dualspeed(gadget)) - break; - /* - * assumes ep0 uses the same value for both - * speeds - */ - dev_qualifier.bMaxPacketSize0 = - gadget->ep0->maxpacket; - value = min(wLength, - (u16) sizeof dev_qualifier); - memcpy(req->buf, &dev_qualifier, value); - break; - - case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget_is_dualspeed(gadget)) - break; - /* FALLTHROUGH */ -#endif /* CONFIG_USB_GADGET_DUALSPEED */ - case USB_DT_CONFIG: - value = config_buf(gadget->speed, req->buf, - wValue >> 8, - wValue & 0xff, - gadget->is_otg); - if (value >= 0) - value = min(wLength, (u16) value); - break; - - case USB_DT_STRING: - value = usb_gadget_get_string(&stringtab, - wValue & 0xff, req->buf); - if (value >= 0) - value = min(wLength, (u16) value); - break; - } - break; - - case USB_REQ_SET_CONFIGURATION: - if (ctrl->bRequestType != 0) - break; - if (gadget->a_hnp_support) - DBG(dev, "HNP available\n"); - else if (gadget->a_alt_hnp_support) - DBG(dev, "HNP needs a different root port\n"); - value = printer_set_config(dev, wValue); - if (!value) - value = set_interface(dev, PRINTER_INTERFACE); - break; - case USB_REQ_GET_CONFIGURATION: - if (ctrl->bRequestType != USB_DIR_IN) - break; - *(u8 *)req->buf = dev->config; - value = min(wLength, (u16) 1); - break; - - case USB_REQ_SET_INTERFACE: - if (ctrl->bRequestType != USB_RECIP_INTERFACE || - !dev->config) - break; - - value = set_interface(dev, PRINTER_INTERFACE); - break; - case USB_REQ_GET_INTERFACE: - if (ctrl->bRequestType != - (USB_DIR_IN|USB_RECIP_INTERFACE) - || !dev->config) - break; - - *(u8 *)req->buf = dev->interface; - value = min(wLength, (u16) 1); - break; - - default: - goto unknown; - } - break; - - case USB_TYPE_CLASS: - switch (ctrl->bRequest) { - case 0: /* Get the IEEE-1284 PNP String */ - /* Only one printer interface is supported. */ - if ((wIndex>>8) != PRINTER_INTERFACE) - break; - - value = (pnp_string[0]<<8)|pnp_string[1]; - memcpy(req->buf, pnp_string, value); - DBG(dev, "1284 PNP String: %x %s\n", value, - &pnp_string[2]); - break; - - case 1: /* Get Port Status */ - /* Only one printer interface is supported. */ - if (wIndex != PRINTER_INTERFACE) - break; - - *(u8 *)req->buf = dev->printer_status; - value = min(wLength, (u16) 1); - break; - - case 2: /* Soft Reset */ - /* Only one printer interface is supported. */ - if (wIndex != PRINTER_INTERFACE) - break; - - printer_soft_reset(dev); - - value = 0; - break; - - default: - goto unknown; - } - break; - - default: -unknown: - VDBG(dev, - "unknown ctrl req%02x.%02x v%04x i%04x l%d\n", - ctrl->bRequestType, ctrl->bRequest, - wValue, wIndex, wLength); - break; - } - - /* respond with data transfer before status phase? */ - if (value >= 0) { - req->length = value; - req->zero = value < wLength; - value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); - if (value < 0) { - DBG(dev, "ep_queue --> %d\n", value); - req->status = 0; - printer_setup_complete(gadget->ep0, req); - } - } - - /* host either stalls (value < 0) or reports success */ - return value; -} - -static void -printer_disconnect(struct usb_gadget *gadget) -{ - struct printer_dev *dev = get_gadget_data(gadget); - unsigned long flags; - - DBG(dev, "%s\n", __func__); - - spin_lock_irqsave(&dev->lock, flags); - - printer_reset_interface(dev); - - spin_unlock_irqrestore(&dev->lock, flags); -} - -static void -printer_unbind(struct usb_gadget *gadget) -{ - struct printer_dev *dev = get_gadget_data(gadget); - struct usb_request *req; - - - DBG(dev, "%s\n", __func__); - - /* Remove sysfs files */ - device_destroy(usb_gadget_class, g_printer_devno); - - /* Remove Character Device */ - cdev_del(&dev->printer_cdev); - - /* we must already have been disconnected ... no i/o may be active */ - WARN_ON(!list_empty(&dev->tx_reqs_active)); - WARN_ON(!list_empty(&dev->rx_reqs_active)); - - /* Free all memory for this driver. */ - while (!list_empty(&dev->tx_reqs)) { - req = container_of(dev->tx_reqs.next, struct usb_request, - list); - list_del(&req->list); - printer_req_free(dev->in_ep, req); - } - - if (dev->current_rx_req != NULL) - printer_req_free(dev->out_ep, dev->current_rx_req); - - while (!list_empty(&dev->rx_reqs)) { - req = container_of(dev->rx_reqs.next, - struct usb_request, list); - list_del(&req->list); - printer_req_free(dev->out_ep, req); - } - - while (!list_empty(&dev->rx_buffers)) { - req = container_of(dev->rx_buffers.next, - struct usb_request, list); - list_del(&req->list); - printer_req_free(dev->out_ep, req); - } - - if (dev->req) { - printer_req_free(gadget->ep0, dev->req); - dev->req = NULL; - } - - set_gadget_data(gadget, NULL); -} - -static int __init -printer_bind(struct usb_gadget *gadget) -{ - struct printer_dev *dev; - struct usb_ep *in_ep, *out_ep; - int status = -ENOMEM; - int gcnum; - size_t len; - u32 i; - struct usb_request *req; - - dev = &usb_printer_gadget; - - - /* Setup the sysfs files for the printer gadget. */ - dev->pdev = device_create(usb_gadget_class, NULL, g_printer_devno, - NULL, "g_printer"); - if (IS_ERR(dev->pdev)) { - ERROR(dev, "Failed to create device: g_printer\n"); - goto fail; - } - - /* - * Register a character device as an interface to a user mode - * program that handles the printer specific functionality. - */ - cdev_init(&dev->printer_cdev, &printer_io_operations); - dev->printer_cdev.owner = THIS_MODULE; - status = cdev_add(&dev->printer_cdev, g_printer_devno, 1); - if (status) { - ERROR(dev, "Failed to open char device\n"); - goto fail; - } - - gcnum = usb_gadget_controller_number(gadget); - if (gcnum >= 0) { - device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum); - } else { - dev_warn(&gadget->dev, "controller '%s' not recognized\n", - gadget->name); - /* unrecognized, but safe unless bulk is REALLY quirky */ - device_desc.bcdDevice = - cpu_to_le16(0xFFFF); - } - snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s", - init_utsname()->sysname, init_utsname()->release, - gadget->name); - - device_desc.idVendor = - cpu_to_le16(PRINTER_VENDOR_NUM); - device_desc.idProduct = - cpu_to_le16(PRINTER_PRODUCT_NUM); - - /* support optional vendor/distro customization */ - if (idVendor) { - if (!idProduct) { - dev_err(&gadget->dev, "idVendor needs idProduct!\n"); - return -ENODEV; - } - device_desc.idVendor = cpu_to_le16(idVendor); - device_desc.idProduct = cpu_to_le16(idProduct); - if (bcdDevice) - device_desc.bcdDevice = cpu_to_le16(bcdDevice); - } - - if (iManufacturer) - strlcpy(manufacturer, iManufacturer, sizeof manufacturer); - - if (iProduct) - strlcpy(product_desc, iProduct, sizeof product_desc); - - if (iSerialNum) - strlcpy(serial_num, iSerialNum, sizeof serial_num); - - if (iPNPstring) - strlcpy(&pnp_string[2], iPNPstring, (sizeof pnp_string)-2); - - len = strlen(pnp_string); - pnp_string[0] = (len >> 8) & 0xFF; - pnp_string[1] = len & 0xFF; - - /* all we really need is bulk IN/OUT */ - usb_ep_autoconfig_reset(gadget); - in_ep = usb_ep_autoconfig(gadget, &fs_ep_in_desc); - if (!in_ep) { -autoconf_fail: - dev_err(&gadget->dev, "can't autoconfigure on %s\n", - gadget->name); - return -ENODEV; - } - in_ep->driver_data = in_ep; /* claim */ - - out_ep = usb_ep_autoconfig(gadget, &fs_ep_out_desc); - if (!out_ep) - goto autoconf_fail; - out_ep->driver_data = out_ep; /* claim */ - -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* assumes that all endpoints are dual-speed */ - hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress; - hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress; -#endif /* DUALSPEED */ - - usb_gadget_set_selfpowered(gadget); - - if (gadget->is_otg) { - otg_desc.bmAttributes |= USB_OTG_HNP, - config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; - } - - spin_lock_init(&dev->lock); - mutex_init(&dev->lock_printer_io); - INIT_LIST_HEAD(&dev->tx_reqs); - INIT_LIST_HEAD(&dev->tx_reqs_active); - INIT_LIST_HEAD(&dev->rx_reqs); - INIT_LIST_HEAD(&dev->rx_reqs_active); - INIT_LIST_HEAD(&dev->rx_buffers); - init_waitqueue_head(&dev->rx_wait); - init_waitqueue_head(&dev->tx_wait); - init_waitqueue_head(&dev->tx_flush_wait); - - dev->config = 0; - dev->interface = -1; - dev->printer_cdev_open = 0; - dev->printer_status = PRINTER_NOT_ERROR; - dev->current_rx_req = NULL; - dev->current_rx_bytes = 0; - dev->current_rx_buf = NULL; - - dev->in_ep = in_ep; - dev->out_ep = out_ep; - - /* preallocate control message data and buffer */ - dev->req = printer_req_alloc(gadget->ep0, USB_DESC_BUFSIZE, - GFP_KERNEL); - if (!dev->req) { - status = -ENOMEM; - goto fail; - } - - for (i = 0; i < QLEN; i++) { - req = printer_req_alloc(dev->in_ep, USB_BUFSIZE, GFP_KERNEL); - if (!req) { - while (!list_empty(&dev->tx_reqs)) { - req = container_of(dev->tx_reqs.next, - struct usb_request, list); - list_del(&req->list); - printer_req_free(dev->in_ep, req); - } - return -ENOMEM; - } - list_add(&req->list, &dev->tx_reqs); - } - - for (i = 0; i < QLEN; i++) { - req = printer_req_alloc(dev->out_ep, USB_BUFSIZE, GFP_KERNEL); - if (!req) { - while (!list_empty(&dev->rx_reqs)) { - req = container_of(dev->rx_reqs.next, - struct usb_request, list); - list_del(&req->list); - printer_req_free(dev->out_ep, req); - } - return -ENOMEM; - } - list_add(&req->list, &dev->rx_reqs); - } - - dev->req->complete = printer_setup_complete; - - /* finish hookup to lower layer ... */ - dev->gadget = gadget; - set_gadget_data(gadget, dev); - gadget->ep0->driver_data = dev; - - INFO(dev, "%s, version: " DRIVER_VERSION "\n", driver_desc); - INFO(dev, "using %s, OUT %s IN %s\n", gadget->name, out_ep->name, - in_ep->name); - - return 0; - -fail: - printer_unbind(gadget); - return status; -} - -/*-------------------------------------------------------------------------*/ - -static struct usb_gadget_driver printer_driver = { - .max_speed = DEVSPEED, - - .function = (char *) driver_desc, - .unbind = printer_unbind, - - .setup = printer_setup, - .disconnect = printer_disconnect, - - .driver = { - .name = (char *) shortname, - .owner = THIS_MODULE, - }, -}; - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Craig Nadler"); -MODULE_LICENSE("GPL"); - -static int __init -init(void) -{ - int status; - - usb_gadget_class = class_create(THIS_MODULE, "usb_printer_gadget"); - if (IS_ERR(usb_gadget_class)) { - status = PTR_ERR(usb_gadget_class); - ERROR(dev, "unable to create usb_gadget class %d\n", status); - return status; - } - - status = alloc_chrdev_region(&g_printer_devno, 0, 1, - "USB printer gadget"); - if (status) { - ERROR(dev, "alloc_chrdev_region %d\n", status); - class_destroy(usb_gadget_class); - return status; - } - - status = usb_gadget_probe_driver(&printer_driver, printer_bind); - if (status) { - class_destroy(usb_gadget_class); - unregister_chrdev_region(g_printer_devno, 1); - DBG(dev, "usb_gadget_probe_driver %x\n", status); - } - - return status; -} -module_init(init); - -static void __exit -cleanup(void) -{ - int status; - - mutex_lock(&usb_printer_gadget.lock_printer_io); - status = usb_gadget_unregister_driver(&printer_driver); - if (status) - ERROR(dev, "usb_gadget_unregister_driver %x\n", status); - - unregister_chrdev_region(g_printer_devno, 1); - class_destroy(usb_gadget_class); - mutex_unlock(&usb_printer_gadget.lock_printer_io); -} -module_exit(cleanup); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/pxa25x_udc.c b/ANDROID_3.4.5/drivers/usb/gadget/pxa25x_udc.c deleted file mode 100644 index 41ed69c9..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/pxa25x_udc.c +++ /dev/null @@ -1,2373 +0,0 @@ -/* - * Intel PXA25x and IXP4xx on-chip full speed USB device controllers - * - * Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker) - * Copyright (C) 2003 Robert Schwebel, Pengutronix - * Copyright (C) 2003 Benedikt Spranger, Pengutronix - * Copyright (C) 2003 David Brownell - * Copyright (C) 2003 Joshua Wise - * - * 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. - */ - -/* #define VERBOSE_DEBUG */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -/* - * This driver is PXA25x only. Grab the right register definitions. - */ -#ifdef CONFIG_ARCH_PXA -#include -#endif - -#ifdef CONFIG_ARCH_LUBBOCK -#include -#endif - -#include - - -/* - * This driver handles the USB Device Controller (UDC) in Intel's PXA 25x - * series processors. The UDC for the IXP 4xx series is very similar. - * There are fifteen endpoints, in addition to ep0. - * - * Such controller drivers work with a gadget driver. The gadget driver - * returns descriptors, implements configuration and data protocols used - * by the host to interact with this device, and allocates endpoints to - * the different protocol interfaces. The controller driver virtualizes - * usb hardware so that the gadget drivers will be more portable. - * - * This UDC hardware wants to implement a bit too much USB protocol, so - * it constrains the sorts of USB configuration change events that work. - * The errata for these chips are misleading; some "fixed" bugs from - * pxa250 a0/a1 b0/b1/b2 sure act like they're still there. - * - * Note that the UDC hardware supports DMA (except on IXP) but that's - * not used here. IN-DMA (to host) is simple enough, when the data is - * suitably aligned (16 bytes) ... the network stack doesn't do that, - * other software can. OUT-DMA is buggy in most chip versions, as well - * as poorly designed (data toggle not automatic). So this driver won't - * bother using DMA. (Mostly-working IN-DMA support was available in - * kernels before 2.6.23, but was never enabled or well tested.) - */ - -#define DRIVER_VERSION "30-June-2007" -#define DRIVER_DESC "PXA 25x USB Device Controller driver" - - -static const char driver_name [] = "pxa25x_udc"; - -static const char ep0name [] = "ep0"; - - -#ifdef CONFIG_ARCH_IXP4XX - -/* cpu-specific register addresses are compiled in to this code */ -#ifdef CONFIG_ARCH_PXA -#error "Can't configure both IXP and PXA" -#endif - -/* IXP doesn't yet support */ -#define clk_get(dev,name) NULL -#define clk_enable(clk) do { } while (0) -#define clk_disable(clk) do { } while (0) -#define clk_put(clk) do { } while (0) - -#endif - -#include "pxa25x_udc.h" - - -#ifdef CONFIG_USB_PXA25X_SMALL -#define SIZE_STR " (small)" -#else -#define SIZE_STR "" -#endif - -/* --------------------------------------------------------------------------- - * endpoint related parts of the api to the usb controller hardware, - * used by gadget driver; and the inner talker-to-hardware core. - * --------------------------------------------------------------------------- - */ - -static void pxa25x_ep_fifo_flush (struct usb_ep *ep); -static void nuke (struct pxa25x_ep *, int status); - -/* one GPIO should control a D+ pullup, so host sees this device (or not) */ -static void pullup_off(void) -{ - struct pxa2xx_udc_mach_info *mach = the_controller->mach; - int off_level = mach->gpio_pullup_inverted; - - if (gpio_is_valid(mach->gpio_pullup)) - gpio_set_value(mach->gpio_pullup, off_level); - else if (mach->udc_command) - mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); -} - -static void pullup_on(void) -{ - struct pxa2xx_udc_mach_info *mach = the_controller->mach; - int on_level = !mach->gpio_pullup_inverted; - - if (gpio_is_valid(mach->gpio_pullup)) - gpio_set_value(mach->gpio_pullup, on_level); - else if (mach->udc_command) - mach->udc_command(PXA2XX_UDC_CMD_CONNECT); -} - -static void pio_irq_enable(int bEndpointAddress) -{ - bEndpointAddress &= 0xf; - if (bEndpointAddress < 8) - UICR0 &= ~(1 << bEndpointAddress); - else { - bEndpointAddress -= 8; - UICR1 &= ~(1 << bEndpointAddress); - } -} - -static void pio_irq_disable(int bEndpointAddress) -{ - bEndpointAddress &= 0xf; - if (bEndpointAddress < 8) - UICR0 |= 1 << bEndpointAddress; - else { - bEndpointAddress -= 8; - UICR1 |= 1 << bEndpointAddress; - } -} - -/* The UDCCR reg contains mask and interrupt status bits, - * so using '|=' isn't safe as it may ack an interrupt. - */ -#define UDCCR_MASK_BITS (UDCCR_REM | UDCCR_SRM | UDCCR_UDE) - -static inline void udc_set_mask_UDCCR(int mask) -{ - UDCCR = (UDCCR & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS); -} - -static inline void udc_clear_mask_UDCCR(int mask) -{ - UDCCR = (UDCCR & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS); -} - -static inline void udc_ack_int_UDCCR(int mask) -{ - /* udccr contains the bits we dont want to change */ - __u32 udccr = UDCCR & UDCCR_MASK_BITS; - - UDCCR = udccr | (mask & ~UDCCR_MASK_BITS); -} - -/* - * endpoint enable/disable - * - * we need to verify the descriptors used to enable endpoints. since pxa25x - * endpoint configurations are fixed, and are pretty much always enabled, - * there's not a lot to manage here. - * - * because pxa25x can't selectively initialize bulk (or interrupt) endpoints, - * (resetting endpoint halt and toggle), SET_INTERFACE is unusable except - * for a single interface (with only the default altsetting) and for gadget - * drivers that don't halt endpoints (not reset by set_interface). that also - * means that if you use ISO, you must violate the USB spec rule that all - * iso endpoints must be in non-default altsettings. - */ -static int pxa25x_ep_enable (struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct pxa25x_ep *ep; - struct pxa25x_udc *dev; - - ep = container_of (_ep, struct pxa25x_ep, ep); - if (!_ep || !desc || ep->desc || _ep->name == ep0name - || desc->bDescriptorType != USB_DT_ENDPOINT - || ep->bEndpointAddress != desc->bEndpointAddress - || ep->fifo_size < usb_endpoint_maxp (desc)) { - DMSG("%s, bad ep or descriptor\n", __func__); - return -EINVAL; - } - - /* xfer types must match, except that interrupt ~= bulk */ - if (ep->bmAttributes != desc->bmAttributes - && ep->bmAttributes != USB_ENDPOINT_XFER_BULK - && desc->bmAttributes != USB_ENDPOINT_XFER_INT) { - DMSG("%s, %s type mismatch\n", __func__, _ep->name); - return -EINVAL; - } - - /* hardware _could_ do smaller, but driver doesn't */ - if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK - && usb_endpoint_maxp (desc) - != BULK_FIFO_SIZE) - || !desc->wMaxPacketSize) { - DMSG("%s, bad %s maxpacket\n", __func__, _ep->name); - return -ERANGE; - } - - dev = ep->dev; - if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { - DMSG("%s, bogus device state\n", __func__); - return -ESHUTDOWN; - } - - ep->desc = desc; - ep->stopped = 0; - ep->pio_irqs = 0; - ep->ep.maxpacket = usb_endpoint_maxp (desc); - - /* flush fifo (mostly for OUT buffers) */ - pxa25x_ep_fifo_flush (_ep); - - /* ... reset halt state too, if we could ... */ - - DBG(DBG_VERBOSE, "enabled %s\n", _ep->name); - return 0; -} - -static int pxa25x_ep_disable (struct usb_ep *_ep) -{ - struct pxa25x_ep *ep; - unsigned long flags; - - ep = container_of (_ep, struct pxa25x_ep, ep); - if (!_ep || !ep->desc) { - DMSG("%s, %s not enabled\n", __func__, - _ep ? ep->ep.name : NULL); - return -EINVAL; - } - local_irq_save(flags); - - nuke (ep, -ESHUTDOWN); - - /* flush fifo (mostly for IN buffers) */ - pxa25x_ep_fifo_flush (_ep); - - ep->desc = NULL; - ep->ep.desc = NULL; - ep->stopped = 1; - - local_irq_restore(flags); - DBG(DBG_VERBOSE, "%s disabled\n", _ep->name); - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* for the pxa25x, these can just wrap kmalloc/kfree. gadget drivers - * must still pass correctly initialized endpoints, since other controller - * drivers may care about how it's currently set up (dma issues etc). - */ - -/* - * pxa25x_ep_alloc_request - allocate a request data structure - */ -static struct usb_request * -pxa25x_ep_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags) -{ - struct pxa25x_request *req; - - req = kzalloc(sizeof(*req), gfp_flags); - if (!req) - return NULL; - - INIT_LIST_HEAD (&req->queue); - return &req->req; -} - - -/* - * pxa25x_ep_free_request - deallocate a request data structure - */ -static void -pxa25x_ep_free_request (struct usb_ep *_ep, struct usb_request *_req) -{ - struct pxa25x_request *req; - - req = container_of (_req, struct pxa25x_request, req); - WARN_ON(!list_empty (&req->queue)); - kfree(req); -} - -/*-------------------------------------------------------------------------*/ - -/* - * done - retire a request; caller blocked irqs - */ -static void done(struct pxa25x_ep *ep, struct pxa25x_request *req, int status) -{ - unsigned stopped = ep->stopped; - - list_del_init(&req->queue); - - if (likely (req->req.status == -EINPROGRESS)) - req->req.status = status; - else - status = req->req.status; - - if (status && status != -ESHUTDOWN) - DBG(DBG_VERBOSE, "complete %s req %p stat %d len %u/%u\n", - ep->ep.name, &req->req, status, - req->req.actual, req->req.length); - - /* don't modify queue heads during completion callback */ - ep->stopped = 1; - req->req.complete(&ep->ep, &req->req); - ep->stopped = stopped; -} - - -static inline void ep0_idle (struct pxa25x_udc *dev) -{ - dev->ep0state = EP0_IDLE; -} - -static int -write_packet(volatile u32 *uddr, struct pxa25x_request *req, unsigned max) -{ - u8 *buf; - unsigned length, count; - - buf = req->req.buf + req->req.actual; - prefetch(buf); - - /* how big will this packet be? */ - length = min(req->req.length - req->req.actual, max); - req->req.actual += length; - - count = length; - while (likely(count--)) - *uddr = *buf++; - - return length; -} - -/* - * write to an IN endpoint fifo, as many packets as possible. - * irqs will use this to write the rest later. - * caller guarantees at least one packet buffer is ready (or a zlp). - */ -static int -write_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req) -{ - unsigned max; - - max = usb_endpoint_maxp(ep->desc); - do { - unsigned count; - int is_last, is_short; - - count = write_packet(ep->reg_uddr, req, max); - - /* last packet is usually short (or a zlp) */ - if (unlikely (count != max)) - is_last = is_short = 1; - else { - if (likely(req->req.length != req->req.actual) - || req->req.zero) - is_last = 0; - else - is_last = 1; - /* interrupt/iso maxpacket may not fill the fifo */ - is_short = unlikely (max < ep->fifo_size); - } - - DBG(DBG_VERY_NOISY, "wrote %s %d bytes%s%s %d left %p\n", - ep->ep.name, count, - is_last ? "/L" : "", is_short ? "/S" : "", - req->req.length - req->req.actual, req); - - /* let loose that packet. maybe try writing another one, - * double buffering might work. TSP, TPC, and TFS - * bit values are the same for all normal IN endpoints. - */ - *ep->reg_udccs = UDCCS_BI_TPC; - if (is_short) - *ep->reg_udccs = UDCCS_BI_TSP; - - /* requests complete when all IN data is in the FIFO */ - if (is_last) { - done (ep, req, 0); - if (list_empty(&ep->queue)) - pio_irq_disable (ep->bEndpointAddress); - return 1; - } - - // TODO experiment: how robust can fifo mode tweaking be? - // double buffering is off in the default fifo mode, which - // prevents TFS from being set here. - - } while (*ep->reg_udccs & UDCCS_BI_TFS); - return 0; -} - -/* caller asserts req->pending (ep0 irq status nyet cleared); starts - * ep0 data stage. these chips want very simple state transitions. - */ -static inline -void ep0start(struct pxa25x_udc *dev, u32 flags, const char *tag) -{ - UDCCS0 = flags|UDCCS0_SA|UDCCS0_OPR; - USIR0 = USIR0_IR0; - dev->req_pending = 0; - DBG(DBG_VERY_NOISY, "%s %s, %02x/%02x\n", - __func__, tag, UDCCS0, flags); -} - -static int -write_ep0_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req) -{ - unsigned count; - int is_short; - - count = write_packet(&UDDR0, req, EP0_FIFO_SIZE); - ep->dev->stats.write.bytes += count; - - /* last packet "must be" short (or a zlp) */ - is_short = (count != EP0_FIFO_SIZE); - - DBG(DBG_VERY_NOISY, "ep0in %d bytes %d left %p\n", count, - req->req.length - req->req.actual, req); - - if (unlikely (is_short)) { - if (ep->dev->req_pending) - ep0start(ep->dev, UDCCS0_IPR, "short IN"); - else - UDCCS0 = UDCCS0_IPR; - - count = req->req.length; - done (ep, req, 0); - ep0_idle(ep->dev); -#ifndef CONFIG_ARCH_IXP4XX -#if 1 - /* This seems to get rid of lost status irqs in some cases: - * host responds quickly, or next request involves config - * change automagic, or should have been hidden, or ... - * - * FIXME get rid of all udelays possible... - */ - if (count >= EP0_FIFO_SIZE) { - count = 100; - do { - if ((UDCCS0 & UDCCS0_OPR) != 0) { - /* clear OPR, generate ack */ - UDCCS0 = UDCCS0_OPR; - break; - } - count--; - udelay(1); - } while (count); - } -#endif -#endif - } else if (ep->dev->req_pending) - ep0start(ep->dev, 0, "IN"); - return is_short; -} - - -/* - * read_fifo - unload packet(s) from the fifo we use for usb OUT - * transfers and put them into the request. caller should have made - * sure there's at least one packet ready. - * - * returns true if the request completed because of short packet or the - * request buffer having filled (and maybe overran till end-of-packet). - */ -static int -read_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req) -{ - for (;;) { - u32 udccs; - u8 *buf; - unsigned bufferspace, count, is_short; - - /* make sure there's a packet in the FIFO. - * UDCCS_{BO,IO}_RPC are all the same bit value. - * UDCCS_{BO,IO}_RNE are all the same bit value. - */ - udccs = *ep->reg_udccs; - if (unlikely ((udccs & UDCCS_BO_RPC) == 0)) - break; - buf = req->req.buf + req->req.actual; - prefetchw(buf); - bufferspace = req->req.length - req->req.actual; - - /* read all bytes from this packet */ - if (likely (udccs & UDCCS_BO_RNE)) { - count = 1 + (0x0ff & *ep->reg_ubcr); - req->req.actual += min (count, bufferspace); - } else /* zlp */ - count = 0; - is_short = (count < ep->ep.maxpacket); - DBG(DBG_VERY_NOISY, "read %s %02x, %d bytes%s req %p %d/%d\n", - ep->ep.name, udccs, count, - is_short ? "/S" : "", - req, req->req.actual, req->req.length); - while (likely (count-- != 0)) { - u8 byte = (u8) *ep->reg_uddr; - - if (unlikely (bufferspace == 0)) { - /* this happens when the driver's buffer - * is smaller than what the host sent. - * discard the extra data. - */ - if (req->req.status != -EOVERFLOW) - DMSG("%s overflow %d\n", - ep->ep.name, count); - req->req.status = -EOVERFLOW; - } else { - *buf++ = byte; - bufferspace--; - } - } - *ep->reg_udccs = UDCCS_BO_RPC; - /* RPC/RSP/RNE could now reflect the other packet buffer */ - - /* iso is one request per packet */ - if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) { - if (udccs & UDCCS_IO_ROF) - req->req.status = -EHOSTUNREACH; - /* more like "is_done" */ - is_short = 1; - } - - /* completion */ - if (is_short || req->req.actual == req->req.length) { - done (ep, req, 0); - if (list_empty(&ep->queue)) - pio_irq_disable (ep->bEndpointAddress); - return 1; - } - - /* finished that packet. the next one may be waiting... */ - } - return 0; -} - -/* - * special ep0 version of the above. no UBCR0 or double buffering; status - * handshaking is magic. most device protocols don't need control-OUT. - * CDC vendor commands (and RNDIS), mass storage CB/CBI, and some other - * protocols do use them. - */ -static int -read_ep0_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req) -{ - u8 *buf, byte; - unsigned bufferspace; - - buf = req->req.buf + req->req.actual; - bufferspace = req->req.length - req->req.actual; - - while (UDCCS0 & UDCCS0_RNE) { - byte = (u8) UDDR0; - - if (unlikely (bufferspace == 0)) { - /* this happens when the driver's buffer - * is smaller than what the host sent. - * discard the extra data. - */ - if (req->req.status != -EOVERFLOW) - DMSG("%s overflow\n", ep->ep.name); - req->req.status = -EOVERFLOW; - } else { - *buf++ = byte; - req->req.actual++; - bufferspace--; - } - } - - UDCCS0 = UDCCS0_OPR | UDCCS0_IPR; - - /* completion */ - if (req->req.actual >= req->req.length) - return 1; - - /* finished that packet. the next one may be waiting... */ - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static int -pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) -{ - struct pxa25x_request *req; - struct pxa25x_ep *ep; - struct pxa25x_udc *dev; - unsigned long flags; - - req = container_of(_req, struct pxa25x_request, req); - if (unlikely (!_req || !_req->complete || !_req->buf - || !list_empty(&req->queue))) { - DMSG("%s, bad params\n", __func__); - return -EINVAL; - } - - ep = container_of(_ep, struct pxa25x_ep, ep); - if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) { - DMSG("%s, bad ep\n", __func__); - return -EINVAL; - } - - dev = ep->dev; - if (unlikely (!dev->driver - || dev->gadget.speed == USB_SPEED_UNKNOWN)) { - DMSG("%s, bogus device state\n", __func__); - return -ESHUTDOWN; - } - - /* iso is always one packet per request, that's the only way - * we can report per-packet status. that also helps with dma. - */ - if (unlikely (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC - && req->req.length > usb_endpoint_maxp (ep->desc))) - return -EMSGSIZE; - - DBG(DBG_NOISY, "%s queue req %p, len %d buf %p\n", - _ep->name, _req, _req->length, _req->buf); - - local_irq_save(flags); - - _req->status = -EINPROGRESS; - _req->actual = 0; - - /* kickstart this i/o queue? */ - if (list_empty(&ep->queue) && !ep->stopped) { - if (ep->desc == NULL/* ep0 */) { - unsigned length = _req->length; - - switch (dev->ep0state) { - case EP0_IN_DATA_PHASE: - dev->stats.write.ops++; - if (write_ep0_fifo(ep, req)) - req = NULL; - break; - - case EP0_OUT_DATA_PHASE: - dev->stats.read.ops++; - /* messy ... */ - if (dev->req_config) { - DBG(DBG_VERBOSE, "ep0 config ack%s\n", - dev->has_cfr ? "" : " raced"); - if (dev->has_cfr) - UDCCFR = UDCCFR_AREN|UDCCFR_ACM - |UDCCFR_MB1; - done(ep, req, 0); - dev->ep0state = EP0_END_XFER; - local_irq_restore (flags); - return 0; - } - if (dev->req_pending) - ep0start(dev, UDCCS0_IPR, "OUT"); - if (length == 0 || ((UDCCS0 & UDCCS0_RNE) != 0 - && read_ep0_fifo(ep, req))) { - ep0_idle(dev); - done(ep, req, 0); - req = NULL; - } - break; - - default: - DMSG("ep0 i/o, odd state %d\n", dev->ep0state); - local_irq_restore (flags); - return -EL2HLT; - } - /* can the FIFO can satisfy the request immediately? */ - } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) { - if ((*ep->reg_udccs & UDCCS_BI_TFS) != 0 - && write_fifo(ep, req)) - req = NULL; - } else if ((*ep->reg_udccs & UDCCS_BO_RFS) != 0 - && read_fifo(ep, req)) { - req = NULL; - } - - if (likely (req && ep->desc)) - pio_irq_enable(ep->bEndpointAddress); - } - - /* pio or dma irq handler advances the queue. */ - if (likely(req != NULL)) - list_add_tail(&req->queue, &ep->queue); - local_irq_restore(flags); - - return 0; -} - - -/* - * nuke - dequeue ALL requests - */ -static void nuke(struct pxa25x_ep *ep, int status) -{ - struct pxa25x_request *req; - - /* called with irqs blocked */ - while (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, - struct pxa25x_request, - queue); - done(ep, req, status); - } - if (ep->desc) - pio_irq_disable (ep->bEndpointAddress); -} - - -/* dequeue JUST ONE request */ -static int pxa25x_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct pxa25x_ep *ep; - struct pxa25x_request *req; - unsigned long flags; - - ep = container_of(_ep, struct pxa25x_ep, ep); - if (!_ep || ep->ep.name == ep0name) - return -EINVAL; - - local_irq_save(flags); - - /* make sure it's actually queued on this endpoint */ - list_for_each_entry (req, &ep->queue, queue) { - if (&req->req == _req) - break; - } - if (&req->req != _req) { - local_irq_restore(flags); - return -EINVAL; - } - - done(ep, req, -ECONNRESET); - - local_irq_restore(flags); - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static int pxa25x_ep_set_halt(struct usb_ep *_ep, int value) -{ - struct pxa25x_ep *ep; - unsigned long flags; - - ep = container_of(_ep, struct pxa25x_ep, ep); - if (unlikely (!_ep - || (!ep->desc && ep->ep.name != ep0name)) - || ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) { - DMSG("%s, bad ep\n", __func__); - return -EINVAL; - } - if (value == 0) { - /* this path (reset toggle+halt) is needed to implement - * SET_INTERFACE on normal hardware. but it can't be - * done from software on the PXA UDC, and the hardware - * forgets to do it as part of SET_INTERFACE automagic. - */ - DMSG("only host can clear %s halt\n", _ep->name); - return -EROFS; - } - - local_irq_save(flags); - - if ((ep->bEndpointAddress & USB_DIR_IN) != 0 - && ((*ep->reg_udccs & UDCCS_BI_TFS) == 0 - || !list_empty(&ep->queue))) { - local_irq_restore(flags); - return -EAGAIN; - } - - /* FST bit is the same for control, bulk in, bulk out, interrupt in */ - *ep->reg_udccs = UDCCS_BI_FST|UDCCS_BI_FTF; - - /* ep0 needs special care */ - if (!ep->desc) { - start_watchdog(ep->dev); - ep->dev->req_pending = 0; - ep->dev->ep0state = EP0_STALL; - - /* and bulk/intr endpoints like dropping stalls too */ - } else { - unsigned i; - for (i = 0; i < 1000; i += 20) { - if (*ep->reg_udccs & UDCCS_BI_SST) - break; - udelay(20); - } - } - local_irq_restore(flags); - - DBG(DBG_VERBOSE, "%s halt\n", _ep->name); - return 0; -} - -static int pxa25x_ep_fifo_status(struct usb_ep *_ep) -{ - struct pxa25x_ep *ep; - - ep = container_of(_ep, struct pxa25x_ep, ep); - if (!_ep) { - DMSG("%s, bad ep\n", __func__); - return -ENODEV; - } - /* pxa can't report unclaimed bytes from IN fifos */ - if ((ep->bEndpointAddress & USB_DIR_IN) != 0) - return -EOPNOTSUPP; - if (ep->dev->gadget.speed == USB_SPEED_UNKNOWN - || (*ep->reg_udccs & UDCCS_BO_RFS) == 0) - return 0; - else - return (*ep->reg_ubcr & 0xfff) + 1; -} - -static void pxa25x_ep_fifo_flush(struct usb_ep *_ep) -{ - struct pxa25x_ep *ep; - - ep = container_of(_ep, struct pxa25x_ep, ep); - if (!_ep || ep->ep.name == ep0name || !list_empty(&ep->queue)) { - DMSG("%s, bad ep\n", __func__); - return; - } - - /* toggle and halt bits stay unchanged */ - - /* for OUT, just read and discard the FIFO contents. */ - if ((ep->bEndpointAddress & USB_DIR_IN) == 0) { - while (((*ep->reg_udccs) & UDCCS_BO_RNE) != 0) - (void) *ep->reg_uddr; - return; - } - - /* most IN status is the same, but ISO can't stall */ - *ep->reg_udccs = UDCCS_BI_TPC|UDCCS_BI_FTF|UDCCS_BI_TUR - | (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC - ? 0 : UDCCS_BI_SST); -} - - -static struct usb_ep_ops pxa25x_ep_ops = { - .enable = pxa25x_ep_enable, - .disable = pxa25x_ep_disable, - - .alloc_request = pxa25x_ep_alloc_request, - .free_request = pxa25x_ep_free_request, - - .queue = pxa25x_ep_queue, - .dequeue = pxa25x_ep_dequeue, - - .set_halt = pxa25x_ep_set_halt, - .fifo_status = pxa25x_ep_fifo_status, - .fifo_flush = pxa25x_ep_fifo_flush, -}; - - -/* --------------------------------------------------------------------------- - * device-scoped parts of the api to the usb controller hardware - * --------------------------------------------------------------------------- - */ - -static int pxa25x_udc_get_frame(struct usb_gadget *_gadget) -{ - return ((UFNRH & 0x07) << 8) | (UFNRL & 0xff); -} - -static int pxa25x_udc_wakeup(struct usb_gadget *_gadget) -{ - /* host may not have enabled remote wakeup */ - if ((UDCCS0 & UDCCS0_DRWF) == 0) - return -EHOSTUNREACH; - udc_set_mask_UDCCR(UDCCR_RSM); - return 0; -} - -static void stop_activity(struct pxa25x_udc *, struct usb_gadget_driver *); -static void udc_enable (struct pxa25x_udc *); -static void udc_disable(struct pxa25x_udc *); - -/* We disable the UDC -- and its 48 MHz clock -- whenever it's not - * in active use. - */ -static int pullup(struct pxa25x_udc *udc) -{ - int is_active = udc->vbus && udc->pullup && !udc->suspended; - DMSG("%s\n", is_active ? "active" : "inactive"); - if (is_active) { - if (!udc->active) { - udc->active = 1; - /* Enable clock for USB device */ - clk_enable(udc->clk); - udc_enable(udc); - } - } else { - if (udc->active) { - if (udc->gadget.speed != USB_SPEED_UNKNOWN) { - DMSG("disconnect %s\n", udc->driver - ? udc->driver->driver.name - : "(no driver)"); - stop_activity(udc, udc->driver); - } - udc_disable(udc); - /* Disable clock for USB device */ - clk_disable(udc->clk); - udc->active = 0; - } - - } - return 0; -} - -/* VBUS reporting logically comes from a transceiver */ -static int pxa25x_udc_vbus_session(struct usb_gadget *_gadget, int is_active) -{ - struct pxa25x_udc *udc; - - udc = container_of(_gadget, struct pxa25x_udc, gadget); - udc->vbus = is_active; - DMSG("vbus %s\n", is_active ? "supplied" : "inactive"); - pullup(udc); - return 0; -} - -/* drivers may have software control over D+ pullup */ -static int pxa25x_udc_pullup(struct usb_gadget *_gadget, int is_active) -{ - struct pxa25x_udc *udc; - - udc = container_of(_gadget, struct pxa25x_udc, gadget); - - /* not all boards support pullup control */ - if (!gpio_is_valid(udc->mach->gpio_pullup) && !udc->mach->udc_command) - return -EOPNOTSUPP; - - udc->pullup = (is_active != 0); - pullup(udc); - return 0; -} - -/* boards may consume current from VBUS, up to 100-500mA based on config. - * the 500uA suspend ceiling means that exclusively vbus-powered PXA designs - * violate USB specs. - */ -static int pxa25x_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA) -{ - struct pxa25x_udc *udc; - - udc = container_of(_gadget, struct pxa25x_udc, gadget); - - if (udc->transceiver) - return usb_phy_set_power(udc->transceiver, mA); - return -EOPNOTSUPP; -} - -static int pxa25x_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int pxa25x_stop(struct usb_gadget_driver *driver); - -static const struct usb_gadget_ops pxa25x_udc_ops = { - .get_frame = pxa25x_udc_get_frame, - .wakeup = pxa25x_udc_wakeup, - .vbus_session = pxa25x_udc_vbus_session, - .pullup = pxa25x_udc_pullup, - .vbus_draw = pxa25x_udc_vbus_draw, - .start = pxa25x_start, - .stop = pxa25x_stop, -}; - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_USB_GADGET_DEBUG_FS - -static int -udc_seq_show(struct seq_file *m, void *_d) -{ - struct pxa25x_udc *dev = m->private; - unsigned long flags; - int i; - u32 tmp; - - local_irq_save(flags); - - /* basic device status */ - seq_printf(m, DRIVER_DESC "\n" - "%s version: %s\nGadget driver: %s\nHost %s\n\n", - driver_name, DRIVER_VERSION SIZE_STR "(pio)", - dev->driver ? dev->driver->driver.name : "(none)", - dev->gadget.speed == USB_SPEED_FULL ? "full speed" : "disconnected"); - - /* registers for device and ep0 */ - seq_printf(m, - "uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n", - UICR1, UICR0, USIR1, USIR0, UFNRH, UFNRL); - - tmp = UDCCR; - seq_printf(m, - "udccr %02X =%s%s%s%s%s%s%s%s\n", tmp, - (tmp & UDCCR_REM) ? " rem" : "", - (tmp & UDCCR_RSTIR) ? " rstir" : "", - (tmp & UDCCR_SRM) ? " srm" : "", - (tmp & UDCCR_SUSIR) ? " susir" : "", - (tmp & UDCCR_RESIR) ? " resir" : "", - (tmp & UDCCR_RSM) ? " rsm" : "", - (tmp & UDCCR_UDA) ? " uda" : "", - (tmp & UDCCR_UDE) ? " ude" : ""); - - tmp = UDCCS0; - seq_printf(m, - "udccs0 %02X =%s%s%s%s%s%s%s%s\n", tmp, - (tmp & UDCCS0_SA) ? " sa" : "", - (tmp & UDCCS0_RNE) ? " rne" : "", - (tmp & UDCCS0_FST) ? " fst" : "", - (tmp & UDCCS0_SST) ? " sst" : "", - (tmp & UDCCS0_DRWF) ? " dwrf" : "", - (tmp & UDCCS0_FTF) ? " ftf" : "", - (tmp & UDCCS0_IPR) ? " ipr" : "", - (tmp & UDCCS0_OPR) ? " opr" : ""); - - if (dev->has_cfr) { - tmp = UDCCFR; - seq_printf(m, - "udccfr %02X =%s%s\n", tmp, - (tmp & UDCCFR_AREN) ? " aren" : "", - (tmp & UDCCFR_ACM) ? " acm" : ""); - } - - if (dev->gadget.speed != USB_SPEED_FULL || !dev->driver) - goto done; - - seq_printf(m, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n", - dev->stats.write.bytes, dev->stats.write.ops, - dev->stats.read.bytes, dev->stats.read.ops, - dev->stats.irqs); - - /* dump endpoint queues */ - for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) { - struct pxa25x_ep *ep = &dev->ep [i]; - struct pxa25x_request *req; - - if (i != 0) { - const struct usb_endpoint_descriptor *desc; - - desc = ep->desc; - if (!desc) - continue; - tmp = *dev->ep [i].reg_udccs; - seq_printf(m, - "%s max %d %s udccs %02x irqs %lu\n", - ep->ep.name, usb_endpoint_maxp(desc), - "pio", tmp, ep->pio_irqs); - /* TODO translate all five groups of udccs bits! */ - - } else /* ep0 should only have one transfer queued */ - seq_printf(m, "ep0 max 16 pio irqs %lu\n", - ep->pio_irqs); - - if (list_empty(&ep->queue)) { - seq_printf(m, "\t(nothing queued)\n"); - continue; - } - list_for_each_entry(req, &ep->queue, queue) { - seq_printf(m, - "\treq %p len %d/%d buf %p\n", - &req->req, req->req.actual, - req->req.length, req->req.buf); - } - } - -done: - local_irq_restore(flags); - return 0; -} - -static int -udc_debugfs_open(struct inode *inode, struct file *file) -{ - return single_open(file, udc_seq_show, inode->i_private); -} - -static const struct file_operations debug_fops = { - .open = udc_debugfs_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -#define create_debug_files(dev) \ - do { \ - dev->debugfs_udc = debugfs_create_file(dev->gadget.name, \ - S_IRUGO, NULL, dev, &debug_fops); \ - } while (0) -#define remove_debug_files(dev) \ - do { \ - if (dev->debugfs_udc) \ - debugfs_remove(dev->debugfs_udc); \ - } while (0) - -#else /* !CONFIG_USB_GADGET_DEBUG_FILES */ - -#define create_debug_files(dev) do {} while (0) -#define remove_debug_files(dev) do {} while (0) - -#endif /* CONFIG_USB_GADGET_DEBUG_FILES */ - -/*-------------------------------------------------------------------------*/ - -/* - * udc_disable - disable USB device controller - */ -static void udc_disable(struct pxa25x_udc *dev) -{ - /* block all irqs */ - udc_set_mask_UDCCR(UDCCR_SRM|UDCCR_REM); - UICR0 = UICR1 = 0xff; - UFNRH = UFNRH_SIM; - - /* if hardware supports it, disconnect from usb */ - pullup_off(); - - udc_clear_mask_UDCCR(UDCCR_UDE); - - ep0_idle (dev); - dev->gadget.speed = USB_SPEED_UNKNOWN; -} - - -/* - * udc_reinit - initialize software state - */ -static void udc_reinit(struct pxa25x_udc *dev) -{ - u32 i; - - /* device/ep0 records init */ - INIT_LIST_HEAD (&dev->gadget.ep_list); - INIT_LIST_HEAD (&dev->gadget.ep0->ep_list); - dev->ep0state = EP0_IDLE; - - /* basic endpoint records init */ - for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) { - struct pxa25x_ep *ep = &dev->ep[i]; - - if (i != 0) - list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list); - - ep->desc = NULL; - ep->ep.desc = NULL; - ep->stopped = 0; - INIT_LIST_HEAD (&ep->queue); - ep->pio_irqs = 0; - } - - /* the rest was statically initialized, and is read-only */ -} - -/* until it's enabled, this UDC should be completely invisible - * to any USB host. - */ -static void udc_enable (struct pxa25x_udc *dev) -{ - udc_clear_mask_UDCCR(UDCCR_UDE); - - /* try to clear these bits before we enable the udc */ - udc_ack_int_UDCCR(UDCCR_SUSIR|/*UDCCR_RSTIR|*/UDCCR_RESIR); - - ep0_idle(dev); - dev->gadget.speed = USB_SPEED_UNKNOWN; - dev->stats.irqs = 0; - - /* - * sequence taken from chapter 12.5.10, PXA250 AppProcDevManual: - * - enable UDC - * - if RESET is already in progress, ack interrupt - * - unmask reset interrupt - */ - udc_set_mask_UDCCR(UDCCR_UDE); - if (!(UDCCR & UDCCR_UDA)) - udc_ack_int_UDCCR(UDCCR_RSTIR); - - if (dev->has_cfr /* UDC_RES2 is defined */) { - /* pxa255 (a0+) can avoid a set_config race that could - * prevent gadget drivers from configuring correctly - */ - UDCCFR = UDCCFR_ACM | UDCCFR_MB1; - } else { - /* "USB test mode" for pxa250 errata 40-42 (stepping a0, a1) - * which could result in missing packets and interrupts. - * supposedly one bit per endpoint, controlling whether it - * double buffers or not; ACM/AREN bits fit into the holes. - * zero bits (like USIR0_IRx) disable double buffering. - */ - UDC_RES1 = 0x00; - UDC_RES2 = 0x00; - } - - /* enable suspend/resume and reset irqs */ - udc_clear_mask_UDCCR(UDCCR_SRM | UDCCR_REM); - - /* enable ep0 irqs */ - UICR0 &= ~UICR0_IM0; - - /* if hardware supports it, pullup D+ and wait for reset */ - pullup_on(); -} - - -/* when a driver is successfully registered, it will receive - * control requests including set_configuration(), which enables - * non-control requests. then usb traffic follows until a - * disconnect is reported. then a host may connect again, or - * the driver might get unbound. - */ -static int pxa25x_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) -{ - struct pxa25x_udc *dev = the_controller; - int retval; - - if (!driver - || driver->max_speed < USB_SPEED_FULL - || !bind - || !driver->disconnect - || !driver->setup) - return -EINVAL; - if (!dev) - return -ENODEV; - if (dev->driver) - return -EBUSY; - - /* first hook up the driver ... */ - dev->driver = driver; - dev->gadget.dev.driver = &driver->driver; - dev->pullup = 1; - - retval = device_add (&dev->gadget.dev); - if (retval) { -fail: - dev->driver = NULL; - dev->gadget.dev.driver = NULL; - return retval; - } - retval = bind(&dev->gadget); - if (retval) { - DMSG("bind to driver %s --> error %d\n", - driver->driver.name, retval); - device_del (&dev->gadget.dev); - goto fail; - } - - /* ... then enable host detection and ep0; and we're ready - * for set_configuration as well as eventual disconnect. - */ - DMSG("registered gadget driver '%s'\n", driver->driver.name); - - /* connect to bus through transceiver */ - if (dev->transceiver) { - retval = otg_set_peripheral(dev->transceiver->otg, - &dev->gadget); - if (retval) { - DMSG("can't bind to transceiver\n"); - if (driver->unbind) - driver->unbind(&dev->gadget); - goto bind_fail; - } - } - - pullup(dev); - dump_state(dev); - return 0; -bind_fail: - return retval; -} - -static void -stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver) -{ - int i; - - /* don't disconnect drivers more than once */ - if (dev->gadget.speed == USB_SPEED_UNKNOWN) - driver = NULL; - dev->gadget.speed = USB_SPEED_UNKNOWN; - - /* prevent new request submissions, kill any outstanding requests */ - for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) { - struct pxa25x_ep *ep = &dev->ep[i]; - - ep->stopped = 1; - nuke(ep, -ESHUTDOWN); - } - del_timer_sync(&dev->timer); - - /* report disconnect; the driver is already quiesced */ - if (driver) - driver->disconnect(&dev->gadget); - - /* re-init driver-visible data structures */ - udc_reinit(dev); -} - -static int pxa25x_stop(struct usb_gadget_driver *driver) -{ - struct pxa25x_udc *dev = the_controller; - - if (!dev) - return -ENODEV; - if (!driver || driver != dev->driver || !driver->unbind) - return -EINVAL; - - local_irq_disable(); - dev->pullup = 0; - pullup(dev); - stop_activity(dev, driver); - local_irq_enable(); - - if (dev->transceiver) - (void) otg_set_peripheral(dev->transceiver->otg, NULL); - - driver->unbind(&dev->gadget); - dev->gadget.dev.driver = NULL; - dev->driver = NULL; - - device_del (&dev->gadget.dev); - - DMSG("unregistered gadget driver '%s'\n", driver->driver.name); - dump_state(dev); - return 0; -} - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_ARCH_LUBBOCK - -/* Lubbock has separate connect and disconnect irqs. More typical designs - * use one GPIO as the VBUS IRQ, and another to control the D+ pullup. - */ - -static irqreturn_t -lubbock_vbus_irq(int irq, void *_dev) -{ - struct pxa25x_udc *dev = _dev; - int vbus; - - dev->stats.irqs++; - switch (irq) { - case LUBBOCK_USB_IRQ: - vbus = 1; - disable_irq(LUBBOCK_USB_IRQ); - enable_irq(LUBBOCK_USB_DISC_IRQ); - break; - case LUBBOCK_USB_DISC_IRQ: - vbus = 0; - disable_irq(LUBBOCK_USB_DISC_IRQ); - enable_irq(LUBBOCK_USB_IRQ); - break; - default: - return IRQ_NONE; - } - - pxa25x_udc_vbus_session(&dev->gadget, vbus); - return IRQ_HANDLED; -} - -#endif - - -/*-------------------------------------------------------------------------*/ - -static inline void clear_ep_state (struct pxa25x_udc *dev) -{ - unsigned i; - - /* hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint - * fifos, and pending transactions mustn't be continued in any case. - */ - for (i = 1; i < PXA_UDC_NUM_ENDPOINTS; i++) - nuke(&dev->ep[i], -ECONNABORTED); -} - -static void udc_watchdog(unsigned long _dev) -{ - struct pxa25x_udc *dev = (void *)_dev; - - local_irq_disable(); - if (dev->ep0state == EP0_STALL - && (UDCCS0 & UDCCS0_FST) == 0 - && (UDCCS0 & UDCCS0_SST) == 0) { - UDCCS0 = UDCCS0_FST|UDCCS0_FTF; - DBG(DBG_VERBOSE, "ep0 re-stall\n"); - start_watchdog(dev); - } - local_irq_enable(); -} - -static void handle_ep0 (struct pxa25x_udc *dev) -{ - u32 udccs0 = UDCCS0; - struct pxa25x_ep *ep = &dev->ep [0]; - struct pxa25x_request *req; - union { - struct usb_ctrlrequest r; - u8 raw [8]; - u32 word [2]; - } u; - - if (list_empty(&ep->queue)) - req = NULL; - else - req = list_entry(ep->queue.next, struct pxa25x_request, queue); - - /* clear stall status */ - if (udccs0 & UDCCS0_SST) { - nuke(ep, -EPIPE); - UDCCS0 = UDCCS0_SST; - del_timer(&dev->timer); - ep0_idle(dev); - } - - /* previous request unfinished? non-error iff back-to-back ... */ - if ((udccs0 & UDCCS0_SA) != 0 && dev->ep0state != EP0_IDLE) { - nuke(ep, 0); - del_timer(&dev->timer); - ep0_idle(dev); - } - - switch (dev->ep0state) { - case EP0_IDLE: - /* late-breaking status? */ - udccs0 = UDCCS0; - - /* start control request? */ - if (likely((udccs0 & (UDCCS0_OPR|UDCCS0_SA|UDCCS0_RNE)) - == (UDCCS0_OPR|UDCCS0_SA|UDCCS0_RNE))) { - int i; - - nuke (ep, -EPROTO); - - /* read SETUP packet */ - for (i = 0; i < 8; i++) { - if (unlikely(!(UDCCS0 & UDCCS0_RNE))) { -bad_setup: - DMSG("SETUP %d!\n", i); - goto stall; - } - u.raw [i] = (u8) UDDR0; - } - if (unlikely((UDCCS0 & UDCCS0_RNE) != 0)) - goto bad_setup; - -got_setup: - DBG(DBG_VERBOSE, "SETUP %02x.%02x v%04x i%04x l%04x\n", - u.r.bRequestType, u.r.bRequest, - le16_to_cpu(u.r.wValue), - le16_to_cpu(u.r.wIndex), - le16_to_cpu(u.r.wLength)); - - /* cope with automagic for some standard requests. */ - dev->req_std = (u.r.bRequestType & USB_TYPE_MASK) - == USB_TYPE_STANDARD; - dev->req_config = 0; - dev->req_pending = 1; - switch (u.r.bRequest) { - /* hardware restricts gadget drivers here! */ - case USB_REQ_SET_CONFIGURATION: - if (u.r.bRequestType == USB_RECIP_DEVICE) { - /* reflect hardware's automagic - * up to the gadget driver. - */ -config_change: - dev->req_config = 1; - clear_ep_state(dev); - /* if !has_cfr, there's no synch - * else use AREN (later) not SA|OPR - * USIR0_IR0 acts edge sensitive - */ - } - break; - /* ... and here, even more ... */ - case USB_REQ_SET_INTERFACE: - if (u.r.bRequestType == USB_RECIP_INTERFACE) { - /* udc hardware is broken by design: - * - altsetting may only be zero; - * - hw resets all interfaces' eps; - * - ep reset doesn't include halt(?). - */ - DMSG("broken set_interface (%d/%d)\n", - le16_to_cpu(u.r.wIndex), - le16_to_cpu(u.r.wValue)); - goto config_change; - } - break; - /* hardware was supposed to hide this */ - case USB_REQ_SET_ADDRESS: - if (u.r.bRequestType == USB_RECIP_DEVICE) { - ep0start(dev, 0, "address"); - return; - } - break; - } - - if (u.r.bRequestType & USB_DIR_IN) - dev->ep0state = EP0_IN_DATA_PHASE; - else - dev->ep0state = EP0_OUT_DATA_PHASE; - - i = dev->driver->setup(&dev->gadget, &u.r); - if (i < 0) { - /* hardware automagic preventing STALL... */ - if (dev->req_config) { - /* hardware sometimes neglects to tell - * tell us about config change events, - * so later ones may fail... - */ - WARNING("config change %02x fail %d?\n", - u.r.bRequest, i); - return; - /* TODO experiment: if has_cfr, - * hardware didn't ACK; maybe we - * could actually STALL! - */ - } - DBG(DBG_VERBOSE, "protocol STALL, " - "%02x err %d\n", UDCCS0, i); -stall: - /* the watchdog timer helps deal with cases - * where udc seems to clear FST wrongly, and - * then NAKs instead of STALLing. - */ - ep0start(dev, UDCCS0_FST|UDCCS0_FTF, "stall"); - start_watchdog(dev); - dev->ep0state = EP0_STALL; - - /* deferred i/o == no response yet */ - } else if (dev->req_pending) { - if (likely(dev->ep0state == EP0_IN_DATA_PHASE - || dev->req_std || u.r.wLength)) - ep0start(dev, 0, "defer"); - else - ep0start(dev, UDCCS0_IPR, "defer/IPR"); - } - - /* expect at least one data or status stage irq */ - return; - - } else if (likely((udccs0 & (UDCCS0_OPR|UDCCS0_SA)) - == (UDCCS0_OPR|UDCCS0_SA))) { - unsigned i; - - /* pxa210/250 erratum 131 for B0/B1 says RNE lies. - * still observed on a pxa255 a0. - */ - DBG(DBG_VERBOSE, "e131\n"); - nuke(ep, -EPROTO); - - /* read SETUP data, but don't trust it too much */ - for (i = 0; i < 8; i++) - u.raw [i] = (u8) UDDR0; - if ((u.r.bRequestType & USB_RECIP_MASK) - > USB_RECIP_OTHER) - goto stall; - if (u.word [0] == 0 && u.word [1] == 0) - goto stall; - goto got_setup; - } else { - /* some random early IRQ: - * - we acked FST - * - IPR cleared - * - OPR got set, without SA (likely status stage) - */ - UDCCS0 = udccs0 & (UDCCS0_SA|UDCCS0_OPR); - } - break; - case EP0_IN_DATA_PHASE: /* GET_DESCRIPTOR etc */ - if (udccs0 & UDCCS0_OPR) { - UDCCS0 = UDCCS0_OPR|UDCCS0_FTF; - DBG(DBG_VERBOSE, "ep0in premature status\n"); - if (req) - done(ep, req, 0); - ep0_idle(dev); - } else /* irq was IPR clearing */ { - if (req) { - /* this IN packet might finish the request */ - (void) write_ep0_fifo(ep, req); - } /* else IN token before response was written */ - } - break; - case EP0_OUT_DATA_PHASE: /* SET_DESCRIPTOR etc */ - if (udccs0 & UDCCS0_OPR) { - if (req) { - /* this OUT packet might finish the request */ - if (read_ep0_fifo(ep, req)) - done(ep, req, 0); - /* else more OUT packets expected */ - } /* else OUT token before read was issued */ - } else /* irq was IPR clearing */ { - DBG(DBG_VERBOSE, "ep0out premature status\n"); - if (req) - done(ep, req, 0); - ep0_idle(dev); - } - break; - case EP0_END_XFER: - if (req) - done(ep, req, 0); - /* ack control-IN status (maybe in-zlp was skipped) - * also appears after some config change events. - */ - if (udccs0 & UDCCS0_OPR) - UDCCS0 = UDCCS0_OPR; - ep0_idle(dev); - break; - case EP0_STALL: - UDCCS0 = UDCCS0_FST; - break; - } - USIR0 = USIR0_IR0; -} - -static void handle_ep(struct pxa25x_ep *ep) -{ - struct pxa25x_request *req; - int is_in = ep->bEndpointAddress & USB_DIR_IN; - int completed; - u32 udccs, tmp; - - do { - completed = 0; - if (likely (!list_empty(&ep->queue))) - req = list_entry(ep->queue.next, - struct pxa25x_request, queue); - else - req = NULL; - - // TODO check FST handling - - udccs = *ep->reg_udccs; - if (unlikely(is_in)) { /* irq from TPC, SST, or (ISO) TUR */ - tmp = UDCCS_BI_TUR; - if (likely(ep->bmAttributes == USB_ENDPOINT_XFER_BULK)) - tmp |= UDCCS_BI_SST; - tmp &= udccs; - if (likely (tmp)) - *ep->reg_udccs = tmp; - if (req && likely ((udccs & UDCCS_BI_TFS) != 0)) - completed = write_fifo(ep, req); - - } else { /* irq from RPC (or for ISO, ROF) */ - if (likely(ep->bmAttributes == USB_ENDPOINT_XFER_BULK)) - tmp = UDCCS_BO_SST | UDCCS_BO_DME; - else - tmp = UDCCS_IO_ROF | UDCCS_IO_DME; - tmp &= udccs; - if (likely(tmp)) - *ep->reg_udccs = tmp; - - /* fifos can hold packets, ready for reading... */ - if (likely(req)) { - completed = read_fifo(ep, req); - } else - pio_irq_disable (ep->bEndpointAddress); - } - ep->pio_irqs++; - } while (completed); -} - -/* - * pxa25x_udc_irq - interrupt handler - * - * avoid delays in ep0 processing. the control handshaking isn't always - * under software control (pxa250c0 and the pxa255 are better), and delays - * could cause usb protocol errors. - */ -static irqreturn_t -pxa25x_udc_irq(int irq, void *_dev) -{ - struct pxa25x_udc *dev = _dev; - int handled; - - dev->stats.irqs++; - do { - u32 udccr = UDCCR; - - handled = 0; - - /* SUSpend Interrupt Request */ - if (unlikely(udccr & UDCCR_SUSIR)) { - udc_ack_int_UDCCR(UDCCR_SUSIR); - handled = 1; - DBG(DBG_VERBOSE, "USB suspend\n"); - - if (dev->gadget.speed != USB_SPEED_UNKNOWN - && dev->driver - && dev->driver->suspend) - dev->driver->suspend(&dev->gadget); - ep0_idle (dev); - } - - /* RESume Interrupt Request */ - if (unlikely(udccr & UDCCR_RESIR)) { - udc_ack_int_UDCCR(UDCCR_RESIR); - handled = 1; - DBG(DBG_VERBOSE, "USB resume\n"); - - if (dev->gadget.speed != USB_SPEED_UNKNOWN - && dev->driver - && dev->driver->resume) - dev->driver->resume(&dev->gadget); - } - - /* ReSeT Interrupt Request - USB reset */ - if (unlikely(udccr & UDCCR_RSTIR)) { - udc_ack_int_UDCCR(UDCCR_RSTIR); - handled = 1; - - if ((UDCCR & UDCCR_UDA) == 0) { - DBG(DBG_VERBOSE, "USB reset start\n"); - - /* reset driver and endpoints, - * in case that's not yet done - */ - stop_activity (dev, dev->driver); - - } else { - DBG(DBG_VERBOSE, "USB reset end\n"); - dev->gadget.speed = USB_SPEED_FULL; - memset(&dev->stats, 0, sizeof dev->stats); - /* driver and endpoints are still reset */ - } - - } else { - u32 usir0 = USIR0 & ~UICR0; - u32 usir1 = USIR1 & ~UICR1; - int i; - - if (unlikely (!usir0 && !usir1)) - continue; - - DBG(DBG_VERY_NOISY, "irq %02x.%02x\n", usir1, usir0); - - /* control traffic */ - if (usir0 & USIR0_IR0) { - dev->ep[0].pio_irqs++; - handle_ep0(dev); - handled = 1; - } - - /* endpoint data transfers */ - for (i = 0; i < 8; i++) { - u32 tmp = 1 << i; - - if (i && (usir0 & tmp)) { - handle_ep(&dev->ep[i]); - USIR0 |= tmp; - handled = 1; - } -#ifndef CONFIG_USB_PXA25X_SMALL - if (usir1 & tmp) { - handle_ep(&dev->ep[i+8]); - USIR1 |= tmp; - handled = 1; - } -#endif - } - } - - /* we could also ask for 1 msec SOF (SIR) interrupts */ - - } while (handled); - return IRQ_HANDLED; -} - -/*-------------------------------------------------------------------------*/ - -static void nop_release (struct device *dev) -{ - DMSG("%s %s\n", __func__, dev_name(dev)); -} - -/* this uses load-time allocation and initialization (instead of - * doing it at run-time) to save code, eliminate fault paths, and - * be more obviously correct. - */ -static struct pxa25x_udc memory = { - .gadget = { - .ops = &pxa25x_udc_ops, - .ep0 = &memory.ep[0].ep, - .name = driver_name, - .dev = { - .init_name = "gadget", - .release = nop_release, - }, - }, - - /* control endpoint */ - .ep[0] = { - .ep = { - .name = ep0name, - .ops = &pxa25x_ep_ops, - .maxpacket = EP0_FIFO_SIZE, - }, - .dev = &memory, - .reg_udccs = &UDCCS0, - .reg_uddr = &UDDR0, - }, - - /* first group of endpoints */ - .ep[1] = { - .ep = { - .name = "ep1in-bulk", - .ops = &pxa25x_ep_ops, - .maxpacket = BULK_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = BULK_FIFO_SIZE, - .bEndpointAddress = USB_DIR_IN | 1, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .reg_udccs = &UDCCS1, - .reg_uddr = &UDDR1, - }, - .ep[2] = { - .ep = { - .name = "ep2out-bulk", - .ops = &pxa25x_ep_ops, - .maxpacket = BULK_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = BULK_FIFO_SIZE, - .bEndpointAddress = 2, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .reg_udccs = &UDCCS2, - .reg_ubcr = &UBCR2, - .reg_uddr = &UDDR2, - }, -#ifndef CONFIG_USB_PXA25X_SMALL - .ep[3] = { - .ep = { - .name = "ep3in-iso", - .ops = &pxa25x_ep_ops, - .maxpacket = ISO_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = ISO_FIFO_SIZE, - .bEndpointAddress = USB_DIR_IN | 3, - .bmAttributes = USB_ENDPOINT_XFER_ISOC, - .reg_udccs = &UDCCS3, - .reg_uddr = &UDDR3, - }, - .ep[4] = { - .ep = { - .name = "ep4out-iso", - .ops = &pxa25x_ep_ops, - .maxpacket = ISO_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = ISO_FIFO_SIZE, - .bEndpointAddress = 4, - .bmAttributes = USB_ENDPOINT_XFER_ISOC, - .reg_udccs = &UDCCS4, - .reg_ubcr = &UBCR4, - .reg_uddr = &UDDR4, - }, - .ep[5] = { - .ep = { - .name = "ep5in-int", - .ops = &pxa25x_ep_ops, - .maxpacket = INT_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = INT_FIFO_SIZE, - .bEndpointAddress = USB_DIR_IN | 5, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .reg_udccs = &UDCCS5, - .reg_uddr = &UDDR5, - }, - - /* second group of endpoints */ - .ep[6] = { - .ep = { - .name = "ep6in-bulk", - .ops = &pxa25x_ep_ops, - .maxpacket = BULK_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = BULK_FIFO_SIZE, - .bEndpointAddress = USB_DIR_IN | 6, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .reg_udccs = &UDCCS6, - .reg_uddr = &UDDR6, - }, - .ep[7] = { - .ep = { - .name = "ep7out-bulk", - .ops = &pxa25x_ep_ops, - .maxpacket = BULK_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = BULK_FIFO_SIZE, - .bEndpointAddress = 7, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .reg_udccs = &UDCCS7, - .reg_ubcr = &UBCR7, - .reg_uddr = &UDDR7, - }, - .ep[8] = { - .ep = { - .name = "ep8in-iso", - .ops = &pxa25x_ep_ops, - .maxpacket = ISO_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = ISO_FIFO_SIZE, - .bEndpointAddress = USB_DIR_IN | 8, - .bmAttributes = USB_ENDPOINT_XFER_ISOC, - .reg_udccs = &UDCCS8, - .reg_uddr = &UDDR8, - }, - .ep[9] = { - .ep = { - .name = "ep9out-iso", - .ops = &pxa25x_ep_ops, - .maxpacket = ISO_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = ISO_FIFO_SIZE, - .bEndpointAddress = 9, - .bmAttributes = USB_ENDPOINT_XFER_ISOC, - .reg_udccs = &UDCCS9, - .reg_ubcr = &UBCR9, - .reg_uddr = &UDDR9, - }, - .ep[10] = { - .ep = { - .name = "ep10in-int", - .ops = &pxa25x_ep_ops, - .maxpacket = INT_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = INT_FIFO_SIZE, - .bEndpointAddress = USB_DIR_IN | 10, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .reg_udccs = &UDCCS10, - .reg_uddr = &UDDR10, - }, - - /* third group of endpoints */ - .ep[11] = { - .ep = { - .name = "ep11in-bulk", - .ops = &pxa25x_ep_ops, - .maxpacket = BULK_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = BULK_FIFO_SIZE, - .bEndpointAddress = USB_DIR_IN | 11, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .reg_udccs = &UDCCS11, - .reg_uddr = &UDDR11, - }, - .ep[12] = { - .ep = { - .name = "ep12out-bulk", - .ops = &pxa25x_ep_ops, - .maxpacket = BULK_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = BULK_FIFO_SIZE, - .bEndpointAddress = 12, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .reg_udccs = &UDCCS12, - .reg_ubcr = &UBCR12, - .reg_uddr = &UDDR12, - }, - .ep[13] = { - .ep = { - .name = "ep13in-iso", - .ops = &pxa25x_ep_ops, - .maxpacket = ISO_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = ISO_FIFO_SIZE, - .bEndpointAddress = USB_DIR_IN | 13, - .bmAttributes = USB_ENDPOINT_XFER_ISOC, - .reg_udccs = &UDCCS13, - .reg_uddr = &UDDR13, - }, - .ep[14] = { - .ep = { - .name = "ep14out-iso", - .ops = &pxa25x_ep_ops, - .maxpacket = ISO_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = ISO_FIFO_SIZE, - .bEndpointAddress = 14, - .bmAttributes = USB_ENDPOINT_XFER_ISOC, - .reg_udccs = &UDCCS14, - .reg_ubcr = &UBCR14, - .reg_uddr = &UDDR14, - }, - .ep[15] = { - .ep = { - .name = "ep15in-int", - .ops = &pxa25x_ep_ops, - .maxpacket = INT_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = INT_FIFO_SIZE, - .bEndpointAddress = USB_DIR_IN | 15, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .reg_udccs = &UDCCS15, - .reg_uddr = &UDDR15, - }, -#endif /* !CONFIG_USB_PXA25X_SMALL */ -}; - -#define CP15R0_VENDOR_MASK 0xffffe000 - -#if defined(CONFIG_ARCH_PXA) -#define CP15R0_XSCALE_VALUE 0x69052000 /* intel/arm/xscale */ - -#elif defined(CONFIG_ARCH_IXP4XX) -#define CP15R0_XSCALE_VALUE 0x69054000 /* intel/arm/ixp4xx */ - -#endif - -#define CP15R0_PROD_MASK 0x000003f0 -#define PXA25x 0x00000100 /* and PXA26x */ -#define PXA210 0x00000120 - -#define CP15R0_REV_MASK 0x0000000f - -#define CP15R0_PRODREV_MASK (CP15R0_PROD_MASK | CP15R0_REV_MASK) - -#define PXA255_A0 0x00000106 /* or PXA260_B1 */ -#define PXA250_C0 0x00000105 /* or PXA26x_B0 */ -#define PXA250_B2 0x00000104 -#define PXA250_B1 0x00000103 /* or PXA260_A0 */ -#define PXA250_B0 0x00000102 -#define PXA250_A1 0x00000101 -#define PXA250_A0 0x00000100 - -#define PXA210_C0 0x00000125 -#define PXA210_B2 0x00000124 -#define PXA210_B1 0x00000123 -#define PXA210_B0 0x00000122 -#define IXP425_A0 0x000001c1 -#define IXP425_B0 0x000001f1 -#define IXP465_AD 0x00000200 - -/* - * probe - binds to the platform device - */ -static int __init pxa25x_udc_probe(struct platform_device *pdev) -{ - struct pxa25x_udc *dev = &memory; - int retval, irq; - u32 chiprev; - - /* insist on Intel/ARM/XScale */ - asm("mrc%? p15, 0, %0, c0, c0" : "=r" (chiprev)); - if ((chiprev & CP15R0_VENDOR_MASK) != CP15R0_XSCALE_VALUE) { - pr_err("%s: not XScale!\n", driver_name); - return -ENODEV; - } - - /* trigger chiprev-specific logic */ - switch (chiprev & CP15R0_PRODREV_MASK) { -#if defined(CONFIG_ARCH_PXA) - case PXA255_A0: - dev->has_cfr = 1; - break; - case PXA250_A0: - case PXA250_A1: - /* A0/A1 "not released"; ep 13, 15 unusable */ - /* fall through */ - case PXA250_B2: case PXA210_B2: - case PXA250_B1: case PXA210_B1: - case PXA250_B0: case PXA210_B0: - /* OUT-DMA is broken ... */ - /* fall through */ - case PXA250_C0: case PXA210_C0: - break; -#elif defined(CONFIG_ARCH_IXP4XX) - case IXP425_A0: - case IXP425_B0: - case IXP465_AD: - dev->has_cfr = 1; - break; -#endif - default: - pr_err("%s: unrecognized processor: %08x\n", - driver_name, chiprev); - /* iop3xx, ixp4xx, ... */ - return -ENODEV; - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return -ENODEV; - - dev->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(dev->clk)) { - retval = PTR_ERR(dev->clk); - goto err_clk; - } - - pr_debug("%s: IRQ %d%s%s\n", driver_name, irq, - dev->has_cfr ? "" : " (!cfr)", - SIZE_STR "(pio)" - ); - - /* other non-static parts of init */ - dev->dev = &pdev->dev; - dev->mach = pdev->dev.platform_data; - - dev->transceiver = usb_get_transceiver(); - - if (gpio_is_valid(dev->mach->gpio_pullup)) { - if ((retval = gpio_request(dev->mach->gpio_pullup, - "pca25x_udc GPIO PULLUP"))) { - dev_dbg(&pdev->dev, - "can't get pullup gpio %d, err: %d\n", - dev->mach->gpio_pullup, retval); - goto err_gpio_pullup; - } - gpio_direction_output(dev->mach->gpio_pullup, 0); - } - - init_timer(&dev->timer); - dev->timer.function = udc_watchdog; - dev->timer.data = (unsigned long) dev; - - device_initialize(&dev->gadget.dev); - dev->gadget.dev.parent = &pdev->dev; - dev->gadget.dev.dma_mask = pdev->dev.dma_mask; - - the_controller = dev; - platform_set_drvdata(pdev, dev); - - udc_disable(dev); - udc_reinit(dev); - - dev->vbus = 0; - - /* irq setup after old hardware state is cleaned up */ - retval = request_irq(irq, pxa25x_udc_irq, - 0, driver_name, dev); - if (retval != 0) { - pr_err("%s: can't get irq %d, err %d\n", - driver_name, irq, retval); - goto err_irq1; - } - dev->got_irq = 1; - -#ifdef CONFIG_ARCH_LUBBOCK - if (machine_is_lubbock()) { - retval = request_irq(LUBBOCK_USB_DISC_IRQ, - lubbock_vbus_irq, - IRQF_SAMPLE_RANDOM, - driver_name, dev); - if (retval != 0) { - pr_err("%s: can't get irq %i, err %d\n", - driver_name, LUBBOCK_USB_DISC_IRQ, retval); - goto err_irq_lub; - } - retval = request_irq(LUBBOCK_USB_IRQ, - lubbock_vbus_irq, - IRQF_SAMPLE_RANDOM, - driver_name, dev); - if (retval != 0) { - pr_err("%s: can't get irq %i, err %d\n", - driver_name, LUBBOCK_USB_IRQ, retval); - goto lubbock_fail0; - } - } else -#endif - create_debug_files(dev); - - retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); - if (!retval) - return retval; - - remove_debug_files(dev); -#ifdef CONFIG_ARCH_LUBBOCK -lubbock_fail0: - free_irq(LUBBOCK_USB_DISC_IRQ, dev); - err_irq_lub: - free_irq(irq, dev); -#endif - err_irq1: - if (gpio_is_valid(dev->mach->gpio_pullup)) - gpio_free(dev->mach->gpio_pullup); - err_gpio_pullup: - if (dev->transceiver) { - usb_put_transceiver(dev->transceiver); - dev->transceiver = NULL; - } - clk_put(dev->clk); - err_clk: - return retval; -} - -static void pxa25x_udc_shutdown(struct platform_device *_dev) -{ - pullup_off(); -} - -static int __exit pxa25x_udc_remove(struct platform_device *pdev) -{ - struct pxa25x_udc *dev = platform_get_drvdata(pdev); - - usb_del_gadget_udc(&dev->gadget); - if (dev->driver) - return -EBUSY; - - dev->pullup = 0; - pullup(dev); - - remove_debug_files(dev); - - if (dev->got_irq) { - free_irq(platform_get_irq(pdev, 0), dev); - dev->got_irq = 0; - } -#ifdef CONFIG_ARCH_LUBBOCK - if (machine_is_lubbock()) { - free_irq(LUBBOCK_USB_DISC_IRQ, dev); - free_irq(LUBBOCK_USB_IRQ, dev); - } -#endif - if (gpio_is_valid(dev->mach->gpio_pullup)) - gpio_free(dev->mach->gpio_pullup); - - clk_put(dev->clk); - - if (dev->transceiver) { - usb_put_transceiver(dev->transceiver); - dev->transceiver = NULL; - } - - platform_set_drvdata(pdev, NULL); - the_controller = NULL; - return 0; -} - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_PM - -/* USB suspend (controlled by the host) and system suspend (controlled - * by the PXA) don't necessarily work well together. If USB is active, - * the 48 MHz clock is required; so the system can't enter 33 MHz idle - * mode, or any deeper PM saving state. - * - * For now, we punt and forcibly disconnect from the USB host when PXA - * enters any suspend state. While we're disconnected, we always disable - * the 48MHz USB clock ... allowing PXA sleep and/or 33 MHz idle states. - * Boards without software pullup control shouldn't use those states. - * VBUS IRQs should probably be ignored so that the PXA device just acts - * "dead" to USB hosts until system resume. - */ -static int pxa25x_udc_suspend(struct platform_device *dev, pm_message_t state) -{ - struct pxa25x_udc *udc = platform_get_drvdata(dev); - unsigned long flags; - - if (!gpio_is_valid(udc->mach->gpio_pullup) && !udc->mach->udc_command) - WARNING("USB host won't detect disconnect!\n"); - udc->suspended = 1; - - local_irq_save(flags); - pullup(udc); - local_irq_restore(flags); - - return 0; -} - -static int pxa25x_udc_resume(struct platform_device *dev) -{ - struct pxa25x_udc *udc = platform_get_drvdata(dev); - unsigned long flags; - - udc->suspended = 0; - local_irq_save(flags); - pullup(udc); - local_irq_restore(flags); - - return 0; -} - -#else -#define pxa25x_udc_suspend NULL -#define pxa25x_udc_resume NULL -#endif - -/*-------------------------------------------------------------------------*/ - -static struct platform_driver udc_driver = { - .shutdown = pxa25x_udc_shutdown, - .remove = __exit_p(pxa25x_udc_remove), - .suspend = pxa25x_udc_suspend, - .resume = pxa25x_udc_resume, - .driver = { - .owner = THIS_MODULE, - .name = "pxa25x-udc", - }, -}; - -static int __init udc_init(void) -{ - pr_info("%s: version %s\n", driver_name, DRIVER_VERSION); - return platform_driver_probe(&udc_driver, pxa25x_udc_probe); -} -module_init(udc_init); - -static void __exit udc_exit(void) -{ - platform_driver_unregister(&udc_driver); -} -module_exit(udc_exit); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Frank Becker, Robert Schwebel, David Brownell"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:pxa25x-udc"); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/pxa25x_udc.h b/ANDROID_3.4.5/drivers/usb/gadget/pxa25x_udc.h deleted file mode 100644 index 893e917f..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/pxa25x_udc.h +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Intel PXA25x on-chip full speed USB device controller - * - * Copyright (C) 2003 Robert Schwebel , Pengutronix - * Copyright (C) 2003 David Brownell - * - * - * 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. - */ - -#ifndef __LINUX_USB_GADGET_PXA25X_H -#define __LINUX_USB_GADGET_PXA25X_H - -#include - -/*-------------------------------------------------------------------------*/ - -/* pxa25x has this (move to include/asm-arm/arch-pxa/pxa-regs.h) */ -#define UFNRH_SIR (1 << 7) /* SOF interrupt request */ -#define UFNRH_SIM (1 << 6) /* SOF interrupt mask */ -#define UFNRH_IPE14 (1 << 5) /* ISO packet error, ep14 */ -#define UFNRH_IPE9 (1 << 4) /* ISO packet error, ep9 */ -#define UFNRH_IPE4 (1 << 3) /* ISO packet error, ep4 */ - -/* pxa255 has this (move to include/asm-arm/arch-pxa/pxa-regs.h) */ -#define UDCCFR UDC_RES2 /* UDC Control Function Register */ -#define UDCCFR_AREN (1 << 7) /* ACK response enable (now) */ -#define UDCCFR_ACM (1 << 2) /* ACK control mode (wait for AREN) */ - -/* latest pxa255 errata define new "must be one" bits in UDCCFR */ -#define UDCCFR_MB1 (0xff & ~(UDCCFR_AREN|UDCCFR_ACM)) - -/*-------------------------------------------------------------------------*/ - -struct pxa25x_udc; - -struct pxa25x_ep { - struct usb_ep ep; - struct pxa25x_udc *dev; - - const struct usb_endpoint_descriptor *desc; - struct list_head queue; - unsigned long pio_irqs; - - unsigned short fifo_size; - u8 bEndpointAddress; - u8 bmAttributes; - - unsigned stopped : 1; - unsigned dma_fixup : 1; - - /* UDCCS = UDC Control/Status for this EP - * UBCR = UDC Byte Count Remaining (contents of OUT fifo) - * UDDR = UDC Endpoint Data Register (the fifo) - * DRCM = DMA Request Channel Map - */ - volatile u32 *reg_udccs; - volatile u32 *reg_ubcr; - volatile u32 *reg_uddr; -}; - -struct pxa25x_request { - struct usb_request req; - struct list_head queue; -}; - -enum ep0_state { - EP0_IDLE, - EP0_IN_DATA_PHASE, - EP0_OUT_DATA_PHASE, - EP0_END_XFER, - EP0_STALL, -}; - -#define EP0_FIFO_SIZE ((unsigned)16) -#define BULK_FIFO_SIZE ((unsigned)64) -#define ISO_FIFO_SIZE ((unsigned)256) -#define INT_FIFO_SIZE ((unsigned)8) - -struct udc_stats { - struct ep0stats { - unsigned long ops; - unsigned long bytes; - } read, write; - unsigned long irqs; -}; - -#ifdef CONFIG_USB_PXA25X_SMALL -/* when memory's tight, SMALL config saves code+data. */ -#define PXA_UDC_NUM_ENDPOINTS 3 -#endif - -#ifndef PXA_UDC_NUM_ENDPOINTS -#define PXA_UDC_NUM_ENDPOINTS 16 -#endif - -struct pxa25x_udc { - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - - enum ep0_state ep0state; - struct udc_stats stats; - unsigned got_irq : 1, - vbus : 1, - pullup : 1, - has_cfr : 1, - req_pending : 1, - req_std : 1, - req_config : 1, - suspended : 1, - active : 1; - -#define start_watchdog(dev) mod_timer(&dev->timer, jiffies + (HZ/200)) - struct timer_list timer; - - struct device *dev; - struct clk *clk; - struct pxa2xx_udc_mach_info *mach; - struct usb_phy *transceiver; - u64 dma_mask; - struct pxa25x_ep ep [PXA_UDC_NUM_ENDPOINTS]; - -#ifdef CONFIG_USB_GADGET_DEBUG_FS - struct dentry *debugfs_udc; -#endif -}; - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_ARCH_LUBBOCK -#include -/* lubbock can also report usb connect/disconnect irqs */ -#endif - -static struct pxa25x_udc *the_controller; - -/*-------------------------------------------------------------------------*/ - -/* - * Debugging support vanishes in non-debug builds. DBG_NORMAL should be - * mostly silent during normal use/testing, with no timing side-effects. - */ -#define DBG_NORMAL 1 /* error paths, device state transitions */ -#define DBG_VERBOSE 2 /* add some success path trace info */ -#define DBG_NOISY 3 /* ... even more: request level */ -#define DBG_VERY_NOISY 4 /* ... even more: packet level */ - -#define DMSG(stuff...) pr_debug("udc: " stuff) - -#ifdef DEBUG - -static const char *state_name[] = { - "EP0_IDLE", - "EP0_IN_DATA_PHASE", "EP0_OUT_DATA_PHASE", - "EP0_END_XFER", "EP0_STALL" -}; - -#ifdef VERBOSE_DEBUG -# define UDC_DEBUG DBG_VERBOSE -#else -# define UDC_DEBUG DBG_NORMAL -#endif - -static void __maybe_unused -dump_udccr(const char *label) -{ - u32 udccr = UDCCR; - DMSG("%s %02X =%s%s%s%s%s%s%s%s\n", - label, udccr, - (udccr & UDCCR_REM) ? " rem" : "", - (udccr & UDCCR_RSTIR) ? " rstir" : "", - (udccr & UDCCR_SRM) ? " srm" : "", - (udccr & UDCCR_SUSIR) ? " susir" : "", - (udccr & UDCCR_RESIR) ? " resir" : "", - (udccr & UDCCR_RSM) ? " rsm" : "", - (udccr & UDCCR_UDA) ? " uda" : "", - (udccr & UDCCR_UDE) ? " ude" : ""); -} - -static void __maybe_unused -dump_udccs0(const char *label) -{ - u32 udccs0 = UDCCS0; - - DMSG("%s %s %02X =%s%s%s%s%s%s%s%s\n", - label, state_name[the_controller->ep0state], udccs0, - (udccs0 & UDCCS0_SA) ? " sa" : "", - (udccs0 & UDCCS0_RNE) ? " rne" : "", - (udccs0 & UDCCS0_FST) ? " fst" : "", - (udccs0 & UDCCS0_SST) ? " sst" : "", - (udccs0 & UDCCS0_DRWF) ? " dwrf" : "", - (udccs0 & UDCCS0_FTF) ? " ftf" : "", - (udccs0 & UDCCS0_IPR) ? " ipr" : "", - (udccs0 & UDCCS0_OPR) ? " opr" : ""); -} - -static void __maybe_unused -dump_state(struct pxa25x_udc *dev) -{ - u32 tmp; - unsigned i; - - DMSG("%s, uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n", - state_name[dev->ep0state], - UICR1, UICR0, USIR1, USIR0, UFNRH, UFNRL); - dump_udccr("udccr"); - if (dev->has_cfr) { - tmp = UDCCFR; - DMSG("udccfr %02X =%s%s\n", tmp, - (tmp & UDCCFR_AREN) ? " aren" : "", - (tmp & UDCCFR_ACM) ? " acm" : ""); - } - - if (!dev->driver) { - DMSG("no gadget driver bound\n"); - return; - } else - DMSG("ep0 driver '%s'\n", dev->driver->driver.name); - - dump_udccs0 ("udccs0"); - DMSG("ep0 IN %lu/%lu, OUT %lu/%lu\n", - dev->stats.write.bytes, dev->stats.write.ops, - dev->stats.read.bytes, dev->stats.read.ops); - - for (i = 1; i < PXA_UDC_NUM_ENDPOINTS; i++) { - if (dev->ep [i].desc == NULL) - continue; - DMSG ("udccs%d = %02x\n", i, *dev->ep->reg_udccs); - } -} - -#else - -#define dump_udccr(x) do{}while(0) -#define dump_udccs0(x) do{}while(0) -#define dump_state(x) do{}while(0) - -#define UDC_DEBUG ((unsigned)0) - -#endif - -#define DBG(lvl, stuff...) do{if ((lvl) <= UDC_DEBUG) DMSG(stuff);}while(0) - -#define ERR(stuff...) pr_err("udc: " stuff) -#define WARNING(stuff...) pr_warning("udc: " stuff) -#define INFO(stuff...) pr_info("udc: " stuff) - - -#endif /* __LINUX_USB_GADGET_PXA25X_H */ diff --git a/ANDROID_3.4.5/drivers/usb/gadget/pxa27x_udc.c b/ANDROID_3.4.5/drivers/usb/gadget/pxa27x_udc.c deleted file mode 100644 index 98acb3ab..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/pxa27x_udc.c +++ /dev/null @@ -1,2679 +0,0 @@ -/* - * Handles the Intel 27x USB Device Controller (UDC) - * - * Inspired by original driver by Frank Becker, David Brownell, and others. - * Copyright (C) 2008 Robert Jarzmik - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include "pxa27x_udc.h" - -/* - * This driver handles the USB Device Controller (UDC) in Intel's PXA 27x - * series processors. - * - * Such controller drivers work with a gadget driver. The gadget driver - * returns descriptors, implements configuration and data protocols used - * by the host to interact with this device, and allocates endpoints to - * the different protocol interfaces. The controller driver virtualizes - * usb hardware so that the gadget drivers will be more portable. - * - * This UDC hardware wants to implement a bit too much USB protocol. The - * biggest issues are: that the endpoints have to be set up before the - * controller can be enabled (minor, and not uncommon); and each endpoint - * can only have one configuration, interface and alternative interface - * number (major, and very unusual). Once set up, these cannot be changed - * without a controller reset. - * - * The workaround is to setup all combinations necessary for the gadgets which - * will work with this driver. This is done in pxa_udc structure, statically. - * See pxa_udc, udc_usb_ep versus pxa_ep, and matching function find_pxa_ep. - * (You could modify this if needed. Some drivers have a "fifo_mode" module - * parameter to facilitate such changes.) - * - * The combinations have been tested with these gadgets : - * - zero gadget - * - file storage gadget - * - ether gadget - * - * The driver doesn't use DMA, only IO access and IRQ callbacks. No use is - * made of UDC's double buffering either. USB "On-The-Go" is not implemented. - * - * All the requests are handled the same way : - * - the drivers tries to handle the request directly to the IO - * - if the IO fifo is not big enough, the remaining is send/received in - * interrupt handling. - */ - -#define DRIVER_VERSION "2008-04-18" -#define DRIVER_DESC "PXA 27x USB Device Controller driver" - -static const char driver_name[] = "pxa27x_udc"; -static struct pxa_udc *the_controller; - -static void handle_ep(struct pxa_ep *ep); - -/* - * Debug filesystem - */ -#ifdef CONFIG_USB_GADGET_DEBUG_FS - -#include -#include -#include - -static int state_dbg_show(struct seq_file *s, void *p) -{ - struct pxa_udc *udc = s->private; - int pos = 0, ret; - u32 tmp; - - ret = -ENODEV; - if (!udc->driver) - goto out; - - /* basic device status */ - pos += seq_printf(s, DRIVER_DESC "\n" - "%s version: %s\nGadget driver: %s\n", - driver_name, DRIVER_VERSION, - udc->driver ? udc->driver->driver.name : "(none)"); - - tmp = udc_readl(udc, UDCCR); - pos += seq_printf(s, - "udccr=0x%0x(%s%s%s%s%s%s%s%s%s%s), " - "con=%d,inter=%d,altinter=%d\n", tmp, - (tmp & UDCCR_OEN) ? " oen":"", - (tmp & UDCCR_AALTHNP) ? " aalthnp":"", - (tmp & UDCCR_AHNP) ? " rem" : "", - (tmp & UDCCR_BHNP) ? " rstir" : "", - (tmp & UDCCR_DWRE) ? " dwre" : "", - (tmp & UDCCR_SMAC) ? " smac" : "", - (tmp & UDCCR_EMCE) ? " emce" : "", - (tmp & UDCCR_UDR) ? " udr" : "", - (tmp & UDCCR_UDA) ? " uda" : "", - (tmp & UDCCR_UDE) ? " ude" : "", - (tmp & UDCCR_ACN) >> UDCCR_ACN_S, - (tmp & UDCCR_AIN) >> UDCCR_AIN_S, - (tmp & UDCCR_AAISN) >> UDCCR_AAISN_S); - /* registers for device and ep0 */ - pos += seq_printf(s, "udcicr0=0x%08x udcicr1=0x%08x\n", - udc_readl(udc, UDCICR0), udc_readl(udc, UDCICR1)); - pos += seq_printf(s, "udcisr0=0x%08x udcisr1=0x%08x\n", - udc_readl(udc, UDCISR0), udc_readl(udc, UDCISR1)); - pos += seq_printf(s, "udcfnr=%d\n", udc_readl(udc, UDCFNR)); - pos += seq_printf(s, "irqs: reset=%lu, suspend=%lu, resume=%lu, " - "reconfig=%lu\n", - udc->stats.irqs_reset, udc->stats.irqs_suspend, - udc->stats.irqs_resume, udc->stats.irqs_reconfig); - - ret = 0; -out: - return ret; -} - -static int queues_dbg_show(struct seq_file *s, void *p) -{ - struct pxa_udc *udc = s->private; - struct pxa_ep *ep; - struct pxa27x_request *req; - int pos = 0, i, maxpkt, ret; - - ret = -ENODEV; - if (!udc->driver) - goto out; - - /* dump endpoint queues */ - for (i = 0; i < NR_PXA_ENDPOINTS; i++) { - ep = &udc->pxa_ep[i]; - maxpkt = ep->fifo_size; - pos += seq_printf(s, "%-12s max_pkt=%d %s\n", - EPNAME(ep), maxpkt, "pio"); - - if (list_empty(&ep->queue)) { - pos += seq_printf(s, "\t(nothing queued)\n"); - continue; - } - - list_for_each_entry(req, &ep->queue, queue) { - pos += seq_printf(s, "\treq %p len %d/%d buf %p\n", - &req->req, req->req.actual, - req->req.length, req->req.buf); - } - } - - ret = 0; -out: - return ret; -} - -static int eps_dbg_show(struct seq_file *s, void *p) -{ - struct pxa_udc *udc = s->private; - struct pxa_ep *ep; - int pos = 0, i, ret; - u32 tmp; - - ret = -ENODEV; - if (!udc->driver) - goto out; - - ep = &udc->pxa_ep[0]; - tmp = udc_ep_readl(ep, UDCCSR); - pos += seq_printf(s, "udccsr0=0x%03x(%s%s%s%s%s%s%s)\n", tmp, - (tmp & UDCCSR0_SA) ? " sa" : "", - (tmp & UDCCSR0_RNE) ? " rne" : "", - (tmp & UDCCSR0_FST) ? " fst" : "", - (tmp & UDCCSR0_SST) ? " sst" : "", - (tmp & UDCCSR0_DME) ? " dme" : "", - (tmp & UDCCSR0_IPR) ? " ipr" : "", - (tmp & UDCCSR0_OPC) ? " opc" : ""); - for (i = 0; i < NR_PXA_ENDPOINTS; i++) { - ep = &udc->pxa_ep[i]; - tmp = i? udc_ep_readl(ep, UDCCR) : udc_readl(udc, UDCCR); - pos += seq_printf(s, "%-12s: " - "IN %lu(%lu reqs), OUT %lu(%lu reqs), " - "irqs=%lu, udccr=0x%08x, udccsr=0x%03x, " - "udcbcr=%d\n", - EPNAME(ep), - ep->stats.in_bytes, ep->stats.in_ops, - ep->stats.out_bytes, ep->stats.out_ops, - ep->stats.irqs, - tmp, udc_ep_readl(ep, UDCCSR), - udc_ep_readl(ep, UDCBCR)); - } - - ret = 0; -out: - return ret; -} - -static int eps_dbg_open(struct inode *inode, struct file *file) -{ - return single_open(file, eps_dbg_show, inode->i_private); -} - -static int queues_dbg_open(struct inode *inode, struct file *file) -{ - return single_open(file, queues_dbg_show, inode->i_private); -} - -static int state_dbg_open(struct inode *inode, struct file *file) -{ - return single_open(file, state_dbg_show, inode->i_private); -} - -static const struct file_operations state_dbg_fops = { - .owner = THIS_MODULE, - .open = state_dbg_open, - .llseek = seq_lseek, - .read = seq_read, - .release = single_release, -}; - -static const struct file_operations queues_dbg_fops = { - .owner = THIS_MODULE, - .open = queues_dbg_open, - .llseek = seq_lseek, - .read = seq_read, - .release = single_release, -}; - -static const struct file_operations eps_dbg_fops = { - .owner = THIS_MODULE, - .open = eps_dbg_open, - .llseek = seq_lseek, - .read = seq_read, - .release = single_release, -}; - -static void pxa_init_debugfs(struct pxa_udc *udc) -{ - struct dentry *root, *state, *queues, *eps; - - root = debugfs_create_dir(udc->gadget.name, NULL); - if (IS_ERR(root) || !root) - goto err_root; - - state = debugfs_create_file("udcstate", 0400, root, udc, - &state_dbg_fops); - if (!state) - goto err_state; - queues = debugfs_create_file("queues", 0400, root, udc, - &queues_dbg_fops); - if (!queues) - goto err_queues; - eps = debugfs_create_file("epstate", 0400, root, udc, - &eps_dbg_fops); - if (!eps) - goto err_eps; - - udc->debugfs_root = root; - udc->debugfs_state = state; - udc->debugfs_queues = queues; - udc->debugfs_eps = eps; - return; -err_eps: - debugfs_remove(eps); -err_queues: - debugfs_remove(queues); -err_state: - debugfs_remove(root); -err_root: - dev_err(udc->dev, "debugfs is not available\n"); -} - -static void pxa_cleanup_debugfs(struct pxa_udc *udc) -{ - debugfs_remove(udc->debugfs_eps); - debugfs_remove(udc->debugfs_queues); - debugfs_remove(udc->debugfs_state); - debugfs_remove(udc->debugfs_root); - udc->debugfs_eps = NULL; - udc->debugfs_queues = NULL; - udc->debugfs_state = NULL; - udc->debugfs_root = NULL; -} - -#else -static inline void pxa_init_debugfs(struct pxa_udc *udc) -{ -} - -static inline void pxa_cleanup_debugfs(struct pxa_udc *udc) -{ -} -#endif - -/** - * is_match_usb_pxa - check if usb_ep and pxa_ep match - * @udc_usb_ep: usb endpoint - * @ep: pxa endpoint - * @config: configuration required in pxa_ep - * @interface: interface required in pxa_ep - * @altsetting: altsetting required in pxa_ep - * - * Returns 1 if all criteria match between pxa and usb endpoint, 0 otherwise - */ -static int is_match_usb_pxa(struct udc_usb_ep *udc_usb_ep, struct pxa_ep *ep, - int config, int interface, int altsetting) -{ - if (usb_endpoint_num(&udc_usb_ep->desc) != ep->addr) - return 0; - if (usb_endpoint_dir_in(&udc_usb_ep->desc) != ep->dir_in) - return 0; - if (usb_endpoint_type(&udc_usb_ep->desc) != ep->type) - return 0; - if ((ep->config != config) || (ep->interface != interface) - || (ep->alternate != altsetting)) - return 0; - return 1; -} - -/** - * find_pxa_ep - find pxa_ep structure matching udc_usb_ep - * @udc: pxa udc - * @udc_usb_ep: udc_usb_ep structure - * - * Match udc_usb_ep and all pxa_ep available, to see if one matches. - * This is necessary because of the strong pxa hardware restriction requiring - * that once pxa endpoints are initialized, their configuration is freezed, and - * no change can be made to their address, direction, or in which configuration, - * interface or altsetting they are active ... which differs from more usual - * models which have endpoints be roughly just addressable fifos, and leave - * configuration events up to gadget drivers (like all control messages). - * - * Note that there is still a blurred point here : - * - we rely on UDCCR register "active interface" and "active altsetting". - * This is a nonsense in regard of USB spec, where multiple interfaces are - * active at the same time. - * - if we knew for sure that the pxa can handle multiple interface at the - * same time, assuming Intel's Developer Guide is wrong, this function - * should be reviewed, and a cache of couples (iface, altsetting) should - * be kept in the pxa_udc structure. In this case this function would match - * against the cache of couples instead of the "last altsetting" set up. - * - * Returns the matched pxa_ep structure or NULL if none found - */ -static struct pxa_ep *find_pxa_ep(struct pxa_udc *udc, - struct udc_usb_ep *udc_usb_ep) -{ - int i; - struct pxa_ep *ep; - int cfg = udc->config; - int iface = udc->last_interface; - int alt = udc->last_alternate; - - if (udc_usb_ep == &udc->udc_usb_ep[0]) - return &udc->pxa_ep[0]; - - for (i = 1; i < NR_PXA_ENDPOINTS; i++) { - ep = &udc->pxa_ep[i]; - if (is_match_usb_pxa(udc_usb_ep, ep, cfg, iface, alt)) - return ep; - } - return NULL; -} - -/** - * update_pxa_ep_matches - update pxa_ep cached values in all udc_usb_ep - * @udc: pxa udc - * - * Context: in_interrupt() - * - * Updates all pxa_ep fields in udc_usb_ep structures, if this field was - * previously set up (and is not NULL). The update is necessary is a - * configuration change or altsetting change was issued by the USB host. - */ -static void update_pxa_ep_matches(struct pxa_udc *udc) -{ - int i; - struct udc_usb_ep *udc_usb_ep; - - for (i = 1; i < NR_USB_ENDPOINTS; i++) { - udc_usb_ep = &udc->udc_usb_ep[i]; - if (udc_usb_ep->pxa_ep) - udc_usb_ep->pxa_ep = find_pxa_ep(udc, udc_usb_ep); - } -} - -/** - * pio_irq_enable - Enables irq generation for one endpoint - * @ep: udc endpoint - */ -static void pio_irq_enable(struct pxa_ep *ep) -{ - struct pxa_udc *udc = ep->dev; - int index = EPIDX(ep); - u32 udcicr0 = udc_readl(udc, UDCICR0); - u32 udcicr1 = udc_readl(udc, UDCICR1); - - if (index < 16) - udc_writel(udc, UDCICR0, udcicr0 | (3 << (index * 2))); - else - udc_writel(udc, UDCICR1, udcicr1 | (3 << ((index - 16) * 2))); -} - -/** - * pio_irq_disable - Disables irq generation for one endpoint - * @ep: udc endpoint - */ -static void pio_irq_disable(struct pxa_ep *ep) -{ - struct pxa_udc *udc = ep->dev; - int index = EPIDX(ep); - u32 udcicr0 = udc_readl(udc, UDCICR0); - u32 udcicr1 = udc_readl(udc, UDCICR1); - - if (index < 16) - udc_writel(udc, UDCICR0, udcicr0 & ~(3 << (index * 2))); - else - udc_writel(udc, UDCICR1, udcicr1 & ~(3 << ((index - 16) * 2))); -} - -/** - * udc_set_mask_UDCCR - set bits in UDCCR - * @udc: udc device - * @mask: bits to set in UDCCR - * - * Sets bits in UDCCR, leaving DME and FST bits as they were. - */ -static inline void udc_set_mask_UDCCR(struct pxa_udc *udc, int mask) -{ - u32 udccr = udc_readl(udc, UDCCR); - udc_writel(udc, UDCCR, - (udccr & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS)); -} - -/** - * udc_clear_mask_UDCCR - clears bits in UDCCR - * @udc: udc device - * @mask: bit to clear in UDCCR - * - * Clears bits in UDCCR, leaving DME and FST bits as they were. - */ -static inline void udc_clear_mask_UDCCR(struct pxa_udc *udc, int mask) -{ - u32 udccr = udc_readl(udc, UDCCR); - udc_writel(udc, UDCCR, - (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 - * - * Returns number of bytes in OUT fifos. Broken for IN fifos (-EOPNOTSUPP) - */ -static int ep_count_bytes_remain(struct pxa_ep *ep) -{ - if (ep->dir_in) - return -EOPNOTSUPP; - return udc_ep_readl(ep, UDCBCR) & 0x3ff; -} - -/** - * ep_is_empty - checks if ep has byte ready for reading - * @ep: udc endpoint - * - * If endpoint is the control endpoint, checks if there are bytes in the - * control endpoint fifo. If endpoint is a data endpoint, checks if bytes - * are ready for reading on OUT endpoint. - * - * Returns 0 if ep not empty, 1 if ep empty, -EOPNOTSUPP if IN endpoint - */ -static int ep_is_empty(struct pxa_ep *ep) -{ - int ret; - - if (!is_ep0(ep) && ep->dir_in) - return -EOPNOTSUPP; - if (is_ep0(ep)) - ret = !(udc_ep_readl(ep, UDCCSR) & UDCCSR0_RNE); - else - ret = !(udc_ep_readl(ep, UDCCSR) & UDCCSR_BNE); - return ret; -} - -/** - * ep_is_full - checks if ep has place to write bytes - * @ep: udc endpoint - * - * If endpoint is not the control endpoint and is an IN endpoint, checks if - * there is place to write bytes into the endpoint. - * - * Returns 0 if ep not full, 1 if ep full, -EOPNOTSUPP if OUT endpoint - */ -static int ep_is_full(struct pxa_ep *ep) -{ - if (is_ep0(ep)) - return (udc_ep_readl(ep, UDCCSR) & UDCCSR0_IPR); - if (!ep->dir_in) - return -EOPNOTSUPP; - return (!(udc_ep_readl(ep, UDCCSR) & UDCCSR_BNF)); -} - -/** - * epout_has_pkt - checks if OUT endpoint fifo has a packet available - * @ep: pxa endpoint - * - * Returns 1 if a complete packet is available, 0 if not, -EOPNOTSUPP for IN ep. - */ -static int epout_has_pkt(struct pxa_ep *ep) -{ - if (!is_ep0(ep) && ep->dir_in) - return -EOPNOTSUPP; - if (is_ep0(ep)) - return (udc_ep_readl(ep, UDCCSR) & UDCCSR0_OPC); - return (udc_ep_readl(ep, UDCCSR) & UDCCSR_PC); -} - -/** - * set_ep0state - Set ep0 automata state - * @dev: udc device - * @state: state - */ -static void set_ep0state(struct pxa_udc *udc, int state) -{ - struct pxa_ep *ep = &udc->pxa_ep[0]; - char *old_stname = EP0_STNAME(udc); - - udc->ep0state = state; - ep_dbg(ep, "state=%s->%s, udccsr0=0x%03x, udcbcr=%d\n", old_stname, - EP0_STNAME(udc), udc_ep_readl(ep, UDCCSR), - udc_ep_readl(ep, UDCBCR)); -} - -/** - * ep0_idle - Put control endpoint into idle state - * @dev: udc device - */ -static void ep0_idle(struct pxa_udc *dev) -{ - set_ep0state(dev, WAIT_FOR_SETUP); -} - -/** - * inc_ep_stats_reqs - Update ep stats counts - * @ep: physical endpoint - * @req: usb request - * @is_in: ep direction (USB_DIR_IN or 0) - * - */ -static void inc_ep_stats_reqs(struct pxa_ep *ep, int is_in) -{ - if (is_in) - ep->stats.in_ops++; - else - ep->stats.out_ops++; -} - -/** - * inc_ep_stats_bytes - Update ep stats counts - * @ep: physical endpoint - * @count: bytes transferred on endpoint - * @is_in: ep direction (USB_DIR_IN or 0) - */ -static void inc_ep_stats_bytes(struct pxa_ep *ep, int count, int is_in) -{ - if (is_in) - ep->stats.in_bytes += count; - else - ep->stats.out_bytes += count; -} - -/** - * pxa_ep_setup - Sets up an usb physical endpoint - * @ep: pxa27x physical endpoint - * - * Find the physical pxa27x ep, and setup its UDCCR - */ -static __init void pxa_ep_setup(struct pxa_ep *ep) -{ - u32 new_udccr; - - new_udccr = ((ep->config << UDCCONR_CN_S) & UDCCONR_CN) - | ((ep->interface << UDCCONR_IN_S) & UDCCONR_IN) - | ((ep->alternate << UDCCONR_AISN_S) & UDCCONR_AISN) - | ((EPADDR(ep) << UDCCONR_EN_S) & UDCCONR_EN) - | ((EPXFERTYPE(ep) << UDCCONR_ET_S) & UDCCONR_ET) - | ((ep->dir_in) ? UDCCONR_ED : 0) - | ((ep->fifo_size << UDCCONR_MPS_S) & UDCCONR_MPS) - | UDCCONR_EE; - - udc_ep_writel(ep, UDCCR, new_udccr); -} - -/** - * pxa_eps_setup - Sets up all usb physical endpoints - * @dev: udc device - * - * Setup all pxa physical endpoints, except ep0 - */ -static __init void pxa_eps_setup(struct pxa_udc *dev) -{ - unsigned int i; - - dev_dbg(dev->dev, "%s: dev=%p\n", __func__, dev); - - for (i = 1; i < NR_PXA_ENDPOINTS; i++) - pxa_ep_setup(&dev->pxa_ep[i]); -} - -/** - * pxa_ep_alloc_request - Allocate usb request - * @_ep: usb endpoint - * @gfp_flags: - * - * For the pxa27x, these can just wrap kmalloc/kfree. gadget drivers - * must still pass correctly initialized endpoints, since other controller - * drivers may care about how it's currently set up (dma issues etc). - */ -static struct usb_request * -pxa_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) -{ - struct pxa27x_request *req; - - req = kzalloc(sizeof *req, gfp_flags); - if (!req) - return NULL; - - INIT_LIST_HEAD(&req->queue); - req->in_use = 0; - req->udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); - - return &req->req; -} - -/** - * pxa_ep_free_request - Free usb request - * @_ep: usb endpoint - * @_req: usb request - * - * Wrapper around kfree to free _req - */ -static void pxa_ep_free_request(struct usb_ep *_ep, struct usb_request *_req) -{ - struct pxa27x_request *req; - - req = container_of(_req, struct pxa27x_request, req); - WARN_ON(!list_empty(&req->queue)); - kfree(req); -} - -/** - * ep_add_request - add a request to the endpoint's queue - * @ep: usb endpoint - * @req: usb request - * - * Context: ep->lock held - * - * Queues the request in the endpoint's queue, and enables the interrupts - * on the endpoint. - */ -static void ep_add_request(struct pxa_ep *ep, struct pxa27x_request *req) -{ - if (unlikely(!req)) - return; - ep_vdbg(ep, "req:%p, lg=%d, udccsr=0x%03x\n", req, - req->req.length, udc_ep_readl(ep, UDCCSR)); - - req->in_use = 1; - list_add_tail(&req->queue, &ep->queue); - pio_irq_enable(ep); -} - -/** - * ep_del_request - removes a request from the endpoint's queue - * @ep: usb endpoint - * @req: usb request - * - * Context: ep->lock held - * - * Unqueue the request from the endpoint's queue. If there are no more requests - * on the endpoint, and if it's not the control endpoint, interrupts are - * disabled on the endpoint. - */ -static void ep_del_request(struct pxa_ep *ep, struct pxa27x_request *req) -{ - if (unlikely(!req)) - return; - ep_vdbg(ep, "req:%p, lg=%d, udccsr=0x%03x\n", req, - req->req.length, udc_ep_readl(ep, UDCCSR)); - - list_del_init(&req->queue); - req->in_use = 0; - if (!is_ep0(ep) && list_empty(&ep->queue)) - pio_irq_disable(ep); -} - -/** - * req_done - Complete an usb request - * @ep: pxa physical endpoint - * @req: pxa request - * @status: usb request status sent to gadget API - * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held - * - * Context: ep->lock held if flags not NULL, else ep->lock released - * - * Retire a pxa27x usb request. Endpoint must be locked. - */ -static void req_done(struct pxa_ep *ep, struct pxa27x_request *req, int status, - unsigned long *pflags) -{ - unsigned long flags; - - ep_del_request(ep, req); - if (likely(req->req.status == -EINPROGRESS)) - req->req.status = status; - else - status = req->req.status; - - if (status && status != -ESHUTDOWN) - ep_dbg(ep, "complete req %p stat %d len %u/%u\n", - &req->req, status, - req->req.actual, req->req.length); - - if (pflags) - spin_unlock_irqrestore(&ep->lock, *pflags); - local_irq_save(flags); - req->req.complete(&req->udc_usb_ep->usb_ep, &req->req); - local_irq_restore(flags); - if (pflags) - spin_lock_irqsave(&ep->lock, *pflags); -} - -/** - * ep_end_out_req - Ends endpoint OUT request - * @ep: physical endpoint - * @req: pxa request - * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held - * - * Context: ep->lock held or released (see req_done()) - * - * Ends endpoint OUT request (completes usb request). - */ -static void ep_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req, - unsigned long *pflags) -{ - inc_ep_stats_reqs(ep, !USB_DIR_IN); - req_done(ep, req, 0, pflags); -} - -/** - * ep0_end_out_req - Ends control endpoint OUT request (ends data stage) - * @ep: physical endpoint - * @req: pxa request - * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held - * - * Context: ep->lock held or released (see req_done()) - * - * Ends control endpoint OUT request (completes usb request), and puts - * control endpoint into idle state - */ -static void ep0_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req, - unsigned long *pflags) -{ - set_ep0state(ep->dev, OUT_STATUS_STAGE); - ep_end_out_req(ep, req, pflags); - ep0_idle(ep->dev); -} - -/** - * ep_end_in_req - Ends endpoint IN request - * @ep: physical endpoint - * @req: pxa request - * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held - * - * Context: ep->lock held or released (see req_done()) - * - * Ends endpoint IN request (completes usb request). - */ -static void ep_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req, - unsigned long *pflags) -{ - inc_ep_stats_reqs(ep, USB_DIR_IN); - req_done(ep, req, 0, pflags); -} - -/** - * ep0_end_in_req - Ends control endpoint IN request (ends data stage) - * @ep: physical endpoint - * @req: pxa request - * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held - * - * Context: ep->lock held or released (see req_done()) - * - * Ends control endpoint IN request (completes usb request), and puts - * control endpoint into status state - */ -static void ep0_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req, - unsigned long *pflags) -{ - set_ep0state(ep->dev, IN_STATUS_STAGE); - ep_end_in_req(ep, req, pflags); -} - -/** - * nuke - Dequeue all requests - * @ep: pxa endpoint - * @status: usb request status - * - * Context: ep->lock released - * - * Dequeues all requests on an endpoint. As a side effect, interrupts will be - * disabled on that endpoint (because no more requests). - */ -static void nuke(struct pxa_ep *ep, int status) -{ - struct pxa27x_request *req; - unsigned long flags; - - spin_lock_irqsave(&ep->lock, flags); - while (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, struct pxa27x_request, queue); - req_done(ep, req, status, &flags); - } - spin_unlock_irqrestore(&ep->lock, flags); -} - -/** - * read_packet - transfer 1 packet from an OUT endpoint into request - * @ep: pxa physical endpoint - * @req: usb request - * - * Takes bytes from OUT endpoint and transfers them info the usb request. - * If there is less space in request than bytes received in OUT endpoint, - * bytes are left in the OUT endpoint. - * - * Returns how many bytes were actually transferred - */ -static int read_packet(struct pxa_ep *ep, struct pxa27x_request *req) -{ - u32 *buf; - int bytes_ep, bufferspace, count, i; - - bytes_ep = ep_count_bytes_remain(ep); - bufferspace = req->req.length - req->req.actual; - - buf = (u32 *)(req->req.buf + req->req.actual); - prefetchw(buf); - - if (likely(!ep_is_empty(ep))) - count = min(bytes_ep, bufferspace); - else /* zlp */ - count = 0; - - for (i = count; i > 0; i -= 4) - *buf++ = udc_ep_readl(ep, UDCDR); - req->req.actual += count; - - ep_write_UDCCSR(ep, UDCCSR_PC); - - return count; -} - -/** - * write_packet - transfer 1 packet from request into an IN endpoint - * @ep: pxa physical endpoint - * @req: usb request - * @max: max bytes that fit into endpoint - * - * Takes bytes from usb request, and transfers them into the physical - * endpoint. If there are no bytes to transfer, doesn't write anything - * to physical endpoint. - * - * Returns how many bytes were actually transferred. - */ -static int write_packet(struct pxa_ep *ep, struct pxa27x_request *req, - unsigned int max) -{ - int length, count, remain, i; - u32 *buf; - u8 *buf_8; - - buf = (u32 *)(req->req.buf + req->req.actual); - prefetch(buf); - - length = min(req->req.length - req->req.actual, max); - req->req.actual += length; - - remain = length & 0x3; - count = length & ~(0x3); - for (i = count; i > 0 ; i -= 4) - udc_ep_writel(ep, UDCDR, *buf++); - - buf_8 = (u8 *)buf; - for (i = remain; i > 0; i--) - udc_ep_writeb(ep, UDCDR, *buf_8++); - - ep_vdbg(ep, "length=%d+%d, udccsr=0x%03x\n", count, remain, - udc_ep_readl(ep, UDCCSR)); - - return length; -} - -/** - * read_fifo - Transfer packets from OUT endpoint into usb request - * @ep: pxa physical endpoint - * @req: usb request - * - * Context: callable when in_interrupt() - * - * Unload as many packets as possible from the fifo we use for usb OUT - * transfers and put them into the request. Caller should have made sure - * there's at least one packet ready. - * Doesn't complete the request, that's the caller's job - * - * Returns 1 if the request completed, 0 otherwise - */ -static int read_fifo(struct pxa_ep *ep, struct pxa27x_request *req) -{ - int count, is_short, completed = 0; - - while (epout_has_pkt(ep)) { - count = read_packet(ep, req); - inc_ep_stats_bytes(ep, count, !USB_DIR_IN); - - is_short = (count < ep->fifo_size); - ep_dbg(ep, "read udccsr:%03x, count:%d bytes%s req %p %d/%d\n", - udc_ep_readl(ep, UDCCSR), count, is_short ? "/S" : "", - &req->req, req->req.actual, req->req.length); - - /* completion */ - if (is_short || req->req.actual == req->req.length) { - completed = 1; - break; - } - /* finished that packet. the next one may be waiting... */ - } - return completed; -} - -/** - * write_fifo - transfer packets from usb request into an IN endpoint - * @ep: pxa physical endpoint - * @req: pxa usb request - * - * Write to an IN endpoint fifo, as many packets as possible. - * irqs will use this to write the rest later. - * caller guarantees at least one packet buffer is ready (or a zlp). - * Doesn't complete the request, that's the caller's job - * - * Returns 1 if request fully transferred, 0 if partial transfer - */ -static int write_fifo(struct pxa_ep *ep, struct pxa27x_request *req) -{ - unsigned max; - int count, is_short, is_last = 0, completed = 0, totcount = 0; - u32 udccsr; - - max = ep->fifo_size; - do { - is_short = 0; - - udccsr = udc_ep_readl(ep, UDCCSR); - if (udccsr & UDCCSR_PC) { - ep_vdbg(ep, "Clearing Transmit Complete, udccsr=%x\n", - udccsr); - ep_write_UDCCSR(ep, UDCCSR_PC); - } - if (udccsr & UDCCSR_TRN) { - ep_vdbg(ep, "Clearing Underrun on, udccsr=%x\n", - udccsr); - ep_write_UDCCSR(ep, UDCCSR_TRN); - } - - count = write_packet(ep, req, max); - inc_ep_stats_bytes(ep, count, USB_DIR_IN); - totcount += count; - - /* last packet is usually short (or a zlp) */ - if (unlikely(count < max)) { - is_last = 1; - is_short = 1; - } else { - if (likely(req->req.length > req->req.actual) - || req->req.zero) - is_last = 0; - else - is_last = 1; - /* interrupt/iso maxpacket may not fill the fifo */ - is_short = unlikely(max < ep->fifo_size); - } - - if (is_short) - ep_write_UDCCSR(ep, UDCCSR_SP); - - /* requests complete when all IN data is in the FIFO */ - if (is_last) { - completed = 1; - break; - } - } while (!ep_is_full(ep)); - - ep_dbg(ep, "wrote count:%d bytes%s%s, left:%d req=%p\n", - totcount, is_last ? "/L" : "", is_short ? "/S" : "", - req->req.length - req->req.actual, &req->req); - - return completed; -} - -/** - * read_ep0_fifo - Transfer packets from control endpoint into usb request - * @ep: control endpoint - * @req: pxa usb request - * - * Special ep0 version of the above read_fifo. Reads as many bytes from control - * endpoint as can be read, and stores them into usb request (limited by request - * maximum length). - * - * Returns 0 if usb request only partially filled, 1 if fully filled - */ -static int read_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req) -{ - int count, is_short, completed = 0; - - while (epout_has_pkt(ep)) { - count = read_packet(ep, req); - ep_write_UDCCSR(ep, UDCCSR0_OPC); - inc_ep_stats_bytes(ep, count, !USB_DIR_IN); - - is_short = (count < ep->fifo_size); - ep_dbg(ep, "read udccsr:%03x, count:%d bytes%s req %p %d/%d\n", - udc_ep_readl(ep, UDCCSR), count, is_short ? "/S" : "", - &req->req, req->req.actual, req->req.length); - - if (is_short || req->req.actual >= req->req.length) { - completed = 1; - break; - } - } - - return completed; -} - -/** - * write_ep0_fifo - Send a request to control endpoint (ep0 in) - * @ep: control endpoint - * @req: request - * - * Context: callable when in_interrupt() - * - * Sends a request (or a part of the request) to the control endpoint (ep0 in). - * If the request doesn't fit, the remaining part will be sent from irq. - * The request is considered fully written only if either : - * - last write transferred all remaining bytes, but fifo was not fully filled - * - last write was a 0 length write - * - * Returns 1 if request fully written, 0 if request only partially sent - */ -static int write_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req) -{ - unsigned count; - int is_last, is_short; - - count = write_packet(ep, req, EP0_FIFO_SIZE); - inc_ep_stats_bytes(ep, count, USB_DIR_IN); - - is_short = (count < EP0_FIFO_SIZE); - is_last = ((count == 0) || (count < EP0_FIFO_SIZE)); - - /* Sends either a short packet or a 0 length packet */ - if (unlikely(is_short)) - 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" : "", - req->req.length - req->req.actual, - &req->req, udc_ep_readl(ep, UDCCSR)); - - return is_last; -} - -/** - * pxa_ep_queue - Queue a request into an IN endpoint - * @_ep: usb endpoint - * @_req: usb request - * @gfp_flags: flags - * - * Context: normally called when !in_interrupt, but callable when in_interrupt() - * in the special case of ep0 setup : - * (irq->handle_ep0_ctrl_req->gadget_setup->pxa_ep_queue) - * - * Returns 0 if succedeed, error otherwise - */ -static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req, - gfp_t gfp_flags) -{ - struct udc_usb_ep *udc_usb_ep; - struct pxa_ep *ep; - struct pxa27x_request *req; - struct pxa_udc *dev; - unsigned long flags; - int rc = 0; - int is_first_req; - unsigned length; - int recursion_detected; - - req = container_of(_req, struct pxa27x_request, req); - udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); - - if (unlikely(!_req || !_req->complete || !_req->buf)) - return -EINVAL; - - if (unlikely(!_ep)) - return -EINVAL; - - dev = udc_usb_ep->dev; - ep = udc_usb_ep->pxa_ep; - if (unlikely(!ep)) - return -EINVAL; - - dev = ep->dev; - if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) { - ep_dbg(ep, "bogus device state\n"); - return -ESHUTDOWN; - } - - /* iso is always one packet per request, that's the only way - * we can report per-packet status. that also helps with dma. - */ - if (unlikely(EPXFERTYPE_is_ISO(ep) - && req->req.length > ep->fifo_size)) - return -EMSGSIZE; - - spin_lock_irqsave(&ep->lock, flags); - recursion_detected = ep->in_handle_ep; - - is_first_req = list_empty(&ep->queue); - ep_dbg(ep, "queue req %p(first=%s), len %d buf %p\n", - _req, is_first_req ? "yes" : "no", - _req->length, _req->buf); - - if (!ep->enabled) { - _req->status = -ESHUTDOWN; - rc = -ESHUTDOWN; - goto out_locked; - } - - if (req->in_use) { - ep_err(ep, "refusing to queue req %p (already queued)\n", req); - goto out_locked; - } - - length = _req->length; - _req->status = -EINPROGRESS; - _req->actual = 0; - - ep_add_request(ep, req); - spin_unlock_irqrestore(&ep->lock, flags); - - if (is_ep0(ep)) { - switch (dev->ep0state) { - case WAIT_ACK_SET_CONF_INTERF: - if (length == 0) { - ep_end_in_req(ep, req, NULL); - } else { - ep_err(ep, "got a request of %d bytes while" - "in state WAIT_ACK_SET_CONF_INTERF\n", - length); - ep_del_request(ep, req); - rc = -EL2HLT; - } - ep0_idle(ep->dev); - break; - case IN_DATA_STAGE: - if (!ep_is_full(ep)) - if (write_ep0_fifo(ep, req)) - ep0_end_in_req(ep, req, NULL); - break; - case OUT_DATA_STAGE: - if ((length == 0) || !epout_has_pkt(ep)) - if (read_ep0_fifo(ep, req)) - ep0_end_out_req(ep, req, NULL); - break; - default: - ep_err(ep, "odd state %s to send me a request\n", - EP0_STNAME(ep->dev)); - ep_del_request(ep, req); - rc = -EL2HLT; - break; - } - } else { - if (!recursion_detected) - handle_ep(ep); - } - -out: - return rc; -out_locked: - spin_unlock_irqrestore(&ep->lock, flags); - goto out; -} - -/** - * pxa_ep_dequeue - Dequeue one request - * @_ep: usb endpoint - * @_req: usb request - * - * Return 0 if no error, -EINVAL or -ECONNRESET otherwise - */ -static int pxa_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct pxa_ep *ep; - struct udc_usb_ep *udc_usb_ep; - struct pxa27x_request *req; - unsigned long flags; - int rc = -EINVAL; - - if (!_ep) - return rc; - udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); - ep = udc_usb_ep->pxa_ep; - if (!ep || is_ep0(ep)) - return rc; - - spin_lock_irqsave(&ep->lock, flags); - - /* make sure it's actually queued on this endpoint */ - list_for_each_entry(req, &ep->queue, queue) { - if (&req->req == _req) { - rc = 0; - break; - } - } - - spin_unlock_irqrestore(&ep->lock, flags); - if (!rc) - req_done(ep, req, -ECONNRESET, NULL); - return rc; -} - -/** - * pxa_ep_set_halt - Halts operations on one endpoint - * @_ep: usb endpoint - * @value: - * - * Returns 0 if no error, -EINVAL, -EROFS, -EAGAIN otherwise - */ -static int pxa_ep_set_halt(struct usb_ep *_ep, int value) -{ - struct pxa_ep *ep; - struct udc_usb_ep *udc_usb_ep; - unsigned long flags; - int rc; - - - if (!_ep) - return -EINVAL; - udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); - ep = udc_usb_ep->pxa_ep; - if (!ep || is_ep0(ep)) - return -EINVAL; - - if (value == 0) { - /* - * This path (reset toggle+halt) is needed to implement - * SET_INTERFACE on normal hardware. but it can't be - * done from software on the PXA UDC, and the hardware - * forgets to do it as part of SET_INTERFACE automagic. - */ - ep_dbg(ep, "only host can clear halt\n"); - return -EROFS; - } - - spin_lock_irqsave(&ep->lock, flags); - - rc = -EAGAIN; - if (ep->dir_in && (ep_is_full(ep) || !list_empty(&ep->queue))) - goto out; - - /* FST, FEF bits are the same for control and non control endpoints */ - rc = 0; - ep_write_UDCCSR(ep, UDCCSR_FST | UDCCSR_FEF); - if (is_ep0(ep)) - set_ep0state(ep->dev, STALL); - -out: - spin_unlock_irqrestore(&ep->lock, flags); - return rc; -} - -/** - * pxa_ep_fifo_status - Get how many bytes in physical endpoint - * @_ep: usb endpoint - * - * Returns number of bytes in OUT fifos. Broken for IN fifos. - */ -static int pxa_ep_fifo_status(struct usb_ep *_ep) -{ - struct pxa_ep *ep; - struct udc_usb_ep *udc_usb_ep; - - if (!_ep) - return -ENODEV; - udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); - ep = udc_usb_ep->pxa_ep; - if (!ep || is_ep0(ep)) - return -ENODEV; - - if (ep->dir_in) - return -EOPNOTSUPP; - if (ep->dev->gadget.speed == USB_SPEED_UNKNOWN || ep_is_empty(ep)) - return 0; - else - return ep_count_bytes_remain(ep) + 1; -} - -/** - * pxa_ep_fifo_flush - Flushes one endpoint - * @_ep: usb endpoint - * - * Discards all data in one endpoint(IN or OUT), except control endpoint. - */ -static void pxa_ep_fifo_flush(struct usb_ep *_ep) -{ - struct pxa_ep *ep; - struct udc_usb_ep *udc_usb_ep; - unsigned long flags; - - if (!_ep) - return; - udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); - ep = udc_usb_ep->pxa_ep; - if (!ep || is_ep0(ep)) - return; - - spin_lock_irqsave(&ep->lock, flags); - - if (unlikely(!list_empty(&ep->queue))) - ep_dbg(ep, "called while queue list not empty\n"); - ep_dbg(ep, "called\n"); - - /* for OUT, just read and discard the FIFO contents. */ - if (!ep->dir_in) { - while (!ep_is_empty(ep)) - udc_ep_readl(ep, UDCDR); - } else { - /* most IN status is the same, but ISO can't stall */ - ep_write_UDCCSR(ep, - UDCCSR_PC | UDCCSR_FEF | UDCCSR_TRN - | (EPXFERTYPE_is_ISO(ep) ? 0 : UDCCSR_SST)); - } - - spin_unlock_irqrestore(&ep->lock, flags); -} - -/** - * pxa_ep_enable - Enables usb endpoint - * @_ep: usb endpoint - * @desc: usb endpoint descriptor - * - * Nothing much to do here, as ep configuration is done once and for all - * before udc is enabled. After udc enable, no physical endpoint configuration - * can be changed. - * Function makes sanity checks and flushes the endpoint. - */ -static int pxa_ep_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct pxa_ep *ep; - struct udc_usb_ep *udc_usb_ep; - struct pxa_udc *udc; - - if (!_ep || !desc) - return -EINVAL; - - udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); - if (udc_usb_ep->pxa_ep) { - ep = udc_usb_ep->pxa_ep; - ep_warn(ep, "usb_ep %s already enabled, doing nothing\n", - _ep->name); - } else { - ep = find_pxa_ep(udc_usb_ep->dev, udc_usb_ep); - } - - if (!ep || is_ep0(ep)) { - dev_err(udc_usb_ep->dev->dev, - "unable to match pxa_ep for ep %s\n", - _ep->name); - return -EINVAL; - } - - if ((desc->bDescriptorType != USB_DT_ENDPOINT) - || (ep->type != usb_endpoint_type(desc))) { - ep_err(ep, "type mismatch\n"); - return -EINVAL; - } - - if (ep->fifo_size < usb_endpoint_maxp(desc)) { - ep_err(ep, "bad maxpacket\n"); - return -ERANGE; - } - - udc_usb_ep->pxa_ep = ep; - udc = ep->dev; - - if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) { - ep_err(ep, "bogus device state\n"); - return -ESHUTDOWN; - } - - ep->enabled = 1; - - /* flush fifo (mostly for OUT buffers) */ - pxa_ep_fifo_flush(_ep); - - ep_dbg(ep, "enabled\n"); - return 0; -} - -/** - * pxa_ep_disable - Disable usb endpoint - * @_ep: usb endpoint - * - * Same as for pxa_ep_enable, no physical endpoint configuration can be - * changed. - * Function flushes the endpoint and related requests. - */ -static int pxa_ep_disable(struct usb_ep *_ep) -{ - struct pxa_ep *ep; - struct udc_usb_ep *udc_usb_ep; - - if (!_ep) - return -EINVAL; - - udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep); - ep = udc_usb_ep->pxa_ep; - if (!ep || is_ep0(ep) || !list_empty(&ep->queue)) - return -EINVAL; - - ep->enabled = 0; - nuke(ep, -ESHUTDOWN); - - pxa_ep_fifo_flush(_ep); - udc_usb_ep->pxa_ep = NULL; - - ep_dbg(ep, "disabled\n"); - return 0; -} - -static struct usb_ep_ops pxa_ep_ops = { - .enable = pxa_ep_enable, - .disable = pxa_ep_disable, - - .alloc_request = pxa_ep_alloc_request, - .free_request = pxa_ep_free_request, - - .queue = pxa_ep_queue, - .dequeue = pxa_ep_dequeue, - - .set_halt = pxa_ep_set_halt, - .fifo_status = pxa_ep_fifo_status, - .fifo_flush = pxa_ep_fifo_flush, -}; - -/** - * dplus_pullup - Connect or disconnect pullup resistor to D+ pin - * @udc: udc device - * @on: 0 if disconnect pullup resistor, 1 otherwise - * Context: any - * - * Handle D+ pullup resistor, make the device visible to the usb bus, and - * declare it as a full speed usb device - */ -static void dplus_pullup(struct pxa_udc *udc, int on) -{ - if (on) { - if (gpio_is_valid(udc->mach->gpio_pullup)) - gpio_set_value(udc->mach->gpio_pullup, - !udc->mach->gpio_pullup_inverted); - if (udc->mach->udc_command) - udc->mach->udc_command(PXA2XX_UDC_CMD_CONNECT); - } else { - if (gpio_is_valid(udc->mach->gpio_pullup)) - gpio_set_value(udc->mach->gpio_pullup, - udc->mach->gpio_pullup_inverted); - if (udc->mach->udc_command) - udc->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); - } - udc->pullup_on = on; -} - -/** - * pxa_udc_get_frame - Returns usb frame number - * @_gadget: usb gadget - */ -static int pxa_udc_get_frame(struct usb_gadget *_gadget) -{ - struct pxa_udc *udc = to_gadget_udc(_gadget); - - return (udc_readl(udc, UDCFNR) & 0x7ff); -} - -/** - * pxa_udc_wakeup - Force udc device out of suspend - * @_gadget: usb gadget - * - * Returns 0 if successful, error code otherwise - */ -static int pxa_udc_wakeup(struct usb_gadget *_gadget) -{ - struct pxa_udc *udc = to_gadget_udc(_gadget); - - /* host may not have enabled remote wakeup */ - if ((udc_readl(udc, UDCCR) & UDCCR_DWRE) == 0) - return -EHOSTUNREACH; - udc_set_mask_UDCCR(udc, UDCCR_UDR); - return 0; -} - -static void udc_enable(struct pxa_udc *udc); -static void udc_disable(struct pxa_udc *udc); - -/** - * should_enable_udc - Tells if UDC should be enabled - * @udc: udc device - * Context: any - * - * The UDC should be enabled if : - - * - the pullup resistor is connected - * - and a gadget driver is bound - * - and vbus is sensed (or no vbus sense is available) - * - * Returns 1 if UDC should be enabled, 0 otherwise - */ -static int should_enable_udc(struct pxa_udc *udc) -{ - int put_on; - - put_on = ((udc->pullup_on) && (udc->driver)); - put_on &= ((udc->vbus_sensed) || (!udc->transceiver)); - return put_on; -} - -/** - * should_disable_udc - Tells if UDC should be disabled - * @udc: udc device - * Context: any - * - * The UDC should be disabled if : - * - the pullup resistor is not connected - * - or no gadget driver is bound - * - or no vbus is sensed (when vbus sesing is available) - * - * Returns 1 if UDC should be disabled - */ -static int should_disable_udc(struct pxa_udc *udc) -{ - int put_off; - - put_off = ((!udc->pullup_on) || (!udc->driver)); - put_off |= ((!udc->vbus_sensed) && (udc->transceiver)); - return put_off; -} - -/** - * pxa_udc_pullup - Offer manual D+ pullup control - * @_gadget: usb gadget using the control - * @is_active: 0 if disconnect, else connect D+ pullup resistor - * Context: !in_interrupt() - * - * Returns 0 if OK, -EOPNOTSUPP if udc driver doesn't handle D+ pullup - */ -static int pxa_udc_pullup(struct usb_gadget *_gadget, int is_active) -{ - struct pxa_udc *udc = to_gadget_udc(_gadget); - - if (!gpio_is_valid(udc->mach->gpio_pullup) && !udc->mach->udc_command) - return -EOPNOTSUPP; - - dplus_pullup(udc, is_active); - - if (should_enable_udc(udc)) - udc_enable(udc); - if (should_disable_udc(udc)) - udc_disable(udc); - return 0; -} - -static void udc_enable(struct pxa_udc *udc); -static void udc_disable(struct pxa_udc *udc); - -/** - * pxa_udc_vbus_session - Called by external transceiver to enable/disable udc - * @_gadget: usb gadget - * @is_active: 0 if should disable the udc, 1 if should enable - * - * Enables the udc, and optionnaly activates D+ pullup resistor. Or disables the - * udc, and deactivates D+ pullup resistor. - * - * Returns 0 - */ -static int pxa_udc_vbus_session(struct usb_gadget *_gadget, int is_active) -{ - struct pxa_udc *udc = to_gadget_udc(_gadget); - - udc->vbus_sensed = is_active; - if (should_enable_udc(udc)) - udc_enable(udc); - if (should_disable_udc(udc)) - udc_disable(udc); - - return 0; -} - -/** - * pxa_udc_vbus_draw - Called by gadget driver after SET_CONFIGURATION completed - * @_gadget: usb gadget - * @mA: current drawn - * - * Context: !in_interrupt() - * - * Called after a configuration was chosen by a USB host, to inform how much - * current can be drawn by the device from VBus line. - * - * Returns 0 or -EOPNOTSUPP if no transceiver is handling the udc - */ -static int pxa_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA) -{ - struct pxa_udc *udc; - - udc = to_gadget_udc(_gadget); - if (udc->transceiver) - return usb_phy_set_power(udc->transceiver, mA); - return -EOPNOTSUPP; -} - -static int pxa27x_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int pxa27x_udc_stop(struct usb_gadget_driver *driver); - -static const struct usb_gadget_ops pxa_udc_ops = { - .get_frame = pxa_udc_get_frame, - .wakeup = pxa_udc_wakeup, - .pullup = pxa_udc_pullup, - .vbus_session = pxa_udc_vbus_session, - .vbus_draw = pxa_udc_vbus_draw, - .start = pxa27x_udc_start, - .stop = pxa27x_udc_stop, -}; - -/** - * udc_disable - disable udc device controller - * @udc: udc device - * Context: any - * - * Disables the udc device : disables clocks, udc interrupts, control endpoint - * interrupts. - */ -static void udc_disable(struct pxa_udc *udc) -{ - if (!udc->enabled) - return; - - udc_writel(udc, UDCICR0, 0); - udc_writel(udc, UDCICR1, 0); - - udc_clear_mask_UDCCR(udc, UDCCR_UDE); - clk_disable(udc->clk); - - ep0_idle(udc); - udc->gadget.speed = USB_SPEED_UNKNOWN; - - udc->enabled = 0; -} - -/** - * udc_init_data - Initialize udc device data structures - * @dev: udc device - * - * Initializes gadget endpoint list, endpoints locks. No action is taken - * on the hardware. - */ -static __init void udc_init_data(struct pxa_udc *dev) -{ - int i; - struct pxa_ep *ep; - - /* device/ep0 records init */ - INIT_LIST_HEAD(&dev->gadget.ep_list); - INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); - dev->udc_usb_ep[0].pxa_ep = &dev->pxa_ep[0]; - ep0_idle(dev); - - /* PXA endpoints init */ - for (i = 0; i < NR_PXA_ENDPOINTS; i++) { - ep = &dev->pxa_ep[i]; - - ep->enabled = is_ep0(ep); - INIT_LIST_HEAD(&ep->queue); - spin_lock_init(&ep->lock); - } - - /* USB endpoints init */ - for (i = 1; i < NR_USB_ENDPOINTS; i++) - list_add_tail(&dev->udc_usb_ep[i].usb_ep.ep_list, - &dev->gadget.ep_list); -} - -/** - * udc_enable - Enables the udc device - * @dev: udc device - * - * Enables the udc device : enables clocks, udc interrupts, control endpoint - * interrupts, sets usb as UDC client and setups endpoints. - */ -static void udc_enable(struct pxa_udc *udc) -{ - if (udc->enabled) - return; - - udc_writel(udc, UDCICR0, 0); - udc_writel(udc, UDCICR1, 0); - udc_clear_mask_UDCCR(udc, UDCCR_UDE); - - clk_enable(udc->clk); - - ep0_idle(udc); - udc->gadget.speed = USB_SPEED_FULL; - 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"); - - /* - * Caller must be able to sleep in order to cope with startup transients - */ - msleep(100); - - /* enable suspend/resume and reset irqs */ - udc_writel(udc, UDCICR1, - UDCICR1_IECC | UDCICR1_IERU - | UDCICR1_IESU | UDCICR1_IERS); - - /* enable ep0 irqs */ - pio_irq_enable(&udc->pxa_ep[0]); - - udc->enabled = 1; -} - -/** - * pxa27x_start - Register gadget driver - * @driver: gadget driver - * @bind: bind function - * - * When a driver is successfully registered, it will receive control requests - * including set_configuration(), which enables non-control requests. Then - * usb traffic follows until a disconnect is reported. Then a host may connect - * again, or the driver might get unbound. - * - * Note that the udc is not automatically enabled. Check function - * should_enable_udc(). - * - * Returns 0 if no error, -EINVAL, -ENODEV, -EBUSY otherwise - */ -static int pxa27x_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) -{ - struct pxa_udc *udc = the_controller; - int retval; - - if (!driver || driver->max_speed < USB_SPEED_FULL || !bind - || !driver->disconnect || !driver->setup) - return -EINVAL; - if (!udc) - return -ENODEV; - if (udc->driver) - return -EBUSY; - - /* first hook up the driver ... */ - udc->driver = driver; - udc->gadget.dev.driver = &driver->driver; - dplus_pullup(udc, 1); - - retval = device_add(&udc->gadget.dev); - if (retval) { - dev_err(udc->dev, "device_add error %d\n", retval); - goto add_fail; - } - retval = bind(&udc->gadget); - if (retval) { - dev_err(udc->dev, "bind to driver %s --> error %d\n", - driver->driver.name, retval); - goto bind_fail; - } - dev_dbg(udc->dev, "registered gadget driver '%s'\n", - driver->driver.name); - - if (udc->transceiver) { - retval = otg_set_peripheral(udc->transceiver->otg, - &udc->gadget); - if (retval) { - dev_err(udc->dev, "can't bind to transceiver\n"); - goto transceiver_fail; - } - } - - if (should_enable_udc(udc)) - udc_enable(udc); - return 0; - -transceiver_fail: - if (driver->unbind) - driver->unbind(&udc->gadget); -bind_fail: - device_del(&udc->gadget.dev); -add_fail: - udc->driver = NULL; - udc->gadget.dev.driver = NULL; - return retval; -} - -/** - * stop_activity - Stops udc endpoints - * @udc: udc device - * @driver: gadget driver - * - * Disables all udc endpoints (even control endpoint), report disconnect to - * the gadget user. - */ -static void stop_activity(struct pxa_udc *udc, struct usb_gadget_driver *driver) -{ - int i; - - /* don't disconnect drivers more than once */ - if (udc->gadget.speed == USB_SPEED_UNKNOWN) - driver = NULL; - udc->gadget.speed = USB_SPEED_UNKNOWN; - - for (i = 0; i < NR_USB_ENDPOINTS; i++) - pxa_ep_disable(&udc->udc_usb_ep[i].usb_ep); - - if (driver) - driver->disconnect(&udc->gadget); -} - -/** - * pxa27x_udc_stop - Unregister the gadget driver - * @driver: gadget driver - * - * Returns 0 if no error, -ENODEV, -EINVAL otherwise - */ -static int pxa27x_udc_stop(struct usb_gadget_driver *driver) -{ - struct pxa_udc *udc = the_controller; - - if (!udc) - return -ENODEV; - if (!driver || driver != udc->driver || !driver->unbind) - return -EINVAL; - - stop_activity(udc, driver); - udc_disable(udc); - dplus_pullup(udc, 0); - - driver->unbind(&udc->gadget); - udc->driver = NULL; - - device_del(&udc->gadget.dev); - dev_info(udc->dev, "unregistered gadget driver '%s'\n", - driver->driver.name); - - if (udc->transceiver) - return otg_set_peripheral(udc->transceiver->otg, NULL); - return 0; -} - -/** - * handle_ep0_ctrl_req - handle control endpoint control request - * @udc: udc device - * @req: control request - */ -static void handle_ep0_ctrl_req(struct pxa_udc *udc, - struct pxa27x_request *req) -{ - struct pxa_ep *ep = &udc->pxa_ep[0]; - union { - struct usb_ctrlrequest r; - u32 word[2]; - } u; - int i; - int have_extrabytes = 0; - unsigned long flags; - - nuke(ep, -EPROTO); - spin_lock_irqsave(&ep->lock, flags); - - /* - * 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))) - goto stall; - u.word[i] = udc_ep_readl(ep, UDCDR); - } - - have_extrabytes = !ep_is_empty(ep); - while (!ep_is_empty(ep)) { - i = udc_ep_readl(ep, UDCDR); - ep_err(ep, "wrong to have extra bytes for setup : 0x%08x\n", i); - } - - ep_dbg(ep, "SETUP %02x.%02x v%04x i%04x l%04x\n", - u.r.bRequestType, u.r.bRequest, - le16_to_cpu(u.r.wValue), le16_to_cpu(u.r.wIndex), - le16_to_cpu(u.r.wLength)); - if (unlikely(have_extrabytes)) - goto stall; - - if (u.r.bRequestType & USB_DIR_IN) - set_ep0state(udc, IN_DATA_STAGE); - else - set_ep0state(udc, OUT_DATA_STAGE); - - /* Tell UDC to enter Data Stage */ - ep_write_UDCCSR(ep, UDCCSR0_SA | UDCCSR0_OPC); - - spin_unlock_irqrestore(&ep->lock, flags); - i = udc->driver->setup(&udc->gadget, &u.r); - spin_lock_irqsave(&ep->lock, flags); - if (i < 0) - goto stall; -out: - spin_unlock_irqrestore(&ep->lock, flags); - return; -stall: - ep_dbg(ep, "protocol STALL, udccsr0=%03x err %d\n", - udc_ep_readl(ep, UDCCSR), i); - ep_write_UDCCSR(ep, UDCCSR0_FST | UDCCSR0_FTF); - set_ep0state(udc, STALL); - goto out; -} - -/** - * handle_ep0 - Handle control endpoint data transfers - * @udc: udc device - * @fifo_irq: 1 if triggered by fifo service type irq - * @opc_irq: 1 if triggered by output packet complete type irq - * - * Context : when in_interrupt() or with ep->lock held - * - * Tries to transfer all pending request data into the endpoint and/or - * transfer all pending data in the endpoint into usb requests. - * Handles states of ep0 automata. - * - * PXA27x hardware handles several standard usb control requests without - * driver notification. The requests fully handled by hardware are : - * SET_ADDRESS, SET_FEATURE, CLEAR_FEATURE, GET_CONFIGURATION, GET_INTERFACE, - * GET_STATUS - * The requests handled by hardware, but with irq notification are : - * SYNCH_FRAME, SET_CONFIGURATION, SET_INTERFACE - * The remaining standard requests really handled by handle_ep0 are : - * GET_DESCRIPTOR, SET_DESCRIPTOR, specific requests. - * Requests standardized outside of USB 2.0 chapter 9 are handled more - * uniformly, by gadget drivers. - * - * The control endpoint state machine is _not_ USB spec compliant, it's even - * hardly compliant with Intel PXA270 developers guide. - * The key points which inferred this state machine are : - * - on every setup token, bit UDCCSR0_SA is raised and held until cleared by - * software. - * - on every OUT packet received, UDCCSR0_OPC is raised and held until - * 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). - * - as UDCCSR0_SA can be activated while in irq handling, and clearing - * UDCCSR0_OPC would flush the setup data, we almost never clear UDCCSR0_OPC - * => we never actually read the "status stage" packet of an IN data stage - * => this is not documented in Intel documentation - * - hardware as no idea of STATUS STAGE, it only handle SETUP STAGE and DATA - * STAGE. The driver add STATUS STAGE to send last zero length packet in - * OUT_STATUS_STAGE. - * - special attention was needed for IN_STATUS_STAGE. If a packet complete - * event is detected, we terminate the status stage without ackowledging the - * packet (not to risk to loose a potential SETUP packet) - */ -static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq) -{ - u32 udccsr0; - struct pxa_ep *ep = &udc->pxa_ep[0]; - struct pxa27x_request *req = NULL; - int completed = 0; - - if (!list_empty(&ep->queue)) - req = list_entry(ep->queue.next, struct pxa27x_request, queue); - - udccsr0 = udc_ep_readl(ep, UDCCSR); - ep_dbg(ep, "state=%s, req=%p, udccsr0=0x%03x, udcbcr=%d, irq_msk=%x\n", - EP0_STNAME(udc), req, udccsr0, udc_ep_readl(ep, UDCBCR), - (fifo_irq << 1 | opc_irq)); - - if (udccsr0 & UDCCSR0_SST) { - ep_dbg(ep, "clearing stall status\n"); - nuke(ep, -EPIPE); - ep_write_UDCCSR(ep, UDCCSR0_SST); - ep0_idle(udc); - } - - if (udccsr0 & UDCCSR0_SA) { - nuke(ep, 0); - set_ep0state(udc, SETUP_STAGE); - } - - switch (udc->ep0state) { - case WAIT_FOR_SETUP: - /* - * Hardware bug : beware, we cannot clear OPC, since we would - * miss a potential OPC irq for a setup packet. - * So, we only do ... nothing, and hope for a next irq with - * UDCCSR0_SA set. - */ - break; - case SETUP_STAGE: - udccsr0 &= UDCCSR0_CTRL_REQ_MASK; - if (likely(udccsr0 == UDCCSR0_CTRL_REQ_MASK)) - handle_ep0_ctrl_req(udc, req); - break; - case IN_DATA_STAGE: /* GET_DESCRIPTOR */ - if (epout_has_pkt(ep)) - ep_write_UDCCSR(ep, UDCCSR0_OPC); - if (req && !ep_is_full(ep)) - completed = write_ep0_fifo(ep, req); - if (completed) - ep0_end_in_req(ep, req, NULL); - break; - case OUT_DATA_STAGE: /* SET_DESCRIPTOR */ - if (epout_has_pkt(ep) && req) - completed = read_ep0_fifo(ep, req); - if (completed) - ep0_end_out_req(ep, req, NULL); - break; - case STALL: - ep_write_UDCCSR(ep, UDCCSR0_FST); - break; - case IN_STATUS_STAGE: - /* - * Hardware bug : beware, we cannot clear OPC, since we would - * miss a potential PC irq for a setup packet. - * So, we only put the ep0 into WAIT_FOR_SETUP state. - */ - if (opc_irq) - ep0_idle(udc); - break; - case OUT_STATUS_STAGE: - case WAIT_ACK_SET_CONF_INTERF: - ep_warn(ep, "should never get in %s state here!!!\n", - EP0_STNAME(ep->dev)); - ep0_idle(udc); - break; - } -} - -/** - * handle_ep - Handle endpoint data tranfers - * @ep: pxa physical endpoint - * - * Tries to transfer all pending request data into the endpoint and/or - * transfer all pending data in the endpoint into usb requests. - * - * Is always called when in_interrupt() and with ep->lock released. - */ -static void handle_ep(struct pxa_ep *ep) -{ - struct pxa27x_request *req; - int completed; - u32 udccsr; - int is_in = ep->dir_in; - int loop = 0; - unsigned long flags; - - spin_lock_irqsave(&ep->lock, flags); - if (ep->in_handle_ep) - goto recursion_detected; - ep->in_handle_ep = 1; - - do { - completed = 0; - udccsr = udc_ep_readl(ep, UDCCSR); - - if (likely(!list_empty(&ep->queue))) - req = list_entry(ep->queue.next, - struct pxa27x_request, queue); - else - req = NULL; - - ep_dbg(ep, "req:%p, udccsr 0x%03x loop=%d\n", - req, udccsr, loop++); - - if (unlikely(udccsr & (UDCCSR_SST | UDCCSR_TRN))) - udc_ep_writel(ep, UDCCSR, - udccsr & (UDCCSR_SST | UDCCSR_TRN)); - if (!req) - break; - - if (unlikely(is_in)) { - if (likely(!ep_is_full(ep))) - completed = write_fifo(ep, req); - } else { - if (likely(epout_has_pkt(ep))) - completed = read_fifo(ep, req); - } - - if (completed) { - if (is_in) - ep_end_in_req(ep, req, &flags); - else - ep_end_out_req(ep, req, &flags); - } - } while (completed); - - ep->in_handle_ep = 0; -recursion_detected: - spin_unlock_irqrestore(&ep->lock, flags); -} - -/** - * pxa27x_change_configuration - Handle SET_CONF usb request notification - * @udc: udc device - * @config: usb configuration - * - * Post the request to upper level. - * Don't use any pxa specific harware configuration capabilities - */ -static void pxa27x_change_configuration(struct pxa_udc *udc, int config) -{ - struct usb_ctrlrequest req ; - - dev_dbg(udc->dev, "config=%d\n", config); - - udc->config = config; - udc->last_interface = 0; - udc->last_alternate = 0; - - req.bRequestType = 0; - req.bRequest = USB_REQ_SET_CONFIGURATION; - req.wValue = config; - req.wIndex = 0; - req.wLength = 0; - - set_ep0state(udc, WAIT_ACK_SET_CONF_INTERF); - udc->driver->setup(&udc->gadget, &req); - ep_write_UDCCSR(&udc->pxa_ep[0], UDCCSR0_AREN); -} - -/** - * pxa27x_change_interface - Handle SET_INTERF usb request notification - * @udc: udc device - * @iface: interface number - * @alt: alternate setting number - * - * Post the request to upper level. - * Don't use any pxa specific harware configuration capabilities - */ -static void pxa27x_change_interface(struct pxa_udc *udc, int iface, int alt) -{ - struct usb_ctrlrequest req; - - dev_dbg(udc->dev, "interface=%d, alternate setting=%d\n", iface, alt); - - udc->last_interface = iface; - udc->last_alternate = alt; - - req.bRequestType = USB_RECIP_INTERFACE; - req.bRequest = USB_REQ_SET_INTERFACE; - req.wValue = alt; - req.wIndex = iface; - req.wLength = 0; - - set_ep0state(udc, WAIT_ACK_SET_CONF_INTERF); - udc->driver->setup(&udc->gadget, &req); - ep_write_UDCCSR(&udc->pxa_ep[0], UDCCSR0_AREN); -} - -/* - * irq_handle_data - Handle data transfer - * @irq: irq IRQ number - * @udc: dev pxa_udc device structure - * - * Called from irq handler, transferts data to or from endpoint to queue - */ -static void irq_handle_data(int irq, struct pxa_udc *udc) -{ - int i; - struct pxa_ep *ep; - u32 udcisr0 = udc_readl(udc, UDCISR0) & UDCCISR0_EP_MASK; - u32 udcisr1 = udc_readl(udc, UDCISR1) & UDCCISR1_EP_MASK; - - if (udcisr0 & UDCISR_INT_MASK) { - udc->pxa_ep[0].stats.irqs++; - udc_writel(udc, UDCISR0, UDCISR_INT(0, UDCISR_INT_MASK)); - handle_ep0(udc, !!(udcisr0 & UDCICR_FIFOERR), - !!(udcisr0 & UDCICR_PKTCOMPL)); - } - - udcisr0 >>= 2; - for (i = 1; udcisr0 != 0 && i < 16; udcisr0 >>= 2, i++) { - if (!(udcisr0 & UDCISR_INT_MASK)) - continue; - - udc_writel(udc, UDCISR0, UDCISR_INT(i, UDCISR_INT_MASK)); - - WARN_ON(i >= ARRAY_SIZE(udc->pxa_ep)); - if (i < ARRAY_SIZE(udc->pxa_ep)) { - ep = &udc->pxa_ep[i]; - ep->stats.irqs++; - handle_ep(ep); - } - } - - for (i = 16; udcisr1 != 0 && i < 24; udcisr1 >>= 2, i++) { - udc_writel(udc, UDCISR1, UDCISR_INT(i - 16, UDCISR_INT_MASK)); - if (!(udcisr1 & UDCISR_INT_MASK)) - continue; - - WARN_ON(i >= ARRAY_SIZE(udc->pxa_ep)); - if (i < ARRAY_SIZE(udc->pxa_ep)) { - ep = &udc->pxa_ep[i]; - ep->stats.irqs++; - handle_ep(ep); - } - } - -} - -/** - * irq_udc_suspend - Handle IRQ "UDC Suspend" - * @udc: udc device - */ -static void irq_udc_suspend(struct pxa_udc *udc) -{ - udc_writel(udc, UDCISR1, UDCISR1_IRSU); - udc->stats.irqs_suspend++; - - if (udc->gadget.speed != USB_SPEED_UNKNOWN - && udc->driver && udc->driver->suspend) - udc->driver->suspend(&udc->gadget); - ep0_idle(udc); -} - -/** - * irq_udc_resume - Handle IRQ "UDC Resume" - * @udc: udc device - */ -static void irq_udc_resume(struct pxa_udc *udc) -{ - udc_writel(udc, UDCISR1, UDCISR1_IRRU); - udc->stats.irqs_resume++; - - if (udc->gadget.speed != USB_SPEED_UNKNOWN - && udc->driver && udc->driver->resume) - udc->driver->resume(&udc->gadget); -} - -/** - * irq_udc_reconfig - Handle IRQ "UDC Change Configuration" - * @udc: udc device - */ -static void irq_udc_reconfig(struct pxa_udc *udc) -{ - unsigned config, interface, alternate, config_change; - u32 udccr = udc_readl(udc, UDCCR); - - udc_writel(udc, UDCISR1, UDCISR1_IRCC); - udc->stats.irqs_reconfig++; - - config = (udccr & UDCCR_ACN) >> UDCCR_ACN_S; - config_change = (config != udc->config); - pxa27x_change_configuration(udc, config); - - interface = (udccr & UDCCR_AIN) >> UDCCR_AIN_S; - alternate = (udccr & UDCCR_AAISN) >> UDCCR_AAISN_S; - pxa27x_change_interface(udc, interface, alternate); - - if (config_change) - update_pxa_ep_matches(udc); - udc_set_mask_UDCCR(udc, UDCCR_SMAC); -} - -/** - * irq_udc_reset - Handle IRQ "UDC Reset" - * @udc: udc device - */ -static void irq_udc_reset(struct pxa_udc *udc) -{ - u32 udccr = udc_readl(udc, UDCCR); - struct pxa_ep *ep = &udc->pxa_ep[0]; - - dev_info(udc->dev, "USB reset\n"); - udc_writel(udc, UDCISR1, UDCISR1_IRRS); - udc->stats.irqs_reset++; - - if ((udccr & UDCCR_UDA) == 0) { - dev_dbg(udc->dev, "USB reset start\n"); - stop_activity(udc, udc->driver); - } - udc->gadget.speed = USB_SPEED_FULL; - memset(&udc->stats, 0, sizeof udc->stats); - - nuke(ep, -EPROTO); - ep_write_UDCCSR(ep, UDCCSR0_FTF | UDCCSR0_OPC); - ep0_idle(udc); -} - -/** - * pxa_udc_irq - Main irq handler - * @irq: irq number - * @_dev: udc device - * - * Handles all udc interrupts - */ -static irqreturn_t pxa_udc_irq(int irq, void *_dev) -{ - struct pxa_udc *udc = _dev; - u32 udcisr0 = udc_readl(udc, UDCISR0); - u32 udcisr1 = udc_readl(udc, UDCISR1); - u32 udccr = udc_readl(udc, UDCCR); - u32 udcisr1_spec; - - dev_vdbg(udc->dev, "Interrupt, UDCISR0:0x%08x, UDCISR1:0x%08x, " - "UDCCR:0x%08x\n", udcisr0, udcisr1, udccr); - - udcisr1_spec = udcisr1 & 0xf8000000; - if (unlikely(udcisr1_spec & UDCISR1_IRSU)) - irq_udc_suspend(udc); - if (unlikely(udcisr1_spec & UDCISR1_IRRU)) - irq_udc_resume(udc); - if (unlikely(udcisr1_spec & UDCISR1_IRCC)) - irq_udc_reconfig(udc); - if (unlikely(udcisr1_spec & UDCISR1_IRRS)) - irq_udc_reset(udc); - - if ((udcisr0 & UDCCISR0_EP_MASK) | (udcisr1 & UDCCISR1_EP_MASK)) - irq_handle_data(irq, udc); - - return IRQ_HANDLED; -} - -static struct pxa_udc memory = { - .gadget = { - .ops = &pxa_udc_ops, - .ep0 = &memory.udc_usb_ep[0].usb_ep, - .name = driver_name, - .dev = { - .init_name = "gadget", - }, - }, - - .udc_usb_ep = { - USB_EP_CTRL, - USB_EP_OUT_BULK(1), - USB_EP_IN_BULK(2), - USB_EP_IN_ISO(3), - USB_EP_OUT_ISO(4), - USB_EP_IN_INT(5), - }, - - .pxa_ep = { - PXA_EP_CTRL, - /* Endpoints for gadget zero */ - PXA_EP_OUT_BULK(1, 1, 3, 0, 0), - PXA_EP_IN_BULK(2, 2, 3, 0, 0), - /* Endpoints for ether gadget, file storage gadget */ - PXA_EP_OUT_BULK(3, 1, 1, 0, 0), - PXA_EP_IN_BULK(4, 2, 1, 0, 0), - PXA_EP_IN_ISO(5, 3, 1, 0, 0), - PXA_EP_OUT_ISO(6, 4, 1, 0, 0), - PXA_EP_IN_INT(7, 5, 1, 0, 0), - /* Endpoints for RNDIS, serial */ - PXA_EP_OUT_BULK(8, 1, 2, 0, 0), - PXA_EP_IN_BULK(9, 2, 2, 0, 0), - PXA_EP_IN_INT(10, 5, 2, 0, 0), - /* - * All the following endpoints are only for completion. They - * won't never work, as multiple interfaces are really broken on - * the pxa. - */ - PXA_EP_OUT_BULK(11, 1, 2, 1, 0), - PXA_EP_IN_BULK(12, 2, 2, 1, 0), - /* Endpoint for CDC Ether */ - PXA_EP_OUT_BULK(13, 1, 1, 1, 1), - PXA_EP_IN_BULK(14, 2, 1, 1, 1), - } -}; - -/** - * pxa_udc_probe - probes the udc device - * @_dev: platform device - * - * Perform basic init : allocates udc clock, creates sysfs files, requests - * irq. - */ -static int __init pxa_udc_probe(struct platform_device *pdev) -{ - struct resource *regs; - struct pxa_udc *udc = &memory; - int retval = 0, gpio; - - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!regs) - return -ENXIO; - udc->irq = platform_get_irq(pdev, 0); - if (udc->irq < 0) - return udc->irq; - - udc->dev = &pdev->dev; - udc->mach = pdev->dev.platform_data; - udc->transceiver = usb_get_transceiver(); - - gpio = udc->mach->gpio_pullup; - if (gpio_is_valid(gpio)) { - retval = gpio_request(gpio, "USB D+ pullup"); - if (retval == 0) - gpio_direction_output(gpio, - udc->mach->gpio_pullup_inverted); - } - if (retval) { - dev_err(&pdev->dev, "Couldn't request gpio %d : %d\n", - gpio, retval); - return retval; - } - - udc->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(udc->clk)) { - retval = PTR_ERR(udc->clk); - goto err_clk; - } - - retval = -ENOMEM; - udc->regs = ioremap(regs->start, resource_size(regs)); - if (!udc->regs) { - dev_err(&pdev->dev, "Unable to map UDC I/O memory\n"); - goto err_map; - } - - device_initialize(&udc->gadget.dev); - udc->gadget.dev.parent = &pdev->dev; - udc->gadget.dev.dma_mask = NULL; - udc->vbus_sensed = 0; - - the_controller = udc; - platform_set_drvdata(pdev, udc); - udc_init_data(udc); - pxa_eps_setup(udc); - - /* irq setup after old hardware state is cleaned up */ - retval = request_irq(udc->irq, pxa_udc_irq, - IRQF_SHARED, driver_name, udc); - if (retval != 0) { - dev_err(udc->dev, "%s: can't get irq %i, err %d\n", - driver_name, IRQ_USB, retval); - goto err_irq; - } - retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget); - if (retval) - goto err_add_udc; - - pxa_init_debugfs(udc); - return 0; -err_add_udc: - free_irq(udc->irq, udc); -err_irq: - iounmap(udc->regs); -err_map: - clk_put(udc->clk); - udc->clk = NULL; -err_clk: - return retval; -} - -/** - * pxa_udc_remove - removes the udc device driver - * @_dev: platform device - */ -static int __exit pxa_udc_remove(struct platform_device *_dev) -{ - struct pxa_udc *udc = platform_get_drvdata(_dev); - int gpio = udc->mach->gpio_pullup; - - usb_del_gadget_udc(&udc->gadget); - usb_gadget_unregister_driver(udc->driver); - free_irq(udc->irq, udc); - pxa_cleanup_debugfs(udc); - if (gpio_is_valid(gpio)) - gpio_free(gpio); - - usb_put_transceiver(udc->transceiver); - - udc->transceiver = NULL; - platform_set_drvdata(_dev, NULL); - the_controller = NULL; - clk_put(udc->clk); - iounmap(udc->regs); - - return 0; -} - -static void pxa_udc_shutdown(struct platform_device *_dev) -{ - struct pxa_udc *udc = platform_get_drvdata(_dev); - - if (udc_readl(udc, UDCCR) & UDCCR_UDE) - udc_disable(udc); -} - -#ifdef CONFIG_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 - * @_dev: platform device - * @state: suspend state - * - * Suspends udc : saves configuration registers (UDCCR*), then disables the udc - * device. - */ -static int pxa_udc_suspend(struct platform_device *_dev, pm_message_t state) -{ - int i; - struct pxa_udc *udc = platform_get_drvdata(_dev); - struct pxa_ep *ep; - - ep = &udc->pxa_ep[0]; - udc->udccsr0 = udc_ep_readl(ep, UDCCSR); - for (i = 1; i < NR_PXA_ENDPOINTS; i++) { - ep = &udc->pxa_ep[i]; - ep->udccsr_value = udc_ep_readl(ep, UDCCSR); - ep->udccr_value = udc_ep_readl(ep, UDCCR); - ep_dbg(ep, "udccsr:0x%03x, udccr:0x%x\n", - ep->udccsr_value, ep->udccr_value); - } - - udc_disable(udc); - udc->pullup_resume = udc->pullup_on; - dplus_pullup(udc, 0); - - return 0; -} - -/** - * pxa_udc_resume - Resume udc device - * @_dev: platform device - * - * Resumes udc : restores configuration registers (UDCCR*), then enables the udc - * device. - */ -static int pxa_udc_resume(struct platform_device *_dev) -{ - int i; - struct pxa_udc *udc = platform_get_drvdata(_dev); - struct pxa_ep *ep; - - ep = &udc->pxa_ep[0]; - udc_ep_writel(ep, UDCCSR, udc->udccsr0 & (UDCCSR0_FST | UDCCSR0_DME)); - for (i = 1; i < NR_PXA_ENDPOINTS; i++) { - ep = &udc->pxa_ep[i]; - udc_ep_writel(ep, UDCCSR, ep->udccsr_value); - udc_ep_writel(ep, UDCCR, ep->udccr_value); - ep_dbg(ep, "udccsr:0x%03x, udccr:0x%x\n", - ep->udccsr_value, ep->udccr_value); - } - - dplus_pullup(udc, udc->pullup_resume); - if (should_enable_udc(udc)) - udc_enable(udc); - /* - * We do not handle OTG yet. - * - * OTGPH bit is set when sleep mode is entered. - * it indicates that OTG pad is retaining its state. - * Upon exit from sleep mode and before clearing OTGPH, - * Software must configure the USB OTG pad, UDC, and UHC - * to the state they were in before entering sleep mode. - */ - pxa27x_clear_otgph(); - - return 0; -} -#endif - -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:pxa27x-udc"); - -static struct platform_driver udc_driver = { - .driver = { - .name = "pxa27x-udc", - .owner = THIS_MODULE, - }, - .remove = __exit_p(pxa_udc_remove), - .shutdown = pxa_udc_shutdown, -#ifdef CONFIG_PM - .suspend = pxa_udc_suspend, - .resume = pxa_udc_resume -#endif -}; - -static int __init udc_init(void) -{ - if (!cpu_is_pxa27x() && !cpu_is_pxa3xx()) - return -ENODEV; - - printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION); - return platform_driver_probe(&udc_driver, pxa_udc_probe); -} -module_init(udc_init); - - -static void __exit udc_exit(void) -{ - platform_driver_unregister(&udc_driver); -} -module_exit(udc_exit); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Robert Jarzmik"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/pxa27x_udc.h b/ANDROID_3.4.5/drivers/usb/gadget/pxa27x_udc.h deleted file mode 100644 index a1d268c6..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/pxa27x_udc.h +++ /dev/null @@ -1,496 +0,0 @@ -/* - * linux/drivers/usb/gadget/pxa27x_udc.h - * Intel PXA27x on-chip full speed USB device controller - * - * Inspired by original driver by Frank Becker, David Brownell, and others. - * Copyright (C) 2008 Robert Jarzmik - * - * 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. - */ - -#ifndef __LINUX_USB_GADGET_PXA27X_H -#define __LINUX_USB_GADGET_PXA27X_H - -#include -#include -#include -#include - -/* - * Register definitions - */ -/* Offsets */ -#define UDCCR 0x0000 /* UDC Control Register */ -#define UDCICR0 0x0004 /* UDC Interrupt Control Register0 */ -#define UDCICR1 0x0008 /* UDC Interrupt Control Register1 */ -#define UDCISR0 0x000C /* UDC Interrupt Status Register 0 */ -#define UDCISR1 0x0010 /* UDC Interrupt Status Register 1 */ -#define UDCFNR 0x0014 /* UDC Frame Number Register */ -#define UDCOTGICR 0x0018 /* UDC On-The-Go interrupt control */ -#define UP2OCR 0x0020 /* USB Port 2 Output Control register */ -#define UP3OCR 0x0024 /* USB Port 3 Output Control register */ -#define UDCCSRn(x) (0x0100 + ((x)<<2)) /* UDC Control/Status register */ -#define UDCBCRn(x) (0x0200 + ((x)<<2)) /* UDC Byte Count Register */ -#define UDCDRn(x) (0x0300 + ((x)<<2)) /* UDC Data Register */ -#define UDCCRn(x) (0x0400 + ((x)<<2)) /* UDC Control Register */ - -#define UDCCR_OEN (1 << 31) /* On-the-Go Enable */ -#define UDCCR_AALTHNP (1 << 30) /* A-device Alternate Host Negotiation - Protocol Port Support */ -#define UDCCR_AHNP (1 << 29) /* A-device Host Negotiation Protocol - Support */ -#define UDCCR_BHNP (1 << 28) /* B-device Host Negotiation Protocol - Enable */ -#define UDCCR_DWRE (1 << 16) /* Device Remote Wake-up Enable */ -#define UDCCR_ACN (0x03 << 11) /* Active UDC configuration Number */ -#define UDCCR_ACN_S 11 -#define UDCCR_AIN (0x07 << 8) /* Active UDC interface Number */ -#define UDCCR_AIN_S 8 -#define UDCCR_AAISN (0x07 << 5) /* Active UDC Alternate Interface - Setting Number */ -#define UDCCR_AAISN_S 5 -#define UDCCR_SMAC (1 << 4) /* Switch Endpoint Memory to Active - Configuration */ -#define UDCCR_EMCE (1 << 3) /* Endpoint Memory Configuration - Error */ -#define UDCCR_UDR (1 << 2) /* UDC Resume */ -#define UDCCR_UDA (1 << 1) /* UDC Active */ -#define UDCCR_UDE (1 << 0) /* UDC Enable */ - -#define UDCICR_INT(n, intr) (((intr) & 0x03) << (((n) & 0x0F) * 2)) -#define UDCICR1_IECC (1 << 31) /* IntEn - Configuration Change */ -#define UDCICR1_IESOF (1 << 30) /* IntEn - Start of Frame */ -#define UDCICR1_IERU (1 << 29) /* IntEn - Resume */ -#define UDCICR1_IESU (1 << 28) /* IntEn - Suspend */ -#define UDCICR1_IERS (1 << 27) /* IntEn - Reset */ -#define UDCICR_FIFOERR (1 << 1) /* FIFO Error interrupt for EP */ -#define UDCICR_PKTCOMPL (1 << 0) /* Packet Complete interrupt for EP */ -#define UDCICR_INT_MASK (UDCICR_FIFOERR | UDCICR_PKTCOMPL) - -#define UDCISR_INT(n, intr) (((intr) & 0x03) << (((n) & 0x0F) * 2)) -#define UDCISR1_IRCC (1 << 31) /* IntReq - Configuration Change */ -#define UDCISR1_IRSOF (1 << 30) /* IntReq - Start of Frame */ -#define UDCISR1_IRRU (1 << 29) /* IntReq - Resume */ -#define UDCISR1_IRSU (1 << 28) /* IntReq - Suspend */ -#define UDCISR1_IRRS (1 << 27) /* IntReq - Reset */ -#define UDCISR_INT_MASK (UDCICR_FIFOERR | UDCICR_PKTCOMPL) - -#define UDCOTGICR_IESF (1 << 24) /* OTG SET_FEATURE command recvd */ -#define UDCOTGICR_IEXR (1 << 17) /* Extra Transceiver Interrupt - Rising Edge Interrupt Enable */ -#define UDCOTGICR_IEXF (1 << 16) /* Extra Transceiver Interrupt - Falling Edge Interrupt Enable */ -#define UDCOTGICR_IEVV40R (1 << 9) /* OTG Vbus Valid 4.0V Rising Edge - Interrupt Enable */ -#define UDCOTGICR_IEVV40F (1 << 8) /* OTG Vbus Valid 4.0V Falling Edge - Interrupt Enable */ -#define UDCOTGICR_IEVV44R (1 << 7) /* OTG Vbus Valid 4.4V Rising Edge - Interrupt Enable */ -#define UDCOTGICR_IEVV44F (1 << 6) /* OTG Vbus Valid 4.4V Falling Edge - Interrupt Enable */ -#define UDCOTGICR_IESVR (1 << 5) /* OTG Session Valid Rising Edge - Interrupt Enable */ -#define UDCOTGICR_IESVF (1 << 4) /* OTG Session Valid Falling Edge - Interrupt Enable */ -#define UDCOTGICR_IESDR (1 << 3) /* OTG A-Device SRP Detect Rising - Edge Interrupt Enable */ -#define UDCOTGICR_IESDF (1 << 2) /* OTG A-Device SRP Detect Falling - Edge Interrupt Enable */ -#define UDCOTGICR_IEIDR (1 << 1) /* OTG ID Change Rising Edge - Interrupt Enable */ -#define UDCOTGICR_IEIDF (1 << 0) /* OTG ID Change Falling Edge - Interrupt Enable */ - -/* Host Port 2 field bits */ -#define UP2OCR_CPVEN (1 << 0) /* Charge Pump Vbus Enable */ -#define UP2OCR_CPVPE (1 << 1) /* Charge Pump Vbus Pulse Enable */ - /* Transceiver enablers */ -#define UP2OCR_DPPDE (1 << 2) /* D+ Pull Down Enable */ -#define UP2OCR_DMPDE (1 << 3) /* D- Pull Down Enable */ -#define UP2OCR_DPPUE (1 << 4) /* D+ Pull Up Enable */ -#define UP2OCR_DMPUE (1 << 5) /* D- Pull Up Enable */ -#define UP2OCR_DPPUBE (1 << 6) /* D+ Pull Up Bypass Enable */ -#define UP2OCR_DMPUBE (1 << 7) /* D- Pull Up Bypass Enable */ -#define UP2OCR_EXSP (1 << 8) /* External Transceiver Speed Control */ -#define UP2OCR_EXSUS (1 << 9) /* External Transceiver Speed Enable */ -#define UP2OCR_IDON (1 << 10) /* OTG ID Read Enable */ -#define UP2OCR_HXS (1 << 16) /* Transceiver Output Select */ -#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 */ -#define UDCCSR0_SST (1 << 4) /* Sent Stall */ -#define UDCCSR0_DME (1 << 3) /* DMA Enable */ -#define UDCCSR0_FTF (1 << 2) /* Flush Transmit FIFO */ -#define UDCCSR0_IPR (1 << 1) /* IN Packet Ready */ -#define UDCCSR0_OPC (1 << 0) /* OUT Packet Complete */ - -#define UDCCSR_DPE (1 << 9) /* Data Packet Error */ -#define UDCCSR_FEF (1 << 8) /* Flush Endpoint FIFO */ -#define UDCCSR_SP (1 << 7) /* Short Packet Control/Status */ -#define UDCCSR_BNE (1 << 6) /* Buffer Not Empty (IN endpoints) */ -#define UDCCSR_BNF (1 << 6) /* Buffer Not Full (OUT endpoints) */ -#define UDCCSR_FST (1 << 5) /* Force STALL */ -#define UDCCSR_SST (1 << 4) /* Sent STALL */ -#define UDCCSR_DME (1 << 3) /* DMA Enable */ -#define UDCCSR_TRN (1 << 2) /* Tx/Rx NAK */ -#define UDCCSR_PC (1 << 1) /* Packet Complete */ -#define UDCCSR_FS (1 << 0) /* FIFO needs service */ - -#define UDCCONR_CN (0x03 << 25) /* Configuration Number */ -#define UDCCONR_CN_S 25 -#define UDCCONR_IN (0x07 << 22) /* Interface Number */ -#define UDCCONR_IN_S 22 -#define UDCCONR_AISN (0x07 << 19) /* Alternate Interface Number */ -#define UDCCONR_AISN_S 19 -#define UDCCONR_EN (0x0f << 15) /* Endpoint Number */ -#define UDCCONR_EN_S 15 -#define UDCCONR_ET (0x03 << 13) /* Endpoint Type: */ -#define UDCCONR_ET_S 13 -#define UDCCONR_ET_INT (0x03 << 13) /* Interrupt */ -#define UDCCONR_ET_BULK (0x02 << 13) /* Bulk */ -#define UDCCONR_ET_ISO (0x01 << 13) /* Isochronous */ -#define UDCCONR_ET_NU (0x00 << 13) /* Not used */ -#define UDCCONR_ED (1 << 12) /* Endpoint Direction */ -#define UDCCONR_MPS (0x3ff << 2) /* Maximum Packet Size */ -#define UDCCONR_MPS_S 2 -#define UDCCONR_DE (1 << 1) /* Double Buffering Enable */ -#define UDCCONR_EE (1 << 0) /* Endpoint Enable */ - -#define UDCCR_MASK_BITS (UDCCR_OEN | UDCCR_SMAC | UDCCR_UDR | UDCCR_UDE) -#define UDCCSR_WR_MASK (UDCCSR_DME | UDCCSR_FST) -#define UDC_FNR_MASK (0x7ff) -#define UDC_BCR_MASK (0x3ff) - -/* - * UDCCR = UDC Endpoint Configuration Registers - * UDCCSR = UDC Control/Status Register for this EP - * UDCBCR = UDC Byte Count Remaining (contents of OUT fifo) - * UDCDR = UDC Endpoint Data Register (the fifo) - */ -#define ofs_UDCCR(ep) (UDCCRn(ep->idx)) -#define ofs_UDCCSR(ep) (UDCCSRn(ep->idx)) -#define ofs_UDCBCR(ep) (UDCBCRn(ep->idx)) -#define ofs_UDCDR(ep) (UDCDRn(ep->idx)) - -/* Register access macros */ -#define udc_ep_readl(ep, reg) \ - __raw_readl((ep)->dev->regs + ofs_##reg(ep)) -#define udc_ep_writel(ep, reg, value) \ - __raw_writel((value), ep->dev->regs + ofs_##reg(ep)) -#define udc_ep_readb(ep, reg) \ - __raw_readb((ep)->dev->regs + ofs_##reg(ep)) -#define udc_ep_writeb(ep, reg, value) \ - __raw_writeb((value), ep->dev->regs + ofs_##reg(ep)) -#define udc_readl(dev, reg) \ - __raw_readl((dev)->regs + (reg)) -#define udc_writel(udc, reg, value) \ - __raw_writel((value), (udc)->regs + (reg)) - -#define UDCCSR_MASK (UDCCSR_FST | UDCCSR_DME) -#define UDCCISR0_EP_MASK ~0 -#define UDCCISR1_EP_MASK 0xffff -#define UDCCSR0_CTRL_REQ_MASK (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE) - -#define EPIDX(ep) (ep->idx) -#define EPADDR(ep) (ep->addr) -#define EPXFERTYPE(ep) (ep->type) -#define EPNAME(ep) (ep->name) -#define is_ep0(ep) (!ep->idx) -#define EPXFERTYPE_is_ISO(ep) (EPXFERTYPE(ep) == USB_ENDPOINT_XFER_ISOC) - -/* - * Endpoint definitions - * - * Once enabled, pxa endpoint configuration is freezed, and cannot change - * unless a reset happens or the udc is disabled. - * Therefore, we must define all pxa potential endpoint definitions needed for - * all gadget and set them up before the udc is enabled. - * - * As the architecture chosen is fully static, meaning the pxa endpoint - * configurations are set up once and for all, we must provide a way to match - * one usb endpoint (usb_ep) to several pxa endpoints. The reason is that gadget - * layer autoconf doesn't choose the usb_ep endpoint on (config, interface, alt) - * criteria, while the pxa architecture requires that. - * - * The solution is to define several pxa endpoints matching one usb_ep. Ex: - * - "ep1-in" matches pxa endpoint EPA (which is an IN ep at addr 1, when - * the udc talks on (config=3, interface=0, alt=0) - * - "ep1-in" matches pxa endpoint EPB (which is an IN ep at addr 1, when - * the udc talks on (config=3, interface=0, alt=1) - * - "ep1-in" matches pxa endpoint EPC (which is an IN ep at addr 1, when - * the udc talks on (config=2, interface=0, alt=0) - * - * We'll define the pxa endpoint by its index (EPA => idx=1, EPB => idx=2, ...) - */ - -/* - * Endpoint definition helpers - */ -#define USB_EP_DEF(addr, bname, dir, type, maxpkt) \ -{ .usb_ep = { .name = bname, .ops = &pxa_ep_ops, .maxpacket = maxpkt, }, \ - .desc = { .bEndpointAddress = addr | (dir ? USB_DIR_IN : 0), \ - .bmAttributes = type, \ - .wMaxPacketSize = maxpkt, }, \ - .dev = &memory \ -} -#define USB_EP_BULK(addr, bname, dir) \ - USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_BULK, BULK_FIFO_SIZE) -#define USB_EP_ISO(addr, bname, dir) \ - USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_ISOC, ISO_FIFO_SIZE) -#define USB_EP_INT(addr, bname, dir) \ - USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_INT, INT_FIFO_SIZE) -#define USB_EP_IN_BULK(n) USB_EP_BULK(n, "ep" #n "in-bulk", 1) -#define USB_EP_OUT_BULK(n) USB_EP_BULK(n, "ep" #n "out-bulk", 0) -#define USB_EP_IN_ISO(n) USB_EP_ISO(n, "ep" #n "in-iso", 1) -#define USB_EP_OUT_ISO(n) USB_EP_ISO(n, "ep" #n "out-iso", 0) -#define USB_EP_IN_INT(n) USB_EP_INT(n, "ep" #n "in-int", 1) -#define USB_EP_CTRL USB_EP_DEF(0, "ep0", 0, 0, EP0_FIFO_SIZE) - -#define PXA_EP_DEF(_idx, _addr, dir, _type, maxpkt, _config, iface, altset) \ -{ \ - .dev = &memory, \ - .name = "ep" #_idx, \ - .idx = _idx, .enabled = 0, \ - .dir_in = dir, .addr = _addr, \ - .config = _config, .interface = iface, .alternate = altset, \ - .type = _type, .fifo_size = maxpkt, \ -} -#define PXA_EP_BULK(_idx, addr, dir, config, iface, alt) \ - PXA_EP_DEF(_idx, addr, dir, USB_ENDPOINT_XFER_BULK, BULK_FIFO_SIZE, \ - config, iface, alt) -#define PXA_EP_ISO(_idx, addr, dir, config, iface, alt) \ - PXA_EP_DEF(_idx, addr, dir, USB_ENDPOINT_XFER_ISOC, ISO_FIFO_SIZE, \ - config, iface, alt) -#define PXA_EP_INT(_idx, addr, dir, config, iface, alt) \ - PXA_EP_DEF(_idx, addr, dir, USB_ENDPOINT_XFER_INT, INT_FIFO_SIZE, \ - config, iface, alt) -#define PXA_EP_IN_BULK(i, adr, c, f, a) PXA_EP_BULK(i, adr, 1, c, f, a) -#define PXA_EP_OUT_BULK(i, adr, c, f, a) PXA_EP_BULK(i, adr, 0, c, f, a) -#define PXA_EP_IN_ISO(i, adr, c, f, a) PXA_EP_ISO(i, adr, 1, c, f, a) -#define PXA_EP_OUT_ISO(i, adr, c, f, a) PXA_EP_ISO(i, adr, 0, c, f, a) -#define PXA_EP_IN_INT(i, adr, c, f, a) PXA_EP_INT(i, adr, 1, c, f, a) -#define PXA_EP_CTRL PXA_EP_DEF(0, 0, 0, 0, EP0_FIFO_SIZE, 0, 0, 0) - -struct pxa27x_udc; - -struct stats { - unsigned long in_ops; - unsigned long out_ops; - unsigned long in_bytes; - unsigned long out_bytes; - unsigned long irqs; -}; - -/** - * struct udc_usb_ep - container of each usb_ep structure - * @usb_ep: usb endpoint - * @desc: usb descriptor, especially type and address - * @dev: udc managing this endpoint - * @pxa_ep: matching pxa_ep (cache of find_pxa_ep() call) - */ -struct udc_usb_ep { - struct usb_ep usb_ep; - struct usb_endpoint_descriptor desc; - struct pxa_udc *dev; - struct pxa_ep *pxa_ep; -}; - -/** - * struct pxa_ep - pxa endpoint - * @dev: udc device - * @queue: requests queue - * @lock: lock to pxa_ep data (queues and stats) - * @enabled: true when endpoint enabled (not stopped by gadget layer) - * @in_handle_ep: number of recursions of handle_ep() function - * Prevents deadlocks or infinite recursions of types : - * irq->handle_ep()->req_done()->req.complete()->pxa_ep_queue()->handle_ep() - * or - * pxa_ep_queue()->handle_ep()->req_done()->req.complete()->pxa_ep_queue() - * @idx: endpoint index (1 => epA, 2 => epB, ..., 24 => epX) - * @name: endpoint name (for trace/debug purpose) - * @dir_in: 1 if IN endpoint, 0 if OUT endpoint - * @addr: usb endpoint number - * @config: configuration in which this endpoint is active - * @interface: interface in which this endpoint is active - * @alternate: altsetting in which this endpoitn is active - * @fifo_size: max packet size in the endpoint fifo - * @type: endpoint type (bulk, iso, int, ...) - * @udccsr_value: save register of UDCCSR0 for suspend/resume - * @udccr_value: save register of UDCCR for suspend/resume - * @stats: endpoint statistics - * - * The *PROBLEM* is that pxa's endpoint configuration scheme is both misdesigned - * (cares about config/interface/altsetting, thus placing needless limits on - * device capability) and full of implementation bugs forcing it to be set up - * for use more or less like a pxa255. - * - * As we define the pxa_ep statically, we must guess all needed pxa_ep for all - * gadget which may work with this udc driver. - */ -struct pxa_ep { - struct pxa_udc *dev; - - struct list_head queue; - spinlock_t lock; /* Protects this structure */ - /* (queues, stats) */ - unsigned enabled:1; - unsigned in_handle_ep:1; - - unsigned idx:5; - char *name; - - /* - * Specific pxa endpoint data, needed for hardware initialization - */ - unsigned dir_in:1; - unsigned addr:4; - unsigned config:2; - unsigned interface:3; - unsigned alternate:3; - unsigned fifo_size; - unsigned type; - -#ifdef CONFIG_PM - u32 udccsr_value; - u32 udccr_value; -#endif - struct stats stats; -}; - -/** - * struct pxa27x_request - container of each usb_request structure - * @req: usb request - * @udc_usb_ep: usb endpoint the request was submitted on - * @in_use: sanity check if request already queued on an pxa_ep - * @queue: linked list of requests, linked on pxa_ep->queue - */ -struct pxa27x_request { - struct usb_request req; - struct udc_usb_ep *udc_usb_ep; - unsigned in_use:1; - struct list_head queue; -}; - -enum ep0_state { - WAIT_FOR_SETUP, - SETUP_STAGE, - IN_DATA_STAGE, - OUT_DATA_STAGE, - IN_STATUS_STAGE, - OUT_STATUS_STAGE, - STALL, - WAIT_ACK_SET_CONF_INTERF -}; - -static char *ep0_state_name[] = { - "WAIT_FOR_SETUP", "SETUP_STAGE", "IN_DATA_STAGE", "OUT_DATA_STAGE", - "IN_STATUS_STAGE", "OUT_STATUS_STAGE", "STALL", - "WAIT_ACK_SET_CONF_INTERF" -}; -#define EP0_STNAME(udc) ep0_state_name[(udc)->ep0state] - -#define EP0_FIFO_SIZE 16U -#define BULK_FIFO_SIZE 64U -#define ISO_FIFO_SIZE 256U -#define INT_FIFO_SIZE 16U - -struct udc_stats { - unsigned long irqs_reset; - unsigned long irqs_suspend; - unsigned long irqs_resume; - unsigned long irqs_reconfig; -}; - -#define NR_USB_ENDPOINTS (1 + 5) /* ep0 + ep1in-bulk + .. + ep3in-iso */ -#define NR_PXA_ENDPOINTS (1 + 14) /* ep0 + epA + epB + .. + epX */ - -/** - * struct pxa_udc - udc structure - * @regs: mapped IO space - * @irq: udc irq - * @clk: udc clock - * @usb_gadget: udc gadget structure - * @driver: bound gadget (zero, g_ether, g_file_storage, ...) - * @dev: device - * @mach: machine info, used to activate specific GPIO - * @transceiver: external transceiver to handle vbus sense and D+ pullup - * @ep0state: control endpoint state machine state - * @stats: statistics on udc usage - * @udc_usb_ep: array of usb endpoints offered by the gadget - * @pxa_ep: array of pxa available endpoints - * @enabled: UDC was enabled by a previous udc_enable() - * @pullup_on: if pullup resistor connected to D+ pin - * @pullup_resume: if pullup resistor should be connected to D+ pin on resume - * @config: UDC active configuration - * @last_interface: UDC interface of the last SET_INTERFACE host request - * @last_alternate: UDC altsetting of the last SET_INTERFACE host request - * @udccsr0: save of udccsr0 in case of suspend - * @debugfs_root: root entry of debug filesystem - * @debugfs_state: debugfs entry for "udcstate" - * @debugfs_queues: debugfs entry for "queues" - * @debugfs_eps: debugfs entry for "epstate" - */ -struct pxa_udc { - void __iomem *regs; - int irq; - struct clk *clk; - - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - struct device *dev; - struct pxa2xx_udc_mach_info *mach; - struct usb_phy *transceiver; - - enum ep0_state ep0state; - struct udc_stats stats; - - struct udc_usb_ep udc_usb_ep[NR_USB_ENDPOINTS]; - struct pxa_ep pxa_ep[NR_PXA_ENDPOINTS]; - - unsigned enabled:1; - unsigned pullup_on:1; - unsigned pullup_resume:1; - unsigned vbus_sensed:1; - unsigned config:2; - unsigned last_interface:3; - unsigned last_alternate:3; - -#ifdef CONFIG_PM - unsigned udccsr0; -#endif -#ifdef CONFIG_USB_GADGET_DEBUG_FS - struct dentry *debugfs_root; - struct dentry *debugfs_state; - struct dentry *debugfs_queues; - struct dentry *debugfs_eps; -#endif -}; - -static inline struct pxa_udc *to_gadget_udc(struct usb_gadget *gadget) -{ - return container_of(gadget, struct pxa_udc, gadget); -} - -/* - * Debugging/message support - */ -#define ep_dbg(ep, fmt, arg...) \ - dev_dbg(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg) -#define ep_vdbg(ep, fmt, arg...) \ - dev_vdbg(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg) -#define ep_err(ep, fmt, arg...) \ - dev_err(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg) -#define ep_info(ep, fmt, arg...) \ - dev_info(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg) -#define ep_warn(ep, fmt, arg...) \ - dev_warn(ep->dev->dev, "%s:%s:" fmt, EPNAME(ep), __func__, ## arg) - -#endif /* __LINUX_USB_GADGET_PXA27X_H */ diff --git a/ANDROID_3.4.5/drivers/usb/gadget/r8a66597-udc.c b/ANDROID_3.4.5/drivers/usb/gadget/r8a66597-udc.c deleted file mode 100644 index c4401e7d..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/r8a66597-udc.c +++ /dev/null @@ -1,2043 +0,0 @@ -/* - * R8A66597 UDC (USB gadget) - * - * Copyright (C) 2006-2009 Renesas Solutions Corp. - * - * Author : Yoshihiro Shimoda - * - * 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; version 2 of the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "r8a66597-udc.h" - -#define DRIVER_VERSION "2011-09-26" - -static const char udc_name[] = "r8a66597_udc"; -static const char *r8a66597_ep_name[] = { - "ep0", "ep1", "ep2", "ep3", "ep4", "ep5", "ep6", "ep7", - "ep8", "ep9", -}; - -static void init_controller(struct r8a66597 *r8a66597); -static void disable_controller(struct r8a66597 *r8a66597); -static void irq_ep0_write(struct r8a66597_ep *ep, struct r8a66597_request *req); -static void irq_packet_write(struct r8a66597_ep *ep, - struct r8a66597_request *req); -static int r8a66597_queue(struct usb_ep *_ep, struct usb_request *_req, - gfp_t gfp_flags); - -static void transfer_complete(struct r8a66597_ep *ep, - struct r8a66597_request *req, int status); - -/*-------------------------------------------------------------------------*/ -static inline u16 get_usb_speed(struct r8a66597 *r8a66597) -{ - return r8a66597_read(r8a66597, DVSTCTR0) & RHST; -} - -static void enable_pipe_irq(struct r8a66597 *r8a66597, u16 pipenum, - unsigned long reg) -{ - u16 tmp; - - tmp = r8a66597_read(r8a66597, INTENB0); - r8a66597_bclr(r8a66597, BEMPE | NRDYE | BRDYE, - INTENB0); - r8a66597_bset(r8a66597, (1 << pipenum), reg); - r8a66597_write(r8a66597, tmp, INTENB0); -} - -static void disable_pipe_irq(struct r8a66597 *r8a66597, u16 pipenum, - unsigned long reg) -{ - u16 tmp; - - tmp = r8a66597_read(r8a66597, INTENB0); - r8a66597_bclr(r8a66597, BEMPE | NRDYE | BRDYE, - INTENB0); - r8a66597_bclr(r8a66597, (1 << pipenum), reg); - r8a66597_write(r8a66597, tmp, INTENB0); -} - -static void r8a66597_usb_connect(struct r8a66597 *r8a66597) -{ - r8a66597_bset(r8a66597, CTRE, INTENB0); - r8a66597_bset(r8a66597, BEMPE | BRDYE, INTENB0); - - r8a66597_bset(r8a66597, DPRPU, SYSCFG0); -} - -static void r8a66597_usb_disconnect(struct r8a66597 *r8a66597) -__releases(r8a66597->lock) -__acquires(r8a66597->lock) -{ - r8a66597_bclr(r8a66597, CTRE, INTENB0); - r8a66597_bclr(r8a66597, BEMPE | BRDYE, INTENB0); - r8a66597_bclr(r8a66597, DPRPU, SYSCFG0); - - r8a66597->gadget.speed = USB_SPEED_UNKNOWN; - spin_unlock(&r8a66597->lock); - r8a66597->driver->disconnect(&r8a66597->gadget); - spin_lock(&r8a66597->lock); - - disable_controller(r8a66597); - init_controller(r8a66597); - r8a66597_bset(r8a66597, VBSE, INTENB0); - INIT_LIST_HEAD(&r8a66597->ep[0].queue); -} - -static inline u16 control_reg_get_pid(struct r8a66597 *r8a66597, u16 pipenum) -{ - u16 pid = 0; - unsigned long offset; - - if (pipenum == 0) { - pid = r8a66597_read(r8a66597, DCPCTR) & PID; - } else if (pipenum < R8A66597_MAX_NUM_PIPE) { - offset = get_pipectr_addr(pipenum); - pid = r8a66597_read(r8a66597, offset) & PID; - } else { - dev_err(r8a66597_to_dev(r8a66597), "unexpect pipe num (%d)\n", - pipenum); - } - - return pid; -} - -static inline void control_reg_set_pid(struct r8a66597 *r8a66597, u16 pipenum, - u16 pid) -{ - unsigned long offset; - - if (pipenum == 0) { - r8a66597_mdfy(r8a66597, pid, PID, DCPCTR); - } else if (pipenum < R8A66597_MAX_NUM_PIPE) { - offset = get_pipectr_addr(pipenum); - r8a66597_mdfy(r8a66597, pid, PID, offset); - } else { - dev_err(r8a66597_to_dev(r8a66597), "unexpect pipe num (%d)\n", - pipenum); - } -} - -static inline void pipe_start(struct r8a66597 *r8a66597, u16 pipenum) -{ - control_reg_set_pid(r8a66597, pipenum, PID_BUF); -} - -static inline void pipe_stop(struct r8a66597 *r8a66597, u16 pipenum) -{ - control_reg_set_pid(r8a66597, pipenum, PID_NAK); -} - -static inline void pipe_stall(struct r8a66597 *r8a66597, u16 pipenum) -{ - control_reg_set_pid(r8a66597, pipenum, PID_STALL); -} - -static inline u16 control_reg_get(struct r8a66597 *r8a66597, u16 pipenum) -{ - u16 ret = 0; - unsigned long offset; - - if (pipenum == 0) { - ret = r8a66597_read(r8a66597, DCPCTR); - } else if (pipenum < R8A66597_MAX_NUM_PIPE) { - offset = get_pipectr_addr(pipenum); - ret = r8a66597_read(r8a66597, offset); - } else { - dev_err(r8a66597_to_dev(r8a66597), "unexpect pipe num (%d)\n", - pipenum); - } - - return ret; -} - -static inline void control_reg_sqclr(struct r8a66597 *r8a66597, u16 pipenum) -{ - unsigned long offset; - - pipe_stop(r8a66597, pipenum); - - if (pipenum == 0) { - r8a66597_bset(r8a66597, SQCLR, DCPCTR); - } else if (pipenum < R8A66597_MAX_NUM_PIPE) { - offset = get_pipectr_addr(pipenum); - r8a66597_bset(r8a66597, SQCLR, offset); - } else { - dev_err(r8a66597_to_dev(r8a66597), "unexpect pipe num (%d)\n", - pipenum); - } -} - -static void control_reg_sqset(struct r8a66597 *r8a66597, u16 pipenum) -{ - unsigned long offset; - - pipe_stop(r8a66597, pipenum); - - if (pipenum == 0) { - r8a66597_bset(r8a66597, SQSET, DCPCTR); - } else if (pipenum < R8A66597_MAX_NUM_PIPE) { - offset = get_pipectr_addr(pipenum); - r8a66597_bset(r8a66597, SQSET, offset); - } else { - dev_err(r8a66597_to_dev(r8a66597), - "unexpect pipe num(%d)\n", pipenum); - } -} - -static u16 control_reg_sqmon(struct r8a66597 *r8a66597, u16 pipenum) -{ - unsigned long offset; - - if (pipenum == 0) { - return r8a66597_read(r8a66597, DCPCTR) & SQMON; - } else if (pipenum < R8A66597_MAX_NUM_PIPE) { - offset = get_pipectr_addr(pipenum); - return r8a66597_read(r8a66597, offset) & SQMON; - } else { - dev_err(r8a66597_to_dev(r8a66597), - "unexpect pipe num(%d)\n", pipenum); - } - - return 0; -} - -static u16 save_usb_toggle(struct r8a66597 *r8a66597, u16 pipenum) -{ - return control_reg_sqmon(r8a66597, pipenum); -} - -static void restore_usb_toggle(struct r8a66597 *r8a66597, u16 pipenum, - u16 toggle) -{ - if (toggle) - control_reg_sqset(r8a66597, pipenum); - else - control_reg_sqclr(r8a66597, pipenum); -} - -static inline int get_buffer_size(struct r8a66597 *r8a66597, u16 pipenum) -{ - u16 tmp; - int size; - - if (pipenum == 0) { - tmp = r8a66597_read(r8a66597, DCPCFG); - if ((tmp & R8A66597_CNTMD) != 0) - size = 256; - else { - tmp = r8a66597_read(r8a66597, DCPMAXP); - size = tmp & MAXP; - } - } else { - r8a66597_write(r8a66597, pipenum, PIPESEL); - tmp = r8a66597_read(r8a66597, PIPECFG); - if ((tmp & R8A66597_CNTMD) != 0) { - tmp = r8a66597_read(r8a66597, PIPEBUF); - size = ((tmp >> 10) + 1) * 64; - } else { - tmp = r8a66597_read(r8a66597, PIPEMAXP); - size = tmp & MXPS; - } - } - - return size; -} - -static inline unsigned short mbw_value(struct r8a66597 *r8a66597) -{ - if (r8a66597->pdata->on_chip) - return MBW_32; - else - return MBW_16; -} - -static void r8a66597_change_curpipe(struct r8a66597 *r8a66597, u16 pipenum, - u16 isel, u16 fifosel) -{ - u16 tmp, mask, loop; - int i = 0; - - if (!pipenum) { - mask = ISEL | CURPIPE; - loop = isel; - } else { - mask = CURPIPE; - loop = pipenum; - } - r8a66597_mdfy(r8a66597, loop, mask, fifosel); - - do { - tmp = r8a66597_read(r8a66597, fifosel); - if (i++ > 1000000) { - dev_err(r8a66597_to_dev(r8a66597), - "r8a66597: register%x, loop %x " - "is timeout\n", fifosel, loop); - break; - } - ndelay(1); - } while ((tmp & mask) != loop); -} - -static inline void pipe_change(struct r8a66597 *r8a66597, u16 pipenum) -{ - struct r8a66597_ep *ep = r8a66597->pipenum2ep[pipenum]; - - if (ep->use_dma) - r8a66597_bclr(r8a66597, DREQE, ep->fifosel); - - r8a66597_mdfy(r8a66597, pipenum, CURPIPE, ep->fifosel); - - ndelay(450); - - if (r8a66597_is_sudmac(r8a66597) && ep->use_dma) - r8a66597_bclr(r8a66597, mbw_value(r8a66597), ep->fifosel); - else - r8a66597_bset(r8a66597, mbw_value(r8a66597), ep->fifosel); - - if (ep->use_dma) - r8a66597_bset(r8a66597, DREQE, ep->fifosel); -} - -static int pipe_buffer_setting(struct r8a66597 *r8a66597, - struct r8a66597_pipe_info *info) -{ - u16 bufnum = 0, buf_bsize = 0; - u16 pipecfg = 0; - - if (info->pipe == 0) - return -EINVAL; - - r8a66597_write(r8a66597, info->pipe, PIPESEL); - - if (info->dir_in) - pipecfg |= R8A66597_DIR; - pipecfg |= info->type; - pipecfg |= info->epnum; - switch (info->type) { - case R8A66597_INT: - bufnum = 4 + (info->pipe - R8A66597_BASE_PIPENUM_INT); - buf_bsize = 0; - break; - case R8A66597_BULK: - /* isochronous pipes may be used as bulk pipes */ - if (info->pipe >= R8A66597_BASE_PIPENUM_BULK) - bufnum = info->pipe - R8A66597_BASE_PIPENUM_BULK; - else - bufnum = info->pipe - R8A66597_BASE_PIPENUM_ISOC; - - bufnum = R8A66597_BASE_BUFNUM + (bufnum * 16); - buf_bsize = 7; - pipecfg |= R8A66597_DBLB; - if (!info->dir_in) - pipecfg |= R8A66597_SHTNAK; - break; - case R8A66597_ISO: - bufnum = R8A66597_BASE_BUFNUM + - (info->pipe - R8A66597_BASE_PIPENUM_ISOC) * 16; - buf_bsize = 7; - break; - } - - if (buf_bsize && ((bufnum + 16) >= R8A66597_MAX_BUFNUM)) { - pr_err("r8a66597 pipe memory is insufficient\n"); - return -ENOMEM; - } - - r8a66597_write(r8a66597, pipecfg, PIPECFG); - r8a66597_write(r8a66597, (buf_bsize << 10) | (bufnum), PIPEBUF); - r8a66597_write(r8a66597, info->maxpacket, PIPEMAXP); - if (info->interval) - info->interval--; - r8a66597_write(r8a66597, info->interval, PIPEPERI); - - return 0; -} - -static void pipe_buffer_release(struct r8a66597 *r8a66597, - struct r8a66597_pipe_info *info) -{ - if (info->pipe == 0) - return; - - if (is_bulk_pipe(info->pipe)) { - r8a66597->bulk--; - } else if (is_interrupt_pipe(info->pipe)) { - r8a66597->interrupt--; - } else if (is_isoc_pipe(info->pipe)) { - r8a66597->isochronous--; - if (info->type == R8A66597_BULK) - r8a66597->bulk--; - } else { - dev_err(r8a66597_to_dev(r8a66597), - "ep_release: unexpect pipenum (%d)\n", info->pipe); - } -} - -static void pipe_initialize(struct r8a66597_ep *ep) -{ - struct r8a66597 *r8a66597 = ep->r8a66597; - - r8a66597_mdfy(r8a66597, 0, CURPIPE, ep->fifosel); - - r8a66597_write(r8a66597, ACLRM, ep->pipectr); - r8a66597_write(r8a66597, 0, ep->pipectr); - r8a66597_write(r8a66597, SQCLR, ep->pipectr); - if (ep->use_dma) { - r8a66597_mdfy(r8a66597, ep->pipenum, CURPIPE, ep->fifosel); - - ndelay(450); - - r8a66597_bset(r8a66597, mbw_value(r8a66597), ep->fifosel); - } -} - -static void r8a66597_ep_setting(struct r8a66597 *r8a66597, - struct r8a66597_ep *ep, - const struct usb_endpoint_descriptor *desc, - u16 pipenum, int dma) -{ - ep->use_dma = 0; - ep->fifoaddr = CFIFO; - ep->fifosel = CFIFOSEL; - ep->fifoctr = CFIFOCTR; - - ep->pipectr = get_pipectr_addr(pipenum); - if (is_bulk_pipe(pipenum) || is_isoc_pipe(pipenum)) { - ep->pipetre = get_pipetre_addr(pipenum); - ep->pipetrn = get_pipetrn_addr(pipenum); - } else { - ep->pipetre = 0; - ep->pipetrn = 0; - } - ep->pipenum = pipenum; - ep->ep.maxpacket = usb_endpoint_maxp(desc); - r8a66597->pipenum2ep[pipenum] = ep; - r8a66597->epaddr2ep[desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK] - = ep; - INIT_LIST_HEAD(&ep->queue); -} - -static void r8a66597_ep_release(struct r8a66597_ep *ep) -{ - struct r8a66597 *r8a66597 = ep->r8a66597; - u16 pipenum = ep->pipenum; - - if (pipenum == 0) - return; - - if (ep->use_dma) - r8a66597->num_dma--; - ep->pipenum = 0; - ep->busy = 0; - ep->use_dma = 0; -} - -static int alloc_pipe_config(struct r8a66597_ep *ep, - const struct usb_endpoint_descriptor *desc) -{ - struct r8a66597 *r8a66597 = ep->r8a66597; - struct r8a66597_pipe_info info; - int dma = 0; - unsigned char *counter; - int ret; - - ep->desc = desc; - - if (ep->pipenum) /* already allocated pipe */ - return 0; - - switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { - case USB_ENDPOINT_XFER_BULK: - if (r8a66597->bulk >= R8A66597_MAX_NUM_BULK) { - if (r8a66597->isochronous >= R8A66597_MAX_NUM_ISOC) { - dev_err(r8a66597_to_dev(r8a66597), - "bulk pipe is insufficient\n"); - return -ENODEV; - } else { - info.pipe = R8A66597_BASE_PIPENUM_ISOC - + r8a66597->isochronous; - counter = &r8a66597->isochronous; - } - } else { - info.pipe = R8A66597_BASE_PIPENUM_BULK + r8a66597->bulk; - counter = &r8a66597->bulk; - } - info.type = R8A66597_BULK; - dma = 1; - break; - case USB_ENDPOINT_XFER_INT: - if (r8a66597->interrupt >= R8A66597_MAX_NUM_INT) { - dev_err(r8a66597_to_dev(r8a66597), - "interrupt pipe is insufficient\n"); - return -ENODEV; - } - info.pipe = R8A66597_BASE_PIPENUM_INT + r8a66597->interrupt; - info.type = R8A66597_INT; - counter = &r8a66597->interrupt; - break; - case USB_ENDPOINT_XFER_ISOC: - if (r8a66597->isochronous >= R8A66597_MAX_NUM_ISOC) { - dev_err(r8a66597_to_dev(r8a66597), - "isochronous pipe is insufficient\n"); - return -ENODEV; - } - info.pipe = R8A66597_BASE_PIPENUM_ISOC + r8a66597->isochronous; - info.type = R8A66597_ISO; - counter = &r8a66597->isochronous; - break; - default: - dev_err(r8a66597_to_dev(r8a66597), "unexpect xfer type\n"); - return -EINVAL; - } - ep->type = info.type; - - info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - info.maxpacket = usb_endpoint_maxp(desc); - info.interval = desc->bInterval; - if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) - info.dir_in = 1; - else - info.dir_in = 0; - - ret = pipe_buffer_setting(r8a66597, &info); - if (ret < 0) { - dev_err(r8a66597_to_dev(r8a66597), - "pipe_buffer_setting fail\n"); - return ret; - } - - (*counter)++; - if ((counter == &r8a66597->isochronous) && info.type == R8A66597_BULK) - r8a66597->bulk++; - - r8a66597_ep_setting(r8a66597, ep, desc, info.pipe, dma); - pipe_initialize(ep); - - return 0; -} - -static int free_pipe_config(struct r8a66597_ep *ep) -{ - struct r8a66597 *r8a66597 = ep->r8a66597; - struct r8a66597_pipe_info info; - - info.pipe = ep->pipenum; - info.type = ep->type; - pipe_buffer_release(r8a66597, &info); - r8a66597_ep_release(ep); - - return 0; -} - -/*-------------------------------------------------------------------------*/ -static void pipe_irq_enable(struct r8a66597 *r8a66597, u16 pipenum) -{ - enable_irq_ready(r8a66597, pipenum); - enable_irq_nrdy(r8a66597, pipenum); -} - -static void pipe_irq_disable(struct r8a66597 *r8a66597, u16 pipenum) -{ - disable_irq_ready(r8a66597, pipenum); - disable_irq_nrdy(r8a66597, pipenum); -} - -/* if complete is true, gadget driver complete function is not call */ -static void control_end(struct r8a66597 *r8a66597, unsigned ccpl) -{ - r8a66597->ep[0].internal_ccpl = ccpl; - pipe_start(r8a66597, 0); - r8a66597_bset(r8a66597, CCPL, DCPCTR); -} - -static void start_ep0_write(struct r8a66597_ep *ep, - struct r8a66597_request *req) -{ - struct r8a66597 *r8a66597 = ep->r8a66597; - - pipe_change(r8a66597, ep->pipenum); - r8a66597_mdfy(r8a66597, ISEL, (ISEL | CURPIPE), CFIFOSEL); - r8a66597_write(r8a66597, BCLR, ep->fifoctr); - if (req->req.length == 0) { - r8a66597_bset(r8a66597, BVAL, ep->fifoctr); - pipe_start(r8a66597, 0); - transfer_complete(ep, req, 0); - } else { - r8a66597_write(r8a66597, ~BEMP0, BEMPSTS); - irq_ep0_write(ep, req); - } -} - -static void disable_fifosel(struct r8a66597 *r8a66597, u16 pipenum, - u16 fifosel) -{ - u16 tmp; - - tmp = r8a66597_read(r8a66597, fifosel) & CURPIPE; - if (tmp == pipenum) - r8a66597_change_curpipe(r8a66597, 0, 0, fifosel); -} - -static void change_bfre_mode(struct r8a66597 *r8a66597, u16 pipenum, - int enable) -{ - struct r8a66597_ep *ep = r8a66597->pipenum2ep[pipenum]; - u16 tmp, toggle; - - /* check current BFRE bit */ - r8a66597_write(r8a66597, pipenum, PIPESEL); - tmp = r8a66597_read(r8a66597, PIPECFG) & R8A66597_BFRE; - if ((enable && tmp) || (!enable && !tmp)) - return; - - /* change BFRE bit */ - pipe_stop(r8a66597, pipenum); - disable_fifosel(r8a66597, pipenum, CFIFOSEL); - disable_fifosel(r8a66597, pipenum, D0FIFOSEL); - disable_fifosel(r8a66597, pipenum, D1FIFOSEL); - - toggle = save_usb_toggle(r8a66597, pipenum); - - r8a66597_write(r8a66597, pipenum, PIPESEL); - if (enable) - r8a66597_bset(r8a66597, R8A66597_BFRE, PIPECFG); - else - r8a66597_bclr(r8a66597, R8A66597_BFRE, PIPECFG); - - /* initialize for internal BFRE flag */ - r8a66597_bset(r8a66597, ACLRM, ep->pipectr); - r8a66597_bclr(r8a66597, ACLRM, ep->pipectr); - - restore_usb_toggle(r8a66597, pipenum, toggle); -} - -static int sudmac_alloc_channel(struct r8a66597 *r8a66597, - struct r8a66597_ep *ep, - struct r8a66597_request *req) -{ - struct r8a66597_dma *dma; - - if (!r8a66597_is_sudmac(r8a66597)) - return -ENODEV; - - /* Check transfer type */ - if (!is_bulk_pipe(ep->pipenum)) - return -EIO; - - if (r8a66597->dma.used) - return -EBUSY; - - /* set SUDMAC parameters */ - dma = &r8a66597->dma; - dma->used = 1; - if (ep->desc->bEndpointAddress & USB_DIR_IN) { - dma->dir = 1; - } else { - dma->dir = 0; - change_bfre_mode(r8a66597, ep->pipenum, 1); - } - - /* set r8a66597_ep paramters */ - ep->use_dma = 1; - ep->dma = dma; - ep->fifoaddr = D0FIFO; - ep->fifosel = D0FIFOSEL; - ep->fifoctr = D0FIFOCTR; - - /* dma mapping */ - return usb_gadget_map_request(&r8a66597->gadget, &req->req, dma->dir); -} - -static void sudmac_free_channel(struct r8a66597 *r8a66597, - struct r8a66597_ep *ep, - struct r8a66597_request *req) -{ - if (!r8a66597_is_sudmac(r8a66597)) - return; - - usb_gadget_unmap_request(&r8a66597->gadget, &req->req, ep->dma->dir); - - r8a66597_bclr(r8a66597, DREQE, ep->fifosel); - r8a66597_change_curpipe(r8a66597, 0, 0, ep->fifosel); - - ep->dma->used = 0; - ep->use_dma = 0; - ep->fifoaddr = CFIFO; - ep->fifosel = CFIFOSEL; - ep->fifoctr = CFIFOCTR; -} - -static void sudmac_start(struct r8a66597 *r8a66597, struct r8a66597_ep *ep, - struct r8a66597_request *req) -{ - BUG_ON(req->req.length == 0); - - r8a66597_sudmac_write(r8a66597, LBA_WAIT, CH0CFG); - r8a66597_sudmac_write(r8a66597, req->req.dma, CH0BA); - r8a66597_sudmac_write(r8a66597, req->req.length, CH0BBC); - r8a66597_sudmac_write(r8a66597, CH0ENDE, DINTCTRL); - - r8a66597_sudmac_write(r8a66597, DEN, CH0DEN); -} - -static void start_packet_write(struct r8a66597_ep *ep, - struct r8a66597_request *req) -{ - struct r8a66597 *r8a66597 = ep->r8a66597; - u16 tmp; - - pipe_change(r8a66597, ep->pipenum); - disable_irq_empty(r8a66597, ep->pipenum); - pipe_start(r8a66597, ep->pipenum); - - if (req->req.length == 0) { - transfer_complete(ep, req, 0); - } else { - r8a66597_write(r8a66597, ~(1 << ep->pipenum), BRDYSTS); - if (sudmac_alloc_channel(r8a66597, ep, req) < 0) { - /* PIO mode */ - pipe_change(r8a66597, ep->pipenum); - disable_irq_empty(r8a66597, ep->pipenum); - pipe_start(r8a66597, ep->pipenum); - tmp = r8a66597_read(r8a66597, ep->fifoctr); - if (unlikely((tmp & FRDY) == 0)) - pipe_irq_enable(r8a66597, ep->pipenum); - else - irq_packet_write(ep, req); - } else { - /* DMA mode */ - pipe_change(r8a66597, ep->pipenum); - disable_irq_nrdy(r8a66597, ep->pipenum); - pipe_start(r8a66597, ep->pipenum); - enable_irq_nrdy(r8a66597, ep->pipenum); - sudmac_start(r8a66597, ep, req); - } - } -} - -static void start_packet_read(struct r8a66597_ep *ep, - struct r8a66597_request *req) -{ - struct r8a66597 *r8a66597 = ep->r8a66597; - u16 pipenum = ep->pipenum; - - if (ep->pipenum == 0) { - r8a66597_mdfy(r8a66597, 0, (ISEL | CURPIPE), CFIFOSEL); - r8a66597_write(r8a66597, BCLR, ep->fifoctr); - pipe_start(r8a66597, pipenum); - pipe_irq_enable(r8a66597, pipenum); - } else { - pipe_stop(r8a66597, pipenum); - if (ep->pipetre) { - enable_irq_nrdy(r8a66597, pipenum); - r8a66597_write(r8a66597, TRCLR, ep->pipetre); - r8a66597_write(r8a66597, - DIV_ROUND_UP(req->req.length, ep->ep.maxpacket), - ep->pipetrn); - r8a66597_bset(r8a66597, TRENB, ep->pipetre); - } - - if (sudmac_alloc_channel(r8a66597, ep, req) < 0) { - /* PIO mode */ - change_bfre_mode(r8a66597, ep->pipenum, 0); - pipe_start(r8a66597, pipenum); /* trigger once */ - pipe_irq_enable(r8a66597, pipenum); - } else { - pipe_change(r8a66597, pipenum); - sudmac_start(r8a66597, ep, req); - pipe_start(r8a66597, pipenum); /* trigger once */ - } - } -} - -static void start_packet(struct r8a66597_ep *ep, struct r8a66597_request *req) -{ - if (ep->desc->bEndpointAddress & USB_DIR_IN) - start_packet_write(ep, req); - else - start_packet_read(ep, req); -} - -static void start_ep0(struct r8a66597_ep *ep, struct r8a66597_request *req) -{ - u16 ctsq; - - ctsq = r8a66597_read(ep->r8a66597, INTSTS0) & CTSQ; - - switch (ctsq) { - case CS_RDDS: - start_ep0_write(ep, req); - break; - case CS_WRDS: - start_packet_read(ep, req); - break; - - case CS_WRND: - control_end(ep->r8a66597, 0); - break; - default: - dev_err(r8a66597_to_dev(ep->r8a66597), - "start_ep0: unexpect ctsq(%x)\n", ctsq); - break; - } -} - -static void init_controller(struct r8a66597 *r8a66597) -{ - u16 vif = r8a66597->pdata->vif ? LDRV : 0; - u16 irq_sense = r8a66597->irq_sense_low ? INTL : 0; - u16 endian = r8a66597->pdata->endian ? BIGEND : 0; - - if (r8a66597->pdata->on_chip) { - if (r8a66597->pdata->buswait) - r8a66597_write(r8a66597, r8a66597->pdata->buswait, - SYSCFG1); - else - r8a66597_write(r8a66597, 0x0f, SYSCFG1); - r8a66597_bset(r8a66597, HSE, SYSCFG0); - - r8a66597_bclr(r8a66597, USBE, SYSCFG0); - r8a66597_bclr(r8a66597, DPRPU, SYSCFG0); - r8a66597_bset(r8a66597, USBE, SYSCFG0); - - r8a66597_bset(r8a66597, SCKE, SYSCFG0); - - r8a66597_bset(r8a66597, irq_sense, INTENB1); - r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR, - DMA0CFG); - } else { - r8a66597_bset(r8a66597, vif | endian, PINCFG); - r8a66597_bset(r8a66597, HSE, SYSCFG0); /* High spd */ - r8a66597_mdfy(r8a66597, get_xtal_from_pdata(r8a66597->pdata), - XTAL, SYSCFG0); - - r8a66597_bclr(r8a66597, USBE, SYSCFG0); - r8a66597_bclr(r8a66597, DPRPU, SYSCFG0); - r8a66597_bset(r8a66597, USBE, SYSCFG0); - - r8a66597_bset(r8a66597, XCKE, SYSCFG0); - - msleep(3); - - r8a66597_bset(r8a66597, PLLC, SYSCFG0); - - msleep(1); - - r8a66597_bset(r8a66597, SCKE, SYSCFG0); - - r8a66597_bset(r8a66597, irq_sense, INTENB1); - r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR, - DMA0CFG); - } -} - -static void disable_controller(struct r8a66597 *r8a66597) -{ - if (r8a66597->pdata->on_chip) { - r8a66597_bset(r8a66597, SCKE, SYSCFG0); - r8a66597_bclr(r8a66597, UTST, TESTMODE); - - /* disable interrupts */ - r8a66597_write(r8a66597, 0, INTENB0); - r8a66597_write(r8a66597, 0, INTENB1); - r8a66597_write(r8a66597, 0, BRDYENB); - r8a66597_write(r8a66597, 0, BEMPENB); - r8a66597_write(r8a66597, 0, NRDYENB); - - /* clear status */ - r8a66597_write(r8a66597, 0, BRDYSTS); - r8a66597_write(r8a66597, 0, NRDYSTS); - r8a66597_write(r8a66597, 0, BEMPSTS); - - r8a66597_bclr(r8a66597, USBE, SYSCFG0); - r8a66597_bclr(r8a66597, SCKE, SYSCFG0); - - } else { - r8a66597_bclr(r8a66597, UTST, TESTMODE); - r8a66597_bclr(r8a66597, SCKE, SYSCFG0); - udelay(1); - r8a66597_bclr(r8a66597, PLLC, SYSCFG0); - udelay(1); - udelay(1); - r8a66597_bclr(r8a66597, XCKE, SYSCFG0); - } -} - -static void r8a66597_start_xclock(struct r8a66597 *r8a66597) -{ - u16 tmp; - - if (!r8a66597->pdata->on_chip) { - tmp = r8a66597_read(r8a66597, SYSCFG0); - if (!(tmp & XCKE)) - r8a66597_bset(r8a66597, XCKE, SYSCFG0); - } -} - -static struct r8a66597_request *get_request_from_ep(struct r8a66597_ep *ep) -{ - return list_entry(ep->queue.next, struct r8a66597_request, queue); -} - -/*-------------------------------------------------------------------------*/ -static void transfer_complete(struct r8a66597_ep *ep, - struct r8a66597_request *req, int status) -__releases(r8a66597->lock) -__acquires(r8a66597->lock) -{ - int restart = 0; - - if (unlikely(ep->pipenum == 0)) { - if (ep->internal_ccpl) { - ep->internal_ccpl = 0; - return; - } - } - - list_del_init(&req->queue); - if (ep->r8a66597->gadget.speed == USB_SPEED_UNKNOWN) - req->req.status = -ESHUTDOWN; - else - req->req.status = status; - - if (!list_empty(&ep->queue)) - restart = 1; - - if (ep->use_dma) - sudmac_free_channel(ep->r8a66597, ep, req); - - spin_unlock(&ep->r8a66597->lock); - req->req.complete(&ep->ep, &req->req); - spin_lock(&ep->r8a66597->lock); - - if (restart) { - req = get_request_from_ep(ep); - if (ep->desc) - start_packet(ep, req); - } -} - -static void irq_ep0_write(struct r8a66597_ep *ep, struct r8a66597_request *req) -{ - int i; - u16 tmp; - unsigned bufsize; - size_t size; - void *buf; - u16 pipenum = ep->pipenum; - struct r8a66597 *r8a66597 = ep->r8a66597; - - pipe_change(r8a66597, pipenum); - r8a66597_bset(r8a66597, ISEL, ep->fifosel); - - i = 0; - do { - tmp = r8a66597_read(r8a66597, ep->fifoctr); - if (i++ > 100000) { - dev_err(r8a66597_to_dev(r8a66597), - "pipe0 is busy. maybe cpu i/o bus " - "conflict. please power off this controller."); - return; - } - ndelay(1); - } while ((tmp & FRDY) == 0); - - /* prepare parameters */ - bufsize = get_buffer_size(r8a66597, pipenum); - buf = req->req.buf + req->req.actual; - size = min(bufsize, req->req.length - req->req.actual); - - /* write fifo */ - if (req->req.buf) { - if (size > 0) - r8a66597_write_fifo(r8a66597, ep, buf, size); - if ((size == 0) || ((size % ep->ep.maxpacket) != 0)) - r8a66597_bset(r8a66597, BVAL, ep->fifoctr); - } - - /* update parameters */ - req->req.actual += size; - - /* check transfer finish */ - if ((!req->req.zero && (req->req.actual == req->req.length)) - || (size % ep->ep.maxpacket) - || (size == 0)) { - disable_irq_ready(r8a66597, pipenum); - disable_irq_empty(r8a66597, pipenum); - } else { - disable_irq_ready(r8a66597, pipenum); - enable_irq_empty(r8a66597, pipenum); - } - pipe_start(r8a66597, pipenum); -} - -static void irq_packet_write(struct r8a66597_ep *ep, - struct r8a66597_request *req) -{ - u16 tmp; - unsigned bufsize; - size_t size; - void *buf; - u16 pipenum = ep->pipenum; - struct r8a66597 *r8a66597 = ep->r8a66597; - - pipe_change(r8a66597, pipenum); - tmp = r8a66597_read(r8a66597, ep->fifoctr); - if (unlikely((tmp & FRDY) == 0)) { - pipe_stop(r8a66597, pipenum); - pipe_irq_disable(r8a66597, pipenum); - dev_err(r8a66597_to_dev(r8a66597), - "write fifo not ready. pipnum=%d\n", pipenum); - return; - } - - /* prepare parameters */ - bufsize = get_buffer_size(r8a66597, pipenum); - buf = req->req.buf + req->req.actual; - size = min(bufsize, req->req.length - req->req.actual); - - /* write fifo */ - if (req->req.buf) { - r8a66597_write_fifo(r8a66597, ep, buf, size); - if ((size == 0) - || ((size % ep->ep.maxpacket) != 0) - || ((bufsize != ep->ep.maxpacket) - && (bufsize > size))) - r8a66597_bset(r8a66597, BVAL, ep->fifoctr); - } - - /* update parameters */ - req->req.actual += size; - /* check transfer finish */ - if ((!req->req.zero && (req->req.actual == req->req.length)) - || (size % ep->ep.maxpacket) - || (size == 0)) { - disable_irq_ready(r8a66597, pipenum); - enable_irq_empty(r8a66597, pipenum); - } else { - disable_irq_empty(r8a66597, pipenum); - pipe_irq_enable(r8a66597, pipenum); - } -} - -static void irq_packet_read(struct r8a66597_ep *ep, - struct r8a66597_request *req) -{ - u16 tmp; - int rcv_len, bufsize, req_len; - int size; - void *buf; - u16 pipenum = ep->pipenum; - struct r8a66597 *r8a66597 = ep->r8a66597; - int finish = 0; - - pipe_change(r8a66597, pipenum); - tmp = r8a66597_read(r8a66597, ep->fifoctr); - if (unlikely((tmp & FRDY) == 0)) { - req->req.status = -EPIPE; - pipe_stop(r8a66597, pipenum); - pipe_irq_disable(r8a66597, pipenum); - dev_err(r8a66597_to_dev(r8a66597), "read fifo not ready"); - return; - } - - /* prepare parameters */ - rcv_len = tmp & DTLN; - bufsize = get_buffer_size(r8a66597, pipenum); - - buf = req->req.buf + req->req.actual; - req_len = req->req.length - req->req.actual; - if (rcv_len < bufsize) - size = min(rcv_len, req_len); - else - size = min(bufsize, req_len); - - /* update parameters */ - req->req.actual += size; - - /* check transfer finish */ - if ((!req->req.zero && (req->req.actual == req->req.length)) - || (size % ep->ep.maxpacket) - || (size == 0)) { - pipe_stop(r8a66597, pipenum); - pipe_irq_disable(r8a66597, pipenum); - finish = 1; - } - - /* read fifo */ - if (req->req.buf) { - if (size == 0) - r8a66597_write(r8a66597, BCLR, ep->fifoctr); - else - r8a66597_read_fifo(r8a66597, ep->fifoaddr, buf, size); - - } - - if ((ep->pipenum != 0) && finish) - transfer_complete(ep, req, 0); -} - -static void irq_pipe_ready(struct r8a66597 *r8a66597, u16 status, u16 enb) -{ - u16 check; - u16 pipenum; - struct r8a66597_ep *ep; - struct r8a66597_request *req; - - if ((status & BRDY0) && (enb & BRDY0)) { - r8a66597_write(r8a66597, ~BRDY0, BRDYSTS); - r8a66597_mdfy(r8a66597, 0, CURPIPE, CFIFOSEL); - - ep = &r8a66597->ep[0]; - req = get_request_from_ep(ep); - irq_packet_read(ep, req); - } else { - for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) { - check = 1 << pipenum; - if ((status & check) && (enb & check)) { - r8a66597_write(r8a66597, ~check, BRDYSTS); - ep = r8a66597->pipenum2ep[pipenum]; - req = get_request_from_ep(ep); - if (ep->desc->bEndpointAddress & USB_DIR_IN) - irq_packet_write(ep, req); - else - irq_packet_read(ep, req); - } - } - } -} - -static void irq_pipe_empty(struct r8a66597 *r8a66597, u16 status, u16 enb) -{ - u16 tmp; - u16 check; - u16 pipenum; - struct r8a66597_ep *ep; - struct r8a66597_request *req; - - if ((status & BEMP0) && (enb & BEMP0)) { - r8a66597_write(r8a66597, ~BEMP0, BEMPSTS); - - ep = &r8a66597->ep[0]; - req = get_request_from_ep(ep); - irq_ep0_write(ep, req); - } else { - for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) { - check = 1 << pipenum; - if ((status & check) && (enb & check)) { - r8a66597_write(r8a66597, ~check, BEMPSTS); - tmp = control_reg_get(r8a66597, pipenum); - if ((tmp & INBUFM) == 0) { - disable_irq_empty(r8a66597, pipenum); - pipe_irq_disable(r8a66597, pipenum); - pipe_stop(r8a66597, pipenum); - ep = r8a66597->pipenum2ep[pipenum]; - req = get_request_from_ep(ep); - if (!list_empty(&ep->queue)) - transfer_complete(ep, req, 0); - } - } - } - } -} - -static void get_status(struct r8a66597 *r8a66597, struct usb_ctrlrequest *ctrl) -__releases(r8a66597->lock) -__acquires(r8a66597->lock) -{ - struct r8a66597_ep *ep; - u16 pid; - u16 status = 0; - u16 w_index = le16_to_cpu(ctrl->wIndex); - - switch (ctrl->bRequestType & USB_RECIP_MASK) { - case USB_RECIP_DEVICE: - status = 1 << USB_DEVICE_SELF_POWERED; - break; - case USB_RECIP_INTERFACE: - status = 0; - break; - case USB_RECIP_ENDPOINT: - ep = r8a66597->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK]; - pid = control_reg_get_pid(r8a66597, ep->pipenum); - if (pid == PID_STALL) - status = 1 << USB_ENDPOINT_HALT; - else - status = 0; - break; - default: - pipe_stall(r8a66597, 0); - return; /* exit */ - } - - r8a66597->ep0_data = cpu_to_le16(status); - r8a66597->ep0_req->buf = &r8a66597->ep0_data; - r8a66597->ep0_req->length = 2; - /* AV: what happens if we get called again before that gets through? */ - spin_unlock(&r8a66597->lock); - r8a66597_queue(r8a66597->gadget.ep0, r8a66597->ep0_req, GFP_KERNEL); - spin_lock(&r8a66597->lock); -} - -static void clear_feature(struct r8a66597 *r8a66597, - struct usb_ctrlrequest *ctrl) -{ - switch (ctrl->bRequestType & USB_RECIP_MASK) { - case USB_RECIP_DEVICE: - control_end(r8a66597, 1); - break; - case USB_RECIP_INTERFACE: - control_end(r8a66597, 1); - break; - case USB_RECIP_ENDPOINT: { - struct r8a66597_ep *ep; - struct r8a66597_request *req; - u16 w_index = le16_to_cpu(ctrl->wIndex); - - ep = r8a66597->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK]; - if (!ep->wedge) { - pipe_stop(r8a66597, ep->pipenum); - control_reg_sqclr(r8a66597, ep->pipenum); - spin_unlock(&r8a66597->lock); - usb_ep_clear_halt(&ep->ep); - spin_lock(&r8a66597->lock); - } - - control_end(r8a66597, 1); - - req = get_request_from_ep(ep); - if (ep->busy) { - ep->busy = 0; - if (list_empty(&ep->queue)) - break; - start_packet(ep, req); - } else if (!list_empty(&ep->queue)) - pipe_start(r8a66597, ep->pipenum); - } - break; - default: - pipe_stall(r8a66597, 0); - break; - } -} - -static void set_feature(struct r8a66597 *r8a66597, struct usb_ctrlrequest *ctrl) -{ - u16 tmp; - int timeout = 3000; - - switch (ctrl->bRequestType & USB_RECIP_MASK) { - case USB_RECIP_DEVICE: - switch (le16_to_cpu(ctrl->wValue)) { - case USB_DEVICE_TEST_MODE: - control_end(r8a66597, 1); - /* Wait for the completion of status stage */ - do { - tmp = r8a66597_read(r8a66597, INTSTS0) & CTSQ; - udelay(1); - } while (tmp != CS_IDST || timeout-- > 0); - - if (tmp == CS_IDST) - r8a66597_bset(r8a66597, - le16_to_cpu(ctrl->wIndex >> 8), - TESTMODE); - break; - default: - pipe_stall(r8a66597, 0); - break; - } - break; - case USB_RECIP_INTERFACE: - control_end(r8a66597, 1); - break; - case USB_RECIP_ENDPOINT: { - struct r8a66597_ep *ep; - u16 w_index = le16_to_cpu(ctrl->wIndex); - - ep = r8a66597->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK]; - pipe_stall(r8a66597, ep->pipenum); - - control_end(r8a66597, 1); - } - break; - default: - pipe_stall(r8a66597, 0); - break; - } -} - -/* if return value is true, call class driver's setup() */ -static int setup_packet(struct r8a66597 *r8a66597, struct usb_ctrlrequest *ctrl) -{ - u16 *p = (u16 *)ctrl; - unsigned long offset = USBREQ; - int i, ret = 0; - - /* read fifo */ - r8a66597_write(r8a66597, ~VALID, INTSTS0); - - for (i = 0; i < 4; i++) - p[i] = r8a66597_read(r8a66597, offset + i*2); - - /* check request */ - if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { - switch (ctrl->bRequest) { - case USB_REQ_GET_STATUS: - get_status(r8a66597, ctrl); - break; - case USB_REQ_CLEAR_FEATURE: - clear_feature(r8a66597, ctrl); - break; - case USB_REQ_SET_FEATURE: - set_feature(r8a66597, ctrl); - break; - default: - ret = 1; - break; - } - } else - ret = 1; - return ret; -} - -static void r8a66597_update_usb_speed(struct r8a66597 *r8a66597) -{ - u16 speed = get_usb_speed(r8a66597); - - switch (speed) { - case HSMODE: - r8a66597->gadget.speed = USB_SPEED_HIGH; - break; - case FSMODE: - r8a66597->gadget.speed = USB_SPEED_FULL; - break; - default: - r8a66597->gadget.speed = USB_SPEED_UNKNOWN; - dev_err(r8a66597_to_dev(r8a66597), "USB speed unknown\n"); - } -} - -static void irq_device_state(struct r8a66597 *r8a66597) -{ - u16 dvsq; - - dvsq = r8a66597_read(r8a66597, INTSTS0) & DVSQ; - r8a66597_write(r8a66597, ~DVST, INTSTS0); - - if (dvsq == DS_DFLT) { - /* bus reset */ - spin_unlock(&r8a66597->lock); - r8a66597->driver->disconnect(&r8a66597->gadget); - spin_lock(&r8a66597->lock); - r8a66597_update_usb_speed(r8a66597); - } - if (r8a66597->old_dvsq == DS_CNFG && dvsq != DS_CNFG) - r8a66597_update_usb_speed(r8a66597); - if ((dvsq == DS_CNFG || dvsq == DS_ADDS) - && r8a66597->gadget.speed == USB_SPEED_UNKNOWN) - r8a66597_update_usb_speed(r8a66597); - - r8a66597->old_dvsq = dvsq; -} - -static void irq_control_stage(struct r8a66597 *r8a66597) -__releases(r8a66597->lock) -__acquires(r8a66597->lock) -{ - struct usb_ctrlrequest ctrl; - u16 ctsq; - - ctsq = r8a66597_read(r8a66597, INTSTS0) & CTSQ; - r8a66597_write(r8a66597, ~CTRT, INTSTS0); - - switch (ctsq) { - case CS_IDST: { - struct r8a66597_ep *ep; - struct r8a66597_request *req; - ep = &r8a66597->ep[0]; - req = get_request_from_ep(ep); - transfer_complete(ep, req, 0); - } - break; - - case CS_RDDS: - case CS_WRDS: - case CS_WRND: - if (setup_packet(r8a66597, &ctrl)) { - spin_unlock(&r8a66597->lock); - if (r8a66597->driver->setup(&r8a66597->gadget, &ctrl) - < 0) - pipe_stall(r8a66597, 0); - spin_lock(&r8a66597->lock); - } - break; - case CS_RDSS: - case CS_WRSS: - control_end(r8a66597, 0); - break; - default: - dev_err(r8a66597_to_dev(r8a66597), - "ctrl_stage: unexpect ctsq(%x)\n", ctsq); - break; - } -} - -static void sudmac_finish(struct r8a66597 *r8a66597, struct r8a66597_ep *ep) -{ - u16 pipenum; - struct r8a66597_request *req; - u32 len; - int i = 0; - - pipenum = ep->pipenum; - pipe_change(r8a66597, pipenum); - - while (!(r8a66597_read(r8a66597, ep->fifoctr) & FRDY)) { - udelay(1); - if (unlikely(i++ >= 10000)) { /* timeout = 10 msec */ - dev_err(r8a66597_to_dev(r8a66597), - "%s: FRDY was not set (%d)\n", - __func__, pipenum); - return; - } - } - - r8a66597_bset(r8a66597, BCLR, ep->fifoctr); - req = get_request_from_ep(ep); - - /* prepare parameters */ - len = r8a66597_sudmac_read(r8a66597, CH0CBC); - req->req.actual += len; - - /* clear */ - r8a66597_sudmac_write(r8a66597, CH0STCLR, DSTSCLR); - - /* check transfer finish */ - if ((!req->req.zero && (req->req.actual == req->req.length)) - || (len % ep->ep.maxpacket)) { - if (ep->dma->dir) { - disable_irq_ready(r8a66597, pipenum); - enable_irq_empty(r8a66597, pipenum); - } else { - /* Clear the interrupt flag for next transfer */ - r8a66597_write(r8a66597, ~(1 << pipenum), BRDYSTS); - transfer_complete(ep, req, 0); - } - } -} - -static void r8a66597_sudmac_irq(struct r8a66597 *r8a66597) -{ - u32 irqsts; - struct r8a66597_ep *ep; - u16 pipenum; - - irqsts = r8a66597_sudmac_read(r8a66597, DINTSTS); - if (irqsts & CH0ENDS) { - r8a66597_sudmac_write(r8a66597, CH0ENDC, DINTSTSCLR); - pipenum = (r8a66597_read(r8a66597, D0FIFOSEL) & CURPIPE); - ep = r8a66597->pipenum2ep[pipenum]; - sudmac_finish(r8a66597, ep); - } -} - -static irqreturn_t r8a66597_irq(int irq, void *_r8a66597) -{ - struct r8a66597 *r8a66597 = _r8a66597; - u16 intsts0; - u16 intenb0; - u16 brdysts, nrdysts, bempsts; - u16 brdyenb, nrdyenb, bempenb; - u16 savepipe; - u16 mask0; - - if (r8a66597_is_sudmac(r8a66597)) - r8a66597_sudmac_irq(r8a66597); - - spin_lock(&r8a66597->lock); - - intsts0 = r8a66597_read(r8a66597, INTSTS0); - intenb0 = r8a66597_read(r8a66597, INTENB0); - - savepipe = r8a66597_read(r8a66597, CFIFOSEL); - - mask0 = intsts0 & intenb0; - if (mask0) { - brdysts = r8a66597_read(r8a66597, BRDYSTS); - nrdysts = r8a66597_read(r8a66597, NRDYSTS); - bempsts = r8a66597_read(r8a66597, BEMPSTS); - brdyenb = r8a66597_read(r8a66597, BRDYENB); - nrdyenb = r8a66597_read(r8a66597, NRDYENB); - bempenb = r8a66597_read(r8a66597, BEMPENB); - - if (mask0 & VBINT) { - r8a66597_write(r8a66597, 0xffff & ~VBINT, - INTSTS0); - r8a66597_start_xclock(r8a66597); - - /* start vbus sampling */ - r8a66597->old_vbus = r8a66597_read(r8a66597, INTSTS0) - & VBSTS; - r8a66597->scount = R8A66597_MAX_SAMPLING; - - mod_timer(&r8a66597->timer, - jiffies + msecs_to_jiffies(50)); - } - if (intsts0 & DVSQ) - irq_device_state(r8a66597); - - if ((intsts0 & BRDY) && (intenb0 & BRDYE) - && (brdysts & brdyenb)) - irq_pipe_ready(r8a66597, brdysts, brdyenb); - if ((intsts0 & BEMP) && (intenb0 & BEMPE) - && (bempsts & bempenb)) - irq_pipe_empty(r8a66597, bempsts, bempenb); - - if (intsts0 & CTRT) - irq_control_stage(r8a66597); - } - - r8a66597_write(r8a66597, savepipe, CFIFOSEL); - - spin_unlock(&r8a66597->lock); - return IRQ_HANDLED; -} - -static void r8a66597_timer(unsigned long _r8a66597) -{ - struct r8a66597 *r8a66597 = (struct r8a66597 *)_r8a66597; - unsigned long flags; - u16 tmp; - - spin_lock_irqsave(&r8a66597->lock, flags); - tmp = r8a66597_read(r8a66597, SYSCFG0); - if (r8a66597->scount > 0) { - tmp = r8a66597_read(r8a66597, INTSTS0) & VBSTS; - if (tmp == r8a66597->old_vbus) { - r8a66597->scount--; - if (r8a66597->scount == 0) { - if (tmp == VBSTS) - r8a66597_usb_connect(r8a66597); - else - r8a66597_usb_disconnect(r8a66597); - } else { - mod_timer(&r8a66597->timer, - jiffies + msecs_to_jiffies(50)); - } - } else { - r8a66597->scount = R8A66597_MAX_SAMPLING; - r8a66597->old_vbus = tmp; - mod_timer(&r8a66597->timer, - jiffies + msecs_to_jiffies(50)); - } - } - spin_unlock_irqrestore(&r8a66597->lock, flags); -} - -/*-------------------------------------------------------------------------*/ -static int r8a66597_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct r8a66597_ep *ep; - - ep = container_of(_ep, struct r8a66597_ep, ep); - return alloc_pipe_config(ep, desc); -} - -static int r8a66597_disable(struct usb_ep *_ep) -{ - struct r8a66597_ep *ep; - struct r8a66597_request *req; - unsigned long flags; - - ep = container_of(_ep, struct r8a66597_ep, ep); - BUG_ON(!ep); - - while (!list_empty(&ep->queue)) { - req = get_request_from_ep(ep); - spin_lock_irqsave(&ep->r8a66597->lock, flags); - transfer_complete(ep, req, -ECONNRESET); - spin_unlock_irqrestore(&ep->r8a66597->lock, flags); - } - - pipe_irq_disable(ep->r8a66597, ep->pipenum); - return free_pipe_config(ep); -} - -static struct usb_request *r8a66597_alloc_request(struct usb_ep *_ep, - gfp_t gfp_flags) -{ - struct r8a66597_request *req; - - req = kzalloc(sizeof(struct r8a66597_request), gfp_flags); - if (!req) - return NULL; - - INIT_LIST_HEAD(&req->queue); - - return &req->req; -} - -static void r8a66597_free_request(struct usb_ep *_ep, struct usb_request *_req) -{ - struct r8a66597_request *req; - - req = container_of(_req, struct r8a66597_request, req); - kfree(req); -} - -static int r8a66597_queue(struct usb_ep *_ep, struct usb_request *_req, - gfp_t gfp_flags) -{ - struct r8a66597_ep *ep; - struct r8a66597_request *req; - unsigned long flags; - int request = 0; - - ep = container_of(_ep, struct r8a66597_ep, ep); - req = container_of(_req, struct r8a66597_request, req); - - if (ep->r8a66597->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - spin_lock_irqsave(&ep->r8a66597->lock, flags); - - if (list_empty(&ep->queue)) - request = 1; - - list_add_tail(&req->queue, &ep->queue); - req->req.actual = 0; - req->req.status = -EINPROGRESS; - - if (ep->desc == NULL) /* control */ - start_ep0(ep, req); - else { - if (request && !ep->busy) - start_packet(ep, req); - } - - spin_unlock_irqrestore(&ep->r8a66597->lock, flags); - - return 0; -} - -static int r8a66597_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct r8a66597_ep *ep; - struct r8a66597_request *req; - unsigned long flags; - - ep = container_of(_ep, struct r8a66597_ep, ep); - req = container_of(_req, struct r8a66597_request, req); - - spin_lock_irqsave(&ep->r8a66597->lock, flags); - if (!list_empty(&ep->queue)) - transfer_complete(ep, req, -ECONNRESET); - spin_unlock_irqrestore(&ep->r8a66597->lock, flags); - - return 0; -} - -static int r8a66597_set_halt(struct usb_ep *_ep, int value) -{ - struct r8a66597_ep *ep; - struct r8a66597_request *req; - unsigned long flags; - int ret = 0; - - ep = container_of(_ep, struct r8a66597_ep, ep); - req = get_request_from_ep(ep); - - spin_lock_irqsave(&ep->r8a66597->lock, flags); - if (!list_empty(&ep->queue)) { - ret = -EAGAIN; - goto out; - } - if (value) { - ep->busy = 1; - pipe_stall(ep->r8a66597, ep->pipenum); - } else { - ep->busy = 0; - ep->wedge = 0; - pipe_stop(ep->r8a66597, ep->pipenum); - } - -out: - spin_unlock_irqrestore(&ep->r8a66597->lock, flags); - return ret; -} - -static int r8a66597_set_wedge(struct usb_ep *_ep) -{ - struct r8a66597_ep *ep; - unsigned long flags; - - ep = container_of(_ep, struct r8a66597_ep, ep); - - if (!ep || !ep->desc) - return -EINVAL; - - spin_lock_irqsave(&ep->r8a66597->lock, flags); - ep->wedge = 1; - spin_unlock_irqrestore(&ep->r8a66597->lock, flags); - - return usb_ep_set_halt(_ep); -} - -static void r8a66597_fifo_flush(struct usb_ep *_ep) -{ - struct r8a66597_ep *ep; - unsigned long flags; - - ep = container_of(_ep, struct r8a66597_ep, ep); - spin_lock_irqsave(&ep->r8a66597->lock, flags); - if (list_empty(&ep->queue) && !ep->busy) { - pipe_stop(ep->r8a66597, ep->pipenum); - r8a66597_bclr(ep->r8a66597, BCLR, ep->fifoctr); - r8a66597_write(ep->r8a66597, ACLRM, ep->pipectr); - r8a66597_write(ep->r8a66597, 0, ep->pipectr); - } - spin_unlock_irqrestore(&ep->r8a66597->lock, flags); -} - -static struct usb_ep_ops r8a66597_ep_ops = { - .enable = r8a66597_enable, - .disable = r8a66597_disable, - - .alloc_request = r8a66597_alloc_request, - .free_request = r8a66597_free_request, - - .queue = r8a66597_queue, - .dequeue = r8a66597_dequeue, - - .set_halt = r8a66597_set_halt, - .set_wedge = r8a66597_set_wedge, - .fifo_flush = r8a66597_fifo_flush, -}; - -/*-------------------------------------------------------------------------*/ -static int r8a66597_start(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) -{ - struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget); - - if (!driver - || driver->max_speed < USB_SPEED_HIGH - || !driver->setup) - return -EINVAL; - if (!r8a66597) - return -ENODEV; - - /* hook up the driver */ - r8a66597->driver = driver; - - init_controller(r8a66597); - r8a66597_bset(r8a66597, VBSE, INTENB0); - if (r8a66597_read(r8a66597, INTSTS0) & VBSTS) { - r8a66597_start_xclock(r8a66597); - /* start vbus sampling */ - r8a66597->old_vbus = r8a66597_read(r8a66597, - INTSTS0) & VBSTS; - r8a66597->scount = R8A66597_MAX_SAMPLING; - mod_timer(&r8a66597->timer, jiffies + msecs_to_jiffies(50)); - } - - return 0; -} - -static int r8a66597_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) -{ - struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget); - unsigned long flags; - - spin_lock_irqsave(&r8a66597->lock, flags); - r8a66597_bclr(r8a66597, VBSE, INTENB0); - disable_controller(r8a66597); - spin_unlock_irqrestore(&r8a66597->lock, flags); - - r8a66597->driver = NULL; - return 0; -} - -/*-------------------------------------------------------------------------*/ -static int r8a66597_get_frame(struct usb_gadget *_gadget) -{ - struct r8a66597 *r8a66597 = gadget_to_r8a66597(_gadget); - return r8a66597_read(r8a66597, FRMNUM) & 0x03FF; -} - -static int r8a66597_pullup(struct usb_gadget *gadget, int is_on) -{ - struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget); - unsigned long flags; - - spin_lock_irqsave(&r8a66597->lock, flags); - if (is_on) - r8a66597_bset(r8a66597, DPRPU, SYSCFG0); - else - r8a66597_bclr(r8a66597, DPRPU, SYSCFG0); - spin_unlock_irqrestore(&r8a66597->lock, flags); - - return 0; -} - -static struct usb_gadget_ops r8a66597_gadget_ops = { - .get_frame = r8a66597_get_frame, - .udc_start = r8a66597_start, - .udc_stop = r8a66597_stop, - .pullup = r8a66597_pullup, -}; - -static int __exit r8a66597_remove(struct platform_device *pdev) -{ - struct r8a66597 *r8a66597 = dev_get_drvdata(&pdev->dev); - - usb_del_gadget_udc(&r8a66597->gadget); - del_timer_sync(&r8a66597->timer); - iounmap(r8a66597->reg); - if (r8a66597->pdata->sudmac) - iounmap(r8a66597->sudmac_reg); - free_irq(platform_get_irq(pdev, 0), r8a66597); - r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req); -#ifdef CONFIG_HAVE_CLK - if (r8a66597->pdata->on_chip) { - clk_disable(r8a66597->clk); - clk_put(r8a66597->clk); - } -#endif - device_unregister(&r8a66597->gadget.dev); - kfree(r8a66597); - return 0; -} - -static void nop_completion(struct usb_ep *ep, struct usb_request *r) -{ -} - -static int __init r8a66597_sudmac_ioremap(struct r8a66597 *r8a66597, - struct platform_device *pdev) -{ - struct resource *res; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sudmac"); - if (!res) { - dev_err(&pdev->dev, "platform_get_resource error(sudmac).\n"); - return -ENODEV; - } - - r8a66597->sudmac_reg = ioremap(res->start, resource_size(res)); - if (r8a66597->sudmac_reg == NULL) { - dev_err(&pdev->dev, "ioremap error(sudmac).\n"); - return -ENOMEM; - } - - return 0; -} - -static int __init r8a66597_probe(struct platform_device *pdev) -{ -#ifdef CONFIG_HAVE_CLK - char clk_name[8]; -#endif - struct resource *res, *ires; - int irq; - void __iomem *reg = NULL; - struct r8a66597 *r8a66597 = NULL; - int ret = 0; - int i; - unsigned long irq_trigger; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENODEV; - dev_err(&pdev->dev, "platform_get_resource error.\n"); - goto clean_up; - } - - ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - irq = ires->start; - irq_trigger = ires->flags & IRQF_TRIGGER_MASK; - - if (irq < 0) { - ret = -ENODEV; - dev_err(&pdev->dev, "platform_get_irq error.\n"); - goto clean_up; - } - - reg = ioremap(res->start, resource_size(res)); - if (reg == NULL) { - ret = -ENOMEM; - dev_err(&pdev->dev, "ioremap error.\n"); - goto clean_up; - } - - /* initialize ucd */ - r8a66597 = kzalloc(sizeof(struct r8a66597), GFP_KERNEL); - if (r8a66597 == NULL) { - ret = -ENOMEM; - dev_err(&pdev->dev, "kzalloc error\n"); - goto clean_up; - } - - spin_lock_init(&r8a66597->lock); - dev_set_drvdata(&pdev->dev, r8a66597); - r8a66597->pdata = pdev->dev.platform_data; - r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW; - - r8a66597->gadget.ops = &r8a66597_gadget_ops; - dev_set_name(&r8a66597->gadget.dev, "gadget"); - r8a66597->gadget.max_speed = USB_SPEED_HIGH; - r8a66597->gadget.dev.parent = &pdev->dev; - r8a66597->gadget.dev.dma_mask = pdev->dev.dma_mask; - r8a66597->gadget.dev.release = pdev->dev.release; - r8a66597->gadget.name = udc_name; - ret = device_register(&r8a66597->gadget.dev); - if (ret < 0) { - dev_err(&pdev->dev, "device_register failed\n"); - goto clean_up; - } - - init_timer(&r8a66597->timer); - r8a66597->timer.function = r8a66597_timer; - r8a66597->timer.data = (unsigned long)r8a66597; - r8a66597->reg = reg; - -#ifdef CONFIG_HAVE_CLK - if (r8a66597->pdata->on_chip) { - snprintf(clk_name, sizeof(clk_name), "usb%d", pdev->id); - r8a66597->clk = clk_get(&pdev->dev, clk_name); - if (IS_ERR(r8a66597->clk)) { - dev_err(&pdev->dev, "cannot get clock \"%s\"\n", - clk_name); - ret = PTR_ERR(r8a66597->clk); - goto clean_up_dev; - } - clk_enable(r8a66597->clk); - } -#endif - if (r8a66597->pdata->sudmac) { - ret = r8a66597_sudmac_ioremap(r8a66597, pdev); - if (ret < 0) - goto clean_up2; - } - - disable_controller(r8a66597); /* make sure controller is disabled */ - - ret = request_irq(irq, r8a66597_irq, IRQF_SHARED, - udc_name, r8a66597); - if (ret < 0) { - dev_err(&pdev->dev, "request_irq error (%d)\n", ret); - goto clean_up2; - } - - INIT_LIST_HEAD(&r8a66597->gadget.ep_list); - r8a66597->gadget.ep0 = &r8a66597->ep[0].ep; - INIT_LIST_HEAD(&r8a66597->gadget.ep0->ep_list); - for (i = 0; i < R8A66597_MAX_NUM_PIPE; i++) { - struct r8a66597_ep *ep = &r8a66597->ep[i]; - - if (i != 0) { - INIT_LIST_HEAD(&r8a66597->ep[i].ep.ep_list); - list_add_tail(&r8a66597->ep[i].ep.ep_list, - &r8a66597->gadget.ep_list); - } - ep->r8a66597 = r8a66597; - INIT_LIST_HEAD(&ep->queue); - ep->ep.name = r8a66597_ep_name[i]; - ep->ep.ops = &r8a66597_ep_ops; - ep->ep.maxpacket = 512; - } - r8a66597->ep[0].ep.maxpacket = 64; - r8a66597->ep[0].pipenum = 0; - r8a66597->ep[0].fifoaddr = CFIFO; - r8a66597->ep[0].fifosel = CFIFOSEL; - r8a66597->ep[0].fifoctr = CFIFOCTR; - r8a66597->ep[0].pipectr = get_pipectr_addr(0); - r8a66597->pipenum2ep[0] = &r8a66597->ep[0]; - r8a66597->epaddr2ep[0] = &r8a66597->ep[0]; - - r8a66597->ep0_req = r8a66597_alloc_request(&r8a66597->ep[0].ep, - GFP_KERNEL); - if (r8a66597->ep0_req == NULL) - goto clean_up3; - r8a66597->ep0_req->complete = nop_completion; - - ret = usb_add_gadget_udc(&pdev->dev, &r8a66597->gadget); - if (ret) - goto err_add_udc; - - dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION); - return 0; - -err_add_udc: - r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req); -clean_up3: - free_irq(irq, r8a66597); -clean_up2: -#ifdef CONFIG_HAVE_CLK - if (r8a66597->pdata->on_chip) { - clk_disable(r8a66597->clk); - clk_put(r8a66597->clk); - } -clean_up_dev: -#endif - device_unregister(&r8a66597->gadget.dev); -clean_up: - if (r8a66597) { - if (r8a66597->sudmac_reg) - iounmap(r8a66597->sudmac_reg); - if (r8a66597->ep0_req) - r8a66597_free_request(&r8a66597->ep[0].ep, - r8a66597->ep0_req); - kfree(r8a66597); - } - if (reg) - iounmap(reg); - - return ret; -} - -/*-------------------------------------------------------------------------*/ -static struct platform_driver r8a66597_driver = { - .remove = __exit_p(r8a66597_remove), - .driver = { - .name = (char *) udc_name, - }, -}; -MODULE_ALIAS("platform:r8a66597_udc"); - -static int __init r8a66597_udc_init(void) -{ - return platform_driver_probe(&r8a66597_driver, r8a66597_probe); -} -module_init(r8a66597_udc_init); - -static void __exit r8a66597_udc_cleanup(void) -{ - platform_driver_unregister(&r8a66597_driver); -} -module_exit(r8a66597_udc_cleanup); - -MODULE_DESCRIPTION("R8A66597 USB gadget driver"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Yoshihiro Shimoda"); - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/r8a66597-udc.h b/ANDROID_3.4.5/drivers/usb/gadget/r8a66597-udc.h deleted file mode 100644 index 8e3de61c..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/r8a66597-udc.h +++ /dev/null @@ -1,294 +0,0 @@ -/* - * R8A66597 UDC - * - * Copyright (C) 2007-2009 Renesas Solutions Corp. - * - * Author : Yoshihiro Shimoda - * - * 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; version 2 of the License. - */ - -#ifndef __R8A66597_H__ -#define __R8A66597_H__ - -#ifdef CONFIG_HAVE_CLK -#include -#endif - -#include - -#define R8A66597_MAX_SAMPLING 10 - -#define R8A66597_MAX_NUM_PIPE 8 -#define R8A66597_MAX_NUM_BULK 3 -#define R8A66597_MAX_NUM_ISOC 2 -#define R8A66597_MAX_NUM_INT 2 - -#define R8A66597_BASE_PIPENUM_BULK 3 -#define R8A66597_BASE_PIPENUM_ISOC 1 -#define R8A66597_BASE_PIPENUM_INT 6 - -#define R8A66597_BASE_BUFNUM 6 -#define R8A66597_MAX_BUFNUM 0x4F - -#define is_bulk_pipe(pipenum) \ - ((pipenum >= R8A66597_BASE_PIPENUM_BULK) && \ - (pipenum < (R8A66597_BASE_PIPENUM_BULK + R8A66597_MAX_NUM_BULK))) -#define is_interrupt_pipe(pipenum) \ - ((pipenum >= R8A66597_BASE_PIPENUM_INT) && \ - (pipenum < (R8A66597_BASE_PIPENUM_INT + R8A66597_MAX_NUM_INT))) -#define is_isoc_pipe(pipenum) \ - ((pipenum >= R8A66597_BASE_PIPENUM_ISOC) && \ - (pipenum < (R8A66597_BASE_PIPENUM_ISOC + R8A66597_MAX_NUM_ISOC))) - -#define r8a66597_is_sudmac(r8a66597) (r8a66597->pdata->sudmac) -struct r8a66597_pipe_info { - u16 pipe; - u16 epnum; - u16 maxpacket; - u16 type; - u16 interval; - u16 dir_in; -}; - -struct r8a66597_request { - struct usb_request req; - struct list_head queue; -}; - -struct r8a66597_ep { - struct usb_ep ep; - struct r8a66597 *r8a66597; - struct r8a66597_dma *dma; - - struct list_head queue; - unsigned busy:1; - unsigned wedge:1; - unsigned internal_ccpl:1; /* use only control */ - - /* this member can able to after r8a66597_enable */ - unsigned use_dma:1; - u16 pipenum; - u16 type; - const struct usb_endpoint_descriptor *desc; - /* register address */ - unsigned char fifoaddr; - unsigned char fifosel; - unsigned char fifoctr; - unsigned char pipectr; - unsigned char pipetre; - unsigned char pipetrn; -}; - -struct r8a66597_dma { - unsigned used:1; - unsigned dir:1; /* 1 = IN(write), 0 = OUT(read) */ -}; - -struct r8a66597 { - spinlock_t lock; - void __iomem *reg; - void __iomem *sudmac_reg; - -#ifdef CONFIG_HAVE_CLK - struct clk *clk; -#endif - struct r8a66597_platdata *pdata; - - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - - struct r8a66597_ep ep[R8A66597_MAX_NUM_PIPE]; - struct r8a66597_ep *pipenum2ep[R8A66597_MAX_NUM_PIPE]; - struct r8a66597_ep *epaddr2ep[16]; - struct r8a66597_dma dma; - - struct timer_list timer; - struct usb_request *ep0_req; /* for internal request */ - u16 ep0_data; /* for internal request */ - u16 old_vbus; - u16 scount; - u16 old_dvsq; - - /* pipe config */ - unsigned char bulk; - unsigned char interrupt; - unsigned char isochronous; - unsigned char num_dma; - - unsigned irq_sense_low:1; -}; - -#define gadget_to_r8a66597(_gadget) \ - container_of(_gadget, struct r8a66597, gadget) -#define r8a66597_to_gadget(r8a66597) (&r8a66597->gadget) -#define r8a66597_to_dev(r8a66597) (r8a66597->gadget.dev.parent) - -static inline u16 r8a66597_read(struct r8a66597 *r8a66597, unsigned long offset) -{ - return ioread16(r8a66597->reg + offset); -} - -static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597, - unsigned long offset, - unsigned char *buf, - int len) -{ - void __iomem *fifoaddr = r8a66597->reg + offset; - unsigned int data = 0; - int i; - - if (r8a66597->pdata->on_chip) { - /* 32-bit accesses for on_chip controllers */ - - /* aligned buf case */ - if (len >= 4 && !((unsigned long)buf & 0x03)) { - ioread32_rep(fifoaddr, buf, len / 4); - buf += len & ~0x03; - len &= 0x03; - } - - /* unaligned buf case */ - for (i = 0; i < len; i++) { - if (!(i & 0x03)) - data = ioread32(fifoaddr); - - buf[i] = (data >> ((i & 0x03) * 8)) & 0xff; - } - } else { - /* 16-bit accesses for external controllers */ - - /* aligned buf case */ - if (len >= 2 && !((unsigned long)buf & 0x01)) { - ioread16_rep(fifoaddr, buf, len / 2); - buf += len & ~0x01; - len &= 0x01; - } - - /* unaligned buf case */ - for (i = 0; i < len; i++) { - if (!(i & 0x01)) - data = ioread16(fifoaddr); - - buf[i] = (data >> ((i & 0x01) * 8)) & 0xff; - } - } -} - -static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val, - unsigned long offset) -{ - iowrite16(val, r8a66597->reg + offset); -} - -static inline void r8a66597_mdfy(struct r8a66597 *r8a66597, - u16 val, u16 pat, unsigned long offset) -{ - u16 tmp; - tmp = r8a66597_read(r8a66597, offset); - tmp = tmp & (~pat); - tmp = tmp | val; - r8a66597_write(r8a66597, tmp, offset); -} - -#define r8a66597_bclr(r8a66597, val, offset) \ - r8a66597_mdfy(r8a66597, 0, val, offset) -#define r8a66597_bset(r8a66597, val, offset) \ - r8a66597_mdfy(r8a66597, val, 0, offset) - -static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597, - struct r8a66597_ep *ep, - unsigned char *buf, - int len) -{ - void __iomem *fifoaddr = r8a66597->reg + ep->fifoaddr; - int adj = 0; - int i; - - if (r8a66597->pdata->on_chip) { - /* 32-bit access only if buf is 32-bit aligned */ - if (len >= 4 && !((unsigned long)buf & 0x03)) { - iowrite32_rep(fifoaddr, buf, len / 4); - buf += len & ~0x03; - len &= 0x03; - } - } else { - /* 16-bit access only if buf is 16-bit aligned */ - if (len >= 2 && !((unsigned long)buf & 0x01)) { - iowrite16_rep(fifoaddr, buf, len / 2); - buf += len & ~0x01; - len &= 0x01; - } - } - - /* adjust fifo address in the little endian case */ - if (!(r8a66597_read(r8a66597, CFIFOSEL) & BIGEND)) { - if (r8a66597->pdata->on_chip) - adj = 0x03; /* 32-bit wide */ - else - adj = 0x01; /* 16-bit wide */ - } - - if (r8a66597->pdata->wr0_shorted_to_wr1) - r8a66597_bclr(r8a66597, MBW_16, ep->fifosel); - for (i = 0; i < len; i++) - iowrite8(buf[i], fifoaddr + adj - (i & adj)); - if (r8a66597->pdata->wr0_shorted_to_wr1) - r8a66597_bclr(r8a66597, MBW_16, ep->fifosel); -} - -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; -} - -static inline u32 r8a66597_sudmac_read(struct r8a66597 *r8a66597, - unsigned long offset) -{ - return ioread32(r8a66597->sudmac_reg + offset); -} - -static inline void r8a66597_sudmac_write(struct r8a66597 *r8a66597, u32 val, - unsigned long offset) -{ - iowrite32(val, r8a66597->sudmac_reg + offset); -} - -#define get_pipectr_addr(pipenum) (PIPE1CTR + (pipenum - 1) * 2) -#define get_pipetre_addr(pipenum) (PIPE1TRE + (pipenum - 1) * 4) -#define get_pipetrn_addr(pipenum) (PIPE1TRN + (pipenum - 1) * 4) - -#define enable_irq_ready(r8a66597, pipenum) \ - enable_pipe_irq(r8a66597, pipenum, BRDYENB) -#define disable_irq_ready(r8a66597, pipenum) \ - disable_pipe_irq(r8a66597, pipenum, BRDYENB) -#define enable_irq_empty(r8a66597, pipenum) \ - enable_pipe_irq(r8a66597, pipenum, BEMPENB) -#define disable_irq_empty(r8a66597, pipenum) \ - disable_pipe_irq(r8a66597, pipenum, BEMPENB) -#define enable_irq_nrdy(r8a66597, pipenum) \ - enable_pipe_irq(r8a66597, pipenum, NRDYENB) -#define disable_irq_nrdy(r8a66597, pipenum) \ - disable_pipe_irq(r8a66597, pipenum, NRDYENB) - -#endif /* __R8A66597_H__ */ - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/rawbulk.c b/ANDROID_3.4.5/drivers/usb/gadget/rawbulk.c deleted file mode 100755 index 5c027da4..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/rawbulk.c +++ /dev/null @@ -1,1272 +0,0 @@ -/* - * Rawbulk Gadget Function Driver from VIA Telecom - * - * Copyright (C) 2011 VIA Telecom, Inc. - * Author: Karfield Chen (kfchen@via-telecom.com) - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - * - */ - -/* #define DEBUG */ -/* #define VERBOSE_DEBUG */ - -#define DRIVER_AUTHOR "Karfield Chen " -#define DRIVER_DESC "Rawbulk Gadget - transport data from CP to Gadget" -#define DRIVER_VERSION "1.0.1" -#define DRIVER_NAME "usb_rawbulk" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#ifdef DEBUG -#define ldbg(f, a...) printk(KERN_DEBUG "%s - " f "\n", __func__, ##a) -#else -#define ldbg(...) {} -#endif - -/* sysfs attr idx assignment */ -enum _attr_idx { - ATTR_ENABLE = 0, /** enable switch for Rawbulk */ -#ifdef SUPPORT_LEGACY_CONTROL - ATTR_ENABLE_C, /** enable switch too, but for legacy */ -#endif - ATTR_AUTORECONN, /** enable to rebind cp when it reconnect */ - ATTR_STATISTICS, /** Rawbulk summary/statistics for one pipe */ - ATTR_NUPS, /** upstream transfers count */ - ATTR_NDOWNS, /** downstram transfers count */ - ATTR_UPSIZE, /** upstream buffer for each transaction */ - ATTR_DOWNSIZE, /** downstram buffer for each transaction */ - ATTR_SPLIT, /** split option for downstream */ - ATTR_PUSHABLE, /** set to use push-way for upstream */ - ATTR_DTR, /** DTR control, only for Data-Call port */ -}; - -/* USB gadget framework is not strong enough, and not be compatiable with some - * controller, such as musb. - * in musb driver, the usb_request's member list is used internally, but in some - * applications it used in function driver too. to avoid this, here we - * re-wrap the usb_request */ -struct usb_request_wrapper { - struct list_head list; - struct usb_request *request; - int length; - struct rawbulk_function *fn; - char buffer[0]; -}; - -static struct usb_request_wrapper *get_wrapper(struct usb_request *req) { - if (!req->buf) - return NULL; - return container_of(req->buf, struct usb_request_wrapper, buffer); -} - -/* Internal TTY functions/data */ -static int rawbulk_tty_activate(struct tty_port *port, struct tty_struct - *tty); -static void rawbulk_tty_deactivate(struct tty_port *port); -static int rawbulk_tty_install(struct tty_driver *driver, struct tty_struct - *tty); -static void rawbulk_tty_cleanup(struct tty_struct *tty); -static int rawbulk_tty_open(struct tty_struct *tty, struct file *flip); -static void rawbulk_tty_hangup(struct tty_struct *tty); -static void rawbulk_tty_close(struct tty_struct *tty, struct file *flip); -static int rawbulk_tty_write(struct tty_struct *tty, const unsigned char *buf, - int count); -static int rawbulk_tty_write_room(struct tty_struct *tty); -static int rawbulk_tty_chars_in_buffer(struct tty_struct *tty); -static void rawbulk_tty_throttle(struct tty_struct *tty); -static void rawbulk_tty_unthrottle(struct tty_struct *tty); -static void rawbulk_tty_set_termios(struct tty_struct *tty, struct ktermios - *old); -static int rawbulk_tty_tiocmget(struct tty_struct *tty); -static int rawbulk_tty_tiocmset(struct tty_struct *tty, unsigned int set, - unsigned int clear); - -static struct tty_port_operations rawbulk_tty_port_ops = { - .activate = rawbulk_tty_activate, - .shutdown = rawbulk_tty_deactivate, -}; - -static struct tty_operations rawbulk_tty_ops = { - .open = rawbulk_tty_open, - .close = rawbulk_tty_close, - .write = rawbulk_tty_write, - .hangup = rawbulk_tty_hangup, - .write_room = rawbulk_tty_write_room, - .set_termios = rawbulk_tty_set_termios, - .throttle = rawbulk_tty_throttle, - .unthrottle = rawbulk_tty_unthrottle, - .chars_in_buffer = rawbulk_tty_chars_in_buffer, - .tiocmget = rawbulk_tty_tiocmget, - .tiocmset = rawbulk_tty_tiocmset, - .cleanup = rawbulk_tty_cleanup, - .install = rawbulk_tty_install, -}; - -struct tty_driver *rawbulk_tty_driver; - -struct rawbulk_function *prealloced_functions[_MAX_TID] = { NULL }; -struct rawbulk_function *rawbulk_lookup_function(int transfer_id) { - if (transfer_id >= 0 && transfer_id < _MAX_TID) - return prealloced_functions[transfer_id]; - return NULL; -} -EXPORT_SYMBOL_GPL(rawbulk_lookup_function); - -static struct rawbulk_function *lookup_by_tty_minor(int minor) { - int n; - struct rawbulk_function *fn; - for (n = 0; n < _MAX_TID; n ++) { - fn = prealloced_functions[n]; - if (fn->tty_minor == minor) - return fn; - } - return NULL; -} - -static inline int check_enable_state(struct rawbulk_function *fn) { - int enab; - unsigned long flags; - spin_lock_irqsave(&fn->lock, flags); - enab = fn->enable? 1: 0; - spin_unlock_irqrestore(&fn->lock, flags); - return enab; -} - -int rawbulk_check_enable(struct rawbulk_function *fn) { - return check_enable_state(fn); -} -EXPORT_SYMBOL_GPL(rawbulk_check_enable); - -static inline int check_tty_opened(struct rawbulk_function *fn) { - int opened; - unsigned long flags; - spin_lock_irqsave(&fn->lock, flags); - opened = fn->tty_opened? 1: 0; - spin_unlock_irqrestore(&fn->lock, flags); - return opened; -} - -static inline void set_enable_state(struct rawbulk_function *fn, int enab) { - unsigned long flags; - spin_lock_irqsave(&fn->lock, flags); - fn->enable = !!enab; - spin_unlock_irqrestore(&fn->lock, flags); -} - -void rawbulk_disable_function(struct rawbulk_function *fn) { - set_enable_state(fn, 0); -} -EXPORT_SYMBOL_GPL(rawbulk_disable_function); - -static inline void set_tty_opened(struct rawbulk_function *fn, int opened) { - unsigned long flags; - spin_lock_irqsave(&fn->lock, flags); - fn->tty_opened = !!opened; - spin_unlock_irqrestore(&fn->lock, flags); -} - -#define port_to_rawbulk(p) container_of(p, struct rawbulk_function, port) -#define function_to_rawbulk(f) container_of(f, struct rawbulk_function, function) - -static struct usb_request_wrapper *get_req(struct list_head *head, spinlock_t - *lock) { - unsigned long flags; - struct usb_request_wrapper *req = NULL; - spin_lock_irqsave(lock, flags); - if (!list_empty(head)) { - req = list_first_entry(head, struct usb_request_wrapper, list); - list_del(&req->list); - } - spin_unlock_irqrestore(lock, flags); - return req; -} - -static void put_req(struct usb_request_wrapper *req, struct list_head *head, - spinlock_t *lock) { - unsigned long flags; - spin_lock_irqsave(lock, flags); - list_add_tail(&req->list, head); - spin_unlock_irqrestore(lock, flags); -} - -static void move_req(struct usb_request_wrapper *req, struct list_head *head, - spinlock_t *lock) { - unsigned long flags; - spin_lock_irqsave(lock, flags); - list_move_tail(&req->list, head); - spin_unlock_irqrestore(lock, flags); -} - -static void insert_req(struct usb_request_wrapper *req, struct list_head *head, - spinlock_t *lock) { - unsigned long flags; - spin_lock_irqsave(lock, flags); - list_add(&req->list, head); - spin_unlock_irqrestore(lock, flags); -} - -static int control_dtr(int set) { - struct usb_ctrlrequest ctrl = { - .bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR, //0x40 - .bRequest = 0x01, - .wLength = 0, - .wIndex = 0, - }; - - ctrl.wValue = cpu_to_le16(!!set); - return rawbulk_forward_ctrlrequest(&ctrl); -} - -static void init_endpoint_desc(struct usb_endpoint_descriptor *epdesc, int in, - int maxpacksize) { - struct usb_endpoint_descriptor template = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - }; - - *epdesc = template; - if (in) - epdesc->bEndpointAddress = USB_DIR_IN; - else - epdesc->bEndpointAddress = USB_DIR_OUT; - epdesc->wMaxPacketSize = cpu_to_le16(maxpacksize); -} - -static void init_interface_desc(struct usb_interface_descriptor *ifdesc) { - struct usb_interface_descriptor template = { - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = 0, - .bAlternateSetting = 0, - .bNumEndpoints = 2, - .bInterfaceClass = 0xff,//USB_CLASS_VENDOR_SPEC, - .bInterfaceSubClass = 0xff, - .bInterfaceProtocol = 0xff, - .iInterface = 0, - }; - - *ifdesc = template; -} - -static ssize_t rawbulk_attr_show(struct device *dev, struct device_attribute - *attr, char *buf); -static ssize_t rawbulk_attr_store(struct device *dev, struct device_attribute - *attr, const char *buf, size_t count); - -static inline void add_device_attr(struct rawbulk_function *fn, int n, const char - *name, int mode) { - if (n < MAX_ATTRIBUTES) { - fn->attr[n].attr.name = name; - fn->attr[n].attr.mode = mode; - fn->attr[n].show = rawbulk_attr_show; - fn->attr[n].store = rawbulk_attr_store; - } -} - -static int which_attr(struct rawbulk_function *fn, struct device_attribute - *attr) { - int n; - for (n = 0; n < fn->max_attrs; n ++) { - if (attr == &fn->attr[n]) - return n; - } - return -1; -} - -static ssize_t rawbulk_attr_show(struct device *dev, struct device_attribute *attr, - char *buf) { - int n; - int idx; - int enab; - struct rawbulk_function *fn; - - for (n = 0; n < _MAX_TID; n ++) { - fn = rawbulk_lookup_function(n); - if (fn->dev == dev) { - idx = which_attr(fn, attr); - break; - } -#ifdef SUPPORT_LEGACY_CONTROL - if (!strcmp(attr->attr.name, fn->shortname)) { - idx = ATTR_ENABLE_C; - break; - } -#endif - } - - if (n == _MAX_TID) - return 0; - - enab = check_enable_state(fn); - switch (idx) { - case ATTR_ENABLE: - return sprintf(buf, "%d", enab); -#ifdef SUPPORT_LEGACY_CONTROL - case ATTR_ENABLE_C: - return sprintf(buf, "%s", enab? "gadget": "tty"); -#endif - case ATTR_AUTORECONN: - return sprintf(buf, "%d", fn->autoreconn); - case ATTR_STATISTICS: - return rawbulk_transfer_statistics(fn->transfer_id, buf); - case ATTR_NUPS: - return sprintf(buf, "%d", enab? fn->nups: -1); - case ATTR_NDOWNS: - return sprintf(buf, "%d", enab? fn->ndowns: -1); - case ATTR_UPSIZE: - return sprintf(buf, "%d", enab? fn->upsz: -1); - case ATTR_DOWNSIZE: - return sprintf(buf, "%d", enab? fn->downsz: -1); - case ATTR_SPLIT: - return sprintf(buf, "%d", enab? fn->splitsz: -1); - case ATTR_PUSHABLE: - return sprintf(buf, "%d", fn->pushable); - default: - break; - } - return 0; -} - -static ssize_t rawbulk_attr_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) { - int n; - int rc = 0; - int idx = -1; - int nups; - int ndowns; - int upsz; - int downsz; - int splitsz; - int pushable; - struct rawbulk_function *fn; - - for (n = 0; n < _MAX_TID; n ++) { - fn = rawbulk_lookup_function(n); - if (fn->dev == dev) { - idx = which_attr(fn, attr); - break; - } -#ifdef SUPPORT_LEGACY_CONTROL - if (!strcmp(attr->attr.name, fn->shortname)) { - idx = ATTR_ENABLE_C; - break; - } -#endif - } - - if (idx < 0) { - printk(KERN_ERR "sorry, I cannot find rawbulk fn '%s'\n", attr->attr.name); - goto exit; - } - - nups = fn->nups; - ndowns = fn->ndowns; - upsz = fn->upsz; - downsz = fn->downsz; - splitsz = fn->splitsz; - pushable = fn->pushable; - - /* find out which attr(file) we write */ - -#ifdef SUPPORT_LEGACY_CONTROL - if (idx <= ATTR_ENABLE_C) -#else - if (idx == ATTR_ENABLE) -#endif - { - int enable; - if (idx == ATTR_ENABLE) { - enable = simple_strtoul(buf, NULL, 10); -#ifdef SUPPORT_LEGACY_CONTROL - } else if (idx == ATTR_ENABLE_C) { - if (!strncmp(buf, "tty", 3)) - enable = 0; - else if (!strncmp(buf, "gadget", 6)) - enable = 1; - else { - printk(KERN_ERR "invalid option(%s) for bypass, try again...\n", buf); - goto exit; - } -#endif /* SUPPORT_LEGACY_CONTROL */ - } else - goto exit; - - if (check_enable_state(fn) != (!!enable)) { - set_enable_state(fn, enable); - if (!!enable && fn->activated) { - printk(KERN_DEBUG "enable rawbulk %s channel, been activated? %s\n", - fn->shortname, fn->activated? "yes": "no"); - if (fn->transfer_id == RAWBULK_TID_MODEM) { - /* clear DTR to endup last session between AP and CP */ - control_dtr(1); - msleep(10); - control_dtr(0); - } - - /* Stop TTY i/o */ - rawbulk_tty_stop_io(fn); - - /* Start rawbulk transfer */ - wake_lock(&fn->keep_awake); - rc = rawbulk_start_transactions(fn->transfer_id, nups, - ndowns, upsz, downsz, splitsz, pushable); - if (rc < 0) { - set_enable_state(fn, !enable); - rawbulk_tty_start_io(fn); - } - } else { - /* Stop rawbulk transfer */ - printk(KERN_DEBUG "disable rawbulk %s channel, been activated? %s\n", - fn->shortname, fn->activated? "yes": "no"); - rawbulk_stop_transactions(fn->transfer_id); - if (fn->transfer_id == RAWBULK_TID_MODEM) { - /* clear DTR automatically when disable modem rawbulk */ - control_dtr(1); - msleep(10); - control_dtr(0); - } - wake_unlock(&fn->keep_awake); - - /* Start TTY i/o */ - rawbulk_tty_start_io(fn); - } - } - } else if (idx == ATTR_DTR) { - if (fn->transfer_id == RAWBULK_TID_MODEM) { - if (check_enable_state(fn)) - control_dtr(simple_strtoul(buf, NULL, 10)); - } - } else if (idx == ATTR_AUTORECONN) { - fn->autoreconn = !!simple_strtoul(buf, NULL, 10); - } else { - int val = simple_strtoul(buf, NULL, 10); - switch (idx) { - case ATTR_NUPS: nups = val; break; - case ATTR_NDOWNS: ndowns = val; break; - case ATTR_UPSIZE: upsz = val; break; - case ATTR_DOWNSIZE: downsz = val; break; - case ATTR_SPLIT: splitsz = val; break; - case ATTR_PUSHABLE: - pushable = !!val; - fn->pushable = pushable; - break; - default: goto exit; - } - - if (!check_enable_state(fn)) - goto exit; - - if (!fn->activated) - goto exit; - - rawbulk_stop_transactions(fn->transfer_id); - rc = rawbulk_start_transactions(fn->transfer_id, nups, ndowns, upsz, - downsz, splitsz, pushable); - if (rc >= 0) { - fn->nups = nups; - fn->ndowns = ndowns; - fn->upsz = upsz; - fn->downsz = downsz; - fn->splitsz = splitsz; - fn->pushable = pushable; - } else { - rawbulk_stop_transactions(fn->transfer_id); - wake_unlock(&fn->keep_awake); - set_enable_state(fn, 0); - } - } - -exit: - return count; -} - -static int rawbulk_create_files(struct rawbulk_function *fn) { - int n, rc; - for (n = 0; n < fn->max_attrs; n ++){ -#ifdef SUPPORT_LEGACY_CONTROL - if (n == ATTR_ENABLE_C) - continue; -#endif - rc = device_create_file(fn->dev, &fn->attr[n]); - if (rc < 0) { - while (--n >= 0) { -#ifdef SUPPORT_LEGACY_CONTROL - if (n == ATTR_ENABLE_C) - continue; -#endif - device_remove_file(fn->dev, &fn->attr[n]); - } - return rc; - } - } - return 0; -} - -static void rawbulk_remove_files(struct rawbulk_function *fn) { - int n = fn->max_attrs; - while (--n >= 0) { -#ifdef SUPPORT_LEGACY_CONTROL - if (n == ATTR_ENABLE_C) - continue; -#endif - device_remove_file(fn->dev, &fn->attr[n]); - } -} - -#define RAWBULK_TTY_MINORS 255 -static int tty_minors[RAWBULK_TTY_MINORS] = { 0 }; -static int alloc_tty_minor(struct rawbulk_function *fn) { - int n; - if (check_tty_opened(fn)) - printk(KERN_WARNING "ttyRB%d has opened yet %s has been disconnected\n", - fn->tty_minor, fn->longname); - for (n = 0; n < RAWBULK_TTY_MINORS; n ++) { - if (tty_minors[n] == 0) { - tty_minors[n] = fn->transfer_id + 0x8000; - return n; - } - } - return -ENODEV; -} - -static void free_tty_minor(struct rawbulk_function *fn) { - int n; - struct tty_struct **ttys = rawbulk_tty_driver->ttys; - if (!check_tty_opened(fn)) - tty_minors[fn->tty_minor] = 0; - /* Clear the closed tty minors of this port */ - for (n = 0; n < RAWBULK_TTY_MINORS; n ++) { - if ((tty_minors[n] == fn->transfer_id + 0x8000) && ttys[n]) { - struct tty_struct *tty = ttys[n]; - if (tty->count > 0) - continue; /* Keep the minor while tty is being used */ - if (test_bit(TTY_CLOSING, &tty->flags)) { - /* FIXME: Cannot close the tty_struct! */ - printk(KERN_DEBUG "cannot recycle the minor %d because " \ - "the TTY_CLOSING flags is still on\n", n); - continue; - } - tty_minors[n] = 0; - } - } -} - -int rawbulk_register_tty(struct rawbulk_function *fn) { - struct device *dev; - - spin_lock_init(&fn->tx_lock); - spin_lock_init(&fn->rx_lock); - INIT_LIST_HEAD(&fn->tx_free); - INIT_LIST_HEAD(&fn->rx_free); - INIT_LIST_HEAD(&fn->tx_inproc); - INIT_LIST_HEAD(&fn->rx_inproc); - INIT_LIST_HEAD(&fn->rx_throttled); - - fn->tty_minor = alloc_tty_minor(fn); - if (fn->tty_minor < 0) - return -ENODEV; - fn->tty_opened = 0; - fn->last_pushed = 0; - tty_port_init(&fn->port); - fn->port.ops = &rawbulk_tty_port_ops; - - /* Bring up the tty device */ - dev = tty_register_device(rawbulk_tty_driver, fn->tty_minor, fn->dev); - if (IS_ERR(dev)) - printk(KERN_ERR "Failed to attach ttyRB%d to %s device.\n", - fn->tty_minor, fn->longname); - - return 0; -} -EXPORT_SYMBOL_GPL(rawbulk_register_tty); - -void rawbulk_unregister_tty(struct rawbulk_function *fn) { - tty_unregister_device(rawbulk_tty_driver, fn->tty_minor); - free_tty_minor(fn); -} -EXPORT_SYMBOL_GPL(rawbulk_unregister_tty); - -/******************************************************************************/ - -/* Call this after all request has detached! */ -void rawbulk_tty_free_request(struct rawbulk_function *fn) { - struct usb_request_wrapper *req; - - while ((req = get_req(&fn->rx_free, &fn->rx_lock))) { - usb_ep_free_request(fn->bulk_out, req->request); - kfree(req); - } - - while ((req = get_req(&fn->tx_free, &fn->tx_lock))) { - usb_ep_free_request(fn->bulk_in, req->request); - kfree(req); - } -} -EXPORT_SYMBOL_GPL(rawbulk_tty_free_request); - -static void rawbulk_tty_rx_complete(struct usb_ep *ep, struct usb_request *req); -static void rawbulk_tty_tx_complete(struct usb_ep *ep, struct usb_request *req); - -int rawbulk_tty_alloc_request(struct rawbulk_function *fn) { - int n; - struct usb_request_wrapper *req; - unsigned long flags; - - spin_lock_irqsave(&fn->lock, flags); - if (!fn->bulk_out || !fn->bulk_in) { - spin_unlock_irqrestore(&fn->lock, flags); - return -ENODEV; - } - spin_unlock_irqrestore(&fn->lock, flags); - - /* Allocate and init rx request */ - for (n = 0; n < MAX_TTY_RX; n ++) { - req = kmalloc(sizeof(struct usb_request_wrapper) + - MAX_TTY_RX_PACKAGE, GFP_KERNEL); - if (!req) - break; - - req->request = usb_ep_alloc_request(fn->bulk_out, GFP_KERNEL); - if (!req->request) { - kfree(req); - break; - } - - req->fn = fn; - INIT_LIST_HEAD(&req->list); - req->length = MAX_TTY_RX_PACKAGE; - req->request->buf = req->buffer; - req->request->length = MAX_TTY_RX_PACKAGE; - req->request->complete = rawbulk_tty_rx_complete; - put_req(req, &fn->rx_free, &fn->rx_lock); - } - - if (n < MAX_TTY_RX) { - /* free allocated request */ - rawbulk_tty_free_request(fn); - return -ENOMEM; - } - - /* Allocate and init tx request */ - for (n = 0; n < MAX_TTY_TX; n ++) { - req = kmalloc(sizeof(struct usb_request_wrapper) + - MAX_TTY_TX_PACKAGE, GFP_KERNEL); - if (!req) - break; - - req->request = usb_ep_alloc_request(fn->bulk_in, GFP_KERNEL); - if (!req->request) { - kfree(req); - break; - } - - req->fn = fn; - INIT_LIST_HEAD(&req->list); - req->length = MAX_TTY_TX_PACKAGE; - req->request->zero = 0; - req->request->buf = req->buffer; - req->request->complete = rawbulk_tty_tx_complete; - put_req(req, &fn->tx_free, &fn->tx_lock); - } - - if (n < MAX_TTY_TX) { - /* free allocated request */ - rawbulk_tty_free_request(fn); - return -ENOMEM; - } - - return 0; -} -EXPORT_SYMBOL_GPL(rawbulk_tty_alloc_request); - -int rawbulk_tty_stop_io(struct rawbulk_function *fn) { - struct usb_request_wrapper *req; - - if (!check_tty_opened(fn)) - return -ENODEV; - - while ((req = get_req(&fn->rx_inproc, &fn->rx_lock))) { - if (req->request->status == -EINPROGRESS) { - put_req(req, &fn->rx_inproc, &fn->rx_lock); - usb_ep_dequeue(fn->bulk_out, req->request); - } - } - - while ((req = get_req(&fn->tx_inproc, &fn->tx_lock))) { - if (req->request->status == -EINPROGRESS) { - put_req(req, &fn->tx_inproc, &fn->tx_lock); - usb_ep_dequeue(fn->bulk_in, req->request); - } - } - return 0; -} -EXPORT_SYMBOL_GPL(rawbulk_tty_stop_io); - -int rawbulk_tty_start_io(struct rawbulk_function *fn) { - int ret; - struct usb_request_wrapper *req; - - if (!check_tty_opened(fn)) - return -ENODEV; - - while ((req = get_req(&fn->rx_free, &fn->rx_lock))) { - put_req(req, &fn->rx_inproc, &fn->rx_lock); - ret = usb_ep_queue(fn->bulk_out, req->request, GFP_ATOMIC); - if (ret < 0) { - move_req(req, &fn->rx_free, &fn->rx_lock); - return ret; - } - } - - return 0; -} -EXPORT_SYMBOL_GPL(rawbulk_tty_start_io); - -/* Complete the data send stage */ -static void rawbulk_tty_tx_complete(struct usb_ep *ep, struct usb_request *req) { - struct usb_request_wrapper *r = get_wrapper(req); - struct rawbulk_function *fn = r->fn; - - move_req(r, &fn->tx_free, &fn->tx_lock); -} - -static void rawbulk_tty_push_data(struct rawbulk_function *fn) { - struct usb_request_wrapper *r; - struct tty_struct *tty; - - tty = tty_port_tty_get(&fn->port); - tty->minimum_to_wake = 1; /* wakeup to read even pushed only once */ - /* walk the throttled list, push all the data to TTY */ - while ((r = get_req(&fn->rx_throttled, &fn->rx_lock))) { - char *sbuf; - int push_count; - struct usb_request *req = r->request; - - if (req->status < 0) { - put_req(r, &fn->rx_free, &fn->rx_lock); - continue; - } - sbuf = req->buf + fn->last_pushed; - push_count = req->actual - fn->last_pushed; - if (push_count) { - int count = tty_insert_flip_string(tty, sbuf, push_count); - if (count < push_count) { - /* We met throttled again */ - fn->last_pushed += count; - if (count) - tty_flip_buffer_push(tty); - insert_req(r, &fn->rx_throttled, &fn->rx_lock); - break; - } - tty_flip_buffer_push(tty); - fn->last_pushed = 0; - } - put_req(r, &fn->rx_free, &fn->rx_lock); - } - tty_kref_put(tty); -} - -/* Recieve data from host */ -static void rawbulk_tty_rx_complete(struct usb_ep *ep, struct usb_request *req) { - int ret; - struct usb_request_wrapper *r = get_wrapper(req); - struct rawbulk_function *fn = r->fn; - struct tty_struct *tty = fn->tty; - - if (req->status < 0 || !check_tty_opened(fn)) { - move_req(r, &fn->rx_free, &fn->rx_lock); - return; - } - - if (test_bit(TTY_THROTTLED, &tty->flags)) { - /* Give up to resubmitted the request */ - move_req(r, &fn->rx_free, &fn->rx_lock); - return; - } else { - /* Move the request to the throttled queue */ - move_req(r, &fn->rx_throttled, &fn->rx_lock); - /* Start to push data */ - rawbulk_tty_push_data(fn); - } - - /* Re-queue the request again */ - while ((r = get_req(&fn->rx_free, &fn->rx_lock))) { - put_req(r, &fn->rx_inproc, &fn->rx_lock); - ret = usb_ep_queue(fn->bulk_out, r->request, GFP_ATOMIC); - if (ret < 0) { - move_req(r, &fn->rx_free, &fn->rx_lock); - break; - } - } -} - -/* Start to queue request on BULK OUT endpoint, when tty is try to open */ -static int rawbulk_tty_activate(struct tty_port *port, struct tty_struct - *tty) { - struct rawbulk_function *fn = port_to_rawbulk(port); - /* Low latency for tty */ - tty->low_latency = 1; - tty->termios->c_cc[VMIN] = 1; - return rawbulk_tty_start_io(fn); -} - -static void rawbulk_tty_deactivate(struct tty_port *port) { - struct usb_request_wrapper *req; - struct rawbulk_function *fn = port_to_rawbulk(port); - - /* This is a little different from stop_io */ - while ((req = get_req(&fn->rx_inproc, &fn->rx_lock))) { - put_req(req, &fn->rx_inproc, &fn->rx_lock); - usb_ep_dequeue(fn->bulk_out, req->request); - } - - while ((req = get_req(&fn->rx_throttled, &fn->rx_lock))) - put_req(req, &fn->rx_free, &fn->rx_lock); - - while ((req = get_req(&fn->tx_inproc, &fn->tx_lock))) { - put_req(req, &fn->tx_inproc, &fn->tx_lock); - usb_ep_dequeue(fn->bulk_in, req->request); - } -} - -static int rawbulk_tty_write(struct tty_struct *tty, const unsigned char *buf, - int count) { - int ret; - int submitted = 0; - struct usb_request_wrapper *req; - struct rawbulk_function *fn = tty->driver_data; - - if (check_enable_state(fn)) - return -EBUSY; - - /* Get new request(s) that freed, fill it, queue it to the endpoint */ - while ((req = get_req(&fn->tx_free, &fn->tx_lock))) { - int length = count - submitted; - if (length <= 0) { - put_req(req, &fn->tx_free, &fn->tx_lock); - break; - } - if (length > MAX_TTY_TX_PACKAGE) - length = MAX_TTY_TX_PACKAGE; - memcpy(req->buffer, buf + submitted, length); - req->request->length = length; - put_req(req, &fn->tx_inproc, &fn->tx_lock); - ret = usb_ep_queue(fn->bulk_in, req->request, GFP_ATOMIC); - if (ret < 0) { - move_req(req, &fn->tx_free, &fn->tx_lock); - return ret; - } - submitted += length; - } - - return submitted; -} - -static int rawbulk_tty_write_room(struct tty_struct *tty) { - int room = 0; - unsigned long flags; - struct usb_request_wrapper *req; - struct rawbulk_function *fn = tty->driver_data; - - if (check_enable_state(fn)) - return 0; - - spin_lock_irqsave(&fn->tx_lock, flags); - list_for_each_entry(req, &fn->tx_free, list) - room += req->length; - spin_unlock_irqrestore(&fn->tx_lock, flags); - - return room; -} - -static int rawbulk_tty_chars_in_buffer(struct tty_struct *tty) { - int chars = 0; - unsigned long flags; - struct usb_request_wrapper *req; - struct rawbulk_function *fn = tty->driver_data; - - if (check_enable_state(fn)) - return 0; - - spin_lock_irqsave(&fn->rx_lock, flags); - list_for_each_entry(req, &fn->rx_throttled, list) { - if (req->request->status < 0) - continue; - chars += req->request->actual; - } - chars -= fn->last_pushed; - spin_unlock_irqrestore(&fn->rx_lock, flags); - - return chars; -} - -static void rawbulk_tty_throttle(struct tty_struct *tty) { - struct usb_request_wrapper *req; - struct rawbulk_function *fn = tty->driver_data; - - /* Stop the processing requests */ - while ((req = get_req(&fn->rx_inproc, &fn->rx_lock))) { - if (req->request->status == -EINPROGRESS) { - put_req(req, &fn->rx_inproc, &fn->rx_lock); - usb_ep_dequeue(fn->bulk_out, req->request); - } - } -} - -static void rawbulk_tty_unthrottle(struct tty_struct *tty) { - int ret; - struct usb_request_wrapper *req; - struct rawbulk_function *fn = tty->driver_data; - - /* Try to push the throttled requests' data to TTY */ - rawbulk_tty_push_data(fn); - - /* Restart the free requests */ - while ((req = get_req(&fn->rx_free, &fn->rx_lock))) { - put_req(req, &fn->rx_inproc, &fn->rx_lock); - ret = usb_ep_queue(fn->bulk_out, req->request, GFP_ATOMIC); - if (ret < 0) { - move_req(req, &fn->rx_free, &fn->rx_lock); - break; - } - } -} - -static void rawbulk_tty_set_termios(struct tty_struct *tty, struct ktermios - *old) { - //struct rawbulk_function *fn = tty->driver_data; -} - -static int rawbulk_tty_tiocmget(struct tty_struct *tty) { - //struct rawbulk_function *fn = tty->driver_data; - return 0; -} - -static int rawbulk_tty_tiocmset(struct tty_struct *tty, unsigned int set, - unsigned int clear) { - //struct rawbulk_function *fn = tty->driver_data; - return 0; -} - -static int rawbulk_tty_install(struct tty_driver *driver, struct tty_struct - *tty) { - int ret = 0; - struct rawbulk_function *fn = lookup_by_tty_minor(tty->index); - - if (!fn) - return -ENODEV; - - ret = tty_init_termios(tty); - if (ret < 0) - return ret; - - tty->driver_data = fn; - fn->tty = tty; - - /* Final install (we use the default method) */ - tty_driver_kref_get(driver); - tty->count++; - driver->ttys[tty->index] = tty; - return ret; -} - -static void rawbulk_tty_cleanup(struct tty_struct *tty) { - struct rawbulk_function *fn = lookup_by_tty_minor(tty->index); - tty->driver_data = NULL; - if (fn) - fn->tty = NULL; -} - -static int rawbulk_tty_open(struct tty_struct *tty, struct file *flip) { - int ret; - struct rawbulk_function *fn = lookup_by_tty_minor(tty->index); - - if (!fn) - return -ENODEV; - - tty->driver_data = fn; - fn->tty = tty; - - if (check_enable_state(fn)) - return -EBUSY; - - if (check_tty_opened(fn)) - return -EBUSY; - - set_tty_opened(fn, 1); - - ret = tty_port_open(&fn->port, tty, flip); - if (ret < 0) - return ret; - return 0; -} - -static void rawbulk_tty_hangup(struct tty_struct *tty) { - struct rawbulk_function *fn = tty->driver_data; - if (!fn) - return; - tty_port_hangup(&fn->port); -} - -static void rawbulk_tty_close(struct tty_struct *tty, struct file *flip) { - struct rawbulk_function *fn = tty->driver_data; - if (!fn) - return; - set_tty_opened(fn, 0); - tty_port_close(&fn->port, tty, flip); -} - -static __init int rawbulk_tty_init(void) { - int ret; - struct tty_driver *drv = alloc_tty_driver(_MAX_TID); - if (!drv) - return -ENOMEM; - - drv->owner = THIS_MODULE; - drv->driver_name = "rawbulkport"; - drv->name = "ttyRB";//prefix - drv->type = TTY_DRIVER_TYPE_SERIAL; - drv->subtype = SERIAL_TYPE_NORMAL; - drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - drv->init_termios = tty_std_termios; - drv->init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - drv->init_termios.c_lflag = 0; - drv->init_termios.c_ispeed = 9600; - drv->init_termios.c_ospeed = 9600; - - tty_set_operations(drv, &rawbulk_tty_ops); - - ret = tty_register_driver(drv); - if (ret < 0) { - put_tty_driver(drv); - } else - rawbulk_tty_driver = drv; - return ret; -} - -/******************************************************************************/ -static struct class *rawbulk_class; - -static struct _function_init_stuff { - const char *longname; - const char *shortname; - const char *iString; - unsigned int ep_maxpkg; - unsigned int nups; - unsigned int ndowns; - unsigned int upsz; - unsigned int downsz; - unsigned int splitsz; - bool autoreconn; - bool pushable; -} _init_params[] = { - {"rawbulk-modem", "data", "Modem Port", 64, 16, 16, PAGE_SIZE, PAGE_SIZE, PAGE_SIZE, true, false }, - {"rawbulk-ets", "ets", "ETS Port", 512, 4, 1, PAGE_SIZE, PAGE_SIZE, PAGE_SIZE, true, false }, - {"rawbulk-at", "atc", "AT Channel", 64, 1, 1, PAGE_SIZE, PAGE_SIZE, PAGE_SIZE, true, false }, - {"rawbulk-pcv", "pcv", "PCM Voice", 64, 1, 1, PAGE_SIZE, PAGE_SIZE, PAGE_SIZE, true, false }, - {"rawbulk-gps", "gps", "LBS GPS Port", 64, 1, 1, PAGE_SIZE, PAGE_SIZE, PAGE_SIZE, true, false }, - { }, /* End of configurations */ -}; - -static __init struct rawbulk_function *rawbulk_alloc_function(int transfer_id) { - int rc; - struct rawbulk_function *fn; - struct _function_init_stuff *_init = &_init_params[transfer_id]; - - if (transfer_id == _MAX_TID) - return NULL; - - fn = kzalloc(sizeof *fn, GFP_KERNEL); - if (IS_ERR(fn)) - return NULL; - - /* init default features of rawbulk functions */ - fn->longname = _init->longname; - fn->shortname = _init->shortname; - fn->string_defs[0].s = _init->iString; - fn->nups = _init->nups; - fn->ndowns = _init->ndowns; - fn->upsz = _init->upsz; - fn->downsz = _init->downsz; - fn->splitsz = _init->splitsz; - fn->autoreconn = _init->autoreconn; - fn->pushable = _init->pushable; - - fn->tty_minor = -1; - /* init descriptors */ - init_interface_desc(&fn->interface); - init_endpoint_desc(&fn->fs_bulkin_endpoint, 1, _init->ep_maxpkg); - init_endpoint_desc(&fn->hs_bulkin_endpoint, 1, _init->ep_maxpkg); - init_endpoint_desc(&fn->fs_bulkout_endpoint, 0, _init->ep_maxpkg); - init_endpoint_desc(&fn->hs_bulkout_endpoint, 0, _init->ep_maxpkg); - - fn->fs_descs[INTF_DESC] = (struct usb_descriptor_header *) &fn->interface; - fn->fs_descs[BULKIN_DESC] = (struct usb_descriptor_header *) &fn->fs_bulkin_endpoint; - fn->fs_descs[BULKOUT_DESC] = (struct usb_descriptor_header *) &fn->fs_bulkout_endpoint; - - fn->hs_descs[INTF_DESC] = (struct usb_descriptor_header *) &fn->interface; - fn->hs_descs[BULKIN_DESC] = (struct usb_descriptor_header *) &fn->hs_bulkin_endpoint; - fn->hs_descs[BULKOUT_DESC] = (struct usb_descriptor_header *) &fn->hs_bulkout_endpoint; - - fn->string_table.language = 0x0409; - fn->string_table.strings = fn->string_defs; - fn->strings[0] = &fn->string_table; - fn->strings[1] = NULL; - - fn->transfer_id = transfer_id; - - /* init function callbacks */ - fn->function.strings = fn->strings; - fn->function.descriptors = fn->fs_descs; - fn->function.hs_descriptors = fn->hs_descs; - - /* init device attributes */ - add_device_attr(fn, ATTR_ENABLE, "enable", 0755); -#ifdef SUPPORT_LEGACY_CONTROL - add_device_attr(fn, ATTR_ENABLE_C, fn->shortname, 0755); -#endif - add_device_attr(fn, ATTR_AUTORECONN, "autoreconn", 0755); - add_device_attr(fn, ATTR_STATISTICS, "statistics", 0644); - add_device_attr(fn, ATTR_NUPS, "nups", 0755); - add_device_attr(fn, ATTR_NDOWNS, "ndowns", 0755); - add_device_attr(fn, ATTR_UPSIZE, "ups_size", 0755); - add_device_attr(fn, ATTR_DOWNSIZE, "downs_size", 0755); - add_device_attr(fn, ATTR_SPLIT, "split_size", 0755); - add_device_attr(fn, ATTR_PUSHABLE, "pushable", 0755); - - fn->max_attrs = ATTR_PUSHABLE + 1; - - if (transfer_id == RAWBULK_TID_MODEM) { - // printk(" kevin chagnge dtr for 200 for cts, disable usb est bypass \n"); - add_device_attr(fn, ATTR_DTR, "dtr", 0200); - fn->max_attrs ++; - } - - fn->dev = device_create(rawbulk_class, NULL, MKDEV(0, - fn->transfer_id), NULL, fn->shortname); - if (IS_ERR(fn->dev)) { - kfree(fn); - return NULL; - } - - rc = rawbulk_create_files(fn); - if (rc < 0) { - device_destroy(rawbulk_class, fn->dev->devt); - kfree(fn); - return NULL; - } - - spin_lock_init(&fn->lock); - wake_lock_init(&fn->keep_awake, WAKE_LOCK_SUSPEND, fn->longname); - return fn; -} - -static void rawbulk_destory_function(struct rawbulk_function *fn) { - if (!fn) - return; - wake_lock_destroy(&fn->keep_awake); - rawbulk_remove_files(fn); - device_destroy(rawbulk_class, fn->dev->devt); - kfree(fn); -} - -#ifdef SUPPORT_LEGACY_CONTROL -static struct attribute *legacy_sysfs[_MAX_TID + 1] = { NULL }; -static struct attribute_group legacy_sysfs_group = { - .attrs = legacy_sysfs, -}; -struct kobject *legacy_sysfs_stuff; -#endif /* SUPPORT_LEGACY_CONTROL */ - -static int __init init(void) { - int n; - int rc = 0; - - printk(KERN_INFO "rawbulk functions init.\n"); - - rawbulk_class = class_create(THIS_MODULE, "usb_rawbulk"); - if (IS_ERR(rawbulk_class)) - return PTR_ERR(rawbulk_class); - - for (n = 0; n < _MAX_TID; n ++) { - struct rawbulk_function *fn = rawbulk_alloc_function(n); - if (IS_ERR(fn)) { - while (n --) - rawbulk_destory_function(prealloced_functions[n]); - rc = PTR_ERR(fn); - break; - } - prealloced_functions[n] = fn; -#ifdef SUPPORT_LEGACY_CONTROL - legacy_sysfs[n] = &fn->attr[ATTR_ENABLE_C].attr; -#endif - } - - if (rc < 0) { - class_destroy(rawbulk_class); - return rc; - } - -#ifdef SUPPORT_LEGACY_CONTROL - /* make compatiable with old bypass sysfs access */ - legacy_sysfs_stuff = kobject_create_and_add("usb_bypass", NULL); - if (legacy_sysfs_stuff) { - rc = sysfs_create_group(legacy_sysfs_stuff, &legacy_sysfs_group); - if (rc < 0) - printk(KERN_ERR "failed to create legacy bypass sys-stuff, but continue...\n"); - } -#endif /* SUPPORT_LEGACY_CONTROL */ - - rc = rawbulk_tty_init(); - if (rc < 0) { - printk(KERN_ERR "failed to init rawbulk tty driver.\n"); - return rc; - } - - for (n = 0; n < _MAX_TID; n ++) { - struct rawbulk_function *fn = prealloced_functions[n]; - rc = rawbulk_register_tty(fn); - if (rc < 0) { - printk(KERN_ERR "fatal error: we cannot create ttyRB%d for %s\n", - n, fn->longname); - return rc; - } - } - - return 0; -} - -module_init(init); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/rawbulk_transfer.c b/ANDROID_3.4.5/drivers/usb/gadget/rawbulk_transfer.c deleted file mode 100755 index 70ec5be1..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/rawbulk_transfer.c +++ /dev/null @@ -1,1372 +0,0 @@ -/* - * Rawbulk Driver from VIA Telecom - * - * Copyright (C) 2011 VIA Telecom, Inc. - * Author: Karfield Chen (kfchen@via-telecom.com) - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - * - */ -/* - * Rawbulk is transfer performer between CBP host driver and Gadget driver - * - * 1 rawbulk transfer can be consist by serval upstream and/or downstream - * transactions. - * - * upstream: CBP Driver ---> Gadget IN - * downstream: Gadget OUT ---> CBP Driver - * - * upstream flowchart: - * - * -x-> usb_submit_urb -> complete -> usb_ep_queue -> complete -, - * | | - * `----------------------(control)----------------------------' - * - * downstream flowchart: - * - * -x-> usb_ep_queue -> complete -> usb_submit_urb -> complete -, - * | | - * `----------------------(control)----------------------------' - * - */ - -/* #define DEBUG */ -/* #define VERBOSE_DEBUG */ - -#define DRIVER_AUTHOR "Karfield Chen " -#define DRIVER_DESC "Rawbulk Driver - perform bypass for Kunlun" -#define DRIVER_VERSION "1.0.3" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef VERBOSE_DEBUG -#define ldbg(fmt, args...) \ - printk(KERN_DEBUG "%s: " fmt "\n", __func__, ##args) -#define tdbg(t, fmt, args...) \ - printk(KERN_DEBUG "Rawbulk %s: " fmt "\n", t->name, ##args) -#else -#define ldbg(args...) -#define tdbg(args...) -#endif - -#define lerr(fmt, args...) \ - printk(KERN_ERR "%s: " fmt "\n", __func__, ##args) -#define terr(t, fmt, args...) \ - printk(KERN_ERR "Rawbulk [%s]:" fmt "\n", t->name, ##args) - -#define FREE_STALLED 1 -#define FREE_IDLED 2 -#define FREE_RETRIVING 4 -#define FREE_ALL (FREE_STALLED | FREE_IDLED | FREE_RETRIVING) - -#define STOP_UPSTREAM 0x1 -#define STOP_DOWNSTREAM 0x2 - -struct rawbulk_transfer { - enum transfer_id id; - spinlock_t lock; - int control; - struct usb_anchor submitted; - struct usb_function *function; - struct usb_interface *interface; - struct mutex mutex; /* protection for API calling */ - rawbulk_autoreconn_callback_t autoreconn; - rawbulk_intercept_t inceptor; - spinlock_t suspend_lock; - int suspended; - struct { - int ntrans; - struct list_head transactions; - struct usb_ep *ep; - struct usb_host_endpoint *host_ep; - } upstream, downstream; -}; - -static inline int get_epnum(struct usb_host_endpoint *ep) { - return (int)(ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); -} - -static inline int get_maxpacksize(struct usb_host_endpoint *ep) { - return (int)(le16_to_cpu(ep->desc.wMaxPacketSize)); -} - - -#define MAX_RESPONSE 32 -struct rawbulk_transfer_model { - struct usb_device *udev; - struct usb_composite_dev *cdev; - char ctrl_response[MAX_RESPONSE]; - struct usb_ctrlrequest forward_dr; - struct urb *forwarding_urb; - struct rawbulk_transfer transfer[_MAX_TID]; -}; -static struct rawbulk_transfer_model *rawbulk; - -static struct rawbulk_transfer *id_to_transfer(int transfer_id) { - if (transfer_id < 0 || transfer_id >= _MAX_TID) - return NULL; - return &rawbulk->transfer[transfer_id]; -} - -/* - * upstream - */ - -#define UPSTREAM_STAT_FREE 0 -#define UPSTREAM_STAT_RETRIEVING 1 -#define UPSTREAM_STAT_UPLOADING 2 - -struct upstream_transaction { - int state; - int stalled; - char name[32]; - struct list_head tlist; - struct delayed_work delayed; - struct rawbulk_transfer *transfer; - struct usb_request *req; - struct urb *urb; - int buffer_length; - unsigned char *buffer; -}; - -static void upstream_delayed_work(struct work_struct *work); -static struct upstream_transaction * -alloc_upstream_transaction(struct rawbulk_transfer *transfer, int bufsz, int pushable) -{ - struct upstream_transaction *t; - - if (bufsz < get_maxpacksize(transfer->upstream.host_ep)) - return NULL; - if (bufsz < PAGE_SIZE || bufsz % PAGE_SIZE != 0) - return NULL; - - t = kzalloc(sizeof *t, GFP_KERNEL); - if (!t) - return NULL; - - t->buffer = (unsigned char *)__get_free_pages(GFP_KERNEL, get_order(bufsz)); - if (!t->buffer) { - kfree(t); - return NULL; - } - - t->buffer_length = bufsz; - - t->req = usb_ep_alloc_request(transfer->upstream.ep, GFP_KERNEL); - if (!t->req) - goto failto_alloc_usb_request; - - if (!pushable) { - t->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!t->urb) - goto failto_alloc_urb; - } - - t->name[0] = 0; - sprintf(t->name, "U%d (H:ep%din, G:%s)", transfer->upstream.ntrans, - get_epnum(transfer->upstream.host_ep), - transfer->upstream.ep->name); - - INIT_LIST_HEAD(&t->tlist); - list_add_tail(&t->tlist, &transfer->upstream.transactions); - transfer->upstream.ntrans ++; - t->transfer = transfer; - - INIT_DELAYED_WORK(&t->delayed, upstream_delayed_work); - t->state = UPSTREAM_STAT_FREE; - return t; - -failto_alloc_urb: - usb_ep_free_request(transfer->upstream.ep, t->req); -failto_alloc_usb_request: - free_page((unsigned long)t->buffer); - kfree(t); - return NULL; -} - -static void free_upstream_transaction(struct rawbulk_transfer *transfer, int option) { - struct list_head *p, *n; - list_for_each_safe(p, n, &transfer->upstream.transactions) { - struct upstream_transaction *t = list_entry(p, struct - upstream_transaction, tlist); - - if ((option & FREE_RETRIVING) && - (t->state == UPSTREAM_STAT_RETRIEVING)) { - if (t->urb) usb_unlink_urb(t->urb); - goto free; - } - - if ((option & FREE_STALLED) && t->stalled) - goto free; - - if ((option & FREE_IDLED) && (t->state == UPSTREAM_STAT_FREE)) - goto free; - - continue; -free: - list_del(p); - if (t->urb) - usb_free_urb(t->urb); - usb_ep_free_request(transfer->upstream.ep, t->req); - free_page((unsigned long)t->buffer); - kfree(t); - - transfer->upstream.ntrans --; - } -} - -static void upstream_second_stage(struct urb *urb); -static void upstream_final_stage(struct usb_ep *ep, struct usb_request - *req); - -static int start_upstream(struct upstream_transaction *t, gfp_t mem_flags) { - int rc; - unsigned long flags; - struct rawbulk_transfer *transfer = t->transfer; - - spin_lock_irqsave(&transfer->lock, flags); - if (transfer->control & STOP_UPSTREAM) { - spin_unlock_irqrestore(&transfer->lock, flags); - cancel_delayed_work(&t->delayed); - t->state = UPSTREAM_STAT_FREE; - t->stalled = 1; - return -EPIPE; - } - spin_unlock_irqrestore(&transfer->lock, flags); - - t->stalled = 0; - t->state = UPSTREAM_STAT_FREE; - - usb_fill_bulk_urb(t->urb, rawbulk->udev, - usb_rcvbulkpipe(rawbulk->udev, - get_epnum(transfer->upstream.host_ep)), - t->buffer, t->buffer_length, - upstream_second_stage, t); - usb_anchor_urb(t->urb, &transfer->submitted); - - rc = usb_submit_urb(t->urb, mem_flags); - usb_mark_last_busy(rawbulk->udev); - if (rc < 0) { - terr(t, "fail to submit urb %d", rc); - /* FIXME: if we met the host is suspending yet, we may add re-submit - * this urb in a ashman thread. so what is a ashman? this can deal any - * error that occur in this driver, and maintain the driver's health, I - * will complete this code in future, here we just stall the transaction - */ - t->stalled = 1; - usb_unanchor_urb(t->urb); - } - - t->state = UPSTREAM_STAT_RETRIEVING; - return rc; -} - -static void upstream_delayed_work(struct work_struct *work) { - int rc; - int stop; - unsigned long flags; - struct delayed_work *dw = container_of(work, struct delayed_work, work); - struct upstream_transaction *t = container_of (work, struct - upstream_transaction, delayed.work); - struct rawbulk_transfer *transfer = t->transfer; - - spin_lock_irqsave(&transfer->lock, flags); - stop = !!(transfer->control & STOP_UPSTREAM); - spin_unlock_irqrestore(&transfer->lock, flags); - - rc = start_upstream(t, GFP_ATOMIC); - if (rc < 0 && !stop) - schedule_delayed_work(dw, HZ); -} - -static unsigned int dump_mask = 0; -module_param(dump_mask, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(dump_mask, "Set data dump mask for each transfers"); - -static inline void dump_data(struct rawbulk_transfer *trans, - const char *str, const unsigned char *data, int size) { - int i; - int no_chars = 0; - - if (!(dump_mask & (1 << trans->id))) - return; - - printk(KERN_DEBUG "DUMP tid = %d, %s: len = %d, chars = \"", - trans->id, str, size); - for (i = 0; i < size; ++i) { - char c = data[i]; - if (c > 0x20 && c < 0x7e) { - printk("%c", c); - } else { - printk("."); - no_chars ++; - } - } - printk("\", data = "); - for (i = 0; i < size; ++i) { - printk("%.2x ", data[i]); - if (i > 7) - break; - } - if (size < 8) { - printk("\n"); - return; - } else if (i < size - 8) { - printk("... "); - i = size - 8; - } - for (; i < size; ++i) - printk("%.2x ", data[i]); - printk("\n"); -} - -static void upstream_second_stage(struct urb *urb) { - int rc; - struct upstream_transaction *t = urb->context; - struct rawbulk_transfer *transfer = t->transfer; - struct usb_request *req = t->req; - - if (urb->status < 0) { - if (urb->status == -ECONNRESET) { - terr(t, "usb-device connection reset!"); - return; - } - printk("WTF?! %s failed %d\n", __func__, urb->status); - /* start again atomatically */ - rc = start_upstream(t, GFP_ATOMIC); -#if 0 - if (rc < 0) - schedule_delayed_work(&t->delayed, HZ); -#endif - return; - } - - dump_data(transfer, "upstream", t->buffer, urb->actual_length); - /* allow zero-length package to pass - if (!urb->actual_length) { - terr(t, "urb actual_length 0"); - start_upstream(t, GFP_ATOMIC); - return; - } - */ - - req->status = 0; - req->context = t; - req->buf = urb->transfer_buffer; - req->length = urb->actual_length; - req->complete = upstream_final_stage; - if (urb->actual_length == 0) - req->zero = 1; - else - req->zero = 0; - - t->state = UPSTREAM_STAT_UPLOADING; - rc = usb_ep_queue(transfer->upstream.ep, req, GFP_ATOMIC); - if (rc < 0) { - terr(t, "fail to queue request, %d", rc); - t->stalled = 1; - t->state = UPSTREAM_STAT_FREE; - } -} - -static void upstream_final_stage(struct usb_ep *ep, - struct usb_request *req) { - struct upstream_transaction *t = req->context; - - t->state = UPSTREAM_STAT_FREE; - - if (req->status < 0) { - if (req->status != -ECONNRESET) - terr(t, "req status %d", req->status); - if (req->status == -ESHUTDOWN) { - t->stalled = 1; - return; - } - } - - if (!req->actual) - terr(t, "req actual 0"); - - if (t->urb) - start_upstream(t, GFP_ATOMIC); -} - -static void stop_upstream(struct upstream_transaction *t) { - struct rawbulk_transfer *transfer = t->transfer; - if (t->state == UPSTREAM_STAT_RETRIEVING) { - cancel_delayed_work(&t->delayed); - if (t->urb) - usb_unlink_urb(t->urb); - } else if (t->state == UPSTREAM_STAT_UPLOADING) { - usb_ep_dequeue(transfer->upstream.ep, t->req); - } - t->stalled = 1; - t->state = UPSTREAM_STAT_FREE; -} - -int rawbulk_push_upstream_buffer(int transfer_id, const void *buffer, - unsigned int length) { - int ret = -ENOENT; - struct upstream_transaction *t; - struct rawbulk_transfer *transfer; - struct usb_request *req; - - transfer = id_to_transfer(transfer_id); - if (!transfer) - return -ENODEV; - - /* search for free transfer */ - mutex_lock(&transfer->mutex); - list_for_each_entry(t, &transfer->upstream.transactions, tlist) { - if (t && t->state != UPSTREAM_STAT_UPLOADING) { - ret = 0; - break; - } - } - mutex_unlock(&transfer->mutex); - if (ret < 0) { - terr(t, "no entry for transfer %d while pushing!\n", transfer_id); - return ret; - } - req = t->req; - if (!req) - return -EINVAL; - - /* copy the buffer */ - memcpy(t->buffer, buffer, length); - dump_data(transfer, "pushing up", t->buffer, length); - - req->status = 0; - req->length = length; - req->buf = t->buffer; - req->complete = upstream_final_stage; - req->zero = (length > 0)? 0: 1; - - t->state = UPSTREAM_STAT_UPLOADING; - ret = usb_ep_queue(transfer->upstream.ep, req, GFP_ATOMIC); - if (ret < 0) { - terr(t, "fail to queue request, %d", ret); - t->stalled = 1; - t->state = UPSTREAM_STAT_FREE; - return ret; - } - return 0; -} -EXPORT_SYMBOL_GPL(rawbulk_push_upstream_buffer); - -/* - * downstream - */ - -#define MAX_SPLIT_LIMITED 64 - -#define DOWNSTREAM_STAT_FREE 0 -#define DOWNSTREAM_STAT_RETRIEVING 1 -#define DOWNSTREAM_STAT_DOWNLOADING 2 - -struct downstream_transaction { - int state; - int stalled; - char name[32]; - struct list_head tlist; - struct rawbulk_transfer *transfer; - struct usb_request *req; - int nurb; - struct urb *urb[MAX_SPLIT_LIMITED]; - int urb_length; - int buffer_length; - unsigned char buffer[0]; -}; - -static void downstream_second_stage(struct usb_ep *ep, - struct usb_request *req); -static void downstream_final_stage(struct urb *urb); - -static struct downstream_transaction *alloc_downstream_transaction( - struct rawbulk_transfer *transfer, int bufsz, int urbsz) { - int n = 0; - struct downstream_transaction *t; - int maxurbs = bufsz / urbsz; - - if (urbsz < get_maxpacksize(transfer->downstream.host_ep)) - return NULL; - - if (maxurbs > MAX_SPLIT_LIMITED) - return NULL; - - t = kzalloc(sizeof *t + bufsz * sizeof(unsigned char), GFP_KERNEL); - if (!t) - return NULL; - - t->buffer_length = bufsz; - t->urb_length = urbsz; - - t->req = usb_ep_alloc_request(transfer->downstream.ep, GFP_KERNEL); - if (!t->req) - goto failto_alloc_usb_request; - - for (n = 0; n < maxurbs; n ++) { - t->urb[n] = usb_alloc_urb(0, GFP_KERNEL); - if (!t->urb[n]) - goto failto_alloc_urb; - } - t->nurb = 0; - - t->name[0] = 0; - sprintf(t->name, "D%d (G:%s, H:ep%dout)", transfer->downstream.ntrans, - transfer->downstream.ep->name, - get_epnum(transfer->downstream.host_ep)); - - INIT_LIST_HEAD(&t->tlist); - list_add_tail(&t->tlist, &transfer->downstream.transactions); - transfer->downstream.ntrans ++; - t->transfer = transfer; - - t->state = DOWNSTREAM_STAT_FREE; - return t; - -failto_alloc_urb: - while (n --) - usb_free_urb(t->urb[n]); - usb_ep_free_request(transfer->downstream.ep, t->req); -failto_alloc_usb_request: - kfree(t); - return NULL; -} - -static void free_downstream_transaction(struct rawbulk_transfer *transfer, int option) { - int i; - int maxurbs; - struct list_head *p, *n; - list_for_each_safe(p, n, &transfer->downstream.transactions) { - struct downstream_transaction *t = list_entry(p, struct - downstream_transaction, tlist); - - if ((option & FREE_STALLED) && t->stalled) - goto free; - - if ((option & FREE_IDLED) && (t->state == DOWNSTREAM_STAT_FREE)) - goto free; - - if ((option & FREE_RETRIVING) && - (t->state == DOWNSTREAM_STAT_RETRIEVING)) { - usb_ep_dequeue(transfer->downstream.ep, t->req); - goto free; - } - - continue; -free: - list_del(p); - maxurbs = t->buffer_length / t->urb_length; - for (i = 0; i < maxurbs; i ++) - usb_free_urb(t->urb[i]); - usb_ep_free_request(transfer->downstream.ep, t->req); - kfree(t); - - transfer->downstream.ntrans --; - } -} - -static int start_downstream(struct downstream_transaction *t) { - int rc; - unsigned long flags; - struct rawbulk_transfer *transfer = t->transfer; - struct usb_request *req = t->req; - - spin_lock_irqsave(&transfer->lock, flags); - if (transfer->control & STOP_DOWNSTREAM) { - spin_unlock_irqrestore(&transfer->lock, flags); - t->state = DOWNSTREAM_STAT_FREE; - t->stalled = 1; - return -EPIPE; - } - spin_unlock_irqrestore(&transfer->lock, flags); - - t->stalled = 0; - t->state = DOWNSTREAM_STAT_FREE; - - req->buf = t->buffer; - req->length = t->buffer_length; - req->complete = downstream_second_stage; - - rc = usb_ep_queue(transfer->downstream.ep, req, GFP_ATOMIC); - if (rc < 0) { - terr(t, "fail to queue request, %d", rc); - t->stalled = 1; - return rc; - } - - t->state = DOWNSTREAM_STAT_RETRIEVING; - return 0; -} - -static void downstream_second_stage(struct usb_ep *ep, - struct usb_request *req) { - int n = 0; - void *next_buf = req->buf; - int data_length = req->actual; - struct downstream_transaction *t = container_of(req->buf, - struct downstream_transaction, buffer); - struct rawbulk_transfer *transfer = t->transfer; - - if (req->status) { - if (req->status != -ECONNRESET) - terr(t, "req status %d", req->status); - if (req->status == -ESHUTDOWN ||req->status == -ECONNRESET ) - t->stalled = 1; - else - start_downstream(t); - return; - } - - dump_data(transfer, "downstream", t->buffer, req->actual); - /* - if (!data_length) { - terr(t, "req actual 0"); - start_downstream(t); - return; - } - */ - - /* split recieved data into servral urb size less than maxpacket of cbp - * endpoint */ - do { - int rc; - struct urb *urb = t->urb[n]; - int tsize = (data_length > t->urb_length)? t->urb_length: - data_length; - - urb->status = 0; - usb_fill_bulk_urb(urb, rawbulk->udev, - usb_sndbulkpipe(rawbulk->udev, - get_epnum(transfer->downstream.host_ep)), - next_buf, tsize, downstream_final_stage, t); - usb_anchor_urb(urb, &transfer->submitted); - - rc = usb_submit_urb(urb, GFP_ATOMIC); - usb_mark_last_busy(rawbulk->udev); - if (rc < 0) { - terr(t, "fail to submit urb %d, n %d", rc, n); - usb_unanchor_urb(urb); - break; - } - - data_length -= tsize; - next_buf += tsize; - n ++; - } while (data_length > 0); - - t->nurb = n; - t->state = DOWNSTREAM_STAT_DOWNLOADING; -} - -static void downstream_final_stage(struct urb *urb) { - int n; - int actual_total = 0; - struct downstream_transaction *t = urb->context; - - if (urb->status < 0) { - printk("WTF?! - %s failed %d\n", __func__, urb->status); - } - - /* check the condition, re-queue usb_request on gadget ep again if possible */ - for (n = 0; n < t->nurb; n ++) { - int status = t->urb[n]->status; - - if (status == -EINPROGRESS) - return; - - if (!status) - actual_total += t->urb[n]->actual_length; - } - - if (actual_total < t->req->actual) { - terr(t, "requested %d actual %d", t->req->actual, actual_total); - t->stalled = 1; - return; - } - - /* completely transfered over, we can start next transfer now */ - start_downstream(t); -} - -static void stop_downstream(struct downstream_transaction *t) { - int n; - struct rawbulk_transfer *transfer = t->transfer; - int maxurbs = t->buffer_length / t->urb_length; - - if (t->state == DOWNSTREAM_STAT_RETRIEVING) { - usb_ep_dequeue(transfer->downstream.ep, t->req); - } else if (t->state == DOWNSTREAM_STAT_DOWNLOADING) { - for (n = 0; n < maxurbs; n ++) - usb_unlink_urb(t->urb[n]); - } - - t->stalled = 1; -} - -/* - * Ctrlrequest forwarding - */ - -static void response_complete(struct usb_ep *ep, struct usb_request *req) { - if (req->status < 0) - ldbg("feedback error %d\n", req->status); -} - -static void forward_ctrl_complete(struct urb *urb) { - struct usb_composite_dev *cdev = urb->context; - if (!cdev) - return; - - if (urb->status >= 0) { - struct usb_request *req = cdev->req; - if (urb->pipe & USB_DIR_IN) { - memcpy(req->buf, urb->transfer_buffer, urb->actual_length); - req->zero = 0; - req->length = urb->actual_length; - req->complete = response_complete; - ldbg("cp echo: len %d data[0] %02x", req->length, *((char *)req->buf)); - usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); - } else /* Finish the status stage */ - usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); - } -} - -int rawbulk_forward_ctrlrequest(const struct usb_ctrlrequest *ctrl) { - struct usb_device *dev; - struct urb *urb; - - ldbg("req_type %02x req %02x value %04x index %04x len %d", - ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, ctrl->wIndex, - ctrl->wLength); - - dev = rawbulk->udev; - if (!dev) { - return -ENODEV; - } - - rawbulk->forward_dr.bRequestType = ctrl->bRequestType; - rawbulk->forward_dr.bRequest = ctrl->bRequest; - rawbulk->forward_dr.wValue = ctrl->wValue; - //rawbulk->forward_dr.wIndex = ctrl->wIndex; - rawbulk->forward_dr.wIndex = 0;//MODEM DATA PORT - rawbulk->forward_dr.wLength = ctrl->wLength; - - if (!rawbulk->forwarding_urb) { - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return -ENOMEM; - rawbulk->forwarding_urb = urb; - } else - urb = rawbulk->forwarding_urb; - - if (ctrl->bRequestType & USB_DIR_IN) - usb_fill_control_urb(urb, dev, - usb_rcvctrlpipe(dev, 0), - (unsigned char *)&rawbulk->forward_dr, - rawbulk->ctrl_response, - __le16_to_cpu(ctrl->wLength), - forward_ctrl_complete, - rawbulk->cdev); - else - usb_fill_control_urb(urb, dev, - usb_sndctrlpipe(dev, 0), - (unsigned char *)&rawbulk->forward_dr, - NULL, 0, - forward_ctrl_complete, - rawbulk->cdev); - - return usb_submit_urb(urb, GFP_ATOMIC); -} - -EXPORT_SYMBOL_GPL(rawbulk_forward_ctrlrequest); - -int rawbulk_start_transactions(int transfer_id, int nups, int ndowns, int upsz, - int downsz, int splitsz, int pushable) { - int n; - int rc; - unsigned long flags = 0; - int suspended; - struct rawbulk_transfer *transfer; - struct upstream_transaction *upstream; - struct downstream_transaction *downstream; - - transfer = id_to_transfer(transfer_id); - if (!transfer) - return -ENODEV; - - if (!rawbulk->cdev || !rawbulk->udev) - return -ENODEV; - - if (!transfer->function || !transfer->interface) - return -ENODEV; - - ldbg("start transactions on id %d, nups %d ndowns %d upsz %d downsz %d split %d pushable %d\n", - transfer_id, nups, ndowns, upsz, downsz, splitsz, pushable); - - mutex_lock(&transfer->mutex); - - /* stop host transfer 1stly */ - if (transfer->inceptor) - transfer->inceptor(transfer->interface, pushable? - (RAWBULK_INCEPT_FLAG_ENABLE | RAWBULK_INCEPT_FLAG_PUSH_WAY): - RAWBULK_INCEPT_FLAG_ENABLE); - - /* Make upstream buffer larger than the pusher */ - if (pushable && (upsz < 4096)) - upsz = 4096; - - for (n = 0; n < nups; n ++) { - upstream = alloc_upstream_transaction(transfer, upsz, pushable); - if (!upstream) { - rc = -ENOMEM; - ldbg("fail to allocate upstream transaction n %d", n); - goto failto_alloc_upstream; - } - } - - for (n = 0; n < ndowns; n ++) { - downstream = alloc_downstream_transaction(transfer, downsz, splitsz); - if (!downstream) { - rc = -ENOMEM; - ldbg("fail to allocate downstream transaction n %d", n); - goto failto_alloc_downstream; - } - } - - spin_lock_irqsave(&transfer->suspend_lock, flags); - suspended = transfer->suspended; - spin_unlock_irqrestore(&transfer->suspend_lock, flags); - - if (suspended) { - ldbg("interface %d is sleeping", transfer_id); - mutex_unlock(&transfer->mutex); - return 0; - } - - transfer->control &= ~STOP_UPSTREAM; - if (!pushable) { - list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) { - if (upstream->state == UPSTREAM_STAT_FREE && !upstream->stalled) { - rc = start_upstream(upstream, GFP_KERNEL); - if (rc < 0) { - ldbg("fail to start upstream %s rc %d\n", upstream->name, rc); - goto failto_start_upstream; - } - } - } - } - - transfer->control &= ~STOP_DOWNSTREAM; - list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) { - if (downstream->state == DOWNSTREAM_STAT_FREE && !downstream->stalled) { - rc = start_downstream(downstream); - if (rc < 0) { - ldbg("fail to start downstream %s rc %d\n", downstream->name, rc); - goto failto_start_downstream; - } - } - } - - mutex_unlock(&transfer->mutex); - return 0; - -failto_start_downstream: - list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) - stop_downstream(downstream); -failto_start_upstream: - list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) - stop_upstream(upstream); -failto_alloc_downstream: - free_downstream_transaction(transfer, FREE_ALL); -failto_alloc_upstream: - free_upstream_transaction(transfer, FREE_ALL); - /* recover host transfer */ - if (transfer->inceptor) - transfer->inceptor(transfer->interface, 0); - mutex_unlock(&transfer->mutex); - return rc; -} - -EXPORT_SYMBOL_GPL(rawbulk_start_transactions); - -void rawbulk_stop_transactions(int transfer_id) { - unsigned long flags; - struct rawbulk_transfer *transfer; - struct upstream_transaction *upstream; - struct downstream_transaction *downstream; - - transfer = id_to_transfer(transfer_id); - if (!transfer) - return; - - mutex_lock(&transfer->mutex); - spin_lock_irqsave(&transfer->lock, flags); - transfer->control |= (STOP_UPSTREAM | STOP_DOWNSTREAM); - spin_unlock_irqrestore(&transfer->lock, flags); - - list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) - stop_upstream(upstream); - free_upstream_transaction(transfer, FREE_ALL); - list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) - stop_downstream(downstream); - free_downstream_transaction(transfer, FREE_ALL); - if (transfer->inceptor) - transfer->inceptor(transfer->interface, 0); - mutex_unlock(&transfer->mutex); -} - -EXPORT_SYMBOL_GPL(rawbulk_stop_transactions); - -int rawbulk_halt_transactions(int transfer_id) { - unsigned long flags; - struct rawbulk_transfer *transfer; - struct upstream_transaction *upstream; - struct downstream_transaction *downstream; - - transfer = id_to_transfer(transfer_id); - if (!transfer) - return -ENODEV; - - spin_lock_irqsave(&transfer->lock, flags); - transfer->control |= (STOP_UPSTREAM | STOP_DOWNSTREAM); - spin_unlock_irqrestore(&transfer->lock, flags); - - list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) - stop_upstream(upstream); - list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) - stop_downstream(downstream); - return 0; -} - -EXPORT_SYMBOL_GPL(rawbulk_halt_transactions); - -int rawbulk_resume_transactions(int transfer_id) { - int rc; - struct rawbulk_transfer *transfer; - struct upstream_transaction *upstream; - struct downstream_transaction *downstream; - - transfer = id_to_transfer(transfer_id); - if (!transfer) - return -ENODEV; - - if (!rawbulk->cdev || !rawbulk->udev) - return -ENODEV; - - if (!transfer->function || !transfer->interface) - return -ENODEV; - - transfer->control &= ~STOP_UPSTREAM; - list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) { - if (upstream->state == UPSTREAM_STAT_FREE && !upstream->stalled) { - rc = start_upstream(upstream, GFP_KERNEL); - if (rc < 0) { - ldbg("fail to start upstream %s rc %d", upstream->name, rc); - goto failto_start_upstream; - } - } - } - - transfer->control &= ~STOP_DOWNSTREAM; - list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) { - if (downstream->state == DOWNSTREAM_STAT_FREE && !downstream->stalled) { - rc = start_downstream(downstream); - if (rc < 0) { - ldbg("fail to start downstream %s rc %d", downstream->name, rc); - goto failto_start_downstream; - } - } - } - return 0; - -failto_start_downstream: - list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) - stop_downstream(downstream); -failto_start_upstream: - list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) - stop_upstream(upstream); - return rc; -} - -EXPORT_SYMBOL_GPL(rawbulk_resume_transactions); - -int rawbulk_transfer_state(int transfer_id) { - int stalled = 1; - int count = 0; - struct rawbulk_transfer *transfer; - struct upstream_transaction *upstream; - struct downstream_transaction *downstream; - - transfer = id_to_transfer(transfer_id); - if (!transfer) - return -EINVAL; - - if (!rawbulk->udev || !rawbulk->cdev) - return -ENODEV; - - if (!transfer->interface || !transfer->function) - return -EIO; - - list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) { - if (!upstream->stalled) - stalled = 0; - count ++; - } - - if (stalled || count == 0) - return -EACCES; - - list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) { - if (!downstream->stalled) - stalled = 0; - count ++; - } - if (stalled || count == 0) - return -EACCES; - - return 0; -} - -EXPORT_SYMBOL_GPL(rawbulk_transfer_state); - -static char *state2string(int state, int upstream) { - if (upstream) { - switch (state) { - case UPSTREAM_STAT_FREE: - return "FREE"; - case UPSTREAM_STAT_RETRIEVING: - return "RETRIEVING"; - case UPSTREAM_STAT_UPLOADING: - return "UPLOADING"; - default: - return "UNKNOW"; - } - } else { - switch (state) { - case DOWNSTREAM_STAT_FREE: - return "FREE"; - case DOWNSTREAM_STAT_RETRIEVING: - return "RETRIEVING"; - case DOWNSTREAM_STAT_DOWNLOADING: - return "DOWNLOADING"; - default: - return "UNKNOW"; - } - } -} - -int rawbulk_transfer_statistics(int transfer_id, char *buf) { - char *pbuf = buf; - struct rawbulk_transfer *transfer; - struct upstream_transaction *upstream; - struct downstream_transaction *downstream; - - transfer = id_to_transfer(transfer_id); - if (!transfer) - return sprintf(pbuf, "-ENODEV, id %d\n", transfer_id); - - pbuf += sprintf(pbuf, "rawbulk statistics:\n"); - if (rawbulk->udev) - pbuf += sprintf(pbuf, " host device: %d-%d\n", rawbulk->udev->bus->busnum, - rawbulk->udev->devnum); - else - pbuf += sprintf(pbuf, " host device: -ENODEV\n"); - if (rawbulk->cdev && rawbulk->cdev->config) - pbuf += sprintf(pbuf, " gadget device: %s\n", - rawbulk->cdev->config->label); - else - pbuf += sprintf(pbuf, " gadget device: -ENODEV\n"); - pbuf += sprintf(pbuf, " upstreams (total %d transactions)\n", - transfer->upstream.ntrans); - list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) { - pbuf += sprintf(pbuf, " %s state: %s", upstream->name, - state2string(upstream->state, 1)); - pbuf += sprintf(pbuf, ", maxbuf: %d bytes", upstream->buffer_length); - if (upstream->stalled) - pbuf += sprintf(pbuf, " (stalled!)"); - pbuf += sprintf(pbuf, "\n"); - } - pbuf += sprintf(pbuf, " downstreams (total %d transactions)\n", - transfer->downstream.ntrans); - list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) { - pbuf += sprintf(pbuf, " %s state: %s", downstream->name, - state2string(downstream->state, 0)); - pbuf += sprintf(pbuf, ", maxbuf: %d bytes", downstream->buffer_length); - if (downstream->state == DOWNSTREAM_STAT_DOWNLOADING) - pbuf += sprintf(pbuf, ", spliting: %d urbs(%d bytes)", downstream->nurb, - downstream->urb_length); - if (downstream->stalled) - pbuf += sprintf(pbuf, " (stalled!)"); - pbuf += sprintf(pbuf, "\n"); - } - pbuf += sprintf(pbuf, "\n"); - return (int)(pbuf - buf); -} - -EXPORT_SYMBOL_GPL(rawbulk_transfer_statistics); - -int rawbulk_bind_function(int transfer_id, struct usb_function *function, struct - usb_ep *bulk_out, struct usb_ep *bulk_in, - rawbulk_autoreconn_callback_t autoreconn_callback) { - struct rawbulk_transfer *transfer; - - if (!function || !bulk_out || !bulk_in) - return -EINVAL; - - transfer = id_to_transfer(transfer_id); - if (!transfer) - return -ENODEV; - - transfer->downstream.ep = bulk_out; - transfer->upstream.ep = bulk_in; - transfer->function = function; - rawbulk->cdev = function->config->cdev; - - transfer->autoreconn = autoreconn_callback; - return 0; -} - -EXPORT_SYMBOL_GPL(rawbulk_bind_function); - -void rawbulk_unbind_function(int transfer_id) { - int n; - int no_functions = 1; - struct rawbulk_transfer *transfer; - - transfer = id_to_transfer(transfer_id); - if (!transfer) - return; - - rawbulk_stop_transactions(transfer_id); - transfer->downstream.ep = NULL; - transfer->upstream.ep = NULL; - transfer->function = NULL; - - for (n = 0; n < _MAX_TID; n ++) { - if (!!rawbulk->transfer[n].function) - no_functions = 0; - } - - if (no_functions) - rawbulk->cdev = NULL; -} - -EXPORT_SYMBOL_GPL(rawbulk_unbind_function); - -int rawbulk_bind_host_interface(struct usb_interface *interface, - rawbulk_intercept_t inceptor) { - int n; - int transfer_id; - struct rawbulk_transfer *transfer; - struct usb_device *udev; - - if (!interface || !inceptor) - return -EINVAL; - - transfer_id = interface->cur_altsetting->desc.bInterfaceNumber; - transfer = id_to_transfer(transfer_id); - if (!transfer) - return -ENODEV; - - udev = interface_to_usbdev(interface); - if (!udev) - return -ENODEV; - - if (!rawbulk->udev) { - rawbulk->udev = udev; - } - - /* search host bulk ep for up/downstreams */ - for (n = 0; n < interface->cur_altsetting->desc.bNumEndpoints; n++) { - struct usb_host_endpoint *endpoint = - &interface->cur_altsetting->endpoint[n]; - if (usb_endpoint_is_bulk_out(&endpoint->desc)) - transfer->upstream.host_ep = endpoint; - if (usb_endpoint_is_bulk_in(&endpoint->desc)) - transfer->downstream.host_ep = endpoint; - } - - if (!transfer->upstream.host_ep || !transfer->downstream.host_ep) { - lerr("endpoints do not match bulk pair that needed\n"); - return -EINVAL; - } - - transfer->interface = interface; - transfer->inceptor = inceptor; - - if (transfer->autoreconn) - transfer->autoreconn(transfer->id); - - return 0; -} - -EXPORT_SYMBOL_GPL(rawbulk_bind_host_interface); - -void rawbulk_unbind_host_interface(struct usb_interface *interface) { - int n; - int no_interfaces = 1; - struct rawbulk_transfer *transfer; - int transfer_id = interface->cur_altsetting->desc.bInterfaceNumber; - - transfer = id_to_transfer(transfer_id); - if (!transfer) - return; - - rawbulk_stop_transactions(transfer_id); - transfer->upstream.host_ep = NULL; - transfer->downstream.host_ep = NULL; - transfer->interface = NULL; - transfer->inceptor = NULL; - - for (n = 0; n < _MAX_TID; n ++) { - if(!!rawbulk->transfer[n].interface) - no_interfaces = 0; - } - - if (no_interfaces) { - usb_kill_urb(rawbulk->forwarding_urb); - usb_free_urb(rawbulk->forwarding_urb); - rawbulk->forwarding_urb = NULL; - rawbulk->udev = NULL; - } -} - -EXPORT_SYMBOL_GPL(rawbulk_unbind_host_interface); - -int rawbulk_suspend_host_interface(int transfer_id, pm_message_t message) { - unsigned long flags = 0; - struct rawbulk_transfer *transfer; - - transfer = id_to_transfer(transfer_id); - if (!transfer) - return -EINVAL; - - spin_lock_irqsave(&transfer->suspend_lock, flags); - transfer->suspended = 1; - spin_unlock_irqrestore(&transfer->suspend_lock, flags); - - return 0; -} - -EXPORT_SYMBOL_GPL(rawbulk_suspend_host_interface); - -int rawbulk_resume_host_interface(int transfer_id) { - int rc; - unsigned long flags = 0; - struct rawbulk_transfer *transfer; - struct upstream_transaction *upstream; - struct downstream_transaction *downstream; - - transfer = id_to_transfer(transfer_id); - if (!transfer) - return -EINVAL; - - spin_lock_irqsave(&transfer->suspend_lock, flags); - transfer->suspended = 0; - spin_unlock_irqrestore(&transfer->suspend_lock, flags); - - list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) { - if (upstream->stalled) { - transfer->control &= ~STOP_UPSTREAM; - /* restart transaction again */ - ldbg("restart upstream: %s", upstream->name); - stop_upstream(upstream); - rc = start_upstream(upstream, GFP_KERNEL); - if (rc < 0) { - ldbg("fail to start upstream %s rc %d", upstream->name, rc); - goto failto_start_upstream; - } - } - } - - list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) { - if (downstream->stalled) { - transfer->control &= ~STOP_DOWNSTREAM; - ldbg("restart downstream: %s", downstream->name); - stop_downstream(downstream); - rc = start_downstream(downstream); - if (rc < 0) { - ldbg("fail to start downstream %s rc %d", downstream->name, rc); - goto failto_start_downstream; - } - } - } - - return 0; -failto_start_downstream: - list_for_each_entry(downstream, &transfer->downstream.transactions, tlist) - stop_downstream(downstream); -failto_start_upstream: - list_for_each_entry(upstream, &transfer->upstream.transactions, tlist) - stop_upstream(upstream); - return rc; -} - -EXPORT_SYMBOL_GPL(rawbulk_resume_host_interface); - -static __init int rawbulk_init(void) { - int n; - - rawbulk = kzalloc(sizeof *rawbulk, GFP_KERNEL); - if (!rawbulk) - return -ENOMEM; - - for (n = 0; n < _MAX_TID; n ++) { - struct rawbulk_transfer *t = &rawbulk->transfer[n]; - - t->id = n; - INIT_LIST_HEAD(&t->upstream.transactions); - INIT_LIST_HEAD(&t->downstream.transactions); - - mutex_init(&t->mutex); - spin_lock_init(&t->lock); - spin_lock_init(&t->suspend_lock); - t->suspended = 0; - t->control = STOP_UPSTREAM | STOP_DOWNSTREAM; - - init_usb_anchor(&t->submitted); - } - - return 0; -} - -fs_initcall (rawbulk_init); - -static __exit void rawbulk_exit(void) { - int n; - for (n = 0; n < _MAX_TID; n ++) - rawbulk_stop_transactions(n); - - if (rawbulk->forwarding_urb) { - usb_kill_urb(rawbulk->forwarding_urb); - usb_free_urb(rawbulk->forwarding_urb); - rawbulk->forwarding_urb = NULL; - } - - kfree(rawbulk); -} - -module_exit (rawbulk_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/rndis.c b/ANDROID_3.4.5/drivers/usb/gadget/rndis.c deleted file mode 100644 index 953439d4..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/rndis.c +++ /dev/null @@ -1,1209 +0,0 @@ -/* - * RNDIS MSG parser - * - * Authors: Benedikt Spranger, Pengutronix - * Robert Schwebel, Pengutronix - * - * 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 software was originally developed in conformance with - * Microsoft's Remote NDIS Specification License Agreement. - * - * 03/12/2004 Kai-Uwe Bloem - * Fixed message length bug in init_response - * - * 03/25/2004 Kai-Uwe Bloem - * Fixed rndis_rm_hdr length bug. - * - * Copyright (C) 2004 by David Brownell - * updates to merge with Linux 2.6, better match RNDIS spec - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - - -#undef VERBOSE_DEBUG - -#include "rndis.h" - - -/* The driver for your USB chip needs to support ep0 OUT to work with - * RNDIS, plus all three CDC Ethernet endpoints (interrupt not optional). - * - * Windows hosts need an INF file like Documentation/usb/linux.inf - * and will be happier if you provide the host_addr module parameter. - */ - -#if 0 -static int rndis_debug = 0; -module_param (rndis_debug, int, 0); -MODULE_PARM_DESC (rndis_debug, "enable debugging"); -#else -#define rndis_debug 0 -#endif - -#define RNDIS_MAX_CONFIGS 1 - - -static rndis_params rndis_per_dev_params[RNDIS_MAX_CONFIGS]; - -/* Driver Version */ -static const __le32 rndis_driver_version = cpu_to_le32(1); - -/* Function Prototypes */ -static rndis_resp_t *rndis_add_response(int configNr, u32 length); - - -/* supported OIDs */ -static const u32 oid_supported_list[] = -{ - /* the general stuff */ - OID_GEN_SUPPORTED_LIST, - OID_GEN_HARDWARE_STATUS, - OID_GEN_MEDIA_SUPPORTED, - OID_GEN_MEDIA_IN_USE, - OID_GEN_MAXIMUM_FRAME_SIZE, - OID_GEN_LINK_SPEED, - OID_GEN_TRANSMIT_BLOCK_SIZE, - OID_GEN_RECEIVE_BLOCK_SIZE, - OID_GEN_VENDOR_ID, - OID_GEN_VENDOR_DESCRIPTION, - OID_GEN_VENDOR_DRIVER_VERSION, - OID_GEN_CURRENT_PACKET_FILTER, - OID_GEN_MAXIMUM_TOTAL_SIZE, - OID_GEN_MEDIA_CONNECT_STATUS, - OID_GEN_PHYSICAL_MEDIUM, - - /* the statistical stuff */ - OID_GEN_XMIT_OK, - OID_GEN_RCV_OK, - OID_GEN_XMIT_ERROR, - OID_GEN_RCV_ERROR, - OID_GEN_RCV_NO_BUFFER, -#ifdef RNDIS_OPTIONAL_STATS - OID_GEN_DIRECTED_BYTES_XMIT, - OID_GEN_DIRECTED_FRAMES_XMIT, - OID_GEN_MULTICAST_BYTES_XMIT, - OID_GEN_MULTICAST_FRAMES_XMIT, - OID_GEN_BROADCAST_BYTES_XMIT, - OID_GEN_BROADCAST_FRAMES_XMIT, - OID_GEN_DIRECTED_BYTES_RCV, - OID_GEN_DIRECTED_FRAMES_RCV, - OID_GEN_MULTICAST_BYTES_RCV, - OID_GEN_MULTICAST_FRAMES_RCV, - OID_GEN_BROADCAST_BYTES_RCV, - OID_GEN_BROADCAST_FRAMES_RCV, - OID_GEN_RCV_CRC_ERROR, - OID_GEN_TRANSMIT_QUEUE_LENGTH, -#endif /* RNDIS_OPTIONAL_STATS */ - - /* mandatory 802.3 */ - /* the general stuff */ - OID_802_3_PERMANENT_ADDRESS, - OID_802_3_CURRENT_ADDRESS, - OID_802_3_MULTICAST_LIST, - OID_802_3_MAC_OPTIONS, - OID_802_3_MAXIMUM_LIST_SIZE, - - /* the statistical stuff */ - OID_802_3_RCV_ERROR_ALIGNMENT, - OID_802_3_XMIT_ONE_COLLISION, - OID_802_3_XMIT_MORE_COLLISIONS, -#ifdef RNDIS_OPTIONAL_STATS - OID_802_3_XMIT_DEFERRED, - OID_802_3_XMIT_MAX_COLLISIONS, - OID_802_3_RCV_OVERRUN, - OID_802_3_XMIT_UNDERRUN, - OID_802_3_XMIT_HEARTBEAT_FAILURE, - OID_802_3_XMIT_TIMES_CRS_LOST, - OID_802_3_XMIT_LATE_COLLISIONS, -#endif /* RNDIS_OPTIONAL_STATS */ - -#ifdef RNDIS_PM - /* PM and wakeup are "mandatory" for USB, but the RNDIS specs - * don't say what they mean ... and the NDIS specs are often - * confusing and/or ambiguous in this context. (That is, more - * so than their specs for the other OIDs.) - * - * FIXME someone who knows what these should do, please - * implement them! - */ - - /* power management */ - OID_PNP_CAPABILITIES, - OID_PNP_QUERY_POWER, - OID_PNP_SET_POWER, - -#ifdef RNDIS_WAKEUP - /* wake up host */ - OID_PNP_ENABLE_WAKE_UP, - OID_PNP_ADD_WAKE_UP_PATTERN, - OID_PNP_REMOVE_WAKE_UP_PATTERN, -#endif /* RNDIS_WAKEUP */ -#endif /* RNDIS_PM */ -}; - - -/* NDIS Functions */ -static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, - unsigned buf_len, rndis_resp_t *r) -{ - int retval = -ENOTSUPP; - u32 length = 4; /* usually */ - __le32 *outbuf; - int i, count; - rndis_query_cmplt_type *resp; - struct net_device *net; - struct rtnl_link_stats64 temp; - const struct rtnl_link_stats64 *stats; - - if (!r) return -ENOMEM; - resp = (rndis_query_cmplt_type *)r->buf; - - if (!resp) return -ENOMEM; - - if (buf_len && rndis_debug > 1) { - pr_debug("query OID %08x value, len %d:\n", OID, buf_len); - for (i = 0; i < buf_len; i += 16) { - pr_debug("%03d: %08x %08x %08x %08x\n", i, - get_unaligned_le32(&buf[i]), - get_unaligned_le32(&buf[i + 4]), - get_unaligned_le32(&buf[i + 8]), - get_unaligned_le32(&buf[i + 12])); - } - } - - /* response goes here, right after the header */ - outbuf = (__le32 *)&resp[1]; - resp->InformationBufferOffset = cpu_to_le32(16); - - net = rndis_per_dev_params[configNr].dev; - stats = dev_get_stats(net, &temp); - - switch (OID) { - - /* general oids (table 4-1) */ - - /* mandatory */ - case OID_GEN_SUPPORTED_LIST: - pr_debug("%s: OID_GEN_SUPPORTED_LIST\n", __func__); - length = sizeof(oid_supported_list); - count = length / sizeof(u32); - for (i = 0; i < count; i++) - outbuf[i] = cpu_to_le32(oid_supported_list[i]); - retval = 0; - break; - - /* mandatory */ - case OID_GEN_HARDWARE_STATUS: - pr_debug("%s: OID_GEN_HARDWARE_STATUS\n", __func__); - /* Bogus question! - * Hardware must be ready to receive high level protocols. - * BTW: - * reddite ergo quae sunt Caesaris Caesari - * et quae sunt Dei Deo! - */ - *outbuf = cpu_to_le32(0); - retval = 0; - break; - - /* mandatory */ - case OID_GEN_MEDIA_SUPPORTED: - pr_debug("%s: OID_GEN_MEDIA_SUPPORTED\n", __func__); - *outbuf = cpu_to_le32(rndis_per_dev_params[configNr].medium); - retval = 0; - break; - - /* mandatory */ - case OID_GEN_MEDIA_IN_USE: - pr_debug("%s: OID_GEN_MEDIA_IN_USE\n", __func__); - /* one medium, one transport... (maybe you do it better) */ - *outbuf = cpu_to_le32(rndis_per_dev_params[configNr].medium); - retval = 0; - break; - - /* mandatory */ - case OID_GEN_MAXIMUM_FRAME_SIZE: - pr_debug("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __func__); - if (rndis_per_dev_params[configNr].dev) { - *outbuf = cpu_to_le32( - rndis_per_dev_params[configNr].dev->mtu); - retval = 0; - } - break; - - /* mandatory */ - case OID_GEN_LINK_SPEED: - if (rndis_debug > 1) - pr_debug("%s: OID_GEN_LINK_SPEED\n", __func__); - if (rndis_per_dev_params[configNr].media_state - == NDIS_MEDIA_STATE_DISCONNECTED) - *outbuf = cpu_to_le32(0); - else - *outbuf = cpu_to_le32( - rndis_per_dev_params[configNr].speed); - retval = 0; - break; - - /* mandatory */ - case OID_GEN_TRANSMIT_BLOCK_SIZE: - pr_debug("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __func__); - if (rndis_per_dev_params[configNr].dev) { - *outbuf = cpu_to_le32( - rndis_per_dev_params[configNr].dev->mtu); - retval = 0; - } - break; - - /* mandatory */ - case OID_GEN_RECEIVE_BLOCK_SIZE: - pr_debug("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __func__); - if (rndis_per_dev_params[configNr].dev) { - *outbuf = cpu_to_le32( - rndis_per_dev_params[configNr].dev->mtu); - retval = 0; - } - break; - - /* mandatory */ - case OID_GEN_VENDOR_ID: - pr_debug("%s: OID_GEN_VENDOR_ID\n", __func__); - *outbuf = cpu_to_le32( - rndis_per_dev_params[configNr].vendorID); - retval = 0; - break; - - /* mandatory */ - case OID_GEN_VENDOR_DESCRIPTION: - pr_debug("%s: OID_GEN_VENDOR_DESCRIPTION\n", __func__); - if (rndis_per_dev_params[configNr].vendorDescr) { - length = strlen(rndis_per_dev_params[configNr]. - vendorDescr); - memcpy(outbuf, - rndis_per_dev_params[configNr].vendorDescr, - length); - } else { - outbuf[0] = 0; - } - retval = 0; - break; - - case OID_GEN_VENDOR_DRIVER_VERSION: - pr_debug("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __func__); - /* Created as LE */ - *outbuf = rndis_driver_version; - retval = 0; - break; - - /* mandatory */ - case OID_GEN_CURRENT_PACKET_FILTER: - pr_debug("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __func__); - *outbuf = cpu_to_le32(*rndis_per_dev_params[configNr].filter); - retval = 0; - break; - - /* mandatory */ - case OID_GEN_MAXIMUM_TOTAL_SIZE: - pr_debug("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __func__); - *outbuf = cpu_to_le32(RNDIS_MAX_TOTAL_SIZE); - retval = 0; - break; - - /* mandatory */ - case OID_GEN_MEDIA_CONNECT_STATUS: - if (rndis_debug > 1) - pr_debug("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __func__); - *outbuf = cpu_to_le32(rndis_per_dev_params[configNr] - .media_state); - retval = 0; - break; - - case OID_GEN_PHYSICAL_MEDIUM: - pr_debug("%s: OID_GEN_PHYSICAL_MEDIUM\n", __func__); - *outbuf = cpu_to_le32(0); - retval = 0; - break; - - /* The RNDIS specification is incomplete/wrong. Some versions - * of MS-Windows expect OIDs that aren't specified there. Other - * versions emit undefined RNDIS messages. DOCUMENT ALL THESE! - */ - case OID_GEN_MAC_OPTIONS: /* from WinME */ - pr_debug("%s: OID_GEN_MAC_OPTIONS\n", __func__); - *outbuf = cpu_to_le32( - NDIS_MAC_OPTION_RECEIVE_SERIALIZED - | NDIS_MAC_OPTION_FULL_DUPLEX); - retval = 0; - break; - - /* statistics OIDs (table 4-2) */ - - /* mandatory */ - case OID_GEN_XMIT_OK: - if (rndis_debug > 1) - pr_debug("%s: OID_GEN_XMIT_OK\n", __func__); - if (stats) { - *outbuf = cpu_to_le32(stats->tx_packets - - stats->tx_errors - stats->tx_dropped); - retval = 0; - } - break; - - /* mandatory */ - case OID_GEN_RCV_OK: - if (rndis_debug > 1) - pr_debug("%s: OID_GEN_RCV_OK\n", __func__); - if (stats) { - *outbuf = cpu_to_le32(stats->rx_packets - - stats->rx_errors - stats->rx_dropped); - retval = 0; - } - break; - - /* mandatory */ - case OID_GEN_XMIT_ERROR: - if (rndis_debug > 1) - pr_debug("%s: OID_GEN_XMIT_ERROR\n", __func__); - if (stats) { - *outbuf = cpu_to_le32(stats->tx_errors); - retval = 0; - } - break; - - /* mandatory */ - case OID_GEN_RCV_ERROR: - if (rndis_debug > 1) - pr_debug("%s: OID_GEN_RCV_ERROR\n", __func__); - if (stats) { - *outbuf = cpu_to_le32(stats->rx_errors); - retval = 0; - } - break; - - /* mandatory */ - case OID_GEN_RCV_NO_BUFFER: - pr_debug("%s: OID_GEN_RCV_NO_BUFFER\n", __func__); - if (stats) { - *outbuf = cpu_to_le32(stats->rx_dropped); - retval = 0; - } - break; - - /* ieee802.3 OIDs (table 4-3) */ - - /* mandatory */ - case OID_802_3_PERMANENT_ADDRESS: - pr_debug("%s: OID_802_3_PERMANENT_ADDRESS\n", __func__); - if (rndis_per_dev_params[configNr].dev) { - length = ETH_ALEN; - memcpy(outbuf, - rndis_per_dev_params[configNr].host_mac, - length); - retval = 0; - } - break; - - /* mandatory */ - case OID_802_3_CURRENT_ADDRESS: - pr_debug("%s: OID_802_3_CURRENT_ADDRESS\n", __func__); - if (rndis_per_dev_params[configNr].dev) { - length = ETH_ALEN; - memcpy(outbuf, - rndis_per_dev_params [configNr].host_mac, - length); - retval = 0; - } - break; - - /* mandatory */ - case OID_802_3_MULTICAST_LIST: - pr_debug("%s: OID_802_3_MULTICAST_LIST\n", __func__); - /* Multicast base address only */ - *outbuf = cpu_to_le32(0xE0000000); - retval = 0; - break; - - /* mandatory */ - case OID_802_3_MAXIMUM_LIST_SIZE: - pr_debug("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __func__); - /* Multicast base address only */ - *outbuf = cpu_to_le32(1); - retval = 0; - break; - - case OID_802_3_MAC_OPTIONS: - pr_debug("%s: OID_802_3_MAC_OPTIONS\n", __func__); - *outbuf = cpu_to_le32(0); - retval = 0; - break; - - /* ieee802.3 statistics OIDs (table 4-4) */ - - /* mandatory */ - case OID_802_3_RCV_ERROR_ALIGNMENT: - pr_debug("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __func__); - if (stats) { - *outbuf = cpu_to_le32(stats->rx_frame_errors); - retval = 0; - } - break; - - /* mandatory */ - case OID_802_3_XMIT_ONE_COLLISION: - pr_debug("%s: OID_802_3_XMIT_ONE_COLLISION\n", __func__); - *outbuf = cpu_to_le32(0); - retval = 0; - break; - - /* mandatory */ - case OID_802_3_XMIT_MORE_COLLISIONS: - pr_debug("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __func__); - *outbuf = cpu_to_le32(0); - retval = 0; - break; - - default: - pr_warning("%s: query unknown OID 0x%08X\n", - __func__, OID); - } - if (retval < 0) - length = 0; - - resp->InformationBufferLength = cpu_to_le32(length); - r->length = length + sizeof(*resp); - resp->MessageLength = cpu_to_le32(r->length); - return retval; -} - -static int gen_ndis_set_resp(u8 configNr, u32 OID, u8 *buf, u32 buf_len, - rndis_resp_t *r) -{ - rndis_set_cmplt_type *resp; - int i, retval = -ENOTSUPP; - struct rndis_params *params; - - if (!r) - return -ENOMEM; - resp = (rndis_set_cmplt_type *)r->buf; - if (!resp) - return -ENOMEM; - - if (buf_len && rndis_debug > 1) { - pr_debug("set OID %08x value, len %d:\n", OID, buf_len); - for (i = 0; i < buf_len; i += 16) { - pr_debug("%03d: %08x %08x %08x %08x\n", i, - get_unaligned_le32(&buf[i]), - get_unaligned_le32(&buf[i + 4]), - get_unaligned_le32(&buf[i + 8]), - get_unaligned_le32(&buf[i + 12])); - } - } - - params = &rndis_per_dev_params[configNr]; - switch (OID) { - case OID_GEN_CURRENT_PACKET_FILTER: - - /* these NDIS_PACKET_TYPE_* bitflags are shared with - * cdc_filter; it's not RNDIS-specific - * NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in: - * PROMISCUOUS, DIRECTED, - * MULTICAST, ALL_MULTICAST, BROADCAST - */ - *params->filter = (u16)get_unaligned_le32(buf); - pr_debug("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n", - __func__, *params->filter); - - /* this call has a significant side effect: it's - * what makes the packet flow start and stop, like - * activating the CDC Ethernet altsetting. - */ - retval = 0; - if (*params->filter) { - params->state = RNDIS_DATA_INITIALIZED; - netif_carrier_on(params->dev); - if (netif_running(params->dev)) - netif_wake_queue(params->dev); - } else { - params->state = RNDIS_INITIALIZED; - netif_carrier_off(params->dev); - netif_stop_queue(params->dev); - } - break; - - case OID_802_3_MULTICAST_LIST: - /* I think we can ignore this */ - pr_debug("%s: OID_802_3_MULTICAST_LIST\n", __func__); - retval = 0; - break; - - default: - pr_warning("%s: set unknown OID 0x%08X, size %d\n", - __func__, OID, buf_len); - } - - return retval; -} - -/* - * Response Functions - */ - -static int rndis_init_response(int configNr, rndis_init_msg_type *buf) -{ - rndis_init_cmplt_type *resp; - rndis_resp_t *r; - struct rndis_params *params = rndis_per_dev_params + configNr; - - if (!params->dev) - return -ENOTSUPP; - - r = rndis_add_response(configNr, sizeof(rndis_init_cmplt_type)); - if (!r) - return -ENOMEM; - resp = (rndis_init_cmplt_type *)r->buf; - - resp->MessageType = cpu_to_le32(REMOTE_NDIS_INITIALIZE_CMPLT); - resp->MessageLength = cpu_to_le32(52); - resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ - resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS); - resp->MajorVersion = cpu_to_le32(RNDIS_MAJOR_VERSION); - resp->MinorVersion = cpu_to_le32(RNDIS_MINOR_VERSION); - resp->DeviceFlags = cpu_to_le32(RNDIS_DF_CONNECTIONLESS); - resp->Medium = cpu_to_le32(RNDIS_MEDIUM_802_3); - resp->MaxPacketsPerTransfer = cpu_to_le32(1); - resp->MaxTransferSize = cpu_to_le32( - params->dev->mtu - + sizeof(struct ethhdr) - + sizeof(struct rndis_packet_msg_type) - + 22); - resp->PacketAlignmentFactor = cpu_to_le32(0); - resp->AFListOffset = cpu_to_le32(0); - resp->AFListSize = cpu_to_le32(0); - - params->resp_avail(params->v); - return 0; -} - -static int rndis_query_response(int configNr, rndis_query_msg_type *buf) -{ - rndis_query_cmplt_type *resp; - rndis_resp_t *r; - struct rndis_params *params = rndis_per_dev_params + configNr; - - /* pr_debug("%s: OID = %08X\n", __func__, cpu_to_le32(buf->OID)); */ - if (!params->dev) - return -ENOTSUPP; - - /* - * we need more memory: - * gen_ndis_query_resp expects enough space for - * rndis_query_cmplt_type followed by data. - * oid_supported_list is the largest data reply - */ - r = rndis_add_response(configNr, - sizeof(oid_supported_list) + sizeof(rndis_query_cmplt_type)); - if (!r) - return -ENOMEM; - resp = (rndis_query_cmplt_type *)r->buf; - - resp->MessageType = cpu_to_le32(REMOTE_NDIS_QUERY_CMPLT); - resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ - - if (gen_ndis_query_resp(configNr, le32_to_cpu(buf->OID), - le32_to_cpu(buf->InformationBufferOffset) - + 8 + (u8 *)buf, - le32_to_cpu(buf->InformationBufferLength), - r)) { - /* OID not supported */ - resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED); - resp->MessageLength = cpu_to_le32(sizeof *resp); - resp->InformationBufferLength = cpu_to_le32(0); - resp->InformationBufferOffset = cpu_to_le32(0); - } else - resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS); - - params->resp_avail(params->v); - return 0; -} - -static int rndis_set_response(int configNr, rndis_set_msg_type *buf) -{ - u32 BufLength, BufOffset; - rndis_set_cmplt_type *resp; - rndis_resp_t *r; - struct rndis_params *params = rndis_per_dev_params + configNr; - - r = rndis_add_response(configNr, sizeof(rndis_set_cmplt_type)); - if (!r) - return -ENOMEM; - resp = (rndis_set_cmplt_type *)r->buf; - - BufLength = le32_to_cpu(buf->InformationBufferLength); - BufOffset = le32_to_cpu(buf->InformationBufferOffset); - -#ifdef VERBOSE_DEBUG - pr_debug("%s: Length: %d\n", __func__, BufLength); - pr_debug("%s: Offset: %d\n", __func__, BufOffset); - pr_debug("%s: InfoBuffer: ", __func__); - - for (i = 0; i < BufLength; i++) { - pr_debug("%02x ", *(((u8 *) buf) + i + 8 + BufOffset)); - } - - pr_debug("\n"); -#endif - - resp->MessageType = cpu_to_le32(REMOTE_NDIS_SET_CMPLT); - resp->MessageLength = cpu_to_le32(16); - resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ - if (gen_ndis_set_resp(configNr, le32_to_cpu(buf->OID), - ((u8 *)buf) + 8 + BufOffset, BufLength, r)) - resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED); - else - resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS); - - params->resp_avail(params->v); - return 0; -} - -static int rndis_reset_response(int configNr, rndis_reset_msg_type *buf) -{ - rndis_reset_cmplt_type *resp; - rndis_resp_t *r; - struct rndis_params *params = rndis_per_dev_params + configNr; - - r = rndis_add_response(configNr, sizeof(rndis_reset_cmplt_type)); - if (!r) - return -ENOMEM; - resp = (rndis_reset_cmplt_type *)r->buf; - - resp->MessageType = cpu_to_le32(REMOTE_NDIS_RESET_CMPLT); - resp->MessageLength = cpu_to_le32(16); - resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS); - /* resent information */ - resp->AddressingReset = cpu_to_le32(1); - - params->resp_avail(params->v); - return 0; -} - -static int rndis_keepalive_response(int configNr, - rndis_keepalive_msg_type *buf) -{ - rndis_keepalive_cmplt_type *resp; - rndis_resp_t *r; - struct rndis_params *params = rndis_per_dev_params + configNr; - - /* host "should" check only in RNDIS_DATA_INITIALIZED state */ - - r = rndis_add_response(configNr, sizeof(rndis_keepalive_cmplt_type)); - if (!r) - return -ENOMEM; - resp = (rndis_keepalive_cmplt_type *)r->buf; - - resp->MessageType = cpu_to_le32( - REMOTE_NDIS_KEEPALIVE_CMPLT); - resp->MessageLength = cpu_to_le32(16); - resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ - resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS); - - params->resp_avail(params->v); - return 0; -} - - -/* - * Device to Host Comunication - */ -static int rndis_indicate_status_msg(int configNr, u32 status) -{ - rndis_indicate_status_msg_type *resp; - rndis_resp_t *r; - struct rndis_params *params = rndis_per_dev_params + configNr; - - if (params->state == RNDIS_UNINITIALIZED) - return -ENOTSUPP; - - r = rndis_add_response(configNr, - sizeof(rndis_indicate_status_msg_type)); - if (!r) - return -ENOMEM; - resp = (rndis_indicate_status_msg_type *)r->buf; - - resp->MessageType = cpu_to_le32(REMOTE_NDIS_INDICATE_STATUS_MSG); - resp->MessageLength = cpu_to_le32(20); - resp->Status = cpu_to_le32(status); - resp->StatusBufferLength = cpu_to_le32(0); - resp->StatusBufferOffset = cpu_to_le32(0); - - params->resp_avail(params->v); - return 0; -} - -int rndis_signal_connect(int configNr) -{ - rndis_per_dev_params[configNr].media_state - = NDIS_MEDIA_STATE_CONNECTED; - return rndis_indicate_status_msg(configNr, - RNDIS_STATUS_MEDIA_CONNECT); -} - -int rndis_signal_disconnect(int configNr) -{ - rndis_per_dev_params[configNr].media_state - = NDIS_MEDIA_STATE_DISCONNECTED; - return rndis_indicate_status_msg(configNr, - RNDIS_STATUS_MEDIA_DISCONNECT); -} - -void rndis_uninit(int configNr) -{ - u8 *buf; - u32 length; - - if (configNr >= RNDIS_MAX_CONFIGS) - return; - rndis_per_dev_params[configNr].state = RNDIS_UNINITIALIZED; - - /* drain the response queue */ - while ((buf = rndis_get_next_response(configNr, &length))) - rndis_free_response(configNr, buf); -} - -void rndis_set_host_mac(int configNr, const u8 *addr) -{ - rndis_per_dev_params[configNr].host_mac = addr; -} - -/* - * Message Parser - */ -int rndis_msg_parser(u8 configNr, u8 *buf) -{ - u32 MsgType, MsgLength; - __le32 *tmp; - struct rndis_params *params; - - if (!buf) - return -ENOMEM; - - tmp = (__le32 *)buf; - MsgType = get_unaligned_le32(tmp++); - MsgLength = get_unaligned_le32(tmp++); - - if (configNr >= RNDIS_MAX_CONFIGS) - return -ENOTSUPP; - params = &rndis_per_dev_params[configNr]; - - /* NOTE: RNDIS is *EXTREMELY* chatty ... Windows constantly polls for - * rx/tx statistics and link status, in addition to KEEPALIVE traffic - * and normal HC level polling to see if there's any IN traffic. - */ - - /* For USB: responses may take up to 10 seconds */ - switch (MsgType) { - case REMOTE_NDIS_INITIALIZE_MSG: - pr_debug("%s: REMOTE_NDIS_INITIALIZE_MSG\n", - __func__); - params->state = RNDIS_INITIALIZED; - return rndis_init_response(configNr, - (rndis_init_msg_type *)buf); - - case REMOTE_NDIS_HALT_MSG: - pr_debug("%s: REMOTE_NDIS_HALT_MSG\n", - __func__); - params->state = RNDIS_UNINITIALIZED; - if (params->dev) { - netif_carrier_off(params->dev); - netif_stop_queue(params->dev); - } - return 0; - - case REMOTE_NDIS_QUERY_MSG: - return rndis_query_response(configNr, - (rndis_query_msg_type *)buf); - - case REMOTE_NDIS_SET_MSG: - return rndis_set_response(configNr, - (rndis_set_msg_type *)buf); - - case REMOTE_NDIS_RESET_MSG: - pr_debug("%s: REMOTE_NDIS_RESET_MSG\n", - __func__); - return rndis_reset_response(configNr, - (rndis_reset_msg_type *)buf); - - case REMOTE_NDIS_KEEPALIVE_MSG: - /* For USB: host does this every 5 seconds */ - if (rndis_debug > 1) - pr_debug("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", - __func__); - return rndis_keepalive_response(configNr, - (rndis_keepalive_msg_type *) - buf); - - default: - /* At least Windows XP emits some undefined RNDIS messages. - * In one case those messages seemed to relate to the host - * suspending itself. - */ - pr_warning("%s: unknown RNDIS message 0x%08X len %d\n", - __func__, MsgType, MsgLength); - { - unsigned i; - for (i = 0; i < MsgLength; i += 16) { - pr_debug("%03d: " - " %02x %02x %02x %02x" - " %02x %02x %02x %02x" - " %02x %02x %02x %02x" - " %02x %02x %02x %02x" - "\n", - i, - buf[i], buf [i+1], - buf[i+2], buf[i+3], - buf[i+4], buf [i+5], - buf[i+6], buf[i+7], - buf[i+8], buf [i+9], - buf[i+10], buf[i+11], - buf[i+12], buf [i+13], - buf[i+14], buf[i+15]); - } - } - break; - } - - return -ENOTSUPP; -} - -int rndis_register(void (*resp_avail)(void *v), void *v) -{ - u8 i; - - if (!resp_avail) - return -EINVAL; - - for (i = 0; i < RNDIS_MAX_CONFIGS; i++) { - if (!rndis_per_dev_params[i].used) { - rndis_per_dev_params[i].used = 1; - rndis_per_dev_params[i].resp_avail = resp_avail; - rndis_per_dev_params[i].v = v; - pr_debug("%s: configNr = %d\n", __func__, i); - return i; - } - } - pr_debug("failed\n"); - - return -ENODEV; -} - -void rndis_deregister(int configNr) -{ - pr_debug("%s:\n", __func__); - - if (configNr >= RNDIS_MAX_CONFIGS) return; - rndis_per_dev_params[configNr].used = 0; -} - -int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter) -{ - pr_debug("%s:\n", __func__); - if (!dev) - return -EINVAL; - if (configNr >= RNDIS_MAX_CONFIGS) return -1; - - rndis_per_dev_params[configNr].dev = dev; - rndis_per_dev_params[configNr].filter = cdc_filter; - - return 0; -} - -int rndis_set_param_vendor(u8 configNr, u32 vendorID, const char *vendorDescr) -{ - pr_debug("%s:\n", __func__); - if (!vendorDescr) return -1; - if (configNr >= RNDIS_MAX_CONFIGS) return -1; - - rndis_per_dev_params[configNr].vendorID = vendorID; - rndis_per_dev_params[configNr].vendorDescr = vendorDescr; - - return 0; -} - -int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed) -{ - pr_debug("%s: %u %u\n", __func__, medium, speed); - if (configNr >= RNDIS_MAX_CONFIGS) return -1; - - rndis_per_dev_params[configNr].medium = medium; - rndis_per_dev_params[configNr].speed = speed; - - return 0; -} - -void rndis_add_hdr(struct sk_buff *skb) -{ - struct rndis_packet_msg_type *header; - - if (!skb) - return; - header = (void *)skb_push(skb, sizeof(*header)); - memset(header, 0, sizeof *header); - header->MessageType = cpu_to_le32(REMOTE_NDIS_PACKET_MSG); - header->MessageLength = cpu_to_le32(skb->len); - header->DataOffset = cpu_to_le32(36); - header->DataLength = cpu_to_le32(skb->len - sizeof(*header)); -} - -void rndis_free_response(int configNr, u8 *buf) -{ - rndis_resp_t *r; - struct list_head *act, *tmp; - - list_for_each_safe(act, tmp, - &(rndis_per_dev_params[configNr].resp_queue)) - { - r = list_entry(act, rndis_resp_t, list); - if (r && r->buf == buf) { - list_del(&r->list); - kfree(r); - } - } -} - -u8 *rndis_get_next_response(int configNr, u32 *length) -{ - rndis_resp_t *r; - struct list_head *act, *tmp; - - if (!length) return NULL; - - list_for_each_safe(act, tmp, - &(rndis_per_dev_params[configNr].resp_queue)) - { - r = list_entry(act, rndis_resp_t, list); - if (!r->send) { - r->send = 1; - *length = r->length; - return r->buf; - } - } - - return NULL; -} - -static rndis_resp_t *rndis_add_response(int configNr, u32 length) -{ - rndis_resp_t *r; - - /* NOTE: this gets copied into ether.c USB_BUFSIZ bytes ... */ - r = kmalloc(sizeof(rndis_resp_t) + length, GFP_ATOMIC); - if (!r) return NULL; - - r->buf = (u8 *)(r + 1); - r->length = length; - r->send = 0; - - list_add_tail(&r->list, - &(rndis_per_dev_params[configNr].resp_queue)); - return r; -} - -int rndis_rm_hdr(struct gether *port, - struct sk_buff *skb, - struct sk_buff_head *list) -{ - /* tmp points to a struct rndis_packet_msg_type */ - __le32 *tmp = (void *)skb->data; - - /* MessageType, MessageLength */ - if (cpu_to_le32(REMOTE_NDIS_PACKET_MSG) - != get_unaligned(tmp++)) { - dev_kfree_skb_any(skb); - return -EINVAL; - } - tmp++; - - /* DataOffset, DataLength */ - if (!skb_pull(skb, get_unaligned_le32(tmp++) + 8)) { - dev_kfree_skb_any(skb); - return -EOVERFLOW; - } - skb_trim(skb, get_unaligned_le32(tmp++)); - - skb_queue_tail(list, skb); - return 0; -} - -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - -static int rndis_proc_show(struct seq_file *m, void *v) -{ - rndis_params *param = m->private; - - seq_printf(m, - "Config Nr. %d\n" - "used : %s\n" - "state : %s\n" - "medium : 0x%08X\n" - "speed : %d\n" - "cable : %s\n" - "vendor ID : 0x%08X\n" - "vendor : %s\n", - param->confignr, (param->used) ? "y" : "n", - ({ char *s = "?"; - switch (param->state) { - case RNDIS_UNINITIALIZED: - s = "RNDIS_UNINITIALIZED"; break; - case RNDIS_INITIALIZED: - s = "RNDIS_INITIALIZED"; break; - case RNDIS_DATA_INITIALIZED: - s = "RNDIS_DATA_INITIALIZED"; break; - }; s; }), - param->medium, - (param->media_state) ? 0 : param->speed*100, - (param->media_state) ? "disconnected" : "connected", - param->vendorID, param->vendorDescr); - return 0; -} - -static ssize_t rndis_proc_write(struct file *file, const char __user *buffer, - size_t count, loff_t *ppos) -{ - rndis_params *p = PDE(file->f_path.dentry->d_inode)->data; - u32 speed = 0; - int i, fl_speed = 0; - - for (i = 0; i < count; i++) { - char c; - if (get_user(c, buffer)) - return -EFAULT; - switch (c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - fl_speed = 1; - speed = speed * 10 + c - '0'; - break; - case 'C': - case 'c': - rndis_signal_connect(p->confignr); - break; - case 'D': - case 'd': - rndis_signal_disconnect(p->confignr); - break; - default: - if (fl_speed) p->speed = speed; - else pr_debug("%c is not valid\n", c); - break; - } - - buffer++; - } - - return count; -} - -static int rndis_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, rndis_proc_show, PDE(inode)->data); -} - -static const struct file_operations rndis_proc_fops = { - .owner = THIS_MODULE, - .open = rndis_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .write = rndis_proc_write, -}; - -#define NAME_TEMPLATE "driver/rndis-%03d" - -static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS]; - -#endif /* CONFIG_USB_GADGET_DEBUG_FILES */ - -static bool rndis_initialized; - -int rndis_init(void) -{ - u8 i; - - if (rndis_initialized) - return 0; - - for (i = 0; i < RNDIS_MAX_CONFIGS; i++) { -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - char name [20]; - - sprintf(name, NAME_TEMPLATE, i); - rndis_connect_state[i] = proc_create_data(name, 0660, NULL, - &rndis_proc_fops, - (void *)(rndis_per_dev_params + i)); - if (!rndis_connect_state[i]) { - pr_debug("%s: remove entries", __func__); - while (i) { - sprintf(name, NAME_TEMPLATE, --i); - remove_proc_entry(name, NULL); - } - pr_debug("\n"); - return -EIO; - } -#endif - rndis_per_dev_params[i].confignr = i; - rndis_per_dev_params[i].used = 0; - rndis_per_dev_params[i].state = RNDIS_UNINITIALIZED; - rndis_per_dev_params[i].media_state - = NDIS_MEDIA_STATE_DISCONNECTED; - INIT_LIST_HEAD(&(rndis_per_dev_params[i].resp_queue)); - } - - rndis_initialized = true; - return 0; -} - -void rndis_exit(void) -{ -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - u8 i; - char name[20]; -#endif - - if (!rndis_initialized) - return; - rndis_initialized = false; - -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - for (i = 0; i < RNDIS_MAX_CONFIGS; i++) { - sprintf(name, NAME_TEMPLATE, i); - remove_proc_entry(name, NULL); - } -#endif -} -bool get_rndis_initialized(void) -{ - return rndis_initialized; -} \ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/usb/gadget/rndis.h b/ANDROID_3.4.5/drivers/usb/gadget/rndis.h deleted file mode 100644 index 907c3300..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/rndis.h +++ /dev/null @@ -1,268 +0,0 @@ -/* - * RNDIS Definitions for Remote NDIS - * - * Authors: Benedikt Spranger, Pengutronix - * Robert Schwebel, Pengutronix - * - * 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 software was originally developed in conformance with - * Microsoft's Remote NDIS Specification License Agreement. - */ - -#ifndef _LINUX_RNDIS_H -#define _LINUX_RNDIS_H - -#include "ndis.h" - -#define RNDIS_MAXIMUM_FRAME_SIZE 1518 -#define RNDIS_MAX_TOTAL_SIZE 1558 - -/* Remote NDIS Versions */ -#define RNDIS_MAJOR_VERSION 1 -#define RNDIS_MINOR_VERSION 0 - -/* Status Values */ -#define RNDIS_STATUS_SUCCESS 0x00000000U /* Success */ -#define RNDIS_STATUS_FAILURE 0xC0000001U /* Unspecified error */ -#define RNDIS_STATUS_INVALID_DATA 0xC0010015U /* Invalid data */ -#define RNDIS_STATUS_NOT_SUPPORTED 0xC00000BBU /* Unsupported request */ -#define RNDIS_STATUS_MEDIA_CONNECT 0x4001000BU /* Device connected */ -#define RNDIS_STATUS_MEDIA_DISCONNECT 0x4001000CU /* Device disconnected */ -/* For all not specified status messages: - * RNDIS_STATUS_Xxx -> NDIS_STATUS_Xxx - */ - -/* Message Set for Connectionless (802.3) Devices */ -#define REMOTE_NDIS_PACKET_MSG 0x00000001U -#define REMOTE_NDIS_INITIALIZE_MSG 0x00000002U /* Initialize device */ -#define REMOTE_NDIS_HALT_MSG 0x00000003U -#define REMOTE_NDIS_QUERY_MSG 0x00000004U -#define REMOTE_NDIS_SET_MSG 0x00000005U -#define REMOTE_NDIS_RESET_MSG 0x00000006U -#define REMOTE_NDIS_INDICATE_STATUS_MSG 0x00000007U -#define REMOTE_NDIS_KEEPALIVE_MSG 0x00000008U - -/* Message completion */ -#define REMOTE_NDIS_INITIALIZE_CMPLT 0x80000002U -#define REMOTE_NDIS_QUERY_CMPLT 0x80000004U -#define REMOTE_NDIS_SET_CMPLT 0x80000005U -#define REMOTE_NDIS_RESET_CMPLT 0x80000006U -#define REMOTE_NDIS_KEEPALIVE_CMPLT 0x80000008U - -/* Device Flags */ -#define RNDIS_DF_CONNECTIONLESS 0x00000001U -#define RNDIS_DF_CONNECTION_ORIENTED 0x00000002U - -#define RNDIS_MEDIUM_802_3 0x00000000U - -/* from drivers/net/sk98lin/h/skgepnmi.h */ -#define OID_PNP_CAPABILITIES 0xFD010100 -#define OID_PNP_SET_POWER 0xFD010101 -#define OID_PNP_QUERY_POWER 0xFD010102 -#define OID_PNP_ADD_WAKE_UP_PATTERN 0xFD010103 -#define OID_PNP_REMOVE_WAKE_UP_PATTERN 0xFD010104 -#define OID_PNP_ENABLE_WAKE_UP 0xFD010106 - - -typedef struct rndis_init_msg_type -{ - __le32 MessageType; - __le32 MessageLength; - __le32 RequestID; - __le32 MajorVersion; - __le32 MinorVersion; - __le32 MaxTransferSize; -} rndis_init_msg_type; - -typedef struct rndis_init_cmplt_type -{ - __le32 MessageType; - __le32 MessageLength; - __le32 RequestID; - __le32 Status; - __le32 MajorVersion; - __le32 MinorVersion; - __le32 DeviceFlags; - __le32 Medium; - __le32 MaxPacketsPerTransfer; - __le32 MaxTransferSize; - __le32 PacketAlignmentFactor; - __le32 AFListOffset; - __le32 AFListSize; -} rndis_init_cmplt_type; - -typedef struct rndis_halt_msg_type -{ - __le32 MessageType; - __le32 MessageLength; - __le32 RequestID; -} rndis_halt_msg_type; - -typedef struct rndis_query_msg_type -{ - __le32 MessageType; - __le32 MessageLength; - __le32 RequestID; - __le32 OID; - __le32 InformationBufferLength; - __le32 InformationBufferOffset; - __le32 DeviceVcHandle; -} rndis_query_msg_type; - -typedef struct rndis_query_cmplt_type -{ - __le32 MessageType; - __le32 MessageLength; - __le32 RequestID; - __le32 Status; - __le32 InformationBufferLength; - __le32 InformationBufferOffset; -} rndis_query_cmplt_type; - -typedef struct rndis_set_msg_type -{ - __le32 MessageType; - __le32 MessageLength; - __le32 RequestID; - __le32 OID; - __le32 InformationBufferLength; - __le32 InformationBufferOffset; - __le32 DeviceVcHandle; -} rndis_set_msg_type; - -typedef struct rndis_set_cmplt_type -{ - __le32 MessageType; - __le32 MessageLength; - __le32 RequestID; - __le32 Status; -} rndis_set_cmplt_type; - -typedef struct rndis_reset_msg_type -{ - __le32 MessageType; - __le32 MessageLength; - __le32 Reserved; -} rndis_reset_msg_type; - -typedef struct rndis_reset_cmplt_type -{ - __le32 MessageType; - __le32 MessageLength; - __le32 Status; - __le32 AddressingReset; -} rndis_reset_cmplt_type; - -typedef struct rndis_indicate_status_msg_type -{ - __le32 MessageType; - __le32 MessageLength; - __le32 Status; - __le32 StatusBufferLength; - __le32 StatusBufferOffset; -} rndis_indicate_status_msg_type; - -typedef struct rndis_keepalive_msg_type -{ - __le32 MessageType; - __le32 MessageLength; - __le32 RequestID; -} rndis_keepalive_msg_type; - -typedef struct rndis_keepalive_cmplt_type -{ - __le32 MessageType; - __le32 MessageLength; - __le32 RequestID; - __le32 Status; -} rndis_keepalive_cmplt_type; - -struct rndis_packet_msg_type -{ - __le32 MessageType; - __le32 MessageLength; - __le32 DataOffset; - __le32 DataLength; - __le32 OOBDataOffset; - __le32 OOBDataLength; - __le32 NumOOBDataElements; - __le32 PerPacketInfoOffset; - __le32 PerPacketInfoLength; - __le32 VcHandle; - __le32 Reserved; -} __attribute__ ((packed)); - -struct rndis_config_parameter -{ - __le32 ParameterNameOffset; - __le32 ParameterNameLength; - __le32 ParameterType; - __le32 ParameterValueOffset; - __le32 ParameterValueLength; -}; - -/* implementation specific */ -enum rndis_state -{ - RNDIS_UNINITIALIZED, - RNDIS_INITIALIZED, - RNDIS_DATA_INITIALIZED, -}; - -typedef struct rndis_resp_t -{ - struct list_head list; - u8 *buf; - u32 length; - int send; -} rndis_resp_t; - -typedef struct rndis_params -{ - u8 confignr; - u8 used; - u16 saved_filter; - enum rndis_state state; - u32 medium; - u32 speed; - u32 media_state; - - const u8 *host_mac; - u16 *filter; - struct net_device *dev; - - u32 vendorID; - const char *vendorDescr; - void (*resp_avail)(void *v); - void *v; - struct list_head resp_queue; -} rndis_params; - -/* RNDIS Message parser and other useless functions */ -int rndis_msg_parser (u8 configNr, u8 *buf); -int rndis_register(void (*resp_avail)(void *v), void *v); -void rndis_deregister (int configNr); -int rndis_set_param_dev (u8 configNr, struct net_device *dev, - u16 *cdc_filter); -int rndis_set_param_vendor (u8 configNr, u32 vendorID, - const char *vendorDescr); -int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed); -void rndis_add_hdr (struct sk_buff *skb); -int rndis_rm_hdr(struct gether *port, struct sk_buff *skb, - struct sk_buff_head *list); -u8 *rndis_get_next_response (int configNr, u32 *length); -void rndis_free_response (int configNr, u8 *buf); - -void rndis_uninit (int configNr); -int rndis_signal_connect (int configNr); -int rndis_signal_disconnect (int configNr); -int rndis_state (int configNr); -extern void rndis_set_host_mac (int configNr, const u8 *addr); - -int rndis_init(void); -void rndis_exit (void); - -#endif /* _LINUX_RNDIS_H */ diff --git a/ANDROID_3.4.5/drivers/usb/gadget/s3c-hsotg.c b/ANDROID_3.4.5/drivers/usb/gadget/s3c-hsotg.c deleted file mode 100644 index 105b206c..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/s3c-hsotg.c +++ /dev/null @@ -1,3478 +0,0 @@ -/* linux/drivers/usb/gadget/s3c-hsotg.c - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * Copyright 2008 Openmoko, Inc. - * Copyright 2008 Simtec Electronics - * Ben Dooks - * http://armlinux.simtec.co.uk/ - * - * S3C USB2.0 High-speed / OtG 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. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include -#include - -#define DMA_ADDR_INVALID (~((dma_addr_t)0)) - -/* EP0_MPS_LIMIT - * - * Unfortunately there seems to be a limit of the amount of data that can - * be transferred by IN transactions on EP0. This is either 127 bytes or 3 - * packets (which practically means 1 packet and 63 bytes of data) when the - * MPS is set to 64. - * - * This means if we are wanting to move >127 bytes of data, we need to - * split the transactions up, but just doing one packet at a time does - * not work (this may be an implicit DATA0 PID on first packet of the - * transaction) and doing 2 packets is outside the controller's limits. - * - * If we try to lower the MPS size for EP0, then no transfers work properly - * for EP0, and the system will fail basic enumeration. As no cause for this - * has currently been found, we cannot support any large IN transfers for - * EP0. - */ -#define EP0_MPS_LIMIT 64 - -struct s3c_hsotg; -struct s3c_hsotg_req; - -/** - * struct s3c_hsotg_ep - driver endpoint definition. - * @ep: The gadget layer representation of the endpoint. - * @name: The driver generated name for the endpoint. - * @queue: Queue of requests for this endpoint. - * @parent: Reference back to the parent device structure. - * @req: The current request that the endpoint is processing. This is - * used to indicate an request has been loaded onto the endpoint - * and has yet to be completed (maybe due to data move, or simply - * awaiting an ack from the core all the data has been completed). - * @debugfs: File entry for debugfs file for this endpoint. - * @lock: State lock to protect contents of endpoint. - * @dir_in: Set to true if this endpoint is of the IN direction, which - * means that it is sending data to the Host. - * @index: The index for the endpoint registers. - * @name: The name array passed to the USB core. - * @halted: Set if the endpoint has been halted. - * @periodic: Set if this is a periodic ep, such as Interrupt - * @sent_zlp: Set if we've sent a zero-length packet. - * @total_data: The total number of data bytes done. - * @fifo_size: The size of the FIFO (for periodic IN endpoints) - * @fifo_load: The amount of data loaded into the FIFO (periodic IN) - * @last_load: The offset of data for the last start of request. - * @size_loaded: The last loaded size for DxEPTSIZE for periodic IN - * - * This is the driver's state for each registered enpoint, allowing it - * to keep track of transactions that need doing. Each endpoint has a - * lock to protect the state, to try and avoid using an overall lock - * for the host controller as much as possible. - * - * For periodic IN endpoints, we have fifo_size and fifo_load to try - * and keep track of the amount of data in the periodic FIFO for each - * of these as we don't have a status register that tells us how much - * is in each of them. (note, this may actually be useless information - * as in shared-fifo mode periodic in acts like a single-frame packet - * buffer than a fifo) - */ -struct s3c_hsotg_ep { - struct usb_ep ep; - struct list_head queue; - struct s3c_hsotg *parent; - struct s3c_hsotg_req *req; - struct dentry *debugfs; - - spinlock_t lock; - - unsigned long total_data; - unsigned int size_loaded; - unsigned int last_load; - unsigned int fifo_load; - unsigned short fifo_size; - - unsigned char dir_in; - unsigned char index; - - unsigned int halted:1; - unsigned int periodic:1; - unsigned int sent_zlp:1; - - char name[10]; -}; - -#define S3C_HSOTG_EPS (8+1) /* limit to 9 for the moment */ - -/** - * struct s3c_hsotg - driver state. - * @dev: The parent device supplied to the probe function - * @driver: USB gadget driver - * @plat: The platform specific configuration data. - * @regs: The memory area mapped for accessing registers. - * @regs_res: The resource that was allocated when claiming register space. - * @irq: The IRQ number we are using - * @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos. - * @debug_root: root directrory for debugfs. - * @debug_file: main status file for debugfs. - * @debug_fifo: FIFO status file for debugfs. - * @ep0_reply: Request used for ep0 reply. - * @ep0_buff: Buffer for EP0 reply data, if needed. - * @ctrl_buff: Buffer for EP0 control requests. - * @ctrl_req: Request for EP0 control packets. - * @eps: The endpoints being supplied to the gadget framework - */ -struct s3c_hsotg { - struct device *dev; - struct usb_gadget_driver *driver; - struct s3c_hsotg_plat *plat; - - void __iomem *regs; - struct resource *regs_res; - int irq; - struct clk *clk; - - unsigned int dedicated_fifos:1; - - struct dentry *debug_root; - struct dentry *debug_file; - struct dentry *debug_fifo; - - struct usb_request *ep0_reply; - struct usb_request *ctrl_req; - u8 ep0_buff[8]; - u8 ctrl_buff[8]; - - struct usb_gadget gadget; - struct s3c_hsotg_ep eps[]; -}; - -/** - * struct s3c_hsotg_req - data transfer request - * @req: The USB gadget request - * @queue: The list of requests for the endpoint this is queued for. - * @in_progress: Has already had size/packets written to core - * @mapped: DMA buffer for this request has been mapped via dma_map_single(). - */ -struct s3c_hsotg_req { - struct usb_request req; - struct list_head queue; - unsigned char in_progress; - unsigned char mapped; -}; - -/* conversion functions */ -static inline struct s3c_hsotg_req *our_req(struct usb_request *req) -{ - return container_of(req, struct s3c_hsotg_req, req); -} - -static inline struct s3c_hsotg_ep *our_ep(struct usb_ep *ep) -{ - return container_of(ep, struct s3c_hsotg_ep, ep); -} - -static inline struct s3c_hsotg *to_hsotg(struct usb_gadget *gadget) -{ - return container_of(gadget, struct s3c_hsotg, gadget); -} - -static inline void __orr32(void __iomem *ptr, u32 val) -{ - writel(readl(ptr) | val, ptr); -} - -static inline void __bic32(void __iomem *ptr, u32 val) -{ - writel(readl(ptr) & ~val, ptr); -} - -/* forward decleration of functions */ -static void s3c_hsotg_dump(struct s3c_hsotg *hsotg); - -/** - * using_dma - return the DMA status of the driver. - * @hsotg: The driver state. - * - * Return true if we're using DMA. - * - * Currently, we have the DMA support code worked into everywhere - * that needs it, but the AMBA DMA implementation in the hardware can - * only DMA from 32bit aligned addresses. This means that gadgets such - * as the CDC Ethernet cannot work as they often pass packets which are - * not 32bit aligned. - * - * Unfortunately the choice to use DMA or not is global to the controller - * and seems to be only settable when the controller is being put through - * a core reset. This means we either need to fix the gadgets to take - * account of DMA alignment, or add bounce buffers (yuerk). - * - * Until this issue is sorted out, we always return 'false'. - */ -static inline bool using_dma(struct s3c_hsotg *hsotg) -{ - return false; /* support is not complete */ -} - -/** - * s3c_hsotg_en_gsint - enable one or more of the general interrupt - * @hsotg: The device state - * @ints: A bitmask of the interrupts to enable - */ -static void s3c_hsotg_en_gsint(struct s3c_hsotg *hsotg, u32 ints) -{ - u32 gsintmsk = readl(hsotg->regs + S3C_GINTMSK); - u32 new_gsintmsk; - - new_gsintmsk = gsintmsk | ints; - - if (new_gsintmsk != gsintmsk) { - dev_dbg(hsotg->dev, "gsintmsk now 0x%08x\n", new_gsintmsk); - writel(new_gsintmsk, hsotg->regs + S3C_GINTMSK); - } -} - -/** - * s3c_hsotg_disable_gsint - disable one or more of the general interrupt - * @hsotg: The device state - * @ints: A bitmask of the interrupts to enable - */ -static void s3c_hsotg_disable_gsint(struct s3c_hsotg *hsotg, u32 ints) -{ - u32 gsintmsk = readl(hsotg->regs + S3C_GINTMSK); - u32 new_gsintmsk; - - new_gsintmsk = gsintmsk & ~ints; - - if (new_gsintmsk != gsintmsk) - writel(new_gsintmsk, hsotg->regs + S3C_GINTMSK); -} - -/** - * s3c_hsotg_ctrl_epint - enable/disable an endpoint irq - * @hsotg: The device state - * @ep: The endpoint index - * @dir_in: True if direction is in. - * @en: The enable value, true to enable - * - * Set or clear the mask for an individual endpoint's interrupt - * request. - */ -static void s3c_hsotg_ctrl_epint(struct s3c_hsotg *hsotg, - unsigned int ep, unsigned int dir_in, - unsigned int en) -{ - unsigned long flags; - u32 bit = 1 << ep; - u32 daint; - - if (!dir_in) - bit <<= 16; - - local_irq_save(flags); - daint = readl(hsotg->regs + S3C_DAINTMSK); - if (en) - daint |= bit; - else - daint &= ~bit; - writel(daint, hsotg->regs + S3C_DAINTMSK); - local_irq_restore(flags); -} - -/** - * s3c_hsotg_init_fifo - initialise non-periodic FIFOs - * @hsotg: The device instance. - */ -static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg) -{ - unsigned int ep; - unsigned int addr; - unsigned int size; - int timeout; - u32 val; - - /* the ryu 2.6.24 release ahs - writel(0x1C0, hsotg->regs + S3C_GRXFSIZ); - writel(S3C_GNPTXFSIZ_NPTxFStAddr(0x200) | - S3C_GNPTXFSIZ_NPTxFDep(0x1C0), - hsotg->regs + S3C_GNPTXFSIZ); - */ - - /* set FIFO sizes to 2048/1024 */ - - writel(2048, hsotg->regs + S3C_GRXFSIZ); - writel(S3C_GNPTXFSIZ_NPTxFStAddr(2048) | - S3C_GNPTXFSIZ_NPTxFDep(1024), - hsotg->regs + S3C_GNPTXFSIZ); - - /* arange all the rest of the TX FIFOs, as some versions of this - * block have overlapping default addresses. This also ensures - * that if the settings have been changed, then they are set to - * known values. */ - - /* start at the end of the GNPTXFSIZ, rounded up */ - addr = 2048 + 1024; - size = 768; - - /* currently we allocate TX FIFOs for all possible endpoints, - * and assume that they are all the same size. */ - - for (ep = 1; ep <= 15; ep++) { - val = addr; - val |= size << S3C_DPTXFSIZn_DPTxFSize_SHIFT; - addr += size; - - writel(val, hsotg->regs + S3C_DPTXFSIZn(ep)); - } - - /* according to p428 of the design guide, we need to ensure that - * all fifos are flushed before continuing */ - - writel(S3C_GRSTCTL_TxFNum(0x10) | S3C_GRSTCTL_TxFFlsh | - S3C_GRSTCTL_RxFFlsh, hsotg->regs + S3C_GRSTCTL); - - /* wait until the fifos are both flushed */ - timeout = 100; - while (1) { - val = readl(hsotg->regs + S3C_GRSTCTL); - - if ((val & (S3C_GRSTCTL_TxFFlsh | S3C_GRSTCTL_RxFFlsh)) == 0) - break; - - if (--timeout == 0) { - dev_err(hsotg->dev, - "%s: timeout flushing fifos (GRSTCTL=%08x)\n", - __func__, val); - } - - udelay(1); - } - - dev_dbg(hsotg->dev, "FIFOs reset, timeout at %d\n", timeout); -} - -/** - * @ep: USB endpoint to allocate request for. - * @flags: Allocation flags - * - * Allocate a new USB request structure appropriate for the specified endpoint - */ -static struct usb_request *s3c_hsotg_ep_alloc_request(struct usb_ep *ep, - gfp_t flags) -{ - struct s3c_hsotg_req *req; - - req = kzalloc(sizeof(struct s3c_hsotg_req), flags); - if (!req) - return NULL; - - INIT_LIST_HEAD(&req->queue); - - req->req.dma = DMA_ADDR_INVALID; - return &req->req; -} - -/** - * is_ep_periodic - return true if the endpoint is in periodic mode. - * @hs_ep: The endpoint to query. - * - * Returns true if the endpoint is in periodic mode, meaning it is being - * used for an Interrupt or ISO transfer. - */ -static inline int is_ep_periodic(struct s3c_hsotg_ep *hs_ep) -{ - return hs_ep->periodic; -} - -/** - * s3c_hsotg_unmap_dma - unmap the DMA memory being used for the request - * @hsotg: The device state. - * @hs_ep: The endpoint for the request - * @hs_req: The request being processed. - * - * This is the reverse of s3c_hsotg_map_dma(), called for the completion - * of a request to ensure the buffer is ready for access by the caller. -*/ -static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg, - struct s3c_hsotg_ep *hs_ep, - struct s3c_hsotg_req *hs_req) -{ - struct usb_request *req = &hs_req->req; - enum dma_data_direction dir; - - dir = hs_ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE; - - /* ignore this if we're not moving any data */ - if (hs_req->req.length == 0) - return; - - if (hs_req->mapped) { - /* we mapped this, so unmap and remove the dma */ - - dma_unmap_single(hsotg->dev, req->dma, req->length, dir); - - req->dma = DMA_ADDR_INVALID; - hs_req->mapped = 0; - } else { - dma_sync_single_for_cpu(hsotg->dev, req->dma, req->length, dir); - } -} - -/** - * s3c_hsotg_write_fifo - write packet Data to the TxFIFO - * @hsotg: The controller state. - * @hs_ep: The endpoint we're going to write for. - * @hs_req: The request to write data for. - * - * This is called when the TxFIFO has some space in it to hold a new - * transmission and we have something to give it. The actual setup of - * the data size is done elsewhere, so all we have to do is to actually - * write the data. - * - * The return value is zero if there is more space (or nothing was done) - * otherwise -ENOSPC is returned if the FIFO space was used up. - * - * This routine is only needed for PIO -*/ -static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, - struct s3c_hsotg_ep *hs_ep, - struct s3c_hsotg_req *hs_req) -{ - bool periodic = is_ep_periodic(hs_ep); - u32 gnptxsts = readl(hsotg->regs + S3C_GNPTXSTS); - int buf_pos = hs_req->req.actual; - int to_write = hs_ep->size_loaded; - void *data; - int can_write; - int pkt_round; - - to_write -= (buf_pos - hs_ep->last_load); - - /* if there's nothing to write, get out early */ - if (to_write == 0) - return 0; - - if (periodic && !hsotg->dedicated_fifos) { - u32 epsize = readl(hsotg->regs + S3C_DIEPTSIZ(hs_ep->index)); - int size_left; - int size_done; - - /* work out how much data was loaded so we can calculate - * how much data is left in the fifo. */ - - size_left = S3C_DxEPTSIZ_XferSize_GET(epsize); - - /* if shared fifo, we cannot write anything until the - * previous data has been completely sent. - */ - if (hs_ep->fifo_load != 0) { - s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_PTxFEmp); - return -ENOSPC; - } - - dev_dbg(hsotg->dev, "%s: left=%d, load=%d, fifo=%d, size %d\n", - __func__, size_left, - hs_ep->size_loaded, hs_ep->fifo_load, hs_ep->fifo_size); - - /* how much of the data has moved */ - size_done = hs_ep->size_loaded - size_left; - - /* how much data is left in the fifo */ - can_write = hs_ep->fifo_load - size_done; - dev_dbg(hsotg->dev, "%s: => can_write1=%d\n", - __func__, can_write); - - can_write = hs_ep->fifo_size - can_write; - dev_dbg(hsotg->dev, "%s: => can_write2=%d\n", - __func__, can_write); - - if (can_write <= 0) { - s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_PTxFEmp); - return -ENOSPC; - } - } else if (hsotg->dedicated_fifos && hs_ep->index != 0) { - can_write = readl(hsotg->regs + S3C_DTXFSTS(hs_ep->index)); - - can_write &= 0xffff; - can_write *= 4; - } else { - if (S3C_GNPTXSTS_NPTxQSpcAvail_GET(gnptxsts) == 0) { - dev_dbg(hsotg->dev, - "%s: no queue slots available (0x%08x)\n", - __func__, gnptxsts); - - s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_NPTxFEmp); - return -ENOSPC; - } - - can_write = S3C_GNPTXSTS_NPTxFSpcAvail_GET(gnptxsts); - can_write *= 4; /* fifo size is in 32bit quantities. */ - } - - dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, mps %d\n", - __func__, gnptxsts, can_write, to_write, hs_ep->ep.maxpacket); - - /* limit to 512 bytes of data, it seems at least on the non-periodic - * FIFO, requests of >512 cause the endpoint to get stuck with a - * fragment of the end of the transfer in it. - */ - if (can_write > 512) - can_write = 512; - - /* limit the write to one max-packet size worth of data, but allow - * the transfer to return that it did not run out of fifo space - * doing it. */ - if (to_write > hs_ep->ep.maxpacket) { - to_write = hs_ep->ep.maxpacket; - - s3c_hsotg_en_gsint(hsotg, - periodic ? S3C_GINTSTS_PTxFEmp : - S3C_GINTSTS_NPTxFEmp); - } - - /* see if we can write data */ - - if (to_write > can_write) { - to_write = can_write; - pkt_round = to_write % hs_ep->ep.maxpacket; - - /* Not sure, but we probably shouldn't be writing partial - * packets into the FIFO, so round the write down to an - * exact number of packets. - * - * Note, we do not currently check to see if we can ever - * write a full packet or not to the FIFO. - */ - - if (pkt_round) - to_write -= pkt_round; - - /* enable correct FIFO interrupt to alert us when there - * is more room left. */ - - s3c_hsotg_en_gsint(hsotg, - periodic ? S3C_GINTSTS_PTxFEmp : - S3C_GINTSTS_NPTxFEmp); - } - - dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n", - to_write, hs_req->req.length, can_write, buf_pos); - - if (to_write <= 0) - return -ENOSPC; - - hs_req->req.actual = buf_pos + to_write; - hs_ep->total_data += to_write; - - if (periodic) - hs_ep->fifo_load += to_write; - - to_write = DIV_ROUND_UP(to_write, 4); - data = hs_req->req.buf + buf_pos; - - writesl(hsotg->regs + S3C_EPFIFO(hs_ep->index), data, to_write); - - return (to_write >= can_write) ? -ENOSPC : 0; -} - -/** - * get_ep_limit - get the maximum data legnth for this endpoint - * @hs_ep: The endpoint - * - * Return the maximum data that can be queued in one go on a given endpoint - * so that transfers that are too long can be split. - */ -static unsigned get_ep_limit(struct s3c_hsotg_ep *hs_ep) -{ - int index = hs_ep->index; - unsigned maxsize; - unsigned maxpkt; - - if (index != 0) { - maxsize = S3C_DxEPTSIZ_XferSize_LIMIT + 1; - maxpkt = S3C_DxEPTSIZ_PktCnt_LIMIT + 1; - } else { - maxsize = 64+64; - if (hs_ep->dir_in) - maxpkt = S3C_DIEPTSIZ0_PktCnt_LIMIT + 1; - else - maxpkt = 2; - } - - /* we made the constant loading easier above by using +1 */ - maxpkt--; - maxsize--; - - /* constrain by packet count if maxpkts*pktsize is greater - * than the length register size. */ - - if ((maxpkt * hs_ep->ep.maxpacket) < maxsize) - maxsize = maxpkt * hs_ep->ep.maxpacket; - - return maxsize; -} - -/** - * s3c_hsotg_start_req - start a USB request from an endpoint's queue - * @hsotg: The controller state. - * @hs_ep: The endpoint to process a request for - * @hs_req: The request to start. - * @continuing: True if we are doing more for the current request. - * - * Start the given request running by setting the endpoint registers - * appropriately, and writing any data to the FIFOs. - */ -static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, - struct s3c_hsotg_ep *hs_ep, - struct s3c_hsotg_req *hs_req, - bool continuing) -{ - struct usb_request *ureq = &hs_req->req; - int index = hs_ep->index; - int dir_in = hs_ep->dir_in; - u32 epctrl_reg; - u32 epsize_reg; - u32 epsize; - u32 ctrl; - unsigned length; - unsigned packets; - unsigned maxreq; - - if (index != 0) { - if (hs_ep->req && !continuing) { - dev_err(hsotg->dev, "%s: active request\n", __func__); - WARN_ON(1); - return; - } else if (hs_ep->req != hs_req && continuing) { - dev_err(hsotg->dev, - "%s: continue different req\n", __func__); - WARN_ON(1); - return; - } - } - - epctrl_reg = dir_in ? S3C_DIEPCTL(index) : S3C_DOEPCTL(index); - epsize_reg = dir_in ? S3C_DIEPTSIZ(index) : S3C_DOEPTSIZ(index); - - dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x, ep %d, dir %s\n", - __func__, readl(hsotg->regs + epctrl_reg), index, - hs_ep->dir_in ? "in" : "out"); - - /* If endpoint is stalled, we will restart request later */ - ctrl = readl(hsotg->regs + epctrl_reg); - - if (ctrl & S3C_DxEPCTL_Stall) { - dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index); - return; - } - - length = ureq->length - ureq->actual; - - if (0) - dev_dbg(hsotg->dev, - "REQ buf %p len %d dma 0x%08x noi=%d zp=%d snok=%d\n", - ureq->buf, length, ureq->dma, - ureq->no_interrupt, ureq->zero, ureq->short_not_ok); - - maxreq = get_ep_limit(hs_ep); - if (length > maxreq) { - int round = maxreq % hs_ep->ep.maxpacket; - - dev_dbg(hsotg->dev, "%s: length %d, max-req %d, r %d\n", - __func__, length, maxreq, round); - - /* round down to multiple of packets */ - if (round) - maxreq -= round; - - length = maxreq; - } - - if (length) - packets = DIV_ROUND_UP(length, hs_ep->ep.maxpacket); - else - packets = 1; /* send one packet if length is zero. */ - - if (dir_in && index != 0) - epsize = S3C_DxEPTSIZ_MC(1); - else - epsize = 0; - - if (index != 0 && ureq->zero) { - /* test for the packets being exactly right for the - * transfer */ - - if (length == (packets * hs_ep->ep.maxpacket)) - packets++; - } - - epsize |= S3C_DxEPTSIZ_PktCnt(packets); - epsize |= S3C_DxEPTSIZ_XferSize(length); - - dev_dbg(hsotg->dev, "%s: %d@%d/%d, 0x%08x => 0x%08x\n", - __func__, packets, length, ureq->length, epsize, epsize_reg); - - /* store the request as the current one we're doing */ - hs_ep->req = hs_req; - - /* write size / packets */ - writel(epsize, hsotg->regs + epsize_reg); - - if (using_dma(hsotg) && !continuing) { - unsigned int dma_reg; - - /* write DMA address to control register, buffer already - * synced by s3c_hsotg_ep_queue(). */ - - dma_reg = dir_in ? S3C_DIEPDMA(index) : S3C_DOEPDMA(index); - writel(ureq->dma, hsotg->regs + dma_reg); - - dev_dbg(hsotg->dev, "%s: 0x%08x => 0x%08x\n", - __func__, ureq->dma, dma_reg); - } - - ctrl |= S3C_DxEPCTL_EPEna; /* ensure ep enabled */ - ctrl |= S3C_DxEPCTL_USBActEp; - ctrl |= S3C_DxEPCTL_CNAK; /* clear NAK set by core */ - - dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); - writel(ctrl, hsotg->regs + epctrl_reg); - - /* set these, it seems that DMA support increments past the end - * of the packet buffer so we need to calculate the length from - * this information. */ - hs_ep->size_loaded = length; - hs_ep->last_load = ureq->actual; - - if (dir_in && !using_dma(hsotg)) { - /* set these anyway, we may need them for non-periodic in */ - hs_ep->fifo_load = 0; - - s3c_hsotg_write_fifo(hsotg, hs_ep, hs_req); - } - - /* clear the INTknTXFEmpMsk when we start request, more as a aide - * to debugging to see what is going on. */ - if (dir_in) - writel(S3C_DIEPMSK_INTknTXFEmpMsk, - hsotg->regs + S3C_DIEPINT(index)); - - /* Note, trying to clear the NAK here causes problems with transmit - * on the S3C6400 ending up with the TXFIFO becoming full. */ - - /* check ep is enabled */ - if (!(readl(hsotg->regs + epctrl_reg) & S3C_DxEPCTL_EPEna)) - dev_warn(hsotg->dev, - "ep%d: failed to become enabled (DxEPCTL=0x%08x)?\n", - index, readl(hsotg->regs + epctrl_reg)); - - dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", - __func__, readl(hsotg->regs + epctrl_reg)); -} - -/** - * s3c_hsotg_map_dma - map the DMA memory being used for the request - * @hsotg: The device state. - * @hs_ep: The endpoint the request is on. - * @req: The request being processed. - * - * We've been asked to queue a request, so ensure that the memory buffer - * is correctly setup for DMA. If we've been passed an extant DMA address - * then ensure the buffer has been synced to memory. If our buffer has no - * DMA memory, then we map the memory and mark our request to allow us to - * cleanup on completion. -*/ -static int s3c_hsotg_map_dma(struct s3c_hsotg *hsotg, - struct s3c_hsotg_ep *hs_ep, - struct usb_request *req) -{ - enum dma_data_direction dir; - struct s3c_hsotg_req *hs_req = our_req(req); - - dir = hs_ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE; - - /* if the length is zero, ignore the DMA data */ - if (hs_req->req.length == 0) - return 0; - - if (req->dma == DMA_ADDR_INVALID) { - dma_addr_t dma; - - dma = dma_map_single(hsotg->dev, req->buf, req->length, dir); - - if (unlikely(dma_mapping_error(hsotg->dev, dma))) - goto dma_error; - - if (dma & 3) { - dev_err(hsotg->dev, "%s: unaligned dma buffer\n", - __func__); - - dma_unmap_single(hsotg->dev, dma, req->length, dir); - return -EINVAL; - } - - hs_req->mapped = 1; - req->dma = dma; - } else { - dma_sync_single_for_cpu(hsotg->dev, req->dma, req->length, dir); - hs_req->mapped = 0; - } - - return 0; - -dma_error: - dev_err(hsotg->dev, "%s: failed to map buffer %p, %d bytes\n", - __func__, req->buf, req->length); - - return -EIO; -} - -static int s3c_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, - gfp_t gfp_flags) -{ - struct s3c_hsotg_req *hs_req = our_req(req); - struct s3c_hsotg_ep *hs_ep = our_ep(ep); - struct s3c_hsotg *hs = hs_ep->parent; - unsigned long irqflags; - bool first; - - dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d, snok=%d\n", - ep->name, req, req->length, req->buf, req->no_interrupt, - req->zero, req->short_not_ok); - - /* initialise status of the request */ - INIT_LIST_HEAD(&hs_req->queue); - req->actual = 0; - req->status = -EINPROGRESS; - - /* if we're using DMA, sync the buffers as necessary */ - if (using_dma(hs)) { - int ret = s3c_hsotg_map_dma(hs, hs_ep, req); - if (ret) - return ret; - } - - spin_lock_irqsave(&hs_ep->lock, irqflags); - - first = list_empty(&hs_ep->queue); - list_add_tail(&hs_req->queue, &hs_ep->queue); - - if (first) - s3c_hsotg_start_req(hs, hs_ep, hs_req, false); - - spin_unlock_irqrestore(&hs_ep->lock, irqflags); - - return 0; -} - -static void s3c_hsotg_ep_free_request(struct usb_ep *ep, - struct usb_request *req) -{ - struct s3c_hsotg_req *hs_req = our_req(req); - - kfree(hs_req); -} - -/** - * s3c_hsotg_complete_oursetup - setup completion callback - * @ep: The endpoint the request was on. - * @req: The request completed. - * - * Called on completion of any requests the driver itself - * submitted that need cleaning up. - */ -static void s3c_hsotg_complete_oursetup(struct usb_ep *ep, - struct usb_request *req) -{ - struct s3c_hsotg_ep *hs_ep = our_ep(ep); - struct s3c_hsotg *hsotg = hs_ep->parent; - - dev_dbg(hsotg->dev, "%s: ep %p, req %p\n", __func__, ep, req); - - s3c_hsotg_ep_free_request(ep, req); -} - -/** - * ep_from_windex - convert control wIndex value to endpoint - * @hsotg: The driver state. - * @windex: The control request wIndex field (in host order). - * - * Convert the given wIndex into a pointer to an driver endpoint - * structure, or return NULL if it is not a valid endpoint. -*/ -static struct s3c_hsotg_ep *ep_from_windex(struct s3c_hsotg *hsotg, - u32 windex) -{ - struct s3c_hsotg_ep *ep = &hsotg->eps[windex & 0x7F]; - int dir = (windex & USB_DIR_IN) ? 1 : 0; - int idx = windex & 0x7F; - - if (windex >= 0x100) - return NULL; - - if (idx > S3C_HSOTG_EPS) - return NULL; - - if (idx && ep->dir_in != dir) - return NULL; - - return ep; -} - -/** - * s3c_hsotg_send_reply - send reply to control request - * @hsotg: The device state - * @ep: Endpoint 0 - * @buff: Buffer for request - * @length: Length of reply. - * - * Create a request and queue it on the given endpoint. This is useful as - * an internal method of sending replies to certain control requests, etc. - */ -static int s3c_hsotg_send_reply(struct s3c_hsotg *hsotg, - struct s3c_hsotg_ep *ep, - void *buff, - int length) -{ - struct usb_request *req; - int ret; - - dev_dbg(hsotg->dev, "%s: buff %p, len %d\n", __func__, buff, length); - - req = s3c_hsotg_ep_alloc_request(&ep->ep, GFP_ATOMIC); - hsotg->ep0_reply = req; - if (!req) { - dev_warn(hsotg->dev, "%s: cannot alloc req\n", __func__); - return -ENOMEM; - } - - req->buf = hsotg->ep0_buff; - req->length = length; - req->zero = 1; /* always do zero-length final transfer */ - req->complete = s3c_hsotg_complete_oursetup; - - if (length) - memcpy(req->buf, buff, length); - else - ep->sent_zlp = 1; - - ret = s3c_hsotg_ep_queue(&ep->ep, req, GFP_ATOMIC); - if (ret) { - dev_warn(hsotg->dev, "%s: cannot queue req\n", __func__); - return ret; - } - - return 0; -} - -/** - * s3c_hsotg_process_req_status - process request GET_STATUS - * @hsotg: The device state - * @ctrl: USB control request - */ -static int s3c_hsotg_process_req_status(struct s3c_hsotg *hsotg, - struct usb_ctrlrequest *ctrl) -{ - struct s3c_hsotg_ep *ep0 = &hsotg->eps[0]; - struct s3c_hsotg_ep *ep; - __le16 reply; - int ret; - - dev_dbg(hsotg->dev, "%s: USB_REQ_GET_STATUS\n", __func__); - - if (!ep0->dir_in) { - dev_warn(hsotg->dev, "%s: direction out?\n", __func__); - return -EINVAL; - } - - switch (ctrl->bRequestType & USB_RECIP_MASK) { - case USB_RECIP_DEVICE: - reply = cpu_to_le16(0); /* bit 0 => self powered, - * bit 1 => remote wakeup */ - break; - - case USB_RECIP_INTERFACE: - /* currently, the data result should be zero */ - reply = cpu_to_le16(0); - break; - - case USB_RECIP_ENDPOINT: - ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex)); - if (!ep) - return -ENOENT; - - reply = cpu_to_le16(ep->halted ? 1 : 0); - break; - - default: - return 0; - } - - if (le16_to_cpu(ctrl->wLength) != 2) - return -EINVAL; - - ret = s3c_hsotg_send_reply(hsotg, ep0, &reply, 2); - if (ret) { - dev_err(hsotg->dev, "%s: failed to send reply\n", __func__); - return ret; - } - - return 1; -} - -static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value); - -/** - * get_ep_head - return the first request on the endpoint - * @hs_ep: The controller endpoint to get - * - * Get the first request on the endpoint. - */ -static struct s3c_hsotg_req *get_ep_head(struct s3c_hsotg_ep *hs_ep) -{ - if (list_empty(&hs_ep->queue)) - return NULL; - - return list_first_entry(&hs_ep->queue, struct s3c_hsotg_req, queue); -} - -/** - * s3c_hsotg_process_req_featire - process request {SET,CLEAR}_FEATURE - * @hsotg: The device state - * @ctrl: USB control request - */ -static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg, - struct usb_ctrlrequest *ctrl) -{ - struct s3c_hsotg_ep *ep0 = &hsotg->eps[0]; - struct s3c_hsotg_req *hs_req; - bool restart; - bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE); - struct s3c_hsotg_ep *ep; - int ret; - - dev_dbg(hsotg->dev, "%s: %s_FEATURE\n", - __func__, set ? "SET" : "CLEAR"); - - if (ctrl->bRequestType == USB_RECIP_ENDPOINT) { - ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex)); - if (!ep) { - dev_dbg(hsotg->dev, "%s: no endpoint for 0x%04x\n", - __func__, le16_to_cpu(ctrl->wIndex)); - return -ENOENT; - } - - switch (le16_to_cpu(ctrl->wValue)) { - case USB_ENDPOINT_HALT: - s3c_hsotg_ep_sethalt(&ep->ep, set); - - ret = s3c_hsotg_send_reply(hsotg, ep0, NULL, 0); - if (ret) { - dev_err(hsotg->dev, - "%s: failed to send reply\n", __func__); - return ret; - } - - if (!set) { - /* - * If we have request in progress, - * then complete it - */ - if (ep->req) { - hs_req = ep->req; - ep->req = NULL; - list_del_init(&hs_req->queue); - hs_req->req.complete(&ep->ep, - &hs_req->req); - } - - /* If we have pending request, then start it */ - restart = !list_empty(&ep->queue); - if (restart) { - hs_req = get_ep_head(ep); - s3c_hsotg_start_req(hsotg, ep, - hs_req, false); - } - } - - break; - - default: - return -ENOENT; - } - } else - return -ENOENT; /* currently only deal with endpoint */ - - return 1; -} - -/** - * s3c_hsotg_process_control - process a control request - * @hsotg: The device state - * @ctrl: The control request received - * - * The controller has received the SETUP phase of a control request, and - * needs to work out what to do next (and whether to pass it on to the - * gadget driver). - */ -static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg, - struct usb_ctrlrequest *ctrl) -{ - struct s3c_hsotg_ep *ep0 = &hsotg->eps[0]; - int ret = 0; - u32 dcfg; - - ep0->sent_zlp = 0; - - dev_dbg(hsotg->dev, "ctrl Req=%02x, Type=%02x, V=%04x, L=%04x\n", - ctrl->bRequest, ctrl->bRequestType, - ctrl->wValue, ctrl->wLength); - - /* record the direction of the request, for later use when enquing - * packets onto EP0. */ - - ep0->dir_in = (ctrl->bRequestType & USB_DIR_IN) ? 1 : 0; - dev_dbg(hsotg->dev, "ctrl: dir_in=%d\n", ep0->dir_in); - - /* if we've no data with this request, then the last part of the - * transaction is going to implicitly be IN. */ - if (ctrl->wLength == 0) - ep0->dir_in = 1; - - if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { - switch (ctrl->bRequest) { - case USB_REQ_SET_ADDRESS: - dcfg = readl(hsotg->regs + S3C_DCFG); - dcfg &= ~S3C_DCFG_DevAddr_MASK; - dcfg |= ctrl->wValue << S3C_DCFG_DevAddr_SHIFT; - writel(dcfg, hsotg->regs + S3C_DCFG); - - dev_info(hsotg->dev, "new address %d\n", ctrl->wValue); - - ret = s3c_hsotg_send_reply(hsotg, ep0, NULL, 0); - return; - - case USB_REQ_GET_STATUS: - ret = s3c_hsotg_process_req_status(hsotg, ctrl); - break; - - case USB_REQ_CLEAR_FEATURE: - case USB_REQ_SET_FEATURE: - ret = s3c_hsotg_process_req_feature(hsotg, ctrl); - break; - } - } - - /* as a fallback, try delivering it to the driver to deal with */ - - if (ret == 0 && hsotg->driver) { - ret = hsotg->driver->setup(&hsotg->gadget, ctrl); - if (ret < 0) - dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret); - } - - /* the request is either unhandlable, or is not formatted correctly - * so respond with a STALL for the status stage to indicate failure. - */ - - if (ret < 0) { - u32 reg; - u32 ctrl; - - dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in); - reg = (ep0->dir_in) ? S3C_DIEPCTL0 : S3C_DOEPCTL0; - - /* S3C_DxEPCTL_Stall will be cleared by EP once it has - * taken effect, so no need to clear later. */ - - ctrl = readl(hsotg->regs + reg); - ctrl |= S3C_DxEPCTL_Stall; - ctrl |= S3C_DxEPCTL_CNAK; - writel(ctrl, hsotg->regs + reg); - - dev_dbg(hsotg->dev, - "written DxEPCTL=0x%08x to %08x (DxEPCTL=0x%08x)\n", - ctrl, reg, readl(hsotg->regs + reg)); - - /* don't believe we need to anything more to get the EP - * to reply with a STALL packet */ - } -} - -static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg); - -/** - * s3c_hsotg_complete_setup - completion of a setup transfer - * @ep: The endpoint the request was on. - * @req: The request completed. - * - * Called on completion of any requests the driver itself submitted for - * EP0 setup packets - */ -static void s3c_hsotg_complete_setup(struct usb_ep *ep, - struct usb_request *req) -{ - struct s3c_hsotg_ep *hs_ep = our_ep(ep); - struct s3c_hsotg *hsotg = hs_ep->parent; - - if (req->status < 0) { - dev_dbg(hsotg->dev, "%s: failed %d\n", __func__, req->status); - return; - } - - if (req->actual == 0) - s3c_hsotg_enqueue_setup(hsotg); - else - s3c_hsotg_process_control(hsotg, req->buf); -} - -/** - * s3c_hsotg_enqueue_setup - start a request for EP0 packets - * @hsotg: The device state. - * - * Enqueue a request on EP0 if necessary to received any SETUP packets - * received from the host. - */ -static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg) -{ - struct usb_request *req = hsotg->ctrl_req; - struct s3c_hsotg_req *hs_req = our_req(req); - int ret; - - dev_dbg(hsotg->dev, "%s: queueing setup request\n", __func__); - - req->zero = 0; - req->length = 8; - req->buf = hsotg->ctrl_buff; - req->complete = s3c_hsotg_complete_setup; - - if (!list_empty(&hs_req->queue)) { - dev_dbg(hsotg->dev, "%s already queued???\n", __func__); - return; - } - - hsotg->eps[0].dir_in = 0; - - ret = s3c_hsotg_ep_queue(&hsotg->eps[0].ep, req, GFP_ATOMIC); - if (ret < 0) { - dev_err(hsotg->dev, "%s: failed queue (%d)\n", __func__, ret); - /* Don't think there's much we can do other than watch the - * driver fail. */ - } -} - -/** - * s3c_hsotg_complete_request - complete a request given to us - * @hsotg: The device state. - * @hs_ep: The endpoint the request was on. - * @hs_req: The request to complete. - * @result: The result code (0 => Ok, otherwise errno) - * - * The given request has finished, so call the necessary completion - * if it has one and then look to see if we can start a new request - * on the endpoint. - * - * Note, expects the ep to already be locked as appropriate. -*/ -static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg, - struct s3c_hsotg_ep *hs_ep, - struct s3c_hsotg_req *hs_req, - int result) -{ - bool restart; - - if (!hs_req) { - dev_dbg(hsotg->dev, "%s: nothing to complete?\n", __func__); - return; - } - - dev_dbg(hsotg->dev, "complete: ep %p %s, req %p, %d => %p\n", - hs_ep, hs_ep->ep.name, hs_req, result, hs_req->req.complete); - - /* only replace the status if we've not already set an error - * from a previous transaction */ - - if (hs_req->req.status == -EINPROGRESS) - hs_req->req.status = result; - - hs_ep->req = NULL; - list_del_init(&hs_req->queue); - - if (using_dma(hsotg)) - s3c_hsotg_unmap_dma(hsotg, hs_ep, hs_req); - - /* call the complete request with the locks off, just in case the - * request tries to queue more work for this endpoint. */ - - if (hs_req->req.complete) { - spin_unlock(&hs_ep->lock); - hs_req->req.complete(&hs_ep->ep, &hs_req->req); - spin_lock(&hs_ep->lock); - } - - /* Look to see if there is anything else to do. Note, the completion - * of the previous request may have caused a new request to be started - * so be careful when doing this. */ - - if (!hs_ep->req && result >= 0) { - restart = !list_empty(&hs_ep->queue); - if (restart) { - hs_req = get_ep_head(hs_ep); - s3c_hsotg_start_req(hsotg, hs_ep, hs_req, false); - } - } -} - -/** - * s3c_hsotg_complete_request_lock - complete a request given to us (locked) - * @hsotg: The device state. - * @hs_ep: The endpoint the request was on. - * @hs_req: The request to complete. - * @result: The result code (0 => Ok, otherwise errno) - * - * See s3c_hsotg_complete_request(), but called with the endpoint's - * lock held. -*/ -static void s3c_hsotg_complete_request_lock(struct s3c_hsotg *hsotg, - struct s3c_hsotg_ep *hs_ep, - struct s3c_hsotg_req *hs_req, - int result) -{ - unsigned long flags; - - spin_lock_irqsave(&hs_ep->lock, flags); - s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, result); - spin_unlock_irqrestore(&hs_ep->lock, flags); -} - -/** - * s3c_hsotg_rx_data - receive data from the FIFO for an endpoint - * @hsotg: The device state. - * @ep_idx: The endpoint index for the data - * @size: The size of data in the fifo, in bytes - * - * The FIFO status shows there is data to read from the FIFO for a given - * endpoint, so sort out whether we need to read the data into a request - * that has been made for that endpoint. - */ -static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size) -{ - struct s3c_hsotg_ep *hs_ep = &hsotg->eps[ep_idx]; - struct s3c_hsotg_req *hs_req = hs_ep->req; - void __iomem *fifo = hsotg->regs + S3C_EPFIFO(ep_idx); - int to_read; - int max_req; - int read_ptr; - - if (!hs_req) { - u32 epctl = readl(hsotg->regs + S3C_DOEPCTL(ep_idx)); - int ptr; - - dev_warn(hsotg->dev, - "%s: FIFO %d bytes on ep%d but no req (DxEPCTl=0x%08x)\n", - __func__, size, ep_idx, epctl); - - /* dump the data from the FIFO, we've nothing we can do */ - for (ptr = 0; ptr < size; ptr += 4) - (void)readl(fifo); - - return; - } - - spin_lock(&hs_ep->lock); - - to_read = size; - read_ptr = hs_req->req.actual; - max_req = hs_req->req.length - read_ptr; - - dev_dbg(hsotg->dev, "%s: read %d/%d, done %d/%d\n", - __func__, to_read, max_req, read_ptr, hs_req->req.length); - - if (to_read > max_req) { - /* more data appeared than we where willing - * to deal with in this request. - */ - - /* currently we don't deal this */ - WARN_ON_ONCE(1); - } - - hs_ep->total_data += to_read; - hs_req->req.actual += to_read; - to_read = DIV_ROUND_UP(to_read, 4); - - /* note, we might over-write the buffer end by 3 bytes depending on - * alignment of the data. */ - readsl(fifo, hs_req->req.buf + read_ptr, to_read); - - spin_unlock(&hs_ep->lock); -} - -/** - * s3c_hsotg_send_zlp - send zero-length packet on control endpoint - * @hsotg: The device instance - * @req: The request currently on this endpoint - * - * Generate a zero-length IN packet request for terminating a SETUP - * transaction. - * - * Note, since we don't write any data to the TxFIFO, then it is - * currently believed that we do not need to wait for any space in - * the TxFIFO. - */ -static void s3c_hsotg_send_zlp(struct s3c_hsotg *hsotg, - struct s3c_hsotg_req *req) -{ - u32 ctrl; - - if (!req) { - dev_warn(hsotg->dev, "%s: no request?\n", __func__); - return; - } - - if (req->req.length == 0) { - hsotg->eps[0].sent_zlp = 1; - s3c_hsotg_enqueue_setup(hsotg); - return; - } - - hsotg->eps[0].dir_in = 1; - hsotg->eps[0].sent_zlp = 1; - - dev_dbg(hsotg->dev, "sending zero-length packet\n"); - - /* issue a zero-sized packet to terminate this */ - writel(S3C_DxEPTSIZ_MC(1) | S3C_DxEPTSIZ_PktCnt(1) | - S3C_DxEPTSIZ_XferSize(0), hsotg->regs + S3C_DIEPTSIZ(0)); - - ctrl = readl(hsotg->regs + S3C_DIEPCTL0); - ctrl |= S3C_DxEPCTL_CNAK; /* clear NAK set by core */ - ctrl |= S3C_DxEPCTL_EPEna; /* ensure ep enabled */ - ctrl |= S3C_DxEPCTL_USBActEp; - writel(ctrl, hsotg->regs + S3C_DIEPCTL0); -} - -/** - * s3c_hsotg_handle_outdone - handle receiving OutDone/SetupDone from RXFIFO - * @hsotg: The device instance - * @epnum: The endpoint received from - * @was_setup: Set if processing a SetupDone event. - * - * The RXFIFO has delivered an OutDone event, which means that the data - * transfer for an OUT endpoint has been completed, either by a short - * packet or by the finish of a transfer. -*/ -static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg, - int epnum, bool was_setup) -{ - u32 epsize = readl(hsotg->regs + S3C_DOEPTSIZ(epnum)); - struct s3c_hsotg_ep *hs_ep = &hsotg->eps[epnum]; - struct s3c_hsotg_req *hs_req = hs_ep->req; - struct usb_request *req = &hs_req->req; - unsigned size_left = S3C_DxEPTSIZ_XferSize_GET(epsize); - int result = 0; - - if (!hs_req) { - dev_dbg(hsotg->dev, "%s: no request active\n", __func__); - return; - } - - if (using_dma(hsotg)) { - unsigned size_done; - - /* Calculate the size of the transfer by checking how much - * is left in the endpoint size register and then working it - * out from the amount we loaded for the transfer. - * - * We need to do this as DMA pointers are always 32bit aligned - * so may overshoot/undershoot the transfer. - */ - - size_done = hs_ep->size_loaded - size_left; - size_done += hs_ep->last_load; - - req->actual = size_done; - } - - /* if there is more request to do, schedule new transfer */ - if (req->actual < req->length && size_left == 0) { - s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true); - return; - } - - if (req->actual < req->length && req->short_not_ok) { - dev_dbg(hsotg->dev, "%s: got %d/%d (short not ok) => error\n", - __func__, req->actual, req->length); - - /* todo - what should we return here? there's no one else - * even bothering to check the status. */ - } - - if (epnum == 0) { - if (!was_setup && req->complete != s3c_hsotg_complete_setup) - s3c_hsotg_send_zlp(hsotg, hs_req); - } - - s3c_hsotg_complete_request_lock(hsotg, hs_ep, hs_req, result); -} - -/** - * s3c_hsotg_read_frameno - read current frame number - * @hsotg: The device instance - * - * Return the current frame number -*/ -static u32 s3c_hsotg_read_frameno(struct s3c_hsotg *hsotg) -{ - u32 dsts; - - dsts = readl(hsotg->regs + S3C_DSTS); - dsts &= S3C_DSTS_SOFFN_MASK; - dsts >>= S3C_DSTS_SOFFN_SHIFT; - - return dsts; -} - -/** - * s3c_hsotg_handle_rx - RX FIFO has data - * @hsotg: The device instance - * - * The IRQ handler has detected that the RX FIFO has some data in it - * that requires processing, so find out what is in there and do the - * appropriate read. - * - * The RXFIFO is a true FIFO, the packets coming out are still in packet - * chunks, so if you have x packets received on an endpoint you'll get x - * FIFO events delivered, each with a packet's worth of data in it. - * - * When using DMA, we should not be processing events from the RXFIFO - * as the actual data should be sent to the memory directly and we turn - * on the completion interrupts to get notifications of transfer completion. - */ -static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg) -{ - u32 grxstsr = readl(hsotg->regs + S3C_GRXSTSP); - u32 epnum, status, size; - - WARN_ON(using_dma(hsotg)); - - epnum = grxstsr & S3C_GRXSTS_EPNum_MASK; - status = grxstsr & S3C_GRXSTS_PktSts_MASK; - - size = grxstsr & S3C_GRXSTS_ByteCnt_MASK; - size >>= S3C_GRXSTS_ByteCnt_SHIFT; - - if (1) - dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n", - __func__, grxstsr, size, epnum); - -#define __status(x) ((x) >> S3C_GRXSTS_PktSts_SHIFT) - - switch (status >> S3C_GRXSTS_PktSts_SHIFT) { - case __status(S3C_GRXSTS_PktSts_GlobalOutNAK): - dev_dbg(hsotg->dev, "GlobalOutNAK\n"); - break; - - case __status(S3C_GRXSTS_PktSts_OutDone): - dev_dbg(hsotg->dev, "OutDone (Frame=0x%08x)\n", - s3c_hsotg_read_frameno(hsotg)); - - if (!using_dma(hsotg)) - s3c_hsotg_handle_outdone(hsotg, epnum, false); - break; - - case __status(S3C_GRXSTS_PktSts_SetupDone): - dev_dbg(hsotg->dev, - "SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n", - s3c_hsotg_read_frameno(hsotg), - readl(hsotg->regs + S3C_DOEPCTL(0))); - - s3c_hsotg_handle_outdone(hsotg, epnum, true); - break; - - case __status(S3C_GRXSTS_PktSts_OutRX): - s3c_hsotg_rx_data(hsotg, epnum, size); - break; - - case __status(S3C_GRXSTS_PktSts_SetupRX): - dev_dbg(hsotg->dev, - "SetupRX (Frame=0x%08x, DOPEPCTL=0x%08x)\n", - s3c_hsotg_read_frameno(hsotg), - readl(hsotg->regs + S3C_DOEPCTL(0))); - - s3c_hsotg_rx_data(hsotg, epnum, size); - break; - - default: - dev_warn(hsotg->dev, "%s: unknown status %08x\n", - __func__, grxstsr); - - s3c_hsotg_dump(hsotg); - break; - } -} - -/** - * s3c_hsotg_ep0_mps - turn max packet size into register setting - * @mps: The maximum packet size in bytes. -*/ -static u32 s3c_hsotg_ep0_mps(unsigned int mps) -{ - switch (mps) { - case 64: - return S3C_D0EPCTL_MPS_64; - case 32: - return S3C_D0EPCTL_MPS_32; - case 16: - return S3C_D0EPCTL_MPS_16; - case 8: - return S3C_D0EPCTL_MPS_8; - } - - /* bad max packet size, warn and return invalid result */ - WARN_ON(1); - return (u32)-1; -} - -/** - * s3c_hsotg_set_ep_maxpacket - set endpoint's max-packet field - * @hsotg: The driver state. - * @ep: The index number of the endpoint - * @mps: The maximum packet size in bytes - * - * Configure the maximum packet size for the given endpoint, updating - * the hardware control registers to reflect this. - */ -static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg, - unsigned int ep, unsigned int mps) -{ - struct s3c_hsotg_ep *hs_ep = &hsotg->eps[ep]; - void __iomem *regs = hsotg->regs; - u32 mpsval; - u32 reg; - - if (ep == 0) { - /* EP0 is a special case */ - mpsval = s3c_hsotg_ep0_mps(mps); - if (mpsval > 3) - goto bad_mps; - } else { - if (mps >= S3C_DxEPCTL_MPS_LIMIT+1) - goto bad_mps; - - mpsval = mps; - } - - hs_ep->ep.maxpacket = mps; - - /* update both the in and out endpoint controldir_ registers, even - * if one of the directions may not be in use. */ - - reg = readl(regs + S3C_DIEPCTL(ep)); - reg &= ~S3C_DxEPCTL_MPS_MASK; - reg |= mpsval; - writel(reg, regs + S3C_DIEPCTL(ep)); - - if (ep) { - reg = readl(regs + S3C_DOEPCTL(ep)); - reg &= ~S3C_DxEPCTL_MPS_MASK; - reg |= mpsval; - writel(reg, regs + S3C_DOEPCTL(ep)); - } - - return; - -bad_mps: - dev_err(hsotg->dev, "ep%d: bad mps of %d\n", ep, mps); -} - -/** - * s3c_hsotg_txfifo_flush - flush Tx FIFO - * @hsotg: The driver state - * @idx: The index for the endpoint (0..15) - */ -static void s3c_hsotg_txfifo_flush(struct s3c_hsotg *hsotg, unsigned int idx) -{ - int timeout; - int val; - - writel(S3C_GRSTCTL_TxFNum(idx) | S3C_GRSTCTL_TxFFlsh, - hsotg->regs + S3C_GRSTCTL); - - /* wait until the fifo is flushed */ - timeout = 100; - - while (1) { - val = readl(hsotg->regs + S3C_GRSTCTL); - - if ((val & (S3C_GRSTCTL_TxFFlsh)) == 0) - break; - - if (--timeout == 0) { - dev_err(hsotg->dev, - "%s: timeout flushing fifo (GRSTCTL=%08x)\n", - __func__, val); - } - - udelay(1); - } -} - -/** - * s3c_hsotg_trytx - check to see if anything needs transmitting - * @hsotg: The driver state - * @hs_ep: The driver endpoint to check. - * - * Check to see if there is a request that has data to send, and if so - * make an attempt to write data into the FIFO. - */ -static int s3c_hsotg_trytx(struct s3c_hsotg *hsotg, - struct s3c_hsotg_ep *hs_ep) -{ - struct s3c_hsotg_req *hs_req = hs_ep->req; - - if (!hs_ep->dir_in || !hs_req) - return 0; - - if (hs_req->req.actual < hs_req->req.length) { - dev_dbg(hsotg->dev, "trying to write more for ep%d\n", - hs_ep->index); - return s3c_hsotg_write_fifo(hsotg, hs_ep, hs_req); - } - - return 0; -} - -/** - * s3c_hsotg_complete_in - complete IN transfer - * @hsotg: The device state. - * @hs_ep: The endpoint that has just completed. - * - * An IN transfer has been completed, update the transfer's state and then - * call the relevant completion routines. - */ -static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg, - struct s3c_hsotg_ep *hs_ep) -{ - struct s3c_hsotg_req *hs_req = hs_ep->req; - u32 epsize = readl(hsotg->regs + S3C_DIEPTSIZ(hs_ep->index)); - int size_left, size_done; - - if (!hs_req) { - dev_dbg(hsotg->dev, "XferCompl but no req\n"); - return; - } - - /* Calculate the size of the transfer by checking how much is left - * in the endpoint size register and then working it out from - * the amount we loaded for the transfer. - * - * We do this even for DMA, as the transfer may have incremented - * past the end of the buffer (DMA transfers are always 32bit - * aligned). - */ - - size_left = S3C_DxEPTSIZ_XferSize_GET(epsize); - - size_done = hs_ep->size_loaded - size_left; - size_done += hs_ep->last_load; - - if (hs_req->req.actual != size_done) - dev_dbg(hsotg->dev, "%s: adjusting size done %d => %d\n", - __func__, hs_req->req.actual, size_done); - - hs_req->req.actual = size_done; - - /* if we did all of the transfer, and there is more data left - * around, then try restarting the rest of the request */ - - if (!size_left && hs_req->req.actual < hs_req->req.length) { - dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__); - s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true); - } else - s3c_hsotg_complete_request_lock(hsotg, hs_ep, hs_req, 0); -} - -/** - * s3c_hsotg_epint - handle an in/out endpoint interrupt - * @hsotg: The driver state - * @idx: The index for the endpoint (0..15) - * @dir_in: Set if this is an IN endpoint - * - * Process and clear any interrupt pending for an individual endpoint -*/ -static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, - int dir_in) -{ - struct s3c_hsotg_ep *hs_ep = &hsotg->eps[idx]; - u32 epint_reg = dir_in ? S3C_DIEPINT(idx) : S3C_DOEPINT(idx); - u32 epctl_reg = dir_in ? S3C_DIEPCTL(idx) : S3C_DOEPCTL(idx); - u32 epsiz_reg = dir_in ? S3C_DIEPTSIZ(idx) : S3C_DOEPTSIZ(idx); - u32 ints; - - ints = readl(hsotg->regs + epint_reg); - - /* Clear endpoint interrupts */ - writel(ints, hsotg->regs + epint_reg); - - dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n", - __func__, idx, dir_in ? "in" : "out", ints); - - if (ints & S3C_DxEPINT_XferCompl) { - dev_dbg(hsotg->dev, - "%s: XferCompl: DxEPCTL=0x%08x, DxEPTSIZ=%08x\n", - __func__, readl(hsotg->regs + epctl_reg), - readl(hsotg->regs + epsiz_reg)); - - /* we get OutDone from the FIFO, so we only need to look - * at completing IN requests here */ - if (dir_in) { - s3c_hsotg_complete_in(hsotg, hs_ep); - - if (idx == 0 && !hs_ep->req) - s3c_hsotg_enqueue_setup(hsotg); - } else if (using_dma(hsotg)) { - /* We're using DMA, we need to fire an OutDone here - * as we ignore the RXFIFO. */ - - s3c_hsotg_handle_outdone(hsotg, idx, false); - } - } - - if (ints & S3C_DxEPINT_EPDisbld) { - dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__); - - if (dir_in) { - int epctl = readl(hsotg->regs + epctl_reg); - - s3c_hsotg_txfifo_flush(hsotg, idx); - - if ((epctl & S3C_DxEPCTL_Stall) && - (epctl & S3C_DxEPCTL_EPType_Bulk)) { - int dctl = readl(hsotg->regs + S3C_DCTL); - - dctl |= S3C_DCTL_CGNPInNAK; - writel(dctl, hsotg->regs + S3C_DCTL); - } - } - } - - if (ints & S3C_DxEPINT_AHBErr) - dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__); - - if (ints & S3C_DxEPINT_Setup) { /* Setup or Timeout */ - dev_dbg(hsotg->dev, "%s: Setup/Timeout\n", __func__); - - if (using_dma(hsotg) && idx == 0) { - /* this is the notification we've received a - * setup packet. In non-DMA mode we'd get this - * from the RXFIFO, instead we need to process - * the setup here. */ - - if (dir_in) - WARN_ON_ONCE(1); - else - s3c_hsotg_handle_outdone(hsotg, 0, true); - } - } - - if (ints & S3C_DxEPINT_Back2BackSetup) - dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__); - - if (dir_in) { - /* not sure if this is important, but we'll clear it anyway - */ - if (ints & S3C_DIEPMSK_INTknTXFEmpMsk) { - dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n", - __func__, idx); - } - - /* this probably means something bad is happening */ - if (ints & S3C_DIEPMSK_INTknEPMisMsk) { - dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n", - __func__, idx); - } - - /* FIFO has space or is empty (see GAHBCFG) */ - if (hsotg->dedicated_fifos && - ints & S3C_DIEPMSK_TxFIFOEmpty) { - dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n", - __func__, idx); - if (!using_dma(hsotg)) - s3c_hsotg_trytx(hsotg, hs_ep); - } - } -} - -/** - * s3c_hsotg_irq_enumdone - Handle EnumDone interrupt (enumeration done) - * @hsotg: The device state. - * - * Handle updating the device settings after the enumeration phase has - * been completed. -*/ -static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg) -{ - u32 dsts = readl(hsotg->regs + S3C_DSTS); - int ep0_mps = 0, ep_mps; - - /* This should signal the finish of the enumeration phase - * of the USB handshaking, so we should now know what rate - * we connected at. */ - - dev_dbg(hsotg->dev, "EnumDone (DSTS=0x%08x)\n", dsts); - - /* note, since we're limited by the size of transfer on EP0, and - * it seems IN transfers must be a even number of packets we do - * not advertise a 64byte MPS on EP0. */ - - /* catch both EnumSpd_FS and EnumSpd_FS48 */ - switch (dsts & S3C_DSTS_EnumSpd_MASK) { - case S3C_DSTS_EnumSpd_FS: - case S3C_DSTS_EnumSpd_FS48: - hsotg->gadget.speed = USB_SPEED_FULL; - ep0_mps = EP0_MPS_LIMIT; - ep_mps = 64; - break; - - case S3C_DSTS_EnumSpd_HS: - hsotg->gadget.speed = USB_SPEED_HIGH; - ep0_mps = EP0_MPS_LIMIT; - ep_mps = 512; - break; - - case S3C_DSTS_EnumSpd_LS: - hsotg->gadget.speed = USB_SPEED_LOW; - /* note, we don't actually support LS in this driver at the - * moment, and the documentation seems to imply that it isn't - * supported by the PHYs on some of the devices. - */ - break; - } - dev_info(hsotg->dev, "new device is %s\n", - usb_speed_string(hsotg->gadget.speed)); - - /* we should now know the maximum packet size for an - * endpoint, so set the endpoints to a default value. */ - - if (ep0_mps) { - int i; - s3c_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps); - for (i = 1; i < S3C_HSOTG_EPS; i++) - s3c_hsotg_set_ep_maxpacket(hsotg, i, ep_mps); - } - - /* ensure after enumeration our EP0 is active */ - - s3c_hsotg_enqueue_setup(hsotg); - - dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", - readl(hsotg->regs + S3C_DIEPCTL0), - readl(hsotg->regs + S3C_DOEPCTL0)); -} - -/** - * kill_all_requests - remove all requests from the endpoint's queue - * @hsotg: The device state. - * @ep: The endpoint the requests may be on. - * @result: The result code to use. - * @force: Force removal of any current requests - * - * Go through the requests on the given endpoint and mark them - * completed with the given result code. - */ -static void kill_all_requests(struct s3c_hsotg *hsotg, - struct s3c_hsotg_ep *ep, - int result, bool force) -{ - struct s3c_hsotg_req *req, *treq; - unsigned long flags; - - spin_lock_irqsave(&ep->lock, flags); - - list_for_each_entry_safe(req, treq, &ep->queue, queue) { - /* currently, we can't do much about an already - * running request on an in endpoint */ - - if (ep->req == req && ep->dir_in && !force) - continue; - - s3c_hsotg_complete_request(hsotg, ep, req, - result); - } - - spin_unlock_irqrestore(&ep->lock, flags); -} - -#define call_gadget(_hs, _entry) \ - if ((_hs)->gadget.speed != USB_SPEED_UNKNOWN && \ - (_hs)->driver && (_hs)->driver->_entry) \ - (_hs)->driver->_entry(&(_hs)->gadget); - -/** - * s3c_hsotg_disconnect_irq - disconnect irq service - * @hsotg: The device state. - * - * A disconnect IRQ has been received, meaning that the host has - * lost contact with the bus. Remove all current transactions - * and signal the gadget driver that this has happened. -*/ -static void s3c_hsotg_disconnect_irq(struct s3c_hsotg *hsotg) -{ - unsigned ep; - - for (ep = 0; ep < S3C_HSOTG_EPS; ep++) - kill_all_requests(hsotg, &hsotg->eps[ep], -ESHUTDOWN, true); - - call_gadget(hsotg, disconnect); -} - -/** - * s3c_hsotg_irq_fifoempty - TX FIFO empty interrupt handler - * @hsotg: The device state: - * @periodic: True if this is a periodic FIFO interrupt - */ -static void s3c_hsotg_irq_fifoempty(struct s3c_hsotg *hsotg, bool periodic) -{ - struct s3c_hsotg_ep *ep; - int epno, ret; - - /* look through for any more data to transmit */ - - for (epno = 0; epno < S3C_HSOTG_EPS; epno++) { - ep = &hsotg->eps[epno]; - - if (!ep->dir_in) - continue; - - if ((periodic && !ep->periodic) || - (!periodic && ep->periodic)) - continue; - - ret = s3c_hsotg_trytx(hsotg, ep); - if (ret < 0) - break; - } -} - -static struct s3c_hsotg *our_hsotg; - -/* IRQ flags which will trigger a retry around the IRQ loop */ -#define IRQ_RETRY_MASK (S3C_GINTSTS_NPTxFEmp | \ - S3C_GINTSTS_PTxFEmp | \ - S3C_GINTSTS_RxFLvl) - -/** - * s3c_hsotg_irq - handle device interrupt - * @irq: The IRQ number triggered - * @pw: The pw value when registered the handler. - */ -static irqreturn_t s3c_hsotg_irq(int irq, void *pw) -{ - struct s3c_hsotg *hsotg = pw; - int retry_count = 8; - u32 gintsts; - u32 gintmsk; - -irq_retry: - gintsts = readl(hsotg->regs + S3C_GINTSTS); - gintmsk = readl(hsotg->regs + S3C_GINTMSK); - - dev_dbg(hsotg->dev, "%s: %08x %08x (%08x) retry %d\n", - __func__, gintsts, gintsts & gintmsk, gintmsk, retry_count); - - gintsts &= gintmsk; - - if (gintsts & S3C_GINTSTS_OTGInt) { - u32 otgint = readl(hsotg->regs + S3C_GOTGINT); - - dev_info(hsotg->dev, "OTGInt: %08x\n", otgint); - - writel(otgint, hsotg->regs + S3C_GOTGINT); - } - - if (gintsts & S3C_GINTSTS_DisconnInt) { - dev_dbg(hsotg->dev, "%s: DisconnInt\n", __func__); - writel(S3C_GINTSTS_DisconnInt, hsotg->regs + S3C_GINTSTS); - - s3c_hsotg_disconnect_irq(hsotg); - } - - if (gintsts & S3C_GINTSTS_SessReqInt) { - dev_dbg(hsotg->dev, "%s: SessReqInt\n", __func__); - writel(S3C_GINTSTS_SessReqInt, hsotg->regs + S3C_GINTSTS); - } - - if (gintsts & S3C_GINTSTS_EnumDone) { - writel(S3C_GINTSTS_EnumDone, hsotg->regs + S3C_GINTSTS); - - s3c_hsotg_irq_enumdone(hsotg); - } - - if (gintsts & S3C_GINTSTS_ConIDStsChng) { - dev_dbg(hsotg->dev, "ConIDStsChg (DSTS=0x%08x, GOTCTL=%08x)\n", - readl(hsotg->regs + S3C_DSTS), - readl(hsotg->regs + S3C_GOTGCTL)); - - writel(S3C_GINTSTS_ConIDStsChng, hsotg->regs + S3C_GINTSTS); - } - - if (gintsts & (S3C_GINTSTS_OEPInt | S3C_GINTSTS_IEPInt)) { - u32 daint = readl(hsotg->regs + S3C_DAINT); - u32 daint_out = daint >> S3C_DAINT_OutEP_SHIFT; - u32 daint_in = daint & ~(daint_out << S3C_DAINT_OutEP_SHIFT); - int ep; - - dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint); - - for (ep = 0; ep < 15 && daint_out; ep++, daint_out >>= 1) { - if (daint_out & 1) - s3c_hsotg_epint(hsotg, ep, 0); - } - - for (ep = 0; ep < 15 && daint_in; ep++, daint_in >>= 1) { - if (daint_in & 1) - s3c_hsotg_epint(hsotg, ep, 1); - } - } - - if (gintsts & S3C_GINTSTS_USBRst) { - dev_info(hsotg->dev, "%s: USBRst\n", __func__); - dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n", - readl(hsotg->regs + S3C_GNPTXSTS)); - - writel(S3C_GINTSTS_USBRst, hsotg->regs + S3C_GINTSTS); - - kill_all_requests(hsotg, &hsotg->eps[0], -ECONNRESET, true); - - /* it seems after a reset we can end up with a situation - * where the TXFIFO still has data in it... the docs - * suggest resetting all the fifos, so use the init_fifo - * code to relayout and flush the fifos. - */ - - s3c_hsotg_init_fifo(hsotg); - - s3c_hsotg_enqueue_setup(hsotg); - } - - /* check both FIFOs */ - - if (gintsts & S3C_GINTSTS_NPTxFEmp) { - dev_dbg(hsotg->dev, "NPTxFEmp\n"); - - /* Disable the interrupt to stop it happening again - * unless one of these endpoint routines decides that - * it needs re-enabling */ - - s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_NPTxFEmp); - s3c_hsotg_irq_fifoempty(hsotg, false); - } - - if (gintsts & S3C_GINTSTS_PTxFEmp) { - dev_dbg(hsotg->dev, "PTxFEmp\n"); - - /* See note in S3C_GINTSTS_NPTxFEmp */ - - s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_PTxFEmp); - s3c_hsotg_irq_fifoempty(hsotg, true); - } - - if (gintsts & S3C_GINTSTS_RxFLvl) { - /* note, since GINTSTS_RxFLvl doubles as FIFO-not-empty, - * we need to retry s3c_hsotg_handle_rx if this is still - * set. */ - - s3c_hsotg_handle_rx(hsotg); - } - - if (gintsts & S3C_GINTSTS_ModeMis) { - dev_warn(hsotg->dev, "warning, mode mismatch triggered\n"); - writel(S3C_GINTSTS_ModeMis, hsotg->regs + S3C_GINTSTS); - } - - if (gintsts & S3C_GINTSTS_USBSusp) { - dev_info(hsotg->dev, "S3C_GINTSTS_USBSusp\n"); - writel(S3C_GINTSTS_USBSusp, hsotg->regs + S3C_GINTSTS); - - call_gadget(hsotg, suspend); - } - - if (gintsts & S3C_GINTSTS_WkUpInt) { - dev_info(hsotg->dev, "S3C_GINTSTS_WkUpIn\n"); - writel(S3C_GINTSTS_WkUpInt, hsotg->regs + S3C_GINTSTS); - - call_gadget(hsotg, resume); - } - - if (gintsts & S3C_GINTSTS_ErlySusp) { - dev_dbg(hsotg->dev, "S3C_GINTSTS_ErlySusp\n"); - writel(S3C_GINTSTS_ErlySusp, hsotg->regs + S3C_GINTSTS); - } - - /* these next two seem to crop-up occasionally causing the core - * to shutdown the USB transfer, so try clearing them and logging - * the occurrence. */ - - if (gintsts & S3C_GINTSTS_GOUTNakEff) { - dev_info(hsotg->dev, "GOUTNakEff triggered\n"); - - writel(S3C_DCTL_CGOUTNak, hsotg->regs + S3C_DCTL); - - s3c_hsotg_dump(hsotg); - } - - if (gintsts & S3C_GINTSTS_GINNakEff) { - dev_info(hsotg->dev, "GINNakEff triggered\n"); - - writel(S3C_DCTL_CGNPInNAK, hsotg->regs + S3C_DCTL); - - s3c_hsotg_dump(hsotg); - } - - /* if we've had fifo events, we should try and go around the - * loop again to see if there's any point in returning yet. */ - - if (gintsts & IRQ_RETRY_MASK && --retry_count > 0) - goto irq_retry; - - return IRQ_HANDLED; -} - -/** - * s3c_hsotg_ep_enable - enable the given endpoint - * @ep: The USB endpint to configure - * @desc: The USB endpoint descriptor to configure with. - * - * This is called from the USB gadget code's usb_ep_enable(). -*/ -static int s3c_hsotg_ep_enable(struct usb_ep *ep, - const struct usb_endpoint_descriptor *desc) -{ - struct s3c_hsotg_ep *hs_ep = our_ep(ep); - struct s3c_hsotg *hsotg = hs_ep->parent; - unsigned long flags; - int index = hs_ep->index; - u32 epctrl_reg; - u32 epctrl; - u32 mps; - int dir_in; - int ret = 0; - - dev_dbg(hsotg->dev, - "%s: ep %s: a 0x%02x, attr 0x%02x, mps 0x%04x, intr %d\n", - __func__, ep->name, desc->bEndpointAddress, desc->bmAttributes, - desc->wMaxPacketSize, desc->bInterval); - - /* not to be called for EP0 */ - WARN_ON(index == 0); - - dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0; - if (dir_in != hs_ep->dir_in) { - dev_err(hsotg->dev, "%s: direction mismatch!\n", __func__); - return -EINVAL; - } - - mps = usb_endpoint_maxp(desc); - - /* note, we handle this here instead of s3c_hsotg_set_ep_maxpacket */ - - epctrl_reg = dir_in ? S3C_DIEPCTL(index) : S3C_DOEPCTL(index); - epctrl = readl(hsotg->regs + epctrl_reg); - - dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n", - __func__, epctrl, epctrl_reg); - - spin_lock_irqsave(&hs_ep->lock, flags); - - epctrl &= ~(S3C_DxEPCTL_EPType_MASK | S3C_DxEPCTL_MPS_MASK); - epctrl |= S3C_DxEPCTL_MPS(mps); - - /* mark the endpoint as active, otherwise the core may ignore - * transactions entirely for this endpoint */ - epctrl |= S3C_DxEPCTL_USBActEp; - - /* set the NAK status on the endpoint, otherwise we might try and - * do something with data that we've yet got a request to process - * since the RXFIFO will take data for an endpoint even if the - * size register hasn't been set. - */ - - epctrl |= S3C_DxEPCTL_SNAK; - - /* update the endpoint state */ - hs_ep->ep.maxpacket = mps; - - /* default, set to non-periodic */ - hs_ep->periodic = 0; - - switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { - case USB_ENDPOINT_XFER_ISOC: - dev_err(hsotg->dev, "no current ISOC support\n"); - ret = -EINVAL; - goto out; - - case USB_ENDPOINT_XFER_BULK: - epctrl |= S3C_DxEPCTL_EPType_Bulk; - break; - - case USB_ENDPOINT_XFER_INT: - if (dir_in) { - /* Allocate our TxFNum by simply using the index - * of the endpoint for the moment. We could do - * something better if the host indicates how - * many FIFOs we are expecting to use. */ - - hs_ep->periodic = 1; - epctrl |= S3C_DxEPCTL_TxFNum(index); - } - - epctrl |= S3C_DxEPCTL_EPType_Intterupt; - break; - - case USB_ENDPOINT_XFER_CONTROL: - epctrl |= S3C_DxEPCTL_EPType_Control; - break; - } - - /* if the hardware has dedicated fifos, we must give each IN EP - * a unique tx-fifo even if it is non-periodic. - */ - if (dir_in && hsotg->dedicated_fifos) - epctrl |= S3C_DxEPCTL_TxFNum(index); - - /* for non control endpoints, set PID to D0 */ - if (index) - epctrl |= S3C_DxEPCTL_SetD0PID; - - dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n", - __func__, epctrl); - - writel(epctrl, hsotg->regs + epctrl_reg); - dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x\n", - __func__, readl(hsotg->regs + epctrl_reg)); - - /* enable the endpoint interrupt */ - s3c_hsotg_ctrl_epint(hsotg, index, dir_in, 1); - -out: - spin_unlock_irqrestore(&hs_ep->lock, flags); - return ret; -} - -static int s3c_hsotg_ep_disable(struct usb_ep *ep) -{ - struct s3c_hsotg_ep *hs_ep = our_ep(ep); - struct s3c_hsotg *hsotg = hs_ep->parent; - int dir_in = hs_ep->dir_in; - int index = hs_ep->index; - unsigned long flags; - u32 epctrl_reg; - u32 ctrl; - - dev_info(hsotg->dev, "%s(ep %p)\n", __func__, ep); - - if (ep == &hsotg->eps[0].ep) { - dev_err(hsotg->dev, "%s: called for ep0\n", __func__); - return -EINVAL; - } - - epctrl_reg = dir_in ? S3C_DIEPCTL(index) : S3C_DOEPCTL(index); - - /* terminate all requests with shutdown */ - kill_all_requests(hsotg, hs_ep, -ESHUTDOWN, false); - - spin_lock_irqsave(&hs_ep->lock, flags); - - ctrl = readl(hsotg->regs + epctrl_reg); - ctrl &= ~S3C_DxEPCTL_EPEna; - ctrl &= ~S3C_DxEPCTL_USBActEp; - ctrl |= S3C_DxEPCTL_SNAK; - - dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); - writel(ctrl, hsotg->regs + epctrl_reg); - - /* disable endpoint interrupts */ - s3c_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 0); - - spin_unlock_irqrestore(&hs_ep->lock, flags); - return 0; -} - -/** - * on_list - check request is on the given endpoint - * @ep: The endpoint to check. - * @test: The request to test if it is on the endpoint. -*/ -static bool on_list(struct s3c_hsotg_ep *ep, struct s3c_hsotg_req *test) -{ - struct s3c_hsotg_req *req, *treq; - - list_for_each_entry_safe(req, treq, &ep->queue, queue) { - if (req == test) - return true; - } - - return false; -} - -static int s3c_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) -{ - struct s3c_hsotg_req *hs_req = our_req(req); - struct s3c_hsotg_ep *hs_ep = our_ep(ep); - struct s3c_hsotg *hs = hs_ep->parent; - unsigned long flags; - - dev_info(hs->dev, "ep_dequeue(%p,%p)\n", ep, req); - - spin_lock_irqsave(&hs_ep->lock, flags); - - if (!on_list(hs_ep, hs_req)) { - spin_unlock_irqrestore(&hs_ep->lock, flags); - return -EINVAL; - } - - s3c_hsotg_complete_request(hs, hs_ep, hs_req, -ECONNRESET); - spin_unlock_irqrestore(&hs_ep->lock, flags); - - return 0; -} - -static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value) -{ - struct s3c_hsotg_ep *hs_ep = our_ep(ep); - struct s3c_hsotg *hs = hs_ep->parent; - int index = hs_ep->index; - unsigned long irqflags; - u32 epreg; - u32 epctl; - u32 xfertype; - - dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value); - - spin_lock_irqsave(&hs_ep->lock, irqflags); - - /* write both IN and OUT control registers */ - - epreg = S3C_DIEPCTL(index); - epctl = readl(hs->regs + epreg); - - if (value) { - epctl |= S3C_DxEPCTL_Stall + S3C_DxEPCTL_SNAK; - if (epctl & S3C_DxEPCTL_EPEna) - epctl |= S3C_DxEPCTL_EPDis; - } else { - epctl &= ~S3C_DxEPCTL_Stall; - xfertype = epctl & S3C_DxEPCTL_EPType_MASK; - if (xfertype == S3C_DxEPCTL_EPType_Bulk || - xfertype == S3C_DxEPCTL_EPType_Intterupt) - epctl |= S3C_DxEPCTL_SetD0PID; - } - - writel(epctl, hs->regs + epreg); - - epreg = S3C_DOEPCTL(index); - epctl = readl(hs->regs + epreg); - - if (value) - epctl |= S3C_DxEPCTL_Stall; - else { - epctl &= ~S3C_DxEPCTL_Stall; - xfertype = epctl & S3C_DxEPCTL_EPType_MASK; - if (xfertype == S3C_DxEPCTL_EPType_Bulk || - xfertype == S3C_DxEPCTL_EPType_Intterupt) - epctl |= S3C_DxEPCTL_SetD0PID; - } - - writel(epctl, hs->regs + epreg); - - spin_unlock_irqrestore(&hs_ep->lock, irqflags); - - return 0; -} - -static struct usb_ep_ops s3c_hsotg_ep_ops = { - .enable = s3c_hsotg_ep_enable, - .disable = s3c_hsotg_ep_disable, - .alloc_request = s3c_hsotg_ep_alloc_request, - .free_request = s3c_hsotg_ep_free_request, - .queue = s3c_hsotg_ep_queue, - .dequeue = s3c_hsotg_ep_dequeue, - .set_halt = s3c_hsotg_ep_sethalt, - /* note, don't believe we have any call for the fifo routines */ -}; - -/** - * s3c_hsotg_corereset - issue softreset to the core - * @hsotg: The device state - * - * Issue a soft reset to the core, and await the core finishing it. -*/ -static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg) -{ - int timeout; - u32 grstctl; - - dev_dbg(hsotg->dev, "resetting core\n"); - - /* issue soft reset */ - writel(S3C_GRSTCTL_CSftRst, hsotg->regs + S3C_GRSTCTL); - - timeout = 1000; - do { - grstctl = readl(hsotg->regs + S3C_GRSTCTL); - } while ((grstctl & S3C_GRSTCTL_CSftRst) && timeout-- > 0); - - if (grstctl & S3C_GRSTCTL_CSftRst) { - dev_err(hsotg->dev, "Failed to get CSftRst asserted\n"); - return -EINVAL; - } - - timeout = 1000; - - while (1) { - u32 grstctl = readl(hsotg->regs + S3C_GRSTCTL); - - if (timeout-- < 0) { - dev_info(hsotg->dev, - "%s: reset failed, GRSTCTL=%08x\n", - __func__, grstctl); - return -ETIMEDOUT; - } - - if (!(grstctl & S3C_GRSTCTL_AHBIdle)) - continue; - - break; /* reset done */ - } - - dev_dbg(hsotg->dev, "reset successful\n"); - return 0; -} - -static int s3c_hsotg_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) -{ - struct s3c_hsotg *hsotg = our_hsotg; - int ret; - - if (!hsotg) { - printk(KERN_ERR "%s: called with no device\n", __func__); - return -ENODEV; - } - - if (!driver) { - dev_err(hsotg->dev, "%s: no driver\n", __func__); - return -EINVAL; - } - - if (driver->max_speed < USB_SPEED_FULL) - dev_err(hsotg->dev, "%s: bad speed\n", __func__); - - if (!bind || !driver->setup) { - dev_err(hsotg->dev, "%s: missing entry points\n", __func__); - return -EINVAL; - } - - WARN_ON(hsotg->driver); - - driver->driver.bus = NULL; - hsotg->driver = driver; - hsotg->gadget.dev.driver = &driver->driver; - hsotg->gadget.dev.dma_mask = hsotg->dev->dma_mask; - hsotg->gadget.speed = USB_SPEED_UNKNOWN; - - ret = device_add(&hsotg->gadget.dev); - if (ret) { - dev_err(hsotg->dev, "failed to register gadget device\n"); - goto err; - } - - ret = bind(&hsotg->gadget); - if (ret) { - dev_err(hsotg->dev, "failed bind %s\n", driver->driver.name); - - hsotg->gadget.dev.driver = NULL; - hsotg->driver = NULL; - goto err; - } - - /* we must now enable ep0 ready for host detection and then - * set configuration. */ - - s3c_hsotg_corereset(hsotg); - - /* set the PLL on, remove the HNP/SRP and set the PHY */ - writel(S3C_GUSBCFG_PHYIf16 | S3C_GUSBCFG_TOutCal(7) | - (0x5 << 10), hsotg->regs + S3C_GUSBCFG); - - /* looks like soft-reset changes state of FIFOs */ - s3c_hsotg_init_fifo(hsotg); - - __orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon); - - writel(1 << 18 | S3C_DCFG_DevSpd_HS, hsotg->regs + S3C_DCFG); - - /* Clear any pending OTG interrupts */ - writel(0xffffffff, hsotg->regs + S3C_GOTGINT); - - /* Clear any pending interrupts */ - writel(0xffffffff, hsotg->regs + S3C_GINTSTS); - - writel(S3C_GINTSTS_DisconnInt | S3C_GINTSTS_SessReqInt | - S3C_GINTSTS_ConIDStsChng | S3C_GINTSTS_USBRst | - S3C_GINTSTS_EnumDone | S3C_GINTSTS_OTGInt | - S3C_GINTSTS_USBSusp | S3C_GINTSTS_WkUpInt | - S3C_GINTSTS_GOUTNakEff | S3C_GINTSTS_GINNakEff | - S3C_GINTSTS_ErlySusp, - hsotg->regs + S3C_GINTMSK); - - if (using_dma(hsotg)) - writel(S3C_GAHBCFG_GlblIntrEn | S3C_GAHBCFG_DMAEn | - S3C_GAHBCFG_HBstLen_Incr4, - hsotg->regs + S3C_GAHBCFG); - else - writel(S3C_GAHBCFG_GlblIntrEn, hsotg->regs + S3C_GAHBCFG); - - /* Enabling INTknTXFEmpMsk here seems to be a big mistake, we end - * up being flooded with interrupts if the host is polling the - * endpoint to try and read data. */ - - writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk | - S3C_DIEPMSK_INTknEPMisMsk | - S3C_DIEPMSK_EPDisbldMsk | S3C_DIEPMSK_XferComplMsk | - ((hsotg->dedicated_fifos) ? S3C_DIEPMSK_TxFIFOEmpty : 0), - hsotg->regs + S3C_DIEPMSK); - - /* don't need XferCompl, we get that from RXFIFO in slave mode. In - * DMA mode we may need this. */ - writel(S3C_DOEPMSK_SetupMsk | S3C_DOEPMSK_AHBErrMsk | - S3C_DOEPMSK_EPDisbldMsk | - (using_dma(hsotg) ? (S3C_DIEPMSK_XferComplMsk | - S3C_DIEPMSK_TimeOUTMsk) : 0), - hsotg->regs + S3C_DOEPMSK); - - writel(0, hsotg->regs + S3C_DAINTMSK); - - dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", - readl(hsotg->regs + S3C_DIEPCTL0), - readl(hsotg->regs + S3C_DOEPCTL0)); - - /* enable in and out endpoint interrupts */ - s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_OEPInt | S3C_GINTSTS_IEPInt); - - /* Enable the RXFIFO when in slave mode, as this is how we collect - * the data. In DMA mode, we get events from the FIFO but also - * things we cannot process, so do not use it. */ - if (!using_dma(hsotg)) - s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_RxFLvl); - - /* Enable interrupts for EP0 in and out */ - s3c_hsotg_ctrl_epint(hsotg, 0, 0, 1); - s3c_hsotg_ctrl_epint(hsotg, 0, 1, 1); - - __orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_PWROnPrgDone); - udelay(10); /* see openiboot */ - __bic32(hsotg->regs + S3C_DCTL, S3C_DCTL_PWROnPrgDone); - - dev_dbg(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + S3C_DCTL)); - - /* S3C_DxEPCTL_USBActEp says RO in manual, but seems to be set by - writing to the EPCTL register.. */ - - /* set to read 1 8byte packet */ - writel(S3C_DxEPTSIZ_MC(1) | S3C_DxEPTSIZ_PktCnt(1) | - S3C_DxEPTSIZ_XferSize(8), hsotg->regs + DOEPTSIZ0); - - writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) | - S3C_DxEPCTL_CNAK | S3C_DxEPCTL_EPEna | - S3C_DxEPCTL_USBActEp, - hsotg->regs + S3C_DOEPCTL0); - - /* enable, but don't activate EP0in */ - writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) | - S3C_DxEPCTL_USBActEp, hsotg->regs + S3C_DIEPCTL0); - - s3c_hsotg_enqueue_setup(hsotg); - - dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", - readl(hsotg->regs + S3C_DIEPCTL0), - readl(hsotg->regs + S3C_DOEPCTL0)); - - /* clear global NAKs */ - writel(S3C_DCTL_CGOUTNak | S3C_DCTL_CGNPInNAK, - hsotg->regs + S3C_DCTL); - - /* must be at-least 3ms to allow bus to see disconnect */ - msleep(3); - - /* remove the soft-disconnect and let's go */ - __bic32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon); - - /* report to the user, and return */ - - dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); - return 0; - -err: - hsotg->driver = NULL; - hsotg->gadget.dev.driver = NULL; - return ret; -} - -static int s3c_hsotg_stop(struct usb_gadget_driver *driver) -{ - struct s3c_hsotg *hsotg = our_hsotg; - int ep; - - if (!hsotg) - return -ENODEV; - - if (!driver || driver != hsotg->driver || !driver->unbind) - return -EINVAL; - - /* all endpoints should be shutdown */ - for (ep = 0; ep < S3C_HSOTG_EPS; ep++) - s3c_hsotg_ep_disable(&hsotg->eps[ep].ep); - - call_gadget(hsotg, disconnect); - - driver->unbind(&hsotg->gadget); - hsotg->driver = NULL; - hsotg->gadget.speed = USB_SPEED_UNKNOWN; - - device_del(&hsotg->gadget.dev); - - dev_info(hsotg->dev, "unregistered gadget driver '%s'\n", - driver->driver.name); - - return 0; -} - -static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget) -{ - return s3c_hsotg_read_frameno(to_hsotg(gadget)); -} - -static struct usb_gadget_ops s3c_hsotg_gadget_ops = { - .get_frame = s3c_hsotg_gadget_getframe, - .start = s3c_hsotg_start, - .stop = s3c_hsotg_stop, -}; - -/** - * s3c_hsotg_initep - initialise a single endpoint - * @hsotg: The device state. - * @hs_ep: The endpoint to be initialised. - * @epnum: The endpoint number - * - * Initialise the given endpoint (as part of the probe and device state - * creation) to give to the gadget driver. Setup the endpoint name, any - * direction information and other state that may be required. - */ -static void __devinit s3c_hsotg_initep(struct s3c_hsotg *hsotg, - struct s3c_hsotg_ep *hs_ep, - int epnum) -{ - u32 ptxfifo; - char *dir; - - if (epnum == 0) - dir = ""; - else if ((epnum % 2) == 0) { - dir = "out"; - } else { - dir = "in"; - hs_ep->dir_in = 1; - } - - hs_ep->index = epnum; - - snprintf(hs_ep->name, sizeof(hs_ep->name), "ep%d%s", epnum, dir); - - INIT_LIST_HEAD(&hs_ep->queue); - INIT_LIST_HEAD(&hs_ep->ep.ep_list); - - spin_lock_init(&hs_ep->lock); - - /* add to the list of endpoints known by the gadget driver */ - if (epnum) - list_add_tail(&hs_ep->ep.ep_list, &hsotg->gadget.ep_list); - - hs_ep->parent = hsotg; - hs_ep->ep.name = hs_ep->name; - hs_ep->ep.maxpacket = epnum ? 512 : EP0_MPS_LIMIT; - hs_ep->ep.ops = &s3c_hsotg_ep_ops; - - /* Read the FIFO size for the Periodic TX FIFO, even if we're - * an OUT endpoint, we may as well do this if in future the - * code is changed to make each endpoint's direction changeable. - */ - - ptxfifo = readl(hsotg->regs + S3C_DPTXFSIZn(epnum)); - hs_ep->fifo_size = S3C_DPTXFSIZn_DPTxFSize_GET(ptxfifo) * 4; - - /* if we're using dma, we need to set the next-endpoint pointer - * to be something valid. - */ - - if (using_dma(hsotg)) { - u32 next = S3C_DxEPCTL_NextEp((epnum + 1) % 15); - writel(next, hsotg->regs + S3C_DIEPCTL(epnum)); - writel(next, hsotg->regs + S3C_DOEPCTL(epnum)); - } -} - -/** - * s3c_hsotg_otgreset - reset the OtG phy block - * @hsotg: The host state. - * - * Power up the phy, set the basic configuration and start the PHY. - */ -static void s3c_hsotg_otgreset(struct s3c_hsotg *hsotg) -{ - struct clk *xusbxti; - u32 pwr, osc; - - pwr = readl(S3C_PHYPWR); - pwr &= ~0x19; - writel(pwr, S3C_PHYPWR); - mdelay(1); - - osc = hsotg->plat->is_osc ? S3C_PHYCLK_EXT_OSC : 0; - - xusbxti = clk_get(hsotg->dev, "xusbxti"); - if (xusbxti && !IS_ERR(xusbxti)) { - switch (clk_get_rate(xusbxti)) { - case 12*MHZ: - osc |= S3C_PHYCLK_CLKSEL_12M; - break; - case 24*MHZ: - osc |= S3C_PHYCLK_CLKSEL_24M; - break; - default: - case 48*MHZ: - /* default reference clock */ - break; - } - clk_put(xusbxti); - } - - writel(osc | 0x10, S3C_PHYCLK); - - /* issue a full set of resets to the otg and core */ - - writel(S3C_RSTCON_PHY, S3C_RSTCON); - udelay(20); /* at-least 10uS */ - writel(0, S3C_RSTCON); -} - - -static void s3c_hsotg_init(struct s3c_hsotg *hsotg) -{ - u32 cfg4; - - /* unmask subset of endpoint interrupts */ - - writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk | - S3C_DIEPMSK_EPDisbldMsk | S3C_DIEPMSK_XferComplMsk, - hsotg->regs + S3C_DIEPMSK); - - writel(S3C_DOEPMSK_SetupMsk | S3C_DOEPMSK_AHBErrMsk | - S3C_DOEPMSK_EPDisbldMsk | S3C_DOEPMSK_XferComplMsk, - hsotg->regs + S3C_DOEPMSK); - - writel(0, hsotg->regs + S3C_DAINTMSK); - - /* Be in disconnected state until gadget is registered */ - __orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon); - - if (0) { - /* post global nak until we're ready */ - writel(S3C_DCTL_SGNPInNAK | S3C_DCTL_SGOUTNak, - hsotg->regs + S3C_DCTL); - } - - /* setup fifos */ - - dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", - readl(hsotg->regs + S3C_GRXFSIZ), - readl(hsotg->regs + S3C_GNPTXFSIZ)); - - s3c_hsotg_init_fifo(hsotg); - - /* set the PLL on, remove the HNP/SRP and set the PHY */ - writel(S3C_GUSBCFG_PHYIf16 | S3C_GUSBCFG_TOutCal(7) | (0x5 << 10), - hsotg->regs + S3C_GUSBCFG); - - writel(using_dma(hsotg) ? S3C_GAHBCFG_DMAEn : 0x0, - hsotg->regs + S3C_GAHBCFG); - - /* check hardware configuration */ - - cfg4 = readl(hsotg->regs + 0x50); - hsotg->dedicated_fifos = (cfg4 >> 25) & 1; - - dev_info(hsotg->dev, "%s fifos\n", - hsotg->dedicated_fifos ? "dedicated" : "shared"); -} - -static void s3c_hsotg_dump(struct s3c_hsotg *hsotg) -{ -#ifdef DEBUG - struct device *dev = hsotg->dev; - void __iomem *regs = hsotg->regs; - u32 val; - int idx; - - dev_info(dev, "DCFG=0x%08x, DCTL=0x%08x, DIEPMSK=%08x\n", - readl(regs + S3C_DCFG), readl(regs + S3C_DCTL), - readl(regs + S3C_DIEPMSK)); - - dev_info(dev, "GAHBCFG=0x%08x, 0x44=0x%08x\n", - readl(regs + S3C_GAHBCFG), readl(regs + 0x44)); - - dev_info(dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", - readl(regs + S3C_GRXFSIZ), readl(regs + S3C_GNPTXFSIZ)); - - /* show periodic fifo settings */ - - for (idx = 1; idx <= 15; idx++) { - val = readl(regs + S3C_DPTXFSIZn(idx)); - dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx, - val >> S3C_DPTXFSIZn_DPTxFSize_SHIFT, - val & S3C_DPTXFSIZn_DPTxFStAddr_MASK); - } - - for (idx = 0; idx < 15; idx++) { - dev_info(dev, - "ep%d-in: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", idx, - readl(regs + S3C_DIEPCTL(idx)), - readl(regs + S3C_DIEPTSIZ(idx)), - readl(regs + S3C_DIEPDMA(idx))); - - val = readl(regs + S3C_DOEPCTL(idx)); - dev_info(dev, - "ep%d-out: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", - idx, readl(regs + S3C_DOEPCTL(idx)), - readl(regs + S3C_DOEPTSIZ(idx)), - readl(regs + S3C_DOEPDMA(idx))); - - } - - dev_info(dev, "DVBUSDIS=0x%08x, DVBUSPULSE=%08x\n", - readl(regs + S3C_DVBUSDIS), readl(regs + S3C_DVBUSPULSE)); -#endif -} - - -/** - * state_show - debugfs: show overall driver and device state. - * @seq: The seq file to write to. - * @v: Unused parameter. - * - * This debugfs entry shows the overall state of the hardware and - * some general information about each of the endpoints available - * to the system. - */ -static int state_show(struct seq_file *seq, void *v) -{ - struct s3c_hsotg *hsotg = seq->private; - void __iomem *regs = hsotg->regs; - int idx; - - seq_printf(seq, "DCFG=0x%08x, DCTL=0x%08x, DSTS=0x%08x\n", - readl(regs + S3C_DCFG), - readl(regs + S3C_DCTL), - readl(regs + S3C_DSTS)); - - seq_printf(seq, "DIEPMSK=0x%08x, DOEPMASK=0x%08x\n", - readl(regs + S3C_DIEPMSK), readl(regs + S3C_DOEPMSK)); - - seq_printf(seq, "GINTMSK=0x%08x, GINTSTS=0x%08x\n", - readl(regs + S3C_GINTMSK), - readl(regs + S3C_GINTSTS)); - - seq_printf(seq, "DAINTMSK=0x%08x, DAINT=0x%08x\n", - readl(regs + S3C_DAINTMSK), - readl(regs + S3C_DAINT)); - - seq_printf(seq, "GNPTXSTS=0x%08x, GRXSTSR=%08x\n", - readl(regs + S3C_GNPTXSTS), - readl(regs + S3C_GRXSTSR)); - - seq_printf(seq, "\nEndpoint status:\n"); - - for (idx = 0; idx < 15; idx++) { - u32 in, out; - - in = readl(regs + S3C_DIEPCTL(idx)); - out = readl(regs + S3C_DOEPCTL(idx)); - - seq_printf(seq, "ep%d: DIEPCTL=0x%08x, DOEPCTL=0x%08x", - idx, in, out); - - in = readl(regs + S3C_DIEPTSIZ(idx)); - out = readl(regs + S3C_DOEPTSIZ(idx)); - - seq_printf(seq, ", DIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x", - in, out); - - seq_printf(seq, "\n"); - } - - return 0; -} - -static int state_open(struct inode *inode, struct file *file) -{ - return single_open(file, state_show, inode->i_private); -} - -static const struct file_operations state_fops = { - .owner = THIS_MODULE, - .open = state_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -/** - * fifo_show - debugfs: show the fifo information - * @seq: The seq_file to write data to. - * @v: Unused parameter. - * - * Show the FIFO information for the overall fifo and all the - * periodic transmission FIFOs. -*/ -static int fifo_show(struct seq_file *seq, void *v) -{ - struct s3c_hsotg *hsotg = seq->private; - void __iomem *regs = hsotg->regs; - u32 val; - int idx; - - seq_printf(seq, "Non-periodic FIFOs:\n"); - seq_printf(seq, "RXFIFO: Size %d\n", readl(regs + S3C_GRXFSIZ)); - - val = readl(regs + S3C_GNPTXFSIZ); - seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n", - val >> S3C_GNPTXFSIZ_NPTxFDep_SHIFT, - val & S3C_GNPTXFSIZ_NPTxFStAddr_MASK); - - seq_printf(seq, "\nPeriodic TXFIFOs:\n"); - - for (idx = 1; idx <= 15; idx++) { - val = readl(regs + S3C_DPTXFSIZn(idx)); - - seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx, - val >> S3C_DPTXFSIZn_DPTxFSize_SHIFT, - val & S3C_DPTXFSIZn_DPTxFStAddr_MASK); - } - - return 0; -} - -static int fifo_open(struct inode *inode, struct file *file) -{ - return single_open(file, fifo_show, inode->i_private); -} - -static const struct file_operations fifo_fops = { - .owner = THIS_MODULE, - .open = fifo_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - - -static const char *decode_direction(int is_in) -{ - return is_in ? "in" : "out"; -} - -/** - * ep_show - debugfs: show the state of an endpoint. - * @seq: The seq_file to write data to. - * @v: Unused parameter. - * - * This debugfs entry shows the state of the given endpoint (one is - * registered for each available). -*/ -static int ep_show(struct seq_file *seq, void *v) -{ - struct s3c_hsotg_ep *ep = seq->private; - struct s3c_hsotg *hsotg = ep->parent; - struct s3c_hsotg_req *req; - void __iomem *regs = hsotg->regs; - int index = ep->index; - int show_limit = 15; - unsigned long flags; - - seq_printf(seq, "Endpoint index %d, named %s, dir %s:\n", - ep->index, ep->ep.name, decode_direction(ep->dir_in)); - - /* first show the register state */ - - seq_printf(seq, "\tDIEPCTL=0x%08x, DOEPCTL=0x%08x\n", - readl(regs + S3C_DIEPCTL(index)), - readl(regs + S3C_DOEPCTL(index))); - - seq_printf(seq, "\tDIEPDMA=0x%08x, DOEPDMA=0x%08x\n", - readl(regs + S3C_DIEPDMA(index)), - readl(regs + S3C_DOEPDMA(index))); - - seq_printf(seq, "\tDIEPINT=0x%08x, DOEPINT=0x%08x\n", - readl(regs + S3C_DIEPINT(index)), - readl(regs + S3C_DOEPINT(index))); - - seq_printf(seq, "\tDIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x\n", - readl(regs + S3C_DIEPTSIZ(index)), - readl(regs + S3C_DOEPTSIZ(index))); - - seq_printf(seq, "\n"); - seq_printf(seq, "mps %d\n", ep->ep.maxpacket); - seq_printf(seq, "total_data=%ld\n", ep->total_data); - - seq_printf(seq, "request list (%p,%p):\n", - ep->queue.next, ep->queue.prev); - - spin_lock_irqsave(&ep->lock, flags); - - list_for_each_entry(req, &ep->queue, queue) { - if (--show_limit < 0) { - seq_printf(seq, "not showing more requests...\n"); - break; - } - - seq_printf(seq, "%c req %p: %d bytes @%p, ", - req == ep->req ? '*' : ' ', - req, req->req.length, req->req.buf); - seq_printf(seq, "%d done, res %d\n", - req->req.actual, req->req.status); - } - - spin_unlock_irqrestore(&ep->lock, flags); - - return 0; -} - -static int ep_open(struct inode *inode, struct file *file) -{ - return single_open(file, ep_show, inode->i_private); -} - -static const struct file_operations ep_fops = { - .owner = THIS_MODULE, - .open = ep_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -/** - * s3c_hsotg_create_debug - create debugfs directory and files - * @hsotg: The driver state - * - * Create the debugfs files to allow the user to get information - * about the state of the system. The directory name is created - * with the same name as the device itself, in case we end up - * with multiple blocks in future systems. -*/ -static void __devinit s3c_hsotg_create_debug(struct s3c_hsotg *hsotg) -{ - struct dentry *root; - unsigned epidx; - - root = debugfs_create_dir(dev_name(hsotg->dev), NULL); - hsotg->debug_root = root; - if (IS_ERR(root)) { - dev_err(hsotg->dev, "cannot create debug root\n"); - return; - } - - /* create general state file */ - - hsotg->debug_file = debugfs_create_file("state", 0444, root, - hsotg, &state_fops); - - if (IS_ERR(hsotg->debug_file)) - dev_err(hsotg->dev, "%s: failed to create state\n", __func__); - - hsotg->debug_fifo = debugfs_create_file("fifo", 0444, root, - hsotg, &fifo_fops); - - if (IS_ERR(hsotg->debug_fifo)) - dev_err(hsotg->dev, "%s: failed to create fifo\n", __func__); - - /* create one file for each endpoint */ - - for (epidx = 0; epidx < S3C_HSOTG_EPS; epidx++) { - struct s3c_hsotg_ep *ep = &hsotg->eps[epidx]; - - ep->debugfs = debugfs_create_file(ep->name, 0444, - root, ep, &ep_fops); - - if (IS_ERR(ep->debugfs)) - dev_err(hsotg->dev, "failed to create %s debug file\n", - ep->name); - } -} - -/** - * s3c_hsotg_delete_debug - cleanup debugfs entries - * @hsotg: The driver state - * - * Cleanup (remove) the debugfs files for use on module exit. -*/ -static void __devexit s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg) -{ - unsigned epidx; - - for (epidx = 0; epidx < S3C_HSOTG_EPS; epidx++) { - struct s3c_hsotg_ep *ep = &hsotg->eps[epidx]; - debugfs_remove(ep->debugfs); - } - - debugfs_remove(hsotg->debug_file); - debugfs_remove(hsotg->debug_fifo); - debugfs_remove(hsotg->debug_root); -} - -/** - * s3c_hsotg_gate - set the hardware gate for the block - * @pdev: The device we bound to - * @on: On or off. - * - * Set the hardware gate setting into the block. If we end up on - * something other than an S3C64XX, then we might need to change this - * to using a platform data callback, or some other mechanism. - */ -static void s3c_hsotg_gate(struct platform_device *pdev, bool on) -{ - unsigned long flags; - u32 others; - - local_irq_save(flags); - - others = __raw_readl(S3C64XX_OTHERS); - if (on) - others |= S3C64XX_OTHERS_USBMASK; - else - others &= ~S3C64XX_OTHERS_USBMASK; - __raw_writel(others, S3C64XX_OTHERS); - - local_irq_restore(flags); -} - -static struct s3c_hsotg_plat s3c_hsotg_default_pdata; - -static int __devinit s3c_hsotg_probe(struct platform_device *pdev) -{ - struct s3c_hsotg_plat *plat = pdev->dev.platform_data; - struct device *dev = &pdev->dev; - struct s3c_hsotg *hsotg; - struct resource *res; - int epnum; - int ret; - - if (!plat) - plat = &s3c_hsotg_default_pdata; - - hsotg = kzalloc(sizeof(struct s3c_hsotg) + - sizeof(struct s3c_hsotg_ep) * S3C_HSOTG_EPS, - GFP_KERNEL); - if (!hsotg) { - dev_err(dev, "cannot get memory\n"); - return -ENOMEM; - } - - hsotg->dev = dev; - hsotg->plat = plat; - - hsotg->clk = clk_get(&pdev->dev, "otg"); - if (IS_ERR(hsotg->clk)) { - dev_err(dev, "cannot get otg clock\n"); - ret = PTR_ERR(hsotg->clk); - goto err_mem; - } - - platform_set_drvdata(pdev, hsotg); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "cannot find register resource 0\n"); - ret = -EINVAL; - goto err_clk; - } - - hsotg->regs_res = request_mem_region(res->start, resource_size(res), - dev_name(dev)); - if (!hsotg->regs_res) { - dev_err(dev, "cannot reserve registers\n"); - ret = -ENOENT; - goto err_clk; - } - - hsotg->regs = ioremap(res->start, resource_size(res)); - if (!hsotg->regs) { - dev_err(dev, "cannot map registers\n"); - ret = -ENXIO; - goto err_regs_res; - } - - ret = platform_get_irq(pdev, 0); - if (ret < 0) { - dev_err(dev, "cannot find IRQ\n"); - goto err_regs; - } - - hsotg->irq = ret; - - ret = request_irq(ret, s3c_hsotg_irq, 0, dev_name(dev), hsotg); - if (ret < 0) { - dev_err(dev, "cannot claim IRQ\n"); - goto err_regs; - } - - dev_info(dev, "regs %p, irq %d\n", hsotg->regs, hsotg->irq); - - device_initialize(&hsotg->gadget.dev); - - dev_set_name(&hsotg->gadget.dev, "gadget"); - - hsotg->gadget.max_speed = USB_SPEED_HIGH; - hsotg->gadget.ops = &s3c_hsotg_gadget_ops; - hsotg->gadget.name = dev_name(dev); - - hsotg->gadget.dev.parent = dev; - hsotg->gadget.dev.dma_mask = dev->dma_mask; - - /* setup endpoint information */ - - INIT_LIST_HEAD(&hsotg->gadget.ep_list); - hsotg->gadget.ep0 = &hsotg->eps[0].ep; - - /* allocate EP0 request */ - - hsotg->ctrl_req = s3c_hsotg_ep_alloc_request(&hsotg->eps[0].ep, - GFP_KERNEL); - if (!hsotg->ctrl_req) { - dev_err(dev, "failed to allocate ctrl req\n"); - goto err_regs; - } - - /* reset the system */ - - clk_enable(hsotg->clk); - - s3c_hsotg_gate(pdev, true); - - s3c_hsotg_otgreset(hsotg); - s3c_hsotg_corereset(hsotg); - s3c_hsotg_init(hsotg); - - /* initialise the endpoints now the core has been initialised */ - for (epnum = 0; epnum < S3C_HSOTG_EPS; epnum++) - s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum); - - ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget); - if (ret) - goto err_add_udc; - - s3c_hsotg_create_debug(hsotg); - - s3c_hsotg_dump(hsotg); - - our_hsotg = hsotg; - return 0; - -err_add_udc: - s3c_hsotg_gate(pdev, false); - clk_disable(hsotg->clk); - clk_put(hsotg->clk); - -err_regs: - iounmap(hsotg->regs); - -err_regs_res: - release_resource(hsotg->regs_res); - kfree(hsotg->regs_res); -err_clk: - clk_put(hsotg->clk); -err_mem: - kfree(hsotg); - return ret; -} - -static int __devexit s3c_hsotg_remove(struct platform_device *pdev) -{ - struct s3c_hsotg *hsotg = platform_get_drvdata(pdev); - - usb_del_gadget_udc(&hsotg->gadget); - - s3c_hsotg_delete_debug(hsotg); - - usb_gadget_unregister_driver(hsotg->driver); - - free_irq(hsotg->irq, hsotg); - iounmap(hsotg->regs); - - release_resource(hsotg->regs_res); - kfree(hsotg->regs_res); - - s3c_hsotg_gate(pdev, false); - - clk_disable(hsotg->clk); - clk_put(hsotg->clk); - - kfree(hsotg); - return 0; -} - -#if 1 -#define s3c_hsotg_suspend NULL -#define s3c_hsotg_resume NULL -#endif - -static struct platform_driver s3c_hsotg_driver = { - .driver = { - .name = "s3c-hsotg", - .owner = THIS_MODULE, - }, - .probe = s3c_hsotg_probe, - .remove = __devexit_p(s3c_hsotg_remove), - .suspend = s3c_hsotg_suspend, - .resume = s3c_hsotg_resume, -}; - -module_platform_driver(s3c_hsotg_driver); - -MODULE_DESCRIPTION("Samsung S3C USB High-speed/OtG device"); -MODULE_AUTHOR("Ben Dooks "); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:s3c-hsotg"); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/s3c-hsudc.c b/ANDROID_3.4.5/drivers/usb/gadget/s3c-hsudc.c deleted file mode 100644 index cef9b82f..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/s3c-hsudc.c +++ /dev/null @@ -1,1413 +0,0 @@ -/* linux/drivers/usb/gadget/s3c-hsudc.c - * - * Copyright (c) 2010 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - * - * S3C24XX USB 2.0 High-speed USB controller gadget driver - * - * The S3C24XX USB 2.0 high-speed USB controller supports upto 9 endpoints. - * Each endpoint can be configured as either in or out endpoint. Endpoints - * can be configured for Bulk or Interrupt transfer mode. - * - * 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. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define S3C_HSUDC_REG(x) (x) - -/* Non-Indexed Registers */ -#define S3C_IR S3C_HSUDC_REG(0x00) /* Index Register */ -#define S3C_EIR S3C_HSUDC_REG(0x04) /* EP Intr Status */ -#define S3C_EIR_EP0 (1<<0) -#define S3C_EIER S3C_HSUDC_REG(0x08) /* EP Intr Enable */ -#define S3C_FAR S3C_HSUDC_REG(0x0c) /* Gadget Address */ -#define S3C_FNR S3C_HSUDC_REG(0x10) /* Frame Number */ -#define S3C_EDR S3C_HSUDC_REG(0x14) /* EP Direction */ -#define S3C_TR S3C_HSUDC_REG(0x18) /* Test Register */ -#define S3C_SSR S3C_HSUDC_REG(0x1c) /* System Status */ -#define S3C_SSR_DTZIEN_EN (0xff8f) -#define S3C_SSR_ERR (0xff80) -#define S3C_SSR_VBUSON (1 << 8) -#define S3C_SSR_HSP (1 << 4) -#define S3C_SSR_SDE (1 << 3) -#define S3C_SSR_RESUME (1 << 2) -#define S3C_SSR_SUSPEND (1 << 1) -#define S3C_SSR_RESET (1 << 0) -#define S3C_SCR S3C_HSUDC_REG(0x20) /* System Control */ -#define S3C_SCR_DTZIEN_EN (1 << 14) -#define S3C_SCR_RRD_EN (1 << 5) -#define S3C_SCR_SUS_EN (1 << 1) -#define S3C_SCR_RST_EN (1 << 0) -#define S3C_EP0SR S3C_HSUDC_REG(0x24) /* EP0 Status */ -#define S3C_EP0SR_EP0_LWO (1 << 6) -#define S3C_EP0SR_STALL (1 << 4) -#define S3C_EP0SR_TX_SUCCESS (1 << 1) -#define S3C_EP0SR_RX_SUCCESS (1 << 0) -#define S3C_EP0CR S3C_HSUDC_REG(0x28) /* EP0 Control */ -#define S3C_BR(_x) S3C_HSUDC_REG(0x60 + (_x * 4)) - -/* Indexed Registers */ -#define S3C_ESR S3C_HSUDC_REG(0x2c) /* EPn Status */ -#define S3C_ESR_FLUSH (1 << 6) -#define S3C_ESR_STALL (1 << 5) -#define S3C_ESR_LWO (1 << 4) -#define S3C_ESR_PSIF_ONE (1 << 2) -#define S3C_ESR_PSIF_TWO (2 << 2) -#define S3C_ESR_TX_SUCCESS (1 << 1) -#define S3C_ESR_RX_SUCCESS (1 << 0) -#define S3C_ECR S3C_HSUDC_REG(0x30) /* EPn Control */ -#define S3C_ECR_DUEN (1 << 7) -#define S3C_ECR_FLUSH (1 << 6) -#define S3C_ECR_STALL (1 << 1) -#define S3C_ECR_IEMS (1 << 0) -#define S3C_BRCR S3C_HSUDC_REG(0x34) /* Read Count */ -#define S3C_BWCR S3C_HSUDC_REG(0x38) /* Write Count */ -#define S3C_MPR S3C_HSUDC_REG(0x3c) /* Max Pkt Size */ - -#define WAIT_FOR_SETUP (0) -#define DATA_STATE_XMIT (1) -#define DATA_STATE_RECV (2) - -static const char * const s3c_hsudc_supply_names[] = { - "vdda", /* analog phy supply, 3.3V */ - "vddi", /* digital phy supply, 1.2V */ - "vddosc", /* oscillator supply, 1.8V - 3.3V */ -}; - -/** - * struct s3c_hsudc_ep - Endpoint representation used by driver. - * @ep: USB gadget layer representation of device endpoint. - * @name: Endpoint name (as required by ep autoconfiguration). - * @dev: Reference to the device controller to which this EP belongs. - * @desc: Endpoint descriptor obtained from the gadget driver. - * @queue: Transfer request queue for the endpoint. - * @stopped: Maintains state of endpoint, set if EP is halted. - * @bEndpointAddress: EP address (including direction bit). - * @fifo: Base address of EP FIFO. - */ -struct s3c_hsudc_ep { - struct usb_ep ep; - char name[20]; - struct s3c_hsudc *dev; - const struct usb_endpoint_descriptor *desc; - struct list_head queue; - u8 stopped; - u8 wedge; - u8 bEndpointAddress; - void __iomem *fifo; -}; - -/** - * struct s3c_hsudc_req - Driver encapsulation of USB gadget transfer request. - * @req: Reference to USB gadget transfer request. - * @queue: Used for inserting this request to the endpoint request queue. - */ -struct s3c_hsudc_req { - struct usb_request req; - struct list_head queue; -}; - -/** - * struct s3c_hsudc - Driver's abstraction of the device controller. - * @gadget: Instance of usb_gadget which is referenced by gadget driver. - * @driver: Reference to currenty active gadget driver. - * @dev: The device reference used by probe function. - * @lock: Lock to synchronize the usage of Endpoints (EP's are indexed). - * @regs: Remapped base address of controller's register space. - * @mem_rsrc: Device memory resource used for remapping device register space. - * irq: IRQ number used by the controller. - * uclk: Reference to the controller clock. - * ep0state: Current state of EP0. - * ep: List of endpoints supported by the controller. - */ -struct s3c_hsudc { - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - struct device *dev; - struct s3c24xx_hsudc_platdata *pd; - struct usb_phy *transceiver; - struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsudc_supply_names)]; - spinlock_t lock; - void __iomem *regs; - struct resource *mem_rsrc; - int irq; - struct clk *uclk; - int ep0state; - struct s3c_hsudc_ep ep[]; -}; - -#define ep_maxpacket(_ep) ((_ep)->ep.maxpacket) -#define ep_is_in(_ep) ((_ep)->bEndpointAddress & USB_DIR_IN) -#define ep_index(_ep) ((_ep)->bEndpointAddress & \ - USB_ENDPOINT_NUMBER_MASK) - -static const char driver_name[] = "s3c-udc"; -static const char ep0name[] = "ep0-control"; - -static inline struct s3c_hsudc_req *our_req(struct usb_request *req) -{ - return container_of(req, struct s3c_hsudc_req, req); -} - -static inline struct s3c_hsudc_ep *our_ep(struct usb_ep *ep) -{ - return container_of(ep, struct s3c_hsudc_ep, ep); -} - -static inline struct s3c_hsudc *to_hsudc(struct usb_gadget *gadget) -{ - return container_of(gadget, struct s3c_hsudc, gadget); -} - -static inline void set_index(struct s3c_hsudc *hsudc, int ep_addr) -{ - ep_addr &= USB_ENDPOINT_NUMBER_MASK; - writel(ep_addr, hsudc->regs + S3C_IR); -} - -static inline void __orr32(void __iomem *ptr, u32 val) -{ - writel(readl(ptr) | val, ptr); -} - -static void s3c_hsudc_init_phy(void) -{ - u32 cfg; - - cfg = readl(S3C2443_PWRCFG) | S3C2443_PWRCFG_USBPHY; - writel(cfg, S3C2443_PWRCFG); - - cfg = readl(S3C2443_URSTCON); - cfg |= (S3C2443_URSTCON_FUNCRST | S3C2443_URSTCON_PHYRST); - writel(cfg, S3C2443_URSTCON); - mdelay(1); - - cfg = readl(S3C2443_URSTCON); - cfg &= ~(S3C2443_URSTCON_FUNCRST | S3C2443_URSTCON_PHYRST); - writel(cfg, S3C2443_URSTCON); - - cfg = readl(S3C2443_PHYCTRL); - cfg &= ~(S3C2443_PHYCTRL_CLKSEL | S3C2443_PHYCTRL_DSPORT); - cfg |= (S3C2443_PHYCTRL_EXTCLK | S3C2443_PHYCTRL_PLLSEL); - writel(cfg, S3C2443_PHYCTRL); - - cfg = readl(S3C2443_PHYPWR); - cfg &= ~(S3C2443_PHYPWR_FSUSPEND | S3C2443_PHYPWR_PLL_PWRDN | - S3C2443_PHYPWR_XO_ON | S3C2443_PHYPWR_PLL_REFCLK | - S3C2443_PHYPWR_ANALOG_PD); - cfg |= S3C2443_PHYPWR_COMMON_ON; - writel(cfg, S3C2443_PHYPWR); - - cfg = readl(S3C2443_UCLKCON); - cfg |= (S3C2443_UCLKCON_DETECT_VBUS | S3C2443_UCLKCON_FUNC_CLKEN | - S3C2443_UCLKCON_TCLKEN); - writel(cfg, S3C2443_UCLKCON); -} - -static void s3c_hsudc_uninit_phy(void) -{ - u32 cfg; - - cfg = readl(S3C2443_PWRCFG) & ~S3C2443_PWRCFG_USBPHY; - writel(cfg, S3C2443_PWRCFG); - - writel(S3C2443_PHYPWR_FSUSPEND, S3C2443_PHYPWR); - - cfg = readl(S3C2443_UCLKCON) & ~S3C2443_UCLKCON_FUNC_CLKEN; - writel(cfg, S3C2443_UCLKCON); -} - -/** - * s3c_hsudc_complete_request - Complete a transfer request. - * @hsep: Endpoint to which the request belongs. - * @hsreq: Transfer request to be completed. - * @status: Transfer completion status for the transfer request. - */ -static void s3c_hsudc_complete_request(struct s3c_hsudc_ep *hsep, - struct s3c_hsudc_req *hsreq, int status) -{ - unsigned int stopped = hsep->stopped; - struct s3c_hsudc *hsudc = hsep->dev; - - list_del_init(&hsreq->queue); - hsreq->req.status = status; - - if (!ep_index(hsep)) { - hsudc->ep0state = WAIT_FOR_SETUP; - hsep->bEndpointAddress &= ~USB_DIR_IN; - } - - hsep->stopped = 1; - spin_unlock(&hsudc->lock); - if (hsreq->req.complete != NULL) - hsreq->req.complete(&hsep->ep, &hsreq->req); - spin_lock(&hsudc->lock); - hsep->stopped = stopped; -} - -/** - * s3c_hsudc_nuke_ep - Terminate all requests queued for a endpoint. - * @hsep: Endpoint for which queued requests have to be terminated. - * @status: Transfer completion status for the transfer request. - */ -static void s3c_hsudc_nuke_ep(struct s3c_hsudc_ep *hsep, int status) -{ - struct s3c_hsudc_req *hsreq; - - while (!list_empty(&hsep->queue)) { - hsreq = list_entry(hsep->queue.next, - struct s3c_hsudc_req, queue); - s3c_hsudc_complete_request(hsep, hsreq, status); - } -} - -/** - * s3c_hsudc_stop_activity - Stop activity on all endpoints. - * @hsudc: Device controller for which EP activity is to be stopped. - * @driver: Reference to the gadget driver which is currently active. - * - * All the endpoints are stopped and any pending transfer requests if any on - * the endpoint are terminated. - */ -static void s3c_hsudc_stop_activity(struct s3c_hsudc *hsudc) -{ - struct s3c_hsudc_ep *hsep; - int epnum; - - hsudc->gadget.speed = USB_SPEED_UNKNOWN; - - for (epnum = 0; epnum < hsudc->pd->epnum; epnum++) { - hsep = &hsudc->ep[epnum]; - hsep->stopped = 1; - s3c_hsudc_nuke_ep(hsep, -ESHUTDOWN); - } -} - -/** - * s3c_hsudc_read_setup_pkt - Read the received setup packet from EP0 fifo. - * @hsudc: Device controller from which setup packet is to be read. - * @buf: The buffer into which the setup packet is read. - * - * The setup packet received in the EP0 fifo is read and stored into a - * given buffer address. - */ - -static void s3c_hsudc_read_setup_pkt(struct s3c_hsudc *hsudc, u16 *buf) -{ - int count; - - count = readl(hsudc->regs + S3C_BRCR); - while (count--) - *buf++ = (u16)readl(hsudc->regs + S3C_BR(0)); - - writel(S3C_EP0SR_RX_SUCCESS, hsudc->regs + S3C_EP0SR); -} - -/** - * s3c_hsudc_write_fifo - Write next chunk of transfer data to EP fifo. - * @hsep: Endpoint to which the data is to be written. - * @hsreq: Transfer request from which the next chunk of data is written. - * - * Write the next chunk of data from a transfer request to the endpoint FIFO. - * If the transfer request completes, 1 is returned, otherwise 0 is returned. - */ -static int s3c_hsudc_write_fifo(struct s3c_hsudc_ep *hsep, - struct s3c_hsudc_req *hsreq) -{ - u16 *buf; - u32 max = ep_maxpacket(hsep); - u32 count, length; - bool is_last; - void __iomem *fifo = hsep->fifo; - - buf = hsreq->req.buf + hsreq->req.actual; - prefetch(buf); - - length = hsreq->req.length - hsreq->req.actual; - length = min(length, max); - hsreq->req.actual += length; - - writel(length, hsep->dev->regs + S3C_BWCR); - for (count = 0; count < length; count += 2) - writel(*buf++, fifo); - - if (count != max) { - is_last = true; - } else { - if (hsreq->req.length != hsreq->req.actual || hsreq->req.zero) - is_last = false; - else - is_last = true; - } - - if (is_last) { - s3c_hsudc_complete_request(hsep, hsreq, 0); - return 1; - } - - return 0; -} - -/** - * s3c_hsudc_read_fifo - Read the next chunk of data from EP fifo. - * @hsep: Endpoint from which the data is to be read. - * @hsreq: Transfer request to which the next chunk of data read is written. - * - * Read the next chunk of data from the endpoint FIFO and a write it to the - * transfer request buffer. If the transfer request completes, 1 is returned, - * otherwise 0 is returned. - */ -static int s3c_hsudc_read_fifo(struct s3c_hsudc_ep *hsep, - struct s3c_hsudc_req *hsreq) -{ - struct s3c_hsudc *hsudc = hsep->dev; - u32 csr, offset; - u16 *buf, word; - u32 buflen, rcnt, rlen; - void __iomem *fifo = hsep->fifo; - u32 is_short = 0; - - offset = (ep_index(hsep)) ? S3C_ESR : S3C_EP0SR; - csr = readl(hsudc->regs + offset); - if (!(csr & S3C_ESR_RX_SUCCESS)) - return -EINVAL; - - buf = hsreq->req.buf + hsreq->req.actual; - prefetchw(buf); - buflen = hsreq->req.length - hsreq->req.actual; - - rcnt = readl(hsudc->regs + S3C_BRCR); - rlen = (csr & S3C_ESR_LWO) ? (rcnt * 2 - 1) : (rcnt * 2); - - hsreq->req.actual += min(rlen, buflen); - is_short = (rlen < hsep->ep.maxpacket); - - while (rcnt-- != 0) { - word = (u16)readl(fifo); - if (buflen) { - *buf++ = word; - buflen--; - } else { - hsreq->req.status = -EOVERFLOW; - } - } - - writel(S3C_ESR_RX_SUCCESS, hsudc->regs + offset); - - if (is_short || hsreq->req.actual == hsreq->req.length) { - s3c_hsudc_complete_request(hsep, hsreq, 0); - return 1; - } - - return 0; -} - -/** - * s3c_hsudc_epin_intr - Handle in-endpoint interrupt. - * @hsudc - Device controller for which the interrupt is to be handled. - * @ep_idx - Endpoint number on which an interrupt is pending. - * - * Handles interrupt for a in-endpoint. The interrupts that are handled are - * stall and data transmit complete interrupt. - */ -static void s3c_hsudc_epin_intr(struct s3c_hsudc *hsudc, u32 ep_idx) -{ - struct s3c_hsudc_ep *hsep = &hsudc->ep[ep_idx]; - struct s3c_hsudc_req *hsreq; - u32 csr; - - csr = readl((u32)hsudc->regs + S3C_ESR); - if (csr & S3C_ESR_STALL) { - writel(S3C_ESR_STALL, hsudc->regs + S3C_ESR); - return; - } - - if (csr & S3C_ESR_TX_SUCCESS) { - writel(S3C_ESR_TX_SUCCESS, hsudc->regs + S3C_ESR); - if (list_empty(&hsep->queue)) - return; - - hsreq = list_entry(hsep->queue.next, - struct s3c_hsudc_req, queue); - if ((s3c_hsudc_write_fifo(hsep, hsreq) == 0) && - (csr & S3C_ESR_PSIF_TWO)) - s3c_hsudc_write_fifo(hsep, hsreq); - } -} - -/** - * s3c_hsudc_epout_intr - Handle out-endpoint interrupt. - * @hsudc - Device controller for which the interrupt is to be handled. - * @ep_idx - Endpoint number on which an interrupt is pending. - * - * Handles interrupt for a out-endpoint. The interrupts that are handled are - * stall, flush and data ready interrupt. - */ -static void s3c_hsudc_epout_intr(struct s3c_hsudc *hsudc, u32 ep_idx) -{ - struct s3c_hsudc_ep *hsep = &hsudc->ep[ep_idx]; - struct s3c_hsudc_req *hsreq; - u32 csr; - - csr = readl((u32)hsudc->regs + S3C_ESR); - if (csr & S3C_ESR_STALL) { - writel(S3C_ESR_STALL, hsudc->regs + S3C_ESR); - return; - } - - if (csr & S3C_ESR_FLUSH) { - __orr32(hsudc->regs + S3C_ECR, S3C_ECR_FLUSH); - return; - } - - if (csr & S3C_ESR_RX_SUCCESS) { - if (list_empty(&hsep->queue)) - return; - - hsreq = list_entry(hsep->queue.next, - struct s3c_hsudc_req, queue); - if (((s3c_hsudc_read_fifo(hsep, hsreq)) == 0) && - (csr & S3C_ESR_PSIF_TWO)) - s3c_hsudc_read_fifo(hsep, hsreq); - } -} - -/** s3c_hsudc_set_halt - Set or clear a endpoint halt. - * @_ep: Endpoint on which halt has to be set or cleared. - * @value: 1 for setting halt on endpoint, 0 to clear halt. - * - * Set or clear endpoint halt. If halt is set, the endpoint is stopped. - * If halt is cleared, for in-endpoints, if there are any pending - * transfer requests, transfers are started. - */ -static int s3c_hsudc_set_halt(struct usb_ep *_ep, int value) -{ - struct s3c_hsudc_ep *hsep = our_ep(_ep); - struct s3c_hsudc *hsudc = hsep->dev; - struct s3c_hsudc_req *hsreq; - unsigned long irqflags; - u32 ecr; - u32 offset; - - if (value && ep_is_in(hsep) && !list_empty(&hsep->queue)) - return -EAGAIN; - - spin_lock_irqsave(&hsudc->lock, irqflags); - set_index(hsudc, ep_index(hsep)); - offset = (ep_index(hsep)) ? S3C_ECR : S3C_EP0CR; - ecr = readl(hsudc->regs + offset); - - if (value) { - ecr |= S3C_ECR_STALL; - if (ep_index(hsep)) - ecr |= S3C_ECR_FLUSH; - hsep->stopped = 1; - } else { - ecr &= ~S3C_ECR_STALL; - hsep->stopped = hsep->wedge = 0; - } - writel(ecr, hsudc->regs + offset); - - if (ep_is_in(hsep) && !list_empty(&hsep->queue) && !value) { - hsreq = list_entry(hsep->queue.next, - struct s3c_hsudc_req, queue); - if (hsreq) - s3c_hsudc_write_fifo(hsep, hsreq); - } - - spin_unlock_irqrestore(&hsudc->lock, irqflags); - return 0; -} - -/** s3c_hsudc_set_wedge - Sets the halt feature with the clear requests ignored - * @_ep: Endpoint on which wedge has to be set. - * - * Sets the halt feature with the clear requests ignored. - */ -static int s3c_hsudc_set_wedge(struct usb_ep *_ep) -{ - struct s3c_hsudc_ep *hsep = our_ep(_ep); - - if (!hsep) - return -EINVAL; - - hsep->wedge = 1; - return usb_ep_set_halt(_ep); -} - -/** s3c_hsudc_handle_reqfeat - Handle set feature or clear feature requests. - * @_ep: Device controller on which the set/clear feature needs to be handled. - * @ctrl: Control request as received on the endpoint 0. - * - * Handle set feature or clear feature control requests on the control endpoint. - */ -static int s3c_hsudc_handle_reqfeat(struct s3c_hsudc *hsudc, - struct usb_ctrlrequest *ctrl) -{ - struct s3c_hsudc_ep *hsep; - bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE); - u8 ep_num = ctrl->wIndex & USB_ENDPOINT_NUMBER_MASK; - - if (ctrl->bRequestType == USB_RECIP_ENDPOINT) { - hsep = &hsudc->ep[ep_num]; - switch (le16_to_cpu(ctrl->wValue)) { - case USB_ENDPOINT_HALT: - if (set || (!set && !hsep->wedge)) - s3c_hsudc_set_halt(&hsep->ep, set); - return 0; - } - } - - return -ENOENT; -} - -/** - * s3c_hsudc_process_req_status - Handle get status control request. - * @hsudc: Device controller on which get status request has be handled. - * @ctrl: Control request as received on the endpoint 0. - * - * Handle get status control request received on control endpoint. - */ -static void s3c_hsudc_process_req_status(struct s3c_hsudc *hsudc, - struct usb_ctrlrequest *ctrl) -{ - struct s3c_hsudc_ep *hsep0 = &hsudc->ep[0]; - struct s3c_hsudc_req hsreq; - struct s3c_hsudc_ep *hsep; - __le16 reply; - u8 epnum; - - switch (ctrl->bRequestType & USB_RECIP_MASK) { - case USB_RECIP_DEVICE: - reply = cpu_to_le16(0); - break; - - case USB_RECIP_INTERFACE: - reply = cpu_to_le16(0); - break; - - case USB_RECIP_ENDPOINT: - epnum = le16_to_cpu(ctrl->wIndex) & USB_ENDPOINT_NUMBER_MASK; - hsep = &hsudc->ep[epnum]; - reply = cpu_to_le16(hsep->stopped ? 1 : 0); - break; - } - - INIT_LIST_HEAD(&hsreq.queue); - hsreq.req.length = 2; - hsreq.req.buf = &reply; - hsreq.req.actual = 0; - hsreq.req.complete = NULL; - s3c_hsudc_write_fifo(hsep0, &hsreq); -} - -/** - * s3c_hsudc_process_setup - Process control request received on endpoint 0. - * @hsudc: Device controller on which control request has been received. - * - * Read the control request received on endpoint 0, decode it and handle - * the request. - */ -static void s3c_hsudc_process_setup(struct s3c_hsudc *hsudc) -{ - struct s3c_hsudc_ep *hsep = &hsudc->ep[0]; - struct usb_ctrlrequest ctrl = {0}; - int ret; - - s3c_hsudc_nuke_ep(hsep, -EPROTO); - s3c_hsudc_read_setup_pkt(hsudc, (u16 *)&ctrl); - - if (ctrl.bRequestType & USB_DIR_IN) { - hsep->bEndpointAddress |= USB_DIR_IN; - hsudc->ep0state = DATA_STATE_XMIT; - } else { - hsep->bEndpointAddress &= ~USB_DIR_IN; - hsudc->ep0state = DATA_STATE_RECV; - } - - switch (ctrl.bRequest) { - case USB_REQ_SET_ADDRESS: - if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) - break; - hsudc->ep0state = WAIT_FOR_SETUP; - return; - - case USB_REQ_GET_STATUS: - if ((ctrl.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD) - break; - s3c_hsudc_process_req_status(hsudc, &ctrl); - return; - - case USB_REQ_SET_FEATURE: - case USB_REQ_CLEAR_FEATURE: - if ((ctrl.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD) - break; - s3c_hsudc_handle_reqfeat(hsudc, &ctrl); - hsudc->ep0state = WAIT_FOR_SETUP; - return; - } - - if (hsudc->driver) { - spin_unlock(&hsudc->lock); - ret = hsudc->driver->setup(&hsudc->gadget, &ctrl); - spin_lock(&hsudc->lock); - - if (ctrl.bRequest == USB_REQ_SET_CONFIGURATION) { - hsep->bEndpointAddress &= ~USB_DIR_IN; - hsudc->ep0state = WAIT_FOR_SETUP; - } - - if (ret < 0) { - dev_err(hsudc->dev, "setup failed, returned %d\n", - ret); - s3c_hsudc_set_halt(&hsep->ep, 1); - hsudc->ep0state = WAIT_FOR_SETUP; - hsep->bEndpointAddress &= ~USB_DIR_IN; - } - } -} - -/** s3c_hsudc_handle_ep0_intr - Handle endpoint 0 interrupt. - * @hsudc: Device controller on which endpoint 0 interrupt has occured. - * - * Handle endpoint 0 interrupt when it occurs. EP0 interrupt could occur - * when a stall handshake is sent to host or data is sent/received on - * endpoint 0. - */ -static void s3c_hsudc_handle_ep0_intr(struct s3c_hsudc *hsudc) -{ - struct s3c_hsudc_ep *hsep = &hsudc->ep[0]; - struct s3c_hsudc_req *hsreq; - u32 csr = readl(hsudc->regs + S3C_EP0SR); - u32 ecr; - - if (csr & S3C_EP0SR_STALL) { - ecr = readl(hsudc->regs + S3C_EP0CR); - ecr &= ~(S3C_ECR_STALL | S3C_ECR_FLUSH); - writel(ecr, hsudc->regs + S3C_EP0CR); - - writel(S3C_EP0SR_STALL, hsudc->regs + S3C_EP0SR); - hsep->stopped = 0; - - s3c_hsudc_nuke_ep(hsep, -ECONNABORTED); - hsudc->ep0state = WAIT_FOR_SETUP; - hsep->bEndpointAddress &= ~USB_DIR_IN; - return; - } - - if (csr & S3C_EP0SR_TX_SUCCESS) { - writel(S3C_EP0SR_TX_SUCCESS, hsudc->regs + S3C_EP0SR); - if (ep_is_in(hsep)) { - if (list_empty(&hsep->queue)) - return; - - hsreq = list_entry(hsep->queue.next, - struct s3c_hsudc_req, queue); - s3c_hsudc_write_fifo(hsep, hsreq); - } - } - - if (csr & S3C_EP0SR_RX_SUCCESS) { - if (hsudc->ep0state == WAIT_FOR_SETUP) - s3c_hsudc_process_setup(hsudc); - else { - if (!ep_is_in(hsep)) { - if (list_empty(&hsep->queue)) - return; - hsreq = list_entry(hsep->queue.next, - struct s3c_hsudc_req, queue); - s3c_hsudc_read_fifo(hsep, hsreq); - } - } - } -} - -/** - * s3c_hsudc_ep_enable - Enable a endpoint. - * @_ep: The endpoint to be enabled. - * @desc: Endpoint descriptor. - * - * Enables a endpoint when called from the gadget driver. Endpoint stall if - * any is cleared, transfer type is configured and endpoint interrupt is - * enabled. - */ -static int s3c_hsudc_ep_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct s3c_hsudc_ep *hsep; - struct s3c_hsudc *hsudc; - unsigned long flags; - u32 ecr = 0; - - hsep = our_ep(_ep); - if (!_ep || !desc || hsep->desc || _ep->name == ep0name - || desc->bDescriptorType != USB_DT_ENDPOINT - || hsep->bEndpointAddress != desc->bEndpointAddress - || ep_maxpacket(hsep) < usb_endpoint_maxp(desc)) - return -EINVAL; - - if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK - && usb_endpoint_maxp(desc) != ep_maxpacket(hsep)) - || !desc->wMaxPacketSize) - return -ERANGE; - - hsudc = hsep->dev; - if (!hsudc->driver || hsudc->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - spin_lock_irqsave(&hsudc->lock, flags); - - set_index(hsudc, hsep->bEndpointAddress); - ecr |= ((usb_endpoint_xfer_int(desc)) ? S3C_ECR_IEMS : S3C_ECR_DUEN); - writel(ecr, hsudc->regs + S3C_ECR); - - hsep->stopped = hsep->wedge = 0; - hsep->desc = desc; - hsep->ep.maxpacket = usb_endpoint_maxp(desc); - - s3c_hsudc_set_halt(_ep, 0); - __set_bit(ep_index(hsep), hsudc->regs + S3C_EIER); - - spin_unlock_irqrestore(&hsudc->lock, flags); - return 0; -} - -/** - * s3c_hsudc_ep_disable - Disable a endpoint. - * @_ep: The endpoint to be disabled. - * @desc: Endpoint descriptor. - * - * Disables a endpoint when called from the gadget driver. - */ -static int s3c_hsudc_ep_disable(struct usb_ep *_ep) -{ - struct s3c_hsudc_ep *hsep = our_ep(_ep); - struct s3c_hsudc *hsudc = hsep->dev; - unsigned long flags; - - if (!_ep || !hsep->desc) - return -EINVAL; - - spin_lock_irqsave(&hsudc->lock, flags); - - set_index(hsudc, hsep->bEndpointAddress); - __clear_bit(ep_index(hsep), hsudc->regs + S3C_EIER); - - s3c_hsudc_nuke_ep(hsep, -ESHUTDOWN); - - hsep->desc = 0; - hsep->ep.desc = NULL; - hsep->stopped = 1; - - spin_unlock_irqrestore(&hsudc->lock, flags); - return 0; -} - -/** - * s3c_hsudc_alloc_request - Allocate a new request. - * @_ep: Endpoint for which request is allocated (not used). - * @gfp_flags: Flags used for the allocation. - * - * Allocates a single transfer request structure when called from gadget driver. - */ -static struct usb_request *s3c_hsudc_alloc_request(struct usb_ep *_ep, - gfp_t gfp_flags) -{ - struct s3c_hsudc_req *hsreq; - - hsreq = kzalloc(sizeof *hsreq, gfp_flags); - if (!hsreq) - return 0; - - INIT_LIST_HEAD(&hsreq->queue); - return &hsreq->req; -} - -/** - * s3c_hsudc_free_request - Deallocate a request. - * @ep: Endpoint for which request is deallocated (not used). - * @_req: Request to be deallocated. - * - * Allocates a single transfer request structure when called from gadget driver. - */ -static void s3c_hsudc_free_request(struct usb_ep *ep, struct usb_request *_req) -{ - struct s3c_hsudc_req *hsreq; - - hsreq = our_req(_req); - WARN_ON(!list_empty(&hsreq->queue)); - kfree(hsreq); -} - -/** - * s3c_hsudc_queue - Queue a transfer request for the endpoint. - * @_ep: Endpoint for which the request is queued. - * @_req: Request to be queued. - * @gfp_flags: Not used. - * - * Start or enqueue a request for a endpoint when called from gadget driver. - */ -static int s3c_hsudc_queue(struct usb_ep *_ep, struct usb_request *_req, - gfp_t gfp_flags) -{ - struct s3c_hsudc_req *hsreq; - struct s3c_hsudc_ep *hsep; - struct s3c_hsudc *hsudc; - unsigned long flags; - u32 offset; - u32 csr; - - hsreq = our_req(_req); - if ((!_req || !_req->complete || !_req->buf || - !list_empty(&hsreq->queue))) - return -EINVAL; - - hsep = our_ep(_ep); - hsudc = hsep->dev; - if (!hsudc->driver || hsudc->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - spin_lock_irqsave(&hsudc->lock, flags); - set_index(hsudc, hsep->bEndpointAddress); - - _req->status = -EINPROGRESS; - _req->actual = 0; - - if (!ep_index(hsep) && _req->length == 0) { - hsudc->ep0state = WAIT_FOR_SETUP; - s3c_hsudc_complete_request(hsep, hsreq, 0); - spin_unlock_irqrestore(&hsudc->lock, flags); - return 0; - } - - if (list_empty(&hsep->queue) && !hsep->stopped) { - offset = (ep_index(hsep)) ? S3C_ESR : S3C_EP0SR; - if (ep_is_in(hsep)) { - csr = readl((u32)hsudc->regs + offset); - if (!(csr & S3C_ESR_TX_SUCCESS) && - (s3c_hsudc_write_fifo(hsep, hsreq) == 1)) - hsreq = 0; - } else { - csr = readl((u32)hsudc->regs + offset); - if ((csr & S3C_ESR_RX_SUCCESS) - && (s3c_hsudc_read_fifo(hsep, hsreq) == 1)) - hsreq = 0; - } - } - - if (hsreq != 0) - list_add_tail(&hsreq->queue, &hsep->queue); - - spin_unlock_irqrestore(&hsudc->lock, flags); - return 0; -} - -/** - * s3c_hsudc_dequeue - Dequeue a transfer request from an endpoint. - * @_ep: Endpoint from which the request is dequeued. - * @_req: Request to be dequeued. - * - * Dequeue a request from a endpoint when called from gadget driver. - */ -static int s3c_hsudc_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct s3c_hsudc_ep *hsep = our_ep(_ep); - struct s3c_hsudc *hsudc = hsep->dev; - struct s3c_hsudc_req *hsreq; - unsigned long flags; - - hsep = our_ep(_ep); - if (!_ep || hsep->ep.name == ep0name) - return -EINVAL; - - spin_lock_irqsave(&hsudc->lock, flags); - - list_for_each_entry(hsreq, &hsep->queue, queue) { - if (&hsreq->req == _req) - break; - } - if (&hsreq->req != _req) { - spin_unlock_irqrestore(&hsudc->lock, flags); - return -EINVAL; - } - - set_index(hsudc, hsep->bEndpointAddress); - s3c_hsudc_complete_request(hsep, hsreq, -ECONNRESET); - - spin_unlock_irqrestore(&hsudc->lock, flags); - return 0; -} - -static struct usb_ep_ops s3c_hsudc_ep_ops = { - .enable = s3c_hsudc_ep_enable, - .disable = s3c_hsudc_ep_disable, - .alloc_request = s3c_hsudc_alloc_request, - .free_request = s3c_hsudc_free_request, - .queue = s3c_hsudc_queue, - .dequeue = s3c_hsudc_dequeue, - .set_halt = s3c_hsudc_set_halt, - .set_wedge = s3c_hsudc_set_wedge, -}; - -/** - * s3c_hsudc_initep - Initialize a endpoint to default state. - * @hsudc - Reference to the device controller. - * @hsep - Endpoint to be initialized. - * @epnum - Address to be assigned to the endpoint. - * - * Initialize a endpoint with default configuration. - */ -static void s3c_hsudc_initep(struct s3c_hsudc *hsudc, - struct s3c_hsudc_ep *hsep, int epnum) -{ - char *dir; - - if ((epnum % 2) == 0) { - dir = "out"; - } else { - dir = "in"; - hsep->bEndpointAddress = USB_DIR_IN; - } - - hsep->bEndpointAddress |= epnum; - if (epnum) - snprintf(hsep->name, sizeof(hsep->name), "ep%d%s", epnum, dir); - else - snprintf(hsep->name, sizeof(hsep->name), "%s", ep0name); - - INIT_LIST_HEAD(&hsep->queue); - INIT_LIST_HEAD(&hsep->ep.ep_list); - if (epnum) - list_add_tail(&hsep->ep.ep_list, &hsudc->gadget.ep_list); - - hsep->dev = hsudc; - hsep->ep.name = hsep->name; - hsep->ep.maxpacket = epnum ? 512 : 64; - hsep->ep.ops = &s3c_hsudc_ep_ops; - hsep->fifo = hsudc->regs + S3C_BR(epnum); - hsep->desc = 0; - hsep->ep.desc = NULL; - hsep->stopped = 0; - hsep->wedge = 0; - - set_index(hsudc, epnum); - writel(hsep->ep.maxpacket, hsudc->regs + S3C_MPR); -} - -/** - * s3c_hsudc_setup_ep - Configure all endpoints to default state. - * @hsudc: Reference to device controller. - * - * Configures all endpoints to default state. - */ -static void s3c_hsudc_setup_ep(struct s3c_hsudc *hsudc) -{ - int epnum; - - hsudc->ep0state = WAIT_FOR_SETUP; - INIT_LIST_HEAD(&hsudc->gadget.ep_list); - for (epnum = 0; epnum < hsudc->pd->epnum; epnum++) - s3c_hsudc_initep(hsudc, &hsudc->ep[epnum], epnum); -} - -/** - * s3c_hsudc_reconfig - Reconfigure the device controller to default state. - * @hsudc: Reference to device controller. - * - * Reconfigures the device controller registers to a default state. - */ -static void s3c_hsudc_reconfig(struct s3c_hsudc *hsudc) -{ - writel(0xAA, hsudc->regs + S3C_EDR); - writel(1, hsudc->regs + S3C_EIER); - writel(0, hsudc->regs + S3C_TR); - writel(S3C_SCR_DTZIEN_EN | S3C_SCR_RRD_EN | S3C_SCR_SUS_EN | - S3C_SCR_RST_EN, hsudc->regs + S3C_SCR); - writel(0, hsudc->regs + S3C_EP0CR); - - s3c_hsudc_setup_ep(hsudc); -} - -/** - * s3c_hsudc_irq - Interrupt handler for device controller. - * @irq: Not used. - * @_dev: Reference to the device controller. - * - * Interrupt handler for the device controller. This handler handles controller - * interrupts and endpoint interrupts. - */ -static irqreturn_t s3c_hsudc_irq(int irq, void *_dev) -{ - struct s3c_hsudc *hsudc = _dev; - struct s3c_hsudc_ep *hsep; - u32 ep_intr; - u32 sys_status; - u32 ep_idx; - - spin_lock(&hsudc->lock); - - sys_status = readl(hsudc->regs + S3C_SSR); - ep_intr = readl(hsudc->regs + S3C_EIR) & 0x3FF; - - if (!ep_intr && !(sys_status & S3C_SSR_DTZIEN_EN)) { - spin_unlock(&hsudc->lock); - return IRQ_HANDLED; - } - - if (sys_status) { - if (sys_status & S3C_SSR_VBUSON) - writel(S3C_SSR_VBUSON, hsudc->regs + S3C_SSR); - - if (sys_status & S3C_SSR_ERR) - writel(S3C_SSR_ERR, hsudc->regs + S3C_SSR); - - if (sys_status & S3C_SSR_SDE) { - writel(S3C_SSR_SDE, hsudc->regs + S3C_SSR); - hsudc->gadget.speed = (sys_status & S3C_SSR_HSP) ? - USB_SPEED_HIGH : USB_SPEED_FULL; - } - - if (sys_status & S3C_SSR_SUSPEND) { - writel(S3C_SSR_SUSPEND, hsudc->regs + S3C_SSR); - if (hsudc->gadget.speed != USB_SPEED_UNKNOWN - && hsudc->driver && hsudc->driver->suspend) - hsudc->driver->suspend(&hsudc->gadget); - } - - if (sys_status & S3C_SSR_RESUME) { - writel(S3C_SSR_RESUME, hsudc->regs + S3C_SSR); - if (hsudc->gadget.speed != USB_SPEED_UNKNOWN - && hsudc->driver && hsudc->driver->resume) - hsudc->driver->resume(&hsudc->gadget); - } - - if (sys_status & S3C_SSR_RESET) { - writel(S3C_SSR_RESET, hsudc->regs + S3C_SSR); - for (ep_idx = 0; ep_idx < hsudc->pd->epnum; ep_idx++) { - hsep = &hsudc->ep[ep_idx]; - hsep->stopped = 1; - s3c_hsudc_nuke_ep(hsep, -ECONNRESET); - } - s3c_hsudc_reconfig(hsudc); - hsudc->ep0state = WAIT_FOR_SETUP; - } - } - - if (ep_intr & S3C_EIR_EP0) { - writel(S3C_EIR_EP0, hsudc->regs + S3C_EIR); - set_index(hsudc, 0); - s3c_hsudc_handle_ep0_intr(hsudc); - } - - ep_intr >>= 1; - ep_idx = 1; - while (ep_intr) { - if (ep_intr & 1) { - hsep = &hsudc->ep[ep_idx]; - set_index(hsudc, ep_idx); - writel(1 << ep_idx, hsudc->regs + S3C_EIR); - if (ep_is_in(hsep)) - s3c_hsudc_epin_intr(hsudc, ep_idx); - else - s3c_hsudc_epout_intr(hsudc, ep_idx); - } - ep_intr >>= 1; - ep_idx++; - } - - spin_unlock(&hsudc->lock); - return IRQ_HANDLED; -} - -static int s3c_hsudc_start(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) -{ - struct s3c_hsudc *hsudc = to_hsudc(gadget); - int ret; - - if (!driver - || driver->max_speed < USB_SPEED_FULL - || !driver->setup) - return -EINVAL; - - if (!hsudc) - return -ENODEV; - - if (hsudc->driver) - return -EBUSY; - - hsudc->driver = driver; - hsudc->gadget.dev.driver = &driver->driver; - - ret = regulator_bulk_enable(ARRAY_SIZE(hsudc->supplies), - hsudc->supplies); - if (ret != 0) { - dev_err(hsudc->dev, "failed to enable supplies: %d\n", ret); - goto err_supplies; - } - - /* connect to bus through transceiver */ - if (hsudc->transceiver) { - ret = otg_set_peripheral(hsudc->transceiver->otg, - &hsudc->gadget); - if (ret) { - dev_err(hsudc->dev, "%s: can't bind to transceiver\n", - hsudc->gadget.name); - goto err_otg; - } - } - - enable_irq(hsudc->irq); - dev_info(hsudc->dev, "bound driver %s\n", driver->driver.name); - - s3c_hsudc_reconfig(hsudc); - - pm_runtime_get_sync(hsudc->dev); - - s3c_hsudc_init_phy(); - if (hsudc->pd->gpio_init) - hsudc->pd->gpio_init(); - - return 0; -err_otg: - regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies); -err_supplies: - hsudc->driver = NULL; - hsudc->gadget.dev.driver = NULL; - return ret; -} - -static int s3c_hsudc_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) -{ - struct s3c_hsudc *hsudc = to_hsudc(gadget); - unsigned long flags; - - if (!hsudc) - return -ENODEV; - - if (!driver || driver != hsudc->driver) - return -EINVAL; - - spin_lock_irqsave(&hsudc->lock, flags); - hsudc->driver = NULL; - hsudc->gadget.dev.driver = NULL; - hsudc->gadget.speed = USB_SPEED_UNKNOWN; - s3c_hsudc_uninit_phy(); - - pm_runtime_put(hsudc->dev); - - if (hsudc->pd->gpio_uninit) - hsudc->pd->gpio_uninit(); - s3c_hsudc_stop_activity(hsudc); - spin_unlock_irqrestore(&hsudc->lock, flags); - - if (hsudc->transceiver) - (void) otg_set_peripheral(hsudc->transceiver->otg, NULL); - - disable_irq(hsudc->irq); - - regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies); - - dev_info(hsudc->dev, "unregistered gadget driver '%s'\n", - driver->driver.name); - return 0; -} - -static inline u32 s3c_hsudc_read_frameno(struct s3c_hsudc *hsudc) -{ - return readl(hsudc->regs + S3C_FNR) & 0x3FF; -} - -static int s3c_hsudc_gadget_getframe(struct usb_gadget *gadget) -{ - return s3c_hsudc_read_frameno(to_hsudc(gadget)); -} - -static int s3c_hsudc_vbus_draw(struct usb_gadget *gadget, unsigned mA) -{ - struct s3c_hsudc *hsudc = to_hsudc(gadget); - - if (!hsudc) - return -ENODEV; - - if (hsudc->transceiver) - return usb_phy_set_power(hsudc->transceiver, mA); - - return -EOPNOTSUPP; -} - -static struct usb_gadget_ops s3c_hsudc_gadget_ops = { - .get_frame = s3c_hsudc_gadget_getframe, - .udc_start = s3c_hsudc_start, - .udc_stop = s3c_hsudc_stop, - .vbus_draw = s3c_hsudc_vbus_draw, -}; - -static int __devinit s3c_hsudc_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct resource *res; - struct s3c_hsudc *hsudc; - struct s3c24xx_hsudc_platdata *pd = pdev->dev.platform_data; - int ret, i; - - hsudc = kzalloc(sizeof(struct s3c_hsudc) + - sizeof(struct s3c_hsudc_ep) * pd->epnum, - GFP_KERNEL); - if (!hsudc) { - dev_err(dev, "cannot allocate memory\n"); - return -ENOMEM; - } - - platform_set_drvdata(pdev, dev); - hsudc->dev = dev; - hsudc->pd = pdev->dev.platform_data; - - hsudc->transceiver = usb_get_transceiver(); - - for (i = 0; i < ARRAY_SIZE(hsudc->supplies); i++) - hsudc->supplies[i].supply = s3c_hsudc_supply_names[i]; - - ret = regulator_bulk_get(dev, ARRAY_SIZE(hsudc->supplies), - hsudc->supplies); - if (ret != 0) { - dev_err(dev, "failed to request supplies: %d\n", ret); - goto err_supplies; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "unable to obtain driver resource data\n"); - ret = -ENODEV; - goto err_res; - } - - hsudc->mem_rsrc = request_mem_region(res->start, resource_size(res), - dev_name(&pdev->dev)); - if (!hsudc->mem_rsrc) { - dev_err(dev, "failed to reserve register area\n"); - ret = -ENODEV; - goto err_res; - } - - hsudc->regs = ioremap(res->start, resource_size(res)); - if (!hsudc->regs) { - dev_err(dev, "error mapping device register area\n"); - ret = -EBUSY; - goto err_remap; - } - - spin_lock_init(&hsudc->lock); - - dev_set_name(&hsudc->gadget.dev, "gadget"); - - hsudc->gadget.max_speed = USB_SPEED_HIGH; - hsudc->gadget.ops = &s3c_hsudc_gadget_ops; - hsudc->gadget.name = dev_name(dev); - hsudc->gadget.dev.parent = dev; - hsudc->gadget.dev.dma_mask = dev->dma_mask; - hsudc->gadget.ep0 = &hsudc->ep[0].ep; - - hsudc->gadget.is_otg = 0; - hsudc->gadget.is_a_peripheral = 0; - hsudc->gadget.speed = USB_SPEED_UNKNOWN; - - s3c_hsudc_setup_ep(hsudc); - - ret = platform_get_irq(pdev, 0); - if (ret < 0) { - dev_err(dev, "unable to obtain IRQ number\n"); - goto err_irq; - } - hsudc->irq = ret; - - ret = request_irq(hsudc->irq, s3c_hsudc_irq, 0, driver_name, hsudc); - if (ret < 0) { - dev_err(dev, "irq request failed\n"); - goto err_irq; - } - - hsudc->uclk = clk_get(&pdev->dev, "usb-device"); - if (IS_ERR(hsudc->uclk)) { - dev_err(dev, "failed to find usb-device clock source\n"); - ret = PTR_ERR(hsudc->uclk); - goto err_clk; - } - clk_enable(hsudc->uclk); - - local_irq_disable(); - - disable_irq(hsudc->irq); - local_irq_enable(); - - ret = device_register(&hsudc->gadget.dev); - if (ret) { - put_device(&hsudc->gadget.dev); - goto err_add_device; - } - - ret = usb_add_gadget_udc(&pdev->dev, &hsudc->gadget); - if (ret) - goto err_add_udc; - - pm_runtime_enable(dev); - - return 0; -err_add_udc: - device_unregister(&hsudc->gadget.dev); -err_add_device: - clk_disable(hsudc->uclk); - clk_put(hsudc->uclk); -err_clk: - free_irq(hsudc->irq, hsudc); -err_irq: - iounmap(hsudc->regs); - -err_remap: - release_mem_region(res->start, resource_size(res)); -err_res: - if (hsudc->transceiver) - usb_put_transceiver(hsudc->transceiver); - - regulator_bulk_free(ARRAY_SIZE(hsudc->supplies), hsudc->supplies); -err_supplies: - kfree(hsudc); - return ret; -} - -static struct platform_driver s3c_hsudc_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "s3c-hsudc", - }, - .probe = s3c_hsudc_probe, -}; - -module_platform_driver(s3c_hsudc_driver); - -MODULE_DESCRIPTION("Samsung S3C24XX USB high-speed controller driver"); -MODULE_AUTHOR("Thomas Abraham "); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:s3c-hsudc"); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/s3c2410_udc.c b/ANDROID_3.4.5/drivers/usb/gadget/s3c2410_udc.c deleted file mode 100644 index 195524cd..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/s3c2410_udc.c +++ /dev/null @@ -1,2106 +0,0 @@ -/* - * linux/drivers/usb/gadget/s3c2410_udc.c - * - * Samsung S3C24xx series on-chip full speed USB device controllers - * - * Copyright (C) 2004-2007 Herbert Pötzl - Arnaud Patard - * Additional cleanups by Ben Dooks - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include -#include - - -#include "s3c2410_udc.h" - -#define DRIVER_DESC "S3C2410 USB Device Controller Gadget" -#define DRIVER_VERSION "29 Apr 2007" -#define DRIVER_AUTHOR "Herbert Pötzl , " \ - "Arnaud Patard " - -static const char gadget_name[] = "s3c2410_udc"; -static const char driver_desc[] = DRIVER_DESC; - -static struct s3c2410_udc *the_controller; -static struct clk *udc_clock; -static struct clk *usb_bus_clock; -static void __iomem *base_addr; -static u64 rsrc_start; -static u64 rsrc_len; -static struct dentry *s3c2410_udc_debugfs_root; - -static inline u32 udc_read(u32 reg) -{ - return readb(base_addr + reg); -} - -static inline void udc_write(u32 value, u32 reg) -{ - writeb(value, base_addr + reg); -} - -static inline void udc_writeb(void __iomem *base, u32 value, u32 reg) -{ - writeb(value, base + reg); -} - -static struct s3c2410_udc_mach_info *udc_info; - -/*************************** DEBUG FUNCTION ***************************/ -#define DEBUG_NORMAL 1 -#define DEBUG_VERBOSE 2 - -#ifdef CONFIG_USB_S3C2410_DEBUG -#define USB_S3C2410_DEBUG_LEVEL 0 - -static uint32_t s3c2410_ticks = 0; - -static int dprintk(int level, const char *fmt, ...) -{ - static char printk_buf[1024]; - static long prevticks; - static int invocation; - va_list args; - int len; - - if (level > USB_S3C2410_DEBUG_LEVEL) - return 0; - - if (s3c2410_ticks != prevticks) { - prevticks = s3c2410_ticks; - invocation = 0; - } - - len = scnprintf(printk_buf, - sizeof(printk_buf), "%1lu.%02d USB: ", - prevticks, invocation++); - - va_start(args, fmt); - len = vscnprintf(printk_buf+len, - sizeof(printk_buf)-len, fmt, args); - va_end(args); - - return printk(KERN_DEBUG "%s", printk_buf); -} -#else -static int dprintk(int level, const char *fmt, ...) -{ - return 0; -} -#endif -static int s3c2410_udc_debugfs_seq_show(struct seq_file *m, void *p) -{ - u32 addr_reg,pwr_reg,ep_int_reg,usb_int_reg; - u32 ep_int_en_reg, usb_int_en_reg, ep0_csr; - u32 ep1_i_csr1,ep1_i_csr2,ep1_o_csr1,ep1_o_csr2; - u32 ep2_i_csr1,ep2_i_csr2,ep2_o_csr1,ep2_o_csr2; - - addr_reg = udc_read(S3C2410_UDC_FUNC_ADDR_REG); - pwr_reg = udc_read(S3C2410_UDC_PWR_REG); - ep_int_reg = udc_read(S3C2410_UDC_EP_INT_REG); - usb_int_reg = udc_read(S3C2410_UDC_USB_INT_REG); - ep_int_en_reg = udc_read(S3C2410_UDC_EP_INT_EN_REG); - usb_int_en_reg = udc_read(S3C2410_UDC_USB_INT_EN_REG); - udc_write(0, S3C2410_UDC_INDEX_REG); - ep0_csr = udc_read(S3C2410_UDC_IN_CSR1_REG); - udc_write(1, S3C2410_UDC_INDEX_REG); - ep1_i_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG); - ep1_i_csr2 = udc_read(S3C2410_UDC_IN_CSR2_REG); - ep1_o_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG); - ep1_o_csr2 = udc_read(S3C2410_UDC_IN_CSR2_REG); - udc_write(2, S3C2410_UDC_INDEX_REG); - ep2_i_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG); - ep2_i_csr2 = udc_read(S3C2410_UDC_IN_CSR2_REG); - ep2_o_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG); - ep2_o_csr2 = udc_read(S3C2410_UDC_IN_CSR2_REG); - - seq_printf(m, "FUNC_ADDR_REG : 0x%04X\n" - "PWR_REG : 0x%04X\n" - "EP_INT_REG : 0x%04X\n" - "USB_INT_REG : 0x%04X\n" - "EP_INT_EN_REG : 0x%04X\n" - "USB_INT_EN_REG : 0x%04X\n" - "EP0_CSR : 0x%04X\n" - "EP1_I_CSR1 : 0x%04X\n" - "EP1_I_CSR2 : 0x%04X\n" - "EP1_O_CSR1 : 0x%04X\n" - "EP1_O_CSR2 : 0x%04X\n" - "EP2_I_CSR1 : 0x%04X\n" - "EP2_I_CSR2 : 0x%04X\n" - "EP2_O_CSR1 : 0x%04X\n" - "EP2_O_CSR2 : 0x%04X\n", - addr_reg,pwr_reg,ep_int_reg,usb_int_reg, - ep_int_en_reg, usb_int_en_reg, ep0_csr, - ep1_i_csr1,ep1_i_csr2,ep1_o_csr1,ep1_o_csr2, - ep2_i_csr1,ep2_i_csr2,ep2_o_csr1,ep2_o_csr2 - ); - - return 0; -} - -static int s3c2410_udc_debugfs_fops_open(struct inode *inode, - struct file *file) -{ - return single_open(file, s3c2410_udc_debugfs_seq_show, NULL); -} - -static const struct file_operations s3c2410_udc_debugfs_fops = { - .open = s3c2410_udc_debugfs_fops_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -/* io macros */ - -static inline void s3c2410_udc_clear_ep0_opr(void __iomem *base) -{ - udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); - udc_writeb(base, S3C2410_UDC_EP0_CSR_SOPKTRDY, - S3C2410_UDC_EP0_CSR_REG); -} - -static inline void s3c2410_udc_clear_ep0_sst(void __iomem *base) -{ - udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); - writeb(0x00, base + S3C2410_UDC_EP0_CSR_REG); -} - -static inline void s3c2410_udc_clear_ep0_se(void __iomem *base) -{ - udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); - udc_writeb(base, S3C2410_UDC_EP0_CSR_SSE, S3C2410_UDC_EP0_CSR_REG); -} - -static inline void s3c2410_udc_set_ep0_ipr(void __iomem *base) -{ - udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); - udc_writeb(base, S3C2410_UDC_EP0_CSR_IPKRDY, S3C2410_UDC_EP0_CSR_REG); -} - -static inline void s3c2410_udc_set_ep0_de(void __iomem *base) -{ - udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); - udc_writeb(base, S3C2410_UDC_EP0_CSR_DE, S3C2410_UDC_EP0_CSR_REG); -} - -inline void s3c2410_udc_set_ep0_ss(void __iomem *b) -{ - udc_writeb(b, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); - udc_writeb(b, S3C2410_UDC_EP0_CSR_SENDSTL, S3C2410_UDC_EP0_CSR_REG); -} - -static inline void s3c2410_udc_set_ep0_de_out(void __iomem *base) -{ - udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); - - udc_writeb(base,(S3C2410_UDC_EP0_CSR_SOPKTRDY - | S3C2410_UDC_EP0_CSR_DE), - S3C2410_UDC_EP0_CSR_REG); -} - -static inline void s3c2410_udc_set_ep0_sse_out(void __iomem *base) -{ - udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); - udc_writeb(base, (S3C2410_UDC_EP0_CSR_SOPKTRDY - | S3C2410_UDC_EP0_CSR_SSE), - S3C2410_UDC_EP0_CSR_REG); -} - -static inline void s3c2410_udc_set_ep0_de_in(void __iomem *base) -{ - udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); - udc_writeb(base, (S3C2410_UDC_EP0_CSR_IPKRDY - | S3C2410_UDC_EP0_CSR_DE), - S3C2410_UDC_EP0_CSR_REG); -} - -/*------------------------- I/O ----------------------------------*/ - -/* - * s3c2410_udc_done - */ -static void s3c2410_udc_done(struct s3c2410_ep *ep, - struct s3c2410_request *req, int status) -{ - unsigned halted = ep->halted; - - list_del_init(&req->queue); - - if (likely (req->req.status == -EINPROGRESS)) - req->req.status = status; - else - status = req->req.status; - - ep->halted = 1; - req->req.complete(&ep->ep, &req->req); - ep->halted = halted; -} - -static void s3c2410_udc_nuke(struct s3c2410_udc *udc, - struct s3c2410_ep *ep, int status) -{ - /* Sanity check */ - if (&ep->queue == NULL) - return; - - while (!list_empty (&ep->queue)) { - struct s3c2410_request *req; - req = list_entry (ep->queue.next, struct s3c2410_request, - queue); - s3c2410_udc_done(ep, req, status); - } -} - -static inline void s3c2410_udc_clear_ep_state(struct s3c2410_udc *dev) -{ - unsigned i; - - /* hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint - * fifos, and pending transactions mustn't be continued in any case. - */ - - for (i = 1; i < S3C2410_ENDPOINTS; i++) - s3c2410_udc_nuke(dev, &dev->ep[i], -ECONNABORTED); -} - -static inline int s3c2410_udc_fifo_count_out(void) -{ - int tmp; - - tmp = udc_read(S3C2410_UDC_OUT_FIFO_CNT2_REG) << 8; - tmp |= udc_read(S3C2410_UDC_OUT_FIFO_CNT1_REG); - return tmp; -} - -/* - * s3c2410_udc_write_packet - */ -static inline int s3c2410_udc_write_packet(int fifo, - struct s3c2410_request *req, - unsigned max) -{ - unsigned len = min(req->req.length - req->req.actual, max); - u8 *buf = req->req.buf + req->req.actual; - - prefetch(buf); - - dprintk(DEBUG_VERBOSE, "%s %d %d %d %d\n", __func__, - req->req.actual, req->req.length, len, req->req.actual + len); - - req->req.actual += len; - - udelay(5); - writesb(base_addr + fifo, buf, len); - return len; -} - -/* - * s3c2410_udc_write_fifo - * - * return: 0 = still running, 1 = completed, negative = errno - */ -static int s3c2410_udc_write_fifo(struct s3c2410_ep *ep, - struct s3c2410_request *req) -{ - unsigned count; - int is_last; - u32 idx; - int fifo_reg; - u32 ep_csr; - - idx = ep->bEndpointAddress & 0x7F; - switch (idx) { - default: - idx = 0; - case 0: - fifo_reg = S3C2410_UDC_EP0_FIFO_REG; - break; - case 1: - fifo_reg = S3C2410_UDC_EP1_FIFO_REG; - break; - case 2: - fifo_reg = S3C2410_UDC_EP2_FIFO_REG; - break; - case 3: - fifo_reg = S3C2410_UDC_EP3_FIFO_REG; - break; - case 4: - fifo_reg = S3C2410_UDC_EP4_FIFO_REG; - break; - } - - count = s3c2410_udc_write_packet(fifo_reg, req, ep->ep.maxpacket); - - /* last packet is often short (sometimes a zlp) */ - if (count != ep->ep.maxpacket) - is_last = 1; - else if (req->req.length != req->req.actual || req->req.zero) - is_last = 0; - else - is_last = 2; - - /* Only ep0 debug messages are interesting */ - if (idx == 0) - dprintk(DEBUG_NORMAL, - "Written ep%d %d.%d of %d b [last %d,z %d]\n", - idx, count, req->req.actual, req->req.length, - is_last, req->req.zero); - - if (is_last) { - /* The order is important. It prevents sending 2 packets - * at the same time */ - - if (idx == 0) { - /* Reset signal => no need to say 'data sent' */ - if (! (udc_read(S3C2410_UDC_USB_INT_REG) - & S3C2410_UDC_USBINT_RESET)) - s3c2410_udc_set_ep0_de_in(base_addr); - ep->dev->ep0state=EP0_IDLE; - } else { - udc_write(idx, S3C2410_UDC_INDEX_REG); - ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG); - udc_write(idx, S3C2410_UDC_INDEX_REG); - udc_write(ep_csr | S3C2410_UDC_ICSR1_PKTRDY, - S3C2410_UDC_IN_CSR1_REG); - } - - s3c2410_udc_done(ep, req, 0); - is_last = 1; - } else { - if (idx == 0) { - /* Reset signal => no need to say 'data sent' */ - if (! (udc_read(S3C2410_UDC_USB_INT_REG) - & S3C2410_UDC_USBINT_RESET)) - s3c2410_udc_set_ep0_ipr(base_addr); - } else { - udc_write(idx, S3C2410_UDC_INDEX_REG); - ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG); - udc_write(idx, S3C2410_UDC_INDEX_REG); - udc_write(ep_csr | S3C2410_UDC_ICSR1_PKTRDY, - S3C2410_UDC_IN_CSR1_REG); - } - } - - return is_last; -} - -static inline int s3c2410_udc_read_packet(int fifo, u8 *buf, - struct s3c2410_request *req, unsigned avail) -{ - unsigned len; - - len = min(req->req.length - req->req.actual, avail); - req->req.actual += len; - - readsb(fifo + base_addr, buf, len); - return len; -} - -/* - * return: 0 = still running, 1 = queue empty, negative = errno - */ -static int s3c2410_udc_read_fifo(struct s3c2410_ep *ep, - struct s3c2410_request *req) -{ - u8 *buf; - u32 ep_csr; - unsigned bufferspace; - int is_last=1; - unsigned avail; - int fifo_count = 0; - u32 idx; - int fifo_reg; - - idx = ep->bEndpointAddress & 0x7F; - - switch (idx) { - default: - idx = 0; - case 0: - fifo_reg = S3C2410_UDC_EP0_FIFO_REG; - break; - case 1: - fifo_reg = S3C2410_UDC_EP1_FIFO_REG; - break; - case 2: - fifo_reg = S3C2410_UDC_EP2_FIFO_REG; - break; - case 3: - fifo_reg = S3C2410_UDC_EP3_FIFO_REG; - break; - case 4: - fifo_reg = S3C2410_UDC_EP4_FIFO_REG; - break; - } - - if (!req->req.length) - return 1; - - buf = req->req.buf + req->req.actual; - bufferspace = req->req.length - req->req.actual; - if (!bufferspace) { - dprintk(DEBUG_NORMAL, "%s: buffer full!\n", __func__); - return -1; - } - - udc_write(idx, S3C2410_UDC_INDEX_REG); - - fifo_count = s3c2410_udc_fifo_count_out(); - dprintk(DEBUG_NORMAL, "%s fifo count : %d\n", __func__, fifo_count); - - if (fifo_count > ep->ep.maxpacket) - avail = ep->ep.maxpacket; - else - avail = fifo_count; - - fifo_count = s3c2410_udc_read_packet(fifo_reg, buf, req, avail); - - /* checking this with ep0 is not accurate as we already - * read a control request - **/ - if (idx != 0 && fifo_count < ep->ep.maxpacket) { - is_last = 1; - /* overflowed this request? flush extra data */ - if (fifo_count != avail) - req->req.status = -EOVERFLOW; - } else { - is_last = (req->req.length <= req->req.actual) ? 1 : 0; - } - - udc_write(idx, S3C2410_UDC_INDEX_REG); - fifo_count = s3c2410_udc_fifo_count_out(); - - /* Only ep0 debug messages are interesting */ - if (idx == 0) - dprintk(DEBUG_VERBOSE, "%s fifo count : %d [last %d]\n", - __func__, fifo_count,is_last); - - if (is_last) { - if (idx == 0) { - s3c2410_udc_set_ep0_de_out(base_addr); - ep->dev->ep0state = EP0_IDLE; - } else { - udc_write(idx, S3C2410_UDC_INDEX_REG); - ep_csr = udc_read(S3C2410_UDC_OUT_CSR1_REG); - udc_write(idx, S3C2410_UDC_INDEX_REG); - udc_write(ep_csr & ~S3C2410_UDC_OCSR1_PKTRDY, - S3C2410_UDC_OUT_CSR1_REG); - } - - s3c2410_udc_done(ep, req, 0); - } else { - if (idx == 0) { - s3c2410_udc_clear_ep0_opr(base_addr); - } else { - udc_write(idx, S3C2410_UDC_INDEX_REG); - ep_csr = udc_read(S3C2410_UDC_OUT_CSR1_REG); - udc_write(idx, S3C2410_UDC_INDEX_REG); - udc_write(ep_csr & ~S3C2410_UDC_OCSR1_PKTRDY, - S3C2410_UDC_OUT_CSR1_REG); - } - } - - return is_last; -} - -static int s3c2410_udc_read_fifo_crq(struct usb_ctrlrequest *crq) -{ - unsigned char *outbuf = (unsigned char*)crq; - int bytes_read = 0; - - udc_write(0, S3C2410_UDC_INDEX_REG); - - bytes_read = s3c2410_udc_fifo_count_out(); - - dprintk(DEBUG_NORMAL, "%s: fifo_count=%d\n", __func__, bytes_read); - - if (bytes_read > sizeof(struct usb_ctrlrequest)) - bytes_read = sizeof(struct usb_ctrlrequest); - - readsb(S3C2410_UDC_EP0_FIFO_REG + base_addr, outbuf, bytes_read); - - dprintk(DEBUG_VERBOSE, "%s: len=%d %02x:%02x {%x,%x,%x}\n", __func__, - bytes_read, crq->bRequest, crq->bRequestType, - crq->wValue, crq->wIndex, crq->wLength); - - return bytes_read; -} - -static int s3c2410_udc_get_status(struct s3c2410_udc *dev, - struct usb_ctrlrequest *crq) -{ - u16 status = 0; - u8 ep_num = crq->wIndex & 0x7F; - u8 is_in = crq->wIndex & USB_DIR_IN; - - switch (crq->bRequestType & USB_RECIP_MASK) { - case USB_RECIP_INTERFACE: - break; - - case USB_RECIP_DEVICE: - status = dev->devstatus; - break; - - case USB_RECIP_ENDPOINT: - if (ep_num > 4 || crq->wLength > 2) - return 1; - - if (ep_num == 0) { - udc_write(0, S3C2410_UDC_INDEX_REG); - status = udc_read(S3C2410_UDC_IN_CSR1_REG); - status = status & S3C2410_UDC_EP0_CSR_SENDSTL; - } else { - udc_write(ep_num, S3C2410_UDC_INDEX_REG); - if (is_in) { - status = udc_read(S3C2410_UDC_IN_CSR1_REG); - status = status & S3C2410_UDC_ICSR1_SENDSTL; - } else { - status = udc_read(S3C2410_UDC_OUT_CSR1_REG); - status = status & S3C2410_UDC_OCSR1_SENDSTL; - } - } - - status = status ? 1 : 0; - break; - - default: - return 1; - } - - /* Seems to be needed to get it working. ouch :( */ - udelay(5); - udc_write(status & 0xFF, S3C2410_UDC_EP0_FIFO_REG); - udc_write(status >> 8, S3C2410_UDC_EP0_FIFO_REG); - s3c2410_udc_set_ep0_de_in(base_addr); - - return 0; -} -/*------------------------- usb state machine -------------------------------*/ -static int s3c2410_udc_set_halt(struct usb_ep *_ep, int value); - -static void s3c2410_udc_handle_ep0_idle(struct s3c2410_udc *dev, - struct s3c2410_ep *ep, - struct usb_ctrlrequest *crq, - u32 ep0csr) -{ - int len, ret, tmp; - - /* start control request? */ - if (!(ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY)) - return; - - s3c2410_udc_nuke(dev, ep, -EPROTO); - - len = s3c2410_udc_read_fifo_crq(crq); - if (len != sizeof(*crq)) { - dprintk(DEBUG_NORMAL, "setup begin: fifo READ ERROR" - " wanted %d bytes got %d. Stalling out...\n", - sizeof(*crq), len); - s3c2410_udc_set_ep0_ss(base_addr); - return; - } - - dprintk(DEBUG_NORMAL, "bRequest = %d bRequestType %d wLength = %d\n", - crq->bRequest, crq->bRequestType, crq->wLength); - - /* cope with automagic for some standard requests. */ - dev->req_std = (crq->bRequestType & USB_TYPE_MASK) - == USB_TYPE_STANDARD; - dev->req_config = 0; - dev->req_pending = 1; - - switch (crq->bRequest) { - case USB_REQ_SET_CONFIGURATION: - dprintk(DEBUG_NORMAL, "USB_REQ_SET_CONFIGURATION ... \n"); - - if (crq->bRequestType == USB_RECIP_DEVICE) { - dev->req_config = 1; - s3c2410_udc_set_ep0_de_out(base_addr); - } - break; - - case USB_REQ_SET_INTERFACE: - dprintk(DEBUG_NORMAL, "USB_REQ_SET_INTERFACE ... \n"); - - if (crq->bRequestType == USB_RECIP_INTERFACE) { - dev->req_config = 1; - s3c2410_udc_set_ep0_de_out(base_addr); - } - break; - - case USB_REQ_SET_ADDRESS: - dprintk(DEBUG_NORMAL, "USB_REQ_SET_ADDRESS ... \n"); - - if (crq->bRequestType == USB_RECIP_DEVICE) { - tmp = crq->wValue & 0x7F; - dev->address = tmp; - udc_write((tmp | S3C2410_UDC_FUNCADDR_UPDATE), - S3C2410_UDC_FUNC_ADDR_REG); - s3c2410_udc_set_ep0_de_out(base_addr); - return; - } - break; - - case USB_REQ_GET_STATUS: - dprintk(DEBUG_NORMAL, "USB_REQ_GET_STATUS ... \n"); - s3c2410_udc_clear_ep0_opr(base_addr); - - if (dev->req_std) { - if (!s3c2410_udc_get_status(dev, crq)) { - return; - } - } - break; - - case USB_REQ_CLEAR_FEATURE: - s3c2410_udc_clear_ep0_opr(base_addr); - - if (crq->bRequestType != USB_RECIP_ENDPOINT) - break; - - if (crq->wValue != USB_ENDPOINT_HALT || crq->wLength != 0) - break; - - s3c2410_udc_set_halt(&dev->ep[crq->wIndex & 0x7f].ep, 0); - s3c2410_udc_set_ep0_de_out(base_addr); - return; - - case USB_REQ_SET_FEATURE: - s3c2410_udc_clear_ep0_opr(base_addr); - - if (crq->bRequestType != USB_RECIP_ENDPOINT) - break; - - if (crq->wValue != USB_ENDPOINT_HALT || crq->wLength != 0) - break; - - s3c2410_udc_set_halt(&dev->ep[crq->wIndex & 0x7f].ep, 1); - s3c2410_udc_set_ep0_de_out(base_addr); - return; - - default: - s3c2410_udc_clear_ep0_opr(base_addr); - break; - } - - if (crq->bRequestType & USB_DIR_IN) - dev->ep0state = EP0_IN_DATA_PHASE; - else - dev->ep0state = EP0_OUT_DATA_PHASE; - - if (!dev->driver) - return; - - /* deliver the request to the gadget driver */ - ret = dev->driver->setup(&dev->gadget, crq); - if (ret < 0) { - if (dev->req_config) { - dprintk(DEBUG_NORMAL, "config change %02x fail %d?\n", - crq->bRequest, ret); - return; - } - - if (ret == -EOPNOTSUPP) - dprintk(DEBUG_NORMAL, "Operation not supported\n"); - else - dprintk(DEBUG_NORMAL, - "dev->driver->setup failed. (%d)\n", ret); - - udelay(5); - s3c2410_udc_set_ep0_ss(base_addr); - s3c2410_udc_set_ep0_de_out(base_addr); - dev->ep0state = EP0_IDLE; - /* deferred i/o == no response yet */ - } else if (dev->req_pending) { - dprintk(DEBUG_VERBOSE, "dev->req_pending... what now?\n"); - dev->req_pending=0; - } - - dprintk(DEBUG_VERBOSE, "ep0state %s\n", ep0states[dev->ep0state]); -} - -static void s3c2410_udc_handle_ep0(struct s3c2410_udc *dev) -{ - u32 ep0csr; - struct s3c2410_ep *ep = &dev->ep[0]; - struct s3c2410_request *req; - struct usb_ctrlrequest crq; - - if (list_empty(&ep->queue)) - req = NULL; - else - req = list_entry(ep->queue.next, struct s3c2410_request, queue); - - /* We make the assumption that S3C2410_UDC_IN_CSR1_REG equal to - * S3C2410_UDC_EP0_CSR_REG when index is zero */ - - udc_write(0, S3C2410_UDC_INDEX_REG); - ep0csr = udc_read(S3C2410_UDC_IN_CSR1_REG); - - dprintk(DEBUG_NORMAL, "ep0csr %x ep0state %s\n", - ep0csr, ep0states[dev->ep0state]); - - /* clear stall status */ - if (ep0csr & S3C2410_UDC_EP0_CSR_SENTSTL) { - s3c2410_udc_nuke(dev, ep, -EPIPE); - dprintk(DEBUG_NORMAL, "... clear SENT_STALL ...\n"); - s3c2410_udc_clear_ep0_sst(base_addr); - dev->ep0state = EP0_IDLE; - return; - } - - /* clear setup end */ - if (ep0csr & S3C2410_UDC_EP0_CSR_SE) { - dprintk(DEBUG_NORMAL, "... serviced SETUP_END ...\n"); - s3c2410_udc_nuke(dev, ep, 0); - s3c2410_udc_clear_ep0_se(base_addr); - dev->ep0state = EP0_IDLE; - } - - switch (dev->ep0state) { - case EP0_IDLE: - s3c2410_udc_handle_ep0_idle(dev, ep, &crq, ep0csr); - break; - - case EP0_IN_DATA_PHASE: /* GET_DESCRIPTOR etc */ - dprintk(DEBUG_NORMAL, "EP0_IN_DATA_PHASE ... what now?\n"); - if (!(ep0csr & S3C2410_UDC_EP0_CSR_IPKRDY) && req) { - s3c2410_udc_write_fifo(ep, req); - } - break; - - case EP0_OUT_DATA_PHASE: /* SET_DESCRIPTOR etc */ - dprintk(DEBUG_NORMAL, "EP0_OUT_DATA_PHASE ... what now?\n"); - if ((ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY) && req ) { - s3c2410_udc_read_fifo(ep,req); - } - break; - - case EP0_END_XFER: - dprintk(DEBUG_NORMAL, "EP0_END_XFER ... what now?\n"); - dev->ep0state = EP0_IDLE; - break; - - case EP0_STALL: - dprintk(DEBUG_NORMAL, "EP0_STALL ... what now?\n"); - dev->ep0state = EP0_IDLE; - break; - } -} - -/* - * handle_ep - Manage I/O endpoints - */ - -static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep) -{ - struct s3c2410_request *req; - int is_in = ep->bEndpointAddress & USB_DIR_IN; - u32 ep_csr1; - u32 idx; - - if (likely (!list_empty(&ep->queue))) - req = list_entry(ep->queue.next, - struct s3c2410_request, queue); - else - req = NULL; - - idx = ep->bEndpointAddress & 0x7F; - - if (is_in) { - udc_write(idx, S3C2410_UDC_INDEX_REG); - ep_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG); - dprintk(DEBUG_VERBOSE, "ep%01d write csr:%02x %d\n", - idx, ep_csr1, req ? 1 : 0); - - if (ep_csr1 & S3C2410_UDC_ICSR1_SENTSTL) { - dprintk(DEBUG_VERBOSE, "st\n"); - udc_write(idx, S3C2410_UDC_INDEX_REG); - udc_write(ep_csr1 & ~S3C2410_UDC_ICSR1_SENTSTL, - S3C2410_UDC_IN_CSR1_REG); - return; - } - - if (!(ep_csr1 & S3C2410_UDC_ICSR1_PKTRDY) && req) { - s3c2410_udc_write_fifo(ep,req); - } - } else { - udc_write(idx, S3C2410_UDC_INDEX_REG); - ep_csr1 = udc_read(S3C2410_UDC_OUT_CSR1_REG); - dprintk(DEBUG_VERBOSE, "ep%01d rd csr:%02x\n", idx, ep_csr1); - - if (ep_csr1 & S3C2410_UDC_OCSR1_SENTSTL) { - udc_write(idx, S3C2410_UDC_INDEX_REG); - udc_write(ep_csr1 & ~S3C2410_UDC_OCSR1_SENTSTL, - S3C2410_UDC_OUT_CSR1_REG); - return; - } - - if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && req) { - s3c2410_udc_read_fifo(ep,req); - } - } -} - -#include - -/* - * s3c2410_udc_irq - interrupt handler - */ -static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev) -{ - struct s3c2410_udc *dev = _dev; - int usb_status; - int usbd_status; - int pwr_reg; - int ep0csr; - int i; - u32 idx, idx2; - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - - /* Driver connected ? */ - if (!dev->driver) { - /* Clear interrupts */ - udc_write(udc_read(S3C2410_UDC_USB_INT_REG), - S3C2410_UDC_USB_INT_REG); - udc_write(udc_read(S3C2410_UDC_EP_INT_REG), - S3C2410_UDC_EP_INT_REG); - } - - /* Save index */ - idx = udc_read(S3C2410_UDC_INDEX_REG); - - /* Read status registers */ - usb_status = udc_read(S3C2410_UDC_USB_INT_REG); - usbd_status = udc_read(S3C2410_UDC_EP_INT_REG); - pwr_reg = udc_read(S3C2410_UDC_PWR_REG); - - udc_writeb(base_addr, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG); - ep0csr = udc_read(S3C2410_UDC_IN_CSR1_REG); - - dprintk(DEBUG_NORMAL, "usbs=%02x, usbds=%02x, pwr=%02x ep0csr=%02x\n", - usb_status, usbd_status, pwr_reg, ep0csr); - - /* - * Now, handle interrupts. There's two types : - * - Reset, Resume, Suspend coming -> usb_int_reg - * - EP -> ep_int_reg - */ - - /* RESET */ - if (usb_status & S3C2410_UDC_USBINT_RESET) { - /* two kind of reset : - * - reset start -> pwr reg = 8 - * - reset end -> pwr reg = 0 - **/ - dprintk(DEBUG_NORMAL, "USB reset csr %x pwr %x\n", - ep0csr, pwr_reg); - - dev->gadget.speed = USB_SPEED_UNKNOWN; - udc_write(0x00, S3C2410_UDC_INDEX_REG); - udc_write((dev->ep[0].ep.maxpacket & 0x7ff) >> 3, - S3C2410_UDC_MAXP_REG); - dev->address = 0; - - dev->ep0state = EP0_IDLE; - dev->gadget.speed = USB_SPEED_FULL; - - /* clear interrupt */ - udc_write(S3C2410_UDC_USBINT_RESET, - S3C2410_UDC_USB_INT_REG); - - udc_write(idx, S3C2410_UDC_INDEX_REG); - spin_unlock_irqrestore(&dev->lock, flags); - return IRQ_HANDLED; - } - - /* RESUME */ - if (usb_status & S3C2410_UDC_USBINT_RESUME) { - dprintk(DEBUG_NORMAL, "USB resume\n"); - - /* clear interrupt */ - udc_write(S3C2410_UDC_USBINT_RESUME, - S3C2410_UDC_USB_INT_REG); - - if (dev->gadget.speed != USB_SPEED_UNKNOWN - && dev->driver - && dev->driver->resume) - dev->driver->resume(&dev->gadget); - } - - /* SUSPEND */ - if (usb_status & S3C2410_UDC_USBINT_SUSPEND) { - dprintk(DEBUG_NORMAL, "USB suspend\n"); - - /* clear interrupt */ - udc_write(S3C2410_UDC_USBINT_SUSPEND, - S3C2410_UDC_USB_INT_REG); - - if (dev->gadget.speed != USB_SPEED_UNKNOWN - && dev->driver - && dev->driver->suspend) - dev->driver->suspend(&dev->gadget); - - dev->ep0state = EP0_IDLE; - } - - /* EP */ - /* control traffic */ - /* check on ep0csr != 0 is not a good idea as clearing in_pkt_ready - * generate an interrupt - */ - if (usbd_status & S3C2410_UDC_INT_EP0) { - dprintk(DEBUG_VERBOSE, "USB ep0 irq\n"); - /* Clear the interrupt bit by setting it to 1 */ - udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_REG); - s3c2410_udc_handle_ep0(dev); - } - - /* endpoint data transfers */ - for (i = 1; i < S3C2410_ENDPOINTS; i++) { - u32 tmp = 1 << i; - if (usbd_status & tmp) { - dprintk(DEBUG_VERBOSE, "USB ep%d irq\n", i); - - /* Clear the interrupt bit by setting it to 1 */ - udc_write(tmp, S3C2410_UDC_EP_INT_REG); - s3c2410_udc_handle_ep(&dev->ep[i]); - } - } - - /* what else causes this interrupt? a receive! who is it? */ - if (!usb_status && !usbd_status && !pwr_reg && !ep0csr) { - for (i = 1; i < S3C2410_ENDPOINTS; i++) { - idx2 = udc_read(S3C2410_UDC_INDEX_REG); - udc_write(i, S3C2410_UDC_INDEX_REG); - - if (udc_read(S3C2410_UDC_OUT_CSR1_REG) & 0x1) - s3c2410_udc_handle_ep(&dev->ep[i]); - - /* restore index */ - udc_write(idx2, S3C2410_UDC_INDEX_REG); - } - } - - dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", IRQ_USBD); - - /* Restore old index */ - udc_write(idx, S3C2410_UDC_INDEX_REG); - - spin_unlock_irqrestore(&dev->lock, flags); - - return IRQ_HANDLED; -} -/*------------------------- s3c2410_ep_ops ----------------------------------*/ - -static inline struct s3c2410_ep *to_s3c2410_ep(struct usb_ep *ep) -{ - return container_of(ep, struct s3c2410_ep, ep); -} - -static inline struct s3c2410_udc *to_s3c2410_udc(struct usb_gadget *gadget) -{ - return container_of(gadget, struct s3c2410_udc, gadget); -} - -static inline struct s3c2410_request *to_s3c2410_req(struct usb_request *req) -{ - return container_of(req, struct s3c2410_request, req); -} - -/* - * s3c2410_udc_ep_enable - */ -static int s3c2410_udc_ep_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct s3c2410_udc *dev; - struct s3c2410_ep *ep; - u32 max, tmp; - unsigned long flags; - u32 csr1,csr2; - u32 int_en_reg; - - ep = to_s3c2410_ep(_ep); - - if (!_ep || !desc || ep->desc - || _ep->name == ep0name - || desc->bDescriptorType != USB_DT_ENDPOINT) - return -EINVAL; - - dev = ep->dev; - if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - max = usb_endpoint_maxp(desc) & 0x1fff; - - local_irq_save (flags); - _ep->maxpacket = max & 0x7ff; - ep->desc = desc; - ep->halted = 0; - ep->bEndpointAddress = desc->bEndpointAddress; - - /* set max packet */ - udc_write(ep->num, S3C2410_UDC_INDEX_REG); - udc_write(max >> 3, S3C2410_UDC_MAXP_REG); - - /* set type, direction, address; reset fifo counters */ - if (desc->bEndpointAddress & USB_DIR_IN) { - csr1 = S3C2410_UDC_ICSR1_FFLUSH|S3C2410_UDC_ICSR1_CLRDT; - csr2 = S3C2410_UDC_ICSR2_MODEIN|S3C2410_UDC_ICSR2_DMAIEN; - - udc_write(ep->num, S3C2410_UDC_INDEX_REG); - udc_write(csr1, S3C2410_UDC_IN_CSR1_REG); - udc_write(ep->num, S3C2410_UDC_INDEX_REG); - udc_write(csr2, S3C2410_UDC_IN_CSR2_REG); - } else { - /* don't flush in fifo or it will cause endpoint interrupt */ - csr1 = S3C2410_UDC_ICSR1_CLRDT; - csr2 = S3C2410_UDC_ICSR2_DMAIEN; - - udc_write(ep->num, S3C2410_UDC_INDEX_REG); - udc_write(csr1, S3C2410_UDC_IN_CSR1_REG); - udc_write(ep->num, S3C2410_UDC_INDEX_REG); - udc_write(csr2, S3C2410_UDC_IN_CSR2_REG); - - csr1 = S3C2410_UDC_OCSR1_FFLUSH | S3C2410_UDC_OCSR1_CLRDT; - csr2 = S3C2410_UDC_OCSR2_DMAIEN; - - udc_write(ep->num, S3C2410_UDC_INDEX_REG); - udc_write(csr1, S3C2410_UDC_OUT_CSR1_REG); - udc_write(ep->num, S3C2410_UDC_INDEX_REG); - udc_write(csr2, S3C2410_UDC_OUT_CSR2_REG); - } - - /* enable irqs */ - int_en_reg = udc_read(S3C2410_UDC_EP_INT_EN_REG); - udc_write(int_en_reg | (1 << ep->num), S3C2410_UDC_EP_INT_EN_REG); - - /* print some debug message */ - tmp = desc->bEndpointAddress; - dprintk (DEBUG_NORMAL, "enable %s(%d) ep%x%s-blk max %02x\n", - _ep->name,ep->num, tmp, - desc->bEndpointAddress & USB_DIR_IN ? "in" : "out", max); - - local_irq_restore (flags); - s3c2410_udc_set_halt(_ep, 0); - - return 0; -} - -/* - * s3c2410_udc_ep_disable - */ -static int s3c2410_udc_ep_disable(struct usb_ep *_ep) -{ - struct s3c2410_ep *ep = to_s3c2410_ep(_ep); - unsigned long flags; - u32 int_en_reg; - - if (!_ep || !ep->desc) { - dprintk(DEBUG_NORMAL, "%s not enabled\n", - _ep ? ep->ep.name : NULL); - return -EINVAL; - } - - local_irq_save(flags); - - dprintk(DEBUG_NORMAL, "ep_disable: %s\n", _ep->name); - - ep->desc = NULL; - ep->ep.desc = NULL; - ep->halted = 1; - - s3c2410_udc_nuke (ep->dev, ep, -ESHUTDOWN); - - /* disable irqs */ - int_en_reg = udc_read(S3C2410_UDC_EP_INT_EN_REG); - udc_write(int_en_reg & ~(1<num), S3C2410_UDC_EP_INT_EN_REG); - - local_irq_restore(flags); - - dprintk(DEBUG_NORMAL, "%s disabled\n", _ep->name); - - return 0; -} - -/* - * s3c2410_udc_alloc_request - */ -static struct usb_request * -s3c2410_udc_alloc_request(struct usb_ep *_ep, gfp_t mem_flags) -{ - struct s3c2410_request *req; - - dprintk(DEBUG_VERBOSE,"%s(%p,%d)\n", __func__, _ep, mem_flags); - - if (!_ep) - return NULL; - - req = kzalloc (sizeof(struct s3c2410_request), mem_flags); - if (!req) - return NULL; - - INIT_LIST_HEAD (&req->queue); - return &req->req; -} - -/* - * s3c2410_udc_free_request - */ -static void -s3c2410_udc_free_request(struct usb_ep *_ep, struct usb_request *_req) -{ - struct s3c2410_ep *ep = to_s3c2410_ep(_ep); - struct s3c2410_request *req = to_s3c2410_req(_req); - - dprintk(DEBUG_VERBOSE, "%s(%p,%p)\n", __func__, _ep, _req); - - if (!ep || !_req || (!ep->desc && _ep->name != ep0name)) - return; - - WARN_ON (!list_empty (&req->queue)); - kfree(req); -} - -/* - * s3c2410_udc_queue - */ -static int s3c2410_udc_queue(struct usb_ep *_ep, struct usb_request *_req, - gfp_t gfp_flags) -{ - struct s3c2410_request *req = to_s3c2410_req(_req); - struct s3c2410_ep *ep = to_s3c2410_ep(_ep); - struct s3c2410_udc *dev; - u32 ep_csr = 0; - int fifo_count = 0; - unsigned long flags; - - if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) { - dprintk(DEBUG_NORMAL, "%s: invalid args\n", __func__); - return -EINVAL; - } - - dev = ep->dev; - if (unlikely (!dev->driver - || dev->gadget.speed == USB_SPEED_UNKNOWN)) { - return -ESHUTDOWN; - } - - local_irq_save (flags); - - if (unlikely(!_req || !_req->complete - || !_req->buf || !list_empty(&req->queue))) { - if (!_req) - dprintk(DEBUG_NORMAL, "%s: 1 X X X\n", __func__); - else { - dprintk(DEBUG_NORMAL, "%s: 0 %01d %01d %01d\n", - __func__, !_req->complete,!_req->buf, - !list_empty(&req->queue)); - } - - local_irq_restore(flags); - return -EINVAL; - } - - _req->status = -EINPROGRESS; - _req->actual = 0; - - dprintk(DEBUG_VERBOSE, "%s: ep%x len %d\n", - __func__, ep->bEndpointAddress, _req->length); - - if (ep->bEndpointAddress) { - udc_write(ep->bEndpointAddress & 0x7F, S3C2410_UDC_INDEX_REG); - - ep_csr = udc_read((ep->bEndpointAddress & USB_DIR_IN) - ? S3C2410_UDC_IN_CSR1_REG - : S3C2410_UDC_OUT_CSR1_REG); - fifo_count = s3c2410_udc_fifo_count_out(); - } else { - udc_write(0, S3C2410_UDC_INDEX_REG); - ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG); - fifo_count = s3c2410_udc_fifo_count_out(); - } - - /* kickstart this i/o queue? */ - if (list_empty(&ep->queue) && !ep->halted) { - if (ep->bEndpointAddress == 0 /* ep0 */) { - switch (dev->ep0state) { - case EP0_IN_DATA_PHASE: - if (!(ep_csr&S3C2410_UDC_EP0_CSR_IPKRDY) - && s3c2410_udc_write_fifo(ep, - req)) { - dev->ep0state = EP0_IDLE; - req = NULL; - } - break; - - case EP0_OUT_DATA_PHASE: - if ((!_req->length) - || ((ep_csr & S3C2410_UDC_OCSR1_PKTRDY) - && s3c2410_udc_read_fifo(ep, - req))) { - dev->ep0state = EP0_IDLE; - req = NULL; - } - break; - - default: - local_irq_restore(flags); - return -EL2HLT; - } - } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0 - && (!(ep_csr&S3C2410_UDC_OCSR1_PKTRDY)) - && s3c2410_udc_write_fifo(ep, req)) { - req = NULL; - } else if ((ep_csr & S3C2410_UDC_OCSR1_PKTRDY) - && fifo_count - && s3c2410_udc_read_fifo(ep, req)) { - req = NULL; - } - } - - /* pio or dma irq handler advances the queue. */ - if (likely (req != 0)) - list_add_tail(&req->queue, &ep->queue); - - local_irq_restore(flags); - - dprintk(DEBUG_VERBOSE, "%s ok\n", __func__); - return 0; -} - -/* - * s3c2410_udc_dequeue - */ -static int s3c2410_udc_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct s3c2410_ep *ep = to_s3c2410_ep(_ep); - struct s3c2410_udc *udc; - int retval = -EINVAL; - unsigned long flags; - struct s3c2410_request *req = NULL; - - dprintk(DEBUG_VERBOSE, "%s(%p,%p)\n", __func__, _ep, _req); - - if (!the_controller->driver) - return -ESHUTDOWN; - - if (!_ep || !_req) - return retval; - - udc = to_s3c2410_udc(ep->gadget); - - local_irq_save (flags); - - list_for_each_entry (req, &ep->queue, queue) { - if (&req->req == _req) { - list_del_init (&req->queue); - _req->status = -ECONNRESET; - retval = 0; - break; - } - } - - if (retval == 0) { - dprintk(DEBUG_VERBOSE, - "dequeued req %p from %s, len %d buf %p\n", - req, _ep->name, _req->length, _req->buf); - - s3c2410_udc_done(ep, req, -ECONNRESET); - } - - local_irq_restore (flags); - return retval; -} - -/* - * s3c2410_udc_set_halt - */ -static int s3c2410_udc_set_halt(struct usb_ep *_ep, int value) -{ - struct s3c2410_ep *ep = to_s3c2410_ep(_ep); - u32 ep_csr = 0; - unsigned long flags; - u32 idx; - - if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) { - dprintk(DEBUG_NORMAL, "%s: inval 2\n", __func__); - return -EINVAL; - } - - local_irq_save (flags); - - idx = ep->bEndpointAddress & 0x7F; - - if (idx == 0) { - s3c2410_udc_set_ep0_ss(base_addr); - s3c2410_udc_set_ep0_de_out(base_addr); - } else { - udc_write(idx, S3C2410_UDC_INDEX_REG); - ep_csr = udc_read((ep->bEndpointAddress &USB_DIR_IN) - ? S3C2410_UDC_IN_CSR1_REG - : S3C2410_UDC_OUT_CSR1_REG); - - if ((ep->bEndpointAddress & USB_DIR_IN) != 0) { - if (value) - udc_write(ep_csr | S3C2410_UDC_ICSR1_SENDSTL, - S3C2410_UDC_IN_CSR1_REG); - else { - ep_csr &= ~S3C2410_UDC_ICSR1_SENDSTL; - udc_write(ep_csr, S3C2410_UDC_IN_CSR1_REG); - ep_csr |= S3C2410_UDC_ICSR1_CLRDT; - udc_write(ep_csr, S3C2410_UDC_IN_CSR1_REG); - } - } else { - if (value) - udc_write(ep_csr | S3C2410_UDC_OCSR1_SENDSTL, - S3C2410_UDC_OUT_CSR1_REG); - else { - ep_csr &= ~S3C2410_UDC_OCSR1_SENDSTL; - udc_write(ep_csr, S3C2410_UDC_OUT_CSR1_REG); - ep_csr |= S3C2410_UDC_OCSR1_CLRDT; - udc_write(ep_csr, S3C2410_UDC_OUT_CSR1_REG); - } - } - } - - ep->halted = value ? 1 : 0; - local_irq_restore (flags); - - return 0; -} - -static const struct usb_ep_ops s3c2410_ep_ops = { - .enable = s3c2410_udc_ep_enable, - .disable = s3c2410_udc_ep_disable, - - .alloc_request = s3c2410_udc_alloc_request, - .free_request = s3c2410_udc_free_request, - - .queue = s3c2410_udc_queue, - .dequeue = s3c2410_udc_dequeue, - - .set_halt = s3c2410_udc_set_halt, -}; - -/*------------------------- usb_gadget_ops ----------------------------------*/ - -/* - * s3c2410_udc_get_frame - */ -static int s3c2410_udc_get_frame(struct usb_gadget *_gadget) -{ - int tmp; - - dprintk(DEBUG_VERBOSE, "%s()\n", __func__); - - tmp = udc_read(S3C2410_UDC_FRAME_NUM2_REG) << 8; - tmp |= udc_read(S3C2410_UDC_FRAME_NUM1_REG); - return tmp; -} - -/* - * s3c2410_udc_wakeup - */ -static int s3c2410_udc_wakeup(struct usb_gadget *_gadget) -{ - dprintk(DEBUG_NORMAL, "%s()\n", __func__); - return 0; -} - -/* - * s3c2410_udc_set_selfpowered - */ -static int s3c2410_udc_set_selfpowered(struct usb_gadget *gadget, int value) -{ - struct s3c2410_udc *udc = to_s3c2410_udc(gadget); - - dprintk(DEBUG_NORMAL, "%s()\n", __func__); - - if (value) - udc->devstatus |= (1 << USB_DEVICE_SELF_POWERED); - else - udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED); - - return 0; -} - -static void s3c2410_udc_disable(struct s3c2410_udc *dev); -static void s3c2410_udc_enable(struct s3c2410_udc *dev); - -static int s3c2410_udc_set_pullup(struct s3c2410_udc *udc, int is_on) -{ - dprintk(DEBUG_NORMAL, "%s()\n", __func__); - - if (udc_info && (udc_info->udc_command || - gpio_is_valid(udc_info->pullup_pin))) { - - if (is_on) - s3c2410_udc_enable(udc); - else { - if (udc->gadget.speed != USB_SPEED_UNKNOWN) { - if (udc->driver && udc->driver->disconnect) - udc->driver->disconnect(&udc->gadget); - - } - s3c2410_udc_disable(udc); - } - } - else - return -EOPNOTSUPP; - - return 0; -} - -static int s3c2410_udc_vbus_session(struct usb_gadget *gadget, int is_active) -{ - struct s3c2410_udc *udc = to_s3c2410_udc(gadget); - - dprintk(DEBUG_NORMAL, "%s()\n", __func__); - - udc->vbus = (is_active != 0); - s3c2410_udc_set_pullup(udc, is_active); - return 0; -} - -static int s3c2410_udc_pullup(struct usb_gadget *gadget, int is_on) -{ - struct s3c2410_udc *udc = to_s3c2410_udc(gadget); - - dprintk(DEBUG_NORMAL, "%s()\n", __func__); - - s3c2410_udc_set_pullup(udc, is_on ? 0 : 1); - return 0; -} - -static irqreturn_t s3c2410_udc_vbus_irq(int irq, void *_dev) -{ - struct s3c2410_udc *dev = _dev; - unsigned int value; - - dprintk(DEBUG_NORMAL, "%s()\n", __func__); - - value = gpio_get_value(udc_info->vbus_pin) ? 1 : 0; - if (udc_info->vbus_pin_inverted) - value = !value; - - if (value != dev->vbus) - s3c2410_udc_vbus_session(&dev->gadget, value); - - return IRQ_HANDLED; -} - -static int s3c2410_vbus_draw(struct usb_gadget *_gadget, unsigned ma) -{ - dprintk(DEBUG_NORMAL, "%s()\n", __func__); - - if (udc_info && udc_info->vbus_draw) { - udc_info->vbus_draw(ma); - return 0; - } - - return -ENOTSUPP; -} - -static int s3c2410_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int s3c2410_udc_stop(struct usb_gadget_driver *driver); - -static const struct usb_gadget_ops s3c2410_ops = { - .get_frame = s3c2410_udc_get_frame, - .wakeup = s3c2410_udc_wakeup, - .set_selfpowered = s3c2410_udc_set_selfpowered, - .pullup = s3c2410_udc_pullup, - .vbus_session = s3c2410_udc_vbus_session, - .vbus_draw = s3c2410_vbus_draw, - .start = s3c2410_udc_start, - .stop = s3c2410_udc_stop, -}; - -static void s3c2410_udc_command(enum s3c2410_udc_cmd_e cmd) -{ - if (!udc_info) - return; - - if (udc_info->udc_command) { - udc_info->udc_command(cmd); - } else if (gpio_is_valid(udc_info->pullup_pin)) { - int value; - - switch (cmd) { - case S3C2410_UDC_P_ENABLE: - value = 1; - break; - case S3C2410_UDC_P_DISABLE: - value = 0; - break; - default: - return; - } - value ^= udc_info->pullup_pin_inverted; - - gpio_set_value(udc_info->pullup_pin, value); - } -} - -/*------------------------- gadget driver handling---------------------------*/ -/* - * s3c2410_udc_disable - */ -static void s3c2410_udc_disable(struct s3c2410_udc *dev) -{ - dprintk(DEBUG_NORMAL, "%s()\n", __func__); - - /* Disable all interrupts */ - udc_write(0x00, S3C2410_UDC_USB_INT_EN_REG); - udc_write(0x00, S3C2410_UDC_EP_INT_EN_REG); - - /* Clear the interrupt registers */ - udc_write(S3C2410_UDC_USBINT_RESET - | S3C2410_UDC_USBINT_RESUME - | S3C2410_UDC_USBINT_SUSPEND, - S3C2410_UDC_USB_INT_REG); - - udc_write(0x1F, S3C2410_UDC_EP_INT_REG); - - /* Good bye, cruel world */ - s3c2410_udc_command(S3C2410_UDC_P_DISABLE); - - /* Set speed to unknown */ - dev->gadget.speed = USB_SPEED_UNKNOWN; -} - -/* - * s3c2410_udc_reinit - */ -static void s3c2410_udc_reinit(struct s3c2410_udc *dev) -{ - u32 i; - - /* device/ep0 records init */ - INIT_LIST_HEAD (&dev->gadget.ep_list); - INIT_LIST_HEAD (&dev->gadget.ep0->ep_list); - dev->ep0state = EP0_IDLE; - - for (i = 0; i < S3C2410_ENDPOINTS; i++) { - struct s3c2410_ep *ep = &dev->ep[i]; - - if (i != 0) - list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list); - - ep->dev = dev; - ep->desc = NULL; - ep->ep.desc = NULL; - ep->halted = 0; - INIT_LIST_HEAD (&ep->queue); - } -} - -/* - * s3c2410_udc_enable - */ -static void s3c2410_udc_enable(struct s3c2410_udc *dev) -{ - int i; - - dprintk(DEBUG_NORMAL, "s3c2410_udc_enable called\n"); - - /* dev->gadget.speed = USB_SPEED_UNKNOWN; */ - dev->gadget.speed = USB_SPEED_FULL; - - /* Set MAXP for all endpoints */ - for (i = 0; i < S3C2410_ENDPOINTS; i++) { - udc_write(i, S3C2410_UDC_INDEX_REG); - udc_write((dev->ep[i].ep.maxpacket & 0x7ff) >> 3, - S3C2410_UDC_MAXP_REG); - } - - /* Set default power state */ - udc_write(DEFAULT_POWER_STATE, S3C2410_UDC_PWR_REG); - - /* Enable reset and suspend interrupt interrupts */ - udc_write(S3C2410_UDC_USBINT_RESET | S3C2410_UDC_USBINT_SUSPEND, - S3C2410_UDC_USB_INT_EN_REG); - - /* Enable ep0 interrupt */ - udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_EN_REG); - - /* time to say "hello, world" */ - s3c2410_udc_command(S3C2410_UDC_P_ENABLE); -} - -static int s3c2410_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) -{ - struct s3c2410_udc *udc = the_controller; - int retval; - - dprintk(DEBUG_NORMAL, "%s() '%s'\n", __func__, driver->driver.name); - - /* Sanity checks */ - if (!udc) - return -ENODEV; - - if (udc->driver) - return -EBUSY; - - if (!bind || !driver->setup || driver->max_speed < USB_SPEED_FULL) { - printk(KERN_ERR "Invalid driver: bind %p setup %p speed %d\n", - bind, driver->setup, driver->max_speed); - return -EINVAL; - } -#if defined(MODULE) - if (!driver->unbind) { - printk(KERN_ERR "Invalid driver: no unbind method\n"); - return -EINVAL; - } -#endif - - /* Hook the driver */ - udc->driver = driver; - udc->gadget.dev.driver = &driver->driver; - - /* Bind the driver */ - if ((retval = device_add(&udc->gadget.dev)) != 0) { - printk(KERN_ERR "Error in device_add() : %d\n",retval); - goto register_error; - } - - dprintk(DEBUG_NORMAL, "binding gadget driver '%s'\n", - driver->driver.name); - - if ((retval = bind(&udc->gadget)) != 0) { - device_del(&udc->gadget.dev); - goto register_error; - } - - /* Enable udc */ - s3c2410_udc_enable(udc); - - return 0; - -register_error: - udc->driver = NULL; - udc->gadget.dev.driver = NULL; - return retval; -} - -static int s3c2410_udc_stop(struct usb_gadget_driver *driver) -{ - struct s3c2410_udc *udc = the_controller; - - if (!udc) - return -ENODEV; - - if (!driver || driver != udc->driver || !driver->unbind) - return -EINVAL; - - dprintk(DEBUG_NORMAL, "usb_gadget_unregister_driver() '%s'\n", - driver->driver.name); - - /* report disconnect */ - if (driver->disconnect) - driver->disconnect(&udc->gadget); - - driver->unbind(&udc->gadget); - - device_del(&udc->gadget.dev); - udc->driver = NULL; - - /* Disable udc */ - s3c2410_udc_disable(udc); - - return 0; -} - -/*---------------------------------------------------------------------------*/ -static struct s3c2410_udc memory = { - .gadget = { - .ops = &s3c2410_ops, - .ep0 = &memory.ep[0].ep, - .name = gadget_name, - .dev = { - .init_name = "gadget", - }, - }, - - /* control endpoint */ - .ep[0] = { - .num = 0, - .ep = { - .name = ep0name, - .ops = &s3c2410_ep_ops, - .maxpacket = EP0_FIFO_SIZE, - }, - .dev = &memory, - }, - - /* first group of endpoints */ - .ep[1] = { - .num = 1, - .ep = { - .name = "ep1-bulk", - .ops = &s3c2410_ep_ops, - .maxpacket = EP_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = EP_FIFO_SIZE, - .bEndpointAddress = 1, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - }, - .ep[2] = { - .num = 2, - .ep = { - .name = "ep2-bulk", - .ops = &s3c2410_ep_ops, - .maxpacket = EP_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = EP_FIFO_SIZE, - .bEndpointAddress = 2, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - }, - .ep[3] = { - .num = 3, - .ep = { - .name = "ep3-bulk", - .ops = &s3c2410_ep_ops, - .maxpacket = EP_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = EP_FIFO_SIZE, - .bEndpointAddress = 3, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - }, - .ep[4] = { - .num = 4, - .ep = { - .name = "ep4-bulk", - .ops = &s3c2410_ep_ops, - .maxpacket = EP_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = EP_FIFO_SIZE, - .bEndpointAddress = 4, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - } - -}; - -/* - * probe - binds to the platform device - */ -static int s3c2410_udc_probe(struct platform_device *pdev) -{ - struct s3c2410_udc *udc = &memory; - struct device *dev = &pdev->dev; - int retval; - int irq; - - dev_dbg(dev, "%s()\n", __func__); - - usb_bus_clock = clk_get(NULL, "usb-bus-gadget"); - if (IS_ERR(usb_bus_clock)) { - dev_err(dev, "failed to get usb bus clock source\n"); - return PTR_ERR(usb_bus_clock); - } - - clk_enable(usb_bus_clock); - - udc_clock = clk_get(NULL, "usb-device"); - if (IS_ERR(udc_clock)) { - dev_err(dev, "failed to get udc clock source\n"); - return PTR_ERR(udc_clock); - } - - clk_enable(udc_clock); - - mdelay(10); - - dev_dbg(dev, "got and enabled clocks\n"); - - if (strncmp(pdev->name, "s3c2440", 7) == 0) { - dev_info(dev, "S3C2440: increasing FIFO to 128 bytes\n"); - memory.ep[1].fifo_size = S3C2440_EP_FIFO_SIZE; - memory.ep[2].fifo_size = S3C2440_EP_FIFO_SIZE; - memory.ep[3].fifo_size = S3C2440_EP_FIFO_SIZE; - memory.ep[4].fifo_size = S3C2440_EP_FIFO_SIZE; - } - - spin_lock_init (&udc->lock); - udc_info = pdev->dev.platform_data; - - rsrc_start = S3C2410_PA_USBDEV; - rsrc_len = S3C24XX_SZ_USBDEV; - - if (!request_mem_region(rsrc_start, rsrc_len, gadget_name)) - return -EBUSY; - - base_addr = ioremap(rsrc_start, rsrc_len); - if (!base_addr) { - retval = -ENOMEM; - goto err_mem; - } - - device_initialize(&udc->gadget.dev); - udc->gadget.dev.parent = &pdev->dev; - udc->gadget.dev.dma_mask = pdev->dev.dma_mask; - - the_controller = udc; - platform_set_drvdata(pdev, udc); - - s3c2410_udc_disable(udc); - s3c2410_udc_reinit(udc); - - /* irq setup after old hardware state is cleaned up */ - retval = request_irq(IRQ_USBD, s3c2410_udc_irq, - 0, gadget_name, udc); - - if (retval != 0) { - dev_err(dev, "cannot get irq %i, err %d\n", IRQ_USBD, retval); - retval = -EBUSY; - goto err_map; - } - - dev_dbg(dev, "got irq %i\n", IRQ_USBD); - - if (udc_info && udc_info->vbus_pin > 0) { - retval = gpio_request(udc_info->vbus_pin, "udc vbus"); - if (retval < 0) { - dev_err(dev, "cannot claim vbus pin\n"); - goto err_int; - } - - irq = gpio_to_irq(udc_info->vbus_pin); - if (irq < 0) { - dev_err(dev, "no irq for gpio vbus pin\n"); - goto err_gpio_claim; - } - - retval = request_irq(irq, s3c2410_udc_vbus_irq, - IRQF_TRIGGER_RISING - | IRQF_TRIGGER_FALLING | IRQF_SHARED, - gadget_name, udc); - - if (retval != 0) { - dev_err(dev, "can't get vbus irq %d, err %d\n", - irq, retval); - retval = -EBUSY; - goto err_gpio_claim; - } - - dev_dbg(dev, "got irq %i\n", irq); - } else { - udc->vbus = 1; - } - - if (udc_info && !udc_info->udc_command && - gpio_is_valid(udc_info->pullup_pin)) { - - retval = gpio_request_one(udc_info->pullup_pin, - udc_info->vbus_pin_inverted ? - GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, - "udc pullup"); - if (retval) - goto err_vbus_irq; - } - - retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget); - if (retval) - goto err_add_udc; - - if (s3c2410_udc_debugfs_root) { - udc->regs_info = debugfs_create_file("registers", S_IRUGO, - s3c2410_udc_debugfs_root, - udc, &s3c2410_udc_debugfs_fops); - if (!udc->regs_info) - dev_warn(dev, "debugfs file creation failed\n"); - } - - dev_dbg(dev, "probe ok\n"); - - return 0; - -err_add_udc: - if (udc_info && !udc_info->udc_command && - gpio_is_valid(udc_info->pullup_pin)) - gpio_free(udc_info->pullup_pin); -err_vbus_irq: - if (udc_info && udc_info->vbus_pin > 0) - free_irq(gpio_to_irq(udc_info->vbus_pin), udc); -err_gpio_claim: - if (udc_info && udc_info->vbus_pin > 0) - gpio_free(udc_info->vbus_pin); -err_int: - free_irq(IRQ_USBD, udc); -err_map: - iounmap(base_addr); -err_mem: - release_mem_region(rsrc_start, rsrc_len); - - return retval; -} - -/* - * s3c2410_udc_remove - */ -static int s3c2410_udc_remove(struct platform_device *pdev) -{ - struct s3c2410_udc *udc = platform_get_drvdata(pdev); - unsigned int irq; - - dev_dbg(&pdev->dev, "%s()\n", __func__); - - usb_del_gadget_udc(&udc->gadget); - if (udc->driver) - return -EBUSY; - - debugfs_remove(udc->regs_info); - - if (udc_info && !udc_info->udc_command && - gpio_is_valid(udc_info->pullup_pin)) - gpio_free(udc_info->pullup_pin); - - if (udc_info && udc_info->vbus_pin > 0) { - irq = gpio_to_irq(udc_info->vbus_pin); - free_irq(irq, udc); - } - - free_irq(IRQ_USBD, udc); - - iounmap(base_addr); - release_mem_region(rsrc_start, rsrc_len); - - platform_set_drvdata(pdev, NULL); - - if (!IS_ERR(udc_clock) && udc_clock != NULL) { - clk_disable(udc_clock); - clk_put(udc_clock); - udc_clock = NULL; - } - - if (!IS_ERR(usb_bus_clock) && usb_bus_clock != NULL) { - clk_disable(usb_bus_clock); - clk_put(usb_bus_clock); - usb_bus_clock = NULL; - } - - dev_dbg(&pdev->dev, "%s: remove ok\n", __func__); - return 0; -} - -#ifdef CONFIG_PM -static int s3c2410_udc_suspend(struct platform_device *pdev, pm_message_t message) -{ - s3c2410_udc_command(S3C2410_UDC_P_DISABLE); - - return 0; -} - -static int s3c2410_udc_resume(struct platform_device *pdev) -{ - s3c2410_udc_command(S3C2410_UDC_P_ENABLE); - - return 0; -} -#else -#define s3c2410_udc_suspend NULL -#define s3c2410_udc_resume NULL -#endif - -static const struct platform_device_id s3c_udc_ids[] = { - { "s3c2410-usbgadget", }, - { "s3c2440-usbgadget", }, - { } -}; -MODULE_DEVICE_TABLE(platform, s3c_udc_ids); - -static struct platform_driver udc_driver_24x0 = { - .driver = { - .name = "s3c24x0-usbgadget", - .owner = THIS_MODULE, - }, - .probe = s3c2410_udc_probe, - .remove = s3c2410_udc_remove, - .suspend = s3c2410_udc_suspend, - .resume = s3c2410_udc_resume, - .id_table = s3c_udc_ids, -}; - -static int __init udc_init(void) -{ - int retval; - - dprintk(DEBUG_NORMAL, "%s: version %s\n", gadget_name, DRIVER_VERSION); - - s3c2410_udc_debugfs_root = debugfs_create_dir(gadget_name, NULL); - if (IS_ERR(s3c2410_udc_debugfs_root)) { - printk(KERN_ERR "%s: debugfs dir creation failed %ld\n", - gadget_name, PTR_ERR(s3c2410_udc_debugfs_root)); - s3c2410_udc_debugfs_root = NULL; - } - - retval = platform_driver_register(&udc_driver_24x0); - if (retval) - goto err; - - return 0; - -err: - debugfs_remove(s3c2410_udc_debugfs_root); - return retval; -} - -static void __exit udc_exit(void) -{ - platform_driver_unregister(&udc_driver_24x0); - debugfs_remove(s3c2410_udc_debugfs_root); -} - -module_init(udc_init); -module_exit(udc_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/s3c2410_udc.h b/ANDROID_3.4.5/drivers/usb/gadget/s3c2410_udc.h deleted file mode 100644 index 1653bae0..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/s3c2410_udc.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * linux/drivers/usb/gadget/s3c2410_udc.h - * Samsung on-chip full speed USB device controllers - * - * Copyright (C) 2004-2007 Herbert Pötzl - Arnaud Patard - * Additional cleanups by Ben Dooks - * - * 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. - */ - -#ifndef _S3C2410_UDC_H -#define _S3C2410_UDC_H - -struct s3c2410_ep { - struct list_head queue; - unsigned long last_io; /* jiffies timestamp */ - struct usb_gadget *gadget; - struct s3c2410_udc *dev; - const struct usb_endpoint_descriptor *desc; - struct usb_ep ep; - u8 num; - - unsigned short fifo_size; - u8 bEndpointAddress; - u8 bmAttributes; - - unsigned halted : 1; - unsigned already_seen : 1; - unsigned setup_stage : 1; -}; - - -/* Warning : ep0 has a fifo of 16 bytes */ -/* Don't try to set 32 or 64 */ -/* also testusb 14 fails wit 16 but is */ -/* fine with 8 */ -#define EP0_FIFO_SIZE 8 -#define EP_FIFO_SIZE 64 -#define DEFAULT_POWER_STATE 0x00 - -#define S3C2440_EP_FIFO_SIZE 128 - -static const char ep0name [] = "ep0"; - -static const char *const ep_name[] = { - ep0name, /* everyone has ep0 */ - /* s3c2410 four bidirectional bulk endpoints */ - "ep1-bulk", "ep2-bulk", "ep3-bulk", "ep4-bulk", -}; - -#define S3C2410_ENDPOINTS ARRAY_SIZE(ep_name) - -struct s3c2410_request { - struct list_head queue; /* ep's requests */ - struct usb_request req; -}; - -enum ep0_state { - EP0_IDLE, - EP0_IN_DATA_PHASE, - EP0_OUT_DATA_PHASE, - EP0_END_XFER, - EP0_STALL, -}; - -static const char *ep0states[]= { - "EP0_IDLE", - "EP0_IN_DATA_PHASE", - "EP0_OUT_DATA_PHASE", - "EP0_END_XFER", - "EP0_STALL", -}; - -struct s3c2410_udc { - spinlock_t lock; - - struct s3c2410_ep ep[S3C2410_ENDPOINTS]; - int address; - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - struct s3c2410_request fifo_req; - u8 fifo_buf[EP_FIFO_SIZE]; - u16 devstatus; - - u32 port_status; - int ep0state; - - unsigned got_irq : 1; - - unsigned req_std : 1; - unsigned req_config : 1; - unsigned req_pending : 1; - u8 vbus; - struct dentry *regs_info; -}; - -#endif diff --git a/ANDROID_3.4.5/drivers/usb/gadget/serial.c b/ANDROID_3.4.5/drivers/usb/gadget/serial.c deleted file mode 100644 index 665c0742..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/serial.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * serial.c -- USB gadget serial driver - * - * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com) - * Copyright (C) 2008 by David Brownell - * Copyright (C) 2008 by Nokia Corporation - * - * This software is distributed under the terms of the GNU General - * Public License ("GPL") as published by the Free Software Foundation, - * either version 2 of that License or (at your option) any later version. - */ - -#include -#include -#include -#include -#include - -#include "u_serial.h" -#include "gadget_chips.h" - - -/* Defines */ - -#define GS_VERSION_STR "v2.4" -#define GS_VERSION_NUM 0x2400 - -#define GS_LONG_NAME "Gadget Serial" -#define GS_VERSION_NAME GS_LONG_NAME " " GS_VERSION_STR - -/*-------------------------------------------------------------------------*/ - -/* - * 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 "f_acm.c" -#include "f_obex.c" -#include "f_serial.c" -#include "u_serial.c" - -/*-------------------------------------------------------------------------*/ - -/* Thanks to NetChip Technologies for donating this product ID. -* -* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! -* Instead: allocate your own, using normal USB-IF procedures. -*/ -#define GS_VENDOR_ID 0x0525 /* NetChip */ -#define GS_PRODUCT_ID 0xa4a6 /* Linux-USB Serial Gadget */ -#define GS_CDC_PRODUCT_ID 0xa4a7 /* ... as CDC-ACM */ -#define GS_CDC_OBEX_PRODUCT_ID 0xa4a9 /* ... as CDC-OBEX */ - -/* string IDs are assigned dynamically */ - -#define STRING_MANUFACTURER_IDX 0 -#define STRING_PRODUCT_IDX 1 -#define STRING_DESCRIPTION_IDX 2 - -static char manufacturer[50]; - -static struct usb_string strings_dev[] = { - [STRING_MANUFACTURER_IDX].s = manufacturer, - [STRING_PRODUCT_IDX].s = GS_VERSION_NAME, - [STRING_DESCRIPTION_IDX].s = NULL /* updated; f(use_acm) */, - { } /* end of list */ -}; - -static struct usb_gadget_strings stringtab_dev = { - .language = 0x0409, /* en-us */ - .strings = strings_dev, -}; - -static struct usb_gadget_strings *dev_strings[] = { - &stringtab_dev, - NULL, -}; - -static struct usb_device_descriptor device_desc = { - .bLength = USB_DT_DEVICE_SIZE, - .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = cpu_to_le16(0x0200), - /* .bDeviceClass = f(use_acm) */ - .bDeviceSubClass = 0, - .bDeviceProtocol = 0, - /* .bMaxPacketSize0 = f(hardware) */ - .idVendor = cpu_to_le16(GS_VENDOR_ID), - /* .idProduct = f(use_acm) */ - /* .bcdDevice = f(hardware) */ - /* .iManufacturer = DYNAMIC */ - /* .iProduct = DYNAMIC */ - .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, -}; - -/*-------------------------------------------------------------------------*/ - -/* Module */ -MODULE_DESCRIPTION(GS_VERSION_NAME); -MODULE_AUTHOR("Al Borchers"); -MODULE_AUTHOR("David Brownell"); -MODULE_LICENSE("GPL"); - -static bool use_acm = true; -module_param(use_acm, bool, 0); -MODULE_PARM_DESC(use_acm, "Use CDC ACM, default=yes"); - -static bool use_obex = false; -module_param(use_obex, bool, 0); -MODULE_PARM_DESC(use_obex, "Use CDC OBEX, default=no"); - -static unsigned n_ports = 1; -module_param(n_ports, uint, 0); -MODULE_PARM_DESC(n_ports, "number of ports to create, default=1"); - -/*-------------------------------------------------------------------------*/ - -static int __init serial_bind_config(struct usb_configuration *c) -{ - unsigned i; - int status = 0; - - for (i = 0; i < n_ports && status == 0; i++) { - if (use_acm) - status = acm_bind_config(c, i); - else if (use_obex) - status = obex_bind_config(c, i); - else - status = gser_bind_config(c, i); - } - return status; -} - -static struct usb_configuration serial_config_driver = { - /* .label = f(use_acm) */ - /* .bConfigurationValue = f(use_acm) */ - /* .iConfiguration = DYNAMIC */ - .bmAttributes = USB_CONFIG_ATT_SELFPOWER, -}; - -static int __init gs_bind(struct usb_composite_dev *cdev) -{ - int gcnum; - struct usb_gadget *gadget = cdev->gadget; - int status; - - status = gserial_setup(cdev->gadget, n_ports); - if (status < 0) - return status; - - /* Allocate string descriptor numbers ... note that string - * contents can be overridden by the composite_dev glue. - */ - - /* device description: manufacturer, product */ - snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", - init_utsname()->sysname, init_utsname()->release, - 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; - - /* config description */ - status = usb_string_id(cdev); - if (status < 0) - goto fail; - strings_dev[STRING_DESCRIPTION_IDX].id = status; - - serial_config_driver.iConfiguration = status; - - /* set up other descriptors */ - gcnum = usb_gadget_controller_number(gadget); - if (gcnum >= 0) - device_desc.bcdDevice = cpu_to_le16(GS_VERSION_NUM | gcnum); - else { - /* this is so simple (for now, no altsettings) that it - * SHOULD NOT have problems with bulk-capable hardware. - * so warn about unrcognized controllers -- don't panic. - * - * things like configuration and altsetting numbering - * can need hardware-specific attention though. - */ - pr_warning("gs_bind: controller '%s' not recognized\n", - gadget->name); - device_desc.bcdDevice = - cpu_to_le16(GS_VERSION_NUM | 0x0099); - } - - if (gadget_is_otg(cdev->gadget)) { - serial_config_driver.descriptors = otg_desc; - serial_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; - } - - /* register our configuration */ - status = usb_add_config(cdev, &serial_config_driver, - serial_bind_config); - if (status < 0) - goto fail; - - INFO(cdev, "%s\n", GS_VERSION_NAME); - - return 0; - -fail: - gserial_cleanup(); - return status; -} - -static struct usb_composite_driver gserial_driver = { - .name = "g_serial", - .dev = &device_desc, - .strings = dev_strings, - .max_speed = USB_SPEED_SUPER, -}; - -static int __init init(void) -{ - /* We *could* export two configs; that'd be much cleaner... - * but neither of these product IDs was defined that way. - */ - if (use_acm) { - serial_config_driver.label = "CDC ACM config"; - serial_config_driver.bConfigurationValue = 2; - device_desc.bDeviceClass = USB_CLASS_COMM; - device_desc.idProduct = - cpu_to_le16(GS_CDC_PRODUCT_ID); - } else if (use_obex) { - serial_config_driver.label = "CDC OBEX config"; - serial_config_driver.bConfigurationValue = 3; - device_desc.bDeviceClass = USB_CLASS_COMM; - device_desc.idProduct = - cpu_to_le16(GS_CDC_OBEX_PRODUCT_ID); - } else { - serial_config_driver.label = "Generic Serial config"; - serial_config_driver.bConfigurationValue = 1; - device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC; - device_desc.idProduct = - cpu_to_le16(GS_PRODUCT_ID); - } - strings_dev[STRING_DESCRIPTION_IDX].s = serial_config_driver.label; - - return usb_composite_probe(&gserial_driver, gs_bind); -} -module_init(init); - -static void __exit cleanup(void) -{ - usb_composite_unregister(&gserial_driver); - gserial_cleanup(); -} -module_exit(cleanup); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/storage_common.c b/ANDROID_3.4.5/drivers/usb/gadget/storage_common.c deleted file mode 100644 index 88e9c0ef..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/storage_common.c +++ /dev/null @@ -1,938 +0,0 @@ -/* - * storage_common.c -- Common definitions for mass storage functionality - * - * Copyright (C) 2003-2008 Alan Stern - * Copyeight (C) 2009 Samsung Electronics - * Author: Michal Nazarewicz (mina86@mina86.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - - -/* - * This file requires the following identifiers used in USB strings to - * be defined (each of type pointer to char): - * - fsg_string_manufacturer -- name of the manufacturer - * - fsg_string_product -- name of the product - * - fsg_string_config -- name of the configuration - * - fsg_string_interface -- name of the interface - * The first four are only needed when FSG_DESCRIPTORS_DEVICE_STRINGS - * macro is defined prior to including this file. - */ - -/* - * When FSG_NO_INTR_EP is defined fsg_fs_intr_in_desc and - * fsg_hs_intr_in_desc objects as well as - * FSG_FS_FUNCTION_PRE_EP_ENTRIES and FSG_HS_FUNCTION_PRE_EP_ENTRIES - * macros are not defined. - * - * When FSG_NO_DEVICE_STRINGS is defined FSG_STRING_MANUFACTURER, - * FSG_STRING_PRODUCT, FSG_STRING_SERIAL and FSG_STRING_CONFIG are not - * defined (as well as corresponding entries in string tables are - * missing) and FSG_STRING_INTERFACE has value of zero. - * - * When FSG_NO_OTG is defined fsg_otg_desc won't be defined. - */ - -/* - * When FSG_BUFFHD_STATIC_BUFFER is defined when this file is included - * the fsg_buffhd structure's buf field will be an array of FSG_BUFLEN - * characters rather then a pointer to void. - */ - -/* - * When USB_GADGET_DEBUG_FILES is defined the module param num_buffers - * sets the number of pipeline buffers (length of the fsg_buffhd array). - * The valid range of num_buffers is: num >= 2 && num <= 4. - */ - - -#include -#include -#include - - -/* - * Thanks to NetChip Technologies for donating this product ID. - * - * DO NOT REUSE THESE IDs with any other driver!! Ever!! - * Instead: allocate your own, using normal USB-IF procedures. - */ -#define FSG_VENDOR_ID 0x0525 /* NetChip */ -#define FSG_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */ - - -/*-------------------------------------------------------------------------*/ - - -#ifndef DEBUG -#undef VERBOSE_DEBUG -#undef DUMP_MSGS -#endif /* !DEBUG */ - -#ifdef VERBOSE_DEBUG -#define VLDBG LDBG -#else -#define VLDBG(lun, fmt, args...) do { } while (0) -#endif /* VERBOSE_DEBUG */ - -#define LDBG(lun, fmt, args...) dev_dbg (&(lun)->dev, fmt, ## args) -#define LERROR(lun, fmt, args...) dev_err (&(lun)->dev, fmt, ## args) -#define LWARN(lun, fmt, args...) dev_warn(&(lun)->dev, fmt, ## args) -#define LINFO(lun, fmt, args...) dev_info(&(lun)->dev, fmt, ## args) - -/* - * Keep those macros in sync with those in - * include/linux/usb/composite.h or else GCC will complain. If they - * are identical (the same names of arguments, white spaces in the - * same places) GCC will allow redefinition otherwise (even if some - * white space is removed or added) warning will be issued. - * - * Those macros are needed here because File Storage Gadget does not - * include the composite.h header. For composite gadgets those macros - * are redundant since composite.h is included any way. - * - * One could check whether those macros are already defined (which - * would indicate composite.h had been included) or not (which would - * indicate we were in FSG) but this is not done because a warning is - * desired if definitions here differ from the ones in composite.h. - * - * We want the definitions to match and be the same in File Storage - * Gadget as well as Mass Storage Function (and so composite gadgets - * using MSF). If someone changes them in composite.h it will produce - * a warning in this file when building MSF. - */ -#define DBG(d, fmt, args...) dev_dbg(&(d)->gadget->dev , fmt , ## args) -#define VDBG(d, fmt, args...) dev_vdbg(&(d)->gadget->dev , fmt , ## args) -#define ERROR(d, fmt, args...) dev_err(&(d)->gadget->dev , fmt , ## args) -#define WARNING(d, fmt, args...) dev_warn(&(d)->gadget->dev , fmt , ## args) -#define INFO(d, fmt, args...) dev_info(&(d)->gadget->dev , fmt , ## args) - - - -#ifdef DUMP_MSGS - -# define dump_msg(fsg, /* const char * */ label, \ - /* const u8 * */ buf, /* unsigned */ length) do { \ - if (length < 512) { \ - DBG(fsg, "%s, length %u:\n", label, length); \ - print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, \ - 16, 1, buf, length, 0); \ - } \ -} while (0) - -# define dump_cdb(fsg) do { } while (0) - -#else - -# define dump_msg(fsg, /* const char * */ label, \ - /* const u8 * */ buf, /* unsigned */ length) do { } while (0) - -# ifdef VERBOSE_DEBUG - -# define dump_cdb(fsg) \ - print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE, \ - 16, 1, (fsg)->cmnd, (fsg)->cmnd_size, 0) \ - -# else - -# define dump_cdb(fsg) do { } while (0) - -# endif /* VERBOSE_DEBUG */ - -#endif /* DUMP_MSGS */ - -/*-------------------------------------------------------------------------*/ - -/* CBI Interrupt data structure */ -struct interrupt_data { - u8 bType; - u8 bValue; -}; - -#define CBI_INTERRUPT_DATA_LEN 2 - -/* CBI Accept Device-Specific Command request */ -#define USB_CBI_ADSC_REQUEST 0x00 - - -/* Length of a SCSI Command Data Block */ -#define MAX_COMMAND_SIZE 16 - -/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */ -#define SS_NO_SENSE 0 -#define SS_COMMUNICATION_FAILURE 0x040800 -#define SS_INVALID_COMMAND 0x052000 -#define SS_INVALID_FIELD_IN_CDB 0x052400 -#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x052100 -#define SS_LOGICAL_UNIT_NOT_SUPPORTED 0x052500 -#define SS_MEDIUM_NOT_PRESENT 0x023a00 -#define SS_MEDIUM_REMOVAL_PREVENTED 0x055302 -#define SS_NOT_READY_TO_READY_TRANSITION 0x062800 -#define SS_RESET_OCCURRED 0x062900 -#define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x053900 -#define SS_UNRECOVERED_READ_ERROR 0x031100 -#define SS_WRITE_ERROR 0x030c02 -#define SS_WRITE_PROTECTED 0x072700 - -#define SK(x) ((u8) ((x) >> 16)) /* Sense Key byte, etc. */ -#define ASC(x) ((u8) ((x) >> 8)) -#define ASCQ(x) ((u8) (x)) - - -/*-------------------------------------------------------------------------*/ - - -struct fsg_lun { - struct file *filp; - loff_t file_length; - loff_t num_sectors; - - unsigned int initially_ro:1; - unsigned int ro:1; - unsigned int removable:1; - unsigned int cdrom:1; - unsigned int prevent_medium_removal:1; - unsigned int registered:1; - unsigned int info_valid:1; - unsigned int nofua:1; - - u32 sense_data; - u32 sense_data_info; - u32 unit_attention_data; - - unsigned int blkbits; /* Bits of logical block size of bound block device */ - unsigned int blksize; /* logical block size of bound block device */ - struct device dev; -}; - -#define fsg_lun_is_open(curlun) ((curlun)->filp != NULL) - -static struct fsg_lun *fsg_lun_from_dev(struct device *dev) -{ - return container_of(dev, struct fsg_lun, dev); -} - - -/* Big enough to hold our biggest descriptor */ -#define EP0_BUFSIZE 256 -#define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */ - -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - -static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; -module_param_named(num_buffers, fsg_num_buffers, uint, S_IRUGO); -MODULE_PARM_DESC(num_buffers, "Number of pipeline buffers"); - -#else - -/* - * Number of buffers we will use. - * 2 is usually enough for good buffering pipeline - */ -#define fsg_num_buffers CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS - -#endif /* CONFIG_USB_DEBUG */ - -/* check if fsg_num_buffers is within a valid range */ -static inline int fsg_num_buffers_validate(void) -{ - if (fsg_num_buffers >= 2 && fsg_num_buffers <= 4) - return 0; - pr_err("fsg_num_buffers %u is out of range (%d to %d)\n", - fsg_num_buffers, 2 ,4); - return -EINVAL; -} - -/* Default size of buffer length. */ -#define FSG_BUFLEN ((u32)16384) - -/* Maximal number of LUNs supported in mass storage function */ -#define FSG_MAX_LUNS 8 - -enum fsg_buffer_state { - BUF_STATE_EMPTY = 0, - BUF_STATE_FULL, - BUF_STATE_BUSY -}; - -struct fsg_buffhd { -#ifdef FSG_BUFFHD_STATIC_BUFFER - char buf[FSG_BUFLEN]; -#else - void *buf; -#endif - enum fsg_buffer_state state; - struct fsg_buffhd *next; - - /* - * The NetChip 2280 is faster, and handles some protocol faults - * better, if we don't submit any short bulk-out read requests. - * So we will record the intended request length here. - */ - unsigned int bulk_out_intended_length; - - struct usb_request *inreq; - int inreq_busy; - struct usb_request *outreq; - int outreq_busy; -}; - -enum fsg_state { - /* This one isn't used anywhere */ - FSG_STATE_COMMAND_PHASE = -10, - FSG_STATE_DATA_PHASE, - FSG_STATE_STATUS_PHASE, - - FSG_STATE_IDLE = 0, - FSG_STATE_ABORT_BULK_OUT, - FSG_STATE_RESET, - FSG_STATE_INTERFACE_CHANGE, - FSG_STATE_CONFIG_CHANGE, - FSG_STATE_DISCONNECT, - FSG_STATE_EXIT, - FSG_STATE_TERMINATED -}; - -enum data_direction { - DATA_DIR_UNKNOWN = 0, - DATA_DIR_FROM_HOST, - DATA_DIR_TO_HOST, - DATA_DIR_NONE -}; - - -/*-------------------------------------------------------------------------*/ - - -static inline u32 get_unaligned_be24(u8 *buf) -{ - return 0xffffff & (u32) get_unaligned_be32(buf - 1); -} - - -/*-------------------------------------------------------------------------*/ - - -enum { -#ifndef FSG_NO_DEVICE_STRINGS - FSG_STRING_MANUFACTURER = 1, - FSG_STRING_PRODUCT, - FSG_STRING_SERIAL, - FSG_STRING_CONFIG, -#endif - FSG_STRING_INTERFACE -}; - - -#ifndef FSG_NO_OTG -static struct usb_otg_descriptor -fsg_otg_desc = { - .bLength = sizeof fsg_otg_desc, - .bDescriptorType = USB_DT_OTG, - - .bmAttributes = USB_OTG_SRP, -}; -#endif - -/* There is only one interface. */ - -static struct usb_interface_descriptor -fsg_intf_desc = { - .bLength = sizeof fsg_intf_desc, - .bDescriptorType = USB_DT_INTERFACE, - - .bNumEndpoints = 2, /* Adjusted during fsg_bind() */ - .bInterfaceClass = USB_CLASS_MASS_STORAGE, - .bInterfaceSubClass = USB_SC_SCSI, /* Adjusted during fsg_bind() */ - .bInterfaceProtocol = USB_PR_BULK, /* Adjusted during fsg_bind() */ - .iInterface = FSG_STRING_INTERFACE, -}; - -/* - * Three full-speed endpoint descriptors: bulk-in, bulk-out, and - * interrupt-in. - */ - -static struct usb_endpoint_descriptor -fsg_fs_bulk_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - /* wMaxPacketSize set by autoconfiguration */ -}; - -static struct usb_endpoint_descriptor -fsg_fs_bulk_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - /* wMaxPacketSize set by autoconfiguration */ -}; - -#ifndef FSG_NO_INTR_EP - -static struct usb_endpoint_descriptor -fsg_fs_intr_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(2), - .bInterval = 32, /* frames -> 32 ms */ -}; - -#ifndef FSG_NO_OTG -# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 2 -#else -# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 1 -#endif - -#endif - -static struct usb_descriptor_header *fsg_fs_function[] = { -#ifndef FSG_NO_OTG - (struct usb_descriptor_header *) &fsg_otg_desc, -#endif - (struct usb_descriptor_header *) &fsg_intf_desc, - (struct usb_descriptor_header *) &fsg_fs_bulk_in_desc, - (struct usb_descriptor_header *) &fsg_fs_bulk_out_desc, -#ifndef FSG_NO_INTR_EP - (struct usb_descriptor_header *) &fsg_fs_intr_in_desc, -#endif - NULL, -}; - - -/* - * USB 2.0 devices need to expose both high speed and full speed - * descriptors, unless they only run at full speed. - * - * That means alternate endpoint descriptors (bigger packets) - * and a "device qualifier" ... plus more construction options - * for the configuration descriptor. - */ -static struct usb_endpoint_descriptor -fsg_hs_bulk_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */ - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), -}; - -static struct usb_endpoint_descriptor -fsg_hs_bulk_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */ - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), - .bInterval = 1, /* NAK every 1 uframe */ -}; - -#ifndef FSG_NO_INTR_EP - -static struct usb_endpoint_descriptor -fsg_hs_intr_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */ - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(2), - .bInterval = 9, /* 2**(9-1) = 256 uframes -> 32 ms */ -}; - -#ifndef FSG_NO_OTG -# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 2 -#else -# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 1 -#endif - -#endif - -static struct usb_descriptor_header *fsg_hs_function[] = { -#ifndef FSG_NO_OTG - (struct usb_descriptor_header *) &fsg_otg_desc, -#endif - (struct usb_descriptor_header *) &fsg_intf_desc, - (struct usb_descriptor_header *) &fsg_hs_bulk_in_desc, - (struct usb_descriptor_header *) &fsg_hs_bulk_out_desc, -#ifndef FSG_NO_INTR_EP - (struct usb_descriptor_header *) &fsg_hs_intr_in_desc, -#endif - NULL, -}; - -static struct usb_endpoint_descriptor -fsg_ss_bulk_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */ - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(1024), -}; - -static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = { - .bLength = sizeof(fsg_ss_bulk_in_comp_desc), - .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, - - /*.bMaxBurst = DYNAMIC, */ -}; - -static struct usb_endpoint_descriptor -fsg_ss_bulk_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */ - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(1024), -}; - -static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = { - .bLength = sizeof(fsg_ss_bulk_in_comp_desc), - .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, - - /*.bMaxBurst = DYNAMIC, */ -}; - -#ifndef FSG_NO_INTR_EP - -static struct usb_endpoint_descriptor -fsg_ss_intr_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */ - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(2), - .bInterval = 9, /* 2**(9-1) = 256 uframes -> 32 ms */ -}; - -static struct usb_ss_ep_comp_descriptor fsg_ss_intr_in_comp_desc = { - .bLength = sizeof(fsg_ss_bulk_in_comp_desc), - .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, - - .wBytesPerInterval = cpu_to_le16(2), -}; - -#ifndef FSG_NO_OTG -# define FSG_SS_FUNCTION_PRE_EP_ENTRIES 2 -#else -# define FSG_SS_FUNCTION_PRE_EP_ENTRIES 1 -#endif - -#endif - -static __maybe_unused struct usb_ext_cap_descriptor fsg_ext_cap_desc = { - .bLength = USB_DT_USB_EXT_CAP_SIZE, - .bDescriptorType = USB_DT_DEVICE_CAPABILITY, - .bDevCapabilityType = USB_CAP_TYPE_EXT, - - .bmAttributes = cpu_to_le32(USB_LPM_SUPPORT), -}; - -static __maybe_unused struct usb_ss_cap_descriptor fsg_ss_cap_desc = { - .bLength = USB_DT_USB_SS_CAP_SIZE, - .bDescriptorType = USB_DT_DEVICE_CAPABILITY, - .bDevCapabilityType = USB_SS_CAP_TYPE, - - /* .bmAttributes = LTM is not supported yet */ - - .wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION - | USB_FULL_SPEED_OPERATION - | USB_HIGH_SPEED_OPERATION - | USB_5GBPS_OPERATION), - .bFunctionalitySupport = USB_LOW_SPEED_OPERATION, - .bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT, - .bU2DevExitLat = cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT), -}; - -static __maybe_unused struct usb_bos_descriptor fsg_bos_desc = { - .bLength = USB_DT_BOS_SIZE, - .bDescriptorType = USB_DT_BOS, - - .wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE - + USB_DT_USB_EXT_CAP_SIZE - + USB_DT_USB_SS_CAP_SIZE), - - .bNumDeviceCaps = 2, -}; - -static struct usb_descriptor_header *fsg_ss_function[] = { -#ifndef FSG_NO_OTG - (struct usb_descriptor_header *) &fsg_otg_desc, -#endif - (struct usb_descriptor_header *) &fsg_intf_desc, - (struct usb_descriptor_header *) &fsg_ss_bulk_in_desc, - (struct usb_descriptor_header *) &fsg_ss_bulk_in_comp_desc, - (struct usb_descriptor_header *) &fsg_ss_bulk_out_desc, - (struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc, -#ifndef FSG_NO_INTR_EP - (struct usb_descriptor_header *) &fsg_ss_intr_in_desc, - (struct usb_descriptor_header *) &fsg_ss_intr_in_comp_desc, -#endif - NULL, -}; - -/* Maxpacket and other transfer characteristics vary by speed. */ -static __maybe_unused struct usb_endpoint_descriptor * -fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, - struct usb_endpoint_descriptor *hs, - struct usb_endpoint_descriptor *ss) -{ - if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER) - return ss; - else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) - return hs; - return fs; -} - - -/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */ -static struct usb_string fsg_strings[] = { -#ifndef FSG_NO_DEVICE_STRINGS - {FSG_STRING_MANUFACTURER, fsg_string_manufacturer}, - {FSG_STRING_PRODUCT, fsg_string_product}, - {FSG_STRING_SERIAL, ""}, - {FSG_STRING_CONFIG, fsg_string_config}, -#endif - {FSG_STRING_INTERFACE, fsg_string_interface}, - {} -}; - -static struct usb_gadget_strings fsg_stringtab = { - .language = 0x0409, /* en-us */ - .strings = fsg_strings, -}; - - - /*-------------------------------------------------------------------------*/ - -/* - * If the next two routines are called while the gadget is registered, - * the caller must own fsg->filesem for writing. - */ - -static int fsg_lun_open(struct fsg_lun *curlun, const char *filename) -{ - int ro; - struct file *filp = NULL; - int rc = -EINVAL; - struct inode *inode = NULL; - loff_t size; - loff_t num_sectors; - loff_t min_sectors; - - /* R/W if we can, R/O if we must */ - ro = curlun->initially_ro; - if (!ro) { - filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0); - if (PTR_ERR(filp) == -EROFS || PTR_ERR(filp) == -EACCES) - ro = 1; - } - if (ro) - filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0); - if (IS_ERR(filp)) { - LINFO(curlun, "unable to open backing file: %s\n", filename); - return PTR_ERR(filp); - } - - if (!(filp->f_mode & FMODE_WRITE)) - ro = 1; - - if (filp->f_path.dentry) - inode = filp->f_path.dentry->d_inode; - if (!inode || (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))) { - LINFO(curlun, "invalid file type: %s\n", filename); - goto out; - } - - /* - * If we can't read the file, it's no good. - * If we can't write the file, use it read-only. - */ - if (!filp->f_op || !(filp->f_op->read || filp->f_op->aio_read)) { - LINFO(curlun, "file not readable: %s\n", filename); - goto out; - } - if (!(filp->f_op->write || filp->f_op->aio_write)) - ro = 1; - - size = i_size_read(inode->i_mapping->host); - if (size < 0) { - LINFO(curlun, "unable to find file size: %s\n", filename); - rc = (int) size; - goto out; - } - - if (curlun->cdrom) { - curlun->blksize = 2048; - curlun->blkbits = 11; - } else if (inode->i_bdev) { - curlun->blksize = bdev_logical_block_size(inode->i_bdev); - curlun->blkbits = blksize_bits(curlun->blksize); - } else { - curlun->blksize = 512; - curlun->blkbits = 9; - } - - num_sectors = size >> curlun->blkbits; /* File size in logic-block-size blocks */ - min_sectors = 1; - if (curlun->cdrom) { - min_sectors = 300; /* Smallest track is 300 frames */ - if (num_sectors >= 256*60*75) { - num_sectors = 256*60*75 - 1; - LINFO(curlun, "file too big: %s\n", filename); - LINFO(curlun, "using only first %d blocks\n", - (int) num_sectors); - } - } - if (num_sectors < min_sectors) { - LINFO(curlun, "file too small: %s\n", filename); - rc = -ETOOSMALL; - goto out; - } - - get_file(filp); - curlun->ro = ro; - curlun->filp = filp; - curlun->file_length = size; - curlun->num_sectors = num_sectors; - LDBG(curlun, "open backing file: %s\n", filename); - rc = 0; - -out: - filp_close(filp, current->files); - return rc; -} - - -static void fsg_lun_close(struct fsg_lun *curlun) -{ - if (curlun->filp) { - LDBG(curlun, "close backing file\n"); - fput(curlun->filp); - curlun->filp = NULL; - } -} - - -/*-------------------------------------------------------------------------*/ - -/* - * Sync the file data, don't bother with the metadata. - * This code was copied from fs/buffer.c:sys_fdatasync(). - */ -static int fsg_lun_fsync_sub(struct fsg_lun *curlun) -{ - struct file *filp = curlun->filp; - - if (curlun->ro || !filp) - return 0; - return vfs_fsync(filp, 1); -} - -static void store_cdrom_address(u8 *dest, int msf, u32 addr) -{ - if (msf) { - /* Convert to Minutes-Seconds-Frames */ - addr >>= 2; /* Convert to 2048-byte frames */ - addr += 2*75; /* Lead-in occupies 2 seconds */ - dest[3] = addr % 75; /* Frames */ - addr /= 75; - dest[2] = addr % 60; /* Seconds */ - addr /= 60; - dest[1] = addr; /* Minutes */ - dest[0] = 0; /* Reserved */ - } else { - /* Absolute sector */ - put_unaligned_be32(addr, dest); - } -} - - -/*-------------------------------------------------------------------------*/ - - -static ssize_t fsg_show_ro(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct fsg_lun *curlun = fsg_lun_from_dev(dev); - - return sprintf(buf, "%d\n", fsg_lun_is_open(curlun) - ? curlun->ro - : curlun->initially_ro); -} - -static ssize_t fsg_show_nofua(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct fsg_lun *curlun = fsg_lun_from_dev(dev); - - return sprintf(buf, "%u\n", curlun->nofua); -} - -static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct fsg_lun *curlun = fsg_lun_from_dev(dev); - struct rw_semaphore *filesem = dev_get_drvdata(dev); - char *p; - ssize_t rc; - - down_read(filesem); - if (fsg_lun_is_open(curlun)) { /* Get the complete pathname */ - p = d_path(&curlun->filp->f_path, buf, PAGE_SIZE - 1); - if (IS_ERR(p)) - rc = PTR_ERR(p); - else { - rc = strlen(p); - memmove(buf, p, rc); - buf[rc] = '\n'; /* Add a newline */ - buf[++rc] = 0; - } - } else { /* No file, return 0 bytes */ - *buf = 0; - rc = 0; - } - up_read(filesem); - return rc; -} - -static ssize_t fsg_show_cdrom(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct fsg_lun *curlun = fsg_lun_from_dev(dev); - - return sprintf(buf, "%d\n", curlun->cdrom); -} - - -static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - ssize_t rc; - struct fsg_lun *curlun = fsg_lun_from_dev(dev); - struct rw_semaphore *filesem = dev_get_drvdata(dev); - unsigned ro; - - rc = kstrtouint(buf, 2, &ro); - if (rc) - return rc; - - /* - * Allow the write-enable status to change only while the - * backing file is closed. - */ - down_read(filesem); - if (fsg_lun_is_open(curlun)) { - LDBG(curlun, "read-only status change prevented\n"); - rc = -EBUSY; - } else { - curlun->ro = ro; - curlun->initially_ro = ro; - LDBG(curlun, "read-only status set to %d\n", curlun->ro); - rc = count; - } - up_read(filesem); - return rc; -} - -static ssize_t fsg_store_nofua(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct fsg_lun *curlun = fsg_lun_from_dev(dev); - unsigned nofua; - int ret; - - ret = kstrtouint(buf, 2, &nofua); - if (ret) - return ret; - - /* Sync data when switching from async mode to sync */ - if (!nofua && curlun->nofua) - fsg_lun_fsync_sub(curlun); - - curlun->nofua = nofua; - - return count; -} - -static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct fsg_lun *curlun = fsg_lun_from_dev(dev); - struct rw_semaphore *filesem = dev_get_drvdata(dev); - int rc = 0; - - if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) { - LDBG(curlun, "eject attempt prevented\n"); - return -EBUSY; /* "Door is locked" */ - } - - /* Remove a trailing newline */ - if (count > 0 && buf[count-1] == '\n') - ((char *) buf)[count-1] = 0; /* Ugh! */ - - /* Eject current medium */ - down_write(filesem); - if (fsg_lun_is_open(curlun)) { - fsg_lun_close(curlun); - curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT; - } - - /* Load new medium */ - if (count > 0 && buf[0]) { - rc = fsg_lun_open(curlun, buf); - if (rc == 0) - curlun->unit_attention_data = - SS_NOT_READY_TO_READY_TRANSITION; - } - up_write(filesem); - return (rc < 0 ? rc : count); -} - -static ssize_t fsg_store_cdrom(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - ssize_t rc; - struct fsg_lun *curlun = fsg_lun_from_dev(dev); - struct rw_semaphore *filesem = dev_get_drvdata(dev); - unsigned cdrom; - - rc = kstrtouint(buf, 2, &cdrom); - if (rc) - return rc; - - /* - * Allow the write-enable status to change only while the - * backing file is closed. - */ - down_read(filesem); - if (fsg_lun_is_open(curlun)) { - LDBG(curlun, "read-only status change prevented\n"); - rc = -EBUSY; - } else { - curlun->cdrom = cdrom; - LDBG(curlun, "cdrom status set to %d\n", curlun->cdrom); - rc = count; - } - up_read(filesem); - return rc; -} - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/u_ether.c b/ANDROID_3.4.5/drivers/usb/gadget/u_ether.c deleted file mode 100644 index 59ac7227..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/u_ether.c +++ /dev/null @@ -1,1015 +0,0 @@ -/* - * u_ether.c -- Ethernet-over-USB link layer utilities for Gadget stack - * - * Copyright (C) 2003-2005,2008 David Brownell - * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -/* #define VERBOSE_DEBUG */ - -#include -#include -#include -#include -#include -#include - -#include "u_ether.h" - - -/* - * This component encapsulates the Ethernet link glue needed to provide - * one (!) network link through the USB gadget stack, normally "usb0". - * - * The control and data models are handled by the function driver which - * connects to this code; such as CDC Ethernet (ECM or EEM), - * "CDC Subset", or RNDIS. That includes all descriptor and endpoint - * management. - * - * Link level addressing is handled by this component using module - * parameters; if no such parameters are provided, random link level - * addresses are used. Each end of the link uses one address. The - * host end address is exported in various ways, and is often recorded - * in configuration databases. - * - * The driver which assembles each configuration using such a link is - * responsible for ensuring that each configuration includes at most one - * instance of is network link. (The network layer provides ways for - * this single "physical" link to be used by multiple virtual links.) - */ - -#define UETH__VERSION "29-May-2008" - -struct eth_dev { - /* lock is held while accessing port_usb - * or updating its backlink port_usb->ioport - */ - spinlock_t lock; - struct gether *port_usb; - - struct net_device *net; - struct usb_gadget *gadget; - - spinlock_t req_lock; /* guard {rx,tx}_reqs */ - struct list_head tx_reqs, rx_reqs; - atomic_t tx_qlen; - - struct sk_buff_head rx_frames; - - unsigned header_len; - struct sk_buff *(*wrap)(struct gether *, struct sk_buff *skb); - int (*unwrap)(struct gether *, - struct sk_buff *skb, - struct sk_buff_head *list); - - struct work_struct work; - - unsigned long todo; -#define WORK_RX_MEMORY 0 - - bool zlp; - u8 host_mac[ETH_ALEN]; -}; - -/*-------------------------------------------------------------------------*/ - -#define RX_EXTRA 20 /* bytes guarding against rx overflows */ - -#define DEFAULT_QLEN 2 /* double buffering by default */ - - -#ifdef CONFIG_USB_GADGET_DUALSPEED - -static unsigned qmult = 5; -module_param(qmult, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(qmult, "queue length multiplier at high/super speed"); - -#else /* full speed (low speed doesn't do bulk) */ -#define qmult 1 -#endif - -/* for dual-speed hardware, use deeper queues at high/super speed */ -static inline int qlen(struct usb_gadget *gadget) -{ - if (gadget_is_dualspeed(gadget) && (gadget->speed == USB_SPEED_HIGH || - gadget->speed == USB_SPEED_SUPER)) - return qmult * DEFAULT_QLEN; - else - return DEFAULT_QLEN; -} - -/*-------------------------------------------------------------------------*/ - -/* REVISIT there must be a better way than having two sets - * of debug calls ... - */ - -#undef DBG -#undef VDBG -#undef ERROR -#undef INFO - -#define xprintk(d, level, fmt, args...) \ - printk(level "%s: " fmt , (d)->net->name , ## args) - -#ifdef DEBUG -#undef DEBUG -#define DBG(dev, fmt, args...) \ - xprintk(dev , KERN_DEBUG , fmt , ## args) -#else -#define DBG(dev, fmt, args...) \ - do { } while (0) -#endif /* DEBUG */ - -#ifdef VERBOSE_DEBUG -#define VDBG DBG -#else -#define VDBG(dev, fmt, args...) \ - do { } while (0) -#endif /* DEBUG */ - -#define ERROR(dev, fmt, args...) \ - xprintk(dev , KERN_ERR , fmt , ## args) -#define INFO(dev, fmt, args...) \ - xprintk(dev , KERN_INFO , fmt , ## args) - -/*-------------------------------------------------------------------------*/ - -/* NETWORK DRIVER HOOKUP (to the layer above this driver) */ - -static int ueth_change_mtu(struct net_device *net, int new_mtu) -{ - struct eth_dev *dev = netdev_priv(net); - unsigned long flags; - int status = 0; - - /* don't change MTU on "live" link (peer won't know) */ - spin_lock_irqsave(&dev->lock, flags); - if (dev->port_usb) - status = -EBUSY; - else if (new_mtu <= ETH_HLEN || new_mtu > ETH_FRAME_LEN) - status = -ERANGE; - else - net->mtu = new_mtu; - spin_unlock_irqrestore(&dev->lock, flags); - - return status; -} - -static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p) -{ - struct eth_dev *dev = netdev_priv(net); - - strlcpy(p->driver, "g_ether", sizeof p->driver); - strlcpy(p->version, UETH__VERSION, sizeof p->version); - strlcpy(p->fw_version, dev->gadget->name, sizeof p->fw_version); - strlcpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof p->bus_info); -} - -/* REVISIT can also support: - * - WOL (by tracking suspends and issuing remote wakeup) - * - msglevel (implies updated messaging) - * - ... probably more ethtool ops - */ - -static const struct ethtool_ops ops = { - .get_drvinfo = eth_get_drvinfo, - .get_link = ethtool_op_get_link, -}; - -static void defer_kevent(struct eth_dev *dev, int flag) -{ - if (test_and_set_bit(flag, &dev->todo)) - return; - if (!schedule_work(&dev->work)) - ERROR(dev, "kevent %d may have been dropped\n", flag); - else - DBG(dev, "kevent %d scheduled\n", flag); -} - -static void rx_complete(struct usb_ep *ep, struct usb_request *req); - -static int -rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags) -{ - struct sk_buff *skb; - int retval = -ENOMEM; - size_t size = 0; - struct usb_ep *out; - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - if (dev->port_usb) - out = dev->port_usb->out_ep; - else - out = NULL; - spin_unlock_irqrestore(&dev->lock, flags); - - if (!out) - return -ENOTCONN; - - - /* Padding up to RX_EXTRA handles minor disagreements with host. - * Normally we use the USB "terminate on short read" convention; - * so allow up to (N*maxpacket), since that memory is normally - * already allocated. Some hardware doesn't deal well with short - * reads (e.g. DMA must be N*maxpacket), so for now don't trim a - * byte off the end (to force hardware errors on overflow). - * - * RNDIS uses internal framing, and explicitly allows senders to - * pad to end-of-packet. That's potentially nice for speed, but - * means receivers can't recover lost synch on their own (because - * new packets don't only start after a short RX). - */ - size += sizeof(struct ethhdr) + dev->net->mtu + RX_EXTRA; - size += dev->port_usb->header_len; - size += out->maxpacket - 1; - size -= size % out->maxpacket; - - if (dev->port_usb->is_fixed) - size = max_t(size_t, size, dev->port_usb->fixed_out_len); - - skb = alloc_skb(size + NET_IP_ALIGN, gfp_flags); - if (skb == NULL) { - DBG(dev, "no rx skb\n"); - goto enomem; - } - - /* Some platforms perform better when IP packets are aligned, - * but on at least one, checksumming fails otherwise. Note: - * RNDIS headers involve variable numbers of LE32 values. - */ - skb_reserve(skb, NET_IP_ALIGN); - - req->buf = skb->data; - req->length = size; - req->complete = rx_complete; - req->context = skb; - - retval = usb_ep_queue(out, req, gfp_flags); - if (retval == -ENOMEM) -enomem: - defer_kevent(dev, WORK_RX_MEMORY); - if (retval) { - DBG(dev, "rx submit --> %d\n", retval); - if (skb) - dev_kfree_skb_any(skb); - spin_lock_irqsave(&dev->req_lock, flags); - list_add(&req->list, &dev->rx_reqs); - spin_unlock_irqrestore(&dev->req_lock, flags); - } - return retval; -} - -static void rx_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct sk_buff *skb = req->context, *skb2; - struct eth_dev *dev = ep->driver_data; - int status = req->status; - - switch (status) { - - /* normal completion */ - case 0: - skb_put(skb, req->actual); - - if (dev->unwrap) { - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - if (dev->port_usb) { - status = dev->unwrap(dev->port_usb, - skb, - &dev->rx_frames); - } else { - dev_kfree_skb_any(skb); - status = -ENOTCONN; - } - spin_unlock_irqrestore(&dev->lock, flags); - } else { - skb_queue_tail(&dev->rx_frames, skb); - } - skb = NULL; - - skb2 = skb_dequeue(&dev->rx_frames); - while (skb2) { - if (status < 0 - || ETH_HLEN > skb2->len - || skb2->len > ETH_FRAME_LEN) { - dev->net->stats.rx_errors++; - dev->net->stats.rx_length_errors++; - DBG(dev, "rx length %d\n", skb2->len); - dev_kfree_skb_any(skb2); - goto next_frame; - } - skb2->protocol = eth_type_trans(skb2, dev->net); - dev->net->stats.rx_packets++; - dev->net->stats.rx_bytes += skb2->len; - - /* no buffer copies needed, unless hardware can't - * use skb buffers. - */ - status = netif_rx(skb2); -next_frame: - skb2 = skb_dequeue(&dev->rx_frames); - } - break; - - /* software-driven interface shutdown */ - case -ECONNRESET: /* unlink */ - case -ESHUTDOWN: /* disconnect etc */ - VDBG(dev, "rx shutdown, code %d\n", status); - goto quiesce; - - /* for hardware automagic (such as pxa) */ - case -ECONNABORTED: /* endpoint reset */ - DBG(dev, "rx %s reset\n", ep->name); - defer_kevent(dev, WORK_RX_MEMORY); -quiesce: - dev_kfree_skb_any(skb); - goto clean; - - /* data overrun */ - case -EOVERFLOW: - dev->net->stats.rx_over_errors++; - /* FALLTHROUGH */ - - default: - dev->net->stats.rx_errors++; - DBG(dev, "rx status %d\n", status); - break; - } - - if (skb) - dev_kfree_skb_any(skb); - if (!netif_running(dev->net)) { -clean: - spin_lock(&dev->req_lock); - list_add(&req->list, &dev->rx_reqs); - spin_unlock(&dev->req_lock); - req = NULL; - } - if (req) - rx_submit(dev, req, GFP_ATOMIC); -} - -static int prealloc(struct list_head *list, struct usb_ep *ep, unsigned n) -{ - unsigned i; - struct usb_request *req; - - if (!n) - return -ENOMEM; - - /* queue/recycle up to N requests */ - i = n; - list_for_each_entry(req, list, list) { - if (i-- == 0) - goto extra; - } - while (i--) { - req = usb_ep_alloc_request(ep, GFP_ATOMIC); - if (!req) - return list_empty(list) ? -ENOMEM : 0; - list_add(&req->list, list); - } - return 0; - -extra: - /* free extras */ - for (;;) { - struct list_head *next; - - next = req->list.next; - list_del(&req->list); - usb_ep_free_request(ep, req); - - if (next == list) - break; - - req = container_of(next, struct usb_request, list); - } - return 0; -} - -static int alloc_requests(struct eth_dev *dev, struct gether *link, unsigned n) -{ - int status; - - spin_lock(&dev->req_lock); - status = prealloc(&dev->tx_reqs, link->in_ep, n); - if (status < 0) - goto fail; - status = prealloc(&dev->rx_reqs, link->out_ep, n); - if (status < 0) - goto fail; - goto done; -fail: - DBG(dev, "can't alloc requests\n"); -done: - spin_unlock(&dev->req_lock); - return status; -} - -static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags) -{ - struct usb_request *req; - unsigned long flags; - - /* fill unused rxq slots with some skb */ - spin_lock_irqsave(&dev->req_lock, flags); - while (!list_empty(&dev->rx_reqs)) { - req = container_of(dev->rx_reqs.next, - struct usb_request, list); - list_del_init(&req->list); - spin_unlock_irqrestore(&dev->req_lock, flags); - - if (rx_submit(dev, req, gfp_flags) < 0) { - defer_kevent(dev, WORK_RX_MEMORY); - return; - } - - spin_lock_irqsave(&dev->req_lock, flags); - } - spin_unlock_irqrestore(&dev->req_lock, flags); -} - -static void eth_work(struct work_struct *work) -{ - struct eth_dev *dev = container_of(work, struct eth_dev, work); - - if (test_and_clear_bit(WORK_RX_MEMORY, &dev->todo)) { - if (netif_running(dev->net)) - rx_fill(dev, GFP_KERNEL); - } - - if (dev->todo) - DBG(dev, "work done, flags = 0x%lx\n", dev->todo); -} - -static void tx_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct sk_buff *skb = req->context; - struct eth_dev *dev = ep->driver_data; - unsigned long flags; - switch (req->status) { - default: - dev->net->stats.tx_errors++; - VDBG(dev, "tx err %d\n", req->status); - /* FALLTHROUGH */ - case -ECONNRESET: /* unlink */ - case -ESHUTDOWN: /* disconnect etc */ - break; - case 0: - dev->net->stats.tx_bytes += skb->len; - } - dev->net->stats.tx_packets++; - - //spin_lock(&dev->req_lock); - spin_lock_irqsave(&dev->req_lock, flags); - list_add(&req->list, &dev->tx_reqs); - //spin_unlock(&dev->req_lock); - spin_unlock_irqrestore(&dev->req_lock, flags); - dev_kfree_skb_any(skb); - - atomic_dec(&dev->tx_qlen); - if (netif_carrier_ok(dev->net)) - netif_wake_queue(dev->net); -} - -static inline int is_promisc(u16 cdc_filter) -{ - return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS; -} - -static netdev_tx_t eth_start_xmit(struct sk_buff *skb, - struct net_device *net) -{ - struct eth_dev *dev = netdev_priv(net); - int length = skb->len; - int retval; - struct usb_request *req = NULL; - unsigned long flags; - struct usb_ep *in; - u16 cdc_filter; - - spin_lock_irqsave(&dev->lock, flags); - if (dev->port_usb) { - in = dev->port_usb->in_ep; - cdc_filter = dev->port_usb->cdc_filter; - } else { - in = NULL; - cdc_filter = 0; - } - spin_unlock_irqrestore(&dev->lock, flags); - - if (!in) { - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; - } - - /* apply outgoing CDC or RNDIS filters */ - if (!is_promisc(cdc_filter)) { - u8 *dest = skb->data; - - if (is_multicast_ether_addr(dest)) { - u16 type; - - /* ignores USB_CDC_PACKET_TYPE_MULTICAST and host - * SET_ETHERNET_MULTICAST_FILTERS requests - */ - if (is_broadcast_ether_addr(dest)) - type = USB_CDC_PACKET_TYPE_BROADCAST; - else - type = USB_CDC_PACKET_TYPE_ALL_MULTICAST; - if (!(cdc_filter & type)) { - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; - } - } - /* ignores USB_CDC_PACKET_TYPE_DIRECTED */ - } - - spin_lock_irqsave(&dev->req_lock, flags); - /* - * this freelist can be empty if an interrupt triggered disconnect() - * and reconfigured the gadget (shutting down this queue) after the - * network stack decided to xmit but before we got the spinlock. - */ - if (list_empty(&dev->tx_reqs)) { - spin_unlock_irqrestore(&dev->req_lock, flags); - return NETDEV_TX_BUSY; - } - - req = container_of(dev->tx_reqs.next, struct usb_request, list); - list_del(&req->list); - - /* temporarily stop TX queue when the freelist empties */ - if (list_empty(&dev->tx_reqs)) - netif_stop_queue(net); - spin_unlock_irqrestore(&dev->req_lock, flags); - - /* no buffer copies needed, unless the network stack did it - * or the hardware can't use skb buffers. - * or there's not enough space for extra headers we need - */ - if (dev->wrap) { - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - if (dev->port_usb) - skb = dev->wrap(dev->port_usb, skb); - spin_unlock_irqrestore(&dev->lock, flags); - if (!skb) - goto drop; - - length = skb->len; - } - req->buf = skb->data; - req->context = skb; - req->complete = tx_complete; - - /* NCM requires no zlp if transfer is dwNtbInMaxSize */ - if (dev->port_usb->is_fixed && - length == dev->port_usb->fixed_in_len && - (length % in->maxpacket) == 0) - req->zero = 0; - else - req->zero = 1; - - /* use zlp framing on tx for strict CDC-Ether conformance, - * though any robust network rx path ignores extra padding. - * and some hardware doesn't like to write zlps. - */ - if (req->zero && !dev->zlp && (length % in->maxpacket) == 0) - length++; - - req->length = length; - - /* throttle high/super speed IRQ rate back slightly */ - if (gadget_is_dualspeed(dev->gadget)) - req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH || - dev->gadget->speed == USB_SPEED_SUPER) - ? ((atomic_read(&dev->tx_qlen) % qmult) != 0) - : 0; - - retval = usb_ep_queue(in, req, GFP_ATOMIC); - switch (retval) { - default: - DBG(dev, "tx queue err %d\n", retval); - break; - case 0: - net->trans_start = jiffies; - atomic_inc(&dev->tx_qlen); - } - - if (retval) { - dev_kfree_skb_any(skb); -drop: - dev->net->stats.tx_dropped++; - spin_lock_irqsave(&dev->req_lock, flags); - if (list_empty(&dev->tx_reqs)) - netif_start_queue(net); - list_add(&req->list, &dev->tx_reqs); - spin_unlock_irqrestore(&dev->req_lock, flags); - } - return NETDEV_TX_OK; -} - -/*-------------------------------------------------------------------------*/ - -static void eth_start(struct eth_dev *dev, gfp_t gfp_flags) -{ - DBG(dev, "%s\n", __func__); - - /* fill the rx queue */ - rx_fill(dev, gfp_flags); - - /* and open the tx floodgates */ - atomic_set(&dev->tx_qlen, 0); - netif_wake_queue(dev->net); -} - -static int eth_open(struct net_device *net) -{ - struct eth_dev *dev = netdev_priv(net); - struct gether *link; - - DBG(dev, "%s\n", __func__); - if (netif_carrier_ok(dev->net)) - eth_start(dev, GFP_KERNEL); - - spin_lock_irq(&dev->lock); - link = dev->port_usb; - if (link && link->open) - link->open(link); - spin_unlock_irq(&dev->lock); - - return 0; -} - -static int eth_stop(struct net_device *net) -{ - struct eth_dev *dev = netdev_priv(net); - unsigned long flags; - - VDBG(dev, "%s\n", __func__); - netif_stop_queue(net); - - DBG(dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n", - dev->net->stats.rx_packets, dev->net->stats.tx_packets, - dev->net->stats.rx_errors, dev->net->stats.tx_errors - ); - - /* ensure there are no more active requests */ - spin_lock_irqsave(&dev->lock, flags); - if (dev->port_usb) { - struct gether *link = dev->port_usb; - - if (link->close) - link->close(link); - - /* NOTE: we have no abort-queue primitive we could use - * to cancel all pending I/O. Instead, we disable then - * reenable the endpoints ... this idiom may leave toggle - * wrong, but that's a self-correcting error. - * - * REVISIT: we *COULD* just let the transfers complete at - * their own pace; the network stack can handle old packets. - * For the moment we leave this here, since it works. - */ - usb_ep_disable(link->in_ep); - usb_ep_disable(link->out_ep); - if (netif_carrier_ok(net)) { - DBG(dev, "host still using in/out endpoints\n"); - usb_ep_enable(link->in_ep); - usb_ep_enable(link->out_ep); - } - } - spin_unlock_irqrestore(&dev->lock, flags); - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* initial value, changed by "ifconfig usb0 hw ether xx:xx:xx:xx:xx:xx" */ -static char *dev_addr; -module_param(dev_addr, charp, S_IRUGO); -MODULE_PARM_DESC(dev_addr, "Device Ethernet Address"); - -/* this address is invisible to ifconfig */ -static char *host_addr="02:50:e6:a8:b8:63"; -module_param(host_addr, charp, S_IRUGO); -MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); - -static int get_ether_addr(const char *str, u8 *dev_addr) -{ - if (str) { - unsigned i; - - for (i = 0; i < 6; i++) { - unsigned char num; - - if ((*str == '.') || (*str == ':')) - str++; - num = hex_to_bin(*str++) << 4; - num |= hex_to_bin(*str++); - dev_addr [i] = num; - } - if (is_valid_ether_addr(dev_addr)) - return 0; - } - random_ether_addr(dev_addr); - return 1; -} - -static struct eth_dev *the_dev; - -static const struct net_device_ops eth_netdev_ops = { - .ndo_open = eth_open, - .ndo_stop = eth_stop, - .ndo_start_xmit = eth_start_xmit, - .ndo_change_mtu = ueth_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - -static struct device_type gadget_type = { - .name = "gadget", -}; - -/** - * gether_setup - initialize one ethernet-over-usb link - * @g: gadget to associated with these links - * @ethaddr: NULL, or a buffer in which the ethernet address of the - * host side of the link is recorded - * Context: may sleep - * - * This sets up the single network link that may be exported by a - * gadget driver using this framework. The link layer addresses are - * set up using module parameters. - * - * Returns negative errno, or zero on success - */ -int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]) -{ - return gether_setup_name(g, ethaddr, "usb"); -} - -/** - * gether_setup_name - initialize one ethernet-over-usb link - * @g: gadget to associated with these links - * @ethaddr: NULL, or a buffer in which the ethernet address of the - * host side of the link is recorded - * @netname: name for network device (for example, "usb") - * Context: may sleep - * - * This sets up the single network link that may be exported by a - * gadget driver using this framework. The link layer addresses are - * set up using module parameters. - * - * Returns negative errno, or zero on success - */ -int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN], - const char *netname) -{ - struct eth_dev *dev; - struct net_device *net; - int status; - - if (the_dev) - return -EBUSY; - - net = alloc_etherdev(sizeof *dev); - if (!net) - return -ENOMEM; - - dev = netdev_priv(net); - spin_lock_init(&dev->lock); - spin_lock_init(&dev->req_lock); - INIT_WORK(&dev->work, eth_work); - INIT_LIST_HEAD(&dev->tx_reqs); - INIT_LIST_HEAD(&dev->rx_reqs); - - skb_queue_head_init(&dev->rx_frames); - - /* network device setup */ - dev->net = net; - snprintf(net->name, sizeof(net->name), "%s%%d", netname); - - if (get_ether_addr(dev_addr, net->dev_addr)) - dev_warn(&g->dev, - "using random %s ethernet address\n", "self"); - if (get_ether_addr(host_addr, dev->host_mac)) - dev_warn(&g->dev, - "using random %s ethernet address\n", "host"); - - if (ethaddr) - memcpy(ethaddr, dev->host_mac, ETH_ALEN); - - net->netdev_ops = ð_netdev_ops; - - SET_ETHTOOL_OPS(net, &ops); - - /* two kinds of host-initiated state changes: - * - iff DATA transfer is active, carrier is "on" - * - tx queueing enabled if open *and* carrier is "on" - */ - netif_carrier_off(net); - - dev->gadget = g; - SET_NETDEV_DEV(net, &g->dev); - SET_NETDEV_DEVTYPE(net, &gadget_type); - - status = register_netdev(net); - if (status < 0) { - dev_dbg(&g->dev, "register_netdev failed, %d\n", status); - free_netdev(net); - } else { - INFO(dev, "MAC %pM\n", net->dev_addr); - INFO(dev, "HOST MAC %pM\n", dev->host_mac); - - the_dev = dev; - } - - return status; -} - -/** - * gether_cleanup - remove Ethernet-over-USB device - * Context: may sleep - * - * This is called to free all resources allocated by @gether_setup(). - */ -void gether_cleanup(void) -{ - if (!the_dev) - return; - - unregister_netdev(the_dev->net); - flush_work_sync(&the_dev->work); - free_netdev(the_dev->net); - - the_dev = NULL; -} - - -/** - * gether_connect - notify network layer that USB link is active - * @link: the USB link, set up with endpoints, descriptors matching - * current device speed, and any framing wrapper(s) set up. - * Context: irqs blocked - * - * This is called to activate endpoints and let the network layer know - * the connection is active ("carrier detect"). It may cause the I/O - * queues to open and start letting network packets flow, but will in - * any case activate the endpoints so that they respond properly to the - * USB host. - * - * Verify net_device pointer returned using IS_ERR(). If it doesn't - * indicate some error code (negative errno), ep->driver_data values - * have been overwritten. - */ -struct net_device *gether_connect(struct gether *link) -{ - struct eth_dev *dev = the_dev; - int result = 0; - - if (!dev) - return ERR_PTR(-EINVAL); - - link->in_ep->driver_data = dev; - result = usb_ep_enable(link->in_ep); - if (result != 0) { - DBG(dev, "enable %s --> %d\n", - link->in_ep->name, result); - goto fail0; - } - - link->out_ep->driver_data = dev; - result = usb_ep_enable(link->out_ep); - if (result != 0) { - DBG(dev, "enable %s --> %d\n", - link->out_ep->name, result); - goto fail1; - } - - if (result == 0) - result = alloc_requests(dev, link, qlen(dev->gadget)); - - if (result == 0) { - dev->zlp = link->is_zlp_ok; - DBG(dev, "qlen %d\n", qlen(dev->gadget)); - - dev->header_len = link->header_len; - dev->unwrap = link->unwrap; - dev->wrap = link->wrap; - - spin_lock(&dev->lock); - dev->port_usb = link; - link->ioport = dev; - if (netif_running(dev->net)) { - if (link->open) - link->open(link); - } else { - if (link->close) - link->close(link); - } - spin_unlock(&dev->lock); - - netif_carrier_on(dev->net); - if (netif_running(dev->net)) - eth_start(dev, GFP_ATOMIC); - - /* on error, disable any endpoints */ - } else { - (void) usb_ep_disable(link->out_ep); -fail1: - (void) usb_ep_disable(link->in_ep); - } -fail0: - /* caller is responsible for cleanup on error */ - if (result < 0) - return ERR_PTR(result); - return dev->net; -} -extern void wmt_cleanup_done_thread(int number); -/** - * gether_disconnect - notify network layer that USB link is inactive - * @link: the USB link, on which gether_connect() was called - * Context: irqs blocked - * - * This is called to deactivate endpoints and let the network layer know - * the connection went inactive ("no carrier"). - * - * On return, the state is as if gether_connect() had never been called. - * The endpoints are inactive, and accordingly without active USB I/O. - * Pointers to endpoint descriptors and endpoint private data are nulled. - */ -void gether_disconnect(struct gether *link) -{ - struct eth_dev *dev = link->ioport; - struct usb_request *req; - unsigned long flags; - WARN_ON(!dev); - if (!dev) - return; - - DBG(dev, "%s\n", __func__); - - netif_stop_queue(dev->net); - netif_carrier_off(dev->net); - - /* disable endpoints, forcing (synchronous) completion - * of all pending i/o. then free the request objects - * and forget about the endpoints. - */ - usb_ep_disable(link->in_ep); - wmt_cleanup_done_thread(1); - spin_lock(&dev->req_lock); - while (!list_empty(&dev->tx_reqs)) { - req = container_of(dev->tx_reqs.next, - struct usb_request, list); - list_del(&req->list); - - spin_unlock(&dev->req_lock); - usb_ep_free_request(link->in_ep, req); - spin_lock(&dev->req_lock); - } - spin_unlock(&dev->req_lock); - link->in_ep->driver_data = NULL; - link->in_ep->desc = NULL; - - usb_ep_disable(link->out_ep); - wmt_cleanup_done_thread(1); - spin_lock(&dev->req_lock); - while (!list_empty(&dev->rx_reqs)) { - req = container_of(dev->rx_reqs.next, - struct usb_request, list); - list_del(&req->list); - - spin_unlock(&dev->req_lock); - usb_ep_free_request(link->out_ep, req); - spin_lock(&dev->req_lock); - } - spin_unlock(&dev->req_lock); - link->out_ep->driver_data = NULL; - link->out_ep->desc = NULL; - - /* finish forgetting about this USB link episode */ - dev->header_len = 0; - dev->unwrap = NULL; - dev->wrap = NULL; - - spin_lock(&dev->lock); - dev->port_usb = NULL; - link->ioport = NULL; - spin_unlock(&dev->lock); -} diff --git a/ANDROID_3.4.5/drivers/usb/gadget/u_ether.h b/ANDROID_3.4.5/drivers/usb/gadget/u_ether.h deleted file mode 100644 index 37431f52..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/u_ether.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * u_ether.h -- interface to USB gadget "ethernet link" utilities - * - * Copyright (C) 2003-2005,2008 David Brownell - * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger - * Copyright (C) 2008 Nokia Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef __U_ETHER_H -#define __U_ETHER_H - -#include -#include -#include -#include - -#include "gadget_chips.h" - - -/* - * This represents the USB side of an "ethernet" link, managed by a USB - * function which provides control and (maybe) framing. Two functions - * in different configurations could share the same ethernet link/netdev, - * using different host interaction models. - * - * There is a current limitation that only one instance of this link may - * be present in any given configuration. When that's a problem, network - * layer facilities can be used to package multiple logical links on this - * single "physical" one. - */ -struct gether { - struct usb_function func; - - /* updated by gether_{connect,disconnect} */ - struct eth_dev *ioport; - - /* endpoints handle full and/or high speeds */ - struct usb_ep *in_ep; - struct usb_ep *out_ep; - - bool is_zlp_ok; - - u16 cdc_filter; - - /* hooks for added framing, as needed for RNDIS and EEM. */ - u32 header_len; - /* NCM requires fixed size bundles */ - bool is_fixed; - u32 fixed_out_len; - u32 fixed_in_len; - struct sk_buff *(*wrap)(struct gether *port, - struct sk_buff *skb); - int (*unwrap)(struct gether *port, - struct sk_buff *skb, - struct sk_buff_head *list); - - /* called on network open/close */ - void (*open)(struct gether *); - void (*close)(struct gether *); -}; - -#define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \ - |USB_CDC_PACKET_TYPE_ALL_MULTICAST \ - |USB_CDC_PACKET_TYPE_PROMISCUOUS \ - |USB_CDC_PACKET_TYPE_DIRECTED) - - -/* netdev setup/teardown as directed by the gadget driver */ -int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]); -void gether_cleanup(void); -/* variant of gether_setup that allows customizing network device name */ -int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN], - const char *netname); - -/* connect/disconnect is handled by individual functions */ -struct net_device *gether_connect(struct gether *); -void gether_disconnect(struct gether *); - -/* Some controllers can't support CDC Ethernet (ECM) ... */ -static inline bool can_support_ecm(struct usb_gadget *gadget) -{ - if (!gadget_supports_altsettings(gadget)) - return false; - - /* Everything else is *presumably* fine ... but this is a bit - * chancy, so be **CERTAIN** there are no hardware issues with - * your controller. Add it above if it can't handle CDC. - */ - return true; -} - -/* each configuration may bind one instance of an ethernet link */ -int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]); -int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]); -int ncm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]); -int eem_bind_config(struct usb_configuration *c); - -#ifdef USB_ETH_RNDIS - -int rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]); -int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], - u32 vendorID, const char *manufacturer); - -#else - -static inline int -rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) -{ - return 0; -} - -static inline int -rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], - u32 vendorID, const char *manufacturer) -{ - return 0; -} - -#endif - -#endif /* __U_ETHER_H */ diff --git a/ANDROID_3.4.5/drivers/usb/gadget/u_phonet.h b/ANDROID_3.4.5/drivers/usb/gadget/u_phonet.h deleted file mode 100644 index 09a75259..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/u_phonet.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * u_phonet.h - interface to Phonet - * - * Copyright (C) 2007-2008 by Nokia Corporation - * - * This software is distributed under the terms of the GNU General - * Public License ("GPL") as published by the Free Software Foundation, - * either version 2 of that License or (at your option) any later version. - */ - -#ifndef __U_PHONET_H -#define __U_PHONET_H - -#include -#include - -int gphonet_setup(struct usb_gadget *gadget); -int phonet_bind_config(struct usb_configuration *c); -void gphonet_cleanup(void); - -#endif /* __U_PHONET_H */ diff --git a/ANDROID_3.4.5/drivers/usb/gadget/u_serial.c b/ANDROID_3.4.5/drivers/usb/gadget/u_serial.c deleted file mode 100644 index 380a87f6..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/u_serial.c +++ /dev/null @@ -1,1344 +0,0 @@ -/* - * u_serial.c - utilities for USB gadget "serial port"/TTY support - * - * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com) - * Copyright (C) 2008 David Brownell - * Copyright (C) 2008 by Nokia Corporation - * - * This code also borrows from usbserial.c, which is - * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2000 Peter Berger (pberger@brimson.com) - * Copyright (C) 2000 Al Borchers (alborchers@steinerpoint.com) - * - * This software is distributed under the terms of the GNU General - * Public License ("GPL") as published by the Free Software Foundation, - * either version 2 of that License or (at your option) any later version. - */ - -/* #define VERBOSE_DEBUG */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "u_serial.h" - - -/* - * This component encapsulates the TTY layer glue needed to provide basic - * "serial port" functionality through the USB gadget stack. Each such - * port is exposed through a /dev/ttyGS* node. - * - * After initialization (gserial_setup), these TTY port devices stay - * available until they are removed (gserial_cleanup). Each one may be - * connected to a USB function (gserial_connect), or disconnected (with - * gserial_disconnect) when the USB host issues a config change event. - * Data can only flow when the port is connected to the host. - * - * A given TTY port can be made available in multiple configurations. - * For example, each one might expose a ttyGS0 node which provides a - * login application. In one case that might use CDC ACM interface 0, - * while another configuration might use interface 3 for that. The - * work to handle that (including descriptor management) is not part - * of this component. - * - * Configurations may expose more than one TTY port. For example, if - * ttyGS0 provides login service, then ttyGS1 might provide dialer access - * for a telephone or fax link. And ttyGS2 might be something that just - * needs a simple byte stream interface for some messaging protocol that - * is managed in userspace ... OBEX, PTP, and MTP have been mentioned. - */ - -#define PREFIX "ttyGS" - -/* - * gserial is the lifecycle interface, used by USB functions - * gs_port is the I/O nexus, used by the tty driver - * tty_struct links to the tty/filesystem framework - * - * gserial <---> gs_port ... links will be null when the USB link is - * inactive; managed by gserial_{connect,disconnect}(). each gserial - * instance can wrap its own USB control protocol. - * gserial->ioport == usb_ep->driver_data ... gs_port - * gs_port->port_usb ... gserial - * - * gs_port <---> tty_struct ... links will be null when the TTY file - * isn't opened; managed by gs_open()/gs_close() - * gserial->port_tty ... tty_struct - * tty_struct->driver_data ... gserial - */ - -/* RX and TX queues can buffer QUEUE_SIZE packets before they hit the - * next layer of buffering. For TX that's a circular buffer; for RX - * consider it a NOP. A third layer is provided by the TTY code. - */ -#define QUEUE_SIZE 16 -#define WRITE_BUF_SIZE 8192 /* TX only */ - -/* circular buffer */ -struct gs_buf { - unsigned buf_size; - char *buf_buf; - char *buf_get; - char *buf_put; -}; - -/* - * The port structure holds info for each port, one for each minor number - * (and thus for each /dev/ node). - */ -struct gs_port { - spinlock_t port_lock; /* guard port_* access */ - - struct gserial *port_usb; - struct tty_struct *port_tty; - - unsigned open_count; - bool openclose; /* open/close in progress */ - u8 port_num; - - wait_queue_head_t close_wait; /* wait for last close */ - - struct list_head read_pool; - int read_started; - int read_allocated; - struct list_head read_queue; - unsigned n_read; - struct tasklet_struct push; - - struct list_head write_pool; - int write_started; - int write_allocated; - struct gs_buf port_write_buf; - wait_queue_head_t drain_wait; /* wait while writes drain */ - - /* REVISIT this state ... */ - struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */ -}; - -/* increase N_PORTS if you need more */ -#define N_PORTS 4 -static struct portmaster { - struct mutex lock; /* protect open/close */ - struct gs_port *port; -} ports[N_PORTS]; -static unsigned n_ports; - -#define GS_CLOSE_TIMEOUT 15 /* seconds */ - - - -#ifdef VERBOSE_DEBUG -#define pr_vdebug(fmt, arg...) \ - pr_debug(fmt, ##arg) -#else -#define pr_vdebug(fmt, arg...) \ - ({ if (0) pr_debug(fmt, ##arg); }) -#endif - -/*-------------------------------------------------------------------------*/ - -/* Circular Buffer */ - -/* - * gs_buf_alloc - * - * Allocate a circular buffer and all associated memory. - */ -static int gs_buf_alloc(struct gs_buf *gb, unsigned size) -{ - gb->buf_buf = kmalloc(size, GFP_KERNEL); - if (gb->buf_buf == NULL) - return -ENOMEM; - - gb->buf_size = size; - gb->buf_put = gb->buf_buf; - gb->buf_get = gb->buf_buf; - - return 0; -} - -/* - * gs_buf_free - * - * Free the buffer and all associated memory. - */ -static void gs_buf_free(struct gs_buf *gb) -{ - kfree(gb->buf_buf); - gb->buf_buf = NULL; -} - -/* - * gs_buf_clear - * - * Clear out all data in the circular buffer. - */ -static void gs_buf_clear(struct gs_buf *gb) -{ - gb->buf_get = gb->buf_put; - /* equivalent to a get of all data available */ -} - -/* - * gs_buf_data_avail - * - * Return the number of bytes of data written into the circular - * buffer. - */ -static unsigned gs_buf_data_avail(struct gs_buf *gb) -{ - return (gb->buf_size + gb->buf_put - gb->buf_get) % gb->buf_size; -} - -/* - * gs_buf_space_avail - * - * Return the number of bytes of space available in the circular - * buffer. - */ -static unsigned gs_buf_space_avail(struct gs_buf *gb) -{ - return (gb->buf_size + gb->buf_get - gb->buf_put - 1) % gb->buf_size; -} - -/* - * gs_buf_put - * - * Copy data data from a user buffer and put it into the circular buffer. - * Restrict to the amount of space available. - * - * Return the number of bytes copied. - */ -static unsigned -gs_buf_put(struct gs_buf *gb, const char *buf, unsigned count) -{ - unsigned len; - - len = gs_buf_space_avail(gb); - if (count > len) - count = len; - - if (count == 0) - return 0; - - len = gb->buf_buf + gb->buf_size - gb->buf_put; - if (count > len) { - memcpy(gb->buf_put, buf, len); - memcpy(gb->buf_buf, buf+len, count - len); - gb->buf_put = gb->buf_buf + count - len; - } else { - memcpy(gb->buf_put, buf, count); - if (count < len) - gb->buf_put += count; - else /* count == len */ - gb->buf_put = gb->buf_buf; - } - - return count; -} - -/* - * gs_buf_get - * - * Get data from the circular buffer and copy to the given buffer. - * Restrict to the amount of data available. - * - * Return the number of bytes copied. - */ -static unsigned -gs_buf_get(struct gs_buf *gb, char *buf, unsigned count) -{ - unsigned len; - - len = gs_buf_data_avail(gb); - if (count > len) - count = len; - - if (count == 0) - return 0; - - len = gb->buf_buf + gb->buf_size - gb->buf_get; - if (count > len) { - memcpy(buf, gb->buf_get, len); - memcpy(buf+len, gb->buf_buf, count - len); - gb->buf_get = gb->buf_buf + count - len; - } else { - memcpy(buf, gb->buf_get, count); - if (count < len) - gb->buf_get += count; - else /* count == len */ - gb->buf_get = gb->buf_buf; - } - - return count; -} - -/*-------------------------------------------------------------------------*/ - -/* I/O glue between TTY (upper) and USB function (lower) driver layers */ - -/* - * gs_alloc_req - * - * Allocate a usb_request and its buffer. Returns a pointer to the - * usb_request or NULL if there is an error. - */ -struct usb_request * -gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t kmalloc_flags) -{ - struct usb_request *req; - - req = usb_ep_alloc_request(ep, kmalloc_flags); - - if (req != NULL) { - req->length = len; - req->buf = kmalloc(len, kmalloc_flags); - if (req->buf == NULL) { - usb_ep_free_request(ep, req); - return NULL; - } - } - - return req; -} - -/* - * gs_free_req - * - * Free a usb_request and its buffer. - */ -void gs_free_req(struct usb_ep *ep, struct usb_request *req) -{ - kfree(req->buf); - usb_ep_free_request(ep, req); -} - -/* - * gs_send_packet - * - * If there is data to send, a packet is built in the given - * buffer and the size is returned. If there is no data to - * send, 0 is returned. - * - * Called with port_lock held. - */ -static unsigned -gs_send_packet(struct gs_port *port, char *packet, unsigned size) -{ - unsigned len; - - len = gs_buf_data_avail(&port->port_write_buf); - if (len < size) - size = len; - if (size != 0) - size = gs_buf_get(&port->port_write_buf, packet, size); - return size; -} - -/* - * gs_start_tx - * - * This function finds available write requests, calls - * gs_send_packet to fill these packets with data, and - * continues until either there are no more write requests - * available or no more data to send. This function is - * run whenever data arrives or write requests are available. - * - * Context: caller owns port_lock; port_usb is non-null. - */ -static int gs_start_tx(struct gs_port *port) -/* -__releases(&port->port_lock) -__acquires(&port->port_lock) -*/ -{ - struct list_head *pool = &port->write_pool; - struct usb_ep *in = port->port_usb->in; - int status = 0; - bool do_tty_wake = false; - - while (!list_empty(pool)) { - struct usb_request *req; - int len; - - if (port->write_started >= QUEUE_SIZE) - break; - - req = list_entry(pool->next, struct usb_request, list); - len = gs_send_packet(port, req->buf, in->maxpacket); - if (len == 0) { - wake_up_interruptible(&port->drain_wait); - break; - } - do_tty_wake = true; - - 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), - *((u8 *)req->buf+1), *((u8 *)req->buf+2)); - - /* Drop lock while we call out of driver; completions - * could be issued while we do so. Disconnection may - * happen too; maybe immediately before we queue this! - * - * NOTE that we may keep sending data for a while after - * the TTY closed (dev->ioport->port_tty is NULL). - */ - spin_unlock(&port->port_lock); - status = usb_ep_queue(in, req, GFP_ATOMIC); - spin_lock(&port->port_lock); - - if (status) { - pr_debug("%s: %s %s err %d\n", - __func__, "queue", in->name, status); - list_add(&req->list, pool); - break; - } - - port->write_started++; - - /* abort immediately after disconnect */ - if (!port->port_usb) - break; - } - - if (do_tty_wake && port->port_tty) - tty_wakeup(port->port_tty); - return status; -} - -/* - * Context: caller owns port_lock, and port_usb is set - */ -static unsigned gs_start_rx(struct gs_port *port) -/* -__releases(&port->port_lock) -__acquires(&port->port_lock) -*/ -{ - struct list_head *pool = &port->read_pool; - struct usb_ep *out = port->port_usb->out; - - while (!list_empty(pool)) { - struct usb_request *req; - int status; - struct tty_struct *tty; - - /* no more rx if closed */ - tty = port->port_tty; - if (!tty) - break; - - if (port->read_started >= QUEUE_SIZE) - break; - - req = list_entry(pool->next, struct usb_request, list); - list_del(&req->list); - req->length = out->maxpacket; - - /* drop lock while we call out; the controller driver - * may need to call us back (e.g. for disconnect) - */ - spin_unlock(&port->port_lock); - status = usb_ep_queue(out, req, GFP_ATOMIC); - spin_lock(&port->port_lock); - - if (status) { - pr_debug("%s: %s %s err %d\n", - __func__, "queue", out->name, status); - list_add(&req->list, pool); - break; - } - port->read_started++; - - /* abort immediately after disconnect */ - if (!port->port_usb) - break; - } - return port->read_started; -} - -/* - * RX tasklet takes data out of the RX queue and hands it up to the TTY - * layer until it refuses to take any more data (or is throttled back). - * Then it issues reads for any further data. - * - * If the RX queue becomes full enough that no usb_request is queued, - * the OUT endpoint may begin NAKing as soon as its FIFO fills up. - * So QUEUE_SIZE packets plus however many the FIFO holds (usually two) - * can be buffered before the TTY layer's buffers (currently 64 KB). - */ -static void gs_rx_push(unsigned long _port) -{ - struct gs_port *port = (void *)_port; - struct tty_struct *tty; - struct list_head *queue = &port->read_queue; - bool disconnect = false; - bool do_push = false; - - /* hand any queued data to the tty */ - spin_lock_irq(&port->port_lock); - tty = port->port_tty; - while (!list_empty(queue)) { - struct usb_request *req; - - req = list_first_entry(queue, struct usb_request, list); - - /* discard data if tty was closed */ - if (!tty) - goto recycle; - - /* leave data queued if tty was rx throttled */ - if (test_bit(TTY_THROTTLED, &tty->flags)) - break; - - switch (req->status) { - case -ESHUTDOWN: - disconnect = true; - pr_vdebug(PREFIX "%d: shutdown\n", port->port_num); - break; - - default: - /* presumably a transient fault */ - pr_warning(PREFIX "%d: unexpected RX status %d\n", - port->port_num, req->status); - /* FALLTHROUGH */ - case 0: - /* normal completion */ - break; - } - - /* push data to (open) tty */ - if (req->actual) { - char *packet = req->buf; - unsigned size = req->actual; - unsigned n; - int count; - - /* we may have pushed part of this packet already... */ - n = port->n_read; - if (n) { - packet += n; - size -= n; - } - - count = tty_insert_flip_string(tty, packet, size); - if (count) - do_push = true; - if (count != size) { - /* stop pushing; TTY layer can't handle more */ - port->n_read += count; - pr_vdebug(PREFIX "%d: rx block %d/%d\n", - port->port_num, - count, req->actual); - break; - } - port->n_read = 0; - } -recycle: - list_move(&req->list, &port->read_pool); - port->read_started--; - } - - /* Push from tty to ldisc; without low_latency set this is handled by - * a workqueue, so we won't get callbacks and can hold port_lock - */ - if (tty && do_push) - tty_flip_buffer_push(tty); - - - /* We want our data queue to become empty ASAP, keeping data - * in the tty and ldisc (not here). If we couldn't push any - * this time around, there may be trouble unless there's an - * implicit tty_unthrottle() call on its way... - * - * REVISIT we should probably add a timer to keep the tasklet - * from starving ... but it's not clear that case ever happens. - */ - if (!list_empty(queue) && tty) { - if (!test_bit(TTY_THROTTLED, &tty->flags)) { - if (do_push) - tasklet_schedule(&port->push); - else - pr_warning(PREFIX "%d: RX not scheduled?\n", - port->port_num); - } - } - - /* If we're still connected, refill the USB RX queue. */ - if (!disconnect && port->port_usb) - gs_start_rx(port); - - spin_unlock_irq(&port->port_lock); -} - -static void gs_read_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct gs_port *port = ep->driver_data; - - /* Queue all received data until the tty layer is ready for it. */ - spin_lock(&port->port_lock); - list_add_tail(&req->list, &port->read_queue); - tasklet_schedule(&port->push); - spin_unlock(&port->port_lock); -} - -static void gs_write_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct gs_port *port = ep->driver_data; - - spin_lock(&port->port_lock); - list_add(&req->list, &port->write_pool); - port->write_started--; - - switch (req->status) { - default: - /* presumably a transient fault */ - pr_warning("%s: unexpected %s status %d\n", - __func__, ep->name, req->status); - /* FALL THROUGH */ - case 0: - /* normal completion */ - gs_start_tx(port); - break; - - case -ESHUTDOWN: - /* disconnect */ - pr_vdebug("%s: %s shutdown\n", __func__, ep->name); - break; - } - - spin_unlock(&port->port_lock); -} - -static void gs_free_requests(struct usb_ep *ep, struct list_head *head, - int *allocated) -{ - struct usb_request *req; - - while (!list_empty(head)) { - req = list_entry(head->next, struct usb_request, list); - list_del(&req->list); - gs_free_req(ep, req); - if (allocated) - (*allocated)--; - } -} - -static int gs_alloc_requests(struct usb_ep *ep, struct list_head *head, - void (*fn)(struct usb_ep *, struct usb_request *), - int *allocated) -{ - int i; - struct usb_request *req; - int n = allocated ? QUEUE_SIZE - *allocated : QUEUE_SIZE; - - /* Pre-allocate up to QUEUE_SIZE transfers, but if we can't - * do quite that many this time, don't fail ... we just won't - * be as speedy as we might otherwise be. - */ - for (i = 0; i < n; i++) { - req = gs_alloc_req(ep, ep->maxpacket, GFP_ATOMIC); - if (!req) - return list_empty(head) ? -ENOMEM : 0; - req->complete = fn; - list_add_tail(&req->list, head); - if (allocated) - (*allocated)++; - } - return 0; -} - -/** - * gs_start_io - start USB I/O streams - * @dev: encapsulates endpoints to use - * Context: holding port_lock; port_tty and port_usb are non-null - * - * We only start I/O when something is connected to both sides of - * this port. If nothing is listening on the host side, we may - * be pointlessly filling up our TX buffers and FIFO. - */ -static int gs_start_io(struct gs_port *port) -{ - struct list_head *head = &port->read_pool; - struct usb_ep *ep = port->port_usb->out; - int status; - unsigned started; - - /* Allocate RX and TX I/O buffers. We can't easily do this much - * earlier (with GFP_KERNEL) because the requests are coupled to - * endpoints, as are the packet sizes we'll be using. Different - * configurations may use different endpoints with a given port; - * and high speed vs full speed changes packet sizes too. - */ - status = gs_alloc_requests(ep, head, gs_read_complete, - &port->read_allocated); - if (status) - return status; - - status = gs_alloc_requests(port->port_usb->in, &port->write_pool, - gs_write_complete, &port->write_allocated); - if (status) { - gs_free_requests(ep, head, &port->read_allocated); - return status; - } - - /* queue read requests */ - port->n_read = 0; - started = gs_start_rx(port); - - /* unblock any pending writes into our circular buffer */ - if (started) { - tty_wakeup(port->port_tty); - } else { - gs_free_requests(ep, head, &port->read_allocated); - gs_free_requests(port->port_usb->in, &port->write_pool, - &port->write_allocated); - status = -EIO; - } - - return status; -} - -/*-------------------------------------------------------------------------*/ - -/* TTY Driver */ - -/* - * gs_open sets up the link between a gs_port and its associated TTY. - * That link is broken *only* by TTY close(), and all driver methods - * know that. - */ -static int gs_open(struct tty_struct *tty, struct file *file) -{ - int port_num = tty->index; - struct gs_port *port; - int status; - - do { - mutex_lock(&ports[port_num].lock); - port = ports[port_num].port; - if (!port) - status = -ENODEV; - else { - spin_lock_irq(&port->port_lock); - - /* already open? Great. */ - if (port->open_count) { - status = 0; - port->open_count++; - - /* currently opening/closing? wait ... */ - } else if (port->openclose) { - status = -EBUSY; - - /* ... else we do the work */ - } else { - status = -EAGAIN; - port->openclose = true; - } - spin_unlock_irq(&port->port_lock); - } - mutex_unlock(&ports[port_num].lock); - - switch (status) { - default: - /* fully handled */ - return status; - case -EAGAIN: - /* must do the work */ - break; - case -EBUSY: - /* wait for EAGAIN task to finish */ - msleep(1); - /* REVISIT could have a waitchannel here, if - * concurrent open performance is important - */ - break; - } - } while (status != -EAGAIN); - - /* Do the "real open" */ - spin_lock_irq(&port->port_lock); - - /* allocate circular buffer on first open */ - if (port->port_write_buf.buf_buf == NULL) { - - spin_unlock_irq(&port->port_lock); - status = gs_buf_alloc(&port->port_write_buf, WRITE_BUF_SIZE); - spin_lock_irq(&port->port_lock); - - if (status) { - pr_debug("gs_open: ttyGS%d (%p,%p) no buffer\n", - port->port_num, tty, file); - port->openclose = false; - goto exit_unlock_port; - } - } - - /* REVISIT if REMOVED (ports[].port NULL), abort the open - * to let rmmod work faster (but this way isn't wrong). - */ - - /* REVISIT maybe wait for "carrier detect" */ - - tty->driver_data = port; - port->port_tty = tty; - - port->open_count = 1; - port->openclose = false; - - /* if connected, start the I/O stream */ - if (port->port_usb) { - struct gserial *gser = port->port_usb; - - pr_debug("gs_open: start ttyGS%d\n", port->port_num); - gs_start_io(port); - - if (gser->connect) - gser->connect(gser); - } - - pr_debug("gs_open: ttyGS%d (%p,%p)\n", port->port_num, tty, file); - - status = 0; - -exit_unlock_port: - spin_unlock_irq(&port->port_lock); - return status; -} - -static int gs_writes_finished(struct gs_port *p) -{ - int cond; - - /* return true on disconnect or empty buffer */ - spin_lock_irq(&p->port_lock); - cond = (p->port_usb == NULL) || !gs_buf_data_avail(&p->port_write_buf); - spin_unlock_irq(&p->port_lock); - - return cond; -} - -static void gs_close(struct tty_struct *tty, struct file *file) -{ - struct gs_port *port = tty->driver_data; - struct gserial *gser; - - spin_lock_irq(&port->port_lock); - - if (port->open_count != 1) { - if (port->open_count == 0) - WARN_ON(1); - else - --port->open_count; - goto exit; - } - - pr_debug("gs_close: ttyGS%d (%p,%p) ...\n", port->port_num, tty, file); - - /* mark port as closing but in use; we can drop port lock - * and sleep if necessary - */ - port->openclose = true; - port->open_count = 0; - - gser = port->port_usb; - if (gser && gser->disconnect) - gser->disconnect(gser); - - /* wait for circular write buffer to drain, disconnect, or at - * most GS_CLOSE_TIMEOUT seconds; then discard the rest - */ - if (gs_buf_data_avail(&port->port_write_buf) > 0 && gser) { - spin_unlock_irq(&port->port_lock); - wait_event_interruptible_timeout(port->drain_wait, - gs_writes_finished(port), - GS_CLOSE_TIMEOUT * HZ); - spin_lock_irq(&port->port_lock); - gser = port->port_usb; - } - - /* Iff we're disconnected, there can be no I/O in flight so it's - * ok to free the circular buffer; else just scrub it. And don't - * let the push tasklet fire again until we're re-opened. - */ - if (gser == NULL) - gs_buf_free(&port->port_write_buf); - else - gs_buf_clear(&port->port_write_buf); - - tty->driver_data = NULL; - port->port_tty = NULL; - - port->openclose = false; - - pr_debug("gs_close: ttyGS%d (%p,%p) done!\n", - port->port_num, tty, file); - - wake_up_interruptible(&port->close_wait); -exit: - spin_unlock_irq(&port->port_lock); -} - -static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count) -{ - struct gs_port *port = tty->driver_data; - unsigned long flags; - int status; - - pr_vdebug("gs_write: ttyGS%d (%p) writing %d bytes\n", - port->port_num, tty, count); - - spin_lock_irqsave(&port->port_lock, flags); - if (count) - count = gs_buf_put(&port->port_write_buf, buf, count); - /* treat count == 0 as flush_chars() */ - if (port->port_usb) - status = gs_start_tx(port); - spin_unlock_irqrestore(&port->port_lock, flags); - - return count; -} - -static int gs_put_char(struct tty_struct *tty, unsigned char ch) -{ - struct gs_port *port = tty->driver_data; - unsigned long flags; - int status; - - pr_vdebug("gs_put_char: (%d,%p) char=0x%x, called from %p\n", - port->port_num, tty, ch, __builtin_return_address(0)); - - spin_lock_irqsave(&port->port_lock, flags); - status = gs_buf_put(&port->port_write_buf, &ch, 1); - spin_unlock_irqrestore(&port->port_lock, flags); - - return status; -} - -static void gs_flush_chars(struct tty_struct *tty) -{ - struct gs_port *port = tty->driver_data; - unsigned long flags; - - pr_vdebug("gs_flush_chars: (%d,%p)\n", port->port_num, tty); - - spin_lock_irqsave(&port->port_lock, flags); - if (port->port_usb) - gs_start_tx(port); - spin_unlock_irqrestore(&port->port_lock, flags); -} - -static int gs_write_room(struct tty_struct *tty) -{ - struct gs_port *port = tty->driver_data; - unsigned long flags; - int room = 0; - - spin_lock_irqsave(&port->port_lock, flags); - if (port->port_usb) - room = gs_buf_space_avail(&port->port_write_buf); - spin_unlock_irqrestore(&port->port_lock, flags); - - pr_vdebug("gs_write_room: (%d,%p) room=%d\n", - port->port_num, tty, room); - - return room; -} - -static int gs_chars_in_buffer(struct tty_struct *tty) -{ - struct gs_port *port = tty->driver_data; - unsigned long flags; - int chars = 0; - - spin_lock_irqsave(&port->port_lock, flags); - chars = gs_buf_data_avail(&port->port_write_buf); - spin_unlock_irqrestore(&port->port_lock, flags); - - pr_vdebug("gs_chars_in_buffer: (%d,%p) chars=%d\n", - port->port_num, tty, chars); - - return chars; -} - -/* undo side effects of setting TTY_THROTTLED */ -static void gs_unthrottle(struct tty_struct *tty) -{ - struct gs_port *port = tty->driver_data; - unsigned long flags; - - spin_lock_irqsave(&port->port_lock, flags); - if (port->port_usb) { - /* Kickstart read queue processing. We don't do xon/xoff, - * rts/cts, or other handshaking with the host, but if the - * read queue backs up enough we'll be NAKing OUT packets. - */ - tasklet_schedule(&port->push); - pr_vdebug(PREFIX "%d: unthrottle\n", port->port_num); - } - spin_unlock_irqrestore(&port->port_lock, flags); -} - -static int gs_break_ctl(struct tty_struct *tty, int duration) -{ - struct gs_port *port = tty->driver_data; - int status = 0; - struct gserial *gser; - - pr_vdebug("gs_break_ctl: ttyGS%d, send break (%d) \n", - port->port_num, duration); - - spin_lock_irq(&port->port_lock); - gser = port->port_usb; - if (gser && gser->send_break) - status = gser->send_break(gser, duration); - spin_unlock_irq(&port->port_lock); - - return status; -} - -static const struct tty_operations gs_tty_ops = { - .open = gs_open, - .close = gs_close, - .write = gs_write, - .put_char = gs_put_char, - .flush_chars = gs_flush_chars, - .write_room = gs_write_room, - .chars_in_buffer = gs_chars_in_buffer, - .unthrottle = gs_unthrottle, - .break_ctl = gs_break_ctl, -}; - -/*-------------------------------------------------------------------------*/ - -static struct tty_driver *gs_tty_driver; - -static int -gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding) -{ - struct gs_port *port; - - port = kzalloc(sizeof(struct gs_port), GFP_KERNEL); - if (port == NULL) - return -ENOMEM; - - spin_lock_init(&port->port_lock); - init_waitqueue_head(&port->close_wait); - init_waitqueue_head(&port->drain_wait); - - tasklet_init(&port->push, gs_rx_push, (unsigned long) port); - - INIT_LIST_HEAD(&port->read_pool); - INIT_LIST_HEAD(&port->read_queue); - INIT_LIST_HEAD(&port->write_pool); - - port->port_num = port_num; - port->port_line_coding = *coding; - - ports[port_num].port = port; - - return 0; -} - -/** - * gserial_setup - initialize TTY driver for one or more ports - * @g: gadget to associate with these ports - * @count: how many ports to support - * Context: may sleep - * - * The TTY stack needs to know in advance how many devices it should - * plan to manage. Use this call to set up the ports you will be - * exporting through USB. Later, connect them to functions based - * on what configuration is activated by the USB host; and disconnect - * them as appropriate. - * - * An example would be a two-configuration device in which both - * configurations expose port 0, but through different functions. - * One configuration could even expose port 1 while the other - * one doesn't. - * - * Returns negative errno or zero. - */ -int gserial_setup(struct usb_gadget *g, unsigned count) -{ - unsigned i; - struct usb_cdc_line_coding coding; - int status; - - if (count == 0 || count > N_PORTS) - return -EINVAL; - - gs_tty_driver = alloc_tty_driver(count); - if (!gs_tty_driver) - return -ENOMEM; - - gs_tty_driver->driver_name = "g_serial"; - gs_tty_driver->name = PREFIX; - /* uses dynamically assigned dev_t values */ - - gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; - gs_tty_driver->subtype = SERIAL_TYPE_NORMAL; - gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - gs_tty_driver->init_termios = tty_std_termios; - - /* 9600-8-N-1 ... matches defaults expected by "usbser.sys" on - * MS-Windows. Otherwise, most of these flags shouldn't affect - * anything unless we were to actually hook up to a serial line. - */ - gs_tty_driver->init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - gs_tty_driver->init_termios.c_ispeed = 9600; - gs_tty_driver->init_termios.c_ospeed = 9600; - - coding.dwDTERate = cpu_to_le32(9600); - coding.bCharFormat = 8; - coding.bParityType = USB_CDC_NO_PARITY; - coding.bDataBits = USB_CDC_1_STOP_BITS; - - tty_set_operations(gs_tty_driver, &gs_tty_ops); - - /* make devices be openable */ - for (i = 0; i < count; i++) { - mutex_init(&ports[i].lock); - status = gs_port_alloc(i, &coding); - if (status) { - count = i; - goto fail; - } - } - n_ports = count; - - /* export the driver ... */ - status = tty_register_driver(gs_tty_driver); - if (status) { - pr_err("%s: cannot register, err %d\n", - __func__, status); - goto fail; - } - - /* ... and sysfs class devices, so mdev/udev make /dev/ttyGS* */ - for (i = 0; i < count; i++) { - struct device *tty_dev; - - tty_dev = tty_register_device(gs_tty_driver, i, &g->dev); - if (IS_ERR(tty_dev)) - pr_warning("%s: no classdev for port %d, err %ld\n", - __func__, i, PTR_ERR(tty_dev)); - } - - pr_debug("%s: registered %d ttyGS* device%s\n", __func__, - count, (count == 1) ? "" : "s"); - - return status; -fail: - while (count--) - kfree(ports[count].port); - put_tty_driver(gs_tty_driver); - gs_tty_driver = NULL; - return status; -} - -static int gs_closed(struct gs_port *port) -{ - int cond; - - spin_lock_irq(&port->port_lock); - cond = (port->open_count == 0) && !port->openclose; - spin_unlock_irq(&port->port_lock); - return cond; -} - -/** - * gserial_cleanup - remove TTY-over-USB driver and devices - * Context: may sleep - * - * This is called to free all resources allocated by @gserial_setup(). - * Accordingly, it may need to wait until some open /dev/ files have - * closed. - * - * The caller must have issued @gserial_disconnect() for any ports - * that had previously been connected, so that there is never any - * I/O pending when it's called. - */ -void gserial_cleanup(void) -{ - unsigned i; - struct gs_port *port; - - if (!gs_tty_driver) - return; - - /* start sysfs and /dev/ttyGS* node removal */ - for (i = 0; i < n_ports; i++) - tty_unregister_device(gs_tty_driver, i); - - for (i = 0; i < n_ports; i++) { - /* prevent new opens */ - mutex_lock(&ports[i].lock); - port = ports[i].port; - ports[i].port = NULL; - mutex_unlock(&ports[i].lock); - - tasklet_kill(&port->push); - - /* wait for old opens to finish */ - wait_event(port->close_wait, gs_closed(port)); - - WARN_ON(port->port_usb != NULL); - - kfree(port); - } - n_ports = 0; - - tty_unregister_driver(gs_tty_driver); - put_tty_driver(gs_tty_driver); - gs_tty_driver = NULL; - - pr_debug("%s: cleaned up ttyGS* support\n", __func__); -} - -/** - * gserial_connect - notify TTY I/O glue that USB link is active - * @gser: the function, set up with endpoints and descriptors - * @port_num: which port is active - * Context: any (usually from irq) - * - * This is called activate endpoints and let the TTY layer know that - * the connection is active ... not unlike "carrier detect". It won't - * necessarily start I/O queues; unless the TTY is held open by any - * task, there would be no point. However, the endpoints will be - * activated so the USB host can perform I/O, subject to basic USB - * hardware flow control. - * - * Caller needs to have set up the endpoints and USB function in @dev - * before calling this, as well as the appropriate (speed-specific) - * endpoint descriptors, and also have set up the TTY driver by calling - * @gserial_setup(). - * - * Returns negative errno or zero. - * On success, ep->driver_data will be overwritten. - */ -int gserial_connect(struct gserial *gser, u8 port_num) -{ - struct gs_port *port; - unsigned long flags; - int status; - - if (!gs_tty_driver || port_num >= n_ports) - return -ENXIO; - - /* we "know" gserial_cleanup() hasn't been called */ - port = ports[port_num].port; - - /* activate the endpoints */ - status = usb_ep_enable(gser->in); - if (status < 0) - return status; - gser->in->driver_data = port; - - status = usb_ep_enable(gser->out); - if (status < 0) - goto fail_out; - gser->out->driver_data = port; - - /* then tell the tty glue that I/O can work */ - spin_lock_irqsave(&port->port_lock, flags); - gser->ioport = port; - port->port_usb = gser; - - /* REVISIT unclear how best to handle this state... - * we don't really couple it with the Linux TTY. - */ - gser->port_line_coding = port->port_line_coding; - - /* REVISIT if waiting on "carrier detect", signal. */ - - /* if it's already open, start I/O ... and notify the serial - * protocol about open/close status (connect/disconnect). - */ - if (port->open_count) { - pr_debug("gserial_connect: start ttyGS%d\n", port->port_num); - gs_start_io(port); - if (gser->connect) - gser->connect(gser); - } else { - if (gser->disconnect) - gser->disconnect(gser); - } - - spin_unlock_irqrestore(&port->port_lock, flags); - - return status; - -fail_out: - usb_ep_disable(gser->in); - gser->in->driver_data = NULL; - return status; -} - -/** - * gserial_disconnect - notify TTY I/O glue that USB link is inactive - * @gser: the function, on which gserial_connect() was called - * Context: any (usually from irq) - * - * This is called to deactivate endpoints and let the TTY layer know - * that the connection went inactive ... not unlike "hangup". - * - * On return, the state is as if gserial_connect() had never been called; - * there is no active USB I/O on these endpoints. - */ -void gserial_disconnect(struct gserial *gser) -{ - struct gs_port *port = gser->ioport; - unsigned long flags; - - if (!port) - return; - - /* tell the TTY glue not to do I/O here any more */ - spin_lock_irqsave(&port->port_lock, flags); - - /* REVISIT as above: how best to track this? */ - port->port_line_coding = gser->port_line_coding; - - port->port_usb = NULL; - gser->ioport = NULL; - if (port->open_count > 0 || port->openclose) { - wake_up_interruptible(&port->drain_wait); - if (port->port_tty) - tty_hangup(port->port_tty); - } - spin_unlock_irqrestore(&port->port_lock, flags); - - /* disable endpoints, aborting down any active I/O */ - usb_ep_disable(gser->out); - gser->out->driver_data = NULL; - - usb_ep_disable(gser->in); - gser->in->driver_data = NULL; - - /* finally, free any unused/unusable I/O buffers */ - spin_lock_irqsave(&port->port_lock, flags); - if (port->open_count == 0 && !port->openclose) - gs_buf_free(&port->port_write_buf); - gs_free_requests(gser->out, &port->read_pool, NULL); - gs_free_requests(gser->out, &port->read_queue, NULL); - gs_free_requests(gser->in, &port->write_pool, NULL); - - port->read_allocated = port->read_started = - port->write_allocated = port->write_started = 0; - - spin_unlock_irqrestore(&port->port_lock, flags); -} diff --git a/ANDROID_3.4.5/drivers/usb/gadget/u_serial.h b/ANDROID_3.4.5/drivers/usb/gadget/u_serial.h deleted file mode 100644 index 9b0fe645..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/u_serial.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * u_serial.h - interface to USB gadget "serial port"/TTY utilities - * - * Copyright (C) 2008 David Brownell - * Copyright (C) 2008 by Nokia Corporation - * - * This software is distributed under the terms of the GNU General - * Public License ("GPL") as published by the Free Software Foundation, - * either version 2 of that License or (at your option) any later version. - */ - -#ifndef __U_SERIAL_H -#define __U_SERIAL_H - -#include -#include - -/* - * One non-multiplexed "serial" I/O port ... there can be several of these - * on any given USB peripheral device, if it provides enough endpoints. - * - * The "u_serial" utility component exists to do one thing: manage TTY - * style I/O using the USB peripheral endpoints listed here, including - * hookups to sysfs and /dev for each logical "tty" device. - * - * REVISIT at least ACM could support tiocmget() if needed. - * - * REVISIT someday, allow multiplexing several TTYs over these endpoints. - */ -struct gserial { - struct usb_function func; - - /* port is managed by gserial_{connect,disconnect} */ - struct gs_port *ioport; - - struct usb_ep *in; - struct usb_ep *out; - - /* REVISIT avoid this CDC-ACM support harder ... */ - struct usb_cdc_line_coding port_line_coding; /* 9600-8-N-1 etc */ - - /* notification callbacks */ - void (*connect)(struct gserial *p); - void (*disconnect)(struct gserial *p); - int (*send_break)(struct gserial *p, int duration); -}; - -/* utilities to allocate/free request and buffer */ -struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned len, gfp_t flags); -void gs_free_req(struct usb_ep *, struct usb_request *req); - -/* port setup/teardown is handled by gadget driver */ -int gserial_setup(struct usb_gadget *g, unsigned n_ports); -void gserial_cleanup(void); - -/* connect/disconnect is handled by individual functions */ -int gserial_connect(struct gserial *, u8 port_num); -void gserial_disconnect(struct gserial *); - -/* functions are bound to configurations by a config or gadget driver */ -int acm_bind_config(struct usb_configuration *c, u8 port_num); -int gser_bind_config(struct usb_configuration *c, u8 port_num); -int obex_bind_config(struct usb_configuration *c, u8 port_num); - -#endif /* __U_SERIAL_H */ diff --git a/ANDROID_3.4.5/drivers/usb/gadget/u_uac1.c b/ANDROID_3.4.5/drivers/usb/gadget/u_uac1.c deleted file mode 100644 index af989898..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/u_uac1.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - * u_uac1.c -- ALSA audio utilities for Gadget stack - * - * Copyright (C) 2008 Bryan Wu - * Copyright (C) 2008 Analog Devices, Inc - * - * Enter bugs at http://blackfin.uclinux.org/ - * - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "u_uac1.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->substream = NULL; - snd->card = NULL; - snd->filp = NULL; - } else { - 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 (snd->filp) - filp_close(snd->filp, current->files); - - /* Close PCM playback device and setup substream */ - snd = &gau->playback; - if (snd->filp) - filp_close(snd->filp, current->files); - - /* Close PCM capture device and setup substream */ - snd = &gau->capture; - if (snd->filp) - filp_close(snd->filp, current->files); - - return 0; -} - -static struct gaudio *the_card; -/** - * 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"); - else if (!the_card) - the_card = card; - - return ret; - -} - -/** - * gaudio_cleanup - remove ALSA device interface - * - * This is called to free all resources allocated by @gaudio_setup(). - */ -void gaudio_cleanup(void) -{ - if (the_card) { - gaudio_close_snd_dev(the_card); - the_card = NULL; - } -} - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/u_uac1.h b/ANDROID_3.4.5/drivers/usb/gadget/u_uac1.h deleted file mode 100644 index 18c2e729..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/u_uac1.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * u_uac1.h -- interface to USB gadget "ALSA AUDIO" utilities - * - * Copyright (C) 2008 Bryan Wu - * 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 -#include -#include -#include - -#include -#include -#include - -#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(void); - -#endif /* __U_AUDIO_H */ diff --git a/ANDROID_3.4.5/drivers/usb/gadget/udc-core.c b/ANDROID_3.4.5/drivers/usb/gadget/udc-core.c deleted file mode 100644 index e5e44f8c..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/udc-core.c +++ /dev/null @@ -1,539 +0,0 @@ -/** - * udc.c - Core UDC Framework - * - * Copyright (C) 2010 Texas Instruments - * Author: Felipe Balbi - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 of - * the License 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, see . - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -/** - * struct usb_udc - describes one usb device controller - * @driver - the gadget driver pointer. For use by the class code - * @dev - the child device to the actual controller - * @gadget - the gadget. For use by the class code - * @list - for use by the udc class driver - * - * This represents the internal data structure which is used by the UDC-class - * to hold information about udc driver and gadget together. - */ -struct usb_udc { - struct usb_gadget_driver *driver; - struct usb_gadget *gadget; - struct device dev; - struct list_head list; -}; - -static struct class *udc_class; -static LIST_HEAD(udc_list); -static DEFINE_MUTEX(udc_lock); - -/* ------------------------------------------------------------------------- */ - -int usb_gadget_map_request(struct usb_gadget *gadget, - struct usb_request *req, int is_in) -{ - if (req->length == 0) - return 0; - - if (req->num_sgs) { - int mapped; - - mapped = dma_map_sg(&gadget->dev, req->sg, req->num_sgs, - is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - if (mapped == 0) { - dev_err(&gadget->dev, "failed to map SGs\n"); - return -EFAULT; - } - - req->num_mapped_sgs = mapped; - } else { - req->dma = dma_map_single(&gadget->dev, req->buf, req->length, - is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - - if (dma_mapping_error(&gadget->dev, req->dma)) { - dev_err(&gadget->dev, "failed to map buffer\n"); - return -EFAULT; - } - } - - return 0; -} -EXPORT_SYMBOL_GPL(usb_gadget_map_request); - -void usb_gadget_unmap_request(struct usb_gadget *gadget, - struct usb_request *req, int is_in) -{ - if (req->length == 0) - return; - - if (req->num_mapped_sgs) { - dma_unmap_sg(&gadget->dev, req->sg, req->num_mapped_sgs, - is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - - req->num_mapped_sgs = 0; - } else { - dma_unmap_single(&gadget->dev, req->dma, req->length, - is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - } -} -EXPORT_SYMBOL_GPL(usb_gadget_unmap_request); - -/* ------------------------------------------------------------------------- */ - -/** - * usb_gadget_start - tells usb device controller to start up - * @gadget: The gadget we want to get started - * @driver: The driver we want to bind to @gadget - * @bind: The bind function for @driver - * - * This call is issued by the UDC Class driver when it's about - * to register a gadget driver to the device controller, before - * calling gadget driver's bind() method. - * - * It allows the controller to be powered off until strictly - * necessary to have it powered on. - * - * Returns zero on success, else negative errno. - */ -static inline int usb_gadget_start(struct usb_gadget *gadget, - struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) -{ - return gadget->ops->start(driver, bind); -} - -/** - * usb_gadget_udc_start - tells usb device controller to start up - * @gadget: The gadget we want to get started - * @driver: The driver we want to bind to @gadget - * - * This call is issued by the UDC Class driver when it's about - * to register a gadget driver to the device controller, before - * calling gadget driver's bind() method. - * - * It allows the controller to be powered off until strictly - * necessary to have it powered on. - * - * Returns zero on success, else negative errno. - */ -static inline int usb_gadget_udc_start(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) -{ - return gadget->ops->udc_start(gadget, driver); -} - -/** - * usb_gadget_stop - tells usb device controller we don't need it anymore - * @gadget: The device we want to stop activity - * @driver: The driver to unbind from @gadget - * - * This call is issued by the UDC Class driver after calling - * gadget driver's unbind() method. - * - * The details are implementation specific, but it can go as - * far as powering off UDC completely and disable its data - * line pullups. - */ -static inline void usb_gadget_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) -{ - gadget->ops->stop(driver); -} - -/** - * usb_gadget_udc_stop - tells usb device controller we don't need it anymore - * @gadget: The device we want to stop activity - * @driver: The driver to unbind from @gadget - * - * This call is issued by the UDC Class driver after calling - * gadget driver's unbind() method. - * - * The details are implementation specific, but it can go as - * far as powering off UDC completely and disable its data - * line pullups. - */ -static inline void usb_gadget_udc_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) -{ - gadget->ops->udc_stop(gadget, driver); -} - -/** - * usb_udc_release - release the usb_udc struct - * @dev: the dev member within usb_udc - * - * This is called by driver's core in order to free memory once the last - * reference is released. - */ -static void usb_udc_release(struct device *dev) -{ - struct usb_udc *udc; - - udc = container_of(dev, struct usb_udc, dev); - dev_dbg(dev, "releasing '%s'\n", dev_name(dev)); - kfree(udc); -} - -static const struct attribute_group *usb_udc_attr_groups[]; -/** - * usb_add_gadget_udc - adds a new gadget to the udc class driver list - * @parent: the parent device to this udc. Usually the controller - * driver's device. - * @gadget: the gadget to be added to the list - * - * Returns zero on success, negative errno otherwise. - */ -int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget) -{ - struct usb_udc *udc; - int ret = -ENOMEM; - - udc = kzalloc(sizeof(*udc), GFP_KERNEL); - if (!udc) - goto err1; - - device_initialize(&udc->dev); - udc->dev.release = usb_udc_release; - udc->dev.class = udc_class; - udc->dev.groups = usb_udc_attr_groups; - udc->dev.parent = parent; - ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj)); - if (ret) - goto err2; - - udc->gadget = gadget; - - mutex_lock(&udc_lock); - list_add_tail(&udc->list, &udc_list); - - ret = device_add(&udc->dev); - if (ret) - goto err3; - - mutex_unlock(&udc_lock); - - return 0; -err3: - list_del(&udc->list); - mutex_unlock(&udc_lock); - -err2: - put_device(&udc->dev); - -err1: - return ret; -} -EXPORT_SYMBOL_GPL(usb_add_gadget_udc); - -static int udc_is_newstyle(struct usb_udc *udc) -{ - if (udc->gadget->ops->udc_start && udc->gadget->ops->udc_stop) - return 1; - return 0; -} - - -static void usb_gadget_remove_driver(struct usb_udc *udc) -{ - dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n", - udc->gadget->name); - - kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); - - if (udc_is_newstyle(udc)) { - udc->driver->disconnect(udc->gadget); - usb_gadget_disconnect(udc->gadget); - udc->driver->unbind(udc->gadget); - usb_gadget_udc_stop(udc->gadget, udc->driver); - } else { - usb_gadget_stop(udc->gadget, udc->driver); - } - - udc->driver = NULL; - udc->dev.driver = NULL; -} - -/** - * usb_del_gadget_udc - deletes @udc from udc_list - * @gadget: the gadget to be removed. - * - * This, will call usb_gadget_unregister_driver() if - * the @udc is still busy. - */ -void usb_del_gadget_udc(struct usb_gadget *gadget) -{ - struct usb_udc *udc = NULL; - - mutex_lock(&udc_lock); - list_for_each_entry(udc, &udc_list, list) - if (udc->gadget == gadget) - goto found; - - dev_err(gadget->dev.parent, "gadget not registered.\n"); - mutex_unlock(&udc_lock); - - return; - -found: - dev_vdbg(gadget->dev.parent, "unregistering gadget\n"); - - list_del(&udc->list); - mutex_unlock(&udc_lock); - - if (udc->driver) - usb_gadget_remove_driver(udc); - - kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE); - device_unregister(&udc->dev); -} -EXPORT_SYMBOL_GPL(usb_del_gadget_udc); - -/* ------------------------------------------------------------------------- */ - -int usb_gadget_probe_driver(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) -{ - struct usb_udc *udc = NULL; - int ret; - - if (!driver || !bind || !driver->setup) - return -EINVAL; - - mutex_lock(&udc_lock); - list_for_each_entry(udc, &udc_list, list) { - /* For now we take the first one */ - if (!udc->driver) - goto found; - } - - pr_debug("couldn't find an available UDC\n"); - mutex_unlock(&udc_lock); - return -ENODEV; - -found: - dev_dbg(&udc->dev, "registering UDC driver [%s]\n", - driver->function); - - udc->driver = driver; - udc->dev.driver = &driver->driver; - - if (udc_is_newstyle(udc)) { - ret = bind(udc->gadget); - if (ret) - goto err1; - ret = usb_gadget_udc_start(udc->gadget, driver); - if (ret) { - driver->unbind(udc->gadget); - goto err1; - } - usb_gadget_connect(udc->gadget); - } else { - - ret = usb_gadget_start(udc->gadget, driver, bind); - if (ret) - goto err1; - - } - - kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); - mutex_unlock(&udc_lock); - return 0; - -err1: - dev_err(&udc->dev, "failed to start %s: %d\n", - udc->driver->function, ret); - udc->driver = NULL; - udc->dev.driver = NULL; - mutex_unlock(&udc_lock); - return ret; -} -EXPORT_SYMBOL_GPL(usb_gadget_probe_driver); - -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) -{ - struct usb_udc *udc = NULL; - int ret = -ENODEV; - - if (!driver || !driver->unbind) - return -EINVAL; - - mutex_lock(&udc_lock); - list_for_each_entry(udc, &udc_list, list) - if (udc->driver == driver) { - usb_gadget_remove_driver(udc); - ret = 0; - break; - } - - mutex_unlock(&udc_lock); - return ret; -} -EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver); - -/* ------------------------------------------------------------------------- */ - -static ssize_t usb_udc_srp_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t n) -{ - struct usb_udc *udc = container_of(dev, struct usb_udc, dev); - - if (sysfs_streq(buf, "1")) - usb_gadget_wakeup(udc->gadget); - - return n; -} -static DEVICE_ATTR(srp, S_IWUSR, NULL, usb_udc_srp_store); - -static ssize_t usb_udc_softconn_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t n) -{ - struct usb_udc *udc = container_of(dev, struct usb_udc, dev); - - if (sysfs_streq(buf, "connect")) { - if (udc_is_newstyle(udc)) - usb_gadget_udc_start(udc->gadget, udc->driver); - usb_gadget_connect(udc->gadget); - } else if (sysfs_streq(buf, "disconnect")) { - usb_gadget_disconnect(udc->gadget); - if (udc_is_newstyle(udc)) - usb_gadget_udc_stop(udc->gadget, udc->driver); - } else { - dev_err(dev, "unsupported command '%s'\n", buf); - return -EINVAL; - } - - return n; -} -static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store); - -#define USB_UDC_SPEED_ATTR(name, param) \ -ssize_t usb_udc_##param##_show(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct usb_udc *udc = container_of(dev, struct usb_udc, dev); \ - return snprintf(buf, PAGE_SIZE, "%s\n", \ - usb_speed_string(udc->gadget->param)); \ -} \ -static DEVICE_ATTR(name, S_IRUSR, usb_udc_##param##_show, NULL) - -static USB_UDC_SPEED_ATTR(current_speed, speed); -static USB_UDC_SPEED_ATTR(maximum_speed, max_speed); - -/* TODO: Scheduled for removal in 3.8. */ -static ssize_t usb_udc_is_dualspeed_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct usb_udc *udc = container_of(dev, struct usb_udc, dev); - return snprintf(buf, PAGE_SIZE, "%d\n", - gadget_is_dualspeed(udc->gadget)); -} -static DEVICE_ATTR(is_dualspeed, S_IRUSR, usb_udc_is_dualspeed_show, NULL); - -#define USB_UDC_ATTR(name) \ -ssize_t usb_udc_##name##_show(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct usb_udc *udc = container_of(dev, struct usb_udc, dev); \ - struct usb_gadget *gadget = udc->gadget; \ - \ - return snprintf(buf, PAGE_SIZE, "%d\n", gadget->name); \ -} \ -static DEVICE_ATTR(name, S_IRUGO, usb_udc_##name##_show, NULL) - -static USB_UDC_ATTR(is_otg); -static USB_UDC_ATTR(is_a_peripheral); -static USB_UDC_ATTR(b_hnp_enable); -static USB_UDC_ATTR(a_hnp_support); -static USB_UDC_ATTR(a_alt_hnp_support); - -static struct attribute *usb_udc_attrs[] = { - &dev_attr_srp.attr, - &dev_attr_soft_connect.attr, - &dev_attr_current_speed.attr, - &dev_attr_maximum_speed.attr, - - &dev_attr_is_dualspeed.attr, - &dev_attr_is_otg.attr, - &dev_attr_is_a_peripheral.attr, - &dev_attr_b_hnp_enable.attr, - &dev_attr_a_hnp_support.attr, - &dev_attr_a_alt_hnp_support.attr, - NULL, -}; - -static const struct attribute_group usb_udc_attr_group = { - .attrs = usb_udc_attrs, -}; - -static const struct attribute_group *usb_udc_attr_groups[] = { - &usb_udc_attr_group, - NULL, -}; - -static int usb_udc_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - struct usb_udc *udc = container_of(dev, struct usb_udc, dev); - int ret; - - ret = add_uevent_var(env, "USB_UDC_NAME=%s", udc->gadget->name); - if (ret) { - dev_err(dev, "failed to add uevent USB_UDC_NAME\n"); - return ret; - } - - if (udc->driver) { - ret = add_uevent_var(env, "USB_UDC_DRIVER=%s", - udc->driver->function); - if (ret) { - dev_err(dev, "failed to add uevent USB_UDC_DRIVER\n"); - return ret; - } - } - - return 0; -} - -static int __init usb_udc_init(void) -{ - udc_class = class_create(THIS_MODULE, "udc"); - if (IS_ERR(udc_class)) { - pr_err("failed to create udc class --> %ld\n", - PTR_ERR(udc_class)); - return PTR_ERR(udc_class); - } - - udc_class->dev_uevent = usb_udc_uevent; - return 0; -} -subsys_initcall(usb_udc_init); - -static void __exit usb_udc_exit(void) -{ - class_destroy(udc_class); -} -module_exit(usb_udc_exit); - -MODULE_DESCRIPTION("UDC Framework"); -MODULE_AUTHOR("Felipe Balbi "); -MODULE_LICENSE("GPL v2"); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.c b/ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.c deleted file mode 100755 index c239e3d8..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.c +++ /dev/null @@ -1,4699 +0,0 @@ -/* - * wmt_udc.c -- for WonderMedia Technology udc - * - * Copyright (C) 2007 VIA Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#undef DEBUG -#undef VERBOSE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -#include -#include -#include -#include -#include -#include -#include - -#include "udc_wmt.h" - -#define USE_BULK3_TO_INTERRUPT //gri - -//#define FULL_SPEED_ONLY -/*#define HW_BUG_HIGH_SPEED_PHY*/ -#undef USB_TRACE - -/* bulk DMA seems to be behaving for both IN and OUT */ -#define USE_DMA - -/*#define DEBUG_UDC_ISR_TIMER*/ -#undef DEBUG_UDC_ISR_TIMER - -/*#define RNDIS_INFO_DEBUG_BULK_OUT*/ -#undef RNDIS_INFO_DEBUG_BULK_OUT - -/*#define RNDIS_INFO_DEBUG_BULK_IN*/ -#undef RNDIS_INFO_DEBUG_BULK_IN - -/*#define MSC_COMPLIANCE_TEST*/ -#undef MSC_COMPLIANCE_TEST - -/*#define UDC_A1_SELF_POWER_ENABLE*/ - -/*-----------------------------------------------------------------------------*/ - -#define DRIVER_DESC "VIA UDC driver" -#define DRIVER_VERSION "3 December 2007" - -#define DMA_ADDR_INVALID (~(dma_addr_t)0) - -static unsigned fifo_mode; - -static unsigned fiq_using = 0; - -/* "modprobe vt8500_udc fifo_mode=42", or else as a kernel - * boot parameter "vt8500_udc:fifo_mode=42" - */ - -module_param(fifo_mode, uint, 0); -MODULE_PARM_DESC(fifo_mode, "endpoint setup (0 == default)"); - -static bool use_dma = 1; - -module_param(use_dma, bool, 0); -MODULE_PARM_DESC(use_dma, "enable/disable DMA"); - -static const char driver_name[] = "wmotgdev";/*"wmt_udc";*/ -static const char driver_desc[] = DRIVER_DESC; - -static DEFINE_SEMAPHORE(wmt_udc_sem); -static int f_ep3_used = 0; - -static struct vt8500_udc *udc; -static struct device *pDMADescLI, *pDMADescSI; -static struct device *pDMADescLO, *pDMADescSO; - -static struct device *pDMADescL2I, *pDMADescS2I; - -dma_addr_t UdcPdmaPhyAddrLI, UdcPdmaPhyAddrSI; -static UINT UdcPdmaVirAddrLI, UdcPdmaVirAddrSI; -dma_addr_t UdcPdmaPhyAddrLO, UdcPdmaPhyAddrSO; -static UINT UdcPdmaVirAddrLO, UdcPdmaVirAddrSO; - -dma_addr_t UdcPdmaPhyAddrL2I, UdcPdmaPhyAddrS2I; -static UINT UdcPdmaVirAddrL2I, UdcPdmaVirAddrS2I; - -dma_addr_t UdcRndisEp1PhyAddr, UdcRndisEp2PhyAddr, UdcRndisEp3PhyAddr; -static UINT UdcRndisEp1VirAddr, UdcRndisEp2VirAddr, UdcRndisEp3VirAddr; - -#ifdef OTGIP -static struct USB_GLOBAL_REG *pGlobalReg; -#endif -/*static struct UDC_REGISTER *udc_reg;*/ - -static volatile struct UDC_REGISTER *pDevReg; -static volatile struct UDC_DMA_REG *pUdcDmaReg; - -PSETUPCOMMAND pSetupCommand; -UCHAR *pSetupCommandBuf; -UCHAR *SetupBuf; -UCHAR *IntBuf; - -UCHAR ControlState; /* the state the control pipe*/ -UCHAR USBState; -UCHAR TestMode; - -/* Basic Define*/ -//#define REG32 *(volatile unsigned int *) -//#define REG_GET32(addr) (REG32(addr)) /* Read 32 bits Register */ - -static unsigned long irq_flags;//gri - -volatile unsigned char *pUSBMiscControlRegister5; - -unsigned int interrupt_transfer_size; - -static void wmt_pdma_reset(void); -static void wmt_pdma0_reset(void); -static void wmt_pdma1_reset(void); - -#ifdef USE_BULK3_TO_INTERRUPT -static void wmt_pdma2_reset(void); -#endif - -/* 1 : storage */ -static unsigned int gadget_connect=0; -//static unsigned int first_mount=0; - - -struct work_struct online_thread; -struct work_struct offline_thread; -struct work_struct done_thread; -struct work_struct chkiso_thread; - - - -struct list_head done_main_list; -spinlock_t gri_lock; -static unsigned long gri_flags;//gri - -static unsigned int b_pullup=0; - -void run_chkiso (struct work_struct *work); - -static inline unsigned int wmt_ost_counter(void) -{ - OSTC_VAL |= OSTC_RDREQ; - while (OSTA_VAL & OSTA_RCA) - ; - - return (u32)OSCR_VAL; -} - -static inline void wmt_ost2_set_match(u32 new_match) -{ - /* check if can write OS Timer2 match register nows */ - while (OSTA_VAL & OSTA_MWA2) - ; - - OSM2_VAL = new_match; -} - -void wmt_enable_fiq(unsigned int how_many_us) -{ - unsigned int cnt = 0; - - cnt = wmt_ost_counter(); - cnt += (3*how_many_us); - wmt_ost2_set_match(cnt); - OSTI_VAL |= OSTI_E2; -} - -void wmt_disable_fiq(void) -{ - OSTI_VAL &= ~OSTI_E2; -} - -static irqreturn_t -test_fiq_handler(int irq, void *_udc)//, struct pt_regs *r) -{ - OSTS_VAL = OSTI_E2; - - //printk("i am test_fiq_handler\n"); - - run_chkiso(NULL); - return IRQ_HANDLED; -} - -void initial_test_fiq(void) -{ - //int ret = -1; - int status = -ENODEV; - - printk("\n\n\ninitial_test_fiq\n\n"); - // set fiq - - OSTS_VAL = OSTI_E2; - OSTI_VAL &= ~OSTI_E2; -#if 0 - fhandler.fiq = test_fiq_handler; - fhandler.resume = test_fiq_resume; - ret = fiq_wmt_register_handler(&fhandler); - if (ret) { - pr_err("%s: could not install fiq handler ( %d )\n", __func__, ret); - return; - } - - //use OST2 to test - - enable_fiq(70); -#else - status = request_irq(IRQ_OST2, test_fiq_handler, -// (SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM), driver_name, udc); -// (IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM), driver_name, udc); - (IRQF_DISABLED), driver_name, udc);//gri - if (status != 0) { - ERR("**** can't get irq %d, err %d\n", - IRQ_OST2, status); - } else - INFO("**** wmt_udc_probe - request_irq(0x%02X) pass!\n", IRQ_OST2); -#endif -} - -/** - * - * Run these two functions to execute shell script to mount / umount storage - * - */ -#if 0 -static int run_online(void) -{ - kobject_uevent(&udc->dev->kobj, 2); - return 0; -} -#endif -void wmt_cleanup_done_thread(int number); -static void run_offline (struct work_struct *work) -{ - if ((udc->driver) && b_pullup){ -// printk(KERN_INFO "disconnect\n"); //gri - udc->driver->disconnect(&udc->gadget); - } -// return 0; -} - -static void run_done (struct work_struct *work) -{ - struct vt8500_req * req; - - spin_lock_irqsave(&gri_lock, gri_flags); -// printk(KERN_INFO "d1\n"); //gri - while (!list_empty(&done_main_list)){ -// printk(KERN_INFO "d3\n"); //gri - req = list_entry(done_main_list.next, struct vt8500_req, mem_list); - list_del_init(&req->mem_list); - spin_unlock_irqrestore(&gri_lock, gri_flags); - req->req.complete(&req->ep->ep, &req->req); - spin_lock_irqsave(&gri_lock, gri_flags); - } -// printk(KERN_INFO "d2\n"); //gri - spin_unlock_irqrestore(&gri_lock, gri_flags); -// return 0; -} - -void dma_irq(u8 addr); -void next_in_dma(struct vt8500_ep *ep, struct vt8500_req *req); -void iso_prepare_0byte(void); -void run_chkiso (struct work_struct *work) -{ - spin_lock_irqsave(&udc->lock, irq_flags); - if (!fiq_using) { - //printk("iso fail\n"); - spin_unlock_irqrestore(&udc->lock, irq_flags); - return; - } - - //do { - //schedule(); - if (pDevReg->Bulk3DesStatus & BULKXFER_XACTERR) { - { - struct vt8500_ep *ep; - struct vt8500_req *req; - /*u32 temp32;*/ - /*u32 i;*/ - - ep = &udc->ep[4]; - if (!list_empty(&ep->queue)) { - req = container_of(ep->queue.next, struct vt8500_req, queue); - //printk("iso h q\n"); - next_in_dma(ep, req); - } else { - //printk("no q\n"); - wmt_disable_fiq(); - fiq_using = 0; - wmt_pdma2_reset(); - iso_prepare_0byte(); - } - } - //printk("iso hit\n"); - //break; - } else { - wmt_enable_fiq(300); - //printk("iso hit miss\n"); - } - //} while (1); - spin_unlock_irqrestore(&udc->lock, irq_flags); -} - -enum schedule_work_action -{ - action_done, action_off_line, action_chkiso -}; - -static void run_script(enum schedule_work_action dwAction) -{ - - if (dwAction == action_done){//8 - schedule_work(&done_thread); - }else if (dwAction == action_off_line){//7 - schedule_work(&offline_thread); - }else if (dwAction == action_chkiso){//7 - schedule_work(&chkiso_thread); - }else { - } - -} - - -void udc_device_dump_register(void) -{ - volatile unsigned int address; - volatile unsigned char temp8; - int i; - - for (i = 0x20; i <= 0x3F; i++) { /*0x20~0x3F (0x3F-0x20 + 1) /4 = 8 DWORD*/ - address = (USB_UDC_REG_BASE + i); - temp8 = REG_GET8(address); - - INFO("[UDC Device] Offset[0x%8.8X] = 0x%2.2X \n", address, temp8); - } - - for (i = 0x308; i <= 0x30D; i++) { /*0x308~0x30D*/ - address = (USB_UDC_REG_BASE + i); - temp8 = REG_GET8(address); - - INFO("[UDC Device] Offset[0x%8.8X] = 0x%2.2X \n", address, temp8); - } - - for (i = 0x310; i <= 0x317; i++) { /*0x310~0x317*/ - address = (USB_UDC_REG_BASE + i); - temp8 = REG_GET8(address); - - INFO("[UDC Device] Offset[0x%8.8X] = 0x%2.2X \n", address, temp8); - } - - INFO("[UDC Device] Dump Reigster PASS!\n"); - -} /*void udc_device_dump_register(void)*/ - -void udc_bulk_dma_dump_register(void) -{ - volatile unsigned int temp32; - int i; - - for (i = 0; i <= 0x10; i++) { /*0x100 ~ 0x113 (0x113 - 0x100 + 1) = 0x14 /4 = 5*/ - temp32 = REG_GET32(USB_UDC_DMA_REG_BASE + i*4); - INFO("[UDC Bulk DMA] Offset[0x%8.8X] = 0x%8.8X \n", (USB_UDC_DMA_REG_BASE + i*4), temp32); - } - INFO("[UDC Bulk DMAD] Dump Reigster PASS!\n"); - -} /*void udc_bulk_dma_dump_register(void)*/ - -void wmt_ep_setup_csr(char *name, u8 addr, u8 type, unsigned maxp) -{ - struct vt8500_ep *ep; - /*u32 epn_rxtx = 0;*/ - /*U8 temp_adr;*/ - - VDBG("wmt_ep_setup_csr()\n"); - - /* OUT endpoints first, then IN*/ - - ep = &udc->ep[addr & 0x7f]; - - VDBG("wmt_ep_setup()\n"); - - /* OUT endpoints first, then IN*/ - ep = &udc->ep[addr & 0x7f]; - - if (type == USB_ENDPOINT_XFER_CONTROL) { - /*pDevReg->ControlEpControl;*/ - pDevReg->ControlEpReserved = 0; - pDevReg->ControlEpMaxLen = (maxp & 0xFF); - pDevReg->ControlEpEpNum = 0; - } else if (type == USB_ENDPOINT_XFER_BULK) { - if (addr & USB_DIR_IN) { - /*pDevReg->Bulk1EpControl;*/ - pDevReg->Bulk1EpOutEpNum = (addr & 0x7f) << 4; - pDevReg->Bulk1EpMaxLen = (maxp & 0xFF); - pDevReg->Bulk1EpInEpNum = (((addr & 0x7f) << 4) | ((maxp & 0x700) >> 8)); - } else { - /*pDevReg->Bulk2EpControl;*/ - pDevReg->Bulk2EpOutEpNum = (addr & 0x7f) << 4; - pDevReg->Bulk2EpMaxLen = (maxp & 0xFF); - pDevReg->Bulk2EpInEpNum = (((addr & 0x7f) << 4) | ((maxp & 0x700) >> 8)); - } - } else if (type == USB_ENDPOINT_XFER_INT) { -#ifdef USE_BULK3_TO_INTERRUPT - pDevReg->Bulk3EpOutEpNum = (addr & 0x7f) << 4; - pDevReg->Bulk3EpMaxLen = (maxp & 0xFF); - pDevReg->Bulk3EpInEpNum = (((addr & 0x7f) << 4) | ((maxp & 0x700) >> 8)); - - pDevReg->InterruptReserved = (0x85 & 0x7f) << 4; - pDevReg->InterruptEpMaxLen = (8 & 0xFF); /* Interrupt maximum transfer length - 2E*/ - pDevReg->InterruptEpEpNum = (((0x85 & 0x7f) << 4) | ((8 & 0x700) >> 8)); -#else - /*pDevReg->InterruptEpControl; // Interrupt endpoint control - 2C*/ - /* Interrupt endpoint reserved byte - 2D*/ - pDevReg->InterruptReserved = (addr & 0x7f) << 4; - pDevReg->InterruptEpMaxLen = (maxp & 0xFF); /* Interrupt maximum transfer length - 2E*/ - pDevReg->InterruptEpEpNum = (((addr & 0x7f) << 4) | ((maxp & 0x700) >> 8)); -#endif - } else if (type == USB_ENDPOINT_XFER_ISOC) { - pDevReg->Bulk3EpOutEpNum = (addr & 0x7f) << 4; - pDevReg->Bulk3EpMaxLen = (maxp & 0xFF); - pDevReg->Bulk3EpInEpNum = (((addr & 0x7f) << 4) | ((maxp & 0x700) >> 8)); - } - - /*Setting address pointer ...*/ - wmb(); - VDBG("wmt_ep_setup_csr() - %s addr %02x maxp %d\n", - name, addr, maxp); - - ep->toggle_bit = 0; - ep->ep.maxpacket = maxp; -} /*tatic void wmt_ep_setup_csr()*/ - -static int wmt_ep_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct vt8500_ep *ep = container_of(_ep, struct vt8500_ep, ep); - struct vt8500_udc *udc; - - u16 maxp; - - DBG("wmt_ep_enable() %s\n", ep ? ep->ep.name : NULL); - printk(KERN_INFO "gri wmt_ep_enable() %s\n", ep ? ep->ep.name : NULL); - - /* catch various bogus parameters*/ - if (!_ep || !desc || (ep->desc && ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC)) - || desc->bDescriptorType != USB_DT_ENDPOINT - || ep->bEndpointAddress != desc->bEndpointAddress - || ep->maxpacket < usb_endpoint_maxp(desc)) { - VDBG("ep->bEndpointAddress = 0x%08X\n", ep->bEndpointAddress); - VDBG("desc->bEndpointAddres = 0x%08X\n", desc->bEndpointAddress); - VDBG("ep->maxpacket =0x%08X\n", ep->maxpacket); - VDBG("desc->wMaxPacketSize =0x%08X\n", desc->wMaxPacketSize); - VDBG("_ep =0x%08X\n", (unsigned int)_ep); - VDBG("desc =0x%08X\n", (unsigned int)desc); - VDBG("ep->desc =0x%08X\n", (unsigned int)ep->desc); - - /*DBG("%s, bad ep or descriptor\n", __FUNCTION__);*/ - return -EINVAL; - } - - maxp = usb_endpoint_maxp(desc); - - if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK) - && (usb_endpoint_maxp(desc) > ep->maxpacket - || !desc->wMaxPacketSize)) { - DBG("[wmt_ep_enable]bad %s maxpacket\n", _ep->name); - return -ERANGE; - } - -#if 1 - if ((desc->bmAttributes == USB_ENDPOINT_XFER_ISOC - && desc->bInterval != 1)) { - /* hardware wants period = 1; USB allows 2^(Interval-1) */ - DBG("%s, unsupported ISO period %dms\n", _ep->name, - 1 << (desc->bInterval - 1)); - return -EDOM; - } - -#if 0 - /* xfer types must match, except that interrupt ~= bulk*/ - if (ep->bmAttributes != desc->bmAttributes - && ep->bmAttributes != USB_ENDPOINT_XFER_BULK - && desc->bmAttributes != USB_ENDPOINT_XFER_INT) { - DBG("[wmt_ep_enable], %s type mismatch\n", _ep->name); - printk("[wmt_ep_enable], %s type mismatch\n", _ep->name); - return -EINVAL; - } -#endif -#endif - - udc = ep->udc; - - spin_lock_irqsave(&udc->lock, irq_flags); - - ep->desc = desc; - ep->irqs = 0; - ep->stopped = 0; - ep->ep.maxpacket = maxp; - - ep->has_dma = 1; - ep->ackwait = 0; - - switch ((ep->bEndpointAddress & 0x7F)) { - case 0:/*Control In/Out*/ - wmt_ep_setup_csr("ep0", 0, USB_ENDPOINT_XFER_CONTROL, 64); - wmb(); - pDevReg->ControlEpControl = EP_RUN + EP_ENABLEDMA; - break; - - case 1:/*Bulk In*/ - wmt_ep_setup_csr("ep1in-bulk", (USB_DIR_IN | 1), USB_ENDPOINT_XFER_BULK, maxp); - wmb(); - pDevReg->Bulk1EpControl = EP_RUN + EP_ENABLEDMA; - break; - - case 2:/*Bulk Out*/ - wmt_ep_setup_csr("ep2out-bulk", (USB_DIR_OUT | 2), USB_ENDPOINT_XFER_BULK, maxp); - wmb(); - pDevReg->Bulk2EpControl = EP_RUN + EP_ENABLEDMA; - break; - - case 3:/*Interrupt In*/ -#ifdef USE_BULK3_TO_INTERRUPT - if (f_ep3_used == 4) - return -ERANGE; - f_ep3_used = 3; - wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, maxp); - wmb(); - pDevReg->Bulk3EpControl = EP_RUN + EP_ENABLEDMA; -#else - wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, maxp); - wmb(); - pDevReg->InterruptEpControl = EP_RUN + EP_ENABLEDMA; -#endif - break; - - case 4:/*iso in*/ - if (f_ep3_used == 3) - return -ERANGE; - f_ep3_used = 4; - wmt_ep_setup_csr("ep4in-iso", (USB_DIR_IN | 4), USB_ENDPOINT_XFER_ISOC, 384); - wmb(); - - wmt_pdma2_reset(); - iso_prepare_0byte(); - - pDevReg->Bulk3EpControl = EP_RUN + EP_ENABLEDMA; - break; - - } - wmb(); - spin_unlock_irqrestore(&udc->lock, irq_flags); - VDBG("%s enabled\n", _ep->name); -// printk(KERN_INFO "gri enabled %s\n", ep ? ep->ep.name : NULL); - - return 0; -} /*static int wmt_ep_enable()*/ - -static void nuke(struct vt8500_ep *, int status); - -static int wmt_ep_disable(struct usb_ep *_ep) -{ - struct vt8500_ep *ep = container_of(_ep, struct vt8500_ep, ep); -// unsigned long flags; - - DBG("wmt_ep_disable() %s\n", ep ? ep->ep.name : NULL); - - if (!_ep || !ep->desc) { - DBG("[wmt_ep_disable], %s not enabled\n", - _ep ? ep->ep.name : NULL); - return -EINVAL; - } - - spin_lock_irqsave(&ep->udc->lock, irq_flags); - ep->desc = 0; - nuke(ep, -ESHUTDOWN); - ep->ep.maxpacket = ep->maxpacket; - ep->has_dma = 0; - - del_timer(&ep->timer); - - switch ((ep->bEndpointAddress & 0x7F)) { - case 0:/*Control In/Out*/ - pDevReg->ControlEpControl &= 0xFC; - break; - - case 1:/*Bulk In*/ - pDevReg->Bulk1EpControl &= 0xFC; - break; - - case 2:/*Bulk Out*/ - pDevReg->Bulk2EpControl &= 0xFC; - break; - - case 3:/*Interrupt In*/ -#ifdef USE_BULK3_TO_INTERRUPT - if (f_ep3_used == 3) - f_ep3_used = 0; - pDevReg->Bulk3EpControl &= 0xFC; -#else - pDevReg->InterruptEpControl &= 0xFC; -#endif - break; - - case 4:/*Iso In*/ - if (f_ep3_used == 4) - f_ep3_used = 0; - pDevReg->Bulk3EpControl &= 0xFC; - fiq_using = 0; - break; - } - wmb(); - spin_unlock_irqrestore(&ep->udc->lock, irq_flags); - - VDBG("%s disabled\n", _ep->name); - return 0; -} /*static int wmt_ep_disable()*/ - - -static struct usb_request * -wmt_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) -{ - struct vt8500_req *req; - struct vt8500_ep *ep = NULL; - -// DBG("gri wmt_alloc_request() %s\n", ep->name); - - ep = container_of(_ep, struct vt8500_ep, ep); -// printk(KERN_INFO "gri wmt_alloc_request() %s\n", ep->name); -// if ((ep->bEndpointAddress & 0x7F) > 4) -// return NULL; - - - /*if(ep->bEndpointAddress == 3)*/ - /* INFO("wmt_alloc_request() %s\n", ep->name);*/ - - req = kmalloc(sizeof *req, gfp_flags); - if (req) { - memset(req, 0, sizeof *req); - req->req.dma = DMA_ADDR_INVALID; - INIT_LIST_HEAD(&req->queue); - } - return &req->req;/*struct usb_request for file_storage.o*/ -} /*wmt_alloc_request()*/ - -static void -wmt_free_request(struct usb_ep *_ep, struct usb_request *_req) -{ - struct vt8500_req *req = container_of(_req, struct vt8500_req, req); - struct vt8500_ep *ep = NULL; - - DBG("wmt_free_request() %s\n", ep->name); - ep = container_of(_ep, struct vt8500_ep, ep); - - /*if(ep->bEndpointAddress == 3)*/ - /* INFO("wmt_free_request() %s\n", ep->name);*/ - - if (_req) - kfree(req); -} /*wmt_free_request()*/ - -/*EP0 - Control 256 bytes*/ -/*EP2,3 Bulk In/Out 16384 bytes (16K)*/ -/*file_storeage.c - req->buf*/ -/*struct usb_request req;*/ -static void wmt_pdma_init(struct device *dev); - - -static void ep0_status(struct vt8500_udc *udc) -{ - struct vt8500_ep *ep; - - ep = &udc->ep[0]; - - if (udc->ep0_in) { /*OUT STATUS*/ - if (udc->ep0_status_0_byte == 1) { - udc->ep0_status_0_byte = 0; - - /* the data phase is OUT*/ - - if (ep->toggle_bit) - pDevReg->ControlDesTbytes = 0x40|CTRLXFER_DATA1; - else - pDevReg->ControlDesTbytes = 0x40|CTRLXFER_DATA0; - - pDevReg->ControlDesControl = CTRLXFER_OUT+CTRLXFER_IOC; - wmb(); - pDevReg->ControlDesStatus = CTRLXFER_ACTIVE; - ControlState = CONTROLSTATE_STATUS; - } /*if(udc->ep0_status_0_byte == 1)*/ - } else { /*IN STATUS*/ - if (udc->ep0_status_0_byte == 1) { - udc->ep0_status_0_byte = 0; - - if (ep->toggle_bit) - pDevReg->ControlDesTbytes = 0x00 | CTRLXFER_DATA1; - else - pDevReg->ControlDesTbytes = 0x00 | CTRLXFER_DATA0; - - pDevReg->ControlDesTbytes = 0x00 | CTRLXFER_DATA1; /* zero length*/ - pDevReg->ControlDesControl = CTRLXFER_IN + CTRLXFER_IOC; - wmb(); - pDevReg->ControlDesStatus = CTRLXFER_ACTIVE; - ControlState = CONTROLSTATE_STATUS; - } /*if(udc->ep0_status_0_byte == 1)*/ - } - -} /*static void ep0_status(struct vt8500_udc *udc)*/ - - -static void -done(struct vt8500_ep *ep, struct vt8500_req *req, int status) -{ - unsigned stopped = ep->stopped; - - DBG("done() %s\n", ep ? ep->ep.name : NULL); - - list_del_init(&req->queue); - - /*#define EINPROGRESS 115*/ /* Operation now in progress */ - if (req->req.status == -EINPROGRESS) - req->req.status = status; - else { - if (status != 0) - status = req->req.status; - } - - DBG("complete %s req %p stat %d len %u/%u\n", - ep->ep.name, &req->req, status, - req->req.actual, req->req.length); - - /* don't modify queue heads during completion callback*/ - ep->stopped = 1; - - spin_unlock_irqrestore(&ep->udc->lock, irq_flags); - req->req.complete(&ep->ep, &req->req); - spin_lock_irqsave(&ep->udc->lock, irq_flags); - - if ((ep->bEndpointAddress & 0x7F) == 0)/*Control*/ - { - if (req->req.actual != 0) { - ep->udc->ep0_status_0_byte = 1; - } - } -#if 0 - else - printk("**done() %s\n", ep ? ep->ep.name : NULL); -#endif - - ep->stopped = stopped; - -} /*done(struct vt8500_ep *ep, struct vt8500_req *req, int status)*/ - -static u32 dma_src_len(struct vt8500_ep *ep, struct vt8500_req *req) -{ - /*dma_addr_t end;*/ - /*U32 ep_trans_len;*/ - unsigned start = 0 , end = 0; - u32 temp32 = 0; - - start = req->req.length; - - if ((ep->bEndpointAddress & 0x7F) == 0) {/*Control In*/ - end = (pDevReg->ControlDesTbytes & 0x7F); - temp32 = (ep->ep_fifo_length - end); - return temp32; - } else if ((ep->bEndpointAddress & 0x7F) == 1) {/*Bulk In*/ - end = (pDevReg->Bulk1DesTbytes2 & 0x03) << 16; - end |= pDevReg->Bulk1DesTbytes1 << 8; - end |= pDevReg->Bulk1DesTbytes0; - } else if ((ep->bEndpointAddress & 0x7F) == 3)/*Interrupt In*/ - { -#ifdef USE_BULK3_TO_INTERRUPT - end = (pDevReg->Bulk3DesTbytes2 & 0x03) << 16; - end |= pDevReg->Bulk3DesTbytes1 << 8; - end |= pDevReg->Bulk3DesTbytes0; -#else - start = req->dma_bytes; - end = (pDevReg->InterruptDes >> 4); -#endif - } else if ((ep->bEndpointAddress & 0x7F) == 4)/*Iso In*/ - { - end = 0; - } - - temp32 = (start - end); - return temp32; -} /*static u32 dma_src_len()*/ - -static u32 dma_dest_len(struct vt8500_ep *ep, struct vt8500_req *req) -{ - /*dma_addr_t end;*/ - unsigned start = 0 , end = 0; - u32 temp32 = 0; - - start = req->req.length; - - if ((ep->bEndpointAddress & 0x7F) == 0) {/*Control Out*/ - end = (pDevReg->ControlDesTbytes & 0x7F); - temp32 = (ep->ep_fifo_length - end); - return temp32; - } else if (ep->bEndpointAddress == 2) {/*Bulk Out*/ - end = (pDevReg->Bulk2DesTbytes2 & 0x03) << 16; - end |= pDevReg->Bulk2DesTbytes1 << 8; - end |= pDevReg->Bulk2DesTbytes0; - } - - temp32 = (start - end); - return temp32; -} /*static u32 dma_dest_len()*/ - -/* Each USB transfer request using DMA maps to one or more DMA transfers. - * When DMA completion isn't request completion, the UDC continues with - * the next DMA transfer for that USB transfer. - */ - -static void wmt_udc_pdma_des_prepare(unsigned int size, unsigned int dma_phy - , unsigned char des_type, unsigned char channel, int is_bulk) -{ - unsigned int res_size = size; - volatile unsigned int trans_dma_phy = dma_phy, des_phy_addr = 0, des_vir_addr = 0; - unsigned int cut_size = 0x40; - - switch (des_type) { - case DESCRIPTOT_TYPE_SHORT: - { - struct _UDC_PDMA_DESC_S *pDMADescS; - - if (channel == TRANS_OUT) { - des_phy_addr = (unsigned int) UdcPdmaPhyAddrSO; - des_vir_addr = UdcPdmaVirAddrSO; - pUdcDmaReg->DMA_Descriptor_Point1 = (unsigned int)(des_phy_addr); - cut_size = pDevReg->Bulk2EpMaxLen & 0x3ff; - } else if (channel == TRANS_IN) { - if (is_bulk) { - des_phy_addr = (unsigned int) UdcPdmaPhyAddrSI; - des_vir_addr = UdcPdmaVirAddrSI; - pUdcDmaReg->DMA_Descriptor_Point0 = (unsigned int)(des_phy_addr); - cut_size = pDevReg->Bulk1EpMaxLen & 0x3ff; - } - else { - des_phy_addr = (unsigned int) UdcPdmaPhyAddrS2I; - des_vir_addr = UdcPdmaVirAddrS2I; - pUdcDmaReg->DMA_Descriptor_Point2 = (unsigned int)(des_phy_addr); - cut_size = pDevReg->Bulk3EpMaxLen & 0x3ff; - } - } else - DBG("!! wrong channel %d\n", channel); - - while (res_size) { - pDMADescS = (struct _UDC_PDMA_DESC_S *) des_vir_addr; - - pDMADescS->Data_Addr = trans_dma_phy; - pDMADescS->D_Word0_Bits.Format = 0; - -// if (res_size <= 65535) { - if (res_size <= 32767) { - pDMADescS->D_Word0_Bits.i = 1; - pDMADescS->D_Word0_Bits.End = 1; - pDMADescS->D_Word0_Bits.ReqCount = res_size; - - res_size -= res_size; - } else { - pDMADescS->D_Word0_Bits.i = 0; - pDMADescS->D_Word0_Bits.End = 0; - pDMADescS->D_Word0_Bits.ReqCount = 0x8000 - cut_size; - - res_size -= 0x8000; - des_vir_addr += (unsigned int)DES_S_SIZE; - trans_dma_phy += (unsigned int)0x8000; - } - } - break; - } - - case DESCRIPTOT_TYPE_LONG: - { - struct _UDC_PDMA_DESC_L *pDMADescL; - - if (channel == TRANS_OUT) { - des_phy_addr = (unsigned int) UdcPdmaPhyAddrLO; - des_vir_addr = UdcPdmaVirAddrLO; - pUdcDmaReg->DMA_Descriptor_Point1 = (unsigned int)(des_phy_addr); - cut_size = pDevReg->Bulk2EpMaxLen & 0x3ff; - -// printk(KERN_INFO "wmt_udc_pdma_des_prepare() pUdcDmaReg->DMA_Descriptor_Point=0x%08X", -// pUdcDmaReg->DMA_Descriptor_Point1); //gri - -// printk(KERN_INFO "des_vir_addr=0x%08X", -// des_vir_addr); //gri - - } else if (channel == TRANS_IN) { - if (is_bulk){ - des_phy_addr = (unsigned int) UdcPdmaPhyAddrLI; - des_vir_addr = UdcPdmaVirAddrLI; - pUdcDmaReg->DMA_Descriptor_Point0 = (unsigned int)(des_phy_addr); - cut_size = pDevReg->Bulk1EpMaxLen & 0x3ff; - - // printk(KERN_INFO "wmt_udc_pdma_des_prepare() pUdcDmaReg->DMA_Descriptor_Point=0x%08X", - // pUdcDmaReg->DMA_Descriptor_Point0); //gri - -// printk(KERN_INFO "des_vir_addr=0x%08X", -// des_vir_addr); //gri - } - else { - des_phy_addr = (unsigned int) UdcPdmaPhyAddrL2I; - des_vir_addr = UdcPdmaVirAddrL2I; - pUdcDmaReg->DMA_Descriptor_Point2 = (unsigned int)(des_phy_addr); - cut_size = pDevReg->Bulk3EpMaxLen & 0x3ff; - -// printk(KERN_INFO "wmt_udc_pdma_des_prepare() pUdcDmaReg->DMA_Descriptor_Point2=0x%08X", -// pUdcDmaReg->DMA_Descriptor_Point2); //gri - -// printk(KERN_INFO "des_vir_addr 2 =0x%08X", -// des_vir_addr); //gri - } - - } else - DBG("!! wrong channel %d\n", channel); - - memset((void *)des_vir_addr, 0, 0x100); - - while (res_size) { - pDMADescL = (struct _UDC_PDMA_DESC_L *) des_vir_addr; - - pDMADescL->Data_Addr = trans_dma_phy; - pDMADescL->D_Word0_Bits.Format = 1; - -// if (res_size <= 65535) { - if (res_size <= 32767) { - pDMADescL->D_Word0_Bits.i = 1; - pDMADescL->D_Word0_Bits.End = 1; - pDMADescL->Branch_addr = 0; - pDMADescL->D_Word0_Bits.ReqCount = res_size; - - res_size -= res_size; - } else { - pDMADescL->D_Word0_Bits.i = 0; - pDMADescL->D_Word0_Bits.End = 0; - pDMADescL->Branch_addr = des_vir_addr + (unsigned int)DES_L_SIZE; - pDMADescL->D_Word0_Bits.ReqCount = 0x8000 - cut_size; - - res_size -= 0x8000; - des_vir_addr += (unsigned int)DES_L_SIZE; - trans_dma_phy += (unsigned int)0x8000; - } - } - -#if 0 - if (channel == TRANS_IN) { - if (!is_bulk) { - printk(KERN_INFO "pDMADescL(0x%08X)\n", - des_vir_addr); //gri - printk(KERN_INFO "D_Word0(0x%08X)\n", pDMADescL->D_Word0); //gri - printk(KERN_INFO "Data_Addr(0x%08X)\n", pDMADescL->Data_Addr); //gri - printk(KERN_INFO "Branch_addr(0x%08X)\n", pDMADescL->Branch_addr); //gri - } - else { - printk(KERN_INFO "pDMADescL(0x%08X)\n", - des_vir_addr); //gri - printk(KERN_INFO "D_Word0(0x%08X)\n", pDMADescL->D_Word0); //gri - printk(KERN_INFO "Data_Addr(0x%08X)\n", pDMADescL->Data_Addr); //gri - printk(KERN_INFO "Branch_addr(0x%08X)\n", pDMADescL->Branch_addr); //gri - } - } -#endif - - break; - } - - case DESCRIPTOT_TYPE_MIX: - break; - default: - break; - } - - //wmb(); -} /*wmt_udc_pdma_des_prepare*/ - -void iso_prepare_0byte(void) -{ - unsigned char ubulk3tmp; - - ubulk3tmp = pDevReg->Bulk3EpControl; - pDevReg->Bulk3EpControl = EP_DMALIGHTRESET; - while (pDevReg->Bulk3EpControl & EP_DMALIGHTRESET) - ; - - pDevReg->Bulk3DesStatus = 0; - pDevReg->Bulk3DesTbytes2 = 0; - pDevReg->Bulk3DesTbytes1 = 0; - pDevReg->Bulk3DesTbytes0 = 0; - - pDevReg->Bulk3EpControl = ubulk3tmp; - - /* set endpoint data toggle*/ - pDevReg->Bulk3DesStatus = (BULKXFER_IOC | BULKXFER_IN); - //wmb(); - pDevReg->Bulk3DesStatus |= BULKXFER_ACTIVE; - -} -void next_in_dma(struct vt8500_ep *ep, struct vt8500_req *req) -{ - u32 temp32; - u32 dma_ccr = 0; - unsigned int length; - u32 dcmd; - u32 buf; - int is_in, i; - u8 *pctrlbuf; -#ifndef USE_BULK3_TO_INTERRUPT - u8 *pintbuf; -#endif - -// printk(KERN_INFO "next_in_dma s\n"); //gri - - dcmd = length = req->req.length - req->req.actual;/*wmt_ep_queue() : req->req.actual = 0*/ - buf = ((req->req.dma + req->req.actual) & 0xFFFFFFFC); - - is_in = 1;/*ep->bEndpointAddress & USB_DIR_IN;*/ - - DBG("next_in_dma() %s\n", ep ? ep->ep.name : NULL); - -#ifdef RNDIS_INFO_DEBUG_BULK_IN - if ((ep->bEndpointAddress & 0x7F) == 1) - INFO("next_in_dma() %s\n", ep ? ep->ep.name : NULL); -#endif - - if (((ep->bEndpointAddress & 0x7F) == 1) && (req->req.dma == 0xFFFFFFFF) && (ep->rndis == 0)) { - unsigned int dma_length = 65536; - -printk(KERN_INFO "rndis xxxxx %d\n",req->req.length); - - if (ep->rndis_buffer_alloc == 0) { - - ep->rndis_buffer_address = (unsigned int)UdcRndisEp1VirAddr; - ep->rndis_dma_phy_address = (u32)UdcRndisEp1PhyAddr; - ep->rndis_buffer_length = dma_length; - ep->rndis_buffer_alloc = 1; - } - ep->rndis = 1; - - } - -#ifdef USE_BULK3_TO_INTERRUPT - if (((ep->bEndpointAddress & 0x7F) == 3) && (req->req.dma == 0xFFFFFFFF) && (ep->rndis == 0)) { - unsigned int dma_length = 65536; - -//printk(KERN_INFO "rndis 3 xxxxx %d\n",req->req.length); - if (ep->rndis_buffer_alloc == 0) { - - ep->rndis_buffer_address = (unsigned int)UdcRndisEp3VirAddr; - ep->rndis_dma_phy_address = (u32)UdcRndisEp3PhyAddr; - ep->rndis_buffer_length = dma_length; - ep->rndis_buffer_alloc = 1; - } - ep->rndis = 1; - - } -#endif - - if (((ep->bEndpointAddress & 0x7F) == 4) && (req->req.dma == 0xFFFFFFFF) && (ep->rndis == 0)) { - unsigned int dma_length = 65536; - -//printk(KERN_INFO "rndis 3 xxxxx %d\n",req->req.length); - if (ep->rndis_buffer_alloc == 0) { - - ep->rndis_buffer_address = (unsigned int)UdcRndisEp3VirAddr; - ep->rndis_dma_phy_address = (u32)UdcRndisEp3PhyAddr; - ep->rndis_buffer_length = dma_length; - ep->rndis_buffer_alloc = 1; - } - ep->rndis = 1; - - } - - if (((ep->bEndpointAddress & 0x7F) == 1) && (ep->rndis == 1) && (req->req.length > ep->rndis_buffer_length)) { - //void *retval; - //dma_addr_t dma; - -printk(KERN_INFO "rndis ooooobb %d\n",req->req.length); - } - -#ifdef USE_BULK3_TO_INTERRUPT - if (((ep->bEndpointAddress & 0x7F) == 3) && (ep->rndis == 1) && (req->req.length > ep->rndis_buffer_length)) { - //void *retval; - //dma_addr_t dma; - -//printk(KERN_INFO "rndis 3 ooooobb %d\n",req->req.length); - } -#endif - - if ((ep->bEndpointAddress & 0x7F) == 0) {/*Control*/ - ep->ep_fifo_length = 0; - - if (length >= 64) - length = 64; - - ep->ep_fifo_length = length; - pctrlbuf = (u8 *)(req->req.buf + req->req.actual); - - for (i = 0; i < length; i++) - SetupBuf[i] = pctrlbuf[i]; - - if (ep->toggle_bit) - pDevReg->ControlDesTbytes = length | CTRLXFER_DATA1; - else - pDevReg->ControlDesTbytes = length | CTRLXFER_DATA0; - - pDevReg->ControlDesControl = CTRLXFER_IN + CTRLXFER_IOC; - wmb(); - pDevReg->ControlDesStatus = CTRLXFER_ACTIVE; - ControlState = CONTROLSTATE_DATA; - - if (ep->toggle_bit == 0) - ep->toggle_bit = 1; - else - ep->toggle_bit = 0; - } else if (((ep->bEndpointAddress & 0x7F) == 1)) {/*Bulk In*/ - ep->stall_more_processing = 0; - -// printk(KERN_INFO "next_in_dma %d %d %d\n", length, req->req.length,req->req.actual); //gri - - if (dcmd > UBE_MAX_DMA) - dcmd = UBE_MAX_DMA; - - if (pDevReg->Bulk1EpControl & EP_STALL) { - ep->stall_more_processing = 1; - ep->temp_dcmd = dcmd; - } - - if (ep->rndis == 1) { - memcpy((void *)((u32)ep->rndis_buffer_address), (void *)((u32)req->req.buf), length); - wmt_udc_pdma_des_prepare(dcmd, - ((ep->rndis_dma_phy_address + req->req.actual) & 0xFFFFFFFC), - DESCRIPTOT_TYPE_LONG, TRANS_IN, 1); - } else - wmt_udc_pdma_des_prepare(dcmd, buf, DESCRIPTOT_TYPE_LONG, TRANS_IN, 1); - - if (pDevReg->Bulk1EpControl & EP_STALL) - ep->temp_bulk_dma_addr = buf; - - if (pDevReg->Bulk1EpControl & EP_STALL) - ep->temp_dma_ccr = dma_ccr; - - pDevReg->Bulk1DesStatus = 0x00; - pDevReg->Bulk1DesTbytes2 |= (dcmd >> 16) & 0x3; - pDevReg->Bulk1DesTbytes1 = (dcmd >> 8) & 0xFF; - pDevReg->Bulk1DesTbytes0 = dcmd & 0xFF; - - /* set endpoint data toggle*/ - if (is_in) { - if (ep->toggle_bit) - pDevReg->Bulk1DesTbytes2 |= 0x40;/* BULKXFER_DATA1;*/ - else - pDevReg->Bulk1DesTbytes2 &= 0xBF;/*(~BULKXFER_DATA1);*/ - - pDevReg->Bulk1DesStatus = (BULKXFER_IOC | BULKXFER_IN); - } /*if(is_in)*/ - - if (pDevReg->Bulk1EpControl & EP_STALL) - ep->ep_stall_toggle_bit = ep->toggle_bit; - - - /*if((ep->bEndpointAddress & 0x7F) != 0)//!Control*/ - if (req->req.length > ep->maxpacket) { - /*ex : 512 /64 = 8 8 % 2 = 0*/ - temp32 = (req->req.length + ep->maxpacket - 1) / ep->maxpacket; - ep->toggle_bit = ((temp32 + ep->toggle_bit) % 2); - } else { - if (ep->toggle_bit == 0) - ep->toggle_bit = 1; - else - ep->toggle_bit = 0; - } - - /* DMA Channel Control Reg*/ - /* Software Request + Channel Enable*/ - dma_ccr = 0; - dma_ccr = DMA_RUN; - if (!is_in) - dma_ccr |= DMA_TRANS_OUT_DIR; - - if (dcmd) /* PDMA can not support 0 byte transfer*/ - pUdcDmaReg->DMA_Context_Control0 = dma_ccr; - - wmb(); - pDevReg->Bulk1DesStatus |= BULKXFER_ACTIVE; - } else if ((ep->bEndpointAddress & 0x7F) == 3) {/*Interrupt In*/ -#ifdef USE_BULK3_TO_INTERRUPT - ep->stall_more_processing = 0; - -// printk(KERN_INFO "next_in_dma %d %d %d\n", length, req->req.length,req->req.actual); //gri - - if (dcmd > UBE_MAX_DMA) - dcmd = UBE_MAX_DMA; - - if (pDevReg->Bulk3EpControl & EP_STALL) { - ep->stall_more_processing = 1; - ep->temp_dcmd = dcmd; - } - - if (ep->rndis == 1) { - memcpy((void *)((u32)ep->rndis_buffer_address), (void *)((u32)req->req.buf), length); - wmt_udc_pdma_des_prepare(dcmd, - ((ep->rndis_dma_phy_address + req->req.actual) & 0xFFFFFFFC), - DESCRIPTOT_TYPE_LONG, TRANS_IN, 0); - } else - wmt_udc_pdma_des_prepare(dcmd, buf, DESCRIPTOT_TYPE_LONG, TRANS_IN, 0); - - if (pDevReg->Bulk3EpControl & EP_STALL) - ep->temp_bulk_dma_addr = buf; - - if (pDevReg->Bulk3EpControl & EP_STALL) - ep->temp_dma_ccr = dma_ccr; - - pDevReg->Bulk3DesStatus = 0x00; - pDevReg->Bulk3DesTbytes2 |= (dcmd >> 16) & 0x3; - pDevReg->Bulk3DesTbytes1 = (dcmd >> 8) & 0xFF; - pDevReg->Bulk3DesTbytes0 = dcmd & 0xFF; - - /* set endpoint data toggle*/ - if (is_in) { - if (ep->toggle_bit) - pDevReg->Bulk3DesTbytes2 |= 0x40;/* BULKXFER_DATA1;*/ - else - pDevReg->Bulk3DesTbytes2 &= 0xBF;/*(~BULKXFER_DATA1);*/ - - pDevReg->Bulk3DesStatus = (BULKXFER_IOC | BULKXFER_IN); - } /*if(is_in)*/ - - if (pDevReg->Bulk3EpControl & EP_STALL) - ep->ep_stall_toggle_bit = ep->toggle_bit; - - - /*if((ep->bEndpointAddress & 0x7F) != 0)//!Control*/ - if (req->req.length > ep->maxpacket) { - /*ex : 512 /64 = 8 8 % 2 = 0*/ - temp32 = (req->req.length + ep->maxpacket - 1) / ep->maxpacket; - ep->toggle_bit = ((temp32 + ep->toggle_bit) % 2); - } else { - if (ep->toggle_bit == 0) - ep->toggle_bit = 1; - else - ep->toggle_bit = 0; - } - - /* DMA Channel Control Reg*/ - /* Software Request + Channel Enable*/ - dma_ccr = 0; - //dma_ccr = DMA_RUN; - if (!is_in) - dma_ccr |= DMA_TRANS_OUT_DIR; - - wmb(); - if (dcmd) /* PDMA can not support 0 byte transfer*/ - pUdcDmaReg->DMA_Context_Control2 = dma_ccr; - - dma_ccr |= DMA_RUN; - - wmb(); - if (dcmd) /* PDMA can not support 0 byte transfer*/ - pUdcDmaReg->DMA_Context_Control2 = dma_ccr; - - wmb(); - pDevReg->Bulk3DesStatus |= BULKXFER_ACTIVE; -#else - -//printk(KERN_INFO "udc interrupt\n"); - - if (dcmd > INT_FIFO_SIZE) - dcmd = INT_FIFO_SIZE; - interrupt_transfer_size = dcmd; - - pintbuf = (u8 *)(req->req.buf);/* + req->req.actual);*/ - - for (i = req->req.actual; i < (req->req.actual + dcmd); i++) - IntBuf[(i-req->req.actual)] = pintbuf[i]; - - pDevReg->InterruptDes = 0x00; - pDevReg->InterruptDes = (dcmd << 4); - - if (ep->toggle_bit) - pDevReg->InterruptDes |= INTXFER_DATA1; - else - pDevReg->InterruptDes &= 0xF7; - - if (ep->toggle_bit == 0) - ep->toggle_bit = 1; - else - ep->toggle_bit = 0; - - pDevReg->InterruptDes |= INTXFER_IOC; - wmb(); - pDevReg->InterruptDes |= INTXFER_ACTIVE; -#endif - } else if ((ep->bEndpointAddress & 0x7F) == 4) {/*Iso In*/ - - unsigned char tmp; - - tmp = pDevReg->Bulk3EpControl; - - pDevReg->Bulk3EpControl = EP_DMALIGHTRESET; - while (pDevReg->Bulk3EpControl & EP_DMALIGHTRESET) - ; - - pDevReg->Bulk3EpControl = tmp; - - wmt_pdma2_reset(); - - ep->stall_more_processing = 0; - - //printk(KERN_INFO "next_in_dma 4 %d %d %d\n", length, req->req.length,req->req.actual); //gri - //printk(KERN_INFO "next_in_dma 4\n"); //gri - - if (dcmd > UBE_MAX_DMA) - dcmd = UBE_MAX_DMA; - - if (pDevReg->Bulk3EpControl & EP_STALL) { - ep->stall_more_processing = 1; - ep->temp_dcmd = dcmd; - } - - if (ep->rndis == 1) { - memcpy((void *)((u32)ep->rndis_buffer_address), (void *)((u32)req->req.buf), length); - wmt_udc_pdma_des_prepare(dcmd, - ((ep->rndis_dma_phy_address + req->req.actual) & 0xFFFFFFFC), - DESCRIPTOT_TYPE_LONG, TRANS_IN, 0); - } else - wmt_udc_pdma_des_prepare(dcmd, buf, DESCRIPTOT_TYPE_LONG, TRANS_IN, 0); - - if (pDevReg->Bulk3EpControl & EP_STALL) - ep->temp_bulk_dma_addr = buf; - - if (pDevReg->Bulk3EpControl & EP_STALL) - ep->temp_dma_ccr = dma_ccr; - - pDevReg->Bulk3DesStatus = 0x00; - pDevReg->Bulk3DesTbytes2 |= (dcmd >> 16) & 0x3; - pDevReg->Bulk3DesTbytes1 = (dcmd >> 8) & 0xFF; - pDevReg->Bulk3DesTbytes0 = dcmd & 0xFF; - - /* set endpoint data toggle*/ - if (is_in) { - pDevReg->Bulk3DesTbytes2 &= 0xBF;/*(~BULKXFER_DATA1);*/ - - pDevReg->Bulk3DesStatus = (BULKXFER_IOC | BULKXFER_IN); - } /*if(is_in)*/ - - if (pDevReg->Bulk3EpControl & EP_STALL) - ep->ep_stall_toggle_bit = ep->toggle_bit; - - - /*if((ep->bEndpointAddress & 0x7F) != 0)//!Control*/ - ep->toggle_bit = 0; - - - /* DMA Channel Control Reg*/ - /* Software Request + Channel Enable*/ - dma_ccr = 0; - //dma_ccr = DMA_RUN; - if (!is_in) - dma_ccr |= DMA_TRANS_OUT_DIR; - -// wmb(); - if (dcmd) /* PDMA can not support 0 byte transfer*/ - pUdcDmaReg->DMA_Context_Control2 = dma_ccr; - - dma_ccr |= DMA_RUN; - -// wmb(); - if (dcmd) /* PDMA can not support 0 byte transfer*/ - pUdcDmaReg->DMA_Context_Control2 = dma_ccr; - -// wmb(); - - pDevReg->Bulk3DesStatus |= BULKXFER_ACTIVE; - fiq_using = 1; - - wmt_enable_fiq(300); - //run_script(action_chkiso); - } - - DBG("req->req.dma 0x%08X \n", req->req.dma); - -#ifdef MSC_COMPLIANCE_TEST - INFO("req->req.dma 0x%08X \n", req->req.dma); -#endif - - req->dma_bytes = dcmd;//length; - -#if 0 - if (((ep->bEndpointAddress & 0x7F) == 3) || ((ep->bEndpointAddress & 0x7F) == 4)) { - printk(KERN_INFO "next_in_dma 3 e\n"); //gri - printk(KERN_INFO "Bulk3EpInEpNum =0x%2.2x\n", pDevReg->Bulk3EpInEpNum); //gri - printk(KERN_INFO "Bulk3EpMaxLen =0x%2.2x\n", pDevReg->Bulk3EpMaxLen); //gri - printk(KERN_INFO "Bulk3EpOutEpNum =0x%2.2x\n", pDevReg->Bulk3EpOutEpNum); //gri - printk(KERN_INFO "Bulk3EpControl =0x%2.2x\n", pDevReg->Bulk3EpControl); //gri - - printk(KERN_INFO "Bulk3DesTbytes2 =0x%2.2x\n", pDevReg->Bulk3DesTbytes2); //gri - printk(KERN_INFO "Bulk3DesTbytes1 =0x%2.2x\n", pDevReg->Bulk3DesTbytes1); //gri - printk(KERN_INFO "Bulk3DesTbytes0 =0x%2.2x\n", pDevReg->Bulk3DesTbytes0); //gri - printk(KERN_INFO "Bulk3DesStatus =0x%2.2x\n", pDevReg->Bulk3DesStatus); //gri - - printk(KERN_INFO "DMA_Descriptor_Point2 =0x%8.8x\n", pUdcDmaReg->DMA_Descriptor_Point2); //gri - printk(KERN_INFO "DMA_Residual_Bytes2 =0x%8.8x\n", pUdcDmaReg->DMA_Residual_Bytes2); //gri - printk(KERN_INFO "DMA_Data_Addr2 =0x%8.8x\n", pUdcDmaReg->DMA_Data_Addr2); //gri - printk(KERN_INFO "DMA_Branch_Addr2 =0x%8.8x\n", pUdcDmaReg->DMA_Branch_Addr2); //gri - printk(KERN_INFO "Descriptor_Addr2 =0x%8.8x\n", pUdcDmaReg->Descriptor_Addr2); //gri - printk(KERN_INFO "DMA_Context_Control2 =0x%8.8x\n", pUdcDmaReg->DMA_Context_Control2); //gri - - } - else if ((ep->bEndpointAddress & 0x7F) == 1) { - printk(KERN_INFO "next_in_dma 1 e\n"); //gri - printk(KERN_INFO "Bulk1EpInEpNum =0x%2.2x\n", pDevReg->Bulk1EpInEpNum); //gri - printk(KERN_INFO "Bulk1EpMaxLen =0x%2.2x\n", pDevReg->Bulk1EpMaxLen); //gri - printk(KERN_INFO "Bulk1EpOutEpNum =0x%2.2x\n", pDevReg->Bulk1EpOutEpNum); //gri - printk(KERN_INFO "Bulk1EpControl =0x%2.2x\n", pDevReg->Bulk1EpControl); //gri - - printk(KERN_INFO "Bulk1DesTbytes2 =0x%2.2x\n", pDevReg->Bulk1DesTbytes2); //gri - printk(KERN_INFO "Bulk1DesTbytes1 =0x%2.2x\n", pDevReg->Bulk1DesTbytes1); //gri - printk(KERN_INFO "Bulk1DesTbytes0 =0x%2.2x\n", pDevReg->Bulk1DesTbytes0); //gri - printk(KERN_INFO "Bulk1DesStatus =0x%2.2x\n", pDevReg->Bulk1DesStatus); //gri - - printk(KERN_INFO "DMA_Descriptor_Point2 =0x%8.8x\n", pUdcDmaReg->DMA_Descriptor_Point0); //gri - printk(KERN_INFO "DMA_Residual_Bytes2 =0x%8.8x\n", pUdcDmaReg->DMA_Residual_Bytes0); //gri - printk(KERN_INFO "DMA_Data_Addr2 =0x%8.8x\n", pUdcDmaReg->DMA_Data_Addr0); //gri - printk(KERN_INFO "DMA_Branch_Addr2 =0x%8.8x\n", pUdcDmaReg->DMA_Branch_Addr0); //gri - printk(KERN_INFO "Descriptor_Addr2 =0x%8.8x\n", pUdcDmaReg->Descriptor_Addr0); //gri - printk(KERN_INFO "DMA_Context_Control2 =0x%8.8x\n", pUdcDmaReg->DMA_Context_Control0); //gri - } -#endif - -} /*static void next_in_dma()*/ - -static void finish_in_dma(struct vt8500_ep *ep, struct vt8500_req *req, int status) -{ -// printk(KERN_INFO "finish_in_dma()s\n"); //gri - - DBG("finish_in_dma() %s\n", ep ? ep->ep.name : NULL); - - if (status == 0) { /* Normal complete!*/ -#ifdef USE_BULK3_TO_INTERRUPT - req->req.actual += dma_src_len(ep, req);/*req->dma_bytes;*/ -#else -// if ((ep->bEndpointAddress & 0x7F) == 3) -// req->req.actual += interrupt_transfer_size; -// else - if ((ep->bEndpointAddress & 0x7F) != 3) - req->req.actual += dma_src_len(ep, req);/*req->dma_bytes;*/ -#endif - - /* return if this request needs to send data or zlp*/ - if (req->req.actual < req->req.length) - return; - - if (req->req.zero - && req->dma_bytes != 0 - && (req->req.actual % ep->maxpacket) == 0) - return; - - } else - req->req.actual += dma_src_len(ep, req); - -#ifdef RNDIS_INFO_DEBUG_BULK_IN - if ((ep->bEndpointAddress & 0x7F) == 1) - INFO("finish_in_dma()e %s req->req.actual(0x%08X) req->req.length(0x%08X)\n", - ep ? ep->ep.name : NULL, req->req.actual, req->req.length); -#endif - - done(ep, req, status); - -//printk(KERN_INFO "finish_in_dma() %s req->req.actual(0x%08X) req->req.length(0x%08X)\n", -//ep ? ep->ep.name : NULL, req->req.actual, req->req.length); //gri - - -} /*static void finish_in_dma()*/ - -static void next_out_dma(struct vt8500_ep *ep, struct vt8500_req *req) -{ - /*unsigned packets;*/ - u32 dma_ccr = 0; - u32 dcmd; - u32 buf; - int is_in; - -// printk(KERN_INFO "next_out_dma s\n"); //gri - - is_in = 0;/*ep->bEndpointAddress & USB_DIR_IN;*/ - -#ifdef RNDIS_INFO_DEBUG_BULK_OUT - if (ep->bEndpointAddress == 2) - INFO("next_out_dma() %s\n", ep ? ep->ep.name : NULL); -#endif - - DBG("next_out_dma() %s\n", ep ? ep->ep.name : NULL); - - dcmd = req->dma_bytes = req->req.length - req->req.actual; - buf = ((req->req.dma + req->req.actual) & 0xFFFFFFFC); - - if ((ep->bEndpointAddress == 2) && (req->req.dma == 0xFFFFFFFF) && (ep->rndis == 0)) { - unsigned int dma_length = 65536; - -printk(KERN_INFO "rndis ooooo %d\n",req->req.length); - if (ep->rndis_buffer_alloc == 0) { - - ep->rndis_buffer_address = (unsigned int)UdcRndisEp2VirAddr; - ep->rndis_dma_phy_address = (u32)UdcRndisEp2PhyAddr; - ep->rndis_buffer_length = dma_length; - ep->rndis_buffer_alloc = 1; - } - ep->rndis = 1; - } - if ((ep->bEndpointAddress == 2) && (ep->rndis == 1) && (req->req.length > ep->rndis_buffer_length)) { -// void *retval; -// dma_addr_t dma; - -printk(KERN_INFO "rndis ooooobb %d\n",req->req.length); -#if 0 - dma_free_coherent (ep->udc->dev, - ep->rndis_buffer_length, - (void *)ep->rndis_buffer_address, (dma_addr_t)ep->rndis_dma_phy_address); - - retval = dma_alloc_coherent(ep->udc->dev, - req->req.length, &dma, GFP_ATOMIC); - - ep->rndis_buffer_address = (unsigned int)retval; - ep->rndis_dma_phy_address = (u32)dma; - ep->rndis_buffer_length = req->req.length; - ep->rndis = 1; -#endif - } - - if (ep->bEndpointAddress == 0) {/*Control*/ - ep->ep_fifo_length = 0; - - if (dcmd >= 64) - dcmd = 64; - - ep->ep_fifo_length = dcmd; - - if (ep->toggle_bit) - pDevReg->ControlDesTbytes = dcmd | CTRLXFER_DATA1; - else - pDevReg->ControlDesTbytes = dcmd | CTRLXFER_DATA0; - - pDevReg->ControlDesControl = CTRLXFER_OUT+CTRLXFER_IOC; - wmb(); - pDevReg->ControlDesStatus = CTRLXFER_ACTIVE; - ControlState = CONTROLSTATE_DATA; - - if (ep->toggle_bit == 0) - ep->toggle_bit = 1; - else - ep->toggle_bit = 0; - - } else if (ep->bEndpointAddress == 2) {/*Bulk Out*/ - ep->stall_more_processing = 0; - -// printk(KERN_INFO "next_out_dma %d %d %d\n", req->dma_bytes, req->req.length,req->req.actual); //gri - - /*if(req->dma_bytes == 64)*/ - ep->udc->cbw_virtual_address = (((u32)req->req.buf + req->req.actual) & 0xFFFFFFFC); - - if (dcmd > UBE_MAX_DMA) - dcmd = UBE_MAX_DMA; - - if (pDevReg->Bulk2EpControl & EP_STALL) { - ep->stall_more_processing = 1; - ep->temp_dcmd = dcmd; - } - /* Set Address*/ - if (ep->rndis == 1) - wmt_udc_pdma_des_prepare(dcmd, - ((ep->rndis_dma_phy_address + req->req.actual) & 0xFFFFFFFC), - DESCRIPTOT_TYPE_LONG, TRANS_OUT, 1); - else - wmt_udc_pdma_des_prepare(dcmd, buf, DESCRIPTOT_TYPE_LONG, TRANS_OUT, 1); - - if (pDevReg->Bulk2EpControl & EP_STALL) - ep->temp_bulk_dma_addr = buf; - - if (pDevReg->Bulk2EpControl & EP_STALL) - ep->temp_dma_ccr = dma_ccr; - - /* DMA Global Controller Reg*/ - /* DMA Controller Enable +*/ - /* DMA Global Interrupt Enable(if any TC, error, or abort status in any channels occurs)*/ - - pDevReg->Bulk2DesStatus = 0x00; - pDevReg->Bulk2DesTbytes2 |= (dcmd >> 16) & 0x3; - pDevReg->Bulk2DesTbytes1 = (dcmd >> 8) & 0xFF; - pDevReg->Bulk2DesTbytes0 = dcmd & 0xFF; - - /* set endpoint data toggle*/ - if (ep->toggle_bit) - pDevReg->Bulk2DesTbytes2 |= BULKXFER_DATA1; - else - pDevReg->Bulk2DesTbytes2 &= 0x3F;/*BULKXFER_DATA0;*/ - - pDevReg->Bulk2DesStatus = BULKXFER_IOC;/*| BULKXFER_IN;*/ - - if (pDevReg->Bulk2EpControl & EP_STALL) - ep->ep_stall_toggle_bit = ep->toggle_bit; - - dma_ccr = 0; - dma_ccr = DMA_RUN; - if (!is_in) - dma_ccr |= DMA_TRANS_OUT_DIR; - - wmb(); - pUdcDmaReg->DMA_Context_Control1 = dma_ccr; - wmb(); - pDevReg->Bulk2DesStatus |= BULKXFER_ACTIVE; - /*udc_device_dump_register();*/ - } - - VDBG("req->req.dma 0x%08X \n", req->req.dma); - -//printk(KERN_INFO "next_out_dma e\n"); //gri - -} /*static void next_out_dma()*/ - -static void -finish_out_dma(struct vt8500_ep *ep, struct vt8500_req *req, int status) -{ - u16 count; - u8 temp8; - u32 temp32; - /*u8 bulk_dma_csr;*/ - -// printk(KERN_INFO "finish_out_dma s\n"); //gri - - DBG("finish_out_dma() %s\n", ep ? ep->ep.name : NULL); - - count = dma_dest_len(ep, req); - - if (ep->bEndpointAddress == 0) {/*Control*/ - u8 *pctrlbuf; - int i; - - pctrlbuf = (u8 *)(req->req.buf + req->req.actual); - for (i = 0; i < count; i++) - pctrlbuf[i] = SetupBuf[i]; - - /*INFO("finish_out_dma() %s\n", ep ? ep->ep.name : NULL);*/ - /*dump_bulk_buffer((req->req.buf + req->req.actual), count);*/ - } - - count += req->req.actual; - - if (count <= req->req.length) - req->req.actual = count; - - if (ep->bEndpointAddress == 0) {/*Control*/ - if (req->req.actual < req->req.length) { - temp8 = pDevReg->ControlDesStatus; - - if ((temp8 & CTRLXFER_SHORTPKT) == 0) - return; /*Continue...*/ - } - } else if (ep->bEndpointAddress == 2) { - - if (pDevReg->Bulk2DesTbytes2 & 0x80) - ep->toggle_bit= 1; - else - ep->toggle_bit= 0; - -// while((pUdcDmaReg->DMA_Context_Control1_Bis.EventCode != 0xf) && -// (pUdcDmaReg->DMA_Context_Control1_Bis.EventCode != 0x5)); - -// printk(KERN_INFO "finish_out_dma() %s req->actual(%d) req->length(%d) toggle_bit(%8x) add %x\n", -// ep ? ep->ep.name : NULL, req->req.actual, req->req.length, (pDevReg->Bulk2DesTbytes2), (unsigned int)pDevReg);//gri - // INFO("finish_out_dma() %s req->actual(%d) req->length(%d) toggle_bit(%8x) add %x\n", - // ep ? ep->ep.name : NULL, req->req.actual, req->req.length, (pDevReg->Bulk2DesTbytes2), (unsigned int)pDevReg); - - - { - { - unsigned int gri_t_d; - unsigned int gri_count=0; - unsigned int dma_count; - do{ - gri_t_d=pUdcDmaReg->DMA_ISR ; - gri_t_d &= 0x2; - gri_count++; - if (gri_count & 0x10){ - gri_count=0; -// printk(KERN_INFO "pUdcDmaReg->DMA_Context_Control1 0x%08x\n", &(pUdcDmaReg->DMA_Context_Control1)); - printk(KERN_INFO "XXXXXXXXXXX 0x%08x\n",pUdcDmaReg->DMA_Context_Control1); - dma_count = req->req.length - pUdcDmaReg->DMA_Residual_Bytes1_Bits.ResidualBytes; -// printk(KERN_INFO "CC 0x%08x 0x%08x\n", dma_count, count); - if (pUdcDmaReg->DMA_Context_Control1_Bis.Run == 0) - break; - if ((count == dma_count) || (count == 0)){ -// printk(KERN_INFO "XXXXXXXXXXX 0x%08x\n",pUdcDmaReg->DMA_Context_Control1); -// printk(KERN_INFO "CC 0x%08x 0x%08x\n", dma_count, count); -// while(1); - pUdcDmaReg->DMA_Context_Control1_Bis.Run = 0; - break; - } - } - }while(!gri_t_d); - } - } - - - if (req->req.actual < req->req.length) { - DBG("finish_out_dma() req->actual < req->req.length\n"); - temp8 = pDevReg->Bulk2DesStatus; - - if ((temp8 & BULKXFER_SHORTPKT) == 0) - return; /*Continue...*/ - else { /*Short Package.*/ - pDevReg->Bulk2EpControl |= EP_DMALIGHTRESET; - wmb(); - - while (pDevReg->Bulk2EpControl & EP_DMALIGHTRESET) - ; - pDevReg->Bulk2EpControl = EP_RUN + EP_ENABLEDMA; - wmb(); - } - } - } - /* rx completion*/ - /*UDC_DMA_IRQ_EN_REG &= ~UDC_RX_EOT_IE(ep->dma_channel);*/ - -//#ifdef RNDIS_INFO_DEBUG_BULK_OUT -// if (ep->bEndpointAddress == 2) -// INFO("finish_out_dma() %s req->actual(%d) req->length(%d) toggle_bit(%8x) add %x\n", -// ep ? ep->ep.name : NULL, req->req.actual, req->req.length, (pDevReg->Bulk2DesTbytes2), (unsigned int)pDevReg); -//#endif - - /*dump_bulk_buffer(req->req.buf, req->req.actual);*/ - - if ((ep->bEndpointAddress == 2) && (ep->rndis == 1)) { - memcpy((void *)((u32)req->req.buf), (void *)((u32)ep->rndis_buffer_address), req->req.actual); - - #ifdef RNDIS_INFO_DEBUG_BULK_OUT - /*if ((req->req.actual % 4 == 3))// && (b_message == 0))*/ - /*dump_bulk_buffer(req->req.buf, req->req.actual);*/ - #endif -#if 0 - if ((req->req.length == 1600) || (req->req.length == 2048)) {/*F.S. [1600] : H.S. [2048]*/ - /*ex : 512 /64 = 8 8 % 2 = 0*/ - temp32 = (req->req.actual + ep->maxpacket - 1) / ep->maxpacket; - ep->toggle_bit = ((temp32 + ep->toggle_bit) % 2); - } else - INFO("Different Length for Bulk Out (%08d) Toggle Bit would Error\n" - , req->req.length); -#else -#if 0 - if (req->req.length > ep->maxpacket) { - /*ex : 512 /64 = 8 8 % 2 = 0*/ - temp32 = (req->req.actual + ep->maxpacket - 1) / ep->maxpacket; - ep->toggle_bit = ((temp32 + ep->toggle_bit) % 2); - } else { - if (ep->toggle_bit == 0) - ep->toggle_bit = 1; - else - ep->toggle_bit = 0; - } -#endif - -#endif - } else { -#if 1 - if (ep->bEndpointAddress == 0){ - /*GigaHsu-B 2008.5.15 : Add this caculate toggle from next_out_dma() : - fixed sideshow gadget issue.*/ - if (req->req.length > ep->maxpacket) { - /*ex : 512 /64 = 8 8 % 2 = 0*/ - temp32 = (req->req.actual + ep->maxpacket - 1) / ep->maxpacket; - ep->toggle_bit = ((temp32 + ep->toggle_bit) % 2); - } else { - if (ep->toggle_bit == 0) - ep->toggle_bit = 1; - else - ep->toggle_bit = 0; - } - } -#endif - - /*GigaHsu-E 2008.5.15*/ - } - - done(ep, req, status); - -//printk(KERN_INFO "finish_out_dma e\n"); //gri - -} /*finish_out_dma()*/ - -void dma_irq(u8 addr) -{ - struct vt8500_ep *ep; - struct vt8500_req *req; - /*u32 temp32;*/ - /*u32 i;*/ - - ep = &udc->ep[addr & 0x7f]; - - if ((ep->bEndpointAddress & 0x7F) == 1) {/*Bulk In*/ - - /* IN dma: tx to host*/ - if (!list_empty(&ep->queue)) { - req = container_of(ep->queue.next, struct vt8500_req, queue); - finish_in_dma(ep, req, 0); - } - - while (pDevReg->Bulk1EpControl & EP_COMPLETEINT) - ; - - if (!list_empty(&ep->queue)) { - req = container_of(ep->queue.next, struct vt8500_req, queue); - next_in_dma(ep, req); - } - } else if (ep->bEndpointAddress == 2) {/*Bulk Out*/ - - /* OUT dma: rx from host*/ - if (!list_empty(&ep->queue)) { - req = container_of(ep->queue.next, struct vt8500_req, queue); - finish_out_dma(ep, req, 0); - } - - while (pDevReg->Bulk2EpControl & EP_COMPLETEINT) - ; - - if (!list_empty(&ep->queue)) { - req = container_of(ep->queue.next, struct vt8500_req, queue); - next_out_dma(ep, req); - } - } else if ((ep->bEndpointAddress & 0x7F) == 3) {/*Interrupt In*/ - -#ifdef USE_BULK3_TO_INTERRUPT - /* IN dma: tx to host*/ - if (!list_empty(&ep->queue)) { - req = container_of(ep->queue.next, struct vt8500_req, queue); - finish_in_dma(ep, req, 0); - } - - while (pDevReg->Bulk3EpControl & EP_COMPLETEINT) - ; - - if (!list_empty(&ep->queue)) { - req = container_of(ep->queue.next, struct vt8500_req, queue); - next_in_dma(ep, req); - } -#else - /* IN dma: tx to host*/ - while (pDevReg->InterruptEpControl & EP_COMPLETEINT) - ; - if (!list_empty(&ep->queue)) { - req = container_of(ep->queue.next, struct vt8500_req, queue); - req->req.actual += dma_src_len(ep, req); - if (req->req.actual < req->req.length) - next_in_dma(ep, req); - else - finish_in_dma(ep, req, 0); - } - -// if (!list_empty(&ep->queue)) { -// req = container_of(ep->queue.next, struct vt8500_req, queue); -// next_in_dma(ep, req); -// } -#endif - } else if ((ep->bEndpointAddress & 0x7F) == 4) {/*Iso In*/ - - /* IN dma: tx to host*/ - if (!list_empty(&ep->queue)) { - req = container_of(ep->queue.next, struct vt8500_req, queue); - finish_in_dma(ep, req, 0); - } - } - -} /*static void dma_irq()*/ - - -static void pullup_enable(struct vt8500_udc *udc) -{ - INFO("gri pullup_enable()\n"); - b_pullup = 1; - /*Enable port control's FSM to enable 1.5k pull-up on D+.*/ - //pDevReg->PhyMisc &= 0x0F;/*Hardware auto-mode*/ - pDevReg->FunctionPatchEn |= 0x20; /* HW attach process evaluation enable bit*/ - wmb(); - /*pDevReg->PhyMisc |= 0x50;*/ - -} /*static void pullup_enable()*/ - - - -/*-------------------------------------------------------------------------*/ -/*file_storage.c ep0_queue() - control*/ -/*file_storage.c start_transfer() - bulk*/ -static int -wmt_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) -{ - struct vt8500_ep *ep = container_of(_ep, struct vt8500_ep, ep); - struct vt8500_req *req = container_of(_req, struct vt8500_req, req); - /*struct vt8500_udc *udc;*/ -// unsigned long flags; - unsigned char empty_data = 0; - - DBG("wmt_ep_queue() %s\n", ep ? ep->ep.name : NULL); -// INFO("gri wmt_ep_queue() %s\n", ep ? ep->ep.name : NULL); - -// if ((ep->bEndpointAddress & 0x7F) > 4) -// return -EINVAL; - -#ifdef RNDIS_INFO_DEBUG_BULK_OUT - if ((ep->bEndpointAddress == 3))/* || ((ep->bEndpointAddress & 0x7F) == 2))*/ - INFO("wmt_ep_queue() %s\n", ep ? ep->ep.name : NULL); -#endif - - /* catch various bogus parameters*/ - if (!_req || !req->req.complete || !req->req.buf - || !list_empty(&req->queue)) { - DBG("[wmt_ep_queue], bad params\n"); - return -EINVAL; - } - if (!_ep || (!ep->desc && ep->bEndpointAddress)) { - DBG("[wmt_ep_queue], bad ep\n"); - return -EINVAL; - } - -//#ifdef RNDIS_INFO_DEBUG_BULK_OUT -// if ((ep->bEndpointAddress == 2))/* || ((ep->bEndpointAddress & 0x7F) == 1))*/ -// INFO("wmt_ep_queue() %s queue req %p, len %d buf %p\n", -// ep->ep.name, _req, _req->length, _req->buf); -//#endif - -//#ifdef MSC_COMPLIANCE_TEST -// if ((ep->bEndpointAddress & 0x7F) == 1) -// INFO("wmt_ep_queue() %s queue req %p, len %d buf %p\n", -// ep->ep.name, _req, _req->length, _req->buf); -//#endif - - DBG("wmt_ep_queue() %s queue req %p, len %d buf %p\n", - ep->ep.name, _req, _req->length, _req->buf); - - spin_lock_irqsave(&udc->lock, irq_flags); - - req->req.status = -EINPROGRESS; - req->req.actual = 0; - - /* maybe kickstart non-iso i/o queues*/ - - if (list_empty(&ep->queue) && !ep->stopped && !ep->ackwait) { - int is_in; - - if (ep->bEndpointAddress == 0) { - if (!udc->ep0_pending || !list_empty(&ep->queue)) { - spin_unlock_irqrestore(&udc->lock, irq_flags); - return -EL2HLT; - } - - /* empty DATA stage?*/ - is_in = udc->ep0_in; - - if (!req->req.length) { /*status 0 bytes*/ - - udc->ep0_status_0_byte = 1; - ep0_status(udc); - - /* cleanup*/ - udc->ep0_pending = 0; - done(ep, req, 0); - empty_data = 1; - } - - if (req->req.length) { - udc->bulk_out_dma_write_error = 0; - (is_in ? next_in_dma : next_out_dma)(ep, req); - } - } else { - is_in = ep->bEndpointAddress & USB_DIR_IN; - - if (req != 0){ - list_add_tail(&req->queue, &ep->queue); - empty_data = 1; - } -// else -// { -// printk(KERN_INFO "xxx %x %x\n",req,empty_data); //gri -// } - /*if (!ep->has_dma)*/ - /* use_ep(ep, UDC_EP_SEL);*/ - /* if ISO: SOF IRQs must be enabled/disabled!*/ - if (((ep->bEndpointAddress & 0x7F) != 4) || (!fiq_using)) - (is_in ? next_in_dma : next_out_dma)(ep, req); -#if 0 - else - printk("gri w_e_q() 01 %s not q f_u=%d \n", ep ? ep->ep.name : NULL, fiq_using); -#endif - } - } - /* irq handler advances the queue*/ -#if 0 - if ((ep->bEndpointAddress & 0x7F) == 4) - printk("gri w_e_q() 02 %s not q f_u=%d \n", ep ? ep->ep.name : NULL, fiq_using); -#endif - - if ((req != 0) && (empty_data == 0)) - list_add_tail(&req->queue, &ep->queue); - - spin_unlock_irqrestore(&udc->lock, irq_flags); - - return 0; -} /*wmt_ep_queue()*/ - -void ep1_cancel_tx(struct vt8500_ep *ep) -{ - unsigned char btmp; - unsigned char bctrl0; - - bctrl0 = pDevReg->Bulk1EpControl & 0xE3; - pDevReg->Bulk1DesStatus &= 0xF0; - - ep->stall_more_processing = 0; - - pDevReg->Bulk1DesStatus = 0x00; - pDevReg->Bulk1DesTbytes2 |= - (ep->temp_dcmd >> 16) & 0x3; - pDevReg->Bulk1DesTbytes1 = - (ep->temp_dcmd >> 8) & 0xFF; - pDevReg->Bulk1DesTbytes0 = - ep->temp_dcmd & 0xFF; - - /* set endpoint data toggle*/ - btmp = pDevReg->Bulk1DesTbytes2 & 0x40; - - if (btmp) - ep->toggle_bit = 1; - else - ep->toggle_bit = 0; - - if (ep->toggle_bit) { - /* BULKXFER_DATA1;*/ - pDevReg->Bulk1DesTbytes2 |= 0x40; - } else { - /*(~BULKXFER_DATA1);*/ - pDevReg->Bulk1DesTbytes2 &= 0xBF; - } - - pDevReg->Bulk1DesStatus = - (BULKXFER_IOC | BULKXFER_IN); - - wmb(); - pDevReg->Bulk1EpControl |= EP_DMALIGHTRESET; - wmb(); - while (pDevReg->Bulk1EpControl & EP_DMALIGHTRESET); - pDevReg->Bulk1EpControl = bctrl0; - - wmt_pdma0_reset(); - wmb(); -} - -void ep2_cancel_tx(struct vt8500_ep *ep) -{ - unsigned char btmp; - unsigned char bctrl0; - - bctrl0 = pDevReg->Bulk2EpControl & 0xE3; - pDevReg->Bulk2DesStatus &= 0xF0; - - ep->stall_more_processing = 0; - - pDevReg->Bulk2DesStatus = 0x00; - pDevReg->Bulk2DesTbytes2 |= - (ep->temp_dcmd >> 16) & 0x3; - pDevReg->Bulk2DesTbytes1 = - (ep->temp_dcmd >> 8) & 0xFF; - pDevReg->Bulk2DesTbytes0 = - ep->temp_dcmd & 0xFF; - - /* set endpoint data toggle*/ - btmp = pDevReg->Bulk2DesTbytes2 & 0x80; - - if (btmp) - ep->toggle_bit = 1; - else - ep->toggle_bit = 0; - - if (ep->toggle_bit) { - /* BULKXFER_DATA1;*/ - pDevReg->Bulk2DesTbytes2 |= 0x40; - } else { - /*(~BULKXFER_DATA1);*/ - pDevReg->Bulk2DesTbytes2 &= 0xBF; - } - - pDevReg->Bulk2DesStatus = - (BULKXFER_IOC | BULKXFER_IN); - - wmb(); - pDevReg->Bulk2EpControl |= EP_DMALIGHTRESET; - wmb(); - while (pDevReg->Bulk2EpControl & EP_DMALIGHTRESET); - pDevReg->Bulk2EpControl = bctrl0; - - wmt_pdma1_reset(); - wmb(); -} - -void ep3_cancel_tx(struct vt8500_ep *ep) -{ -#ifdef USE_BULK3_TO_INTERRUPT - unsigned char btmp; - unsigned char bctrl0; - - bctrl0 = pDevReg->Bulk3EpControl & 0xE3; - pDevReg->Bulk3DesStatus &= 0xF0; - - ep->stall_more_processing = 0; - - pDevReg->Bulk3DesStatus = 0x00; - pDevReg->Bulk3DesTbytes2 |= - (ep->temp_dcmd >> 16) & 0x3; - pDevReg->Bulk3DesTbytes1 = - (ep->temp_dcmd >> 8) & 0xFF; - pDevReg->Bulk3DesTbytes0 = - ep->temp_dcmd & 0xFF; - - /* set endpoint data toggle*/ - btmp = pDevReg->Bulk3DesTbytes2 & 0x40; - - if (btmp) - ep->toggle_bit = 1; - else - ep->toggle_bit = 0; - - if (ep->toggle_bit) { - /* BULKXFER_DATA1;*/ - pDevReg->Bulk3DesTbytes2 |= 0x40; - } else { - /*(~BULKXFER_DATA1);*/ - pDevReg->Bulk3DesTbytes2 &= 0xBF; - } - - pDevReg->Bulk3DesStatus = - (BULKXFER_IOC | BULKXFER_IN); - - wmb(); - pDevReg->Bulk3EpControl |= EP_DMALIGHTRESET; - wmb(); - while (pDevReg->Bulk3EpControl & EP_DMALIGHTRESET); - pDevReg->Bulk3EpControl = bctrl0; - - wmt_pdma2_reset(); - wmb(); -#else - unsigned char tmp0, tmp1, tmp2, tmp3; - - pDevReg->InterruptDes = 0x00; - wmb(); - tmp0 = InterruptEpControl; - tmp1 = InterruptReserved; - tmp2 = InterruptEpMaxLen; - tmp3 = InterruptEpEpNum; - InterruptEpControl |= EP_DMALIGHTRESET; - wmb(); - while (pDevReg->InterruptEpControl & EP_DMALIGHTRESET); - InterruptEpControl = tmp0; - InterruptReserved = tmp1; - InterruptEpMaxLen = tmp2; - InterruptEpEpNum = tmp3; - wmb(); -#endif -} - -void ep4_cancel_tx(struct vt8500_ep *ep) -{ - - unsigned char btmp; - unsigned char bctrl0; - - fiq_using = 0; - - bctrl0 = pDevReg->Bulk3EpControl & 0xE3; - pDevReg->Bulk3DesStatus &= 0xF0; - - ep->stall_more_processing = 0; - - pDevReg->Bulk3DesStatus = 0x00; - pDevReg->Bulk3DesTbytes2 |= - (ep->temp_dcmd >> 16) & 0x3; - pDevReg->Bulk3DesTbytes1 = - (ep->temp_dcmd >> 8) & 0xFF; - pDevReg->Bulk3DesTbytes0 = - ep->temp_dcmd & 0xFF; - - /* set endpoint data toggle*/ - btmp = pDevReg->Bulk3DesTbytes2 & 0x40; - - if (btmp) - ep->toggle_bit = 1; - else - ep->toggle_bit = 0; - - if (ep->toggle_bit) { - /* BULKXFER_DATA1;*/ - pDevReg->Bulk3DesTbytes2 |= 0x40; - } else { - /*(~BULKXFER_DATA1);*/ - pDevReg->Bulk3DesTbytes2 &= 0xBF; - } - - pDevReg->Bulk3DesStatus = - (BULKXFER_IOC | BULKXFER_IN); - - wmb(); - pDevReg->Bulk3EpControl |= EP_DMALIGHTRESET; - wmb(); - while (pDevReg->Bulk3EpControl & EP_DMALIGHTRESET); - pDevReg->Bulk3EpControl = bctrl0; - - wmt_pdma2_reset(); - wmb(); -} - -static int wmt_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct vt8500_ep *ep = container_of(_ep, struct vt8500_ep, ep); - struct vt8500_req *req; - int is_in; -// unsigned long flags; - - if (!_ep || !_req) - return -EINVAL; - - spin_lock_irqsave(&ep->udc->lock, irq_flags); - - DBG("wmt_ep_dequeue() %s\n", ep ? ep->ep.name : NULL); - /* make sure it's actually queued on this endpoint*/ - list_for_each_entry(req, &ep->queue, queue) { - if (&req->req == _req) - break; - } - if (&req->req != _req) { - spin_unlock_irqrestore(&ep->udc->lock, irq_flags); - return -EINVAL; - } - - - if (((ep->bEndpointAddress & 0x7F) != 0) && ep->queue.next == &req->queue) { - - if (ep->bEndpointAddress == 1){ - ep1_cancel_tx(ep); - } - else if (ep->bEndpointAddress == 2){ - ep2_cancel_tx(ep); - } - else if (ep->bEndpointAddress == 3){ - ep3_cancel_tx(ep); - } - else if (ep->bEndpointAddress == 4){ - ep4_cancel_tx(ep); - } - } - - done(ep, req, -ECONNRESET); - - if (!list_empty(&ep->queue)) { - req = container_of(ep->queue.next, struct vt8500_req, queue); - is_in = ep->bEndpointAddress & USB_DIR_IN; - (is_in ? next_in_dma : next_out_dma)(ep, req); - } - - spin_unlock_irqrestore(&ep->udc->lock, irq_flags); - - return 0; -} /*static int wmt_ep_dequeue()*/ - -/*-------------------------------------------------------------------------*/ - -static int wmt_ep_set_halt(struct usb_ep *_ep, int value) -{ - struct vt8500_ep *ep = container_of(_ep, struct vt8500_ep, ep); -// unsigned long flags; - int status = -EOPNOTSUPP; - - spin_lock_irqsave(&ep->udc->lock, irq_flags); - - ep->toggle_bit = 0; /*patch CLEAR_FEATURE ENDPOINT_HALT*/ - DBG("wmt_ep_set_halt() %s\n", ep ? ep->ep.name : NULL); - - if (value) { - u8 temp32bytes[31]; - - memset(temp32bytes, 0, 31); - temp32bytes[0] = 0xEF; - temp32bytes[1] = 0xBE; - temp32bytes[2] = 0xAD; - temp32bytes[3] = 0xDE; - - /*usb_ep_set_halt() - value == 1 stall*/ - - switch ((ep->bEndpointAddress & 0x7F)) { - case 0:/*Control In/Out*/ - pDevReg->ControlEpControl |= EP_STALL; - break; - - case 1:/*Bulk In*/ - pDevReg->Bulk1EpControl |= EP_STALL; - break; - - case 2:/*Bulk Out*/ - pDevReg->Bulk2EpControl |= EP_STALL; - break; - - case 3:/*Interrupt In*/ -#ifdef USE_BULK3_TO_INTERRUPT - pDevReg->Bulk3EpControl |= EP_STALL; -#else - pDevReg->InterruptEpControl |= EP_STALL; -#endif - break; - - case 4:/*Iso In*/ - pDevReg->Bulk3EpControl |= EP_STALL; - break; - } - - ep->stall = 1; - /*DBG("wmt_ep_set_halt(1) HALT CSR(0x%08X)\n", *ep->reg_control_status);*/ - status = 0; - - if (memcmp(temp32bytes, (void *)ep->udc->cbw_virtual_address, 4) == 0) - udc->file_storage_set_halt = 1; /*forbid to CLEAR FEATURE*/ - } else {/*usb_ep_clear_halt - value == 0 reset*/ - - /**ep->reg_control_status &= 0xFFFFFFFB;*/ - switch ((ep->bEndpointAddress & 0x7F)) { - case 0:/*Control In/Out*/ - pDevReg->ControlEpControl &= 0xF7; - break; - - case 1:/*Bulk In*/ - pDevReg->Bulk1EpControl &= 0xF7; - break; - - case 2:/*Bulk Out*/ - pDevReg->Bulk2EpControl &= 0xF7; - break; - - case 3:/*Interrupt In*/ - -#ifdef USE_BULK3_TO_INTERRUPT - pDevReg->Bulk3EpControl &= 0xF7; -#else - pDevReg->InterruptEpControl &= 0xF7; -#endif - break; - - case 4:/*Iso In*/ - pDevReg->Bulk3EpControl &= 0xF7; - break; - } - - ep->stall = 0; - status = 0; - udc->file_storage_set_halt = 0; - } - - VDBG("%s %s halt stat %d\n", ep->ep.name, - value ? "set" : "clear", status); - wmb(); - spin_unlock_irqrestore(&ep->udc->lock, irq_flags); - - return status; -} /*static int wmt_ep_set_halt()*/ - -static struct usb_ep_ops wmt_ep_ops = { - .enable = wmt_ep_enable, - .disable = wmt_ep_disable, - - .alloc_request = wmt_alloc_request, - .free_request = wmt_free_request, - -// .alloc_buffer = wmt_alloc_buffer, -// .free_buffer = wmt_free_buffer, - - .queue = wmt_ep_queue, - .dequeue = wmt_ep_dequeue, - - .set_halt = wmt_ep_set_halt, - - /* fifo_status ... report bytes in fifo*/ - /* fifo_flush ... flush fifo*/ -}; - -#if 0 -static void -wmt_udc_csr(struct vt8500_udc *udc) -{ - /* abolish any previous hardware state*/ - - DBG("wmt_udc_csr()\n"); - - if (udc->gadget.speed == USB_SPEED_FULL) { - wmt_ep_setup_csr("ep1in-bulk", (USB_DIR_IN | 1), USB_ENDPOINT_XFER_BULK, 64); - wmt_ep_setup_csr("ep2out-bulk", (USB_DIR_OUT | 2), USB_ENDPOINT_XFER_BULK, 64); - } else if (udc->gadget.speed == USB_SPEED_HIGH) { - wmt_ep_setup_csr("ep1in-bulk", (USB_DIR_IN | 1), USB_ENDPOINT_XFER_BULK, 512); - wmt_ep_setup_csr("ep2out-bulk", (USB_DIR_OUT | 2), USB_ENDPOINT_XFER_BULK, 512); - } else if (udc->gadget.speed == USB_SPEED_UNKNOWN) { - wmt_ep_setup_csr("ep1in-bulk", (USB_DIR_IN | 1), USB_ENDPOINT_XFER_BULK, 512); - wmt_ep_setup_csr("ep2out-bulk", (USB_DIR_OUT | 2), USB_ENDPOINT_XFER_BULK, 512); - } - //wmt_ep_setup_csr("ep3in""-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 8); -#ifdef USE_BULK3_TO_INTERRUPT - wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 28); -#else - wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 8); -#endif -} /*wmt_udc_csr(void)*/ -#endif - -static int wmt_get_frame(struct usb_gadget *gadget) -{ - DBG("wmt_get_frame()\n"); - return 0; -} - -static int wmt_wakeup(struct usb_gadget *gadget) -{ - /*struct vt8500_udc *udc;*/ - /*unsigned long flags;*/ - int retval = 0; - DBG("wmt_wakeup()\n"); -/* - udc = container_of(gadget, struct vt8500_udc, gadget); - - spin_lock_irqsave(&udc->lock, irq_flags); - if (udc->devstat & UDC_SUS) { - // NOTE: OTG spec erratum says that OTG devices may - // issue wakeups without host enable. - // - if (udc->devstat & (UDC_B_HNP_ENABLE|UDC_R_WK_OK)) { - DBG("remote wakeup...\n"); - UDC_SYSCON2_REG = UDC_RMT_WKP; - retval = 0; - } - - // NOTE: non-OTG systems may use SRP TOO... - } else if (!(udc->devstat & UDC_ATT)) { - if (udc->transceiver) - retval = otg_start_srp(udc->transceiver->otg); - } - spin_unlock_irqrestore(&udc->lock, irq_flags); -*/ - return retval; -} - -static int -wmt_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered) -{ - DBG("wmt_set_selfpowered()\n"); -/* struct vt8500_udc *udc; - unsigned long flags; - u16 syscon1; - - udc = container_of(gadget, struct vt8500_udc, gadget); - spin_lock_irqsave(&udc->lock, irq_flags); - syscon1 = UDC_SYSCON1_REG; - if (is_selfpowered) - syscon1 |= UDC_SELF_PWR; - else - syscon1 &= ~UDC_SELF_PWR; - UDC_SYSCON1_REG = syscon1; - spin_unlock_irqrestore(&udc->lock, irq_flags); -*/ - return 0; -} - - -void reset_ep(void) -{ -#if 1 - wmt_disable_fiq(); - fiq_using = 0; - - pDevReg->Bulk1EpControl = EP_DMALIGHTRESET; - while (pDevReg->Bulk1EpControl & EP_DMALIGHTRESET) - ; - - pDevReg->Bulk2EpControl = EP_DMALIGHTRESET; - while (pDevReg->Bulk2EpControl & EP_DMALIGHTRESET) - ; - - pDevReg->Bulk3EpControl = EP_DMALIGHTRESET; - while (pDevReg->Bulk3EpControl & EP_DMALIGHTRESET) - ; -#else - pDevReg->Bulk1EpControl = 0; /* stop the bulk DMA*/ - while (pDevReg->Bulk1EpControl & EP_ACTIVE) /* wait the DMA stopped*/ - ; - - pDevReg->Bulk2EpControl = 0; /* stop the bulk DMA*/ - while (pDevReg->Bulk2EpControl & EP_ACTIVE) /* wait the DMA stopped*/ - ; - - pDevReg->Bulk3EpControl = 0; /* stop the bulk DMA*/ - while (pDevReg->Bulk3EpControl & EP_ACTIVE) /* wait the DMA stopped*/ - ; -#endif - pDevReg->Bulk1DesStatus = 0x00; - pDevReg->Bulk2DesStatus = 0x00; - pDevReg->Bulk3DesStatus = 0x00; - - pDevReg->Bulk1DesTbytes0 = 0; - pDevReg->Bulk1DesTbytes1 = 0; - pDevReg->Bulk1DesTbytes2 = 0; - - pDevReg->Bulk2DesTbytes0 = 0; - pDevReg->Bulk2DesTbytes1 = 0; - pDevReg->Bulk2DesTbytes2 = 0; - - pDevReg->Bulk3DesTbytes0 = 0; - pDevReg->Bulk3DesTbytes1 = 0; - pDevReg->Bulk3DesTbytes2 = 0; - - /* enable DMA and run the control endpoint*/ - wmb(); - - pDevReg->ControlEpControl = EP_RUN + EP_ENABLEDMA; -#if 0 - /* enable DMA and run the bulk endpoint*/ - pDevReg->Bulk1EpControl = EP_RUN + EP_ENABLEDMA; - pDevReg->Bulk2EpControl = EP_RUN + EP_ENABLEDMA; - -#ifdef USE_BULK3_TO_INTERRUPT - pDevReg->Bulk3EpControl = EP_RUN + EP_ENABLEDMA; -#else - pDevReg->InterruptEpControl = EP_RUN + EP_ENABLEDMA; -#endif -#endif - /* enable DMA and run the interrupt endpoint*/ - /* UsbControlRegister.InterruptEpControl = EP_RUN+EP_ENABLEDMA;*/ - /* run the USB controller*/ - pDevReg->MiscControl3 = 0x3d; - wmb(); - pDevReg->PortControl |= PORTCTRL_SELFPOWER;/* Device port control register - 22*/ - pDevReg->CommandStatus = USBREG_RUNCONTROLLER; - wmb(); - ControlState = CONTROLSTATE_SETUP; - USBState = USBSTATE_DEFAULT; - TestMode = 0; - - /*status = wmt_udc_setup(odev, xceiv);*/ - wmt_ep_setup_csr("ep0", 0, USB_ENDPOINT_XFER_CONTROL, 64); -#if 1 - wmt_ep_setup_csr("ep1in-bulk", (USB_DIR_IN | 1), USB_ENDPOINT_XFER_BULK, 64); - wmt_ep_setup_csr("ep2out-bulk", (USB_DIR_OUT | 2), USB_ENDPOINT_XFER_BULK, 64); -#if 0 -#ifdef USE_BULK3_TO_INTERRUPT - wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 28); -#else - wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 8); -#endif -#endif -#endif -} - -void reset_udc(void) -{ -/* if (!((*(volatile unsigned int *)(PM_CTRL_BASE_ADDR + 0x254))&0x00000080))*/ -/* *(volatile unsigned int *)(PM_CTRL_BASE_ADDR + 0x254) |= 0x00000080;*/ /*DPM needed*/ - -pDevReg->CommandStatus |= USBREG_RESETCONTROLLER; - wmb(); - - if ((*(volatile unsigned char *)(USB_IP_BASE + 0x249))&0x04) { - *(volatile unsigned char*)(USB_IP_BASE + 0x249)&= ~0x04; - mdelay(1); - } - - pUSBMiscControlRegister5 = (unsigned char *)(USB_UDC_REG_BASE + 0x1A0); - *pUSBMiscControlRegister5 = 0x01;/*USB in normal operation*/ - /* reset Bulk descriptor control*/ - wmb(); - - f_ep3_used = 0; - reset_ep(); - - pDevReg->SelfPowerConnect |= 0x10;//Neil - wmb(); - /* enable all interrupt*/ -#ifdef FULL_SPEED_ONLY - pDevReg->IntEnable = (INTENABLE_ALL | INTENABLE_FULLSPEEDONLY) ;/*0x70*/ -#else - pDevReg->IntEnable = INTENABLE_ALL;/*0x70*/ -#endif - wmb(); - /* set IOC on the Setup decscriptor to accept the Setup request*/ - pDevReg->ControlDesControl = CTRLXFER_IOC; -/*Neil_080731*/ -/* pullup_disable here and enable in /arch/arm/kernel/apm.c:395 - apm_ioctl() to patch issue signal fail when resume when recive*/ -/* set_configuration time out.*/ -/* pullup_enable(udc);//usb_gadget_probe_driver()*/ - wmb(); - wmt_pdma_reset(); - -// pullup_enable(udc); -// pDevReg->FunctionPatchEn |= 0x20; /* HW attach process evaluation enable bit*/ -/* pullup_disable(udc);*/ -/*Neil_080731*/ - -} - - -/* -static int can_pullup(struct vt8500_udc *udc) -{ - return udc->driver && udc->softconnect && udc->vbus_active; -} -*/ -static void pullup_disable(struct vt8500_udc *udc) -{ - INFO("pullup_disable()\n"); - /*Hold port control's FSM from enter device mode.*/ - //pDevReg->PhyMisc &= 0x0F; - //pDevReg->PhyMisc |= 0x10; - pDevReg->FunctionPatchEn &= (~0x20); /* HW attach process evaluation enable bit*/ - wmb(); - gadget_connect=0; - - f_ep3_used = 0; - reset_ep(); - wmt_pdma_reset(); - - -} /*static void pullup_disable()*/ - -/* - * Called by whatever detects VBUS sessions: external transceiver - * driver, or maybe GPIO0 VBUS IRQ. May request 48 MHz clock. - */ -static int wmt_vbus_session(struct usb_gadget *gadget, int is_active) -{ - DBG("wmt_vbus_session()\n"); - return 0; -} - -static int wmt_vbus_draw(struct usb_gadget *gadget, unsigned mA) -{ - DBG("wmt_vbus_draw()\n"); - return -EOPNOTSUPP; -} - -static int wmt_pullup(struct usb_gadget *gadget, int is_on) -{ - struct vt8500_udc *udc; -// unsigned long flags; - - DBG("wmt_pullup()\n"); - - udc = container_of(gadget, struct vt8500_udc, gadget); - down(&wmt_udc_sem); - spin_lock_irqsave(&udc->lock, irq_flags); - udc->softconnect = (is_on != 0); -// if (can_pullup(udc)) - - if (udc->softconnect) - pullup_enable(udc); - else { - pullup_disable(udc); - //run_script(action_off_line); - } - spin_unlock_irqrestore(&udc->lock, irq_flags); - up(&wmt_udc_sem); - - return 0; -} - -void get_udc_sem (void) -{ - down(&wmt_udc_sem); -} - -void release_udc_sem (void) -{ - up(&wmt_udc_sem); -} - -static int wmt_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int wmt_udc_stop(struct usb_gadget_driver *driver); - -static struct usb_gadget_ops wmt_gadget_ops = { - .get_frame = wmt_get_frame, - .wakeup = wmt_wakeup, - .set_selfpowered = wmt_set_selfpowered, - .vbus_session = wmt_vbus_session, - .vbus_draw = wmt_vbus_draw, - .pullup = wmt_pullup, - .start = wmt_udc_start, - .stop = wmt_udc_stop, -}; - -/* dequeue ALL requests; caller holds udc->lock */ -static void nuke(struct vt8500_ep *ep, int status) -{ - struct vt8500_req *req; - - DBG("nuke()\n"); - ep->stopped = 1; - - while (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, struct vt8500_req, queue); - done(ep, req, status); - } -} /*void nuke()*/ - -/* caller holds udc->lock */ -static void udc_quiesce(struct vt8500_udc *udc) -{ - struct vt8500_ep *ep; - DBG("udc_quiesce()\n"); - - udc->gadget.speed = USB_SPEED_UNKNOWN; - nuke(&udc->ep[0], -ESHUTDOWN); - list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) - nuke(ep, -ESHUTDOWN); -} /*void udc_quiesce()*/ - -/* -static void update_otg(struct vt8500_udc *udc) -{ - u16 devstat; - - if (!udc->gadget.is_otg) - return; - - if (OTG_CTRL_REG & OTG_ID) - devstat = UDC_DEVSTAT_REG; - else - devstat = 0; - - udc->gadget.b_hnp_enable = !!(devstat & UDC_B_HNP_ENABLE); - udc->gadget.a_hnp_support = !!(devstat & UDC_A_HNP_SUPPORT); - udc->gadget.a_alt_hnp_support = !!(devstat & UDC_A_ALT_HNP_SUPPORT); - - // Enable HNP early, avoiding races on suspend irq path. - // ASSUMES OTG state machine B_BUS_REQ input is true. - // - if (udc->gadget.b_hnp_enable) - OTG_CTRL_REG = (OTG_CTRL_REG | OTG_B_HNPEN | OTG_B_BUSREQ) - & ~OTG_PULLUP; - -}//static void update_otg() -*/ - - -/* define the prepare result codes*/ -#define RESPOK 0 -#define RESPFAIL 1 -u16 Control_Length; /* the length of transfer for current control transfer*/ -u16 Configure_Length; - - -/*UDC_IS_SETUP_INT*/ -static void udc_control_prepare_data_resp(void)/*(struct vt8500_udc *udc, u32 udc_irq_src)*/ -{ - struct vt8500_ep *ep0 = &udc->ep[0]; - struct vt8500_req *req = 0; - /*UCHAR Result = RESPFAIL;*/ - /*unsigned char CurXferLength = 0;*/ - /*unsigned char Control_Length = 0;*/ - int i; - u8 test_mode_enable = 0; - - Configure_Length = 0; - - /*ep0->irqs++;*/ - DBG("ep0_irq()\n"); - ep0->toggle_bit = 1; - - if (!list_empty(&ep0->queue)) - req = container_of(ep0->queue.next, struct vt8500_req, queue); - - /* SETUP starts all control transfers*/ - { - union u { - u8 bytes[8]; - struct usb_ctrlrequest r; - } u; - int status = -EINVAL; - struct vt8500_ep *ep = &udc->ep[0]; - int ep0_status_phase_0_byte = 0; - - nuke(ep0, 0); - /* read the (latest) SETUP message*/ - for (i = 0; i <= 7; i++) - u.bytes[i] = pSetupCommandBuf[i]; - - le32_to_cpus(&u.r.wValue); - le32_to_cpus(&u.r.wIndex); - le32_to_cpus(&u.r.wLength); - - /* Delegate almost all control requests to the gadget driver,*/ - /* except for a handful of ch9 status/feature requests that*/ - /* hardware doesn't autodecode _and_ the gadget API hides.*/ - /**/ - udc->ep0_in = (u.r.bRequestType & USB_DIR_IN) != 0; - udc->ep0_set_config = 0; - udc->ep0_pending = 1; - udc->ep0_in_status = 0; - - ep0->stopped = 0; - ep0->ackwait = 0; - - if ((u.r.bRequestType & USB_RECIP_OTHER) == USB_RECIP_OTHER) {/*USB_RECIP_OTHER(0x03)*/ - status = 0; - - /*INFO("ep0_irq() setup command[0]=(0x%08X)\n",u.dword[0]);*/ - /*INFO("ep0_irq() setup command[1]=(0x%08X)\n",u.dword[1]);*/ - /*INFO("ep0_irq() address(%08X)", udc_reg->AddressControl);*/ - goto delegate; - } - - switch (u.r.bRequest) { - case USB_REQ_SET_CONFIGURATION: - /* udc needs to know when ep != 0 is valid*/ - /*SETUP 00.09 v0001 i0000 l0000*/ - if (u.r.bRequestType != USB_RECIP_DEVICE)/*USB_RECIP_DEVICE(0x00)*/ - goto delegate; - if (u.r.wLength != 0) - goto do_stall; - udc->ep0_set_config = 1; - udc->ep0_reset_config = (u.r.wValue == 0); - VDBG("set config %d\n", u.r.wValue); - - if (u.r.wValue == 0) - USBState = USBSTATE_ADDRESS; - else - USBState = USBSTATE_CONFIGED; - /* update udc NOW since gadget driver may start*/ - /* queueing requests immediately; clear config*/ - /* later if it fails the request.*/ - /**/ - - udc->ep[0].toggle_bit = 0; - udc->ep[1].toggle_bit = 0; - udc->ep[2].toggle_bit = 0; - udc->ep[3].toggle_bit = 0; - udc->ep[4].toggle_bit = 0; - udc->ep[5].toggle_bit = 0;//gri - udc->ep[6].toggle_bit = 0;//gri - - - status = 0; - goto delegate; - - /* Giga Hsu : 2007.6.6 This would cause set interface status 0 - return to fast and cause bulk endpoint in out error*/ - case USB_REQ_SET_INTERFACE: - - VDBG("set interface %d\n", u.r.wValue); - status = 0; - - udc->ep[0].toggle_bit = 0; - udc->ep[1].toggle_bit = 0; - udc->ep[2].toggle_bit = 0; - udc->ep[3].toggle_bit = 0; - udc->ep[4].toggle_bit = 0; - udc->ep[5].toggle_bit = 0;//gri - udc->ep[6].toggle_bit = 0;//gri - - goto delegate; - /*break;*/ - - case USB_REQ_CLEAR_FEATURE: - /* clear endpoint halt*/ - - if (u.r.bRequestType != USB_RECIP_ENDPOINT) - goto delegate; - - if (u.r.wValue != USB_ENDPOINT_HALT - || u.r.wLength != 0) - goto do_stall; - - ep = &udc->ep[u.r.wIndex & 0xf]; - - if (ep != ep0) { - if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC || !ep->desc) - goto do_stall; - - if (udc->file_storage_set_halt == 0) { - switch ((ep->bEndpointAddress & 0x7F)) { - case 0:/*Control In/Out*/ - pDevReg->ControlEpControl &= 0xF7; - break; - - case 1:/*Bulk In*/ - - pDevReg->Bulk1EpControl &= 0xF7; - #ifdef MSC_COMPLIANCE_TEST - udc_bulk_dma_dump_register(); - udc_device_dump_register(); - #endif - if (ep->stall_more_processing == 1) { - u32 dma_ccr = 0; - - ep->stall_more_processing = 0; - wmt_pdma0_reset(); - wmt_udc_pdma_des_prepare(ep->temp_dcmd, - ep->temp_bulk_dma_addr, - DESCRIPTOT_TYPE_LONG, TRANS_IN, 1); - - pDevReg->Bulk1DesStatus = 0x00; - pDevReg->Bulk1DesTbytes2 |= - (ep->temp_dcmd >> 16) & 0x3; - pDevReg->Bulk1DesTbytes1 = - (ep->temp_dcmd >> 8) & 0xFF; - pDevReg->Bulk1DesTbytes0 = - ep->temp_dcmd & 0xFF; - - /* set endpoint data toggle*/ - if (ep->ep_stall_toggle_bit) { - /* BULKXFER_DATA1;*/ - pDevReg->Bulk1DesTbytes2 |= 0x40; - } else { - /*(~BULKXFER_DATA1);*/ - pDevReg->Bulk1DesTbytes2 &= 0xBF; - } - - pDevReg->Bulk1DesStatus = - (BULKXFER_IOC | BULKXFER_IN); - - /* DMA Channel Control Reg*/ - /* Software Request + Channel Enable*/ - dma_ccr = 0; - dma_ccr = DMA_RUN; - wmb(); - pUdcDmaReg->DMA_Context_Control0 = dma_ccr; //neil - wmb(); - pDevReg->Bulk1DesStatus |= BULKXFER_ACTIVE; - } - break; - - case 2:/*Bulk Out*/ - pDevReg->Bulk2EpControl &= 0xF7; - - if (ep->stall_more_processing == 1) { - u32 dma_ccr = 0; - ep->stall_more_processing = 0; - wmt_pdma1_reset(); - // wmt_pdma_reset(); - wmt_udc_pdma_des_prepare(ep->temp_dcmd, - ep->temp_bulk_dma_addr, - DESCRIPTOT_TYPE_LONG, TRANS_OUT, 1); - /* DMA Global Controller Reg*/ - /* DMA Controller Enable +*/ - /* DMA Global Interrupt Enable(if any TC, error, - or abort status in any channels occurs)*/ - - pDevReg->Bulk2DesStatus = 0x00; - pDevReg->Bulk2DesTbytes2 |= - (ep->temp_dcmd >> 16) & 0x3; - pDevReg->Bulk2DesTbytes1 = - (ep->temp_dcmd >> 8) & 0xFF; - pDevReg->Bulk2DesTbytes0 = - ep->temp_dcmd & 0xFF; - - if (ep->ep_stall_toggle_bit) - pDevReg->Bulk2DesTbytes2 |= BULKXFER_DATA1; - else - pDevReg->Bulk2DesTbytes2 &= 0x3F; - - pDevReg->Bulk2DesStatus = BULKXFER_IOC; - - /* DMA Channel Control Reg*/ - /* Software Request + Channel Enable*/ - - /*udc_bulk_dma_dump_register();*/ - dma_ccr = 0; - dma_ccr = DMA_RUN; - dma_ccr |= DMA_TRANS_OUT_DIR; - wmb(); - pUdcDmaReg->DMA_Context_Control1 = dma_ccr; - wmb(); - pDevReg->Bulk2DesStatus |= BULKXFER_ACTIVE; - } - break; - - case 3:/*Interrupt In*/ -#ifdef USE_BULK3_TO_INTERRUPT -/*Bulk In*/ - - pDevReg->Bulk3EpControl &= 0xF7; - #ifdef MSC_COMPLIANCE_TEST - udc_bulk_dma_dump_register(); - udc_device_dump_register(); - #endif - if (ep->stall_more_processing == 1) { - u32 dma_ccr = 0; - - ep->stall_more_processing = 0; - wmt_pdma2_reset(); - wmt_udc_pdma_des_prepare(ep->temp_dcmd, - ep->temp_bulk_dma_addr, - DESCRIPTOT_TYPE_LONG, TRANS_IN, 0); - - pDevReg->Bulk3DesStatus = 0x00; - pDevReg->Bulk3DesTbytes2 |= - (ep->temp_dcmd >> 16) & 0x3; - pDevReg->Bulk3DesTbytes1 = - (ep->temp_dcmd >> 8) & 0xFF; - pDevReg->Bulk3DesTbytes0 = - ep->temp_dcmd & 0xFF; - - /* set endpoint data toggle*/ - if (ep->ep_stall_toggle_bit) { - /* BULKXFER_DATA1;*/ - pDevReg->Bulk3DesTbytes2 |= 0x40; - } else { - /*(~BULKXFER_DATA1);*/ - pDevReg->Bulk3DesTbytes2 &= 0xBF; - } - - pDevReg->Bulk3DesStatus = - (BULKXFER_IOC | BULKXFER_IN); - - /* DMA Channel Control Reg*/ - /* Software Request + Channel Enable*/ - dma_ccr = 0; - dma_ccr = DMA_RUN; - wmb(); - pUdcDmaReg->DMA_Context_Control2 = dma_ccr; //neil - wmb(); - pDevReg->Bulk3DesStatus |= BULKXFER_ACTIVE; - } - -#else -/*Interrupt In*/ - pDevReg->InterruptEpControl &= 0xF7; -#endif - break; - - case 4:/*Iso In*/ - - pDevReg->Bulk3EpControl &= 0xF7; - #ifdef MSC_COMPLIANCE_TEST - udc_bulk_dma_dump_register(); - udc_device_dump_register(); - #endif - if (ep->stall_more_processing == 1) { - u32 dma_ccr = 0; - - ep->stall_more_processing = 0; - wmt_pdma2_reset(); - wmt_udc_pdma_des_prepare(ep->temp_dcmd, - ep->temp_bulk_dma_addr, - DESCRIPTOT_TYPE_LONG, TRANS_IN, 0); - - pDevReg->Bulk3DesStatus = 0x00; - pDevReg->Bulk3DesTbytes2 |= - (ep->temp_dcmd >> 16) & 0x3; - pDevReg->Bulk3DesTbytes1 = - (ep->temp_dcmd >> 8) & 0xFF; - pDevReg->Bulk3DesTbytes0 = - ep->temp_dcmd & 0xFF; - - /* set endpoint data toggle*/ - if (ep->ep_stall_toggle_bit) { - /* BULKXFER_DATA1;*/ - pDevReg->Bulk3DesTbytes2 |= 0x40; - } else { - /*(~BULKXFER_DATA1);*/ - pDevReg->Bulk3DesTbytes2 &= 0xBF; - } - - pDevReg->Bulk3DesStatus = - (BULKXFER_IOC | BULKXFER_IN); - - /* DMA Channel Control Reg*/ - /* Software Request + Channel Enable*/ - dma_ccr = 0; - dma_ccr = DMA_RUN; - wmb(); - pUdcDmaReg->DMA_Context_Control2 = dma_ccr; //neil - wmb(); - pDevReg->Bulk3DesStatus |= BULKXFER_ACTIVE; - } - - break; - - } - - ep->stall = 0; - ep->stopped = 0; - /**ep->reg_irp_descriptor = ep->temp_irp_descriptor;*/ - } - } /*if (ep != ep0)*/ - - ep0_status_phase_0_byte = 1; - VDBG("%s halt cleared by host\n", ep->name); - /*goto ep0out_status_stage;*/ - status = 0; - udc->ep0_pending = 0; - /*break;*/ - goto delegate; - - case USB_REQ_SET_FEATURE: - /* set endpoint halt*/ - - if ((u.r.wValue == USB_DEVICE_TEST_MODE)) {/*(USBState == USBSTATE_DEFAULT) &&*/ - TestMode = (UCHAR)(u.r.wIndex >> 8); - test_mode_enable = 1; - INFO("USB_REQ_SET_FEATURE - TestMode (0x%02X)\n", TestMode); - - /*ControlState = CONTROLSTATE_STATUS;*/ - ep0_status_phase_0_byte = 1; - status = 0; - break; - } - - if (u.r.bRequestType != USB_RECIP_ENDPOINT) - goto delegate; - - if (u.r.wValue != USB_ENDPOINT_HALT || u.r.wLength != 0) - goto do_stall; - - ep = &udc->ep[u.r.wIndex & 0xf]; - - if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC || ep == ep0 || !ep->desc) - goto do_stall; - - wmb(); - switch ((ep->bEndpointAddress & 0x7F)) { - case 0:/*Control In/Out*/ - pDevReg->ControlEpControl |= EP_STALL; - break; - - case 1:/*Bulk In*/ - pDevReg->Bulk1EpControl |= EP_STALL; - break; - - case 2:/*Bulk Out*/ - pDevReg->Bulk2EpControl |= EP_STALL; - break; - - case 3: -#ifdef USE_BULK3_TO_INTERRUPT - /*Bulk Out*/ - pDevReg->Bulk3EpControl |= EP_STALL; -#else - /*Interrupt In*/ - pDevReg->InterruptEpControl |= EP_STALL; -#endif - break; - - case 4: - /*Bulk Out*/ - pDevReg->Bulk3EpControl |= EP_STALL; - break; - } - wmb(); - ep->stall = 1; - ep->stopped = 1; - - ep0_status_phase_0_byte = 1; - /*use_ep(ep, 0);*/ - /* can't halt if fifo isn't empty...*/ - /*UDC_CTRL_REG = UDC_CLR_EP;*/ - /*UDC_CTRL_REG = UDC_SET_HALT;*/ - VDBG("%s halted by host\n", ep->name); - /*ep0out_status_stage:*/ - status = 0; - - udc->ep0_pending = 0; - /*break;*/ - goto delegate; - - case USB_REQ_GET_STATUS: - /* return interface status. if we were pedantic,*/ - /* we'd detect non-existent interfaces, and stall.*/ - /**/ - - if (u.r.bRequestType == (USB_DIR_IN|USB_RECIP_ENDPOINT)) { - ep = &udc->ep[u.r.wIndex & 0xf]; - - if (ep->stall == 1) { - udc->ep0_in_status = 0x01; - - /*GgiaHsu-B 2007.08.10 : patch HW Bug : - MSC Compliance Test : Error Recovery Items.*/ - ep = &udc->ep[3]; - if ((udc->file_storage_set_halt == 1) && (ep->stall == 1)) - ep->stall = 1; - /*GgiaHsu-E 2007.08.10 : - --------------------------------------------*/ - - ep = &udc->ep[0]; - ep->stall = 0; - } else - udc->ep0_in_status = 0x00; - - VDBG("GET_STATUS, interface wIndex(0x%02X) ep0_in_status(0x%04X)\n" - , u.r.wIndex, udc->ep0_in_status); - } else - udc->ep0_in_status = 0x00; - - /* return two zero bytes*/ - status = 0; - - /* next, status stage*/ - goto delegate; - break; - - case USB_REQ_SET_ADDRESS: - if (u.r.bRequestType == USB_RECIP_DEVICE) { /*USB_RECIP_DEVICE(0x00)*/ - if (USBState == USBSTATE_DEFAULT) { - if (u.r.wValue != 0) - USBState = USBSTATE_ADDRESS; - } else if (USBState == USBSTATE_ADDRESS) { - if (u.r.wValue == 0) - USBState = USBSTATE_DEFAULT; - } - - pDevReg->DeviceAddr |= (DEVADDR_ADDRCHANGE | u.r.wValue); - VDBG("USB_REQ_SET_ADDRESS 0x%03d\n", u.r.wValue); - ControlState = CONTROLSTATE_STATUS; - ep0_status_phase_0_byte = 1; - status = 0; - } - break; - - case USB_BULK_RESET_REQUEST: - - VDBG("USB_BULK_RESET_REQUEST\n"); - udc->file_storage_set_halt = 0; - - udc->ep[0].toggle_bit = 0; - udc->ep[1].toggle_bit = 0; - udc->ep[2].toggle_bit = 0; - udc->ep[3].toggle_bit = 0; - udc->ep[4].toggle_bit = 0; - udc->ep[5].toggle_bit = 0;//gri - udc->ep[6].toggle_bit = 0;//gri - - status = 0; - - goto delegate; - /*break;*/ - - default: -delegate: - VDBG("SETUP %02x.%02x v%04x i%04x l%04x\n", - u.r.bRequestType, u.r.bRequest, - u.r.wValue, u.r.wIndex, u.r.wLength); - /* - // The gadget driver may return an error here, - // causing an immediate protocol stall. - // - // Else it must issue a response, either queueing a - // response buffer for the DATA stage, or halting ep0 - // (causing a protocol stall, not a real halt). A - // zero length buffer means no DATA stage. - // - // It's fine to issue that response after the setup() - // call returns, and this IRQ was handled. - // - */ - udc->ep0_setup = 1; - - spin_unlock_irqrestore(&udc->lock, irq_flags); - /*usb gadget driver prepare setup data phase(control in)*/ - status = udc->driver->setup(&udc->gadget, &u.r); /*usb_gadget_driver->setup()*/ - spin_lock_irqsave(&udc->lock, irq_flags); - udc->ep0_setup = 0; - } /*switch (u.r.bRequest)*/ - - if (ep0_status_phase_0_byte == 1) {/* && (udc->ep[0].stall==0))*/ - udc->ep0_status_0_byte = 1; - if (test_mode_enable == 1) - ep0_status(udc); - } - - if (status < 0) { -do_stall: - /* ep = &udc->ep[0];*/ - /**ep->reg_control_status |= UDC_EP0_STALL;*/ - /* fail in the command parsing*/ - pDevReg->ControlEpControl |= EP_STALL; /* stall the pipe*/ - wmb(); - ControlState = CONTROLSTATE_SETUP; /* go back to setup state*/ - - ep->stall = 1; - DBG("Setup Command STALL : req %02x.%02x protocol STALL; stat %d\n", - u.r.bRequestType, u.r.bRequest, status); - - udc->ep0_pending = 0; - } /*if (status < 0)*/ - } /*if (udc_irq_src & UDC_IS_SETUP_INT)*/ -} /*udc_control_prepare_data_resp()*/ - -#define OTG_FLAGS (UDC_B_HNP_ENABLE|UDC_A_HNP_SUPPORT|UDC_A_ALT_HNP_SUPPORT) - -static void devstate_irq(struct vt8500_udc *udc, u32 port0_status) -{ - udc->usb_connect = 0; - - if (pDevReg->IntEnable & INTENABLE_DEVICERESET) { - /*vt3357 hw issue : clear all device register.*/ - /*payload & address needs re-set again...*/ - pDevReg->IntEnable |= INTENABLE_SUSPENDDETECT; - VDBG("devstate_irq() - Global Reset...\n"); -//printk("[devstate_irq]0xd8009834 = 0x%8.8x\n",*(volatile unsigned int *)(USB_IP_BASE+0x2034)); - - if (udc->driver) { - udc->gadget.speed = USB_SPEED_UNKNOWN; -// ppudc = udc; -// run_script(action_off_line); -// udc->driver->disconnect(&udc->gadget); - } - - udc->ep0_set_config = 0; - pDevReg->Bulk1DesStatus = 0; - - udc->ep[0].toggle_bit = 0; - udc->ep[1].toggle_bit = 0; - udc->ep[2].toggle_bit = 0; - udc->ep[3].toggle_bit = 0; - udc->ep[4].toggle_bit = 0; - udc->ep[5].toggle_bit = 0;//gri - udc->ep[6].toggle_bit = 0;//gri - - - udc->ep[0].rndis = 0; - udc->ep[1].rndis = 0; - udc->ep[2].rndis = 0; - udc->ep[3].rndis = 0; - udc->ep[4].rndis = 0; - udc->ep[5].rndis = 0;//gri - udc->ep[6].rndis = 0;//gri - - udc->file_storage_set_halt = 0; - udc->bulk_out_dma_write_error = 0; - - udc->gadget.speed = USB_SPEED_UNKNOWN; - wmt_pdma_reset(); - - gadget_connect=0; - /*vt8500_usb_device_reg_dump();*/ - - } /*if (pDevReg->IntEnable & INTENABLE_DEVICERESET)*/ - - if (pDevReg->IntEnable & INTENABLE_SUSPENDDETECT) { - VDBG("devstate_irq() - Global Suspend...\n"); - pDevReg->IntEnable |= INTENABLE_SUSPENDDETECT; - - - - } /*if (pDevReg->IntEnable & INTENABLE_SUSPENDDETECT)*/ - - if (pDevReg->IntEnable & INTENABLE_RESUMEDETECT) { - pDevReg->IntEnable |= INTENABLE_RESUMEDETECT; - VDBG("devstate_irq() - Global Resume...\n"); - - } /*if (pDevReg->IntEnable & INTENABLE_RESUMEDETECT)*/ - -/*#ifdef UDC_A1_SELF_POWER_ENABLE*/ - /* USB Bus Connection Change*/ - /* clear connection change event*/ - if (pDevReg->PortControl & PORTCTRL_SELFPOWER)/* Device port control register - 22)*/ - if (pDevReg->PortControl & PORTCTRL_CONNECTCHANGE)/* Device port control register - 22)*/ - pDevReg->PortControl |= PORTCTRL_CONNECTCHANGE;/* 0x02 // connection change bit*/ - -/*#endif*/ - - if (pDevReg->PortControl & PORTCTRL_FULLSPEEDMODE) { - udc->gadget.speed = USB_SPEED_FULL; - udc->usb_connect = 1; - /*2007-8.27 GigaHsu : enable float, reset, suspend and resume IE*/ - /*after host controller connected.*/ - VDBG("devstate_irq() - full speed host connect...\n"); - } /*if(pDevReg->PortControl & PORTCTRL_FULLSPEEDMODE)*/ - - if (pDevReg->PortControl & PORTCTRL_HIGHSPEEDMODE) { - udc->gadget.speed = USB_SPEED_HIGH; - udc->usb_connect = 1; - /*2007-8.27 GigaHsu : enable float, reset, suspend and resume IE*/ - /*after host controller connected.*/ - VDBG("devstate_irq() - high speed host connect...\n"); - } /*if(pDevReg->PortControl & PORTCTRL_HIGHSPEEDMODE)*/ - -} /*static void devstate_irq()*/ - -void USB_ControlXferComplete(void) -{ - struct vt8500_ep *ep; - struct vt8500_req *req; - - ep = &udc->ep[0]; - /* when ever a setup received, the Control state will reset*/ - /* check for the valid bit of the contol descriptor*/ - /*DBG("USB_ControlXferComplete()\n");*/ - if (pDevReg->ControlDesControl & CTRLXFER_CMDVALID) { - ep->toggle_bit = 1; - if (udc->usb_connect == 0) { - if (pDevReg->PortControl & PORTCTRL_FULLSPEEDMODE) { - udc->gadget.speed = USB_SPEED_FULL; - udc->usb_connect = 1; - udc->gadget.max_speed = USB_SPEED_HIGH; - /*2007-8.27 GigaHsu : enable float, reset, suspend and resume IE*/ - /*after host controller connected.*/ - //wmt_udc_csr(udc); - VDBG("devstate_irq() - full speed host connect...\n"); - USBState = USBSTATE_DEFAULT; - } /*if(pDevReg->PortControl & PORTCTRL_FULLSPEEDMODE)*/ - - if (pDevReg->PortControl & PORTCTRL_HIGHSPEEDMODE) { - udc->gadget.speed = USB_SPEED_HIGH; - udc->usb_connect = 1; - udc->gadget.max_speed = USB_SPEED_HIGH; - /*2007-8.27 GigaHsu : enable float, reset, suspend and resume IE*/ - /*after host controller connected.*/ - //wmt_udc_csr(udc); - VDBG("devstate_irq() - high speed host connect...\n"); - USBState = USBSTATE_DEFAULT; - } /*if(pDevReg->PortControl & PORTCTRL_HIGHSPEEDMODE)*/ - } - /* HP11_Begin*/ - /* clear the command valid bit*/ - /* pDevReg->ControlDesControl |= CTRLXFER_CMDVALID;*/ - /* always clear control stall when SETUP received*/ - pDevReg->ControlEpControl &= 0x17; /* clear the stall*/ - wmb(); - ControlState = CONTROLSTATE_DATA; - udc_control_prepare_data_resp(); /*processing SETUP command ...*/ - pDevReg->ControlDesControl &= 0xEF;/*(~CTRLXFER_CMDVALID);*/ - wmb(); - /*HP11_End*/ - return; - } - - if (udc->ep0_in) { - /* IN dma: tx to host*/ - if (!list_empty(&ep->queue)) { /* >64 bytes for prepare DATA*/ - req = container_of(ep->queue.next, struct vt8500_req, queue); - VDBG("dma_irq : finish_in_dma() EP0 %s\n", ep ? ep->ep.name : NULL); - finish_in_dma(ep, req, 0); - } - - while (pDevReg->ControlEpControl & EP_COMPLETEINT) /* clear the event*/ - ; - if (!list_empty(&ep->queue)) { /* >64 bytes for prepare DATA*/ - req = container_of(ep->queue.next, struct vt8500_req, queue); - VDBG("dma_irq : next_in_dma() EP0 %s\n", ep ? ep->ep.name : NULL); - next_in_dma(ep, req); - } - } else {/*ep0 out*/ - /* OUT dma: rx from host*/ - if (!list_empty(&ep->queue)) { - req = container_of(ep->queue.next, struct vt8500_req, queue); - finish_out_dma(ep, req, 0); - } - - while (pDevReg->ControlEpControl & EP_COMPLETEINT) /* clear the event*/ - ; - if (!list_empty(&ep->queue)) { /* >64 bytes for prepare DATA*/ - req = container_of(ep->queue.next, struct vt8500_req, queue); - next_out_dma(ep, req); - } - } - -} /*void USB_ControlXferComplete(void)*/ -static irqreturn_t -wmt_udc_dma_irq(int irq, void *_udc)//, struct pt_regs *r) -{ - irqreturn_t status = IRQ_NONE; - u32 bulk_dma_csr; - - bulk_dma_csr = pUdcDmaReg->DMA_ISR; - /*printk("[udc_dma_isr]dma int_sts = 0x%8.8x\n",pUdcDmaReg->DMA_ISR);*/ - - if (bulk_dma_csr & DMA_INTERRUPT_STATUS0) { - /* printk("[udc_dma_isr]channel0 event = 0x%8.8x\n",pUdcDmaReg->DMA_Context_Control0);*/ - pUdcDmaReg->DMA_ISR = DMA_INTERRUPT_STATUS0; - status = IRQ_HANDLED; - } - - if (bulk_dma_csr & DMA_INTERRUPT_STATUS1) { - /* printk("[udc_dma_isr]channel1 event = 0x%8.8x\n",pUdcDmaReg->DMA_Context_Control1);*/ - pUdcDmaReg->DMA_ISR = DMA_INTERRUPT_STATUS1; - status = IRQ_HANDLED; - } - - if (bulk_dma_csr & DMA_INTERRUPT_STATUS2) { - /* printk("[udc_dma_isr]channel2 event = 0x%8.8x\n",pUdcDmaReg->DMA_Context_Control2);*/ - pUdcDmaReg->DMA_ISR = DMA_INTERRUPT_STATUS2; - //printk("iso dma hit\n"); - dma_irq(0x84); - status = IRQ_HANDLED; - } - return status; -} - -static irqreturn_t -wmt_udc_irq(int irq, void *_udc)//, struct pt_regs *r) -{ - struct vt8500_udc *udc = _udc; - u32 udc_irq_src; - irqreturn_t status = IRQ_NONE; -// unsigned long flags; -#ifdef OTGIP - u32 global_irq_src; -#endif - /*u32 i;*/ - - spin_lock_irqsave(&udc->lock, irq_flags); - - DBG("wmt_udc_irq()\n"); - -#ifdef OTGIP - /*Global Interrupt Status*/ - global_irq_src = pGlobalReg->UHDC_Interrupt_Status; - - if (global_irq_src & UHDC_INT_UDC) {/*UDC Core + UDC DMA1 + UDC DMA2 */ - if (global_irq_src & UHDC_INT_UDC_CORE) {/*UDC Core*/ -#endif - /*connection interrupt*/ - if (pDevReg->SelfPowerConnect & 0x02) { - //struct usb_gadget_driver *driver = udc->driver; - - if (pDevReg->SelfPowerConnect & 0x01) //connect - { -// wmt_pdma_reset(); -reset_udc(); -//pullup_enable(udc); - } - else {//disconnct -// spin_unlock_irqrestore(&udc->lock, irq_flags); -// if (udc->driver) -// udc->driver->disconnect(&udc->gadget); -// ppudc = udc; - printk(KERN_INFO "disconnect 1\n"); //gri - run_script(action_off_line); - gadget_connect=0; - -// pullup_disable(udc); - - } - - status = IRQ_HANDLED; - pDevReg->SelfPowerConnect |= 0x02; - } - wmb(); - /* Device Global Interrupt Pending Status*/ - udc_irq_src = pDevReg->CommandStatus; - - /* Device state change (usb ch9 stuff)*/ - if (udc_irq_src & USBREG_BUSACTINT) {/* the bus activity interrupt occured*/ - /*caused by Port 0 Statsu Change*/ - devstate_irq(_udc, udc_irq_src); - status = IRQ_HANDLED; - pDevReg->CommandStatus |= USBREG_BUSACTINT; - wmb(); - } - - if (udc_irq_src & USBREG_BABBLEINT) {/* the Babble interrupt ocuured*/ - /* check for Control endpoint for BABBLE error*/ - if (pDevReg->ControlEpControl & EP_BABBLE) { - /* the Control endpoint is encounted the babble error*/ - /* stall the endpoint and clear the babble condition*/ - pDevReg->ControlEpControl |= (EP_BABBLE + EP_STALL); - INFO("vt8430_udc_irq() - EP0 Babble Detect!\n"); - udc->ep[0].stopped = 1; - udc->ep[0].stall = 1; - } - - if (pDevReg->Bulk1EpControl & EP_BABBLE) { - /* the Bulk endpoint is encounted the babble error*/ - /* stall the endpoint and clear the babble condition*/ - pDevReg->Bulk1EpControl |= (EP_BABBLE + EP_STALL); - INFO("vt8430_udc_irq() - EP1 Babble Detect!\n"); - udc->ep[1].stopped = 1; - udc->ep[1].stall = 1; - } - - if (pDevReg->Bulk2EpControl & EP_BABBLE) { - /* the Bulk endpoint is encounted the babble error*/ - /* stall the endpoint and clear the babble condition*/ - pDevReg->Bulk2EpControl |= (EP_BABBLE + EP_STALL); - INFO("vt8430_udc_irq() - EP2 Babble Detect!\n"); - udc->ep[2].stopped = 1; - udc->ep[2].stall = 1; - } - - if (pDevReg->Bulk3EpControl & EP_BABBLE) { - /* the Bulk endpoint is encounted the babble error*/ - /* stall the endpoint and clear the babble condition*/ - pDevReg->Bulk3EpControl |= (EP_BABBLE + EP_STALL); - INFO("vt8430_udc_irq() - EP3 Babble Detect!\n"); - udc->ep[3].stopped = 1; - udc->ep[3].stall = 1; - } - wmb(); - status = IRQ_HANDLED; - } - - if (udc_irq_src & USBREG_COMPLETEINT) {/* the complete inerrupt occured*/ - if (pDevReg->ControlEpControl & EP_COMPLETEINT) { - /* the control transfer complete event*/ - pDevReg->ControlEpControl |= EP_COMPLETEINT; /* clear the event*/ - wmb(); - USB_ControlXferComplete(); -#if 0 - gadget_connect=1; -#endif - - } - - if (pDevReg->Bulk1EpControl & EP_COMPLETEINT) { - /* the bulk transfer complete event*/ - pDevReg->Bulk1EpControl |= EP_COMPLETEINT; - wmb(); - /*DBG("USB_Bulk 1 DMA()\n");*/ - dma_irq(0x81); -#if 1 - gadget_connect=1; -#endif - } - - if (pDevReg->Bulk2EpControl & EP_COMPLETEINT) { - /* the bulk transfer complete event*/ - pDevReg->Bulk2EpControl |= EP_COMPLETEINT; - wmb(); - /*DBG("USB_Bulk 2 DMA()\n");*/ - dma_irq(2); -#if 1 - gadget_connect=1; -#endif - } - -#ifdef USE_BULK3_TO_INTERRUPT - if (pDevReg->Bulk3EpControl & EP_COMPLETEINT) { - /* the bulk transfer complete event*/ - pDevReg->Bulk3EpControl |= EP_COMPLETEINT; - wmb(); - /*DBG("USB_Bulk 3 DMA()\n");*/ - dma_irq(0x83); -#if 1 - gadget_connect=1; -#endif - } -#else - if (pDevReg->InterruptEpControl & EP_COMPLETEINT) { - /* the bulk transfer complete event*/ - pDevReg->InterruptEpControl |= EP_COMPLETEINT; - /*DBG("USB_INT 3 DMA()\n");*/ - if (f_ep3_used == 3) - dma_irq(0x83); -#if 1 - gadget_connect=1; -#endif - } -#endif - status = IRQ_HANDLED; - } - - if (udc->ep0_status_0_byte == 1)/* && (udc_ep[0].stall==0))*/ - ep0_status(udc); - - if (ControlState == CONTROLSTATE_STATUS) { - /* checking for test mode*/ - if (TestMode != 0x00) { -#if 0 - pDevReg->CommandStatus &= 0x1F; - wmb(); - pDevReg->CommandStatus |= USBREG_RESETCONTROLLER; - while (pDevReg->CommandStatus & USBREG_RESETCONTROLLER) - ; - /* HW attach process evaluation enable bit*/ -#if 0 - pDevReg->FunctionPatchEn |= 0x20; - /* Device port control register - 22*/ - pDevReg->PortControl |= PORTCTRL_SELFPOWER; - wmb(); -#else - pullup_enable(udc); - pDevReg->FunctionPatchEn |= 0x20; /* HW attach process evaluation enable bit*/ - wmb(); - //msleep(1000); -#endif -#endif - wmb(); - udelay(1000); - /*GigaHsu 2008.1.26 : Don't set RUN bit while TestMode enable*/ - /* setting the test mode*/ - switch (TestMode) { - case UDC_TEST_MODE_NOT_ENABLED:/*0*/ - INFO("UDC_TEST_MODE_NOT_ENABLED (0x%02X)\n", TestMode); - break; - - case UDC_TEST_J_STATE:/*1*/ - pDevReg->CommandStatus = USBREG_TEST_J; - INFO("UDC_TEST_J_STATE wIndex(0x%02X)\n", TestMode); - break; - - case UDC_TEST_K_STATE:/*2*/ - pDevReg->CommandStatus = USBREG_TEST_K; - INFO("UDC_TEST_K_STATE wIndex(0x%02X)\n", TestMode); - break; - - case UDC_TEST_SE0_NAK:/*3*/ - pDevReg->CommandStatus = USBREG_SE0_NAK; - INFO("UDC_TEST_SE0_NAK wIndex(0x%02X)\n", TestMode); - break; - - case UDC_TEST_PACKET:/*4*/ - pDevReg->CommandStatus = USBREG_TESTPACKET; - INFO("UDC_TEST_PACKET wIndex(0x%02X)\n", TestMode); - break; - - case UDC_TEST_FRORCE_ENABLE:/*5*/ - pDevReg->CommandStatus = USBREG_FORCEENABLE; - INFO("UDC_TEST_FRORCE_ENABLE wIndex(0x%02X)\n", TestMode); - break; - - case UDC_TEST_EYE_PATTERN:/*6*/ - pDevReg->CommandStatus = USBREG_TESTEYE; - INFO("UDC_TEST_EYE_PATTERN wIndex(0x%02X)\n", TestMode); - break; - } /*switch(TestMode)*/ - - INFO("UDC - CommandStatus(0x%02X)\n", pDevReg->CommandStatus); - /* stop the 8051*/ - /*ChipTopRegister.Config |= CT_STOP8051;*/ - } - ControlState = CONTROLSTATE_SETUP; /* go back SETUP state*/ - } -#ifdef OTGIP - } - - global_irq_src = pGlobalReg->UHDC_Interrupt_Status; - if (global_irq_src & UHDC_INT_UDC_DMA1)/*UDC Bulk DMA 1*/ - status = wmt_udc_dma_irq(UDC_IRQ_USB, udc);//, r); - -// if (global_irq_src & UHDC_INT_UDC_DMA2)/*UDC Bulk DMA 1*/ -// wmt_udc_dma_irq(UDC_IRQ_USB, udc);//, r); - -// if (global_irq_src & UHDC_INT_UDC_DMA3)/*UDC Bulk DMA 1*/ -// wmt_udc_dma_irq(UDC_IRQ_USB, udc);//, r); - - } -#endif - spin_unlock_irqrestore(&udc->lock, irq_flags); - //printk("udc s =0x%x\n",pGlobalReg->UHDC_Interrupt_Status); - - return status; -} /*wmt_udc_irq()*/ - -/* workaround for seemingly-lost IRQs for RX ACKs... */ -#define PIO_OUT_TIMEOUT (jiffies + HZ/3) - -#ifdef DEBUG_UDC_ISR_TIMER -static void wmt_udc_softirq(unsigned long _udc) -{ - struct vt8500_udc *udc = (void *) _udc; - /*unsigned long flags;*/ - struct pt_regs r; - - INFO("wmt_udc_softirq()\n"); - wmt_udc_irq(UDC_IRQ_USB, udc, &r); - mod_timer(&udc->timer, PIO_OUT_TIMEOUT); - -} -#endif - -static void __init wmt_ep_setup(char *name, u8 addr, u8 type, unsigned maxp); - -static int wmt_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) - -{ - int status = -ENODEV; - struct vt8500_ep *ep; -// unsigned long flags; - - DBG("wmt_udc_start()\n"); - - /* basic sanity tests */ - if (!udc) - return -ENODEV; - if (!driver - /* FIXME if otg, check: driver->is_otg*/ - || driver->max_speed < USB_SPEED_FULL - || !bind -// || !driver->unbind - || !driver->setup){ -// printk(KERN_INFO "gri usb_gadget_probe_driver f2\n"); -// printk(KERN_INFO "gri driver=%x driver->speed=%x driver->bind=%x driver->unbind=%x driver->setup=%x\n", -// (unsigned int)driver,(unsigned int)driver->speed,(unsigned int)driver->bind,(unsigned int)driver->unbind,(unsigned int)driver->setup); - return -EINVAL; - } - - spin_lock_irqsave(&udc->lock, irq_flags); - if (udc->driver) { - spin_unlock_irqrestore(&udc->lock, irq_flags); - return -EBUSY; - } - - /* reset state */ - list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { - ep->irqs = 0; - if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) - continue; - /*use_ep(ep, 0);*/ - /*UDC_CTRL_REG = UDC_SET_HALT;*/ - } - udc->ep0_pending = 0; - udc->ep0_status_0_byte = 0; - udc->ep[0].irqs = 0; - udc->softconnect = 1; - udc->file_storage_set_halt = 0; - /* hook up the driver */ - driver->driver.bus = 0; - udc->driver = driver; - udc->gadget.dev.driver = &driver->driver; - spin_unlock_irqrestore(&udc->lock, irq_flags); - - status = bind(&udc->gadget); - spin_lock_irqsave(&udc->lock, irq_flags); -printk(KERN_INFO "bind to %s --> %d\n", driver->driver.name, status); - - if (status) { - /* %s -> g_file_storage*/ - DBG("bind to %s --> %d\n", driver->driver.name, status); -// printk(KERN_INFO "gri usb_gadget_probe_driver %d\n", status); - udc->gadget.dev.driver = 0; - udc->driver = 0; - goto done; - } - - DBG("bound to driver %s\n", driver->driver.name);/*udc: bound to driver g_file_storage*/ - pUSBMiscControlRegister5 = (unsigned char *)(USB_UDC_REG_BASE + 0x1A0); - - *pUSBMiscControlRegister5 = 0x01;/*USB in normal operation*/ - wmb(); -#if 0 - /* reset Bulk descriptor control*/ - pDevReg->Bulk1EpControl = 0; /* stop the bulk DMA*/ - while (pDevReg->Bulk1EpControl & EP_ACTIVE) - ; /* wait the DMA stopped*/ - - pDevReg->Bulk2EpControl = 0; /* stop the bulk DMA*/ - while (pDevReg->Bulk2EpControl & EP_ACTIVE) - ; /* wait the DMA stopped*/ - - pDevReg->Bulk3EpControl = 0; /* stop the bulk DMA*/ - while (pDevReg->Bulk3EpControl & EP_ACTIVE) - ; /* wait the DMA stopped*/ - - pDevReg->Bulk1DesStatus = 0x00; - pDevReg->Bulk2DesStatus = 0x00; - pDevReg->Bulk3DesStatus = 0x00; - - pDevReg->Bulk1DesTbytes0 = 0; - pDevReg->Bulk1DesTbytes1 = 0; - pDevReg->Bulk1DesTbytes2 = 0; - - pDevReg->Bulk2DesTbytes0 = 0; - pDevReg->Bulk2DesTbytes1 = 0; - pDevReg->Bulk2DesTbytes2 = 0; - - pDevReg->Bulk3DesTbytes0 = 0; - pDevReg->Bulk3DesTbytes1 = 0; - pDevReg->Bulk3DesTbytes2 = 0; - - /* enable DMA and run the control endpoint*/ - pDevReg->ControlEpControl = EP_RUN + EP_ENABLEDMA; - /* enable DMA and run the bulk endpoint*/ - pDevReg->Bulk1EpControl = EP_RUN + EP_ENABLEDMA; - pDevReg->Bulk2EpControl = EP_RUN + EP_ENABLEDMA; -#ifdef USE_BULK3_TO_INTERRUPT - pDevReg->Bulk3EpControl = EP_RUN + EP_ENABLEDMA; -#else - pDevReg->InterruptEpControl = EP_RUN + EP_ENABLEDMA; -#endif -#endif - /* enable DMA and run the interrupt endpoint*/ - /* UsbControlRegister.InterruptEpControl = EP_RUN+EP_ENABLEDMA;*/ - /* run the USB controller*/ - pDevReg->MiscControl3 = 0x3d; - - - pDevReg->PortControl |= PORTCTRL_SELFPOWER;/* Device port control register - 22*/ - wmb(); - pDevReg->CommandStatus = USBREG_RUNCONTROLLER; - wmb(); - - ControlState = CONTROLSTATE_SETUP; - USBState = USBSTATE_DEFAULT; - TestMode = 0; - - wmt_ep_setup_csr("ep0", 0, USB_ENDPOINT_XFER_CONTROL, 64); -#if 0 - wmt_ep_setup_csr("ep1in-bulk", (USB_DIR_IN | 1), USB_ENDPOINT_XFER_BULK, 512); - wmt_ep_setup_csr("ep2out-bulk", (USB_DIR_OUT | 2), USB_ENDPOINT_XFER_BULK, 512); -#ifdef USE_BULK3_TO_INTERRUPT - wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 28); -#else - wmt_ep_setup_csr("ep3in-int", (USB_DIR_IN | 3), USB_ENDPOINT_XFER_INT, 8); -#endif - wmt_ep_setup_csr("ep4in-iso", (USB_DIR_IN | 4), USB_ENDPOINT_XFER_ISO, 384); -#endif - - /* enable all interrupt*/ -#ifdef FULL_SPEED_ONLY - pDevReg->IntEnable = (INTENABLE_ALL | INTENABLE_FULLSPEEDONLY) ;/*0x70*/ -#else - pDevReg->IntEnable = INTENABLE_ALL;/*0x70*/ -#endif - /* set IOC on the Setup decscriptor to accept the Setup request*/ - pDevReg->ControlDesControl = CTRLXFER_IOC; - wmt_pdma_reset();/*NeilChen*/ - -// pDevReg->FunctionPatchEn |= 0x20; /* HW attach process evaluation enable bit*/ - -#ifdef DEBUG_UDC_ISR_TIMER - init_timer(&udc->timer); - udc->timer.function = wmt_udc_softirq; - udc->timer.data = (unsigned long) udc; - add_timer(&udc->timer); -#endif - -done: - spin_unlock_irqrestore(&udc->lock, irq_flags); - return status; -} /*int wmt_udc_start ()*/ - -static int wmt_udc_stop(struct usb_gadget_driver *driver) -{ -// unsigned long flags; - int status = -ENODEV; - - if (!udc) - return -ENODEV; - if (!driver || driver != udc->driver) - return -EINVAL; - - spin_lock_irqsave(&udc->lock, irq_flags); - udc_quiesce(udc); - spin_unlock_irqrestore(&udc->lock, irq_flags); - - driver->unbind(&udc->gadget); - udc->gadget.dev.driver = 0; - udc->driver = 0; - - pDevReg->IntEnable &= 0x8F;/*INTENABLE_ALL(0x70)*/ - /* set IOC on the Setup decscriptor to accept the Setup request*/ - pDevReg->ControlDesControl &= 0x7F;/*CTRLXFER_IOC;*/ - - if (udc->transceiver) - (void) otg_set_peripheral(udc->transceiver->otg, NULL); - else { - pullup_disable(udc); -// pDevReg->FunctionPatchEn &= ~0x20; - } - - if (TestMode != 0x00) { - pDevReg->CommandStatus &= 0x1F; - - pUSBMiscControlRegister5 = (unsigned char *)(USB_UDC_REG_BASE + 0x1A0); - *pUSBMiscControlRegister5 = 0x00;/* USB PHY in power down & USB in reset*/ - - INFO("usb_gadget_unregister_driver() RESET_UDC OK!\n"); - TestMode = 0; - } - - DBG("unregistered driver '%s'\n", driver->driver.name); - return status; -} /*int wmt_udc_stop ()*/ - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_USB_vt8500_PROC - -#include - -static const char proc_filename[] = "driver/udc"; - -#define FOURBITS "%s%s%s%s" -#define EIGHTBITS FOURBITS FOURBITS - -static void proc_ep_show(struct seq_file *s, struct vt8500_ep *ep) -{ - -} /*proc_ep_show()*/ - - -static char *trx_mode(unsigned m) -{ - switch (m) { - case 3: - case 0: return "6wire"; - case 1: return "4wire"; - case 2: return "3wire"; - default: return "unknown"; - } -} - -static int proc_udc_show(struct seq_file *s, void *_) -{ - return 0; -} - -static int proc_udc_open(struct inode *inode, struct file *file) -{ - return single_open(file, proc_udc_show, 0); -} - -static struct file_operations proc_ops = { - .open = proc_udc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static void create_proc_file(void) -{ - struct proc_dir_entry *pde; - - pde = create_proc_entry(proc_filename, 0, NULL); - if (pde) - pde->proc_fops = &proc_ops; -} - -static void remove_proc_file(void) -{ - remove_proc_entry(proc_filename, 0); -} - -#else - -static inline void create_proc_file(void) {} -static inline void remove_proc_file(void) {} - -#endif - -/*-------------------------------------------------------------------------*/ - -/* Before this controller can enumerate, we need to pick an endpoint - * configuration, or "fifo_mode" That involves allocating 2KB of packet - * buffer space among the endpoints we'll be operating. - */ -static void __init -wmt_ep_setup(char *name, u8 addr, u8 type, - unsigned maxp) -{ - struct vt8500_ep *ep; - - VDBG("wmt_ep_setup()\n"); - - /* OUT endpoints first, then IN*/ - ep = &udc->ep[addr & 0x7f]; - - VDBG("wmt_ep_setup() - %s addr %02x maxp %d\n", - name, addr, maxp); - - strlcpy(ep->name, name, sizeof ep->name); - INIT_LIST_HEAD(&ep->queue); - ep->bEndpointAddress = addr; - ep->bmAttributes = type; - ep->double_buf = 0;/*dbuf;*/ - ep->udc = udc; - ep->toggle_bit = 0; - ep->ep.name = ep->name; - ep->ep.ops = &wmt_ep_ops;/*struct usb_ep_ops*/ - ep->ep.maxpacket = ep->maxpacket = maxp; - list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); - - /*return buf;*/ -} /*wmt_ep_setup()*/ - -static void wmt_udc_release(struct device *dev) -{ - DBG("wmt_udc_release()\n"); - complete(udc->done); - kfree(udc); - udc = 0; -} /*wmt_udc_release()*/ - -static int __init -wmt_udc_setup(struct platform_device *odev, struct usb_phy *xceiv) -{ - DBG("wmt_udc_setup()\n"); - udc = kmalloc(sizeof *udc, GFP_KERNEL); - - if (!udc) - return -ENOMEM; - - memset(udc, 0, sizeof *udc); - spin_lock_init(&udc->lock); - - spin_lock_init(&gri_lock); - - sema_init(&wmt_udc_sem, 1); - - udc->gadget.ops = &wmt_gadget_ops; - udc->gadget.ep0 = &udc->ep[0].ep; - INIT_LIST_HEAD(&udc->gadget.ep_list); - /*INIT_LIST_HEAD(&udc->iso);*/ - udc->gadget.speed = USB_SPEED_UNKNOWN; - udc->gadget.name = driver_name; - - device_initialize(&udc->gadget.dev); - //strcpy(udc->gadget.dev.bus_id, "gadget"); - dev_set_name(&udc->gadget.dev, "gadget"); - udc->gadget.dev.release = wmt_udc_release; - udc->transceiver = NULL; - /* ep0 is special; put it right after the SETUP buffer*/ - wmt_ep_setup("ep0", 0, USB_ENDPOINT_XFER_CONTROL, 64); - - list_del_init(&udc->ep[0].ep.ep_list); - -#if 1 -#if 1 -#define VT8430_BULK_EP(name, addr) \ - wmt_ep_setup(name "-bulk", addr, \ - USB_ENDPOINT_XFER_BULK, 512); - -/*usb_ch9.h*/ -/*#define USB_DIR_OUT 0 *//* to device */ -/*#define USB_DIR_IN 0x80 *//* to host */ -#define VT8430_INT_EP(name, addr, maxp) \ - wmt_ep_setup(name "-int", addr, \ - USB_ENDPOINT_XFER_INT, maxp); - -#define VT8430_ISO_EP(name, addr, maxp) \ - wmt_ep_setup(name "-iso", addr, \ - USB_ENDPOINT_XFER_ISOC, maxp); -#endif - - VT8430_BULK_EP("ep1in", USB_DIR_IN | 1); - VT8430_BULK_EP("ep2out", USB_DIR_OUT | 2); -#ifdef USE_BULK3_TO_INTERRUPT - VT8430_INT_EP("ep3in", USB_DIR_IN | 3, 512); -#else - VT8430_INT_EP("ep3in", USB_DIR_IN | 3, 8); -#endif - VT8430_ISO_EP("ep4in", USB_DIR_IN | 4, 512); -#endif - udc->ep[0].rndis_buffer_alloc = 0; - udc->ep[1].rndis_buffer_alloc = 0; - udc->ep[2].rndis_buffer_alloc = 0; - udc->ep[3].rndis_buffer_alloc = 0; - udc->ep[4].rndis_buffer_alloc = 0; - udc->ep[5].rndis_buffer_alloc = 0;//gri - udc->ep[6].rndis_buffer_alloc = 0;//gri - - /*INFO("fifo mode %d, %d bytes not used\n", fifo_mode, 2048 - buf);*/ - return 0; -} /*wmt_udc_setup()*/ - -static void wmt_pdma_reset(void) -{ - - if (!pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable) - pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/ - - pUdcDmaReg->DMA_Global_Bits.SoftwareReset = 1; - wmb(); - while (pUdcDmaReg->DMA_Global_Bits.SoftwareReset)/*wait reset complete*/ - ; - - pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/ - pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable0 = 1; - pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable1 = 1; - pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable2 = 1; - - pUdcDmaReg->DMA_Context_Control0_Bis.TransDir = 0; - pUdcDmaReg->DMA_Context_Control1_Bis.TransDir = 1; - pUdcDmaReg->DMA_Context_Control2_Bis.TransDir = 0; - wmb(); - /*descriptor initial*/ - -} /*wmt_pdma_init*/ - -static void wmt_pdma0_reset(void) -{ - - if (!pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable) - pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/ - - pUdcDmaReg->DMA_Global_Bits.SoftwareReset0 = 1; - wmb(); - while (pUdcDmaReg->DMA_Global_Bits.SoftwareReset0)/*wait reset complete*/ - ; - - pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable0 = 1; - - pUdcDmaReg->DMA_Context_Control0_Bis.TransDir = 0; - wmb(); - /*descriptor initial*/ - -} /*wmt_pdma_init*/ - - -static void wmt_pdma1_reset(void) -{ - - if (!pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable) - pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/ - - pUdcDmaReg->DMA_Global_Bits.SoftwareReset1 = 1; - wmb(); - while (pUdcDmaReg->DMA_Global_Bits.SoftwareReset1)/*wait reset complete*/ - ; - - pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable1 = 1; - - pUdcDmaReg->DMA_Context_Control1_Bis.TransDir = 1; - wmb(); - /*descriptor initial*/ - -} /*wmt_pdma_init*/ - -#ifdef USE_BULK3_TO_INTERRUPT -static void wmt_pdma2_reset(void) -{ - - if (!pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable) - pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/ - - pUdcDmaReg->DMA_Global_Bits.SoftwareReset2 = 1; - wmb(); - while (pUdcDmaReg->DMA_Global_Bits.SoftwareReset2)/*wait reset complete*/ - ; - - pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable2 = 1; - - pUdcDmaReg->DMA_Context_Control2_Bis.TransDir = 0; - wmb(); - /*descriptor initial*/ - -} /*wmt_pdma_init*/ -#endif - - -/*static void wmt_pdma_init(struct device *dev)*/ -static void wmt_pdma_init(struct device *dev) -{ - UdcRndisEp1VirAddr = (unsigned int) dma_alloc_coherent(dev, (size_t)65536, (dma_addr_t *)(&UdcRndisEp1PhyAddr), GFP_KERNEL|GFP_ATOMIC); - UdcRndisEp2VirAddr = (unsigned int) dma_alloc_coherent(dev, (size_t)65536, (dma_addr_t *)(&UdcRndisEp2PhyAddr), GFP_KERNEL|GFP_ATOMIC); - UdcRndisEp3VirAddr = (unsigned int) dma_alloc_coherent(dev, (size_t)65536, (dma_addr_t *)(&UdcRndisEp3PhyAddr), GFP_KERNEL|GFP_ATOMIC); - - UdcPdmaVirAddrLI = (unsigned int) dma_alloc_coherent(pDMADescLI, (size_t)0x100, (dma_addr_t *)(&UdcPdmaPhyAddrLI), GFP_KERNEL|GFP_ATOMIC); - UdcPdmaVirAddrSI = (unsigned int) dma_alloc_coherent(pDMADescSI, (size_t)0x100, (dma_addr_t *)(&UdcPdmaPhyAddrSI), GFP_KERNEL|GFP_ATOMIC); - UdcPdmaVirAddrLO = (unsigned int) dma_alloc_coherent(pDMADescLO, (size_t)0x100, (dma_addr_t *)(&UdcPdmaPhyAddrLO), GFP_KERNEL|GFP_ATOMIC); - UdcPdmaVirAddrSO = (unsigned int) dma_alloc_coherent(pDMADescSO, (size_t)0x100, (dma_addr_t *)(&UdcPdmaPhyAddrSO), GFP_KERNEL|GFP_ATOMIC); - -#ifdef USE_BULK3_TO_INTERRUPT - UdcPdmaVirAddrL2I = (unsigned int) dma_alloc_coherent(pDMADescL2I, (size_t)0x100, (dma_addr_t *)(&UdcPdmaPhyAddrL2I), GFP_KERNEL|GFP_ATOMIC); - UdcPdmaVirAddrS2I = (unsigned int) dma_alloc_coherent(pDMADescS2I, (size_t)0x100, (dma_addr_t *)(&UdcPdmaPhyAddrS2I), GFP_KERNEL|GFP_ATOMIC); -#endif - - pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/ - pUdcDmaReg->DMA_Global_Bits.SoftwareReset = 1; - wmb(); - while (pUdcDmaReg->DMA_Global_Bits.SoftwareReset)/*wait reset complete*/ - ; - pUdcDmaReg->DMA_Global_Bits.DMAConrollerEnable = 1;/*enable DMA*/ - pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable0 = 1; - pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable1 = 1; - - pUdcDmaReg->DMA_Context_Control0_Bis.TransDir = 0; - pUdcDmaReg->DMA_Context_Control1_Bis.TransDir = 1; - -#ifdef USE_BULK3_TO_INTERRUPT - pUdcDmaReg->DMA_IER_Bits.DMAInterruptEnable2 = 1; - pUdcDmaReg->DMA_Context_Control2_Bis.TransDir = 0; -#endif - wmb(); - -} /*wmt_pdma_init*/ - -/*static int __init wmt_udc_probe(struct device *dev)*/ -static int __init wmt_udc_probe(struct platform_device *pdev) -{ -/* struct platform_device *odev = to_platform_device(dev);*/ - struct device *dev = &pdev->dev; - int status = -ENODEV; - struct usb_phy *xceiv = 0; - - DBG("wmt_udc_probe()\n"); - - /*UDC Register Space 0x400~0x7EF*/ - - INIT_LIST_HEAD (&done_main_list); - - b_pullup = 0; - - pDevReg = (struct UDC_REGISTER *)USB_UDC_REG_BASE; - pUdcDmaReg = (struct UDC_DMA_REG *)USB_UDC_DMA_REG_BASE; - pSetupCommand = (PSETUPCOMMAND)(USB_UDC_REG_BASE + 0x300); - pSetupCommandBuf = (unsigned char *)(USB_UDC_REG_BASE + 0x300); - SetupBuf = (UCHAR *)(USB_UDC_REG_BASE + 0x340); - IntBuf = (UCHAR *)(USB_UDC_REG_BASE + 0x40); - pUSBMiscControlRegister5 = (unsigned char *)(USB_UDC_REG_BASE + 0x1A0); - -#ifdef OTGIP - /*UHDC Global Register Space 0x7F0~0x7F7*/ - pGlobalReg = (struct USB_GLOBAL_REG *) USB_GLOBAL_REG_BASE; -#endif - - *pUSBMiscControlRegister5 = 0x01; - pDevReg->CommandStatus &= 0x1F; - pDevReg->CommandStatus |= USBREG_RESETCONTROLLER; - wmb(); - while (pDevReg->CommandStatus & USBREG_RESETCONTROLLER) - ; - - wmt_pdma_init(dev); - - pDevReg->Bulk1EpControl = 0; /* stop the bulk DMA*/ - wmb(); - while (pDevReg->Bulk1EpControl & EP_ACTIVE) /* wait the DMA stopped*/ - ; - pDevReg->Bulk2EpControl = 0; /* stop the bulk DMA*/ - wmb(); - while (pDevReg->Bulk2EpControl & EP_ACTIVE) /* wait the DMA stopped*/ - ; - pDevReg->Bulk1DesStatus = 0x00; - pDevReg->Bulk2DesStatus = 0x00; - - pDevReg->Bulk1DesTbytes0 = 0; - pDevReg->Bulk1DesTbytes1 = 0; - pDevReg->Bulk1DesTbytes2 = 0; - - pDevReg->Bulk2DesTbytes0 = 0; - pDevReg->Bulk2DesTbytes1 = 0; - pDevReg->Bulk2DesTbytes2 = 0; - -#ifdef USE_BULK3_TO_INTERRUPT - pDevReg->Bulk3EpControl = 0; /* stop the bulk DMA*/ - wmb(); - while (pDevReg->Bulk3EpControl & EP_ACTIVE) /* wait the DMA stopped*/ - ; - pDevReg->Bulk3DesStatus = 0x00; - - pDevReg->Bulk3DesTbytes0 = 0; - pDevReg->Bulk3DesTbytes1 = 0; - pDevReg->Bulk3DesTbytes2 = 0; -#endif - - /* enable DMA and run the control endpoint*/ - wmb(); - pDevReg->ControlEpControl = EP_RUN + EP_ENABLEDMA; - /* enable DMA and run the bulk endpoint*/ - pDevReg->Bulk1EpControl = EP_RUN + EP_ENABLEDMA; - pDevReg->Bulk2EpControl = EP_RUN + EP_ENABLEDMA; - -#ifdef USE_BULK3_TO_INTERRUPT - pDevReg->Bulk3EpControl = EP_RUN + EP_ENABLEDMA; -#else - pDevReg->InterruptEpControl = EP_RUN + EP_ENABLEDMA; -#endif - wmb(); - /* enable DMA and run the interrupt endpoint*/ - /* UsbControlRegister.InterruptEpControl = EP_RUN+EP_ENABLEDMA;*/ - /* run the USB controller*/ - pDevReg->MiscControl3 = 0x3d; - - /* HW attach process evaluation enable bit For WM3426 and after project*/ - /*pDevReg->FunctionPatchEn |= 0x20;*/ -#ifdef HW_BUG_HIGH_SPEED_PHY - pDevReg->MiscControl0 &= ~0x80; -#endif - pDevReg->MiscControl0 |= 0x02; - wmb(); - pDevReg->CommandStatus = USBREG_RUNCONTROLLER; - - ControlState = CONTROLSTATE_SETUP; - USBState = USBSTATE_DEFAULT; - TestMode = 0; - - status = wmt_udc_setup(pdev, xceiv); - if (status) - goto cleanup0; - - xceiv = 0; - - /*udc->chip_version = tmp8;*/ - /* "udc" is now valid*/ - pullup_disable(udc); - - udc->gadget.is_otg = 0;/*(config->otg != 0);*/ - udc->dev = dev; - udc->gadget.max_speed = USB_SPEED_HIGH;; - udc->ep0_status_0_byte = 0; - udc->usb_connect = 0; - /* USB general purpose IRQ: ep0, state changes, dma, etc*/ - status = request_irq(UDC_IRQ_USB, wmt_udc_irq, -// (SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM), driver_name, udc); -// (IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM), driver_name, udc); - (IRQF_SHARED | IRQF_SAMPLE_RANDOM), driver_name, udc);//gri - pDevReg->SelfPowerConnect |= 0x10;//Neil - -#ifndef OTGIP - status = request_irq(UDC_IRQ_DMA, wmt_udc_dma_irq, -// (SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM), driver_name, udc); -// (IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM), driver_name, udc); - (IRQF_SHARED | IRQF_SAMPLE_RANDOM), driver_name, udc); -#endif - /*SA_SAMPLE_RANDOM, driver_name, udc);*/ - if (status != 0) { - ERR("can't get irq %d, err %d\n", - UDC_IRQ_USB, status); - goto cleanup1; - } else - INFO("wmt_udc_probe - request_irq(0x%02X) pass!\n", UDC_IRQ_USB); - - create_proc_file(); - status = device_add(&udc->gadget.dev); - if (status) - goto cleanup4; - - status = usb_add_gadget_udc(&pdev->dev, &udc->gadget); - initial_test_fiq(); - if (!status) - return 0; - -cleanup4: - remove_proc_file(); - -/*cleanup2:*/ - free_irq(UDC_IRQ_USB, udc); - INFO("wmt_udc_probe - free_irq(0x%02X)?\n", UDC_IRQ_USB); -cleanup1: - kfree(udc); - udc = 0; - -cleanup0: - if (xceiv) - usb_put_transceiver(xceiv); - /*release_mem_region(odev->resource[0].start,*/ - /* odev->resource[0].end - odev->resource[0].start + 1);*/ - return status; - -} /*wmt_udc_probe()*/ - -static int __exit wmt_udc_remove(struct platform_device *pdev) -{ - /*struct platform_device *odev = to_platform_device(dev);*/ - DECLARE_COMPLETION(done); - DBG("wmt_udc_remove()\n"); - - if (!udc) - return -ENODEV; - - udc->done = &done; - - pullup_disable(udc); - if (udc->transceiver) { - usb_put_transceiver(udc->transceiver); - udc->transceiver = 0; - } - /*UDC_SYSCON1_REG = 0;*/ - - remove_proc_file(); - - free_irq(UDC_IRQ_USB, udc); - - device_unregister(&udc->gadget.dev); - wait_for_completion(&done); - - return 0; -} /*wmt_udc_remove()*/ - -/* suspend/resume/wakeup from sysfs (echo > power/state) */ - -static int -wmt_udc_pm_notify(struct notifier_block *nb, unsigned long event, void *dummy) -{ - - - if (event == PM_SUSPEND_PREPARE) { - if (udc->driver){ - run_script(action_off_line); - } - gadget_connect=0; - down(&wmt_udc_sem); - pullup_disable(udc); - up(&wmt_udc_sem); - } - else if (event == PM_POST_SUSPEND) { - - down(&wmt_udc_sem); - pullup_enable(udc); - up(&wmt_udc_sem); - - wmt_wakeup(&udc->gadget); - } - - return NOTIFY_OK; -} - - -static struct notifier_block wmt_udc_pm_notifier = { - .notifier_call = wmt_udc_pm_notify, -}; - - - - -static int wmt_udc_suspend(struct platform_device *pdev, pm_message_t state) -{ - DBG("wmt_udc_suspend()\n"); - printk(KERN_INFO "wmt_udc_suspend\n"); //gri -#if 0 - if (udc->driver){ - run_script(action_off_line); - } - gadget_connect=0; - run_script(action_mount); -#endif - pDevReg->CommandStatus &= 0x1F; - - pUSBMiscControlRegister5 = (unsigned char *)(USB_UDC_REG_BASE + 0x1A0); - /**pUSBMiscControlRegister5 = 0x02;// USB PHY in power down & USB in reset*/ - *pUSBMiscControlRegister5 = 0x00;/*USB in reset*/ - wmb(); - - TestMode = 0; -#if 0 - down(&wmt_udc_sem); - pullup_disable(udc); - up(&wmt_udc_sem); -#endif - -/* if ((state == 3) && (level == 3))*/ -/* *(volatile unsigned int *)(PM_CTRL_BASE_ADDR + 0x254) &= ~0x00000080;*/ /*DPM needed*/ - *(volatile unsigned char*)(USB_IP_BASE + 0x249) |= 0x04; - - return 0; - -} /*wmt_udc_suspend()*/ - -static int wmt_udc_resume(struct platform_device *pdev) -{ -#if 0 - DBG("wmt_udc_resume()\n"); - printk(KERN_INFO "wmt_udc_resume\n"); //gri - down(&wmt_udc_sem); - reset_udc(); - pullup_enable(udc); - up(&wmt_udc_sem); - - return wmt_wakeup(&udc->gadget); -#endif - reset_udc(); - return 0; - -} /*wmt_udc_resume()*/ - -/*-------------------------------------------------------------------------*/ - -static struct platform_driver udc_driver = { - .driver.name = (char *) driver_name, - .probe = wmt_udc_probe, - .remove = __exit_p(wmt_udc_remove), - .suspend = wmt_udc_suspend, - .resume = wmt_udc_resume, -}; - -static struct resource wmt_udc_resources[] = { - [0] = { - .start = (USB_IP_BASE + 0x2000), - .end = (USB_IP_BASE + 0x2400), - .flags = IORESOURCE_MEM, - }, -}; -static u64 wmt_udc_dma_mask = 0xFFFFF000; - -static struct platform_device wmt_udc_device = { - .name = (char *) driver_name, - .id = 0, - .dev = { - .dma_mask = &wmt_udc_dma_mask, - .coherent_dma_mask = ~0, - }, - .num_resources = ARRAY_SIZE(wmt_udc_resources), - .resource = wmt_udc_resources, -}; - -void wmt_cleanup_done_thread(int number) -{ - unsigned long flags; - struct usb_composite_dev *cdev = get_gadget_data(&(udc->gadget)); -#if 1 - if(number == 1) - { - if(in_interrupt()) - return; - if(spin_is_locked(&cdev->lock)){ - //local_irq_save(flags); - spin_unlock(&cdev->lock); - //local_irq_enable(); - //schedule_work(&done_thread); - flush_work_sync(&done_thread); - //local_irq_restore(flags); - spin_lock(&cdev->lock); - }else{ - flush_work_sync(&done_thread); - } - //wmt_ep_disable(&udc->ep[0]); - spin_lock_irqsave(&udc->lock, flags); - nuke(&udc->ep[0],ESHUTDOWN); - spin_unlock_irqrestore(&udc->lock, flags); - }else if(number == 2) - { - }else{ - //flush_work_sync(&mount_thread); - printk("erro parameter:%s\n",__func__); - } -#endif -} -EXPORT_SYMBOL(wmt_cleanup_done_thread); - -static int __init udc_init(void) -{ - INFO("%s, version: " DRIVER_VERSION - "%s\n", driver_desc, - use_dma ? " (dma)" : ""); - - DBG("udc_init()\n"); - -//INIT_WORK(&online_thread, run_online); -INIT_WORK(&offline_thread, run_offline); -INIT_WORK(&done_thread, run_done); -INIT_WORK(&chkiso_thread, run_chkiso); - -platform_device_register(&wmt_udc_device); - - register_pm_notifier(&wmt_udc_pm_notifier); - - return platform_driver_register(&udc_driver); -} /*udc_init()*/ - -module_init(udc_init); - -static void __exit udc_exit(void) -{ - DBG("udc_exit()\n"); - //driver_unregister(&udc_driver); - platform_driver_unregister(&udc_driver); - platform_device_unregister(&wmt_udc_device); -} /*udc_exit()*/ - -module_exit(udc_exit); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.h b/ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.h deleted file mode 100755 index c566f3cd..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/udc_wmt.h +++ /dev/null @@ -1,801 +0,0 @@ -/* - * wmt_udc.c -- for WonderMedia Technology udc - * - * Copyright (C) 2007 VIA Technologies, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef __LINUX_USB_GADGET_VT8500_H -#define __LINUX_USB_GADGET_VT8500_H - -#include -/*#include */ -/*#include */ -/*#include */ -#include -#include - -#define OTGIP - -#define UINT volatile unsigned int -#define USHORT volatile unsigned short -#define UCHAR volatile unsigned char -#define ULL volatile unsigned long long - -#define UDC_IRQ_USB IRQ_UHDC - -#ifndef OTGIP -#define UDC_IRQ_DMA 2 -#endif -/*#define DWORD volatile unsigned long*/ -/*#define WORD volatile unsigned short*/ -/*#define BYTE volatile unsigned char*/ -#define USB_IP_BASE USB20_HOST_DEVICE_CFG_BASE_ADDR -/*UDC Register Space 0x400~0x7EF*/ -#define USB_UDC_REG_BASE (USB_IP_BASE + 0x400) -/*Bulk Endpoint DMA Register Space 0x100*/ -#define USB_UDC_DMA_REG_BASE (USB_IP_BASE + 0x500) -#ifdef OTGIP -/*UHDC Global Register Space 0x7F0~0x7F7*/ -#define USB_GLOBAL_REG_BASE (USB_IP_BASE + 0x7f0) -#endif - -#define UDC_REG(offset) REG32_PTR(USB_UDC_REG_BASE + offset) - -#define OTG_HOST_MEM_BASE 0x01400000/*20MB*/ - -#define USB_EP0_CTRL_DMA_BASE OTG_HOST_MEM_BASE /*64 bytes*/ -#define USB_EP1_BULK_IN_DMA_BASE 0x01400040/*OTG_HOST_MEM_BASE + 64 */ /*64B +64KB*/ -#define USB_EP2_BULK_OUT_DMA_BASE 0x01410040/*OTG_HOST_MEM_BASE + 65536*/ /* ~ END*/ -#define USB_DOWNLOAD_KERNEL_RAM_ADDR USB_EP2_BULK_OUT_DMA_BASE - -/* Basic Define*/ -#define REG32 *(volatile unsigned int *) -#define REG16 *(volatile unsigned short *) -#define REG8 *(volatile unsigned char *) - -#define REG_GET32(addr) ( REG32(addr) ) /* Read 32 bits Register */ -#define REG_GET16(addr) ( REG16(addr) ) /* Read 16 bits Register */ -#define REG_GET8(addr) ( REG8(addr) ) /* Read 8 bits Register */ - -#define REG_SET32(addr, val) ( REG32(addr) = (val) ) /* Write 32 bits Register */ -#define REG_SET16(addr, val) ( REG16(addr) = (val) ) /* Write 16 bits Register */ -#define REG_SET8(addr, val) ( REG8(addr) = (val) ) /* Write 8 bits Register */ - -#define MEM_GET32(addr) ( REG32(addr) ) /* Read 32 bits Memory */ -#define MEM_SET32(addr, val) ( REG32(addr) = (val) ) /* Write 32 bits Memory */ - -/*#define USB_TIMEOUT 0x100*/ /*256*/ -/*#define USB_TEST_SUCCESS 1*/ -/*#define USB_TEST_FAIL 0*/ - -/* define the state of the USB device*/ -#define USBSTATE_ATTACHED 0x00 /* device attached to host*/ -#define USBSTATE_POWERED 0x01 /* device obtain power*/ -#define USBSTATE_DEFAULT 0x02 /* default working state*/ -#define USBSTATE_ADDRESS 0x04 /* device has get the address*/ -#define USBSTATE_CONFIGED 0x10 /* deivce has set the configuration*/ -#define USBSTATE_SUSPEND 0x20 /* No bus activity device goes to suspend */ - -#define UDC_TEST_J_STATE 1 -#define UDC_TEST_K_STATE 2 -#define UDC_TEST_SE0_NAK 3 -#define UDC_TEST_PACKET 4 -#define UDC_TEST_FRORCE_ENABLE 5 -#define UDC_TEST_EYE_PATTERN 6 -#define UDC_TEST_MODE_NOT_ENABLED 0 - -/*Define the USB register bit value*/ -/* USB device commmand/status register - 20*/ -#define USBREG_RUNCONTROLLER 0x01 /* set the controller run*/ -#define USBREG_RESETCONTROLLER 0x02 /* reset the device contrller*/ -#define USBREG_COMPLETEINT 0x04 /* the completion interrupt*/ -#define USBREG_BABBLEINT 0x08 /* the babble interrupt*/ -#define USBREG_BUSACTINT 0x10 /* the bus activity interrupt*/ -#define USBREG_TEST_J 0x20 /* set test J state*/ -#define USBREG_TEST_K 0x40 /* set test k state*/ -#define USBREG_SE0_NAK 0x60 /* set test SE0 and NAK*/ -#define USBREG_TESTPACKET 0x80 /* set device sending test packet*/ -#define USBREG_FORCEENABLE 0xA0 /* force port enable*/ -#define USBREG_TESTEYE 0xC0 /* Send test eye pattern packet*/ - -/* The device address register - 21*/ -#define DEVADDR_ADDRCHANGE 0x80 /* the address change bit for device address register*/ - -/* Device port control register - 22*/ -#define PORTCTRL_CONNECTSTATUS 0x01 /* current connection status*/ -#define PORTCTRL_CONNECTCHANGE 0x02 /* connection change bit*/ -#define PORTCTRL_SELFPOWER 0x04 /* the device is in the self power configuration*/ -#define PORTCTRL_FORCERESUME 0x08 /* force deivce to wake the host*/ -#define PORTCTRL_HIGHSPEEDMODE 0x10 /* device is in the high speed mode*/ -#define PORTCTRL_FULLSPEEDMODE 0x20 /* device is in the full speed mode*/ - -/* Device itnerrupt enable register - 23*/ -#define INTENABLE_DEVICERESET 0x01 /* this bit is set when the bus reset is completed*/ -#define INTENABLE_SUSPENDDETECT 0x02 /* device controller detect the suspend signal*/ -#define INTENABLE_RESUMEDETECT 0x04 /* device controller detect the resume signal*/ -#define INTENABLE_COMPLETEINTEN 0x10 /* enable completion interrupt*/ -#define INTENABLE_BABBLEINTEN 0x20 /* enable babble interrupt*/ -#define INTENABLE_BUSACTINTEN 0x40 /* enable bus activity interrupt*/ -#define INTENABLE_ALL 0x70 /* enable all interrupt */ -#define INTENABLE_FULLSPEEDONLY 0x80 /* force device to support full speed only*/ - -/* Control endpoint control - 24*/ -/* Bulk endpoint control - 28*/ -/* Interrupt endpoint control - 2C*/ -/* Bulk endpoint control - 0x310*/ -#define EP_RUN 0x01 /* run the enpoint DMA*/ -#define EP_ENABLEDMA 0x02 /* enable the DMA engine to run the schedule*/ -#define EP_DMALIGHTRESET 0x04 /* light reset the DMA engine*/ -#define EP_STALL 0x08 /* set the endpoint to stall*/ -#define EP_ACTIVE 0x10 /* the endpoint DMA is active*/ -#define EP_COMPLETEINT 0x20 /* endpoint transfer complete interrupt*/ -#define EP_BABBLE 0x40 /* endpoint babble interrupt*/ - -/* Control transfer descriptor status byte - 30*/ -#define CTRLXFER_XACTERR 0x01 /* trnasacion error of control transfer*/ -#define CTRLXFER_BABBLE 0x02 /* babbe error of control transfer*/ -#define CTRLXFER_SHORTPKT 0x04 /* shortpacket detect of control transfer*/ -#define CTRLXFER_ACTIVE 0x08 /* transfer active of control transfer*/ - -#define CTRLXFER_IN 0x08 /* I/O control bit 0 for OUT , 1 for In*/ -#define CTRLXFER_OUT 0x00 /**/ -#define CTRLXFER_CMDVALID 0x10 /* setup command is valid*/ -#define CTRLXFER_IOC 0x80 /* determine to gen interrupt for completion or not*/ -#define CTRLXFER_DATA1 0x80 /* for data_toggle 1*/ -#define CTRLXFER_DATA0 0x00 /* for data_toggle 0*/ - -/* Bulk endpoint transfer descriptor status - 34*/ -/* Bulk endpoint transfer descriptor status - 0x314 */ -#define BULKXFER_XACTERR 0x01 /* trnasacion error of bulk transfer*/ -#define BULKXFER_BABBLE 0x02 /* babbe error of bulk transfer*/ -#define BULKXFER_SHORTPKT 0X04 /* shortpacket detect of bulk transfer*/ -#define BULKXFER_ACTIVE 0x08 /* transfer active of bulk transfer*/ -#define BULKXFER_IN 0x10 /* I/O control bit 0 for OUT , 1 for In*/ -#define BULKXFER_OUT 0x00 -/*HP05_Begin*/ -#define BULKXFER_CBWBUF 0x20 /* enable CBW dedicated buffer*/ -/*HP05_End*/ -#define BULKXFER_IOC 0x80 /* determine to generate interrupt for completion or not*/ -#define BULKXFER_DATA1 0x80 /* for data_toggle 1*/ -#define BULKXFER_DATA0 0x00 /* for data_toggle 0*/ - -/* Interupt endpoint transfer descriptor - 33*/ -#define INTXFER_XACTERR 0x01 /* trnasacion error for interrupt transfer*/ -#define INTXFER_ACTIVE 0x02 /* transfer active*/ -#define INTXFER_IOC 0x04 /* determine to generate interrupt for completion or not*/ -#define INTXFER_DATA1 0x08 /* for data_toggle 1*/ -#define INTXFER_DATA0 0x00 /* for data_toggle 0*/ - -/*UDC 0x400 ~ 0x7FF*/ -struct UDC_REGISTER{ - UCHAR Reserved0[0x20]; /* 0x00~0x19 Reserved 0*/ - UCHAR CommandStatus; /* USB device commmand/status register - 20*/ - UCHAR DeviceAddr; /* The device address register - 21*/ - - UCHAR PortControl; /* Device port control register - 22*/ - UCHAR IntEnable; /* Device itnerrupt enable register - 23*/ - - UCHAR ControlEpControl; /* Control endpoint control - 24*/ - UCHAR ControlEpReserved; /* Control endpoint reserved byte - 25*/ - UCHAR ControlEpMaxLen; /* max length of control endpoint - 26*/ - UCHAR ControlEpEpNum; /* The control endpoint number - 27*/ - - UCHAR Bulk1EpControl; /* Bulk endpoint control - 28*/ - UCHAR Bulk1EpOutEpNum; /* Bulk out endpoint number - 29*/ - UCHAR Bulk1EpMaxLen; /* Bulk maximum length - 2A*/ - UCHAR Bulk1EpInEpNum; /* Bulk In endpoint number - 2B*/ - - UCHAR InterruptEpControl; /* Interrupt endpoint control - 2C*/ - UCHAR InterruptReserved; /* Interrupt endpoint reserved byte - 2D*/ - UCHAR InterruptEpMaxLen; /* Interrupt maximum transfer length - 2E*/ - UCHAR InterruptEpEpNum; /* interrupt endpoint number - 2F*/ - - UCHAR ControlDesStatus; /* Control transfer descriptor status byte - 30*/ - UCHAR ControlDesControl; /* Control transfer descriptor control byte - 31*/ - UCHAR ControlDesTbytes; /* Control transfer descriptor total bytes - 32*/ - - UCHAR InterruptDes; /* Interupt endpoint transfer descriptor - 33*/ - - UCHAR Bulk1DesStatus; /* Bulk endpoint transfer descriptor status - 34*/ - UCHAR Bulk1DesTbytes0; /* Bulk endpoint transfer descriptor control - 35*/ - UCHAR Bulk1DesTbytes1; /* Bulk endpoint transfer descriptor lower total bytes - 36*/ - UCHAR Bulk1DesTbytes2; /* Bulk endpoint transfer descriptor higer total bytes - 37*/ - - UCHAR MacToParameter; /* USB2.0 MAC timeout parameter register - 38*/ - UCHAR PhyMisc; /* PHY misc control register - 39*/ - UCHAR MiscControl0; /* Misc. control register 0 - 3A*/ - UCHAR MiscControl1; /* Misc. control register 1 - 3B*/ - UCHAR MiscControl2; /* Misc. control register 2 - 3C*/ - UCHAR MiscControl3; /* Misc. control register 3 - 3D*/ - UCHAR MACDelay; /* MAC receiver enable delay parameter - 3E*/ - UCHAR FunctionPatchEn; /* Function Patch Enable bits - 3F*/ - - UCHAR InterruptInBuf[32]; /* Interrupt In Endpoint Data Buffer - 40 ~ 5F (32 bytes) for CBW(31 bytes)*/ - - UCHAR Reserved1[0x2A0]; /* 0x060~0x2FF ; 0x2FF - 0x60 + 1 = 0x2A0 for Bulk Endpoint 01 02 DMA Source / Destination*/ - UCHAR SetupCommand[8]; /* 0x300~0x307 */ - UCHAR PHYControlBit; /* 0x308 Phy Control Bit */ - UCHAR Reserved2[2]; /* 0x309 ~ 0x30A*/ - UCHAR NewUSBPhyTestControl;/* 0x30B New USB 1.1 and USB 2.0 PHY test control bit*/ - UCHAR NewUSBPhyTestStatus; /* 0x30C New USB 1.1 and USB 2.0 PHY test status bit*/ - UCHAR SelfPowerConnect; /* 0x30D Debug pins for USBC side control bit*/ - - UCHAR Reserved3[2]; /* 0x30E ~ 0x30F*/ - - UCHAR Bulk2EpControl; /* Bulk endpoint control - 0x310*/ - UCHAR Bulk2EpOutEpNum; /* Bulk out endpoint number - 0x311*/ - UCHAR Bulk2EpMaxLen; /* Bulk maximum length - 0x312*/ - UCHAR Bulk2EpInEpNum; /* Bulk In endpoint number - 0x313*/ - - UCHAR Bulk2DesStatus; /* Bulk endpoint transfer descriptor status - 0x314*/ - UCHAR Bulk2DesTbytes0; /* Bulk endpoint transfer descriptor control - 0x315*/ - UCHAR Bulk2DesTbytes1; /* Bulk endpoint transfer descriptor lower total bytes - 0x316*/ - UCHAR Bulk2DesTbytes2; /* Bulk endpoint transfer descriptor higer total bytes - 0x317*/ - - UCHAR Bulk3EpControl; /* Bulk endpoint control - 0x310*/ - UCHAR Bulk3EpOutEpNum; /* Bulk out endpoint number - 0x311*/ - UCHAR Bulk3EpMaxLen; /* Bulk maximum length - 0x312*/ - UCHAR Bulk3EpInEpNum; /* Bulk In endpoint number - 0x313*/ - - UCHAR Bulk3DesStatus; /* Bulk endpoint transfer descriptor status - 0x314*/ - UCHAR Bulk3DesTbytes0; /* Bulk endpoint transfer descriptor control - 0x315*/ - UCHAR Bulk3DesTbytes1; /* Bulk endpoint transfer descriptor lower total bytes - 0x316*/ - UCHAR Bulk3DesTbytes2; /* Bulk endpoint transfer descriptor higer total bytes - 0x317*/ - - UCHAR Reserved4[0x20]; /*0x318 ~ 0x33F ; 0x33F - 0x318 + 1 = 0x28*/ - - UCHAR ControlDataBuf[64]; /*0x340~0x37F Control Endpoint Data Buffer */ -}__attribute__((packed)); - -/*DMA_Context_Control*/ -/*1:IF0-->peripheral 0:peripher-->IF0*/ -#define DMA_TRANS_OUT_DIR 0x00400000 -/*1:Run 0:Stop Scheduled*/ -#define DMA_RUN 0x00000080 - -/*DMA Interrupt Enable*/ -/*enable interfac 0 interrupt*/ -#define DMA_INTERRUPT_ENABLE0 0x00000001 -/*enable interfac 1 interrupt*/ -#define DMA_INTERRUPT_ENABLE1 0x00000002 -/*enable interfac 2 interrupt*/ -#define DMA_INTERRUPT_ENABLE2 0x00000010 - -/*enable interfac 0 status*/ -#define DMA_INTERRUPT_STATUS0 0x00000001 -/*enable interfac 1 status*/ -#define DMA_INTERRUPT_STATUS1 0x00000002 -/*enable interfac 2 status*/ -#define DMA_INTERRUPT_STATUS2 0x00000004 - -struct UDC_DMA_REG { - union { /*Rx00 - DMA Global Register (0x100~0x103)*/ - UINT DMA_Global; - struct { - UINT DMAConrollerEnable:1; - UINT Reserved0:7; - UINT SoftwareReset:1; - UINT SoftwareReset0:1; - UINT SoftwareReset1:1; - UINT SoftwareReset2:1; - UINT Reserved1:20; - } DMA_Global_Bits; - }; - - union { /*Rx04 - DMA Interrupt Enable (0x104~x107)*/ - UINT DMA_IER; - struct { - UINT DMAInterruptEnable0:1; - UINT DMAInterruptEnable1:1; - UINT Reserved:2; - UINT DMAInterruptEnable2:1; - UINT Reserved1:27; - } DMA_IER_Bits; - }; - - union { /*Rx08 - DMA Interrupt Status Register (0x108~0x10b)*/ - UINT DMA_ISR; - struct { - UINT InterruptStatus0:1; - UINT InterruptStatus1:1; - UINT InterruptStatus2:1; - UINT Reserved:29; - } DMA_ISR_Bits; - }; - - /*Interface 0*/ - union {/*Rx10c - DMA Memory-Descriptor Point Register dor Interdace 0 (0x10c~0x10f)*/ - UINT DMA_Descriptor_Point0; - struct { - UINT Reserved:2; - UINT DesBaseAddr:30; - } DMA_Descriptor_Point0_Bits; - }; - - union { /*Rx110 - DMA Residual Bytes Register for Interface 0 (Rx110~Rx103)*/ - UINT DMA_Residual_Bytes0; - struct { - UINT ResidualBytes:16; - UINT IntEn:1; - UINT Reseved:13; - UINT Format:1; - UINT End:1; - } DMA_Residual_Bytes0_Bits; - }; - - /*Rx114 - DMA Data Address Register for Interface 0 (0x114~0x117)*/ - UINT DMA_Data_Addr0; - - union {/*Rx118 DMA Branch Address Register for INterface 0(0x118~0x11b)*/ - UINT DMA_Branch_Addr0; - struct { - UINT Reserved:4; - UINT BranchDesxriptorAddress:28; - } DMA_Branch_Addr0_Bits; - }; - - union {/*Rx11c DMA command Pointer Register for Interrface 0(0x11c~0x11f)*/ - UINT Descriptor_Addr0; - struct { - UINT Reserved:4; - UINT DescriptorAddr:28; - } Descriptor_Addr0_Bits; - }; - - union {/*Rx120 DMA Context Control Register for Interfaxe 0(0x120~0x123)*/ - UINT DMA_Context_Control0; - struct { - UINT EventCode:4; - UINT Reserved0:3; - UINT Run:1; - UINT Active:1; - UINT P0Cmpl:1; - UINT Reserved1:2; - UINT Prot:4; - UINT Reserved2:6; - UINT TransDir:1; - UINT Reserved3:9; - } DMA_Context_Control0_Bis; - }; - - /*Interface 1*/ - union {/*Rx124 - DMA Memory-Descriptor Point Register dor Interdace 1 (0x124~0x127)*/ - UINT DMA_Descriptor_Point1; - struct { - UINT Reserved:2; - UINT DesBaseAddr:30; - } DMA_Descriptor_Point1_Bits; - }; - - union { /*Rx128 - DMA Residual Bytes Register for Interface 1 (Rx128~Rx12b)*/ - UINT DMA_Residual_Bytes1; - struct { - UINT ResidualBytes:16; - UINT IntEn:1; - UINT Reseved:13; - UINT Format:1; - UINT End:1; - } DMA_Residual_Bytes1_Bits; - }; - - /*Rx12c - DMA Data Address Register for Interface 1 (0x12c~0x12f)*/ - UINT DMA_Data_Addr1; - - union {/*Rx130 DMA Branch Address Register for INterface 10(0x130~0x133)*/ - UINT DMA_Branch_Addr1; - struct { - UINT Reserved:4; - UINT BranchDesxriptorAddress:28; - } DMA_Branch_Addr1_Bits; - }; - - union {/*Rx134 DMA command Pointer Register for Interrface 1(0x134~0x137)*/ - UINT Descriptor_Addr1; - struct { - UINT Reserved:4; - UINT DescriptorAddr:28; - } Descriptor_Addr1_Bits; - }; - - union {/*Rx138DMA Context Control Register for Interfaxe 1(0x138~0x13b)*/ - UINT DMA_Context_Control1; - struct { - UINT EventCode:4; - UINT Reserved0:3; - UINT Run:1; - UINT Active:1; - UINT P0Cmpl:1; - UINT Reserved1:2; - UINT Prot:4; - UINT Reserved2:6; - UINT TransDir:1; - UINT Reserved3:9; - } DMA_Context_Control1_Bis; - }; - - /*Interface 2*/ - union {/*Rx13c - DMA Memory-Descriptor Point Register dor Interdace 2 (0x10c~0x10f)*/ - UINT DMA_Descriptor_Point2; - struct { - UINT Reserved:2; - UINT DesBaseAddr:30; - } DMA_Descriptor_Point2_Bits; - }; - - union { /*Rx140 - DMA Residual Bytes Register for Interface 2 (Rx110~Rx103)*/ - UINT DMA_Residual_Bytes2; - struct { - UINT ResidualBytes:16; - UINT IntEn:1; - UINT Reseved:13; - UINT Format:1; - UINT End:1; - } DMA_Residual_Bytes2_Bits; - }; - - /*Rx144 - DMA Data Address Register for Interface 2 (0x144~0x147)*/ - UINT DMA_Data_Addr2; - - union {/*Rx148 DMA Branch Address Register for INterface 2(0x148~0x14b)*/ - UINT DMA_Branch_Addr2; - struct { - UINT Reserved:4; - UINT BranchDesxriptorAddress:28; - } DMA_Branch_Addr2_Bits; - }; - - union {/*Rx14c DMA command Pointer Register for Interrface 2(0x14c~0x14f)*/ - UINT Descriptor_Addr2; - struct { - UINT Reserved:4; - UINT DescriptorAddr:28; - } Descriptor_Addr2_Bits; - }; - - union {/*Rx150 DMA Context Control Register for Interfaxe 2(0x150~0x153)*/ - UINT DMA_Context_Control2; - struct { - UINT EventCode:4; - UINT Reserved0:3; - UINT Run:1; - UINT Active:1; - UINT P0Cmpl:1; - UINT Reserved1:2; - UINT Prot:4; - UINT Reserved2:6; - UINT TransDir:1; - UINT Reserved3:9; - } DMA_Context_Control2_Bis; - }; - -}__attribute__((packed)); - -#define DESCRIPTOT_TYPE_SHORT 0 -#define DESCRIPTOT_TYPE_LONG 1 -#define DESCRIPTOT_TYPE_MIX 2 - -#define TRANS_OUT 1 -#define TRANS_IN 0 - -#define DES_L_SIZE 0x10 -#define DES_S_SIZE 0x4 - - -/* - * PDMA Descriptor short - */ -struct _UDC_PDMA_DESC_S { - union { - UINT D_Word0; - struct { - UINT ReqCount:16; /* bit 0 -15 -Request count*/ - UINT i:1; /* bit 16 -interrupt*/ - UINT Reserved:13; - UINT Format:1; /* bit 30 -The descriptor format*/ - UINT End:1; /* bit 31-End flag of descriptor list*/ - } D_Word0_Bits; - }; - - UINT Data_Addr; /* bit 0-31 -Data Buffer address*/ -}__attribute__((packed)); - -/* - * PDMA Descriptor long - */ - -struct _UDC_PDMA_DESC_L { - union { - UINT D_Word0; - struct { - UINT ReqCount:16; /* bit 0 -15-Request count*/ - UINT i:1; /* bit 16-interrupt*/ - UINT Reserved:13; - UINT Format:1; /* bit 30-The descriptor format*/ - UINT End:1; /* bit 31-End flag of descriptor list*/ - } D_Word0_Bits; - }; - - UINT Data_Addr; /* bit 0-31 -Data Buffer address*/ - - union { - UINT Branch_addr; - struct { - UINT Reserved:2; - UINT BranchAddr:30; /* bit 31-2 -Descriptor Branch address*/ - } Branch_addr_Bits; - }; - - UINT Reserve0; -}__attribute__((packed)); - -/*Rx00 - UHDC Interrupt Status Register*/ -#define UHDC_INT_UDC 0x0300 -//#define UHDC_INT_UDC_DMA2 0x0400 -#define UHDC_INT_UDC_DMA1 0x0200 -#define UHDC_INT_UDC_CORE 0x0100 - -#ifdef OTGIP -/*UHDC Global Register Space : 0x7F0~0x7F7*/ -struct USB_GLOBAL_REG { - union { /*Rx00 - UHDC Interrupt Status Register*/ - USHORT UHDC_Interrupt_Status; - struct { - USHORT EHCIInt:1; /* [0] EHCI Interrupt bit*/ - USHORT UHCIInt:1; /* [1] UHCI Interrupt bit*/ - USHORT Reserved0:6; /* reserved for future use*/ - USHORT UDCCoreInt:1; /* [8] UDC Core Interrupt bit(IOC/Babble/Bus Activity)*/ - USHORT UDCDMA1Int:1; /* [9] DMA1 Interrupt bit (Bulk Transfer)*/ - USHORT UDCDMA2Int:1; /* [10] DMA2 Interrupt bit (Bulk Transfer)*/ - USHORT Reserved1:5; /* reserved for future use*/ - } UHDC_Interrupt_Status_Bits; - }; - - union { /*Rx01 - UHDC ID Status Register*/ - UCHAR UHDC_ID_Status; - struct { - UCHAR DualRoleID:1; /* Dual-Role USB Controller ID Value*/ - UCHAR Reserved:7; /* reserved for future use*/ - } UHDC_ID_Status_Bits; - }; - - union { /*Rx02 - UHDC Offchip Power Control Register*/ - UCHAR UHDC_OffChip_PowerControl; - struct { - UCHAR PowerSupplyMode:1; /* Power Supply Mode Select (1)SW mode (0)HW mode*/ - UCHAR PowerSupplySWEn:1; /* Power Supply SW Mode Enable bit */ - UCHAR Reserved:6; /* reserved for future use */ - } UHDC_OffChip_PowerControl_Bits; - }; - - union { /*Rx03 - UHDC Clock Reset Control Register*/ - USHORT UHDC_Clock_Reset_Control; - struct { - USHORT AHBClkGatingEn:1; /* [0] AHB clock Gating Enable bit*/ - USHORT HCSuspendClkGatingEn:1; /* [1] Host Controller Suspend Clock Gating Enable bit*/ - USHORT DCSuspendClkGatingEn:1; /* [2] Device Controller Suspend Clock Gating Enable bit*/ - USHORT DataReceivingClkGatingEn:1;/* [3] Controller Data-Receiving Clock Gating Enable bit*/ - USHORT Phy120MClkGatingEn:1; /* [4] Phy 120M Clock Gating Enable bit*/ - USHORT Phy60MClkGatingEn:1; /* [5] Phy 60M Clock Gating Enable bit*/ - USHORT Phy48MClkGatingEn:1; /* [6] Phy 48M Clock Gating Enable bit */ - USHORT Reserved0:1; /* [7] reserved for future use*/ - USHORT AHBResetGatingEn:1; /* [8] AHB Bus Reset Gating Enable bit*/ - USHORT PowerOnResetGatingEn:1; /* [9] Power-on Reset Gating Enable bit */ - USHORT Reserved1:6; /* [15:10] reserved for future use*/ - } UHDC_Clock_Reset_Control_Bits; - }; - - union { /*Rx04 - UHDC Pullup/Pulldown Control Register*/ - USHORT UHDC_Pull_Up_Down_Control; - struct { - USHORT PullUpDownSWControlEn:1; /* [0] Pullup/Pulldown SW Control Enable bit*/ - USHORT DPLinePullUpEn:1; /* [1] DP Line Pullup Enable bit*/ - USHORT DPLinePullDownEn:1; /* [2] DP Line Pulldown Enable bit*/ - USHORT DMLinePullDownEn:1; /* [3] DM Line Pulldown Enable bit*/ - USHORT HSTerminationRegisterEn:1; /* [4] High Speed Termination Register On bit*/ - USHORT Reserved1:11; /* [15:5] reserved for future use*/ - } UHDC_Pull_Up_Down_Control_Bits; - }; -}__attribute__((packed)); -#endif - -#define UDC_FULL_SPEED 0 -#define UDC_HIGH_SPEED 1 -/* Define the setup command buffer*/ - -#define MAX_TRANSFER_LENGTH 0x200 /* original is 0x20000, shift 16bits for minimum block size is 0x200*/ -/*HP04_End*/ - -/* Define the interrupt transfer buffer*/ -#define INTBUFFERSTART 0x308 /* the start byte of interrupt transfer buffer*/ -#define INTBUFFEREND 0x30F /* the last byte of interrupt transfer buffer*/ -#define INTBUFFERSIZE 0x08 /* the size of the interrupt transfer buffer*/ - -/* Define the control endpoint buffer*/ -#define CONTROLBUFFERSTART 0x340 /* the start byte of the control data buffer*/ -#define CONTROLBUFFEREND 0x37F /* the last byte of the control data buffer*/ -#define CONTROLBUFFERSIZE 0x40 /* the size of the control data buffer*/ - -/* Define the bulk transfer buffer*/ -#define BULKBUFFERSTART 0x800 /* the start byte of the bulk transfer buffer*/ -#define BULKBUFFEREND 0xFFF /* the last byte of the bulk transfer buffer*/ -#define BULKBUFFERSIZE 0x800 /* the size of the bulk transfer buffer*/ - -/* define the endpoint number for each endpoint*/ -#define BULKINEPNUM 0x01 -/*HP01_begin*/ -#define BULKOUTEPNUM 0x02 -/*HP01_End*/ -#define INTEPNUM 0x03 -#define MAXEPNUM 0x04 -/* define the structure of string table for default strings and vendor specified strings*/ - -/* define the IO state of USB to handle */ -#define IOSTATE_CBWIDLE 0x00 /* usb is idle and set the 8051 clock to stop*/ -#define IOSTATE_ACCEPTCBW 0x01 /* the usb accept a new CBW*/ -#define IOSTATE_DEVICEPREPAREIO 0x02 /* the state will call deivce startio to prepare IO*/ -#define IOSTATE_STARTIO 0x03 /* the CBW send to device to start IO operation*/ -#define IOSTATE_CSW 0x04 /* the state to send CSW back to host*/ -#define IOSTATE_CSWCOMPLETE 0x05 /* the CSW is returned, maybe need some more process*/ -#define IOSTATE_TIMEOUT 0x06 /* the IO is hang to long and it is timeout*/ -#define IOSTATE_FWDOWNLOAD 0x07 /* Download the new firmware.*/ -#define IOSTATE_WAITFORCBW 0x08 /* In this state, the controller is waiting for CBW*/ -#define IOSTATE_CSWIDLE 0x09 /* the idle state for wait for CSW complete, 8051 will stopped*/ - -/*VT3214 Define */ -/* define the state of Control endpoint*/ -#define CONTROLSTATE_SETUP 0x00 /* the control endpoint is in the Setup state*/ -#define CONTROLSTATE_DATA 0x01 /* the control endpoint is in the Data state*/ -#define CONTROLSTATE_STATUS 0x02 /* the control endpoint is in the Status state*/ - - -/* VT3300 PACK Size Defination*/ -#define UCE_MAX_DMA ((unsigned)64) -#define UIE_MAX_DMA ((unsigned)8) -#define UBE_MAX_DMA ((unsigned)0x20000) /* max length = 128K */ -#define EP0_FIFO_SIZE ((unsigned)64) -#define BULK_FIFO_SIZE ((unsigned)512) -#define INT_FIFO_SIZE ((unsigned)8) - -/* Define the setup command buffer*/ -typedef struct _SETUP_COMMAND -{ -unsigned char RequestType; /* the Request type of the SETUP command*/ -unsigned char Request; /* the Request code of the SETUP command*/ -unsigned char ValueLow; /* the lower value field of the SETUP command*/ -unsigned char ValueHigh; /* the higher value field of the SETUP command*/ -unsigned char IndexLow; /* the lower index field of the SETUP command*/ -unsigned char IndexHigh; /* the higher index field of the SETUP command*/ -unsigned char LengthLow; /* the lower length field of the SETUP command*/ -unsigned char LengthHigh; /* the higher length field of the SETUP command*/ -} SETUPCOMMAND, *PSETUPCOMMAND; - - - -struct vt8500_ep { - struct usb_ep ep; - struct list_head queue; - unsigned long irqs; - const struct usb_endpoint_descriptor *desc; - char name[14]; - u16 maxpacket; - u8 bEndpointAddress; - u8 bmAttributes; - unsigned double_buf:1; - unsigned stopped:1; - unsigned fnf:1; - unsigned has_dma:1; - unsigned toggle_bit:1; - unsigned stall:1; - unsigned rndis:1; - u8 ackwait; - /*u8 dma_channel;*/ - u32 dma_counter; - /*int lch;*/ - struct vt8500_udc *udc; - struct timer_list timer; - /*volatile u32 *reg_payload_addr;*/ - /*volatile u32 *reg_control_status;*/ - /*volatile u32 *reg_irp_descriptor;*/ - - /*volatile u32 temp_payload_addr;*/ - /*volatile u32 temp_control_status;*/ - - volatile u32 temp_buffer_address; - volatile u32 temp_dma_phy_address; - volatile u32 temp_buffer_address2; - volatile u32 temp_dma_phy_address2; - - /*volatile u32 temp_req_length;*/ - /*volatile u32 temp_irp_descriptor; */ - volatile u32 rndis_buffer_address; - volatile u32 rndis_dma_phy_address; - unsigned int rndis_buffer_length; - unsigned int rndis_buffer_alloc ; - - /*processing stall and clear stall.*/ - volatile u32 stall_more_processing; - volatile u32 temp_dcmd; - volatile u32 temp_dma_ccr; - volatile u32 temp_bulk_dma_addr; - volatile u32 ep_stall_toggle_bit; - volatile u32 ep_fifo_length; - -}__attribute__((packed)); - -struct vt8500_req { - struct usb_request req; - struct list_head queue; - unsigned dma_bytes; - struct vt8500_ep *ep; - struct list_head mem_list; /* sw qtd list */ - unsigned mapped:1; -}__attribute__((packed)); - - -struct vt8500_udc { - struct device *dev; - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - spinlock_t lock; -// struct vt8500_ep ep[5]; - struct vt8500_ep ep[7];//gri - u16 devstat; - u16 ep0_in_status; - volatile u32 cbw_virtual_address; - /*volatile u32 ep3_virtual_address; */ - struct usb_phy *transceiver; - unsigned softconnect:1; - unsigned vbus_active:1; - unsigned ep0_pending:1; - unsigned ep0_in:1; - unsigned ep0_set_config:1; - unsigned ep0_reset_config:1; - unsigned ep0_setup:1; - unsigned ep0_status_0_byte:1; - unsigned usb_connect:1; - unsigned file_storage_set_halt:1; - unsigned bulk_out_dma_write_error:1; - unsigned int chip_version; - struct completion *done; - u8 setup_command[8]; - struct timer_list timer; -}__attribute__((packed)); - -/*-------------------------------------------------------------------------*/ - -//#define DEBUG -//#define VERBOSE - -#ifdef DEBUG -#define DBG(stuff...) printk(KERN_INFO "udc: " stuff) -#else -#define DBG(stuff...) do{}while(0) -#endif - -#ifdef VERBOSE -#define VDBG DBG -#else -#define VDBG(stuff...) do{}while(0) -#endif - -#define ERR(stuff...) printk(KERN_ERR "udc: " stuff) -//#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff) -#define INFO(stuff...) printk(KERN_INFO "udc: " stuff) - -#define USB_BULK_RESET_REQUEST 0xff -/*--------------------------------------------------------------------*/ - -/*static void vt8500_ep_setup_csr(char *name, u8 addr, u8 type, unsigned maxp);*/ -/*static void vt8500_udc_csr(struct vt8500_udc *udc);*/ - -#endif /* __LINUX_USB_GADGET_VT8500_H */ diff --git a/ANDROID_3.4.5/drivers/usb/gadget/usbstring.c b/ANDROID_3.4.5/drivers/usb/gadget/usbstring.c deleted file mode 100644 index 4d25b900..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/usbstring.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2003 David Brownell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - -/** - * usb_gadget_get_string - fill out a string descriptor - * @table: of c strings encoded using UTF-8 - * @id: string id, from low byte of wValue in get string descriptor - * @buf: at least 256 bytes, must be 16-bit aligned - * - * Finds the UTF-8 string matching the ID, and converts it into a - * string descriptor in utf16-le. - * Returns length of descriptor (always even) or negative errno - * - * If your driver needs stings in multiple languages, you'll probably - * "switch (wIndex) { ... }" in your ep0 string descriptor logic, - * using this routine after choosing which set of UTF-8 strings to use. - * Note that US-ASCII is a strict subset of UTF-8; any string bytes with - * the eighth bit set will be multibyte UTF-8 characters, not ISO-8859/1 - * characters (which are also widely used in C strings). - */ -int -usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf) -{ - struct usb_string *s; - int len; - - /* descriptor 0 has the language id */ - if (id == 0) { - buf [0] = 4; - buf [1] = USB_DT_STRING; - buf [2] = (u8) table->language; - buf [3] = (u8) (table->language >> 8); - return 4; - } - for (s = table->strings; s && s->s; s++) - if (s->id == id) - break; - - /* unrecognized: stall. */ - if (!s || !s->s) - return -EINVAL; - - /* string descriptors have length, tag, then UTF16-LE text */ - len = min ((size_t) 126, strlen (s->s)); - len = utf8s_to_utf16s(s->s, len, UTF16_LITTLE_ENDIAN, - (wchar_t *) &buf[2], 126); - if (len < 0) - return -EINVAL; - buf [0] = (len + 1) * 2; - buf [1] = USB_DT_STRING; - return buf [0]; -} - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/uvc.h b/ANDROID_3.4.5/drivers/usb/gadget/uvc.h deleted file mode 100644 index ca4e03a1..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/uvc.h +++ /dev/null @@ -1,199 +0,0 @@ -/* - * uvc_gadget.h -- USB Video Class Gadget driver - * - * Copyright (C) 2009-2010 - * Laurent Pinchart (laurent.pinchart@ideasonboard.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef _UVC_GADGET_H_ -#define _UVC_GADGET_H_ - -#include -#include -#include - -#define UVC_EVENT_FIRST (V4L2_EVENT_PRIVATE_START + 0) -#define UVC_EVENT_CONNECT (V4L2_EVENT_PRIVATE_START + 0) -#define UVC_EVENT_DISCONNECT (V4L2_EVENT_PRIVATE_START + 1) -#define UVC_EVENT_STREAMON (V4L2_EVENT_PRIVATE_START + 2) -#define UVC_EVENT_STREAMOFF (V4L2_EVENT_PRIVATE_START + 3) -#define UVC_EVENT_SETUP (V4L2_EVENT_PRIVATE_START + 4) -#define UVC_EVENT_DATA (V4L2_EVENT_PRIVATE_START + 5) -#define UVC_EVENT_LAST (V4L2_EVENT_PRIVATE_START + 5) - -struct uvc_request_data -{ - __s32 length; - __u8 data[60]; -}; - -struct uvc_event -{ - union { - enum usb_device_speed speed; - struct usb_ctrlrequest req; - struct uvc_request_data data; - }; -}; - -#define UVCIOC_SEND_RESPONSE _IOW('U', 1, struct uvc_request_data) - -#define UVC_INTF_CONTROL 0 -#define UVC_INTF_STREAMING 1 - -/* ------------------------------------------------------------------------ - * Debugging, printing and logging - */ - -#ifdef __KERNEL__ - -#include /* For usb_endpoint_* */ -#include -#include -#include -#include - -#include "uvc_queue.h" - -#define UVC_TRACE_PROBE (1 << 0) -#define UVC_TRACE_DESCR (1 << 1) -#define UVC_TRACE_CONTROL (1 << 2) -#define UVC_TRACE_FORMAT (1 << 3) -#define UVC_TRACE_CAPTURE (1 << 4) -#define UVC_TRACE_CALLS (1 << 5) -#define UVC_TRACE_IOCTL (1 << 6) -#define UVC_TRACE_FRAME (1 << 7) -#define UVC_TRACE_SUSPEND (1 << 8) -#define UVC_TRACE_STATUS (1 << 9) - -#define UVC_WARN_MINMAX 0 -#define UVC_WARN_PROBE_DEF 1 - -extern unsigned int uvc_gadget_trace_param; - -#define uvc_trace(flag, msg...) \ - do { \ - if (uvc_gadget_trace_param & flag) \ - printk(KERN_DEBUG "uvcvideo: " msg); \ - } while (0) - -#define uvc_warn_once(dev, warn, msg...) \ - do { \ - if (!test_and_set_bit(warn, &dev->warnings)) \ - printk(KERN_INFO "uvcvideo: " msg); \ - } while (0) - -#define uvc_printk(level, msg...) \ - printk(level "uvcvideo: " msg) - -/* ------------------------------------------------------------------------ - * Driver specific constants - */ - -#define DRIVER_VERSION "0.1.0" -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 1, 0) - -#define DMA_ADDR_INVALID (~(dma_addr_t)0) - -#define UVC_NUM_REQUESTS 4 -#define UVC_MAX_REQUEST_SIZE 64 -#define UVC_MAX_EVENTS 4 - -/* ------------------------------------------------------------------------ - * Structures - */ - -struct uvc_video -{ - struct usb_ep *ep; - - /* Frame parameters */ - u8 bpp; - u32 fcc; - unsigned int width; - unsigned int height; - unsigned int imagesize; - - /* Requests */ - unsigned int req_size; - struct usb_request *req[UVC_NUM_REQUESTS]; - __u8 *req_buffer[UVC_NUM_REQUESTS]; - struct list_head req_free; - spinlock_t req_lock; - - void (*encode) (struct usb_request *req, struct uvc_video *video, - struct uvc_buffer *buf); - - /* Context data used by the completion handler */ - __u32 payload_size; - __u32 max_payload_size; - - struct uvc_video_queue queue; - unsigned int fid; -}; - -enum uvc_state -{ - UVC_STATE_DISCONNECTED, - UVC_STATE_CONNECTED, - UVC_STATE_STREAMING, -}; - -struct uvc_device -{ - struct video_device *vdev; - enum uvc_state state; - struct usb_function func; - struct uvc_video video; - - /* Descriptors */ - struct { - const struct uvc_descriptor_header * const *control; - const struct uvc_descriptor_header * const *fs_streaming; - const struct uvc_descriptor_header * const *hs_streaming; - } desc; - - unsigned int control_intf; - struct usb_ep *control_ep; - struct usb_request *control_req; - void *control_buf; - - unsigned int streaming_intf; - - /* Events */ - unsigned int event_length; - unsigned int event_setup_out : 1; -}; - -static inline struct uvc_device *to_uvc(struct usb_function *f) -{ - return container_of(f, struct uvc_device, func); -} - -struct uvc_file_handle -{ - struct v4l2_fh vfh; - struct uvc_video *device; -}; - -#define to_uvc_file_handle(handle) \ - container_of(handle, struct uvc_file_handle, vfh) - -/* ------------------------------------------------------------------------ - * Functions - */ - -extern void uvc_endpoint_stream(struct uvc_device *dev); - -extern void uvc_function_connect(struct uvc_device *uvc); -extern void uvc_function_disconnect(struct uvc_device *uvc); - -#endif /* __KERNEL__ */ - -#endif /* _UVC_GADGET_H_ */ - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/uvc_queue.c b/ANDROID_3.4.5/drivers/usb/gadget/uvc_queue.c deleted file mode 100644 index 0cdf89d3..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/uvc_queue.c +++ /dev/null @@ -1,585 +0,0 @@ -/* - * uvc_queue.c -- USB Video Class driver - Buffers management - * - * Copyright (C) 2005-2010 - * Laurent Pinchart (laurent.pinchart@ideasonboard.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "uvc.h" - -/* ------------------------------------------------------------------------ - * Video buffers queue management. - * - * Video queues is initialized by uvc_queue_init(). The function performs - * basic initialization of the uvc_video_queue struct and never fails. - * - * Video buffer allocation and freeing are performed by uvc_alloc_buffers and - * uvc_free_buffers respectively. The former acquires the video queue lock, - * while the later must be called with the lock held (so that allocation can - * free previously allocated buffers). Trying to free buffers that are mapped - * to user space will return -EBUSY. - * - * Video buffers are managed using two queues. However, unlike most USB video - * drivers that use an in queue and an out queue, we use a main queue to hold - * all queued buffers (both 'empty' and 'done' buffers), and an irq queue to - * hold empty buffers. This design (copied from video-buf) minimizes locking - * in interrupt, as only one queue is shared between interrupt and user - * contexts. - * - * Use cases - * --------- - * - * Unless stated otherwise, all operations that modify the irq buffers queue - * are protected by the irq spinlock. - * - * 1. The user queues the buffers, starts streaming and dequeues a buffer. - * - * The buffers are added to the main and irq queues. Both operations are - * protected by the queue lock, and the later is protected by the irq - * spinlock as well. - * - * The completion handler fetches a buffer from the irq queue and fills it - * with video data. If no buffer is available (irq queue empty), the handler - * returns immediately. - * - * When the buffer is full, the completion handler removes it from the irq - * queue, marks it as ready (UVC_BUF_STATE_DONE) and wakes its wait queue. - * At that point, any process waiting on the buffer will be woken up. If a - * process tries to dequeue a buffer after it has been marked ready, the - * dequeing will succeed immediately. - * - * 2. Buffers are queued, user is waiting on a buffer and the device gets - * disconnected. - * - * When the device is disconnected, the kernel calls the completion handler - * with an appropriate status code. The handler marks all buffers in the - * irq queue as being erroneous (UVC_BUF_STATE_ERROR) and wakes them up so - * that any process waiting on a buffer gets woken up. - * - * Waking up up the first buffer on the irq list is not enough, as the - * process waiting on the buffer might restart the dequeue operation - * immediately. - * - */ - -static void -uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type) -{ - mutex_init(&queue->mutex); - spin_lock_init(&queue->irqlock); - INIT_LIST_HEAD(&queue->mainqueue); - INIT_LIST_HEAD(&queue->irqqueue); - queue->type = type; -} - -/* - * Free the video buffers. - * - * This function must be called with the queue lock held. - */ -static int uvc_free_buffers(struct uvc_video_queue *queue) -{ - unsigned int i; - - for (i = 0; i < queue->count; ++i) { - if (queue->buffer[i].vma_use_count != 0) - return -EBUSY; - } - - if (queue->count) { - vfree(queue->mem); - queue->count = 0; - } - - return 0; -} - -/* - * Allocate the video buffers. - * - * Pages are reserved to make sure they will not be swapped, as they will be - * filled in the URB completion handler. - * - * Buffers will be individually mapped, so they must all be page aligned. - */ -static int -uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers, - unsigned int buflength) -{ - unsigned int bufsize = PAGE_ALIGN(buflength); - unsigned int i; - void *mem = NULL; - int ret; - - if (nbuffers > UVC_MAX_VIDEO_BUFFERS) - nbuffers = UVC_MAX_VIDEO_BUFFERS; - - mutex_lock(&queue->mutex); - - if ((ret = uvc_free_buffers(queue)) < 0) - goto done; - - /* Bail out if no buffers should be allocated. */ - if (nbuffers == 0) - goto done; - - /* Decrement the number of buffers until allocation succeeds. */ - for (; nbuffers > 0; --nbuffers) { - mem = vmalloc_32(nbuffers * bufsize); - if (mem != NULL) - break; - } - - if (mem == NULL) { - ret = -ENOMEM; - goto done; - } - - for (i = 0; i < nbuffers; ++i) { - memset(&queue->buffer[i], 0, sizeof queue->buffer[i]); - queue->buffer[i].buf.index = i; - queue->buffer[i].buf.m.offset = i * bufsize; - queue->buffer[i].buf.length = buflength; - queue->buffer[i].buf.type = queue->type; - queue->buffer[i].buf.sequence = 0; - queue->buffer[i].buf.field = V4L2_FIELD_NONE; - queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP; - queue->buffer[i].buf.flags = 0; - init_waitqueue_head(&queue->buffer[i].wait); - } - - queue->mem = mem; - queue->count = nbuffers; - queue->buf_size = bufsize; - ret = nbuffers; - -done: - mutex_unlock(&queue->mutex); - return ret; -} - -static void __uvc_query_buffer(struct uvc_buffer *buf, - struct v4l2_buffer *v4l2_buf) -{ - memcpy(v4l2_buf, &buf->buf, sizeof *v4l2_buf); - - if (buf->vma_use_count) - v4l2_buf->flags |= V4L2_BUF_FLAG_MAPPED; - - switch (buf->state) { - case UVC_BUF_STATE_ERROR: - case UVC_BUF_STATE_DONE: - v4l2_buf->flags |= V4L2_BUF_FLAG_DONE; - break; - case UVC_BUF_STATE_QUEUED: - case UVC_BUF_STATE_ACTIVE: - v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED; - break; - case UVC_BUF_STATE_IDLE: - default: - break; - } -} - -static int -uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf) -{ - int ret = 0; - - mutex_lock(&queue->mutex); - if (v4l2_buf->index >= queue->count) { - ret = -EINVAL; - goto done; - } - - __uvc_query_buffer(&queue->buffer[v4l2_buf->index], v4l2_buf); - -done: - mutex_unlock(&queue->mutex); - return ret; -} - -/* - * Queue a video buffer. Attempting to queue a buffer that has already been - * queued will return -EINVAL. - */ -static int -uvc_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf) -{ - struct uvc_buffer *buf; - unsigned long flags; - int ret = 0; - - uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index); - - if (v4l2_buf->type != queue->type || - v4l2_buf->memory != V4L2_MEMORY_MMAP) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) " - "and/or memory (%u).\n", v4l2_buf->type, - v4l2_buf->memory); - return -EINVAL; - } - - mutex_lock(&queue->mutex); - if (v4l2_buf->index >= queue->count) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Out of range index.\n"); - ret = -EINVAL; - goto done; - } - - buf = &queue->buffer[v4l2_buf->index]; - if (buf->state != UVC_BUF_STATE_IDLE) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state " - "(%u).\n", buf->state); - ret = -EINVAL; - goto done; - } - - if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && - v4l2_buf->bytesused > buf->buf.length) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n"); - ret = -EINVAL; - goto done; - } - - if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - buf->buf.bytesused = 0; - else - buf->buf.bytesused = v4l2_buf->bytesused; - - spin_lock_irqsave(&queue->irqlock, flags); - if (queue->flags & UVC_QUEUE_DISCONNECTED) { - spin_unlock_irqrestore(&queue->irqlock, flags); - ret = -ENODEV; - goto done; - } - buf->state = UVC_BUF_STATE_QUEUED; - - ret = (queue->flags & UVC_QUEUE_PAUSED) != 0; - queue->flags &= ~UVC_QUEUE_PAUSED; - - list_add_tail(&buf->stream, &queue->mainqueue); - list_add_tail(&buf->queue, &queue->irqqueue); - spin_unlock_irqrestore(&queue->irqlock, flags); - -done: - mutex_unlock(&queue->mutex); - return ret; -} - -static int uvc_queue_waiton(struct uvc_buffer *buf, int nonblocking) -{ - if (nonblocking) { - return (buf->state != UVC_BUF_STATE_QUEUED && - buf->state != UVC_BUF_STATE_ACTIVE) - ? 0 : -EAGAIN; - } - - return wait_event_interruptible(buf->wait, - buf->state != UVC_BUF_STATE_QUEUED && - buf->state != UVC_BUF_STATE_ACTIVE); -} - -/* - * Dequeue a video buffer. If nonblocking is false, block until a buffer is - * available. - */ -static int -uvc_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf, - int nonblocking) -{ - struct uvc_buffer *buf; - int ret = 0; - - if (v4l2_buf->type != queue->type || - v4l2_buf->memory != V4L2_MEMORY_MMAP) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) " - "and/or memory (%u).\n", v4l2_buf->type, - v4l2_buf->memory); - return -EINVAL; - } - - mutex_lock(&queue->mutex); - if (list_empty(&queue->mainqueue)) { - uvc_trace(UVC_TRACE_CAPTURE, "[E] Empty buffer queue.\n"); - ret = -EINVAL; - goto done; - } - - buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream); - if ((ret = uvc_queue_waiton(buf, nonblocking)) < 0) - goto done; - - uvc_trace(UVC_TRACE_CAPTURE, "Dequeuing buffer %u (%u, %u bytes).\n", - buf->buf.index, buf->state, buf->buf.bytesused); - - switch (buf->state) { - case UVC_BUF_STATE_ERROR: - uvc_trace(UVC_TRACE_CAPTURE, "[W] Corrupted data " - "(transmission error).\n"); - ret = -EIO; - case UVC_BUF_STATE_DONE: - buf->state = UVC_BUF_STATE_IDLE; - break; - - case UVC_BUF_STATE_IDLE: - case UVC_BUF_STATE_QUEUED: - case UVC_BUF_STATE_ACTIVE: - default: - uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state %u " - "(driver bug?).\n", buf->state); - ret = -EINVAL; - goto done; - } - - list_del(&buf->stream); - __uvc_query_buffer(buf, v4l2_buf); - -done: - mutex_unlock(&queue->mutex); - return ret; -} - -/* - * Poll the video queue. - * - * This function implements video queue polling and is intended to be used by - * the device poll handler. - */ -static unsigned int -uvc_queue_poll(struct uvc_video_queue *queue, struct file *file, - poll_table *wait) -{ - struct uvc_buffer *buf; - unsigned int mask = 0; - - mutex_lock(&queue->mutex); - if (list_empty(&queue->mainqueue)) - goto done; - - buf = list_first_entry(&queue->mainqueue, struct uvc_buffer, stream); - - poll_wait(file, &buf->wait, wait); - if (buf->state == UVC_BUF_STATE_DONE || - buf->state == UVC_BUF_STATE_ERROR) - mask |= POLLOUT | POLLWRNORM; - -done: - mutex_unlock(&queue->mutex); - return mask; -} - -/* - * VMA operations. - */ -static void uvc_vm_open(struct vm_area_struct *vma) -{ - struct uvc_buffer *buffer = vma->vm_private_data; - buffer->vma_use_count++; -} - -static void uvc_vm_close(struct vm_area_struct *vma) -{ - struct uvc_buffer *buffer = vma->vm_private_data; - buffer->vma_use_count--; -} - -static struct vm_operations_struct uvc_vm_ops = { - .open = uvc_vm_open, - .close = uvc_vm_close, -}; - -/* - * Memory-map a buffer. - * - * This function implements video buffer memory mapping and is intended to be - * used by the device mmap handler. - */ -static int -uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma) -{ - struct uvc_buffer *uninitialized_var(buffer); - struct page *page; - unsigned long addr, start, size; - unsigned int i; - int ret = 0; - - start = vma->vm_start; - size = vma->vm_end - vma->vm_start; - - mutex_lock(&queue->mutex); - - for (i = 0; i < queue->count; ++i) { - buffer = &queue->buffer[i]; - if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) - break; - } - - if (i == queue->count || size != queue->buf_size) { - ret = -EINVAL; - goto done; - } - - /* - * VM_IO marks the area as being an mmaped region for I/O to a - * device. It also prevents the region from being core dumped. - */ - vma->vm_flags |= VM_IO; - - addr = (unsigned long)queue->mem + buffer->buf.m.offset; - while (size > 0) { - page = vmalloc_to_page((void *)addr); - if ((ret = vm_insert_page(vma, start, page)) < 0) - goto done; - - start += PAGE_SIZE; - addr += PAGE_SIZE; - size -= PAGE_SIZE; - } - - vma->vm_ops = &uvc_vm_ops; - vma->vm_private_data = buffer; - uvc_vm_open(vma); - -done: - mutex_unlock(&queue->mutex); - return ret; -} - -/* - * Cancel the video buffers queue. - * - * Cancelling the queue marks all buffers on the irq queue as erroneous, - * wakes them up and removes them from the queue. - * - * If the disconnect parameter is set, further calls to uvc_queue_buffer will - * fail with -ENODEV. - * - * This function acquires the irq spinlock and can be called from interrupt - * context. - */ -static void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect) -{ - struct uvc_buffer *buf; - unsigned long flags; - - spin_lock_irqsave(&queue->irqlock, flags); - while (!list_empty(&queue->irqqueue)) { - buf = list_first_entry(&queue->irqqueue, struct uvc_buffer, - queue); - list_del(&buf->queue); - buf->state = UVC_BUF_STATE_ERROR; - wake_up(&buf->wait); - } - /* This must be protected by the irqlock spinlock to avoid race - * conditions between uvc_queue_buffer and the disconnection event that - * could result in an interruptible wait in uvc_dequeue_buffer. Do not - * blindly replace this logic by checking for the UVC_DEV_DISCONNECTED - * state outside the queue code. - */ - if (disconnect) - queue->flags |= UVC_QUEUE_DISCONNECTED; - spin_unlock_irqrestore(&queue->irqlock, flags); -} - -/* - * Enable or disable the video buffers queue. - * - * The queue must be enabled before starting video acquisition and must be - * disabled after stopping it. This ensures that the video buffers queue - * state can be properly initialized before buffers are accessed from the - * interrupt handler. - * - * Enabling the video queue initializes parameters (such as sequence number, - * sync pattern, ...). If the queue is already enabled, return -EBUSY. - * - * Disabling the video queue cancels the queue and removes all buffers from - * the main queue. - * - * This function can't be called from interrupt context. Use - * uvc_queue_cancel() instead. - */ -static int uvc_queue_enable(struct uvc_video_queue *queue, int enable) -{ - unsigned int i; - int ret = 0; - - mutex_lock(&queue->mutex); - if (enable) { - if (uvc_queue_streaming(queue)) { - ret = -EBUSY; - goto done; - } - queue->sequence = 0; - queue->flags |= UVC_QUEUE_STREAMING; - queue->buf_used = 0; - } else { - uvc_queue_cancel(queue, 0); - INIT_LIST_HEAD(&queue->mainqueue); - - for (i = 0; i < queue->count; ++i) - queue->buffer[i].state = UVC_BUF_STATE_IDLE; - - queue->flags &= ~UVC_QUEUE_STREAMING; - } - -done: - mutex_unlock(&queue->mutex); - return ret; -} - -/* called with queue->irqlock held.. */ -static struct uvc_buffer * -uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf) -{ - struct uvc_buffer *nextbuf; - - if ((queue->flags & UVC_QUEUE_DROP_INCOMPLETE) && - buf->buf.length != buf->buf.bytesused) { - buf->state = UVC_BUF_STATE_QUEUED; - buf->buf.bytesused = 0; - return buf; - } - - list_del(&buf->queue); - if (!list_empty(&queue->irqqueue)) - nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer, - queue); - else - nextbuf = NULL; - - buf->buf.sequence = queue->sequence++; - do_gettimeofday(&buf->buf.timestamp); - - wake_up(&buf->wait); - return nextbuf; -} - -static struct uvc_buffer *uvc_queue_head(struct uvc_video_queue *queue) -{ - struct uvc_buffer *buf = NULL; - - if (!list_empty(&queue->irqqueue)) - buf = list_first_entry(&queue->irqqueue, struct uvc_buffer, - queue); - else - queue->flags |= UVC_QUEUE_PAUSED; - - return buf; -} - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/uvc_queue.h b/ANDROID_3.4.5/drivers/usb/gadget/uvc_queue.h deleted file mode 100644 index 1812a8ec..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/uvc_queue.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef _UVC_QUEUE_H_ -#define _UVC_QUEUE_H_ - -#ifdef __KERNEL__ - -#include -#include -#include - -/* Maximum frame size in bytes, for sanity checking. */ -#define UVC_MAX_FRAME_SIZE (16*1024*1024) -/* Maximum number of video buffers. */ -#define UVC_MAX_VIDEO_BUFFERS 32 - -/* ------------------------------------------------------------------------ - * Structures. - */ - -enum uvc_buffer_state { - UVC_BUF_STATE_IDLE = 0, - UVC_BUF_STATE_QUEUED = 1, - UVC_BUF_STATE_ACTIVE = 2, - UVC_BUF_STATE_DONE = 3, - UVC_BUF_STATE_ERROR = 4, -}; - -struct uvc_buffer { - unsigned long vma_use_count; - struct list_head stream; - - /* Touched by interrupt handler. */ - struct v4l2_buffer buf; - struct list_head queue; - wait_queue_head_t wait; - enum uvc_buffer_state state; -}; - -#define UVC_QUEUE_STREAMING (1 << 0) -#define UVC_QUEUE_DISCONNECTED (1 << 1) -#define UVC_QUEUE_DROP_INCOMPLETE (1 << 2) -#define UVC_QUEUE_PAUSED (1 << 3) - -struct uvc_video_queue { - enum v4l2_buf_type type; - - void *mem; - unsigned int flags; - __u32 sequence; - - unsigned int count; - unsigned int buf_size; - unsigned int buf_used; - struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS]; - struct mutex mutex; /* protects buffers and mainqueue */ - spinlock_t irqlock; /* protects irqqueue */ - - struct list_head mainqueue; - struct list_head irqqueue; -}; - -static inline int uvc_queue_streaming(struct uvc_video_queue *queue) -{ - return queue->flags & UVC_QUEUE_STREAMING; -} - -#endif /* __KERNEL__ */ - -#endif /* _UVC_QUEUE_H_ */ - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/uvc_v4l2.c b/ANDROID_3.4.5/drivers/usb/gadget/uvc_v4l2.c deleted file mode 100644 index 54d7ca55..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/uvc_v4l2.c +++ /dev/null @@ -1,356 +0,0 @@ -/* - * uvc_v4l2.c -- USB Video Class Gadget driver - * - * Copyright (C) 2009-2010 - * Laurent Pinchart (laurent.pinchart@ideasonboard.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "uvc.h" -#include "uvc_queue.h" - -/* -------------------------------------------------------------------------- - * Requests handling - */ - -static int -uvc_send_response(struct uvc_device *uvc, struct uvc_request_data *data) -{ - struct usb_composite_dev *cdev = uvc->func.config->cdev; - struct usb_request *req = uvc->control_req; - - if (data->length < 0) - return usb_ep_set_halt(cdev->gadget->ep0); - - req->length = min_t(unsigned int, uvc->event_length, data->length); - req->zero = data->length < uvc->event_length; - req->dma = DMA_ADDR_INVALID; - - memcpy(req->buf, data->data, data->length); - - return usb_ep_queue(cdev->gadget->ep0, req, GFP_KERNEL); -} - -/* -------------------------------------------------------------------------- - * V4L2 - */ - -struct uvc_format -{ - u8 bpp; - u32 fcc; -}; - -static struct uvc_format uvc_formats[] = { - { 16, V4L2_PIX_FMT_YUYV }, - { 0, V4L2_PIX_FMT_MJPEG }, -}; - -static int -uvc_v4l2_get_format(struct uvc_video *video, struct v4l2_format *fmt) -{ - fmt->fmt.pix.pixelformat = video->fcc; - fmt->fmt.pix.width = video->width; - fmt->fmt.pix.height = video->height; - fmt->fmt.pix.field = V4L2_FIELD_NONE; - fmt->fmt.pix.bytesperline = video->bpp * video->width / 8; - fmt->fmt.pix.sizeimage = video->imagesize; - fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; - fmt->fmt.pix.priv = 0; - - return 0; -} - -static int -uvc_v4l2_set_format(struct uvc_video *video, struct v4l2_format *fmt) -{ - struct uvc_format *format; - unsigned int imagesize; - unsigned int bpl; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(uvc_formats); ++i) { - format = &uvc_formats[i]; - if (format->fcc == fmt->fmt.pix.pixelformat) - break; - } - - if (i == ARRAY_SIZE(uvc_formats)) { - printk(KERN_INFO "Unsupported format 0x%08x.\n", - fmt->fmt.pix.pixelformat); - return -EINVAL; - } - - bpl = format->bpp * fmt->fmt.pix.width / 8; - imagesize = bpl ? bpl * fmt->fmt.pix.height : fmt->fmt.pix.sizeimage; - - video->fcc = format->fcc; - video->bpp = format->bpp; - video->width = fmt->fmt.pix.width; - video->height = fmt->fmt.pix.height; - video->imagesize = imagesize; - - fmt->fmt.pix.field = V4L2_FIELD_NONE; - fmt->fmt.pix.bytesperline = bpl; - fmt->fmt.pix.sizeimage = imagesize; - fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; - fmt->fmt.pix.priv = 0; - - return 0; -} - -static int -uvc_v4l2_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct uvc_device *uvc = video_get_drvdata(vdev); - struct uvc_file_handle *handle; - - handle = kzalloc(sizeof(*handle), GFP_KERNEL); - if (handle == NULL) - return -ENOMEM; - - v4l2_fh_init(&handle->vfh, vdev); - v4l2_fh_add(&handle->vfh); - - handle->device = &uvc->video; - file->private_data = &handle->vfh; - - uvc_function_connect(uvc); - return 0; -} - -static int -uvc_v4l2_release(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct uvc_device *uvc = video_get_drvdata(vdev); - struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data); - struct uvc_video *video = handle->device; - - uvc_function_disconnect(uvc); - - uvc_video_enable(video, 0); - mutex_lock(&video->queue.mutex); - if (uvc_free_buffers(&video->queue) < 0) - printk(KERN_ERR "uvc_v4l2_release: Unable to free " - "buffers.\n"); - mutex_unlock(&video->queue.mutex); - - file->private_data = NULL; - v4l2_fh_del(&handle->vfh); - v4l2_fh_exit(&handle->vfh); - kfree(handle); - return 0; -} - -static long -uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) -{ - struct video_device *vdev = video_devdata(file); - struct uvc_device *uvc = video_get_drvdata(vdev); - struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data); - struct usb_composite_dev *cdev = uvc->func.config->cdev; - struct uvc_video *video = &uvc->video; - int ret = 0; - - switch (cmd) { - /* Query capabilities */ - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *cap = arg; - - memset(cap, 0, sizeof *cap); - strncpy(cap->driver, "g_uvc", sizeof(cap->driver)); - strncpy(cap->card, cdev->gadget->name, sizeof(cap->card)); - strncpy(cap->bus_info, dev_name(&cdev->gadget->dev), - sizeof cap->bus_info); - cap->version = DRIVER_VERSION_NUMBER; - cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; - break; - } - - /* Get & Set format */ - case VIDIOC_G_FMT: - { - struct v4l2_format *fmt = arg; - - if (fmt->type != video->queue.type) - return -EINVAL; - - return uvc_v4l2_get_format(video, fmt); - } - - case VIDIOC_S_FMT: - { - struct v4l2_format *fmt = arg; - - if (fmt->type != video->queue.type) - return -EINVAL; - - return uvc_v4l2_set_format(video, fmt); - } - - /* Buffers & streaming */ - case VIDIOC_REQBUFS: - { - struct v4l2_requestbuffers *rb = arg; - - if (rb->type != video->queue.type || - rb->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - ret = uvc_alloc_buffers(&video->queue, rb->count, - video->imagesize); - if (ret < 0) - return ret; - - rb->count = ret; - ret = 0; - break; - } - - case VIDIOC_QUERYBUF: - { - struct v4l2_buffer *buf = arg; - - if (buf->type != video->queue.type) - return -EINVAL; - - return uvc_query_buffer(&video->queue, buf); - } - - case VIDIOC_QBUF: - if ((ret = uvc_queue_buffer(&video->queue, arg)) < 0) - return ret; - - return uvc_video_pump(video); - - case VIDIOC_DQBUF: - return uvc_dequeue_buffer(&video->queue, arg, - file->f_flags & O_NONBLOCK); - - case VIDIOC_STREAMON: - { - int *type = arg; - - if (*type != video->queue.type) - return -EINVAL; - - return uvc_video_enable(video, 1); - } - - case VIDIOC_STREAMOFF: - { - int *type = arg; - - if (*type != video->queue.type) - return -EINVAL; - - return uvc_video_enable(video, 0); - } - - /* Events */ - case VIDIOC_DQEVENT: - { - struct v4l2_event *event = arg; - - ret = v4l2_event_dequeue(&handle->vfh, event, - file->f_flags & O_NONBLOCK); - if (ret == 0 && event->type == UVC_EVENT_SETUP) { - struct uvc_event *uvc_event = (void *)&event->u.data; - - /* Tell the complete callback to generate an event for - * the next request that will be enqueued by - * uvc_event_write. - */ - uvc->event_setup_out = - !(uvc_event->req.bRequestType & USB_DIR_IN); - uvc->event_length = uvc_event->req.wLength; - } - - return ret; - } - - case VIDIOC_SUBSCRIBE_EVENT: - { - struct v4l2_event_subscription *sub = arg; - - if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST) - return -EINVAL; - - return v4l2_event_subscribe(&handle->vfh, arg, 2); - } - - case VIDIOC_UNSUBSCRIBE_EVENT: - return v4l2_event_unsubscribe(&handle->vfh, arg); - - case UVCIOC_SEND_RESPONSE: - ret = uvc_send_response(uvc, arg); - break; - - default: - return -ENOIOCTLCMD; - } - - return ret; -} - -static long -uvc_v4l2_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - return video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl); -} - -static int -uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct video_device *vdev = video_devdata(file); - struct uvc_device *uvc = video_get_drvdata(vdev); - - return uvc_queue_mmap(&uvc->video.queue, vma); -} - -static unsigned int -uvc_v4l2_poll(struct file *file, poll_table *wait) -{ - struct video_device *vdev = video_devdata(file); - struct uvc_device *uvc = video_get_drvdata(vdev); - struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data); - unsigned int mask = 0; - - poll_wait(file, &handle->vfh.wait, wait); - if (v4l2_event_pending(&handle->vfh)) - mask |= POLLPRI; - - mask |= uvc_queue_poll(&uvc->video.queue, file, wait); - - return mask; -} - -static struct v4l2_file_operations uvc_v4l2_fops = { - .owner = THIS_MODULE, - .open = uvc_v4l2_open, - .release = uvc_v4l2_release, - .ioctl = uvc_v4l2_ioctl, - .mmap = uvc_v4l2_mmap, - .poll = uvc_v4l2_poll, -}; - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/uvc_video.c b/ANDROID_3.4.5/drivers/usb/gadget/uvc_video.c deleted file mode 100644 index b0e53a8e..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/uvc_video.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - * uvc_video.c -- USB Video Class Gadget driver - * - * Copyright (C) 2009-2010 - * Laurent Pinchart (laurent.pinchart@ideasonboard.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include - -#include - -#include "uvc.h" -#include "uvc_queue.h" - -/* -------------------------------------------------------------------------- - * Video codecs - */ - -static int -uvc_video_encode_header(struct uvc_video *video, struct uvc_buffer *buf, - u8 *data, int len) -{ - data[0] = 2; - data[1] = UVC_STREAM_EOH | video->fid; - - if (buf->buf.bytesused - video->queue.buf_used <= len - 2) - data[1] |= UVC_STREAM_EOF; - - return 2; -} - -static int -uvc_video_encode_data(struct uvc_video *video, struct uvc_buffer *buf, - u8 *data, int len) -{ - struct uvc_video_queue *queue = &video->queue; - unsigned int nbytes; - void *mem; - - /* Copy video data to the USB buffer. */ - mem = queue->mem + buf->buf.m.offset + queue->buf_used; - nbytes = min((unsigned int)len, buf->buf.bytesused - queue->buf_used); - - memcpy(data, mem, nbytes); - queue->buf_used += nbytes; - - return nbytes; -} - -static void -uvc_video_encode_bulk(struct usb_request *req, struct uvc_video *video, - struct uvc_buffer *buf) -{ - void *mem = req->buf; - int len = video->req_size; - int ret; - - /* Add a header at the beginning of the payload. */ - if (video->payload_size == 0) { - ret = uvc_video_encode_header(video, buf, mem, len); - video->payload_size += ret; - mem += ret; - len -= ret; - } - - /* Process video data. */ - len = min((int)(video->max_payload_size - video->payload_size), len); - ret = uvc_video_encode_data(video, buf, mem, len); - - video->payload_size += ret; - len -= ret; - - req->length = video->req_size - len; - req->zero = video->payload_size == video->max_payload_size; - - if (buf->buf.bytesused == video->queue.buf_used) { - video->queue.buf_used = 0; - buf->state = UVC_BUF_STATE_DONE; - uvc_queue_next_buffer(&video->queue, buf); - video->fid ^= UVC_STREAM_FID; - - video->payload_size = 0; - } - - if (video->payload_size == video->max_payload_size || - buf->buf.bytesused == video->queue.buf_used) - video->payload_size = 0; -} - -static void -uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video, - struct uvc_buffer *buf) -{ - void *mem = req->buf; - int len = video->req_size; - int ret; - - /* Add the header. */ - ret = uvc_video_encode_header(video, buf, mem, len); - mem += ret; - len -= ret; - - /* Process video data. */ - ret = uvc_video_encode_data(video, buf, mem, len); - len -= ret; - - req->length = video->req_size - len; - - if (buf->buf.bytesused == video->queue.buf_used) { - video->queue.buf_used = 0; - buf->state = UVC_BUF_STATE_DONE; - uvc_queue_next_buffer(&video->queue, buf); - video->fid ^= UVC_STREAM_FID; - } -} - -/* -------------------------------------------------------------------------- - * Request handling - */ - -/* - * I somehow feel that synchronisation won't be easy to achieve here. We have - * three events that control USB requests submission: - * - * - USB request completion: the completion handler will resubmit the request - * if a video buffer is available. - * - * - USB interface setting selection: in response to a SET_INTERFACE request, - * the handler will start streaming if a video buffer is available and if - * video is not currently streaming. - * - * - V4L2 buffer queueing: the driver will start streaming if video is not - * currently streaming. - * - * Race conditions between those 3 events might lead to deadlocks or other - * nasty side effects. - * - * The "video currently streaming" condition can't be detected by the irqqueue - * being empty, as a request can still be in flight. A separate "queue paused" - * flag is thus needed. - * - * The paused flag will be set when we try to retrieve the irqqueue head if the - * queue is empty, and cleared when we queue a buffer. - * - * The USB request completion handler will get the buffer at the irqqueue head - * under protection of the queue spinlock. If the queue is empty, the streaming - * paused flag will be set. Right after releasing the spinlock a userspace - * application can queue a buffer. The flag will then cleared, and the ioctl - * handler will restart the video stream. - */ -static void -uvc_video_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct uvc_video *video = req->context; - struct uvc_buffer *buf; - unsigned long flags; - int ret; - - switch (req->status) { - case 0: - break; - - case -ESHUTDOWN: - printk(KERN_INFO "VS request cancelled.\n"); - goto requeue; - - default: - printk(KERN_INFO "VS request completed with status %d.\n", - req->status); - goto requeue; - } - - spin_lock_irqsave(&video->queue.irqlock, flags); - buf = uvc_queue_head(&video->queue); - if (buf == NULL) { - spin_unlock_irqrestore(&video->queue.irqlock, flags); - goto requeue; - } - - video->encode(req, video, buf); - - if ((ret = usb_ep_queue(ep, req, GFP_ATOMIC)) < 0) { - printk(KERN_INFO "Failed to queue request (%d).\n", ret); - usb_ep_set_halt(ep); - spin_unlock_irqrestore(&video->queue.irqlock, flags); - goto requeue; - } - spin_unlock_irqrestore(&video->queue.irqlock, flags); - - return; - -requeue: - spin_lock_irqsave(&video->req_lock, flags); - list_add_tail(&req->list, &video->req_free); - spin_unlock_irqrestore(&video->req_lock, flags); -} - -static int -uvc_video_free_requests(struct uvc_video *video) -{ - unsigned int i; - - for (i = 0; i < UVC_NUM_REQUESTS; ++i) { - if (video->req[i]) { - usb_ep_free_request(video->ep, video->req[i]); - video->req[i] = NULL; - } - - if (video->req_buffer[i]) { - kfree(video->req_buffer[i]); - video->req_buffer[i] = NULL; - } - } - - INIT_LIST_HEAD(&video->req_free); - video->req_size = 0; - return 0; -} - -static int -uvc_video_alloc_requests(struct uvc_video *video) -{ - unsigned int i; - int ret = -ENOMEM; - - BUG_ON(video->req_size); - - for (i = 0; i < UVC_NUM_REQUESTS; ++i) { - video->req_buffer[i] = kmalloc(video->ep->maxpacket, GFP_KERNEL); - if (video->req_buffer[i] == NULL) - goto error; - - video->req[i] = usb_ep_alloc_request(video->ep, GFP_KERNEL); - if (video->req[i] == NULL) - goto error; - - video->req[i]->buf = video->req_buffer[i]; - video->req[i]->length = 0; - video->req[i]->dma = DMA_ADDR_INVALID; - video->req[i]->complete = uvc_video_complete; - video->req[i]->context = video; - - list_add_tail(&video->req[i]->list, &video->req_free); - } - - video->req_size = video->ep->maxpacket; - return 0; - -error: - uvc_video_free_requests(video); - return ret; -} - -/* -------------------------------------------------------------------------- - * Video streaming - */ - -/* - * uvc_video_pump - Pump video data into the USB requests - * - * This function fills the available USB requests (listed in req_free) with - * video data from the queued buffers. - */ -static int -uvc_video_pump(struct uvc_video *video) -{ - struct usb_request *req; - struct uvc_buffer *buf; - unsigned long flags; - int ret; - - /* FIXME TODO Race between uvc_video_pump and requests completion - * handler ??? - */ - - while (1) { - /* Retrieve the first available USB request, protected by the - * request lock. - */ - spin_lock_irqsave(&video->req_lock, flags); - if (list_empty(&video->req_free)) { - spin_unlock_irqrestore(&video->req_lock, flags); - return 0; - } - req = list_first_entry(&video->req_free, struct usb_request, - list); - list_del(&req->list); - spin_unlock_irqrestore(&video->req_lock, flags); - - /* Retrieve the first available video buffer and fill the - * request, protected by the video queue irqlock. - */ - spin_lock_irqsave(&video->queue.irqlock, flags); - buf = uvc_queue_head(&video->queue); - if (buf == NULL) { - spin_unlock_irqrestore(&video->queue.irqlock, flags); - break; - } - - video->encode(req, video, buf); - - /* Queue the USB request */ - if ((ret = usb_ep_queue(video->ep, req, GFP_KERNEL)) < 0) { - printk(KERN_INFO "Failed to queue request (%d)\n", ret); - usb_ep_set_halt(video->ep); - spin_unlock_irqrestore(&video->queue.irqlock, flags); - break; - } - spin_unlock_irqrestore(&video->queue.irqlock, flags); - } - - spin_lock_irqsave(&video->req_lock, flags); - list_add_tail(&req->list, &video->req_free); - spin_unlock_irqrestore(&video->req_lock, flags); - return 0; -} - -/* - * Enable or disable the video stream. - */ -static int -uvc_video_enable(struct uvc_video *video, int enable) -{ - unsigned int i; - int ret; - - if (video->ep == NULL) { - printk(KERN_INFO "Video enable failed, device is " - "uninitialized.\n"); - return -ENODEV; - } - - if (!enable) { - for (i = 0; i < UVC_NUM_REQUESTS; ++i) - usb_ep_dequeue(video->ep, video->req[i]); - - uvc_video_free_requests(video); - uvc_queue_enable(&video->queue, 0); - return 0; - } - - if ((ret = uvc_queue_enable(&video->queue, 1)) < 0) - return ret; - - if ((ret = uvc_video_alloc_requests(video)) < 0) - return ret; - - if (video->max_payload_size) { - video->encode = uvc_video_encode_bulk; - video->payload_size = 0; - } else - video->encode = uvc_video_encode_isoc; - - return uvc_video_pump(video); -} - -/* - * Initialize the UVC video stream. - */ -static int -uvc_video_init(struct uvc_video *video) -{ - INIT_LIST_HEAD(&video->req_free); - spin_lock_init(&video->req_lock); - - video->fcc = V4L2_PIX_FMT_YUYV; - video->bpp = 16; - video->width = 320; - video->height = 240; - video->imagesize = 320 * 240 * 2; - - /* Initialize the video buffers queue. */ - uvc_queue_init(&video->queue, V4L2_BUF_TYPE_VIDEO_OUTPUT); - return 0; -} - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/webcam.c b/ANDROID_3.4.5/drivers/usb/gadget/webcam.c deleted file mode 100644 index 668fe128..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/webcam.c +++ /dev/null @@ -1,399 +0,0 @@ -/* - * webcam.c -- USB webcam gadget driver - * - * Copyright (C) 2009-2010 - * Laurent Pinchart (laurent.pinchart@ideasonboard.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include - -#include "f_uvc.h" - -/* - * 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 "uvc_queue.c" -#include "uvc_video.c" -#include "uvc_v4l2.c" -#include "f_uvc.c" - -/* -------------------------------------------------------------------------- - * Device descriptor - */ - -#define WEBCAM_VENDOR_ID 0x1d6b /* Linux Foundation */ -#define WEBCAM_PRODUCT_ID 0x0102 /* Webcam A/V gadget */ -#define WEBCAM_DEVICE_BCD 0x0010 /* 0.10 */ - -static char webcam_vendor_label[] = "Linux Foundation"; -static char webcam_product_label[] = "Webcam gadget"; -static char webcam_config_label[] = "Video"; - -/* string IDs are assigned dynamically */ - -#define STRING_MANUFACTURER_IDX 0 -#define STRING_PRODUCT_IDX 1 -#define STRING_DESCRIPTION_IDX 2 - -static struct usb_string webcam_strings[] = { - [STRING_MANUFACTURER_IDX].s = webcam_vendor_label, - [STRING_PRODUCT_IDX].s = webcam_product_label, - [STRING_DESCRIPTION_IDX].s = webcam_config_label, - { } -}; - -static struct usb_gadget_strings webcam_stringtab = { - .language = 0x0409, /* en-us */ - .strings = webcam_strings, -}; - -static struct usb_gadget_strings *webcam_device_strings[] = { - &webcam_stringtab, - NULL, -}; - -static struct usb_device_descriptor webcam_device_descriptor = { - .bLength = USB_DT_DEVICE_SIZE, - .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_MISC, - .bDeviceSubClass = 0x02, - .bDeviceProtocol = 0x01, - .bMaxPacketSize0 = 0, /* dynamic */ - .idVendor = cpu_to_le16(WEBCAM_VENDOR_ID), - .idProduct = cpu_to_le16(WEBCAM_PRODUCT_ID), - .bcdDevice = cpu_to_le16(WEBCAM_DEVICE_BCD), - .iManufacturer = 0, /* dynamic */ - .iProduct = 0, /* dynamic */ - .iSerialNumber = 0, /* dynamic */ - .bNumConfigurations = 0, /* dynamic */ -}; - -DECLARE_UVC_HEADER_DESCRIPTOR(1); - -static const struct UVC_HEADER_DESCRIPTOR(1) uvc_control_header = { - .bLength = UVC_DT_HEADER_SIZE(1), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = UVC_VC_HEADER, - .bcdUVC = cpu_to_le16(0x0100), - .wTotalLength = 0, /* dynamic */ - .dwClockFrequency = cpu_to_le32(48000000), - .bInCollection = 0, /* dynamic */ - .baInterfaceNr[0] = 0, /* dynamic */ -}; - -static const struct uvc_camera_terminal_descriptor uvc_camera_terminal = { - .bLength = UVC_DT_CAMERA_TERMINAL_SIZE(3), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = UVC_VC_INPUT_TERMINAL, - .bTerminalID = 1, - .wTerminalType = cpu_to_le16(0x0201), - .bAssocTerminal = 0, - .iTerminal = 0, - .wObjectiveFocalLengthMin = cpu_to_le16(0), - .wObjectiveFocalLengthMax = cpu_to_le16(0), - .wOcularFocalLength = cpu_to_le16(0), - .bControlSize = 3, - .bmControls[0] = 2, - .bmControls[1] = 0, - .bmControls[2] = 0, -}; - -static const struct uvc_processing_unit_descriptor uvc_processing = { - .bLength = UVC_DT_PROCESSING_UNIT_SIZE(2), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = UVC_VC_PROCESSING_UNIT, - .bUnitID = 2, - .bSourceID = 1, - .wMaxMultiplier = cpu_to_le16(16*1024), - .bControlSize = 2, - .bmControls[0] = 1, - .bmControls[1] = 0, - .iProcessing = 0, -}; - -static const struct uvc_output_terminal_descriptor uvc_output_terminal = { - .bLength = UVC_DT_OUTPUT_TERMINAL_SIZE, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = UVC_VC_OUTPUT_TERMINAL, - .bTerminalID = 3, - .wTerminalType = cpu_to_le16(0x0101), - .bAssocTerminal = 0, - .bSourceID = 2, - .iTerminal = 0, -}; - -DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(1, 2); - -static const struct UVC_INPUT_HEADER_DESCRIPTOR(1, 2) uvc_input_header = { - .bLength = UVC_DT_INPUT_HEADER_SIZE(1, 2), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = UVC_VS_INPUT_HEADER, - .bNumFormats = 2, - .wTotalLength = 0, /* dynamic */ - .bEndpointAddress = 0, /* dynamic */ - .bmInfo = 0, - .bTerminalLink = 3, - .bStillCaptureMethod = 0, - .bTriggerSupport = 0, - .bTriggerUsage = 0, - .bControlSize = 1, - .bmaControls[0][0] = 0, - .bmaControls[1][0] = 4, -}; - -static const struct uvc_format_uncompressed uvc_format_yuv = { - .bLength = UVC_DT_FORMAT_UNCOMPRESSED_SIZE, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = UVC_VS_FORMAT_UNCOMPRESSED, - .bFormatIndex = 1, - .bNumFrameDescriptors = 2, - .guidFormat = - { 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, - 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}, - .bBitsPerPixel = 16, - .bDefaultFrameIndex = 1, - .bAspectRatioX = 0, - .bAspectRatioY = 0, - .bmInterfaceFlags = 0, - .bCopyProtect = 0, -}; - -DECLARE_UVC_FRAME_UNCOMPRESSED(1); -DECLARE_UVC_FRAME_UNCOMPRESSED(3); - -static const struct UVC_FRAME_UNCOMPRESSED(3) uvc_frame_yuv_360p = { - .bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(3), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = UVC_VS_FRAME_UNCOMPRESSED, - .bFrameIndex = 1, - .bmCapabilities = 0, - .wWidth = cpu_to_le16(640), - .wHeight = cpu_to_le16(360), - .dwMinBitRate = cpu_to_le32(18432000), - .dwMaxBitRate = cpu_to_le32(55296000), - .dwMaxVideoFrameBufferSize = cpu_to_le32(460800), - .dwDefaultFrameInterval = cpu_to_le32(666666), - .bFrameIntervalType = 3, - .dwFrameInterval[0] = cpu_to_le32(666666), - .dwFrameInterval[1] = cpu_to_le32(1000000), - .dwFrameInterval[2] = cpu_to_le32(5000000), -}; - -static const struct UVC_FRAME_UNCOMPRESSED(1) uvc_frame_yuv_720p = { - .bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(1), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = UVC_VS_FRAME_UNCOMPRESSED, - .bFrameIndex = 2, - .bmCapabilities = 0, - .wWidth = cpu_to_le16(1280), - .wHeight = cpu_to_le16(720), - .dwMinBitRate = cpu_to_le32(29491200), - .dwMaxBitRate = cpu_to_le32(29491200), - .dwMaxVideoFrameBufferSize = cpu_to_le32(1843200), - .dwDefaultFrameInterval = cpu_to_le32(5000000), - .bFrameIntervalType = 1, - .dwFrameInterval[0] = cpu_to_le32(5000000), -}; - -static const struct uvc_format_mjpeg uvc_format_mjpg = { - .bLength = UVC_DT_FORMAT_MJPEG_SIZE, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = UVC_VS_FORMAT_MJPEG, - .bFormatIndex = 2, - .bNumFrameDescriptors = 2, - .bmFlags = 0, - .bDefaultFrameIndex = 1, - .bAspectRatioX = 0, - .bAspectRatioY = 0, - .bmInterfaceFlags = 0, - .bCopyProtect = 0, -}; - -DECLARE_UVC_FRAME_MJPEG(1); -DECLARE_UVC_FRAME_MJPEG(3); - -static const struct UVC_FRAME_MJPEG(3) uvc_frame_mjpg_360p = { - .bLength = UVC_DT_FRAME_MJPEG_SIZE(3), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = UVC_VS_FRAME_MJPEG, - .bFrameIndex = 1, - .bmCapabilities = 0, - .wWidth = cpu_to_le16(640), - .wHeight = cpu_to_le16(360), - .dwMinBitRate = cpu_to_le32(18432000), - .dwMaxBitRate = cpu_to_le32(55296000), - .dwMaxVideoFrameBufferSize = cpu_to_le32(460800), - .dwDefaultFrameInterval = cpu_to_le32(666666), - .bFrameIntervalType = 3, - .dwFrameInterval[0] = cpu_to_le32(666666), - .dwFrameInterval[1] = cpu_to_le32(1000000), - .dwFrameInterval[2] = cpu_to_le32(5000000), -}; - -static const struct UVC_FRAME_MJPEG(1) uvc_frame_mjpg_720p = { - .bLength = UVC_DT_FRAME_MJPEG_SIZE(1), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = UVC_VS_FRAME_MJPEG, - .bFrameIndex = 2, - .bmCapabilities = 0, - .wWidth = cpu_to_le16(1280), - .wHeight = cpu_to_le16(720), - .dwMinBitRate = cpu_to_le32(29491200), - .dwMaxBitRate = cpu_to_le32(29491200), - .dwMaxVideoFrameBufferSize = cpu_to_le32(1843200), - .dwDefaultFrameInterval = cpu_to_le32(5000000), - .bFrameIntervalType = 1, - .dwFrameInterval[0] = cpu_to_le32(5000000), -}; - -static const struct uvc_color_matching_descriptor uvc_color_matching = { - .bLength = UVC_DT_COLOR_MATCHING_SIZE, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = UVC_VS_COLORFORMAT, - .bColorPrimaries = 1, - .bTransferCharacteristics = 1, - .bMatrixCoefficients = 4, -}; - -static const struct uvc_descriptor_header * const uvc_control_cls[] = { - (const struct uvc_descriptor_header *) &uvc_control_header, - (const struct uvc_descriptor_header *) &uvc_camera_terminal, - (const struct uvc_descriptor_header *) &uvc_processing, - (const struct uvc_descriptor_header *) &uvc_output_terminal, - NULL, -}; - -static const struct uvc_descriptor_header * const uvc_fs_streaming_cls[] = { - (const struct uvc_descriptor_header *) &uvc_input_header, - (const struct uvc_descriptor_header *) &uvc_format_yuv, - (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p, - (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p, - (const struct uvc_descriptor_header *) &uvc_format_mjpg, - (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p, - (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p, - (const struct uvc_descriptor_header *) &uvc_color_matching, - NULL, -}; - -static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = { - (const struct uvc_descriptor_header *) &uvc_input_header, - (const struct uvc_descriptor_header *) &uvc_format_yuv, - (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p, - (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p, - (const struct uvc_descriptor_header *) &uvc_format_mjpg, - (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p, - (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p, - (const struct uvc_descriptor_header *) &uvc_color_matching, - NULL, -}; - -/* -------------------------------------------------------------------------- - * USB configuration - */ - -static int __init -webcam_config_bind(struct usb_configuration *c) -{ - return uvc_bind_config(c, uvc_control_cls, uvc_fs_streaming_cls, - uvc_hs_streaming_cls); -} - -static struct usb_configuration webcam_config_driver = { - .label = webcam_config_label, - .bConfigurationValue = 1, - .iConfiguration = 0, /* dynamic */ - .bmAttributes = USB_CONFIG_ATT_SELFPOWER, - .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2, -}; - -static int /* __init_or_exit */ -webcam_unbind(struct usb_composite_dev *cdev) -{ - return 0; -} - -static int __init -webcam_bind(struct usb_composite_dev *cdev) -{ - int ret; - - /* Allocate string descriptor numbers ... note that string contents - * can be overridden by the composite_dev glue. - */ - if ((ret = usb_string_id(cdev)) < 0) - goto error; - webcam_strings[STRING_MANUFACTURER_IDX].id = ret; - webcam_device_descriptor.iManufacturer = ret; - - if ((ret = usb_string_id(cdev)) < 0) - goto error; - webcam_strings[STRING_PRODUCT_IDX].id = ret; - webcam_device_descriptor.iProduct = ret; - - if ((ret = usb_string_id(cdev)) < 0) - goto error; - webcam_strings[STRING_DESCRIPTION_IDX].id = ret; - webcam_config_driver.iConfiguration = ret; - - /* Register our configuration. */ - if ((ret = usb_add_config(cdev, &webcam_config_driver, - webcam_config_bind)) < 0) - goto error; - - INFO(cdev, "Webcam Video Gadget\n"); - return 0; - -error: - webcam_unbind(cdev); - return ret; -} - -/* -------------------------------------------------------------------------- - * Driver - */ - -static struct usb_composite_driver webcam_driver = { - .name = "g_webcam", - .dev = &webcam_device_descriptor, - .strings = webcam_device_strings, - .max_speed = USB_SPEED_HIGH, - .unbind = webcam_unbind, -}; - -static int __init -webcam_init(void) -{ - return usb_composite_probe(&webcam_driver, webcam_bind); -} - -static void __exit -webcam_cleanup(void) -{ - usb_composite_unregister(&webcam_driver); -} - -module_init(webcam_init); -module_exit(webcam_cleanup); - -MODULE_AUTHOR("Laurent Pinchart"); -MODULE_DESCRIPTION("Webcam Video Gadget"); -MODULE_LICENSE("GPL"); -MODULE_VERSION("0.1.0"); - diff --git a/ANDROID_3.4.5/drivers/usb/gadget/zero.c b/ANDROID_3.4.5/drivers/usb/gadget/zero.c deleted file mode 100644 index 31d34832..00000000 --- a/ANDROID_3.4.5/drivers/usb/gadget/zero.c +++ /dev/null @@ -1,353 +0,0 @@ -/* - * zero.c -- Gadget Zero, for USB development - * - * Copyright (C) 2003-2008 David Brownell - * Copyright (C) 2008 by Nokia Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - - -/* - * Gadget Zero only needs two bulk endpoints, and is an example of how you - * can write a hardware-agnostic gadget driver running inside a USB device. - * Some hardware details are visible, but don't affect most of the driver. - * - * Use it with the Linux host/master side "usbtest" driver to get a basic - * functional test of your device-side usb stack, or with "usb-skeleton". - * - * It supports two similar configurations. One sinks whatever the usb host - * writes, and in return sources zeroes. The other loops whatever the host - * writes back, so the host can read it. - * - * Many drivers will only have one configuration, letting them be much - * simpler if they also don't support high speed operation (like this - * driver does). - * - * Why is *this* driver using two configurations, rather than setting up - * two interfaces with different functions? To help verify that multiple - * configuration infrastucture is working correctly; also, so that it can - * work with low capability USB controllers without four bulk endpoints. - */ - -/* - * driver assumes self-powered hardware, and - * has no way for users to trigger remote wakeup. - */ - -/* #define VERBOSE_DEBUG */ - -#include -#include -#include -#include - -#include "g_zero.h" -#include "gadget_chips.h" - - -/*-------------------------------------------------------------------------*/ - -/* - * 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 "f_sourcesink.c" -#include "f_loopback.c" - -/*-------------------------------------------------------------------------*/ - -#define DRIVER_VERSION "Cinco de Mayo 2008" - -static const char longname[] = "Gadget Zero"; - -unsigned buflen = 4096; -module_param(buflen, uint, 0); - -/* - * Normally the "loopback" configuration is second (index 1) so - * it's not the default. Here's where to change that order, to - * work better with hosts where config changes are problematic or - * controllers (like original superh) that only support one config. - */ -static bool loopdefault = 0; -module_param(loopdefault, bool, S_IRUGO|S_IWUSR); - -/*-------------------------------------------------------------------------*/ - -/* Thanks to NetChip Technologies for donating this product ID. - * - * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! - * Instead: allocate your own, using normal USB-IF procedures. - */ -#ifndef CONFIG_USB_ZERO_HNPTEST -#define DRIVER_VENDOR_NUM 0x0525 /* NetChip */ -#define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */ -#define DEFAULT_AUTORESUME 0 -#else -#define DRIVER_VENDOR_NUM 0x1a0a /* OTG test device IDs */ -#define DRIVER_PRODUCT_NUM 0xbadd -#define DEFAULT_AUTORESUME 5 -#endif - -/* If the optional "autoresume" mode is enabled, it provides good - * functional coverage for the "USBCV" test harness from USB-IF. - * It's always set if OTG mode is enabled. - */ -unsigned autoresume = DEFAULT_AUTORESUME; -module_param(autoresume, uint, S_IRUGO); -MODULE_PARM_DESC(autoresume, "zero, or seconds before remote wakeup"); - -/*-------------------------------------------------------------------------*/ - -static struct usb_device_descriptor device_desc = { - .bLength = sizeof device_desc, - .bDescriptorType = USB_DT_DEVICE, - - .bcdUSB = cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_VENDOR_SPEC, - - .idVendor = cpu_to_le16(DRIVER_VENDOR_NUM), - .idProduct = cpu_to_le16(DRIVER_PRODUCT_NUM), - .bNumConfigurations = 2, -}; - -#ifdef CONFIG_USB_OTG -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, -}; - -const struct usb_descriptor_header *otg_desc[] = { - (struct usb_descriptor_header *) &otg_descriptor, - NULL, -}; -#endif - -/* string IDs are assigned dynamically */ - -#define STRING_MANUFACTURER_IDX 0 -#define STRING_PRODUCT_IDX 1 -#define STRING_SERIAL_IDX 2 - -static char manufacturer[50]; - -/* default serial number takes at least two packets */ -static char serial[] = "0123456789.0123456789.0123456789"; - -static struct usb_string strings_dev[] = { - [STRING_MANUFACTURER_IDX].s = manufacturer, - [STRING_PRODUCT_IDX].s = longname, - [STRING_SERIAL_IDX].s = serial, - { } /* end of list */ -}; - -static struct usb_gadget_strings stringtab_dev = { - .language = 0x0409, /* en-us */ - .strings = strings_dev, -}; - -static struct usb_gadget_strings *dev_strings[] = { - &stringtab_dev, - NULL, -}; - -/*-------------------------------------------------------------------------*/ - -struct usb_request *alloc_ep_req(struct usb_ep *ep) -{ - struct usb_request *req; - - req = usb_ep_alloc_request(ep, GFP_ATOMIC); - if (req) { - req->length = buflen; - req->buf = kmalloc(buflen, GFP_ATOMIC); - if (!req->buf) { - usb_ep_free_request(ep, req); - req = NULL; - } - } - return req; -} - -void free_ep_req(struct usb_ep *ep, struct usb_request *req) -{ - kfree(req->buf); - usb_ep_free_request(ep, req); -} - -static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep) -{ - int value; - - if (ep->driver_data) { - value = usb_ep_disable(ep); - if (value < 0) - DBG(cdev, "disable %s --> %d\n", - ep->name, value); - ep->driver_data = NULL; - } -} - -void disable_endpoints(struct usb_composite_dev *cdev, - struct usb_ep *in, struct usb_ep *out) -{ - disable_ep(cdev, in); - disable_ep(cdev, out); -} - -/*-------------------------------------------------------------------------*/ - -static struct timer_list autoresume_timer; - -static void zero_autoresume(unsigned long _c) -{ - struct usb_composite_dev *cdev = (void *)_c; - struct usb_gadget *g = cdev->gadget; - - /* unconfigured devices can't issue wakeups */ - if (!cdev->config) - return; - - /* Normally the host would be woken up for something - * more significant than just a timer firing; likely - * because of some direct user request. - */ - if (g->speed != USB_SPEED_UNKNOWN) { - int status = usb_gadget_wakeup(g); - INFO(cdev, "%s --> %d\n", __func__, status); - } -} - -static void zero_suspend(struct usb_composite_dev *cdev) -{ - if (cdev->gadget->speed == USB_SPEED_UNKNOWN) - return; - - if (autoresume) { - mod_timer(&autoresume_timer, jiffies + (HZ * autoresume)); - DBG(cdev, "suspend, wakeup in %d seconds\n", autoresume); - } else - DBG(cdev, "%s\n", __func__); -} - -static void zero_resume(struct usb_composite_dev *cdev) -{ - DBG(cdev, "%s\n", __func__); - del_timer(&autoresume_timer); -} - -/*-------------------------------------------------------------------------*/ - -static int __init zero_bind(struct usb_composite_dev *cdev) -{ - int gcnum; - struct usb_gadget *gadget = cdev->gadget; - int id; - - /* Allocate string descriptor numbers ... note that string - * contents can be overridden by the composite_dev glue. - */ - id = usb_string_id(cdev); - if (id < 0) - return id; - strings_dev[STRING_MANUFACTURER_IDX].id = id; - device_desc.iManufacturer = id; - - id = usb_string_id(cdev); - if (id < 0) - return id; - strings_dev[STRING_PRODUCT_IDX].id = id; - device_desc.iProduct = id; - - id = usb_string_id(cdev); - if (id < 0) - return id; - strings_dev[STRING_SERIAL_IDX].id = id; - device_desc.iSerialNumber = id; - - setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev); - - /* Register primary, then secondary configuration. Note that - * SH3 only allows one config... - */ - if (loopdefault) { - loopback_add(cdev, autoresume != 0); - sourcesink_add(cdev, autoresume != 0); - } else { - sourcesink_add(cdev, autoresume != 0); - loopback_add(cdev, autoresume != 0); - } - - gcnum = usb_gadget_controller_number(gadget); - if (gcnum >= 0) - device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum); - else { - /* gadget zero is so simple (for now, no altsettings) that - * it SHOULD NOT have problems with bulk-capable hardware. - * so just warn about unrcognized controllers -- don't panic. - * - * things like configuration and altsetting numbering - * can need hardware-specific attention though. - */ - pr_warning("%s: controller '%s' not recognized\n", - longname, gadget->name); - device_desc.bcdDevice = cpu_to_le16(0x9999); - } - - - INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname); - - snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", - init_utsname()->sysname, init_utsname()->release, - gadget->name); - - return 0; -} - -static int zero_unbind(struct usb_composite_dev *cdev) -{ - del_timer_sync(&autoresume_timer); - return 0; -} - -static struct usb_composite_driver zero_driver = { - .name = "zero", - .dev = &device_desc, - .strings = dev_strings, - .max_speed = USB_SPEED_SUPER, - .unbind = zero_unbind, - .suspend = zero_suspend, - .resume = zero_resume, -}; - -MODULE_AUTHOR("David Brownell"); -MODULE_LICENSE("GPL"); - -static int __init init(void) -{ - return usb_composite_probe(&zero_driver, zero_bind); -} -module_init(init); - -static void __exit cleanup(void) -{ - usb_composite_unregister(&zero_driver); -} -module_exit(cleanup); diff --git a/ANDROID_3.4.5/drivers/usb/host/Kconfig b/ANDROID_3.4.5/drivers/usb/host/Kconfig deleted file mode 100644 index 302bae2a..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/Kconfig +++ /dev/null @@ -1,655 +0,0 @@ -# -# USB Host Controller Drivers -# -comment "USB Host Controller Drivers" - depends on USB - -config USB_C67X00_HCD - tristate "Cypress C67x00 HCD support" - depends on USB - help - The Cypress C67x00 (EZ-Host/EZ-OTG) chips are dual-role - host/peripheral/OTG USB controllers. - - Enable this option to support this chip in host controller mode. - If unsure, say N. - - 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 && USB_ARCH_HAS_XHCI && 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_PLATFORM - tristate - depends on USB_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 - ---help--- - The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0 - "high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware. - If your USB host controller supports USB 2.0, you will likely want to - configure this Host Controller Driver. - - EHCI controllers are packaged with "companion" host controllers (OHCI - or UHCI) to handle USB 1.1 devices connected to root hub ports. Ports - will connect to EHCI if the device is high speed, otherwise they - connect to a companion controller. If you configure EHCI, you should - probably configure the OHCI (for NEC and some other vendors) USB Host - Controller Driver or UHCI (for Via motherboards) Host Controller - Driver too. - - You may want to read . - - To compile this driver as a module, choose M here: the - module will be called ehci-hcd. - -#CharlesTu, for test mode # -config USB_EHCI_EHSET - bool "Embedded High-speed Host Electrical Test Support (EXPERIMENTAL)" - depends on USB_EHCI_HCD - default y - ---help--- - This option is only used if you are developing firmware for - an embedded device with a Hi-speed USB Host or OTG port. - - If you say Y here, software support for the Embedded High-speed - Host Electrical Tests will be added to the EHCI driver. This is - one of the tests performed during High-speed USB Host certification - testing. - - If you are at all unsure then say N here. -config USB_EHCI_ROOT_HUB_TT - bool "Root Hub Transaction Translators" - depends on USB_EHCI_HCD - ---help--- - Some EHCI chips have vendor-specific extensions to integrate - transaction translators, so that no OHCI or UHCI companion - controller is needed. It's safe to say "y" even if your - controller doesn't support this feature. - - This supports the EHCI implementation that's originally - from ARC, and has since changed hands a few times. - -config USB_EHCI_TT_NEWSCHED - bool "Improved Transaction Translator scheduling" - depends on USB_EHCI_HCD - default y - ---help--- - This changes the periodic scheduling code to fill more of the low - and full speed bandwidth available from the Transaction Translator - (TT) in USB 2.0 hubs. Without this, only one transfer will be - issued in each microframe, significantly reducing the number of - periodic low/fullspeed transfers possible. - - If you have multiple periodic low/fullspeed devices connected to a - highspeed USB hub which is connected to a highspeed USB Host - Controller, and some of those devices will not work correctly - (possibly due to "ENOSPC" or "-28" errors), say Y. Conversely, if - you have only one such device and it doesn't work, you could try - saying N. - - If unsure, say Y. - -config USB_EHCI_HCD_PMC_MSP - tristate "EHCI support for on-chip PMC MSP71xx USB controller" - depends on USB_EHCI_HCD && MSP_HAS_USB - default n - select USB_EHCI_BIG_ENDIAN_DESC - select USB_EHCI_BIG_ENDIAN_MMIO - ---help--- - Enables support for the onchip USB controller on the PMC_MSP7100 Family SoC's. - If unsure, say N. - -config USB_EHCI_BIG_ENDIAN_MMIO - bool - depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || \ - ARCH_IXP4XX || XPS_USB_HCD_XILINX || \ - PPC_MPC512x || CPU_CAVIUM_OCTEON || \ - PMC_MSP || SPARC_LEON) - default y - -config USB_EHCI_BIG_ENDIAN_DESC - bool - depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX || \ - PPC_MPC512x || PMC_MSP || SPARC_LEON) - default y - -config XPS_USB_HCD_XILINX - bool "Use Xilinx usb host EHCI controller core" - depends on USB_EHCI_HCD && (PPC32 || MICROBLAZE) - select USB_EHCI_BIG_ENDIAN_DESC - select USB_EHCI_BIG_ENDIAN_MMIO - ---help--- - Xilinx xps USB host controller core is EHCI compilant and has - transaction translator built-in. It can be configured to either - support both high speed and full speed devices, or high speed - devices only. - -config USB_FSL_MPH_DR_OF - tristate - -config USB_EHCI_FSL - bool "Support for Freescale PPC on-chip EHCI USB controller" - depends on USB_EHCI_HCD && FSL_SOC - select USB_EHCI_ROOT_HUB_TT - select USB_FSL_MPH_DR_OF if OF - ---help--- - Variation of ARC USB block used in some Freescale chips. - -config USB_EHCI_MXC - bool "Support for Freescale i.MX on-chip EHCI USB controller" - depends on USB_EHCI_HCD && ARCH_MXC - select USB_EHCI_ROOT_HUB_TT - ---help--- - Variation of ARC USB block used in some Freescale chips. - -config USB_EHCI_HCD_OMAP - bool "EHCI support for OMAP3 and later chips" - depends on USB_EHCI_HCD && ARCH_OMAP - default y - --- help --- - Enables support for the on-chip EHCI controller on - OMAP3 and later chips. - -config USB_EHCI_MSM - bool "Support for MSM on-chip EHCI USB controller" - depends on USB_EHCI_HCD && ARCH_MSM - select USB_EHCI_ROOT_HUB_TT - select USB_MSM_OTG - ---help--- - Enables support for the USB Host controller present on the - Qualcomm chipsets. Root Hub has inbuilt TT. - This driver depends on OTG driver for PHY initialization, - clock management, powering up VBUS, and power management. - This driver is not supported on boards like trout which - has an external PHY. - -config USB_EHCI_TEGRA - boolean "NVIDIA Tegra HCD support" - depends on USB_EHCI_HCD && ARCH_TEGRA - select USB_EHCI_ROOT_HUB_TT - help - This driver enables support for the internal USB Host Controllers - found in NVIDIA Tegra SoCs. The controllers are EHCI compliant. - -config USB_EHCI_HCD_PPC_OF - bool "EHCI support for PPC USB controller on OF platform bus" - depends on USB_EHCI_HCD && PPC_OF - default y - ---help--- - Enables support for the USB controller present on the PowerPC - OpenFirmware platform bus. - -config USB_EHCI_SH - bool "EHCI support for SuperH USB controller" - depends on USB_EHCI_HCD && SUPERH - ---help--- - Enables support for the on-chip EHCI controller on the SuperH. - If you use the PCI EHCI controller, this option is not necessary. - -config USB_EHCI_S5P - boolean "S5P EHCI support" - depends on USB_EHCI_HCD && PLAT_S5P - help - Enable support for the S5P SOC's on-chip EHCI controller. - -config USB_EHCI_MV - bool "EHCI support for Marvell on-chip controller" - depends on USB_EHCI_HCD && (ARCH_PXA || ARCH_MMP) - select USB_EHCI_ROOT_HUB_TT - ---help--- - Enables support for Marvell (including PXA and MMP series) on-chip - USB SPH and OTG controller. SPH is a single port host, and it can - only be EHCI host. OTG is controller that can switch to host mode. - -config USB_W90X900_EHCI - bool "W90X900(W90P910) EHCI support" - depends on USB_EHCI_HCD && ARCH_W90X900 - ---help--- - Enables support for the W90X900 USB controller - -config USB_CNS3XXX_EHCI - bool "Cavium CNS3XXX EHCI Module" - depends on USB_EHCI_HCD && ARCH_CNS3XXX - ---help--- - Enable support for the CNS3XXX SOC's on-chip EHCI controller. - It is needed for high-speed (480Mbit/sec) USB 2.0 device - support. - -config USB_EHCI_ATH79 - bool "EHCI support for AR7XXX/AR9XXX SoCs (DEPRECATED)" - depends on USB_EHCI_HCD && (SOC_AR71XX || SOC_AR724X || SOC_AR913X || SOC_AR933X) - select USB_EHCI_ROOT_HUB_TT - select USB_EHCI_HCD_PLATFORM - default y - ---help--- - This option is deprecated now and the driver was removed, use - USB_EHCI_HCD_PLATFORM instead. - - Enables support for the built-in EHCI controller present - on the Atheros AR7XXX/AR9XXX SoCs. - -config USB_OXU210HP_HCD - tristate "OXU210HP HCD support" - depends on USB - ---help--- - The OXU210HP is an USB host/OTG/device controller. Enable this - option if your board has this chip. If unsure, say N. - - This driver does not support isochronous transfers and doesn't - implement OTG nor USB device controllers. - - To compile this driver as a module, choose M here: the - module will be called oxu210hp-hcd. - -config USB_ISP116X_HCD - tristate "ISP116X HCD support" - depends on USB - ---help--- - The ISP1160 and ISP1161 chips are USB host controllers. Enable this - option if your board has this chip. If unsure, say N. - - This driver does not support isochronous transfers. - - To compile this driver as a module, choose M here: the - module will be called isp116x-hcd. - -config USB_ISP1760_HCD - tristate "ISP 1760 HCD support" - depends on USB && EXPERIMENTAL - ---help--- - The ISP1760 chip is a USB 2.0 host controller. - - This driver does not support isochronous transfers or OTG. - This USB controller is usually attached to a non-DMA-Master - capable bus. NXP's eval kit brings this chip on PCI card - where the chip itself is behind a PLB to simulate such - a bus. - - To compile this driver as a module, choose M here: the - module will be called isp1760. - -config USB_ISP1362_HCD - tristate "ISP1362 HCD support" - depends on USB - default N - ---help--- - Supports the Philips ISP1362 chip as a host controller - - This driver does not support isochronous transfers. - - To compile this driver as a module, choose M here: the - module will be called isp1362-hcd. - -config USB_OHCI_HCD - tristate "OHCI HCD support" - depends on USB && USB_ARCH_HAS_OHCI - select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 - select USB_OTG_UTILS if ARCH_OMAP - ---help--- - The Open Host Controller Interface (OHCI) is a standard for accessing - USB 1.1 host controller hardware. It does more in hardware than Intel's - UHCI specification. If your USB host controller follows the OHCI spec, - say Y. On most non-x86 systems, and on x86 hardware that's not using a - USB controller from Intel or VIA, this is appropriate. If your host - controller doesn't use PCI, this is probably appropriate. For a PCI - based system where you're not sure, the "lspci -v" entry will list the - right "prog-if" for your USB controller(s): EHCI, OHCI, or UHCI. - - To compile this driver as a module, choose M here: the - module will be called ohci-hcd. - -config USB_OHCI_HCD_OMAP1 - bool "OHCI support for OMAP1/2 chips" - depends on USB_OHCI_HCD && (ARCH_OMAP1 || ARCH_OMAP2) - default y - ---help--- - Enables support for the OHCI controller on OMAP1/2 chips. - -config USB_OHCI_HCD_OMAP3 - bool "OHCI support for OMAP3 and later chips" - depends on USB_OHCI_HCD && (ARCH_OMAP3 || ARCH_OMAP4) - default y - ---help--- - Enables support for the on-chip OHCI controller on - OMAP3 and later chips. - -config USB_OHCI_ATH79 - bool "USB OHCI support for the Atheros AR71XX/AR7240 SoCs (DEPRECATED)" - depends on USB_OHCI_HCD && (SOC_AR71XX || SOC_AR724X) - select USB_OHCI_HCD_PLATFORM - default y - help - This option is deprecated now and the driver was removed, use - USB_OHCI_HCD_PLATFORM instead. - - Enables support for the built-in OHCI controller present on the - Atheros AR71XX/AR7240 SoCs. - -config USB_OHCI_HCD_PPC_SOC - bool "OHCI support for on-chip PPC USB controller" - depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx) - default y - select USB_OHCI_BIG_ENDIAN_DESC - select USB_OHCI_BIG_ENDIAN_MMIO - ---help--- - Enables support for the USB controller on the MPC52xx or - STB03xxx processor chip. If unsure, say Y. - -config USB_OHCI_HCD_PPC_OF_BE - bool "OHCI support for OF platform bus (big endian)" - depends on USB_OHCI_HCD && PPC_OF - select USB_OHCI_BIG_ENDIAN_DESC - select USB_OHCI_BIG_ENDIAN_MMIO - ---help--- - Enables support for big-endian USB controllers present on the - OpenFirmware platform bus. - -config USB_OHCI_HCD_PPC_OF_LE - bool "OHCI support for OF platform bus (little endian)" - depends on USB_OHCI_HCD && PPC_OF - select USB_OHCI_LITTLE_ENDIAN - ---help--- - Enables support for little-endian USB controllers present on the - OpenFirmware platform bus. - -config USB_OHCI_HCD_PPC_OF - bool - depends on USB_OHCI_HCD && PPC_OF - default USB_OHCI_HCD_PPC_OF_BE || USB_OHCI_HCD_PPC_OF_LE - -config USB_OHCI_HCD_PCI - bool "OHCI support for PCI-bus USB controllers" - depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx || USB_OHCI_HCD_PPC_OF) - default y - select USB_OHCI_LITTLE_ENDIAN - ---help--- - Enables support for PCI-bus plug-in USB controller cards. - If unsure, say Y. - -config USB_OHCI_HCD_SSB - bool "OHCI support for Broadcom SSB OHCI core" - depends on USB_OHCI_HCD && (SSB = y || SSB = USB_OHCI_HCD) && EXPERIMENTAL - default n - ---help--- - Support for the Sonics Silicon Backplane (SSB) attached - Broadcom USB OHCI core. - - This device is present in some embedded devices with - Broadcom based SSB bus. - - If unsure, say N. - -config USB_OHCI_SH - bool "OHCI support for SuperH USB controller" - depends on USB_OHCI_HCD && SUPERH - ---help--- - Enables support for the on-chip OHCI controller on the SuperH. - If you use the PCI OHCI controller, this option is not necessary. - -config USB_OHCI_EXYNOS - boolean "OHCI support for Samsung EXYNOS SoC Series" - depends on USB_OHCI_HCD && ARCH_EXYNOS - help - Enable support for the Samsung Exynos SOC's on-chip OHCI controller. - -config USB_CNS3XXX_OHCI - bool "Cavium CNS3XXX OHCI Module" - depends on USB_OHCI_HCD && ARCH_CNS3XXX - ---help--- - Enable support for the CNS3XXX SOC's on-chip OHCI controller. - It is needed for low-speed USB 1.0 device support. - -config USB_OHCI_HCD_PLATFORM - bool "Generic OHCI driver for a platform device" - depends on USB_OHCI_HCD && EXPERIMENTAL - default n - ---help--- - Adds an OHCI host driver for a generic platform device, which - provieds a memory space and an irq. - - If unsure, say N. - -config USB_EHCI_HCD_PLATFORM - bool "Generic EHCI driver for a platform device" - depends on USB_EHCI_HCD && EXPERIMENTAL - default n - ---help--- - Adds an EHCI host driver for a generic platform device, which - provieds a memory space and an irq. - - If unsure, say N. - -config USB_OHCI_BIG_ENDIAN_DESC - bool - depends on USB_OHCI_HCD - default n - -config USB_OHCI_BIG_ENDIAN_MMIO - bool - depends on USB_OHCI_HCD - default n - -config USB_OHCI_LITTLE_ENDIAN - bool - depends on USB_OHCI_HCD - default n if STB03xxx || PPC_MPC52xx - default y - -config USB_UHCI_HCD - tristate "UHCI HCD (most Intel and VIA) support" - depends on USB && (PCI || SPARC_LEON) - ---help--- - The Universal Host Controller Interface is a standard by Intel for - accessing the USB hardware in the PC (which is also called the USB - host controller). If your USB host controller conforms to this - standard, you may want to say Y, but see below. All recent boards - with Intel PCI chipsets (like intel 430TX, 440FX, 440LX, 440BX, - i810, i820) conform to this standard. Also all VIA PCI chipsets - (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo Pro II or Apollo Pro - 133) and LEON/GRLIB SoCs with the GRUSBHC controller. - If unsure, say Y. - - To compile this driver as a module, choose M here: the - module will be called uhci-hcd. - -config USB_UHCI_SUPPORT_NON_PCI_HC - bool - depends on USB_UHCI_HCD - default y if SPARC_LEON - -config USB_UHCI_BIG_ENDIAN_MMIO - bool - depends on USB_UHCI_SUPPORT_NON_PCI_HC && SPARC_LEON - default y - -config USB_UHCI_BIG_ENDIAN_DESC - bool - depends on USB_UHCI_SUPPORT_NON_PCI_HC && SPARC_LEON - default y - -config USB_FHCI_HCD - tristate "Freescale QE USB Host Controller support" - depends on USB && OF_GPIO && QE_GPIO && QUICC_ENGINE - select FSL_GTM - select QE_USB - help - This driver enables support for Freescale QE USB Host Controller - (as found on MPC8360 and MPC8323 processors), the driver supports - Full and Low Speed USB. - -config FHCI_DEBUG - bool "Freescale QE USB Host Controller debug support" - depends on USB_FHCI_HCD && DEBUG_FS - help - Say "y" to see some FHCI debug information and statistics - through debugfs. - -config USB_U132_HCD - tristate "Elan U132 Adapter Host Controller" - depends on USB && USB_FTDI_ELAN - default M - help - The U132 adapter is a USB to CardBus adapter specifically designed - for PC cards that contain an OHCI host controller. Typical PC cards - are the Orange Mobile 3G Option GlobeTrotter Fusion card. The U132 - adapter will *NOT* work with PC cards that do not contain an OHCI - controller. - - For those PC cards that contain multiple OHCI controllers only the - first one is used. - - The driver consists of two modules, the "ftdi-elan" module is a - USB client driver that interfaces to the FTDI chip within ELAN's - USB-to-PCMCIA adapter, and this "u132-hcd" module is a USB host - controller driver that talks to the OHCI controller within the - CardBus cards that are inserted in the U132 adapter. - - This driver has been tested with a CardBus OHCI USB adapter, and - worked with a USB PEN Drive inserted into the first USB port of - the PCCARD. A rather pointless thing to do, but useful for testing. - - It is safe to say M here. - - See also - -config USB_SL811_HCD - tristate "SL811HS HCD support" - depends on USB - help - The SL811HS is a single-port USB controller that supports either - host side or peripheral side roles. Enable this option if your - board has this chip, and you want to use it as a host controller. - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called sl811-hcd. - -config USB_SL811_HCD_ISO - bool "partial ISO support" - depends on USB_SL811_HCD - help - The driver doesn't support iso_frame_desc (yet), but for some simple - devices that just queue one ISO frame per URB, then ISO transfers - "should" work using the normal urb status fields. - - If unsure, say N. - -config USB_SL811_CS - tristate "CF/PCMCIA support for SL811HS HCD" - depends on USB_SL811_HCD && PCMCIA - help - Wraps a PCMCIA driver around the SL811HS HCD, supporting the RATOC - REX-CFU1U CF card (often used with PDAs). If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called "sl811_cs". - -config USB_R8A66597_HCD - tristate "R8A66597 HCD support" - depends on USB - help - The R8A66597 is a USB 2.0 host and peripheral controller. - - Enable this option if your board has this chip, and you want - to use it as a host controller. If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called r8a66597-hcd. - -config USB_RENESAS_USBHS_HCD - tristate "Renesas USBHS HCD support" - depends on USB - depends on USB_RENESAS_USBHS - help - The Renesas USBHS is a USB 2.0 host and peripheral controller. - - Enable this option if your board has this chip, and you want - to use it as a host controller. If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called renesas-usbhs. - -config USB_WHCI_HCD - tristate "Wireless USB Host Controller Interface (WHCI) driver (EXPERIMENTAL)" - depends on EXPERIMENTAL - depends on PCI && USB && UWB - select USB_WUSB - select UWB_WHCI - help - A driver for PCI-based Wireless USB Host Controllers that are - compliant with the WHCI specification. - - To compile this driver a module, choose M here: the module - will be called "whci-hcd". - -config USB_HWA_HCD - tristate "Host Wire Adapter (HWA) driver (EXPERIMENTAL)" - depends on EXPERIMENTAL - depends on USB && UWB - select USB_WUSB - select UWB_HWA - help - This driver enables you to connect Wireless USB devices to - your system using a Host Wire Adaptor USB dongle. This is an - UWB Radio Controller and WUSB Host Controller connected to - your machine via USB (specified in WUSB1.0). - - To compile this driver a module, choose M here: the module - will be called "hwa-hc". - -config USB_IMX21_HCD - tristate "i.MX21 HCD support" - depends on USB && ARM && ARCH_MXC - help - This driver enables support for the on-chip USB host in the - i.MX21 processor. - - To compile this driver as a module, choose M here: the - module will be called "imx21-hcd". - -config USB_OCTEON_EHCI - bool "Octeon on-chip EHCI support" - depends on USB && USB_EHCI_HCD && CPU_CAVIUM_OCTEON - default n - select USB_EHCI_BIG_ENDIAN_MMIO - help - Enable support for the Octeon II SOC's on-chip EHCI - controller. It is needed for high-speed (480Mbit/sec) - USB 2.0 device support. All CN6XXX based chips with USB are - supported. - -config USB_OCTEON_OHCI - bool "Octeon on-chip OHCI support" - depends on USB && USB_OHCI_HCD && CPU_CAVIUM_OCTEON - default USB_OCTEON_EHCI - select USB_OHCI_BIG_ENDIAN_MMIO - select USB_OHCI_LITTLE_ENDIAN - help - Enable support for the Octeon II SOC's on-chip OHCI - controller. It is needed for low-speed USB 1.0 device - support. All CN6XXX based chips with USB are supported. - -config USB_OCTEON2_COMMON - bool - default y if USB_OCTEON_EHCI || USB_OCTEON_OHCI diff --git a/ANDROID_3.4.5/drivers/usb/host/Makefile b/ANDROID_3.4.5/drivers/usb/host/Makefile deleted file mode 100644 index 0982bcc1..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -# -# Makefile for USB Host Controller Drivers -# - -ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG - -isp1760-y := isp1760-hcd.o isp1760-if.o - -fhci-y := fhci-hcd.o fhci-hub.o fhci-q.o -fhci-y += fhci-mem.o fhci-tds.o fhci-sched.o - -fhci-$(CONFIG_FHCI_DEBUG) += fhci-dbg.o - -xhci-hcd-y := xhci.o xhci-mem.o -xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o -xhci-hcd-$(CONFIG_PCI) += xhci-pci.o - -ifneq ($(CONFIG_USB_XHCI_PLATFORM), ) - xhci-hcd-y += xhci-plat.o -endif - -obj-$(CONFIG_USB_WHCI_HCD) += whci/ - -obj-$(CONFIG_PCI) += pci-quirks.o - -obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o -obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o -obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o -obj-$(CONFIG_USB_ISP1362_HCD) += isp1362-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-hcd.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 -obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o -obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o -obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o -obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o -obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o -obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o -obj-$(CONFIG_MIPS_ALCHEMY) += alchemy-common.o diff --git a/ANDROID_3.4.5/drivers/usb/host/alchemy-common.c b/ANDROID_3.4.5/drivers/usb/host/alchemy-common.c deleted file mode 100644 index 936af835..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/alchemy-common.c +++ /dev/null @@ -1,614 +0,0 @@ -/* - * USB block power/access management abstraction. - * - * Au1000+: The OHCI block control register is at the far end of the OHCI memory - * area. Au1550 has OHCI on different base address. No need to handle - * UDC here. - * Au1200: one register to control access and clocks to O/EHCI, UDC and OTG - * as well as the PHY for EHCI and UDC. - * - */ - -#include -#include -#include -#include -#include -#include - -/* control register offsets */ -#define AU1000_OHCICFG 0x7fffc -#define AU1550_OHCICFG 0x07ffc -#define AU1200_USBCFG 0x04 - -/* Au1000 USB block config bits */ -#define USBHEN_RD (1 << 4) /* OHCI reset-done indicator */ -#define USBHEN_CE (1 << 3) /* OHCI block clock enable */ -#define USBHEN_E (1 << 2) /* OHCI block enable */ -#define USBHEN_C (1 << 1) /* OHCI block coherency bit */ -#define USBHEN_BE (1 << 0) /* OHCI Big-Endian */ - -/* Au1200 USB config bits */ -#define USBCFG_PFEN (1 << 31) /* prefetch enable (undoc) */ -#define USBCFG_RDCOMB (1 << 30) /* read combining (undoc) */ -#define USBCFG_UNKNOWN (5 << 20) /* unknown, leave this way */ -#define USBCFG_SSD (1 << 23) /* serial short detect en */ -#define USBCFG_PPE (1 << 19) /* HS PHY PLL */ -#define USBCFG_UCE (1 << 18) /* UDC clock enable */ -#define USBCFG_ECE (1 << 17) /* EHCI clock enable */ -#define USBCFG_OCE (1 << 16) /* OHCI clock enable */ -#define USBCFG_FLA(x) (((x) & 0x3f) << 8) -#define USBCFG_UCAM (1 << 7) /* coherent access (undoc) */ -#define USBCFG_GME (1 << 6) /* OTG mem access */ -#define USBCFG_DBE (1 << 5) /* UDC busmaster enable */ -#define USBCFG_DME (1 << 4) /* UDC mem enable */ -#define USBCFG_EBE (1 << 3) /* EHCI busmaster enable */ -#define USBCFG_EME (1 << 2) /* EHCI mem enable */ -#define USBCFG_OBE (1 << 1) /* OHCI busmaster enable */ -#define USBCFG_OME (1 << 0) /* OHCI mem enable */ -#define USBCFG_INIT_AU1200 (USBCFG_PFEN | USBCFG_RDCOMB | USBCFG_UNKNOWN |\ - USBCFG_SSD | USBCFG_FLA(0x20) | USBCFG_UCAM | \ - USBCFG_GME | USBCFG_DBE | USBCFG_DME | \ - USBCFG_EBE | USBCFG_EME | USBCFG_OBE | \ - USBCFG_OME) - -/* Au1300 USB config registers */ -#define USB_DWC_CTRL1 0x00 -#define USB_DWC_CTRL2 0x04 -#define USB_VBUS_TIMER 0x10 -#define USB_SBUS_CTRL 0x14 -#define USB_MSR_ERR 0x18 -#define USB_DWC_CTRL3 0x1C -#define USB_DWC_CTRL4 0x20 -#define USB_OTG_STATUS 0x28 -#define USB_DWC_CTRL5 0x2C -#define USB_DWC_CTRL6 0x30 -#define USB_DWC_CTRL7 0x34 -#define USB_PHY_STATUS 0xC0 -#define USB_INT_STATUS 0xC4 -#define USB_INT_ENABLE 0xC8 - -#define USB_DWC_CTRL1_OTGD 0x04 /* set to DISable OTG */ -#define USB_DWC_CTRL1_HSTRS 0x02 /* set to ENable EHCI */ -#define USB_DWC_CTRL1_DCRS 0x01 /* set to ENable UDC */ - -#define USB_DWC_CTRL2_PHY1RS 0x04 /* set to enable PHY1 */ -#define USB_DWC_CTRL2_PHY0RS 0x02 /* set to enable PHY0 */ -#define USB_DWC_CTRL2_PHYRS 0x01 /* set to enable PHY */ - -#define USB_DWC_CTRL3_OHCI1_CKEN (1 << 19) -#define USB_DWC_CTRL3_OHCI0_CKEN (1 << 18) -#define USB_DWC_CTRL3_EHCI0_CKEN (1 << 17) -#define USB_DWC_CTRL3_OTG0_CKEN (1 << 16) - -#define USB_SBUS_CTRL_SBCA 0x04 /* coherent access */ - -#define USB_INTEN_FORCE 0x20 -#define USB_INTEN_PHY 0x10 -#define USB_INTEN_UDC 0x08 -#define USB_INTEN_EHCI 0x04 -#define USB_INTEN_OHCI1 0x02 -#define USB_INTEN_OHCI0 0x01 - -static DEFINE_SPINLOCK(alchemy_usb_lock); - -static inline void __au1300_usb_phyctl(void __iomem *base, int enable) -{ - unsigned long r, s; - - r = __raw_readl(base + USB_DWC_CTRL2); - s = __raw_readl(base + USB_DWC_CTRL3); - - s &= USB_DWC_CTRL3_OHCI1_CKEN | USB_DWC_CTRL3_OHCI0_CKEN | - USB_DWC_CTRL3_EHCI0_CKEN | USB_DWC_CTRL3_OTG0_CKEN; - - if (enable) { - /* simply enable all PHYs */ - r |= USB_DWC_CTRL2_PHY1RS | USB_DWC_CTRL2_PHY0RS | - USB_DWC_CTRL2_PHYRS; - __raw_writel(r, base + USB_DWC_CTRL2); - wmb(); - } else if (!s) { - /* no USB block active, do disable all PHYs */ - r &= ~(USB_DWC_CTRL2_PHY1RS | USB_DWC_CTRL2_PHY0RS | - USB_DWC_CTRL2_PHYRS); - __raw_writel(r, base + USB_DWC_CTRL2); - wmb(); - } -} - -static inline void __au1300_ohci_control(void __iomem *base, int enable, int id) -{ - unsigned long r; - - if (enable) { - __raw_writel(1, base + USB_DWC_CTRL7); /* start OHCI clock */ - wmb(); - - r = __raw_readl(base + USB_DWC_CTRL3); /* enable OHCI block */ - r |= (id == 0) ? USB_DWC_CTRL3_OHCI0_CKEN - : USB_DWC_CTRL3_OHCI1_CKEN; - __raw_writel(r, base + USB_DWC_CTRL3); - wmb(); - - __au1300_usb_phyctl(base, enable); /* power up the PHYs */ - - r = __raw_readl(base + USB_INT_ENABLE); - r |= (id == 0) ? USB_INTEN_OHCI0 : USB_INTEN_OHCI1; - __raw_writel(r, base + USB_INT_ENABLE); - wmb(); - - /* reset the OHCI start clock bit */ - __raw_writel(0, base + USB_DWC_CTRL7); - wmb(); - } else { - r = __raw_readl(base + USB_INT_ENABLE); - r &= ~((id == 0) ? USB_INTEN_OHCI0 : USB_INTEN_OHCI1); - __raw_writel(r, base + USB_INT_ENABLE); - wmb(); - - r = __raw_readl(base + USB_DWC_CTRL3); - r &= ~((id == 0) ? USB_DWC_CTRL3_OHCI0_CKEN - : USB_DWC_CTRL3_OHCI1_CKEN); - __raw_writel(r, base + USB_DWC_CTRL3); - wmb(); - - __au1300_usb_phyctl(base, enable); - } -} - -static inline void __au1300_ehci_control(void __iomem *base, int enable) -{ - unsigned long r; - - if (enable) { - r = __raw_readl(base + USB_DWC_CTRL3); - r |= USB_DWC_CTRL3_EHCI0_CKEN; - __raw_writel(r, base + USB_DWC_CTRL3); - wmb(); - - r = __raw_readl(base + USB_DWC_CTRL1); - r |= USB_DWC_CTRL1_HSTRS; - __raw_writel(r, base + USB_DWC_CTRL1); - wmb(); - - __au1300_usb_phyctl(base, enable); - - r = __raw_readl(base + USB_INT_ENABLE); - r |= USB_INTEN_EHCI; - __raw_writel(r, base + USB_INT_ENABLE); - wmb(); - } else { - r = __raw_readl(base + USB_INT_ENABLE); - r &= ~USB_INTEN_EHCI; - __raw_writel(r, base + USB_INT_ENABLE); - wmb(); - - r = __raw_readl(base + USB_DWC_CTRL1); - r &= ~USB_DWC_CTRL1_HSTRS; - __raw_writel(r, base + USB_DWC_CTRL1); - wmb(); - - r = __raw_readl(base + USB_DWC_CTRL3); - r &= ~USB_DWC_CTRL3_EHCI0_CKEN; - __raw_writel(r, base + USB_DWC_CTRL3); - wmb(); - - __au1300_usb_phyctl(base, enable); - } -} - -static inline void __au1300_udc_control(void __iomem *base, int enable) -{ - unsigned long r; - - if (enable) { - r = __raw_readl(base + USB_DWC_CTRL1); - r |= USB_DWC_CTRL1_DCRS; - __raw_writel(r, base + USB_DWC_CTRL1); - wmb(); - - __au1300_usb_phyctl(base, enable); - - r = __raw_readl(base + USB_INT_ENABLE); - r |= USB_INTEN_UDC; - __raw_writel(r, base + USB_INT_ENABLE); - wmb(); - } else { - r = __raw_readl(base + USB_INT_ENABLE); - r &= ~USB_INTEN_UDC; - __raw_writel(r, base + USB_INT_ENABLE); - wmb(); - - r = __raw_readl(base + USB_DWC_CTRL1); - r &= ~USB_DWC_CTRL1_DCRS; - __raw_writel(r, base + USB_DWC_CTRL1); - wmb(); - - __au1300_usb_phyctl(base, enable); - } -} - -static inline void __au1300_otg_control(void __iomem *base, int enable) -{ - unsigned long r; - if (enable) { - r = __raw_readl(base + USB_DWC_CTRL3); - r |= USB_DWC_CTRL3_OTG0_CKEN; - __raw_writel(r, base + USB_DWC_CTRL3); - wmb(); - - r = __raw_readl(base + USB_DWC_CTRL1); - r &= ~USB_DWC_CTRL1_OTGD; - __raw_writel(r, base + USB_DWC_CTRL1); - wmb(); - - __au1300_usb_phyctl(base, enable); - } else { - r = __raw_readl(base + USB_DWC_CTRL1); - r |= USB_DWC_CTRL1_OTGD; - __raw_writel(r, base + USB_DWC_CTRL1); - wmb(); - - r = __raw_readl(base + USB_DWC_CTRL3); - r &= ~USB_DWC_CTRL3_OTG0_CKEN; - __raw_writel(r, base + USB_DWC_CTRL3); - wmb(); - - __au1300_usb_phyctl(base, enable); - } -} - -static inline int au1300_usb_control(int block, int enable) -{ - void __iomem *base = - (void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR); - int ret = 0; - - switch (block) { - case ALCHEMY_USB_OHCI0: - __au1300_ohci_control(base, enable, 0); - break; - case ALCHEMY_USB_OHCI1: - __au1300_ohci_control(base, enable, 1); - break; - case ALCHEMY_USB_EHCI0: - __au1300_ehci_control(base, enable); - break; - case ALCHEMY_USB_UDC0: - __au1300_udc_control(base, enable); - break; - case ALCHEMY_USB_OTG0: - __au1300_otg_control(base, enable); - break; - default: - ret = -ENODEV; - } - return ret; -} - -static inline void au1300_usb_init(void) -{ - void __iomem *base = - (void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR); - - /* set some sane defaults. Note: we don't fiddle with DWC_CTRL4 - * here at all: Port 2 routing (EHCI or UDC) must be set either - * by boot firmware or platform init code; I can't autodetect - * a sane setting. - */ - __raw_writel(0, base + USB_INT_ENABLE); /* disable all USB irqs */ - wmb(); - __raw_writel(0, base + USB_DWC_CTRL3); /* disable all clocks */ - wmb(); - __raw_writel(~0, base + USB_MSR_ERR); /* clear all errors */ - wmb(); - __raw_writel(~0, base + USB_INT_STATUS); /* clear int status */ - wmb(); - /* set coherent access bit */ - __raw_writel(USB_SBUS_CTRL_SBCA, base + USB_SBUS_CTRL); - wmb(); -} - -static inline void __au1200_ohci_control(void __iomem *base, int enable) -{ - unsigned long r = __raw_readl(base + AU1200_USBCFG); - if (enable) { - __raw_writel(r | USBCFG_OCE, base + AU1200_USBCFG); - wmb(); - udelay(2000); - } else { - __raw_writel(r & ~USBCFG_OCE, base + AU1200_USBCFG); - wmb(); - udelay(1000); - } -} - -static inline void __au1200_ehci_control(void __iomem *base, int enable) -{ - unsigned long r = __raw_readl(base + AU1200_USBCFG); - if (enable) { - __raw_writel(r | USBCFG_ECE | USBCFG_PPE, base + AU1200_USBCFG); - wmb(); - udelay(1000); - } else { - if (!(r & USBCFG_UCE)) /* UDC also off? */ - r &= ~USBCFG_PPE; /* yes: disable HS PHY PLL */ - __raw_writel(r & ~USBCFG_ECE, base + AU1200_USBCFG); - wmb(); - udelay(1000); - } -} - -static inline void __au1200_udc_control(void __iomem *base, int enable) -{ - unsigned long r = __raw_readl(base + AU1200_USBCFG); - if (enable) { - __raw_writel(r | USBCFG_UCE | USBCFG_PPE, base + AU1200_USBCFG); - wmb(); - } else { - if (!(r & USBCFG_ECE)) /* EHCI also off? */ - r &= ~USBCFG_PPE; /* yes: disable HS PHY PLL */ - __raw_writel(r & ~USBCFG_UCE, base + AU1200_USBCFG); - wmb(); - } -} - -static inline int au1200_coherency_bug(void) -{ -#if defined(CONFIG_DMA_COHERENT) - /* Au1200 AB USB does not support coherent memory */ - if (!(read_c0_prid() & 0xff)) { - printk(KERN_INFO "Au1200 USB: this is chip revision AB !!\n"); - printk(KERN_INFO "Au1200 USB: update your board or re-configure" - " the kernel\n"); - return -ENODEV; - } -#endif - return 0; -} - -static inline int au1200_usb_control(int block, int enable) -{ - void __iomem *base = - (void __iomem *)KSEG1ADDR(AU1200_USB_CTL_PHYS_ADDR); - int ret = 0; - - switch (block) { - case ALCHEMY_USB_OHCI0: - ret = au1200_coherency_bug(); - if (ret && enable) - goto out; - __au1200_ohci_control(base, enable); - break; - case ALCHEMY_USB_UDC0: - __au1200_udc_control(base, enable); - break; - case ALCHEMY_USB_EHCI0: - ret = au1200_coherency_bug(); - if (ret && enable) - goto out; - __au1200_ehci_control(base, enable); - break; - default: - ret = -ENODEV; - } -out: - return ret; -} - - -/* initialize USB block(s) to a known working state */ -static inline void au1200_usb_init(void) -{ - void __iomem *base = - (void __iomem *)KSEG1ADDR(AU1200_USB_CTL_PHYS_ADDR); - __raw_writel(USBCFG_INIT_AU1200, base + AU1200_USBCFG); - wmb(); - udelay(1000); -} - -static inline void au1000_usb_init(unsigned long rb, int reg) -{ - void __iomem *base = (void __iomem *)KSEG1ADDR(rb + reg); - unsigned long r = __raw_readl(base); - -#if defined(__BIG_ENDIAN) - r |= USBHEN_BE; -#endif - r |= USBHEN_C; - - __raw_writel(r, base); - wmb(); - udelay(1000); -} - - -static inline void __au1xx0_ohci_control(int enable, unsigned long rb, int creg) -{ - void __iomem *base = (void __iomem *)KSEG1ADDR(rb); - unsigned long r = __raw_readl(base + creg); - - if (enable) { - __raw_writel(r | USBHEN_CE, base + creg); - wmb(); - udelay(1000); - __raw_writel(r | USBHEN_CE | USBHEN_E, base + creg); - wmb(); - udelay(1000); - - /* wait for reset complete (read reg twice: au1500 erratum) */ - while (__raw_readl(base + creg), - !(__raw_readl(base + creg) & USBHEN_RD)) - udelay(1000); - } else { - __raw_writel(r & ~(USBHEN_CE | USBHEN_E), base + creg); - wmb(); - } -} - -static inline int au1000_usb_control(int block, int enable, unsigned long rb, - int creg) -{ - int ret = 0; - - switch (block) { - case ALCHEMY_USB_OHCI0: - __au1xx0_ohci_control(enable, rb, creg); - break; - default: - ret = -ENODEV; - } - return ret; -} - -/* - * alchemy_usb_control - control Alchemy on-chip USB blocks - * @block: USB block to target - * @enable: set 1 to enable a block, 0 to disable - */ -int alchemy_usb_control(int block, int enable) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&alchemy_usb_lock, flags); - switch (alchemy_get_cputype()) { - case ALCHEMY_CPU_AU1000: - case ALCHEMY_CPU_AU1500: - case ALCHEMY_CPU_AU1100: - ret = au1000_usb_control(block, enable, - AU1000_USB_OHCI_PHYS_ADDR, AU1000_OHCICFG); - break; - case ALCHEMY_CPU_AU1550: - ret = au1000_usb_control(block, enable, - AU1550_USB_OHCI_PHYS_ADDR, AU1550_OHCICFG); - break; - case ALCHEMY_CPU_AU1200: - ret = au1200_usb_control(block, enable); - break; - case ALCHEMY_CPU_AU1300: - ret = au1300_usb_control(block, enable); - break; - default: - ret = -ENODEV; - } - spin_unlock_irqrestore(&alchemy_usb_lock, flags); - return ret; -} -EXPORT_SYMBOL_GPL(alchemy_usb_control); - - -static unsigned long alchemy_usb_pmdata[2]; - -static void au1000_usb_pm(unsigned long br, int creg, int susp) -{ - void __iomem *base = (void __iomem *)KSEG1ADDR(br); - - if (susp) { - alchemy_usb_pmdata[0] = __raw_readl(base + creg); - /* There appears to be some undocumented reset register.... */ - __raw_writel(0, base + 0x04); - wmb(); - __raw_writel(0, base + creg); - wmb(); - } else { - __raw_writel(alchemy_usb_pmdata[0], base + creg); - wmb(); - } -} - -static void au1200_usb_pm(int susp) -{ - void __iomem *base = - (void __iomem *)KSEG1ADDR(AU1200_USB_OTG_PHYS_ADDR); - if (susp) { - /* save OTG_CAP/MUX registers which indicate port routing */ - /* FIXME: write an OTG driver to do that */ - alchemy_usb_pmdata[0] = __raw_readl(base + 0x00); - alchemy_usb_pmdata[1] = __raw_readl(base + 0x04); - } else { - /* restore access to all MMIO areas */ - au1200_usb_init(); - - /* restore OTG_CAP/MUX registers */ - __raw_writel(alchemy_usb_pmdata[0], base + 0x00); - __raw_writel(alchemy_usb_pmdata[1], base + 0x04); - wmb(); - } -} - -static void au1300_usb_pm(int susp) -{ - void __iomem *base = - (void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR); - /* remember Port2 routing */ - if (susp) { - alchemy_usb_pmdata[0] = __raw_readl(base + USB_DWC_CTRL4); - } else { - au1300_usb_init(); - __raw_writel(alchemy_usb_pmdata[0], base + USB_DWC_CTRL4); - wmb(); - } -} - -static void alchemy_usb_pm(int susp) -{ - switch (alchemy_get_cputype()) { - case ALCHEMY_CPU_AU1000: - case ALCHEMY_CPU_AU1500: - case ALCHEMY_CPU_AU1100: - au1000_usb_pm(AU1000_USB_OHCI_PHYS_ADDR, AU1000_OHCICFG, susp); - break; - case ALCHEMY_CPU_AU1550: - au1000_usb_pm(AU1550_USB_OHCI_PHYS_ADDR, AU1550_OHCICFG, susp); - break; - case ALCHEMY_CPU_AU1200: - au1200_usb_pm(susp); - break; - case ALCHEMY_CPU_AU1300: - au1300_usb_pm(susp); - break; - } -} - -static int alchemy_usb_suspend(void) -{ - alchemy_usb_pm(1); - return 0; -} - -static void alchemy_usb_resume(void) -{ - alchemy_usb_pm(0); -} - -static struct syscore_ops alchemy_usb_pm_ops = { - .suspend = alchemy_usb_suspend, - .resume = alchemy_usb_resume, -}; - -static int __init alchemy_usb_init(void) -{ - switch (alchemy_get_cputype()) { - case ALCHEMY_CPU_AU1000: - case ALCHEMY_CPU_AU1500: - case ALCHEMY_CPU_AU1100: - au1000_usb_init(AU1000_USB_OHCI_PHYS_ADDR, AU1000_OHCICFG); - break; - case ALCHEMY_CPU_AU1550: - au1000_usb_init(AU1550_USB_OHCI_PHYS_ADDR, AU1550_OHCICFG); - break; - case ALCHEMY_CPU_AU1200: - au1200_usb_init(); - break; - case ALCHEMY_CPU_AU1300: - au1300_usb_init(); - break; - } - - register_syscore_ops(&alchemy_usb_pm_ops); - - return 0; -} -arch_initcall(alchemy_usb_init); diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-atmel.c b/ANDROID_3.4.5/drivers/usb/host/ehci-atmel.c deleted file mode 100644 index cf14c95a..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-atmel.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Driver for EHCI UHP on Atmel chips - * - * Copyright (C) 2009 Atmel Corporation, - * Nicolas Ferre - * - * Based on various ehci-*.c drivers - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - */ - -#include -#include -#include -#include - -/* interface and function clocks */ -static struct clk *iclk, *fclk; -static int clocked; - -/*-------------------------------------------------------------------------*/ - -static void atmel_start_clock(void) -{ - clk_enable(iclk); - clk_enable(fclk); - clocked = 1; -} - -static void atmel_stop_clock(void) -{ - clk_disable(fclk); - clk_disable(iclk); - clocked = 0; -} - -static void atmel_start_ehci(struct platform_device *pdev) -{ - dev_dbg(&pdev->dev, "start\n"); - atmel_start_clock(); -} - -static void atmel_stop_ehci(struct platform_device *pdev) -{ - dev_dbg(&pdev->dev, "stop\n"); - atmel_stop_clock(); -} - -/*-------------------------------------------------------------------------*/ - -static int ehci_atmel_setup(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval = 0; - - /* registers start at offset 0x0 */ - ehci->caps = hcd->regs; - ehci->regs = hcd->regs + - HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); - dbg_hcs_params(ehci, "reset"); - dbg_hcc_params(ehci, "reset"); - - /* cache this readonly data; minimize chip reads */ - ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); - - retval = ehci_halt(ehci); - if (retval) - return retval; - - /* data structure init */ - retval = ehci_init(hcd); - if (retval) - return retval; - - ehci->sbrn = 0x20; - - ehci_reset(ehci); - ehci_port_power(ehci, 0); - - return retval; -} - -static const struct hc_driver ehci_atmel_hc_driver = { - .description = hcd_name, - .product_desc = "Atmel EHCI UHP HS", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* generic hardware linkage */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* basic lifecycle operations */ - .reset = ehci_atmel_setup, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* managing i/o requests and associated device resources */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* scheduling support */ - .get_frame_number = ehci_get_frame, - - /* root hub support */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static u64 at91_ehci_dma_mask = DMA_BIT_MASK(32); - -static int __devinit ehci_atmel_drv_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - const struct hc_driver *driver = &ehci_atmel_hc_driver; - struct resource *res; - int irq; - int retval; - - if (usb_disabled()) - return -ENODEV; - - pr_debug("Initializing Atmel-SoC USB Host Controller\n"); - - irq = platform_get_irq(pdev, 0); - if (irq <= 0) { - dev_err(&pdev->dev, - "Found HC with no IRQ. Check %s setup!\n", - dev_name(&pdev->dev)); - retval = -ENODEV; - goto fail_create_hcd; - } - - /* Right now device-tree probed devices don't get dma_mask set. - * Since shared usb code relies on it, set it here for now. - * Once we have dma capability bindings this can go away. - */ - if (!pdev->dev.dma_mask) - pdev->dev.dma_mask = &at91_ehci_dma_mask; - - hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - retval = -ENOMEM; - goto fail_create_hcd; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, - "Found HC with no register addr. Check %s setup!\n", - dev_name(&pdev->dev)); - retval = -ENODEV; - goto fail_request_resource; - } - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) { - dev_dbg(&pdev->dev, "controller already in use\n"); - retval = -EBUSY; - goto fail_request_resource; - } - - hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); - if (hcd->regs == NULL) { - dev_dbg(&pdev->dev, "error mapping memory\n"); - retval = -EFAULT; - goto fail_ioremap; - } - - iclk = clk_get(&pdev->dev, "ehci_clk"); - if (IS_ERR(iclk)) { - dev_err(&pdev->dev, "Error getting interface clock\n"); - retval = -ENOENT; - goto fail_get_iclk; - } - fclk = clk_get(&pdev->dev, "uhpck"); - if (IS_ERR(fclk)) { - dev_err(&pdev->dev, "Error getting function clock\n"); - retval = -ENOENT; - goto fail_get_fclk; - } - - atmel_start_ehci(pdev); - - retval = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (retval) - goto fail_add_hcd; - - return retval; - -fail_add_hcd: - atmel_stop_ehci(pdev); - clk_put(fclk); -fail_get_fclk: - clk_put(iclk); -fail_get_iclk: - iounmap(hcd->regs); -fail_ioremap: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -fail_request_resource: - usb_put_hcd(hcd); -fail_create_hcd: - dev_err(&pdev->dev, "init %s fail, %d\n", - dev_name(&pdev->dev), retval); - - return retval; -} - -static int __devexit ehci_atmel_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - ehci_shutdown(hcd); - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - - atmel_stop_ehci(pdev); - clk_put(fclk); - clk_put(iclk); - fclk = iclk = NULL; - - return 0; -} - -#ifdef CONFIG_OF -static const struct of_device_id atmel_ehci_dt_ids[] = { - { .compatible = "atmel,at91sam9g45-ehci" }, - { /* sentinel */ } -}; - -MODULE_DEVICE_TABLE(of, atmel_ehci_dt_ids); -#endif - -static struct platform_driver ehci_atmel_driver = { - .probe = ehci_atmel_drv_probe, - .remove = __devexit_p(ehci_atmel_drv_remove), - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "atmel-ehci", - .of_match_table = of_match_ptr(atmel_ehci_dt_ids), - }, -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-au1xxx.c b/ANDROID_3.4.5/drivers/usb/host/ehci-au1xxx.c deleted file mode 100644 index bf7441af..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-au1xxx.c +++ /dev/null @@ -1,267 +0,0 @@ -/* - * EHCI HCD (Host Controller Driver) for USB. - * - * Bus Glue for AMD Alchemy Au1xxx - * - * Based on "ohci-au1xxx.c" by Matt Porter - * - * Modified for AMD Alchemy Au1200 EHC - * by K.Boge - * - * This file is licenced under the GPL. - */ - -#include -#include - - -extern int usb_disabled(void); - -static int au1xxx_ehci_setup(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int ret = ehci_init(hcd); - - ehci->need_io_watchdog = 0; - ehci_reset(ehci); - return ret; -} - -static const struct hc_driver ehci_au1xxx_hc_driver = { - .description = hcd_name, - .product_desc = "Au1xxx EHCI", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* - * basic lifecycle operations - * - * FIXME -- ehci_init() doesn't do enough here. - * See ehci-ppc-soc for a complete implementation. - */ - .reset = au1xxx_ehci_setup, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - struct ehci_hcd *ehci; - struct resource *res; - int ret; - - if (usb_disabled()) - return -ENODEV; - - if (pdev->resource[1].flags != IORESOURCE_IRQ) { - pr_debug("resource[1] is not IORESOURCE_IRQ"); - return -ENOMEM; - } - hcd = usb_create_hcd(&ehci_au1xxx_hc_driver, &pdev->dev, "Au1xxx"); - if (!hcd) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - pr_debug("request_mem_region failed"); - ret = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - pr_debug("ioremap failed"); - ret = -ENOMEM; - goto err2; - } - - if (alchemy_usb_control(ALCHEMY_USB_EHCI0, 1)) { - printk(KERN_INFO "%s: controller init failed!\n", pdev->name); - ret = -ENODEV; - goto err3; - } - - ehci = hcd_to_ehci(hcd); - ehci->caps = hcd->regs; - ehci->regs = hcd->regs + - HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase)); - /* cache this readonly data; minimize chip reads */ - ehci->hcs_params = readl(&ehci->caps->hcs_params); - - ret = usb_add_hcd(hcd, pdev->resource[1].start, - IRQF_SHARED); - if (ret == 0) { - platform_set_drvdata(pdev, hcd); - return ret; - } - - alchemy_usb_control(ALCHEMY_USB_EHCI0, 0); -err3: - iounmap(hcd->regs); -err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err1: - usb_put_hcd(hcd); - return ret; -} - -static int ehci_hcd_au1xxx_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - alchemy_usb_control(ALCHEMY_USB_EHCI0, 0); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - platform_set_drvdata(pdev, NULL); - - return 0; -} - -#ifdef CONFIG_PM -static int ehci_hcd_au1xxx_drv_suspend(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - unsigned long flags; - int rc = 0; - - if (time_before(jiffies, ehci->next_statechange)) - msleep(10); - - /* Root hub was already suspended. Disable irq emission and - * mark HW unaccessible. The PM and USB cores make sure that - * the root hub is either suspended or stopped. - */ - ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev)); - spin_lock_irqsave(&ehci->lock, flags); - ehci_writel(ehci, 0, &ehci->regs->intr_enable); - (void)ehci_readl(ehci, &ehci->regs->intr_enable); - - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - spin_unlock_irqrestore(&ehci->lock, flags); - - // could save FLADJ in case of Vaux power loss - // ... we'd only use it to handle clock skew - - alchemy_usb_control(ALCHEMY_USB_EHCI0, 0); - - return rc; -} - -static int ehci_hcd_au1xxx_drv_resume(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - - alchemy_usb_control(ALCHEMY_USB_EHCI0, 1); - - // maybe restore FLADJ - - if (time_before(jiffies, ehci->next_statechange)) - msleep(100); - - /* 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. - * Just undo the effect of ehci_pci_suspend(). - */ - if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) { - int mask = INTR_MASK; - - ehci_prepare_ports_for_controller_resume(ehci); - if (!hcd->self.root_hub->do_remote_wakeup) - mask &= ~STS_PCD; - ehci_writel(ehci, mask, &ehci->regs->intr_enable); - ehci_readl(ehci, &ehci->regs->intr_enable); - 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 - * style "resume" having let BIOS kick in during reboot. - */ - (void) ehci_halt(ehci); - (void) ehci_reset(ehci); - - /* emptying the schedule aborts any urbs */ - spin_lock_irq(&ehci->lock); - if (ehci->reclaim) - end_unlink_async(ehci); - ehci_work(ehci); - spin_unlock_irq(&ehci->lock); - - ehci_writel(ehci, ehci->command, &ehci->regs->command); - ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); - ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ - - /* here we "know" root ports should always stay powered */ - ehci_port_power(ehci, 1); - - ehci->rh_state = EHCI_RH_SUSPENDED; - - return 0; -} - -static const struct dev_pm_ops au1xxx_ehci_pmops = { - .suspend = ehci_hcd_au1xxx_drv_suspend, - .resume = ehci_hcd_au1xxx_drv_resume, -}; - -#define AU1XXX_EHCI_PMOPS &au1xxx_ehci_pmops - -#else -#define AU1XXX_EHCI_PMOPS NULL -#endif - -static struct platform_driver ehci_hcd_au1xxx_driver = { - .probe = ehci_hcd_au1xxx_drv_probe, - .remove = ehci_hcd_au1xxx_drv_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "au1xxx-ehci", - .owner = THIS_MODULE, - .pm = AU1XXX_EHCI_PMOPS, - } -}; - -MODULE_ALIAS("platform:au1xxx-ehci"); diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-cns3xxx.c b/ANDROID_3.4.5/drivers/usb/host/ehci-cns3xxx.c deleted file mode 100644 index 6536abde..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-cns3xxx.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright 2008 Cavium Networks - * - * This file 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. - */ - -#include -#include -#include -#include - -static int cns3xxx_ehci_init(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; - - /* - * EHCI and OHCI share the same clock and power, - * resetting twice would cause the 1st controller been reset. - * Therefore only do power up at the first up device, and - * power down at the last down device. - * - * Set USB AHB INCR length to 16 - */ - if (atomic_inc_return(&usb_pwr_ref) == 1) { - cns3xxx_pwr_power_up(1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_PLL_USB); - cns3xxx_pwr_clk_en(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); - cns3xxx_pwr_soft_rst(1 << PM_SOFT_RST_REG_OFFST_USB_HOST); - __raw_writel((__raw_readl(MISC_CHIP_CONFIG_REG) | (0X2 << 24)), - MISC_CHIP_CONFIG_REG); - } - - ehci->caps = hcd->regs; - ehci->regs = hcd->regs - + HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); - ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); - - hcd->has_tt = 0; - ehci_reset(ehci); - - retval = ehci_init(hcd); - if (retval) - return retval; - - ehci_port_power(ehci, 0); - - return retval; -} - -static const struct hc_driver cns3xxx_ehci_hc_driver = { - .description = hcd_name, - .product_desc = "CNS3XXX EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - .reset = cns3xxx_ehci_init, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - .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, -#ifdef CONFIG_PM - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, -#endif - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static int cns3xxx_ehci_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct usb_hcd *hcd; - const struct hc_driver *driver = &cns3xxx_ehci_hc_driver; - struct resource *res; - int irq; - int retval; - - if (usb_disabled()) - return -ENODEV; - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(dev, "Found HC with no IRQ.\n"); - return -ENODEV; - } - irq = res->start; - - hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "Found HC with no register addr.\n"); - retval = -ENODEV; - goto err1; - } - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) { - dev_dbg(dev, "controller already in use\n"); - retval = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (hcd->regs == NULL) { - dev_dbg(dev, "error mapping memory\n"); - retval = -EFAULT; - goto err2; - } - - retval = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (retval == 0) - return retval; - - iounmap(hcd->regs); -err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err1: - usb_put_hcd(hcd); - - return retval; -} - -static int cns3xxx_ehci_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - - /* - * EHCI and OHCI share the same clock and power, - * resetting twice would cause the 1st controller been reset. - * Therefore only do power up at the first up device, and - * power down at the last down device. - */ - if (atomic_dec_return(&usb_pwr_ref) == 0) - cns3xxx_pwr_clk_dis(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); - - usb_put_hcd(hcd); - - platform_set_drvdata(pdev, NULL); - - return 0; -} - -MODULE_ALIAS("platform:cns3xxx-ehci"); - -static struct platform_driver cns3xxx_ehci_driver = { - .probe = cns3xxx_ehci_probe, - .remove = cns3xxx_ehci_remove, - .driver = { - .name = "cns3xxx-ehci", - }, -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-dbg.c b/ANDROID_3.4.5/drivers/usb/host/ehci-dbg.c deleted file mode 100644 index 680e1a31..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-dbg.c +++ /dev/null @@ -1,1089 +0,0 @@ -/* - * Copyright (c) 2001-2002 by David Brownell - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* this file is part of ehci-hcd.c */ - -#define ehci_dbg(ehci, fmt, args...) \ - dev_dbg (ehci_to_hcd(ehci)->self.controller , fmt , ## args ) -#define ehci_err(ehci, fmt, args...) \ - dev_err (ehci_to_hcd(ehci)->self.controller , fmt , ## args ) -#define ehci_info(ehci, fmt, args...) \ - dev_info (ehci_to_hcd(ehci)->self.controller , fmt , ## args ) -#define ehci_warn(ehci, fmt, args...) \ - dev_warn (ehci_to_hcd(ehci)->self.controller , fmt , ## args ) - -#ifdef VERBOSE_DEBUG -# define ehci_vdbg ehci_dbg -#else - static inline void ehci_vdbg(struct ehci_hcd *ehci, ...) {} -#endif - -#ifdef DEBUG - -/* check the values in the HCSPARAMS register - * (host controller _Structural_ parameters) - * see EHCI spec, Table 2-4 for each value - */ -static void dbg_hcs_params (struct ehci_hcd *ehci, char *label) -{ - u32 params = ehci_readl(ehci, &ehci->caps->hcs_params); - - ehci_dbg (ehci, - "%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d\n", - label, params, - HCS_DEBUG_PORT (params), - HCS_INDICATOR (params) ? " ind" : "", - HCS_N_CC (params), - HCS_N_PCC (params), - HCS_PORTROUTED (params) ? "" : " ordered", - HCS_PPC (params) ? "" : " !ppc", - HCS_N_PORTS (params) - ); - /* Port routing, per EHCI 0.95 Spec, Section 2.2.5 */ - if (HCS_PORTROUTED (params)) { - int i; - char buf [46], tmp [7], byte; - - buf[0] = 0; - for (i = 0; i < HCS_N_PORTS (params); i++) { - // FIXME MIPS won't readb() ... - byte = readb (&ehci->caps->portroute[(i>>1)]); - sprintf(tmp, "%d ", - ((i & 0x1) ? ((byte)&0xf) : ((byte>>4)&0xf))); - strcat(buf, tmp); - } - ehci_dbg (ehci, "%s portroute %s\n", - label, buf); - } -} -#else - -static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {} - -#endif - -#ifdef DEBUG - -/* check the values in the HCCPARAMS register - * (host controller _Capability_ parameters) - * see EHCI Spec, Table 2-5 for each value - * */ -static void dbg_hcc_params (struct ehci_hcd *ehci, char *label) -{ - u32 params = ehci_readl(ehci, &ehci->caps->hcc_params); - - if (HCC_ISOC_CACHE (params)) { - ehci_dbg (ehci, - "%s hcc_params %04x caching frame %s%s%s\n", - label, params, - HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024", - HCC_CANPARK(params) ? " park" : "", - HCC_64BIT_ADDR(params) ? " 64 bit addr" : ""); - } else { - ehci_dbg (ehci, - "%s hcc_params %04x thresh %d uframes %s%s%s%s%s%s%s\n", - label, - params, - HCC_ISOC_THRES(params), - HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024", - HCC_CANPARK(params) ? " park" : "", - HCC_64BIT_ADDR(params) ? " 64 bit addr" : "", - HCC_LPM(params) ? " LPM" : "", - HCC_PER_PORT_CHANGE_EVENT(params) ? " ppce" : "", - HCC_HW_PREFETCH(params) ? " hw prefetch" : "", - HCC_32FRAME_PERIODIC_LIST(params) ? - " 32 periodic list" : ""); - } -} -#else - -static inline void dbg_hcc_params (struct ehci_hcd *ehci, char *label) {} - -#endif - -#ifdef DEBUG - -static void __maybe_unused -dbg_qtd (const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd) -{ - ehci_dbg(ehci, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd, - hc32_to_cpup(ehci, &qtd->hw_next), - hc32_to_cpup(ehci, &qtd->hw_alt_next), - hc32_to_cpup(ehci, &qtd->hw_token), - hc32_to_cpup(ehci, &qtd->hw_buf [0])); - if (qtd->hw_buf [1]) - ehci_dbg(ehci, " p1=%08x p2=%08x p3=%08x p4=%08x\n", - hc32_to_cpup(ehci, &qtd->hw_buf[1]), - hc32_to_cpup(ehci, &qtd->hw_buf[2]), - hc32_to_cpup(ehci, &qtd->hw_buf[3]), - hc32_to_cpup(ehci, &qtd->hw_buf[4])); -} - -static void __maybe_unused -dbg_qh (const char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) -{ - struct ehci_qh_hw *hw = qh->hw; - - ehci_dbg (ehci, "%s qh %p n%08x info %x %x qtd %x\n", label, - qh, hw->hw_next, hw->hw_info1, hw->hw_info2, hw->hw_current); - dbg_qtd("overlay", ehci, (struct ehci_qtd *) &hw->hw_qtd_next); -} - -static void __maybe_unused -dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd) -{ - ehci_dbg (ehci, "%s [%d] itd %p, next %08x, urb %p\n", - label, itd->frame, itd, hc32_to_cpu(ehci, itd->hw_next), - itd->urb); - ehci_dbg (ehci, - " trans: %08x %08x %08x %08x %08x %08x %08x %08x\n", - hc32_to_cpu(ehci, itd->hw_transaction[0]), - hc32_to_cpu(ehci, itd->hw_transaction[1]), - hc32_to_cpu(ehci, itd->hw_transaction[2]), - hc32_to_cpu(ehci, itd->hw_transaction[3]), - hc32_to_cpu(ehci, itd->hw_transaction[4]), - hc32_to_cpu(ehci, itd->hw_transaction[5]), - hc32_to_cpu(ehci, itd->hw_transaction[6]), - hc32_to_cpu(ehci, itd->hw_transaction[7])); - ehci_dbg (ehci, - " buf: %08x %08x %08x %08x %08x %08x %08x\n", - hc32_to_cpu(ehci, itd->hw_bufp[0]), - hc32_to_cpu(ehci, itd->hw_bufp[1]), - hc32_to_cpu(ehci, itd->hw_bufp[2]), - hc32_to_cpu(ehci, itd->hw_bufp[3]), - hc32_to_cpu(ehci, itd->hw_bufp[4]), - hc32_to_cpu(ehci, itd->hw_bufp[5]), - hc32_to_cpu(ehci, itd->hw_bufp[6])); - ehci_dbg (ehci, " index: %d %d %d %d %d %d %d %d\n", - itd->index[0], itd->index[1], itd->index[2], - itd->index[3], itd->index[4], itd->index[5], - itd->index[6], itd->index[7]); -} - -static void __maybe_unused -dbg_sitd (const char *label, struct ehci_hcd *ehci, struct ehci_sitd *sitd) -{ - ehci_dbg (ehci, "%s [%d] sitd %p, next %08x, urb %p\n", - label, sitd->frame, sitd, hc32_to_cpu(ehci, sitd->hw_next), - sitd->urb); - ehci_dbg (ehci, - " addr %08x sched %04x result %08x buf %08x %08x\n", - hc32_to_cpu(ehci, sitd->hw_fullspeed_ep), - hc32_to_cpu(ehci, sitd->hw_uframe), - hc32_to_cpu(ehci, sitd->hw_results), - hc32_to_cpu(ehci, sitd->hw_buf[0]), - hc32_to_cpu(ehci, sitd->hw_buf[1])); -} - -static int __maybe_unused -dbg_status_buf (char *buf, unsigned len, const char *label, u32 status) -{ - return scnprintf (buf, len, - "%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s%s", - label, label [0] ? " " : "", status, - (status & STS_PPCE_MASK) ? " PPCE" : "", - (status & STS_ASS) ? " Async" : "", - (status & STS_PSS) ? " Periodic" : "", - (status & STS_RECL) ? " Recl" : "", - (status & STS_HALT) ? " Halt" : "", - (status & STS_IAA) ? " IAA" : "", - (status & STS_FATAL) ? " FATAL" : "", - (status & STS_FLR) ? " FLR" : "", - (status & STS_PCD) ? " PCD" : "", - (status & STS_ERR) ? " ERR" : "", - (status & STS_INT) ? " INT" : "" - ); -} - -static int __maybe_unused -dbg_intr_buf (char *buf, unsigned len, const char *label, u32 enable) -{ - return scnprintf (buf, len, - "%s%sintrenable %02x%s%s%s%s%s%s%s", - label, label [0] ? " " : "", enable, - (enable & STS_PPCE_MASK) ? " PPCE" : "", - (enable & STS_IAA) ? " IAA" : "", - (enable & STS_FATAL) ? " FATAL" : "", - (enable & STS_FLR) ? " FLR" : "", - (enable & STS_PCD) ? " PCD" : "", - (enable & STS_ERR) ? " ERR" : "", - (enable & STS_INT) ? " INT" : "" - ); -} - -static const char *const fls_strings [] = - { "1024", "512", "256", "??" }; - -static int -dbg_command_buf (char *buf, unsigned len, const char *label, u32 command) -{ - return scnprintf (buf, len, - "%s%scommand %07x %s%s%s%s%s%s=%d ithresh=%d%s%s%s%s " - "period=%s%s %s", - label, label [0] ? " " : "", command, - (command & CMD_HIRD) ? " HIRD" : "", - (command & CMD_PPCEE) ? " PPCEE" : "", - (command & CMD_FSP) ? " FSP" : "", - (command & CMD_ASPE) ? " ASPE" : "", - (command & CMD_PSPE) ? " PSPE" : "", - (command & CMD_PARK) ? " park" : "(park)", - CMD_PARK_CNT (command), - (command >> 16) & 0x3f, - (command & CMD_LRESET) ? " LReset" : "", - (command & CMD_IAAD) ? " IAAD" : "", - (command & CMD_ASE) ? " Async" : "", - (command & CMD_PSE) ? " Periodic" : "", - fls_strings [(command >> 2) & 0x3], - (command & CMD_RESET) ? " Reset" : "", - (command & CMD_RUN) ? "RUN" : "HALT" - ); -} - -static int -dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status) -{ - char *sig; - - /* signaling state */ - switch (status & (3 << 10)) { - case 0 << 10: sig = "se0"; break; - case 1 << 10: sig = "k"; break; /* low speed */ - case 2 << 10: sig = "j"; break; - default: sig = "?"; break; - } - - return scnprintf (buf, len, - "%s%sport:%d status %06x %d %s%s%s%s%s%s " - "sig=%s%s%s%s%s%s%s%s%s%s%s", - label, label [0] ? " " : "", port, status, - status>>25,/*device address */ - (status & PORT_SSTS)>>23 == PORTSC_SUSPEND_STS_ACK ? - " ACK" : "", - (status & PORT_SSTS)>>23 == PORTSC_SUSPEND_STS_NYET ? - " NYET" : "", - (status & PORT_SSTS)>>23 == PORTSC_SUSPEND_STS_STALL ? - " STALL" : "", - (status & PORT_SSTS)>>23 == PORTSC_SUSPEND_STS_ERR ? - " ERR" : "", - (status & PORT_POWER) ? " POWER" : "", - (status & PORT_OWNER) ? " OWNER" : "", - sig, - (status & PORT_LPM) ? " LPM" : "", - (status & PORT_RESET) ? " RESET" : "", - (status & PORT_SUSPEND) ? " SUSPEND" : "", - (status & PORT_RESUME) ? " RESUME" : "", - (status & PORT_OCC) ? " OCC" : "", - (status & PORT_OC) ? " OC" : "", - (status & PORT_PEC) ? " PEC" : "", - (status & PORT_PE) ? " PE" : "", - (status & PORT_CSC) ? " CSC" : "", - (status & PORT_CONNECT) ? " CONNECT" : ""); -} - -#else -static inline void __maybe_unused -dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) -{} - -static inline int __maybe_unused -dbg_status_buf (char *buf, unsigned len, const char *label, u32 status) -{ return 0; } - -static inline int __maybe_unused -dbg_command_buf (char *buf, unsigned len, const char *label, u32 command) -{ return 0; } - -static inline int __maybe_unused -dbg_intr_buf (char *buf, unsigned len, const char *label, u32 enable) -{ return 0; } - -static inline int __maybe_unused -dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status) -{ return 0; } - -#endif /* DEBUG */ - -/* functions have the "wrong" filename when they're output... */ -#define dbg_status(ehci, label, status) { \ - char _buf [80]; \ - dbg_status_buf (_buf, sizeof _buf, label, status); \ - ehci_dbg (ehci, "%s\n", _buf); \ -} - -#define dbg_cmd(ehci, label, command) { \ - char _buf [80]; \ - dbg_command_buf (_buf, sizeof _buf, label, command); \ - ehci_dbg (ehci, "%s\n", _buf); \ -} - -#define dbg_port(ehci, label, port, status) { \ - char _buf [80]; \ - dbg_port_buf (_buf, sizeof _buf, label, port, status); \ - ehci_dbg (ehci, "%s\n", _buf); \ -} - -/*-------------------------------------------------------------------------*/ - -#ifdef STUB_DEBUG_FILES - -static inline void create_debug_files (struct ehci_hcd *bus) { } -static inline void remove_debug_files (struct ehci_hcd *bus) { } - -#else - -/* troubleshooting help: expose state in debugfs */ - -static int debug_async_open(struct inode *, struct file *); -static int debug_periodic_open(struct inode *, struct file *); -static int debug_registers_open(struct inode *, struct file *); -static int debug_async_open(struct inode *, struct file *); -static ssize_t debug_lpm_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -static ssize_t debug_lpm_write(struct file *file, const char __user *buffer, - size_t count, loff_t *ppos); -static int debug_lpm_close(struct inode *inode, struct file *file); - -static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*); -static int debug_close(struct inode *, struct file *); - -static const struct file_operations debug_async_fops = { - .owner = THIS_MODULE, - .open = debug_async_open, - .read = debug_output, - .release = debug_close, - .llseek = default_llseek, -}; -static const struct file_operations debug_periodic_fops = { - .owner = THIS_MODULE, - .open = debug_periodic_open, - .read = debug_output, - .release = debug_close, - .llseek = default_llseek, -}; -static const struct file_operations debug_registers_fops = { - .owner = THIS_MODULE, - .open = debug_registers_open, - .read = debug_output, - .release = debug_close, - .llseek = default_llseek, -}; -static const struct file_operations debug_lpm_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = debug_lpm_read, - .write = debug_lpm_write, - .release = debug_lpm_close, - .llseek = noop_llseek, -}; - -static struct dentry *ehci_debug_root; - -struct debug_buffer { - ssize_t (*fill_func)(struct debug_buffer *); /* fill method */ - struct usb_bus *bus; - struct mutex mutex; /* protect filling of buffer */ - size_t count; /* number of characters filled into buffer */ - char *output_buf; - size_t alloc_size; -}; - -#define speed_char(info1) ({ char tmp; \ - switch (info1 & (3 << 12)) { \ - case 0 << 12: tmp = 'f'; break; \ - case 1 << 12: tmp = 'l'; break; \ - case 2 << 12: tmp = 'h'; break; \ - default: tmp = '?'; break; \ - }; tmp; }) - -static inline char token_mark(struct ehci_hcd *ehci, __hc32 token) -{ - __u32 v = hc32_to_cpu(ehci, token); - - if (v & QTD_STS_ACTIVE) - return '*'; - if (v & QTD_STS_HALT) - return '-'; - if (!IS_SHORT_READ (v)) - return ' '; - /* tries to advance through hw_alt_next */ - return '/'; -} - -static void qh_lines ( - struct ehci_hcd *ehci, - struct ehci_qh *qh, - char **nextp, - unsigned *sizep -) -{ - u32 scratch; - u32 hw_curr; - struct list_head *entry; - struct ehci_qtd *td; - unsigned temp; - unsigned size = *sizep; - char *next = *nextp; - char mark; - __le32 list_end = EHCI_LIST_END(ehci); - struct ehci_qh_hw *hw = qh->hw; - - if (hw->hw_qtd_next == list_end) /* NEC does this */ - mark = '@'; - else - mark = token_mark(ehci, hw->hw_token); - if (mark == '/') { /* qh_alt_next controls qh advance? */ - if ((hw->hw_alt_next & QTD_MASK(ehci)) - == ehci->async->hw->hw_alt_next) - mark = '#'; /* blocked */ - else if (hw->hw_alt_next == list_end) - mark = '.'; /* use hw_qtd_next */ - /* else alt_next points to some other qtd */ - } - scratch = hc32_to_cpup(ehci, &hw->hw_info1); - hw_curr = (mark == '*') ? hc32_to_cpup(ehci, &hw->hw_current) : 0; - temp = scnprintf (next, size, - "qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)", - qh, scratch & 0x007f, - speed_char (scratch), - (scratch >> 8) & 0x000f, - scratch, hc32_to_cpup(ehci, &hw->hw_info2), - hc32_to_cpup(ehci, &hw->hw_token), mark, - (cpu_to_hc32(ehci, QTD_TOGGLE) & hw->hw_token) - ? "data1" : "data0", - (hc32_to_cpup(ehci, &hw->hw_alt_next) >> 1) & 0x0f); - size -= temp; - next += temp; - - /* hc may be modifying the list as we read it ... */ - list_for_each (entry, &qh->qtd_list) { - td = list_entry (entry, struct ehci_qtd, qtd_list); - scratch = hc32_to_cpup(ehci, &td->hw_token); - mark = ' '; - if (hw_curr == td->qtd_dma) - mark = '*'; - else if (hw->hw_qtd_next == cpu_to_hc32(ehci, td->qtd_dma)) - mark = '+'; - else if (QTD_LENGTH (scratch)) { - if (td->hw_alt_next == ehci->async->hw->hw_alt_next) - mark = '#'; - else if (td->hw_alt_next != list_end) - mark = '/'; - } - temp = snprintf (next, size, - "\n\t%p%c%s len=%d %08x urb %p", - td, mark, ({ char *tmp; - switch ((scratch>>8)&0x03) { - case 0: tmp = "out"; break; - case 1: tmp = "in"; break; - case 2: tmp = "setup"; break; - default: tmp = "?"; break; - } tmp;}), - (scratch >> 16) & 0x7fff, - scratch, - td->urb); - if (size < temp) - temp = size; - size -= temp; - next += temp; - if (temp == size) - goto done; - } - - temp = snprintf (next, size, "\n"); - if (size < temp) - temp = size; - size -= temp; - next += temp; - -done: - *sizep = size; - *nextp = next; -} - -static ssize_t fill_async_buffer(struct debug_buffer *buf) -{ - struct usb_hcd *hcd; - struct ehci_hcd *ehci; - unsigned long flags; - unsigned temp, size; - char *next; - struct ehci_qh *qh; - - hcd = bus_to_hcd(buf->bus); - ehci = hcd_to_ehci (hcd); - next = buf->output_buf; - size = buf->alloc_size; - - *next = 0; - - /* dumps a snapshot of the async schedule. - * usually empty except for long-term bulk reads, or head. - * one QH per line, and TDs we know about - */ - spin_lock_irqsave (&ehci->lock, flags); - for (qh = ehci->async->qh_next.qh; size > 0 && qh; qh = qh->qh_next.qh) - qh_lines (ehci, qh, &next, &size); - if (ehci->reclaim && size > 0) { - temp = scnprintf (next, size, "\nreclaim =\n"); - size -= temp; - next += temp; - - for (qh = ehci->reclaim; size > 0 && qh; qh = qh->reclaim) - qh_lines (ehci, qh, &next, &size); - } - spin_unlock_irqrestore (&ehci->lock, flags); - - return strlen(buf->output_buf); -} - -#define DBG_SCHED_LIMIT 64 -static ssize_t fill_periodic_buffer(struct debug_buffer *buf) -{ - struct usb_hcd *hcd; - struct ehci_hcd *ehci; - unsigned long flags; - union ehci_shadow p, *seen; - unsigned temp, size, seen_count; - char *next; - unsigned i; - __hc32 tag; - - if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, GFP_ATOMIC))) - return 0; - seen_count = 0; - - hcd = bus_to_hcd(buf->bus); - ehci = hcd_to_ehci (hcd); - next = buf->output_buf; - size = buf->alloc_size; - - temp = scnprintf (next, size, "size = %d\n", ehci->periodic_size); - size -= temp; - next += temp; - - /* dump a snapshot of the periodic schedule. - * iso changes, interrupt usually doesn't. - */ - spin_lock_irqsave (&ehci->lock, flags); - for (i = 0; i < ehci->periodic_size; i++) { - p = ehci->pshadow [i]; - if (likely (!p.ptr)) - continue; - tag = Q_NEXT_TYPE(ehci, ehci->periodic [i]); - - temp = scnprintf (next, size, "%4d: ", i); - size -= temp; - next += temp; - - do { - struct ehci_qh_hw *hw; - - switch (hc32_to_cpu(ehci, tag)) { - case Q_TYPE_QH: - hw = p.qh->hw; - temp = scnprintf (next, size, " qh%d-%04x/%p", - p.qh->period, - hc32_to_cpup(ehci, - &hw->hw_info2) - /* uframe masks */ - & (QH_CMASK | QH_SMASK), - p.qh); - size -= temp; - next += temp; - /* don't repeat what follows this qh */ - for (temp = 0; temp < seen_count; temp++) { - if (seen [temp].ptr != p.ptr) - continue; - if (p.qh->qh_next.ptr) { - temp = scnprintf (next, size, - " ..."); - size -= temp; - next += temp; - } - break; - } - /* show more info the first time around */ - if (temp == seen_count) { - u32 scratch = hc32_to_cpup(ehci, - &hw->hw_info1); - struct ehci_qtd *qtd; - char *type = ""; - - /* count tds, get ep direction */ - temp = 0; - list_for_each_entry (qtd, - &p.qh->qtd_list, - qtd_list) { - temp++; - switch (0x03 & (hc32_to_cpu( - ehci, - qtd->hw_token) >> 8)) { - case 0: type = "out"; continue; - case 1: type = "in"; continue; - } - } - - temp = scnprintf (next, size, - " (%c%d ep%d%s " - "[%d/%d] q%d p%d)", - speed_char (scratch), - scratch & 0x007f, - (scratch >> 8) & 0x000f, type, - p.qh->usecs, p.qh->c_usecs, - temp, - 0x7ff & (scratch >> 16)); - - if (seen_count < DBG_SCHED_LIMIT) - seen [seen_count++].qh = p.qh; - } else - temp = 0; - if (p.qh) { - tag = Q_NEXT_TYPE(ehci, hw->hw_next); - p = p.qh->qh_next; - } - break; - case Q_TYPE_FSTN: - temp = scnprintf (next, size, - " fstn-%8x/%p", p.fstn->hw_prev, - p.fstn); - tag = Q_NEXT_TYPE(ehci, p.fstn->hw_next); - p = p.fstn->fstn_next; - break; - case Q_TYPE_ITD: - temp = scnprintf (next, size, - " itd/%p", p.itd); - tag = Q_NEXT_TYPE(ehci, p.itd->hw_next); - p = p.itd->itd_next; - break; - case Q_TYPE_SITD: - temp = scnprintf (next, size, - " sitd%d-%04x/%p", - p.sitd->stream->interval, - hc32_to_cpup(ehci, &p.sitd->hw_uframe) - & 0x0000ffff, - p.sitd); - tag = Q_NEXT_TYPE(ehci, p.sitd->hw_next); - p = p.sitd->sitd_next; - break; - } - size -= temp; - next += temp; - } while (p.ptr); - - temp = scnprintf (next, size, "\n"); - size -= temp; - next += temp; - } - spin_unlock_irqrestore (&ehci->lock, flags); - kfree (seen); - - return buf->alloc_size - size; -} -#undef DBG_SCHED_LIMIT - -static const char *rh_state_string(struct ehci_hcd *ehci) -{ - switch (ehci->rh_state) { - case EHCI_RH_HALTED: - return "halted"; - case EHCI_RH_SUSPENDED: - return "suspended"; - case EHCI_RH_RUNNING: - return "running"; - } - return "?"; -} - -static ssize_t fill_registers_buffer(struct debug_buffer *buf) -{ - struct usb_hcd *hcd; - struct ehci_hcd *ehci; - unsigned long flags; - unsigned temp, size, i; - char *next, scratch [80]; - static char fmt [] = "%*s\n"; - static char label [] = ""; - - hcd = bus_to_hcd(buf->bus); - ehci = hcd_to_ehci (hcd); - next = buf->output_buf; - size = buf->alloc_size; - - spin_lock_irqsave (&ehci->lock, flags); - - if (!HCD_HW_ACCESSIBLE(hcd)) { - size = scnprintf (next, size, - "bus %s, device %s\n" - "%s\n" - "SUSPENDED (no register access)\n", - hcd->self.controller->bus->name, - dev_name(hcd->self.controller), - hcd->product_desc); - goto done; - } - - /* Capability Registers */ - i = HC_VERSION(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); - temp = scnprintf (next, size, - "bus %s, device %s\n" - "%s\n" - "EHCI %x.%02x, rh state %s\n", - hcd->self.controller->bus->name, - dev_name(hcd->self.controller), - hcd->product_desc, - i >> 8, i & 0x0ff, rh_state_string(ehci)); - size -= temp; - next += temp; - -#ifdef CONFIG_PCI - /* EHCI 0.96 and later may have "extended capabilities" */ - if (hcd->self.controller->bus == &pci_bus_type) { - struct pci_dev *pdev; - u32 offset, cap, cap2; - unsigned count = 256/4; - - pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller); - offset = HCC_EXT_CAPS(ehci_readl(ehci, - &ehci->caps->hcc_params)); - while (offset && count--) { - pci_read_config_dword (pdev, offset, &cap); - switch (cap & 0xff) { - case 1: - temp = scnprintf (next, size, - "ownership %08x%s%s\n", cap, - (cap & (1 << 24)) ? " linux" : "", - (cap & (1 << 16)) ? " firmware" : ""); - size -= temp; - next += temp; - - offset += 4; - pci_read_config_dword (pdev, offset, &cap2); - temp = scnprintf (next, size, - "SMI sts/enable 0x%08x\n", cap2); - size -= temp; - next += temp; - break; - case 0: /* illegal reserved capability */ - cap = 0; - /* FALLTHROUGH */ - default: /* unknown */ - break; - } - temp = (cap >> 8) & 0xff; - } - } -#endif - - // FIXME interpret both types of params - i = ehci_readl(ehci, &ehci->caps->hcs_params); - temp = scnprintf (next, size, "structural params 0x%08x\n", i); - size -= temp; - next += temp; - - i = ehci_readl(ehci, &ehci->caps->hcc_params); - temp = scnprintf (next, size, "capability params 0x%08x\n", i); - size -= temp; - next += temp; - - /* Operational Registers */ - temp = dbg_status_buf (scratch, sizeof scratch, label, - ehci_readl(ehci, &ehci->regs->status)); - temp = scnprintf (next, size, fmt, temp, scratch); - size -= temp; - next += temp; - - temp = dbg_command_buf (scratch, sizeof scratch, label, - ehci_readl(ehci, &ehci->regs->command)); - temp = scnprintf (next, size, fmt, temp, scratch); - size -= temp; - next += temp; - - temp = dbg_intr_buf (scratch, sizeof scratch, label, - ehci_readl(ehci, &ehci->regs->intr_enable)); - temp = scnprintf (next, size, fmt, temp, scratch); - size -= temp; - next += temp; - - temp = scnprintf (next, size, "uframe %04x\n", - ehci_read_frame_index(ehci)); - size -= temp; - next += temp; - - for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) { - temp = dbg_port_buf (scratch, sizeof scratch, label, i, - ehci_readl(ehci, - &ehci->regs->port_status[i - 1])); - temp = scnprintf (next, size, fmt, temp, scratch); - size -= temp; - next += temp; - if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) { - temp = scnprintf (next, size, - " debug control %08x\n", - ehci_readl(ehci, - &ehci->debug->control)); - size -= temp; - next += temp; - } - } - - if (ehci->reclaim) { - temp = scnprintf(next, size, "reclaim qh %p\n", ehci->reclaim); - size -= temp; - next += temp; - } - -#ifdef EHCI_STATS - temp = scnprintf (next, size, - "irq normal %ld err %ld reclaim %ld (lost %ld)\n", - ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim, - ehci->stats.lost_iaa); - size -= temp; - next += temp; - - temp = scnprintf (next, size, "complete %ld unlink %ld\n", - ehci->stats.complete, ehci->stats.unlink); - size -= temp; - next += temp; -#endif - -done: - spin_unlock_irqrestore (&ehci->lock, flags); - - return buf->alloc_size - size; -} - -static struct debug_buffer *alloc_buffer(struct usb_bus *bus, - ssize_t (*fill_func)(struct debug_buffer *)) -{ - struct debug_buffer *buf; - - buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL); - - if (buf) { - buf->bus = bus; - buf->fill_func = fill_func; - mutex_init(&buf->mutex); - buf->alloc_size = PAGE_SIZE; - } - - return buf; -} - -static int fill_buffer(struct debug_buffer *buf) -{ - int ret = 0; - - if (!buf->output_buf) - buf->output_buf = vmalloc(buf->alloc_size); - - if (!buf->output_buf) { - ret = -ENOMEM; - goto out; - } - - ret = buf->fill_func(buf); - - if (ret >= 0) { - buf->count = ret; - ret = 0; - } - -out: - return ret; -} - -static ssize_t debug_output(struct file *file, char __user *user_buf, - size_t len, loff_t *offset) -{ - struct debug_buffer *buf = file->private_data; - int ret = 0; - - mutex_lock(&buf->mutex); - if (buf->count == 0) { - ret = fill_buffer(buf); - if (ret != 0) { - mutex_unlock(&buf->mutex); - goto out; - } - } - mutex_unlock(&buf->mutex); - - ret = simple_read_from_buffer(user_buf, len, offset, - buf->output_buf, buf->count); - -out: - return ret; - -} - -static int debug_close(struct inode *inode, struct file *file) -{ - struct debug_buffer *buf = file->private_data; - - if (buf) { - vfree(buf->output_buf); - kfree(buf); - } - - return 0; -} -static int debug_async_open(struct inode *inode, struct file *file) -{ - file->private_data = alloc_buffer(inode->i_private, fill_async_buffer); - - return file->private_data ? 0 : -ENOMEM; -} - -static int debug_periodic_open(struct inode *inode, struct file *file) -{ - struct debug_buffer *buf; - buf = alloc_buffer(inode->i_private, fill_periodic_buffer); - if (!buf) - return -ENOMEM; - - buf->alloc_size = (sizeof(void *) == 4 ? 6 : 8)*PAGE_SIZE; - file->private_data = buf; - return 0; -} - -static int debug_registers_open(struct inode *inode, struct file *file) -{ - file->private_data = alloc_buffer(inode->i_private, - fill_registers_buffer); - - return file->private_data ? 0 : -ENOMEM; -} - -static int debug_lpm_close(struct inode *inode, struct file *file) -{ - return 0; -} - -static ssize_t debug_lpm_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - /* TODO: show lpm stats */ - return 0; -} - -static ssize_t debug_lpm_write(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct usb_hcd *hcd; - struct ehci_hcd *ehci; - char buf[50]; - size_t len; - u32 temp; - unsigned long port; - u32 __iomem *portsc ; - u32 params; - - hcd = bus_to_hcd(file->private_data); - ehci = hcd_to_ehci(hcd); - - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - buf[len] = '\0'; - if (len > 0 && buf[len - 1] == '\n') - buf[len - 1] = '\0'; - - if (strncmp(buf, "enable", 5) == 0) { - if (strict_strtoul(buf + 7, 10, &port)) - return -EINVAL; - params = ehci_readl(ehci, &ehci->caps->hcs_params); - if (port > HCS_N_PORTS(params)) { - ehci_dbg(ehci, "ERR: LPM on bad port %lu\n", port); - return -ENODEV; - } - portsc = &ehci->regs->port_status[port-1]; - temp = ehci_readl(ehci, portsc); - if (!(temp & PORT_DEV_ADDR)) { - ehci_dbg(ehci, "LPM: no device attached\n"); - return -ENODEV; - } - temp |= PORT_LPM; - ehci_writel(ehci, temp, portsc); - printk(KERN_INFO "force enable LPM for port %lu\n", port); - } else if (strncmp(buf, "hird=", 5) == 0) { - unsigned long hird; - if (strict_strtoul(buf + 5, 16, &hird)) - return -EINVAL; - printk(KERN_INFO "setting hird %s %lu\n", buf + 6, hird); - temp = ehci_readl(ehci, &ehci->regs->command); - temp &= ~CMD_HIRD; - temp |= hird << 24; - ehci_writel(ehci, temp, &ehci->regs->command); - } else if (strncmp(buf, "disable", 7) == 0) { - if (strict_strtoul(buf + 8, 10, &port)) - return -EINVAL; - params = ehci_readl(ehci, &ehci->caps->hcs_params); - if (port > HCS_N_PORTS(params)) { - ehci_dbg(ehci, "ERR: LPM off bad port %lu\n", port); - return -ENODEV; - } - portsc = &ehci->regs->port_status[port-1]; - temp = ehci_readl(ehci, portsc); - if (!(temp & PORT_DEV_ADDR)) { - ehci_dbg(ehci, "ERR: no device attached\n"); - return -ENODEV; - } - temp &= ~PORT_LPM; - ehci_writel(ehci, temp, portsc); - printk(KERN_INFO "disabled LPM for port %lu\n", port); - } else - return -EOPNOTSUPP; - return count; -} - -static inline void create_debug_files (struct ehci_hcd *ehci) -{ - struct usb_bus *bus = &ehci_to_hcd(ehci)->self; - - ehci->debug_dir = debugfs_create_dir(bus->bus_name, ehci_debug_root); - if (!ehci->debug_dir) - return; - - if (!debugfs_create_file("async", S_IRUGO, ehci->debug_dir, bus, - &debug_async_fops)) - goto file_error; - - if (!debugfs_create_file("periodic", S_IRUGO, ehci->debug_dir, bus, - &debug_periodic_fops)) - goto file_error; - - if (!debugfs_create_file("registers", S_IRUGO, ehci->debug_dir, bus, - &debug_registers_fops)) - goto file_error; - - if (!debugfs_create_file("lpm", S_IRUGO|S_IWUSR, ehci->debug_dir, bus, - &debug_lpm_fops)) - goto file_error; - - return; - -file_error: - debugfs_remove_recursive(ehci->debug_dir); -} - -static inline void remove_debug_files (struct ehci_hcd *ehci) -{ - debugfs_remove_recursive(ehci->debug_dir); -} - -#endif /* STUB_DEBUG_FILES */ diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-fsl.c b/ANDROID_3.4.5/drivers/usb/host/ehci-fsl.c deleted file mode 100644 index d0a84bd3..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-fsl.c +++ /dev/null @@ -1,706 +0,0 @@ -/* - * Copyright 2005-2009 MontaVista Software, Inc. - * Copyright 2008 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Ported to 834x by Randy Vinson using code provided - * by Hunter Wu. - * Power Management support by Dave Liu , - * Jerry Huang and - * Anton Vorontsov . - */ - -#include -#include -#include -#include -#include -#include - -#include "ehci-fsl.h" - -/* configure so an HC device and id are always provided */ -/* always called with process context; sleeping is OK */ - -/** - * usb_hcd_fsl_probe - initialize FSL-based HCDs - * @drvier: Driver to be used for this HCD - * @pdev: USB Host Controller being probed - * Context: !in_interrupt() - * - * Allocates basic resources for this USB host controller. - * - */ -static int usb_hcd_fsl_probe(const struct hc_driver *driver, - struct platform_device *pdev) -{ - struct fsl_usb2_platform_data *pdata; - struct usb_hcd *hcd; - struct resource *res; - int irq; - int retval; - - pr_debug("initializing FSL-SOC USB Controller\n"); - - /* Need platform data for setup */ - pdata = (struct fsl_usb2_platform_data *)pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, - "No platform data for %s.\n", dev_name(&pdev->dev)); - return -ENODEV; - } - - /* - * This is a host mode driver, verify that we're supposed to be - * in host mode. - */ - if (!((pdata->operating_mode == FSL_USB2_DR_HOST) || - (pdata->operating_mode == FSL_USB2_MPH_HOST) || - (pdata->operating_mode == FSL_USB2_DR_OTG))) { - dev_err(&pdev->dev, - "Non Host Mode configured for %s. Wrong driver linked.\n", - dev_name(&pdev->dev)); - return -ENODEV; - } - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(&pdev->dev, - "Found HC with no IRQ. Check %s setup!\n", - dev_name(&pdev->dev)); - return -ENODEV; - } - irq = res->start; - - hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - retval = -ENOMEM; - goto err1; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, - "Found HC with no register addr. Check %s setup!\n", - dev_name(&pdev->dev)); - retval = -ENODEV; - goto err2; - } - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) { - dev_dbg(&pdev->dev, "controller already in use\n"); - retval = -EBUSY; - goto err2; - } - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - - if (hcd->regs == NULL) { - dev_dbg(&pdev->dev, "error mapping memory\n"); - retval = -EFAULT; - goto err3; - } - - pdata->regs = hcd->regs; - - if (pdata->power_budget) - hcd->power_budget = pdata->power_budget; - - /* - * do platform specific init: check the clock, grab/config pins, etc. - */ - if (pdata->init && pdata->init(pdev)) { - retval = -ENODEV; - goto err4; - } - - /* Enable USB controller, 83xx or 8536 */ - if (pdata->have_sysif_regs) - setbits32(hcd->regs + FSL_SOC_USB_CTRL, 0x4); - - /* Don't need to set host mode here. It will be done by tdi_reset() */ - - retval = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (retval != 0) - goto err4; - -#ifdef CONFIG_USB_OTG - if (pdata->operating_mode == FSL_USB2_DR_OTG) { - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - - ehci->transceiver = usb_get_transceiver(); - dev_dbg(&pdev->dev, "hcd=0x%p ehci=0x%p, transceiver=0x%p\n", - hcd, ehci, ehci->transceiver); - - if (ehci->transceiver) { - retval = otg_set_host(ehci->transceiver->otg, - &ehci_to_hcd(ehci)->self); - if (retval) { - if (ehci->transceiver) - put_device(ehci->transceiver->dev); - goto err4; - } - } else { - dev_err(&pdev->dev, "can't find transceiver\n"); - retval = -ENODEV; - goto err4; - } - } -#endif - return retval; - - err4: - iounmap(hcd->regs); - err3: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - err2: - usb_put_hcd(hcd); - err1: - dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval); - if (pdata->exit) - pdata->exit(pdev); - return retval; -} - -/* may be called without controller electrically present */ -/* may be called with controller, bus, and devices active */ - -/** - * usb_hcd_fsl_remove - shutdown processing for FSL-based HCDs - * @dev: USB Host Controller being removed - * Context: !in_interrupt() - * - * Reverses the effect of usb_hcd_fsl_probe(). - * - */ -static void usb_hcd_fsl_remove(struct usb_hcd *hcd, - struct platform_device *pdev) -{ - struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - - if (ehci->transceiver) { - otg_set_host(ehci->transceiver->otg, NULL); - put_device(ehci->transceiver->dev); - } - - usb_remove_hcd(hcd); - - /* - * do platform specific un-initialization: - * release iomux pins, disable clock, etc. - */ - if (pdata->exit) - pdata->exit(pdev); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); -} - -static void ehci_fsl_setup_phy(struct ehci_hcd *ehci, - enum fsl_usb2_phy_modes phy_mode, - unsigned int port_offset) -{ - u32 portsc; - struct usb_hcd *hcd = ehci_to_hcd(ehci); - void __iomem *non_ehci = hcd->regs; - struct fsl_usb2_platform_data *pdata; - - pdata = hcd->self.controller->platform_data; - - portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]); - portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW); - - switch (phy_mode) { - case FSL_USB2_PHY_ULPI: - portsc |= PORT_PTS_ULPI; - break; - case FSL_USB2_PHY_SERIAL: - portsc |= PORT_PTS_SERIAL; - break; - case FSL_USB2_PHY_UTMI_WIDE: - portsc |= PORT_PTS_PTW; - /* fall through */ - case FSL_USB2_PHY_UTMI: - /* enable UTMI PHY */ - if (pdata->have_sysif_regs) - setbits32(non_ehci + FSL_SOC_USB_CTRL, - CTRL_UTMI_PHY_EN); - portsc |= PORT_PTS_UTMI; - break; - case FSL_USB2_PHY_NONE: - break; - } - ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]); -} - -static void ehci_fsl_usb_setup(struct ehci_hcd *ehci) -{ - struct usb_hcd *hcd = ehci_to_hcd(ehci); - struct fsl_usb2_platform_data *pdata; - void __iomem *non_ehci = hcd->regs; - u32 temp; - - pdata = hcd->self.controller->platform_data; - - /* Enable PHY interface in the control reg. */ - if (pdata->have_sysif_regs) { - temp = in_be32(non_ehci + FSL_SOC_USB_CTRL); - out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004); - - /* - * Turn on cache snooping hardware, since some PowerPC platforms - * wholly rely on hardware to deal with cache coherent - */ - - /* Setup Snooping for all the 4GB space */ - /* SNOOP1 starts from 0x0, size 2G */ - out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0 | SNOOP_SIZE_2GB); - /* SNOOP2 starts from 0x80000000, size 2G */ - out_be32(non_ehci + FSL_SOC_USB_SNOOP2, 0x80000000 | SNOOP_SIZE_2GB); - } - - if ((pdata->operating_mode == FSL_USB2_DR_HOST) || - (pdata->operating_mode == FSL_USB2_DR_OTG)) - ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0); - - if (pdata->operating_mode == FSL_USB2_MPH_HOST) { - unsigned int chip, rev, svr; - - svr = mfspr(SPRN_SVR); - chip = svr >> 16; - rev = (svr >> 4) & 0xf; - - /* Deal with USB Erratum #14 on MPC834x Rev 1.0 & 1.1 chips */ - if ((rev == 1) && (chip >= 0x8050) && (chip <= 0x8055)) - ehci->has_fsl_port_bug = 1; - - if (pdata->port_enables & FSL_USB2_PORT0_ENABLED) - ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0); - if (pdata->port_enables & FSL_USB2_PORT1_ENABLED) - ehci_fsl_setup_phy(ehci, pdata->phy_mode, 1); - } - - if (pdata->have_sysif_regs) { -#ifdef CONFIG_PPC_85xx - out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x00000008); - out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000080); -#else - out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c); - out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040); -#endif - out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001); - } -} - -/* called after powerup, by probe or system-pm "wakeup" */ -static int ehci_fsl_reinit(struct ehci_hcd *ehci) -{ - ehci_fsl_usb_setup(ehci); - ehci_port_power(ehci, 0); - - return 0; -} - -/* called during probe() after chip reset completes */ -static int ehci_fsl_setup(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; - struct fsl_usb2_platform_data *pdata; - struct device *dev; - - dev = hcd->self.controller; - pdata = hcd->self.controller->platform_data; - ehci->big_endian_desc = pdata->big_endian_desc; - ehci->big_endian_mmio = pdata->big_endian_mmio; - - /* EHCI registers start at offset 0x100 */ - ehci->caps = hcd->regs + 0x100; - ehci->regs = hcd->regs + 0x100 + - HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); - dbg_hcs_params(ehci, "reset"); - dbg_hcc_params(ehci, "reset"); - - /* cache this readonly data; minimize chip reads */ - ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); - - hcd->has_tt = 1; - - retval = ehci_halt(ehci); - if (retval) - return retval; - - /* data structure init */ - retval = ehci_init(hcd); - if (retval) - return retval; - - ehci->sbrn = 0x20; - - ehci_reset(ehci); - - if (of_device_is_compatible(dev->parent->of_node, - "fsl,mpc5121-usb2-dr")) { - /* - * set SBUSCFG:AHBBRST so that control msgs don't - * fail when doing heavy PATA writes. - */ - ehci_writel(ehci, SBUSCFG_INCR8, - hcd->regs + FSL_SOC_USB_SBUSCFG); - } - - retval = ehci_fsl_reinit(ehci); - return retval; -} - -struct ehci_fsl { - struct ehci_hcd ehci; - -#ifdef CONFIG_PM - /* Saved USB PHY settings, need to restore after deep sleep. */ - u32 usb_ctrl; -#endif -}; - -#ifdef CONFIG_PM - -#ifdef CONFIG_PPC_MPC512x -static int ehci_fsl_mpc512x_drv_suspend(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - struct fsl_usb2_platform_data *pdata = dev->platform_data; - u32 tmp; - -#ifdef DEBUG - u32 mode = ehci_readl(ehci, hcd->regs + FSL_SOC_USB_USBMODE); - mode &= USBMODE_CM_MASK; - tmp = ehci_readl(ehci, hcd->regs + 0x140); /* usbcmd */ - - dev_dbg(dev, "suspend=%d already_suspended=%d " - "mode=%d usbcmd %08x\n", pdata->suspended, - pdata->already_suspended, mode, tmp); -#endif - - /* - * If the controller is already suspended, then this must be a - * PM suspend. Remember this fact, so that we will leave the - * controller suspended at PM resume time. - */ - if (pdata->suspended) { - dev_dbg(dev, "already suspended, leaving early\n"); - pdata->already_suspended = 1; - return 0; - } - - dev_dbg(dev, "suspending...\n"); - - ehci->rh_state = EHCI_RH_SUSPENDED; - dev->power.power_state = PMSG_SUSPEND; - - /* ignore non-host interrupts */ - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - - /* stop the controller */ - tmp = ehci_readl(ehci, &ehci->regs->command); - tmp &= ~CMD_RUN; - ehci_writel(ehci, tmp, &ehci->regs->command); - - /* save EHCI registers */ - pdata->pm_command = ehci_readl(ehci, &ehci->regs->command); - pdata->pm_command &= ~CMD_RUN; - pdata->pm_status = ehci_readl(ehci, &ehci->regs->status); - pdata->pm_intr_enable = ehci_readl(ehci, &ehci->regs->intr_enable); - pdata->pm_frame_index = ehci_readl(ehci, &ehci->regs->frame_index); - pdata->pm_segment = ehci_readl(ehci, &ehci->regs->segment); - pdata->pm_frame_list = ehci_readl(ehci, &ehci->regs->frame_list); - pdata->pm_async_next = ehci_readl(ehci, &ehci->regs->async_next); - pdata->pm_configured_flag = - ehci_readl(ehci, &ehci->regs->configured_flag); - pdata->pm_portsc = ehci_readl(ehci, &ehci->regs->port_status[0]); - pdata->pm_usbgenctrl = ehci_readl(ehci, - hcd->regs + FSL_SOC_USB_USBGENCTRL); - - /* clear the W1C bits */ - pdata->pm_portsc &= cpu_to_hc32(ehci, ~PORT_RWC_BITS); - - pdata->suspended = 1; - - /* clear PP to cut power to the port */ - tmp = ehci_readl(ehci, &ehci->regs->port_status[0]); - tmp &= ~PORT_POWER; - ehci_writel(ehci, tmp, &ehci->regs->port_status[0]); - - return 0; -} - -static int ehci_fsl_mpc512x_drv_resume(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - struct fsl_usb2_platform_data *pdata = dev->platform_data; - u32 tmp; - - dev_dbg(dev, "suspend=%d already_suspended=%d\n", - pdata->suspended, pdata->already_suspended); - - /* - * If the controller was already suspended at suspend time, - * then don't resume it now. - */ - if (pdata->already_suspended) { - dev_dbg(dev, "already suspended, leaving early\n"); - pdata->already_suspended = 0; - return 0; - } - - if (!pdata->suspended) { - dev_dbg(dev, "not suspended, leaving early\n"); - return 0; - } - - pdata->suspended = 0; - - dev_dbg(dev, "resuming...\n"); - - /* set host mode */ - tmp = USBMODE_CM_HOST | (pdata->es ? USBMODE_ES : 0); - ehci_writel(ehci, tmp, hcd->regs + FSL_SOC_USB_USBMODE); - - ehci_writel(ehci, pdata->pm_usbgenctrl, - hcd->regs + FSL_SOC_USB_USBGENCTRL); - ehci_writel(ehci, ISIPHYCTRL_PXE | ISIPHYCTRL_PHYE, - hcd->regs + FSL_SOC_USB_ISIPHYCTRL); - - ehci_writel(ehci, SBUSCFG_INCR8, hcd->regs + FSL_SOC_USB_SBUSCFG); - - /* restore EHCI registers */ - ehci_writel(ehci, pdata->pm_command, &ehci->regs->command); - ehci_writel(ehci, pdata->pm_intr_enable, &ehci->regs->intr_enable); - ehci_writel(ehci, pdata->pm_frame_index, &ehci->regs->frame_index); - ehci_writel(ehci, pdata->pm_segment, &ehci->regs->segment); - ehci_writel(ehci, pdata->pm_frame_list, &ehci->regs->frame_list); - ehci_writel(ehci, pdata->pm_async_next, &ehci->regs->async_next); - ehci_writel(ehci, pdata->pm_configured_flag, - &ehci->regs->configured_flag); - ehci_writel(ehci, pdata->pm_portsc, &ehci->regs->port_status[0]); - - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - ehci->rh_state = EHCI_RH_RUNNING; - dev->power.power_state = PMSG_ON; - - tmp = ehci_readl(ehci, &ehci->regs->command); - tmp |= CMD_RUN; - ehci_writel(ehci, tmp, &ehci->regs->command); - - usb_hcd_resume_root_hub(hcd); - - return 0; -} -#else -static inline int ehci_fsl_mpc512x_drv_suspend(struct device *dev) -{ - return 0; -} - -static inline int ehci_fsl_mpc512x_drv_resume(struct device *dev) -{ - return 0; -} -#endif /* CONFIG_PPC_MPC512x */ - -static struct ehci_fsl *hcd_to_ehci_fsl(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - - return container_of(ehci, struct ehci_fsl, ehci); -} - -static int ehci_fsl_drv_suspend(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd); - void __iomem *non_ehci = hcd->regs; - - if (of_device_is_compatible(dev->parent->of_node, - "fsl,mpc5121-usb2-dr")) { - return ehci_fsl_mpc512x_drv_suspend(dev); - } - - ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd), - device_may_wakeup(dev)); - if (!fsl_deep_sleep()) - return 0; - - ehci_fsl->usb_ctrl = in_be32(non_ehci + FSL_SOC_USB_CTRL); - return 0; -} - -static int ehci_fsl_drv_resume(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd); - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - void __iomem *non_ehci = hcd->regs; - - if (of_device_is_compatible(dev->parent->of_node, - "fsl,mpc5121-usb2-dr")) { - return ehci_fsl_mpc512x_drv_resume(dev); - } - - ehci_prepare_ports_for_controller_resume(ehci); - if (!fsl_deep_sleep()) - return 0; - - usb_root_hub_lost_power(hcd->self.root_hub); - - /* Restore USB PHY settings and enable the controller. */ - out_be32(non_ehci + FSL_SOC_USB_CTRL, ehci_fsl->usb_ctrl); - - ehci_reset(ehci); - ehci_fsl_reinit(ehci); - - return 0; -} - -static int ehci_fsl_drv_restore(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - - usb_root_hub_lost_power(hcd->self.root_hub); - return 0; -} - -static struct dev_pm_ops ehci_fsl_pm_ops = { - .suspend = ehci_fsl_drv_suspend, - .resume = ehci_fsl_drv_resume, - .restore = ehci_fsl_drv_restore, -}; - -#define EHCI_FSL_PM_OPS (&ehci_fsl_pm_ops) -#else -#define EHCI_FSL_PM_OPS NULL -#endif /* CONFIG_PM */ - -#ifdef CONFIG_USB_OTG -static int ehci_start_port_reset(struct usb_hcd *hcd, unsigned port) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - u32 status; - - if (!port) - return -EINVAL; - - port--; - - /* start port reset before HNP protocol time out */ - status = readl(&ehci->regs->port_status[port]); - if (!(status & PORT_CONNECT)) - return -ENODEV; - - /* khubd will finish the reset later */ - if (ehci_is_TDI(ehci)) { - writel(PORT_RESET | - (status & ~(PORT_CSC | PORT_PEC | PORT_OCC)), - &ehci->regs->port_status[port]); - } else { - writel(PORT_RESET, &ehci->regs->port_status[port]); - } - - return 0; -} -#else -#define ehci_start_port_reset NULL -#endif /* CONFIG_USB_OTG */ - - -static const struct hc_driver ehci_fsl_hc_driver = { - .description = hcd_name, - .product_desc = "Freescale On-Chip EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_fsl), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_USB2 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .reset = ehci_fsl_setup, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - .start_port_reset = ehci_start_port_reset, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static int ehci_fsl_drv_probe(struct platform_device *pdev) -{ - if (usb_disabled()) - return -ENODEV; - - /* FIXME we only want one one probe() not two */ - return usb_hcd_fsl_probe(&ehci_fsl_hc_driver, pdev); -} - -static int ehci_fsl_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - /* FIXME we only want one one remove() not two */ - usb_hcd_fsl_remove(hcd, pdev); - return 0; -} - -MODULE_ALIAS("platform:fsl-ehci"); - -static struct platform_driver ehci_fsl_driver = { - .probe = ehci_fsl_drv_probe, - .remove = ehci_fsl_drv_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "fsl-ehci", - .pm = EHCI_FSL_PM_OPS, - }, -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-fsl.h b/ANDROID_3.4.5/drivers/usb/host/ehci-fsl.h deleted file mode 100644 index 863fb0c0..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-fsl.h +++ /dev/null @@ -1,53 +0,0 @@ -/* Copyright (C) 2005-2010 Freescale Semiconductor, Inc. - * Copyright (c) 2005 MontaVista Software - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#ifndef _EHCI_FSL_H -#define _EHCI_FSL_H - -/* offsets for the non-ehci registers in the FSL SOC USB controller */ -#define FSL_SOC_USB_SBUSCFG 0x90 -#define SBUSCFG_INCR8 0x02 /* INCR8, specified */ -#define FSL_SOC_USB_ULPIVP 0x170 -#define FSL_SOC_USB_PORTSC1 0x184 -#define PORT_PTS_MSK (3<<30) -#define PORT_PTS_UTMI (0<<30) -#define PORT_PTS_ULPI (2<<30) -#define PORT_PTS_SERIAL (3<<30) -#define PORT_PTS_PTW (1<<28) -#define FSL_SOC_USB_PORTSC2 0x188 -#define FSL_SOC_USB_USBMODE 0x1a8 -#define USBMODE_CM_MASK (3 << 0) /* controller mode mask */ -#define USBMODE_CM_HOST (3 << 0) /* controller mode: host */ -#define USBMODE_ES (1 << 2) /* (Big) Endian Select */ - -#define FSL_SOC_USB_USBGENCTRL 0x200 -#define USBGENCTRL_PPP (1 << 3) -#define USBGENCTRL_PFP (1 << 2) -#define FSL_SOC_USB_ISIPHYCTRL 0x204 -#define ISIPHYCTRL_PXE (1) -#define ISIPHYCTRL_PHYE (1 << 4) - -#define FSL_SOC_USB_SNOOP1 0x400 /* NOTE: big-endian */ -#define FSL_SOC_USB_SNOOP2 0x404 /* NOTE: big-endian */ -#define FSL_SOC_USB_AGECNTTHRSH 0x408 /* NOTE: big-endian */ -#define FSL_SOC_USB_PRICTRL 0x40c /* NOTE: big-endian */ -#define FSL_SOC_USB_SICTRL 0x410 /* NOTE: big-endian */ -#define FSL_SOC_USB_CTRL 0x500 /* NOTE: big-endian */ -#define CTRL_UTMI_PHY_EN (1<<9) -#define CTRL_PHY_CLK_VALID (1 << 17) -#define SNOOP_SIZE_2GB 0x1e -#endif /* _EHCI_FSL_H */ diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-grlib.c b/ANDROID_3.4.5/drivers/usb/host/ehci-grlib.c deleted file mode 100644 index fdfd8c5b..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-grlib.c +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Driver for Aeroflex Gaisler GRLIB GRUSBHC EHCI host controller - * - * GRUSBHC is typically found on LEON/GRLIB SoCs - * - * (c) Jan Andersson - * - * Based on ehci-ppc-of.c which is: - * (c) Valentine Barshak - * and in turn based on "ehci-ppc-soc.c" by Stefan Roese - * and "ohci-ppc-of.c" by Sylvain Munaut - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#include - -#include -#include -#include - -#define GRUSBHC_HCIVERSION 0x0100 /* Known value of cap. reg. HCIVERSION */ - -/* called during probe() after chip reset completes */ -static int ehci_grlib_setup(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; - - retval = ehci_halt(ehci); - if (retval) - return retval; - - retval = ehci_init(hcd); - if (retval) - return retval; - - ehci->sbrn = 0x20; - ehci_port_power(ehci, 1); - - return ehci_reset(ehci); -} - - -static const struct hc_driver ehci_grlib_hc_driver = { - .description = hcd_name, - .product_desc = "GRLIB GRUSBHC EHCI", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* - * basic lifecycle operations - */ - .reset = ehci_grlib_setup, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, -#endif - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - - -static int __devinit ehci_hcd_grlib_probe(struct platform_device *op) -{ - struct device_node *dn = op->dev.of_node; - struct usb_hcd *hcd; - struct ehci_hcd *ehci = NULL; - struct resource res; - u32 hc_capbase; - int irq; - int rv; - - if (usb_disabled()) - return -ENODEV; - - dev_dbg(&op->dev, "initializing GRUSBHC EHCI USB Controller\n"); - - rv = of_address_to_resource(dn, 0, &res); - if (rv) - return rv; - - /* usb_create_hcd requires dma_mask != NULL */ - op->dev.dma_mask = &op->dev.coherent_dma_mask; - hcd = usb_create_hcd(&ehci_grlib_hc_driver, &op->dev, - "GRUSBHC EHCI USB"); - if (!hcd) - return -ENOMEM; - - hcd->rsrc_start = res.start; - hcd->rsrc_len = resource_size(&res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__); - rv = -EBUSY; - goto err_rmr; - } - - irq = irq_of_parse_and_map(dn, 0); - if (irq == NO_IRQ) { - printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__); - rv = -EBUSY; - goto err_irq; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - printk(KERN_ERR "%s: ioremap failed\n", __FILE__); - rv = -ENOMEM; - goto err_ioremap; - } - - ehci = hcd_to_ehci(hcd); - - ehci->caps = hcd->regs; - - /* determine endianness of this implementation */ - hc_capbase = ehci_readl(ehci, &ehci->caps->hc_capbase); - if (HC_VERSION(ehci, hc_capbase) != GRUSBHC_HCIVERSION) { - ehci->big_endian_mmio = 1; - ehci->big_endian_desc = 1; - ehci->big_endian_capbase = 1; - } - - ehci->regs = hcd->regs + - HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); - - /* cache this readonly data; minimize chip reads */ - ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); - - rv = usb_add_hcd(hcd, irq, 0); - if (rv) - goto err_ehci; - - return 0; - -err_ehci: - iounmap(hcd->regs); -err_ioremap: - irq_dispose_mapping(irq); -err_irq: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err_rmr: - usb_put_hcd(hcd); - - return rv; -} - - -static int ehci_hcd_grlib_remove(struct platform_device *op) -{ - struct usb_hcd *hcd = dev_get_drvdata(&op->dev); - - dev_set_drvdata(&op->dev, NULL); - - dev_dbg(&op->dev, "stopping GRLIB GRUSBHC EHCI USB Controller\n"); - - usb_remove_hcd(hcd); - - iounmap(hcd->regs); - irq_dispose_mapping(hcd->irq); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - - usb_put_hcd(hcd); - - return 0; -} - - -static void ehci_hcd_grlib_shutdown(struct platform_device *op) -{ - struct usb_hcd *hcd = dev_get_drvdata(&op->dev); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - - -static const struct of_device_id ehci_hcd_grlib_of_match[] = { - { - .name = "GAISLER_EHCI", - }, - { - .name = "01_026", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, ehci_hcd_grlib_of_match); - - -static struct platform_driver ehci_grlib_driver = { - .probe = ehci_hcd_grlib_probe, - .remove = ehci_hcd_grlib_remove, - .shutdown = ehci_hcd_grlib_shutdown, - .driver = { - .name = "grlib-ehci", - .owner = THIS_MODULE, - .of_match_table = ehci_hcd_grlib_of_match, - }, -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-hcd.c b/ANDROID_3.4.5/drivers/usb/host/ehci-hcd.c deleted file mode 100644 index dabd379f..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-hcd.c +++ /dev/null @@ -1,1554 +0,0 @@ -/* - * Enhanced Host Controller Interface (EHCI) driver for USB. - * - * Maintainer: Alan Stern - * - * Copyright (c) 2000-2004 by David Brownell - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#if defined(CONFIG_PPC_PS3) -#include -#endif - -/*-------------------------------------------------------------------------*/ - -/* - * EHCI hc_driver implementation ... experimental, incomplete. - * Based on the final 1.0 register interface specification. - * - * USB 2.0 shows up in upcoming www.pcmcia.org technology. - * First was PCMCIA, like ISA; then CardBus, which is PCI. - * Next comes "CardBay", using USB 2.0 signals. - * - * Contains additional contributions by Brad Hards, Rory Bolt, and others. - * Special thanks to Intel and VIA for providing host controllers to - * test this driver on, and Cypress (including In-System Design) for - * providing early devices for those host controllers to talk to! - */ - -#define DRIVER_AUTHOR "David Brownell" -#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver" - -static const char hcd_name [] = "ehci_hcd"; - - -#undef VERBOSE_DEBUG -#undef EHCI_URB_TRACE - -#ifdef DEBUG -#define EHCI_STATS -#endif - -/* magic numbers that can affect system performance */ -#define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */ -#define EHCI_TUNE_RL_HS 4 /* nak throttle; see 4.9 */ -#define EHCI_TUNE_RL_TT 0 -#define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */ -#define EHCI_TUNE_MULT_TT 1 -/* - * Some drivers think it's safe to schedule isochronous transfers more than - * 256 ms into the future (partly as a result of an old bug in the scheduling - * code). In an attempt to avoid trouble, we will use a minimum scheduling - * length of 512 frames instead of 256. - */ -#define EHCI_TUNE_FLS 1 /* (medium) 512-frame schedule */ - -#define EHCI_IAA_MSECS 10 /* arbitrary */ -#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ -#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */ -#define EHCI_SHRINK_JIFFIES (DIV_ROUND_UP(HZ, 200) + 1) - /* 5-ms async qh unlink delay */ - -/* Initial IRQ latency: faster than hw default */ -static int log2_irq_thresh = 0; // 0 to 6 -module_param (log2_irq_thresh, int, S_IRUGO); -MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes"); - -/* initial park setting: slower than hw default */ -static unsigned park = 0; -module_param (park, uint, S_IRUGO); -MODULE_PARM_DESC (park, "park setting; 1-3 back-to-back async packets"); - -/* for flakey hardware, ignore overcurrent indicators */ -static bool ignore_oc = 0; -module_param (ignore_oc, bool, S_IRUGO); -MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications"); - -/* for link power management(LPM) feature */ -static unsigned int hird; -module_param(hird, int, S_IRUGO); -MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us"); - -#define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT) - -/*-------------------------------------------------------------------------*/ - -#include "ehci.h" -#include "ehci-dbg.c" -#include "pci-quirks.h" - -/*-------------------------------------------------------------------------*/ - -extern unsigned int usb_storage_id; -extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); -unsigned int usb_param[2] = {0xff}; - -static void -timer_action(struct ehci_hcd *ehci, enum ehci_timer_action action) -{ - /* Don't override timeouts which shrink or (later) disable - * the async ring; just the I/O watchdog. Note that if a - * SHRINK were pending, OFF would never be requested. - */ - if (timer_pending(&ehci->watchdog) - && ((BIT(TIMER_ASYNC_SHRINK) | BIT(TIMER_ASYNC_OFF)) - & ehci->actions)) - return; - - if (!test_and_set_bit(action, &ehci->actions)) { - unsigned long t; - - switch (action) { - case TIMER_IO_WATCHDOG: - if (!ehci->need_io_watchdog) - return; - t = EHCI_IO_JIFFIES; - break; - case TIMER_ASYNC_OFF: - t = EHCI_ASYNC_JIFFIES; - break; - /* case TIMER_ASYNC_SHRINK: */ - default: - t = EHCI_SHRINK_JIFFIES; - break; - } - mod_timer(&ehci->watchdog, t + jiffies); - } -} - -/*-------------------------------------------------------------------------*/ - -/* - * handshake - spin reading hc until handshake completes or fails - * @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 - * @usec: timeout in microseconds - * - * Returns negative errno, or zero on success - * - * Success happens when the "mask" bits have the specified value (hardware - * handshake done). There are two failure modes: "usec" have passed (major - * hardware flakeout), or the register reads as all-ones (hardware removed). - * - * That last failure should_only happen in cases like physical cardbus eject - * before driver shutdown. But it also seems to be caused by bugs in cardbus - * bridge shutdown: shutting down the bridge before the devices using it. - */ -static int handshake (struct ehci_hcd *ehci, void __iomem *ptr, - u32 mask, u32 done, int usec) -{ - u32 result; - - do { - result = ehci_readl(ehci, ptr); - if (result == ~(u32)0) /* card removed */ - return -ENODEV; - result &= mask; - if (result == done) - return 0; - udelay (1); - usec--; - } while (usec > 0); - return -ETIMEDOUT; -} - -/* check TDI/ARC silicon is in host mode */ -static int tdi_in_host_mode (struct ehci_hcd *ehci) -{ - u32 __iomem *reg_ptr; - u32 tmp; - - reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + USBMODE); - tmp = ehci_readl(ehci, reg_ptr); - return (tmp & 3) == USBMODE_CM_HC; -} - -/* force HC to halt state from unknown (EHCI spec section 2.3) */ -static int ehci_halt (struct ehci_hcd *ehci) -{ - u32 temp = ehci_readl(ehci, &ehci->regs->status); - - /* disable any irqs left enabled by previous code */ - ehci_writel(ehci, 0, &ehci->regs->intr_enable); - - if (ehci_is_TDI(ehci) && tdi_in_host_mode(ehci) == 0) { - return 0; - } - - if ((temp & STS_HALT) != 0) - return 0; - - temp = ehci_readl(ehci, &ehci->regs->command); - temp &= ~CMD_RUN; - ehci_writel(ehci, temp, &ehci->regs->command); - return handshake (ehci, &ehci->regs->status, - STS_HALT, STS_HALT, 16 * 125); -} - -#if defined(CONFIG_USB_SUSPEND) && defined(CONFIG_PPC_PS3) - -/* - * The EHCI controller of the Cell Super Companion Chip used in the - * PS3 will stop the root hub after all root hub ports are suspended. - * When in this condition handshake will return -ETIMEDOUT. The - * STS_HLT bit will not be set, so inspection of the frame index is - * used here to test for the condition. If the condition is found - * return success to allow the USB suspend to complete. - */ - -static int handshake_for_broken_root_hub(struct ehci_hcd *ehci, - void __iomem *ptr, u32 mask, u32 done, - int usec) -{ - unsigned int old_index; - int error; - - if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) - return -ETIMEDOUT; - - old_index = ehci_read_frame_index(ehci); - - error = handshake(ehci, ptr, mask, done, usec); - - if (error == -ETIMEDOUT && ehci_read_frame_index(ehci) == old_index) - return 0; - - return error; -} - -#else - -static int handshake_for_broken_root_hub(struct ehci_hcd *ehci, - void __iomem *ptr, u32 mask, u32 done, - int usec) -{ - return -ETIMEDOUT; -} - -#endif - -static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr, - u32 mask, u32 done, int usec) -{ - int error; - - error = handshake(ehci, ptr, mask, done, usec); - if (error == -ETIMEDOUT) - error = handshake_for_broken_root_hub(ehci, ptr, mask, done, - usec); - - if (error) { - ehci_halt(ehci); - ehci->rh_state = EHCI_RH_HALTED; - ehci_err(ehci, "force halt; handshake %p %08x %08x -> %d\n", - ptr, mask, done, error); - } - - return error; -} - -/* put TDI/ARC silicon into EHCI mode */ -static void tdi_reset (struct ehci_hcd *ehci) -{ - u32 __iomem *reg_ptr; - u32 tmp; - - reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + USBMODE); - tmp = ehci_readl(ehci, reg_ptr); - tmp |= USBMODE_CM_HC; - /* The default byte access to MMR space is LE after - * controller reset. Set the required endian mode - * for transfer buffers to match the host microprocessor - */ - if (ehci_big_endian_mmio(ehci)) - tmp |= USBMODE_BE; - ehci_writel(ehci, tmp, reg_ptr); -} - -/* reset a non-running (STS_HALT == 1) controller */ -static int ehci_reset (struct ehci_hcd *ehci) -{ - int retval; - u32 command = ehci_readl(ehci, &ehci->regs->command); - - /* If the EHCI debug controller is active, special care must be - * taken before and after a host controller reset */ - if (ehci->debug && !dbgp_reset_prep()) - ehci->debug = NULL; - - command |= CMD_RESET; - dbg_cmd (ehci, "reset", command); - ehci_writel(ehci, command, &ehci->regs->command); - ehci->rh_state = EHCI_RH_HALTED; - ehci->next_statechange = jiffies; - retval = handshake (ehci, &ehci->regs->command, - CMD_RESET, 0, 250 * 1000); - - if (ehci->has_hostpc) { - ehci_writel(ehci, USBMODE_EX_HC | USBMODE_EX_VBPS, - (u32 __iomem *)(((u8 *)ehci->regs) + USBMODE_EX)); - ehci_writel(ehci, TXFIFO_DEFAULT, - (u32 __iomem *)(((u8 *)ehci->regs) + TXFILLTUNING)); - } - if (retval) - return retval; - - if (ehci_is_TDI(ehci)) - tdi_reset (ehci); - - if (ehci->debug) - dbgp_external_startup(); - - ehci->port_c_suspend = ehci->suspended_ports = - ehci->resuming_ports = 0; - return retval; -} - -/* idle the controller (from running) */ -static void ehci_quiesce (struct ehci_hcd *ehci) -{ - u32 temp; - -#ifdef DEBUG - if (ehci->rh_state != EHCI_RH_RUNNING) - BUG (); -#endif - - /* wait for any schedule enables/disables to take effect */ - temp = ehci_readl(ehci, &ehci->regs->command) << 10; - temp &= STS_ASS | STS_PSS; - if (handshake_on_error_set_halt(ehci, &ehci->regs->status, - STS_ASS | STS_PSS, temp, 16 * 125)) - return; - - /* then disable anything that's still active */ - temp = ehci_readl(ehci, &ehci->regs->command); - temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE); - ehci_writel(ehci, temp, &ehci->regs->command); - - /* hardware can take 16 microframes to turn off ... */ - handshake_on_error_set_halt(ehci, &ehci->regs->status, - STS_ASS | STS_PSS, 0, 16 * 125); -} - -/*-------------------------------------------------------------------------*/ - -static void end_unlink_async(struct ehci_hcd *ehci); -static void ehci_work(struct ehci_hcd *ehci); - -#include "ehci-hub.c" -#include "ehci-lpm.c" -#include "ehci-mem.c" -#include "ehci-q.c" -#include "ehci-sched.c" -#include "ehci-sysfs.c" - -/*-------------------------------------------------------------------------*/ - -static void ehci_iaa_watchdog(unsigned long param) -{ - struct ehci_hcd *ehci = (struct ehci_hcd *) param; - unsigned long flags; - - spin_lock_irqsave (&ehci->lock, flags); - - /* Lost IAA irqs wedge things badly; seen first with a vt8235. - * So we need this watchdog, but must protect it against both - * (a) SMP races against real IAA firing and retriggering, and - * (b) clean HC shutdown, when IAA watchdog was pending. - */ - if (ehci->reclaim - && !timer_pending(&ehci->iaa_watchdog) - && ehci->rh_state == EHCI_RH_RUNNING) { - u32 cmd, status; - - /* If we get here, IAA is *REALLY* late. It's barely - * conceivable that the system is so busy that CMD_IAAD - * is still legitimately set, so let's be sure it's - * clear before we read STS_IAA. (The HC should clear - * CMD_IAAD when it sets STS_IAA.) - */ - cmd = ehci_readl(ehci, &ehci->regs->command); - if (cmd & CMD_IAAD) - ehci_writel(ehci, cmd & ~CMD_IAAD, - &ehci->regs->command); - - /* If IAA is set here it either legitimately triggered - * before we cleared IAAD above (but _way_ late, so we'll - * still count it as lost) ... or a silicon erratum: - * - VIA seems to set IAA without triggering the IRQ; - * - IAAD potentially cleared without setting IAA. - */ - status = ehci_readl(ehci, &ehci->regs->status); - if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { - COUNT (ehci->stats.lost_iaa); - ehci_writel(ehci, STS_IAA, &ehci->regs->status); - } - - ehci_vdbg(ehci, "IAA watchdog: status %x cmd %x\n", - status, cmd); - end_unlink_async(ehci); - } - - spin_unlock_irqrestore(&ehci->lock, flags); -} - -static void ehci_watchdog(unsigned long param) -{ - struct ehci_hcd *ehci = (struct ehci_hcd *) param; - unsigned long flags; - - spin_lock_irqsave(&ehci->lock, flags); - - /* stop async processing after it's idled a bit */ - if (test_bit (TIMER_ASYNC_OFF, &ehci->actions)) - start_unlink_async (ehci, ehci->async); - - /* ehci could run by timer, without IRQs ... */ - ehci_work (ehci); - - spin_unlock_irqrestore (&ehci->lock, flags); -} - -/* On some systems, leaving remote wakeup enabled prevents system shutdown. - * The firmware seems to think that powering off is a wakeup event! - * This routine turns off remote wakeup and everything else, on all ports. - */ -static void ehci_turn_off_all_ports(struct ehci_hcd *ehci) -{ - int port = HCS_N_PORTS(ehci->hcs_params); - - while (port--) - ehci_writel(ehci, PORT_RWC_BITS, - &ehci->regs->port_status[port]); -} - -/* - * Halt HC, turn off all ports, and let the BIOS use the companion controllers. - * Should be called with ehci->lock held. - */ -static void ehci_silence_controller(struct ehci_hcd *ehci) -{ - ehci_halt(ehci); - ehci_turn_off_all_ports(ehci); - - /* make BIOS/etc use companion controller during reboot */ - ehci_writel(ehci, 0, &ehci->regs->configured_flag); - - /* unblock posted writes */ - ehci_readl(ehci, &ehci->regs->configured_flag); -} - -/* ehci_shutdown kick in for silicon on any bus (not just pci, etc). - * This forcibly disables dma and IRQs, helping kexec and other cases - * where the next system software may expect clean state. - */ -static void ehci_shutdown(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - - del_timer_sync(&ehci->watchdog); - del_timer_sync(&ehci->iaa_watchdog); - - spin_lock_irq(&ehci->lock); - ehci_silence_controller(ehci); - spin_unlock_irq(&ehci->lock); -} - -static void ehci_port_power (struct ehci_hcd *ehci, int is_on) -{ - unsigned port; - - if (!HCS_PPC (ehci->hcs_params)) - return; - - ehci_dbg (ehci, "...power%s ports...\n", is_on ? "up" : "down"); - for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) - (void) ehci_hub_control(ehci_to_hcd(ehci), - is_on ? SetPortFeature : ClearPortFeature, - USB_PORT_FEAT_POWER, - port--, NULL, 0); - /* Flush those writes */ - ehci_readl(ehci, &ehci->regs->command); - msleep(20); -} - -/*-------------------------------------------------------------------------*/ - -/* - * ehci_work is called from some interrupts, timers, and so on. - * it calls driver completion functions, after dropping ehci->lock. - */ -static void ehci_work (struct ehci_hcd *ehci) -{ - timer_action_done (ehci, TIMER_IO_WATCHDOG); - - /* another CPU may drop ehci->lock during a schedule scan while - * it reports urb completions. this flag guards against bogus - * attempts at re-entrant schedule scanning. - */ - if (ehci->scanning) - return; - ehci->scanning = 1; - scan_async (ehci); - if (ehci->next_uframe != -1) - scan_periodic (ehci); - ehci->scanning = 0; - - /* the IO watchdog guards against hardware or driver bugs that - * misplace IRQs, and should let us run completely without IRQs. - * such lossage has been observed on both VT6202 and VT8235. - */ - if (ehci->rh_state == EHCI_RH_RUNNING && - (ehci->async->qh_next.ptr != NULL || - ehci->periodic_sched != 0)) - timer_action (ehci, TIMER_IO_WATCHDOG); -} - -/* - * Called when the ehci_hcd module is removed. - */ -static void ehci_stop (struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci (hcd); - - ehci_dbg (ehci, "stop\n"); - - /* no more interrupts ... */ - del_timer_sync (&ehci->watchdog); - del_timer_sync(&ehci->iaa_watchdog); - - spin_lock_irq(&ehci->lock); - if (ehci->rh_state == EHCI_RH_RUNNING) - ehci_quiesce (ehci); - - ehci_silence_controller(ehci); - ehci_reset (ehci); - spin_unlock_irq(&ehci->lock); - - remove_sysfs_files(ehci); - remove_debug_files (ehci); - - /* root hub is shut down separately (first, when possible) */ - spin_lock_irq (&ehci->lock); - if (ehci->async) - ehci_work (ehci); - spin_unlock_irq (&ehci->lock); - ehci_mem_cleanup (ehci); - - if (ehci->amd_pll_fix == 1) - usb_amd_dev_put(); - -#ifdef EHCI_STATS - ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n", - ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim, - ehci->stats.lost_iaa); - ehci_dbg (ehci, "complete %ld unlink %ld\n", - ehci->stats.complete, ehci->stats.unlink); -#endif - - dbg_status (ehci, "ehci_stop completed", - ehci_readl(ehci, &ehci->regs->status)); -} - -int env_mos_gpio; -unsigned int env_active; -unsigned int env_port; -unsigned int env_bitmap; -unsigned int env_ctraddr; -unsigned int env_ocaddr; -unsigned int env_odaddr; - -/* one-time init, only for memory state */ -static int ehci_init(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - u32 temp; - int retval; - u32 hcc_params; - struct ehci_qh_hw *hw; - char usb_env_name[] = "wmt.usb.param"; - char usb_env_val[20] = "0"; - int varlen = 20; - - char usb_resume_env_name[] = "wmt.gpo.usb"; - char usb_resume_env_val[80] = "0"; - int varlen_resume = 80; - - spin_lock_init(&ehci->lock); - - /* - * keep io watchdog by default, those good HCDs could turn off it later - */ - ehci->need_io_watchdog = 1; - init_timer(&ehci->watchdog); - ehci->watchdog.function = ehci_watchdog; - ehci->watchdog.data = (unsigned long) ehci; - - init_timer(&ehci->iaa_watchdog); - ehci->iaa_watchdog.function = ehci_iaa_watchdog; - ehci->iaa_watchdog.data = (unsigned long) ehci; - - hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params); - - /* - * by default set standard 80% (== 100 usec/uframe) max periodic - * bandwidth as required by USB 2.0 - */ - ehci->uframe_periodic_max = 100; - - /* - * hw default: 1K periodic list heads, one per frame. - * periodic_size can shrink by USBCMD update if hcc_params allows. - */ - ehci->periodic_size = DEFAULT_I_TDPS; - INIT_LIST_HEAD(&ehci->cached_itd_list); - INIT_LIST_HEAD(&ehci->cached_sitd_list); - - if (HCC_PGM_FRAMELISTLEN(hcc_params)) { - /* periodic schedule size can be smaller than default */ - switch (EHCI_TUNE_FLS) { - case 0: ehci->periodic_size = 1024; break; - case 1: ehci->periodic_size = 512; break; - case 2: ehci->periodic_size = 256; break; - default: BUG(); - } - } - if ((retval = ehci_mem_init(ehci, GFP_KERNEL)) < 0) - return retval; - - /* controllers may cache some of the periodic schedule ... */ - if (HCC_ISOC_CACHE(hcc_params)) // full frame cache - ehci->i_thresh = 2 + 8; - else // N microframes cached - ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params); - - ehci->reclaim = NULL; - ehci->next_uframe = -1; - ehci->clock_frame = -1; - - /* - * dedicate a qh for the async ring head, since we couldn't unlink - * a 'real' qh without stopping the async schedule [4.8]. use it - * as the 'reclamation list head' too. - * its dummy is used in hw_alt_next of many tds, to prevent the qh - * from automatically advancing to the next td after short reads. - */ - ehci->async->qh_next.qh = NULL; - hw = ehci->async->hw; - hw->hw_next = QH_NEXT(ehci, ehci->async->qh_dma); - hw->hw_info1 = cpu_to_hc32(ehci, QH_HEAD); -#if defined(CONFIG_PPC_PS3) - hw->hw_info1 |= cpu_to_hc32(ehci, (1 << 7)); /* I = 1 */ -#endif - hw->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT); - hw->hw_qtd_next = EHCI_LIST_END(ehci); - ehci->async->qh_state = QH_STATE_LINKED; - hw->hw_alt_next = QTD_NEXT(ehci, ehci->async->dummy->qtd_dma); - - /* clear interrupt enables, set irq latency */ - if (log2_irq_thresh < 0 || log2_irq_thresh > 6) - log2_irq_thresh = 0; - temp = 1 << (16 + log2_irq_thresh); - if (HCC_PER_PORT_CHANGE_EVENT(hcc_params)) { - ehci->has_ppcd = 1; - ehci_dbg(ehci, "enable per-port change event\n"); - temp |= CMD_PPCEE; - } - if (HCC_CANPARK(hcc_params)) { - /* HW default park == 3, on hardware that supports it (like - * NVidia and ALI silicon), maximizes throughput on the async - * schedule by avoiding QH fetches between transfers. - * - * With fast usb storage devices and NForce2, "park" seems to - * make problems: throughput reduction (!), data errors... - */ - if (park) { - park = min(park, (unsigned) 3); - temp |= CMD_PARK; - temp |= park << 8; - } - ehci_dbg(ehci, "park %d\n", park); - } - if (HCC_PGM_FRAMELISTLEN(hcc_params)) { - /* periodic schedule size can be smaller than default */ - temp &= ~(3 << 2); - temp |= (EHCI_TUNE_FLS << 2); - } - if (HCC_LPM(hcc_params)) { - /* support link power management EHCI 1.1 addendum */ - ehci_dbg(ehci, "support lpm\n"); - ehci->has_lpm = 1; - if (hird > 0xf) { - ehci_dbg(ehci, "hird %d invalid, use default 0", - hird); - hird = 0; - } - temp |= hird << 24; - } - ehci->command = temp; - - if(wmt_getsyspara(usb_env_name, usb_env_val, &varlen) == 0) { - sscanf(usb_env_val,"%X:%X", &usb_param[0],&usb_param[1]); - //printk("usb_param[0] =%x ,usb_param[1]=%x \n",usb_param[0],usb_param[1]); - if (usb_param[0] & 0x01) { - if(usb_param[1] <= 0x03 ) { - usb_storage_id = usb_param[1]+1; - //printk("usb_storage_id =%x , it should be small than or equal 4 .\n",usb_storage_id); - } else { - usb_storage_id = 2;// default port B - } - } else { - usb_storage_id=0; //disable - } - } - - if(wmt_getsyspara(usb_resume_env_name, usb_resume_env_val, &varlen_resume) == 0) { - sscanf(usb_resume_env_val,"%d:%X:%X:%X:%X:%X", &env_mos_gpio,&env_active,&env_bitmap,&env_ctraddr,&env_ocaddr,&env_odaddr); - - if (env_active) { - env_port = (env_active >> 4); - env_active &= 0x1; - env_ctraddr = ((env_ctraddr & 0xffffff) | 0xfe000000); - env_ocaddr = ((env_ocaddr & 0xffffff) | 0xfe000000); - env_odaddr = ((env_odaddr & 0xffffff) | 0xfe000000); - } - } else - env_active = 0; - - printk("env_mos_gpio=%d env_active =%x ,env_port=%x env_bitmap=%x env_ctraddr=%x env_ocaddr=%x env_odaddr=%x \n",env_mos_gpio,env_active,env_port,env_bitmap,env_ctraddr,env_ocaddr,env_odaddr); - - /* Accept arbitrarily long scatter-gather lists */ - if (!(hcd->driver->flags & HCD_LOCAL_MEM)) - hcd->self.sg_tablesize = ~0; - return 0; -} - -/* start HC running; it's halted, ehci_init() has been run (once) */ -static int ehci_run (struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci (hcd); - u32 temp; - u32 hcc_params; - - hcd->uses_new_polling = 1; - - /* EHCI spec section 4.1 */ - - ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list); - ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next); - - /* - * hcc_params controls whether ehci->regs->segment must (!!!) - * be used; it constrains QH/ITD/SITD and QTD locations. - * pci_pool consistent memory always uses segment zero. - * streaming mappings for I/O buffers, like pci_map_single(), - * can return segments above 4GB, if the device allows. - * - * NOTE: the dma mask is visible through dma_supported(), so - * drivers can pass this info along ... like NETIF_F_HIGHDMA, - * Scsi_Host.highmem_io, and so forth. It's readonly to all - * host side drivers though. - */ - hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params); - if (HCC_64BIT_ADDR(hcc_params)) { - ehci_writel(ehci, 0, &ehci->regs->segment); -#if 0 -// this is deeply broken on almost all architectures - if (!dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64))) - ehci_info(ehci, "enabled 64bit DMA\n"); -#endif - } - - - // Philips, Intel, and maybe others need CMD_RUN before the - // root hub will detect new devices (why?); NEC doesn't - ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET); - ehci->command |= CMD_RUN; - ehci_writel(ehci, ehci->command, &ehci->regs->command); - dbg_cmd (ehci, "init", ehci->command); - - /* - * Start, enabling full USB 2.0 functionality ... usb 1.1 devices - * are explicitly handed to companion controller(s), so no TT is - * involved with the root hub. (Except where one is integrated, - * and there's no companion controller unless maybe for USB OTG.) - * - * Turning on the CF flag will transfer ownership of all ports - * from the companions to the EHCI controller. If any of the - * companions are in the middle of a port reset at the time, it - * could cause trouble. Write-locking ehci_cf_port_reset_rwsem - * guarantees that no resets are in progress. After we set CF, - * a short delay lets the hardware catch up; new resets shouldn't - * be started before the port switching actions could complete. - */ - down_write(&ehci_cf_port_reset_rwsem); - ehci->rh_state = EHCI_RH_RUNNING; - ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); - ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ - msleep(5); - up_write(&ehci_cf_port_reset_rwsem); - ehci->last_periodic_enable = ktime_get_real(); - - temp = HC_VERSION(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); - ehci_info (ehci, - "USB %x.%x started, EHCI %x.%02x%s\n", - ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f), - temp >> 8, temp & 0xff, - ignore_oc ? ", overcurrent ignored" : ""); - - ehci_writel(ehci, INTR_MASK, - &ehci->regs->intr_enable); /* Turn On Interrupts */ - - /* GRR this is run-once init(), being done every time the HC starts. - * So long as they're part of class devices, we can't do it init() - * since the class device isn't created that early. - */ - create_debug_files(ehci); - create_sysfs_files(ehci); - - return 0; -} - -static int __maybe_unused ehci_setup (struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; - - ehci->regs = (void __iomem *)ehci->caps + - HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); - dbg_hcs_params(ehci, "reset"); - dbg_hcc_params(ehci, "reset"); - - /* cache this readonly data; minimize chip reads */ - ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); - - ehci->sbrn = HCD_USB2; - - retval = ehci_halt(ehci); - if (retval) - return retval; - - /* data structure init */ - retval = ehci_init(hcd); - if (retval) - return retval; - - ehci_reset(ehci); - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static irqreturn_t ehci_irq (struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci (hcd); - u32 status, masked_status, pcd_status = 0, cmd; - int bh; - - spin_lock (&ehci->lock); - - status = ehci_readl(ehci, &ehci->regs->status); - - /* e.g. cardbus physical eject */ - if (status == ~(u32) 0) { - ehci_dbg (ehci, "device removed\n"); - goto dead; - } - - /* - * We don't use STS_FLR, but some controllers don't like it to - * remain on, so mask it out along with the other status bits. - */ - masked_status = status & (INTR_MASK | STS_FLR); - - /* Shared IRQ? */ - if (!masked_status || unlikely(ehci->rh_state == EHCI_RH_HALTED)) { - spin_unlock(&ehci->lock); - return IRQ_NONE; - } - - /* clear (just) interrupts */ - ehci_writel(ehci, masked_status, &ehci->regs->status); - cmd = ehci_readl(ehci, &ehci->regs->command); - bh = 0; - -#ifdef VERBOSE_DEBUG - /* unrequested/ignored: Frame List Rollover */ - dbg_status (ehci, "irq", status); -#endif - - /* INT, ERR, and IAA interrupt rates can be throttled */ - - /* normal [4.15.1.2] or error [4.15.1.1] completion */ - if (likely ((status & (STS_INT|STS_ERR)) != 0)) { - if (likely ((status & STS_ERR) == 0)) - COUNT (ehci->stats.normal); - else - COUNT (ehci->stats.error); - bh = 1; - } - - /* complete the unlinking of some qh [4.15.2.3] */ - if (status & STS_IAA) { - /* guard against (alleged) silicon errata */ - if (cmd & CMD_IAAD) { - ehci_writel(ehci, cmd & ~CMD_IAAD, - &ehci->regs->command); - ehci_dbg(ehci, "IAA with IAAD still set?\n"); - } - if (ehci->reclaim) { - COUNT(ehci->stats.reclaim); - end_unlink_async(ehci); - } else - ehci_dbg(ehci, "IAA with nothing to reclaim?\n"); - } - - /* remote wakeup [4.3.1] */ - if (status & STS_PCD) { - unsigned i = HCS_N_PORTS (ehci->hcs_params); - u32 ppcd = 0; - - /* kick root hub later */ - pcd_status = status; - - /* resume root hub? */ - if (ehci->rh_state == EHCI_RH_SUSPENDED) - usb_hcd_resume_root_hub(hcd); - - /* get per-port change detect bits */ - if (ehci->has_ppcd) - ppcd = status >> 16; - - while (i--) { - int pstatus; - - /* leverage per-port change bits feature */ - if (ehci->has_ppcd && !(ppcd & (1 << i))) - continue; - pstatus = ehci_readl(ehci, - &ehci->regs->port_status[i]); - - if (pstatus & PORT_OWNER) - continue; - if (!(test_bit(i, &ehci->suspended_ports) && - ((pstatus & PORT_RESUME) || - !(pstatus & PORT_SUSPEND)) && - (pstatus & PORT_PE) && - ehci->reset_done[i] == 0)) - continue; - - /* start 20 msec resume signaling from this port, - * and make khubd collect PORT_STAT_C_SUSPEND to - * stop that signaling. Use 5 ms extra for safety, - * like usb_port_resume() does. - */ - ehci->reset_done[i] = jiffies + msecs_to_jiffies(25); - set_bit(i, &ehci->resuming_ports); - ehci_dbg (ehci, "port %d remote wakeup\n", i + 1); - mod_timer(&hcd->rh_timer, ehci->reset_done[i]); - } - } - - /* PCI errors [4.15.2.4] */ - if (unlikely ((status & STS_FATAL) != 0)) { - ehci_err(ehci, "fatal error\n"); - dbg_cmd(ehci, "fatal", cmd); - dbg_status(ehci, "fatal", status); - ehci_halt(ehci); -dead: - ehci_reset(ehci); - ehci_writel(ehci, 0, &ehci->regs->configured_flag); - usb_hc_died(hcd); - /* generic layer kills/unlinks all urbs, then - * uses ehci_stop to clean up the rest - */ - bh = 1; - } - - if (bh) - ehci_work (ehci); - spin_unlock (&ehci->lock); - if (pcd_status) - usb_hcd_poll_rh_status(hcd); - return IRQ_HANDLED; -} - -/*-------------------------------------------------------------------------*/ - -/* - * non-error returns are a promise to giveback() the urb later - * we drop ownership so next owner (or urb unlink) can get it - * - * urb + dev is in hcd.self.controller.urb_list - * we're queueing TDs onto software and hardware lists - * - * hcd-specific init for hcpriv hasn't been done yet - * - * NOTE: control, bulk, and interrupt share the same code to append TDs - * to a (possibly active) QH, and the same QH scanning code. - */ -static int ehci_urb_enqueue ( - struct usb_hcd *hcd, - struct urb *urb, - gfp_t mem_flags -) { - struct ehci_hcd *ehci = hcd_to_ehci (hcd); - struct list_head qtd_list; - - INIT_LIST_HEAD (&qtd_list); - - switch (usb_pipetype (urb->pipe)) { - case PIPE_CONTROL: - /* qh_completions() code doesn't handle all the fault cases - * in multi-TD control transfers. Even 1KB is rare anyway. - */ - if (urb->transfer_buffer_length > (16 * 1024)) - return -EMSGSIZE; - /* FALLTHROUGH */ - /* case PIPE_BULK: */ - default: - if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags)) - return -ENOMEM; - return submit_async(ehci, urb, &qtd_list, mem_flags); - - case PIPE_INTERRUPT: - if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags)) - return -ENOMEM; - return intr_submit(ehci, urb, &qtd_list, mem_flags); - - case PIPE_ISOCHRONOUS: - if (urb->dev->speed == USB_SPEED_HIGH) - return itd_submit (ehci, urb, mem_flags); - else - return sitd_submit (ehci, urb, mem_flags); - } -} - -static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) -{ - /* failfast */ - if (ehci->rh_state != EHCI_RH_RUNNING && ehci->reclaim) - end_unlink_async(ehci); - - /* If the QH isn't linked then there's nothing we can do - * unless we were called during a giveback, in which case - * qh_completions() has to deal with it. - */ - if (qh->qh_state != QH_STATE_LINKED) { - if (qh->qh_state == QH_STATE_COMPLETING) - qh->needs_rescan = 1; - return; - } - - /* defer till later if busy */ - if (ehci->reclaim) { - struct ehci_qh *last; - - for (last = ehci->reclaim; - last->reclaim; - last = last->reclaim) - continue; - qh->qh_state = QH_STATE_UNLINK_WAIT; - last->reclaim = qh; - - /* start IAA cycle */ - } else - start_unlink_async (ehci, qh); -} - -/* remove from hardware lists - * completions normally happen asynchronously - */ - -static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) -{ - struct ehci_hcd *ehci = hcd_to_ehci (hcd); - struct ehci_qh *qh; - unsigned long flags; - int rc; - - spin_lock_irqsave (&ehci->lock, flags); - rc = usb_hcd_check_unlink_urb(hcd, urb, status); - if (rc) - goto done; - - switch (usb_pipetype (urb->pipe)) { - // case PIPE_CONTROL: - // case PIPE_BULK: - default: - qh = (struct ehci_qh *) urb->hcpriv; - if (!qh) - break; - switch (qh->qh_state) { - case QH_STATE_LINKED: - case QH_STATE_COMPLETING: - unlink_async(ehci, qh); - break; - case QH_STATE_UNLINK: - case QH_STATE_UNLINK_WAIT: - /* already started */ - break; - case QH_STATE_IDLE: - /* QH might be waiting for a Clear-TT-Buffer */ - qh_completions(ehci, qh); - break; - } - break; - - case PIPE_INTERRUPT: - qh = (struct ehci_qh *) urb->hcpriv; - if (!qh) - break; - switch (qh->qh_state) { - case QH_STATE_LINKED: - case QH_STATE_COMPLETING: - intr_deschedule (ehci, qh); - break; - case QH_STATE_IDLE: - qh_completions (ehci, qh); - break; - default: - ehci_dbg (ehci, "bogus qh %p state %d\n", - qh, qh->qh_state); - goto done; - } - break; - - case PIPE_ISOCHRONOUS: - // itd or sitd ... - - // wait till next completion, do it then. - // completion irqs can wait up to 1024 msec, - break; - } -done: - spin_unlock_irqrestore (&ehci->lock, flags); - return rc; -} - -/*-------------------------------------------------------------------------*/ - -// bulk qh holds the data toggle - -static void -ehci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep) -{ - struct ehci_hcd *ehci = hcd_to_ehci (hcd); - unsigned long flags; - struct ehci_qh *qh, *tmp; - - /* ASSERT: any requests/urbs are being unlinked */ - /* ASSERT: nobody can be submitting urbs for this any more */ - -rescan: - spin_lock_irqsave (&ehci->lock, flags); - qh = ep->hcpriv; - if (!qh) - goto done; - - /* endpoints can be iso streams. for now, we don't - * accelerate iso completions ... so spin a while. - */ - if (qh->hw == NULL) { - ehci_vdbg (ehci, "iso delay\n"); - goto idle_timeout; - } - - if (ehci->rh_state != EHCI_RH_RUNNING) - qh->qh_state = QH_STATE_IDLE; - switch (qh->qh_state) { - case QH_STATE_LINKED: - case QH_STATE_COMPLETING: - for (tmp = ehci->async->qh_next.qh; - tmp && tmp != qh; - tmp = tmp->qh_next.qh) - continue; - /* periodic qh self-unlinks on empty, and a COMPLETING qh - * may already be unlinked. - */ - if (tmp) - unlink_async(ehci, qh); - /* FALL THROUGH */ - case QH_STATE_UNLINK: /* wait for hw to finish? */ - case QH_STATE_UNLINK_WAIT: -idle_timeout: - spin_unlock_irqrestore (&ehci->lock, flags); - schedule_timeout_uninterruptible(1); - goto rescan; - case QH_STATE_IDLE: /* fully unlinked */ - if (qh->clearing_tt) - goto idle_timeout; - if (list_empty (&qh->qtd_list)) { - qh_put (qh); - break; - } - /* else FALL THROUGH */ - default: - /* caller was supposed to have unlinked any requests; - * that's not our job. just leak this memory. - */ - ehci_err (ehci, "qh %p (#%02x) state %d%s\n", - qh, ep->desc.bEndpointAddress, qh->qh_state, - list_empty (&qh->qtd_list) ? "" : "(has tds)"); - break; - } - ep->hcpriv = NULL; -done: - spin_unlock_irqrestore (&ehci->lock, flags); -} - -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); - int epnum = usb_endpoint_num(&ep->desc); - int is_out = usb_endpoint_dir_out(&ep->desc); - unsigned long flags; - - if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT) - return; - - spin_lock_irqsave(&ehci->lock, flags); - 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) { - usb_settoggle(qh->dev, epnum, is_out, 0); - if (!list_empty(&qh->qtd_list)) { - WARN_ONCE(1, "clear_halt for a busy endpoint\n"); - } else if (qh->qh_state == QH_STATE_LINKED || - qh->qh_state == QH_STATE_COMPLETING) { - - /* The toggle value in the QH can't be updated - * while the QH is active. Unlink it now; - * re-linking will call qh_refresh(). - */ - if (eptype == USB_ENDPOINT_XFER_BULK) - unlink_async(ehci, qh); - else - intr_deschedule(ehci, qh); - } - } - spin_unlock_irqrestore(&ehci->lock, flags); -} - -static int ehci_get_frame (struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci (hcd); - return (ehci_read_frame_index(ehci) >> 3) % ehci->periodic_size; -} - -/*-------------------------------------------------------------------------*/ - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR (DRIVER_AUTHOR); -MODULE_LICENSE ("GPL"); - -#ifdef CONFIG_PCI -#include "ehci-pci.c" -#define PCI_DRIVER ehci_pci_driver -#endif - -#ifdef CONFIG_USB_EHCI_FSL -#include "ehci-fsl.c" -#define PLATFORM_DRIVER ehci_fsl_driver -#endif - -#ifdef CONFIG_USB_EHCI_MXC -#include "ehci-mxc.c" -#define PLATFORM_DRIVER ehci_mxc_driver -#endif - -#ifdef CONFIG_USB_EHCI_SH -#include "ehci-sh.c" -#define PLATFORM_DRIVER ehci_hcd_sh_driver -#endif - -#ifdef CONFIG_MIPS_ALCHEMY -#include "ehci-au1xxx.c" -#define PLATFORM_DRIVER ehci_hcd_au1xxx_driver -#endif - -#ifdef CONFIG_USB_EHCI_HCD_OMAP -#include "ehci-omap.c" -#define PLATFORM_DRIVER ehci_hcd_omap_driver -#endif - -#ifdef CONFIG_PPC_PS3 -#include "ehci-ps3.c" -#define PS3_SYSTEM_BUS_DRIVER ps3_ehci_driver -#endif - -#ifdef CONFIG_USB_EHCI_HCD_PPC_OF -#include "ehci-ppc-of.c" -#define OF_PLATFORM_DRIVER ehci_hcd_ppc_of_driver -#endif - -#ifdef CONFIG_XPS_USB_HCD_XILINX -#include "ehci-xilinx-of.c" -#define XILINX_OF_PLATFORM_DRIVER ehci_hcd_xilinx_of_driver -#endif - -#ifdef CONFIG_PLAT_ORION -#include "ehci-orion.c" -#define PLATFORM_DRIVER ehci_orion_driver -#endif - -#ifdef CONFIG_ARCH_IXP4XX -#include "ehci-ixp4xx.c" -#define PLATFORM_DRIVER ixp4xx_ehci_driver -#endif - -#ifdef CONFIG_USB_W90X900_EHCI -#include "ehci-w90x900.c" -#define PLATFORM_DRIVER ehci_hcd_w90x900_driver -#endif - -#ifdef CONFIG_ARCH_AT91 -#include "ehci-atmel.c" -#define PLATFORM_DRIVER ehci_atmel_driver -#endif - -#ifdef CONFIG_USB_OCTEON_EHCI -#include "ehci-octeon.c" -#define PLATFORM_DRIVER ehci_octeon_driver -#endif - -#ifdef CONFIG_USB_CNS3XXX_EHCI -#include "ehci-cns3xxx.c" -#define PLATFORM_DRIVER cns3xxx_ehci_driver -#endif - -#ifdef CONFIG_ARCH_VT8500 -#include "ehci-vt8500.c" -#define PLATFORM_DRIVER vt8500_ehci_driver -#endif - -#ifdef CONFIG_PLAT_SPEAR -#include "ehci-spear.c" -#define PLATFORM_DRIVER spear_ehci_hcd_driver -#endif - -#ifdef CONFIG_USB_EHCI_MSM -#include "ehci-msm.c" -#define PLATFORM_DRIVER ehci_msm_driver -#endif - -#ifdef CONFIG_USB_EHCI_HCD_PMC_MSP -#include "ehci-pmcmsp.c" -#define PLATFORM_DRIVER ehci_hcd_msp_driver -#endif - -#ifdef CONFIG_USB_EHCI_TEGRA -#include "ehci-tegra.c" -#define PLATFORM_DRIVER tegra_ehci_driver -#endif - -#ifdef CONFIG_USB_EHCI_S5P -#include "ehci-s5p.c" -#define PLATFORM_DRIVER s5p_ehci_driver -#endif - -#ifdef CONFIG_SPARC_LEON -#include "ehci-grlib.c" -#define PLATFORM_DRIVER ehci_grlib_driver -#endif - -#ifdef CONFIG_CPU_XLR -#include "ehci-xls.c" -#define PLATFORM_DRIVER ehci_xls_driver -#endif - -#ifdef CONFIG_USB_EHCI_MV -#include "ehci-mv.c" -#define PLATFORM_DRIVER ehci_mv_driver -#endif - -#ifdef CONFIG_MACH_LOONGSON1 -#include "ehci-ls1x.c" -#define PLATFORM_DRIVER ehci_ls1x_driver -#endif - -#ifdef CONFIG_USB_EHCI_HCD_PLATFORM -#include "ehci-platform.c" -#define PLATFORM_DRIVER ehci_platform_driver -#endif - -#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ - !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \ - !defined(XILINX_OF_PLATFORM_DRIVER) -#error "missing bus glue for ehci-hcd" -#endif - -static int __init ehci_hcd_init(void) -{ - int retval = 0; - - if (usb_disabled()) - return -ENODEV; - - printk(KERN_INFO "%s: " DRIVER_DESC "\n", hcd_name); - set_bit(USB_EHCI_LOADED, &usb_hcds_loaded); - if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) || - test_bit(USB_OHCI_LOADED, &usb_hcds_loaded)) - printk(KERN_WARNING "Warning! ehci_hcd should always be loaded" - " before uhci_hcd and ohci_hcd, not after\n"); - - pr_debug("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n", - hcd_name, - sizeof(struct ehci_qh), sizeof(struct ehci_qtd), - sizeof(struct ehci_itd), sizeof(struct ehci_sitd)); - -#ifdef DEBUG - ehci_debug_root = debugfs_create_dir("ehci", usb_debug_root); - if (!ehci_debug_root) { - retval = -ENOENT; - goto err_debug; - } -#endif - -#ifdef PLATFORM_DRIVER - retval = platform_driver_register(&PLATFORM_DRIVER); - if (retval < 0) - goto clean0; -#endif - -#ifdef PCI_DRIVER - retval = pci_register_driver(&PCI_DRIVER); - if (retval < 0) - goto clean1; -#endif - -#ifdef PS3_SYSTEM_BUS_DRIVER - retval = ps3_ehci_driver_register(&PS3_SYSTEM_BUS_DRIVER); - if (retval < 0) - goto clean2; -#endif - -#ifdef OF_PLATFORM_DRIVER - retval = platform_driver_register(&OF_PLATFORM_DRIVER); - if (retval < 0) - goto clean3; -#endif - -#ifdef XILINX_OF_PLATFORM_DRIVER - retval = platform_driver_register(&XILINX_OF_PLATFORM_DRIVER); - if (retval < 0) - goto clean4; -#endif - return retval; - -#ifdef XILINX_OF_PLATFORM_DRIVER - /* platform_driver_unregister(&XILINX_OF_PLATFORM_DRIVER); */ -clean4: -#endif -#ifdef OF_PLATFORM_DRIVER - platform_driver_unregister(&OF_PLATFORM_DRIVER); -clean3: -#endif -#ifdef PS3_SYSTEM_BUS_DRIVER - ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); -clean2: -#endif -#ifdef PCI_DRIVER - pci_unregister_driver(&PCI_DRIVER); -clean1: -#endif -#ifdef PLATFORM_DRIVER - platform_driver_unregister(&PLATFORM_DRIVER); -clean0: -#endif -#ifdef DEBUG - debugfs_remove(ehci_debug_root); - ehci_debug_root = NULL; -err_debug: -#endif - clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded); - return retval; -} -module_init(ehci_hcd_init); - -static void __exit ehci_hcd_cleanup(void) -{ -#ifdef XILINX_OF_PLATFORM_DRIVER - platform_driver_unregister(&XILINX_OF_PLATFORM_DRIVER); -#endif -#ifdef OF_PLATFORM_DRIVER - platform_driver_unregister(&OF_PLATFORM_DRIVER); -#endif -#ifdef PLATFORM_DRIVER - platform_driver_unregister(&PLATFORM_DRIVER); -#endif -#ifdef PCI_DRIVER - pci_unregister_driver(&PCI_DRIVER); -#endif -#ifdef PS3_SYSTEM_BUS_DRIVER - ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); -#endif -#ifdef DEBUG - debugfs_remove(ehci_debug_root); -#endif - clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded); -} -module_exit(ehci_hcd_cleanup); - diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-hub.c b/ANDROID_3.4.5/drivers/usb/host/ehci-hub.c deleted file mode 100644 index 714ca48b..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-hub.c +++ /dev/null @@ -1,1405 +0,0 @@ -/* - * Copyright (C) 2001-2004 by David Brownell - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* this file is part of ehci-hcd.c */ - -/*-------------------------------------------------------------------------*/ - -/* - * EHCI Root Hub ... the nonsharable stuff - * - * Registers don't need cpu_to_le32, that happens transparently - */ - -/*-------------------------------------------------------------------------*/ -#include - -#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E) - -#ifdef CONFIG_PM - -static int ehci_hub_control( - struct usb_hcd *hcd, - u16 typeReq, - u16 wValue, - u16 wIndex, - char *buf, - u16 wLength -); - -/* After a power loss, ports that were owned by the companion must be - * reset so that the companion can still own them. - */ -static void ehci_handover_companion_ports(struct ehci_hcd *ehci) -{ - u32 __iomem *reg; - u32 status; - int port; - __le32 buf; - struct usb_hcd *hcd = ehci_to_hcd(ehci); - - if (!ehci->owned_ports) - return; - - /* Give the connections some time to appear */ - msleep(20); - - port = HCS_N_PORTS(ehci->hcs_params); - while (port--) { - if (test_bit(port, &ehci->owned_ports)) { - reg = &ehci->regs->port_status[port]; - status = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; - - /* Port already owned by companion? */ - if (status & PORT_OWNER) - clear_bit(port, &ehci->owned_ports); - else if (test_bit(port, &ehci->companion_ports)) - ehci_writel(ehci, status & ~PORT_PE, reg); - else - ehci_hub_control(hcd, SetPortFeature, - USB_PORT_FEAT_RESET, port + 1, - NULL, 0); - } - } - - if (!ehci->owned_ports) - return; - msleep(90); /* Wait for resets to complete */ - - port = HCS_N_PORTS(ehci->hcs_params); - while (port--) { - if (test_bit(port, &ehci->owned_ports)) { - ehci_hub_control(hcd, GetPortStatus, - 0, port + 1, - (char *) &buf, sizeof(buf)); - - /* The companion should now own the port, - * but if something went wrong the port must not - * remain enabled. - */ - reg = &ehci->regs->port_status[port]; - status = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; - if (status & PORT_OWNER) - ehci_writel(ehci, status | PORT_CSC, reg); - else { - ehci_dbg(ehci, "failed handover port %d: %x\n", - port + 1, status); - ehci_writel(ehci, status & ~PORT_PE, reg); - } - } - } - - ehci->owned_ports = 0; -} - -static int __maybe_unused ehci_port_change(struct ehci_hcd *ehci) -{ - int i = HCS_N_PORTS(ehci->hcs_params); - - /* First check if the controller indicates a change event */ - - if (ehci_readl(ehci, &ehci->regs->status) & STS_PCD) - return 1; - - /* - * Not all controllers appear to update this while going from D3 to D0, - * so check the individual port status registers as well - */ - - while (i--) - if (ehci_readl(ehci, &ehci->regs->port_status[i]) & PORT_CSC) - return 1; - - return 0; -} - -extern char enable_ehci_wake; -extern char enable_ehci_disc_wakeup; - -static __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, - bool suspending, bool do_wakeup) -{ - int port; - u32 temp; - unsigned long flags; - - /* If remote wakeup is enabled for the root hub but disabled - * for the controller, we must adjust all the port wakeup flags - * when the controller is suspended or resumed. In all other - * cases they don't need to be changed. - */ - if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup || do_wakeup) - return; - - spin_lock_irqsave(&ehci->lock, flags); - - /* clear phy low-power mode before changing wakeup flags */ - if (ehci->has_hostpc) { - port = HCS_N_PORTS(ehci->hcs_params); - while (port--) { - u32 __iomem *hostpc_reg; - - hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs - + HOSTPC0 + 4 * port); - temp = ehci_readl(ehci, hostpc_reg); - ehci_writel(ehci, temp & ~HOSTPC_PHCD, hostpc_reg); - } - spin_unlock_irqrestore(&ehci->lock, flags); - msleep(5); - spin_lock_irqsave(&ehci->lock, flags); - } - - port = HCS_N_PORTS(ehci->hcs_params); - while (port--) { - u32 __iomem *reg = &ehci->regs->port_status[port]; - u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; - u32 t2 = t1 & ~PORT_WAKE_BITS; - - /* If we are suspending the controller, clear the flags. - * If we are resuming the controller, set the wakeup flags. - */ - if (!suspending) { - if (enable_ehci_wake && enable_ehci_disc_wakeup) { - if (t1 & PORT_CONNECT) - t2 |= PORT_WKOC_E | PORT_WKDISC_E; - else - t2 |= PORT_WKOC_E | PORT_WKCONN_E; - } else - t2 |= PORT_WKOC_E; - } - ehci_vdbg(ehci, "port %d, %08x -> %08x\n", - port + 1, t1, t2); - ehci_writel(ehci, t2, reg); - } - - /* enter phy low-power mode again */ - if (ehci->has_hostpc) { - port = HCS_N_PORTS(ehci->hcs_params); - while (port--) { - u32 __iomem *hostpc_reg; - - hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs - + HOSTPC0 + 4 * port); - temp = ehci_readl(ehci, hostpc_reg); - ehci_writel(ehci, temp | HOSTPC_PHCD, hostpc_reg); - } - } - - /* Does the root hub have a port wakeup pending? */ - if (!suspending && ehci_port_change(ehci)) - usb_hcd_resume_root_hub(ehci_to_hcd(ehci)); - - spin_unlock_irqrestore(&ehci->lock, flags); -} - -static int ehci_bus_suspend (struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci (hcd); - int port; - int mask; - int changed; - - ehci_dbg(ehci, "suspend root hub\n"); - - if (time_before (jiffies, ehci->next_statechange)) - msleep(5); - del_timer_sync(&ehci->watchdog); - del_timer_sync(&ehci->iaa_watchdog); - - spin_lock_irq (&ehci->lock); - - /* Once the controller is stopped, port resumes that are already - * in progress won't complete. Hence if remote wakeup is enabled - * for the root hub and any ports are in the middle of a resume or - * remote wakeup, we must fail the suspend. - */ - if (hcd->self.root_hub->do_remote_wakeup) { - if (ehci->resuming_ports) { - spin_unlock_irq(&ehci->lock); - ehci_dbg(ehci, "suspend failed because a port is resuming\n"); - return -EBUSY; - } - } - - /* stop schedules, clean any completed work */ - if (ehci->rh_state == EHCI_RH_RUNNING) - ehci_quiesce (ehci); - ehci->command = ehci_readl(ehci, &ehci->regs->command); - ehci_work(ehci); - - /* Unlike other USB host controller types, EHCI doesn't have - * any notion of "global" or bus-wide suspend. The driver has - * to manually suspend all the active unsuspended ports, and - * then manually resume them in the bus_resume() routine. - */ - ehci->bus_suspended = 0; - ehci->owned_ports = 0; - changed = 0; - port = HCS_N_PORTS(ehci->hcs_params); - while (port--) { - u32 __iomem *reg = &ehci->regs->port_status [port]; - u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; - u32 t2 = t1 & ~PORT_WAKE_BITS; - - /* keep track of which ports we suspend */ - if (t1 & PORT_OWNER) - set_bit(port, &ehci->owned_ports); - else if ((t1 & PORT_PE) && !(t1 & PORT_SUSPEND)) { - if (enable_ehci_wake) - t2 |= PORT_SUSPEND; - else - t2 &= ~PORT_PE;// CharlesTu, disable port - set_bit(port, &ehci->bus_suspended); - } - - /* enable remote wakeup on all ports, if told to do so */ - if (hcd->self.root_hub->do_remote_wakeup) { - /* only enable appropriate wake bits, otherwise the - * hardware can not go phy low power mode. If a race - * condition happens here(connection change during bits - * set), the port change detection will finally fix it. - */ - if (enable_ehci_wake && enable_ehci_disc_wakeup) { - if (t1 & PORT_CONNECT) - t2 |= PORT_WKOC_E | PORT_WKDISC_E; - else - t2 |= PORT_WKOC_E | PORT_WKCONN_E; - } else - t2 |= PORT_WKOC_E; - } - - if (t1 != t2) { - ehci_vdbg (ehci, "port %d, %08x -> %08x\n", - port + 1, t1, t2); - ehci_writel(ehci, t2, reg); - changed = 1; - } - } - - if (changed && ehci->has_hostpc) { - spin_unlock_irq(&ehci->lock); - msleep(5); /* 5 ms for HCD to enter low-power mode */ - spin_lock_irq(&ehci->lock); - - port = HCS_N_PORTS(ehci->hcs_params); - while (port--) { - u32 __iomem *hostpc_reg; - u32 t3; - - hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs - + HOSTPC0 + 4 * port); - t3 = ehci_readl(ehci, hostpc_reg); - ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg); - t3 = ehci_readl(ehci, hostpc_reg); - ehci_dbg(ehci, "Port %d phy low-power mode %s\n", - port, (t3 & HOSTPC_PHCD) ? - "succeeded" : "failed"); - } - } - - /* Apparently some devices need a >= 1-uframe delay here */ - if (ehci->bus_suspended) - udelay(150); - - /* turn off now-idle HC */ - ehci_halt (ehci); - ehci->rh_state = EHCI_RH_SUSPENDED; - - if (ehci->reclaim) - end_unlink_async(ehci); - - /* allow remote wakeup */ - mask = INTR_MASK; - if (!hcd->self.root_hub->do_remote_wakeup) - mask &= ~STS_PCD; - ehci_writel(ehci, mask, &ehci->regs->intr_enable); - ehci_readl(ehci, &ehci->regs->intr_enable); - - ehci->next_statechange = jiffies + msecs_to_jiffies(10); - spin_unlock_irq (&ehci->lock); - - /* ehci_work() may have re-enabled the watchdog timer, which we do not - * want, and so we must delete any pending watchdog timer events. - */ - del_timer_sync(&ehci->watchdog); - return 0; -} - - -/* caller has locked the root hub, and should reset/reinit on error */ -static int ehci_bus_resume (struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci (hcd); - u32 temp; - u32 power_okay; - int i; - unsigned long resume_needed = 0; - - if (time_before (jiffies, ehci->next_statechange)) - msleep(5); - spin_lock_irq (&ehci->lock); - if (!HCD_HW_ACCESSIBLE(hcd)) { - spin_unlock_irq(&ehci->lock); - return -ESHUTDOWN; - } - - if (unlikely(ehci->debug)) { - if (!dbgp_reset_prep()) - ehci->debug = NULL; - else - dbgp_external_startup(); - } - - /* Ideally and we've got a real resume here, and no port's power - * was lost. (For PCI, that means Vaux was maintained.) But we - * could instead be restoring a swsusp snapshot -- so that BIOS was - * the last user of the controller, not reset/pm hardware keeping - * state we gave to it. - */ - power_okay = ehci_readl(ehci, &ehci->regs->intr_enable); - ehci_dbg(ehci, "resume root hub%s\n", - power_okay ? "" : " after power loss"); - - /* at least some APM implementations will try to deliver - * IRQs right away, so delay them until we're ready. - */ - ehci_writel(ehci, 0, &ehci->regs->intr_enable); - - /* re-init operational registers */ - ehci_writel(ehci, 0, &ehci->regs->segment); - ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list); - ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next); - - /* restore CMD_RUN, framelist size, and irq threshold */ - ehci_writel(ehci, ehci->command, &ehci->regs->command); - ehci->rh_state = EHCI_RH_RUNNING; - - /* Some controller/firmware combinations need a delay during which - * they set up the port statuses. See Bugzilla #8190. */ - spin_unlock_irq(&ehci->lock); - msleep(8); - spin_lock_irq(&ehci->lock); - - /* clear phy low-power mode before resume */ - if (ehci->bus_suspended && ehci->has_hostpc) { - i = HCS_N_PORTS(ehci->hcs_params); - while (i--) { - if (test_bit(i, &ehci->bus_suspended)) { - u32 __iomem *hostpc_reg; - - hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs - + HOSTPC0 + 4 * i); - temp = ehci_readl(ehci, hostpc_reg); - ehci_writel(ehci, temp & ~HOSTPC_PHCD, - hostpc_reg); - } - } - spin_unlock_irq(&ehci->lock); - msleep(5); - spin_lock_irq(&ehci->lock); - } - - /* manually resume the ports we suspended during bus_suspend() */ - i = HCS_N_PORTS (ehci->hcs_params); - while (i--) { - temp = ehci_readl(ehci, &ehci->regs->port_status [i]); - temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); - if (test_bit(i, &ehci->bus_suspended) && - (temp & PORT_SUSPEND)) { - temp |= PORT_RESUME; - set_bit(i, &resume_needed); - } - ehci_writel(ehci, temp, &ehci->regs->port_status [i]); - } - - /* msleep for 20ms only if code is trying to resume port */ - if (resume_needed) { - spin_unlock_irq(&ehci->lock); - msleep(20); - spin_lock_irq(&ehci->lock); - } - - i = HCS_N_PORTS (ehci->hcs_params); - while (i--) { - temp = ehci_readl(ehci, &ehci->regs->port_status [i]); - if (test_bit(i, &resume_needed)) { - temp &= ~(PORT_RWC_BITS | PORT_RESUME); - ehci_writel(ehci, temp, &ehci->regs->port_status [i]); - ehci_vdbg (ehci, "resumed port %d\n", i + 1); - } - } - (void) ehci_readl(ehci, &ehci->regs->command); - - /* maybe re-activate the schedule(s) */ - temp = 0; - if (ehci->async->qh_next.qh) - temp |= CMD_ASE; - if (ehci->periodic_sched) - temp |= CMD_PSE; - if (temp) { - ehci->command |= temp; - ehci_writel(ehci, ehci->command, &ehci->regs->command); - } - - ehci->next_statechange = jiffies + msecs_to_jiffies(5); - - /* Now we can safely re-enable irqs */ - ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable); - - spin_unlock_irq (&ehci->lock); - ehci_handover_companion_ports(ehci); - return 0; -} - -#else - -#define ehci_bus_suspend NULL -#define ehci_bus_resume NULL - -#endif /* CONFIG_PM */ - -/*-------------------------------------------------------------------------*/ - -/* - * Sets the owner of a port - */ -static void set_owner(struct ehci_hcd *ehci, int portnum, int new_owner) -{ - u32 __iomem *status_reg; - u32 port_status; - int try; - - status_reg = &ehci->regs->port_status[portnum]; - - /* - * The controller won't set the OWNER bit if the port is - * enabled, so this loop will sometimes require at least two - * iterations: one to disable the port and one to set OWNER. - */ - for (try = 4; try > 0; --try) { - spin_lock_irq(&ehci->lock); - port_status = ehci_readl(ehci, status_reg); - if ((port_status & PORT_OWNER) == new_owner - || (port_status & (PORT_OWNER | PORT_CONNECT)) - == 0) - try = 0; - else { - port_status ^= PORT_OWNER; - port_status &= ~(PORT_PE | PORT_RWC_BITS); - ehci_writel(ehci, port_status, status_reg); - } - spin_unlock_irq(&ehci->lock); - if (try > 1) - msleep(5); - } -} - -/*-------------------------------------------------------------------------*/ - -static int check_reset_complete ( - struct ehci_hcd *ehci, - int index, - u32 __iomem *status_reg, - int port_status -) { - if (!(port_status & PORT_CONNECT)) - return port_status; - - /* if reset finished and it's still not enabled -- handoff */ - if (!(port_status & PORT_PE)) { - - /* with integrated TT, there's nobody to hand it to! */ - if (ehci_is_TDI(ehci)) { - ehci_dbg (ehci, - "Failed to enable port %d on root hub TT\n", - index+1); - return port_status; - } - - ehci_dbg (ehci, "port %d full speed --> companion\n", - index + 1); - - // what happens if HCS_N_CC(params) == 0 ? - port_status |= PORT_OWNER; - port_status &= ~PORT_RWC_BITS; - ehci_writel(ehci, port_status, status_reg); - - /* ensure 440EPX ohci controller state is operational */ - if (ehci->has_amcc_usb23) - set_ohci_hcfs(ehci, 1); - } else { - ehci_dbg (ehci, "port %d high speed\n", index + 1); - /* ensure 440EPx ohci controller state is suspended */ - if (ehci->has_amcc_usb23) - set_ohci_hcfs(ehci, 0); - } - - return port_status; -} - -/*-------------------------------------------------------------------------*/ - - -/* build "status change" packet (one or two bytes) from HC registers */ - -static int -ehci_hub_status_data (struct usb_hcd *hcd, char *buf) -{ - struct ehci_hcd *ehci = hcd_to_ehci (hcd); - u32 temp, status; - u32 mask; - int ports, i, retval = 1; - unsigned long flags; - u32 ppcd = 0; - - /* init status to no-changes */ - buf [0] = 0; - ports = HCS_N_PORTS (ehci->hcs_params); - if (ports > 7) { - buf [1] = 0; - retval++; - } - - /* Inform the core about resumes-in-progress by returning - * a non-zero value even if there are no status changes. - */ - status = ehci->resuming_ports; - - /* Some boards (mostly VIA?) report bogus overcurrent indications, - * causing massive log spam unless we completely ignore them. It - * may be relevant that VIA VT8235 controllers, where PORT_POWER is - * always set, seem to clear PORT_OCC and PORT_CSC when writing to - * PORT_POWER; that's surprising, but maybe within-spec. - */ - if (!ignore_oc) - mask = PORT_CSC | PORT_PEC | PORT_OCC; - else - mask = PORT_CSC | PORT_PEC; - // PORT_RESUME from hardware ~= PORT_STAT_C_SUSPEND - - /* no hub change reports (bit 0) for now (power, ...) */ - - /* port N changes (bit N)? */ - spin_lock_irqsave (&ehci->lock, flags); - - /* get per-port change detect bits */ - if (ehci->has_ppcd) - ppcd = ehci_readl(ehci, &ehci->regs->status) >> 16; - - for (i = 0; i < ports; i++) { - /* leverage per-port change bits feature */ - if (ehci->has_ppcd && !(ppcd & (1 << i))) - continue; - temp = ehci_readl(ehci, &ehci->regs->port_status [i]); - - /* - * Return status information even for ports with OWNER set. - * Otherwise khubd wouldn't see the disconnect event when a - * high-speed device is switched over to the companion - * controller by the user. - */ - - /* - *CharlesTu,2009.08.17,patch Trancend 8GB usb device , - *copy and fast hot plug reset slowly issue. - *Due to Transcend 8GB device ,connect slowly and reset_done clear 0 - */ - /*if (!(temp & PORT_CONNECT))*/ - if (!(temp & (PORT_CONNECT|PORT_RESET))) - ehci->reset_done [i] = 0; - - - if ((temp & mask) != 0 || test_bit(i, &ehci->port_c_suspend) - || (ehci->reset_done[i] && time_after_eq( - jiffies, ehci->reset_done[i]))) { - if (i < 7) - buf [0] |= 1 << (i + 1); - else - buf [1] |= 1 << (i - 7); - status = STS_PCD; - } - /*CharlesTu,090415,patch usb card reader plug/unplug fastly - * port fail issue. Due to the port reset assert and not clear. - */ - if ((temp & PORT_RESET) - && time_after (jiffies, ehci->reset_done [i])) { - /*printk("port reset \n");*/ - /* force reset to complete */ - ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET), - &ehci->regs->port_status [i]); - /* REVISIT: some hardware needs 550+ usec to clear - * this bit; seems too long to spin routinely... - */ - retval = handshake(ehci, - &ehci->regs->port_status [i], - PORT_RESET, 0, 750); - if (retval != 0) { - ehci_err (ehci, "port %d reset error %d\n", - i + 1, retval); - - } - } - } - /* FIXME autosuspend idle root hubs */ - spin_unlock_irqrestore (&ehci->lock, flags); - return status ? retval : 0; -} - -/*-------------------------------------------------------------------------*/ - -static void -ehci_hub_descriptor ( - struct ehci_hcd *ehci, - struct usb_hub_descriptor *desc -) { - int ports = HCS_N_PORTS (ehci->hcs_params); - u16 temp; - - desc->bDescriptorType = 0x29; - desc->bPwrOn2PwrGood = 10; /* ehci 1.0, 2.3.9 says 20ms max */ - desc->bHubContrCurrent = 0; - - desc->bNbrPorts = ports; - temp = 1 + (ports / 8); - desc->bDescLength = 7 + 2 * temp; - - /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ - memset(&desc->u.hs.DeviceRemovable[0], 0, temp); - memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp); - - temp = 0x0008; /* per-port overcurrent reporting */ - if (HCS_PPC (ehci->hcs_params)) - temp |= 0x0001; /* per-port power control */ - else - temp |= 0x0002; /* no power switching */ -#if 0 -// re-enable when we support USB_PORT_FEAT_INDICATOR below. - if (HCS_INDICATOR (ehci->hcs_params)) - temp |= 0x0080; /* per-port indicators (LEDs) */ -#endif - desc->wHubCharacteristics = cpu_to_le16(temp); -} - -/*-------------------------------------------------------------------------*/ -/*{CharlesTu,2010.08.26, for test mode --------------------------------*/ -#ifdef CONFIG_USB_EHCI_EHSET - -static int -single_step_set_feature( struct usb_hcd *hcd, u8 port) -{ - struct usb_bus *bus = hcd_to_bus(hcd); - struct usb_device *udev; - struct ehci_hcd *ehci = hcd_to_ehci (hcd); - struct list_head qtd_list; - struct list_head setup_list; - struct list_head data_list; - struct ehci_qtd *qtd; - struct urb urb; - struct usb_ctrlrequest setup_packet; - char data_buffer[USB_DT_DEVICE_SIZE]; - - ehci_info (ehci, "Testing SINGLE_STEP_SET_FEATURE\n"); - - if (bus == NULL) { - ehci_err (ehci, "EHSET: usb_bus pointer is NULL\n"); - return -EPIPE; - } - - udev = bus->root_hub; - if (udev == NULL) { - ehci_err (ehci, "EHSET: root_hub pointer is NULL\n"); - return -EPIPE; - } - /* Charles, modify for MVL5 */ - /*udev = udev->children[port - 1];*/ - udev = udev->children[port ]; - - if (udev == NULL) { - ehci_err (ehci, "EHSET: No test device found on port %d\n", - port); - return -EPIPE; - } - - setup_packet.bRequestType = USB_DIR_IN; - setup_packet.bRequest = USB_REQ_GET_DESCRIPTOR; - setup_packet.wValue = (USB_DT_DEVICE << 8); - setup_packet.wIndex = 0; - setup_packet.wLength = USB_DT_DEVICE_SIZE; - - INIT_LIST_HEAD (&qtd_list); - INIT_LIST_HEAD (&setup_list); - INIT_LIST_HEAD (&data_list); - - urb.transfer_buffer_length = USB_DT_DEVICE_SIZE; - urb.dev = udev; - urb.pipe = usb_rcvctrlpipe(udev, 0); - /* Charles, modify for MVL5 */ - urb.hcpriv = udev->ep0.hcpriv; - /*urb.hcpriv = udev->ep0.hcpriv; */ - - urb.setup_packet = (char *)&setup_packet; - urb.transfer_buffer = data_buffer; - urb.transfer_flags = URB_HCD_DRIVER_TEST; - //spin_lock_init(&urb.lock); - - urb.setup_dma = dma_map_single( hcd->self.controller, - urb.setup_packet, - sizeof (struct usb_ctrlrequest), - DMA_TO_DEVICE); - urb.transfer_dma = dma_map_single ( - hcd->self.controller, - urb.transfer_buffer, - sizeof (struct usb_ctrlrequest), - DMA_TO_DEVICE); - - if (!urb.setup_dma || !urb.transfer_dma) { - ehci_err (ehci, "dma_map_single Failed\n"); - return -EBUSY; - } - - if (!qh_urb_transaction (ehci, &urb, &qtd_list, GFP_ATOMIC)) { - ehci_err (ehci, "qh_urb_transaction Failed\n"); - return -EBUSY; - } - - qtd = container_of (qtd_list.next, struct ehci_qtd, qtd_list); - list_del_init (&qtd->qtd_list); - list_add (&qtd->qtd_list, &setup_list); - qtd = container_of (qtd_list.next, struct ehci_qtd, qtd_list); - list_del_init (&qtd->qtd_list); - list_add (&qtd->qtd_list, &data_list); - qtd = container_of (qtd_list.next, struct ehci_qtd, qtd_list); - list_del_init (&qtd->qtd_list); - ehci_qtd_free (ehci, qtd); - - ehci_info (ehci, "Sending SETUP PHASE\n"); - /* Charles, modify for MVL5 */ - //if (submit_async (ehci, &udev->ep0, &urb, &setup_list, GFP_ATOMIC)) { - if (submit_async (ehci, &urb, &setup_list, GFP_ATOMIC)) { - ehci_err (ehci, "Failed to queue up qtds\n"); - return -EBUSY; - } - - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(msecs_to_jiffies(15000)); - urb.status = 0; - urb.actual_length = 0; - - ehci_info (ehci, "Sending DATA PHASE\n"); - /* Charles, modify for MVL5 */ - //if (submit_async (ehci, &udev->ep0, &urb, &data_list, GFP_ATOMIC)) { - - if (submit_async (ehci, &urb, &setup_list, GFP_ATOMIC)) { - - ehci_err (ehci, "Failed to queue up qtds\n"); - return -EBUSY; - } - - return 0; -} -static void stop_test(struct ehci_hcd *ehci) -{ - volatile unsigned int temp32 = 0; - //int ports = 0,i = 0; - - /*reset HC */ - temp32 = readl(&ehci->regs->command); - ehci_info(ehci, "command before set reset 0x%8.8x\n", temp32); - temp32 |= 0x00000002; - writel(temp32, &ehci->regs->command); - temp32 = readl (&ehci->regs->command); - ehci_info(ehci, "command after set reset 0x%8.8x\n", temp32); - while ((readl(&ehci->regs->command)) & 0x00000002) - ; - - /*set CF bit*/ - temp32 = readl(&ehci->regs->configured_flag); - ehci_info(ehci, "CF before set CF 0x%8.8x\n", temp32); - if (!temp32) - writel (FLAG_CF, &ehci->regs->configured_flag); - temp32 = readl(&ehci->regs->configured_flag); - while (!((readl(&ehci->regs->configured_flag)) & 0x00000001)) - ; - ehci_info(ehci, "CF after set CF 0x%8.8x\n", temp32); - - -} -#endif -/*CharlesTu}-------------------------------------------------------------*/ - -static int handshake_wmt (struct ehci_hcd *ehci, void __iomem *ptr, - u32 mask, u32 done, int usec) -{ - u32 result; - u32 result1; - int usec_250; - - if (usec > 1000) - usec_250 = usec - 261; - else - usec_250 = usec; - - do { - result = ehci_readl(ehci, ptr); - result1 = result; - if (result == ~(u32)0) /* card removed */ - return -ENODEV; - result &= mask; - if (result == done) - return 0; - udelay (1); - usec--; - if (usec == usec_250) { - ehci_writel(ehci, - result1 & ~(PORT_RWC_BITS | PORT_RESUME | PORT_SUSPEND), - ptr); -// printk("*2nd clear resume\n"); - } - } while (usec > 0); - return -ETIMEDOUT; -} - -extern unsigned int env_active; -extern unsigned int env_port; -extern unsigned int env_bitmap; -extern unsigned int env_ctraddr; -extern unsigned int env_ocaddr; -extern unsigned int env_odaddr; - -static int ehci_hub_control ( - struct usb_hcd *hcd, - u16 typeReq, - u16 wValue, - u16 wIndex, - char *buf, - u16 wLength -) { - struct ehci_hcd *ehci = hcd_to_ehci (hcd); - int ports = HCS_N_PORTS (ehci->hcs_params); - u32 __iomem *status_reg = &ehci->regs->port_status[ - (wIndex & 0xff) - 1]; - u32 __iomem *hostpc_reg = NULL; - u32 temp, temp1, status; - unsigned long flags; - int retval = 0; - unsigned selector=0; - u8 port_num = 0; //CharlesTu, for testmode - - /* - * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR. - * HCS_INDICATOR may say we can change LEDs to off/amber/green. - * (track current state ourselves) ... blink for diagnostics, - * power, "this is the one", etc. EHCI spec supports this. - */ - - if (ehci->has_hostpc) - hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs - + HOSTPC0 + 4 * ((wIndex & 0xff) - 1)); - spin_lock_irqsave (&ehci->lock, flags); - switch (typeReq) { - case ClearHubFeature: - switch (wValue) { - case C_HUB_LOCAL_POWER: - case C_HUB_OVER_CURRENT: - /* no hub-wide feature/status flags */ - break; - default: - goto error; - } - break; - case ClearPortFeature: - if (!wIndex || wIndex > ports) - goto error; - wIndex--; - temp = ehci_readl(ehci, status_reg); - - /* - * Even if OWNER is set, so the port is owned by the - * companion controller, khubd needs to be able to clear - * the port-change status bits (especially - * USB_PORT_STAT_C_CONNECTION). - */ - - switch (wValue) { - case USB_PORT_FEAT_ENABLE: - ehci_writel(ehci, temp & ~PORT_PE, status_reg); - break; - case USB_PORT_FEAT_C_ENABLE: - ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_PEC, - status_reg); - break; - case USB_PORT_FEAT_SUSPEND: - if (temp & PORT_RESET) - goto error; - if (ehci->no_selective_suspend) - break; -#ifdef CONFIG_USB_OTG - if ((hcd->self.otg_port == (wIndex + 1)) - && hcd->self.b_hnp_enable) { - otg_start_hnp(ehci->transceiver->otg); - break; - } -#endif - if (!(temp & PORT_SUSPEND)) - break; - if ((temp & PORT_PE) == 0) - goto error; - - /* clear phy low-power mode before resume */ - if (hostpc_reg) { - temp1 = ehci_readl(ehci, hostpc_reg); - ehci_writel(ehci, temp1 & ~HOSTPC_PHCD, - hostpc_reg); - spin_unlock_irqrestore(&ehci->lock, flags); - msleep(5);/* wait to leave low-power mode */ - spin_lock_irqsave(&ehci->lock, flags); - } - /* resume signaling for 20 msec */ - //temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); - temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS | PORT_SUSPEND); - ehci_writel(ehci, temp | PORT_RESUME, status_reg); - ehci->reset_done[wIndex] = jiffies - + msecs_to_jiffies(20); - break; - case USB_PORT_FEAT_C_SUSPEND: - clear_bit(wIndex, &ehci->port_c_suspend); - break; - case USB_PORT_FEAT_POWER: - if (HCS_PPC (ehci->hcs_params)) - ehci_writel(ehci, - temp & ~(PORT_RWC_BITS | PORT_POWER), - status_reg); - break; - case USB_PORT_FEAT_C_CONNECTION: - if (ehci->has_lpm) { - /* clear PORTSC bits on disconnect */ - temp &= ~PORT_LPM; - temp &= ~PORT_DEV_ADDR; - } - ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC, - status_reg); - break; - case USB_PORT_FEAT_C_OVER_CURRENT: - ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_OCC, - status_reg); - break; - case USB_PORT_FEAT_C_RESET: - /* GetPortStatus clears reset */ - break; - default: - goto error; - } - ehci_readl(ehci, &ehci->regs->command); /* unblock posted write */ - break; - case GetHubDescriptor: - ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *) - buf); - break; - case GetHubStatus: - /* no hub-wide feature/status flags */ - memset (buf, 0, 4); - //cpu_to_le32s ((u32 *) buf); - break; - case GetPortStatus: - if (!wIndex || wIndex > ports) - goto error; - wIndex--; - status = 0; - temp = ehci_readl(ehci, status_reg); - - // wPortChange bits - if (temp & PORT_CSC) - status |= USB_PORT_STAT_C_CONNECTION << 16; - if (temp & PORT_PEC) - status |= USB_PORT_STAT_C_ENABLE << 16; - - if ((temp & PORT_OCC) && !ignore_oc){ - status |= USB_PORT_STAT_C_OVERCURRENT << 16; - - /* - * Hubs should disable port power on over-current. - * However, not all EHCI implementations do this - * automatically, even if they _do_ support per-port - * power switching; they're allowed to just limit the - * current. khubd will turn the power back on. - */ - if ((temp & PORT_OC) && HCS_PPC(ehci->hcs_params)) { - ehci_writel(ehci, - temp & ~(PORT_RWC_BITS | PORT_POWER), - status_reg); - temp = ehci_readl(ehci, status_reg); - } - } - - /* whoever resumes must GetPortStatus to complete it!! */ - if (temp & PORT_RESUME) { - - /* Remote Wakeup received? */ - if (!ehci->reset_done[wIndex]) { - /* resume signaling for 20 msec */ - ehci->reset_done[wIndex] = jiffies - + msecs_to_jiffies(20); - /* check the port again */ - mod_timer(&ehci_to_hcd(ehci)->rh_timer, - ehci->reset_done[wIndex]); - } - - /* resume completed? */ - else if (time_after_eq(jiffies, - ehci->reset_done[wIndex])) { - clear_bit(wIndex, &ehci->suspended_ports); - set_bit(wIndex, &ehci->port_c_suspend); - ehci->reset_done[wIndex] = 0; - - /* stop resume signaling */ - temp = ehci_readl(ehci, status_reg); -// ehci_writel(ehci, -// temp & ~(PORT_RWC_BITS | PORT_RESUME), -// status_reg); - if ((env_active) && (env_port == wIndex)) { - *((volatile unsigned char *)(env_ctraddr)) |= env_bitmap; - *((volatile unsigned char *)(env_ocaddr)) |= env_bitmap; - *((volatile unsigned char *)(env_odaddr)) |= env_bitmap; - } - ehci_writel(ehci, - temp & ~(PORT_RWC_BITS | PORT_RESUME | PORT_SUSPEND), - status_reg); - clear_bit(wIndex, &ehci->resuming_ports); - - udelay(1); - - if ((env_active) && (env_port == wIndex)) { - *((volatile unsigned char *)(env_odaddr)) &= (~env_bitmap); - } - -// retval = handshake(ehci, status_reg, -// PORT_RESUME, 0, 2000 /* 2msec */); - retval = handshake_wmt(ehci, status_reg, - PORT_RESUME, 0, 2000 /* 2msec */); - if (retval != 0) { - ehci_err(ehci, - "port %d resume error %d\n", - wIndex + 1, retval); - goto error; - } - temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); - } - } - - /* whoever resets must GetPortStatus to complete it!! */ - if ((temp & PORT_RESET) - && time_after_eq(jiffies, - ehci->reset_done[wIndex])) { - status |= USB_PORT_STAT_C_RESET << 16; - ehci->reset_done [wIndex] = 0; - clear_bit(wIndex, &ehci->resuming_ports); - - /* force reset to complete */ - ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET), - status_reg); - /* REVISIT: some hardware needs 550+ usec to clear - * this bit; seems too long to spin routinely... - */ - retval = handshake(ehci, status_reg, - PORT_RESET, 0, 1000); - if (retval != 0) { - ehci_err (ehci, "port %d reset error %d\n", - wIndex + 1, retval); - goto error; - } - - /* see what we found out */ - temp = check_reset_complete (ehci, wIndex, status_reg, - ehci_readl(ehci, status_reg)); - } - - if (!(temp & (PORT_RESUME|PORT_RESET))) { - ehci->reset_done[wIndex] = 0; - clear_bit(wIndex, &ehci->resuming_ports); - } - - /* transfer dedicated ports to the companion hc */ - if ((temp & PORT_CONNECT) && - test_bit(wIndex, &ehci->companion_ports)) { - temp &= ~PORT_RWC_BITS; - temp |= PORT_OWNER; - ehci_writel(ehci, temp, status_reg); - ehci_dbg(ehci, "port %d --> companion\n", wIndex + 1); - temp = ehci_readl(ehci, status_reg); - } - - /* - * Even if OWNER is set, there's no harm letting khubd - * see the wPortStatus values (they should all be 0 except - * for PORT_POWER anyway). - */ - - if (temp & PORT_CONNECT) { - status |= USB_PORT_STAT_CONNECTION; - // status may be from integrated TT - if (ehci->has_hostpc) { - temp1 = ehci_readl(ehci, hostpc_reg); - status |= ehci_port_speed(ehci, temp1); - } else - status |= ehci_port_speed(ehci, temp); - } - if (temp & PORT_PE) - status |= USB_PORT_STAT_ENABLE; - - /* maybe the port was unsuspended without our knowledge */ - if (temp & (PORT_SUSPEND|PORT_RESUME)) { - status |= USB_PORT_STAT_SUSPEND; - } else if (test_bit(wIndex, &ehci->suspended_ports)) { - clear_bit(wIndex, &ehci->suspended_ports); - clear_bit(wIndex, &ehci->resuming_ports); - ehci->reset_done[wIndex] = 0; - if (temp & PORT_PE) - set_bit(wIndex, &ehci->port_c_suspend); - } - - if (temp & PORT_OC) - status |= USB_PORT_STAT_OVERCURRENT; - if (temp & PORT_RESET) - status |= USB_PORT_STAT_RESET; - if (temp & PORT_POWER) - status |= USB_PORT_STAT_POWER; - if (test_bit(wIndex, &ehci->port_c_suspend)) - status |= USB_PORT_STAT_C_SUSPEND << 16; - -#ifndef VERBOSE_DEBUG - if (status & ~0xffff) /* only if wPortChange is interesting */ -#endif - dbg_port (ehci, "GetStatus", wIndex + 1, temp); - put_unaligned_le32(status, buf); - break; - case SetHubFeature: - switch (wValue) { - case C_HUB_LOCAL_POWER: - case C_HUB_OVER_CURRENT: - /* no hub-wide feature/status flags */ - break; - default: - goto error; - } - break; - case SetPortFeature: - selector = wIndex >> 8; - wIndex &= 0xff; - if (unlikely(ehci->debug)) { - /* If the debug port is active any port - * feature requests should get denied */ - if (wIndex == HCS_DEBUG_PORT(ehci->hcs_params) && - (readl(&ehci->debug->control) & DBGP_ENABLED)) { - retval = -ENODEV; - goto error_exit; - } - } - if (!wIndex || wIndex > ports) - goto error; - wIndex--; - temp = ehci_readl(ehci, status_reg); - if (temp & PORT_OWNER) - break; - - temp &= ~PORT_RWC_BITS; - switch (wValue) { - case USB_PORT_FEAT_SUSPEND: - if (ehci->no_selective_suspend) - break; - if ((temp & PORT_PE) == 0 - || (temp & PORT_RESET) != 0) - goto error; - - /* After above check the port must be connected. - * Set appropriate bit thus could put phy into low power - * mode if we have hostpc feature - */ - temp &= ~PORT_WKCONN_E; - - if (enable_ehci_wake && enable_ehci_disc_wakeup) - temp |= PORT_WKDISC_E | PORT_WKOC_E; - else - temp |= PORT_WKOC_E; - - ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); - if (hostpc_reg) { - spin_unlock_irqrestore(&ehci->lock, flags); - msleep(5);/* 5ms for HCD enter low pwr mode */ - spin_lock_irqsave(&ehci->lock, flags); - temp1 = ehci_readl(ehci, hostpc_reg); - ehci_writel(ehci, temp1 | HOSTPC_PHCD, - hostpc_reg); - temp1 = ehci_readl(ehci, hostpc_reg); - ehci_dbg(ehci, "Port%d phy low pwr mode %s\n", - wIndex, (temp1 & HOSTPC_PHCD) ? - "succeeded" : "failed"); - } - set_bit(wIndex, &ehci->suspended_ports); - break; - case USB_PORT_FEAT_POWER: - if (HCS_PPC (ehci->hcs_params)) - ehci_writel(ehci, temp | PORT_POWER, - status_reg); - break; - case USB_PORT_FEAT_RESET: - if (temp & PORT_RESUME) - goto error; - /* line status bits may report this as low speed, - * which can be fine if this root hub has a - * transaction translator built in. - */ - if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT - && !ehci_is_TDI(ehci) - && PORT_USB11 (temp)) { - ehci_dbg (ehci, - "port %d low speed --> companion\n", - wIndex + 1); - temp |= PORT_OWNER; - } else { - ehci_vdbg (ehci, "port %d reset\n", wIndex + 1); - temp |= PORT_RESET; - temp &= ~PORT_PE; - - /* - * caller must wait, then call GetPortStatus - * usb 2.0 spec says 50 ms resets on root - */ - ehci->reset_done [wIndex] = jiffies - + msecs_to_jiffies (50); - } - ehci_writel(ehci, temp, status_reg); - break; - - /* For downstream facing ports (these): one hub port is put - * into test mode according to USB2 11.24.2.13, then the hub - * must be reset (which for root hub now means rmmod+modprobe, - * or else system reboot). See EHCI 2.3.9 and 4.14 for info - * about the EHCI-specific stuff. - */ -/* - case USB_PORT_FEAT_TEST: - if (!selector || selector > 5) - goto error; - ehci_quiesce(ehci); - - // Put all enabled ports into suspend - while (ports--) { - u32 __iomem *sreg = - &ehci->regs->port_status[ports]; - - temp = ehci_readl(ehci, sreg) & ~PORT_RWC_BITS; - if (temp & PORT_PE) - ehci_writel(ehci, temp | PORT_SUSPEND, - sreg); - } - ehci_halt(ehci); - temp = ehci_readl(ehci, status_reg); - temp |= selector << 16; - ehci_writel(ehci, temp, status_reg); - break; -*/ - /*{CharlesTu, 2010.8.26, for test mode */ - case USB_PORT_FEAT_TEST: - ehci_info(ehci, "selector : %x\n ", selector); - //selector = (wIndex >> 8) & 0xff; - port_num = (wIndex) & 0xff; - ehci_info(ehci, "USB_PORT_FEAT_TEST : running test %x " - "on port %d\n", selector, port_num); - if (!selector || selector > 5) - ehci_info(ehci, "USB_PORT_FEAT_TEST 1: running test %x " - "on port %d\n", selector, port_num); - - switch (selector) { - case USB_PORT_TEST_J: - case USB_PORT_TEST_K: - case USB_PORT_TEST_SE0_NAK: - case USB_PORT_TEST_PACKET: - case USB_PORT_TEST_FORCE_ENABLE: - ehci_quiesce(ehci); - ehci_halt(ehci); -#ifdef CONFIG_USB_EHCI_EHSET - stop_test(ehci); -#endif - temp = ehci_readl(ehci, &ehci->regs->command); - temp &= 0xfffffffe; - writel(temp, &ehci->regs->command); - - temp = readl(&ehci->regs->port_status [(wIndex & 0x00ff)]); - temp &= 0xfff0ffff; - writel(temp, &ehci->regs->port_status[port_num]); - temp |= selector << 16; - writel(temp, &ehci->regs->port_status[port_num]); - break; -#ifdef CONFIG_USB_EHCI_EHSET - case USB_PORT_TEST_SINGLE_STEP_SET_FEATURE: - spin_unlock_irqrestore (&ehci->lock, flags); - if (single_step_set_feature(hcd, port_num)) { - spin_lock_irqsave (&ehci->lock, flags); - goto error; - } - spin_lock_irqsave (&ehci->lock, flags); - break; -#endif - - default: - goto error; - ehci_quiesce(ehci); - ehci_halt(ehci); - temp |= selector << 16; - writel (temp, &ehci->regs->port_status[port_num - 1]); - } - break; - /*CharlesTu} */ - - default: - goto error; - } - ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ - break; - - default: -error: - /* "stall" on error */ - retval = -EPIPE; - } -error_exit: - spin_unlock_irqrestore (&ehci->lock, flags); - return retval; -} - -static void __maybe_unused ehci_relinquish_port(struct usb_hcd *hcd, - int portnum) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - - if (ehci_is_TDI(ehci)) - return; - set_owner(ehci, --portnum, PORT_OWNER); -} - -static int __maybe_unused ehci_port_handed_over(struct usb_hcd *hcd, - int portnum) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - u32 __iomem *reg; - - if (ehci_is_TDI(ehci)) - return 0; - reg = &ehci->regs->port_status[portnum - 1]; - return ehci_readl(ehci, reg) & PORT_OWNER; -} diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-ixp4xx.c b/ANDROID_3.4.5/drivers/usb/host/ehci-ixp4xx.c deleted file mode 100644 index c4460f3d..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-ixp4xx.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * IXP4XX EHCI Host Controller Driver - * - * Author: Vladimir Barinov - * - * Based on "ehci-fsl.c" by Randy Vinson - * - * 2007 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ - -#include - -static int ixp4xx_ehci_init(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval = 0; - - ehci->big_endian_desc = 1; - ehci->big_endian_mmio = 1; - - ehci->caps = hcd->regs + 0x100; - ehci->regs = hcd->regs + 0x100 - + HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); - ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); - - hcd->has_tt = 1; - ehci_reset(ehci); - - retval = ehci_init(hcd); - if (retval) - return retval; - - ehci_port_power(ehci, 0); - - return retval; -} - -static const struct hc_driver ixp4xx_ehci_hc_driver = { - .description = hcd_name, - .product_desc = "IXP4XX EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - .reset = ixp4xx_ehci_init, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - .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, -#if defined(CONFIG_PM) - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, -#endif - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static int ixp4xx_ehci_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - const struct hc_driver *driver = &ixp4xx_ehci_hc_driver; - struct resource *res; - int irq; - int retval; - - if (usb_disabled()) - return -ENODEV; - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(&pdev->dev, - "Found HC with no IRQ. Check %s setup!\n", - dev_name(&pdev->dev)); - return -ENODEV; - } - irq = res->start; - - hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - retval = -ENOMEM; - goto fail_create_hcd; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, - "Found HC with no register addr. Check %s setup!\n", - dev_name(&pdev->dev)); - retval = -ENODEV; - goto fail_request_resource; - } - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) { - dev_dbg(&pdev->dev, "controller already in use\n"); - retval = -EBUSY; - goto fail_request_resource; - } - - hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); - if (hcd->regs == NULL) { - dev_dbg(&pdev->dev, "error mapping memory\n"); - retval = -EFAULT; - goto fail_ioremap; - } - - retval = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (retval) - goto fail_add_hcd; - - return retval; - -fail_add_hcd: - iounmap(hcd->regs); -fail_ioremap: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -fail_request_resource: - usb_put_hcd(hcd); -fail_create_hcd: - dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval); - return retval; -} - -static int ixp4xx_ehci_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - - return 0; -} - -MODULE_ALIAS("platform:ixp4xx-ehci"); - -static struct platform_driver ixp4xx_ehci_driver = { - .probe = ixp4xx_ehci_probe, - .remove = ixp4xx_ehci_remove, - .driver = { - .name = "ixp4xx-ehci", - }, -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-lpm.c b/ANDROID_3.4.5/drivers/usb/host/ehci-lpm.c deleted file mode 100644 index 2111627a..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-lpm.c +++ /dev/null @@ -1,84 +0,0 @@ -/* ehci-lpm.c EHCI HCD LPM support code - * Copyright (c) 2008 - 2010, Intel Corporation. - * Author: Jacob Pan - * - * 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. -*/ - -/* this file is part of ehci-hcd.c */ -static int __maybe_unused ehci_lpm_set_da(struct ehci_hcd *ehci, - int dev_addr, int port_num) -{ - u32 __iomem portsc; - - ehci_dbg(ehci, "set dev address %d for port %d\n", dev_addr, port_num); - if (port_num > HCS_N_PORTS(ehci->hcs_params)) { - ehci_dbg(ehci, "invalid port number %d\n", port_num); - return -ENODEV; - } - portsc = ehci_readl(ehci, &ehci->regs->port_status[port_num-1]); - portsc &= ~PORT_DEV_ADDR; - portsc |= dev_addr<<25; - ehci_writel(ehci, portsc, &ehci->regs->port_status[port_num-1]); - return 0; -} - -/* - * this function is used to check if the device support LPM - * if yes, mark the PORTSC register with PORT_LPM bit - */ -static int __maybe_unused ehci_lpm_check(struct ehci_hcd *ehci, int port) -{ - u32 __iomem *portsc ; - u32 val32; - int retval; - - portsc = &ehci->regs->port_status[port-1]; - val32 = ehci_readl(ehci, portsc); - if (!(val32 & PORT_DEV_ADDR)) { - ehci_dbg(ehci, "LPM: no device attached\n"); - return -ENODEV; - } - val32 |= PORT_LPM; - ehci_writel(ehci, val32, portsc); - msleep(5); - val32 |= PORT_SUSPEND; - ehci_dbg(ehci, "Sending LPM 0x%08x to port %d\n", val32, port); - ehci_writel(ehci, val32, portsc); - /* wait for ACK */ - msleep(10); - retval = handshake(ehci, &ehci->regs->port_status[port-1], PORT_SSTS, - PORTSC_SUSPEND_STS_ACK, 125); - dbg_port(ehci, "LPM", port, val32); - if (retval != -ETIMEDOUT) { - ehci_dbg(ehci, "LPM: device ACK for LPM\n"); - val32 |= PORT_LPM; - /* - * now device should be in L1 sleep, let's wake up the device - * so that we can complete enumeration. - */ - ehci_writel(ehci, val32, portsc); - msleep(10); - val32 |= PORT_RESUME; - ehci_writel(ehci, val32, portsc); - } else { - ehci_dbg(ehci, "LPM: device does not ACK, disable LPM %d\n", - retval); - val32 &= ~PORT_LPM; - retval = -ETIMEDOUT; - ehci_writel(ehci, val32, portsc); - } - - return retval; -} diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-ls1x.c b/ANDROID_3.4.5/drivers/usb/host/ehci-ls1x.c deleted file mode 100644 index a283e597..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-ls1x.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Bus Glue for Loongson LS1X built-in EHCI controller. - * - * Copyright (c) 2012 Zhang, Keguang - * - * 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. - */ - - -#include - -static int ehci_ls1x_reset(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int ret; - - ehci->caps = hcd->regs; - - ret = ehci_setup(hcd); - if (ret) - return ret; - - ehci_port_power(ehci, 0); - - return 0; -} - -static const struct hc_driver ehci_ls1x_hc_driver = { - .description = hcd_name, - .product_desc = "LOONGSON1 EHCI", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* - * basic lifecycle operations - */ - .reset = ehci_ls1x_reset, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static int ehci_hcd_ls1x_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - struct resource *res; - int irq; - int ret; - - pr_debug("initializing loongson1 ehci USB Controller\n"); - - if (usb_disabled()) - return -ENODEV; - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(&pdev->dev, - "Found HC with no IRQ. Check %s setup!\n", - dev_name(&pdev->dev)); - return -ENODEV; - } - irq = res->start; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, - "Found HC with no register addr. Check %s setup!\n", - dev_name(&pdev->dev)); - return -ENODEV; - } - - hcd = usb_create_hcd(&ehci_ls1x_hc_driver, &pdev->dev, - dev_name(&pdev->dev)); - if (!hcd) - return -ENOMEM; - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - dev_dbg(&pdev->dev, "controller already in use\n"); - ret = -EBUSY; - goto err_put_hcd; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (hcd->regs == NULL) { - dev_dbg(&pdev->dev, "error mapping memory\n"); - ret = -EFAULT; - goto err_release_region; - } - - ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); - if (ret) - goto err_iounmap; - - return ret; - -err_iounmap: - iounmap(hcd->regs); -err_release_region: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err_put_hcd: - usb_put_hcd(hcd); - return ret; -} - -static int ehci_hcd_ls1x_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - - return 0; -} - -static struct platform_driver ehci_ls1x_driver = { - .probe = ehci_hcd_ls1x_probe, - .remove = ehci_hcd_ls1x_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "ls1x-ehci", - .owner = THIS_MODULE, - }, -}; - -MODULE_ALIAS(PLATFORM_MODULE_PREFIX "ls1x-ehci"); diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-mem.c b/ANDROID_3.4.5/drivers/usb/host/ehci-mem.c deleted file mode 100644 index 12f70c30..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-mem.c +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (c) 2001 by David Brownell - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* this file is part of ehci-hcd.c */ - -/*-------------------------------------------------------------------------*/ - -/* - * There's basically three types of memory: - * - data used only by the HCD ... kmalloc is fine - * - async and periodic schedules, shared by HC and HCD ... these - * need to use dma_pool or dma_alloc_coherent - * - driver buffers, read/written by HC ... single shot DMA mapped - * - * There's also "register" data (e.g. PCI or SOC), which is memory mapped. - * No memory seen by this driver is pageable. - */ - -/*-------------------------------------------------------------------------*/ - -/* Allocate the key transfer structures from the previously allocated pool */ - -static inline void ehci_qtd_init(struct ehci_hcd *ehci, struct ehci_qtd *qtd, - dma_addr_t dma) -{ - memset (qtd, 0, sizeof *qtd); - qtd->qtd_dma = dma; - qtd->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT); - qtd->hw_next = EHCI_LIST_END(ehci); - qtd->hw_alt_next = EHCI_LIST_END(ehci); - INIT_LIST_HEAD (&qtd->qtd_list); -} - -static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, gfp_t flags) -{ - struct ehci_qtd *qtd; - dma_addr_t dma; - - qtd = dma_pool_alloc (ehci->qtd_pool, flags, &dma); - if (qtd != NULL) { - ehci_qtd_init(ehci, qtd, dma); - } - return qtd; -} - -static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd) -{ - dma_pool_free (ehci->qtd_pool, qtd, qtd->qtd_dma); -} - - -static void qh_destroy(struct ehci_qh *qh) -{ - struct ehci_hcd *ehci = qh->ehci; - - /* clean qtds first, and know this is not linked */ - if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) { - ehci_dbg (ehci, "unused qh not empty!\n"); - BUG (); - } - if (qh->dummy) - ehci_qtd_free (ehci, qh->dummy); - dma_pool_free(ehci->qh_pool, qh->hw, qh->qh_dma); - kfree(qh); -} - -static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags) -{ - struct ehci_qh *qh; - dma_addr_t dma; - - qh = kzalloc(sizeof *qh, GFP_ATOMIC); - if (!qh) - goto done; - qh->hw = (struct ehci_qh_hw *) - dma_pool_alloc(ehci->qh_pool, flags, &dma); - if (!qh->hw) - goto fail; - memset(qh->hw, 0, sizeof *qh->hw); - qh->refcount = 1; - qh->ehci = ehci; - qh->qh_dma = dma; - // INIT_LIST_HEAD (&qh->qh_list); - INIT_LIST_HEAD (&qh->qtd_list); - - /* dummy td enables safe urb queuing */ - qh->dummy = ehci_qtd_alloc (ehci, flags); - if (qh->dummy == NULL) { - ehci_dbg (ehci, "no dummy td\n"); - goto fail1; - } -done: - return qh; -fail1: - dma_pool_free(ehci->qh_pool, qh->hw, qh->qh_dma); -fail: - kfree(qh); - return NULL; -} - -/* to share a qh (cpu threads, or hc) */ -static inline struct ehci_qh *qh_get (struct ehci_qh *qh) -{ - WARN_ON(!qh->refcount); - qh->refcount++; - return qh; -} - -static inline void qh_put (struct ehci_qh *qh) -{ - if (!--qh->refcount) - qh_destroy(qh); -} - -/*-------------------------------------------------------------------------*/ - -/* The queue heads and transfer descriptors are managed from pools tied - * to each of the "per device" structures. - * This is the initialisation and cleanup code. - */ - -static void ehci_mem_cleanup (struct ehci_hcd *ehci) -{ - free_cached_lists(ehci); - if (ehci->async) - qh_put (ehci->async); - ehci->async = NULL; - - if (ehci->dummy) - qh_put(ehci->dummy); - ehci->dummy = NULL; - - /* DMA consistent memory and pools */ - if (ehci->qtd_pool) - dma_pool_destroy (ehci->qtd_pool); - ehci->qtd_pool = NULL; - - if (ehci->qh_pool) { - dma_pool_destroy (ehci->qh_pool); - ehci->qh_pool = NULL; - } - - if (ehci->itd_pool) - dma_pool_destroy (ehci->itd_pool); - ehci->itd_pool = NULL; - - if (ehci->sitd_pool) - dma_pool_destroy (ehci->sitd_pool); - ehci->sitd_pool = NULL; - - if (ehci->periodic) - dma_free_coherent (ehci_to_hcd(ehci)->self.controller, - ehci->periodic_size * sizeof (u32), - ehci->periodic, ehci->periodic_dma); - ehci->periodic = NULL; - - /* shadow periodic table */ - kfree(ehci->pshadow); - ehci->pshadow = NULL; -} - -/* remember to add cleanup code (above) if you add anything here */ -static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags) -{ - int i; - - /* QTDs for control/bulk/intr transfers */ - ehci->qtd_pool = dma_pool_create ("ehci_qtd", - ehci_to_hcd(ehci)->self.controller, - sizeof (struct ehci_qtd), - 32 /* byte alignment (for hw parts) */, - 4096 /* can't cross 4K */); - if (!ehci->qtd_pool) { - goto fail; - } - - /* QHs for control/bulk/intr transfers */ - ehci->qh_pool = dma_pool_create ("ehci_qh", - ehci_to_hcd(ehci)->self.controller, - sizeof(struct ehci_qh_hw), - 32 /* byte alignment (for hw parts) */, - 4096 /* can't cross 4K */); - if (!ehci->qh_pool) { - goto fail; - } - ehci->async = ehci_qh_alloc (ehci, flags); - if (!ehci->async) { - goto fail; - } - - /* ITD for high speed ISO transfers */ - ehci->itd_pool = dma_pool_create ("ehci_itd", - ehci_to_hcd(ehci)->self.controller, - sizeof (struct ehci_itd), - 32 /* byte alignment (for hw parts) */, - 4096 /* can't cross 4K */); - if (!ehci->itd_pool) { - goto fail; - } - - /* SITD for full/low speed split ISO transfers */ - ehci->sitd_pool = dma_pool_create ("ehci_sitd", - ehci_to_hcd(ehci)->self.controller, - sizeof (struct ehci_sitd), - 32 /* byte alignment (for hw parts) */, - 4096 /* can't cross 4K */); - if (!ehci->sitd_pool) { - goto fail; - } - - /* Hardware periodic table */ - ehci->periodic = (__le32 *) - dma_alloc_coherent (ehci_to_hcd(ehci)->self.controller, - ehci->periodic_size * sizeof(__le32), - &ehci->periodic_dma, 0); - if (ehci->periodic == NULL) { - goto fail; - } - - if (ehci->use_dummy_qh) { - struct ehci_qh_hw *hw; - ehci->dummy = ehci_qh_alloc(ehci, flags); - if (!ehci->dummy) - goto fail; - - hw = ehci->dummy->hw; - hw->hw_next = EHCI_LIST_END(ehci); - hw->hw_qtd_next = EHCI_LIST_END(ehci); - hw->hw_alt_next = EHCI_LIST_END(ehci); - hw->hw_token &= ~QTD_STS_ACTIVE; - ehci->dummy->hw = hw; - - for (i = 0; i < ehci->periodic_size; i++) - ehci->periodic[i] = ehci->dummy->qh_dma; - } else { - for (i = 0; i < ehci->periodic_size; i++) - ehci->periodic[i] = EHCI_LIST_END(ehci); - } - - /* software shadow of hardware table */ - ehci->pshadow = kcalloc(ehci->periodic_size, sizeof(void *), flags); - if (ehci->pshadow != NULL) - return 0; - -fail: - ehci_dbg (ehci, "couldn't init memory\n"); - ehci_mem_cleanup (ehci); - return -ENOMEM; -} diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-msm.c b/ANDROID_3.4.5/drivers/usb/host/ehci-msm.c deleted file mode 100644 index 9803a55f..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-msm.c +++ /dev/null @@ -1,247 +0,0 @@ -/* ehci-msm.c - HSUSB Host Controller Driver Implementation - * - * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved. - * - * Partly derived from ehci-fsl.c and ehci-hcd.c - * Copyright (c) 2000-2004 by David Brownell - * Copyright (c) 2005 MontaVista Software - * - * All source code in this file is licensed under the following license except - * where indicated. - * - * 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, you can find it at http://www.fsf.org - */ - -#include -#include -#include -#include - -#include -#include - -#define MSM_USB_BASE (hcd->regs) - -static struct usb_phy *phy; - -static int ehci_msm_reset(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; - - ehci->caps = USB_CAPLENGTH; - hcd->has_tt = 1; - - retval = ehci_setup(hcd); - if (retval) - return retval; - - /* bursts of unspecified length. */ - writel(0, USB_AHBBURST); - /* Use the AHB transactor */ - writel(0, USB_AHBMODE); - /* Disable streaming mode and select host mode */ - writel(0x13, USB_USBMODE); - - ehci_port_power(ehci, 1); - return 0; -} - -static struct hc_driver msm_hc_driver = { - .description = hcd_name, - .product_desc = "Qualcomm On-Chip EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_USB2 | HCD_MEMORY, - - .reset = ehci_msm_reset, - .start = ehci_run, - - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - /* - * PM support - */ - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, -}; - -static int ehci_msm_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - struct resource *res; - int ret; - - dev_dbg(&pdev->dev, "ehci_msm proble\n"); - - hcd = usb_create_hcd(&msm_hc_driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - dev_err(&pdev->dev, "Unable to create HCD\n"); - return -ENOMEM; - } - - hcd->irq = platform_get_irq(pdev, 0); - if (hcd->irq < 0) { - dev_err(&pdev->dev, "Unable to get IRQ resource\n"); - ret = hcd->irq; - goto put_hcd; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Unable to get memory resource\n"); - ret = -ENODEV; - goto put_hcd; - } - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto put_hcd; - } - - /* - * OTG driver takes care of PHY initialization, clock management, - * powering up VBUS, mapping of registers address space and power - * management. - */ - phy = usb_get_transceiver(); - if (!phy) { - dev_err(&pdev->dev, "unable to find transceiver\n"); - ret = -ENODEV; - goto unmap; - } - - ret = otg_set_host(phy->otg, &hcd->self); - if (ret < 0) { - dev_err(&pdev->dev, "unable to register with transceiver\n"); - goto put_transceiver; - } - - device_init_wakeup(&pdev->dev, 1); - /* - * OTG device parent of HCD takes care of putting - * hardware into low power mode. - */ - pm_runtime_no_callbacks(&pdev->dev); - pm_runtime_enable(&pdev->dev); - - return 0; - -put_transceiver: - usb_put_transceiver(phy); -unmap: - iounmap(hcd->regs); -put_hcd: - usb_put_hcd(hcd); - - return ret; -} - -static int __devexit ehci_msm_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - device_init_wakeup(&pdev->dev, 0); - pm_runtime_disable(&pdev->dev); - pm_runtime_set_suspended(&pdev->dev); - - otg_set_host(phy->otg, NULL); - usb_put_transceiver(phy); - - usb_put_hcd(hcd); - - return 0; -} - -#ifdef CONFIG_PM -static int ehci_msm_pm_suspend(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - bool wakeup = device_may_wakeup(dev); - - dev_dbg(dev, "ehci-msm PM suspend\n"); - - /* - * EHCI helper function has also the same check before manipulating - * port wakeup flags. We do check here the same condition before - * calling the same helper function to avoid bringing hardware - * from Low power mode when there is no need for adjusting port - * wakeup flags. - */ - if (hcd->self.root_hub->do_remote_wakeup && !wakeup) { - pm_runtime_resume(dev); - ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd), - wakeup); - } - - return 0; -} - -static int ehci_msm_pm_resume(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - - dev_dbg(dev, "ehci-msm PM resume\n"); - ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd)); - - return 0; -} -#else -#define ehci_msm_pm_suspend NULL -#define ehci_msm_pm_resume NULL -#endif - -static const struct dev_pm_ops ehci_msm_dev_pm_ops = { - .suspend = ehci_msm_pm_suspend, - .resume = ehci_msm_pm_resume, -}; - -static struct platform_driver ehci_msm_driver = { - .probe = ehci_msm_probe, - .remove = __devexit_p(ehci_msm_remove), - .driver = { - .name = "msm_hsusb_host", - .pm = &ehci_msm_dev_pm_ops, - }, -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-mv.c b/ANDROID_3.4.5/drivers/usb/host/ehci-mv.c deleted file mode 100644 index a936bbcf..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-mv.c +++ /dev/null @@ -1,391 +0,0 @@ -/* - * Copyright (C) 2011 Marvell International Ltd. All rights reserved. - * Author: Chao Xie - * Neil Zhang - * - * 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 -#include -#include -#include -#include -#include - -#define CAPLENGTH_MASK (0xff) - -struct ehci_hcd_mv { - struct usb_hcd *hcd; - - /* Which mode does this ehci running OTG/Host ? */ - int mode; - - void __iomem *phy_regs; - void __iomem *cap_regs; - void __iomem *op_regs; - - struct usb_phy *otg; - - struct mv_usb_platform_data *pdata; - - /* clock source and total clock number */ - unsigned int clknum; - struct clk *clk[0]; -}; - -static void ehci_clock_enable(struct ehci_hcd_mv *ehci_mv) -{ - unsigned int i; - - for (i = 0; i < ehci_mv->clknum; i++) - clk_enable(ehci_mv->clk[i]); -} - -static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv) -{ - unsigned int i; - - for (i = 0; i < ehci_mv->clknum; i++) - clk_disable(ehci_mv->clk[i]); -} - -static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv) -{ - int retval; - - ehci_clock_enable(ehci_mv); - if (ehci_mv->pdata->phy_init) { - retval = ehci_mv->pdata->phy_init(ehci_mv->phy_regs); - if (retval) - return retval; - } - - return 0; -} - -static void mv_ehci_disable(struct ehci_hcd_mv *ehci_mv) -{ - if (ehci_mv->pdata->phy_deinit) - ehci_mv->pdata->phy_deinit(ehci_mv->phy_regs); - ehci_clock_disable(ehci_mv); -} - -static int mv_ehci_reset(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - struct device *dev = hcd->self.controller; - struct ehci_hcd_mv *ehci_mv = dev_get_drvdata(dev); - int retval; - - if (ehci_mv == NULL) { - dev_err(dev, "Can not find private ehci data\n"); - return -ENODEV; - } - - /* - * data structure init - */ - retval = ehci_init(hcd); - if (retval) { - dev_err(dev, "ehci_init failed %d\n", retval); - return retval; - } - - hcd->has_tt = 1; - ehci->sbrn = 0x20; - - retval = ehci_reset(ehci); - if (retval) { - dev_err(dev, "ehci_reset failed %d\n", retval); - return retval; - } - - return 0; -} - -static const struct hc_driver mv_ehci_hc_driver = { - .description = hcd_name, - .product_desc = "Marvell EHCI", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* - * basic lifecycle operations - */ - .reset = mv_ehci_reset, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, -}; - -static int mv_ehci_probe(struct platform_device *pdev) -{ - struct mv_usb_platform_data *pdata = pdev->dev.platform_data; - struct usb_hcd *hcd; - struct ehci_hcd *ehci; - struct ehci_hcd_mv *ehci_mv; - struct resource *r; - int clk_i, retval = -ENODEV; - u32 offset; - size_t size; - - if (!pdata) { - dev_err(&pdev->dev, "missing platform_data\n"); - return -ENODEV; - } - - if (usb_disabled()) - return -ENODEV; - - hcd = usb_create_hcd(&mv_ehci_hc_driver, &pdev->dev, "mv ehci"); - if (!hcd) - return -ENOMEM; - - size = sizeof(*ehci_mv) + sizeof(struct clk *) * pdata->clknum; - ehci_mv = kzalloc(size, GFP_KERNEL); - if (ehci_mv == NULL) { - dev_err(&pdev->dev, "cannot allocate ehci_hcd_mv\n"); - retval = -ENOMEM; - goto err_put_hcd; - } - - platform_set_drvdata(pdev, ehci_mv); - ehci_mv->pdata = pdata; - ehci_mv->hcd = hcd; - - ehci_mv->clknum = pdata->clknum; - for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++) { - ehci_mv->clk[clk_i] = - clk_get(&pdev->dev, pdata->clkname[clk_i]); - if (IS_ERR(ehci_mv->clk[clk_i])) { - dev_err(&pdev->dev, "error get clck \"%s\"\n", - pdata->clkname[clk_i]); - retval = PTR_ERR(ehci_mv->clk[clk_i]); - goto err_put_clk; - } - } - - r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phyregs"); - if (r == NULL) { - dev_err(&pdev->dev, "no phy I/O memory resource defined\n"); - retval = -ENODEV; - goto err_put_clk; - } - - ehci_mv->phy_regs = ioremap(r->start, resource_size(r)); - if (ehci_mv->phy_regs == 0) { - dev_err(&pdev->dev, "failed to map phy I/O memory\n"); - retval = -EFAULT; - goto err_put_clk; - } - - r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "capregs"); - if (!r) { - dev_err(&pdev->dev, "no I/O memory resource defined\n"); - retval = -ENODEV; - goto err_iounmap_phyreg; - } - - ehci_mv->cap_regs = ioremap(r->start, resource_size(r)); - if (ehci_mv->cap_regs == NULL) { - dev_err(&pdev->dev, "failed to map I/O memory\n"); - retval = -EFAULT; - goto err_iounmap_phyreg; - } - - retval = mv_ehci_enable(ehci_mv); - if (retval) { - dev_err(&pdev->dev, "init phy error %d\n", retval); - goto err_iounmap_capreg; - } - - offset = readl(ehci_mv->cap_regs) & CAPLENGTH_MASK; - ehci_mv->op_regs = - (void __iomem *) ((unsigned long) ehci_mv->cap_regs + offset); - - hcd->rsrc_start = r->start; - hcd->rsrc_len = r->end - r->start + 1; - hcd->regs = ehci_mv->op_regs; - - hcd->irq = platform_get_irq(pdev, 0); - if (!hcd->irq) { - dev_err(&pdev->dev, "Cannot get irq."); - retval = -ENODEV; - goto err_disable_clk; - } - - ehci = hcd_to_ehci(hcd); - ehci->caps = (struct ehci_caps *) ehci_mv->cap_regs; - ehci->regs = (struct ehci_regs *) ehci_mv->op_regs; - ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); - - ehci_mv->mode = pdata->mode; - if (ehci_mv->mode == MV_USB_MODE_OTG) { -#ifdef CONFIG_USB_OTG_UTILS - ehci_mv->otg = usb_get_transceiver(); - if (!ehci_mv->otg) { - dev_err(&pdev->dev, - "unable to find transceiver\n"); - retval = -ENODEV; - goto err_disable_clk; - } - - retval = otg_set_host(ehci_mv->otg->otg, &hcd->self); - if (retval < 0) { - dev_err(&pdev->dev, - "unable to register with transceiver\n"); - retval = -ENODEV; - goto err_put_transceiver; - } - /* otg will enable clock before use as host */ - mv_ehci_disable(ehci_mv); -#else - dev_info(&pdev->dev, "MV_USB_MODE_OTG " - "must have CONFIG_USB_OTG_UTILS enabled\n"); - goto err_disable_clk; -#endif - } else { - if (pdata->set_vbus) - pdata->set_vbus(1); - - retval = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); - if (retval) { - dev_err(&pdev->dev, - "failed to add hcd with err %d\n", retval); - goto err_set_vbus; - } - } - - if (pdata->private_init) - pdata->private_init(ehci_mv->op_regs, ehci_mv->phy_regs); - - dev_info(&pdev->dev, - "successful find EHCI device with regs 0x%p irq %d" - " working in %s mode\n", hcd->regs, hcd->irq, - ehci_mv->mode == MV_USB_MODE_OTG ? "OTG" : "Host"); - - return 0; - -err_set_vbus: - if (pdata->set_vbus) - pdata->set_vbus(0); -#ifdef CONFIG_USB_OTG_UTILS -err_put_transceiver: - if (ehci_mv->otg) - usb_put_transceiver(ehci_mv->otg); -#endif -err_disable_clk: - mv_ehci_disable(ehci_mv); -err_iounmap_capreg: - iounmap(ehci_mv->cap_regs); -err_iounmap_phyreg: - iounmap(ehci_mv->phy_regs); -err_put_clk: - for (clk_i--; clk_i >= 0; clk_i--) - clk_put(ehci_mv->clk[clk_i]); - platform_set_drvdata(pdev, NULL); - kfree(ehci_mv); -err_put_hcd: - usb_put_hcd(hcd); - - return retval; -} - -static int mv_ehci_remove(struct platform_device *pdev) -{ - struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev); - struct usb_hcd *hcd = ehci_mv->hcd; - int clk_i; - - if (hcd->rh_registered) - usb_remove_hcd(hcd); - - if (ehci_mv->otg) { - otg_set_host(ehci_mv->otg->otg, NULL); - usb_put_transceiver(ehci_mv->otg); - } - - if (ehci_mv->mode == MV_USB_MODE_HOST) { - if (ehci_mv->pdata->set_vbus) - ehci_mv->pdata->set_vbus(0); - - mv_ehci_disable(ehci_mv); - } - - iounmap(ehci_mv->cap_regs); - iounmap(ehci_mv->phy_regs); - - for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++) - clk_put(ehci_mv->clk[clk_i]); - - platform_set_drvdata(pdev, NULL); - - kfree(ehci_mv); - usb_put_hcd(hcd); - - return 0; -} - -MODULE_ALIAS("mv-ehci"); - -static const struct platform_device_id ehci_id_table[] = { - {"pxa-u2oehci", PXA_U2OEHCI}, - {"pxa-sph", PXA_SPH}, - {"mmp3-hsic", MMP3_HSIC}, - {"mmp3-fsic", MMP3_FSIC}, - {}, -}; - -static void mv_ehci_shutdown(struct platform_device *pdev) -{ - struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev); - struct usb_hcd *hcd = ehci_mv->hcd; - - if (!hcd->rh_registered) - return; - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - -static struct platform_driver ehci_mv_driver = { - .probe = mv_ehci_probe, - .remove = mv_ehci_remove, - .shutdown = mv_ehci_shutdown, - .driver = { - .name = "mv-ehci", - .bus = &platform_bus_type, - }, - .id_table = ehci_id_table, -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-mxc.c b/ANDROID_3.4.5/drivers/usb/host/ehci-mxc.c deleted file mode 100644 index a797d51e..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-mxc.c +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright (c) 2008 Sascha Hauer , Pengutronix - * Copyright (c) 2009 Daniel Mack - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#define ULPI_VIEWPORT_OFFSET 0x170 - -struct ehci_mxc_priv { - struct clk *usbclk, *ahbclk, *phy1clk; - struct usb_hcd *hcd; -}; - -/* called during probe() after chip reset completes */ -static int ehci_mxc_setup(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; - - dbg_hcs_params(ehci, "reset"); - dbg_hcc_params(ehci, "reset"); - - /* cache this readonly data; minimize chip reads */ - ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); - - hcd->has_tt = 1; - - retval = ehci_halt(ehci); - if (retval) - return retval; - - /* data structure init */ - retval = ehci_init(hcd); - if (retval) - return retval; - - ehci->sbrn = 0x20; - - ehci_reset(ehci); - - ehci_port_power(ehci, 0); - return 0; -} - -static const struct hc_driver ehci_mxc_hc_driver = { - .description = hcd_name, - .product_desc = "Freescale On-Chip EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_USB2 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .reset = ehci_mxc_setup, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static int ehci_mxc_drv_probe(struct platform_device *pdev) -{ - struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data; - struct usb_hcd *hcd; - struct resource *res; - int irq, ret; - unsigned int flags; - struct ehci_mxc_priv *priv; - struct device *dev = &pdev->dev; - struct ehci_hcd *ehci; - - dev_info(&pdev->dev, "initializing i.MX USB Controller\n"); - - if (!pdata) { - dev_err(dev, "No platform data given, bailing out.\n"); - return -EINVAL; - } - - irq = platform_get_irq(pdev, 0); - - hcd = usb_create_hcd(&ehci_mxc_hc_driver, dev, dev_name(dev)); - if (!hcd) - return -ENOMEM; - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { - ret = -ENOMEM; - goto err_alloc; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "Found HC with no register addr. Check setup!\n"); - ret = -ENODEV; - goto err_get_resource; - } - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - dev_dbg(dev, "controller already in use\n"); - ret = -EBUSY; - goto err_request_mem; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - dev_err(dev, "error mapping memory\n"); - ret = -EFAULT; - goto err_ioremap; - } - - /* enable clocks */ - priv->usbclk = clk_get(dev, "usb"); - if (IS_ERR(priv->usbclk)) { - ret = PTR_ERR(priv->usbclk); - goto err_clk; - } - clk_enable(priv->usbclk); - - if (!cpu_is_mx35() && !cpu_is_mx25()) { - priv->ahbclk = clk_get(dev, "usb_ahb"); - if (IS_ERR(priv->ahbclk)) { - ret = PTR_ERR(priv->ahbclk); - goto err_clk_ahb; - } - clk_enable(priv->ahbclk); - } - - /* "dr" device has its own clock on i.MX51 */ - if (cpu_is_mx51() && (pdev->id == 0)) { - priv->phy1clk = clk_get(dev, "usb_phy1"); - if (IS_ERR(priv->phy1clk)) { - ret = PTR_ERR(priv->phy1clk); - goto err_clk_phy; - } - clk_enable(priv->phy1clk); - } - - - /* call platform specific init function */ - if (pdata->init) { - ret = pdata->init(pdev); - if (ret) { - dev_err(dev, "platform init failed\n"); - goto err_init; - } - /* platforms need some time to settle changed IO settings */ - mdelay(10); - } - - ehci = hcd_to_ehci(hcd); - - /* EHCI registers start at offset 0x100 */ - ehci->caps = hcd->regs + 0x100; - ehci->regs = hcd->regs + 0x100 + - HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); - - /* set up the PORTSCx register */ - ehci_writel(ehci, pdata->portsc, &ehci->regs->port_status[0]); - - /* is this really needed? */ - msleep(10); - - /* Initialize the transceiver */ - if (pdata->otg) { - pdata->otg->io_priv = hcd->regs + ULPI_VIEWPORT_OFFSET; - ret = usb_phy_init(pdata->otg); - if (ret) { - dev_err(dev, "unable to init transceiver, probably missing\n"); - ret = -ENODEV; - goto err_add; - } - ret = otg_set_vbus(pdata->otg->otg, 1); - if (ret) { - dev_err(dev, "unable to enable vbus on transceiver\n"); - goto err_add; - } - } - - priv->hcd = hcd; - platform_set_drvdata(pdev, priv); - - ret = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (ret) - goto err_add; - - if (pdata->otg) { - /* - * efikamx and efikasb have some hardware bug which is - * preventing usb to work unless CHRGVBUS is set. - * It's in violation of USB specs - */ - if (machine_is_mx51_efikamx() || machine_is_mx51_efikasb()) { - flags = usb_phy_io_read(pdata->otg, - ULPI_OTG_CTRL); - flags |= ULPI_OTG_CTRL_CHRGVBUS; - ret = usb_phy_io_write(pdata->otg, flags, - ULPI_OTG_CTRL); - if (ret) { - dev_err(dev, "unable to set CHRVBUS\n"); - goto err_add; - } - } - } - - return 0; - -err_add: - if (pdata && pdata->exit) - pdata->exit(pdev); -err_init: - if (priv->phy1clk) { - clk_disable(priv->phy1clk); - clk_put(priv->phy1clk); - } -err_clk_phy: - if (priv->ahbclk) { - clk_disable(priv->ahbclk); - clk_put(priv->ahbclk); - } -err_clk_ahb: - clk_disable(priv->usbclk); - clk_put(priv->usbclk); -err_clk: - iounmap(hcd->regs); -err_ioremap: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err_request_mem: -err_get_resource: - kfree(priv); -err_alloc: - usb_put_hcd(hcd); - return ret; -} - -static int __exit ehci_mxc_drv_remove(struct platform_device *pdev) -{ - struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data; - struct ehci_mxc_priv *priv = platform_get_drvdata(pdev); - struct usb_hcd *hcd = priv->hcd; - - if (pdata && pdata->exit) - pdata->exit(pdev); - - if (pdata->otg) - usb_phy_shutdown(pdata->otg); - - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - platform_set_drvdata(pdev, NULL); - - clk_disable(priv->usbclk); - clk_put(priv->usbclk); - if (priv->ahbclk) { - clk_disable(priv->ahbclk); - clk_put(priv->ahbclk); - } - if (priv->phy1clk) { - clk_disable(priv->phy1clk); - clk_put(priv->phy1clk); - } - - kfree(priv); - - return 0; -} - -static void ehci_mxc_drv_shutdown(struct platform_device *pdev) -{ - struct ehci_mxc_priv *priv = platform_get_drvdata(pdev); - struct usb_hcd *hcd = priv->hcd; - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - -MODULE_ALIAS("platform:mxc-ehci"); - -static struct platform_driver ehci_mxc_driver = { - .probe = ehci_mxc_drv_probe, - .remove = __exit_p(ehci_mxc_drv_remove), - .shutdown = ehci_mxc_drv_shutdown, - .driver = { - .name = "mxc-ehci", - }, -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-octeon.c b/ANDROID_3.4.5/drivers/usb/host/ehci-octeon.c deleted file mode 100644 index c0104882..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-octeon.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * EHCI HCD glue for Cavium Octeon II SOCs. - * - * Loosely based on ehci-au1xxx.c - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2010 Cavium Networks - * - */ - -#include - -#include -#include - -#define OCTEON_EHCI_HCD_NAME "octeon-ehci" - -/* Common clock init code. */ -void octeon2_usb_clocks_start(void); -void octeon2_usb_clocks_stop(void); - -static void ehci_octeon_start(void) -{ - union cvmx_uctlx_ehci_ctl ehci_ctl; - - octeon2_usb_clocks_start(); - - ehci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_EHCI_CTL(0)); - /* Use 64-bit addressing. */ - ehci_ctl.s.ehci_64b_addr_en = 1; - ehci_ctl.s.l2c_addr_msb = 0; - ehci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */ - ehci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */ - cvmx_write_csr(CVMX_UCTLX_EHCI_CTL(0), ehci_ctl.u64); -} - -static void ehci_octeon_stop(void) -{ - octeon2_usb_clocks_stop(); -} - -static const struct hc_driver ehci_octeon_hc_driver = { - .description = hcd_name, - .product_desc = "Octeon EHCI", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* - * basic lifecycle operations - */ - .reset = ehci_init, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static u64 ehci_octeon_dma_mask = DMA_BIT_MASK(64); - -static int ehci_octeon_drv_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - struct ehci_hcd *ehci; - struct resource *res_mem; - int irq; - int ret; - - if (usb_disabled()) - return -ENODEV; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "No irq assigned\n"); - return -ENODEV; - } - - res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res_mem == NULL) { - dev_err(&pdev->dev, "No register space assigned\n"); - return -ENODEV; - } - - /* - * We can DMA from anywhere. But the descriptors must be in - * the lower 4GB. - */ - pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - pdev->dev.dma_mask = &ehci_octeon_dma_mask; - - hcd = usb_create_hcd(&ehci_octeon_hc_driver, &pdev->dev, "octeon"); - if (!hcd) - return -ENOMEM; - - hcd->rsrc_start = res_mem->start; - hcd->rsrc_len = resource_size(res_mem); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - OCTEON_EHCI_HCD_NAME)) { - dev_err(&pdev->dev, "request_mem_region failed\n"); - ret = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto err2; - } - - ehci_octeon_start(); - - ehci = hcd_to_ehci(hcd); - - /* Octeon EHCI matches CPU endianness. */ -#ifdef __BIG_ENDIAN - ehci->big_endian_mmio = 1; -#endif - - ehci->caps = hcd->regs; - ehci->regs = hcd->regs + - HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); - /* cache this readonly data; minimize chip reads */ - ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); - - ehci_reset(ehci); - - ret = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (ret) { - dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret); - goto err3; - } - - platform_set_drvdata(pdev, hcd); - - /* root ports should always stay powered */ - ehci_port_power(ehci, 1); - - return 0; -err3: - ehci_octeon_stop(); - - iounmap(hcd->regs); -err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err1: - usb_put_hcd(hcd); - return ret; -} - -static int ehci_octeon_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - - ehci_octeon_stop(); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - - platform_set_drvdata(pdev, NULL); - - return 0; -} - -static struct platform_driver ehci_octeon_driver = { - .probe = ehci_octeon_drv_probe, - .remove = ehci_octeon_drv_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = OCTEON_EHCI_HCD_NAME, - .owner = THIS_MODULE, - } -}; - -MODULE_ALIAS("platform:" OCTEON_EHCI_HCD_NAME); diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-omap.c b/ANDROID_3.4.5/drivers/usb/host/ehci-omap.c deleted file mode 100644 index e669c6a7..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-omap.c +++ /dev/null @@ -1,377 +0,0 @@ -/* - * ehci-omap.c - driver for USBHOST on OMAP3/4 processors - * - * Bus Glue for the EHCI controllers in OMAP3/4 - * Tested on several OMAP3 boards, and OMAP4 Pandaboard - * - * Copyright (C) 2007-2011 Texas Instruments, Inc. - * Author: Vikram Pandita - * Author: Anand Gadiyar - * Author: Keshava Munegowda - * - * Copyright (C) 2009 Nokia Corporation - * Contact: Felipe Balbi - * - * Based on "ehci-fsl.c" and "ehci-au1xxx.c" ehci glue layers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * TODO (last updated Feb 27, 2010): - * - add kernel-doc - * - enable AUTOIDLE - * - add suspend/resume - * - add HSIC and TLL support - * - convert to use hwmod and runtime PM - */ - -#include -#include -#include -#include -#include -#include -#include - -/* EHCI Register Set */ -#define EHCI_INSNREG04 (0xA0) -#define EHCI_INSNREG04_DISABLE_UNSUSPEND (1 << 5) -#define EHCI_INSNREG05_ULPI (0xA4) -#define EHCI_INSNREG05_ULPI_CONTROL_SHIFT 31 -#define EHCI_INSNREG05_ULPI_PORTSEL_SHIFT 24 -#define EHCI_INSNREG05_ULPI_OPSEL_SHIFT 22 -#define EHCI_INSNREG05_ULPI_REGADD_SHIFT 16 -#define EHCI_INSNREG05_ULPI_EXTREGADD_SHIFT 8 -#define EHCI_INSNREG05_ULPI_WRDATA_SHIFT 0 - -/*-------------------------------------------------------------------------*/ - -static const struct hc_driver ehci_omap_hc_driver; - - -static inline void ehci_write(void __iomem *base, u32 reg, u32 val) -{ - __raw_writel(val, base + reg); -} - -static inline u32 ehci_read(void __iomem *base, u32 reg) -{ - return __raw_readl(base + reg); -} - -static void omap_ehci_soft_phy_reset(struct platform_device *pdev, u8 port) -{ - struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev); - unsigned long timeout = jiffies + msecs_to_jiffies(1000); - unsigned reg = 0; - - reg = ULPI_FUNC_CTRL_RESET - /* FUNCTION_CTRL_SET register */ - | (ULPI_SET(ULPI_FUNC_CTRL) << EHCI_INSNREG05_ULPI_REGADD_SHIFT) - /* Write */ - | (2 << EHCI_INSNREG05_ULPI_OPSEL_SHIFT) - /* PORTn */ - | ((port + 1) << EHCI_INSNREG05_ULPI_PORTSEL_SHIFT) - /* start ULPI access*/ - | (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT); - - ehci_write(hcd->regs, EHCI_INSNREG05_ULPI, reg); - - /* Wait for ULPI access completion */ - while ((ehci_read(hcd->regs, EHCI_INSNREG05_ULPI) - & (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT))) { - cpu_relax(); - - if (time_after(jiffies, timeout)) { - dev_dbg(&pdev->dev, "phy reset operation timed out\n"); - break; - } - } -} - -static void disable_put_regulator( - struct ehci_hcd_omap_platform_data *pdata) -{ - int i; - - for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) { - if (pdata->regulator[i]) { - regulator_disable(pdata->regulator[i]); - regulator_put(pdata->regulator[i]); - } - } -} - -/* configure so an HC device and id are always provided */ -/* always called with process context; sleeping is OK */ - -/** - * ehci_hcd_omap_probe - initialize TI-based HCDs - * - * Allocates basic resources for this USB host controller, and - * then invokes the start() method for the HCD associated with it - * through the hotplug entry's driver_data. - */ -static int ehci_hcd_omap_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct ehci_hcd_omap_platform_data *pdata = dev->platform_data; - struct resource *res; - struct usb_hcd *hcd; - void __iomem *regs; - struct ehci_hcd *omap_ehci; - int ret = -ENODEV; - int irq; - int i; - char supply[7]; - - if (usb_disabled()) - return -ENODEV; - - if (!dev->parent) { - dev_err(dev, "Missing parent device\n"); - return -ENODEV; - } - - irq = platform_get_irq_byname(pdev, "ehci-irq"); - if (irq < 0) { - dev_err(dev, "EHCI irq failed\n"); - return -ENODEV; - } - - res = platform_get_resource_byname(pdev, - IORESOURCE_MEM, "ehci"); - if (!res) { - dev_err(dev, "UHH EHCI get resource failed\n"); - return -ENODEV; - } - - regs = ioremap(res->start, resource_size(res)); - if (!regs) { - dev_err(dev, "UHH EHCI ioremap failed\n"); - return -ENOMEM; - } - - hcd = usb_create_hcd(&ehci_omap_hc_driver, dev, - dev_name(dev)); - if (!hcd) { - dev_err(dev, "failed to create hcd with err %d\n", ret); - ret = -ENOMEM; - goto err_io; - } - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - hcd->regs = regs; - - /* get ehci regulator and enable */ - for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) { - if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY) { - pdata->regulator[i] = NULL; - continue; - } - snprintf(supply, sizeof(supply), "hsusb%d", i); - pdata->regulator[i] = regulator_get(dev, supply); - if (IS_ERR(pdata->regulator[i])) { - pdata->regulator[i] = NULL; - dev_dbg(dev, - "failed to get ehci port%d regulator\n", i); - } else { - regulator_enable(pdata->regulator[i]); - } - } - - if (pdata->phy_reset) { - if (gpio_is_valid(pdata->reset_gpio_port[0])) - gpio_request_one(pdata->reset_gpio_port[0], - GPIOF_OUT_INIT_LOW, "USB1 PHY reset"); - - if (gpio_is_valid(pdata->reset_gpio_port[1])) - gpio_request_one(pdata->reset_gpio_port[1], - GPIOF_OUT_INIT_LOW, "USB2 PHY reset"); - - /* Hold the PHY in RESET for enough time till DIR is high */ - udelay(10); - } - - pm_runtime_enable(dev); - pm_runtime_get_sync(dev); - - /* - * An undocumented "feature" in the OMAP3 EHCI controller, - * causes suspended ports to be taken out of suspend when - * the USBCMD.Run/Stop bit is cleared (for example when - * we do ehci_bus_suspend). - * This breaks suspend-resume if the root-hub is allowed - * to suspend. Writing 1 to this undocumented register bit - * disables this feature and restores normal behavior. - */ - ehci_write(regs, EHCI_INSNREG04, - EHCI_INSNREG04_DISABLE_UNSUSPEND); - - /* Soft reset the PHY using PHY reset command over ULPI */ - if (pdata->port_mode[0] == OMAP_EHCI_PORT_MODE_PHY) - omap_ehci_soft_phy_reset(pdev, 0); - if (pdata->port_mode[1] == OMAP_EHCI_PORT_MODE_PHY) - omap_ehci_soft_phy_reset(pdev, 1); - - omap_ehci = hcd_to_ehci(hcd); - omap_ehci->sbrn = 0x20; - - /* we know this is the memory we want, no need to ioremap again */ - omap_ehci->caps = hcd->regs; - omap_ehci->regs = hcd->regs - + HC_LENGTH(ehci, readl(&omap_ehci->caps->hc_capbase)); - - dbg_hcs_params(omap_ehci, "reset"); - dbg_hcc_params(omap_ehci, "reset"); - - /* cache this readonly data; minimize chip reads */ - omap_ehci->hcs_params = readl(&omap_ehci->caps->hcs_params); - - ehci_reset(omap_ehci); - - if (pdata->phy_reset) { - /* Hold the PHY in RESET for enough time till - * PHY is settled and ready - */ - udelay(10); - - if (gpio_is_valid(pdata->reset_gpio_port[0])) - gpio_set_value(pdata->reset_gpio_port[0], 1); - - if (gpio_is_valid(pdata->reset_gpio_port[1])) - gpio_set_value(pdata->reset_gpio_port[1], 1); - } - - ret = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (ret) { - dev_err(dev, "failed to add hcd with err %d\n", ret); - goto err_add_hcd; - } - - /* root ports should always stay powered */ - ehci_port_power(omap_ehci, 1); - - return 0; - -err_add_hcd: - disable_put_regulator(pdata); - pm_runtime_put_sync(dev); - -err_io: - iounmap(regs); - return ret; -} - - -/** - * ehci_hcd_omap_remove - shutdown processing for EHCI HCDs - * @pdev: USB Host Controller being removed - * - * Reverses the effect of usb_ehci_hcd_omap_probe(), first invoking - * the HCD's stop() method. It is always called from a thread - * context, normally "rmmod", "apmd", or something similar. - */ -static int ehci_hcd_omap_remove(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct ehci_hcd_omap_platform_data *pdata = dev->platform_data; - - usb_remove_hcd(hcd); - disable_put_regulator(dev->platform_data); - iounmap(hcd->regs); - usb_put_hcd(hcd); - pm_runtime_put_sync(dev); - pm_runtime_disable(dev); - - if (pdata->phy_reset) { - if (gpio_is_valid(pdata->reset_gpio_port[0])) - gpio_free(pdata->reset_gpio_port[0]); - - if (gpio_is_valid(pdata->reset_gpio_port[1])) - gpio_free(pdata->reset_gpio_port[1]); - } - return 0; -} - -static void ehci_hcd_omap_shutdown(struct platform_device *pdev) -{ - struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - -static struct platform_driver ehci_hcd_omap_driver = { - .probe = ehci_hcd_omap_probe, - .remove = ehci_hcd_omap_remove, - .shutdown = ehci_hcd_omap_shutdown, - /*.suspend = ehci_hcd_omap_suspend, */ - /*.resume = ehci_hcd_omap_resume, */ - .driver = { - .name = "ehci-omap", - } -}; - -/*-------------------------------------------------------------------------*/ - -static const struct hc_driver ehci_omap_hc_driver = { - .description = hcd_name, - .product_desc = "OMAP-EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* - * basic lifecycle operations - */ - .reset = ehci_init, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -MODULE_ALIAS("platform:omap-ehci"); -MODULE_AUTHOR("Texas Instruments, Inc."); -MODULE_AUTHOR("Felipe Balbi "); - diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-orion.c b/ANDROID_3.4.5/drivers/usb/host/ehci-orion.c deleted file mode 100644 index 6c6a5a3b..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-orion.c +++ /dev/null @@ -1,320 +0,0 @@ -/* - * drivers/usb/host/ehci-orion.c - * - * Tzachi Perelstein - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include -#include -#include -#include -#include - -#define rdl(off) __raw_readl(hcd->regs + (off)) -#define wrl(off, val) __raw_writel((val), hcd->regs + (off)) - -#define USB_CMD 0x140 -#define USB_MODE 0x1a8 -#define USB_CAUSE 0x310 -#define USB_MASK 0x314 -#define USB_WINDOW_CTRL(i) (0x320 + ((i) << 4)) -#define USB_WINDOW_BASE(i) (0x324 + ((i) << 4)) -#define USB_IPG 0x360 -#define USB_PHY_PWR_CTRL 0x400 -#define USB_PHY_TX_CTRL 0x420 -#define USB_PHY_RX_CTRL 0x430 -#define USB_PHY_IVREF_CTRL 0x440 -#define USB_PHY_TST_GRP_CTRL 0x450 - -/* - * Implement Orion USB controller specification guidelines - */ -static void orion_usb_phy_v1_setup(struct usb_hcd *hcd) -{ - /* The below GLs are according to the Orion Errata document */ - /* - * Clear interrupt cause and mask - */ - wrl(USB_CAUSE, 0); - wrl(USB_MASK, 0); - - /* - * Reset controller - */ - wrl(USB_CMD, rdl(USB_CMD) | 0x2); - while (rdl(USB_CMD) & 0x2); - - /* - * GL# USB-10: Set IPG for non start of frame packets - * Bits[14:8]=0xc - */ - wrl(USB_IPG, (rdl(USB_IPG) & ~0x7f00) | 0xc00); - - /* - * GL# USB-9: USB 2.0 Power Control - * BG_VSEL[7:6]=0x1 - */ - wrl(USB_PHY_PWR_CTRL, (rdl(USB_PHY_PWR_CTRL) & ~0xc0)| 0x40); - - /* - * GL# USB-1: USB PHY Tx Control - force calibration to '8' - * TXDATA_BLOCK_EN[21]=0x1, EXT_RCAL_EN[13]=0x1, IMP_CAL[6:3]=0x8 - */ - wrl(USB_PHY_TX_CTRL, (rdl(USB_PHY_TX_CTRL) & ~0x78) | 0x202040); - - /* - * GL# USB-3 GL# USB-9: USB PHY Rx Control - * RXDATA_BLOCK_LENGHT[31:30]=0x3, EDGE_DET_SEL[27:26]=0, - * CDR_FASTLOCK_EN[21]=0, DISCON_THRESHOLD[9:8]=0, SQ_THRESH[7:4]=0x1 - */ - wrl(USB_PHY_RX_CTRL, (rdl(USB_PHY_RX_CTRL) & ~0xc2003f0) | 0xc0000010); - - /* - * GL# USB-3 GL# USB-9: USB PHY IVREF Control - * PLLVDD12[1:0]=0x2, RXVDD[5:4]=0x3, Reserved[19]=0 - */ - wrl(USB_PHY_IVREF_CTRL, (rdl(USB_PHY_IVREF_CTRL) & ~0x80003 ) | 0x32); - - /* - * GL# USB-3 GL# USB-9: USB PHY Test Group Control - * REG_FIFO_SQ_RST[15]=0 - */ - wrl(USB_PHY_TST_GRP_CTRL, rdl(USB_PHY_TST_GRP_CTRL) & ~0x8000); - - /* - * Stop and reset controller - */ - wrl(USB_CMD, rdl(USB_CMD) & ~0x1); - wrl(USB_CMD, rdl(USB_CMD) | 0x2); - while (rdl(USB_CMD) & 0x2); - - /* - * GL# USB-5 Streaming disable REG_USB_MODE[4]=1 - * TBD: This need to be done after each reset! - * GL# USB-4 Setup USB Host mode - */ - wrl(USB_MODE, 0x13); -} - -static int ehci_orion_setup(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; - - hcd->has_tt = 1; - - retval = ehci_halt(ehci); - if (retval) - return retval; - - /* - * data structure init - */ - retval = ehci_init(hcd); - if (retval) - return retval; - - ehci_reset(ehci); - - ehci_port_power(ehci, 0); - - return retval; -} - -static const struct hc_driver ehci_orion_hc_driver = { - .description = hcd_name, - .product_desc = "Marvell Orion EHCI", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* - * basic lifecycle operations - */ - .reset = ehci_orion_setup, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static void __init -ehci_orion_conf_mbus_windows(struct usb_hcd *hcd, - const struct mbus_dram_target_info *dram) -{ - int i; - - for (i = 0; i < 4; i++) { - wrl(USB_WINDOW_CTRL(i), 0); - wrl(USB_WINDOW_BASE(i), 0); - } - - for (i = 0; i < dram->num_cs; i++) { - const struct mbus_dram_window *cs = dram->cs + i; - - wrl(USB_WINDOW_CTRL(i), ((cs->size - 1) & 0xffff0000) | - (cs->mbus_attr << 8) | - (dram->mbus_dram_target_id << 4) | 1); - wrl(USB_WINDOW_BASE(i), cs->base); - } -} - -static int __devinit ehci_orion_drv_probe(struct platform_device *pdev) -{ - struct orion_ehci_data *pd = pdev->dev.platform_data; - const struct mbus_dram_target_info *dram; - struct resource *res; - struct usb_hcd *hcd; - struct ehci_hcd *ehci; - void __iomem *regs; - int irq, err; - - if (usb_disabled()) - return -ENODEV; - - pr_debug("Initializing Orion-SoC USB Host Controller\n"); - - irq = platform_get_irq(pdev, 0); - if (irq <= 0) { - dev_err(&pdev->dev, - "Found HC with no IRQ. Check %s setup!\n", - dev_name(&pdev->dev)); - err = -ENODEV; - goto err1; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, - "Found HC with no register addr. Check %s setup!\n", - dev_name(&pdev->dev)); - err = -ENODEV; - goto err1; - } - - if (!request_mem_region(res->start, resource_size(res), - ehci_orion_hc_driver.description)) { - dev_dbg(&pdev->dev, "controller already in use\n"); - err = -EBUSY; - goto err1; - } - - regs = ioremap(res->start, resource_size(res)); - if (regs == NULL) { - dev_dbg(&pdev->dev, "error mapping memory\n"); - err = -EFAULT; - goto err2; - } - - hcd = usb_create_hcd(&ehci_orion_hc_driver, - &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - err = -ENOMEM; - goto err3; - } - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - hcd->regs = regs; - - ehci = hcd_to_ehci(hcd); - ehci->caps = hcd->regs + 0x100; - ehci->regs = hcd->regs + 0x100 + - HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); - ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); - hcd->has_tt = 1; - ehci->sbrn = 0x20; - - /* - * (Re-)program MBUS remapping windows if we are asked to. - */ - dram = mv_mbus_dram_info(); - if (dram) - ehci_orion_conf_mbus_windows(hcd, dram); - - /* - * setup Orion USB controller. - */ - switch (pd->phy_version) { - case EHCI_PHY_NA: /* dont change USB phy settings */ - break; - case EHCI_PHY_ORION: - orion_usb_phy_v1_setup(hcd); - break; - case EHCI_PHY_DD: - case EHCI_PHY_KW: - default: - printk(KERN_WARNING "Orion ehci -USB phy version isn't supported.\n"); - } - - err = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (err) - goto err4; - - return 0; - -err4: - usb_put_hcd(hcd); -err3: - iounmap(regs); -err2: - release_mem_region(res->start, resource_size(res)); -err1: - dev_err(&pdev->dev, "init %s fail, %d\n", - dev_name(&pdev->dev), err); - - return err; -} - -static int __exit ehci_orion_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - - return 0; -} - -MODULE_ALIAS("platform:orion-ehci"); - -static struct platform_driver ehci_orion_driver = { - .probe = ehci_orion_drv_probe, - .remove = __exit_p(ehci_orion_drv_remove), - .shutdown = usb_hcd_platform_shutdown, - .driver.name = "orion-ehci", -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-pci.c b/ANDROID_3.4.5/drivers/usb/host/ehci-pci.c deleted file mode 100644 index 49726685..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-pci.c +++ /dev/null @@ -1,575 +0,0 @@ -/* - * EHCI HCD (Host Controller Driver) PCI Bus Glue. - * - * Copyright (c) 2000-2004 by David Brownell - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef CONFIG_PCI -#error "This file is PCI bus glue. CONFIG_PCI must be defined." -#endif - -/* defined here to avoid adding to pci_ids.h for single instance use */ -#define PCI_DEVICE_ID_INTEL_CE4100_USB 0x2e70 - -/*-------------------------------------------------------------------------*/ - -extern char enable_ehci_wake; - -/* called after powerup, by probe or system-pm "wakeup" */ -static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev) -{ - int retval; - - /* we expect static quirk code to handle the "extended capabilities" - * (currently just BIOS handoff) allowed starting with EHCI 0.96 - */ - - /* PCI Memory-Write-Invalidate cycle support is optional (uncommon) */ - retval = pci_set_mwi(pdev); - if (!retval) - ehci_dbg(ehci, "MWI active\n"); - - return 0; -} - -/* called during probe() after chip reset completes */ -static int ehci_pci_setup(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - struct pci_dev *p_smbus; - u8 rev; - u32 temp; - int retval; - - switch (pdev->vendor) { - case PCI_VENDOR_ID_TOSHIBA_2: - /* celleb's companion chip */ - if (pdev->device == 0x01b5) { -#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO - ehci->big_endian_mmio = 1; -#else - ehci_warn(ehci, - "unsupported big endian Toshiba quirk\n"); -#endif - } - break; - } - - ehci->caps = hcd->regs; - ehci->regs = hcd->regs + - HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); - - dbg_hcs_params(ehci, "reset"); - dbg_hcc_params(ehci, "reset"); - - /* ehci_init() causes memory for DMA transfers to be - * allocated. Thus, any vendor-specific workarounds based on - * limiting the type of memory used for DMA transfers must - * happen before ehci_init() is called. */ - switch (pdev->vendor) { - case PCI_VENDOR_ID_NVIDIA: - /* NVidia reports that certain chips don't handle - * QH, ITD, or SITD addresses above 2GB. (But TD, - * data buffer, and periodic schedule are normal.) - */ - switch (pdev->device) { - case 0x003c: /* MCP04 */ - case 0x005b: /* CK804 */ - case 0x00d8: /* CK8 */ - case 0x00e8: /* CK8S */ - if (pci_set_consistent_dma_mask(pdev, - DMA_BIT_MASK(31)) < 0) - ehci_warn(ehci, "can't enable NVidia " - "workaround for >2GB RAM\n"); - break; - } - break; - } - - /* cache this readonly data; minimize chip reads */ - ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); - - retval = ehci_halt(ehci); - if (retval) - return retval; - - if ((pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x7808) || - (pdev->vendor == PCI_VENDOR_ID_ATI && pdev->device == 0x4396)) { - /* EHCI controller on AMD SB700/SB800/Hudson-2/3 platforms may - * read/write memory space which does not belong to it when - * there is NULL pointer with T-bit set to 1 in the frame list - * table. To avoid the issue, the frame list link pointer - * should always contain a valid pointer to a inactive qh. - */ - ehci->use_dummy_qh = 1; - ehci_info(ehci, "applying AMD SB700/SB800/Hudson-2/3 EHCI " - "dummy qh workaround\n"); - } - - /* data structure init */ - retval = ehci_init(hcd); - if (retval) - return retval; - - switch (pdev->vendor) { - case PCI_VENDOR_ID_NEC: - ehci->need_io_watchdog = 0; - break; - case PCI_VENDOR_ID_INTEL: - ehci->need_io_watchdog = 0; - ehci->fs_i_thresh = 1; - if (pdev->device == 0x27cc) { - ehci->broken_periodic = 1; - ehci_info(ehci, "using broken periodic workaround\n"); - } - if (pdev->device == 0x0806 || pdev->device == 0x0811 - || pdev->device == 0x0829) { - ehci_info(ehci, "disable lpm for langwell/penwell\n"); - ehci->has_lpm = 0; - } - if (pdev->device == PCI_DEVICE_ID_INTEL_CE4100_USB) { - hcd->has_tt = 1; - tdi_reset(ehci); - } - break; - case PCI_VENDOR_ID_TDI: - if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) { - hcd->has_tt = 1; - tdi_reset(ehci); - } - break; - case PCI_VENDOR_ID_AMD: - /* AMD PLL quirk */ - if (usb_amd_find_chipset_info()) - ehci->amd_pll_fix = 1; - /* AMD8111 EHCI doesn't work, according to AMD errata */ - if (pdev->device == 0x7463) { - ehci_info(ehci, "ignoring AMD8111 (errata)\n"); - retval = -EIO; - goto done; - } - break; - case PCI_VENDOR_ID_NVIDIA: - switch (pdev->device) { - /* Some NForce2 chips have problems with selective suspend; - * fixed in newer silicon. - */ - case 0x0068: - if (pdev->revision < 0xa4) - ehci->no_selective_suspend = 1; - break; - - /* MCP89 chips on the MacBookAir3,1 give EPROTO when - * fetching device descriptors unless LPM is disabled. - * There are also intermittent problems enumerating - * devices with PPCD enabled. - */ - case 0x0d9d: - ehci_info(ehci, "disable lpm/ppcd for nvidia mcp89"); - ehci->has_lpm = 0; - ehci->has_ppcd = 0; - ehci->command &= ~CMD_PPCEE; - break; - } - break; - case PCI_VENDOR_ID_VIA: - if (pdev->device == 0x3104 && (pdev->revision & 0xf0) == 0x60) { - u8 tmp; - - /* The VT6212 defaults to a 1 usec EHCI sleep time which - * hogs the PCI bus *badly*. Setting bit 5 of 0x4B makes - * that sleep time use the conventional 10 usec. - */ - pci_read_config_byte(pdev, 0x4b, &tmp); - if (tmp & 0x20) - break; - pci_write_config_byte(pdev, 0x4b, tmp | 0x20); - } - break; - case PCI_VENDOR_ID_ATI: - /* AMD PLL quirk */ - if (usb_amd_find_chipset_info()) - ehci->amd_pll_fix = 1; - /* SB600 and old version of SB700 have a bug in EHCI controller, - * which causes usb devices lose response in some cases. - */ - if ((pdev->device == 0x4386) || (pdev->device == 0x4396)) { - p_smbus = pci_get_device(PCI_VENDOR_ID_ATI, - PCI_DEVICE_ID_ATI_SBX00_SMBUS, - NULL); - if (!p_smbus) - break; - rev = p_smbus->revision; - if ((pdev->device == 0x4386) || (rev == 0x3a) - || (rev == 0x3b)) { - u8 tmp; - ehci_info(ehci, "applying AMD SB600/SB700 USB " - "freeze workaround\n"); - pci_read_config_byte(pdev, 0x53, &tmp); - pci_write_config_byte(pdev, 0x53, tmp | (1<<3)); - } - pci_dev_put(p_smbus); - } - break; - case PCI_VENDOR_ID_NETMOS: - /* MosChip frame-index-register bug */ - ehci_info(ehci, "applying MosChip frame-index workaround\n"); - ehci->frame_index_bug = 1; - break; - } - - /* optional debug port, normally in the first BAR */ - temp = pci_find_capability(pdev, 0x0a); - if (temp) { - pci_read_config_dword(pdev, temp, &temp); - temp >>= 16; - if ((temp & (3 << 13)) == (1 << 13)) { - temp &= 0x1fff; - ehci->debug = ehci_to_hcd(ehci)->regs + temp; - temp = ehci_readl(ehci, &ehci->debug->control); - ehci_info(ehci, "debug port %d%s\n", - HCS_DEBUG_PORT(ehci->hcs_params), - (temp & DBGP_ENABLED) - ? " IN USE" - : ""); - if (!(temp & DBGP_ENABLED)) - ehci->debug = NULL; - } - } - - ehci_reset(ehci); - - /* at least the Genesys GL880S needs fixup here */ - temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params); - temp &= 0x0f; - if (temp && HCS_N_PORTS(ehci->hcs_params) > temp) { - ehci_dbg(ehci, "bogus port configuration: " - "cc=%d x pcc=%d < ports=%d\n", - HCS_N_CC(ehci->hcs_params), - HCS_N_PCC(ehci->hcs_params), - HCS_N_PORTS(ehci->hcs_params)); - - switch (pdev->vendor) { - case 0x17a0: /* GENESYS */ - /* GL880S: should be PORTS=2 */ - temp |= (ehci->hcs_params & ~0xf); - ehci->hcs_params = temp; - break; - case PCI_VENDOR_ID_NVIDIA: - /* NF4: should be PCC=10 */ - break; - } - } - - /* Serial Bus Release Number is at PCI 0x60 offset */ - pci_read_config_byte(pdev, 0x60, &ehci->sbrn); - if (pdev->vendor == PCI_VENDOR_ID_STMICRO - && pdev->device == PCI_DEVICE_ID_STMICRO_USB_HOST) - ehci->sbrn = 0x20; /* ConneXT has no sbrn register */ - - /* Keep this around for a while just in case some EHCI - * implementation uses legacy PCI PM support. This test - * can be removed on 17 Dec 2009 if the dev_warn() hasn't - * been triggered by then. - */ - if (!device_can_wakeup(&pdev->dev)) { - u16 port_wake; - - pci_read_config_word(pdev, 0x62, &port_wake); - if (port_wake & 0x0001) { - dev_warn(&pdev->dev, "Enabling legacy PCI PM\n"); - device_set_wakeup_capable(&pdev->dev, 1); - } - } - -#ifdef CONFIG_USB_SUSPEND - /* REVISIT: the controller works fine for wakeup iff the root hub - * itself is "globally" suspended, but usbcore currently doesn't - * understand such things. - * - * System suspend currently expects to be able to suspend the entire - * device tree, device-at-a-time. If we failed selective suspend - * reports, system suspend would fail; so the root hub code must claim - * success. That's lying to usbcore, and it matters for runtime - * PM scenarios with selective suspend and remote wakeup... - */ - if (ehci->no_selective_suspend && device_can_wakeup(&pdev->dev)) - ehci_warn(ehci, "selective suspend/wakeup unavailable\n"); -#endif - - ehci_port_power(ehci, 1); - retval = ehci_pci_reinit(ehci, pdev); -done: - return retval; -} - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_PM - -/* suspend/resume, section 4.3 */ - -/* These routines rely on the PCI bus glue - * to handle powerdown and wakeup, and currently also on - * transceivers that don't need any software attention to set up - * the right sort of wakeup. - * Also they depend on separate root hub suspend/resume. - */ - -static int ehci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - unsigned long flags; - int rc = 0; - u16 pmc_enable = 0; - if (time_before(jiffies, ehci->next_statechange)) - msleep(10); - - /* Root hub was already suspended. Disable irq emission and - * mark HW unaccessible. The PM and USB cores make sure that - * the root hub is either suspended or stopped. - */ - ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup); - spin_lock_irqsave (&ehci->lock, flags); - ehci_writel(ehci, 0, &ehci->regs->intr_enable); - (void)ehci_readl(ehci, &ehci->regs->intr_enable); - - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - spin_unlock_irqrestore (&ehci->lock, flags); - - // could save FLADJ in case of Vaux power loss - // ... we'd only use it to handle clock skew - //CharlesTu,for PM high memory - if (enable_ehci_wake) { - pci_read_config_word(to_pci_dev(hcd->self.controller), 0x84, &pmc_enable); - pmc_enable |= 0x103; - pci_write_config_word(to_pci_dev(hcd->self.controller), 0x84, pmc_enable); - } - return rc; -} - -static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev) -{ - return pdev->class == PCI_CLASS_SERIAL_USB_EHCI && - pdev->vendor == PCI_VENDOR_ID_INTEL && - (pdev->device == 0x1E26 || - pdev->device == 0x8C2D || - pdev->device == 0x8C26); -} - -static void ehci_enable_xhci_companion(void) -{ - struct pci_dev *companion = NULL; - - /* The xHCI and EHCI controllers are not on the same PCI slot */ - for_each_pci_dev(companion) { - if (!usb_is_intel_switchable_xhci(companion)) - continue; - usb_enable_xhci_ports(companion); - return; - } -} - -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); - - /* The BIOS on systems with the Intel Panther Point chipset may or may - * not support xHCI natively. That means that during system resume, it - * may switch the ports back to EHCI so that users can use their - * keyboard to select a kernel from GRUB after resume from hibernate. - * - * The BIOS is supposed to remember whether the OS had xHCI ports - * enabled before resume, and switch the ports back to xHCI when the - * BIOS/OS semaphore is written, but we all know we can't trust BIOS - * writers. - * - * Unconditionally switch the ports back to xHCI after a system resume. - * We can't tell whether the EHCI or xHCI controller will be resumed - * first, so we have to do the port switchover in both drivers. Writing - * a '1' to the port switchover registers should have no effect if the - * port was already switched over. - */ - u16 pmc_enable = 0; - //CharlesTu,for PM high memory - if (enable_ehci_wake) { - pci_read_config_word(pdev, 0x84, &pmc_enable); - pmc_enable &= ~0x03; - pci_write_config_word(pdev, 0x84, pmc_enable); - } - if (usb_is_intel_switchable_ehci(pdev)) - ehci_enable_xhci_companion(); - - // maybe restore FLADJ - - if (time_before(jiffies, ehci->next_statechange)) - msleep(100); - - /* Mark hardware accessible again as we are out of D3 state by now */ - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - /*CharlesTu,2011.01,21,move ahead,due to vbus lost when suspend - * when resume ehci hub activate ,type= HUB_RESET_RESUME - */ - if (!enable_ehci_wake) - usb_root_hub_lost_power(hcd->self.root_hub); - /* 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 && - !hibernated) { - int mask = INTR_MASK; - - ehci_prepare_ports_for_controller_resume(ehci); - if (!hcd->self.root_hub->do_remote_wakeup) - mask &= ~STS_PCD; - ehci_writel(ehci, mask, &ehci->regs->intr_enable); - ehci_readl(ehci, &ehci->regs->intr_enable); - return 0; - } - /*CharlesTu,2011.01,21,move ahead,due to vbus lost when suspend*/ - if (enable_ehci_wake) - usb_root_hub_lost_power(hcd->self.root_hub); - - /* Else reset, to cope with power loss or flush-to-storage - * style "resume" having let BIOS kick in during reboot. - */ - (void) ehci_halt(ehci); - (void) ehci_reset(ehci); - (void) ehci_pci_reinit(ehci, pdev); - - /* emptying the schedule aborts any urbs */ - spin_lock_irq(&ehci->lock); - if (ehci->reclaim) - end_unlink_async(ehci); - ehci_work(ehci); - spin_unlock_irq(&ehci->lock); - - ehci_writel(ehci, ehci->command, &ehci->regs->command); - ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); - ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ - - /* here we "know" root ports should always stay powered */ - ehci_port_power(ehci, 1); - - ehci->rh_state = EHCI_RH_SUSPENDED; - return 0; -} -#endif - -static int ehci_update_device(struct usb_hcd *hcd, struct usb_device *udev) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int rc = 0; - - if (!udev->parent) /* udev is root hub itself, impossible */ - rc = -1; - /* we only support lpm device connected to root hub yet */ - if (ehci->has_lpm && !udev->parent->parent) { - rc = ehci_lpm_set_da(ehci, udev->devnum, udev->portnum); - if (!rc) - rc = ehci_lpm_check(ehci, udev->portnum); - } - return rc; -} - -static const struct hc_driver ehci_pci_hc_driver = { - .description = hcd_name, - .product_desc = "EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* - * basic lifecycle operations - */ - .reset = ehci_pci_setup, - .start = ehci_run, -#ifdef CONFIG_PM - .pci_suspend = ehci_pci_suspend, - .pci_resume = ehci_pci_resume, -#endif - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - /* - * call back when device connected and addressed - */ - .update_device = ehci_update_device, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -/*-------------------------------------------------------------------------*/ - -/* PCI driver selection metadata; PCI hotplugging uses this */ -static const struct pci_device_id pci_ids [] = { { - /* handle any USB 2.0 EHCI controller */ - PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_EHCI, ~0), - .driver_data = (unsigned long) &ehci_pci_hc_driver, - }, { - PCI_VDEVICE(STMICRO, PCI_DEVICE_ID_STMICRO_USB_HOST), - .driver_data = (unsigned long) &ehci_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 ehci_pci_driver = { - .name = (char *) hcd_name, - .id_table = pci_ids, - - .probe = usb_hcd_pci_probe, - .remove = usb_hcd_pci_remove, - .shutdown = usb_hcd_pci_shutdown, - -#ifdef CONFIG_PM_SLEEP - .driver = { - .pm = &usb_hcd_pci_pm_ops - }, -#endif -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-platform.c b/ANDROID_3.4.5/drivers/usb/host/ehci-platform.c deleted file mode 100644 index 82c1eb8b..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-platform.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Generic platform ehci driver - * - * Copyright 2007 Steven Brown - * Copyright 2010-2012 Hauke Mehrtens - * - * Derived from the ohci-ssb driver - * Copyright 2007 Michael Buesch - * - * Derived from the EHCI-PCI driver - * Copyright (c) 2000-2004 by David Brownell - * - * Derived from the ohci-pci driver - * Copyright 1999 Roman Weissgaerber - * Copyright 2000-2002 David Brownell - * Copyright 1999 Linus Torvalds - * Copyright 1999 Gregory P. Smith - * - * Licensed under the GNU/GPL. See COPYING for details. - */ -#include -#include - -static int ehci_platform_reset(struct usb_hcd *hcd) -{ - struct platform_device *pdev = to_platform_device(hcd->self.controller); - struct usb_ehci_pdata *pdata = pdev->dev.platform_data; - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; - - hcd->has_tt = pdata->has_tt; - ehci->has_synopsys_hc_bug = pdata->has_synopsys_hc_bug; - ehci->big_endian_desc = pdata->big_endian_desc; - ehci->big_endian_mmio = pdata->big_endian_mmio; - - ehci->caps = hcd->regs + pdata->caps_offset; - retval = ehci_setup(hcd); - if (retval) - return retval; - - if (pdata->port_power_on) - ehci_port_power(ehci, 1); - if (pdata->port_power_off) - ehci_port_power(ehci, 0); - - return 0; -} - -static const struct hc_driver ehci_platform_hc_driver = { - .description = hcd_name, - .product_desc = "Generic Platform EHCI Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - .reset = ehci_platform_reset, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - .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, -#if defined(CONFIG_PM) - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, -#endif - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static int __devinit ehci_platform_probe(struct platform_device *dev) -{ - struct usb_hcd *hcd; - struct resource *res_mem; - int irq; - int err = -ENOMEM; - - BUG_ON(!dev->dev.platform_data); - - if (usb_disabled()) - return -ENODEV; - - irq = platform_get_irq(dev, 0); - if (irq < 0) { - pr_err("no irq provieded"); - return irq; - } - res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!res_mem) { - pr_err("no memory recourse provieded"); - return -ENXIO; - } - - hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev, - dev_name(&dev->dev)); - if (!hcd) - return -ENOMEM; - - hcd->rsrc_start = res_mem->start; - hcd->rsrc_len = resource_size(res_mem); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - pr_err("controller already in use"); - err = -EBUSY; - goto err_put_hcd; - } - - hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) - goto err_release_region; - err = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (err) - goto err_iounmap; - - platform_set_drvdata(dev, hcd); - - return err; - -err_iounmap: - iounmap(hcd->regs); -err_release_region: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err_put_hcd: - usb_put_hcd(hcd); - return err; -} - -static int __devexit ehci_platform_remove(struct platform_device *dev) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - platform_set_drvdata(dev, NULL); - - return 0; -} - -#ifdef CONFIG_PM - -static int ehci_platform_suspend(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - bool wakeup = device_may_wakeup(dev); - - ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd), wakeup); - return 0; -} - -static int ehci_platform_resume(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - - ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd)); - return 0; -} - -#else /* !CONFIG_PM */ -#define ehci_platform_suspend NULL -#define ehci_platform_resume NULL -#endif /* CONFIG_PM */ - -static const struct platform_device_id ehci_platform_table[] = { - { "ehci-platform", 0 }, - { } -}; -MODULE_DEVICE_TABLE(platform, ehci_platform_table); - -static const struct dev_pm_ops ehci_platform_pm_ops = { - .suspend = ehci_platform_suspend, - .resume = ehci_platform_resume, -}; - -static struct platform_driver ehci_platform_driver = { - .id_table = ehci_platform_table, - .probe = ehci_platform_probe, - .remove = __devexit_p(ehci_platform_remove), - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .owner = THIS_MODULE, - .name = "ehci-platform", - .pm = &ehci_platform_pm_ops, - } -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-pmcmsp.c b/ANDROID_3.4.5/drivers/usb/host/ehci-pmcmsp.c deleted file mode 100644 index e8d54de4..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-pmcmsp.c +++ /dev/null @@ -1,383 +0,0 @@ -/* - * PMC MSP EHCI (Host Controller Driver) for USB. - * - * (C) Copyright 2006-2010 PMC-Sierra Inc - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - */ - -/* includes */ -#include -#include -#include -#include - -/* stream disable*/ -#define USB_CTRL_MODE_STREAM_DISABLE 0x10 - -/* threshold */ -#define USB_CTRL_FIFO_THRESH 0x00300000 - -/* register offset for usb_mode */ -#define USB_EHCI_REG_USB_MODE 0x68 - -/* register offset for usb fifo */ -#define USB_EHCI_REG_USB_FIFO 0x24 - -/* register offset for usb status */ -#define USB_EHCI_REG_USB_STATUS 0x44 - -/* serial/parallel transceiver */ -#define USB_EHCI_REG_BIT_STAT_STS (1<<29) - -/* TWI USB0 host device pin */ -#define MSP_PIN_USB0_HOST_DEV 49 - -/* TWI USB1 host device pin */ -#define MSP_PIN_USB1_HOST_DEV 50 - - -static void usb_hcd_tdi_set_mode(struct ehci_hcd *ehci) -{ - u8 *base; - u8 *statreg; - u8 *fiforeg; - u32 val; - struct ehci_regs *reg_base = ehci->regs; - - /* get register base */ - base = (u8 *)reg_base + USB_EHCI_REG_USB_MODE; - statreg = (u8 *)reg_base + USB_EHCI_REG_USB_STATUS; - fiforeg = (u8 *)reg_base + USB_EHCI_REG_USB_FIFO; - - /* Disable controller mode stream */ - val = ehci_readl(ehci, (u32 *)base); - ehci_writel(ehci, (val | USB_CTRL_MODE_STREAM_DISABLE), - (u32 *)base); - - /* clear STS to select parallel transceiver interface */ - val = ehci_readl(ehci, (u32 *)statreg); - val = val & ~USB_EHCI_REG_BIT_STAT_STS; - ehci_writel(ehci, val, (u32 *)statreg); - - /* write to set the proper fifo threshold */ - ehci_writel(ehci, USB_CTRL_FIFO_THRESH, (u32 *)fiforeg); - - /* set TWI GPIO USB_HOST_DEV pin high */ - gpio_direction_output(MSP_PIN_USB0_HOST_DEV, 1); -#ifdef CONFIG_MSP_HAS_DUAL_USB - gpio_direction_output(MSP_PIN_USB1_HOST_DEV, 1); -#endif -} - -/* called during probe() after chip reset completes */ -static int ehci_msp_setup(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; - ehci->big_endian_mmio = 1; - ehci->big_endian_desc = 1; - - ehci->caps = hcd->regs; - ehci->regs = hcd->regs + - HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); - dbg_hcs_params(ehci, "reset"); - dbg_hcc_params(ehci, "reset"); - - /* cache this readonly data; minimize chip reads */ - ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); - hcd->has_tt = 1; - - retval = ehci_halt(ehci); - if (retval) - return retval; - - ehci_reset(ehci); - - /* data structure init */ - retval = ehci_init(hcd); - if (retval) - return retval; - - usb_hcd_tdi_set_mode(ehci); - ehci_port_power(ehci, 0); - - return retval; -} - - -/* configure so an HC device and id are always provided - * always called with process context; sleeping is OK - */ - -static int usb_hcd_msp_map_regs(struct mspusb_device *dev) -{ - struct resource *res; - struct platform_device *pdev = &dev->dev; - u32 res_len; - int retval; - - /* MAB register space */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (res == NULL) - return -ENOMEM; - res_len = resource_size(res); - if (!request_mem_region(res->start, res_len, "mab regs")) - return -EBUSY; - - dev->mab_regs = ioremap_nocache(res->start, res_len); - if (dev->mab_regs == NULL) { - retval = -ENOMEM; - goto err1; - } - - /* MSP USB register space */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 2); - if (res == NULL) { - retval = -ENOMEM; - goto err2; - } - res_len = resource_size(res); - if (!request_mem_region(res->start, res_len, "usbid regs")) { - retval = -EBUSY; - goto err2; - } - dev->usbid_regs = ioremap_nocache(res->start, res_len); - if (dev->usbid_regs == NULL) { - retval = -ENOMEM; - goto err3; - } - - return 0; -err3: - res = platform_get_resource(pdev, IORESOURCE_MEM, 2); - res_len = resource_size(res); - release_mem_region(res->start, res_len); -err2: - iounmap(dev->mab_regs); -err1: - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - res_len = resource_size(res); - release_mem_region(res->start, res_len); - dev_err(&pdev->dev, "Failed to map non-EHCI regs.\n"); - return retval; -} - -/** - * usb_hcd_msp_probe - initialize PMC MSP-based HCDs - * Context: !in_interrupt() - * - * Allocates basic resources for this USB host controller, and - * then invokes the start() method for the HCD associated with it - * through the hotplug entry's driver_data. - * - */ -int usb_hcd_msp_probe(const struct hc_driver *driver, - struct platform_device *dev) -{ - int retval; - struct usb_hcd *hcd; - struct resource *res; - struct ehci_hcd *ehci ; - - hcd = usb_create_hcd(driver, &dev->dev, "pmcmsp"); - if (!hcd) - return -ENOMEM; - - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (res == NULL) { - pr_debug("No IOMEM resource info for %s.\n", dev->name); - retval = -ENOMEM; - goto err1; - } - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, dev->name)) { - retval = -EBUSY; - goto err1; - } - hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - pr_debug("ioremap failed"); - retval = -ENOMEM; - goto err2; - } - - res = platform_get_resource(dev, IORESOURCE_IRQ, 0); - if (res == NULL) { - dev_err(&dev->dev, "No IRQ resource info for %s.\n", dev->name); - retval = -ENOMEM; - goto err3; - } - - /* Map non-EHCI register spaces */ - retval = usb_hcd_msp_map_regs(to_mspusb_device(dev)); - if (retval != 0) - goto err3; - - ehci = hcd_to_ehci(hcd); - ehci->big_endian_mmio = 1; - ehci->big_endian_desc = 1; - - - retval = usb_add_hcd(hcd, res->start, IRQF_SHARED); - if (retval == 0) - return 0; - - usb_remove_hcd(hcd); -err3: - iounmap(hcd->regs); -err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err1: - usb_put_hcd(hcd); - - return retval; -} - - - -/** - * usb_hcd_msp_remove - shutdown processing for PMC MSP-based HCDs - * @dev: USB Host Controller being removed - * Context: !in_interrupt() - * - * Reverses the effect of usb_hcd_msp_probe(), first invoking - * the HCD's stop() method. It is always called from a thread - * context, normally "rmmod", "apmd", or something similar. - * - * may be called without controller electrically present - * may be called with controller, bus, and devices active - */ -void usb_hcd_msp_remove(struct usb_hcd *hcd, struct platform_device *dev) -{ - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); -} - -#ifdef CONFIG_MSP_HAS_DUAL_USB -/* - * Wrapper around the main ehci_irq. Since both USB host controllers are - * sharing the same IRQ, need to first determine whether we're the intended - * recipient of this interrupt. - */ -static irqreturn_t ehci_msp_irq(struct usb_hcd *hcd) -{ - u32 int_src; - struct device *dev = hcd->self.controller; - struct platform_device *pdev; - struct mspusb_device *mdev; - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - /* need to reverse-map a couple of containers to get our device */ - pdev = to_platform_device(dev); - mdev = to_mspusb_device(pdev); - - /* Check to see if this interrupt is for this host controller */ - int_src = ehci_readl(ehci, &mdev->mab_regs->int_stat); - if (int_src & (1 << pdev->id)) - return ehci_irq(hcd); - - /* Not for this device */ - return IRQ_NONE; -} -#endif /* DUAL_USB */ - -static const struct hc_driver ehci_msp_hc_driver = { - .description = hcd_name, - .product_desc = "PMC MSP EHCI", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ -#ifdef CONFIG_MSP_HAS_DUAL_USB - .irq = ehci_msp_irq, -#else - .irq = ehci_irq, -#endif - .flags = HCD_MEMORY | HCD_USB2, - - /* - * basic lifecycle operations - */ - .reset = ehci_msp_setup, - .start = ehci_run, - .shutdown = ehci_shutdown, - .start = ehci_run, - .stop = ehci_stop, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static int ehci_hcd_msp_drv_probe(struct platform_device *pdev) -{ - int ret; - - pr_debug("In ehci_hcd_msp_drv_probe"); - - if (usb_disabled()) - return -ENODEV; - - gpio_request(MSP_PIN_USB0_HOST_DEV, "USB0_HOST_DEV_GPIO"); -#ifdef CONFIG_MSP_HAS_DUAL_USB - gpio_request(MSP_PIN_USB1_HOST_DEV, "USB1_HOST_DEV_GPIO"); -#endif - - ret = usb_hcd_msp_probe(&ehci_msp_hc_driver, pdev); - - return ret; -} - -static int ehci_hcd_msp_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_hcd_msp_remove(hcd, pdev); - - /* free TWI GPIO USB_HOST_DEV pin */ - gpio_free(MSP_PIN_USB0_HOST_DEV); -#ifdef CONFIG_MSP_HAS_DUAL_USB - gpio_free(MSP_PIN_USB1_HOST_DEV); -#endif - - return 0; -} - -MODULE_ALIAS("pmcmsp-ehci"); - -static struct platform_driver ehci_hcd_msp_driver = { - .probe = ehci_hcd_msp_drv_probe, - .remove = ehci_hcd_msp_drv_remove, - .driver = { - .name = "pmcmsp-ehci", - .owner = THIS_MODULE, - }, -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-ppc-of.c b/ANDROID_3.4.5/drivers/usb/host/ehci-ppc-of.c deleted file mode 100644 index 41d11fe1..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-ppc-of.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * EHCI HCD (Host Controller Driver) for USB. - * - * Bus Glue for PPC On-Chip EHCI driver on the of_platform bus - * Tested on AMCC PPC 440EPx - * - * Valentine Barshak - * - * Based on "ehci-ppc-soc.c" by Stefan Roese - * and "ohci-ppc-of.c" by Sylvain Munaut - * - * This file is licenced under the GPL. - */ - -#include - -#include -#include - -/* called during probe() after chip reset completes */ -static int ehci_ppc_of_setup(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; - - retval = ehci_halt(ehci); - if (retval) - return retval; - - retval = ehci_init(hcd); - if (retval) - return retval; - - ehci->sbrn = 0x20; - return ehci_reset(ehci); -} - - -static const struct hc_driver ehci_ppc_of_hc_driver = { - .description = hcd_name, - .product_desc = "OF EHCI", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* - * basic lifecycle operations - */ - .reset = ehci_ppc_of_setup, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, -#endif - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - - -/* - * 440EPx Errata USBH_3 - * Fix: Enable Break Memory Transfer (BMT) in INSNREG3 - */ -#define PPC440EPX_EHCI0_INSREG_BMT (0x1 << 0) -static int __devinit -ppc44x_enable_bmt(struct device_node *dn) -{ - __iomem u32 *insreg_virt; - - insreg_virt = of_iomap(dn, 1); - if (!insreg_virt) - return -EINVAL; - - out_be32(insreg_virt + 3, PPC440EPX_EHCI0_INSREG_BMT); - - iounmap(insreg_virt); - return 0; -} - - -static int __devinit ehci_hcd_ppc_of_probe(struct platform_device *op) -{ - struct device_node *dn = op->dev.of_node; - struct usb_hcd *hcd; - struct ehci_hcd *ehci = NULL; - struct resource res; - int irq; - int rv; - - struct device_node *np; - - if (usb_disabled()) - return -ENODEV; - - dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n"); - - rv = of_address_to_resource(dn, 0, &res); - if (rv) - return rv; - - hcd = usb_create_hcd(&ehci_ppc_of_hc_driver, &op->dev, "PPC-OF USB"); - if (!hcd) - return -ENOMEM; - - hcd->rsrc_start = res.start; - hcd->rsrc_len = resource_size(&res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__); - rv = -EBUSY; - goto err_rmr; - } - - irq = irq_of_parse_and_map(dn, 0); - if (irq == NO_IRQ) { - printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__); - rv = -EBUSY; - goto err_irq; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - printk(KERN_ERR "%s: ioremap failed\n", __FILE__); - rv = -ENOMEM; - goto err_ioremap; - } - - ehci = hcd_to_ehci(hcd); - np = of_find_compatible_node(NULL, NULL, "ibm,usb-ohci-440epx"); - if (np != NULL) { - /* claim we really affected by usb23 erratum */ - if (!of_address_to_resource(np, 0, &res)) - ehci->ohci_hcctrl_reg = ioremap(res.start + - OHCI_HCCTRL_OFFSET, OHCI_HCCTRL_LEN); - else - pr_debug("%s: no ohci offset in fdt\n", __FILE__); - if (!ehci->ohci_hcctrl_reg) { - pr_debug("%s: ioremap for ohci hcctrl failed\n", __FILE__); - } else { - ehci->has_amcc_usb23 = 1; - } - } - - if (of_get_property(dn, "big-endian", NULL)) { - ehci->big_endian_mmio = 1; - ehci->big_endian_desc = 1; - } - if (of_get_property(dn, "big-endian-regs", NULL)) - ehci->big_endian_mmio = 1; - if (of_get_property(dn, "big-endian-desc", NULL)) - ehci->big_endian_desc = 1; - - ehci->caps = hcd->regs; - ehci->regs = hcd->regs + - HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); - - /* cache this readonly data; minimize chip reads */ - ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); - - if (of_device_is_compatible(dn, "ibm,usb-ehci-440epx")) { - rv = ppc44x_enable_bmt(dn); - ehci_dbg(ehci, "Break Memory Transfer (BMT) is %senabled!\n", - rv ? "NOT ": ""); - } - - rv = usb_add_hcd(hcd, irq, 0); - if (rv) - goto err_ehci; - - return 0; - -err_ehci: - if (ehci->has_amcc_usb23) - iounmap(ehci->ohci_hcctrl_reg); - iounmap(hcd->regs); -err_ioremap: - irq_dispose_mapping(irq); -err_irq: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err_rmr: - usb_put_hcd(hcd); - - return rv; -} - - -static int ehci_hcd_ppc_of_remove(struct platform_device *op) -{ - struct usb_hcd *hcd = dev_get_drvdata(&op->dev); - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - - struct device_node *np; - struct resource res; - - dev_set_drvdata(&op->dev, NULL); - - dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n"); - - usb_remove_hcd(hcd); - - iounmap(hcd->regs); - irq_dispose_mapping(hcd->irq); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - - /* use request_mem_region to test if the ohci driver is loaded. if so - * ensure the ohci core is operational. - */ - if (ehci->has_amcc_usb23) { - np = of_find_compatible_node(NULL, NULL, "ibm,usb-ohci-440epx"); - if (np != NULL) { - if (!of_address_to_resource(np, 0, &res)) - if (!request_mem_region(res.start, - 0x4, hcd_name)) - set_ohci_hcfs(ehci, 1); - else - release_mem_region(res.start, 0x4); - else - pr_debug("%s: no ohci offset in fdt\n", __FILE__); - of_node_put(np); - } - - iounmap(ehci->ohci_hcctrl_reg); - } - usb_put_hcd(hcd); - - return 0; -} - - -static void ehci_hcd_ppc_of_shutdown(struct platform_device *op) -{ - struct usb_hcd *hcd = dev_get_drvdata(&op->dev); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - - -static const struct of_device_id ehci_hcd_ppc_of_match[] = { - { - .compatible = "usb-ehci", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, ehci_hcd_ppc_of_match); - - -static struct platform_driver ehci_hcd_ppc_of_driver = { - .probe = ehci_hcd_ppc_of_probe, - .remove = ehci_hcd_ppc_of_remove, - .shutdown = ehci_hcd_ppc_of_shutdown, - .driver = { - .name = "ppc-of-ehci", - .owner = THIS_MODULE, - .of_match_table = ehci_hcd_ppc_of_match, - }, -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-ps3.c b/ANDROID_3.4.5/drivers/usb/host/ehci-ps3.c deleted file mode 100644 index a20e496e..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-ps3.c +++ /dev/null @@ -1,282 +0,0 @@ -/* - * PS3 EHCI Host Controller driver - * - * Copyright (C) 2006 Sony Computer Entertainment Inc. - * Copyright 2006 Sony Corp. - * - * 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; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include - -static void ps3_ehci_setup_insnreg(struct ehci_hcd *ehci) -{ - /* PS3 HC internal setup register offsets. */ - - enum ps3_ehci_hc_insnreg { - ps3_ehci_hc_insnreg01 = 0x084, - ps3_ehci_hc_insnreg02 = 0x088, - ps3_ehci_hc_insnreg03 = 0x08c, - }; - - /* PS3 EHCI HC errata fix 316 - The PS3 EHCI HC will reset its - * internal INSNREGXX setup regs back to the chip default values - * on Host Controller Reset (CMD_RESET) or Light Host Controller - * Reset (CMD_LRESET). The work-around for this is for the HC - * driver to re-initialise these regs when ever the HC is reset. - */ - - /* Set burst transfer counts to 256 out, 32 in. */ - - writel_be(0x01000020, (void __iomem *)ehci->regs + - ps3_ehci_hc_insnreg01); - - /* Enable burst transfer counts. */ - - writel_be(0x00000001, (void __iomem *)ehci->regs + - ps3_ehci_hc_insnreg03); -} - -static int ps3_ehci_hc_reset(struct usb_hcd *hcd) -{ - int result; - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - - ehci->big_endian_mmio = 1; - - ehci->caps = hcd->regs; - ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci, - &ehci->caps->hc_capbase)); - - dbg_hcs_params(ehci, "reset"); - dbg_hcc_params(ehci, "reset"); - - ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); - - result = ehci_halt(ehci); - - if (result) - return result; - - result = ehci_init(hcd); - - if (result) - return result; - - ehci_reset(ehci); - - ps3_ehci_setup_insnreg(ehci); - - return result; -} - -static const struct hc_driver ps3_ehci_hc_driver = { - .description = hcd_name, - .product_desc = "PS3 EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - .reset = ps3_ehci_hc_reset, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - .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, -#if defined(CONFIG_PM) - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, -#endif - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static int __devinit ps3_ehci_probe(struct ps3_system_bus_device *dev) -{ - int result; - struct usb_hcd *hcd; - unsigned int virq; - static u64 dummy_mask = DMA_BIT_MASK(32); - - if (usb_disabled()) { - result = -ENODEV; - goto fail_start; - } - - result = ps3_open_hv_device(dev); - - if (result) { - dev_dbg(&dev->core, "%s:%d: ps3_open_hv_device failed\n", - __func__, __LINE__); - goto fail_open; - } - - result = ps3_dma_region_create(dev->d_region); - - if (result) { - dev_dbg(&dev->core, "%s:%d: ps3_dma_region_create failed: " - "(%d)\n", __func__, __LINE__, result); - BUG_ON("check region type"); - goto fail_dma_region; - } - - result = ps3_mmio_region_create(dev->m_region); - - if (result) { - dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n", - __func__, __LINE__); - result = -EPERM; - goto fail_mmio_region; - } - - dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__, - __LINE__, dev->m_region->lpar_addr); - - result = ps3_io_irq_setup(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq); - - if (result) { - dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n", - __func__, __LINE__, virq); - result = -EPERM; - goto fail_irq; - } - - dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */ - - hcd = usb_create_hcd(&ps3_ehci_hc_driver, &dev->core, dev_name(&dev->core)); - - if (!hcd) { - dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__, - __LINE__); - result = -ENOMEM; - goto fail_create_hcd; - } - - hcd->rsrc_start = dev->m_region->lpar_addr; - hcd->rsrc_len = dev->m_region->len; - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) - dev_dbg(&dev->core, "%s:%d: request_mem_region failed\n", - __func__, __LINE__); - - hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len); - - if (!hcd->regs) { - dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__, - __LINE__); - result = -EPERM; - goto fail_ioremap; - } - - dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__, - (unsigned long)hcd->rsrc_start); - dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len %lxh\n", __func__, __LINE__, - (unsigned long)hcd->rsrc_len); - dev_dbg(&dev->core, "%s:%d: hcd->regs %lxh\n", __func__, __LINE__, - (unsigned long)hcd->regs); - dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__, - (unsigned long)virq); - - ps3_system_bus_set_drvdata(dev, hcd); - - result = usb_add_hcd(hcd, virq, 0); - - if (result) { - dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n", - __func__, __LINE__, result); - goto fail_add_hcd; - } - - return result; - -fail_add_hcd: - iounmap(hcd->regs); -fail_ioremap: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); -fail_create_hcd: - ps3_io_irq_destroy(virq); -fail_irq: - ps3_free_mmio_region(dev->m_region); -fail_mmio_region: - ps3_dma_region_free(dev->d_region); -fail_dma_region: - ps3_close_hv_device(dev); -fail_open: -fail_start: - return result; -} - -static int ps3_ehci_remove(struct ps3_system_bus_device *dev) -{ - unsigned int tmp; - struct usb_hcd *hcd = ps3_system_bus_get_drvdata(dev); - - BUG_ON(!hcd); - - dev_dbg(&dev->core, "%s:%d: regs %p\n", __func__, __LINE__, hcd->regs); - dev_dbg(&dev->core, "%s:%d: irq %u\n", __func__, __LINE__, hcd->irq); - - tmp = hcd->irq; - - ehci_shutdown(hcd); - usb_remove_hcd(hcd); - - ps3_system_bus_set_drvdata(dev, NULL); - - BUG_ON(!hcd->regs); - iounmap(hcd->regs); - - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - - ps3_io_irq_destroy(tmp); - ps3_free_mmio_region(dev->m_region); - - ps3_dma_region_free(dev->d_region); - ps3_close_hv_device(dev); - - return 0; -} - -static int __init ps3_ehci_driver_register(struct ps3_system_bus_driver *drv) -{ - return firmware_has_feature(FW_FEATURE_PS3_LV1) - ? ps3_system_bus_driver_register(drv) - : 0; -} - -static void ps3_ehci_driver_unregister(struct ps3_system_bus_driver *drv) -{ - if (firmware_has_feature(FW_FEATURE_PS3_LV1)) - ps3_system_bus_driver_unregister(drv); -} - -MODULE_ALIAS(PS3_MODULE_ALIAS_EHCI); - -static struct ps3_system_bus_driver ps3_ehci_driver = { - .core.name = "ps3-ehci-driver", - .core.owner = THIS_MODULE, - .match_id = PS3_MATCH_ID_EHCI, - .probe = ps3_ehci_probe, - .remove = ps3_ehci_remove, - .shutdown = ps3_ehci_remove, -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-q.c b/ANDROID_3.4.5/drivers/usb/host/ehci-q.c deleted file mode 100644 index 9e11e38a..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-q.c +++ /dev/null @@ -1,1321 +0,0 @@ -/* - * Copyright (C) 2001-2004 by David Brownell - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* this file is part of ehci-hcd.c */ - -/*-------------------------------------------------------------------------*/ - -/* - * EHCI hardware queue manipulation ... the core. QH/QTD manipulation. - * - * Control, bulk, and interrupt traffic all use "qh" lists. They list "qtd" - * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned - * buffers needed for the larger number). We use one QH per endpoint, queue - * multiple urbs (all three types) per endpoint. URBs may need several qtds. - * - * ISO traffic uses "ISO TD" (itd, and sitd) records, and (along with - * interrupts) needs careful scheduling. Performance improvements can be - * an ongoing challenge. That's in "ehci-sched.c". - * - * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs, - * or otherwise through transaction translators (TTs) in USB 2.0 hubs using - * (b) special fields in qh entries or (c) split iso entries. TTs will - * buffer low/full speed data so the host collects it at high speed. - */ - -/*-------------------------------------------------------------------------*/ - -/* fill a qtd, returning how much of the buffer we were able to queue up */ - -static int -qtd_fill(struct ehci_hcd *ehci, struct ehci_qtd *qtd, dma_addr_t buf, - size_t len, int token, int maxpacket) -{ - int i, count; - u64 addr = buf; - - /* one buffer entry per 4K ... first might be short or unaligned */ - qtd->hw_buf[0] = cpu_to_hc32(ehci, (u32)addr); - qtd->hw_buf_hi[0] = cpu_to_hc32(ehci, (u32)(addr >> 32)); - count = 0x1000 - (buf & 0x0fff); /* rest of that page */ - if (likely (len < count)) /* ... iff needed */ - count = len; - else { - buf += 0x1000; - buf &= ~0x0fff; - - /* per-qtd limit: from 16K to 20K (best alignment) */ - for (i = 1; count < len && i < 5; i++) { - addr = buf; - qtd->hw_buf[i] = cpu_to_hc32(ehci, (u32)addr); - qtd->hw_buf_hi[i] = cpu_to_hc32(ehci, - (u32)(addr >> 32)); - buf += 0x1000; - if ((count + 0x1000) < len) - count += 0x1000; - else - count = len; - } - - /* short packets may only terminate transfers */ - if (count != len) - count -= (count % maxpacket); - } - qtd->hw_token = cpu_to_hc32(ehci, (count << 16) | token); - qtd->length = count; - - return count; -} - -/*-------------------------------------------------------------------------*/ - -static inline void -qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd) -{ - struct ehci_qh_hw *hw = qh->hw; - - /* writes to an active overlay are unsafe */ - BUG_ON(qh->qh_state != QH_STATE_IDLE); - - hw->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma); - hw->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 (!(hw->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) { - unsigned is_out, epnum; - - is_out = qh->is_out; - epnum = (hc32_to_cpup(ehci, &hw->hw_info1) >> 8) & 0x0f; - if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) { - hw->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE); - usb_settoggle (qh->dev, epnum, is_out, 1); - } - } - - hw->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING); -} - -/* if it weren't for a common silicon quirk (writing the dummy into the qh - * overlay, so qh->hw_token wrongly becomes inactive/halted), only fault - * recovery (including urb dequeue) would need software changes to a QH... - */ -static void -qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh) -{ - struct ehci_qtd *qtd; - - if (list_empty (&qh->qtd_list)) - qtd = qh->dummy; - else { - qtd = list_entry (qh->qtd_list.next, - struct ehci_qtd, qtd_list); - /* first qtd may already be partially processed */ - if (cpu_to_hc32(ehci, qtd->qtd_dma) == qh->hw->hw_current) - qtd = NULL; - } - - if (qtd) - qh_update (ehci, qh, qtd); -} - -/*-------------------------------------------------------------------------*/ - -static void qh_link_async(struct ehci_hcd *ehci, struct ehci_qh *qh); - -static void ehci_clear_tt_buffer_complete(struct usb_hcd *hcd, - struct usb_host_endpoint *ep) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - struct ehci_qh *qh = ep->hcpriv; - unsigned long flags; - - spin_lock_irqsave(&ehci->lock, flags); - qh->clearing_tt = 0; - if (qh->qh_state == QH_STATE_IDLE && !list_empty(&qh->qtd_list) - && ehci->rh_state == EHCI_RH_RUNNING) - qh_link_async(ehci, qh); - spin_unlock_irqrestore(&ehci->lock, flags); -} - -static void ehci_clear_tt_buffer(struct ehci_hcd *ehci, struct ehci_qh *qh, - struct urb *urb, u32 token) -{ - - /* If an async split transaction gets an error or is unlinked, - * the TT buffer may be left in an indeterminate state. We - * have to clear the TT buffer. - * - * Note: this routine is never called for Isochronous transfers. - */ - if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) { -#ifdef DEBUG - struct usb_device *tt = urb->dev->tt->hub; - dev_dbg(&tt->dev, - "clear tt buffer port %d, a%d ep%d t%08x\n", - urb->dev->ttport, urb->dev->devnum, - usb_pipeendpoint(urb->pipe), token); -#endif /* DEBUG */ - if (!ehci_is_TDI(ehci) - || urb->dev->tt->hub != - ehci_to_hcd(ehci)->self.root_hub) { - if (usb_hub_clear_tt_buffer(urb) == 0) - qh->clearing_tt = 1; - } else { - - /* REVISIT ARC-derived cores don't clear the root - * hub TT buffer in this way... - */ - } - } -} - -static int qtd_copy_status ( - struct ehci_hcd *ehci, - struct urb *urb, - size_t length, - u32 token -) -{ - int status = -EINPROGRESS; - - /* count IN/OUT bytes, not SETUP (even short packets) */ - if (likely (QTD_PID (token) != 2)) - urb->actual_length += length - QTD_LENGTH (token); - - /* don't modify error codes */ - if (unlikely(urb->unlinked)) - return status; - - /* force cleanup after short read; not always an error */ - if (unlikely (IS_SHORT_READ (token))) - status = -EREMOTEIO; - - /* serious "can't proceed" faults reported by the hardware */ - if (token & QTD_STS_HALT) { - if (token & QTD_STS_BABBLE) { - /* FIXME "must" disable babbling device's port too */ - status = -EOVERFLOW; - /* CERR nonzero + halt --> stall */ - } else if (QTD_CERR(token)) { - status = -EPIPE; - - /* In theory, more than one of the following bits can be set - * since they are sticky and the transaction is retried. - * Which to test first is rather arbitrary. - */ - } else if (token & QTD_STS_MMF) { - /* fs/ls interrupt xfer missed the complete-split */ - status = -EPROTO; - } else if (token & QTD_STS_DBE) { - status = (QTD_PID (token) == 1) /* IN ? */ - ? -ENOSR /* hc couldn't read data */ - : -ECOMM; /* hc couldn't write data */ - } else if (token & QTD_STS_XACT) { - /* timeout, bad CRC, wrong PID, etc */ - ehci_dbg(ehci, "devpath %s ep%d%s 3strikes\n", - urb->dev->devpath, - usb_pipeendpoint(urb->pipe), - usb_pipein(urb->pipe) ? "in" : "out"); - status = -EPROTO; - } else { /* unknown */ - status = -EPROTO; - } - - ehci_vdbg (ehci, - "dev%d ep%d%s qtd token %08x --> status %d\n", - usb_pipedevice (urb->pipe), - usb_pipeendpoint (urb->pipe), - usb_pipein (urb->pipe) ? "in" : "out", - token, status); - } - - return status; -} - -static void -ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status) -__releases(ehci->lock) -__acquires(ehci->lock) -{ - if (likely (urb->hcpriv != NULL)) { - struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv; - - /* S-mask in a QH means it's an interrupt urb */ - if ((qh->hw->hw_info2 & cpu_to_hc32(ehci, QH_SMASK)) != 0) { - - /* ... update hc-wide periodic stats (for usbfs) */ - ehci_to_hcd(ehci)->self.bandwidth_int_reqs--; - } - qh_put (qh); - } - - if (unlikely(urb->unlinked)) { - COUNT(ehci->stats.unlink); - } else { - /* report non-error and short read status as zero */ - if (status == -EINPROGRESS || status == -EREMOTEIO) - status = 0; - COUNT(ehci->stats.complete); - } - -#ifdef EHCI_URB_TRACE - ehci_dbg (ehci, - "%s %s urb %p ep%d%s status %d len %d/%d\n", - __func__, urb->dev->devpath, urb, - usb_pipeendpoint (urb->pipe), - usb_pipein (urb->pipe) ? "in" : "out", - status, - urb->actual_length, urb->transfer_buffer_length); -#endif - /*{CharlesTu, 2008.12.26, for test mode */ -#ifdef CONFIG_USB_EHCI_EHSET - if (likely(urb->transfer_flags == URB_HCD_DRIVER_TEST)) - return; -#endif - /*CharlesTu}*/ - /* complete() can reenter this HCD */ - usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); - spin_unlock (&ehci->lock); - usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status); - spin_lock (&ehci->lock); -} - -static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh); -static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh); - -static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh); - -/* - * Process and free completed qtds for a qh, returning URBs to drivers. - * Chases up to qh->hw_current. Returns number of completions called, - * indicating how much "real" work we did. - */ -static unsigned -qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) -{ - struct ehci_qtd *last, *end = qh->dummy; - struct list_head *entry, *tmp; - int last_status; - int stopped; - unsigned count = 0; - u8 state; - struct ehci_qh_hw *hw = qh->hw; - - if (unlikely (list_empty (&qh->qtd_list))) - return count; - - /* completions (or tasks on other cpus) must never clobber HALT - * till we've gone through and cleaned everything up, even when - * they add urbs to this qh's queue or mark them for unlinking. - * - * NOTE: unlinking expects to be done in queue order. - * - * It's a bug for qh->qh_state to be anything other than - * QH_STATE_IDLE, unless our caller is scan_async() or - * scan_periodic(). - */ - state = qh->qh_state; - qh->qh_state = QH_STATE_COMPLETING; - stopped = (state == QH_STATE_IDLE); - - rescan: - last = NULL; - last_status = -EINPROGRESS; - qh->needs_rescan = 0; - - /* remove de-activated QTDs from front of queue. - * after faults (including short reads), cleanup this urb - * then let the queue advance. - * if queue is stopped, handles unlinks. - */ - list_for_each_safe (entry, tmp, &qh->qtd_list) { - struct ehci_qtd *qtd; - struct urb *urb; - u32 token = 0; - - qtd = list_entry (entry, struct ehci_qtd, qtd_list); - urb = qtd->urb; - - /* clean up any state from previous QTD ...*/ - if (last) { - if (likely (last->urb != urb)) { - ehci_urb_done(ehci, last->urb, last_status); - count++; - last_status = -EINPROGRESS; - } - ehci_qtd_free (ehci, last); - last = NULL; - } - - /* ignore urbs submitted during completions we reported */ - if (qtd == end) - break; - - /* hardware copies qtd out of qh overlay */ - rmb (); - token = hc32_to_cpu(ehci, qtd->hw_token); - - /* always clean up qtds the hc de-activated */ - retry_xacterr: - if ((token & QTD_STS_ACTIVE) == 0) { - - /* Report Data Buffer Error: non-fatal but useful */ - if (token & QTD_STS_DBE) - ehci_dbg(ehci, - "detected DataBufferErr for urb %p ep%d%s len %d, qtd %p [qh %p]\n", - urb, - usb_endpoint_num(&urb->ep->desc), - usb_endpoint_dir_in(&urb->ep->desc) ? "in" : "out", - urb->transfer_buffer_length, - qtd, - qh); - - /* on STALL, error, and short reads this urb must - * complete and all its qtds must be recycled. - */ - if ((token & QTD_STS_HALT) != 0) { - - /* retry transaction errors until we - * reach the software xacterr limit - */ - if ((token & QTD_STS_XACT) && - QTD_CERR(token) == 0 && - ++qh->xacterrs < QH_XACTERR_MAX && - !urb->unlinked) { - ehci_dbg(ehci, - "detected XactErr len %zu/%zu retry %d\n", - qtd->length - QTD_LENGTH(token), qtd->length, qh->xacterrs); - - /* reset the token in the qtd and the - * qh overlay (which still contains - * the qtd) so that we pick up from - * where we left off - */ - token &= ~QTD_STS_HALT; - token |= QTD_STS_ACTIVE | - (EHCI_TUNE_CERR << 10); - qtd->hw_token = cpu_to_hc32(ehci, - token); - wmb(); - hw->hw_token = cpu_to_hc32(ehci, - token); - goto retry_xacterr; - } - stopped = 1; - - /* magic dummy for some short reads; qh won't advance. - * that silicon quirk can kick in with this dummy too. - * - * other short reads won't stop the queue, including - * control transfers (status stage handles that) or - * most other single-qtd reads ... the queue stops if - * URB_SHORT_NOT_OK was set so the driver submitting - * the urbs could clean it up. - */ - } else if (IS_SHORT_READ (token) - && !(qtd->hw_alt_next - & EHCI_LIST_END(ehci))) { - stopped = 1; - } - - /* stop scanning when we reach qtds the hc is using */ - } else if (likely (!stopped - && ehci->rh_state == EHCI_RH_RUNNING)) { - break; - - /* scan the whole queue for unlinks whenever it stops */ - } else { - stopped = 1; - - /* cancel everything if we halt, suspend, etc */ - if (ehci->rh_state != EHCI_RH_RUNNING) - last_status = -ESHUTDOWN; - - /* this qtd is active; skip it unless a previous qtd - * for its urb faulted, or its urb was canceled. - */ - else if (last_status == -EINPROGRESS && !urb->unlinked) - continue; - - /* qh unlinked; token in overlay may be most current */ - if (state == QH_STATE_IDLE - && cpu_to_hc32(ehci, qtd->qtd_dma) - == hw->hw_current) { - token = hc32_to_cpu(ehci, hw->hw_token); - - /* An unlink may leave an incomplete - * async transaction in the TT buffer. - * We have to clear it. - */ - ehci_clear_tt_buffer(ehci, qh, urb, token); - } - } - - /* unless we already know the urb's status, collect qtd status - * and update count of bytes transferred. in common short read - * cases with only one data qtd (including control transfers), - * queue processing won't halt. but with two or more qtds (for - * example, with a 32 KB transfer), when the first qtd gets a - * short read the second must be removed by hand. - */ - if (last_status == -EINPROGRESS) { - last_status = qtd_copy_status(ehci, urb, - qtd->length, token); - if (last_status == -EREMOTEIO - && (qtd->hw_alt_next - & EHCI_LIST_END(ehci))) - last_status = -EINPROGRESS; - - /* As part of low/full-speed endpoint-halt processing - * we must clear the TT buffer (11.17.5). - */ - if (unlikely(last_status != -EINPROGRESS && - last_status != -EREMOTEIO)) { - /* The TT's in some hubs malfunction when they - * receive this request following a STALL (they - * stop sending isochronous packets). Since a - * STALL can't leave the TT buffer in a busy - * state (if you believe Figures 11-48 - 11-51 - * in the USB 2.0 spec), we won't clear the TT - * buffer in this case. Strictly speaking this - * is a violation of the spec. - */ - if (last_status != -EPIPE) - ehci_clear_tt_buffer(ehci, qh, urb, - token); - } - } - - /* if we're removing something not at the queue head, - * patch the hardware queue pointer. - */ - if (stopped && qtd->qtd_list.prev != &qh->qtd_list) { - last = list_entry (qtd->qtd_list.prev, - struct ehci_qtd, qtd_list); - last->hw_next = qtd->hw_next; - } - - /* remove qtd; it's recycled after possible urb completion */ - list_del (&qtd->qtd_list); - last = qtd; - - /* reinit the xacterr counter for the next qtd */ - qh->xacterrs = 0; - } - - /* last urb's completion might still need calling */ - if (likely (last != NULL)) { - ehci_urb_done(ehci, last->urb, last_status); - count++; - ehci_qtd_free (ehci, last); - } - - /* Do we need to rescan for URBs dequeued during a giveback? */ - if (unlikely(qh->needs_rescan)) { - /* If the QH is already unlinked, do the rescan now. */ - if (state == QH_STATE_IDLE) - goto rescan; - - /* Otherwise we have to wait until the QH is fully unlinked. - * Our caller will start an unlink if qh->needs_rescan is - * set. But if an unlink has already started, nothing needs - * to be done. - */ - if (state != QH_STATE_LINKED) - qh->needs_rescan = 0; - } - - /* restore original state; caller must unlink or relink */ - qh->qh_state = state; - - /* be sure the hardware's done with the qh before refreshing - * it after fault cleanup, or recovering from silicon wrongly - * overlaying the dummy qtd (which reduces DMA chatter). - */ - if (stopped != 0 || hw->hw_qtd_next == EHCI_LIST_END(ehci)) { - switch (state) { - case QH_STATE_IDLE: - qh_refresh(ehci, qh); - break; - case QH_STATE_LINKED: - /* We won't refresh a QH that's linked (after the HC - * stopped the queue). That avoids a race: - * - HC reads first part of QH; - * - CPU updates that first part and the token; - * - HC reads rest of that QH, including token - * Result: HC gets an inconsistent image, and then - * DMAs to/from the wrong memory (corrupting it). - * - * That should be rare for interrupt transfers, - * except maybe high bandwidth ... - */ - - /* Tell the caller to start an unlink */ - qh->needs_rescan = 1; - break; - /* otherwise, unlink already started */ - } - } - - return count; -} - -/*-------------------------------------------------------------------------*/ - -// high bandwidth multiplier, as encoded in highspeed endpoint descriptors -#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) -// ... and packet size, for any kind of endpoint descriptor -#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff) - -/* - * reverse of qh_urb_transaction: free a list of TDs. - * used for cleanup after errors, before HC sees an URB's TDs. - */ -static void qtd_list_free ( - struct ehci_hcd *ehci, - struct urb *urb, - struct list_head *qtd_list -) { - struct list_head *entry, *temp; - - list_for_each_safe (entry, temp, qtd_list) { - struct ehci_qtd *qtd; - - qtd = list_entry (entry, struct ehci_qtd, qtd_list); - list_del (&qtd->qtd_list); - ehci_qtd_free (ehci, qtd); - } -} - -/* - * create a list of filled qtds for this URB; won't link into qh. - */ -static struct list_head * -qh_urb_transaction ( - struct ehci_hcd *ehci, - struct urb *urb, - struct list_head *head, - gfp_t flags -) { - struct ehci_qtd *qtd, *qtd_prev; - dma_addr_t buf; - int len, this_sg_len, maxpacket; - int is_input; - u32 token; - int i; - struct scatterlist *sg; - - /* - * URBs map to sequences of QTDs: one logical transaction - */ - qtd = ehci_qtd_alloc (ehci, flags); - if (unlikely (!qtd)) - return NULL; - list_add_tail (&qtd->qtd_list, head); - qtd->urb = urb; - - token = QTD_STS_ACTIVE; - token |= (EHCI_TUNE_CERR << 10); - /* for split transactions, SplitXState initialized to zero */ - - len = urb->transfer_buffer_length; - is_input = usb_pipein (urb->pipe); - if (usb_pipecontrol (urb->pipe)) { - /* SETUP pid */ - qtd_fill(ehci, qtd, urb->setup_dma, - sizeof (struct usb_ctrlrequest), - token | (2 /* "setup" */ << 8), 8); - - /* ... and always at least one more pid */ - token ^= QTD_TOGGLE; - qtd_prev = qtd; - qtd = ehci_qtd_alloc (ehci, flags); - if (unlikely (!qtd)) - goto cleanup; - qtd->urb = urb; - qtd_prev->hw_next = QTD_NEXT(ehci, qtd->qtd_dma); - list_add_tail (&qtd->qtd_list, head); - - /* for zero length DATA stages, STATUS is always IN */ - if (len == 0) - token |= (1 /* "in" */ << 8); - } - - /* - * data transfer stage: buffer setup - */ - i = urb->num_mapped_sgs; - if (len > 0 && i > 0) { - sg = urb->sg; - buf = sg_dma_address(sg); - - /* urb->transfer_buffer_length may be smaller than the - * size of the scatterlist (or vice versa) - */ - this_sg_len = min_t(int, sg_dma_len(sg), len); - } else { - sg = NULL; - buf = urb->transfer_dma; - this_sg_len = len; - } - - if (is_input) - token |= (1 /* "in" */ << 8); - /* else it's already initted to "out" pid (0 << 8) */ - - maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input)); - - /* - * buffer gets wrapped in one or more qtds; - * last one may be "short" (including zero len) - * and may serve as a control status ack - */ - for (;;) { - int this_qtd_len; - - this_qtd_len = qtd_fill(ehci, qtd, buf, this_sg_len, token, - maxpacket); - this_sg_len -= this_qtd_len; - len -= this_qtd_len; - buf += this_qtd_len; - - /* - * short reads advance to a "magic" dummy instead of the next - * qtd ... that forces the queue to stop, for manual cleanup. - * (this will usually be overridden later.) - */ - if (is_input) - qtd->hw_alt_next = ehci->async->hw->hw_alt_next; - - /* qh makes control packets use qtd toggle; maybe switch it */ - if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0) - token ^= QTD_TOGGLE; - - if (likely(this_sg_len <= 0)) { - if (--i <= 0 || len <= 0) - break; - sg = sg_next(sg); - buf = sg_dma_address(sg); - this_sg_len = min_t(int, sg_dma_len(sg), len); - } - - qtd_prev = qtd; - qtd = ehci_qtd_alloc (ehci, flags); - if (unlikely (!qtd)) - goto cleanup; - qtd->urb = urb; - qtd_prev->hw_next = QTD_NEXT(ehci, qtd->qtd_dma); - list_add_tail (&qtd->qtd_list, head); - } - - /* - * unless the caller requires manual cleanup after short reads, - * have the alt_next mechanism keep the queue running after the - * last data qtd (the only one, for control and most other cases). - */ - if (likely ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0 - || usb_pipecontrol (urb->pipe))) - qtd->hw_alt_next = EHCI_LIST_END(ehci); - - /* - * control requests may need a terminating data "status" ack; - * other OUT ones may need a terminating short packet - * (zero length). - */ - if (likely (urb->transfer_buffer_length != 0)) { - int one_more = 0; - - if (usb_pipecontrol (urb->pipe)) { - one_more = 1; - token ^= 0x0100; /* "in" <--> "out" */ - token |= QTD_TOGGLE; /* force DATA1 */ - } else if (usb_pipeout(urb->pipe) - && (urb->transfer_flags & URB_ZERO_PACKET) - && !(urb->transfer_buffer_length % maxpacket)) { - one_more = 1; - } - if (one_more) { - qtd_prev = qtd; - qtd = ehci_qtd_alloc (ehci, flags); - if (unlikely (!qtd)) - goto cleanup; - qtd->urb = urb; - qtd_prev->hw_next = QTD_NEXT(ehci, qtd->qtd_dma); - list_add_tail (&qtd->qtd_list, head); - - /* never any data in such packets */ - qtd_fill(ehci, qtd, 0, 0, token, 0); - } - } - - /* by default, enable interrupt on urb completion */ - if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT))) - qtd->hw_token |= cpu_to_hc32(ehci, QTD_IOC); - return head; - -cleanup: - qtd_list_free (ehci, urb, head); - return NULL; -} - -/*-------------------------------------------------------------------------*/ - -// Would be best to create all qh's from config descriptors, -// when each interface/altsetting is established. Unlink -// any previous qh and cancel its urbs first; endpoints are -// implicitly reset then (data toggle too). -// That'd mean updating how usbcore talks to HCDs. (2.7?) - - -/* - * Each QH holds a qtd list; a QH is used for everything except iso. - * - * For interrupt urbs, the scheduler must set the microframe scheduling - * mask(s) each time the QH gets scheduled. For highspeed, that's - * just one microframe in the s-mask. For split interrupt transactions - * there are additional complications: c-mask, maybe FSTNs. - */ -static struct ehci_qh * -qh_make ( - struct ehci_hcd *ehci, - struct urb *urb, - gfp_t flags -) { - struct ehci_qh *qh = ehci_qh_alloc (ehci, flags); - u32 info1 = 0, info2 = 0; - int is_input, type; - int maxp = 0; - struct usb_tt *tt = urb->dev->tt; - struct ehci_qh_hw *hw; - - if (!qh) - return qh; - - /* - * init endpoint/device data for this QH - */ - info1 |= usb_pipeendpoint (urb->pipe) << 8; - info1 |= usb_pipedevice (urb->pipe) << 0; - - is_input = usb_pipein (urb->pipe); - type = usb_pipetype (urb->pipe); - maxp = usb_maxpacket (urb->dev, urb->pipe, !is_input); - - /* 1024 byte maxpacket is a hardware ceiling. High bandwidth - * acts like up to 3KB, but is built from smaller packets. - */ - if (max_packet(maxp) > 1024) { - ehci_dbg(ehci, "bogus qh maxpacket %d\n", max_packet(maxp)); - goto done; - } - - /* Compute interrupt scheduling parameters just once, and save. - * - allowing for high bandwidth, how many nsec/uframe are used? - * - split transactions need a second CSPLIT uframe; same question - * - splits also need a schedule gap (for full/low speed I/O) - * - qh has a polling interval - * - * For control/bulk requests, the HC or TT handles these. - */ - if (type == PIPE_INTERRUPT) { - qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH, - is_input, 0, - hb_mult(maxp) * max_packet(maxp))); - qh->start = NO_FRAME; - qh->stamp = ehci->periodic_stamp; - - if (urb->dev->speed == USB_SPEED_HIGH) { - qh->c_usecs = 0; - qh->gap_uf = 0; - - qh->period = urb->interval >> 3; - if (qh->period == 0 && urb->interval != 1) { - /* NOTE interval 2 or 4 uframes could work. - * But interval 1 scheduling is simpler, and - * includes high bandwidth. - */ - urb->interval = 1; - } else if (qh->period > ehci->periodic_size) { - qh->period = ehci->periodic_size; - urb->interval = qh->period << 3; - } - } else { - int think_time; - - /* gap is f(FS/LS transfer times) */ - qh->gap_uf = 1 + usb_calc_bus_time (urb->dev->speed, - is_input, 0, maxp) / (125 * 1000); - - /* FIXME this just approximates SPLIT/CSPLIT times */ - if (is_input) { // SPLIT, gap, CSPLIT+DATA - qh->c_usecs = qh->usecs + HS_USECS (0); - qh->usecs = HS_USECS (1); - } else { // SPLIT+DATA, gap, CSPLIT - qh->usecs += HS_USECS (1); - qh->c_usecs = HS_USECS (0); - } - - think_time = tt ? tt->think_time : 0; - qh->tt_usecs = NS_TO_US (think_time + - usb_calc_bus_time (urb->dev->speed, - is_input, 0, max_packet (maxp))); - qh->period = urb->interval; - if (qh->period > ehci->periodic_size) { - qh->period = ehci->periodic_size; - urb->interval = qh->period; - } - } - } - - /* support for tt scheduling, and access to toggles */ - qh->dev = urb->dev; - - /* using TT? */ - switch (urb->dev->speed) { - case USB_SPEED_LOW: - info1 |= (1 << 12); /* EPS "low" */ - /* FALL THROUGH */ - - case USB_SPEED_FULL: - /* EPS 0 means "full" */ - if (type != PIPE_INTERRUPT) - info1 |= (EHCI_TUNE_RL_TT << 28); - if (type == PIPE_CONTROL) { - info1 |= (1 << 27); /* for TT */ - info1 |= 1 << 14; /* toggle from qtd */ - } - info1 |= maxp << 16; - - info2 |= (EHCI_TUNE_MULT_TT << 30); - - /* Some Freescale processors have an erratum in which the - * port number in the queue head was 0..N-1 instead of 1..N. - */ - if (ehci_has_fsl_portno_bug(ehci)) - info2 |= (urb->dev->ttport-1) << 23; - else - info2 |= urb->dev->ttport << 23; - - /* set the address of the TT; for TDI's integrated - * root hub tt, leave it zeroed. - */ - if (tt && tt->hub != ehci_to_hcd(ehci)->self.root_hub) - info2 |= tt->hub->devnum << 16; - - /* NOTE: if (PIPE_INTERRUPT) { scheduler sets c-mask } */ - - break; - - case USB_SPEED_HIGH: /* no TT involved */ - info1 |= (2 << 12); /* EPS "high" */ - if (type == PIPE_CONTROL) { - info1 |= (EHCI_TUNE_RL_HS << 28); - info1 |= 64 << 16; /* usb2 fixed maxpacket */ - info1 |= 1 << 14; /* toggle from qtd */ - info2 |= (EHCI_TUNE_MULT_HS << 30); - } else if (type == PIPE_BULK) { - info1 |= (EHCI_TUNE_RL_HS << 28); - /* The USB spec says that high speed bulk endpoints - * always use 512 byte maxpacket. But some device - * vendors decided to ignore that, and MSFT is happy - * to help them do so. So now people expect to use - * such nonconformant devices with Linux too; sigh. - */ - info1 |= max_packet(maxp) << 16; - info2 |= (EHCI_TUNE_MULT_HS << 30); - } else { /* PIPE_INTERRUPT */ - info1 |= max_packet (maxp) << 16; - info2 |= hb_mult (maxp) << 30; - } - break; - default: - dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed); -done: - qh_put (qh); - return NULL; - } - - /* NOTE: if (PIPE_INTERRUPT) { scheduler sets s-mask } */ - - /* init as live, toggle clear, advance to dummy */ - qh->qh_state = QH_STATE_IDLE; - hw = qh->hw; - hw->hw_info1 = cpu_to_hc32(ehci, info1); - hw->hw_info2 = cpu_to_hc32(ehci, info2); - qh->is_out = !is_input; - usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1); - qh_refresh (ehci, qh); - return qh; -} - -/*-------------------------------------------------------------------------*/ - -/* move qh (and its qtds) onto async queue; maybe enable queue. */ - -static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) -{ - __hc32 dma = QH_NEXT(ehci, qh->qh_dma); - struct ehci_qh *head; - - /* Don't link a QH if there's a Clear-TT-Buffer pending */ - if (unlikely(qh->clearing_tt)) - return; - - WARN_ON(qh->qh_state != QH_STATE_IDLE); - - /* (re)start the async schedule? */ - head = ehci->async; - timer_action_done (ehci, TIMER_ASYNC_OFF); - if (!head->qh_next.qh) { - u32 cmd = ehci_readl(ehci, &ehci->regs->command); - - if (!(cmd & CMD_ASE)) { - /* in case a clear of CMD_ASE didn't take yet */ - (void)handshake(ehci, &ehci->regs->status, - STS_ASS, 0, 150); - cmd |= CMD_ASE; - ehci_writel(ehci, cmd, &ehci->regs->command); - /* posted write need not be known to HC yet ... */ - } - } - - /* clear halt and/or toggle; and maybe recover from silicon quirk */ - qh_refresh(ehci, qh); - - /* splice right after start */ - qh->qh_next = head->qh_next; - qh->hw->hw_next = head->hw->hw_next; - wmb (); - - head->qh_next.qh = qh; - head->hw->hw_next = dma; - - qh_get(qh); - qh->xacterrs = 0; - qh->qh_state = QH_STATE_LINKED; - /* qtd completions reported later by interrupt */ -} - -/*-------------------------------------------------------------------------*/ - -/* - * For control/bulk/interrupt, return QH with these TDs appended. - * Allocates and initializes the QH if necessary. - * Returns null if it can't allocate a QH it needs to. - * If the QH has TDs (urbs) already, that's great. - */ -static struct ehci_qh *qh_append_tds ( - struct ehci_hcd *ehci, - struct urb *urb, - struct list_head *qtd_list, - int epnum, - void **ptr -) -{ - struct ehci_qh *qh = NULL; - __hc32 qh_addr_mask = cpu_to_hc32(ehci, 0x7f); - - qh = (struct ehci_qh *) *ptr; - if (unlikely (qh == NULL)) { - /* can't sleep here, we have ehci->lock... */ - qh = qh_make (ehci, urb, GFP_ATOMIC); - *ptr = qh; - } - if (likely (qh != NULL)) { - struct ehci_qtd *qtd; - - if (unlikely (list_empty (qtd_list))) - qtd = NULL; - else - qtd = list_entry (qtd_list->next, struct ehci_qtd, - qtd_list); - - /* control qh may need patching ... */ - if (unlikely (epnum == 0)) { - - /* usb_reset_device() briefly reverts to address 0 */ - if (usb_pipedevice (urb->pipe) == 0) - qh->hw->hw_info1 &= ~qh_addr_mask; - } - - /* just one way to queue requests: swap with the dummy qtd. - * only hc or qh_refresh() ever modify the overlay. - */ - if (likely (qtd != NULL)) { - struct ehci_qtd *dummy; - dma_addr_t dma; - __hc32 token; - - /* to avoid racing the HC, use the dummy td instead of - * the first td of our list (becomes new dummy). both - * tds stay deactivated until we're done, when the - * HC is allowed to fetch the old dummy (4.10.2). - */ - token = qtd->hw_token; - qtd->hw_token = HALT_BIT(ehci); - - dummy = qh->dummy; - - dma = dummy->qtd_dma; - *dummy = *qtd; - dummy->qtd_dma = dma; - - list_del (&qtd->qtd_list); - list_add (&dummy->qtd_list, qtd_list); - list_splice_tail(qtd_list, &qh->qtd_list); - - ehci_qtd_init(ehci, qtd, qtd->qtd_dma); - qh->dummy = qtd; - - /* hc must see the new dummy at list end */ - dma = qtd->qtd_dma; - qtd = list_entry (qh->qtd_list.prev, - struct ehci_qtd, qtd_list); - qtd->hw_next = QTD_NEXT(ehci, dma); - - /* let the hc process these next qtds */ - wmb (); - dummy->hw_token = token; - - urb->hcpriv = qh_get (qh); - } - } - return qh; -} - -/*-------------------------------------------------------------------------*/ - -static int -submit_async ( - struct ehci_hcd *ehci, - struct urb *urb, - struct list_head *qtd_list, - gfp_t mem_flags -) { - int epnum; - unsigned long flags; - struct ehci_qh *qh = NULL; - int rc; - - epnum = urb->ep->desc.bEndpointAddress; - -#ifdef EHCI_URB_TRACE - { - struct ehci_qtd *qtd; - qtd = list_entry(qtd_list->next, struct ehci_qtd, qtd_list); - ehci_dbg(ehci, - "%s %s urb %p ep%d%s len %d, qtd %p [qh %p]\n", - __func__, urb->dev->devpath, urb, - epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out", - urb->transfer_buffer_length, - qtd, urb->ep->hcpriv); - } -#endif - - spin_lock_irqsave (&ehci->lock, flags); - if (unlikely(!HCD_HW_ACCESSIBLE(ehci_to_hcd(ehci)))) { - rc = -ESHUTDOWN; - goto done; - } - rc = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb); - if (unlikely(rc)) - goto done; - - qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv); - if (unlikely(qh == NULL)) { - usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); - rc = -ENOMEM; - goto done; - } - - /* Control/bulk operations through TTs don't need scheduling, - * the HC and TT handle it when the TT has a buffer ready. - */ - if (likely (qh->qh_state == QH_STATE_IDLE)) - qh_link_async(ehci, qh); - done: - spin_unlock_irqrestore (&ehci->lock, flags); - if (unlikely (qh == NULL)) - qtd_list_free (ehci, urb, qtd_list); - return rc; -} - -/*-------------------------------------------------------------------------*/ - -/* the async qh for the qtds being reclaimed are now unlinked from the HC */ - -static void end_unlink_async (struct ehci_hcd *ehci) -{ - struct ehci_qh *qh = ehci->reclaim; - struct ehci_qh *next; - - iaa_watchdog_done(ehci); - - // qh->hw_next = cpu_to_hc32(qh->qh_dma); - qh->qh_state = QH_STATE_IDLE; - qh->qh_next.qh = NULL; - qh_put (qh); // refcount from reclaim - - /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */ - next = qh->reclaim; - ehci->reclaim = next; - qh->reclaim = NULL; - - qh_completions (ehci, qh); - - if (!list_empty(&qh->qtd_list) && ehci->rh_state == EHCI_RH_RUNNING) { - qh_link_async (ehci, qh); - } else { - /* it's not free to turn the async schedule on/off; leave it - * active but idle for a while once it empties. - */ - if (ehci->rh_state == EHCI_RH_RUNNING - && ehci->async->qh_next.qh == NULL) - timer_action (ehci, TIMER_ASYNC_OFF); - } - qh_put(qh); /* refcount from async list */ - - if (next) { - ehci->reclaim = NULL; - start_unlink_async (ehci, next); - } - - if (ehci->has_synopsys_hc_bug) - ehci_writel(ehci, (u32) ehci->async->qh_dma, - &ehci->regs->async_next); -} - -/* makes sure the async qh will become idle */ -/* caller must own ehci->lock */ - -static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) -{ - int cmd = ehci_readl(ehci, &ehci->regs->command); - struct ehci_qh *prev; - -#ifdef DEBUG - assert_spin_locked(&ehci->lock); - if (ehci->reclaim - || (qh->qh_state != QH_STATE_LINKED - && qh->qh_state != QH_STATE_UNLINK_WAIT) - ) - BUG (); -#endif - - /* stop async schedule right now? */ - if (unlikely (qh == ehci->async)) { - /* can't get here without STS_ASS set */ - if (ehci->rh_state != EHCI_RH_HALTED - && !ehci->reclaim) { - /* ... and CMD_IAAD clear */ - ehci_writel(ehci, cmd & ~CMD_ASE, - &ehci->regs->command); - wmb (); - // handshake later, if we need to - timer_action_done (ehci, TIMER_ASYNC_OFF); - } - return; - } - - qh->qh_state = QH_STATE_UNLINK; - ehci->reclaim = qh = qh_get (qh); - - prev = ehci->async; - while (prev->qh_next.qh != qh) - prev = prev->qh_next.qh; - - prev->hw->hw_next = qh->hw->hw_next; - prev->qh_next = qh->qh_next; - if (ehci->qh_scan_next == qh) - ehci->qh_scan_next = qh->qh_next.qh; - wmb (); - - /* If the controller isn't running, we don't have to wait for it */ - if (unlikely(ehci->rh_state != EHCI_RH_RUNNING)) { - /* if (unlikely (qh->reclaim != 0)) - * this will recurse, probably not much - */ - end_unlink_async (ehci); - return; - } - - cmd |= CMD_IAAD; - ehci_writel(ehci, cmd, &ehci->regs->command); - (void)ehci_readl(ehci, &ehci->regs->command); - iaa_watchdog_start(ehci); -} - -/*-------------------------------------------------------------------------*/ - -static void scan_async (struct ehci_hcd *ehci) -{ - bool stopped; - struct ehci_qh *qh; - enum ehci_timer_action action = TIMER_IO_WATCHDOG; - - timer_action_done (ehci, TIMER_ASYNC_SHRINK); - stopped = (ehci->rh_state != EHCI_RH_RUNNING); - - ehci->qh_scan_next = ehci->async->qh_next.qh; - while (ehci->qh_scan_next) { - qh = ehci->qh_scan_next; - ehci->qh_scan_next = qh->qh_next.qh; - rescan: - /* clean any finished work for this qh */ - if (!list_empty(&qh->qtd_list)) { - int temp; - - /* - * Unlinks could happen here; completion reporting - * drops the lock. That's why ehci->qh_scan_next - * always holds the next qh to scan; if the next qh - * gets unlinked then ehci->qh_scan_next is adjusted - * in start_unlink_async(). - */ - qh = qh_get(qh); - temp = qh_completions(ehci, qh); - if (qh->needs_rescan) - unlink_async(ehci, qh); - qh->unlink_time = jiffies + EHCI_SHRINK_JIFFIES; - qh_put(qh); - if (temp != 0) - goto rescan; - } - - /* unlink idle entries, reducing DMA usage as well - * as HCD schedule-scanning costs. delay for any qh - * we just scanned, there's a not-unusual case that it - * doesn't stay idle for long. - * (plus, avoids some kind of re-activation race.) - */ - if (list_empty(&qh->qtd_list) - && qh->qh_state == QH_STATE_LINKED) { - if (!ehci->reclaim && (stopped || - time_after_eq(jiffies, qh->unlink_time))) - start_unlink_async(ehci, qh); - else - action = TIMER_ASYNC_SHRINK; - } - } - if (action == TIMER_ASYNC_SHRINK) - timer_action (ehci, TIMER_ASYNC_SHRINK); -} diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-s5p.c b/ANDROID_3.4.5/drivers/usb/host/ehci-s5p.c deleted file mode 100644 index f098e2a2..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-s5p.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - * SAMSUNG S5P USB HOST EHCI Controller - * - * Copyright (C) 2011 Samsung Electronics Co.Ltd - * Author: Jingoo Han - * Author: Joonyoung Shim - * - * 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 -#include -#include -#include - -#define EHCI_INSNREG00(base) (base + 0x90) -#define EHCI_INSNREG00_ENA_INCR16 (0x1 << 25) -#define EHCI_INSNREG00_ENA_INCR8 (0x1 << 24) -#define EHCI_INSNREG00_ENA_INCR4 (0x1 << 23) -#define EHCI_INSNREG00_ENA_INCRX_ALIGN (0x1 << 22) -#define EHCI_INSNREG00_ENABLE_DMA_BURST \ - (EHCI_INSNREG00_ENA_INCR16 | EHCI_INSNREG00_ENA_INCR8 | \ - EHCI_INSNREG00_ENA_INCR4 | EHCI_INSNREG00_ENA_INCRX_ALIGN) - -struct s5p_ehci_hcd { - struct device *dev; - struct usb_hcd *hcd; - struct clk *clk; -}; - -static const struct hc_driver s5p_ehci_hc_driver = { - .description = hcd_name, - .product_desc = "S5P EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - .reset = ehci_init, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - .get_frame_number = ehci_get_frame, - - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static int __devinit s5p_ehci_probe(struct platform_device *pdev) -{ - struct s5p_ehci_platdata *pdata; - struct s5p_ehci_hcd *s5p_ehci; - struct usb_hcd *hcd; - struct ehci_hcd *ehci; - struct resource *res; - int irq; - int err; - - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "No platform data defined\n"); - return -EINVAL; - } - - s5p_ehci = kzalloc(sizeof(struct s5p_ehci_hcd), GFP_KERNEL); - if (!s5p_ehci) - return -ENOMEM; - - s5p_ehci->dev = &pdev->dev; - - hcd = usb_create_hcd(&s5p_ehci_hc_driver, &pdev->dev, - dev_name(&pdev->dev)); - if (!hcd) { - dev_err(&pdev->dev, "Unable to create HCD\n"); - err = -ENOMEM; - goto fail_hcd; - } - - s5p_ehci->hcd = hcd; - s5p_ehci->clk = clk_get(&pdev->dev, "usbhost"); - - if (IS_ERR(s5p_ehci->clk)) { - dev_err(&pdev->dev, "Failed to get usbhost clock\n"); - err = PTR_ERR(s5p_ehci->clk); - goto fail_clk; - } - - err = clk_enable(s5p_ehci->clk); - if (err) - goto fail_clken; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Failed to get I/O memory\n"); - err = -ENXIO; - goto fail_io; - } - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - hcd->regs = ioremap(res->start, resource_size(res)); - if (!hcd->regs) { - dev_err(&pdev->dev, "Failed to remap I/O memory\n"); - err = -ENOMEM; - goto fail_io; - } - - irq = platform_get_irq(pdev, 0); - if (!irq) { - dev_err(&pdev->dev, "Failed to get IRQ\n"); - err = -ENODEV; - goto fail; - } - - if (pdata->phy_init) - pdata->phy_init(pdev, S5P_USB_PHY_HOST); - - ehci = hcd_to_ehci(hcd); - ehci->caps = hcd->regs; - ehci->regs = hcd->regs + - HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase)); - - /* DMA burst Enable */ - writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs)); - - dbg_hcs_params(ehci, "reset"); - dbg_hcc_params(ehci, "reset"); - - /* cache this readonly data; minimize chip reads */ - ehci->hcs_params = readl(&ehci->caps->hcs_params); - - ehci_reset(ehci); - - err = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (err) { - dev_err(&pdev->dev, "Failed to add USB HCD\n"); - goto fail; - } - - platform_set_drvdata(pdev, s5p_ehci); - - return 0; - -fail: - iounmap(hcd->regs); -fail_io: - clk_disable(s5p_ehci->clk); -fail_clken: - clk_put(s5p_ehci->clk); -fail_clk: - usb_put_hcd(hcd); -fail_hcd: - kfree(s5p_ehci); - return err; -} - -static int __devexit s5p_ehci_remove(struct platform_device *pdev) -{ - struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; - struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev); - struct usb_hcd *hcd = s5p_ehci->hcd; - - usb_remove_hcd(hcd); - - if (pdata && pdata->phy_exit) - pdata->phy_exit(pdev, S5P_USB_PHY_HOST); - - iounmap(hcd->regs); - - clk_disable(s5p_ehci->clk); - clk_put(s5p_ehci->clk); - - usb_put_hcd(hcd); - kfree(s5p_ehci); - - return 0; -} - -static void s5p_ehci_shutdown(struct platform_device *pdev) -{ - struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev); - struct usb_hcd *hcd = s5p_ehci->hcd; - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - -#ifdef CONFIG_PM -static int s5p_ehci_suspend(struct device *dev) -{ - struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev); - struct usb_hcd *hcd = s5p_ehci->hcd; - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - struct platform_device *pdev = to_platform_device(dev); - struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; - unsigned long flags; - int rc = 0; - - if (time_before(jiffies, ehci->next_statechange)) - msleep(20); - - /* - * Root hub was already suspended. Disable irq emission and - * mark HW unaccessible. The PM and USB cores make sure that - * the root hub is either suspended or stopped. - */ - ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev)); - spin_lock_irqsave(&ehci->lock, flags); - ehci_writel(ehci, 0, &ehci->regs->intr_enable); - (void)ehci_readl(ehci, &ehci->regs->intr_enable); - - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - spin_unlock_irqrestore(&ehci->lock, flags); - - if (pdata && pdata->phy_exit) - pdata->phy_exit(pdev, S5P_USB_PHY_HOST); - - return rc; -} - -static int s5p_ehci_resume(struct device *dev) -{ - struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev); - struct usb_hcd *hcd = s5p_ehci->hcd; - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - struct platform_device *pdev = to_platform_device(dev); - struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; - - if (pdata && pdata->phy_init) - pdata->phy_init(pdev, S5P_USB_PHY_HOST); - - /* DMA burst Enable */ - writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs)); - - if (time_before(jiffies, ehci->next_statechange)) - msleep(100); - - /* Mark hardware accessible again as we are out of D3 state by now */ - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - - if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) { - int mask = INTR_MASK; - - ehci_prepare_ports_for_controller_resume(ehci); - if (!hcd->self.root_hub->do_remote_wakeup) - mask &= ~STS_PCD; - ehci_writel(ehci, mask, &ehci->regs->intr_enable); - ehci_readl(ehci, &ehci->regs->intr_enable); - return 0; - } - - usb_root_hub_lost_power(hcd->self.root_hub); - - (void) ehci_halt(ehci); - (void) ehci_reset(ehci); - - /* emptying the schedule aborts any urbs */ - spin_lock_irq(&ehci->lock); - if (ehci->reclaim) - end_unlink_async(ehci); - ehci_work(ehci); - spin_unlock_irq(&ehci->lock); - - ehci_writel(ehci, ehci->command, &ehci->regs->command); - ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); - ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ - - /* here we "know" root ports should always stay powered */ - ehci_port_power(ehci, 1); - - ehci->rh_state = EHCI_RH_SUSPENDED; - - return 0; -} -#else -#define s5p_ehci_suspend NULL -#define s5p_ehci_resume NULL -#endif - -static const struct dev_pm_ops s5p_ehci_pm_ops = { - .suspend = s5p_ehci_suspend, - .resume = s5p_ehci_resume, -}; - -static struct platform_driver s5p_ehci_driver = { - .probe = s5p_ehci_probe, - .remove = __devexit_p(s5p_ehci_remove), - .shutdown = s5p_ehci_shutdown, - .driver = { - .name = "s5p-ehci", - .owner = THIS_MODULE, - .pm = &s5p_ehci_pm_ops, - } -}; - -MODULE_ALIAS("platform:s5p-ehci"); diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-sched.c b/ANDROID_3.4.5/drivers/usb/host/ehci-sched.c deleted file mode 100644 index 757e3463..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-sched.c +++ /dev/null @@ -1,2502 +0,0 @@ -/* - * Copyright (c) 2001-2004 by David Brownell - * Copyright (c) 2003 Michal Sojka, for high-speed iso transfers - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* this file is part of ehci-hcd.c */ - -/*-------------------------------------------------------------------------*/ - -/* - * EHCI scheduled transaction support: interrupt, iso, split iso - * These are called "periodic" transactions in the EHCI spec. - * - * Note that for interrupt transfers, the QH/QTD manipulation is shared - * with the "asynchronous" transaction support (control/bulk transfers). - * The only real difference is in how interrupt transfers are scheduled. - * - * For ISO, we make an "iso_stream" head to serve the same role as a QH. - * It keeps track of every ITD (or SITD) that's linked, and holds enough - * pre-calculated schedule data to make appending to the queue be quick. - */ - -static int ehci_get_frame (struct usb_hcd *hcd); - -#ifdef CONFIG_PCI - -static unsigned ehci_read_frame_index(struct ehci_hcd *ehci) -{ - unsigned uf; - - /* - * The MosChip MCS9990 controller updates its microframe counter - * a little before the frame counter, and occasionally we will read - * the invalid intermediate value. Avoid problems by checking the - * microframe number (the low-order 3 bits); if they are 0 then - * re-read the register to get the correct value. - */ - uf = ehci_readl(ehci, &ehci->regs->frame_index); - if (unlikely(ehci->frame_index_bug && ((uf & 7) == 0))) - uf = ehci_readl(ehci, &ehci->regs->frame_index); - return uf; -} - -#endif - -/*-------------------------------------------------------------------------*/ - -/* - * periodic_next_shadow - return "next" pointer on shadow list - * @periodic: host pointer to qh/itd/sitd - * @tag: hardware tag for type of this record - */ -static union ehci_shadow * -periodic_next_shadow(struct ehci_hcd *ehci, union ehci_shadow *periodic, - __hc32 tag) -{ - switch (hc32_to_cpu(ehci, tag)) { - case Q_TYPE_QH: - return &periodic->qh->qh_next; - case Q_TYPE_FSTN: - return &periodic->fstn->fstn_next; - case Q_TYPE_ITD: - return &periodic->itd->itd_next; - // case Q_TYPE_SITD: - default: - return &periodic->sitd->sitd_next; - } -} - -static __hc32 * -shadow_next_periodic(struct ehci_hcd *ehci, union ehci_shadow *periodic, - __hc32 tag) -{ - switch (hc32_to_cpu(ehci, tag)) { - /* our ehci_shadow.qh is actually software part */ - case Q_TYPE_QH: - return &periodic->qh->hw->hw_next; - /* others are hw parts */ - default: - return periodic->hw_next; - } -} - -/* caller must hold ehci->lock */ -static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr) -{ - union ehci_shadow *prev_p = &ehci->pshadow[frame]; - __hc32 *hw_p = &ehci->periodic[frame]; - union ehci_shadow here = *prev_p; - - /* find predecessor of "ptr"; hw and shadow lists are in sync */ - while (here.ptr && here.ptr != ptr) { - prev_p = periodic_next_shadow(ehci, prev_p, - Q_NEXT_TYPE(ehci, *hw_p)); - hw_p = shadow_next_periodic(ehci, &here, - Q_NEXT_TYPE(ehci, *hw_p)); - here = *prev_p; - } - /* an interrupt entry (at list end) could have been shared */ - if (!here.ptr) - return; - - /* update shadow and hardware lists ... the old "next" pointers - * from ptr may still be in use, the caller updates them. - */ - *prev_p = *periodic_next_shadow(ehci, &here, - Q_NEXT_TYPE(ehci, *hw_p)); - - if (!ehci->use_dummy_qh || - *shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p)) - != EHCI_LIST_END(ehci)) - *hw_p = *shadow_next_periodic(ehci, &here, - Q_NEXT_TYPE(ehci, *hw_p)); - else - *hw_p = ehci->dummy->qh_dma; -} - -/* how many of the uframe's 125 usecs are allocated? */ -static unsigned short -periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) -{ - __hc32 *hw_p = &ehci->periodic [frame]; - union ehci_shadow *q = &ehci->pshadow [frame]; - unsigned usecs = 0; - struct ehci_qh_hw *hw; - - while (q->ptr) { - switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) { - case Q_TYPE_QH: - hw = q->qh->hw; - /* is it in the S-mask? */ - if (hw->hw_info2 & cpu_to_hc32(ehci, 1 << uframe)) - usecs += q->qh->usecs; - /* ... or C-mask? */ - if (hw->hw_info2 & cpu_to_hc32(ehci, - 1 << (8 + uframe))) - usecs += q->qh->c_usecs; - hw_p = &hw->hw_next; - q = &q->qh->qh_next; - break; - // case Q_TYPE_FSTN: - default: - /* for "save place" FSTNs, count the relevant INTR - * bandwidth from the previous frame - */ - if (q->fstn->hw_prev != EHCI_LIST_END(ehci)) { - ehci_dbg (ehci, "ignoring FSTN cost ...\n"); - } - hw_p = &q->fstn->hw_next; - q = &q->fstn->fstn_next; - break; - case Q_TYPE_ITD: - if (q->itd->hw_transaction[uframe]) - usecs += q->itd->stream->usecs; - hw_p = &q->itd->hw_next; - q = &q->itd->itd_next; - break; - case Q_TYPE_SITD: - /* is it in the S-mask? (count SPLIT, DATA) */ - if (q->sitd->hw_uframe & cpu_to_hc32(ehci, - 1 << uframe)) { - if (q->sitd->hw_fullspeed_ep & - cpu_to_hc32(ehci, 1<<31)) - usecs += q->sitd->stream->usecs; - else /* worst case for OUT start-split */ - usecs += HS_USECS_ISO (188); - } - - /* ... C-mask? (count CSPLIT, DATA) */ - if (q->sitd->hw_uframe & - cpu_to_hc32(ehci, 1 << (8 + uframe))) { - /* worst case for IN complete-split */ - usecs += q->sitd->stream->c_usecs; - } - - hw_p = &q->sitd->hw_next; - q = &q->sitd->sitd_next; - break; - } - } -#ifdef DEBUG - if (usecs > ehci->uframe_periodic_max) - ehci_err (ehci, "uframe %d sched overrun: %d usecs\n", - frame * 8 + uframe, usecs); -#endif - return usecs; -} - -/*-------------------------------------------------------------------------*/ - -static int same_tt (struct usb_device *dev1, struct usb_device *dev2) -{ - if (!dev1->tt || !dev2->tt) - return 0; - if (dev1->tt != dev2->tt) - return 0; - if (dev1->tt->multi) - return dev1->ttport == dev2->ttport; - else - return 1; -} - -#ifdef CONFIG_USB_EHCI_TT_NEWSCHED - -/* Which uframe does the low/fullspeed transfer start in? - * - * The parameter is the mask of ssplits in "H-frame" terms - * and this returns the transfer start uframe in "B-frame" terms, - * which allows both to match, e.g. a ssplit in "H-frame" uframe 0 - * will cause a transfer in "B-frame" uframe 0. "B-frames" lag - * "H-frames" by 1 uframe. See the EHCI spec sec 4.5 and figure 4.7. - */ -static inline unsigned char tt_start_uframe(struct ehci_hcd *ehci, __hc32 mask) -{ - unsigned char smask = QH_SMASK & hc32_to_cpu(ehci, mask); - if (!smask) { - ehci_err(ehci, "invalid empty smask!\n"); - /* uframe 7 can't have bw so this will indicate failure */ - return 7; - } - return ffs(smask) - 1; -} - -static const unsigned char -max_tt_usecs[] = { 125, 125, 125, 125, 125, 125, 30, 0 }; - -/* carryover low/fullspeed bandwidth that crosses uframe boundries */ -static inline void carryover_tt_bandwidth(unsigned short tt_usecs[8]) -{ - int i; - for (i=0; i<7; i++) { - if (max_tt_usecs[i] < tt_usecs[i]) { - tt_usecs[i+1] += tt_usecs[i] - max_tt_usecs[i]; - tt_usecs[i] = max_tt_usecs[i]; - } - } -} - -/* How many of the tt's periodic downstream 1000 usecs are allocated? - * - * While this measures the bandwidth in terms of usecs/uframe, - * the low/fullspeed bus has no notion of uframes, so any particular - * low/fullspeed transfer can "carry over" from one uframe to the next, - * since the TT just performs downstream transfers in sequence. - * - * For example two separate 100 usec transfers can start in the same uframe, - * and the second one would "carry over" 75 usecs into the next uframe. - */ -static void -periodic_tt_usecs ( - struct ehci_hcd *ehci, - struct usb_device *dev, - unsigned frame, - unsigned short tt_usecs[8] -) -{ - __hc32 *hw_p = &ehci->periodic [frame]; - union ehci_shadow *q = &ehci->pshadow [frame]; - unsigned char uf; - - memset(tt_usecs, 0, 16); - - while (q->ptr) { - switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) { - case Q_TYPE_ITD: - hw_p = &q->itd->hw_next; - q = &q->itd->itd_next; - continue; - case Q_TYPE_QH: - if (same_tt(dev, q->qh->dev)) { - uf = tt_start_uframe(ehci, q->qh->hw->hw_info2); - tt_usecs[uf] += q->qh->tt_usecs; - } - hw_p = &q->qh->hw->hw_next; - q = &q->qh->qh_next; - continue; - case Q_TYPE_SITD: - if (same_tt(dev, q->sitd->urb->dev)) { - uf = tt_start_uframe(ehci, q->sitd->hw_uframe); - tt_usecs[uf] += q->sitd->stream->tt_usecs; - } - hw_p = &q->sitd->hw_next; - q = &q->sitd->sitd_next; - continue; - // case Q_TYPE_FSTN: - default: - ehci_dbg(ehci, "ignoring periodic frame %d FSTN\n", - frame); - hw_p = &q->fstn->hw_next; - q = &q->fstn->fstn_next; - } - } - - carryover_tt_bandwidth(tt_usecs); - - if (max_tt_usecs[7] < tt_usecs[7]) - ehci_err(ehci, "frame %d tt sched overrun: %d usecs\n", - frame, tt_usecs[7] - max_tt_usecs[7]); -} - -/* - * Return true if the device's tt's downstream bus is available for a - * periodic transfer of the specified length (usecs), starting at the - * specified frame/uframe. Note that (as summarized in section 11.19 - * of the usb 2.0 spec) TTs can buffer multiple transactions for each - * uframe. - * - * The uframe parameter is when the fullspeed/lowspeed transfer - * should be executed in "B-frame" terms, which is the same as the - * highspeed ssplit's uframe (which is in "H-frame" terms). For example - * a ssplit in "H-frame" 0 causes a transfer in "B-frame" 0. - * See the EHCI spec sec 4.5 and fig 4.7. - * - * This checks if the full/lowspeed bus, at the specified starting uframe, - * has the specified bandwidth available, according to rules listed - * in USB 2.0 spec section 11.18.1 fig 11-60. - * - * This does not check if the transfer would exceed the max ssplit - * limit of 16, specified in USB 2.0 spec section 11.18.4 requirement #4, - * since proper scheduling limits ssplits to less than 16 per uframe. - */ -static int tt_available ( - struct ehci_hcd *ehci, - unsigned period, - struct usb_device *dev, - unsigned frame, - unsigned uframe, - u16 usecs -) -{ - if ((period == 0) || (uframe >= 7)) /* error */ - return 0; - - for (; frame < ehci->periodic_size; frame += period) { - unsigned short tt_usecs[8]; - - periodic_tt_usecs (ehci, dev, frame, tt_usecs); - - ehci_vdbg(ehci, "tt frame %d check %d usecs start uframe %d in" - " schedule %d/%d/%d/%d/%d/%d/%d/%d\n", - frame, usecs, uframe, - tt_usecs[0], tt_usecs[1], tt_usecs[2], tt_usecs[3], - tt_usecs[4], tt_usecs[5], tt_usecs[6], tt_usecs[7]); - - if (max_tt_usecs[uframe] <= tt_usecs[uframe]) { - ehci_vdbg(ehci, "frame %d uframe %d fully scheduled\n", - frame, uframe); - return 0; - } - - /* special case for isoc transfers larger than 125us: - * the first and each subsequent fully used uframe - * must be empty, so as to not illegally delay - * already scheduled transactions - */ - if (125 < usecs) { - int ufs = (usecs / 125); - int i; - for (i = uframe; i < (uframe + ufs) && i < 8; i++) - if (0 < tt_usecs[i]) { - ehci_vdbg(ehci, - "multi-uframe xfer can't fit " - "in frame %d uframe %d\n", - frame, i); - return 0; - } - } - - tt_usecs[uframe] += usecs; - - carryover_tt_bandwidth(tt_usecs); - - /* fail if the carryover pushed bw past the last uframe's limit */ - if (max_tt_usecs[7] < tt_usecs[7]) { - ehci_vdbg(ehci, - "tt unavailable usecs %d frame %d uframe %d\n", - usecs, frame, uframe); - return 0; - } - } - - return 1; -} - -#else - -/* return true iff the device's transaction translator is available - * for a periodic transfer starting at the specified frame, using - * all the uframes in the mask. - */ -static int tt_no_collision ( - struct ehci_hcd *ehci, - unsigned period, - struct usb_device *dev, - unsigned frame, - u32 uf_mask -) -{ - if (period == 0) /* error */ - return 0; - - /* note bandwidth wastage: split never follows csplit - * (different dev or endpoint) until the next uframe. - * calling convention doesn't make that distinction. - */ - for (; frame < ehci->periodic_size; frame += period) { - union ehci_shadow here; - __hc32 type; - struct ehci_qh_hw *hw; - - here = ehci->pshadow [frame]; - type = Q_NEXT_TYPE(ehci, ehci->periodic [frame]); - while (here.ptr) { - switch (hc32_to_cpu(ehci, type)) { - case Q_TYPE_ITD: - type = Q_NEXT_TYPE(ehci, here.itd->hw_next); - here = here.itd->itd_next; - continue; - case Q_TYPE_QH: - hw = here.qh->hw; - if (same_tt (dev, here.qh->dev)) { - u32 mask; - - mask = hc32_to_cpu(ehci, - hw->hw_info2); - /* "knows" no gap is needed */ - mask |= mask >> 8; - if (mask & uf_mask) - break; - } - type = Q_NEXT_TYPE(ehci, hw->hw_next); - here = here.qh->qh_next; - continue; - case Q_TYPE_SITD: - if (same_tt (dev, here.sitd->urb->dev)) { - u16 mask; - - mask = hc32_to_cpu(ehci, here.sitd - ->hw_uframe); - /* FIXME assumes no gap for IN! */ - mask |= mask >> 8; - if (mask & uf_mask) - break; - } - type = Q_NEXT_TYPE(ehci, here.sitd->hw_next); - here = here.sitd->sitd_next; - continue; - // case Q_TYPE_FSTN: - default: - ehci_dbg (ehci, - "periodic frame %d bogus type %d\n", - frame, type); - } - - /* collision or error */ - return 0; - } - } - - /* no collision */ - return 1; -} - -#endif /* CONFIG_USB_EHCI_TT_NEWSCHED */ - -/*-------------------------------------------------------------------------*/ - -static int enable_periodic (struct ehci_hcd *ehci) -{ - u32 cmd; - int status; - - if (ehci->periodic_sched++) - return 0; - - /* did clearing PSE did take effect yet? - * takes effect only at frame boundaries... - */ - status = handshake_on_error_set_halt(ehci, &ehci->regs->status, - STS_PSS, 0, 9 * 125); - if (status) { - usb_hc_died(ehci_to_hcd(ehci)); - return status; - } - - cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE; - ehci_writel(ehci, cmd, &ehci->regs->command); - /* posted write ... PSS happens later */ - - /* make sure ehci_work scans these */ - ehci->next_uframe = ehci_read_frame_index(ehci) - % (ehci->periodic_size << 3); - if (unlikely(ehci->broken_periodic)) - ehci->last_periodic_enable = ktime_get_real(); - return 0; -} - -static int disable_periodic (struct ehci_hcd *ehci) -{ - u32 cmd; - int status; - - if (--ehci->periodic_sched) - return 0; - - if (unlikely(ehci->broken_periodic)) { - /* delay experimentally determined */ - ktime_t safe = ktime_add_us(ehci->last_periodic_enable, 1000); - ktime_t now = ktime_get_real(); - s64 delay = ktime_us_delta(safe, now); - - if (unlikely(delay > 0)) - udelay(delay); - } - - /* did setting PSE not take effect yet? - * takes effect only at frame boundaries... - */ - status = handshake_on_error_set_halt(ehci, &ehci->regs->status, - STS_PSS, STS_PSS, 9 * 125); - if (status) { - usb_hc_died(ehci_to_hcd(ehci)); - return status; - } - - cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE; - ehci_writel(ehci, cmd, &ehci->regs->command); - /* posted write ... */ - - free_cached_lists(ehci); - - ehci->next_uframe = -1; - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* periodic schedule slots have iso tds (normal or split) first, then a - * sparse tree for active interrupt transfers. - * - * this just links in a qh; caller guarantees uframe masks are set right. - * no FSTN support (yet; ehci 0.96+) - */ -static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh) -{ - unsigned i; - unsigned period = qh->period; - - dev_dbg (&qh->dev->dev, - "link qh%d-%04x/%p start %d [%d/%d us]\n", - period, hc32_to_cpup(ehci, &qh->hw->hw_info2) - & (QH_CMASK | QH_SMASK), - qh, qh->start, qh->usecs, qh->c_usecs); - - /* high bandwidth, or otherwise every microframe */ - if (period == 0) - period = 1; - - for (i = qh->start; i < ehci->periodic_size; i += period) { - union ehci_shadow *prev = &ehci->pshadow[i]; - __hc32 *hw_p = &ehci->periodic[i]; - union ehci_shadow here = *prev; - __hc32 type = 0; - - /* skip the iso nodes at list head */ - while (here.ptr) { - type = Q_NEXT_TYPE(ehci, *hw_p); - if (type == cpu_to_hc32(ehci, Q_TYPE_QH)) - break; - prev = periodic_next_shadow(ehci, prev, type); - hw_p = shadow_next_periodic(ehci, &here, type); - here = *prev; - } - - /* sorting each branch by period (slow-->fast) - * enables sharing interior tree nodes - */ - while (here.ptr && qh != here.qh) { - if (qh->period > here.qh->period) - break; - prev = &here.qh->qh_next; - hw_p = &here.qh->hw->hw_next; - here = *prev; - } - /* link in this qh, unless some earlier pass did that */ - if (qh != here.qh) { - qh->qh_next = here; - if (here.qh) - qh->hw->hw_next = *hw_p; - wmb (); - prev->qh = qh; - *hw_p = QH_NEXT (ehci, qh->qh_dma); - } - } - qh->qh_state = QH_STATE_LINKED; - qh->xacterrs = 0; - qh_get (qh); - - /* update per-qh bandwidth for usbfs */ - ehci_to_hcd(ehci)->self.bandwidth_allocated += qh->period - ? ((qh->usecs + qh->c_usecs) / qh->period) - : (qh->usecs * 8); - - /* maybe enable periodic schedule processing */ - return enable_periodic(ehci); -} - -static int qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh) -{ - unsigned i; - unsigned period; - - // FIXME: - // IF this isn't high speed - // and this qh is active in the current uframe - // (and overlay token SplitXstate is false?) - // THEN - // qh->hw_info1 |= cpu_to_hc32(1 << 7 /* "ignore" */); - - /* high bandwidth, or otherwise part of every microframe */ - if ((period = qh->period) == 0) - period = 1; - - for (i = qh->start; i < ehci->periodic_size; i += period) - periodic_unlink (ehci, i, qh); - - /* update per-qh bandwidth for usbfs */ - ehci_to_hcd(ehci)->self.bandwidth_allocated -= qh->period - ? ((qh->usecs + qh->c_usecs) / qh->period) - : (qh->usecs * 8); - - dev_dbg (&qh->dev->dev, - "unlink qh%d-%04x/%p start %d [%d/%d us]\n", - qh->period, - hc32_to_cpup(ehci, &qh->hw->hw_info2) & (QH_CMASK | QH_SMASK), - qh, qh->start, qh->usecs, qh->c_usecs); - - /* qh->qh_next still "live" to HC */ - qh->qh_state = QH_STATE_UNLINK; - qh->qh_next.ptr = NULL; - qh_put (qh); - - /* maybe turn off periodic schedule */ - //return disable_periodic(ehci); - return 0; -} - -static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh) -{ - unsigned wait; - struct ehci_qh_hw *hw = qh->hw; - int rc; - - /* If the QH isn't linked then there's nothing we can do - * unless we were called during a giveback, in which case - * qh_completions() has to deal with it. - */ - if (qh->qh_state != QH_STATE_LINKED) { - if (qh->qh_state == QH_STATE_COMPLETING) - qh->needs_rescan = 1; - return; - } - - qh_unlink_periodic (ehci, qh); - - /* simple/paranoid: always delay, expecting the HC needs to read - * qh->hw_next or finish a writeback after SPLIT/CSPLIT ... and - * expect khubd to clean up after any CSPLITs we won't issue. - * active high speed queues may need bigger delays... - */ - if (list_empty (&qh->qtd_list) - || (cpu_to_hc32(ehci, QH_CMASK) - & hw->hw_info2) != 0) - wait = 2; - else - wait = 55; /* worst case: 3 * 1024 */ - - udelay (wait); - qh->qh_state = QH_STATE_IDLE; - hw->hw_next = EHCI_LIST_END(ehci); - wmb (); - - qh_completions(ehci, qh); - - /* reschedule QH iff another request is queued */ - if (!list_empty(&qh->qtd_list) && - ehci->rh_state == EHCI_RH_RUNNING) { - rc = qh_schedule(ehci, qh); - - /* An error here likely indicates handshake failure - * or no space left in the schedule. Neither fault - * should happen often ... - * - * FIXME kill the now-dysfunctional queued urbs - */ - if (rc != 0) - ehci_err(ehci, "can't reschedule qh %p, err %d\n", - qh, rc); - } -} - -/*-------------------------------------------------------------------------*/ - -static int check_period ( - struct ehci_hcd *ehci, - unsigned frame, - unsigned uframe, - unsigned period, - unsigned usecs -) { - int claimed; - - /* complete split running into next frame? - * given FSTN support, we could sometimes check... - */ - if (uframe >= 8) - return 0; - - /* convert "usecs we need" to "max already claimed" */ - usecs = ehci->uframe_periodic_max - usecs; - - /* we "know" 2 and 4 uframe intervals were rejected; so - * for period 0, check _every_ microframe in the schedule. - */ - if (unlikely (period == 0)) { - do { - for (uframe = 0; uframe < 7; uframe++) { - claimed = periodic_usecs (ehci, frame, uframe); - if (claimed > usecs) - return 0; - } - } while ((frame += 1) < ehci->periodic_size); - - /* just check the specified uframe, at that period */ - } else { - do { - claimed = periodic_usecs (ehci, frame, uframe); - if (claimed > usecs) - return 0; - } while ((frame += period) < ehci->periodic_size); - } - - // success! - return 1; -} - -static int check_intr_schedule ( - struct ehci_hcd *ehci, - unsigned frame, - unsigned uframe, - const struct ehci_qh *qh, - __hc32 *c_maskp -) -{ - int retval = -ENOSPC; - u8 mask = 0; - - if (qh->c_usecs && uframe >= 6) /* FSTN territory? */ - goto done; - - if (!check_period (ehci, frame, uframe, qh->period, qh->usecs)) - goto done; - if (!qh->c_usecs) { - retval = 0; - *c_maskp = 0; - goto done; - } - -#ifdef CONFIG_USB_EHCI_TT_NEWSCHED - if (tt_available (ehci, qh->period, qh->dev, frame, uframe, - qh->tt_usecs)) { - unsigned i; - - /* TODO : this may need FSTN for SSPLIT in uframe 5. */ - for (i=uframe+1; i<8 && iperiod, qh->c_usecs)) - goto done; - else - mask |= 1 << i; - - retval = 0; - - *c_maskp = cpu_to_hc32(ehci, mask << 8); - } -#else - /* Make sure this tt's buffer is also available for CSPLITs. - * We pessimize a bit; probably the typical full speed case - * doesn't need the second CSPLIT. - * - * NOTE: both SPLIT and CSPLIT could be checked in just - * one smart pass... - */ - mask = 0x03 << (uframe + qh->gap_uf); - *c_maskp = cpu_to_hc32(ehci, mask << 8); - - mask |= 1 << uframe; - if (tt_no_collision (ehci, qh->period, qh->dev, frame, mask)) { - if (!check_period (ehci, frame, uframe + qh->gap_uf + 1, - qh->period, qh->c_usecs)) - goto done; - if (!check_period (ehci, frame, uframe + qh->gap_uf, - qh->period, qh->c_usecs)) - goto done; - retval = 0; - } -#endif -done: - return retval; -} - -/* "first fit" scheduling policy used the first time through, - * or when the previous schedule slot can't be re-used. - */ -static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh) -{ - int status; - unsigned uframe; - __hc32 c_mask; - unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */ - struct ehci_qh_hw *hw = qh->hw; - - qh_refresh(ehci, qh); - hw->hw_next = EHCI_LIST_END(ehci); - frame = qh->start; - - /* reuse the previous schedule slots, if we can */ - if (frame < qh->period) { - uframe = ffs(hc32_to_cpup(ehci, &hw->hw_info2) & QH_SMASK); - status = check_intr_schedule (ehci, frame, --uframe, - qh, &c_mask); - } else { - uframe = 0; - c_mask = 0; - status = -ENOSPC; - } - - /* else scan the schedule to find a group of slots such that all - * uframes have enough periodic bandwidth available. - */ - if (status) { - /* "normal" case, uframing flexible except with splits */ - if (qh->period) { - 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, - &c_mask); - if (status == 0) - break; - } - } - - /* qh->period == 0 means every uframe */ - } else { - frame = 0; - status = check_intr_schedule (ehci, 0, 0, qh, &c_mask); - } - if (status) - goto done; - qh->start = frame; - - /* reset S-frame and (maybe) C-frame masks */ - hw->hw_info2 &= cpu_to_hc32(ehci, ~(QH_CMASK | QH_SMASK)); - hw->hw_info2 |= qh->period - ? cpu_to_hc32(ehci, 1 << uframe) - : cpu_to_hc32(ehci, QH_SMASK); - hw->hw_info2 |= c_mask; - } else - ehci_dbg (ehci, "reused qh %p schedule\n", qh); - - /* stuff into the periodic schedule */ - status = qh_link_periodic (ehci, qh); -done: - return status; -} - -static int intr_submit ( - struct ehci_hcd *ehci, - struct urb *urb, - struct list_head *qtd_list, - gfp_t mem_flags -) { - unsigned epnum; - unsigned long flags; - struct ehci_qh *qh; - int status; - struct list_head empty; - - /* get endpoint and transfer/schedule data */ - epnum = urb->ep->desc.bEndpointAddress; - - spin_lock_irqsave (&ehci->lock, flags); - - if (unlikely(!HCD_HW_ACCESSIBLE(ehci_to_hcd(ehci)))) { - status = -ESHUTDOWN; - goto done_not_linked; - } - status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb); - if (unlikely(status)) - goto done_not_linked; - - /* get qh and force any scheduling errors */ - INIT_LIST_HEAD (&empty); - qh = qh_append_tds(ehci, urb, &empty, epnum, &urb->ep->hcpriv); - if (qh == NULL) { - status = -ENOMEM; - goto done; - } - if (qh->qh_state == QH_STATE_IDLE) { - if ((status = qh_schedule (ehci, qh)) != 0) - goto done; - } - - /* then queue the urb's tds to the qh */ - qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv); - BUG_ON (qh == NULL); - - /* ... update usbfs periodic stats */ - ehci_to_hcd(ehci)->self.bandwidth_int_reqs++; - -done: - if (unlikely(status)) - usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); -done_not_linked: - spin_unlock_irqrestore (&ehci->lock, flags); - if (status) - qtd_list_free (ehci, urb, qtd_list); - - return status; -} - -/*-------------------------------------------------------------------------*/ - -/* ehci_iso_stream ops work with both ITD and SITD */ - -static struct ehci_iso_stream * -iso_stream_alloc (gfp_t mem_flags) -{ - struct ehci_iso_stream *stream; - - stream = kzalloc(sizeof *stream, mem_flags); - if (likely (stream != NULL)) { - INIT_LIST_HEAD(&stream->td_list); - INIT_LIST_HEAD(&stream->free_list); - stream->next_uframe = -1; - stream->refcount = 1; - } - return stream; -} - -static void -iso_stream_init ( - struct ehci_hcd *ehci, - struct ehci_iso_stream *stream, - struct usb_device *dev, - int pipe, - unsigned interval -) -{ - static const u8 smask_out [] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f }; - - u32 buf1; - unsigned epnum, maxp; - int is_input; - long bandwidth; - - /* - * this might be a "high bandwidth" highspeed endpoint, - * as encoded in the ep descriptor's wMaxPacket field - */ - epnum = usb_pipeendpoint (pipe); - is_input = usb_pipein (pipe) ? USB_DIR_IN : 0; - maxp = usb_maxpacket(dev, pipe, !is_input); - if (is_input) { - buf1 = (1 << 11); - } else { - buf1 = 0; - } - - /* knows about ITD vs SITD */ - if (dev->speed == USB_SPEED_HIGH) { - unsigned multi = hb_mult(maxp); - - stream->highspeed = 1; - - maxp = max_packet(maxp); - buf1 |= maxp; - maxp *= multi; - - stream->buf0 = cpu_to_hc32(ehci, (epnum << 8) | dev->devnum); - stream->buf1 = cpu_to_hc32(ehci, buf1); - stream->buf2 = cpu_to_hc32(ehci, multi); - - /* usbfs wants to report the average usecs per frame tied up - * when transfers on this endpoint are scheduled ... - */ - stream->usecs = HS_USECS_ISO (maxp); - bandwidth = stream->usecs * 8; - bandwidth /= interval; - - } else { - u32 addr; - int think_time; - int hs_transfers; - - addr = dev->ttport << 24; - if (!ehci_is_TDI(ehci) - || (dev->tt->hub != - ehci_to_hcd(ehci)->self.root_hub)) - addr |= dev->tt->hub->devnum << 16; - addr |= epnum << 8; - addr |= dev->devnum; - stream->usecs = HS_USECS_ISO (maxp); - think_time = dev->tt ? dev->tt->think_time : 0; - stream->tt_usecs = NS_TO_US (think_time + usb_calc_bus_time ( - dev->speed, is_input, 1, maxp)); - hs_transfers = max (1u, (maxp + 187) / 188); - if (is_input) { - u32 tmp; - - addr |= 1 << 31; - stream->c_usecs = stream->usecs; - stream->usecs = HS_USECS_ISO (1); - stream->raw_mask = 1; - - /* c-mask as specified in USB 2.0 11.18.4 3.c */ - tmp = (1 << (hs_transfers + 2)) - 1; - stream->raw_mask |= tmp << (8 + 2); - } else - stream->raw_mask = smask_out [hs_transfers - 1]; - bandwidth = stream->usecs + stream->c_usecs; - bandwidth /= interval << 3; - - /* stream->splits gets created from raw_mask later */ - stream->address = cpu_to_hc32(ehci, addr); - } - stream->bandwidth = bandwidth; - - stream->udev = dev; - - stream->bEndpointAddress = is_input | epnum; - stream->interval = interval; - stream->maxp = maxp; -} - -static void -iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream) -{ - stream->refcount--; - - /* free whenever just a dev->ep reference remains. - * not like a QH -- no persistent state (toggle, halt) - */ - if (stream->refcount == 1) { - // BUG_ON (!list_empty(&stream->td_list)); - - while (!list_empty (&stream->free_list)) { - struct list_head *entry; - - entry = stream->free_list.next; - list_del (entry); - - /* knows about ITD vs SITD */ - if (stream->highspeed) { - struct ehci_itd *itd; - - itd = list_entry (entry, struct ehci_itd, - itd_list); - dma_pool_free (ehci->itd_pool, itd, - itd->itd_dma); - } else { - struct ehci_sitd *sitd; - - sitd = list_entry (entry, struct ehci_sitd, - sitd_list); - dma_pool_free (ehci->sitd_pool, sitd, - sitd->sitd_dma); - } - } - - stream->bEndpointAddress &= 0x0f; - if (stream->ep) - stream->ep->hcpriv = NULL; - - kfree(stream); - } -} - -static inline struct ehci_iso_stream * -iso_stream_get (struct ehci_iso_stream *stream) -{ - if (likely (stream != NULL)) - stream->refcount++; - return stream; -} - -static struct ehci_iso_stream * -iso_stream_find (struct ehci_hcd *ehci, struct urb *urb) -{ - unsigned epnum; - struct ehci_iso_stream *stream; - struct usb_host_endpoint *ep; - unsigned long flags; - - epnum = usb_pipeendpoint (urb->pipe); - if (usb_pipein(urb->pipe)) - ep = urb->dev->ep_in[epnum]; - else - ep = urb->dev->ep_out[epnum]; - - spin_lock_irqsave (&ehci->lock, flags); - stream = ep->hcpriv; - - if (unlikely (stream == NULL)) { - stream = iso_stream_alloc(GFP_ATOMIC); - if (likely (stream != NULL)) { - /* dev->ep owns the initial refcount */ - ep->hcpriv = stream; - stream->ep = ep; - iso_stream_init(ehci, stream, urb->dev, urb->pipe, - urb->interval); - } - - /* if dev->ep [epnum] is a QH, hw is set */ - } else if (unlikely (stream->hw != NULL)) { - ehci_dbg (ehci, "dev %s ep%d%s, not iso??\n", - urb->dev->devpath, epnum, - usb_pipein(urb->pipe) ? "in" : "out"); - stream = NULL; - } - - /* caller guarantees an eventual matching iso_stream_put */ - stream = iso_stream_get (stream); - - spin_unlock_irqrestore (&ehci->lock, flags); - return stream; -} - -/*-------------------------------------------------------------------------*/ - -/* ehci_iso_sched ops can be ITD-only or SITD-only */ - -static struct ehci_iso_sched * -iso_sched_alloc (unsigned packets, gfp_t mem_flags) -{ - struct ehci_iso_sched *iso_sched; - int size = sizeof *iso_sched; - - size += packets * sizeof (struct ehci_iso_packet); - iso_sched = kzalloc(size, mem_flags); - if (likely (iso_sched != NULL)) { - INIT_LIST_HEAD (&iso_sched->td_list); - } - return iso_sched; -} - -static inline void -itd_sched_init( - struct ehci_hcd *ehci, - struct ehci_iso_sched *iso_sched, - struct ehci_iso_stream *stream, - struct urb *urb -) -{ - unsigned i; - dma_addr_t dma = urb->transfer_dma; - - /* how many uframes are needed for these transfers */ - iso_sched->span = urb->number_of_packets * stream->interval; - - /* figure out per-uframe itd fields that we'll need later - * when we fit new itds into the schedule. - */ - for (i = 0; i < urb->number_of_packets; i++) { - struct ehci_iso_packet *uframe = &iso_sched->packet [i]; - unsigned length; - dma_addr_t buf; - u32 trans; - - length = urb->iso_frame_desc [i].length; - buf = dma + urb->iso_frame_desc [i].offset; - - trans = EHCI_ISOC_ACTIVE; - trans |= buf & 0x0fff; - if (unlikely (((i + 1) == urb->number_of_packets)) - && !(urb->transfer_flags & URB_NO_INTERRUPT)) - trans |= EHCI_ITD_IOC; - trans |= length << 16; - uframe->transaction = cpu_to_hc32(ehci, trans); - - /* might need to cross a buffer page within a uframe */ - uframe->bufp = (buf & ~(u64)0x0fff); - buf += length; - if (unlikely ((uframe->bufp != (buf & ~(u64)0x0fff)))) - uframe->cross = 1; - } -} - -static void -iso_sched_free ( - struct ehci_iso_stream *stream, - struct ehci_iso_sched *iso_sched -) -{ - if (!iso_sched) - return; - // caller must hold ehci->lock! - list_splice (&iso_sched->td_list, &stream->free_list); - kfree (iso_sched); -} - -static int -itd_urb_transaction ( - struct ehci_iso_stream *stream, - struct ehci_hcd *ehci, - struct urb *urb, - gfp_t mem_flags -) -{ - struct ehci_itd *itd; - dma_addr_t itd_dma; - int i; - unsigned num_itds; - struct ehci_iso_sched *sched; - unsigned long flags; - - sched = iso_sched_alloc (urb->number_of_packets, mem_flags); - if (unlikely (sched == NULL)) - return -ENOMEM; - - itd_sched_init(ehci, sched, stream, urb); - - if (urb->interval < 8) - num_itds = 1 + (sched->span + 7) / 8; - else - num_itds = urb->number_of_packets; - - /* allocate/init ITDs */ - spin_lock_irqsave (&ehci->lock, flags); - for (i = 0; i < num_itds; i++) { - - /* free_list.next might be cache-hot ... but maybe - * the HC caches it too. avoid that issue for now. - */ - - /* prefer previously-allocated itds */ - if (likely (!list_empty(&stream->free_list))) { - itd = list_entry (stream->free_list.prev, - struct ehci_itd, itd_list); - list_del (&itd->itd_list); - itd_dma = itd->itd_dma; - } else { - spin_unlock_irqrestore (&ehci->lock, flags); - itd = dma_pool_alloc (ehci->itd_pool, mem_flags, - &itd_dma); - spin_lock_irqsave (&ehci->lock, flags); - if (!itd) { - iso_sched_free(stream, sched); - spin_unlock_irqrestore(&ehci->lock, flags); - return -ENOMEM; - } - } - - memset (itd, 0, sizeof *itd); - itd->itd_dma = itd_dma; - list_add (&itd->itd_list, &sched->td_list); - } - spin_unlock_irqrestore (&ehci->lock, flags); - - /* temporarily store schedule info in hcpriv */ - urb->hcpriv = sched; - urb->error_count = 0; - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static inline int -itd_slot_ok ( - struct ehci_hcd *ehci, - u32 mod, - u32 uframe, - u8 usecs, - u32 period -) -{ - uframe %= period; - do { - /* can't commit more than uframe_periodic_max usec */ - if (periodic_usecs (ehci, uframe >> 3, uframe & 0x7) - > (ehci->uframe_periodic_max - usecs)) - return 0; - - /* we know urb->interval is 2^N uframes */ - uframe += period; - } while (uframe < mod); - return 1; -} - -static inline int -sitd_slot_ok ( - struct ehci_hcd *ehci, - u32 mod, - struct ehci_iso_stream *stream, - u32 uframe, - struct ehci_iso_sched *sched, - u32 period_uframes -) -{ - u32 mask, tmp; - u32 frame, uf; - - mask = stream->raw_mask << (uframe & 7); - - /* for IN, don't wrap CSPLIT into the next frame */ - if (mask & ~0xffff) - return 0; - - /* this multi-pass logic is simple, but performance may - * suffer when the schedule data isn't cached. - */ - - /* check bandwidth */ - uframe %= period_uframes; - do { - u32 max_used; - - frame = uframe >> 3; - uf = uframe & 7; - -#ifdef CONFIG_USB_EHCI_TT_NEWSCHED - /* The tt's fullspeed bus bandwidth must be available. - * tt_available scheduling guarantees 10+% for control/bulk. - */ - if (!tt_available (ehci, period_uframes << 3, - stream->udev, frame, uf, stream->tt_usecs)) - return 0; -#else - /* tt must be idle for start(s), any gap, and csplit. - * assume scheduling slop leaves 10+% for control/bulk. - */ - if (!tt_no_collision (ehci, period_uframes << 3, - stream->udev, frame, mask)) - return 0; -#endif - - /* check starts (OUT uses more than one) */ - max_used = ehci->uframe_periodic_max - stream->usecs; - for (tmp = stream->raw_mask & 0xff; tmp; tmp >>= 1, uf++) { - if (periodic_usecs (ehci, frame, uf) > max_used) - return 0; - } - - /* for IN, check CSPLIT */ - if (stream->c_usecs) { - uf = uframe & 7; - max_used = ehci->uframe_periodic_max - stream->c_usecs; - do { - tmp = 1 << uf; - tmp <<= 8; - if ((stream->raw_mask & tmp) == 0) - continue; - if (periodic_usecs (ehci, frame, uf) - > max_used) - return 0; - } while (++uf < 8); - } - - /* we know urb->interval is 2^N uframes */ - uframe += period_uframes; - } while (uframe < mod); - - stream->splits = cpu_to_hc32(ehci, stream->raw_mask << (uframe & 7)); - return 1; -} - -/* - * This scheduler plans almost as far into the future as it has actual - * periodic schedule slots. (Affected by TUNE_FLS, which defaults to - * "as small as possible" to be cache-friendlier.) That limits the size - * transfers you can stream reliably; avoid more than 64 msec per urb. - * Also avoid queue depths of less than ehci's worst irq latency (affected - * by the per-urb URB_NO_INTERRUPT hint, the log2_irq_thresh module parameter, - * and other factors); or more than about 230 msec total (for portability, - * given EHCI_TUNE_FLS and the slop). Or, write a smarter scheduler! - */ - -#define SCHEDULE_SLOP 80 /* microframes */ - -static int -iso_stream_schedule ( - struct ehci_hcd *ehci, - struct urb *urb, - struct ehci_iso_stream *stream -) -{ - u32 now, next, start, period, span; - int status; - unsigned mod = ehci->periodic_size << 3; - struct ehci_iso_sched *sched = urb->hcpriv; - - period = urb->interval; - span = sched->span; - if (!stream->highspeed) { - period <<= 3; - span <<= 3; - } - - if (span > mod - SCHEDULE_SLOP) { - ehci_dbg (ehci, "iso request %p too long\n", urb); - status = -EFBIG; - goto fail; - } - - now = ehci_read_frame_index(ehci) & (mod - 1); - - /* Typical case: reuse current schedule, stream is still active. - * Hopefully there are no gaps from the host falling behind - * (irq delays etc), but if there are we'll take the next - * slot in the schedule, implicitly assuming URB_ISO_ASAP. - */ - if (likely (!list_empty (&stream->td_list))) { - u32 excess; - - /* For high speed devices, allow scheduling within the - * isochronous scheduling threshold. For full speed devices - * and Intel PCI-based controllers, don't (work around for - * Intel ICH9 bug). - */ - if (!stream->highspeed && ehci->fs_i_thresh) - next = now + ehci->i_thresh; - else - next = now; - - /* Fell behind (by up to twice the slop amount)? - * We decide based on the time of the last currently-scheduled - * slot, not the time of the next available slot. - */ - excess = (stream->next_uframe - period - next) & (mod - 1); - if (excess >= mod - 2 * SCHEDULE_SLOP) - start = next + excess - mod + period * - DIV_ROUND_UP(mod - excess, period); - else - start = next + excess + period; - if (start - now >= mod) { - ehci_dbg(ehci, "request %p would overflow (%d+%d >= %d)\n", - urb, start - now - period, period, - mod); - status = -EFBIG; - goto fail; - } - } - - /* need to schedule; when's the next (u)frame we could start? - * this is bigger than ehci->i_thresh allows; scheduling itself - * isn't free, the slop should handle reasonably slow cpus. it - * can also help high bandwidth if the dma and irq loads don't - * jump until after the queue is primed. - */ - else { - int done = 0; - start = SCHEDULE_SLOP + (now & ~0x07); - - /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */ - - /* find a uframe slot with enough bandwidth. - * Early uframes are more precious because full-speed - * iso IN transfers can't use late uframes, - * and therefore they should be allocated last. - */ - next = start; - start += period; - do { - start--; - /* check schedule: enough space? */ - if (stream->highspeed) { - if (itd_slot_ok(ehci, mod, start, - stream->usecs, period)) - done = 1; - } else { - if ((start % 8) >= 6) - continue; - if (sitd_slot_ok(ehci, mod, stream, - start, sched, period)) - done = 1; - } - } while (start > next && !done); - - /* no room in the schedule */ - if (!done) { - ehci_dbg(ehci, "iso resched full %p (now %d max %d)\n", - urb, now, now + mod); - status = -ENOSPC; - goto fail; - } - } - - /* Tried to schedule too far into the future? */ - if (unlikely(start - now + span - period - >= mod - 2 * SCHEDULE_SLOP)) { - ehci_dbg(ehci, "request %p would overflow (%d+%d >= %d)\n", - urb, start - now, span - period, - mod - 2 * SCHEDULE_SLOP); - status = -EFBIG; - goto fail; - } - - stream->next_uframe = start & (mod - 1); - - /* report high speed start in uframes; full speed, in frames */ - urb->start_frame = stream->next_uframe; - if (!stream->highspeed) - urb->start_frame >>= 3; - return 0; - - fail: - iso_sched_free(stream, sched); - urb->hcpriv = NULL; - return status; -} - -/*-------------------------------------------------------------------------*/ - -static inline void -itd_init(struct ehci_hcd *ehci, struct ehci_iso_stream *stream, - struct ehci_itd *itd) -{ - int i; - - /* it's been recently zeroed */ - itd->hw_next = EHCI_LIST_END(ehci); - itd->hw_bufp [0] = stream->buf0; - itd->hw_bufp [1] = stream->buf1; - itd->hw_bufp [2] = stream->buf2; - - for (i = 0; i < 8; i++) - itd->index[i] = -1; - - /* All other fields are filled when scheduling */ -} - -static inline void -itd_patch( - struct ehci_hcd *ehci, - struct ehci_itd *itd, - struct ehci_iso_sched *iso_sched, - unsigned index, - u16 uframe -) -{ - struct ehci_iso_packet *uf = &iso_sched->packet [index]; - unsigned pg = itd->pg; - - // BUG_ON (pg == 6 && uf->cross); - - uframe &= 0x07; - itd->index [uframe] = index; - - itd->hw_transaction[uframe] = uf->transaction; - itd->hw_transaction[uframe] |= cpu_to_hc32(ehci, pg << 12); - itd->hw_bufp[pg] |= cpu_to_hc32(ehci, uf->bufp & ~(u32)0); - itd->hw_bufp_hi[pg] |= cpu_to_hc32(ehci, (u32)(uf->bufp >> 32)); - - /* iso_frame_desc[].offset must be strictly increasing */ - if (unlikely (uf->cross)) { - u64 bufp = uf->bufp + 4096; - - itd->pg = ++pg; - itd->hw_bufp[pg] |= cpu_to_hc32(ehci, bufp & ~(u32)0); - itd->hw_bufp_hi[pg] |= cpu_to_hc32(ehci, (u32)(bufp >> 32)); - } -} - -static inline void -itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd) -{ - union ehci_shadow *prev = &ehci->pshadow[frame]; - __hc32 *hw_p = &ehci->periodic[frame]; - union ehci_shadow here = *prev; - __hc32 type = 0; - - /* skip any iso nodes which might belong to previous microframes */ - while (here.ptr) { - type = Q_NEXT_TYPE(ehci, *hw_p); - if (type == cpu_to_hc32(ehci, Q_TYPE_QH)) - break; - prev = periodic_next_shadow(ehci, prev, type); - hw_p = shadow_next_periodic(ehci, &here, type); - here = *prev; - } - - itd->itd_next = here; - itd->hw_next = *hw_p; - prev->itd = itd; - itd->frame = frame; - wmb (); - *hw_p = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD); -} - -/* fit urb's itds into the selected schedule slot; activate as needed */ -static int -itd_link_urb ( - struct ehci_hcd *ehci, - struct urb *urb, - unsigned mod, - struct ehci_iso_stream *stream -) -{ - int packet; - unsigned next_uframe, uframe, frame; - struct ehci_iso_sched *iso_sched = urb->hcpriv; - struct ehci_itd *itd; - - next_uframe = stream->next_uframe & (mod - 1); - - if (unlikely (list_empty(&stream->td_list))) { - ehci_to_hcd(ehci)->self.bandwidth_allocated - += stream->bandwidth; - ehci_vdbg (ehci, - "schedule devp %s ep%d%s-iso period %d start %d.%d\n", - urb->dev->devpath, stream->bEndpointAddress & 0x0f, - (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out", - urb->interval, - next_uframe >> 3, next_uframe & 0x7); - } - - if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { - if (ehci->amd_pll_fix == 1) - usb_amd_quirk_pll_disable(); - } - - ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++; - - /* fill iTDs uframe by uframe */ - for (packet = 0, itd = NULL; packet < urb->number_of_packets; ) { - if (itd == NULL) { - /* ASSERT: we have all necessary itds */ - // BUG_ON (list_empty (&iso_sched->td_list)); - - /* ASSERT: no itds for this endpoint in this uframe */ - - itd = list_entry (iso_sched->td_list.next, - struct ehci_itd, itd_list); - list_move_tail (&itd->itd_list, &stream->td_list); - itd->stream = iso_stream_get (stream); - itd->urb = urb; - itd_init (ehci, stream, itd); - } - - uframe = next_uframe & 0x07; - frame = next_uframe >> 3; - - itd_patch(ehci, itd, iso_sched, packet, uframe); - - next_uframe += stream->interval; - next_uframe &= mod - 1; - packet++; - - /* link completed itds into the schedule */ - if (((next_uframe >> 3) != frame) - || packet == urb->number_of_packets) { - itd_link(ehci, frame & (ehci->periodic_size - 1), itd); - itd = NULL; - } - } - stream->next_uframe = next_uframe; - - /* don't need that schedule data any more */ - iso_sched_free (stream, iso_sched); - urb->hcpriv = NULL; - - timer_action (ehci, TIMER_IO_WATCHDOG); - return enable_periodic(ehci); -} - -#define ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR) - -/* Process and recycle a completed ITD. Return true iff its urb completed, - * and hence its completion callback probably added things to the hardware - * schedule. - * - * Note that we carefully avoid recycling this descriptor until after any - * completion callback runs, so that it won't be reused quickly. That is, - * assuming (a) no more than two urbs per frame on this endpoint, and also - * (b) only this endpoint's completions submit URBs. It seems some silicon - * corrupts things if you reuse completed descriptors very quickly... - */ -static unsigned -itd_complete ( - struct ehci_hcd *ehci, - struct ehci_itd *itd -) { - struct urb *urb = itd->urb; - struct usb_iso_packet_descriptor *desc; - u32 t; - unsigned uframe; - int urb_index = -1; - struct ehci_iso_stream *stream = itd->stream; - struct usb_device *dev; - unsigned retval = false; - - /* for each uframe with a packet */ - for (uframe = 0; uframe < 8; uframe++) { - if (likely (itd->index[uframe] == -1)) - continue; - urb_index = itd->index[uframe]; - desc = &urb->iso_frame_desc [urb_index]; - - t = hc32_to_cpup(ehci, &itd->hw_transaction [uframe]); - itd->hw_transaction [uframe] = 0; - - /* report transfer status */ - if (unlikely (t & ISO_ERRS)) { - urb->error_count++; - if (t & EHCI_ISOC_BUF_ERR) - desc->status = usb_pipein (urb->pipe) - ? -ENOSR /* hc couldn't read */ - : -ECOMM; /* hc couldn't write */ - else if (t & EHCI_ISOC_BABBLE) - desc->status = -EOVERFLOW; - else /* (t & EHCI_ISOC_XACTERR) */ - desc->status = -EPROTO; - - /* HC need not update length with this error */ - if (!(t & EHCI_ISOC_BABBLE)) { - desc->actual_length = EHCI_ITD_LENGTH(t); - urb->actual_length += desc->actual_length; - } - } else if (likely ((t & EHCI_ISOC_ACTIVE) == 0)) { - desc->status = 0; - desc->actual_length = EHCI_ITD_LENGTH(t); - urb->actual_length += desc->actual_length; - } else { - /* URB was too late */ - desc->status = -EXDEV; - } - } - - /* handle completion now? */ - if (likely ((urb_index + 1) != urb->number_of_packets)) - goto done; - - /* ASSERT: it's really the last itd for this urb - list_for_each_entry (itd, &stream->td_list, itd_list) - BUG_ON (itd->urb == urb); - */ - - /* give urb back to the driver; completion often (re)submits */ - dev = urb->dev; - ehci_urb_done(ehci, urb, 0); - retval = true; - urb = NULL; - //(void) disable_periodic(ehci); gri - ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--; - - if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { - if (ehci->amd_pll_fix == 1) - usb_amd_quirk_pll_enable(); - } - - if (unlikely(list_is_singular(&stream->td_list))) { - ehci_to_hcd(ehci)->self.bandwidth_allocated - -= stream->bandwidth; - ehci_vdbg (ehci, - "deschedule devp %s ep%d%s-iso\n", - dev->devpath, stream->bEndpointAddress & 0x0f, - (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); - } - iso_stream_put (ehci, stream); - -done: - itd->urb = NULL; - if (ehci->clock_frame != itd->frame || itd->index[7] != -1) { - /* OK to recycle this ITD now. */ - itd->stream = NULL; - list_move(&itd->itd_list, &stream->free_list); - iso_stream_put(ehci, stream); - } else { - /* HW might remember this ITD, so we can't recycle it yet. - * Move it to a safe place until a new frame starts. - */ - list_move(&itd->itd_list, &ehci->cached_itd_list); - if (stream->refcount == 2) { - /* If iso_stream_put() were called here, stream - * would be freed. Instead, just prevent reuse. - */ - stream->ep->hcpriv = NULL; - stream->ep = NULL; - } - } - return retval; -} - -/*-------------------------------------------------------------------------*/ - -static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, - gfp_t mem_flags) -{ - int status = -EINVAL; - unsigned long flags; - struct ehci_iso_stream *stream; - - /* Get iso_stream head */ - stream = iso_stream_find (ehci, urb); - if (unlikely (stream == NULL)) { - ehci_dbg (ehci, "can't get iso stream\n"); - return -ENOMEM; - } - if (unlikely (urb->interval != stream->interval)) { - ehci_dbg (ehci, "can't change iso interval %d --> %d\n", - stream->interval, urb->interval); - goto done; - } - -#ifdef EHCI_URB_TRACE - ehci_dbg (ehci, - "%s %s urb %p ep%d%s len %d, %d pkts %d uframes [%p]\n", - __func__, urb->dev->devpath, urb, - usb_pipeendpoint (urb->pipe), - usb_pipein (urb->pipe) ? "in" : "out", - urb->transfer_buffer_length, - urb->number_of_packets, urb->interval, - stream); -#endif - - /* allocate ITDs w/o locking anything */ - status = itd_urb_transaction (stream, ehci, urb, mem_flags); - if (unlikely (status < 0)) { - ehci_dbg (ehci, "can't init itds\n"); - goto done; - } - - /* schedule ... need to lock */ - spin_lock_irqsave (&ehci->lock, flags); - if (unlikely(!HCD_HW_ACCESSIBLE(ehci_to_hcd(ehci)))) { - status = -ESHUTDOWN; - goto done_not_linked; - } - status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb); - if (unlikely(status)) - goto done_not_linked; - status = iso_stream_schedule(ehci, urb, stream); - if (likely (status == 0)) - itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); - else - usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); -done_not_linked: - spin_unlock_irqrestore (&ehci->lock, flags); - -done: - if (unlikely (status < 0)) - iso_stream_put (ehci, stream); - return status; -} - -/*-------------------------------------------------------------------------*/ - -/* - * "Split ISO TDs" ... used for USB 1.1 devices going through the - * TTs in USB 2.0 hubs. These need microframe scheduling. - */ - -static inline void -sitd_sched_init( - struct ehci_hcd *ehci, - struct ehci_iso_sched *iso_sched, - struct ehci_iso_stream *stream, - struct urb *urb -) -{ - unsigned i; - dma_addr_t dma = urb->transfer_dma; - - /* how many frames are needed for these transfers */ - iso_sched->span = urb->number_of_packets * stream->interval; - - /* figure out per-frame sitd fields that we'll need later - * when we fit new sitds into the schedule. - */ - for (i = 0; i < urb->number_of_packets; i++) { - struct ehci_iso_packet *packet = &iso_sched->packet [i]; - unsigned length; - dma_addr_t buf; - u32 trans; - - length = urb->iso_frame_desc [i].length & 0x03ff; - buf = dma + urb->iso_frame_desc [i].offset; - - trans = SITD_STS_ACTIVE; - if (((i + 1) == urb->number_of_packets) - && !(urb->transfer_flags & URB_NO_INTERRUPT)) - trans |= SITD_IOC; - trans |= length << 16; - packet->transaction = cpu_to_hc32(ehci, trans); - - /* might need to cross a buffer page within a td */ - packet->bufp = buf; - packet->buf1 = (buf + length) & ~0x0fff; - if (packet->buf1 != (buf & ~(u64)0x0fff)) - packet->cross = 1; - - /* OUT uses multiple start-splits */ - if (stream->bEndpointAddress & USB_DIR_IN) - continue; - length = (length + 187) / 188; - if (length > 1) /* BEGIN vs ALL */ - length |= 1 << 3; - packet->buf1 |= length; - } -} - -static int -sitd_urb_transaction ( - struct ehci_iso_stream *stream, - struct ehci_hcd *ehci, - struct urb *urb, - gfp_t mem_flags -) -{ - struct ehci_sitd *sitd; - dma_addr_t sitd_dma; - int i; - struct ehci_iso_sched *iso_sched; - unsigned long flags; - - iso_sched = iso_sched_alloc (urb->number_of_packets, mem_flags); - if (iso_sched == NULL) - return -ENOMEM; - - sitd_sched_init(ehci, iso_sched, stream, urb); - - /* allocate/init sITDs */ - spin_lock_irqsave (&ehci->lock, flags); - for (i = 0; i < urb->number_of_packets; i++) { - - /* NOTE: for now, we don't try to handle wraparound cases - * for IN (using sitd->hw_backpointer, like a FSTN), which - * means we never need two sitds for full speed packets. - */ - - /* free_list.next might be cache-hot ... but maybe - * the HC caches it too. avoid that issue for now. - */ - - /* prefer previously-allocated sitds */ - if (!list_empty(&stream->free_list)) { - sitd = list_entry (stream->free_list.prev, - struct ehci_sitd, sitd_list); - list_del (&sitd->sitd_list); - sitd_dma = sitd->sitd_dma; - } else { - spin_unlock_irqrestore (&ehci->lock, flags); - sitd = dma_pool_alloc (ehci->sitd_pool, mem_flags, - &sitd_dma); - spin_lock_irqsave (&ehci->lock, flags); - if (!sitd) { - iso_sched_free(stream, iso_sched); - spin_unlock_irqrestore(&ehci->lock, flags); - return -ENOMEM; - } - } - - memset (sitd, 0, sizeof *sitd); - sitd->sitd_dma = sitd_dma; - list_add (&sitd->sitd_list, &iso_sched->td_list); - } - - /* temporarily store schedule info in hcpriv */ - urb->hcpriv = iso_sched; - urb->error_count = 0; - - spin_unlock_irqrestore (&ehci->lock, flags); - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static inline void -sitd_patch( - struct ehci_hcd *ehci, - struct ehci_iso_stream *stream, - struct ehci_sitd *sitd, - struct ehci_iso_sched *iso_sched, - unsigned index -) -{ - struct ehci_iso_packet *uf = &iso_sched->packet [index]; - u64 bufp = uf->bufp; - - sitd->hw_next = EHCI_LIST_END(ehci); - sitd->hw_fullspeed_ep = stream->address; - sitd->hw_uframe = stream->splits; - sitd->hw_results = uf->transaction; - sitd->hw_backpointer = EHCI_LIST_END(ehci); - - bufp = uf->bufp; - sitd->hw_buf[0] = cpu_to_hc32(ehci, bufp); - sitd->hw_buf_hi[0] = cpu_to_hc32(ehci, bufp >> 32); - - sitd->hw_buf[1] = cpu_to_hc32(ehci, uf->buf1); - if (uf->cross) - bufp += 4096; - sitd->hw_buf_hi[1] = cpu_to_hc32(ehci, bufp >> 32); - sitd->index = index; -} - -static inline void -sitd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd) -{ - /* note: sitd ordering could matter (CSPLIT then SSPLIT) */ - sitd->sitd_next = ehci->pshadow [frame]; - sitd->hw_next = ehci->periodic [frame]; - ehci->pshadow [frame].sitd = sitd; - sitd->frame = frame; - wmb (); - ehci->periodic[frame] = cpu_to_hc32(ehci, sitd->sitd_dma | Q_TYPE_SITD); -} - -/* fit urb's sitds into the selected schedule slot; activate as needed */ -static int -sitd_link_urb ( - struct ehci_hcd *ehci, - struct urb *urb, - unsigned mod, - struct ehci_iso_stream *stream -) -{ - int packet; - unsigned next_uframe; - struct ehci_iso_sched *sched = urb->hcpriv; - struct ehci_sitd *sitd; - - next_uframe = stream->next_uframe; - - if (list_empty(&stream->td_list)) { - /* usbfs ignores TT bandwidth */ - ehci_to_hcd(ehci)->self.bandwidth_allocated - += stream->bandwidth; - ehci_vdbg (ehci, - "sched devp %s ep%d%s-iso [%d] %dms/%04x\n", - urb->dev->devpath, stream->bEndpointAddress & 0x0f, - (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out", - (next_uframe >> 3) & (ehci->periodic_size - 1), - stream->interval, hc32_to_cpu(ehci, stream->splits)); - } - - if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { - if (ehci->amd_pll_fix == 1) - usb_amd_quirk_pll_disable(); - } - - ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++; - - /* fill sITDs frame by frame */ - for (packet = 0, sitd = NULL; - packet < urb->number_of_packets; - packet++) { - - /* ASSERT: we have all necessary sitds */ - BUG_ON (list_empty (&sched->td_list)); - - /* ASSERT: no itds for this endpoint in this frame */ - - sitd = list_entry (sched->td_list.next, - struct ehci_sitd, sitd_list); - list_move_tail (&sitd->sitd_list, &stream->td_list); - sitd->stream = iso_stream_get (stream); - sitd->urb = urb; - - sitd_patch(ehci, stream, sitd, sched, packet); - sitd_link(ehci, (next_uframe >> 3) & (ehci->periodic_size - 1), - sitd); - - next_uframe += stream->interval << 3; - } - stream->next_uframe = next_uframe & (mod - 1); - - /* don't need that schedule data any more */ - iso_sched_free (stream, sched); - urb->hcpriv = NULL; - - timer_action (ehci, TIMER_IO_WATCHDOG); - return enable_periodic(ehci); -} - -/*-------------------------------------------------------------------------*/ - -#define SITD_ERRS (SITD_STS_ERR | SITD_STS_DBE | SITD_STS_BABBLE \ - | SITD_STS_XACT | SITD_STS_MMF) - -/* Process and recycle a completed SITD. Return true iff its urb completed, - * and hence its completion callback probably added things to the hardware - * schedule. - * - * Note that we carefully avoid recycling this descriptor until after any - * completion callback runs, so that it won't be reused quickly. That is, - * assuming (a) no more than two urbs per frame on this endpoint, and also - * (b) only this endpoint's completions submit URBs. It seems some silicon - * corrupts things if you reuse completed descriptors very quickly... - */ -static unsigned -sitd_complete ( - struct ehci_hcd *ehci, - struct ehci_sitd *sitd -) { - struct urb *urb = sitd->urb; - struct usb_iso_packet_descriptor *desc; - u32 t; - int urb_index = -1; - struct ehci_iso_stream *stream = sitd->stream; - struct usb_device *dev; - unsigned retval = false; - - urb_index = sitd->index; - desc = &urb->iso_frame_desc [urb_index]; - t = hc32_to_cpup(ehci, &sitd->hw_results); - - /* report transfer status */ - if (t & SITD_ERRS) { - urb->error_count++; - if (t & SITD_STS_DBE) - desc->status = usb_pipein (urb->pipe) - ? -ENOSR /* hc couldn't read */ - : -ECOMM; /* hc couldn't write */ - else if (t & SITD_STS_BABBLE) - desc->status = -EOVERFLOW; - else /* XACT, MMF, etc */ - desc->status = -EPROTO; - } else { - desc->status = 0; - desc->actual_length = desc->length - SITD_LENGTH(t); - urb->actual_length += desc->actual_length; - } - - /* handle completion now? */ - if ((urb_index + 1) != urb->number_of_packets) - goto done; - - /* ASSERT: it's really the last sitd for this urb - list_for_each_entry (sitd, &stream->td_list, sitd_list) - BUG_ON (sitd->urb == urb); - */ - - /* give urb back to the driver; completion often (re)submits */ - dev = urb->dev; - ehci_urb_done(ehci, urb, 0); - retval = true; - urb = NULL; - //(void) disable_periodic(ehci);//gri - ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--; - - if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { - if (ehci->amd_pll_fix == 1) - usb_amd_quirk_pll_enable(); - } - - if (list_is_singular(&stream->td_list)) { - ehci_to_hcd(ehci)->self.bandwidth_allocated - -= stream->bandwidth; - ehci_vdbg (ehci, - "deschedule devp %s ep%d%s-iso\n", - dev->devpath, stream->bEndpointAddress & 0x0f, - (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); - } - iso_stream_put (ehci, stream); - -done: - sitd->urb = NULL; - if (ehci->clock_frame != sitd->frame) { - /* OK to recycle this SITD now. */ - sitd->stream = NULL; - list_move(&sitd->sitd_list, &stream->free_list); - iso_stream_put(ehci, stream); - } else { - /* HW might remember this SITD, so we can't recycle it yet. - * Move it to a safe place until a new frame starts. - */ - list_move(&sitd->sitd_list, &ehci->cached_sitd_list); - if (stream->refcount == 2) { - /* If iso_stream_put() were called here, stream - * would be freed. Instead, just prevent reuse. - */ - stream->ep->hcpriv = NULL; - stream->ep = NULL; - } - } - return retval; -} - - -static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, - gfp_t mem_flags) -{ - int status = -EINVAL; - unsigned long flags; - struct ehci_iso_stream *stream; - - /* Get iso_stream head */ - stream = iso_stream_find (ehci, urb); - if (stream == NULL) { - ehci_dbg (ehci, "can't get iso stream\n"); - return -ENOMEM; - } - if (urb->interval != stream->interval) { - ehci_dbg (ehci, "can't change iso interval %d --> %d\n", - stream->interval, urb->interval); - goto done; - } - -#ifdef EHCI_URB_TRACE - ehci_dbg (ehci, - "submit %p dev%s ep%d%s-iso len %d\n", - urb, urb->dev->devpath, - usb_pipeendpoint (urb->pipe), - usb_pipein (urb->pipe) ? "in" : "out", - urb->transfer_buffer_length); -#endif - - /* allocate SITDs */ - status = sitd_urb_transaction (stream, ehci, urb, mem_flags); - if (status < 0) { - ehci_dbg (ehci, "can't init sitds\n"); - goto done; - } - - /* schedule ... need to lock */ - spin_lock_irqsave (&ehci->lock, flags); - if (unlikely(!HCD_HW_ACCESSIBLE(ehci_to_hcd(ehci)))) { - status = -ESHUTDOWN; - goto done_not_linked; - } - status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb); - if (unlikely(status)) - goto done_not_linked; - status = iso_stream_schedule(ehci, urb, stream); - if (status == 0) - sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); - else - usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); -done_not_linked: - spin_unlock_irqrestore (&ehci->lock, flags); - -done: - if (status < 0) - iso_stream_put (ehci, stream); - return status; -} - -/*-------------------------------------------------------------------------*/ - -static void free_cached_lists(struct ehci_hcd *ehci) -{ - struct ehci_itd *itd, *n; - struct ehci_sitd *sitd, *sn; - - list_for_each_entry_safe(itd, n, &ehci->cached_itd_list, itd_list) { - struct ehci_iso_stream *stream = itd->stream; - itd->stream = NULL; - list_move(&itd->itd_list, &stream->free_list); - iso_stream_put(ehci, stream); - } - - list_for_each_entry_safe(sitd, sn, &ehci->cached_sitd_list, sitd_list) { - struct ehci_iso_stream *stream = sitd->stream; - sitd->stream = NULL; - list_move(&sitd->sitd_list, &stream->free_list); - iso_stream_put(ehci, stream); - } -} - -/*-------------------------------------------------------------------------*/ - -static void -scan_periodic (struct ehci_hcd *ehci) -{ - unsigned now_uframe, frame, clock, clock_frame, mod; - unsigned modified; - - mod = ehci->periodic_size << 3; - - /* - * When running, scan from last scan point up to "now" - * else clean up by scanning everything that's left. - * Touches as few pages as possible: cache-friendly. - */ - now_uframe = ehci->next_uframe; - if (ehci->rh_state == EHCI_RH_RUNNING) { - clock = ehci_read_frame_index(ehci); - clock_frame = (clock >> 3) & (ehci->periodic_size - 1); - } else { - clock = now_uframe + mod - 1; - clock_frame = -1; - } - if (ehci->clock_frame != clock_frame) { - free_cached_lists(ehci); - ehci->clock_frame = clock_frame; - } - clock &= mod - 1; - clock_frame = clock >> 3; - ++ehci->periodic_stamp; - - for (;;) { - union ehci_shadow q, *q_p; - __hc32 type, *hw_p; - unsigned incomplete = false; - - frame = now_uframe >> 3; - -restart: - /* scan each element in frame's queue for completions */ - q_p = &ehci->pshadow [frame]; - hw_p = &ehci->periodic [frame]; - q.ptr = q_p->ptr; - type = Q_NEXT_TYPE(ehci, *hw_p); - modified = 0; - - while (q.ptr != NULL) { - unsigned uf; - union ehci_shadow temp; - int live; - - live = (ehci->rh_state == EHCI_RH_RUNNING); - switch (hc32_to_cpu(ehci, type)) { - case Q_TYPE_QH: - /* handle any completions */ - temp.qh = qh_get (q.qh); - type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next); - q = q.qh->qh_next; - if (temp.qh->stamp != ehci->periodic_stamp) { - modified = qh_completions(ehci, temp.qh); - if (!modified) - temp.qh->stamp = ehci->periodic_stamp; - if (unlikely(list_empty(&temp.qh->qtd_list) || - temp.qh->needs_rescan)) - intr_deschedule(ehci, temp.qh); - } - qh_put (temp.qh); - break; - case Q_TYPE_FSTN: - /* for "save place" FSTNs, look at QH entries - * in the previous frame for completions. - */ - if (q.fstn->hw_prev != EHCI_LIST_END(ehci)) { - dbg ("ignoring completions from FSTNs"); - } - type = Q_NEXT_TYPE(ehci, q.fstn->hw_next); - q = q.fstn->fstn_next; - break; - case Q_TYPE_ITD: - /* If this ITD is still active, leave it for - * later processing ... check the next entry. - * No need to check for activity unless the - * frame is current. - */ - if (frame == clock_frame && live) { - rmb(); - for (uf = 0; uf < 8; uf++) { - if (q.itd->hw_transaction[uf] & - ITD_ACTIVE(ehci)) - break; - } - if (uf < 8) { - incomplete = true; - q_p = &q.itd->itd_next; - hw_p = &q.itd->hw_next; - type = Q_NEXT_TYPE(ehci, - q.itd->hw_next); - q = *q_p; - break; - } - } - - /* Take finished ITDs out of the schedule - * and process them: recycle, maybe report - * URB completion. HC won't cache the - * pointer for much longer, if at all. - */ - *q_p = q.itd->itd_next; - if (!ehci->use_dummy_qh || - q.itd->hw_next != EHCI_LIST_END(ehci)) - *hw_p = q.itd->hw_next; - else - *hw_p = ehci->dummy->qh_dma; - type = Q_NEXT_TYPE(ehci, q.itd->hw_next); - wmb(); - modified = itd_complete (ehci, q.itd); - q = *q_p; - break; - case Q_TYPE_SITD: - /* If this SITD is still active, leave it for - * later processing ... check the next entry. - * No need to check for activity unless the - * frame is current. - */ - if (((frame == clock_frame) || - (((frame + 1) & (ehci->periodic_size - 1)) - == clock_frame)) - && live - && (q.sitd->hw_results & - SITD_ACTIVE(ehci))) { - - incomplete = true; - q_p = &q.sitd->sitd_next; - hw_p = &q.sitd->hw_next; - type = Q_NEXT_TYPE(ehci, - q.sitd->hw_next); - q = *q_p; - break; - } - - /* Take finished SITDs out of the schedule - * and process them: recycle, maybe report - * URB completion. - */ - *q_p = q.sitd->sitd_next; - if (!ehci->use_dummy_qh || - q.sitd->hw_next != EHCI_LIST_END(ehci)) - *hw_p = q.sitd->hw_next; - else - *hw_p = ehci->dummy->qh_dma; - type = Q_NEXT_TYPE(ehci, q.sitd->hw_next); - wmb(); - modified = sitd_complete (ehci, q.sitd); - q = *q_p; - break; - default: - dbg ("corrupt type %d frame %d shadow %p", - type, frame, q.ptr); - // BUG (); - q.ptr = NULL; - } - - /* assume completion callbacks modify the queue */ - if (unlikely (modified)) { - if (likely(ehci->periodic_sched > 0)) - goto restart; - /* short-circuit this scan */ - now_uframe = clock; - break; - } - } - - /* If we can tell we caught up to the hardware, stop now. - * We can't advance our scan without collecting the ISO - * transfers that are still pending in this frame. - */ - if (incomplete && ehci->rh_state == EHCI_RH_RUNNING) { - ehci->next_uframe = now_uframe; - break; - } - - // FIXME: this assumes we won't get lapped when - // latencies climb; that should be rare, but... - // detect it, and just go all the way around. - // FLR might help detect this case, so long as latencies - // don't exceed periodic_size msec (default 1.024 sec). - - // FIXME: likewise assumes HC doesn't halt mid-scan - - if (now_uframe == clock) { - unsigned now; - - if (ehci->rh_state != EHCI_RH_RUNNING - || ehci->periodic_sched == 0) - break; - ehci->next_uframe = now_uframe; - now = ehci_read_frame_index(ehci) & (mod - 1); - if (now_uframe == now) - break; - - /* rescan the rest of this frame, then ... */ - clock = now; - clock_frame = clock >> 3; - if (ehci->clock_frame != clock_frame) { - free_cached_lists(ehci); - ehci->clock_frame = clock_frame; - ++ehci->periodic_stamp; - } - } else { - now_uframe++; - now_uframe &= mod - 1; - } - } -} diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-sh.c b/ANDROID_3.4.5/drivers/usb/host/ehci-sh.c deleted file mode 100644 index 9d9cf47d..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-sh.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * SuperH EHCI host controller driver - * - * Copyright (C) 2010 Paul Mundt - * - * Based on ohci-sh.c and ehci-atmel.c. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ -#include -#include - -struct ehci_sh_priv { - struct clk *iclk, *fclk; - struct usb_hcd *hcd; -}; - -static int ehci_sh_reset(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int ret; - - ehci->caps = hcd->regs; - ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci, - &ehci->caps->hc_capbase)); - - dbg_hcs_params(ehci, "reset"); - dbg_hcc_params(ehci, "reset"); - - ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); - - ret = ehci_halt(ehci); - if (unlikely(ret)) - return ret; - - ret = ehci_init(hcd); - if (unlikely(ret)) - return ret; - - ehci->sbrn = 0x20; - - ehci_reset(ehci); - ehci_port_power(ehci, 0); - - return ret; -} - -static const struct hc_driver ehci_sh_hc_driver = { - .description = hcd_name, - .product_desc = "SuperH EHCI", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_USB2 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .reset = ehci_sh_reset, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - -#ifdef CONFIG_PM - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, -#endif - - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static int ehci_hcd_sh_probe(struct platform_device *pdev) -{ - const struct hc_driver *driver = &ehci_sh_hc_driver; - struct resource *res; - struct ehci_sh_priv *priv; - struct usb_hcd *hcd; - int irq, ret; - - if (usb_disabled()) - return -ENODEV; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, - "Found HC with no register addr. Check %s setup!\n", - dev_name(&pdev->dev)); - ret = -ENODEV; - goto fail_create_hcd; - } - - irq = platform_get_irq(pdev, 0); - if (irq <= 0) { - dev_err(&pdev->dev, - "Found HC with no IRQ. Check %s setup!\n", - dev_name(&pdev->dev)); - ret = -ENODEV; - goto fail_create_hcd; - } - - /* initialize hcd */ - hcd = usb_create_hcd(&ehci_sh_hc_driver, &pdev->dev, - dev_name(&pdev->dev)); - if (!hcd) { - ret = -ENOMEM; - goto fail_create_hcd; - } - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) { - dev_dbg(&pdev->dev, "controller already in use\n"); - ret = -EBUSY; - goto fail_request_resource; - } - - hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); - if (hcd->regs == NULL) { - dev_dbg(&pdev->dev, "error mapping memory\n"); - ret = -ENXIO; - goto fail_ioremap; - } - - priv = kmalloc(sizeof(struct ehci_sh_priv), GFP_KERNEL); - if (!priv) { - dev_dbg(&pdev->dev, "error allocating priv data\n"); - ret = -ENOMEM; - goto fail_alloc; - } - - /* These are optional, we don't care if they fail */ - priv->fclk = clk_get(&pdev->dev, "usb_fck"); - if (IS_ERR(priv->fclk)) - priv->fclk = NULL; - - priv->iclk = clk_get(&pdev->dev, "usb_ick"); - if (IS_ERR(priv->iclk)) - priv->iclk = NULL; - - clk_enable(priv->fclk); - clk_enable(priv->iclk); - - ret = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (ret != 0) { - dev_err(&pdev->dev, "Failed to add hcd"); - goto fail_add_hcd; - } - - priv->hcd = hcd; - platform_set_drvdata(pdev, priv); - - return ret; - -fail_add_hcd: - clk_disable(priv->iclk); - clk_disable(priv->fclk); - - clk_put(priv->iclk); - clk_put(priv->fclk); - - kfree(priv); -fail_alloc: - iounmap(hcd->regs); -fail_ioremap: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -fail_request_resource: - usb_put_hcd(hcd); -fail_create_hcd: - dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), ret); - - return ret; -} - -static int __exit ehci_hcd_sh_remove(struct platform_device *pdev) -{ - struct ehci_sh_priv *priv = platform_get_drvdata(pdev); - struct usb_hcd *hcd = priv->hcd; - - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - platform_set_drvdata(pdev, NULL); - - clk_disable(priv->fclk); - clk_disable(priv->iclk); - - clk_put(priv->fclk); - clk_put(priv->iclk); - - kfree(priv); - - return 0; -} - -static void ehci_hcd_sh_shutdown(struct platform_device *pdev) -{ - struct ehci_sh_priv *priv = platform_get_drvdata(pdev); - struct usb_hcd *hcd = priv->hcd; - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - -static struct platform_driver ehci_hcd_sh_driver = { - .probe = ehci_hcd_sh_probe, - .remove = __exit_p(ehci_hcd_sh_remove), - .shutdown = ehci_hcd_sh_shutdown, - .driver = { - .name = "sh_ehci", - .owner = THIS_MODULE, - }, -}; - -MODULE_ALIAS("platform:sh_ehci"); diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-spear.c b/ANDROID_3.4.5/drivers/usb/host/ehci-spear.c deleted file mode 100644 index 6e928559..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-spear.c +++ /dev/null @@ -1,291 +0,0 @@ -/* -* Driver for EHCI HCD on SPEAR SOC -* -* Copyright (C) 2010 ST Micro Electronics, -* Deepak Sikri -* -* Based on various ehci-*.c drivers -* -* This file is subject to the terms and conditions of the GNU General Public -* License. See the file COPYING in the main directory of this archive for -* more details. -*/ - -#include -#include -#include -#include - -struct spear_ehci { - struct ehci_hcd ehci; - struct clk *clk; -}; - -#define to_spear_ehci(hcd) (struct spear_ehci *)hcd_to_ehci(hcd) - -static void spear_start_ehci(struct spear_ehci *ehci) -{ - clk_enable(ehci->clk); -} - -static void spear_stop_ehci(struct spear_ehci *ehci) -{ - clk_disable(ehci->clk); -} - -static int ehci_spear_setup(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval = 0; - - /* registers start at offset 0x0 */ - ehci->caps = hcd->regs; - ehci->regs = hcd->regs + HC_LENGTH(ehci, ehci_readl(ehci, - &ehci->caps->hc_capbase)); - /* cache this readonly data; minimize chip reads */ - ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); - retval = ehci_halt(ehci); - if (retval) - return retval; - - retval = ehci_init(hcd); - if (retval) - return retval; - - ehci_reset(ehci); - ehci_port_power(ehci, 0); - - return retval; -} - -static const struct hc_driver ehci_spear_hc_driver = { - .description = hcd_name, - .product_desc = "SPEAr EHCI", - .hcd_priv_size = sizeof(struct spear_ehci), - - /* generic hardware linkage */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* basic lifecycle operations */ - .reset = ehci_spear_setup, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* managing i/o requests and associated device resources */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* scheduling support */ - .get_frame_number = ehci_get_frame, - - /* root hub support */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -#ifdef CONFIG_PM -static int ehci_spear_drv_suspend(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - unsigned long flags; - int rc = 0; - - if (time_before(jiffies, ehci->next_statechange)) - msleep(10); - - /* - * Root hub was already suspended. Disable irq emission and mark HW - * unaccessible. The PM and USB cores make sure that the root hub is - * either suspended or stopped. - */ - spin_lock_irqsave(&ehci->lock, flags); - ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev)); - ehci_writel(ehci, 0, &ehci->regs->intr_enable); - ehci_readl(ehci, &ehci->regs->intr_enable); - spin_unlock_irqrestore(&ehci->lock, flags); - - return rc; -} - -static int ehci_spear_drv_resume(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - - if (time_before(jiffies, ehci->next_statechange)) - msleep(100); - - if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) { - int mask = INTR_MASK; - - ehci_prepare_ports_for_controller_resume(ehci); - - if (!hcd->self.root_hub->do_remote_wakeup) - mask &= ~STS_PCD; - - ehci_writel(ehci, mask, &ehci->regs->intr_enable); - ehci_readl(ehci, &ehci->regs->intr_enable); - return 0; - } - - usb_root_hub_lost_power(hcd->self.root_hub); - - /* - * Else reset, to cope with power loss or flush-to-storage style - * "resume" having let BIOS kick in during reboot. - */ - ehci_halt(ehci); - ehci_reset(ehci); - - /* emptying the schedule aborts any urbs */ - spin_lock_irq(&ehci->lock); - if (ehci->reclaim) - end_unlink_async(ehci); - - ehci_work(ehci); - spin_unlock_irq(&ehci->lock); - - ehci_writel(ehci, ehci->command, &ehci->regs->command); - ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); - ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ - - /* here we "know" root ports should always stay powered */ - ehci_port_power(ehci, 1); - return 0; -} -#endif /* CONFIG_PM */ - -static SIMPLE_DEV_PM_OPS(ehci_spear_pm_ops, ehci_spear_drv_suspend, - ehci_spear_drv_resume); - -static int spear_ehci_hcd_drv_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd ; - struct spear_ehci *ehci; - struct resource *res; - struct clk *usbh_clk; - const struct hc_driver *driver = &ehci_spear_hc_driver; - int *pdata = pdev->dev.platform_data; - int irq, retval; - char clk_name[20] = "usbh_clk"; - - if (pdata == NULL) - return -EFAULT; - - if (usb_disabled()) - return -ENODEV; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - retval = irq; - goto fail_irq_get; - } - - if (*pdata >= 0) - sprintf(clk_name, "usbh.%01d_clk", *pdata); - - usbh_clk = clk_get(NULL, clk_name); - if (IS_ERR(usbh_clk)) { - dev_err(&pdev->dev, "Error getting interface clock\n"); - retval = PTR_ERR(usbh_clk); - goto fail_get_usbh_clk; - } - - hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - retval = -ENOMEM; - goto fail_create_hcd; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - retval = -ENODEV; - goto fail_request_resource; - } - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) { - retval = -EBUSY; - goto fail_request_resource; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (hcd->regs == NULL) { - dev_dbg(&pdev->dev, "error mapping memory\n"); - retval = -ENOMEM; - goto fail_ioremap; - } - - ehci = (struct spear_ehci *)hcd_to_ehci(hcd); - ehci->clk = usbh_clk; - - spear_start_ehci(ehci); - retval = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (retval) - goto fail_add_hcd; - - return retval; - -fail_add_hcd: - spear_stop_ehci(ehci); - iounmap(hcd->regs); -fail_ioremap: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -fail_request_resource: - usb_put_hcd(hcd); -fail_create_hcd: - clk_put(usbh_clk); -fail_get_usbh_clk: -fail_irq_get: - dev_err(&pdev->dev, "init fail, %d\n", retval); - - return retval ; -} - -static int spear_ehci_hcd_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct spear_ehci *ehci_p = to_spear_ehci(hcd); - - if (!hcd) - return 0; - if (in_interrupt()) - BUG(); - usb_remove_hcd(hcd); - - if (ehci_p->clk) - spear_stop_ehci(ehci_p); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - - if (ehci_p->clk) - clk_put(ehci_p->clk); - - return 0; -} - -static struct platform_driver spear_ehci_hcd_driver = { - .probe = spear_ehci_hcd_drv_probe, - .remove = spear_ehci_hcd_drv_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "spear-ehci", - .bus = &platform_bus_type, - .pm = &ehci_spear_pm_ops, - } -}; - -MODULE_ALIAS("platform:spear-ehci"); diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-sysfs.c b/ANDROID_3.4.5/drivers/usb/host/ehci-sysfs.c deleted file mode 100644 index 14ced00b..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-sysfs.c +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (C) 2007 by Alan Stern - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* this file is part of ehci-hcd.c */ - - -/* Display the ports dedicated to the companion controller */ -static ssize_t show_companion(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct ehci_hcd *ehci; - int nports, index, n; - int count = PAGE_SIZE; - char *ptr = buf; - - ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); - nports = HCS_N_PORTS(ehci->hcs_params); - - for (index = 0; index < nports; ++index) { - if (test_bit(index, &ehci->companion_ports)) { - n = scnprintf(ptr, count, "%d\n", index + 1); - ptr += n; - count -= n; - } - } - return ptr - buf; -} - -/* - * Dedicate or undedicate a port to the companion controller. - * Syntax is "[-]portnum", where a leading '-' sign means - * return control of the port to the EHCI controller. - */ -static ssize_t store_companion(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ehci_hcd *ehci; - int portnum, new_owner; - - ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); - new_owner = PORT_OWNER; /* Owned by companion */ - if (sscanf(buf, "%d", &portnum) != 1) - return -EINVAL; - if (portnum < 0) { - portnum = - portnum; - new_owner = 0; /* Owned by EHCI */ - } - if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params)) - return -ENOENT; - portnum--; - if (new_owner) - set_bit(portnum, &ehci->companion_ports); - else - clear_bit(portnum, &ehci->companion_ports); - set_owner(ehci, portnum, new_owner); - return count; -} -static DEVICE_ATTR(companion, 0644, show_companion, store_companion); - - -/* - * Display / Set uframe_periodic_max - */ -static ssize_t show_uframe_periodic_max(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct ehci_hcd *ehci; - int n; - - ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); - n = scnprintf(buf, PAGE_SIZE, "%d\n", ehci->uframe_periodic_max); - return n; -} - - -static ssize_t store_uframe_periodic_max(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ehci_hcd *ehci; - unsigned uframe_periodic_max; - unsigned frame, uframe; - unsigned short allocated_max; - unsigned long flags; - ssize_t ret; - - ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev))); - if (kstrtouint(buf, 0, &uframe_periodic_max) < 0) - return -EINVAL; - - if (uframe_periodic_max < 100 || uframe_periodic_max >= 125) { - ehci_info(ehci, "rejecting invalid request for " - "uframe_periodic_max=%u\n", uframe_periodic_max); - return -EINVAL; - } - - ret = -EINVAL; - - /* - * lock, so that our checking does not race with possible periodic - * bandwidth allocation through submitting new urbs. - */ - spin_lock_irqsave (&ehci->lock, flags); - - /* - * for request to decrease max periodic bandwidth, we have to check - * every microframe in the schedule to see whether the decrease is - * possible. - */ - if (uframe_periodic_max < ehci->uframe_periodic_max) { - allocated_max = 0; - - for (frame = 0; frame < ehci->periodic_size; ++frame) - for (uframe = 0; uframe < 7; ++uframe) - allocated_max = max(allocated_max, - periodic_usecs (ehci, frame, uframe)); - - if (allocated_max > uframe_periodic_max) { - ehci_info(ehci, - "cannot decrease uframe_periodic_max becase " - "periodic bandwidth is already allocated " - "(%u > %u)\n", - allocated_max, uframe_periodic_max); - goto out_unlock; - } - } - - /* increasing is always ok */ - - ehci_info(ehci, "setting max periodic bandwidth to %u%% " - "(== %u usec/uframe)\n", - 100*uframe_periodic_max/125, uframe_periodic_max); - - if (uframe_periodic_max != 100) - ehci_warn(ehci, "max periodic bandwidth set is non-standard\n"); - - ehci->uframe_periodic_max = uframe_periodic_max; - ret = count; - -out_unlock: - spin_unlock_irqrestore (&ehci->lock, flags); - return ret; -} -static DEVICE_ATTR(uframe_periodic_max, 0644, show_uframe_periodic_max, store_uframe_periodic_max); - - -static inline int create_sysfs_files(struct ehci_hcd *ehci) -{ - struct device *controller = ehci_to_hcd(ehci)->self.controller; - int i = 0; - - /* with integrated TT there is no companion! */ - if (!ehci_is_TDI(ehci)) - i = device_create_file(controller, &dev_attr_companion); - if (i) - goto out; - - i = device_create_file(controller, &dev_attr_uframe_periodic_max); -out: - return i; -} - -static inline void remove_sysfs_files(struct ehci_hcd *ehci) -{ - struct device *controller = ehci_to_hcd(ehci)->self.controller; - - /* with integrated TT there is no companion! */ - if (!ehci_is_TDI(ehci)) - device_remove_file(controller, &dev_attr_companion); - - device_remove_file(controller, &dev_attr_uframe_periodic_max); -} diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-tegra.c b/ANDROID_3.4.5/drivers/usb/host/ehci-tegra.c deleted file mode 100644 index f214a80c..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-tegra.c +++ /dev/null @@ -1,873 +0,0 @@ -/* - * EHCI-compliant USB host controller driver for NVIDIA Tegra SoCs - * - * Copyright (C) 2010 Google, Inc. - * Copyright (C) 2009 NVIDIA Corporation - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define TEGRA_USB_DMA_ALIGN 32 - -struct tegra_ehci_hcd { - struct ehci_hcd *ehci; - struct tegra_usb_phy *phy; - struct clk *clk; - struct clk *emc_clk; - struct usb_phy *transceiver; - int host_resumed; - int port_resuming; - enum tegra_usb_phy_port_speed port_speed; -}; - -static void tegra_ehci_power_up(struct usb_hcd *hcd) -{ - struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); - - clk_enable(tegra->emc_clk); - clk_enable(tegra->clk); - tegra_usb_phy_power_on(tegra->phy); - tegra->host_resumed = 1; -} - -static void tegra_ehci_power_down(struct usb_hcd *hcd) -{ - struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); - - tegra->host_resumed = 0; - tegra_usb_phy_power_off(tegra->phy); - clk_disable(tegra->clk); - clk_disable(tegra->emc_clk); -} - -static int tegra_ehci_internal_port_reset( - struct ehci_hcd *ehci, - u32 __iomem *portsc_reg -) -{ - u32 temp; - unsigned long flags; - int retval = 0; - int i, tries; - u32 saved_usbintr; - - spin_lock_irqsave(&ehci->lock, flags); - saved_usbintr = ehci_readl(ehci, &ehci->regs->intr_enable); - /* disable USB interrupt */ - ehci_writel(ehci, 0, &ehci->regs->intr_enable); - spin_unlock_irqrestore(&ehci->lock, flags); - - /* - * Here we have to do Port Reset at most twice for - * Port Enable bit to be set. - */ - for (i = 0; i < 2; i++) { - temp = ehci_readl(ehci, portsc_reg); - temp |= PORT_RESET; - ehci_writel(ehci, temp, portsc_reg); - mdelay(10); - temp &= ~PORT_RESET; - ehci_writel(ehci, temp, portsc_reg); - mdelay(1); - tries = 100; - do { - mdelay(1); - /* - * Up to this point, Port Enable bit is - * expected to be set after 2 ms waiting. - * USB1 usually takes extra 45 ms, for safety, - * we take 100 ms as timeout. - */ - temp = ehci_readl(ehci, portsc_reg); - } while (!(temp & PORT_PE) && tries--); - if (temp & PORT_PE) - break; - } - if (i == 2) - retval = -ETIMEDOUT; - - /* - * Clear Connect Status Change bit if it's set. - * We can't clear PORT_PEC. It will also cause PORT_PE to be cleared. - */ - if (temp & PORT_CSC) - ehci_writel(ehci, PORT_CSC, portsc_reg); - - /* - * Write to clear any interrupt status bits that might be set - * during port reset. - */ - temp = ehci_readl(ehci, &ehci->regs->status); - ehci_writel(ehci, temp, &ehci->regs->status); - - /* restore original interrupt enable bits */ - ehci_writel(ehci, saved_usbintr, &ehci->regs->intr_enable); - return retval; -} - -static int tegra_ehci_hub_control( - struct usb_hcd *hcd, - u16 typeReq, - u16 wValue, - u16 wIndex, - char *buf, - u16 wLength -) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); - u32 __iomem *status_reg; - u32 temp; - unsigned long flags; - int retval = 0; - - status_reg = &ehci->regs->port_status[(wIndex & 0xff) - 1]; - - spin_lock_irqsave(&ehci->lock, flags); - - /* - * In ehci_hub_control() for USB_PORT_FEAT_ENABLE clears the other bits - * that are write on clear, by writing back the register read value, so - * USB_PORT_FEAT_ENABLE is handled by masking the set on clear bits - */ - if (typeReq == ClearPortFeature && wValue == USB_PORT_FEAT_ENABLE) { - temp = ehci_readl(ehci, status_reg) & ~PORT_RWC_BITS; - ehci_writel(ehci, temp & ~PORT_PE, status_reg); - goto done; - } - - else if (typeReq == GetPortStatus) { - temp = ehci_readl(ehci, status_reg); - if (tegra->port_resuming && !(temp & PORT_SUSPEND)) { - /* Resume completed, re-enable disconnect detection */ - tegra->port_resuming = 0; - tegra_usb_phy_postresume(tegra->phy); - } - } - - else if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) { - temp = ehci_readl(ehci, status_reg); - if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0) { - retval = -EPIPE; - goto done; - } - - temp &= ~PORT_WKCONN_E; - temp |= PORT_WKDISC_E | PORT_WKOC_E; - ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); - - /* - * If a transaction is in progress, there may be a delay in - * suspending the port. Poll until the port is suspended. - */ - if (handshake(ehci, status_reg, PORT_SUSPEND, - PORT_SUSPEND, 5000)) - pr_err("%s: timeout waiting for SUSPEND\n", __func__); - - set_bit((wIndex & 0xff) - 1, &ehci->suspended_ports); - goto done; - } - - /* For USB1 port we need to issue Port Reset twice internally */ - if (tegra->phy->instance == 0 && - (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_RESET)) { - spin_unlock_irqrestore(&ehci->lock, flags); - return tegra_ehci_internal_port_reset(ehci, status_reg); - } - - /* - * Tegra host controller will time the resume operation to clear the bit - * when the port control state switches to HS or FS Idle. This behavior - * is different from EHCI where the host controller driver is required - * to set this bit to a zero after the resume duration is timed in the - * driver. - */ - else if (typeReq == ClearPortFeature && - wValue == USB_PORT_FEAT_SUSPEND) { - temp = ehci_readl(ehci, status_reg); - if ((temp & PORT_RESET) || !(temp & PORT_PE)) { - retval = -EPIPE; - goto done; - } - - if (!(temp & PORT_SUSPEND)) - goto done; - - /* Disable disconnect detection during port resume */ - tegra_usb_phy_preresume(tegra->phy); - - ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25); - - temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); - /* start resume signalling */ - ehci_writel(ehci, temp | PORT_RESUME, status_reg); - set_bit(wIndex-1, &ehci->resuming_ports); - - spin_unlock_irqrestore(&ehci->lock, flags); - msleep(20); - spin_lock_irqsave(&ehci->lock, flags); - - /* Poll until the controller clears RESUME and SUSPEND */ - if (handshake(ehci, status_reg, PORT_RESUME, 0, 2000)) - pr_err("%s: timeout waiting for RESUME\n", __func__); - if (handshake(ehci, status_reg, PORT_SUSPEND, 0, 2000)) - pr_err("%s: timeout waiting for SUSPEND\n", __func__); - - ehci->reset_done[wIndex-1] = 0; - clear_bit(wIndex-1, &ehci->resuming_ports); - - tegra->port_resuming = 1; - goto done; - } - - spin_unlock_irqrestore(&ehci->lock, flags); - - /* Handle the hub control events here */ - return ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); -done: - spin_unlock_irqrestore(&ehci->lock, flags); - return retval; -} - -static void tegra_ehci_restart(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - - ehci_reset(ehci); - - /* setup the frame list and Async q heads */ - ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list); - ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next); - /* setup the command register and set the controller in RUN mode */ - ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET); - ehci->command |= CMD_RUN; - ehci_writel(ehci, ehci->command, &ehci->regs->command); - - down_write(&ehci_cf_port_reset_rwsem); - ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); - /* flush posted writes */ - ehci_readl(ehci, &ehci->regs->command); - up_write(&ehci_cf_port_reset_rwsem); -} - -static void tegra_ehci_shutdown(struct usb_hcd *hcd) -{ - struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); - - /* ehci_shutdown touches the USB controller registers, make sure - * controller has clocks to it */ - if (!tegra->host_resumed) - tegra_ehci_power_up(hcd); - - ehci_shutdown(hcd); -} - -static int tegra_ehci_setup(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; - - /* EHCI registers start at offset 0x100 */ - ehci->caps = hcd->regs + 0x100; - ehci->regs = hcd->regs + 0x100 + - HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase)); - - dbg_hcs_params(ehci, "reset"); - dbg_hcc_params(ehci, "reset"); - - /* cache this readonly data; minimize chip reads */ - ehci->hcs_params = readl(&ehci->caps->hcs_params); - - /* switch to host mode */ - hcd->has_tt = 1; - ehci_reset(ehci); - - retval = ehci_halt(ehci); - if (retval) - return retval; - - /* data structure init */ - retval = ehci_init(hcd); - if (retval) - return retval; - - ehci->sbrn = 0x20; - - ehci_port_power(ehci, 1); - return retval; -} - -struct temp_buffer { - void *kmalloc_ptr; - void *old_xfer_buffer; - u8 data[0]; -}; - -static void free_temp_buffer(struct urb *urb) -{ - enum dma_data_direction dir; - struct temp_buffer *temp; - - if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER)) - return; - - dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - - temp = container_of(urb->transfer_buffer, struct temp_buffer, - data); - - if (dir == DMA_FROM_DEVICE) - memcpy(temp->old_xfer_buffer, temp->data, - urb->transfer_buffer_length); - urb->transfer_buffer = temp->old_xfer_buffer; - kfree(temp->kmalloc_ptr); - - urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER; -} - -static int alloc_temp_buffer(struct urb *urb, gfp_t mem_flags) -{ - enum dma_data_direction dir; - struct temp_buffer *temp, *kmalloc_ptr; - size_t kmalloc_size; - - if (urb->num_sgs || urb->sg || - urb->transfer_buffer_length == 0 || - !((uintptr_t)urb->transfer_buffer & (TEGRA_USB_DMA_ALIGN - 1))) - return 0; - - dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - - /* Allocate a buffer with enough padding for alignment */ - kmalloc_size = urb->transfer_buffer_length + - sizeof(struct temp_buffer) + TEGRA_USB_DMA_ALIGN - 1; - - kmalloc_ptr = kmalloc(kmalloc_size, mem_flags); - if (!kmalloc_ptr) - return -ENOMEM; - - /* Position our struct temp_buffer such that data is aligned */ - temp = PTR_ALIGN(kmalloc_ptr + 1, TEGRA_USB_DMA_ALIGN) - 1; - - temp->kmalloc_ptr = kmalloc_ptr; - temp->old_xfer_buffer = urb->transfer_buffer; - if (dir == DMA_TO_DEVICE) - memcpy(temp->data, urb->transfer_buffer, - urb->transfer_buffer_length); - urb->transfer_buffer = temp->data; - - urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER; - - return 0; -} - -static int tegra_ehci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, - gfp_t mem_flags) -{ - int ret; - - ret = alloc_temp_buffer(urb, mem_flags); - if (ret) - return ret; - - ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags); - if (ret) - free_temp_buffer(urb); - - return ret; -} - -static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) -{ - usb_hcd_unmap_urb_for_dma(hcd, urb); - free_temp_buffer(urb); -} - -static const struct hc_driver tegra_ehci_hc_driver = { - .description = hcd_name, - .product_desc = "Tegra EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - - .flags = HCD_USB2 | HCD_MEMORY, - - .reset = tegra_ehci_setup, - .irq = ehci_irq, - - .start = ehci_run, - .stop = ehci_stop, - .shutdown = tegra_ehci_shutdown, - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .map_urb_for_dma = tegra_ehci_map_urb_for_dma, - .unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma, - .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 = tegra_ehci_hub_control, - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -#ifdef CONFIG_PM - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, -#endif - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, -}; - -static int setup_vbus_gpio(struct platform_device *pdev) -{ - int err = 0; - int gpio; - - if (!pdev->dev.of_node) - return 0; - - gpio = of_get_named_gpio(pdev->dev.of_node, "nvidia,vbus-gpio", 0); - if (!gpio_is_valid(gpio)) - return 0; - - err = gpio_request(gpio, "vbus_gpio"); - if (err) { - dev_err(&pdev->dev, "can't request vbus gpio %d", gpio); - return err; - } - err = gpio_direction_output(gpio, 1); - if (err) { - dev_err(&pdev->dev, "can't enable vbus\n"); - return err; - } - - return err; -} - -#ifdef CONFIG_PM - -static int controller_suspend(struct device *dev) -{ - struct tegra_ehci_hcd *tegra = - platform_get_drvdata(to_platform_device(dev)); - struct ehci_hcd *ehci = tegra->ehci; - struct usb_hcd *hcd = ehci_to_hcd(ehci); - struct ehci_regs __iomem *hw = ehci->regs; - unsigned long flags; - - if (time_before(jiffies, ehci->next_statechange)) - msleep(10); - - spin_lock_irqsave(&ehci->lock, flags); - - tegra->port_speed = (readl(&hw->port_status[0]) >> 26) & 0x3; - ehci_halt(ehci); - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - - spin_unlock_irqrestore(&ehci->lock, flags); - - tegra_ehci_power_down(hcd); - return 0; -} - -static int controller_resume(struct device *dev) -{ - struct tegra_ehci_hcd *tegra = - platform_get_drvdata(to_platform_device(dev)); - struct ehci_hcd *ehci = tegra->ehci; - struct usb_hcd *hcd = ehci_to_hcd(ehci); - struct ehci_regs __iomem *hw = ehci->regs; - unsigned long val; - - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - tegra_ehci_power_up(hcd); - - if (tegra->port_speed > TEGRA_USB_PHY_PORT_SPEED_HIGH) { - /* Wait for the phy to detect new devices - * before we restart the controller */ - msleep(10); - goto restart; - } - - /* Force the phy to keep data lines in suspend state */ - tegra_ehci_phy_restore_start(tegra->phy, tegra->port_speed); - - /* Enable host mode */ - tdi_reset(ehci); - - /* Enable Port Power */ - val = readl(&hw->port_status[0]); - val |= PORT_POWER; - writel(val, &hw->port_status[0]); - udelay(10); - - /* Check if the phy resume from LP0. When the phy resume from LP0 - * USB register will be reset. */ - if (!readl(&hw->async_next)) { - /* Program the field PTC based on the saved speed mode */ - val = readl(&hw->port_status[0]); - val &= ~PORT_TEST(~0); - if (tegra->port_speed == TEGRA_USB_PHY_PORT_SPEED_HIGH) - val |= PORT_TEST_FORCE; - else if (tegra->port_speed == TEGRA_USB_PHY_PORT_SPEED_FULL) - val |= PORT_TEST(6); - else if (tegra->port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW) - val |= PORT_TEST(7); - writel(val, &hw->port_status[0]); - udelay(10); - - /* Disable test mode by setting PTC field to NORMAL_OP */ - val = readl(&hw->port_status[0]); - val &= ~PORT_TEST(~0); - writel(val, &hw->port_status[0]); - udelay(10); - } - - /* Poll until CCS is enabled */ - if (handshake(ehci, &hw->port_status[0], PORT_CONNECT, - PORT_CONNECT, 2000)) { - pr_err("%s: timeout waiting for PORT_CONNECT\n", __func__); - goto restart; - } - - /* Poll until PE is enabled */ - if (handshake(ehci, &hw->port_status[0], PORT_PE, - PORT_PE, 2000)) { - pr_err("%s: timeout waiting for USB_PORTSC1_PE\n", __func__); - goto restart; - } - - /* Clear the PCI status, to avoid an interrupt taken upon resume */ - val = readl(&hw->status); - val |= STS_PCD; - writel(val, &hw->status); - - /* Put controller in suspend mode by writing 1 to SUSP bit of PORTSC */ - val = readl(&hw->port_status[0]); - if ((val & PORT_POWER) && (val & PORT_PE)) { - val |= PORT_SUSPEND; - writel(val, &hw->port_status[0]); - - /* Wait until port suspend completes */ - if (handshake(ehci, &hw->port_status[0], PORT_SUSPEND, - PORT_SUSPEND, 1000)) { - pr_err("%s: timeout waiting for PORT_SUSPEND\n", - __func__); - goto restart; - } - } - - tegra_ehci_phy_restore_end(tegra->phy); - goto done; - - restart: - if (tegra->port_speed <= TEGRA_USB_PHY_PORT_SPEED_HIGH) - tegra_ehci_phy_restore_end(tegra->phy); - - tegra_ehci_restart(hcd); - - done: - tegra_usb_phy_preresume(tegra->phy); - tegra->port_resuming = 1; - return 0; -} - -static int tegra_ehci_suspend(struct device *dev) -{ - struct tegra_ehci_hcd *tegra = - platform_get_drvdata(to_platform_device(dev)); - struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci); - int rc = 0; - - /* - * When system sleep is supported and USB controller wakeup is - * implemented: If the controller is runtime-suspended and the - * wakeup setting needs to be changed, call pm_runtime_resume(). - */ - if (HCD_HW_ACCESSIBLE(hcd)) - rc = controller_suspend(dev); - return rc; -} - -static int tegra_ehci_resume(struct device *dev) -{ - int rc; - - rc = controller_resume(dev); - if (rc == 0) { - pm_runtime_disable(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - } - return rc; -} - -static int tegra_ehci_runtime_suspend(struct device *dev) -{ - return controller_suspend(dev); -} - -static int tegra_ehci_runtime_resume(struct device *dev) -{ - return controller_resume(dev); -} - -static const struct dev_pm_ops tegra_ehci_pm_ops = { - .suspend = tegra_ehci_suspend, - .resume = tegra_ehci_resume, - .runtime_suspend = tegra_ehci_runtime_suspend, - .runtime_resume = tegra_ehci_runtime_resume, -}; - -#endif - -static u64 tegra_ehci_dma_mask = DMA_BIT_MASK(32); - -static int tegra_ehci_probe(struct platform_device *pdev) -{ - struct resource *res; - struct usb_hcd *hcd; - struct tegra_ehci_hcd *tegra; - struct tegra_ehci_platform_data *pdata; - int err = 0; - int irq; - int instance = pdev->id; - - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "Platform data missing\n"); - return -EINVAL; - } - - /* Right now device-tree probed devices don't get dma_mask set. - * Since shared usb code relies on it, set it here for now. - * Once we have dma capability bindings this can go away. - */ - if (!pdev->dev.dma_mask) - pdev->dev.dma_mask = &tegra_ehci_dma_mask; - - setup_vbus_gpio(pdev); - - tegra = kzalloc(sizeof(struct tegra_ehci_hcd), GFP_KERNEL); - if (!tegra) - return -ENOMEM; - - hcd = usb_create_hcd(&tegra_ehci_hc_driver, &pdev->dev, - dev_name(&pdev->dev)); - if (!hcd) { - dev_err(&pdev->dev, "Unable to create HCD\n"); - err = -ENOMEM; - goto fail_hcd; - } - - platform_set_drvdata(pdev, tegra); - - tegra->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(tegra->clk)) { - dev_err(&pdev->dev, "Can't get ehci clock\n"); - err = PTR_ERR(tegra->clk); - goto fail_clk; - } - - err = clk_enable(tegra->clk); - if (err) - goto fail_clken; - - tegra->emc_clk = clk_get(&pdev->dev, "emc"); - if (IS_ERR(tegra->emc_clk)) { - dev_err(&pdev->dev, "Can't get emc clock\n"); - err = PTR_ERR(tegra->emc_clk); - goto fail_emc_clk; - } - - clk_enable(tegra->emc_clk); - clk_set_rate(tegra->emc_clk, 400000000); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Failed to get I/O memory\n"); - err = -ENXIO; - goto fail_io; - } - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - hcd->regs = ioremap(res->start, resource_size(res)); - if (!hcd->regs) { - dev_err(&pdev->dev, "Failed to remap I/O memory\n"); - err = -ENOMEM; - goto fail_io; - } - - /* This is pretty ugly and needs to be fixed when we do only - * device-tree probing. Old code relies on the platform_device - * numbering that we lack for device-tree-instantiated devices. - */ - if (instance < 0) { - switch (res->start) { - case TEGRA_USB_BASE: - instance = 0; - break; - case TEGRA_USB2_BASE: - instance = 1; - break; - case TEGRA_USB3_BASE: - instance = 2; - break; - default: - err = -ENODEV; - dev_err(&pdev->dev, "unknown usb instance\n"); - goto fail_phy; - } - } - - tegra->phy = tegra_usb_phy_open(instance, hcd->regs, pdata->phy_config, - TEGRA_USB_PHY_MODE_HOST); - if (IS_ERR(tegra->phy)) { - dev_err(&pdev->dev, "Failed to open USB phy\n"); - err = -ENXIO; - goto fail_phy; - } - - err = tegra_usb_phy_power_on(tegra->phy); - if (err) { - dev_err(&pdev->dev, "Failed to power on the phy\n"); - goto fail; - } - - tegra->host_resumed = 1; - tegra->ehci = hcd_to_ehci(hcd); - - irq = platform_get_irq(pdev, 0); - if (!irq) { - dev_err(&pdev->dev, "Failed to get IRQ\n"); - err = -ENODEV; - goto fail; - } - -#ifdef CONFIG_USB_OTG_UTILS - if (pdata->operating_mode == TEGRA_USB_OTG) { - tegra->transceiver = usb_get_transceiver(); - if (tegra->transceiver) - otg_set_host(tegra->transceiver->otg, &hcd->self); - } -#endif - - err = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (err) { - dev_err(&pdev->dev, "Failed to add USB HCD\n"); - goto fail; - } - - pm_runtime_set_active(&pdev->dev); - pm_runtime_get_noresume(&pdev->dev); - - /* Don't skip the pm_runtime_forbid call if wakeup isn't working */ - /* if (!pdata->power_down_on_bus_suspend) */ - pm_runtime_forbid(&pdev->dev); - pm_runtime_enable(&pdev->dev); - pm_runtime_put_sync(&pdev->dev); - return err; - -fail: -#ifdef CONFIG_USB_OTG_UTILS - if (tegra->transceiver) { - otg_set_host(tegra->transceiver->otg, NULL); - usb_put_transceiver(tegra->transceiver); - } -#endif - tegra_usb_phy_close(tegra->phy); -fail_phy: - iounmap(hcd->regs); -fail_io: - clk_disable(tegra->emc_clk); - clk_put(tegra->emc_clk); -fail_emc_clk: - clk_disable(tegra->clk); -fail_clken: - clk_put(tegra->clk); -fail_clk: - usb_put_hcd(hcd); -fail_hcd: - kfree(tegra); - return err; -} - -static int tegra_ehci_remove(struct platform_device *pdev) -{ - struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev); - struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci); - - if (tegra == NULL || hcd == NULL) - return -EINVAL; - - pm_runtime_get_sync(&pdev->dev); - pm_runtime_disable(&pdev->dev); - pm_runtime_put_noidle(&pdev->dev); - -#ifdef CONFIG_USB_OTG_UTILS - if (tegra->transceiver) { - otg_set_host(tegra->transceiver->otg, NULL); - usb_put_transceiver(tegra->transceiver); - } -#endif - - usb_remove_hcd(hcd); - usb_put_hcd(hcd); - - tegra_usb_phy_close(tegra->phy); - iounmap(hcd->regs); - - clk_disable(tegra->clk); - clk_put(tegra->clk); - - clk_disable(tegra->emc_clk); - clk_put(tegra->emc_clk); - - kfree(tegra); - return 0; -} - -static void tegra_ehci_hcd_shutdown(struct platform_device *pdev) -{ - struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev); - struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - -static struct of_device_id tegra_ehci_of_match[] __devinitdata = { - { .compatible = "nvidia,tegra20-ehci", }, - { }, -}; - -static struct platform_driver tegra_ehci_driver = { - .probe = tegra_ehci_probe, - .remove = tegra_ehci_remove, - .shutdown = tegra_ehci_hcd_shutdown, - .driver = { - .name = "tegra-ehci", - .of_match_table = tegra_ehci_of_match, -#ifdef CONFIG_PM - .pm = &tegra_ehci_pm_ops, -#endif - } -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-vt8500.c b/ANDROID_3.4.5/drivers/usb/host/ehci-vt8500.c deleted file mode 100644 index c1eda739..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-vt8500.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * drivers/usb/host/ehci-vt8500.c - * - * Copyright (C) 2010 Alexey Charkov - * - * Based on ehci-au1xxx.c - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - * - */ - -#include - -static int ehci_update_device(struct usb_hcd *hcd, struct usb_device *udev) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int rc = 0; - - if (!udev->parent) /* udev is root hub itself, impossible */ - rc = -1; - /* we only support lpm device connected to root hub yet */ - if (ehci->has_lpm && !udev->parent->parent) { - rc = ehci_lpm_set_da(ehci, udev->devnum, udev->portnum); - if (!rc) - rc = ehci_lpm_check(ehci, udev->portnum); - } - return rc; -} - -static const struct hc_driver vt8500_ehci_hc_driver = { - .description = hcd_name, - .product_desc = "VT8500 EHCI", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* - * basic lifecycle operations - */ - .reset = ehci_init, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - /* - * call back when device connected and addressed - */ - .update_device = ehci_update_device, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static int vt8500_ehci_drv_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - struct ehci_hcd *ehci; - struct resource *res; - int ret; - - if (usb_disabled()) - return -ENODEV; - - if (pdev->resource[1].flags != IORESOURCE_IRQ) { - pr_debug("resource[1] is not IORESOURCE_IRQ"); - return -ENOMEM; - } - hcd = usb_create_hcd(&vt8500_ehci_hc_driver, &pdev->dev, "VT8500"); - if (!hcd) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - pr_debug("request_mem_region failed"); - ret = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - pr_debug("ioremap failed"); - ret = -ENOMEM; - goto err2; - } - - ehci = hcd_to_ehci(hcd); - ehci->caps = hcd->regs; - ehci->regs = hcd->regs + - HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase)); - - dbg_hcs_params(ehci, "reset"); - dbg_hcc_params(ehci, "reset"); - - /* cache this readonly data; minimize chip reads */ - ehci->hcs_params = readl(&ehci->caps->hcs_params); - - ehci_port_power(ehci, 1); - - ehci_reset(ehci); - - ret = usb_add_hcd(hcd, pdev->resource[1].start, - IRQF_SHARED); - if (ret == 0) { - platform_set_drvdata(pdev, hcd); - return ret; - } - - iounmap(hcd->regs); -err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err1: - usb_put_hcd(hcd); - return ret; -} - -static int vt8500_ehci_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - platform_set_drvdata(pdev, NULL); - - return 0; -} - -static struct platform_driver vt8500_ehci_driver = { - .probe = vt8500_ehci_drv_probe, - .remove = vt8500_ehci_drv_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "vt8500-ehci", - .owner = THIS_MODULE, - } -}; - -MODULE_ALIAS("platform:vt8500-ehci"); diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-w90x900.c b/ANDROID_3.4.5/drivers/usb/host/ehci-w90x900.c deleted file mode 100644 index 3d2e26cb..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-w90x900.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - * linux/driver/usb/host/ehci-w90x900.c - * - * Copyright (c) 2008 Nuvoton technology corporation. - * - * Wan ZongShun - * - * 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;version 2 of the License. - * - */ - -#include - -/*ebable phy0 and phy1 for w90p910*/ -#define ENPHY (0x01<<8) -#define PHY0_CTR (0xA4) -#define PHY1_CTR (0xA8) - -static int __devinit usb_w90x900_probe(const struct hc_driver *driver, - struct platform_device *pdev) -{ - struct usb_hcd *hcd; - struct ehci_hcd *ehci; - struct resource *res; - int retval = 0, irq; - unsigned long val; - - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - retval = -ENXIO; - goto err1; - } - - hcd = usb_create_hcd(driver, &pdev->dev, "w90x900 EHCI"); - if (!hcd) { - retval = -ENOMEM; - goto err1; - } - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - retval = -EBUSY; - goto err2; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (hcd->regs == NULL) { - retval = -EFAULT; - goto err3; - } - - ehci = hcd_to_ehci(hcd); - ehci->caps = hcd->regs; - ehci->regs = hcd->regs + - HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); - - /* enable PHY 0,1,the regs only apply to w90p910 - * 0xA4,0xA8 were offsets of PHY0 and PHY1 controller of - * w90p910 IC relative to ehci->regs. - */ - val = __raw_readl(ehci->regs+PHY0_CTR); - val |= ENPHY; - __raw_writel(val, ehci->regs+PHY0_CTR); - - val = __raw_readl(ehci->regs+PHY1_CTR); - val |= ENPHY; - __raw_writel(val, ehci->regs+PHY1_CTR); - - ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); - ehci->sbrn = 0x20; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) - goto err4; - - ehci_reset(ehci); - - retval = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (retval != 0) - goto err4; - - ehci_writel(ehci, 1, &ehci->regs->configured_flag); - - return retval; -err4: - iounmap(hcd->regs); -err3: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err2: - usb_put_hcd(hcd); -err1: - return retval; -} - -static -void usb_w90x900_remove(struct usb_hcd *hcd, struct platform_device *pdev) -{ - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); -} - -static const struct hc_driver ehci_w90x900_hc_driver = { - .description = hcd_name, - .product_desc = "Nuvoton w90x900 EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_USB2|HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .reset = ehci_init, - .start = ehci_run, - - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, -#endif - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static int __devinit ehci_w90x900_probe(struct platform_device *pdev) -{ - if (usb_disabled()) - return -ENODEV; - - return usb_w90x900_probe(&ehci_w90x900_hc_driver, pdev); -} - -static int __devexit ehci_w90x900_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_w90x900_remove(hcd, pdev); - - return 0; -} - -static struct platform_driver ehci_hcd_w90x900_driver = { - .probe = ehci_w90x900_probe, - .remove = __devexit_p(ehci_w90x900_remove), - .driver = { - .name = "w90x900-ehci", - .owner = THIS_MODULE, - }, -}; - -MODULE_AUTHOR("Wan ZongShun "); -MODULE_DESCRIPTION("w90p910 usb ehci driver!"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:w90p910-ehci"); diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-xilinx-of.c b/ANDROID_3.4.5/drivers/usb/host/ehci-xilinx-of.c deleted file mode 100644 index 9c2cc463..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-xilinx-of.c +++ /dev/null @@ -1,299 +0,0 @@ -/* - * EHCI HCD (Host Controller Driver) for USB. - * - * Bus Glue for Xilinx EHCI core on the of_platform bus - * - * Copyright (c) 2009 Xilinx, Inc. - * - * Based on "ehci-ppc-of.c" by Valentine Barshak - * and "ehci-ppc-soc.c" by Stefan Roese - * and "ohci-ppc-of.c" by Sylvain Munaut - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include - -#include -#include -#include - -/** - * ehci_xilinx_of_setup - Initialize the device for ehci_reset() - * @hcd: Pointer to the usb_hcd device to which the host controller bound - * - * called during probe() after chip reset completes. - */ -static int ehci_xilinx_of_setup(struct usb_hcd *hcd) -{ - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - int retval; - - retval = ehci_halt(ehci); - if (retval) - return retval; - - retval = ehci_init(hcd); - if (retval) - return retval; - - ehci->sbrn = 0x20; - - return ehci_reset(ehci); -} - -/** - * ehci_xilinx_port_handed_over - hand the port out if failed to enable it - * @hcd: Pointer to the usb_hcd device to which the host controller bound - * @portnum:Port number to which the device is attached. - * - * This function is used as a place to tell the user that the Xilinx USB host - * controller does support LS devices. And in an HS only configuration, it - * does not support FS devices either. It is hoped that this can help a - * confused user. - * - * There are cases when the host controller fails to enable the port due to, - * for example, insufficient power that can be supplied to the device from - * the USB bus. In those cases, the messages printed here are not helpful. - */ -static int ehci_xilinx_port_handed_over(struct usb_hcd *hcd, int portnum) -{ - dev_warn(hcd->self.controller, "port %d cannot be enabled\n", portnum); - if (hcd->has_tt) { - dev_warn(hcd->self.controller, - "Maybe you have connected a low speed device?\n"); - - dev_warn(hcd->self.controller, - "We do not support low speed devices\n"); - } else { - dev_warn(hcd->self.controller, - "Maybe your device is not a high speed device?\n"); - dev_warn(hcd->self.controller, - "The USB host controller does not support full speed " - "nor low speed devices\n"); - dev_warn(hcd->self.controller, - "You can reconfigure the host controller to have " - "full speed support\n"); - } - - return 0; -} - - -static const struct hc_driver ehci_xilinx_of_hc_driver = { - .description = hcd_name, - .product_desc = "OF EHCI", - .hcd_priv_size = sizeof(struct ehci_hcd), - - /* - * generic hardware linkage - */ - .irq = ehci_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* - * basic lifecycle operations - */ - .reset = ehci_xilinx_of_setup, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ehci_urb_enqueue, - .urb_dequeue = ehci_urb_dequeue, - .endpoint_disable = ehci_endpoint_disable, - .endpoint_reset = ehci_endpoint_reset, - - /* - * scheduling support - */ - .get_frame_number = ehci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ehci_hub_status_data, - .hub_control = ehci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, -#endif - .relinquish_port = NULL, - .port_handed_over = ehci_xilinx_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -/** - * ehci_hcd_xilinx_of_probe - Probe method for the USB host controller - * @op: pointer to the platform_device bound to the host controller - * - * This function requests resources and sets up appropriate properties for the - * host controller. Because the Xilinx USB host controller can be configured - * as HS only or HS/FS only, it checks the configuration in the device tree - * entry, and sets an appropriate value for hcd->has_tt. - */ -static int __devinit ehci_hcd_xilinx_of_probe(struct platform_device *op) -{ - struct device_node *dn = op->dev.of_node; - struct usb_hcd *hcd; - struct ehci_hcd *ehci; - struct resource res; - int irq; - int rv; - int *value; - - if (usb_disabled()) - return -ENODEV; - - dev_dbg(&op->dev, "initializing XILINX-OF USB Controller\n"); - - rv = of_address_to_resource(dn, 0, &res); - if (rv) - return rv; - - hcd = usb_create_hcd(&ehci_xilinx_of_hc_driver, &op->dev, - "XILINX-OF USB"); - if (!hcd) - return -ENOMEM; - - hcd->rsrc_start = res.start; - hcd->rsrc_len = resource_size(&res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__); - rv = -EBUSY; - goto err_rmr; - } - - irq = irq_of_parse_and_map(dn, 0); - if (!irq) { - printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__); - rv = -EBUSY; - goto err_irq; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - printk(KERN_ERR "%s: ioremap failed\n", __FILE__); - rv = -ENOMEM; - goto err_ioremap; - } - - ehci = hcd_to_ehci(hcd); - - /* This core always has big-endian register interface and uses - * big-endian memory descriptors. - */ - ehci->big_endian_mmio = 1; - ehci->big_endian_desc = 1; - - /* Check whether the FS support option is selected in the hardware. - */ - value = (int *)of_get_property(dn, "xlnx,support-usb-fs", NULL); - if (value && (*value == 1)) { - ehci_dbg(ehci, "USB host controller supports FS devices\n"); - hcd->has_tt = 1; - } else { - ehci_dbg(ehci, - "USB host controller is HS only\n"); - hcd->has_tt = 0; - } - - /* Debug registers are at the first 0x100 region - */ - ehci->caps = hcd->regs + 0x100; - ehci->regs = hcd->regs + 0x100 + - HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); - - /* cache this readonly data; minimize chip reads */ - ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); - - rv = usb_add_hcd(hcd, irq, 0); - if (rv == 0) - return 0; - - iounmap(hcd->regs); - -err_ioremap: -err_irq: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err_rmr: - usb_put_hcd(hcd); - - return rv; -} - -/** - * ehci_hcd_xilinx_of_remove - shutdown hcd and release resources - * @op: pointer to platform_device structure that is to be removed - * - * Remove the hcd structure, and release resources that has been requested - * during probe. - */ -static int ehci_hcd_xilinx_of_remove(struct platform_device *op) -{ - struct usb_hcd *hcd = dev_get_drvdata(&op->dev); - dev_set_drvdata(&op->dev, NULL); - - dev_dbg(&op->dev, "stopping XILINX-OF USB Controller\n"); - - usb_remove_hcd(hcd); - - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - - usb_put_hcd(hcd); - - return 0; -} - -/** - * ehci_hcd_xilinx_of_shutdown - shutdown the hcd - * @op: pointer to platform_device structure that is to be removed - * - * Properly shutdown the hcd, call driver's shutdown routine. - */ -static int ehci_hcd_xilinx_of_shutdown(struct platform_device *op) -{ - struct usb_hcd *hcd = dev_get_drvdata(&op->dev); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); - - return 0; -} - - -static const struct of_device_id ehci_hcd_xilinx_of_match[] = { - {.compatible = "xlnx,xps-usb-host-1.00.a",}, - {}, -}; -MODULE_DEVICE_TABLE(of, ehci_hcd_xilinx_of_match); - -static struct platform_driver ehci_hcd_xilinx_of_driver = { - .probe = ehci_hcd_xilinx_of_probe, - .remove = ehci_hcd_xilinx_of_remove, - .shutdown = ehci_hcd_xilinx_of_shutdown, - .driver = { - .name = "xilinx-of-ehci", - .owner = THIS_MODULE, - .of_match_table = ehci_hcd_xilinx_of_match, - }, -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci-xls.c b/ANDROID_3.4.5/drivers/usb/host/ehci-xls.c deleted file mode 100644 index 72f08196..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci-xls.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * EHCI HCD for Netlogic XLS processors. - * - * (C) Copyright 2011 Netlogic Microsystems Inc. - * - * Based on various ehci-*.c drivers - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - */ - -#include - -static int ehci_xls_setup(struct usb_hcd *hcd) -{ - int retval; - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - - ehci->caps = hcd->regs; - ehci->regs = hcd->regs + - HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); - dbg_hcs_params(ehci, "reset"); - dbg_hcc_params(ehci, "reset"); - - /* cache this readonly data; minimize chip reads */ - ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); - - retval = ehci_halt(ehci); - if (retval) - return retval; - - /* data structure init */ - retval = ehci_init(hcd); - if (retval) - return retval; - - ehci_reset(ehci); - - return retval; -} - -int ehci_xls_probe_internal(const struct hc_driver *driver, - struct platform_device *pdev) -{ - struct usb_hcd *hcd; - struct resource *res; - int retval, irq; - - /* Get our IRQ from an earlier registered Platform Resource */ - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "Found HC with no IRQ. Check %s setup!\n", - dev_name(&pdev->dev)); - return -ENODEV; - } - - /* Get our Memory Handle */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Error: MMIO Handle %s setup!\n", - dev_name(&pdev->dev)); - return -ENODEV; - } - hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - retval = -ENOMEM; - goto err1; - } - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) { - dev_dbg(&pdev->dev, "controller already in use\n"); - retval = -EBUSY; - goto err2; - } - hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); - - if (hcd->regs == NULL) { - dev_dbg(&pdev->dev, "error mapping memory\n"); - retval = -EFAULT; - goto err3; - } - - retval = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (retval != 0) - goto err4; - return retval; - -err4: - iounmap(hcd->regs); -err3: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err2: - usb_put_hcd(hcd); -err1: - dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), - retval); - return retval; -} - -static struct hc_driver ehci_xls_hc_driver = { - .description = hcd_name, - .product_desc = "XLS EHCI Host Controller", - .hcd_priv_size = sizeof(struct ehci_hcd), - .irq = ehci_irq, - .flags = HCD_USB2 | HCD_MEMORY, - .reset = ehci_xls_setup, - .start = ehci_run, - .stop = ehci_stop, - .shutdown = ehci_shutdown, - - .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, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, - .relinquish_port = ehci_relinquish_port, - .port_handed_over = ehci_port_handed_over, - - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; - -static int ehci_xls_probe(struct platform_device *pdev) -{ - if (usb_disabled()) - return -ENODEV; - - return ehci_xls_probe_internal(&ehci_xls_hc_driver, pdev); -} - -static int ehci_xls_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - return 0; -} - -MODULE_ALIAS("ehci-xls"); - -static struct platform_driver ehci_xls_driver = { - .probe = ehci_xls_probe, - .remove = ehci_xls_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "ehci-xls", - }, -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ehci.h b/ANDROID_3.4.5/drivers/usb/host/ehci.h deleted file mode 100644 index f04172ef..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ehci.h +++ /dev/null @@ -1,796 +0,0 @@ -/* - * Copyright (c) 2001-2002 by David Brownell - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __LINUX_EHCI_HCD_H -#define __LINUX_EHCI_HCD_H - -/* definitions used for the EHCI driver */ - -/* - * __hc32 and __hc16 are "Host Controller" types, they may be equivalent to - * __leXX (normally) or __beXX (given EHCI_BIG_ENDIAN_DESC), depending on - * the host controller implementation. - * - * To facilitate the strongest possible byte-order checking from "sparse" - * and so on, we use __leXX unless that's not practical. - */ -#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_DESC -typedef __u32 __bitwise __hc32; -typedef __u16 __bitwise __hc16; -#else -#define __hc32 __le32 -#define __hc16 __le16 -#endif - -/* statistics can be kept for tuning/monitoring */ -struct ehci_stats { - /* irq usage */ - unsigned long normal; - unsigned long error; - unsigned long reclaim; - unsigned long lost_iaa; - - /* termination of urbs from core */ - unsigned long complete; - unsigned long unlink; -}; - -/* ehci_hcd->lock guards shared data against other CPUs: - * ehci_hcd: async, reclaim, periodic (and shadow), ... - * usb_host_endpoint: hcpriv - * ehci_qh: qh_next, qtd_list - * ehci_qtd: qtd_list - * - * Also, hold this lock when talking to HC registers or - * when updating hw_* fields in shared qh/qtd/... structures. - */ - -#define EHCI_MAX_ROOT_PORTS 15 /* see HCS_N_PORTS */ - -enum ehci_rh_state { - EHCI_RH_HALTED, - EHCI_RH_SUSPENDED, - EHCI_RH_RUNNING -}; - -struct ehci_hcd { /* one per controller */ - /* glue to PCI and HCD framework */ - struct ehci_caps __iomem *caps; - struct ehci_regs __iomem *regs; - struct ehci_dbg_port __iomem *debug; - - __u32 hcs_params; /* cached register copy */ - spinlock_t lock; - enum ehci_rh_state rh_state; - - /* async schedule support */ - struct ehci_qh *async; - struct ehci_qh *dummy; /* For AMD quirk use */ - struct ehci_qh *reclaim; - struct ehci_qh *qh_scan_next; - unsigned scanning : 1; - - /* periodic schedule support */ -#define DEFAULT_I_TDPS 1024 /* some HCs can do less */ - unsigned periodic_size; - __hc32 *periodic; /* hw periodic table */ - dma_addr_t periodic_dma; - unsigned i_thresh; /* uframes HC might cache */ - - union ehci_shadow *pshadow; /* mirror hw periodic table */ - int next_uframe; /* scan periodic, start here */ - unsigned periodic_sched; /* periodic activity count */ - unsigned uframe_periodic_max; /* max periodic time per uframe */ - - - /* list of itds & sitds completed while clock_frame was still active */ - struct list_head cached_itd_list; - struct list_head cached_sitd_list; - unsigned clock_frame; - - /* per root hub port */ - unsigned long reset_done [EHCI_MAX_ROOT_PORTS]; - - /* bit vectors (one bit per port) */ - unsigned long bus_suspended; /* which ports were - already suspended at the start of a bus suspend */ - unsigned long companion_ports; /* which ports are - dedicated to the companion controller */ - unsigned long owned_ports; /* which ports are - owned by the companion during a bus suspend */ - unsigned long port_c_suspend; /* which ports have - the change-suspend feature turned on */ - unsigned long suspended_ports; /* which ports are - suspended */ - unsigned long resuming_ports; /* which ports have - started to resume */ - - /* per-HC memory pools (could be per-bus, but ...) */ - struct dma_pool *qh_pool; /* qh per active urb */ - struct dma_pool *qtd_pool; /* one or more per qh */ - struct dma_pool *itd_pool; /* itd per iso urb */ - struct dma_pool *sitd_pool; /* sitd per split iso urb */ - - struct timer_list iaa_watchdog; - struct timer_list watchdog; - unsigned long actions; - unsigned periodic_stamp; - unsigned random_frame; - unsigned long next_statechange; - ktime_t last_periodic_enable; - u32 command; - - /* SILICON QUIRKS */ - unsigned no_selective_suspend:1; - unsigned has_fsl_port_bug:1; /* FreeScale */ - unsigned big_endian_mmio:1; - unsigned big_endian_desc:1; - unsigned big_endian_capbase:1; - unsigned has_amcc_usb23:1; - unsigned need_io_watchdog:1; - unsigned broken_periodic:1; - unsigned amd_pll_fix:1; - unsigned fs_i_thresh:1; /* Intel iso scheduling */ - unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/ - unsigned has_synopsys_hc_bug:1; /* Synopsys HC */ - unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */ - - /* required for usb32 quirk */ - #define OHCI_CTRL_HCFS (3 << 6) - #define OHCI_USB_OPER (2 << 6) - #define OHCI_USB_SUSPEND (3 << 6) - - #define OHCI_HCCTRL_OFFSET 0x4 - #define OHCI_HCCTRL_LEN 0x4 - __hc32 *ohci_hcctrl_reg; - unsigned has_hostpc:1; - unsigned has_lpm:1; /* support link power management */ - unsigned has_ppcd:1; /* support per-port change bits */ - u8 sbrn; /* packed release number */ - - /* irq statistics */ -#ifdef EHCI_STATS - struct ehci_stats stats; -# define COUNT(x) do { (x)++; } while (0) -#else -# define COUNT(x) do {} while (0) -#endif - - /* debug files */ -#ifdef DEBUG - struct dentry *debug_dir; -#endif - /* - * OTG controllers and transceivers need software interaction - */ - struct usb_phy *transceiver; -}; - -/* convert between an HCD pointer and the corresponding EHCI_HCD */ -static inline struct ehci_hcd *hcd_to_ehci (struct usb_hcd *hcd) -{ - return (struct ehci_hcd *) (hcd->hcd_priv); -} -static inline struct usb_hcd *ehci_to_hcd (struct ehci_hcd *ehci) -{ - return container_of ((void *) ehci, struct usb_hcd, hcd_priv); -} - - -static inline void -iaa_watchdog_start(struct ehci_hcd *ehci) -{ - WARN_ON(timer_pending(&ehci->iaa_watchdog)); - mod_timer(&ehci->iaa_watchdog, - jiffies + msecs_to_jiffies(EHCI_IAA_MSECS)); -} - -static inline void iaa_watchdog_done(struct ehci_hcd *ehci) -{ - del_timer(&ehci->iaa_watchdog); -} - -enum ehci_timer_action { - TIMER_IO_WATCHDOG, - TIMER_ASYNC_SHRINK, - TIMER_ASYNC_OFF, -}; - -static inline void -timer_action_done (struct ehci_hcd *ehci, enum ehci_timer_action action) -{ - clear_bit (action, &ehci->actions); -} - -static void free_cached_lists(struct ehci_hcd *ehci); - -/*-------------------------------------------------------------------------*/ - -#include - -/*-------------------------------------------------------------------------*/ - -#define QTD_NEXT(ehci, dma) cpu_to_hc32(ehci, (u32)dma) - -/* - * EHCI Specification 0.95 Section 3.5 - * QTD: describe data transfer components (buffer, direction, ...) - * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram". - * - * These are associated only with "QH" (Queue Head) structures, - * used with control, bulk, and interrupt transfers. - */ -struct ehci_qtd { - /* first part defined by EHCI spec */ - __hc32 hw_next; /* see EHCI 3.5.1 */ - __hc32 hw_alt_next; /* see EHCI 3.5.2 */ - __hc32 hw_token; /* see EHCI 3.5.3 */ -#define QTD_TOGGLE (1 << 31) /* data toggle */ -#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff) -#define QTD_IOC (1 << 15) /* interrupt on complete */ -#define QTD_CERR(tok) (((tok)>>10) & 0x3) -#define QTD_PID(tok) (((tok)>>8) & 0x3) -#define QTD_STS_ACTIVE (1 << 7) /* HC may execute this */ -#define QTD_STS_HALT (1 << 6) /* halted on error */ -#define QTD_STS_DBE (1 << 5) /* data buffer error (in HC) */ -#define QTD_STS_BABBLE (1 << 4) /* device was babbling (qtd halted) */ -#define QTD_STS_XACT (1 << 3) /* device gave illegal response */ -#define QTD_STS_MMF (1 << 2) /* incomplete split transaction */ -#define QTD_STS_STS (1 << 1) /* split transaction state */ -#define QTD_STS_PING (1 << 0) /* issue PING? */ - -#define ACTIVE_BIT(ehci) cpu_to_hc32(ehci, QTD_STS_ACTIVE) -#define HALT_BIT(ehci) cpu_to_hc32(ehci, QTD_STS_HALT) -#define STATUS_BIT(ehci) cpu_to_hc32(ehci, QTD_STS_STS) - - __hc32 hw_buf [5]; /* see EHCI 3.5.4 */ - __hc32 hw_buf_hi [5]; /* Appendix B */ - - /* the rest is HCD-private */ - dma_addr_t qtd_dma; /* qtd address */ - struct list_head qtd_list; /* sw qtd list */ - struct urb *urb; /* qtd's urb */ - size_t length; /* length of buffer */ -} __attribute__ ((aligned (32))); - -/* mask NakCnt+T in qh->hw_alt_next */ -#define QTD_MASK(ehci) cpu_to_hc32 (ehci, ~0x1f) - -#define IS_SHORT_READ(token) (QTD_LENGTH (token) != 0 && QTD_PID (token) == 1) - -/*-------------------------------------------------------------------------*/ - -/* type tag from {qh,itd,sitd,fstn}->hw_next */ -#define Q_NEXT_TYPE(ehci,dma) ((dma) & cpu_to_hc32(ehci, 3 << 1)) - -/* - * Now the following defines are not converted using the - * cpu_to_le32() macro anymore, since we have to support - * "dynamic" switching between be and le support, so that the driver - * can be used on one system with SoC EHCI controller using big-endian - * descriptors as well as a normal little-endian PCI EHCI controller. - */ -/* values for that type tag */ -#define Q_TYPE_ITD (0 << 1) -#define Q_TYPE_QH (1 << 1) -#define Q_TYPE_SITD (2 << 1) -#define Q_TYPE_FSTN (3 << 1) - -/* next async queue entry, or pointer to interrupt/periodic QH */ -#define QH_NEXT(ehci,dma) (cpu_to_hc32(ehci, (((u32)dma)&~0x01f)|Q_TYPE_QH)) - -/* for periodic/async schedules and qtd lists, mark end of list */ -#define EHCI_LIST_END(ehci) cpu_to_hc32(ehci, 1) /* "null pointer" to hw */ - -/* - * Entries in periodic shadow table are pointers to one of four kinds - * of data structure. That's dictated by the hardware; a type tag is - * encoded in the low bits of the hardware's periodic schedule. Use - * Q_NEXT_TYPE to get the tag. - * - * For entries in the async schedule, the type tag always says "qh". - */ -union ehci_shadow { - struct ehci_qh *qh; /* Q_TYPE_QH */ - struct ehci_itd *itd; /* Q_TYPE_ITD */ - struct ehci_sitd *sitd; /* Q_TYPE_SITD */ - struct ehci_fstn *fstn; /* Q_TYPE_FSTN */ - __hc32 *hw_next; /* (all types) */ - void *ptr; -}; - -/*-------------------------------------------------------------------------*/ - -/* - * EHCI Specification 0.95 Section 3.6 - * QH: describes control/bulk/interrupt endpoints - * See Fig 3-7 "Queue Head Structure Layout". - * - * These appear in both the async and (for interrupt) periodic schedules. - */ - -/* first part defined by EHCI spec */ -struct ehci_qh_hw { - __hc32 hw_next; /* see EHCI 3.6.1 */ - __hc32 hw_info1; /* see EHCI 3.6.2 */ -#define QH_HEAD 0x00008000 - __hc32 hw_info2; /* see EHCI 3.6.2 */ -#define QH_SMASK 0x000000ff -#define QH_CMASK 0x0000ff00 -#define QH_HUBADDR 0x007f0000 -#define QH_HUBPORT 0x3f800000 -#define QH_MULT 0xc0000000 - __hc32 hw_current; /* qtd list - see EHCI 3.6.4 */ - - /* qtd overlay (hardware parts of a struct ehci_qtd) */ - __hc32 hw_qtd_next; - __hc32 hw_alt_next; - __hc32 hw_token; - __hc32 hw_buf [5]; - __hc32 hw_buf_hi [5]; -} __attribute__ ((aligned(32))); - -struct ehci_qh { - struct ehci_qh_hw *hw; - /* the rest is HCD-private */ - dma_addr_t qh_dma; /* address of qh */ - union ehci_shadow qh_next; /* ptr to qh; or periodic */ - struct list_head qtd_list; /* sw qtd list */ - struct ehci_qtd *dummy; - struct ehci_qh *reclaim; /* next to reclaim */ - - struct ehci_hcd *ehci; - unsigned long unlink_time; - - /* - * Do NOT use atomic operations for QH refcounting. On some CPUs - * (PPC7448 for example), atomic operations cannot be performed on - * memory that is cache-inhibited (i.e. being used for DMA). - * Spinlocks are used to protect all QH fields. - */ - u32 refcount; - unsigned stamp; - - u8 needs_rescan; /* Dequeue during giveback */ - u8 qh_state; -#define QH_STATE_LINKED 1 /* HC sees this */ -#define QH_STATE_UNLINK 2 /* HC may still see this */ -#define QH_STATE_IDLE 3 /* HC doesn't see this */ -#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on reclaim q */ -#define QH_STATE_COMPLETING 5 /* don't touch token.HALT */ - - u8 xacterrs; /* XactErr retry counter */ -#define QH_XACTERR_MAX 32 /* XactErr retry limit */ - - /* periodic schedule info */ - u8 usecs; /* intr bandwidth */ - u8 gap_uf; /* uframes split/csplit gap */ - u8 c_usecs; /* ... split completion bw */ - u16 tt_usecs; /* tt downstream bandwidth */ - unsigned short period; /* polling interval */ - unsigned short start; /* where polling starts */ -#define NO_FRAME ((unsigned short)~0) /* pick new start */ - - struct usb_device *dev; /* access to TT */ - unsigned is_out:1; /* bulk or intr OUT */ - unsigned clearing_tt:1; /* Clear-TT-Buf in progress */ -}; - -/*-------------------------------------------------------------------------*/ - -/* description of one iso transaction (up to 3 KB data if highspeed) */ -struct ehci_iso_packet { - /* These will be copied to iTD when scheduling */ - u64 bufp; /* itd->hw_bufp{,_hi}[pg] |= */ - __hc32 transaction; /* itd->hw_transaction[i] |= */ - u8 cross; /* buf crosses pages */ - /* for full speed OUT splits */ - u32 buf1; -}; - -/* temporary schedule data for packets from iso urbs (both speeds) - * each packet is one logical usb transaction to the device (not TT), - * beginning at stream->next_uframe - */ -struct ehci_iso_sched { - struct list_head td_list; - unsigned span; - struct ehci_iso_packet packet [0]; -}; - -/* - * ehci_iso_stream - groups all (s)itds for this endpoint. - * acts like a qh would, if EHCI had them for ISO. - */ -struct ehci_iso_stream { - /* first field matches ehci_hq, but is NULL */ - struct ehci_qh_hw *hw; - - u32 refcount; - u8 bEndpointAddress; - u8 highspeed; - struct list_head td_list; /* queued itds/sitds */ - struct list_head free_list; /* list of unused itds/sitds */ - struct usb_device *udev; - struct usb_host_endpoint *ep; - - /* output of (re)scheduling */ - int next_uframe; - __hc32 splits; - - /* the rest is derived from the endpoint descriptor, - * trusting urb->interval == f(epdesc->bInterval) and - * including the extra info for hw_bufp[0..2] - */ - u8 usecs, c_usecs; - u16 interval; - u16 tt_usecs; - u16 maxp; - u16 raw_mask; - unsigned bandwidth; - - /* This is used to initialize iTD's hw_bufp fields */ - __hc32 buf0; - __hc32 buf1; - __hc32 buf2; - - /* this is used to initialize sITD's tt info */ - __hc32 address; -}; - -/*-------------------------------------------------------------------------*/ - -/* - * EHCI Specification 0.95 Section 3.3 - * Fig 3-4 "Isochronous Transaction Descriptor (iTD)" - * - * Schedule records for high speed iso xfers - */ -struct ehci_itd { - /* first part defined by EHCI spec */ - __hc32 hw_next; /* see EHCI 3.3.1 */ - __hc32 hw_transaction [8]; /* see EHCI 3.3.2 */ -#define EHCI_ISOC_ACTIVE (1<<31) /* activate transfer this slot */ -#define EHCI_ISOC_BUF_ERR (1<<30) /* Data buffer error */ -#define EHCI_ISOC_BABBLE (1<<29) /* babble detected */ -#define EHCI_ISOC_XACTERR (1<<28) /* XactErr - transaction error */ -#define EHCI_ITD_LENGTH(tok) (((tok)>>16) & 0x0fff) -#define EHCI_ITD_IOC (1 << 15) /* interrupt on complete */ - -#define ITD_ACTIVE(ehci) cpu_to_hc32(ehci, EHCI_ISOC_ACTIVE) - - __hc32 hw_bufp [7]; /* see EHCI 3.3.3 */ - __hc32 hw_bufp_hi [7]; /* Appendix B */ - - /* the rest is HCD-private */ - dma_addr_t itd_dma; /* for this itd */ - union ehci_shadow itd_next; /* ptr to periodic q entry */ - - struct urb *urb; - struct ehci_iso_stream *stream; /* endpoint's queue */ - struct list_head itd_list; /* list of stream's itds */ - - /* any/all hw_transactions here may be used by that urb */ - unsigned frame; /* where scheduled */ - unsigned pg; - unsigned index[8]; /* in urb->iso_frame_desc */ -} __attribute__ ((aligned (32))); - -/*-------------------------------------------------------------------------*/ - -/* - * EHCI Specification 0.95 Section 3.4 - * siTD, aka split-transaction isochronous Transfer Descriptor - * ... describe full speed iso xfers through TT in hubs - * see Figure 3-5 "Split-transaction Isochronous Transaction Descriptor (siTD) - */ -struct ehci_sitd { - /* first part defined by EHCI spec */ - __hc32 hw_next; -/* uses bit field macros above - see EHCI 0.95 Table 3-8 */ - __hc32 hw_fullspeed_ep; /* EHCI table 3-9 */ - __hc32 hw_uframe; /* EHCI table 3-10 */ - __hc32 hw_results; /* EHCI table 3-11 */ -#define SITD_IOC (1 << 31) /* interrupt on completion */ -#define SITD_PAGE (1 << 30) /* buffer 0/1 */ -#define SITD_LENGTH(x) (0x3ff & ((x)>>16)) -#define SITD_STS_ACTIVE (1 << 7) /* HC may execute this */ -#define SITD_STS_ERR (1 << 6) /* error from TT */ -#define SITD_STS_DBE (1 << 5) /* data buffer error (in HC) */ -#define SITD_STS_BABBLE (1 << 4) /* device was babbling */ -#define SITD_STS_XACT (1 << 3) /* illegal IN response */ -#define SITD_STS_MMF (1 << 2) /* incomplete split transaction */ -#define SITD_STS_STS (1 << 1) /* split transaction state */ - -#define SITD_ACTIVE(ehci) cpu_to_hc32(ehci, SITD_STS_ACTIVE) - - __hc32 hw_buf [2]; /* EHCI table 3-12 */ - __hc32 hw_backpointer; /* EHCI table 3-13 */ - __hc32 hw_buf_hi [2]; /* Appendix B */ - - /* the rest is HCD-private */ - dma_addr_t sitd_dma; - union ehci_shadow sitd_next; /* ptr to periodic q entry */ - - struct urb *urb; - struct ehci_iso_stream *stream; /* endpoint's queue */ - struct list_head sitd_list; /* list of stream's sitds */ - unsigned frame; - unsigned index; -} __attribute__ ((aligned (32))); - -/*-------------------------------------------------------------------------*/ - -/* - * EHCI Specification 0.96 Section 3.7 - * Periodic Frame Span Traversal Node (FSTN) - * - * Manages split interrupt transactions (using TT) that span frame boundaries - * into uframes 0/1; see 4.12.2.2. In those uframes, a "save place" FSTN - * makes the HC jump (back) to a QH to scan for fs/ls QH completions until - * it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work. - */ -struct ehci_fstn { - __hc32 hw_next; /* any periodic q entry */ - __hc32 hw_prev; /* qh or EHCI_LIST_END */ - - /* the rest is HCD-private */ - dma_addr_t fstn_dma; - union ehci_shadow fstn_next; /* ptr to periodic q entry */ -} __attribute__ ((aligned (32))); - -/*-------------------------------------------------------------------------*/ - -/* Prepare the PORTSC wakeup flags during controller suspend/resume */ - -#define ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup) \ - ehci_adjust_port_wakeup_flags(ehci, true, do_wakeup); - -#define ehci_prepare_ports_for_controller_resume(ehci) \ - ehci_adjust_port_wakeup_flags(ehci, false, false); - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_USB_EHCI_ROOT_HUB_TT - -/* - * Some EHCI controllers have a Transaction Translator built into the - * root hub. This is a non-standard feature. Each controller will need - * to add code to the following inline functions, and call them as - * needed (mostly in root hub code). - */ - -#define ehci_is_TDI(e) (ehci_to_hcd(e)->has_tt) - -/* Returns the speed of a device attached to a port on the root hub. */ -static inline unsigned int -ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc) -{ - if (ehci_is_TDI(ehci)) { - switch ((portsc >> (ehci->has_hostpc ? 25 : 26)) & 3) { - case 0: - return 0; - case 1: - return USB_PORT_STAT_LOW_SPEED; - case 2: - default: - return USB_PORT_STAT_HIGH_SPEED; - } - } - return USB_PORT_STAT_HIGH_SPEED; -} - -#else - -#define ehci_is_TDI(e) (0) - -#define ehci_port_speed(ehci, portsc) USB_PORT_STAT_HIGH_SPEED -#endif - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_PPC_83xx -/* Some Freescale processors have an erratum in which the TT - * port number in the queue head was 0..N-1 instead of 1..N. - */ -#define ehci_has_fsl_portno_bug(e) ((e)->has_fsl_port_bug) -#else -#define ehci_has_fsl_portno_bug(e) (0) -#endif - -/* - * While most USB host controllers implement their registers in - * little-endian format, a minority (celleb companion chip) implement - * them in big endian format. - * - * This attempts to support either format at compile time without a - * runtime penalty, or both formats with the additional overhead - * of checking a flag bit. - * - * ehci_big_endian_capbase is a special quirk for controllers that - * implement the HC capability registers as separate registers and not - * as fields of a 32-bit register. - */ - -#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO -#define ehci_big_endian_mmio(e) ((e)->big_endian_mmio) -#define ehci_big_endian_capbase(e) ((e)->big_endian_capbase) -#else -#define ehci_big_endian_mmio(e) 0 -#define ehci_big_endian_capbase(e) 0 -#endif - -/* - * Big-endian read/write functions are arch-specific. - * Other arches can be added if/when they're needed. - */ -#if defined(CONFIG_ARM) && defined(CONFIG_ARCH_IXP4XX) -#define readl_be(addr) __raw_readl((__force unsigned *)addr) -#define writel_be(val, addr) __raw_writel(val, (__force unsigned *)addr) -#endif - -static inline unsigned int ehci_readl(const struct ehci_hcd *ehci, - __u32 __iomem * regs) -{ -#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO - return ehci_big_endian_mmio(ehci) ? - readl_be(regs) : - readl(regs); -#else - return readl(regs); -#endif -} - -static inline void ehci_writel(const struct ehci_hcd *ehci, - const unsigned int val, __u32 __iomem *regs) -{ -#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO - ehci_big_endian_mmio(ehci) ? - writel_be(val, regs) : - writel(val, regs); -#else - writel(val, regs); -#endif -} - -/* - * On certain ppc-44x SoC there is a HW issue, that could only worked around with - * explicit suspend/operate of OHCI. This function hereby makes sense only on that arch. - * Other common bits are dependent on has_amcc_usb23 quirk flag. - */ -#ifdef CONFIG_44x -static inline void set_ohci_hcfs(struct ehci_hcd *ehci, int operational) -{ - u32 hc_control; - - hc_control = (readl_be(ehci->ohci_hcctrl_reg) & ~OHCI_CTRL_HCFS); - if (operational) - hc_control |= OHCI_USB_OPER; - else - hc_control |= OHCI_USB_SUSPEND; - - writel_be(hc_control, ehci->ohci_hcctrl_reg); - (void) readl_be(ehci->ohci_hcctrl_reg); -} -#else -static inline void set_ohci_hcfs(struct ehci_hcd *ehci, int operational) -{ } -#endif - -/*-------------------------------------------------------------------------*/ - -/* - * The AMCC 440EPx not only implements its EHCI registers in big-endian - * format, but also its DMA data structures (descriptors). - * - * EHCI controllers accessed through PCI work normally (little-endian - * everywhere), so we won't bother supporting a BE-only mode for now. - */ -#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_DESC -#define ehci_big_endian_desc(e) ((e)->big_endian_desc) - -/* cpu to ehci */ -static inline __hc32 cpu_to_hc32 (const struct ehci_hcd *ehci, const u32 x) -{ - return ehci_big_endian_desc(ehci) - ? (__force __hc32)cpu_to_be32(x) - : (__force __hc32)cpu_to_le32(x); -} - -/* ehci to cpu */ -static inline u32 hc32_to_cpu (const struct ehci_hcd *ehci, const __hc32 x) -{ - return ehci_big_endian_desc(ehci) - ? be32_to_cpu((__force __be32)x) - : le32_to_cpu((__force __le32)x); -} - -static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x) -{ - return ehci_big_endian_desc(ehci) - ? be32_to_cpup((__force __be32 *)x) - : le32_to_cpup((__force __le32 *)x); -} - -#else - -/* cpu to ehci */ -static inline __hc32 cpu_to_hc32 (const struct ehci_hcd *ehci, const u32 x) -{ - return cpu_to_le32(x); -} - -/* ehci to cpu */ -static inline u32 hc32_to_cpu (const struct ehci_hcd *ehci, const __hc32 x) -{ - return le32_to_cpu(x); -} - -static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x) -{ - return le32_to_cpup(x); -} - -#endif - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_PCI - -/* For working around the MosChip frame-index-register bug */ -static unsigned ehci_read_frame_index(struct ehci_hcd *ehci); - -#else - -static inline unsigned ehci_read_frame_index(struct ehci_hcd *ehci) -{ - return ehci_readl(ehci, &ehci->regs->frame_index); -} - -#endif - -/*-------------------------------------------------------------------------*/ - -#ifndef DEBUG -#define STUB_DEBUG_FILES -#endif /* DEBUG */ - -/*-------------------------------------------------------------------------*/ -/*{CharlesTu, 2010.08.26, for test mode */ - -static struct list_head * -qh_urb_transaction ( - struct ehci_hcd *ehci, - struct urb *urb, - struct list_head *head, - gfp_t flags -); - -static int submit_async ( - struct ehci_hcd *ehci, - struct urb *urb, - struct list_head *qtd_list, - gfp_t mem_flags -) ; - -static inline void ehci_qtd_free ( - struct ehci_hcd *ehci, - struct ehci_qtd *qtd); - -/*CharlesTu}*/ -#endif /* __LINUX_EHCI_HCD_H */ diff --git a/ANDROID_3.4.5/drivers/usb/host/fhci-dbg.c b/ANDROID_3.4.5/drivers/usb/host/fhci-dbg.c deleted file mode 100644 index 6fe55004..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/fhci-dbg.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Freescale QUICC Engine USB Host Controller Driver - * - * Copyright (c) Freescale Semicondutor, Inc. 2006. - * Shlomi Gridish - * Jerry Huang - * Copyright (c) Logic Product Development, Inc. 2007 - * Peter Barada - * Copyright (c) MontaVista Software, Inc. 2008. - * Anton Vorontsov - * - * 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 -#include -#include -#include -#include -#include -#include "fhci.h" - -void fhci_dbg_isr(struct fhci_hcd *fhci, int usb_er) -{ - int i; - - if (usb_er == -1) { - fhci->usb_irq_stat[12]++; - return; - } - - for (i = 0; i < 12; ++i) { - if (usb_er & (1 << i)) - fhci->usb_irq_stat[i]++; - } -} - -static int fhci_dfs_regs_show(struct seq_file *s, void *v) -{ - struct fhci_hcd *fhci = s->private; - struct fhci_regs __iomem *regs = fhci->regs; - - seq_printf(s, - "mode: 0x%x\n" "addr: 0x%x\n" - "command: 0x%x\n" "ep0: 0x%x\n" - "event: 0x%x\n" "mask: 0x%x\n" - "status: 0x%x\n" "SOF timer: %d\n" - "frame number: %d\n" - "lines status: 0x%x\n", - in_8(®s->usb_mod), in_8(®s->usb_addr), - in_8(®s->usb_comm), in_be16(®s->usb_ep[0]), - in_be16(®s->usb_event), in_be16(®s->usb_mask), - in_8(®s->usb_status), in_be16(®s->usb_sof_tmr), - in_be16(®s->usb_frame_num), - fhci_ioports_check_bus_state(fhci)); - - return 0; -} - -static int fhci_dfs_irq_stat_show(struct seq_file *s, void *v) -{ - struct fhci_hcd *fhci = s->private; - int *usb_irq_stat = fhci->usb_irq_stat; - - seq_printf(s, - "RXB: %d\n" "TXB: %d\n" "BSY: %d\n" - "SOF: %d\n" "TXE0: %d\n" "TXE1: %d\n" - "TXE2: %d\n" "TXE3: %d\n" "IDLE: %d\n" - "RESET: %d\n" "SFT: %d\n" "MSF: %d\n" - "IDLE_ONLY: %d\n", - usb_irq_stat[0], usb_irq_stat[1], usb_irq_stat[2], - usb_irq_stat[3], usb_irq_stat[4], usb_irq_stat[5], - usb_irq_stat[6], usb_irq_stat[7], usb_irq_stat[8], - usb_irq_stat[9], usb_irq_stat[10], usb_irq_stat[11], - usb_irq_stat[12]); - - return 0; -} - -static int fhci_dfs_regs_open(struct inode *inode, struct file *file) -{ - return single_open(file, fhci_dfs_regs_show, inode->i_private); -} - -static int fhci_dfs_irq_stat_open(struct inode *inode, struct file *file) -{ - return single_open(file, fhci_dfs_irq_stat_show, inode->i_private); -} - -static const struct file_operations fhci_dfs_regs_fops = { - .open = fhci_dfs_regs_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations fhci_dfs_irq_stat_fops = { - .open = fhci_dfs_irq_stat_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -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), usb_debug_root); - if (!fhci->dfs_root) { - WARN_ON(1); - return; - } - - fhci->dfs_regs = debugfs_create_file("regs", S_IFREG | S_IRUGO, - fhci->dfs_root, fhci, &fhci_dfs_regs_fops); - - fhci->dfs_irq_stat = debugfs_create_file("irq_stat", - S_IFREG | S_IRUGO, fhci->dfs_root, fhci, - &fhci_dfs_irq_stat_fops); - - WARN_ON(!fhci->dfs_regs || !fhci->dfs_irq_stat); -} - -void fhci_dfs_destroy(struct fhci_hcd *fhci) -{ - if (!fhci->dfs_root) - return; - - if (fhci->dfs_irq_stat) - debugfs_remove(fhci->dfs_irq_stat); - - if (fhci->dfs_regs) - debugfs_remove(fhci->dfs_regs); - - debugfs_remove(fhci->dfs_root); -} diff --git a/ANDROID_3.4.5/drivers/usb/host/fhci-hcd.c b/ANDROID_3.4.5/drivers/usb/host/fhci-hcd.c deleted file mode 100644 index d2623747..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/fhci-hcd.c +++ /dev/null @@ -1,833 +0,0 @@ -/* - * Freescale QUICC Engine USB Host Controller Driver - * - * Copyright (c) Freescale Semicondutor, Inc. 2006. - * Shlomi Gridish - * Jerry Huang - * Copyright (c) Logic Product Development, Inc. 2007 - * Peter Barada - * Copyright (c) MontaVista Software, Inc. 2008. - * Anton Vorontsov - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "fhci.h" - -void fhci_start_sof_timer(struct fhci_hcd *fhci) -{ - fhci_dbg(fhci, "-> %s\n", __func__); - - /* clear frame_n */ - out_be16(&fhci->pram->frame_num, 0); - - out_be16(&fhci->regs->usb_sof_tmr, 0); - setbits8(&fhci->regs->usb_mod, USB_MODE_SFTE); - - fhci_dbg(fhci, "<- %s\n", __func__); -} - -void fhci_stop_sof_timer(struct fhci_hcd *fhci) -{ - fhci_dbg(fhci, "-> %s\n", __func__); - - clrbits8(&fhci->regs->usb_mod, USB_MODE_SFTE); - gtm_stop_timer16(fhci->timer); - - fhci_dbg(fhci, "<- %s\n", __func__); -} - -u16 fhci_get_sof_timer_count(struct fhci_usb *usb) -{ - return be16_to_cpu(in_be16(&usb->fhci->regs->usb_sof_tmr) / 12); -} - -/* initialize the endpoint zero */ -static u32 endpoint_zero_init(struct fhci_usb *usb, - enum fhci_mem_alloc data_mem, - u32 ring_len) -{ - u32 rc; - - rc = fhci_create_ep(usb, data_mem, ring_len); - if (rc) - return rc; - - /* inilialize endpoint registers */ - fhci_init_ep_registers(usb, usb->ep0, data_mem); - - return 0; -} - -/* enable the USB interrupts */ -void fhci_usb_enable_interrupt(struct fhci_usb *usb) -{ - struct fhci_hcd *fhci = usb->fhci; - - if (usb->intr_nesting_cnt == 1) { - /* initialize the USB interrupt */ - enable_irq(fhci_to_hcd(fhci)->irq); - - /* initialize the event register and mask register */ - out_be16(&usb->fhci->regs->usb_event, 0xffff); - out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk); - - /* enable the timer interrupts */ - enable_irq(fhci->timer->irq); - } else if (usb->intr_nesting_cnt > 1) - fhci_info(fhci, "unbalanced USB interrupts nesting\n"); - usb->intr_nesting_cnt--; -} - -/* disable the usb interrupt */ -void fhci_usb_disable_interrupt(struct fhci_usb *usb) -{ - struct fhci_hcd *fhci = usb->fhci; - - if (usb->intr_nesting_cnt == 0) { - /* disable the timer interrupt */ - disable_irq_nosync(fhci->timer->irq); - - /* disable the usb interrupt */ - disable_irq_nosync(fhci_to_hcd(fhci)->irq); - out_be16(&usb->fhci->regs->usb_mask, 0); - } - usb->intr_nesting_cnt++; -} - -/* enable the USB controller */ -static u32 fhci_usb_enable(struct fhci_hcd *fhci) -{ - struct fhci_usb *usb = fhci->usb_lld; - - out_be16(&usb->fhci->regs->usb_event, 0xffff); - out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk); - setbits8(&usb->fhci->regs->usb_mod, USB_MODE_EN); - - mdelay(100); - - return 0; -} - -/* disable the USB controller */ -static u32 fhci_usb_disable(struct fhci_hcd *fhci) -{ - struct fhci_usb *usb = fhci->usb_lld; - - fhci_usb_disable_interrupt(usb); - fhci_port_disable(fhci); - - /* disable the usb controller */ - if (usb->port_status == FHCI_PORT_FULL || - usb->port_status == FHCI_PORT_LOW) - fhci_device_disconnected_interrupt(fhci); - - clrbits8(&usb->fhci->regs->usb_mod, USB_MODE_EN); - - return 0; -} - -/* check the bus state by polling the QE bit on the IO ports */ -int fhci_ioports_check_bus_state(struct fhci_hcd *fhci) -{ - u8 bits = 0; - - /* check USBOE,if transmitting,exit */ - if (!gpio_get_value(fhci->gpios[GPIO_USBOE])) - return -1; - - /* check USBRP */ - if (gpio_get_value(fhci->gpios[GPIO_USBRP])) - bits |= 0x2; - - /* check USBRN */ - if (gpio_get_value(fhci->gpios[GPIO_USBRN])) - bits |= 0x1; - - return bits; -} - -static void fhci_mem_free(struct fhci_hcd *fhci) -{ - struct ed *ed; - struct ed *next_ed; - struct td *td; - struct td *next_td; - - list_for_each_entry_safe(ed, next_ed, &fhci->empty_eds, node) { - list_del(&ed->node); - kfree(ed); - } - - list_for_each_entry_safe(td, next_td, &fhci->empty_tds, node) { - list_del(&td->node); - kfree(td); - } - - kfree(fhci->vroot_hub); - fhci->vroot_hub = NULL; - - kfree(fhci->hc_list); - fhci->hc_list = NULL; -} - -static int fhci_mem_init(struct fhci_hcd *fhci) -{ - int i; - - fhci->hc_list = kzalloc(sizeof(*fhci->hc_list), GFP_KERNEL); - if (!fhci->hc_list) - goto err; - - INIT_LIST_HEAD(&fhci->hc_list->ctrl_list); - INIT_LIST_HEAD(&fhci->hc_list->bulk_list); - INIT_LIST_HEAD(&fhci->hc_list->iso_list); - INIT_LIST_HEAD(&fhci->hc_list->intr_list); - INIT_LIST_HEAD(&fhci->hc_list->done_list); - - fhci->vroot_hub = kzalloc(sizeof(*fhci->vroot_hub), GFP_KERNEL); - if (!fhci->vroot_hub) - goto err; - - INIT_LIST_HEAD(&fhci->empty_eds); - INIT_LIST_HEAD(&fhci->empty_tds); - - /* initialize work queue to handle done list */ - fhci_tasklet.data = (unsigned long)fhci; - fhci->process_done_task = &fhci_tasklet; - - for (i = 0; i < MAX_TDS; i++) { - struct td *td; - - td = kmalloc(sizeof(*td), GFP_KERNEL); - if (!td) - goto err; - fhci_recycle_empty_td(fhci, td); - } - for (i = 0; i < MAX_EDS; i++) { - struct ed *ed; - - ed = kmalloc(sizeof(*ed), GFP_KERNEL); - if (!ed) - goto err; - fhci_recycle_empty_ed(fhci, ed); - } - - fhci->active_urbs = 0; - return 0; -err: - fhci_mem_free(fhci); - return -ENOMEM; -} - -/* destroy the fhci_usb structure */ -static void fhci_usb_free(void *lld) -{ - struct fhci_usb *usb = lld; - struct fhci_hcd *fhci; - - if (usb) { - fhci = usb->fhci; - fhci_config_transceiver(fhci, FHCI_PORT_POWER_OFF); - fhci_ep0_free(usb); - kfree(usb->actual_frame); - kfree(usb); - } -} - -/* initialize the USB */ -static int fhci_usb_init(struct fhci_hcd *fhci) -{ - struct fhci_usb *usb = fhci->usb_lld; - - memset_io(usb->fhci->pram, 0, FHCI_PRAM_SIZE); - - usb->port_status = FHCI_PORT_DISABLED; - usb->max_frame_usage = FRAME_TIME_USAGE; - usb->sw_transaction_time = SW_FIX_TIME_BETWEEN_TRANSACTION; - - usb->actual_frame = kzalloc(sizeof(*usb->actual_frame), GFP_KERNEL); - if (!usb->actual_frame) { - fhci_usb_free(usb); - return -ENOMEM; - } - - INIT_LIST_HEAD(&usb->actual_frame->tds_list); - - /* initializing registers on chip, clear frame number */ - out_be16(&fhci->pram->frame_num, 0); - - /* clear rx state */ - out_be32(&fhci->pram->rx_state, 0); - - /* set mask register */ - usb->saved_msk = (USB_E_TXB_MASK | - USB_E_TXE1_MASK | - USB_E_IDLE_MASK | - USB_E_RESET_MASK | USB_E_SFT_MASK | USB_E_MSF_MASK); - - out_8(&usb->fhci->regs->usb_mod, USB_MODE_HOST | USB_MODE_EN); - - /* clearing the mask register */ - out_be16(&usb->fhci->regs->usb_mask, 0); - - /* initialing the event register */ - out_be16(&usb->fhci->regs->usb_event, 0xffff); - - if (endpoint_zero_init(usb, DEFAULT_DATA_MEM, DEFAULT_RING_LEN) != 0) { - fhci_usb_free(usb); - return -EINVAL; - } - - return 0; -} - -/* initialize the fhci_usb struct and the corresponding data staruct */ -static struct fhci_usb *fhci_create_lld(struct fhci_hcd *fhci) -{ - struct fhci_usb *usb; - - /* allocate memory for SCC data structure */ - usb = kzalloc(sizeof(*usb), GFP_KERNEL); - if (!usb) { - fhci_err(fhci, "no memory for SCC data struct\n"); - return NULL; - } - - usb->fhci = fhci; - usb->hc_list = fhci->hc_list; - usb->vroot_hub = fhci->vroot_hub; - - usb->transfer_confirm = fhci_transfer_confirm_callback; - - return usb; -} - -static int fhci_start(struct usb_hcd *hcd) -{ - int ret; - struct fhci_hcd *fhci = hcd_to_fhci(hcd); - - ret = fhci_mem_init(fhci); - if (ret) { - fhci_err(fhci, "failed to allocate memory\n"); - goto err; - } - - fhci->usb_lld = fhci_create_lld(fhci); - if (!fhci->usb_lld) { - fhci_err(fhci, "low level driver config failed\n"); - ret = -ENOMEM; - goto err; - } - - ret = fhci_usb_init(fhci); - if (ret) { - fhci_err(fhci, "low level driver initialize failed\n"); - goto err; - } - - spin_lock_init(&fhci->lock); - - /* connect the virtual root hub */ - fhci->vroot_hub->dev_num = 1; /* this field may be needed to fix */ - fhci->vroot_hub->hub.wHubStatus = 0; - fhci->vroot_hub->hub.wHubChange = 0; - fhci->vroot_hub->port.wPortStatus = 0; - fhci->vroot_hub->port.wPortChange = 0; - - hcd->state = HC_STATE_RUNNING; - - /* - * From here on, khubd concurrently accesses the root - * hub; drivers will be talking to enumerated devices. - * (On restart paths, khubd already knows about the root - * hub and could find work as soon as we wrote FLAG_CF.) - * - * Before this point the HC was idle/ready. After, khubd - * and device drivers may start it running. - */ - fhci_usb_enable(fhci); - return 0; -err: - fhci_mem_free(fhci); - return ret; -} - -static void fhci_stop(struct usb_hcd *hcd) -{ - struct fhci_hcd *fhci = hcd_to_fhci(hcd); - - fhci_usb_disable_interrupt(fhci->usb_lld); - fhci_usb_disable(fhci); - - fhci_usb_free(fhci->usb_lld); - fhci->usb_lld = NULL; - fhci_mem_free(fhci); -} - -static int fhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, - gfp_t mem_flags) -{ - struct fhci_hcd *fhci = hcd_to_fhci(hcd); - u32 pipe = urb->pipe; - int ret; - int i; - int size = 0; - struct urb_priv *urb_priv; - unsigned long flags; - - switch (usb_pipetype(pipe)) { - case PIPE_CONTROL: - /* 1 td fro setup,1 for ack */ - size = 2; - case PIPE_BULK: - /* one td for every 4096 bytes(can be up to 8k) */ - size += urb->transfer_buffer_length / 4096; - /* ...add for any remaining bytes... */ - if ((urb->transfer_buffer_length % 4096) != 0) - size++; - /* ..and maybe a zero length packet to wrap it up */ - if (size == 0) - size++; - else if ((urb->transfer_flags & URB_ZERO_PACKET) != 0 - && (urb->transfer_buffer_length - % usb_maxpacket(urb->dev, pipe, - usb_pipeout(pipe))) != 0) - size++; - break; - case PIPE_ISOCHRONOUS: - size = urb->number_of_packets; - if (size <= 0) - return -EINVAL; - for (i = 0; i < urb->number_of_packets; i++) { - urb->iso_frame_desc[i].actual_length = 0; - urb->iso_frame_desc[i].status = (u32) (-EXDEV); - } - break; - case PIPE_INTERRUPT: - size = 1; - } - - /* allocate the private part of the URB */ - urb_priv = kzalloc(sizeof(*urb_priv), mem_flags); - if (!urb_priv) - return -ENOMEM; - - /* allocate the private part of the URB */ - urb_priv->tds = kcalloc(size, sizeof(*urb_priv->tds), mem_flags); - if (!urb_priv->tds) { - kfree(urb_priv); - return -ENOMEM; - } - - spin_lock_irqsave(&fhci->lock, flags); - - ret = usb_hcd_link_urb_to_ep(hcd, urb); - if (ret) - goto err; - - /* fill the private part of the URB */ - urb_priv->num_of_tds = size; - - urb->status = -EINPROGRESS; - urb->actual_length = 0; - urb->error_count = 0; - urb->hcpriv = urb_priv; - - fhci_queue_urb(fhci, urb); -err: - if (ret) { - kfree(urb_priv->tds); - kfree(urb_priv); - } - spin_unlock_irqrestore(&fhci->lock, flags); - return ret; -} - -/* dequeue FHCI URB */ -static int fhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) -{ - struct fhci_hcd *fhci = hcd_to_fhci(hcd); - struct fhci_usb *usb = fhci->usb_lld; - int ret = -EINVAL; - unsigned long flags; - - if (!urb || !urb->dev || !urb->dev->bus) - goto out; - - spin_lock_irqsave(&fhci->lock, flags); - - ret = usb_hcd_check_unlink_urb(hcd, urb, status); - if (ret) - goto out2; - - if (usb->port_status != FHCI_PORT_DISABLED) { - struct urb_priv *urb_priv; - - /* - * flag the urb's data for deletion in some upcoming - * SF interrupt's delete list processing - */ - urb_priv = urb->hcpriv; - - if (!urb_priv || (urb_priv->state == URB_DEL)) - goto out2; - - urb_priv->state = URB_DEL; - - /* already pending? */ - urb_priv->ed->state = FHCI_ED_URB_DEL; - } else { - fhci_urb_complete_free(fhci, urb); - } - -out2: - spin_unlock_irqrestore(&fhci->lock, flags); -out: - return ret; -} - -static void fhci_endpoint_disable(struct usb_hcd *hcd, - struct usb_host_endpoint *ep) -{ - struct fhci_hcd *fhci; - struct ed *ed; - unsigned long flags; - - fhci = hcd_to_fhci(hcd); - spin_lock_irqsave(&fhci->lock, flags); - ed = ep->hcpriv; - if (ed) { - while (ed->td_head != NULL) { - struct td *td = fhci_remove_td_from_ed(ed); - fhci_urb_complete_free(fhci, td->urb); - } - fhci_recycle_empty_ed(fhci, ed); - ep->hcpriv = NULL; - } - spin_unlock_irqrestore(&fhci->lock, flags); -} - -static int fhci_get_frame_number(struct usb_hcd *hcd) -{ - struct fhci_hcd *fhci = hcd_to_fhci(hcd); - - return get_frame_num(fhci); -} - -static const struct hc_driver fhci_driver = { - .description = "fsl,usb-fhci", - .product_desc = "FHCI HOST Controller", - .hcd_priv_size = sizeof(struct fhci_hcd), - - /* generic hardware linkage */ - .irq = fhci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* basic lifecycle operation */ - .start = fhci_start, - .stop = fhci_stop, - - /* managing i/o requests and associated device resources */ - .urb_enqueue = fhci_urb_enqueue, - .urb_dequeue = fhci_urb_dequeue, - .endpoint_disable = fhci_endpoint_disable, - - /* scheduling support */ - .get_frame_number = fhci_get_frame_number, - - /* root hub support */ - .hub_status_data = fhci_hub_status_data, - .hub_control = fhci_hub_control, -}; - -static int __devinit of_fhci_probe(struct platform_device *ofdev) -{ - struct device *dev = &ofdev->dev; - struct device_node *node = dev->of_node; - struct usb_hcd *hcd; - struct fhci_hcd *fhci; - struct resource usb_regs; - unsigned long pram_addr; - unsigned int usb_irq; - const char *sprop; - const u32 *iprop; - int size; - int ret; - int i; - int j; - - if (usb_disabled()) - return -ENODEV; - - sprop = of_get_property(node, "mode", NULL); - if (sprop && strcmp(sprop, "host")) - return -ENODEV; - - hcd = usb_create_hcd(&fhci_driver, dev, dev_name(dev)); - if (!hcd) { - dev_err(dev, "could not create hcd\n"); - return -ENOMEM; - } - - fhci = hcd_to_fhci(hcd); - hcd->self.controller = dev; - dev_set_drvdata(dev, hcd); - - iprop = of_get_property(node, "hub-power-budget", &size); - if (iprop && size == sizeof(*iprop)) - hcd->power_budget = *iprop; - - /* FHCI registers. */ - ret = of_address_to_resource(node, 0, &usb_regs); - if (ret) { - dev_err(dev, "could not get regs\n"); - goto err_regs; - } - - hcd->regs = ioremap(usb_regs.start, resource_size(&usb_regs)); - if (!hcd->regs) { - dev_err(dev, "could not ioremap regs\n"); - ret = -ENOMEM; - goto err_regs; - } - fhci->regs = hcd->regs; - - /* Parameter RAM. */ - iprop = of_get_property(node, "reg", &size); - if (!iprop || size < sizeof(*iprop) * 4) { - dev_err(dev, "can't get pram offset\n"); - ret = -EINVAL; - goto err_pram; - } - - pram_addr = cpm_muram_alloc(FHCI_PRAM_SIZE, 64); - if (IS_ERR_VALUE(pram_addr)) { - dev_err(dev, "failed to allocate usb pram\n"); - ret = -ENOMEM; - goto err_pram; - } - - qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, QE_CR_SUBBLOCK_USB, - QE_CR_PROTOCOL_UNSPECIFIED, pram_addr); - fhci->pram = cpm_muram_addr(pram_addr); - - /* GPIOs and pins */ - for (i = 0; i < NUM_GPIOS; i++) { - int gpio; - enum of_gpio_flags flags; - - gpio = of_get_gpio_flags(node, i, &flags); - fhci->gpios[i] = gpio; - fhci->alow_gpios[i] = flags & OF_GPIO_ACTIVE_LOW; - - if (!gpio_is_valid(gpio)) { - if (i < GPIO_SPEED) { - dev_err(dev, "incorrect GPIO%d: %d\n", - i, gpio); - goto err_gpios; - } else { - dev_info(dev, "assuming board doesn't have " - "%s gpio\n", i == GPIO_SPEED ? - "speed" : "power"); - continue; - } - } - - ret = gpio_request(gpio, dev_name(dev)); - if (ret) { - dev_err(dev, "failed to request gpio %d", i); - goto err_gpios; - } - - if (i >= GPIO_SPEED) { - ret = gpio_direction_output(gpio, 0); - if (ret) { - dev_err(dev, "failed to set gpio %d as " - "an output\n", i); - i++; - goto err_gpios; - } - } - } - - for (j = 0; j < NUM_PINS; j++) { - fhci->pins[j] = qe_pin_request(node, j); - if (IS_ERR(fhci->pins[j])) { - ret = PTR_ERR(fhci->pins[j]); - dev_err(dev, "can't get pin %d: %d\n", j, ret); - goto err_pins; - } - } - - /* Frame limit timer and its interrupt. */ - fhci->timer = gtm_get_timer16(); - if (IS_ERR(fhci->timer)) { - ret = PTR_ERR(fhci->timer); - dev_err(dev, "failed to request qe timer: %i", ret); - goto err_get_timer; - } - - ret = request_irq(fhci->timer->irq, fhci_frame_limit_timer_irq, - 0, "qe timer (usb)", hcd); - if (ret) { - dev_err(dev, "failed to request timer irq"); - goto err_timer_irq; - } - - /* USB Host interrupt. */ - usb_irq = irq_of_parse_and_map(node, 0); - if (usb_irq == NO_IRQ) { - dev_err(dev, "could not get usb irq\n"); - ret = -EINVAL; - goto err_usb_irq; - } - - /* Clocks. */ - sprop = of_get_property(node, "fsl,fullspeed-clock", NULL); - if (sprop) { - fhci->fullspeed_clk = qe_clock_source(sprop); - if (fhci->fullspeed_clk == QE_CLK_DUMMY) { - dev_err(dev, "wrong fullspeed-clock\n"); - ret = -EINVAL; - goto err_clocks; - } - } - - sprop = of_get_property(node, "fsl,lowspeed-clock", NULL); - if (sprop) { - fhci->lowspeed_clk = qe_clock_source(sprop); - if (fhci->lowspeed_clk == QE_CLK_DUMMY) { - dev_err(dev, "wrong lowspeed-clock\n"); - ret = -EINVAL; - goto err_clocks; - } - } - - if (fhci->fullspeed_clk == QE_CLK_NONE && - fhci->lowspeed_clk == QE_CLK_NONE) { - dev_err(dev, "no clocks specified\n"); - ret = -EINVAL; - goto err_clocks; - } - - dev_info(dev, "at 0x%p, irq %d\n", hcd->regs, usb_irq); - - fhci_config_transceiver(fhci, FHCI_PORT_POWER_OFF); - - /* Start with full-speed, if possible. */ - if (fhci->fullspeed_clk != QE_CLK_NONE) { - fhci_config_transceiver(fhci, FHCI_PORT_FULL); - qe_usb_clock_set(fhci->fullspeed_clk, USB_CLOCK); - } else { - fhci_config_transceiver(fhci, FHCI_PORT_LOW); - qe_usb_clock_set(fhci->lowspeed_clk, USB_CLOCK >> 3); - } - - /* Clear and disable any pending interrupts. */ - out_be16(&fhci->regs->usb_event, 0xffff); - out_be16(&fhci->regs->usb_mask, 0); - - ret = usb_add_hcd(hcd, usb_irq, 0); - if (ret < 0) - goto err_add_hcd; - - fhci_dfs_create(fhci); - - return 0; - -err_add_hcd: -err_clocks: - irq_dispose_mapping(usb_irq); -err_usb_irq: - free_irq(fhci->timer->irq, hcd); -err_timer_irq: - gtm_put_timer16(fhci->timer); -err_get_timer: -err_pins: - while (--j >= 0) - qe_pin_free(fhci->pins[j]); -err_gpios: - while (--i >= 0) { - if (gpio_is_valid(fhci->gpios[i])) - gpio_free(fhci->gpios[i]); - } - cpm_muram_free(pram_addr); -err_pram: - iounmap(hcd->regs); -err_regs: - usb_put_hcd(hcd); - return ret; -} - -static int __devexit fhci_remove(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct fhci_hcd *fhci = hcd_to_fhci(hcd); - int i; - int j; - - usb_remove_hcd(hcd); - free_irq(fhci->timer->irq, hcd); - gtm_put_timer16(fhci->timer); - cpm_muram_free(cpm_muram_offset(fhci->pram)); - for (i = 0; i < NUM_GPIOS; i++) { - if (!gpio_is_valid(fhci->gpios[i])) - continue; - gpio_free(fhci->gpios[i]); - } - for (j = 0; j < NUM_PINS; j++) - qe_pin_free(fhci->pins[j]); - fhci_dfs_destroy(fhci); - usb_put_hcd(hcd); - return 0; -} - -static int __devexit of_fhci_remove(struct platform_device *ofdev) -{ - return fhci_remove(&ofdev->dev); -} - -static const struct of_device_id of_fhci_match[] = { - { .compatible = "fsl,mpc8323-qe-usb", }, - {}, -}; -MODULE_DEVICE_TABLE(of, of_fhci_match); - -static struct platform_driver of_fhci_driver = { - .driver = { - .name = "fsl,usb-fhci", - .owner = THIS_MODULE, - .of_match_table = of_fhci_match, - }, - .probe = of_fhci_probe, - .remove = __devexit_p(of_fhci_remove), -}; - -module_platform_driver(of_fhci_driver); - -MODULE_DESCRIPTION("USB Freescale Host Controller Interface Driver"); -MODULE_AUTHOR("Shlomi Gridish , " - "Jerry Huang , " - "Anton Vorontsov "); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/host/fhci-hub.c b/ANDROID_3.4.5/drivers/usb/host/fhci-hub.c deleted file mode 100644 index 348fe62e..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/fhci-hub.c +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Freescale QUICC Engine USB Host Controller Driver - * - * Copyright (c) Freescale Semicondutor, Inc. 2006. - * Shlomi Gridish - * Jerry Huang - * Copyright (c) Logic Product Development, Inc. 2007 - * Peter Barada - * Copyright (c) MontaVista Software, Inc. 2008. - * Anton Vorontsov - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "fhci.h" - -/* virtual root hub specific descriptor */ -static u8 root_hub_des[] = { - 0x09, /* blength */ - 0x29, /* bDescriptorType;hub-descriptor */ - 0x01, /* bNbrPorts */ - 0x00, /* wHubCharacteristics */ - 0x00, - 0x01, /* bPwrOn2pwrGood;2ms */ - 0x00, /* bHubContrCurrent;0mA */ - 0x00, /* DeviceRemoveable */ - 0xff, /* PortPwrCtrlMask */ -}; - -static void fhci_gpio_set_value(struct fhci_hcd *fhci, int gpio_nr, bool on) -{ - int gpio = fhci->gpios[gpio_nr]; - bool alow = fhci->alow_gpios[gpio_nr]; - - if (!gpio_is_valid(gpio)) - return; - - gpio_set_value(gpio, on ^ alow); - mdelay(5); -} - -void fhci_config_transceiver(struct fhci_hcd *fhci, - enum fhci_port_status status) -{ - fhci_dbg(fhci, "-> %s: %d\n", __func__, status); - - switch (status) { - case FHCI_PORT_POWER_OFF: - fhci_gpio_set_value(fhci, GPIO_POWER, false); - break; - case FHCI_PORT_DISABLED: - case FHCI_PORT_WAITING: - fhci_gpio_set_value(fhci, GPIO_POWER, true); - break; - case FHCI_PORT_LOW: - fhci_gpio_set_value(fhci, GPIO_SPEED, false); - break; - case FHCI_PORT_FULL: - fhci_gpio_set_value(fhci, GPIO_SPEED, true); - break; - default: - WARN_ON(1); - break; - } - - fhci_dbg(fhci, "<- %s: %d\n", __func__, status); -} - -/* disable the USB port by clearing the EN bit in the USBMOD register */ -void fhci_port_disable(struct fhci_hcd *fhci) -{ - struct fhci_usb *usb = (struct fhci_usb *)fhci->usb_lld; - enum fhci_port_status port_status; - - fhci_dbg(fhci, "-> %s\n", __func__); - - fhci_stop_sof_timer(fhci); - - fhci_flush_all_transmissions(usb); - - fhci_usb_disable_interrupt((struct fhci_usb *)fhci->usb_lld); - port_status = usb->port_status; - usb->port_status = FHCI_PORT_DISABLED; - - /* Enable IDLE since we want to know if something comes along */ - usb->saved_msk |= USB_E_IDLE_MASK; - out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk); - - /* check if during the disconnection process attached new device */ - if (port_status == FHCI_PORT_WAITING) - fhci_device_connected_interrupt(fhci); - usb->vroot_hub->port.wPortStatus &= ~USB_PORT_STAT_ENABLE; - usb->vroot_hub->port.wPortChange |= USB_PORT_STAT_C_ENABLE; - fhci_usb_enable_interrupt((struct fhci_usb *)fhci->usb_lld); - - fhci_dbg(fhci, "<- %s\n", __func__); -} - -/* enable the USB port by setting the EN bit in the USBMOD register */ -void fhci_port_enable(void *lld) -{ - struct fhci_usb *usb = (struct fhci_usb *)lld; - struct fhci_hcd *fhci = usb->fhci; - - fhci_dbg(fhci, "-> %s\n", __func__); - - fhci_config_transceiver(fhci, usb->port_status); - - if ((usb->port_status != FHCI_PORT_FULL) && - (usb->port_status != FHCI_PORT_LOW)) - fhci_start_sof_timer(fhci); - - usb->vroot_hub->port.wPortStatus |= USB_PORT_STAT_ENABLE; - usb->vroot_hub->port.wPortChange |= USB_PORT_STAT_C_ENABLE; - - fhci_dbg(fhci, "<- %s\n", __func__); -} - -void fhci_io_port_generate_reset(struct fhci_hcd *fhci) -{ - fhci_dbg(fhci, "-> %s\n", __func__); - - gpio_direction_output(fhci->gpios[GPIO_USBOE], 0); - gpio_direction_output(fhci->gpios[GPIO_USBTP], 0); - gpio_direction_output(fhci->gpios[GPIO_USBTN], 0); - - mdelay(5); - - qe_pin_set_dedicated(fhci->pins[PIN_USBOE]); - qe_pin_set_dedicated(fhci->pins[PIN_USBTP]); - qe_pin_set_dedicated(fhci->pins[PIN_USBTN]); - - fhci_dbg(fhci, "<- %s\n", __func__); -} - -/* generate the RESET condition on the bus */ -void fhci_port_reset(void *lld) -{ - struct fhci_usb *usb = (struct fhci_usb *)lld; - struct fhci_hcd *fhci = usb->fhci; - u8 mode; - u16 mask; - - fhci_dbg(fhci, "-> %s\n", __func__); - - fhci_stop_sof_timer(fhci); - /* disable the USB controller */ - mode = in_8(&fhci->regs->usb_mod); - out_8(&fhci->regs->usb_mod, mode & (~USB_MODE_EN)); - - /* disable idle interrupts */ - mask = in_be16(&fhci->regs->usb_mask); - out_be16(&fhci->regs->usb_mask, mask & (~USB_E_IDLE_MASK)); - - fhci_io_port_generate_reset(fhci); - - /* enable interrupt on this endpoint */ - out_be16(&fhci->regs->usb_mask, mask); - - /* enable the USB controller */ - mode = in_8(&fhci->regs->usb_mod); - out_8(&fhci->regs->usb_mod, mode | USB_MODE_EN); - fhci_start_sof_timer(fhci); - - fhci_dbg(fhci, "<- %s\n", __func__); -} - -int fhci_hub_status_data(struct usb_hcd *hcd, char *buf) -{ - struct fhci_hcd *fhci = hcd_to_fhci(hcd); - int ret = 0; - unsigned long flags; - - fhci_dbg(fhci, "-> %s\n", __func__); - - spin_lock_irqsave(&fhci->lock, flags); - - if (fhci->vroot_hub->port.wPortChange & (USB_PORT_STAT_C_CONNECTION | - USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_SUSPEND | - USB_PORT_STAT_C_RESET | USB_PORT_STAT_C_OVERCURRENT)) { - *buf = 1 << 1; - ret = 1; - fhci_dbg(fhci, "-- %s\n", __func__); - } - - spin_unlock_irqrestore(&fhci->lock, flags); - - fhci_dbg(fhci, "<- %s\n", __func__); - - return ret; -} - -int fhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, - u16 wIndex, char *buf, u16 wLength) -{ - struct fhci_hcd *fhci = hcd_to_fhci(hcd); - int retval = 0; - int len = 0; - struct usb_hub_status *hub_status; - struct usb_port_status *port_status; - unsigned long flags; - - spin_lock_irqsave(&fhci->lock, flags); - - fhci_dbg(fhci, "-> %s\n", __func__); - - switch (typeReq) { - case ClearHubFeature: - switch (wValue) { - case C_HUB_LOCAL_POWER: - case C_HUB_OVER_CURRENT: - break; - default: - goto error; - } - break; - case ClearPortFeature: - fhci->vroot_hub->feature &= (1 << wValue); - - switch (wValue) { - case USB_PORT_FEAT_ENABLE: - fhci->vroot_hub->port.wPortStatus &= - ~USB_PORT_STAT_ENABLE; - fhci_port_disable(fhci); - break; - case USB_PORT_FEAT_C_ENABLE: - fhci->vroot_hub->port.wPortChange &= - ~USB_PORT_STAT_C_ENABLE; - break; - case USB_PORT_FEAT_SUSPEND: - fhci->vroot_hub->port.wPortStatus &= - ~USB_PORT_STAT_SUSPEND; - fhci_stop_sof_timer(fhci); - break; - case USB_PORT_FEAT_C_SUSPEND: - fhci->vroot_hub->port.wPortChange &= - ~USB_PORT_STAT_C_SUSPEND; - break; - case USB_PORT_FEAT_POWER: - fhci->vroot_hub->port.wPortStatus &= - ~USB_PORT_STAT_POWER; - fhci_config_transceiver(fhci, FHCI_PORT_POWER_OFF); - break; - case USB_PORT_FEAT_C_CONNECTION: - fhci->vroot_hub->port.wPortChange &= - ~USB_PORT_STAT_C_CONNECTION; - break; - case USB_PORT_FEAT_C_OVER_CURRENT: - fhci->vroot_hub->port.wPortChange &= - ~USB_PORT_STAT_C_OVERCURRENT; - break; - case USB_PORT_FEAT_C_RESET: - fhci->vroot_hub->port.wPortChange &= - ~USB_PORT_STAT_C_RESET; - break; - default: - goto error; - } - break; - case GetHubDescriptor: - memcpy(buf, root_hub_des, sizeof(root_hub_des)); - buf[3] = 0x11; /* per-port power, no ovrcrnt */ - len = (buf[0] < wLength) ? buf[0] : wLength; - break; - case GetHubStatus: - hub_status = (struct usb_hub_status *)buf; - hub_status->wHubStatus = - cpu_to_le16(fhci->vroot_hub->hub.wHubStatus); - hub_status->wHubChange = - cpu_to_le16(fhci->vroot_hub->hub.wHubChange); - len = 4; - break; - case GetPortStatus: - port_status = (struct usb_port_status *)buf; - port_status->wPortStatus = - cpu_to_le16(fhci->vroot_hub->port.wPortStatus); - port_status->wPortChange = - cpu_to_le16(fhci->vroot_hub->port.wPortChange); - len = 4; - break; - case SetHubFeature: - switch (wValue) { - case C_HUB_OVER_CURRENT: - case C_HUB_LOCAL_POWER: - break; - default: - goto error; - } - break; - case SetPortFeature: - fhci->vroot_hub->feature |= (1 << wValue); - - switch (wValue) { - case USB_PORT_FEAT_ENABLE: - fhci->vroot_hub->port.wPortStatus |= - USB_PORT_STAT_ENABLE; - fhci_port_enable(fhci->usb_lld); - break; - case USB_PORT_FEAT_SUSPEND: - fhci->vroot_hub->port.wPortStatus |= - USB_PORT_STAT_SUSPEND; - fhci_stop_sof_timer(fhci); - break; - case USB_PORT_FEAT_RESET: - fhci->vroot_hub->port.wPortStatus |= - USB_PORT_STAT_RESET; - fhci_port_reset(fhci->usb_lld); - fhci->vroot_hub->port.wPortStatus |= - USB_PORT_STAT_ENABLE; - fhci->vroot_hub->port.wPortStatus &= - ~USB_PORT_STAT_RESET; - break; - case USB_PORT_FEAT_POWER: - fhci->vroot_hub->port.wPortStatus |= - USB_PORT_STAT_POWER; - fhci_config_transceiver(fhci, FHCI_PORT_WAITING); - break; - default: - goto error; - } - break; - default: -error: - retval = -EPIPE; - } - - fhci_dbg(fhci, "<- %s\n", __func__); - - spin_unlock_irqrestore(&fhci->lock, flags); - - return retval; -} diff --git a/ANDROID_3.4.5/drivers/usb/host/fhci-mem.c b/ANDROID_3.4.5/drivers/usb/host/fhci-mem.c deleted file mode 100644 index b0b88f57..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/fhci-mem.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Freescale QUICC Engine USB Host Controller Driver - * - * Copyright (c) Freescale Semicondutor, Inc. 2006. - * Shlomi Gridish - * Jerry Huang - * Copyright (c) Logic Product Development, Inc. 2007 - * Peter Barada - * Copyright (c) MontaVista Software, Inc. 2008. - * Anton Vorontsov - * - * 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 -#include -#include -#include -#include -#include -#include -#include "fhci.h" - -static void init_td(struct td *td) -{ - memset(td, 0, sizeof(*td)); - INIT_LIST_HEAD(&td->node); - INIT_LIST_HEAD(&td->frame_lh); -} - -static void init_ed(struct ed *ed) -{ - memset(ed, 0, sizeof(*ed)); - INIT_LIST_HEAD(&ed->td_list); - INIT_LIST_HEAD(&ed->node); -} - -static struct td *get_empty_td(struct fhci_hcd *fhci) -{ - struct td *td; - - if (!list_empty(&fhci->empty_tds)) { - td = list_entry(fhci->empty_tds.next, struct td, node); - list_del(fhci->empty_tds.next); - } else { - td = kmalloc(sizeof(*td), GFP_ATOMIC); - if (!td) - fhci_err(fhci, "No memory to allocate to TD\n"); - else - init_td(td); - } - - return td; -} - -void fhci_recycle_empty_td(struct fhci_hcd *fhci, struct td *td) -{ - init_td(td); - list_add(&td->node, &fhci->empty_tds); -} - -struct ed *fhci_get_empty_ed(struct fhci_hcd *fhci) -{ - struct ed *ed; - - if (!list_empty(&fhci->empty_eds)) { - ed = list_entry(fhci->empty_eds.next, struct ed, node); - list_del(fhci->empty_eds.next); - } else { - ed = kmalloc(sizeof(*ed), GFP_ATOMIC); - if (!ed) - fhci_err(fhci, "No memory to allocate to ED\n"); - else - init_ed(ed); - } - - return ed; -} - -void fhci_recycle_empty_ed(struct fhci_hcd *fhci, struct ed *ed) -{ - init_ed(ed); - list_add(&ed->node, &fhci->empty_eds); -} - -struct td *fhci_td_fill(struct fhci_hcd *fhci, struct urb *urb, - struct urb_priv *urb_priv, struct ed *ed, u16 index, - enum fhci_ta_type type, int toggle, u8 *data, u32 len, - u16 interval, u16 start_frame, bool ioc) -{ - struct td *td = get_empty_td(fhci); - - if (!td) - return NULL; - - td->urb = urb; - td->ed = ed; - td->type = type; - td->toggle = toggle; - td->data = data; - td->len = len; - td->iso_index = index; - td->interval = interval; - td->start_frame = start_frame; - td->ioc = ioc; - td->status = USB_TD_OK; - - urb_priv->tds[index] = td; - - return td; -} diff --git a/ANDROID_3.4.5/drivers/usb/host/fhci-q.c b/ANDROID_3.4.5/drivers/usb/host/fhci-q.c deleted file mode 100644 index 03be7494..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/fhci-q.c +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Freescale QUICC Engine USB Host Controller Driver - * - * Copyright (c) Freescale Semicondutor, Inc. 2006. - * Shlomi Gridish - * Jerry Huang - * Copyright (c) Logic Product Development, Inc. 2007 - * Peter Barada - * Copyright (c) MontaVista Software, Inc. 2008. - * Anton Vorontsov - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include "fhci.h" - -/* maps the hardware error code to the USB error code */ -static int status_to_error(u32 status) -{ - if (status == USB_TD_OK) - return 0; - else if (status & USB_TD_RX_ER_CRC) - return -EILSEQ; - else if (status & USB_TD_RX_ER_NONOCT) - return -EPROTO; - else if (status & USB_TD_RX_ER_OVERUN) - return -ECOMM; - else if (status & USB_TD_RX_ER_BITSTUFF) - return -EPROTO; - else if (status & USB_TD_RX_ER_PID) - return -EILSEQ; - else if (status & (USB_TD_TX_ER_NAK | USB_TD_TX_ER_TIMEOUT)) - return -ETIMEDOUT; - else if (status & USB_TD_TX_ER_STALL) - return -EPIPE; - else if (status & USB_TD_TX_ER_UNDERUN) - return -ENOSR; - else if (status & USB_TD_RX_DATA_UNDERUN) - return -EREMOTEIO; - else if (status & USB_TD_RX_DATA_OVERUN) - return -EOVERFLOW; - else - return -EINVAL; -} - -void fhci_add_td_to_frame(struct fhci_time_frame *frame, struct td *td) -{ - list_add_tail(&td->frame_lh, &frame->tds_list); -} - -void fhci_add_tds_to_ed(struct ed *ed, struct td **td_list, int number) -{ - int i; - - for (i = 0; i < number; i++) { - struct td *td = td_list[i]; - list_add_tail(&td->node, &ed->td_list); - } - if (ed->td_head == NULL) - ed->td_head = td_list[0]; -} - -static struct td *peek_td_from_ed(struct ed *ed) -{ - struct td *td; - - if (!list_empty(&ed->td_list)) - td = list_entry(ed->td_list.next, struct td, node); - else - td = NULL; - - return td; -} - -struct td *fhci_remove_td_from_frame(struct fhci_time_frame *frame) -{ - struct td *td; - - if (!list_empty(&frame->tds_list)) { - td = list_entry(frame->tds_list.next, struct td, frame_lh); - list_del_init(frame->tds_list.next); - } else - td = NULL; - - return td; -} - -struct td *fhci_peek_td_from_frame(struct fhci_time_frame *frame) -{ - struct td *td; - - if (!list_empty(&frame->tds_list)) - td = list_entry(frame->tds_list.next, struct td, frame_lh); - else - td = NULL; - - return td; -} - -struct td *fhci_remove_td_from_ed(struct ed *ed) -{ - struct td *td; - - if (!list_empty(&ed->td_list)) { - td = list_entry(ed->td_list.next, struct td, node); - list_del_init(ed->td_list.next); - - /* if this TD was the ED's head, find next TD */ - if (!list_empty(&ed->td_list)) - ed->td_head = list_entry(ed->td_list.next, struct td, - node); - else - ed->td_head = NULL; - } else - td = NULL; - - return td; -} - -struct td *fhci_remove_td_from_done_list(struct fhci_controller_list *p_list) -{ - struct td *td; - - if (!list_empty(&p_list->done_list)) { - td = list_entry(p_list->done_list.next, struct td, node); - list_del_init(p_list->done_list.next); - } else - td = NULL; - - return td; -} - -void fhci_move_td_from_ed_to_done_list(struct fhci_usb *usb, struct ed *ed) -{ - struct td *td; - - td = ed->td_head; - list_del_init(&td->node); - - /* If this TD was the ED's head,find next TD */ - if (!list_empty(&ed->td_list)) - ed->td_head = list_entry(ed->td_list.next, struct td, node); - else { - ed->td_head = NULL; - ed->state = FHCI_ED_SKIP; - } - ed->toggle_carry = td->toggle; - list_add_tail(&td->node, &usb->hc_list->done_list); - if (td->ioc) - usb->transfer_confirm(usb->fhci); -} - -/* free done FHCI URB resource such as ED and TD */ -static void free_urb_priv(struct fhci_hcd *fhci, struct urb *urb) -{ - int i; - struct urb_priv *urb_priv = urb->hcpriv; - struct ed *ed = urb_priv->ed; - - for (i = 0; i < urb_priv->num_of_tds; i++) { - list_del_init(&urb_priv->tds[i]->node); - fhci_recycle_empty_td(fhci, urb_priv->tds[i]); - } - - /* if this TD was the ED's head,find the next TD */ - if (!list_empty(&ed->td_list)) - ed->td_head = list_entry(ed->td_list.next, struct td, node); - else - ed->td_head = NULL; - - kfree(urb_priv->tds); - kfree(urb_priv); - urb->hcpriv = NULL; - - /* if this TD was the ED's head,find next TD */ - if (ed->td_head == NULL) - list_del_init(&ed->node); - fhci->active_urbs--; -} - -/* this routine called to complete and free done URB */ -void fhci_urb_complete_free(struct fhci_hcd *fhci, struct urb *urb) -{ - free_urb_priv(fhci, urb); - - if (urb->status == -EINPROGRESS) { - if (urb->actual_length != urb->transfer_buffer_length && - urb->transfer_flags & URB_SHORT_NOT_OK) - urb->status = -EREMOTEIO; - else - urb->status = 0; - } - - usb_hcd_unlink_urb_from_ep(fhci_to_hcd(fhci), urb); - - spin_unlock(&fhci->lock); - - usb_hcd_giveback_urb(fhci_to_hcd(fhci), urb, urb->status); - - spin_lock(&fhci->lock); -} - -/* - * caculate transfer length/stats and update the urb - * Precondition: irqsafe(only for urb-?status locking) - */ -void fhci_done_td(struct urb *urb, struct td *td) -{ - struct ed *ed = td->ed; - u32 cc = td->status; - - /* ISO...drivers see per-TD length/status */ - if (ed->mode == FHCI_TF_ISO) { - u32 len; - if (!(urb->transfer_flags & URB_SHORT_NOT_OK && - cc == USB_TD_RX_DATA_UNDERUN)) - cc = USB_TD_OK; - - if (usb_pipeout(urb->pipe)) - len = urb->iso_frame_desc[td->iso_index].length; - else - len = td->actual_len; - - urb->actual_length += len; - urb->iso_frame_desc[td->iso_index].actual_length = len; - urb->iso_frame_desc[td->iso_index].status = - status_to_error(cc); - } - - /* BULK,INT,CONTROL... drivers see aggregate length/status, - * except that "setup" bytes aren't counted and "short" transfers - * might not be reported as errors. - */ - else { - if (td->error_cnt >= 3) - urb->error_count = 3; - - /* control endpoint only have soft stalls */ - - /* update packet status if needed(short may be ok) */ - if (!(urb->transfer_flags & URB_SHORT_NOT_OK) && - cc == USB_TD_RX_DATA_UNDERUN) { - ed->state = FHCI_ED_OPER; - cc = USB_TD_OK; - } - if (cc != USB_TD_OK) { - if (urb->status == -EINPROGRESS) - urb->status = status_to_error(cc); - } - - /* count all non-empty packets except control SETUP packet */ - if (td->type != FHCI_TA_SETUP || td->iso_index != 0) - urb->actual_length += td->actual_len; - } -} - -/* there are some pedning request to unlink */ -void fhci_del_ed_list(struct fhci_hcd *fhci, struct ed *ed) -{ - struct td *td = peek_td_from_ed(ed); - struct urb *urb = td->urb; - struct urb_priv *urb_priv = urb->hcpriv; - - if (urb_priv->state == URB_DEL) { - td = fhci_remove_td_from_ed(ed); - /* HC may have partly processed this TD */ - if (td->status != USB_TD_INPROGRESS) - fhci_done_td(urb, td); - - /* URB is done;clean up */ - if (++(urb_priv->tds_cnt) == urb_priv->num_of_tds) - fhci_urb_complete_free(fhci, urb); - } -} diff --git a/ANDROID_3.4.5/drivers/usb/host/fhci-sched.c b/ANDROID_3.4.5/drivers/usb/host/fhci-sched.c deleted file mode 100644 index 2df851b4..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/fhci-sched.c +++ /dev/null @@ -1,895 +0,0 @@ -/* - * Freescale QUICC Engine USB Host Controller Driver - * - * Copyright (c) Freescale Semicondutor, Inc. 2006, 2011. - * Shlomi Gridish - * Jerry Huang - * Copyright (c) Logic Product Development, Inc. 2007 - * Peter Barada - * Copyright (c) MontaVista Software, Inc. 2008. - * Anton Vorontsov - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "fhci.h" - -static void recycle_frame(struct fhci_usb *usb, struct packet *pkt) -{ - pkt->data = NULL; - pkt->len = 0; - pkt->status = USB_TD_OK; - pkt->info = 0; - pkt->priv_data = NULL; - - cq_put(&usb->ep0->empty_frame_Q, pkt); -} - -/* confirm submitted packet */ -void fhci_transaction_confirm(struct fhci_usb *usb, struct packet *pkt) -{ - struct td *td; - struct packet *td_pkt; - struct ed *ed; - u32 trans_len; - bool td_done = false; - - td = fhci_remove_td_from_frame(usb->actual_frame); - td_pkt = td->pkt; - trans_len = pkt->len; - td->status = pkt->status; - if (td->type == FHCI_TA_IN && td_pkt->info & PKT_DUMMY_PACKET) { - if ((td->data + td->actual_len) && trans_len) - memcpy(td->data + td->actual_len, pkt->data, - trans_len); - cq_put(&usb->ep0->dummy_packets_Q, pkt->data); - } - - recycle_frame(usb, pkt); - - ed = td->ed; - if (ed->mode == FHCI_TF_ISO) { - if (ed->td_list.next->next != &ed->td_list) { - struct td *td_next = - list_entry(ed->td_list.next->next, struct td, - node); - - td_next->start_frame = usb->actual_frame->frame_num; - } - td->actual_len = trans_len; - td_done = true; - } else if ((td->status & USB_TD_ERROR) && - !(td->status & USB_TD_TX_ER_NAK)) { - /* - * There was an error on the transaction (but not NAK). - * If it is fatal error (data underrun, stall, bad pid or 3 - * errors exceeded), mark this TD as done. - */ - if ((td->status & USB_TD_RX_DATA_UNDERUN) || - (td->status & USB_TD_TX_ER_STALL) || - (td->status & USB_TD_RX_ER_PID) || - (++td->error_cnt >= 3)) { - ed->state = FHCI_ED_HALTED; - td_done = true; - - if (td->status & USB_TD_RX_DATA_UNDERUN) { - fhci_dbg(usb->fhci, "td err fu\n"); - td->toggle = !td->toggle; - td->actual_len += trans_len; - } else { - fhci_dbg(usb->fhci, "td err f!u\n"); - } - } else { - fhci_dbg(usb->fhci, "td err !f\n"); - /* it is not a fatal error -retry this transaction */ - td->nak_cnt = 0; - td->error_cnt++; - td->status = USB_TD_OK; - } - } else if (td->status & USB_TD_TX_ER_NAK) { - /* there was a NAK response */ - fhci_vdbg(usb->fhci, "td nack\n"); - td->nak_cnt++; - td->error_cnt = 0; - td->status = USB_TD_OK; - } else { - /* there was no error on transaction */ - td->error_cnt = 0; - td->nak_cnt = 0; - td->toggle = !td->toggle; - td->actual_len += trans_len; - - if (td->len == td->actual_len) - td_done = true; - } - - if (td_done) - fhci_move_td_from_ed_to_done_list(usb, ed); -} - -/* - * Flush all transmitted packets from BDs - * This routine is called when disabling the USB port to flush all - * transmissions that are already scheduled in the BDs - */ -void fhci_flush_all_transmissions(struct fhci_usb *usb) -{ - u8 mode; - struct td *td; - - mode = in_8(&usb->fhci->regs->usb_mod); - clrbits8(&usb->fhci->regs->usb_mod, USB_MODE_EN); - - fhci_flush_bds(usb); - - while ((td = fhci_peek_td_from_frame(usb->actual_frame)) != NULL) { - struct packet *pkt = td->pkt; - - pkt->status = USB_TD_TX_ER_TIMEOUT; - fhci_transaction_confirm(usb, pkt); - } - - usb->actual_frame->frame_status = FRAME_END_TRANSMISSION; - - /* reset the event register */ - out_be16(&usb->fhci->regs->usb_event, 0xffff); - /* enable the USB controller */ - out_8(&usb->fhci->regs->usb_mod, mode | USB_MODE_EN); -} - -/* - * This function forms the packet and transmit the packet. This function - * will handle all endpoint type:ISO,interrupt,control and bulk - */ -static int add_packet(struct fhci_usb *usb, struct ed *ed, struct td *td) -{ - u32 fw_transaction_time, len = 0; - struct packet *pkt; - u8 *data = NULL; - - /* calcalate data address,len and toggle and then add the transaction */ - if (td->toggle == USB_TD_TOGGLE_CARRY) - td->toggle = ed->toggle_carry; - - switch (ed->mode) { - case FHCI_TF_ISO: - len = td->len; - if (td->type != FHCI_TA_IN) - data = td->data; - break; - case FHCI_TF_CTRL: - case FHCI_TF_BULK: - len = min(td->len - td->actual_len, ed->max_pkt_size); - if (!((td->type == FHCI_TA_IN) && - ((len + td->actual_len) == td->len))) - data = td->data + td->actual_len; - break; - case FHCI_TF_INTR: - len = min(td->len, ed->max_pkt_size); - if (!((td->type == FHCI_TA_IN) && - ((td->len + CRC_SIZE) >= ed->max_pkt_size))) - data = td->data; - break; - default: - break; - } - - if (usb->port_status == FHCI_PORT_FULL) - fw_transaction_time = (((len + PROTOCOL_OVERHEAD) * 11) >> 4); - else - fw_transaction_time = ((len + PROTOCOL_OVERHEAD) * 6); - - /* check if there's enough space in this frame to submit this TD */ - if (usb->actual_frame->total_bytes + len + PROTOCOL_OVERHEAD >= - usb->max_bytes_per_frame) { - fhci_vdbg(usb->fhci, "not enough space in this frame: " - "%d %d %d\n", usb->actual_frame->total_bytes, len, - usb->max_bytes_per_frame); - return -1; - } - - /* check if there's enough time in this frame to submit this TD */ - if (usb->actual_frame->frame_status != FRAME_IS_PREPARED && - (usb->actual_frame->frame_status & FRAME_END_TRANSMISSION || - (fw_transaction_time + usb->sw_transaction_time >= - 1000 - fhci_get_sof_timer_count(usb)))) { - fhci_dbg(usb->fhci, "not enough time in this frame\n"); - return -1; - } - - /* update frame object fields before transmitting */ - pkt = cq_get(&usb->ep0->empty_frame_Q); - if (!pkt) { - fhci_dbg(usb->fhci, "there is no empty frame\n"); - return -1; - } - td->pkt = pkt; - - pkt->info = 0; - if (data == NULL) { - data = cq_get(&usb->ep0->dummy_packets_Q); - BUG_ON(!data); - pkt->info = PKT_DUMMY_PACKET; - } - pkt->data = data; - pkt->len = len; - pkt->status = USB_TD_OK; - /* update TD status field before transmitting */ - td->status = USB_TD_INPROGRESS; - /* update actual frame time object with the actual transmission */ - usb->actual_frame->total_bytes += (len + PROTOCOL_OVERHEAD); - fhci_add_td_to_frame(usb->actual_frame, td); - - if (usb->port_status != FHCI_PORT_FULL && - usb->port_status != FHCI_PORT_LOW) { - pkt->status = USB_TD_TX_ER_TIMEOUT; - pkt->len = 0; - fhci_transaction_confirm(usb, pkt); - } else if (fhci_host_transaction(usb, pkt, td->type, ed->dev_addr, - ed->ep_addr, ed->mode, ed->speed, td->toggle)) { - /* remove TD from actual frame */ - list_del_init(&td->frame_lh); - td->status = USB_TD_OK; - if (pkt->info & PKT_DUMMY_PACKET) - cq_put(&usb->ep0->dummy_packets_Q, pkt->data); - recycle_frame(usb, pkt); - usb->actual_frame->total_bytes -= (len + PROTOCOL_OVERHEAD); - fhci_err(usb->fhci, "host transaction failed\n"); - return -1; - } - - return len; -} - -static void move_head_to_tail(struct list_head *list) -{ - struct list_head *node = list->next; - - if (!list_empty(list)) { - list_del(node); - list_add_tail(node, list); - } -} - -/* - * This function goes through the endpoint list and schedules the - * transactions within this list - */ -static int scan_ed_list(struct fhci_usb *usb, - struct list_head *list, enum fhci_tf_mode list_type) -{ - static const int frame_part[4] = { - [FHCI_TF_CTRL] = MAX_BYTES_PER_FRAME, - [FHCI_TF_ISO] = (MAX_BYTES_PER_FRAME * - MAX_PERIODIC_FRAME_USAGE) / 100, - [FHCI_TF_BULK] = MAX_BYTES_PER_FRAME, - [FHCI_TF_INTR] = (MAX_BYTES_PER_FRAME * - MAX_PERIODIC_FRAME_USAGE) / 100 - }; - struct ed *ed; - struct td *td; - int ans = 1; - u32 save_transaction_time = usb->sw_transaction_time; - - list_for_each_entry(ed, list, node) { - td = ed->td_head; - - if (!td || (td && td->status == USB_TD_INPROGRESS)) - continue; - - if (ed->state != FHCI_ED_OPER) { - if (ed->state == FHCI_ED_URB_DEL) { - td->status = USB_TD_OK; - fhci_move_td_from_ed_to_done_list(usb, ed); - ed->state = FHCI_ED_SKIP; - } - continue; - } - - /* - * if it isn't interrupt pipe or it is not iso pipe and the - * interval time passed - */ - if ((list_type == FHCI_TF_INTR || list_type == FHCI_TF_ISO) && - (((usb->actual_frame->frame_num - - td->start_frame) & 0x7ff) < td->interval)) - continue; - - if (add_packet(usb, ed, td) < 0) - continue; - - /* update time stamps in the TD */ - td->start_frame = usb->actual_frame->frame_num; - usb->sw_transaction_time += save_transaction_time; - - if (usb->actual_frame->total_bytes >= - usb->max_bytes_per_frame) { - usb->actual_frame->frame_status = - FRAME_DATA_END_TRANSMISSION; - fhci_push_dummy_bd(usb->ep0); - ans = 0; - break; - } - - if (usb->actual_frame->total_bytes >= frame_part[list_type]) - break; - } - - /* be fair to each ED(move list head around) */ - move_head_to_tail(list); - usb->sw_transaction_time = save_transaction_time; - - return ans; -} - -static u32 rotate_frames(struct fhci_usb *usb) -{ - struct fhci_hcd *fhci = usb->fhci; - - if (!list_empty(&usb->actual_frame->tds_list)) { - if ((((in_be16(&fhci->pram->frame_num) & 0x07ff) - - usb->actual_frame->frame_num) & 0x7ff) > 5) - fhci_flush_actual_frame(usb); - else - return -EINVAL; - } - - usb->actual_frame->frame_status = FRAME_IS_PREPARED; - usb->actual_frame->frame_num = in_be16(&fhci->pram->frame_num) & 0x7ff; - usb->actual_frame->total_bytes = 0; - - return 0; -} - -/* - * This function schedule the USB transaction and will process the - * endpoint in the following order: iso, interrupt, control and bulk. - */ -void fhci_schedule_transactions(struct fhci_usb *usb) -{ - int left = 1; - - if (usb->actual_frame->frame_status & FRAME_END_TRANSMISSION) - if (rotate_frames(usb) != 0) - return; - - if (usb->actual_frame->frame_status & FRAME_END_TRANSMISSION) - return; - - if (usb->actual_frame->total_bytes == 0) { - /* - * schedule the next available ISO transfer - *or next stage of the ISO transfer - */ - scan_ed_list(usb, &usb->hc_list->iso_list, FHCI_TF_ISO); - - /* - * schedule the next available interrupt transfer or - * the next stage of the interrupt transfer - */ - scan_ed_list(usb, &usb->hc_list->intr_list, FHCI_TF_INTR); - - /* - * schedule the next available control transfer - * or the next stage of the control transfer - */ - left = scan_ed_list(usb, &usb->hc_list->ctrl_list, - FHCI_TF_CTRL); - } - - /* - * schedule the next available bulk transfer or the next stage of the - * bulk transfer - */ - if (left > 0) - scan_ed_list(usb, &usb->hc_list->bulk_list, FHCI_TF_BULK); -} - -/* Handles SOF interrupt */ -static void sof_interrupt(struct fhci_hcd *fhci) -{ - struct fhci_usb *usb = fhci->usb_lld; - - if ((usb->port_status == FHCI_PORT_DISABLED) && - (usb->vroot_hub->port.wPortStatus & USB_PORT_STAT_CONNECTION) && - !(usb->vroot_hub->port.wPortChange & USB_PORT_STAT_C_CONNECTION)) { - if (usb->vroot_hub->port.wPortStatus & USB_PORT_STAT_LOW_SPEED) - usb->port_status = FHCI_PORT_LOW; - else - usb->port_status = FHCI_PORT_FULL; - /* Disable IDLE */ - usb->saved_msk &= ~USB_E_IDLE_MASK; - out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk); - } - - gtm_set_exact_timer16(fhci->timer, usb->max_frame_usage, false); - - fhci_host_transmit_actual_frame(usb); - usb->actual_frame->frame_status = FRAME_IS_TRANSMITTED; - - fhci_schedule_transactions(usb); -} - -/* Handles device disconnected interrupt on port */ -void fhci_device_disconnected_interrupt(struct fhci_hcd *fhci) -{ - struct fhci_usb *usb = fhci->usb_lld; - - fhci_dbg(fhci, "-> %s\n", __func__); - - fhci_usb_disable_interrupt(usb); - clrbits8(&usb->fhci->regs->usb_mod, USB_MODE_LSS); - usb->port_status = FHCI_PORT_DISABLED; - - fhci_stop_sof_timer(fhci); - - /* Enable IDLE since we want to know if something comes along */ - usb->saved_msk |= USB_E_IDLE_MASK; - out_be16(&usb->fhci->regs->usb_mask, usb->saved_msk); - - usb->vroot_hub->port.wPortStatus &= ~USB_PORT_STAT_CONNECTION; - usb->vroot_hub->port.wPortChange |= USB_PORT_STAT_C_CONNECTION; - usb->max_bytes_per_frame = 0; - fhci_usb_enable_interrupt(usb); - - fhci_dbg(fhci, "<- %s\n", __func__); -} - -/* detect a new device connected on the USB port */ -void fhci_device_connected_interrupt(struct fhci_hcd *fhci) -{ - - struct fhci_usb *usb = fhci->usb_lld; - int state; - int ret; - - fhci_dbg(fhci, "-> %s\n", __func__); - - fhci_usb_disable_interrupt(usb); - state = fhci_ioports_check_bus_state(fhci); - - /* low-speed device was connected to the USB port */ - if (state == 1) { - ret = qe_usb_clock_set(fhci->lowspeed_clk, USB_CLOCK >> 3); - if (ret) { - fhci_warn(fhci, "Low-Speed device is not supported, " - "try use BRGx\n"); - goto out; - } - - usb->port_status = FHCI_PORT_LOW; - setbits8(&usb->fhci->regs->usb_mod, USB_MODE_LSS); - usb->vroot_hub->port.wPortStatus |= - (USB_PORT_STAT_LOW_SPEED | - USB_PORT_STAT_CONNECTION); - usb->vroot_hub->port.wPortChange |= - USB_PORT_STAT_C_CONNECTION; - usb->max_bytes_per_frame = - (MAX_BYTES_PER_FRAME >> 3) - 7; - fhci_port_enable(usb); - } else if (state == 2) { - ret = qe_usb_clock_set(fhci->fullspeed_clk, USB_CLOCK); - if (ret) { - fhci_warn(fhci, "Full-Speed device is not supported, " - "try use CLKx\n"); - goto out; - } - - usb->port_status = FHCI_PORT_FULL; - clrbits8(&usb->fhci->regs->usb_mod, USB_MODE_LSS); - usb->vroot_hub->port.wPortStatus &= - ~USB_PORT_STAT_LOW_SPEED; - usb->vroot_hub->port.wPortStatus |= - USB_PORT_STAT_CONNECTION; - usb->vroot_hub->port.wPortChange |= - USB_PORT_STAT_C_CONNECTION; - usb->max_bytes_per_frame = (MAX_BYTES_PER_FRAME - 15); - fhci_port_enable(usb); - } -out: - fhci_usb_enable_interrupt(usb); - fhci_dbg(fhci, "<- %s\n", __func__); -} - -irqreturn_t fhci_frame_limit_timer_irq(int irq, void *_hcd) -{ - struct usb_hcd *hcd = _hcd; - struct fhci_hcd *fhci = hcd_to_fhci(hcd); - struct fhci_usb *usb = fhci->usb_lld; - - spin_lock(&fhci->lock); - - gtm_set_exact_timer16(fhci->timer, 1000, false); - - if (usb->actual_frame->frame_status == FRAME_IS_TRANSMITTED) { - usb->actual_frame->frame_status = FRAME_TIMER_END_TRANSMISSION; - fhci_push_dummy_bd(usb->ep0); - } - - fhci_schedule_transactions(usb); - - spin_unlock(&fhci->lock); - - return IRQ_HANDLED; -} - -/* Cancel transmission on the USB endpoint */ -static void abort_transmission(struct fhci_usb *usb) -{ - fhci_dbg(usb->fhci, "-> %s\n", __func__); - /* issue stop Tx command */ - qe_issue_cmd(QE_USB_STOP_TX, QE_CR_SUBBLOCK_USB, EP_ZERO, 0); - /* flush Tx FIFOs */ - out_8(&usb->fhci->regs->usb_comm, USB_CMD_FLUSH_FIFO | EP_ZERO); - udelay(1000); - /* reset Tx BDs */ - fhci_flush_bds(usb); - /* issue restart Tx command */ - qe_issue_cmd(QE_USB_RESTART_TX, QE_CR_SUBBLOCK_USB, EP_ZERO, 0); - fhci_dbg(usb->fhci, "<- %s\n", __func__); -} - -irqreturn_t fhci_irq(struct usb_hcd *hcd) -{ - struct fhci_hcd *fhci = hcd_to_fhci(hcd); - struct fhci_usb *usb; - u16 usb_er = 0; - unsigned long flags; - - spin_lock_irqsave(&fhci->lock, flags); - - usb = fhci->usb_lld; - - usb_er |= in_be16(&usb->fhci->regs->usb_event) & - in_be16(&usb->fhci->regs->usb_mask); - - /* clear event bits for next time */ - out_be16(&usb->fhci->regs->usb_event, usb_er); - - fhci_dbg_isr(fhci, usb_er); - - if (usb_er & USB_E_RESET_MASK) { - if ((usb->port_status == FHCI_PORT_FULL) || - (usb->port_status == FHCI_PORT_LOW)) { - fhci_device_disconnected_interrupt(fhci); - usb_er &= ~USB_E_IDLE_MASK; - } else if (usb->port_status == FHCI_PORT_WAITING) { - usb->port_status = FHCI_PORT_DISCONNECTING; - - /* Turn on IDLE since we want to disconnect */ - usb->saved_msk |= USB_E_IDLE_MASK; - out_be16(&usb->fhci->regs->usb_event, - usb->saved_msk); - } else if (usb->port_status == FHCI_PORT_DISABLED) { - if (fhci_ioports_check_bus_state(fhci) == 1) - fhci_device_connected_interrupt(fhci); - } - usb_er &= ~USB_E_RESET_MASK; - } - - if (usb_er & USB_E_MSF_MASK) { - abort_transmission(fhci->usb_lld); - usb_er &= ~USB_E_MSF_MASK; - } - - if (usb_er & (USB_E_SOF_MASK | USB_E_SFT_MASK)) { - sof_interrupt(fhci); - usb_er &= ~(USB_E_SOF_MASK | USB_E_SFT_MASK); - } - - if (usb_er & USB_E_TXB_MASK) { - fhci_tx_conf_interrupt(fhci->usb_lld); - usb_er &= ~USB_E_TXB_MASK; - } - - if (usb_er & USB_E_TXE1_MASK) { - fhci_tx_conf_interrupt(fhci->usb_lld); - usb_er &= ~USB_E_TXE1_MASK; - } - - if (usb_er & USB_E_IDLE_MASK) { - if (usb->port_status == FHCI_PORT_DISABLED) { - usb_er &= ~USB_E_RESET_MASK; - fhci_device_connected_interrupt(fhci); - } else if (usb->port_status == - FHCI_PORT_DISCONNECTING) { - /* XXX usb->port_status = FHCI_PORT_WAITING; */ - /* Disable IDLE */ - usb->saved_msk &= ~USB_E_IDLE_MASK; - out_be16(&usb->fhci->regs->usb_mask, - usb->saved_msk); - } else { - fhci_dbg_isr(fhci, -1); - } - - usb_er &= ~USB_E_IDLE_MASK; - } - - spin_unlock_irqrestore(&fhci->lock, flags); - - return IRQ_HANDLED; -} - - -/* - * Process normal completions(error or success) and clean the schedule. - * - * This is the main path for handing urbs back to drivers. The only other patth - * is process_del_list(),which unlinks URBs by scanning EDs,instead of scanning - * the (re-reversed) done list as this does. - */ -static void process_done_list(unsigned long data) -{ - struct urb *urb; - struct ed *ed; - struct td *td; - struct urb_priv *urb_priv; - struct fhci_hcd *fhci = (struct fhci_hcd *)data; - - disable_irq(fhci->timer->irq); - disable_irq(fhci_to_hcd(fhci)->irq); - spin_lock(&fhci->lock); - - td = fhci_remove_td_from_done_list(fhci->hc_list); - while (td != NULL) { - urb = td->urb; - urb_priv = urb->hcpriv; - ed = td->ed; - - /* update URB's length and status from TD */ - fhci_done_td(urb, td); - urb_priv->tds_cnt++; - - /* - * if all this urb's TDs are done, call complete() - * Interrupt transfers are the onley special case: - * they are reissued,until "deleted" by usb_unlink_urb - * (real work done in a SOF intr, by process_del_list) - */ - if (urb_priv->tds_cnt == urb_priv->num_of_tds) { - fhci_urb_complete_free(fhci, urb); - } else if (urb_priv->state == URB_DEL && - ed->state == FHCI_ED_SKIP) { - fhci_del_ed_list(fhci, ed); - ed->state = FHCI_ED_OPER; - } else if (ed->state == FHCI_ED_HALTED) { - urb_priv->state = URB_DEL; - ed->state = FHCI_ED_URB_DEL; - fhci_del_ed_list(fhci, ed); - ed->state = FHCI_ED_OPER; - } - - td = fhci_remove_td_from_done_list(fhci->hc_list); - } - - spin_unlock(&fhci->lock); - enable_irq(fhci->timer->irq); - enable_irq(fhci_to_hcd(fhci)->irq); -} - -DECLARE_TASKLET(fhci_tasklet, process_done_list, 0); - -/* transfer complted callback */ -u32 fhci_transfer_confirm_callback(struct fhci_hcd *fhci) -{ - if (!fhci->process_done_task->state) - tasklet_schedule(fhci->process_done_task); - return 0; -} - -/* - * adds urb to the endpoint descriptor list - * arguments: - * fhci data structure for the Low level host controller - * ep USB Host endpoint data structure - * urb USB request block data structure - */ -void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb) -{ - struct ed *ed = urb->ep->hcpriv; - struct urb_priv *urb_priv = urb->hcpriv; - u32 data_len = urb->transfer_buffer_length; - int urb_state = 0; - int toggle = 0; - struct td *td; - u8 *data; - u16 cnt = 0; - - if (ed == NULL) { - ed = fhci_get_empty_ed(fhci); - ed->dev_addr = usb_pipedevice(urb->pipe); - ed->ep_addr = usb_pipeendpoint(urb->pipe); - switch (usb_pipetype(urb->pipe)) { - case PIPE_CONTROL: - ed->mode = FHCI_TF_CTRL; - break; - case PIPE_BULK: - ed->mode = FHCI_TF_BULK; - break; - case PIPE_INTERRUPT: - ed->mode = FHCI_TF_INTR; - break; - case PIPE_ISOCHRONOUS: - ed->mode = FHCI_TF_ISO; - break; - default: - break; - } - ed->speed = (urb->dev->speed == USB_SPEED_LOW) ? - FHCI_LOW_SPEED : FHCI_FULL_SPEED; - ed->max_pkt_size = usb_maxpacket(urb->dev, - urb->pipe, usb_pipeout(urb->pipe)); - urb->ep->hcpriv = ed; - fhci_dbg(fhci, "new ep speed=%d max_pkt_size=%d\n", - ed->speed, ed->max_pkt_size); - } - - /* for ISO transfer calculate start frame index */ - if (ed->mode == FHCI_TF_ISO && urb->transfer_flags & URB_ISO_ASAP) - urb->start_frame = ed->td_head ? ed->last_iso + 1 : - get_frame_num(fhci); - - /* - * OHCI handles the DATA toggle itself,we just use the USB - * toggle bits - */ - if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe))) - toggle = USB_TD_TOGGLE_CARRY; - else { - toggle = USB_TD_TOGGLE_DATA0; - usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe), 1); - } - - urb_priv->tds_cnt = 0; - urb_priv->ed = ed; - if (data_len > 0) - data = urb->transfer_buffer; - else - data = NULL; - - switch (ed->mode) { - case FHCI_TF_BULK: - if (urb->transfer_flags & URB_ZERO_PACKET && - urb->transfer_buffer_length > 0 && - ((urb->transfer_buffer_length % - usb_maxpacket(urb->dev, urb->pipe, - usb_pipeout(urb->pipe))) == 0)) - urb_state = US_BULK0; - while (data_len > 4096) { - td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt, - usb_pipeout(urb->pipe) ? FHCI_TA_OUT : - FHCI_TA_IN, - cnt ? USB_TD_TOGGLE_CARRY : - toggle, - data, 4096, 0, 0, true); - data += 4096; - data_len -= 4096; - cnt++; - } - - td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt, - usb_pipeout(urb->pipe) ? FHCI_TA_OUT : FHCI_TA_IN, - cnt ? USB_TD_TOGGLE_CARRY : toggle, - data, data_len, 0, 0, true); - cnt++; - - if (urb->transfer_flags & URB_ZERO_PACKET && - cnt < urb_priv->num_of_tds) { - td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt, - usb_pipeout(urb->pipe) ? FHCI_TA_OUT : - FHCI_TA_IN, - USB_TD_TOGGLE_CARRY, NULL, 0, 0, 0, true); - cnt++; - } - break; - case FHCI_TF_INTR: - urb->start_frame = get_frame_num(fhci) + 1; - td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, - usb_pipeout(urb->pipe) ? FHCI_TA_OUT : FHCI_TA_IN, - USB_TD_TOGGLE_DATA0, data, data_len, - urb->interval, urb->start_frame, true); - break; - case FHCI_TF_CTRL: - ed->dev_addr = usb_pipedevice(urb->pipe); - ed->max_pkt_size = usb_maxpacket(urb->dev, urb->pipe, - usb_pipeout(urb->pipe)); - /* setup stage */ - td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, FHCI_TA_SETUP, - USB_TD_TOGGLE_DATA0, urb->setup_packet, 8, 0, 0, true); - - /* data stage */ - if (data_len > 0) { - td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, - usb_pipeout(urb->pipe) ? FHCI_TA_OUT : - FHCI_TA_IN, - USB_TD_TOGGLE_DATA1, data, data_len, 0, 0, - true); - } - - /* status stage */ - if (data_len > 0) - td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, - (usb_pipeout(urb->pipe) ? FHCI_TA_IN : - FHCI_TA_OUT), - USB_TD_TOGGLE_DATA1, data, 0, 0, 0, true); - else - td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, - FHCI_TA_IN, - USB_TD_TOGGLE_DATA1, data, 0, 0, 0, true); - - urb_state = US_CTRL_SETUP; - break; - case FHCI_TF_ISO: - for (cnt = 0; cnt < urb->number_of_packets; cnt++) { - u16 frame = urb->start_frame; - - /* - * FIXME scheduling should handle frame counter - * roll-around ... exotic case (and OHCI has - * a 2^16 iso range, vs other HCs max of 2^10) - */ - frame += cnt * urb->interval; - frame &= 0x07ff; - td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt, - usb_pipeout(urb->pipe) ? FHCI_TA_OUT : - FHCI_TA_IN, - USB_TD_TOGGLE_DATA0, - data + urb->iso_frame_desc[cnt].offset, - urb->iso_frame_desc[cnt].length, - urb->interval, frame, true); - } - break; - default: - break; - } - - /* - * set the state of URB - * control pipe:3 states -- setup,data,status - * interrupt and bulk pipe:1 state -- data - */ - urb->pipe &= ~0x1f; - urb->pipe |= urb_state & 0x1f; - - urb_priv->state = URB_INPROGRESS; - - if (!ed->td_head) { - ed->state = FHCI_ED_OPER; - switch (ed->mode) { - case FHCI_TF_CTRL: - list_add(&ed->node, &fhci->hc_list->ctrl_list); - break; - case FHCI_TF_BULK: - list_add(&ed->node, &fhci->hc_list->bulk_list); - break; - case FHCI_TF_INTR: - list_add(&ed->node, &fhci->hc_list->intr_list); - break; - case FHCI_TF_ISO: - list_add(&ed->node, &fhci->hc_list->iso_list); - break; - default: - break; - } - } - - fhci_add_tds_to_ed(ed, urb_priv->tds, urb_priv->num_of_tds); - fhci->active_urbs++; -} diff --git a/ANDROID_3.4.5/drivers/usb/host/fhci-tds.c b/ANDROID_3.4.5/drivers/usb/host/fhci-tds.c deleted file mode 100644 index 0ea577bf..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/fhci-tds.c +++ /dev/null @@ -1,626 +0,0 @@ -/* - * Freescale QUICC Engine USB Host Controller Driver - * - * Copyright (c) Freescale Semicondutor, Inc. 2006. - * Shlomi Gridish - * Jerry Huang - * Copyright (c) Logic Product Development, Inc. 2007 - * Peter Barada - * Copyright (c) MontaVista Software, Inc. 2008. - * Anton Vorontsov - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include "fhci.h" - -#define DUMMY_BD_BUFFER 0xdeadbeef -#define DUMMY2_BD_BUFFER 0xbaadf00d - -/* Transaction Descriptors bits */ -#define TD_R 0x8000 /* ready bit */ -#define TD_W 0x2000 /* wrap bit */ -#define TD_I 0x1000 /* interrupt on completion */ -#define TD_L 0x0800 /* last */ -#define TD_TC 0x0400 /* transmit CRC */ -#define TD_CNF 0x0200 /* CNF - Must be always 1 */ -#define TD_LSP 0x0100 /* Low-speed transaction */ -#define TD_PID 0x00c0 /* packet id */ -#define TD_RXER 0x0020 /* Rx error or not */ - -#define TD_NAK 0x0010 /* No ack. */ -#define TD_STAL 0x0008 /* Stall received */ -#define TD_TO 0x0004 /* time out */ -#define TD_UN 0x0002 /* underrun */ -#define TD_NO 0x0010 /* Rx Non Octet Aligned Packet */ -#define TD_AB 0x0008 /* Frame Aborted */ -#define TD_CR 0x0004 /* CRC Error */ -#define TD_OV 0x0002 /* Overrun */ -#define TD_BOV 0x0001 /* Buffer Overrun */ - -#define TD_ERRORS (TD_NAK | TD_STAL | TD_TO | TD_UN | \ - TD_NO | TD_AB | TD_CR | TD_OV | TD_BOV) - -#define TD_PID_DATA0 0x0080 /* Data 0 toggle */ -#define TD_PID_DATA1 0x00c0 /* Data 1 toggle */ -#define TD_PID_TOGGLE 0x00c0 /* Data 0/1 toggle mask */ - -#define TD_TOK_SETUP 0x0000 -#define TD_TOK_OUT 0x4000 -#define TD_TOK_IN 0x8000 -#define TD_ISO 0x1000 -#define TD_ENDP 0x0780 -#define TD_ADDR 0x007f - -#define TD_ENDP_SHIFT 7 - -struct usb_td { - __be16 status; - __be16 length; - __be32 buf_ptr; - __be16 extra; - __be16 reserved; -}; - -static struct usb_td __iomem *next_bd(struct usb_td __iomem *base, - struct usb_td __iomem *td, - u16 status) -{ - if (status & TD_W) - return base; - else - return ++td; -} - -void fhci_push_dummy_bd(struct endpoint *ep) -{ - if (ep->already_pushed_dummy_bd == false) { - u16 td_status = in_be16(&ep->empty_td->status); - - out_be32(&ep->empty_td->buf_ptr, DUMMY_BD_BUFFER); - /* get the next TD in the ring */ - ep->empty_td = next_bd(ep->td_base, ep->empty_td, td_status); - ep->already_pushed_dummy_bd = true; - } -} - -/* destroy an USB endpoint */ -void fhci_ep0_free(struct fhci_usb *usb) -{ - struct endpoint *ep; - int size; - - ep = usb->ep0; - if (ep) { - if (ep->td_base) - cpm_muram_free(cpm_muram_offset(ep->td_base)); - - if (kfifo_initialized(&ep->conf_frame_Q)) { - size = cq_howmany(&ep->conf_frame_Q); - for (; size; size--) { - struct packet *pkt = cq_get(&ep->conf_frame_Q); - - kfree(pkt); - } - cq_delete(&ep->conf_frame_Q); - } - - if (kfifo_initialized(&ep->empty_frame_Q)) { - size = cq_howmany(&ep->empty_frame_Q); - for (; size; size--) { - struct packet *pkt = cq_get(&ep->empty_frame_Q); - - kfree(pkt); - } - cq_delete(&ep->empty_frame_Q); - } - - if (kfifo_initialized(&ep->dummy_packets_Q)) { - size = cq_howmany(&ep->dummy_packets_Q); - for (; size; size--) { - u8 *buff = cq_get(&ep->dummy_packets_Q); - - kfree(buff); - } - cq_delete(&ep->dummy_packets_Q); - } - - kfree(ep); - usb->ep0 = NULL; - } -} - -/* - * create the endpoint structure - * - * arguments: - * usb A pointer to the data structure of the USB - * data_mem The data memory partition(BUS) - * ring_len TD ring length - */ -u32 fhci_create_ep(struct fhci_usb *usb, enum fhci_mem_alloc data_mem, - u32 ring_len) -{ - struct endpoint *ep; - struct usb_td __iomem *td; - unsigned long ep_offset; - char *err_for = "enpoint PRAM"; - int ep_mem_size; - u32 i; - - /* we need at least 3 TDs in the ring */ - if (!(ring_len > 2)) { - fhci_err(usb->fhci, "illegal TD ring length parameters\n"); - return -EINVAL; - } - - ep = kzalloc(sizeof(*ep), GFP_KERNEL); - if (!ep) - return -ENOMEM; - - ep_mem_size = ring_len * sizeof(*td) + sizeof(struct fhci_ep_pram); - ep_offset = cpm_muram_alloc(ep_mem_size, 32); - if (IS_ERR_VALUE(ep_offset)) - goto err; - ep->td_base = cpm_muram_addr(ep_offset); - - /* zero all queue pointers */ - if (cq_new(&ep->conf_frame_Q, ring_len + 2) || - cq_new(&ep->empty_frame_Q, ring_len + 2) || - cq_new(&ep->dummy_packets_Q, ring_len + 2)) { - err_for = "frame_queues"; - goto err; - } - - for (i = 0; i < (ring_len + 1); i++) { - struct packet *pkt; - u8 *buff; - - pkt = kmalloc(sizeof(*pkt), GFP_KERNEL); - if (!pkt) { - err_for = "frame"; - goto err; - } - - buff = kmalloc(1028 * sizeof(*buff), GFP_KERNEL); - if (!buff) { - kfree(pkt); - err_for = "buffer"; - goto err; - } - cq_put(&ep->empty_frame_Q, pkt); - cq_put(&ep->dummy_packets_Q, buff); - } - - /* we put the endpoint parameter RAM right behind the TD ring */ - ep->ep_pram_ptr = (void __iomem *)ep->td_base + sizeof(*td) * ring_len; - - ep->conf_td = ep->td_base; - ep->empty_td = ep->td_base; - - ep->already_pushed_dummy_bd = false; - - /* initialize tds */ - td = ep->td_base; - for (i = 0; i < ring_len; i++) { - out_be32(&td->buf_ptr, 0); - out_be16(&td->status, 0); - out_be16(&td->length, 0); - out_be16(&td->extra, 0); - td++; - } - td--; - out_be16(&td->status, TD_W); /* for last TD set Wrap bit */ - out_be16(&td->length, 0); - - /* endpoint structure has been created */ - usb->ep0 = ep; - - return 0; -err: - fhci_ep0_free(usb); - kfree(ep); - fhci_err(usb->fhci, "no memory for the %s\n", err_for); - return -ENOMEM; -} - -/* - * initialize the endpoint register according to the given parameters - * - * artuments: - * usb A pointer to the data strucutre of the USB - * ep A pointer to the endpoint structre - * data_mem The data memory partition(BUS) - */ -void fhci_init_ep_registers(struct fhci_usb *usb, struct endpoint *ep, - enum fhci_mem_alloc data_mem) -{ - u8 rt; - - /* set the endpoint registers according to the endpoint */ - out_be16(&usb->fhci->regs->usb_ep[0], - USB_TRANS_CTR | USB_EP_MF | USB_EP_RTE); - out_be16(&usb->fhci->pram->ep_ptr[0], - cpm_muram_offset(ep->ep_pram_ptr)); - - rt = (BUS_MODE_BO_BE | BUS_MODE_GBL); -#ifdef MULTI_DATA_BUS - if (data_mem == MEM_SECONDARY) - rt |= BUS_MODE_DTB; -#endif - out_8(&ep->ep_pram_ptr->rx_func_code, rt); - out_8(&ep->ep_pram_ptr->tx_func_code, rt); - out_be16(&ep->ep_pram_ptr->rx_buff_len, 1028); - out_be16(&ep->ep_pram_ptr->rx_base, 0); - out_be16(&ep->ep_pram_ptr->tx_base, cpm_muram_offset(ep->td_base)); - out_be16(&ep->ep_pram_ptr->rx_bd_ptr, 0); - out_be16(&ep->ep_pram_ptr->tx_bd_ptr, cpm_muram_offset(ep->td_base)); - out_be32(&ep->ep_pram_ptr->tx_state, 0); -} - -/* - * Collect the submitted frames and inform the application about them - * It is also preparing the TDs for new frames. If the Tx interrupts - * are disabled, the application should call that routine to get - * confirmation about the submitted frames. Otherwise, the routine is - * called from the interrupt service routine during the Tx interrupt. - * In that case the application is informed by calling the application - * specific 'fhci_transaction_confirm' routine - */ -static void fhci_td_transaction_confirm(struct fhci_usb *usb) -{ - struct endpoint *ep = usb->ep0; - struct packet *pkt; - struct usb_td __iomem *td; - u16 extra_data; - u16 td_status; - u16 td_length; - u32 buf; - - /* - * collect transmitted BDs from the chip. The routine clears all BDs - * with R bit = 0 and the pointer to data buffer is not NULL, that is - * BDs which point to the transmitted data buffer - */ - while (1) { - td = ep->conf_td; - td_status = in_be16(&td->status); - td_length = in_be16(&td->length); - buf = in_be32(&td->buf_ptr); - extra_data = in_be16(&td->extra); - - /* check if the TD is empty */ - if (!(!(td_status & TD_R) && ((td_status & ~TD_W) || buf))) - break; - /* check if it is a dummy buffer */ - else if ((buf == DUMMY_BD_BUFFER) && !(td_status & ~TD_W)) - break; - - /* mark TD as empty */ - clrbits16(&td->status, ~TD_W); - out_be16(&td->length, 0); - out_be32(&td->buf_ptr, 0); - out_be16(&td->extra, 0); - /* advance the TD pointer */ - ep->conf_td = next_bd(ep->td_base, ep->conf_td, td_status); - - /* check if it is a dummy buffer(type2) */ - if ((buf == DUMMY2_BD_BUFFER) && !(td_status & ~TD_W)) - continue; - - pkt = cq_get(&ep->conf_frame_Q); - if (!pkt) - fhci_err(usb->fhci, "no frame to confirm\n"); - - if (td_status & TD_ERRORS) { - if (td_status & TD_RXER) { - if (td_status & TD_CR) - pkt->status = USB_TD_RX_ER_CRC; - else if (td_status & TD_AB) - pkt->status = USB_TD_RX_ER_BITSTUFF; - else if (td_status & TD_OV) - pkt->status = USB_TD_RX_ER_OVERUN; - else if (td_status & TD_BOV) - pkt->status = USB_TD_RX_DATA_OVERUN; - else if (td_status & TD_NO) - pkt->status = USB_TD_RX_ER_NONOCT; - else - fhci_err(usb->fhci, "illegal error " - "occurred\n"); - } else if (td_status & TD_NAK) - pkt->status = USB_TD_TX_ER_NAK; - else if (td_status & TD_TO) - pkt->status = USB_TD_TX_ER_TIMEOUT; - else if (td_status & TD_UN) - pkt->status = USB_TD_TX_ER_UNDERUN; - else if (td_status & TD_STAL) - pkt->status = USB_TD_TX_ER_STALL; - else - fhci_err(usb->fhci, "illegal error occurred\n"); - } else if ((extra_data & TD_TOK_IN) && - pkt->len > td_length - CRC_SIZE) { - pkt->status = USB_TD_RX_DATA_UNDERUN; - } - - if (extra_data & TD_TOK_IN) - pkt->len = td_length - CRC_SIZE; - else if (pkt->info & PKT_ZLP) - pkt->len = 0; - else - pkt->len = td_length; - - fhci_transaction_confirm(usb, pkt); - } -} - -/* - * Submitting a data frame to a specified endpoint of a USB device - * The frame is put in the driver's transmit queue for this endpoint - * - * Arguments: - * usb A pointer to the USB structure - * pkt A pointer to the user frame structure - * trans_type Transaction tyep - IN,OUT or SETUP - * dest_addr Device address - 0~127 - * dest_ep Endpoint number of the device - 0~16 - * trans_mode Pipe type - ISO,Interrupt,bulk or control - * dest_speed USB speed - Low speed or FULL speed - * data_toggle Data sequence toggle - 0 or 1 - */ -u32 fhci_host_transaction(struct fhci_usb *usb, - struct packet *pkt, - enum fhci_ta_type trans_type, - u8 dest_addr, - u8 dest_ep, - enum fhci_tf_mode trans_mode, - enum fhci_speed dest_speed, u8 data_toggle) -{ - struct endpoint *ep = usb->ep0; - struct usb_td __iomem *td; - u16 extra_data; - u16 td_status; - - fhci_usb_disable_interrupt(usb); - /* start from the next BD that should be filled */ - td = ep->empty_td; - td_status = in_be16(&td->status); - - if (td_status & TD_R && in_be16(&td->length)) { - /* if the TD is not free */ - fhci_usb_enable_interrupt(usb); - return -1; - } - - /* get the next TD in the ring */ - ep->empty_td = next_bd(ep->td_base, ep->empty_td, td_status); - fhci_usb_enable_interrupt(usb); - pkt->priv_data = td; - out_be32(&td->buf_ptr, virt_to_phys(pkt->data)); - /* sets up transaction parameters - addr,endp,dir,and type */ - extra_data = (dest_ep << TD_ENDP_SHIFT) | dest_addr; - switch (trans_type) { - case FHCI_TA_IN: - extra_data |= TD_TOK_IN; - break; - case FHCI_TA_OUT: - extra_data |= TD_TOK_OUT; - break; - case FHCI_TA_SETUP: - extra_data |= TD_TOK_SETUP; - break; - } - if (trans_mode == FHCI_TF_ISO) - extra_data |= TD_ISO; - out_be16(&td->extra, extra_data); - - /* sets up the buffer descriptor */ - td_status = ((td_status & TD_W) | TD_R | TD_L | TD_I | TD_CNF); - if (!(pkt->info & PKT_NO_CRC)) - td_status |= TD_TC; - - switch (trans_type) { - case FHCI_TA_IN: - if (data_toggle) - pkt->info |= PKT_PID_DATA1; - else - pkt->info |= PKT_PID_DATA0; - break; - default: - if (data_toggle) { - td_status |= TD_PID_DATA1; - pkt->info |= PKT_PID_DATA1; - } else { - td_status |= TD_PID_DATA0; - pkt->info |= PKT_PID_DATA0; - } - break; - } - - if ((dest_speed == FHCI_LOW_SPEED) && - (usb->port_status == FHCI_PORT_FULL)) - td_status |= TD_LSP; - - out_be16(&td->status, td_status); - - /* set up buffer length */ - if (trans_type == FHCI_TA_IN) - out_be16(&td->length, pkt->len + CRC_SIZE); - else - out_be16(&td->length, pkt->len); - - /* put the frame to the confirmation queue */ - cq_put(&ep->conf_frame_Q, pkt); - - if (cq_howmany(&ep->conf_frame_Q) == 1) - out_8(&usb->fhci->regs->usb_comm, USB_CMD_STR_FIFO); - - return 0; -} - -/* Reset the Tx BD ring */ -void fhci_flush_bds(struct fhci_usb *usb) -{ - u16 extra_data; - u16 td_status; - u32 buf; - struct usb_td __iomem *td; - struct endpoint *ep = usb->ep0; - - td = ep->td_base; - while (1) { - td_status = in_be16(&td->status); - buf = in_be32(&td->buf_ptr); - extra_data = in_be16(&td->extra); - - /* if the TD is not empty - we'll confirm it as Timeout */ - if (td_status & TD_R) - out_be16(&td->status, (td_status & ~TD_R) | TD_TO); - /* if this TD is dummy - let's skip this TD */ - else if (in_be32(&td->buf_ptr) == DUMMY_BD_BUFFER) - out_be32(&td->buf_ptr, DUMMY2_BD_BUFFER); - /* if this is the last TD - break */ - if (td_status & TD_W) - break; - - td++; - } - - fhci_td_transaction_confirm(usb); - - td = ep->td_base; - do { - out_be16(&td->status, 0); - out_be16(&td->length, 0); - out_be32(&td->buf_ptr, 0); - out_be16(&td->extra, 0); - td++; - } while (!(in_be16(&td->status) & TD_W)); - out_be16(&td->status, TD_W); /* for last TD set Wrap bit */ - out_be16(&td->length, 0); - out_be32(&td->buf_ptr, 0); - out_be16(&td->extra, 0); - - out_be16(&ep->ep_pram_ptr->tx_bd_ptr, - in_be16(&ep->ep_pram_ptr->tx_base)); - out_be32(&ep->ep_pram_ptr->tx_state, 0); - out_be16(&ep->ep_pram_ptr->tx_cnt, 0); - ep->empty_td = ep->td_base; - ep->conf_td = ep->td_base; -} - -/* - * Flush all transmitted packets from TDs in the actual frame. - * This routine is called when something wrong with the controller and - * we want to get rid of the actual frame and start again next frame - */ -void fhci_flush_actual_frame(struct fhci_usb *usb) -{ - u8 mode; - u16 tb_ptr; - u16 extra_data; - u16 td_status; - u32 buf_ptr; - struct usb_td __iomem *td; - struct endpoint *ep = usb->ep0; - - /* disable the USB controller */ - mode = in_8(&usb->fhci->regs->usb_mod); - out_8(&usb->fhci->regs->usb_mod, mode & ~USB_MODE_EN); - - tb_ptr = in_be16(&ep->ep_pram_ptr->tx_bd_ptr); - td = cpm_muram_addr(tb_ptr); - td_status = in_be16(&td->status); - buf_ptr = in_be32(&td->buf_ptr); - extra_data = in_be16(&td->extra); - do { - if (td_status & TD_R) { - out_be16(&td->status, (td_status & ~TD_R) | TD_TO); - } else { - out_be32(&td->buf_ptr, 0); - ep->already_pushed_dummy_bd = false; - break; - } - - /* advance the TD pointer */ - td = next_bd(ep->td_base, td, td_status); - td_status = in_be16(&td->status); - buf_ptr = in_be32(&td->buf_ptr); - extra_data = in_be16(&td->extra); - } while ((td_status & TD_R) || buf_ptr); - - fhci_td_transaction_confirm(usb); - - out_be16(&ep->ep_pram_ptr->tx_bd_ptr, - in_be16(&ep->ep_pram_ptr->tx_base)); - out_be32(&ep->ep_pram_ptr->tx_state, 0); - out_be16(&ep->ep_pram_ptr->tx_cnt, 0); - ep->empty_td = ep->td_base; - ep->conf_td = ep->td_base; - - usb->actual_frame->frame_status = FRAME_TIMER_END_TRANSMISSION; - - /* reset the event register */ - out_be16(&usb->fhci->regs->usb_event, 0xffff); - /* enable the USB controller */ - out_8(&usb->fhci->regs->usb_mod, mode | USB_MODE_EN); -} - -/* handles Tx confirm and Tx error interrupt */ -void fhci_tx_conf_interrupt(struct fhci_usb *usb) -{ - fhci_td_transaction_confirm(usb); - - /* - * Schedule another transaction to this frame only if we have - * already confirmed all transaction in the frame. - */ - if (((fhci_get_sof_timer_count(usb) < usb->max_frame_usage) || - (usb->actual_frame->frame_status & FRAME_END_TRANSMISSION)) && - (list_empty(&usb->actual_frame->tds_list))) - fhci_schedule_transactions(usb); -} - -void fhci_host_transmit_actual_frame(struct fhci_usb *usb) -{ - u16 tb_ptr; - u16 td_status; - struct usb_td __iomem *td; - struct endpoint *ep = usb->ep0; - - tb_ptr = in_be16(&ep->ep_pram_ptr->tx_bd_ptr); - td = cpm_muram_addr(tb_ptr); - - if (in_be32(&td->buf_ptr) == DUMMY_BD_BUFFER) { - struct usb_td __iomem *old_td = td; - - ep->already_pushed_dummy_bd = false; - td_status = in_be16(&td->status); - /* gets the next TD in the ring */ - td = next_bd(ep->td_base, td, td_status); - tb_ptr = cpm_muram_offset(td); - out_be16(&ep->ep_pram_ptr->tx_bd_ptr, tb_ptr); - - /* start transmit only if we have something in the TDs */ - if (in_be16(&td->status) & TD_R) - out_8(&usb->fhci->regs->usb_comm, USB_CMD_STR_FIFO); - - if (in_be32(&ep->conf_td->buf_ptr) == DUMMY_BD_BUFFER) { - out_be32(&old_td->buf_ptr, 0); - ep->conf_td = next_bd(ep->td_base, ep->conf_td, - td_status); - } else { - out_be32(&old_td->buf_ptr, DUMMY2_BD_BUFFER); - } - } -} diff --git a/ANDROID_3.4.5/drivers/usb/host/fhci.h b/ANDROID_3.4.5/drivers/usb/host/fhci.h deleted file mode 100644 index dc6939a4..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/fhci.h +++ /dev/null @@ -1,612 +0,0 @@ -/* - * Freescale QUICC Engine USB Host Controller Driver - * - * Copyright (c) Freescale Semicondutor, Inc. 2006. - * Shlomi Gridish - * Jerry Huang - * Copyright (c) Logic Product Development, Inc. 2007 - * Peter Barada - * Copyright (c) MontaVista Software, Inc. 2008. - * Anton Vorontsov - * - * 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. - */ - -#ifndef __FHCI_H -#define __FHCI_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define USB_CLOCK 48000000 - -#define FHCI_PRAM_SIZE 0x100 - -#define MAX_EDS 32 -#define MAX_TDS 32 - - -/* CRC16 field size */ -#define CRC_SIZE 2 - -/* USB protocol overhead for each frame transmitted from the host */ -#define PROTOCOL_OVERHEAD 7 - -/* Packet structure, info field */ -#define PKT_PID_DATA0 0x80000000 /* PID - Data toggle zero */ -#define PKT_PID_DATA1 0x40000000 /* PID - Data toggle one */ -#define PKT_PID_SETUP 0x20000000 /* PID - Setup bit */ -#define PKT_SETUP_STATUS 0x10000000 /* Setup status bit */ -#define PKT_SETADDR_STATUS 0x08000000 /* Set address status bit */ -#define PKT_SET_HOST_LAST 0x04000000 /* Last data packet */ -#define PKT_HOST_DATA 0x02000000 /* Data packet */ -#define PKT_FIRST_IN_FRAME 0x01000000 /* First packet in the frame */ -#define PKT_TOKEN_FRAME 0x00800000 /* Token packet */ -#define PKT_ZLP 0x00400000 /* Zero length packet */ -#define PKT_IN_TOKEN_FRAME 0x00200000 /* IN token packet */ -#define PKT_OUT_TOKEN_FRAME 0x00100000 /* OUT token packet */ -#define PKT_SETUP_TOKEN_FRAME 0x00080000 /* SETUP token packet */ -#define PKT_STALL_FRAME 0x00040000 /* STALL packet */ -#define PKT_NACK_FRAME 0x00020000 /* NACK packet */ -#define PKT_NO_PID 0x00010000 /* No PID */ -#define PKT_NO_CRC 0x00008000 /* don't append CRC */ -#define PKT_HOST_COMMAND 0x00004000 /* Host command packet */ -#define PKT_DUMMY_PACKET 0x00002000 /* Dummy packet, used for mmm */ -#define PKT_LOW_SPEED_PACKET 0x00001000 /* Low-Speed packet */ - -#define TRANS_OK (0) -#define TRANS_INPROGRESS (-1) -#define TRANS_DISCARD (-2) -#define TRANS_FAIL (-3) - -#define PS_INT 0 -#define PS_DISCONNECTED 1 -#define PS_CONNECTED 2 -#define PS_READY 3 -#define PS_MISSING 4 - -/* Transfer Descriptor status field */ -#define USB_TD_OK 0x00000000 /* TD transmited or received ok */ -#define USB_TD_INPROGRESS 0x80000000 /* TD is being transmitted */ -#define USB_TD_RX_ER_NONOCT 0x40000000 /* Tx Non Octet Aligned Packet */ -#define USB_TD_RX_ER_BITSTUFF 0x20000000 /* Frame Aborted-Received pkt */ -#define USB_TD_RX_ER_CRC 0x10000000 /* CRC error */ -#define USB_TD_RX_ER_OVERUN 0x08000000 /* Over - run occurred */ -#define USB_TD_RX_ER_PID 0x04000000 /* wrong PID received */ -#define USB_TD_RX_DATA_UNDERUN 0x02000000 /* shorter than expected */ -#define USB_TD_RX_DATA_OVERUN 0x01000000 /* longer than expected */ -#define USB_TD_TX_ER_NAK 0x00800000 /* NAK handshake */ -#define USB_TD_TX_ER_STALL 0x00400000 /* STALL handshake */ -#define USB_TD_TX_ER_TIMEOUT 0x00200000 /* transmit time out */ -#define USB_TD_TX_ER_UNDERUN 0x00100000 /* transmit underrun */ - -#define USB_TD_ERROR (USB_TD_RX_ER_NONOCT | USB_TD_RX_ER_BITSTUFF | \ - USB_TD_RX_ER_CRC | USB_TD_RX_ER_OVERUN | USB_TD_RX_ER_PID | \ - USB_TD_RX_DATA_UNDERUN | USB_TD_RX_DATA_OVERUN | \ - USB_TD_TX_ER_NAK | USB_TD_TX_ER_STALL | \ - USB_TD_TX_ER_TIMEOUT | USB_TD_TX_ER_UNDERUN) - -/* Transfer Descriptor toggle field */ -#define USB_TD_TOGGLE_DATA0 0 -#define USB_TD_TOGGLE_DATA1 1 -#define USB_TD_TOGGLE_CARRY 2 - -/* #define MULTI_DATA_BUS */ - -/* Bus mode register RBMR/TBMR */ -#define BUS_MODE_GBL 0x20 /* Global snooping */ -#define BUS_MODE_BO 0x18 /* Byte ordering */ -#define BUS_MODE_BO_BE 0x10 /* Byte ordering - Big-endian */ -#define BUS_MODE_DTB 0x02 /* Data bus */ - -/* FHCI QE USB Register Description */ - -/* USB Mode Register bit define */ -#define USB_MODE_EN 0x01 -#define USB_MODE_HOST 0x02 -#define USB_MODE_TEST 0x04 -#define USB_MODE_SFTE 0x08 -#define USB_MODE_RESUME 0x40 -#define USB_MODE_LSS 0x80 - -/* USB Slave Address Register Mask */ -#define USB_SLVADDR_MASK 0x7F - -/* USB Endpoint register define */ -#define USB_EPNUM_MASK 0xF000 -#define USB_EPNUM_SHIFT 12 - -#define USB_TRANS_MODE_SHIFT 8 -#define USB_TRANS_CTR 0x0000 -#define USB_TRANS_INT 0x0100 -#define USB_TRANS_BULK 0x0200 -#define USB_TRANS_ISO 0x0300 - -#define USB_EP_MF 0x0020 -#define USB_EP_RTE 0x0010 - -#define USB_THS_SHIFT 2 -#define USB_THS_MASK 0x000c -#define USB_THS_NORMAL 0x0 -#define USB_THS_IGNORE_IN 0x0004 -#define USB_THS_NACK 0x0008 -#define USB_THS_STALL 0x000c - -#define USB_RHS_SHIFT 0 -#define USB_RHS_MASK 0x0003 -#define USB_RHS_NORMAL 0x0 -#define USB_RHS_IGNORE_OUT 0x0001 -#define USB_RHS_NACK 0x0002 -#define USB_RHS_STALL 0x0003 - -#define USB_RTHS_MASK 0x000f - -/* USB Command Register define */ -#define USB_CMD_STR_FIFO 0x80 -#define USB_CMD_FLUSH_FIFO 0x40 -#define USB_CMD_ISFT 0x20 -#define USB_CMD_DSFT 0x10 -#define USB_CMD_EP_MASK 0x03 - -/* USB Event and Mask Register define */ -#define USB_E_MSF_MASK 0x0800 -#define USB_E_SFT_MASK 0x0400 -#define USB_E_RESET_MASK 0x0200 -#define USB_E_IDLE_MASK 0x0100 -#define USB_E_TXE4_MASK 0x0080 -#define USB_E_TXE3_MASK 0x0040 -#define USB_E_TXE2_MASK 0x0020 -#define USB_E_TXE1_MASK 0x0010 -#define USB_E_SOF_MASK 0x0008 -#define USB_E_BSY_MASK 0x0004 -#define USB_E_TXB_MASK 0x0002 -#define USB_E_RXB_MASK 0x0001 - -/* Freescale USB Host controller registers */ -struct fhci_regs { - u8 usb_mod; /* mode register */ - u8 usb_addr; /* address register */ - u8 usb_comm; /* command register */ - u8 reserved1[1]; - __be16 usb_ep[4]; /* endpoint register */ - u8 reserved2[4]; - __be16 usb_event; /* event register */ - u8 reserved3[2]; - __be16 usb_mask; /* mask register */ - u8 reserved4[1]; - u8 usb_status; /* status register */ - __be16 usb_sof_tmr; /* Start Of Frame timer */ - u8 reserved5[2]; - __be16 usb_frame_num; /* frame number register */ - u8 reserved6[1]; -}; - -/* Freescale USB HOST */ -struct fhci_pram { - __be16 ep_ptr[4]; /* Endpoint porter reg */ - __be32 rx_state; /* Rx internal state */ - __be32 rx_ptr; /* Rx internal data pointer */ - __be16 frame_num; /* Frame number */ - __be16 rx_cnt; /* Rx byte count */ - __be32 rx_temp; /* Rx temp */ - __be32 rx_data_temp; /* Rx data temp */ - __be16 rx_u_ptr; /* Rx microcode return address temp */ - u8 reserved1[2]; /* reserved area */ - __be32 sof_tbl; /* SOF lookup table pointer */ - u8 sof_u_crc_temp; /* SOF micorcode CRC5 temp reg */ - u8 reserved2[0xdb]; -}; - -/* Freescale USB Endpoint*/ -struct fhci_ep_pram { - __be16 rx_base; /* Rx BD base address */ - __be16 tx_base; /* Tx BD base address */ - u8 rx_func_code; /* Rx function code */ - u8 tx_func_code; /* Tx function code */ - __be16 rx_buff_len; /* Rx buffer length */ - __be16 rx_bd_ptr; /* Rx BD pointer */ - __be16 tx_bd_ptr; /* Tx BD pointer */ - __be32 tx_state; /* Tx internal state */ - __be32 tx_ptr; /* Tx internal data pointer */ - __be16 tx_crc; /* temp transmit CRC */ - __be16 tx_cnt; /* Tx byte count */ - __be32 tx_temp; /* Tx temp */ - __be16 tx_u_ptr; /* Tx microcode return address temp */ - __be16 reserved; -}; - -struct fhci_controller_list { - struct list_head ctrl_list; /* control endpoints */ - struct list_head bulk_list; /* bulk endpoints */ - struct list_head iso_list; /* isochronous endpoints */ - struct list_head intr_list; /* interruput endpoints */ - struct list_head done_list; /* done transfers */ -}; - -struct virtual_root_hub { - int dev_num; /* USB address of the root hub */ - u32 feature; /* indicates what feature has been set */ - struct usb_hub_status hub; - struct usb_port_status port; -}; - -enum fhci_gpios { - GPIO_USBOE = 0, - GPIO_USBTP, - GPIO_USBTN, - GPIO_USBRP, - GPIO_USBRN, - /* these are optional */ - GPIO_SPEED, - GPIO_POWER, - NUM_GPIOS, -}; - -enum fhci_pins { - PIN_USBOE = 0, - PIN_USBTP, - PIN_USBTN, - NUM_PINS, -}; - -struct fhci_hcd { - enum qe_clock fullspeed_clk; - enum qe_clock lowspeed_clk; - struct qe_pin *pins[NUM_PINS]; - int gpios[NUM_GPIOS]; - bool alow_gpios[NUM_GPIOS]; - - struct fhci_regs __iomem *regs; /* I/O memory used to communicate */ - struct fhci_pram __iomem *pram; /* Parameter RAM */ - struct gtm_timer *timer; - - spinlock_t lock; - struct fhci_usb *usb_lld; /* Low-level driver */ - struct virtual_root_hub *vroot_hub; /* the virtual root hub */ - int active_urbs; - struct fhci_controller_list *hc_list; - struct tasklet_struct *process_done_task; /* tasklet for done list */ - - struct list_head empty_eds; - struct list_head empty_tds; - -#ifdef CONFIG_FHCI_DEBUG - int usb_irq_stat[13]; - struct dentry *dfs_root; - struct dentry *dfs_regs; - struct dentry *dfs_irq_stat; -#endif -}; - -#define USB_FRAME_USAGE 90 -#define FRAME_TIME_USAGE (USB_FRAME_USAGE*10) /* frame time usage */ -#define SW_FIX_TIME_BETWEEN_TRANSACTION 150 /* SW */ -#define MAX_BYTES_PER_FRAME (USB_FRAME_USAGE*15) -#define MAX_PERIODIC_FRAME_USAGE 90 - -/* transaction type */ -enum fhci_ta_type { - FHCI_TA_IN = 0, /* input transaction */ - FHCI_TA_OUT, /* output transaction */ - FHCI_TA_SETUP, /* setup transaction */ -}; - -/* transfer mode */ -enum fhci_tf_mode { - FHCI_TF_CTRL = 0, - FHCI_TF_ISO, - FHCI_TF_BULK, - FHCI_TF_INTR, -}; - -enum fhci_speed { - FHCI_FULL_SPEED, - FHCI_LOW_SPEED, -}; - -/* endpoint state */ -enum fhci_ed_state { - FHCI_ED_NEW = 0, /* pipe is new */ - FHCI_ED_OPER, /* pipe is operating */ - FHCI_ED_URB_DEL, /* pipe is in hold because urb is being deleted */ - FHCI_ED_SKIP, /* skip this pipe */ - FHCI_ED_HALTED, /* pipe is halted */ -}; - -enum fhci_port_status { - FHCI_PORT_POWER_OFF = 0, - FHCI_PORT_DISABLED, - FHCI_PORT_DISCONNECTING, - FHCI_PORT_WAITING, /* waiting for connection */ - FHCI_PORT_FULL, /* full speed connected */ - FHCI_PORT_LOW, /* low speed connected */ -}; - -enum fhci_mem_alloc { - MEM_CACHABLE_SYS = 0x00000001, /* primary DDR,cachable */ - MEM_NOCACHE_SYS = 0x00000004, /* primary DDR,non-cachable */ - MEM_SECONDARY = 0x00000002, /* either secondary DDR or SDRAM */ - MEM_PRAM = 0x00000008, /* multi-user RAM identifier */ -}; - -/* USB default parameters*/ -#define DEFAULT_RING_LEN 8 -#define DEFAULT_DATA_MEM MEM_CACHABLE_SYS - -struct ed { - u8 dev_addr; /* device address */ - u8 ep_addr; /* endpoint address */ - enum fhci_tf_mode mode; /* USB transfer mode */ - enum fhci_speed speed; - unsigned int max_pkt_size; - enum fhci_ed_state state; - struct list_head td_list; /* a list of all queued TD to this pipe */ - struct list_head node; - - /* read only parameters, should be cleared upon initialization */ - u8 toggle_carry; /* toggle carry from the last TD submitted */ - u32 last_iso; /* time stamp of last queued ISO transfer */ - struct td *td_head; /* a pointer to the current TD handled */ -}; - -struct td { - void *data; /* a pointer to the data buffer */ - unsigned int len; /* length of the data to be submitted */ - unsigned int actual_len; /* actual bytes transferred on this td */ - enum fhci_ta_type type; /* transaction type */ - u8 toggle; /* toggle for next trans. within this TD */ - u16 iso_index; /* ISO transaction index */ - u16 start_frame; /* start frame time stamp */ - u16 interval; /* interval between trans. (for ISO/Intr) */ - u32 status; /* status of the TD */ - struct ed *ed; /* a handle to the corresponding ED */ - struct urb *urb; /* a handle to the corresponding URB */ - bool ioc; /* Inform On Completion */ - struct list_head node; - - /* read only parameters should be cleared upon initialization */ - struct packet *pkt; - int nak_cnt; - int error_cnt; - struct list_head frame_lh; -}; - -struct packet { - u8 *data; /* packet data */ - u32 len; /* packet length */ - u32 status; /* status of the packet - equivalent to the status - * field for the corresponding structure td */ - u32 info; /* packet information */ - void __iomem *priv_data; /* private data of the driver (TDs or BDs) */ -}; - -/* struct for each URB */ -#define URB_INPROGRESS 0 -#define URB_DEL 1 - -/* URB states (state field) */ -#define US_BULK 0 -#define US_BULK0 1 - -/* three setup states */ -#define US_CTRL_SETUP 2 -#define US_CTRL_DATA 1 -#define US_CTRL_ACK 0 - -#define EP_ZERO 0 - -struct urb_priv { - int num_of_tds; - int tds_cnt; - int state; - - struct td **tds; - struct ed *ed; - struct timer_list time_out; -}; - -struct endpoint { - /* Pointer to ep parameter RAM */ - struct fhci_ep_pram __iomem *ep_pram_ptr; - - /* Host transactions */ - struct usb_td __iomem *td_base; /* first TD in the ring */ - struct usb_td __iomem *conf_td; /* next TD for confirm after transac */ - struct usb_td __iomem *empty_td;/* next TD for new transaction req. */ - struct kfifo empty_frame_Q; /* Empty frames list to use */ - struct kfifo conf_frame_Q; /* frames passed to TDs,waiting for tx */ - struct kfifo dummy_packets_Q;/* dummy packets for the CRC overun */ - - bool already_pushed_dummy_bd; -}; - -/* struct for each 1mSec frame time */ -#define FRAME_IS_TRANSMITTED 0x00 -#define FRAME_TIMER_END_TRANSMISSION 0x01 -#define FRAME_DATA_END_TRANSMISSION 0x02 -#define FRAME_END_TRANSMISSION 0x03 -#define FRAME_IS_PREPARED 0x04 - -struct fhci_time_frame { - u16 frame_num; /* frame number */ - u16 total_bytes; /* total bytes submitted within this frame */ - u8 frame_status; /* flag that indicates to stop fill this frame */ - struct list_head tds_list; /* all tds of this frame */ -}; - -/* internal driver structure*/ -struct fhci_usb { - u16 saved_msk; /* saving of the USB mask register */ - struct endpoint *ep0; /* pointer for endpoint0 structure */ - int intr_nesting_cnt; /* interrupt nesting counter */ - u16 max_frame_usage; /* max frame time usage,in micro-sec */ - u16 max_bytes_per_frame; /* max byte can be tx in one time frame */ - u32 sw_transaction_time; /* sw complete trans time,in micro-sec */ - struct fhci_time_frame *actual_frame; - struct fhci_controller_list *hc_list; /* main structure for hc */ - struct virtual_root_hub *vroot_hub; - enum fhci_port_status port_status; /* v_rh port status */ - - u32 (*transfer_confirm)(struct fhci_hcd *fhci); - - struct fhci_hcd *fhci; -}; - -/* - * Various helpers and prototypes below. - */ - -static inline u16 get_frame_num(struct fhci_hcd *fhci) -{ - return in_be16(&fhci->pram->frame_num) & 0x07ff; -} - -#define fhci_dbg(fhci, fmt, args...) \ - dev_dbg(fhci_to_hcd(fhci)->self.controller, fmt, ##args) -#define fhci_vdbg(fhci, fmt, args...) \ - dev_vdbg(fhci_to_hcd(fhci)->self.controller, fmt, ##args) -#define fhci_err(fhci, fmt, args...) \ - dev_err(fhci_to_hcd(fhci)->self.controller, fmt, ##args) -#define fhci_info(fhci, fmt, args...) \ - dev_info(fhci_to_hcd(fhci)->self.controller, fmt, ##args) -#define fhci_warn(fhci, fmt, args...) \ - dev_warn(fhci_to_hcd(fhci)->self.controller, fmt, ##args) - -static inline struct fhci_hcd *hcd_to_fhci(struct usb_hcd *hcd) -{ - return (struct fhci_hcd *)hcd->hcd_priv; -} - -static inline struct usb_hcd *fhci_to_hcd(struct fhci_hcd *fhci) -{ - return container_of((void *)fhci, struct usb_hcd, hcd_priv); -} - -/* fifo of pointers */ -static inline int cq_new(struct kfifo *fifo, int size) -{ - return kfifo_alloc(fifo, size * sizeof(void *), GFP_KERNEL); -} - -static inline void cq_delete(struct kfifo *kfifo) -{ - kfifo_free(kfifo); -} - -static inline unsigned int cq_howmany(struct kfifo *kfifo) -{ - return kfifo_len(kfifo) / sizeof(void *); -} - -static inline int cq_put(struct kfifo *kfifo, void *p) -{ - return kfifo_in(kfifo, (void *)&p, sizeof(p)); -} - -static inline void *cq_get(struct kfifo *kfifo) -{ - unsigned int sz; - void *p; - - sz = kfifo_out(kfifo, (void *)&p, sizeof(p)); - if (sz != sizeof(p)) - return NULL; - - return p; -} - -/* fhci-hcd.c */ -void fhci_start_sof_timer(struct fhci_hcd *fhci); -void fhci_stop_sof_timer(struct fhci_hcd *fhci); -u16 fhci_get_sof_timer_count(struct fhci_usb *usb); -void fhci_usb_enable_interrupt(struct fhci_usb *usb); -void fhci_usb_disable_interrupt(struct fhci_usb *usb); -int fhci_ioports_check_bus_state(struct fhci_hcd *fhci); - -/* fhci-mem.c */ -void fhci_recycle_empty_td(struct fhci_hcd *fhci, struct td *td); -void fhci_recycle_empty_ed(struct fhci_hcd *fhci, struct ed *ed); -struct ed *fhci_get_empty_ed(struct fhci_hcd *fhci); -struct td *fhci_td_fill(struct fhci_hcd *fhci, struct urb *urb, - struct urb_priv *urb_priv, struct ed *ed, u16 index, - enum fhci_ta_type type, int toggle, u8 *data, u32 len, - u16 interval, u16 start_frame, bool ioc); -void fhci_add_tds_to_ed(struct ed *ed, struct td **td_list, int number); - -/* fhci-hub.c */ -void fhci_config_transceiver(struct fhci_hcd *fhci, - enum fhci_port_status status); -void fhci_port_disable(struct fhci_hcd *fhci); -void fhci_port_enable(void *lld); -void fhci_io_port_generate_reset(struct fhci_hcd *fhci); -void fhci_port_reset(void *lld); -int fhci_hub_status_data(struct usb_hcd *hcd, char *buf); -int fhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, - u16 wIndex, char *buf, u16 wLength); - -/* fhci-tds.c */ -void fhci_flush_bds(struct fhci_usb *usb); -void fhci_flush_actual_frame(struct fhci_usb *usb); -u32 fhci_host_transaction(struct fhci_usb *usb, struct packet *pkt, - enum fhci_ta_type trans_type, u8 dest_addr, - u8 dest_ep, enum fhci_tf_mode trans_mode, - enum fhci_speed dest_speed, u8 data_toggle); -void fhci_host_transmit_actual_frame(struct fhci_usb *usb); -void fhci_tx_conf_interrupt(struct fhci_usb *usb); -void fhci_push_dummy_bd(struct endpoint *ep); -u32 fhci_create_ep(struct fhci_usb *usb, enum fhci_mem_alloc data_mem, - u32 ring_len); -void fhci_init_ep_registers(struct fhci_usb *usb, - struct endpoint *ep, - enum fhci_mem_alloc data_mem); -void fhci_ep0_free(struct fhci_usb *usb); - -/* fhci-sched.c */ -extern struct tasklet_struct fhci_tasklet; -void fhci_transaction_confirm(struct fhci_usb *usb, struct packet *pkt); -void fhci_flush_all_transmissions(struct fhci_usb *usb); -void fhci_schedule_transactions(struct fhci_usb *usb); -void fhci_device_connected_interrupt(struct fhci_hcd *fhci); -void fhci_device_disconnected_interrupt(struct fhci_hcd *fhci); -void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb); -u32 fhci_transfer_confirm_callback(struct fhci_hcd *fhci); -irqreturn_t fhci_irq(struct usb_hcd *hcd); -irqreturn_t fhci_frame_limit_timer_irq(int irq, void *_hcd); - -/* fhci-q.h */ -void fhci_urb_complete_free(struct fhci_hcd *fhci, struct urb *urb); -struct td *fhci_remove_td_from_ed(struct ed *ed); -struct td *fhci_remove_td_from_frame(struct fhci_time_frame *frame); -void fhci_move_td_from_ed_to_done_list(struct fhci_usb *usb, struct ed *ed); -struct td *fhci_peek_td_from_frame(struct fhci_time_frame *frame); -void fhci_add_td_to_frame(struct fhci_time_frame *frame, struct td *td); -struct td *fhci_remove_td_from_done_list(struct fhci_controller_list *p_list); -void fhci_done_td(struct urb *urb, struct td *td); -void fhci_del_ed_list(struct fhci_hcd *fhci, struct ed *ed); - -#ifdef CONFIG_FHCI_DEBUG - -void fhci_dbg_isr(struct fhci_hcd *fhci, int usb_er); -void fhci_dfs_destroy(struct fhci_hcd *fhci); -void fhci_dfs_create(struct fhci_hcd *fhci); - -#else - -static inline void fhci_dbg_isr(struct fhci_hcd *fhci, int usb_er) {} -static inline void fhci_dfs_destroy(struct fhci_hcd *fhci) {} -static inline void fhci_dfs_create(struct fhci_hcd *fhci) {} - -#endif /* CONFIG_FHCI_DEBUG */ - -#endif /* __FHCI_H */ diff --git a/ANDROID_3.4.5/drivers/usb/host/fsl-mph-dr-of.c b/ANDROID_3.4.5/drivers/usb/host/fsl-mph-dr-of.c deleted file mode 100644 index ab333ac6..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/fsl-mph-dr-of.c +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Setup platform devices needed by the Freescale multi-port host - * and/or dual-role USB controller modules based on the description - * in flat device tree. - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -struct fsl_usb2_dev_data { - char *dr_mode; /* controller mode */ - char *drivers[3]; /* drivers to instantiate for this mode */ - enum fsl_usb2_operating_modes op_mode; /* operating mode */ -}; - -struct fsl_usb2_dev_data dr_mode_data[] __devinitdata = { - { - .dr_mode = "host", - .drivers = { "fsl-ehci", NULL, NULL, }, - .op_mode = FSL_USB2_DR_HOST, - }, - { - .dr_mode = "otg", - .drivers = { "fsl-usb2-otg", "fsl-ehci", "fsl-usb2-udc", }, - .op_mode = FSL_USB2_DR_OTG, - }, - { - .dr_mode = "peripheral", - .drivers = { "fsl-usb2-udc", NULL, NULL, }, - .op_mode = FSL_USB2_DR_DEVICE, - }, -}; - -struct fsl_usb2_dev_data * __devinit get_dr_mode_data(struct device_node *np) -{ - const unsigned char *prop; - int i; - - prop = of_get_property(np, "dr_mode", NULL); - if (prop) { - for (i = 0; i < ARRAY_SIZE(dr_mode_data); i++) { - if (!strcmp(prop, dr_mode_data[i].dr_mode)) - return &dr_mode_data[i]; - } - } - pr_warn("%s: Invalid 'dr_mode' property, fallback to host mode\n", - np->full_name); - return &dr_mode_data[0]; /* mode not specified, use host */ -} - -static enum fsl_usb2_phy_modes __devinit determine_usb_phy(const char *phy_type) -{ - if (!phy_type) - return FSL_USB2_PHY_NONE; - if (!strcasecmp(phy_type, "ulpi")) - return FSL_USB2_PHY_ULPI; - if (!strcasecmp(phy_type, "utmi")) - return FSL_USB2_PHY_UTMI; - if (!strcasecmp(phy_type, "utmi_wide")) - return FSL_USB2_PHY_UTMI_WIDE; - if (!strcasecmp(phy_type, "serial")) - return FSL_USB2_PHY_SERIAL; - - return FSL_USB2_PHY_NONE; -} - -struct platform_device * __devinit fsl_usb2_device_register( - struct platform_device *ofdev, - struct fsl_usb2_platform_data *pdata, - const char *name, int id) -{ - struct platform_device *pdev; - const struct resource *res = ofdev->resource; - unsigned int num = ofdev->num_resources; - int retval; - - pdev = platform_device_alloc(name, id); - if (!pdev) { - retval = -ENOMEM; - goto error; - } - - pdev->dev.parent = &ofdev->dev; - - pdev->dev.coherent_dma_mask = ofdev->dev.coherent_dma_mask; - *pdev->dev.dma_mask = *ofdev->dev.dma_mask; - - retval = platform_device_add_data(pdev, pdata, sizeof(*pdata)); - if (retval) - goto error; - - if (num) { - retval = platform_device_add_resources(pdev, res, num); - if (retval) - goto error; - } - - retval = platform_device_add(pdev); - if (retval) - goto error; - - return pdev; - -error: - platform_device_put(pdev); - return ERR_PTR(retval); -} - -static const struct of_device_id fsl_usb2_mph_dr_of_match[]; - -static int __devinit fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) -{ - struct device_node *np = ofdev->dev.of_node; - struct platform_device *usb_dev; - struct fsl_usb2_platform_data data, *pdata; - struct fsl_usb2_dev_data *dev_data; - const struct of_device_id *match; - const unsigned char *prop; - static unsigned int idx; - int i; - - if (!of_device_is_available(np)) - return -ENODEV; - - match = of_match_device(fsl_usb2_mph_dr_of_match, &ofdev->dev); - if (!match) - return -ENODEV; - - pdata = &data; - if (match->data) - memcpy(pdata, match->data, sizeof(data)); - else - memset(pdata, 0, sizeof(data)); - - dev_data = get_dr_mode_data(np); - - if (of_device_is_compatible(np, "fsl-usb2-mph")) { - if (of_get_property(np, "port0", NULL)) - pdata->port_enables |= FSL_USB2_PORT0_ENABLED; - - if (of_get_property(np, "port1", NULL)) - pdata->port_enables |= FSL_USB2_PORT1_ENABLED; - - pdata->operating_mode = FSL_USB2_MPH_HOST; - } else { - if (of_get_property(np, "fsl,invert-drvvbus", NULL)) - pdata->invert_drvvbus = 1; - - if (of_get_property(np, "fsl,invert-pwr-fault", NULL)) - pdata->invert_pwr_fault = 1; - - /* setup mode selected in the device tree */ - pdata->operating_mode = dev_data->op_mode; - } - - prop = of_get_property(np, "phy_type", NULL); - pdata->phy_mode = determine_usb_phy(prop); - - for (i = 0; i < ARRAY_SIZE(dev_data->drivers); i++) { - if (!dev_data->drivers[i]) - continue; - usb_dev = fsl_usb2_device_register(ofdev, pdata, - dev_data->drivers[i], idx); - if (IS_ERR(usb_dev)) { - dev_err(&ofdev->dev, "Can't register usb device\n"); - return PTR_ERR(usb_dev); - } - } - idx++; - return 0; -} - -static int __devexit __unregister_subdev(struct device *dev, void *d) -{ - platform_device_unregister(to_platform_device(dev)); - return 0; -} - -static int __devexit fsl_usb2_mph_dr_of_remove(struct platform_device *ofdev) -{ - device_for_each_child(&ofdev->dev, NULL, __unregister_subdev); - return 0; -} - -#ifdef CONFIG_PPC_MPC512x - -#define USBGENCTRL 0x200 /* NOTE: big endian */ -#define GC_WU_INT_CLR (1 << 5) /* Wakeup int clear */ -#define GC_ULPI_SEL (1 << 4) /* ULPI i/f select (usb0 only)*/ -#define GC_PPP (1 << 3) /* Inv. Port Power Polarity */ -#define GC_PFP (1 << 2) /* Inv. Power Fault Polarity */ -#define GC_WU_ULPI_EN (1 << 1) /* Wakeup on ULPI event */ -#define GC_WU_IE (1 << 1) /* Wakeup interrupt enable */ - -#define ISIPHYCTRL 0x204 /* NOTE: big endian */ -#define PHYCTRL_PHYE (1 << 4) /* On-chip UTMI PHY enable */ -#define PHYCTRL_BSENH (1 << 3) /* Bit Stuff Enable High */ -#define PHYCTRL_BSEN (1 << 2) /* Bit Stuff Enable */ -#define PHYCTRL_LSFE (1 << 1) /* Line State Filter Enable */ -#define PHYCTRL_PXE (1 << 0) /* PHY oscillator enable */ - -int fsl_usb2_mpc5121_init(struct platform_device *pdev) -{ - struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; - struct clk *clk; - char clk_name[10]; - int base, clk_num; - - base = pdev->resource->start & 0xf000; - if (base == 0x3000) - clk_num = 1; - else if (base == 0x4000) - clk_num = 2; - else - return -ENODEV; - - snprintf(clk_name, sizeof(clk_name), "usb%d_clk", clk_num); - clk = clk_get(&pdev->dev, clk_name); - if (IS_ERR(clk)) { - dev_err(&pdev->dev, "failed to get clk\n"); - return PTR_ERR(clk); - } - - clk_enable(clk); - pdata->clk = clk; - - if (pdata->phy_mode == FSL_USB2_PHY_UTMI_WIDE) { - u32 reg = 0; - - if (pdata->invert_drvvbus) - reg |= GC_PPP; - - if (pdata->invert_pwr_fault) - reg |= GC_PFP; - - out_be32(pdata->regs + ISIPHYCTRL, PHYCTRL_PHYE | PHYCTRL_PXE); - out_be32(pdata->regs + USBGENCTRL, reg); - } - return 0; -} - -static void fsl_usb2_mpc5121_exit(struct platform_device *pdev) -{ - struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; - - pdata->regs = NULL; - - if (pdata->clk) { - clk_disable(pdata->clk); - clk_put(pdata->clk); - } -} - -static struct fsl_usb2_platform_data fsl_usb2_mpc5121_pd = { - .big_endian_desc = 1, - .big_endian_mmio = 1, - .es = 1, - .have_sysif_regs = 0, - .le_setup_buf = 1, - .init = fsl_usb2_mpc5121_init, - .exit = fsl_usb2_mpc5121_exit, -}; -#endif /* CONFIG_PPC_MPC512x */ - -static struct fsl_usb2_platform_data fsl_usb2_mpc8xxx_pd = { - .have_sysif_regs = 1, -}; - -static const struct of_device_id fsl_usb2_mph_dr_of_match[] = { - { .compatible = "fsl-usb2-mph", .data = &fsl_usb2_mpc8xxx_pd, }, - { .compatible = "fsl-usb2-dr", .data = &fsl_usb2_mpc8xxx_pd, }, -#ifdef CONFIG_PPC_MPC512x - { .compatible = "fsl,mpc5121-usb2-dr", .data = &fsl_usb2_mpc5121_pd, }, -#endif - {}, -}; - -static struct platform_driver fsl_usb2_mph_dr_driver = { - .driver = { - .name = "fsl-usb2-mph-dr", - .owner = THIS_MODULE, - .of_match_table = fsl_usb2_mph_dr_of_match, - }, - .probe = fsl_usb2_mph_dr_of_probe, - .remove = __devexit_p(fsl_usb2_mph_dr_of_remove), -}; - -module_platform_driver(fsl_usb2_mph_dr_driver); - -MODULE_DESCRIPTION("FSL MPH DR OF devices driver"); -MODULE_AUTHOR("Anatolij Gustschin "); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/host/hwa-hc.c b/ANDROID_3.4.5/drivers/usb/host/hwa-hc.c deleted file mode 100644 index 104730da..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/hwa-hc.c +++ /dev/null @@ -1,843 +0,0 @@ -/* - * Host Wire Adapter: - * Driver glue, HWA-specific functions, bridges to WAHC and WUSBHC - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * - * The HWA driver is a simple layer that forwards requests to the WAHC - * (Wire Adater Host Controller) or WUSBHC (Wireless USB Host - * Controller) layers. - * - * Host Wire Adapter is the 'WUSB 1.0 standard' name for Wireless-USB - * Host Controller that is connected to your system via USB (a USB - * dongle that implements a USB host...). There is also a Device Wired - * Adaptor, DWA (Wireless USB hub) that uses the same mechanism for - * transferring data (it is after all a USB host connected via - * Wireless USB), we have a common layer called Wire Adapter Host - * Controller that does all the hard work. The WUSBHC (Wireless USB - * Host Controller) is the part common to WUSB Host Controllers, the - * HWA and the PCI-based one, that is implemented following the WHCI - * spec. All these layers are implemented in ../wusbcore. - * - * The main functions are hwahc_op_urb_{en,de}queue(), that pass the - * job of converting a URB to a Wire Adapter - * - * Entry points: - * - * hwahc_driver_*() Driver initialization, registration and - * teardown. - * - * hwahc_probe() New device came up, create an instance for - * it [from device enumeration]. - * - * hwahc_disconnect() Remove device instance [from device - * enumeration]. - * - * [__]hwahc_op_*() Host-Wire-Adaptor specific functions for - * starting/stopping/etc (some might be made also - * DWA). - */ -#include -#include -#include -#include -#include -#include -#include -#include "../wusbcore/wa-hc.h" -#include "../wusbcore/wusbhc.h" - -struct hwahc { - struct wusbhc wusbhc; /* has to be 1st */ - struct wahc wa; -}; - -/* - * FIXME should be wusbhc - * - * NOTE: we need to cache the Cluster ID because later...there is no - * way to get it :) - */ -static int __hwahc_set_cluster_id(struct hwahc *hwahc, u8 cluster_id) -{ - int result; - struct wusbhc *wusbhc = &hwahc->wusbhc; - struct wahc *wa = &hwahc->wa; - struct device *dev = &wa->usb_iface->dev; - - result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), - WUSB_REQ_SET_CLUSTER_ID, - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - cluster_id, - wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, - NULL, 0, 1000 /* FIXME: arbitrary */); - if (result < 0) - dev_err(dev, "Cannot set WUSB Cluster ID to 0x%02x: %d\n", - cluster_id, result); - else - wusbhc->cluster_id = cluster_id; - dev_info(dev, "Wireless USB Cluster ID set to 0x%02x\n", cluster_id); - return result; -} - -static int __hwahc_op_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots) -{ - struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); - struct wahc *wa = &hwahc->wa; - - return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), - WUSB_REQ_SET_NUM_DNTS, - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - interval << 8 | slots, - wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, - NULL, 0, 1000 /* FIXME: arbitrary */); -} - -/* - * Reset a WUSB host controller and wait for it to complete doing it. - * - * @usb_hcd: Pointer to WUSB Host Controller instance. - * - */ -static int hwahc_op_reset(struct usb_hcd *usb_hcd) -{ - int result; - struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); - struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); - struct device *dev = &hwahc->wa.usb_iface->dev; - - mutex_lock(&wusbhc->mutex); - wa_nep_disarm(&hwahc->wa); - result = __wa_set_feature(&hwahc->wa, WA_RESET); - if (result < 0) { - dev_err(dev, "error commanding HC to reset: %d\n", result); - goto error_unlock; - } - result = __wa_wait_status(&hwahc->wa, WA_STATUS_RESETTING, 0); - if (result < 0) { - dev_err(dev, "error waiting for HC to reset: %d\n", result); - goto error_unlock; - } -error_unlock: - mutex_unlock(&wusbhc->mutex); - return result; -} - -/* - * FIXME: break this function up - */ -static int hwahc_op_start(struct usb_hcd *usb_hcd) -{ - u8 addr; - int result; - struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); - struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); - - result = -ENOSPC; - mutex_lock(&wusbhc->mutex); - addr = wusb_cluster_id_get(); - if (addr == 0) - goto error_cluster_id_get; - result = __hwahc_set_cluster_id(hwahc, addr); - if (result < 0) - goto error_set_cluster_id; - - usb_hcd->uses_new_polling = 1; - set_bit(HCD_FLAG_POLL_RH, &usb_hcd->flags); - usb_hcd->state = HC_STATE_RUNNING; - result = 0; -out: - mutex_unlock(&wusbhc->mutex); - return result; - -error_set_cluster_id: - wusb_cluster_id_put(wusbhc->cluster_id); -error_cluster_id_get: - goto out; - -} - -/* - * No need to abort pipes, as when this is called, all the children - * has been disconnected and that has done it [through - * usb_disable_interface() -> usb_disable_endpoint() -> - * hwahc_op_ep_disable() - >rpipe_ep_disable()]. - */ -static void hwahc_op_stop(struct usb_hcd *usb_hcd) -{ - struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); - - mutex_lock(&wusbhc->mutex); - wusb_cluster_id_put(wusbhc->cluster_id); - mutex_unlock(&wusbhc->mutex); -} - -static int hwahc_op_get_frame_number(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; -} - -static int hwahc_op_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb, - gfp_t gfp) -{ - struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); - struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); - - return wa_urb_enqueue(&hwahc->wa, urb->ep, urb, gfp); -} - -static int hwahc_op_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb, - int status) -{ - struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); - struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); - - return wa_urb_dequeue(&hwahc->wa, urb); -} - -/* - * Release resources allocated for an endpoint - * - * If there is an associated rpipe to this endpoint, go ahead and put it. - */ -static void hwahc_op_endpoint_disable(struct usb_hcd *usb_hcd, - struct usb_host_endpoint *ep) -{ - struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); - struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); - - rpipe_ep_disable(&hwahc->wa, ep); -} - -static int __hwahc_op_wusbhc_start(struct wusbhc *wusbhc) -{ - int result; - struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); - struct device *dev = &hwahc->wa.usb_iface->dev; - - result = __wa_set_feature(&hwahc->wa, WA_ENABLE); - if (result < 0) { - dev_err(dev, "error commanding HC to start: %d\n", result); - goto error_stop; - } - result = __wa_wait_status(&hwahc->wa, WA_ENABLE, WA_ENABLE); - if (result < 0) { - dev_err(dev, "error waiting for HC to start: %d\n", result); - goto error_stop; - } - result = wa_nep_arm(&hwahc->wa, GFP_KERNEL); - if (result < 0) { - dev_err(dev, "cannot listen to notifications: %d\n", result); - goto error_stop; - } - return result; - -error_stop: - __wa_clear_feature(&hwahc->wa, WA_ENABLE); - return result; -} - -static void __hwahc_op_wusbhc_stop(struct wusbhc *wusbhc, int delay) -{ - struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); - struct wahc *wa = &hwahc->wa; - u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber; - int ret; - - ret = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), - WUSB_REQ_CHAN_STOP, - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - delay * 1000, - iface_no, - NULL, 0, 1000 /* FIXME: arbitrary */); - if (ret == 0) - msleep(delay); - - wa_nep_disarm(&hwahc->wa); - __wa_stop(&hwahc->wa); -} - -/* - * Set the UWB MAS allocation for the WUSB cluster - * - * @stream_index: stream to use (-1 for cancelling the allocation) - * @mas: mas bitmap to use - */ -static int __hwahc_op_bwa_set(struct wusbhc *wusbhc, s8 stream_index, - const struct uwb_mas_bm *mas) -{ - int result; - struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); - struct wahc *wa = &hwahc->wa; - struct device *dev = &wa->usb_iface->dev; - u8 mas_le[UWB_NUM_MAS/8]; - - /* Set the stream index */ - result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), - WUSB_REQ_SET_STREAM_IDX, - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - stream_index, - wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, - NULL, 0, 1000 /* FIXME: arbitrary */); - if (result < 0) { - dev_err(dev, "Cannot set WUSB stream index: %d\n", result); - goto out; - } - uwb_mas_bm_copy_le(mas_le, mas); - /* Set the MAS allocation */ - result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), - WUSB_REQ_SET_WUSB_MAS, - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, - mas_le, 32, 1000 /* FIXME: arbitrary */); - if (result < 0) - dev_err(dev, "Cannot set WUSB MAS allocation: %d\n", result); -out: - return result; -} - -/* - * Add an IE to the host's MMC - * - * @interval: See WUSB1.0[8.5.3.1] - * @repeat_cnt: See WUSB1.0[8.5.3.1] - * @handle: See WUSB1.0[8.5.3.1] - * @wuie: Pointer to the header of the WUSB IE data to add. - * MUST BE allocated in a kmalloc buffer (no stack or - * vmalloc). - * - * NOTE: the format of the WUSB IEs for MMCs are different to the - * normal MBOA MAC IEs (IE Id + Length in MBOA MAC vs. Length + - * Id in WUSB IEs). Standards...you gotta love'em. - */ -static int __hwahc_op_mmcie_add(struct wusbhc *wusbhc, u8 interval, - u8 repeat_cnt, u8 handle, - struct wuie_hdr *wuie) -{ - struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); - struct wahc *wa = &hwahc->wa; - u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber; - - return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), - WUSB_REQ_ADD_MMC_IE, - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - interval << 8 | repeat_cnt, - handle << 8 | iface_no, - wuie, wuie->bLength, 1000 /* FIXME: arbitrary */); -} - -/* - * Remove an IE to the host's MMC - * - * @handle: See WUSB1.0[8.5.3.1] - */ -static int __hwahc_op_mmcie_rm(struct wusbhc *wusbhc, u8 handle) -{ - struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); - struct wahc *wa = &hwahc->wa; - u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber; - return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), - WUSB_REQ_REMOVE_MMC_IE, - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, handle << 8 | iface_no, - NULL, 0, 1000 /* FIXME: arbitrary */); -} - -/* - * Update device information for a given fake port - * - * @port_idx: Fake port to which device is connected (wusbhc index, not - * USB port number). - */ -static int __hwahc_op_dev_info_set(struct wusbhc *wusbhc, - struct wusb_dev *wusb_dev) -{ - struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); - struct wahc *wa = &hwahc->wa; - u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber; - struct hwa_dev_info *dev_info; - int ret; - - /* fill out the Device Info buffer and send it */ - dev_info = kzalloc(sizeof(struct hwa_dev_info), GFP_KERNEL); - if (!dev_info) - return -ENOMEM; - uwb_mas_bm_copy_le(dev_info->bmDeviceAvailability, - &wusb_dev->availability); - dev_info->bDeviceAddress = wusb_dev->addr; - - /* - * If the descriptors haven't been read yet, use a default PHY - * rate of 53.3 Mbit/s only. The correct value will be used - * when this will be called again as part of the - * authentication process (which occurs after the descriptors - * have been read). - */ - if (wusb_dev->wusb_cap_descr) - dev_info->wPHYRates = wusb_dev->wusb_cap_descr->wPHYRates; - else - dev_info->wPHYRates = cpu_to_le16(USB_WIRELESS_PHY_53); - - ret = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), - WUSB_REQ_SET_DEV_INFO, - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, wusb_dev->port_idx << 8 | iface_no, - dev_info, sizeof(struct hwa_dev_info), - 1000 /* FIXME: arbitrary */); - kfree(dev_info); - return ret; -} - -/* - * Set host's idea of which encryption (and key) method to use when - * talking to ad evice on a given port. - * - * If key is NULL, it means disable encryption for that "virtual port" - * (used when we disconnect). - */ -static int __hwahc_dev_set_key(struct wusbhc *wusbhc, u8 port_idx, u32 tkid, - const void *key, size_t key_size, - u8 key_idx) -{ - int result = -ENOMEM; - struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); - struct wahc *wa = &hwahc->wa; - u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber; - struct usb_key_descriptor *keyd; - size_t keyd_len; - - keyd_len = sizeof(*keyd) + key_size; - keyd = kzalloc(keyd_len, GFP_KERNEL); - if (keyd == NULL) - return -ENOMEM; - - keyd->bLength = keyd_len; - keyd->bDescriptorType = USB_DT_KEY; - keyd->tTKID[0] = (tkid >> 0) & 0xff; - keyd->tTKID[1] = (tkid >> 8) & 0xff; - keyd->tTKID[2] = (tkid >> 16) & 0xff; - memcpy(keyd->bKeyData, key, key_size); - - result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), - USB_REQ_SET_DESCRIPTOR, - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - USB_DT_KEY << 8 | key_idx, - port_idx << 8 | iface_no, - keyd, keyd_len, 1000 /* FIXME: arbitrary */); - - kzfree(keyd); /* clear keys etc. */ - return result; -} - -/* - * Set host's idea of which encryption (and key) method to use when - * talking to ad evice on a given port. - * - * If key is NULL, it means disable encryption for that "virtual port" - * (used when we disconnect). - */ -static int __hwahc_op_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid, - const void *key, size_t key_size) -{ - int result = -ENOMEM; - struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); - struct wahc *wa = &hwahc->wa; - u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber; - u8 encryption_value; - - /* Tell the host which key to use to talk to the device */ - if (key) { - u8 key_idx = wusb_key_index(0, WUSB_KEY_INDEX_TYPE_PTK, - WUSB_KEY_INDEX_ORIGINATOR_HOST); - - result = __hwahc_dev_set_key(wusbhc, port_idx, tkid, - key, key_size, key_idx); - if (result < 0) - goto error_set_key; - encryption_value = wusbhc->ccm1_etd->bEncryptionValue; - } else { - /* FIXME: this should come from wusbhc->etd[UNSECURE].value */ - encryption_value = 0; - } - - /* Set the encryption type for communicating with the device */ - result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), - USB_REQ_SET_ENCRYPTION, - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - encryption_value, port_idx << 8 | iface_no, - NULL, 0, 1000 /* FIXME: arbitrary */); - if (result < 0) - dev_err(wusbhc->dev, "Can't set host's WUSB encryption for " - "port index %u to %s (value %d): %d\n", port_idx, - wusb_et_name(wusbhc->ccm1_etd->bEncryptionType), - wusbhc->ccm1_etd->bEncryptionValue, result); -error_set_key: - return result; -} - -/* - * Set host's GTK key - */ -static int __hwahc_op_set_gtk(struct wusbhc *wusbhc, u32 tkid, - const void *key, size_t key_size) -{ - u8 key_idx = wusb_key_index(0, WUSB_KEY_INDEX_TYPE_GTK, - WUSB_KEY_INDEX_ORIGINATOR_HOST); - - return __hwahc_dev_set_key(wusbhc, 0, tkid, key, key_size, key_idx); -} - -/* - * Get the Wire Adapter class-specific descriptor - * - * NOTE: this descriptor comes with the big bundled configuration - * descriptor that includes the interfaces' and endpoints', so - * we just look for it in the cached copy kept by the USB stack. - * - * NOTE2: We convert LE fields to CPU order. - */ -static int wa_fill_descr(struct wahc *wa) -{ - int result; - struct device *dev = &wa->usb_iface->dev; - char *itr; - struct usb_device *usb_dev = wa->usb_dev; - struct usb_descriptor_header *hdr; - struct usb_wa_descriptor *wa_descr; - size_t itr_size, actconfig_idx; - - actconfig_idx = (usb_dev->actconfig - usb_dev->config) / - sizeof(usb_dev->config[0]); - itr = usb_dev->rawdescriptors[actconfig_idx]; - itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength); - while (itr_size >= sizeof(*hdr)) { - hdr = (struct usb_descriptor_header *) itr; - dev_dbg(dev, "Extra device descriptor: " - "type %02x/%u bytes @ %zu (%zu left)\n", - hdr->bDescriptorType, hdr->bLength, - (itr - usb_dev->rawdescriptors[actconfig_idx]), - itr_size); - if (hdr->bDescriptorType == USB_DT_WIRE_ADAPTER) - goto found; - itr += hdr->bLength; - itr_size -= hdr->bLength; - } - dev_err(dev, "cannot find Wire Adapter Class descriptor\n"); - return -ENODEV; - -found: - result = -EINVAL; - if (hdr->bLength > itr_size) { /* is it available? */ - dev_err(dev, "incomplete Wire Adapter Class descriptor " - "(%zu bytes left, %u needed)\n", - itr_size, hdr->bLength); - goto error; - } - if (hdr->bLength < sizeof(*wa->wa_descr)) { - dev_err(dev, "short Wire Adapter Class descriptor\n"); - goto error; - } - wa->wa_descr = wa_descr = (struct usb_wa_descriptor *) hdr; - /* Make LE fields CPU order */ - wa_descr->bcdWAVersion = le16_to_cpu(wa_descr->bcdWAVersion); - wa_descr->wNumRPipes = le16_to_cpu(wa_descr->wNumRPipes); - wa_descr->wRPipeMaxBlock = le16_to_cpu(wa_descr->wRPipeMaxBlock); - if (wa_descr->bcdWAVersion > 0x0100) - dev_warn(dev, "Wire Adapter v%d.%d newer than groked v1.0\n", - wa_descr->bcdWAVersion & 0xff00 >> 8, - wa_descr->bcdWAVersion & 0x00ff); - result = 0; -error: - return result; -} - -static struct hc_driver hwahc_hc_driver = { - .description = "hwa-hcd", - .product_desc = "Wireless USB HWA host controller", - .hcd_priv_size = sizeof(struct hwahc) - sizeof(struct usb_hcd), - .irq = NULL, /* FIXME */ - .flags = HCD_USB2, /* FIXME */ - .reset = hwahc_op_reset, - .start = hwahc_op_start, - .stop = hwahc_op_stop, - .get_frame_number = hwahc_op_get_frame_number, - .urb_enqueue = hwahc_op_urb_enqueue, - .urb_dequeue = hwahc_op_urb_dequeue, - .endpoint_disable = hwahc_op_endpoint_disable, - - .hub_status_data = wusbhc_rh_status_data, - .hub_control = wusbhc_rh_control, - .bus_suspend = wusbhc_rh_suspend, - .bus_resume = wusbhc_rh_resume, - .start_port_reset = wusbhc_rh_start_port_reset, -}; - -static int hwahc_security_create(struct hwahc *hwahc) -{ - int result; - struct wusbhc *wusbhc = &hwahc->wusbhc; - struct usb_device *usb_dev = hwahc->wa.usb_dev; - struct device *dev = &usb_dev->dev; - struct usb_security_descriptor *secd; - struct usb_encryption_descriptor *etd; - void *itr, *top; - size_t itr_size, needed, bytes; - u8 index; - char buf[64]; - - /* Find the host's security descriptors in the config descr bundle */ - index = (usb_dev->actconfig - usb_dev->config) / - sizeof(usb_dev->config[0]); - itr = usb_dev->rawdescriptors[index]; - itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength); - top = itr + itr_size; - result = __usb_get_extra_descriptor(usb_dev->rawdescriptors[index], - le16_to_cpu(usb_dev->actconfig->desc.wTotalLength), - USB_DT_SECURITY, (void **) &secd); - if (result == -1) { - dev_warn(dev, "BUG? WUSB host has no security descriptors\n"); - return 0; - } - needed = sizeof(*secd); - if (top - (void *)secd < needed) { - dev_err(dev, "BUG? Not enough data to process security " - "descriptor header (%zu bytes left vs %zu needed)\n", - top - (void *) secd, needed); - return 0; - } - needed = le16_to_cpu(secd->wTotalLength); - if (top - (void *)secd < needed) { - dev_err(dev, "BUG? Not enough data to process security " - "descriptors (%zu bytes left vs %zu needed)\n", - top - (void *) secd, needed); - return 0; - } - /* Walk over the sec descriptors and store CCM1's on wusbhc */ - itr = (void *) secd + sizeof(*secd); - top = (void *) secd + le16_to_cpu(secd->wTotalLength); - index = 0; - bytes = 0; - while (itr < top) { - etd = itr; - if (top - itr < sizeof(*etd)) { - dev_err(dev, "BUG: bad host security descriptor; " - "not enough data (%zu vs %zu left)\n", - top - itr, sizeof(*etd)); - break; - } - if (etd->bLength < sizeof(*etd)) { - dev_err(dev, "BUG: bad host encryption descriptor; " - "descriptor is too short " - "(%zu vs %zu needed)\n", - (size_t)etd->bLength, sizeof(*etd)); - break; - } - itr += etd->bLength; - bytes += snprintf(buf + bytes, sizeof(buf) - bytes, - "%s (0x%02x) ", - wusb_et_name(etd->bEncryptionType), - etd->bEncryptionValue); - wusbhc->ccm1_etd = etd; - } - dev_info(dev, "supported encryption types: %s\n", buf); - if (wusbhc->ccm1_etd == NULL) { - dev_err(dev, "E: host doesn't support CCM-1 crypto\n"); - return 0; - } - /* Pretty print what we support */ - return 0; -} - -static void hwahc_security_release(struct hwahc *hwahc) -{ - /* nothing to do here so far... */ -} - -static int hwahc_create(struct hwahc *hwahc, struct usb_interface *iface) -{ - int result; - struct device *dev = &iface->dev; - struct wusbhc *wusbhc = &hwahc->wusbhc; - struct wahc *wa = &hwahc->wa; - struct usb_device *usb_dev = interface_to_usbdev(iface); - - wa->usb_dev = usb_get_dev(usb_dev); /* bind the USB device */ - wa->usb_iface = usb_get_intf(iface); - wusbhc->dev = dev; - wusbhc->uwb_rc = uwb_rc_get_by_grandpa(iface->dev.parent); - if (wusbhc->uwb_rc == NULL) { - result = -ENODEV; - dev_err(dev, "Cannot get associated UWB Host Controller\n"); - goto error_rc_get; - } - result = wa_fill_descr(wa); /* Get the device descriptor */ - if (result < 0) - goto error_fill_descriptor; - if (wa->wa_descr->bNumPorts > USB_MAXCHILDREN) { - dev_err(dev, "FIXME: USB_MAXCHILDREN too low for WUSB " - "adapter (%u ports)\n", wa->wa_descr->bNumPorts); - wusbhc->ports_max = USB_MAXCHILDREN; - } else { - wusbhc->ports_max = wa->wa_descr->bNumPorts; - } - wusbhc->mmcies_max = wa->wa_descr->bNumMMCIEs; - wusbhc->start = __hwahc_op_wusbhc_start; - wusbhc->stop = __hwahc_op_wusbhc_stop; - wusbhc->mmcie_add = __hwahc_op_mmcie_add; - wusbhc->mmcie_rm = __hwahc_op_mmcie_rm; - wusbhc->dev_info_set = __hwahc_op_dev_info_set; - wusbhc->bwa_set = __hwahc_op_bwa_set; - wusbhc->set_num_dnts = __hwahc_op_set_num_dnts; - wusbhc->set_ptk = __hwahc_op_set_ptk; - wusbhc->set_gtk = __hwahc_op_set_gtk; - result = hwahc_security_create(hwahc); - if (result < 0) { - dev_err(dev, "Can't initialize security: %d\n", result); - goto error_security_create; - } - wa->wusb = wusbhc; /* FIXME: ugly, need to fix */ - result = wusbhc_create(&hwahc->wusbhc); - if (result < 0) { - dev_err(dev, "Can't create WUSB HC structures: %d\n", result); - goto error_wusbhc_create; - } - result = wa_create(&hwahc->wa, iface); - if (result < 0) - goto error_wa_create; - return 0; - -error_wa_create: - wusbhc_destroy(&hwahc->wusbhc); -error_wusbhc_create: - /* WA Descr fill allocs no resources */ -error_security_create: -error_fill_descriptor: - uwb_rc_put(wusbhc->uwb_rc); -error_rc_get: - usb_put_intf(iface); - usb_put_dev(usb_dev); - return result; -} - -static void hwahc_destroy(struct hwahc *hwahc) -{ - struct wusbhc *wusbhc = &hwahc->wusbhc; - - mutex_lock(&wusbhc->mutex); - __wa_destroy(&hwahc->wa); - wusbhc_destroy(&hwahc->wusbhc); - hwahc_security_release(hwahc); - hwahc->wusbhc.dev = NULL; - uwb_rc_put(wusbhc->uwb_rc); - usb_put_intf(hwahc->wa.usb_iface); - usb_put_dev(hwahc->wa.usb_dev); - mutex_unlock(&wusbhc->mutex); -} - -static void hwahc_init(struct hwahc *hwahc) -{ - wa_init(&hwahc->wa); -} - -static int hwahc_probe(struct usb_interface *usb_iface, - const struct usb_device_id *id) -{ - int result; - struct usb_hcd *usb_hcd; - struct wusbhc *wusbhc; - struct hwahc *hwahc; - struct device *dev = &usb_iface->dev; - - result = -ENOMEM; - usb_hcd = usb_create_hcd(&hwahc_hc_driver, &usb_iface->dev, "wusb-hwa"); - if (usb_hcd == NULL) { - dev_err(dev, "unable to allocate instance\n"); - goto error_alloc; - } - usb_hcd->wireless = 1; - wusbhc = usb_hcd_to_wusbhc(usb_hcd); - hwahc = container_of(wusbhc, struct hwahc, wusbhc); - hwahc_init(hwahc); - result = hwahc_create(hwahc, usb_iface); - if (result < 0) { - dev_err(dev, "Cannot initialize internals: %d\n", result); - goto error_hwahc_create; - } - result = usb_add_hcd(usb_hcd, 0, 0); - if (result < 0) { - dev_err(dev, "Cannot add HCD: %d\n", result); - goto error_add_hcd; - } - result = wusbhc_b_create(&hwahc->wusbhc); - if (result < 0) { - dev_err(dev, "Cannot setup phase B of WUSBHC: %d\n", result); - goto error_wusbhc_b_create; - } - return 0; - -error_wusbhc_b_create: - usb_remove_hcd(usb_hcd); -error_add_hcd: - hwahc_destroy(hwahc); -error_hwahc_create: - usb_put_hcd(usb_hcd); -error_alloc: - return result; -} - -static void hwahc_disconnect(struct usb_interface *usb_iface) -{ - struct usb_hcd *usb_hcd; - struct wusbhc *wusbhc; - struct hwahc *hwahc; - - usb_hcd = usb_get_intfdata(usb_iface); - wusbhc = usb_hcd_to_wusbhc(usb_hcd); - hwahc = container_of(wusbhc, struct hwahc, wusbhc); - - wusbhc_b_destroy(&hwahc->wusbhc); - usb_remove_hcd(usb_hcd); - hwahc_destroy(hwahc); - usb_put_hcd(usb_hcd); -} - -static struct usb_device_id hwahc_id_table[] = { - /* FIXME: use class labels for this */ - { USB_INTERFACE_INFO(0xe0, 0x02, 0x01), }, - {}, -}; -MODULE_DEVICE_TABLE(usb, hwahc_id_table); - -static struct usb_driver hwahc_driver = { - .name = "hwa-hc", - .probe = hwahc_probe, - .disconnect = hwahc_disconnect, - .id_table = hwahc_id_table, -}; - -module_usb_driver(hwahc_driver); - -MODULE_AUTHOR("Inaky Perez-Gonzalez "); -MODULE_DESCRIPTION("Host Wired Adapter USB Host Control Driver"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/host/imx21-dbg.c b/ANDROID_3.4.5/drivers/usb/host/imx21-dbg.c deleted file mode 100644 index ec98ecee..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/imx21-dbg.c +++ /dev/null @@ -1,527 +0,0 @@ -/* - * Copyright (c) 2009 by Martin Fuzzey - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* this file is part of imx21-hcd.c */ - -#ifndef DEBUG - -static inline void create_debug_files(struct imx21 *imx21) { } -static inline void remove_debug_files(struct imx21 *imx21) { } -static inline void debug_urb_submitted(struct imx21 *imx21, struct urb *urb) {} -static inline void debug_urb_completed(struct imx21 *imx21, struct urb *urb, - int status) {} -static inline void debug_urb_unlinked(struct imx21 *imx21, struct urb *urb) {} -static inline void debug_urb_queued_for_etd(struct imx21 *imx21, - struct urb *urb) {} -static inline void debug_urb_queued_for_dmem(struct imx21 *imx21, - struct urb *urb) {} -static inline void debug_etd_allocated(struct imx21 *imx21) {} -static inline void debug_etd_freed(struct imx21 *imx21) {} -static inline void debug_dmem_allocated(struct imx21 *imx21, int size) {} -static inline void debug_dmem_freed(struct imx21 *imx21, int size) {} -static inline void debug_isoc_submitted(struct imx21 *imx21, - int frame, struct td *td) {} -static inline void debug_isoc_completed(struct imx21 *imx21, - int frame, struct td *td, int cc, int len) {} - -#else - -#include -#include - -static const char *dir_labels[] = { - "TD 0", - "OUT", - "IN", - "TD 1" -}; - -static const char *speed_labels[] = { - "Full", - "Low" -}; - -static const char *format_labels[] = { - "Control", - "ISO", - "Bulk", - "Interrupt" -}; - -static inline struct debug_stats *stats_for_urb(struct imx21 *imx21, - struct urb *urb) -{ - return usb_pipeisoc(urb->pipe) ? - &imx21->isoc_stats : &imx21->nonisoc_stats; -} - -static void debug_urb_submitted(struct imx21 *imx21, struct urb *urb) -{ - stats_for_urb(imx21, urb)->submitted++; -} - -static void debug_urb_completed(struct imx21 *imx21, struct urb *urb, int st) -{ - if (st) - stats_for_urb(imx21, urb)->completed_failed++; - else - stats_for_urb(imx21, urb)->completed_ok++; -} - -static void debug_urb_unlinked(struct imx21 *imx21, struct urb *urb) -{ - stats_for_urb(imx21, urb)->unlinked++; -} - -static void debug_urb_queued_for_etd(struct imx21 *imx21, struct urb *urb) -{ - stats_for_urb(imx21, urb)->queue_etd++; -} - -static void debug_urb_queued_for_dmem(struct imx21 *imx21, struct urb *urb) -{ - stats_for_urb(imx21, urb)->queue_dmem++; -} - -static inline void debug_etd_allocated(struct imx21 *imx21) -{ - imx21->etd_usage.maximum = max( - ++(imx21->etd_usage.value), - imx21->etd_usage.maximum); -} - -static inline void debug_etd_freed(struct imx21 *imx21) -{ - imx21->etd_usage.value--; -} - -static inline void debug_dmem_allocated(struct imx21 *imx21, int size) -{ - imx21->dmem_usage.value += size; - imx21->dmem_usage.maximum = max( - imx21->dmem_usage.value, - imx21->dmem_usage.maximum); -} - -static inline void debug_dmem_freed(struct imx21 *imx21, int size) -{ - imx21->dmem_usage.value -= size; -} - - -static void debug_isoc_submitted(struct imx21 *imx21, - int frame, struct td *td) -{ - struct debug_isoc_trace *trace = &imx21->isoc_trace[ - imx21->isoc_trace_index++]; - - imx21->isoc_trace_index %= ARRAY_SIZE(imx21->isoc_trace); - trace->schedule_frame = td->frame; - trace->submit_frame = frame; - trace->request_len = td->len; - trace->td = td; -} - -static inline void debug_isoc_completed(struct imx21 *imx21, - int frame, struct td *td, int cc, int len) -{ - struct debug_isoc_trace *trace, *trace_failed; - int i; - int found = 0; - - trace = imx21->isoc_trace; - for (i = 0; i < ARRAY_SIZE(imx21->isoc_trace); i++, trace++) { - if (trace->td == td) { - trace->done_frame = frame; - trace->done_len = len; - trace->cc = cc; - trace->td = NULL; - found = 1; - break; - } - } - - if (found && cc) { - trace_failed = &imx21->isoc_trace_failed[ - imx21->isoc_trace_index_failed++]; - - imx21->isoc_trace_index_failed %= ARRAY_SIZE( - imx21->isoc_trace_failed); - *trace_failed = *trace; - } -} - - -static char *format_ep(struct usb_host_endpoint *ep, char *buf, int bufsize) -{ - if (ep) - snprintf(buf, bufsize, "ep_%02x (type:%02X kaddr:%p)", - ep->desc.bEndpointAddress, - usb_endpoint_type(&ep->desc), - ep); - else - snprintf(buf, bufsize, "none"); - return buf; -} - -static char *format_etd_dword0(u32 value, char *buf, int bufsize) -{ - snprintf(buf, bufsize, - "addr=%d ep=%d dir=%s speed=%s format=%s halted=%d", - value & 0x7F, - (value >> DW0_ENDPNT) & 0x0F, - dir_labels[(value >> DW0_DIRECT) & 0x03], - speed_labels[(value >> DW0_SPEED) & 0x01], - format_labels[(value >> DW0_FORMAT) & 0x03], - (value >> DW0_HALTED) & 0x01); - return buf; -} - -static int debug_status_show(struct seq_file *s, void *v) -{ - struct imx21 *imx21 = s->private; - int etds_allocated = 0; - int etds_sw_busy = 0; - int etds_hw_busy = 0; - int dmem_blocks = 0; - int queued_for_etd = 0; - int queued_for_dmem = 0; - unsigned int dmem_bytes = 0; - int i; - struct etd_priv *etd; - u32 etd_enable_mask; - unsigned long flags; - struct imx21_dmem_area *dmem; - struct ep_priv *ep_priv; - - spin_lock_irqsave(&imx21->lock, flags); - - etd_enable_mask = readl(imx21->regs + USBH_ETDENSET); - for (i = 0, etd = imx21->etd; i < USB_NUM_ETD; i++, etd++) { - if (etd->alloc) - etds_allocated++; - if (etd->urb) - etds_sw_busy++; - if (etd_enable_mask & (1<dmem_list, list) { - dmem_bytes += dmem->size; - dmem_blocks++; - } - - list_for_each_entry(ep_priv, &imx21->queue_for_etd, queue) - queued_for_etd++; - - list_for_each_entry(etd, &imx21->queue_for_dmem, queue) - queued_for_dmem++; - - spin_unlock_irqrestore(&imx21->lock, flags); - - seq_printf(s, - "Frame: %d\n" - "ETDs allocated: %d/%d (max=%d)\n" - "ETDs in use sw: %d\n" - "ETDs in use hw: %d\n" - "DMEM allocated: %d/%d (max=%d)\n" - "DMEM blocks: %d\n" - "Queued waiting for ETD: %d\n" - "Queued waiting for DMEM: %d\n", - readl(imx21->regs + USBH_FRMNUB) & 0xFFFF, - etds_allocated, USB_NUM_ETD, imx21->etd_usage.maximum, - etds_sw_busy, - etds_hw_busy, - dmem_bytes, DMEM_SIZE, imx21->dmem_usage.maximum, - dmem_blocks, - queued_for_etd, - queued_for_dmem); - - return 0; -} - -static int debug_dmem_show(struct seq_file *s, void *v) -{ - struct imx21 *imx21 = s->private; - struct imx21_dmem_area *dmem; - unsigned long flags; - char ep_text[40]; - - spin_lock_irqsave(&imx21->lock, flags); - - list_for_each_entry(dmem, &imx21->dmem_list, list) - seq_printf(s, - "%04X: size=0x%X " - "ep=%s\n", - dmem->offset, dmem->size, - format_ep(dmem->ep, ep_text, sizeof(ep_text))); - - spin_unlock_irqrestore(&imx21->lock, flags); - - return 0; -} - -static int debug_etd_show(struct seq_file *s, void *v) -{ - struct imx21 *imx21 = s->private; - struct etd_priv *etd; - char buf[60]; - u32 dword; - int i, j; - unsigned long flags; - - spin_lock_irqsave(&imx21->lock, flags); - - for (i = 0, etd = imx21->etd; i < USB_NUM_ETD; i++, etd++) { - int state = -1; - struct urb_priv *urb_priv; - if (etd->urb) { - urb_priv = etd->urb->hcpriv; - if (urb_priv) - state = urb_priv->state; - } - - seq_printf(s, - "etd_num: %d\n" - "ep: %s\n" - "alloc: %d\n" - "len: %d\n" - "busy sw: %d\n" - "busy hw: %d\n" - "urb state: %d\n" - "current urb: %p\n", - - i, - format_ep(etd->ep, buf, sizeof(buf)), - etd->alloc, - etd->len, - etd->urb != NULL, - (readl(imx21->regs + USBH_ETDENSET) & (1 << i)) > 0, - state, - etd->urb); - - for (j = 0; j < 4; j++) { - dword = etd_readl(imx21, i, j); - switch (j) { - case 0: - format_etd_dword0(dword, buf, sizeof(buf)); - break; - case 2: - snprintf(buf, sizeof(buf), - "cc=0X%02X", dword >> DW2_COMPCODE); - break; - default: - *buf = 0; - break; - } - seq_printf(s, - "dword %d: submitted=%08X cur=%08X [%s]\n", - j, - etd->submitted_dwords[j], - dword, - buf); - } - seq_printf(s, "\n"); - } - - spin_unlock_irqrestore(&imx21->lock, flags); - - return 0; -} - -static void debug_statistics_show_one(struct seq_file *s, - const char *name, struct debug_stats *stats) -{ - seq_printf(s, "%s:\n" - "submitted URBs: %lu\n" - "completed OK: %lu\n" - "completed failed: %lu\n" - "unlinked: %lu\n" - "queued for ETD: %lu\n" - "queued for DMEM: %lu\n\n", - name, - stats->submitted, - stats->completed_ok, - stats->completed_failed, - stats->unlinked, - stats->queue_etd, - stats->queue_dmem); -} - -static int debug_statistics_show(struct seq_file *s, void *v) -{ - struct imx21 *imx21 = s->private; - unsigned long flags; - - spin_lock_irqsave(&imx21->lock, flags); - - debug_statistics_show_one(s, "nonisoc", &imx21->nonisoc_stats); - debug_statistics_show_one(s, "isoc", &imx21->isoc_stats); - seq_printf(s, "unblock kludge triggers: %lu\n", imx21->debug_unblocks); - spin_unlock_irqrestore(&imx21->lock, flags); - - return 0; -} - -static void debug_isoc_show_one(struct seq_file *s, - const char *name, int index, struct debug_isoc_trace *trace) -{ - seq_printf(s, "%s %d:\n" - "cc=0X%02X\n" - "scheduled frame %d (%d)\n" - "submitted frame %d (%d)\n" - "completed frame %d (%d)\n" - "requested length=%d\n" - "completed length=%d\n\n", - name, index, - trace->cc, - trace->schedule_frame, trace->schedule_frame & 0xFFFF, - trace->submit_frame, trace->submit_frame & 0xFFFF, - trace->done_frame, trace->done_frame & 0xFFFF, - trace->request_len, - trace->done_len); -} - -static int debug_isoc_show(struct seq_file *s, void *v) -{ - struct imx21 *imx21 = s->private; - struct debug_isoc_trace *trace; - unsigned long flags; - int i; - - spin_lock_irqsave(&imx21->lock, flags); - - trace = imx21->isoc_trace_failed; - for (i = 0; i < ARRAY_SIZE(imx21->isoc_trace_failed); i++, trace++) - debug_isoc_show_one(s, "isoc failed", i, trace); - - trace = imx21->isoc_trace; - for (i = 0; i < ARRAY_SIZE(imx21->isoc_trace); i++, trace++) - debug_isoc_show_one(s, "isoc", i, trace); - - spin_unlock_irqrestore(&imx21->lock, flags); - - return 0; -} - -static int debug_status_open(struct inode *inode, struct file *file) -{ - return single_open(file, debug_status_show, inode->i_private); -} - -static int debug_dmem_open(struct inode *inode, struct file *file) -{ - return single_open(file, debug_dmem_show, inode->i_private); -} - -static int debug_etd_open(struct inode *inode, struct file *file) -{ - return single_open(file, debug_etd_show, inode->i_private); -} - -static int debug_statistics_open(struct inode *inode, struct file *file) -{ - return single_open(file, debug_statistics_show, inode->i_private); -} - -static int debug_isoc_open(struct inode *inode, struct file *file) -{ - return single_open(file, debug_isoc_show, inode->i_private); -} - -static const struct file_operations debug_status_fops = { - .open = debug_status_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations debug_dmem_fops = { - .open = debug_dmem_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations debug_etd_fops = { - .open = debug_etd_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations debug_statistics_fops = { - .open = debug_statistics_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations debug_isoc_fops = { - .open = debug_isoc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static void create_debug_files(struct imx21 *imx21) -{ - imx21->debug_root = debugfs_create_dir(dev_name(imx21->dev), NULL); - if (!imx21->debug_root) - goto failed_create_rootdir; - - if (!debugfs_create_file("status", S_IRUGO, - imx21->debug_root, imx21, &debug_status_fops)) - goto failed_create; - - if (!debugfs_create_file("dmem", S_IRUGO, - imx21->debug_root, imx21, &debug_dmem_fops)) - goto failed_create; - - if (!debugfs_create_file("etd", S_IRUGO, - imx21->debug_root, imx21, &debug_etd_fops)) - goto failed_create; - - if (!debugfs_create_file("statistics", S_IRUGO, - imx21->debug_root, imx21, &debug_statistics_fops)) - goto failed_create; - - if (!debugfs_create_file("isoc", S_IRUGO, - imx21->debug_root, imx21, &debug_isoc_fops)) - goto failed_create; - - return; - -failed_create: - debugfs_remove_recursive(imx21->debug_root); - -failed_create_rootdir: - imx21->debug_root = NULL; -} - - -static void remove_debug_files(struct imx21 *imx21) -{ - if (imx21->debug_root) { - debugfs_remove_recursive(imx21->debug_root); - imx21->debug_root = NULL; - } -} - -#endif - diff --git a/ANDROID_3.4.5/drivers/usb/host/imx21-hcd.c b/ANDROID_3.4.5/drivers/usb/host/imx21-hcd.c deleted file mode 100644 index ff471c1c..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/imx21-hcd.c +++ /dev/null @@ -1,1932 +0,0 @@ -/* - * USB Host Controller Driver for IMX21 - * - * Copyright (C) 2006 Loping Dog Embedded Systems - * Copyright (C) 2009 Martin Fuzzey - * Originally written by Jay Monkman - * Ported to 2.6.30, debugged and enhanced by Martin Fuzzey - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - - /* - * The i.MX21 USB hardware contains - * * 32 transfer descriptors (called ETDs) - * * 4Kb of Data memory - * - * The data memory is shared between the host and function controllers - * (but this driver only supports the host controller) - * - * So setting up a transfer involves: - * * Allocating a ETD - * * Fill in ETD with appropriate information - * * Allocating data memory (and putting the offset in the ETD) - * * Activate the ETD - * * Get interrupt when done. - * - * An ETD is assigned to each active endpoint. - * - * Low resource (ETD and Data memory) situations are handled differently for - * isochronous and non insosynchronous transactions : - * - * Non ISOC transfers are queued if either ETDs or Data memory are unavailable - * - * ISOC transfers use 2 ETDs per endpoint to achieve double buffering. - * They allocate both ETDs and Data memory during URB submission - * (and fail if unavailable). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "imx21-hcd.h" - -#ifdef DEBUG -#define DEBUG_LOG_FRAME(imx21, etd, event) \ - (etd)->event##_frame = readl((imx21)->regs + USBH_FRMNUB) -#else -#define DEBUG_LOG_FRAME(imx21, etd, event) do { } while (0) -#endif - -static const char hcd_name[] = "imx21-hcd"; - -static inline struct imx21 *hcd_to_imx21(struct usb_hcd *hcd) -{ - return (struct imx21 *)hcd->hcd_priv; -} - - -/* =========================================== */ -/* Hardware access helpers */ -/* =========================================== */ - -static inline void set_register_bits(struct imx21 *imx21, u32 offset, u32 mask) -{ - void __iomem *reg = imx21->regs + offset; - writel(readl(reg) | mask, reg); -} - -static inline void clear_register_bits(struct imx21 *imx21, - u32 offset, u32 mask) -{ - void __iomem *reg = imx21->regs + offset; - writel(readl(reg) & ~mask, reg); -} - -static inline void clear_toggle_bit(struct imx21 *imx21, u32 offset, u32 mask) -{ - void __iomem *reg = imx21->regs + offset; - - if (readl(reg) & mask) - writel(mask, reg); -} - -static inline void set_toggle_bit(struct imx21 *imx21, u32 offset, u32 mask) -{ - void __iomem *reg = imx21->regs + offset; - - if (!(readl(reg) & mask)) - writel(mask, reg); -} - -static void etd_writel(struct imx21 *imx21, int etd_num, int dword, u32 value) -{ - writel(value, imx21->regs + USB_ETD_DWORD(etd_num, dword)); -} - -static u32 etd_readl(struct imx21 *imx21, int etd_num, int dword) -{ - return readl(imx21->regs + USB_ETD_DWORD(etd_num, dword)); -} - -static inline int wrap_frame(int counter) -{ - return counter & 0xFFFF; -} - -static inline int frame_after(int frame, int after) -{ - /* handle wrapping like jiffies time_afer */ - return (s16)((s16)after - (s16)frame) < 0; -} - -static int imx21_hc_get_frame(struct usb_hcd *hcd) -{ - struct imx21 *imx21 = hcd_to_imx21(hcd); - - return wrap_frame(readl(imx21->regs + USBH_FRMNUB)); -} - -static inline bool unsuitable_for_dma(dma_addr_t addr) -{ - return (addr & 3) != 0; -} - -#include "imx21-dbg.c" - -static void nonisoc_urb_completed_for_etd( - struct imx21 *imx21, struct etd_priv *etd, int status); -static void schedule_nonisoc_etd(struct imx21 *imx21, struct urb *urb); -static void free_dmem(struct imx21 *imx21, struct etd_priv *etd); - -/* =========================================== */ -/* ETD management */ -/* =========================================== */ - -static int alloc_etd(struct imx21 *imx21) -{ - int i; - struct etd_priv *etd = imx21->etd; - - for (i = 0; i < USB_NUM_ETD; i++, etd++) { - if (etd->alloc == 0) { - memset(etd, 0, sizeof(imx21->etd[0])); - etd->alloc = 1; - debug_etd_allocated(imx21); - return i; - } - } - return -1; -} - -static void disactivate_etd(struct imx21 *imx21, int num) -{ - int etd_mask = (1 << num); - struct etd_priv *etd = &imx21->etd[num]; - - writel(etd_mask, imx21->regs + USBH_ETDENCLR); - clear_register_bits(imx21, USBH_ETDDONEEN, etd_mask); - writel(etd_mask, imx21->regs + USB_ETDDMACHANLCLR); - clear_toggle_bit(imx21, USBH_ETDDONESTAT, etd_mask); - - etd->active_count = 0; - - DEBUG_LOG_FRAME(imx21, etd, disactivated); -} - -static void reset_etd(struct imx21 *imx21, int num) -{ - struct etd_priv *etd = imx21->etd + num; - int i; - - disactivate_etd(imx21, num); - - for (i = 0; i < 4; i++) - etd_writel(imx21, num, i, 0); - etd->urb = NULL; - etd->ep = NULL; - etd->td = NULL; - etd->bounce_buffer = NULL; -} - -static void free_etd(struct imx21 *imx21, int num) -{ - if (num < 0) - return; - - if (num >= USB_NUM_ETD) { - dev_err(imx21->dev, "BAD etd=%d!\n", num); - return; - } - if (imx21->etd[num].alloc == 0) { - dev_err(imx21->dev, "ETD %d already free!\n", num); - return; - } - - debug_etd_freed(imx21); - reset_etd(imx21, num); - memset(&imx21->etd[num], 0, sizeof(imx21->etd[0])); -} - - -static void setup_etd_dword0(struct imx21 *imx21, - int etd_num, struct urb *urb, u8 dir, u16 maxpacket) -{ - etd_writel(imx21, etd_num, 0, - ((u32) usb_pipedevice(urb->pipe)) << DW0_ADDRESS | - ((u32) usb_pipeendpoint(urb->pipe) << DW0_ENDPNT) | - ((u32) dir << DW0_DIRECT) | - ((u32) ((urb->dev->speed == USB_SPEED_LOW) ? - 1 : 0) << DW0_SPEED) | - ((u32) fmt_urb_to_etd[usb_pipetype(urb->pipe)] << DW0_FORMAT) | - ((u32) maxpacket << DW0_MAXPKTSIZ)); -} - -/** - * Copy buffer to data controller data memory. - * We cannot use memcpy_toio() because the hardware requires 32bit writes - */ -static void copy_to_dmem( - struct imx21 *imx21, int dmem_offset, void *src, int count) -{ - void __iomem *dmem = imx21->regs + USBOTG_DMEM + dmem_offset; - u32 word = 0; - u8 *p = src; - int byte = 0; - int i; - - for (i = 0; i < count; i++) { - byte = i % 4; - word += (*p++ << (byte * 8)); - if (byte == 3) { - writel(word, dmem); - dmem += 4; - word = 0; - } - } - - if (count && byte != 3) - writel(word, dmem); -} - -static void activate_etd(struct imx21 *imx21, int etd_num, u8 dir) -{ - u32 etd_mask = 1 << etd_num; - struct etd_priv *etd = &imx21->etd[etd_num]; - - if (etd->dma_handle && unsuitable_for_dma(etd->dma_handle)) { - /* For non aligned isoc the condition below is always true */ - if (etd->len <= etd->dmem_size) { - /* Fits into data memory, use PIO */ - if (dir != TD_DIR_IN) { - copy_to_dmem(imx21, - etd->dmem_offset, - etd->cpu_buffer, etd->len); - } - etd->dma_handle = 0; - - } else { - /* Too big for data memory, use bounce buffer */ - enum dma_data_direction dmadir; - - if (dir == TD_DIR_IN) { - dmadir = DMA_FROM_DEVICE; - etd->bounce_buffer = kmalloc(etd->len, - GFP_ATOMIC); - } else { - dmadir = DMA_TO_DEVICE; - etd->bounce_buffer = kmemdup(etd->cpu_buffer, - etd->len, - GFP_ATOMIC); - } - if (!etd->bounce_buffer) { - dev_err(imx21->dev, "failed bounce alloc\n"); - goto err_bounce_alloc; - } - - etd->dma_handle = - dma_map_single(imx21->dev, - etd->bounce_buffer, - etd->len, - dmadir); - if (dma_mapping_error(imx21->dev, etd->dma_handle)) { - dev_err(imx21->dev, "failed bounce map\n"); - goto err_bounce_map; - } - } - } - - clear_toggle_bit(imx21, USBH_ETDDONESTAT, etd_mask); - set_register_bits(imx21, USBH_ETDDONEEN, etd_mask); - clear_toggle_bit(imx21, USBH_XFILLSTAT, etd_mask); - clear_toggle_bit(imx21, USBH_YFILLSTAT, etd_mask); - - if (etd->dma_handle) { - set_register_bits(imx21, USB_ETDDMACHANLCLR, etd_mask); - clear_toggle_bit(imx21, USBH_XBUFSTAT, etd_mask); - clear_toggle_bit(imx21, USBH_YBUFSTAT, etd_mask); - writel(etd->dma_handle, imx21->regs + USB_ETDSMSA(etd_num)); - set_register_bits(imx21, USB_ETDDMAEN, etd_mask); - } else { - if (dir != TD_DIR_IN) { - /* need to set for ZLP and PIO */ - set_toggle_bit(imx21, USBH_XFILLSTAT, etd_mask); - set_toggle_bit(imx21, USBH_YFILLSTAT, etd_mask); - } - } - - DEBUG_LOG_FRAME(imx21, etd, activated); - -#ifdef DEBUG - if (!etd->active_count) { - int i; - etd->activated_frame = readl(imx21->regs + USBH_FRMNUB); - etd->disactivated_frame = -1; - etd->last_int_frame = -1; - etd->last_req_frame = -1; - - for (i = 0; i < 4; i++) - etd->submitted_dwords[i] = etd_readl(imx21, etd_num, i); - } -#endif - - etd->active_count = 1; - writel(etd_mask, imx21->regs + USBH_ETDENSET); - return; - -err_bounce_map: - kfree(etd->bounce_buffer); - -err_bounce_alloc: - free_dmem(imx21, etd); - nonisoc_urb_completed_for_etd(imx21, etd, -ENOMEM); -} - -/* =========================================== */ -/* Data memory management */ -/* =========================================== */ - -static int alloc_dmem(struct imx21 *imx21, unsigned int size, - struct usb_host_endpoint *ep) -{ - unsigned int offset = 0; - struct imx21_dmem_area *area; - struct imx21_dmem_area *tmp; - - size += (~size + 1) & 0x3; /* Round to 4 byte multiple */ - - if (size > DMEM_SIZE) { - dev_err(imx21->dev, "size=%d > DMEM_SIZE(%d)\n", - size, DMEM_SIZE); - return -EINVAL; - } - - list_for_each_entry(tmp, &imx21->dmem_list, list) { - if ((size + offset) < offset) - goto fail; - if ((size + offset) <= tmp->offset) - break; - offset = tmp->size + tmp->offset; - if ((offset + size) > DMEM_SIZE) - goto fail; - } - - area = kmalloc(sizeof(struct imx21_dmem_area), GFP_ATOMIC); - if (area == NULL) - return -ENOMEM; - - area->ep = ep; - area->offset = offset; - area->size = size; - list_add_tail(&area->list, &tmp->list); - debug_dmem_allocated(imx21, size); - return offset; - -fail: - return -ENOMEM; -} - -/* Memory now available for a queued ETD - activate it */ -static void activate_queued_etd(struct imx21 *imx21, - struct etd_priv *etd, u32 dmem_offset) -{ - struct urb_priv *urb_priv = etd->urb->hcpriv; - int etd_num = etd - &imx21->etd[0]; - u32 maxpacket = etd_readl(imx21, etd_num, 1) >> DW1_YBUFSRTAD; - u8 dir = (etd_readl(imx21, etd_num, 2) >> DW2_DIRPID) & 0x03; - - dev_dbg(imx21->dev, "activating queued ETD %d now DMEM available\n", - etd_num); - etd_writel(imx21, etd_num, 1, - ((dmem_offset + maxpacket) << DW1_YBUFSRTAD) | dmem_offset); - - etd->dmem_offset = dmem_offset; - urb_priv->active = 1; - activate_etd(imx21, etd_num, dir); -} - -static void free_dmem(struct imx21 *imx21, struct etd_priv *etd) -{ - struct imx21_dmem_area *area; - struct etd_priv *tmp; - int found = 0; - int offset; - - if (!etd->dmem_size) - return; - etd->dmem_size = 0; - - offset = etd->dmem_offset; - list_for_each_entry(area, &imx21->dmem_list, list) { - if (area->offset == offset) { - debug_dmem_freed(imx21, area->size); - list_del(&area->list); - kfree(area); - found = 1; - break; - } - } - - if (!found) { - dev_err(imx21->dev, - "Trying to free unallocated DMEM %d\n", offset); - return; - } - - /* Try again to allocate memory for anything we've queued */ - list_for_each_entry_safe(etd, tmp, &imx21->queue_for_dmem, queue) { - offset = alloc_dmem(imx21, etd->dmem_size, etd->ep); - if (offset >= 0) { - list_del(&etd->queue); - activate_queued_etd(imx21, etd, (u32)offset); - } - } -} - -static void free_epdmem(struct imx21 *imx21, struct usb_host_endpoint *ep) -{ - struct imx21_dmem_area *area, *tmp; - - list_for_each_entry_safe(area, tmp, &imx21->dmem_list, list) { - if (area->ep == ep) { - dev_err(imx21->dev, - "Active DMEM %d for disabled ep=%p\n", - area->offset, ep); - list_del(&area->list); - kfree(area); - } - } -} - - -/* =========================================== */ -/* End handling */ -/* =========================================== */ - -/* Endpoint now idle - release its ETD(s) or assign to queued request */ -static void ep_idle(struct imx21 *imx21, struct ep_priv *ep_priv) -{ - int i; - - for (i = 0; i < NUM_ISO_ETDS; i++) { - int etd_num = ep_priv->etd[i]; - struct etd_priv *etd; - if (etd_num < 0) - continue; - - etd = &imx21->etd[etd_num]; - ep_priv->etd[i] = -1; - - free_dmem(imx21, etd); /* for isoc */ - - if (list_empty(&imx21->queue_for_etd)) { - free_etd(imx21, etd_num); - continue; - } - - dev_dbg(imx21->dev, - "assigning idle etd %d for queued request\n", etd_num); - ep_priv = list_first_entry(&imx21->queue_for_etd, - struct ep_priv, queue); - list_del(&ep_priv->queue); - reset_etd(imx21, etd_num); - ep_priv->waiting_etd = 0; - ep_priv->etd[i] = etd_num; - - if (list_empty(&ep_priv->ep->urb_list)) { - dev_err(imx21->dev, "No urb for queued ep!\n"); - continue; - } - schedule_nonisoc_etd(imx21, list_first_entry( - &ep_priv->ep->urb_list, struct urb, urb_list)); - } -} - -static void urb_done(struct usb_hcd *hcd, struct urb *urb, int status) -__releases(imx21->lock) -__acquires(imx21->lock) -{ - struct imx21 *imx21 = hcd_to_imx21(hcd); - struct ep_priv *ep_priv = urb->ep->hcpriv; - struct urb_priv *urb_priv = urb->hcpriv; - - debug_urb_completed(imx21, urb, status); - dev_vdbg(imx21->dev, "urb %p done %d\n", urb, status); - - kfree(urb_priv->isoc_td); - kfree(urb->hcpriv); - urb->hcpriv = NULL; - usb_hcd_unlink_urb_from_ep(hcd, urb); - spin_unlock(&imx21->lock); - usb_hcd_giveback_urb(hcd, urb, status); - spin_lock(&imx21->lock); - if (list_empty(&ep_priv->ep->urb_list)) - ep_idle(imx21, ep_priv); -} - -static void nonisoc_urb_completed_for_etd( - struct imx21 *imx21, struct etd_priv *etd, int status) -{ - struct usb_host_endpoint *ep = etd->ep; - - urb_done(imx21->hcd, etd->urb, status); - etd->urb = NULL; - - if (!list_empty(&ep->urb_list)) { - struct urb *urb = list_first_entry( - &ep->urb_list, struct urb, urb_list); - - dev_vdbg(imx21->dev, "next URB %p\n", urb); - schedule_nonisoc_etd(imx21, urb); - } -} - - -/* =========================================== */ -/* ISOC Handling ... */ -/* =========================================== */ - -static void schedule_isoc_etds(struct usb_hcd *hcd, - struct usb_host_endpoint *ep) -{ - struct imx21 *imx21 = hcd_to_imx21(hcd); - struct ep_priv *ep_priv = ep->hcpriv; - struct etd_priv *etd; - struct urb_priv *urb_priv; - struct td *td; - int etd_num; - int i; - int cur_frame; - u8 dir; - - for (i = 0; i < NUM_ISO_ETDS; i++) { -too_late: - if (list_empty(&ep_priv->td_list)) - break; - - etd_num = ep_priv->etd[i]; - if (etd_num < 0) - break; - - etd = &imx21->etd[etd_num]; - if (etd->urb) - continue; - - td = list_entry(ep_priv->td_list.next, struct td, list); - list_del(&td->list); - urb_priv = td->urb->hcpriv; - - cur_frame = imx21_hc_get_frame(hcd); - if (frame_after(cur_frame, td->frame)) { - dev_dbg(imx21->dev, "isoc too late frame %d > %d\n", - cur_frame, td->frame); - urb_priv->isoc_status = -EXDEV; - td->urb->iso_frame_desc[ - td->isoc_index].actual_length = 0; - td->urb->iso_frame_desc[td->isoc_index].status = -EXDEV; - if (--urb_priv->isoc_remaining == 0) - urb_done(hcd, td->urb, urb_priv->isoc_status); - goto too_late; - } - - urb_priv->active = 1; - etd->td = td; - etd->ep = td->ep; - etd->urb = td->urb; - etd->len = td->len; - etd->dma_handle = td->dma_handle; - etd->cpu_buffer = td->cpu_buffer; - - debug_isoc_submitted(imx21, cur_frame, td); - - dir = usb_pipeout(td->urb->pipe) ? TD_DIR_OUT : TD_DIR_IN; - setup_etd_dword0(imx21, etd_num, td->urb, dir, etd->dmem_size); - etd_writel(imx21, etd_num, 1, etd->dmem_offset); - etd_writel(imx21, etd_num, 2, - (TD_NOTACCESSED << DW2_COMPCODE) | - ((td->frame & 0xFFFF) << DW2_STARTFRM)); - etd_writel(imx21, etd_num, 3, - (TD_NOTACCESSED << DW3_COMPCODE0) | - (td->len << DW3_PKTLEN0)); - - activate_etd(imx21, etd_num, dir); - } -} - -static void isoc_etd_done(struct usb_hcd *hcd, int etd_num) -{ - struct imx21 *imx21 = hcd_to_imx21(hcd); - int etd_mask = 1 << etd_num; - struct etd_priv *etd = imx21->etd + etd_num; - struct urb *urb = etd->urb; - struct urb_priv *urb_priv = urb->hcpriv; - struct td *td = etd->td; - struct usb_host_endpoint *ep = etd->ep; - int isoc_index = td->isoc_index; - unsigned int pipe = urb->pipe; - int dir_in = usb_pipein(pipe); - int cc; - int bytes_xfrd; - - disactivate_etd(imx21, etd_num); - - cc = (etd_readl(imx21, etd_num, 3) >> DW3_COMPCODE0) & 0xf; - bytes_xfrd = etd_readl(imx21, etd_num, 3) & 0x3ff; - - /* Input doesn't always fill the buffer, don't generate an error - * when this happens. - */ - if (dir_in && (cc == TD_DATAUNDERRUN)) - cc = TD_CC_NOERROR; - - if (cc == TD_NOTACCESSED) - bytes_xfrd = 0; - - debug_isoc_completed(imx21, - imx21_hc_get_frame(hcd), td, cc, bytes_xfrd); - if (cc) { - urb_priv->isoc_status = -EXDEV; - dev_dbg(imx21->dev, - "bad iso cc=0x%X frame=%d sched frame=%d " - "cnt=%d len=%d urb=%p etd=%d index=%d\n", - cc, imx21_hc_get_frame(hcd), td->frame, - bytes_xfrd, td->len, urb, etd_num, isoc_index); - } - - if (dir_in) { - clear_toggle_bit(imx21, USBH_XFILLSTAT, etd_mask); - if (!etd->dma_handle) - memcpy_fromio(etd->cpu_buffer, - imx21->regs + USBOTG_DMEM + etd->dmem_offset, - bytes_xfrd); - } - - urb->actual_length += bytes_xfrd; - urb->iso_frame_desc[isoc_index].actual_length = bytes_xfrd; - urb->iso_frame_desc[isoc_index].status = cc_to_error[cc]; - - etd->td = NULL; - etd->urb = NULL; - etd->ep = NULL; - - if (--urb_priv->isoc_remaining == 0) - urb_done(hcd, urb, urb_priv->isoc_status); - - schedule_isoc_etds(hcd, ep); -} - -static struct ep_priv *alloc_isoc_ep( - struct imx21 *imx21, struct usb_host_endpoint *ep) -{ - struct ep_priv *ep_priv; - int i; - - ep_priv = kzalloc(sizeof(struct ep_priv), GFP_ATOMIC); - if (!ep_priv) - return NULL; - - for (i = 0; i < NUM_ISO_ETDS; i++) - ep_priv->etd[i] = -1; - - INIT_LIST_HEAD(&ep_priv->td_list); - ep_priv->ep = ep; - ep->hcpriv = ep_priv; - return ep_priv; -} - -static int alloc_isoc_etds(struct imx21 *imx21, struct ep_priv *ep_priv) -{ - int i, j; - int etd_num; - - /* Allocate the ETDs if required */ - for (i = 0; i < NUM_ISO_ETDS; i++) { - if (ep_priv->etd[i] < 0) { - etd_num = alloc_etd(imx21); - if (etd_num < 0) - goto alloc_etd_failed; - - ep_priv->etd[i] = etd_num; - imx21->etd[etd_num].ep = ep_priv->ep; - } - } - return 0; - -alloc_etd_failed: - dev_err(imx21->dev, "isoc: Couldn't allocate etd\n"); - for (j = 0; j < i; j++) { - free_etd(imx21, ep_priv->etd[j]); - ep_priv->etd[j] = -1; - } - return -ENOMEM; -} - -static int imx21_hc_urb_enqueue_isoc(struct usb_hcd *hcd, - struct usb_host_endpoint *ep, - struct urb *urb, gfp_t mem_flags) -{ - struct imx21 *imx21 = hcd_to_imx21(hcd); - struct urb_priv *urb_priv; - unsigned long flags; - struct ep_priv *ep_priv; - struct td *td = NULL; - int i; - int ret; - int cur_frame; - u16 maxpacket; - - urb_priv = kzalloc(sizeof(struct urb_priv), mem_flags); - if (urb_priv == NULL) - return -ENOMEM; - - urb_priv->isoc_td = kzalloc( - sizeof(struct td) * urb->number_of_packets, mem_flags); - if (urb_priv->isoc_td == NULL) { - ret = -ENOMEM; - goto alloc_td_failed; - } - - spin_lock_irqsave(&imx21->lock, flags); - - if (ep->hcpriv == NULL) { - ep_priv = alloc_isoc_ep(imx21, ep); - if (ep_priv == NULL) { - ret = -ENOMEM; - goto alloc_ep_failed; - } - } else { - ep_priv = ep->hcpriv; - } - - ret = alloc_isoc_etds(imx21, ep_priv); - if (ret) - goto alloc_etd_failed; - - ret = usb_hcd_link_urb_to_ep(hcd, urb); - if (ret) - goto link_failed; - - urb->status = -EINPROGRESS; - urb->actual_length = 0; - urb->error_count = 0; - urb->hcpriv = urb_priv; - urb_priv->ep = ep; - - /* allocate data memory for largest packets if not already done */ - maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); - for (i = 0; i < NUM_ISO_ETDS; i++) { - struct etd_priv *etd = &imx21->etd[ep_priv->etd[i]]; - - if (etd->dmem_size > 0 && etd->dmem_size < maxpacket) { - /* not sure if this can really occur.... */ - dev_err(imx21->dev, "increasing isoc buffer %d->%d\n", - etd->dmem_size, maxpacket); - ret = -EMSGSIZE; - goto alloc_dmem_failed; - } - - if (etd->dmem_size == 0) { - etd->dmem_offset = alloc_dmem(imx21, maxpacket, ep); - if (etd->dmem_offset < 0) { - dev_dbg(imx21->dev, "failed alloc isoc dmem\n"); - ret = -EAGAIN; - goto alloc_dmem_failed; - } - etd->dmem_size = maxpacket; - } - } - - /* calculate frame */ - cur_frame = imx21_hc_get_frame(hcd); - if (urb->transfer_flags & URB_ISO_ASAP) { - if (list_empty(&ep_priv->td_list)) - urb->start_frame = cur_frame + 5; - else - urb->start_frame = list_entry( - ep_priv->td_list.prev, - struct td, list)->frame + urb->interval; - } - urb->start_frame = wrap_frame(urb->start_frame); - if (frame_after(cur_frame, urb->start_frame)) { - dev_dbg(imx21->dev, - "enqueue: adjusting iso start %d (cur=%d) asap=%d\n", - urb->start_frame, cur_frame, - (urb->transfer_flags & URB_ISO_ASAP) != 0); - urb->start_frame = wrap_frame(cur_frame + 1); - } - - /* set up transfers */ - td = urb_priv->isoc_td; - for (i = 0; i < urb->number_of_packets; i++, td++) { - unsigned int offset = urb->iso_frame_desc[i].offset; - td->ep = ep; - td->urb = urb; - td->len = urb->iso_frame_desc[i].length; - td->isoc_index = i; - td->frame = wrap_frame(urb->start_frame + urb->interval * i); - td->dma_handle = urb->transfer_dma + offset; - td->cpu_buffer = urb->transfer_buffer + offset; - list_add_tail(&td->list, &ep_priv->td_list); - } - - urb_priv->isoc_remaining = urb->number_of_packets; - dev_vdbg(imx21->dev, "setup %d packets for iso frame %d->%d\n", - urb->number_of_packets, urb->start_frame, td->frame); - - debug_urb_submitted(imx21, urb); - schedule_isoc_etds(hcd, ep); - - spin_unlock_irqrestore(&imx21->lock, flags); - return 0; - -alloc_dmem_failed: - usb_hcd_unlink_urb_from_ep(hcd, urb); - -link_failed: -alloc_etd_failed: -alloc_ep_failed: - spin_unlock_irqrestore(&imx21->lock, flags); - kfree(urb_priv->isoc_td); - -alloc_td_failed: - kfree(urb_priv); - return ret; -} - -static void dequeue_isoc_urb(struct imx21 *imx21, - struct urb *urb, struct ep_priv *ep_priv) -{ - struct urb_priv *urb_priv = urb->hcpriv; - struct td *td, *tmp; - int i; - - if (urb_priv->active) { - for (i = 0; i < NUM_ISO_ETDS; i++) { - int etd_num = ep_priv->etd[i]; - if (etd_num != -1 && imx21->etd[etd_num].urb == urb) { - struct etd_priv *etd = imx21->etd + etd_num; - - reset_etd(imx21, etd_num); - free_dmem(imx21, etd); - } - } - } - - list_for_each_entry_safe(td, tmp, &ep_priv->td_list, list) { - if (td->urb == urb) { - dev_vdbg(imx21->dev, "removing td %p\n", td); - list_del(&td->list); - } - } -} - -/* =========================================== */ -/* NON ISOC Handling ... */ -/* =========================================== */ - -static void schedule_nonisoc_etd(struct imx21 *imx21, struct urb *urb) -{ - unsigned int pipe = urb->pipe; - struct urb_priv *urb_priv = urb->hcpriv; - struct ep_priv *ep_priv = urb_priv->ep->hcpriv; - int state = urb_priv->state; - int etd_num = ep_priv->etd[0]; - struct etd_priv *etd; - u32 count; - u16 etd_buf_size; - u16 maxpacket; - u8 dir; - u8 bufround; - u8 datatoggle; - u8 interval = 0; - u8 relpolpos = 0; - - if (etd_num < 0) { - dev_err(imx21->dev, "No valid ETD\n"); - return; - } - if (readl(imx21->regs + USBH_ETDENSET) & (1 << etd_num)) - dev_err(imx21->dev, "submitting to active ETD %d\n", etd_num); - - etd = &imx21->etd[etd_num]; - maxpacket = usb_maxpacket(urb->dev, pipe, usb_pipeout(pipe)); - if (!maxpacket) - maxpacket = 8; - - if (usb_pipecontrol(pipe) && (state != US_CTRL_DATA)) { - if (state == US_CTRL_SETUP) { - dir = TD_DIR_SETUP; - if (unsuitable_for_dma(urb->setup_dma)) - usb_hcd_unmap_urb_setup_for_dma(imx21->hcd, - urb); - etd->dma_handle = urb->setup_dma; - etd->cpu_buffer = urb->setup_packet; - bufround = 0; - count = 8; - datatoggle = TD_TOGGLE_DATA0; - } else { /* US_CTRL_ACK */ - dir = usb_pipeout(pipe) ? TD_DIR_IN : TD_DIR_OUT; - bufround = 0; - count = 0; - datatoggle = TD_TOGGLE_DATA1; - } - } else { - dir = usb_pipeout(pipe) ? TD_DIR_OUT : TD_DIR_IN; - bufround = (dir == TD_DIR_IN) ? 1 : 0; - if (unsuitable_for_dma(urb->transfer_dma)) - usb_hcd_unmap_urb_for_dma(imx21->hcd, urb); - - etd->dma_handle = urb->transfer_dma; - etd->cpu_buffer = urb->transfer_buffer; - if (usb_pipebulk(pipe) && (state == US_BULK0)) - count = 0; - else - count = urb->transfer_buffer_length; - - if (usb_pipecontrol(pipe)) { - datatoggle = TD_TOGGLE_DATA1; - } else { - if (usb_gettoggle( - urb->dev, - usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe))) - datatoggle = TD_TOGGLE_DATA1; - else - datatoggle = TD_TOGGLE_DATA0; - } - } - - etd->urb = urb; - etd->ep = urb_priv->ep; - etd->len = count; - - if (usb_pipeint(pipe)) { - interval = urb->interval; - relpolpos = (readl(imx21->regs + USBH_FRMNUB) + 1) & 0xff; - } - - /* Write ETD to device memory */ - setup_etd_dword0(imx21, etd_num, urb, dir, maxpacket); - - etd_writel(imx21, etd_num, 2, - (u32) interval << DW2_POLINTERV | - ((u32) relpolpos << DW2_RELPOLPOS) | - ((u32) dir << DW2_DIRPID) | - ((u32) bufround << DW2_BUFROUND) | - ((u32) datatoggle << DW2_DATATOG) | - ((u32) TD_NOTACCESSED << DW2_COMPCODE)); - - /* DMA will always transfer buffer size even if TOBYCNT in DWORD3 - is smaller. Make sure we don't overrun the buffer! - */ - if (count && count < maxpacket) - etd_buf_size = count; - else - etd_buf_size = maxpacket; - - etd_writel(imx21, etd_num, 3, - ((u32) (etd_buf_size - 1) << DW3_BUFSIZE) | (u32) count); - - if (!count) - etd->dma_handle = 0; - - /* allocate x and y buffer space at once */ - etd->dmem_size = (count > maxpacket) ? maxpacket * 2 : maxpacket; - etd->dmem_offset = alloc_dmem(imx21, etd->dmem_size, urb_priv->ep); - if (etd->dmem_offset < 0) { - /* Setup everything we can in HW and update when we get DMEM */ - etd_writel(imx21, etd_num, 1, (u32)maxpacket << 16); - - dev_dbg(imx21->dev, "Queuing etd %d for DMEM\n", etd_num); - debug_urb_queued_for_dmem(imx21, urb); - list_add_tail(&etd->queue, &imx21->queue_for_dmem); - return; - } - - etd_writel(imx21, etd_num, 1, - (((u32) etd->dmem_offset + (u32) maxpacket) << DW1_YBUFSRTAD) | - (u32) etd->dmem_offset); - - urb_priv->active = 1; - - /* enable the ETD to kick off transfer */ - dev_vdbg(imx21->dev, "Activating etd %d for %d bytes %s\n", - etd_num, count, dir != TD_DIR_IN ? "out" : "in"); - activate_etd(imx21, etd_num, dir); - -} - -static void nonisoc_etd_done(struct usb_hcd *hcd, int etd_num) -{ - struct imx21 *imx21 = hcd_to_imx21(hcd); - struct etd_priv *etd = &imx21->etd[etd_num]; - struct urb *urb = etd->urb; - u32 etd_mask = 1 << etd_num; - struct urb_priv *urb_priv = urb->hcpriv; - int dir; - int cc; - u32 bytes_xfrd; - int etd_done; - - disactivate_etd(imx21, etd_num); - - dir = (etd_readl(imx21, etd_num, 0) >> DW0_DIRECT) & 0x3; - cc = (etd_readl(imx21, etd_num, 2) >> DW2_COMPCODE) & 0xf; - bytes_xfrd = etd->len - (etd_readl(imx21, etd_num, 3) & 0x1fffff); - - /* save toggle carry */ - usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe), - (etd_readl(imx21, etd_num, 0) >> DW0_TOGCRY) & 0x1); - - if (dir == TD_DIR_IN) { - clear_toggle_bit(imx21, USBH_XFILLSTAT, etd_mask); - clear_toggle_bit(imx21, USBH_YFILLSTAT, etd_mask); - - if (etd->bounce_buffer) { - memcpy(etd->cpu_buffer, etd->bounce_buffer, bytes_xfrd); - dma_unmap_single(imx21->dev, - etd->dma_handle, etd->len, DMA_FROM_DEVICE); - } else if (!etd->dma_handle && bytes_xfrd) {/* PIO */ - memcpy_fromio(etd->cpu_buffer, - imx21->regs + USBOTG_DMEM + etd->dmem_offset, - bytes_xfrd); - } - } - - kfree(etd->bounce_buffer); - etd->bounce_buffer = NULL; - free_dmem(imx21, etd); - - urb->error_count = 0; - if (!(urb->transfer_flags & URB_SHORT_NOT_OK) - && (cc == TD_DATAUNDERRUN)) - cc = TD_CC_NOERROR; - - if (cc != 0) - dev_vdbg(imx21->dev, "cc is 0x%x\n", cc); - - etd_done = (cc_to_error[cc] != 0); /* stop if error */ - - switch (usb_pipetype(urb->pipe)) { - case PIPE_CONTROL: - switch (urb_priv->state) { - case US_CTRL_SETUP: - if (urb->transfer_buffer_length > 0) - urb_priv->state = US_CTRL_DATA; - else - urb_priv->state = US_CTRL_ACK; - break; - case US_CTRL_DATA: - urb->actual_length += bytes_xfrd; - urb_priv->state = US_CTRL_ACK; - break; - case US_CTRL_ACK: - etd_done = 1; - break; - default: - dev_err(imx21->dev, - "Invalid pipe state %d\n", urb_priv->state); - etd_done = 1; - break; - } - break; - - case PIPE_BULK: - urb->actual_length += bytes_xfrd; - if ((urb_priv->state == US_BULK) - && (urb->transfer_flags & URB_ZERO_PACKET) - && urb->transfer_buffer_length > 0 - && ((urb->transfer_buffer_length % - usb_maxpacket(urb->dev, urb->pipe, - usb_pipeout(urb->pipe))) == 0)) { - /* need a 0-packet */ - urb_priv->state = US_BULK0; - } else { - etd_done = 1; - } - break; - - case PIPE_INTERRUPT: - urb->actual_length += bytes_xfrd; - etd_done = 1; - break; - } - - if (etd_done) - nonisoc_urb_completed_for_etd(imx21, etd, cc_to_error[cc]); - else { - dev_vdbg(imx21->dev, "next state=%d\n", urb_priv->state); - schedule_nonisoc_etd(imx21, urb); - } -} - - -static struct ep_priv *alloc_ep(void) -{ - int i; - struct ep_priv *ep_priv; - - ep_priv = kzalloc(sizeof(struct ep_priv), GFP_ATOMIC); - if (!ep_priv) - return NULL; - - for (i = 0; i < NUM_ISO_ETDS; ++i) - ep_priv->etd[i] = -1; - - return ep_priv; -} - -static int imx21_hc_urb_enqueue(struct usb_hcd *hcd, - struct urb *urb, gfp_t mem_flags) -{ - struct imx21 *imx21 = hcd_to_imx21(hcd); - struct usb_host_endpoint *ep = urb->ep; - struct urb_priv *urb_priv; - struct ep_priv *ep_priv; - struct etd_priv *etd; - int ret; - unsigned long flags; - - dev_vdbg(imx21->dev, - "enqueue urb=%p ep=%p len=%d " - "buffer=%p dma=%08X setupBuf=%p setupDma=%08X\n", - urb, ep, - urb->transfer_buffer_length, - urb->transfer_buffer, urb->transfer_dma, - urb->setup_packet, urb->setup_dma); - - if (usb_pipeisoc(urb->pipe)) - return imx21_hc_urb_enqueue_isoc(hcd, ep, urb, mem_flags); - - urb_priv = kzalloc(sizeof(struct urb_priv), mem_flags); - if (!urb_priv) - return -ENOMEM; - - spin_lock_irqsave(&imx21->lock, flags); - - ep_priv = ep->hcpriv; - if (ep_priv == NULL) { - ep_priv = alloc_ep(); - if (!ep_priv) { - ret = -ENOMEM; - goto failed_alloc_ep; - } - ep->hcpriv = ep_priv; - ep_priv->ep = ep; - } - - ret = usb_hcd_link_urb_to_ep(hcd, urb); - if (ret) - goto failed_link; - - urb->status = -EINPROGRESS; - urb->actual_length = 0; - urb->error_count = 0; - urb->hcpriv = urb_priv; - urb_priv->ep = ep; - - switch (usb_pipetype(urb->pipe)) { - case PIPE_CONTROL: - urb_priv->state = US_CTRL_SETUP; - break; - case PIPE_BULK: - urb_priv->state = US_BULK; - break; - } - - debug_urb_submitted(imx21, urb); - if (ep_priv->etd[0] < 0) { - if (ep_priv->waiting_etd) { - dev_dbg(imx21->dev, - "no ETD available already queued %p\n", - ep_priv); - debug_urb_queued_for_etd(imx21, urb); - goto out; - } - ep_priv->etd[0] = alloc_etd(imx21); - if (ep_priv->etd[0] < 0) { - dev_dbg(imx21->dev, - "no ETD available queueing %p\n", ep_priv); - debug_urb_queued_for_etd(imx21, urb); - list_add_tail(&ep_priv->queue, &imx21->queue_for_etd); - ep_priv->waiting_etd = 1; - goto out; - } - } - - /* Schedule if no URB already active for this endpoint */ - etd = &imx21->etd[ep_priv->etd[0]]; - if (etd->urb == NULL) { - DEBUG_LOG_FRAME(imx21, etd, last_req); - schedule_nonisoc_etd(imx21, urb); - } - -out: - spin_unlock_irqrestore(&imx21->lock, flags); - return 0; - -failed_link: -failed_alloc_ep: - spin_unlock_irqrestore(&imx21->lock, flags); - kfree(urb_priv); - return ret; -} - -static int imx21_hc_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, - int status) -{ - struct imx21 *imx21 = hcd_to_imx21(hcd); - unsigned long flags; - struct usb_host_endpoint *ep; - struct ep_priv *ep_priv; - struct urb_priv *urb_priv = urb->hcpriv; - int ret = -EINVAL; - - dev_vdbg(imx21->dev, "dequeue urb=%p iso=%d status=%d\n", - urb, usb_pipeisoc(urb->pipe), status); - - spin_lock_irqsave(&imx21->lock, flags); - - ret = usb_hcd_check_unlink_urb(hcd, urb, status); - if (ret) - goto fail; - ep = urb_priv->ep; - ep_priv = ep->hcpriv; - - debug_urb_unlinked(imx21, urb); - - if (usb_pipeisoc(urb->pipe)) { - dequeue_isoc_urb(imx21, urb, ep_priv); - schedule_isoc_etds(hcd, ep); - } else if (urb_priv->active) { - int etd_num = ep_priv->etd[0]; - if (etd_num != -1) { - struct etd_priv *etd = &imx21->etd[etd_num]; - - disactivate_etd(imx21, etd_num); - free_dmem(imx21, etd); - etd->urb = NULL; - kfree(etd->bounce_buffer); - etd->bounce_buffer = NULL; - } - } - - urb_done(hcd, urb, status); - - spin_unlock_irqrestore(&imx21->lock, flags); - return 0; - -fail: - spin_unlock_irqrestore(&imx21->lock, flags); - return ret; -} - -/* =========================================== */ -/* Interrupt dispatch */ -/* =========================================== */ - -static void process_etds(struct usb_hcd *hcd, struct imx21 *imx21, int sof) -{ - int etd_num; - int enable_sof_int = 0; - unsigned long flags; - - spin_lock_irqsave(&imx21->lock, flags); - - for (etd_num = 0; etd_num < USB_NUM_ETD; etd_num++) { - u32 etd_mask = 1 << etd_num; - u32 enabled = readl(imx21->regs + USBH_ETDENSET) & etd_mask; - u32 done = readl(imx21->regs + USBH_ETDDONESTAT) & etd_mask; - struct etd_priv *etd = &imx21->etd[etd_num]; - - - if (done) { - DEBUG_LOG_FRAME(imx21, etd, last_int); - } else { -/* - * Kludge warning! - * - * When multiple transfers are using the bus we sometimes get into a state - * where the transfer has completed (the CC field of the ETD is != 0x0F), - * the ETD has self disabled but the ETDDONESTAT flag is not set - * (and hence no interrupt occurs). - * This causes the transfer in question to hang. - * The kludge below checks for this condition at each SOF and processes any - * blocked ETDs (after an arbitrary 10 frame wait) - * - * With a single active transfer the usbtest test suite will run for days - * without the kludge. - * With other bus activity (eg mass storage) even just test1 will hang without - * the kludge. - */ - u32 dword0; - int cc; - - if (etd->active_count && !enabled) /* suspicious... */ - enable_sof_int = 1; - - if (!sof || enabled || !etd->active_count) - continue; - - cc = etd_readl(imx21, etd_num, 2) >> DW2_COMPCODE; - if (cc == TD_NOTACCESSED) - continue; - - if (++etd->active_count < 10) - continue; - - dword0 = etd_readl(imx21, etd_num, 0); - dev_dbg(imx21->dev, - "unblock ETD %d dev=0x%X ep=0x%X cc=0x%02X!\n", - etd_num, dword0 & 0x7F, - (dword0 >> DW0_ENDPNT) & 0x0F, - cc); - -#ifdef DEBUG - dev_dbg(imx21->dev, - "frame: act=%d disact=%d" - " int=%d req=%d cur=%d\n", - etd->activated_frame, - etd->disactivated_frame, - etd->last_int_frame, - etd->last_req_frame, - readl(imx21->regs + USBH_FRMNUB)); - imx21->debug_unblocks++; -#endif - etd->active_count = 0; -/* End of kludge */ - } - - if (etd->ep == NULL || etd->urb == NULL) { - dev_dbg(imx21->dev, - "Interrupt for unexpected etd %d" - " ep=%p urb=%p\n", - etd_num, etd->ep, etd->urb); - disactivate_etd(imx21, etd_num); - continue; - } - - if (usb_pipeisoc(etd->urb->pipe)) - isoc_etd_done(hcd, etd_num); - else - nonisoc_etd_done(hcd, etd_num); - } - - /* only enable SOF interrupt if it may be needed for the kludge */ - if (enable_sof_int) - set_register_bits(imx21, USBH_SYSIEN, USBH_SYSIEN_SOFINT); - else - clear_register_bits(imx21, USBH_SYSIEN, USBH_SYSIEN_SOFINT); - - - spin_unlock_irqrestore(&imx21->lock, flags); -} - -static irqreturn_t imx21_irq(struct usb_hcd *hcd) -{ - struct imx21 *imx21 = hcd_to_imx21(hcd); - u32 ints = readl(imx21->regs + USBH_SYSISR); - - if (ints & USBH_SYSIEN_HERRINT) - dev_dbg(imx21->dev, "Scheduling error\n"); - - if (ints & USBH_SYSIEN_SORINT) - dev_dbg(imx21->dev, "Scheduling overrun\n"); - - if (ints & (USBH_SYSISR_DONEINT | USBH_SYSISR_SOFINT)) - process_etds(hcd, imx21, ints & USBH_SYSISR_SOFINT); - - writel(ints, imx21->regs + USBH_SYSISR); - return IRQ_HANDLED; -} - -static void imx21_hc_endpoint_disable(struct usb_hcd *hcd, - struct usb_host_endpoint *ep) -{ - struct imx21 *imx21 = hcd_to_imx21(hcd); - unsigned long flags; - struct ep_priv *ep_priv; - int i; - - if (ep == NULL) - return; - - spin_lock_irqsave(&imx21->lock, flags); - ep_priv = ep->hcpriv; - dev_vdbg(imx21->dev, "disable ep=%p, ep->hcpriv=%p\n", ep, ep_priv); - - if (!list_empty(&ep->urb_list)) - dev_dbg(imx21->dev, "ep's URB list is not empty\n"); - - if (ep_priv != NULL) { - for (i = 0; i < NUM_ISO_ETDS; i++) { - if (ep_priv->etd[i] > -1) - dev_dbg(imx21->dev, "free etd %d for disable\n", - ep_priv->etd[i]); - - free_etd(imx21, ep_priv->etd[i]); - } - kfree(ep_priv); - ep->hcpriv = NULL; - } - - for (i = 0; i < USB_NUM_ETD; i++) { - if (imx21->etd[i].alloc && imx21->etd[i].ep == ep) { - dev_err(imx21->dev, - "Active etd %d for disabled ep=%p!\n", i, ep); - free_etd(imx21, i); - } - } - free_epdmem(imx21, ep); - spin_unlock_irqrestore(&imx21->lock, flags); -} - -/* =========================================== */ -/* Hub handling */ -/* =========================================== */ - -static int get_hub_descriptor(struct usb_hcd *hcd, - struct usb_hub_descriptor *desc) -{ - struct imx21 *imx21 = hcd_to_imx21(hcd); - desc->bDescriptorType = 0x29; /* HUB descriptor */ - desc->bHubContrCurrent = 0; - - desc->bNbrPorts = readl(imx21->regs + USBH_ROOTHUBA) - & USBH_ROOTHUBA_NDNSTMPRT_MASK; - desc->bDescLength = 9; - desc->bPwrOn2PwrGood = 0; - desc->wHubCharacteristics = (__force __u16) cpu_to_le16( - 0x0002 | /* No power switching */ - 0x0010 | /* No over current protection */ - 0); - - desc->u.hs.DeviceRemovable[0] = 1 << 1; - desc->u.hs.DeviceRemovable[1] = ~0; - return 0; -} - -static int imx21_hc_hub_status_data(struct usb_hcd *hcd, char *buf) -{ - struct imx21 *imx21 = hcd_to_imx21(hcd); - int ports; - int changed = 0; - int i; - unsigned long flags; - - spin_lock_irqsave(&imx21->lock, flags); - ports = readl(imx21->regs + USBH_ROOTHUBA) - & USBH_ROOTHUBA_NDNSTMPRT_MASK; - if (ports > 7) { - ports = 7; - dev_err(imx21->dev, "ports %d > 7\n", ports); - } - for (i = 0; i < ports; i++) { - if (readl(imx21->regs + USBH_PORTSTAT(i)) & - (USBH_PORTSTAT_CONNECTSC | - USBH_PORTSTAT_PRTENBLSC | - USBH_PORTSTAT_PRTSTATSC | - USBH_PORTSTAT_OVRCURIC | - USBH_PORTSTAT_PRTRSTSC)) { - - changed = 1; - buf[0] |= 1 << (i + 1); - } - } - spin_unlock_irqrestore(&imx21->lock, flags); - - if (changed) - dev_info(imx21->dev, "Hub status changed\n"); - return changed; -} - -static int imx21_hc_hub_control(struct usb_hcd *hcd, - u16 typeReq, - u16 wValue, u16 wIndex, char *buf, u16 wLength) -{ - struct imx21 *imx21 = hcd_to_imx21(hcd); - int rc = 0; - u32 status_write = 0; - - switch (typeReq) { - case ClearHubFeature: - dev_dbg(imx21->dev, "ClearHubFeature\n"); - switch (wValue) { - case C_HUB_OVER_CURRENT: - dev_dbg(imx21->dev, " OVER_CURRENT\n"); - break; - case C_HUB_LOCAL_POWER: - dev_dbg(imx21->dev, " LOCAL_POWER\n"); - break; - default: - dev_dbg(imx21->dev, " unknown\n"); - rc = -EINVAL; - break; - } - break; - - case ClearPortFeature: - dev_dbg(imx21->dev, "ClearPortFeature\n"); - switch (wValue) { - case USB_PORT_FEAT_ENABLE: - dev_dbg(imx21->dev, " ENABLE\n"); - status_write = USBH_PORTSTAT_CURCONST; - break; - case USB_PORT_FEAT_SUSPEND: - dev_dbg(imx21->dev, " SUSPEND\n"); - status_write = USBH_PORTSTAT_PRTOVRCURI; - break; - case USB_PORT_FEAT_POWER: - dev_dbg(imx21->dev, " POWER\n"); - status_write = USBH_PORTSTAT_LSDEVCON; - break; - case USB_PORT_FEAT_C_ENABLE: - dev_dbg(imx21->dev, " C_ENABLE\n"); - status_write = USBH_PORTSTAT_PRTENBLSC; - break; - case USB_PORT_FEAT_C_SUSPEND: - dev_dbg(imx21->dev, " C_SUSPEND\n"); - status_write = USBH_PORTSTAT_PRTSTATSC; - break; - case USB_PORT_FEAT_C_CONNECTION: - dev_dbg(imx21->dev, " C_CONNECTION\n"); - status_write = USBH_PORTSTAT_CONNECTSC; - break; - case USB_PORT_FEAT_C_OVER_CURRENT: - dev_dbg(imx21->dev, " C_OVER_CURRENT\n"); - status_write = USBH_PORTSTAT_OVRCURIC; - break; - case USB_PORT_FEAT_C_RESET: - dev_dbg(imx21->dev, " C_RESET\n"); - status_write = USBH_PORTSTAT_PRTRSTSC; - break; - default: - dev_dbg(imx21->dev, " unknown\n"); - rc = -EINVAL; - break; - } - - break; - - case GetHubDescriptor: - dev_dbg(imx21->dev, "GetHubDescriptor\n"); - rc = get_hub_descriptor(hcd, (void *)buf); - break; - - case GetHubStatus: - dev_dbg(imx21->dev, " GetHubStatus\n"); - *(__le32 *) buf = 0; - break; - - case GetPortStatus: - dev_dbg(imx21->dev, "GetPortStatus: port: %d, 0x%x\n", - wIndex, USBH_PORTSTAT(wIndex - 1)); - *(__le32 *) buf = readl(imx21->regs + - USBH_PORTSTAT(wIndex - 1)); - break; - - case SetHubFeature: - dev_dbg(imx21->dev, "SetHubFeature\n"); - switch (wValue) { - case C_HUB_OVER_CURRENT: - dev_dbg(imx21->dev, " OVER_CURRENT\n"); - break; - - case C_HUB_LOCAL_POWER: - dev_dbg(imx21->dev, " LOCAL_POWER\n"); - break; - default: - dev_dbg(imx21->dev, " unknown\n"); - rc = -EINVAL; - break; - } - - break; - - case SetPortFeature: - dev_dbg(imx21->dev, "SetPortFeature\n"); - switch (wValue) { - case USB_PORT_FEAT_SUSPEND: - dev_dbg(imx21->dev, " SUSPEND\n"); - status_write = USBH_PORTSTAT_PRTSUSPST; - break; - case USB_PORT_FEAT_POWER: - dev_dbg(imx21->dev, " POWER\n"); - status_write = USBH_PORTSTAT_PRTPWRST; - break; - case USB_PORT_FEAT_RESET: - dev_dbg(imx21->dev, " RESET\n"); - status_write = USBH_PORTSTAT_PRTRSTST; - break; - default: - dev_dbg(imx21->dev, " unknown\n"); - rc = -EINVAL; - break; - } - break; - - default: - dev_dbg(imx21->dev, " unknown\n"); - rc = -EINVAL; - break; - } - - if (status_write) - writel(status_write, imx21->regs + USBH_PORTSTAT(wIndex - 1)); - return rc; -} - -/* =========================================== */ -/* Host controller management */ -/* =========================================== */ - -static int imx21_hc_reset(struct usb_hcd *hcd) -{ - struct imx21 *imx21 = hcd_to_imx21(hcd); - unsigned long timeout; - unsigned long flags; - - spin_lock_irqsave(&imx21->lock, flags); - - /* Reset the Host controller modules */ - writel(USBOTG_RST_RSTCTRL | USBOTG_RST_RSTRH | - USBOTG_RST_RSTHSIE | USBOTG_RST_RSTHC, - imx21->regs + USBOTG_RST_CTRL); - - /* Wait for reset to finish */ - timeout = jiffies + HZ; - while (readl(imx21->regs + USBOTG_RST_CTRL) != 0) { - if (time_after(jiffies, timeout)) { - spin_unlock_irqrestore(&imx21->lock, flags); - dev_err(imx21->dev, "timeout waiting for reset\n"); - return -ETIMEDOUT; - } - spin_unlock_irq(&imx21->lock); - schedule_timeout_uninterruptible(1); - spin_lock_irq(&imx21->lock); - } - spin_unlock_irqrestore(&imx21->lock, flags); - return 0; -} - -static int __devinit imx21_hc_start(struct usb_hcd *hcd) -{ - struct imx21 *imx21 = hcd_to_imx21(hcd); - unsigned long flags; - int i, j; - u32 hw_mode = USBOTG_HWMODE_CRECFG_HOST; - u32 usb_control = 0; - - hw_mode |= ((imx21->pdata->host_xcvr << USBOTG_HWMODE_HOSTXCVR_SHIFT) & - USBOTG_HWMODE_HOSTXCVR_MASK); - hw_mode |= ((imx21->pdata->otg_xcvr << USBOTG_HWMODE_OTGXCVR_SHIFT) & - USBOTG_HWMODE_OTGXCVR_MASK); - - if (imx21->pdata->host1_txenoe) - usb_control |= USBCTRL_HOST1_TXEN_OE; - - if (!imx21->pdata->host1_xcverless) - usb_control |= USBCTRL_HOST1_BYP_TLL; - - if (imx21->pdata->otg_ext_xcvr) - usb_control |= USBCTRL_OTC_RCV_RXDP; - - - spin_lock_irqsave(&imx21->lock, flags); - - writel((USBOTG_CLK_CTRL_HST | USBOTG_CLK_CTRL_MAIN), - imx21->regs + USBOTG_CLK_CTRL); - writel(hw_mode, imx21->regs + USBOTG_HWMODE); - writel(usb_control, imx21->regs + USBCTRL); - writel(USB_MISCCONTROL_SKPRTRY | USB_MISCCONTROL_ARBMODE, - imx21->regs + USB_MISCCONTROL); - - /* Clear the ETDs */ - for (i = 0; i < USB_NUM_ETD; i++) - for (j = 0; j < 4; j++) - etd_writel(imx21, i, j, 0); - - /* Take the HC out of reset */ - writel(USBH_HOST_CTRL_HCUSBSTE_OPERATIONAL | USBH_HOST_CTRL_CTLBLKSR_1, - imx21->regs + USBH_HOST_CTRL); - - /* Enable ports */ - if (imx21->pdata->enable_otg_host) - writel(USBH_PORTSTAT_PRTPWRST | USBH_PORTSTAT_PRTENABST, - imx21->regs + USBH_PORTSTAT(0)); - - if (imx21->pdata->enable_host1) - writel(USBH_PORTSTAT_PRTPWRST | USBH_PORTSTAT_PRTENABST, - imx21->regs + USBH_PORTSTAT(1)); - - if (imx21->pdata->enable_host2) - writel(USBH_PORTSTAT_PRTPWRST | USBH_PORTSTAT_PRTENABST, - imx21->regs + USBH_PORTSTAT(2)); - - - hcd->state = HC_STATE_RUNNING; - - /* Enable host controller interrupts */ - set_register_bits(imx21, USBH_SYSIEN, - USBH_SYSIEN_HERRINT | - USBH_SYSIEN_DONEINT | USBH_SYSIEN_SORINT); - set_register_bits(imx21, USBOTG_CINT_STEN, USBOTG_HCINT); - - spin_unlock_irqrestore(&imx21->lock, flags); - - return 0; -} - -static void imx21_hc_stop(struct usb_hcd *hcd) -{ - struct imx21 *imx21 = hcd_to_imx21(hcd); - unsigned long flags; - - spin_lock_irqsave(&imx21->lock, flags); - - writel(0, imx21->regs + USBH_SYSIEN); - clear_register_bits(imx21, USBOTG_CINT_STEN, USBOTG_HCINT); - clear_register_bits(imx21, USBOTG_CLK_CTRL_HST | USBOTG_CLK_CTRL_MAIN, - USBOTG_CLK_CTRL); - spin_unlock_irqrestore(&imx21->lock, flags); -} - -/* =========================================== */ -/* Driver glue */ -/* =========================================== */ - -static struct hc_driver imx21_hc_driver = { - .description = hcd_name, - .product_desc = "IMX21 USB Host Controller", - .hcd_priv_size = sizeof(struct imx21), - - .flags = HCD_USB11, - .irq = imx21_irq, - - .reset = imx21_hc_reset, - .start = imx21_hc_start, - .stop = imx21_hc_stop, - - /* I/O requests */ - .urb_enqueue = imx21_hc_urb_enqueue, - .urb_dequeue = imx21_hc_urb_dequeue, - .endpoint_disable = imx21_hc_endpoint_disable, - - /* scheduling support */ - .get_frame_number = imx21_hc_get_frame, - - /* Root hub support */ - .hub_status_data = imx21_hc_hub_status_data, - .hub_control = imx21_hc_hub_control, - -}; - -static struct mx21_usbh_platform_data default_pdata = { - .host_xcvr = MX21_USBXCVR_TXDIF_RXDIF, - .otg_xcvr = MX21_USBXCVR_TXDIF_RXDIF, - .enable_host1 = 1, - .enable_host2 = 1, - .enable_otg_host = 1, - -}; - -static int imx21_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct imx21 *imx21 = hcd_to_imx21(hcd); - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - remove_debug_files(imx21); - usb_remove_hcd(hcd); - - if (res != NULL) { - clk_disable(imx21->clk); - clk_put(imx21->clk); - iounmap(imx21->regs); - release_mem_region(res->start, resource_size(res)); - } - - kfree(hcd); - return 0; -} - - -static int imx21_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - struct imx21 *imx21; - struct resource *res; - int ret; - int irq; - - printk(KERN_INFO "%s\n", imx21_hc_driver.product_desc); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return -ENXIO; - - hcd = usb_create_hcd(&imx21_hc_driver, - &pdev->dev, dev_name(&pdev->dev)); - if (hcd == NULL) { - dev_err(&pdev->dev, "Cannot create hcd (%s)\n", - dev_name(&pdev->dev)); - return -ENOMEM; - } - - imx21 = hcd_to_imx21(hcd); - imx21->hcd = hcd; - imx21->dev = &pdev->dev; - imx21->pdata = pdev->dev.platform_data; - if (!imx21->pdata) - imx21->pdata = &default_pdata; - - spin_lock_init(&imx21->lock); - INIT_LIST_HEAD(&imx21->dmem_list); - INIT_LIST_HEAD(&imx21->queue_for_etd); - INIT_LIST_HEAD(&imx21->queue_for_dmem); - create_debug_files(imx21); - - res = request_mem_region(res->start, resource_size(res), hcd_name); - if (!res) { - ret = -EBUSY; - goto failed_request_mem; - } - - imx21->regs = ioremap(res->start, resource_size(res)); - if (imx21->regs == NULL) { - dev_err(imx21->dev, "Cannot map registers\n"); - ret = -ENOMEM; - goto failed_ioremap; - } - - /* Enable clocks source */ - imx21->clk = clk_get(imx21->dev, NULL); - if (IS_ERR(imx21->clk)) { - dev_err(imx21->dev, "no clock found\n"); - ret = PTR_ERR(imx21->clk); - goto failed_clock_get; - } - - ret = clk_set_rate(imx21->clk, clk_round_rate(imx21->clk, 48000000)); - if (ret) - goto failed_clock_set; - ret = clk_enable(imx21->clk); - if (ret) - goto failed_clock_enable; - - dev_info(imx21->dev, "Hardware HC revision: 0x%02X\n", - (readl(imx21->regs + USBOTG_HWMODE) >> 16) & 0xFF); - - ret = usb_add_hcd(hcd, irq, 0); - if (ret != 0) { - dev_err(imx21->dev, "usb_add_hcd() returned %d\n", ret); - goto failed_add_hcd; - } - - return 0; - -failed_add_hcd: - clk_disable(imx21->clk); -failed_clock_enable: -failed_clock_set: - clk_put(imx21->clk); -failed_clock_get: - iounmap(imx21->regs); -failed_ioremap: - release_mem_region(res->start, resource_size(res)); -failed_request_mem: - remove_debug_files(imx21); - usb_put_hcd(hcd); - return ret; -} - -static struct platform_driver imx21_hcd_driver = { - .driver = { - .name = (char *)hcd_name, - }, - .probe = imx21_probe, - .remove = imx21_remove, - .suspend = NULL, - .resume = NULL, -}; - -module_platform_driver(imx21_hcd_driver); - -MODULE_DESCRIPTION("i.MX21 USB Host controller"); -MODULE_AUTHOR("Martin Fuzzey"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:imx21-hcd"); diff --git a/ANDROID_3.4.5/drivers/usb/host/imx21-hcd.h b/ANDROID_3.4.5/drivers/usb/host/imx21-hcd.h deleted file mode 100644 index 87b29fd9..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/imx21-hcd.h +++ /dev/null @@ -1,440 +0,0 @@ -/* - * Macros and prototypes for i.MX21 - * - * Copyright (C) 2006 Loping Dog Embedded Systems - * Copyright (C) 2009 Martin Fuzzey - * Originally written by Jay Monkman - * Ported to 2.6.30, debugged and enhanced by Martin Fuzzey - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __LINUX_IMX21_HCD_H__ -#define __LINUX_IMX21_HCD_H__ - -#include - -#define NUM_ISO_ETDS 2 -#define USB_NUM_ETD 32 -#define DMEM_SIZE 4096 - -/* Register definitions */ -#define USBOTG_HWMODE 0x00 -#define USBOTG_HWMODE_ANASDBEN (1 << 14) -#define USBOTG_HWMODE_OTGXCVR_SHIFT 6 -#define USBOTG_HWMODE_OTGXCVR_MASK (3 << 6) -#define USBOTG_HWMODE_OTGXCVR_TD_RD (0 << 6) -#define USBOTG_HWMODE_OTGXCVR_TS_RD (2 << 6) -#define USBOTG_HWMODE_OTGXCVR_TD_RS (1 << 6) -#define USBOTG_HWMODE_OTGXCVR_TS_RS (3 << 6) -#define USBOTG_HWMODE_HOSTXCVR_SHIFT 4 -#define USBOTG_HWMODE_HOSTXCVR_MASK (3 << 4) -#define USBOTG_HWMODE_HOSTXCVR_TD_RD (0 << 4) -#define USBOTG_HWMODE_HOSTXCVR_TS_RD (2 << 4) -#define USBOTG_HWMODE_HOSTXCVR_TD_RS (1 << 4) -#define USBOTG_HWMODE_HOSTXCVR_TS_RS (3 << 4) -#define USBOTG_HWMODE_CRECFG_MASK (3 << 0) -#define USBOTG_HWMODE_CRECFG_HOST (1 << 0) -#define USBOTG_HWMODE_CRECFG_FUNC (2 << 0) -#define USBOTG_HWMODE_CRECFG_HNP (3 << 0) - -#define USBOTG_CINT_STAT 0x04 -#define USBOTG_CINT_STEN 0x08 -#define USBOTG_ASHNPINT (1 << 5) -#define USBOTG_ASFCINT (1 << 4) -#define USBOTG_ASHCINT (1 << 3) -#define USBOTG_SHNPINT (1 << 2) -#define USBOTG_FCINT (1 << 1) -#define USBOTG_HCINT (1 << 0) - -#define USBOTG_CLK_CTRL 0x0c -#define USBOTG_CLK_CTRL_FUNC (1 << 2) -#define USBOTG_CLK_CTRL_HST (1 << 1) -#define USBOTG_CLK_CTRL_MAIN (1 << 0) - -#define USBOTG_RST_CTRL 0x10 -#define USBOTG_RST_RSTI2C (1 << 15) -#define USBOTG_RST_RSTCTRL (1 << 5) -#define USBOTG_RST_RSTFC (1 << 4) -#define USBOTG_RST_RSTFSKE (1 << 3) -#define USBOTG_RST_RSTRH (1 << 2) -#define USBOTG_RST_RSTHSIE (1 << 1) -#define USBOTG_RST_RSTHC (1 << 0) - -#define USBOTG_FRM_INTVL 0x14 -#define USBOTG_FRM_REMAIN 0x18 -#define USBOTG_HNP_CSR 0x1c -#define USBOTG_HNP_ISR 0x2c -#define USBOTG_HNP_IEN 0x30 - -#define USBOTG_I2C_TXCVR_REG(x) (0x100 + (x)) -#define USBOTG_I2C_XCVR_DEVAD 0x118 -#define USBOTG_I2C_SEQ_OP_REG 0x119 -#define USBOTG_I2C_SEQ_RD_STARTAD 0x11a -#define USBOTG_I2C_OP_CTRL_REG 0x11b -#define USBOTG_I2C_SCLK_TO_SCK_HPER 0x11e -#define USBOTG_I2C_MASTER_INT_REG 0x11f - -#define USBH_HOST_CTRL 0x80 -#define USBH_HOST_CTRL_HCRESET (1 << 31) -#define USBH_HOST_CTRL_SCHDOVR(x) ((x) << 16) -#define USBH_HOST_CTRL_RMTWUEN (1 << 4) -#define USBH_HOST_CTRL_HCUSBSTE_RESET (0 << 2) -#define USBH_HOST_CTRL_HCUSBSTE_RESUME (1 << 2) -#define USBH_HOST_CTRL_HCUSBSTE_OPERATIONAL (2 << 2) -#define USBH_HOST_CTRL_HCUSBSTE_SUSPEND (3 << 2) -#define USBH_HOST_CTRL_CTLBLKSR_1 (0 << 0) -#define USBH_HOST_CTRL_CTLBLKSR_2 (1 << 0) -#define USBH_HOST_CTRL_CTLBLKSR_3 (2 << 0) -#define USBH_HOST_CTRL_CTLBLKSR_4 (3 << 0) - -#define USBH_SYSISR 0x88 -#define USBH_SYSISR_PSCINT (1 << 6) -#define USBH_SYSISR_FMOFINT (1 << 5) -#define USBH_SYSISR_HERRINT (1 << 4) -#define USBH_SYSISR_RESDETINT (1 << 3) -#define USBH_SYSISR_SOFINT (1 << 2) -#define USBH_SYSISR_DONEINT (1 << 1) -#define USBH_SYSISR_SORINT (1 << 0) - -#define USBH_SYSIEN 0x8c -#define USBH_SYSIEN_PSCINT (1 << 6) -#define USBH_SYSIEN_FMOFINT (1 << 5) -#define USBH_SYSIEN_HERRINT (1 << 4) -#define USBH_SYSIEN_RESDETINT (1 << 3) -#define USBH_SYSIEN_SOFINT (1 << 2) -#define USBH_SYSIEN_DONEINT (1 << 1) -#define USBH_SYSIEN_SORINT (1 << 0) - -#define USBH_XBUFSTAT 0x98 -#define USBH_YBUFSTAT 0x9c -#define USBH_XYINTEN 0xa0 -#define USBH_XFILLSTAT 0xa8 -#define USBH_YFILLSTAT 0xac -#define USBH_ETDENSET 0xc0 -#define USBH_ETDENCLR 0xc4 -#define USBH_IMMEDINT 0xcc -#define USBH_ETDDONESTAT 0xd0 -#define USBH_ETDDONEEN 0xd4 -#define USBH_FRMNUB 0xe0 -#define USBH_LSTHRESH 0xe4 - -#define USBH_ROOTHUBA 0xe8 -#define USBH_ROOTHUBA_PWRTOGOOD_MASK (0xff) -#define USBH_ROOTHUBA_PWRTOGOOD_SHIFT (24) -#define USBH_ROOTHUBA_NOOVRCURP (1 << 12) -#define USBH_ROOTHUBA_OVRCURPM (1 << 11) -#define USBH_ROOTHUBA_DEVTYPE (1 << 10) -#define USBH_ROOTHUBA_PWRSWTMD (1 << 9) -#define USBH_ROOTHUBA_NOPWRSWT (1 << 8) -#define USBH_ROOTHUBA_NDNSTMPRT_MASK (0xff) - -#define USBH_ROOTHUBB 0xec -#define USBH_ROOTHUBB_PRTPWRCM(x) (1 << ((x) + 16)) -#define USBH_ROOTHUBB_DEVREMOVE(x) (1 << (x)) - -#define USBH_ROOTSTAT 0xf0 -#define USBH_ROOTSTAT_CLRRMTWUE (1 << 31) -#define USBH_ROOTSTAT_OVRCURCHG (1 << 17) -#define USBH_ROOTSTAT_DEVCONWUE (1 << 15) -#define USBH_ROOTSTAT_OVRCURI (1 << 1) -#define USBH_ROOTSTAT_LOCPWRS (1 << 0) - -#define USBH_PORTSTAT(x) (0xf4 + ((x) * 4)) -#define USBH_PORTSTAT_PRTRSTSC (1 << 20) -#define USBH_PORTSTAT_OVRCURIC (1 << 19) -#define USBH_PORTSTAT_PRTSTATSC (1 << 18) -#define USBH_PORTSTAT_PRTENBLSC (1 << 17) -#define USBH_PORTSTAT_CONNECTSC (1 << 16) -#define USBH_PORTSTAT_LSDEVCON (1 << 9) -#define USBH_PORTSTAT_PRTPWRST (1 << 8) -#define USBH_PORTSTAT_PRTRSTST (1 << 4) -#define USBH_PORTSTAT_PRTOVRCURI (1 << 3) -#define USBH_PORTSTAT_PRTSUSPST (1 << 2) -#define USBH_PORTSTAT_PRTENABST (1 << 1) -#define USBH_PORTSTAT_CURCONST (1 << 0) - -#define USB_DMAREV 0x800 -#define USB_DMAINTSTAT 0x804 -#define USB_DMAINTSTAT_EPERR (1 << 1) -#define USB_DMAINTSTAT_ETDERR (1 << 0) - -#define USB_DMAINTEN 0x808 -#define USB_DMAINTEN_EPERRINTEN (1 << 1) -#define USB_DMAINTEN_ETDERRINTEN (1 << 0) - -#define USB_ETDDMAERSTAT 0x80c -#define USB_EPDMAERSTAT 0x810 -#define USB_ETDDMAEN 0x820 -#define USB_EPDMAEN 0x824 -#define USB_ETDDMAXTEN 0x828 -#define USB_EPDMAXTEN 0x82c -#define USB_ETDDMAENXYT 0x830 -#define USB_EPDMAENXYT 0x834 -#define USB_ETDDMABST4EN 0x838 -#define USB_EPDMABST4EN 0x83c - -#define USB_MISCCONTROL 0x840 -#define USB_MISCCONTROL_ISOPREVFRM (1 << 3) -#define USB_MISCCONTROL_SKPRTRY (1 << 2) -#define USB_MISCCONTROL_ARBMODE (1 << 1) -#define USB_MISCCONTROL_FILTCC (1 << 0) - -#define USB_ETDDMACHANLCLR 0x848 -#define USB_EPDMACHANLCLR 0x84c -#define USB_ETDSMSA(x) (0x900 + ((x) * 4)) -#define USB_EPSMSA(x) (0x980 + ((x) * 4)) -#define USB_ETDDMABUFPTR(x) (0xa00 + ((x) * 4)) -#define USB_EPDMABUFPTR(x) (0xa80 + ((x) * 4)) - -#define USB_ETD_DWORD(x, w) (0x200 + ((x) * 16) + ((w) * 4)) -#define DW0_ADDRESS 0 -#define DW0_ENDPNT 7 -#define DW0_DIRECT 11 -#define DW0_SPEED 13 -#define DW0_FORMAT 14 -#define DW0_MAXPKTSIZ 16 -#define DW0_HALTED 27 -#define DW0_TOGCRY 28 -#define DW0_SNDNAK 30 - -#define DW1_XBUFSRTAD 0 -#define DW1_YBUFSRTAD 16 - -#define DW2_RTRYDELAY 0 -#define DW2_POLINTERV 0 -#define DW2_STARTFRM 0 -#define DW2_RELPOLPOS 8 -#define DW2_DIRPID 16 -#define DW2_BUFROUND 18 -#define DW2_DELAYINT 19 -#define DW2_DATATOG 22 -#define DW2_ERRORCNT 24 -#define DW2_COMPCODE 28 - -#define DW3_TOTBYECNT 0 -#define DW3_PKTLEN0 0 -#define DW3_COMPCODE0 12 -#define DW3_PKTLEN1 16 -#define DW3_BUFSIZE 21 -#define DW3_COMPCODE1 28 - -#define USBCTRL 0x600 -#define USBCTRL_I2C_WU_INT_STAT (1 << 27) -#define USBCTRL_OTG_WU_INT_STAT (1 << 26) -#define USBCTRL_HOST_WU_INT_STAT (1 << 25) -#define USBCTRL_FNT_WU_INT_STAT (1 << 24) -#define USBCTRL_I2C_WU_INT_EN (1 << 19) -#define USBCTRL_OTG_WU_INT_EN (1 << 18) -#define USBCTRL_HOST_WU_INT_EN (1 << 17) -#define USBCTRL_FNT_WU_INT_EN (1 << 16) -#define USBCTRL_OTC_RCV_RXDP (1 << 13) -#define USBCTRL_HOST1_BYP_TLL (1 << 12) -#define USBCTRL_OTG_BYP_VAL(x) ((x) << 10) -#define USBCTRL_HOST1_BYP_VAL(x) ((x) << 8) -#define USBCTRL_OTG_PWR_MASK (1 << 6) -#define USBCTRL_HOST1_PWR_MASK (1 << 5) -#define USBCTRL_HOST2_PWR_MASK (1 << 4) -#define USBCTRL_USB_BYP (1 << 2) -#define USBCTRL_HOST1_TXEN_OE (1 << 1) - -#define USBOTG_DMEM 0x1000 - -/* Values in TD blocks */ -#define TD_DIR_SETUP 0 -#define TD_DIR_OUT 1 -#define TD_DIR_IN 2 -#define TD_FORMAT_CONTROL 0 -#define TD_FORMAT_ISO 1 -#define TD_FORMAT_BULK 2 -#define TD_FORMAT_INT 3 -#define TD_TOGGLE_CARRY 0 -#define TD_TOGGLE_DATA0 2 -#define TD_TOGGLE_DATA1 3 - -/* control transfer states */ -#define US_CTRL_SETUP 2 -#define US_CTRL_DATA 1 -#define US_CTRL_ACK 0 - -/* bulk transfer main state and 0-length packet */ -#define US_BULK 1 -#define US_BULK0 0 - -/*ETD format description*/ -#define IMX_FMT_CTRL 0x0 -#define IMX_FMT_ISO 0x1 -#define IMX_FMT_BULK 0x2 -#define IMX_FMT_INT 0x3 - -static char fmt_urb_to_etd[4] = { -/*PIPE_ISOCHRONOUS*/ IMX_FMT_ISO, -/*PIPE_INTERRUPT*/ IMX_FMT_INT, -/*PIPE_CONTROL*/ IMX_FMT_CTRL, -/*PIPE_BULK*/ IMX_FMT_BULK -}; - -/* condition (error) CC codes and mapping (OHCI like) */ - -#define TD_CC_NOERROR 0x00 -#define TD_CC_CRC 0x01 -#define TD_CC_BITSTUFFING 0x02 -#define TD_CC_DATATOGGLEM 0x03 -#define TD_CC_STALL 0x04 -#define TD_DEVNOTRESP 0x05 -#define TD_PIDCHECKFAIL 0x06 -/*#define TD_UNEXPECTEDPID 0x07 - reserved, not active on MX2*/ -#define TD_DATAOVERRUN 0x08 -#define TD_DATAUNDERRUN 0x09 -#define TD_BUFFEROVERRUN 0x0C -#define TD_BUFFERUNDERRUN 0x0D -#define TD_SCHEDULEOVERRUN 0x0E -#define TD_NOTACCESSED 0x0F - -static const int cc_to_error[16] = { - /* No Error */ 0, - /* CRC Error */ -EILSEQ, - /* Bit Stuff */ -EPROTO, - /* Data Togg */ -EILSEQ, - /* Stall */ -EPIPE, - /* DevNotResp */ -ETIMEDOUT, - /* PIDCheck */ -EPROTO, - /* UnExpPID */ -EPROTO, - /* DataOver */ -EOVERFLOW, - /* DataUnder */ -EREMOTEIO, - /* (for hw) */ -EIO, - /* (for hw) */ -EIO, - /* BufferOver */ -ECOMM, - /* BuffUnder */ -ENOSR, - /* (for HCD) */ -ENOSPC, - /* (for HCD) */ -EALREADY -}; - -/* HCD data associated with a usb core URB */ -struct urb_priv { - struct urb *urb; - struct usb_host_endpoint *ep; - int active; - int state; - struct td *isoc_td; - int isoc_remaining; - int isoc_status; -}; - -/* HCD data associated with a usb core endpoint */ -struct ep_priv { - struct usb_host_endpoint *ep; - struct list_head td_list; - struct list_head queue; - int etd[NUM_ISO_ETDS]; - int waiting_etd; -}; - -/* isoc packet */ -struct td { - struct list_head list; - struct urb *urb; - struct usb_host_endpoint *ep; - dma_addr_t dma_handle; - void *cpu_buffer; - int len; - int frame; - int isoc_index; -}; - -/* HCD data associated with a hardware ETD */ -struct etd_priv { - struct usb_host_endpoint *ep; - struct urb *urb; - struct td *td; - struct list_head queue; - dma_addr_t dma_handle; - void *cpu_buffer; - void *bounce_buffer; - int alloc; - int len; - int dmem_size; - int dmem_offset; - int active_count; -#ifdef DEBUG - int activated_frame; - int disactivated_frame; - int last_int_frame; - int last_req_frame; - u32 submitted_dwords[4]; -#endif -}; - -/* Hardware data memory info */ -struct imx21_dmem_area { - struct usb_host_endpoint *ep; - unsigned int offset; - unsigned int size; - struct list_head list; -}; - -#ifdef DEBUG -struct debug_usage_stats { - unsigned int value; - unsigned int maximum; -}; - -struct debug_stats { - unsigned long submitted; - unsigned long completed_ok; - unsigned long completed_failed; - unsigned long unlinked; - unsigned long queue_etd; - unsigned long queue_dmem; -}; - -struct debug_isoc_trace { - int schedule_frame; - int submit_frame; - int request_len; - int done_frame; - int done_len; - int cc; - struct td *td; -}; -#endif - -/* HCD data structure */ -struct imx21 { - spinlock_t lock; - struct device *dev; - struct usb_hcd *hcd; - struct mx21_usbh_platform_data *pdata; - struct list_head dmem_list; - struct list_head queue_for_etd; /* eps queued due to etd shortage */ - struct list_head queue_for_dmem; /* etds queued due to dmem shortage */ - struct etd_priv etd[USB_NUM_ETD]; - struct clk *clk; - void __iomem *regs; -#ifdef DEBUG - struct dentry *debug_root; - struct debug_stats nonisoc_stats; - struct debug_stats isoc_stats; - struct debug_usage_stats etd_usage; - struct debug_usage_stats dmem_usage; - struct debug_isoc_trace isoc_trace[20]; - struct debug_isoc_trace isoc_trace_failed[20]; - unsigned long debug_unblocks; - int isoc_trace_index; - int isoc_trace_index_failed; -#endif -}; - -#endif diff --git a/ANDROID_3.4.5/drivers/usb/host/isp116x-hcd.c b/ANDROID_3.4.5/drivers/usb/host/isp116x-hcd.c deleted file mode 100644 index 9e65e309..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/isp116x-hcd.c +++ /dev/null @@ -1,1713 +0,0 @@ -/* - * ISP116x HCD (Host Controller Driver) for USB. - * - * Derived from the SL811 HCD, rewritten for ISP116x. - * Copyright (C) 2005 Olav Kongas - * - * Portions: - * Copyright (C) 2004 Psion Teklogix (for NetBook PRO) - * Copyright (C) 2004 David Brownell - * - * Periodic scheduling is based on Roman's OHCI code - * Copyright (C) 1999 Roman Weissgaerber - * - */ - -/* - * The driver basically works. A number of people have used it with a range - * of devices. - * - * The driver passes all usbtests 1-14. - * - * Suspending/resuming of root hub via sysfs works. Remote wakeup works too. - * And suspending/resuming of platform device works too. Suspend/resume - * via HCD operations vector is not implemented. - * - * Iso transfer support is not implemented. Adding this would include - * implementing recovery from the failure to service the processed ITL - * fifo ram in time, which will involve chip reset. - * - * TODO: - + More testing of suspend/resume. -*/ - -/* - ISP116x chips require certain delays between accesses to its - registers. The following timing options exist. - - 1. Configure your memory controller (the best) - 2. Implement platform-specific delay function possibly - combined with configuring the memory controller; see - include/linux/usb-isp116x.h for more info. Some broken - memory controllers line LH7A400 SMC need this. Also, - uncomment for that to work the following - USE_PLATFORM_DELAY macro. - 3. Use ndelay (easiest, poorest). For that, uncomment - the following USE_NDELAY macro. -*/ -#define USE_PLATFORM_DELAY -//#define USE_NDELAY - -//#define DEBUG -//#define VERBOSE -/* Transfer descriptors. See dump_ptd() for printout format */ -//#define PTD_TRACE -/* enqueuing/finishing log of urbs */ -//#define URB_TRACE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "isp116x.h" - -#define DRIVER_VERSION "03 Nov 2005" -#define DRIVER_DESC "ISP116x USB Host Controller Driver" - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -static const char hcd_name[] = "isp116x-hcd"; - -/*-----------------------------------------------------------------*/ - -/* - Write len bytes to fifo, pad till 32-bit boundary - */ -static void write_ptddata_to_fifo(struct isp116x *isp116x, void *buf, int len) -{ - u8 *dp = (u8 *) buf; - u16 *dp2 = (u16 *) buf; - u16 w; - int quot = len % 4; - - /* buffer is already in 'usb data order', which is LE. */ - /* When reading buffer as u16, we have to take care byte order */ - /* doesn't get mixed up */ - - if ((unsigned long)dp2 & 1) { - /* not aligned */ - for (; len > 1; len -= 2) { - w = *dp++; - w |= *dp++ << 8; - isp116x_raw_write_data16(isp116x, w); - } - if (len) - isp116x_write_data16(isp116x, (u16) * dp); - } else { - /* aligned */ - for (; len > 1; len -= 2) { - /* Keep byte order ! */ - isp116x_raw_write_data16(isp116x, cpu_to_le16(*dp2++)); - } - - if (len) - isp116x_write_data16(isp116x, 0xff & *((u8 *) dp2)); - } - if (quot == 1 || quot == 2) - isp116x_raw_write_data16(isp116x, 0); -} - -/* - Read len bytes from fifo and then read till 32-bit boundary. - */ -static void read_ptddata_from_fifo(struct isp116x *isp116x, void *buf, int len) -{ - u8 *dp = (u8 *) buf; - u16 *dp2 = (u16 *) buf; - u16 w; - int quot = len % 4; - - /* buffer is already in 'usb data order', which is LE. */ - /* When reading buffer as u16, we have to take care byte order */ - /* doesn't get mixed up */ - - if ((unsigned long)dp2 & 1) { - /* not aligned */ - for (; len > 1; len -= 2) { - w = isp116x_raw_read_data16(isp116x); - *dp++ = w & 0xff; - *dp++ = (w >> 8) & 0xff; - } - - if (len) - *dp = 0xff & isp116x_read_data16(isp116x); - } else { - /* aligned */ - for (; len > 1; len -= 2) { - /* Keep byte order! */ - *dp2++ = le16_to_cpu(isp116x_raw_read_data16(isp116x)); - } - - if (len) - *(u8 *) dp2 = 0xff & isp116x_read_data16(isp116x); - } - if (quot == 1 || quot == 2) - isp116x_raw_read_data16(isp116x); -} - -/* - Write ptd's and data for scheduled transfers into - the fifo ram. Fifo must be empty and ready. -*/ -static void pack_fifo(struct isp116x *isp116x) -{ - struct isp116x_ep *ep; - struct ptd *ptd; - int buflen = isp116x->atl_last_dir == PTD_DIR_IN - ? isp116x->atl_bufshrt : isp116x->atl_buflen; - - isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT); - isp116x_write_reg16(isp116x, HCXFERCTR, buflen); - isp116x_write_addr(isp116x, HCATLPORT | ISP116x_WRITE_OFFSET); - for (ep = isp116x->atl_active; ep; ep = ep->active) { - ptd = &ep->ptd; - dump_ptd(ptd); - dump_ptd_out_data(ptd, ep->data); - isp116x_write_data16(isp116x, ptd->count); - isp116x_write_data16(isp116x, ptd->mps); - isp116x_write_data16(isp116x, ptd->len); - isp116x_write_data16(isp116x, ptd->faddr); - buflen -= sizeof(struct ptd); - /* Skip writing data for last IN PTD */ - if (ep->active || (isp116x->atl_last_dir != PTD_DIR_IN)) { - write_ptddata_to_fifo(isp116x, ep->data, ep->length); - buflen -= ALIGN(ep->length, 4); - } - } - BUG_ON(buflen); -} - -/* - Read the processed ptd's and data from fifo ram back to - URBs' buffers. Fifo must be full and done -*/ -static void unpack_fifo(struct isp116x *isp116x) -{ - struct isp116x_ep *ep; - struct ptd *ptd; - int buflen = isp116x->atl_last_dir == PTD_DIR_IN - ? isp116x->atl_buflen : isp116x->atl_bufshrt; - - isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT); - isp116x_write_reg16(isp116x, HCXFERCTR, buflen); - isp116x_write_addr(isp116x, HCATLPORT); - for (ep = isp116x->atl_active; ep; ep = ep->active) { - ptd = &ep->ptd; - ptd->count = isp116x_read_data16(isp116x); - ptd->mps = isp116x_read_data16(isp116x); - ptd->len = isp116x_read_data16(isp116x); - ptd->faddr = isp116x_read_data16(isp116x); - buflen -= sizeof(struct ptd); - /* Skip reading data for last Setup or Out PTD */ - if (ep->active || (isp116x->atl_last_dir == PTD_DIR_IN)) { - read_ptddata_from_fifo(isp116x, ep->data, ep->length); - buflen -= ALIGN(ep->length, 4); - } - dump_ptd(ptd); - dump_ptd_in_data(ptd, ep->data); - } - BUG_ON(buflen); -} - -/*---------------------------------------------------------------*/ - -/* - Set up PTD's. -*/ -static void preproc_atl_queue(struct isp116x *isp116x) -{ - struct isp116x_ep *ep; - struct urb *urb; - struct ptd *ptd; - u16 len; - - for (ep = isp116x->atl_active; ep; ep = ep->active) { - u16 toggle = 0, dir = PTD_DIR_SETUP; - - BUG_ON(list_empty(&ep->hep->urb_list)); - urb = container_of(ep->hep->urb_list.next, - struct urb, urb_list); - ptd = &ep->ptd; - len = ep->length; - ep->data = (unsigned char *)urb->transfer_buffer - + urb->actual_length; - - switch (ep->nextpid) { - case USB_PID_IN: - toggle = usb_gettoggle(urb->dev, ep->epnum, 0); - dir = PTD_DIR_IN; - break; - case USB_PID_OUT: - toggle = usb_gettoggle(urb->dev, ep->epnum, 1); - dir = PTD_DIR_OUT; - break; - case USB_PID_SETUP: - len = sizeof(struct usb_ctrlrequest); - ep->data = urb->setup_packet; - break; - case USB_PID_ACK: - toggle = 1; - len = 0; - dir = (urb->transfer_buffer_length - && usb_pipein(urb->pipe)) - ? PTD_DIR_OUT : PTD_DIR_IN; - break; - default: - ERR("%s %d: ep->nextpid %d\n", __func__, __LINE__, - ep->nextpid); - BUG(); - } - - ptd->count = PTD_CC_MSK | PTD_ACTIVE_MSK | PTD_TOGGLE(toggle); - ptd->mps = PTD_MPS(ep->maxpacket) - | PTD_SPD(urb->dev->speed == USB_SPEED_LOW) - | PTD_EP(ep->epnum); - ptd->len = PTD_LEN(len) | PTD_DIR(dir); - ptd->faddr = PTD_FA(usb_pipedevice(urb->pipe)); - if (!ep->active) { - ptd->mps |= PTD_LAST_MSK; - isp116x->atl_last_dir = dir; - } - isp116x->atl_bufshrt = sizeof(struct ptd) + isp116x->atl_buflen; - isp116x->atl_buflen = isp116x->atl_bufshrt + ALIGN(len, 4); - } -} - -/* - Take done or failed requests out of schedule. Give back - processed urbs. -*/ -static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep, - struct urb *urb, int status) -__releases(isp116x->lock) __acquires(isp116x->lock) -{ - unsigned i; - - ep->error_count = 0; - - if (usb_pipecontrol(urb->pipe)) - ep->nextpid = USB_PID_SETUP; - - urb_dbg(urb, "Finish"); - - usb_hcd_unlink_urb_from_ep(isp116x_to_hcd(isp116x), urb); - spin_unlock(&isp116x->lock); - usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb, status); - spin_lock(&isp116x->lock); - - /* take idle endpoints out of the schedule */ - if (!list_empty(&ep->hep->urb_list)) - return; - - /* async deschedule */ - if (!list_empty(&ep->schedule)) { - list_del_init(&ep->schedule); - return; - } - - /* periodic deschedule */ - DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch); - for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) { - struct isp116x_ep *temp; - struct isp116x_ep **prev = &isp116x->periodic[i]; - - while (*prev && ((temp = *prev) != ep)) - prev = &temp->next; - if (*prev) - *prev = ep->next; - isp116x->load[i] -= ep->load; - } - ep->branch = PERIODIC_SIZE; - isp116x_to_hcd(isp116x)->self.bandwidth_allocated -= - ep->load / ep->period; - - /* switch irq type? */ - if (!--isp116x->periodic_count) { - isp116x->irqenb &= ~HCuPINT_SOF; - isp116x->irqenb |= HCuPINT_ATL; - } -} - -/* - Analyze transfer results, handle partial transfers and errors -*/ -static void postproc_atl_queue(struct isp116x *isp116x) -{ - struct isp116x_ep *ep; - struct urb *urb; - struct usb_device *udev; - struct ptd *ptd; - int short_not_ok; - int status; - u8 cc; - - for (ep = isp116x->atl_active; ep; ep = ep->active) { - BUG_ON(list_empty(&ep->hep->urb_list)); - urb = - container_of(ep->hep->urb_list.next, struct urb, urb_list); - udev = urb->dev; - ptd = &ep->ptd; - cc = PTD_GET_CC(ptd); - short_not_ok = 1; - status = -EINPROGRESS; - - /* Data underrun is special. For allowed underrun - we clear the error and continue as normal. For - forbidden underrun we finish the DATA stage - immediately while for control transfer, - we do a STATUS stage. */ - if (cc == TD_DATAUNDERRUN) { - if (!(urb->transfer_flags & URB_SHORT_NOT_OK) || - usb_pipecontrol(urb->pipe)) { - DBG("Allowed or control data underrun\n"); - cc = TD_CC_NOERROR; - short_not_ok = 0; - } else { - ep->error_count = 1; - usb_settoggle(udev, ep->epnum, - ep->nextpid == USB_PID_OUT, - PTD_GET_TOGGLE(ptd)); - urb->actual_length += PTD_GET_COUNT(ptd); - status = cc_to_error[TD_DATAUNDERRUN]; - goto done; - } - } - - if (cc != TD_CC_NOERROR && cc != TD_NOTACCESSED - && (++ep->error_count >= 3 || cc == TD_CC_STALL - || cc == TD_DATAOVERRUN)) { - status = cc_to_error[cc]; - if (ep->nextpid == USB_PID_ACK) - ep->nextpid = 0; - goto done; - } - /* According to usb spec, zero-length Int transfer signals - finishing of the urb. Hey, does this apply only - for IN endpoints? */ - if (usb_pipeint(urb->pipe) && !PTD_GET_LEN(ptd)) { - status = 0; - goto done; - } - - /* Relax after previously failed, but later succeeded - or correctly NAK'ed retransmission attempt */ - if (ep->error_count - && (cc == TD_CC_NOERROR || cc == TD_NOTACCESSED)) - ep->error_count = 0; - - /* Take into account idiosyncracies of the isp116x chip - regarding toggle bit for failed transfers */ - if (ep->nextpid == USB_PID_OUT) - usb_settoggle(udev, ep->epnum, 1, PTD_GET_TOGGLE(ptd) - ^ (ep->error_count > 0)); - else if (ep->nextpid == USB_PID_IN) - usb_settoggle(udev, ep->epnum, 0, PTD_GET_TOGGLE(ptd) - ^ (ep->error_count > 0)); - - switch (ep->nextpid) { - case USB_PID_IN: - case USB_PID_OUT: - urb->actual_length += PTD_GET_COUNT(ptd); - if (PTD_GET_ACTIVE(ptd) - || (cc != TD_CC_NOERROR && cc < 0x0E)) - break; - if (urb->transfer_buffer_length != urb->actual_length) { - if (short_not_ok) - break; - } else { - if (urb->transfer_flags & URB_ZERO_PACKET - && ep->nextpid == USB_PID_OUT - && !(PTD_GET_COUNT(ptd) % ep->maxpacket)) { - DBG("Zero packet requested\n"); - break; - } - } - /* All data for this URB is transferred, let's finish */ - if (usb_pipecontrol(urb->pipe)) - ep->nextpid = USB_PID_ACK; - else - status = 0; - break; - case USB_PID_SETUP: - if (PTD_GET_ACTIVE(ptd) - || (cc != TD_CC_NOERROR && cc < 0x0E)) - break; - if (urb->transfer_buffer_length == urb->actual_length) - ep->nextpid = USB_PID_ACK; - else if (usb_pipeout(urb->pipe)) { - usb_settoggle(udev, 0, 1, 1); - ep->nextpid = USB_PID_OUT; - } else { - usb_settoggle(udev, 0, 0, 1); - ep->nextpid = USB_PID_IN; - } - break; - case USB_PID_ACK: - if (PTD_GET_ACTIVE(ptd) - || (cc != TD_CC_NOERROR && cc < 0x0E)) - break; - status = 0; - ep->nextpid = 0; - break; - default: - BUG(); - } - - done: - if (status != -EINPROGRESS || urb->unlinked) - finish_request(isp116x, ep, urb, status); - } -} - -/* - Scan transfer lists, schedule transfers, send data off - to chip. - */ -static void start_atl_transfers(struct isp116x *isp116x) -{ - struct isp116x_ep *last_ep = NULL, *ep; - struct urb *urb; - u16 load = 0; - int len, index, speed, byte_time; - - if (atomic_read(&isp116x->atl_finishing)) - return; - - if (!HC_IS_RUNNING(isp116x_to_hcd(isp116x)->state)) - return; - - /* FIFO not empty? */ - if (isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_FULL) - return; - - isp116x->atl_active = NULL; - isp116x->atl_buflen = isp116x->atl_bufshrt = 0; - - /* Schedule int transfers */ - if (isp116x->periodic_count) { - isp116x->fmindex = index = - (isp116x->fmindex + 1) & (PERIODIC_SIZE - 1); - if ((load = isp116x->load[index])) { - /* Bring all int transfers for this frame - into the active queue */ - isp116x->atl_active = last_ep = - isp116x->periodic[index]; - while (last_ep->next) - last_ep = (last_ep->active = last_ep->next); - last_ep->active = NULL; - } - } - - /* Schedule control/bulk transfers */ - list_for_each_entry(ep, &isp116x->async, schedule) { - urb = container_of(ep->hep->urb_list.next, - struct urb, urb_list); - speed = urb->dev->speed; - byte_time = speed == USB_SPEED_LOW - ? BYTE_TIME_LOWSPEED : BYTE_TIME_FULLSPEED; - - if (ep->nextpid == USB_PID_SETUP) { - len = sizeof(struct usb_ctrlrequest); - } else if (ep->nextpid == USB_PID_ACK) { - len = 0; - } else { - /* Find current free length ... */ - len = (MAX_LOAD_LIMIT - load) / byte_time; - - /* ... then limit it to configured max size ... */ - len = min(len, speed == USB_SPEED_LOW ? - MAX_TRANSFER_SIZE_LOWSPEED : - MAX_TRANSFER_SIZE_FULLSPEED); - - /* ... and finally cut to the multiple of MaxPacketSize, - or to the real length if there's enough room. */ - if (len < - (urb->transfer_buffer_length - - urb->actual_length)) { - len -= len % ep->maxpacket; - if (!len) - continue; - } else - len = urb->transfer_buffer_length - - urb->actual_length; - BUG_ON(len < 0); - } - - load += len * byte_time; - if (load > MAX_LOAD_LIMIT) - break; - - ep->active = NULL; - ep->length = len; - if (last_ep) - last_ep->active = ep; - else - isp116x->atl_active = ep; - last_ep = ep; - } - - /* Avoid starving of endpoints */ - if ((&isp116x->async)->next != (&isp116x->async)->prev) - list_move(&isp116x->async, (&isp116x->async)->next); - - if (isp116x->atl_active) { - preproc_atl_queue(isp116x); - pack_fifo(isp116x); - } -} - -/* - Finish the processed transfers -*/ -static void finish_atl_transfers(struct isp116x *isp116x) -{ - if (!isp116x->atl_active) - return; - /* Fifo not ready? */ - if (!(isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_DONE)) - return; - - atomic_inc(&isp116x->atl_finishing); - unpack_fifo(isp116x); - postproc_atl_queue(isp116x); - atomic_dec(&isp116x->atl_finishing); -} - -static irqreturn_t isp116x_irq(struct usb_hcd *hcd) -{ - struct isp116x *isp116x = hcd_to_isp116x(hcd); - u16 irqstat; - irqreturn_t ret = IRQ_NONE; - - spin_lock(&isp116x->lock); - isp116x_write_reg16(isp116x, HCuPINTENB, 0); - irqstat = isp116x_read_reg16(isp116x, HCuPINT); - isp116x_write_reg16(isp116x, HCuPINT, irqstat); - - if (irqstat & (HCuPINT_ATL | HCuPINT_SOF)) { - ret = IRQ_HANDLED; - finish_atl_transfers(isp116x); - } - - if (irqstat & HCuPINT_OPR) { - u32 intstat = isp116x_read_reg32(isp116x, HCINTSTAT); - isp116x_write_reg32(isp116x, HCINTSTAT, intstat); - if (intstat & HCINT_UE) { - ERR("Unrecoverable error, HC is dead!\n"); - /* IRQ's are off, we do no DMA, - perfectly ready to die ... */ - hcd->state = HC_STATE_HALT; - usb_hc_died(hcd); - ret = IRQ_HANDLED; - goto done; - } - if (intstat & HCINT_RHSC) - /* When root hub or any of its ports is going - to come out of suspend, it may take more - than 10ms for status bits to stabilize. */ - mod_timer(&hcd->rh_timer, jiffies - + msecs_to_jiffies(20) + 1); - if (intstat & HCINT_RD) { - DBG("---- remote wakeup\n"); - usb_hcd_resume_root_hub(hcd); - } - irqstat &= ~HCuPINT_OPR; - ret = IRQ_HANDLED; - } - - if (irqstat & (HCuPINT_ATL | HCuPINT_SOF)) { - start_atl_transfers(isp116x); - } - - isp116x_write_reg16(isp116x, HCuPINTENB, isp116x->irqenb); - done: - spin_unlock(&isp116x->lock); - return ret; -} - -/*-----------------------------------------------------------------*/ - -/* usb 1.1 says max 90% of a frame is available for periodic transfers. - * this driver doesn't promise that much since it's got to handle an - * IRQ per packet; irq handling latencies also use up that time. - */ - -/* out of 1000 us */ -#define MAX_PERIODIC_LOAD 600 -static int balance(struct isp116x *isp116x, u16 period, u16 load) -{ - int i, branch = -ENOSPC; - - /* search for the least loaded schedule branch of that period - which has enough bandwidth left unreserved. */ - for (i = 0; i < period; i++) { - if (branch < 0 || isp116x->load[branch] > isp116x->load[i]) { - int j; - - for (j = i; j < PERIODIC_SIZE; j += period) { - if ((isp116x->load[j] + load) - > MAX_PERIODIC_LOAD) - break; - } - if (j < PERIODIC_SIZE) - continue; - branch = i; - } - } - return branch; -} - -/* NB! ALL the code above this point runs with isp116x->lock - held, irqs off -*/ - -/*-----------------------------------------------------------------*/ - -static int isp116x_urb_enqueue(struct usb_hcd *hcd, - struct urb *urb, - gfp_t mem_flags) -{ - struct isp116x *isp116x = hcd_to_isp116x(hcd); - struct usb_device *udev = urb->dev; - unsigned int pipe = urb->pipe; - int is_out = !usb_pipein(pipe); - int type = usb_pipetype(pipe); - int epnum = usb_pipeendpoint(pipe); - struct usb_host_endpoint *hep = urb->ep; - struct isp116x_ep *ep = NULL; - unsigned long flags; - int i; - int ret = 0; - - urb_dbg(urb, "Enqueue"); - - if (type == PIPE_ISOCHRONOUS) { - ERR("Isochronous transfers not supported\n"); - urb_dbg(urb, "Refused to enqueue"); - return -ENXIO; - } - /* avoid all allocations within spinlocks: request or endpoint */ - if (!hep->hcpriv) { - ep = kzalloc(sizeof *ep, mem_flags); - if (!ep) - return -ENOMEM; - } - - spin_lock_irqsave(&isp116x->lock, flags); - if (!HC_IS_RUNNING(hcd->state)) { - kfree(ep); - ret = -ENODEV; - goto fail_not_linked; - } - ret = usb_hcd_link_urb_to_ep(hcd, urb); - if (ret) { - kfree(ep); - goto fail_not_linked; - } - - if (hep->hcpriv) - ep = hep->hcpriv; - else { - INIT_LIST_HEAD(&ep->schedule); - ep->udev = udev; - ep->epnum = epnum; - ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out); - usb_settoggle(udev, epnum, is_out, 0); - - if (type == PIPE_CONTROL) { - ep->nextpid = USB_PID_SETUP; - } else if (is_out) { - ep->nextpid = USB_PID_OUT; - } else { - ep->nextpid = USB_PID_IN; - } - - if (urb->interval) { - /* - With INT URBs submitted, the driver works with SOF - interrupt enabled and ATL interrupt disabled. After - the PTDs are written to fifo ram, the chip starts - fifo processing and usb transfers after the next - SOF and continues until the transfers are finished - (succeeded or failed) or the frame ends. Therefore, - the transfers occur only in every second frame, - while fifo reading/writing and data processing - occur in every other second frame. */ - if (urb->interval < 2) - urb->interval = 2; - if (urb->interval > 2 * PERIODIC_SIZE) - urb->interval = 2 * PERIODIC_SIZE; - ep->period = urb->interval >> 1; - ep->branch = PERIODIC_SIZE; - ep->load = usb_calc_bus_time(udev->speed, - !is_out, - (type == PIPE_ISOCHRONOUS), - usb_maxpacket(udev, pipe, - is_out)) / - 1000; - } - hep->hcpriv = ep; - ep->hep = hep; - } - - /* maybe put endpoint into schedule */ - switch (type) { - case PIPE_CONTROL: - case PIPE_BULK: - if (list_empty(&ep->schedule)) - list_add_tail(&ep->schedule, &isp116x->async); - break; - case PIPE_INTERRUPT: - urb->interval = ep->period; - ep->length = min_t(u32, ep->maxpacket, - urb->transfer_buffer_length); - - /* urb submitted for already existing endpoint */ - if (ep->branch < PERIODIC_SIZE) - break; - - ep->branch = ret = balance(isp116x, ep->period, ep->load); - if (ret < 0) - goto fail; - ret = 0; - - urb->start_frame = (isp116x->fmindex & (PERIODIC_SIZE - 1)) - + ep->branch; - - /* sort each schedule branch by period (slow before fast) - to share the faster parts of the tree without needing - dummy/placeholder nodes */ - DBG("schedule qh%d/%p branch %d\n", ep->period, ep, ep->branch); - for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) { - struct isp116x_ep **prev = &isp116x->periodic[i]; - struct isp116x_ep *here = *prev; - - while (here && ep != here) { - if (ep->period > here->period) - break; - prev = &here->next; - here = *prev; - } - if (ep != here) { - ep->next = here; - *prev = ep; - } - isp116x->load[i] += ep->load; - } - hcd->self.bandwidth_allocated += ep->load / ep->period; - - /* switch over to SOFint */ - if (!isp116x->periodic_count++) { - isp116x->irqenb &= ~HCuPINT_ATL; - isp116x->irqenb |= HCuPINT_SOF; - isp116x_write_reg16(isp116x, HCuPINTENB, - isp116x->irqenb); - } - } - - urb->hcpriv = hep; - start_atl_transfers(isp116x); - - fail: - if (ret) - usb_hcd_unlink_urb_from_ep(hcd, urb); - fail_not_linked: - spin_unlock_irqrestore(&isp116x->lock, flags); - return ret; -} - -/* - Dequeue URBs. -*/ -static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, - int status) -{ - struct isp116x *isp116x = hcd_to_isp116x(hcd); - struct usb_host_endpoint *hep; - struct isp116x_ep *ep, *ep_act; - unsigned long flags; - int rc; - - spin_lock_irqsave(&isp116x->lock, flags); - rc = usb_hcd_check_unlink_urb(hcd, urb, status); - if (rc) - goto done; - - hep = urb->hcpriv; - ep = hep->hcpriv; - WARN_ON(hep != ep->hep); - - /* In front of queue? */ - if (ep->hep->urb_list.next == &urb->urb_list) - /* active? */ - for (ep_act = isp116x->atl_active; ep_act; - ep_act = ep_act->active) - if (ep_act == ep) { - VDBG("dequeue, urb %p active; wait for irq\n", - urb); - urb = NULL; - break; - } - - if (urb) - finish_request(isp116x, ep, urb, status); - done: - spin_unlock_irqrestore(&isp116x->lock, flags); - return rc; -} - -static void isp116x_endpoint_disable(struct usb_hcd *hcd, - struct usb_host_endpoint *hep) -{ - int i; - struct isp116x_ep *ep = hep->hcpriv; - - if (!ep) - return; - - /* assume we'd just wait for the irq */ - for (i = 0; i < 100 && !list_empty(&hep->urb_list); i++) - msleep(3); - if (!list_empty(&hep->urb_list)) - WARNING("ep %p not empty?\n", ep); - - kfree(ep); - hep->hcpriv = NULL; -} - -static int isp116x_get_frame(struct usb_hcd *hcd) -{ - struct isp116x *isp116x = hcd_to_isp116x(hcd); - u32 fmnum; - unsigned long flags; - - spin_lock_irqsave(&isp116x->lock, flags); - fmnum = isp116x_read_reg32(isp116x, HCFMNUM); - spin_unlock_irqrestore(&isp116x->lock, flags); - return (int)fmnum; -} - -/* - Adapted from ohci-hub.c. Currently we don't support autosuspend. -*/ -static int isp116x_hub_status_data(struct usb_hcd *hcd, char *buf) -{ - struct isp116x *isp116x = hcd_to_isp116x(hcd); - int ports, i, changed = 0; - unsigned long flags; - - if (!HC_IS_RUNNING(hcd->state)) - return -ESHUTDOWN; - - /* Report no status change now, if we are scheduled to be - called later */ - if (timer_pending(&hcd->rh_timer)) - return 0; - - ports = isp116x->rhdesca & RH_A_NDP; - spin_lock_irqsave(&isp116x->lock, flags); - isp116x->rhstatus = isp116x_read_reg32(isp116x, HCRHSTATUS); - if (isp116x->rhstatus & (RH_HS_LPSC | RH_HS_OCIC)) - buf[0] = changed = 1; - else - buf[0] = 0; - - for (i = 0; i < ports; i++) { - u32 status = isp116x_read_reg32(isp116x, i ? HCRHPORT2 : HCRHPORT1); - - if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC - | RH_PS_OCIC | RH_PS_PRSC)) { - changed = 1; - buf[0] |= 1 << (i + 1); - } - } - spin_unlock_irqrestore(&isp116x->lock, flags); - return changed; -} - -static void isp116x_hub_descriptor(struct isp116x *isp116x, - struct usb_hub_descriptor *desc) -{ - u32 reg = isp116x->rhdesca; - - desc->bDescriptorType = 0x29; - desc->bDescLength = 9; - desc->bHubContrCurrent = 0; - desc->bNbrPorts = (u8) (reg & 0x3); - /* Power switching, device type, overcurrent. */ - desc->wHubCharacteristics = cpu_to_le16((u16) ((reg >> 8) & 0x1f)); - desc->bPwrOn2PwrGood = (u8) ((reg >> 24) & 0xff); - /* ports removable, and legacy PortPwrCtrlMask */ - desc->u.hs.DeviceRemovable[0] = 0; - desc->u.hs.DeviceRemovable[1] = ~0; -} - -/* Perform reset of a given port. - It would be great to just start the reset and let the - USB core to clear the reset in due time. However, - root hub ports should be reset for at least 50 ms, while - our chip stays in reset for about 10 ms. I.e., we must - repeatedly reset it ourself here. -*/ -static inline void root_port_reset(struct isp116x *isp116x, unsigned port) -{ - u32 tmp; - unsigned long flags, t; - - /* Root hub reset should be 50 ms, but some devices - want it even longer. */ - t = jiffies + msecs_to_jiffies(100); - - while (time_before(jiffies, t)) { - spin_lock_irqsave(&isp116x->lock, flags); - /* spin until any current reset finishes */ - for (;;) { - tmp = isp116x_read_reg32(isp116x, port ? - HCRHPORT2 : HCRHPORT1); - if (!(tmp & RH_PS_PRS)) - break; - udelay(500); - } - /* Don't reset a disconnected port */ - if (!(tmp & RH_PS_CCS)) { - spin_unlock_irqrestore(&isp116x->lock, flags); - break; - } - /* Reset lasts 10ms (claims datasheet) */ - isp116x_write_reg32(isp116x, port ? HCRHPORT2 : - HCRHPORT1, (RH_PS_PRS)); - spin_unlock_irqrestore(&isp116x->lock, flags); - msleep(10); - } -} - -/* Adapted from ohci-hub.c */ -static int isp116x_hub_control(struct usb_hcd *hcd, - u16 typeReq, - u16 wValue, u16 wIndex, char *buf, u16 wLength) -{ - struct isp116x *isp116x = hcd_to_isp116x(hcd); - int ret = 0; - unsigned long flags; - int ports = isp116x->rhdesca & RH_A_NDP; - u32 tmp = 0; - - switch (typeReq) { - case ClearHubFeature: - DBG("ClearHubFeature: "); - switch (wValue) { - case C_HUB_OVER_CURRENT: - DBG("C_HUB_OVER_CURRENT\n"); - spin_lock_irqsave(&isp116x->lock, flags); - isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_OCIC); - spin_unlock_irqrestore(&isp116x->lock, flags); - case C_HUB_LOCAL_POWER: - DBG("C_HUB_LOCAL_POWER\n"); - break; - default: - goto error; - } - break; - case SetHubFeature: - DBG("SetHubFeature: "); - switch (wValue) { - case C_HUB_OVER_CURRENT: - case C_HUB_LOCAL_POWER: - DBG("C_HUB_OVER_CURRENT or C_HUB_LOCAL_POWER\n"); - break; - default: - goto error; - } - break; - case GetHubDescriptor: - DBG("GetHubDescriptor\n"); - isp116x_hub_descriptor(isp116x, - (struct usb_hub_descriptor *)buf); - break; - case GetHubStatus: - DBG("GetHubStatus\n"); - *(__le32 *) buf = 0; - break; - case GetPortStatus: - DBG("GetPortStatus\n"); - if (!wIndex || wIndex > ports) - goto error; - spin_lock_irqsave(&isp116x->lock, flags); - tmp = isp116x_read_reg32(isp116x, (--wIndex) ? HCRHPORT2 : HCRHPORT1); - spin_unlock_irqrestore(&isp116x->lock, flags); - *(__le32 *) buf = cpu_to_le32(tmp); - DBG("GetPortStatus: port[%d] %08x\n", wIndex + 1, tmp); - break; - case ClearPortFeature: - DBG("ClearPortFeature: "); - if (!wIndex || wIndex > ports) - goto error; - wIndex--; - - switch (wValue) { - case USB_PORT_FEAT_ENABLE: - DBG("USB_PORT_FEAT_ENABLE\n"); - tmp = RH_PS_CCS; - break; - case USB_PORT_FEAT_C_ENABLE: - DBG("USB_PORT_FEAT_C_ENABLE\n"); - tmp = RH_PS_PESC; - break; - case USB_PORT_FEAT_SUSPEND: - DBG("USB_PORT_FEAT_SUSPEND\n"); - tmp = RH_PS_POCI; - break; - case USB_PORT_FEAT_C_SUSPEND: - DBG("USB_PORT_FEAT_C_SUSPEND\n"); - tmp = RH_PS_PSSC; - break; - case USB_PORT_FEAT_POWER: - DBG("USB_PORT_FEAT_POWER\n"); - tmp = RH_PS_LSDA; - break; - case USB_PORT_FEAT_C_CONNECTION: - DBG("USB_PORT_FEAT_C_CONNECTION\n"); - tmp = RH_PS_CSC; - break; - case USB_PORT_FEAT_C_OVER_CURRENT: - DBG("USB_PORT_FEAT_C_OVER_CURRENT\n"); - tmp = RH_PS_OCIC; - break; - case USB_PORT_FEAT_C_RESET: - DBG("USB_PORT_FEAT_C_RESET\n"); - tmp = RH_PS_PRSC; - break; - default: - goto error; - } - spin_lock_irqsave(&isp116x->lock, flags); - isp116x_write_reg32(isp116x, wIndex - ? HCRHPORT2 : HCRHPORT1, tmp); - spin_unlock_irqrestore(&isp116x->lock, flags); - break; - case SetPortFeature: - DBG("SetPortFeature: "); - if (!wIndex || wIndex > ports) - goto error; - wIndex--; - switch (wValue) { - case USB_PORT_FEAT_SUSPEND: - DBG("USB_PORT_FEAT_SUSPEND\n"); - spin_lock_irqsave(&isp116x->lock, flags); - isp116x_write_reg32(isp116x, wIndex - ? HCRHPORT2 : HCRHPORT1, RH_PS_PSS); - spin_unlock_irqrestore(&isp116x->lock, flags); - break; - case USB_PORT_FEAT_POWER: - DBG("USB_PORT_FEAT_POWER\n"); - spin_lock_irqsave(&isp116x->lock, flags); - isp116x_write_reg32(isp116x, wIndex - ? HCRHPORT2 : HCRHPORT1, RH_PS_PPS); - spin_unlock_irqrestore(&isp116x->lock, flags); - break; - case USB_PORT_FEAT_RESET: - DBG("USB_PORT_FEAT_RESET\n"); - root_port_reset(isp116x, wIndex); - break; - default: - goto error; - } - break; - - default: - error: - /* "protocol stall" on error */ - DBG("PROTOCOL STALL\n"); - ret = -EPIPE; - } - return ret; -} - -/*-----------------------------------------------------------------*/ - -#ifdef CONFIG_DEBUG_FS - -static void dump_irq(struct seq_file *s, char *label, u16 mask) -{ - seq_printf(s, "%s %04x%s%s%s%s%s%s\n", label, mask, - mask & HCuPINT_CLKRDY ? " clkrdy" : "", - mask & HCuPINT_SUSP ? " susp" : "", - mask & HCuPINT_OPR ? " opr" : "", - mask & HCuPINT_AIIEOT ? " eot" : "", - mask & HCuPINT_ATL ? " atl" : "", - mask & HCuPINT_SOF ? " sof" : ""); -} - -static void dump_int(struct seq_file *s, char *label, u32 mask) -{ - seq_printf(s, "%s %08x%s%s%s%s%s%s%s\n", label, mask, - mask & HCINT_MIE ? " MIE" : "", - mask & HCINT_RHSC ? " rhsc" : "", - mask & HCINT_FNO ? " fno" : "", - mask & HCINT_UE ? " ue" : "", - mask & HCINT_RD ? " rd" : "", - mask & HCINT_SF ? " sof" : "", mask & HCINT_SO ? " so" : ""); -} - -static int isp116x_show_dbg(struct seq_file *s, void *unused) -{ - struct isp116x *isp116x = s->private; - - seq_printf(s, "%s\n%s version %s\n", - isp116x_to_hcd(isp116x)->product_desc, hcd_name, - DRIVER_VERSION); - - if (HC_IS_SUSPENDED(isp116x_to_hcd(isp116x)->state)) { - seq_printf(s, "HCD is suspended\n"); - return 0; - } - if (!HC_IS_RUNNING(isp116x_to_hcd(isp116x)->state)) { - seq_printf(s, "HCD not running\n"); - return 0; - } - - spin_lock_irq(&isp116x->lock); - dump_irq(s, "hc_irq_enable", isp116x_read_reg16(isp116x, HCuPINTENB)); - dump_irq(s, "hc_irq_status", isp116x_read_reg16(isp116x, HCuPINT)); - dump_int(s, "hc_int_enable", isp116x_read_reg32(isp116x, HCINTENB)); - dump_int(s, "hc_int_status", isp116x_read_reg32(isp116x, HCINTSTAT)); - isp116x_show_regs_seq(isp116x, s); - spin_unlock_irq(&isp116x->lock); - seq_printf(s, "\n"); - - return 0; -} - -static int isp116x_open_seq(struct inode *inode, struct file *file) -{ - return single_open(file, isp116x_show_dbg, inode->i_private); -} - -static const struct file_operations isp116x_debug_fops = { - .open = isp116x_open_seq, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int create_debug_file(struct isp116x *isp116x) -{ - isp116x->dentry = debugfs_create_file(hcd_name, - S_IRUGO, NULL, isp116x, - &isp116x_debug_fops); - if (!isp116x->dentry) - return -ENOMEM; - return 0; -} - -static void remove_debug_file(struct isp116x *isp116x) -{ - debugfs_remove(isp116x->dentry); -} - -#else - -#define create_debug_file(d) 0 -#define remove_debug_file(d) do{}while(0) - -#endif /* CONFIG_DEBUG_FS */ - -/*-----------------------------------------------------------------*/ - -/* - Software reset - can be called from any contect. -*/ -static int isp116x_sw_reset(struct isp116x *isp116x) -{ - int retries = 15; - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&isp116x->lock, flags); - isp116x_write_reg16(isp116x, HCSWRES, HCSWRES_MAGIC); - isp116x_write_reg32(isp116x, HCCMDSTAT, HCCMDSTAT_HCR); - while (--retries) { - /* It usually resets within 1 ms */ - mdelay(1); - if (!(isp116x_read_reg32(isp116x, HCCMDSTAT) & HCCMDSTAT_HCR)) - break; - } - if (!retries) { - ERR("Software reset timeout\n"); - ret = -ETIME; - } - spin_unlock_irqrestore(&isp116x->lock, flags); - return ret; -} - -static int isp116x_reset(struct usb_hcd *hcd) -{ - struct isp116x *isp116x = hcd_to_isp116x(hcd); - unsigned long t; - u16 clkrdy = 0; - int ret, timeout = 15 /* ms */ ; - - ret = isp116x_sw_reset(isp116x); - if (ret) - return ret; - - t = jiffies + msecs_to_jiffies(timeout); - while (time_before_eq(jiffies, t)) { - msleep(4); - spin_lock_irq(&isp116x->lock); - clkrdy = isp116x_read_reg16(isp116x, HCuPINT) & HCuPINT_CLKRDY; - spin_unlock_irq(&isp116x->lock); - if (clkrdy) - break; - } - if (!clkrdy) { - ERR("Clock not ready after %dms\n", timeout); - /* After sw_reset the clock won't report to be ready, if - H_WAKEUP pin is high. */ - ERR("Please make sure that the H_WAKEUP pin is pulled low!\n"); - ret = -ENODEV; - } - return ret; -} - -static void isp116x_stop(struct usb_hcd *hcd) -{ - struct isp116x *isp116x = hcd_to_isp116x(hcd); - unsigned long flags; - u32 val; - - spin_lock_irqsave(&isp116x->lock, flags); - isp116x_write_reg16(isp116x, HCuPINTENB, 0); - - /* Switch off ports' power, some devices don't come up - after next 'insmod' without this */ - val = isp116x_read_reg32(isp116x, HCRHDESCA); - val &= ~(RH_A_NPS | RH_A_PSM); - isp116x_write_reg32(isp116x, HCRHDESCA, val); - isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPS); - spin_unlock_irqrestore(&isp116x->lock, flags); - - isp116x_sw_reset(isp116x); -} - -/* - Configure the chip. The chip must be successfully reset by now. -*/ -static int isp116x_start(struct usb_hcd *hcd) -{ - struct isp116x *isp116x = hcd_to_isp116x(hcd); - struct isp116x_platform_data *board = isp116x->board; - u32 val; - unsigned long flags; - - spin_lock_irqsave(&isp116x->lock, flags); - - /* clear interrupt status and disable all interrupt sources */ - isp116x_write_reg16(isp116x, HCuPINT, 0xff); - isp116x_write_reg16(isp116x, HCuPINTENB, 0); - - val = isp116x_read_reg16(isp116x, HCCHIPID); - if ((val & HCCHIPID_MASK) != HCCHIPID_MAGIC) { - ERR("Invalid chip ID %04x\n", val); - spin_unlock_irqrestore(&isp116x->lock, flags); - return -ENODEV; - } - - /* To be removed in future */ - hcd->uses_new_polling = 1; - - isp116x_write_reg16(isp116x, HCITLBUFLEN, ISP116x_ITL_BUFSIZE); - isp116x_write_reg16(isp116x, HCATLBUFLEN, ISP116x_ATL_BUFSIZE); - - /* ----- HW conf */ - val = HCHWCFG_INT_ENABLE | HCHWCFG_DBWIDTH(1); - if (board->sel15Kres) - val |= HCHWCFG_15KRSEL; - /* Remote wakeup won't work without working clock */ - if (board->remote_wakeup_enable) - val |= HCHWCFG_CLKNOTSTOP; - if (board->oc_enable) - val |= HCHWCFG_ANALOG_OC; - if (board->int_act_high) - val |= HCHWCFG_INT_POL; - if (board->int_edge_triggered) - val |= HCHWCFG_INT_TRIGGER; - isp116x_write_reg16(isp116x, HCHWCFG, val); - - /* ----- Root hub conf */ - val = (25 << 24) & RH_A_POTPGT; - /* AN10003_1.pdf recommends RH_A_NPS (no power switching) to - be always set. Yet, instead, we request individual port - power switching. */ - val |= RH_A_PSM; - /* Report overcurrent per port */ - val |= RH_A_OCPM; - isp116x_write_reg32(isp116x, HCRHDESCA, val); - isp116x->rhdesca = isp116x_read_reg32(isp116x, HCRHDESCA); - - val = RH_B_PPCM; - isp116x_write_reg32(isp116x, HCRHDESCB, val); - isp116x->rhdescb = isp116x_read_reg32(isp116x, HCRHDESCB); - - val = 0; - if (board->remote_wakeup_enable) { - if (!device_can_wakeup(hcd->self.controller)) - device_init_wakeup(hcd->self.controller, 1); - val |= RH_HS_DRWE; - } - isp116x_write_reg32(isp116x, HCRHSTATUS, val); - isp116x->rhstatus = isp116x_read_reg32(isp116x, HCRHSTATUS); - - isp116x_write_reg32(isp116x, HCFMINTVL, 0x27782edf); - - hcd->state = HC_STATE_RUNNING; - - /* Set up interrupts */ - isp116x->intenb = HCINT_MIE | HCINT_RHSC | HCINT_UE; - if (board->remote_wakeup_enable) - isp116x->intenb |= HCINT_RD; - isp116x->irqenb = HCuPINT_ATL | HCuPINT_OPR; /* | HCuPINT_SUSP; */ - isp116x_write_reg32(isp116x, HCINTENB, isp116x->intenb); - isp116x_write_reg16(isp116x, HCuPINTENB, isp116x->irqenb); - - /* Go operational */ - val = HCCONTROL_USB_OPER; - if (board->remote_wakeup_enable) - val |= HCCONTROL_RWE; - isp116x_write_reg32(isp116x, HCCONTROL, val); - - /* Disable ports to avoid race in device enumeration */ - isp116x_write_reg32(isp116x, HCRHPORT1, RH_PS_CCS); - isp116x_write_reg32(isp116x, HCRHPORT2, RH_PS_CCS); - - isp116x_show_regs_log(isp116x); - spin_unlock_irqrestore(&isp116x->lock, flags); - return 0; -} - -#ifdef CONFIG_PM - -static int isp116x_bus_suspend(struct usb_hcd *hcd) -{ - struct isp116x *isp116x = hcd_to_isp116x(hcd); - unsigned long flags; - u32 val; - int ret = 0; - - spin_lock_irqsave(&isp116x->lock, flags); - val = isp116x_read_reg32(isp116x, HCCONTROL); - - switch (val & HCCONTROL_HCFS) { - case HCCONTROL_USB_OPER: - spin_unlock_irqrestore(&isp116x->lock, flags); - val &= (~HCCONTROL_HCFS & ~HCCONTROL_RWE); - val |= HCCONTROL_USB_SUSPEND; - if (hcd->self.root_hub->do_remote_wakeup) - val |= HCCONTROL_RWE; - /* Wait for usb transfers to finish */ - msleep(2); - spin_lock_irqsave(&isp116x->lock, flags); - isp116x_write_reg32(isp116x, HCCONTROL, val); - spin_unlock_irqrestore(&isp116x->lock, flags); - /* Wait for devices to suspend */ - msleep(5); - break; - case HCCONTROL_USB_RESUME: - isp116x_write_reg32(isp116x, HCCONTROL, - (val & ~HCCONTROL_HCFS) | - HCCONTROL_USB_RESET); - case HCCONTROL_USB_RESET: - ret = -EBUSY; - default: /* HCCONTROL_USB_SUSPEND */ - spin_unlock_irqrestore(&isp116x->lock, flags); - break; - } - - return ret; -} - -static int isp116x_bus_resume(struct usb_hcd *hcd) -{ - struct isp116x *isp116x = hcd_to_isp116x(hcd); - u32 val; - - msleep(5); - spin_lock_irq(&isp116x->lock); - - val = isp116x_read_reg32(isp116x, HCCONTROL); - switch (val & HCCONTROL_HCFS) { - case HCCONTROL_USB_SUSPEND: - val &= ~HCCONTROL_HCFS; - val |= HCCONTROL_USB_RESUME; - isp116x_write_reg32(isp116x, HCCONTROL, val); - case HCCONTROL_USB_RESUME: - break; - case HCCONTROL_USB_OPER: - spin_unlock_irq(&isp116x->lock); - return 0; - default: - /* HCCONTROL_USB_RESET: this may happen, when during - suspension the HC lost power. Reinitialize completely */ - spin_unlock_irq(&isp116x->lock); - DBG("Chip has been reset while suspended. Reinit from scratch.\n"); - isp116x_reset(hcd); - isp116x_start(hcd); - isp116x_hub_control(hcd, SetPortFeature, - USB_PORT_FEAT_POWER, 1, NULL, 0); - if ((isp116x->rhdesca & RH_A_NDP) == 2) - isp116x_hub_control(hcd, SetPortFeature, - USB_PORT_FEAT_POWER, 2, NULL, 0); - return 0; - } - - val = isp116x->rhdesca & RH_A_NDP; - while (val--) { - u32 stat = - isp116x_read_reg32(isp116x, val ? HCRHPORT2 : HCRHPORT1); - /* force global, not selective, resume */ - if (!(stat & RH_PS_PSS)) - continue; - DBG("%s: Resuming port %d\n", __func__, val); - isp116x_write_reg32(isp116x, RH_PS_POCI, val - ? HCRHPORT2 : HCRHPORT1); - } - spin_unlock_irq(&isp116x->lock); - - hcd->state = HC_STATE_RESUMING; - msleep(20); - - /* Go operational */ - spin_lock_irq(&isp116x->lock); - val = isp116x_read_reg32(isp116x, HCCONTROL); - isp116x_write_reg32(isp116x, HCCONTROL, - (val & ~HCCONTROL_HCFS) | HCCONTROL_USB_OPER); - spin_unlock_irq(&isp116x->lock); - hcd->state = HC_STATE_RUNNING; - - return 0; -} - -#else - -#define isp116x_bus_suspend NULL -#define isp116x_bus_resume NULL - -#endif - -static struct hc_driver isp116x_hc_driver = { - .description = hcd_name, - .product_desc = "ISP116x Host Controller", - .hcd_priv_size = sizeof(struct isp116x), - - .irq = isp116x_irq, - .flags = HCD_USB11, - - .reset = isp116x_reset, - .start = isp116x_start, - .stop = isp116x_stop, - - .urb_enqueue = isp116x_urb_enqueue, - .urb_dequeue = isp116x_urb_dequeue, - .endpoint_disable = isp116x_endpoint_disable, - - .get_frame_number = isp116x_get_frame, - - .hub_status_data = isp116x_hub_status_data, - .hub_control = isp116x_hub_control, - .bus_suspend = isp116x_bus_suspend, - .bus_resume = isp116x_bus_resume, -}; - -/*----------------------------------------------------------------*/ - -static int isp116x_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct isp116x *isp116x; - struct resource *res; - - if (!hcd) - return 0; - isp116x = hcd_to_isp116x(hcd); - remove_debug_file(isp116x); - usb_remove_hcd(hcd); - - iounmap(isp116x->data_reg); - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - release_mem_region(res->start, 2); - iounmap(isp116x->addr_reg); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, 2); - - usb_put_hcd(hcd); - return 0; -} - -static int __devinit isp116x_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - struct isp116x *isp116x; - struct resource *addr, *data, *ires; - void __iomem *addr_reg; - void __iomem *data_reg; - int irq; - int ret = 0; - unsigned long irqflags; - - if (usb_disabled()) - return -ENODEV; - - if (pdev->num_resources < 3) { - ret = -ENODEV; - goto err1; - } - - data = platform_get_resource(pdev, IORESOURCE_MEM, 0); - addr = platform_get_resource(pdev, IORESOURCE_MEM, 1); - ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - - if (!addr || !data || !ires) { - ret = -ENODEV; - goto err1; - } - - irq = ires->start; - irqflags = ires->flags & IRQF_TRIGGER_MASK; - - if (pdev->dev.dma_mask) { - DBG("DMA not supported\n"); - ret = -EINVAL; - goto err1; - } - - if (!request_mem_region(addr->start, 2, hcd_name)) { - ret = -EBUSY; - goto err1; - } - addr_reg = ioremap(addr->start, resource_size(addr)); - if (addr_reg == NULL) { - ret = -ENOMEM; - goto err2; - } - if (!request_mem_region(data->start, 2, hcd_name)) { - ret = -EBUSY; - goto err3; - } - data_reg = ioremap(data->start, resource_size(data)); - if (data_reg == NULL) { - ret = -ENOMEM; - goto err4; - } - - /* allocate and initialize hcd */ - hcd = usb_create_hcd(&isp116x_hc_driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - ret = -ENOMEM; - goto err5; - } - /* this rsrc_start is bogus */ - hcd->rsrc_start = addr->start; - isp116x = hcd_to_isp116x(hcd); - isp116x->data_reg = data_reg; - isp116x->addr_reg = addr_reg; - spin_lock_init(&isp116x->lock); - INIT_LIST_HEAD(&isp116x->async); - isp116x->board = pdev->dev.platform_data; - - if (!isp116x->board) { - ERR("Platform data structure not initialized\n"); - ret = -ENODEV; - goto err6; - } - if (isp116x_check_platform_delay(isp116x)) { - ERR("USE_PLATFORM_DELAY defined, but delay function not " - "implemented.\n"); - ERR("See comments in drivers/usb/host/isp116x-hcd.c\n"); - ret = -ENODEV; - goto err6; - } - - ret = usb_add_hcd(hcd, irq, irqflags); - if (ret) - goto err6; - - ret = create_debug_file(isp116x); - if (ret) { - ERR("Couldn't create debugfs entry\n"); - goto err7; - } - - return 0; - - err7: - usb_remove_hcd(hcd); - err6: - usb_put_hcd(hcd); - err5: - iounmap(data_reg); - err4: - release_mem_region(data->start, 2); - err3: - iounmap(addr_reg); - err2: - release_mem_region(addr->start, 2); - err1: - ERR("init error, %d\n", ret); - return ret; -} - -#ifdef CONFIG_PM -/* - Suspend of platform device -*/ -static int isp116x_suspend(struct platform_device *dev, pm_message_t state) -{ - VDBG("%s: state %x\n", __func__, state.event); - return 0; -} - -/* - Resume platform device -*/ -static int isp116x_resume(struct platform_device *dev) -{ - VDBG("%s\n", __func__); - return 0; -} - -#else - -#define isp116x_suspend NULL -#define isp116x_resume NULL - -#endif - -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:isp116x-hcd"); - -static struct platform_driver isp116x_driver = { - .probe = isp116x_probe, - .remove = isp116x_remove, - .suspend = isp116x_suspend, - .resume = isp116x_resume, - .driver = { - .name = (char *)hcd_name, - .owner = THIS_MODULE, - }, -}; - -module_platform_driver(isp116x_driver); diff --git a/ANDROID_3.4.5/drivers/usb/host/isp116x.h b/ANDROID_3.4.5/drivers/usb/host/isp116x.h deleted file mode 100644 index 9a2c400e..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/isp116x.h +++ /dev/null @@ -1,606 +0,0 @@ -/* - * ISP116x register declarations and HCD data structures - * - * Copyright (C) 2005 Olav Kongas - * Portions: - * Copyright (C) 2004 Lothar Wassmann - * Copyright (C) 2004 Psion Teklogix - * Copyright (C) 2004 David Brownell - */ - -/* us of 1ms frame */ -#define MAX_LOAD_LIMIT 850 - -/* Full speed: max # of bytes to transfer for a single urb - at a time must be < 1024 && must be multiple of 64. - 832 allows transferring 4kiB within 5 frames. */ -#define MAX_TRANSFER_SIZE_FULLSPEED 832 - -/* Low speed: there is no reason to schedule in very big - chunks; often the requested long transfers are for - string descriptors containing short strings. */ -#define MAX_TRANSFER_SIZE_LOWSPEED 64 - -/* Bytetime (us), a rough indication of how much time it - would take to transfer a byte of useful data over USB */ -#define BYTE_TIME_FULLSPEED 1 -#define BYTE_TIME_LOWSPEED 20 - -/* Buffer sizes */ -#define ISP116x_BUF_SIZE 4096 -#define ISP116x_ITL_BUFSIZE 0 -#define ISP116x_ATL_BUFSIZE ((ISP116x_BUF_SIZE) - 2*(ISP116x_ITL_BUFSIZE)) - -#define ISP116x_WRITE_OFFSET 0x80 - -/*------------ ISP116x registers/bits ------------*/ -#define HCREVISION 0x00 -#define HCCONTROL 0x01 -#define HCCONTROL_HCFS (3 << 6) /* host controller - functional state */ -#define HCCONTROL_USB_RESET (0 << 6) -#define HCCONTROL_USB_RESUME (1 << 6) -#define HCCONTROL_USB_OPER (2 << 6) -#define HCCONTROL_USB_SUSPEND (3 << 6) -#define HCCONTROL_RWC (1 << 9) /* remote wakeup connected */ -#define HCCONTROL_RWE (1 << 10) /* remote wakeup enable */ -#define HCCMDSTAT 0x02 -#define HCCMDSTAT_HCR (1 << 0) /* host controller reset */ -#define HCCMDSTAT_SOC (3 << 16) /* scheduling overrun count */ -#define HCINTSTAT 0x03 -#define HCINT_SO (1 << 0) /* scheduling overrun */ -#define HCINT_WDH (1 << 1) /* writeback of done_head */ -#define HCINT_SF (1 << 2) /* start frame */ -#define HCINT_RD (1 << 3) /* resume detect */ -#define HCINT_UE (1 << 4) /* unrecoverable error */ -#define HCINT_FNO (1 << 5) /* frame number overflow */ -#define HCINT_RHSC (1 << 6) /* root hub status change */ -#define HCINT_OC (1 << 30) /* ownership change */ -#define HCINT_MIE (1 << 31) /* master interrupt enable */ -#define HCINTENB 0x04 -#define HCINTDIS 0x05 -#define HCFMINTVL 0x0d -#define HCFMREM 0x0e -#define HCFMNUM 0x0f -#define HCLSTHRESH 0x11 -#define HCRHDESCA 0x12 -#define RH_A_NDP (0x3 << 0) /* # downstream ports */ -#define RH_A_PSM (1 << 8) /* power switching mode */ -#define RH_A_NPS (1 << 9) /* no power switching */ -#define RH_A_DT (1 << 10) /* device type (mbz) */ -#define RH_A_OCPM (1 << 11) /* overcurrent protection - mode */ -#define RH_A_NOCP (1 << 12) /* no overcurrent protection */ -#define RH_A_POTPGT (0xff << 24) /* power on -> power good - time */ -#define HCRHDESCB 0x13 -#define RH_B_DR (0xffff << 0) /* device removable flags */ -#define RH_B_PPCM (0xffff << 16) /* port power control mask */ -#define HCRHSTATUS 0x14 -#define RH_HS_LPS (1 << 0) /* local power status */ -#define RH_HS_OCI (1 << 1) /* over current indicator */ -#define RH_HS_DRWE (1 << 15) /* device remote wakeup - enable */ -#define RH_HS_LPSC (1 << 16) /* local power status change */ -#define RH_HS_OCIC (1 << 17) /* over current indicator - change */ -#define RH_HS_CRWE (1 << 31) /* clear remote wakeup - enable */ -#define HCRHPORT1 0x15 -#define RH_PS_CCS (1 << 0) /* current connect status */ -#define RH_PS_PES (1 << 1) /* port enable status */ -#define RH_PS_PSS (1 << 2) /* port suspend status */ -#define RH_PS_POCI (1 << 3) /* port over current - indicator */ -#define RH_PS_PRS (1 << 4) /* port reset status */ -#define RH_PS_PPS (1 << 8) /* port power status */ -#define RH_PS_LSDA (1 << 9) /* low speed device attached */ -#define RH_PS_CSC (1 << 16) /* connect status change */ -#define RH_PS_PESC (1 << 17) /* port enable status change */ -#define RH_PS_PSSC (1 << 18) /* port suspend status - change */ -#define RH_PS_OCIC (1 << 19) /* over current indicator - change */ -#define RH_PS_PRSC (1 << 20) /* port reset status change */ -#define HCRHPORT_CLRMASK (0x1f << 16) -#define HCRHPORT2 0x16 -#define HCHWCFG 0x20 -#define HCHWCFG_15KRSEL (1 << 12) -#define HCHWCFG_CLKNOTSTOP (1 << 11) -#define HCHWCFG_ANALOG_OC (1 << 10) -#define HCHWCFG_DACK_MODE (1 << 8) -#define HCHWCFG_EOT_POL (1 << 7) -#define HCHWCFG_DACK_POL (1 << 6) -#define HCHWCFG_DREQ_POL (1 << 5) -#define HCHWCFG_DBWIDTH_MASK (0x03 << 3) -#define HCHWCFG_DBWIDTH(n) (((n) << 3) & HCHWCFG_DBWIDTH_MASK) -#define HCHWCFG_INT_POL (1 << 2) -#define HCHWCFG_INT_TRIGGER (1 << 1) -#define HCHWCFG_INT_ENABLE (1 << 0) -#define HCDMACFG 0x21 -#define HCDMACFG_BURST_LEN_MASK (0x03 << 5) -#define HCDMACFG_BURST_LEN(n) (((n) << 5) & HCDMACFG_BURST_LEN_MASK) -#define HCDMACFG_BURST_LEN_1 HCDMACFG_BURST_LEN(0) -#define HCDMACFG_BURST_LEN_4 HCDMACFG_BURST_LEN(1) -#define HCDMACFG_BURST_LEN_8 HCDMACFG_BURST_LEN(2) -#define HCDMACFG_DMA_ENABLE (1 << 4) -#define HCDMACFG_BUF_TYPE_MASK (0x07 << 1) -#define HCDMACFG_CTR_SEL (1 << 2) -#define HCDMACFG_ITLATL_SEL (1 << 1) -#define HCDMACFG_DMA_RW_SELECT (1 << 0) -#define HCXFERCTR 0x22 -#define HCuPINT 0x24 -#define HCuPINT_SOF (1 << 0) -#define HCuPINT_ATL (1 << 1) -#define HCuPINT_AIIEOT (1 << 2) -#define HCuPINT_OPR (1 << 4) -#define HCuPINT_SUSP (1 << 5) -#define HCuPINT_CLKRDY (1 << 6) -#define HCuPINTENB 0x25 -#define HCCHIPID 0x27 -#define HCCHIPID_MASK 0xff00 -#define HCCHIPID_MAGIC 0x6100 -#define HCSCRATCH 0x28 -#define HCSWRES 0x29 -#define HCSWRES_MAGIC 0x00f6 -#define HCITLBUFLEN 0x2a -#define HCATLBUFLEN 0x2b -#define HCBUFSTAT 0x2c -#define HCBUFSTAT_ITL0_FULL (1 << 0) -#define HCBUFSTAT_ITL1_FULL (1 << 1) -#define HCBUFSTAT_ATL_FULL (1 << 2) -#define HCBUFSTAT_ITL0_DONE (1 << 3) -#define HCBUFSTAT_ITL1_DONE (1 << 4) -#define HCBUFSTAT_ATL_DONE (1 << 5) -#define HCRDITL0LEN 0x2d -#define HCRDITL1LEN 0x2e -#define HCITLPORT 0x40 -#define HCATLPORT 0x41 - -/* Philips transfer descriptor */ -struct ptd { - u16 count; -#define PTD_COUNT_MSK (0x3ff << 0) -#define PTD_TOGGLE_MSK (1 << 10) -#define PTD_ACTIVE_MSK (1 << 11) -#define PTD_CC_MSK (0xf << 12) - u16 mps; -#define PTD_MPS_MSK (0x3ff << 0) -#define PTD_SPD_MSK (1 << 10) -#define PTD_LAST_MSK (1 << 11) -#define PTD_EP_MSK (0xf << 12) - u16 len; -#define PTD_LEN_MSK (0x3ff << 0) -#define PTD_DIR_MSK (3 << 10) -#define PTD_DIR_SETUP (0) -#define PTD_DIR_OUT (1) -#define PTD_DIR_IN (2) -#define PTD_B5_5_MSK (1 << 13) - u16 faddr; -#define PTD_FA_MSK (0x7f << 0) -#define PTD_FMT_MSK (1 << 7) -} __attribute__ ((packed, aligned(2))); - -/* PTD accessor macros. */ -#define PTD_GET_COUNT(p) (((p)->count & PTD_COUNT_MSK) >> 0) -#define PTD_COUNT(v) (((v) << 0) & PTD_COUNT_MSK) -#define PTD_GET_TOGGLE(p) (((p)->count & PTD_TOGGLE_MSK) >> 10) -#define PTD_TOGGLE(v) (((v) << 10) & PTD_TOGGLE_MSK) -#define PTD_GET_ACTIVE(p) (((p)->count & PTD_ACTIVE_MSK) >> 11) -#define PTD_ACTIVE(v) (((v) << 11) & PTD_ACTIVE_MSK) -#define PTD_GET_CC(p) (((p)->count & PTD_CC_MSK) >> 12) -#define PTD_CC(v) (((v) << 12) & PTD_CC_MSK) -#define PTD_GET_MPS(p) (((p)->mps & PTD_MPS_MSK) >> 0) -#define PTD_MPS(v) (((v) << 0) & PTD_MPS_MSK) -#define PTD_GET_SPD(p) (((p)->mps & PTD_SPD_MSK) >> 10) -#define PTD_SPD(v) (((v) << 10) & PTD_SPD_MSK) -#define PTD_GET_LAST(p) (((p)->mps & PTD_LAST_MSK) >> 11) -#define PTD_LAST(v) (((v) << 11) & PTD_LAST_MSK) -#define PTD_GET_EP(p) (((p)->mps & PTD_EP_MSK) >> 12) -#define PTD_EP(v) (((v) << 12) & PTD_EP_MSK) -#define PTD_GET_LEN(p) (((p)->len & PTD_LEN_MSK) >> 0) -#define PTD_LEN(v) (((v) << 0) & PTD_LEN_MSK) -#define PTD_GET_DIR(p) (((p)->len & PTD_DIR_MSK) >> 10) -#define PTD_DIR(v) (((v) << 10) & PTD_DIR_MSK) -#define PTD_GET_B5_5(p) (((p)->len & PTD_B5_5_MSK) >> 13) -#define PTD_B5_5(v) (((v) << 13) & PTD_B5_5_MSK) -#define PTD_GET_FA(p) (((p)->faddr & PTD_FA_MSK) >> 0) -#define PTD_FA(v) (((v) << 0) & PTD_FA_MSK) -#define PTD_GET_FMT(p) (((p)->faddr & PTD_FMT_MSK) >> 7) -#define PTD_FMT(v) (((v) << 7) & PTD_FMT_MSK) - -/* Hardware transfer status codes -- CC from ptd->count */ -#define TD_CC_NOERROR 0x00 -#define TD_CC_CRC 0x01 -#define TD_CC_BITSTUFFING 0x02 -#define TD_CC_DATATOGGLEM 0x03 -#define TD_CC_STALL 0x04 -#define TD_DEVNOTRESP 0x05 -#define TD_PIDCHECKFAIL 0x06 -#define TD_UNEXPECTEDPID 0x07 -#define TD_DATAOVERRUN 0x08 -#define TD_DATAUNDERRUN 0x09 - /* 0x0A, 0x0B reserved for hardware */ -#define TD_BUFFEROVERRUN 0x0C -#define TD_BUFFERUNDERRUN 0x0D - /* 0x0E, 0x0F reserved for HCD */ -#define TD_NOTACCESSED 0x0F - -/* map PTD status codes (CC) to errno values */ -static const int cc_to_error[16] = { - /* No Error */ 0, - /* CRC Error */ -EILSEQ, - /* Bit Stuff */ -EPROTO, - /* Data Togg */ -EILSEQ, - /* Stall */ -EPIPE, - /* DevNotResp */ -ETIME, - /* PIDCheck */ -EPROTO, - /* UnExpPID */ -EPROTO, - /* DataOver */ -EOVERFLOW, - /* DataUnder */ -EREMOTEIO, - /* (for hw) */ -EIO, - /* (for hw) */ -EIO, - /* BufferOver */ -ECOMM, - /* BuffUnder */ -ENOSR, - /* (for HCD) */ -EALREADY, - /* (for HCD) */ -EALREADY -}; - -/*--------------------------------------------------------------*/ - -#define LOG2_PERIODIC_SIZE 5 /* arbitrary; this matches OHCI */ -#define PERIODIC_SIZE (1 << LOG2_PERIODIC_SIZE) - -struct isp116x { - spinlock_t lock; - - void __iomem *addr_reg; - void __iomem *data_reg; - - struct isp116x_platform_data *board; - - struct dentry *dentry; - unsigned long stat1, stat2, stat4, stat8, stat16; - - /* HC registers */ - u32 intenb; /* "OHCI" interrupts */ - u16 irqenb; /* uP interrupts */ - - /* Root hub registers */ - u32 rhdesca; - u32 rhdescb; - u32 rhstatus; - - /* async schedule: control, bulk */ - struct list_head async; - - /* periodic schedule: int */ - u16 load[PERIODIC_SIZE]; - struct isp116x_ep *periodic[PERIODIC_SIZE]; - unsigned periodic_count; - u16 fmindex; - - /* Schedule for the current frame */ - struct isp116x_ep *atl_active; - int atl_buflen; - int atl_bufshrt; - int atl_last_dir; - atomic_t atl_finishing; -}; - -static inline struct isp116x *hcd_to_isp116x(struct usb_hcd *hcd) -{ - return (struct isp116x *)(hcd->hcd_priv); -} - -static inline struct usb_hcd *isp116x_to_hcd(struct isp116x *isp116x) -{ - return container_of((void *)isp116x, struct usb_hcd, hcd_priv); -} - -struct isp116x_ep { - struct usb_host_endpoint *hep; - struct usb_device *udev; - struct ptd ptd; - - u8 maxpacket; - u8 epnum; - u8 nextpid; - u16 error_count; - u16 length; /* of current packet */ - unsigned char *data; /* to databuf */ - /* queue of active EP's (the ones scheduled for the - current frame) */ - struct isp116x_ep *active; - - /* periodic schedule */ - u16 period; - u16 branch; - u16 load; - struct isp116x_ep *next; - - /* async schedule */ - struct list_head schedule; -}; - -/*-------------------------------------------------------------------------*/ - -#ifdef DEBUG -#define DBG(stuff...) printk(KERN_DEBUG "116x: " stuff) -#else -#define DBG(stuff...) do{}while(0) -#endif - -#ifdef VERBOSE -# define VDBG DBG -#else -# define VDBG(stuff...) do{}while(0) -#endif - -#define ERR(stuff...) printk(KERN_ERR "116x: " stuff) -#define WARNING(stuff...) printk(KERN_WARNING "116x: " stuff) -#define INFO(stuff...) printk(KERN_INFO "116x: " stuff) - -/* ------------------------------------------------- */ - -#if defined(USE_PLATFORM_DELAY) -#if defined(USE_NDELAY) -#error USE_PLATFORM_DELAY and USE_NDELAY simultaneously defined. -#endif -#define isp116x_delay(h,d) (h)->board->delay( \ - isp116x_to_hcd(h)->self.controller,d) -#define isp116x_check_platform_delay(h) ((h)->board->delay == NULL) -#elif defined(USE_NDELAY) -#define isp116x_delay(h,d) ndelay(d) -#define isp116x_check_platform_delay(h) 0 -#else -#define isp116x_delay(h,d) do{}while(0) -#define isp116x_check_platform_delay(h) 0 -#endif - -#if defined(DEBUG) -#define IRQ_TEST() BUG_ON(!irqs_disabled()) -#else -#define IRQ_TEST() do{}while(0) -#endif - -static inline void isp116x_write_addr(struct isp116x *isp116x, unsigned reg) -{ - IRQ_TEST(); - writew(reg & 0xff, isp116x->addr_reg); - isp116x_delay(isp116x, 300); -} - -static inline void isp116x_write_data16(struct isp116x *isp116x, u16 val) -{ - writew(val, isp116x->data_reg); - isp116x_delay(isp116x, 150); -} - -static inline void isp116x_raw_write_data16(struct isp116x *isp116x, u16 val) -{ - __raw_writew(val, isp116x->data_reg); - isp116x_delay(isp116x, 150); -} - -static inline u16 isp116x_read_data16(struct isp116x *isp116x) -{ - u16 val; - - val = readw(isp116x->data_reg); - isp116x_delay(isp116x, 150); - return val; -} - -static inline u16 isp116x_raw_read_data16(struct isp116x *isp116x) -{ - u16 val; - - val = __raw_readw(isp116x->data_reg); - isp116x_delay(isp116x, 150); - return val; -} - -static inline void isp116x_write_data32(struct isp116x *isp116x, u32 val) -{ - writew(val & 0xffff, isp116x->data_reg); - isp116x_delay(isp116x, 150); - writew(val >> 16, isp116x->data_reg); - isp116x_delay(isp116x, 150); -} - -static inline u32 isp116x_read_data32(struct isp116x *isp116x) -{ - u32 val; - - val = (u32) readw(isp116x->data_reg); - isp116x_delay(isp116x, 150); - val |= ((u32) readw(isp116x->data_reg)) << 16; - isp116x_delay(isp116x, 150); - return val; -} - -/* Let's keep register access functions out of line. Hint: - we wait at least 150 ns at every access. -*/ -static u16 isp116x_read_reg16(struct isp116x *isp116x, unsigned reg) -{ - isp116x_write_addr(isp116x, reg); - return isp116x_read_data16(isp116x); -} - -static u32 isp116x_read_reg32(struct isp116x *isp116x, unsigned reg) -{ - isp116x_write_addr(isp116x, reg); - return isp116x_read_data32(isp116x); -} - -static void isp116x_write_reg16(struct isp116x *isp116x, unsigned reg, - unsigned val) -{ - isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET); - isp116x_write_data16(isp116x, (u16) (val & 0xffff)); -} - -static void isp116x_write_reg32(struct isp116x *isp116x, unsigned reg, - unsigned val) -{ - isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET); - isp116x_write_data32(isp116x, (u32) val); -} - -#define isp116x_show_reg_log(d,r,s) { \ - if ((r) < 0x20) { \ - DBG("%-12s[%02x]: %08x\n", #r, \ - r, isp116x_read_reg32(d, r)); \ - } else { \ - DBG("%-12s[%02x]: %04x\n", #r, \ - r, isp116x_read_reg16(d, r)); \ - } \ -} -#define isp116x_show_reg_seq(d,r,s) { \ - if ((r) < 0x20) { \ - seq_printf(s, "%-12s[%02x]: %08x\n", #r, \ - r, isp116x_read_reg32(d, r)); \ - } else { \ - seq_printf(s, "%-12s[%02x]: %04x\n", #r, \ - r, isp116x_read_reg16(d, r)); \ - } \ -} - -#define isp116x_show_regs(d,type,s) { \ - isp116x_show_reg_##type(d, HCREVISION, s); \ - isp116x_show_reg_##type(d, HCCONTROL, s); \ - isp116x_show_reg_##type(d, HCCMDSTAT, s); \ - isp116x_show_reg_##type(d, HCINTSTAT, s); \ - isp116x_show_reg_##type(d, HCINTENB, s); \ - isp116x_show_reg_##type(d, HCFMINTVL, s); \ - isp116x_show_reg_##type(d, HCFMREM, s); \ - isp116x_show_reg_##type(d, HCFMNUM, s); \ - isp116x_show_reg_##type(d, HCLSTHRESH, s); \ - isp116x_show_reg_##type(d, HCRHDESCA, s); \ - isp116x_show_reg_##type(d, HCRHDESCB, s); \ - isp116x_show_reg_##type(d, HCRHSTATUS, s); \ - isp116x_show_reg_##type(d, HCRHPORT1, s); \ - isp116x_show_reg_##type(d, HCRHPORT2, s); \ - isp116x_show_reg_##type(d, HCHWCFG, s); \ - isp116x_show_reg_##type(d, HCDMACFG, s); \ - isp116x_show_reg_##type(d, HCXFERCTR, s); \ - isp116x_show_reg_##type(d, HCuPINT, s); \ - isp116x_show_reg_##type(d, HCuPINTENB, s); \ - isp116x_show_reg_##type(d, HCCHIPID, s); \ - isp116x_show_reg_##type(d, HCSCRATCH, s); \ - isp116x_show_reg_##type(d, HCITLBUFLEN, s); \ - isp116x_show_reg_##type(d, HCATLBUFLEN, s); \ - isp116x_show_reg_##type(d, HCBUFSTAT, s); \ - isp116x_show_reg_##type(d, HCRDITL0LEN, s); \ - isp116x_show_reg_##type(d, HCRDITL1LEN, s); \ -} - -/* - Dump registers for debugfs. -*/ -static inline void isp116x_show_regs_seq(struct isp116x *isp116x, - struct seq_file *s) -{ - isp116x_show_regs(isp116x, seq, s); -} - -/* - Dump registers to syslog. -*/ -static inline void isp116x_show_regs_log(struct isp116x *isp116x) -{ - isp116x_show_regs(isp116x, log, NULL); -} - -#if defined(URB_TRACE) - -#define PIPETYPE(pipe) ({ char *__s; \ - if (usb_pipecontrol(pipe)) __s = "ctrl"; \ - else if (usb_pipeint(pipe)) __s = "int"; \ - else if (usb_pipebulk(pipe)) __s = "bulk"; \ - else __s = "iso"; \ - __s;}) -#define PIPEDIR(pipe) ({ usb_pipein(pipe) ? "in" : "out"; }) -#define URB_NOTSHORT(urb) ({ (urb)->transfer_flags & URB_SHORT_NOT_OK ? \ - "short_not_ok" : ""; }) - -/* print debug info about the URB */ -static void urb_dbg(struct urb *urb, char *msg) -{ - unsigned int pipe; - - if (!urb) { - DBG("%s: zero urb\n", msg); - return; - } - pipe = urb->pipe; - DBG("%s: FA %d ep%d%s %s: len %d/%d %s\n", msg, - usb_pipedevice(pipe), usb_pipeendpoint(pipe), - PIPEDIR(pipe), PIPETYPE(pipe), - urb->transfer_buffer_length, urb->actual_length, URB_NOTSHORT(urb)); -} - -#else - -#define urb_dbg(urb,msg) do{}while(0) - -#endif /* ! defined(URB_TRACE) */ - -#if defined(PTD_TRACE) - -#define PTD_DIR_STR(ptd) ({char __c; \ - switch(PTD_GET_DIR(ptd)){ \ - case 0: __c = 's'; break; \ - case 1: __c = 'o'; break; \ - default: __c = 'i'; break; \ - }; __c;}) - -/* - Dump PTD info. The code documents the format - perfectly, right :) -*/ -static inline void dump_ptd(struct ptd *ptd) -{ - printk(KERN_WARNING "td: %x %d%c%d %d,%d,%d %x %x%x%x\n", - PTD_GET_CC(ptd), PTD_GET_FA(ptd), - PTD_DIR_STR(ptd), PTD_GET_EP(ptd), - PTD_GET_COUNT(ptd), PTD_GET_LEN(ptd), PTD_GET_MPS(ptd), - PTD_GET_TOGGLE(ptd), PTD_GET_ACTIVE(ptd), - PTD_GET_SPD(ptd), PTD_GET_LAST(ptd)); -} - -static inline void dump_ptd_out_data(struct ptd *ptd, u8 * buf) -{ - int k; - - if (PTD_GET_DIR(ptd) != PTD_DIR_IN && PTD_GET_LEN(ptd)) { - printk(KERN_WARNING "-> "); - for (k = 0; k < PTD_GET_LEN(ptd); ++k) - printk("%02x ", ((u8 *) buf)[k]); - printk("\n"); - } -} - -static inline void dump_ptd_in_data(struct ptd *ptd, u8 * buf) -{ - int k; - - if (PTD_GET_DIR(ptd) == PTD_DIR_IN && PTD_GET_COUNT(ptd)) { - printk(KERN_WARNING "<- "); - for (k = 0; k < PTD_GET_COUNT(ptd); ++k) - printk("%02x ", ((u8 *) buf)[k]); - printk("\n"); - } - if (PTD_GET_LAST(ptd)) - printk(KERN_WARNING "-\n"); -} - -#else - -#define dump_ptd(ptd) do{}while(0) -#define dump_ptd_in_data(ptd,buf) do{}while(0) -#define dump_ptd_out_data(ptd,buf) do{}while(0) - -#endif /* ! defined(PTD_TRACE) */ diff --git a/ANDROID_3.4.5/drivers/usb/host/isp1362-hcd.c b/ANDROID_3.4.5/drivers/usb/host/isp1362-hcd.c deleted file mode 100644 index 2ed112d3..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/isp1362-hcd.c +++ /dev/null @@ -1,2869 +0,0 @@ -/* - * ISP1362 HCD (Host Controller Driver) for USB. - * - * Copyright (C) 2005 Lothar Wassmann - * - * Derived from the SL811 HCD, rewritten for ISP116x. - * Copyright (C) 2005 Olav Kongas - * - * Portions: - * Copyright (C) 2004 Psion Teklogix (for NetBook PRO) - * Copyright (C) 2004 David Brownell - */ - -/* - * The ISP1362 chip requires a large delay (300ns and 462ns) between - * accesses to the address and data register. - * The following timing options exist: - * - * 1. Configure your memory controller to add such delays if it can (the best) - * 2. Implement platform-specific delay function possibly - * combined with configuring the memory controller; see - * include/linux/usb_isp1362.h for more info. - * 3. Use ndelay (easiest, poorest). - * - * Use the corresponding macros USE_PLATFORM_DELAY and USE_NDELAY in the - * platform specific section of isp1362.h to select the appropriate variant. - * - * Also note that according to the Philips "ISP1362 Errata" document - * Rev 1.00 from 27 May data corruption may occur when the #WR signal - * is reasserted (even with #CS deasserted) within 132ns after a - * write cycle to any controller register. If the hardware doesn't - * implement the recommended fix (gating the #WR with #CS) software - * must ensure that no further write cycle (not necessarily to the chip!) - * is issued by the CPU within this interval. - - * For PXA25x this can be ensured by using VLIO with the maximum - * recovery time (MSCx = 0x7f8c) with a memory clock of 99.53 MHz. - */ - -#ifdef CONFIG_USB_DEBUG -# define ISP1362_DEBUG -#else -# undef ISP1362_DEBUG -#endif - -/* - * The PXA255 UDC apparently doesn't handle GET_STATUS, GET_CONFIG and - * GET_INTERFACE requests correctly when the SETUP and DATA stages of the - * requests are carried out in separate frames. This will delay any SETUP - * packets until the start of the next frame so that this situation is - * unlikely to occur (and makes usbtest happy running with a PXA255 target - * device). - */ -#undef BUGGY_PXA2XX_UDC_USBTEST - -#undef PTD_TRACE -#undef URB_TRACE -#undef VERBOSE -#undef REGISTERS - -/* This enables a memory test on the ISP1362 chip memory to make sure the - * chip access timing is correct. - */ -#undef CHIP_BUFFER_TEST - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -static int dbg_level; -#ifdef ISP1362_DEBUG -module_param(dbg_level, int, 0644); -#else -module_param(dbg_level, int, 0); -#define STUB_DEBUG_FILE -#endif - -#include "../core/usb.h" -#include "isp1362.h" - - -#define DRIVER_VERSION "2005-04-04" -#define DRIVER_DESC "ISP1362 USB Host Controller Driver" - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -static const char hcd_name[] = "isp1362-hcd"; - -static void isp1362_hc_stop(struct usb_hcd *hcd); -static int isp1362_hc_start(struct usb_hcd *hcd); - -/*-------------------------------------------------------------------------*/ - -/* - * When called from the interrupthandler only isp1362_hcd->irqenb is modified, - * since the interrupt handler will write isp1362_hcd->irqenb to HCuPINT upon - * completion. - * We don't need a 'disable' counterpart, since interrupts will be disabled - * only by the interrupt handler. - */ -static inline void isp1362_enable_int(struct isp1362_hcd *isp1362_hcd, u16 mask) -{ - if ((isp1362_hcd->irqenb | mask) == isp1362_hcd->irqenb) - return; - if (mask & ~isp1362_hcd->irqenb) - isp1362_write_reg16(isp1362_hcd, HCuPINT, mask & ~isp1362_hcd->irqenb); - isp1362_hcd->irqenb |= mask; - if (isp1362_hcd->irq_active) - return; - isp1362_write_reg16(isp1362_hcd, HCuPINTENB, isp1362_hcd->irqenb); -} - -/*-------------------------------------------------------------------------*/ - -static inline struct isp1362_ep_queue *get_ptd_queue(struct isp1362_hcd *isp1362_hcd, - u16 offset) -{ - struct isp1362_ep_queue *epq = NULL; - - if (offset < isp1362_hcd->istl_queue[1].buf_start) - epq = &isp1362_hcd->istl_queue[0]; - else if (offset < isp1362_hcd->intl_queue.buf_start) - epq = &isp1362_hcd->istl_queue[1]; - else if (offset < isp1362_hcd->atl_queue.buf_start) - epq = &isp1362_hcd->intl_queue; - else if (offset < isp1362_hcd->atl_queue.buf_start + - isp1362_hcd->atl_queue.buf_size) - epq = &isp1362_hcd->atl_queue; - - if (epq) - DBG(1, "%s: PTD $%04x is on %s queue\n", __func__, offset, epq->name); - else - pr_warning("%s: invalid PTD $%04x\n", __func__, offset); - - return epq; -} - -static inline int get_ptd_offset(struct isp1362_ep_queue *epq, u8 index) -{ - int offset; - - if (index * epq->blk_size > epq->buf_size) { - pr_warning("%s: Bad %s index %d(%d)\n", __func__, epq->name, index, - epq->buf_size / epq->blk_size); - return -EINVAL; - } - offset = epq->buf_start + index * epq->blk_size; - DBG(3, "%s: %s PTD[%02x] # %04x\n", __func__, epq->name, index, offset); - - return offset; -} - -/*-------------------------------------------------------------------------*/ - -static inline u16 max_transfer_size(struct isp1362_ep_queue *epq, size_t size, - int mps) -{ - u16 xfer_size = min_t(size_t, MAX_XFER_SIZE, size); - - xfer_size = min_t(size_t, xfer_size, epq->buf_avail * epq->blk_size - PTD_HEADER_SIZE); - if (xfer_size < size && xfer_size % mps) - xfer_size -= xfer_size % mps; - - return xfer_size; -} - -static int claim_ptd_buffers(struct isp1362_ep_queue *epq, - struct isp1362_ep *ep, u16 len) -{ - int ptd_offset = -EINVAL; - int num_ptds = ((len + PTD_HEADER_SIZE - 1) / epq->blk_size) + 1; - int found; - - BUG_ON(len > epq->buf_size); - - if (!epq->buf_avail) - return -ENOMEM; - - if (ep->num_ptds) - pr_err("%s: %s len %d/%d num_ptds %d buf_map %08lx skip_map %08lx\n", __func__, - epq->name, len, epq->blk_size, num_ptds, epq->buf_map, epq->skip_map); - BUG_ON(ep->num_ptds != 0); - - found = bitmap_find_next_zero_area(&epq->buf_map, epq->buf_count, 0, - num_ptds, 0); - if (found >= epq->buf_count) - return -EOVERFLOW; - - DBG(1, "%s: Found %d PTDs[%d] for %d/%d byte\n", __func__, - num_ptds, found, len, (int)(epq->blk_size - PTD_HEADER_SIZE)); - ptd_offset = get_ptd_offset(epq, found); - WARN_ON(ptd_offset < 0); - ep->ptd_offset = ptd_offset; - ep->num_ptds += num_ptds; - epq->buf_avail -= num_ptds; - BUG_ON(epq->buf_avail > epq->buf_count); - ep->ptd_index = found; - bitmap_set(&epq->buf_map, found, num_ptds); - DBG(1, "%s: Done %s PTD[%d] $%04x, avail %d count %d claimed %d %08lx:%08lx\n", - __func__, epq->name, ep->ptd_index, ep->ptd_offset, - epq->buf_avail, epq->buf_count, num_ptds, epq->buf_map, epq->skip_map); - - return found; -} - -static inline void release_ptd_buffers(struct isp1362_ep_queue *epq, struct isp1362_ep *ep) -{ - int last = ep->ptd_index + ep->num_ptds; - - if (last > epq->buf_count) - pr_err("%s: ep %p req %d len %d %s PTD[%d] $%04x num_ptds %d buf_count %d buf_avail %d buf_map %08lx skip_map %08lx\n", - __func__, ep, ep->num_req, ep->length, epq->name, ep->ptd_index, - ep->ptd_offset, ep->num_ptds, epq->buf_count, epq->buf_avail, - epq->buf_map, epq->skip_map); - BUG_ON(last > epq->buf_count); - - bitmap_clear(&epq->buf_map, ep->ptd_index, ep->num_ptds); - bitmap_set(&epq->skip_map, ep->ptd_index, ep->num_ptds); - epq->buf_avail += ep->num_ptds; - epq->ptd_count--; - - BUG_ON(epq->buf_avail > epq->buf_count); - BUG_ON(epq->ptd_count > epq->buf_count); - - DBG(1, "%s: Done %s PTDs $%04x released %d avail %d count %d\n", - __func__, epq->name, - ep->ptd_offset, ep->num_ptds, epq->buf_avail, epq->buf_count); - DBG(1, "%s: buf_map %08lx skip_map %08lx\n", __func__, - epq->buf_map, epq->skip_map); - - ep->num_ptds = 0; - ep->ptd_offset = -EINVAL; - ep->ptd_index = -EINVAL; -} - -/*-------------------------------------------------------------------------*/ - -/* - Set up PTD's. -*/ -static void prepare_ptd(struct isp1362_hcd *isp1362_hcd, struct urb *urb, - struct isp1362_ep *ep, struct isp1362_ep_queue *epq, - u16 fno) -{ - struct ptd *ptd; - int toggle; - int dir; - u16 len; - size_t buf_len = urb->transfer_buffer_length - urb->actual_length; - - DBG(3, "%s: %s ep %p\n", __func__, epq->name, ep); - - ptd = &ep->ptd; - - ep->data = (unsigned char *)urb->transfer_buffer + urb->actual_length; - - switch (ep->nextpid) { - case USB_PID_IN: - toggle = usb_gettoggle(urb->dev, ep->epnum, 0); - dir = PTD_DIR_IN; - if (usb_pipecontrol(urb->pipe)) { - len = min_t(size_t, ep->maxpacket, buf_len); - } else if (usb_pipeisoc(urb->pipe)) { - len = min_t(size_t, urb->iso_frame_desc[fno].length, MAX_XFER_SIZE); - ep->data = urb->transfer_buffer + urb->iso_frame_desc[fno].offset; - } else - len = max_transfer_size(epq, buf_len, ep->maxpacket); - DBG(1, "%s: IN len %d/%d/%d from URB\n", __func__, len, ep->maxpacket, - (int)buf_len); - break; - case USB_PID_OUT: - toggle = usb_gettoggle(urb->dev, ep->epnum, 1); - dir = PTD_DIR_OUT; - if (usb_pipecontrol(urb->pipe)) - len = min_t(size_t, ep->maxpacket, buf_len); - else if (usb_pipeisoc(urb->pipe)) - len = min_t(size_t, urb->iso_frame_desc[0].length, MAX_XFER_SIZE); - else - len = max_transfer_size(epq, buf_len, ep->maxpacket); - if (len == 0) - pr_info("%s: Sending ZERO packet: %d\n", __func__, - urb->transfer_flags & URB_ZERO_PACKET); - DBG(1, "%s: OUT len %d/%d/%d from URB\n", __func__, len, ep->maxpacket, - (int)buf_len); - break; - case USB_PID_SETUP: - toggle = 0; - dir = PTD_DIR_SETUP; - len = sizeof(struct usb_ctrlrequest); - DBG(1, "%s: SETUP len %d\n", __func__, len); - ep->data = urb->setup_packet; - break; - case USB_PID_ACK: - toggle = 1; - len = 0; - dir = (urb->transfer_buffer_length && usb_pipein(urb->pipe)) ? - PTD_DIR_OUT : PTD_DIR_IN; - DBG(1, "%s: ACK len %d\n", __func__, len); - break; - default: - toggle = dir = len = 0; - pr_err("%s@%d: ep->nextpid %02x\n", __func__, __LINE__, ep->nextpid); - BUG_ON(1); - } - - ep->length = len; - if (!len) - ep->data = NULL; - - ptd->count = PTD_CC_MSK | PTD_ACTIVE_MSK | PTD_TOGGLE(toggle); - ptd->mps = PTD_MPS(ep->maxpacket) | PTD_SPD(urb->dev->speed == USB_SPEED_LOW) | - PTD_EP(ep->epnum); - ptd->len = PTD_LEN(len) | PTD_DIR(dir); - ptd->faddr = PTD_FA(usb_pipedevice(urb->pipe)); - - if (usb_pipeint(urb->pipe)) { - ptd->faddr |= PTD_SF_INT(ep->branch); - ptd->faddr |= PTD_PR(ep->interval ? __ffs(ep->interval) : 0); - } - if (usb_pipeisoc(urb->pipe)) - ptd->faddr |= PTD_SF_ISO(fno); - - DBG(1, "%s: Finished\n", __func__); -} - -static void isp1362_write_ptd(struct isp1362_hcd *isp1362_hcd, struct isp1362_ep *ep, - struct isp1362_ep_queue *epq) -{ - struct ptd *ptd = &ep->ptd; - int len = PTD_GET_DIR(ptd) == PTD_DIR_IN ? 0 : ep->length; - - _BUG_ON(ep->ptd_offset < 0); - - prefetch(ptd); - isp1362_write_buffer(isp1362_hcd, ptd, ep->ptd_offset, PTD_HEADER_SIZE); - if (len) - isp1362_write_buffer(isp1362_hcd, ep->data, - ep->ptd_offset + PTD_HEADER_SIZE, len); - - dump_ptd(ptd); - dump_ptd_out_data(ptd, ep->data); -} - -static void isp1362_read_ptd(struct isp1362_hcd *isp1362_hcd, struct isp1362_ep *ep, - struct isp1362_ep_queue *epq) -{ - struct ptd *ptd = &ep->ptd; - int act_len; - - WARN_ON(list_empty(&ep->active)); - BUG_ON(ep->ptd_offset < 0); - - list_del_init(&ep->active); - DBG(1, "%s: ep %p removed from active list %p\n", __func__, ep, &epq->active); - - prefetchw(ptd); - isp1362_read_buffer(isp1362_hcd, ptd, ep->ptd_offset, PTD_HEADER_SIZE); - dump_ptd(ptd); - act_len = PTD_GET_COUNT(ptd); - if (PTD_GET_DIR(ptd) != PTD_DIR_IN || act_len == 0) - return; - if (act_len > ep->length) - pr_err("%s: ep %p PTD $%04x act_len %d ep->length %d\n", __func__, ep, - ep->ptd_offset, act_len, ep->length); - BUG_ON(act_len > ep->length); - /* Only transfer the amount of data that has actually been overwritten - * in the chip buffer. We don't want any data that doesn't belong to the - * transfer to leak out of the chip to the callers transfer buffer! - */ - prefetchw(ep->data); - isp1362_read_buffer(isp1362_hcd, ep->data, - ep->ptd_offset + PTD_HEADER_SIZE, act_len); - dump_ptd_in_data(ptd, ep->data); -} - -/* - * INT PTDs will stay in the chip until data is available. - * This function will remove a PTD from the chip when the URB is dequeued. - * Must be called with the spinlock held and IRQs disabled - */ -static void remove_ptd(struct isp1362_hcd *isp1362_hcd, struct isp1362_ep *ep) - -{ - int index; - struct isp1362_ep_queue *epq; - - DBG(1, "%s: ep %p PTD[%d] $%04x\n", __func__, ep, ep->ptd_index, ep->ptd_offset); - BUG_ON(ep->ptd_offset < 0); - - epq = get_ptd_queue(isp1362_hcd, ep->ptd_offset); - BUG_ON(!epq); - - /* put ep in remove_list for cleanup */ - WARN_ON(!list_empty(&ep->remove_list)); - list_add_tail(&ep->remove_list, &isp1362_hcd->remove_list); - /* let SOF interrupt handle the cleanup */ - isp1362_enable_int(isp1362_hcd, HCuPINT_SOF); - - index = ep->ptd_index; - if (index < 0) - /* ISO queues don't have SKIP registers */ - return; - - DBG(1, "%s: Disabling PTD[%02x] $%04x %08lx|%08x\n", __func__, - index, ep->ptd_offset, epq->skip_map, 1 << index); - - /* prevent further processing of PTD (will be effective after next SOF) */ - epq->skip_map |= 1 << index; - if (epq == &isp1362_hcd->atl_queue) { - DBG(2, "%s: ATLSKIP = %08x -> %08lx\n", __func__, - isp1362_read_reg32(isp1362_hcd, HCATLSKIP), epq->skip_map); - isp1362_write_reg32(isp1362_hcd, HCATLSKIP, epq->skip_map); - if (~epq->skip_map == 0) - isp1362_clr_mask16(isp1362_hcd, HCBUFSTAT, HCBUFSTAT_ATL_ACTIVE); - } else if (epq == &isp1362_hcd->intl_queue) { - DBG(2, "%s: INTLSKIP = %08x -> %08lx\n", __func__, - isp1362_read_reg32(isp1362_hcd, HCINTLSKIP), epq->skip_map); - isp1362_write_reg32(isp1362_hcd, HCINTLSKIP, epq->skip_map); - if (~epq->skip_map == 0) - isp1362_clr_mask16(isp1362_hcd, HCBUFSTAT, HCBUFSTAT_INTL_ACTIVE); - } -} - -/* - Take done or failed requests out of schedule. Give back - processed urbs. -*/ -static void finish_request(struct isp1362_hcd *isp1362_hcd, struct isp1362_ep *ep, - struct urb *urb, int status) - __releases(isp1362_hcd->lock) - __acquires(isp1362_hcd->lock) -{ - urb->hcpriv = NULL; - ep->error_count = 0; - - if (usb_pipecontrol(urb->pipe)) - ep->nextpid = USB_PID_SETUP; - - URB_DBG("%s: req %d FA %d ep%d%s %s: len %d/%d %s stat %d\n", __func__, - ep->num_req, usb_pipedevice(urb->pipe), - usb_pipeendpoint(urb->pipe), - !usb_pipein(urb->pipe) ? "out" : "in", - usb_pipecontrol(urb->pipe) ? "ctrl" : - usb_pipeint(urb->pipe) ? "int" : - usb_pipebulk(urb->pipe) ? "bulk" : - "iso", - urb->actual_length, urb->transfer_buffer_length, - !(urb->transfer_flags & URB_SHORT_NOT_OK) ? - "short_ok" : "", urb->status); - - - usb_hcd_unlink_urb_from_ep(isp1362_hcd_to_hcd(isp1362_hcd), urb); - spin_unlock(&isp1362_hcd->lock); - usb_hcd_giveback_urb(isp1362_hcd_to_hcd(isp1362_hcd), urb, status); - spin_lock(&isp1362_hcd->lock); - - /* take idle endpoints out of the schedule right away */ - if (!list_empty(&ep->hep->urb_list)) - return; - - /* async deschedule */ - if (!list_empty(&ep->schedule)) { - list_del_init(&ep->schedule); - return; - } - - - if (ep->interval) { - /* periodic deschedule */ - DBG(1, "deschedule qh%d/%p branch %d load %d bandwidth %d -> %d\n", ep->interval, - ep, ep->branch, ep->load, - isp1362_hcd->load[ep->branch], - isp1362_hcd->load[ep->branch] - ep->load); - isp1362_hcd->load[ep->branch] -= ep->load; - ep->branch = PERIODIC_SIZE; - } -} - -/* - * Analyze transfer results, handle partial transfers and errors -*/ -static void postproc_ep(struct isp1362_hcd *isp1362_hcd, struct isp1362_ep *ep) -{ - struct urb *urb = get_urb(ep); - struct usb_device *udev; - struct ptd *ptd; - int short_ok; - u16 len; - int urbstat = -EINPROGRESS; - u8 cc; - - DBG(2, "%s: ep %p req %d\n", __func__, ep, ep->num_req); - - udev = urb->dev; - ptd = &ep->ptd; - cc = PTD_GET_CC(ptd); - if (cc == PTD_NOTACCESSED) { - pr_err("%s: req %d PTD %p Untouched by ISP1362\n", __func__, - ep->num_req, ptd); - cc = PTD_DEVNOTRESP; - } - - short_ok = !(urb->transfer_flags & URB_SHORT_NOT_OK); - len = urb->transfer_buffer_length - urb->actual_length; - - /* Data underrun is special. For allowed underrun - we clear the error and continue as normal. For - forbidden underrun we finish the DATA stage - immediately while for control transfer, - we do a STATUS stage. - */ - if (cc == PTD_DATAUNDERRUN) { - if (short_ok) { - DBG(1, "%s: req %d Allowed data underrun short_%sok %d/%d/%d byte\n", - __func__, ep->num_req, short_ok ? "" : "not_", - PTD_GET_COUNT(ptd), ep->maxpacket, len); - cc = PTD_CC_NOERROR; - urbstat = 0; - } else { - DBG(1, "%s: req %d Data Underrun %s nextpid %02x short_%sok %d/%d/%d byte\n", - __func__, ep->num_req, - usb_pipein(urb->pipe) ? "IN" : "OUT", ep->nextpid, - short_ok ? "" : "not_", - PTD_GET_COUNT(ptd), ep->maxpacket, len); - if (usb_pipecontrol(urb->pipe)) { - ep->nextpid = USB_PID_ACK; - /* save the data underrun error code for later and - * proceed with the status stage - */ - urb->actual_length += PTD_GET_COUNT(ptd); - BUG_ON(urb->actual_length > urb->transfer_buffer_length); - - if (urb->status == -EINPROGRESS) - urb->status = cc_to_error[PTD_DATAUNDERRUN]; - } else { - usb_settoggle(udev, ep->epnum, ep->nextpid == USB_PID_OUT, - PTD_GET_TOGGLE(ptd)); - urbstat = cc_to_error[PTD_DATAUNDERRUN]; - } - goto out; - } - } - - if (cc != PTD_CC_NOERROR) { - if (++ep->error_count >= 3 || cc == PTD_CC_STALL || cc == PTD_DATAOVERRUN) { - urbstat = cc_to_error[cc]; - DBG(1, "%s: req %d nextpid %02x, status %d, error %d, error_count %d\n", - __func__, ep->num_req, ep->nextpid, urbstat, cc, - ep->error_count); - } - goto out; - } - - switch (ep->nextpid) { - case USB_PID_OUT: - if (PTD_GET_COUNT(ptd) != ep->length) - pr_err("%s: count=%d len=%d\n", __func__, - PTD_GET_COUNT(ptd), ep->length); - BUG_ON(PTD_GET_COUNT(ptd) != ep->length); - urb->actual_length += ep->length; - BUG_ON(urb->actual_length > urb->transfer_buffer_length); - usb_settoggle(udev, ep->epnum, 1, PTD_GET_TOGGLE(ptd)); - if (urb->actual_length == urb->transfer_buffer_length) { - DBG(3, "%s: req %d xfer complete %d/%d status %d -> 0\n", __func__, - ep->num_req, len, ep->maxpacket, urbstat); - if (usb_pipecontrol(urb->pipe)) { - DBG(3, "%s: req %d %s Wait for ACK\n", __func__, - ep->num_req, - usb_pipein(urb->pipe) ? "IN" : "OUT"); - ep->nextpid = USB_PID_ACK; - } else { - if (len % ep->maxpacket || - !(urb->transfer_flags & URB_ZERO_PACKET)) { - urbstat = 0; - DBG(3, "%s: req %d URB %s status %d count %d/%d/%d\n", - __func__, ep->num_req, usb_pipein(urb->pipe) ? "IN" : "OUT", - urbstat, len, ep->maxpacket, urb->actual_length); - } - } - } - break; - case USB_PID_IN: - len = PTD_GET_COUNT(ptd); - BUG_ON(len > ep->length); - urb->actual_length += len; - BUG_ON(urb->actual_length > urb->transfer_buffer_length); - usb_settoggle(udev, ep->epnum, 0, PTD_GET_TOGGLE(ptd)); - /* if transfer completed or (allowed) data underrun */ - if ((urb->transfer_buffer_length == urb->actual_length) || - len % ep->maxpacket) { - DBG(3, "%s: req %d xfer complete %d/%d status %d -> 0\n", __func__, - ep->num_req, len, ep->maxpacket, urbstat); - if (usb_pipecontrol(urb->pipe)) { - DBG(3, "%s: req %d %s Wait for ACK\n", __func__, - ep->num_req, - usb_pipein(urb->pipe) ? "IN" : "OUT"); - ep->nextpid = USB_PID_ACK; - } else { - urbstat = 0; - DBG(3, "%s: req %d URB %s status %d count %d/%d/%d\n", - __func__, ep->num_req, usb_pipein(urb->pipe) ? "IN" : "OUT", - urbstat, len, ep->maxpacket, urb->actual_length); - } - } - break; - case USB_PID_SETUP: - if (urb->transfer_buffer_length == urb->actual_length) { - ep->nextpid = USB_PID_ACK; - } else if (usb_pipeout(urb->pipe)) { - usb_settoggle(udev, 0, 1, 1); - ep->nextpid = USB_PID_OUT; - } else { - usb_settoggle(udev, 0, 0, 1); - ep->nextpid = USB_PID_IN; - } - break; - case USB_PID_ACK: - DBG(3, "%s: req %d got ACK %d -> 0\n", __func__, ep->num_req, - urbstat); - WARN_ON(urbstat != -EINPROGRESS); - urbstat = 0; - ep->nextpid = 0; - break; - default: - BUG_ON(1); - } - - out: - if (urbstat != -EINPROGRESS) { - DBG(2, "%s: Finishing ep %p req %d urb %p status %d\n", __func__, - ep, ep->num_req, urb, urbstat); - finish_request(isp1362_hcd, ep, urb, urbstat); - } -} - -static void finish_unlinks(struct isp1362_hcd *isp1362_hcd) -{ - struct isp1362_ep *ep; - struct isp1362_ep *tmp; - - list_for_each_entry_safe(ep, tmp, &isp1362_hcd->remove_list, remove_list) { - struct isp1362_ep_queue *epq = - get_ptd_queue(isp1362_hcd, ep->ptd_offset); - int index = ep->ptd_index; - - BUG_ON(epq == NULL); - if (index >= 0) { - DBG(1, "%s: remove PTD[%d] $%04x\n", __func__, index, ep->ptd_offset); - BUG_ON(ep->num_ptds == 0); - release_ptd_buffers(epq, ep); - } - if (!list_empty(&ep->hep->urb_list)) { - struct urb *urb = get_urb(ep); - - DBG(1, "%s: Finishing req %d ep %p from remove_list\n", __func__, - ep->num_req, ep); - finish_request(isp1362_hcd, ep, urb, -ESHUTDOWN); - } - WARN_ON(list_empty(&ep->active)); - if (!list_empty(&ep->active)) { - list_del_init(&ep->active); - DBG(1, "%s: ep %p removed from active list\n", __func__, ep); - } - list_del_init(&ep->remove_list); - DBG(1, "%s: ep %p removed from remove_list\n", __func__, ep); - } - DBG(1, "%s: Done\n", __func__); -} - -static inline void enable_atl_transfers(struct isp1362_hcd *isp1362_hcd, int count) -{ - if (count > 0) { - if (count < isp1362_hcd->atl_queue.ptd_count) - isp1362_write_reg16(isp1362_hcd, HCATLDTC, count); - isp1362_enable_int(isp1362_hcd, HCuPINT_ATL); - isp1362_write_reg32(isp1362_hcd, HCATLSKIP, isp1362_hcd->atl_queue.skip_map); - isp1362_set_mask16(isp1362_hcd, HCBUFSTAT, HCBUFSTAT_ATL_ACTIVE); - } else - isp1362_enable_int(isp1362_hcd, HCuPINT_SOF); -} - -static inline void enable_intl_transfers(struct isp1362_hcd *isp1362_hcd) -{ - isp1362_enable_int(isp1362_hcd, HCuPINT_INTL); - isp1362_set_mask16(isp1362_hcd, HCBUFSTAT, HCBUFSTAT_INTL_ACTIVE); - isp1362_write_reg32(isp1362_hcd, HCINTLSKIP, isp1362_hcd->intl_queue.skip_map); -} - -static inline void enable_istl_transfers(struct isp1362_hcd *isp1362_hcd, int flip) -{ - isp1362_enable_int(isp1362_hcd, flip ? HCuPINT_ISTL1 : HCuPINT_ISTL0); - isp1362_set_mask16(isp1362_hcd, HCBUFSTAT, flip ? - HCBUFSTAT_ISTL1_FULL : HCBUFSTAT_ISTL0_FULL); -} - -static int submit_req(struct isp1362_hcd *isp1362_hcd, struct urb *urb, - struct isp1362_ep *ep, struct isp1362_ep_queue *epq) -{ - int index = epq->free_ptd; - - prepare_ptd(isp1362_hcd, urb, ep, epq, 0); - index = claim_ptd_buffers(epq, ep, ep->length); - if (index == -ENOMEM) { - DBG(1, "%s: req %d No free %s PTD available: %d, %08lx:%08lx\n", __func__, - ep->num_req, epq->name, ep->num_ptds, epq->buf_map, epq->skip_map); - return index; - } else if (index == -EOVERFLOW) { - DBG(1, "%s: req %d Not enough space for %d byte %s PTD %d %08lx:%08lx\n", - __func__, ep->num_req, ep->length, epq->name, ep->num_ptds, - epq->buf_map, epq->skip_map); - return index; - } else - BUG_ON(index < 0); - list_add_tail(&ep->active, &epq->active); - DBG(1, "%s: ep %p req %d len %d added to active list %p\n", __func__, - ep, ep->num_req, ep->length, &epq->active); - DBG(1, "%s: Submitting %s PTD $%04x for ep %p req %d\n", __func__, epq->name, - ep->ptd_offset, ep, ep->num_req); - isp1362_write_ptd(isp1362_hcd, ep, epq); - __clear_bit(ep->ptd_index, &epq->skip_map); - - return 0; -} - -static void start_atl_transfers(struct isp1362_hcd *isp1362_hcd) -{ - int ptd_count = 0; - struct isp1362_ep_queue *epq = &isp1362_hcd->atl_queue; - struct isp1362_ep *ep; - int defer = 0; - - if (atomic_read(&epq->finishing)) { - DBG(1, "%s: finish_transfers is active for %s\n", __func__, epq->name); - return; - } - - list_for_each_entry(ep, &isp1362_hcd->async, schedule) { - struct urb *urb = get_urb(ep); - int ret; - - if (!list_empty(&ep->active)) { - DBG(2, "%s: Skipping active %s ep %p\n", __func__, epq->name, ep); - continue; - } - - DBG(1, "%s: Processing %s ep %p req %d\n", __func__, epq->name, - ep, ep->num_req); - - ret = submit_req(isp1362_hcd, urb, ep, epq); - if (ret == -ENOMEM) { - defer = 1; - break; - } else if (ret == -EOVERFLOW) { - defer = 1; - continue; - } -#ifdef BUGGY_PXA2XX_UDC_USBTEST - defer = ep->nextpid == USB_PID_SETUP; -#endif - ptd_count++; - } - - /* Avoid starving of endpoints */ - if (isp1362_hcd->async.next != isp1362_hcd->async.prev) { - DBG(2, "%s: Cycling ASYNC schedule %d\n", __func__, ptd_count); - list_move(&isp1362_hcd->async, isp1362_hcd->async.next); - } - if (ptd_count || defer) - enable_atl_transfers(isp1362_hcd, defer ? 0 : ptd_count); - - epq->ptd_count += ptd_count; - if (epq->ptd_count > epq->stat_maxptds) { - epq->stat_maxptds = epq->ptd_count; - DBG(0, "%s: max_ptds: %d\n", __func__, epq->stat_maxptds); - } -} - -static void start_intl_transfers(struct isp1362_hcd *isp1362_hcd) -{ - int ptd_count = 0; - struct isp1362_ep_queue *epq = &isp1362_hcd->intl_queue; - struct isp1362_ep *ep; - - if (atomic_read(&epq->finishing)) { - DBG(1, "%s: finish_transfers is active for %s\n", __func__, epq->name); - return; - } - - list_for_each_entry(ep, &isp1362_hcd->periodic, schedule) { - struct urb *urb = get_urb(ep); - int ret; - - if (!list_empty(&ep->active)) { - DBG(1, "%s: Skipping active %s ep %p\n", __func__, - epq->name, ep); - continue; - } - - DBG(1, "%s: Processing %s ep %p req %d\n", __func__, - epq->name, ep, ep->num_req); - ret = submit_req(isp1362_hcd, urb, ep, epq); - if (ret == -ENOMEM) - break; - else if (ret == -EOVERFLOW) - continue; - ptd_count++; - } - - if (ptd_count) { - static int last_count; - - if (ptd_count != last_count) { - DBG(0, "%s: ptd_count: %d\n", __func__, ptd_count); - last_count = ptd_count; - } - enable_intl_transfers(isp1362_hcd); - } - - epq->ptd_count += ptd_count; - if (epq->ptd_count > epq->stat_maxptds) - epq->stat_maxptds = epq->ptd_count; -} - -static inline int next_ptd(struct isp1362_ep_queue *epq, struct isp1362_ep *ep) -{ - u16 ptd_offset = ep->ptd_offset; - int num_ptds = (ep->length + PTD_HEADER_SIZE + (epq->blk_size - 1)) / epq->blk_size; - - DBG(2, "%s: PTD offset $%04x + %04x => %d * %04x -> $%04x\n", __func__, ptd_offset, - ep->length, num_ptds, epq->blk_size, ptd_offset + num_ptds * epq->blk_size); - - ptd_offset += num_ptds * epq->blk_size; - if (ptd_offset < epq->buf_start + epq->buf_size) - return ptd_offset; - else - return -ENOMEM; -} - -static void start_iso_transfers(struct isp1362_hcd *isp1362_hcd) -{ - int ptd_count = 0; - int flip = isp1362_hcd->istl_flip; - struct isp1362_ep_queue *epq; - int ptd_offset; - struct isp1362_ep *ep; - struct isp1362_ep *tmp; - u16 fno = isp1362_read_reg32(isp1362_hcd, HCFMNUM); - - fill2: - epq = &isp1362_hcd->istl_queue[flip]; - if (atomic_read(&epq->finishing)) { - DBG(1, "%s: finish_transfers is active for %s\n", __func__, epq->name); - return; - } - - if (!list_empty(&epq->active)) - return; - - ptd_offset = epq->buf_start; - list_for_each_entry_safe(ep, tmp, &isp1362_hcd->isoc, schedule) { - struct urb *urb = get_urb(ep); - s16 diff = fno - (u16)urb->start_frame; - - DBG(1, "%s: Processing %s ep %p\n", __func__, epq->name, ep); - - if (diff > urb->number_of_packets) { - /* time frame for this URB has elapsed */ - finish_request(isp1362_hcd, ep, urb, -EOVERFLOW); - continue; - } else if (diff < -1) { - /* URB is not due in this frame or the next one. - * Comparing with '-1' instead of '0' accounts for double - * buffering in the ISP1362 which enables us to queue the PTD - * one frame ahead of time - */ - } else if (diff == -1) { - /* submit PTD's that are due in the next frame */ - prepare_ptd(isp1362_hcd, urb, ep, epq, fno); - if (ptd_offset + PTD_HEADER_SIZE + ep->length > - epq->buf_start + epq->buf_size) { - pr_err("%s: Not enough ISO buffer space for %d byte PTD\n", - __func__, ep->length); - continue; - } - ep->ptd_offset = ptd_offset; - list_add_tail(&ep->active, &epq->active); - - ptd_offset = next_ptd(epq, ep); - if (ptd_offset < 0) { - pr_warning("%s: req %d No more %s PTD buffers available\n", __func__, - ep->num_req, epq->name); - break; - } - } - } - list_for_each_entry(ep, &epq->active, active) { - if (epq->active.next == &ep->active) - ep->ptd.mps |= PTD_LAST_MSK; - isp1362_write_ptd(isp1362_hcd, ep, epq); - ptd_count++; - } - - if (ptd_count) - enable_istl_transfers(isp1362_hcd, flip); - - epq->ptd_count += ptd_count; - if (epq->ptd_count > epq->stat_maxptds) - epq->stat_maxptds = epq->ptd_count; - - /* check, whether the second ISTL buffer may also be filled */ - if (!(isp1362_read_reg16(isp1362_hcd, HCBUFSTAT) & - (flip ? HCBUFSTAT_ISTL0_FULL : HCBUFSTAT_ISTL1_FULL))) { - fno++; - ptd_count = 0; - flip = 1 - flip; - goto fill2; - } -} - -static void finish_transfers(struct isp1362_hcd *isp1362_hcd, unsigned long done_map, - struct isp1362_ep_queue *epq) -{ - struct isp1362_ep *ep; - struct isp1362_ep *tmp; - - if (list_empty(&epq->active)) { - DBG(1, "%s: Nothing to do for %s queue\n", __func__, epq->name); - return; - } - - DBG(1, "%s: Finishing %s transfers %08lx\n", __func__, epq->name, done_map); - - atomic_inc(&epq->finishing); - list_for_each_entry_safe(ep, tmp, &epq->active, active) { - int index = ep->ptd_index; - - DBG(1, "%s: Checking %s PTD[%02x] $%04x\n", __func__, epq->name, - index, ep->ptd_offset); - - BUG_ON(index < 0); - if (__test_and_clear_bit(index, &done_map)) { - isp1362_read_ptd(isp1362_hcd, ep, epq); - epq->free_ptd = index; - BUG_ON(ep->num_ptds == 0); - release_ptd_buffers(epq, ep); - - DBG(1, "%s: ep %p req %d removed from active list\n", __func__, - ep, ep->num_req); - if (!list_empty(&ep->remove_list)) { - list_del_init(&ep->remove_list); - DBG(1, "%s: ep %p removed from remove list\n", __func__, ep); - } - DBG(1, "%s: Postprocessing %s ep %p req %d\n", __func__, epq->name, - ep, ep->num_req); - postproc_ep(isp1362_hcd, ep); - } - if (!done_map) - break; - } - if (done_map) - pr_warning("%s: done_map not clear: %08lx:%08lx\n", __func__, done_map, - epq->skip_map); - atomic_dec(&epq->finishing); -} - -static void finish_iso_transfers(struct isp1362_hcd *isp1362_hcd, struct isp1362_ep_queue *epq) -{ - struct isp1362_ep *ep; - struct isp1362_ep *tmp; - - if (list_empty(&epq->active)) { - DBG(1, "%s: Nothing to do for %s queue\n", __func__, epq->name); - return; - } - - DBG(1, "%s: Finishing %s transfers\n", __func__, epq->name); - - atomic_inc(&epq->finishing); - list_for_each_entry_safe(ep, tmp, &epq->active, active) { - DBG(1, "%s: Checking PTD $%04x\n", __func__, ep->ptd_offset); - - isp1362_read_ptd(isp1362_hcd, ep, epq); - DBG(1, "%s: Postprocessing %s ep %p\n", __func__, epq->name, ep); - postproc_ep(isp1362_hcd, ep); - } - WARN_ON(epq->blk_size != 0); - atomic_dec(&epq->finishing); -} - -static irqreturn_t isp1362_irq(struct usb_hcd *hcd) -{ - int handled = 0; - struct isp1362_hcd *isp1362_hcd = hcd_to_isp1362_hcd(hcd); - u16 irqstat; - u16 svc_mask; - - spin_lock(&isp1362_hcd->lock); - - BUG_ON(isp1362_hcd->irq_active++); - - isp1362_write_reg16(isp1362_hcd, HCuPINTENB, 0); - - irqstat = isp1362_read_reg16(isp1362_hcd, HCuPINT); - DBG(3, "%s: got IRQ %04x:%04x\n", __func__, irqstat, isp1362_hcd->irqenb); - - /* only handle interrupts that are currently enabled */ - irqstat &= isp1362_hcd->irqenb; - isp1362_write_reg16(isp1362_hcd, HCuPINT, irqstat); - svc_mask = irqstat; - - if (irqstat & HCuPINT_SOF) { - isp1362_hcd->irqenb &= ~HCuPINT_SOF; - isp1362_hcd->irq_stat[ISP1362_INT_SOF]++; - handled = 1; - svc_mask &= ~HCuPINT_SOF; - DBG(3, "%s: SOF\n", __func__); - isp1362_hcd->fmindex = isp1362_read_reg32(isp1362_hcd, HCFMNUM); - if (!list_empty(&isp1362_hcd->remove_list)) - finish_unlinks(isp1362_hcd); - if (!list_empty(&isp1362_hcd->async) && !(irqstat & HCuPINT_ATL)) { - if (list_empty(&isp1362_hcd->atl_queue.active)) { - start_atl_transfers(isp1362_hcd); - } else { - isp1362_enable_int(isp1362_hcd, HCuPINT_ATL); - isp1362_write_reg32(isp1362_hcd, HCATLSKIP, - isp1362_hcd->atl_queue.skip_map); - isp1362_set_mask16(isp1362_hcd, HCBUFSTAT, HCBUFSTAT_ATL_ACTIVE); - } - } - } - - if (irqstat & HCuPINT_ISTL0) { - isp1362_hcd->irq_stat[ISP1362_INT_ISTL0]++; - handled = 1; - svc_mask &= ~HCuPINT_ISTL0; - isp1362_clr_mask16(isp1362_hcd, HCBUFSTAT, HCBUFSTAT_ISTL0_FULL); - DBG(1, "%s: ISTL0\n", __func__); - WARN_ON((int)!!isp1362_hcd->istl_flip); - WARN_ON(isp1362_read_reg16(isp1362_hcd, HCBUFSTAT) & - HCBUFSTAT_ISTL0_ACTIVE); - WARN_ON(!(isp1362_read_reg16(isp1362_hcd, HCBUFSTAT) & - HCBUFSTAT_ISTL0_DONE)); - isp1362_hcd->irqenb &= ~HCuPINT_ISTL0; - } - - if (irqstat & HCuPINT_ISTL1) { - isp1362_hcd->irq_stat[ISP1362_INT_ISTL1]++; - handled = 1; - svc_mask &= ~HCuPINT_ISTL1; - isp1362_clr_mask16(isp1362_hcd, HCBUFSTAT, HCBUFSTAT_ISTL1_FULL); - DBG(1, "%s: ISTL1\n", __func__); - WARN_ON(!(int)isp1362_hcd->istl_flip); - WARN_ON(isp1362_read_reg16(isp1362_hcd, HCBUFSTAT) & - HCBUFSTAT_ISTL1_ACTIVE); - WARN_ON(!(isp1362_read_reg16(isp1362_hcd, HCBUFSTAT) & - HCBUFSTAT_ISTL1_DONE)); - isp1362_hcd->irqenb &= ~HCuPINT_ISTL1; - } - - if (irqstat & (HCuPINT_ISTL0 | HCuPINT_ISTL1)) { - WARN_ON((irqstat & (HCuPINT_ISTL0 | HCuPINT_ISTL1)) == - (HCuPINT_ISTL0 | HCuPINT_ISTL1)); - finish_iso_transfers(isp1362_hcd, - &isp1362_hcd->istl_queue[isp1362_hcd->istl_flip]); - start_iso_transfers(isp1362_hcd); - isp1362_hcd->istl_flip = 1 - isp1362_hcd->istl_flip; - } - - if (irqstat & HCuPINT_INTL) { - u32 done_map = isp1362_read_reg32(isp1362_hcd, HCINTLDONE); - u32 skip_map = isp1362_read_reg32(isp1362_hcd, HCINTLSKIP); - isp1362_hcd->irq_stat[ISP1362_INT_INTL]++; - - DBG(2, "%s: INTL\n", __func__); - - svc_mask &= ~HCuPINT_INTL; - - isp1362_write_reg32(isp1362_hcd, HCINTLSKIP, skip_map | done_map); - if (~(done_map | skip_map) == 0) - /* All PTDs are finished, disable INTL processing entirely */ - isp1362_clr_mask16(isp1362_hcd, HCBUFSTAT, HCBUFSTAT_INTL_ACTIVE); - - handled = 1; - WARN_ON(!done_map); - if (done_map) { - DBG(3, "%s: INTL done_map %08x\n", __func__, done_map); - finish_transfers(isp1362_hcd, done_map, &isp1362_hcd->intl_queue); - start_intl_transfers(isp1362_hcd); - } - } - - if (irqstat & HCuPINT_ATL) { - u32 done_map = isp1362_read_reg32(isp1362_hcd, HCATLDONE); - u32 skip_map = isp1362_read_reg32(isp1362_hcd, HCATLSKIP); - isp1362_hcd->irq_stat[ISP1362_INT_ATL]++; - - DBG(2, "%s: ATL\n", __func__); - - svc_mask &= ~HCuPINT_ATL; - - isp1362_write_reg32(isp1362_hcd, HCATLSKIP, skip_map | done_map); - if (~(done_map | skip_map) == 0) - isp1362_clr_mask16(isp1362_hcd, HCBUFSTAT, HCBUFSTAT_ATL_ACTIVE); - if (done_map) { - DBG(3, "%s: ATL done_map %08x\n", __func__, done_map); - finish_transfers(isp1362_hcd, done_map, &isp1362_hcd->atl_queue); - start_atl_transfers(isp1362_hcd); - } - handled = 1; - } - - if (irqstat & HCuPINT_OPR) { - u32 intstat = isp1362_read_reg32(isp1362_hcd, HCINTSTAT); - isp1362_hcd->irq_stat[ISP1362_INT_OPR]++; - - svc_mask &= ~HCuPINT_OPR; - DBG(2, "%s: OPR %08x:%08x\n", __func__, intstat, isp1362_hcd->intenb); - intstat &= isp1362_hcd->intenb; - if (intstat & OHCI_INTR_UE) { - pr_err("Unrecoverable error\n"); - /* FIXME: do here reset or cleanup or whatever */ - } - if (intstat & OHCI_INTR_RHSC) { - isp1362_hcd->rhstatus = isp1362_read_reg32(isp1362_hcd, HCRHSTATUS); - isp1362_hcd->rhport[0] = isp1362_read_reg32(isp1362_hcd, HCRHPORT1); - isp1362_hcd->rhport[1] = isp1362_read_reg32(isp1362_hcd, HCRHPORT2); - } - if (intstat & OHCI_INTR_RD) { - pr_info("%s: RESUME DETECTED\n", __func__); - isp1362_show_reg(isp1362_hcd, HCCONTROL); - usb_hcd_resume_root_hub(hcd); - } - isp1362_write_reg32(isp1362_hcd, HCINTSTAT, intstat); - irqstat &= ~HCuPINT_OPR; - handled = 1; - } - - if (irqstat & HCuPINT_SUSP) { - isp1362_hcd->irq_stat[ISP1362_INT_SUSP]++; - handled = 1; - svc_mask &= ~HCuPINT_SUSP; - - pr_info("%s: SUSPEND IRQ\n", __func__); - } - - if (irqstat & HCuPINT_CLKRDY) { - isp1362_hcd->irq_stat[ISP1362_INT_CLKRDY]++; - handled = 1; - isp1362_hcd->irqenb &= ~HCuPINT_CLKRDY; - svc_mask &= ~HCuPINT_CLKRDY; - pr_info("%s: CLKRDY IRQ\n", __func__); - } - - if (svc_mask) - pr_err("%s: Unserviced interrupt(s) %04x\n", __func__, svc_mask); - - isp1362_write_reg16(isp1362_hcd, HCuPINTENB, isp1362_hcd->irqenb); - isp1362_hcd->irq_active--; - spin_unlock(&isp1362_hcd->lock); - - return IRQ_RETVAL(handled); -} - -/*-------------------------------------------------------------------------*/ - -#define MAX_PERIODIC_LOAD 900 /* out of 1000 usec */ -static int balance(struct isp1362_hcd *isp1362_hcd, u16 interval, u16 load) -{ - int i, branch = -ENOSPC; - - /* search for the least loaded schedule branch of that interval - * which has enough bandwidth left unreserved. - */ - for (i = 0; i < interval; i++) { - if (branch < 0 || isp1362_hcd->load[branch] > isp1362_hcd->load[i]) { - int j; - - for (j = i; j < PERIODIC_SIZE; j += interval) { - if ((isp1362_hcd->load[j] + load) > MAX_PERIODIC_LOAD) { - pr_err("%s: new load %d load[%02x] %d max %d\n", __func__, - load, j, isp1362_hcd->load[j], MAX_PERIODIC_LOAD); - break; - } - } - if (j < PERIODIC_SIZE) - continue; - branch = i; - } - } - return branch; -} - -/* NB! ALL the code above this point runs with isp1362_hcd->lock - held, irqs off -*/ - -/*-------------------------------------------------------------------------*/ - -static int isp1362_urb_enqueue(struct usb_hcd *hcd, - struct urb *urb, - gfp_t mem_flags) -{ - struct isp1362_hcd *isp1362_hcd = hcd_to_isp1362_hcd(hcd); - struct usb_device *udev = urb->dev; - unsigned int pipe = urb->pipe; - int is_out = !usb_pipein(pipe); - int type = usb_pipetype(pipe); - int epnum = usb_pipeendpoint(pipe); - struct usb_host_endpoint *hep = urb->ep; - struct isp1362_ep *ep = NULL; - unsigned long flags; - int retval = 0; - - DBG(3, "%s: urb %p\n", __func__, urb); - - if (type == PIPE_ISOCHRONOUS) { - pr_err("Isochronous transfers not supported\n"); - return -ENOSPC; - } - - URB_DBG("%s: FA %d ep%d%s %s: len %d %s%s\n", __func__, - usb_pipedevice(pipe), epnum, - is_out ? "out" : "in", - usb_pipecontrol(pipe) ? "ctrl" : - usb_pipeint(pipe) ? "int" : - usb_pipebulk(pipe) ? "bulk" : - "iso", - urb->transfer_buffer_length, - (urb->transfer_flags & URB_ZERO_PACKET) ? "ZERO_PACKET " : "", - !(urb->transfer_flags & URB_SHORT_NOT_OK) ? - "short_ok" : ""); - - /* avoid all allocations within spinlocks: request or endpoint */ - if (!hep->hcpriv) { - ep = kzalloc(sizeof *ep, mem_flags); - if (!ep) - return -ENOMEM; - } - spin_lock_irqsave(&isp1362_hcd->lock, flags); - - /* don't submit to a dead or disabled port */ - if (!((isp1362_hcd->rhport[0] | isp1362_hcd->rhport[1]) & - USB_PORT_STAT_ENABLE) || - !HC_IS_RUNNING(hcd->state)) { - kfree(ep); - retval = -ENODEV; - goto fail_not_linked; - } - - retval = usb_hcd_link_urb_to_ep(hcd, urb); - if (retval) { - kfree(ep); - goto fail_not_linked; - } - - if (hep->hcpriv) { - ep = hep->hcpriv; - } else { - INIT_LIST_HEAD(&ep->schedule); - INIT_LIST_HEAD(&ep->active); - INIT_LIST_HEAD(&ep->remove_list); - ep->udev = usb_get_dev(udev); - ep->hep = hep; - ep->epnum = epnum; - ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out); - ep->ptd_offset = -EINVAL; - ep->ptd_index = -EINVAL; - usb_settoggle(udev, epnum, is_out, 0); - - if (type == PIPE_CONTROL) - ep->nextpid = USB_PID_SETUP; - else if (is_out) - ep->nextpid = USB_PID_OUT; - else - ep->nextpid = USB_PID_IN; - - switch (type) { - case PIPE_ISOCHRONOUS: - case PIPE_INTERRUPT: - if (urb->interval > PERIODIC_SIZE) - urb->interval = PERIODIC_SIZE; - ep->interval = urb->interval; - ep->branch = PERIODIC_SIZE; - ep->load = usb_calc_bus_time(udev->speed, !is_out, - (type == PIPE_ISOCHRONOUS), - usb_maxpacket(udev, pipe, is_out)) / 1000; - break; - } - hep->hcpriv = ep; - } - ep->num_req = isp1362_hcd->req_serial++; - - /* maybe put endpoint into schedule */ - switch (type) { - case PIPE_CONTROL: - case PIPE_BULK: - if (list_empty(&ep->schedule)) { - DBG(1, "%s: Adding ep %p req %d to async schedule\n", - __func__, ep, ep->num_req); - list_add_tail(&ep->schedule, &isp1362_hcd->async); - } - break; - case PIPE_ISOCHRONOUS: - case PIPE_INTERRUPT: - urb->interval = ep->interval; - - /* urb submitted for already existing EP */ - if (ep->branch < PERIODIC_SIZE) - break; - - retval = balance(isp1362_hcd, ep->interval, ep->load); - if (retval < 0) { - pr_err("%s: balance returned %d\n", __func__, retval); - goto fail; - } - ep->branch = retval; - retval = 0; - isp1362_hcd->fmindex = isp1362_read_reg32(isp1362_hcd, HCFMNUM); - DBG(1, "%s: Current frame %04x branch %02x start_frame %04x(%04x)\n", - __func__, isp1362_hcd->fmindex, ep->branch, - ((isp1362_hcd->fmindex + PERIODIC_SIZE - 1) & - ~(PERIODIC_SIZE - 1)) + ep->branch, - (isp1362_hcd->fmindex & (PERIODIC_SIZE - 1)) + ep->branch); - - if (list_empty(&ep->schedule)) { - if (type == PIPE_ISOCHRONOUS) { - u16 frame = isp1362_hcd->fmindex; - - frame += max_t(u16, 8, ep->interval); - frame &= ~(ep->interval - 1); - frame |= ep->branch; - if (frame_before(frame, isp1362_hcd->fmindex)) - frame += ep->interval; - urb->start_frame = frame; - - DBG(1, "%s: Adding ep %p to isoc schedule\n", __func__, ep); - list_add_tail(&ep->schedule, &isp1362_hcd->isoc); - } else { - DBG(1, "%s: Adding ep %p to periodic schedule\n", __func__, ep); - list_add_tail(&ep->schedule, &isp1362_hcd->periodic); - } - } else - DBG(1, "%s: ep %p already scheduled\n", __func__, ep); - - DBG(2, "%s: load %d bandwidth %d -> %d\n", __func__, - ep->load / ep->interval, isp1362_hcd->load[ep->branch], - isp1362_hcd->load[ep->branch] + ep->load); - isp1362_hcd->load[ep->branch] += ep->load; - } - - urb->hcpriv = hep; - ALIGNSTAT(isp1362_hcd, urb->transfer_buffer); - - switch (type) { - case PIPE_CONTROL: - case PIPE_BULK: - start_atl_transfers(isp1362_hcd); - break; - case PIPE_INTERRUPT: - start_intl_transfers(isp1362_hcd); - break; - case PIPE_ISOCHRONOUS: - start_iso_transfers(isp1362_hcd); - break; - default: - BUG(); - } - fail: - if (retval) - usb_hcd_unlink_urb_from_ep(hcd, urb); - - - fail_not_linked: - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - if (retval) - DBG(0, "%s: urb %p failed with %d\n", __func__, urb, retval); - return retval; -} - -static int isp1362_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) -{ - struct isp1362_hcd *isp1362_hcd = hcd_to_isp1362_hcd(hcd); - struct usb_host_endpoint *hep; - unsigned long flags; - struct isp1362_ep *ep; - int retval = 0; - - DBG(3, "%s: urb %p\n", __func__, urb); - - spin_lock_irqsave(&isp1362_hcd->lock, flags); - retval = usb_hcd_check_unlink_urb(hcd, urb, status); - if (retval) - goto done; - - hep = urb->hcpriv; - - if (!hep) { - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - return -EIDRM; - } - - ep = hep->hcpriv; - if (ep) { - /* In front of queue? */ - if (ep->hep->urb_list.next == &urb->urb_list) { - if (!list_empty(&ep->active)) { - DBG(1, "%s: urb %p ep %p req %d active PTD[%d] $%04x\n", __func__, - urb, ep, ep->num_req, ep->ptd_index, ep->ptd_offset); - /* disable processing and queue PTD for removal */ - remove_ptd(isp1362_hcd, ep); - urb = NULL; - } - } - if (urb) { - DBG(1, "%s: Finishing ep %p req %d\n", __func__, ep, - ep->num_req); - finish_request(isp1362_hcd, ep, urb, status); - } else - DBG(1, "%s: urb %p active; wait4irq\n", __func__, urb); - } else { - pr_warning("%s: No EP in URB %p\n", __func__, urb); - retval = -EINVAL; - } -done: - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - - DBG(3, "%s: exit\n", __func__); - - return retval; -} - -static void isp1362_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep) -{ - struct isp1362_ep *ep = hep->hcpriv; - struct isp1362_hcd *isp1362_hcd = hcd_to_isp1362_hcd(hcd); - unsigned long flags; - - DBG(1, "%s: ep %p\n", __func__, ep); - if (!ep) - return; - spin_lock_irqsave(&isp1362_hcd->lock, flags); - if (!list_empty(&hep->urb_list)) { - if (!list_empty(&ep->active) && list_empty(&ep->remove_list)) { - DBG(1, "%s: Removing ep %p req %d PTD[%d] $%04x\n", __func__, - ep, ep->num_req, ep->ptd_index, ep->ptd_offset); - remove_ptd(isp1362_hcd, ep); - pr_info("%s: Waiting for Interrupt to clean up\n", __func__); - } - } - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - /* Wait for interrupt to clear out active list */ - while (!list_empty(&ep->active)) - msleep(1); - - DBG(1, "%s: Freeing EP %p\n", __func__, ep); - - usb_put_dev(ep->udev); - kfree(ep); - hep->hcpriv = NULL; -} - -static int isp1362_get_frame(struct usb_hcd *hcd) -{ - struct isp1362_hcd *isp1362_hcd = hcd_to_isp1362_hcd(hcd); - u32 fmnum; - unsigned long flags; - - spin_lock_irqsave(&isp1362_hcd->lock, flags); - fmnum = isp1362_read_reg32(isp1362_hcd, HCFMNUM); - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - - return (int)fmnum; -} - -/*-------------------------------------------------------------------------*/ - -/* Adapted from ohci-hub.c */ -static int isp1362_hub_status_data(struct usb_hcd *hcd, char *buf) -{ - struct isp1362_hcd *isp1362_hcd = hcd_to_isp1362_hcd(hcd); - int ports, i, changed = 0; - unsigned long flags; - - if (!HC_IS_RUNNING(hcd->state)) - return -ESHUTDOWN; - - /* Report no status change now, if we are scheduled to be - called later */ - if (timer_pending(&hcd->rh_timer)) - return 0; - - ports = isp1362_hcd->rhdesca & RH_A_NDP; - BUG_ON(ports > 2); - - spin_lock_irqsave(&isp1362_hcd->lock, flags); - /* init status */ - if (isp1362_hcd->rhstatus & (RH_HS_LPSC | RH_HS_OCIC)) - buf[0] = changed = 1; - else - buf[0] = 0; - - for (i = 0; i < ports; i++) { - u32 status = isp1362_hcd->rhport[i]; - - if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC | - RH_PS_OCIC | RH_PS_PRSC)) { - changed = 1; - buf[0] |= 1 << (i + 1); - continue; - } - - if (!(status & RH_PS_CCS)) - continue; - } - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - return changed; -} - -static void isp1362_hub_descriptor(struct isp1362_hcd *isp1362_hcd, - struct usb_hub_descriptor *desc) -{ - u32 reg = isp1362_hcd->rhdesca; - - DBG(3, "%s: enter\n", __func__); - - desc->bDescriptorType = 0x29; - desc->bDescLength = 9; - desc->bHubContrCurrent = 0; - desc->bNbrPorts = reg & 0x3; - /* Power switching, device type, overcurrent. */ - desc->wHubCharacteristics = cpu_to_le16((reg >> 8) & 0x1f); - DBG(0, "%s: hubcharacteristics = %02x\n", __func__, cpu_to_le16((reg >> 8) & 0x1f)); - desc->bPwrOn2PwrGood = (reg >> 24) & 0xff; - /* ports removable, and legacy PortPwrCtrlMask */ - desc->u.hs.DeviceRemovable[0] = desc->bNbrPorts == 1 ? 1 << 1 : 3 << 1; - desc->u.hs.DeviceRemovable[1] = ~0; - - DBG(3, "%s: exit\n", __func__); -} - -/* Adapted from ohci-hub.c */ -static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, - u16 wIndex, char *buf, u16 wLength) -{ - struct isp1362_hcd *isp1362_hcd = hcd_to_isp1362_hcd(hcd); - int retval = 0; - unsigned long flags; - unsigned long t1; - int ports = isp1362_hcd->rhdesca & RH_A_NDP; - u32 tmp = 0; - - switch (typeReq) { - case ClearHubFeature: - DBG(0, "ClearHubFeature: "); - switch (wValue) { - case C_HUB_OVER_CURRENT: - _DBG(0, "C_HUB_OVER_CURRENT\n"); - spin_lock_irqsave(&isp1362_hcd->lock, flags); - isp1362_write_reg32(isp1362_hcd, HCRHSTATUS, RH_HS_OCIC); - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - case C_HUB_LOCAL_POWER: - _DBG(0, "C_HUB_LOCAL_POWER\n"); - break; - default: - goto error; - } - break; - case SetHubFeature: - DBG(0, "SetHubFeature: "); - switch (wValue) { - case C_HUB_OVER_CURRENT: - case C_HUB_LOCAL_POWER: - _DBG(0, "C_HUB_OVER_CURRENT or C_HUB_LOCAL_POWER\n"); - break; - default: - goto error; - } - break; - case GetHubDescriptor: - DBG(0, "GetHubDescriptor\n"); - isp1362_hub_descriptor(isp1362_hcd, (struct usb_hub_descriptor *)buf); - break; - case GetHubStatus: - DBG(0, "GetHubStatus\n"); - put_unaligned(cpu_to_le32(0), (__le32 *) buf); - break; - case GetPortStatus: -#ifndef VERBOSE - DBG(0, "GetPortStatus\n"); -#endif - if (!wIndex || wIndex > ports) - goto error; - tmp = isp1362_hcd->rhport[--wIndex]; - put_unaligned(cpu_to_le32(tmp), (__le32 *) buf); - break; - case ClearPortFeature: - DBG(0, "ClearPortFeature: "); - if (!wIndex || wIndex > ports) - goto error; - wIndex--; - - switch (wValue) { - case USB_PORT_FEAT_ENABLE: - _DBG(0, "USB_PORT_FEAT_ENABLE\n"); - tmp = RH_PS_CCS; - break; - case USB_PORT_FEAT_C_ENABLE: - _DBG(0, "USB_PORT_FEAT_C_ENABLE\n"); - tmp = RH_PS_PESC; - break; - case USB_PORT_FEAT_SUSPEND: - _DBG(0, "USB_PORT_FEAT_SUSPEND\n"); - tmp = RH_PS_POCI; - break; - case USB_PORT_FEAT_C_SUSPEND: - _DBG(0, "USB_PORT_FEAT_C_SUSPEND\n"); - tmp = RH_PS_PSSC; - break; - case USB_PORT_FEAT_POWER: - _DBG(0, "USB_PORT_FEAT_POWER\n"); - tmp = RH_PS_LSDA; - - break; - case USB_PORT_FEAT_C_CONNECTION: - _DBG(0, "USB_PORT_FEAT_C_CONNECTION\n"); - tmp = RH_PS_CSC; - break; - case USB_PORT_FEAT_C_OVER_CURRENT: - _DBG(0, "USB_PORT_FEAT_C_OVER_CURRENT\n"); - tmp = RH_PS_OCIC; - break; - case USB_PORT_FEAT_C_RESET: - _DBG(0, "USB_PORT_FEAT_C_RESET\n"); - tmp = RH_PS_PRSC; - break; - default: - goto error; - } - - spin_lock_irqsave(&isp1362_hcd->lock, flags); - isp1362_write_reg32(isp1362_hcd, HCRHPORT1 + wIndex, tmp); - isp1362_hcd->rhport[wIndex] = - isp1362_read_reg32(isp1362_hcd, HCRHPORT1 + wIndex); - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - break; - case SetPortFeature: - DBG(0, "SetPortFeature: "); - if (!wIndex || wIndex > ports) - goto error; - wIndex--; - switch (wValue) { - case USB_PORT_FEAT_SUSPEND: - _DBG(0, "USB_PORT_FEAT_SUSPEND\n"); - spin_lock_irqsave(&isp1362_hcd->lock, flags); - isp1362_write_reg32(isp1362_hcd, HCRHPORT1 + wIndex, RH_PS_PSS); - isp1362_hcd->rhport[wIndex] = - isp1362_read_reg32(isp1362_hcd, HCRHPORT1 + wIndex); - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - break; - case USB_PORT_FEAT_POWER: - _DBG(0, "USB_PORT_FEAT_POWER\n"); - spin_lock_irqsave(&isp1362_hcd->lock, flags); - isp1362_write_reg32(isp1362_hcd, HCRHPORT1 + wIndex, RH_PS_PPS); - isp1362_hcd->rhport[wIndex] = - isp1362_read_reg32(isp1362_hcd, HCRHPORT1 + wIndex); - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - break; - case USB_PORT_FEAT_RESET: - _DBG(0, "USB_PORT_FEAT_RESET\n"); - spin_lock_irqsave(&isp1362_hcd->lock, flags); - - t1 = jiffies + msecs_to_jiffies(USB_RESET_WIDTH); - while (time_before(jiffies, t1)) { - /* spin until any current reset finishes */ - for (;;) { - tmp = isp1362_read_reg32(isp1362_hcd, HCRHPORT1 + wIndex); - if (!(tmp & RH_PS_PRS)) - break; - udelay(500); - } - if (!(tmp & RH_PS_CCS)) - break; - /* Reset lasts 10ms (claims datasheet) */ - isp1362_write_reg32(isp1362_hcd, HCRHPORT1 + wIndex, (RH_PS_PRS)); - - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - msleep(10); - spin_lock_irqsave(&isp1362_hcd->lock, flags); - } - - isp1362_hcd->rhport[wIndex] = isp1362_read_reg32(isp1362_hcd, - HCRHPORT1 + wIndex); - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - break; - default: - goto error; - } - break; - - default: - error: - /* "protocol stall" on error */ - _DBG(0, "PROTOCOL STALL\n"); - retval = -EPIPE; - } - - return retval; -} - -#ifdef CONFIG_PM -static int isp1362_bus_suspend(struct usb_hcd *hcd) -{ - int status = 0; - struct isp1362_hcd *isp1362_hcd = hcd_to_isp1362_hcd(hcd); - unsigned long flags; - - if (time_before(jiffies, isp1362_hcd->next_statechange)) - msleep(5); - - spin_lock_irqsave(&isp1362_hcd->lock, flags); - - isp1362_hcd->hc_control = isp1362_read_reg32(isp1362_hcd, HCCONTROL); - switch (isp1362_hcd->hc_control & OHCI_CTRL_HCFS) { - case OHCI_USB_RESUME: - DBG(0, "%s: resume/suspend?\n", __func__); - isp1362_hcd->hc_control &= ~OHCI_CTRL_HCFS; - isp1362_hcd->hc_control |= OHCI_USB_RESET; - isp1362_write_reg32(isp1362_hcd, HCCONTROL, isp1362_hcd->hc_control); - /* FALL THROUGH */ - case OHCI_USB_RESET: - status = -EBUSY; - pr_warning("%s: needs reinit!\n", __func__); - goto done; - case OHCI_USB_SUSPEND: - pr_warning("%s: already suspended?\n", __func__); - goto done; - } - DBG(0, "%s: suspend root hub\n", __func__); - - /* First stop any processing */ - hcd->state = HC_STATE_QUIESCING; - if (!list_empty(&isp1362_hcd->atl_queue.active) || - !list_empty(&isp1362_hcd->intl_queue.active) || - !list_empty(&isp1362_hcd->istl_queue[0] .active) || - !list_empty(&isp1362_hcd->istl_queue[1] .active)) { - int limit; - - isp1362_write_reg32(isp1362_hcd, HCATLSKIP, ~0); - isp1362_write_reg32(isp1362_hcd, HCINTLSKIP, ~0); - isp1362_write_reg16(isp1362_hcd, HCBUFSTAT, 0); - isp1362_write_reg16(isp1362_hcd, HCuPINTENB, 0); - isp1362_write_reg32(isp1362_hcd, HCINTSTAT, OHCI_INTR_SF); - - DBG(0, "%s: stopping schedules ...\n", __func__); - limit = 2000; - while (limit > 0) { - udelay(250); - limit -= 250; - if (isp1362_read_reg32(isp1362_hcd, HCINTSTAT) & OHCI_INTR_SF) - break; - } - mdelay(7); - if (isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_ATL) { - u32 done_map = isp1362_read_reg32(isp1362_hcd, HCATLDONE); - finish_transfers(isp1362_hcd, done_map, &isp1362_hcd->atl_queue); - } - if (isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_INTL) { - u32 done_map = isp1362_read_reg32(isp1362_hcd, HCINTLDONE); - finish_transfers(isp1362_hcd, done_map, &isp1362_hcd->intl_queue); - } - if (isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_ISTL0) - finish_iso_transfers(isp1362_hcd, &isp1362_hcd->istl_queue[0]); - if (isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_ISTL1) - finish_iso_transfers(isp1362_hcd, &isp1362_hcd->istl_queue[1]); - } - DBG(0, "%s: HCINTSTAT: %08x\n", __func__, - isp1362_read_reg32(isp1362_hcd, HCINTSTAT)); - isp1362_write_reg32(isp1362_hcd, HCINTSTAT, - isp1362_read_reg32(isp1362_hcd, HCINTSTAT)); - - /* Suspend hub */ - isp1362_hcd->hc_control = OHCI_USB_SUSPEND; - isp1362_show_reg(isp1362_hcd, HCCONTROL); - isp1362_write_reg32(isp1362_hcd, HCCONTROL, isp1362_hcd->hc_control); - isp1362_show_reg(isp1362_hcd, HCCONTROL); - -#if 1 - isp1362_hcd->hc_control = isp1362_read_reg32(isp1362_hcd, HCCONTROL); - if ((isp1362_hcd->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_SUSPEND) { - pr_err("%s: controller won't suspend %08x\n", __func__, - isp1362_hcd->hc_control); - status = -EBUSY; - } else -#endif - { - /* no resumes until devices finish suspending */ - isp1362_hcd->next_statechange = jiffies + msecs_to_jiffies(5); - } -done: - if (status == 0) { - hcd->state = HC_STATE_SUSPENDED; - DBG(0, "%s: HCD suspended: %08x\n", __func__, - isp1362_read_reg32(isp1362_hcd, HCCONTROL)); - } - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - return status; -} - -static int isp1362_bus_resume(struct usb_hcd *hcd) -{ - struct isp1362_hcd *isp1362_hcd = hcd_to_isp1362_hcd(hcd); - u32 port; - unsigned long flags; - int status = -EINPROGRESS; - - if (time_before(jiffies, isp1362_hcd->next_statechange)) - msleep(5); - - spin_lock_irqsave(&isp1362_hcd->lock, flags); - isp1362_hcd->hc_control = isp1362_read_reg32(isp1362_hcd, HCCONTROL); - pr_info("%s: HCCONTROL: %08x\n", __func__, isp1362_hcd->hc_control); - if (hcd->state == HC_STATE_RESUMING) { - pr_warning("%s: duplicate resume\n", __func__); - status = 0; - } else - switch (isp1362_hcd->hc_control & OHCI_CTRL_HCFS) { - case OHCI_USB_SUSPEND: - DBG(0, "%s: resume root hub\n", __func__); - isp1362_hcd->hc_control &= ~OHCI_CTRL_HCFS; - isp1362_hcd->hc_control |= OHCI_USB_RESUME; - isp1362_write_reg32(isp1362_hcd, HCCONTROL, isp1362_hcd->hc_control); - break; - case OHCI_USB_RESUME: - /* HCFS changes sometime after INTR_RD */ - DBG(0, "%s: remote wakeup\n", __func__); - break; - case OHCI_USB_OPER: - DBG(0, "%s: odd resume\n", __func__); - status = 0; - hcd->self.root_hub->dev.power.power_state = PMSG_ON; - break; - default: /* RESET, we lost power */ - DBG(0, "%s: root hub hardware reset\n", __func__); - status = -EBUSY; - } - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - if (status == -EBUSY) { - DBG(0, "%s: Restarting HC\n", __func__); - isp1362_hc_stop(hcd); - return isp1362_hc_start(hcd); - } - if (status != -EINPROGRESS) - return status; - spin_lock_irqsave(&isp1362_hcd->lock, flags); - port = isp1362_read_reg32(isp1362_hcd, HCRHDESCA) & RH_A_NDP; - while (port--) { - u32 stat = isp1362_read_reg32(isp1362_hcd, HCRHPORT1 + port); - - /* force global, not selective, resume */ - if (!(stat & RH_PS_PSS)) { - DBG(0, "%s: Not Resuming RH port %d\n", __func__, port); - continue; - } - DBG(0, "%s: Resuming RH port %d\n", __func__, port); - isp1362_write_reg32(isp1362_hcd, HCRHPORT1 + port, RH_PS_POCI); - } - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - - /* Some controllers (lucent) need extra-long delays */ - hcd->state = HC_STATE_RESUMING; - mdelay(20 /* usb 11.5.1.10 */ + 15); - - isp1362_hcd->hc_control = OHCI_USB_OPER; - spin_lock_irqsave(&isp1362_hcd->lock, flags); - isp1362_show_reg(isp1362_hcd, HCCONTROL); - isp1362_write_reg32(isp1362_hcd, HCCONTROL, isp1362_hcd->hc_control); - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - /* TRSMRCY */ - msleep(10); - - /* keep it alive for ~5x suspend + resume costs */ - isp1362_hcd->next_statechange = jiffies + msecs_to_jiffies(250); - - hcd->self.root_hub->dev.power.power_state = PMSG_ON; - hcd->state = HC_STATE_RUNNING; - return 0; -} -#else -#define isp1362_bus_suspend NULL -#define isp1362_bus_resume NULL -#endif - -/*-------------------------------------------------------------------------*/ - -#ifdef STUB_DEBUG_FILE - -static inline void create_debug_file(struct isp1362_hcd *isp1362_hcd) -{ -} -static inline void remove_debug_file(struct isp1362_hcd *isp1362_hcd) -{ -} - -#else - -#include -#include - -static void dump_irq(struct seq_file *s, char *label, u16 mask) -{ - seq_printf(s, "%-15s %04x%s%s%s%s%s%s\n", label, mask, - mask & HCuPINT_CLKRDY ? " clkrdy" : "", - mask & HCuPINT_SUSP ? " susp" : "", - mask & HCuPINT_OPR ? " opr" : "", - mask & HCuPINT_EOT ? " eot" : "", - mask & HCuPINT_ATL ? " atl" : "", - mask & HCuPINT_SOF ? " sof" : ""); -} - -static void dump_int(struct seq_file *s, char *label, u32 mask) -{ - seq_printf(s, "%-15s %08x%s%s%s%s%s%s%s\n", label, mask, - mask & OHCI_INTR_MIE ? " MIE" : "", - mask & OHCI_INTR_RHSC ? " rhsc" : "", - mask & OHCI_INTR_FNO ? " fno" : "", - mask & OHCI_INTR_UE ? " ue" : "", - mask & OHCI_INTR_RD ? " rd" : "", - mask & OHCI_INTR_SF ? " sof" : "", - mask & OHCI_INTR_SO ? " so" : ""); -} - -static void dump_ctrl(struct seq_file *s, char *label, u32 mask) -{ - seq_printf(s, "%-15s %08x%s%s%s\n", label, mask, - mask & OHCI_CTRL_RWC ? " rwc" : "", - mask & OHCI_CTRL_RWE ? " rwe" : "", - ({ - char *hcfs; - switch (mask & OHCI_CTRL_HCFS) { - case OHCI_USB_OPER: - hcfs = " oper"; - break; - case OHCI_USB_RESET: - hcfs = " reset"; - break; - case OHCI_USB_RESUME: - hcfs = " resume"; - break; - case OHCI_USB_SUSPEND: - hcfs = " suspend"; - break; - default: - hcfs = " ?"; - } - hcfs; - })); -} - -static void dump_regs(struct seq_file *s, struct isp1362_hcd *isp1362_hcd) -{ - seq_printf(s, "HCREVISION [%02x] %08x\n", ISP1362_REG_NO(ISP1362_REG_HCREVISION), - isp1362_read_reg32(isp1362_hcd, HCREVISION)); - seq_printf(s, "HCCONTROL [%02x] %08x\n", ISP1362_REG_NO(ISP1362_REG_HCCONTROL), - isp1362_read_reg32(isp1362_hcd, HCCONTROL)); - seq_printf(s, "HCCMDSTAT [%02x] %08x\n", ISP1362_REG_NO(ISP1362_REG_HCCMDSTAT), - isp1362_read_reg32(isp1362_hcd, HCCMDSTAT)); - seq_printf(s, "HCINTSTAT [%02x] %08x\n", ISP1362_REG_NO(ISP1362_REG_HCINTSTAT), - isp1362_read_reg32(isp1362_hcd, HCINTSTAT)); - seq_printf(s, "HCINTENB [%02x] %08x\n", ISP1362_REG_NO(ISP1362_REG_HCINTENB), - isp1362_read_reg32(isp1362_hcd, HCINTENB)); - seq_printf(s, "HCFMINTVL [%02x] %08x\n", ISP1362_REG_NO(ISP1362_REG_HCFMINTVL), - isp1362_read_reg32(isp1362_hcd, HCFMINTVL)); - seq_printf(s, "HCFMREM [%02x] %08x\n", ISP1362_REG_NO(ISP1362_REG_HCFMREM), - isp1362_read_reg32(isp1362_hcd, HCFMREM)); - seq_printf(s, "HCFMNUM [%02x] %08x\n", ISP1362_REG_NO(ISP1362_REG_HCFMNUM), - isp1362_read_reg32(isp1362_hcd, HCFMNUM)); - seq_printf(s, "HCLSTHRESH [%02x] %08x\n", ISP1362_REG_NO(ISP1362_REG_HCLSTHRESH), - isp1362_read_reg32(isp1362_hcd, HCLSTHRESH)); - seq_printf(s, "HCRHDESCA [%02x] %08x\n", ISP1362_REG_NO(ISP1362_REG_HCRHDESCA), - isp1362_read_reg32(isp1362_hcd, HCRHDESCA)); - seq_printf(s, "HCRHDESCB [%02x] %08x\n", ISP1362_REG_NO(ISP1362_REG_HCRHDESCB), - isp1362_read_reg32(isp1362_hcd, HCRHDESCB)); - seq_printf(s, "HCRHSTATUS [%02x] %08x\n", ISP1362_REG_NO(ISP1362_REG_HCRHSTATUS), - isp1362_read_reg32(isp1362_hcd, HCRHSTATUS)); - seq_printf(s, "HCRHPORT1 [%02x] %08x\n", ISP1362_REG_NO(ISP1362_REG_HCRHPORT1), - isp1362_read_reg32(isp1362_hcd, HCRHPORT1)); - seq_printf(s, "HCRHPORT2 [%02x] %08x\n", ISP1362_REG_NO(ISP1362_REG_HCRHPORT2), - isp1362_read_reg32(isp1362_hcd, HCRHPORT2)); - seq_printf(s, "\n"); - seq_printf(s, "HCHWCFG [%02x] %04x\n", ISP1362_REG_NO(ISP1362_REG_HCHWCFG), - isp1362_read_reg16(isp1362_hcd, HCHWCFG)); - seq_printf(s, "HCDMACFG [%02x] %04x\n", ISP1362_REG_NO(ISP1362_REG_HCDMACFG), - isp1362_read_reg16(isp1362_hcd, HCDMACFG)); - seq_printf(s, "HCXFERCTR [%02x] %04x\n", ISP1362_REG_NO(ISP1362_REG_HCXFERCTR), - isp1362_read_reg16(isp1362_hcd, HCXFERCTR)); - seq_printf(s, "HCuPINT [%02x] %04x\n", ISP1362_REG_NO(ISP1362_REG_HCuPINT), - isp1362_read_reg16(isp1362_hcd, HCuPINT)); - seq_printf(s, "HCuPINTENB [%02x] %04x\n", ISP1362_REG_NO(ISP1362_REG_HCuPINTENB), - isp1362_read_reg16(isp1362_hcd, HCuPINTENB)); - seq_printf(s, "HCCHIPID [%02x] %04x\n", ISP1362_REG_NO(ISP1362_REG_HCCHIPID), - isp1362_read_reg16(isp1362_hcd, HCCHIPID)); - seq_printf(s, "HCSCRATCH [%02x] %04x\n", ISP1362_REG_NO(ISP1362_REG_HCSCRATCH), - isp1362_read_reg16(isp1362_hcd, HCSCRATCH)); - seq_printf(s, "HCBUFSTAT [%02x] %04x\n", ISP1362_REG_NO(ISP1362_REG_HCBUFSTAT), - isp1362_read_reg16(isp1362_hcd, HCBUFSTAT)); - seq_printf(s, "HCDIRADDR [%02x] %08x\n", ISP1362_REG_NO(ISP1362_REG_HCDIRADDR), - isp1362_read_reg32(isp1362_hcd, HCDIRADDR)); -#if 0 - seq_printf(s, "HCDIRDATA [%02x] %04x\n", ISP1362_REG_NO(HCDIRDATA), - isp1362_read_reg16(isp1362_hcd, HCDIRDATA)); -#endif - seq_printf(s, "HCISTLBUFSZ[%02x] %04x\n", ISP1362_REG_NO(ISP1362_REG_HCISTLBUFSZ), - isp1362_read_reg16(isp1362_hcd, HCISTLBUFSZ)); - seq_printf(s, "HCISTLRATE [%02x] %04x\n", ISP1362_REG_NO(ISP1362_REG_HCISTLRATE), - isp1362_read_reg16(isp1362_hcd, HCISTLRATE)); - seq_printf(s, "\n"); - seq_printf(s, "HCINTLBUFSZ[%02x] %04x\n", ISP1362_REG_NO(ISP1362_REG_HCINTLBUFSZ), - isp1362_read_reg16(isp1362_hcd, HCINTLBUFSZ)); - seq_printf(s, "HCINTLBLKSZ[%02x] %04x\n", ISP1362_REG_NO(ISP1362_REG_HCINTLBLKSZ), - isp1362_read_reg16(isp1362_hcd, HCINTLBLKSZ)); - seq_printf(s, "HCINTLDONE [%02x] %08x\n", ISP1362_REG_NO(ISP1362_REG_HCINTLDONE), - isp1362_read_reg32(isp1362_hcd, HCINTLDONE)); - seq_printf(s, "HCINTLSKIP [%02x] %08x\n", ISP1362_REG_NO(ISP1362_REG_HCINTLSKIP), - isp1362_read_reg32(isp1362_hcd, HCINTLSKIP)); - seq_printf(s, "HCINTLLAST [%02x] %08x\n", ISP1362_REG_NO(ISP1362_REG_HCINTLLAST), - isp1362_read_reg32(isp1362_hcd, HCINTLLAST)); - seq_printf(s, "HCINTLCURR [%02x] %04x\n", ISP1362_REG_NO(ISP1362_REG_HCINTLCURR), - isp1362_read_reg16(isp1362_hcd, HCINTLCURR)); - seq_printf(s, "\n"); - seq_printf(s, "HCATLBUFSZ [%02x] %04x\n", ISP1362_REG_NO(ISP1362_REG_HCATLBUFSZ), - isp1362_read_reg16(isp1362_hcd, HCATLBUFSZ)); - seq_printf(s, "HCATLBLKSZ [%02x] %04x\n", ISP1362_REG_NO(ISP1362_REG_HCATLBLKSZ), - isp1362_read_reg16(isp1362_hcd, HCATLBLKSZ)); -#if 0 - seq_printf(s, "HCATLDONE [%02x] %08x\n", ISP1362_REG_NO(ISP1362_REG_HCATLDONE), - isp1362_read_reg32(isp1362_hcd, HCATLDONE)); -#endif - seq_printf(s, "HCATLSKIP [%02x] %08x\n", ISP1362_REG_NO(ISP1362_REG_HCATLSKIP), - isp1362_read_reg32(isp1362_hcd, HCATLSKIP)); - seq_printf(s, "HCATLLAST [%02x] %08x\n", ISP1362_REG_NO(ISP1362_REG_HCATLLAST), - isp1362_read_reg32(isp1362_hcd, HCATLLAST)); - seq_printf(s, "HCATLCURR [%02x] %04x\n", ISP1362_REG_NO(ISP1362_REG_HCATLCURR), - isp1362_read_reg16(isp1362_hcd, HCATLCURR)); - seq_printf(s, "\n"); - seq_printf(s, "HCATLDTC [%02x] %04x\n", ISP1362_REG_NO(ISP1362_REG_HCATLDTC), - isp1362_read_reg16(isp1362_hcd, HCATLDTC)); - seq_printf(s, "HCATLDTCTO [%02x] %04x\n", ISP1362_REG_NO(ISP1362_REG_HCATLDTCTO), - isp1362_read_reg16(isp1362_hcd, HCATLDTCTO)); -} - -static int proc_isp1362_show(struct seq_file *s, void *unused) -{ - struct isp1362_hcd *isp1362_hcd = s->private; - struct isp1362_ep *ep; - int i; - - seq_printf(s, "%s\n%s version %s\n", - isp1362_hcd_to_hcd(isp1362_hcd)->product_desc, hcd_name, DRIVER_VERSION); - - /* collect statistics to help estimate potential win for - * DMA engines that care about alignment (PXA) - */ - seq_printf(s, "alignment: 16b/%ld 8b/%ld 4b/%ld 2b/%ld 1b/%ld\n", - isp1362_hcd->stat16, isp1362_hcd->stat8, isp1362_hcd->stat4, - isp1362_hcd->stat2, isp1362_hcd->stat1); - seq_printf(s, "max # ptds in ATL fifo: %d\n", isp1362_hcd->atl_queue.stat_maxptds); - seq_printf(s, "max # ptds in INTL fifo: %d\n", isp1362_hcd->intl_queue.stat_maxptds); - seq_printf(s, "max # ptds in ISTL fifo: %d\n", - max(isp1362_hcd->istl_queue[0] .stat_maxptds, - isp1362_hcd->istl_queue[1] .stat_maxptds)); - - /* FIXME: don't show the following in suspended state */ - spin_lock_irq(&isp1362_hcd->lock); - - dump_irq(s, "hc_irq_enable", isp1362_read_reg16(isp1362_hcd, HCuPINTENB)); - dump_irq(s, "hc_irq_status", isp1362_read_reg16(isp1362_hcd, HCuPINT)); - dump_int(s, "ohci_int_enable", isp1362_read_reg32(isp1362_hcd, HCINTENB)); - dump_int(s, "ohci_int_status", isp1362_read_reg32(isp1362_hcd, HCINTSTAT)); - dump_ctrl(s, "ohci_control", isp1362_read_reg32(isp1362_hcd, HCCONTROL)); - - for (i = 0; i < NUM_ISP1362_IRQS; i++) - if (isp1362_hcd->irq_stat[i]) - seq_printf(s, "%-15s: %d\n", - ISP1362_INT_NAME(i), isp1362_hcd->irq_stat[i]); - - dump_regs(s, isp1362_hcd); - list_for_each_entry(ep, &isp1362_hcd->async, schedule) { - struct urb *urb; - - seq_printf(s, "%p, ep%d%s, maxpacket %d:\n", ep, ep->epnum, - ({ - char *s; - switch (ep->nextpid) { - case USB_PID_IN: - s = "in"; - break; - case USB_PID_OUT: - s = "out"; - break; - case USB_PID_SETUP: - s = "setup"; - break; - case USB_PID_ACK: - s = "status"; - break; - default: - s = "?"; - break; - }; - s;}), ep->maxpacket) ; - list_for_each_entry(urb, &ep->hep->urb_list, urb_list) { - seq_printf(s, " urb%p, %d/%d\n", urb, - urb->actual_length, - urb->transfer_buffer_length); - } - } - if (!list_empty(&isp1362_hcd->async)) - seq_printf(s, "\n"); - dump_ptd_queue(&isp1362_hcd->atl_queue); - - seq_printf(s, "periodic size= %d\n", PERIODIC_SIZE); - - list_for_each_entry(ep, &isp1362_hcd->periodic, schedule) { - seq_printf(s, "branch:%2d load:%3d PTD[%d] $%04x:\n", ep->branch, - isp1362_hcd->load[ep->branch], ep->ptd_index, ep->ptd_offset); - - seq_printf(s, " %d/%p (%sdev%d ep%d%s max %d)\n", - ep->interval, ep, - (ep->udev->speed == USB_SPEED_FULL) ? "" : "ls ", - ep->udev->devnum, ep->epnum, - (ep->epnum == 0) ? "" : - ((ep->nextpid == USB_PID_IN) ? - "in" : "out"), ep->maxpacket); - } - dump_ptd_queue(&isp1362_hcd->intl_queue); - - seq_printf(s, "ISO:\n"); - - list_for_each_entry(ep, &isp1362_hcd->isoc, schedule) { - seq_printf(s, " %d/%p (%sdev%d ep%d%s max %d)\n", - ep->interval, ep, - (ep->udev->speed == USB_SPEED_FULL) ? "" : "ls ", - ep->udev->devnum, ep->epnum, - (ep->epnum == 0) ? "" : - ((ep->nextpid == USB_PID_IN) ? - "in" : "out"), ep->maxpacket); - } - - spin_unlock_irq(&isp1362_hcd->lock); - seq_printf(s, "\n"); - - return 0; -} - -static int proc_isp1362_open(struct inode *inode, struct file *file) -{ - return single_open(file, proc_isp1362_show, PDE(inode)->data); -} - -static const struct file_operations proc_ops = { - .open = proc_isp1362_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -/* expect just one isp1362_hcd per system */ -static const char proc_filename[] = "driver/isp1362"; - -static void create_debug_file(struct isp1362_hcd *isp1362_hcd) -{ - struct proc_dir_entry *pde; - - pde = create_proc_entry(proc_filename, 0, NULL); - if (pde == NULL) { - pr_warning("%s: Failed to create debug file '%s'\n", __func__, proc_filename); - return; - } - - pde->proc_fops = &proc_ops; - pde->data = isp1362_hcd; - isp1362_hcd->pde = pde; -} - -static void remove_debug_file(struct isp1362_hcd *isp1362_hcd) -{ - if (isp1362_hcd->pde) - remove_proc_entry(proc_filename, NULL); -} - -#endif - -/*-------------------------------------------------------------------------*/ - -static void __isp1362_sw_reset(struct isp1362_hcd *isp1362_hcd) -{ - int tmp = 20; - - isp1362_write_reg16(isp1362_hcd, HCSWRES, HCSWRES_MAGIC); - isp1362_write_reg32(isp1362_hcd, HCCMDSTAT, OHCI_HCR); - while (--tmp) { - mdelay(1); - if (!(isp1362_read_reg32(isp1362_hcd, HCCMDSTAT) & OHCI_HCR)) - break; - } - if (!tmp) - pr_err("Software reset timeout\n"); -} - -static void isp1362_sw_reset(struct isp1362_hcd *isp1362_hcd) -{ - unsigned long flags; - - spin_lock_irqsave(&isp1362_hcd->lock, flags); - __isp1362_sw_reset(isp1362_hcd); - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); -} - -static int isp1362_mem_config(struct usb_hcd *hcd) -{ - struct isp1362_hcd *isp1362_hcd = hcd_to_isp1362_hcd(hcd); - unsigned long flags; - u32 total; - u16 istl_size = ISP1362_ISTL_BUFSIZE; - u16 intl_blksize = ISP1362_INTL_BLKSIZE + PTD_HEADER_SIZE; - u16 intl_size = ISP1362_INTL_BUFFERS * intl_blksize; - u16 atl_blksize = ISP1362_ATL_BLKSIZE + PTD_HEADER_SIZE; - u16 atl_buffers = (ISP1362_BUF_SIZE - (istl_size + intl_size)) / atl_blksize; - u16 atl_size; - int i; - - WARN_ON(istl_size & 3); - WARN_ON(atl_blksize & 3); - WARN_ON(intl_blksize & 3); - WARN_ON(atl_blksize < PTD_HEADER_SIZE); - WARN_ON(intl_blksize < PTD_HEADER_SIZE); - - BUG_ON((unsigned)ISP1362_INTL_BUFFERS > 32); - if (atl_buffers > 32) - atl_buffers = 32; - atl_size = atl_buffers * atl_blksize; - total = atl_size + intl_size + istl_size; - dev_info(hcd->self.controller, "ISP1362 Memory usage:\n"); - dev_info(hcd->self.controller, " ISTL: 2 * %4d: %4d @ $%04x:$%04x\n", - istl_size / 2, istl_size, 0, istl_size / 2); - dev_info(hcd->self.controller, " INTL: %4d * (%3zu+8): %4d @ $%04x\n", - ISP1362_INTL_BUFFERS, intl_blksize - PTD_HEADER_SIZE, - intl_size, istl_size); - dev_info(hcd->self.controller, " ATL : %4d * (%3zu+8): %4d @ $%04x\n", - atl_buffers, atl_blksize - PTD_HEADER_SIZE, - atl_size, istl_size + intl_size); - dev_info(hcd->self.controller, " USED/FREE: %4d %4d\n", total, - ISP1362_BUF_SIZE - total); - - if (total > ISP1362_BUF_SIZE) { - dev_err(hcd->self.controller, "%s: Memory requested: %d, available %d\n", - __func__, total, ISP1362_BUF_SIZE); - return -ENOMEM; - } - - total = istl_size + intl_size + atl_size; - spin_lock_irqsave(&isp1362_hcd->lock, flags); - - for (i = 0; i < 2; i++) { - isp1362_hcd->istl_queue[i].buf_start = i * istl_size / 2, - isp1362_hcd->istl_queue[i].buf_size = istl_size / 2; - isp1362_hcd->istl_queue[i].blk_size = 4; - INIT_LIST_HEAD(&isp1362_hcd->istl_queue[i].active); - snprintf(isp1362_hcd->istl_queue[i].name, - sizeof(isp1362_hcd->istl_queue[i].name), "ISTL%d", i); - DBG(3, "%s: %5s buf $%04x %d\n", __func__, - isp1362_hcd->istl_queue[i].name, - isp1362_hcd->istl_queue[i].buf_start, - isp1362_hcd->istl_queue[i].buf_size); - } - isp1362_write_reg16(isp1362_hcd, HCISTLBUFSZ, istl_size / 2); - - isp1362_hcd->intl_queue.buf_start = istl_size; - isp1362_hcd->intl_queue.buf_size = intl_size; - isp1362_hcd->intl_queue.buf_count = ISP1362_INTL_BUFFERS; - isp1362_hcd->intl_queue.blk_size = intl_blksize; - isp1362_hcd->intl_queue.buf_avail = isp1362_hcd->intl_queue.buf_count; - isp1362_hcd->intl_queue.skip_map = ~0; - INIT_LIST_HEAD(&isp1362_hcd->intl_queue.active); - - isp1362_write_reg16(isp1362_hcd, HCINTLBUFSZ, - isp1362_hcd->intl_queue.buf_size); - isp1362_write_reg16(isp1362_hcd, HCINTLBLKSZ, - isp1362_hcd->intl_queue.blk_size - PTD_HEADER_SIZE); - isp1362_write_reg32(isp1362_hcd, HCINTLSKIP, ~0); - isp1362_write_reg32(isp1362_hcd, HCINTLLAST, - 1 << (ISP1362_INTL_BUFFERS - 1)); - - isp1362_hcd->atl_queue.buf_start = istl_size + intl_size; - isp1362_hcd->atl_queue.buf_size = atl_size; - isp1362_hcd->atl_queue.buf_count = atl_buffers; - isp1362_hcd->atl_queue.blk_size = atl_blksize; - isp1362_hcd->atl_queue.buf_avail = isp1362_hcd->atl_queue.buf_count; - isp1362_hcd->atl_queue.skip_map = ~0; - INIT_LIST_HEAD(&isp1362_hcd->atl_queue.active); - - isp1362_write_reg16(isp1362_hcd, HCATLBUFSZ, - isp1362_hcd->atl_queue.buf_size); - isp1362_write_reg16(isp1362_hcd, HCATLBLKSZ, - isp1362_hcd->atl_queue.blk_size - PTD_HEADER_SIZE); - isp1362_write_reg32(isp1362_hcd, HCATLSKIP, ~0); - isp1362_write_reg32(isp1362_hcd, HCATLLAST, - 1 << (atl_buffers - 1)); - - snprintf(isp1362_hcd->atl_queue.name, - sizeof(isp1362_hcd->atl_queue.name), "ATL"); - snprintf(isp1362_hcd->intl_queue.name, - sizeof(isp1362_hcd->intl_queue.name), "INTL"); - DBG(3, "%s: %5s buf $%04x %2d * %4d = %4d\n", __func__, - isp1362_hcd->intl_queue.name, - isp1362_hcd->intl_queue.buf_start, - ISP1362_INTL_BUFFERS, isp1362_hcd->intl_queue.blk_size, - isp1362_hcd->intl_queue.buf_size); - DBG(3, "%s: %5s buf $%04x %2d * %4d = %4d\n", __func__, - isp1362_hcd->atl_queue.name, - isp1362_hcd->atl_queue.buf_start, - atl_buffers, isp1362_hcd->atl_queue.blk_size, - isp1362_hcd->atl_queue.buf_size); - - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - - return 0; -} - -static int isp1362_hc_reset(struct usb_hcd *hcd) -{ - int ret = 0; - struct isp1362_hcd *isp1362_hcd = hcd_to_isp1362_hcd(hcd); - unsigned long t; - unsigned long timeout = 100; - unsigned long flags; - int clkrdy = 0; - - pr_debug("%s:\n", __func__); - - if (isp1362_hcd->board && isp1362_hcd->board->reset) { - isp1362_hcd->board->reset(hcd->self.controller, 1); - msleep(20); - if (isp1362_hcd->board->clock) - isp1362_hcd->board->clock(hcd->self.controller, 1); - isp1362_hcd->board->reset(hcd->self.controller, 0); - } else - isp1362_sw_reset(isp1362_hcd); - - /* chip has been reset. First we need to see a clock */ - t = jiffies + msecs_to_jiffies(timeout); - while (!clkrdy && time_before_eq(jiffies, t)) { - spin_lock_irqsave(&isp1362_hcd->lock, flags); - clkrdy = isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_CLKRDY; - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - if (!clkrdy) - msleep(4); - } - - spin_lock_irqsave(&isp1362_hcd->lock, flags); - isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_CLKRDY); - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - if (!clkrdy) { - pr_err("Clock not ready after %lums\n", timeout); - ret = -ENODEV; - } - return ret; -} - -static void isp1362_hc_stop(struct usb_hcd *hcd) -{ - struct isp1362_hcd *isp1362_hcd = hcd_to_isp1362_hcd(hcd); - unsigned long flags; - u32 tmp; - - pr_debug("%s:\n", __func__); - - del_timer_sync(&hcd->rh_timer); - - spin_lock_irqsave(&isp1362_hcd->lock, flags); - - isp1362_write_reg16(isp1362_hcd, HCuPINTENB, 0); - - /* Switch off power for all ports */ - tmp = isp1362_read_reg32(isp1362_hcd, HCRHDESCA); - tmp &= ~(RH_A_NPS | RH_A_PSM); - isp1362_write_reg32(isp1362_hcd, HCRHDESCA, tmp); - isp1362_write_reg32(isp1362_hcd, HCRHSTATUS, RH_HS_LPS); - - /* Reset the chip */ - if (isp1362_hcd->board && isp1362_hcd->board->reset) - isp1362_hcd->board->reset(hcd->self.controller, 1); - else - __isp1362_sw_reset(isp1362_hcd); - - if (isp1362_hcd->board && isp1362_hcd->board->clock) - isp1362_hcd->board->clock(hcd->self.controller, 0); - - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); -} - -#ifdef CHIP_BUFFER_TEST -static int isp1362_chip_test(struct isp1362_hcd *isp1362_hcd) -{ - int ret = 0; - u16 *ref; - unsigned long flags; - - ref = kmalloc(2 * ISP1362_BUF_SIZE, GFP_KERNEL); - if (ref) { - int offset; - u16 *tst = &ref[ISP1362_BUF_SIZE / 2]; - - for (offset = 0; offset < ISP1362_BUF_SIZE / 2; offset++) { - ref[offset] = ~offset; - tst[offset] = offset; - } - - for (offset = 0; offset < 4; offset++) { - int j; - - for (j = 0; j < 8; j++) { - spin_lock_irqsave(&isp1362_hcd->lock, flags); - isp1362_write_buffer(isp1362_hcd, (u8 *)ref + offset, 0, j); - isp1362_read_buffer(isp1362_hcd, (u8 *)tst + offset, 0, j); - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - - if (memcmp(ref, tst, j)) { - ret = -ENODEV; - pr_err("%s: memory check with %d byte offset %d failed\n", - __func__, j, offset); - dump_data((u8 *)ref + offset, j); - dump_data((u8 *)tst + offset, j); - } - } - } - - spin_lock_irqsave(&isp1362_hcd->lock, flags); - isp1362_write_buffer(isp1362_hcd, ref, 0, ISP1362_BUF_SIZE); - isp1362_read_buffer(isp1362_hcd, tst, 0, ISP1362_BUF_SIZE); - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - - if (memcmp(ref, tst, ISP1362_BUF_SIZE)) { - ret = -ENODEV; - pr_err("%s: memory check failed\n", __func__); - dump_data((u8 *)tst, ISP1362_BUF_SIZE / 2); - } - - for (offset = 0; offset < 256; offset++) { - int test_size = 0; - - yield(); - - memset(tst, 0, ISP1362_BUF_SIZE); - spin_lock_irqsave(&isp1362_hcd->lock, flags); - isp1362_write_buffer(isp1362_hcd, tst, 0, ISP1362_BUF_SIZE); - isp1362_read_buffer(isp1362_hcd, tst, 0, ISP1362_BUF_SIZE); - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - if (memcmp(tst, tst + (ISP1362_BUF_SIZE / (2 * sizeof(*tst))), - ISP1362_BUF_SIZE / 2)) { - pr_err("%s: Failed to clear buffer\n", __func__); - dump_data((u8 *)tst, ISP1362_BUF_SIZE); - break; - } - spin_lock_irqsave(&isp1362_hcd->lock, flags); - isp1362_write_buffer(isp1362_hcd, ref, offset * 2, PTD_HEADER_SIZE); - isp1362_write_buffer(isp1362_hcd, ref + PTD_HEADER_SIZE / sizeof(*ref), - offset * 2 + PTD_HEADER_SIZE, test_size); - isp1362_read_buffer(isp1362_hcd, tst, offset * 2, - PTD_HEADER_SIZE + test_size); - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - if (memcmp(ref, tst, PTD_HEADER_SIZE + test_size)) { - dump_data(((u8 *)ref) + offset, PTD_HEADER_SIZE + test_size); - dump_data((u8 *)tst, PTD_HEADER_SIZE + test_size); - spin_lock_irqsave(&isp1362_hcd->lock, flags); - isp1362_read_buffer(isp1362_hcd, tst, offset * 2, - PTD_HEADER_SIZE + test_size); - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - if (memcmp(ref, tst, PTD_HEADER_SIZE + test_size)) { - ret = -ENODEV; - pr_err("%s: memory check with offset %02x failed\n", - __func__, offset); - break; - } - pr_warning("%s: memory check with offset %02x ok after second read\n", - __func__, offset); - } - } - kfree(ref); - } - return ret; -} -#endif - -static int isp1362_hc_start(struct usb_hcd *hcd) -{ - int ret; - struct isp1362_hcd *isp1362_hcd = hcd_to_isp1362_hcd(hcd); - struct isp1362_platform_data *board = isp1362_hcd->board; - u16 hwcfg; - u16 chipid; - unsigned long flags; - - pr_debug("%s:\n", __func__); - - spin_lock_irqsave(&isp1362_hcd->lock, flags); - chipid = isp1362_read_reg16(isp1362_hcd, HCCHIPID); - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - - if ((chipid & HCCHIPID_MASK) != HCCHIPID_MAGIC) { - pr_err("%s: Invalid chip ID %04x\n", __func__, chipid); - return -ENODEV; - } - -#ifdef CHIP_BUFFER_TEST - ret = isp1362_chip_test(isp1362_hcd); - if (ret) - return -ENODEV; -#endif - spin_lock_irqsave(&isp1362_hcd->lock, flags); - /* clear interrupt status and disable all interrupt sources */ - isp1362_write_reg16(isp1362_hcd, HCuPINT, 0xff); - isp1362_write_reg16(isp1362_hcd, HCuPINTENB, 0); - - /* HW conf */ - hwcfg = HCHWCFG_INT_ENABLE | HCHWCFG_DBWIDTH(1); - if (board->sel15Kres) - hwcfg |= HCHWCFG_PULLDOWN_DS2 | - ((MAX_ROOT_PORTS > 1) ? HCHWCFG_PULLDOWN_DS1 : 0); - if (board->clknotstop) - hwcfg |= HCHWCFG_CLKNOTSTOP; - if (board->oc_enable) - hwcfg |= HCHWCFG_ANALOG_OC; - if (board->int_act_high) - hwcfg |= HCHWCFG_INT_POL; - if (board->int_edge_triggered) - hwcfg |= HCHWCFG_INT_TRIGGER; - if (board->dreq_act_high) - hwcfg |= HCHWCFG_DREQ_POL; - if (board->dack_act_high) - hwcfg |= HCHWCFG_DACK_POL; - isp1362_write_reg16(isp1362_hcd, HCHWCFG, hwcfg); - isp1362_show_reg(isp1362_hcd, HCHWCFG); - isp1362_write_reg16(isp1362_hcd, HCDMACFG, 0); - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - - ret = isp1362_mem_config(hcd); - if (ret) - return ret; - - spin_lock_irqsave(&isp1362_hcd->lock, flags); - - /* Root hub conf */ - isp1362_hcd->rhdesca = 0; - if (board->no_power_switching) - isp1362_hcd->rhdesca |= RH_A_NPS; - if (board->power_switching_mode) - isp1362_hcd->rhdesca |= RH_A_PSM; - if (board->potpg) - isp1362_hcd->rhdesca |= (board->potpg << 24) & RH_A_POTPGT; - else - isp1362_hcd->rhdesca |= (25 << 24) & RH_A_POTPGT; - - isp1362_write_reg32(isp1362_hcd, HCRHDESCA, isp1362_hcd->rhdesca & ~RH_A_OCPM); - isp1362_write_reg32(isp1362_hcd, HCRHDESCA, isp1362_hcd->rhdesca | RH_A_OCPM); - isp1362_hcd->rhdesca = isp1362_read_reg32(isp1362_hcd, HCRHDESCA); - - isp1362_hcd->rhdescb = RH_B_PPCM; - isp1362_write_reg32(isp1362_hcd, HCRHDESCB, isp1362_hcd->rhdescb); - isp1362_hcd->rhdescb = isp1362_read_reg32(isp1362_hcd, HCRHDESCB); - - isp1362_read_reg32(isp1362_hcd, HCFMINTVL); - isp1362_write_reg32(isp1362_hcd, HCFMINTVL, (FSMP(FI) << 16) | FI); - isp1362_write_reg32(isp1362_hcd, HCLSTHRESH, LSTHRESH); - - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - - isp1362_hcd->hc_control = OHCI_USB_OPER; - hcd->state = HC_STATE_RUNNING; - - spin_lock_irqsave(&isp1362_hcd->lock, flags); - /* Set up interrupts */ - isp1362_hcd->intenb = OHCI_INTR_MIE | OHCI_INTR_RHSC | OHCI_INTR_UE; - isp1362_hcd->intenb |= OHCI_INTR_RD; - isp1362_hcd->irqenb = HCuPINT_OPR | HCuPINT_SUSP; - isp1362_write_reg32(isp1362_hcd, HCINTENB, isp1362_hcd->intenb); - isp1362_write_reg16(isp1362_hcd, HCuPINTENB, isp1362_hcd->irqenb); - - /* Go operational */ - isp1362_write_reg32(isp1362_hcd, HCCONTROL, isp1362_hcd->hc_control); - /* enable global power */ - isp1362_write_reg32(isp1362_hcd, HCRHSTATUS, RH_HS_LPSC | RH_HS_DRWE); - - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static struct hc_driver isp1362_hc_driver = { - .description = hcd_name, - .product_desc = "ISP1362 Host Controller", - .hcd_priv_size = sizeof(struct isp1362_hcd), - - .irq = isp1362_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - .reset = isp1362_hc_reset, - .start = isp1362_hc_start, - .stop = isp1362_hc_stop, - - .urb_enqueue = isp1362_urb_enqueue, - .urb_dequeue = isp1362_urb_dequeue, - .endpoint_disable = isp1362_endpoint_disable, - - .get_frame_number = isp1362_get_frame, - - .hub_status_data = isp1362_hub_status_data, - .hub_control = isp1362_hub_control, - .bus_suspend = isp1362_bus_suspend, - .bus_resume = isp1362_bus_resume, -}; - -/*-------------------------------------------------------------------------*/ - -static int __devexit isp1362_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct isp1362_hcd *isp1362_hcd = hcd_to_isp1362_hcd(hcd); - struct resource *res; - - remove_debug_file(isp1362_hcd); - DBG(0, "%s: Removing HCD\n", __func__); - usb_remove_hcd(hcd); - - DBG(0, "%s: Unmapping data_reg @ %p\n", __func__, - isp1362_hcd->data_reg); - iounmap(isp1362_hcd->data_reg); - - DBG(0, "%s: Unmapping addr_reg @ %p\n", __func__, - isp1362_hcd->addr_reg); - iounmap(isp1362_hcd->addr_reg); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - DBG(0, "%s: release mem_region: %08lx\n", __func__, (long unsigned int)res->start); - if (res) - release_mem_region(res->start, resource_size(res)); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - DBG(0, "%s: release mem_region: %08lx\n", __func__, (long unsigned int)res->start); - if (res) - release_mem_region(res->start, resource_size(res)); - - DBG(0, "%s: put_hcd\n", __func__); - usb_put_hcd(hcd); - DBG(0, "%s: Done\n", __func__); - - return 0; -} - -static int __devinit isp1362_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - struct isp1362_hcd *isp1362_hcd; - struct resource *addr, *data; - void __iomem *addr_reg; - void __iomem *data_reg; - int irq; - int retval = 0; - struct resource *irq_res; - unsigned int irq_flags = 0; - - if (usb_disabled()) - return -ENODEV; - - /* basic sanity checks first. board-specific init logic should - * have initialized this the three resources and probably board - * specific platform_data. we don't probe for IRQs, and do only - * minimal sanity checking. - */ - if (pdev->num_resources < 3) { - retval = -ENODEV; - goto err1; - } - - data = platform_get_resource(pdev, IORESOURCE_MEM, 0); - addr = platform_get_resource(pdev, IORESOURCE_MEM, 1); - irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!addr || !data || !irq_res) { - retval = -ENODEV; - goto err1; - } - irq = irq_res->start; - - if (pdev->dev.dma_mask) { - DBG(1, "won't do DMA"); - retval = -ENODEV; - goto err1; - } - - if (!request_mem_region(addr->start, resource_size(addr), hcd_name)) { - retval = -EBUSY; - goto err1; - } - addr_reg = ioremap(addr->start, resource_size(addr)); - if (addr_reg == NULL) { - retval = -ENOMEM; - goto err2; - } - - if (!request_mem_region(data->start, resource_size(data), hcd_name)) { - retval = -EBUSY; - goto err3; - } - data_reg = ioremap(data->start, resource_size(data)); - if (data_reg == NULL) { - retval = -ENOMEM; - goto err4; - } - - /* allocate and initialize hcd */ - hcd = usb_create_hcd(&isp1362_hc_driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - retval = -ENOMEM; - goto err5; - } - hcd->rsrc_start = data->start; - isp1362_hcd = hcd_to_isp1362_hcd(hcd); - isp1362_hcd->data_reg = data_reg; - isp1362_hcd->addr_reg = addr_reg; - - isp1362_hcd->next_statechange = jiffies; - spin_lock_init(&isp1362_hcd->lock); - INIT_LIST_HEAD(&isp1362_hcd->async); - INIT_LIST_HEAD(&isp1362_hcd->periodic); - INIT_LIST_HEAD(&isp1362_hcd->isoc); - INIT_LIST_HEAD(&isp1362_hcd->remove_list); - isp1362_hcd->board = pdev->dev.platform_data; -#if USE_PLATFORM_DELAY - if (!isp1362_hcd->board->delay) { - dev_err(hcd->self.controller, "No platform delay function given\n"); - retval = -ENODEV; - goto err6; - } -#endif - - if (irq_res->flags & IORESOURCE_IRQ_HIGHEDGE) - irq_flags |= IRQF_TRIGGER_RISING; - if (irq_res->flags & IORESOURCE_IRQ_LOWEDGE) - irq_flags |= IRQF_TRIGGER_FALLING; - if (irq_res->flags & IORESOURCE_IRQ_HIGHLEVEL) - irq_flags |= IRQF_TRIGGER_HIGH; - if (irq_res->flags & IORESOURCE_IRQ_LOWLEVEL) - irq_flags |= IRQF_TRIGGER_LOW; - - retval = usb_add_hcd(hcd, irq, irq_flags | IRQF_SHARED); - if (retval != 0) - goto err6; - pr_info("%s, irq %d\n", hcd->product_desc, irq); - - create_debug_file(isp1362_hcd); - - return 0; - - err6: - DBG(0, "%s: Freeing dev %p\n", __func__, isp1362_hcd); - usb_put_hcd(hcd); - err5: - DBG(0, "%s: Unmapping data_reg @ %p\n", __func__, data_reg); - iounmap(data_reg); - err4: - DBG(0, "%s: Releasing mem region %08lx\n", __func__, (long unsigned int)data->start); - release_mem_region(data->start, resource_size(data)); - err3: - DBG(0, "%s: Unmapping addr_reg @ %p\n", __func__, addr_reg); - iounmap(addr_reg); - err2: - DBG(0, "%s: Releasing mem region %08lx\n", __func__, (long unsigned int)addr->start); - release_mem_region(addr->start, resource_size(addr)); - err1: - pr_err("%s: init error, %d\n", __func__, retval); - - return retval; -} - -#ifdef CONFIG_PM -static int isp1362_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct isp1362_hcd *isp1362_hcd = hcd_to_isp1362_hcd(hcd); - unsigned long flags; - int retval = 0; - - DBG(0, "%s: Suspending device\n", __func__); - - if (state.event == PM_EVENT_FREEZE) { - DBG(0, "%s: Suspending root hub\n", __func__); - retval = isp1362_bus_suspend(hcd); - } else { - DBG(0, "%s: Suspending RH ports\n", __func__); - spin_lock_irqsave(&isp1362_hcd->lock, flags); - isp1362_write_reg32(isp1362_hcd, HCRHSTATUS, RH_HS_LPS); - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - } - if (retval == 0) - pdev->dev.power.power_state = state; - return retval; -} - -static int isp1362_resume(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct isp1362_hcd *isp1362_hcd = hcd_to_isp1362_hcd(hcd); - unsigned long flags; - - DBG(0, "%s: Resuming\n", __func__); - - if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { - DBG(0, "%s: Resume RH ports\n", __func__); - spin_lock_irqsave(&isp1362_hcd->lock, flags); - isp1362_write_reg32(isp1362_hcd, HCRHSTATUS, RH_HS_LPSC); - spin_unlock_irqrestore(&isp1362_hcd->lock, flags); - return 0; - } - - pdev->dev.power.power_state = PMSG_ON; - - return isp1362_bus_resume(isp1362_hcd_to_hcd(isp1362_hcd)); -} -#else -#define isp1362_suspend NULL -#define isp1362_resume NULL -#endif - -static struct platform_driver isp1362_driver = { - .probe = isp1362_probe, - .remove = __devexit_p(isp1362_remove), - - .suspend = isp1362_suspend, - .resume = isp1362_resume, - .driver = { - .name = (char *)hcd_name, - .owner = THIS_MODULE, - }, -}; - -module_platform_driver(isp1362_driver); diff --git a/ANDROID_3.4.5/drivers/usb/host/isp1362.h b/ANDROID_3.4.5/drivers/usb/host/isp1362.h deleted file mode 100644 index 0f97820e..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/isp1362.h +++ /dev/null @@ -1,1057 +0,0 @@ -/* - * ISP1362 HCD (Host Controller Driver) for USB. - * - * COPYRIGHT (C) by L. Wassmann - */ - -/* ------------------------------------------------------------------------- */ -/* - * Platform specific compile time options - */ -#if defined(CONFIG_BLACKFIN) - -#include -#define USE_32BIT 0 -#define MAX_ROOT_PORTS 2 -#define USE_PLATFORM_DELAY 0 -#define USE_NDELAY 1 - -#define DUMMY_DELAY_ACCESS \ - do { \ - bfin_read16(ASYNC_BANK0_BASE); \ - bfin_read16(ASYNC_BANK0_BASE); \ - bfin_read16(ASYNC_BANK0_BASE); \ - } while (0) - -#undef insw -#undef outsw - -#define insw delayed_insw -#define outsw delayed_outsw - -static inline void delayed_outsw(unsigned int addr, void *buf, int len) -{ - unsigned short *bp = (unsigned short *)buf; - while (len--) { - DUMMY_DELAY_ACCESS; - outw(*bp++, addr); - } -} - -static inline void delayed_insw(unsigned int addr, void *buf, int len) -{ - unsigned short *bp = (unsigned short *)buf; - while (len--) { - DUMMY_DELAY_ACCESS; - *bp++ = inw(addr); - } -} - -#else - -#define MAX_ROOT_PORTS 2 - -#define USE_32BIT 0 - -/* These options are mutually eclusive */ -#define USE_PLATFORM_DELAY 0 -#define USE_NDELAY 0 - -#define DUMMY_DELAY_ACCESS do {} while (0) - -#endif - - -/* ------------------------------------------------------------------------- */ - -#define USB_RESET_WIDTH 50 -#define MAX_XFER_SIZE 1023 - -/* Buffer sizes */ -#define ISP1362_BUF_SIZE 4096 -#define ISP1362_ISTL_BUFSIZE 512 -#define ISP1362_INTL_BLKSIZE 64 -#define ISP1362_INTL_BUFFERS 16 -#define ISP1362_ATL_BLKSIZE 64 - -#define ISP1362_REG_WRITE_OFFSET 0x80 - -#ifdef ISP1362_DEBUG -typedef const unsigned int isp1362_reg_t; - -#define REG_WIDTH_16 0x000 -#define REG_WIDTH_32 0x100 -#define REG_WIDTH_MASK 0x100 -#define REG_NO_MASK 0x0ff - -#define REG_ACCESS_R 0x200 -#define REG_ACCESS_W 0x400 -#define REG_ACCESS_RW 0x600 -#define REG_ACCESS_MASK 0x600 - -#define ISP1362_REG_NO(r) ((r) & REG_NO_MASK) - -#define _BUG_ON(x) BUG_ON(x) -#define _WARN_ON(x) WARN_ON(x) - -#define ISP1362_REG(name, addr, width, rw) \ -static isp1362_reg_t ISP1362_REG_##name = ((addr) | (width) | (rw)) - -#define REG_ACCESS_TEST(r) BUG_ON(((r) & ISP1362_REG_WRITE_OFFSET) && !((r) & REG_ACCESS_W)) -#define REG_WIDTH_TEST(r, w) BUG_ON(((r) & REG_WIDTH_MASK) != (w)) -#else -typedef const unsigned char isp1362_reg_t; -#define ISP1362_REG_NO(r) (r) -#define _BUG_ON(x) do {} while (0) -#define _WARN_ON(x) do {} while (0) - -#define ISP1362_REG(name, addr, width, rw) \ -static isp1362_reg_t ISP1362_REG_##name = addr - -#define REG_ACCESS_TEST(r) do {} while (0) -#define REG_WIDTH_TEST(r, w) do {} while (0) -#endif - -/* OHCI compatible registers */ -/* - * Note: Some of the ISP1362 'OHCI' registers implement only - * a subset of the bits defined in the OHCI spec. - * - * Bitmasks for the individual bits of these registers are defined in "ohci.h" - */ -ISP1362_REG(HCREVISION, 0x00, REG_WIDTH_32, REG_ACCESS_R); -ISP1362_REG(HCCONTROL, 0x01, REG_WIDTH_32, REG_ACCESS_RW); -ISP1362_REG(HCCMDSTAT, 0x02, REG_WIDTH_32, REG_ACCESS_RW); -ISP1362_REG(HCINTSTAT, 0x03, REG_WIDTH_32, REG_ACCESS_RW); -ISP1362_REG(HCINTENB, 0x04, REG_WIDTH_32, REG_ACCESS_RW); -ISP1362_REG(HCINTDIS, 0x05, REG_WIDTH_32, REG_ACCESS_RW); -ISP1362_REG(HCFMINTVL, 0x0d, REG_WIDTH_32, REG_ACCESS_RW); -ISP1362_REG(HCFMREM, 0x0e, REG_WIDTH_32, REG_ACCESS_RW); -ISP1362_REG(HCFMNUM, 0x0f, REG_WIDTH_32, REG_ACCESS_RW); -ISP1362_REG(HCLSTHRESH, 0x11, REG_WIDTH_32, REG_ACCESS_RW); -ISP1362_REG(HCRHDESCA, 0x12, REG_WIDTH_32, REG_ACCESS_RW); -ISP1362_REG(HCRHDESCB, 0x13, REG_WIDTH_32, REG_ACCESS_RW); -ISP1362_REG(HCRHSTATUS, 0x14, REG_WIDTH_32, REG_ACCESS_RW); -ISP1362_REG(HCRHPORT1, 0x15, REG_WIDTH_32, REG_ACCESS_RW); -ISP1362_REG(HCRHPORT2, 0x16, REG_WIDTH_32, REG_ACCESS_RW); - -/* Philips ISP1362 specific registers */ -ISP1362_REG(HCHWCFG, 0x20, REG_WIDTH_16, REG_ACCESS_RW); -#define HCHWCFG_DISABLE_SUSPEND (1 << 15) -#define HCHWCFG_GLOBAL_PWRDOWN (1 << 14) -#define HCHWCFG_PULLDOWN_DS2 (1 << 13) -#define HCHWCFG_PULLDOWN_DS1 (1 << 12) -#define HCHWCFG_CLKNOTSTOP (1 << 11) -#define HCHWCFG_ANALOG_OC (1 << 10) -#define HCHWCFG_ONEINT (1 << 9) -#define HCHWCFG_DACK_MODE (1 << 8) -#define HCHWCFG_ONEDMA (1 << 7) -#define HCHWCFG_DACK_POL (1 << 6) -#define HCHWCFG_DREQ_POL (1 << 5) -#define HCHWCFG_DBWIDTH_MASK (0x03 << 3) -#define HCHWCFG_DBWIDTH(n) (((n) << 3) & HCHWCFG_DBWIDTH_MASK) -#define HCHWCFG_INT_POL (1 << 2) -#define HCHWCFG_INT_TRIGGER (1 << 1) -#define HCHWCFG_INT_ENABLE (1 << 0) - -ISP1362_REG(HCDMACFG, 0x21, REG_WIDTH_16, REG_ACCESS_RW); -#define HCDMACFG_CTR_ENABLE (1 << 7) -#define HCDMACFG_BURST_LEN_MASK (0x03 << 5) -#define HCDMACFG_BURST_LEN(n) (((n) << 5) & HCDMACFG_BURST_LEN_MASK) -#define HCDMACFG_BURST_LEN_1 HCDMACFG_BURST_LEN(0) -#define HCDMACFG_BURST_LEN_4 HCDMACFG_BURST_LEN(1) -#define HCDMACFG_BURST_LEN_8 HCDMACFG_BURST_LEN(2) -#define HCDMACFG_DMA_ENABLE (1 << 4) -#define HCDMACFG_BUF_TYPE_MASK (0x07 << 1) -#define HCDMACFG_BUF_TYPE(n) (((n) << 1) & HCDMACFG_BUF_TYPE_MASK) -#define HCDMACFG_BUF_ISTL0 HCDMACFG_BUF_TYPE(0) -#define HCDMACFG_BUF_ISTL1 HCDMACFG_BUF_TYPE(1) -#define HCDMACFG_BUF_INTL HCDMACFG_BUF_TYPE(2) -#define HCDMACFG_BUF_ATL HCDMACFG_BUF_TYPE(3) -#define HCDMACFG_BUF_DIRECT HCDMACFG_BUF_TYPE(4) -#define HCDMACFG_DMA_RW_SELECT (1 << 0) - -ISP1362_REG(HCXFERCTR, 0x22, REG_WIDTH_16, REG_ACCESS_RW); - -ISP1362_REG(HCuPINT, 0x24, REG_WIDTH_16, REG_ACCESS_RW); -#define HCuPINT_SOF (1 << 0) -#define HCuPINT_ISTL0 (1 << 1) -#define HCuPINT_ISTL1 (1 << 2) -#define HCuPINT_EOT (1 << 3) -#define HCuPINT_OPR (1 << 4) -#define HCuPINT_SUSP (1 << 5) -#define HCuPINT_CLKRDY (1 << 6) -#define HCuPINT_INTL (1 << 7) -#define HCuPINT_ATL (1 << 8) -#define HCuPINT_OTG (1 << 9) - -ISP1362_REG(HCuPINTENB, 0x25, REG_WIDTH_16, REG_ACCESS_RW); -/* same bit definitions apply as for HCuPINT */ - -ISP1362_REG(HCCHIPID, 0x27, REG_WIDTH_16, REG_ACCESS_R); -#define HCCHIPID_MASK 0xff00 -#define HCCHIPID_MAGIC 0x3600 - -ISP1362_REG(HCSCRATCH, 0x28, REG_WIDTH_16, REG_ACCESS_RW); - -ISP1362_REG(HCSWRES, 0x29, REG_WIDTH_16, REG_ACCESS_W); -#define HCSWRES_MAGIC 0x00f6 - -ISP1362_REG(HCBUFSTAT, 0x2c, REG_WIDTH_16, REG_ACCESS_RW); -#define HCBUFSTAT_ISTL0_FULL (1 << 0) -#define HCBUFSTAT_ISTL1_FULL (1 << 1) -#define HCBUFSTAT_INTL_ACTIVE (1 << 2) -#define HCBUFSTAT_ATL_ACTIVE (1 << 3) -#define HCBUFSTAT_RESET_HWPP (1 << 4) -#define HCBUFSTAT_ISTL0_ACTIVE (1 << 5) -#define HCBUFSTAT_ISTL1_ACTIVE (1 << 6) -#define HCBUFSTAT_ISTL0_DONE (1 << 8) -#define HCBUFSTAT_ISTL1_DONE (1 << 9) -#define HCBUFSTAT_PAIRED_PTDPP (1 << 10) - -ISP1362_REG(HCDIRADDR, 0x32, REG_WIDTH_32, REG_ACCESS_RW); -#define HCDIRADDR_ADDR_MASK 0x0000ffff -#define HCDIRADDR_ADDR(n) (((n) << 0) & HCDIRADDR_ADDR_MASK) -#define HCDIRADDR_COUNT_MASK 0xffff0000 -#define HCDIRADDR_COUNT(n) (((n) << 16) & HCDIRADDR_COUNT_MASK) -ISP1362_REG(HCDIRDATA, 0x45, REG_WIDTH_16, REG_ACCESS_RW); - -ISP1362_REG(HCISTLBUFSZ, 0x30, REG_WIDTH_16, REG_ACCESS_RW); -ISP1362_REG(HCISTL0PORT, 0x40, REG_WIDTH_16, REG_ACCESS_RW); -ISP1362_REG(HCISTL1PORT, 0x42, REG_WIDTH_16, REG_ACCESS_RW); -ISP1362_REG(HCISTLRATE, 0x47, REG_WIDTH_16, REG_ACCESS_RW); - -ISP1362_REG(HCINTLBUFSZ, 0x33, REG_WIDTH_16, REG_ACCESS_RW); -ISP1362_REG(HCINTLPORT, 0x43, REG_WIDTH_16, REG_ACCESS_RW); -ISP1362_REG(HCINTLBLKSZ, 0x53, REG_WIDTH_16, REG_ACCESS_RW); -ISP1362_REG(HCINTLDONE, 0x17, REG_WIDTH_32, REG_ACCESS_R); -ISP1362_REG(HCINTLSKIP, 0x18, REG_WIDTH_32, REG_ACCESS_RW); -ISP1362_REG(HCINTLLAST, 0x19, REG_WIDTH_32, REG_ACCESS_RW); -ISP1362_REG(HCINTLCURR, 0x1a, REG_WIDTH_16, REG_ACCESS_R); - -ISP1362_REG(HCATLBUFSZ, 0x34, REG_WIDTH_16, REG_ACCESS_RW); -ISP1362_REG(HCATLPORT, 0x44, REG_WIDTH_16, REG_ACCESS_RW); -ISP1362_REG(HCATLBLKSZ, 0x54, REG_WIDTH_16, REG_ACCESS_RW); -ISP1362_REG(HCATLDONE, 0x1b, REG_WIDTH_32, REG_ACCESS_R); -ISP1362_REG(HCATLSKIP, 0x1c, REG_WIDTH_32, REG_ACCESS_RW); -ISP1362_REG(HCATLLAST, 0x1d, REG_WIDTH_32, REG_ACCESS_RW); -ISP1362_REG(HCATLCURR, 0x1e, REG_WIDTH_16, REG_ACCESS_R); - -ISP1362_REG(HCATLDTC, 0x51, REG_WIDTH_16, REG_ACCESS_RW); -ISP1362_REG(HCATLDTCTO, 0x52, REG_WIDTH_16, REG_ACCESS_RW); - - -ISP1362_REG(OTGCONTROL, 0x62, REG_WIDTH_16, REG_ACCESS_RW); -ISP1362_REG(OTGSTATUS, 0x67, REG_WIDTH_16, REG_ACCESS_R); -ISP1362_REG(OTGINT, 0x68, REG_WIDTH_16, REG_ACCESS_RW); -ISP1362_REG(OTGINTENB, 0x69, REG_WIDTH_16, REG_ACCESS_RW); -ISP1362_REG(OTGTIMER, 0x6A, REG_WIDTH_16, REG_ACCESS_RW); -ISP1362_REG(OTGALTTMR, 0x6C, REG_WIDTH_16, REG_ACCESS_RW); - -/* Philips transfer descriptor, cpu-endian */ -struct ptd { - u16 count; -#define PTD_COUNT_MSK (0x3ff << 0) -#define PTD_TOGGLE_MSK (1 << 10) -#define PTD_ACTIVE_MSK (1 << 11) -#define PTD_CC_MSK (0xf << 12) - u16 mps; -#define PTD_MPS_MSK (0x3ff << 0) -#define PTD_SPD_MSK (1 << 10) -#define PTD_LAST_MSK (1 << 11) -#define PTD_EP_MSK (0xf << 12) - u16 len; -#define PTD_LEN_MSK (0x3ff << 0) -#define PTD_DIR_MSK (3 << 10) -#define PTD_DIR_SETUP (0) -#define PTD_DIR_OUT (1) -#define PTD_DIR_IN (2) - u16 faddr; -#define PTD_FA_MSK (0x7f << 0) -/* PTD Byte 7: [StartingFrame (if ISO PTD) | StartingFrame[0..4], PollingRate[0..2] (if INT PTD)] */ -#define PTD_SF_ISO_MSK (0xff << 8) -#define PTD_SF_INT_MSK (0x1f << 8) -#define PTD_PR_MSK (0x07 << 13) -} __attribute__ ((packed, aligned(2))); -#define PTD_HEADER_SIZE sizeof(struct ptd) - -/* ------------------------------------------------------------------------- */ -/* Copied from ohci.h: */ -/* - * Hardware transfer status codes -- CC from PTD - */ -#define PTD_CC_NOERROR 0x00 -#define PTD_CC_CRC 0x01 -#define PTD_CC_BITSTUFFING 0x02 -#define PTD_CC_DATATOGGLEM 0x03 -#define PTD_CC_STALL 0x04 -#define PTD_DEVNOTRESP 0x05 -#define PTD_PIDCHECKFAIL 0x06 -#define PTD_UNEXPECTEDPID 0x07 -#define PTD_DATAOVERRUN 0x08 -#define PTD_DATAUNDERRUN 0x09 - /* 0x0A, 0x0B reserved for hardware */ -#define PTD_BUFFEROVERRUN 0x0C -#define PTD_BUFFERUNDERRUN 0x0D - /* 0x0E, 0x0F reserved for HCD */ -#define PTD_NOTACCESSED 0x0F - - -/* map OHCI TD status codes (CC) to errno values */ -static const int cc_to_error[16] = { - /* No Error */ 0, - /* CRC Error */ -EILSEQ, - /* Bit Stuff */ -EPROTO, - /* Data Togg */ -EILSEQ, - /* Stall */ -EPIPE, - /* DevNotResp */ -ETIMEDOUT, - /* PIDCheck */ -EPROTO, - /* UnExpPID */ -EPROTO, - /* DataOver */ -EOVERFLOW, - /* DataUnder */ -EREMOTEIO, - /* (for hw) */ -EIO, - /* (for hw) */ -EIO, - /* BufferOver */ -ECOMM, - /* BuffUnder */ -ENOSR, - /* (for HCD) */ -EALREADY, - /* (for HCD) */ -EALREADY -}; - - -/* - * HcControl (control) register masks - */ -#define OHCI_CTRL_HCFS (3 << 6) /* host controller functional state */ -#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ -#define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */ - -/* pre-shifted values for HCFS */ -# define OHCI_USB_RESET (0 << 6) -# define OHCI_USB_RESUME (1 << 6) -# define OHCI_USB_OPER (2 << 6) -# define OHCI_USB_SUSPEND (3 << 6) - -/* - * HcCommandStatus (cmdstatus) register masks - */ -#define OHCI_HCR (1 << 0) /* host controller reset */ -#define OHCI_SOC (3 << 16) /* scheduling overrun count */ - -/* - * masks used with interrupt registers: - * HcInterruptStatus (intrstatus) - * HcInterruptEnable (intrenable) - * HcInterruptDisable (intrdisable) - */ -#define OHCI_INTR_SO (1 << 0) /* scheduling overrun */ -#define OHCI_INTR_WDH (1 << 1) /* writeback of done_head */ -#define OHCI_INTR_SF (1 << 2) /* start frame */ -#define OHCI_INTR_RD (1 << 3) /* resume detect */ -#define OHCI_INTR_UE (1 << 4) /* unrecoverable error */ -#define OHCI_INTR_FNO (1 << 5) /* frame number overflow */ -#define OHCI_INTR_RHSC (1 << 6) /* root hub status change */ -#define OHCI_INTR_OC (1 << 30) /* ownership change */ -#define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */ - -/* roothub.portstatus [i] bits */ -#define RH_PS_CCS 0x00000001 /* current connect status */ -#define RH_PS_PES 0x00000002 /* port enable status*/ -#define RH_PS_PSS 0x00000004 /* port suspend status */ -#define RH_PS_POCI 0x00000008 /* port over current indicator */ -#define RH_PS_PRS 0x00000010 /* port reset status */ -#define RH_PS_PPS 0x00000100 /* port power status */ -#define RH_PS_LSDA 0x00000200 /* low speed device attached */ -#define RH_PS_CSC 0x00010000 /* connect status change */ -#define RH_PS_PESC 0x00020000 /* port enable status change */ -#define RH_PS_PSSC 0x00040000 /* port suspend status change */ -#define RH_PS_OCIC 0x00080000 /* over current indicator change */ -#define RH_PS_PRSC 0x00100000 /* port reset status change */ - -/* roothub.status bits */ -#define RH_HS_LPS 0x00000001 /* local power status */ -#define RH_HS_OCI 0x00000002 /* over current indicator */ -#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */ -#define RH_HS_LPSC 0x00010000 /* local power status change */ -#define RH_HS_OCIC 0x00020000 /* over current indicator change */ -#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */ - -/* roothub.b masks */ -#define RH_B_DR 0x0000ffff /* device removable flags */ -#define RH_B_PPCM 0xffff0000 /* port power control mask */ - -/* roothub.a masks */ -#define RH_A_NDP (0xff << 0) /* number of downstream ports */ -#define RH_A_PSM (1 << 8) /* power switching mode */ -#define RH_A_NPS (1 << 9) /* no power switching */ -#define RH_A_DT (1 << 10) /* device type (mbz) */ -#define RH_A_OCPM (1 << 11) /* over current protection mode */ -#define RH_A_NOCP (1 << 12) /* no over current protection */ -#define RH_A_POTPGT (0xff << 24) /* power on to power good time */ - -#define FI 0x2edf /* 12000 bits per frame (-1) */ -#define FSMP(fi) (0x7fff & ((6 * ((fi) - 210)) / 7)) -#define LSTHRESH 0x628 /* lowspeed bit threshold */ - -/* ------------------------------------------------------------------------- */ - -/* PTD accessor macros. */ -#define PTD_GET_COUNT(p) (((p)->count & PTD_COUNT_MSK) >> 0) -#define PTD_COUNT(v) (((v) << 0) & PTD_COUNT_MSK) -#define PTD_GET_TOGGLE(p) (((p)->count & PTD_TOGGLE_MSK) >> 10) -#define PTD_TOGGLE(v) (((v) << 10) & PTD_TOGGLE_MSK) -#define PTD_GET_ACTIVE(p) (((p)->count & PTD_ACTIVE_MSK) >> 11) -#define PTD_ACTIVE(v) (((v) << 11) & PTD_ACTIVE_MSK) -#define PTD_GET_CC(p) (((p)->count & PTD_CC_MSK) >> 12) -#define PTD_CC(v) (((v) << 12) & PTD_CC_MSK) -#define PTD_GET_MPS(p) (((p)->mps & PTD_MPS_MSK) >> 0) -#define PTD_MPS(v) (((v) << 0) & PTD_MPS_MSK) -#define PTD_GET_SPD(p) (((p)->mps & PTD_SPD_MSK) >> 10) -#define PTD_SPD(v) (((v) << 10) & PTD_SPD_MSK) -#define PTD_GET_LAST(p) (((p)->mps & PTD_LAST_MSK) >> 11) -#define PTD_LAST(v) (((v) << 11) & PTD_LAST_MSK) -#define PTD_GET_EP(p) (((p)->mps & PTD_EP_MSK) >> 12) -#define PTD_EP(v) (((v) << 12) & PTD_EP_MSK) -#define PTD_GET_LEN(p) (((p)->len & PTD_LEN_MSK) >> 0) -#define PTD_LEN(v) (((v) << 0) & PTD_LEN_MSK) -#define PTD_GET_DIR(p) (((p)->len & PTD_DIR_MSK) >> 10) -#define PTD_DIR(v) (((v) << 10) & PTD_DIR_MSK) -#define PTD_GET_FA(p) (((p)->faddr & PTD_FA_MSK) >> 0) -#define PTD_FA(v) (((v) << 0) & PTD_FA_MSK) -#define PTD_GET_SF_INT(p) (((p)->faddr & PTD_SF_INT_MSK) >> 8) -#define PTD_SF_INT(v) (((v) << 8) & PTD_SF_INT_MSK) -#define PTD_GET_SF_ISO(p) (((p)->faddr & PTD_SF_ISO_MSK) >> 8) -#define PTD_SF_ISO(v) (((v) << 8) & PTD_SF_ISO_MSK) -#define PTD_GET_PR(p) (((p)->faddr & PTD_PR_MSK) >> 13) -#define PTD_PR(v) (((v) << 13) & PTD_PR_MSK) - -#define LOG2_PERIODIC_SIZE 5 /* arbitrary; this matches OHCI */ -#define PERIODIC_SIZE (1 << LOG2_PERIODIC_SIZE) - -struct isp1362_ep { - struct usb_host_endpoint *hep; - struct usb_device *udev; - - /* philips transfer descriptor */ - struct ptd ptd; - - u8 maxpacket; - u8 epnum; - u8 nextpid; - u16 error_count; - u16 length; /* of current packet */ - s16 ptd_offset; /* buffer offset in ISP1362 where - PTD has been stored - (for access thru HCDIRDATA) */ - int ptd_index; - int num_ptds; - void *data; /* to databuf */ - /* queue of active EPs (the ones transmitted to the chip) */ - struct list_head active; - - /* periodic schedule */ - u8 branch; - u16 interval; - u16 load; - u16 last_iso; - - /* async schedule */ - struct list_head schedule; /* list of all EPs that need processing */ - struct list_head remove_list; - int num_req; -}; - -struct isp1362_ep_queue { - struct list_head active; /* list of PTDs currently processed by HC */ - atomic_t finishing; - unsigned long buf_map; - unsigned long skip_map; - int free_ptd; - u16 buf_start; - u16 buf_size; - u16 blk_size; /* PTD buffer block size for ATL and INTL */ - u8 buf_count; - u8 buf_avail; - char name[16]; - - /* for statistical tracking */ - u8 stat_maxptds; /* Max # of ptds seen simultaneously in fifo */ - u8 ptd_count; /* number of ptds submitted to this queue */ -}; - -struct isp1362_hcd { - spinlock_t lock; - void __iomem *addr_reg; - void __iomem *data_reg; - - struct isp1362_platform_data *board; - - struct proc_dir_entry *pde; - unsigned long stat1, stat2, stat4, stat8, stat16; - - /* HC registers */ - u32 intenb; /* "OHCI" interrupts */ - u16 irqenb; /* uP interrupts */ - - /* Root hub registers */ - u32 rhdesca; - u32 rhdescb; - u32 rhstatus; - u32 rhport[MAX_ROOT_PORTS]; - unsigned long next_statechange; - - /* HC control reg shadow copy */ - u32 hc_control; - - /* async schedule: control, bulk */ - struct list_head async; - - /* periodic schedule: int */ - u16 load[PERIODIC_SIZE]; - struct list_head periodic; - u16 fmindex; - - /* periodic schedule: isochronous */ - struct list_head isoc; - unsigned int istl_flip:1; - unsigned int irq_active:1; - - /* Schedules for the current frame */ - struct isp1362_ep_queue atl_queue; - struct isp1362_ep_queue intl_queue; - struct isp1362_ep_queue istl_queue[2]; - - /* list of PTDs retrieved from HC */ - struct list_head remove_list; - enum { - ISP1362_INT_SOF, - ISP1362_INT_ISTL0, - ISP1362_INT_ISTL1, - ISP1362_INT_EOT, - ISP1362_INT_OPR, - ISP1362_INT_SUSP, - ISP1362_INT_CLKRDY, - ISP1362_INT_INTL, - ISP1362_INT_ATL, - ISP1362_INT_OTG, - NUM_ISP1362_IRQS - } IRQ_NAMES; - unsigned int irq_stat[NUM_ISP1362_IRQS]; - int req_serial; -}; - -static inline const char *ISP1362_INT_NAME(int n) -{ - switch (n) { - case ISP1362_INT_SOF: return "SOF"; - case ISP1362_INT_ISTL0: return "ISTL0"; - case ISP1362_INT_ISTL1: return "ISTL1"; - case ISP1362_INT_EOT: return "EOT"; - case ISP1362_INT_OPR: return "OPR"; - case ISP1362_INT_SUSP: return "SUSP"; - case ISP1362_INT_CLKRDY: return "CLKRDY"; - case ISP1362_INT_INTL: return "INTL"; - case ISP1362_INT_ATL: return "ATL"; - case ISP1362_INT_OTG: return "OTG"; - default: return "unknown"; - } -} - -static inline void ALIGNSTAT(struct isp1362_hcd *isp1362_hcd, void *ptr) -{ - unsigned long p = (unsigned long)ptr; - if (!(p & 0xf)) - isp1362_hcd->stat16++; - else if (!(p & 0x7)) - isp1362_hcd->stat8++; - else if (!(p & 0x3)) - isp1362_hcd->stat4++; - else if (!(p & 0x1)) - isp1362_hcd->stat2++; - else - isp1362_hcd->stat1++; -} - -static inline struct isp1362_hcd *hcd_to_isp1362_hcd(struct usb_hcd *hcd) -{ - return (struct isp1362_hcd *) (hcd->hcd_priv); -} - -static inline struct usb_hcd *isp1362_hcd_to_hcd(struct isp1362_hcd *isp1362_hcd) -{ - return container_of((void *)isp1362_hcd, struct usb_hcd, hcd_priv); -} - -#define frame_before(f1, f2) ((s16)((u16)f1 - (u16)f2) < 0) - -/* - * ISP1362 HW Interface - */ - -#ifdef ISP1362_DEBUG -#define DBG(level, fmt...) \ - do { \ - if (dbg_level > level) \ - pr_debug(fmt); \ - } while (0) -#define _DBG(level, fmt...) \ - do { \ - if (dbg_level > level) \ - printk(fmt); \ - } while (0) -#else -#define DBG(fmt...) do {} while (0) -#define _DBG DBG -#endif - -#ifdef VERBOSE -# define VDBG(fmt...) DBG(3, fmt) -#else -# define VDBG(fmt...) do {} while (0) -#endif - -#ifdef REGISTERS -# define RDBG(fmt...) DBG(1, fmt) -#else -# define RDBG(fmt...) do {} while (0) -#endif - -#ifdef URB_TRACE -#define URB_DBG(fmt...) DBG(0, fmt) -#else -#define URB_DBG(fmt...) do {} while (0) -#endif - - -#if USE_PLATFORM_DELAY -#if USE_NDELAY -#error USE_PLATFORM_DELAY and USE_NDELAY defined simultaneously. -#endif -#define isp1362_delay(h, d) (h)->board->delay(isp1362_hcd_to_hcd(h)->self.controller, d) -#elif USE_NDELAY -#define isp1362_delay(h, d) ndelay(d) -#else -#define isp1362_delay(h, d) do {} while (0) -#endif - -#define get_urb(ep) ({ \ - BUG_ON(list_empty(&ep->hep->urb_list)); \ - container_of(ep->hep->urb_list.next, struct urb, urb_list); \ -}) - -/* basic access functions for ISP1362 chip registers */ -/* NOTE: The contents of the address pointer register cannot be read back! The driver must ensure, - * that all register accesses are performed with interrupts disabled, since the interrupt - * handler has no way of restoring the previous state. - */ -static void isp1362_write_addr(struct isp1362_hcd *isp1362_hcd, isp1362_reg_t reg) -{ - /*_BUG_ON((reg & ISP1362_REG_WRITE_OFFSET) && !(reg & REG_ACCESS_W));*/ - REG_ACCESS_TEST(reg); - _BUG_ON(!irqs_disabled()); - DUMMY_DELAY_ACCESS; - writew(ISP1362_REG_NO(reg), isp1362_hcd->addr_reg); - DUMMY_DELAY_ACCESS; - isp1362_delay(isp1362_hcd, 1); -} - -static void isp1362_write_data16(struct isp1362_hcd *isp1362_hcd, u16 val) -{ - _BUG_ON(!irqs_disabled()); - DUMMY_DELAY_ACCESS; - writew(val, isp1362_hcd->data_reg); -} - -static u16 isp1362_read_data16(struct isp1362_hcd *isp1362_hcd) -{ - u16 val; - - _BUG_ON(!irqs_disabled()); - DUMMY_DELAY_ACCESS; - val = readw(isp1362_hcd->data_reg); - - return val; -} - -static void isp1362_write_data32(struct isp1362_hcd *isp1362_hcd, u32 val) -{ - _BUG_ON(!irqs_disabled()); -#if USE_32BIT - DUMMY_DELAY_ACCESS; - writel(val, isp1362_hcd->data_reg); -#else - DUMMY_DELAY_ACCESS; - writew((u16)val, isp1362_hcd->data_reg); - DUMMY_DELAY_ACCESS; - writew(val >> 16, isp1362_hcd->data_reg); -#endif -} - -static u32 isp1362_read_data32(struct isp1362_hcd *isp1362_hcd) -{ - u32 val; - - _BUG_ON(!irqs_disabled()); -#if USE_32BIT - DUMMY_DELAY_ACCESS; - val = readl(isp1362_hcd->data_reg); -#else - DUMMY_DELAY_ACCESS; - val = (u32)readw(isp1362_hcd->data_reg); - DUMMY_DELAY_ACCESS; - val |= (u32)readw(isp1362_hcd->data_reg) << 16; -#endif - return val; -} - -/* use readsw/writesw to access the fifo whenever possible */ -/* assume HCDIRDATA or XFERCTR & addr_reg have been set up */ -static void isp1362_read_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 len) -{ - u8 *dp = buf; - u16 data; - - if (!len) - return; - - _BUG_ON(!irqs_disabled()); - - RDBG("%s: Reading %d byte from fifo to mem @ %p\n", __func__, len, buf); -#if USE_32BIT - if (len >= 4) { - RDBG("%s: Using readsl for %d dwords\n", __func__, len >> 2); - readsl(isp1362_hcd->data_reg, dp, len >> 2); - dp += len & ~3; - len &= 3; - } -#endif - if (len >= 2) { - RDBG("%s: Using readsw for %d words\n", __func__, len >> 1); - insw((unsigned long)isp1362_hcd->data_reg, dp, len >> 1); - dp += len & ~1; - len &= 1; - } - - BUG_ON(len & ~1); - if (len > 0) { - data = isp1362_read_data16(isp1362_hcd); - RDBG("%s: Reading trailing byte %02x to mem @ %08x\n", __func__, - (u8)data, (u32)dp); - *dp = (u8)data; - } -} - -static void isp1362_write_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 len) -{ - u8 *dp = buf; - u16 data; - - if (!len) - return; - - if ((unsigned long)dp & 0x1) { - /* not aligned */ - for (; len > 1; len -= 2) { - data = *dp++; - data |= *dp++ << 8; - isp1362_write_data16(isp1362_hcd, data); - } - if (len) - isp1362_write_data16(isp1362_hcd, *dp); - return; - } - - _BUG_ON(!irqs_disabled()); - - RDBG("%s: Writing %d byte to fifo from memory @%p\n", __func__, len, buf); -#if USE_32BIT - if (len >= 4) { - RDBG("%s: Using writesl for %d dwords\n", __func__, len >> 2); - writesl(isp1362_hcd->data_reg, dp, len >> 2); - dp += len & ~3; - len &= 3; - } -#endif - if (len >= 2) { - RDBG("%s: Using writesw for %d words\n", __func__, len >> 1); - outsw((unsigned long)isp1362_hcd->data_reg, dp, len >> 1); - dp += len & ~1; - len &= 1; - } - - BUG_ON(len & ~1); - if (len > 0) { - /* finally write any trailing byte; we don't need to care - * about the high byte of the last word written - */ - data = (u16)*dp; - RDBG("%s: Sending trailing byte %02x from mem @ %08x\n", __func__, - data, (u32)dp); - isp1362_write_data16(isp1362_hcd, data); - } -} - -#define isp1362_read_reg16(d, r) ({ \ - u16 __v; \ - REG_WIDTH_TEST(ISP1362_REG_##r, REG_WIDTH_16); \ - isp1362_write_addr(d, ISP1362_REG_##r); \ - __v = isp1362_read_data16(d); \ - RDBG("%s: Read %04x from %s[%02x]\n", __func__, __v, #r, \ - ISP1362_REG_NO(ISP1362_REG_##r)); \ - __v; \ -}) - -#define isp1362_read_reg32(d, r) ({ \ - u32 __v; \ - REG_WIDTH_TEST(ISP1362_REG_##r, REG_WIDTH_32); \ - isp1362_write_addr(d, ISP1362_REG_##r); \ - __v = isp1362_read_data32(d); \ - RDBG("%s: Read %08x from %s[%02x]\n", __func__, __v, #r, \ - ISP1362_REG_NO(ISP1362_REG_##r)); \ - __v; \ -}) - -#define isp1362_write_reg16(d, r, v) { \ - REG_WIDTH_TEST(ISP1362_REG_##r, REG_WIDTH_16); \ - isp1362_write_addr(d, (ISP1362_REG_##r) | ISP1362_REG_WRITE_OFFSET); \ - isp1362_write_data16(d, (u16)(v)); \ - RDBG("%s: Wrote %04x to %s[%02x]\n", __func__, (u16)(v), #r, \ - ISP1362_REG_NO(ISP1362_REG_##r)); \ -} - -#define isp1362_write_reg32(d, r, v) { \ - REG_WIDTH_TEST(ISP1362_REG_##r, REG_WIDTH_32); \ - isp1362_write_addr(d, (ISP1362_REG_##r) | ISP1362_REG_WRITE_OFFSET); \ - isp1362_write_data32(d, (u32)(v)); \ - RDBG("%s: Wrote %08x to %s[%02x]\n", __func__, (u32)(v), #r, \ - ISP1362_REG_NO(ISP1362_REG_##r)); \ -} - -#define isp1362_set_mask16(d, r, m) { \ - u16 __v; \ - __v = isp1362_read_reg16(d, r); \ - if ((__v | m) != __v) \ - isp1362_write_reg16(d, r, __v | m); \ -} - -#define isp1362_clr_mask16(d, r, m) { \ - u16 __v; \ - __v = isp1362_read_reg16(d, r); \ - if ((__v & ~m) != __v) \ - isp1362_write_reg16(d, r, __v & ~m); \ -} - -#define isp1362_set_mask32(d, r, m) { \ - u32 __v; \ - __v = isp1362_read_reg32(d, r); \ - if ((__v | m) != __v) \ - isp1362_write_reg32(d, r, __v | m); \ -} - -#define isp1362_clr_mask32(d, r, m) { \ - u32 __v; \ - __v = isp1362_read_reg32(d, r); \ - if ((__v & ~m) != __v) \ - isp1362_write_reg32(d, r, __v & ~m); \ -} - -#ifdef ISP1362_DEBUG -#define isp1362_show_reg(d, r) { \ - if ((ISP1362_REG_##r & REG_WIDTH_MASK) == REG_WIDTH_32) \ - DBG(0, "%-12s[%02x]: %08x\n", #r, \ - ISP1362_REG_NO(ISP1362_REG_##r), isp1362_read_reg32(d, r)); \ - else \ - DBG(0, "%-12s[%02x]: %04x\n", #r, \ - ISP1362_REG_NO(ISP1362_REG_##r), isp1362_read_reg16(d, r)); \ -} -#else -#define isp1362_show_reg(d, r) do {} while (0) -#endif - -static void __attribute__((__unused__)) isp1362_show_regs(struct isp1362_hcd *isp1362_hcd) -{ - isp1362_show_reg(isp1362_hcd, HCREVISION); - isp1362_show_reg(isp1362_hcd, HCCONTROL); - isp1362_show_reg(isp1362_hcd, HCCMDSTAT); - isp1362_show_reg(isp1362_hcd, HCINTSTAT); - isp1362_show_reg(isp1362_hcd, HCINTENB); - isp1362_show_reg(isp1362_hcd, HCFMINTVL); - isp1362_show_reg(isp1362_hcd, HCFMREM); - isp1362_show_reg(isp1362_hcd, HCFMNUM); - isp1362_show_reg(isp1362_hcd, HCLSTHRESH); - isp1362_show_reg(isp1362_hcd, HCRHDESCA); - isp1362_show_reg(isp1362_hcd, HCRHDESCB); - isp1362_show_reg(isp1362_hcd, HCRHSTATUS); - isp1362_show_reg(isp1362_hcd, HCRHPORT1); - isp1362_show_reg(isp1362_hcd, HCRHPORT2); - - isp1362_show_reg(isp1362_hcd, HCHWCFG); - isp1362_show_reg(isp1362_hcd, HCDMACFG); - isp1362_show_reg(isp1362_hcd, HCXFERCTR); - isp1362_show_reg(isp1362_hcd, HCuPINT); - - if (in_interrupt()) - DBG(0, "%-12s[%02x]: %04x\n", "HCuPINTENB", - ISP1362_REG_NO(ISP1362_REG_HCuPINTENB), isp1362_hcd->irqenb); - else - isp1362_show_reg(isp1362_hcd, HCuPINTENB); - isp1362_show_reg(isp1362_hcd, HCCHIPID); - isp1362_show_reg(isp1362_hcd, HCSCRATCH); - isp1362_show_reg(isp1362_hcd, HCBUFSTAT); - isp1362_show_reg(isp1362_hcd, HCDIRADDR); - /* Access would advance fifo - * isp1362_show_reg(isp1362_hcd, HCDIRDATA); - */ - isp1362_show_reg(isp1362_hcd, HCISTLBUFSZ); - isp1362_show_reg(isp1362_hcd, HCISTLRATE); - isp1362_show_reg(isp1362_hcd, HCINTLBUFSZ); - isp1362_show_reg(isp1362_hcd, HCINTLBLKSZ); - isp1362_show_reg(isp1362_hcd, HCINTLDONE); - isp1362_show_reg(isp1362_hcd, HCINTLSKIP); - isp1362_show_reg(isp1362_hcd, HCINTLLAST); - isp1362_show_reg(isp1362_hcd, HCINTLCURR); - isp1362_show_reg(isp1362_hcd, HCATLBUFSZ); - isp1362_show_reg(isp1362_hcd, HCATLBLKSZ); - /* only valid after ATL_DONE interrupt - * isp1362_show_reg(isp1362_hcd, HCATLDONE); - */ - isp1362_show_reg(isp1362_hcd, HCATLSKIP); - isp1362_show_reg(isp1362_hcd, HCATLLAST); - isp1362_show_reg(isp1362_hcd, HCATLCURR); - isp1362_show_reg(isp1362_hcd, HCATLDTC); - isp1362_show_reg(isp1362_hcd, HCATLDTCTO); -} - -static void isp1362_write_diraddr(struct isp1362_hcd *isp1362_hcd, u16 offset, u16 len) -{ - _BUG_ON(offset & 1); - _BUG_ON(offset >= ISP1362_BUF_SIZE); - _BUG_ON(len > ISP1362_BUF_SIZE); - _BUG_ON(offset + len > ISP1362_BUF_SIZE); - len = (len + 1) & ~1; - - isp1362_clr_mask16(isp1362_hcd, HCDMACFG, HCDMACFG_CTR_ENABLE); - isp1362_write_reg32(isp1362_hcd, HCDIRADDR, - HCDIRADDR_ADDR(offset) | HCDIRADDR_COUNT(len)); -} - -static void isp1362_read_buffer(struct isp1362_hcd *isp1362_hcd, void *buf, u16 offset, int len) -{ - _BUG_ON(offset & 1); - - isp1362_write_diraddr(isp1362_hcd, offset, len); - - DBG(3, "%s: Reading %d byte from buffer @%04x to memory @ %p\n", - __func__, len, offset, buf); - - isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT); - _WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT)); - - isp1362_write_addr(isp1362_hcd, ISP1362_REG_HCDIRDATA); - - isp1362_read_fifo(isp1362_hcd, buf, len); - _WARN_ON(!(isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT)); - isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT); - _WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT)); -} - -static void isp1362_write_buffer(struct isp1362_hcd *isp1362_hcd, void *buf, u16 offset, int len) -{ - _BUG_ON(offset & 1); - - isp1362_write_diraddr(isp1362_hcd, offset, len); - - DBG(3, "%s: Writing %d byte to buffer @%04x from memory @ %p\n", - __func__, len, offset, buf); - - isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT); - _WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT)); - - isp1362_write_addr(isp1362_hcd, ISP1362_REG_HCDIRDATA | ISP1362_REG_WRITE_OFFSET); - isp1362_write_fifo(isp1362_hcd, buf, len); - - _WARN_ON(!(isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT)); - isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT); - _WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT)); -} - -static void __attribute__((unused)) dump_data(char *buf, int len) -{ - if (dbg_level > 0) { - int k; - int lf = 0; - - for (k = 0; k < len; ++k) { - if (!lf) - DBG(0, "%04x:", k); - printk(" %02x", ((u8 *) buf)[k]); - lf = 1; - if (!k) - continue; - if (k % 16 == 15) { - printk("\n"); - lf = 0; - continue; - } - if (k % 8 == 7) - printk(" "); - if (k % 4 == 3) - printk(" "); - } - if (lf) - printk("\n"); - } -} - -#if defined(ISP1362_DEBUG) && defined(PTD_TRACE) - -static void dump_ptd(struct ptd *ptd) -{ - DBG(0, "EP %p: CC=%x EP=%d DIR=%x CNT=%d LEN=%d MPS=%d TGL=%x ACT=%x FA=%d SPD=%x SF=%x PR=%x LST=%x\n", - container_of(ptd, struct isp1362_ep, ptd), - PTD_GET_CC(ptd), PTD_GET_EP(ptd), PTD_GET_DIR(ptd), - PTD_GET_COUNT(ptd), PTD_GET_LEN(ptd), PTD_GET_MPS(ptd), - PTD_GET_TOGGLE(ptd), PTD_GET_ACTIVE(ptd), PTD_GET_FA(ptd), - PTD_GET_SPD(ptd), PTD_GET_SF_INT(ptd), PTD_GET_PR(ptd), PTD_GET_LAST(ptd)); - DBG(0, " %04x %04x %04x %04x\n", ptd->count, ptd->mps, ptd->len, ptd->faddr); -} - -static void dump_ptd_out_data(struct ptd *ptd, u8 *buf) -{ - if (dbg_level > 0) { - if (PTD_GET_DIR(ptd) != PTD_DIR_IN && PTD_GET_LEN(ptd)) { - DBG(0, "--out->\n"); - dump_data(buf, PTD_GET_LEN(ptd)); - } - } -} - -static void dump_ptd_in_data(struct ptd *ptd, u8 *buf) -{ - if (dbg_level > 0) { - if (PTD_GET_DIR(ptd) == PTD_DIR_IN && PTD_GET_COUNT(ptd)) { - DBG(0, "<--in--\n"); - dump_data(buf, PTD_GET_COUNT(ptd)); - } - DBG(0, "-----\n"); - } -} - -static void dump_ptd_queue(struct isp1362_ep_queue *epq) -{ - struct isp1362_ep *ep; - int dbg = dbg_level; - - dbg_level = 1; - list_for_each_entry(ep, &epq->active, active) { - dump_ptd(&ep->ptd); - dump_data(ep->data, ep->length); - } - dbg_level = dbg; -} -#else -#define dump_ptd(ptd) do {} while (0) -#define dump_ptd_in_data(ptd, buf) do {} while (0) -#define dump_ptd_out_data(ptd, buf) do {} while (0) -#define dump_ptd_data(ptd, buf) do {} while (0) -#define dump_ptd_queue(epq) do {} while (0) -#endif diff --git a/ANDROID_3.4.5/drivers/usb/host/isp1760-hcd.c b/ANDROID_3.4.5/drivers/usb/host/isp1760-hcd.c deleted file mode 100644 index fc72d44b..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/isp1760-hcd.c +++ /dev/null @@ -1,2262 +0,0 @@ -/* - * Driver for the NXP ISP1760 chip - * - * However, the code might contain some bugs. What doesn't work for sure is: - * - ISO - * - OTG - e The interrupt line is configured as active low, level. - * - * (c) 2007 Sebastian Siewior - * - * (c) 2011 Arvid Brodin - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "isp1760-hcd.h" - -static struct kmem_cache *qtd_cachep; -static struct kmem_cache *qh_cachep; -static struct kmem_cache *urb_listitem_cachep; - -enum queue_head_types { - QH_CONTROL, - QH_BULK, - QH_INTERRUPT, - QH_END -}; - -struct isp1760_hcd { - u32 hcs_params; - spinlock_t lock; - struct slotinfo atl_slots[32]; - int atl_done_map; - struct slotinfo int_slots[32]; - int int_done_map; - struct memory_chunk memory_pool[BLOCKS]; - struct list_head qh_list[QH_END]; - - /* periodic schedule support */ -#define DEFAULT_I_TDPS 1024 - unsigned periodic_size; - unsigned i_thresh; - unsigned long reset_done; - unsigned long next_statechange; - unsigned int devflags; - - int rst_gpio; -}; - -static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd) -{ - return (struct isp1760_hcd *) (hcd->hcd_priv); -} - -/* Section 2.2 Host Controller Capability Registers */ -#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */ -#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */ -#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */ -#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */ -#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */ -#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */ -#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */ - -/* Section 2.3 Host Controller Operational Registers */ -#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */ -#define CMD_RESET (1<<1) /* reset HC not bus */ -#define CMD_RUN (1<<0) /* start/stop HC */ -#define STS_PCD (1<<2) /* port change detect */ -#define FLAG_CF (1<<0) /* true: we'll support "high speed" */ - -#define PORT_OWNER (1<<13) /* true: companion hc owns this port */ -#define PORT_POWER (1<<12) /* true: has power (see PPC) */ -#define PORT_USB11(x) (((x) & (3 << 10)) == (1 << 10)) /* USB 1.1 device */ -#define PORT_RESET (1<<8) /* reset port */ -#define PORT_SUSPEND (1<<7) /* suspend port */ -#define PORT_RESUME (1<<6) /* resume it */ -#define PORT_PE (1<<2) /* port enable */ -#define PORT_CSC (1<<1) /* connect status change */ -#define PORT_CONNECT (1<<0) /* device connected */ -#define PORT_RWC_BITS (PORT_CSC) - -struct isp1760_qtd { - u8 packet_type; - void *data_buffer; - u32 payload_addr; - - /* the rest is HCD-private */ - struct list_head qtd_list; - struct urb *urb; - size_t length; - size_t actual_length; - - /* QTD_ENQUEUED: waiting for transfer (inactive) */ - /* QTD_PAYLOAD_ALLOC: chip mem has been allocated for payload */ - /* QTD_XFER_STARTED: valid ptd has been written to isp176x - only - interrupt handler may touch this qtd! */ - /* QTD_XFER_COMPLETE: payload has been transferred successfully */ - /* QTD_RETIRE: transfer error/abort qtd */ -#define QTD_ENQUEUED 0 -#define QTD_PAYLOAD_ALLOC 1 -#define QTD_XFER_STARTED 2 -#define QTD_XFER_COMPLETE 3 -#define QTD_RETIRE 4 - u32 status; -}; - -/* Queue head, one for each active endpoint */ -struct isp1760_qh { - struct list_head qh_list; - struct list_head qtd_list; - u32 toggle; - u32 ping; - int slot; - int tt_buffer_dirty; /* See USB2.0 spec section 11.17.5 */ -}; - -struct urb_listitem { - struct list_head urb_list; - struct urb *urb; -}; - -/* - * Access functions for isp176x registers (addresses 0..0x03FF). - */ -static u32 reg_read32(void __iomem *base, u32 reg) -{ - return readl(base + reg); -} - -static void reg_write32(void __iomem *base, u32 reg, u32 val) -{ - writel(val, base + reg); -} - -/* - * Access functions for isp176x memory (offset >= 0x0400). - * - * bank_reads8() reads memory locations prefetched by an earlier write to - * HC_MEMORY_REG (see isp176x datasheet). Unless you want to do fancy multi- - * bank optimizations, you should use the more generic mem_reads8() below. - * - * For access to ptd memory, use the specialized ptd_read() and ptd_write() - * below. - * - * These functions copy via MMIO data to/from the device. memcpy_{to|from}io() - * doesn't quite work because some people have to enforce 32-bit access - */ -static void bank_reads8(void __iomem *src_base, u32 src_offset, u32 bank_addr, - __u32 *dst, u32 bytes) -{ - __u32 __iomem *src; - u32 val; - __u8 *src_byteptr; - __u8 *dst_byteptr; - - src = src_base + (bank_addr | src_offset); - - if (src_offset < PAYLOAD_OFFSET) { - while (bytes >= 4) { - *dst = le32_to_cpu(__raw_readl(src)); - bytes -= 4; - src++; - dst++; - } - } else { - while (bytes >= 4) { - *dst = __raw_readl(src); - bytes -= 4; - src++; - dst++; - } - } - - if (!bytes) - return; - - /* in case we have 3, 2 or 1 by left. The dst buffer may not be fully - * allocated. - */ - if (src_offset < PAYLOAD_OFFSET) - val = le32_to_cpu(__raw_readl(src)); - else - val = __raw_readl(src); - - dst_byteptr = (void *) dst; - src_byteptr = (void *) &val; - while (bytes > 0) { - *dst_byteptr = *src_byteptr; - dst_byteptr++; - src_byteptr++; - bytes--; - } -} - -static void mem_reads8(void __iomem *src_base, u32 src_offset, void *dst, - u32 bytes) -{ - reg_write32(src_base, HC_MEMORY_REG, src_offset + ISP_BANK(0)); - ndelay(90); - bank_reads8(src_base, src_offset, ISP_BANK(0), dst, bytes); -} - -static void mem_writes8(void __iomem *dst_base, u32 dst_offset, - __u32 const *src, u32 bytes) -{ - __u32 __iomem *dst; - - dst = dst_base + dst_offset; - - if (dst_offset < PAYLOAD_OFFSET) { - while (bytes >= 4) { - __raw_writel(cpu_to_le32(*src), dst); - bytes -= 4; - src++; - dst++; - } - } else { - while (bytes >= 4) { - __raw_writel(*src, dst); - bytes -= 4; - src++; - dst++; - } - } - - if (!bytes) - return; - /* in case we have 3, 2 or 1 bytes left. The buffer is allocated and the - * extra bytes should not be read by the HW. - */ - - if (dst_offset < PAYLOAD_OFFSET) - __raw_writel(cpu_to_le32(*src), dst); - else - __raw_writel(*src, dst); -} - -/* - * Read and write ptds. 'ptd_offset' should be one of ISO_PTD_OFFSET, - * INT_PTD_OFFSET, and ATL_PTD_OFFSET. 'slot' should be less than 32. - */ -static void ptd_read(void __iomem *base, u32 ptd_offset, u32 slot, - struct ptd *ptd) -{ - reg_write32(base, HC_MEMORY_REG, - ISP_BANK(0) + ptd_offset + slot*sizeof(*ptd)); - ndelay(90); - bank_reads8(base, ptd_offset + slot*sizeof(*ptd), ISP_BANK(0), - (void *) ptd, sizeof(*ptd)); -} - -static void ptd_write(void __iomem *base, u32 ptd_offset, u32 slot, - struct ptd *ptd) -{ - mem_writes8(base, ptd_offset + slot*sizeof(*ptd) + sizeof(ptd->dw0), - &ptd->dw1, 7*sizeof(ptd->dw1)); - /* Make sure dw0 gets written last (after other dw's and after payload) - since it contains the enable bit */ - wmb(); - mem_writes8(base, ptd_offset + slot*sizeof(*ptd), &ptd->dw0, - sizeof(ptd->dw0)); -} - - -/* memory management of the 60kb on the chip from 0x1000 to 0xffff */ -static void init_memory(struct isp1760_hcd *priv) -{ - int i, curr; - u32 payload_addr; - - payload_addr = PAYLOAD_OFFSET; - for (i = 0; i < BLOCK_1_NUM; i++) { - priv->memory_pool[i].start = payload_addr; - priv->memory_pool[i].size = BLOCK_1_SIZE; - priv->memory_pool[i].free = 1; - payload_addr += priv->memory_pool[i].size; - } - - curr = i; - for (i = 0; i < BLOCK_2_NUM; i++) { - priv->memory_pool[curr + i].start = payload_addr; - priv->memory_pool[curr + i].size = BLOCK_2_SIZE; - priv->memory_pool[curr + i].free = 1; - payload_addr += priv->memory_pool[curr + i].size; - } - - curr = i; - for (i = 0; i < BLOCK_3_NUM; i++) { - priv->memory_pool[curr + i].start = payload_addr; - priv->memory_pool[curr + i].size = BLOCK_3_SIZE; - priv->memory_pool[curr + i].free = 1; - payload_addr += priv->memory_pool[curr + i].size; - } - - WARN_ON(payload_addr - priv->memory_pool[0].start > PAYLOAD_AREA_SIZE); -} - -static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd) -{ - struct isp1760_hcd *priv = hcd_to_priv(hcd); - int i; - - WARN_ON(qtd->payload_addr); - - if (!qtd->length) - return; - - for (i = 0; i < BLOCKS; i++) { - if (priv->memory_pool[i].size >= qtd->length && - priv->memory_pool[i].free) { - priv->memory_pool[i].free = 0; - qtd->payload_addr = priv->memory_pool[i].start; - return; - } - } -} - -static void free_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd) -{ - struct isp1760_hcd *priv = hcd_to_priv(hcd); - int i; - - if (!qtd->payload_addr) - return; - - for (i = 0; i < BLOCKS; i++) { - if (priv->memory_pool[i].start == qtd->payload_addr) { - WARN_ON(priv->memory_pool[i].free); - priv->memory_pool[i].free = 1; - qtd->payload_addr = 0; - return; - } - } - - dev_err(hcd->self.controller, "%s: Invalid pointer: %08x\n", - __func__, qtd->payload_addr); - WARN_ON(1); - qtd->payload_addr = 0; -} - -static int handshake(struct usb_hcd *hcd, u32 reg, - u32 mask, u32 done, int usec) -{ - u32 result; - - do { - result = reg_read32(hcd->regs, reg); - if (result == ~0) - return -ENODEV; - result &= mask; - if (result == done) - return 0; - udelay(1); - usec--; - } while (usec > 0); - return -ETIMEDOUT; -} - -/* reset a non-running (STS_HALT == 1) controller */ -static int ehci_reset(struct usb_hcd *hcd) -{ - int retval; - struct isp1760_hcd *priv = hcd_to_priv(hcd); - - u32 command = reg_read32(hcd->regs, HC_USBCMD); - - command |= CMD_RESET; - reg_write32(hcd->regs, HC_USBCMD, command); - hcd->state = HC_STATE_HALT; - priv->next_statechange = jiffies; - retval = handshake(hcd, HC_USBCMD, - CMD_RESET, 0, 250 * 1000); - return retval; -} - -static struct isp1760_qh *qh_alloc(gfp_t flags) -{ - struct isp1760_qh *qh; - - qh = kmem_cache_zalloc(qh_cachep, flags); - if (!qh) - return NULL; - - INIT_LIST_HEAD(&qh->qh_list); - INIT_LIST_HEAD(&qh->qtd_list); - qh->slot = -1; - - return qh; -} - -static void qh_free(struct isp1760_qh *qh) -{ - WARN_ON(!list_empty(&qh->qtd_list)); - WARN_ON(qh->slot > -1); - kmem_cache_free(qh_cachep, qh); -} - -/* one-time init, only for memory state */ -static int priv_init(struct usb_hcd *hcd) -{ - struct isp1760_hcd *priv = hcd_to_priv(hcd); - u32 hcc_params; - int i; - - spin_lock_init(&priv->lock); - - for (i = 0; i < QH_END; i++) - INIT_LIST_HEAD(&priv->qh_list[i]); - - /* - * hw default: 1K periodic list heads, one per frame. - * periodic_size can shrink by USBCMD update if hcc_params allows. - */ - priv->periodic_size = DEFAULT_I_TDPS; - - /* controllers may cache some of the periodic schedule ... */ - hcc_params = reg_read32(hcd->regs, HC_HCCPARAMS); - /* full frame cache */ - if (HCC_ISOC_CACHE(hcc_params)) - priv->i_thresh = 8; - else /* N microframes cached */ - priv->i_thresh = 2 + HCC_ISOC_THRES(hcc_params); - - return 0; -} - -static int isp1760_hc_setup(struct usb_hcd *hcd) -{ - struct isp1760_hcd *priv = hcd_to_priv(hcd); - int result; - u32 scratch, hwmode; - - /* low-level chip reset */ - if (gpio_is_valid(priv->rst_gpio)) { - unsigned int rst_lvl; - - rst_lvl = (priv->devflags & - ISP1760_FLAG_RESET_ACTIVE_HIGH) ? 1 : 0; - - gpio_set_value(priv->rst_gpio, rst_lvl); - mdelay(50); - gpio_set_value(priv->rst_gpio, !rst_lvl); - } - - /* Setup HW Mode Control: This assumes a level active-low interrupt */ - hwmode = HW_DATA_BUS_32BIT; - - if (priv->devflags & ISP1760_FLAG_BUS_WIDTH_16) - hwmode &= ~HW_DATA_BUS_32BIT; - if (priv->devflags & ISP1760_FLAG_ANALOG_OC) - hwmode |= HW_ANA_DIGI_OC; - if (priv->devflags & ISP1760_FLAG_DACK_POL_HIGH) - hwmode |= HW_DACK_POL_HIGH; - if (priv->devflags & ISP1760_FLAG_DREQ_POL_HIGH) - hwmode |= HW_DREQ_POL_HIGH; - if (priv->devflags & ISP1760_FLAG_INTR_POL_HIGH) - hwmode |= HW_INTR_HIGH_ACT; - if (priv->devflags & ISP1760_FLAG_INTR_EDGE_TRIG) - hwmode |= HW_INTR_EDGE_TRIG; - - /* - * We have to set this first in case we're in 16-bit mode. - * Write it twice to ensure correct upper bits if switching - * to 16-bit mode. - */ - reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode); - reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode); - - reg_write32(hcd->regs, HC_SCRATCH_REG, 0xdeadbabe); - /* Change bus pattern */ - scratch = reg_read32(hcd->regs, HC_CHIP_ID_REG); - scratch = reg_read32(hcd->regs, HC_SCRATCH_REG); - if (scratch != 0xdeadbabe) { - dev_err(hcd->self.controller, "Scratch test failed.\n"); - return -ENODEV; - } - - /* pre reset */ - reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, 0); - reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE); - reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE); - reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE); - - /* reset */ - reg_write32(hcd->regs, HC_RESET_REG, SW_RESET_RESET_ALL); - mdelay(100); - - reg_write32(hcd->regs, HC_RESET_REG, SW_RESET_RESET_HC); - mdelay(100); - - result = ehci_reset(hcd); - if (result) - return result; - - /* Step 11 passed */ - - dev_info(hcd->self.controller, "bus width: %d, oc: %s\n", - (priv->devflags & ISP1760_FLAG_BUS_WIDTH_16) ? - 16 : 32, (priv->devflags & ISP1760_FLAG_ANALOG_OC) ? - "analog" : "digital"); - - /* ATL reset */ - reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode | ALL_ATX_RESET); - mdelay(10); - reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode); - - reg_write32(hcd->regs, HC_INTERRUPT_ENABLE, INTERRUPT_ENABLE_MASK); - - /* - * PORT 1 Control register of the ISP1760 is the OTG control - * register on ISP1761. Since there is no OTG or device controller - * support in this driver, we use port 1 as a "normal" USB host port on - * both chips. - */ - reg_write32(hcd->regs, HC_PORT1_CTRL, PORT1_POWER | PORT1_INIT2); - mdelay(10); - - priv->hcs_params = reg_read32(hcd->regs, HC_HCSPARAMS); - - return priv_init(hcd); -} - -static u32 base_to_chip(u32 base) -{ - return ((base - 0x400) >> 3); -} - -static int last_qtd_of_urb(struct isp1760_qtd *qtd, struct isp1760_qh *qh) -{ - struct urb *urb; - - if (list_is_last(&qtd->qtd_list, &qh->qtd_list)) - return 1; - - urb = qtd->urb; - qtd = list_entry(qtd->qtd_list.next, typeof(*qtd), qtd_list); - return (qtd->urb != urb); -} - -/* magic numbers that can affect system performance */ -#define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */ -#define EHCI_TUNE_RL_HS 4 /* nak throttle; see 4.9 */ -#define EHCI_TUNE_RL_TT 0 -#define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */ -#define EHCI_TUNE_MULT_TT 1 -#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */ - -static void create_ptd_atl(struct isp1760_qh *qh, - struct isp1760_qtd *qtd, struct ptd *ptd) -{ - u32 maxpacket; - u32 multi; - u32 rl = RL_COUNTER; - u32 nak = NAK_COUNTER; - - memset(ptd, 0, sizeof(*ptd)); - - /* according to 3.6.2, max packet len can not be > 0x400 */ - maxpacket = usb_maxpacket(qtd->urb->dev, qtd->urb->pipe, - usb_pipeout(qtd->urb->pipe)); - multi = 1 + ((maxpacket >> 11) & 0x3); - maxpacket &= 0x7ff; - - /* DW0 */ - ptd->dw0 = DW0_VALID_BIT; - ptd->dw0 |= TO_DW0_LENGTH(qtd->length); - ptd->dw0 |= TO_DW0_MAXPACKET(maxpacket); - ptd->dw0 |= TO_DW0_ENDPOINT(usb_pipeendpoint(qtd->urb->pipe)); - - /* DW1 */ - ptd->dw1 = usb_pipeendpoint(qtd->urb->pipe) >> 1; - ptd->dw1 |= TO_DW1_DEVICE_ADDR(usb_pipedevice(qtd->urb->pipe)); - ptd->dw1 |= TO_DW1_PID_TOKEN(qtd->packet_type); - - if (usb_pipebulk(qtd->urb->pipe)) - ptd->dw1 |= DW1_TRANS_BULK; - else if (usb_pipeint(qtd->urb->pipe)) - ptd->dw1 |= DW1_TRANS_INT; - - if (qtd->urb->dev->speed != USB_SPEED_HIGH) { - /* split transaction */ - - ptd->dw1 |= DW1_TRANS_SPLIT; - if (qtd->urb->dev->speed == USB_SPEED_LOW) - ptd->dw1 |= DW1_SE_USB_LOSPEED; - - ptd->dw1 |= TO_DW1_PORT_NUM(qtd->urb->dev->ttport); - ptd->dw1 |= TO_DW1_HUB_NUM(qtd->urb->dev->tt->hub->devnum); - - /* SE bit for Split INT transfers */ - if (usb_pipeint(qtd->urb->pipe) && - (qtd->urb->dev->speed == USB_SPEED_LOW)) - ptd->dw1 |= 2 << 16; - - rl = 0; - nak = 0; - } else { - ptd->dw0 |= TO_DW0_MULTI(multi); - if (usb_pipecontrol(qtd->urb->pipe) || - usb_pipebulk(qtd->urb->pipe)) - ptd->dw3 |= TO_DW3_PING(qh->ping); - } - /* DW2 */ - ptd->dw2 = 0; - ptd->dw2 |= TO_DW2_DATA_START_ADDR(base_to_chip(qtd->payload_addr)); - ptd->dw2 |= TO_DW2_RL(rl); - - /* DW3 */ - ptd->dw3 |= TO_DW3_NAKCOUNT(nak); - ptd->dw3 |= TO_DW3_DATA_TOGGLE(qh->toggle); - if (usb_pipecontrol(qtd->urb->pipe)) { - if (qtd->data_buffer == qtd->urb->setup_packet) - ptd->dw3 &= ~TO_DW3_DATA_TOGGLE(1); - else if (last_qtd_of_urb(qtd, qh)) - ptd->dw3 |= TO_DW3_DATA_TOGGLE(1); - } - - ptd->dw3 |= DW3_ACTIVE_BIT; - /* Cerr */ - ptd->dw3 |= TO_DW3_CERR(ERR_COUNTER); -} - -static void transform_add_int(struct isp1760_qh *qh, - struct isp1760_qtd *qtd, struct ptd *ptd) -{ - u32 usof; - u32 period; - - /* - * Most of this is guessing. ISP1761 datasheet is quite unclear, and - * the algorithm from the original Philips driver code, which was - * pretty much used in this driver before as well, is quite horrendous - * and, i believe, incorrect. The code below follows the datasheet and - * USB2.0 spec as far as I can tell, and plug/unplug seems to be much - * more reliable this way (fingers crossed...). - */ - - if (qtd->urb->dev->speed == USB_SPEED_HIGH) { - /* urb->interval is in units of microframes (1/8 ms) */ - period = qtd->urb->interval >> 3; - - if (qtd->urb->interval > 4) - usof = 0x01; /* One bit set => - interval 1 ms * uFrame-match */ - else if (qtd->urb->interval > 2) - usof = 0x22; /* Two bits set => interval 1/2 ms */ - else if (qtd->urb->interval > 1) - usof = 0x55; /* Four bits set => interval 1/4 ms */ - else - usof = 0xff; /* All bits set => interval 1/8 ms */ - } else { - /* urb->interval is in units of frames (1 ms) */ - period = qtd->urb->interval; - usof = 0x0f; /* Execute Start Split on any of the - four first uFrames */ - - /* - * First 8 bits in dw5 is uSCS and "specifies which uSOF the - * complete split needs to be sent. Valid only for IN." Also, - * "All bits can be set to one for every transfer." (p 82, - * ISP1761 data sheet.) 0x1c is from Philips driver. Where did - * that number come from? 0xff seems to work fine... - */ - /* ptd->dw5 = 0x1c; */ - ptd->dw5 = 0xff; /* Execute Complete Split on any uFrame */ - } - - period = period >> 1;/* Ensure equal or shorter period than requested */ - period &= 0xf8; /* Mask off too large values and lowest unused 3 bits */ - - ptd->dw2 |= period; - ptd->dw4 = usof; -} - -static void create_ptd_int(struct isp1760_qh *qh, - struct isp1760_qtd *qtd, struct ptd *ptd) -{ - create_ptd_atl(qh, qtd, ptd); - transform_add_int(qh, qtd, ptd); -} - -static void isp1760_urb_done(struct usb_hcd *hcd, struct urb *urb) -__releases(priv->lock) -__acquires(priv->lock) -{ - struct isp1760_hcd *priv = hcd_to_priv(hcd); - - if (!urb->unlinked) { - if (urb->status == -EINPROGRESS) - urb->status = 0; - } - - if (usb_pipein(urb->pipe) && usb_pipetype(urb->pipe) != PIPE_CONTROL) { - void *ptr; - for (ptr = urb->transfer_buffer; - ptr < urb->transfer_buffer + urb->transfer_buffer_length; - ptr += PAGE_SIZE) - flush_dcache_page(virt_to_page(ptr)); - } - - /* complete() can reenter this HCD */ - usb_hcd_unlink_urb_from_ep(hcd, urb); - spin_unlock(&priv->lock); - usb_hcd_giveback_urb(hcd, urb, urb->status); - spin_lock(&priv->lock); -} - -static struct isp1760_qtd *qtd_alloc(gfp_t flags, struct urb *urb, - u8 packet_type) -{ - struct isp1760_qtd *qtd; - - qtd = kmem_cache_zalloc(qtd_cachep, flags); - if (!qtd) - return NULL; - - INIT_LIST_HEAD(&qtd->qtd_list); - qtd->urb = urb; - qtd->packet_type = packet_type; - qtd->status = QTD_ENQUEUED; - qtd->actual_length = 0; - - return qtd; -} - -static void qtd_free(struct isp1760_qtd *qtd) -{ - WARN_ON(qtd->payload_addr); - kmem_cache_free(qtd_cachep, qtd); -} - -static void start_bus_transfer(struct usb_hcd *hcd, u32 ptd_offset, int slot, - struct slotinfo *slots, struct isp1760_qtd *qtd, - struct isp1760_qh *qh, struct ptd *ptd) -{ - struct isp1760_hcd *priv = hcd_to_priv(hcd); - int skip_map; - - WARN_ON((slot < 0) || (slot > 31)); - WARN_ON(qtd->length && !qtd->payload_addr); - WARN_ON(slots[slot].qtd); - WARN_ON(slots[slot].qh); - WARN_ON(qtd->status != QTD_PAYLOAD_ALLOC); - - /* Make sure done map has not triggered from some unlinked transfer */ - if (ptd_offset == ATL_PTD_OFFSET) { - priv->atl_done_map |= reg_read32(hcd->regs, - HC_ATL_PTD_DONEMAP_REG); - priv->atl_done_map &= ~(1 << slot); - } else { - priv->int_done_map |= reg_read32(hcd->regs, - HC_INT_PTD_DONEMAP_REG); - priv->int_done_map &= ~(1 << slot); - } - - qh->slot = slot; - qtd->status = QTD_XFER_STARTED; - slots[slot].timestamp = jiffies; - slots[slot].qtd = qtd; - slots[slot].qh = qh; - ptd_write(hcd->regs, ptd_offset, slot, ptd); - - if (ptd_offset == ATL_PTD_OFFSET) { - skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG); - skip_map &= ~(1 << qh->slot); - reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map); - } else { - skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG); - skip_map &= ~(1 << qh->slot); - reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map); - } -} - -static int is_short_bulk(struct isp1760_qtd *qtd) -{ - return (usb_pipebulk(qtd->urb->pipe) && - (qtd->actual_length < qtd->length)); -} - -static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh, - struct list_head *urb_list) -{ - int last_qtd; - struct isp1760_qtd *qtd, *qtd_next; - struct urb_listitem *urb_listitem; - - list_for_each_entry_safe(qtd, qtd_next, &qh->qtd_list, qtd_list) { - if (qtd->status < QTD_XFER_COMPLETE) - break; - - last_qtd = last_qtd_of_urb(qtd, qh); - - if ((!last_qtd) && (qtd->status == QTD_RETIRE)) - qtd_next->status = QTD_RETIRE; - - if (qtd->status == QTD_XFER_COMPLETE) { - if (qtd->actual_length) { - switch (qtd->packet_type) { - case IN_PID: - mem_reads8(hcd->regs, qtd->payload_addr, - qtd->data_buffer, - qtd->actual_length); - /* Fall through (?) */ - case OUT_PID: - qtd->urb->actual_length += - qtd->actual_length; - /* Fall through ... */ - case SETUP_PID: - break; - } - } - - if (is_short_bulk(qtd)) { - if (qtd->urb->transfer_flags & URB_SHORT_NOT_OK) - qtd->urb->status = -EREMOTEIO; - if (!last_qtd) - qtd_next->status = QTD_RETIRE; - } - } - - if (qtd->payload_addr) - free_mem(hcd, qtd); - - if (last_qtd) { - if ((qtd->status == QTD_RETIRE) && - (qtd->urb->status == -EINPROGRESS)) - qtd->urb->status = -EPIPE; - /* Defer calling of urb_done() since it releases lock */ - urb_listitem = kmem_cache_zalloc(urb_listitem_cachep, - GFP_ATOMIC); - if (unlikely(!urb_listitem)) - break; /* Try again on next call */ - urb_listitem->urb = qtd->urb; - list_add_tail(&urb_listitem->urb_list, urb_list); - } - - list_del(&qtd->qtd_list); - qtd_free(qtd); - } -} - -#define ENQUEUE_DEPTH 2 -static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh) -{ - struct isp1760_hcd *priv = hcd_to_priv(hcd); - int ptd_offset; - struct slotinfo *slots; - int curr_slot, free_slot; - int n; - struct ptd ptd; - struct isp1760_qtd *qtd; - - if (unlikely(list_empty(&qh->qtd_list))) { - WARN_ON(1); - return; - } - - /* Make sure this endpoint's TT buffer is clean before queueing ptds */ - if (qh->tt_buffer_dirty) - return; - - if (usb_pipeint(list_entry(qh->qtd_list.next, struct isp1760_qtd, - qtd_list)->urb->pipe)) { - ptd_offset = INT_PTD_OFFSET; - slots = priv->int_slots; - } else { - ptd_offset = ATL_PTD_OFFSET; - slots = priv->atl_slots; - } - - free_slot = -1; - for (curr_slot = 0; curr_slot < 32; curr_slot++) { - if ((free_slot == -1) && (slots[curr_slot].qtd == NULL)) - free_slot = curr_slot; - if (slots[curr_slot].qh == qh) - break; - } - - n = 0; - list_for_each_entry(qtd, &qh->qtd_list, qtd_list) { - if (qtd->status == QTD_ENQUEUED) { - WARN_ON(qtd->payload_addr); - alloc_mem(hcd, qtd); - if ((qtd->length) && (!qtd->payload_addr)) - break; - - if ((qtd->length) && - ((qtd->packet_type == SETUP_PID) || - (qtd->packet_type == OUT_PID))) { - mem_writes8(hcd->regs, qtd->payload_addr, - qtd->data_buffer, qtd->length); - } - - qtd->status = QTD_PAYLOAD_ALLOC; - } - - if (qtd->status == QTD_PAYLOAD_ALLOC) { -/* - if ((curr_slot > 31) && (free_slot == -1)) - dev_dbg(hcd->self.controller, "%s: No slot " - "available for transfer\n", __func__); -*/ - /* Start xfer for this endpoint if not already done */ - if ((curr_slot > 31) && (free_slot > -1)) { - if (usb_pipeint(qtd->urb->pipe)) - create_ptd_int(qh, qtd, &ptd); - else - create_ptd_atl(qh, qtd, &ptd); - - start_bus_transfer(hcd, ptd_offset, free_slot, - slots, qtd, qh, &ptd); - curr_slot = free_slot; - } - - n++; - if (n >= ENQUEUE_DEPTH) - break; - } - } -} - -void schedule_ptds(struct usb_hcd *hcd) -{ - struct isp1760_hcd *priv; - struct isp1760_qh *qh, *qh_next; - struct list_head *ep_queue; - LIST_HEAD(urb_list); - struct urb_listitem *urb_listitem, *urb_listitem_next; - int i; - - if (!hcd) { - WARN_ON(1); - return; - } - - priv = hcd_to_priv(hcd); - - /* - * check finished/retired xfers, transfer payloads, call urb_done() - */ - for (i = 0; i < QH_END; i++) { - ep_queue = &priv->qh_list[i]; - list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list) { - collect_qtds(hcd, qh, &urb_list); - if (list_empty(&qh->qtd_list)) - list_del(&qh->qh_list); - } - } - - list_for_each_entry_safe(urb_listitem, urb_listitem_next, &urb_list, - urb_list) { - isp1760_urb_done(hcd, urb_listitem->urb); - kmem_cache_free(urb_listitem_cachep, urb_listitem); - } - - /* - * Schedule packets for transfer. - * - * According to USB2.0 specification: - * - * 1st prio: interrupt xfers, up to 80 % of bandwidth - * 2nd prio: control xfers - * 3rd prio: bulk xfers - * - * ... but let's use a simpler scheme here (mostly because ISP1761 doc - * is very unclear on how to prioritize traffic): - * - * 1) Enqueue any queued control transfers, as long as payload chip mem - * and PTD ATL slots are available. - * 2) Enqueue any queued INT transfers, as long as payload chip mem - * and PTD INT slots are available. - * 3) Enqueue any queued bulk transfers, as long as payload chip mem - * and PTD ATL slots are available. - * - * Use double buffering (ENQUEUE_DEPTH==2) as a compromise between - * conservation of chip mem and performance. - * - * I'm sure this scheme could be improved upon! - */ - for (i = 0; i < QH_END; i++) { - ep_queue = &priv->qh_list[i]; - list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list) - enqueue_qtds(hcd, qh); - } -} - -#define PTD_STATE_QTD_DONE 1 -#define PTD_STATE_QTD_RELOAD 2 -#define PTD_STATE_URB_RETIRE 3 - -static int check_int_transfer(struct usb_hcd *hcd, struct ptd *ptd, - struct urb *urb) -{ - __dw dw4; - int i; - - dw4 = ptd->dw4; - dw4 >>= 8; - - /* FIXME: ISP1761 datasheet does not say what to do with these. Do we - need to handle these errors? Is it done in hardware? */ - - if (ptd->dw3 & DW3_HALT_BIT) { - - urb->status = -EPROTO; /* Default unknown error */ - - for (i = 0; i < 8; i++) { - switch (dw4 & 0x7) { - case INT_UNDERRUN: - dev_dbg(hcd->self.controller, "%s: underrun " - "during uFrame %d\n", - __func__, i); - urb->status = -ECOMM; /* Could not write data */ - break; - case INT_EXACT: - dev_dbg(hcd->self.controller, "%s: transaction " - "error during uFrame %d\n", - __func__, i); - urb->status = -EPROTO; /* timeout, bad CRC, PID - error etc. */ - break; - case INT_BABBLE: - dev_dbg(hcd->self.controller, "%s: babble " - "error during uFrame %d\n", - __func__, i); - urb->status = -EOVERFLOW; - break; - } - dw4 >>= 3; - } - - return PTD_STATE_URB_RETIRE; - } - - return PTD_STATE_QTD_DONE; -} - -static int check_atl_transfer(struct usb_hcd *hcd, struct ptd *ptd, - struct urb *urb) -{ - WARN_ON(!ptd); - if (ptd->dw3 & DW3_HALT_BIT) { - if (ptd->dw3 & DW3_BABBLE_BIT) - urb->status = -EOVERFLOW; - else if (FROM_DW3_CERR(ptd->dw3)) - urb->status = -EPIPE; /* Stall */ - else if (ptd->dw3 & DW3_ERROR_BIT) - urb->status = -EPROTO; /* XactErr */ - else - urb->status = -EPROTO; /* Unknown */ -/* - dev_dbg(hcd->self.controller, "%s: ptd error:\n" - " dw0: %08x dw1: %08x dw2: %08x dw3: %08x\n" - " dw4: %08x dw5: %08x dw6: %08x dw7: %08x\n", - __func__, - ptd->dw0, ptd->dw1, ptd->dw2, ptd->dw3, - ptd->dw4, ptd->dw5, ptd->dw6, ptd->dw7); -*/ - return PTD_STATE_URB_RETIRE; - } - - if ((ptd->dw3 & DW3_ERROR_BIT) && (ptd->dw3 & DW3_ACTIVE_BIT)) { - /* Transfer Error, *but* active and no HALT -> reload */ - dev_dbg(hcd->self.controller, "PID error; reloading ptd\n"); - return PTD_STATE_QTD_RELOAD; - } - - if (!FROM_DW3_NAKCOUNT(ptd->dw3) && (ptd->dw3 & DW3_ACTIVE_BIT)) { - /* - * NAKs are handled in HW by the chip. Usually if the - * device is not able to send data fast enough. - * This happens mostly on slower hardware. - */ - return PTD_STATE_QTD_RELOAD; - } - - return PTD_STATE_QTD_DONE; -} - -static void handle_done_ptds(struct usb_hcd *hcd) -{ - struct isp1760_hcd *priv = hcd_to_priv(hcd); - struct ptd ptd; - struct isp1760_qh *qh; - int slot; - int state; - struct slotinfo *slots; - u32 ptd_offset; - struct isp1760_qtd *qtd; - int modified; - int skip_map; - - skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG); - priv->int_done_map &= ~skip_map; - skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG); - priv->atl_done_map &= ~skip_map; - - modified = priv->int_done_map || priv->atl_done_map; - - while (priv->int_done_map || priv->atl_done_map) { - if (priv->int_done_map) { - /* INT ptd */ - slot = __ffs(priv->int_done_map); - priv->int_done_map &= ~(1 << slot); - slots = priv->int_slots; - /* This should not trigger, and could be removed if - noone have any problems with it triggering: */ - if (!slots[slot].qh) { - WARN_ON(1); - continue; - } - ptd_offset = INT_PTD_OFFSET; - ptd_read(hcd->regs, INT_PTD_OFFSET, slot, &ptd); - state = check_int_transfer(hcd, &ptd, - slots[slot].qtd->urb); - } else { - /* ATL ptd */ - slot = __ffs(priv->atl_done_map); - priv->atl_done_map &= ~(1 << slot); - slots = priv->atl_slots; - /* This should not trigger, and could be removed if - noone have any problems with it triggering: */ - if (!slots[slot].qh) { - WARN_ON(1); - continue; - } - ptd_offset = ATL_PTD_OFFSET; - ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd); - state = check_atl_transfer(hcd, &ptd, - slots[slot].qtd->urb); - } - - qtd = slots[slot].qtd; - slots[slot].qtd = NULL; - qh = slots[slot].qh; - slots[slot].qh = NULL; - qh->slot = -1; - - WARN_ON(qtd->status != QTD_XFER_STARTED); - - switch (state) { - case PTD_STATE_QTD_DONE: - if ((usb_pipeint(qtd->urb->pipe)) && - (qtd->urb->dev->speed != USB_SPEED_HIGH)) - qtd->actual_length = - FROM_DW3_SCS_NRBYTESTRANSFERRED(ptd.dw3); - else - qtd->actual_length = - FROM_DW3_NRBYTESTRANSFERRED(ptd.dw3); - - qtd->status = QTD_XFER_COMPLETE; - if (list_is_last(&qtd->qtd_list, &qh->qtd_list) || - is_short_bulk(qtd)) - qtd = NULL; - else - qtd = list_entry(qtd->qtd_list.next, - typeof(*qtd), qtd_list); - - qh->toggle = FROM_DW3_DATA_TOGGLE(ptd.dw3); - qh->ping = FROM_DW3_PING(ptd.dw3); - break; - - case PTD_STATE_QTD_RELOAD: /* QTD_RETRY, for atls only */ - qtd->status = QTD_PAYLOAD_ALLOC; - ptd.dw0 |= DW0_VALID_BIT; - /* RL counter = ERR counter */ - ptd.dw3 &= ~TO_DW3_NAKCOUNT(0xf); - ptd.dw3 |= TO_DW3_NAKCOUNT(FROM_DW2_RL(ptd.dw2)); - ptd.dw3 &= ~TO_DW3_CERR(3); - ptd.dw3 |= TO_DW3_CERR(ERR_COUNTER); - qh->toggle = FROM_DW3_DATA_TOGGLE(ptd.dw3); - qh->ping = FROM_DW3_PING(ptd.dw3); - break; - - case PTD_STATE_URB_RETIRE: - qtd->status = QTD_RETIRE; - if ((qtd->urb->dev->speed != USB_SPEED_HIGH) && - (qtd->urb->status != -EPIPE) && - (qtd->urb->status != -EREMOTEIO)) { - qh->tt_buffer_dirty = 1; - if (usb_hub_clear_tt_buffer(qtd->urb)) - /* Clear failed; let's hope things work - anyway */ - qh->tt_buffer_dirty = 0; - } - qtd = NULL; - qh->toggle = 0; - qh->ping = 0; - break; - - default: - WARN_ON(1); - continue; - } - - if (qtd && (qtd->status == QTD_PAYLOAD_ALLOC)) { - if (slots == priv->int_slots) { - if (state == PTD_STATE_QTD_RELOAD) - dev_err(hcd->self.controller, - "%s: PTD_STATE_QTD_RELOAD on " - "interrupt packet\n", __func__); - if (state != PTD_STATE_QTD_RELOAD) - create_ptd_int(qh, qtd, &ptd); - } else { - if (state != PTD_STATE_QTD_RELOAD) - create_ptd_atl(qh, qtd, &ptd); - } - - start_bus_transfer(hcd, ptd_offset, slot, slots, qtd, - qh, &ptd); - } - } - - if (modified) - schedule_ptds(hcd); -} - -static irqreturn_t isp1760_irq(struct usb_hcd *hcd) -{ - struct isp1760_hcd *priv = hcd_to_priv(hcd); - u32 imask; - irqreturn_t irqret = IRQ_NONE; - - spin_lock(&priv->lock); - - if (!(hcd->state & HC_STATE_RUNNING)) - goto leave; - - imask = reg_read32(hcd->regs, HC_INTERRUPT_REG); - if (unlikely(!imask)) - goto leave; - reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); /* Clear */ - - priv->int_done_map |= reg_read32(hcd->regs, HC_INT_PTD_DONEMAP_REG); - priv->atl_done_map |= reg_read32(hcd->regs, HC_ATL_PTD_DONEMAP_REG); - - handle_done_ptds(hcd); - - irqret = IRQ_HANDLED; -leave: - spin_unlock(&priv->lock); - - return irqret; -} - -/* - * Workaround for problem described in chip errata 2: - * - * Sometimes interrupts are not generated when ATL (not INT?) completion occurs. - * One solution suggested in the errata is to use SOF interrupts _instead_of_ - * ATL done interrupts (the "instead of" might be important since it seems - * enabling ATL interrupts also causes the chip to sometimes - rarely - "forget" - * to set the PTD's done bit in addition to not generating an interrupt!). - * - * So if we use SOF + ATL interrupts, we sometimes get stale PTDs since their - * done bit is not being set. This is bad - it blocks the endpoint until reboot. - * - * If we use SOF interrupts only, we get latency between ptd completion and the - * actual handling. This is very noticeable in testusb runs which takes several - * minutes longer without ATL interrupts. - * - * A better solution is to run the code below every SLOT_CHECK_PERIOD ms. If it - * finds active ATL slots which are older than SLOT_TIMEOUT ms, it checks the - * slot's ACTIVE and VALID bits. If these are not set, the ptd is considered - * completed and its done map bit is set. - * - * The values of SLOT_TIMEOUT and SLOT_CHECK_PERIOD have been arbitrarily chosen - * not to cause too much lag when this HW bug occurs, while still hopefully - * ensuring that the check does not falsely trigger. - */ -#define SLOT_TIMEOUT 300 -#define SLOT_CHECK_PERIOD 200 -static struct timer_list errata2_timer; - -void errata2_function(unsigned long data) -{ - struct usb_hcd *hcd = (struct usb_hcd *) data; - struct isp1760_hcd *priv = hcd_to_priv(hcd); - int slot; - struct ptd ptd; - unsigned long spinflags; - - spin_lock_irqsave(&priv->lock, spinflags); - - for (slot = 0; slot < 32; slot++) - if (priv->atl_slots[slot].qh && time_after(jiffies, - priv->atl_slots[slot].timestamp + - SLOT_TIMEOUT * HZ / 1000)) { - ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd); - if (!FROM_DW0_VALID(ptd.dw0) && - !FROM_DW3_ACTIVE(ptd.dw3)) - priv->atl_done_map |= 1 << slot; - } - - if (priv->atl_done_map) - handle_done_ptds(hcd); - - spin_unlock_irqrestore(&priv->lock, spinflags); - - errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000; - add_timer(&errata2_timer); -} - -static int isp1760_run(struct usb_hcd *hcd) -{ - int retval; - u32 temp; - u32 command; - u32 chipid; - - hcd->uses_new_polling = 1; - - hcd->state = HC_STATE_RUNNING; - - /* Set PTD interrupt AND & OR maps */ - reg_write32(hcd->regs, HC_ATL_IRQ_MASK_AND_REG, 0); - reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, 0xffffffff); - reg_write32(hcd->regs, HC_INT_IRQ_MASK_AND_REG, 0); - reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, 0xffffffff); - reg_write32(hcd->regs, HC_ISO_IRQ_MASK_AND_REG, 0); - reg_write32(hcd->regs, HC_ISO_IRQ_MASK_OR_REG, 0xffffffff); - /* step 23 passed */ - - temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL); - reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp | HW_GLOBAL_INTR_EN); - - command = reg_read32(hcd->regs, HC_USBCMD); - command &= ~(CMD_LRESET|CMD_RESET); - command |= CMD_RUN; - reg_write32(hcd->regs, HC_USBCMD, command); - - retval = handshake(hcd, HC_USBCMD, CMD_RUN, CMD_RUN, 250 * 1000); - if (retval) - return retval; - - /* - * XXX - * Spec says to write FLAG_CF as last config action, priv code grabs - * the semaphore while doing so. - */ - down_write(&ehci_cf_port_reset_rwsem); - reg_write32(hcd->regs, HC_CONFIGFLAG, FLAG_CF); - - retval = handshake(hcd, HC_CONFIGFLAG, FLAG_CF, FLAG_CF, 250 * 1000); - up_write(&ehci_cf_port_reset_rwsem); - if (retval) - return retval; - - init_timer(&errata2_timer); - errata2_timer.function = errata2_function; - errata2_timer.data = (unsigned long) hcd; - errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000; - add_timer(&errata2_timer); - - chipid = reg_read32(hcd->regs, HC_CHIP_ID_REG); - dev_info(hcd->self.controller, "USB ISP %04x HW rev. %d started\n", - chipid & 0xffff, chipid >> 16); - - /* PTD Register Init Part 2, Step 28 */ - - /* Setup registers controlling PTD checking */ - reg_write32(hcd->regs, HC_ATL_PTD_LASTPTD_REG, 0x80000000); - reg_write32(hcd->regs, HC_INT_PTD_LASTPTD_REG, 0x80000000); - reg_write32(hcd->regs, HC_ISO_PTD_LASTPTD_REG, 0x00000001); - reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, 0xffffffff); - reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, 0xffffffff); - reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, 0xffffffff); - reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, - ATL_BUF_FILL | INT_BUF_FILL); - - /* GRR this is run-once init(), being done every time the HC starts. - * So long as they're part of class devices, we can't do it init() - * since the class device isn't created that early. - */ - return 0; -} - -static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len) -{ - qtd->data_buffer = databuffer; - - if (len > MAX_PAYLOAD_SIZE) - len = MAX_PAYLOAD_SIZE; - qtd->length = len; - - return qtd->length; -} - -static void qtd_list_free(struct list_head *qtd_list) -{ - struct isp1760_qtd *qtd, *qtd_next; - - list_for_each_entry_safe(qtd, qtd_next, qtd_list, qtd_list) { - list_del(&qtd->qtd_list); - qtd_free(qtd); - } -} - -/* - * Packetize urb->transfer_buffer into list of packets of size wMaxPacketSize. - * Also calculate the PID type (SETUP/IN/OUT) for each packet. - */ -#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff) -static void packetize_urb(struct usb_hcd *hcd, - struct urb *urb, struct list_head *head, gfp_t flags) -{ - struct isp1760_qtd *qtd; - void *buf; - int len, maxpacketsize; - u8 packet_type; - - /* - * URBs map to sequences of QTDs: one logical transaction - */ - - if (!urb->transfer_buffer && urb->transfer_buffer_length) { - /* XXX This looks like usb storage / SCSI bug */ - dev_err(hcd->self.controller, - "buf is null, dma is %08lx len is %d\n", - (long unsigned)urb->transfer_dma, - urb->transfer_buffer_length); - WARN_ON(1); - } - - if (usb_pipein(urb->pipe)) - packet_type = IN_PID; - else - packet_type = OUT_PID; - - if (usb_pipecontrol(urb->pipe)) { - qtd = qtd_alloc(flags, urb, SETUP_PID); - if (!qtd) - goto cleanup; - qtd_fill(qtd, urb->setup_packet, sizeof(struct usb_ctrlrequest)); - list_add_tail(&qtd->qtd_list, head); - - /* for zero length DATA stages, STATUS is always IN */ - if (urb->transfer_buffer_length == 0) - packet_type = IN_PID; - } - - maxpacketsize = max_packet(usb_maxpacket(urb->dev, urb->pipe, - usb_pipeout(urb->pipe))); - - /* - * buffer gets wrapped in one or more qtds; - * last one may be "short" (including zero len) - * and may serve as a control status ack - */ - buf = urb->transfer_buffer; - len = urb->transfer_buffer_length; - - for (;;) { - int this_qtd_len; - - qtd = qtd_alloc(flags, urb, packet_type); - if (!qtd) - goto cleanup; - this_qtd_len = qtd_fill(qtd, buf, len); - list_add_tail(&qtd->qtd_list, head); - - len -= this_qtd_len; - buf += this_qtd_len; - - if (len <= 0) - break; - } - - /* - * control requests may need a terminating data "status" ack; - * bulk ones may need a terminating short packet (zero length). - */ - if (urb->transfer_buffer_length != 0) { - int one_more = 0; - - if (usb_pipecontrol(urb->pipe)) { - one_more = 1; - if (packet_type == IN_PID) - packet_type = OUT_PID; - else - packet_type = IN_PID; - } else if (usb_pipebulk(urb->pipe) - && (urb->transfer_flags & URB_ZERO_PACKET) - && !(urb->transfer_buffer_length % - maxpacketsize)) { - one_more = 1; - } - if (one_more) { - qtd = qtd_alloc(flags, urb, packet_type); - if (!qtd) - goto cleanup; - - /* never any data in such packets */ - qtd_fill(qtd, NULL, 0); - list_add_tail(&qtd->qtd_list, head); - } - } - - return; - -cleanup: - qtd_list_free(head); -} - -static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, - gfp_t mem_flags) -{ - struct isp1760_hcd *priv = hcd_to_priv(hcd); - struct list_head *ep_queue; - struct isp1760_qh *qh, *qhit; - unsigned long spinflags; - LIST_HEAD(new_qtds); - int retval; - int qh_in_queue; - - switch (usb_pipetype(urb->pipe)) { - case PIPE_CONTROL: - ep_queue = &priv->qh_list[QH_CONTROL]; - break; - case PIPE_BULK: - ep_queue = &priv->qh_list[QH_BULK]; - break; - case PIPE_INTERRUPT: - if (urb->interval < 0) - return -EINVAL; - /* FIXME: Check bandwidth */ - ep_queue = &priv->qh_list[QH_INTERRUPT]; - break; - case PIPE_ISOCHRONOUS: - dev_err(hcd->self.controller, "%s: isochronous USB packets " - "not yet supported\n", - __func__); - return -EPIPE; - default: - dev_err(hcd->self.controller, "%s: unknown pipe type\n", - __func__); - return -EPIPE; - } - - if (usb_pipein(urb->pipe)) - urb->actual_length = 0; - - packetize_urb(hcd, urb, &new_qtds, mem_flags); - if (list_empty(&new_qtds)) - return -ENOMEM; - - retval = 0; - spin_lock_irqsave(&priv->lock, spinflags); - - if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { - retval = -ESHUTDOWN; - goto out; - } - retval = usb_hcd_link_urb_to_ep(hcd, urb); - if (retval) - goto out; - - qh = urb->ep->hcpriv; - if (qh) { - qh_in_queue = 0; - list_for_each_entry(qhit, ep_queue, qh_list) { - if (qhit == qh) { - qh_in_queue = 1; - break; - } - } - if (!qh_in_queue) - list_add_tail(&qh->qh_list, ep_queue); - } else { - qh = qh_alloc(GFP_ATOMIC); - if (!qh) { - retval = -ENOMEM; - usb_hcd_unlink_urb_from_ep(hcd, urb); - goto out; - } - list_add_tail(&qh->qh_list, ep_queue); - urb->ep->hcpriv = qh; - } - - list_splice_tail(&new_qtds, &qh->qtd_list); - schedule_ptds(hcd); - -out: - spin_unlock_irqrestore(&priv->lock, spinflags); - return retval; -} - -static void kill_transfer(struct usb_hcd *hcd, struct urb *urb, - struct isp1760_qh *qh) -{ - struct isp1760_hcd *priv = hcd_to_priv(hcd); - int skip_map; - - WARN_ON(qh->slot == -1); - - /* We need to forcefully reclaim the slot since some transfers never - return, e.g. interrupt transfers and NAKed bulk transfers. */ - if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe)) { - skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG); - skip_map |= (1 << qh->slot); - reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map); - priv->atl_slots[qh->slot].qh = NULL; - priv->atl_slots[qh->slot].qtd = NULL; - } else { - skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG); - skip_map |= (1 << qh->slot); - reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map); - priv->int_slots[qh->slot].qh = NULL; - priv->int_slots[qh->slot].qtd = NULL; - } - - qh->slot = -1; -} - -/* - * Retire the qtds beginning at 'qtd' and belonging all to the same urb, killing - * any active transfer belonging to the urb in the process. - */ -static void dequeue_urb_from_qtd(struct usb_hcd *hcd, struct isp1760_qh *qh, - struct isp1760_qtd *qtd) -{ - struct urb *urb; - int urb_was_running; - - urb = qtd->urb; - urb_was_running = 0; - list_for_each_entry_from(qtd, &qh->qtd_list, qtd_list) { - if (qtd->urb != urb) - break; - - if (qtd->status >= QTD_XFER_STARTED) - urb_was_running = 1; - if (last_qtd_of_urb(qtd, qh) && - (qtd->status >= QTD_XFER_COMPLETE)) - urb_was_running = 0; - - if (qtd->status == QTD_XFER_STARTED) - kill_transfer(hcd, urb, qh); - qtd->status = QTD_RETIRE; - } - - if ((urb->dev->speed != USB_SPEED_HIGH) && urb_was_running) { - qh->tt_buffer_dirty = 1; - if (usb_hub_clear_tt_buffer(urb)) - /* Clear failed; let's hope things work anyway */ - qh->tt_buffer_dirty = 0; - } -} - -static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, - int status) -{ - struct isp1760_hcd *priv = hcd_to_priv(hcd); - unsigned long spinflags; - struct isp1760_qh *qh; - struct isp1760_qtd *qtd; - int retval = 0; - - spin_lock_irqsave(&priv->lock, spinflags); - retval = usb_hcd_check_unlink_urb(hcd, urb, status); - if (retval) - goto out; - - qh = urb->ep->hcpriv; - if (!qh) { - retval = -EINVAL; - goto out; - } - - list_for_each_entry(qtd, &qh->qtd_list, qtd_list) - if (qtd->urb == urb) { - dequeue_urb_from_qtd(hcd, qh, qtd); - break; - } - - urb->status = status; - schedule_ptds(hcd); - -out: - spin_unlock_irqrestore(&priv->lock, spinflags); - return retval; -} - -static void isp1760_endpoint_disable(struct usb_hcd *hcd, - struct usb_host_endpoint *ep) -{ - struct isp1760_hcd *priv = hcd_to_priv(hcd); - unsigned long spinflags; - struct isp1760_qh *qh, *qh_iter; - int i; - - spin_lock_irqsave(&priv->lock, spinflags); - - qh = ep->hcpriv; - if (!qh) - goto out; - - WARN_ON(!list_empty(&qh->qtd_list)); - - for (i = 0; i < QH_END; i++) - list_for_each_entry(qh_iter, &priv->qh_list[i], qh_list) - if (qh_iter == qh) { - list_del(&qh_iter->qh_list); - i = QH_END; - break; - } - qh_free(qh); - ep->hcpriv = NULL; - - schedule_ptds(hcd); - -out: - spin_unlock_irqrestore(&priv->lock, spinflags); -} - -static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf) -{ - struct isp1760_hcd *priv = hcd_to_priv(hcd); - u32 temp, status = 0; - u32 mask; - int retval = 1; - unsigned long flags; - - /* if !USB_SUSPEND, root hub timers won't get shut down ... */ - if (!HC_IS_RUNNING(hcd->state)) - return 0; - - /* init status to no-changes */ - buf[0] = 0; - mask = PORT_CSC; - - spin_lock_irqsave(&priv->lock, flags); - temp = reg_read32(hcd->regs, HC_PORTSC1); - - if (temp & PORT_OWNER) { - if (temp & PORT_CSC) { - temp &= ~PORT_CSC; - reg_write32(hcd->regs, HC_PORTSC1, temp); - goto done; - } - } - - /* - * Return status information even for ports with OWNER set. - * Otherwise khubd wouldn't see the disconnect event when a - * high-speed device is switched over to the companion - * controller by the user. - */ - - if ((temp & mask) != 0 - || ((temp & PORT_RESUME) != 0 - && time_after_eq(jiffies, - priv->reset_done))) { - buf [0] |= 1 << (0 + 1); - status = STS_PCD; - } - /* FIXME autosuspend idle root hubs */ -done: - spin_unlock_irqrestore(&priv->lock, flags); - return status ? retval : 0; -} - -static void isp1760_hub_descriptor(struct isp1760_hcd *priv, - struct usb_hub_descriptor *desc) -{ - int ports = HCS_N_PORTS(priv->hcs_params); - u16 temp; - - desc->bDescriptorType = 0x29; - /* priv 1.0, 2.3.9 says 20ms max */ - desc->bPwrOn2PwrGood = 10; - desc->bHubContrCurrent = 0; - - desc->bNbrPorts = ports; - temp = 1 + (ports / 8); - desc->bDescLength = 7 + 2 * temp; - - /* ports removable, and usb 1.0 legacy PortPwrCtrlMask */ - memset(&desc->u.hs.DeviceRemovable[0], 0, temp); - memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp); - - /* per-port overcurrent reporting */ - temp = 0x0008; - if (HCS_PPC(priv->hcs_params)) - /* per-port power control */ - temp |= 0x0001; - else - /* no power switching */ - temp |= 0x0002; - desc->wHubCharacteristics = cpu_to_le16(temp); -} - -#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E) - -static int check_reset_complete(struct usb_hcd *hcd, int index, - int port_status) -{ - if (!(port_status & PORT_CONNECT)) - return port_status; - - /* if reset finished and it's still not enabled -- handoff */ - if (!(port_status & PORT_PE)) { - - dev_info(hcd->self.controller, - "port %d full speed --> companion\n", - index + 1); - - port_status |= PORT_OWNER; - port_status &= ~PORT_RWC_BITS; - reg_write32(hcd->regs, HC_PORTSC1, port_status); - - } else - dev_info(hcd->self.controller, "port %d high speed\n", - index + 1); - - return port_status; -} - -static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq, - u16 wValue, u16 wIndex, char *buf, u16 wLength) -{ - struct isp1760_hcd *priv = hcd_to_priv(hcd); - int ports = HCS_N_PORTS(priv->hcs_params); - u32 temp, status; - unsigned long flags; - int retval = 0; - unsigned selector; - - /* - * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR. - * HCS_INDICATOR may say we can change LEDs to off/amber/green. - * (track current state ourselves) ... blink for diagnostics, - * power, "this is the one", etc. EHCI spec supports this. - */ - - spin_lock_irqsave(&priv->lock, flags); - switch (typeReq) { - case ClearHubFeature: - switch (wValue) { - case C_HUB_LOCAL_POWER: - case C_HUB_OVER_CURRENT: - /* no hub-wide feature/status flags */ - break; - default: - goto error; - } - break; - case ClearPortFeature: - if (!wIndex || wIndex > ports) - goto error; - wIndex--; - temp = reg_read32(hcd->regs, HC_PORTSC1); - - /* - * Even if OWNER is set, so the port is owned by the - * companion controller, khubd needs to be able to clear - * the port-change status bits (especially - * USB_PORT_STAT_C_CONNECTION). - */ - - switch (wValue) { - case USB_PORT_FEAT_ENABLE: - reg_write32(hcd->regs, HC_PORTSC1, temp & ~PORT_PE); - break; - case USB_PORT_FEAT_C_ENABLE: - /* XXX error? */ - break; - case USB_PORT_FEAT_SUSPEND: - if (temp & PORT_RESET) - goto error; - - if (temp & PORT_SUSPEND) { - if ((temp & PORT_PE) == 0) - goto error; - /* resume signaling for 20 msec */ - temp &= ~(PORT_RWC_BITS); - reg_write32(hcd->regs, HC_PORTSC1, - temp | PORT_RESUME); - priv->reset_done = jiffies + - msecs_to_jiffies(20); - } - break; - case USB_PORT_FEAT_C_SUSPEND: - /* we auto-clear this feature */ - break; - case USB_PORT_FEAT_POWER: - if (HCS_PPC(priv->hcs_params)) - reg_write32(hcd->regs, HC_PORTSC1, - temp & ~PORT_POWER); - break; - case USB_PORT_FEAT_C_CONNECTION: - reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_CSC); - break; - case USB_PORT_FEAT_C_OVER_CURRENT: - /* XXX error ?*/ - break; - case USB_PORT_FEAT_C_RESET: - /* GetPortStatus clears reset */ - break; - default: - goto error; - } - reg_read32(hcd->regs, HC_USBCMD); - break; - case GetHubDescriptor: - isp1760_hub_descriptor(priv, (struct usb_hub_descriptor *) - buf); - break; - case GetHubStatus: - /* no hub-wide feature/status flags */ - memset(buf, 0, 4); - break; - case GetPortStatus: - if (!wIndex || wIndex > ports) - goto error; - wIndex--; - status = 0; - temp = reg_read32(hcd->regs, HC_PORTSC1); - - /* wPortChange bits */ - if (temp & PORT_CSC) - status |= USB_PORT_STAT_C_CONNECTION << 16; - - - /* whoever resumes must GetPortStatus to complete it!! */ - if (temp & PORT_RESUME) { - dev_err(hcd->self.controller, "Port resume should be skipped.\n"); - - /* Remote Wakeup received? */ - if (!priv->reset_done) { - /* resume signaling for 20 msec */ - priv->reset_done = jiffies - + msecs_to_jiffies(20); - /* check the port again */ - mod_timer(&hcd->rh_timer, priv->reset_done); - } - - /* resume completed? */ - else if (time_after_eq(jiffies, - priv->reset_done)) { - status |= USB_PORT_STAT_C_SUSPEND << 16; - priv->reset_done = 0; - - /* stop resume signaling */ - temp = reg_read32(hcd->regs, HC_PORTSC1); - reg_write32(hcd->regs, HC_PORTSC1, - temp & ~(PORT_RWC_BITS | PORT_RESUME)); - retval = handshake(hcd, HC_PORTSC1, - PORT_RESUME, 0, 2000 /* 2msec */); - if (retval != 0) { - dev_err(hcd->self.controller, - "port %d resume error %d\n", - wIndex + 1, retval); - goto error; - } - temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); - } - } - - /* whoever resets must GetPortStatus to complete it!! */ - if ((temp & PORT_RESET) - && time_after_eq(jiffies, - priv->reset_done)) { - status |= USB_PORT_STAT_C_RESET << 16; - priv->reset_done = 0; - - /* force reset to complete */ - reg_write32(hcd->regs, HC_PORTSC1, temp & ~PORT_RESET); - /* REVISIT: some hardware needs 550+ usec to clear - * this bit; seems too long to spin routinely... - */ - retval = handshake(hcd, HC_PORTSC1, - PORT_RESET, 0, 750); - if (retval != 0) { - dev_err(hcd->self.controller, "port %d reset error %d\n", - wIndex + 1, retval); - goto error; - } - - /* see what we found out */ - temp = check_reset_complete(hcd, wIndex, - reg_read32(hcd->regs, HC_PORTSC1)); - } - /* - * Even if OWNER is set, there's no harm letting khubd - * see the wPortStatus values (they should all be 0 except - * for PORT_POWER anyway). - */ - - if (temp & PORT_OWNER) - dev_err(hcd->self.controller, "PORT_OWNER is set\n"); - - if (temp & PORT_CONNECT) { - status |= USB_PORT_STAT_CONNECTION; - /* status may be from integrated TT */ - status |= USB_PORT_STAT_HIGH_SPEED; - } - if (temp & PORT_PE) - status |= USB_PORT_STAT_ENABLE; - if (temp & (PORT_SUSPEND|PORT_RESUME)) - status |= USB_PORT_STAT_SUSPEND; - if (temp & PORT_RESET) - status |= USB_PORT_STAT_RESET; - if (temp & PORT_POWER) - status |= USB_PORT_STAT_POWER; - - put_unaligned(cpu_to_le32(status), (__le32 *) buf); - break; - case SetHubFeature: - switch (wValue) { - case C_HUB_LOCAL_POWER: - case C_HUB_OVER_CURRENT: - /* no hub-wide feature/status flags */ - break; - default: - goto error; - } - break; - case SetPortFeature: - selector = wIndex >> 8; - wIndex &= 0xff; - if (!wIndex || wIndex > ports) - goto error; - wIndex--; - temp = reg_read32(hcd->regs, HC_PORTSC1); - if (temp & PORT_OWNER) - break; - -/* temp &= ~PORT_RWC_BITS; */ - switch (wValue) { - case USB_PORT_FEAT_ENABLE: - reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_PE); - break; - - case USB_PORT_FEAT_SUSPEND: - if ((temp & PORT_PE) == 0 - || (temp & PORT_RESET) != 0) - goto error; - - reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_SUSPEND); - break; - case USB_PORT_FEAT_POWER: - if (HCS_PPC(priv->hcs_params)) - reg_write32(hcd->regs, HC_PORTSC1, - temp | PORT_POWER); - break; - case USB_PORT_FEAT_RESET: - if (temp & PORT_RESUME) - goto error; - /* line status bits may report this as low speed, - * which can be fine if this root hub has a - * transaction translator built in. - */ - if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT - && PORT_USB11(temp)) { - temp |= PORT_OWNER; - } else { - temp |= PORT_RESET; - temp &= ~PORT_PE; - - /* - * caller must wait, then call GetPortStatus - * usb 2.0 spec says 50 ms resets on root - */ - priv->reset_done = jiffies + - msecs_to_jiffies(50); - } - reg_write32(hcd->regs, HC_PORTSC1, temp); - break; - default: - goto error; - } - reg_read32(hcd->regs, HC_USBCMD); - break; - - default: -error: - /* "stall" on error */ - retval = -EPIPE; - } - spin_unlock_irqrestore(&priv->lock, flags); - return retval; -} - -static int isp1760_get_frame(struct usb_hcd *hcd) -{ - struct isp1760_hcd *priv = hcd_to_priv(hcd); - u32 fr; - - fr = reg_read32(hcd->regs, HC_FRINDEX); - return (fr >> 3) % priv->periodic_size; -} - -static void isp1760_stop(struct usb_hcd *hcd) -{ - struct isp1760_hcd *priv = hcd_to_priv(hcd); - u32 temp; - - del_timer(&errata2_timer); - - isp1760_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER, 1, - NULL, 0); - mdelay(20); - - spin_lock_irq(&priv->lock); - ehci_reset(hcd); - /* Disable IRQ */ - temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL); - reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp &= ~HW_GLOBAL_INTR_EN); - spin_unlock_irq(&priv->lock); - - reg_write32(hcd->regs, HC_CONFIGFLAG, 0); -} - -static void isp1760_shutdown(struct usb_hcd *hcd) -{ - u32 command, temp; - - isp1760_stop(hcd); - temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL); - reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp &= ~HW_GLOBAL_INTR_EN); - - command = reg_read32(hcd->regs, HC_USBCMD); - command &= ~CMD_RUN; - reg_write32(hcd->regs, HC_USBCMD, command); -} - -static void isp1760_clear_tt_buffer_complete(struct usb_hcd *hcd, - struct usb_host_endpoint *ep) -{ - struct isp1760_hcd *priv = hcd_to_priv(hcd); - struct isp1760_qh *qh = ep->hcpriv; - unsigned long spinflags; - - if (!qh) - return; - - spin_lock_irqsave(&priv->lock, spinflags); - qh->tt_buffer_dirty = 0; - schedule_ptds(hcd); - spin_unlock_irqrestore(&priv->lock, spinflags); -} - - -static const struct hc_driver isp1760_hc_driver = { - .description = "isp1760-hcd", - .product_desc = "NXP ISP1760 USB Host Controller", - .hcd_priv_size = sizeof(struct isp1760_hcd), - .irq = isp1760_irq, - .flags = HCD_MEMORY | HCD_USB2, - .reset = isp1760_hc_setup, - .start = isp1760_run, - .stop = isp1760_stop, - .shutdown = isp1760_shutdown, - .urb_enqueue = isp1760_urb_enqueue, - .urb_dequeue = isp1760_urb_dequeue, - .endpoint_disable = isp1760_endpoint_disable, - .get_frame_number = isp1760_get_frame, - .hub_status_data = isp1760_hub_status_data, - .hub_control = isp1760_hub_control, - .clear_tt_buffer_complete = isp1760_clear_tt_buffer_complete, -}; - -int __init init_kmem_once(void) -{ - urb_listitem_cachep = kmem_cache_create("isp1760 urb_listitem", - sizeof(struct urb_listitem), 0, SLAB_TEMPORARY | - SLAB_MEM_SPREAD, NULL); - - if (!urb_listitem_cachep) - return -ENOMEM; - - qtd_cachep = kmem_cache_create("isp1760_qtd", - sizeof(struct isp1760_qtd), 0, SLAB_TEMPORARY | - SLAB_MEM_SPREAD, NULL); - - if (!qtd_cachep) - return -ENOMEM; - - qh_cachep = kmem_cache_create("isp1760_qh", sizeof(struct isp1760_qh), - 0, SLAB_TEMPORARY | SLAB_MEM_SPREAD, NULL); - - if (!qh_cachep) { - kmem_cache_destroy(qtd_cachep); - return -ENOMEM; - } - - return 0; -} - -void deinit_kmem_cache(void) -{ - kmem_cache_destroy(qtd_cachep); - kmem_cache_destroy(qh_cachep); - kmem_cache_destroy(urb_listitem_cachep); -} - -struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len, - int irq, unsigned long irqflags, - int rst_gpio, - struct device *dev, const char *busname, - unsigned int devflags) -{ - struct usb_hcd *hcd; - struct isp1760_hcd *priv; - int ret; - - if (usb_disabled()) - return ERR_PTR(-ENODEV); - - /* prevent usb-core allocating DMA pages */ - dev->dma_mask = NULL; - - hcd = usb_create_hcd(&isp1760_hc_driver, dev, dev_name(dev)); - if (!hcd) - return ERR_PTR(-ENOMEM); - - priv = hcd_to_priv(hcd); - priv->devflags = devflags; - priv->rst_gpio = rst_gpio; - init_memory(priv); - hcd->regs = ioremap(res_start, res_len); - if (!hcd->regs) { - ret = -EIO; - goto err_put; - } - - hcd->irq = irq; - hcd->rsrc_start = res_start; - hcd->rsrc_len = res_len; - - ret = usb_add_hcd(hcd, irq, irqflags); - if (ret) - goto err_unmap; - - return hcd; - -err_unmap: - iounmap(hcd->regs); - -err_put: - usb_put_hcd(hcd); - - return ERR_PTR(ret); -} - -MODULE_DESCRIPTION("Driver for the ISP1760 USB-controller from NXP"); -MODULE_AUTHOR("Sebastian Siewior "); -MODULE_LICENSE("GPL v2"); diff --git a/ANDROID_3.4.5/drivers/usb/host/isp1760-hcd.h b/ANDROID_3.4.5/drivers/usb/host/isp1760-hcd.h deleted file mode 100644 index 33dc79cc..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/isp1760-hcd.h +++ /dev/null @@ -1,208 +0,0 @@ -#ifndef _ISP1760_HCD_H_ -#define _ISP1760_HCD_H_ - -/* exports for if */ -struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len, - int irq, unsigned long irqflags, - int rst_gpio, - struct device *dev, const char *busname, - unsigned int devflags); -int init_kmem_once(void); -void deinit_kmem_cache(void); - -/* EHCI capability registers */ -#define HC_CAPLENGTH 0x00 -#define HC_HCSPARAMS 0x04 -#define HC_HCCPARAMS 0x08 - -/* EHCI operational registers */ -#define HC_USBCMD 0x20 -#define HC_USBSTS 0x24 -#define HC_FRINDEX 0x2c -#define HC_CONFIGFLAG 0x60 -#define HC_PORTSC1 0x64 -#define HC_ISO_PTD_DONEMAP_REG 0x130 -#define HC_ISO_PTD_SKIPMAP_REG 0x134 -#define HC_ISO_PTD_LASTPTD_REG 0x138 -#define HC_INT_PTD_DONEMAP_REG 0x140 -#define HC_INT_PTD_SKIPMAP_REG 0x144 -#define HC_INT_PTD_LASTPTD_REG 0x148 -#define HC_ATL_PTD_DONEMAP_REG 0x150 -#define HC_ATL_PTD_SKIPMAP_REG 0x154 -#define HC_ATL_PTD_LASTPTD_REG 0x158 - -/* Configuration Register */ -#define HC_HW_MODE_CTRL 0x300 -#define ALL_ATX_RESET (1 << 31) -#define HW_ANA_DIGI_OC (1 << 15) -#define HW_DATA_BUS_32BIT (1 << 8) -#define HW_DACK_POL_HIGH (1 << 6) -#define HW_DREQ_POL_HIGH (1 << 5) -#define HW_INTR_HIGH_ACT (1 << 2) -#define HW_INTR_EDGE_TRIG (1 << 1) -#define HW_GLOBAL_INTR_EN (1 << 0) - -#define HC_CHIP_ID_REG 0x304 -#define HC_SCRATCH_REG 0x308 - -#define HC_RESET_REG 0x30c -#define SW_RESET_RESET_HC (1 << 1) -#define SW_RESET_RESET_ALL (1 << 0) - -#define HC_BUFFER_STATUS_REG 0x334 -#define ISO_BUF_FILL (1 << 2) -#define INT_BUF_FILL (1 << 1) -#define ATL_BUF_FILL (1 << 0) - -#define HC_MEMORY_REG 0x33c -#define ISP_BANK(x) ((x) << 16) - -#define HC_PORT1_CTRL 0x374 -#define PORT1_POWER (3 << 3) -#define PORT1_INIT1 (1 << 7) -#define PORT1_INIT2 (1 << 23) -#define HW_OTG_CTRL_SET 0x374 -#define HW_OTG_CTRL_CLR 0x376 - -/* Interrupt Register */ -#define HC_INTERRUPT_REG 0x310 - -#define HC_INTERRUPT_ENABLE 0x314 -#define HC_ISO_INT (1 << 9) -#define HC_ATL_INT (1 << 8) -#define HC_INTL_INT (1 << 7) -#define HC_EOT_INT (1 << 3) -#define HC_SOT_INT (1 << 1) -#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT) - -#define HC_ISO_IRQ_MASK_OR_REG 0x318 -#define HC_INT_IRQ_MASK_OR_REG 0x31C -#define HC_ATL_IRQ_MASK_OR_REG 0x320 -#define HC_ISO_IRQ_MASK_AND_REG 0x324 -#define HC_INT_IRQ_MASK_AND_REG 0x328 -#define HC_ATL_IRQ_MASK_AND_REG 0x32C - -/* urb state*/ -#define DELETE_URB (0x0008) -#define NO_TRANSFER_ACTIVE (0xffffffff) - -/* Philips Proprietary Transfer Descriptor (PTD) */ -typedef __u32 __bitwise __dw; -struct ptd { - __dw dw0; - __dw dw1; - __dw dw2; - __dw dw3; - __dw dw4; - __dw dw5; - __dw dw6; - __dw dw7; -}; -#define PTD_OFFSET 0x0400 -#define ISO_PTD_OFFSET 0x0400 -#define INT_PTD_OFFSET 0x0800 -#define ATL_PTD_OFFSET 0x0c00 -#define PAYLOAD_OFFSET 0x1000 - -struct slotinfo { - struct isp1760_qh *qh; - struct isp1760_qtd *qtd; - unsigned long timestamp; -}; - - -typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh, - struct isp1760_qtd *qtd); - -/* - * Device flags that can vary from board to board. All of these - * indicate the most "atypical" case, so that a devflags of 0 is - * a sane default configuration. - */ -#define ISP1760_FLAG_BUS_WIDTH_16 0x00000002 /* 16-bit data bus width */ -#define ISP1760_FLAG_OTG_EN 0x00000004 /* Port 1 supports OTG */ -#define ISP1760_FLAG_ANALOG_OC 0x00000008 /* Analog overcurrent */ -#define ISP1760_FLAG_DACK_POL_HIGH 0x00000010 /* DACK active high */ -#define ISP1760_FLAG_DREQ_POL_HIGH 0x00000020 /* DREQ active high */ -#define ISP1760_FLAG_ISP1761 0x00000040 /* Chip is ISP1761 */ -#define ISP1760_FLAG_INTR_POL_HIGH 0x00000080 /* Interrupt polarity active high */ -#define ISP1760_FLAG_INTR_EDGE_TRIG 0x00000100 /* Interrupt edge triggered */ -#define ISP1760_FLAG_RESET_ACTIVE_HIGH 0x80000000 /* RESET GPIO active high */ - -/* chip memory management */ -struct memory_chunk { - unsigned int start; - unsigned int size; - unsigned int free; -}; - -/* - * 60kb divided in: - * - 32 blocks @ 256 bytes - * - 20 blocks @ 1024 bytes - * - 4 blocks @ 8192 bytes - */ - -#define BLOCK_1_NUM 32 -#define BLOCK_2_NUM 20 -#define BLOCK_3_NUM 4 - -#define BLOCK_1_SIZE 256 -#define BLOCK_2_SIZE 1024 -#define BLOCK_3_SIZE 8192 -#define BLOCKS (BLOCK_1_NUM + BLOCK_2_NUM + BLOCK_3_NUM) -#define MAX_PAYLOAD_SIZE BLOCK_3_SIZE -#define PAYLOAD_AREA_SIZE 0xf000 - -/* ATL */ -/* DW0 */ -#define DW0_VALID_BIT 1 -#define FROM_DW0_VALID(x) ((x) & 0x01) -#define TO_DW0_LENGTH(x) (((u32) x) << 3) -#define TO_DW0_MAXPACKET(x) (((u32) x) << 18) -#define TO_DW0_MULTI(x) (((u32) x) << 29) -#define TO_DW0_ENDPOINT(x) (((u32) x) << 31) -/* DW1 */ -#define TO_DW1_DEVICE_ADDR(x) (((u32) x) << 3) -#define TO_DW1_PID_TOKEN(x) (((u32) x) << 10) -#define DW1_TRANS_BULK ((u32) 2 << 12) -#define DW1_TRANS_INT ((u32) 3 << 12) -#define DW1_TRANS_SPLIT ((u32) 1 << 14) -#define DW1_SE_USB_LOSPEED ((u32) 2 << 16) -#define TO_DW1_PORT_NUM(x) (((u32) x) << 18) -#define TO_DW1_HUB_NUM(x) (((u32) x) << 25) -/* DW2 */ -#define TO_DW2_DATA_START_ADDR(x) (((u32) x) << 8) -#define TO_DW2_RL(x) ((x) << 25) -#define FROM_DW2_RL(x) (((x) >> 25) & 0xf) -/* DW3 */ -#define FROM_DW3_NRBYTESTRANSFERRED(x) ((x) & 0x7fff) -#define FROM_DW3_SCS_NRBYTESTRANSFERRED(x) ((x) & 0x07ff) -#define TO_DW3_NAKCOUNT(x) ((x) << 19) -#define FROM_DW3_NAKCOUNT(x) (((x) >> 19) & 0xf) -#define TO_DW3_CERR(x) ((x) << 23) -#define FROM_DW3_CERR(x) (((x) >> 23) & 0x3) -#define TO_DW3_DATA_TOGGLE(x) ((x) << 25) -#define FROM_DW3_DATA_TOGGLE(x) (((x) >> 25) & 0x1) -#define TO_DW3_PING(x) ((x) << 26) -#define FROM_DW3_PING(x) (((x) >> 26) & 0x1) -#define DW3_ERROR_BIT (1 << 28) -#define DW3_BABBLE_BIT (1 << 29) -#define DW3_HALT_BIT (1 << 30) -#define DW3_ACTIVE_BIT (1 << 31) -#define FROM_DW3_ACTIVE(x) (((x) >> 31) & 0x01) - -#define INT_UNDERRUN (1 << 2) -#define INT_BABBLE (1 << 1) -#define INT_EXACT (1 << 0) - -#define SETUP_PID (2) -#define IN_PID (1) -#define OUT_PID (0) - -/* Errata 1 */ -#define RL_COUNTER (0) -#define NAK_COUNTER (0) -#define ERR_COUNTER (2) - -#endif /* _ISP1760_HCD_H_ */ diff --git a/ANDROID_3.4.5/drivers/usb/host/isp1760-if.c b/ANDROID_3.4.5/drivers/usb/host/isp1760-if.c deleted file mode 100644 index 4592dc17..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/isp1760-if.c +++ /dev/null @@ -1,473 +0,0 @@ -/* - * Glue code for the ISP1760 driver and bus - * Currently there is support for - * - OpenFirmware - * - PCI - * - PDEV (generic platform device centralized driver model) - * - * (c) 2007 Sebastian Siewior - * - */ - -#include -#include -#include -#include -#include -#include - -#include "isp1760-hcd.h" - -#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) -#include -#include -#include -#include -#include -#include -#endif - -#ifdef CONFIG_PCI -#include -#endif - -#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) -struct isp1760 { - struct usb_hcd *hcd; - int rst_gpio; -}; - -static int of_isp1760_probe(struct platform_device *dev) -{ - struct isp1760 *drvdata; - struct device_node *dp = dev->dev.of_node; - struct resource *res; - struct resource memory; - struct of_irq oirq; - int virq; - resource_size_t res_len; - int ret; - unsigned int devflags = 0; - enum of_gpio_flags gpio_flags; - u32 bus_width = 0; - - drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) - return -ENOMEM; - - ret = of_address_to_resource(dp, 0, &memory); - if (ret) { - ret = -ENXIO; - goto free_data; - } - - res_len = resource_size(&memory); - - res = request_mem_region(memory.start, res_len, dev_name(&dev->dev)); - if (!res) { - ret = -EBUSY; - goto free_data; - } - - if (of_irq_map_one(dp, 0, &oirq)) { - ret = -ENODEV; - goto release_reg; - } - - virq = irq_create_of_mapping(oirq.controller, oirq.specifier, - oirq.size); - - if (of_device_is_compatible(dp, "nxp,usb-isp1761")) - devflags |= ISP1760_FLAG_ISP1761; - - /* Some systems wire up only 16 of the 32 data lines */ - of_property_read_u32(dp, "bus-width", &bus_width); - if (bus_width == 16) - devflags |= ISP1760_FLAG_BUS_WIDTH_16; - - if (of_get_property(dp, "port1-otg", NULL) != NULL) - devflags |= ISP1760_FLAG_OTG_EN; - - if (of_get_property(dp, "analog-oc", NULL) != NULL) - devflags |= ISP1760_FLAG_ANALOG_OC; - - if (of_get_property(dp, "dack-polarity", NULL) != NULL) - devflags |= ISP1760_FLAG_DACK_POL_HIGH; - - if (of_get_property(dp, "dreq-polarity", NULL) != NULL) - devflags |= ISP1760_FLAG_DREQ_POL_HIGH; - - drvdata->rst_gpio = of_get_gpio_flags(dp, 0, &gpio_flags); - if (gpio_is_valid(drvdata->rst_gpio)) { - ret = gpio_request(drvdata->rst_gpio, dev_name(&dev->dev)); - if (!ret) { - if (!(gpio_flags & OF_GPIO_ACTIVE_LOW)) { - devflags |= ISP1760_FLAG_RESET_ACTIVE_HIGH; - gpio_direction_output(drvdata->rst_gpio, 0); - } else { - gpio_direction_output(drvdata->rst_gpio, 1); - } - } else { - drvdata->rst_gpio = ret; - } - } - - drvdata->hcd = isp1760_register(memory.start, res_len, virq, - IRQF_SHARED, drvdata->rst_gpio, - &dev->dev, dev_name(&dev->dev), - devflags); - if (IS_ERR(drvdata->hcd)) { - ret = PTR_ERR(drvdata->hcd); - goto free_gpio; - } - - dev_set_drvdata(&dev->dev, drvdata); - return ret; - -free_gpio: - if (gpio_is_valid(drvdata->rst_gpio)) - gpio_free(drvdata->rst_gpio); -release_reg: - release_mem_region(memory.start, res_len); -free_data: - kfree(drvdata); - return ret; -} - -static int of_isp1760_remove(struct platform_device *dev) -{ - struct isp1760 *drvdata = dev_get_drvdata(&dev->dev); - - dev_set_drvdata(&dev->dev, NULL); - - usb_remove_hcd(drvdata->hcd); - iounmap(drvdata->hcd->regs); - release_mem_region(drvdata->hcd->rsrc_start, drvdata->hcd->rsrc_len); - usb_put_hcd(drvdata->hcd); - - if (gpio_is_valid(drvdata->rst_gpio)) - gpio_free(drvdata->rst_gpio); - - kfree(drvdata); - return 0; -} - -static const struct of_device_id of_isp1760_match[] = { - { - .compatible = "nxp,usb-isp1760", - }, - { - .compatible = "nxp,usb-isp1761", - }, - { }, -}; -MODULE_DEVICE_TABLE(of, of_isp1760_match); - -static struct platform_driver isp1760_of_driver = { - .driver = { - .name = "nxp-isp1760", - .owner = THIS_MODULE, - .of_match_table = of_isp1760_match, - }, - .probe = of_isp1760_probe, - .remove = of_isp1760_remove, -}; -#endif - -#ifdef CONFIG_PCI -static int __devinit isp1761_pci_probe(struct pci_dev *dev, - const struct pci_device_id *id) -{ - u8 latency, limit; - __u32 reg_data; - int retry_count; - struct usb_hcd *hcd; - unsigned int devflags = 0; - int ret_status = 0; - - resource_size_t pci_mem_phy0; - resource_size_t memlength; - - u8 __iomem *chip_addr; - u8 __iomem *iobase; - resource_size_t nxp_pci_io_base; - resource_size_t iolength; - - if (usb_disabled()) - return -ENODEV; - - if (pci_enable_device(dev) < 0) - return -ENODEV; - - if (!dev->irq) - return -ENODEV; - - /* Grab the PLX PCI mem maped port start address we need */ - nxp_pci_io_base = pci_resource_start(dev, 0); - iolength = pci_resource_len(dev, 0); - - if (!request_mem_region(nxp_pci_io_base, iolength, "ISP1761 IO MEM")) { - printk(KERN_ERR "request region #1\n"); - return -EBUSY; - } - - iobase = ioremap_nocache(nxp_pci_io_base, iolength); - if (!iobase) { - printk(KERN_ERR "ioremap #1\n"); - ret_status = -ENOMEM; - goto cleanup1; - } - /* Grab the PLX PCI shared memory of the ISP 1761 we need */ - pci_mem_phy0 = pci_resource_start(dev, 3); - memlength = pci_resource_len(dev, 3); - if (memlength < 0xffff) { - printk(KERN_ERR "memory length for this resource is wrong\n"); - ret_status = -ENOMEM; - goto cleanup2; - } - - if (!request_mem_region(pci_mem_phy0, memlength, "ISP-PCI")) { - printk(KERN_ERR "host controller already in use\n"); - ret_status = -EBUSY; - goto cleanup2; - } - - /* map available memory */ - chip_addr = ioremap_nocache(pci_mem_phy0,memlength); - if (!chip_addr) { - printk(KERN_ERR "Error ioremap failed\n"); - ret_status = -ENOMEM; - goto cleanup3; - } - - /* bad pci latencies can contribute to overruns */ - pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency); - if (latency) { - pci_read_config_byte(dev, PCI_MAX_LAT, &limit); - if (limit && limit < latency) - pci_write_config_byte(dev, PCI_LATENCY_TIMER, limit); - } - - /* Try to check whether we can access Scratch Register of - * Host Controller or not. The initial PCI access is retried until - * local init for the PCI bridge is completed - */ - retry_count = 20; - reg_data = 0; - while ((reg_data != 0xFACE) && retry_count) { - /*by default host is in 16bit mode, so - * io operations at this stage must be 16 bit - * */ - writel(0xface, chip_addr + HC_SCRATCH_REG); - udelay(100); - reg_data = readl(chip_addr + HC_SCRATCH_REG) & 0x0000ffff; - retry_count--; - } - - iounmap(chip_addr); - - /* Host Controller presence is detected by writing to scratch register - * and reading back and checking the contents are same or not - */ - if (reg_data != 0xFACE) { - dev_err(&dev->dev, "scratch register mismatch %x\n", reg_data); - ret_status = -ENOMEM; - goto cleanup3; - } - - pci_set_master(dev); - - /* configure PLX PCI chip to pass interrupts */ -#define PLX_INT_CSR_REG 0x68 - reg_data = readl(iobase + PLX_INT_CSR_REG); - reg_data |= 0x900; - writel(reg_data, iobase + PLX_INT_CSR_REG); - - dev->dev.dma_mask = NULL; - hcd = isp1760_register(pci_mem_phy0, memlength, dev->irq, - IRQF_SHARED, -ENOENT, &dev->dev, dev_name(&dev->dev), - devflags); - if (IS_ERR(hcd)) { - ret_status = -ENODEV; - goto cleanup3; - } - - /* done with PLX IO access */ - iounmap(iobase); - release_mem_region(nxp_pci_io_base, iolength); - - pci_set_drvdata(dev, hcd); - return 0; - -cleanup3: - release_mem_region(pci_mem_phy0, memlength); -cleanup2: - iounmap(iobase); -cleanup1: - release_mem_region(nxp_pci_io_base, iolength); - return ret_status; -} - -static void isp1761_pci_remove(struct pci_dev *dev) -{ - struct usb_hcd *hcd; - - hcd = pci_get_drvdata(dev); - - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - - pci_disable_device(dev); -} - -static void isp1761_pci_shutdown(struct pci_dev *dev) -{ - printk(KERN_ERR "ips1761_pci_shutdown\n"); -} - -static const struct pci_device_id isp1760_plx [] = { - { - .class = PCI_CLASS_BRIDGE_OTHER << 8, - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_PLX, - .device = 0x5406, - .subvendor = PCI_VENDOR_ID_PLX, - .subdevice = 0x9054, - }, - { } -}; -MODULE_DEVICE_TABLE(pci, isp1760_plx); - -static struct pci_driver isp1761_pci_driver = { - .name = "isp1760", - .id_table = isp1760_plx, - .probe = isp1761_pci_probe, - .remove = isp1761_pci_remove, - .shutdown = isp1761_pci_shutdown, -}; -#endif - -static int __devinit isp1760_plat_probe(struct platform_device *pdev) -{ - int ret = 0; - struct usb_hcd *hcd; - struct resource *mem_res; - struct resource *irq_res; - resource_size_t mem_size; - struct isp1760_platform_data *priv = pdev->dev.platform_data; - unsigned int devflags = 0; - unsigned long irqflags = IRQF_SHARED; - - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem_res) { - pr_warning("isp1760: Memory resource not available\n"); - ret = -ENODEV; - goto out; - } - mem_size = resource_size(mem_res); - if (!request_mem_region(mem_res->start, mem_size, "isp1760")) { - pr_warning("isp1760: Cannot reserve the memory resource\n"); - ret = -EBUSY; - goto out; - } - - irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!irq_res) { - pr_warning("isp1760: IRQ resource not available\n"); - return -ENODEV; - } - irqflags |= irq_res->flags & IRQF_TRIGGER_MASK; - - if (priv) { - if (priv->is_isp1761) - devflags |= ISP1760_FLAG_ISP1761; - if (priv->bus_width_16) - devflags |= ISP1760_FLAG_BUS_WIDTH_16; - if (priv->port1_otg) - devflags |= ISP1760_FLAG_OTG_EN; - if (priv->analog_oc) - devflags |= ISP1760_FLAG_ANALOG_OC; - if (priv->dack_polarity_high) - devflags |= ISP1760_FLAG_DACK_POL_HIGH; - if (priv->dreq_polarity_high) - devflags |= ISP1760_FLAG_DREQ_POL_HIGH; - } - - hcd = isp1760_register(mem_res->start, mem_size, irq_res->start, - irqflags, -ENOENT, - &pdev->dev, dev_name(&pdev->dev), devflags); - if (IS_ERR(hcd)) { - pr_warning("isp1760: Failed to register the HCD device\n"); - ret = -ENODEV; - goto cleanup; - } - - pr_info("ISP1760 USB device initialised\n"); - return ret; - -cleanup: - release_mem_region(mem_res->start, mem_size); -out: - return ret; -} - -static int __devexit isp1760_plat_remove(struct platform_device *pdev) -{ - struct resource *mem_res; - resource_size_t mem_size; - - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mem_size = resource_size(mem_res); - release_mem_region(mem_res->start, mem_size); - - return 0; -} - -static struct platform_driver isp1760_plat_driver = { - .probe = isp1760_plat_probe, - .remove = __devexit_p(isp1760_plat_remove), - .driver = { - .name = "isp1760", - }, -}; - -static int __init isp1760_init(void) -{ - int ret, any_ret = -ENODEV; - - init_kmem_once(); - - ret = platform_driver_register(&isp1760_plat_driver); - if (!ret) - any_ret = 0; -#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) - ret = platform_driver_register(&isp1760_of_driver); - if (!ret) - any_ret = 0; -#endif -#ifdef CONFIG_PCI - ret = pci_register_driver(&isp1761_pci_driver); - if (!ret) - any_ret = 0; -#endif - - if (any_ret) - deinit_kmem_cache(); - return any_ret; -} -module_init(isp1760_init); - -static void __exit isp1760_exit(void) -{ - platform_driver_unregister(&isp1760_plat_driver); -#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) - platform_driver_unregister(&isp1760_of_driver); -#endif -#ifdef CONFIG_PCI - pci_unregister_driver(&isp1761_pci_driver); -#endif - deinit_kmem_cache(); -} -module_exit(isp1760_exit); diff --git a/ANDROID_3.4.5/drivers/usb/host/octeon2-common.c b/ANDROID_3.4.5/drivers/usb/host/octeon2-common.c deleted file mode 100644 index d9df423f..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/octeon2-common.c +++ /dev/null @@ -1,200 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2010, 2011 Cavium Networks - */ - -#include -#include -#include - -#include -#include - -static DEFINE_MUTEX(octeon2_usb_clocks_mutex); - -static int octeon2_usb_clock_start_cnt; - -void octeon2_usb_clocks_start(void) -{ - u64 div; - union cvmx_uctlx_if_ena if_ena; - union cvmx_uctlx_clk_rst_ctl clk_rst_ctl; - union cvmx_uctlx_uphy_ctl_status uphy_ctl_status; - union cvmx_uctlx_uphy_portx_ctl_status port_ctl_status; - int i; - unsigned long io_clk_64_to_ns; - - - mutex_lock(&octeon2_usb_clocks_mutex); - - octeon2_usb_clock_start_cnt++; - if (octeon2_usb_clock_start_cnt != 1) - goto exit; - - io_clk_64_to_ns = 64000000000ull / octeon_get_io_clock_rate(); - - /* - * Step 1: Wait for voltages stable. That surely happened - * before starting the kernel. - * - * Step 2: Enable SCLK of UCTL by writing UCTL0_IF_ENA[EN] = 1 - */ - if_ena.u64 = 0; - if_ena.s.en = 1; - cvmx_write_csr(CVMX_UCTLX_IF_ENA(0), if_ena.u64); - - /* Step 3: Configure the reference clock, PHY, and HCLK */ - clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0)); - - /* - * If the UCTL looks like it has already been started, skip - * the initialization, otherwise bus errors are obtained. - */ - if (clk_rst_ctl.s.hrst) - goto end_clock; - /* 3a */ - clk_rst_ctl.s.p_por = 1; - clk_rst_ctl.s.hrst = 0; - clk_rst_ctl.s.p_prst = 0; - clk_rst_ctl.s.h_clkdiv_rst = 0; - clk_rst_ctl.s.o_clkdiv_rst = 0; - clk_rst_ctl.s.h_clkdiv_en = 0; - clk_rst_ctl.s.o_clkdiv_en = 0; - cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); - - /* 3b */ - /* 12MHz crystal. */ - clk_rst_ctl.s.p_refclk_sel = 0; - clk_rst_ctl.s.p_refclk_div = 0; - cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); - - /* 3c */ - div = octeon_get_io_clock_rate() / 130000000ull; - - switch (div) { - case 0: - div = 1; - break; - case 1: - case 2: - case 3: - case 4: - break; - case 5: - div = 4; - break; - case 6: - case 7: - div = 6; - break; - case 8: - case 9: - case 10: - case 11: - div = 8; - break; - default: - div = 12; - break; - } - clk_rst_ctl.s.h_div = div; - cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); - /* Read it back, */ - clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0)); - clk_rst_ctl.s.h_clkdiv_en = 1; - cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); - /* 3d */ - clk_rst_ctl.s.h_clkdiv_rst = 1; - cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); - - /* 3e: delay 64 io clocks */ - ndelay(io_clk_64_to_ns); - - /* - * Step 4: Program the power-on reset field in the UCTL - * clock-reset-control register. - */ - clk_rst_ctl.s.p_por = 0; - cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); - - /* Step 5: Wait 1 ms for the PHY clock to start. */ - mdelay(1); - - /* - * Step 6: Program the reset input from automatic test - * equipment field in the UPHY CSR - */ - uphy_ctl_status.u64 = cvmx_read_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0)); - uphy_ctl_status.s.ate_reset = 1; - cvmx_write_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0), uphy_ctl_status.u64); - - /* Step 7: Wait for at least 10ns. */ - ndelay(10); - - /* Step 8: Clear the ATE_RESET field in the UPHY CSR. */ - uphy_ctl_status.s.ate_reset = 0; - cvmx_write_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0), uphy_ctl_status.u64); - - /* - * Step 9: Wait for at least 20ns for UPHY to output PHY clock - * signals and OHCI_CLK48 - */ - ndelay(20); - - /* Step 10: Configure the OHCI_CLK48 and OHCI_CLK12 clocks. */ - /* 10a */ - clk_rst_ctl.s.o_clkdiv_rst = 1; - cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); - - /* 10b */ - clk_rst_ctl.s.o_clkdiv_en = 1; - cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); - - /* 10c */ - ndelay(io_clk_64_to_ns); - - /* - * Step 11: Program the PHY reset field: - * UCTL0_CLK_RST_CTL[P_PRST] = 1 - */ - clk_rst_ctl.s.p_prst = 1; - cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); - - /* Step 12: Wait 1 uS. */ - udelay(1); - - /* Step 13: Program the HRESET_N field: UCTL0_CLK_RST_CTL[HRST] = 1 */ - clk_rst_ctl.s.hrst = 1; - cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64); - -end_clock: - /* Now we can set some other registers. */ - - for (i = 0; i <= 1; i++) { - port_ctl_status.u64 = - cvmx_read_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0)); - /* Set txvreftune to 15 to obtain compliant 'eye' diagram. */ - port_ctl_status.s.txvreftune = 15; - port_ctl_status.s.txrisetune = 1; - port_ctl_status.s.txpreemphasistune = 1; - cvmx_write_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0), - port_ctl_status.u64); - } - - /* Set uSOF cycle period to 60,000 bits. */ - cvmx_write_csr(CVMX_UCTLX_EHCI_FLA(0), 0x20ull); -exit: - mutex_unlock(&octeon2_usb_clocks_mutex); -} -EXPORT_SYMBOL(octeon2_usb_clocks_start); - -void octeon2_usb_clocks_stop(void) -{ - mutex_lock(&octeon2_usb_clocks_mutex); - octeon2_usb_clock_start_cnt--; - mutex_unlock(&octeon2_usb_clocks_mutex); -} -EXPORT_SYMBOL(octeon2_usb_clocks_stop); diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-at91.c b/ANDROID_3.4.5/drivers/usb/host/ohci-at91.c deleted file mode 100644 index 55d3d641..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-at91.c +++ /dev/null @@ -1,717 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * Copyright (C) 2004 SAN People (Pty) Ltd. - * Copyright (C) 2005 Thibaut VARENE - * - * AT91 Bus Glue - * - * Based on fragments of 2.4 driver by Rick Bronson. - * Based on ohci-omap.c - * - * This file is licenced under the GPL. - */ - -#include -#include -#include -#include - -#include -#include - -#include -#include - -#ifndef CONFIG_ARCH_AT91 -#error "CONFIG_ARCH_AT91 must be defined." -#endif - -#define valid_port(index) ((index) >= 0 && (index) < AT91_MAX_USBH_PORTS) -#define at91_for_each_port(index) \ - for ((index) = 0; (index) < AT91_MAX_USBH_PORTS; (index)++) - -/* interface and function clocks; sometimes also an AHB clock */ -static struct clk *iclk, *fclk, *hclk; -static int clocked; - -extern int usb_disabled(void); - -/*-------------------------------------------------------------------------*/ - -static void at91_start_clock(void) -{ - clk_enable(hclk); - clk_enable(iclk); - clk_enable(fclk); - clocked = 1; -} - -static void at91_stop_clock(void) -{ - clk_disable(fclk); - clk_disable(iclk); - clk_disable(hclk); - clocked = 0; -} - -static void at91_start_hc(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct ohci_regs __iomem *regs = hcd->regs; - - dev_dbg(&pdev->dev, "start\n"); - - /* - * Start the USB clocks. - */ - at91_start_clock(); - - /* - * The USB host controller must remain in reset. - */ - writel(0, ®s->control); -} - -static void at91_stop_hc(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct ohci_regs __iomem *regs = hcd->regs; - - dev_dbg(&pdev->dev, "stop\n"); - - /* - * Put the USB host controller into reset. - */ - writel(0, ®s->control); - - /* - * Stop the USB clocks. - */ - at91_stop_clock(); -} - - -/*-------------------------------------------------------------------------*/ - -static void __devexit usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *); - -/* configure so an HC device and id are always provided */ -/* always called with process context; sleeping is OK */ - - -/** - * usb_hcd_at91_probe - initialize AT91-based HCDs - * Context: !in_interrupt() - * - * Allocates basic resources for this USB host controller, and - * then invokes the start() method for the HCD associated with it - * through the hotplug entry's driver_data. - */ -static int __devinit usb_hcd_at91_probe(const struct hc_driver *driver, - struct platform_device *pdev) -{ - int retval; - struct usb_hcd *hcd = NULL; - - if (pdev->num_resources != 2) { - pr_debug("hcd probe: invalid num_resources"); - return -ENODEV; - } - - if ((pdev->resource[0].flags != IORESOURCE_MEM) - || (pdev->resource[1].flags != IORESOURCE_IRQ)) { - pr_debug("hcd probe: invalid resource type\n"); - return -ENODEV; - } - - hcd = usb_create_hcd(driver, &pdev->dev, "at91"); - if (!hcd) - return -ENOMEM; - hcd->rsrc_start = pdev->resource[0].start; - hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - pr_debug("request_mem_region failed\n"); - retval = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - pr_debug("ioremap failed\n"); - retval = -EIO; - goto err2; - } - - iclk = clk_get(&pdev->dev, "ohci_clk"); - if (IS_ERR(iclk)) { - dev_err(&pdev->dev, "failed to get ohci_clk\n"); - retval = PTR_ERR(iclk); - goto err3; - } - fclk = clk_get(&pdev->dev, "uhpck"); - if (IS_ERR(fclk)) { - dev_err(&pdev->dev, "failed to get uhpck\n"); - retval = PTR_ERR(fclk); - goto err4; - } - hclk = clk_get(&pdev->dev, "hclk"); - if (IS_ERR(hclk)) { - dev_err(&pdev->dev, "failed to get hclk\n"); - retval = PTR_ERR(hclk); - goto err5; - } - - at91_start_hc(pdev); - ohci_hcd_init(hcd_to_ohci(hcd)); - - retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED); - if (retval == 0) - return retval; - - /* Error handling */ - at91_stop_hc(pdev); - - clk_put(hclk); - err5: - clk_put(fclk); - err4: - clk_put(iclk); - - err3: - iounmap(hcd->regs); - - err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - - err1: - usb_put_hcd(hcd); - return retval; -} - - -/* may be called with controller, bus, and devices active */ - -/** - * usb_hcd_at91_remove - shutdown processing for AT91-based HCDs - * @dev: USB Host Controller being removed - * Context: !in_interrupt() - * - * Reverses the effect of usb_hcd_at91_probe(), first invoking - * the HCD's stop() method. It is always called from a thread - * context, "rmmod" or something similar. - * - */ -static void __devexit usb_hcd_at91_remove(struct usb_hcd *hcd, - struct platform_device *pdev) -{ - usb_remove_hcd(hcd); - at91_stop_hc(pdev); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - - clk_put(hclk); - clk_put(fclk); - clk_put(iclk); - fclk = iclk = hclk = NULL; - - dev_set_drvdata(&pdev->dev, NULL); -} - -/*-------------------------------------------------------------------------*/ - -static int __devinit -ohci_at91_reset (struct usb_hcd *hcd) -{ - struct at91_usbh_data *board = hcd->self.controller->platform_data; - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int ret; - - if ((ret = ohci_init(ohci)) < 0) - return ret; - - ohci->num_ports = board->ports; - return 0; -} - -static int __devinit -ohci_at91_start (struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int ret; - - if ((ret = ohci_run(ohci)) < 0) { - err("can't start %s", hcd->self.bus_name); - ohci_stop(hcd); - return ret; - } - return 0; -} - -static void ohci_at91_usb_set_power(struct at91_usbh_data *pdata, int port, int enable) -{ - if (!valid_port(port)) - return; - - if (!gpio_is_valid(pdata->vbus_pin[port])) - return; - - gpio_set_value(pdata->vbus_pin[port], - pdata->vbus_pin_active_low[port] ^ enable); -} - -static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port) -{ - if (!valid_port(port)) - return -EINVAL; - - if (!gpio_is_valid(pdata->vbus_pin[port])) - return -EINVAL; - - return gpio_get_value(pdata->vbus_pin[port]) ^ - pdata->vbus_pin_active_low[port]; -} - -/* - * Update the status data from the hub with the over-current indicator change. - */ -static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf) -{ - struct at91_usbh_data *pdata = hcd->self.controller->platform_data; - int length = ohci_hub_status_data(hcd, buf); - int port; - - at91_for_each_port(port) { - if (pdata->overcurrent_changed[port]) { - if (!length) - length = 1; - buf[0] |= 1 << (port + 1); - } - } - - return length; -} - -/* - * Look at the control requests to the root hub and see if we need to override. - */ -static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, - u16 wIndex, char *buf, u16 wLength) -{ - struct at91_usbh_data *pdata = hcd->self.controller->platform_data; - struct usb_hub_descriptor *desc; - int ret = -EINVAL; - u32 *data = (u32 *)buf; - - dev_dbg(hcd->self.controller, - "ohci_at91_hub_control(%p,0x%04x,0x%04x,0x%04x,%p,%04x)\n", - hcd, typeReq, wValue, wIndex, buf, wLength); - - wIndex--; - - switch (typeReq) { - case SetPortFeature: - if (wValue == USB_PORT_FEAT_POWER) { - dev_dbg(hcd->self.controller, "SetPortFeat: POWER\n"); - if (valid_port(wIndex)) { - ohci_at91_usb_set_power(pdata, wIndex, 1); - ret = 0; - } - - goto out; - } - break; - - case ClearPortFeature: - switch (wValue) { - case USB_PORT_FEAT_C_OVER_CURRENT: - dev_dbg(hcd->self.controller, - "ClearPortFeature: C_OVER_CURRENT\n"); - - if (valid_port(wIndex)) { - pdata->overcurrent_changed[wIndex] = 0; - pdata->overcurrent_status[wIndex] = 0; - } - - goto out; - - case USB_PORT_FEAT_OVER_CURRENT: - dev_dbg(hcd->self.controller, - "ClearPortFeature: OVER_CURRENT\n"); - - if (valid_port(wIndex)) - pdata->overcurrent_status[wIndex] = 0; - - goto out; - - case USB_PORT_FEAT_POWER: - dev_dbg(hcd->self.controller, - "ClearPortFeature: POWER\n"); - - if (valid_port(wIndex)) { - ohci_at91_usb_set_power(pdata, wIndex, 0); - return 0; - } - } - break; - } - - ret = ohci_hub_control(hcd, typeReq, wValue, wIndex + 1, buf, wLength); - if (ret) - goto out; - - switch (typeReq) { - case GetHubDescriptor: - - /* update the hub's descriptor */ - - desc = (struct usb_hub_descriptor *)buf; - - dev_dbg(hcd->self.controller, "wHubCharacteristics 0x%04x\n", - desc->wHubCharacteristics); - - /* remove the old configurations for power-switching, and - * over-current protection, and insert our new configuration - */ - - desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_LPSM); - desc->wHubCharacteristics |= cpu_to_le16(0x0001); - - if (pdata->overcurrent_supported) { - desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_OCPM); - desc->wHubCharacteristics |= cpu_to_le16(0x0008|0x0001); - } - - dev_dbg(hcd->self.controller, "wHubCharacteristics after 0x%04x\n", - desc->wHubCharacteristics); - - return ret; - - case GetPortStatus: - /* check port status */ - - dev_dbg(hcd->self.controller, "GetPortStatus(%d)\n", wIndex); - - if (valid_port(wIndex)) { - if (!ohci_at91_usb_get_power(pdata, wIndex)) - *data &= ~cpu_to_le32(RH_PS_PPS); - - if (pdata->overcurrent_changed[wIndex]) - *data |= cpu_to_le32(RH_PS_OCIC); - - if (pdata->overcurrent_status[wIndex]) - *data |= cpu_to_le32(RH_PS_POCI); - } - } - - out: - return ret; -} - -/*-------------------------------------------------------------------------*/ - -static const struct hc_driver ohci_at91_hc_driver = { - .description = hcd_name, - .product_desc = "AT91 OHCI", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .reset = ohci_at91_reset, - .start = ohci_at91_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_at91_hub_status_data, - .hub_control = ohci_at91_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -/*-------------------------------------------------------------------------*/ - -static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data) -{ - struct platform_device *pdev = data; - struct at91_usbh_data *pdata = pdev->dev.platform_data; - int val, gpio, port; - - /* From the GPIO notifying the over-current situation, find - * out the corresponding port */ - at91_for_each_port(port) { - if (gpio_to_irq(pdata->overcurrent_pin[port]) == irq) { - gpio = pdata->overcurrent_pin[port]; - break; - } - } - - if (port == AT91_MAX_USBH_PORTS) { - dev_err(& pdev->dev, "overcurrent interrupt from unknown GPIO\n"); - return IRQ_HANDLED; - } - - val = gpio_get_value(gpio); - - /* When notified of an over-current situation, disable power - on the corresponding port, and mark this port in - over-current. */ - if (!val) { - ohci_at91_usb_set_power(pdata, port, 0); - pdata->overcurrent_status[port] = 1; - pdata->overcurrent_changed[port] = 1; - } - - dev_dbg(& pdev->dev, "overcurrent situation %s\n", - val ? "exited" : "notified"); - - return IRQ_HANDLED; -} - -#ifdef CONFIG_OF -static const struct of_device_id at91_ohci_dt_ids[] = { - { .compatible = "atmel,at91rm9200-ohci" }, - { /* sentinel */ } -}; - -MODULE_DEVICE_TABLE(of, at91_ohci_dt_ids); - -static u64 at91_ohci_dma_mask = DMA_BIT_MASK(32); - -static int __devinit ohci_at91_of_init(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - int i, gpio; - enum of_gpio_flags flags; - struct at91_usbh_data *pdata; - u32 ports; - - if (!np) - return 0; - - /* Right now device-tree probed devices don't get dma_mask set. - * Since shared usb code relies on it, set it here for now. - * Once we have dma capability bindings this can go away. - */ - if (!pdev->dev.dma_mask) - pdev->dev.dma_mask = &at91_ohci_dma_mask; - - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return -ENOMEM; - - if (!of_property_read_u32(np, "num-ports", &ports)) - pdata->ports = ports; - - at91_for_each_port(i) { - gpio = of_get_named_gpio_flags(np, "atmel,vbus-gpio", i, &flags); - pdata->vbus_pin[i] = gpio; - if (!gpio_is_valid(gpio)) - continue; - pdata->vbus_pin_active_low[i] = flags & OF_GPIO_ACTIVE_LOW; - } - - at91_for_each_port(i) - pdata->overcurrent_pin[i] = - of_get_named_gpio_flags(np, "atmel,oc-gpio", i, &flags); - - pdev->dev.platform_data = pdata; - - return 0; -} -#else -static int __devinit ohci_at91_of_init(struct platform_device *pdev) -{ - return 0; -} -#endif - -/*-------------------------------------------------------------------------*/ - -static int __devinit ohci_hcd_at91_drv_probe(struct platform_device *pdev) -{ - struct at91_usbh_data *pdata; - int i; - int gpio; - int ret; - - ret = ohci_at91_of_init(pdev); - if (ret) - return ret; - - pdata = pdev->dev.platform_data; - - if (pdata) { - at91_for_each_port(i) { - if (!gpio_is_valid(pdata->vbus_pin[i])) - continue; - gpio = pdata->vbus_pin[i]; - - ret = gpio_request(gpio, "ohci_vbus"); - if (ret) { - dev_err(&pdev->dev, - "can't request vbus gpio %d\n", gpio); - continue; - } - ret = gpio_direction_output(gpio, - !pdata->vbus_pin_active_low[i]); - if (ret) { - dev_err(&pdev->dev, - "can't put vbus gpio %d as output %d\n", - gpio, !pdata->vbus_pin_active_low[i]); - gpio_free(gpio); - continue; - } - - ohci_at91_usb_set_power(pdata, i, 1); - } - - at91_for_each_port(i) { - if (!gpio_is_valid(pdata->overcurrent_pin[i])) - continue; - gpio = pdata->overcurrent_pin[i]; - - ret = gpio_request(gpio, "ohci_overcurrent"); - if (ret) { - dev_err(&pdev->dev, - "can't request overcurrent gpio %d\n", - gpio); - continue; - } - - ret = gpio_direction_input(gpio); - if (ret) { - dev_err(&pdev->dev, - "can't configure overcurrent gpio %d as input\n", - gpio); - gpio_free(gpio); - continue; - } - - ret = request_irq(gpio_to_irq(gpio), - ohci_hcd_at91_overcurrent_irq, - IRQF_SHARED, "ohci_overcurrent", pdev); - if (ret) { - gpio_free(gpio); - dev_err(&pdev->dev, - "can't get gpio IRQ for overcurrent\n"); - } - } - } - - device_init_wakeup(&pdev->dev, 1); - return usb_hcd_at91_probe(&ohci_at91_hc_driver, pdev); -} - -static int __devexit ohci_hcd_at91_drv_remove(struct platform_device *pdev) -{ - struct at91_usbh_data *pdata = pdev->dev.platform_data; - int i; - - if (pdata) { - at91_for_each_port(i) { - if (!gpio_is_valid(pdata->vbus_pin[i])) - continue; - ohci_at91_usb_set_power(pdata, i, 0); - gpio_free(pdata->vbus_pin[i]); - } - - at91_for_each_port(i) { - if (!gpio_is_valid(pdata->overcurrent_pin[i])) - continue; - free_irq(gpio_to_irq(pdata->overcurrent_pin[i]), pdev); - gpio_free(pdata->overcurrent_pin[i]); - } - } - - device_init_wakeup(&pdev->dev, 0); - usb_hcd_at91_remove(platform_get_drvdata(pdev), pdev); - return 0; -} - -#ifdef CONFIG_PM - -static int -ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - - if (device_may_wakeup(&pdev->dev)) - enable_irq_wake(hcd->irq); - - /* - * The integrated transceivers seem unable to notice disconnect, - * reconnect, or wakeup without the 48 MHz clock active. so for - * correctness, always discard connection state (using reset). - * - * REVISIT: some boards will be able to turn VBUS off... - */ - if (at91_suspend_entering_slow_clock()) { - ohci_usb_reset (ohci); - /* flush the writes */ - (void) ohci_readl (ohci, &ohci->regs->control); - at91_stop_clock(); - } - - return 0; -} - -static int ohci_hcd_at91_drv_resume(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - if (device_may_wakeup(&pdev->dev)) - disable_irq_wake(hcd->irq); - - if (!clocked) - at91_start_clock(); - - ohci_finish_controller_resume(hcd); - return 0; -} -#else -#define ohci_hcd_at91_drv_suspend NULL -#define ohci_hcd_at91_drv_resume NULL -#endif - -MODULE_ALIAS("platform:at91_ohci"); - -static struct platform_driver ohci_hcd_at91_driver = { - .probe = ohci_hcd_at91_drv_probe, - .remove = __devexit_p(ohci_hcd_at91_drv_remove), - .shutdown = usb_hcd_platform_shutdown, - .suspend = ohci_hcd_at91_drv_suspend, - .resume = ohci_hcd_at91_drv_resume, - .driver = { - .name = "at91_ohci", - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(at91_ohci_dt_ids), - }, -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-au1xxx.c b/ANDROID_3.4.5/drivers/usb/host/ohci-au1xxx.c deleted file mode 100644 index 4ea63b2c..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-au1xxx.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2002 David Brownell - * (C) Copyright 2002 Hewlett-Packard Company - * - * Bus Glue for AMD Alchemy Au1xxx - * - * Written by Christopher Hoover - * Based on fragments of previous driver by Russell King et al. - * - * Modified for LH7A404 from ohci-sa1111.c - * by Durgesh Pattamatta - * Modified for AMD Alchemy Au1xxx - * by Matt Porter - * - * This file is licenced under the GPL. - */ - -#include -#include - -#include - - -extern int usb_disabled(void); - -static int __devinit ohci_au1xxx_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - ohci_dbg(ohci, "ohci_au1xxx_start, ohci:%p", ohci); - - if ((ret = ohci_init(ohci)) < 0) - return ret; - - if ((ret = ohci_run(ohci)) < 0) { - err ("can't start %s", hcd->self.bus_name); - ohci_stop(hcd); - return ret; - } - - return 0; -} - -static const struct hc_driver ohci_au1xxx_hc_driver = { - .description = hcd_name, - .product_desc = "Au1xxx OHCI", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .start = ohci_au1xxx_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -static int ohci_hcd_au1xxx_drv_probe(struct platform_device *pdev) -{ - int ret, unit; - struct usb_hcd *hcd; - - if (usb_disabled()) - return -ENODEV; - - if (pdev->resource[1].flags != IORESOURCE_IRQ) { - pr_debug("resource[1] is not IORESOURCE_IRQ\n"); - return -ENOMEM; - } - - hcd = usb_create_hcd(&ohci_au1xxx_hc_driver, &pdev->dev, "au1xxx"); - if (!hcd) - return -ENOMEM; - - hcd->rsrc_start = pdev->resource[0].start; - hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - pr_debug("request_mem_region failed\n"); - ret = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - pr_debug("ioremap failed\n"); - ret = -ENOMEM; - goto err2; - } - - unit = (hcd->rsrc_start == AU1300_USB_OHCI1_PHYS_ADDR) ? - ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0; - if (alchemy_usb_control(unit, 1)) { - printk(KERN_INFO "%s: controller init failed!\n", pdev->name); - ret = -ENODEV; - goto err3; - } - - ohci_hcd_init(hcd_to_ohci(hcd)); - - ret = usb_add_hcd(hcd, pdev->resource[1].start, - IRQF_SHARED); - if (ret == 0) { - platform_set_drvdata(pdev, hcd); - return ret; - } - - alchemy_usb_control(unit, 0); -err3: - iounmap(hcd->regs); -err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err1: - usb_put_hcd(hcd); - return ret; -} - -static int ohci_hcd_au1xxx_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - int unit; - - unit = (hcd->rsrc_start == AU1300_USB_OHCI1_PHYS_ADDR) ? - ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0; - usb_remove_hcd(hcd); - alchemy_usb_control(unit, 0); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - platform_set_drvdata(pdev, NULL); - - return 0; -} - -#ifdef CONFIG_PM -static int ohci_hcd_au1xxx_drv_suspend(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - unsigned long flags; - int rc; - - rc = 0; - - /* Root hub was already suspended. Disable irq emission and - * mark HW unaccessible, bail out if RH has been resumed. Use - * the spinlock to properly synchronize with possible pending - * RH suspend or resume activity. - */ - spin_lock_irqsave(&ohci->lock, flags); - if (ohci->rh_state != OHCI_RH_SUSPENDED) { - rc = -EINVAL; - goto bail; - } - ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); - (void)ohci_readl(ohci, &ohci->regs->intrdisable); - - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - - alchemy_usb_control(ALCHEMY_USB_OHCI0, 0); -bail: - spin_unlock_irqrestore(&ohci->lock, flags); - - return rc; -} - -static int ohci_hcd_au1xxx_drv_resume(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - - alchemy_usb_control(ALCHEMY_USB_OHCI0, 1); - - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - ohci_finish_controller_resume(hcd); - - return 0; -} - -static const struct dev_pm_ops au1xxx_ohci_pmops = { - .suspend = ohci_hcd_au1xxx_drv_suspend, - .resume = ohci_hcd_au1xxx_drv_resume, -}; - -#define AU1XXX_OHCI_PMOPS &au1xxx_ohci_pmops - -#else -#define AU1XXX_OHCI_PMOPS NULL -#endif - -static struct platform_driver ohci_hcd_au1xxx_driver = { - .probe = ohci_hcd_au1xxx_drv_probe, - .remove = ohci_hcd_au1xxx_drv_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "au1xxx-ohci", - .owner = THIS_MODULE, - .pm = AU1XXX_OHCI_PMOPS, - }, -}; - -MODULE_ALIAS("platform:au1xxx-ohci"); diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-cns3xxx.c b/ANDROID_3.4.5/drivers/usb/host/ohci-cns3xxx.c deleted file mode 100644 index 5a00a1e1..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-cns3xxx.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright 2008 Cavium Networks - * - * This file 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. - */ - -#include -#include -#include -#include - -static int __devinit -cns3xxx_ohci_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - /* - * EHCI and OHCI share the same clock and power, - * resetting twice would cause the 1st controller been reset. - * Therefore only do power up at the first up device, and - * power down at the last down device. - * - * Set USB AHB INCR length to 16 - */ - if (atomic_inc_return(&usb_pwr_ref) == 1) { - cns3xxx_pwr_power_up(1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_PLL_USB); - cns3xxx_pwr_clk_en(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); - cns3xxx_pwr_soft_rst(1 << PM_SOFT_RST_REG_OFFST_USB_HOST); - __raw_writel((__raw_readl(MISC_CHIP_CONFIG_REG) | (0X2 << 24)), - MISC_CHIP_CONFIG_REG); - } - - ret = ohci_init(ohci); - if (ret < 0) - return ret; - - ohci->num_ports = 1; - - ret = ohci_run(ohci); - if (ret < 0) { - err("can't start %s", hcd->self.bus_name); - ohci_stop(hcd); - return ret; - } - return 0; -} - -static const struct hc_driver cns3xxx_ohci_hc_driver = { - .description = hcd_name, - .product_desc = "CNS3XXX OHCI Host controller", - .hcd_priv_size = sizeof(struct ohci_hcd), - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - .start = cns3xxx_ohci_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - .get_frame_number = ohci_get_frame, - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -static int cns3xxx_ohci_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct usb_hcd *hcd; - const struct hc_driver *driver = &cns3xxx_ohci_hc_driver; - struct resource *res; - int irq; - int retval; - - if (usb_disabled()) - return -ENODEV; - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(dev, "Found HC with no IRQ.\n"); - return -ENODEV; - } - irq = res->start; - - hcd = usb_create_hcd(driver, dev, dev_name(dev)); - if (!hcd) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "Found HC with no register addr.\n"); - retval = -ENODEV; - goto err1; - } - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) { - dev_dbg(dev, "controller already in use\n"); - retval = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - dev_dbg(dev, "error mapping memory\n"); - retval = -EFAULT; - goto err2; - } - - ohci_hcd_init(hcd_to_ohci(hcd)); - - retval = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (retval == 0) - return retval; - - iounmap(hcd->regs); -err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err1: - usb_put_hcd(hcd); - return retval; -} - -static int cns3xxx_ohci_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - - /* - * EHCI and OHCI share the same clock and power, - * resetting twice would cause the 1st controller been reset. - * Therefore only do power up at the first up device, and - * power down at the last down device. - */ - if (atomic_dec_return(&usb_pwr_ref) == 0) - cns3xxx_pwr_clk_dis(1 << PM_CLK_GATE_REG_OFFSET_USB_HOST); - - usb_put_hcd(hcd); - - platform_set_drvdata(pdev, NULL); - - return 0; -} - -MODULE_ALIAS("platform:cns3xxx-ohci"); - -static struct platform_driver ohci_hcd_cns3xxx_driver = { - .probe = cns3xxx_ohci_probe, - .remove = cns3xxx_ohci_remove, - .driver = { - .name = "cns3xxx-ohci", - }, -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-da8xx.c b/ANDROID_3.4.5/drivers/usb/host/ohci-da8xx.c deleted file mode 100644 index 84350977..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-da8xx.c +++ /dev/null @@ -1,456 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * TI DA8xx (OMAP-L1x) Bus Glue - * - * Derived from: ohci-omap.c and ohci-s3c2410.c - * Copyright (C) 2008-2009 MontaVista Software, Inc. - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -#include -#include -#include -#include - -#include -#include - -#ifndef CONFIG_ARCH_DAVINCI_DA8XX -#error "This file is DA8xx bus glue. Define CONFIG_ARCH_DAVINCI_DA8XX." -#endif - -#define CFGCHIP2 DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG) - -static struct clk *usb11_clk; -static struct clk *usb20_clk; - -/* Over-current indicator change bitmask */ -static volatile u16 ocic_mask; - -static void ohci_da8xx_clock(int on) -{ - u32 cfgchip2; - - cfgchip2 = __raw_readl(CFGCHIP2); - if (on) { - clk_enable(usb11_clk); - - /* - * If USB 1.1 reference clock is sourced from USB 2.0 PHY, we - * need to enable the USB 2.0 module clocking, start its PHY, - * and not allow it to stop the clock during USB 2.0 suspend. - */ - if (!(cfgchip2 & CFGCHIP2_USB1PHYCLKMUX)) { - clk_enable(usb20_clk); - - cfgchip2 &= ~(CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN); - cfgchip2 |= CFGCHIP2_PHY_PLLON; - __raw_writel(cfgchip2, CFGCHIP2); - - pr_info("Waiting for USB PHY clock good...\n"); - while (!(__raw_readl(CFGCHIP2) & CFGCHIP2_PHYCLKGD)) - cpu_relax(); - } - - /* Enable USB 1.1 PHY */ - cfgchip2 |= CFGCHIP2_USB1SUSPENDM; - } else { - clk_disable(usb11_clk); - if (!(cfgchip2 & CFGCHIP2_USB1PHYCLKMUX)) - clk_disable(usb20_clk); - - /* Disable USB 1.1 PHY */ - cfgchip2 &= ~CFGCHIP2_USB1SUSPENDM; - } - __raw_writel(cfgchip2, CFGCHIP2); -} - -/* - * Handle the port over-current indicator change. - */ -static void ohci_da8xx_ocic_handler(struct da8xx_ohci_root_hub *hub, - unsigned port) -{ - ocic_mask |= 1 << port; - - /* Once over-current is detected, the port needs to be powered down */ - if (hub->get_oci(port) > 0) - hub->set_power(port, 0); -} - -static int ohci_da8xx_init(struct usb_hcd *hcd) -{ - struct device *dev = hcd->self.controller; - struct da8xx_ohci_root_hub *hub = dev->platform_data; - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int result; - u32 rh_a; - - dev_dbg(dev, "starting USB controller\n"); - - ohci_da8xx_clock(1); - - /* - * DA8xx only have 1 port connected to the pins but the HC root hub - * register A reports 2 ports, thus we'll have to override it... - */ - ohci->num_ports = 1; - - result = ohci_init(ohci); - if (result < 0) - return result; - - /* - * Since we're providing a board-specific root hub port power control - * and over-current reporting, we have to override the HC root hub A - * register's default value, so that ohci_hub_control() could return - * the correct hub descriptor... - */ - rh_a = ohci_readl(ohci, &ohci->regs->roothub.a); - if (hub->set_power) { - rh_a &= ~RH_A_NPS; - rh_a |= RH_A_PSM; - } - if (hub->get_oci) { - rh_a &= ~RH_A_NOCP; - rh_a |= RH_A_OCPM; - } - rh_a &= ~RH_A_POTPGT; - rh_a |= hub->potpgt << 24; - ohci_writel(ohci, rh_a, &ohci->regs->roothub.a); - - return result; -} - -static void ohci_da8xx_stop(struct usb_hcd *hcd) -{ - ohci_stop(hcd); - ohci_da8xx_clock(0); -} - -static int ohci_da8xx_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int result; - - result = ohci_run(ohci); - if (result < 0) - ohci_da8xx_stop(hcd); - - return result; -} - -/* - * Update the status data from the hub with the over-current indicator change. - */ -static int ohci_da8xx_hub_status_data(struct usb_hcd *hcd, char *buf) -{ - int length = ohci_hub_status_data(hcd, buf); - - /* See if we have OCIC bit set on port 1 */ - if (ocic_mask & (1 << 1)) { - dev_dbg(hcd->self.controller, "over-current indicator change " - "on port 1\n"); - - if (!length) - length = 1; - - buf[0] |= 1 << 1; - } - return length; -} - -/* - * Look at the control requests to the root hub and see if we need to override. - */ -static int ohci_da8xx_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, - u16 wIndex, char *buf, u16 wLength) -{ - struct device *dev = hcd->self.controller; - struct da8xx_ohci_root_hub *hub = dev->platform_data; - int temp; - - switch (typeReq) { - case GetPortStatus: - /* Check the port number */ - if (wIndex != 1) - break; - - dev_dbg(dev, "GetPortStatus(%u)\n", wIndex); - - temp = roothub_portstatus(hcd_to_ohci(hcd), wIndex - 1); - - /* The port power status (PPS) bit defaults to 1 */ - if (hub->get_power && hub->get_power(wIndex) == 0) - temp &= ~RH_PS_PPS; - - /* The port over-current indicator (POCI) bit is always 0 */ - if (hub->get_oci && hub->get_oci(wIndex) > 0) - temp |= RH_PS_POCI; - - /* The over-current indicator change (OCIC) bit is 0 too */ - if (ocic_mask & (1 << wIndex)) - temp |= RH_PS_OCIC; - - put_unaligned(cpu_to_le32(temp), (__le32 *)buf); - return 0; - case SetPortFeature: - temp = 1; - goto check_port; - case ClearPortFeature: - temp = 0; - -check_port: - /* Check the port number */ - if (wIndex != 1) - break; - - switch (wValue) { - case USB_PORT_FEAT_POWER: - dev_dbg(dev, "%sPortFeature(%u): %s\n", - temp ? "Set" : "Clear", wIndex, "POWER"); - - if (!hub->set_power) - return -EPIPE; - - return hub->set_power(wIndex, temp) ? -EPIPE : 0; - case USB_PORT_FEAT_C_OVER_CURRENT: - dev_dbg(dev, "%sPortFeature(%u): %s\n", - temp ? "Set" : "Clear", wIndex, - "C_OVER_CURRENT"); - - if (temp) - ocic_mask |= 1 << wIndex; - else - ocic_mask &= ~(1 << wIndex); - return 0; - } - } - - return ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); -} - -static const struct hc_driver ohci_da8xx_hc_driver = { - .description = hcd_name, - .product_desc = "DA8xx OHCI", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .reset = ohci_da8xx_init, - .start = ohci_da8xx_start, - .stop = ohci_da8xx_stop, - .shutdown = ohci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_da8xx_hub_status_data, - .hub_control = ohci_da8xx_hub_control, - -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -/*-------------------------------------------------------------------------*/ - - -/** - * usb_hcd_da8xx_probe - initialize DA8xx-based HCDs - * Context: !in_interrupt() - * - * Allocates basic resources for this USB host controller, and - * then invokes the start() method for the HCD associated with it - * through the hotplug entry's driver_data. - */ -static int usb_hcd_da8xx_probe(const struct hc_driver *driver, - struct platform_device *pdev) -{ - struct da8xx_ohci_root_hub *hub = pdev->dev.platform_data; - struct usb_hcd *hcd; - struct resource *mem; - int error, irq; - - if (hub == NULL) - return -ENODEV; - - usb11_clk = clk_get(&pdev->dev, "usb11"); - if (IS_ERR(usb11_clk)) - return PTR_ERR(usb11_clk); - - usb20_clk = clk_get(&pdev->dev, "usb20"); - if (IS_ERR(usb20_clk)) { - error = PTR_ERR(usb20_clk); - goto err0; - } - - hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - error = -ENOMEM; - goto err1; - } - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - error = -ENODEV; - goto err2; - } - hcd->rsrc_start = mem->start; - hcd->rsrc_len = resource_size(mem); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - dev_dbg(&pdev->dev, "request_mem_region failed\n"); - error = -EBUSY; - goto err2; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - dev_err(&pdev->dev, "ioremap failed\n"); - error = -ENOMEM; - goto err3; - } - - ohci_hcd_init(hcd_to_ohci(hcd)); - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - error = -ENODEV; - goto err4; - } - error = usb_add_hcd(hcd, irq, 0); - if (error) - goto err4; - - if (hub->ocic_notify) { - error = hub->ocic_notify(ohci_da8xx_ocic_handler); - if (!error) - return 0; - } - - usb_remove_hcd(hcd); -err4: - iounmap(hcd->regs); -err3: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err2: - usb_put_hcd(hcd); -err1: - clk_put(usb20_clk); -err0: - clk_put(usb11_clk); - return error; -} - -/** - * usb_hcd_da8xx_remove - shutdown processing for DA8xx-based HCDs - * @dev: USB Host Controller being removed - * Context: !in_interrupt() - * - * Reverses the effect of usb_hcd_da8xx_probe(), first invoking - * the HCD's stop() method. It is always called from a thread - * context, normally "rmmod", "apmd", or something similar. - */ -static inline void -usb_hcd_da8xx_remove(struct usb_hcd *hcd, struct platform_device *pdev) -{ - struct da8xx_ohci_root_hub *hub = pdev->dev.platform_data; - - hub->ocic_notify(NULL); - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - clk_put(usb20_clk); - clk_put(usb11_clk); -} - -static int ohci_hcd_da8xx_drv_probe(struct platform_device *dev) -{ - return usb_hcd_da8xx_probe(&ohci_da8xx_hc_driver, dev); -} - -static int ohci_hcd_da8xx_drv_remove(struct platform_device *dev) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - - usb_hcd_da8xx_remove(hcd, dev); - platform_set_drvdata(dev, NULL); - - return 0; -} - -#ifdef CONFIG_PM -static int ohci_da8xx_suspend(struct platform_device *dev, pm_message_t message) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - - if (time_before(jiffies, ohci->next_statechange)) - msleep(5); - ohci->next_statechange = jiffies; - - ohci_da8xx_clock(0); - hcd->state = HC_STATE_SUSPENDED; - dev->dev.power.power_state = PMSG_SUSPEND; - return 0; -} - -static int ohci_da8xx_resume(struct platform_device *dev) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - - if (time_before(jiffies, ohci->next_statechange)) - msleep(5); - ohci->next_statechange = jiffies; - - ohci_da8xx_clock(1); - dev->dev.power.power_state = PMSG_ON; - usb_hcd_resume_root_hub(hcd); - return 0; -} -#endif - -/* - * Driver definition to register with platform structure. - */ -static struct platform_driver ohci_hcd_da8xx_driver = { - .probe = ohci_hcd_da8xx_drv_probe, - .remove = ohci_hcd_da8xx_drv_remove, - .shutdown = usb_hcd_platform_shutdown, -#ifdef CONFIG_PM - .suspend = ohci_da8xx_suspend, - .resume = ohci_da8xx_resume, -#endif - .driver = { - .owner = THIS_MODULE, - .name = "ohci", - }, -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-dbg.c b/ANDROID_3.4.5/drivers/usb/host/ohci-dbg.c deleted file mode 100644 index e4bcb62b..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-dbg.c +++ /dev/null @@ -1,877 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2002 David Brownell - * - * This file is licenced under the GPL. - */ - -/*-------------------------------------------------------------------------*/ - -#ifdef DEBUG - -#define edstring(ed_type) ({ char *temp; \ - switch (ed_type) { \ - case PIPE_CONTROL: temp = "ctrl"; break; \ - case PIPE_BULK: temp = "bulk"; break; \ - case PIPE_INTERRUPT: temp = "intr"; break; \ - default: temp = "isoc"; break; \ - }; temp;}) -#define pipestring(pipe) edstring(usb_pipetype(pipe)) - -/* debug| print the main components of an URB - * small: 0) header + data packets 1) just header - */ -static void __maybe_unused -urb_print(struct urb * urb, char * str, int small, int status) -{ - unsigned int pipe= urb->pipe; - - if (!urb->dev || !urb->dev->bus) { - dbg("%s URB: no dev", str); - return; - } - -#ifndef OHCI_VERBOSE_DEBUG - if (status != 0) -#endif - dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d", - str, - urb, - usb_pipedevice (pipe), - usb_pipeendpoint (pipe), - usb_pipeout (pipe)? "out" : "in", - pipestring (pipe), - urb->transfer_flags, - urb->actual_length, - urb->transfer_buffer_length, - status); - -#ifdef OHCI_VERBOSE_DEBUG - if (!small) { - int i, len; - - if (usb_pipecontrol (pipe)) { - printk (KERN_DEBUG "%s: setup(8):", __FILE__); - for (i = 0; i < 8 ; i++) - printk (" %02x", ((__u8 *) urb->setup_packet) [i]); - printk ("\n"); - } - if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) { - printk (KERN_DEBUG "%s: data(%d/%d):", __FILE__, - urb->actual_length, - urb->transfer_buffer_length); - len = usb_pipeout (pipe)? - urb->transfer_buffer_length: urb->actual_length; - for (i = 0; i < 16 && i < len; i++) - printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]); - printk ("%s stat:%d\n", i < len? "...": "", status); - } - } -#endif -} - -#define ohci_dbg_sw(ohci, next, size, format, arg...) \ - do { \ - if (next != NULL) { \ - unsigned s_len; \ - s_len = scnprintf (*next, *size, format, ## arg ); \ - *size -= s_len; *next += s_len; \ - } else \ - ohci_dbg(ohci,format, ## arg ); \ - } while (0); - -/* Version for use where "next" is the address of a local variable */ -#define ohci_dbg_nosw(ohci, next, size, format, arg...) \ - do { \ - unsigned s_len; \ - s_len = scnprintf(*next, *size, format, ## arg); \ - *size -= s_len; *next += s_len; \ - } while (0); - - -static void ohci_dump_intr_mask ( - struct ohci_hcd *ohci, - char *label, - u32 mask, - char **next, - unsigned *size) -{ - ohci_dbg_sw (ohci, next, size, "%s 0x%08x%s%s%s%s%s%s%s%s%s\n", - label, - mask, - (mask & OHCI_INTR_MIE) ? " MIE" : "", - (mask & OHCI_INTR_OC) ? " OC" : "", - (mask & OHCI_INTR_RHSC) ? " RHSC" : "", - (mask & OHCI_INTR_FNO) ? " FNO" : "", - (mask & OHCI_INTR_UE) ? " UE" : "", - (mask & OHCI_INTR_RD) ? " RD" : "", - (mask & OHCI_INTR_SF) ? " SF" : "", - (mask & OHCI_INTR_WDH) ? " WDH" : "", - (mask & OHCI_INTR_SO) ? " SO" : "" - ); -} - -static void maybe_print_eds ( - struct ohci_hcd *ohci, - char *label, - u32 value, - char **next, - unsigned *size) -{ - if (value) - ohci_dbg_sw (ohci, next, size, "%s %08x\n", label, value); -} - -static char *hcfs2string (int state) -{ - switch (state) { - case OHCI_USB_RESET: return "reset"; - case OHCI_USB_RESUME: return "resume"; - case OHCI_USB_OPER: return "operational"; - case OHCI_USB_SUSPEND: return "suspend"; - } - return "?"; -} - -static const char *rh_state_string(struct ohci_hcd *ohci) -{ - switch (ohci->rh_state) { - case OHCI_RH_HALTED: - return "halted"; - case OHCI_RH_SUSPENDED: - return "suspended"; - case OHCI_RH_RUNNING: - return "running"; - } - return "?"; -} - -// dump control and status registers -static void -ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size) -{ - struct ohci_regs __iomem *regs = controller->regs; - u32 temp; - - temp = ohci_readl (controller, ®s->revision) & 0xff; - ohci_dbg_sw (controller, next, size, - "OHCI %d.%d, %s legacy support registers, rh state %s\n", - 0x03 & (temp >> 4), (temp & 0x0f), - (temp & 0x0100) ? "with" : "NO", - rh_state_string(controller)); - - temp = ohci_readl (controller, ®s->control); - ohci_dbg_sw (controller, next, size, - "control 0x%03x%s%s%s HCFS=%s%s%s%s%s CBSR=%d\n", - temp, - (temp & OHCI_CTRL_RWE) ? " RWE" : "", - (temp & OHCI_CTRL_RWC) ? " RWC" : "", - (temp & OHCI_CTRL_IR) ? " IR" : "", - hcfs2string (temp & OHCI_CTRL_HCFS), - (temp & OHCI_CTRL_BLE) ? " BLE" : "", - (temp & OHCI_CTRL_CLE) ? " CLE" : "", - (temp & OHCI_CTRL_IE) ? " IE" : "", - (temp & OHCI_CTRL_PLE) ? " PLE" : "", - temp & OHCI_CTRL_CBSR - ); - - temp = ohci_readl (controller, ®s->cmdstatus); - ohci_dbg_sw (controller, next, size, - "cmdstatus 0x%05x SOC=%d%s%s%s%s\n", temp, - (temp & OHCI_SOC) >> 16, - (temp & OHCI_OCR) ? " OCR" : "", - (temp & OHCI_BLF) ? " BLF" : "", - (temp & OHCI_CLF) ? " CLF" : "", - (temp & OHCI_HCR) ? " HCR" : "" - ); - - ohci_dump_intr_mask (controller, "intrstatus", - ohci_readl (controller, ®s->intrstatus), - next, size); - ohci_dump_intr_mask (controller, "intrenable", - ohci_readl (controller, ®s->intrenable), - next, size); - // intrdisable always same as intrenable - - maybe_print_eds (controller, "ed_periodcurrent", - ohci_readl (controller, ®s->ed_periodcurrent), - next, size); - - maybe_print_eds (controller, "ed_controlhead", - ohci_readl (controller, ®s->ed_controlhead), - next, size); - maybe_print_eds (controller, "ed_controlcurrent", - ohci_readl (controller, ®s->ed_controlcurrent), - next, size); - - maybe_print_eds (controller, "ed_bulkhead", - ohci_readl (controller, ®s->ed_bulkhead), - next, size); - maybe_print_eds (controller, "ed_bulkcurrent", - ohci_readl (controller, ®s->ed_bulkcurrent), - next, size); - - maybe_print_eds (controller, "donehead", - ohci_readl (controller, ®s->donehead), next, size); -} - -#define dbg_port_sw(hc,num,value,next,size) \ - ohci_dbg_sw (hc, next, size, \ - "roothub.portstatus [%d] " \ - "0x%08x%s%s%s%s%s%s%s%s%s%s%s%s\n", \ - num, temp, \ - (temp & RH_PS_PRSC) ? " PRSC" : "", \ - (temp & RH_PS_OCIC) ? " OCIC" : "", \ - (temp & RH_PS_PSSC) ? " PSSC" : "", \ - (temp & RH_PS_PESC) ? " PESC" : "", \ - (temp & RH_PS_CSC) ? " CSC" : "", \ - \ - (temp & RH_PS_LSDA) ? " LSDA" : "", \ - (temp & RH_PS_PPS) ? " PPS" : "", \ - (temp & RH_PS_PRS) ? " PRS" : "", \ - (temp & RH_PS_POCI) ? " POCI" : "", \ - (temp & RH_PS_PSS) ? " PSS" : "", \ - \ - (temp & RH_PS_PES) ? " PES" : "", \ - (temp & RH_PS_CCS) ? " CCS" : "" \ - ); - - -static void -ohci_dump_roothub ( - struct ohci_hcd *controller, - int verbose, - char **next, - unsigned *size) -{ - u32 temp, i; - - temp = roothub_a (controller); - if (temp == ~(u32)0) - return; - - if (verbose) { - ohci_dbg_sw (controller, next, size, - "roothub.a %08x POTPGT=%d%s%s%s%s%s NDP=%d(%d)\n", temp, - ((temp & RH_A_POTPGT) >> 24) & 0xff, - (temp & RH_A_NOCP) ? " NOCP" : "", - (temp & RH_A_OCPM) ? " OCPM" : "", - (temp & RH_A_DT) ? " DT" : "", - (temp & RH_A_NPS) ? " NPS" : "", - (temp & RH_A_PSM) ? " PSM" : "", - (temp & RH_A_NDP), controller->num_ports - ); - temp = roothub_b (controller); - ohci_dbg_sw (controller, next, size, - "roothub.b %08x PPCM=%04x DR=%04x\n", - temp, - (temp & RH_B_PPCM) >> 16, - (temp & RH_B_DR) - ); - temp = roothub_status (controller); - ohci_dbg_sw (controller, next, size, - "roothub.status %08x%s%s%s%s%s%s\n", - temp, - (temp & RH_HS_CRWE) ? " CRWE" : "", - (temp & RH_HS_OCIC) ? " OCIC" : "", - (temp & RH_HS_LPSC) ? " LPSC" : "", - (temp & RH_HS_DRWE) ? " DRWE" : "", - (temp & RH_HS_OCI) ? " OCI" : "", - (temp & RH_HS_LPS) ? " LPS" : "" - ); - } - - for (i = 0; i < controller->num_ports; i++) { - temp = roothub_portstatus (controller, i); - dbg_port_sw (controller, i, temp, next, size); - } -} - -static void ohci_dump (struct ohci_hcd *controller, int verbose) -{ - ohci_dbg (controller, "OHCI controller state\n"); - - // dumps some of the state we know about - ohci_dump_status (controller, NULL, NULL); - if (controller->hcca) - ohci_dbg (controller, - "hcca frame #%04x\n", ohci_frame_no(controller)); - ohci_dump_roothub (controller, 1, NULL, NULL); -} - -static const char data0 [] = "DATA0"; -static const char data1 [] = "DATA1"; - -static void ohci_dump_td (const struct ohci_hcd *ohci, const char *label, - const struct td *td) -{ - u32 tmp = hc32_to_cpup (ohci, &td->hwINFO); - - ohci_dbg (ohci, "%s td %p%s; urb %p index %d; hw next td %08x\n", - label, td, - (tmp & TD_DONE) ? " (DONE)" : "", - td->urb, td->index, - hc32_to_cpup (ohci, &td->hwNextTD)); - if ((tmp & TD_ISO) == 0) { - const char *toggle, *pid; - u32 cbp, be; - - switch (tmp & TD_T) { - case TD_T_DATA0: toggle = data0; break; - case TD_T_DATA1: toggle = data1; break; - case TD_T_TOGGLE: toggle = "(CARRY)"; break; - default: toggle = "(?)"; break; - } - switch (tmp & TD_DP) { - case TD_DP_SETUP: pid = "SETUP"; break; - case TD_DP_IN: pid = "IN"; break; - case TD_DP_OUT: pid = "OUT"; break; - default: pid = "(bad pid)"; break; - } - ohci_dbg (ohci, " info %08x CC=%x %s DI=%d %s %s\n", tmp, - TD_CC_GET(tmp), /* EC, */ toggle, - (tmp & TD_DI) >> 21, pid, - (tmp & TD_R) ? "R" : ""); - cbp = hc32_to_cpup (ohci, &td->hwCBP); - be = hc32_to_cpup (ohci, &td->hwBE); - ohci_dbg (ohci, " cbp %08x be %08x (len %d)\n", cbp, be, - cbp ? (be + 1 - cbp) : 0); - } else { - unsigned i; - ohci_dbg (ohci, " info %08x CC=%x FC=%d DI=%d SF=%04x\n", tmp, - TD_CC_GET(tmp), - (tmp >> 24) & 0x07, - (tmp & TD_DI) >> 21, - tmp & 0x0000ffff); - ohci_dbg (ohci, " bp0 %08x be %08x\n", - hc32_to_cpup (ohci, &td->hwCBP) & ~0x0fff, - hc32_to_cpup (ohci, &td->hwBE)); - for (i = 0; i < MAXPSW; i++) { - u16 psw = ohci_hwPSW (ohci, td, i); - int cc = (psw >> 12) & 0x0f; - ohci_dbg (ohci, " psw [%d] = %2x, CC=%x %s=%d\n", i, - psw, cc, - (cc >= 0x0e) ? "OFFSET" : "SIZE", - psw & 0x0fff); - } - } -} - -/* caller MUST own hcd spinlock if verbose is set! */ -static void __maybe_unused -ohci_dump_ed (const struct ohci_hcd *ohci, const char *label, - const struct ed *ed, int verbose) -{ - u32 tmp = hc32_to_cpu (ohci, ed->hwINFO); - char *type = ""; - - ohci_dbg (ohci, "%s, ed %p state 0x%x type %s; next ed %08x\n", - label, - ed, ed->state, edstring (ed->type), - hc32_to_cpup (ohci, &ed->hwNextED)); - switch (tmp & (ED_IN|ED_OUT)) { - case ED_OUT: type = "-OUT"; break; - case ED_IN: type = "-IN"; break; - /* else from TDs ... control */ - } - ohci_dbg (ohci, - " info %08x MAX=%d%s%s%s%s EP=%d%s DEV=%d\n", tmp, - 0x03ff & (tmp >> 16), - (tmp & ED_DEQUEUE) ? " DQ" : "", - (tmp & ED_ISO) ? " ISO" : "", - (tmp & ED_SKIP) ? " SKIP" : "", - (tmp & ED_LOWSPEED) ? " LOW" : "", - 0x000f & (tmp >> 7), - type, - 0x007f & tmp); - tmp = hc32_to_cpup (ohci, &ed->hwHeadP); - ohci_dbg (ohci, " tds: head %08x %s%s tail %08x%s\n", - tmp, - (tmp & ED_C) ? data1 : data0, - (tmp & ED_H) ? " HALT" : "", - hc32_to_cpup (ohci, &ed->hwTailP), - verbose ? "" : " (not listing)"); - if (verbose) { - struct list_head *tmp; - - /* use ed->td_list because HC concurrently modifies - * hwNextTD as it accumulates ed_donelist. - */ - list_for_each (tmp, &ed->td_list) { - struct td *td; - td = list_entry (tmp, struct td, td_list); - ohci_dump_td (ohci, " ->", td); - } - } -} - -#else -static inline void ohci_dump (struct ohci_hcd *controller, int verbose) {} - -#undef OHCI_VERBOSE_DEBUG - -#endif /* DEBUG */ - -/*-------------------------------------------------------------------------*/ - -#ifdef STUB_DEBUG_FILES - -static inline void create_debug_files (struct ohci_hcd *bus) { } -static inline void remove_debug_files (struct ohci_hcd *bus) { } - -#else - -static int debug_async_open(struct inode *, struct file *); -static int debug_periodic_open(struct inode *, struct file *); -static int debug_registers_open(struct inode *, struct file *); -static int debug_async_open(struct inode *, struct file *); -static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*); -static int debug_close(struct inode *, struct file *); - -static const struct file_operations debug_async_fops = { - .owner = THIS_MODULE, - .open = debug_async_open, - .read = debug_output, - .release = debug_close, - .llseek = default_llseek, -}; -static const struct file_operations debug_periodic_fops = { - .owner = THIS_MODULE, - .open = debug_periodic_open, - .read = debug_output, - .release = debug_close, - .llseek = default_llseek, -}; -static const struct file_operations debug_registers_fops = { - .owner = THIS_MODULE, - .open = debug_registers_open, - .read = debug_output, - .release = debug_close, - .llseek = default_llseek, -}; - -static struct dentry *ohci_debug_root; - -struct debug_buffer { - ssize_t (*fill_func)(struct debug_buffer *); /* fill method */ - struct ohci_hcd *ohci; - struct mutex mutex; /* protect filling of buffer */ - size_t count; /* number of characters filled into buffer */ - char *page; -}; - -static ssize_t -show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed) -{ - unsigned temp, size = count; - - if (!ed) - return 0; - - /* print first --> last */ - while (ed->ed_prev) - ed = ed->ed_prev; - - /* dump a snapshot of the bulk or control schedule */ - while (ed) { - u32 info = hc32_to_cpu (ohci, ed->hwINFO); - u32 headp = hc32_to_cpu (ohci, ed->hwHeadP); - struct list_head *entry; - struct td *td; - - temp = scnprintf (buf, size, - "ed/%p %cs dev%d ep%d%s max %d %08x%s%s %s", - ed, - (info & ED_LOWSPEED) ? 'l' : 'f', - info & 0x7f, - (info >> 7) & 0xf, - (info & ED_IN) ? "in" : "out", - 0x03ff & (info >> 16), - info, - (info & ED_SKIP) ? " s" : "", - (headp & ED_H) ? " H" : "", - (headp & ED_C) ? data1 : data0); - size -= temp; - buf += temp; - - list_for_each (entry, &ed->td_list) { - u32 cbp, be; - - td = list_entry (entry, struct td, td_list); - info = hc32_to_cpup (ohci, &td->hwINFO); - cbp = hc32_to_cpup (ohci, &td->hwCBP); - be = hc32_to_cpup (ohci, &td->hwBE); - temp = scnprintf (buf, size, - "\n\ttd %p %s %d cc=%x urb %p (%08x)", - td, - ({ char *pid; - switch (info & TD_DP) { - case TD_DP_SETUP: pid = "setup"; break; - case TD_DP_IN: pid = "in"; break; - case TD_DP_OUT: pid = "out"; break; - default: pid = "(?)"; break; - } pid;}), - cbp ? (be + 1 - cbp) : 0, - TD_CC_GET (info), td->urb, info); - size -= temp; - buf += temp; - } - - temp = scnprintf (buf, size, "\n"); - size -= temp; - buf += temp; - - ed = ed->ed_next; - } - return count - size; -} - -static ssize_t fill_async_buffer(struct debug_buffer *buf) -{ - struct ohci_hcd *ohci; - size_t temp; - unsigned long flags; - - ohci = buf->ohci; - - /* display control and bulk lists together, for simplicity */ - spin_lock_irqsave (&ohci->lock, flags); - temp = show_list(ohci, buf->page, buf->count, ohci->ed_controltail); - temp += show_list(ohci, buf->page + temp, buf->count - temp, - ohci->ed_bulktail); - spin_unlock_irqrestore (&ohci->lock, flags); - - return temp; -} - -#define DBG_SCHED_LIMIT 64 - -static ssize_t fill_periodic_buffer(struct debug_buffer *buf) -{ - struct ohci_hcd *ohci; - struct ed **seen, *ed; - unsigned long flags; - unsigned temp, size, seen_count; - char *next; - unsigned i; - - if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, GFP_ATOMIC))) - return 0; - seen_count = 0; - - ohci = buf->ohci; - next = buf->page; - size = PAGE_SIZE; - - temp = scnprintf (next, size, "size = %d\n", NUM_INTS); - size -= temp; - next += temp; - - /* dump a snapshot of the periodic schedule (and load) */ - spin_lock_irqsave (&ohci->lock, flags); - for (i = 0; i < NUM_INTS; i++) { - if (!(ed = ohci->periodic [i])) - continue; - - temp = scnprintf (next, size, "%2d [%3d]:", i, ohci->load [i]); - size -= temp; - next += temp; - - do { - temp = scnprintf (next, size, " ed%d/%p", - ed->interval, ed); - size -= temp; - next += temp; - for (temp = 0; temp < seen_count; temp++) { - if (seen [temp] == ed) - break; - } - - /* show more info the first time around */ - if (temp == seen_count) { - u32 info = hc32_to_cpu (ohci, ed->hwINFO); - struct list_head *entry; - unsigned qlen = 0; - - /* qlen measured here in TDs, not urbs */ - list_for_each (entry, &ed->td_list) - qlen++; - - temp = scnprintf (next, size, - " (%cs dev%d ep%d%s-%s qlen %u" - " max %d %08x%s%s)", - (info & ED_LOWSPEED) ? 'l' : 'f', - info & 0x7f, - (info >> 7) & 0xf, - (info & ED_IN) ? "in" : "out", - (info & ED_ISO) ? "iso" : "int", - qlen, - 0x03ff & (info >> 16), - info, - (info & ED_SKIP) ? " K" : "", - (ed->hwHeadP & - cpu_to_hc32(ohci, ED_H)) ? - " H" : ""); - size -= temp; - next += temp; - - if (seen_count < DBG_SCHED_LIMIT) - seen [seen_count++] = ed; - - ed = ed->ed_next; - - } else { - /* we've seen it and what's after */ - temp = 0; - ed = NULL; - } - - } while (ed); - - temp = scnprintf (next, size, "\n"); - size -= temp; - next += temp; - } - spin_unlock_irqrestore (&ohci->lock, flags); - kfree (seen); - - return PAGE_SIZE - size; -} -#undef DBG_SCHED_LIMIT - -static ssize_t fill_registers_buffer(struct debug_buffer *buf) -{ - struct usb_hcd *hcd; - struct ohci_hcd *ohci; - struct ohci_regs __iomem *regs; - unsigned long flags; - unsigned temp, size; - char *next; - u32 rdata; - - ohci = buf->ohci; - hcd = ohci_to_hcd(ohci); - regs = ohci->regs; - next = buf->page; - size = PAGE_SIZE; - - spin_lock_irqsave (&ohci->lock, flags); - - /* dump driver info, then registers in spec order */ - - ohci_dbg_nosw(ohci, &next, &size, - "bus %s, device %s\n" - "%s\n" - "%s\n", - hcd->self.controller->bus->name, - dev_name(hcd->self.controller), - hcd->product_desc, - hcd_name); - - if (!HCD_HW_ACCESSIBLE(hcd)) { - size -= scnprintf (next, size, - "SUSPENDED (no register access)\n"); - goto done; - } - - ohci_dump_status(ohci, &next, &size); - - /* hcca */ - if (ohci->hcca) - ohci_dbg_nosw(ohci, &next, &size, - "hcca frame 0x%04x\n", ohci_frame_no(ohci)); - - /* other registers mostly affect frame timings */ - rdata = ohci_readl (ohci, ®s->fminterval); - temp = scnprintf (next, size, - "fmintvl 0x%08x %sFSMPS=0x%04x FI=0x%04x\n", - rdata, (rdata >> 31) ? "FIT " : "", - (rdata >> 16) & 0xefff, rdata & 0xffff); - size -= temp; - next += temp; - - rdata = ohci_readl (ohci, ®s->fmremaining); - temp = scnprintf (next, size, "fmremaining 0x%08x %sFR=0x%04x\n", - rdata, (rdata >> 31) ? "FRT " : "", - rdata & 0x3fff); - size -= temp; - next += temp; - - rdata = ohci_readl (ohci, ®s->periodicstart); - temp = scnprintf (next, size, "periodicstart 0x%04x\n", - rdata & 0x3fff); - size -= temp; - next += temp; - - rdata = ohci_readl (ohci, ®s->lsthresh); - temp = scnprintf (next, size, "lsthresh 0x%04x\n", - rdata & 0x3fff); - size -= temp; - next += temp; - - temp = scnprintf (next, size, "hub poll timer %s\n", - HCD_POLL_RH(ohci_to_hcd(ohci)) ? "ON" : "off"); - size -= temp; - next += temp; - - /* roothub */ - ohci_dump_roothub (ohci, 1, &next, &size); - -done: - spin_unlock_irqrestore (&ohci->lock, flags); - - return PAGE_SIZE - size; -} - -static struct debug_buffer *alloc_buffer(struct ohci_hcd *ohci, - ssize_t (*fill_func)(struct debug_buffer *)) -{ - struct debug_buffer *buf; - - buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL); - - if (buf) { - buf->ohci = ohci; - buf->fill_func = fill_func; - mutex_init(&buf->mutex); - } - - return buf; -} - -static int fill_buffer(struct debug_buffer *buf) -{ - int ret = 0; - - if (!buf->page) - buf->page = (char *)get_zeroed_page(GFP_KERNEL); - - if (!buf->page) { - ret = -ENOMEM; - goto out; - } - - ret = buf->fill_func(buf); - - if (ret >= 0) { - buf->count = ret; - ret = 0; - } - -out: - return ret; -} - -static ssize_t debug_output(struct file *file, char __user *user_buf, - size_t len, loff_t *offset) -{ - struct debug_buffer *buf = file->private_data; - int ret = 0; - - mutex_lock(&buf->mutex); - if (buf->count == 0) { - ret = fill_buffer(buf); - if (ret != 0) { - mutex_unlock(&buf->mutex); - goto out; - } - } - mutex_unlock(&buf->mutex); - - ret = simple_read_from_buffer(user_buf, len, offset, - buf->page, buf->count); - -out: - return ret; - -} - -static int debug_close(struct inode *inode, struct file *file) -{ - struct debug_buffer *buf = file->private_data; - - if (buf) { - if (buf->page) - free_page((unsigned long)buf->page); - kfree(buf); - } - - return 0; -} -static int debug_async_open(struct inode *inode, struct file *file) -{ - file->private_data = alloc_buffer(inode->i_private, fill_async_buffer); - - return file->private_data ? 0 : -ENOMEM; -} - -static int debug_periodic_open(struct inode *inode, struct file *file) -{ - file->private_data = alloc_buffer(inode->i_private, - fill_periodic_buffer); - - return file->private_data ? 0 : -ENOMEM; -} - -static int debug_registers_open(struct inode *inode, struct file *file) -{ - file->private_data = alloc_buffer(inode->i_private, - fill_registers_buffer); - - return file->private_data ? 0 : -ENOMEM; -} -static inline void create_debug_files (struct ohci_hcd *ohci) -{ - struct usb_bus *bus = &ohci_to_hcd(ohci)->self; - - 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, ohci, - &debug_async_fops); - if (!ohci->debug_async) - goto async_error; - - ohci->debug_periodic = debugfs_create_file("periodic", S_IRUGO, - 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, ohci, - &debug_registers_fops); - if (!ohci->debug_registers) - goto registers_error; - - ohci_dbg (ohci, "created debug files\n"); - return; - -registers_error: - debugfs_remove(ohci->debug_periodic); -periodic_error: - debugfs_remove(ohci->debug_async); -async_error: - debugfs_remove(ohci->debug_dir); -dir_error: - ohci->debug_periodic = NULL; - ohci->debug_async = NULL; - ohci->debug_dir = NULL; -} - -static inline void remove_debug_files (struct ohci_hcd *ohci) -{ - debugfs_remove(ohci->debug_registers); - debugfs_remove(ohci->debug_periodic); - debugfs_remove(ohci->debug_async); - debugfs_remove(ohci->debug_dir); -} - -#endif - -/*-------------------------------------------------------------------------*/ - diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-ep93xx.c b/ANDROID_3.4.5/drivers/usb/host/ohci-ep93xx.c deleted file mode 100644 index 3d63574d..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-ep93xx.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2002 David Brownell - * (C) Copyright 2002 Hewlett-Packard Company - * - * Bus Glue for ep93xx. - * - * Written by Christopher Hoover - * Based on fragments of previous driver by Russell King et al. - * - * Modified for LH7A404 from ohci-sa1111.c - * by Durgesh Pattamatta - * - * Modified for pxa27x from ohci-lh7a404.c - * by Nick Bane 26-8-2004 - * - * Modified for ep93xx from ohci-pxa27x.c - * by Lennert Buytenhek 28-2-2006 - * Based on an earlier driver by Ray Lehtiniemi - * - * This file is licenced under the GPL. - */ - -#include -#include -#include -#include - -static struct clk *usb_host_clock; - -static void ep93xx_start_hc(struct device *dev) -{ - clk_enable(usb_host_clock); -} - -static void ep93xx_stop_hc(struct device *dev) -{ - clk_disable(usb_host_clock); -} - -static int usb_hcd_ep93xx_probe(const struct hc_driver *driver, - struct platform_device *pdev) -{ - int retval; - struct usb_hcd *hcd; - - if (pdev->resource[1].flags != IORESOURCE_IRQ) { - dbg("resource[1] is not IORESOURCE_IRQ"); - return -ENOMEM; - } - - hcd = usb_create_hcd(driver, &pdev->dev, "ep93xx"); - if (hcd == NULL) - return -ENOMEM; - - hcd->rsrc_start = pdev->resource[0].start; - hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - usb_put_hcd(hcd); - retval = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (hcd->regs == NULL) { - dbg("ioremap failed"); - retval = -ENOMEM; - goto err2; - } - - usb_host_clock = clk_get(&pdev->dev, NULL); - if (IS_ERR(usb_host_clock)) { - dbg("clk_get failed"); - retval = PTR_ERR(usb_host_clock); - goto err3; - } - - ep93xx_start_hc(&pdev->dev); - - ohci_hcd_init(hcd_to_ohci(hcd)); - - retval = usb_add_hcd(hcd, pdev->resource[1].start, 0); - if (retval == 0) - return retval; - - ep93xx_stop_hc(&pdev->dev); -err3: - iounmap(hcd->regs); -err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err1: - usb_put_hcd(hcd); - - return retval; -} - -static void usb_hcd_ep93xx_remove(struct usb_hcd *hcd, - struct platform_device *pdev) -{ - usb_remove_hcd(hcd); - ep93xx_stop_hc(&pdev->dev); - clk_put(usb_host_clock); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); -} - -static int __devinit ohci_ep93xx_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - if ((ret = ohci_init(ohci)) < 0) - return ret; - - if ((ret = ohci_run(ohci)) < 0) { - err("can't start %s", hcd->self.bus_name); - ohci_stop(hcd); - return ret; - } - - return 0; -} - -static struct hc_driver ohci_ep93xx_hc_driver = { - .description = hcd_name, - .product_desc = "EP93xx OHCI", - .hcd_priv_size = sizeof(struct ohci_hcd), - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - .start = ohci_ep93xx_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - .get_frame_number = ohci_get_frame, - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -extern int usb_disabled(void); - -static int ohci_hcd_ep93xx_drv_probe(struct platform_device *pdev) -{ - int ret; - - ret = -ENODEV; - if (!usb_disabled()) - ret = usb_hcd_ep93xx_probe(&ohci_ep93xx_hc_driver, pdev); - - return ret; -} - -static int ohci_hcd_ep93xx_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_hcd_ep93xx_remove(hcd, pdev); - - return 0; -} - -#ifdef CONFIG_PM -static int ohci_hcd_ep93xx_drv_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - - if (time_before(jiffies, ohci->next_statechange)) - msleep(5); - ohci->next_statechange = jiffies; - - ep93xx_stop_hc(&pdev->dev); - return 0; -} - -static int ohci_hcd_ep93xx_drv_resume(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - - if (time_before(jiffies, ohci->next_statechange)) - msleep(5); - ohci->next_statechange = jiffies; - - ep93xx_start_hc(&pdev->dev); - - ohci_finish_controller_resume(hcd); - return 0; -} -#endif - - -static struct platform_driver ohci_hcd_ep93xx_driver = { - .probe = ohci_hcd_ep93xx_drv_probe, - .remove = ohci_hcd_ep93xx_drv_remove, - .shutdown = usb_hcd_platform_shutdown, -#ifdef CONFIG_PM - .suspend = ohci_hcd_ep93xx_drv_suspend, - .resume = ohci_hcd_ep93xx_drv_resume, -#endif - .driver = { - .name = "ep93xx-ohci", - .owner = THIS_MODULE, - }, -}; - -MODULE_ALIAS("platform:ep93xx-ohci"); diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-exynos.c b/ANDROID_3.4.5/drivers/usb/host/ohci-exynos.c deleted file mode 100644 index 37bb20eb..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-exynos.c +++ /dev/null @@ -1,272 +0,0 @@ -/* - * SAMSUNG EXYNOS USB HOST OHCI Controller - * - * Copyright (C) 2011 Samsung Electronics Co.Ltd - * Author: Jingoo Han - * - * 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 -#include -#include -#include - -struct exynos_ohci_hcd { - struct device *dev; - struct usb_hcd *hcd; - struct clk *clk; -}; - -static int ohci_exynos_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - ohci_dbg(ohci, "ohci_exynos_start, ohci:%p", ohci); - - ret = ohci_init(ohci); - if (ret < 0) - return ret; - - ret = ohci_run(ohci); - if (ret < 0) { - err("can't start %s", hcd->self.bus_name); - ohci_stop(hcd); - return ret; - } - - return 0; -} - -static const struct hc_driver exynos_ohci_hc_driver = { - .description = hcd_name, - .product_desc = "EXYNOS OHCI Host Controller", - .hcd_priv_size = sizeof(struct ohci_hcd), - - .irq = ohci_irq, - .flags = HCD_MEMORY|HCD_USB11, - - .start = ohci_exynos_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - .get_frame_number = ohci_get_frame, - - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -static int __devinit exynos_ohci_probe(struct platform_device *pdev) -{ - struct exynos4_ohci_platdata *pdata; - struct exynos_ohci_hcd *exynos_ohci; - struct usb_hcd *hcd; - struct ohci_hcd *ohci; - struct resource *res; - int irq; - int err; - - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "No platform data defined\n"); - return -EINVAL; - } - - exynos_ohci = kzalloc(sizeof(struct exynos_ohci_hcd), GFP_KERNEL); - if (!exynos_ohci) - return -ENOMEM; - - exynos_ohci->dev = &pdev->dev; - - hcd = usb_create_hcd(&exynos_ohci_hc_driver, &pdev->dev, - dev_name(&pdev->dev)); - if (!hcd) { - dev_err(&pdev->dev, "Unable to create HCD\n"); - err = -ENOMEM; - goto fail_hcd; - } - - exynos_ohci->hcd = hcd; - exynos_ohci->clk = clk_get(&pdev->dev, "usbhost"); - - if (IS_ERR(exynos_ohci->clk)) { - dev_err(&pdev->dev, "Failed to get usbhost clock\n"); - err = PTR_ERR(exynos_ohci->clk); - goto fail_clk; - } - - err = clk_enable(exynos_ohci->clk); - if (err) - goto fail_clken; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Failed to get I/O memory\n"); - err = -ENXIO; - goto fail_io; - } - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - hcd->regs = ioremap(res->start, resource_size(res)); - if (!hcd->regs) { - dev_err(&pdev->dev, "Failed to remap I/O memory\n"); - err = -ENOMEM; - goto fail_io; - } - - irq = platform_get_irq(pdev, 0); - if (!irq) { - dev_err(&pdev->dev, "Failed to get IRQ\n"); - err = -ENODEV; - goto fail; - } - - if (pdata->phy_init) - pdata->phy_init(pdev, S5P_USB_PHY_HOST); - - ohci = hcd_to_ohci(hcd); - ohci_hcd_init(ohci); - - err = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (err) { - dev_err(&pdev->dev, "Failed to add USB HCD\n"); - goto fail; - } - - platform_set_drvdata(pdev, exynos_ohci); - - return 0; - -fail: - iounmap(hcd->regs); -fail_io: - clk_disable(exynos_ohci->clk); -fail_clken: - clk_put(exynos_ohci->clk); -fail_clk: - usb_put_hcd(hcd); -fail_hcd: - kfree(exynos_ohci); - return err; -} - -static int __devexit exynos_ohci_remove(struct platform_device *pdev) -{ - struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data; - struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev); - struct usb_hcd *hcd = exynos_ohci->hcd; - - usb_remove_hcd(hcd); - - if (pdata && pdata->phy_exit) - pdata->phy_exit(pdev, S5P_USB_PHY_HOST); - - iounmap(hcd->regs); - - clk_disable(exynos_ohci->clk); - clk_put(exynos_ohci->clk); - - usb_put_hcd(hcd); - kfree(exynos_ohci); - - return 0; -} - -static void exynos_ohci_shutdown(struct platform_device *pdev) -{ - struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev); - struct usb_hcd *hcd = exynos_ohci->hcd; - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - -#ifdef CONFIG_PM -static int exynos_ohci_suspend(struct device *dev) -{ - struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev); - struct usb_hcd *hcd = exynos_ohci->hcd; - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - struct platform_device *pdev = to_platform_device(dev); - struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data; - unsigned long flags; - int rc = 0; - - /* - * Root hub was already suspended. Disable irq emission and - * mark HW unaccessible, bail out if RH has been resumed. Use - * the spinlock to properly synchronize with possible pending - * RH suspend or resume activity. - */ - spin_lock_irqsave(&ohci->lock, flags); - if (ohci->rh_state != OHCI_RH_SUSPENDED && - ohci->rh_state != OHCI_RH_HALTED) { - rc = -EINVAL; - goto fail; - } - - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - - if (pdata && pdata->phy_exit) - pdata->phy_exit(pdev, S5P_USB_PHY_HOST); -fail: - spin_unlock_irqrestore(&ohci->lock, flags); - - return rc; -} - -static int exynos_ohci_resume(struct device *dev) -{ - struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev); - struct usb_hcd *hcd = exynos_ohci->hcd; - struct platform_device *pdev = to_platform_device(dev); - struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data; - - if (pdata && pdata->phy_init) - pdata->phy_init(pdev, S5P_USB_PHY_HOST); - - /* Mark hardware accessible again as we are out of D3 state by now */ - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - - ohci_finish_controller_resume(hcd); - - return 0; -} -#else -#define exynos_ohci_suspend NULL -#define exynos_ohci_resume NULL -#endif - -static const struct dev_pm_ops exynos_ohci_pm_ops = { - .suspend = exynos_ohci_suspend, - .resume = exynos_ohci_resume, -}; - -static struct platform_driver exynos_ohci_driver = { - .probe = exynos_ohci_probe, - .remove = __devexit_p(exynos_ohci_remove), - .shutdown = exynos_ohci_shutdown, - .driver = { - .name = "exynos-ohci", - .owner = THIS_MODULE, - .pm = &exynos_ohci_pm_ops, - } -}; - -MODULE_ALIAS("platform:exynos-ohci"); -MODULE_AUTHOR("Jingoo Han "); diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-hcd.c b/ANDROID_3.4.5/drivers/usb/host/ohci-hcd.c deleted file mode 100644 index 235171f2..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-hcd.c +++ /dev/null @@ -1,1305 +0,0 @@ -/* - * Open Host Controller Interface (OHCI) driver for USB. - * - * Maintainer: Alan Stern - * - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2004 David Brownell - * - * [ Initialisation is based on Linus' ] - * [ uhci code and gregs ohci fragments ] - * [ (C) Copyright 1999 Linus Torvalds ] - * [ (C) Copyright 1999 Gregory P. Smith] - * - * - * OHCI is the main "non-Intel/VIA" standard for USB 1.1 host controller - * interfaces (though some non-x86 Intel chips use it). It supports - * smarter hardware than UHCI. A download link for the spec available - * through the http://www.usb.org website. - * - * This file is licenced under the GPL. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - - -#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell" -#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver" - -/*-------------------------------------------------------------------------*/ - -#undef OHCI_VERBOSE_DEBUG /* not always helpful */ - -/* For initializing controller (mask in an HCFS mode too) */ -#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR -#define OHCI_INTR_INIT \ - (OHCI_INTR_MIE | OHCI_INTR_RHSC | OHCI_INTR_UE \ - | OHCI_INTR_RD | OHCI_INTR_WDH) - -#ifdef __hppa__ -/* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */ -#define IR_DISABLE -#endif - -#ifdef CONFIG_ARCH_OMAP -/* OMAP doesn't support IR (no SMM; not needed) */ -#define IR_DISABLE -#endif - -/*-------------------------------------------------------------------------*/ - -static const char hcd_name [] = "ohci_hcd"; - -#define STATECHANGE_DELAY msecs_to_jiffies(300) - -#include "ohci.h" -#include "pci-quirks.h" - -static void ohci_dump (struct ohci_hcd *ohci, int verbose); -static int ohci_init (struct ohci_hcd *ohci); -static void ohci_stop (struct usb_hcd *hcd); - -#if defined(CONFIG_PM) || defined(CONFIG_PCI) -static int ohci_restart (struct ohci_hcd *ohci); -#endif - -#ifdef CONFIG_PCI -static void sb800_prefetch(struct ohci_hcd *ohci, int on); -#else -static inline void sb800_prefetch(struct ohci_hcd *ohci, int on) -{ - return; -} -#endif - - -#include "ohci-hub.c" -#include "ohci-dbg.c" -#include "ohci-mem.c" -#include "ohci-q.c" - - -/* - * On architectures with edge-triggered interrupts we must never return - * IRQ_NONE. - */ -#if defined(CONFIG_SA1111) /* ... or other edge-triggered systems */ -#define IRQ_NOTMINE IRQ_HANDLED -#else -#define IRQ_NOTMINE IRQ_NONE -#endif - - -/* Some boards misreport power switching/overcurrent */ -static bool distrust_firmware = 1; -module_param (distrust_firmware, bool, 0); -MODULE_PARM_DESC (distrust_firmware, - "true to distrust firmware power/overcurrent setup"); - -/* Some boards leave IR set wrongly, since they fail BIOS/SMM handshakes */ -static bool no_handshake = 0; -module_param (no_handshake, bool, 0); -MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake"); - -/*-------------------------------------------------------------------------*/ - -/* - * queue up an urb for anything except the root hub - */ -static int ohci_urb_enqueue ( - struct usb_hcd *hcd, - struct urb *urb, - gfp_t mem_flags -) { - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - struct ed *ed; - urb_priv_t *urb_priv; - unsigned int pipe = urb->pipe; - int i, size = 0; - unsigned long flags; - int retval = 0; - -#ifdef OHCI_VERBOSE_DEBUG - urb_print(urb, "SUB", usb_pipein(pipe), -EINPROGRESS); -#endif - - /* every endpoint has a ed, locate and maybe (re)initialize it */ - if (! (ed = ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval))) - return -ENOMEM; - - /* for the private part of the URB we need the number of TDs (size) */ - switch (ed->type) { - case PIPE_CONTROL: - /* td_submit_urb() doesn't yet handle these */ - if (urb->transfer_buffer_length > 4096) - return -EMSGSIZE; - - /* 1 TD for setup, 1 for ACK, plus ... */ - size = 2; - /* FALLTHROUGH */ - // case PIPE_INTERRUPT: - // case PIPE_BULK: - default: - /* one TD for every 4096 Bytes (can be up to 8K) */ - size += urb->transfer_buffer_length / 4096; - /* ... and for any remaining bytes ... */ - if ((urb->transfer_buffer_length % 4096) != 0) - size++; - /* ... and maybe a zero length packet to wrap it up */ - if (size == 0) - size++; - else if ((urb->transfer_flags & URB_ZERO_PACKET) != 0 - && (urb->transfer_buffer_length - % usb_maxpacket (urb->dev, pipe, - usb_pipeout (pipe))) == 0) - size++; - break; - case PIPE_ISOCHRONOUS: /* number of packets from URB */ - size = urb->number_of_packets; - break; - } - - /* allocate the private part of the URB */ - urb_priv = kzalloc (sizeof (urb_priv_t) + size * sizeof (struct td *), - mem_flags); - if (!urb_priv) - return -ENOMEM; - INIT_LIST_HEAD (&urb_priv->pending); - urb_priv->length = size; - urb_priv->ed = ed; - - /* allocate the TDs (deferring hash chain updates) */ - for (i = 0; i < size; i++) { - urb_priv->td [i] = td_alloc (ohci, mem_flags); - if (!urb_priv->td [i]) { - urb_priv->length = i; - urb_free_priv (ohci, urb_priv); - return -ENOMEM; - } - } - - spin_lock_irqsave (&ohci->lock, flags); - - /* don't submit to a dead HC */ - if (!HCD_HW_ACCESSIBLE(hcd)) { - retval = -ENODEV; - goto fail; - } - if (ohci->rh_state != OHCI_RH_RUNNING) { - retval = -ENODEV; - goto fail; - } - retval = usb_hcd_link_urb_to_ep(hcd, urb); - if (retval) - goto fail; - - /* schedule the ed if needed */ - if (ed->state == ED_IDLE) { - retval = ed_schedule (ohci, ed); - if (retval < 0) { - usb_hcd_unlink_urb_from_ep(hcd, urb); - goto fail; - } - if (ed->type == PIPE_ISOCHRONOUS) { - u16 frame = ohci_frame_no(ohci); - - /* delay a few frames before the first TD */ - frame += max_t (u16, 8, ed->interval); - frame &= ~(ed->interval - 1); - frame |= ed->branch; - urb->start_frame = frame; - - /* yes, only URB_ISO_ASAP is supported, and - * urb->start_frame is never used as input. - */ - } - } else if (ed->type == PIPE_ISOCHRONOUS) - urb->start_frame = ed->last_iso + ed->interval; - - /* fill the TDs and link them to the ed; and - * enable that part of the schedule, if needed - * and update count of queued periodic urbs - */ - urb->hcpriv = urb_priv; - td_submit_urb (ohci, urb); - -fail: - if (retval) - urb_free_priv (ohci, urb_priv); - spin_unlock_irqrestore (&ohci->lock, flags); - return retval; -} - -/* - * decouple the URB from the HC queues (TDs, urb_priv). - * reporting is always done - * asynchronously, and we might be dealing with an urb that's - * partially transferred, or an ED with other urbs being unlinked. - */ -static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - unsigned long flags; - int rc; - -#ifdef OHCI_VERBOSE_DEBUG - urb_print(urb, "UNLINK", 1, status); -#endif - - spin_lock_irqsave (&ohci->lock, flags); - rc = usb_hcd_check_unlink_urb(hcd, urb, status); - if (rc) { - ; /* Do nothing */ - } else if (ohci->rh_state == OHCI_RH_RUNNING) { - urb_priv_t *urb_priv; - - /* Unless an IRQ completed the unlink while it was being - * handed to us, flag it for unlink and giveback, and force - * some upcoming INTR_SF to call finish_unlinks() - */ - urb_priv = urb->hcpriv; - if (urb_priv) { - if (urb_priv->ed->state == ED_OPER) - start_ed_unlink (ohci, urb_priv->ed); - } - } else { - /* - * with HC dead, we won't respect hc queue pointers - * any more ... just clean up every urb's memory. - */ - if (urb->hcpriv) - finish_urb(ohci, urb, status); - } - spin_unlock_irqrestore (&ohci->lock, flags); - return rc; -} - -/*-------------------------------------------------------------------------*/ - -/* frees config/altsetting state for endpoints, - * including ED memory, dummy TD, and bulk/intr data toggle - */ - -static void -ohci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - unsigned long flags; - struct ed *ed = ep->hcpriv; - unsigned limit = 1000; - - /* ASSERT: any requests/urbs are being unlinked */ - /* ASSERT: nobody can be submitting urbs for this any more */ - - if (!ed) - return; - -rescan: - spin_lock_irqsave (&ohci->lock, flags); - - if (ohci->rh_state != OHCI_RH_RUNNING) { -sanitize: - ed->state = ED_IDLE; - if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) - ohci->eds_scheduled--; - finish_unlinks (ohci, 0); - } - - switch (ed->state) { - case ED_UNLINK: /* wait for hw to finish? */ - /* major IRQ delivery trouble loses INTR_SF too... */ - if (limit-- == 0) { - ohci_warn(ohci, "ED unlink timeout\n"); - if (quirk_zfmicro(ohci)) { - ohci_warn(ohci, "Attempting ZF TD recovery\n"); - ohci->ed_to_check = ed; - ohci->zf_delay = 2; - } - goto sanitize; - } - spin_unlock_irqrestore (&ohci->lock, flags); - schedule_timeout_uninterruptible(1); - goto rescan; - case ED_IDLE: /* fully unlinked */ - if (list_empty (&ed->td_list)) { - td_free (ohci, ed->dummy); - ed_free (ohci, ed); - break; - } - /* else FALL THROUGH */ - default: - /* caller was supposed to have unlinked any requests; - * that's not our job. can't recover; must leak ed. - */ - ohci_err (ohci, "leak ed %p (#%02x) state %d%s\n", - ed, ep->desc.bEndpointAddress, ed->state, - list_empty (&ed->td_list) ? "" : " (has tds)"); - td_free (ohci, ed->dummy); - break; - } - ep->hcpriv = NULL; - spin_unlock_irqrestore (&ohci->lock, flags); -} - -static int ohci_get_frame (struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - - return ohci_frame_no(ohci); -} - -static void ohci_usb_reset (struct ohci_hcd *ohci) -{ - ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); - ohci->hc_control &= OHCI_CTRL_RWC; - ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); - ohci->rh_state = OHCI_RH_HALTED; -} - -/* ohci_shutdown forcibly disables IRQs and DMA, helping kexec and - * other cases where the next software may expect clean state from the - * "firmware". this is bus-neutral, unlike shutdown() methods. - */ -static void -ohci_shutdown (struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci; - - ohci = hcd_to_ohci (hcd); - ohci_writel(ohci, (u32) ~0, &ohci->regs->intrdisable); - - /* Software reset, after which the controller goes into SUSPEND */ - ohci_writel(ohci, OHCI_HCR, &ohci->regs->cmdstatus); - ohci_readl(ohci, &ohci->regs->cmdstatus); /* flush the writes */ - udelay(10); - - ohci_writel(ohci, ohci->fminterval, &ohci->regs->fminterval); -} - -static int check_ed(struct ohci_hcd *ohci, struct ed *ed) -{ - return (hc32_to_cpu(ohci, ed->hwINFO) & ED_IN) != 0 - && (hc32_to_cpu(ohci, ed->hwHeadP) & TD_MASK) - == (hc32_to_cpu(ohci, ed->hwTailP) & TD_MASK) - && !list_empty(&ed->td_list); -} - -/* ZF Micro watchdog timer callback. The ZF Micro chipset sometimes completes - * an interrupt TD but neglects to add it to the donelist. On systems with - * this chipset, we need to periodically check the state of the queues to look - * for such "lost" TDs. - */ -static void unlink_watchdog_func(unsigned long _ohci) -{ - unsigned long flags; - unsigned max; - unsigned seen_count = 0; - unsigned i; - struct ed **seen = NULL; - struct ohci_hcd *ohci = (struct ohci_hcd *) _ohci; - - spin_lock_irqsave(&ohci->lock, flags); - max = ohci->eds_scheduled; - if (!max) - goto done; - - if (ohci->ed_to_check) - goto out; - - seen = kcalloc(max, sizeof *seen, GFP_ATOMIC); - if (!seen) - goto out; - - for (i = 0; i < NUM_INTS; i++) { - struct ed *ed = ohci->periodic[i]; - - while (ed) { - unsigned temp; - - /* scan this branch of the periodic schedule tree */ - for (temp = 0; temp < seen_count; temp++) { - if (seen[temp] == ed) { - /* we've checked it and what's after */ - ed = NULL; - break; - } - } - if (!ed) - break; - seen[seen_count++] = ed; - if (!check_ed(ohci, ed)) { - ed = ed->ed_next; - continue; - } - - /* HC's TD list is empty, but HCD sees at least one - * TD that's not been sent through the donelist. - */ - ohci->ed_to_check = ed; - ohci->zf_delay = 2; - - /* The HC may wait until the next frame to report the - * TD as done through the donelist and INTR_WDH. (We - * just *assume* it's not a multi-TD interrupt URB; - * those could defer the IRQ more than one frame, using - * DI...) Check again after the next INTR_SF. - */ - ohci_writel(ohci, OHCI_INTR_SF, - &ohci->regs->intrstatus); - ohci_writel(ohci, OHCI_INTR_SF, - &ohci->regs->intrenable); - - /* flush those writes */ - (void) ohci_readl(ohci, &ohci->regs->control); - - goto out; - } - } -out: - kfree(seen); - if (ohci->eds_scheduled) - mod_timer(&ohci->unlink_watchdog, round_jiffies(jiffies + HZ)); -done: - spin_unlock_irqrestore(&ohci->lock, flags); -} - -/*-------------------------------------------------------------------------* - * HC functions - *-------------------------------------------------------------------------*/ - -/* init memory, and kick BIOS/SMM off */ - -static int ohci_init (struct ohci_hcd *ohci) -{ - int ret; - struct usb_hcd *hcd = ohci_to_hcd(ohci); - - if (distrust_firmware) - ohci->flags |= OHCI_QUIRK_HUB_POWER; - - ohci->rh_state = OHCI_RH_HALTED; - ohci->regs = hcd->regs; - - /* REVISIT this BIOS handshake is now moved into PCI "quirks", and - * was never needed for most non-PCI systems ... remove the code? - */ - -#ifndef IR_DISABLE - /* SMM owns the HC? not for long! */ - if (!no_handshake && ohci_readl (ohci, - &ohci->regs->control) & OHCI_CTRL_IR) { - u32 temp; - - ohci_dbg (ohci, "USB HC TakeOver from BIOS/SMM\n"); - - /* this timeout is arbitrary. we make it long, so systems - * depending on usb keyboards may be usable even if the - * BIOS/SMM code seems pretty broken. - */ - temp = 500; /* arbitrary: five seconds */ - - ohci_writel (ohci, OHCI_INTR_OC, &ohci->regs->intrenable); - ohci_writel (ohci, OHCI_OCR, &ohci->regs->cmdstatus); - while (ohci_readl (ohci, &ohci->regs->control) & OHCI_CTRL_IR) { - msleep (10); - if (--temp == 0) { - ohci_err (ohci, "USB HC takeover failed!" - " (BIOS/SMM bug)\n"); - return -EBUSY; - } - } - ohci_usb_reset (ohci); - } -#endif - - /* Disable HC interrupts */ - ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); - - /* flush the writes, and save key bits like RWC */ - if (ohci_readl (ohci, &ohci->regs->control) & OHCI_CTRL_RWC) - ohci->hc_control |= OHCI_CTRL_RWC; - - /* Read the number of ports unless overridden */ - if (ohci->num_ports == 0) - ohci->num_ports = roothub_a(ohci) & RH_A_NDP; - - if (ohci->hcca) - return 0; - - ohci->hcca = dma_alloc_coherent (hcd->self.controller, - sizeof *ohci->hcca, &ohci->hcca_dma, 0); - if (!ohci->hcca) - return -ENOMEM; - - if ((ret = ohci_mem_init (ohci)) < 0) - ohci_stop (hcd); - else { - create_debug_files (ohci); - } - - return ret; -} - -/*-------------------------------------------------------------------------*/ - -/* Start an OHCI controller, set the BUS operational - * resets USB and controller - * enable interrupts - */ -static int ohci_run (struct ohci_hcd *ohci) -{ - u32 mask, val; - int first = ohci->fminterval == 0; - struct usb_hcd *hcd = ohci_to_hcd(ohci); - - ohci->rh_state = OHCI_RH_HALTED; - - /* boot firmware should have set this up (5.1.1.3.1) */ - if (first) { - - 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); - ohci->fminterval |= FSMP (ohci->fminterval) << 16; - /* also: power/overcurrent flags in roothub.a */ - } - - /* Reset USB nearly "by the book". RemoteWakeupConnected has - * to be checked in case boot firmware (BIOS/SMM/...) has set up - * wakeup in a way the bus isn't aware of (e.g., legacy PCI PM). - * If the bus glue detected wakeup capability then it should - * already be enabled; if so we'll just enable it again. - */ - if ((ohci->hc_control & OHCI_CTRL_RWC) != 0) - device_set_wakeup_capable(hcd->self.controller, 1); - - switch (ohci->hc_control & OHCI_CTRL_HCFS) { - case OHCI_USB_OPER: - val = 0; - break; - case OHCI_USB_SUSPEND: - case OHCI_USB_RESUME: - ohci->hc_control &= OHCI_CTRL_RWC; - ohci->hc_control |= OHCI_USB_RESUME; - val = 10 /* msec wait */; - break; - // case OHCI_USB_RESET: - default: - ohci->hc_control &= OHCI_CTRL_RWC; - ohci->hc_control |= OHCI_USB_RESET; - 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(val); - - memset (ohci->hcca, 0, sizeof (struct ohci_hcca)); - - /* 2msec timelimit here means no irqs/preempt */ - spin_lock_irq (&ohci->lock); - -retry: - /* HC Reset requires max 10 us delay */ - ohci_writel (ohci, OHCI_HCR, &ohci->regs->cmdstatus); - val = 30; /* ... allow extra time */ - while ((ohci_readl (ohci, &ohci->regs->cmdstatus) & OHCI_HCR) != 0) { - if (--val == 0) { - spin_unlock_irq (&ohci->lock); - ohci_err (ohci, "USB HC reset timed out!\n"); - return -1; - } - udelay (1); - } - - /* now we're in the SUSPEND state ... must go OPERATIONAL - * within 2msec else HC enters RESUME - * - * ... but some hardware won't init fmInterval "by the book" - * (SiS, OPTi ...), so reset again instead. SiS doesn't need - * this if we write fmInterval after we're OPERATIONAL. - * Unclear about ALi, ServerWorks, and others ... this could - * easily be a longstanding bug in chip init on Linux. - */ - if (ohci->flags & OHCI_QUIRK_INITRESET) { - ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); - // flush those writes - (void) ohci_readl (ohci, &ohci->regs->control); - } - - /* Tell the controller where the control and bulk lists are - * The lists are empty now. */ - ohci_writel (ohci, 0, &ohci->regs->ed_controlhead); - ohci_writel (ohci, 0, &ohci->regs->ed_bulkhead); - - /* a reset clears this */ - ohci_writel (ohci, (u32) ohci->hcca_dma, &ohci->regs->hcca); - - periodic_reinit (ohci); - - /* some OHCI implementations are finicky about how they init. - * bogus values here mean not even enumeration could work. - */ - if ((ohci_readl (ohci, &ohci->regs->fminterval) & 0x3fff0000) == 0 - || !ohci_readl (ohci, &ohci->regs->periodicstart)) { - if (!(ohci->flags & OHCI_QUIRK_INITRESET)) { - ohci->flags |= OHCI_QUIRK_INITRESET; - ohci_dbg (ohci, "enabling initreset quirk\n"); - goto retry; - } - spin_unlock_irq (&ohci->lock); - ohci_err (ohci, "init err (%08x %04x)\n", - ohci_readl (ohci, &ohci->regs->fminterval), - ohci_readl (ohci, &ohci->regs->periodicstart)); - return -EOVERFLOW; - } - - /* use rhsc irqs after khubd is fully initialized */ - set_bit(HCD_FLAG_POLL_RH, &hcd->flags); - hcd->uses_new_polling = 1; - - /* start controller operations */ - ohci->hc_control &= OHCI_CTRL_RWC; - ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER; - ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); - ohci->rh_state = OHCI_RH_RUNNING; - - /* wake on ConnectStatusChange, matching external hubs */ - ohci_writel (ohci, RH_HS_DRWE, &ohci->regs->roothub.status); - - /* Choose the interrupts we care about now, others later on demand */ - mask = OHCI_INTR_INIT; - ohci_writel (ohci, ~0, &ohci->regs->intrstatus); - ohci_writel (ohci, mask, &ohci->regs->intrenable); - - /* handle root hub init quirks ... */ - val = roothub_a (ohci); - val &= ~(RH_A_PSM | RH_A_OCPM); - if (ohci->flags & OHCI_QUIRK_SUPERIO) { - /* NSC 87560 and maybe others */ - 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. - */ - 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, (val & RH_A_NPS) ? 0 : RH_B_PPCM, - &ohci->regs->roothub.b); - // flush those writes - (void) ohci_readl (ohci, &ohci->regs->control); - - ohci->next_statechange = jiffies + STATECHANGE_DELAY; - spin_unlock_irq (&ohci->lock); - - // POTPGT delay is bits 24-31, in 2 ms units. - mdelay ((val >> 23) & 0x1fe); - - if (quirk_zfmicro(ohci)) { - /* Create timer to watch for bad queue state on ZF Micro */ - setup_timer(&ohci->unlink_watchdog, unlink_watchdog_func, - (unsigned long) ohci); - - ohci->eds_scheduled = 0; - ohci->ed_to_check = NULL; - } - - ohci_dump (ohci, 1); - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* an interrupt happens */ - -static irqreturn_t ohci_irq (struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - struct ohci_regs __iomem *regs = ohci->regs; - int ints; - - /* Read interrupt status (and flush pending writes). We ignore the - * optimization of checking the LSB of hcca->done_head; it doesn't - * work on all systems (edge triggering for OHCI can be a factor). - */ - ints = ohci_readl(ohci, ®s->intrstatus); - - /* Check for an all 1's result which is a typical consequence - * of dead, unclocked, or unplugged (CardBus...) devices - */ - if (ints == ~(u32)0) { - ohci->rh_state = OHCI_RH_HALTED; - ohci_dbg (ohci, "device removed!\n"); - usb_hc_died(hcd); - return IRQ_HANDLED; - } - - /* We only care about interrupts that are enabled */ - ints &= ohci_readl(ohci, ®s->intrenable); - - /* interrupt for some other device? */ - if (ints == 0 || unlikely(ohci->rh_state == OHCI_RH_HALTED)) - return IRQ_NOTMINE; - - if (ints & OHCI_INTR_UE) { - // e.g. due to PCI Master/Target Abort - if (quirk_nec(ohci)) { - /* Workaround for a silicon bug in some NEC chips used - * in Apple's PowerBooks. Adapted from Darwin code. - */ - ohci_err (ohci, "OHCI Unrecoverable Error, scheduling NEC chip restart\n"); - - ohci_writel (ohci, OHCI_INTR_UE, ®s->intrdisable); - - schedule_work (&ohci->nec_work); - } else { - ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n"); - ohci->rh_state = OHCI_RH_HALTED; - usb_hc_died(hcd); - } - - ohci_dump (ohci, 1); - ohci_usb_reset (ohci); - } - - if (ints & OHCI_INTR_RHSC) { - ohci_vdbg(ohci, "rhsc\n"); - ohci->next_statechange = jiffies + STATECHANGE_DELAY; - ohci_writel(ohci, OHCI_INTR_RD | OHCI_INTR_RHSC, - ®s->intrstatus); - - /* NOTE: Vendors didn't always make the same implementation - * choices for RHSC. Many followed the spec; RHSC triggers - * on an edge, like setting and maybe clearing a port status - * change bit. With others it's level-triggered, active - * until khubd clears all the port status change bits. We'll - * always disable it here and rely on polling until khubd - * re-enables it. - */ - ohci_writel(ohci, OHCI_INTR_RHSC, ®s->intrdisable); - usb_hcd_poll_rh_status(hcd); - } - - /* For connect and disconnect events, we expect the controller - * to turn on RHSC along with RD. But for remote wakeup events - * this might not happen. - */ - else if (ints & OHCI_INTR_RD) { - ohci_vdbg(ohci, "resume detect\n"); - ohci_writel(ohci, OHCI_INTR_RD, ®s->intrstatus); - set_bit(HCD_FLAG_POLL_RH, &hcd->flags); - if (ohci->autostop) { - spin_lock (&ohci->lock); - ohci_rh_resume (ohci); - spin_unlock (&ohci->lock); - } else - usb_hcd_resume_root_hub(hcd); - } - - if (ints & OHCI_INTR_WDH) { - spin_lock (&ohci->lock); - dl_done_list (ohci); - spin_unlock (&ohci->lock); - } - - if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) { - spin_lock(&ohci->lock); - if (ohci->ed_to_check) { - struct ed *ed = ohci->ed_to_check; - - if (check_ed(ohci, ed)) { - /* HC thinks the TD list is empty; HCD knows - * at least one TD is outstanding - */ - if (--ohci->zf_delay == 0) { - struct td *td = list_entry( - ed->td_list.next, - struct td, td_list); - ohci_warn(ohci, - "Reclaiming orphan TD %p\n", - td); - takeback_td(ohci, td); - ohci->ed_to_check = NULL; - } - } else - ohci->ed_to_check = NULL; - } - spin_unlock(&ohci->lock); - } - - /* could track INTR_SO to reduce available PCI/... bandwidth */ - - /* handle any pending URB/ED unlinks, leaving INTR_SF enabled - * when there's still unlinking to be done (next frame). - */ - spin_lock (&ohci->lock); - if (ohci->ed_rm_list) - finish_unlinks (ohci, ohci_frame_no(ohci)); - if ((ints & OHCI_INTR_SF) != 0 - && !ohci->ed_rm_list - && !ohci->ed_to_check - && ohci->rh_state == OHCI_RH_RUNNING) - ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable); - spin_unlock (&ohci->lock); - - if (ohci->rh_state == OHCI_RH_RUNNING) { - ohci_writel (ohci, ints, ®s->intrstatus); - ohci_writel (ohci, OHCI_INTR_MIE, ®s->intrenable); - // flush those writes - (void) ohci_readl (ohci, &ohci->regs->control); - } - - return IRQ_HANDLED; -} - -/*-------------------------------------------------------------------------*/ - -static void ohci_stop (struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - - ohci_dump (ohci, 1); - - if (quirk_nec(ohci)) - flush_work_sync(&ohci->nec_work); - - ohci_usb_reset (ohci); - ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); - free_irq(hcd->irq, hcd); - hcd->irq = 0; - - if (quirk_zfmicro(ohci)) - del_timer(&ohci->unlink_watchdog); - if (quirk_amdiso(ohci)) - usb_amd_dev_put(); - - remove_debug_files (ohci); - ohci_mem_cleanup (ohci); - if (ohci->hcca) { - dma_free_coherent (hcd->self.controller, - sizeof *ohci->hcca, - ohci->hcca, ohci->hcca_dma); - ohci->hcca = NULL; - ohci->hcca_dma = 0; - } -} - -/*-------------------------------------------------------------------------*/ - -#if defined(CONFIG_PM) || defined(CONFIG_PCI) - -/* must not be called from interrupt context */ -static int ohci_restart (struct ohci_hcd *ohci) -{ - int temp; - int i; - struct urb_priv *priv; - - spin_lock_irq(&ohci->lock); - ohci->rh_state = OHCI_RH_HALTED; - - /* Recycle any "live" eds/tds (and urbs). */ - if (!list_empty (&ohci->pending)) - ohci_dbg(ohci, "abort schedule...\n"); - list_for_each_entry (priv, &ohci->pending, pending) { - struct urb *urb = priv->td[0]->urb; - struct ed *ed = priv->ed; - - switch (ed->state) { - case ED_OPER: - ed->state = ED_UNLINK; - ed->hwINFO |= cpu_to_hc32(ohci, ED_DEQUEUE); - ed_deschedule (ohci, ed); - - ed->ed_next = ohci->ed_rm_list; - ed->ed_prev = NULL; - ohci->ed_rm_list = ed; - /* FALLTHROUGH */ - case ED_UNLINK: - break; - default: - ohci_dbg(ohci, "bogus ed %p state %d\n", - ed, ed->state); - } - - if (!urb->unlinked) - urb->unlinked = -ESHUTDOWN; - } - finish_unlinks (ohci, 0); - spin_unlock_irq(&ohci->lock); - - /* paranoia, in case that didn't work: */ - - /* empty the interrupt branches */ - for (i = 0; i < NUM_INTS; i++) ohci->load [i] = 0; - for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table [i] = 0; - - /* no EDs to remove */ - ohci->ed_rm_list = NULL; - - /* empty control and bulk lists */ - ohci->ed_controltail = NULL; - ohci->ed_bulktail = NULL; - - if ((temp = ohci_run (ohci)) < 0) { - ohci_err (ohci, "can't restart, %d\n", temp); - return temp; - } - ohci_dbg(ohci, "restart complete\n"); - return 0; -} - -#endif - -/*-------------------------------------------------------------------------*/ - -MODULE_AUTHOR (DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE ("GPL"); - -#ifdef CONFIG_PCI -#include "ohci-pci.c" -#define PCI_DRIVER ohci_pci_driver -#endif - -#if defined(CONFIG_ARCH_SA1100) && defined(CONFIG_SA1111) -#include "ohci-sa1111.c" -#define SA1111_DRIVER ohci_hcd_sa1111_driver -#endif - -#if defined(CONFIG_ARCH_S3C24XX) || defined(CONFIG_ARCH_S3C64XX) -#include "ohci-s3c2410.c" -#define PLATFORM_DRIVER ohci_hcd_s3c2410_driver -#endif - -#ifdef CONFIG_USB_OHCI_EXYNOS -#include "ohci-exynos.c" -#define PLATFORM_DRIVER exynos_ohci_driver -#endif - -#ifdef CONFIG_USB_OHCI_HCD_OMAP1 -#include "ohci-omap.c" -#define OMAP1_PLATFORM_DRIVER ohci_hcd_omap_driver -#endif - -#ifdef CONFIG_USB_OHCI_HCD_OMAP3 -#include "ohci-omap3.c" -#define OMAP3_PLATFORM_DRIVER ohci_hcd_omap3_driver -#endif - -#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) -#include "ohci-pxa27x.c" -#define PLATFORM_DRIVER ohci_hcd_pxa27x_driver -#endif - -#ifdef CONFIG_ARCH_EP93XX -#include "ohci-ep93xx.c" -#define PLATFORM_DRIVER ohci_hcd_ep93xx_driver -#endif - -#ifdef CONFIG_MIPS_ALCHEMY -#include "ohci-au1xxx.c" -#define PLATFORM_DRIVER ohci_hcd_au1xxx_driver -#endif - -#ifdef CONFIG_PNX8550 -#include "ohci-pnx8550.c" -#define PLATFORM_DRIVER ohci_hcd_pnx8550_driver -#endif - -#ifdef CONFIG_USB_OHCI_HCD_PPC_SOC -#include "ohci-ppc-soc.c" -#define PLATFORM_DRIVER ohci_hcd_ppc_soc_driver -#endif - -#ifdef CONFIG_ARCH_AT91 -#include "ohci-at91.c" -#define PLATFORM_DRIVER ohci_hcd_at91_driver -#endif - -#if defined(CONFIG_ARCH_PNX4008) || defined(CONFIG_ARCH_LPC32XX) -#include "ohci-nxp.c" -#define PLATFORM_DRIVER usb_hcd_nxp_driver -#endif - -#ifdef CONFIG_ARCH_DAVINCI_DA8XX -#include "ohci-da8xx.c" -#define PLATFORM_DRIVER ohci_hcd_da8xx_driver -#endif - -#ifdef CONFIG_USB_OHCI_SH -#include "ohci-sh.c" -#define PLATFORM_DRIVER ohci_hcd_sh_driver -#endif - - -#ifdef CONFIG_USB_OHCI_HCD_PPC_OF -#include "ohci-ppc-of.c" -#define OF_PLATFORM_DRIVER ohci_hcd_ppc_of_driver -#endif - -#ifdef CONFIG_PLAT_SPEAR -#include "ohci-spear.c" -#define PLATFORM_DRIVER spear_ohci_hcd_driver -#endif - -#ifdef CONFIG_PPC_PS3 -#include "ohci-ps3.c" -#define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver -#endif - -#ifdef CONFIG_USB_OHCI_HCD_SSB -#include "ohci-ssb.c" -#define SSB_OHCI_DRIVER ssb_ohci_driver -#endif - -#ifdef CONFIG_MFD_SM501 -#include "ohci-sm501.c" -#define SM501_OHCI_DRIVER ohci_hcd_sm501_driver -#endif - -#ifdef CONFIG_MFD_TC6393XB -#include "ohci-tmio.c" -#define TMIO_OHCI_DRIVER ohci_hcd_tmio_driver -#endif - -#ifdef CONFIG_MACH_JZ4740 -#include "ohci-jz4740.c" -#define PLATFORM_DRIVER ohci_hcd_jz4740_driver -#endif - -#ifdef CONFIG_USB_OCTEON_OHCI -#include "ohci-octeon.c" -#define PLATFORM_DRIVER ohci_octeon_driver -#endif - -#ifdef CONFIG_USB_CNS3XXX_OHCI -#include "ohci-cns3xxx.c" -#define PLATFORM_DRIVER ohci_hcd_cns3xxx_driver -#endif - -#ifdef CONFIG_CPU_XLR -#include "ohci-xls.c" -#define PLATFORM_DRIVER ohci_xls_driver -#endif - -#ifdef CONFIG_USB_OHCI_HCD_PLATFORM -#include "ohci-platform.c" -#define PLATFORM_DRIVER ohci_platform_driver -#endif - -#if !defined(PCI_DRIVER) && \ - !defined(PLATFORM_DRIVER) && \ - !defined(OMAP1_PLATFORM_DRIVER) && \ - !defined(OMAP3_PLATFORM_DRIVER) && \ - !defined(OF_PLATFORM_DRIVER) && \ - !defined(SA1111_DRIVER) && \ - !defined(PS3_SYSTEM_BUS_DRIVER) && \ - !defined(SM501_OHCI_DRIVER) && \ - !defined(TMIO_OHCI_DRIVER) && \ - !defined(SSB_OHCI_DRIVER) -#error "missing bus glue for ohci-hcd" -#endif - -static int __init ohci_hcd_mod_init(void) -{ - int retval = 0; - - if (usb_disabled()) - return -ENODEV; - - printk(KERN_INFO "%s: " DRIVER_DESC "\n", hcd_name); - pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name, - sizeof (struct ed), sizeof (struct td)); - set_bit(USB_OHCI_LOADED, &usb_hcds_loaded); - -#ifdef DEBUG - ohci_debug_root = debugfs_create_dir("ohci", usb_debug_root); - if (!ohci_debug_root) { - retval = -ENOENT; - goto error_debug; - } -#endif - -#ifdef PS3_SYSTEM_BUS_DRIVER - retval = ps3_ohci_driver_register(&PS3_SYSTEM_BUS_DRIVER); - if (retval < 0) - goto error_ps3; -#endif - -#ifdef PLATFORM_DRIVER - retval = platform_driver_register(&PLATFORM_DRIVER); - if (retval < 0) - goto error_platform; -#endif - -#ifdef OMAP1_PLATFORM_DRIVER - retval = platform_driver_register(&OMAP1_PLATFORM_DRIVER); - if (retval < 0) - goto error_omap1_platform; -#endif - -#ifdef OMAP3_PLATFORM_DRIVER - retval = platform_driver_register(&OMAP3_PLATFORM_DRIVER); - if (retval < 0) - goto error_omap3_platform; -#endif - -#ifdef OF_PLATFORM_DRIVER - retval = platform_driver_register(&OF_PLATFORM_DRIVER); - if (retval < 0) - goto error_of_platform; -#endif - -#ifdef SA1111_DRIVER - retval = sa1111_driver_register(&SA1111_DRIVER); - if (retval < 0) - goto error_sa1111; -#endif - -#ifdef PCI_DRIVER - retval = pci_register_driver(&PCI_DRIVER); - if (retval < 0) - goto error_pci; -#endif - -#ifdef SSB_OHCI_DRIVER - retval = ssb_driver_register(&SSB_OHCI_DRIVER); - if (retval) - goto error_ssb; -#endif - -#ifdef SM501_OHCI_DRIVER - retval = platform_driver_register(&SM501_OHCI_DRIVER); - if (retval < 0) - goto error_sm501; -#endif - -#ifdef TMIO_OHCI_DRIVER - retval = platform_driver_register(&TMIO_OHCI_DRIVER); - if (retval < 0) - goto error_tmio; -#endif - - return retval; - - /* Error path */ -#ifdef TMIO_OHCI_DRIVER - platform_driver_unregister(&TMIO_OHCI_DRIVER); - error_tmio: -#endif -#ifdef SM501_OHCI_DRIVER - platform_driver_unregister(&SM501_OHCI_DRIVER); - error_sm501: -#endif -#ifdef SSB_OHCI_DRIVER - ssb_driver_unregister(&SSB_OHCI_DRIVER); - error_ssb: -#endif -#ifdef PCI_DRIVER - pci_unregister_driver(&PCI_DRIVER); - error_pci: -#endif -#ifdef SA1111_DRIVER - sa1111_driver_unregister(&SA1111_DRIVER); - error_sa1111: -#endif -#ifdef OF_PLATFORM_DRIVER - platform_driver_unregister(&OF_PLATFORM_DRIVER); - error_of_platform: -#endif -#ifdef PLATFORM_DRIVER - platform_driver_unregister(&PLATFORM_DRIVER); - error_platform: -#endif -#ifdef OMAP1_PLATFORM_DRIVER - platform_driver_unregister(&OMAP1_PLATFORM_DRIVER); - error_omap1_platform: -#endif -#ifdef OMAP3_PLATFORM_DRIVER - platform_driver_unregister(&OMAP3_PLATFORM_DRIVER); - error_omap3_platform: -#endif -#ifdef PS3_SYSTEM_BUS_DRIVER - ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); - error_ps3: -#endif -#ifdef DEBUG - debugfs_remove(ohci_debug_root); - ohci_debug_root = NULL; - error_debug: -#endif - - clear_bit(USB_OHCI_LOADED, &usb_hcds_loaded); - return retval; -} -module_init(ohci_hcd_mod_init); - -static void __exit ohci_hcd_mod_exit(void) -{ -#ifdef TMIO_OHCI_DRIVER - platform_driver_unregister(&TMIO_OHCI_DRIVER); -#endif -#ifdef SM501_OHCI_DRIVER - platform_driver_unregister(&SM501_OHCI_DRIVER); -#endif -#ifdef SSB_OHCI_DRIVER - ssb_driver_unregister(&SSB_OHCI_DRIVER); -#endif -#ifdef PCI_DRIVER - pci_unregister_driver(&PCI_DRIVER); -#endif -#ifdef SA1111_DRIVER - sa1111_driver_unregister(&SA1111_DRIVER); -#endif -#ifdef OF_PLATFORM_DRIVER - platform_driver_unregister(&OF_PLATFORM_DRIVER); -#endif -#ifdef PLATFORM_DRIVER - platform_driver_unregister(&PLATFORM_DRIVER); -#endif -#ifdef OMAP3_PLATFORM_DRIVER - platform_driver_unregister(&OMAP3_PLATFORM_DRIVER); -#endif -#ifdef PS3_SYSTEM_BUS_DRIVER - ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); -#endif -#ifdef DEBUG - debugfs_remove(ohci_debug_root); -#endif - clear_bit(USB_OHCI_LOADED, &usb_hcds_loaded); -} -module_exit(ohci_hcd_mod_exit); - diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-hub.c b/ANDROID_3.4.5/drivers/usb/host/ohci-hub.c deleted file mode 100644 index 836772df..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-hub.c +++ /dev/null @@ -1,825 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2004 David Brownell - * - * This file is licenced under GPL - */ - -/*-------------------------------------------------------------------------*/ - -/* - * OHCI Root Hub ... the nonsharable stuff - */ - -#define dbg_port(hc,label,num,value) \ - ohci_dbg (hc, \ - "%s roothub.portstatus [%d] " \ - "= 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s\n", \ - label, num, temp, \ - (temp & RH_PS_PRSC) ? " PRSC" : "", \ - (temp & RH_PS_OCIC) ? " OCIC" : "", \ - (temp & RH_PS_PSSC) ? " PSSC" : "", \ - (temp & RH_PS_PESC) ? " PESC" : "", \ - (temp & RH_PS_CSC) ? " CSC" : "", \ - \ - (temp & RH_PS_LSDA) ? " LSDA" : "", \ - (temp & RH_PS_PPS) ? " PPS" : "", \ - (temp & RH_PS_PRS) ? " PRS" : "", \ - (temp & RH_PS_POCI) ? " POCI" : "", \ - (temp & RH_PS_PSS) ? " PSS" : "", \ - \ - (temp & RH_PS_PES) ? " PES" : "", \ - (temp & RH_PS_CCS) ? " CCS" : "" \ - ); - -/*-------------------------------------------------------------------------*/ - -#define OHCI_SCHED_ENABLES \ - (OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE) - -static void dl_done_list (struct ohci_hcd *); -static void finish_unlinks (struct ohci_hcd *, u16); - -#ifdef CONFIG_PM -static int ohci_rh_suspend (struct ohci_hcd *ohci, int autostop) -__releases(ohci->lock) -__acquires(ohci->lock) -{ - int status = 0; - - ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); - switch (ohci->hc_control & OHCI_CTRL_HCFS) { - case OHCI_USB_RESUME: - ohci_dbg (ohci, "resume/suspend?\n"); - ohci->hc_control &= ~OHCI_CTRL_HCFS; - ohci->hc_control |= OHCI_USB_RESET; - ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); - (void) ohci_readl (ohci, &ohci->regs->control); - /* FALL THROUGH */ - case OHCI_USB_RESET: - status = -EBUSY; - ohci_dbg (ohci, "needs reinit!\n"); - goto done; - case OHCI_USB_SUSPEND: - if (!ohci->autostop) { - ohci_dbg (ohci, "already suspended\n"); - goto done; - } - } - ohci_dbg (ohci, "%s root hub\n", - autostop ? "auto-stop" : "suspend"); - - /* First stop any processing */ - if (!autostop && (ohci->hc_control & OHCI_SCHED_ENABLES)) { - ohci->hc_control &= ~OHCI_SCHED_ENABLES; - ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); - ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); - ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrstatus); - - /* sched disables take effect on the next frame, - * then the last WDH could take 6+ msec - */ - ohci_dbg (ohci, "stopping schedules ...\n"); - ohci->autostop = 0; - spin_unlock_irq (&ohci->lock); - msleep (8); - spin_lock_irq (&ohci->lock); - } - dl_done_list (ohci); - finish_unlinks (ohci, ohci_frame_no(ohci)); - - /* maybe resume can wake root hub */ - if (ohci_to_hcd(ohci)->self.root_hub->do_remote_wakeup || autostop) { - ohci->hc_control |= OHCI_CTRL_RWE; - } else { - ohci_writel(ohci, OHCI_INTR_RHSC | OHCI_INTR_RD, - &ohci->regs->intrdisable); - ohci->hc_control &= ~OHCI_CTRL_RWE; - } - - /* Suspend hub ... this is the "global (to this bus) suspend" mode, - * which doesn't imply ports will first be individually suspended. - */ - ohci->hc_control &= ~OHCI_CTRL_HCFS; - ohci->hc_control |= OHCI_USB_SUSPEND; - ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); - (void) ohci_readl (ohci, &ohci->regs->control); - - /* no resumes until devices finish suspending */ - if (!autostop) { - ohci->next_statechange = jiffies + msecs_to_jiffies (5); - ohci->autostop = 0; - ohci->rh_state = OHCI_RH_SUSPENDED; - } - -done: - return status; -} - -static inline struct ed *find_head (struct ed *ed) -{ - /* for bulk and control lists */ - while (ed->ed_prev) - ed = ed->ed_prev; - return ed; -} - -/* caller has locked the root hub */ -static int ohci_rh_resume (struct ohci_hcd *ohci) -__releases(ohci->lock) -__acquires(ohci->lock) -{ - struct usb_hcd *hcd = ohci_to_hcd (ohci); - u32 temp, enables; - int status = -EINPROGRESS; - int autostopped = ohci->autostop; - - ohci->autostop = 0; - ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); - - if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { - /* this can happen after resuming a swsusp snapshot */ - if (ohci->rh_state != OHCI_RH_RUNNING) { - ohci_dbg (ohci, "BIOS/SMM active, control %03x\n", - ohci->hc_control); - status = -EBUSY; - /* this happens when pmcore resumes HC then root */ - } else { - ohci_dbg (ohci, "duplicate resume\n"); - status = 0; - } - } else switch (ohci->hc_control & OHCI_CTRL_HCFS) { - case OHCI_USB_SUSPEND: - ohci->hc_control &= ~(OHCI_CTRL_HCFS|OHCI_SCHED_ENABLES); - ohci->hc_control |= OHCI_USB_RESUME; - ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); - (void) ohci_readl (ohci, &ohci->regs->control); - ohci_dbg (ohci, "%s root hub\n", - autostopped ? "auto-start" : "resume"); - break; - case OHCI_USB_RESUME: - /* HCFS changes sometime after INTR_RD */ - ohci_dbg(ohci, "%swakeup root hub\n", - autostopped ? "auto-" : ""); - break; - case OHCI_USB_OPER: - /* this can happen after resuming a swsusp snapshot */ - ohci_dbg (ohci, "snapshot resume? reinit\n"); - status = -EBUSY; - break; - default: /* RESET, we lost power */ - ohci_dbg (ohci, "lost power\n"); - status = -EBUSY; - } - if (status == -EBUSY) { - if (!autostopped) { - spin_unlock_irq (&ohci->lock); - (void) ohci_init (ohci); - status = ohci_restart (ohci); - - usb_root_hub_lost_power(hcd->self.root_hub); - - spin_lock_irq (&ohci->lock); - } - return status; - } - if (status != -EINPROGRESS) - return status; - if (autostopped) - goto skip_resume; - spin_unlock_irq (&ohci->lock); - - /* Some controllers (lucent erratum) need extra-long delays */ - msleep (20 /* usb 11.5.1.10 */ + 12 /* 32 msec counter */ + 1); - - temp = ohci_readl (ohci, &ohci->regs->control); - temp &= OHCI_CTRL_HCFS; - if (temp != OHCI_USB_RESUME) { - ohci_err (ohci, "controller won't resume\n"); - spin_lock_irq(&ohci->lock); - return -EBUSY; - } - - /* disable old schedule state, reinit from scratch */ - ohci_writel (ohci, 0, &ohci->regs->ed_controlhead); - ohci_writel (ohci, 0, &ohci->regs->ed_controlcurrent); - ohci_writel (ohci, 0, &ohci->regs->ed_bulkhead); - ohci_writel (ohci, 0, &ohci->regs->ed_bulkcurrent); - ohci_writel (ohci, 0, &ohci->regs->ed_periodcurrent); - ohci_writel (ohci, (u32) ohci->hcca_dma, &ohci->regs->hcca); - - /* Sometimes PCI D3 suspend trashes frame timings ... */ - periodic_reinit (ohci); - - /* the following code is executed with ohci->lock held and - * irqs disabled if and only if autostopped is true - */ - -skip_resume: - /* interrupts might have been disabled */ - ohci_writel (ohci, OHCI_INTR_INIT, &ohci->regs->intrenable); - if (ohci->ed_rm_list) - ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrenable); - - /* Then re-enable operations */ - ohci_writel (ohci, OHCI_USB_OPER, &ohci->regs->control); - (void) ohci_readl (ohci, &ohci->regs->control); - if (!autostopped) - msleep (3); - - temp = ohci->hc_control; - temp &= OHCI_CTRL_RWC; - temp |= OHCI_CONTROL_INIT | OHCI_USB_OPER; - ohci->hc_control = temp; - ohci_writel (ohci, temp, &ohci->regs->control); - (void) ohci_readl (ohci, &ohci->regs->control); - - /* TRSMRCY */ - if (!autostopped) { - msleep (10); - spin_lock_irq (&ohci->lock); - } - /* now ohci->lock is always held and irqs are always disabled */ - - /* keep it alive for more than ~5x suspend + resume costs */ - ohci->next_statechange = jiffies + STATECHANGE_DELAY; - - /* maybe turn schedules back on */ - enables = 0; - temp = 0; - if (!ohci->ed_rm_list) { - if (ohci->ed_controltail) { - ohci_writel (ohci, - find_head (ohci->ed_controltail)->dma, - &ohci->regs->ed_controlhead); - enables |= OHCI_CTRL_CLE; - temp |= OHCI_CLF; - } - if (ohci->ed_bulktail) { - ohci_writel (ohci, find_head (ohci->ed_bulktail)->dma, - &ohci->regs->ed_bulkhead); - enables |= OHCI_CTRL_BLE; - temp |= OHCI_BLF; - } - } - if (hcd->self.bandwidth_isoc_reqs || hcd->self.bandwidth_int_reqs) - enables |= OHCI_CTRL_PLE|OHCI_CTRL_IE; - if (enables) { - ohci_dbg (ohci, "restarting schedules ... %08x\n", enables); - ohci->hc_control |= enables; - ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); - if (temp) - ohci_writel (ohci, temp, &ohci->regs->cmdstatus); - (void) ohci_readl (ohci, &ohci->regs->control); - } - - ohci->rh_state = OHCI_RH_RUNNING; - return 0; -} - -static int ohci_bus_suspend (struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int rc; - - spin_lock_irq (&ohci->lock); - - if (unlikely(!HCD_HW_ACCESSIBLE(hcd))) - rc = -ESHUTDOWN; - else - rc = ohci_rh_suspend (ohci, 0); - spin_unlock_irq (&ohci->lock); - return rc; -} - -static int ohci_bus_resume (struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int rc; - - if (time_before (jiffies, ohci->next_statechange)) - msleep(5); - - spin_lock_irq (&ohci->lock); - - if (unlikely(!HCD_HW_ACCESSIBLE(hcd))) - rc = -ESHUTDOWN; - else - rc = ohci_rh_resume (ohci); - spin_unlock_irq (&ohci->lock); - - /* poll until we know a device is connected or we autostop */ - if (rc == 0) - usb_hcd_poll_rh_status(hcd); - return rc; -} - -/* Carry out the final steps of resuming the controller device */ -static void ohci_finish_controller_resume(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int port; - bool need_reinit = false; - - /* See if the controller is already running or has been reset */ - ohci->hc_control = ohci_readl(ohci, &ohci->regs->control); - if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { - need_reinit = true; - } else { - switch (ohci->hc_control & OHCI_CTRL_HCFS) { - case OHCI_USB_OPER: - case OHCI_USB_RESET: - need_reinit = true; - } - } - - /* If needed, reinitialize and suspend the root hub */ - if (need_reinit) { - spin_lock_irq(&ohci->lock); - ohci_rh_resume(ohci); - ohci_rh_suspend(ohci, 0); - spin_unlock_irq(&ohci->lock); - } - - /* Normally just turn on port power and enable interrupts */ - else { - ohci_dbg(ohci, "powerup ports\n"); - for (port = 0; port < ohci->num_ports; port++) - ohci_writel(ohci, RH_PS_PPS, - &ohci->regs->roothub.portstatus[port]); - - ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrenable); - ohci_readl(ohci, &ohci->regs->intrenable); - msleep(20); - } - - usb_hcd_resume_root_hub(hcd); -} - -/* Carry out polling-, autostop-, and autoresume-related state changes */ -static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed, - int any_connected, int rhsc_status) -{ - int poll_rh = 1; - int rhsc_enable; - - /* Some broken controllers never turn off RHSC in the interrupt - * status register. For their sake we won't re-enable RHSC - * interrupts if the interrupt bit is already active. - */ - rhsc_enable = ohci_readl(ohci, &ohci->regs->intrenable) & - OHCI_INTR_RHSC; - - switch (ohci->hc_control & OHCI_CTRL_HCFS) { - case OHCI_USB_OPER: - /* If no status changes are pending, enable RHSC interrupts. */ - if (!rhsc_enable && !rhsc_status && !changed) { - rhsc_enable = OHCI_INTR_RHSC; - ohci_writel(ohci, rhsc_enable, &ohci->regs->intrenable); - } - - /* Keep on polling until we know a device is connected - * and RHSC is enabled, or until we autostop. - */ - if (!ohci->autostop) { - if (any_connected || - !device_may_wakeup(&ohci_to_hcd(ohci) - ->self.root_hub->dev)) { - if (rhsc_enable) - poll_rh = 0; - } else { - ohci->autostop = 1; - ohci->next_statechange = jiffies + HZ; - } - - /* if no devices have been attached for one second, autostop */ - } else { - if (changed || any_connected) { - ohci->autostop = 0; - ohci->next_statechange = jiffies + - STATECHANGE_DELAY; - } else if (time_after_eq(jiffies, - ohci->next_statechange) - && !ohci->ed_rm_list - && !(ohci->hc_control & - OHCI_SCHED_ENABLES)) { - ohci_rh_suspend(ohci, 1); - if (rhsc_enable) - poll_rh = 0; - } - } - break; - - case OHCI_USB_SUSPEND: - case OHCI_USB_RESUME: - /* if there is a port change, autostart or ask to be resumed */ - if (changed) { - if (ohci->autostop) - ohci_rh_resume(ohci); - else - usb_hcd_resume_root_hub(ohci_to_hcd(ohci)); - - /* If remote wakeup is disabled, stop polling */ - } else if (!ohci->autostop && - !ohci_to_hcd(ohci)->self.root_hub-> - do_remote_wakeup) { - poll_rh = 0; - - } else { - /* If no status changes are pending, - * enable RHSC interrupts - */ - if (!rhsc_enable && !rhsc_status) { - rhsc_enable = OHCI_INTR_RHSC; - ohci_writel(ohci, rhsc_enable, - &ohci->regs->intrenable); - } - /* Keep polling until RHSC is enabled */ - if (rhsc_enable) - poll_rh = 0; - } - break; - } - return poll_rh; -} - -#else /* CONFIG_PM */ - -static inline int ohci_rh_resume(struct ohci_hcd *ohci) -{ - return 0; -} - -/* Carry out polling-related state changes. - * autostop isn't used when CONFIG_PM is turned off. - */ -static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed, - int any_connected, int rhsc_status) -{ - /* If RHSC is enabled, don't poll */ - if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC) - return 0; - - /* If status changes are pending, continue polling. - * Conversely, if no status changes are pending but the RHSC - * status bit was set, then RHSC may be broken so continue polling. - */ - if (changed || rhsc_status) - return 1; - - /* It's safe to re-enable RHSC interrupts */ - ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); - return 0; -} - -#endif /* CONFIG_PM */ - -/*-------------------------------------------------------------------------*/ - -/* build "status change" packet (one or two bytes) from HC registers */ - -static int -ohci_hub_status_data (struct usb_hcd *hcd, char *buf) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int i, changed = 0, length = 1; - int any_connected = 0; - int rhsc_status; - unsigned long flags; - - spin_lock_irqsave (&ohci->lock, flags); - if (!HCD_HW_ACCESSIBLE(hcd)) - goto done; - - /* undocumented erratum seen on at least rev D */ - if ((ohci->flags & OHCI_QUIRK_AMD756) - && (roothub_a (ohci) & RH_A_NDP) > MAX_ROOT_PORTS) { - ohci_warn (ohci, "bogus NDP, rereads as NDP=%d\n", - ohci_readl (ohci, &ohci->regs->roothub.a) & RH_A_NDP); - /* retry later; "should not happen" */ - goto done; - } - - /* init status */ - if (roothub_status (ohci) & (RH_HS_LPSC | RH_HS_OCIC)) - buf [0] = changed = 1; - else - buf [0] = 0; - if (ohci->num_ports > 7) { - buf [1] = 0; - length++; - } - - /* Clear the RHSC status flag before reading the port statuses */ - ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrstatus); - rhsc_status = ohci_readl(ohci, &ohci->regs->intrstatus) & - OHCI_INTR_RHSC; - - /* look at each port */ - for (i = 0; i < ohci->num_ports; i++) { - u32 status = roothub_portstatus (ohci, i); - - /* can't autostop if ports are connected */ - any_connected |= (status & RH_PS_CCS); - - if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC - | RH_PS_OCIC | RH_PS_PRSC)) { - changed = 1; - if (i < 7) - buf [0] |= 1 << (i + 1); - else - buf [1] |= 1 << (i - 7); - } - } - - if (ohci_root_hub_state_changes(ohci, changed, - any_connected, rhsc_status)) - set_bit(HCD_FLAG_POLL_RH, &hcd->flags); - else - clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); - - -done: - spin_unlock_irqrestore (&ohci->lock, flags); - - return changed ? length : 0; -} - -/*-------------------------------------------------------------------------*/ - -static void -ohci_hub_descriptor ( - struct ohci_hcd *ohci, - struct usb_hub_descriptor *desc -) { - u32 rh = roothub_a (ohci); - u16 temp; - - desc->bDescriptorType = 0x29; - desc->bPwrOn2PwrGood = (rh & RH_A_POTPGT) >> 24; - desc->bHubContrCurrent = 0; - - desc->bNbrPorts = ohci->num_ports; - temp = 1 + (ohci->num_ports / 8); - desc->bDescLength = 7 + 2 * temp; - - temp = 0; - if (rh & RH_A_NPS) /* no power switching? */ - temp |= 0x0002; - if (rh & RH_A_PSM) /* per-port power switching? */ - temp |= 0x0001; - if (rh & RH_A_NOCP) /* no overcurrent reporting? */ - temp |= 0x0010; - else if (rh & RH_A_OCPM) /* per-port overcurrent reporting? */ - temp |= 0x0008; - desc->wHubCharacteristics = (__force __u16)cpu_to_hc16(ohci, temp); - - /* ports removable, and usb 1.0 legacy PortPwrCtrlMask */ - rh = roothub_b (ohci); - memset(desc->u.hs.DeviceRemovable, 0xff, - sizeof(desc->u.hs.DeviceRemovable)); - desc->u.hs.DeviceRemovable[0] = rh & RH_B_DR; - if (ohci->num_ports > 7) { - desc->u.hs.DeviceRemovable[1] = (rh & RH_B_DR) >> 8; - desc->u.hs.DeviceRemovable[2] = 0xff; - } else - desc->u.hs.DeviceRemovable[1] = 0xff; -} - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_USB_OTG - -static int ohci_start_port_reset (struct usb_hcd *hcd, unsigned port) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - u32 status; - - if (!port) - return -EINVAL; - port--; - - /* start port reset before HNP protocol times out */ - status = ohci_readl(ohci, &ohci->regs->roothub.portstatus [port]); - if (!(status & RH_PS_CCS)) - return -ENODEV; - - /* khubd will finish the reset later */ - ohci_writel(ohci, RH_PS_PRS, &ohci->regs->roothub.portstatus [port]); - return 0; -} - -#else - -#define ohci_start_port_reset NULL - -#endif - -/*-------------------------------------------------------------------------*/ - - -/* See usb 7.1.7.5: root hubs must issue at least 50 msec reset signaling, - * not necessarily continuous ... to guard against resume signaling. - * The short timeout is safe for non-root hubs, and is backward-compatible - * with earlier Linux hosts. - */ -#ifdef CONFIG_USB_SUSPEND -#define PORT_RESET_MSEC 50 -#else -#define PORT_RESET_MSEC 10 -#endif - -/* this timer value might be vendor-specific ... */ -#define PORT_RESET_HW_MSEC 10 - -/* wrap-aware logic morphed from */ -#define tick_before(t1,t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0) - -/* called from some task, normally khubd */ -static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port) -{ - __hc32 __iomem *portstat = &ohci->regs->roothub.portstatus [port]; - u32 temp = 0; - u16 now = ohci_readl(ohci, &ohci->regs->fmnumber); - u16 reset_done = now + PORT_RESET_MSEC; - int limit_1 = DIV_ROUND_UP(PORT_RESET_MSEC, PORT_RESET_HW_MSEC); - - /* build a "continuous enough" reset signal, with up to - * 3msec gap between pulses. scheduler HZ==100 must work; - * this might need to be deadline-scheduled. - */ - do { - int limit_2; - - /* spin until any current reset finishes */ - limit_2 = PORT_RESET_HW_MSEC * 2; - while (--limit_2 >= 0) { - temp = ohci_readl (ohci, portstat); - /* handle e.g. CardBus eject */ - if (temp == ~(u32)0) - return -ESHUTDOWN; - if (!(temp & RH_PS_PRS)) - break; - udelay (500); - } - - /* timeout (a hardware error) has been observed when - * EHCI sets CF while this driver is resetting a port; - * presumably other disconnect paths might do it too. - */ - if (limit_2 < 0) { - ohci_dbg(ohci, - "port[%d] reset timeout, stat %08x\n", - port, temp); - break; - } - - if (!(temp & RH_PS_CCS)) - break; - if (temp & RH_PS_PRSC) - ohci_writel (ohci, RH_PS_PRSC, portstat); - - /* start the next reset, sleep till it's probably done */ - ohci_writel (ohci, RH_PS_PRS, portstat); - msleep(PORT_RESET_HW_MSEC); - now = ohci_readl(ohci, &ohci->regs->fmnumber); - } while (tick_before(now, reset_done) && --limit_1 >= 0); - - /* caller synchronizes using PRSC ... and handles PRS - * still being set when this returns. - */ - - return 0; -} - -static int ohci_hub_control ( - struct usb_hcd *hcd, - u16 typeReq, - u16 wValue, - u16 wIndex, - char *buf, - u16 wLength -) { - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int ports = ohci->num_ports; - u32 temp; - int retval = 0; - - if (unlikely(!HCD_HW_ACCESSIBLE(hcd))) - return -ESHUTDOWN; - - switch (typeReq) { - case ClearHubFeature: - switch (wValue) { - case C_HUB_OVER_CURRENT: - ohci_writel (ohci, RH_HS_OCIC, - &ohci->regs->roothub.status); - case C_HUB_LOCAL_POWER: - break; - default: - goto error; - } - break; - case ClearPortFeature: - if (!wIndex || wIndex > ports) - goto error; - wIndex--; - - switch (wValue) { - case USB_PORT_FEAT_ENABLE: - temp = RH_PS_CCS; - break; - case USB_PORT_FEAT_C_ENABLE: - temp = RH_PS_PESC; - break; - case USB_PORT_FEAT_SUSPEND: - temp = RH_PS_POCI; - break; - case USB_PORT_FEAT_C_SUSPEND: - temp = RH_PS_PSSC; - break; - case USB_PORT_FEAT_POWER: - temp = RH_PS_LSDA; - break; - case USB_PORT_FEAT_C_CONNECTION: - temp = RH_PS_CSC; - break; - case USB_PORT_FEAT_C_OVER_CURRENT: - temp = RH_PS_OCIC; - break; - case USB_PORT_FEAT_C_RESET: - temp = RH_PS_PRSC; - break; - default: - goto error; - } - ohci_writel (ohci, temp, - &ohci->regs->roothub.portstatus [wIndex]); - // ohci_readl (ohci, &ohci->regs->roothub.portstatus [wIndex]); - break; - case GetHubDescriptor: - ohci_hub_descriptor (ohci, (struct usb_hub_descriptor *) buf); - break; - case GetHubStatus: - temp = roothub_status (ohci) & ~(RH_HS_CRWE | RH_HS_DRWE); - put_unaligned_le32(temp, buf); - break; - case GetPortStatus: - if (!wIndex || wIndex > ports) - goto error; - wIndex--; - temp = roothub_portstatus (ohci, wIndex); - put_unaligned_le32(temp, buf); - -#ifndef OHCI_VERBOSE_DEBUG - if (*(u16*)(buf+2)) /* only if wPortChange is interesting */ -#endif - dbg_port (ohci, "GetStatus", wIndex, temp); - break; - case SetHubFeature: - switch (wValue) { - case C_HUB_OVER_CURRENT: - // FIXME: this can be cleared, yes? - case C_HUB_LOCAL_POWER: - break; - default: - goto error; - } - break; - case SetPortFeature: - if (!wIndex || wIndex > ports) - goto error; - wIndex--; - switch (wValue) { - case USB_PORT_FEAT_SUSPEND: -#ifdef CONFIG_USB_OTG - if (hcd->self.otg_port == (wIndex + 1) - && hcd->self.b_hnp_enable) - ohci->start_hnp(ohci); - else -#endif - ohci_writel (ohci, RH_PS_PSS, - &ohci->regs->roothub.portstatus [wIndex]); - break; - case USB_PORT_FEAT_POWER: - ohci_writel (ohci, RH_PS_PPS, - &ohci->regs->roothub.portstatus [wIndex]); - break; - case USB_PORT_FEAT_RESET: - retval = root_port_reset (ohci, wIndex); - break; - default: - goto error; - } - break; - - default: -error: - /* "protocol stall" on error */ - retval = -EPIPE; - } - return retval; -} - diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-jz4740.c b/ANDROID_3.4.5/drivers/usb/host/ohci-jz4740.c deleted file mode 100644 index 931d588c..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-jz4740.c +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Copyright (C) 2010, Lars-Peter Clausen - * - * 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. - * - * 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 -#include -#include - -struct jz4740_ohci_hcd { - struct ohci_hcd ohci_hcd; - - struct regulator *vbus; - bool vbus_enabled; - struct clk *clk; -}; - -static inline struct jz4740_ohci_hcd *hcd_to_jz4740_hcd(struct usb_hcd *hcd) -{ - return (struct jz4740_ohci_hcd *)(hcd->hcd_priv); -} - -static inline struct usb_hcd *jz4740_hcd_to_hcd(struct jz4740_ohci_hcd *jz4740_ohci) -{ - return container_of((void *)jz4740_ohci, struct usb_hcd, hcd_priv); -} - -static int ohci_jz4740_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - ret = ohci_init(ohci); - if (ret < 0) - return ret; - - ohci->num_ports = 1; - - ret = ohci_run(ohci); - if (ret < 0) { - dev_err(hcd->self.controller, "Can not start %s", - hcd->self.bus_name); - ohci_stop(hcd); - return ret; - } - return 0; -} - -static int ohci_jz4740_set_vbus_power(struct jz4740_ohci_hcd *jz4740_ohci, - bool enabled) -{ - int ret = 0; - - if (!jz4740_ohci->vbus) - return 0; - - if (enabled && !jz4740_ohci->vbus_enabled) { - ret = regulator_enable(jz4740_ohci->vbus); - if (ret) - dev_err(jz4740_hcd_to_hcd(jz4740_ohci)->self.controller, - "Could not power vbus\n"); - } else if (!enabled && jz4740_ohci->vbus_enabled) { - ret = regulator_disable(jz4740_ohci->vbus); - } - - if (ret == 0) - jz4740_ohci->vbus_enabled = enabled; - - return ret; -} - -static int ohci_jz4740_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, - u16 wIndex, char *buf, u16 wLength) -{ - struct jz4740_ohci_hcd *jz4740_ohci = hcd_to_jz4740_hcd(hcd); - int ret; - - switch (typeReq) { - case SetHubFeature: - if (wValue == USB_PORT_FEAT_POWER) - ret = ohci_jz4740_set_vbus_power(jz4740_ohci, true); - break; - case ClearHubFeature: - if (wValue == USB_PORT_FEAT_POWER) - ret = ohci_jz4740_set_vbus_power(jz4740_ohci, false); - break; - } - - if (ret) - return ret; - - return ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); -} - - -static const struct hc_driver ohci_jz4740_hc_driver = { - .description = hcd_name, - .product_desc = "JZ4740 OHCI", - .hcd_priv_size = sizeof(struct jz4740_ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .start = ohci_jz4740_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_jz4740_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - - -static __devinit int jz4740_ohci_probe(struct platform_device *pdev) -{ - int ret; - struct usb_hcd *hcd; - struct jz4740_ohci_hcd *jz4740_ohci; - struct resource *res; - int irq; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - if (!res) { - dev_err(&pdev->dev, "Failed to get platform resource\n"); - return -ENOENT; - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "Failed to get platform irq\n"); - return irq; - } - - hcd = usb_create_hcd(&ohci_jz4740_hc_driver, &pdev->dev, "jz4740"); - if (!hcd) { - dev_err(&pdev->dev, "Failed to create hcd.\n"); - return -ENOMEM; - } - - jz4740_ohci = hcd_to_jz4740_hcd(hcd); - - res = request_mem_region(res->start, resource_size(res), hcd_name); - if (!res) { - dev_err(&pdev->dev, "Failed to request mem region.\n"); - ret = -EBUSY; - goto err_free; - } - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - hcd->regs = ioremap(res->start, resource_size(res)); - - if (!hcd->regs) { - dev_err(&pdev->dev, "Failed to ioremap registers.\n"); - ret = -EBUSY; - goto err_release_mem; - } - - jz4740_ohci->clk = clk_get(&pdev->dev, "uhc"); - if (IS_ERR(jz4740_ohci->clk)) { - ret = PTR_ERR(jz4740_ohci->clk); - dev_err(&pdev->dev, "Failed to get clock: %d\n", ret); - goto err_iounmap; - } - - jz4740_ohci->vbus = regulator_get(&pdev->dev, "vbus"); - if (IS_ERR(jz4740_ohci->vbus)) - jz4740_ohci->vbus = NULL; - - - clk_set_rate(jz4740_ohci->clk, 48000000); - clk_enable(jz4740_ohci->clk); - if (jz4740_ohci->vbus) - ohci_jz4740_set_vbus_power(jz4740_ohci, true); - - platform_set_drvdata(pdev, hcd); - - ohci_hcd_init(hcd_to_ohci(hcd)); - - ret = usb_add_hcd(hcd, irq, 0); - if (ret) { - dev_err(&pdev->dev, "Failed to add hcd: %d\n", ret); - goto err_disable; - } - - return 0; - -err_disable: - platform_set_drvdata(pdev, NULL); - if (jz4740_ohci->vbus) { - regulator_disable(jz4740_ohci->vbus); - regulator_put(jz4740_ohci->vbus); - } - clk_disable(jz4740_ohci->clk); - - clk_put(jz4740_ohci->clk); -err_iounmap: - iounmap(hcd->regs); -err_release_mem: - release_mem_region(res->start, resource_size(res)); -err_free: - usb_put_hcd(hcd); - - return ret; -} - -static __devexit int jz4740_ohci_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct jz4740_ohci_hcd *jz4740_ohci = hcd_to_jz4740_hcd(hcd); - - usb_remove_hcd(hcd); - - platform_set_drvdata(pdev, NULL); - - if (jz4740_ohci->vbus) { - regulator_disable(jz4740_ohci->vbus); - regulator_put(jz4740_ohci->vbus); - } - - clk_disable(jz4740_ohci->clk); - clk_put(jz4740_ohci->clk); - - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - - usb_put_hcd(hcd); - - return 0; -} - -static struct platform_driver ohci_hcd_jz4740_driver = { - .probe = jz4740_ohci_probe, - .remove = __devexit_p(jz4740_ohci_remove), - .driver = { - .name = "jz4740-ohci", - .owner = THIS_MODULE, - }, -}; - -MODULE_ALIAS("platform:jz4740-ohci"); diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-mem.c b/ANDROID_3.4.5/drivers/usb/host/ohci-mem.c deleted file mode 100644 index 2f20d3dc..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-mem.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2002 David Brownell - * - * This file is licenced under the GPL. - */ - -/*-------------------------------------------------------------------------*/ - -/* - * OHCI deals with three types of memory: - * - data used only by the HCD ... kmalloc is fine - * - async and periodic schedules, shared by HC and HCD ... these - * need to use dma_pool or dma_alloc_coherent - * - driver buffers, read/written by HC ... the hcd glue or the - * device driver provides us with dma addresses - * - * There's also "register" data, which is memory mapped. - * No memory seen by this driver (or any HCD) may be paged out. - */ - -/*-------------------------------------------------------------------------*/ - -static void ohci_hcd_init (struct ohci_hcd *ohci) -{ - ohci->next_statechange = jiffies; - spin_lock_init (&ohci->lock); - INIT_LIST_HEAD (&ohci->pending); -} - -/*-------------------------------------------------------------------------*/ - -static int ohci_mem_init (struct ohci_hcd *ohci) -{ - ohci->td_cache = dma_pool_create ("ohci_td", - ohci_to_hcd(ohci)->self.controller, - sizeof (struct td), - 32 /* byte alignment */, - 0 /* no page-crossing issues */); - if (!ohci->td_cache) - return -ENOMEM; - ohci->ed_cache = dma_pool_create ("ohci_ed", - ohci_to_hcd(ohci)->self.controller, - sizeof (struct ed), - 16 /* byte alignment */, - 0 /* no page-crossing issues */); - if (!ohci->ed_cache) { - dma_pool_destroy (ohci->td_cache); - return -ENOMEM; - } - return 0; -} - -static void ohci_mem_cleanup (struct ohci_hcd *ohci) -{ - if (ohci->td_cache) { - dma_pool_destroy (ohci->td_cache); - ohci->td_cache = NULL; - } - if (ohci->ed_cache) { - dma_pool_destroy (ohci->ed_cache); - ohci->ed_cache = NULL; - } -} - -/*-------------------------------------------------------------------------*/ - -/* ohci "done list" processing needs this mapping */ -static inline struct td * -dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma) -{ - struct td *td; - - td_dma &= TD_MASK; - td = hc->td_hash [TD_HASH_FUNC(td_dma)]; - while (td && td->td_dma != td_dma) - td = td->td_hash; - return td; -} - -/* TDs ... */ -static struct td * -td_alloc (struct ohci_hcd *hc, gfp_t mem_flags) -{ - dma_addr_t dma; - struct td *td; - - td = dma_pool_alloc (hc->td_cache, mem_flags, &dma); - if (td) { - /* in case hc fetches it, make it look dead */ - memset (td, 0, sizeof *td); - td->hwNextTD = cpu_to_hc32 (hc, dma); - td->td_dma = dma; - /* hashed in td_fill */ - } - return td; -} - -static void -td_free (struct ohci_hcd *hc, struct td *td) -{ - struct td **prev = &hc->td_hash [TD_HASH_FUNC (td->td_dma)]; - - while (*prev && *prev != td) - prev = &(*prev)->td_hash; - if (*prev) - *prev = td->td_hash; - else if ((td->hwINFO & cpu_to_hc32(hc, TD_DONE)) != 0) - ohci_dbg (hc, "no hash for td %p\n", td); - dma_pool_free (hc->td_cache, td, td->td_dma); -} - -/*-------------------------------------------------------------------------*/ - -/* EDs ... */ -static struct ed * -ed_alloc (struct ohci_hcd *hc, gfp_t mem_flags) -{ - dma_addr_t dma; - struct ed *ed; - - ed = dma_pool_alloc (hc->ed_cache, mem_flags, &dma); - if (ed) { - memset (ed, 0, sizeof (*ed)); - INIT_LIST_HEAD (&ed->td_list); - ed->dma = dma; - } - return ed; -} - -static void -ed_free (struct ohci_hcd *hc, struct ed *ed) -{ - dma_pool_free (hc->ed_cache, ed, ed->dma); -} - diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-nxp.c b/ANDROID_3.4.5/drivers/usb/host/ohci-nxp.c deleted file mode 100644 index 6618de1d..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-nxp.c +++ /dev/null @@ -1,528 +0,0 @@ -/* - * driver for NXP USB Host devices - * - * Currently supported OHCI host devices: - * - Philips PNX4008 - * - NXP LPC32xx - * - * Authors: Dmitry Chigirev - * Vitaly Wool - * - * register initialization is based on code examples provided by Philips - * Copyright (c) 2005 Koninklijke Philips Electronics N.V. - * - * NOTE: This driver does not have suspend/resume functionality - * This driver is intended for engineering development purposes only - * - * 2005-2006 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#define USB_CONFIG_BASE 0x31020000 -#define PWRMAN_BASE 0x40004000 - -#define USB_CTRL IO_ADDRESS(PWRMAN_BASE + 0x64) - -/* USB_CTRL bit defines */ -#define USB_SLAVE_HCLK_EN (1 << 24) -#define USB_HOST_NEED_CLK_EN (1 << 21) - -#define USB_OTG_CLK_CTRL IO_ADDRESS(USB_CONFIG_BASE + 0xFF4) -#define USB_OTG_CLK_STAT IO_ADDRESS(USB_CONFIG_BASE + 0xFF8) - -/* USB_OTG_CLK_CTRL bit defines */ -#define AHB_M_CLOCK_ON (1 << 4) -#define OTG_CLOCK_ON (1 << 3) -#define I2C_CLOCK_ON (1 << 2) -#define DEV_CLOCK_ON (1 << 1) -#define HOST_CLOCK_ON (1 << 0) - -#define USB_OTG_STAT_CONTROL IO_ADDRESS(USB_CONFIG_BASE + 0x110) - -/* USB_OTG_STAT_CONTROL bit defines */ -#define TRANSPARENT_I2C_EN (1 << 7) -#define HOST_EN (1 << 0) - -/* ISP1301 USB transceiver I2C registers */ -#define ISP1301_MODE_CONTROL_1 0x04 /* u8 read, set, +1 clear */ - -#define MC1_SPEED_REG (1 << 0) -#define MC1_SUSPEND_REG (1 << 1) -#define MC1_DAT_SE0 (1 << 2) -#define MC1_TRANSPARENT (1 << 3) -#define MC1_BDIS_ACON_EN (1 << 4) -#define MC1_OE_INT_EN (1 << 5) -#define MC1_UART_EN (1 << 6) -#define MC1_MASK 0x7f - -#define ISP1301_MODE_CONTROL_2 0x12 /* u8 read, set, +1 clear */ - -#define MC2_GLOBAL_PWR_DN (1 << 0) -#define MC2_SPD_SUSP_CTRL (1 << 1) -#define MC2_BI_DI (1 << 2) -#define MC2_TRANSP_BDIR0 (1 << 3) -#define MC2_TRANSP_BDIR1 (1 << 4) -#define MC2_AUDIO_EN (1 << 5) -#define MC2_PSW_EN (1 << 6) -#define MC2_EN2V7 (1 << 7) - -#define ISP1301_OTG_CONTROL_1 0x06 /* u8 read, set, +1 clear */ -# define OTG1_DP_PULLUP (1 << 0) -# define OTG1_DM_PULLUP (1 << 1) -# define OTG1_DP_PULLDOWN (1 << 2) -# define OTG1_DM_PULLDOWN (1 << 3) -# define OTG1_ID_PULLDOWN (1 << 4) -# define OTG1_VBUS_DRV (1 << 5) -# define OTG1_VBUS_DISCHRG (1 << 6) -# define OTG1_VBUS_CHRG (1 << 7) -#define ISP1301_OTG_STATUS 0x10 /* u8 readonly */ -# define OTG_B_SESS_END (1 << 6) -# define OTG_B_SESS_VLD (1 << 7) - -#define ISP1301_I2C_ADDR 0x2C - -#define ISP1301_I2C_MODE_CONTROL_1 0x4 -#define ISP1301_I2C_MODE_CONTROL_2 0x12 -#define ISP1301_I2C_OTG_CONTROL_1 0x6 -#define ISP1301_I2C_OTG_CONTROL_2 0x10 -#define ISP1301_I2C_INTERRUPT_SOURCE 0x8 -#define ISP1301_I2C_INTERRUPT_LATCH 0xA -#define ISP1301_I2C_INTERRUPT_FALLING 0xC -#define ISP1301_I2C_INTERRUPT_RISING 0xE -#define ISP1301_I2C_REG_CLEAR_ADDR 1 - -/* On LPC32xx, those are undefined */ -#ifndef start_int_set_falling_edge -#define start_int_set_falling_edge(irq) -#define start_int_set_rising_edge(irq) -#define start_int_ack(irq) -#define start_int_mask(irq) -#define start_int_umask(irq) -#endif - -static struct i2c_driver isp1301_driver; -static struct i2c_client *isp1301_i2c_client; - -extern int usb_disabled(void); -extern int ocpi_enable(void); - -static struct clk *usb_clk; - -static const unsigned short normal_i2c[] = - { ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END }; - -static int isp1301_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - return 0; -} - -static int isp1301_remove(struct i2c_client *client) -{ - return 0; -} - -static const struct i2c_device_id isp1301_id[] = { - { "isp1301_nxp", 0 }, - { } -}; - -static struct i2c_driver isp1301_driver = { - .driver = { - .name = "isp1301_nxp", - }, - .probe = isp1301_probe, - .remove = isp1301_remove, - .id_table = isp1301_id, -}; - -static void isp1301_configure_pnx4008(void) -{ - /* PNX4008 only supports DAT_SE0 USB mode */ - /* PNX4008 R2A requires setting the MAX603 to output 3.6V */ - /* Power up externel charge-pump */ - - i2c_smbus_write_byte_data(isp1301_i2c_client, - ISP1301_I2C_MODE_CONTROL_1, MC1_DAT_SE0 | MC1_SPEED_REG); - i2c_smbus_write_byte_data(isp1301_i2c_client, - ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR, - ~(MC1_DAT_SE0 | MC1_SPEED_REG)); - i2c_smbus_write_byte_data(isp1301_i2c_client, - ISP1301_I2C_MODE_CONTROL_2, - MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL); - i2c_smbus_write_byte_data(isp1301_i2c_client, - ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR, - ~(MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL)); - i2c_smbus_write_byte_data(isp1301_i2c_client, - ISP1301_I2C_OTG_CONTROL_1, OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN); - i2c_smbus_write_byte_data(isp1301_i2c_client, - ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR, - ~(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN)); - i2c_smbus_write_byte_data(isp1301_i2c_client, - ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR, 0xFF); - i2c_smbus_write_byte_data(isp1301_i2c_client, - ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR, - 0xFF); - i2c_smbus_write_byte_data(isp1301_i2c_client, - ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR, - 0xFF); -} - -static void isp1301_configure_lpc32xx(void) -{ - /* LPC32XX only supports DAT_SE0 USB mode */ - /* This sequence is important */ - - /* Disable transparent UART mode first */ - i2c_smbus_write_byte_data(isp1301_i2c_client, - (ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), - MC1_UART_EN); - i2c_smbus_write_byte_data(isp1301_i2c_client, - (ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), - ~MC1_SPEED_REG); - i2c_smbus_write_byte_data(isp1301_i2c_client, - ISP1301_I2C_MODE_CONTROL_1, MC1_SPEED_REG); - i2c_smbus_write_byte_data(isp1301_i2c_client, - (ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR), - ~0); - i2c_smbus_write_byte_data(isp1301_i2c_client, - ISP1301_I2C_MODE_CONTROL_2, - (MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL)); - i2c_smbus_write_byte_data(isp1301_i2c_client, - (ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), ~0); - i2c_smbus_write_byte_data(isp1301_i2c_client, - ISP1301_I2C_MODE_CONTROL_1, MC1_DAT_SE0); - i2c_smbus_write_byte_data(isp1301_i2c_client, - ISP1301_I2C_OTG_CONTROL_1, - (OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN)); - i2c_smbus_write_byte_data(isp1301_i2c_client, - (ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), - (OTG1_DM_PULLUP | OTG1_DP_PULLUP)); - i2c_smbus_write_byte_data(isp1301_i2c_client, - ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR, ~0); - i2c_smbus_write_byte_data(isp1301_i2c_client, - ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR, - ~0); - i2c_smbus_write_byte_data(isp1301_i2c_client, - ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR, ~0); - - /* Enable usb_need_clk clock after transceiver is initialized */ - __raw_writel((__raw_readl(USB_CTRL) | (1 << 22)), USB_CTRL); - - printk(KERN_INFO "ISP1301 Vendor ID : 0x%04x\n", - i2c_smbus_read_word_data(isp1301_i2c_client, 0x00)); - printk(KERN_INFO "ISP1301 Product ID : 0x%04x\n", - i2c_smbus_read_word_data(isp1301_i2c_client, 0x02)); - printk(KERN_INFO "ISP1301 Version ID : 0x%04x\n", - i2c_smbus_read_word_data(isp1301_i2c_client, 0x14)); -} - -static void isp1301_configure(void) -{ - if (machine_is_pnx4008()) - isp1301_configure_pnx4008(); - else - isp1301_configure_lpc32xx(); -} - -static inline void isp1301_vbus_on(void) -{ - i2c_smbus_write_byte_data(isp1301_i2c_client, ISP1301_I2C_OTG_CONTROL_1, - OTG1_VBUS_DRV); -} - -static inline void isp1301_vbus_off(void) -{ - i2c_smbus_write_byte_data(isp1301_i2c_client, - ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR, - OTG1_VBUS_DRV); -} - -static void nxp_start_hc(void) -{ - unsigned long tmp = __raw_readl(USB_OTG_STAT_CONTROL) | HOST_EN; - __raw_writel(tmp, USB_OTG_STAT_CONTROL); - isp1301_vbus_on(); -} - -static void nxp_stop_hc(void) -{ - unsigned long tmp; - isp1301_vbus_off(); - tmp = __raw_readl(USB_OTG_STAT_CONTROL) & ~HOST_EN; - __raw_writel(tmp, USB_OTG_STAT_CONTROL); -} - -static int __devinit ohci_nxp_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - if ((ret = ohci_init(ohci)) < 0) - return ret; - - if ((ret = ohci_run(ohci)) < 0) { - dev_err(hcd->self.controller, "can't start\n"); - ohci_stop(hcd); - return ret; - } - return 0; -} - -static const struct hc_driver ohci_nxp_hc_driver = { - .description = hcd_name, - .product_desc = "nxp OHCI", - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - .hcd_priv_size = sizeof(struct ohci_hcd), - /* - * basic lifecycle operations - */ - .start = ohci_nxp_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -#define USB_CLOCK_MASK (AHB_M_CLOCK_ON| OTG_CLOCK_ON | HOST_CLOCK_ON | I2C_CLOCK_ON) - -static void nxp_set_usb_bits(void) -{ - if (machine_is_pnx4008()) { - start_int_set_falling_edge(SE_USB_OTG_ATX_INT_N); - start_int_ack(SE_USB_OTG_ATX_INT_N); - start_int_umask(SE_USB_OTG_ATX_INT_N); - - start_int_set_rising_edge(SE_USB_OTG_TIMER_INT); - start_int_ack(SE_USB_OTG_TIMER_INT); - start_int_umask(SE_USB_OTG_TIMER_INT); - - start_int_set_rising_edge(SE_USB_I2C_INT); - start_int_ack(SE_USB_I2C_INT); - start_int_umask(SE_USB_I2C_INT); - - start_int_set_rising_edge(SE_USB_INT); - start_int_ack(SE_USB_INT); - start_int_umask(SE_USB_INT); - - start_int_set_rising_edge(SE_USB_NEED_CLK_INT); - start_int_ack(SE_USB_NEED_CLK_INT); - start_int_umask(SE_USB_NEED_CLK_INT); - - start_int_set_rising_edge(SE_USB_AHB_NEED_CLK_INT); - start_int_ack(SE_USB_AHB_NEED_CLK_INT); - start_int_umask(SE_USB_AHB_NEED_CLK_INT); - } -} - -static void nxp_unset_usb_bits(void) -{ - if (machine_is_pnx4008()) { - start_int_mask(SE_USB_OTG_ATX_INT_N); - start_int_mask(SE_USB_OTG_TIMER_INT); - start_int_mask(SE_USB_I2C_INT); - start_int_mask(SE_USB_INT); - start_int_mask(SE_USB_NEED_CLK_INT); - start_int_mask(SE_USB_AHB_NEED_CLK_INT); - } -} - -static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd = 0; - struct ohci_hcd *ohci; - const struct hc_driver *driver = &ohci_nxp_hc_driver; - struct i2c_adapter *i2c_adap; - struct i2c_board_info i2c_info; - - int ret = 0, irq; - - dev_dbg(&pdev->dev, "%s: " DRIVER_DESC " (nxp)\n", hcd_name); - if (usb_disabled()) { - err("USB is disabled"); - ret = -ENODEV; - goto out; - } - - if (pdev->num_resources != 2 - || pdev->resource[0].flags != IORESOURCE_MEM - || pdev->resource[1].flags != IORESOURCE_IRQ) { - err("Invalid resource configuration"); - ret = -ENODEV; - goto out; - } - - /* Enable AHB slave USB clock, needed for further USB clock control */ - __raw_writel(USB_SLAVE_HCLK_EN | (1 << 19), USB_CTRL); - - ret = i2c_add_driver(&isp1301_driver); - if (ret < 0) { - err("failed to add ISP1301 driver"); - goto out; - } - i2c_adap = i2c_get_adapter(2); - memset(&i2c_info, 0, sizeof(struct i2c_board_info)); - strlcpy(i2c_info.type, "isp1301_nxp", I2C_NAME_SIZE); - isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info, - normal_i2c, NULL); - i2c_put_adapter(i2c_adap); - if (!isp1301_i2c_client) { - err("failed to connect I2C to ISP1301 USB Transceiver"); - ret = -ENODEV; - goto out_i2c_driver; - } - - isp1301_configure(); - - /* Enable USB PLL */ - usb_clk = clk_get(&pdev->dev, "ck_pll5"); - if (IS_ERR(usb_clk)) { - err("failed to acquire USB PLL"); - ret = PTR_ERR(usb_clk); - goto out1; - } - - ret = clk_enable(usb_clk); - if (ret < 0) { - err("failed to start USB PLL"); - goto out2; - } - - ret = clk_set_rate(usb_clk, 48000); - if (ret < 0) { - err("failed to set USB clock rate"); - goto out3; - } - - __raw_writel(__raw_readl(USB_CTRL) | USB_HOST_NEED_CLK_EN, USB_CTRL); - - /* Set to enable all needed USB clocks */ - __raw_writel(USB_CLOCK_MASK, USB_OTG_CLK_CTRL); - - while ((__raw_readl(USB_OTG_CLK_STAT) & USB_CLOCK_MASK) != - USB_CLOCK_MASK) ; - - hcd = usb_create_hcd (driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - err("Failed to allocate HC buffer"); - ret = -ENOMEM; - goto out3; - } - - /* Set all USB bits in the Start Enable register */ - nxp_set_usb_bits(); - - hcd->rsrc_start = pdev->resource[0].start; - hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - dev_dbg(&pdev->dev, "request_mem_region failed\n"); - ret = -ENOMEM; - goto out4; - } - hcd->regs = (void __iomem *)pdev->resource[0].start; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = -ENXIO; - goto out4; - } - - nxp_start_hc(); - platform_set_drvdata(pdev, hcd); - ohci = hcd_to_ohci(hcd); - ohci_hcd_init(ohci); - - dev_info(&pdev->dev, "at 0x%p, irq %d\n", hcd->regs, hcd->irq); - ret = usb_add_hcd(hcd, irq, 0); - if (ret == 0) - return ret; - - nxp_stop_hc(); -out4: - nxp_unset_usb_bits(); - usb_put_hcd(hcd); -out3: - clk_disable(usb_clk); -out2: - clk_put(usb_clk); -out1: - i2c_unregister_device(isp1301_i2c_client); - isp1301_i2c_client = NULL; -out_i2c_driver: - i2c_del_driver(&isp1301_driver); -out: - return ret; -} - -static int usb_hcd_nxp_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - nxp_stop_hc(); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - nxp_unset_usb_bits(); - clk_disable(usb_clk); - clk_put(usb_clk); - i2c_unregister_device(isp1301_i2c_client); - isp1301_i2c_client = NULL; - i2c_del_driver(&isp1301_driver); - - platform_set_drvdata(pdev, NULL); - - return 0; -} - -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:usb-ohci"); - -static struct platform_driver usb_hcd_nxp_driver = { - .driver = { - .name = "usb-ohci", - .owner = THIS_MODULE, - }, - .probe = usb_hcd_nxp_probe, - .remove = usb_hcd_nxp_remove, -}; - diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-octeon.c b/ANDROID_3.4.5/drivers/usb/host/ohci-octeon.c deleted file mode 100644 index d469bf9b..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-octeon.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * EHCI HCD glue for Cavium Octeon II SOCs. - * - * Loosely based on ehci-au1xxx.c - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 2010 Cavium Networks - * - */ - -#include - -#include -#include - -#define OCTEON_OHCI_HCD_NAME "octeon-ohci" - -/* Common clock init code. */ -void octeon2_usb_clocks_start(void); -void octeon2_usb_clocks_stop(void); - -static void ohci_octeon_hw_start(void) -{ - union cvmx_uctlx_ohci_ctl ohci_ctl; - - octeon2_usb_clocks_start(); - - ohci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_OHCI_CTL(0)); - ohci_ctl.s.l2c_addr_msb = 0; - ohci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */ - ohci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */ - cvmx_write_csr(CVMX_UCTLX_OHCI_CTL(0), ohci_ctl.u64); - -} - -static void ohci_octeon_hw_stop(void) -{ - /* Undo ohci_octeon_start() */ - octeon2_usb_clocks_stop(); -} - -static int __devinit ohci_octeon_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - ret = ohci_init(ohci); - - if (ret < 0) - return ret; - - ret = ohci_run(ohci); - - if (ret < 0) { - ohci_err(ohci, "can't start %s", hcd->self.bus_name); - ohci_stop(hcd); - return ret; - } - - return 0; -} - -static const struct hc_driver ohci_octeon_hc_driver = { - .description = hcd_name, - .product_desc = "Octeon OHCI", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .start = ohci_octeon_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, - - .start_port_reset = ohci_start_port_reset, -}; - -static int ohci_octeon_drv_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - struct ohci_hcd *ohci; - void *reg_base; - struct resource *res_mem; - int irq; - int ret; - - if (usb_disabled()) - return -ENODEV; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "No irq assigned\n"); - return -ENODEV; - } - - res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res_mem == NULL) { - dev_err(&pdev->dev, "No register space assigned\n"); - return -ENODEV; - } - - /* Ohci is a 32-bit device. */ - pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; - - hcd = usb_create_hcd(&ohci_octeon_hc_driver, &pdev->dev, "octeon"); - if (!hcd) - return -ENOMEM; - - hcd->rsrc_start = res_mem->start; - hcd->rsrc_len = resource_size(res_mem); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - OCTEON_OHCI_HCD_NAME)) { - dev_err(&pdev->dev, "request_mem_region failed\n"); - ret = -EBUSY; - goto err1; - } - - reg_base = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!reg_base) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto err2; - } - - ohci_octeon_hw_start(); - - hcd->regs = reg_base; - - ohci = hcd_to_ohci(hcd); - - /* Octeon OHCI matches CPU endianness. */ -#ifdef __BIG_ENDIAN - ohci->flags |= OHCI_QUIRK_BE_MMIO; -#endif - - ohci_hcd_init(ohci); - - ret = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (ret) { - dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret); - goto err3; - } - - platform_set_drvdata(pdev, hcd); - - return 0; - -err3: - ohci_octeon_hw_stop(); - - iounmap(hcd->regs); -err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err1: - usb_put_hcd(hcd); - return ret; -} - -static int ohci_octeon_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - - ohci_octeon_hw_stop(); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - - platform_set_drvdata(pdev, NULL); - - return 0; -} - -static struct platform_driver ohci_octeon_driver = { - .probe = ohci_octeon_drv_probe, - .remove = ohci_octeon_drv_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = OCTEON_OHCI_HCD_NAME, - .owner = THIS_MODULE, - } -}; - -MODULE_ALIAS("platform:" OCTEON_OHCI_HCD_NAME); diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-omap.c b/ANDROID_3.4.5/drivers/usb/host/ohci-omap.c deleted file mode 100644 index 96451e41..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-omap.c +++ /dev/null @@ -1,557 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2005 David Brownell - * (C) Copyright 2002 Hewlett-Packard Company - * - * OMAP Bus Glue - * - * Modified for OMAP by Tony Lindgren - * Based on the 2.4 OMAP OHCI driver originally done by MontaVista Software Inc. - * and on ohci-sa1111.c by Christopher Hoover - * - * This file is licenced under the GPL. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - - -/* OMAP-1510 OHCI has its own MMU for DMA */ -#define OMAP1510_LB_MEMSIZE 32 /* Should be same as SDRAM size */ -#define OMAP1510_LB_CLOCK_DIV 0xfffec10c -#define OMAP1510_LB_MMU_CTL 0xfffec208 -#define OMAP1510_LB_MMU_LCK 0xfffec224 -#define OMAP1510_LB_MMU_LD_TLB 0xfffec228 -#define OMAP1510_LB_MMU_CAM_H 0xfffec22c -#define OMAP1510_LB_MMU_CAM_L 0xfffec230 -#define OMAP1510_LB_MMU_RAM_H 0xfffec234 -#define OMAP1510_LB_MMU_RAM_L 0xfffec238 - - -#ifndef CONFIG_ARCH_OMAP -#error "This file is OMAP bus glue. CONFIG_OMAP must be defined." -#endif - -#ifdef CONFIG_TPS65010 -#include -#else - -#define LOW 0 -#define HIGH 1 - -#define GPIO1 1 - -static inline int tps65010_set_gpio_out_value(unsigned gpio, unsigned value) -{ - return 0; -} - -#endif - -extern int usb_disabled(void); -extern int ocpi_enable(void); - -static struct clk *usb_host_ck; -static struct clk *usb_dc_ck; -static int host_enabled; -static int host_initialized; - -static void omap_ohci_clock_power(int on) -{ - if (on) { - clk_enable(usb_dc_ck); - clk_enable(usb_host_ck); - /* guesstimate for T5 == 1x 32K clock + APLL lock time */ - udelay(100); - } else { - clk_disable(usb_host_ck); - clk_disable(usb_dc_ck); - } -} - -/* - * Board specific gang-switched transceiver power on/off. - * NOTE: OSK supplies power from DC, not battery. - */ -static int omap_ohci_transceiver_power(int on) -{ - if (on) { - if (machine_is_omap_innovator() && cpu_is_omap1510()) - fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL) - | ((1 << 5/*usb1*/) | (1 << 3/*usb2*/)), - INNOVATOR_FPGA_CAM_USB_CONTROL); - else if (machine_is_omap_osk()) - tps65010_set_gpio_out_value(GPIO1, LOW); - } else { - if (machine_is_omap_innovator() && cpu_is_omap1510()) - fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL) - & ~((1 << 5/*usb1*/) | (1 << 3/*usb2*/)), - INNOVATOR_FPGA_CAM_USB_CONTROL); - else if (machine_is_omap_osk()) - tps65010_set_gpio_out_value(GPIO1, HIGH); - } - - return 0; -} - -#ifdef CONFIG_ARCH_OMAP15XX -/* - * OMAP-1510 specific Local Bus clock on/off - */ -static int omap_1510_local_bus_power(int on) -{ - if (on) { - omap_writel((1 << 1) | (1 << 0), OMAP1510_LB_MMU_CTL); - udelay(200); - } else { - omap_writel(0, OMAP1510_LB_MMU_CTL); - } - - return 0; -} - -/* - * OMAP-1510 specific Local Bus initialization - * NOTE: This assumes 32MB memory size in OMAP1510LB_MEMSIZE. - * See also arch/mach-omap/memory.h for __virt_to_dma() and - * __dma_to_virt() which need to match with the physical - * Local Bus address below. - */ -static int omap_1510_local_bus_init(void) -{ - unsigned int tlb; - unsigned long lbaddr, physaddr; - - omap_writel((omap_readl(OMAP1510_LB_CLOCK_DIV) & 0xfffffff8) | 0x4, - OMAP1510_LB_CLOCK_DIV); - - /* Configure the Local Bus MMU table */ - for (tlb = 0; tlb < OMAP1510_LB_MEMSIZE; tlb++) { - lbaddr = tlb * 0x00100000 + OMAP1510_LB_OFFSET; - physaddr = tlb * 0x00100000 + PHYS_OFFSET; - omap_writel((lbaddr & 0x0fffffff) >> 22, OMAP1510_LB_MMU_CAM_H); - omap_writel(((lbaddr & 0x003ffc00) >> 6) | 0xc, - OMAP1510_LB_MMU_CAM_L); - omap_writel(physaddr >> 16, OMAP1510_LB_MMU_RAM_H); - omap_writel((physaddr & 0x0000fc00) | 0x300, OMAP1510_LB_MMU_RAM_L); - omap_writel(tlb << 4, OMAP1510_LB_MMU_LCK); - omap_writel(0x1, OMAP1510_LB_MMU_LD_TLB); - } - - /* Enable the walking table */ - omap_writel(omap_readl(OMAP1510_LB_MMU_CTL) | (1 << 3), OMAP1510_LB_MMU_CTL); - udelay(200); - - return 0; -} -#else -#define omap_1510_local_bus_power(x) {} -#define omap_1510_local_bus_init() {} -#endif - -#ifdef CONFIG_USB_OTG - -static void start_hnp(struct ohci_hcd *ohci) -{ - const unsigned port = ohci_to_hcd(ohci)->self.otg_port - 1; - unsigned long flags; - u32 l; - - otg_start_hnp(ohci->transceiver->otg); - - local_irq_save(flags); - ohci->transceiver->state = OTG_STATE_A_SUSPEND; - writel (RH_PS_PSS, &ohci->regs->roothub.portstatus [port]); - l = omap_readl(OTG_CTRL); - l &= ~OTG_A_BUSREQ; - omap_writel(l, OTG_CTRL); - local_irq_restore(flags); -} - -#endif - -/*-------------------------------------------------------------------------*/ - -static int ohci_omap_init(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - struct omap_usb_config *config = hcd->self.controller->platform_data; - int need_transceiver = (config->otg != 0); - int ret; - - dev_dbg(hcd->self.controller, "starting USB Controller\n"); - - if (config->otg) { - ohci_to_hcd(ohci)->self.otg_port = config->otg; - /* default/minimum OTG power budget: 8 mA */ - ohci_to_hcd(ohci)->power_budget = 8; - } - - /* boards can use OTG transceivers in non-OTG modes */ - need_transceiver = need_transceiver - || machine_is_omap_h2() || machine_is_omap_h3(); - - if (cpu_is_omap16xx()) - ocpi_enable(); - -#ifdef CONFIG_USB_OTG - if (need_transceiver) { - ohci->transceiver = usb_get_transceiver(); - if (ohci->transceiver) { - int status = otg_set_host(ohci->transceiver->otg, - &ohci_to_hcd(ohci)->self); - dev_dbg(hcd->self.controller, "init %s transceiver, status %d\n", - ohci->transceiver->label, status); - if (status) { - if (ohci->transceiver) - put_device(ohci->transceiver->dev); - return status; - } - } else { - dev_err(hcd->self.controller, "can't find transceiver\n"); - return -ENODEV; - } - ohci->start_hnp = start_hnp; - } -#endif - - omap_ohci_clock_power(1); - - if (cpu_is_omap15xx()) { - omap_1510_local_bus_power(1); - omap_1510_local_bus_init(); - } - - if ((ret = ohci_init(ohci)) < 0) - return ret; - - /* board-specific power switching and overcurrent support */ - if (machine_is_omap_osk() || machine_is_omap_innovator()) { - u32 rh = roothub_a (ohci); - - /* power switching (ganged by default) */ - rh &= ~RH_A_NPS; - - /* TPS2045 switch for internal transceiver (port 1) */ - if (machine_is_omap_osk()) { - ohci_to_hcd(ohci)->power_budget = 250; - - rh &= ~RH_A_NOCP; - - /* gpio9 for overcurrent detction */ - omap_cfg_reg(W8_1610_GPIO9); - gpio_request(9, "OHCI overcurrent"); - gpio_direction_input(9); - - /* for paranoia's sake: disable USB.PUEN */ - omap_cfg_reg(W4_USB_HIGHZ); - } - ohci_writel(ohci, rh, &ohci->regs->roothub.a); - ohci->flags &= ~OHCI_QUIRK_HUB_POWER; - } else if (machine_is_nokia770()) { - /* We require a self-powered hub, which should have - * plenty of power. */ - ohci_to_hcd(ohci)->power_budget = 0; - } - - /* FIXME khubd hub requests should manage power switching */ - omap_ohci_transceiver_power(1); - - /* board init will have already handled HMC and mux setup. - * any external transceiver should already be initialized - * too, so all configured ports use the right signaling now. - */ - - return 0; -} - -static void ohci_omap_stop(struct usb_hcd *hcd) -{ - dev_dbg(hcd->self.controller, "stopping USB Controller\n"); - ohci_stop(hcd); - omap_ohci_clock_power(0); -} - - -/*-------------------------------------------------------------------------*/ - -/** - * usb_hcd_omap_probe - initialize OMAP-based HCDs - * Context: !in_interrupt() - * - * Allocates basic resources for this USB host controller, and - * then invokes the start() method for the HCD associated with it - * through the hotplug entry's driver_data. - */ -static int usb_hcd_omap_probe (const struct hc_driver *driver, - struct platform_device *pdev) -{ - int retval, irq; - struct usb_hcd *hcd = 0; - struct ohci_hcd *ohci; - - if (pdev->num_resources != 2) { - printk(KERN_ERR "hcd probe: invalid num_resources: %i\n", - pdev->num_resources); - return -ENODEV; - } - - if (pdev->resource[0].flags != IORESOURCE_MEM - || pdev->resource[1].flags != IORESOURCE_IRQ) { - printk(KERN_ERR "hcd probe: invalid resource type\n"); - return -ENODEV; - } - - usb_host_ck = clk_get(&pdev->dev, "usb_hhc_ck"); - if (IS_ERR(usb_host_ck)) - return PTR_ERR(usb_host_ck); - - if (!cpu_is_omap15xx()) - usb_dc_ck = clk_get(&pdev->dev, "usb_dc_ck"); - else - usb_dc_ck = clk_get(&pdev->dev, "lb_ck"); - - if (IS_ERR(usb_dc_ck)) { - clk_put(usb_host_ck); - return PTR_ERR(usb_dc_ck); - } - - - hcd = usb_create_hcd (driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - retval = -ENOMEM; - goto err0; - } - hcd->rsrc_start = pdev->resource[0].start; - hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - dev_dbg(&pdev->dev, "request_mem_region failed\n"); - retval = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - dev_err(&pdev->dev, "can't ioremap OHCI HCD\n"); - retval = -ENOMEM; - goto err2; - } - - ohci = hcd_to_ohci(hcd); - ohci_hcd_init(ohci); - - host_initialized = 0; - host_enabled = 1; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - retval = -ENXIO; - goto err3; - } - retval = usb_add_hcd(hcd, irq, 0); - if (retval) - goto err3; - - host_initialized = 1; - - if (!host_enabled) - omap_ohci_clock_power(0); - - return 0; -err3: - iounmap(hcd->regs); -err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err1: - usb_put_hcd(hcd); -err0: - clk_put(usb_dc_ck); - clk_put(usb_host_ck); - return retval; -} - - -/* may be called with controller, bus, and devices active */ - -/** - * usb_hcd_omap_remove - shutdown processing for OMAP-based HCDs - * @dev: USB Host Controller being removed - * Context: !in_interrupt() - * - * Reverses the effect of usb_hcd_omap_probe(), first invoking - * the HCD's stop() method. It is always called from a thread - * context, normally "rmmod", "apmd", or something similar. - */ -static inline void -usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - - usb_remove_hcd(hcd); - if (ohci->transceiver) { - (void) otg_set_host(ohci->transceiver->otg, 0); - put_device(ohci->transceiver->dev); - } - if (machine_is_omap_osk()) - gpio_free(9); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - clk_put(usb_dc_ck); - clk_put(usb_host_ck); -} - -/*-------------------------------------------------------------------------*/ - -static int -ohci_omap_start (struct usb_hcd *hcd) -{ - struct omap_usb_config *config; - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int ret; - - if (!host_enabled) - return 0; - config = hcd->self.controller->platform_data; - if (config->otg || config->rwc) { - ohci->hc_control = OHCI_CTRL_RWC; - writel(OHCI_CTRL_RWC, &ohci->regs->control); - } - - if ((ret = ohci_run (ohci)) < 0) { - dev_err(hcd->self.controller, "can't start\n"); - ohci_stop (hcd); - return ret; - } - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static const struct hc_driver ohci_omap_hc_driver = { - .description = hcd_name, - .product_desc = "OMAP OHCI", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .reset = ohci_omap_init, - .start = ohci_omap_start, - .stop = ohci_omap_stop, - .shutdown = ohci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -/*-------------------------------------------------------------------------*/ - -static int ohci_hcd_omap_drv_probe(struct platform_device *dev) -{ - return usb_hcd_omap_probe(&ohci_omap_hc_driver, dev); -} - -static int ohci_hcd_omap_drv_remove(struct platform_device *dev) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - - usb_hcd_omap_remove(hcd, dev); - platform_set_drvdata(dev, NULL); - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_PM - -static int ohci_omap_suspend(struct platform_device *dev, pm_message_t message) -{ - struct ohci_hcd *ohci = hcd_to_ohci(platform_get_drvdata(dev)); - - if (time_before(jiffies, ohci->next_statechange)) - msleep(5); - ohci->next_statechange = jiffies; - - omap_ohci_clock_power(0); - return 0; -} - -static int ohci_omap_resume(struct platform_device *dev) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - - if (time_before(jiffies, ohci->next_statechange)) - msleep(5); - ohci->next_statechange = jiffies; - - omap_ohci_clock_power(1); - ohci_finish_controller_resume(hcd); - return 0; -} - -#endif - -/*-------------------------------------------------------------------------*/ - -/* - * Driver definition to register with the OMAP bus - */ -static struct platform_driver ohci_hcd_omap_driver = { - .probe = ohci_hcd_omap_drv_probe, - .remove = ohci_hcd_omap_drv_remove, - .shutdown = usb_hcd_platform_shutdown, -#ifdef CONFIG_PM - .suspend = ohci_omap_suspend, - .resume = ohci_omap_resume, -#endif - .driver = { - .owner = THIS_MODULE, - .name = "ohci", - }, -}; - -MODULE_ALIAS("platform:ohci"); diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-omap3.c b/ANDROID_3.4.5/drivers/usb/host/ohci-omap3.c deleted file mode 100644 index 1b8133b6..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-omap3.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * ohci-omap3.c - driver for OHCI on OMAP3 and later processors - * - * Bus Glue for OMAP3 USBHOST 3 port OHCI controller - * This controller is also used in later OMAPs and AM35x chips - * - * Copyright (C) 2007-2010 Texas Instruments, Inc. - * Author: Vikram Pandita - * Author: Anand Gadiyar - * Author: Keshava Munegowda - * - * Based on ehci-omap.c and some other ohci glue layers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * TODO (last updated Feb 27, 2011): - * - add kernel-doc - */ - -#include -#include -#include - -/*-------------------------------------------------------------------------*/ - -static int ohci_omap3_init(struct usb_hcd *hcd) -{ - dev_dbg(hcd->self.controller, "starting OHCI controller\n"); - - return ohci_init(hcd_to_ohci(hcd)); -} - -/*-------------------------------------------------------------------------*/ - -static int ohci_omap3_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - /* - * RemoteWakeupConnected has to be set explicitly before - * calling ohci_run. The reset value of RWC is 0. - */ - ohci->hc_control = OHCI_CTRL_RWC; - writel(OHCI_CTRL_RWC, &ohci->regs->control); - - ret = ohci_run(ohci); - - if (ret < 0) { - dev_err(hcd->self.controller, "can't start\n"); - ohci_stop(hcd); - } - - return ret; -} - -/*-------------------------------------------------------------------------*/ - -static const struct hc_driver ohci_omap3_hc_driver = { - .description = hcd_name, - .product_desc = "OMAP3 OHCI Host Controller", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .reset = ohci_omap3_init, - .start = ohci_omap3_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -/*-------------------------------------------------------------------------*/ - -/* - * configure so an HC device and id are always provided - * always called with process context; sleeping is OK - */ - -/** - * ohci_hcd_omap3_probe - initialize OMAP-based HCDs - * - * Allocates basic resources for this USB host controller, and - * then invokes the start() method for the HCD associated with it - * through the hotplug entry's driver_data. - */ -static int __devinit ohci_hcd_omap3_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct usb_hcd *hcd = NULL; - void __iomem *regs = NULL; - struct resource *res; - int ret = -ENODEV; - int irq; - - if (usb_disabled()) - return -ENODEV; - - if (!dev->parent) { - dev_err(dev, "Missing parent device\n"); - return -ENODEV; - } - - irq = platform_get_irq_byname(pdev, "ohci-irq"); - if (irq < 0) { - dev_err(dev, "OHCI irq failed\n"); - return -ENODEV; - } - - res = platform_get_resource_byname(pdev, - IORESOURCE_MEM, "ohci"); - if (!res) { - dev_err(dev, "UHH OHCI get resource failed\n"); - return -ENOMEM; - } - - regs = ioremap(res->start, resource_size(res)); - if (!regs) { - dev_err(dev, "UHH OHCI ioremap failed\n"); - return -ENOMEM; - } - - - hcd = usb_create_hcd(&ohci_omap3_hc_driver, dev, - dev_name(dev)); - if (!hcd) { - dev_err(dev, "usb_create_hcd failed\n"); - goto err_io; - } - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - hcd->regs = regs; - - pm_runtime_enable(dev); - pm_runtime_get_sync(dev); - - ohci_hcd_init(hcd_to_ohci(hcd)); - - ret = usb_add_hcd(hcd, irq, 0); - if (ret) { - dev_dbg(dev, "failed to add hcd with err %d\n", ret); - goto err_add_hcd; - } - - return 0; - -err_add_hcd: - pm_runtime_put_sync(dev); - usb_put_hcd(hcd); - -err_io: - iounmap(regs); - - return ret; -} - -/* - * may be called without controller electrically present - * may be called with controller, bus, and devices active - */ - -/** - * ohci_hcd_omap3_remove - shutdown processing for OHCI HCDs - * @pdev: USB Host Controller being removed - * - * Reverses the effect of ohci_hcd_omap3_probe(), first invoking - * the HCD's stop() method. It is always called from a thread - * context, normally "rmmod", "apmd", or something similar. - */ -static int __devexit ohci_hcd_omap3_remove(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct usb_hcd *hcd = dev_get_drvdata(dev); - - iounmap(hcd->regs); - usb_remove_hcd(hcd); - pm_runtime_put_sync(dev); - pm_runtime_disable(dev); - usb_put_hcd(hcd); - return 0; -} - -static void ohci_hcd_omap3_shutdown(struct platform_device *pdev) -{ - struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - -static struct platform_driver ohci_hcd_omap3_driver = { - .probe = ohci_hcd_omap3_probe, - .remove = __devexit_p(ohci_hcd_omap3_remove), - .shutdown = ohci_hcd_omap3_shutdown, - .driver = { - .name = "ohci-omap3", - }, -}; - -MODULE_ALIAS("platform:ohci-omap3"); -MODULE_AUTHOR("Anand Gadiyar "); diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-pci.c b/ANDROID_3.4.5/drivers/usb/host/ohci-pci.c deleted file mode 100644 index 1843bb68..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-pci.c +++ /dev/null @@ -1,422 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2002 David Brownell - * - * [ Initialisation is based on Linus' ] - * [ uhci code and gregs ohci fragments ] - * [ (C) Copyright 1999 Linus Torvalds ] - * [ (C) Copyright 1999 Gregory P. Smith] - * - * PCI Bus Glue - * - * This file is licenced under the GPL. - */ - -#ifndef CONFIG_PCI -#error "This file is PCI bus glue. CONFIG_PCI must be defined." -#endif - -#include -#include - - -/*-------------------------------------------------------------------------*/ - -static int broken_suspend(struct usb_hcd *hcd) -{ - device_init_wakeup(&hcd->self.root_hub->dev, 0); - return 0; -} - -/* AMD 756, for most chips (early revs), corrupts register - * values on read ... so enable the vendor workaround. - */ -static int ohci_quirk_amd756(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - - ohci->flags = OHCI_QUIRK_AMD756; - ohci_dbg (ohci, "AMD756 erratum 4 workaround\n"); - - /* also erratum 10 (suspend/resume issues) */ - return broken_suspend(hcd); -} - -/* Apple's OHCI driver has a lot of bizarre workarounds - * for this chip. Evidently control and bulk lists - * can get confused. (B&W G3 models, and ...) - */ -static int ohci_quirk_opti(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - - ohci_dbg (ohci, "WARNING: OPTi workarounds unavailable\n"); - - return 0; -} - -/* Check for NSC87560. We have to look at the bridge (fn1) to - * identify the USB (fn2). This quirk might apply to more or - * even all NSC stuff. - */ -static int ohci_quirk_ns(struct usb_hcd *hcd) -{ - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - struct pci_dev *b; - - b = pci_get_slot (pdev->bus, PCI_DEVFN (PCI_SLOT (pdev->devfn), 1)); - if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO - && b->vendor == PCI_VENDOR_ID_NS) { - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - - ohci->flags |= OHCI_QUIRK_SUPERIO; - ohci_dbg (ohci, "Using NSC SuperIO setup\n"); - } - pci_dev_put(b); - - return 0; -} - -/* Check for Compaq's ZFMicro chipset, which needs short - * delays before control or bulk queues get re-activated - * in finish_unlinks() - */ -static int ohci_quirk_zfmicro(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - - ohci->flags |= OHCI_QUIRK_ZFMICRO; - ohci_dbg(ohci, "enabled Compaq ZFMicro chipset quirks\n"); - - return 0; -} - -/* Check for Toshiba SCC OHCI which has big endian registers - * and little endian in memory data structures - */ -static int ohci_quirk_toshiba_scc(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - - /* That chip is only present in the southbridge of some - * cell based platforms which are supposed to select - * CONFIG_USB_OHCI_BIG_ENDIAN_MMIO. We verify here if - * that was the case though. - */ -#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO - ohci->flags |= OHCI_QUIRK_BE_MMIO; - ohci_dbg (ohci, "enabled big endian Toshiba quirk\n"); - return 0; -#else - ohci_err (ohci, "unsupported big endian Toshiba quirk\n"); - return -ENXIO; -#endif -} - -/* Check for NEC chip and apply quirk for allegedly lost interrupts. - */ - -static void ohci_quirk_nec_worker(struct work_struct *work) -{ - struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work); - int status; - - status = ohci_init(ohci); - if (status != 0) { - ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n", - "ohci_init", status); - return; - } - - status = ohci_restart(ohci); - if (status != 0) - ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n", - "ohci_restart", status); -} - -static int ohci_quirk_nec(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - - ohci->flags |= OHCI_QUIRK_NEC; - INIT_WORK(&ohci->nec_work, ohci_quirk_nec_worker); - ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n"); - - return 0; -} - -static int ohci_quirk_amd700(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - struct pci_dev *amd_smbus_dev; - u8 rev; - - if (usb_amd_find_chipset_info()) - ohci->flags |= OHCI_QUIRK_AMD_PLL; - - amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, - PCI_DEVICE_ID_ATI_SBX00_SMBUS, NULL); - if (!amd_smbus_dev) - return 0; - - rev = amd_smbus_dev->revision; - - /* SB800 needs pre-fetch fix */ - if ((rev >= 0x40) && (rev <= 0x4f)) { - ohci->flags |= OHCI_QUIRK_AMD_PREFETCH; - ohci_dbg(ohci, "enabled AMD prefetch quirk\n"); - } - - pci_dev_put(amd_smbus_dev); - amd_smbus_dev = NULL; - - return 0; -} - -static void sb800_prefetch(struct ohci_hcd *ohci, int on) -{ - struct pci_dev *pdev; - u16 misc; - - pdev = to_pci_dev(ohci_to_hcd(ohci)->self.controller); - pci_read_config_word(pdev, 0x50, &misc); - if (on == 0) - pci_write_config_word(pdev, 0x50, misc & 0xfcff); - else - pci_write_config_word(pdev, 0x50, misc | 0x0300); -} - -/* List of quirks for OHCI */ -static const struct pci_device_id ohci_pci_quirks[] = { - { - PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x740c), - .driver_data = (unsigned long)ohci_quirk_amd756, - }, - { - PCI_DEVICE(PCI_VENDOR_ID_OPTI, 0xc861), - .driver_data = (unsigned long)ohci_quirk_opti, - }, - { - PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_ANY_ID), - .driver_data = (unsigned long)ohci_quirk_ns, - }, - { - PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xa0f8), - .driver_data = (unsigned long)ohci_quirk_zfmicro, - }, - { - PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, 0x01b6), - .driver_data = (unsigned long)ohci_quirk_toshiba_scc, - }, - { - PCI_DEVICE(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB), - .driver_data = (unsigned long)ohci_quirk_nec, - }, - { - /* Toshiba portege 4000 */ - .vendor = PCI_VENDOR_ID_AL, - .device = 0x5237, - .subvendor = PCI_VENDOR_ID_TOSHIBA, - .subdevice = 0x0004, - .driver_data = (unsigned long) broken_suspend, - }, - { - PCI_DEVICE(PCI_VENDOR_ID_ITE, 0x8152), - .driver_data = (unsigned long) broken_suspend, - }, - { - PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4397), - .driver_data = (unsigned long)ohci_quirk_amd700, - }, - { - PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4398), - .driver_data = (unsigned long)ohci_quirk_amd700, - }, - { - PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4399), - .driver_data = (unsigned long)ohci_quirk_amd700, - }, - - /* FIXME for some of the early AMD 760 southbridges, OHCI - * won't work at all. blacklist them. - */ - - {}, -}; - -static int ohci_pci_reset (struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int ret = 0; - - if (hcd->self.controller) { - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - const struct pci_device_id *quirk_id; - - quirk_id = pci_match_id(ohci_pci_quirks, pdev); - if (quirk_id != NULL) { - int (*quirk)(struct usb_hcd *ohci); - quirk = (void *)quirk_id->driver_data; - ret = quirk(hcd); - } - } - if (ret == 0) { - ohci_hcd_init (ohci); - return ohci_init (ohci); - } - return ret; -} - - -static int __devinit ohci_pci_start (struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int ret; - -#ifdef CONFIG_PM /* avoid warnings about unused pdev */ - if (hcd->self.controller) { - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - - /* RWC may not be set for add-in PCI cards, since boot - * firmware probably ignored them. This transfers PCI - * PM wakeup capabilities. - */ - if (device_can_wakeup(&pdev->dev)) - ohci->hc_control |= OHCI_CTRL_RWC; - } -#endif /* CONFIG_PM */ - - ret = ohci_run (ohci); - if (ret < 0) { - ohci_err (ohci, "can't start\n"); - ohci_stop (hcd); - } - return ret; -} - -#ifdef CONFIG_PM - -static int ohci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - unsigned long flags; - int rc = 0; - - /* Root hub was already suspended. Disable irq emission and - * mark HW unaccessible, bail out if RH has been resumed. Use - * the spinlock to properly synchronize with possible pending - * RH suspend or resume activity. - */ - spin_lock_irqsave (&ohci->lock, flags); - if (ohci->rh_state != OHCI_RH_SUSPENDED) { - rc = -EINVAL; - goto bail; - } - ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); - (void)ohci_readl(ohci, &ohci->regs->intrdisable); - - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - bail: - spin_unlock_irqrestore (&ohci->lock, flags); - - return rc; -} - - -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; -} - -#endif /* CONFIG_PM */ - - -/*-------------------------------------------------------------------------*/ - -static const struct hc_driver ohci_pci_hc_driver = { - .description = hcd_name, - .product_desc = "OHCI Host Controller", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_MEMORY | HCD_USB11, - - /* - * basic lifecycle operations - */ - .reset = ohci_pci_reset, - .start = ohci_pci_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - -#ifdef CONFIG_PM - .pci_suspend = ohci_pci_suspend, - .pci_resume = ohci_pci_resume, -#endif - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -/*-------------------------------------------------------------------------*/ - - -static const struct pci_device_id pci_ids [] = { { - /* handle any USB OHCI controller */ - PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_OHCI, ~0), - .driver_data = (unsigned long) &ohci_pci_hc_driver, - }, { - /* The device in the ConneXT I/O hub has no class reg */ - PCI_VDEVICE(STMICRO, PCI_DEVICE_ID_STMICRO_USB_OHCI), - .driver_data = (unsigned long) &ohci_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 ohci_pci_driver = { - .name = (char *) hcd_name, - .id_table = pci_ids, - - .probe = usb_hcd_pci_probe, - .remove = usb_hcd_pci_remove, - .shutdown = usb_hcd_pci_shutdown, - -#ifdef CONFIG_PM_SLEEP - .driver = { - .pm = &usb_hcd_pci_pm_ops - }, -#endif -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-platform.c b/ANDROID_3.4.5/drivers/usb/host/ohci-platform.c deleted file mode 100644 index ec5c6791..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-platform.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Generic platform ohci driver - * - * Copyright 2007 Michael Buesch - * Copyright 2011-2012 Hauke Mehrtens - * - * Derived from the OCHI-SSB driver - * Derived from the OHCI-PCI driver - * Copyright 1999 Roman Weissgaerber - * Copyright 2000-2002 David Brownell - * Copyright 1999 Linus Torvalds - * Copyright 1999 Gregory P. Smith - * - * Licensed under the GNU/GPL. See COPYING for details. - */ -#include -#include - -static int ohci_platform_reset(struct usb_hcd *hcd) -{ - struct platform_device *pdev = to_platform_device(hcd->self.controller); - struct usb_ohci_pdata *pdata = pdev->dev.platform_data; - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int err; - - if (pdata->big_endian_desc) - ohci->flags |= OHCI_QUIRK_BE_DESC; - if (pdata->big_endian_mmio) - ohci->flags |= OHCI_QUIRK_BE_MMIO; - if (pdata->no_big_frame_no) - ohci->flags |= OHCI_QUIRK_FRAME_NO; - - ohci_hcd_init(ohci); - err = ohci_init(ohci); - - return err; -} - -static int ohci_platform_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int err; - - err = ohci_run(ohci); - if (err < 0) { - ohci_err(ohci, "can't start\n"); - ohci_stop(hcd); - } - - return err; -} - -static const struct hc_driver ohci_platform_hc_driver = { - .description = hcd_name, - .product_desc = "Generic Platform OHCI Controller", - .hcd_priv_size = sizeof(struct ohci_hcd), - - .irq = ohci_irq, - .flags = HCD_MEMORY | HCD_USB11, - - .reset = ohci_platform_reset, - .start = ohci_platform_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - .get_frame_number = ohci_get_frame, - - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - - .start_port_reset = ohci_start_port_reset, -}; - -static int __devinit ohci_platform_probe(struct platform_device *dev) -{ - struct usb_hcd *hcd; - struct resource *res_mem; - int irq; - int err = -ENOMEM; - - BUG_ON(!dev->dev.platform_data); - - if (usb_disabled()) - return -ENODEV; - - irq = platform_get_irq(dev, 0); - if (irq < 0) { - pr_err("no irq provieded"); - return irq; - } - - res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!res_mem) { - pr_err("no memory recourse provieded"); - return -ENXIO; - } - - hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev, - dev_name(&dev->dev)); - if (!hcd) - return -ENOMEM; - - hcd->rsrc_start = res_mem->start; - hcd->rsrc_len = resource_size(res_mem); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - pr_err("controller already in use"); - err = -EBUSY; - goto err_put_hcd; - } - - hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) - goto err_release_region; - err = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (err) - goto err_iounmap; - - platform_set_drvdata(dev, hcd); - - return err; - -err_iounmap: - iounmap(hcd->regs); -err_release_region: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err_put_hcd: - usb_put_hcd(hcd); - return err; -} - -static int __devexit ohci_platform_remove(struct platform_device *dev) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - platform_set_drvdata(dev, NULL); - - return 0; -} - -#ifdef CONFIG_PM - -static int ohci_platform_suspend(struct device *dev) -{ - return 0; -} - -static int ohci_platform_resume(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - - ohci_finish_controller_resume(hcd); - return 0; -} - -#else /* !CONFIG_PM */ -#define ohci_platform_suspend NULL -#define ohci_platform_resume NULL -#endif /* CONFIG_PM */ - -static const struct platform_device_id ohci_platform_table[] = { - { "ohci-platform", 0 }, - { } -}; -MODULE_DEVICE_TABLE(platform, ohci_platform_table); - -static const struct dev_pm_ops ohci_platform_pm_ops = { - .suspend = ohci_platform_suspend, - .resume = ohci_platform_resume, -}; - -static struct platform_driver ohci_platform_driver = { - .id_table = ohci_platform_table, - .probe = ohci_platform_probe, - .remove = __devexit_p(ohci_platform_remove), - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .owner = THIS_MODULE, - .name = "ohci-platform", - .pm = &ohci_platform_pm_ops, - } -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-pnx8550.c b/ANDROID_3.4.5/drivers/usb/host/ohci-pnx8550.c deleted file mode 100644 index f13d08f9..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-pnx8550.c +++ /dev/null @@ -1,242 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2002 David Brownell - * (C) Copyright 2002 Hewlett-Packard Company - * (C) Copyright 2005 Embedded Alley Solutions, Inc. - * - * Bus Glue for PNX8550 - * - * Written by Christopher Hoover - * Based on fragments of previous driver by Russell King et al. - * - * Modified for LH7A404 from ohci-sa1111.c - * by Durgesh Pattamatta - * - * Modified for PNX8550 from ohci-sa1111.c and sa-omap.c - * by Vitaly Wool - * - * This file is licenced under the GPL. - */ - -#include -#include -#include -#include -#include - -#ifndef CONFIG_PNX8550 -#error "This file is PNX8550 bus glue. CONFIG_PNX8550 must be defined." -#endif - -extern int usb_disabled(void); - -/*-------------------------------------------------------------------------*/ - -static void pnx8550_start_hc(struct platform_device *dev) -{ - /* - * Set register CLK48CTL to enable and 48MHz - */ - outl(0x00000003, PCI_BASE | 0x0004770c); - - /* - * Set register CLK12CTL to enable and 48MHz - */ - outl(0x00000003, PCI_BASE | 0x00047710); - - udelay(100); -} - -static void pnx8550_stop_hc(struct platform_device *dev) -{ - udelay(10); -} - - -/*-------------------------------------------------------------------------*/ - -/* configure so an HC device and id are always provided */ -/* always called with process context; sleeping is OK */ - - -/** - * usb_hcd_pnx8550_probe - initialize pnx8550-based HCDs - * Context: !in_interrupt() - * - * Allocates basic resources for this USB host controller, and - * then invokes the start() method for the HCD associated with it - * through the hotplug entry's driver_data. - * - */ -int usb_hcd_pnx8550_probe (const struct hc_driver *driver, - struct platform_device *dev) -{ - int retval; - struct usb_hcd *hcd; - - if (dev->resource[0].flags != IORESOURCE_MEM || - dev->resource[1].flags != IORESOURCE_IRQ) { - dev_err (&dev->dev,"invalid resource type\n"); - return -ENOMEM; - } - - hcd = usb_create_hcd (driver, &dev->dev, "pnx8550"); - if (!hcd) - return -ENOMEM; - hcd->rsrc_start = dev->resource[0].start; - hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1; - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - dev_err(&dev->dev, "request_mem_region [0x%08llx, 0x%08llx] " - "failed\n", hcd->rsrc_start, hcd->rsrc_len); - retval = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - dev_err(&dev->dev, "ioremap [[0x%08llx, 0x%08llx] failed\n", - hcd->rsrc_start, hcd->rsrc_len); - retval = -ENOMEM; - goto err2; - } - - pnx8550_start_hc(dev); - - ohci_hcd_init(hcd_to_ohci(hcd)); - - retval = usb_add_hcd(hcd, dev->resource[1].start, 0); - if (retval == 0) - return retval; - - pnx8550_stop_hc(dev); - iounmap(hcd->regs); - err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - err1: - usb_put_hcd(hcd); - return retval; -} - - -/* may be called without controller electrically present */ -/* may be called with controller, bus, and devices active */ - -/** - * usb_hcd_pnx8550_remove - shutdown processing for pnx8550-based HCDs - * @dev: USB Host Controller being removed - * Context: !in_interrupt() - * - * Reverses the effect of usb_hcd_pnx8550_probe(), first invoking - * the HCD's stop() method. It is always called from a thread - * context, normally "rmmod", "apmd", or something similar. - * - */ -void usb_hcd_pnx8550_remove (struct usb_hcd *hcd, struct platform_device *dev) -{ - usb_remove_hcd(hcd); - pnx8550_stop_hc(dev); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); -} - -/*-------------------------------------------------------------------------*/ - -static int __devinit -ohci_pnx8550_start (struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int ret; - - ohci_dbg (ohci, "ohci_pnx8550_start, ohci:%p", ohci); - - if ((ret = ohci_init(ohci)) < 0) - return ret; - - if ((ret = ohci_run (ohci)) < 0) { - err ("can't start %s", hcd->self.bus_name); - ohci_stop (hcd); - return ret; - } - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static const struct hc_driver ohci_pnx8550_hc_driver = { - .description = hcd_name, - .product_desc = "PNX8550 OHCI", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .start = ohci_pnx8550_start, - .stop = ohci_stop, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -/*-------------------------------------------------------------------------*/ - -static int ohci_hcd_pnx8550_drv_probe(struct platform_device *pdev) -{ - int ret; - - if (usb_disabled()) - return -ENODEV; - - ret = usb_hcd_pnx8550_probe(&ohci_pnx8550_hc_driver, pdev); - return ret; -} - -static int ohci_hcd_pnx8550_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_hcd_pnx8550_remove(hcd, pdev); - return 0; -} - -MODULE_ALIAS("platform:pnx8550-ohci"); - -static struct platform_driver ohci_hcd_pnx8550_driver = { - .driver = { - .name = "pnx8550-ohci", - .owner = THIS_MODULE, - }, - .probe = ohci_hcd_pnx8550_drv_probe, - .remove = ohci_hcd_pnx8550_drv_remove, -}; - diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-ppc-of.c b/ANDROID_3.4.5/drivers/usb/host/ohci-ppc-of.c deleted file mode 100644 index d24cc89d..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-ppc-of.c +++ /dev/null @@ -1,253 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2002 David Brownell - * (C) Copyright 2002 Hewlett-Packard Company - * (C) Copyright 2006 Sylvain Munaut - * - * Bus glue for OHCI HC on the of_platform bus - * - * Modified for of_platform bus from ohci-sa1111.c - * - * This file is licenced under the GPL. - */ - -#include -#include - -#include - - -static int __devinit -ohci_ppc_of_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - if ((ret = ohci_init(ohci)) < 0) - return ret; - - if ((ret = ohci_run(ohci)) < 0) { - err("can't start %s", ohci_to_hcd(ohci)->self.bus_name); - ohci_stop(hcd); - return ret; - } - - return 0; -} - -static const struct hc_driver ohci_ppc_of_hc_driver = { - .description = hcd_name, - .product_desc = "OF OHCI", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .start = ohci_ppc_of_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - - -static int __devinit ohci_hcd_ppc_of_probe(struct platform_device *op) -{ - struct device_node *dn = op->dev.of_node; - struct usb_hcd *hcd; - struct ohci_hcd *ohci; - struct resource res; - int irq; - - int rv; - int is_bigendian; - struct device_node *np; - - if (usb_disabled()) - return -ENODEV; - - is_bigendian = - of_device_is_compatible(dn, "ohci-bigendian") || - of_device_is_compatible(dn, "ohci-be"); - - dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n"); - - rv = of_address_to_resource(dn, 0, &res); - if (rv) - return rv; - - hcd = usb_create_hcd(&ohci_ppc_of_hc_driver, &op->dev, "PPC-OF USB"); - if (!hcd) - return -ENOMEM; - - hcd->rsrc_start = res.start; - hcd->rsrc_len = resource_size(&res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__); - rv = -EBUSY; - goto err_rmr; - } - - irq = irq_of_parse_and_map(dn, 0); - if (irq == NO_IRQ) { - printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__); - rv = -EBUSY; - goto err_irq; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - printk(KERN_ERR "%s: ioremap failed\n", __FILE__); - rv = -ENOMEM; - goto err_ioremap; - } - - ohci = hcd_to_ohci(hcd); - if (is_bigendian) { - ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; - if (of_device_is_compatible(dn, "fsl,mpc5200-ohci")) - ohci->flags |= OHCI_QUIRK_FRAME_NO; - if (of_device_is_compatible(dn, "mpc5200-ohci")) - ohci->flags |= OHCI_QUIRK_FRAME_NO; - } - - ohci_hcd_init(ohci); - - rv = usb_add_hcd(hcd, irq, 0); - if (rv == 0) - return 0; - - /* by now, 440epx is known to show usb_23 erratum */ - np = of_find_compatible_node(NULL, NULL, "ibm,usb-ehci-440epx"); - - /* Work around - At this point ohci_run has executed, the - * controller is running, everything, the root ports, etc., is - * set up. If the ehci driver is loaded, put the ohci core in - * the suspended state. The ehci driver will bring it out of - * suspended state when / if a non-high speed USB device is - * attached to the USB Host port. If the ehci driver is not - * loaded, do nothing. request_mem_region is used to test if - * the ehci driver is loaded. - */ - if (np != NULL) { - if (!of_address_to_resource(np, 0, &res)) { - if (!request_mem_region(res.start, 0x4, hcd_name)) { - writel_be((readl_be(&ohci->regs->control) | - OHCI_USB_SUSPEND), &ohci->regs->control); - (void) readl_be(&ohci->regs->control); - } else - release_mem_region(res.start, 0x4); - } else - pr_debug("%s: cannot get ehci offset from fdt\n", __FILE__); - } - - iounmap(hcd->regs); -err_ioremap: - irq_dispose_mapping(irq); -err_irq: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err_rmr: - usb_put_hcd(hcd); - - return rv; -} - -static int ohci_hcd_ppc_of_remove(struct platform_device *op) -{ - struct usb_hcd *hcd = dev_get_drvdata(&op->dev); - dev_set_drvdata(&op->dev, NULL); - - dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n"); - - usb_remove_hcd(hcd); - - iounmap(hcd->regs); - irq_dispose_mapping(hcd->irq); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - - usb_put_hcd(hcd); - - return 0; -} - -static void ohci_hcd_ppc_of_shutdown(struct platform_device *op) -{ - struct usb_hcd *hcd = dev_get_drvdata(&op->dev); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); -} - - -static const struct of_device_id ohci_hcd_ppc_of_match[] = { -#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE - { - .name = "usb", - .compatible = "ohci-bigendian", - }, - { - .name = "usb", - .compatible = "ohci-be", - }, -#endif -#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_LE - { - .name = "usb", - .compatible = "ohci-littledian", - }, - { - .name = "usb", - .compatible = "ohci-le", - }, -#endif - {}, -}; -MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match); - -#if !defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \ - !defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE) -#error "No endianess selected for ppc-of-ohci" -#endif - - -static struct platform_driver ohci_hcd_ppc_of_driver = { - .probe = ohci_hcd_ppc_of_probe, - .remove = ohci_hcd_ppc_of_remove, - .shutdown = ohci_hcd_ppc_of_shutdown, - .driver = { - .name = "ppc-of-ohci", - .owner = THIS_MODULE, - .of_match_table = ohci_hcd_ppc_of_match, - }, -}; - diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-ppc-soc.c b/ANDROID_3.4.5/drivers/usb/host/ohci-ppc-soc.c deleted file mode 100644 index 1514b706..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-ppc-soc.c +++ /dev/null @@ -1,215 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2002 David Brownell - * (C) Copyright 2002 Hewlett-Packard Company - * (C) Copyright 2003-2005 MontaVista Software Inc. - * - * Bus Glue for PPC On-Chip OHCI driver - * Tested on Freescale MPC5200 and IBM STB04xxx - * - * Modified by Dale Farnsworth from ohci-sa1111.c - * - * This file is licenced under the GPL. - */ - -#include -#include - -/* configure so an HC device and id are always provided */ -/* always called with process context; sleeping is OK */ - -/** - * usb_hcd_ppc_soc_probe - initialize On-Chip HCDs - * Context: !in_interrupt() - * - * Allocates basic resources for this USB host controller. - * - * Store this function in the HCD's struct pci_driver as probe(). - */ -static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver, - struct platform_device *pdev) -{ - int retval; - struct usb_hcd *hcd; - struct ohci_hcd *ohci; - struct resource *res; - int irq; - - pr_debug("initializing PPC-SOC USB Controller\n"); - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - pr_debug("%s: no irq\n", __FILE__); - return -ENODEV; - } - irq = res->start; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - pr_debug("%s: no reg addr\n", __FILE__); - return -ENODEV; - } - - hcd = usb_create_hcd(driver, &pdev->dev, "PPC-SOC USB"); - if (!hcd) - return -ENOMEM; - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - pr_debug("%s: request_mem_region failed\n", __FILE__); - retval = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - pr_debug("%s: ioremap failed\n", __FILE__); - retval = -ENOMEM; - goto err2; - } - - ohci = hcd_to_ohci(hcd); - ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; - -#ifdef CONFIG_PPC_MPC52xx - /* MPC52xx doesn't need frame_no shift */ - ohci->flags |= OHCI_QUIRK_FRAME_NO; -#endif - ohci_hcd_init(ohci); - - retval = usb_add_hcd(hcd, irq, 0); - if (retval == 0) - return retval; - - pr_debug("Removing PPC-SOC USB Controller\n"); - - iounmap(hcd->regs); - err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - err1: - usb_put_hcd(hcd); - return retval; -} - - -/* may be called without controller electrically present */ -/* may be called with controller, bus, and devices active */ - -/** - * usb_hcd_ppc_soc_remove - shutdown processing for On-Chip HCDs - * @pdev: USB Host Controller being removed - * Context: !in_interrupt() - * - * Reverses the effect of usb_hcd_ppc_soc_probe(). - * It is always called from a thread - * context, normally "rmmod", "apmd", or something similar. - * - */ -static void usb_hcd_ppc_soc_remove(struct usb_hcd *hcd, - struct platform_device *pdev) -{ - usb_remove_hcd(hcd); - - pr_debug("stopping PPC-SOC USB Controller\n"); - - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); -} - -static int __devinit -ohci_ppc_soc_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - if ((ret = ohci_init(ohci)) < 0) - return ret; - - if ((ret = ohci_run(ohci)) < 0) { - err("can't start %s", ohci_to_hcd(ohci)->self.bus_name); - ohci_stop(hcd); - return ret; - } - - return 0; -} - -static const struct hc_driver ohci_ppc_soc_hc_driver = { - .description = hcd_name, - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .start = ohci_ppc_soc_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -static int ohci_hcd_ppc_soc_drv_probe(struct platform_device *pdev) -{ - int ret; - - if (usb_disabled()) - return -ENODEV; - - ret = usb_hcd_ppc_soc_probe(&ohci_ppc_soc_hc_driver, pdev); - return ret; -} - -static int ohci_hcd_ppc_soc_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_hcd_ppc_soc_remove(hcd, pdev); - return 0; -} - -static struct platform_driver ohci_hcd_ppc_soc_driver = { - .probe = ohci_hcd_ppc_soc_drv_probe, - .remove = ohci_hcd_ppc_soc_drv_remove, - .shutdown = usb_hcd_platform_shutdown, -#ifdef CONFIG_PM - /*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/ - /*.resume = ohci_hcd_ppc_soc_drv_resume,*/ -#endif - .driver = { - .name = "ppc-soc-ohci", - .owner = THIS_MODULE, - }, -}; - -MODULE_ALIAS("platform:ppc-soc-ohci"); diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-ps3.c b/ANDROID_3.4.5/drivers/usb/host/ohci-ps3.c deleted file mode 100644 index 6fd4fa1f..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-ps3.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * PS3 OHCI Host Controller driver - * - * Copyright (C) 2006 Sony Computer Entertainment Inc. - * Copyright 2006 Sony Corp. - * - * 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; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include - -static int ps3_ohci_hc_reset(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - - ohci->flags |= OHCI_QUIRK_BE_MMIO; - ohci_hcd_init(ohci); - return ohci_init(ohci); -} - -static int __devinit ps3_ohci_hc_start(struct usb_hcd *hcd) -{ - int result; - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - - /* Handle root hub init quirk in spider south bridge. */ - /* Also set PwrOn2PwrGood to 0x7f (254ms). */ - - ohci_writel(ohci, 0x7f000000 | RH_A_PSM | RH_A_OCPM, - &ohci->regs->roothub.a); - ohci_writel(ohci, 0x00060000, &ohci->regs->roothub.b); - - result = ohci_run(ohci); - - if (result < 0) { - err("can't start %s", hcd->self.bus_name); - ohci_stop(hcd); - } - - return result; -} - -static const struct hc_driver ps3_ohci_hc_driver = { - .description = hcd_name, - .product_desc = "PS3 OHCI Host Controller", - .hcd_priv_size = sizeof(struct ohci_hcd), - .irq = ohci_irq, - .flags = HCD_MEMORY | HCD_USB11, - .reset = ps3_ohci_hc_reset, - .start = ps3_ohci_hc_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - .get_frame_number = ohci_get_frame, - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, - .start_port_reset = ohci_start_port_reset, -#if defined(CONFIG_PM) - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif -}; - -static int __devinit ps3_ohci_probe(struct ps3_system_bus_device *dev) -{ - int result; - struct usb_hcd *hcd; - unsigned int virq; - static u64 dummy_mask = DMA_BIT_MASK(32); - - if (usb_disabled()) { - result = -ENODEV; - goto fail_start; - } - - result = ps3_open_hv_device(dev); - - if (result) { - dev_dbg(&dev->core, "%s:%d: ps3_open_hv_device failed: %s\n", - __func__, __LINE__, ps3_result(result)); - result = -EPERM; - goto fail_open; - } - - result = ps3_dma_region_create(dev->d_region); - - if (result) { - dev_dbg(&dev->core, "%s:%d: ps3_dma_region_create failed: " - "(%d)\n", __func__, __LINE__, result); - BUG_ON("check region type"); - goto fail_dma_region; - } - - result = ps3_mmio_region_create(dev->m_region); - - if (result) { - dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n", - __func__, __LINE__); - result = -EPERM; - goto fail_mmio_region; - } - - dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__, - __LINE__, dev->m_region->lpar_addr); - - result = ps3_io_irq_setup(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq); - - if (result) { - dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n", - __func__, __LINE__, virq); - result = -EPERM; - goto fail_irq; - } - - dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */ - - hcd = usb_create_hcd(&ps3_ohci_hc_driver, &dev->core, dev_name(&dev->core)); - - if (!hcd) { - dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__, - __LINE__); - result = -ENOMEM; - goto fail_create_hcd; - } - - hcd->rsrc_start = dev->m_region->lpar_addr; - hcd->rsrc_len = dev->m_region->len; - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) - dev_dbg(&dev->core, "%s:%d: request_mem_region failed\n", - __func__, __LINE__); - - hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len); - - if (!hcd->regs) { - dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__, - __LINE__); - result = -EPERM; - goto fail_ioremap; - } - - dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__, - (unsigned long)hcd->rsrc_start); - dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len %lxh\n", __func__, __LINE__, - (unsigned long)hcd->rsrc_len); - dev_dbg(&dev->core, "%s:%d: hcd->regs %lxh\n", __func__, __LINE__, - (unsigned long)hcd->regs); - dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__, - (unsigned long)virq); - - ps3_system_bus_set_drvdata(dev, hcd); - - result = usb_add_hcd(hcd, virq, 0); - - if (result) { - dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n", - __func__, __LINE__, result); - goto fail_add_hcd; - } - - return result; - -fail_add_hcd: - iounmap(hcd->regs); -fail_ioremap: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); -fail_create_hcd: - ps3_io_irq_destroy(virq); -fail_irq: - ps3_free_mmio_region(dev->m_region); -fail_mmio_region: - ps3_dma_region_free(dev->d_region); -fail_dma_region: - ps3_close_hv_device(dev); -fail_open: -fail_start: - return result; -} - -static int ps3_ohci_remove(struct ps3_system_bus_device *dev) -{ - unsigned int tmp; - struct usb_hcd *hcd = ps3_system_bus_get_drvdata(dev); - - BUG_ON(!hcd); - - dev_dbg(&dev->core, "%s:%d: regs %p\n", __func__, __LINE__, hcd->regs); - dev_dbg(&dev->core, "%s:%d: irq %u\n", __func__, __LINE__, hcd->irq); - - tmp = hcd->irq; - - ohci_shutdown(hcd); - usb_remove_hcd(hcd); - - ps3_system_bus_set_drvdata(dev, NULL); - - BUG_ON(!hcd->regs); - iounmap(hcd->regs); - - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - - ps3_io_irq_destroy(tmp); - ps3_free_mmio_region(dev->m_region); - - ps3_dma_region_free(dev->d_region); - ps3_close_hv_device(dev); - - return 0; -} - -static int __init ps3_ohci_driver_register(struct ps3_system_bus_driver *drv) -{ - return firmware_has_feature(FW_FEATURE_PS3_LV1) - ? ps3_system_bus_driver_register(drv) - : 0; -} - -static void ps3_ohci_driver_unregister(struct ps3_system_bus_driver *drv) -{ - if (firmware_has_feature(FW_FEATURE_PS3_LV1)) - ps3_system_bus_driver_unregister(drv); -} - -MODULE_ALIAS(PS3_MODULE_ALIAS_OHCI); - -static struct ps3_system_bus_driver ps3_ohci_driver = { - .core.name = "ps3-ohci-driver", - .core.owner = THIS_MODULE, - .match_id = PS3_MATCH_ID_OHCI, - .probe = ps3_ohci_probe, - .remove = ps3_ohci_remove, - .shutdown = ps3_ohci_remove, -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-pxa27x.c b/ANDROID_3.4.5/drivers/usb/host/ohci-pxa27x.c deleted file mode 100644 index c31b2815..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-pxa27x.c +++ /dev/null @@ -1,551 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2002 David Brownell - * (C) Copyright 2002 Hewlett-Packard Company - * - * Bus Glue for pxa27x - * - * Written by Christopher Hoover - * Based on fragments of previous driver by Russell King et al. - * - * Modified for LH7A404 from ohci-sa1111.c - * by Durgesh Pattamatta - * - * Modified for pxa27x from ohci-lh7a404.c - * by Nick Bane 26-8-2004 - * - * This file is licenced under the GPL. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * UHC: USB Host Controller (OHCI-like) register definitions - */ -#define UHCREV (0x0000) /* UHC HCI Spec Revision */ -#define UHCHCON (0x0004) /* UHC Host Control Register */ -#define UHCCOMS (0x0008) /* UHC Command Status Register */ -#define UHCINTS (0x000C) /* UHC Interrupt Status Register */ -#define UHCINTE (0x0010) /* UHC Interrupt Enable */ -#define UHCINTD (0x0014) /* UHC Interrupt Disable */ -#define UHCHCCA (0x0018) /* UHC Host Controller Comm. Area */ -#define UHCPCED (0x001C) /* UHC Period Current Endpt Descr */ -#define UHCCHED (0x0020) /* UHC Control Head Endpt Descr */ -#define UHCCCED (0x0024) /* UHC Control Current Endpt Descr */ -#define UHCBHED (0x0028) /* UHC Bulk Head Endpt Descr */ -#define UHCBCED (0x002C) /* UHC Bulk Current Endpt Descr */ -#define UHCDHEAD (0x0030) /* UHC Done Head */ -#define UHCFMI (0x0034) /* UHC Frame Interval */ -#define UHCFMR (0x0038) /* UHC Frame Remaining */ -#define UHCFMN (0x003C) /* UHC Frame Number */ -#define UHCPERS (0x0040) /* UHC Periodic Start */ -#define UHCLS (0x0044) /* UHC Low Speed Threshold */ - -#define UHCRHDA (0x0048) /* UHC Root Hub Descriptor A */ -#define UHCRHDA_NOCP (1 << 12) /* No over current protection */ -#define UHCRHDA_OCPM (1 << 11) /* Over Current Protection Mode */ -#define UHCRHDA_POTPGT(x) \ - (((x) & 0xff) << 24) /* Power On To Power Good Time */ - -#define UHCRHDB (0x004C) /* UHC Root Hub Descriptor B */ -#define UHCRHS (0x0050) /* UHC Root Hub Status */ -#define UHCRHPS1 (0x0054) /* UHC Root Hub Port 1 Status */ -#define UHCRHPS2 (0x0058) /* UHC Root Hub Port 2 Status */ -#define UHCRHPS3 (0x005C) /* UHC Root Hub Port 3 Status */ - -#define UHCSTAT (0x0060) /* UHC Status Register */ -#define UHCSTAT_UPS3 (1 << 16) /* USB Power Sense Port3 */ -#define UHCSTAT_SBMAI (1 << 15) /* System Bus Master Abort Interrupt*/ -#define UHCSTAT_SBTAI (1 << 14) /* System Bus Target Abort Interrupt*/ -#define UHCSTAT_UPRI (1 << 13) /* USB Port Resume Interrupt */ -#define UHCSTAT_UPS2 (1 << 12) /* USB Power Sense Port 2 */ -#define UHCSTAT_UPS1 (1 << 11) /* USB Power Sense Port 1 */ -#define UHCSTAT_HTA (1 << 10) /* HCI Target Abort */ -#define UHCSTAT_HBA (1 << 8) /* HCI Buffer Active */ -#define UHCSTAT_RWUE (1 << 7) /* HCI Remote Wake Up Event */ - -#define UHCHR (0x0064) /* UHC Reset Register */ -#define UHCHR_SSEP3 (1 << 11) /* Sleep Standby Enable for Port3 */ -#define UHCHR_SSEP2 (1 << 10) /* Sleep Standby Enable for Port2 */ -#define UHCHR_SSEP1 (1 << 9) /* Sleep Standby Enable for Port1 */ -#define UHCHR_PCPL (1 << 7) /* Power control polarity low */ -#define UHCHR_PSPL (1 << 6) /* Power sense polarity low */ -#define UHCHR_SSE (1 << 5) /* Sleep Standby Enable */ -#define UHCHR_UIT (1 << 4) /* USB Interrupt Test */ -#define UHCHR_SSDC (1 << 3) /* Simulation Scale Down Clock */ -#define UHCHR_CGR (1 << 2) /* Clock Generation Reset */ -#define UHCHR_FHR (1 << 1) /* Force Host Controller Reset */ -#define UHCHR_FSBIR (1 << 0) /* Force System Bus Iface Reset */ - -#define UHCHIE (0x0068) /* UHC Interrupt Enable Register*/ -#define UHCHIE_UPS3IE (1 << 14) /* Power Sense Port3 IntEn */ -#define UHCHIE_UPRIE (1 << 13) /* Port Resume IntEn */ -#define UHCHIE_UPS2IE (1 << 12) /* Power Sense Port2 IntEn */ -#define UHCHIE_UPS1IE (1 << 11) /* Power Sense Port1 IntEn */ -#define UHCHIE_TAIE (1 << 10) /* HCI Interface Transfer Abort - Interrupt Enable*/ -#define UHCHIE_HBAIE (1 << 8) /* HCI Buffer Active IntEn */ -#define UHCHIE_RWIE (1 << 7) /* Remote Wake-up IntEn */ - -#define UHCHIT (0x006C) /* UHC Interrupt Test register */ - -#define PXA_UHC_MAX_PORTNUM 3 - -struct pxa27x_ohci { - /* must be 1st member here for hcd_to_ohci() to work */ - struct ohci_hcd ohci; - - struct device *dev; - struct clk *clk; - void __iomem *mmio_base; -}; - -#define to_pxa27x_ohci(hcd) (struct pxa27x_ohci *)hcd_to_ohci(hcd) - -/* - PMM_NPS_MODE -- PMM Non-power switching mode - Ports are powered continuously. - - PMM_GLOBAL_MODE -- PMM global switching mode - All ports are powered at the same time. - - PMM_PERPORT_MODE -- PMM per port switching mode - Ports are powered individually. - */ -static int pxa27x_ohci_select_pmm(struct pxa27x_ohci *ohci, int mode) -{ - uint32_t uhcrhda = __raw_readl(ohci->mmio_base + UHCRHDA); - uint32_t uhcrhdb = __raw_readl(ohci->mmio_base + UHCRHDB); - - switch (mode) { - case PMM_NPS_MODE: - uhcrhda |= RH_A_NPS; - break; - case PMM_GLOBAL_MODE: - uhcrhda &= ~(RH_A_NPS & RH_A_PSM); - break; - case PMM_PERPORT_MODE: - uhcrhda &= ~(RH_A_NPS); - uhcrhda |= RH_A_PSM; - - /* Set port power control mask bits, only 3 ports. */ - uhcrhdb |= (0x7<<17); - break; - default: - printk( KERN_ERR - "Invalid mode %d, set to non-power switch mode.\n", - mode ); - - uhcrhda |= RH_A_NPS; - } - - __raw_writel(uhcrhda, ohci->mmio_base + UHCRHDA); - __raw_writel(uhcrhdb, ohci->mmio_base + UHCRHDB); - return 0; -} - -extern int usb_disabled(void); - -/*-------------------------------------------------------------------------*/ - -static inline void pxa27x_setup_hc(struct pxa27x_ohci *ohci, - struct pxaohci_platform_data *inf) -{ - uint32_t uhchr = __raw_readl(ohci->mmio_base + UHCHR); - uint32_t uhcrhda = __raw_readl(ohci->mmio_base + UHCRHDA); - - if (inf->flags & ENABLE_PORT1) - uhchr &= ~UHCHR_SSEP1; - - if (inf->flags & ENABLE_PORT2) - uhchr &= ~UHCHR_SSEP2; - - if (inf->flags & ENABLE_PORT3) - uhchr &= ~UHCHR_SSEP3; - - if (inf->flags & POWER_CONTROL_LOW) - uhchr |= UHCHR_PCPL; - - if (inf->flags & POWER_SENSE_LOW) - uhchr |= UHCHR_PSPL; - - if (inf->flags & NO_OC_PROTECTION) - uhcrhda |= UHCRHDA_NOCP; - else - uhcrhda &= ~UHCRHDA_NOCP; - - if (inf->flags & OC_MODE_PERPORT) - uhcrhda |= UHCRHDA_OCPM; - else - uhcrhda &= ~UHCRHDA_OCPM; - - if (inf->power_on_delay) { - uhcrhda &= ~UHCRHDA_POTPGT(0xff); - uhcrhda |= UHCRHDA_POTPGT(inf->power_on_delay / 2); - } - - __raw_writel(uhchr, ohci->mmio_base + UHCHR); - __raw_writel(uhcrhda, ohci->mmio_base + UHCRHDA); -} - -static inline void pxa27x_reset_hc(struct pxa27x_ohci *ohci) -{ - uint32_t uhchr = __raw_readl(ohci->mmio_base + UHCHR); - - __raw_writel(uhchr | UHCHR_FHR, ohci->mmio_base + UHCHR); - udelay(11); - __raw_writel(uhchr & ~UHCHR_FHR, ohci->mmio_base + UHCHR); -} - -#ifdef CONFIG_PXA27x -extern void pxa27x_clear_otgph(void); -#else -#define pxa27x_clear_otgph() do {} while (0) -#endif - -static int pxa27x_start_hc(struct pxa27x_ohci *ohci, struct device *dev) -{ - int retval = 0; - struct pxaohci_platform_data *inf; - uint32_t uhchr; - - inf = dev->platform_data; - - clk_prepare_enable(ohci->clk); - - pxa27x_reset_hc(ohci); - - uhchr = __raw_readl(ohci->mmio_base + UHCHR) | UHCHR_FSBIR; - __raw_writel(uhchr, ohci->mmio_base + UHCHR); - - while (__raw_readl(ohci->mmio_base + UHCHR) & UHCHR_FSBIR) - cpu_relax(); - - pxa27x_setup_hc(ohci, inf); - - if (inf->init) - retval = inf->init(dev); - - if (retval < 0) - return retval; - - if (cpu_is_pxa3xx()) - pxa3xx_u2d_start_hc(&ohci_to_hcd(&ohci->ohci)->self); - - uhchr = __raw_readl(ohci->mmio_base + UHCHR) & ~UHCHR_SSE; - __raw_writel(uhchr, ohci->mmio_base + UHCHR); - __raw_writel(UHCHIE_UPRIE | UHCHIE_RWIE, ohci->mmio_base + UHCHIE); - - /* Clear any OTG Pin Hold */ - pxa27x_clear_otgph(); - return 0; -} - -static void pxa27x_stop_hc(struct pxa27x_ohci *ohci, struct device *dev) -{ - struct pxaohci_platform_data *inf; - uint32_t uhccoms; - - inf = dev->platform_data; - - if (cpu_is_pxa3xx()) - pxa3xx_u2d_stop_hc(&ohci_to_hcd(&ohci->ohci)->self); - - if (inf->exit) - inf->exit(dev); - - pxa27x_reset_hc(ohci); - - /* Host Controller Reset */ - uhccoms = __raw_readl(ohci->mmio_base + UHCCOMS) | 0x01; - __raw_writel(uhccoms, ohci->mmio_base + UHCCOMS); - udelay(10); - - clk_disable_unprepare(ohci->clk); -} - - -/*-------------------------------------------------------------------------*/ - -/* configure so an HC device and id are always provided */ -/* always called with process context; sleeping is OK */ - - -/** - * usb_hcd_pxa27x_probe - initialize pxa27x-based HCDs - * Context: !in_interrupt() - * - * Allocates basic resources for this USB host controller, and - * then invokes the start() method for the HCD associated with it - * through the hotplug entry's driver_data. - * - */ -int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device *pdev) -{ - int retval, irq; - struct usb_hcd *hcd; - struct pxaohci_platform_data *inf; - struct pxa27x_ohci *ohci; - struct resource *r; - struct clk *usb_clk; - - inf = pdev->dev.platform_data; - - if (!inf) - return -ENODEV; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - pr_err("no resource of IORESOURCE_IRQ"); - return -ENXIO; - } - - usb_clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(usb_clk)) - return PTR_ERR(usb_clk); - - hcd = usb_create_hcd (driver, &pdev->dev, "pxa27x"); - if (!hcd) { - retval = -ENOMEM; - goto err0; - } - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r) { - pr_err("no resource of IORESOURCE_MEM"); - retval = -ENXIO; - goto err1; - } - - hcd->rsrc_start = r->start; - hcd->rsrc_len = resource_size(r); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - pr_debug("request_mem_region failed"); - retval = -EBUSY; - goto err1; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - pr_debug("ioremap failed"); - retval = -ENOMEM; - goto err2; - } - - /* initialize "struct pxa27x_ohci" */ - ohci = (struct pxa27x_ohci *)hcd_to_ohci(hcd); - ohci->dev = &pdev->dev; - ohci->clk = usb_clk; - ohci->mmio_base = (void __iomem *)hcd->regs; - - if ((retval = pxa27x_start_hc(ohci, &pdev->dev)) < 0) { - pr_debug("pxa27x_start_hc failed"); - goto err3; - } - - /* Select Power Management Mode */ - pxa27x_ohci_select_pmm(ohci, inf->port_mode); - - if (inf->power_budget) - hcd->power_budget = inf->power_budget; - - ohci_hcd_init(hcd_to_ohci(hcd)); - - retval = usb_add_hcd(hcd, irq, 0); - if (retval == 0) - return retval; - - pxa27x_stop_hc(ohci, &pdev->dev); - err3: - iounmap(hcd->regs); - err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - err1: - usb_put_hcd(hcd); - err0: - clk_put(usb_clk); - return retval; -} - - -/* may be called without controller electrically present */ -/* may be called with controller, bus, and devices active */ - -/** - * usb_hcd_pxa27x_remove - shutdown processing for pxa27x-based HCDs - * @dev: USB Host Controller being removed - * Context: !in_interrupt() - * - * Reverses the effect of usb_hcd_pxa27x_probe(), first invoking - * the HCD's stop() method. It is always called from a thread - * context, normally "rmmod", "apmd", or something similar. - * - */ -void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *pdev) -{ - struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd); - - usb_remove_hcd(hcd); - pxa27x_stop_hc(ohci, &pdev->dev); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - clk_put(ohci->clk); -} - -/*-------------------------------------------------------------------------*/ - -static int __devinit -ohci_pxa27x_start (struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci (hcd); - int ret; - - ohci_dbg (ohci, "ohci_pxa27x_start, ohci:%p", ohci); - - /* The value of NDP in roothub_a is incorrect on this hardware */ - ohci->num_ports = 3; - - if ((ret = ohci_init(ohci)) < 0) - return ret; - - if ((ret = ohci_run (ohci)) < 0) { - err ("can't start %s", hcd->self.bus_name); - ohci_stop (hcd); - return ret; - } - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static const struct hc_driver ohci_pxa27x_hc_driver = { - .description = hcd_name, - .product_desc = "PXA27x OHCI", - .hcd_priv_size = sizeof(struct pxa27x_ohci), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .start = ohci_pxa27x_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -/*-------------------------------------------------------------------------*/ - -static int ohci_hcd_pxa27x_drv_probe(struct platform_device *pdev) -{ - pr_debug ("In ohci_hcd_pxa27x_drv_probe"); - - if (usb_disabled()) - return -ENODEV; - - return usb_hcd_pxa27x_probe(&ohci_pxa27x_hc_driver, pdev); -} - -static int ohci_hcd_pxa27x_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_hcd_pxa27x_remove(hcd, pdev); - platform_set_drvdata(pdev, NULL); - return 0; -} - -#ifdef CONFIG_PM -static int ohci_hcd_pxa27x_drv_suspend(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd); - - if (time_before(jiffies, ohci->ohci.next_statechange)) - msleep(5); - ohci->ohci.next_statechange = jiffies; - - pxa27x_stop_hc(ohci, dev); - return 0; -} - -static int ohci_hcd_pxa27x_drv_resume(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd); - struct pxaohci_platform_data *inf = dev->platform_data; - int status; - - if (time_before(jiffies, ohci->ohci.next_statechange)) - msleep(5); - ohci->ohci.next_statechange = jiffies; - - if ((status = pxa27x_start_hc(ohci, dev)) < 0) - return status; - - /* Select Power Management Mode */ - pxa27x_ohci_select_pmm(ohci, inf->port_mode); - - ohci_finish_controller_resume(hcd); - return 0; -} - -static const struct dev_pm_ops ohci_hcd_pxa27x_pm_ops = { - .suspend = ohci_hcd_pxa27x_drv_suspend, - .resume = ohci_hcd_pxa27x_drv_resume, -}; -#endif - -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:pxa27x-ohci"); - -static struct platform_driver ohci_hcd_pxa27x_driver = { - .probe = ohci_hcd_pxa27x_drv_probe, - .remove = ohci_hcd_pxa27x_drv_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "pxa27x-ohci", - .owner = THIS_MODULE, -#ifdef CONFIG_PM - .pm = &ohci_hcd_pxa27x_pm_ops, -#endif - }, -}; - diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-q.c b/ANDROID_3.4.5/drivers/usb/host/ohci-q.c deleted file mode 100644 index c5a1ea91..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-q.c +++ /dev/null @@ -1,1134 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2002 David Brownell - * - * This file is licenced under the GPL. - */ - -#include -#include - -static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv) -{ - int last = urb_priv->length - 1; - - if (last >= 0) { - int i; - struct td *td; - - for (i = 0; i <= last; i++) { - td = urb_priv->td [i]; - if (td) - td_free (hc, td); - } - } - - list_del (&urb_priv->pending); - kfree (urb_priv); -} - -/*-------------------------------------------------------------------------*/ - -/* - * URB goes back to driver, and isn't reissued. - * It's completely gone from HC data structures. - * PRECONDITION: ohci lock held, irqs blocked. - */ -static void -finish_urb(struct ohci_hcd *ohci, struct urb *urb, int status) -__releases(ohci->lock) -__acquires(ohci->lock) -{ - // ASSERT (urb->hcpriv != 0); - - urb_free_priv (ohci, urb->hcpriv); - if (likely(status == -EINPROGRESS)) - status = 0; - - switch (usb_pipetype (urb->pipe)) { - case PIPE_ISOCHRONOUS: - ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs--; - if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0) { - if (quirk_amdiso(ohci)) - usb_amd_quirk_pll_enable(); - if (quirk_amdprefetch(ohci)) - sb800_prefetch(ohci, 0); - } - break; - case PIPE_INTERRUPT: - ohci_to_hcd(ohci)->self.bandwidth_int_reqs--; - break; - } - -#ifdef OHCI_VERBOSE_DEBUG - urb_print(urb, "RET", usb_pipeout (urb->pipe), status); -#endif - - /* urb->complete() can reenter this HCD */ - usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb); - spin_unlock (&ohci->lock); - usb_hcd_giveback_urb(ohci_to_hcd(ohci), urb, status); - spin_lock (&ohci->lock); - - /* stop periodic dma if it's not needed */ - if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0 - && ohci_to_hcd(ohci)->self.bandwidth_int_reqs == 0) { - ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_IE); - ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); - } -} - - -/*-------------------------------------------------------------------------* - * ED handling functions - *-------------------------------------------------------------------------*/ - -/* search for the right schedule branch to use for a periodic ed. - * does some load balancing; returns the branch, or negative errno. - */ -static int balance (struct ohci_hcd *ohci, int interval, int load) -{ - int i, branch = -ENOSPC; - - /* iso periods can be huge; iso tds specify frame numbers */ - if (interval > NUM_INTS) - interval = NUM_INTS; - - /* search for the least loaded schedule branch of that period - * that has enough bandwidth left unreserved. - */ - for (i = 0; i < interval ; i++) { - if (branch < 0 || ohci->load [branch] > ohci->load [i]) { - int j; - - /* usb 1.1 says 90% of one frame */ - for (j = i; j < NUM_INTS; j += interval) { - if ((ohci->load [j] + load) > 900) - break; - } - if (j < NUM_INTS) - continue; - branch = i; - } - } - return branch; -} - -/*-------------------------------------------------------------------------*/ - -/* both iso and interrupt requests have periods; this routine puts them - * into the schedule tree in the apppropriate place. most iso devices use - * 1msec periods, but that's not required. - */ -static void periodic_link (struct ohci_hcd *ohci, struct ed *ed) -{ - unsigned i; - - ohci_vdbg (ohci, "link %sed %p branch %d [%dus.], interval %d\n", - (ed->hwINFO & cpu_to_hc32 (ohci, ED_ISO)) ? "iso " : "", - ed, ed->branch, ed->load, ed->interval); - - for (i = ed->branch; i < NUM_INTS; i += ed->interval) { - struct ed **prev = &ohci->periodic [i]; - __hc32 *prev_p = &ohci->hcca->int_table [i]; - struct ed *here = *prev; - - /* sorting each branch by period (slow before fast) - * lets us share the faster parts of the tree. - * (plus maybe: put interrupt eds before iso) - */ - while (here && ed != here) { - if (ed->interval > here->interval) - break; - prev = &here->ed_next; - prev_p = &here->hwNextED; - here = *prev; - } - if (ed != here) { - ed->ed_next = here; - if (here) - ed->hwNextED = *prev_p; - wmb (); - *prev = ed; - *prev_p = cpu_to_hc32(ohci, ed->dma); - wmb(); - } - ohci->load [i] += ed->load; - } - ohci_to_hcd(ohci)->self.bandwidth_allocated += ed->load / ed->interval; -} - -/* link an ed into one of the HC chains */ - -static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed) -{ - int branch; - - ed->state = ED_OPER; - ed->ed_prev = NULL; - ed->ed_next = NULL; - ed->hwNextED = 0; - if (quirk_zfmicro(ohci) - && (ed->type == PIPE_INTERRUPT) - && !(ohci->eds_scheduled++)) - mod_timer(&ohci->unlink_watchdog, round_jiffies(jiffies + HZ)); - wmb (); - - /* we care about rm_list when setting CLE/BLE in case the HC was at - * work on some TD when CLE/BLE was turned off, and isn't quiesced - * yet. finish_unlinks() restarts as needed, some upcoming INTR_SF. - * - * control and bulk EDs are doubly linked (ed_next, ed_prev), but - * periodic ones are singly linked (ed_next). that's because the - * periodic schedule encodes a tree like figure 3-5 in the ohci - * spec: each qh can have several "previous" nodes, and the tree - * doesn't have unused/idle descriptors. - */ - switch (ed->type) { - case PIPE_CONTROL: - if (ohci->ed_controltail == NULL) { - WARN_ON (ohci->hc_control & OHCI_CTRL_CLE); - ohci_writel (ohci, ed->dma, - &ohci->regs->ed_controlhead); - } else { - ohci->ed_controltail->ed_next = ed; - ohci->ed_controltail->hwNextED = cpu_to_hc32 (ohci, - ed->dma); - } - ed->ed_prev = ohci->ed_controltail; - if (!ohci->ed_controltail && !ohci->ed_rm_list) { - wmb(); - ohci->hc_control |= OHCI_CTRL_CLE; - ohci_writel (ohci, 0, &ohci->regs->ed_controlcurrent); - ohci_writel (ohci, ohci->hc_control, - &ohci->regs->control); - } - ohci->ed_controltail = ed; - break; - - case PIPE_BULK: - if (ohci->ed_bulktail == NULL) { - WARN_ON (ohci->hc_control & OHCI_CTRL_BLE); - ohci_writel (ohci, ed->dma, &ohci->regs->ed_bulkhead); - } else { - ohci->ed_bulktail->ed_next = ed; - ohci->ed_bulktail->hwNextED = cpu_to_hc32 (ohci, - ed->dma); - } - ed->ed_prev = ohci->ed_bulktail; - if (!ohci->ed_bulktail && !ohci->ed_rm_list) { - wmb(); - ohci->hc_control |= OHCI_CTRL_BLE; - ohci_writel (ohci, 0, &ohci->regs->ed_bulkcurrent); - ohci_writel (ohci, ohci->hc_control, - &ohci->regs->control); - } - ohci->ed_bulktail = ed; - break; - - // case PIPE_INTERRUPT: - // case PIPE_ISOCHRONOUS: - default: - branch = balance (ohci, ed->interval, ed->load); - if (branch < 0) { - ohci_dbg (ohci, - "ERR %d, interval %d msecs, load %d\n", - branch, ed->interval, ed->load); - // FIXME if there are TDs queued, fail them! - return branch; - } - ed->branch = branch; - periodic_link (ohci, ed); - } - - /* the HC may not see the schedule updates yet, but if it does - * then they'll be properly ordered. - */ - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* scan the periodic table to find and unlink this ED */ -static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed) -{ - int i; - - for (i = ed->branch; i < NUM_INTS; i += ed->interval) { - struct ed *temp; - struct ed **prev = &ohci->periodic [i]; - __hc32 *prev_p = &ohci->hcca->int_table [i]; - - while (*prev && (temp = *prev) != ed) { - prev_p = &temp->hwNextED; - prev = &temp->ed_next; - } - if (*prev) { - *prev_p = ed->hwNextED; - *prev = ed->ed_next; - } - ohci->load [i] -= ed->load; - } - ohci_to_hcd(ohci)->self.bandwidth_allocated -= ed->load / ed->interval; - - ohci_vdbg (ohci, "unlink %sed %p branch %d [%dus.], interval %d\n", - (ed->hwINFO & cpu_to_hc32 (ohci, ED_ISO)) ? "iso " : "", - ed, ed->branch, ed->load, ed->interval); -} - -/* unlink an ed from one of the HC chains. - * just the link to the ed is unlinked. - * the link from the ed still points to another operational ed or 0 - * so the HC can eventually finish the processing of the unlinked ed - * (assuming it already started that, which needn't be true). - * - * ED_UNLINK is a transient state: the HC may still see this ED, but soon - * it won't. ED_SKIP means the HC will finish its current transaction, - * but won't start anything new. The TD queue may still grow; device - * drivers don't know about this HCD-internal state. - * - * When the HC can't see the ED, something changes ED_UNLINK to one of: - * - * - ED_OPER: when there's any request queued, the ED gets rescheduled - * immediately. HC should be working on them. - * - * - ED_IDLE: when there's no TD queue. there's no reason for the HC - * to care about this ED; safe to disable the endpoint. - * - * When finish_unlinks() runs later, after SOF interrupt, it will often - * complete one or more URB unlinks before making that state change. - */ -static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed) -{ - ed->hwINFO |= cpu_to_hc32 (ohci, ED_SKIP); - wmb (); - ed->state = ED_UNLINK; - - /* To deschedule something from the control or bulk list, just - * clear CLE/BLE and wait. There's no safe way to scrub out list - * head/current registers until later, and "later" isn't very - * tightly specified. Figure 6-5 and Section 6.4.2.2 show how - * the HC is reading the ED queues (while we modify them). - * - * For now, ed_schedule() is "later". It might be good paranoia - * to scrub those registers in finish_unlinks(), in case of bugs - * that make the HC try to use them. - */ - switch (ed->type) { - case PIPE_CONTROL: - /* remove ED from the HC's list: */ - if (ed->ed_prev == NULL) { - if (!ed->hwNextED) { - ohci->hc_control &= ~OHCI_CTRL_CLE; - ohci_writel (ohci, ohci->hc_control, - &ohci->regs->control); - // a ohci_readl() later syncs CLE with the HC - } else - ohci_writel (ohci, - hc32_to_cpup (ohci, &ed->hwNextED), - &ohci->regs->ed_controlhead); - } else { - ed->ed_prev->ed_next = ed->ed_next; - ed->ed_prev->hwNextED = ed->hwNextED; - } - /* remove ED from the HCD's list: */ - if (ohci->ed_controltail == ed) { - ohci->ed_controltail = ed->ed_prev; - if (ohci->ed_controltail) - ohci->ed_controltail->ed_next = NULL; - } else if (ed->ed_next) { - ed->ed_next->ed_prev = ed->ed_prev; - } - break; - - case PIPE_BULK: - /* remove ED from the HC's list: */ - if (ed->ed_prev == NULL) { - if (!ed->hwNextED) { - ohci->hc_control &= ~OHCI_CTRL_BLE; - ohci_writel (ohci, ohci->hc_control, - &ohci->regs->control); - // a ohci_readl() later syncs BLE with the HC - } else - ohci_writel (ohci, - hc32_to_cpup (ohci, &ed->hwNextED), - &ohci->regs->ed_bulkhead); - } else { - ed->ed_prev->ed_next = ed->ed_next; - ed->ed_prev->hwNextED = ed->hwNextED; - } - /* remove ED from the HCD's list: */ - if (ohci->ed_bulktail == ed) { - ohci->ed_bulktail = ed->ed_prev; - if (ohci->ed_bulktail) - ohci->ed_bulktail->ed_next = NULL; - } else if (ed->ed_next) { - ed->ed_next->ed_prev = ed->ed_prev; - } - break; - - // case PIPE_INTERRUPT: - // case PIPE_ISOCHRONOUS: - default: - periodic_unlink (ohci, ed); - break; - } -} - - -/*-------------------------------------------------------------------------*/ - -/* get and maybe (re)init an endpoint. init _should_ be done only as part - * of enumeration, usb_set_configuration() or usb_set_interface(). - */ -static struct ed *ed_get ( - struct ohci_hcd *ohci, - struct usb_host_endpoint *ep, - struct usb_device *udev, - unsigned int pipe, - int interval -) { - struct ed *ed; - unsigned long flags; - - spin_lock_irqsave (&ohci->lock, flags); - - if (!(ed = ep->hcpriv)) { - struct td *td; - int is_out; - u32 info; - - ed = ed_alloc (ohci, GFP_ATOMIC); - if (!ed) { - /* out of memory */ - goto done; - } - - /* dummy td; end of td list for ed */ - td = td_alloc (ohci, GFP_ATOMIC); - if (!td) { - /* out of memory */ - ed_free (ohci, ed); - ed = NULL; - goto done; - } - ed->dummy = td; - ed->hwTailP = cpu_to_hc32 (ohci, td->td_dma); - ed->hwHeadP = ed->hwTailP; /* ED_C, ED_H zeroed */ - ed->state = ED_IDLE; - - is_out = !(ep->desc.bEndpointAddress & USB_DIR_IN); - - /* FIXME usbcore changes dev->devnum before SET_ADDRESS - * succeeds ... otherwise we wouldn't need "pipe". - */ - info = usb_pipedevice (pipe); - ed->type = usb_pipetype(pipe); - - info |= (ep->desc.bEndpointAddress & ~USB_DIR_IN) << 7; - info |= usb_endpoint_maxp(&ep->desc) << 16; - if (udev->speed == USB_SPEED_LOW) - info |= ED_LOWSPEED; - /* only control transfers store pids in tds */ - if (ed->type != PIPE_CONTROL) { - info |= is_out ? ED_OUT : ED_IN; - if (ed->type != PIPE_BULK) { - /* periodic transfers... */ - if (ed->type == PIPE_ISOCHRONOUS) - info |= ED_ISO; - else if (interval > 32) /* iso can be bigger */ - interval = 32; - ed->interval = interval; - ed->load = usb_calc_bus_time ( - udev->speed, !is_out, - ed->type == PIPE_ISOCHRONOUS, - usb_endpoint_maxp(&ep->desc)) - / 1000; - } - } - ed->hwINFO = cpu_to_hc32(ohci, info); - - ep->hcpriv = ed; - } - -done: - spin_unlock_irqrestore (&ohci->lock, flags); - return ed; -} - -/*-------------------------------------------------------------------------*/ - -/* request unlinking of an endpoint from an operational HC. - * put the ep on the rm_list - * real work is done at the next start frame (SF) hardware interrupt - * caller guarantees HCD is running, so hardware access is safe, - * and that ed->state is ED_OPER - */ -static void start_ed_unlink (struct ohci_hcd *ohci, struct ed *ed) -{ - ed->hwINFO |= cpu_to_hc32 (ohci, ED_DEQUEUE); - ed_deschedule (ohci, ed); - - /* rm_list is just singly linked, for simplicity */ - ed->ed_next = ohci->ed_rm_list; - ed->ed_prev = NULL; - ohci->ed_rm_list = ed; - - /* enable SOF interrupt */ - ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrstatus); - ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrenable); - // flush those writes, and get latest HCCA contents - (void) ohci_readl (ohci, &ohci->regs->control); - - /* SF interrupt might get delayed; record the frame counter value that - * indicates when the HC isn't looking at it, so concurrent unlinks - * behave. frame_no wraps every 2^16 msec, and changes right before - * SF is triggered. - */ - ed->tick = ohci_frame_no(ohci) + 1; - -} - -/*-------------------------------------------------------------------------* - * TD handling functions - *-------------------------------------------------------------------------*/ - -/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */ - -static void -td_fill (struct ohci_hcd *ohci, u32 info, - dma_addr_t data, int len, - struct urb *urb, int index) -{ - struct td *td, *td_pt; - struct urb_priv *urb_priv = urb->hcpriv; - int is_iso = info & TD_ISO; - int hash; - - // ASSERT (index < urb_priv->length); - - /* aim for only one interrupt per urb. mostly applies to control - * and iso; other urbs rarely need more than one TD per urb. - * this way, only final tds (or ones with an error) cause IRQs. - * at least immediately; use DI=6 in case any control request is - * tempted to die part way through. (and to force the hc to flush - * its donelist soonish, even on unlink paths.) - * - * NOTE: could delay interrupts even for the last TD, and get fewer - * interrupts ... increasing per-urb latency by sharing interrupts. - * Drivers that queue bulk urbs may request that behavior. - */ - if (index != (urb_priv->length - 1) - || (urb->transfer_flags & URB_NO_INTERRUPT)) - info |= TD_DI_SET (6); - - /* use this td as the next dummy */ - td_pt = urb_priv->td [index]; - - /* fill the old dummy TD */ - td = urb_priv->td [index] = urb_priv->ed->dummy; - urb_priv->ed->dummy = td_pt; - - td->ed = urb_priv->ed; - td->next_dl_td = NULL; - td->index = index; - td->urb = urb; - td->data_dma = data; - if (!len) - data = 0; - - td->hwINFO = cpu_to_hc32 (ohci, info); - if (is_iso) { - td->hwCBP = cpu_to_hc32 (ohci, data & 0xFFFFF000); - *ohci_hwPSWp(ohci, td, 0) = cpu_to_hc16 (ohci, - (data & 0x0FFF) | 0xE000); - td->ed->last_iso = info & 0xffff; - } else { - td->hwCBP = cpu_to_hc32 (ohci, data); - } - if (data) - td->hwBE = cpu_to_hc32 (ohci, data + len - 1); - else - td->hwBE = 0; - td->hwNextTD = cpu_to_hc32 (ohci, td_pt->td_dma); - - /* append to queue */ - list_add_tail (&td->td_list, &td->ed->td_list); - - /* hash it for later reverse mapping */ - hash = TD_HASH_FUNC (td->td_dma); - td->td_hash = ohci->td_hash [hash]; - ohci->td_hash [hash] = td; - - /* HC might read the TD (or cachelines) right away ... */ - wmb (); - td->ed->hwTailP = td->hwNextTD; -} - -/*-------------------------------------------------------------------------*/ - -/* Prepare all TDs of a transfer, and queue them onto the ED. - * Caller guarantees HC is active. - * Usually the ED is already on the schedule, so TDs might be - * processed as soon as they're queued. - */ -static void td_submit_urb ( - struct ohci_hcd *ohci, - struct urb *urb -) { - struct urb_priv *urb_priv = urb->hcpriv; - dma_addr_t data; - int data_len = urb->transfer_buffer_length; - int cnt = 0; - u32 info = 0; - int is_out = usb_pipeout (urb->pipe); - int periodic = 0; - - /* OHCI handles the bulk/interrupt data toggles itself. We just - * use the device toggle bits for resetting, and rely on the fact - * that resetting toggle is meaningless if the endpoint is active. - */ - if (!usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), is_out)) { - usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), - is_out, 1); - urb_priv->ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_C); - } - - urb_priv->td_cnt = 0; - list_add (&urb_priv->pending, &ohci->pending); - - if (data_len) - data = urb->transfer_dma; - else - data = 0; - - /* NOTE: TD_CC is set so we can tell which TDs the HC processed by - * using TD_CC_GET, as well as by seeing them on the done list. - * (CC = NotAccessed ... 0x0F, or 0x0E in PSWs for ISO.) - */ - switch (urb_priv->ed->type) { - - /* Bulk and interrupt are identical except for where in the schedule - * their EDs live. - */ - case PIPE_INTERRUPT: - /* ... and periodic urbs have extra accounting */ - periodic = ohci_to_hcd(ohci)->self.bandwidth_int_reqs++ == 0 - && ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0; - /* FALLTHROUGH */ - case PIPE_BULK: - info = is_out - ? TD_T_TOGGLE | TD_CC | TD_DP_OUT - : TD_T_TOGGLE | TD_CC | TD_DP_IN; - /* TDs _could_ transfer up to 8K each */ - while (data_len > 4096) { - td_fill (ohci, info, data, 4096, urb, cnt); - data += 4096; - data_len -= 4096; - cnt++; - } - /* maybe avoid ED halt on final TD short read */ - if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) - info |= TD_R; - td_fill (ohci, info, data, data_len, urb, cnt); - cnt++; - if ((urb->transfer_flags & URB_ZERO_PACKET) - && cnt < urb_priv->length) { - td_fill (ohci, info, 0, 0, urb, cnt); - cnt++; - } - /* maybe kickstart bulk list */ - if (urb_priv->ed->type == PIPE_BULK) { - wmb (); - ohci_writel (ohci, OHCI_BLF, &ohci->regs->cmdstatus); - } - break; - - /* control manages DATA0/DATA1 toggle per-request; SETUP resets it, - * any DATA phase works normally, and the STATUS ack is special. - */ - case PIPE_CONTROL: - info = TD_CC | TD_DP_SETUP | TD_T_DATA0; - td_fill (ohci, info, urb->setup_dma, 8, urb, cnt++); - if (data_len > 0) { - info = TD_CC | TD_R | TD_T_DATA1; - info |= is_out ? TD_DP_OUT : TD_DP_IN; - /* NOTE: mishandles transfers >8K, some >4K */ - td_fill (ohci, info, data, data_len, urb, cnt++); - } - info = (is_out || data_len == 0) - ? TD_CC | TD_DP_IN | TD_T_DATA1 - : TD_CC | TD_DP_OUT | TD_T_DATA1; - td_fill (ohci, info, data, 0, urb, cnt++); - /* maybe kickstart control list */ - wmb (); - ohci_writel (ohci, OHCI_CLF, &ohci->regs->cmdstatus); - break; - - /* ISO has no retransmit, so no toggle; and it uses special TDs. - * Each TD could handle multiple consecutive frames (interval 1); - * we could often reduce the number of TDs here. - */ - case PIPE_ISOCHRONOUS: - for (cnt = 0; cnt < urb->number_of_packets; cnt++) { - int frame = urb->start_frame; - - // FIXME scheduling should handle frame counter - // roll-around ... exotic case (and OHCI has - // a 2^16 iso range, vs other HCs max of 2^10) - frame += cnt * urb->interval; - frame &= 0xffff; - td_fill (ohci, TD_CC | TD_ISO | frame, - data + urb->iso_frame_desc [cnt].offset, - urb->iso_frame_desc [cnt].length, urb, cnt); - } - if (ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs == 0) { - if (quirk_amdiso(ohci)) - usb_amd_quirk_pll_disable(); - if (quirk_amdprefetch(ohci)) - sb800_prefetch(ohci, 1); - } - periodic = ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs++ == 0 - && ohci_to_hcd(ohci)->self.bandwidth_int_reqs == 0; - break; - } - - /* start periodic dma if needed */ - if (periodic) { - wmb (); - ohci->hc_control |= OHCI_CTRL_PLE|OHCI_CTRL_IE; - ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); - } - - // ASSERT (urb_priv->length == cnt); -} - -/*-------------------------------------------------------------------------* - * Done List handling functions - *-------------------------------------------------------------------------*/ - -/* calculate transfer length/status and update the urb */ -static int td_done(struct ohci_hcd *ohci, struct urb *urb, struct td *td) -{ - u32 tdINFO = hc32_to_cpup (ohci, &td->hwINFO); - int cc = 0; - int status = -EINPROGRESS; - - list_del (&td->td_list); - - /* ISO ... drivers see per-TD length/status */ - if (tdINFO & TD_ISO) { - u16 tdPSW = ohci_hwPSW(ohci, td, 0); - int dlen = 0; - - /* NOTE: assumes FC in tdINFO == 0, and that - * only the first of 0..MAXPSW psws is used. - */ - - cc = (tdPSW >> 12) & 0xF; - if (tdINFO & TD_CC) /* hc didn't touch? */ - return status; - - if (usb_pipeout (urb->pipe)) - dlen = urb->iso_frame_desc [td->index].length; - else { - /* short reads are always OK for ISO */ - if (cc == TD_DATAUNDERRUN) - cc = TD_CC_NOERROR; - dlen = tdPSW & 0x3ff; - } - urb->actual_length += dlen; - urb->iso_frame_desc [td->index].actual_length = dlen; - urb->iso_frame_desc [td->index].status = cc_to_error [cc]; - - if (cc != TD_CC_NOERROR) - ohci_vdbg (ohci, - "urb %p iso td %p (%d) len %d cc %d\n", - urb, td, 1 + td->index, dlen, cc); - - /* BULK, INT, CONTROL ... drivers see aggregate length/status, - * except that "setup" bytes aren't counted and "short" transfers - * might not be reported as errors. - */ - } else { - int type = usb_pipetype (urb->pipe); - u32 tdBE = hc32_to_cpup (ohci, &td->hwBE); - - cc = TD_CC_GET (tdINFO); - - /* update packet status if needed (short is normally ok) */ - if (cc == TD_DATAUNDERRUN - && !(urb->transfer_flags & URB_SHORT_NOT_OK)) - cc = TD_CC_NOERROR; - if (cc != TD_CC_NOERROR && cc < 0x0E) - status = cc_to_error[cc]; - - /* count all non-empty packets except control SETUP packet */ - if ((type != PIPE_CONTROL || td->index != 0) && tdBE != 0) { - if (td->hwCBP == 0) - urb->actual_length += tdBE - td->data_dma + 1; - else - urb->actual_length += - hc32_to_cpup (ohci, &td->hwCBP) - - td->data_dma; - } - - if (cc != TD_CC_NOERROR && cc < 0x0E) - ohci_vdbg (ohci, - "urb %p td %p (%d) cc %d, len=%d/%d\n", - urb, td, 1 + td->index, cc, - urb->actual_length, - urb->transfer_buffer_length); - } - return status; -} - -/*-------------------------------------------------------------------------*/ - -static void ed_halted(struct ohci_hcd *ohci, struct td *td, int cc) -{ - struct urb *urb = td->urb; - urb_priv_t *urb_priv = urb->hcpriv; - struct ed *ed = td->ed; - struct list_head *tmp = td->td_list.next; - __hc32 toggle = ed->hwHeadP & cpu_to_hc32 (ohci, ED_C); - - /* clear ed halt; this is the td that caused it, but keep it inactive - * until its urb->complete() has a chance to clean up. - */ - ed->hwINFO |= cpu_to_hc32 (ohci, ED_SKIP); - wmb (); - ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H); - - /* Get rid of all later tds from this urb. We don't have - * to be careful: no errors and nothing was transferred. - * Also patch the ed so it looks as if those tds completed normally. - */ - while (tmp != &ed->td_list) { - struct td *next; - - next = list_entry (tmp, struct td, td_list); - tmp = next->td_list.next; - - if (next->urb != urb) - break; - - /* NOTE: if multi-td control DATA segments get supported, - * this urb had one of them, this td wasn't the last td - * in that segment (TD_R clear), this ed halted because - * of a short read, _and_ URB_SHORT_NOT_OK is clear ... - * then we need to leave the control STATUS packet queued - * and clear ED_SKIP. - */ - - list_del(&next->td_list); - urb_priv->td_cnt++; - ed->hwHeadP = next->hwNextTD | toggle; - } - - /* help for troubleshooting: report anything that - * looks odd ... that doesn't include protocol stalls - * (or maybe some other things) - */ - switch (cc) { - case TD_DATAUNDERRUN: - if ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0) - break; - /* fallthrough */ - case TD_CC_STALL: - if (usb_pipecontrol (urb->pipe)) - break; - /* fallthrough */ - default: - ohci_dbg (ohci, - "urb %p path %s ep%d%s %08x cc %d --> status %d\n", - urb, urb->dev->devpath, - usb_pipeendpoint (urb->pipe), - usb_pipein (urb->pipe) ? "in" : "out", - hc32_to_cpu (ohci, td->hwINFO), - cc, cc_to_error [cc]); - } -} - -/* replies to the request have to be on a FIFO basis so - * we unreverse the hc-reversed done-list - */ -static struct td *dl_reverse_done_list (struct ohci_hcd *ohci) -{ - u32 td_dma; - struct td *td_rev = NULL; - struct td *td = NULL; - - td_dma = hc32_to_cpup (ohci, &ohci->hcca->done_head); - ohci->hcca->done_head = 0; - wmb(); - - /* get TD from hc's singly linked list, and - * prepend to ours. ed->td_list changes later. - */ - while (td_dma) { - int cc; - - td = dma_to_td (ohci, td_dma); - if (!td) { - ohci_err (ohci, "bad entry %8x\n", td_dma); - break; - } - - td->hwINFO |= cpu_to_hc32 (ohci, TD_DONE); - cc = TD_CC_GET (hc32_to_cpup (ohci, &td->hwINFO)); - - /* Non-iso endpoints can halt on error; un-halt, - * and dequeue any other TDs from this urb. - * No other TD could have caused the halt. - */ - if (cc != TD_CC_NOERROR - && (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H))) - ed_halted(ohci, td, cc); - - td->next_dl_td = td_rev; - td_rev = td; - td_dma = hc32_to_cpup (ohci, &td->hwNextTD); - } - return td_rev; -} - -/*-------------------------------------------------------------------------*/ - -/* there are some urbs/eds to unlink; called in_irq(), with HCD locked */ -static void -finish_unlinks (struct ohci_hcd *ohci, u16 tick) -{ - struct ed *ed, **last; - -rescan_all: - for (last = &ohci->ed_rm_list, ed = *last; ed != NULL; ed = *last) { - struct list_head *entry, *tmp; - int completed, modified; - __hc32 *prev; - - /* only take off EDs that the HC isn't using, accounting for - * frame counter wraps and EDs with partially retired TDs - */ - if (likely(ohci->rh_state == OHCI_RH_RUNNING)) { - if (tick_before (tick, ed->tick)) { -skip_ed: - last = &ed->ed_next; - continue; - } - - if (!list_empty (&ed->td_list)) { - struct td *td; - u32 head; - - td = list_entry (ed->td_list.next, struct td, - td_list); - head = hc32_to_cpu (ohci, ed->hwHeadP) & - TD_MASK; - - /* INTR_WDH may need to clean up first */ - if (td->td_dma != head) { - if (ed == ohci->ed_to_check) - ohci->ed_to_check = NULL; - else - goto skip_ed; - } - } - } - - /* reentrancy: if we drop the schedule lock, someone might - * have modified this list. normally it's just prepending - * entries (which we'd ignore), but paranoia won't hurt. - */ - *last = ed->ed_next; - ed->ed_next = NULL; - modified = 0; - - /* unlink urbs as requested, but rescan the list after - * we call a completion since it might have unlinked - * another (earlier) urb - * - * When we get here, the HC doesn't see this ed. But it - * must not be rescheduled until all completed URBs have - * been given back to the driver. - */ -rescan_this: - completed = 0; - prev = &ed->hwHeadP; - list_for_each_safe (entry, tmp, &ed->td_list) { - struct td *td; - struct urb *urb; - urb_priv_t *urb_priv; - __hc32 savebits; - u32 tdINFO; - - td = list_entry (entry, struct td, td_list); - urb = td->urb; - urb_priv = td->urb->hcpriv; - - if (!urb->unlinked) { - prev = &td->hwNextTD; - continue; - } - - /* patch pointer hc uses */ - savebits = *prev & ~cpu_to_hc32 (ohci, TD_MASK); - *prev = td->hwNextTD | savebits; - - /* If this was unlinked, the TD may not have been - * retired ... so manually save the data toggle. - * The controller ignores the value we save for - * control and ISO endpoints. - */ - tdINFO = hc32_to_cpup(ohci, &td->hwINFO); - if ((tdINFO & TD_T) == TD_T_DATA0) - ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_C); - else if ((tdINFO & TD_T) == TD_T_DATA1) - ed->hwHeadP |= cpu_to_hc32(ohci, ED_C); - - /* HC may have partly processed this TD */ - td_done (ohci, urb, td); - urb_priv->td_cnt++; - - /* if URB is done, clean up */ - if (urb_priv->td_cnt == urb_priv->length) { - modified = completed = 1; - finish_urb(ohci, urb, 0); - } - } - if (completed && !list_empty (&ed->td_list)) - goto rescan_this; - - /* ED's now officially unlinked, hc doesn't see */ - ed->state = ED_IDLE; - if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) - ohci->eds_scheduled--; - ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H); - ed->hwNextED = 0; - wmb (); - ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP | ED_DEQUEUE); - - /* but if there's work queued, reschedule */ - if (!list_empty (&ed->td_list)) { - if (ohci->rh_state == OHCI_RH_RUNNING) - ed_schedule (ohci, ed); - } - - if (modified) - goto rescan_all; - } - - /* maybe reenable control and bulk lists */ - if (ohci->rh_state == OHCI_RH_RUNNING && !ohci->ed_rm_list) { - u32 command = 0, control = 0; - - if (ohci->ed_controltail) { - command |= OHCI_CLF; - if (quirk_zfmicro(ohci)) - mdelay(1); - if (!(ohci->hc_control & OHCI_CTRL_CLE)) { - control |= OHCI_CTRL_CLE; - ohci_writel (ohci, 0, - &ohci->regs->ed_controlcurrent); - } - } - if (ohci->ed_bulktail) { - command |= OHCI_BLF; - if (quirk_zfmicro(ohci)) - mdelay(1); - if (!(ohci->hc_control & OHCI_CTRL_BLE)) { - control |= OHCI_CTRL_BLE; - ohci_writel (ohci, 0, - &ohci->regs->ed_bulkcurrent); - } - } - - /* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */ - if (control) { - ohci->hc_control |= control; - if (quirk_zfmicro(ohci)) - mdelay(1); - ohci_writel (ohci, ohci->hc_control, - &ohci->regs->control); - } - if (command) { - if (quirk_zfmicro(ohci)) - mdelay(1); - ohci_writel (ohci, command, &ohci->regs->cmdstatus); - } - } -} - - - -/*-------------------------------------------------------------------------*/ - -/* - * Used to take back a TD from the host controller. This would normally be - * called from within dl_done_list, however it may be called directly if the - * HC no longer sees the TD and it has not appeared on the donelist (after - * two frames). This bug has been observed on ZF Micro systems. - */ -static void takeback_td(struct ohci_hcd *ohci, struct td *td) -{ - struct urb *urb = td->urb; - urb_priv_t *urb_priv = urb->hcpriv; - struct ed *ed = td->ed; - int status; - - /* update URB's length and status from TD */ - status = td_done(ohci, urb, td); - urb_priv->td_cnt++; - - /* If all this urb's TDs are done, call complete() */ - if (urb_priv->td_cnt == urb_priv->length) - finish_urb(ohci, urb, status); - - /* clean schedule: unlink EDs that are no longer busy */ - if (list_empty(&ed->td_list)) { - if (ed->state == ED_OPER) - start_ed_unlink(ohci, ed); - - /* ... reenabling halted EDs only after fault cleanup */ - } else if ((ed->hwINFO & cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE)) - == cpu_to_hc32(ohci, ED_SKIP)) { - td = list_entry(ed->td_list.next, struct td, td_list); - if (!(td->hwINFO & cpu_to_hc32(ohci, TD_DONE))) { - ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP); - /* ... hc may need waking-up */ - switch (ed->type) { - case PIPE_CONTROL: - ohci_writel(ohci, OHCI_CLF, - &ohci->regs->cmdstatus); - break; - case PIPE_BULK: - ohci_writel(ohci, OHCI_BLF, - &ohci->regs->cmdstatus); - break; - } - } - } -} - -/* - * Process normal completions (error or success) and clean the schedules. - * - * This is the main path for handing urbs back to drivers. The only other - * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list, - * instead of scanning the (re-reversed) donelist as this does. There's - * an abnormal path too, handling a quirk in some Compaq silicon: URBs - * with TDs that appear to be orphaned are directly reclaimed. - */ -static void -dl_done_list (struct ohci_hcd *ohci) -{ - struct td *td = dl_reverse_done_list (ohci); - - while (td) { - struct td *td_next = td->next_dl_td; - takeback_td(ohci, td); - td = td_next; - } -} diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-s3c2410.c b/ANDROID_3.4.5/drivers/usb/host/ohci-s3c2410.c deleted file mode 100644 index 56dcf069..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-s3c2410.c +++ /dev/null @@ -1,552 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2002 David Brownell - * (C) Copyright 2002 Hewlett-Packard Company - * - * USB Bus Glue for Samsung S3C2410 - * - * Written by Christopher Hoover - * Based on fragments of previous driver by Russell King et al. - * - * Modified for S3C2410 from ohci-sa1111.c, ohci-omap.c and ohci-lh7a40.c - * by Ben Dooks, - * Copyright (C) 2004 Simtec Electronics - * - * Thanks to basprog@mail.ru for updates to newer kernels - * - * This file is licenced under the GPL. -*/ - -#include -#include -#include - -#define valid_port(idx) ((idx) == 1 || (idx) == 2) - -/* clock device associated with the hcd */ - -static struct clk *clk; -static struct clk *usb_clk; - -/* forward definitions */ - -static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc); - -/* conversion functions */ - -static struct s3c2410_hcd_info *to_s3c2410_info(struct usb_hcd *hcd) -{ - return hcd->self.controller->platform_data; -} - -static void s3c2410_start_hc(struct platform_device *dev, struct usb_hcd *hcd) -{ - struct s3c2410_hcd_info *info = dev->dev.platform_data; - - dev_dbg(&dev->dev, "s3c2410_start_hc:\n"); - - clk_enable(usb_clk); - mdelay(2); /* let the bus clock stabilise */ - - clk_enable(clk); - - if (info != NULL) { - info->hcd = hcd; - info->report_oc = s3c2410_hcd_oc; - - if (info->enable_oc != NULL) - (info->enable_oc)(info, 1); - } -} - -static void s3c2410_stop_hc(struct platform_device *dev) -{ - struct s3c2410_hcd_info *info = dev->dev.platform_data; - - dev_dbg(&dev->dev, "s3c2410_stop_hc:\n"); - - if (info != NULL) { - info->report_oc = NULL; - info->hcd = NULL; - - if (info->enable_oc != NULL) - (info->enable_oc)(info, 0); - } - - clk_disable(clk); - clk_disable(usb_clk); -} - -/* ohci_s3c2410_hub_status_data - * - * update the status data from the hub with anything that - * has been detected by our system -*/ - -static int -ohci_s3c2410_hub_status_data(struct usb_hcd *hcd, char *buf) -{ - struct s3c2410_hcd_info *info = to_s3c2410_info(hcd); - struct s3c2410_hcd_port *port; - int orig; - int portno; - - orig = ohci_hub_status_data(hcd, buf); - - if (info == NULL) - return orig; - - port = &info->port[0]; - - /* mark any changed port as changed */ - - for (portno = 0; portno < 2; port++, portno++) { - if (port->oc_changed == 1 && - port->flags & S3C_HCDFLG_USED) { - dev_dbg(hcd->self.controller, - "oc change on port %d\n", portno); - - if (orig < 1) - orig = 1; - - buf[0] |= 1<<(portno+1); - } - } - - return orig; -} - -/* s3c2410_usb_set_power - * - * configure the power on a port, by calling the platform device - * routine registered with the platform device -*/ - -static void s3c2410_usb_set_power(struct s3c2410_hcd_info *info, - int port, int to) -{ - if (info == NULL) - return; - - if (info->power_control != NULL) { - info->port[port-1].power = to; - (info->power_control)(port-1, to); - } -} - -/* ohci_s3c2410_hub_control - * - * look at control requests to the hub, and see if we need - * to take any action or over-ride the results from the - * request. -*/ - -static int ohci_s3c2410_hub_control( - struct usb_hcd *hcd, - u16 typeReq, - u16 wValue, - u16 wIndex, - char *buf, - u16 wLength) -{ - struct s3c2410_hcd_info *info = to_s3c2410_info(hcd); - struct usb_hub_descriptor *desc; - int ret = -EINVAL; - u32 *data = (u32 *)buf; - - dev_dbg(hcd->self.controller, - "s3c2410_hub_control(%p,0x%04x,0x%04x,0x%04x,%p,%04x)\n", - hcd, typeReq, wValue, wIndex, buf, wLength); - - /* if we are only an humble host without any special capabilities - * process the request straight away and exit */ - - if (info == NULL) { - ret = ohci_hub_control(hcd, typeReq, wValue, - wIndex, buf, wLength); - goto out; - } - - /* check the request to see if it needs handling */ - - switch (typeReq) { - case SetPortFeature: - if (wValue == USB_PORT_FEAT_POWER) { - dev_dbg(hcd->self.controller, "SetPortFeat: POWER\n"); - s3c2410_usb_set_power(info, wIndex, 1); - goto out; - } - break; - - case ClearPortFeature: - switch (wValue) { - case USB_PORT_FEAT_C_OVER_CURRENT: - dev_dbg(hcd->self.controller, - "ClearPortFeature: C_OVER_CURRENT\n"); - - if (valid_port(wIndex)) { - info->port[wIndex-1].oc_changed = 0; - info->port[wIndex-1].oc_status = 0; - } - - goto out; - - case USB_PORT_FEAT_OVER_CURRENT: - dev_dbg(hcd->self.controller, - "ClearPortFeature: OVER_CURRENT\n"); - - if (valid_port(wIndex)) - info->port[wIndex-1].oc_status = 0; - - goto out; - - case USB_PORT_FEAT_POWER: - dev_dbg(hcd->self.controller, - "ClearPortFeature: POWER\n"); - - if (valid_port(wIndex)) { - s3c2410_usb_set_power(info, wIndex, 0); - return 0; - } - } - break; - } - - ret = ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); - if (ret) - goto out; - - switch (typeReq) { - case GetHubDescriptor: - - /* update the hub's descriptor */ - - desc = (struct usb_hub_descriptor *)buf; - - if (info->power_control == NULL) - return ret; - - dev_dbg(hcd->self.controller, "wHubCharacteristics 0x%04x\n", - desc->wHubCharacteristics); - - /* remove the old configurations for power-switching, and - * over-current protection, and insert our new configuration - */ - - desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_LPSM); - desc->wHubCharacteristics |= cpu_to_le16(0x0001); - - if (info->enable_oc) { - desc->wHubCharacteristics &= ~cpu_to_le16( - HUB_CHAR_OCPM); - desc->wHubCharacteristics |= cpu_to_le16( - 0x0008 | - 0x0001); - } - - dev_dbg(hcd->self.controller, "wHubCharacteristics after 0x%04x\n", - desc->wHubCharacteristics); - - return ret; - - case GetPortStatus: - /* check port status */ - - dev_dbg(hcd->self.controller, "GetPortStatus(%d)\n", wIndex); - - if (valid_port(wIndex)) { - if (info->port[wIndex-1].oc_changed) - *data |= cpu_to_le32(RH_PS_OCIC); - - if (info->port[wIndex-1].oc_status) - *data |= cpu_to_le32(RH_PS_POCI); - } - } - - out: - return ret; -} - -/* s3c2410_hcd_oc - * - * handle an over-current report -*/ - -static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc) -{ - struct s3c2410_hcd_port *port; - struct usb_hcd *hcd; - unsigned long flags; - int portno; - - if (info == NULL) - return; - - port = &info->port[0]; - hcd = info->hcd; - - local_irq_save(flags); - - for (portno = 0; portno < 2; port++, portno++) { - if (port_oc & (1<flags & S3C_HCDFLG_USED) { - port->oc_status = 1; - port->oc_changed = 1; - - /* ok, once over-current is detected, - the port needs to be powered down */ - s3c2410_usb_set_power(info, portno+1, 0); - } - } - - local_irq_restore(flags); -} - -/* may be called without controller electrically present */ -/* may be called with controller, bus, and devices active */ - -/* - * usb_hcd_s3c2410_remove - shutdown processing for HCD - * @dev: USB Host Controller being removed - * Context: !in_interrupt() - * - * Reverses the effect of usb_hcd_3c2410_probe(), first invoking - * the HCD's stop() method. It is always called from a thread - * context, normally "rmmod", "apmd", or something similar. - * -*/ - -static void -usb_hcd_s3c2410_remove(struct usb_hcd *hcd, struct platform_device *dev) -{ - usb_remove_hcd(hcd); - s3c2410_stop_hc(dev); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); -} - -/** - * usb_hcd_s3c2410_probe - initialize S3C2410-based HCDs - * Context: !in_interrupt() - * - * Allocates basic resources for this USB host controller, and - * then invokes the start() method for the HCD associated with it - * through the hotplug entry's driver_data. - * - */ -static int usb_hcd_s3c2410_probe(const struct hc_driver *driver, - struct platform_device *dev) -{ - struct usb_hcd *hcd = NULL; - int retval; - - s3c2410_usb_set_power(dev->dev.platform_data, 1, 1); - s3c2410_usb_set_power(dev->dev.platform_data, 2, 1); - - hcd = usb_create_hcd(driver, &dev->dev, "s3c24xx"); - if (hcd == NULL) - return -ENOMEM; - - hcd->rsrc_start = dev->resource[0].start; - hcd->rsrc_len = resource_size(&dev->resource[0]); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - dev_err(&dev->dev, "request_mem_region failed\n"); - retval = -EBUSY; - goto err_put; - } - - clk = clk_get(&dev->dev, "usb-host"); - if (IS_ERR(clk)) { - dev_err(&dev->dev, "cannot get usb-host clock\n"); - retval = PTR_ERR(clk); - goto err_mem; - } - - usb_clk = clk_get(&dev->dev, "usb-bus-host"); - if (IS_ERR(usb_clk)) { - dev_err(&dev->dev, "cannot get usb-bus-host clock\n"); - retval = PTR_ERR(usb_clk); - goto err_clk; - } - - s3c2410_start_hc(dev, hcd); - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - dev_err(&dev->dev, "ioremap failed\n"); - retval = -ENOMEM; - goto err_ioremap; - } - - ohci_hcd_init(hcd_to_ohci(hcd)); - - retval = usb_add_hcd(hcd, dev->resource[1].start, 0); - if (retval != 0) - goto err_ioremap; - - return 0; - - err_ioremap: - s3c2410_stop_hc(dev); - iounmap(hcd->regs); - clk_put(usb_clk); - - err_clk: - clk_put(clk); - - err_mem: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - - err_put: - usb_put_hcd(hcd); - return retval; -} - -/*-------------------------------------------------------------------------*/ - -static int -ohci_s3c2410_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - ret = ohci_init(ohci); - if (ret < 0) - return ret; - - ret = ohci_run(ohci); - if (ret < 0) { - err("can't start %s", hcd->self.bus_name); - ohci_stop(hcd); - return ret; - } - - return 0; -} - - -static const struct hc_driver ohci_s3c2410_hc_driver = { - .description = hcd_name, - .product_desc = "S3C24XX OHCI", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .start = ohci_s3c2410_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_s3c2410_hub_status_data, - .hub_control = ohci_s3c2410_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -/* device driver */ - -static int __devinit ohci_hcd_s3c2410_drv_probe(struct platform_device *pdev) -{ - return usb_hcd_s3c2410_probe(&ohci_s3c2410_hc_driver, pdev); -} - -static int __devexit ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_hcd_s3c2410_remove(hcd, pdev); - return 0; -} - -#ifdef CONFIG_PM -static int ohci_hcd_s3c2410_drv_suspend(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - struct platform_device *pdev = to_platform_device(dev); - unsigned long flags; - int rc = 0; - - /* - * Root hub was already suspended. Disable irq emission and - * mark HW unaccessible, bail out if RH has been resumed. Use - * the spinlock to properly synchronize with possible pending - * RH suspend or resume activity. - */ - spin_lock_irqsave(&ohci->lock, flags); - if (ohci->rh_state != OHCI_RH_SUSPENDED) { - rc = -EINVAL; - goto bail; - } - - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - - s3c2410_stop_hc(pdev); -bail: - spin_unlock_irqrestore(&ohci->lock, flags); - - return rc; -} - -static int ohci_hcd_s3c2410_drv_resume(struct device *dev) -{ - struct usb_hcd *hcd = dev_get_drvdata(dev); - struct platform_device *pdev = to_platform_device(dev); - - s3c2410_start_hc(pdev, hcd); - - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - ohci_finish_controller_resume(hcd); - - return 0; -} -#else -#define ohci_hcd_s3c2410_drv_suspend NULL -#define ohci_hcd_s3c2410_drv_resume NULL -#endif - -static const struct dev_pm_ops ohci_hcd_s3c2410_pm_ops = { - .suspend = ohci_hcd_s3c2410_drv_suspend, - .resume = ohci_hcd_s3c2410_drv_resume, -}; - -static struct platform_driver ohci_hcd_s3c2410_driver = { - .probe = ohci_hcd_s3c2410_drv_probe, - .remove = __devexit_p(ohci_hcd_s3c2410_drv_remove), - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .owner = THIS_MODULE, - .name = "s3c2410-ohci", - .pm = &ohci_hcd_s3c2410_pm_ops, - }, -}; - -MODULE_ALIAS("platform:s3c2410-ohci"); diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-sa1111.c b/ANDROID_3.4.5/drivers/usb/host/ohci-sa1111.c deleted file mode 100644 index e1004fb3..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-sa1111.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2002 David Brownell - * (C) Copyright 2002 Hewlett-Packard Company - * - * SA1111 Bus Glue - * - * Written by Christopher Hoover - * Based on fragments of previous driver by Russell King et al. - * - * This file is licenced under the GPL. - */ - -#include -#include -#include -#include - -#ifndef CONFIG_SA1111 -#error "This file is SA-1111 bus glue. CONFIG_SA1111 must be defined." -#endif - -#define USB_STATUS 0x0118 -#define USB_RESET 0x011c -#define USB_IRQTEST 0x0120 - -#define USB_RESET_FORCEIFRESET (1 << 0) -#define USB_RESET_FORCEHCRESET (1 << 1) -#define USB_RESET_CLKGENRESET (1 << 2) -#define USB_RESET_SIMSCALEDOWN (1 << 3) -#define USB_RESET_USBINTTEST (1 << 4) -#define USB_RESET_SLEEPSTBYEN (1 << 5) -#define USB_RESET_PWRSENSELOW (1 << 6) -#define USB_RESET_PWRCTRLLOW (1 << 7) - -#define USB_STATUS_IRQHCIRMTWKUP (1 << 7) -#define USB_STATUS_IRQHCIBUFFACC (1 << 8) -#define USB_STATUS_NIRQHCIM (1 << 9) -#define USB_STATUS_NHCIMFCLR (1 << 10) -#define USB_STATUS_USBPWRSENSE (1 << 11) - -#if 0 -static void dump_hci_status(struct usb_hcd *hcd, const char *label) -{ - unsigned long status = sa1111_readl(hcd->regs + USB_STATUS); - - dbg("%s USB_STATUS = { %s%s%s%s%s}", label, - ((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""), - ((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""), - ((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "), - ((status & USB_STATUS_NHCIMFCLR) ? "" : "HCIMFCLR "), - ((status & USB_STATUS_USBPWRSENSE) ? "USBPWRSENSE " : "")); -} -#endif - -static int ohci_sa1111_reset(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - - ohci_hcd_init(ohci); - return ohci_init(ohci); -} - -static int __devinit ohci_sa1111_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - ret = ohci_run(ohci); - if (ret < 0) { - ohci_err(ohci, "can't start\n"); - ohci_stop(hcd); - } - return ret; -} - -static const struct hc_driver ohci_sa1111_hc_driver = { - .description = hcd_name, - .product_desc = "SA-1111 OHCI", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .reset = ohci_sa1111_reset, - .start = ohci_sa1111_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -static int sa1111_start_hc(struct sa1111_dev *dev) -{ - unsigned int usb_rst = 0; - int ret; - - dev_dbg(&dev->dev, "starting SA-1111 OHCI USB Controller\n"); - - if (machine_is_xp860() || - machine_has_neponset() || - machine_is_pfs168() || - machine_is_badge4()) - usb_rst = USB_RESET_PWRSENSELOW | USB_RESET_PWRCTRLLOW; - - /* - * Configure the power sense and control lines. Place the USB - * host controller in reset. - */ - sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET, - dev->mapbase + USB_RESET); - - /* - * Now, carefully enable the USB clock, and take - * the USB host controller out of reset. - */ - ret = sa1111_enable_device(dev); - if (ret == 0) { - udelay(11); - sa1111_writel(usb_rst, dev->mapbase + USB_RESET); - } - - return ret; -} - -static void sa1111_stop_hc(struct sa1111_dev *dev) -{ - unsigned int usb_rst; - - dev_dbg(&dev->dev, "stopping SA-1111 OHCI USB Controller\n"); - - /* - * Put the USB host controller into reset. - */ - usb_rst = sa1111_readl(dev->mapbase + USB_RESET); - sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET, - dev->mapbase + USB_RESET); - - /* - * Stop the USB clock. - */ - sa1111_disable_device(dev); -} - -/** - * ohci_hcd_sa1111_probe - initialize SA-1111-based HCDs - * - * Allocates basic resources for this USB host controller, and - * then invokes the start() method for the HCD associated with it. - */ -static int ohci_hcd_sa1111_probe(struct sa1111_dev *dev) -{ - struct usb_hcd *hcd; - int ret; - - if (usb_disabled()) - return -ENODEV; - - hcd = usb_create_hcd(&ohci_sa1111_hc_driver, &dev->dev, "sa1111"); - if (!hcd) - return -ENOMEM; - - hcd->rsrc_start = dev->res.start; - hcd->rsrc_len = resource_size(&dev->res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - dbg("request_mem_region failed"); - ret = -EBUSY; - goto err1; - } - - hcd->regs = dev->mapbase; - - ret = sa1111_start_hc(dev); - if (ret) - goto err2; - - ret = usb_add_hcd(hcd, dev->irq[1], 0); - if (ret == 0) - return ret; - - sa1111_stop_hc(dev); - err2: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - err1: - usb_put_hcd(hcd); - return ret; -} - -/** - * ohci_hcd_sa1111_remove - shutdown processing for SA-1111-based HCDs - * @dev: USB Host Controller being removed - * - * Reverses the effect of ohci_hcd_sa1111_probe(), first invoking - * the HCD's stop() method. - */ -static int ohci_hcd_sa1111_remove(struct sa1111_dev *dev) -{ - struct usb_hcd *hcd = sa1111_get_drvdata(dev); - - usb_remove_hcd(hcd); - sa1111_stop_hc(dev); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - - return 0; -} - -static void ohci_hcd_sa1111_shutdown(struct sa1111_dev *dev) -{ - struct usb_hcd *hcd = sa1111_get_drvdata(dev); - - if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { - hcd->driver->shutdown(hcd); - sa1111_stop_hc(dev); - } -} - -static struct sa1111_driver ohci_hcd_sa1111_driver = { - .drv = { - .name = "sa1111-ohci", - .owner = THIS_MODULE, - }, - .devid = SA1111_DEVID_USB, - .probe = ohci_hcd_sa1111_probe, - .remove = ohci_hcd_sa1111_remove, - .shutdown = ohci_hcd_sa1111_shutdown, -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-sh.c b/ANDROID_3.4.5/drivers/usb/host/ohci-sh.c deleted file mode 100644 index 84686d90..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-sh.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * Copyright (C) 2008 Renesas Solutions Corp. - * - * Author : Yoshihiro Shimoda - * - * 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; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include - -static int ohci_sh_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - - ohci_hcd_init(ohci); - ohci_init(ohci); - ohci_run(ohci); - return 0; -} - -static const struct hc_driver ohci_sh_hc_driver = { - .description = hcd_name, - .product_desc = "SuperH OHCI", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* - * basic lifecycle operations - */ - .start = ohci_sh_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -/*-------------------------------------------------------------------------*/ - -static int ohci_hcd_sh_probe(struct platform_device *pdev) -{ - struct resource *res = NULL; - struct usb_hcd *hcd = NULL; - int irq = -1; - int ret; - - if (usb_disabled()) - return -ENODEV; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - err("platform_get_resource error."); - return -ENODEV; - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - err("platform_get_irq error."); - return -ENODEV; - } - - /* initialize hcd */ - hcd = usb_create_hcd(&ohci_sh_hc_driver, &pdev->dev, (char *)hcd_name); - if (!hcd) { - err("Failed to create hcd"); - return -ENOMEM; - } - - hcd->regs = (void __iomem *)res->start; - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - ret = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (ret != 0) { - err("Failed to add hcd"); - usb_put_hcd(hcd); - return ret; - } - - return ret; -} - -static int ohci_hcd_sh_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - - usb_remove_hcd(hcd); - usb_put_hcd(hcd); - - return 0; -} - -static struct platform_driver ohci_hcd_sh_driver = { - .probe = ohci_hcd_sh_probe, - .remove = ohci_hcd_sh_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "sh_ohci", - .owner = THIS_MODULE, - }, -}; - -MODULE_ALIAS("platform:sh_ohci"); diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-sm501.c b/ANDROID_3.4.5/drivers/usb/host/ohci-sm501.c deleted file mode 100644 index 5596ac2b..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-sm501.c +++ /dev/null @@ -1,265 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2005 David Brownell - * (C) Copyright 2002 Hewlett-Packard Company - * (C) Copyright 2008 Magnus Damm - * - * SM501 Bus Glue - based on ohci-omap.c - * - * This file is licenced under the GPL. - */ - -#include -#include -#include -#include -#include -#include - -static int ohci_sm501_init(struct usb_hcd *hcd) -{ - return ohci_init(hcd_to_ohci(hcd)); -} - -static int ohci_sm501_start(struct usb_hcd *hcd) -{ - struct device *dev = hcd->self.controller; - int ret; - - ret = ohci_run(hcd_to_ohci(hcd)); - if (ret < 0) { - dev_err(dev, "can't start %s", hcd->self.bus_name); - ohci_stop(hcd); - } - - return ret; -} - -/*-------------------------------------------------------------------------*/ - -static const struct hc_driver ohci_sm501_hc_driver = { - .description = hcd_name, - .product_desc = "SM501 OHCI", - .hcd_priv_size = sizeof(struct ohci_hcd), - - /* - * generic hardware linkage - */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY | HCD_LOCAL_MEM, - - /* - * basic lifecycle operations - */ - .reset = ohci_sm501_init, - .start = ohci_sm501_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* - * scheduling support - */ - .get_frame_number = ohci_get_frame, - - /* - * root hub support - */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -/*-------------------------------------------------------------------------*/ - -static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev) -{ - const struct hc_driver *driver = &ohci_sm501_hc_driver; - struct device *dev = &pdev->dev; - struct resource *res, *mem; - int retval, irq; - struct usb_hcd *hcd = NULL; - - irq = retval = platform_get_irq(pdev, 0); - if (retval < 0) - goto err0; - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (mem == NULL) { - dev_err(dev, "no resource definition for memory\n"); - retval = -ENOENT; - goto err0; - } - - if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) { - dev_err(dev, "request_mem_region failed\n"); - retval = -EBUSY; - goto err0; - } - - /* The sm501 chip is equipped with local memory that may be used - * by on-chip devices such as the video controller and the usb host. - * This driver uses dma_declare_coherent_memory() to make sure - * usb allocations with dma_alloc_coherent() allocate from - * this local memory. The dma_handle returned by dma_alloc_coherent() - * will be an offset starting from 0 for the first local memory byte. - * - * So as long as data is allocated using dma_alloc_coherent() all is - * fine. This is however not always the case - buffers may be allocated - * using kmalloc() - so the usb core needs to be told that it must copy - * data into our local memory if the buffers happen to be placed in - * regular memory. The HCD_LOCAL_MEM flag does just that. - */ - - if (!dma_declare_coherent_memory(dev, mem->start, - mem->start - mem->parent->start, - resource_size(mem), - DMA_MEMORY_MAP | - DMA_MEMORY_EXCLUSIVE)) { - dev_err(dev, "cannot declare coherent memory\n"); - retval = -ENXIO; - goto err1; - } - - /* allocate, reserve and remap resources for registers */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(dev, "no resource definition for registers\n"); - retval = -ENOENT; - goto err2; - } - - hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - retval = -ENOMEM; - goto err2; - } - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, pdev->name)) { - dev_err(dev, "request_mem_region failed\n"); - retval = -EBUSY; - goto err3; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (hcd->regs == NULL) { - dev_err(dev, "cannot remap registers\n"); - retval = -ENXIO; - goto err4; - } - - ohci_hcd_init(hcd_to_ohci(hcd)); - - retval = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (retval) - goto err5; - - /* enable power and unmask interrupts */ - - sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 1); - sm501_modify_reg(dev->parent, SM501_IRQ_MASK, 1 << 6, 0); - - return 0; -err5: - iounmap(hcd->regs); -err4: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err3: - usb_put_hcd(hcd); -err2: - dma_release_declared_memory(dev); -err1: - release_mem_region(mem->start, resource_size(mem)); -err0: - return retval; -} - -static int ohci_hcd_sm501_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct resource *mem; - - usb_remove_hcd(hcd); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - dma_release_declared_memory(&pdev->dev); - mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (mem) - release_mem_region(mem->start, resource_size(mem)); - - /* mask interrupts and disable power */ - - sm501_modify_reg(pdev->dev.parent, SM501_IRQ_MASK, 0, 1 << 6); - sm501_unit_power(pdev->dev.parent, SM501_GATE_USB_HOST, 0); - - platform_set_drvdata(pdev, NULL); - return 0; -} - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_PM -static int ohci_sm501_suspend(struct platform_device *pdev, pm_message_t msg) -{ - struct device *dev = &pdev->dev; - struct ohci_hcd *ohci = hcd_to_ohci(platform_get_drvdata(pdev)); - - if (time_before(jiffies, ohci->next_statechange)) - msleep(5); - ohci->next_statechange = jiffies; - - sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 0); - return 0; -} - -static int ohci_sm501_resume(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - - if (time_before(jiffies, ohci->next_statechange)) - msleep(5); - ohci->next_statechange = jiffies; - - sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 1); - ohci_finish_controller_resume(hcd); - return 0; -} -#else -#define ohci_sm501_suspend NULL -#define ohci_sm501_resume NULL -#endif - -/*-------------------------------------------------------------------------*/ - -/* - * Driver definition to register with the SM501 bus - */ -static struct platform_driver ohci_hcd_sm501_driver = { - .probe = ohci_hcd_sm501_drv_probe, - .remove = ohci_hcd_sm501_drv_remove, - .shutdown = usb_hcd_platform_shutdown, - .suspend = ohci_sm501_suspend, - .resume = ohci_sm501_resume, - .driver = { - .owner = THIS_MODULE, - .name = "sm501-usb", - }, -}; -MODULE_ALIAS("platform:sm501-usb"); diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-spear.c b/ANDROID_3.4.5/drivers/usb/host/ohci-spear.c deleted file mode 100644 index 95c16489..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-spear.c +++ /dev/null @@ -1,239 +0,0 @@ -/* -* OHCI HCD (Host Controller Driver) for USB. -* -* Copyright (C) 2010 ST Microelectronics. -* Deepak Sikri -* -* Based on various ohci-*.c drivers -* -* This file is licensed under the terms of the GNU General Public -* License version 2. This program is licensed "as is" without any -* warranty of any kind, whether express or implied. -*/ - -#include -#include -#include - -struct spear_ohci { - struct ohci_hcd ohci; - struct clk *clk; -}; - -#define to_spear_ohci(hcd) (struct spear_ohci *)hcd_to_ohci(hcd) - -static void spear_start_ohci(struct spear_ohci *ohci) -{ - clk_enable(ohci->clk); -} - -static void spear_stop_ohci(struct spear_ohci *ohci) -{ - clk_disable(ohci->clk); -} - -static int __devinit ohci_spear_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - ret = ohci_init(ohci); - if (ret < 0) - return ret; - ohci->regs = hcd->regs; - - ret = ohci_run(ohci); - if (ret < 0) { - dev_err(hcd->self.controller, "can't start\n"); - ohci_stop(hcd); - return ret; - } - - create_debug_files(ohci); - -#ifdef DEBUG - ohci_dump(ohci, 1); -#endif - return 0; -} - -static const struct hc_driver ohci_spear_hc_driver = { - .description = hcd_name, - .product_desc = "SPEAr OHCI", - .hcd_priv_size = sizeof(struct spear_ohci), - - /* generic hardware linkage */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* basic lifecycle operations */ - .start = ohci_spear_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - - /* managing i/o requests and associated device resources */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* scheduling support */ - .get_frame_number = ohci_get_frame, - - /* root hub support */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, - - .start_port_reset = ohci_start_port_reset, -}; - -static int spear_ohci_hcd_drv_probe(struct platform_device *pdev) -{ - const struct hc_driver *driver = &ohci_spear_hc_driver; - struct usb_hcd *hcd = NULL; - struct clk *usbh_clk; - struct spear_ohci *ohci_p; - struct resource *res; - int retval, irq; - int *pdata = pdev->dev.platform_data; - char clk_name[20] = "usbh_clk"; - - if (pdata == NULL) - return -EFAULT; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - retval = irq; - goto fail_irq_get; - } - - if (*pdata >= 0) - sprintf(clk_name, "usbh.%01d_clk", *pdata); - - usbh_clk = clk_get(NULL, clk_name); - if (IS_ERR(usbh_clk)) { - dev_err(&pdev->dev, "Error getting interface clock\n"); - retval = PTR_ERR(usbh_clk); - goto fail_get_usbh_clk; - } - - hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - retval = -ENOMEM; - goto fail_create_hcd; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - retval = -ENODEV; - goto fail_request_resource; - } - - hcd->rsrc_start = pdev->resource[0].start; - hcd->rsrc_len = resource_size(res); - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - dev_dbg(&pdev->dev, "request_mem_region failed\n"); - retval = -EBUSY; - goto fail_request_resource; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - dev_dbg(&pdev->dev, "ioremap failed\n"); - retval = -ENOMEM; - goto fail_ioremap; - } - - ohci_p = (struct spear_ohci *)hcd_to_ohci(hcd); - ohci_p->clk = usbh_clk; - spear_start_ohci(ohci_p); - ohci_hcd_init(hcd_to_ohci(hcd)); - - retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), 0); - if (retval == 0) - return retval; - - spear_stop_ohci(ohci_p); - iounmap(hcd->regs); -fail_ioremap: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -fail_request_resource: - usb_put_hcd(hcd); -fail_create_hcd: - clk_put(usbh_clk); -fail_get_usbh_clk: -fail_irq_get: - dev_err(&pdev->dev, "init fail, %d\n", retval); - - return retval; -} - -static int spear_ohci_hcd_drv_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct spear_ohci *ohci_p = to_spear_ohci(hcd); - - usb_remove_hcd(hcd); - if (ohci_p->clk) - spear_stop_ohci(ohci_p); - - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - - if (ohci_p->clk) - clk_put(ohci_p->clk); - platform_set_drvdata(pdev, NULL); - return 0; -} - -#if defined(CONFIG_PM) -static int spear_ohci_hcd_drv_suspend(struct platform_device *dev, - pm_message_t message) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - struct spear_ohci *ohci_p = to_spear_ohci(hcd); - - if (time_before(jiffies, ohci->next_statechange)) - msleep(5); - ohci->next_statechange = jiffies; - - spear_stop_ohci(ohci_p); - return 0; -} - -static int spear_ohci_hcd_drv_resume(struct platform_device *dev) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - struct spear_ohci *ohci_p = to_spear_ohci(hcd); - - if (time_before(jiffies, ohci->next_statechange)) - msleep(5); - ohci->next_statechange = jiffies; - - spear_start_ohci(ohci_p); - ohci_finish_controller_resume(hcd); - return 0; -} -#endif - -/* Driver definition to register with the platform bus */ -static struct platform_driver spear_ohci_hcd_driver = { - .probe = spear_ohci_hcd_drv_probe, - .remove = spear_ohci_hcd_drv_remove, -#ifdef CONFIG_PM - .suspend = spear_ohci_hcd_drv_suspend, - .resume = spear_ohci_hcd_drv_resume, -#endif - .driver = { - .owner = THIS_MODULE, - .name = "spear-ohci", - }, -}; - -MODULE_ALIAS("platform:spear-ohci"); diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-ssb.c b/ANDROID_3.4.5/drivers/usb/host/ohci-ssb.c deleted file mode 100644 index 5ba18595..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-ssb.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Sonics Silicon Backplane - * Broadcom USB-core OHCI driver - * - * Copyright 2007 Michael Buesch - * - * Derived from the OHCI-PCI driver - * Copyright 1999 Roman Weissgaerber - * Copyright 2000-2002 David Brownell - * Copyright 1999 Linus Torvalds - * Copyright 1999 Gregory P. Smith - * - * Derived from the USBcore related parts of Broadcom-SB - * Copyright 2005 Broadcom Corporation - * - * Licensed under the GNU/GPL. See COPYING for details. - */ -#include - - -#define SSB_OHCI_TMSLOW_HOSTMODE (1 << 29) - -struct ssb_ohci_device { - struct ohci_hcd ohci; /* _must_ be at the beginning. */ - - u32 enable_flags; -}; - -static inline -struct ssb_ohci_device *hcd_to_ssb_ohci(struct usb_hcd *hcd) -{ - return (struct ssb_ohci_device *)(hcd->hcd_priv); -} - - -static int ssb_ohci_reset(struct usb_hcd *hcd) -{ - struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); - struct ohci_hcd *ohci = &ohcidev->ohci; - int err; - - ohci_hcd_init(ohci); - err = ohci_init(ohci); - - return err; -} - -static int ssb_ohci_start(struct usb_hcd *hcd) -{ - struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); - struct ohci_hcd *ohci = &ohcidev->ohci; - int err; - - err = ohci_run(ohci); - if (err < 0) { - ohci_err(ohci, "can't start\n"); - ohci_stop(hcd); - } - - return err; -} - -static const struct hc_driver ssb_ohci_hc_driver = { - .description = "ssb-usb-ohci", - .product_desc = "SSB OHCI Controller", - .hcd_priv_size = sizeof(struct ssb_ohci_device), - - .irq = ohci_irq, - .flags = HCD_MEMORY | HCD_USB11, - - .reset = ssb_ohci_reset, - .start = ssb_ohci_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - .get_frame_number = ohci_get_frame, - - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - - .start_port_reset = ohci_start_port_reset, -}; - -static void ssb_ohci_detach(struct ssb_device *dev) -{ - struct usb_hcd *hcd = ssb_get_drvdata(dev); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - ssb_device_disable(dev, 0); -} - -static int ssb_ohci_attach(struct ssb_device *dev) -{ - struct ssb_ohci_device *ohcidev; - struct usb_hcd *hcd; - int err = -ENOMEM; - u32 tmp, flags = 0; - - if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) || - dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32))) - return -EOPNOTSUPP; - - if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) { - /* Put the device into host-mode. */ - flags |= SSB_OHCI_TMSLOW_HOSTMODE; - ssb_device_enable(dev, flags); - } else if (dev->id.coreid == SSB_DEV_USB20_HOST) { - /* - * USB 2.0 special considerations: - * - * In addition to the standard SSB reset sequence, the Host - * Control Register must be programmed to bring the USB core - * and various phy components out of reset. - */ - ssb_device_enable(dev, 0); - ssb_write32(dev, 0x200, 0x7ff); - - /* Change Flush control reg */ - tmp = ssb_read32(dev, 0x400); - tmp &= ~8; - ssb_write32(dev, 0x400, tmp); - tmp = ssb_read32(dev, 0x400); - - /* Change Shim control reg */ - tmp = ssb_read32(dev, 0x304); - tmp &= ~0x100; - ssb_write32(dev, 0x304, tmp); - tmp = ssb_read32(dev, 0x304); - - udelay(1); - - /* Work around for 5354 failures */ - if (dev->id.revision == 2 && dev->bus->chip_id == 0x5354) { - /* Change syn01 reg */ - tmp = 0x00fe00fe; - ssb_write32(dev, 0x894, tmp); - - /* Change syn03 reg */ - tmp = ssb_read32(dev, 0x89c); - tmp |= 0x1; - ssb_write32(dev, 0x89c, tmp); - } - } else - ssb_device_enable(dev, 0); - - hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev, - dev_name(dev->dev)); - if (!hcd) - goto err_dev_disable; - ohcidev = hcd_to_ssb_ohci(hcd); - ohcidev->enable_flags = flags; - - tmp = ssb_read32(dev, SSB_ADMATCH0); - hcd->rsrc_start = ssb_admatch_base(tmp); - hcd->rsrc_len = ssb_admatch_size(tmp); - hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) - goto err_put_hcd; - err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED); - if (err) - goto err_iounmap; - - ssb_set_drvdata(dev, hcd); - - return err; - -err_iounmap: - iounmap(hcd->regs); -err_put_hcd: - usb_put_hcd(hcd); -err_dev_disable: - ssb_device_disable(dev, flags); - return err; -} - -static int ssb_ohci_probe(struct ssb_device *dev, - const struct ssb_device_id *id) -{ - int err; - u16 chipid_top; - - /* USBcores are only connected on embedded devices. */ - chipid_top = (dev->bus->chip_id & 0xFF00); - if (chipid_top != 0x4700 && chipid_top != 0x5300) - return -ENODEV; - - /* TODO: Probably need checks here; is the core connected? */ - - if (usb_disabled()) - return -ENODEV; - - /* We currently always attach SSB_DEV_USB11_HOSTDEV - * as HOST OHCI. If we want to attach it as Client device, - * we must branch here and call into the (yet to - * be written) Client mode driver. Same for remove(). */ - - err = ssb_ohci_attach(dev); - - return err; -} - -static void ssb_ohci_remove(struct ssb_device *dev) -{ - ssb_ohci_detach(dev); -} - -#ifdef CONFIG_PM - -static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state) -{ - ssb_device_disable(dev, 0); - - return 0; -} - -static int ssb_ohci_resume(struct ssb_device *dev) -{ - struct usb_hcd *hcd = ssb_get_drvdata(dev); - struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); - - ssb_device_enable(dev, ohcidev->enable_flags); - - ohci_finish_controller_resume(hcd); - return 0; -} - -#else /* !CONFIG_PM */ -#define ssb_ohci_suspend NULL -#define ssb_ohci_resume NULL -#endif /* CONFIG_PM */ - -static const struct ssb_device_id ssb_ohci_table[] = { - SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV), - SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV), - SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV), - SSB_DEVTABLE_END -}; -MODULE_DEVICE_TABLE(ssb, ssb_ohci_table); - -static struct ssb_driver ssb_ohci_driver = { - .name = KBUILD_MODNAME, - .id_table = ssb_ohci_table, - .probe = ssb_ohci_probe, - .remove = ssb_ohci_remove, - .suspend = ssb_ohci_suspend, - .resume = ssb_ohci_resume, -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-tmio.c b/ANDROID_3.4.5/drivers/usb/host/ohci-tmio.c deleted file mode 100644 index 120bfe6e..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-tmio.c +++ /dev/null @@ -1,373 +0,0 @@ -/* - * OHCI HCD(Host Controller Driver) for USB. - * - *(C) Copyright 1999 Roman Weissgaerber - *(C) Copyright 2000-2002 David Brownell - *(C) Copyright 2002 Hewlett-Packard Company - * - * Bus glue for Toshiba Mobile IO(TMIO) Controller's OHCI core - * (C) Copyright 2005 Chris Humbert - * (C) Copyright 2007, 2008 Dmitry Baryshkov - * - * This is known to work with the following variants: - * TC6393XB revision 3 (32kB SRAM) - * - * The TMIO's OHCI core DMAs through a small internal buffer that - * is directly addressable by the CPU. - * - * Written from sparse documentation from Toshiba and Sharp's driver - * for the 2.4 kernel, - * usb-ohci-tc6393.c(C) Copyright 2004 Lineo Solutions, Inc. - * - * 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. - */ - -/*#include -#include -#include -#include -#include -#include */ -#include -#include -#include -#include - -/*-------------------------------------------------------------------------*/ - -/* - * USB Host Controller Configuration Register - */ -#define CCR_REVID 0x08 /* b Revision ID */ -#define CCR_BASE 0x10 /* l USB Control Register Base Address Low */ -#define CCR_ILME 0x40 /* b Internal Local Memory Enable */ -#define CCR_PM 0x4c /* w Power Management */ -#define CCR_INTC 0x50 /* b INT Control */ -#define CCR_LMW1L 0x54 /* w Local Memory Window 1 LMADRS Low */ -#define CCR_LMW1H 0x56 /* w Local Memory Window 1 LMADRS High */ -#define CCR_LMW1BL 0x58 /* w Local Memory Window 1 Base Address Low */ -#define CCR_LMW1BH 0x5A /* w Local Memory Window 1 Base Address High */ -#define CCR_LMW2L 0x5C /* w Local Memory Window 2 LMADRS Low */ -#define CCR_LMW2H 0x5E /* w Local Memory Window 2 LMADRS High */ -#define CCR_LMW2BL 0x60 /* w Local Memory Window 2 Base Address Low */ -#define CCR_LMW2BH 0x62 /* w Local Memory Window 2 Base Address High */ -#define CCR_MISC 0xFC /* b MISC */ - -#define CCR_PM_GKEN 0x0001 -#define CCR_PM_CKRNEN 0x0002 -#define CCR_PM_USBPW1 0x0004 -#define CCR_PM_USBPW2 0x0008 -#define CCR_PM_USBPW3 0x0008 -#define CCR_PM_PMEE 0x0100 -#define CCR_PM_PMES 0x8000 - -/*-------------------------------------------------------------------------*/ - -struct tmio_hcd { - void __iomem *ccr; - spinlock_t lock; /* protects RMW cycles */ -}; - -#define hcd_to_tmio(hcd) ((struct tmio_hcd *)(hcd_to_ohci(hcd) + 1)) - -/*-------------------------------------------------------------------------*/ - -static void tmio_write_pm(struct platform_device *dev) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - struct tmio_hcd *tmio = hcd_to_tmio(hcd); - u16 pm; - unsigned long flags; - - spin_lock_irqsave(&tmio->lock, flags); - - pm = CCR_PM_GKEN | CCR_PM_CKRNEN | - CCR_PM_PMEE | CCR_PM_PMES; - - tmio_iowrite16(pm, tmio->ccr + CCR_PM); - spin_unlock_irqrestore(&tmio->lock, flags); -} - -static void tmio_stop_hc(struct platform_device *dev) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - struct tmio_hcd *tmio = hcd_to_tmio(hcd); - u16 pm; - - pm = CCR_PM_GKEN | CCR_PM_CKRNEN; - switch (ohci->num_ports) { - default: - dev_err(&dev->dev, "Unsupported amount of ports: %d\n", ohci->num_ports); - case 3: - pm |= CCR_PM_USBPW3; - case 2: - pm |= CCR_PM_USBPW2; - case 1: - pm |= CCR_PM_USBPW1; - } - tmio_iowrite8(0, tmio->ccr + CCR_INTC); - tmio_iowrite8(0, tmio->ccr + CCR_ILME); - tmio_iowrite16(0, tmio->ccr + CCR_BASE); - tmio_iowrite16(0, tmio->ccr + CCR_BASE + 2); - tmio_iowrite16(pm, tmio->ccr + CCR_PM); -} - -static void tmio_start_hc(struct platform_device *dev) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - struct tmio_hcd *tmio = hcd_to_tmio(hcd); - unsigned long base = hcd->rsrc_start; - - tmio_write_pm(dev); - tmio_iowrite16(base, tmio->ccr + CCR_BASE); - tmio_iowrite16(base >> 16, tmio->ccr + CCR_BASE + 2); - tmio_iowrite8(1, tmio->ccr + CCR_ILME); - tmio_iowrite8(2, tmio->ccr + CCR_INTC); - - dev_info(&dev->dev, "revision %d @ 0x%08llx, irq %d\n", - tmio_ioread8(tmio->ccr + CCR_REVID), hcd->rsrc_start, hcd->irq); -} - -static int ohci_tmio_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - int ret; - - if ((ret = ohci_init(ohci)) < 0) - return ret; - - if ((ret = ohci_run(ohci)) < 0) { - err("can't start %s", hcd->self.bus_name); - ohci_stop(hcd); - return ret; - } - - return 0; -} - -static const struct hc_driver ohci_tmio_hc_driver = { - .description = hcd_name, - .product_desc = "TMIO OHCI USB Host Controller", - .hcd_priv_size = sizeof(struct ohci_hcd) + sizeof (struct tmio_hcd), - - /* generic hardware linkage */ - .irq = ohci_irq, - .flags = HCD_USB11 | HCD_MEMORY | HCD_LOCAL_MEM, - - /* basic lifecycle operations */ - .start = ohci_tmio_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - /* managing i/o requests and associated device resources */ - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - /* scheduling support */ - .get_frame_number = ohci_get_frame, - - /* root hub support */ - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -/*-------------------------------------------------------------------------*/ -static struct platform_driver ohci_hcd_tmio_driver; - -static int __devinit ohci_hcd_tmio_drv_probe(struct platform_device *dev) -{ - const struct mfd_cell *cell = mfd_get_cell(dev); - struct resource *regs = platform_get_resource(dev, IORESOURCE_MEM, 0); - struct resource *config = platform_get_resource(dev, IORESOURCE_MEM, 1); - struct resource *sram = platform_get_resource(dev, IORESOURCE_MEM, 2); - int irq = platform_get_irq(dev, 0); - struct tmio_hcd *tmio; - struct ohci_hcd *ohci; - struct usb_hcd *hcd; - int ret; - - if (usb_disabled()) - return -ENODEV; - - if (!cell) - return -EINVAL; - - hcd = usb_create_hcd(&ohci_tmio_hc_driver, &dev->dev, dev_name(&dev->dev)); - if (!hcd) { - ret = -ENOMEM; - goto err_usb_create_hcd; - } - - hcd->rsrc_start = regs->start; - hcd->rsrc_len = resource_size(regs); - - tmio = hcd_to_tmio(hcd); - - spin_lock_init(&tmio->lock); - - tmio->ccr = ioremap(config->start, resource_size(config)); - if (!tmio->ccr) { - ret = -ENOMEM; - goto err_ioremap_ccr; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - ret = -ENOMEM; - goto err_ioremap_regs; - } - - if (!dma_declare_coherent_memory(&dev->dev, sram->start, - sram->start, - resource_size(sram), - DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE)) { - ret = -EBUSY; - goto err_dma_declare; - } - - if (cell->enable) { - ret = cell->enable(dev); - if (ret) - goto err_enable; - } - - tmio_start_hc(dev); - ohci = hcd_to_ohci(hcd); - ohci_hcd_init(ohci); - - ret = usb_add_hcd(hcd, irq, 0); - if (ret) - goto err_add_hcd; - - if (ret == 0) - return ret; - - usb_remove_hcd(hcd); - -err_add_hcd: - tmio_stop_hc(dev); - if (cell->disable) - cell->disable(dev); -err_enable: - dma_release_declared_memory(&dev->dev); -err_dma_declare: - iounmap(hcd->regs); -err_ioremap_regs: - iounmap(tmio->ccr); -err_ioremap_ccr: - usb_put_hcd(hcd); -err_usb_create_hcd: - - return ret; -} - -static int __devexit ohci_hcd_tmio_drv_remove(struct platform_device *dev) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - struct tmio_hcd *tmio = hcd_to_tmio(hcd); - const struct mfd_cell *cell = mfd_get_cell(dev); - - usb_remove_hcd(hcd); - tmio_stop_hc(dev); - if (cell->disable) - cell->disable(dev); - dma_release_declared_memory(&dev->dev); - iounmap(hcd->regs); - iounmap(tmio->ccr); - usb_put_hcd(hcd); - - platform_set_drvdata(dev, NULL); - - return 0; -} - -#ifdef CONFIG_PM -static int ohci_hcd_tmio_drv_suspend(struct platform_device *dev, pm_message_t state) -{ - const struct mfd_cell *cell = mfd_get_cell(dev); - struct usb_hcd *hcd = platform_get_drvdata(dev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - struct tmio_hcd *tmio = hcd_to_tmio(hcd); - unsigned long flags; - u8 misc; - int ret; - - if (time_before(jiffies, ohci->next_statechange)) - msleep(5); - ohci->next_statechange = jiffies; - - spin_lock_irqsave(&tmio->lock, flags); - - misc = tmio_ioread8(tmio->ccr + CCR_MISC); - misc |= 1 << 3; /* USSUSP */ - tmio_iowrite8(misc, tmio->ccr + CCR_MISC); - - spin_unlock_irqrestore(&tmio->lock, flags); - - if (cell->suspend) { - ret = cell->suspend(dev); - if (ret) - return ret; - } - return 0; -} - -static int ohci_hcd_tmio_drv_resume(struct platform_device *dev) -{ - const struct mfd_cell *cell = mfd_get_cell(dev); - struct usb_hcd *hcd = platform_get_drvdata(dev); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - struct tmio_hcd *tmio = hcd_to_tmio(hcd); - unsigned long flags; - u8 misc; - int ret; - - if (time_before(jiffies, ohci->next_statechange)) - msleep(5); - ohci->next_statechange = jiffies; - - if (cell->resume) { - ret = cell->resume(dev); - if (ret) - return ret; - } - - tmio_start_hc(dev); - - spin_lock_irqsave(&tmio->lock, flags); - - misc = tmio_ioread8(tmio->ccr + CCR_MISC); - misc &= ~(1 << 3); /* USSUSP */ - tmio_iowrite8(misc, tmio->ccr + CCR_MISC); - - spin_unlock_irqrestore(&tmio->lock, flags); - - ohci_finish_controller_resume(hcd); - - return 0; -} -#else -#define ohci_hcd_tmio_drv_suspend NULL -#define ohci_hcd_tmio_drv_resume NULL -#endif - -static struct platform_driver ohci_hcd_tmio_driver = { - .probe = ohci_hcd_tmio_drv_probe, - .remove = __devexit_p(ohci_hcd_tmio_drv_remove), - .shutdown = usb_hcd_platform_shutdown, - .suspend = ohci_hcd_tmio_drv_suspend, - .resume = ohci_hcd_tmio_drv_resume, - .driver = { - .name = "tmio-ohci", - .owner = THIS_MODULE, - }, -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci-xls.c b/ANDROID_3.4.5/drivers/usb/host/ohci-xls.c deleted file mode 100644 index a2247867..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci-xls.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * OHCI HCD for Netlogic XLS processors. - * - * (C) Copyright 2011 Netlogic Microsystems Inc. - * - * Based on ohci-au1xxx.c, and other Linux OHCI drivers. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - */ - -#include -#include - -static int ohci_xls_probe_internal(const struct hc_driver *driver, - struct platform_device *dev) -{ - struct resource *res; - struct usb_hcd *hcd; - int retval, irq; - - /* Get our IRQ from an earlier registered Platform Resource */ - irq = platform_get_irq(dev, 0); - if (irq < 0) { - dev_err(&dev->dev, "Found HC with no IRQ\n"); - return -ENODEV; - } - - /* Get our Memory Handle */ - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&dev->dev, "MMIO Handle incorrect!\n"); - return -ENODEV; - } - - hcd = usb_create_hcd(driver, &dev->dev, "XLS"); - if (!hcd) { - retval = -ENOMEM; - goto err1; - } - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) { - dev_dbg(&dev->dev, "Controller already in use\n"); - retval = -EBUSY; - goto err2; - } - - hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); - if (hcd->regs == NULL) { - dev_dbg(&dev->dev, "error mapping memory\n"); - retval = -EFAULT; - goto err3; - } - - retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); - if (retval != 0) - goto err4; - return retval; - -err4: - iounmap(hcd->regs); -err3: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err2: - usb_put_hcd(hcd); -err1: - dev_err(&dev->dev, "init fail, %d\n", retval); - return retval; -} - -static int ohci_xls_reset(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - - ohci_hcd_init(ohci); - return ohci_init(ohci); -} - -static int __devinit ohci_xls_start(struct usb_hcd *hcd) -{ - struct ohci_hcd *ohci; - int ret; - - ohci = hcd_to_ohci(hcd); - ret = ohci_run(ohci); - if (ret < 0) { - err("can't start %s", hcd->self.bus_name); - ohci_stop(hcd); - return ret; - } - return 0; -} - -static struct hc_driver ohci_xls_hc_driver = { - .description = hcd_name, - .product_desc = "XLS OHCI Host Controller", - .hcd_priv_size = sizeof(struct ohci_hcd), - .irq = ohci_irq, - .flags = HCD_MEMORY | HCD_USB11, - .reset = ohci_xls_reset, - .start = ohci_xls_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - .get_frame_number = ohci_get_frame, - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - .start_port_reset = ohci_start_port_reset, -}; - -static int ohci_xls_probe(struct platform_device *dev) -{ - int ret; - - pr_debug("In ohci_xls_probe"); - if (usb_disabled()) - return -ENODEV; - ret = ohci_xls_probe_internal(&ohci_xls_hc_driver, dev); - return ret; -} - -static int ohci_xls_remove(struct platform_device *dev) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - return 0; -} - -static struct platform_driver ohci_xls_driver = { - .probe = ohci_xls_probe, - .remove = ohci_xls_remove, - .shutdown = usb_hcd_platform_shutdown, - .driver = { - .name = "ohci-xls-0", - .owner = THIS_MODULE, - }, -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/ohci.h b/ANDROID_3.4.5/drivers/usb/host/ohci.h deleted file mode 100644 index 1b19aea2..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/ohci.h +++ /dev/null @@ -1,725 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2002 David Brownell - * - * This file is licenced under the GPL. - */ - -/* - * __hc32 and __hc16 are "Host Controller" types, they may be equivalent to - * __leXX (normally) or __beXX (given OHCI_BIG_ENDIAN), depending on the - * host controller implementation. - */ -typedef __u32 __bitwise __hc32; -typedef __u16 __bitwise __hc16; - -/* - * OHCI Endpoint Descriptor (ED) ... holds TD queue - * See OHCI spec, section 4.2 - * - * This is a "Queue Head" for those transfers, which is why - * both EHCI and UHCI call similar structures a "QH". - */ -struct ed { - /* first fields are hardware-specified */ - __hc32 hwINFO; /* endpoint config bitmap */ - /* info bits defined by hcd */ -#define ED_DEQUEUE (1 << 27) - /* info bits defined by the hardware */ -#define ED_ISO (1 << 15) -#define ED_SKIP (1 << 14) -#define ED_LOWSPEED (1 << 13) -#define ED_OUT (0x01 << 11) -#define ED_IN (0x02 << 11) - __hc32 hwTailP; /* tail of TD list */ - __hc32 hwHeadP; /* head of TD list (hc r/w) */ -#define ED_C (0x02) /* toggle carry */ -#define ED_H (0x01) /* halted */ - __hc32 hwNextED; /* next ED in list */ - - /* rest are purely for the driver's use */ - dma_addr_t dma; /* addr of ED */ - struct td *dummy; /* next TD to activate */ - - /* host's view of schedule */ - struct ed *ed_next; /* on schedule or rm_list */ - struct ed *ed_prev; /* for non-interrupt EDs */ - struct list_head td_list; /* "shadow list" of our TDs */ - - /* create --> IDLE --> OPER --> ... --> IDLE --> destroy - * usually: OPER --> UNLINK --> (IDLE | OPER) --> ... - */ - u8 state; /* ED_{IDLE,UNLINK,OPER} */ -#define ED_IDLE 0x00 /* NOT linked to HC */ -#define ED_UNLINK 0x01 /* being unlinked from hc */ -#define ED_OPER 0x02 /* IS linked to hc */ - - u8 type; /* PIPE_{BULK,...} */ - - /* periodic scheduling params (for intr and iso) */ - u8 branch; - u16 interval; - u16 load; - u16 last_iso; /* iso only */ - - /* HC may see EDs on rm_list until next frame (frame_no == tick) */ - u16 tick; -} __attribute__ ((aligned(16))); - -#define ED_MASK ((u32)~0x0f) /* strip hw status in low addr bits */ - - -/* - * OHCI Transfer Descriptor (TD) ... one per transfer segment - * See OHCI spec, sections 4.3.1 (general = control/bulk/interrupt) - * and 4.3.2 (iso) - */ -struct td { - /* first fields are hardware-specified */ - __hc32 hwINFO; /* transfer info bitmask */ - - /* hwINFO bits for both general and iso tds: */ -#define TD_CC 0xf0000000 /* condition code */ -#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f) -//#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28) -#define TD_DI 0x00E00000 /* frames before interrupt */ -#define TD_DI_SET(X) (((X) & 0x07)<< 21) - /* these two bits are available for definition/use by HCDs in both - * general and iso tds ... others are available for only one type - */ -#define TD_DONE 0x00020000 /* retired to donelist */ -#define TD_ISO 0x00010000 /* copy of ED_ISO */ - - /* hwINFO bits for general tds: */ -#define TD_EC 0x0C000000 /* error count */ -#define TD_T 0x03000000 /* data toggle state */ -#define TD_T_DATA0 0x02000000 /* DATA0 */ -#define TD_T_DATA1 0x03000000 /* DATA1 */ -#define TD_T_TOGGLE 0x00000000 /* uses ED_C */ -#define TD_DP 0x00180000 /* direction/pid */ -#define TD_DP_SETUP 0x00000000 /* SETUP pid */ -#define TD_DP_IN 0x00100000 /* IN pid */ -#define TD_DP_OUT 0x00080000 /* OUT pid */ - /* 0x00180000 rsvd */ -#define TD_R 0x00040000 /* round: short packets OK? */ - - /* (no hwINFO #defines yet for iso tds) */ - - __hc32 hwCBP; /* Current Buffer Pointer (or 0) */ - __hc32 hwNextTD; /* Next TD Pointer */ - __hc32 hwBE; /* Memory Buffer End Pointer */ - - /* PSW is only for ISO. Only 1 PSW entry is used, but on - * big-endian PPC hardware that's the second entry. - */ -#define MAXPSW 2 - __hc16 hwPSW [MAXPSW]; - - /* rest are purely for the driver's use */ - __u8 index; - struct ed *ed; - struct td *td_hash; /* dma-->td hashtable */ - struct td *next_dl_td; - struct urb *urb; - - dma_addr_t td_dma; /* addr of this TD */ - dma_addr_t data_dma; /* addr of data it points to */ - - struct list_head td_list; /* "shadow list", TDs on same ED */ -} __attribute__ ((aligned(32))); /* c/b/i need 16; only iso needs 32 */ - -#define TD_MASK ((u32)~0x1f) /* strip hw status in low addr bits */ - -/* - * Hardware transfer status codes -- CC from td->hwINFO or td->hwPSW - */ -#define TD_CC_NOERROR 0x00 -#define TD_CC_CRC 0x01 -#define TD_CC_BITSTUFFING 0x02 -#define TD_CC_DATATOGGLEM 0x03 -#define TD_CC_STALL 0x04 -#define TD_DEVNOTRESP 0x05 -#define TD_PIDCHECKFAIL 0x06 -#define TD_UNEXPECTEDPID 0x07 -#define TD_DATAOVERRUN 0x08 -#define TD_DATAUNDERRUN 0x09 - /* 0x0A, 0x0B reserved for hardware */ -#define TD_BUFFEROVERRUN 0x0C -#define TD_BUFFERUNDERRUN 0x0D - /* 0x0E, 0x0F reserved for HCD */ -#define TD_NOTACCESSED 0x0F - - -/* map OHCI TD status codes (CC) to errno values */ -static const int cc_to_error [16] = { - /* No Error */ 0, - /* CRC Error */ -EILSEQ, - /* Bit Stuff */ -EPROTO, - /* Data Togg */ -EILSEQ, - /* Stall */ -EPIPE, - /* DevNotResp */ -ETIME, - /* PIDCheck */ -EPROTO, - /* UnExpPID */ -EPROTO, - /* DataOver */ -EOVERFLOW, - /* DataUnder */ -EREMOTEIO, - /* (for hw) */ -EIO, - /* (for hw) */ -EIO, - /* BufferOver */ -ECOMM, - /* BuffUnder */ -ENOSR, - /* (for HCD) */ -EALREADY, - /* (for HCD) */ -EALREADY -}; - - -/* - * The HCCA (Host Controller Communications Area) is a 256 byte - * structure defined section 4.4.1 of the OHCI spec. The HC is - * told the base address of it. It must be 256-byte aligned. - */ -struct ohci_hcca { -#define NUM_INTS 32 - __hc32 int_table [NUM_INTS]; /* periodic schedule */ - - /* - * OHCI defines u16 frame_no, followed by u16 zero pad. - * Since some processors can't do 16 bit bus accesses, - * portable access must be a 32 bits wide. - */ - __hc32 frame_no; /* current frame number */ - __hc32 done_head; /* info returned for an interrupt */ - u8 reserved_for_hc [116]; - u8 what [4]; /* spec only identifies 252 bytes :) */ -} __attribute__ ((aligned(256))); - -/* - * This is the structure of the OHCI controller's memory mapped I/O region. - * You must use readl() and writel() (in ) to access these fields!! - * Layout is in section 7 (and appendix B) of the spec. - */ -struct ohci_regs { - /* control and status registers (section 7.1) */ - __hc32 revision; - __hc32 control; - __hc32 cmdstatus; - __hc32 intrstatus; - __hc32 intrenable; - __hc32 intrdisable; - - /* memory pointers (section 7.2) */ - __hc32 hcca; - __hc32 ed_periodcurrent; - __hc32 ed_controlhead; - __hc32 ed_controlcurrent; - __hc32 ed_bulkhead; - __hc32 ed_bulkcurrent; - __hc32 donehead; - - /* frame counters (section 7.3) */ - __hc32 fminterval; - __hc32 fmremaining; - __hc32 fmnumber; - __hc32 periodicstart; - __hc32 lsthresh; - - /* Root hub ports (section 7.4) */ - struct ohci_roothub_regs { - __hc32 a; - __hc32 b; - __hc32 status; -#define MAX_ROOT_PORTS 15 /* maximum OHCI root hub ports (RH_A_NDP) */ - __hc32 portstatus [MAX_ROOT_PORTS]; - } roothub; - - /* and optional "legacy support" registers (appendix B) at 0x0100 */ - -} __attribute__ ((aligned(32))); - - -/* OHCI CONTROL AND STATUS REGISTER MASKS */ - -/* - * HcControl (control) register masks - */ -#define OHCI_CTRL_CBSR (3 << 0) /* control/bulk service ratio */ -#define OHCI_CTRL_PLE (1 << 2) /* periodic list enable */ -#define OHCI_CTRL_IE (1 << 3) /* isochronous enable */ -#define OHCI_CTRL_CLE (1 << 4) /* control list enable */ -#define OHCI_CTRL_BLE (1 << 5) /* bulk list enable */ -#define OHCI_CTRL_HCFS (3 << 6) /* host controller functional state */ -#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */ -#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ -#define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */ - -/* pre-shifted values for HCFS */ -# define OHCI_USB_RESET (0 << 6) -# define OHCI_USB_RESUME (1 << 6) -# define OHCI_USB_OPER (2 << 6) -# define OHCI_USB_SUSPEND (3 << 6) - -/* - * HcCommandStatus (cmdstatus) register masks - */ -#define OHCI_HCR (1 << 0) /* host controller reset */ -#define OHCI_CLF (1 << 1) /* control list filled */ -#define OHCI_BLF (1 << 2) /* bulk list filled */ -#define OHCI_OCR (1 << 3) /* ownership change request */ -#define OHCI_SOC (3 << 16) /* scheduling overrun count */ - -/* - * masks used with interrupt registers: - * HcInterruptStatus (intrstatus) - * HcInterruptEnable (intrenable) - * HcInterruptDisable (intrdisable) - */ -#define OHCI_INTR_SO (1 << 0) /* scheduling overrun */ -#define OHCI_INTR_WDH (1 << 1) /* writeback of done_head */ -#define OHCI_INTR_SF (1 << 2) /* start frame */ -#define OHCI_INTR_RD (1 << 3) /* resume detect */ -#define OHCI_INTR_UE (1 << 4) /* unrecoverable error */ -#define OHCI_INTR_FNO (1 << 5) /* frame number overflow */ -#define OHCI_INTR_RHSC (1 << 6) /* root hub status change */ -#define OHCI_INTR_OC (1 << 30) /* ownership change */ -#define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */ - - -/* OHCI ROOT HUB REGISTER MASKS */ - -/* roothub.portstatus [i] bits */ -#define RH_PS_CCS 0x00000001 /* current connect status */ -#define RH_PS_PES 0x00000002 /* port enable status*/ -#define RH_PS_PSS 0x00000004 /* port suspend status */ -#define RH_PS_POCI 0x00000008 /* port over current indicator */ -#define RH_PS_PRS 0x00000010 /* port reset status */ -#define RH_PS_PPS 0x00000100 /* port power status */ -#define RH_PS_LSDA 0x00000200 /* low speed device attached */ -#define RH_PS_CSC 0x00010000 /* connect status change */ -#define RH_PS_PESC 0x00020000 /* port enable status change */ -#define RH_PS_PSSC 0x00040000 /* port suspend status change */ -#define RH_PS_OCIC 0x00080000 /* over current indicator change */ -#define RH_PS_PRSC 0x00100000 /* port reset status change */ - -/* roothub.status bits */ -#define RH_HS_LPS 0x00000001 /* local power status */ -#define RH_HS_OCI 0x00000002 /* over current indicator */ -#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */ -#define RH_HS_LPSC 0x00010000 /* local power status change */ -#define RH_HS_OCIC 0x00020000 /* over current indicator change */ -#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */ - -/* roothub.b masks */ -#define RH_B_DR 0x0000ffff /* device removable flags */ -#define RH_B_PPCM 0xffff0000 /* port power control mask */ - -/* roothub.a masks */ -#define RH_A_NDP (0xff << 0) /* number of downstream ports */ -#define RH_A_PSM (1 << 8) /* power switching mode */ -#define RH_A_NPS (1 << 9) /* no power switching */ -#define RH_A_DT (1 << 10) /* device type (mbz) */ -#define RH_A_OCPM (1 << 11) /* over current protection mode */ -#define RH_A_NOCP (1 << 12) /* no over current protection */ -#define RH_A_POTPGT (0xff << 24) /* power on to power good time */ - - -/* hcd-private per-urb state */ -typedef struct urb_priv { - struct ed *ed; - u16 length; // # tds in this request - u16 td_cnt; // tds already serviced - struct list_head pending; - struct td *td [0]; // all TDs in this request - -} urb_priv_t; - -#define TD_HASH_SIZE 64 /* power'o'two */ -// sizeof (struct td) ~= 64 == 2^6 ... -#define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 6)) % TD_HASH_SIZE) - - -/* - * This is the full ohci controller description - * - * Note how the "proper" USB information is just - * a subset of what the full implementation needs. (Linus) - */ - -enum ohci_rh_state { - OHCI_RH_HALTED, - OHCI_RH_SUSPENDED, - OHCI_RH_RUNNING -}; - -struct ohci_hcd { - spinlock_t lock; - - /* - * I/O memory used to communicate with the HC (dma-consistent) - */ - struct ohci_regs __iomem *regs; - - /* - * main memory used to communicate with the HC (dma-consistent). - * hcd adds to schedule for a live hc any time, but removals finish - * only at the start of the next frame. - */ - struct ohci_hcca *hcca; - dma_addr_t hcca_dma; - - struct ed *ed_rm_list; /* to be removed */ - - struct ed *ed_bulktail; /* last in bulk list */ - struct ed *ed_controltail; /* last in ctrl list */ - struct ed *periodic [NUM_INTS]; /* shadow int_table */ - - /* - * OTG controllers and transceivers need software interaction; - * other external transceivers should be software-transparent - */ - struct usb_phy *transceiver; - void (*start_hnp)(struct ohci_hcd *ohci); - - /* - * memory management for queue data structures - */ - struct dma_pool *td_cache; - struct dma_pool *ed_cache; - struct td *td_hash [TD_HASH_SIZE]; - struct list_head pending; - - /* - * driver state - */ - enum ohci_rh_state rh_state; - int num_ports; - int load [NUM_INTS]; - u32 hc_control; /* copy of hc control reg */ - unsigned long next_statechange; /* suspend/resume */ - u32 fminterval; /* saved register */ - unsigned autostop:1; /* rh auto stopping/stopped */ - - unsigned long flags; /* for HC bugs */ -#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */ -#define OHCI_QUIRK_SUPERIO 0x02 /* natsemi */ -#define OHCI_QUIRK_INITRESET 0x04 /* SiS, OPTi, ... */ -#define OHCI_QUIRK_BE_DESC 0x08 /* BE descriptors */ -#define OHCI_QUIRK_BE_MMIO 0x10 /* BE registers */ -#define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/ -#define OHCI_QUIRK_NEC 0x40 /* lost interrupts */ -#define OHCI_QUIRK_FRAME_NO 0x80 /* no big endian frame_no shift */ -#define OHCI_QUIRK_HUB_POWER 0x100 /* distrust firmware power/oc setup */ -#define OHCI_QUIRK_AMD_PLL 0x200 /* AMD PLL quirk*/ -#define OHCI_QUIRK_AMD_PREFETCH 0x400 /* pre-fetch for ISO transfer */ - // there are also chip quirks/bugs in init logic - - struct work_struct nec_work; /* Worker for NEC quirk */ - - /* Needed for ZF Micro quirk */ - struct timer_list unlink_watchdog; - unsigned eds_scheduled; - struct ed *ed_to_check; - unsigned zf_delay; - -#ifdef DEBUG - struct dentry *debug_dir; - struct dentry *debug_async; - struct dentry *debug_periodic; - struct dentry *debug_registers; -#endif -}; - -#ifdef CONFIG_PCI -static inline int quirk_nec(struct ohci_hcd *ohci) -{ - return ohci->flags & OHCI_QUIRK_NEC; -} -static inline int quirk_zfmicro(struct ohci_hcd *ohci) -{ - return ohci->flags & OHCI_QUIRK_ZFMICRO; -} -static inline int quirk_amdiso(struct ohci_hcd *ohci) -{ - return ohci->flags & OHCI_QUIRK_AMD_PLL; -} -static inline int quirk_amdprefetch(struct ohci_hcd *ohci) -{ - return ohci->flags & OHCI_QUIRK_AMD_PREFETCH; -} -#else -static inline int quirk_nec(struct ohci_hcd *ohci) -{ - return 0; -} -static inline int quirk_zfmicro(struct ohci_hcd *ohci) -{ - return 0; -} -static inline int quirk_amdiso(struct ohci_hcd *ohci) -{ - return 0; -} -static inline int quirk_amdprefetch(struct ohci_hcd *ohci) -{ - return 0; -} -#endif - -/* convert between an hcd pointer and the corresponding ohci_hcd */ -static inline struct ohci_hcd *hcd_to_ohci (struct usb_hcd *hcd) -{ - return (struct ohci_hcd *) (hcd->hcd_priv); -} -static inline struct usb_hcd *ohci_to_hcd (const struct ohci_hcd *ohci) -{ - return container_of ((void *) ohci, struct usb_hcd, hcd_priv); -} - -/*-------------------------------------------------------------------------*/ - -#ifndef DEBUG -#define STUB_DEBUG_FILES -#endif /* DEBUG */ - -#define ohci_dbg(ohci, fmt, args...) \ - dev_dbg (ohci_to_hcd(ohci)->self.controller , fmt , ## args ) -#define ohci_err(ohci, fmt, args...) \ - dev_err (ohci_to_hcd(ohci)->self.controller , fmt , ## args ) -#define ohci_info(ohci, fmt, args...) \ - dev_info (ohci_to_hcd(ohci)->self.controller , fmt , ## args ) -#define ohci_warn(ohci, fmt, args...) \ - dev_warn (ohci_to_hcd(ohci)->self.controller , fmt , ## args ) - -#ifdef OHCI_VERBOSE_DEBUG -# define ohci_vdbg ohci_dbg -#else -# define ohci_vdbg(ohci, fmt, args...) do { } while (0) -#endif - -/*-------------------------------------------------------------------------*/ - -/* - * While most USB host controllers implement their registers and - * in-memory communication descriptors in little-endian format, - * a minority (notably the IBM STB04XXX and the Motorola MPC5200 - * processors) implement them in big endian format. - * - * In addition some more exotic implementations like the Toshiba - * Spider (aka SCC) cell southbridge are "mixed" endian, that is, - * they have a different endianness for registers vs. in-memory - * descriptors. - * - * This attempts to support either format at compile time without a - * runtime penalty, or both formats with the additional overhead - * of checking a flag bit. - * - * That leads to some tricky Kconfig rules howevber. There are - * different defaults based on some arch/ppc platforms, though - * the basic rules are: - * - * Controller type Kconfig options needed - * --------------- ---------------------- - * little endian CONFIG_USB_OHCI_LITTLE_ENDIAN - * - * fully big endian CONFIG_USB_OHCI_BIG_ENDIAN_DESC _and_ - * CONFIG_USB_OHCI_BIG_ENDIAN_MMIO - * - * mixed endian CONFIG_USB_OHCI_LITTLE_ENDIAN _and_ - * CONFIG_USB_OHCI_BIG_ENDIAN_{MMIO,DESC} - * - * (If you have a mixed endian controller, you -must- also define - * CONFIG_USB_OHCI_LITTLE_ENDIAN or things will not work when building - * both your mixed endian and a fully big endian controller support in - * the same kernel image). - */ - -#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_DESC -#ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN -#define big_endian_desc(ohci) (ohci->flags & OHCI_QUIRK_BE_DESC) -#else -#define big_endian_desc(ohci) 1 /* only big endian */ -#endif -#else -#define big_endian_desc(ohci) 0 /* only little endian */ -#endif - -#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO -#ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN -#define big_endian_mmio(ohci) (ohci->flags & OHCI_QUIRK_BE_MMIO) -#else -#define big_endian_mmio(ohci) 1 /* only big endian */ -#endif -#else -#define big_endian_mmio(ohci) 0 /* only little endian */ -#endif - -/* - * Big-endian read/write functions are arch-specific. - * Other arches can be added if/when they're needed. - * - */ -static inline unsigned int _ohci_readl (const struct ohci_hcd *ohci, - __hc32 __iomem * regs) -{ -#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO - return big_endian_mmio(ohci) ? - readl_be (regs) : - readl (regs); -#else - return readl (regs); -#endif -} - -static inline void _ohci_writel (const struct ohci_hcd *ohci, - const unsigned int val, __hc32 __iomem *regs) -{ -#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO - big_endian_mmio(ohci) ? - writel_be (val, regs) : - writel (val, regs); -#else - writel (val, regs); -#endif -} - -#define ohci_readl(o,r) _ohci_readl(o,r) -#define ohci_writel(o,v,r) _ohci_writel(o,v,r) - - -/*-------------------------------------------------------------------------*/ - -/* cpu to ohci */ -static inline __hc16 cpu_to_hc16 (const struct ohci_hcd *ohci, const u16 x) -{ - return big_endian_desc(ohci) ? - (__force __hc16)cpu_to_be16(x) : - (__force __hc16)cpu_to_le16(x); -} - -static inline __hc16 cpu_to_hc16p (const struct ohci_hcd *ohci, const u16 *x) -{ - return big_endian_desc(ohci) ? - cpu_to_be16p(x) : - cpu_to_le16p(x); -} - -static inline __hc32 cpu_to_hc32 (const struct ohci_hcd *ohci, const u32 x) -{ - return big_endian_desc(ohci) ? - (__force __hc32)cpu_to_be32(x) : - (__force __hc32)cpu_to_le32(x); -} - -static inline __hc32 cpu_to_hc32p (const struct ohci_hcd *ohci, const u32 *x) -{ - return big_endian_desc(ohci) ? - cpu_to_be32p(x) : - cpu_to_le32p(x); -} - -/* ohci to cpu */ -static inline u16 hc16_to_cpu (const struct ohci_hcd *ohci, const __hc16 x) -{ - return big_endian_desc(ohci) ? - be16_to_cpu((__force __be16)x) : - le16_to_cpu((__force __le16)x); -} - -static inline u16 hc16_to_cpup (const struct ohci_hcd *ohci, const __hc16 *x) -{ - return big_endian_desc(ohci) ? - be16_to_cpup((__force __be16 *)x) : - le16_to_cpup((__force __le16 *)x); -} - -static inline u32 hc32_to_cpu (const struct ohci_hcd *ohci, const __hc32 x) -{ - return big_endian_desc(ohci) ? - be32_to_cpu((__force __be32)x) : - le32_to_cpu((__force __le32)x); -} - -static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x) -{ - return big_endian_desc(ohci) ? - be32_to_cpup((__force __be32 *)x) : - le32_to_cpup((__force __le32 *)x); -} - -/*-------------------------------------------------------------------------*/ - -/* HCCA frame number is 16 bits, but is accessed as 32 bits since not all - * hardware handles 16 bit reads. That creates a different confusion on - * some big-endian SOC implementations. Same thing happens with PSW access. - */ - -#ifdef CONFIG_PPC_MPC52xx -#define big_endian_frame_no_quirk(ohci) (ohci->flags & OHCI_QUIRK_FRAME_NO) -#else -#define big_endian_frame_no_quirk(ohci) 0 -#endif - -static inline u16 ohci_frame_no(const struct ohci_hcd *ohci) -{ - u32 tmp; - if (big_endian_desc(ohci)) { - tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no); - if (!big_endian_frame_no_quirk(ohci)) - tmp >>= 16; - } else - tmp = le32_to_cpup((__force __le32 *)&ohci->hcca->frame_no); - - return (u16)tmp; -} - -static inline __hc16 *ohci_hwPSWp(const struct ohci_hcd *ohci, - const struct td *td, int index) -{ - return (__hc16 *)(big_endian_desc(ohci) ? - &td->hwPSW[index ^ 1] : &td->hwPSW[index]); -} - -static inline u16 ohci_hwPSW(const struct ohci_hcd *ohci, - const struct td *td, int index) -{ - return hc16_to_cpup(ohci, ohci_hwPSWp(ohci, td, index)); -} - -/*-------------------------------------------------------------------------*/ - -#define FI 0x2edf /* 12000 bits per frame (-1) */ -#define FSMP(fi) (0x7fff & ((6 * ((fi) - 210)) / 7)) -#define FIT (1 << 31) -#define LSTHRESH 0x628 /* lowspeed bit threshold */ - -static inline void periodic_reinit (struct ohci_hcd *ohci) -{ - u32 fi = ohci->fminterval & 0x03fff; - u32 fit = ohci_readl(ohci, &ohci->regs->fminterval) & FIT; - - ohci_writel (ohci, (fit ^ FIT) | ohci->fminterval, - &ohci->regs->fminterval); - ohci_writel (ohci, ((9 * fi) / 10) & 0x3fff, - &ohci->regs->periodicstart); -} - -/* AMD-756 (D2 rev) reports corrupt register contents in some cases. - * The erratum (#4) description is incorrect. AMD's workaround waits - * till some bits (mostly reserved) are clear; ok for all revs. - */ -#define read_roothub(hc, register, mask) ({ \ - u32 temp = ohci_readl (hc, &hc->regs->roothub.register); \ - if (temp == -1) \ - hc->rh_state = OHCI_RH_HALTED; \ - else if (hc->flags & OHCI_QUIRK_AMD756) \ - while (temp & mask) \ - temp = ohci_readl (hc, &hc->regs->roothub.register); \ - temp; }) - -static inline u32 roothub_a (struct ohci_hcd *hc) - { return read_roothub (hc, a, 0xfc0fe000); } -static inline u32 roothub_b (struct ohci_hcd *hc) - { return ohci_readl (hc, &hc->regs->roothub.b); } -static inline u32 roothub_status (struct ohci_hcd *hc) - { return ohci_readl (hc, &hc->regs->roothub.status); } -static inline u32 roothub_portstatus (struct ohci_hcd *hc, int i) - { return read_roothub (hc, portstatus [i], 0xffe0fce0); } diff --git a/ANDROID_3.4.5/drivers/usb/host/oxu210hp-hcd.c b/ANDROID_3.4.5/drivers/usb/host/oxu210hp-hcd.c deleted file mode 100644 index 3b38030b..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/oxu210hp-hcd.c +++ /dev/null @@ -1,3957 +0,0 @@ -/* - * Copyright (c) 2008 Rodolfo Giometti - * Copyright (c) 2008 Eurotech S.p.A. - * - * This code is *strongly* based on EHCI-HCD code by David Brownell since - * the chip is a quasi-EHCI compatible. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "oxu210hp.h" - -#define DRIVER_VERSION "0.0.50" - -/* - * Main defines - */ - -#define oxu_dbg(oxu, fmt, args...) \ - dev_dbg(oxu_to_hcd(oxu)->self.controller , fmt , ## args) -#define oxu_err(oxu, fmt, args...) \ - dev_err(oxu_to_hcd(oxu)->self.controller , fmt , ## args) -#define oxu_info(oxu, fmt, args...) \ - dev_info(oxu_to_hcd(oxu)->self.controller , fmt , ## args) - -static inline struct usb_hcd *oxu_to_hcd(struct oxu_hcd *oxu) -{ - return container_of((void *) oxu, struct usb_hcd, hcd_priv); -} - -static inline struct oxu_hcd *hcd_to_oxu(struct usb_hcd *hcd) -{ - return (struct oxu_hcd *) (hcd->hcd_priv); -} - -/* - * Debug stuff - */ - -#undef OXU_URB_TRACE -#undef OXU_VERBOSE_DEBUG - -#ifdef OXU_VERBOSE_DEBUG -#define oxu_vdbg oxu_dbg -#else -#define oxu_vdbg(oxu, fmt, args...) /* Nop */ -#endif - -#ifdef DEBUG - -static int __attribute__((__unused__)) -dbg_status_buf(char *buf, unsigned len, const char *label, u32 status) -{ - return scnprintf(buf, len, "%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s", - label, label[0] ? " " : "", status, - (status & STS_ASS) ? " Async" : "", - (status & STS_PSS) ? " Periodic" : "", - (status & STS_RECL) ? " Recl" : "", - (status & STS_HALT) ? " Halt" : "", - (status & STS_IAA) ? " IAA" : "", - (status & STS_FATAL) ? " FATAL" : "", - (status & STS_FLR) ? " FLR" : "", - (status & STS_PCD) ? " PCD" : "", - (status & STS_ERR) ? " ERR" : "", - (status & STS_INT) ? " INT" : "" - ); -} - -static int __attribute__((__unused__)) -dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable) -{ - return scnprintf(buf, len, "%s%sintrenable %02x%s%s%s%s%s%s", - label, label[0] ? " " : "", enable, - (enable & STS_IAA) ? " IAA" : "", - (enable & STS_FATAL) ? " FATAL" : "", - (enable & STS_FLR) ? " FLR" : "", - (enable & STS_PCD) ? " PCD" : "", - (enable & STS_ERR) ? " ERR" : "", - (enable & STS_INT) ? " INT" : "" - ); -} - -static const char *const fls_strings[] = - { "1024", "512", "256", "??" }; - -static int dbg_command_buf(char *buf, unsigned len, - const char *label, u32 command) -{ - return scnprintf(buf, len, - "%s%scommand %06x %s=%d ithresh=%d%s%s%s%s period=%s%s %s", - label, label[0] ? " " : "", command, - (command & CMD_PARK) ? "park" : "(park)", - CMD_PARK_CNT(command), - (command >> 16) & 0x3f, - (command & CMD_LRESET) ? " LReset" : "", - (command & CMD_IAAD) ? " IAAD" : "", - (command & CMD_ASE) ? " Async" : "", - (command & CMD_PSE) ? " Periodic" : "", - fls_strings[(command >> 2) & 0x3], - (command & CMD_RESET) ? " Reset" : "", - (command & CMD_RUN) ? "RUN" : "HALT" - ); -} - -static int dbg_port_buf(char *buf, unsigned len, const char *label, - int port, u32 status) -{ - char *sig; - - /* signaling state */ - switch (status & (3 << 10)) { - case 0 << 10: - sig = "se0"; - break; - case 1 << 10: - sig = "k"; /* low speed */ - break; - case 2 << 10: - sig = "j"; - break; - default: - sig = "?"; - break; - } - - return scnprintf(buf, len, - "%s%sport %d status %06x%s%s sig=%s%s%s%s%s%s%s%s%s%s", - label, label[0] ? " " : "", port, status, - (status & PORT_POWER) ? " POWER" : "", - (status & PORT_OWNER) ? " OWNER" : "", - sig, - (status & PORT_RESET) ? " RESET" : "", - (status & PORT_SUSPEND) ? " SUSPEND" : "", - (status & PORT_RESUME) ? " RESUME" : "", - (status & PORT_OCC) ? " OCC" : "", - (status & PORT_OC) ? " OC" : "", - (status & PORT_PEC) ? " PEC" : "", - (status & PORT_PE) ? " PE" : "", - (status & PORT_CSC) ? " CSC" : "", - (status & PORT_CONNECT) ? " CONNECT" : "" - ); -} - -#else - -static inline int __attribute__((__unused__)) -dbg_status_buf(char *buf, unsigned len, const char *label, u32 status) -{ return 0; } - -static inline int __attribute__((__unused__)) -dbg_command_buf(char *buf, unsigned len, const char *label, u32 command) -{ return 0; } - -static inline int __attribute__((__unused__)) -dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable) -{ return 0; } - -static inline int __attribute__((__unused__)) -dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status) -{ return 0; } - -#endif /* DEBUG */ - -/* functions have the "wrong" filename when they're output... */ -#define dbg_status(oxu, label, status) { \ - char _buf[80]; \ - dbg_status_buf(_buf, sizeof _buf, label, status); \ - oxu_dbg(oxu, "%s\n", _buf); \ -} - -#define dbg_cmd(oxu, label, command) { \ - char _buf[80]; \ - dbg_command_buf(_buf, sizeof _buf, label, command); \ - oxu_dbg(oxu, "%s\n", _buf); \ -} - -#define dbg_port(oxu, label, port, status) { \ - char _buf[80]; \ - dbg_port_buf(_buf, sizeof _buf, label, port, status); \ - oxu_dbg(oxu, "%s\n", _buf); \ -} - -/* - * Module parameters - */ - -/* Initial IRQ latency: faster than hw default */ -static int log2_irq_thresh; /* 0 to 6 */ -module_param(log2_irq_thresh, int, S_IRUGO); -MODULE_PARM_DESC(log2_irq_thresh, "log2 IRQ latency, 1-64 microframes"); - -/* Initial park setting: slower than hw default */ -static unsigned park; -module_param(park, uint, S_IRUGO); -MODULE_PARM_DESC(park, "park setting; 1-3 back-to-back async packets"); - -/* For flakey hardware, ignore overcurrent indicators */ -static bool ignore_oc; -module_param(ignore_oc, bool, S_IRUGO); -MODULE_PARM_DESC(ignore_oc, "ignore bogus hardware overcurrent indications"); - - -static void ehci_work(struct oxu_hcd *oxu); -static int oxu_hub_control(struct usb_hcd *hcd, - u16 typeReq, u16 wValue, u16 wIndex, - char *buf, u16 wLength); - -/* - * Local functions - */ - -/* Low level read/write registers functions */ -static inline u32 oxu_readl(void *base, u32 reg) -{ - return readl(base + reg); -} - -static inline void oxu_writel(void *base, u32 reg, u32 val) -{ - writel(val, base + reg); -} - -static inline void timer_action_done(struct oxu_hcd *oxu, - enum ehci_timer_action action) -{ - clear_bit(action, &oxu->actions); -} - -static inline void timer_action(struct oxu_hcd *oxu, - enum ehci_timer_action action) -{ - if (!test_and_set_bit(action, &oxu->actions)) { - unsigned long t; - - switch (action) { - case TIMER_IAA_WATCHDOG: - t = EHCI_IAA_JIFFIES; - break; - case TIMER_IO_WATCHDOG: - t = EHCI_IO_JIFFIES; - break; - case TIMER_ASYNC_OFF: - t = EHCI_ASYNC_JIFFIES; - break; - case TIMER_ASYNC_SHRINK: - default: - t = EHCI_SHRINK_JIFFIES; - break; - } - t += jiffies; - /* all timings except IAA watchdog can be overridden. - * async queue SHRINK often precedes IAA. while it's ready - * to go OFF neither can matter, and afterwards the IO - * watchdog stops unless there's still periodic traffic. - */ - if (action != TIMER_IAA_WATCHDOG - && t > oxu->watchdog.expires - && timer_pending(&oxu->watchdog)) - return; - mod_timer(&oxu->watchdog, t); - } -} - -/* - * handshake - spin reading hc until handshake completes or fails - * @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 - * @usec: timeout in microseconds - * - * Returns negative errno, or zero on success - * - * Success happens when the "mask" bits have the specified value (hardware - * handshake done). There are two failure modes: "usec" have passed (major - * hardware flakeout), or the register reads as all-ones (hardware removed). - * - * That last failure should_only happen in cases like physical cardbus eject - * before driver shutdown. But it also seems to be caused by bugs in cardbus - * bridge shutdown: shutting down the bridge before the devices using it. - */ -static int handshake(struct oxu_hcd *oxu, void __iomem *ptr, - u32 mask, u32 done, int usec) -{ - u32 result; - - do { - result = readl(ptr); - if (result == ~(u32)0) /* card removed */ - return -ENODEV; - result &= mask; - if (result == done) - return 0; - udelay(1); - usec--; - } while (usec > 0); - return -ETIMEDOUT; -} - -/* Force HC to halt state from unknown (EHCI spec section 2.3) */ -static int ehci_halt(struct oxu_hcd *oxu) -{ - u32 temp = readl(&oxu->regs->status); - - /* disable any irqs left enabled by previous code */ - writel(0, &oxu->regs->intr_enable); - - if ((temp & STS_HALT) != 0) - return 0; - - temp = readl(&oxu->regs->command); - temp &= ~CMD_RUN; - writel(temp, &oxu->regs->command); - return handshake(oxu, &oxu->regs->status, - STS_HALT, STS_HALT, 16 * 125); -} - -/* Put TDI/ARC silicon into EHCI mode */ -static void tdi_reset(struct oxu_hcd *oxu) -{ - u32 __iomem *reg_ptr; - u32 tmp; - - reg_ptr = (u32 __iomem *)(((u8 __iomem *)oxu->regs) + 0x68); - tmp = readl(reg_ptr); - tmp |= 0x3; - writel(tmp, reg_ptr); -} - -/* Reset a non-running (STS_HALT == 1) controller */ -static int ehci_reset(struct oxu_hcd *oxu) -{ - int retval; - u32 command = readl(&oxu->regs->command); - - command |= CMD_RESET; - dbg_cmd(oxu, "reset", command); - writel(command, &oxu->regs->command); - oxu_to_hcd(oxu)->state = HC_STATE_HALT; - oxu->next_statechange = jiffies; - retval = handshake(oxu, &oxu->regs->command, - CMD_RESET, 0, 250 * 1000); - - if (retval) - return retval; - - tdi_reset(oxu); - - return retval; -} - -/* Idle the controller (from running) */ -static void ehci_quiesce(struct oxu_hcd *oxu) -{ - u32 temp; - -#ifdef DEBUG - if (!HC_IS_RUNNING(oxu_to_hcd(oxu)->state)) - BUG(); -#endif - - /* wait for any schedule enables/disables to take effect */ - temp = readl(&oxu->regs->command) << 10; - temp &= STS_ASS | STS_PSS; - if (handshake(oxu, &oxu->regs->status, STS_ASS | STS_PSS, - temp, 16 * 125) != 0) { - oxu_to_hcd(oxu)->state = HC_STATE_HALT; - return; - } - - /* then disable anything that's still active */ - temp = readl(&oxu->regs->command); - temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE); - writel(temp, &oxu->regs->command); - - /* hardware can take 16 microframes to turn off ... */ - if (handshake(oxu, &oxu->regs->status, STS_ASS | STS_PSS, - 0, 16 * 125) != 0) { - oxu_to_hcd(oxu)->state = HC_STATE_HALT; - return; - } -} - -static int check_reset_complete(struct oxu_hcd *oxu, int index, - u32 __iomem *status_reg, int port_status) -{ - if (!(port_status & PORT_CONNECT)) { - oxu->reset_done[index] = 0; - return port_status; - } - - /* if reset finished and it's still not enabled -- handoff */ - if (!(port_status & PORT_PE)) { - oxu_dbg(oxu, "Failed to enable port %d on root hub TT\n", - index+1); - return port_status; - } else - oxu_dbg(oxu, "port %d high speed\n", index + 1); - - return port_status; -} - -static void ehci_hub_descriptor(struct oxu_hcd *oxu, - struct usb_hub_descriptor *desc) -{ - int ports = HCS_N_PORTS(oxu->hcs_params); - u16 temp; - - desc->bDescriptorType = 0x29; - desc->bPwrOn2PwrGood = 10; /* oxu 1.0, 2.3.9 says 20ms max */ - desc->bHubContrCurrent = 0; - - desc->bNbrPorts = ports; - temp = 1 + (ports / 8); - desc->bDescLength = 7 + 2 * temp; - - /* ports removable, and usb 1.0 legacy PortPwrCtrlMask */ - memset(&desc->u.hs.DeviceRemovable[0], 0, temp); - memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp); - - temp = 0x0008; /* per-port overcurrent reporting */ - if (HCS_PPC(oxu->hcs_params)) - temp |= 0x0001; /* per-port power control */ - else - temp |= 0x0002; /* no power switching */ - desc->wHubCharacteristics = (__force __u16)cpu_to_le16(temp); -} - - -/* Allocate an OXU210HP on-chip memory data buffer - * - * An on-chip memory data buffer is required for each OXU210HP USB transfer. - * Each transfer descriptor has one or more on-chip memory data buffers. - * - * Data buffers are allocated from a fix sized pool of data blocks. - * To minimise fragmentation and give reasonable memory utlisation, - * data buffers are allocated with sizes the power of 2 multiples of - * the block size, starting on an address a multiple of the allocated size. - * - * FIXME: callers of this function require a buffer to be allocated for - * len=0. This is a waste of on-chip memory and should be fix. Then this - * function should be changed to not allocate a buffer for len=0. - */ -static int oxu_buf_alloc(struct oxu_hcd *oxu, struct ehci_qtd *qtd, int len) -{ - int n_blocks; /* minium blocks needed to hold len */ - int a_blocks; /* blocks allocated */ - int i, j; - - /* Don't allocte bigger than supported */ - if (len > BUFFER_SIZE * BUFFER_NUM) { - oxu_err(oxu, "buffer too big (%d)\n", len); - return -ENOMEM; - } - - spin_lock(&oxu->mem_lock); - - /* Number of blocks needed to hold len */ - n_blocks = (len + BUFFER_SIZE - 1) / BUFFER_SIZE; - - /* Round the number of blocks up to the power of 2 */ - for (a_blocks = 1; a_blocks < n_blocks; a_blocks <<= 1) - ; - - /* Find a suitable available data buffer */ - for (i = 0; i < BUFFER_NUM; - i += max(a_blocks, (int)oxu->db_used[i])) { - - /* Check all the required blocks are available */ - for (j = 0; j < a_blocks; j++) - if (oxu->db_used[i + j]) - break; - - if (j != a_blocks) - continue; - - /* Allocate blocks found! */ - qtd->buffer = (void *) &oxu->mem->db_pool[i]; - qtd->buffer_dma = virt_to_phys(qtd->buffer); - - qtd->qtd_buffer_len = BUFFER_SIZE * a_blocks; - oxu->db_used[i] = a_blocks; - - spin_unlock(&oxu->mem_lock); - - return 0; - } - - /* Failed */ - - spin_unlock(&oxu->mem_lock); - - return -ENOMEM; -} - -static void oxu_buf_free(struct oxu_hcd *oxu, struct ehci_qtd *qtd) -{ - int index; - - spin_lock(&oxu->mem_lock); - - index = (qtd->buffer - (void *) &oxu->mem->db_pool[0]) - / BUFFER_SIZE; - oxu->db_used[index] = 0; - qtd->qtd_buffer_len = 0; - qtd->buffer_dma = 0; - qtd->buffer = NULL; - - spin_unlock(&oxu->mem_lock); -} - -static inline void ehci_qtd_init(struct ehci_qtd *qtd, dma_addr_t dma) -{ - memset(qtd, 0, sizeof *qtd); - qtd->qtd_dma = dma; - qtd->hw_token = cpu_to_le32(QTD_STS_HALT); - qtd->hw_next = EHCI_LIST_END; - qtd->hw_alt_next = EHCI_LIST_END; - INIT_LIST_HEAD(&qtd->qtd_list); -} - -static inline void oxu_qtd_free(struct oxu_hcd *oxu, struct ehci_qtd *qtd) -{ - int index; - - if (qtd->buffer) - oxu_buf_free(oxu, qtd); - - spin_lock(&oxu->mem_lock); - - index = qtd - &oxu->mem->qtd_pool[0]; - oxu->qtd_used[index] = 0; - - spin_unlock(&oxu->mem_lock); -} - -static struct ehci_qtd *ehci_qtd_alloc(struct oxu_hcd *oxu) -{ - int i; - struct ehci_qtd *qtd = NULL; - - spin_lock(&oxu->mem_lock); - - for (i = 0; i < QTD_NUM; i++) - if (!oxu->qtd_used[i]) - break; - - if (i < QTD_NUM) { - qtd = (struct ehci_qtd *) &oxu->mem->qtd_pool[i]; - memset(qtd, 0, sizeof *qtd); - - qtd->hw_token = cpu_to_le32(QTD_STS_HALT); - qtd->hw_next = EHCI_LIST_END; - qtd->hw_alt_next = EHCI_LIST_END; - INIT_LIST_HEAD(&qtd->qtd_list); - - qtd->qtd_dma = virt_to_phys(qtd); - - oxu->qtd_used[i] = 1; - } - - spin_unlock(&oxu->mem_lock); - - return qtd; -} - -static void oxu_qh_free(struct oxu_hcd *oxu, struct ehci_qh *qh) -{ - int index; - - spin_lock(&oxu->mem_lock); - - index = qh - &oxu->mem->qh_pool[0]; - oxu->qh_used[index] = 0; - - spin_unlock(&oxu->mem_lock); -} - -static void qh_destroy(struct kref *kref) -{ - struct ehci_qh *qh = container_of(kref, struct ehci_qh, kref); - struct oxu_hcd *oxu = qh->oxu; - - /* clean qtds first, and know this is not linked */ - if (!list_empty(&qh->qtd_list) || qh->qh_next.ptr) { - oxu_dbg(oxu, "unused qh not empty!\n"); - BUG(); - } - if (qh->dummy) - oxu_qtd_free(oxu, qh->dummy); - oxu_qh_free(oxu, qh); -} - -static struct ehci_qh *oxu_qh_alloc(struct oxu_hcd *oxu) -{ - int i; - struct ehci_qh *qh = NULL; - - spin_lock(&oxu->mem_lock); - - for (i = 0; i < QHEAD_NUM; i++) - if (!oxu->qh_used[i]) - break; - - if (i < QHEAD_NUM) { - qh = (struct ehci_qh *) &oxu->mem->qh_pool[i]; - memset(qh, 0, sizeof *qh); - - kref_init(&qh->kref); - qh->oxu = oxu; - qh->qh_dma = virt_to_phys(qh); - INIT_LIST_HEAD(&qh->qtd_list); - - /* dummy td enables safe urb queuing */ - qh->dummy = ehci_qtd_alloc(oxu); - if (qh->dummy == NULL) { - oxu_dbg(oxu, "no dummy td\n"); - oxu->qh_used[i] = 0; - qh = NULL; - goto unlock; - } - - oxu->qh_used[i] = 1; - } -unlock: - spin_unlock(&oxu->mem_lock); - - return qh; -} - -/* to share a qh (cpu threads, or hc) */ -static inline struct ehci_qh *qh_get(struct ehci_qh *qh) -{ - kref_get(&qh->kref); - return qh; -} - -static inline void qh_put(struct ehci_qh *qh) -{ - kref_put(&qh->kref, qh_destroy); -} - -static void oxu_murb_free(struct oxu_hcd *oxu, struct oxu_murb *murb) -{ - int index; - - spin_lock(&oxu->mem_lock); - - index = murb - &oxu->murb_pool[0]; - oxu->murb_used[index] = 0; - - spin_unlock(&oxu->mem_lock); -} - -static struct oxu_murb *oxu_murb_alloc(struct oxu_hcd *oxu) - -{ - int i; - struct oxu_murb *murb = NULL; - - spin_lock(&oxu->mem_lock); - - for (i = 0; i < MURB_NUM; i++) - if (!oxu->murb_used[i]) - break; - - if (i < MURB_NUM) { - murb = &(oxu->murb_pool)[i]; - - oxu->murb_used[i] = 1; - } - - spin_unlock(&oxu->mem_lock); - - return murb; -} - -/* The queue heads and transfer descriptors are managed from pools tied - * to each of the "per device" structures. - * This is the initialisation and cleanup code. - */ -static void ehci_mem_cleanup(struct oxu_hcd *oxu) -{ - kfree(oxu->murb_pool); - oxu->murb_pool = NULL; - - if (oxu->async) - qh_put(oxu->async); - oxu->async = NULL; - - del_timer(&oxu->urb_timer); - - oxu->periodic = NULL; - - /* shadow periodic table */ - kfree(oxu->pshadow); - oxu->pshadow = NULL; -} - -/* Remember to add cleanup code (above) if you add anything here. - */ -static int ehci_mem_init(struct oxu_hcd *oxu, gfp_t flags) -{ - int i; - - for (i = 0; i < oxu->periodic_size; i++) - oxu->mem->frame_list[i] = EHCI_LIST_END; - for (i = 0; i < QHEAD_NUM; i++) - oxu->qh_used[i] = 0; - for (i = 0; i < QTD_NUM; i++) - oxu->qtd_used[i] = 0; - - oxu->murb_pool = kcalloc(MURB_NUM, sizeof(struct oxu_murb), flags); - if (!oxu->murb_pool) - goto fail; - - for (i = 0; i < MURB_NUM; i++) - oxu->murb_used[i] = 0; - - oxu->async = oxu_qh_alloc(oxu); - if (!oxu->async) - goto fail; - - oxu->periodic = (__le32 *) &oxu->mem->frame_list; - oxu->periodic_dma = virt_to_phys(oxu->periodic); - - for (i = 0; i < oxu->periodic_size; i++) - oxu->periodic[i] = EHCI_LIST_END; - - /* software shadow of hardware table */ - oxu->pshadow = kcalloc(oxu->periodic_size, sizeof(void *), flags); - if (oxu->pshadow != NULL) - return 0; - -fail: - oxu_dbg(oxu, "couldn't init memory\n"); - ehci_mem_cleanup(oxu); - return -ENOMEM; -} - -/* Fill a qtd, returning how much of the buffer we were able to queue up. - */ -static int qtd_fill(struct ehci_qtd *qtd, dma_addr_t buf, size_t len, - int token, int maxpacket) -{ - int i, count; - u64 addr = buf; - - /* one buffer entry per 4K ... first might be short or unaligned */ - qtd->hw_buf[0] = cpu_to_le32((u32)addr); - qtd->hw_buf_hi[0] = cpu_to_le32((u32)(addr >> 32)); - count = 0x1000 - (buf & 0x0fff); /* rest of that page */ - if (likely(len < count)) /* ... iff needed */ - count = len; - else { - buf += 0x1000; - buf &= ~0x0fff; - - /* per-qtd limit: from 16K to 20K (best alignment) */ - for (i = 1; count < len && i < 5; i++) { - addr = buf; - qtd->hw_buf[i] = cpu_to_le32((u32)addr); - qtd->hw_buf_hi[i] = cpu_to_le32((u32)(addr >> 32)); - buf += 0x1000; - if ((count + 0x1000) < len) - count += 0x1000; - else - count = len; - } - - /* short packets may only terminate transfers */ - if (count != len) - count -= (count % maxpacket); - } - qtd->hw_token = cpu_to_le32((count << 16) | token); - qtd->length = count; - - return count; -} - -static inline void qh_update(struct oxu_hcd *oxu, - struct ehci_qh *qh, struct ehci_qtd *qtd) -{ - /* writes to an active overlay are unsafe */ - BUG_ON(qh->qh_state != QH_STATE_IDLE); - - qh->hw_qtd_next = QTD_NEXT(qtd->qtd_dma); - qh->hw_alt_next = EHCI_LIST_END; - - /* 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_le32(1 << 14))) { - unsigned is_out, epnum; - - is_out = !(qtd->hw_token & cpu_to_le32(1 << 8)); - epnum = (le32_to_cpup(&qh->hw_info1) >> 8) & 0x0f; - if (unlikely(!usb_gettoggle(qh->dev, epnum, is_out))) { - qh->hw_token &= ~cpu_to_le32(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_le32(QTD_TOGGLE | QTD_STS_PING); -} - -/* If it weren't for a common silicon quirk (writing the dummy into the qh - * overlay, so qh->hw_token wrongly becomes inactive/halted), only fault - * recovery (including urb dequeue) would need software changes to a QH... - */ -static void qh_refresh(struct oxu_hcd *oxu, struct ehci_qh *qh) -{ - struct ehci_qtd *qtd; - - if (list_empty(&qh->qtd_list)) - qtd = qh->dummy; - else { - qtd = list_entry(qh->qtd_list.next, - struct ehci_qtd, qtd_list); - /* first qtd may already be partially processed */ - if (cpu_to_le32(qtd->qtd_dma) == qh->hw_current) - qtd = NULL; - } - - if (qtd) - qh_update(oxu, qh, qtd); -} - -static void qtd_copy_status(struct oxu_hcd *oxu, struct urb *urb, - size_t length, u32 token) -{ - /* count IN/OUT bytes, not SETUP (even short packets) */ - if (likely(QTD_PID(token) != 2)) - urb->actual_length += length - QTD_LENGTH(token); - - /* don't modify error codes */ - if (unlikely(urb->status != -EINPROGRESS)) - return; - - /* force cleanup after short read; not always an error */ - if (unlikely(IS_SHORT_READ(token))) - urb->status = -EREMOTEIO; - - /* serious "can't proceed" faults reported by the hardware */ - if (token & QTD_STS_HALT) { - if (token & QTD_STS_BABBLE) { - /* FIXME "must" disable babbling device's port too */ - urb->status = -EOVERFLOW; - } else if (token & QTD_STS_MMF) { - /* fs/ls interrupt xfer missed the complete-split */ - urb->status = -EPROTO; - } else if (token & QTD_STS_DBE) { - urb->status = (QTD_PID(token) == 1) /* IN ? */ - ? -ENOSR /* hc couldn't read data */ - : -ECOMM; /* hc couldn't write data */ - } else if (token & QTD_STS_XACT) { - /* timeout, bad crc, wrong PID, etc; retried */ - if (QTD_CERR(token)) - urb->status = -EPIPE; - else { - oxu_dbg(oxu, "devpath %s ep%d%s 3strikes\n", - urb->dev->devpath, - usb_pipeendpoint(urb->pipe), - usb_pipein(urb->pipe) ? "in" : "out"); - urb->status = -EPROTO; - } - /* CERR nonzero + no errors + halt --> stall */ - } else if (QTD_CERR(token)) - urb->status = -EPIPE; - else /* unknown */ - urb->status = -EPROTO; - - oxu_vdbg(oxu, "dev%d ep%d%s qtd token %08x --> status %d\n", - usb_pipedevice(urb->pipe), - usb_pipeendpoint(urb->pipe), - usb_pipein(urb->pipe) ? "in" : "out", - token, urb->status); - } -} - -static void ehci_urb_done(struct oxu_hcd *oxu, struct urb *urb) -__releases(oxu->lock) -__acquires(oxu->lock) -{ - if (likely(urb->hcpriv != NULL)) { - struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv; - - /* S-mask in a QH means it's an interrupt urb */ - if ((qh->hw_info2 & cpu_to_le32(QH_SMASK)) != 0) { - - /* ... update hc-wide periodic stats (for usbfs) */ - oxu_to_hcd(oxu)->self.bandwidth_int_reqs--; - } - qh_put(qh); - } - - urb->hcpriv = NULL; - switch (urb->status) { - case -EINPROGRESS: /* success */ - urb->status = 0; - default: /* fault */ - break; - case -EREMOTEIO: /* fault or normal */ - if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) - urb->status = 0; - break; - case -ECONNRESET: /* canceled */ - case -ENOENT: - break; - } - -#ifdef OXU_URB_TRACE - oxu_dbg(oxu, "%s %s urb %p ep%d%s status %d len %d/%d\n", - __func__, urb->dev->devpath, urb, - usb_pipeendpoint(urb->pipe), - usb_pipein(urb->pipe) ? "in" : "out", - urb->status, - urb->actual_length, urb->transfer_buffer_length); -#endif - - /* complete() can reenter this HCD */ - spin_unlock(&oxu->lock); - usb_hcd_giveback_urb(oxu_to_hcd(oxu), urb, urb->status); - spin_lock(&oxu->lock); -} - -static void start_unlink_async(struct oxu_hcd *oxu, struct ehci_qh *qh); -static void unlink_async(struct oxu_hcd *oxu, struct ehci_qh *qh); - -static void intr_deschedule(struct oxu_hcd *oxu, struct ehci_qh *qh); -static int qh_schedule(struct oxu_hcd *oxu, struct ehci_qh *qh); - -#define HALT_BIT cpu_to_le32(QTD_STS_HALT) - -/* Process and free completed qtds for a qh, returning URBs to drivers. - * Chases up to qh->hw_current. Returns number of completions called, - * indicating how much "real" work we did. - */ -static unsigned qh_completions(struct oxu_hcd *oxu, struct ehci_qh *qh) -{ - struct ehci_qtd *last = NULL, *end = qh->dummy; - struct list_head *entry, *tmp; - int stopped; - unsigned count = 0; - int do_status = 0; - u8 state; - struct oxu_murb *murb = NULL; - - if (unlikely(list_empty(&qh->qtd_list))) - return count; - - /* completions (or tasks on other cpus) must never clobber HALT - * till we've gone through and cleaned everything up, even when - * they add urbs to this qh's queue or mark them for unlinking. - * - * NOTE: unlinking expects to be done in queue order. - */ - state = qh->qh_state; - qh->qh_state = QH_STATE_COMPLETING; - stopped = (state == QH_STATE_IDLE); - - /* remove de-activated QTDs from front of queue. - * after faults (including short reads), cleanup this urb - * then let the queue advance. - * if queue is stopped, handles unlinks. - */ - list_for_each_safe(entry, tmp, &qh->qtd_list) { - struct ehci_qtd *qtd; - struct urb *urb; - u32 token = 0; - - qtd = list_entry(entry, struct ehci_qtd, qtd_list); - urb = qtd->urb; - - /* Clean up any state from previous QTD ...*/ - if (last) { - if (likely(last->urb != urb)) { - if (last->urb->complete == NULL) { - murb = (struct oxu_murb *) last->urb; - last->urb = murb->main; - if (murb->last) { - ehci_urb_done(oxu, last->urb); - count++; - } - oxu_murb_free(oxu, murb); - } else { - ehci_urb_done(oxu, last->urb); - count++; - } - } - oxu_qtd_free(oxu, last); - last = NULL; - } - - /* ignore urbs submitted during completions we reported */ - if (qtd == end) - break; - - /* hardware copies qtd out of qh overlay */ - rmb(); - token = le32_to_cpu(qtd->hw_token); - - /* always clean up qtds the hc de-activated */ - if ((token & QTD_STS_ACTIVE) == 0) { - - if ((token & QTD_STS_HALT) != 0) { - stopped = 1; - - /* magic dummy for some short reads; qh won't advance. - * that silicon quirk can kick in with this dummy too. - */ - } else if (IS_SHORT_READ(token) && - !(qtd->hw_alt_next & EHCI_LIST_END)) { - stopped = 1; - goto halt; - } - - /* stop scanning when we reach qtds the hc is using */ - } else if (likely(!stopped && - HC_IS_RUNNING(oxu_to_hcd(oxu)->state))) { - break; - - } else { - stopped = 1; - - if (unlikely(!HC_IS_RUNNING(oxu_to_hcd(oxu)->state))) - urb->status = -ESHUTDOWN; - - /* ignore active urbs unless some previous qtd - * for the urb faulted (including short read) or - * its urb was canceled. we may patch qh or qtds. - */ - if (likely(urb->status == -EINPROGRESS)) - continue; - - /* issue status after short control reads */ - if (unlikely(do_status != 0) - && QTD_PID(token) == 0 /* OUT */) { - do_status = 0; - continue; - } - - /* token in overlay may be most current */ - if (state == QH_STATE_IDLE - && cpu_to_le32(qtd->qtd_dma) - == qh->hw_current) - token = le32_to_cpu(qh->hw_token); - - /* force halt for unlinked or blocked qh, so we'll - * patch the qh later and so that completions can't - * activate it while we "know" it's stopped. - */ - if ((HALT_BIT & qh->hw_token) == 0) { -halt: - qh->hw_token |= HALT_BIT; - wmb(); - } - } - - /* Remove it from the queue */ - qtd_copy_status(oxu, urb->complete ? - urb : ((struct oxu_murb *) urb)->main, - qtd->length, token); - if ((usb_pipein(qtd->urb->pipe)) && - (NULL != qtd->transfer_buffer)) - memcpy(qtd->transfer_buffer, qtd->buffer, qtd->length); - do_status = (urb->status == -EREMOTEIO) - && usb_pipecontrol(urb->pipe); - - if (stopped && qtd->qtd_list.prev != &qh->qtd_list) { - last = list_entry(qtd->qtd_list.prev, - struct ehci_qtd, qtd_list); - last->hw_next = qtd->hw_next; - } - list_del(&qtd->qtd_list); - last = qtd; - } - - /* last urb's completion might still need calling */ - if (likely(last != NULL)) { - if (last->urb->complete == NULL) { - murb = (struct oxu_murb *) last->urb; - last->urb = murb->main; - if (murb->last) { - ehci_urb_done(oxu, last->urb); - count++; - } - oxu_murb_free(oxu, murb); - } else { - ehci_urb_done(oxu, last->urb); - count++; - } - oxu_qtd_free(oxu, last); - } - - /* restore original state; caller must unlink or relink */ - qh->qh_state = state; - - /* be sure the hardware's done with the qh before refreshing - * it after fault cleanup, or recovering from silicon wrongly - * overlaying the dummy qtd (which reduces DMA chatter). - */ - if (stopped != 0 || qh->hw_qtd_next == EHCI_LIST_END) { - switch (state) { - case QH_STATE_IDLE: - qh_refresh(oxu, qh); - break; - case QH_STATE_LINKED: - /* should be rare for periodic transfers, - * except maybe high bandwidth ... - */ - if ((cpu_to_le32(QH_SMASK) - & qh->hw_info2) != 0) { - intr_deschedule(oxu, qh); - (void) qh_schedule(oxu, qh); - } else - unlink_async(oxu, qh); - break; - /* otherwise, unlink already started */ - } - } - - return count; -} - -/* High bandwidth multiplier, as encoded in highspeed endpoint descriptors */ -#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) -/* ... and packet size, for any kind of endpoint descriptor */ -#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff) - -/* Reverse of qh_urb_transaction: free a list of TDs. - * used for cleanup after errors, before HC sees an URB's TDs. - */ -static void qtd_list_free(struct oxu_hcd *oxu, - struct urb *urb, struct list_head *qtd_list) -{ - struct list_head *entry, *temp; - - list_for_each_safe(entry, temp, qtd_list) { - struct ehci_qtd *qtd; - - qtd = list_entry(entry, struct ehci_qtd, qtd_list); - list_del(&qtd->qtd_list); - oxu_qtd_free(oxu, qtd); - } -} - -/* Create a list of filled qtds for this URB; won't link into qh. - */ -static struct list_head *qh_urb_transaction(struct oxu_hcd *oxu, - struct urb *urb, - struct list_head *head, - gfp_t flags) -{ - struct ehci_qtd *qtd, *qtd_prev; - dma_addr_t buf; - int len, maxpacket; - int is_input; - u32 token; - void *transfer_buf = NULL; - int ret; - - /* - * URBs map to sequences of QTDs: one logical transaction - */ - qtd = ehci_qtd_alloc(oxu); - if (unlikely(!qtd)) - return NULL; - list_add_tail(&qtd->qtd_list, head); - qtd->urb = urb; - - token = QTD_STS_ACTIVE; - token |= (EHCI_TUNE_CERR << 10); - /* for split transactions, SplitXState initialized to zero */ - - len = urb->transfer_buffer_length; - is_input = usb_pipein(urb->pipe); - if (!urb->transfer_buffer && urb->transfer_buffer_length && is_input) - urb->transfer_buffer = phys_to_virt(urb->transfer_dma); - - if (usb_pipecontrol(urb->pipe)) { - /* SETUP pid */ - ret = oxu_buf_alloc(oxu, qtd, sizeof(struct usb_ctrlrequest)); - if (ret) - goto cleanup; - - qtd_fill(qtd, qtd->buffer_dma, sizeof(struct usb_ctrlrequest), - token | (2 /* "setup" */ << 8), 8); - memcpy(qtd->buffer, qtd->urb->setup_packet, - sizeof(struct usb_ctrlrequest)); - - /* ... and always at least one more pid */ - token ^= QTD_TOGGLE; - qtd_prev = qtd; - qtd = ehci_qtd_alloc(oxu); - if (unlikely(!qtd)) - goto cleanup; - qtd->urb = urb; - qtd_prev->hw_next = QTD_NEXT(qtd->qtd_dma); - list_add_tail(&qtd->qtd_list, head); - - /* for zero length DATA stages, STATUS is always IN */ - if (len == 0) - token |= (1 /* "in" */ << 8); - } - - /* - * Data transfer stage: buffer setup - */ - - ret = oxu_buf_alloc(oxu, qtd, len); - if (ret) - goto cleanup; - - buf = qtd->buffer_dma; - transfer_buf = urb->transfer_buffer; - - if (!is_input) - memcpy(qtd->buffer, qtd->urb->transfer_buffer, len); - - if (is_input) - token |= (1 /* "in" */ << 8); - /* else it's already initted to "out" pid (0 << 8) */ - - maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input)); - - /* - * buffer gets wrapped in one or more qtds; - * last one may be "short" (including zero len) - * and may serve as a control status ack - */ - for (;;) { - int this_qtd_len; - - this_qtd_len = qtd_fill(qtd, buf, len, token, maxpacket); - qtd->transfer_buffer = transfer_buf; - len -= this_qtd_len; - buf += this_qtd_len; - transfer_buf += this_qtd_len; - if (is_input) - qtd->hw_alt_next = oxu->async->hw_alt_next; - - /* qh makes control packets use qtd toggle; maybe switch it */ - if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0) - token ^= QTD_TOGGLE; - - if (likely(len <= 0)) - break; - - qtd_prev = qtd; - qtd = ehci_qtd_alloc(oxu); - if (unlikely(!qtd)) - goto cleanup; - if (likely(len > 0)) { - ret = oxu_buf_alloc(oxu, qtd, len); - if (ret) - goto cleanup; - } - qtd->urb = urb; - qtd_prev->hw_next = QTD_NEXT(qtd->qtd_dma); - list_add_tail(&qtd->qtd_list, head); - } - - /* unless the bulk/interrupt caller wants a chance to clean - * up after short reads, hc should advance qh past this urb - */ - if (likely((urb->transfer_flags & URB_SHORT_NOT_OK) == 0 - || usb_pipecontrol(urb->pipe))) - qtd->hw_alt_next = EHCI_LIST_END; - - /* - * control requests may need a terminating data "status" ack; - * bulk ones may need a terminating short packet (zero length). - */ - if (likely(urb->transfer_buffer_length != 0)) { - int one_more = 0; - - if (usb_pipecontrol(urb->pipe)) { - one_more = 1; - token ^= 0x0100; /* "in" <--> "out" */ - token |= QTD_TOGGLE; /* force DATA1 */ - } else if (usb_pipebulk(urb->pipe) - && (urb->transfer_flags & URB_ZERO_PACKET) - && !(urb->transfer_buffer_length % maxpacket)) { - one_more = 1; - } - if (one_more) { - qtd_prev = qtd; - qtd = ehci_qtd_alloc(oxu); - if (unlikely(!qtd)) - goto cleanup; - qtd->urb = urb; - qtd_prev->hw_next = QTD_NEXT(qtd->qtd_dma); - list_add_tail(&qtd->qtd_list, head); - - /* never any data in such packets */ - qtd_fill(qtd, 0, 0, token, 0); - } - } - - /* by default, enable interrupt on urb completion */ - qtd->hw_token |= cpu_to_le32(QTD_IOC); - return head; - -cleanup: - qtd_list_free(oxu, urb, head); - return NULL; -} - -/* Each QH holds a qtd list; a QH is used for everything except iso. - * - * For interrupt urbs, the scheduler must set the microframe scheduling - * mask(s) each time the QH gets scheduled. For highspeed, that's - * just one microframe in the s-mask. For split interrupt transactions - * there are additional complications: c-mask, maybe FSTNs. - */ -static struct ehci_qh *qh_make(struct oxu_hcd *oxu, - struct urb *urb, gfp_t flags) -{ - struct ehci_qh *qh = oxu_qh_alloc(oxu); - u32 info1 = 0, info2 = 0; - int is_input, type; - int maxp = 0; - - if (!qh) - return qh; - - /* - * init endpoint/device data for this QH - */ - info1 |= usb_pipeendpoint(urb->pipe) << 8; - info1 |= usb_pipedevice(urb->pipe) << 0; - - is_input = usb_pipein(urb->pipe); - type = usb_pipetype(urb->pipe); - maxp = usb_maxpacket(urb->dev, urb->pipe, !is_input); - - /* Compute interrupt scheduling parameters just once, and save. - * - allowing for high bandwidth, how many nsec/uframe are used? - * - split transactions need a second CSPLIT uframe; same question - * - splits also need a schedule gap (for full/low speed I/O) - * - qh has a polling interval - * - * For control/bulk requests, the HC or TT handles these. - */ - if (type == PIPE_INTERRUPT) { - qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH, - is_input, 0, - hb_mult(maxp) * max_packet(maxp))); - qh->start = NO_FRAME; - - if (urb->dev->speed == USB_SPEED_HIGH) { - qh->c_usecs = 0; - qh->gap_uf = 0; - - qh->period = urb->interval >> 3; - if (qh->period == 0 && urb->interval != 1) { - /* NOTE interval 2 or 4 uframes could work. - * But interval 1 scheduling is simpler, and - * includes high bandwidth. - */ - dbg("intr period %d uframes, NYET!", - urb->interval); - goto done; - } - } else { - struct usb_tt *tt = urb->dev->tt; - int think_time; - - /* gap is f(FS/LS transfer times) */ - qh->gap_uf = 1 + usb_calc_bus_time(urb->dev->speed, - is_input, 0, maxp) / (125 * 1000); - - /* FIXME this just approximates SPLIT/CSPLIT times */ - if (is_input) { /* SPLIT, gap, CSPLIT+DATA */ - qh->c_usecs = qh->usecs + HS_USECS(0); - qh->usecs = HS_USECS(1); - } else { /* SPLIT+DATA, gap, CSPLIT */ - qh->usecs += HS_USECS(1); - qh->c_usecs = HS_USECS(0); - } - - think_time = tt ? tt->think_time : 0; - qh->tt_usecs = NS_TO_US(think_time + - usb_calc_bus_time(urb->dev->speed, - is_input, 0, max_packet(maxp))); - qh->period = urb->interval; - } - } - - /* support for tt scheduling, and access to toggles */ - qh->dev = urb->dev; - - /* using TT? */ - switch (urb->dev->speed) { - case USB_SPEED_LOW: - info1 |= (1 << 12); /* EPS "low" */ - /* FALL THROUGH */ - - case USB_SPEED_FULL: - /* EPS 0 means "full" */ - if (type != PIPE_INTERRUPT) - info1 |= (EHCI_TUNE_RL_TT << 28); - if (type == PIPE_CONTROL) { - info1 |= (1 << 27); /* for TT */ - info1 |= 1 << 14; /* toggle from qtd */ - } - info1 |= maxp << 16; - - info2 |= (EHCI_TUNE_MULT_TT << 30); - info2 |= urb->dev->ttport << 23; - - /* NOTE: if (PIPE_INTERRUPT) { scheduler sets c-mask } */ - - break; - - case USB_SPEED_HIGH: /* no TT involved */ - info1 |= (2 << 12); /* EPS "high" */ - if (type == PIPE_CONTROL) { - info1 |= (EHCI_TUNE_RL_HS << 28); - info1 |= 64 << 16; /* usb2 fixed maxpacket */ - info1 |= 1 << 14; /* toggle from qtd */ - info2 |= (EHCI_TUNE_MULT_HS << 30); - } else if (type == PIPE_BULK) { - info1 |= (EHCI_TUNE_RL_HS << 28); - info1 |= 512 << 16; /* usb2 fixed maxpacket */ - info2 |= (EHCI_TUNE_MULT_HS << 30); - } else { /* PIPE_INTERRUPT */ - info1 |= max_packet(maxp) << 16; - info2 |= hb_mult(maxp) << 30; - } - break; - default: - dbg("bogus dev %p speed %d", urb->dev, urb->dev->speed); -done: - qh_put(qh); - return NULL; - } - - /* NOTE: if (PIPE_INTERRUPT) { scheduler sets s-mask } */ - - /* init as live, toggle clear, advance to dummy */ - qh->qh_state = QH_STATE_IDLE; - qh->hw_info1 = cpu_to_le32(info1); - qh->hw_info2 = cpu_to_le32(info2); - usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input, 1); - qh_refresh(oxu, qh); - return qh; -} - -/* Move qh (and its qtds) onto async queue; maybe enable queue. - */ -static void qh_link_async(struct oxu_hcd *oxu, struct ehci_qh *qh) -{ - __le32 dma = QH_NEXT(qh->qh_dma); - struct ehci_qh *head; - - /* (re)start the async schedule? */ - head = oxu->async; - timer_action_done(oxu, TIMER_ASYNC_OFF); - if (!head->qh_next.qh) { - u32 cmd = readl(&oxu->regs->command); - - if (!(cmd & CMD_ASE)) { - /* in case a clear of CMD_ASE didn't take yet */ - (void)handshake(oxu, &oxu->regs->status, - STS_ASS, 0, 150); - cmd |= CMD_ASE | CMD_RUN; - writel(cmd, &oxu->regs->command); - oxu_to_hcd(oxu)->state = HC_STATE_RUNNING; - /* posted write need not be known to HC yet ... */ - } - } - - /* clear halt and/or toggle; and maybe recover from silicon quirk */ - if (qh->qh_state == QH_STATE_IDLE) - qh_refresh(oxu, qh); - - /* splice right after start */ - qh->qh_next = head->qh_next; - qh->hw_next = head->hw_next; - wmb(); - - head->qh_next.qh = qh; - head->hw_next = dma; - - qh->qh_state = QH_STATE_LINKED; - /* qtd completions reported later by interrupt */ -} - -#define QH_ADDR_MASK cpu_to_le32(0x7f) - -/* - * For control/bulk/interrupt, return QH with these TDs appended. - * Allocates and initializes the QH if necessary. - * Returns null if it can't allocate a QH it needs to. - * If the QH has TDs (urbs) already, that's great. - */ -static struct ehci_qh *qh_append_tds(struct oxu_hcd *oxu, - struct urb *urb, struct list_head *qtd_list, - int epnum, void **ptr) -{ - struct ehci_qh *qh = NULL; - - qh = (struct ehci_qh *) *ptr; - if (unlikely(qh == NULL)) { - /* can't sleep here, we have oxu->lock... */ - qh = qh_make(oxu, urb, GFP_ATOMIC); - *ptr = qh; - } - if (likely(qh != NULL)) { - struct ehci_qtd *qtd; - - if (unlikely(list_empty(qtd_list))) - qtd = NULL; - else - qtd = list_entry(qtd_list->next, struct ehci_qtd, - qtd_list); - - /* control qh may need patching ... */ - if (unlikely(epnum == 0)) { - - /* usb_reset_device() briefly reverts to address 0 */ - if (usb_pipedevice(urb->pipe) == 0) - qh->hw_info1 &= ~QH_ADDR_MASK; - } - - /* just one way to queue requests: swap with the dummy qtd. - * only hc or qh_refresh() ever modify the overlay. - */ - if (likely(qtd != NULL)) { - struct ehci_qtd *dummy; - dma_addr_t dma; - __le32 token; - - /* to avoid racing the HC, use the dummy td instead of - * the first td of our list (becomes new dummy). both - * tds stay deactivated until we're done, when the - * HC is allowed to fetch the old dummy (4.10.2). - */ - token = qtd->hw_token; - qtd->hw_token = HALT_BIT; - wmb(); - dummy = qh->dummy; - - dma = dummy->qtd_dma; - *dummy = *qtd; - dummy->qtd_dma = dma; - - list_del(&qtd->qtd_list); - list_add(&dummy->qtd_list, qtd_list); - list_splice(qtd_list, qh->qtd_list.prev); - - ehci_qtd_init(qtd, qtd->qtd_dma); - qh->dummy = qtd; - - /* hc must see the new dummy at list end */ - dma = qtd->qtd_dma; - qtd = list_entry(qh->qtd_list.prev, - struct ehci_qtd, qtd_list); - qtd->hw_next = QTD_NEXT(dma); - - /* let the hc process these next qtds */ - dummy->hw_token = (token & ~(0x80)); - wmb(); - dummy->hw_token = token; - - urb->hcpriv = qh_get(qh); - } - } - return qh; -} - -static int submit_async(struct oxu_hcd *oxu, struct urb *urb, - struct list_head *qtd_list, gfp_t mem_flags) -{ - struct ehci_qtd *qtd; - int epnum; - unsigned long flags; - struct ehci_qh *qh = NULL; - int rc = 0; - - qtd = list_entry(qtd_list->next, struct ehci_qtd, qtd_list); - epnum = urb->ep->desc.bEndpointAddress; - -#ifdef OXU_URB_TRACE - oxu_dbg(oxu, "%s %s urb %p ep%d%s len %d, qtd %p [qh %p]\n", - __func__, urb->dev->devpath, urb, - epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out", - urb->transfer_buffer_length, - qtd, urb->ep->hcpriv); -#endif - - spin_lock_irqsave(&oxu->lock, flags); - if (unlikely(!HCD_HW_ACCESSIBLE(oxu_to_hcd(oxu)))) { - rc = -ESHUTDOWN; - goto done; - } - - qh = qh_append_tds(oxu, urb, qtd_list, epnum, &urb->ep->hcpriv); - if (unlikely(qh == NULL)) { - rc = -ENOMEM; - goto done; - } - - /* Control/bulk operations through TTs don't need scheduling, - * the HC and TT handle it when the TT has a buffer ready. - */ - if (likely(qh->qh_state == QH_STATE_IDLE)) - qh_link_async(oxu, qh_get(qh)); -done: - spin_unlock_irqrestore(&oxu->lock, flags); - if (unlikely(qh == NULL)) - qtd_list_free(oxu, urb, qtd_list); - return rc; -} - -/* The async qh for the qtds being reclaimed are now unlinked from the HC */ - -static void end_unlink_async(struct oxu_hcd *oxu) -{ - struct ehci_qh *qh = oxu->reclaim; - struct ehci_qh *next; - - timer_action_done(oxu, TIMER_IAA_WATCHDOG); - - qh->qh_state = QH_STATE_IDLE; - qh->qh_next.qh = NULL; - qh_put(qh); /* refcount from reclaim */ - - /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */ - next = qh->reclaim; - oxu->reclaim = next; - oxu->reclaim_ready = 0; - qh->reclaim = NULL; - - qh_completions(oxu, qh); - - if (!list_empty(&qh->qtd_list) - && HC_IS_RUNNING(oxu_to_hcd(oxu)->state)) - qh_link_async(oxu, qh); - else { - qh_put(qh); /* refcount from async list */ - - /* it's not free to turn the async schedule on/off; leave it - * active but idle for a while once it empties. - */ - if (HC_IS_RUNNING(oxu_to_hcd(oxu)->state) - && oxu->async->qh_next.qh == NULL) - timer_action(oxu, TIMER_ASYNC_OFF); - } - - if (next) { - oxu->reclaim = NULL; - start_unlink_async(oxu, next); - } -} - -/* makes sure the async qh will become idle */ -/* caller must own oxu->lock */ - -static void start_unlink_async(struct oxu_hcd *oxu, struct ehci_qh *qh) -{ - int cmd = readl(&oxu->regs->command); - struct ehci_qh *prev; - -#ifdef DEBUG - assert_spin_locked(&oxu->lock); - if (oxu->reclaim || (qh->qh_state != QH_STATE_LINKED - && qh->qh_state != QH_STATE_UNLINK_WAIT)) - BUG(); -#endif - - /* stop async schedule right now? */ - if (unlikely(qh == oxu->async)) { - /* can't get here without STS_ASS set */ - if (oxu_to_hcd(oxu)->state != HC_STATE_HALT - && !oxu->reclaim) { - /* ... and CMD_IAAD clear */ - writel(cmd & ~CMD_ASE, &oxu->regs->command); - wmb(); - /* handshake later, if we need to */ - timer_action_done(oxu, TIMER_ASYNC_OFF); - } - return; - } - - qh->qh_state = QH_STATE_UNLINK; - oxu->reclaim = qh = qh_get(qh); - - prev = oxu->async; - while (prev->qh_next.qh != qh) - prev = prev->qh_next.qh; - - prev->hw_next = qh->hw_next; - prev->qh_next = qh->qh_next; - wmb(); - - if (unlikely(oxu_to_hcd(oxu)->state == HC_STATE_HALT)) { - /* if (unlikely(qh->reclaim != 0)) - * this will recurse, probably not much - */ - end_unlink_async(oxu); - return; - } - - oxu->reclaim_ready = 0; - cmd |= CMD_IAAD; - writel(cmd, &oxu->regs->command); - (void) readl(&oxu->regs->command); - timer_action(oxu, TIMER_IAA_WATCHDOG); -} - -static void scan_async(struct oxu_hcd *oxu) -{ - struct ehci_qh *qh; - enum ehci_timer_action action = TIMER_IO_WATCHDOG; - - if (!++(oxu->stamp)) - oxu->stamp++; - timer_action_done(oxu, TIMER_ASYNC_SHRINK); -rescan: - qh = oxu->async->qh_next.qh; - if (likely(qh != NULL)) { - do { - /* clean any finished work for this qh */ - if (!list_empty(&qh->qtd_list) - && qh->stamp != oxu->stamp) { - int temp; - - /* unlinks could happen here; completion - * reporting drops the lock. rescan using - * the latest schedule, but don't rescan - * qhs we already finished (no looping). - */ - qh = qh_get(qh); - qh->stamp = oxu->stamp; - temp = qh_completions(oxu, qh); - qh_put(qh); - if (temp != 0) - goto rescan; - } - - /* unlink idle entries, reducing HC PCI usage as well - * as HCD schedule-scanning costs. delay for any qh - * we just scanned, there's a not-unusual case that it - * doesn't stay idle for long. - * (plus, avoids some kind of re-activation race.) - */ - if (list_empty(&qh->qtd_list)) { - if (qh->stamp == oxu->stamp) - action = TIMER_ASYNC_SHRINK; - else if (!oxu->reclaim - && qh->qh_state == QH_STATE_LINKED) - start_unlink_async(oxu, qh); - } - - qh = qh->qh_next.qh; - } while (qh); - } - if (action == TIMER_ASYNC_SHRINK) - timer_action(oxu, TIMER_ASYNC_SHRINK); -} - -/* - * periodic_next_shadow - return "next" pointer on shadow list - * @periodic: host pointer to qh/itd/sitd - * @tag: hardware tag for type of this record - */ -static union ehci_shadow *periodic_next_shadow(union ehci_shadow *periodic, - __le32 tag) -{ - switch (tag) { - default: - case Q_TYPE_QH: - return &periodic->qh->qh_next; - } -} - -/* caller must hold oxu->lock */ -static void periodic_unlink(struct oxu_hcd *oxu, unsigned frame, void *ptr) -{ - union ehci_shadow *prev_p = &oxu->pshadow[frame]; - __le32 *hw_p = &oxu->periodic[frame]; - union ehci_shadow here = *prev_p; - - /* find predecessor of "ptr"; hw and shadow lists are in sync */ - while (here.ptr && here.ptr != ptr) { - prev_p = periodic_next_shadow(prev_p, Q_NEXT_TYPE(*hw_p)); - hw_p = here.hw_next; - here = *prev_p; - } - /* an interrupt entry (at list end) could have been shared */ - if (!here.ptr) - return; - - /* update shadow and hardware lists ... the old "next" pointers - * from ptr may still be in use, the caller updates them. - */ - *prev_p = *periodic_next_shadow(&here, Q_NEXT_TYPE(*hw_p)); - *hw_p = *here.hw_next; -} - -/* how many of the uframe's 125 usecs are allocated? */ -static unsigned short periodic_usecs(struct oxu_hcd *oxu, - unsigned frame, unsigned uframe) -{ - __le32 *hw_p = &oxu->periodic[frame]; - union ehci_shadow *q = &oxu->pshadow[frame]; - unsigned usecs = 0; - - while (q->ptr) { - switch (Q_NEXT_TYPE(*hw_p)) { - case Q_TYPE_QH: - default: - /* is it in the S-mask? */ - if (q->qh->hw_info2 & cpu_to_le32(1 << uframe)) - usecs += q->qh->usecs; - /* ... or C-mask? */ - if (q->qh->hw_info2 & cpu_to_le32(1 << (8 + uframe))) - usecs += q->qh->c_usecs; - hw_p = &q->qh->hw_next; - q = &q->qh->qh_next; - break; - } - } -#ifdef DEBUG - if (usecs > 100) - oxu_err(oxu, "uframe %d sched overrun: %d usecs\n", - frame * 8 + uframe, usecs); -#endif - return usecs; -} - -static int enable_periodic(struct oxu_hcd *oxu) -{ - u32 cmd; - int status; - - /* did clearing PSE did take effect yet? - * takes effect only at frame boundaries... - */ - status = handshake(oxu, &oxu->regs->status, STS_PSS, 0, 9 * 125); - if (status != 0) { - oxu_to_hcd(oxu)->state = HC_STATE_HALT; - usb_hc_died(oxu_to_hcd(oxu)); - return status; - } - - cmd = readl(&oxu->regs->command) | CMD_PSE; - writel(cmd, &oxu->regs->command); - /* posted write ... PSS happens later */ - oxu_to_hcd(oxu)->state = HC_STATE_RUNNING; - - /* make sure ehci_work scans these */ - oxu->next_uframe = readl(&oxu->regs->frame_index) - % (oxu->periodic_size << 3); - return 0; -} - -static int disable_periodic(struct oxu_hcd *oxu) -{ - u32 cmd; - int status; - - /* did setting PSE not take effect yet? - * takes effect only at frame boundaries... - */ - status = handshake(oxu, &oxu->regs->status, STS_PSS, STS_PSS, 9 * 125); - if (status != 0) { - oxu_to_hcd(oxu)->state = HC_STATE_HALT; - usb_hc_died(oxu_to_hcd(oxu)); - return status; - } - - cmd = readl(&oxu->regs->command) & ~CMD_PSE; - writel(cmd, &oxu->regs->command); - /* posted write ... */ - - oxu->next_uframe = -1; - return 0; -} - -/* periodic schedule slots have iso tds (normal or split) first, then a - * sparse tree for active interrupt transfers. - * - * this just links in a qh; caller guarantees uframe masks are set right. - * no FSTN support (yet; oxu 0.96+) - */ -static int qh_link_periodic(struct oxu_hcd *oxu, struct ehci_qh *qh) -{ - unsigned i; - unsigned period = qh->period; - - dev_dbg(&qh->dev->dev, - "link qh%d-%04x/%p start %d [%d/%d us]\n", - period, le32_to_cpup(&qh->hw_info2) & (QH_CMASK | QH_SMASK), - qh, qh->start, qh->usecs, qh->c_usecs); - - /* high bandwidth, or otherwise every microframe */ - if (period == 0) - period = 1; - - for (i = qh->start; i < oxu->periodic_size; i += period) { - union ehci_shadow *prev = &oxu->pshadow[i]; - __le32 *hw_p = &oxu->periodic[i]; - union ehci_shadow here = *prev; - __le32 type = 0; - - /* skip the iso nodes at list head */ - while (here.ptr) { - type = Q_NEXT_TYPE(*hw_p); - if (type == Q_TYPE_QH) - break; - prev = periodic_next_shadow(prev, type); - hw_p = &here.qh->hw_next; - here = *prev; - } - - /* sorting each branch by period (slow-->fast) - * enables sharing interior tree nodes - */ - while (here.ptr && qh != here.qh) { - if (qh->period > here.qh->period) - break; - prev = &here.qh->qh_next; - hw_p = &here.qh->hw_next; - here = *prev; - } - /* link in this qh, unless some earlier pass did that */ - if (qh != here.qh) { - qh->qh_next = here; - if (here.qh) - qh->hw_next = *hw_p; - wmb(); - prev->qh = qh; - *hw_p = QH_NEXT(qh->qh_dma); - } - } - qh->qh_state = QH_STATE_LINKED; - qh_get(qh); - - /* update per-qh bandwidth for usbfs */ - oxu_to_hcd(oxu)->self.bandwidth_allocated += qh->period - ? ((qh->usecs + qh->c_usecs) / qh->period) - : (qh->usecs * 8); - - /* maybe enable periodic schedule processing */ - if (!oxu->periodic_sched++) - return enable_periodic(oxu); - - return 0; -} - -static void qh_unlink_periodic(struct oxu_hcd *oxu, struct ehci_qh *qh) -{ - unsigned i; - unsigned period; - - /* FIXME: - * IF this isn't high speed - * and this qh is active in the current uframe - * (and overlay token SplitXstate is false?) - * THEN - * qh->hw_info1 |= cpu_to_le32(1 << 7 "ignore"); - */ - - /* high bandwidth, or otherwise part of every microframe */ - period = qh->period; - if (period == 0) - period = 1; - - for (i = qh->start; i < oxu->periodic_size; i += period) - periodic_unlink(oxu, i, qh); - - /* update per-qh bandwidth for usbfs */ - oxu_to_hcd(oxu)->self.bandwidth_allocated -= qh->period - ? ((qh->usecs + qh->c_usecs) / qh->period) - : (qh->usecs * 8); - - dev_dbg(&qh->dev->dev, - "unlink qh%d-%04x/%p start %d [%d/%d us]\n", - qh->period, - le32_to_cpup(&qh->hw_info2) & (QH_CMASK | QH_SMASK), - qh, qh->start, qh->usecs, qh->c_usecs); - - /* qh->qh_next still "live" to HC */ - qh->qh_state = QH_STATE_UNLINK; - qh->qh_next.ptr = NULL; - qh_put(qh); - - /* maybe turn off periodic schedule */ - oxu->periodic_sched--; - if (!oxu->periodic_sched) - (void) disable_periodic(oxu); -} - -static void intr_deschedule(struct oxu_hcd *oxu, struct ehci_qh *qh) -{ - unsigned wait; - - qh_unlink_periodic(oxu, qh); - - /* simple/paranoid: always delay, expecting the HC needs to read - * qh->hw_next or finish a writeback after SPLIT/CSPLIT ... and - * expect khubd to clean up after any CSPLITs we won't issue. - * active high speed queues may need bigger delays... - */ - if (list_empty(&qh->qtd_list) - || (cpu_to_le32(QH_CMASK) & qh->hw_info2) != 0) - wait = 2; - else - wait = 55; /* worst case: 3 * 1024 */ - - udelay(wait); - qh->qh_state = QH_STATE_IDLE; - qh->hw_next = EHCI_LIST_END; - wmb(); -} - -static int check_period(struct oxu_hcd *oxu, - unsigned frame, unsigned uframe, - unsigned period, unsigned usecs) -{ - int claimed; - - /* complete split running into next frame? - * given FSTN support, we could sometimes check... - */ - if (uframe >= 8) - return 0; - - /* - * 80% periodic == 100 usec/uframe available - * convert "usecs we need" to "max already claimed" - */ - usecs = 100 - usecs; - - /* we "know" 2 and 4 uframe intervals were rejected; so - * for period 0, check _every_ microframe in the schedule. - */ - if (unlikely(period == 0)) { - do { - for (uframe = 0; uframe < 7; uframe++) { - claimed = periodic_usecs(oxu, frame, uframe); - if (claimed > usecs) - return 0; - } - } while ((frame += 1) < oxu->periodic_size); - - /* just check the specified uframe, at that period */ - } else { - do { - claimed = periodic_usecs(oxu, frame, uframe); - if (claimed > usecs) - return 0; - } while ((frame += period) < oxu->periodic_size); - } - - return 1; -} - -static int check_intr_schedule(struct oxu_hcd *oxu, - unsigned frame, unsigned uframe, - const struct ehci_qh *qh, __le32 *c_maskp) -{ - int retval = -ENOSPC; - - if (qh->c_usecs && uframe >= 6) /* FSTN territory? */ - goto done; - - if (!check_period(oxu, frame, uframe, qh->period, qh->usecs)) - goto done; - if (!qh->c_usecs) { - retval = 0; - *c_maskp = 0; - goto done; - } - -done: - return retval; -} - -/* "first fit" scheduling policy used the first time through, - * or when the previous schedule slot can't be re-used. - */ -static int qh_schedule(struct oxu_hcd *oxu, struct ehci_qh *qh) -{ - int status; - unsigned uframe; - __le32 c_mask; - unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */ - - qh_refresh(oxu, qh); - qh->hw_next = EHCI_LIST_END; - frame = qh->start; - - /* reuse the previous schedule slots, if we can */ - if (frame < qh->period) { - uframe = ffs(le32_to_cpup(&qh->hw_info2) & QH_SMASK); - status = check_intr_schedule(oxu, frame, --uframe, - qh, &c_mask); - } else { - uframe = 0; - c_mask = 0; - status = -ENOSPC; - } - - /* else scan the schedule to find a group of slots such that all - * uframes have enough periodic bandwidth available. - */ - if (status) { - /* "normal" case, uframing flexible except with splits */ - if (qh->period) { - frame = qh->period - 1; - do { - for (uframe = 0; uframe < 8; uframe++) { - status = check_intr_schedule(oxu, - frame, uframe, qh, - &c_mask); - if (status == 0) - break; - } - } while (status && frame--); - - /* qh->period == 0 means every uframe */ - } else { - frame = 0; - status = check_intr_schedule(oxu, 0, 0, qh, &c_mask); - } - if (status) - goto done; - qh->start = frame; - - /* reset S-frame and (maybe) C-frame masks */ - qh->hw_info2 &= cpu_to_le32(~(QH_CMASK | QH_SMASK)); - qh->hw_info2 |= qh->period - ? cpu_to_le32(1 << uframe) - : cpu_to_le32(QH_SMASK); - qh->hw_info2 |= c_mask; - } else - oxu_dbg(oxu, "reused qh %p schedule\n", qh); - - /* stuff into the periodic schedule */ - status = qh_link_periodic(oxu, qh); -done: - return status; -} - -static int intr_submit(struct oxu_hcd *oxu, struct urb *urb, - struct list_head *qtd_list, gfp_t mem_flags) -{ - unsigned epnum; - unsigned long flags; - struct ehci_qh *qh; - int status = 0; - struct list_head empty; - - /* get endpoint and transfer/schedule data */ - epnum = urb->ep->desc.bEndpointAddress; - - spin_lock_irqsave(&oxu->lock, flags); - - if (unlikely(!HCD_HW_ACCESSIBLE(oxu_to_hcd(oxu)))) { - status = -ESHUTDOWN; - goto done; - } - - /* get qh and force any scheduling errors */ - INIT_LIST_HEAD(&empty); - qh = qh_append_tds(oxu, urb, &empty, epnum, &urb->ep->hcpriv); - if (qh == NULL) { - status = -ENOMEM; - goto done; - } - if (qh->qh_state == QH_STATE_IDLE) { - status = qh_schedule(oxu, qh); - if (status != 0) - goto done; - } - - /* then queue the urb's tds to the qh */ - qh = qh_append_tds(oxu, urb, qtd_list, epnum, &urb->ep->hcpriv); - BUG_ON(qh == NULL); - - /* ... update usbfs periodic stats */ - oxu_to_hcd(oxu)->self.bandwidth_int_reqs++; - -done: - spin_unlock_irqrestore(&oxu->lock, flags); - if (status) - qtd_list_free(oxu, urb, qtd_list); - - return status; -} - -static inline int itd_submit(struct oxu_hcd *oxu, struct urb *urb, - gfp_t mem_flags) -{ - oxu_dbg(oxu, "iso support is missing!\n"); - return -ENOSYS; -} - -static inline int sitd_submit(struct oxu_hcd *oxu, struct urb *urb, - gfp_t mem_flags) -{ - oxu_dbg(oxu, "split iso support is missing!\n"); - return -ENOSYS; -} - -static void scan_periodic(struct oxu_hcd *oxu) -{ - unsigned frame, clock, now_uframe, mod; - unsigned modified; - - mod = oxu->periodic_size << 3; - - /* - * When running, scan from last scan point up to "now" - * else clean up by scanning everything that's left. - * Touches as few pages as possible: cache-friendly. - */ - now_uframe = oxu->next_uframe; - if (HC_IS_RUNNING(oxu_to_hcd(oxu)->state)) - clock = readl(&oxu->regs->frame_index); - else - clock = now_uframe + mod - 1; - clock %= mod; - - for (;;) { - union ehci_shadow q, *q_p; - __le32 type, *hw_p; - unsigned uframes; - - /* don't scan past the live uframe */ - frame = now_uframe >> 3; - if (frame == (clock >> 3)) - uframes = now_uframe & 0x07; - else { - /* safe to scan the whole frame at once */ - now_uframe |= 0x07; - uframes = 8; - } - -restart: - /* scan each element in frame's queue for completions */ - q_p = &oxu->pshadow[frame]; - hw_p = &oxu->periodic[frame]; - q.ptr = q_p->ptr; - type = Q_NEXT_TYPE(*hw_p); - modified = 0; - - while (q.ptr != NULL) { - union ehci_shadow temp; - int live; - - live = HC_IS_RUNNING(oxu_to_hcd(oxu)->state); - switch (type) { - case Q_TYPE_QH: - /* handle any completions */ - temp.qh = qh_get(q.qh); - type = Q_NEXT_TYPE(q.qh->hw_next); - q = q.qh->qh_next; - modified = qh_completions(oxu, temp.qh); - if (unlikely(list_empty(&temp.qh->qtd_list))) - intr_deschedule(oxu, temp.qh); - qh_put(temp.qh); - break; - default: - dbg("corrupt type %d frame %d shadow %p", - type, frame, q.ptr); - q.ptr = NULL; - } - - /* assume completion callbacks modify the queue */ - if (unlikely(modified)) - goto restart; - } - - /* Stop when we catch up to the HC */ - - /* FIXME: this assumes we won't get lapped when - * latencies climb; that should be rare, but... - * detect it, and just go all the way around. - * FLR might help detect this case, so long as latencies - * don't exceed periodic_size msec (default 1.024 sec). - */ - - /* FIXME: likewise assumes HC doesn't halt mid-scan */ - - if (now_uframe == clock) { - unsigned now; - - if (!HC_IS_RUNNING(oxu_to_hcd(oxu)->state)) - break; - oxu->next_uframe = now_uframe; - now = readl(&oxu->regs->frame_index) % mod; - if (now_uframe == now) - break; - - /* rescan the rest of this frame, then ... */ - clock = now; - } else { - now_uframe++; - now_uframe %= mod; - } - } -} - -/* On some systems, leaving remote wakeup enabled prevents system shutdown. - * The firmware seems to think that powering off is a wakeup event! - * This routine turns off remote wakeup and everything else, on all ports. - */ -static void ehci_turn_off_all_ports(struct oxu_hcd *oxu) -{ - int port = HCS_N_PORTS(oxu->hcs_params); - - while (port--) - writel(PORT_RWC_BITS, &oxu->regs->port_status[port]); -} - -static void ehci_port_power(struct oxu_hcd *oxu, int is_on) -{ - unsigned port; - - if (!HCS_PPC(oxu->hcs_params)) - return; - - oxu_dbg(oxu, "...power%s ports...\n", is_on ? "up" : "down"); - for (port = HCS_N_PORTS(oxu->hcs_params); port > 0; ) - (void) oxu_hub_control(oxu_to_hcd(oxu), - is_on ? SetPortFeature : ClearPortFeature, - USB_PORT_FEAT_POWER, - port--, NULL, 0); - msleep(20); -} - -/* Called from some interrupts, timers, and so on. - * It calls driver completion functions, after dropping oxu->lock. - */ -static void ehci_work(struct oxu_hcd *oxu) -{ - timer_action_done(oxu, TIMER_IO_WATCHDOG); - if (oxu->reclaim_ready) - end_unlink_async(oxu); - - /* another CPU may drop oxu->lock during a schedule scan while - * it reports urb completions. this flag guards against bogus - * attempts at re-entrant schedule scanning. - */ - if (oxu->scanning) - return; - oxu->scanning = 1; - scan_async(oxu); - if (oxu->next_uframe != -1) - scan_periodic(oxu); - oxu->scanning = 0; - - /* the IO watchdog guards against hardware or driver bugs that - * misplace IRQs, and should let us run completely without IRQs. - * such lossage has been observed on both VT6202 and VT8235. - */ - if (HC_IS_RUNNING(oxu_to_hcd(oxu)->state) && - (oxu->async->qh_next.ptr != NULL || - oxu->periodic_sched != 0)) - timer_action(oxu, TIMER_IO_WATCHDOG); -} - -static void unlink_async(struct oxu_hcd *oxu, struct ehci_qh *qh) -{ - /* if we need to use IAA and it's busy, defer */ - if (qh->qh_state == QH_STATE_LINKED - && oxu->reclaim - && HC_IS_RUNNING(oxu_to_hcd(oxu)->state)) { - struct ehci_qh *last; - - for (last = oxu->reclaim; - last->reclaim; - last = last->reclaim) - continue; - qh->qh_state = QH_STATE_UNLINK_WAIT; - last->reclaim = qh; - - /* bypass IAA if the hc can't care */ - } else if (!HC_IS_RUNNING(oxu_to_hcd(oxu)->state) && oxu->reclaim) - end_unlink_async(oxu); - - /* something else might have unlinked the qh by now */ - if (qh->qh_state == QH_STATE_LINKED) - start_unlink_async(oxu, qh); -} - -/* - * USB host controller methods - */ - -static irqreturn_t oxu210_hcd_irq(struct usb_hcd *hcd) -{ - struct oxu_hcd *oxu = hcd_to_oxu(hcd); - u32 status, pcd_status = 0; - int bh; - - spin_lock(&oxu->lock); - - status = readl(&oxu->regs->status); - - /* e.g. cardbus physical eject */ - if (status == ~(u32) 0) { - oxu_dbg(oxu, "device removed\n"); - goto dead; - } - - /* Shared IRQ? */ - status &= INTR_MASK; - if (!status || unlikely(hcd->state == HC_STATE_HALT)) { - spin_unlock(&oxu->lock); - return IRQ_NONE; - } - - /* clear (just) interrupts */ - writel(status, &oxu->regs->status); - readl(&oxu->regs->command); /* unblock posted write */ - bh = 0; - -#ifdef OXU_VERBOSE_DEBUG - /* unrequested/ignored: Frame List Rollover */ - dbg_status(oxu, "irq", status); -#endif - - /* INT, ERR, and IAA interrupt rates can be throttled */ - - /* normal [4.15.1.2] or error [4.15.1.1] completion */ - if (likely((status & (STS_INT|STS_ERR)) != 0)) - bh = 1; - - /* complete the unlinking of some qh [4.15.2.3] */ - if (status & STS_IAA) { - oxu->reclaim_ready = 1; - bh = 1; - } - - /* remote wakeup [4.3.1] */ - if (status & STS_PCD) { - unsigned i = HCS_N_PORTS(oxu->hcs_params); - pcd_status = status; - - /* resume root hub? */ - if (!(readl(&oxu->regs->command) & CMD_RUN)) - usb_hcd_resume_root_hub(hcd); - - while (i--) { - int pstatus = readl(&oxu->regs->port_status[i]); - - if (pstatus & PORT_OWNER) - continue; - if (!(pstatus & PORT_RESUME) - || oxu->reset_done[i] != 0) - continue; - - /* start 20 msec resume signaling from this port, - * and make khubd collect PORT_STAT_C_SUSPEND to - * stop that signaling. - */ - oxu->reset_done[i] = jiffies + msecs_to_jiffies(20); - oxu_dbg(oxu, "port %d remote wakeup\n", i + 1); - mod_timer(&hcd->rh_timer, oxu->reset_done[i]); - } - } - - /* PCI errors [4.15.2.4] */ - if (unlikely((status & STS_FATAL) != 0)) { - /* bogus "fatal" IRQs appear on some chips... why? */ - status = readl(&oxu->regs->status); - dbg_cmd(oxu, "fatal", readl(&oxu->regs->command)); - dbg_status(oxu, "fatal", status); - if (status & STS_HALT) { - oxu_err(oxu, "fatal error\n"); -dead: - ehci_reset(oxu); - writel(0, &oxu->regs->configured_flag); - usb_hc_died(hcd); - /* generic layer kills/unlinks all urbs, then - * uses oxu_stop to clean up the rest - */ - bh = 1; - } - } - - if (bh) - ehci_work(oxu); - spin_unlock(&oxu->lock); - if (pcd_status & STS_PCD) - usb_hcd_poll_rh_status(hcd); - return IRQ_HANDLED; -} - -static irqreturn_t oxu_irq(struct usb_hcd *hcd) -{ - struct oxu_hcd *oxu = hcd_to_oxu(hcd); - int ret = IRQ_HANDLED; - - u32 status = oxu_readl(hcd->regs, OXU_CHIPIRQSTATUS); - u32 enable = oxu_readl(hcd->regs, OXU_CHIPIRQEN_SET); - - /* Disable all interrupt */ - oxu_writel(hcd->regs, OXU_CHIPIRQEN_CLR, enable); - - if ((oxu->is_otg && (status & OXU_USBOTGI)) || - (!oxu->is_otg && (status & OXU_USBSPHI))) - oxu210_hcd_irq(hcd); - else - ret = IRQ_NONE; - - /* Enable all interrupt back */ - oxu_writel(hcd->regs, OXU_CHIPIRQEN_SET, enable); - - return ret; -} - -static void oxu_watchdog(unsigned long param) -{ - struct oxu_hcd *oxu = (struct oxu_hcd *) param; - unsigned long flags; - - spin_lock_irqsave(&oxu->lock, flags); - - /* lost IAA irqs wedge things badly; seen with a vt8235 */ - if (oxu->reclaim) { - u32 status = readl(&oxu->regs->status); - if (status & STS_IAA) { - oxu_vdbg(oxu, "lost IAA\n"); - writel(STS_IAA, &oxu->regs->status); - oxu->reclaim_ready = 1; - } - } - - /* stop async processing after it's idled a bit */ - if (test_bit(TIMER_ASYNC_OFF, &oxu->actions)) - start_unlink_async(oxu, oxu->async); - - /* oxu could run by timer, without IRQs ... */ - ehci_work(oxu); - - spin_unlock_irqrestore(&oxu->lock, flags); -} - -/* One-time init, only for memory state. - */ -static int oxu_hcd_init(struct usb_hcd *hcd) -{ - struct oxu_hcd *oxu = hcd_to_oxu(hcd); - u32 temp; - int retval; - u32 hcc_params; - - spin_lock_init(&oxu->lock); - - init_timer(&oxu->watchdog); - oxu->watchdog.function = oxu_watchdog; - oxu->watchdog.data = (unsigned long) oxu; - - /* - * hw default: 1K periodic list heads, one per frame. - * periodic_size can shrink by USBCMD update if hcc_params allows. - */ - oxu->periodic_size = DEFAULT_I_TDPS; - retval = ehci_mem_init(oxu, GFP_KERNEL); - if (retval < 0) - return retval; - - /* controllers may cache some of the periodic schedule ... */ - hcc_params = readl(&oxu->caps->hcc_params); - if (HCC_ISOC_CACHE(hcc_params)) /* full frame cache */ - oxu->i_thresh = 8; - else /* N microframes cached */ - oxu->i_thresh = 2 + HCC_ISOC_THRES(hcc_params); - - oxu->reclaim = NULL; - oxu->reclaim_ready = 0; - oxu->next_uframe = -1; - - /* - * dedicate a qh for the async ring head, since we couldn't unlink - * a 'real' qh without stopping the async schedule [4.8]. use it - * as the 'reclamation list head' too. - * its dummy is used in hw_alt_next of many tds, to prevent the qh - * from automatically advancing to the next td after short reads. - */ - oxu->async->qh_next.qh = NULL; - oxu->async->hw_next = QH_NEXT(oxu->async->qh_dma); - oxu->async->hw_info1 = cpu_to_le32(QH_HEAD); - oxu->async->hw_token = cpu_to_le32(QTD_STS_HALT); - oxu->async->hw_qtd_next = EHCI_LIST_END; - oxu->async->qh_state = QH_STATE_LINKED; - oxu->async->hw_alt_next = QTD_NEXT(oxu->async->dummy->qtd_dma); - - /* clear interrupt enables, set irq latency */ - if (log2_irq_thresh < 0 || log2_irq_thresh > 6) - log2_irq_thresh = 0; - temp = 1 << (16 + log2_irq_thresh); - if (HCC_CANPARK(hcc_params)) { - /* HW default park == 3, on hardware that supports it (like - * NVidia and ALI silicon), maximizes throughput on the async - * schedule by avoiding QH fetches between transfers. - * - * With fast usb storage devices and NForce2, "park" seems to - * make problems: throughput reduction (!), data errors... - */ - if (park) { - park = min(park, (unsigned) 3); - temp |= CMD_PARK; - temp |= park << 8; - } - oxu_dbg(oxu, "park %d\n", park); - } - if (HCC_PGM_FRAMELISTLEN(hcc_params)) { - /* periodic schedule size can be smaller than default */ - temp &= ~(3 << 2); - temp |= (EHCI_TUNE_FLS << 2); - } - oxu->command = temp; - - return 0; -} - -/* Called during probe() after chip reset completes. - */ -static int oxu_reset(struct usb_hcd *hcd) -{ - struct oxu_hcd *oxu = hcd_to_oxu(hcd); - int ret; - - spin_lock_init(&oxu->mem_lock); - INIT_LIST_HEAD(&oxu->urb_list); - oxu->urb_len = 0; - - /* FIMXE */ - hcd->self.controller->dma_mask = NULL; - - if (oxu->is_otg) { - oxu->caps = hcd->regs + OXU_OTG_CAP_OFFSET; - oxu->regs = hcd->regs + OXU_OTG_CAP_OFFSET + \ - HC_LENGTH(readl(&oxu->caps->hc_capbase)); - - oxu->mem = hcd->regs + OXU_SPH_MEM; - } else { - oxu->caps = hcd->regs + OXU_SPH_CAP_OFFSET; - oxu->regs = hcd->regs + OXU_SPH_CAP_OFFSET + \ - HC_LENGTH(readl(&oxu->caps->hc_capbase)); - - oxu->mem = hcd->regs + OXU_OTG_MEM; - } - - oxu->hcs_params = readl(&oxu->caps->hcs_params); - oxu->sbrn = 0x20; - - ret = oxu_hcd_init(hcd); - if (ret) - return ret; - - return 0; -} - -static int oxu_run(struct usb_hcd *hcd) -{ - struct oxu_hcd *oxu = hcd_to_oxu(hcd); - int retval; - u32 temp, hcc_params; - - hcd->uses_new_polling = 1; - - /* EHCI spec section 4.1 */ - retval = ehci_reset(oxu); - if (retval != 0) { - ehci_mem_cleanup(oxu); - return retval; - } - writel(oxu->periodic_dma, &oxu->regs->frame_list); - writel((u32) oxu->async->qh_dma, &oxu->regs->async_next); - - /* hcc_params controls whether oxu->regs->segment must (!!!) - * be used; it constrains QH/ITD/SITD and QTD locations. - * pci_pool consistent memory always uses segment zero. - * streaming mappings for I/O buffers, like pci_map_single(), - * can return segments above 4GB, if the device allows. - * - * NOTE: the dma mask is visible through dma_supported(), so - * drivers can pass this info along ... like NETIF_F_HIGHDMA, - * Scsi_Host.highmem_io, and so forth. It's readonly to all - * host side drivers though. - */ - hcc_params = readl(&oxu->caps->hcc_params); - if (HCC_64BIT_ADDR(hcc_params)) - writel(0, &oxu->regs->segment); - - oxu->command &= ~(CMD_LRESET | CMD_IAAD | CMD_PSE | - CMD_ASE | CMD_RESET); - oxu->command |= CMD_RUN; - writel(oxu->command, &oxu->regs->command); - dbg_cmd(oxu, "init", oxu->command); - - /* - * Start, enabling full USB 2.0 functionality ... usb 1.1 devices - * are explicitly handed to companion controller(s), so no TT is - * involved with the root hub. (Except where one is integrated, - * and there's no companion controller unless maybe for USB OTG.) - */ - hcd->state = HC_STATE_RUNNING; - writel(FLAG_CF, &oxu->regs->configured_flag); - readl(&oxu->regs->command); /* unblock posted writes */ - - temp = HC_VERSION(readl(&oxu->caps->hc_capbase)); - oxu_info(oxu, "USB %x.%x started, quasi-EHCI %x.%02x, driver %s%s\n", - ((oxu->sbrn & 0xf0)>>4), (oxu->sbrn & 0x0f), - temp >> 8, temp & 0xff, DRIVER_VERSION, - ignore_oc ? ", overcurrent ignored" : ""); - - writel(INTR_MASK, &oxu->regs->intr_enable); /* Turn On Interrupts */ - - return 0; -} - -static void oxu_stop(struct usb_hcd *hcd) -{ - struct oxu_hcd *oxu = hcd_to_oxu(hcd); - - /* Turn off port power on all root hub ports. */ - ehci_port_power(oxu, 0); - - /* no more interrupts ... */ - del_timer_sync(&oxu->watchdog); - - spin_lock_irq(&oxu->lock); - if (HC_IS_RUNNING(hcd->state)) - ehci_quiesce(oxu); - - ehci_reset(oxu); - writel(0, &oxu->regs->intr_enable); - spin_unlock_irq(&oxu->lock); - - /* let companion controllers work when we aren't */ - writel(0, &oxu->regs->configured_flag); - - /* root hub is shut down separately (first, when possible) */ - spin_lock_irq(&oxu->lock); - if (oxu->async) - ehci_work(oxu); - spin_unlock_irq(&oxu->lock); - ehci_mem_cleanup(oxu); - - dbg_status(oxu, "oxu_stop completed", readl(&oxu->regs->status)); -} - -/* Kick in for silicon on any bus (not just pci, etc). - * This forcibly disables dma and IRQs, helping kexec and other cases - * where the next system software may expect clean state. - */ -static void oxu_shutdown(struct usb_hcd *hcd) -{ - struct oxu_hcd *oxu = hcd_to_oxu(hcd); - - (void) ehci_halt(oxu); - ehci_turn_off_all_ports(oxu); - - /* make BIOS/etc use companion controller during reboot */ - writel(0, &oxu->regs->configured_flag); - - /* unblock posted writes */ - readl(&oxu->regs->configured_flag); -} - -/* Non-error returns are a promise to giveback() the urb later - * we drop ownership so next owner (or urb unlink) can get it - * - * urb + dev is in hcd.self.controller.urb_list - * we're queueing TDs onto software and hardware lists - * - * hcd-specific init for hcpriv hasn't been done yet - * - * NOTE: control, bulk, and interrupt share the same code to append TDs - * to a (possibly active) QH, and the same QH scanning code. - */ -static int __oxu_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, - gfp_t mem_flags) -{ - struct oxu_hcd *oxu = hcd_to_oxu(hcd); - struct list_head qtd_list; - - INIT_LIST_HEAD(&qtd_list); - - switch (usb_pipetype(urb->pipe)) { - case PIPE_CONTROL: - case PIPE_BULK: - default: - if (!qh_urb_transaction(oxu, urb, &qtd_list, mem_flags)) - return -ENOMEM; - return submit_async(oxu, urb, &qtd_list, mem_flags); - - case PIPE_INTERRUPT: - if (!qh_urb_transaction(oxu, urb, &qtd_list, mem_flags)) - return -ENOMEM; - return intr_submit(oxu, urb, &qtd_list, mem_flags); - - case PIPE_ISOCHRONOUS: - if (urb->dev->speed == USB_SPEED_HIGH) - return itd_submit(oxu, urb, mem_flags); - else - return sitd_submit(oxu, urb, mem_flags); - } -} - -/* This function is responsible for breaking URBs with big data size - * into smaller size and processing small urbs in sequence. - */ -static int oxu_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, - gfp_t mem_flags) -{ - struct oxu_hcd *oxu = hcd_to_oxu(hcd); - int num, rem; - int transfer_buffer_length; - void *transfer_buffer; - struct urb *murb; - int i, ret; - - /* If not bulk pipe just enqueue the URB */ - if (!usb_pipebulk(urb->pipe)) - return __oxu_urb_enqueue(hcd, urb, mem_flags); - - /* Otherwise we should verify the USB transfer buffer size! */ - transfer_buffer = urb->transfer_buffer; - transfer_buffer_length = urb->transfer_buffer_length; - - num = urb->transfer_buffer_length / 4096; - rem = urb->transfer_buffer_length % 4096; - if (rem != 0) - num++; - - /* If URB is smaller than 4096 bytes just enqueue it! */ - if (num == 1) - return __oxu_urb_enqueue(hcd, urb, mem_flags); - - /* Ok, we have more job to do! :) */ - - for (i = 0; i < num - 1; i++) { - /* Get free micro URB poll till a free urb is received */ - - do { - murb = (struct urb *) oxu_murb_alloc(oxu); - if (!murb) - schedule(); - } while (!murb); - - /* Coping the urb */ - memcpy(murb, urb, sizeof(struct urb)); - - murb->transfer_buffer_length = 4096; - murb->transfer_buffer = transfer_buffer + i * 4096; - - /* Null pointer for the encodes that this is a micro urb */ - murb->complete = NULL; - - ((struct oxu_murb *) murb)->main = urb; - ((struct oxu_murb *) murb)->last = 0; - - /* This loop is to guarantee urb to be processed when there's - * not enough resources at a particular time by retrying. - */ - do { - ret = __oxu_urb_enqueue(hcd, murb, mem_flags); - if (ret) - schedule(); - } while (ret); - } - - /* Last urb requires special handling */ - - /* Get free micro URB poll till a free urb is received */ - do { - murb = (struct urb *) oxu_murb_alloc(oxu); - if (!murb) - schedule(); - } while (!murb); - - /* Coping the urb */ - memcpy(murb, urb, sizeof(struct urb)); - - murb->transfer_buffer_length = rem > 0 ? rem : 4096; - murb->transfer_buffer = transfer_buffer + (num - 1) * 4096; - - /* Null pointer for the encodes that this is a micro urb */ - murb->complete = NULL; - - ((struct oxu_murb *) murb)->main = urb; - ((struct oxu_murb *) murb)->last = 1; - - do { - ret = __oxu_urb_enqueue(hcd, murb, mem_flags); - if (ret) - schedule(); - } while (ret); - - return ret; -} - -/* Remove from hardware lists. - * Completions normally happen asynchronously - */ -static int oxu_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) -{ - struct oxu_hcd *oxu = hcd_to_oxu(hcd); - struct ehci_qh *qh; - unsigned long flags; - - spin_lock_irqsave(&oxu->lock, flags); - switch (usb_pipetype(urb->pipe)) { - case PIPE_CONTROL: - case PIPE_BULK: - default: - qh = (struct ehci_qh *) urb->hcpriv; - if (!qh) - break; - unlink_async(oxu, qh); - break; - - case PIPE_INTERRUPT: - qh = (struct ehci_qh *) urb->hcpriv; - if (!qh) - break; - switch (qh->qh_state) { - case QH_STATE_LINKED: - intr_deschedule(oxu, qh); - /* FALL THROUGH */ - case QH_STATE_IDLE: - qh_completions(oxu, qh); - break; - default: - oxu_dbg(oxu, "bogus qh %p state %d\n", - qh, qh->qh_state); - goto done; - } - - /* reschedule QH iff another request is queued */ - if (!list_empty(&qh->qtd_list) - && HC_IS_RUNNING(hcd->state)) { - int status; - - status = qh_schedule(oxu, qh); - spin_unlock_irqrestore(&oxu->lock, flags); - - if (status != 0) { - /* shouldn't happen often, but ... - * FIXME kill those tds' urbs - */ - err("can't reschedule qh %p, err %d", - qh, status); - } - return status; - } - break; - } -done: - spin_unlock_irqrestore(&oxu->lock, flags); - return 0; -} - -/* Bulk qh holds the data toggle */ -static void oxu_endpoint_disable(struct usb_hcd *hcd, - struct usb_host_endpoint *ep) -{ - struct oxu_hcd *oxu = hcd_to_oxu(hcd); - unsigned long flags; - struct ehci_qh *qh, *tmp; - - /* ASSERT: any requests/urbs are being unlinked */ - /* ASSERT: nobody can be submitting urbs for this any more */ - -rescan: - spin_lock_irqsave(&oxu->lock, flags); - qh = ep->hcpriv; - if (!qh) - goto done; - - /* endpoints can be iso streams. for now, we don't - * accelerate iso completions ... so spin a while. - */ - if (qh->hw_info1 == 0) { - oxu_vdbg(oxu, "iso delay\n"); - goto idle_timeout; - } - - if (!HC_IS_RUNNING(hcd->state)) - qh->qh_state = QH_STATE_IDLE; - switch (qh->qh_state) { - case QH_STATE_LINKED: - for (tmp = oxu->async->qh_next.qh; - tmp && tmp != qh; - tmp = tmp->qh_next.qh) - continue; - /* periodic qh self-unlinks on empty */ - if (!tmp) - goto nogood; - unlink_async(oxu, qh); - /* FALL THROUGH */ - case QH_STATE_UNLINK: /* wait for hw to finish? */ -idle_timeout: - spin_unlock_irqrestore(&oxu->lock, flags); - schedule_timeout_uninterruptible(1); - goto rescan; - case QH_STATE_IDLE: /* fully unlinked */ - if (list_empty(&qh->qtd_list)) { - qh_put(qh); - break; - } - /* else FALL THROUGH */ - default: -nogood: - /* caller was supposed to have unlinked any requests; - * that's not our job. just leak this memory. - */ - oxu_err(oxu, "qh %p (#%02x) state %d%s\n", - qh, ep->desc.bEndpointAddress, qh->qh_state, - list_empty(&qh->qtd_list) ? "" : "(has tds)"); - break; - } - ep->hcpriv = NULL; -done: - spin_unlock_irqrestore(&oxu->lock, flags); -} - -static int oxu_get_frame(struct usb_hcd *hcd) -{ - struct oxu_hcd *oxu = hcd_to_oxu(hcd); - - return (readl(&oxu->regs->frame_index) >> 3) % - oxu->periodic_size; -} - -/* Build "status change" packet (one or two bytes) from HC registers */ -static int oxu_hub_status_data(struct usb_hcd *hcd, char *buf) -{ - struct oxu_hcd *oxu = hcd_to_oxu(hcd); - u32 temp, mask, status = 0; - int ports, i, retval = 1; - unsigned long flags; - - /* if !USB_SUSPEND, root hub timers won't get shut down ... */ - if (!HC_IS_RUNNING(hcd->state)) - return 0; - - /* init status to no-changes */ - buf[0] = 0; - ports = HCS_N_PORTS(oxu->hcs_params); - if (ports > 7) { - buf[1] = 0; - retval++; - } - - /* Some boards (mostly VIA?) report bogus overcurrent indications, - * causing massive log spam unless we completely ignore them. It - * may be relevant that VIA VT8235 controllers, where PORT_POWER is - * always set, seem to clear PORT_OCC and PORT_CSC when writing to - * PORT_POWER; that's surprising, but maybe within-spec. - */ - if (!ignore_oc) - mask = PORT_CSC | PORT_PEC | PORT_OCC; - else - mask = PORT_CSC | PORT_PEC; - - /* no hub change reports (bit 0) for now (power, ...) */ - - /* port N changes (bit N)? */ - spin_lock_irqsave(&oxu->lock, flags); - for (i = 0; i < ports; i++) { - temp = readl(&oxu->regs->port_status[i]); - - /* - * Return status information even for ports with OWNER set. - * Otherwise khubd wouldn't see the disconnect event when a - * high-speed device is switched over to the companion - * controller by the user. - */ - - if (!(temp & PORT_CONNECT)) - oxu->reset_done[i] = 0; - if ((temp & mask) != 0 || ((temp & PORT_RESUME) != 0 && - time_after_eq(jiffies, oxu->reset_done[i]))) { - if (i < 7) - buf[0] |= 1 << (i + 1); - else - buf[1] |= 1 << (i - 7); - status = STS_PCD; - } - } - /* FIXME autosuspend idle root hubs */ - spin_unlock_irqrestore(&oxu->lock, flags); - return status ? retval : 0; -} - -/* Returns the speed of a device attached to a port on the root hub. */ -static inline unsigned int oxu_port_speed(struct oxu_hcd *oxu, - unsigned int portsc) -{ - switch ((portsc >> 26) & 3) { - case 0: - return 0; - case 1: - return USB_PORT_STAT_LOW_SPEED; - case 2: - default: - return USB_PORT_STAT_HIGH_SPEED; - } -} - -#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E) -static int oxu_hub_control(struct usb_hcd *hcd, u16 typeReq, - u16 wValue, u16 wIndex, char *buf, u16 wLength) -{ - struct oxu_hcd *oxu = hcd_to_oxu(hcd); - int ports = HCS_N_PORTS(oxu->hcs_params); - u32 __iomem *status_reg = &oxu->regs->port_status[wIndex - 1]; - u32 temp, status; - unsigned long flags; - int retval = 0; - unsigned selector; - - /* - * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR. - * HCS_INDICATOR may say we can change LEDs to off/amber/green. - * (track current state ourselves) ... blink for diagnostics, - * power, "this is the one", etc. EHCI spec supports this. - */ - - spin_lock_irqsave(&oxu->lock, flags); - switch (typeReq) { - case ClearHubFeature: - switch (wValue) { - case C_HUB_LOCAL_POWER: - case C_HUB_OVER_CURRENT: - /* no hub-wide feature/status flags */ - break; - default: - goto error; - } - break; - case ClearPortFeature: - if (!wIndex || wIndex > ports) - goto error; - wIndex--; - temp = readl(status_reg); - - /* - * Even if OWNER is set, so the port is owned by the - * companion controller, khubd needs to be able to clear - * the port-change status bits (especially - * USB_PORT_STAT_C_CONNECTION). - */ - - switch (wValue) { - case USB_PORT_FEAT_ENABLE: - writel(temp & ~PORT_PE, status_reg); - break; - case USB_PORT_FEAT_C_ENABLE: - writel((temp & ~PORT_RWC_BITS) | PORT_PEC, status_reg); - break; - case USB_PORT_FEAT_SUSPEND: - if (temp & PORT_RESET) - goto error; - if (temp & PORT_SUSPEND) { - if ((temp & PORT_PE) == 0) - goto error; - /* resume signaling for 20 msec */ - temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); - writel(temp | PORT_RESUME, status_reg); - oxu->reset_done[wIndex] = jiffies - + msecs_to_jiffies(20); - } - break; - case USB_PORT_FEAT_C_SUSPEND: - /* we auto-clear this feature */ - break; - case USB_PORT_FEAT_POWER: - if (HCS_PPC(oxu->hcs_params)) - writel(temp & ~(PORT_RWC_BITS | PORT_POWER), - status_reg); - break; - case USB_PORT_FEAT_C_CONNECTION: - writel((temp & ~PORT_RWC_BITS) | PORT_CSC, status_reg); - break; - case USB_PORT_FEAT_C_OVER_CURRENT: - writel((temp & ~PORT_RWC_BITS) | PORT_OCC, status_reg); - break; - case USB_PORT_FEAT_C_RESET: - /* GetPortStatus clears reset */ - break; - default: - goto error; - } - readl(&oxu->regs->command); /* unblock posted write */ - break; - case GetHubDescriptor: - ehci_hub_descriptor(oxu, (struct usb_hub_descriptor *) - buf); - break; - case GetHubStatus: - /* no hub-wide feature/status flags */ - memset(buf, 0, 4); - break; - case GetPortStatus: - if (!wIndex || wIndex > ports) - goto error; - wIndex--; - status = 0; - temp = readl(status_reg); - - /* wPortChange bits */ - if (temp & PORT_CSC) - status |= USB_PORT_STAT_C_CONNECTION << 16; - if (temp & PORT_PEC) - status |= USB_PORT_STAT_C_ENABLE << 16; - if ((temp & PORT_OCC) && !ignore_oc) - status |= USB_PORT_STAT_C_OVERCURRENT << 16; - - /* whoever resumes must GetPortStatus to complete it!! */ - if (temp & PORT_RESUME) { - - /* Remote Wakeup received? */ - if (!oxu->reset_done[wIndex]) { - /* resume signaling for 20 msec */ - oxu->reset_done[wIndex] = jiffies - + msecs_to_jiffies(20); - /* check the port again */ - mod_timer(&oxu_to_hcd(oxu)->rh_timer, - oxu->reset_done[wIndex]); - } - - /* resume completed? */ - else if (time_after_eq(jiffies, - oxu->reset_done[wIndex])) { - status |= USB_PORT_STAT_C_SUSPEND << 16; - oxu->reset_done[wIndex] = 0; - - /* stop resume signaling */ - temp = readl(status_reg); - writel(temp & ~(PORT_RWC_BITS | PORT_RESUME), - status_reg); - retval = handshake(oxu, status_reg, - PORT_RESUME, 0, 2000 /* 2msec */); - if (retval != 0) { - oxu_err(oxu, - "port %d resume error %d\n", - wIndex + 1, retval); - goto error; - } - temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); - } - } - - /* whoever resets must GetPortStatus to complete it!! */ - if ((temp & PORT_RESET) - && time_after_eq(jiffies, - oxu->reset_done[wIndex])) { - status |= USB_PORT_STAT_C_RESET << 16; - oxu->reset_done[wIndex] = 0; - - /* force reset to complete */ - writel(temp & ~(PORT_RWC_BITS | PORT_RESET), - status_reg); - /* REVISIT: some hardware needs 550+ usec to clear - * this bit; seems too long to spin routinely... - */ - retval = handshake(oxu, status_reg, - PORT_RESET, 0, 750); - if (retval != 0) { - oxu_err(oxu, "port %d reset error %d\n", - wIndex + 1, retval); - goto error; - } - - /* see what we found out */ - temp = check_reset_complete(oxu, wIndex, status_reg, - readl(status_reg)); - } - - /* transfer dedicated ports to the companion hc */ - if ((temp & PORT_CONNECT) && - test_bit(wIndex, &oxu->companion_ports)) { - temp &= ~PORT_RWC_BITS; - temp |= PORT_OWNER; - writel(temp, status_reg); - oxu_dbg(oxu, "port %d --> companion\n", wIndex + 1); - temp = readl(status_reg); - } - - /* - * Even if OWNER is set, there's no harm letting khubd - * see the wPortStatus values (they should all be 0 except - * for PORT_POWER anyway). - */ - - if (temp & PORT_CONNECT) { - status |= USB_PORT_STAT_CONNECTION; - /* status may be from integrated TT */ - status |= oxu_port_speed(oxu, temp); - } - if (temp & PORT_PE) - status |= USB_PORT_STAT_ENABLE; - if (temp & (PORT_SUSPEND|PORT_RESUME)) - status |= USB_PORT_STAT_SUSPEND; - if (temp & PORT_OC) - status |= USB_PORT_STAT_OVERCURRENT; - if (temp & PORT_RESET) - status |= USB_PORT_STAT_RESET; - if (temp & PORT_POWER) - status |= USB_PORT_STAT_POWER; - -#ifndef OXU_VERBOSE_DEBUG - if (status & ~0xffff) /* only if wPortChange is interesting */ -#endif - dbg_port(oxu, "GetStatus", wIndex + 1, temp); - put_unaligned(cpu_to_le32(status), (__le32 *) buf); - break; - case SetHubFeature: - switch (wValue) { - case C_HUB_LOCAL_POWER: - case C_HUB_OVER_CURRENT: - /* no hub-wide feature/status flags */ - break; - default: - goto error; - } - break; - case SetPortFeature: - selector = wIndex >> 8; - wIndex &= 0xff; - if (!wIndex || wIndex > ports) - goto error; - wIndex--; - temp = readl(status_reg); - if (temp & PORT_OWNER) - break; - - temp &= ~PORT_RWC_BITS; - switch (wValue) { - case USB_PORT_FEAT_SUSPEND: - if ((temp & PORT_PE) == 0 - || (temp & PORT_RESET) != 0) - goto error; - if (device_may_wakeup(&hcd->self.root_hub->dev)) - temp |= PORT_WAKE_BITS; - writel(temp | PORT_SUSPEND, status_reg); - break; - case USB_PORT_FEAT_POWER: - if (HCS_PPC(oxu->hcs_params)) - writel(temp | PORT_POWER, status_reg); - break; - case USB_PORT_FEAT_RESET: - if (temp & PORT_RESUME) - goto error; - /* line status bits may report this as low speed, - * which can be fine if this root hub has a - * transaction translator built in. - */ - oxu_vdbg(oxu, "port %d reset\n", wIndex + 1); - temp |= PORT_RESET; - temp &= ~PORT_PE; - - /* - * caller must wait, then call GetPortStatus - * usb 2.0 spec says 50 ms resets on root - */ - oxu->reset_done[wIndex] = jiffies - + msecs_to_jiffies(50); - writel(temp, status_reg); - break; - - /* For downstream facing ports (these): one hub port is put - * into test mode according to USB2 11.24.2.13, then the hub - * must be reset (which for root hub now means rmmod+modprobe, - * or else system reboot). See EHCI 2.3.9 and 4.14 for info - * about the EHCI-specific stuff. - */ - case USB_PORT_FEAT_TEST: - if (!selector || selector > 5) - goto error; - ehci_quiesce(oxu); - ehci_halt(oxu); - temp |= selector << 16; - writel(temp, status_reg); - break; - - default: - goto error; - } - readl(&oxu->regs->command); /* unblock posted writes */ - break; - - default: -error: - /* "stall" on error */ - retval = -EPIPE; - } - spin_unlock_irqrestore(&oxu->lock, flags); - return retval; -} - -#ifdef CONFIG_PM - -static int oxu_bus_suspend(struct usb_hcd *hcd) -{ - struct oxu_hcd *oxu = hcd_to_oxu(hcd); - int port; - int mask; - - oxu_dbg(oxu, "suspend root hub\n"); - - if (time_before(jiffies, oxu->next_statechange)) - msleep(5); - - port = HCS_N_PORTS(oxu->hcs_params); - spin_lock_irq(&oxu->lock); - - /* stop schedules, clean any completed work */ - if (HC_IS_RUNNING(hcd->state)) { - ehci_quiesce(oxu); - hcd->state = HC_STATE_QUIESCING; - } - oxu->command = readl(&oxu->regs->command); - if (oxu->reclaim) - oxu->reclaim_ready = 1; - ehci_work(oxu); - - /* Unlike other USB host controller types, EHCI doesn't have - * any notion of "global" or bus-wide suspend. The driver has - * to manually suspend all the active unsuspended ports, and - * then manually resume them in the bus_resume() routine. - */ - oxu->bus_suspended = 0; - while (port--) { - u32 __iomem *reg = &oxu->regs->port_status[port]; - u32 t1 = readl(reg) & ~PORT_RWC_BITS; - u32 t2 = t1; - - /* keep track of which ports we suspend */ - if ((t1 & PORT_PE) && !(t1 & PORT_OWNER) && - !(t1 & PORT_SUSPEND)) { - t2 |= PORT_SUSPEND; - set_bit(port, &oxu->bus_suspended); - } - - /* enable remote wakeup on all ports */ - if (device_may_wakeup(&hcd->self.root_hub->dev)) - t2 |= PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E; - else - t2 &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E); - - if (t1 != t2) { - oxu_vdbg(oxu, "port %d, %08x -> %08x\n", - port + 1, t1, t2); - writel(t2, reg); - } - } - - /* turn off now-idle HC */ - del_timer_sync(&oxu->watchdog); - ehci_halt(oxu); - hcd->state = HC_STATE_SUSPENDED; - - /* allow remote wakeup */ - mask = INTR_MASK; - if (!device_may_wakeup(&hcd->self.root_hub->dev)) - mask &= ~STS_PCD; - writel(mask, &oxu->regs->intr_enable); - readl(&oxu->regs->intr_enable); - - oxu->next_statechange = jiffies + msecs_to_jiffies(10); - spin_unlock_irq(&oxu->lock); - return 0; -} - -/* Caller has locked the root hub, and should reset/reinit on error */ -static int oxu_bus_resume(struct usb_hcd *hcd) -{ - struct oxu_hcd *oxu = hcd_to_oxu(hcd); - u32 temp; - int i; - - if (time_before(jiffies, oxu->next_statechange)) - msleep(5); - spin_lock_irq(&oxu->lock); - - /* Ideally and we've got a real resume here, and no port's power - * was lost. (For PCI, that means Vaux was maintained.) But we - * could instead be restoring a swsusp snapshot -- so that BIOS was - * the last user of the controller, not reset/pm hardware keeping - * state we gave to it. - */ - temp = readl(&oxu->regs->intr_enable); - oxu_dbg(oxu, "resume root hub%s\n", temp ? "" : " after power loss"); - - /* at least some APM implementations will try to deliver - * IRQs right away, so delay them until we're ready. - */ - writel(0, &oxu->regs->intr_enable); - - /* re-init operational registers */ - writel(0, &oxu->regs->segment); - writel(oxu->periodic_dma, &oxu->regs->frame_list); - writel((u32) oxu->async->qh_dma, &oxu->regs->async_next); - - /* restore CMD_RUN, framelist size, and irq threshold */ - writel(oxu->command, &oxu->regs->command); - - /* Some controller/firmware combinations need a delay during which - * they set up the port statuses. See Bugzilla #8190. */ - mdelay(8); - - /* manually resume the ports we suspended during bus_suspend() */ - i = HCS_N_PORTS(oxu->hcs_params); - while (i--) { - temp = readl(&oxu->regs->port_status[i]); - temp &= ~(PORT_RWC_BITS - | PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E); - if (test_bit(i, &oxu->bus_suspended) && (temp & PORT_SUSPEND)) { - oxu->reset_done[i] = jiffies + msecs_to_jiffies(20); - temp |= PORT_RESUME; - } - writel(temp, &oxu->regs->port_status[i]); - } - i = HCS_N_PORTS(oxu->hcs_params); - mdelay(20); - while (i--) { - temp = readl(&oxu->regs->port_status[i]); - if (test_bit(i, &oxu->bus_suspended) && (temp & PORT_SUSPEND)) { - temp &= ~(PORT_RWC_BITS | PORT_RESUME); - writel(temp, &oxu->regs->port_status[i]); - oxu_vdbg(oxu, "resumed port %d\n", i + 1); - } - } - (void) readl(&oxu->regs->command); - - /* maybe re-activate the schedule(s) */ - temp = 0; - if (oxu->async->qh_next.qh) - temp |= CMD_ASE; - if (oxu->periodic_sched) - temp |= CMD_PSE; - if (temp) { - oxu->command |= temp; - writel(oxu->command, &oxu->regs->command); - } - - oxu->next_statechange = jiffies + msecs_to_jiffies(5); - hcd->state = HC_STATE_RUNNING; - - /* Now we can safely re-enable irqs */ - writel(INTR_MASK, &oxu->regs->intr_enable); - - spin_unlock_irq(&oxu->lock); - return 0; -} - -#else - -static int oxu_bus_suspend(struct usb_hcd *hcd) -{ - return 0; -} - -static int oxu_bus_resume(struct usb_hcd *hcd) -{ - return 0; -} - -#endif /* CONFIG_PM */ - -static const struct hc_driver oxu_hc_driver = { - .description = "oxu210hp_hcd", - .product_desc = "oxu210hp HCD", - .hcd_priv_size = sizeof(struct oxu_hcd), - - /* - * Generic hardware linkage - */ - .irq = oxu_irq, - .flags = HCD_MEMORY | HCD_USB2, - - /* - * Basic lifecycle operations - */ - .reset = oxu_reset, - .start = oxu_run, - .stop = oxu_stop, - .shutdown = oxu_shutdown, - - /* - * Managing i/o requests and associated device resources - */ - .urb_enqueue = oxu_urb_enqueue, - .urb_dequeue = oxu_urb_dequeue, - .endpoint_disable = oxu_endpoint_disable, - - /* - * Scheduling support - */ - .get_frame_number = oxu_get_frame, - - /* - * Root hub support - */ - .hub_status_data = oxu_hub_status_data, - .hub_control = oxu_hub_control, - .bus_suspend = oxu_bus_suspend, - .bus_resume = oxu_bus_resume, -}; - -/* - * Module stuff - */ - -static void oxu_configuration(struct platform_device *pdev, void *base) -{ - u32 tmp; - - /* Initialize top level registers. - * First write ever - */ - oxu_writel(base, OXU_HOSTIFCONFIG, 0x0000037D); - oxu_writel(base, OXU_SOFTRESET, OXU_SRESET); - oxu_writel(base, OXU_HOSTIFCONFIG, 0x0000037D); - - tmp = oxu_readl(base, OXU_PIOBURSTREADCTRL); - oxu_writel(base, OXU_PIOBURSTREADCTRL, tmp | 0x0040); - - oxu_writel(base, OXU_ASO, OXU_SPHPOEN | OXU_OVRCCURPUPDEN | - OXU_COMPARATOR | OXU_ASO_OP); - - tmp = oxu_readl(base, OXU_CLKCTRL_SET); - oxu_writel(base, OXU_CLKCTRL_SET, tmp | OXU_SYSCLKEN | OXU_USBOTGCLKEN); - - /* Clear all top interrupt enable */ - oxu_writel(base, OXU_CHIPIRQEN_CLR, 0xff); - - /* Clear all top interrupt status */ - oxu_writel(base, OXU_CHIPIRQSTATUS, 0xff); - - /* Enable all needed top interrupt except OTG SPH core */ - oxu_writel(base, OXU_CHIPIRQEN_SET, OXU_USBSPHLPWUI | OXU_USBOTGLPWUI); -} - -static int oxu_verify_id(struct platform_device *pdev, void *base) -{ - u32 id; - static const char * const bo[] = { - "reserved", - "128-pin LQFP", - "84-pin TFBGA", - "reserved", - }; - - /* Read controller signature register to find a match */ - id = oxu_readl(base, OXU_DEVICEID); - dev_info(&pdev->dev, "device ID %x\n", id); - if ((id & OXU_REV_MASK) != (OXU_REV_2100 << OXU_REV_SHIFT)) - return -1; - - dev_info(&pdev->dev, "found device %x %s (%04x:%04x)\n", - id >> OXU_REV_SHIFT, - bo[(id & OXU_BO_MASK) >> OXU_BO_SHIFT], - (id & OXU_MAJ_REV_MASK) >> OXU_MAJ_REV_SHIFT, - (id & OXU_MIN_REV_MASK) >> OXU_MIN_REV_SHIFT); - - return 0; -} - -static const struct hc_driver oxu_hc_driver; -static struct usb_hcd *oxu_create(struct platform_device *pdev, - unsigned long memstart, unsigned long memlen, - void *base, int irq, int otg) -{ - struct device *dev = &pdev->dev; - - struct usb_hcd *hcd; - struct oxu_hcd *oxu; - int ret; - - /* Set endian mode and host mode */ - oxu_writel(base + (otg ? OXU_OTG_CORE_OFFSET : OXU_SPH_CORE_OFFSET), - OXU_USBMODE, - OXU_CM_HOST_ONLY | OXU_ES_LITTLE | OXU_VBPS); - - hcd = usb_create_hcd(&oxu_hc_driver, dev, - otg ? "oxu210hp_otg" : "oxu210hp_sph"); - if (!hcd) - return ERR_PTR(-ENOMEM); - - hcd->rsrc_start = memstart; - hcd->rsrc_len = memlen; - hcd->regs = base; - hcd->irq = irq; - hcd->state = HC_STATE_HALT; - - oxu = hcd_to_oxu(hcd); - oxu->is_otg = otg; - - ret = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (ret < 0) - return ERR_PTR(ret); - - return hcd; -} - -static int oxu_init(struct platform_device *pdev, - unsigned long memstart, unsigned long memlen, - void *base, int irq) -{ - struct oxu_info *info = platform_get_drvdata(pdev); - struct usb_hcd *hcd; - int ret; - - /* First time configuration at start up */ - oxu_configuration(pdev, base); - - ret = oxu_verify_id(pdev, base); - if (ret) { - dev_err(&pdev->dev, "no devices found!\n"); - return -ENODEV; - } - - /* Create the OTG controller */ - hcd = oxu_create(pdev, memstart, memlen, base, irq, 1); - if (IS_ERR(hcd)) { - dev_err(&pdev->dev, "cannot create OTG controller!\n"); - ret = PTR_ERR(hcd); - goto error_create_otg; - } - info->hcd[0] = hcd; - - /* Create the SPH host controller */ - hcd = oxu_create(pdev, memstart, memlen, base, irq, 0); - if (IS_ERR(hcd)) { - dev_err(&pdev->dev, "cannot create SPH controller!\n"); - ret = PTR_ERR(hcd); - goto error_create_sph; - } - info->hcd[1] = hcd; - - oxu_writel(base, OXU_CHIPIRQEN_SET, - oxu_readl(base, OXU_CHIPIRQEN_SET) | 3); - - return 0; - -error_create_sph: - usb_remove_hcd(info->hcd[0]); - usb_put_hcd(info->hcd[0]); - -error_create_otg: - return ret; -} - -static int oxu_drv_probe(struct platform_device *pdev) -{ - struct resource *res; - void *base; - unsigned long memstart, memlen; - int irq, ret; - struct oxu_info *info; - - if (usb_disabled()) - return -ENODEV; - - /* - * Get the platform resources - */ - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(&pdev->dev, - "no IRQ! Check %s setup!\n", dev_name(&pdev->dev)); - return -ENODEV; - } - irq = res->start; - dev_dbg(&pdev->dev, "IRQ resource %d\n", irq); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "no registers address! Check %s setup!\n", - dev_name(&pdev->dev)); - return -ENODEV; - } - memstart = res->start; - memlen = resource_size(res); - dev_dbg(&pdev->dev, "MEM resource %lx-%lx\n", memstart, memlen); - if (!request_mem_region(memstart, memlen, - oxu_hc_driver.description)) { - dev_dbg(&pdev->dev, "memory area already in use\n"); - return -EBUSY; - } - - ret = irq_set_irq_type(irq, IRQF_TRIGGER_FALLING); - if (ret) { - dev_err(&pdev->dev, "error setting irq type\n"); - ret = -EFAULT; - goto error_set_irq_type; - } - - base = ioremap(memstart, memlen); - if (!base) { - dev_dbg(&pdev->dev, "error mapping memory\n"); - ret = -EFAULT; - goto error_ioremap; - } - - /* Allocate a driver data struct to hold useful info for both - * SPH & OTG devices - */ - info = kzalloc(sizeof(struct oxu_info), GFP_KERNEL); - if (!info) { - dev_dbg(&pdev->dev, "error allocating memory\n"); - ret = -EFAULT; - goto error_alloc; - } - platform_set_drvdata(pdev, info); - - ret = oxu_init(pdev, memstart, memlen, base, irq); - if (ret < 0) { - dev_dbg(&pdev->dev, "cannot init USB devices\n"); - goto error_init; - } - - dev_info(&pdev->dev, "devices enabled and running\n"); - platform_set_drvdata(pdev, info); - - return 0; - -error_init: - kfree(info); - platform_set_drvdata(pdev, NULL); - -error_alloc: - iounmap(base); - -error_set_irq_type: -error_ioremap: - release_mem_region(memstart, memlen); - - dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), ret); - return ret; -} - -static void oxu_remove(struct platform_device *pdev, struct usb_hcd *hcd) -{ - usb_remove_hcd(hcd); - usb_put_hcd(hcd); -} - -static int oxu_drv_remove(struct platform_device *pdev) -{ - struct oxu_info *info = platform_get_drvdata(pdev); - unsigned long memstart = info->hcd[0]->rsrc_start, - memlen = info->hcd[0]->rsrc_len; - void *base = info->hcd[0]->regs; - - oxu_remove(pdev, info->hcd[0]); - oxu_remove(pdev, info->hcd[1]); - - iounmap(base); - release_mem_region(memstart, memlen); - - kfree(info); - platform_set_drvdata(pdev, NULL); - - return 0; -} - -static void oxu_drv_shutdown(struct platform_device *pdev) -{ - oxu_drv_remove(pdev); -} - -#if 0 -/* FIXME: TODO */ -static int oxu_drv_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct usb_hcd *hcd = dev_get_drvdata(dev); - - return 0; -} - -static int oxu_drv_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct usb_hcd *hcd = dev_get_drvdata(dev); - - return 0; -} -#else -#define oxu_drv_suspend NULL -#define oxu_drv_resume NULL -#endif - -static struct platform_driver oxu_driver = { - .probe = oxu_drv_probe, - .remove = oxu_drv_remove, - .shutdown = oxu_drv_shutdown, - .suspend = oxu_drv_suspend, - .resume = oxu_drv_resume, - .driver = { - .name = "oxu210hp-hcd", - .bus = &platform_bus_type - } -}; - -module_platform_driver(oxu_driver); - -MODULE_DESCRIPTION("Oxford OXU210HP HCD driver - ver. " DRIVER_VERSION); -MODULE_AUTHOR("Rodolfo Giometti "); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/host/oxu210hp.h b/ANDROID_3.4.5/drivers/usb/host/oxu210hp.h deleted file mode 100644 index 1c216ad9..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/oxu210hp.h +++ /dev/null @@ -1,447 +0,0 @@ -/* - * Host interface registers - */ - -#define OXU_DEVICEID 0x00 - #define OXU_REV_MASK 0xffff0000 - #define OXU_REV_SHIFT 16 - #define OXU_REV_2100 0x2100 - #define OXU_BO_SHIFT 8 - #define OXU_BO_MASK (0x3 << OXU_BO_SHIFT) - #define OXU_MAJ_REV_SHIFT 4 - #define OXU_MAJ_REV_MASK (0xf << OXU_MAJ_REV_SHIFT) - #define OXU_MIN_REV_SHIFT 0 - #define OXU_MIN_REV_MASK (0xf << OXU_MIN_REV_SHIFT) -#define OXU_HOSTIFCONFIG 0x04 -#define OXU_SOFTRESET 0x08 - #define OXU_SRESET (1 << 0) - -#define OXU_PIOBURSTREADCTRL 0x0C - -#define OXU_CHIPIRQSTATUS 0x10 -#define OXU_CHIPIRQEN_SET 0x14 -#define OXU_CHIPIRQEN_CLR 0x18 - #define OXU_USBSPHLPWUI 0x00000080 - #define OXU_USBOTGLPWUI 0x00000040 - #define OXU_USBSPHI 0x00000002 - #define OXU_USBOTGI 0x00000001 - -#define OXU_CLKCTRL_SET 0x1C - #define OXU_SYSCLKEN 0x00000008 - #define OXU_USBSPHCLKEN 0x00000002 - #define OXU_USBOTGCLKEN 0x00000001 - -#define OXU_ASO 0x68 - #define OXU_SPHPOEN 0x00000100 - #define OXU_OVRCCURPUPDEN 0x00000800 - #define OXU_ASO_OP (1 << 10) - #define OXU_COMPARATOR 0x000004000 - -#define OXU_USBMODE 0x1A8 - #define OXU_VBPS 0x00000020 - #define OXU_ES_LITTLE 0x00000000 - #define OXU_CM_HOST_ONLY 0x00000003 - -/* - * Proper EHCI structs & defines - */ - -/* Magic numbers that can affect system performance */ -#define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */ -#define EHCI_TUNE_RL_HS 4 /* nak throttle; see 4.9 */ -#define EHCI_TUNE_RL_TT 0 -#define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */ -#define EHCI_TUNE_MULT_TT 1 -#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */ - -struct oxu_hcd; - -/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */ - -/* Section 2.2 Host Controller Capability Registers */ -struct ehci_caps { - /* these fields are specified as 8 and 16 bit registers, - * but some hosts can't perform 8 or 16 bit PCI accesses. - */ - u32 hc_capbase; -#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */ -#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */ - u32 hcs_params; /* HCSPARAMS - offset 0x4 */ -#define HCS_DEBUG_PORT(p) (((p)>>20)&0xf) /* bits 23:20, debug port? */ -#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */ -#define HCS_N_CC(p) (((p)>>12)&0xf) /* bits 15:12, #companion HCs */ -#define HCS_N_PCC(p) (((p)>>8)&0xf) /* bits 11:8, ports per CC */ -#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */ -#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */ -#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */ - - u32 hcc_params; /* HCCPARAMS - offset 0x8 */ -#define HCC_EXT_CAPS(p) (((p)>>8)&0xff) /* for pci extended caps */ -#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */ -#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */ -#define HCC_CANPARK(p) ((p)&(1 << 2)) /* true: can park on async qh */ -#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/ -#define HCC_64BIT_ADDR(p) ((p)&(1)) /* true: can use 64-bit addr */ - u8 portroute[8]; /* nibbles for routing - offset 0xC */ -} __attribute__ ((packed)); - - -/* Section 2.3 Host Controller Operational Registers */ -struct ehci_regs { - /* USBCMD: offset 0x00 */ - u32 command; -/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */ -#define CMD_PARK (1<<11) /* enable "park" on async qh */ -#define CMD_PARK_CNT(c) (((c)>>8)&3) /* how many transfers to park for */ -#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */ -#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */ -#define CMD_ASE (1<<5) /* async schedule enable */ -#define CMD_PSE (1<<4) /* periodic schedule enable */ -/* 3:2 is periodic frame list size */ -#define CMD_RESET (1<<1) /* reset HC not bus */ -#define CMD_RUN (1<<0) /* start/stop HC */ - - /* USBSTS: offset 0x04 */ - u32 status; -#define STS_ASS (1<<15) /* Async Schedule Status */ -#define STS_PSS (1<<14) /* Periodic Schedule Status */ -#define STS_RECL (1<<13) /* Reclamation */ -#define STS_HALT (1<<12) /* Not running (any reason) */ -/* some bits reserved */ - /* these STS_* flags are also intr_enable bits (USBINTR) */ -#define STS_IAA (1<<5) /* Interrupted on async advance */ -#define STS_FATAL (1<<4) /* such as some PCI access errors */ -#define STS_FLR (1<<3) /* frame list rolled over */ -#define STS_PCD (1<<2) /* port change detect */ -#define STS_ERR (1<<1) /* "error" completion (overflow, ...) */ -#define STS_INT (1<<0) /* "normal" completion (short, ...) */ - -#define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT) - - /* USBINTR: offset 0x08 */ - u32 intr_enable; - - /* FRINDEX: offset 0x0C */ - u32 frame_index; /* current microframe number */ - /* CTRLDSSEGMENT: offset 0x10 */ - u32 segment; /* address bits 63:32 if needed */ - /* PERIODICLISTBASE: offset 0x14 */ - u32 frame_list; /* points to periodic list */ - /* ASYNCLISTADDR: offset 0x18 */ - u32 async_next; /* address of next async queue head */ - - u32 reserved[9]; - - /* CONFIGFLAG: offset 0x40 */ - u32 configured_flag; -#define FLAG_CF (1<<0) /* true: we'll support "high speed" */ - - /* PORTSC: offset 0x44 */ - u32 port_status[0]; /* up to N_PORTS */ -/* 31:23 reserved */ -#define PORT_WKOC_E (1<<22) /* wake on overcurrent (enable) */ -#define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */ -#define PORT_WKCONN_E (1<<20) /* wake on connect (enable) */ -/* 19:16 for port testing */ -#define PORT_LED_OFF (0<<14) -#define PORT_LED_AMBER (1<<14) -#define PORT_LED_GREEN (2<<14) -#define PORT_LED_MASK (3<<14) -#define PORT_OWNER (1<<13) /* true: companion hc owns this port */ -#define PORT_POWER (1<<12) /* true: has power (see PPC) */ -#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10)) /* USB 1.1 device */ -/* 11:10 for detecting lowspeed devices (reset vs release ownership) */ -/* 9 reserved */ -#define PORT_RESET (1<<8) /* reset port */ -#define PORT_SUSPEND (1<<7) /* suspend port */ -#define PORT_RESUME (1<<6) /* resume it */ -#define PORT_OCC (1<<5) /* over current change */ -#define PORT_OC (1<<4) /* over current active */ -#define PORT_PEC (1<<3) /* port enable change */ -#define PORT_PE (1<<2) /* port enable */ -#define PORT_CSC (1<<1) /* connect status change */ -#define PORT_CONNECT (1<<0) /* device connected */ -#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC) -} __attribute__ ((packed)); - -/* Appendix C, Debug port ... intended for use with special "debug devices" - * that can help if there's no serial console. (nonstandard enumeration.) - */ -struct ehci_dbg_port { - u32 control; -#define DBGP_OWNER (1<<30) -#define DBGP_ENABLED (1<<28) -#define DBGP_DONE (1<<16) -#define DBGP_INUSE (1<<10) -#define DBGP_ERRCODE(x) (((x)>>7)&0x07) -# define DBGP_ERR_BAD 1 -# define DBGP_ERR_SIGNAL 2 -#define DBGP_ERROR (1<<6) -#define DBGP_GO (1<<5) -#define DBGP_OUT (1<<4) -#define DBGP_LEN(x) (((x)>>0)&0x0f) - u32 pids; -#define DBGP_PID_GET(x) (((x)>>16)&0xff) -#define DBGP_PID_SET(data, tok) (((data)<<8)|(tok)) - u32 data03; - u32 data47; - u32 address; -#define DBGP_EPADDR(dev, ep) (((dev)<<8)|(ep)) -} __attribute__ ((packed)); - - -#define QTD_NEXT(dma) cpu_to_le32((u32)dma) - -/* - * EHCI Specification 0.95 Section 3.5 - * QTD: describe data transfer components (buffer, direction, ...) - * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram". - * - * These are associated only with "QH" (Queue Head) structures, - * used with control, bulk, and interrupt transfers. - */ -struct ehci_qtd { - /* first part defined by EHCI spec */ - __le32 hw_next; /* see EHCI 3.5.1 */ - __le32 hw_alt_next; /* see EHCI 3.5.2 */ - __le32 hw_token; /* see EHCI 3.5.3 */ -#define QTD_TOGGLE (1 << 31) /* data toggle */ -#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff) -#define QTD_IOC (1 << 15) /* interrupt on complete */ -#define QTD_CERR(tok) (((tok)>>10) & 0x3) -#define QTD_PID(tok) (((tok)>>8) & 0x3) -#define QTD_STS_ACTIVE (1 << 7) /* HC may execute this */ -#define QTD_STS_HALT (1 << 6) /* halted on error */ -#define QTD_STS_DBE (1 << 5) /* data buffer error (in HC) */ -#define QTD_STS_BABBLE (1 << 4) /* device was babbling (qtd halted) */ -#define QTD_STS_XACT (1 << 3) /* device gave illegal response */ -#define QTD_STS_MMF (1 << 2) /* incomplete split transaction */ -#define QTD_STS_STS (1 << 1) /* split transaction state */ -#define QTD_STS_PING (1 << 0) /* issue PING? */ - __le32 hw_buf[5]; /* see EHCI 3.5.4 */ - __le32 hw_buf_hi[5]; /* Appendix B */ - - /* the rest is HCD-private */ - dma_addr_t qtd_dma; /* qtd address */ - struct list_head qtd_list; /* sw qtd list */ - struct urb *urb; /* qtd's urb */ - size_t length; /* length of buffer */ - - u32 qtd_buffer_len; - void *buffer; - dma_addr_t buffer_dma; - void *transfer_buffer; - void *transfer_dma; -} __attribute__ ((aligned(32))); - -/* mask NakCnt+T in qh->hw_alt_next */ -#define QTD_MASK cpu_to_le32 (~0x1f) - -#define IS_SHORT_READ(token) (QTD_LENGTH(token) != 0 && QTD_PID(token) == 1) - -/* Type tag from {qh, itd, sitd, fstn}->hw_next */ -#define Q_NEXT_TYPE(dma) ((dma) & cpu_to_le32 (3 << 1)) - -/* values for that type tag */ -#define Q_TYPE_QH cpu_to_le32 (1 << 1) - -/* next async queue entry, or pointer to interrupt/periodic QH */ -#define QH_NEXT(dma) (cpu_to_le32(((u32)dma)&~0x01f)|Q_TYPE_QH) - -/* for periodic/async schedules and qtd lists, mark end of list */ -#define EHCI_LIST_END cpu_to_le32(1) /* "null pointer" to hw */ - -/* - * Entries in periodic shadow table are pointers to one of four kinds - * of data structure. That's dictated by the hardware; a type tag is - * encoded in the low bits of the hardware's periodic schedule. Use - * Q_NEXT_TYPE to get the tag. - * - * For entries in the async schedule, the type tag always says "qh". - */ -union ehci_shadow { - struct ehci_qh *qh; /* Q_TYPE_QH */ - __le32 *hw_next; /* (all types) */ - void *ptr; -}; - -/* - * EHCI Specification 0.95 Section 3.6 - * QH: describes control/bulk/interrupt endpoints - * See Fig 3-7 "Queue Head Structure Layout". - * - * These appear in both the async and (for interrupt) periodic schedules. - */ - -struct ehci_qh { - /* first part defined by EHCI spec */ - __le32 hw_next; /* see EHCI 3.6.1 */ - __le32 hw_info1; /* see EHCI 3.6.2 */ -#define QH_HEAD 0x00008000 - __le32 hw_info2; /* see EHCI 3.6.2 */ -#define QH_SMASK 0x000000ff -#define QH_CMASK 0x0000ff00 -#define QH_HUBADDR 0x007f0000 -#define QH_HUBPORT 0x3f800000 -#define QH_MULT 0xc0000000 - __le32 hw_current; /* qtd list - see EHCI 3.6.4 */ - - /* qtd overlay (hardware parts of a struct ehci_qtd) */ - __le32 hw_qtd_next; - __le32 hw_alt_next; - __le32 hw_token; - __le32 hw_buf[5]; - __le32 hw_buf_hi[5]; - - /* the rest is HCD-private */ - dma_addr_t qh_dma; /* address of qh */ - union ehci_shadow qh_next; /* ptr to qh; or periodic */ - struct list_head qtd_list; /* sw qtd list */ - struct ehci_qtd *dummy; - struct ehci_qh *reclaim; /* next to reclaim */ - - struct oxu_hcd *oxu; - struct kref kref; - unsigned stamp; - - u8 qh_state; -#define QH_STATE_LINKED 1 /* HC sees this */ -#define QH_STATE_UNLINK 2 /* HC may still see this */ -#define QH_STATE_IDLE 3 /* HC doesn't see this */ -#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on reclaim q */ -#define QH_STATE_COMPLETING 5 /* don't touch token.HALT */ - - /* periodic schedule info */ - u8 usecs; /* intr bandwidth */ - u8 gap_uf; /* uframes split/csplit gap */ - u8 c_usecs; /* ... split completion bw */ - u16 tt_usecs; /* tt downstream bandwidth */ - unsigned short period; /* polling interval */ - unsigned short start; /* where polling starts */ -#define NO_FRAME ((unsigned short)~0) /* pick new start */ - struct usb_device *dev; /* access to TT */ -} __attribute__ ((aligned(32))); - -/* - * Proper OXU210HP structs - */ - -#define OXU_OTG_CORE_OFFSET 0x00400 -#define OXU_OTG_CAP_OFFSET (OXU_OTG_CORE_OFFSET + 0x100) -#define OXU_SPH_CORE_OFFSET 0x00800 -#define OXU_SPH_CAP_OFFSET (OXU_SPH_CORE_OFFSET + 0x100) - -#define OXU_OTG_MEM 0xE000 -#define OXU_SPH_MEM 0x16000 - -/* Only how many elements & element structure are specifies here. */ -/* 2 host controllers are enabled - total size <= 28 kbytes */ -#define DEFAULT_I_TDPS 1024 -#define QHEAD_NUM 16 -#define QTD_NUM 32 -#define SITD_NUM 8 -#define MURB_NUM 8 - -#define BUFFER_NUM 8 -#define BUFFER_SIZE 512 - -struct oxu_info { - struct usb_hcd *hcd[2]; -}; - -struct oxu_buf { - u8 buffer[BUFFER_SIZE]; -} __attribute__ ((aligned(BUFFER_SIZE))); - -struct oxu_onchip_mem { - struct oxu_buf db_pool[BUFFER_NUM]; - - u32 frame_list[DEFAULT_I_TDPS]; - struct ehci_qh qh_pool[QHEAD_NUM]; - struct ehci_qtd qtd_pool[QTD_NUM]; -} __attribute__ ((aligned(4 << 10))); - -#define EHCI_MAX_ROOT_PORTS 15 /* see HCS_N_PORTS */ - -struct oxu_murb { - struct urb urb; - struct urb *main; - u8 last; -}; - -struct oxu_hcd { /* one per controller */ - unsigned int is_otg:1; - - u8 qh_used[QHEAD_NUM]; - u8 qtd_used[QTD_NUM]; - u8 db_used[BUFFER_NUM]; - u8 murb_used[MURB_NUM]; - - struct oxu_onchip_mem __iomem *mem; - spinlock_t mem_lock; - - struct timer_list urb_timer; - - struct ehci_caps __iomem *caps; - struct ehci_regs __iomem *regs; - - __u32 hcs_params; /* cached register copy */ - spinlock_t lock; - - /* async schedule support */ - struct ehci_qh *async; - struct ehci_qh *reclaim; - unsigned reclaim_ready:1; - unsigned scanning:1; - - /* periodic schedule support */ - unsigned periodic_size; - __le32 *periodic; /* hw periodic table */ - dma_addr_t periodic_dma; - unsigned i_thresh; /* uframes HC might cache */ - - union ehci_shadow *pshadow; /* mirror hw periodic table */ - int next_uframe; /* scan periodic, start here */ - unsigned periodic_sched; /* periodic activity count */ - - /* per root hub port */ - unsigned long reset_done[EHCI_MAX_ROOT_PORTS]; - /* bit vectors (one bit per port) */ - unsigned long bus_suspended; /* which ports were - * already suspended at the - * start of a bus suspend - */ - unsigned long companion_ports;/* which ports are dedicated - * to the companion controller - */ - - struct timer_list watchdog; - unsigned long actions; - unsigned stamp; - unsigned long next_statechange; - u32 command; - - /* SILICON QUIRKS */ - struct list_head urb_list; /* this is the head to urb - * queue that didn't get enough - * resources - */ - struct oxu_murb *murb_pool; /* murb per split big urb */ - unsigned urb_len; - - u8 sbrn; /* packed release number */ -}; - -#define EHCI_IAA_JIFFIES (HZ/100) /* arbitrary; ~10 msec */ -#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ -#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */ -#define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */ - -enum ehci_timer_action { - TIMER_IO_WATCHDOG, - TIMER_IAA_WATCHDOG, - TIMER_ASYNC_SHRINK, - TIMER_ASYNC_OFF, -}; - -#include diff --git a/ANDROID_3.4.5/drivers/usb/host/pci-quirks.c b/ANDROID_3.4.5/drivers/usb/host/pci-quirks.c deleted file mode 100644 index 2efade76..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/pci-quirks.c +++ /dev/null @@ -1,934 +0,0 @@ -/* - * This file contains code to reset and initialize USB host controllers. - * Some of it includes work-arounds for PCI hardware and BIOS quirks. - * It may need to run early during booting -- before USB would normally - * initialize -- to ensure that Linux doesn't use any legacy modes. - * - * Copyright (c) 1999 Martin Mares - * (and others) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "pci-quirks.h" -#include "xhci-ext-caps.h" - - -#define UHCI_USBLEGSUP 0xc0 /* legacy support */ -#define UHCI_USBCMD 0 /* command register */ -#define UHCI_USBINTR 4 /* interrupt register */ -#define UHCI_USBLEGSUP_RWC 0x8f00 /* the R/WC bits */ -#define UHCI_USBLEGSUP_RO 0x5040 /* R/O and reserved bits */ -#define UHCI_USBCMD_RUN 0x0001 /* RUN/STOP bit */ -#define UHCI_USBCMD_HCRESET 0x0002 /* Host Controller reset */ -#define UHCI_USBCMD_EGSM 0x0008 /* Global Suspend Mode */ -#define UHCI_USBCMD_CONFIGURE 0x0040 /* Config Flag */ -#define UHCI_USBINTR_RESUME 0x0002 /* Resume interrupt enable */ - -#define OHCI_CONTROL 0x04 -#define OHCI_CMDSTATUS 0x08 -#define OHCI_INTRSTATUS 0x0c -#define OHCI_INTRENABLE 0x10 -#define OHCI_INTRDISABLE 0x14 -#define OHCI_FMINTERVAL 0x34 -#define OHCI_HCFS (3 << 6) /* hc functional state */ -#define OHCI_HCR (1 << 0) /* host controller reset */ -#define OHCI_OCR (1 << 3) /* ownership change request */ -#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ -#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */ -#define OHCI_INTR_OC (1 << 30) /* ownership change */ - -#define EHCI_HCC_PARAMS 0x08 /* extended capabilities */ -#define EHCI_USBCMD 0 /* command register */ -#define EHCI_USBCMD_RUN (1 << 0) /* RUN/STOP bit */ -#define EHCI_USBSTS 4 /* status register */ -#define EHCI_USBSTS_HALTED (1 << 12) /* HCHalted bit */ -#define EHCI_USBINTR 8 /* interrupt register */ -#define EHCI_CONFIGFLAG 0x40 /* configured flag register */ -#define EHCI_USBLEGSUP 0 /* legacy support register */ -#define EHCI_USBLEGSUP_BIOS (1 << 16) /* BIOS semaphore */ -#define EHCI_USBLEGSUP_OS (1 << 24) /* OS semaphore */ -#define EHCI_USBLEGCTLSTS 4 /* legacy control/status */ -#define EHCI_USBLEGCTLSTS_SOOE (1 << 13) /* SMI on ownership change */ - -/* AMD quirk use */ -#define AB_REG_BAR_LOW 0xe0 -#define AB_REG_BAR_HIGH 0xe1 -#define AB_REG_BAR_SB700 0xf0 -#define AB_INDX(addr) ((addr) + 0x00) -#define AB_DATA(addr) ((addr) + 0x04) -#define AX_INDXC 0x30 -#define AX_DATAC 0x34 - -#define NB_PCIE_INDX_ADDR 0xe0 -#define NB_PCIE_INDX_DATA 0xe4 -#define PCIE_P_CNTL 0x10040 -#define BIF_NB 0x10002 -#define NB_PIF0_PWRDOWN_0 0x01100012 -#define NB_PIF0_PWRDOWN_1 0x01100013 - -#define USB_INTEL_XUSB2PR 0xD0 -#define USB_INTEL_USB3_PSSEN 0xD8 - -static struct amd_chipset_info { - struct pci_dev *nb_dev; - struct pci_dev *smbus_dev; - int nb_type; - int sb_type; - int isoc_reqs; - int probe_count; - int probe_result; -} amd_chipset; - -static DEFINE_SPINLOCK(amd_lock); - -int usb_amd_find_chipset_info(void) -{ - u8 rev = 0; - unsigned long flags; - struct amd_chipset_info info; - int ret; - - spin_lock_irqsave(&amd_lock, flags); - - /* probe only once */ - if (amd_chipset.probe_count > 0) { - amd_chipset.probe_count++; - spin_unlock_irqrestore(&amd_lock, flags); - return amd_chipset.probe_result; - } - memset(&info, 0, sizeof(info)); - spin_unlock_irqrestore(&amd_lock, flags); - - info.smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL); - if (info.smbus_dev) { - rev = info.smbus_dev->revision; - if (rev >= 0x40) - info.sb_type = 1; - else if (rev >= 0x30 && rev <= 0x3b) - info.sb_type = 3; - } else { - info.smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, - 0x780b, NULL); - if (!info.smbus_dev) { - ret = 0; - goto commit; - } - - rev = info.smbus_dev->revision; - if (rev >= 0x11 && rev <= 0x18) - info.sb_type = 2; - } - - if (info.sb_type == 0) { - if (info.smbus_dev) { - pci_dev_put(info.smbus_dev); - info.smbus_dev = NULL; - } - ret = 0; - goto commit; - } - - info.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x9601, NULL); - if (info.nb_dev) { - info.nb_type = 1; - } else { - info.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1510, NULL); - if (info.nb_dev) { - info.nb_type = 2; - } else { - info.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, - 0x9600, NULL); - if (info.nb_dev) - info.nb_type = 3; - } - } - - ret = info.probe_result = 1; - printk(KERN_DEBUG "QUIRK: Enable AMD PLL fix\n"); - -commit: - - spin_lock_irqsave(&amd_lock, flags); - if (amd_chipset.probe_count > 0) { - /* race - someone else was faster - drop devices */ - - /* Mark that we where here */ - amd_chipset.probe_count++; - ret = amd_chipset.probe_result; - - spin_unlock_irqrestore(&amd_lock, flags); - - if (info.nb_dev) - pci_dev_put(info.nb_dev); - if (info.smbus_dev) - pci_dev_put(info.smbus_dev); - - } else { - /* no race - commit the result */ - info.probe_count++; - amd_chipset = info; - spin_unlock_irqrestore(&amd_lock, flags); - } - - return ret; -} -EXPORT_SYMBOL_GPL(usb_amd_find_chipset_info); - -/* - * The hardware normally enables the A-link power management feature, which - * lets the system lower the power consumption in idle states. - * - * This USB quirk prevents the link going into that lower power state - * during isochronous transfers. - * - * Without this quirk, isochronous stream on OHCI/EHCI/xHCI controllers of - * some AMD platforms may stutter or have breaks occasionally. - */ -static void usb_amd_quirk_pll(int disable) -{ - u32 addr, addr_low, addr_high, val; - u32 bit = disable ? 0 : 1; - unsigned long flags; - - spin_lock_irqsave(&amd_lock, flags); - - if (disable) { - amd_chipset.isoc_reqs++; - if (amd_chipset.isoc_reqs > 1) { - spin_unlock_irqrestore(&amd_lock, flags); - return; - } - } else { - amd_chipset.isoc_reqs--; - if (amd_chipset.isoc_reqs > 0) { - spin_unlock_irqrestore(&amd_lock, flags); - return; - } - } - - if (amd_chipset.sb_type == 1 || amd_chipset.sb_type == 2) { - outb_p(AB_REG_BAR_LOW, 0xcd6); - addr_low = inb_p(0xcd7); - outb_p(AB_REG_BAR_HIGH, 0xcd6); - addr_high = inb_p(0xcd7); - addr = addr_high << 8 | addr_low; - - outl_p(0x30, AB_INDX(addr)); - outl_p(0x40, AB_DATA(addr)); - outl_p(0x34, AB_INDX(addr)); - val = inl_p(AB_DATA(addr)); - } else if (amd_chipset.sb_type == 3) { - pci_read_config_dword(amd_chipset.smbus_dev, - AB_REG_BAR_SB700, &addr); - outl(AX_INDXC, AB_INDX(addr)); - outl(0x40, AB_DATA(addr)); - outl(AX_DATAC, AB_INDX(addr)); - val = inl(AB_DATA(addr)); - } else { - spin_unlock_irqrestore(&amd_lock, flags); - return; - } - - if (disable) { - val &= ~0x08; - val |= (1 << 4) | (1 << 9); - } else { - val |= 0x08; - val &= ~((1 << 4) | (1 << 9)); - } - outl_p(val, AB_DATA(addr)); - - if (!amd_chipset.nb_dev) { - spin_unlock_irqrestore(&amd_lock, flags); - return; - } - - if (amd_chipset.nb_type == 1 || amd_chipset.nb_type == 3) { - addr = PCIE_P_CNTL; - pci_write_config_dword(amd_chipset.nb_dev, - NB_PCIE_INDX_ADDR, addr); - pci_read_config_dword(amd_chipset.nb_dev, - NB_PCIE_INDX_DATA, &val); - - val &= ~(1 | (1 << 3) | (1 << 4) | (1 << 9) | (1 << 12)); - val |= bit | (bit << 3) | (bit << 12); - val |= ((!bit) << 4) | ((!bit) << 9); - pci_write_config_dword(amd_chipset.nb_dev, - NB_PCIE_INDX_DATA, val); - - addr = BIF_NB; - pci_write_config_dword(amd_chipset.nb_dev, - NB_PCIE_INDX_ADDR, addr); - pci_read_config_dword(amd_chipset.nb_dev, - NB_PCIE_INDX_DATA, &val); - val &= ~(1 << 8); - val |= bit << 8; - - pci_write_config_dword(amd_chipset.nb_dev, - NB_PCIE_INDX_DATA, val); - } else if (amd_chipset.nb_type == 2) { - addr = NB_PIF0_PWRDOWN_0; - pci_write_config_dword(amd_chipset.nb_dev, - NB_PCIE_INDX_ADDR, addr); - pci_read_config_dword(amd_chipset.nb_dev, - NB_PCIE_INDX_DATA, &val); - if (disable) - val &= ~(0x3f << 7); - else - val |= 0x3f << 7; - - pci_write_config_dword(amd_chipset.nb_dev, - NB_PCIE_INDX_DATA, val); - - addr = NB_PIF0_PWRDOWN_1; - pci_write_config_dword(amd_chipset.nb_dev, - NB_PCIE_INDX_ADDR, addr); - pci_read_config_dword(amd_chipset.nb_dev, - NB_PCIE_INDX_DATA, &val); - if (disable) - val &= ~(0x3f << 7); - else - val |= 0x3f << 7; - - pci_write_config_dword(amd_chipset.nb_dev, - NB_PCIE_INDX_DATA, val); - } - - spin_unlock_irqrestore(&amd_lock, flags); - return; -} - -void usb_amd_quirk_pll_disable(void) -{ - usb_amd_quirk_pll(1); -} -EXPORT_SYMBOL_GPL(usb_amd_quirk_pll_disable); - -void usb_amd_quirk_pll_enable(void) -{ - usb_amd_quirk_pll(0); -} -EXPORT_SYMBOL_GPL(usb_amd_quirk_pll_enable); - -void usb_amd_dev_put(void) -{ - struct pci_dev *nb, *smbus; - unsigned long flags; - - spin_lock_irqsave(&amd_lock, flags); - - amd_chipset.probe_count--; - if (amd_chipset.probe_count > 0) { - spin_unlock_irqrestore(&amd_lock, flags); - return; - } - - /* save them to pci_dev_put outside of spinlock */ - nb = amd_chipset.nb_dev; - smbus = amd_chipset.smbus_dev; - - amd_chipset.nb_dev = NULL; - amd_chipset.smbus_dev = NULL; - amd_chipset.nb_type = 0; - amd_chipset.sb_type = 0; - amd_chipset.isoc_reqs = 0; - amd_chipset.probe_result = 0; - - spin_unlock_irqrestore(&amd_lock, flags); - - if (nb) - pci_dev_put(nb); - if (smbus) - pci_dev_put(smbus); -} -EXPORT_SYMBOL_GPL(usb_amd_dev_put); - -/* - * Make sure the controller is completely inactive, unable to - * generate interrupts or do DMA. - */ -void uhci_reset_hc(struct pci_dev *pdev, unsigned long base) -{ - /* Turn off PIRQ enable and SMI enable. (This also turns off the - * BIOS's USB Legacy Support.) Turn off all the R/WC bits too. - */ - pci_write_config_word(pdev, UHCI_USBLEGSUP, UHCI_USBLEGSUP_RWC); - - /* Reset the HC - this will force us to get a - * new notification of any already connected - * ports due to the virtual disconnect that it - * implies. - */ - outw(UHCI_USBCMD_HCRESET, base + UHCI_USBCMD); - mb(); - udelay(5); - if (inw(base + UHCI_USBCMD) & UHCI_USBCMD_HCRESET) - dev_warn(&pdev->dev, "HCRESET not completed yet!\n"); - - /* Just to be safe, disable interrupt requests and - * make sure the controller is stopped. - */ - outw(0, base + UHCI_USBINTR); - outw(0, base + UHCI_USBCMD); -} -EXPORT_SYMBOL_GPL(uhci_reset_hc); - -/* - * Initialize a controller that was newly discovered or has just been - * resumed. In either case we can't be sure of its previous state. - * - * Returns: 1 if the controller was reset, 0 otherwise. - */ -int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base) -{ - //u16 legsup; - unsigned int cmd, intr; - - /* - * When restarting a suspended controller, we expect all the - * settings to be the same as we left them: - * - * PIRQ and SMI disabled, no R/W bits set in USBLEGSUP; - * Controller is stopped and configured with EGSM set; - * No interrupts enabled except possibly Resume Detect. - * - * If any of these conditions are violated we do a complete reset. - */ - #if 0 - pci_read_config_word(pdev, UHCI_USBLEGSUP, &legsup); - if (legsup & ~(UHCI_USBLEGSUP_RO | UHCI_USBLEGSUP_RWC)) { - dev_dbg(&pdev->dev, "%s: legsup = 0x%04x\n", - __func__, legsup); - goto reset_needed; - } - #endif - - cmd = inw(base + UHCI_USBCMD); -// if ((cmd & UHCI_USBCMD_RUN) || !(cmd & UHCI_USBCMD_CONFIGURE) || -// !(cmd & UHCI_USBCMD_EGSM)) { - if ((cmd & UHCI_USBCMD_RUN) || !(cmd & UHCI_USBCMD_EGSM)) { - dev_dbg(&pdev->dev, "%s: cmd = 0x%04x\n", - __func__, cmd); - goto reset_needed; - } - - intr = inw(base + UHCI_USBINTR); - if (intr & (~UHCI_USBINTR_RESUME)) { - dev_dbg(&pdev->dev, "%s: intr = 0x%04x\n", - __func__, intr); - goto reset_needed; - } - return 0; - -reset_needed: - dev_dbg(&pdev->dev, "Performing full reset\n"); - uhci_reset_hc(pdev, base); - return 1; -} -EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc); - -static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask) -{ - u16 cmd; - return !pci_read_config_word(pdev, PCI_COMMAND, &cmd) && (cmd & mask); -} - -#define pio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_IO) -#define mmio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_MEMORY) - -static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev) -{ - unsigned long base = 0; - int i; - - if (!pio_enabled(pdev)) - return; - - for (i = 0; i < PCI_ROM_RESOURCE; i++) - if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) { - base = pci_resource_start(pdev, i); - break; - } - - if (base) - uhci_check_and_reset_hc(pdev, base); -} - -static int __devinit mmio_resource_enabled(struct pci_dev *pdev, int idx) -{ - return pci_resource_start(pdev, idx) && mmio_enabled(pdev); -} - -static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) -{ - void __iomem *base; - u32 control; - u32 fminterval; - int cnt; - - if (!mmio_resource_enabled(pdev, 0)) - return; - - base = pci_ioremap_bar(pdev, 0); - if (base == NULL) - return; - - control = readl(base + OHCI_CONTROL); - -/* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */ -#ifdef __hppa__ -#define OHCI_CTRL_MASK (OHCI_CTRL_RWC | OHCI_CTRL_IR) -#else -#define OHCI_CTRL_MASK OHCI_CTRL_RWC - - if (control & OHCI_CTRL_IR) { - int wait_time = 500; /* arbitrary; 5 seconds */ - writel(OHCI_INTR_OC, base + OHCI_INTRENABLE); - writel(OHCI_OCR, base + OHCI_CMDSTATUS); - while (wait_time > 0 && - readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) { - wait_time -= 10; - msleep(10); - } - if (wait_time <= 0) - dev_warn(&pdev->dev, "OHCI: BIOS handoff failed" - " (BIOS bug?) %08x\n", - readl(base + OHCI_CONTROL)); - } -#endif - - /* disable interrupts */ - writel((u32) ~0, base + OHCI_INTRDISABLE); - - /* Reset the USB bus, if the controller isn't already in RESET */ - if (control & OHCI_HCFS) { - /* Go into RESET, preserving RWC (and possibly IR) */ - writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); - readl(base + OHCI_CONTROL); - - /* drive bus reset for at least 50 ms (7.1.7.5) */ - msleep(50); - } - - /* software reset of the controller, preserving HcFmInterval */ - fminterval = readl(base + OHCI_FMINTERVAL); - writel(OHCI_HCR, base + OHCI_CMDSTATUS); - - /* reset requires max 10 us delay */ - for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */ - if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0) - break; - udelay(1); - } - writel(fminterval, base + OHCI_FMINTERVAL); - - /* Now the controller is safely in SUSPEND and nothing can wake it up */ - iounmap(base); -} - -static const struct dmi_system_id __devinitconst ehci_dmi_nohandoff_table[] = { - { - /* Pegatron Lucid (ExoPC) */ - .matches = { - DMI_MATCH(DMI_BOARD_NAME, "EXOPG06411"), - DMI_MATCH(DMI_BIOS_VERSION, "Lucid-CE-133"), - }, - }, - { - /* Pegatron Lucid (Ordissimo AIRIS) */ - .matches = { - DMI_MATCH(DMI_BOARD_NAME, "M11JB"), - DMI_MATCH(DMI_BIOS_VERSION, "Lucid-GE-133"), - }, - }, - { } -}; - -static void __devinit ehci_bios_handoff(struct pci_dev *pdev, - void __iomem *op_reg_base, - u32 cap, u8 offset) -{ - int try_handoff = 1, tried_handoff = 0; - - /* The Pegatron Lucid tablet sporadically waits for 98 seconds trying - * the handoff on its unused controller. Skip it. */ - if (pdev->vendor == 0x8086 && pdev->device == 0x283a) { - if (dmi_check_system(ehci_dmi_nohandoff_table)) - try_handoff = 0; - } - - if (try_handoff && (cap & EHCI_USBLEGSUP_BIOS)) { - dev_dbg(&pdev->dev, "EHCI: BIOS handoff\n"); - -#if 0 -/* aleksey_gorelov@phoenix.com reports that some systems need SMI forced on, - * but that seems dubious in general (the BIOS left it off intentionally) - * and is known to prevent some systems from booting. so we won't do this - * unless maybe we can determine when we're on a system that needs SMI forced. - */ - /* BIOS workaround (?): be sure the pre-Linux code - * receives the SMI - */ - pci_read_config_dword(pdev, offset + EHCI_USBLEGCTLSTS, &val); - pci_write_config_dword(pdev, offset + EHCI_USBLEGCTLSTS, - val | EHCI_USBLEGCTLSTS_SOOE); -#endif - - /* some systems get upset if this semaphore is - * set for any other reason than forcing a BIOS - * handoff.. - */ - pci_write_config_byte(pdev, offset + 3, 1); - } - - /* if boot firmware now owns EHCI, spin till it hands it over. */ - if (try_handoff) { - int msec = 1000; - while ((cap & EHCI_USBLEGSUP_BIOS) && (msec > 0)) { - tried_handoff = 1; - msleep(10); - msec -= 10; - pci_read_config_dword(pdev, offset, &cap); - } - } - - if (cap & EHCI_USBLEGSUP_BIOS) { - /* well, possibly buggy BIOS... try to shut it down, - * and hope nothing goes too wrong - */ - if (try_handoff) - dev_warn(&pdev->dev, "EHCI: BIOS handoff failed" - " (BIOS bug?) %08x\n", cap); - pci_write_config_byte(pdev, offset + 2, 0); - } - - /* just in case, always disable EHCI SMIs */ - pci_write_config_dword(pdev, offset + EHCI_USBLEGCTLSTS, 0); - - /* If the BIOS ever owned the controller then we can't expect - * any power sessions to remain intact. - */ - if (tried_handoff) - writel(0, op_reg_base + EHCI_CONFIGFLAG); -} - -static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) -{ - void __iomem *base, *op_reg_base; - u32 hcc_params, cap, val; - u8 offset, cap_length; - int wait_time, count = 256/4; - - if (!mmio_resource_enabled(pdev, 0)) - return; - - base = pci_ioremap_bar(pdev, 0); - if (base == NULL) - return; - - cap_length = readb(base); - op_reg_base = base + cap_length; - - /* EHCI 0.96 and later may have "extended capabilities" - * spec section 5.1 explains the bios handoff, e.g. for - * booting from USB disk or using a usb keyboard - */ - hcc_params = readl(base + EHCI_HCC_PARAMS); - offset = (hcc_params >> 8) & 0xff; - while (offset && --count) { - pci_read_config_dword(pdev, offset, &cap); - - switch (cap & 0xff) { - case 1: - ehci_bios_handoff(pdev, op_reg_base, cap, offset); - break; - case 0: /* Illegal reserved cap, set cap=0 so we exit */ - cap = 0; /* then fallthrough... */ - default: - dev_warn(&pdev->dev, "EHCI: unrecognized capability " - "%02x\n", cap & 0xff); - } - offset = (cap >> 8) & 0xff; - } - if (!count) - dev_printk(KERN_DEBUG, &pdev->dev, "EHCI: capability loop?\n"); - - /* - * halt EHCI & disable its interrupts in any case - */ - val = readl(op_reg_base + EHCI_USBSTS); - if ((val & EHCI_USBSTS_HALTED) == 0) { - val = readl(op_reg_base + EHCI_USBCMD); - val &= ~EHCI_USBCMD_RUN; - writel(val, op_reg_base + EHCI_USBCMD); - - wait_time = 2000; - do { - writel(0x3f, op_reg_base + EHCI_USBSTS); - udelay(100); - wait_time -= 100; - val = readl(op_reg_base + EHCI_USBSTS); - if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) { - break; - } - } while (wait_time > 0); - } - writel(0, op_reg_base + EHCI_USBINTR); - writel(0x3f, op_reg_base + EHCI_USBSTS); - - iounmap(base); -} - -/* - * 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; -} - -#define PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI 0x8C31 - -bool usb_is_intel_ppt_switchable_xhci(struct pci_dev *pdev) -{ - return pdev->class == PCI_CLASS_SERIAL_USB_XHCI && - pdev->vendor == PCI_VENDOR_ID_INTEL && - pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI; -} - -/* The Intel Lynx Point chipset also has switchable ports. */ -bool usb_is_intel_lpt_switchable_xhci(struct pci_dev *pdev) -{ - return pdev->class == PCI_CLASS_SERIAL_USB_XHCI && - pdev->vendor == PCI_VENDOR_ID_INTEL && - pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI; -} - -bool usb_is_intel_switchable_xhci(struct pci_dev *pdev) -{ - return usb_is_intel_ppt_switchable_xhci(pdev) || - usb_is_intel_lpt_switchable_xhci(pdev); -} -EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci); - -/* - * Intel's Panther Point chipset has two host controllers (EHCI and xHCI) that - * share some number of ports. These ports can be switched between either - * controller. Not all of the ports under the EHCI host controller may be - * switchable. - * - * The ports should be switched over to xHCI before PCI probes for any device - * start. This avoids active devices under EHCI being disconnected during the - * port switchover, which could cause loss of data on USB storage devices, or - * failed boot when the root file system is on a USB mass storage device and is - * enumerated under EHCI first. - * - * We write into the xHC's PCI configuration space in some Intel-specific - * registers to switch the ports over. The USB 3.0 terminations and the USB - * 2.0 data wires are switched separately. We want to enable the SuperSpeed - * terminations before switching the USB 2.0 wires over, so that USB 3.0 - * devices connect at SuperSpeed, rather than at USB 2.0 speeds. - */ -void usb_enable_xhci_ports(struct pci_dev *xhci_pdev) -{ - u32 ports_available; - - /* Don't switchover the ports if the user hasn't compiled the xHCI - * driver. Otherwise they will see "dead" USB ports that don't power - * the devices. - */ - if (!IS_ENABLED(CONFIG_USB_XHCI_HCD)) { - dev_warn(&xhci_pdev->dev, - "CONFIG_USB_XHCI_HCD is turned off, " - "defaulting to EHCI.\n"); - dev_warn(&xhci_pdev->dev, - "USB 3.0 devices will work at USB 2.0 speeds.\n"); - return; - } - - ports_available = 0xffffffff; - /* Write USB3_PSSEN, the USB 3.0 Port SuperSpeed Enable - * Register, to turn on SuperSpeed terminations for all - * available ports. - */ - pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN, - cpu_to_le32(ports_available)); - - pci_read_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN, - &ports_available); - dev_dbg(&xhci_pdev->dev, "USB 3.0 ports that are now enabled " - "under xHCI: 0x%x\n", ports_available); - - ports_available = 0xffffffff; - /* Write XUSB2PR, the xHC USB 2.0 Port Routing Register, to - * switch the USB 2.0 power and data lines over to the xHCI - * host. - */ - pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR, - cpu_to_le32(ports_available)); - - pci_read_config_dword(xhci_pdev, USB_INTEL_XUSB2PR, - &ports_available); - dev_dbg(&xhci_pdev->dev, "USB 2.0 ports that are now switched over " - "to xHCI: 0x%x\n", ports_available); -} -EXPORT_SYMBOL_GPL(usb_enable_xhci_ports); - -/** - * 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); - } - } - - val = readl(base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET); - /* Mask off (turn off) any enabled SMIs */ - val &= XHCI_LEGACY_DISABLE_SMI; - /* Mask all SMI events bits, RW1C */ - val |= XHCI_LEGACY_SMI_EVENTS; - /* Disable any BIOS SMIs and clear all SMI events*/ - writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET); - - if (usb_is_intel_switchable_xhci(pdev)) - usb_enable_xhci_ports(pdev); -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) -{ - /* Skip Netlogic mips SoC's internal PCI USB controller. - * This device does not need/support EHCI/OHCI handoff - */ - if (pdev->vendor == 0x184e) /* vendor Netlogic */ - return; - if (pdev->class != PCI_CLASS_SERIAL_USB_UHCI && - pdev->class != PCI_CLASS_SERIAL_USB_OHCI && - pdev->class != PCI_CLASS_SERIAL_USB_EHCI && - pdev->class != PCI_CLASS_SERIAL_USB_XHCI) - return; - - if (pci_enable_device(pdev) < 0) { - dev_warn(&pdev->dev, "Can't enable PCI device, " - "BIOS handoff failed.\n"); - return; - } - if (pdev->class == PCI_CLASS_SERIAL_USB_UHCI) - quirk_usb_handoff_uhci(pdev); - else if (pdev->class == PCI_CLASS_SERIAL_USB_OHCI) - 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); - pci_disable_device(pdev); -} -DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_SERIAL_USB, 8, quirk_usb_early_handoff); diff --git a/ANDROID_3.4.5/drivers/usb/host/pci-quirks.h b/ANDROID_3.4.5/drivers/usb/host/pci-quirks.h deleted file mode 100644 index b1002a8e..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/pci-quirks.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef __LINUX_USB_PCI_QUIRKS_H -#define __LINUX_USB_PCI_QUIRKS_H - -#ifdef CONFIG_PCI -void uhci_reset_hc(struct pci_dev *pdev, unsigned long base); -int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base); -int usb_amd_find_chipset_info(void); -void usb_amd_dev_put(void); -void usb_amd_quirk_pll_disable(void); -void usb_amd_quirk_pll_enable(void); -bool usb_is_intel_switchable_xhci(struct pci_dev *pdev); -void usb_enable_xhci_ports(struct pci_dev *xhci_pdev); -#else -static inline void usb_amd_quirk_pll_disable(void) {} -static inline void usb_amd_quirk_pll_enable(void) {} -static inline void usb_amd_dev_put(void) {} -#endif /* CONFIG_PCI */ - -#endif /* __LINUX_USB_PCI_QUIRKS_H */ diff --git a/ANDROID_3.4.5/drivers/usb/host/r8a66597-hcd.c b/ANDROID_3.4.5/drivers/usb/host/r8a66597-hcd.c deleted file mode 100644 index 2bf1320d..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/r8a66597-hcd.c +++ /dev/null @@ -1,2558 +0,0 @@ -/* - * R8A66597 HCD (Host Controller Driver) - * - * Copyright (C) 2006-2007 Renesas Solutions Corp. - * Portions Copyright (C) 2004 Psion Teklogix (for NetBook PRO) - * Portions Copyright (C) 2004-2005 David Brownell - * Portions Copyright (C) 1999 Roman Weissgaerber - * - * Author : Yoshihiro Shimoda - * - * 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; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "r8a66597.h" - -MODULE_DESCRIPTION("R8A66597 USB Host Controller Driver"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Yoshihiro Shimoda"); -MODULE_ALIAS("platform:r8a66597_hcd"); - -#define DRIVER_VERSION "2009-05-26" - -static const char hcd_name[] = "r8a66597_hcd"; - -static void packet_write(struct r8a66597 *r8a66597, u16 pipenum); -static int r8a66597_get_frame(struct usb_hcd *hcd); - -/* this function must be called with interrupt disabled */ -static void enable_pipe_irq(struct r8a66597 *r8a66597, u16 pipenum, - unsigned long reg) -{ - u16 tmp; - - tmp = r8a66597_read(r8a66597, INTENB0); - r8a66597_bclr(r8a66597, BEMPE | NRDYE | BRDYE, INTENB0); - r8a66597_bset(r8a66597, 1 << pipenum, reg); - r8a66597_write(r8a66597, tmp, INTENB0); -} - -/* this function must be called with interrupt disabled */ -static void disable_pipe_irq(struct r8a66597 *r8a66597, u16 pipenum, - unsigned long reg) -{ - u16 tmp; - - tmp = r8a66597_read(r8a66597, INTENB0); - r8a66597_bclr(r8a66597, BEMPE | NRDYE | BRDYE, INTENB0); - r8a66597_bclr(r8a66597, 1 << pipenum, reg); - r8a66597_write(r8a66597, tmp, INTENB0); -} - -static void set_devadd_reg(struct r8a66597 *r8a66597, u8 r8a66597_address, - u16 usbspd, u8 upphub, u8 hubport, int port) -{ - u16 val; - unsigned long devadd_reg = get_devadd_addr(r8a66597_address); - - val = (upphub << 11) | (hubport << 8) | (usbspd << 6) | (port & 0x0001); - r8a66597_write(r8a66597, val, devadd_reg); -} - -static int r8a66597_clock_enable(struct r8a66597 *r8a66597) -{ - u16 tmp; - int i = 0; - - if (r8a66597->pdata->on_chip) { -#ifdef CONFIG_HAVE_CLK - clk_enable(r8a66597->clk); -#endif - do { - r8a66597_write(r8a66597, SCKE, SYSCFG0); - tmp = r8a66597_read(r8a66597, SYSCFG0); - if (i++ > 1000) { - printk(KERN_ERR "r8a66597: reg access fail.\n"); - return -ENXIO; - } - } while ((tmp & SCKE) != SCKE); - r8a66597_write(r8a66597, 0x04, 0x02); - } else { - do { - r8a66597_write(r8a66597, USBE, SYSCFG0); - tmp = r8a66597_read(r8a66597, SYSCFG0); - if (i++ > 1000) { - printk(KERN_ERR "r8a66597: reg access fail.\n"); - return -ENXIO; - } - } while ((tmp & USBE) != USBE); - r8a66597_bclr(r8a66597, USBE, SYSCFG0); - r8a66597_mdfy(r8a66597, get_xtal_from_pdata(r8a66597->pdata), - XTAL, SYSCFG0); - - i = 0; - r8a66597_bset(r8a66597, XCKE, SYSCFG0); - do { - msleep(1); - tmp = r8a66597_read(r8a66597, SYSCFG0); - if (i++ > 500) { - printk(KERN_ERR "r8a66597: reg access fail.\n"); - return -ENXIO; - } - } while ((tmp & SCKE) != SCKE); - } - - return 0; -} - -static void r8a66597_clock_disable(struct r8a66597 *r8a66597) -{ - r8a66597_bclr(r8a66597, SCKE, SYSCFG0); - udelay(1); - - if (r8a66597->pdata->on_chip) { -#ifdef CONFIG_HAVE_CLK - clk_disable(r8a66597->clk); -#endif - } else { - r8a66597_bclr(r8a66597, PLLC, SYSCFG0); - r8a66597_bclr(r8a66597, XCKE, SYSCFG0); - r8a66597_bclr(r8a66597, USBE, SYSCFG0); - } -} - -static void r8a66597_enable_port(struct r8a66597 *r8a66597, int port) -{ - u16 val; - - val = port ? DRPD : DCFM | DRPD; - r8a66597_bset(r8a66597, val, get_syscfg_reg(port)); - r8a66597_bset(r8a66597, HSE, get_syscfg_reg(port)); - - r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR, get_dmacfg_reg(port)); - r8a66597_bclr(r8a66597, DTCHE, get_intenb_reg(port)); - r8a66597_bset(r8a66597, ATTCHE, get_intenb_reg(port)); -} - -static void r8a66597_disable_port(struct r8a66597 *r8a66597, int port) -{ - u16 val, tmp; - - r8a66597_write(r8a66597, 0, get_intenb_reg(port)); - r8a66597_write(r8a66597, 0, get_intsts_reg(port)); - - r8a66597_port_power(r8a66597, port, 0); - - do { - tmp = r8a66597_read(r8a66597, SOFCFG) & EDGESTS; - udelay(640); - } while (tmp == EDGESTS); - - val = port ? DRPD : DCFM | DRPD; - r8a66597_bclr(r8a66597, val, get_syscfg_reg(port)); - r8a66597_bclr(r8a66597, HSE, get_syscfg_reg(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) - return ret; - - r8a66597_bset(r8a66597, vif & LDRV, PINCFG); - r8a66597_bset(r8a66597, USBE, SYSCFG0); - - r8a66597_bset(r8a66597, BEMPE | NRDYE | BRDYE, INTENB0); - r8a66597_bset(r8a66597, irq_sense & INTL, SOFCFG); - r8a66597_bset(r8a66597, BRDY0, BRDYENB); - r8a66597_bset(r8a66597, BEMP0, BEMPENB); - - r8a66597_bset(r8a66597, endian & BIGEND, CFIFOSEL); - r8a66597_bset(r8a66597, endian & BIGEND, D0FIFOSEL); - r8a66597_bset(r8a66597, endian & BIGEND, D1FIFOSEL); - r8a66597_bset(r8a66597, TRNENSEL, SOFCFG); - - r8a66597_bset(r8a66597, SIGNE | SACKE, INTENB1); - - for (port = 0; port < r8a66597->max_root_hub; port++) - r8a66597_enable_port(r8a66597, port); - - return 0; -} - -static void disable_controller(struct r8a66597 *r8a66597) -{ - int port; - - /* disable interrupts */ - r8a66597_write(r8a66597, 0, INTENB0); - r8a66597_write(r8a66597, 0, INTENB1); - r8a66597_write(r8a66597, 0, BRDYENB); - r8a66597_write(r8a66597, 0, BEMPENB); - r8a66597_write(r8a66597, 0, NRDYENB); - - /* clear status */ - r8a66597_write(r8a66597, 0, BRDYSTS); - r8a66597_write(r8a66597, 0, NRDYSTS); - r8a66597_write(r8a66597, 0, BEMPSTS); - - for (port = 0; port < r8a66597->max_root_hub; port++) - r8a66597_disable_port(r8a66597, port); - - r8a66597_clock_disable(r8a66597); -} - -static int get_parent_r8a66597_address(struct r8a66597 *r8a66597, - struct usb_device *udev) -{ - struct r8a66597_device *dev; - - if (udev->parent && udev->parent->devnum != 1) - udev = udev->parent; - - dev = dev_get_drvdata(&udev->dev); - if (dev) - return dev->address; - else - return 0; -} - -static int is_child_device(char *devpath) -{ - return (devpath[2] ? 1 : 0); -} - -static int is_hub_limit(char *devpath) -{ - return ((strlen(devpath) >= 4) ? 1 : 0); -} - -static void get_port_number(struct r8a66597 *r8a66597, - char *devpath, u16 *root_port, u16 *hub_port) -{ - if (root_port) { - *root_port = (devpath[0] & 0x0F) - 1; - if (*root_port >= r8a66597->max_root_hub) - printk(KERN_ERR "r8a66597: Illegal root port number.\n"); - } - if (hub_port) - *hub_port = devpath[2] & 0x0F; -} - -static u16 get_r8a66597_usb_speed(enum usb_device_speed speed) -{ - u16 usbspd = 0; - - switch (speed) { - case USB_SPEED_LOW: - usbspd = LSMODE; - break; - case USB_SPEED_FULL: - usbspd = FSMODE; - break; - case USB_SPEED_HIGH: - usbspd = HSMODE; - break; - default: - printk(KERN_ERR "r8a66597: unknown speed\n"); - break; - } - - return usbspd; -} - -static void set_child_connect_map(struct r8a66597 *r8a66597, int address) -{ - int idx; - - idx = address / 32; - r8a66597->child_connect_map[idx] |= 1 << (address % 32); -} - -static void put_child_connect_map(struct r8a66597 *r8a66597, int address) -{ - int idx; - - idx = address / 32; - r8a66597->child_connect_map[idx] &= ~(1 << (address % 32)); -} - -static void set_pipe_reg_addr(struct r8a66597_pipe *pipe, u8 dma_ch) -{ - u16 pipenum = pipe->info.pipenum; - const unsigned long fifoaddr[] = {D0FIFO, D1FIFO, CFIFO}; - const unsigned long fifosel[] = {D0FIFOSEL, D1FIFOSEL, CFIFOSEL}; - const unsigned long fifoctr[] = {D0FIFOCTR, D1FIFOCTR, CFIFOCTR}; - - if (dma_ch > R8A66597_PIPE_NO_DMA) /* dma fifo not use? */ - dma_ch = R8A66597_PIPE_NO_DMA; - - pipe->fifoaddr = fifoaddr[dma_ch]; - pipe->fifosel = fifosel[dma_ch]; - pipe->fifoctr = fifoctr[dma_ch]; - - if (pipenum == 0) - pipe->pipectr = DCPCTR; - else - pipe->pipectr = get_pipectr_addr(pipenum); - - if (check_bulk_or_isoc(pipenum)) { - pipe->pipetre = get_pipetre_addr(pipenum); - pipe->pipetrn = get_pipetrn_addr(pipenum); - } else { - pipe->pipetre = 0; - pipe->pipetrn = 0; - } -} - -static struct r8a66597_device * -get_urb_to_r8a66597_dev(struct r8a66597 *r8a66597, struct urb *urb) -{ - if (usb_pipedevice(urb->pipe) == 0) - return &r8a66597->device0; - - return dev_get_drvdata(&urb->dev->dev); -} - -static int make_r8a66597_device(struct r8a66597 *r8a66597, - struct urb *urb, u8 addr) -{ - struct r8a66597_device *dev; - int usb_address = urb->setup_packet[2]; /* urb->pipe is address 0 */ - - dev = kzalloc(sizeof(struct r8a66597_device), GFP_ATOMIC); - if (dev == NULL) - return -ENOMEM; - - dev_set_drvdata(&urb->dev->dev, dev); - dev->udev = urb->dev; - dev->address = addr; - dev->usb_address = usb_address; - dev->state = USB_STATE_ADDRESS; - dev->ep_in_toggle = 0; - dev->ep_out_toggle = 0; - INIT_LIST_HEAD(&dev->device_list); - list_add_tail(&dev->device_list, &r8a66597->child_device); - - get_port_number(r8a66597, urb->dev->devpath, - &dev->root_port, &dev->hub_port); - if (!is_child_device(urb->dev->devpath)) - r8a66597->root_hub[dev->root_port].dev = dev; - - set_devadd_reg(r8a66597, dev->address, - get_r8a66597_usb_speed(urb->dev->speed), - get_parent_r8a66597_address(r8a66597, urb->dev), - dev->hub_port, dev->root_port); - - return 0; -} - -/* this function must be called with interrupt disabled */ -static u8 alloc_usb_address(struct r8a66597 *r8a66597, struct urb *urb) -{ - u8 addr; /* R8A66597's address */ - struct r8a66597_device *dev; - - if (is_hub_limit(urb->dev->devpath)) { - dev_err(&urb->dev->dev, "External hub limit reached.\n"); - return 0; - } - - dev = get_urb_to_r8a66597_dev(r8a66597, urb); - if (dev && dev->state >= USB_STATE_ADDRESS) - return dev->address; - - for (addr = 1; addr <= R8A66597_MAX_DEVICE; addr++) { - if (r8a66597->address_map & (1 << addr)) - continue; - - dbg("alloc_address: r8a66597_addr=%d", addr); - r8a66597->address_map |= 1 << addr; - - if (make_r8a66597_device(r8a66597, urb, addr) < 0) - return 0; - - return addr; - } - - dev_err(&urb->dev->dev, - "cannot communicate with a USB device more than 10.(%x)\n", - r8a66597->address_map); - - return 0; -} - -/* this function must be called with interrupt disabled */ -static void free_usb_address(struct r8a66597 *r8a66597, - struct r8a66597_device *dev, int reset) -{ - int port; - - if (!dev) - return; - - dbg("free_addr: addr=%d", dev->address); - - dev->state = USB_STATE_DEFAULT; - r8a66597->address_map &= ~(1 << dev->address); - dev->address = 0; - /* - * Only when resetting USB, it is necessary to erase drvdata. When - * a usb device with usb hub is disconnect, "dev->udev" is already - * freed on usb_desconnect(). So we cannot access the data. - */ - if (reset) - dev_set_drvdata(&dev->udev->dev, NULL); - list_del(&dev->device_list); - kfree(dev); - - for (port = 0; port < r8a66597->max_root_hub; port++) { - if (r8a66597->root_hub[port].dev == dev) { - r8a66597->root_hub[port].dev = NULL; - break; - } - } -} - -static void r8a66597_reg_wait(struct r8a66597 *r8a66597, unsigned long reg, - u16 mask, u16 loop) -{ - u16 tmp; - int i = 0; - - do { - tmp = r8a66597_read(r8a66597, reg); - if (i++ > 1000000) { - printk(KERN_ERR "r8a66597: register%lx, loop %x " - "is timeout\n", reg, loop); - break; - } - ndelay(1); - } while ((tmp & mask) != loop); -} - -/* this function must be called with interrupt disabled */ -static void pipe_start(struct r8a66597 *r8a66597, struct r8a66597_pipe *pipe) -{ - u16 tmp; - - tmp = r8a66597_read(r8a66597, pipe->pipectr) & PID; - if ((pipe->info.pipenum != 0) & ((tmp & PID_STALL) != 0)) /* stall? */ - r8a66597_mdfy(r8a66597, PID_NAK, PID, pipe->pipectr); - r8a66597_mdfy(r8a66597, PID_BUF, PID, pipe->pipectr); -} - -/* this function must be called with interrupt disabled */ -static void pipe_stop(struct r8a66597 *r8a66597, struct r8a66597_pipe *pipe) -{ - u16 tmp; - - tmp = r8a66597_read(r8a66597, pipe->pipectr) & PID; - if ((tmp & PID_STALL11) != PID_STALL11) /* force stall? */ - r8a66597_mdfy(r8a66597, PID_STALL, PID, pipe->pipectr); - r8a66597_mdfy(r8a66597, PID_NAK, PID, pipe->pipectr); - r8a66597_reg_wait(r8a66597, pipe->pipectr, PBUSY, 0); -} - -/* this function must be called with interrupt disabled */ -static void clear_all_buffer(struct r8a66597 *r8a66597, - struct r8a66597_pipe *pipe) -{ - u16 tmp; - - if (!pipe || pipe->info.pipenum == 0) - return; - - pipe_stop(r8a66597, pipe); - r8a66597_bset(r8a66597, ACLRM, pipe->pipectr); - tmp = r8a66597_read(r8a66597, pipe->pipectr); - tmp = r8a66597_read(r8a66597, pipe->pipectr); - tmp = r8a66597_read(r8a66597, pipe->pipectr); - r8a66597_bclr(r8a66597, ACLRM, pipe->pipectr); -} - -/* this function must be called with interrupt disabled */ -static void r8a66597_pipe_toggle(struct r8a66597 *r8a66597, - struct r8a66597_pipe *pipe, int toggle) -{ - if (toggle) - r8a66597_bset(r8a66597, SQSET, pipe->pipectr); - else - r8a66597_bset(r8a66597, SQCLR, pipe->pipectr); -} - -static inline unsigned short mbw_value(struct r8a66597 *r8a66597) -{ - if (r8a66597->pdata->on_chip) - return MBW_32; - else - return MBW_16; -} - -/* this function must be called with interrupt disabled */ -static inline void cfifo_change(struct r8a66597 *r8a66597, u16 pipenum) -{ - unsigned short mbw = mbw_value(r8a66597); - - r8a66597_mdfy(r8a66597, mbw | pipenum, mbw | CURPIPE, CFIFOSEL); - r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, pipenum); -} - -/* this function must be called with interrupt disabled */ -static inline void fifo_change_from_pipe(struct r8a66597 *r8a66597, - struct r8a66597_pipe *pipe) -{ - unsigned short mbw = mbw_value(r8a66597); - - cfifo_change(r8a66597, 0); - r8a66597_mdfy(r8a66597, mbw | 0, mbw | CURPIPE, D0FIFOSEL); - r8a66597_mdfy(r8a66597, mbw | 0, mbw | CURPIPE, D1FIFOSEL); - - r8a66597_mdfy(r8a66597, mbw | pipe->info.pipenum, mbw | CURPIPE, - pipe->fifosel); - r8a66597_reg_wait(r8a66597, pipe->fifosel, CURPIPE, pipe->info.pipenum); -} - -static u16 r8a66597_get_pipenum(struct urb *urb, struct usb_host_endpoint *hep) -{ - struct r8a66597_pipe *pipe = hep->hcpriv; - - if (usb_pipeendpoint(urb->pipe) == 0) - return 0; - else - return pipe->info.pipenum; -} - -static u16 get_urb_to_r8a66597_addr(struct r8a66597 *r8a66597, struct urb *urb) -{ - struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb); - - return (usb_pipedevice(urb->pipe) == 0) ? 0 : dev->address; -} - -static unsigned short *get_toggle_pointer(struct r8a66597_device *dev, - int urb_pipe) -{ - if (!dev) - return NULL; - - return usb_pipein(urb_pipe) ? &dev->ep_in_toggle : &dev->ep_out_toggle; -} - -/* this function must be called with interrupt disabled */ -static void pipe_toggle_set(struct r8a66597 *r8a66597, - struct r8a66597_pipe *pipe, - struct urb *urb, int set) -{ - struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb); - unsigned char endpoint = usb_pipeendpoint(urb->pipe); - unsigned short *toggle = get_toggle_pointer(dev, urb->pipe); - - if (!toggle) - return; - - if (set) - *toggle |= 1 << endpoint; - else - *toggle &= ~(1 << endpoint); -} - -/* this function must be called with interrupt disabled */ -static void pipe_toggle_save(struct r8a66597 *r8a66597, - struct r8a66597_pipe *pipe, - struct urb *urb) -{ - if (r8a66597_read(r8a66597, pipe->pipectr) & SQMON) - pipe_toggle_set(r8a66597, pipe, urb, 1); - else - pipe_toggle_set(r8a66597, pipe, urb, 0); -} - -/* this function must be called with interrupt disabled */ -static void pipe_toggle_restore(struct r8a66597 *r8a66597, - struct r8a66597_pipe *pipe, - struct urb *urb) -{ - struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb); - unsigned char endpoint = usb_pipeendpoint(urb->pipe); - unsigned short *toggle = get_toggle_pointer(dev, urb->pipe); - - if (!toggle) - return; - - r8a66597_pipe_toggle(r8a66597, pipe, *toggle & (1 << endpoint)); -} - -/* this function must be called with interrupt disabled */ -static void pipe_buffer_setting(struct r8a66597 *r8a66597, - struct r8a66597_pipe_info *info) -{ - u16 val = 0; - - if (info->pipenum == 0) - return; - - r8a66597_bset(r8a66597, ACLRM, get_pipectr_addr(info->pipenum)); - r8a66597_bclr(r8a66597, ACLRM, get_pipectr_addr(info->pipenum)); - r8a66597_write(r8a66597, info->pipenum, PIPESEL); - if (!info->dir_in) - val |= R8A66597_DIR; - if (info->type == R8A66597_BULK && info->dir_in) - val |= R8A66597_DBLB | R8A66597_SHTNAK; - val |= info->type | info->epnum; - r8a66597_write(r8a66597, val, PIPECFG); - - r8a66597_write(r8a66597, (info->buf_bsize << 10) | (info->bufnum), - PIPEBUF); - r8a66597_write(r8a66597, make_devsel(info->address) | info->maxpacket, - PIPEMAXP); - r8a66597_write(r8a66597, info->interval, PIPEPERI); -} - -/* this function must be called with interrupt disabled */ -static void pipe_setting(struct r8a66597 *r8a66597, struct r8a66597_td *td) -{ - struct r8a66597_pipe_info *info; - struct urb *urb = td->urb; - - if (td->pipenum > 0) { - info = &td->pipe->info; - cfifo_change(r8a66597, 0); - pipe_buffer_setting(r8a66597, info); - - if (!usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe)) && - !usb_pipecontrol(urb->pipe)) { - r8a66597_pipe_toggle(r8a66597, td->pipe, 0); - pipe_toggle_set(r8a66597, td->pipe, urb, 0); - clear_all_buffer(r8a66597, td->pipe); - usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe), 1); - } - pipe_toggle_restore(r8a66597, td->pipe, urb); - } -} - -/* this function must be called with interrupt disabled */ -static u16 get_empty_pipenum(struct r8a66597 *r8a66597, - struct usb_endpoint_descriptor *ep) -{ - u16 array[R8A66597_MAX_NUM_PIPE], i = 0, min; - - memset(array, 0, sizeof(array)); - switch (usb_endpoint_type(ep)) { - case USB_ENDPOINT_XFER_BULK: - if (usb_endpoint_dir_in(ep)) - array[i++] = 4; - else { - array[i++] = 3; - array[i++] = 5; - } - break; - case USB_ENDPOINT_XFER_INT: - if (usb_endpoint_dir_in(ep)) { - array[i++] = 6; - array[i++] = 7; - array[i++] = 8; - } else - array[i++] = 9; - break; - case USB_ENDPOINT_XFER_ISOC: - if (usb_endpoint_dir_in(ep)) - array[i++] = 2; - else - array[i++] = 1; - break; - default: - printk(KERN_ERR "r8a66597: Illegal type\n"); - return 0; - } - - i = 1; - min = array[0]; - while (array[i] != 0) { - if (r8a66597->pipe_cnt[min] > r8a66597->pipe_cnt[array[i]]) - min = array[i]; - i++; - } - - return min; -} - -static u16 get_r8a66597_type(__u8 type) -{ - u16 r8a66597_type; - - switch (type) { - case USB_ENDPOINT_XFER_BULK: - r8a66597_type = R8A66597_BULK; - break; - case USB_ENDPOINT_XFER_INT: - r8a66597_type = R8A66597_INT; - break; - case USB_ENDPOINT_XFER_ISOC: - r8a66597_type = R8A66597_ISO; - break; - default: - printk(KERN_ERR "r8a66597: Illegal type\n"); - r8a66597_type = 0x0000; - break; - } - - return r8a66597_type; -} - -static u16 get_bufnum(u16 pipenum) -{ - u16 bufnum = 0; - - if (pipenum == 0) - bufnum = 0; - else if (check_bulk_or_isoc(pipenum)) - bufnum = 8 + (pipenum - 1) * R8A66597_BUF_BSIZE*2; - else if (check_interrupt(pipenum)) - bufnum = 4 + (pipenum - 6); - else - printk(KERN_ERR "r8a66597: Illegal pipenum (%d)\n", pipenum); - - return bufnum; -} - -static u16 get_buf_bsize(u16 pipenum) -{ - u16 buf_bsize = 0; - - if (pipenum == 0) - buf_bsize = 3; - else if (check_bulk_or_isoc(pipenum)) - buf_bsize = R8A66597_BUF_BSIZE - 1; - else if (check_interrupt(pipenum)) - buf_bsize = 0; - else - printk(KERN_ERR "r8a66597: Illegal pipenum (%d)\n", pipenum); - - return buf_bsize; -} - -/* this function must be called with interrupt disabled */ -static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597, - struct r8a66597_device *dev, - struct r8a66597_pipe *pipe, - struct urb *urb) -{ - int i; - struct r8a66597_pipe_info *info = &pipe->info; - unsigned short mbw = mbw_value(r8a66597); - - /* pipe dma is only for external controlles */ - if (r8a66597->pdata->on_chip) - return; - - if ((pipe->info.pipenum != 0) && (info->type != R8A66597_INT)) { - for (i = 0; i < R8A66597_MAX_DMA_CHANNEL; i++) { - if ((r8a66597->dma_map & (1 << i)) != 0) - continue; - - dev_info(&dev->udev->dev, - "address %d, EndpointAddress 0x%02x use " - "DMA FIFO\n", usb_pipedevice(urb->pipe), - info->dir_in ? - USB_ENDPOINT_DIR_MASK + info->epnum - : info->epnum); - - r8a66597->dma_map |= 1 << i; - dev->dma_map |= 1 << i; - set_pipe_reg_addr(pipe, i); - - cfifo_change(r8a66597, 0); - r8a66597_mdfy(r8a66597, mbw | pipe->info.pipenum, - mbw | CURPIPE, pipe->fifosel); - - r8a66597_reg_wait(r8a66597, pipe->fifosel, CURPIPE, - pipe->info.pipenum); - r8a66597_bset(r8a66597, BCLR, pipe->fifoctr); - break; - } - } -} - -/* this function must be called with interrupt disabled */ -static void enable_r8a66597_pipe(struct r8a66597 *r8a66597, struct urb *urb, - struct usb_host_endpoint *hep, - struct r8a66597_pipe_info *info) -{ - struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb); - struct r8a66597_pipe *pipe = hep->hcpriv; - - dbg("enable_pipe:"); - - pipe->info = *info; - set_pipe_reg_addr(pipe, R8A66597_PIPE_NO_DMA); - r8a66597->pipe_cnt[pipe->info.pipenum]++; - dev->pipe_cnt[pipe->info.pipenum]++; - - enable_r8a66597_pipe_dma(r8a66597, dev, pipe, urb); -} - -static void r8a66597_urb_done(struct r8a66597 *r8a66597, struct urb *urb, - int status) -__releases(r8a66597->lock) -__acquires(r8a66597->lock) -{ - if (usb_pipein(urb->pipe) && usb_pipetype(urb->pipe) != PIPE_CONTROL) { - void *ptr; - - for (ptr = urb->transfer_buffer; - ptr < urb->transfer_buffer + urb->transfer_buffer_length; - ptr += PAGE_SIZE) - flush_dcache_page(virt_to_page(ptr)); - } - - usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb); - spin_unlock(&r8a66597->lock); - usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb, status); - spin_lock(&r8a66597->lock); -} - -/* this function must be called with interrupt disabled */ -static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address) -{ - struct r8a66597_td *td, *next; - struct urb *urb; - struct list_head *list = &r8a66597->pipe_queue[pipenum]; - - if (list_empty(list)) - return; - - list_for_each_entry_safe(td, next, list, queue) { - if (td->address != address) - continue; - - urb = td->urb; - list_del(&td->queue); - kfree(td); - - if (urb) - r8a66597_urb_done(r8a66597, urb, -ENODEV); - - break; - } -} - -/* this function must be called with interrupt disabled */ -static void disable_r8a66597_pipe_all(struct r8a66597 *r8a66597, - struct r8a66597_device *dev) -{ - int check_ep0 = 0; - u16 pipenum; - - if (!dev) - return; - - for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) { - if (!dev->pipe_cnt[pipenum]) - continue; - - if (!check_ep0) { - check_ep0 = 1; - force_dequeue(r8a66597, 0, dev->address); - } - - r8a66597->pipe_cnt[pipenum] -= dev->pipe_cnt[pipenum]; - dev->pipe_cnt[pipenum] = 0; - force_dequeue(r8a66597, pipenum, dev->address); - } - - dbg("disable_pipe"); - - r8a66597->dma_map &= ~(dev->dma_map); - dev->dma_map = 0; -} - -static u16 get_interval(struct urb *urb, __u8 interval) -{ - u16 time = 1; - int i; - - if (urb->dev->speed == USB_SPEED_HIGH) { - if (interval > IITV) - time = IITV; - else - time = interval ? interval - 1 : 0; - } else { - if (interval > 128) { - time = IITV; - } else { - /* calculate the nearest value for PIPEPERI */ - for (i = 0; i < 7; i++) { - if ((1 << i) < interval && - (1 << (i + 1) > interval)) - time = 1 << i; - } - } - } - - return time; -} - -static unsigned long get_timer_interval(struct urb *urb, __u8 interval) -{ - __u8 i; - unsigned long time = 1; - - if (usb_pipeisoc(urb->pipe)) - return 0; - - if (get_r8a66597_usb_speed(urb->dev->speed) == HSMODE) { - for (i = 0; i < (interval - 1); i++) - time *= 2; - time = time * 125 / 1000; /* uSOF -> msec */ - } else { - time = interval; - } - - return time; -} - -/* this function must be called with interrupt disabled */ -static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb, - struct usb_host_endpoint *hep, - struct usb_endpoint_descriptor *ep) -{ - struct r8a66597_pipe_info info; - - info.pipenum = get_empty_pipenum(r8a66597, ep); - info.address = get_urb_to_r8a66597_addr(r8a66597, urb); - info.epnum = usb_endpoint_num(ep); - info.maxpacket = usb_endpoint_maxp(ep); - info.type = get_r8a66597_type(usb_endpoint_type(ep)); - info.bufnum = get_bufnum(info.pipenum); - info.buf_bsize = get_buf_bsize(info.pipenum); - if (info.type == R8A66597_BULK) { - info.interval = 0; - info.timer_interval = 0; - } else { - info.interval = get_interval(urb, ep->bInterval); - info.timer_interval = get_timer_interval(urb, ep->bInterval); - } - if (usb_endpoint_dir_in(ep)) - info.dir_in = 1; - else - info.dir_in = 0; - - enable_r8a66597_pipe(r8a66597, urb, hep, &info); -} - -static void init_pipe_config(struct r8a66597 *r8a66597, struct urb *urb) -{ - struct r8a66597_device *dev; - - dev = get_urb_to_r8a66597_dev(r8a66597, urb); - dev->state = USB_STATE_CONFIGURED; -} - -static void pipe_irq_enable(struct r8a66597 *r8a66597, struct urb *urb, - u16 pipenum) -{ - if (pipenum == 0 && usb_pipeout(urb->pipe)) - enable_irq_empty(r8a66597, pipenum); - else - enable_irq_ready(r8a66597, pipenum); - - if (!usb_pipeisoc(urb->pipe)) - enable_irq_nrdy(r8a66597, pipenum); -} - -static void pipe_irq_disable(struct r8a66597 *r8a66597, u16 pipenum) -{ - disable_irq_ready(r8a66597, pipenum); - disable_irq_nrdy(r8a66597, pipenum); -} - -static void r8a66597_root_hub_start_polling(struct r8a66597 *r8a66597) -{ - mod_timer(&r8a66597->rh_timer, - jiffies + msecs_to_jiffies(R8A66597_RH_POLL_TIME)); -} - -static void start_root_hub_sampling(struct r8a66597 *r8a66597, int port, - int connect) -{ - struct r8a66597_root_hub *rh = &r8a66597->root_hub[port]; - - rh->old_syssts = r8a66597_read(r8a66597, get_syssts_reg(port)) & LNST; - rh->scount = R8A66597_MAX_SAMPLING; - if (connect) - rh->port |= USB_PORT_STAT_CONNECTION; - else - rh->port &= ~USB_PORT_STAT_CONNECTION; - rh->port |= USB_PORT_STAT_C_CONNECTION << 16; - - r8a66597_root_hub_start_polling(r8a66597); -} - -/* this function must be called with interrupt disabled */ -static void r8a66597_check_syssts(struct r8a66597 *r8a66597, int port, - u16 syssts) -__releases(r8a66597->lock) -__acquires(r8a66597->lock) -{ - if (syssts == SE0) { - r8a66597_write(r8a66597, ~ATTCH, get_intsts_reg(port)); - r8a66597_bset(r8a66597, ATTCHE, get_intenb_reg(port)); - } else { - if (syssts == FS_JSTS) - r8a66597_bset(r8a66597, HSE, get_syscfg_reg(port)); - else if (syssts == LS_JSTS) - r8a66597_bclr(r8a66597, HSE, get_syscfg_reg(port)); - - r8a66597_write(r8a66597, ~DTCH, get_intsts_reg(port)); - r8a66597_bset(r8a66597, DTCHE, get_intenb_reg(port)); - - if (r8a66597->bus_suspended) - usb_hcd_resume_root_hub(r8a66597_to_hcd(r8a66597)); - } - - spin_unlock(&r8a66597->lock); - usb_hcd_poll_rh_status(r8a66597_to_hcd(r8a66597)); - spin_lock(&r8a66597->lock); -} - -/* this function must be called with interrupt disabled */ -static void r8a66597_usb_connect(struct r8a66597 *r8a66597, int port) -{ - u16 speed = get_rh_usb_speed(r8a66597, port); - struct r8a66597_root_hub *rh = &r8a66597->root_hub[port]; - - rh->port &= ~(USB_PORT_STAT_HIGH_SPEED | USB_PORT_STAT_LOW_SPEED); - if (speed == HSMODE) - rh->port |= USB_PORT_STAT_HIGH_SPEED; - else if (speed == LSMODE) - rh->port |= USB_PORT_STAT_LOW_SPEED; - - rh->port &= ~USB_PORT_STAT_RESET; - rh->port |= USB_PORT_STAT_ENABLE; -} - -/* this function must be called with interrupt disabled */ -static void r8a66597_usb_disconnect(struct r8a66597 *r8a66597, int port) -{ - struct r8a66597_device *dev = r8a66597->root_hub[port].dev; - - disable_r8a66597_pipe_all(r8a66597, dev); - free_usb_address(r8a66597, dev, 0); - - start_root_hub_sampling(r8a66597, port, 0); -} - -/* this function must be called with interrupt disabled */ -static void prepare_setup_packet(struct r8a66597 *r8a66597, - struct r8a66597_td *td) -{ - int i; - __le16 *p = (__le16 *)td->urb->setup_packet; - unsigned long setup_addr = USBREQ; - - r8a66597_write(r8a66597, make_devsel(td->address) | td->maxpacket, - DCPMAXP); - r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1); - - for (i = 0; i < 4; i++) { - r8a66597_write(r8a66597, le16_to_cpu(p[i]), setup_addr); - setup_addr += 2; - } - r8a66597_write(r8a66597, SUREQ, DCPCTR); -} - -/* this function must be called with interrupt disabled */ -static void prepare_packet_read(struct r8a66597 *r8a66597, - struct r8a66597_td *td) -{ - struct urb *urb = td->urb; - - if (usb_pipecontrol(urb->pipe)) { - r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG); - r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL); - r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0); - if (urb->actual_length == 0) { - r8a66597_pipe_toggle(r8a66597, td->pipe, 1); - r8a66597_write(r8a66597, BCLR, CFIFOCTR); - } - pipe_irq_disable(r8a66597, td->pipenum); - pipe_start(r8a66597, td->pipe); - pipe_irq_enable(r8a66597, urb, td->pipenum); - } else { - if (urb->actual_length == 0) { - pipe_irq_disable(r8a66597, td->pipenum); - pipe_setting(r8a66597, td); - pipe_stop(r8a66597, td->pipe); - r8a66597_write(r8a66597, ~(1 << td->pipenum), BRDYSTS); - - if (td->pipe->pipetre) { - r8a66597_write(r8a66597, TRCLR, - td->pipe->pipetre); - r8a66597_write(r8a66597, - DIV_ROUND_UP - (urb->transfer_buffer_length, - td->maxpacket), - td->pipe->pipetrn); - r8a66597_bset(r8a66597, TRENB, - td->pipe->pipetre); - } - - pipe_start(r8a66597, td->pipe); - pipe_irq_enable(r8a66597, urb, td->pipenum); - } - } -} - -/* this function must be called with interrupt disabled */ -static void prepare_packet_write(struct r8a66597 *r8a66597, - struct r8a66597_td *td) -{ - u16 tmp; - struct urb *urb = td->urb; - - if (usb_pipecontrol(urb->pipe)) { - pipe_stop(r8a66597, td->pipe); - r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG); - r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL); - r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0); - if (urb->actual_length == 0) { - r8a66597_pipe_toggle(r8a66597, td->pipe, 1); - r8a66597_write(r8a66597, BCLR, CFIFOCTR); - } - } else { - if (urb->actual_length == 0) - pipe_setting(r8a66597, td); - if (td->pipe->pipetre) - r8a66597_bclr(r8a66597, TRENB, td->pipe->pipetre); - } - r8a66597_write(r8a66597, ~(1 << td->pipenum), BRDYSTS); - - fifo_change_from_pipe(r8a66597, td->pipe); - tmp = r8a66597_read(r8a66597, td->pipe->fifoctr); - if (unlikely((tmp & FRDY) == 0)) - pipe_irq_enable(r8a66597, urb, td->pipenum); - else - packet_write(r8a66597, td->pipenum); - pipe_start(r8a66597, td->pipe); -} - -/* this function must be called with interrupt disabled */ -static void prepare_status_packet(struct r8a66597 *r8a66597, - struct r8a66597_td *td) -{ - struct urb *urb = td->urb; - - r8a66597_pipe_toggle(r8a66597, td->pipe, 1); - pipe_stop(r8a66597, td->pipe); - - if (urb->setup_packet[0] & USB_ENDPOINT_DIR_MASK) { - r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG); - r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL); - r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0); - r8a66597_write(r8a66597, ~BEMP0, BEMPSTS); - r8a66597_write(r8a66597, BCLR | BVAL, CFIFOCTR); - enable_irq_empty(r8a66597, 0); - } else { - r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG); - r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL); - r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0); - r8a66597_write(r8a66597, BCLR, CFIFOCTR); - enable_irq_ready(r8a66597, 0); - } - enable_irq_nrdy(r8a66597, 0); - pipe_start(r8a66597, td->pipe); -} - -static int is_set_address(unsigned char *setup_packet) -{ - if (((setup_packet[0] & USB_TYPE_MASK) == USB_TYPE_STANDARD) && - setup_packet[1] == USB_REQ_SET_ADDRESS) - return 1; - else - return 0; -} - -/* this function must be called with interrupt disabled */ -static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td) -{ - BUG_ON(!td); - - switch (td->type) { - case USB_PID_SETUP: - if (is_set_address(td->urb->setup_packet)) { - td->set_address = 1; - td->urb->setup_packet[2] = alloc_usb_address(r8a66597, - td->urb); - if (td->urb->setup_packet[2] == 0) - return -EPIPE; - } - prepare_setup_packet(r8a66597, td); - break; - case USB_PID_IN: - prepare_packet_read(r8a66597, td); - break; - case USB_PID_OUT: - prepare_packet_write(r8a66597, td); - break; - case USB_PID_ACK: - prepare_status_packet(r8a66597, td); - break; - default: - printk(KERN_ERR "r8a66597: invalid type.\n"); - break; - } - - return 0; -} - -static int check_transfer_finish(struct r8a66597_td *td, struct urb *urb) -{ - if (usb_pipeisoc(urb->pipe)) { - if (urb->number_of_packets == td->iso_cnt) - return 1; - } - - /* control or bulk or interrupt */ - if ((urb->transfer_buffer_length <= urb->actual_length) || - (td->short_packet) || (td->zero_packet)) - return 1; - - return 0; -} - -/* this function must be called with interrupt disabled */ -static void set_td_timer(struct r8a66597 *r8a66597, struct r8a66597_td *td) -{ - unsigned long time; - - BUG_ON(!td); - - if (!list_empty(&r8a66597->pipe_queue[td->pipenum]) && - !usb_pipecontrol(td->urb->pipe) && usb_pipein(td->urb->pipe)) { - r8a66597->timeout_map |= 1 << td->pipenum; - switch (usb_pipetype(td->urb->pipe)) { - case PIPE_INTERRUPT: - case PIPE_ISOCHRONOUS: - time = 30; - break; - default: - time = 300; - break; - } - - mod_timer(&r8a66597->td_timer[td->pipenum], - jiffies + msecs_to_jiffies(time)); - } -} - -/* this function must be called with interrupt disabled */ -static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td, - u16 pipenum, struct urb *urb, int status) -__releases(r8a66597->lock) __acquires(r8a66597->lock) -{ - int restart = 0; - struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597); - - r8a66597->timeout_map &= ~(1 << pipenum); - - if (likely(td)) { - if (td->set_address && (status != 0 || urb->unlinked)) - r8a66597->address_map &= ~(1 << urb->setup_packet[2]); - - pipe_toggle_save(r8a66597, td->pipe, urb); - list_del(&td->queue); - kfree(td); - } - - if (!list_empty(&r8a66597->pipe_queue[pipenum])) - restart = 1; - - if (likely(urb)) { - if (usb_pipeisoc(urb->pipe)) - urb->start_frame = r8a66597_get_frame(hcd); - - r8a66597_urb_done(r8a66597, urb, status); - } - - if (restart) { - td = r8a66597_get_td(r8a66597, pipenum); - if (unlikely(!td)) - return; - - start_transfer(r8a66597, td); - set_td_timer(r8a66597, td); - } -} - -static void packet_read(struct r8a66597 *r8a66597, u16 pipenum) -{ - u16 tmp; - int rcv_len, bufsize, urb_len, size; - u16 *buf; - struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum); - struct urb *urb; - int finish = 0; - int status = 0; - - if (unlikely(!td)) - return; - urb = td->urb; - - fifo_change_from_pipe(r8a66597, td->pipe); - tmp = r8a66597_read(r8a66597, td->pipe->fifoctr); - if (unlikely((tmp & FRDY) == 0)) { - pipe_stop(r8a66597, td->pipe); - pipe_irq_disable(r8a66597, pipenum); - printk(KERN_ERR "r8a66597: in fifo not ready (%d)\n", pipenum); - finish_request(r8a66597, td, pipenum, td->urb, -EPIPE); - return; - } - - /* prepare parameters */ - rcv_len = tmp & DTLN; - if (usb_pipeisoc(urb->pipe)) { - buf = (u16 *)(urb->transfer_buffer + - urb->iso_frame_desc[td->iso_cnt].offset); - urb_len = urb->iso_frame_desc[td->iso_cnt].length; - } else { - buf = (void *)urb->transfer_buffer + urb->actual_length; - urb_len = urb->transfer_buffer_length - urb->actual_length; - } - bufsize = min(urb_len, (int) td->maxpacket); - if (rcv_len <= bufsize) { - size = rcv_len; - } else { - size = bufsize; - status = -EOVERFLOW; - finish = 1; - } - - /* update parameters */ - urb->actual_length += size; - if (rcv_len == 0) - td->zero_packet = 1; - if (rcv_len < bufsize) { - td->short_packet = 1; - } - if (usb_pipeisoc(urb->pipe)) { - urb->iso_frame_desc[td->iso_cnt].actual_length = size; - urb->iso_frame_desc[td->iso_cnt].status = status; - td->iso_cnt++; - finish = 0; - } - - /* check transfer finish */ - if (finish || check_transfer_finish(td, urb)) { - pipe_stop(r8a66597, td->pipe); - pipe_irq_disable(r8a66597, pipenum); - finish = 1; - } - - /* read fifo */ - if (urb->transfer_buffer) { - if (size == 0) - r8a66597_write(r8a66597, BCLR, td->pipe->fifoctr); - else - r8a66597_read_fifo(r8a66597, td->pipe->fifoaddr, - buf, size); - } - - if (finish && pipenum != 0) - finish_request(r8a66597, td, pipenum, urb, status); -} - -static void packet_write(struct r8a66597 *r8a66597, u16 pipenum) -{ - u16 tmp; - int bufsize, size; - u16 *buf; - struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum); - struct urb *urb; - - if (unlikely(!td)) - return; - urb = td->urb; - - fifo_change_from_pipe(r8a66597, td->pipe); - tmp = r8a66597_read(r8a66597, td->pipe->fifoctr); - if (unlikely((tmp & FRDY) == 0)) { - pipe_stop(r8a66597, td->pipe); - pipe_irq_disable(r8a66597, pipenum); - printk(KERN_ERR "r8a66597: out fifo not ready (%d)\n", pipenum); - finish_request(r8a66597, td, pipenum, urb, -EPIPE); - return; - } - - /* prepare parameters */ - bufsize = td->maxpacket; - if (usb_pipeisoc(urb->pipe)) { - buf = (u16 *)(urb->transfer_buffer + - urb->iso_frame_desc[td->iso_cnt].offset); - size = min(bufsize, - (int)urb->iso_frame_desc[td->iso_cnt].length); - } else { - buf = (u16 *)(urb->transfer_buffer + urb->actual_length); - size = min_t(u32, bufsize, - urb->transfer_buffer_length - urb->actual_length); - } - - /* write fifo */ - if (pipenum > 0) - r8a66597_write(r8a66597, ~(1 << pipenum), BEMPSTS); - if (urb->transfer_buffer) { - r8a66597_write_fifo(r8a66597, td->pipe, buf, size); - if (!usb_pipebulk(urb->pipe) || td->maxpacket != size) - r8a66597_write(r8a66597, BVAL, td->pipe->fifoctr); - } - - /* update parameters */ - urb->actual_length += size; - if (usb_pipeisoc(urb->pipe)) { - urb->iso_frame_desc[td->iso_cnt].actual_length = size; - urb->iso_frame_desc[td->iso_cnt].status = 0; - td->iso_cnt++; - } - - /* check transfer finish */ - if (check_transfer_finish(td, urb)) { - disable_irq_ready(r8a66597, pipenum); - enable_irq_empty(r8a66597, pipenum); - if (!usb_pipeisoc(urb->pipe)) - enable_irq_nrdy(r8a66597, pipenum); - } else - pipe_irq_enable(r8a66597, urb, pipenum); -} - - -static void check_next_phase(struct r8a66597 *r8a66597, int status) -{ - struct r8a66597_td *td = r8a66597_get_td(r8a66597, 0); - struct urb *urb; - u8 finish = 0; - - if (unlikely(!td)) - return; - urb = td->urb; - - switch (td->type) { - case USB_PID_IN: - case USB_PID_OUT: - if (check_transfer_finish(td, urb)) - td->type = USB_PID_ACK; - break; - case USB_PID_SETUP: - if (urb->transfer_buffer_length == urb->actual_length) - td->type = USB_PID_ACK; - else if (usb_pipeout(urb->pipe)) - td->type = USB_PID_OUT; - else - td->type = USB_PID_IN; - break; - case USB_PID_ACK: - finish = 1; - break; - } - - if (finish || status != 0 || urb->unlinked) - finish_request(r8a66597, td, 0, urb, status); - else - start_transfer(r8a66597, td); -} - -static int get_urb_error(struct r8a66597 *r8a66597, u16 pipenum) -{ - struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum); - - if (td) { - u16 pid = r8a66597_read(r8a66597, td->pipe->pipectr) & PID; - - if (pid == PID_NAK) - return -ECONNRESET; - else - return -EPIPE; - } - return 0; -} - -static void irq_pipe_ready(struct r8a66597 *r8a66597) -{ - u16 check; - u16 pipenum; - u16 mask; - struct r8a66597_td *td; - - mask = r8a66597_read(r8a66597, BRDYSTS) - & r8a66597_read(r8a66597, BRDYENB); - r8a66597_write(r8a66597, ~mask, BRDYSTS); - if (mask & BRDY0) { - td = r8a66597_get_td(r8a66597, 0); - if (td && td->type == USB_PID_IN) - packet_read(r8a66597, 0); - else - pipe_irq_disable(r8a66597, 0); - check_next_phase(r8a66597, 0); - } - - for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) { - check = 1 << pipenum; - if (mask & check) { - td = r8a66597_get_td(r8a66597, pipenum); - if (unlikely(!td)) - continue; - - if (td->type == USB_PID_IN) - packet_read(r8a66597, pipenum); - else if (td->type == USB_PID_OUT) - packet_write(r8a66597, pipenum); - } - } -} - -static void irq_pipe_empty(struct r8a66597 *r8a66597) -{ - u16 tmp; - u16 check; - u16 pipenum; - u16 mask; - struct r8a66597_td *td; - - mask = r8a66597_read(r8a66597, BEMPSTS) - & r8a66597_read(r8a66597, BEMPENB); - r8a66597_write(r8a66597, ~mask, BEMPSTS); - if (mask & BEMP0) { - cfifo_change(r8a66597, 0); - td = r8a66597_get_td(r8a66597, 0); - if (td && td->type != USB_PID_OUT) - disable_irq_empty(r8a66597, 0); - check_next_phase(r8a66597, 0); - } - - for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) { - check = 1 << pipenum; - if (mask & check) { - struct r8a66597_td *td; - td = r8a66597_get_td(r8a66597, pipenum); - if (unlikely(!td)) - continue; - - tmp = r8a66597_read(r8a66597, td->pipe->pipectr); - if ((tmp & INBUFM) == 0) { - disable_irq_empty(r8a66597, pipenum); - pipe_irq_disable(r8a66597, pipenum); - finish_request(r8a66597, td, pipenum, td->urb, - 0); - } - } - } -} - -static void irq_pipe_nrdy(struct r8a66597 *r8a66597) -{ - u16 check; - u16 pipenum; - u16 mask; - int status; - - mask = r8a66597_read(r8a66597, NRDYSTS) - & r8a66597_read(r8a66597, NRDYENB); - r8a66597_write(r8a66597, ~mask, NRDYSTS); - if (mask & NRDY0) { - cfifo_change(r8a66597, 0); - status = get_urb_error(r8a66597, 0); - pipe_irq_disable(r8a66597, 0); - check_next_phase(r8a66597, status); - } - - for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) { - check = 1 << pipenum; - if (mask & check) { - struct r8a66597_td *td; - td = r8a66597_get_td(r8a66597, pipenum); - if (unlikely(!td)) - continue; - - status = get_urb_error(r8a66597, pipenum); - pipe_irq_disable(r8a66597, pipenum); - pipe_stop(r8a66597, td->pipe); - finish_request(r8a66597, td, pipenum, td->urb, status); - } - } -} - -static irqreturn_t r8a66597_irq(struct usb_hcd *hcd) -{ - struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); - u16 intsts0, intsts1, intsts2; - u16 intenb0, intenb1, intenb2; - u16 mask0, mask1, mask2; - int status; - - spin_lock(&r8a66597->lock); - - intsts0 = r8a66597_read(r8a66597, INTSTS0); - intsts1 = r8a66597_read(r8a66597, INTSTS1); - intsts2 = r8a66597_read(r8a66597, INTSTS2); - intenb0 = r8a66597_read(r8a66597, INTENB0); - intenb1 = r8a66597_read(r8a66597, INTENB1); - intenb2 = r8a66597_read(r8a66597, INTENB2); - - mask2 = intsts2 & intenb2; - mask1 = intsts1 & intenb1; - mask0 = intsts0 & intenb0 & (BEMP | NRDY | BRDY); - if (mask2) { - if (mask2 & ATTCH) { - r8a66597_write(r8a66597, ~ATTCH, INTSTS2); - r8a66597_bclr(r8a66597, ATTCHE, INTENB2); - - /* start usb bus sampling */ - start_root_hub_sampling(r8a66597, 1, 1); - } - if (mask2 & DTCH) { - r8a66597_write(r8a66597, ~DTCH, INTSTS2); - r8a66597_bclr(r8a66597, DTCHE, INTENB2); - r8a66597_usb_disconnect(r8a66597, 1); - } - if (mask2 & BCHG) { - r8a66597_write(r8a66597, ~BCHG, INTSTS2); - r8a66597_bclr(r8a66597, BCHGE, INTENB2); - usb_hcd_resume_root_hub(r8a66597_to_hcd(r8a66597)); - } - } - - if (mask1) { - if (mask1 & ATTCH) { - r8a66597_write(r8a66597, ~ATTCH, INTSTS1); - r8a66597_bclr(r8a66597, ATTCHE, INTENB1); - - /* start usb bus sampling */ - start_root_hub_sampling(r8a66597, 0, 1); - } - if (mask1 & DTCH) { - r8a66597_write(r8a66597, ~DTCH, INTSTS1); - r8a66597_bclr(r8a66597, DTCHE, INTENB1); - r8a66597_usb_disconnect(r8a66597, 0); - } - if (mask1 & BCHG) { - r8a66597_write(r8a66597, ~BCHG, INTSTS1); - r8a66597_bclr(r8a66597, BCHGE, INTENB1); - usb_hcd_resume_root_hub(r8a66597_to_hcd(r8a66597)); - } - - if (mask1 & SIGN) { - r8a66597_write(r8a66597, ~SIGN, INTSTS1); - status = get_urb_error(r8a66597, 0); - check_next_phase(r8a66597, status); - } - if (mask1 & SACK) { - r8a66597_write(r8a66597, ~SACK, INTSTS1); - check_next_phase(r8a66597, 0); - } - } - if (mask0) { - if (mask0 & BRDY) - irq_pipe_ready(r8a66597); - if (mask0 & BEMP) - irq_pipe_empty(r8a66597); - if (mask0 & NRDY) - irq_pipe_nrdy(r8a66597); - } - - spin_unlock(&r8a66597->lock); - return IRQ_HANDLED; -} - -/* this function must be called with interrupt disabled */ -static void r8a66597_root_hub_control(struct r8a66597 *r8a66597, int port) -{ - u16 tmp; - struct r8a66597_root_hub *rh = &r8a66597->root_hub[port]; - - if (rh->port & USB_PORT_STAT_RESET) { - unsigned long dvstctr_reg = get_dvstctr_reg(port); - - tmp = r8a66597_read(r8a66597, dvstctr_reg); - if ((tmp & USBRST) == USBRST) { - r8a66597_mdfy(r8a66597, UACT, USBRST | UACT, - dvstctr_reg); - r8a66597_root_hub_start_polling(r8a66597); - } else - r8a66597_usb_connect(r8a66597, port); - } - - if (!(rh->port & USB_PORT_STAT_CONNECTION)) { - r8a66597_write(r8a66597, ~ATTCH, get_intsts_reg(port)); - r8a66597_bset(r8a66597, ATTCHE, get_intenb_reg(port)); - } - - if (rh->scount > 0) { - tmp = r8a66597_read(r8a66597, get_syssts_reg(port)) & LNST; - if (tmp == rh->old_syssts) { - rh->scount--; - if (rh->scount == 0) - r8a66597_check_syssts(r8a66597, port, tmp); - else - r8a66597_root_hub_start_polling(r8a66597); - } else { - rh->scount = R8A66597_MAX_SAMPLING; - rh->old_syssts = tmp; - r8a66597_root_hub_start_polling(r8a66597); - } - } -} - -static void r8a66597_interval_timer(unsigned long _r8a66597) -{ - struct r8a66597 *r8a66597 = (struct r8a66597 *)_r8a66597; - unsigned long flags; - u16 pipenum; - struct r8a66597_td *td; - - spin_lock_irqsave(&r8a66597->lock, flags); - - for (pipenum = 0; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) { - if (!(r8a66597->interval_map & (1 << pipenum))) - continue; - if (timer_pending(&r8a66597->interval_timer[pipenum])) - continue; - - td = r8a66597_get_td(r8a66597, pipenum); - if (td) - start_transfer(r8a66597, td); - } - - spin_unlock_irqrestore(&r8a66597->lock, flags); -} - -static void r8a66597_td_timer(unsigned long _r8a66597) -{ - struct r8a66597 *r8a66597 = (struct r8a66597 *)_r8a66597; - unsigned long flags; - u16 pipenum; - struct r8a66597_td *td, *new_td = NULL; - struct r8a66597_pipe *pipe; - - spin_lock_irqsave(&r8a66597->lock, flags); - for (pipenum = 0; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) { - if (!(r8a66597->timeout_map & (1 << pipenum))) - continue; - if (timer_pending(&r8a66597->td_timer[pipenum])) - continue; - - td = r8a66597_get_td(r8a66597, pipenum); - if (!td) { - r8a66597->timeout_map &= ~(1 << pipenum); - continue; - } - - if (td->urb->actual_length) { - set_td_timer(r8a66597, td); - break; - } - - pipe = td->pipe; - pipe_stop(r8a66597, pipe); - - new_td = td; - do { - list_move_tail(&new_td->queue, - &r8a66597->pipe_queue[pipenum]); - new_td = r8a66597_get_td(r8a66597, pipenum); - if (!new_td) { - new_td = td; - break; - } - } while (td != new_td && td->address == new_td->address); - - start_transfer(r8a66597, new_td); - - if (td == new_td) - r8a66597->timeout_map &= ~(1 << pipenum); - else - set_td_timer(r8a66597, new_td); - break; - } - spin_unlock_irqrestore(&r8a66597->lock, flags); -} - -static void r8a66597_timer(unsigned long _r8a66597) -{ - struct r8a66597 *r8a66597 = (struct r8a66597 *)_r8a66597; - unsigned long flags; - int port; - - spin_lock_irqsave(&r8a66597->lock, flags); - - for (port = 0; port < r8a66597->max_root_hub; port++) - r8a66597_root_hub_control(r8a66597, port); - - spin_unlock_irqrestore(&r8a66597->lock, flags); -} - -static int check_pipe_config(struct r8a66597 *r8a66597, struct urb *urb) -{ - struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb); - - if (dev && dev->address && dev->state != USB_STATE_CONFIGURED && - (urb->dev->state == USB_STATE_CONFIGURED)) - return 1; - else - return 0; -} - -static int r8a66597_start(struct usb_hcd *hcd) -{ - struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); - - hcd->state = HC_STATE_RUNNING; - return enable_controller(r8a66597); -} - -static void r8a66597_stop(struct usb_hcd *hcd) -{ - struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); - - disable_controller(r8a66597); -} - -static void set_address_zero(struct r8a66597 *r8a66597, struct urb *urb) -{ - unsigned int usb_address = usb_pipedevice(urb->pipe); - u16 root_port, hub_port; - - if (usb_address == 0) { - get_port_number(r8a66597, urb->dev->devpath, - &root_port, &hub_port); - set_devadd_reg(r8a66597, 0, - get_r8a66597_usb_speed(urb->dev->speed), - get_parent_r8a66597_address(r8a66597, urb->dev), - hub_port, root_port); - } -} - -static struct r8a66597_td *r8a66597_make_td(struct r8a66597 *r8a66597, - struct urb *urb, - struct usb_host_endpoint *hep) -{ - struct r8a66597_td *td; - u16 pipenum; - - td = kzalloc(sizeof(struct r8a66597_td), GFP_ATOMIC); - if (td == NULL) - return NULL; - - pipenum = r8a66597_get_pipenum(urb, hep); - td->pipenum = pipenum; - td->pipe = hep->hcpriv; - td->urb = urb; - td->address = get_urb_to_r8a66597_addr(r8a66597, urb); - td->maxpacket = usb_maxpacket(urb->dev, urb->pipe, - !usb_pipein(urb->pipe)); - if (usb_pipecontrol(urb->pipe)) - td->type = USB_PID_SETUP; - else if (usb_pipein(urb->pipe)) - td->type = USB_PID_IN; - else - td->type = USB_PID_OUT; - INIT_LIST_HEAD(&td->queue); - - return td; -} - -static int r8a66597_urb_enqueue(struct usb_hcd *hcd, - struct urb *urb, - gfp_t mem_flags) -{ - struct usb_host_endpoint *hep = urb->ep; - struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); - struct r8a66597_td *td = NULL; - int ret, request = 0; - unsigned long flags; - - spin_lock_irqsave(&r8a66597->lock, flags); - if (!get_urb_to_r8a66597_dev(r8a66597, urb)) { - ret = -ENODEV; - goto error_not_linked; - } - - ret = usb_hcd_link_urb_to_ep(hcd, urb); - if (ret) - goto error_not_linked; - - if (!hep->hcpriv) { - hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe), - GFP_ATOMIC); - if (!hep->hcpriv) { - ret = -ENOMEM; - goto error; - } - set_pipe_reg_addr(hep->hcpriv, R8A66597_PIPE_NO_DMA); - if (usb_pipeendpoint(urb->pipe)) - init_pipe_info(r8a66597, urb, hep, &hep->desc); - } - - if (unlikely(check_pipe_config(r8a66597, urb))) - init_pipe_config(r8a66597, urb); - - set_address_zero(r8a66597, urb); - td = r8a66597_make_td(r8a66597, urb, hep); - if (td == NULL) { - ret = -ENOMEM; - goto error; - } - if (list_empty(&r8a66597->pipe_queue[td->pipenum])) - request = 1; - list_add_tail(&td->queue, &r8a66597->pipe_queue[td->pipenum]); - urb->hcpriv = td; - - if (request) { - if (td->pipe->info.timer_interval) { - r8a66597->interval_map |= 1 << td->pipenum; - mod_timer(&r8a66597->interval_timer[td->pipenum], - jiffies + msecs_to_jiffies( - td->pipe->info.timer_interval)); - } else { - ret = start_transfer(r8a66597, td); - if (ret < 0) { - list_del(&td->queue); - kfree(td); - } - } - } else - set_td_timer(r8a66597, td); - -error: - if (ret) - usb_hcd_unlink_urb_from_ep(hcd, urb); -error_not_linked: - spin_unlock_irqrestore(&r8a66597->lock, flags); - return ret; -} - -static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, - int status) -{ - struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); - struct r8a66597_td *td; - unsigned long flags; - int rc; - - spin_lock_irqsave(&r8a66597->lock, flags); - rc = usb_hcd_check_unlink_urb(hcd, urb, status); - if (rc) - goto done; - - if (urb->hcpriv) { - td = urb->hcpriv; - pipe_stop(r8a66597, td->pipe); - pipe_irq_disable(r8a66597, td->pipenum); - disable_irq_empty(r8a66597, td->pipenum); - finish_request(r8a66597, td, td->pipenum, urb, status); - } - done: - spin_unlock_irqrestore(&r8a66597->lock, flags); - return rc; -} - -static void r8a66597_endpoint_disable(struct usb_hcd *hcd, - struct usb_host_endpoint *hep) -{ - struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); - struct r8a66597_pipe *pipe = (struct r8a66597_pipe *)hep->hcpriv; - struct r8a66597_td *td; - struct urb *urb = NULL; - u16 pipenum; - unsigned long flags; - - if (pipe == NULL) - return; - pipenum = pipe->info.pipenum; - - if (pipenum == 0) { - kfree(hep->hcpriv); - hep->hcpriv = NULL; - return; - } - - spin_lock_irqsave(&r8a66597->lock, flags); - pipe_stop(r8a66597, pipe); - pipe_irq_disable(r8a66597, pipenum); - disable_irq_empty(r8a66597, pipenum); - td = r8a66597_get_td(r8a66597, pipenum); - if (td) - urb = td->urb; - finish_request(r8a66597, td, pipenum, urb, -ESHUTDOWN); - kfree(hep->hcpriv); - hep->hcpriv = NULL; - spin_unlock_irqrestore(&r8a66597->lock, flags); -} - -static int r8a66597_get_frame(struct usb_hcd *hcd) -{ - struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); - return r8a66597_read(r8a66597, FRMNUM) & 0x03FF; -} - -static void collect_usb_address_map(struct usb_device *udev, unsigned long *map) -{ - int chix; - - if (udev->state == USB_STATE_CONFIGURED && - udev->parent && udev->parent->devnum > 1 && - udev->parent->descriptor.bDeviceClass == USB_CLASS_HUB) - map[udev->devnum/32] |= (1 << (udev->devnum % 32)); - - for (chix = 0; chix < udev->maxchild; chix++) { - struct usb_device *childdev = udev->children[chix]; - - if (childdev) - collect_usb_address_map(childdev, map); - } -} - -/* this function must be called with interrupt disabled */ -static struct r8a66597_device *get_r8a66597_device(struct r8a66597 *r8a66597, - int addr) -{ - struct r8a66597_device *dev; - struct list_head *list = &r8a66597->child_device; - - list_for_each_entry(dev, list, device_list) { - if (dev->usb_address != addr) - continue; - - return dev; - } - - printk(KERN_ERR "r8a66597: get_r8a66597_device fail.(%d)\n", addr); - return NULL; -} - -static void update_usb_address_map(struct r8a66597 *r8a66597, - struct usb_device *root_hub, - unsigned long *map) -{ - int i, j, addr; - unsigned long diff; - unsigned long flags; - - for (i = 0; i < 4; i++) { - diff = r8a66597->child_connect_map[i] ^ map[i]; - if (!diff) - continue; - - for (j = 0; j < 32; j++) { - if (!(diff & (1 << j))) - continue; - - addr = i * 32 + j; - if (map[i] & (1 << j)) - set_child_connect_map(r8a66597, addr); - else { - struct r8a66597_device *dev; - - spin_lock_irqsave(&r8a66597->lock, flags); - dev = get_r8a66597_device(r8a66597, addr); - disable_r8a66597_pipe_all(r8a66597, dev); - free_usb_address(r8a66597, dev, 0); - put_child_connect_map(r8a66597, addr); - spin_unlock_irqrestore(&r8a66597->lock, flags); - } - } - } -} - -static void r8a66597_check_detect_child(struct r8a66597 *r8a66597, - struct usb_hcd *hcd) -{ - struct usb_bus *bus; - unsigned long now_map[4]; - - memset(now_map, 0, sizeof(now_map)); - - list_for_each_entry(bus, &usb_bus_list, bus_list) { - if (!bus->root_hub) - continue; - - if (bus->busnum != hcd->self.busnum) - continue; - - collect_usb_address_map(bus->root_hub, now_map); - update_usb_address_map(r8a66597, bus->root_hub, now_map); - } -} - -static int r8a66597_hub_status_data(struct usb_hcd *hcd, char *buf) -{ - struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); - unsigned long flags; - int i; - - r8a66597_check_detect_child(r8a66597, hcd); - - spin_lock_irqsave(&r8a66597->lock, flags); - - *buf = 0; /* initialize (no change) */ - - for (i = 0; i < r8a66597->max_root_hub; i++) { - if (r8a66597->root_hub[i].port & 0xffff0000) - *buf |= 1 << (i + 1); - } - - spin_unlock_irqrestore(&r8a66597->lock, flags); - - return (*buf != 0); -} - -static void r8a66597_hub_descriptor(struct r8a66597 *r8a66597, - struct usb_hub_descriptor *desc) -{ - desc->bDescriptorType = 0x29; - desc->bHubContrCurrent = 0; - desc->bNbrPorts = r8a66597->max_root_hub; - desc->bDescLength = 9; - desc->bPwrOn2PwrGood = 0; - desc->wHubCharacteristics = cpu_to_le16(0x0011); - desc->u.hs.DeviceRemovable[0] = - ((1 << r8a66597->max_root_hub) - 1) << 1; - desc->u.hs.DeviceRemovable[1] = ~0; -} - -static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, - u16 wIndex, char *buf, u16 wLength) -{ - struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); - int ret; - int port = (wIndex & 0x00FF) - 1; - struct r8a66597_root_hub *rh = &r8a66597->root_hub[port]; - unsigned long flags; - - ret = 0; - - spin_lock_irqsave(&r8a66597->lock, flags); - switch (typeReq) { - case ClearHubFeature: - case SetHubFeature: - switch (wValue) { - case C_HUB_OVER_CURRENT: - case C_HUB_LOCAL_POWER: - break; - default: - goto error; - } - break; - case ClearPortFeature: - if (wIndex > r8a66597->max_root_hub) - goto error; - if (wLength != 0) - goto error; - - switch (wValue) { - case USB_PORT_FEAT_ENABLE: - rh->port &= ~USB_PORT_STAT_POWER; - break; - case USB_PORT_FEAT_SUSPEND: - break; - case USB_PORT_FEAT_POWER: - r8a66597_port_power(r8a66597, port, 0); - break; - case USB_PORT_FEAT_C_ENABLE: - case USB_PORT_FEAT_C_SUSPEND: - case USB_PORT_FEAT_C_CONNECTION: - case USB_PORT_FEAT_C_OVER_CURRENT: - case USB_PORT_FEAT_C_RESET: - break; - default: - goto error; - } - rh->port &= ~(1 << wValue); - break; - case GetHubDescriptor: - r8a66597_hub_descriptor(r8a66597, - (struct usb_hub_descriptor *)buf); - break; - case GetHubStatus: - *buf = 0x00; - break; - case GetPortStatus: - if (wIndex > r8a66597->max_root_hub) - goto error; - *(__le32 *)buf = cpu_to_le32(rh->port); - break; - case SetPortFeature: - if (wIndex > r8a66597->max_root_hub) - goto error; - if (wLength != 0) - goto error; - - switch (wValue) { - case USB_PORT_FEAT_SUSPEND: - break; - case USB_PORT_FEAT_POWER: - r8a66597_port_power(r8a66597, port, 1); - rh->port |= USB_PORT_STAT_POWER; - break; - case USB_PORT_FEAT_RESET: { - struct r8a66597_device *dev = rh->dev; - - rh->port |= USB_PORT_STAT_RESET; - - disable_r8a66597_pipe_all(r8a66597, dev); - free_usb_address(r8a66597, dev, 1); - - r8a66597_mdfy(r8a66597, USBRST, USBRST | UACT, - get_dvstctr_reg(port)); - mod_timer(&r8a66597->rh_timer, - jiffies + msecs_to_jiffies(50)); - } - break; - default: - goto error; - } - rh->port |= 1 << wValue; - break; - default: -error: - ret = -EPIPE; - break; - } - - spin_unlock_irqrestore(&r8a66597->lock, flags); - return ret; -} - -#if defined(CONFIG_PM) -static int r8a66597_bus_suspend(struct usb_hcd *hcd) -{ - struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); - int port; - - dbg("%s", __func__); - - for (port = 0; port < r8a66597->max_root_hub; port++) { - struct r8a66597_root_hub *rh = &r8a66597->root_hub[port]; - unsigned long dvstctr_reg = get_dvstctr_reg(port); - - if (!(rh->port & USB_PORT_STAT_ENABLE)) - continue; - - dbg("suspend port = %d", port); - r8a66597_bclr(r8a66597, UACT, dvstctr_reg); /* suspend */ - rh->port |= USB_PORT_STAT_SUSPEND; - - if (rh->dev->udev->do_remote_wakeup) { - msleep(3); /* waiting last SOF */ - r8a66597_bset(r8a66597, RWUPE, dvstctr_reg); - r8a66597_write(r8a66597, ~BCHG, get_intsts_reg(port)); - r8a66597_bset(r8a66597, BCHGE, get_intenb_reg(port)); - } - } - - r8a66597->bus_suspended = 1; - - return 0; -} - -static int r8a66597_bus_resume(struct usb_hcd *hcd) -{ - struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); - int port; - - dbg("%s", __func__); - - for (port = 0; port < r8a66597->max_root_hub; port++) { - struct r8a66597_root_hub *rh = &r8a66597->root_hub[port]; - unsigned long dvstctr_reg = get_dvstctr_reg(port); - - if (!(rh->port & USB_PORT_STAT_SUSPEND)) - continue; - - dbg("resume port = %d", port); - rh->port &= ~USB_PORT_STAT_SUSPEND; - rh->port |= USB_PORT_STAT_C_SUSPEND << 16; - r8a66597_mdfy(r8a66597, RESUME, RESUME | UACT, dvstctr_reg); - msleep(50); - r8a66597_mdfy(r8a66597, UACT, RESUME | UACT, dvstctr_reg); - } - - return 0; - -} -#else -#define r8a66597_bus_suspend NULL -#define r8a66597_bus_resume NULL -#endif - -static struct hc_driver r8a66597_hc_driver = { - .description = hcd_name, - .hcd_priv_size = sizeof(struct r8a66597), - .irq = r8a66597_irq, - - /* - * generic hardware linkage - */ - .flags = HCD_USB2, - - .start = r8a66597_start, - .stop = r8a66597_stop, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = r8a66597_urb_enqueue, - .urb_dequeue = r8a66597_urb_dequeue, - .endpoint_disable = r8a66597_endpoint_disable, - - /* - * periodic schedule support - */ - .get_frame_number = r8a66597_get_frame, - - /* - * root hub support - */ - .hub_status_data = r8a66597_hub_status_data, - .hub_control = r8a66597_hub_control, - .bus_suspend = r8a66597_bus_suspend, - .bus_resume = r8a66597_bus_resume, -}; - -#if defined(CONFIG_PM) -static int r8a66597_suspend(struct device *dev) -{ - struct r8a66597 *r8a66597 = dev_get_drvdata(dev); - int port; - - dbg("%s", __func__); - - disable_controller(r8a66597); - - for (port = 0; port < r8a66597->max_root_hub; port++) { - struct r8a66597_root_hub *rh = &r8a66597->root_hub[port]; - - rh->port = 0x00000000; - } - - return 0; -} - -static int r8a66597_resume(struct device *dev) -{ - struct r8a66597 *r8a66597 = dev_get_drvdata(dev); - struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597); - - dbg("%s", __func__); - - enable_controller(r8a66597); - usb_root_hub_lost_power(hcd->self.root_hub); - - return 0; -} - -static const struct dev_pm_ops r8a66597_dev_pm_ops = { - .suspend = r8a66597_suspend, - .resume = r8a66597_resume, - .poweroff = r8a66597_suspend, - .restore = r8a66597_resume, -}; - -#define R8A66597_DEV_PM_OPS (&r8a66597_dev_pm_ops) -#else /* if defined(CONFIG_PM) */ -#define R8A66597_DEV_PM_OPS NULL -#endif - -static int __devexit r8a66597_remove(struct platform_device *pdev) -{ - struct r8a66597 *r8a66597 = dev_get_drvdata(&pdev->dev); - struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597); - - del_timer_sync(&r8a66597->rh_timer); - usb_remove_hcd(hcd); - iounmap(r8a66597->reg); -#ifdef CONFIG_HAVE_CLK - if (r8a66597->pdata->on_chip) - clk_put(r8a66597->clk); -#endif - usb_put_hcd(hcd); - return 0; -} - -static int __devinit r8a66597_probe(struct platform_device *pdev) -{ -#ifdef CONFIG_HAVE_CLK - char clk_name[8]; -#endif - struct resource *res = NULL, *ires; - int irq = -1; - void __iomem *reg = NULL; - struct usb_hcd *hcd = NULL; - struct r8a66597 *r8a66597; - int ret = 0; - int i; - unsigned long irq_trigger; - - if (usb_disabled()) - return -ENODEV; - - if (pdev->dev.dma_mask) { - ret = -EINVAL; - dev_err(&pdev->dev, "dma not supported\n"); - goto clean_up; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENODEV; - dev_err(&pdev->dev, "platform_get_resource error.\n"); - goto clean_up; - } - - ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!ires) { - ret = -ENODEV; - dev_err(&pdev->dev, - "platform_get_resource IORESOURCE_IRQ error.\n"); - goto clean_up; - } - - irq = ires->start; - irq_trigger = ires->flags & IRQF_TRIGGER_MASK; - - reg = ioremap(res->start, resource_size(res)); - if (reg == NULL) { - ret = -ENOMEM; - dev_err(&pdev->dev, "ioremap error.\n"); - 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) { - ret = -ENOMEM; - dev_err(&pdev->dev, "Failed to create hcd\n"); - goto clean_up; - } - 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 (r8a66597->pdata->on_chip) { -#ifdef CONFIG_HAVE_CLK - snprintf(clk_name, sizeof(clk_name), "usb%d", pdev->id); - r8a66597->clk = clk_get(&pdev->dev, clk_name); - if (IS_ERR(r8a66597->clk)) { - dev_err(&pdev->dev, "cannot get clock \"%s\"\n", - clk_name); - ret = PTR_ERR(r8a66597->clk); - goto clean_up2; - } -#endif - r8a66597->max_root_hub = 1; - } else - r8a66597->max_root_hub = 2; - - spin_lock_init(&r8a66597->lock); - init_timer(&r8a66597->rh_timer); - r8a66597->rh_timer.function = r8a66597_timer; - r8a66597->rh_timer.data = (unsigned long)r8a66597; - r8a66597->reg = reg; - - /* make sure no interrupts are pending */ - ret = r8a66597_clock_enable(r8a66597); - if (ret < 0) - goto clean_up3; - disable_controller(r8a66597); - - for (i = 0; i < R8A66597_MAX_NUM_PIPE; i++) { - INIT_LIST_HEAD(&r8a66597->pipe_queue[i]); - init_timer(&r8a66597->td_timer[i]); - r8a66597->td_timer[i].function = r8a66597_td_timer; - r8a66597->td_timer[i].data = (unsigned long)r8a66597; - setup_timer(&r8a66597->interval_timer[i], - r8a66597_interval_timer, - (unsigned long)r8a66597); - } - INIT_LIST_HEAD(&r8a66597->child_device); - - hcd->rsrc_start = res->start; - hcd->has_tt = 1; - - ret = usb_add_hcd(hcd, irq, irq_trigger); - if (ret != 0) { - dev_err(&pdev->dev, "Failed to add hcd\n"); - goto clean_up3; - } - - return 0; - -clean_up3: -#ifdef CONFIG_HAVE_CLK - if (r8a66597->pdata->on_chip) - clk_put(r8a66597->clk); -clean_up2: -#endif - usb_put_hcd(hcd); - -clean_up: - if (reg) - iounmap(reg); - - return ret; -} - -static struct platform_driver r8a66597_driver = { - .probe = r8a66597_probe, - .remove = __devexit_p(r8a66597_remove), - .driver = { - .name = (char *) hcd_name, - .owner = THIS_MODULE, - .pm = R8A66597_DEV_PM_OPS, - }, -}; - -module_platform_driver(r8a66597_driver); diff --git a/ANDROID_3.4.5/drivers/usb/host/r8a66597.h b/ANDROID_3.4.5/drivers/usb/host/r8a66597.h deleted file mode 100644 index f28782d2..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/r8a66597.h +++ /dev/null @@ -1,350 +0,0 @@ -/* - * R8A66597 HCD (Host Controller Driver) - * - * Copyright (C) 2006-2007 Renesas Solutions Corp. - * Portions Copyright (C) 2004 Psion Teklogix (for NetBook PRO) - * Portions Copyright (C) 2004-2005 David Brownell - * Portions Copyright (C) 1999 Roman Weissgaerber - * - * Author : Yoshihiro Shimoda - * - * 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; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __R8A66597_H__ -#define __R8A66597_H__ - -#ifdef CONFIG_HAVE_CLK -#include -#endif - -#include - -#define R8A66597_MAX_NUM_PIPE 10 -#define R8A66597_BUF_BSIZE 8 -#define R8A66597_MAX_DEVICE 10 -#define R8A66597_MAX_ROOT_HUB 2 -#define R8A66597_MAX_SAMPLING 5 -#define R8A66597_RH_POLL_TIME 10 -#define R8A66597_MAX_DMA_CHANNEL 2 -#define R8A66597_PIPE_NO_DMA R8A66597_MAX_DMA_CHANNEL -#define check_bulk_or_isoc(pipenum) ((pipenum >= 1 && pipenum <= 5)) -#define check_interrupt(pipenum) ((pipenum >= 6 && pipenum <= 9)) -#define make_devsel(addr) (addr << 12) - -struct r8a66597_pipe_info { - unsigned long timer_interval; - u16 pipenum; - u16 address; /* R8A66597 HCD usb address */ - u16 epnum; - u16 maxpacket; - u16 type; - u16 bufnum; - u16 buf_bsize; - u16 interval; - u16 dir_in; -}; - -struct r8a66597_pipe { - struct r8a66597_pipe_info info; - - unsigned long fifoaddr; - unsigned long fifosel; - unsigned long fifoctr; - unsigned long pipectr; - unsigned long pipetre; - unsigned long pipetrn; -}; - -struct r8a66597_td { - struct r8a66597_pipe *pipe; - struct urb *urb; - struct list_head queue; - - u16 type; - u16 pipenum; - int iso_cnt; - - u16 address; /* R8A66597's USB address */ - u16 maxpacket; - - unsigned zero_packet:1; - unsigned short_packet:1; - unsigned set_address:1; -}; - -struct r8a66597_device { - u16 address; /* R8A66597's USB address */ - u16 hub_port; - u16 root_port; - - unsigned short ep_in_toggle; - unsigned short ep_out_toggle; - unsigned char pipe_cnt[R8A66597_MAX_NUM_PIPE]; - unsigned char dma_map; - - enum usb_device_state state; - - struct usb_device *udev; - int usb_address; - struct list_head device_list; -}; - -struct r8a66597_root_hub { - u32 port; - u16 old_syssts; - int scount; - - struct r8a66597_device *dev; -}; - -struct r8a66597 { - spinlock_t lock; - void __iomem *reg; -#ifdef 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]; - - struct timer_list rh_timer; - struct timer_list td_timer[R8A66597_MAX_NUM_PIPE]; - struct timer_list interval_timer[R8A66597_MAX_NUM_PIPE]; - - unsigned short address_map; - unsigned short timeout_map; - unsigned short interval_map; - unsigned char pipe_cnt[R8A66597_MAX_NUM_PIPE]; - unsigned char dma_map; - unsigned int max_root_hub; - - struct list_head child_device; - 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) -{ - return (struct r8a66597 *)(hcd->hcd_priv); -} - -static inline struct usb_hcd *r8a66597_to_hcd(struct r8a66597 *r8a66597) -{ - return container_of((void *)r8a66597, struct usb_hcd, hcd_priv); -} - -static inline struct r8a66597_td *r8a66597_get_td(struct r8a66597 *r8a66597, - u16 pipenum) -{ - if (unlikely(list_empty(&r8a66597->pipe_queue[pipenum]))) - return NULL; - - return list_entry(r8a66597->pipe_queue[pipenum].next, - struct r8a66597_td, queue); -} - -static inline struct urb *r8a66597_get_urb(struct r8a66597 *r8a66597, - u16 pipenum) -{ - struct r8a66597_td *td; - - td = r8a66597_get_td(r8a66597, pipenum); - return (td ? td->urb : NULL); -} - -static inline u16 r8a66597_read(struct r8a66597 *r8a66597, unsigned long offset) -{ - return ioread16(r8a66597->reg + offset); -} - -static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597, - unsigned long offset, u16 *buf, - int len) -{ - void __iomem *fifoaddr = r8a66597->reg + offset; - unsigned long count; - - if (r8a66597->pdata->on_chip) { - count = len / 4; - ioread32_rep(fifoaddr, buf, count); - - if (len & 0x00000003) { - unsigned long tmp = ioread32(fifoaddr); - memcpy((unsigned char *)buf + count * 4, &tmp, - len & 0x03); - } - } else { - len = (len + 1) / 2; - ioread16_rep(fifoaddr, buf, len); - } -} - -static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val, - unsigned long offset) -{ - iowrite16(val, r8a66597->reg + offset); -} - -static inline void r8a66597_mdfy(struct r8a66597 *r8a66597, - u16 val, u16 pat, unsigned long offset) -{ - u16 tmp; - tmp = r8a66597_read(r8a66597, offset); - tmp = tmp & (~pat); - tmp = tmp | val; - r8a66597_write(r8a66597, tmp, offset); -} - -#define r8a66597_bclr(r8a66597, val, offset) \ - r8a66597_mdfy(r8a66597, 0, val, offset) -#define r8a66597_bset(r8a66597, val, offset) \ - r8a66597_mdfy(r8a66597, val, 0, offset) - -static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597, - struct r8a66597_pipe *pipe, u16 *buf, - int len) -{ - void __iomem *fifoaddr = r8a66597->reg + pipe->fifoaddr; - unsigned long count; - unsigned char *pb; - int i; - - if (r8a66597->pdata->on_chip) { - count = len / 4; - iowrite32_rep(fifoaddr, buf, count); - - if (len & 0x00000003) { - pb = (unsigned char *)buf + count * 4; - for (i = 0; i < (len & 0x00000003); i++) { - if (r8a66597_read(r8a66597, CFIFOSEL) & BIGEND) - iowrite8(pb[i], fifoaddr + i); - else - iowrite8(pb[i], fifoaddr + 3 - i); - } - } - } else { - int odd = len & 0x0001; - - len = len / 2; - iowrite16_rep(fifoaddr, buf, len); - if (unlikely(odd)) { - buf = &buf[len]; - if (r8a66597->pdata->wr0_shorted_to_wr1) - r8a66597_bclr(r8a66597, MBW_16, pipe->fifosel); - iowrite8((unsigned char)*buf, fifoaddr); - if (r8a66597->pdata->wr0_shorted_to_wr1) - r8a66597_bset(r8a66597, MBW_16, pipe->fifosel); - } - } -} - -static inline unsigned long get_syscfg_reg(int port) -{ - return port == 0 ? SYSCFG0 : SYSCFG1; -} - -static inline unsigned long get_syssts_reg(int port) -{ - return port == 0 ? SYSSTS0 : SYSSTS1; -} - -static inline unsigned long get_dvstctr_reg(int port) -{ - return port == 0 ? DVSTCTR0 : DVSTCTR1; -} - -static inline unsigned long get_dmacfg_reg(int port) -{ - return port == 0 ? DMA0CFG : DMA1CFG; -} - -static inline unsigned long get_intenb_reg(int port) -{ - return port == 0 ? INTENB1 : INTENB2; -} - -static inline unsigned long get_intsts_reg(int port) -{ - return port == 0 ? INTSTS1 : INTSTS2; -} - -static inline u16 get_rh_usb_speed(struct r8a66597 *r8a66597, int port) -{ - unsigned long dvstctr_reg = get_dvstctr_reg(port); - - return r8a66597_read(r8a66597, dvstctr_reg) & RHST; -} - -static inline void r8a66597_port_power(struct r8a66597 *r8a66597, int port, - int power) -{ - unsigned long dvstctr_reg = get_dvstctr_reg(port); - - 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) -#define get_pipetre_addr(pipenum) (PIPE1TRE + (pipenum - 1) * 4) -#define get_pipetrn_addr(pipenum) (PIPE1TRN + (pipenum - 1) * 4) -#define get_devadd_addr(address) (DEVADD0 + address * 2) - -#define enable_irq_ready(r8a66597, pipenum) \ - enable_pipe_irq(r8a66597, pipenum, BRDYENB) -#define disable_irq_ready(r8a66597, pipenum) \ - disable_pipe_irq(r8a66597, pipenum, BRDYENB) -#define enable_irq_empty(r8a66597, pipenum) \ - enable_pipe_irq(r8a66597, pipenum, BEMPENB) -#define disable_irq_empty(r8a66597, pipenum) \ - disable_pipe_irq(r8a66597, pipenum, BEMPENB) -#define enable_irq_nrdy(r8a66597, pipenum) \ - enable_pipe_irq(r8a66597, pipenum, NRDYENB) -#define disable_irq_nrdy(r8a66597, pipenum) \ - disable_pipe_irq(r8a66597, pipenum, NRDYENB) - -#endif /* __R8A66597_H__ */ - diff --git a/ANDROID_3.4.5/drivers/usb/host/sl811-hcd.c b/ANDROID_3.4.5/drivers/usb/host/sl811-hcd.c deleted file mode 100644 index 91ce1c02..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/sl811-hcd.c +++ /dev/null @@ -1,1822 +0,0 @@ -/* - * SL811HS HCD (Host Controller Driver) for USB. - * - * Copyright (C) 2004 Psion Teklogix (for NetBook PRO) - * Copyright (C) 2004-2005 David Brownell - * - * Periodic scheduling is based on Roman's OHCI code - * Copyright (C) 1999 Roman Weissgaerber - * - * The SL811HS controller handles host side USB (like the SL11H, but with - * another register set and SOF generation) as well as peripheral side USB - * (like the SL811S). This driver version doesn't implement the Gadget API - * for the peripheral role; or OTG (that'd need much external circuitry). - * - * For documentation, see the SL811HS spec and the "SL811HS Embedded Host" - * document (providing significant pieces missing from that spec); plus - * the SL811S spec if you want peripheral side info. - */ - -/* - * Status: Passed basic stress testing, works with hubs, mice, keyboards, - * and usb-storage. - * - * TODO: - * - usb suspend/resume triggered by sl811 (with USB_SUSPEND) - * - various issues noted in the code - * - performance work; use both register banks; ... - * - use urb->iso_frame_desc[] with ISO transfers - */ - -#undef VERBOSE -#undef PACKET_TRACE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "sl811.h" - - -MODULE_DESCRIPTION("SL811HS USB Host Controller Driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:sl811-hcd"); - -#define DRIVER_VERSION "19 May 2005" - - -#ifndef DEBUG -# define STUB_DEBUG_FILE -#endif - -/* for now, use only one transfer register bank */ -#undef USE_B - -// #define QUIRK2 -#define QUIRK3 - -static const char hcd_name[] = "sl811-hcd"; - -/*-------------------------------------------------------------------------*/ - -static void port_power(struct sl811 *sl811, int is_on) -{ - struct usb_hcd *hcd = sl811_to_hcd(sl811); - - /* hub is inactive unless the port is powered */ - if (is_on) { - if (sl811->port1 & USB_PORT_STAT_POWER) - return; - - sl811->port1 = USB_PORT_STAT_POWER; - sl811->irq_enable = SL11H_INTMASK_INSRMV; - } else { - sl811->port1 = 0; - sl811->irq_enable = 0; - hcd->state = HC_STATE_HALT; - } - sl811->ctrl1 = 0; - sl811_write(sl811, SL11H_IRQ_ENABLE, 0); - sl811_write(sl811, SL11H_IRQ_STATUS, ~0); - - if (sl811->board && sl811->board->port_power) { - /* switch VBUS, at 500mA unless hub power budget gets set */ - DBG("power %s\n", is_on ? "on" : "off"); - sl811->board->port_power(hcd->self.controller, is_on); - } - - /* reset as thoroughly as we can */ - if (sl811->board && sl811->board->reset) - sl811->board->reset(hcd->self.controller); - else { - sl811_write(sl811, SL11H_CTLREG1, SL11H_CTL1MASK_SE0); - mdelay(20); - } - - sl811_write(sl811, SL11H_IRQ_ENABLE, 0); - sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1); - sl811_write(sl811, SL811HS_CTLREG2, SL811HS_CTL2_INIT); - sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable); - - // if !is_on, put into lowpower mode now -} - -/*-------------------------------------------------------------------------*/ - -/* This is a PIO-only HCD. Queueing appends URBs to the endpoint's queue, - * and may start I/O. Endpoint queues are scanned during completion irq - * handlers (one per packet: ACK, NAK, faults, etc) and urb cancellation. - * - * Using an external DMA engine to copy a packet at a time could work, - * though setup/teardown costs may be too big to make it worthwhile. - */ - -/* SETUP starts a new control request. Devices are not allowed to - * STALL or NAK these; they must cancel any pending control requests. - */ -static void setup_packet( - struct sl811 *sl811, - struct sl811h_ep *ep, - struct urb *urb, - u8 bank, - u8 control -) -{ - u8 addr; - u8 len; - void __iomem *data_reg; - - addr = SL811HS_PACKET_BUF(bank == 0); - len = sizeof(struct usb_ctrlrequest); - data_reg = sl811->data_reg; - sl811_write_buf(sl811, addr, urb->setup_packet, len); - - /* autoincrementing */ - sl811_write(sl811, bank + SL11H_BUFADDRREG, addr); - writeb(len, data_reg); - writeb(SL_SETUP /* | ep->epnum */, data_reg); - writeb(usb_pipedevice(urb->pipe), data_reg); - - /* always OUT/data0 */ ; - sl811_write(sl811, bank + SL11H_HOSTCTLREG, - control | SL11H_HCTLMASK_OUT); - ep->length = 0; - PACKET("SETUP qh%p\n", ep); -} - -/* STATUS finishes control requests, often after IN or OUT data packets */ -static void status_packet( - struct sl811 *sl811, - struct sl811h_ep *ep, - struct urb *urb, - u8 bank, - u8 control -) -{ - int do_out; - void __iomem *data_reg; - - do_out = urb->transfer_buffer_length && usb_pipein(urb->pipe); - data_reg = sl811->data_reg; - - /* autoincrementing */ - sl811_write(sl811, bank + SL11H_BUFADDRREG, 0); - writeb(0, data_reg); - writeb((do_out ? SL_OUT : SL_IN) /* | ep->epnum */, data_reg); - writeb(usb_pipedevice(urb->pipe), data_reg); - - /* always data1; sometimes IN */ - control |= SL11H_HCTLMASK_TOGGLE; - if (do_out) - control |= SL11H_HCTLMASK_OUT; - sl811_write(sl811, bank + SL11H_HOSTCTLREG, control); - ep->length = 0; - PACKET("STATUS%s/%s qh%p\n", ep->nak_count ? "/retry" : "", - do_out ? "out" : "in", ep); -} - -/* IN packets can be used with any type of endpoint. here we just - * start the transfer, data from the peripheral may arrive later. - * urb->iso_frame_desc is currently ignored here... - */ -static void in_packet( - struct sl811 *sl811, - struct sl811h_ep *ep, - struct urb *urb, - u8 bank, - u8 control -) -{ - u8 addr; - u8 len; - void __iomem *data_reg; - - /* avoid losing data on overflow */ - len = ep->maxpacket; - addr = SL811HS_PACKET_BUF(bank == 0); - if (!(control & SL11H_HCTLMASK_ISOCH) - && usb_gettoggle(urb->dev, ep->epnum, 0)) - control |= SL11H_HCTLMASK_TOGGLE; - data_reg = sl811->data_reg; - - /* autoincrementing */ - sl811_write(sl811, bank + SL11H_BUFADDRREG, addr); - writeb(len, data_reg); - writeb(SL_IN | ep->epnum, data_reg); - writeb(usb_pipedevice(urb->pipe), data_reg); - - sl811_write(sl811, bank + SL11H_HOSTCTLREG, control); - ep->length = min_t(u32, len, - urb->transfer_buffer_length - urb->actual_length); - PACKET("IN%s/%d qh%p len%d\n", ep->nak_count ? "/retry" : "", - !!usb_gettoggle(urb->dev, ep->epnum, 0), ep, len); -} - -/* OUT packets can be used with any type of endpoint. - * urb->iso_frame_desc is currently ignored here... - */ -static void out_packet( - struct sl811 *sl811, - struct sl811h_ep *ep, - struct urb *urb, - u8 bank, - u8 control -) -{ - void *buf; - u8 addr; - u8 len; - void __iomem *data_reg; - - buf = urb->transfer_buffer + urb->actual_length; - prefetch(buf); - - len = min_t(u32, ep->maxpacket, - urb->transfer_buffer_length - urb->actual_length); - - if (!(control & SL11H_HCTLMASK_ISOCH) - && usb_gettoggle(urb->dev, ep->epnum, 1)) - control |= SL11H_HCTLMASK_TOGGLE; - addr = SL811HS_PACKET_BUF(bank == 0); - data_reg = sl811->data_reg; - - sl811_write_buf(sl811, addr, buf, len); - - /* autoincrementing */ - sl811_write(sl811, bank + SL11H_BUFADDRREG, addr); - writeb(len, data_reg); - writeb(SL_OUT | ep->epnum, data_reg); - writeb(usb_pipedevice(urb->pipe), data_reg); - - sl811_write(sl811, bank + SL11H_HOSTCTLREG, - control | SL11H_HCTLMASK_OUT); - ep->length = len; - PACKET("OUT%s/%d qh%p len%d\n", ep->nak_count ? "/retry" : "", - !!usb_gettoggle(urb->dev, ep->epnum, 1), ep, len); -} - -/*-------------------------------------------------------------------------*/ - -/* caller updates on-chip enables later */ - -static inline void sofirq_on(struct sl811 *sl811) -{ - if (sl811->irq_enable & SL11H_INTMASK_SOFINTR) - return; - VDBG("sof irq on\n"); - sl811->irq_enable |= SL11H_INTMASK_SOFINTR; -} - -static inline void sofirq_off(struct sl811 *sl811) -{ - if (!(sl811->irq_enable & SL11H_INTMASK_SOFINTR)) - return; - VDBG("sof irq off\n"); - sl811->irq_enable &= ~SL11H_INTMASK_SOFINTR; -} - -/*-------------------------------------------------------------------------*/ - -/* pick the next endpoint for a transaction, and issue it. - * frames start with periodic transfers (after whatever is pending - * from the previous frame), and the rest of the time is async - * transfers, scheduled round-robin. - */ -static struct sl811h_ep *start(struct sl811 *sl811, u8 bank) -{ - struct sl811h_ep *ep; - struct urb *urb; - int fclock; - u8 control; - - /* use endpoint at schedule head */ - if (sl811->next_periodic) { - ep = sl811->next_periodic; - sl811->next_periodic = ep->next; - } else { - if (sl811->next_async) - ep = sl811->next_async; - else if (!list_empty(&sl811->async)) - ep = container_of(sl811->async.next, - struct sl811h_ep, schedule); - else { - /* could set up the first fullspeed periodic - * transfer for the next frame ... - */ - return NULL; - } - -#ifdef USE_B - if ((bank && sl811->active_b == ep) || sl811->active_a == ep) - return NULL; -#endif - - if (ep->schedule.next == &sl811->async) - sl811->next_async = NULL; - else - sl811->next_async = container_of(ep->schedule.next, - struct sl811h_ep, schedule); - } - - if (unlikely(list_empty(&ep->hep->urb_list))) { - DBG("empty %p queue?\n", ep); - return NULL; - } - - urb = container_of(ep->hep->urb_list.next, struct urb, urb_list); - control = ep->defctrl; - - /* if this frame doesn't have enough time left to transfer this - * packet, wait till the next frame. too-simple algorithm... - */ - fclock = sl811_read(sl811, SL11H_SOFTMRREG) << 6; - fclock -= 100; /* setup takes not much time */ - if (urb->dev->speed == USB_SPEED_LOW) { - if (control & SL11H_HCTLMASK_PREAMBLE) { - /* also note erratum 1: some hubs won't work */ - fclock -= 800; - } - fclock -= ep->maxpacket << 8; - - /* erratum 2: AFTERSOF only works for fullspeed */ - if (fclock < 0) { - if (ep->period) - sl811->stat_overrun++; - sofirq_on(sl811); - return NULL; - } - } else { - fclock -= 12000 / 19; /* 19 64byte packets/msec */ - if (fclock < 0) { - if (ep->period) - sl811->stat_overrun++; - control |= SL11H_HCTLMASK_AFTERSOF; - - /* throttle bulk/control irq noise */ - } else if (ep->nak_count) - control |= SL11H_HCTLMASK_AFTERSOF; - } - - - switch (ep->nextpid) { - case USB_PID_IN: - in_packet(sl811, ep, urb, bank, control); - break; - case USB_PID_OUT: - out_packet(sl811, ep, urb, bank, control); - break; - case USB_PID_SETUP: - setup_packet(sl811, ep, urb, bank, control); - break; - case USB_PID_ACK: /* for control status */ - status_packet(sl811, ep, urb, bank, control); - break; - default: - DBG("bad ep%p pid %02x\n", ep, ep->nextpid); - ep = NULL; - } - return ep; -} - -#define MIN_JIFFIES ((msecs_to_jiffies(2) > 1) ? msecs_to_jiffies(2) : 2) - -static inline void start_transfer(struct sl811 *sl811) -{ - if (sl811->port1 & USB_PORT_STAT_SUSPEND) - return; - if (sl811->active_a == NULL) { - sl811->active_a = start(sl811, SL811_EP_A(SL811_HOST_BUF)); - if (sl811->active_a != NULL) - sl811->jiffies_a = jiffies + MIN_JIFFIES; - } -#ifdef USE_B - if (sl811->active_b == NULL) { - sl811->active_b = start(sl811, SL811_EP_B(SL811_HOST_BUF)); - if (sl811->active_b != NULL) - sl811->jiffies_b = jiffies + MIN_JIFFIES; - } -#endif -} - -static void finish_request( - struct sl811 *sl811, - struct sl811h_ep *ep, - struct urb *urb, - int status -) __releases(sl811->lock) __acquires(sl811->lock) -{ - unsigned i; - - if (usb_pipecontrol(urb->pipe)) - ep->nextpid = USB_PID_SETUP; - - usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb); - spin_unlock(&sl811->lock); - usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb, status); - spin_lock(&sl811->lock); - - /* leave active endpoints in the schedule */ - if (!list_empty(&ep->hep->urb_list)) - return; - - /* async deschedule? */ - if (!list_empty(&ep->schedule)) { - list_del_init(&ep->schedule); - if (ep == sl811->next_async) - sl811->next_async = NULL; - return; - } - - /* periodic deschedule */ - DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch); - for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) { - struct sl811h_ep *temp; - struct sl811h_ep **prev = &sl811->periodic[i]; - - while (*prev && ((temp = *prev) != ep)) - prev = &temp->next; - if (*prev) - *prev = ep->next; - sl811->load[i] -= ep->load; - } - ep->branch = PERIODIC_SIZE; - sl811->periodic_count--; - sl811_to_hcd(sl811)->self.bandwidth_allocated - -= ep->load / ep->period; - if (ep == sl811->next_periodic) - sl811->next_periodic = ep->next; - - /* we might turn SOFs back on again for the async schedule */ - if (sl811->periodic_count == 0) - sofirq_off(sl811); -} - -static void -done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank) -{ - u8 status; - struct urb *urb; - int urbstat = -EINPROGRESS; - - if (unlikely(!ep)) - return; - - status = sl811_read(sl811, bank + SL11H_PKTSTATREG); - - urb = container_of(ep->hep->urb_list.next, struct urb, urb_list); - - /* we can safely ignore NAKs */ - if (status & SL11H_STATMASK_NAK) { - // PACKET("...NAK_%02x qh%p\n", bank, ep); - if (!ep->period) - ep->nak_count++; - ep->error_count = 0; - - /* ACK advances transfer, toggle, and maybe queue */ - } else if (status & SL11H_STATMASK_ACK) { - struct usb_device *udev = urb->dev; - int len; - unsigned char *buf; - - /* urb->iso_frame_desc is currently ignored here... */ - - ep->nak_count = ep->error_count = 0; - switch (ep->nextpid) { - case USB_PID_OUT: - // PACKET("...ACK/out_%02x qh%p\n", bank, ep); - urb->actual_length += ep->length; - usb_dotoggle(udev, ep->epnum, 1); - if (urb->actual_length - == urb->transfer_buffer_length) { - if (usb_pipecontrol(urb->pipe)) - ep->nextpid = USB_PID_ACK; - - /* some bulk protocols terminate OUT transfers - * by a short packet, using ZLPs not padding. - */ - else if (ep->length < ep->maxpacket - || !(urb->transfer_flags - & URB_ZERO_PACKET)) - urbstat = 0; - } - break; - case USB_PID_IN: - // PACKET("...ACK/in_%02x qh%p\n", bank, ep); - buf = urb->transfer_buffer + urb->actual_length; - prefetchw(buf); - len = ep->maxpacket - sl811_read(sl811, - bank + SL11H_XFERCNTREG); - if (len > ep->length) { - len = ep->length; - urbstat = -EOVERFLOW; - } - urb->actual_length += len; - sl811_read_buf(sl811, SL811HS_PACKET_BUF(bank == 0), - buf, len); - usb_dotoggle(udev, ep->epnum, 0); - if (urbstat == -EINPROGRESS && - (len < ep->maxpacket || - urb->actual_length == - urb->transfer_buffer_length)) { - if (usb_pipecontrol(urb->pipe)) - ep->nextpid = USB_PID_ACK; - else - urbstat = 0; - } - break; - case USB_PID_SETUP: - // PACKET("...ACK/setup_%02x qh%p\n", bank, ep); - if (urb->transfer_buffer_length == urb->actual_length) - ep->nextpid = USB_PID_ACK; - else if (usb_pipeout(urb->pipe)) { - usb_settoggle(udev, 0, 1, 1); - ep->nextpid = USB_PID_OUT; - } else { - usb_settoggle(udev, 0, 0, 1); - ep->nextpid = USB_PID_IN; - } - break; - case USB_PID_ACK: - // PACKET("...ACK/status_%02x qh%p\n", bank, ep); - urbstat = 0; - break; - } - - /* STALL stops all transfers */ - } else if (status & SL11H_STATMASK_STALL) { - PACKET("...STALL_%02x qh%p\n", bank, ep); - ep->nak_count = ep->error_count = 0; - urbstat = -EPIPE; - - /* error? retry, until "3 strikes" */ - } else if (++ep->error_count >= 3) { - if (status & SL11H_STATMASK_TMOUT) - urbstat = -ETIME; - else if (status & SL11H_STATMASK_OVF) - urbstat = -EOVERFLOW; - else - urbstat = -EPROTO; - ep->error_count = 0; - PACKET("...3STRIKES_%02x %02x qh%p stat %d\n", - bank, status, ep, urbstat); - } - - if (urbstat != -EINPROGRESS || urb->unlinked) - finish_request(sl811, ep, urb, urbstat); -} - -static inline u8 checkdone(struct sl811 *sl811) -{ - u8 ctl; - u8 irqstat = 0; - - if (sl811->active_a && time_before_eq(sl811->jiffies_a, jiffies)) { - ctl = sl811_read(sl811, SL811_EP_A(SL11H_HOSTCTLREG)); - if (ctl & SL11H_HCTLMASK_ARM) - sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG), 0); - DBG("%s DONE_A: ctrl %02x sts %02x\n", - (ctl & SL11H_HCTLMASK_ARM) ? "timeout" : "lost", - ctl, - sl811_read(sl811, SL811_EP_A(SL11H_PKTSTATREG))); - irqstat |= SL11H_INTMASK_DONE_A; - } -#ifdef USE_B - if (sl811->active_b && time_before_eq(sl811->jiffies_b, jiffies)) { - ctl = sl811_read(sl811, SL811_EP_B(SL11H_HOSTCTLREG)); - if (ctl & SL11H_HCTLMASK_ARM) - sl811_write(sl811, SL811_EP_B(SL11H_HOSTCTLREG), 0); - DBG("%s DONE_B: ctrl %02x sts %02x\n", - (ctl & SL11H_HCTLMASK_ARM) ? "timeout" : "lost", - ctl, - sl811_read(sl811, SL811_EP_B(SL11H_PKTSTATREG))); - irqstat |= SL11H_INTMASK_DONE_A; - } -#endif - return irqstat; -} - -static irqreturn_t sl811h_irq(struct usb_hcd *hcd) -{ - struct sl811 *sl811 = hcd_to_sl811(hcd); - u8 irqstat; - irqreturn_t ret = IRQ_NONE; - unsigned retries = 5; - - spin_lock(&sl811->lock); - -retry: - irqstat = sl811_read(sl811, SL11H_IRQ_STATUS) & ~SL11H_INTMASK_DP; - if (irqstat) { - sl811_write(sl811, SL11H_IRQ_STATUS, irqstat); - irqstat &= sl811->irq_enable; - } - -#ifdef QUIRK2 - /* this may no longer be necessary ... */ - if (irqstat == 0) { - irqstat = checkdone(sl811); - if (irqstat) - sl811->stat_lost++; - } -#endif - - /* USB packets, not necessarily handled in the order they're - * issued ... that's fine if they're different endpoints. - */ - if (irqstat & SL11H_INTMASK_DONE_A) { - done(sl811, sl811->active_a, SL811_EP_A(SL811_HOST_BUF)); - sl811->active_a = NULL; - sl811->stat_a++; - } -#ifdef USE_B - if (irqstat & SL11H_INTMASK_DONE_B) { - done(sl811, sl811->active_b, SL811_EP_B(SL811_HOST_BUF)); - sl811->active_b = NULL; - sl811->stat_b++; - } -#endif - if (irqstat & SL11H_INTMASK_SOFINTR) { - unsigned index; - - index = sl811->frame++ % (PERIODIC_SIZE - 1); - sl811->stat_sof++; - - /* be graceful about almost-inevitable periodic schedule - * overruns: continue the previous frame's transfers iff - * this one has nothing scheduled. - */ - if (sl811->next_periodic) { - // ERR("overrun to slot %d\n", index); - sl811->stat_overrun++; - } - if (sl811->periodic[index]) - sl811->next_periodic = sl811->periodic[index]; - } - - /* khubd manages debouncing and wakeup */ - if (irqstat & SL11H_INTMASK_INSRMV) { - sl811->stat_insrmv++; - - /* most stats are reset for each VBUS session */ - sl811->stat_wake = 0; - sl811->stat_sof = 0; - sl811->stat_a = 0; - sl811->stat_b = 0; - sl811->stat_lost = 0; - - sl811->ctrl1 = 0; - sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1); - - sl811->irq_enable = SL11H_INTMASK_INSRMV; - sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable); - - /* usbcore nukes other pending transactions on disconnect */ - if (sl811->active_a) { - sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG), 0); - finish_request(sl811, sl811->active_a, - container_of(sl811->active_a - ->hep->urb_list.next, - struct urb, urb_list), - -ESHUTDOWN); - sl811->active_a = NULL; - } -#ifdef USE_B - if (sl811->active_b) { - sl811_write(sl811, SL811_EP_B(SL11H_HOSTCTLREG), 0); - finish_request(sl811, sl811->active_b, - container_of(sl811->active_b - ->hep->urb_list.next, - struct urb, urb_list), - NULL, -ESHUTDOWN); - sl811->active_b = NULL; - } -#endif - - /* port status seems weird until after reset, so - * force the reset and make khubd clean up later. - */ - if (irqstat & SL11H_INTMASK_RD) - sl811->port1 &= ~USB_PORT_STAT_CONNECTION; - else - sl811->port1 |= USB_PORT_STAT_CONNECTION; - - sl811->port1 |= USB_PORT_STAT_C_CONNECTION << 16; - - } else if (irqstat & SL11H_INTMASK_RD) { - if (sl811->port1 & USB_PORT_STAT_SUSPEND) { - DBG("wakeup\n"); - sl811->port1 |= USB_PORT_STAT_C_SUSPEND << 16; - sl811->stat_wake++; - } else - irqstat &= ~SL11H_INTMASK_RD; - } - - if (irqstat) { - if (sl811->port1 & USB_PORT_STAT_ENABLE) - start_transfer(sl811); - ret = IRQ_HANDLED; - if (retries--) - goto retry; - } - - if (sl811->periodic_count == 0 && list_empty(&sl811->async)) - sofirq_off(sl811); - sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable); - - spin_unlock(&sl811->lock); - - return ret; -} - -/*-------------------------------------------------------------------------*/ - -/* usb 1.1 says max 90% of a frame is available for periodic transfers. - * this driver doesn't promise that much since it's got to handle an - * IRQ per packet; irq handling latencies also use up that time. - * - * NOTE: the periodic schedule is a sparse tree, with the load for - * each branch minimized. see fig 3.5 in the OHCI spec for example. - */ -#define MAX_PERIODIC_LOAD 500 /* out of 1000 usec */ - -static int balance(struct sl811 *sl811, u16 period, u16 load) -{ - int i, branch = -ENOSPC; - - /* search for the least loaded schedule branch of that period - * which has enough bandwidth left unreserved. - */ - for (i = 0; i < period ; i++) { - if (branch < 0 || sl811->load[branch] > sl811->load[i]) { - int j; - - for (j = i; j < PERIODIC_SIZE; j += period) { - if ((sl811->load[j] + load) - > MAX_PERIODIC_LOAD) - break; - } - if (j < PERIODIC_SIZE) - continue; - branch = i; - } - } - return branch; -} - -/*-------------------------------------------------------------------------*/ - -static int sl811h_urb_enqueue( - struct usb_hcd *hcd, - struct urb *urb, - gfp_t mem_flags -) { - struct sl811 *sl811 = hcd_to_sl811(hcd); - struct usb_device *udev = urb->dev; - unsigned int pipe = urb->pipe; - int is_out = !usb_pipein(pipe); - int type = usb_pipetype(pipe); - int epnum = usb_pipeendpoint(pipe); - struct sl811h_ep *ep = NULL; - unsigned long flags; - int i; - int retval; - struct usb_host_endpoint *hep = urb->ep; - -#ifndef CONFIG_USB_SL811_HCD_ISO - if (type == PIPE_ISOCHRONOUS) - return -ENOSPC; -#endif - - /* avoid all allocations within spinlocks */ - if (!hep->hcpriv) { - ep = kzalloc(sizeof *ep, mem_flags); - if (ep == NULL) - return -ENOMEM; - } - - spin_lock_irqsave(&sl811->lock, flags); - - /* don't submit to a dead or disabled port */ - if (!(sl811->port1 & USB_PORT_STAT_ENABLE) - || !HC_IS_RUNNING(hcd->state)) { - retval = -ENODEV; - kfree(ep); - goto fail_not_linked; - } - retval = usb_hcd_link_urb_to_ep(hcd, urb); - if (retval) { - kfree(ep); - goto fail_not_linked; - } - - if (hep->hcpriv) { - kfree(ep); - ep = hep->hcpriv; - } else if (!ep) { - retval = -ENOMEM; - goto fail; - - } else { - INIT_LIST_HEAD(&ep->schedule); - ep->udev = udev; - ep->epnum = epnum; - ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out); - ep->defctrl = SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENABLE; - usb_settoggle(udev, epnum, is_out, 0); - - if (type == PIPE_CONTROL) - ep->nextpid = USB_PID_SETUP; - else if (is_out) - ep->nextpid = USB_PID_OUT; - else - ep->nextpid = USB_PID_IN; - - if (ep->maxpacket > H_MAXPACKET) { - /* iso packets up to 240 bytes could work... */ - DBG("dev %d ep%d maxpacket %d\n", - udev->devnum, epnum, ep->maxpacket); - retval = -EINVAL; - kfree(ep); - goto fail; - } - - if (udev->speed == USB_SPEED_LOW) { - /* send preamble for external hub? */ - if (!(sl811->ctrl1 & SL11H_CTL1MASK_LSPD)) - ep->defctrl |= SL11H_HCTLMASK_PREAMBLE; - } - switch (type) { - case PIPE_ISOCHRONOUS: - case PIPE_INTERRUPT: - if (urb->interval > PERIODIC_SIZE) - urb->interval = PERIODIC_SIZE; - ep->period = urb->interval; - ep->branch = PERIODIC_SIZE; - if (type == PIPE_ISOCHRONOUS) - ep->defctrl |= SL11H_HCTLMASK_ISOCH; - ep->load = usb_calc_bus_time(udev->speed, !is_out, - (type == PIPE_ISOCHRONOUS), - usb_maxpacket(udev, pipe, is_out)) - / 1000; - break; - } - - ep->hep = hep; - hep->hcpriv = ep; - } - - /* maybe put endpoint into schedule */ - switch (type) { - case PIPE_CONTROL: - case PIPE_BULK: - if (list_empty(&ep->schedule)) - list_add_tail(&ep->schedule, &sl811->async); - break; - case PIPE_ISOCHRONOUS: - case PIPE_INTERRUPT: - urb->interval = ep->period; - if (ep->branch < PERIODIC_SIZE) { - /* NOTE: the phase is correct here, but the value - * needs offsetting by the transfer queue depth. - * All current drivers ignore start_frame, so this - * is unlikely to ever matter... - */ - urb->start_frame = (sl811->frame & (PERIODIC_SIZE - 1)) - + ep->branch; - break; - } - - retval = balance(sl811, ep->period, ep->load); - if (retval < 0) - goto fail; - ep->branch = retval; - retval = 0; - urb->start_frame = (sl811->frame & (PERIODIC_SIZE - 1)) - + ep->branch; - - /* sort each schedule branch by period (slow before fast) - * to share the faster parts of the tree without needing - * dummy/placeholder nodes - */ - DBG("schedule qh%d/%p branch %d\n", ep->period, ep, ep->branch); - for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) { - struct sl811h_ep **prev = &sl811->periodic[i]; - struct sl811h_ep *here = *prev; - - while (here && ep != here) { - if (ep->period > here->period) - break; - prev = &here->next; - here = *prev; - } - if (ep != here) { - ep->next = here; - *prev = ep; - } - sl811->load[i] += ep->load; - } - sl811->periodic_count++; - hcd->self.bandwidth_allocated += ep->load / ep->period; - sofirq_on(sl811); - } - - urb->hcpriv = hep; - start_transfer(sl811); - sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable); -fail: - if (retval) - usb_hcd_unlink_urb_from_ep(hcd, urb); -fail_not_linked: - spin_unlock_irqrestore(&sl811->lock, flags); - return retval; -} - -static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) -{ - struct sl811 *sl811 = hcd_to_sl811(hcd); - struct usb_host_endpoint *hep; - unsigned long flags; - struct sl811h_ep *ep; - int retval; - - spin_lock_irqsave(&sl811->lock, flags); - retval = usb_hcd_check_unlink_urb(hcd, urb, status); - if (retval) - goto fail; - - hep = urb->hcpriv; - ep = hep->hcpriv; - if (ep) { - /* finish right away if this urb can't be active ... - * note that some drivers wrongly expect delays - */ - if (ep->hep->urb_list.next != &urb->urb_list) { - /* not front of queue? never active */ - - /* for active transfers, we expect an IRQ */ - } else if (sl811->active_a == ep) { - if (time_before_eq(sl811->jiffies_a, jiffies)) { - /* happens a lot with lowspeed?? */ - DBG("giveup on DONE_A: ctrl %02x sts %02x\n", - sl811_read(sl811, - SL811_EP_A(SL11H_HOSTCTLREG)), - sl811_read(sl811, - SL811_EP_A(SL11H_PKTSTATREG))); - sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG), - 0); - sl811->active_a = NULL; - } else - urb = NULL; -#ifdef USE_B - } else if (sl811->active_b == ep) { - if (time_before_eq(sl811->jiffies_a, jiffies)) { - /* happens a lot with lowspeed?? */ - DBG("giveup on DONE_B: ctrl %02x sts %02x\n", - sl811_read(sl811, - SL811_EP_B(SL11H_HOSTCTLREG)), - sl811_read(sl811, - SL811_EP_B(SL11H_PKTSTATREG))); - sl811_write(sl811, SL811_EP_B(SL11H_HOSTCTLREG), - 0); - sl811->active_b = NULL; - } else - urb = NULL; -#endif - } else { - /* front of queue for inactive endpoint */ - } - - if (urb) - finish_request(sl811, ep, urb, 0); - else - VDBG("dequeue, urb %p active %s; wait4irq\n", urb, - (sl811->active_a == ep) ? "A" : "B"); - } else - retval = -EINVAL; - fail: - spin_unlock_irqrestore(&sl811->lock, flags); - return retval; -} - -static void -sl811h_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep) -{ - struct sl811h_ep *ep = hep->hcpriv; - - if (!ep) - return; - - /* assume we'd just wait for the irq */ - if (!list_empty(&hep->urb_list)) - msleep(3); - if (!list_empty(&hep->urb_list)) - WARNING("ep %p not empty?\n", ep); - - kfree(ep); - hep->hcpriv = NULL; -} - -static int -sl811h_get_frame(struct usb_hcd *hcd) -{ - struct sl811 *sl811 = hcd_to_sl811(hcd); - - /* wrong except while periodic transfers are scheduled; - * never matches the on-the-wire frame; - * subject to overruns. - */ - return sl811->frame; -} - - -/*-------------------------------------------------------------------------*/ - -/* the virtual root hub timer IRQ checks for hub status */ -static int -sl811h_hub_status_data(struct usb_hcd *hcd, char *buf) -{ - struct sl811 *sl811 = hcd_to_sl811(hcd); -#ifdef QUIRK3 - unsigned long flags; - - /* non-SMP HACK: use root hub timer as i/o watchdog - * this seems essential when SOF IRQs aren't in use... - */ - local_irq_save(flags); - if (!timer_pending(&sl811->timer)) { - if (sl811h_irq( /* ~0, */ hcd) != IRQ_NONE) - sl811->stat_lost++; - } - local_irq_restore(flags); -#endif - - if (!(sl811->port1 & (0xffff << 16))) - return 0; - - /* tell khubd port 1 changed */ - *buf = (1 << 1); - return 1; -} - -static void -sl811h_hub_descriptor ( - struct sl811 *sl811, - struct usb_hub_descriptor *desc -) { - u16 temp = 0; - - desc->bDescriptorType = 0x29; - desc->bHubContrCurrent = 0; - - desc->bNbrPorts = 1; - desc->bDescLength = 9; - - /* per-port power switching (gang of one!), or none */ - desc->bPwrOn2PwrGood = 0; - if (sl811->board && sl811->board->port_power) { - desc->bPwrOn2PwrGood = sl811->board->potpg; - if (!desc->bPwrOn2PwrGood) - desc->bPwrOn2PwrGood = 10; - temp = 0x0001; - } else - temp = 0x0002; - - /* no overcurrent errors detection/handling */ - temp |= 0x0010; - - desc->wHubCharacteristics = cpu_to_le16(temp); - - /* ports removable, and legacy PortPwrCtrlMask */ - desc->u.hs.DeviceRemovable[0] = 0 << 1; - desc->u.hs.DeviceRemovable[1] = ~0; -} - -static void -sl811h_timer(unsigned long _sl811) -{ - struct sl811 *sl811 = (void *) _sl811; - unsigned long flags; - u8 irqstat; - u8 signaling = sl811->ctrl1 & SL11H_CTL1MASK_FORCE; - const u32 mask = USB_PORT_STAT_CONNECTION - | USB_PORT_STAT_ENABLE - | USB_PORT_STAT_LOW_SPEED; - - spin_lock_irqsave(&sl811->lock, flags); - - /* stop special signaling */ - sl811->ctrl1 &= ~SL11H_CTL1MASK_FORCE; - sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1); - udelay(3); - - irqstat = sl811_read(sl811, SL11H_IRQ_STATUS); - - switch (signaling) { - case SL11H_CTL1MASK_SE0: - DBG("end reset\n"); - sl811->port1 = (USB_PORT_STAT_C_RESET << 16) - | USB_PORT_STAT_POWER; - sl811->ctrl1 = 0; - /* don't wrongly ack RD */ - if (irqstat & SL11H_INTMASK_INSRMV) - irqstat &= ~SL11H_INTMASK_RD; - break; - case SL11H_CTL1MASK_K: - DBG("end resume\n"); - sl811->port1 &= ~USB_PORT_STAT_SUSPEND; - break; - default: - DBG("odd timer signaling: %02x\n", signaling); - break; - } - sl811_write(sl811, SL11H_IRQ_STATUS, irqstat); - - if (irqstat & SL11H_INTMASK_RD) { - /* usbcore nukes all pending transactions on disconnect */ - if (sl811->port1 & USB_PORT_STAT_CONNECTION) - sl811->port1 |= (USB_PORT_STAT_C_CONNECTION << 16) - | (USB_PORT_STAT_C_ENABLE << 16); - sl811->port1 &= ~mask; - sl811->irq_enable = SL11H_INTMASK_INSRMV; - } else { - sl811->port1 |= mask; - if (irqstat & SL11H_INTMASK_DP) - sl811->port1 &= ~USB_PORT_STAT_LOW_SPEED; - sl811->irq_enable = SL11H_INTMASK_INSRMV | SL11H_INTMASK_RD; - } - - if (sl811->port1 & USB_PORT_STAT_CONNECTION) { - u8 ctrl2 = SL811HS_CTL2_INIT; - - sl811->irq_enable |= SL11H_INTMASK_DONE_A; -#ifdef USE_B - sl811->irq_enable |= SL11H_INTMASK_DONE_B; -#endif - if (sl811->port1 & USB_PORT_STAT_LOW_SPEED) { - sl811->ctrl1 |= SL11H_CTL1MASK_LSPD; - ctrl2 |= SL811HS_CTL2MASK_DSWAP; - } - - /* start SOFs flowing, kickstarting with A registers */ - sl811->ctrl1 |= SL11H_CTL1MASK_SOF_ENA; - sl811_write(sl811, SL11H_SOFLOWREG, 0xe0); - sl811_write(sl811, SL811HS_CTLREG2, ctrl2); - - /* autoincrementing */ - sl811_write(sl811, SL811_EP_A(SL11H_BUFLNTHREG), 0); - writeb(SL_SOF, sl811->data_reg); - writeb(0, sl811->data_reg); - sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG), - SL11H_HCTLMASK_ARM); - - /* khubd provides debounce delay */ - } else { - sl811->ctrl1 = 0; - } - sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1); - - /* reenable irqs */ - sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable); - spin_unlock_irqrestore(&sl811->lock, flags); -} - -static int -sl811h_hub_control( - struct usb_hcd *hcd, - u16 typeReq, - u16 wValue, - u16 wIndex, - char *buf, - u16 wLength -) { - struct sl811 *sl811 = hcd_to_sl811(hcd); - int retval = 0; - unsigned long flags; - - spin_lock_irqsave(&sl811->lock, flags); - - switch (typeReq) { - case ClearHubFeature: - case SetHubFeature: - switch (wValue) { - case C_HUB_OVER_CURRENT: - case C_HUB_LOCAL_POWER: - break; - default: - goto error; - } - break; - case ClearPortFeature: - if (wIndex != 1 || wLength != 0) - goto error; - - switch (wValue) { - case USB_PORT_FEAT_ENABLE: - sl811->port1 &= USB_PORT_STAT_POWER; - sl811->ctrl1 = 0; - sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1); - sl811->irq_enable = SL11H_INTMASK_INSRMV; - sl811_write(sl811, SL11H_IRQ_ENABLE, - sl811->irq_enable); - break; - case USB_PORT_FEAT_SUSPEND: - if (!(sl811->port1 & USB_PORT_STAT_SUSPEND)) - break; - - /* 20 msec of resume/K signaling, other irqs blocked */ - DBG("start resume...\n"); - sl811->irq_enable = 0; - sl811_write(sl811, SL11H_IRQ_ENABLE, - sl811->irq_enable); - sl811->ctrl1 |= SL11H_CTL1MASK_K; - sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1); - - mod_timer(&sl811->timer, jiffies - + msecs_to_jiffies(20)); - break; - case USB_PORT_FEAT_POWER: - port_power(sl811, 0); - break; - case USB_PORT_FEAT_C_ENABLE: - case USB_PORT_FEAT_C_SUSPEND: - case USB_PORT_FEAT_C_CONNECTION: - case USB_PORT_FEAT_C_OVER_CURRENT: - case USB_PORT_FEAT_C_RESET: - break; - default: - goto error; - } - sl811->port1 &= ~(1 << wValue); - break; - case GetHubDescriptor: - sl811h_hub_descriptor(sl811, (struct usb_hub_descriptor *) buf); - break; - case GetHubStatus: - put_unaligned_le32(0, buf); - break; - case GetPortStatus: - if (wIndex != 1) - goto error; - put_unaligned_le32(sl811->port1, buf); - -#ifndef VERBOSE - if (*(u16*)(buf+2)) /* only if wPortChange is interesting */ -#endif - DBG("GetPortStatus %08x\n", sl811->port1); - break; - case SetPortFeature: - if (wIndex != 1 || wLength != 0) - goto error; - switch (wValue) { - case USB_PORT_FEAT_SUSPEND: - if (sl811->port1 & USB_PORT_STAT_RESET) - goto error; - if (!(sl811->port1 & USB_PORT_STAT_ENABLE)) - goto error; - - DBG("suspend...\n"); - sl811->ctrl1 &= ~SL11H_CTL1MASK_SOF_ENA; - sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1); - break; - case USB_PORT_FEAT_POWER: - port_power(sl811, 1); - break; - case USB_PORT_FEAT_RESET: - if (sl811->port1 & USB_PORT_STAT_SUSPEND) - goto error; - if (!(sl811->port1 & USB_PORT_STAT_POWER)) - break; - - /* 50 msec of reset/SE0 signaling, irqs blocked */ - sl811->irq_enable = 0; - sl811_write(sl811, SL11H_IRQ_ENABLE, - sl811->irq_enable); - sl811->ctrl1 = SL11H_CTL1MASK_SE0; - sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1); - sl811->port1 |= USB_PORT_STAT_RESET; - mod_timer(&sl811->timer, jiffies - + msecs_to_jiffies(50)); - break; - default: - goto error; - } - sl811->port1 |= 1 << wValue; - break; - - default: -error: - /* "protocol stall" on error */ - retval = -EPIPE; - } - - spin_unlock_irqrestore(&sl811->lock, flags); - return retval; -} - -#ifdef CONFIG_PM - -static int -sl811h_bus_suspend(struct usb_hcd *hcd) -{ - // SOFs off - DBG("%s\n", __func__); - return 0; -} - -static int -sl811h_bus_resume(struct usb_hcd *hcd) -{ - // SOFs on - DBG("%s\n", __func__); - return 0; -} - -#else - -#define sl811h_bus_suspend NULL -#define sl811h_bus_resume NULL - -#endif - - -/*-------------------------------------------------------------------------*/ - -#ifdef STUB_DEBUG_FILE - -static inline void create_debug_file(struct sl811 *sl811) { } -static inline void remove_debug_file(struct sl811 *sl811) { } - -#else - -#include -#include - -static void dump_irq(struct seq_file *s, char *label, u8 mask) -{ - seq_printf(s, "%s %02x%s%s%s%s%s%s\n", label, mask, - (mask & SL11H_INTMASK_DONE_A) ? " done_a" : "", - (mask & SL11H_INTMASK_DONE_B) ? " done_b" : "", - (mask & SL11H_INTMASK_SOFINTR) ? " sof" : "", - (mask & SL11H_INTMASK_INSRMV) ? " ins/rmv" : "", - (mask & SL11H_INTMASK_RD) ? " rd" : "", - (mask & SL11H_INTMASK_DP) ? " dp" : ""); -} - -static int proc_sl811h_show(struct seq_file *s, void *unused) -{ - struct sl811 *sl811 = s->private; - struct sl811h_ep *ep; - unsigned i; - - seq_printf(s, "%s\n%s version %s\nportstatus[1] = %08x\n", - sl811_to_hcd(sl811)->product_desc, - hcd_name, DRIVER_VERSION, - sl811->port1); - - seq_printf(s, "insert/remove: %ld\n", sl811->stat_insrmv); - seq_printf(s, "current session: done_a %ld done_b %ld " - "wake %ld sof %ld overrun %ld lost %ld\n\n", - sl811->stat_a, sl811->stat_b, - sl811->stat_wake, sl811->stat_sof, - sl811->stat_overrun, sl811->stat_lost); - - spin_lock_irq(&sl811->lock); - - if (sl811->ctrl1 & SL11H_CTL1MASK_SUSPEND) - seq_printf(s, "(suspended)\n\n"); - else { - u8 t = sl811_read(sl811, SL11H_CTLREG1); - - seq_printf(s, "ctrl1 %02x%s%s%s%s\n", t, - (t & SL11H_CTL1MASK_SOF_ENA) ? " sofgen" : "", - ({char *s; switch (t & SL11H_CTL1MASK_FORCE) { - case SL11H_CTL1MASK_NORMAL: s = ""; break; - case SL11H_CTL1MASK_SE0: s = " se0/reset"; break; - case SL11H_CTL1MASK_K: s = " k/resume"; break; - default: s = "j"; break; - }; s; }), - (t & SL11H_CTL1MASK_LSPD) ? " lowspeed" : "", - (t & SL11H_CTL1MASK_SUSPEND) ? " suspend" : ""); - - dump_irq(s, "irq_enable", - sl811_read(sl811, SL11H_IRQ_ENABLE)); - dump_irq(s, "irq_status", - sl811_read(sl811, SL11H_IRQ_STATUS)); - seq_printf(s, "frame clocks remaining: %d\n", - sl811_read(sl811, SL11H_SOFTMRREG) << 6); - } - - seq_printf(s, "A: qh%p ctl %02x sts %02x\n", sl811->active_a, - sl811_read(sl811, SL811_EP_A(SL11H_HOSTCTLREG)), - sl811_read(sl811, SL811_EP_A(SL11H_PKTSTATREG))); - seq_printf(s, "B: qh%p ctl %02x sts %02x\n", sl811->active_b, - sl811_read(sl811, SL811_EP_B(SL11H_HOSTCTLREG)), - sl811_read(sl811, SL811_EP_B(SL11H_PKTSTATREG))); - seq_printf(s, "\n"); - list_for_each_entry (ep, &sl811->async, schedule) { - struct urb *urb; - - seq_printf(s, "%s%sqh%p, ep%d%s, maxpacket %d" - " nak %d err %d\n", - (ep == sl811->active_a) ? "(A) " : "", - (ep == sl811->active_b) ? "(B) " : "", - ep, ep->epnum, - ({ char *s; switch (ep->nextpid) { - case USB_PID_IN: s = "in"; break; - case USB_PID_OUT: s = "out"; break; - case USB_PID_SETUP: s = "setup"; break; - case USB_PID_ACK: s = "status"; break; - default: s = "?"; break; - }; s;}), - ep->maxpacket, - ep->nak_count, ep->error_count); - list_for_each_entry (urb, &ep->hep->urb_list, urb_list) { - seq_printf(s, " urb%p, %d/%d\n", urb, - urb->actual_length, - urb->transfer_buffer_length); - } - } - if (!list_empty(&sl811->async)) - seq_printf(s, "\n"); - - seq_printf(s, "periodic size= %d\n", PERIODIC_SIZE); - - for (i = 0; i < PERIODIC_SIZE; i++) { - ep = sl811->periodic[i]; - if (!ep) - continue; - seq_printf(s, "%2d [%3d]:\n", i, sl811->load[i]); - - /* DUMB: prints shared entries multiple times */ - do { - seq_printf(s, - " %s%sqh%d/%p (%sdev%d ep%d%s max %d) " - "err %d\n", - (ep == sl811->active_a) ? "(A) " : "", - (ep == sl811->active_b) ? "(B) " : "", - ep->period, ep, - (ep->udev->speed == USB_SPEED_FULL) - ? "" : "ls ", - ep->udev->devnum, ep->epnum, - (ep->epnum == 0) ? "" - : ((ep->nextpid == USB_PID_IN) - ? "in" - : "out"), - ep->maxpacket, ep->error_count); - ep = ep->next; - } while (ep); - } - - spin_unlock_irq(&sl811->lock); - seq_printf(s, "\n"); - - return 0; -} - -static int proc_sl811h_open(struct inode *inode, struct file *file) -{ - return single_open(file, proc_sl811h_show, PDE(inode)->data); -} - -static const struct file_operations proc_ops = { - .open = proc_sl811h_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -/* expect just one sl811 per system */ -static const char proc_filename[] = "driver/sl811h"; - -static void create_debug_file(struct sl811 *sl811) -{ - sl811->pde = proc_create_data(proc_filename, 0, NULL, &proc_ops, sl811); -} - -static void remove_debug_file(struct sl811 *sl811) -{ - if (sl811->pde) - remove_proc_entry(proc_filename, NULL); -} - -#endif - -/*-------------------------------------------------------------------------*/ - -static void -sl811h_stop(struct usb_hcd *hcd) -{ - struct sl811 *sl811 = hcd_to_sl811(hcd); - unsigned long flags; - - del_timer_sync(&hcd->rh_timer); - - spin_lock_irqsave(&sl811->lock, flags); - port_power(sl811, 0); - spin_unlock_irqrestore(&sl811->lock, flags); -} - -static int -sl811h_start(struct usb_hcd *hcd) -{ - struct sl811 *sl811 = hcd_to_sl811(hcd); - - /* chip has been reset, VBUS power is off */ - hcd->state = HC_STATE_RUNNING; - - if (sl811->board) { - if (!device_can_wakeup(hcd->self.controller)) - device_init_wakeup(hcd->self.controller, - sl811->board->can_wakeup); - hcd->power_budget = sl811->board->power * 2; - } - - /* enable power and interrupts */ - port_power(sl811, 1); - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static struct hc_driver sl811h_hc_driver = { - .description = hcd_name, - .hcd_priv_size = sizeof(struct sl811), - - /* - * generic hardware linkage - */ - .irq = sl811h_irq, - .flags = HCD_USB11 | HCD_MEMORY, - - /* Basic lifecycle operations */ - .start = sl811h_start, - .stop = sl811h_stop, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = sl811h_urb_enqueue, - .urb_dequeue = sl811h_urb_dequeue, - .endpoint_disable = sl811h_endpoint_disable, - - /* - * periodic schedule support - */ - .get_frame_number = sl811h_get_frame, - - /* - * root hub support - */ - .hub_status_data = sl811h_hub_status_data, - .hub_control = sl811h_hub_control, - .bus_suspend = sl811h_bus_suspend, - .bus_resume = sl811h_bus_resume, -}; - -/*-------------------------------------------------------------------------*/ - -static int __devexit -sl811h_remove(struct platform_device *dev) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - struct sl811 *sl811 = hcd_to_sl811(hcd); - struct resource *res; - - remove_debug_file(sl811); - usb_remove_hcd(hcd); - - /* some platforms may use IORESOURCE_IO */ - res = platform_get_resource(dev, IORESOURCE_MEM, 1); - if (res) - iounmap(sl811->data_reg); - - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (res) - iounmap(sl811->addr_reg); - - usb_put_hcd(hcd); - return 0; -} - -static int __devinit -sl811h_probe(struct platform_device *dev) -{ - struct usb_hcd *hcd; - struct sl811 *sl811; - struct resource *addr, *data, *ires; - int irq; - void __iomem *addr_reg; - void __iomem *data_reg; - int retval; - u8 tmp, ioaddr = 0; - unsigned long irqflags; - - if (usb_disabled()) - return -ENODEV; - - /* basic sanity checks first. board-specific init logic should - * have initialized these three resources and probably board - * specific platform_data. we don't probe for IRQs, and do only - * minimal sanity checking. - */ - ires = platform_get_resource(dev, IORESOURCE_IRQ, 0); - if (dev->num_resources < 3 || !ires) - return -ENODEV; - - irq = ires->start; - irqflags = ires->flags & IRQF_TRIGGER_MASK; - - /* refuse to confuse usbcore */ - if (dev->dev.dma_mask) { - DBG("no we won't dma\n"); - return -EINVAL; - } - - /* the chip may be wired for either kind of addressing */ - addr = platform_get_resource(dev, IORESOURCE_MEM, 0); - data = platform_get_resource(dev, IORESOURCE_MEM, 1); - retval = -EBUSY; - if (!addr || !data) { - addr = platform_get_resource(dev, IORESOURCE_IO, 0); - data = platform_get_resource(dev, IORESOURCE_IO, 1); - if (!addr || !data) - return -ENODEV; - ioaddr = 1; - /* - * NOTE: 64-bit resource->start is getting truncated - * to avoid compiler warning, assuming that ->start - * is always 32-bit for this case - */ - addr_reg = (void __iomem *) (unsigned long) addr->start; - data_reg = (void __iomem *) (unsigned long) data->start; - } else { - addr_reg = ioremap(addr->start, 1); - if (addr_reg == NULL) { - retval = -ENOMEM; - goto err2; - } - - data_reg = ioremap(data->start, 1); - if (data_reg == NULL) { - retval = -ENOMEM; - goto err4; - } - } - - /* allocate and initialize hcd */ - hcd = usb_create_hcd(&sl811h_hc_driver, &dev->dev, dev_name(&dev->dev)); - if (!hcd) { - retval = -ENOMEM; - goto err5; - } - hcd->rsrc_start = addr->start; - sl811 = hcd_to_sl811(hcd); - - spin_lock_init(&sl811->lock); - INIT_LIST_HEAD(&sl811->async); - sl811->board = dev->dev.platform_data; - init_timer(&sl811->timer); - sl811->timer.function = sl811h_timer; - sl811->timer.data = (unsigned long) sl811; - sl811->addr_reg = addr_reg; - sl811->data_reg = data_reg; - - spin_lock_irq(&sl811->lock); - port_power(sl811, 0); - spin_unlock_irq(&sl811->lock); - msleep(200); - - tmp = sl811_read(sl811, SL11H_HWREVREG); - switch (tmp >> 4) { - case 1: - hcd->product_desc = "SL811HS v1.2"; - break; - case 2: - hcd->product_desc = "SL811HS v1.5"; - break; - default: - /* reject case 0, SL11S is less functional */ - DBG("chiprev %02x\n", tmp); - retval = -ENXIO; - goto err6; - } - - /* The chip's IRQ is level triggered, active high. A requirement - * for platform device setup is to cope with things like signal - * inverters (e.g. CF is active low) or working only with edge - * triggers (e.g. most ARM CPUs). Initial driver stress testing - * was on a system with single edge triggering, so most sorts of - * triggering arrangement should work. - * - * Use resource IRQ flags if set by platform device setup. - */ - irqflags |= IRQF_SHARED; - retval = usb_add_hcd(hcd, irq, irqflags); - if (retval != 0) - goto err6; - - create_debug_file(sl811); - return retval; - - err6: - usb_put_hcd(hcd); - err5: - if (!ioaddr) - iounmap(data_reg); - err4: - if (!ioaddr) - iounmap(addr_reg); - err2: - DBG("init error, %d\n", retval); - return retval; -} - -#ifdef CONFIG_PM - -/* for this device there's no useful distinction between the controller - * and its root hub, except that the root hub only gets direct PM calls - * when CONFIG_USB_SUSPEND is enabled. - */ - -static int -sl811h_suspend(struct platform_device *dev, pm_message_t state) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - struct sl811 *sl811 = hcd_to_sl811(hcd); - int retval = 0; - - switch (state.event) { - case PM_EVENT_FREEZE: - retval = sl811h_bus_suspend(hcd); - break; - case PM_EVENT_SUSPEND: - case PM_EVENT_HIBERNATE: - case PM_EVENT_PRETHAW: /* explicitly discard hw state */ - port_power(sl811, 0); - break; - } - return retval; -} - -static int -sl811h_resume(struct platform_device *dev) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - struct sl811 *sl811 = hcd_to_sl811(hcd); - - /* with no "check to see if VBUS is still powered" board hook, - * let's assume it'd only be powered to enable remote wakeup. - */ - if (!sl811->port1 || !device_can_wakeup(&hcd->self.root_hub->dev)) { - sl811->port1 = 0; - port_power(sl811, 1); - usb_root_hub_lost_power(hcd->self.root_hub); - return 0; - } - - return sl811h_bus_resume(hcd); -} - -#else - -#define sl811h_suspend NULL -#define sl811h_resume NULL - -#endif - - -/* this driver is exported so sl811_cs can depend on it */ -struct platform_driver sl811h_driver = { - .probe = sl811h_probe, - .remove = __devexit_p(sl811h_remove), - - .suspend = sl811h_suspend, - .resume = sl811h_resume, - .driver = { - .name = (char *) hcd_name, - .owner = THIS_MODULE, - }, -}; -EXPORT_SYMBOL(sl811h_driver); - -module_platform_driver(sl811h_driver); diff --git a/ANDROID_3.4.5/drivers/usb/host/sl811.h b/ANDROID_3.4.5/drivers/usb/host/sl811.h deleted file mode 100644 index b6b8c1f2..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/sl811.h +++ /dev/null @@ -1,266 +0,0 @@ -/* - * SL811HS register declarations and HCD data structures - * - * Copyright (C) 2004 Psion Teklogix - * Copyright (C) 2004 David Brownell - * Copyright (C) 2001 Cypress Semiconductor Inc. - */ - -/* - * SL811HS has transfer registers, and control registers. In host/master - * mode one set of registers is used; in peripheral/slave mode, another. - * - SL11H only has some "A" transfer registers from 0x00-0x04 - * - SL811HS also has "B" registers from 0x08-0x0c - * - SL811S (or HS in slave mode) has four A+B sets, at 00, 10, 20, 30 - */ - -#define SL811_EP_A(base) ((base) + 0) -#define SL811_EP_B(base) ((base) + 8) - -#define SL811_HOST_BUF 0x00 -#define SL811_PERIPH_EP0 0x00 -#define SL811_PERIPH_EP1 0x10 -#define SL811_PERIPH_EP2 0x20 -#define SL811_PERIPH_EP3 0x30 - - -/* TRANSFER REGISTERS: host and peripheral sides are similar - * except for the control models (master vs slave). - */ -#define SL11H_HOSTCTLREG 0 -# define SL11H_HCTLMASK_ARM 0x01 -# define SL11H_HCTLMASK_ENABLE 0x02 -# define SL11H_HCTLMASK_IN 0x00 -# define SL11H_HCTLMASK_OUT 0x04 -# define SL11H_HCTLMASK_ISOCH 0x10 -# define SL11H_HCTLMASK_AFTERSOF 0x20 -# define SL11H_HCTLMASK_TOGGLE 0x40 -# define SL11H_HCTLMASK_PREAMBLE 0x80 -#define SL11H_BUFADDRREG 1 -#define SL11H_BUFLNTHREG 2 -#define SL11H_PKTSTATREG 3 /* read */ -# define SL11H_STATMASK_ACK 0x01 -# define SL11H_STATMASK_ERROR 0x02 -# define SL11H_STATMASK_TMOUT 0x04 -# define SL11H_STATMASK_SEQ 0x08 -# define SL11H_STATMASK_SETUP 0x10 -# define SL11H_STATMASK_OVF 0x20 -# define SL11H_STATMASK_NAK 0x40 -# define SL11H_STATMASK_STALL 0x80 -#define SL11H_PIDEPREG 3 /* write */ -# define SL_SETUP 0xd0 -# define SL_IN 0x90 -# define SL_OUT 0x10 -# define SL_SOF 0x50 -# define SL_PREAMBLE 0xc0 -# define SL_NAK 0xa0 -# define SL_STALL 0xe0 -# define SL_DATA0 0x30 -# define SL_DATA1 0xb0 -#define SL11H_XFERCNTREG 4 /* read */ -#define SL11H_DEVADDRREG 4 /* write */ - - -/* CONTROL REGISTERS: host and peripheral are very different. - */ -#define SL11H_CTLREG1 5 -# define SL11H_CTL1MASK_SOF_ENA 0x01 -# define SL11H_CTL1MASK_FORCE 0x18 -# define SL11H_CTL1MASK_NORMAL 0x00 -# define SL11H_CTL1MASK_SE0 0x08 /* reset */ -# define SL11H_CTL1MASK_J 0x10 -# define SL11H_CTL1MASK_K 0x18 /* resume */ -# define SL11H_CTL1MASK_LSPD 0x20 -# define SL11H_CTL1MASK_SUSPEND 0x40 -#define SL11H_IRQ_ENABLE 6 -# define SL11H_INTMASK_DONE_A 0x01 -# define SL11H_INTMASK_DONE_B 0x02 -# define SL11H_INTMASK_SOFINTR 0x10 -# define SL11H_INTMASK_INSRMV 0x20 /* to/from SE0 */ -# define SL11H_INTMASK_RD 0x40 -# define SL11H_INTMASK_DP 0x80 /* only in INTSTATREG */ -#define SL11S_ADDRESS 7 - -/* 0x08-0x0c are for the B buffer (not in SL11) */ - -#define SL11H_IRQ_STATUS 0x0D /* write to ack */ -#define SL11H_HWREVREG 0x0E /* read */ -# define SL11H_HWRMASK_HWREV 0xF0 -#define SL11H_SOFLOWREG 0x0E /* write */ -#define SL11H_SOFTMRREG 0x0F /* read */ - -/* a write to this register enables SL811HS features. - * HOST flag presumably overrides the chip input signal? - */ -#define SL811HS_CTLREG2 0x0F -# define SL811HS_CTL2MASK_SOF_MASK 0x3F -# define SL811HS_CTL2MASK_DSWAP 0x40 -# define SL811HS_CTL2MASK_HOST 0x80 - -#define SL811HS_CTL2_INIT (SL811HS_CTL2MASK_HOST | 0x2e) - - -/* DATA BUFFERS: registers from 0x10..0xff are for data buffers; - * that's 240 bytes, which we'll split evenly between A and B sides. - * Only ISO can use more than 64 bytes per packet. - * (The SL11S has 0x40..0xff for buffers.) - */ -#define H_MAXPACKET 120 /* bytes in A or B fifos */ - -#define SL11H_DATA_START 0x10 -#define SL811HS_PACKET_BUF(is_a) ((is_a) \ - ? SL11H_DATA_START \ - : (SL11H_DATA_START + H_MAXPACKET)) - -/*-------------------------------------------------------------------------*/ - -#define LOG2_PERIODIC_SIZE 5 /* arbitrary; this matches OHCI */ -#define PERIODIC_SIZE (1 << LOG2_PERIODIC_SIZE) - -struct sl811 { - spinlock_t lock; - void __iomem *addr_reg; - void __iomem *data_reg; - struct sl811_platform_data *board; - struct proc_dir_entry *pde; - - unsigned long stat_insrmv; - unsigned long stat_wake; - unsigned long stat_sof; - unsigned long stat_a; - unsigned long stat_b; - unsigned long stat_lost; - unsigned long stat_overrun; - - /* sw model */ - struct timer_list timer; - struct sl811h_ep *next_periodic; - struct sl811h_ep *next_async; - - struct sl811h_ep *active_a; - unsigned long jiffies_a; - struct sl811h_ep *active_b; - unsigned long jiffies_b; - - u32 port1; - u8 ctrl1, ctrl2, irq_enable; - u16 frame; - - /* async schedule: control, bulk */ - struct list_head async; - - /* periodic schedule: interrupt, iso */ - u16 load[PERIODIC_SIZE]; - struct sl811h_ep *periodic[PERIODIC_SIZE]; - unsigned periodic_count; -}; - -static inline struct sl811 *hcd_to_sl811(struct usb_hcd *hcd) -{ - return (struct sl811 *) (hcd->hcd_priv); -} - -static inline struct usb_hcd *sl811_to_hcd(struct sl811 *sl811) -{ - return container_of((void *) sl811, struct usb_hcd, hcd_priv); -} - -struct sl811h_ep { - struct usb_host_endpoint *hep; - struct usb_device *udev; - - u8 defctrl; - u8 maxpacket; - u8 epnum; - u8 nextpid; - - u16 error_count; - u16 nak_count; - u16 length; /* of current packet */ - - /* periodic schedule */ - u16 period; - u16 branch; - u16 load; - struct sl811h_ep *next; - - /* async schedule */ - struct list_head schedule; -}; - -/*-------------------------------------------------------------------------*/ - -/* These register utilities should work for the SL811S register API too - * NOTE: caller must hold sl811->lock. - */ - -static inline u8 sl811_read(struct sl811 *sl811, int reg) -{ - writeb(reg, sl811->addr_reg); - return readb(sl811->data_reg); -} - -static inline void sl811_write(struct sl811 *sl811, int reg, u8 val) -{ - writeb(reg, sl811->addr_reg); - writeb(val, sl811->data_reg); -} - -static inline void -sl811_write_buf(struct sl811 *sl811, int addr, const void *buf, size_t count) -{ - const u8 *data; - void __iomem *data_reg; - - if (!count) - return; - writeb(addr, sl811->addr_reg); - - data = buf; - data_reg = sl811->data_reg; - do { - writeb(*data++, data_reg); - } while (--count); -} - -static inline void -sl811_read_buf(struct sl811 *sl811, int addr, void *buf, size_t count) -{ - u8 *data; - void __iomem *data_reg; - - if (!count) - return; - writeb(addr, sl811->addr_reg); - - data = buf; - data_reg = sl811->data_reg; - do { - *data++ = readb(data_reg); - } while (--count); -} - -/*-------------------------------------------------------------------------*/ - -#ifdef DEBUG -#define DBG(stuff...) printk(KERN_DEBUG "sl811: " stuff) -#else -#define DBG(stuff...) do{}while(0) -#endif - -#ifdef VERBOSE -# define VDBG DBG -#else -# define VDBG(stuff...) do{}while(0) -#endif - -#ifdef PACKET_TRACE -# define PACKET VDBG -#else -# define PACKET(stuff...) do{}while(0) -#endif - -#define ERR(stuff...) printk(KERN_ERR "sl811: " stuff) -#define WARNING(stuff...) printk(KERN_WARNING "sl811: " stuff) -#define INFO(stuff...) printk(KERN_INFO "sl811: " stuff) - diff --git a/ANDROID_3.4.5/drivers/usb/host/sl811_cs.c b/ANDROID_3.4.5/drivers/usb/host/sl811_cs.c deleted file mode 100644 index 3b6f50ea..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/sl811_cs.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * PCMCIA driver for SL811HS (as found in REX-CFU1U) - * Filename: sl811_cs.c - * Author: Yukio Yamamoto - * - * Port to sl811-hcd and 2.6.x by - * Botond Botyanszki - * Simon Pickering - * - * Last update: 2005-05-12 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -MODULE_AUTHOR("Botond Botyanszki"); -MODULE_DESCRIPTION("REX-CFU1U PCMCIA driver for 2.6"); -MODULE_LICENSE("GPL"); - - -/*====================================================================*/ -/* MACROS */ -/*====================================================================*/ - -#define INFO(args...) printk(KERN_INFO "sl811_cs: " args) - -/*====================================================================*/ -/* VARIABLES */ -/*====================================================================*/ - -typedef struct local_info_t { - struct pcmcia_device *p_dev; -} local_info_t; - -static void sl811_cs_release(struct pcmcia_device * link); - -/*====================================================================*/ - -static void release_platform_dev(struct device * dev) -{ - dev_dbg(dev, "sl811_cs platform_dev release\n"); - dev->parent = NULL; -} - -static struct sl811_platform_data platform_data = { - .potpg = 100, - .power = 50, /* == 100mA */ - // .reset = ... FIXME: invoke CF reset on the card -}; - -static struct resource resources[] = { - [0] = { - .flags = IORESOURCE_IRQ, - }, - [1] = { - // .name = "address", - .flags = IORESOURCE_IO, - }, - [2] = { - // .name = "data", - .flags = IORESOURCE_IO, - }, -}; - -extern struct platform_driver sl811h_driver; - -static struct platform_device platform_dev = { - .id = -1, - .dev = { - .platform_data = &platform_data, - .release = release_platform_dev, - }, - .resource = resources, - .num_resources = ARRAY_SIZE(resources), -}; - -static int sl811_hc_init(struct device *parent, resource_size_t base_addr, - int irq) -{ - if (platform_dev.dev.parent) - return -EBUSY; - platform_dev.dev.parent = parent; - - /* finish seting up the platform device */ - resources[0].start = irq; - - resources[1].start = base_addr; - resources[1].end = base_addr; - - resources[2].start = base_addr + 1; - resources[2].end = base_addr + 1; - - /* The driver core will probe for us. We know sl811-hcd has been - * initialized already because of the link order dependency created - * by referencing "sl811h_driver". - */ - platform_dev.name = sl811h_driver.driver.name; - return platform_device_register(&platform_dev); -} - -/*====================================================================*/ - -static void sl811_cs_detach(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "sl811_cs_detach\n"); - - sl811_cs_release(link); - - /* This points to the parent local_info_t struct */ - kfree(link->priv); -} - -static void sl811_cs_release(struct pcmcia_device * link) -{ - dev_dbg(&link->dev, "sl811_cs_release\n"); - - pcmcia_disable_device(link); - platform_device_unregister(&platform_dev); -} - -static int sl811_cs_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); -} - - -static int sl811_cs_config(struct pcmcia_device *link) -{ - struct device *parent = &link->dev; - int ret; - - dev_dbg(&link->dev, "sl811_cs_config\n"); - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP | - CONF_AUTO_CHECK_VCC | CONF_AUTO_SET_IO; - - if (pcmcia_loop_config(link, sl811_cs_config_check, NULL)) - goto failed; - - /* require an IRQ and two registers */ - if (resource_size(link->resource[0]) < 2) - goto failed; - - if (!link->irq) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - if (sl811_hc_init(parent, link->resource[0]->start, link->irq) - < 0) { -failed: - printk(KERN_WARNING "sl811_cs_config failed\n"); - sl811_cs_release(link); - return -ENODEV; - } - return 0; -} - -static int sl811_cs_probe(struct pcmcia_device *link) -{ - local_info_t *local; - - local = kzalloc(sizeof(local_info_t), GFP_KERNEL); - if (!local) - return -ENOMEM; - local->p_dev = link; - link->priv = local; - - return sl811_cs_config(link); -} - -static const struct pcmcia_device_id sl811_ids[] = { - PCMCIA_DEVICE_MANF_CARD(0xc015, 0x0001), /* RATOC USB HOST CF+ Card */ - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, sl811_ids); - -static struct pcmcia_driver sl811_cs_driver = { - .owner = THIS_MODULE, - .name = "sl811_cs", - .probe = sl811_cs_probe, - .remove = sl811_cs_detach, - .id_table = sl811_ids, -}; - -/*====================================================================*/ - -static int __init init_sl811_cs(void) -{ - return pcmcia_register_driver(&sl811_cs_driver); -} -module_init(init_sl811_cs); - -static void __exit exit_sl811_cs(void) -{ - pcmcia_unregister_driver(&sl811_cs_driver); -} -module_exit(exit_sl811_cs); diff --git a/ANDROID_3.4.5/drivers/usb/host/u132-hcd.c b/ANDROID_3.4.5/drivers/usb/host/u132-hcd.c deleted file mode 100644 index dbbd1ba2..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/u132-hcd.c +++ /dev/null @@ -1,3260 +0,0 @@ -/* -* Host Controller Driver for the Elan Digital Systems U132 adapter -* -* Copyright(C) 2006 Elan Digital Systems Limited -* http://www.elandigitalsystems.com -* -* Author and Maintainer - Tony Olech - Elan Digital Systems -* tony.olech@elandigitalsystems.com -* -* This program is free software;you can redistribute it and/or -* modify it under the terms of the GNU General Public License as -* published by the Free Software Foundation, version 2. -* -* -* This driver was written by Tony Olech(tony.olech@elandigitalsystems.com) -* based on various USB host drivers in the 2.6.15 linux kernel -* with constant reference to the 3rd Edition of Linux Device Drivers -* published by O'Reilly -* -* The U132 adapter is a USB to CardBus adapter specifically designed -* for PC cards that contain an OHCI host controller. Typical PC cards -* are the Orange Mobile 3G Option GlobeTrotter Fusion card. -* -* The U132 adapter will *NOT *work with PC cards that do not contain -* an OHCI controller. A simple way to test whether a PC card has an -* OHCI controller as an interface is to insert the PC card directly -* into a laptop(or desktop) with a CardBus slot and if "lspci" shows -* a new USB controller and "lsusb -v" shows a new OHCI Host Controller -* then there is a good chance that the U132 adapter will support the -* PC card.(you also need the specific client driver for the PC card) -* -* Please inform the Author and Maintainer about any PC cards that -* contain OHCI Host Controller and work when directly connected to -* an embedded CardBus slot but do not work when they are connected -* via an ELAN U132 adapter. -* -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - /* FIXME ohci.h is ONLY for internal use by the OHCI driver. - * If you're going to try stuff like this, you need to split - * out shareable stuff (register declarations?) into its own - * file, maybe name - */ - -#include "ohci.h" -#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR -#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \ - OHCI_INTR_WDH) -MODULE_AUTHOR("Tony Olech - Elan Digital Systems Limited"); -MODULE_DESCRIPTION("U132 USB Host Controller Driver"); -MODULE_LICENSE("GPL"); -#define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444) -INT_MODULE_PARM(testing, 0); -/* Some boards misreport power switching/overcurrent*/ -static bool distrust_firmware = 1; -module_param(distrust_firmware, bool, 0); -MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren" - "t setup"); -static DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait); -/* -* u132_module_lock exists to protect access to global variables -* -*/ -static struct mutex u132_module_lock; -static int u132_exiting; -static int u132_instances; -static struct list_head u132_static_list; -/* -* end of the global variables protected by u132_module_lock -*/ -static struct workqueue_struct *workqueue; -#define MAX_U132_PORTS 7 -#define MAX_U132_ADDRS 128 -#define MAX_U132_UDEVS 4 -#define MAX_U132_ENDPS 100 -#define MAX_U132_RINGS 4 -static const char *cc_to_text[16] = { - "No Error ", - "CRC Error ", - "Bit Stuff ", - "Data Togg ", - "Stall ", - "DevNotResp ", - "PIDCheck ", - "UnExpPID ", - "DataOver ", - "DataUnder ", - "(for hw) ", - "(for hw) ", - "BufferOver ", - "BuffUnder ", - "(for HCD) ", - "(for HCD) " -}; -struct u132_port { - struct u132 *u132; - int reset; - int enable; - int power; - int Status; -}; -struct u132_addr { - u8 address; -}; -struct u132_udev { - struct kref kref; - struct usb_device *usb_device; - u8 enumeration; - u8 udev_number; - u8 usb_addr; - u8 portnumber; - u8 endp_number_in[16]; - u8 endp_number_out[16]; -}; -#define ENDP_QUEUE_SHIFT 3 -#define ENDP_QUEUE_SIZE (1<platform_dev, offsetof(struct \ - ohci_regs, member), 0, data); -#define u132_write_pcimem(u132, member, data) \ - usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \ - ohci_regs, member), 0, data); -static inline struct u132 *udev_to_u132(struct u132_udev *udev) -{ - u8 udev_number = udev->udev_number; - return container_of(udev, struct u132, udev[udev_number]); -} - -static inline struct u132 *hcd_to_u132(struct usb_hcd *hcd) -{ - return (struct u132 *)(hcd->hcd_priv); -} - -static inline struct usb_hcd *u132_to_hcd(struct u132 *u132) -{ - return container_of((void *)u132, struct usb_hcd, hcd_priv); -} - -static inline void u132_disable(struct u132 *u132) -{ - u132_to_hcd(u132)->state = HC_STATE_HALT; -} - - -#define kref_to_u132(d) container_of(d, struct u132, kref) -#define kref_to_u132_endp(d) container_of(d, struct u132_endp, kref) -#define kref_to_u132_udev(d) container_of(d, struct u132_udev, kref) -#include "../misc/usb_u132.h" -static const char hcd_name[] = "u132_hcd"; -#define PORT_C_MASK ((USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | \ - USB_PORT_STAT_C_SUSPEND | USB_PORT_STAT_C_OVERCURRENT | \ - USB_PORT_STAT_C_RESET) << 16) -static void u132_hcd_delete(struct kref *kref) -{ - struct u132 *u132 = kref_to_u132(kref); - struct platform_device *pdev = u132->platform_dev; - struct usb_hcd *hcd = u132_to_hcd(u132); - u132->going += 1; - mutex_lock(&u132_module_lock); - list_del_init(&u132->u132_list); - u132_instances -= 1; - mutex_unlock(&u132_module_lock); - dev_warn(&u132->platform_dev->dev, "FREEING the hcd=%p and thus the u13" - "2=%p going=%d pdev=%p\n", hcd, u132, u132->going, pdev); - usb_put_hcd(hcd); -} - -static inline void u132_u132_put_kref(struct u132 *u132) -{ - kref_put(&u132->kref, u132_hcd_delete); -} - -static inline void u132_u132_init_kref(struct u132 *u132) -{ - kref_init(&u132->kref); -} - -static void u132_udev_delete(struct kref *kref) -{ - struct u132_udev *udev = kref_to_u132_udev(kref); - udev->udev_number = 0; - udev->usb_device = NULL; - udev->usb_addr = 0; - udev->enumeration = 0; -} - -static inline void u132_udev_put_kref(struct u132 *u132, struct u132_udev *udev) -{ - kref_put(&udev->kref, u132_udev_delete); -} - -static inline void u132_udev_get_kref(struct u132 *u132, struct u132_udev *udev) -{ - kref_get(&udev->kref); -} - -static inline void u132_udev_init_kref(struct u132 *u132, - struct u132_udev *udev) -{ - kref_init(&udev->kref); -} - -static inline void u132_ring_put_kref(struct u132 *u132, struct u132_ring *ring) -{ - kref_put(&u132->kref, u132_hcd_delete); -} - -static void u132_ring_requeue_work(struct u132 *u132, struct u132_ring *ring, - unsigned int delta) -{ - if (delta > 0) { - if (queue_delayed_work(workqueue, &ring->scheduler, delta)) - return; - } else if (queue_delayed_work(workqueue, &ring->scheduler, 0)) - return; - kref_put(&u132->kref, u132_hcd_delete); -} - -static void u132_ring_queue_work(struct u132 *u132, struct u132_ring *ring, - unsigned int delta) -{ - kref_get(&u132->kref); - u132_ring_requeue_work(u132, ring, delta); -} - -static void u132_ring_cancel_work(struct u132 *u132, struct u132_ring *ring) -{ - if (cancel_delayed_work(&ring->scheduler)) - kref_put(&u132->kref, u132_hcd_delete); -} - -static void u132_endp_delete(struct kref *kref) -{ - struct u132_endp *endp = kref_to_u132_endp(kref); - struct u132 *u132 = endp->u132; - u8 usb_addr = endp->usb_addr; - u8 usb_endp = endp->usb_endp; - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - u8 endp_number = endp->endp_number; - struct usb_host_endpoint *hep = endp->hep; - struct u132_ring *ring = endp->ring; - struct list_head *head = &endp->endp_ring; - ring->length -= 1; - if (endp == ring->curr_endp) { - if (list_empty(head)) { - ring->curr_endp = NULL; - list_del(head); - } else { - struct u132_endp *next_endp = list_entry(head->next, - struct u132_endp, endp_ring); - ring->curr_endp = next_endp; - list_del(head); - } - } else - list_del(head); - if (endp->input) { - udev->endp_number_in[usb_endp] = 0; - u132_udev_put_kref(u132, udev); - } - if (endp->output) { - udev->endp_number_out[usb_endp] = 0; - u132_udev_put_kref(u132, udev); - } - u132->endp[endp_number - 1] = NULL; - hep->hcpriv = NULL; - kfree(endp); - u132_u132_put_kref(u132); -} - -static inline void u132_endp_put_kref(struct u132 *u132, struct u132_endp *endp) -{ - kref_put(&endp->kref, u132_endp_delete); -} - -static inline void u132_endp_get_kref(struct u132 *u132, struct u132_endp *endp) -{ - kref_get(&endp->kref); -} - -static inline void u132_endp_init_kref(struct u132 *u132, - struct u132_endp *endp) -{ - kref_init(&endp->kref); - kref_get(&u132->kref); -} - -static void u132_endp_queue_work(struct u132 *u132, struct u132_endp *endp, - unsigned int delta) -{ - if (queue_delayed_work(workqueue, &endp->scheduler, delta)) - kref_get(&endp->kref); -} - -static void u132_endp_cancel_work(struct u132 *u132, struct u132_endp *endp) -{ - if (cancel_delayed_work(&endp->scheduler)) - kref_put(&endp->kref, u132_endp_delete); -} - -static inline void u132_monitor_put_kref(struct u132 *u132) -{ - kref_put(&u132->kref, u132_hcd_delete); -} - -static void u132_monitor_queue_work(struct u132 *u132, unsigned int delta) -{ - if (queue_delayed_work(workqueue, &u132->monitor, delta)) - kref_get(&u132->kref); -} - -static void u132_monitor_requeue_work(struct u132 *u132, unsigned int delta) -{ - if (!queue_delayed_work(workqueue, &u132->monitor, delta)) - kref_put(&u132->kref, u132_hcd_delete); -} - -static void u132_monitor_cancel_work(struct u132 *u132) -{ - if (cancel_delayed_work(&u132->monitor)) - kref_put(&u132->kref, u132_hcd_delete); -} - -static int read_roothub_info(struct u132 *u132) -{ - u32 revision; - int retval; - retval = u132_read_pcimem(u132, revision, &revision); - if (retval) { - dev_err(&u132->platform_dev->dev, "error %d accessing device co" - "ntrol\n", retval); - return retval; - } else if ((revision & 0xFF) == 0x10) { - } else if ((revision & 0xFF) == 0x11) { - } else { - dev_err(&u132->platform_dev->dev, "device revision is not valid" - " %08X\n", revision); - return -ENODEV; - } - retval = u132_read_pcimem(u132, control, &u132->hc_control); - if (retval) { - dev_err(&u132->platform_dev->dev, "error %d accessing device co" - "ntrol\n", retval); - return retval; - } - retval = u132_read_pcimem(u132, roothub.status, - &u132->hc_roothub_status); - if (retval) { - dev_err(&u132->platform_dev->dev, "error %d accessing device re" - "g roothub.status\n", retval); - return retval; - } - retval = u132_read_pcimem(u132, roothub.a, &u132->hc_roothub_a); - if (retval) { - dev_err(&u132->platform_dev->dev, "error %d accessing device re" - "g roothub.a\n", retval); - return retval; - } - { - int I = u132->num_ports; - int i = 0; - while (I-- > 0) { - retval = u132_read_pcimem(u132, roothub.portstatus[i], - &u132->hc_roothub_portstatus[i]); - if (retval) { - dev_err(&u132->platform_dev->dev, "error %d acc" - "essing device roothub.portstatus[%d]\n" - , retval, i); - return retval; - } else - i += 1; - } - } - return 0; -} - -static void u132_hcd_monitor_work(struct work_struct *work) -{ - struct u132 *u132 = container_of(work, struct u132, monitor.work); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - u132_monitor_put_kref(u132); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - u132_monitor_put_kref(u132); - return; - } else { - int retval; - mutex_lock(&u132->sw_lock); - retval = read_roothub_info(u132); - if (retval) { - struct usb_hcd *hcd = u132_to_hcd(u132); - u132_disable(u132); - u132->going = 1; - mutex_unlock(&u132->sw_lock); - usb_hc_died(hcd); - ftdi_elan_gone_away(u132->platform_dev); - u132_monitor_put_kref(u132); - return; - } else { - u132_monitor_requeue_work(u132, 500); - mutex_unlock(&u132->sw_lock); - return; - } - } -} - -static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp, - struct urb *urb, int status) -{ - struct u132_ring *ring; - unsigned long irqs; - struct usb_hcd *hcd = u132_to_hcd(u132); - urb->error_count = 0; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - usb_hcd_unlink_urb_from_ep(hcd, urb); - endp->queue_next += 1; - if (ENDP_QUEUE_SIZE > --endp->queue_size) { - endp->active = 0; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - } else { - struct list_head *next = endp->urb_more.next; - struct u132_urbq *urbq = list_entry(next, struct u132_urbq, - urb_more); - list_del(next); - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = - urbq->urb; - endp->active = 0; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - kfree(urbq); - } - mutex_lock(&u132->scheduler_lock); - ring = endp->ring; - ring->in_use = 0; - u132_ring_cancel_work(u132, ring); - u132_ring_queue_work(u132, ring, 0); - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - usb_hcd_giveback_urb(hcd, urb, status); -} - -static void u132_hcd_forget_urb(struct u132 *u132, struct u132_endp *endp, - struct urb *urb, int status) -{ - u132_endp_put_kref(u132, endp); -} - -static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, - struct urb *urb, int status) -{ - unsigned long irqs; - struct usb_hcd *hcd = u132_to_hcd(u132); - urb->error_count = 0; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - usb_hcd_unlink_urb_from_ep(hcd, urb); - endp->queue_next += 1; - if (ENDP_QUEUE_SIZE > --endp->queue_size) { - endp->active = 0; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - } else { - struct list_head *next = endp->urb_more.next; - struct u132_urbq *urbq = list_entry(next, struct u132_urbq, - urb_more); - list_del(next); - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = - urbq->urb; - endp->active = 0; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - kfree(urbq); - } - usb_hcd_giveback_urb(hcd, urb, status); -} - -static inline int edset_input(struct u132 *u132, struct u132_ring *ring, - struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - return usb_ftdi_elan_edset_input(u132->platform_dev, ring->number, endp, - urb, address, endp->usb_endp, toggle_bits, callback); -} - -static inline int edset_setup(struct u132 *u132, struct u132_ring *ring, - struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - return usb_ftdi_elan_edset_setup(u132->platform_dev, ring->number, endp, - urb, address, endp->usb_endp, toggle_bits, callback); -} - -static inline int edset_single(struct u132 *u132, struct u132_ring *ring, - struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - return usb_ftdi_elan_edset_single(u132->platform_dev, ring->number, - endp, urb, address, endp->usb_endp, toggle_bits, callback); -} - -static inline int edset_output(struct u132 *u132, struct u132_ring *ring, - struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - return usb_ftdi_elan_edset_output(u132->platform_dev, ring->number, - endp, urb, address, endp->usb_endp, toggle_bits, callback); -} - - -/* -* must not LOCK sw_lock -* -*/ -static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - struct u132_ring *ring = endp->ring; - u8 *u = urb->transfer_buffer + urb->actual_length; - u8 *b = buf; - int L = len; - - while (L-- > 0) - *u++ = *b++; - - urb->actual_length += len; - if ((condition_code == TD_CC_NOERROR) && - (urb->transfer_buffer_length > urb->actual_length)) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - if (urb->actual_length > 0) { - int retval; - mutex_unlock(&u132->scheduler_lock); - retval = edset_single(u132, ring, endp, urb, - address, endp->toggle_bits, - u132_hcd_interrupt_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, - retval); - } else { - ring->in_use = 0; - endp->active = 0; - endp->jiffies = jiffies + - msecs_to_jiffies(urb->interval); - u132_ring_cancel_work(u132, ring); - u132_ring_queue_work(u132, ring, 0); - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - } - return; - } else if ((condition_code == TD_DATAUNDERRUN) && - ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { - if (condition_code == TD_CC_NOERROR) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, - 0, 1 & toggle_bits); - } else if (condition_code == TD_CC_STALL) { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, endp->usb_endp, - 0, 0); - } else { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, endp->usb_endp, - 0, 0); - dev_err(&u132->platform_dev->dev, "urb=%p givin" - "g back INTERRUPT %s\n", urb, - cc_to_text[condition_code]); - } - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - struct u132_ring *ring = endp->ring; - urb->actual_length += len; - endp->toggle_bits = toggle_bits; - if (urb->transfer_buffer_length > urb->actual_length) { - int retval; - mutex_unlock(&u132->scheduler_lock); - retval = edset_output(u132, ring, endp, urb, address, - endp->toggle_bits, u132_hcd_bulk_output_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - struct u132_ring *ring = endp->ring; - u8 *u = urb->transfer_buffer + urb->actual_length; - u8 *b = buf; - int L = len; - - while (L-- > 0) - *u++ = *b++; - - urb->actual_length += len; - if ((condition_code == TD_CC_NOERROR) && - (urb->transfer_buffer_length > urb->actual_length)) { - int retval; - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_input(u132->platform_dev, - ring->number, endp, urb, address, - endp->usb_endp, endp->toggle_bits, - u132_hcd_bulk_input_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else if (condition_code == TD_CC_NOERROR) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } else if ((condition_code == TD_DATAUNDERRUN) && - ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else if (condition_code == TD_DATAUNDERRUN) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - dev_warn(&u132->platform_dev->dev, "urb=%p(SHORT NOT OK" - ") giving back BULK IN %s\n", urb, - cc_to_text[condition_code]); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else if (condition_code == TD_CC_STALL) { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } else { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0); - dev_err(&u132->platform_dev->dev, "urb=%p giving back B" - "ULK IN code=%d %s\n", urb, condition_code, - cc_to_text[condition_code]); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - struct u132_ring *ring = endp->ring; - u8 *u = urb->transfer_buffer; - u8 *b = buf; - int L = len; - - while (L-- > 0) - *u++ = *b++; - - urb->actual_length = len; - if ((condition_code == TD_CC_NOERROR) || ((condition_code == - TD_DATAUNDERRUN) && ((urb->transfer_flags & - URB_SHORT_NOT_OK) == 0))) { - int retval; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_empty(u132->platform_dev, - ring->number, endp, urb, address, - endp->usb_endp, 0x3, - u132_hcd_configure_empty_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else if (condition_code == TD_CC_STALL) { - mutex_unlock(&u132->scheduler_lock); - dev_warn(&u132->platform_dev->dev, "giving back SETUP I" - "NPUT STALL urb %p\n", urb); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } else { - mutex_unlock(&u132->scheduler_lock); - dev_err(&u132->platform_dev->dev, "giving back SETUP IN" - "PUT %s urb %p\n", cc_to_text[condition_code], - urb); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - if (usb_pipein(urb->pipe)) { - int retval; - struct u132_ring *ring = endp->ring; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_input(u132->platform_dev, - ring->number, endp, urb, address, - endp->usb_endp, 0, - u132_hcd_configure_input_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - int retval; - struct u132_ring *ring = endp->ring; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_input(u132->platform_dev, - ring->number, endp, urb, address, - endp->usb_endp, 0, - u132_hcd_configure_empty_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb, - u8 *buf, int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - u132->addr[0].address = 0; - endp->usb_addr = udev->usb_addr; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb, - u8 *buf, int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - int retval; - struct u132_ring *ring = endp->ring; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_input(u132->platform_dev, - ring->number, endp, urb, 0, endp->usb_endp, 0, - u132_hcd_enumeration_empty_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - int retval; - struct u132_ring *ring = endp->ring; - u8 *u = urb->transfer_buffer; - u8 *b = buf; - int L = len; - - while (L-- > 0) - *u++ = *b++; - - urb->actual_length = len; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_empty(u132->platform_dev, - ring->number, endp, urb, address, endp->usb_endp, 0x3, - u132_hcd_initial_empty_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - int retval; - struct u132_ring *ring = endp->ring; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_input(u132->platform_dev, - ring->number, endp, urb, address, endp->usb_endp, 0, - u132_hcd_initial_input_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -/* -* this work function is only executed from the work queue -* -*/ -static void u132_hcd_ring_work_scheduler(struct work_struct *work) -{ - struct u132_ring *ring = - container_of(work, struct u132_ring, scheduler.work); - struct u132 *u132 = ring->u132; - mutex_lock(&u132->scheduler_lock); - if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } else if (ring->curr_endp) { - struct u132_endp *last_endp = ring->curr_endp; - struct list_head *scan; - struct list_head *head = &last_endp->endp_ring; - unsigned long wakeup = 0; - list_for_each(scan, head) { - struct u132_endp *endp = list_entry(scan, - struct u132_endp, endp_ring); - if (endp->queue_next == endp->queue_last) { - } else if ((endp->delayed == 0) - || time_after_eq(jiffies, endp->jiffies)) { - ring->curr_endp = endp; - u132_endp_cancel_work(u132, last_endp); - u132_endp_queue_work(u132, last_endp, 0); - mutex_unlock(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } else { - unsigned long delta = endp->jiffies - jiffies; - if (delta > wakeup) - wakeup = delta; - } - } - if (last_endp->queue_next == last_endp->queue_last) { - } else if ((last_endp->delayed == 0) || time_after_eq(jiffies, - last_endp->jiffies)) { - u132_endp_cancel_work(u132, last_endp); - u132_endp_queue_work(u132, last_endp, 0); - mutex_unlock(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } else { - unsigned long delta = last_endp->jiffies - jiffies; - if (delta > wakeup) - wakeup = delta; - } - if (wakeup > 0) { - u132_ring_requeue_work(u132, ring, wakeup); - mutex_unlock(&u132->scheduler_lock); - return; - } else { - mutex_unlock(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } - } else { - mutex_unlock(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } -} - -static void u132_hcd_endp_work_scheduler(struct work_struct *work) -{ - struct u132_ring *ring; - struct u132_endp *endp = - container_of(work, struct u132_endp, scheduler.work); - struct u132 *u132 = endp->u132; - mutex_lock(&u132->scheduler_lock); - ring = endp->ring; - if (endp->edset_flush) { - endp->edset_flush = 0; - if (endp->dequeueing) - usb_ftdi_elan_edset_flush(u132->platform_dev, - ring->number, endp); - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (endp->active) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (endp->queue_next == endp->queue_last) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (endp->pipetype == PIPE_INTERRUPT) { - u8 address = u132->addr[endp->usb_addr].address; - if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else { - int retval; - struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_single(u132, ring, endp, urb, address, - endp->toggle_bits, u132_hcd_interrupt_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } - } else if (endp->pipetype == PIPE_CONTROL) { - u8 address = u132->addr[endp->usb_addr].address; - if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (address == 0) { - int retval; - struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_setup(u132, ring, endp, urb, address, - 0x2, u132_hcd_initial_setup_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else if (endp->usb_addr == 0) { - int retval; - struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_setup(u132, ring, endp, urb, 0, 0x2, - u132_hcd_enumeration_address_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - int retval; - struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_next]; - address = u132->addr[endp->usb_addr].address; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_setup(u132, ring, endp, urb, address, - 0x2, u132_hcd_configure_setup_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } - } else { - if (endp->input) { - u8 address = u132->addr[endp->usb_addr].address; - if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else { - int retval; - struct urb *urb = endp->urb_list[ - ENDP_QUEUE_MASK & endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_input(u132, ring, endp, urb, - address, endp->toggle_bits, - u132_hcd_bulk_input_recv); - if (retval == 0) { - } else - u132_hcd_giveback_urb(u132, endp, urb, - retval); - return; - } - } else { /* output pipe */ - u8 address = u132->addr[endp->usb_addr].address; - if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else { - int retval; - struct urb *urb = endp->urb_list[ - ENDP_QUEUE_MASK & endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_output(u132, ring, endp, urb, - address, endp->toggle_bits, - u132_hcd_bulk_output_sent); - if (retval == 0) { - } else - u132_hcd_giveback_urb(u132, endp, urb, - retval); - return; - } - } - } -} -#ifdef CONFIG_PM - -static void port_power(struct u132 *u132, int pn, int is_on) -{ - u132->port[pn].power = is_on; -} - -#endif - -static void u132_power(struct u132 *u132, int is_on) -{ - struct usb_hcd *hcd = u132_to_hcd(u132) - ; /* hub is inactive unless the port is powered */ - if (is_on) { - if (u132->power) - return; - u132->power = 1; - } else { - u132->power = 0; - hcd->state = HC_STATE_HALT; - } -} - -static int u132_periodic_reinit(struct u132 *u132) -{ - int retval; - u32 fi = u132->hc_fminterval & 0x03fff; - u32 fit; - u32 fminterval; - retval = u132_read_pcimem(u132, fminterval, &fminterval); - if (retval) - return retval; - fit = fminterval & FIT; - retval = u132_write_pcimem(u132, fminterval, - (fit ^ FIT) | u132->hc_fminterval); - if (retval) - return retval; - retval = u132_write_pcimem(u132, periodicstart, - ((9 * fi) / 10) & 0x3fff); - if (retval) - return retval; - return 0; -} - -static char *hcfs2string(int state) -{ - switch (state) { - case OHCI_USB_RESET: - return "reset"; - case OHCI_USB_RESUME: - return "resume"; - case OHCI_USB_OPER: - return "operational"; - case OHCI_USB_SUSPEND: - return "suspend"; - } - return "?"; -} - -static int u132_init(struct u132 *u132) -{ - int retval; - u32 control; - u132_disable(u132); - u132->next_statechange = jiffies; - retval = u132_write_pcimem(u132, intrdisable, OHCI_INTR_MIE); - if (retval) - return retval; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - if (u132->num_ports == 0) { - u32 rh_a = -1; - retval = u132_read_pcimem(u132, roothub.a, &rh_a); - if (retval) - return retval; - u132->num_ports = rh_a & RH_A_NDP; - retval = read_roothub_info(u132); - if (retval) - return retval; - } - if (u132->num_ports > MAX_U132_PORTS) - return -EINVAL; - - return 0; -} - - -/* Start an OHCI controller, set the BUS operational -* resets USB and controller -* enable interrupts -*/ -static int u132_run(struct u132 *u132) -{ - int retval; - u32 control; - u32 status; - u32 fminterval; - u32 periodicstart; - u32 cmdstatus; - u32 roothub_a; - int mask = OHCI_INTR_INIT; - int first = u132->hc_fminterval == 0; - int sleep_time = 0; - int reset_timeout = 30; /* ... allow extra time */ - u132_disable(u132); - if (first) { - u32 temp; - retval = u132_read_pcimem(u132, fminterval, &temp); - if (retval) - return retval; - u132->hc_fminterval = temp & 0x3fff; - u132->hc_fminterval |= FSMP(u132->hc_fminterval) << 16; - } - retval = u132_read_pcimem(u132, control, &u132->hc_control); - if (retval) - return retval; - dev_info(&u132->platform_dev->dev, "resetting from state '%s', control " - "= %08X\n", hcfs2string(u132->hc_control & OHCI_CTRL_HCFS), - u132->hc_control); - switch (u132->hc_control & OHCI_CTRL_HCFS) { - case OHCI_USB_OPER: - sleep_time = 0; - break; - case OHCI_USB_SUSPEND: - case OHCI_USB_RESUME: - u132->hc_control &= OHCI_CTRL_RWC; - u132->hc_control |= OHCI_USB_RESUME; - sleep_time = 10; - break; - default: - u132->hc_control &= OHCI_CTRL_RWC; - u132->hc_control |= OHCI_USB_RESET; - sleep_time = 50; - break; - } - retval = u132_write_pcimem(u132, control, u132->hc_control); - if (retval) - return retval; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - msleep(sleep_time); - retval = u132_read_pcimem(u132, roothub.a, &roothub_a); - if (retval) - return retval; - if (!(roothub_a & RH_A_NPS)) { - int temp; /* power down each port */ - for (temp = 0; temp < u132->num_ports; temp++) { - retval = u132_write_pcimem(u132, - roothub.portstatus[temp], RH_PS_LSDA); - if (retval) - return retval; - } - } - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; -retry: - retval = u132_read_pcimem(u132, cmdstatus, &status); - if (retval) - return retval; - retval = u132_write_pcimem(u132, cmdstatus, OHCI_HCR); - if (retval) - return retval; -extra: { - retval = u132_read_pcimem(u132, cmdstatus, &status); - if (retval) - return retval; - if (0 != (status & OHCI_HCR)) { - if (--reset_timeout == 0) { - dev_err(&u132->platform_dev->dev, "USB HC reset" - " timed out!\n"); - return -ENODEV; - } else { - msleep(5); - goto extra; - } - } - } - if (u132->flags & OHCI_QUIRK_INITRESET) { - retval = u132_write_pcimem(u132, control, u132->hc_control); - if (retval) - return retval; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - } - retval = u132_write_pcimem(u132, ed_controlhead, 0x00000000); - if (retval) - return retval; - retval = u132_write_pcimem(u132, ed_bulkhead, 0x11000000); - if (retval) - return retval; - retval = u132_write_pcimem(u132, hcca, 0x00000000); - if (retval) - return retval; - retval = u132_periodic_reinit(u132); - if (retval) - return retval; - retval = u132_read_pcimem(u132, fminterval, &fminterval); - if (retval) - return retval; - retval = u132_read_pcimem(u132, periodicstart, &periodicstart); - if (retval) - return retval; - if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) { - if (!(u132->flags & OHCI_QUIRK_INITRESET)) { - u132->flags |= OHCI_QUIRK_INITRESET; - goto retry; - } else - dev_err(&u132->platform_dev->dev, "init err(%08x %04x)" - "\n", fminterval, periodicstart); - } /* start controller operations */ - u132->hc_control &= OHCI_CTRL_RWC; - u132->hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER; - retval = u132_write_pcimem(u132, control, u132->hc_control); - if (retval) - return retval; - retval = u132_write_pcimem(u132, cmdstatus, OHCI_BLF); - if (retval) - return retval; - retval = u132_read_pcimem(u132, cmdstatus, &cmdstatus); - if (retval) - return retval; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - u132_to_hcd(u132)->state = HC_STATE_RUNNING; - retval = u132_write_pcimem(u132, roothub.status, RH_HS_DRWE); - if (retval) - return retval; - retval = u132_write_pcimem(u132, intrstatus, mask); - if (retval) - return retval; - retval = u132_write_pcimem(u132, intrdisable, - OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO | - OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH | - OHCI_INTR_SO); - if (retval) - return retval; /* handle root hub init quirks ... */ - retval = u132_read_pcimem(u132, roothub.a, &roothub_a); - if (retval) - return retval; - roothub_a &= ~(RH_A_PSM | RH_A_OCPM); - if (u132->flags & OHCI_QUIRK_SUPERIO) { - roothub_a |= RH_A_NOCP; - roothub_a &= ~(RH_A_POTPGT | RH_A_NPS); - retval = u132_write_pcimem(u132, roothub.a, roothub_a); - if (retval) - return retval; - } else if ((u132->flags & OHCI_QUIRK_AMD756) || distrust_firmware) { - roothub_a |= RH_A_NPS; - retval = u132_write_pcimem(u132, roothub.a, roothub_a); - if (retval) - return retval; - } - retval = u132_write_pcimem(u132, roothub.status, RH_HS_LPSC); - if (retval) - return retval; - retval = u132_write_pcimem(u132, roothub.b, - (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM); - if (retval) - return retval; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - mdelay((roothub_a >> 23) & 0x1fe); - u132_to_hcd(u132)->state = HC_STATE_RUNNING; - return 0; -} - -static void u132_hcd_stop(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p) has b" - "een removed %d\n", u132, hcd, u132->going); - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov" - "ed\n", hcd); - } else { - mutex_lock(&u132->sw_lock); - msleep(100); - u132_power(u132, 0); - mutex_unlock(&u132->sw_lock); - } -} - -static int u132_hcd_start(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else if (hcd->self.controller) { - int retval; - struct platform_device *pdev = - to_platform_device(hcd->self.controller); - u16 vendor = ((struct u132_platform_data *) - (pdev->dev.platform_data))->vendor; - u16 device = ((struct u132_platform_data *) - (pdev->dev.platform_data))->device; - mutex_lock(&u132->sw_lock); - msleep(10); - if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) { - u132->flags = OHCI_QUIRK_AMD756; - } else if (vendor == PCI_VENDOR_ID_OPTI && device == 0xc861) { - dev_err(&u132->platform_dev->dev, "WARNING: OPTi workar" - "ounds unavailable\n"); - } else if (vendor == PCI_VENDOR_ID_COMPAQ && device == 0xa0f8) - u132->flags |= OHCI_QUIRK_ZFMICRO; - retval = u132_run(u132); - if (retval) { - u132_disable(u132); - u132->going = 1; - } - msleep(100); - mutex_unlock(&u132->sw_lock); - return retval; - } else { - dev_err(&u132->platform_dev->dev, "platform_device missing\n"); - return -ENODEV; - } -} - -static int u132_hcd_reset(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - int retval; - mutex_lock(&u132->sw_lock); - retval = u132_init(u132); - if (retval) { - u132_disable(u132); - u132->going = 1; - } - mutex_unlock(&u132->sw_lock); - return retval; - } -} - -static int create_endpoint_and_queue_int(struct u132 *u132, - struct u132_udev *udev, struct urb *urb, - struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address, - gfp_t mem_flags) -{ - struct u132_ring *ring; - unsigned long irqs; - int rc; - u8 endp_number; - struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); - - if (!endp) - return -ENOMEM; - - spin_lock_init(&endp->queue_lock.slock); - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); - if (rc) { - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - kfree(endp); - return rc; - } - - endp_number = ++u132->num_endpoints; - urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; - INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - INIT_LIST_HEAD(&endp->urb_more); - ring = endp->ring = &u132->ring[0]; - if (ring->curr_endp) { - list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring); - } else { - INIT_LIST_HEAD(&endp->endp_ring); - ring->curr_endp = endp; - } - ring->length += 1; - endp->dequeueing = 0; - endp->edset_flush = 0; - endp->active = 0; - endp->delayed = 0; - endp->endp_number = endp_number; - endp->u132 = u132; - endp->hep = urb->ep; - endp->pipetype = usb_pipetype(urb->pipe); - u132_endp_init_kref(u132, endp); - if (usb_pipein(urb->pipe)) { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, usb_endp, 0, 0); - endp->input = 1; - endp->output = 0; - udev->endp_number_in[usb_endp] = endp_number; - u132_udev_get_kref(u132, udev); - } else { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, usb_endp, 1, 0); - endp->input = 0; - endp->output = 1; - udev->endp_number_out[usb_endp] = endp_number; - u132_udev_get_kref(u132, udev); - } - urb->hcpriv = u132; - endp->delayed = 1; - endp->jiffies = jiffies + msecs_to_jiffies(urb->interval); - endp->udev_number = address; - endp->usb_addr = usb_addr; - endp->usb_endp = usb_endp; - endp->queue_size = 1; - endp->queue_last = 0; - endp->queue_next = 0; - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_endp_queue_work(u132, endp, msecs_to_jiffies(urb->interval)); - return 0; -} - -static int queue_int_on_old_endpoint(struct u132 *u132, - struct u132_udev *udev, struct urb *urb, - struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, - u8 usb_endp, u8 address) -{ - urb->hcpriv = u132; - endp->delayed = 1; - endp->jiffies = jiffies + msecs_to_jiffies(urb->interval); - if (endp->queue_size++ < ENDP_QUEUE_SIZE) { - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - } else { - struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq), - GFP_ATOMIC); - if (urbq == NULL) { - endp->queue_size -= 1; - return -ENOMEM; - } else { - list_add_tail(&urbq->urb_more, &endp->urb_more); - urbq->urb = urb; - } - } - return 0; -} - -static int create_endpoint_and_queue_bulk(struct u132 *u132, - struct u132_udev *udev, struct urb *urb, - struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address, - gfp_t mem_flags) -{ - int ring_number; - struct u132_ring *ring; - unsigned long irqs; - int rc; - u8 endp_number; - struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); - - if (!endp) - return -ENOMEM; - - spin_lock_init(&endp->queue_lock.slock); - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); - if (rc) { - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - kfree(endp); - return rc; - } - - endp_number = ++u132->num_endpoints; - urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; - INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - INIT_LIST_HEAD(&endp->urb_more); - endp->dequeueing = 0; - endp->edset_flush = 0; - endp->active = 0; - endp->delayed = 0; - endp->endp_number = endp_number; - endp->u132 = u132; - endp->hep = urb->ep; - endp->pipetype = usb_pipetype(urb->pipe); - u132_endp_init_kref(u132, endp); - if (usb_pipein(urb->pipe)) { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, usb_endp, 0, 0); - ring_number = 3; - endp->input = 1; - endp->output = 0; - udev->endp_number_in[usb_endp] = endp_number; - u132_udev_get_kref(u132, udev); - } else { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, usb_endp, 1, 0); - ring_number = 2; - endp->input = 0; - endp->output = 1; - udev->endp_number_out[usb_endp] = endp_number; - u132_udev_get_kref(u132, udev); - } - ring = endp->ring = &u132->ring[ring_number - 1]; - if (ring->curr_endp) { - list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring); - } else { - INIT_LIST_HEAD(&endp->endp_ring); - ring->curr_endp = endp; - } - ring->length += 1; - urb->hcpriv = u132; - endp->udev_number = address; - endp->usb_addr = usb_addr; - endp->usb_endp = usb_endp; - endp->queue_size = 1; - endp->queue_last = 0; - endp->queue_next = 0; - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_endp_queue_work(u132, endp, 0); - return 0; -} - -static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, - struct urb *urb, - struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, - u8 usb_endp, u8 address) -{ - urb->hcpriv = u132; - if (endp->queue_size++ < ENDP_QUEUE_SIZE) { - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - } else { - struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq), - GFP_ATOMIC); - if (urbq == NULL) { - endp->queue_size -= 1; - return -ENOMEM; - } else { - list_add_tail(&urbq->urb_more, &endp->urb_more); - urbq->urb = urb; - } - } - return 0; -} - -static int create_endpoint_and_queue_control(struct u132 *u132, - struct urb *urb, - struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, - gfp_t mem_flags) -{ - struct u132_ring *ring; - unsigned long irqs; - int rc; - u8 endp_number; - struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); - - if (!endp) - return -ENOMEM; - - spin_lock_init(&endp->queue_lock.slock); - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); - if (rc) { - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - kfree(endp); - return rc; - } - - endp_number = ++u132->num_endpoints; - urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; - INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - INIT_LIST_HEAD(&endp->urb_more); - ring = endp->ring = &u132->ring[0]; - if (ring->curr_endp) { - list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring); - } else { - INIT_LIST_HEAD(&endp->endp_ring); - ring->curr_endp = endp; - } - ring->length += 1; - endp->dequeueing = 0; - endp->edset_flush = 0; - endp->active = 0; - endp->delayed = 0; - endp->endp_number = endp_number; - endp->u132 = u132; - endp->hep = urb->ep; - u132_endp_init_kref(u132, endp); - u132_endp_get_kref(u132, endp); - if (usb_addr == 0) { - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - endp->udev_number = address; - endp->usb_addr = usb_addr; - endp->usb_endp = usb_endp; - endp->input = 1; - endp->output = 1; - endp->pipetype = usb_pipetype(urb->pipe); - u132_udev_init_kref(u132, udev); - u132_udev_get_kref(u132, udev); - udev->endp_number_in[usb_endp] = endp_number; - udev->endp_number_out[usb_endp] = endp_number; - urb->hcpriv = u132; - endp->queue_size = 1; - endp->queue_last = 0; - endp->queue_next = 0; - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_endp_queue_work(u132, endp, 0); - return 0; - } else { /*(usb_addr > 0) */ - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - endp->udev_number = address; - endp->usb_addr = usb_addr; - endp->usb_endp = usb_endp; - endp->input = 1; - endp->output = 1; - endp->pipetype = usb_pipetype(urb->pipe); - u132_udev_get_kref(u132, udev); - udev->enumeration = 2; - udev->endp_number_in[usb_endp] = endp_number; - udev->endp_number_out[usb_endp] = endp_number; - urb->hcpriv = u132; - endp->queue_size = 1; - endp->queue_last = 0; - endp->queue_next = 0; - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_endp_queue_work(u132, endp, 0); - return 0; - } -} - -static int queue_control_on_old_endpoint(struct u132 *u132, - struct urb *urb, - struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, - u8 usb_endp) -{ - if (usb_addr == 0) { - if (usb_pipein(urb->pipe)) { - urb->hcpriv = u132; - if (endp->queue_size++ < ENDP_QUEUE_SIZE) { - endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_last++] = urb; - } else { - struct u132_urbq *urbq = - kmalloc(sizeof(struct u132_urbq), - GFP_ATOMIC); - if (urbq == NULL) { - endp->queue_size -= 1; - return -ENOMEM; - } else { - list_add_tail(&urbq->urb_more, - &endp->urb_more); - urbq->urb = urb; - } - } - return 0; - } else { /* usb_pipeout(urb->pipe) */ - struct u132_addr *addr = &u132->addr[usb_dev->devnum]; - int I = MAX_U132_UDEVS; - int i = 0; - while (--I > 0) { - struct u132_udev *udev = &u132->udev[++i]; - if (udev->usb_device) { - continue; - } else { - udev->enumeration = 1; - u132->addr[0].address = i; - endp->udev_number = i; - udev->udev_number = i; - udev->usb_addr = usb_dev->devnum; - u132_udev_init_kref(u132, udev); - udev->endp_number_in[usb_endp] = - endp->endp_number; - u132_udev_get_kref(u132, udev); - udev->endp_number_out[usb_endp] = - endp->endp_number; - udev->usb_device = usb_dev; - ((u8 *) (urb->setup_packet))[2] = - addr->address = i; - u132_udev_get_kref(u132, udev); - break; - } - } - if (I == 0) { - dev_err(&u132->platform_dev->dev, "run out of d" - "evice space\n"); - return -EINVAL; - } - urb->hcpriv = u132; - if (endp->queue_size++ < ENDP_QUEUE_SIZE) { - endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_last++] = urb; - } else { - struct u132_urbq *urbq = - kmalloc(sizeof(struct u132_urbq), - GFP_ATOMIC); - if (urbq == NULL) { - endp->queue_size -= 1; - return -ENOMEM; - } else { - list_add_tail(&urbq->urb_more, - &endp->urb_more); - urbq->urb = urb; - } - } - return 0; - } - } else { /*(usb_addr > 0) */ - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - urb->hcpriv = u132; - if (udev->enumeration != 2) - udev->enumeration = 2; - if (endp->queue_size++ < ENDP_QUEUE_SIZE) { - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = - urb; - } else { - struct u132_urbq *urbq = - kmalloc(sizeof(struct u132_urbq), GFP_ATOMIC); - if (urbq == NULL) { - endp->queue_size -= 1; - return -ENOMEM; - } else { - list_add_tail(&urbq->urb_more, &endp->urb_more); - urbq->urb = urb; - } - } - return 0; - } -} - -static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, - gfp_t mem_flags) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (irqs_disabled()) { - if (__GFP_WAIT & mem_flags) { - printk(KERN_ERR "invalid context for function that migh" - "t sleep\n"); - return -EINVAL; - } - } - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - return -ESHUTDOWN; - } else { - u8 usb_addr = usb_pipedevice(urb->pipe); - u8 usb_endp = usb_pipeendpoint(urb->pipe); - struct usb_device *usb_dev = urb->dev; - if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - struct u132_endp *endp = urb->ep->hcpriv; - urb->actual_length = 0; - if (endp) { - unsigned long irqs; - int retval; - spin_lock_irqsave(&endp->queue_lock.slock, - irqs); - retval = usb_hcd_link_urb_to_ep(hcd, urb); - if (retval == 0) { - retval = queue_int_on_old_endpoint( - u132, udev, urb, - usb_dev, endp, - usb_addr, usb_endp, - address); - if (retval) - usb_hcd_unlink_urb_from_ep( - hcd, urb); - } - spin_unlock_irqrestore(&endp->queue_lock.slock, - irqs); - if (retval) { - return retval; - } else { - u132_endp_queue_work(u132, endp, - msecs_to_jiffies(urb->interval)) - ; - return 0; - } - } else if (u132->num_endpoints == MAX_U132_ENDPS) { - return -EINVAL; - } else { /*(endp == NULL) */ - return create_endpoint_and_queue_int(u132, udev, - urb, usb_dev, usb_addr, - usb_endp, address, mem_flags); - } - } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { - dev_err(&u132->platform_dev->dev, "the hardware does no" - "t support PIPE_ISOCHRONOUS\n"); - return -EINVAL; - } else if (usb_pipetype(urb->pipe) == PIPE_BULK) { - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - struct u132_endp *endp = urb->ep->hcpriv; - urb->actual_length = 0; - if (endp) { - unsigned long irqs; - int retval; - spin_lock_irqsave(&endp->queue_lock.slock, - irqs); - retval = usb_hcd_link_urb_to_ep(hcd, urb); - if (retval == 0) { - retval = queue_bulk_on_old_endpoint( - u132, udev, urb, - usb_dev, endp, - usb_addr, usb_endp, - address); - if (retval) - usb_hcd_unlink_urb_from_ep( - hcd, urb); - } - spin_unlock_irqrestore(&endp->queue_lock.slock, - irqs); - if (retval) { - return retval; - } else { - u132_endp_queue_work(u132, endp, 0); - return 0; - } - } else if (u132->num_endpoints == MAX_U132_ENDPS) { - return -EINVAL; - } else - return create_endpoint_and_queue_bulk(u132, - udev, urb, usb_dev, usb_addr, - usb_endp, address, mem_flags); - } else { - struct u132_endp *endp = urb->ep->hcpriv; - u16 urb_size = 8; - u8 *b = urb->setup_packet; - int i = 0; - char data[30 * 3 + 4]; - char *d = data; - int m = (sizeof(data) - 1) / 3; - int l = 0; - data[0] = 0; - while (urb_size-- > 0) { - if (i > m) { - } else if (i++ < m) { - int w = sprintf(d, " %02X", *b++); - d += w; - l += w; - } else - d += sprintf(d, " .."); - } - if (endp) { - unsigned long irqs; - int retval; - spin_lock_irqsave(&endp->queue_lock.slock, - irqs); - retval = usb_hcd_link_urb_to_ep(hcd, urb); - if (retval == 0) { - retval = queue_control_on_old_endpoint( - u132, urb, usb_dev, - endp, usb_addr, - usb_endp); - if (retval) - usb_hcd_unlink_urb_from_ep( - hcd, urb); - } - spin_unlock_irqrestore(&endp->queue_lock.slock, - irqs); - if (retval) { - return retval; - } else { - u132_endp_queue_work(u132, endp, 0); - return 0; - } - } else if (u132->num_endpoints == MAX_U132_ENDPS) { - return -EINVAL; - } else - return create_endpoint_and_queue_control(u132, - urb, usb_dev, usb_addr, usb_endp, - mem_flags); - } - } -} - -static int dequeue_from_overflow_chain(struct u132 *u132, - struct u132_endp *endp, struct urb *urb) -{ - struct list_head *scan; - struct list_head *head = &endp->urb_more; - list_for_each(scan, head) { - struct u132_urbq *urbq = list_entry(scan, struct u132_urbq, - urb_more); - if (urbq->urb == urb) { - struct usb_hcd *hcd = u132_to_hcd(u132); - list_del(scan); - endp->queue_size -= 1; - urb->error_count = 0; - usb_hcd_giveback_urb(hcd, urb, 0); - return 0; - } else - continue; - } - dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]=%p ring" - "[%d] %c%c usb_endp=%d usb_addr=%d size=%d next=%04X last=%04X" - "\n", urb, endp->endp_number, endp, endp->ring->number, - endp->input ? 'I' : ' ', endp->output ? 'O' : ' ', - endp->usb_endp, endp->usb_addr, endp->queue_size, - endp->queue_next, endp->queue_last); - return -EINVAL; -} - -static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, - struct urb *urb, int status) -{ - unsigned long irqs; - int rc; - - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - rc = usb_hcd_check_unlink_urb(u132_to_hcd(u132), urb, status); - if (rc) { - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - return rc; - } - if (endp->queue_size == 0) { - dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]" - "=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb, - endp->endp_number, endp, endp->ring->number, - endp->input ? 'I' : ' ', endp->output ? 'O' : ' ', - endp->usb_endp, endp->usb_addr); - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - return -EINVAL; - } - if (urb == endp->urb_list[ENDP_QUEUE_MASK & endp->queue_next]) { - if (endp->active) { - endp->dequeueing = 1; - endp->edset_flush = 1; - u132_endp_queue_work(u132, endp, 0); - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - return 0; - } else { - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_hcd_abandon_urb(u132, endp, urb, status); - return 0; - } - } else { - u16 queue_list = 0; - u16 queue_size = endp->queue_size; - u16 queue_scan = endp->queue_next; - struct urb **urb_slot = NULL; - while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) { - if (urb == endp->urb_list[ENDP_QUEUE_MASK & - ++queue_scan]) { - urb_slot = &endp->urb_list[ENDP_QUEUE_MASK & - queue_scan]; - break; - } else - continue; - } - while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) { - *urb_slot = endp->urb_list[ENDP_QUEUE_MASK & - ++queue_scan]; - urb_slot = &endp->urb_list[ENDP_QUEUE_MASK & - queue_scan]; - } - if (urb_slot) { - struct usb_hcd *hcd = u132_to_hcd(u132); - - usb_hcd_unlink_urb_from_ep(hcd, urb); - endp->queue_size -= 1; - if (list_empty(&endp->urb_more)) { - spin_unlock_irqrestore(&endp->queue_lock.slock, - irqs); - } else { - struct list_head *next = endp->urb_more.next; - struct u132_urbq *urbq = list_entry(next, - struct u132_urbq, urb_more); - list_del(next); - *urb_slot = urbq->urb; - spin_unlock_irqrestore(&endp->queue_lock.slock, - irqs); - kfree(urbq); - } urb->error_count = 0; - usb_hcd_giveback_urb(hcd, urb, status); - return 0; - } else if (list_empty(&endp->urb_more)) { - dev_err(&u132->platform_dev->dev, "urb=%p not found in " - "endp[%d]=%p ring[%d] %c%c usb_endp=%d usb_addr" - "=%d size=%d next=%04X last=%04X\n", urb, - endp->endp_number, endp, endp->ring->number, - endp->input ? 'I' : ' ', - endp->output ? 'O' : ' ', endp->usb_endp, - endp->usb_addr, endp->queue_size, - endp->queue_next, endp->queue_last); - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - return -EINVAL; - } else { - int retval; - - usb_hcd_unlink_urb_from_ep(u132_to_hcd(u132), urb); - retval = dequeue_from_overflow_chain(u132, endp, - urb); - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - return retval; - } - } -} - -static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 2) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else { - u8 usb_addr = usb_pipedevice(urb->pipe); - u8 usb_endp = usb_pipeendpoint(urb->pipe); - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - if (usb_pipein(urb->pipe)) { - u8 endp_number = udev->endp_number_in[usb_endp]; - struct u132_endp *endp = u132->endp[endp_number - 1]; - return u132_endp_urb_dequeue(u132, endp, urb, status); - } else { - u8 endp_number = udev->endp_number_out[usb_endp]; - struct u132_endp *endp = u132->endp[endp_number - 1]; - return u132_endp_urb_dequeue(u132, endp, urb, status); - } - } -} - -static void u132_endpoint_disable(struct usb_hcd *hcd, - struct usb_host_endpoint *hep) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 2) { - dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p hep=%p" - ") has been removed %d\n", u132, hcd, hep, - u132->going); - } else { - struct u132_endp *endp = hep->hcpriv; - if (endp) - u132_endp_put_kref(u132, endp); - } -} - -static int u132_get_frame(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - int frame = 0; - dev_err(&u132->platform_dev->dev, "TODO: u132_get_frame\n"); - msleep(100); - return frame; - } -} - -static int u132_roothub_descriptor(struct u132 *u132, - struct usb_hub_descriptor *desc) -{ - int retval; - u16 temp; - u32 rh_a = -1; - u32 rh_b = -1; - retval = u132_read_pcimem(u132, roothub.a, &rh_a); - if (retval) - return retval; - desc->bDescriptorType = 0x29; - desc->bPwrOn2PwrGood = (rh_a & RH_A_POTPGT) >> 24; - desc->bHubContrCurrent = 0; - desc->bNbrPorts = u132->num_ports; - temp = 1 + (u132->num_ports / 8); - desc->bDescLength = 7 + 2 * temp; - temp = 0; - if (rh_a & RH_A_NPS) - temp |= 0x0002; - if (rh_a & RH_A_PSM) - temp |= 0x0001; - if (rh_a & RH_A_NOCP) - temp |= 0x0010; - else if (rh_a & RH_A_OCPM) - temp |= 0x0008; - desc->wHubCharacteristics = cpu_to_le16(temp); - retval = u132_read_pcimem(u132, roothub.b, &rh_b); - if (retval) - return retval; - memset(desc->u.hs.DeviceRemovable, 0xff, - sizeof(desc->u.hs.DeviceRemovable)); - desc->u.hs.DeviceRemovable[0] = rh_b & RH_B_DR; - if (u132->num_ports > 7) { - desc->u.hs.DeviceRemovable[1] = (rh_b & RH_B_DR) >> 8; - desc->u.hs.DeviceRemovable[2] = 0xff; - } else - desc->u.hs.DeviceRemovable[1] = 0xff; - return 0; -} - -static int u132_roothub_status(struct u132 *u132, __le32 *desc) -{ - u32 rh_status = -1; - int ret_status = u132_read_pcimem(u132, roothub.status, &rh_status); - *desc = cpu_to_le32(rh_status); - return ret_status; -} - -static int u132_roothub_portstatus(struct u132 *u132, __le32 *desc, u16 wIndex) -{ - if (wIndex == 0 || wIndex > u132->num_ports) { - return -EINVAL; - } else { - int port = wIndex - 1; - u32 rh_portstatus = -1; - int ret_portstatus = u132_read_pcimem(u132, - roothub.portstatus[port], &rh_portstatus); - *desc = cpu_to_le32(rh_portstatus); - if (*(u16 *) (desc + 2)) { - dev_info(&u132->platform_dev->dev, "Port %d Status Chan" - "ge = %08X\n", port, *desc); - } - return ret_portstatus; - } -} - - -/* this timer value might be vendor-specific ... */ -#define PORT_RESET_HW_MSEC 10 -#define PORT_RESET_MSEC 10 -/* wrap-aware logic morphed from */ -#define tick_before(t1, t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0) -static int u132_roothub_portreset(struct u132 *u132, int port_index) -{ - int retval; - u32 fmnumber; - u16 now; - u16 reset_done; - retval = u132_read_pcimem(u132, fmnumber, &fmnumber); - if (retval) - return retval; - now = fmnumber; - reset_done = now + PORT_RESET_MSEC; - do { - u32 portstat; - do { - retval = u132_read_pcimem(u132, - roothub.portstatus[port_index], &portstat); - if (retval) - return retval; - if (RH_PS_PRS & portstat) - continue; - else - break; - } while (tick_before(now, reset_done)); - if (RH_PS_PRS & portstat) - return -ENODEV; - if (RH_PS_CCS & portstat) { - if (RH_PS_PRSC & portstat) { - retval = u132_write_pcimem(u132, - roothub.portstatus[port_index], - RH_PS_PRSC); - if (retval) - return retval; - } - } else - break; /* start the next reset, - sleep till it's probably done */ - retval = u132_write_pcimem(u132, roothub.portstatus[port_index], - RH_PS_PRS); - if (retval) - return retval; - msleep(PORT_RESET_HW_MSEC); - retval = u132_read_pcimem(u132, fmnumber, &fmnumber); - if (retval) - return retval; - now = fmnumber; - } while (tick_before(now, reset_done)); - return 0; -} - -static int u132_roothub_setportfeature(struct u132 *u132, u16 wValue, - u16 wIndex) -{ - if (wIndex == 0 || wIndex > u132->num_ports) { - return -EINVAL; - } else { - int retval; - int port_index = wIndex - 1; - struct u132_port *port = &u132->port[port_index]; - port->Status &= ~(1 << wValue); - switch (wValue) { - case USB_PORT_FEAT_SUSPEND: - retval = u132_write_pcimem(u132, - roothub.portstatus[port_index], RH_PS_PSS); - if (retval) - return retval; - return 0; - case USB_PORT_FEAT_POWER: - retval = u132_write_pcimem(u132, - roothub.portstatus[port_index], RH_PS_PPS); - if (retval) - return retval; - return 0; - case USB_PORT_FEAT_RESET: - retval = u132_roothub_portreset(u132, port_index); - if (retval) - return retval; - return 0; - default: - return -EPIPE; - } - } -} - -static int u132_roothub_clearportfeature(struct u132 *u132, u16 wValue, - u16 wIndex) -{ - if (wIndex == 0 || wIndex > u132->num_ports) { - return -EINVAL; - } else { - int port_index = wIndex - 1; - u32 temp; - int retval; - struct u132_port *port = &u132->port[port_index]; - port->Status &= ~(1 << wValue); - switch (wValue) { - case USB_PORT_FEAT_ENABLE: - temp = RH_PS_CCS; - break; - case USB_PORT_FEAT_C_ENABLE: - temp = RH_PS_PESC; - break; - case USB_PORT_FEAT_SUSPEND: - temp = RH_PS_POCI; - if ((u132->hc_control & OHCI_CTRL_HCFS) - != OHCI_USB_OPER) { - dev_err(&u132->platform_dev->dev, "TODO resume_" - "root_hub\n"); - } - break; - case USB_PORT_FEAT_C_SUSPEND: - temp = RH_PS_PSSC; - break; - case USB_PORT_FEAT_POWER: - temp = RH_PS_LSDA; - break; - case USB_PORT_FEAT_C_CONNECTION: - temp = RH_PS_CSC; - break; - case USB_PORT_FEAT_C_OVER_CURRENT: - temp = RH_PS_OCIC; - break; - case USB_PORT_FEAT_C_RESET: - temp = RH_PS_PRSC; - break; - default: - return -EPIPE; - } - retval = u132_write_pcimem(u132, roothub.portstatus[port_index], - temp); - if (retval) - return retval; - return 0; - } -} - - -/* the virtual root hub timer IRQ checks for hub status*/ -static int u132_hub_status_data(struct usb_hcd *hcd, char *buf) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device hcd=%p has been remov" - "ed %d\n", hcd, u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov" - "ed\n", hcd); - return -ESHUTDOWN; - } else { - int i, changed = 0, length = 1; - if (u132->flags & OHCI_QUIRK_AMD756) { - if ((u132->hc_roothub_a & RH_A_NDP) > MAX_ROOT_PORTS) { - dev_err(&u132->platform_dev->dev, "bogus NDP, r" - "ereads as NDP=%d\n", - u132->hc_roothub_a & RH_A_NDP); - goto done; - } - } - if (u132->hc_roothub_status & (RH_HS_LPSC | RH_HS_OCIC)) - buf[0] = changed = 1; - else - buf[0] = 0; - if (u132->num_ports > 7) { - buf[1] = 0; - length++; - } - for (i = 0; i < u132->num_ports; i++) { - if (u132->hc_roothub_portstatus[i] & (RH_PS_CSC | - RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | - RH_PS_PRSC)) { - changed = 1; - if (i < 7) - buf[0] |= 1 << (i + 1); - else - buf[1] |= 1 << (i - 7); - continue; - } - if (!(u132->hc_roothub_portstatus[i] & RH_PS_CCS)) - continue; - - if ((u132->hc_roothub_portstatus[i] & RH_PS_PSS)) - continue; - } -done: - return changed ? length : 0; - } -} - -static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, - u16 wIndex, char *buf, u16 wLength) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - int retval = 0; - mutex_lock(&u132->sw_lock); - switch (typeReq) { - case ClearHubFeature: - switch (wValue) { - case C_HUB_OVER_CURRENT: - case C_HUB_LOCAL_POWER: - break; - default: - goto stall; - } - break; - case SetHubFeature: - switch (wValue) { - case C_HUB_OVER_CURRENT: - case C_HUB_LOCAL_POWER: - break; - default: - goto stall; - } - break; - case ClearPortFeature:{ - retval = u132_roothub_clearportfeature(u132, - wValue, wIndex); - if (retval) - goto error; - break; - } - case GetHubDescriptor:{ - retval = u132_roothub_descriptor(u132, - (struct usb_hub_descriptor *)buf); - if (retval) - goto error; - break; - } - case GetHubStatus:{ - retval = u132_roothub_status(u132, - (__le32 *) buf); - if (retval) - goto error; - break; - } - case GetPortStatus:{ - retval = u132_roothub_portstatus(u132, - (__le32 *) buf, wIndex); - if (retval) - goto error; - break; - } - case SetPortFeature:{ - retval = u132_roothub_setportfeature(u132, - wValue, wIndex); - if (retval) - goto error; - break; - } - default: - goto stall; - error: - u132_disable(u132); - u132->going = 1; - break; - stall: - retval = -EPIPE; - break; - } - mutex_unlock(&u132->sw_lock); - return retval; - } -} - -static int u132_start_port_reset(struct usb_hcd *hcd, unsigned port_num) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else - return 0; -} - - -#ifdef CONFIG_PM -static int u132_bus_suspend(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else - return 0; -} - -static int u132_bus_resume(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else - return 0; -} - -#else -#define u132_bus_suspend NULL -#define u132_bus_resume NULL -#endif -static struct hc_driver u132_hc_driver = { - .description = hcd_name, - .hcd_priv_size = sizeof(struct u132), - .irq = NULL, - .flags = HCD_USB11 | HCD_MEMORY, - .reset = u132_hcd_reset, - .start = u132_hcd_start, - .stop = u132_hcd_stop, - .urb_enqueue = u132_urb_enqueue, - .urb_dequeue = u132_urb_dequeue, - .endpoint_disable = u132_endpoint_disable, - .get_frame_number = u132_get_frame, - .hub_status_data = u132_hub_status_data, - .hub_control = u132_hub_control, - .bus_suspend = u132_bus_suspend, - .bus_resume = u132_bus_resume, - .start_port_reset = u132_start_port_reset, -}; - -/* -* This function may be called by the USB core whilst the "usb_all_devices_rwsem" -* is held for writing, thus this module must not call usb_remove_hcd() -* synchronously - but instead should immediately stop activity to the -* device and asynchronously call usb_remove_hcd() -*/ -static int __devexit u132_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - if (hcd) { - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going++ > 1) { - dev_err(&u132->platform_dev->dev, "already being remove" - "d\n"); - return -ENODEV; - } else { - int rings = MAX_U132_RINGS; - int endps = MAX_U132_ENDPS; - dev_err(&u132->platform_dev->dev, "removing device u132" - ".%d\n", u132->sequence_num); - msleep(100); - mutex_lock(&u132->sw_lock); - u132_monitor_cancel_work(u132); - while (rings-- > 0) { - struct u132_ring *ring = &u132->ring[rings]; - u132_ring_cancel_work(u132, ring); - } while (endps-- > 0) { - struct u132_endp *endp = u132->endp[endps]; - if (endp) - u132_endp_cancel_work(u132, endp); - } - u132->going += 1; - printk(KERN_INFO "removing device u132.%d\n", - u132->sequence_num); - mutex_unlock(&u132->sw_lock); - usb_remove_hcd(hcd); - u132_u132_put_kref(u132); - return 0; - } - } else - return 0; -} - -static void u132_initialise(struct u132 *u132, struct platform_device *pdev) -{ - int rings = MAX_U132_RINGS; - int ports = MAX_U132_PORTS; - int addrs = MAX_U132_ADDRS; - int udevs = MAX_U132_UDEVS; - int endps = MAX_U132_ENDPS; - u132->board = pdev->dev.platform_data; - u132->platform_dev = pdev; - u132->power = 0; - u132->reset = 0; - mutex_init(&u132->sw_lock); - mutex_init(&u132->scheduler_lock); - while (rings-- > 0) { - struct u132_ring *ring = &u132->ring[rings]; - ring->u132 = u132; - ring->number = rings + 1; - ring->length = 0; - ring->curr_endp = NULL; - INIT_DELAYED_WORK(&ring->scheduler, - u132_hcd_ring_work_scheduler); - } - mutex_lock(&u132->sw_lock); - INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work); - while (ports-- > 0) { - struct u132_port *port = &u132->port[ports]; - port->u132 = u132; - port->reset = 0; - port->enable = 0; - port->power = 0; - port->Status = 0; - } - while (addrs-- > 0) { - struct u132_addr *addr = &u132->addr[addrs]; - addr->address = 0; - } - while (udevs-- > 0) { - struct u132_udev *udev = &u132->udev[udevs]; - int i = ARRAY_SIZE(udev->endp_number_in); - int o = ARRAY_SIZE(udev->endp_number_out); - udev->usb_device = NULL; - udev->udev_number = 0; - udev->usb_addr = 0; - udev->portnumber = 0; - while (i-- > 0) - udev->endp_number_in[i] = 0; - - while (o-- > 0) - udev->endp_number_out[o] = 0; - - } - while (endps-- > 0) - u132->endp[endps] = NULL; - - mutex_unlock(&u132->sw_lock); -} - -static int __devinit u132_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - int retval; - u32 control; - u32 rh_a = -1; - u32 num_ports; - - msleep(100); - if (u132_exiting > 0) - return -ENODEV; - - retval = ftdi_write_pcimem(pdev, intrdisable, OHCI_INTR_MIE); - if (retval) - return retval; - retval = ftdi_read_pcimem(pdev, control, &control); - if (retval) - return retval; - retval = ftdi_read_pcimem(pdev, roothub.a, &rh_a); - if (retval) - return retval; - num_ports = rh_a & RH_A_NDP; /* refuse to confuse usbcore */ - if (pdev->dev.dma_mask) - return -EINVAL; - - hcd = usb_create_hcd(&u132_hc_driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - printk(KERN_ERR "failed to create the usb hcd struct for U132\n" - ); - ftdi_elan_gone_away(pdev); - return -ENOMEM; - } else { - struct u132 *u132 = hcd_to_u132(hcd); - retval = 0; - hcd->rsrc_start = 0; - mutex_lock(&u132_module_lock); - list_add_tail(&u132->u132_list, &u132_static_list); - u132->sequence_num = ++u132_instances; - mutex_unlock(&u132_module_lock); - u132_u132_init_kref(u132); - u132_initialise(u132, pdev); - hcd->product_desc = "ELAN U132 Host Controller"; - retval = usb_add_hcd(hcd, 0, 0); - if (retval != 0) { - dev_err(&u132->platform_dev->dev, "init error %d\n", - retval); - u132_u132_put_kref(u132); - return retval; - } else { - u132_monitor_queue_work(u132, 100); - return 0; - } - } -} - - -#ifdef CONFIG_PM -/* for this device there's no useful distinction between the controller -* and its root hub, except that the root hub only gets direct PM calls -* when CONFIG_USB_SUSPEND is enabled. -*/ -static int u132_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - int retval = 0, ports; - - switch (state.event) { - case PM_EVENT_FREEZE: - retval = u132_bus_suspend(hcd); - break; - case PM_EVENT_SUSPEND: - case PM_EVENT_HIBERNATE: - ports = MAX_U132_PORTS; - while (ports-- > 0) { - port_power(u132, ports, 0); - } - break; - } - return retval; - } -} - -static int u132_resume(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - int retval = 0; - if (!u132->port[0].power) { - int ports = MAX_U132_PORTS; - while (ports-- > 0) { - port_power(u132, ports, 1); - } - retval = 0; - } else { - retval = u132_bus_resume(hcd); - } - return retval; - } -} - -#else -#define u132_suspend NULL -#define u132_resume NULL -#endif -/* -* this driver is loaded explicitly by ftdi_u132 -* -* the platform_driver struct is static because it is per type of module -*/ -static struct platform_driver u132_platform_driver = { - .probe = u132_probe, - .remove = __devexit_p(u132_remove), - .suspend = u132_suspend, - .resume = u132_resume, - .driver = { - .name = (char *)hcd_name, - .owner = THIS_MODULE, - }, -}; -static int __init u132_hcd_init(void) -{ - int retval; - INIT_LIST_HEAD(&u132_static_list); - u132_instances = 0; - u132_exiting = 0; - mutex_init(&u132_module_lock); - if (usb_disabled()) - return -ENODEV; - printk(KERN_INFO "driver %s\n", hcd_name); - workqueue = create_singlethread_workqueue("u132"); - retval = platform_driver_register(&u132_platform_driver); - return retval; -} - - -module_init(u132_hcd_init); -static void __exit u132_hcd_exit(void) -{ - struct u132 *u132; - struct u132 *temp; - mutex_lock(&u132_module_lock); - u132_exiting += 1; - mutex_unlock(&u132_module_lock); - list_for_each_entry_safe(u132, temp, &u132_static_list, u132_list) { - platform_device_unregister(u132->platform_dev); - } - platform_driver_unregister(&u132_platform_driver); - printk(KERN_INFO "u132-hcd driver deregistered\n"); - wait_event(u132_hcd_wait, u132_instances == 0); - flush_workqueue(workqueue); - destroy_workqueue(workqueue); -} - - -module_exit(u132_hcd_exit); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:u132_hcd"); diff --git a/ANDROID_3.4.5/drivers/usb/host/uhci-debug.c b/ANDROID_3.4.5/drivers/usb/host/uhci-debug.c deleted file mode 100644 index fc0b0daa..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/uhci-debug.c +++ /dev/null @@ -1,593 +0,0 @@ -/* - * UHCI-specific debugging code. Invaluable when something - * goes wrong, but don't get in my face. - * - * Kernel visible pointers are surrounded in []s and bus - * visible pointers are surrounded in ()s - * - * (C) Copyright 1999 Linus Torvalds - * (C) Copyright 1999-2001 Johannes Erdfelt - */ - -#include -#include -#include -#include - -#include "uhci-hcd.h" - -static struct dentry *uhci_debugfs_root; - -#ifdef DEBUG - -/* Handle REALLY large printks so we don't overflow buffers */ -static void lprintk(char *buf) -{ - char *p; - - /* Just write one line at a time */ - while (buf) { - p = strchr(buf, '\n'); - if (p) - *p = 0; - printk(KERN_DEBUG "%s\n", buf); - buf = p; - if (buf) - buf++; - } -} - -static int uhci_show_td(struct uhci_hcd *uhci, struct uhci_td *td, char *buf, - int len, int space) -{ - char *out = buf; - char *spid; - u32 status, token; - - /* Try to make sure there's enough memory */ - if (len < 160) - return 0; - - status = td_status(uhci, td); - out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td, - hc32_to_cpu(uhci, td->link)); - out += sprintf(out, "e%d %s%s%s%s%s%s%s%s%s%sLength=%x ", - ((status >> 27) & 3), - (status & TD_CTRL_SPD) ? "SPD " : "", - (status & TD_CTRL_LS) ? "LS " : "", - (status & TD_CTRL_IOC) ? "IOC " : "", - (status & TD_CTRL_ACTIVE) ? "Active " : "", - (status & TD_CTRL_STALLED) ? "Stalled " : "", - (status & TD_CTRL_DBUFERR) ? "DataBufErr " : "", - (status & TD_CTRL_BABBLE) ? "Babble " : "", - (status & TD_CTRL_NAK) ? "NAK " : "", - (status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "", - (status & TD_CTRL_BITSTUFF) ? "BitStuff " : "", - status & 0x7ff); - - token = td_token(uhci, td); - switch (uhci_packetid(token)) { - case USB_PID_SETUP: - spid = "SETUP"; - break; - case USB_PID_OUT: - spid = "OUT"; - break; - case USB_PID_IN: - spid = "IN"; - break; - default: - spid = "?"; - break; - } - - out += sprintf(out, "MaxLen=%x DT%d EndPt=%x Dev=%x, PID=%x(%s) ", - token >> 21, - ((token >> 19) & 1), - (token >> 15) & 15, - (token >> 8) & 127, - (token & 0xff), - spid); - out += sprintf(out, "(buf=%08x)\n", hc32_to_cpu(uhci, td->buffer)); - - return out - buf; -} - -static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp, - char *buf, int len, int space) -{ - char *out = buf; - struct uhci_td *td; - int i, nactive, ninactive; - char *ptype; - - if (len < 200) - return 0; - - out += sprintf(out, "urb_priv [%p] ", urbp); - out += sprintf(out, "urb [%p] ", urbp->urb); - out += sprintf(out, "qh [%p] ", urbp->qh); - out += sprintf(out, "Dev=%d ", usb_pipedevice(urbp->urb->pipe)); - out += sprintf(out, "EP=%x(%s) ", usb_pipeendpoint(urbp->urb->pipe), - (usb_pipein(urbp->urb->pipe) ? "IN" : "OUT")); - - switch (usb_pipetype(urbp->urb->pipe)) { - case PIPE_ISOCHRONOUS: ptype = "ISO"; break; - case PIPE_INTERRUPT: ptype = "INT"; break; - case PIPE_BULK: ptype = "BLK"; break; - default: - case PIPE_CONTROL: ptype = "CTL"; break; - } - - out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : "")); - out += sprintf(out, " Actlen=%d%s", urbp->urb->actual_length, - (urbp->qh->type == USB_ENDPOINT_XFER_CONTROL ? - "-8" : "")); - - if (urbp->urb->unlinked) - out += sprintf(out, " Unlinked=%d", urbp->urb->unlinked); - out += sprintf(out, "\n"); - - i = nactive = ninactive = 0; - list_for_each_entry(td, &urbp->td_list, list) { - if (urbp->qh->type != USB_ENDPOINT_XFER_ISOC && - (++i <= 10 || debug > 2)) { - out += sprintf(out, "%*s%d: ", space + 2, "", i); - out += uhci_show_td(uhci, td, out, - len - (out - buf), 0); - } else { - if (td_status(uhci, td) & TD_CTRL_ACTIVE) - ++nactive; - else - ++ninactive; - } - } - if (nactive + ninactive > 0) - out += sprintf(out, "%*s[skipped %d inactive and %d active " - "TDs]\n", - space, "", ninactive, nactive); - - return out - buf; -} - -static int uhci_show_qh(struct uhci_hcd *uhci, - struct uhci_qh *qh, char *buf, int len, int space) -{ - char *out = buf; - int i, nurbs; - __hc32 element = qh_element(qh); - char *qtype; - - /* Try to make sure there's enough memory */ - if (len < 80 * 7) - return 0; - - switch (qh->type) { - case USB_ENDPOINT_XFER_ISOC: qtype = "ISO"; break; - case USB_ENDPOINT_XFER_INT: qtype = "INT"; break; - case USB_ENDPOINT_XFER_BULK: qtype = "BLK"; break; - case USB_ENDPOINT_XFER_CONTROL: qtype = "CTL"; break; - default: qtype = "Skel" ; break; - } - - out += sprintf(out, "%*s[%p] %s QH link (%08x) element (%08x)\n", - space, "", qh, qtype, - hc32_to_cpu(uhci, qh->link), - hc32_to_cpu(uhci, element)); - if (qh->type == USB_ENDPOINT_XFER_ISOC) - out += sprintf(out, "%*s period %d phase %d load %d us, " - "frame %x desc [%p]\n", - space, "", qh->period, qh->phase, qh->load, - qh->iso_frame, qh->iso_packet_desc); - else if (qh->type == USB_ENDPOINT_XFER_INT) - out += sprintf(out, "%*s period %d phase %d load %d us\n", - space, "", qh->period, qh->phase, qh->load); - - if (element & UHCI_PTR_QH(uhci)) - out += sprintf(out, "%*s Element points to QH (bug?)\n", space, ""); - - if (element & UHCI_PTR_DEPTH(uhci)) - out += sprintf(out, "%*s Depth traverse\n", space, ""); - - if (element & cpu_to_hc32(uhci, 8)) - out += sprintf(out, "%*s Bit 3 set (bug?)\n", space, ""); - - if (!(element & ~(UHCI_PTR_QH(uhci) | UHCI_PTR_DEPTH(uhci)))) - out += sprintf(out, "%*s Element is NULL (bug?)\n", space, ""); - - if (list_empty(&qh->queue)) { - out += sprintf(out, "%*s queue is empty\n", space, ""); - if (qh == uhci->skel_async_qh) - out += uhci_show_td(uhci, uhci->term_td, out, - len - (out - buf), 0); - } else { - struct urb_priv *urbp = list_entry(qh->queue.next, - struct urb_priv, node); - struct uhci_td *td = list_entry(urbp->td_list.next, - struct uhci_td, list); - - if (element != LINK_TO_TD(uhci, td)) - out += sprintf(out, "%*s Element != First TD\n", - space, ""); - i = nurbs = 0; - list_for_each_entry(urbp, &qh->queue, node) { - if (++i <= 10) - out += uhci_show_urbp(uhci, urbp, out, - len - (out - buf), space + 2); - else - ++nurbs; - } - if (nurbs > 0) - out += sprintf(out, "%*s Skipped %d URBs\n", - space, "", nurbs); - } - - if (qh->dummy_td) { - out += sprintf(out, "%*s Dummy TD\n", space, ""); - out += uhci_show_td(uhci, qh->dummy_td, out, - len - (out - buf), 0); - } - - return out - buf; -} - -static int uhci_show_sc(int port, unsigned short status, char *buf, int len) -{ - char *out = buf; - - /* Try to make sure there's enough memory */ - if (len < 160) - return 0; - - out += sprintf(out, " stat%d = %04x %s%s%s%s%s%s%s%s%s%s\n", - port, - status, - (status & USBPORTSC_SUSP) ? " Suspend" : "", - (status & USBPORTSC_OCC) ? " OverCurrentChange" : "", - (status & USBPORTSC_OC) ? " OverCurrent" : "", - (status & USBPORTSC_PR) ? " Reset" : "", - (status & USBPORTSC_LSDA) ? " LowSpeed" : "", - (status & USBPORTSC_RD) ? " ResumeDetect" : "", - (status & USBPORTSC_PEC) ? " EnableChange" : "", - (status & USBPORTSC_PE) ? " Enabled" : "", - (status & USBPORTSC_CSC) ? " ConnectChange" : "", - (status & USBPORTSC_CCS) ? " Connected" : ""); - - return out - buf; -} - -static int uhci_show_root_hub_state(struct uhci_hcd *uhci, char *buf, int len) -{ - char *out = buf; - char *rh_state; - - /* Try to make sure there's enough memory */ - if (len < 60) - return 0; - - switch (uhci->rh_state) { - case UHCI_RH_RESET: - rh_state = "reset"; break; - case UHCI_RH_SUSPENDED: - rh_state = "suspended"; break; - case UHCI_RH_AUTO_STOPPED: - rh_state = "auto-stopped"; break; - case UHCI_RH_RESUMING: - rh_state = "resuming"; break; - case UHCI_RH_SUSPENDING: - rh_state = "suspending"; break; - case UHCI_RH_RUNNING: - rh_state = "running"; break; - case UHCI_RH_RUNNING_NODEVS: - rh_state = "running, no devs"; break; - default: - rh_state = "?"; break; - } - out += sprintf(out, "Root-hub state: %s FSBR: %d\n", - rh_state, uhci->fsbr_is_on); - return out - buf; -} - -static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len) -{ - char *out = buf; - unsigned short usbcmd, usbstat, usbint, usbfrnum; - unsigned int flbaseadd; - unsigned char sof; - unsigned short portsc1, portsc2; - - /* Try to make sure there's enough memory */ - if (len < 80 * 9) - return 0; - - usbcmd = uhci_readw(uhci, 0); - usbstat = uhci_readw(uhci, 2); - usbint = uhci_readw(uhci, 4); - usbfrnum = uhci_readw(uhci, 6); - flbaseadd = uhci_readl(uhci, 8); - sof = uhci_readb(uhci, 12); - portsc1 = uhci_readw(uhci, 16); - portsc2 = uhci_readw(uhci, 18); - - out += sprintf(out, " usbcmd = %04x %s%s%s%s%s%s%s%s\n", - usbcmd, - (usbcmd & USBCMD_MAXP) ? "Maxp64 " : "Maxp32 ", - (usbcmd & USBCMD_CF) ? "CF " : "", - (usbcmd & USBCMD_SWDBG) ? "SWDBG " : "", - (usbcmd & USBCMD_FGR) ? "FGR " : "", - (usbcmd & USBCMD_EGSM) ? "EGSM " : "", - (usbcmd & USBCMD_GRESET) ? "GRESET " : "", - (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "", - (usbcmd & USBCMD_RS) ? "RS " : ""); - - out += sprintf(out, " usbstat = %04x %s%s%s%s%s%s\n", - usbstat, - (usbstat & USBSTS_HCH) ? "HCHalted " : "", - (usbstat & USBSTS_HCPE) ? "HostControllerProcessError " : "", - (usbstat & USBSTS_HSE) ? "HostSystemError " : "", - (usbstat & USBSTS_RD) ? "ResumeDetect " : "", - (usbstat & USBSTS_ERROR) ? "USBError " : "", - (usbstat & USBSTS_USBINT) ? "USBINT " : ""); - - out += sprintf(out, " usbint = %04x\n", usbint); - out += sprintf(out, " usbfrnum = (%d)%03x\n", (usbfrnum >> 10) & 1, - 0xfff & (4*(unsigned int)usbfrnum)); - out += sprintf(out, " flbaseadd = %08x\n", flbaseadd); - out += sprintf(out, " sof = %02x\n", sof); - out += uhci_show_sc(1, portsc1, out, len - (out - buf)); - out += uhci_show_sc(2, portsc2, out, len - (out - buf)); - out += sprintf(out, "Most recent frame: %x (%d) " - "Last ISO frame: %x (%d)\n", - uhci->frame_number, uhci->frame_number & 1023, - uhci->last_iso_frame, uhci->last_iso_frame & 1023); - - return out - buf; -} - -static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) -{ - char *out = buf; - int i, j; - struct uhci_qh *qh; - struct uhci_td *td; - struct list_head *tmp, *head; - int nframes, nerrs; - __hc32 link; - __hc32 fsbr_link; - - static const char * const qh_names[] = { - "unlink", "iso", "int128", "int64", "int32", "int16", - "int8", "int4", "int2", "async", "term" - }; - - out += uhci_show_root_hub_state(uhci, out, len - (out - buf)); - out += sprintf(out, "HC status\n"); - out += uhci_show_status(uhci, out, len - (out - buf)); - - out += sprintf(out, "Periodic load table\n"); - for (i = 0; i < MAX_PHASE; ++i) { - out += sprintf(out, "\t%d", uhci->load[i]); - if (i % 8 == 7) - *out++ = '\n'; - } - out += sprintf(out, "Total: %d, #INT: %d, #ISO: %d\n", - uhci->total_load, - uhci_to_hcd(uhci)->self.bandwidth_int_reqs, - uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs); - if (debug <= 1) - return out - buf; - - out += sprintf(out, "Frame List\n"); - nframes = 10; - nerrs = 0; - for (i = 0; i < UHCI_NUMFRAMES; ++i) { - __hc32 qh_dma; - - j = 0; - td = uhci->frame_cpu[i]; - link = uhci->frame[i]; - if (!td) - goto check_link; - - if (nframes > 0) { - out += sprintf(out, "- Frame %d -> (%08x)\n", - i, hc32_to_cpu(uhci, link)); - j = 1; - } - - head = &td->fl_list; - tmp = head; - do { - td = list_entry(tmp, struct uhci_td, fl_list); - tmp = tmp->next; - if (link != LINK_TO_TD(uhci, td)) { - if (nframes > 0) - out += sprintf(out, " link does " - "not match list entry!\n"); - else - ++nerrs; - } - if (nframes > 0) - out += uhci_show_td(uhci, td, out, - len - (out - buf), 4); - link = td->link; - } while (tmp != head); - -check_link: - qh_dma = uhci_frame_skel_link(uhci, i); - if (link != qh_dma) { - if (nframes > 0) { - if (!j) { - out += sprintf(out, - "- Frame %d -> (%08x)\n", - i, hc32_to_cpu(uhci, link)); - j = 1; - } - out += sprintf(out, " link does not match " - "QH (%08x)!\n", - hc32_to_cpu(uhci, qh_dma)); - } else - ++nerrs; - } - nframes -= j; - } - if (nerrs > 0) - out += sprintf(out, "Skipped %d bad links\n", nerrs); - - out += sprintf(out, "Skeleton QHs\n"); - - fsbr_link = 0; - for (i = 0; i < UHCI_NUM_SKELQH; ++i) { - int cnt = 0; - - qh = uhci->skelqh[i]; - out += sprintf(out, "- skel_%s_qh\n", qh_names[i]); \ - out += uhci_show_qh(uhci, qh, out, len - (out - buf), 4); - - /* Last QH is the Terminating QH, it's different */ - if (i == SKEL_TERM) { - if (qh_element(qh) != LINK_TO_TD(uhci, uhci->term_td)) - out += sprintf(out, " skel_term_qh element is not set to term_td!\n"); - link = fsbr_link; - if (!link) - link = LINK_TO_QH(uhci, uhci->skel_term_qh); - goto check_qh_link; - } - - head = &qh->node; - tmp = head->next; - - while (tmp != head) { - qh = list_entry(tmp, struct uhci_qh, node); - tmp = tmp->next; - if (++cnt <= 10) - out += uhci_show_qh(uhci, qh, out, - len - (out - buf), 4); - if (!fsbr_link && qh->skel >= SKEL_FSBR) - fsbr_link = LINK_TO_QH(uhci, qh); - } - if ((cnt -= 10) > 0) - out += sprintf(out, " Skipped %d QHs\n", cnt); - - link = UHCI_PTR_TERM(uhci); - if (i <= SKEL_ISO) - ; - else if (i < SKEL_ASYNC) - link = LINK_TO_QH(uhci, uhci->skel_async_qh); - else if (!uhci->fsbr_is_on) - ; - else - link = LINK_TO_QH(uhci, uhci->skel_term_qh); -check_qh_link: - if (qh->link != link) - out += sprintf(out, " last QH not linked to next skeleton!\n"); - } - - return out - buf; -} - -#ifdef CONFIG_DEBUG_FS - -#define MAX_OUTPUT (64 * 1024) - -struct uhci_debug { - int size; - char *data; -}; - -static int uhci_debug_open(struct inode *inode, struct file *file) -{ - struct uhci_hcd *uhci = inode->i_private; - struct uhci_debug *up; - unsigned long flags; - - up = kmalloc(sizeof(*up), GFP_KERNEL); - if (!up) - return -ENOMEM; - - up->data = kmalloc(MAX_OUTPUT, GFP_KERNEL); - if (!up->data) { - kfree(up); - return -ENOMEM; - } - - up->size = 0; - spin_lock_irqsave(&uhci->lock, flags); - if (uhci->is_initialized) - up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT); - spin_unlock_irqrestore(&uhci->lock, flags); - - file->private_data = up; - - return 0; -} - -static loff_t uhci_debug_lseek(struct file *file, loff_t off, int whence) -{ - struct uhci_debug *up; - loff_t new = -1; - - up = file->private_data; - - /* XXX: atomic 64bit seek access, but that needs to be fixed in the VFS */ - switch (whence) { - case 0: - new = off; - break; - case 1: - new = file->f_pos + off; - break; - } - - if (new < 0 || new > up->size) - return -EINVAL; - - return (file->f_pos = new); -} - -static ssize_t uhci_debug_read(struct file *file, char __user *buf, - size_t nbytes, loff_t *ppos) -{ - struct uhci_debug *up = file->private_data; - return simple_read_from_buffer(buf, nbytes, ppos, up->data, up->size); -} - -static int uhci_debug_release(struct inode *inode, struct file *file) -{ - struct uhci_debug *up = file->private_data; - - kfree(up->data); - kfree(up); - - return 0; -} - -static const struct file_operations uhci_debug_operations = { - .owner = THIS_MODULE, - .open = uhci_debug_open, - .llseek = uhci_debug_lseek, - .read = uhci_debug_read, - .release = uhci_debug_release, -}; -#define UHCI_DEBUG_OPS - -#endif /* CONFIG_DEBUG_FS */ - -#else /* DEBUG */ - -static inline void lprintk(char *buf) -{} - -static inline int uhci_show_qh(struct uhci_hcd *uhci, - struct uhci_qh *qh, char *buf, int len, int space) -{ - return 0; -} - -static inline int uhci_sprint_schedule(struct uhci_hcd *uhci, - char *buf, int len) -{ - return 0; -} - -#endif diff --git a/ANDROID_3.4.5/drivers/usb/host/uhci-grlib.c b/ANDROID_3.4.5/drivers/usb/host/uhci-grlib.c deleted file mode 100644 index f7a62138..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/uhci-grlib.c +++ /dev/null @@ -1,208 +0,0 @@ -/* - * UHCI HCD (Host Controller Driver) for GRLIB GRUSBHC - * - * Copyright (c) 2011 Jan Andersson - * - * This file is based on UHCI PCI HCD: - * (C) Copyright 1999 Linus Torvalds - * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com - * (C) Copyright 1999 Randy Dunlap - * (C) Copyright 1999 Georg Acher, acher@in.tum.de - * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de - * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch - * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at - * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface - * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com). - * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) - * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu - */ - -#include -#include -#include - -static int uhci_grlib_init(struct usb_hcd *hcd) -{ - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - - /* - * Probe to determine the endianness of the controller. - * We know that bit 7 of the PORTSC1 register is always set - * and bit 15 is always clear. If uhci_readw() yields a value - * with bit 7 (0x80) turned on then the current little-endian - * setting is correct. Otherwise we assume the value was - * byte-swapped; hence the register interface and presumably - * also the descriptors are big-endian. - */ - if (!(uhci_readw(uhci, USBPORTSC1) & 0x80)) { - uhci->big_endian_mmio = 1; - uhci->big_endian_desc = 1; - } - - uhci->rh_numports = uhci_count_ports(hcd); - - /* Set up pointers to to generic functions */ - uhci->reset_hc = uhci_generic_reset_hc; - uhci->check_and_reset_hc = uhci_generic_check_and_reset_hc; - /* No special actions need to be taken for the functions below */ - uhci->configure_hc = NULL; - uhci->resume_detect_interrupts_are_broken = NULL; - uhci->global_suspend_mode_is_broken = NULL; - - /* Reset if the controller isn't already safely quiescent. */ - check_and_reset_hc(uhci); - return 0; -} - -static const struct hc_driver uhci_grlib_hc_driver = { - .description = hcd_name, - .product_desc = "GRLIB GRUSBHC UHCI Host Controller", - .hcd_priv_size = sizeof(struct uhci_hcd), - - /* Generic hardware linkage */ - .irq = uhci_irq, - .flags = HCD_MEMORY | HCD_USB11, - - /* Basic lifecycle operations */ - .reset = uhci_grlib_init, - .start = uhci_start, -#ifdef CONFIG_PM - .pci_suspend = NULL, - .pci_resume = NULL, - .bus_suspend = uhci_rh_suspend, - .bus_resume = uhci_rh_resume, -#endif - .stop = uhci_stop, - - .urb_enqueue = uhci_urb_enqueue, - .urb_dequeue = uhci_urb_dequeue, - - .endpoint_disable = uhci_hcd_endpoint_disable, - .get_frame_number = uhci_hcd_get_frame_number, - - .hub_status_data = uhci_hub_status_data, - .hub_control = uhci_hub_control, -}; - - -static int __devinit uhci_hcd_grlib_probe(struct platform_device *op) -{ - struct device_node *dn = op->dev.of_node; - struct usb_hcd *hcd; - struct uhci_hcd *uhci = NULL; - struct resource res; - int irq; - int rv; - - if (usb_disabled()) - return -ENODEV; - - dev_dbg(&op->dev, "initializing GRUSBHC UHCI USB Controller\n"); - - rv = of_address_to_resource(dn, 0, &res); - if (rv) - return rv; - - /* usb_create_hcd requires dma_mask != NULL */ - op->dev.dma_mask = &op->dev.coherent_dma_mask; - hcd = usb_create_hcd(&uhci_grlib_hc_driver, &op->dev, - "GRUSBHC UHCI USB"); - if (!hcd) - return -ENOMEM; - - hcd->rsrc_start = res.start; - hcd->rsrc_len = resource_size(&res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__); - rv = -EBUSY; - goto err_rmr; - } - - irq = irq_of_parse_and_map(dn, 0); - if (irq == NO_IRQ) { - printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__); - rv = -EBUSY; - goto err_irq; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - printk(KERN_ERR "%s: ioremap failed\n", __FILE__); - rv = -ENOMEM; - goto err_ioremap; - } - - uhci = hcd_to_uhci(hcd); - - uhci->regs = hcd->regs; - - rv = usb_add_hcd(hcd, irq, 0); - if (rv) - goto err_uhci; - - return 0; - -err_uhci: - iounmap(hcd->regs); -err_ioremap: - irq_dispose_mapping(irq); -err_irq: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err_rmr: - usb_put_hcd(hcd); - - return rv; -} - -static int uhci_hcd_grlib_remove(struct platform_device *op) -{ - struct usb_hcd *hcd = dev_get_drvdata(&op->dev); - - dev_set_drvdata(&op->dev, NULL); - - dev_dbg(&op->dev, "stopping GRLIB GRUSBHC UHCI USB Controller\n"); - - usb_remove_hcd(hcd); - - iounmap(hcd->regs); - irq_dispose_mapping(hcd->irq); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - - usb_put_hcd(hcd); - - return 0; -} - -/* Make sure the controller is quiescent and that we're not using it - * any more. This is mainly for the benefit of programs which, like kexec, - * expect the hardware to be idle: not doing DMA or generating IRQs. - * - * This routine may be called in a damaged or failing kernel. Hence we - * do not acquire the spinlock before shutting down the controller. - */ -static void uhci_hcd_grlib_shutdown(struct platform_device *op) -{ - struct usb_hcd *hcd = dev_get_drvdata(&op->dev); - - uhci_hc_died(hcd_to_uhci(hcd)); -} - -static const struct of_device_id uhci_hcd_grlib_of_match[] = { - { .name = "GAISLER_UHCI", }, - { .name = "01_027", }, - {}, -}; -MODULE_DEVICE_TABLE(of, uhci_hcd_grlib_of_match); - - -static struct platform_driver uhci_grlib_driver = { - .probe = uhci_hcd_grlib_probe, - .remove = uhci_hcd_grlib_remove, - .shutdown = uhci_hcd_grlib_shutdown, - .driver = { - .name = "grlib-uhci", - .owner = THIS_MODULE, - .of_match_table = uhci_hcd_grlib_of_match, - }, -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/uhci-hcd.c b/ANDROID_3.4.5/drivers/usb/host/uhci-hcd.c deleted file mode 100644 index 3e0d2a8c..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/uhci-hcd.c +++ /dev/null @@ -1,939 +0,0 @@ -/* - * Universal Host Controller Interface driver for USB. - * - * Maintainer: Alan Stern - * - * (C) Copyright 1999 Linus Torvalds - * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com - * (C) Copyright 1999 Randy Dunlap - * (C) Copyright 1999 Georg Acher, acher@in.tum.de - * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de - * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch - * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at - * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface - * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com). - * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) - * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu - * - * Intel documents this fairly well, and as far as I know there - * are no royalties or anything like that, but even so there are - * people who decided that they want to do the same thing in a - * completely different way. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "uhci-hcd.h" - -/* - * Version Information - */ -#define DRIVER_AUTHOR \ - "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, " \ - "Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, " \ - "Roman Weissgaerber, Alan Stern" -#define DRIVER_DESC "USB Universal Host Controller Interface driver" - -/* for flakey hardware, ignore overcurrent indicators */ -static bool ignore_oc; -module_param(ignore_oc, bool, S_IRUGO); -MODULE_PARM_DESC(ignore_oc, "ignore hardware overcurrent indications"); - -/* - * debug = 0, no debugging messages - * debug = 1, dump failed URBs except for stalls - * debug = 2, dump all failed URBs (including stalls) - * show all queues in /sys/kernel/debug/uhci/[pci_addr] - * debug = 3, show all TDs in URBs when dumping - */ -#ifdef DEBUG -#define DEBUG_CONFIGURED 1 -static int debug = 1; -module_param(debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug level"); - -#else -#define DEBUG_CONFIGURED 0 -#define debug 0 -#endif - -static char *errbuf; -#define ERRBUF_LEN (32 * 1024) - -static struct kmem_cache *uhci_up_cachep; /* urb_priv */ - -static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state); -static void wakeup_rh(struct uhci_hcd *uhci); -static void uhci_get_current_frame_number(struct uhci_hcd *uhci); - -extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); - -/* - * Calculate the link pointer DMA value for the first Skeleton QH in a frame. - */ -static __hc32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame) -{ - int skelnum; - - /* - * The interrupt queues will be interleaved as evenly as possible. - * There's not much to be done about period-1 interrupts; they have - * to occur in every frame. But we can schedule period-2 interrupts - * in odd-numbered frames, period-4 interrupts in frames congruent - * to 2 (mod 4), and so on. This way each frame only has two - * interrupt QHs, which will help spread out bandwidth utilization. - * - * ffs (Find First bit Set) does exactly what we need: - * 1,3,5,... => ffs = 0 => use period-2 QH = skelqh[8], - * 2,6,10,... => ffs = 1 => use period-4 QH = skelqh[7], etc. - * ffs >= 7 => not on any high-period queue, so use - * period-1 QH = skelqh[9]. - * Add in UHCI_NUMFRAMES to insure at least one bit is set. - */ - skelnum = 8 - (int) __ffs(frame | UHCI_NUMFRAMES); - if (skelnum <= 1) - skelnum = 9; - return LINK_TO_QH(uhci, uhci->skelqh[skelnum]); -} - -#include "uhci-debug.c" -#include "uhci-q.c" -#include "uhci-hub.c" - -/* - * Finish up a host controller reset and update the recorded state. - */ -static void finish_reset(struct uhci_hcd *uhci) -{ - int port; - - /* HCRESET doesn't affect the Suspend, Reset, and Resume Detect - * bits in the port status and control registers. - * We have to clear them by hand. - */ - for (port = 0; port < uhci->rh_numports; ++port) - uhci_writew(uhci, 0, USBPORTSC1 + (port * 2)); - - uhci->port_c_suspend = uhci->resuming_ports = 0; - uhci->rh_state = UHCI_RH_RESET; - uhci->is_stopped = UHCI_IS_STOPPED; - clear_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags); -} - -/* - * Last rites for a defunct/nonfunctional controller - * or one we don't want to use any more. - */ -static void uhci_hc_died(struct uhci_hcd *uhci) -{ - uhci_get_current_frame_number(uhci); - uhci->reset_hc(uhci); - finish_reset(uhci); - uhci->dead = 1; - - /* The current frame may already be partway finished */ - ++uhci->frame_number; -} - -/* - * Initialize a controller that was newly discovered or has lost power - * or otherwise been reset while it was suspended. In none of these cases - * can we be sure of its previous state. - */ -static void check_and_reset_hc(struct uhci_hcd *uhci) -{ - if (uhci->check_and_reset_hc(uhci)) - finish_reset(uhci); -} - -#if defined(CONFIG_USB_UHCI_SUPPORT_NON_PCI_HC) -/* - * The two functions below are generic reset functions that are used on systems - * that do not have keyboard and mouse legacy support. We assume that we are - * running on such a system if CONFIG_USB_UHCI_SUPPORT_NON_PCI_HC is defined. - */ - -/* - * Make sure the controller is completely inactive, unable to - * generate interrupts or do DMA. - */ -static void uhci_generic_reset_hc(struct uhci_hcd *uhci) -{ - /* Reset the HC - this will force us to get a - * new notification of any already connected - * ports due to the virtual disconnect that it - * implies. - */ - uhci_writew(uhci, USBCMD_HCRESET, USBCMD); - mb(); - udelay(5); - if (uhci_readw(uhci, USBCMD) & USBCMD_HCRESET) - dev_warn(uhci_dev(uhci), "HCRESET not completed yet!\n"); - - /* Just to be safe, disable interrupt requests and - * make sure the controller is stopped. - */ - uhci_writew(uhci, 0, USBINTR); - uhci_writew(uhci, 0, USBCMD); -} - -/* - * Initialize a controller that was newly discovered or has just been - * resumed. In either case we can't be sure of its previous state. - * - * Returns: 1 if the controller was reset, 0 otherwise. - */ -static int uhci_generic_check_and_reset_hc(struct uhci_hcd *uhci) -{ - unsigned int cmd, intr; - - /* - * When restarting a suspended controller, we expect all the - * settings to be the same as we left them: - * - * Controller is stopped and configured with EGSM set; - * No interrupts enabled except possibly Resume Detect. - * - * If any of these conditions are violated we do a complete reset. - */ - - cmd = uhci_readw(uhci, USBCMD); - if ((cmd & USBCMD_RS) || !(cmd & USBCMD_CF) || !(cmd & USBCMD_EGSM)) { - dev_dbg(uhci_dev(uhci), "%s: cmd = 0x%04x\n", - __func__, cmd); - goto reset_needed; - } - - intr = uhci_readw(uhci, USBINTR); - if (intr & (~USBINTR_RESUME)) { - dev_dbg(uhci_dev(uhci), "%s: intr = 0x%04x\n", - __func__, intr); - goto reset_needed; - } - return 0; - -reset_needed: - dev_dbg(uhci_dev(uhci), "Performing full reset\n"); - uhci_generic_reset_hc(uhci); - return 1; -} -#endif /* CONFIG_USB_UHCI_SUPPORT_NON_PCI_HC */ - -/* - * Store the basic register settings needed by the controller. - */ -static void configure_hc(struct uhci_hcd *uhci) -{ - /* Set the frame length to the default: 1 ms exactly */ - uhci_writeb(uhci, USBSOF_DEFAULT, USBSOF); - - /* Store the frame list base address */ - uhci_writel(uhci, uhci->frame_dma_handle, USBFLBASEADD); - - /* Set the current frame number */ - uhci_writew(uhci, uhci->frame_number & UHCI_MAX_SOF_NUMBER, - USBFRNUM); - - /* perform any arch/bus specific configuration */ - if (uhci->configure_hc) - uhci->configure_hc(uhci); -} - -static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci) -{ - /* If we have to ignore overcurrent events then almost by definition - * we can't depend on resume-detect interrupts. */ - if (ignore_oc) - return 1; - - return uhci->resume_detect_interrupts_are_broken ? - uhci->resume_detect_interrupts_are_broken(uhci) : 0; -} - -static int global_suspend_mode_is_broken(struct uhci_hcd *uhci) -{ - return uhci->global_suspend_mode_is_broken ? - uhci->global_suspend_mode_is_broken(uhci) : 0; -} - -static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state) -__releases(uhci->lock) -__acquires(uhci->lock) -{ - int auto_stop; - int int_enable, egsm_enable, wakeup_enable; - struct usb_device *rhdev = uhci_to_hcd(uhci)->self.root_hub; - - auto_stop = (new_state == UHCI_RH_AUTO_STOPPED); - dev_dbg(&rhdev->dev, "%s%s\n", __func__, - (auto_stop ? " (auto-stop)" : "")); - - /* Start off by assuming Resume-Detect interrupts and EGSM work - * and that remote wakeups should be enabled. - */ - egsm_enable = USBCMD_EGSM; - int_enable = USBINTR_RESUME; - wakeup_enable = 1; - - /* - * In auto-stop mode, we must be able to detect new connections. - * The user can force us to poll by disabling remote wakeup; - * otherwise we will use the EGSM/RD mechanism. - */ - if (auto_stop) { - if (!device_may_wakeup(&rhdev->dev)) - egsm_enable = int_enable = 0; - } - -#ifdef CONFIG_PM - /* - * In bus-suspend mode, we use the wakeup setting specified - * for the root hub. - */ - else { - if (!rhdev->do_remote_wakeup) - wakeup_enable = 0; - } -#endif - - /* - * UHCI doesn't distinguish between wakeup requests from downstream - * devices and local connect/disconnect events. There's no way to - * enable one without the other; both are controlled by EGSM. Thus - * if wakeups are disallowed then EGSM must be turned off -- in which - * case remote wakeup requests from downstream during system sleep - * will be lost. - * - * In addition, if EGSM is broken then we can't use it. Likewise, - * if Resume-Detect interrupts are broken then we can't use them. - * - * Finally, neither EGSM nor RD is useful by itself. Without EGSM, - * the RD status bit will never get set. Without RD, the controller - * won't generate interrupts to tell the system about wakeup events. - */ - if (!wakeup_enable || global_suspend_mode_is_broken(uhci) || - resume_detect_interrupts_are_broken(uhci)) - egsm_enable = int_enable = 0; - - uhci->RD_enable = !!int_enable; - uhci_writew(uhci, int_enable, USBINTR); - //gri - uhci_writew(uhci, 0, USBCMD); - mb(); - while (!(uhci_readw(uhci, USBSTS) & USBSTS_HCH)); - // - uhci_writew(uhci, egsm_enable | USBCMD_CF, USBCMD); - mb(); - udelay(5); - - /* If we're auto-stopping then no devices have been attached - * for a while, so there shouldn't be any active URBs and the - * controller should stop after a few microseconds. Otherwise - * we will give the controller one frame to stop. - */ - if (!auto_stop && !(uhci_readw(uhci, USBSTS) & USBSTS_HCH)) { - uhci->rh_state = UHCI_RH_SUSPENDING; - spin_unlock_irq(&uhci->lock); - msleep(1); - spin_lock_irq(&uhci->lock); - if (uhci->dead) - return; - } - if (!(uhci_readw(uhci, USBSTS) & USBSTS_HCH)) - dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n"); - - uhci_get_current_frame_number(uhci); - - uhci->rh_state = new_state; - uhci->is_stopped = UHCI_IS_STOPPED; - - /* - * If remote wakeup is enabled but either EGSM or RD interrupts - * doesn't work, then we won't get an interrupt when a wakeup event - * occurs. Thus the suspended root hub needs to be polled. - */ - if (wakeup_enable && (!int_enable || !egsm_enable)) - set_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags); - else - clear_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags); - - uhci_scan_schedule(uhci); - uhci_fsbr_off(uhci); -} - -static void start_rh(struct uhci_hcd *uhci) -{ - uhci->is_stopped = 0; - - /* Mark it configured and running with a 64-byte max packet. - * All interrupts are enabled, even though RESUME won't do anything. - */ - uhci_writew(uhci, USBCMD_RS | USBCMD_CF | USBCMD_MAXP, USBCMD); - uhci_writew(uhci, USBINTR_TIMEOUT | USBINTR_RESUME | - USBINTR_IOC | USBINTR_SP, USBINTR); - mb(); - uhci->rh_state = UHCI_RH_RUNNING; - set_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags); -} - -static void wakeup_rh(struct uhci_hcd *uhci) -__releases(uhci->lock) -__acquires(uhci->lock) -{ - dev_dbg(&uhci_to_hcd(uhci)->self.root_hub->dev, - "%s%s\n", __func__, - uhci->rh_state == UHCI_RH_AUTO_STOPPED ? - " (auto-start)" : ""); - - /* If we are auto-stopped then no devices are attached so there's - * no need for wakeup signals. Otherwise we send Global Resume - * for 20 ms. - */ - if (uhci->rh_state == UHCI_RH_SUSPENDED) { - unsigned egsm; - - /* Keep EGSM on if it was set before */ - egsm = uhci_readw(uhci, USBCMD) & USBCMD_EGSM; - uhci->rh_state = UHCI_RH_RESUMING; - uhci_writew(uhci, USBCMD_FGR | USBCMD_CF | egsm, USBCMD); - spin_unlock_irq(&uhci->lock); - msleep(20); - spin_lock_irq(&uhci->lock); - if (uhci->dead) - return; - - /* End Global Resume and wait for EOP to be sent */ - uhci_writew(uhci, USBCMD_CF, USBCMD); - mb(); - udelay(4); - if (uhci_readw(uhci, USBCMD) & USBCMD_FGR) - dev_warn(uhci_dev(uhci), "FGR not stopped yet!\n"); - } - - start_rh(uhci); - - /* Restart root hub polling */ - mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies); -} - -static irqreturn_t uhci_irq(struct usb_hcd *hcd) -{ - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - unsigned short status; - - /* - * Read the interrupt status, and write it back to clear the - * interrupt cause. Contrary to the UHCI specification, the - * "HC Halted" status bit is persistent: it is RO, not R/WC. - */ - status = uhci_readw(uhci, USBSTS); - if (!(status & ~USBSTS_HCH)) /* shared interrupt, not mine */ - return IRQ_NONE; - uhci_writew(uhci, status, USBSTS); /* Clear it */ - - if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) { - if (status & USBSTS_HSE) - dev_err(uhci_dev(uhci), "host system error, " - "PCI problems?\n"); - if (status & USBSTS_HCPE) - dev_err(uhci_dev(uhci), "host controller process " - "error, something bad happened!\n"); - if (status & USBSTS_HCH) { - spin_lock(&uhci->lock); - if (uhci->rh_state >= UHCI_RH_RUNNING) { - dev_err(uhci_dev(uhci), - "host controller halted, " - "very bad!\n"); - if (debug > 1 && errbuf) { - /* Print the schedule for debugging */ - uhci_sprint_schedule(uhci, - errbuf, ERRBUF_LEN); - lprintk(errbuf); - } - uhci_hc_died(uhci); - usb_hc_died(hcd); - - /* Force a callback in case there are - * pending unlinks */ - mod_timer(&hcd->rh_timer, jiffies); - } - spin_unlock(&uhci->lock); - } - } - - if (status & USBSTS_RD) - usb_hcd_poll_rh_status(hcd); - else { - spin_lock(&uhci->lock); - uhci_scan_schedule(uhci); - spin_unlock(&uhci->lock); - } - - return IRQ_HANDLED; -} - -/* - * Store the current frame number in uhci->frame_number if the controller - * is running. Expand from 11 bits (of which we use only 10) to a - * full-sized integer. - * - * Like many other parts of the driver, this code relies on being polled - * more than once per second as long as the controller is running. - */ -static void uhci_get_current_frame_number(struct uhci_hcd *uhci) -{ - if (!uhci->is_stopped) { - unsigned delta; - - delta = (uhci_readw(uhci, USBFRNUM) - uhci->frame_number) & - (UHCI_NUMFRAMES - 1); - uhci->frame_number += delta; - } -} - -/* - * De-allocate all resources - */ -static void release_uhci(struct uhci_hcd *uhci) -{ - int i; - - if (DEBUG_CONFIGURED) { - spin_lock_irq(&uhci->lock); - uhci->is_initialized = 0; - spin_unlock_irq(&uhci->lock); - - debugfs_remove(uhci->dentry); - } - - for (i = 0; i < UHCI_NUM_SKELQH; i++) - uhci_free_qh(uhci, uhci->skelqh[i]); - - uhci_free_td(uhci, uhci->term_td); - - dma_pool_destroy(uhci->qh_pool); - - dma_pool_destroy(uhci->td_pool); - - kfree(uhci->frame_cpu); - - dma_free_coherent(uhci_dev(uhci), - UHCI_NUMFRAMES * sizeof(*uhci->frame), - uhci->frame, uhci->frame_dma_handle); -} - -/* - * Allocate a frame list, and then setup the skeleton - * - * The hardware doesn't really know any difference - * in the queues, but the order does matter for the - * protocols higher up. The order in which the queues - * are encountered by the hardware is: - * - * - All isochronous events are handled before any - * of the queues. We don't do that here, because - * we'll create the actual TD entries on demand. - * - The first queue is the high-period interrupt queue. - * - The second queue is the period-1 interrupt and async - * (low-speed control, full-speed control, then bulk) queue. - * - The third queue is the terminating bandwidth reclamation queue, - * which contains no members, loops back to itself, and is present - * only when FSBR is on and there are no full-speed control or bulk QHs. - */ -static int uhci_start(struct usb_hcd *hcd) -{ - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - int retval = -EBUSY; - int i; - struct dentry __maybe_unused *dentry; - - hcd->uses_new_polling = 1; - /* Accept arbitrarily long scatter-gather lists */ - if (!(hcd->driver->flags & HCD_LOCAL_MEM)) - hcd->self.sg_tablesize = ~0; - - spin_lock_init(&uhci->lock); - setup_timer(&uhci->fsbr_timer, uhci_fsbr_timeout, - (unsigned long) uhci); - INIT_LIST_HEAD(&uhci->idle_qh_list); - init_waitqueue_head(&uhci->waitqh); - -#ifdef UHCI_DEBUG_OPS - dentry = debugfs_create_file(hcd->self.bus_name, - S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, - uhci, &uhci_debug_operations); - if (!dentry) { - dev_err(uhci_dev(uhci), "couldn't create uhci debugfs entry\n"); - return -ENOMEM; - } - uhci->dentry = dentry; -#endif - - uhci->frame = dma_alloc_coherent(uhci_dev(uhci), - UHCI_NUMFRAMES * sizeof(*uhci->frame), - &uhci->frame_dma_handle, 0); - if (!uhci->frame) { - dev_err(uhci_dev(uhci), "unable to allocate " - "consistent memory for frame list\n"); - goto err_alloc_frame; - } - memset(uhci->frame, 0, UHCI_NUMFRAMES * sizeof(*uhci->frame)); - - uhci->frame_cpu = kcalloc(UHCI_NUMFRAMES, sizeof(*uhci->frame_cpu), - GFP_KERNEL); - if (!uhci->frame_cpu) { - dev_err(uhci_dev(uhci), "unable to allocate " - "memory for frame pointers\n"); - goto err_alloc_frame_cpu; - } - - uhci->td_pool = dma_pool_create("uhci_td", uhci_dev(uhci), - sizeof(struct uhci_td), 16, 0); - if (!uhci->td_pool) { - dev_err(uhci_dev(uhci), "unable to create td dma_pool\n"); - goto err_create_td_pool; - } - - uhci->qh_pool = dma_pool_create("uhci_qh", uhci_dev(uhci), - sizeof(struct uhci_qh), 16, 0); - if (!uhci->qh_pool) { - dev_err(uhci_dev(uhci), "unable to create qh dma_pool\n"); - goto err_create_qh_pool; - } - - uhci->term_td = uhci_alloc_td(uhci); - if (!uhci->term_td) { - dev_err(uhci_dev(uhci), "unable to allocate terminating TD\n"); - goto err_alloc_term_td; - } - - for (i = 0; i < UHCI_NUM_SKELQH; i++) { - uhci->skelqh[i] = uhci_alloc_qh(uhci, NULL, NULL); - if (!uhci->skelqh[i]) { - dev_err(uhci_dev(uhci), "unable to allocate QH\n"); - goto err_alloc_skelqh; - } - } - - /* - * 8 Interrupt queues; link all higher int queues to int1 = async - */ - for (i = SKEL_ISO + 1; i < SKEL_ASYNC; ++i) - uhci->skelqh[i]->link = LINK_TO_QH(uhci, uhci->skel_async_qh); - uhci->skel_async_qh->link = UHCI_PTR_TERM(uhci); - uhci->skel_term_qh->link = LINK_TO_QH(uhci, uhci->skel_term_qh); - - /* This dummy TD is to work around a bug in Intel PIIX controllers */ - uhci_fill_td(uhci, uhci->term_td, 0, uhci_explen(0) | - (0x7f << TD_TOKEN_DEVADDR_SHIFT) | USB_PID_IN, 0); - uhci->term_td->link = UHCI_PTR_TERM(uhci); - uhci->skel_async_qh->element = uhci->skel_term_qh->element = - LINK_TO_TD(uhci, uhci->term_td); - - /* - * Fill the frame list: make all entries point to the proper - * interrupt queue. - */ - for (i = 0; i < UHCI_NUMFRAMES; i++) { - - /* Only place we don't use the frame list routines */ - uhci->frame[i] = uhci_frame_skel_link(uhci, i); - } - - /* - * Some architectures require a full mb() to enforce completion of - * the memory writes above before the I/O transfers in configure_hc(). - */ - mb(); - - configure_hc(uhci); - uhci->is_initialized = 1; - spin_lock_irq(&uhci->lock); - start_rh(uhci); - spin_unlock_irq(&uhci->lock); - return 0; - -/* - * error exits: - */ -err_alloc_skelqh: - for (i = 0; i < UHCI_NUM_SKELQH; i++) { - if (uhci->skelqh[i]) - uhci_free_qh(uhci, uhci->skelqh[i]); - } - - uhci_free_td(uhci, uhci->term_td); - -err_alloc_term_td: - dma_pool_destroy(uhci->qh_pool); - -err_create_qh_pool: - dma_pool_destroy(uhci->td_pool); - -err_create_td_pool: - kfree(uhci->frame_cpu); - -err_alloc_frame_cpu: - dma_free_coherent(uhci_dev(uhci), - UHCI_NUMFRAMES * sizeof(*uhci->frame), - uhci->frame, uhci->frame_dma_handle); - -err_alloc_frame: - debugfs_remove(uhci->dentry); - - return retval; -} - -static void uhci_stop(struct usb_hcd *hcd) -{ - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - - spin_lock_irq(&uhci->lock); - if (HCD_HW_ACCESSIBLE(hcd) && !uhci->dead) - uhci_hc_died(uhci); - uhci_scan_schedule(uhci); - spin_unlock_irq(&uhci->lock); - synchronize_irq(hcd->irq); - - del_timer_sync(&uhci->fsbr_timer); - release_uhci(uhci); -} - -#ifdef CONFIG_PM -static int uhci_rh_suspend(struct usb_hcd *hcd) -{ - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - int rc = 0; - - spin_lock_irq(&uhci->lock); - if (!HCD_HW_ACCESSIBLE(hcd)) - rc = -ESHUTDOWN; - else if (uhci->dead) - ; /* Dead controllers tell no tales */ - - /* Once the controller is stopped, port resumes that are already - * in progress won't complete. Hence if remote wakeup is enabled - * for the root hub and any ports are in the middle of a resume or - * remote wakeup, we must fail the suspend. - */ - else if (hcd->self.root_hub->do_remote_wakeup && - uhci->resuming_ports) { - dev_dbg(uhci_dev(uhci), "suspend failed because a port " - "is resuming\n"); - rc = -EBUSY; - } else - suspend_rh(uhci, UHCI_RH_SUSPENDED); - spin_unlock_irq(&uhci->lock); - return rc; -} - -static int uhci_rh_resume(struct usb_hcd *hcd) -{ - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - int rc = 0; - - spin_lock_irq(&uhci->lock); - if (!HCD_HW_ACCESSIBLE(hcd)) - rc = -ESHUTDOWN; - else if (!uhci->dead) - wakeup_rh(uhci); - spin_unlock_irq(&uhci->lock); - return rc; -} - -#endif - -/* Wait until a particular device/endpoint's QH is idle, and free it */ -static void uhci_hcd_endpoint_disable(struct usb_hcd *hcd, - struct usb_host_endpoint *hep) -{ - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - struct uhci_qh *qh; - - spin_lock_irq(&uhci->lock); - qh = (struct uhci_qh *) hep->hcpriv; - if (qh == NULL) - goto done; - - while (qh->state != QH_STATE_IDLE) { - ++uhci->num_waiting; - spin_unlock_irq(&uhci->lock); - wait_event_interruptible(uhci->waitqh, - qh->state == QH_STATE_IDLE); - spin_lock_irq(&uhci->lock); - --uhci->num_waiting; - } - - uhci_free_qh(uhci, qh); -done: - spin_unlock_irq(&uhci->lock); -} - -static int uhci_hcd_get_frame_number(struct usb_hcd *hcd) -{ - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - unsigned frame_number; - unsigned delta; - - /* Minimize latency by avoiding the spinlock */ - frame_number = uhci->frame_number; - barrier(); - delta = (uhci_readw(uhci, USBFRNUM) - frame_number) & - (UHCI_NUMFRAMES - 1); - return frame_number + delta; -} - -/* Determines number of ports on controller */ -static int uhci_count_ports(struct usb_hcd *hcd) -{ - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - unsigned io_size = (unsigned) hcd->rsrc_len; - int port; - - /* The UHCI spec says devices must have 2 ports, and goes on to say - * they may have more but gives no way to determine how many there - * are. However according to the UHCI spec, Bit 7 of the port - * status and control register is always set to 1. So we try to - * use this to our advantage. Another common failure mode when - * a nonexistent register is addressed is to return all ones, so - * we test for that also. - */ - for (port = 0; port < (io_size - USBPORTSC1) / 2; port++) { - unsigned int portstatus; - - portstatus = uhci_readw(uhci, USBPORTSC1 + (port * 2)); - if (!(portstatus & 0x0080) || portstatus == 0xffff) - break; - } - if (debug) - dev_info(uhci_dev(uhci), "detected %d ports\n", port); - - /* Anything greater than 7 is weird so we'll ignore it. */ - if (port > UHCI_RH_MAXCHILD) { - dev_info(uhci_dev(uhci), "port count misdetected? " - "forcing to 2 ports\n"); - port = 2; - } - - return port; -} - -static const char hcd_name[] = "uhci_hcd"; - -#ifdef CONFIG_PCI -#include "uhci-pci.c" -#define PCI_DRIVER uhci_pci_driver -#endif - -#ifdef CONFIG_SPARC_LEON -#include "uhci-grlib.c" -#define PLATFORM_DRIVER uhci_grlib_driver -#endif - -#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) -#error "missing bus glue for uhci-hcd" -#endif - -static int __init uhci_hcd_init(void) -{ - int retval = -ENOMEM; - - if (usb_disabled()) - return -ENODEV; - - printk(KERN_INFO "uhci_hcd: " DRIVER_DESC "%s\n", - ignore_oc ? ", overcurrent ignored" : ""); - set_bit(USB_UHCI_LOADED, &usb_hcds_loaded); - - if (DEBUG_CONFIGURED) { - errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL); - if (!errbuf) - goto errbuf_failed; - uhci_debugfs_root = debugfs_create_dir("uhci", usb_debug_root); - if (!uhci_debugfs_root) - goto debug_failed; - } - - uhci_up_cachep = kmem_cache_create("uhci_urb_priv", - sizeof(struct urb_priv), 0, 0, NULL); - if (!uhci_up_cachep) - goto up_failed; - -#ifdef PLATFORM_DRIVER - retval = platform_driver_register(&PLATFORM_DRIVER); - if (retval < 0) - goto clean0; -#endif - -#ifdef PCI_DRIVER - retval = pci_register_driver(&PCI_DRIVER); - if (retval < 0) - goto clean1; -#endif - - return 0; - -#ifdef PCI_DRIVER -clean1: -#endif -#ifdef PLATFORM_DRIVER - platform_driver_unregister(&PLATFORM_DRIVER); -clean0: -#endif - kmem_cache_destroy(uhci_up_cachep); - -up_failed: - debugfs_remove(uhci_debugfs_root); - -debug_failed: - kfree(errbuf); - -errbuf_failed: - - clear_bit(USB_UHCI_LOADED, &usb_hcds_loaded); - return retval; -} - -static void __exit uhci_hcd_cleanup(void) -{ -#ifdef PLATFORM_DRIVER - platform_driver_unregister(&PLATFORM_DRIVER); -#endif -#ifdef PCI_DRIVER - pci_unregister_driver(&PCI_DRIVER); -#endif - kmem_cache_destroy(uhci_up_cachep); - debugfs_remove(uhci_debugfs_root); - kfree(errbuf); - clear_bit(USB_UHCI_LOADED, &usb_hcds_loaded); -} - -module_init(uhci_hcd_init); -module_exit(uhci_hcd_cleanup); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/host/uhci-hcd.h b/ANDROID_3.4.5/drivers/usb/host/uhci-hcd.h deleted file mode 100644 index 7af2b705..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/uhci-hcd.h +++ /dev/null @@ -1,664 +0,0 @@ -#ifndef __LINUX_UHCI_HCD_H -#define __LINUX_UHCI_HCD_H - -#include -#include - -#define usb_packetid(pipe) (usb_pipein(pipe) ? USB_PID_IN : USB_PID_OUT) -#define PIPE_DEVEP_MASK 0x0007ff00 - - -/* - * Universal Host Controller Interface data structures and defines - */ - -/* Command register */ -#define USBCMD 0 -#define USBCMD_RS 0x0001 /* Run/Stop */ -#define USBCMD_HCRESET 0x0002 /* Host reset */ -#define USBCMD_GRESET 0x0004 /* Global reset */ -#define USBCMD_EGSM 0x0008 /* Global Suspend Mode */ -#define USBCMD_FGR 0x0010 /* Force Global Resume */ -#define USBCMD_SWDBG 0x0020 /* SW Debug mode */ -#define USBCMD_CF 0x0040 /* Config Flag (sw only) */ -#define USBCMD_MAXP 0x0080 /* Max Packet (0 = 32, 1 = 64) */ - -/* Status register */ -#define USBSTS 2 -#define USBSTS_USBINT 0x0001 /* Interrupt due to IOC */ -#define USBSTS_ERROR 0x0002 /* Interrupt due to error */ -#define USBSTS_RD 0x0004 /* Resume Detect */ -#define USBSTS_HSE 0x0008 /* Host System Error: PCI problems */ -#define USBSTS_HCPE 0x0010 /* Host Controller Process Error: - * the schedule is buggy */ -#define USBSTS_HCH 0x0020 /* HC Halted */ - -/* Interrupt enable register */ -#define USBINTR 4 -#define USBINTR_TIMEOUT 0x0001 /* Timeout/CRC error enable */ -#define USBINTR_RESUME 0x0002 /* Resume interrupt enable */ -#define USBINTR_IOC 0x0004 /* Interrupt On Complete enable */ -#define USBINTR_SP 0x0008 /* Short packet interrupt enable */ - -#define USBFRNUM 6 -#define USBFLBASEADD 8 -#define USBSOF 12 -#define USBSOF_DEFAULT 64 /* Frame length is exactly 1 ms */ - -/* USB port status and control registers */ -#define USBPORTSC1 16 -#define USBPORTSC2 18 -#define USBPORTSC_CCS 0x0001 /* Current Connect Status - * ("device present") */ -#define USBPORTSC_CSC 0x0002 /* Connect Status Change */ -#define USBPORTSC_PE 0x0004 /* Port Enable */ -#define USBPORTSC_PEC 0x0008 /* Port Enable Change */ -#define USBPORTSC_DPLUS 0x0010 /* D+ high (line status) */ -#define USBPORTSC_DMINUS 0x0020 /* D- high (line status) */ -#define USBPORTSC_RD 0x0040 /* Resume Detect */ -#define USBPORTSC_RES1 0x0080 /* reserved, always 1 */ -#define USBPORTSC_LSDA 0x0100 /* Low Speed Device Attached */ -#define USBPORTSC_PR 0x0200 /* Port Reset */ -/* OC and OCC from Intel 430TX and later (not UHCI 1.1d spec) */ -#define USBPORTSC_OC 0x0400 /* Over Current condition */ -#define USBPORTSC_OCC 0x0800 /* Over Current Change R/WC */ -#define USBPORTSC_SUSP 0x1000 /* Suspend */ -#define USBPORTSC_RES2 0x2000 /* reserved, write zeroes */ -#define USBPORTSC_RES3 0x4000 /* reserved, write zeroes */ -#define USBPORTSC_RES4 0x8000 /* reserved, write zeroes */ - -/* PCI legacy support register */ -#define USBLEGSUP 0xc0 -#define USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */ -#define USBLEGSUP_RWC 0x8f00 /* the R/WC bits */ -#define USBLEGSUP_RO 0x5040 /* R/O and reserved bits */ - -/* PCI Intel-specific resume-enable register */ -#define USBRES_INTEL 0xc4 -#define USBPORT1EN 0x01 -#define USBPORT2EN 0x02 - -#define UHCI_PTR_BITS(uhci) cpu_to_hc32((uhci), 0x000F) -#define UHCI_PTR_TERM(uhci) cpu_to_hc32((uhci), 0x0001) -#define UHCI_PTR_QH(uhci) cpu_to_hc32((uhci), 0x0002) -#define UHCI_PTR_DEPTH(uhci) cpu_to_hc32((uhci), 0x0004) -#define UHCI_PTR_BREADTH(uhci) cpu_to_hc32((uhci), 0x0000) - -#define UHCI_NUMFRAMES 1024 /* in the frame list [array] */ -#define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */ -#define CAN_SCHEDULE_FRAMES 1000 /* how far in the future frames - * can be scheduled */ -#define MAX_PHASE 32 /* Periodic scheduling length */ - -/* When no queues need Full-Speed Bandwidth Reclamation, - * delay this long before turning FSBR off */ -#define FSBR_OFF_DELAY msecs_to_jiffies(10) - -/* If a queue hasn't advanced after this much time, assume it is stuck */ -#define QH_WAIT_TIMEOUT msecs_to_jiffies(200) - - -/* - * __hc32 and __hc16 are "Host Controller" types, they may be equivalent to - * __leXX (normally) or __beXX (given UHCI_BIG_ENDIAN_DESC), depending on - * the host controller implementation. - * - * To facilitate the strongest possible byte-order checking from "sparse" - * and so on, we use __leXX unless that's not practical. - */ -#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_DESC -typedef __u32 __bitwise __hc32; -typedef __u16 __bitwise __hc16; -#else -#define __hc32 __le32 -#define __hc16 __le16 -#endif - -/* - * Queue Headers - */ - -/* - * One role of a QH is to hold a queue of TDs for some endpoint. One QH goes - * with each endpoint, and qh->element (updated by the HC) is either: - * - the next unprocessed TD in the endpoint's queue, or - * - UHCI_PTR_TERM (when there's no more traffic for this endpoint). - * - * The other role of a QH is to serve as a "skeleton" framelist entry, so we - * can easily splice a QH for some endpoint into the schedule at the right - * place. Then qh->element is UHCI_PTR_TERM. - * - * In the schedule, qh->link maintains a list of QHs seen by the HC: - * skel1 --> ep1-qh --> ep2-qh --> ... --> skel2 --> ... - * - * qh->node is the software equivalent of qh->link. The differences - * are that the software list is doubly-linked and QHs in the UNLINKING - * state are on the software list but not the hardware schedule. - * - * For bookkeeping purposes we maintain QHs even for Isochronous endpoints, - * but they never get added to the hardware schedule. - */ -#define QH_STATE_IDLE 1 /* QH is not being used */ -#define QH_STATE_UNLINKING 2 /* QH has been removed from the - * schedule but the hardware may - * still be using it */ -#define QH_STATE_ACTIVE 3 /* QH is on the schedule */ - -struct uhci_qh { - /* Hardware fields */ - __hc32 link; /* Next QH in the schedule */ - __hc32 element; /* Queue element (TD) pointer */ - - /* Software fields */ - dma_addr_t dma_handle; - - struct list_head node; /* Node in the list of QHs */ - struct usb_host_endpoint *hep; /* Endpoint information */ - struct usb_device *udev; - struct list_head queue; /* Queue of urbps for this QH */ - struct uhci_td *dummy_td; /* Dummy TD to end the queue */ - struct uhci_td *post_td; /* Last TD completed */ - - struct usb_iso_packet_descriptor *iso_packet_desc; - /* Next urb->iso_frame_desc entry */ - unsigned long advance_jiffies; /* Time of last queue advance */ - unsigned int unlink_frame; /* When the QH was unlinked */ - unsigned int period; /* For Interrupt and Isochronous QHs */ - short phase; /* Between 0 and period-1 */ - short load; /* Periodic time requirement, in us */ - unsigned int iso_frame; /* Frame # for iso_packet_desc */ - - int state; /* QH_STATE_xxx; see above */ - int type; /* Queue type (control, bulk, etc) */ - int skel; /* Skeleton queue number */ - - unsigned int initial_toggle:1; /* Endpoint's current toggle value */ - unsigned int needs_fixup:1; /* Must fix the TD toggle values */ - unsigned int is_stopped:1; /* Queue was stopped by error/unlink */ - unsigned int wait_expired:1; /* QH_WAIT_TIMEOUT has expired */ - unsigned int bandwidth_reserved:1; /* Periodic bandwidth has - * been allocated */ -} __attribute__((aligned(16))); - -/* - * We need a special accessor for the element pointer because it is - * subject to asynchronous updates by the controller. - */ -#define qh_element(qh) ACCESS_ONCE((qh)->element) - -#define LINK_TO_QH(uhci, qh) (UHCI_PTR_QH((uhci)) | \ - cpu_to_hc32((uhci), (qh)->dma_handle)) - - -/* - * Transfer Descriptors - */ - -/* - * for TD : - */ -#define TD_CTRL_SPD (1 << 29) /* Short Packet Detect */ -#define TD_CTRL_C_ERR_MASK (3 << 27) /* Error Counter bits */ -#define TD_CTRL_C_ERR_SHIFT 27 -#define TD_CTRL_LS (1 << 26) /* Low Speed Device */ -#define TD_CTRL_IOS (1 << 25) /* Isochronous Select */ -#define TD_CTRL_IOC (1 << 24) /* Interrupt on Complete */ -#define TD_CTRL_ACTIVE (1 << 23) /* TD Active */ -#define TD_CTRL_STALLED (1 << 22) /* TD Stalled */ -#define TD_CTRL_DBUFERR (1 << 21) /* Data Buffer Error */ -#define TD_CTRL_BABBLE (1 << 20) /* Babble Detected */ -#define TD_CTRL_NAK (1 << 19) /* NAK Received */ -#define TD_CTRL_CRCTIMEO (1 << 18) /* CRC/Time Out Error */ -#define TD_CTRL_BITSTUFF (1 << 17) /* Bit Stuff Error */ -#define TD_CTRL_ACTLEN_MASK 0x7FF /* actual length, encoded as n - 1 */ - -#define TD_CTRL_ANY_ERROR (TD_CTRL_STALLED | TD_CTRL_DBUFERR | \ - TD_CTRL_BABBLE | TD_CTRL_CRCTIME | \ - TD_CTRL_BITSTUFF) - -#define uhci_maxerr(err) ((err) << TD_CTRL_C_ERR_SHIFT) -#define uhci_status_bits(ctrl_sts) ((ctrl_sts) & 0xF60000) -#define uhci_actual_length(ctrl_sts) (((ctrl_sts) + 1) & \ - TD_CTRL_ACTLEN_MASK) /* 1-based */ - -/* - * for TD : (a.k.a. Token) - */ -#define td_token(uhci, td) hc32_to_cpu((uhci), (td)->token) -#define TD_TOKEN_DEVADDR_SHIFT 8 -#define TD_TOKEN_TOGGLE_SHIFT 19 -#define TD_TOKEN_TOGGLE (1 << 19) -#define TD_TOKEN_EXPLEN_SHIFT 21 -#define TD_TOKEN_EXPLEN_MASK 0x7FF /* expected length, encoded as n-1 */ -#define TD_TOKEN_PID_MASK 0xFF - -#define uhci_explen(len) ((((len) - 1) & TD_TOKEN_EXPLEN_MASK) << \ - TD_TOKEN_EXPLEN_SHIFT) - -#define uhci_expected_length(token) ((((token) >> TD_TOKEN_EXPLEN_SHIFT) + \ - 1) & TD_TOKEN_EXPLEN_MASK) -#define uhci_toggle(token) (((token) >> TD_TOKEN_TOGGLE_SHIFT) & 1) -#define uhci_endpoint(token) (((token) >> 15) & 0xf) -#define uhci_devaddr(token) (((token) >> TD_TOKEN_DEVADDR_SHIFT) & 0x7f) -#define uhci_devep(token) (((token) >> TD_TOKEN_DEVADDR_SHIFT) & 0x7ff) -#define uhci_packetid(token) ((token) & TD_TOKEN_PID_MASK) -#define uhci_packetout(token) (uhci_packetid(token) != USB_PID_IN) -#define uhci_packetin(token) (uhci_packetid(token) == USB_PID_IN) - -/* - * The documentation says "4 words for hardware, 4 words for software". - * - * That's silly, the hardware doesn't care. The hardware only cares that - * the hardware words are 16-byte aligned, and we can have any amount of - * sw space after the TD entry. - * - * td->link points to either another TD (not necessarily for the same urb or - * even the same endpoint), or nothing (PTR_TERM), or a QH. - */ -struct uhci_td { - /* Hardware fields */ - __hc32 link; - __hc32 status; - __hc32 token; - __hc32 buffer; - - /* Software fields */ - dma_addr_t dma_handle; - - struct list_head list; - - int frame; /* for iso: what frame? */ - struct list_head fl_list; -} __attribute__((aligned(16))); - -/* - * We need a special accessor for the control/status word because it is - * subject to asynchronous updates by the controller. - */ -#define td_status(uhci, td) hc32_to_cpu((uhci), \ - ACCESS_ONCE((td)->status)) - -#define LINK_TO_TD(uhci, td) (cpu_to_hc32((uhci), (td)->dma_handle)) - - -/* - * Skeleton Queue Headers - */ - -/* - * The UHCI driver uses QHs with Interrupt, Control and Bulk URBs for - * automatic queuing. To make it easy to insert entries into the schedule, - * we have a skeleton of QHs for each predefined Interrupt latency. - * Asynchronous QHs (low-speed control, full-speed control, and bulk) - * go onto the period-1 interrupt list, since they all get accessed on - * every frame. - * - * When we want to add a new QH, we add it to the list starting from the - * appropriate skeleton QH. For instance, the schedule can look like this: - * - * skel int128 QH - * dev 1 interrupt QH - * dev 5 interrupt QH - * skel int64 QH - * skel int32 QH - * ... - * skel int1 + async QH - * dev 5 low-speed control QH - * dev 1 bulk QH - * dev 2 bulk QH - * - * There is a special terminating QH used to keep full-speed bandwidth - * reclamation active when no full-speed control or bulk QHs are linked - * into the schedule. It has an inactive TD (to work around a PIIX bug, - * see the Intel errata) and it points back to itself. - * - * There's a special skeleton QH for Isochronous QHs which never appears - * on the schedule. Isochronous TDs go on the schedule before the - * the skeleton QHs. The hardware accesses them directly rather than - * through their QH, which is used only for bookkeeping purposes. - * While the UHCI spec doesn't forbid the use of QHs for Isochronous, - * it doesn't use them either. And the spec says that queues never - * advance on an error completion status, which makes them totally - * unsuitable for Isochronous transfers. - * - * There's also a special skeleton QH used for QHs which are in the process - * of unlinking and so may still be in use by the hardware. It too never - * appears on the schedule. - */ - -#define UHCI_NUM_SKELQH 11 -#define SKEL_UNLINK 0 -#define skel_unlink_qh skelqh[SKEL_UNLINK] -#define SKEL_ISO 1 -#define skel_iso_qh skelqh[SKEL_ISO] - /* int128, int64, ..., int1 = 2, 3, ..., 9 */ -#define SKEL_INDEX(exponent) (9 - exponent) -#define SKEL_ASYNC 9 -#define skel_async_qh skelqh[SKEL_ASYNC] -#define SKEL_TERM 10 -#define skel_term_qh skelqh[SKEL_TERM] - -/* The following entries refer to sublists of skel_async_qh */ -#define SKEL_LS_CONTROL 20 -#define SKEL_FS_CONTROL 21 -#define SKEL_FSBR SKEL_FS_CONTROL -#define SKEL_BULK 22 - -/* - * The UHCI controller and root hub - */ - -/* - * States for the root hub: - * - * To prevent "bouncing" in the presence of electrical noise, - * when there are no devices attached we delay for 1 second in the - * RUNNING_NODEVS state before switching to the AUTO_STOPPED state. - * - * (Note that the AUTO_STOPPED state won't be necessary once the hub - * driver learns to autosuspend.) - */ -enum uhci_rh_state { - /* In the following states the HC must be halted. - * These two must come first. */ - UHCI_RH_RESET, - UHCI_RH_SUSPENDED, - - UHCI_RH_AUTO_STOPPED, - UHCI_RH_RESUMING, - - /* In this state the HC changes from running to halted, - * so it can legally appear either way. */ - UHCI_RH_SUSPENDING, - - /* In the following states it's an error if the HC is halted. - * These two must come last. */ - UHCI_RH_RUNNING, /* The normal state */ - UHCI_RH_RUNNING_NODEVS, /* Running with no devices attached */ -}; - -/* - * The full UHCI controller information: - */ -struct uhci_hcd { - - /* debugfs */ - struct dentry *dentry; - - /* Grabbed from PCI */ - unsigned long io_addr; - - /* Used when registers are memory mapped */ - void __iomem *regs; - - struct dma_pool *qh_pool; - struct dma_pool *td_pool; - - struct uhci_td *term_td; /* Terminating TD, see UHCI bug */ - struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QHs */ - struct uhci_qh *next_qh; /* Next QH to scan */ - - spinlock_t lock; - - dma_addr_t frame_dma_handle; /* Hardware frame list */ - __hc32 *frame; - void **frame_cpu; /* CPU's frame list */ - - enum uhci_rh_state rh_state; - unsigned long auto_stop_time; /* When to AUTO_STOP */ - - unsigned int frame_number; /* As of last check */ - unsigned int is_stopped; -#define UHCI_IS_STOPPED 9999 /* Larger than a frame # */ - unsigned int last_iso_frame; /* Frame of last scan */ - unsigned int cur_iso_frame; /* Frame for current scan */ - - unsigned int scan_in_progress:1; /* Schedule scan is running */ - unsigned int need_rescan:1; /* Redo the schedule scan */ - unsigned int dead:1; /* Controller has died */ - unsigned int RD_enable:1; /* Suspended root hub with - Resume-Detect interrupts - enabled */ - unsigned int is_initialized:1; /* Data structure is usable */ - unsigned int fsbr_is_on:1; /* FSBR is turned on */ - unsigned int fsbr_is_wanted:1; /* Does any URB want FSBR? */ - unsigned int fsbr_expiring:1; /* FSBR is timing out */ - - struct timer_list fsbr_timer; /* For turning off FBSR */ - - /* Silicon quirks */ - unsigned int oc_low:1; /* OverCurrent bit active low */ - unsigned int wait_for_hp:1; /* Wait for HP port reset */ - unsigned int big_endian_mmio:1; /* Big endian registers */ - unsigned int big_endian_desc:1; /* Big endian descriptors */ - - /* Support for port suspend/resume/reset */ - unsigned long port_c_suspend; /* Bit-arrays of ports */ - unsigned long resuming_ports; - unsigned long ports_timeout; /* Time to stop signalling */ - - struct list_head idle_qh_list; /* Where the idle QHs live */ - - int rh_numports; /* Number of root-hub ports */ - - wait_queue_head_t waitqh; /* endpoint_disable waiters */ - int num_waiting; /* Number of waiters */ - - int total_load; /* Sum of array values */ - short load[MAX_PHASE]; /* Periodic allocations */ - - /* Reset host controller */ - void (*reset_hc) (struct uhci_hcd *uhci); - int (*check_and_reset_hc) (struct uhci_hcd *uhci); - /* configure_hc should perform arch specific settings, if needed */ - void (*configure_hc) (struct uhci_hcd *uhci); - /* Check for broken resume detect interrupts */ - int (*resume_detect_interrupts_are_broken) (struct uhci_hcd *uhci); - /* Check for broken global suspend */ - int (*global_suspend_mode_is_broken) (struct uhci_hcd *uhci); -}; - -/* Convert between a usb_hcd pointer and the corresponding uhci_hcd */ -static inline struct uhci_hcd *hcd_to_uhci(struct usb_hcd *hcd) -{ - return (struct uhci_hcd *) (hcd->hcd_priv); -} -static inline struct usb_hcd *uhci_to_hcd(struct uhci_hcd *uhci) -{ - return container_of((void *) uhci, struct usb_hcd, hcd_priv); -} - -#define uhci_dev(u) (uhci_to_hcd(u)->self.controller) - -/* Utility macro for comparing frame numbers */ -#define uhci_frame_before_eq(f1, f2) (0 <= (int) ((f2) - (f1))) - - -/* - * Private per-URB data - */ -struct urb_priv { - struct list_head node; /* Node in the QH's urbp list */ - - struct urb *urb; - - struct uhci_qh *qh; /* QH for this URB */ - struct list_head td_list; - - unsigned fsbr:1; /* URB wants FSBR */ -}; - - -/* Some special IDs */ - -#define PCI_VENDOR_ID_GENESYS 0x17a0 -#define PCI_DEVICE_ID_GL880S_UHCI 0x8083 - -/* - * Functions used to access controller registers. The UCHI spec says that host - * controller I/O registers are mapped into PCI I/O space. For non-PCI hosts - * we use memory mapped registers. - */ - -#ifndef CONFIG_USB_UHCI_SUPPORT_NON_PCI_HC -/* Support PCI only */ -static inline u32 uhci_readl(const struct uhci_hcd *uhci, int reg) -{ - return inl(uhci->io_addr + reg); -} - -static inline void uhci_writel(const struct uhci_hcd *uhci, u32 val, int reg) -{ - outl(val, uhci->io_addr + reg); -} - -static inline u16 uhci_readw(const struct uhci_hcd *uhci, int reg) -{ - return inw(uhci->io_addr + reg); -} - -static inline void uhci_writew(const struct uhci_hcd *uhci, u16 val, int reg) -{ - outw(val, uhci->io_addr + reg); -} - -static inline u8 uhci_readb(const struct uhci_hcd *uhci, int reg) -{ - return inb(uhci->io_addr + reg); -} - -static inline void uhci_writeb(const struct uhci_hcd *uhci, u8 val, int reg) -{ - outb(val, uhci->io_addr + reg); -} - -#else -/* Support non-PCI host controllers */ -#ifdef CONFIG_PCI -/* Support PCI and non-PCI host controllers */ -#define uhci_has_pci_registers(u) ((u)->io_addr != 0) -#else -/* Support non-PCI host controllers only */ -#define uhci_has_pci_registers(u) 0 -#endif - -#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO -/* Support (non-PCI) big endian host controllers */ -#define uhci_big_endian_mmio(u) ((u)->big_endian_mmio) -#else -#define uhci_big_endian_mmio(u) 0 -#endif - -static inline u32 uhci_readl(const struct uhci_hcd *uhci, int reg) -{ - if (uhci_has_pci_registers(uhci)) - return inl(uhci->io_addr + reg); -#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO - else if (uhci_big_endian_mmio(uhci)) - return readl_be(uhci->regs + reg); -#endif - else - return readl(uhci->regs + reg); -} - -static inline void uhci_writel(const struct uhci_hcd *uhci, u32 val, int reg) -{ - if (uhci_has_pci_registers(uhci)) - outl(val, uhci->io_addr + reg); -#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO - else if (uhci_big_endian_mmio(uhci)) - writel_be(val, uhci->regs + reg); -#endif - else - writel(val, uhci->regs + reg); -} - -static inline u16 uhci_readw(const struct uhci_hcd *uhci, int reg) -{ - if (uhci_has_pci_registers(uhci)) - return inw(uhci->io_addr + reg); -#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO - else if (uhci_big_endian_mmio(uhci)) - return readw_be(uhci->regs + reg); -#endif - else - return readw(uhci->regs + reg); -} - -static inline void uhci_writew(const struct uhci_hcd *uhci, u16 val, int reg) -{ - if (uhci_has_pci_registers(uhci)) - outw(val, uhci->io_addr + reg); -#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO - else if (uhci_big_endian_mmio(uhci)) - writew_be(val, uhci->regs + reg); -#endif - else - writew(val, uhci->regs + reg); -} - -static inline u8 uhci_readb(const struct uhci_hcd *uhci, int reg) -{ - if (uhci_has_pci_registers(uhci)) - return inb(uhci->io_addr + reg); -#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO - else if (uhci_big_endian_mmio(uhci)) - return readb_be(uhci->regs + reg); -#endif - else - return readb(uhci->regs + reg); -} - -static inline void uhci_writeb(const struct uhci_hcd *uhci, u8 val, int reg) -{ - if (uhci_has_pci_registers(uhci)) - outb(val, uhci->io_addr + reg); -#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_MMIO - else if (uhci_big_endian_mmio(uhci)) - writeb_be(val, uhci->regs + reg); -#endif - else - writeb(val, uhci->regs + reg); -} -#endif /* CONFIG_USB_UHCI_SUPPORT_NON_PCI_HC */ - -/* - * The GRLIB GRUSBHC controller can use big endian format for its descriptors. - * - * UHCI controllers accessed through PCI work normally (little-endian - * everywhere), so we don't bother supporting a BE-only mode. - */ -#ifdef CONFIG_USB_UHCI_BIG_ENDIAN_DESC -#define uhci_big_endian_desc(u) ((u)->big_endian_desc) - -/* cpu to uhci */ -static inline __hc32 cpu_to_hc32(const struct uhci_hcd *uhci, const u32 x) -{ - return uhci_big_endian_desc(uhci) - ? (__force __hc32)cpu_to_be32(x) - : (__force __hc32)cpu_to_le32(x); -} - -/* uhci to cpu */ -static inline u32 hc32_to_cpu(const struct uhci_hcd *uhci, const __hc32 x) -{ - return uhci_big_endian_desc(uhci) - ? be32_to_cpu((__force __be32)x) - : le32_to_cpu((__force __le32)x); -} - -#else -/* cpu to uhci */ -static inline __hc32 cpu_to_hc32(const struct uhci_hcd *uhci, const u32 x) -{ - return cpu_to_le32(x); -} - -/* uhci to cpu */ -static inline u32 hc32_to_cpu(const struct uhci_hcd *uhci, const __hc32 x) -{ - return le32_to_cpu(x); -} -#endif - -#endif diff --git a/ANDROID_3.4.5/drivers/usb/host/uhci-hub.c b/ANDROID_3.4.5/drivers/usb/host/uhci-hub.c deleted file mode 100644 index fb0da10f..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/uhci-hub.c +++ /dev/null @@ -1,421 +0,0 @@ -/* - * Universal Host Controller Interface driver for USB. - * - * Maintainer: Alan Stern - * - * (C) Copyright 1999 Linus Torvalds - * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com - * (C) Copyright 1999 Randy Dunlap - * (C) Copyright 1999 Georg Acher, acher@in.tum.de - * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de - * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch - * (C) Copyright 2004 Alan Stern, stern@rowland.harvard.edu - */ - -static const __u8 root_hub_hub_des[] = -{ - 0x09, /* __u8 bLength; */ - 0x29, /* __u8 bDescriptorType; Hub-descriptor */ - 0x02, /* __u8 bNbrPorts; */ - 0x0a, /* __u16 wHubCharacteristics; */ - 0x00, /* (per-port OC, no power switching) */ - 0x01, /* __u8 bPwrOn2pwrGood; 2ms */ - 0x00, /* __u8 bHubContrCurrent; 0 mA */ - 0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */ - 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */ -}; - -#define UHCI_RH_MAXCHILD 7 - -/* must write as zeroes */ -#define WZ_BITS (USBPORTSC_RES2 | USBPORTSC_RES3 | USBPORTSC_RES4) - -/* status change bits: nonzero writes will clear */ -#define RWC_BITS (USBPORTSC_OCC | USBPORTSC_PEC | USBPORTSC_CSC) - -/* suspend/resume bits: port suspended or port resuming */ -#define SUSPEND_BITS (USBPORTSC_SUSP | USBPORTSC_RD) - -/* A port that either is connected or has a changed-bit set will prevent - * us from AUTO_STOPPING. - */ -static int any_ports_active(struct uhci_hcd *uhci) -{ - int port; - - for (port = 0; port < uhci->rh_numports; ++port) { - if ((uhci_readw(uhci, USBPORTSC1 + port * 2) & - (USBPORTSC_CCS | RWC_BITS)) || - test_bit(port, &uhci->port_c_suspend)) - return 1; - } - return 0; -} - -static inline int get_hub_status_data(struct uhci_hcd *uhci, char *buf) -{ - int port; - int mask = RWC_BITS; - - /* Some boards (both VIA and Intel apparently) report bogus - * overcurrent indications, causing massive log spam unless - * we completely ignore them. This doesn't seem to be a problem - * with the chipset so much as with the way it is connected on - * the motherboard; if the overcurrent input is left to float - * then it may constantly register false positives. */ - if (ignore_oc) - mask &= ~USBPORTSC_OCC; - - *buf = 0; - for (port = 0; port < uhci->rh_numports; ++port) { - if ((uhci_readw(uhci, USBPORTSC1 + port * 2) & mask) || - test_bit(port, &uhci->port_c_suspend)) - *buf |= (1 << (port + 1)); - } - return !!*buf; -} - -#define OK(x) len = (x); break - -#define CLR_RH_PORTSTAT(x) \ - status = uhci_readw(uhci, port_addr); \ - status &= ~(RWC_BITS|WZ_BITS); \ - status &= ~(x); \ - status |= RWC_BITS & (x); \ - uhci_writew(uhci, status, port_addr) - -#define SET_RH_PORTSTAT(x) \ - status = uhci_readw(uhci, port_addr); \ - status |= (x); \ - status &= ~(RWC_BITS|WZ_BITS); \ - uhci_writew(uhci, status, port_addr) - -/* UHCI controllers don't automatically stop resume signalling after 20 msec, - * so we have to poll and check timeouts in order to take care of it. - */ -static void uhci_finish_suspend(struct uhci_hcd *uhci, int port, - unsigned long port_addr) -{ - int status; - int i; - u16 tmp; - - - if (uhci_readw(uhci, port_addr) & SUSPEND_BITS) { - CLR_RH_PORTSTAT(SUSPEND_BITS); - wmb(); - if (test_bit(port, &uhci->resuming_ports)) - set_bit(port, &uhci->port_c_suspend); - - /* The controller won't actually turn off the RD bit until - * it has had a chance to send a low-speed EOP sequence, - * which is supposed to take 3 bit times (= 2 microseconds). - * Experiments show that some controllers take longer, so - * we'll poll for completion. */ - for (i = 0; i < 10; ++i) { - udelay(1); - tmp = uhci_readw(uhci, port_addr); - //if (!(uhci_readw(uhci, port_addr) & SUSPEND_BITS)){ - //printk("uhci_finish_suspend 01\n"); - if (!(tmp & SUSPEND_BITS)){ - break; - } - } - } - clear_bit(port, &uhci->resuming_ports); -} - -/* Wait for the UHCI controller in HP's iLO2 server management chip. - * It can take up to 250 us to finish a reset and set the CSC bit. - */ -static void wait_for_HP(struct uhci_hcd *uhci, unsigned long port_addr) -{ - int i; - - for (i = 10; i < 250; i += 10) { - if (uhci_readw(uhci, port_addr) & USBPORTSC_CSC) - return; - udelay(10); - } - /* Log a warning? */ -} - -static void uhci_check_ports(struct uhci_hcd *uhci) -{ - unsigned int port; - unsigned long port_addr; - int status; - - for (port = 0; port < uhci->rh_numports; ++port) { - port_addr = USBPORTSC1 + 2 * port; - status = uhci_readw(uhci, port_addr); - if (unlikely(status & USBPORTSC_PR)) { - if (time_after_eq(jiffies, uhci->ports_timeout)) { - CLR_RH_PORTSTAT(USBPORTSC_PR); - udelay(10); - - /* HP's server management chip requires - * a longer delay. */ - if (uhci->wait_for_hp) - wait_for_HP(uhci, port_addr); - - /* If the port was enabled before, turning - * reset on caused a port enable change. - * Turning reset off causes a port connect - * status change. Clear these changes. */ - CLR_RH_PORTSTAT(USBPORTSC_CSC | USBPORTSC_PEC); - SET_RH_PORTSTAT(USBPORTSC_PE); - } - } - if (unlikely(status & USBPORTSC_RD)) { - if (!test_bit(port, &uhci->resuming_ports)) { - - /* Port received a wakeup request */ - set_bit(port, &uhci->resuming_ports); - uhci->ports_timeout = jiffies + - msecs_to_jiffies(25); - - /* Make sure we see the port again - * after the resuming period is over. */ - mod_timer(&uhci_to_hcd(uhci)->rh_timer, - uhci->ports_timeout); - } else if (time_after_eq(jiffies, - uhci->ports_timeout)) { - uhci_finish_suspend(uhci, port, port_addr); - } - } - } -} - -static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf) -{ - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - unsigned long flags; - int status = 0; - - spin_lock_irqsave(&uhci->lock, flags); - - uhci_scan_schedule(uhci); - if (!HCD_HW_ACCESSIBLE(hcd) || uhci->dead) - goto done; - uhci_check_ports(uhci); - - status = get_hub_status_data(uhci, buf); - - switch (uhci->rh_state) { - case UHCI_RH_SUSPENDED: - /* if port change, ask to be resumed */ - if (status || uhci->resuming_ports) { - status = 1; - usb_hcd_resume_root_hub(hcd); - } - break; - - case UHCI_RH_AUTO_STOPPED: - /* if port change, auto start */ - if (status) - wakeup_rh(uhci); - break; - - case UHCI_RH_RUNNING: - /* are any devices attached? */ - if (!any_ports_active(uhci)) { - uhci->rh_state = UHCI_RH_RUNNING_NODEVS; - uhci->auto_stop_time = jiffies + HZ; - } - break; - - case UHCI_RH_RUNNING_NODEVS: - /* auto-stop if nothing connected for 1 second */ - if (any_ports_active(uhci)) - uhci->rh_state = UHCI_RH_RUNNING; - else if (time_after_eq(jiffies, uhci->auto_stop_time)) - suspend_rh(uhci, UHCI_RH_AUTO_STOPPED); - break; - - default: - break; - } - -done: - spin_unlock_irqrestore(&uhci->lock, flags); - return status; -} - -/* size of returned buffer is part of USB spec */ -static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, - u16 wIndex, char *buf, u16 wLength) -{ - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - int status, lstatus, retval = 0, len = 0; - unsigned int port = wIndex - 1; - unsigned long port_addr = USBPORTSC1 + 2 * port; - u16 wPortChange, wPortStatus; - unsigned long flags; - - if (!HCD_HW_ACCESSIBLE(hcd) || uhci->dead) - return -ETIMEDOUT; - - spin_lock_irqsave(&uhci->lock, flags); - switch (typeReq) { - - case GetHubStatus: - *(__le32 *)buf = cpu_to_le32(0); - OK(4); /* hub power */ - case GetPortStatus: - if (port >= uhci->rh_numports) - goto err; - - uhci_check_ports(uhci); - status = uhci_readw(uhci, port_addr); - - /* Intel controllers report the OverCurrent bit active on. - * VIA controllers report it active off, so we'll adjust the - * bit value. (It's not standardized in the UHCI spec.) - */ - if (uhci->oc_low) - status ^= USBPORTSC_OC; - - /* UHCI doesn't support C_RESET (always false) */ - wPortChange = lstatus = 0; - if (status & USBPORTSC_CSC) - wPortChange |= USB_PORT_STAT_C_CONNECTION; - if (status & USBPORTSC_PEC) - wPortChange |= USB_PORT_STAT_C_ENABLE; - if ((status & USBPORTSC_OCC) && !ignore_oc) - wPortChange |= USB_PORT_STAT_C_OVERCURRENT; - - if (test_bit(port, &uhci->port_c_suspend)) { - wPortChange |= USB_PORT_STAT_C_SUSPEND; - lstatus |= 1; - } - if (test_bit(port, &uhci->resuming_ports)) - lstatus |= 4; - - /* UHCI has no power switching (always on) */ - wPortStatus = USB_PORT_STAT_POWER; - if (status & USBPORTSC_CCS) - wPortStatus |= USB_PORT_STAT_CONNECTION; - if (status & USBPORTSC_PE) { - wPortStatus |= USB_PORT_STAT_ENABLE; - if (status & SUSPEND_BITS) - wPortStatus |= USB_PORT_STAT_SUSPEND; - } - if (status & USBPORTSC_OC) - wPortStatus |= USB_PORT_STAT_OVERCURRENT; - if (status & USBPORTSC_PR) - wPortStatus |= USB_PORT_STAT_RESET; - if (status & USBPORTSC_LSDA) - wPortStatus |= USB_PORT_STAT_LOW_SPEED; - - if (wPortChange) - dev_dbg(uhci_dev(uhci), "port %d portsc %04x,%02x\n", - wIndex, status, lstatus); - - *(__le16 *)buf = cpu_to_le16(wPortStatus); - *(__le16 *)(buf + 2) = cpu_to_le16(wPortChange); - OK(4); - case SetHubFeature: /* We don't implement these */ - case ClearHubFeature: - switch (wValue) { - case C_HUB_OVER_CURRENT: - case C_HUB_LOCAL_POWER: - OK(0); - default: - goto err; - } - break; - case SetPortFeature: - if (port >= uhci->rh_numports) - goto err; - - switch (wValue) { - case USB_PORT_FEAT_SUSPEND: - SET_RH_PORTSTAT(USBPORTSC_SUSP); - OK(0); - case USB_PORT_FEAT_RESET: - SET_RH_PORTSTAT(USBPORTSC_PR); - - /* Reset terminates Resume signalling */ - uhci_finish_suspend(uhci, port, port_addr); - - /* USB v2.0 7.1.7.5 */ - uhci->ports_timeout = jiffies + msecs_to_jiffies(50); - OK(0); - case USB_PORT_FEAT_POWER: - /* UHCI has no power switching */ - OK(0); - default: - goto err; - } - break; - case ClearPortFeature: - if (port >= uhci->rh_numports) - goto err; - - switch (wValue) { - case USB_PORT_FEAT_ENABLE: - CLR_RH_PORTSTAT(USBPORTSC_PE); - - /* Disable terminates Resume signalling */ - uhci_finish_suspend(uhci, port, port_addr); - OK(0); - case USB_PORT_FEAT_C_ENABLE: - CLR_RH_PORTSTAT(USBPORTSC_PEC); - OK(0); - case USB_PORT_FEAT_SUSPEND: - if (!(uhci_readw(uhci, port_addr) & USBPORTSC_SUSP)) { - - /* Make certain the port isn't suspended */ - uhci_finish_suspend(uhci, port, port_addr); - } else if (!test_and_set_bit(port, - &uhci->resuming_ports)) { - SET_RH_PORTSTAT(USBPORTSC_RD); - - /* The controller won't allow RD to be set - * if the port is disabled. When this happens - * just skip the Resume signalling. - */ - if (!(uhci_readw(uhci, port_addr) & - USBPORTSC_RD)) - uhci_finish_suspend(uhci, port, - port_addr); - else - /* USB v2.0 7.1.7.7 */ - uhci->ports_timeout = jiffies + - msecs_to_jiffies(20); - } - OK(0); - case USB_PORT_FEAT_C_SUSPEND: - clear_bit(port, &uhci->port_c_suspend); - OK(0); - case USB_PORT_FEAT_POWER: - /* UHCI has no power switching */ - goto err; - case USB_PORT_FEAT_C_CONNECTION: - CLR_RH_PORTSTAT(USBPORTSC_CSC); - OK(0); - case USB_PORT_FEAT_C_OVER_CURRENT: - CLR_RH_PORTSTAT(USBPORTSC_OCC); - OK(0); - case USB_PORT_FEAT_C_RESET: - /* this driver won't report these */ - OK(0); - default: - goto err; - } - break; - case GetHubDescriptor: - len = min_t(unsigned int, sizeof(root_hub_hub_des), wLength); - memcpy(buf, root_hub_hub_des, len); - if (len > 2) - buf[2] = uhci->rh_numports; - OK(len); - default: -err: - retval = -EPIPE; - } - spin_unlock_irqrestore(&uhci->lock, flags); - - return retval; -} diff --git a/ANDROID_3.4.5/drivers/usb/host/uhci-pci.c b/ANDROID_3.4.5/drivers/usb/host/uhci-pci.c deleted file mode 100644 index 2de5a93b..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/uhci-pci.c +++ /dev/null @@ -1,325 +0,0 @@ -/* - * UHCI HCD (Host Controller Driver) PCI Bus Glue. - * - * Extracted from uhci-hcd.c: - * Maintainer: Alan Stern - * - * (C) Copyright 1999 Linus Torvalds - * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com - * (C) Copyright 1999 Randy Dunlap - * (C) Copyright 1999 Georg Acher, acher@in.tum.de - * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de - * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch - * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at - * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface - * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com). - * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) - * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu - */ - -#include "pci-quirks.h" -#include - -/* - * Make sure the controller is completely inactive, unable to - * generate interrupts or do DMA. - */ -static void uhci_pci_reset_hc(struct uhci_hcd *uhci) -{ - uhci_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr); -} - -/* - * Initialize a controller that was newly discovered or has just been - * resumed. In either case we can't be sure of its previous state. - * - * Returns: 1 if the controller was reset, 0 otherwise. - */ -static int uhci_pci_check_and_reset_hc(struct uhci_hcd *uhci) -{ - return uhci_check_and_reset_hc(to_pci_dev(uhci_dev(uhci)), - uhci->io_addr); -} - -/* - * Store the basic register settings needed by the controller. - * This function is called at the end of configure_hc in uhci-hcd.c. - */ -static void uhci_pci_configure_hc(struct uhci_hcd *uhci) -{ - struct pci_dev *pdev = to_pci_dev(uhci_dev(uhci)); - - /* Enable PIRQ */ - pci_write_config_word(pdev, USBLEGSUP, USBLEGSUP_DEFAULT); - - /* Disable platform-specific non-PME# wakeup */ - if (pdev->vendor == PCI_VENDOR_ID_INTEL) - pci_write_config_byte(pdev, USBRES_INTEL, 0); -} - -static int uhci_pci_resume_detect_interrupts_are_broken(struct uhci_hcd *uhci) -{ - int port; - - switch (to_pci_dev(uhci_dev(uhci))->vendor) { - default: - break; - - case PCI_VENDOR_ID_GENESYS: - /* Genesys Logic's GL880S controllers don't generate - * resume-detect interrupts. - */ - return 1; - - case PCI_VENDOR_ID_INTEL: - /* Some of Intel's USB controllers have a bug that causes - * resume-detect interrupts if any port has an over-current - * condition. To make matters worse, some motherboards - * hardwire unused USB ports' over-current inputs active! - * To prevent problems, we will not enable resume-detect - * interrupts if any ports are OC. - */ - for (port = 0; port < uhci->rh_numports; ++port) { - if (inw(uhci->io_addr + USBPORTSC1 + port * 2) & - USBPORTSC_OC) - return 1; - } - break; - } - return 0; -} - -static int uhci_pci_global_suspend_mode_is_broken(struct uhci_hcd *uhci) -{ - int port; - const char *sys_info; - static const char bad_Asus_board[] = "A7V8X"; - - /* One of Asus's motherboards has a bug which causes it to - * wake up immediately from suspend-to-RAM if any of the ports - * are connected. In such cases we will not set EGSM. - */ - sys_info = dmi_get_system_info(DMI_BOARD_NAME); - if (sys_info && !strcmp(sys_info, bad_Asus_board)) { - for (port = 0; port < uhci->rh_numports; ++port) { - if (inw(uhci->io_addr + USBPORTSC1 + port * 2) & - USBPORTSC_CCS) - return 1; - } - } - - return 0; -} - -static int uhci_pci_init(struct usb_hcd *hcd) -{ - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - - uhci->io_addr = (unsigned long) hcd->rsrc_start; - - uhci->rh_numports = uhci_count_ports(hcd); - - /* Intel controllers report the OverCurrent bit active on. - * VIA controllers report it active off, so we'll adjust the - * bit value. (It's not standardized in the UHCI spec.) - */ - if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_VIA) - uhci->oc_low = 1; - - /* HP's server management chip requires a longer port reset delay. */ - if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_HP) - uhci->wait_for_hp = 1; - - /* Set up pointers to PCI-specific functions */ - uhci->reset_hc = uhci_pci_reset_hc; - uhci->check_and_reset_hc = uhci_pci_check_and_reset_hc; - uhci->configure_hc = uhci_pci_configure_hc; - uhci->resume_detect_interrupts_are_broken = - uhci_pci_resume_detect_interrupts_are_broken; - uhci->global_suspend_mode_is_broken = - uhci_pci_global_suspend_mode_is_broken; - - - /* Kick BIOS off this hardware and reset if the controller - * isn't already safely quiescent. - */ - check_and_reset_hc(uhci); - return 0; -} - -/* Make sure the controller is quiescent and that we're not using it - * any more. This is mainly for the benefit of programs which, like kexec, - * expect the hardware to be idle: not doing DMA or generating IRQs. - * - * This routine may be called in a damaged or failing kernel. Hence we - * do not acquire the spinlock before shutting down the controller. - */ -static void uhci_shutdown(struct pci_dev *pdev) -{ - struct usb_hcd *hcd = pci_get_drvdata(pdev); - - uhci_hc_died(hcd_to_uhci(hcd)); -} - -#ifdef CONFIG_PM - -extern char enable_ehci_wake; -extern char enable_uhci0_wake; -extern char enable_uhci1_wake; - -static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) -{ - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - struct pci_dev *pdev = to_pci_dev(uhci_dev(uhci)); - int rc = 0; - u16 pmc_enable = 0; - - dev_dbg(uhci_dev(uhci), "%s\n", __func__); - - spin_lock_irq(&uhci->lock); - if (!HCD_HW_ACCESSIBLE(hcd) || uhci->dead) - goto done_okay; /* Already suspended or dead */ - - if (uhci->rh_state > UHCI_RH_SUSPENDED) { - dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n"); - rc = -EBUSY; - goto done; - }; - - /* All PCI host controllers are required to disable IRQ generation - * at the source, so we must turn off PIRQ. - */ - pci_write_config_word(pdev, USBLEGSUP, 0); - clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); - - /* Enable platform-specific non-PME# wakeup */ - if (do_wakeup) { - if (pdev->vendor == PCI_VENDOR_ID_INTEL) - pci_write_config_byte(pdev, USBRES_INTEL, - USBPORT1EN | USBPORT2EN); - } - //CharlesTu, for PM - if (((hcd->self.busnum == 2) && enable_uhci0_wake) || ((hcd->self.busnum == 3) && enable_uhci1_wake)){ - pci_read_config_word(to_pci_dev(uhci_dev(uhci)), 0x84, &pmc_enable); - pmc_enable |= 0x103; - pci_write_config_word(to_pci_dev(uhci_dev(uhci)), 0x84, pmc_enable); - } - -done_okay: - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); -done: - spin_unlock_irq(&uhci->lock); - return rc; -} - -static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated) -{ - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - u16 pmc_enable = 0; - /*CharlesTu,2009.08.30,patch uhci device disconnet irq nobody care issue - * Before clear D3 mode ,disable UHCI resume interrupt - * The right sequence: disconnect->wakeup->D0 mode->clear resume. - */ - if (enable_ehci_wake){ - REG8_VAL(USB20_HOST_DEVICE_CFG_BASE_ADDR+0x0304) &= ~0x02; - REG8_VAL(USB20_HOST_DEVICE_CFG_BASE_ADDR+0x1504) &= ~0x02; - - pci_read_config_word(to_pci_dev(uhci_dev(uhci)), 0x84, &pmc_enable); - pmc_enable &= ~0x03; - pci_write_config_word(to_pci_dev(uhci_dev(uhci)), 0x84, pmc_enable); - } - dev_dbg(uhci_dev(uhci), "%s\n", __func__); - - /* Since we aren't in D3 any more, it's safe to set this flag - * even if the controller was dead. - */ - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - - spin_lock_irq(&uhci->lock); - - /* Make sure resume from hibernation re-enumerates everything */ - if (hibernated) { - uhci->reset_hc(uhci); - finish_reset(uhci); - } - - /* The firmware may have changed the controller settings during - * a system wakeup. Check it and reconfigure to avoid problems. - */ - else { - check_and_reset_hc(uhci); - } - configure_hc(uhci); - - /* Tell the core if the controller had to be reset */ - if (uhci->rh_state == UHCI_RH_RESET) - usb_root_hub_lost_power(hcd->self.root_hub); - - spin_unlock_irq(&uhci->lock); - - /* If interrupts don't work and remote wakeup is enabled then - * the suspended root hub needs to be polled. - */ - if (!uhci->RD_enable && hcd->self.root_hub->do_remote_wakeup) - set_bit(HCD_FLAG_POLL_RH, &hcd->flags); - - /* Does the root hub have a port wakeup pending? */ - usb_hcd_poll_rh_status(hcd); - return 0; -} - -#endif - -static const struct hc_driver uhci_driver = { - .description = hcd_name, - .product_desc = "UHCI Host Controller", - .hcd_priv_size = sizeof(struct uhci_hcd), - - /* Generic hardware linkage */ - .irq = uhci_irq, - .flags = HCD_USB11, - - /* Basic lifecycle operations */ - .reset = uhci_pci_init, - .start = uhci_start, -#ifdef CONFIG_PM - .pci_suspend = uhci_pci_suspend, - .pci_resume = uhci_pci_resume, - .bus_suspend = uhci_rh_suspend, - .bus_resume = uhci_rh_resume, -#endif - .stop = uhci_stop, - - .urb_enqueue = uhci_urb_enqueue, - .urb_dequeue = uhci_urb_dequeue, - - .endpoint_disable = uhci_hcd_endpoint_disable, - .get_frame_number = uhci_hcd_get_frame_number, - - .hub_status_data = uhci_hub_status_data, - .hub_control = uhci_hub_control, -}; - -static DEFINE_PCI_DEVICE_TABLE(uhci_pci_ids) = { { - /* handle any USB UHCI controller */ - PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_UHCI, ~0), - .driver_data = (unsigned long) &uhci_driver, - }, { /* end: all zeroes */ } -}; - -MODULE_DEVICE_TABLE(pci, uhci_pci_ids); - -static struct pci_driver uhci_pci_driver = { - .name = (char *)hcd_name, - .id_table = uhci_pci_ids, - - .probe = usb_hcd_pci_probe, - .remove = usb_hcd_pci_remove, - .shutdown = uhci_shutdown, - -#ifdef CONFIG_PM_SLEEP - .driver = { - .pm = &usb_hcd_pci_pm_ops - }, -#endif -}; diff --git a/ANDROID_3.4.5/drivers/usb/host/uhci-q.c b/ANDROID_3.4.5/drivers/usb/host/uhci-q.c deleted file mode 100644 index d2c6f5ac..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/uhci-q.c +++ /dev/null @@ -1,1791 +0,0 @@ -/* - * Universal Host Controller Interface driver for USB. - * - * Maintainer: Alan Stern - * - * (C) Copyright 1999 Linus Torvalds - * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com - * (C) Copyright 1999 Randy Dunlap - * (C) Copyright 1999 Georg Acher, acher@in.tum.de - * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de - * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch - * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at - * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface - * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com). - * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) - * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu - */ - - -/* - * Technically, updating td->status here is a race, but it's not really a - * problem. The worst that can happen is that we set the IOC bit again - * generating a spurious interrupt. We could fix this by creating another - * QH and leaving the IOC bit always set, but then we would have to play - * games with the FSBR code to make sure we get the correct order in all - * the cases. I don't think it's worth the effort - */ -static void uhci_set_next_interrupt(struct uhci_hcd *uhci) -{ - if (uhci->is_stopped) - mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies); - uhci->term_td->status |= cpu_to_hc32(uhci, TD_CTRL_IOC); -} - -static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci) -{ - uhci->term_td->status &= ~cpu_to_hc32(uhci, TD_CTRL_IOC); -} - - -/* - * Full-Speed Bandwidth Reclamation (FSBR). - * We turn on FSBR whenever a queue that wants it is advancing, - * and leave it on for a short time thereafter. - */ -static void uhci_fsbr_on(struct uhci_hcd *uhci) -{ - struct uhci_qh *lqh; - - /* The terminating skeleton QH always points back to the first - * FSBR QH. Make the last async QH point to the terminating - * skeleton QH. */ - uhci->fsbr_is_on = 1; - lqh = list_entry(uhci->skel_async_qh->node.prev, - struct uhci_qh, node); - lqh->link = LINK_TO_QH(uhci, uhci->skel_term_qh); -} - -static void uhci_fsbr_off(struct uhci_hcd *uhci) -{ - struct uhci_qh *lqh; - - /* Remove the link from the last async QH to the terminating - * skeleton QH. */ - uhci->fsbr_is_on = 0; - lqh = list_entry(uhci->skel_async_qh->node.prev, - struct uhci_qh, node); - lqh->link = UHCI_PTR_TERM(uhci); -} - -static void uhci_add_fsbr(struct uhci_hcd *uhci, struct urb *urb) -{ - struct urb_priv *urbp = urb->hcpriv; - - if (!(urb->transfer_flags & URB_NO_FSBR)) - urbp->fsbr = 1; -} - -static void uhci_urbp_wants_fsbr(struct uhci_hcd *uhci, struct urb_priv *urbp) -{ - if (urbp->fsbr) { - uhci->fsbr_is_wanted = 1; - if (!uhci->fsbr_is_on) - uhci_fsbr_on(uhci); - else if (uhci->fsbr_expiring) { - uhci->fsbr_expiring = 0; - del_timer(&uhci->fsbr_timer); - } - } -} - -static void uhci_fsbr_timeout(unsigned long _uhci) -{ - struct uhci_hcd *uhci = (struct uhci_hcd *) _uhci; - unsigned long flags; - - spin_lock_irqsave(&uhci->lock, flags); - if (uhci->fsbr_expiring) { - uhci->fsbr_expiring = 0; - uhci_fsbr_off(uhci); - } - spin_unlock_irqrestore(&uhci->lock, flags); -} - - -static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci) -{ - dma_addr_t dma_handle; - struct uhci_td *td; - - td = dma_pool_alloc(uhci->td_pool, GFP_ATOMIC, &dma_handle); - if (!td) - return NULL; - - td->dma_handle = dma_handle; - td->frame = -1; - - INIT_LIST_HEAD(&td->list); - INIT_LIST_HEAD(&td->fl_list); - - return td; -} - -static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td) -{ - if (!list_empty(&td->list)) - dev_WARN(uhci_dev(uhci), "td %p still in list!\n", td); - if (!list_empty(&td->fl_list)) - dev_WARN(uhci_dev(uhci), "td %p still in fl_list!\n", td); - - dma_pool_free(uhci->td_pool, td, td->dma_handle); -} - -static inline void uhci_fill_td(struct uhci_hcd *uhci, struct uhci_td *td, - u32 status, u32 token, u32 buffer) -{ - td->status = cpu_to_hc32(uhci, status); - td->token = cpu_to_hc32(uhci, token); - td->buffer = cpu_to_hc32(uhci, buffer); -} - -static void uhci_add_td_to_urbp(struct uhci_td *td, struct urb_priv *urbp) -{ - list_add_tail(&td->list, &urbp->td_list); -} - -static void uhci_remove_td_from_urbp(struct uhci_td *td) -{ - list_del_init(&td->list); -} - -/* - * We insert Isochronous URBs directly into the frame list at the beginning - */ -static inline void uhci_insert_td_in_frame_list(struct uhci_hcd *uhci, - struct uhci_td *td, unsigned framenum) -{ - framenum &= (UHCI_NUMFRAMES - 1); - - td->frame = framenum; - - /* Is there a TD already mapped there? */ - if (uhci->frame_cpu[framenum]) { - struct uhci_td *ftd, *ltd; - - ftd = uhci->frame_cpu[framenum]; - ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list); - - list_add_tail(&td->fl_list, &ftd->fl_list); - - td->link = ltd->link; - wmb(); - ltd->link = LINK_TO_TD(uhci, td); - } else { - td->link = uhci->frame[framenum]; - wmb(); - uhci->frame[framenum] = LINK_TO_TD(uhci, td); - uhci->frame_cpu[framenum] = td; - } -} - -static inline void uhci_remove_td_from_frame_list(struct uhci_hcd *uhci, - struct uhci_td *td) -{ - /* If it's not inserted, don't remove it */ - if (td->frame == -1) { - WARN_ON(!list_empty(&td->fl_list)); - return; - } - - if (uhci->frame_cpu[td->frame] == td) { - if (list_empty(&td->fl_list)) { - uhci->frame[td->frame] = td->link; - uhci->frame_cpu[td->frame] = NULL; - } else { - struct uhci_td *ntd; - - ntd = list_entry(td->fl_list.next, - struct uhci_td, - fl_list); - uhci->frame[td->frame] = LINK_TO_TD(uhci, ntd); - uhci->frame_cpu[td->frame] = ntd; - } - } else { - struct uhci_td *ptd; - - ptd = list_entry(td->fl_list.prev, struct uhci_td, fl_list); - ptd->link = td->link; - } - - list_del_init(&td->fl_list); - td->frame = -1; -} - -static inline void uhci_remove_tds_from_frame(struct uhci_hcd *uhci, - unsigned int framenum) -{ - struct uhci_td *ftd, *ltd; - - framenum &= (UHCI_NUMFRAMES - 1); - - ftd = uhci->frame_cpu[framenum]; - if (ftd) { - ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list); - uhci->frame[framenum] = ltd->link; - uhci->frame_cpu[framenum] = NULL; - - while (!list_empty(&ftd->fl_list)) - list_del_init(ftd->fl_list.prev); - } -} - -/* - * Remove all the TDs for an Isochronous URB from the frame list - */ -static void uhci_unlink_isochronous_tds(struct uhci_hcd *uhci, struct urb *urb) -{ - struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; - struct uhci_td *td; - - list_for_each_entry(td, &urbp->td_list, list) - uhci_remove_td_from_frame_list(uhci, td); -} - -static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, - struct usb_device *udev, struct usb_host_endpoint *hep) -{ - dma_addr_t dma_handle; - struct uhci_qh *qh; - - qh = dma_pool_alloc(uhci->qh_pool, GFP_ATOMIC, &dma_handle); - if (!qh) - return NULL; - - memset(qh, 0, sizeof(*qh)); - qh->dma_handle = dma_handle; - - qh->element = UHCI_PTR_TERM(uhci); - qh->link = UHCI_PTR_TERM(uhci); - - INIT_LIST_HEAD(&qh->queue); - INIT_LIST_HEAD(&qh->node); - - if (udev) { /* Normal QH */ - 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) { - dma_pool_free(uhci->qh_pool, qh, dma_handle); - return NULL; - } - } - qh->state = QH_STATE_IDLE; - qh->hep = hep; - qh->udev = udev; - hep->hcpriv = qh; - - if (qh->type == USB_ENDPOINT_XFER_INT || - qh->type == USB_ENDPOINT_XFER_ISOC) - qh->load = usb_calc_bus_time(udev->speed, - usb_endpoint_dir_in(&hep->desc), - qh->type == USB_ENDPOINT_XFER_ISOC, - usb_endpoint_maxp(&hep->desc)) - / 1000 + 1; - - } else { /* Skeleton QH */ - qh->state = QH_STATE_ACTIVE; - qh->type = -1; - } - return qh; -} - -static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) -{ - WARN_ON(qh->state != QH_STATE_IDLE && qh->udev); - if (!list_empty(&qh->queue)) - dev_WARN(uhci_dev(uhci), "qh %p list not empty!\n", qh); - - list_del(&qh->node); - if (qh->udev) { - qh->hep->hcpriv = NULL; - if (qh->dummy_td) - uhci_free_td(uhci, qh->dummy_td); - } - dma_pool_free(uhci->qh_pool, qh, qh->dma_handle); -} - -/* - * When a queue is stopped and a dequeued URB is given back, adjust - * the previous TD link (if the URB isn't first on the queue) or - * save its toggle value (if it is first and is currently executing). - * - * Returns 0 if the URB should not yet be given back, 1 otherwise. - */ -static int uhci_cleanup_queue(struct uhci_hcd *uhci, struct uhci_qh *qh, - struct urb *urb) -{ - struct urb_priv *urbp = urb->hcpriv; - struct uhci_td *td; - int ret = 1; - - /* Isochronous pipes don't use toggles and their TD link pointers - * get adjusted during uhci_urb_dequeue(). But since their queues - * cannot truly be stopped, we have to watch out for dequeues - * occurring after the nominal unlink frame. */ - if (qh->type == USB_ENDPOINT_XFER_ISOC) { - ret = (uhci->frame_number + uhci->is_stopped != - qh->unlink_frame); - goto done; - } - - /* If the URB isn't first on its queue, adjust the link pointer - * of the last TD in the previous URB. The toggle doesn't need - * to be saved since this URB can't be executing yet. */ - if (qh->queue.next != &urbp->node) { - struct urb_priv *purbp; - struct uhci_td *ptd; - - purbp = list_entry(urbp->node.prev, struct urb_priv, node); - WARN_ON(list_empty(&purbp->td_list)); - ptd = list_entry(purbp->td_list.prev, struct uhci_td, - list); - td = list_entry(urbp->td_list.prev, struct uhci_td, - list); - ptd->link = td->link; - goto done; - } - - /* If the QH element pointer is UHCI_PTR_TERM then then currently - * executing URB has already been unlinked, so this one isn't it. */ - if (qh_element(qh) == UHCI_PTR_TERM(uhci)) - goto done; - qh->element = UHCI_PTR_TERM(uhci); - - /* Control pipes don't have to worry about toggles */ - if (qh->type == USB_ENDPOINT_XFER_CONTROL) - goto done; - - /* Save the next toggle value */ - WARN_ON(list_empty(&urbp->td_list)); - td = list_entry(urbp->td_list.next, struct uhci_td, list); - qh->needs_fixup = 1; - qh->initial_toggle = uhci_toggle(td_token(uhci, td)); - -done: - return ret; -} - -/* - * Fix up the data toggles for URBs in a queue, when one of them - * terminates early (short transfer, error, or dequeued). - */ -static void uhci_fixup_toggles(struct uhci_hcd *uhci, struct uhci_qh *qh, - int skip_first) -{ - struct urb_priv *urbp = NULL; - struct uhci_td *td; - unsigned int toggle = qh->initial_toggle; - unsigned int pipe; - - /* Fixups for a short transfer start with the second URB in the - * queue (the short URB is the first). */ - if (skip_first) - urbp = list_entry(qh->queue.next, struct urb_priv, node); - - /* When starting with the first URB, if the QH element pointer is - * still valid then we know the URB's toggles are okay. */ - else if (qh_element(qh) != UHCI_PTR_TERM(uhci)) - toggle = 2; - - /* Fix up the toggle for the URBs in the queue. Normally this - * loop won't run more than once: When an error or short transfer - * occurs, the queue usually gets emptied. */ - urbp = list_prepare_entry(urbp, &qh->queue, node); - list_for_each_entry_continue(urbp, &qh->queue, node) { - - /* If the first TD has the right toggle value, we don't - * need to change any toggles in this URB */ - td = list_entry(urbp->td_list.next, struct uhci_td, list); - if (toggle > 1 || uhci_toggle(td_token(uhci, td)) == toggle) { - td = list_entry(urbp->td_list.prev, struct uhci_td, - list); - toggle = uhci_toggle(td_token(uhci, td)) ^ 1; - - /* Otherwise all the toggles in the URB have to be switched */ - } else { - list_for_each_entry(td, &urbp->td_list, list) { - td->token ^= cpu_to_hc32(uhci, - TD_TOKEN_TOGGLE); - toggle ^= 1; - } - } - } - - wmb(); - pipe = list_entry(qh->queue.next, struct urb_priv, node)->urb->pipe; - usb_settoggle(qh->udev, usb_pipeendpoint(pipe), - usb_pipeout(pipe), toggle); - qh->needs_fixup = 0; -} - -/* - * Link an Isochronous QH into its skeleton's list - */ -static inline void link_iso(struct uhci_hcd *uhci, struct uhci_qh *qh) -{ - list_add_tail(&qh->node, &uhci->skel_iso_qh->node); - - /* Isochronous QHs aren't linked by the hardware */ -} - -/* - * Link a high-period interrupt QH into the schedule at the end of its - * skeleton's list - */ -static void link_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh) -{ - struct uhci_qh *pqh; - - list_add_tail(&qh->node, &uhci->skelqh[qh->skel]->node); - - pqh = list_entry(qh->node.prev, struct uhci_qh, node); - qh->link = pqh->link; - wmb(); - pqh->link = LINK_TO_QH(uhci, qh); -} - -/* - * Link a period-1 interrupt or async QH into the schedule at the - * correct spot in the async skeleton's list, and update the FSBR link - */ -static void link_async(struct uhci_hcd *uhci, struct uhci_qh *qh) -{ - struct uhci_qh *pqh; - __hc32 link_to_new_qh; - - /* Find the predecessor QH for our new one and insert it in the list. - * The list of QHs is expected to be short, so linear search won't - * take too long. */ - list_for_each_entry_reverse(pqh, &uhci->skel_async_qh->node, node) { - if (pqh->skel <= qh->skel) - break; - } - list_add(&qh->node, &pqh->node); - - /* Link it into the schedule */ - qh->link = pqh->link; - wmb(); - link_to_new_qh = LINK_TO_QH(uhci, qh); - pqh->link = link_to_new_qh; - - /* If this is now the first FSBR QH, link the terminating skeleton - * QH to it. */ - if (pqh->skel < SKEL_FSBR && qh->skel >= SKEL_FSBR) - uhci->skel_term_qh->link = link_to_new_qh; -} - -/* - * Put a QH on the schedule in both hardware and software - */ -static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) -{ - WARN_ON(list_empty(&qh->queue)); - - /* Set the element pointer if it isn't set already. - * This isn't needed for Isochronous queues, but it doesn't hurt. */ - if (qh_element(qh) == UHCI_PTR_TERM(uhci)) { - struct urb_priv *urbp = list_entry(qh->queue.next, - struct urb_priv, node); - struct uhci_td *td = list_entry(urbp->td_list.next, - struct uhci_td, list); - - qh->element = LINK_TO_TD(uhci, td); - } - - /* Treat the queue as if it has just advanced */ - qh->wait_expired = 0; - qh->advance_jiffies = jiffies; - - if (qh->state == QH_STATE_ACTIVE) - return; - qh->state = QH_STATE_ACTIVE; - - /* Move the QH from its old list to the correct spot in the appropriate - * skeleton's list */ - if (qh == uhci->next_qh) - uhci->next_qh = list_entry(qh->node.next, struct uhci_qh, - node); - list_del(&qh->node); - - if (qh->skel == SKEL_ISO) - link_iso(uhci, qh); - else if (qh->skel < SKEL_ASYNC) - link_interrupt(uhci, qh); - else - link_async(uhci, qh); -} - -/* - * Unlink a high-period interrupt QH from the schedule - */ -static void unlink_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh) -{ - struct uhci_qh *pqh; - - pqh = list_entry(qh->node.prev, struct uhci_qh, node); - pqh->link = qh->link; - mb(); -} - -/* - * Unlink a period-1 interrupt or async QH from the schedule - */ -static void unlink_async(struct uhci_hcd *uhci, struct uhci_qh *qh) -{ - struct uhci_qh *pqh; - __hc32 link_to_next_qh = qh->link; - - pqh = list_entry(qh->node.prev, struct uhci_qh, node); - pqh->link = link_to_next_qh; - - /* If this was the old first FSBR QH, link the terminating skeleton - * QH to the next (new first FSBR) QH. */ - if (pqh->skel < SKEL_FSBR && qh->skel >= SKEL_FSBR) - uhci->skel_term_qh->link = link_to_next_qh; - mb(); -} - -/* - * Take a QH off the hardware schedule - */ -static void uhci_unlink_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) -{ - if (qh->state == QH_STATE_UNLINKING) - return; - WARN_ON(qh->state != QH_STATE_ACTIVE || !qh->udev); - qh->state = QH_STATE_UNLINKING; - - /* Unlink the QH from the schedule and record when we did it */ - if (qh->skel == SKEL_ISO) - ; - else if (qh->skel < SKEL_ASYNC) - unlink_interrupt(uhci, qh); - else - unlink_async(uhci, qh); - - uhci_get_current_frame_number(uhci); - qh->unlink_frame = uhci->frame_number; - - /* Force an interrupt so we know when the QH is fully unlinked */ - if (list_empty(&uhci->skel_unlink_qh->node) || uhci->is_stopped) - uhci_set_next_interrupt(uhci); - - /* Move the QH from its old list to the end of the unlinking list */ - if (qh == uhci->next_qh) - uhci->next_qh = list_entry(qh->node.next, struct uhci_qh, - node); - list_move_tail(&qh->node, &uhci->skel_unlink_qh->node); -} - -/* - * When we and the controller are through with a QH, it becomes IDLE. - * This happens when a QH has been off the schedule (on the unlinking - * list) for more than one frame, or when an error occurs while adding - * the first URB onto a new QH. - */ -static void uhci_make_qh_idle(struct uhci_hcd *uhci, struct uhci_qh *qh) -{ - WARN_ON(qh->state == QH_STATE_ACTIVE); - - if (qh == uhci->next_qh) - uhci->next_qh = list_entry(qh->node.next, struct uhci_qh, - node); - list_move(&qh->node, &uhci->idle_qh_list); - qh->state = QH_STATE_IDLE; - - /* Now that the QH is idle, its post_td isn't being used */ - if (qh->post_td) { - uhci_free_td(uhci, qh->post_td); - qh->post_td = NULL; - } - - /* If anyone is waiting for a QH to become idle, wake them up */ - if (uhci->num_waiting) - wake_up_all(&uhci->waitqh); -} - -/* - * Find the highest existing bandwidth load for a given phase and period. - */ -static int uhci_highest_load(struct uhci_hcd *uhci, int phase, int period) -{ - int highest_load = uhci->load[phase]; - - for (phase += period; phase < MAX_PHASE; phase += period) - highest_load = max_t(int, highest_load, uhci->load[phase]); - return highest_load; -} - -/* - * Set qh->phase to the optimal phase for a periodic transfer and - * check whether the bandwidth requirement is acceptable. - */ -static int uhci_check_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh) -{ - int minimax_load; - - /* Find the optimal phase (unless it is already set) and get - * its load value. */ - if (qh->phase >= 0) - minimax_load = uhci_highest_load(uhci, qh->phase, qh->period); - else { - int phase, load; - int max_phase = min_t(int, MAX_PHASE, qh->period); - - qh->phase = 0; - minimax_load = uhci_highest_load(uhci, qh->phase, qh->period); - for (phase = 1; phase < max_phase; ++phase) { - load = uhci_highest_load(uhci, phase, qh->period); - if (load < minimax_load) { - minimax_load = load; - qh->phase = phase; - } - } - } - - /* Maximum allowable periodic bandwidth is 90%, or 900 us per frame */ - if (minimax_load + qh->load > 900) { - dev_dbg(uhci_dev(uhci), "bandwidth allocation failed: " - "period %d, phase %d, %d + %d us\n", - qh->period, qh->phase, minimax_load, qh->load); - return -ENOSPC; - } - return 0; -} - -/* - * Reserve a periodic QH's bandwidth in the schedule - */ -static void uhci_reserve_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh) -{ - int i; - int load = qh->load; - char *p = "??"; - - for (i = qh->phase; i < MAX_PHASE; i += qh->period) { - uhci->load[i] += load; - uhci->total_load += load; - } - uhci_to_hcd(uhci)->self.bandwidth_allocated = - uhci->total_load / MAX_PHASE; - switch (qh->type) { - case USB_ENDPOINT_XFER_INT: - ++uhci_to_hcd(uhci)->self.bandwidth_int_reqs; - p = "INT"; - break; - case USB_ENDPOINT_XFER_ISOC: - ++uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs; - p = "ISO"; - break; - } - qh->bandwidth_reserved = 1; - dev_dbg(uhci_dev(uhci), - "%s dev %d ep%02x-%s, period %d, phase %d, %d us\n", - "reserve", qh->udev->devnum, - qh->hep->desc.bEndpointAddress, p, - qh->period, qh->phase, load); -} - -/* - * Release a periodic QH's bandwidth reservation - */ -static void uhci_release_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh) -{ - int i; - int load = qh->load; - char *p = "??"; - - for (i = qh->phase; i < MAX_PHASE; i += qh->period) { - uhci->load[i] -= load; - uhci->total_load -= load; - } - uhci_to_hcd(uhci)->self.bandwidth_allocated = - uhci->total_load / MAX_PHASE; - switch (qh->type) { - case USB_ENDPOINT_XFER_INT: - --uhci_to_hcd(uhci)->self.bandwidth_int_reqs; - p = "INT"; - break; - case USB_ENDPOINT_XFER_ISOC: - --uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs; - p = "ISO"; - break; - } - qh->bandwidth_reserved = 0; - dev_dbg(uhci_dev(uhci), - "%s dev %d ep%02x-%s, period %d, phase %d, %d us\n", - "release", qh->udev->devnum, - qh->hep->desc.bEndpointAddress, p, - qh->period, qh->phase, load); -} - -static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, - struct urb *urb) -{ - struct urb_priv *urbp; - - urbp = kmem_cache_zalloc(uhci_up_cachep, GFP_ATOMIC); - if (!urbp) - return NULL; - - urbp->urb = urb; - urb->hcpriv = urbp; - - INIT_LIST_HEAD(&urbp->node); - INIT_LIST_HEAD(&urbp->td_list); - - return urbp; -} - -static void uhci_free_urb_priv(struct uhci_hcd *uhci, - struct urb_priv *urbp) -{ - struct uhci_td *td, *tmp; - - if (!list_empty(&urbp->node)) - dev_WARN(uhci_dev(uhci), "urb %p still on QH's list!\n", - urbp->urb); - - list_for_each_entry_safe(td, tmp, &urbp->td_list, list) { - uhci_remove_td_from_urbp(td); - uhci_free_td(uhci, td); - } - - kmem_cache_free(uhci_up_cachep, urbp); -} - -/* - * Map status to standard result codes - * - * is (td_status(uhci, td) & 0xF60000), a.k.a. - * uhci_status_bits(td_status(uhci, td)). - * Note: does not include the TD_CTRL_NAK bit. - * is True for output TDs and False for input TDs. - */ -static int uhci_map_status(int status, int dir_out) -{ - if (!status) - return 0; - if (status & TD_CTRL_BITSTUFF) /* Bitstuff error */ - return -EPROTO; - if (status & TD_CTRL_CRCTIMEO) { /* CRC/Timeout */ - if (dir_out) - return -EPROTO; - else - return -EILSEQ; - } - if (status & TD_CTRL_BABBLE) /* Babble */ - return -EOVERFLOW; - if (status & TD_CTRL_DBUFERR) /* Buffer error */ - return -ENOSR; - if (status & TD_CTRL_STALLED) /* Stalled */ - return -EPIPE; - return 0; -} - -/* - * Control transfers - */ -static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, - struct uhci_qh *qh) -{ - struct uhci_td *td; - unsigned long destination, status; - int maxsze = usb_endpoint_maxp(&qh->hep->desc); - int len = urb->transfer_buffer_length; - dma_addr_t data = urb->transfer_dma; - __hc32 *plink; - struct urb_priv *urbp = urb->hcpriv; - int skel; - - /* The "pipe" thing contains the destination in bits 8--18 */ - destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP; - - /* 3 errors, dummy TD remains inactive */ - status = uhci_maxerr(3); - if (urb->dev->speed == USB_SPEED_LOW) - status |= TD_CTRL_LS; - - /* - * Build the TD for the control request setup packet - */ - td = qh->dummy_td; - uhci_add_td_to_urbp(td, urbp); - uhci_fill_td(uhci, td, status, destination | uhci_explen(8), - urb->setup_dma); - plink = &td->link; - status |= TD_CTRL_ACTIVE; - - /* - * If direction is "send", change the packet ID from SETUP (0x2D) - * to OUT (0xE1). Else change it from SETUP to IN (0x69) and - * set Short Packet Detect (SPD) for all data packets. - * - * 0-length transfers always get treated as "send". - */ - if (usb_pipeout(urb->pipe) || len == 0) - destination ^= (USB_PID_SETUP ^ USB_PID_OUT); - else { - destination ^= (USB_PID_SETUP ^ USB_PID_IN); - status |= TD_CTRL_SPD; - } - - /* - * Build the DATA TDs - */ - while (len > 0) { - int pktsze = maxsze; - - if (len <= pktsze) { /* The last data packet */ - pktsze = len; - status &= ~TD_CTRL_SPD; - } - - td = uhci_alloc_td(uhci); - if (!td) - goto nomem; - *plink = LINK_TO_TD(uhci, td); - - /* Alternate Data0/1 (start with Data1) */ - destination ^= TD_TOKEN_TOGGLE; - - uhci_add_td_to_urbp(td, urbp); - uhci_fill_td(uhci, td, status, - destination | uhci_explen(pktsze), data); - plink = &td->link; - - data += pktsze; - len -= pktsze; - } - - /* - * Build the final TD for control status - */ - td = uhci_alloc_td(uhci); - if (!td) - goto nomem; - *plink = LINK_TO_TD(uhci, td); - - /* Change direction for the status transaction */ - destination ^= (USB_PID_IN ^ USB_PID_OUT); - destination |= TD_TOKEN_TOGGLE; /* End in Data1 */ - - uhci_add_td_to_urbp(td, urbp); - uhci_fill_td(uhci, td, status | TD_CTRL_IOC, - destination | uhci_explen(0), 0); - plink = &td->link; - - /* - * Build the new dummy TD and activate the old one - */ - td = uhci_alloc_td(uhci); - if (!td) - goto nomem; - *plink = LINK_TO_TD(uhci, td); - - uhci_fill_td(uhci, td, 0, USB_PID_OUT | uhci_explen(0), 0); - wmb(); - qh->dummy_td->status |= cpu_to_hc32(uhci, TD_CTRL_ACTIVE); - qh->dummy_td = td; - - /* Low-speed transfers get a different queue, and won't hog the bus. - * Also, some devices enumerate better without FSBR; the easiest way - * to do that is to put URBs on the low-speed queue while the device - * isn't in the CONFIGURED state. */ - if (urb->dev->speed == USB_SPEED_LOW || - urb->dev->state != USB_STATE_CONFIGURED) - skel = SKEL_LS_CONTROL; - else { - skel = SKEL_FS_CONTROL; - uhci_add_fsbr(uhci, urb); - } - if (qh->state != QH_STATE_ACTIVE) - qh->skel = skel; - return 0; - -nomem: - /* Remove the dummy TD from the td_list so it doesn't get freed */ - uhci_remove_td_from_urbp(qh->dummy_td); - return -ENOMEM; -} - -/* - * Common submit for bulk and interrupt - */ -static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, - struct uhci_qh *qh) -{ - struct uhci_td *td; - unsigned long destination, status; - int maxsze = usb_endpoint_maxp(&qh->hep->desc); - int len = urb->transfer_buffer_length; - int this_sg_len; - dma_addr_t data; - __hc32 *plink; - struct urb_priv *urbp = urb->hcpriv; - unsigned int toggle; - struct scatterlist *sg; - int i; - - if (len < 0) - return -EINVAL; - - /* The "pipe" thing contains the destination in bits 8--18 */ - destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); - toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe)); - - /* 3 errors, dummy TD remains inactive */ - status = uhci_maxerr(3); - if (urb->dev->speed == USB_SPEED_LOW) - status |= TD_CTRL_LS; - if (usb_pipein(urb->pipe)) - status |= TD_CTRL_SPD; - - i = urb->num_mapped_sgs; - if (len > 0 && i > 0) { - sg = urb->sg; - data = sg_dma_address(sg); - - /* urb->transfer_buffer_length may be smaller than the - * size of the scatterlist (or vice versa) - */ - this_sg_len = min_t(int, sg_dma_len(sg), len); - } else { - sg = NULL; - data = urb->transfer_dma; - this_sg_len = len; - } - /* - * Build the DATA TDs - */ - plink = NULL; - td = qh->dummy_td; - for (;;) { /* Allow zero length packets */ - int pktsze = maxsze; - - if (len <= pktsze) { /* The last packet */ - pktsze = len; - if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) - status &= ~TD_CTRL_SPD; - } - - if (plink) { - td = uhci_alloc_td(uhci); - if (!td) - goto nomem; - *plink = LINK_TO_TD(uhci, td); - } - uhci_add_td_to_urbp(td, urbp); - uhci_fill_td(uhci, td, status, - destination | uhci_explen(pktsze) | - (toggle << TD_TOKEN_TOGGLE_SHIFT), - data); - plink = &td->link; - status |= TD_CTRL_ACTIVE; - - toggle ^= 1; - data += pktsze; - this_sg_len -= pktsze; - len -= maxsze; - if (this_sg_len <= 0) { - if (--i <= 0 || len <= 0) - break; - sg = sg_next(sg); - data = sg_dma_address(sg); - this_sg_len = min_t(int, sg_dma_len(sg), len); - } - } - - /* - * URB_ZERO_PACKET means adding a 0-length packet, if direction - * is OUT and the transfer_length was an exact multiple of maxsze, - * hence (len = transfer_length - N * maxsze) == 0 - * however, if transfer_length == 0, the zero packet was already - * prepared above. - */ - if ((urb->transfer_flags & URB_ZERO_PACKET) && - usb_pipeout(urb->pipe) && len == 0 && - urb->transfer_buffer_length > 0) { - td = uhci_alloc_td(uhci); - if (!td) - goto nomem; - *plink = LINK_TO_TD(uhci, td); - - uhci_add_td_to_urbp(td, urbp); - uhci_fill_td(uhci, td, status, - destination | uhci_explen(0) | - (toggle << TD_TOKEN_TOGGLE_SHIFT), - data); - plink = &td->link; - - toggle ^= 1; - } - - /* Set the interrupt-on-completion flag on the last packet. - * A more-or-less typical 4 KB URB (= size of one memory page) - * will require about 3 ms to transfer; that's a little on the - * fast side but not enough to justify delaying an interrupt - * more than 2 or 3 URBs, so we will ignore the URB_NO_INTERRUPT - * flag setting. */ - td->status |= cpu_to_hc32(uhci, TD_CTRL_IOC); - - /* - * Build the new dummy TD and activate the old one - */ - td = uhci_alloc_td(uhci); - if (!td) - goto nomem; - *plink = LINK_TO_TD(uhci, td); - - uhci_fill_td(uhci, td, 0, USB_PID_OUT | uhci_explen(0), 0); - wmb(); - qh->dummy_td->status |= cpu_to_hc32(uhci, TD_CTRL_ACTIVE); - qh->dummy_td = td; - - usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe), toggle); - return 0; - -nomem: - /* Remove the dummy TD from the td_list so it doesn't get freed */ - uhci_remove_td_from_urbp(qh->dummy_td); - return -ENOMEM; -} - -static int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, - struct uhci_qh *qh) -{ - int ret; - - /* Can't have low-speed bulk transfers */ - if (urb->dev->speed == USB_SPEED_LOW) - return -EINVAL; - - if (qh->state != QH_STATE_ACTIVE) - qh->skel = SKEL_BULK; - ret = uhci_submit_common(uhci, urb, qh); - if (ret == 0) - uhci_add_fsbr(uhci, urb); - return ret; -} - -static int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, - struct uhci_qh *qh) -{ - int ret; - - /* USB 1.1 interrupt transfers only involve one packet per interval. - * Drivers can submit URBs of any length, but longer ones will need - * multiple intervals to complete. - */ - - if (!qh->bandwidth_reserved) { - int exponent; - - /* Figure out which power-of-two queue to use */ - for (exponent = 7; exponent >= 0; --exponent) { - if ((1 << exponent) <= urb->interval) - break; - } - if (exponent < 0) - return -EINVAL; - - /* If the slot is full, try a lower period */ - do { - qh->period = 1 << exponent; - qh->skel = SKEL_INDEX(exponent); - - /* For now, interrupt phase is fixed by the layout - * of the QH lists. - */ - qh->phase = (qh->period / 2) & (MAX_PHASE - 1); - ret = uhci_check_bandwidth(uhci, qh); - } while (ret != 0 && --exponent >= 0); - if (ret) - return ret; - } else if (qh->period > urb->interval) - return -EINVAL; /* Can't decrease the period */ - - ret = uhci_submit_common(uhci, urb, qh); - if (ret == 0) { - urb->interval = qh->period; - if (!qh->bandwidth_reserved) - uhci_reserve_bandwidth(uhci, qh); - } - return ret; -} - -/* - * Fix up the data structures following a short transfer - */ -static int uhci_fixup_short_transfer(struct uhci_hcd *uhci, - struct uhci_qh *qh, struct urb_priv *urbp) -{ - struct uhci_td *td; - struct list_head *tmp; - int ret; - - td = list_entry(urbp->td_list.prev, struct uhci_td, list); - if (qh->type == USB_ENDPOINT_XFER_CONTROL) { - - /* When a control transfer is short, we have to restart - * the queue at the status stage transaction, which is - * the last TD. */ - WARN_ON(list_empty(&urbp->td_list)); - qh->element = LINK_TO_TD(uhci, td); - tmp = td->list.prev; - ret = -EINPROGRESS; - - } else { - - /* When a bulk/interrupt transfer is short, we have to - * fix up the toggles of the following URBs on the queue - * before restarting the queue at the next URB. */ - qh->initial_toggle = - uhci_toggle(td_token(uhci, qh->post_td)) ^ 1; - uhci_fixup_toggles(uhci, qh, 1); - - if (list_empty(&urbp->td_list)) - td = qh->post_td; - qh->element = td->link; - tmp = urbp->td_list.prev; - ret = 0; - } - - /* Remove all the TDs we skipped over, from tmp back to the start */ - while (tmp != &urbp->td_list) { - td = list_entry(tmp, struct uhci_td, list); - tmp = tmp->prev; - - uhci_remove_td_from_urbp(td); - uhci_free_td(uhci, td); - } - return ret; -} - -/* - * Common result for control, bulk, and interrupt - */ -static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb) -{ - struct urb_priv *urbp = urb->hcpriv; - struct uhci_qh *qh = urbp->qh; - struct uhci_td *td, *tmp; - unsigned status; - int ret = 0; - - list_for_each_entry_safe(td, tmp, &urbp->td_list, list) { - unsigned int ctrlstat; - int len; - - ctrlstat = td_status(uhci, td); - status = uhci_status_bits(ctrlstat); - if (status & TD_CTRL_ACTIVE) - return -EINPROGRESS; - - len = uhci_actual_length(ctrlstat); - urb->actual_length += len; - - if (status) { - ret = uhci_map_status(status, - uhci_packetout(td_token(uhci, td))); - if ((debug == 1 && ret != -EPIPE) || debug > 1) { - /* Some debugging code */ - dev_dbg(&urb->dev->dev, - "%s: failed with status %x\n", - __func__, status); - - if (debug > 1 && errbuf) { - /* Print the chain for debugging */ - uhci_show_qh(uhci, urbp->qh, errbuf, - ERRBUF_LEN, 0); - lprintk(errbuf); - } - } - - /* Did we receive a short packet? */ - } else if (len < uhci_expected_length(td_token(uhci, td))) { - - /* For control transfers, go to the status TD if - * this isn't already the last data TD */ - if (qh->type == USB_ENDPOINT_XFER_CONTROL) { - if (td->list.next != urbp->td_list.prev) - ret = 1; - } - - /* For bulk and interrupt, this may be an error */ - else if (urb->transfer_flags & URB_SHORT_NOT_OK) - ret = -EREMOTEIO; - - /* Fixup needed only if this isn't the URB's last TD */ - else if (&td->list != urbp->td_list.prev) - ret = 1; - } - - uhci_remove_td_from_urbp(td); - if (qh->post_td) - uhci_free_td(uhci, qh->post_td); - qh->post_td = td; - - if (ret != 0) - goto err; - } - return ret; - -err: - if (ret < 0) { - /* Note that the queue has stopped and save - * the next toggle value */ - qh->element = UHCI_PTR_TERM(uhci); - qh->is_stopped = 1; - qh->needs_fixup = (qh->type != USB_ENDPOINT_XFER_CONTROL); - qh->initial_toggle = uhci_toggle(td_token(uhci, td)) ^ - (ret == -EREMOTEIO); - - } else /* Short packet received */ - ret = uhci_fixup_short_transfer(uhci, qh, urbp); - return ret; -} - -/* - * Isochronous transfers - */ -static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, - struct uhci_qh *qh) -{ - struct uhci_td *td = NULL; /* Since urb->number_of_packets > 0 */ - int i, frame; - unsigned long destination, status; - struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; - - /* Values must not be too big (could overflow below) */ - if (urb->interval >= UHCI_NUMFRAMES || - urb->number_of_packets >= UHCI_NUMFRAMES) - return -EFBIG; - - /* Check the period and figure out the starting frame number */ - if (!qh->bandwidth_reserved) { - qh->period = urb->interval; - if (urb->transfer_flags & URB_ISO_ASAP) { - qh->phase = -1; /* Find the best phase */ - i = uhci_check_bandwidth(uhci, qh); - if (i) - return i; - - /* Allow a little time to allocate the TDs */ - uhci_get_current_frame_number(uhci); - frame = uhci->frame_number + 10; - - /* Move forward to the first frame having the - * correct phase */ - urb->start_frame = frame + ((qh->phase - frame) & - (qh->period - 1)); - } else { - i = urb->start_frame - uhci->last_iso_frame; - if (i <= 0 || i >= UHCI_NUMFRAMES) - return -EINVAL; - qh->phase = urb->start_frame & (qh->period - 1); - i = uhci_check_bandwidth(uhci, qh); - if (i) - return i; - } - - } else if (qh->period != urb->interval) { - return -EINVAL; /* Can't change the period */ - - } else { - /* Find the next unused frame */ - if (list_empty(&qh->queue)) { - frame = qh->iso_frame; - } else { - struct urb *lurb; - - lurb = list_entry(qh->queue.prev, - struct urb_priv, node)->urb; - frame = lurb->start_frame + - lurb->number_of_packets * - lurb->interval; - } - if (urb->transfer_flags & URB_ISO_ASAP) { - /* Skip some frames if necessary to insure - * the start frame is in the future. - */ - uhci_get_current_frame_number(uhci); - if (uhci_frame_before_eq(frame, uhci->frame_number)) { - frame = uhci->frame_number + 1; - frame += ((qh->phase - frame) & - (qh->period - 1)); - } - } /* Otherwise pick up where the last URB leaves off */ - urb->start_frame = frame; - } - - /* Make sure we won't have to go too far into the future */ - if (uhci_frame_before_eq(uhci->last_iso_frame + UHCI_NUMFRAMES, - urb->start_frame + urb->number_of_packets * - urb->interval)) - return -EFBIG; - - status = TD_CTRL_ACTIVE | TD_CTRL_IOS; - destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe); - - for (i = 0; i < urb->number_of_packets; i++) { - td = uhci_alloc_td(uhci); - if (!td) - return -ENOMEM; - - uhci_add_td_to_urbp(td, urbp); - uhci_fill_td(uhci, td, status, destination | - uhci_explen(urb->iso_frame_desc[i].length), - urb->transfer_dma + - urb->iso_frame_desc[i].offset); - } - - /* Set the interrupt-on-completion flag on the last packet. */ - td->status |= cpu_to_hc32(uhci, TD_CTRL_IOC); - - /* Add the TDs to the frame list */ - frame = urb->start_frame; - list_for_each_entry(td, &urbp->td_list, list) { - uhci_insert_td_in_frame_list(uhci, td, frame); - frame += qh->period; - } - - if (list_empty(&qh->queue)) { - qh->iso_packet_desc = &urb->iso_frame_desc[0]; - qh->iso_frame = urb->start_frame; - } - - qh->skel = SKEL_ISO; - if (!qh->bandwidth_reserved) - uhci_reserve_bandwidth(uhci, qh); - return 0; -} - -static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb) -{ - struct uhci_td *td, *tmp; - struct urb_priv *urbp = urb->hcpriv; - struct uhci_qh *qh = urbp->qh; - - list_for_each_entry_safe(td, tmp, &urbp->td_list, list) { - unsigned int ctrlstat; - int status; - int actlength; - - if (uhci_frame_before_eq(uhci->cur_iso_frame, qh->iso_frame)) - return -EINPROGRESS; - - uhci_remove_tds_from_frame(uhci, qh->iso_frame); - - ctrlstat = td_status(uhci, td); - if (ctrlstat & TD_CTRL_ACTIVE) { - status = -EXDEV; /* TD was added too late? */ - } else { - status = uhci_map_status(uhci_status_bits(ctrlstat), - usb_pipeout(urb->pipe)); - actlength = uhci_actual_length(ctrlstat); - - urb->actual_length += actlength; - qh->iso_packet_desc->actual_length = actlength; - qh->iso_packet_desc->status = status; - } - if (status) - urb->error_count++; - - uhci_remove_td_from_urbp(td); - uhci_free_td(uhci, td); - qh->iso_frame += qh->period; - ++qh->iso_packet_desc; - } - return 0; -} - -static int uhci_urb_enqueue(struct usb_hcd *hcd, - struct urb *urb, gfp_t mem_flags) -{ - int ret; - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - unsigned long flags; - struct urb_priv *urbp; - struct uhci_qh *qh; - - spin_lock_irqsave(&uhci->lock, flags); - - ret = usb_hcd_link_urb_to_ep(hcd, urb); - if (ret) - goto done_not_linked; - - ret = -ENOMEM; - urbp = uhci_alloc_urb_priv(uhci, urb); - if (!urbp) - goto done; - - if (urb->ep->hcpriv) - qh = urb->ep->hcpriv; - else { - qh = uhci_alloc_qh(uhci, urb->dev, urb->ep); - if (!qh) - goto err_no_qh; - } - urbp->qh = qh; - - switch (qh->type) { - case USB_ENDPOINT_XFER_CONTROL: - ret = uhci_submit_control(uhci, urb, qh); - break; - case USB_ENDPOINT_XFER_BULK: - ret = uhci_submit_bulk(uhci, urb, qh); - break; - case USB_ENDPOINT_XFER_INT: - ret = uhci_submit_interrupt(uhci, urb, qh); - break; - case USB_ENDPOINT_XFER_ISOC: - urb->error_count = 0; - ret = uhci_submit_isochronous(uhci, urb, qh); - break; - } - if (ret != 0) - goto err_submit_failed; - - /* Add this URB to the QH */ - list_add_tail(&urbp->node, &qh->queue); - - /* If the new URB is the first and only one on this QH then either - * the QH is new and idle or else it's unlinked and waiting to - * become idle, so we can activate it right away. But only if the - * queue isn't stopped. */ - if (qh->queue.next == &urbp->node && !qh->is_stopped) { - uhci_activate_qh(uhci, qh); - uhci_urbp_wants_fsbr(uhci, urbp); - } - goto done; - -err_submit_failed: - if (qh->state == QH_STATE_IDLE) - uhci_make_qh_idle(uhci, qh); /* Reclaim unused QH */ -err_no_qh: - uhci_free_urb_priv(uhci, urbp); -done: - if (ret) - usb_hcd_unlink_urb_from_ep(hcd, urb); -done_not_linked: - spin_unlock_irqrestore(&uhci->lock, flags); - return ret; -} - -static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) -{ - struct uhci_hcd *uhci = hcd_to_uhci(hcd); - unsigned long flags; - struct uhci_qh *qh; - int rc; - - spin_lock_irqsave(&uhci->lock, flags); - rc = usb_hcd_check_unlink_urb(hcd, urb, status); - if (rc) - goto done; - - qh = ((struct urb_priv *) urb->hcpriv)->qh; - - /* Remove Isochronous TDs from the frame list ASAP */ - if (qh->type == USB_ENDPOINT_XFER_ISOC) { - uhci_unlink_isochronous_tds(uhci, urb); - mb(); - - /* If the URB has already started, update the QH unlink time */ - uhci_get_current_frame_number(uhci); - if (uhci_frame_before_eq(urb->start_frame, uhci->frame_number)) - qh->unlink_frame = uhci->frame_number; - } - - uhci_unlink_qh(uhci, qh); - -done: - spin_unlock_irqrestore(&uhci->lock, flags); - return rc; -} - -/* - * Finish unlinking an URB and give it back - */ -static void uhci_giveback_urb(struct uhci_hcd *uhci, struct uhci_qh *qh, - struct urb *urb, int status) -__releases(uhci->lock) -__acquires(uhci->lock) -{ - struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv; - - if (qh->type == USB_ENDPOINT_XFER_CONTROL) { - - /* Subtract off the length of the SETUP packet from - * urb->actual_length. - */ - urb->actual_length -= min_t(u32, 8, urb->actual_length); - } - - /* When giving back the first URB in an Isochronous queue, - * reinitialize the QH's iso-related members for the next URB. */ - else if (qh->type == USB_ENDPOINT_XFER_ISOC && - urbp->node.prev == &qh->queue && - urbp->node.next != &qh->queue) { - struct urb *nurb = list_entry(urbp->node.next, - struct urb_priv, node)->urb; - - qh->iso_packet_desc = &nurb->iso_frame_desc[0]; - qh->iso_frame = nurb->start_frame; - } - - /* Take the URB off the QH's queue. If the queue is now empty, - * this is a perfect time for a toggle fixup. */ - list_del_init(&urbp->node); - if (list_empty(&qh->queue) && qh->needs_fixup) { - usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe), qh->initial_toggle); - qh->needs_fixup = 0; - } - - uhci_free_urb_priv(uhci, urbp); - usb_hcd_unlink_urb_from_ep(uhci_to_hcd(uhci), urb); - - spin_unlock(&uhci->lock); - usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb, status); - spin_lock(&uhci->lock); - - /* If the queue is now empty, we can unlink the QH and give up its - * reserved bandwidth. */ - if (list_empty(&qh->queue)) { - uhci_unlink_qh(uhci, qh); - if (qh->bandwidth_reserved) - uhci_release_bandwidth(uhci, qh); - } -} - -/* - * Scan the URBs in a QH's queue - */ -#define QH_FINISHED_UNLINKING(qh) \ - (qh->state == QH_STATE_UNLINKING && \ - uhci->frame_number + uhci->is_stopped != qh->unlink_frame) - -static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) -{ - struct urb_priv *urbp; - struct urb *urb; - int status; - - while (!list_empty(&qh->queue)) { - urbp = list_entry(qh->queue.next, struct urb_priv, node); - urb = urbp->urb; - - if (qh->type == USB_ENDPOINT_XFER_ISOC) - status = uhci_result_isochronous(uhci, urb); - else - status = uhci_result_common(uhci, urb); - if (status == -EINPROGRESS) - break; - - /* Dequeued but completed URBs can't be given back unless - * the QH is stopped or has finished unlinking. */ - if (urb->unlinked) { - if (QH_FINISHED_UNLINKING(qh)) - qh->is_stopped = 1; - else if (!qh->is_stopped) - return; - } - - uhci_giveback_urb(uhci, qh, urb, status); - if (status < 0) - break; - } - - /* If the QH is neither stopped nor finished unlinking (normal case), - * our work here is done. */ - if (QH_FINISHED_UNLINKING(qh)) - qh->is_stopped = 1; - else if (!qh->is_stopped) - return; - - /* Otherwise give back each of the dequeued URBs */ -restart: - list_for_each_entry(urbp, &qh->queue, node) { - urb = urbp->urb; - if (urb->unlinked) { - - /* Fix up the TD links and save the toggles for - * non-Isochronous queues. For Isochronous queues, - * test for too-recent dequeues. */ - if (!uhci_cleanup_queue(uhci, qh, urb)) { - qh->is_stopped = 0; - return; - } - uhci_giveback_urb(uhci, qh, urb, 0); - goto restart; - } - } - qh->is_stopped = 0; - - /* There are no more dequeued URBs. If there are still URBs on the - * queue, the QH can now be re-activated. */ - if (!list_empty(&qh->queue)) { - if (qh->needs_fixup) - uhci_fixup_toggles(uhci, qh, 0); - - /* If the first URB on the queue wants FSBR but its time - * limit has expired, set the next TD to interrupt on - * completion before reactivating the QH. */ - urbp = list_entry(qh->queue.next, struct urb_priv, node); - if (urbp->fsbr && qh->wait_expired) { - struct uhci_td *td = list_entry(urbp->td_list.next, - struct uhci_td, list); - - td->status |= cpu_to_hc32(uhci, TD_CTRL_IOC); - } - - uhci_activate_qh(uhci, qh); - } - - /* The queue is empty. The QH can become idle if it is fully - * unlinked. */ - else if (QH_FINISHED_UNLINKING(qh)) - uhci_make_qh_idle(uhci, qh); -} - -/* - * Check for queues that have made some forward progress. - * Returns 0 if the queue is not Isochronous, is ACTIVE, and - * has not advanced since last examined; 1 otherwise. - * - * Early Intel controllers have a bug which causes qh->element sometimes - * not to advance when a TD completes successfully. The queue remains - * stuck on the inactive completed TD. We detect such cases and advance - * the element pointer by hand. - */ -static int uhci_advance_check(struct uhci_hcd *uhci, struct uhci_qh *qh) -{ - struct urb_priv *urbp = NULL; - struct uhci_td *td; - int ret = 1; - unsigned status; - - if (qh->type == USB_ENDPOINT_XFER_ISOC) - goto done; - - /* Treat an UNLINKING queue as though it hasn't advanced. - * This is okay because reactivation will treat it as though - * it has advanced, and if it is going to become IDLE then - * this doesn't matter anyway. Furthermore it's possible - * for an UNLINKING queue not to have any URBs at all, or - * for its first URB not to have any TDs (if it was dequeued - * just as it completed). So it's not easy in any case to - * test whether such queues have advanced. */ - if (qh->state != QH_STATE_ACTIVE) { - urbp = NULL; - status = 0; - - } else { - urbp = list_entry(qh->queue.next, struct urb_priv, node); - td = list_entry(urbp->td_list.next, struct uhci_td, list); - status = td_status(uhci, td); - if (!(status & TD_CTRL_ACTIVE)) { - - /* We're okay, the queue has advanced */ - qh->wait_expired = 0; - qh->advance_jiffies = jiffies; - goto done; - } - ret = uhci->is_stopped; - } - - /* The queue hasn't advanced; check for timeout */ - if (qh->wait_expired) - goto done; - - if (time_after(jiffies, qh->advance_jiffies + QH_WAIT_TIMEOUT)) { - - /* Detect the Intel bug and work around it */ - if (qh->post_td && qh_element(qh) == - LINK_TO_TD(uhci, qh->post_td)) { - qh->element = qh->post_td->link; - qh->advance_jiffies = jiffies; - ret = 1; - goto done; - } - - qh->wait_expired = 1; - - /* If the current URB wants FSBR, unlink it temporarily - * so that we can safely set the next TD to interrupt on - * completion. That way we'll know as soon as the queue - * starts moving again. */ - if (urbp && urbp->fsbr && !(status & TD_CTRL_IOC)) - uhci_unlink_qh(uhci, qh); - - } else { - /* Unmoving but not-yet-expired queues keep FSBR alive */ - if (urbp) - uhci_urbp_wants_fsbr(uhci, urbp); - } - -done: - return ret; -} - -/* - * Process events in the schedule, but only in one thread at a time - */ -static void uhci_scan_schedule(struct uhci_hcd *uhci) -{ - int i; - struct uhci_qh *qh; - - /* Don't allow re-entrant calls */ - if (uhci->scan_in_progress) { - uhci->need_rescan = 1; - return; - } - uhci->scan_in_progress = 1; -rescan: - uhci->need_rescan = 0; - uhci->fsbr_is_wanted = 0; - - uhci_clear_next_interrupt(uhci); - uhci_get_current_frame_number(uhci); - uhci->cur_iso_frame = uhci->frame_number; - - /* Go through all the QH queues and process the URBs in each one */ - for (i = 0; i < UHCI_NUM_SKELQH - 1; ++i) { - uhci->next_qh = list_entry(uhci->skelqh[i]->node.next, - struct uhci_qh, node); - while ((qh = uhci->next_qh) != uhci->skelqh[i]) { - uhci->next_qh = list_entry(qh->node.next, - struct uhci_qh, node); - - if (uhci_advance_check(uhci, qh)) { - uhci_scan_qh(uhci, qh); - if (qh->state == QH_STATE_ACTIVE) { - uhci_urbp_wants_fsbr(uhci, - list_entry(qh->queue.next, struct urb_priv, node)); - } - } - } - } - - uhci->last_iso_frame = uhci->cur_iso_frame; - if (uhci->need_rescan) - goto rescan; - uhci->scan_in_progress = 0; - - if (uhci->fsbr_is_on && !uhci->fsbr_is_wanted && - !uhci->fsbr_expiring) { - uhci->fsbr_expiring = 1; - mod_timer(&uhci->fsbr_timer, jiffies + FSBR_OFF_DELAY); - } - - if (list_empty(&uhci->skel_unlink_qh->node)) - uhci_clear_next_interrupt(uhci); - else - uhci_set_next_interrupt(uhci); -} diff --git a/ANDROID_3.4.5/drivers/usb/host/whci/Kbuild b/ANDROID_3.4.5/drivers/usb/host/whci/Kbuild deleted file mode 100644 index 26df0138..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/whci/Kbuild +++ /dev/null @@ -1,12 +0,0 @@ -obj-$(CONFIG_USB_WHCI_HCD) += whci-hcd.o - -whci-hcd-y := \ - asl.o \ - debug.o \ - hcd.o \ - hw.o \ - init.o \ - int.o \ - pzl.o \ - qset.o \ - wusb.o diff --git a/ANDROID_3.4.5/drivers/usb/host/whci/asl.c b/ANDROID_3.4.5/drivers/usb/host/whci/asl.c deleted file mode 100644 index 77324930..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/whci/asl.c +++ /dev/null @@ -1,389 +0,0 @@ -/* - * Wireless Host Controller (WHC) asynchronous schedule management. - * - * Copyright (C) 2007 Cambridge Silicon Radio Ltd. - * - * 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, see . - */ -#include -#include -#include -#include -#include - -#include "../../wusbcore/wusbhc.h" - -#include "whcd.h" - -static void qset_get_next_prev(struct whc *whc, struct whc_qset *qset, - struct whc_qset **next, struct whc_qset **prev) -{ - struct list_head *n, *p; - - BUG_ON(list_empty(&whc->async_list)); - - n = qset->list_node.next; - if (n == &whc->async_list) - n = n->next; - p = qset->list_node.prev; - if (p == &whc->async_list) - p = p->prev; - - *next = container_of(n, struct whc_qset, list_node); - *prev = container_of(p, struct whc_qset, list_node); - -} - -static void asl_qset_insert_begin(struct whc *whc, struct whc_qset *qset) -{ - list_move(&qset->list_node, &whc->async_list); - qset->in_sw_list = true; -} - -static void asl_qset_insert(struct whc *whc, struct whc_qset *qset) -{ - struct whc_qset *next, *prev; - - qset_clear(whc, qset); - - /* Link into ASL. */ - qset_get_next_prev(whc, qset, &next, &prev); - whc_qset_set_link_ptr(&qset->qh.link, next->qset_dma); - whc_qset_set_link_ptr(&prev->qh.link, qset->qset_dma); - qset->in_hw_list = true; -} - -static void asl_qset_remove(struct whc *whc, struct whc_qset *qset) -{ - struct whc_qset *prev, *next; - - qset_get_next_prev(whc, qset, &next, &prev); - - list_move(&qset->list_node, &whc->async_removed_list); - qset->in_sw_list = false; - - /* - * No more qsets in the ASL? The caller must stop the ASL as - * it's no longer valid. - */ - if (list_empty(&whc->async_list)) - return; - - /* Remove from ASL. */ - whc_qset_set_link_ptr(&prev->qh.link, next->qset_dma); - qset->in_hw_list = false; -} - -/** - * process_qset - process any recently inactivated or halted qTDs in a - * qset. - * - * After inactive qTDs are removed, new qTDs can be added if the - * urb queue still contains URBs. - * - * Returns any additional WUSBCMD bits for the ASL sync command (i.e., - * WUSBCMD_ASYNC_QSET_RM if a halted qset was removed). - */ -static uint32_t process_qset(struct whc *whc, struct whc_qset *qset) -{ - enum whc_update update = 0; - uint32_t status = 0; - - while (qset->ntds) { - struct whc_qtd *td; - int t; - - t = qset->td_start; - td = &qset->qtd[qset->td_start]; - status = le32_to_cpu(td->status); - - /* - * Nothing to do with a still active qTD. - */ - if (status & QTD_STS_ACTIVE) - break; - - if (status & QTD_STS_HALTED) { - /* Ug, an error. */ - process_halted_qtd(whc, qset, td); - /* A halted qTD always triggers an update - because the qset was either removed or - reactivated. */ - update |= WHC_UPDATE_UPDATED; - goto done; - } - - /* Mmm, a completed qTD. */ - process_inactive_qtd(whc, qset, td); - } - - if (!qset->remove) - update |= qset_add_qtds(whc, qset); - -done: - /* - * Remove this qset from the ASL if requested, but only if has - * no qTDs. - */ - if (qset->remove && qset->ntds == 0) { - asl_qset_remove(whc, qset); - update |= WHC_UPDATE_REMOVED; - } - return update; -} - -void asl_start(struct whc *whc) -{ - struct whc_qset *qset; - - qset = list_first_entry(&whc->async_list, struct whc_qset, list_node); - - le_writeq(qset->qset_dma | QH_LINK_NTDS(8), whc->base + WUSBASYNCLISTADDR); - - whc_write_wusbcmd(whc, WUSBCMD_ASYNC_EN, WUSBCMD_ASYNC_EN); - whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS, - WUSBSTS_ASYNC_SCHED, WUSBSTS_ASYNC_SCHED, - 1000, "start ASL"); -} - -void asl_stop(struct whc *whc) -{ - whc_write_wusbcmd(whc, WUSBCMD_ASYNC_EN, 0); - whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS, - WUSBSTS_ASYNC_SCHED, 0, - 1000, "stop ASL"); -} - -/** - * asl_update - request an ASL update and wait for the hardware to be synced - * @whc: the WHCI HC - * @wusbcmd: WUSBCMD value to start the update. - * - * If the WUSB HC is inactive (i.e., the ASL is stopped) then the - * update must be skipped as the hardware may not respond to update - * requests. - */ -void asl_update(struct whc *whc, uint32_t wusbcmd) -{ - struct wusbhc *wusbhc = &whc->wusbhc; - long t; - - mutex_lock(&wusbhc->mutex); - if (wusbhc->active) { - whc_write_wusbcmd(whc, wusbcmd, wusbcmd); - t = wait_event_timeout( - whc->async_list_wq, - (le_readl(whc->base + WUSBCMD) & WUSBCMD_ASYNC_UPDATED) == 0, - msecs_to_jiffies(1000)); - if (t == 0) - whc_hw_error(whc, "ASL update timeout"); - } - mutex_unlock(&wusbhc->mutex); -} - -/** - * scan_async_work - scan the ASL for qsets to process. - * - * Process each qset in the ASL in turn and then signal the WHC that - * the ASL has been updated. - * - * Then start, stop or update the asynchronous schedule as required. - */ -void scan_async_work(struct work_struct *work) -{ - struct whc *whc = container_of(work, struct whc, async_work); - struct whc_qset *qset, *t; - enum whc_update update = 0; - - spin_lock_irq(&whc->lock); - - /* - * Transerve the software list backwards so new qsets can be - * safely inserted into the ASL without making it non-circular. - */ - list_for_each_entry_safe_reverse(qset, t, &whc->async_list, list_node) { - if (!qset->in_hw_list) { - asl_qset_insert(whc, qset); - update |= WHC_UPDATE_ADDED; - } - - update |= process_qset(whc, qset); - } - - spin_unlock_irq(&whc->lock); - - if (update) { - uint32_t wusbcmd = WUSBCMD_ASYNC_UPDATED | WUSBCMD_ASYNC_SYNCED_DB; - if (update & WHC_UPDATE_REMOVED) - wusbcmd |= WUSBCMD_ASYNC_QSET_RM; - asl_update(whc, wusbcmd); - } - - /* - * Now that the ASL is updated, complete the removal of any - * removed qsets. - * - * If the qset was to be reset, do so and reinsert it into the - * ASL if it has pending transfers. - */ - spin_lock_irq(&whc->lock); - - list_for_each_entry_safe(qset, t, &whc->async_removed_list, list_node) { - qset_remove_complete(whc, qset); - if (qset->reset) { - qset_reset(whc, qset); - if (!list_empty(&qset->stds)) { - asl_qset_insert_begin(whc, qset); - queue_work(whc->workqueue, &whc->async_work); - } - } - } - - spin_unlock_irq(&whc->lock); -} - -/** - * asl_urb_enqueue - queue an URB onto the asynchronous list (ASL). - * @whc: the WHCI host controller - * @urb: the URB to enqueue - * @mem_flags: flags for any memory allocations - * - * The qset for the endpoint is obtained and the urb queued on to it. - * - * Work is scheduled to update the hardware's view of the ASL. - */ -int asl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags) -{ - struct whc_qset *qset; - int err; - unsigned long flags; - - spin_lock_irqsave(&whc->lock, flags); - - err = usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb); - if (err < 0) { - spin_unlock_irqrestore(&whc->lock, flags); - return err; - } - - qset = get_qset(whc, urb, GFP_ATOMIC); - if (qset == NULL) - err = -ENOMEM; - else - err = qset_add_urb(whc, qset, urb, GFP_ATOMIC); - if (!err) { - if (!qset->in_sw_list && !qset->remove) - asl_qset_insert_begin(whc, qset); - } else - usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb); - - spin_unlock_irqrestore(&whc->lock, flags); - - if (!err) - queue_work(whc->workqueue, &whc->async_work); - - return err; -} - -/** - * asl_urb_dequeue - remove an URB (qset) from the async list. - * @whc: the WHCI host controller - * @urb: the URB to dequeue - * @status: the current status of the URB - * - * URBs that do yet have qTDs can simply be removed from the software - * queue, otherwise the qset must be removed from the ASL so the qTDs - * can be removed. - */ -int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status) -{ - struct whc_urb *wurb = urb->hcpriv; - struct whc_qset *qset = wurb->qset; - struct whc_std *std, *t; - bool has_qtd = false; - int ret; - unsigned long flags; - - spin_lock_irqsave(&whc->lock, flags); - - ret = usb_hcd_check_unlink_urb(&whc->wusbhc.usb_hcd, urb, status); - if (ret < 0) - goto out; - - list_for_each_entry_safe(std, t, &qset->stds, list_node) { - if (std->urb == urb) { - if (std->qtd) - has_qtd = true; - qset_free_std(whc, std); - } else - std->qtd = NULL; /* so this std is re-added when the qset is */ - } - - if (has_qtd) { - asl_qset_remove(whc, qset); - wurb->status = status; - wurb->is_async = true; - queue_work(whc->workqueue, &wurb->dequeue_work); - } else - qset_remove_urb(whc, qset, urb, status); -out: - spin_unlock_irqrestore(&whc->lock, flags); - - return ret; -} - -/** - * asl_qset_delete - delete a qset from the ASL - */ -void asl_qset_delete(struct whc *whc, struct whc_qset *qset) -{ - qset->remove = 1; - queue_work(whc->workqueue, &whc->async_work); - qset_delete(whc, qset); -} - -/** - * asl_init - initialize the asynchronous schedule list - * - * A dummy qset with no qTDs is added to the ASL to simplify removing - * qsets (no need to stop the ASL when the last qset is removed). - */ -int asl_init(struct whc *whc) -{ - struct whc_qset *qset; - - qset = qset_alloc(whc, GFP_KERNEL); - if (qset == NULL) - return -ENOMEM; - - asl_qset_insert_begin(whc, qset); - asl_qset_insert(whc, qset); - - return 0; -} - -/** - * asl_clean_up - free ASL resources - * - * The ASL is stopped and empty except for the dummy qset. - */ -void asl_clean_up(struct whc *whc) -{ - struct whc_qset *qset; - - if (!list_empty(&whc->async_list)) { - qset = list_first_entry(&whc->async_list, struct whc_qset, list_node); - list_del(&qset->list_node); - qset_free(whc, qset); - } -} diff --git a/ANDROID_3.4.5/drivers/usb/host/whci/debug.c b/ANDROID_3.4.5/drivers/usb/host/whci/debug.c deleted file mode 100644 index ba61dae9..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/whci/debug.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Wireless Host Controller (WHC) debug. - * - * Copyright (C) 2008 Cambridge Silicon Radio Ltd. - * - * 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, see . - */ -#include -#include -#include -#include -#include - -#include "../../wusbcore/wusbhc.h" - -#include "whcd.h" - -struct whc_dbg { - struct dentry *di_f; - struct dentry *asl_f; - struct dentry *pzl_f; -}; - -static void qset_print(struct seq_file *s, struct whc_qset *qset) -{ - static const char *qh_type[] = { - "ctrl", "isoc", "bulk", "intr", "rsvd", "rsvd", "rsvd", "lpintr", }; - struct whc_std *std; - struct urb *urb = NULL; - int i; - - seq_printf(s, "qset %08x", (u32)qset->qset_dma); - if (&qset->list_node == qset->whc->async_list.prev) { - seq_printf(s, " (dummy)\n"); - } else { - seq_printf(s, " ep%d%s-%s maxpkt: %d\n", - qset->qh.info1 & 0x0f, - (qset->qh.info1 >> 4) & 0x1 ? "in" : "out", - qh_type[(qset->qh.info1 >> 5) & 0x7], - (qset->qh.info1 >> 16) & 0xffff); - } - seq_printf(s, " -> %08x\n", (u32)qset->qh.link); - seq_printf(s, " info: %08x %08x %08x\n", - qset->qh.info1, qset->qh.info2, qset->qh.info3); - seq_printf(s, " sts: %04x errs: %d curwin: %08x\n", - qset->qh.status, qset->qh.err_count, qset->qh.cur_window); - seq_printf(s, " TD: sts: %08x opts: %08x\n", - qset->qh.overlay.qtd.status, qset->qh.overlay.qtd.options); - - for (i = 0; i < WHCI_QSET_TD_MAX; i++) { - seq_printf(s, " %c%c TD[%d]: sts: %08x opts: %08x ptr: %08x\n", - i == qset->td_start ? 'S' : ' ', - i == qset->td_end ? 'E' : ' ', - i, qset->qtd[i].status, qset->qtd[i].options, - (u32)qset->qtd[i].page_list_ptr); - } - seq_printf(s, " ntds: %d\n", qset->ntds); - list_for_each_entry(std, &qset->stds, list_node) { - if (urb != std->urb) { - urb = std->urb; - seq_printf(s, " urb %p transferred: %d bytes\n", urb, - urb->actual_length); - } - if (std->qtd) - seq_printf(s, " sTD[%td]: %zu bytes @ %08x\n", - std->qtd - &qset->qtd[0], - std->len, std->num_pointers ? - (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr); - else - seq_printf(s, " sTD[-]: %zd bytes @ %08x\n", - std->len, std->num_pointers ? - (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr); - } -} - -static int di_print(struct seq_file *s, void *p) -{ - struct whc *whc = s->private; - char buf[72]; - int d; - - for (d = 0; d < whc->n_devices; d++) { - struct di_buf_entry *di = &whc->di_buf[d]; - - bitmap_scnprintf(buf, sizeof(buf), - (unsigned long *)di->availability_info, UWB_NUM_MAS); - - seq_printf(s, "DI[%d]\n", d); - seq_printf(s, " availability: %s\n", buf); - seq_printf(s, " %c%c key idx: %d dev addr: %d\n", - (di->addr_sec_info & WHC_DI_SECURE) ? 'S' : ' ', - (di->addr_sec_info & WHC_DI_DISABLE) ? 'D' : ' ', - (di->addr_sec_info & WHC_DI_KEY_IDX_MASK) >> 8, - (di->addr_sec_info & WHC_DI_DEV_ADDR_MASK)); - } - return 0; -} - -static int asl_print(struct seq_file *s, void *p) -{ - struct whc *whc = s->private; - struct whc_qset *qset; - - list_for_each_entry(qset, &whc->async_list, list_node) { - qset_print(s, qset); - } - - return 0; -} - -static int pzl_print(struct seq_file *s, void *p) -{ - struct whc *whc = s->private; - struct whc_qset *qset; - int period; - - for (period = 0; period < 5; period++) { - seq_printf(s, "Period %d\n", period); - list_for_each_entry(qset, &whc->periodic_list[period], list_node) { - qset_print(s, qset); - } - } - return 0; -} - -static int di_open(struct inode *inode, struct file *file) -{ - return single_open(file, di_print, inode->i_private); -} - -static int asl_open(struct inode *inode, struct file *file) -{ - return single_open(file, asl_print, inode->i_private); -} - -static int pzl_open(struct inode *inode, struct file *file) -{ - return single_open(file, pzl_print, inode->i_private); -} - -static const struct file_operations di_fops = { - .open = di_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static const struct file_operations asl_fops = { - .open = asl_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static const struct file_operations pzl_fops = { - .open = pzl_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -void whc_dbg_init(struct whc *whc) -{ - if (whc->wusbhc.pal.debugfs_dir == NULL) - return; - - whc->dbg = kzalloc(sizeof(struct whc_dbg), GFP_KERNEL); - if (whc->dbg == NULL) - return; - - whc->dbg->di_f = debugfs_create_file("di", 0444, - whc->wusbhc.pal.debugfs_dir, whc, - &di_fops); - whc->dbg->asl_f = debugfs_create_file("asl", 0444, - whc->wusbhc.pal.debugfs_dir, whc, - &asl_fops); - whc->dbg->pzl_f = debugfs_create_file("pzl", 0444, - whc->wusbhc.pal.debugfs_dir, whc, - &pzl_fops); -} - -void whc_dbg_clean_up(struct whc *whc) -{ - if (whc->dbg) { - debugfs_remove(whc->dbg->pzl_f); - debugfs_remove(whc->dbg->asl_f); - debugfs_remove(whc->dbg->di_f); - kfree(whc->dbg); - } -} diff --git a/ANDROID_3.4.5/drivers/usb/host/whci/hcd.c b/ANDROID_3.4.5/drivers/usb/host/whci/hcd.c deleted file mode 100644 index 1e141f75..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/whci/hcd.c +++ /dev/null @@ -1,368 +0,0 @@ -/* - * Wireless Host Controller (WHC) driver. - * - * Copyright (C) 2007 Cambridge Silicon Radio Ltd. - * - * 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, see . - */ -#include -#include -#include -#include - -#include "../../wusbcore/wusbhc.h" - -#include "whcd.h" - -/* - * One time initialization. - * - * Nothing to do here. - */ -static int whc_reset(struct usb_hcd *usb_hcd) -{ - return 0; -} - -/* - * Start the wireless host controller. - * - * Start device notification. - * - * Put hc into run state, set DNTS parameters. - */ -static int whc_start(struct usb_hcd *usb_hcd) -{ - struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); - struct whc *whc = wusbhc_to_whc(wusbhc); - u8 bcid; - int ret; - - mutex_lock(&wusbhc->mutex); - - le_writel(WUSBINTR_GEN_CMD_DONE - | WUSBINTR_HOST_ERR - | WUSBINTR_ASYNC_SCHED_SYNCED - | WUSBINTR_DNTS_INT - | WUSBINTR_ERR_INT - | WUSBINTR_INT, - whc->base + WUSBINTR); - - /* set cluster ID */ - bcid = wusb_cluster_id_get(); - ret = whc_set_cluster_id(whc, bcid); - if (ret < 0) - goto out; - wusbhc->cluster_id = bcid; - - /* start HC */ - whc_write_wusbcmd(whc, WUSBCMD_RUN, WUSBCMD_RUN); - - usb_hcd->uses_new_polling = 1; - set_bit(HCD_FLAG_POLL_RH, &usb_hcd->flags); - usb_hcd->state = HC_STATE_RUNNING; - -out: - mutex_unlock(&wusbhc->mutex); - return ret; -} - - -/* - * Stop the wireless host controller. - * - * Stop device notification. - * - * Wait for pending transfer to stop? Put hc into stop state? - */ -static void whc_stop(struct usb_hcd *usb_hcd) -{ - struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); - struct whc *whc = wusbhc_to_whc(wusbhc); - - mutex_lock(&wusbhc->mutex); - - /* stop HC */ - le_writel(0, whc->base + WUSBINTR); - whc_write_wusbcmd(whc, WUSBCMD_RUN, 0); - whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS, - WUSBSTS_HCHALTED, WUSBSTS_HCHALTED, - 100, "HC to halt"); - - wusb_cluster_id_put(wusbhc->cluster_id); - - mutex_unlock(&wusbhc->mutex); -} - -static int whc_get_frame_number(struct usb_hcd *usb_hcd) -{ - /* Frame numbers are not applicable to WUSB. */ - return -ENOSYS; -} - - -/* - * Queue an URB to the ASL or PZL - */ -static int whc_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb, - gfp_t mem_flags) -{ - struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); - struct whc *whc = wusbhc_to_whc(wusbhc); - int ret; - - switch (usb_pipetype(urb->pipe)) { - case PIPE_INTERRUPT: - ret = pzl_urb_enqueue(whc, urb, mem_flags); - break; - case PIPE_ISOCHRONOUS: - dev_err(&whc->umc->dev, "isochronous transfers unsupported\n"); - ret = -ENOTSUPP; - break; - case PIPE_CONTROL: - case PIPE_BULK: - default: - ret = asl_urb_enqueue(whc, urb, mem_flags); - break; - }; - - return ret; -} - -/* - * Remove a queued URB from the ASL or PZL. - */ -static int whc_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb, int status) -{ - struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); - struct whc *whc = wusbhc_to_whc(wusbhc); - int ret; - - switch (usb_pipetype(urb->pipe)) { - case PIPE_INTERRUPT: - ret = pzl_urb_dequeue(whc, urb, status); - break; - case PIPE_ISOCHRONOUS: - ret = -ENOTSUPP; - break; - case PIPE_CONTROL: - case PIPE_BULK: - default: - ret = asl_urb_dequeue(whc, urb, status); - break; - }; - - return ret; -} - -/* - * Wait for all URBs to the endpoint to be completed, then delete the - * qset. - */ -static void whc_endpoint_disable(struct usb_hcd *usb_hcd, - struct usb_host_endpoint *ep) -{ - struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); - struct whc *whc = wusbhc_to_whc(wusbhc); - struct whc_qset *qset; - - qset = ep->hcpriv; - if (qset) { - ep->hcpriv = NULL; - if (usb_endpoint_xfer_bulk(&ep->desc) - || usb_endpoint_xfer_control(&ep->desc)) - asl_qset_delete(whc, qset); - else - pzl_qset_delete(whc, qset); - } -} - -static void whc_endpoint_reset(struct usb_hcd *usb_hcd, - struct usb_host_endpoint *ep) -{ - struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); - struct whc *whc = wusbhc_to_whc(wusbhc); - struct whc_qset *qset; - unsigned long flags; - - spin_lock_irqsave(&whc->lock, flags); - - qset = ep->hcpriv; - if (qset) { - qset->remove = 1; - qset->reset = 1; - - if (usb_endpoint_xfer_bulk(&ep->desc) - || usb_endpoint_xfer_control(&ep->desc)) - queue_work(whc->workqueue, &whc->async_work); - else - queue_work(whc->workqueue, &whc->periodic_work); - } - - spin_unlock_irqrestore(&whc->lock, flags); -} - - -static struct hc_driver whc_hc_driver = { - .description = "whci-hcd", - .product_desc = "Wireless host controller", - .hcd_priv_size = sizeof(struct whc) - sizeof(struct usb_hcd), - .irq = whc_int_handler, - .flags = HCD_USB2, - - .reset = whc_reset, - .start = whc_start, - .stop = whc_stop, - .get_frame_number = whc_get_frame_number, - .urb_enqueue = whc_urb_enqueue, - .urb_dequeue = whc_urb_dequeue, - .endpoint_disable = whc_endpoint_disable, - .endpoint_reset = whc_endpoint_reset, - - .hub_status_data = wusbhc_rh_status_data, - .hub_control = wusbhc_rh_control, - .bus_suspend = wusbhc_rh_suspend, - .bus_resume = wusbhc_rh_resume, - .start_port_reset = wusbhc_rh_start_port_reset, -}; - -static int whc_probe(struct umc_dev *umc) -{ - int ret = -ENOMEM; - struct usb_hcd *usb_hcd; - struct wusbhc *wusbhc = NULL; - struct whc *whc = NULL; - struct device *dev = &umc->dev; - - usb_hcd = usb_create_hcd(&whc_hc_driver, dev, "whci"); - if (usb_hcd == NULL) { - dev_err(dev, "unable to create hcd\n"); - goto error; - } - - usb_hcd->wireless = 1; - usb_hcd->self.sg_tablesize = 2048; /* somewhat arbitrary */ - - wusbhc = usb_hcd_to_wusbhc(usb_hcd); - whc = wusbhc_to_whc(wusbhc); - whc->umc = umc; - - ret = whc_init(whc); - if (ret) - goto error; - - wusbhc->dev = dev; - wusbhc->uwb_rc = uwb_rc_get_by_grandpa(umc->dev.parent); - if (!wusbhc->uwb_rc) { - ret = -ENODEV; - dev_err(dev, "cannot get radio controller\n"); - goto error; - } - - if (whc->n_devices > USB_MAXCHILDREN) { - dev_warn(dev, "USB_MAXCHILDREN too low for WUSB adapter (%u ports)\n", - whc->n_devices); - wusbhc->ports_max = USB_MAXCHILDREN; - } else - wusbhc->ports_max = whc->n_devices; - wusbhc->mmcies_max = whc->n_mmc_ies; - wusbhc->start = whc_wusbhc_start; - wusbhc->stop = whc_wusbhc_stop; - wusbhc->mmcie_add = whc_mmcie_add; - wusbhc->mmcie_rm = whc_mmcie_rm; - wusbhc->dev_info_set = whc_dev_info_set; - wusbhc->bwa_set = whc_bwa_set; - wusbhc->set_num_dnts = whc_set_num_dnts; - wusbhc->set_ptk = whc_set_ptk; - wusbhc->set_gtk = whc_set_gtk; - - ret = wusbhc_create(wusbhc); - if (ret) - goto error_wusbhc_create; - - ret = usb_add_hcd(usb_hcd, whc->umc->irq, IRQF_SHARED); - if (ret) { - dev_err(dev, "cannot add HCD: %d\n", ret); - goto error_usb_add_hcd; - } - - ret = wusbhc_b_create(wusbhc); - if (ret) { - dev_err(dev, "WUSBHC phase B setup failed: %d\n", ret); - goto error_wusbhc_b_create; - } - - whc_dbg_init(whc); - - return 0; - -error_wusbhc_b_create: - usb_remove_hcd(usb_hcd); -error_usb_add_hcd: - wusbhc_destroy(wusbhc); -error_wusbhc_create: - uwb_rc_put(wusbhc->uwb_rc); -error: - whc_clean_up(whc); - if (usb_hcd) - usb_put_hcd(usb_hcd); - return ret; -} - - -static void whc_remove(struct umc_dev *umc) -{ - struct usb_hcd *usb_hcd = dev_get_drvdata(&umc->dev); - struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); - struct whc *whc = wusbhc_to_whc(wusbhc); - - if (usb_hcd) { - whc_dbg_clean_up(whc); - wusbhc_b_destroy(wusbhc); - usb_remove_hcd(usb_hcd); - wusbhc_destroy(wusbhc); - uwb_rc_put(wusbhc->uwb_rc); - whc_clean_up(whc); - usb_put_hcd(usb_hcd); - } -} - -static struct umc_driver whci_hc_driver = { - .name = "whci-hcd", - .cap_id = UMC_CAP_ID_WHCI_WUSB_HC, - .probe = whc_probe, - .remove = whc_remove, -}; - -static int __init whci_hc_driver_init(void) -{ - return umc_driver_register(&whci_hc_driver); -} -module_init(whci_hc_driver_init); - -static void __exit whci_hc_driver_exit(void) -{ - umc_driver_unregister(&whci_hc_driver); -} -module_exit(whci_hc_driver_exit); - -/* PCI device ID's that we handle (so it gets loaded) */ -static struct pci_device_id __used whci_hcd_id_table[] = { - { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) }, - { /* empty last entry */ } -}; -MODULE_DEVICE_TABLE(pci, whci_hcd_id_table); - -MODULE_DESCRIPTION("WHCI Wireless USB host controller driver"); -MODULE_AUTHOR("Cambridge Silicon Radio Ltd."); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/host/whci/hw.c b/ANDROID_3.4.5/drivers/usb/host/whci/hw.c deleted file mode 100644 index 6afa2e37..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/whci/hw.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Wireless Host Controller (WHC) hardware access helpers. - * - * Copyright (C) 2007 Cambridge Silicon Radio Ltd. - * - * 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, see . - */ -#include -#include -#include - -#include "../../wusbcore/wusbhc.h" - -#include "whcd.h" - -void whc_write_wusbcmd(struct whc *whc, u32 mask, u32 val) -{ - unsigned long flags; - u32 cmd; - - spin_lock_irqsave(&whc->lock, flags); - - cmd = le_readl(whc->base + WUSBCMD); - cmd = (cmd & ~mask) | val; - le_writel(cmd, whc->base + WUSBCMD); - - spin_unlock_irqrestore(&whc->lock, flags); -} - -/** - * whc_do_gencmd - start a generic command via the WUSBGENCMDSTS register - * @whc: the WHCI HC - * @cmd: command to start. - * @params: parameters for the command (the WUSBGENCMDPARAMS register value). - * @addr: pointer to any data for the command (may be NULL). - * @len: length of the data (if any). - */ -int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len) -{ - unsigned long flags; - dma_addr_t dma_addr; - int t; - int ret = 0; - - mutex_lock(&whc->mutex); - - /* Wait for previous command to complete. */ - t = wait_event_timeout(whc->cmd_wq, - (le_readl(whc->base + WUSBGENCMDSTS) & WUSBGENCMDSTS_ACTIVE) == 0, - WHC_GENCMD_TIMEOUT_MS); - if (t == 0) { - dev_err(&whc->umc->dev, "generic command timeout (%04x/%04x)\n", - le_readl(whc->base + WUSBGENCMDSTS), - le_readl(whc->base + WUSBGENCMDPARAMS)); - ret = -ETIMEDOUT; - goto out; - } - - if (addr) { - memcpy(whc->gen_cmd_buf, addr, len); - dma_addr = whc->gen_cmd_buf_dma; - } else - dma_addr = 0; - - /* Poke registers to start cmd. */ - spin_lock_irqsave(&whc->lock, flags); - - le_writel(params, whc->base + WUSBGENCMDPARAMS); - le_writeq(dma_addr, whc->base + WUSBGENADDR); - - le_writel(WUSBGENCMDSTS_ACTIVE | WUSBGENCMDSTS_IOC | cmd, - whc->base + WUSBGENCMDSTS); - - spin_unlock_irqrestore(&whc->lock, flags); -out: - mutex_unlock(&whc->mutex); - - return ret; -} - -/** - * whc_hw_error - recover from a hardware error - * @whc: the WHCI HC that broke. - * @reason: a description of the failure. - * - * Recover from broken hardware with a full reset. - */ -void whc_hw_error(struct whc *whc, const char *reason) -{ - struct wusbhc *wusbhc = &whc->wusbhc; - - dev_err(&whc->umc->dev, "hardware error: %s\n", reason); - wusbhc_reset_all(wusbhc); -} diff --git a/ANDROID_3.4.5/drivers/usb/host/whci/init.c b/ANDROID_3.4.5/drivers/usb/host/whci/init.c deleted file mode 100644 index d3e13b64..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/whci/init.c +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Wireless Host Controller (WHC) initialization. - * - * Copyright (C) 2007 Cambridge Silicon Radio Ltd. - * - * 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, see . - */ -#include -#include -#include -#include - -#include "../../wusbcore/wusbhc.h" - -#include "whcd.h" - -/* - * Reset the host controller. - */ -static void whc_hw_reset(struct whc *whc) -{ - le_writel(WUSBCMD_WHCRESET, whc->base + WUSBCMD); - whci_wait_for(&whc->umc->dev, whc->base + WUSBCMD, WUSBCMD_WHCRESET, 0, - 100, "reset"); -} - -static void whc_hw_init_di_buf(struct whc *whc) -{ - int d; - - /* Disable all entries in the Device Information buffer. */ - for (d = 0; d < whc->n_devices; d++) - whc->di_buf[d].addr_sec_info = WHC_DI_DISABLE; - - le_writeq(whc->di_buf_dma, whc->base + WUSBDEVICEINFOADDR); -} - -static void whc_hw_init_dn_buf(struct whc *whc) -{ - /* Clear the Device Notification buffer to ensure the V (valid) - * bits are clear. */ - memset(whc->dn_buf, 0, 4096); - - le_writeq(whc->dn_buf_dma, whc->base + WUSBDNTSBUFADDR); -} - -int whc_init(struct whc *whc) -{ - u32 whcsparams; - int ret, i; - resource_size_t start, len; - - spin_lock_init(&whc->lock); - mutex_init(&whc->mutex); - init_waitqueue_head(&whc->cmd_wq); - init_waitqueue_head(&whc->async_list_wq); - init_waitqueue_head(&whc->periodic_list_wq); - whc->workqueue = create_singlethread_workqueue(dev_name(&whc->umc->dev)); - if (whc->workqueue == NULL) { - ret = -ENOMEM; - goto error; - } - INIT_WORK(&whc->dn_work, whc_dn_work); - - INIT_WORK(&whc->async_work, scan_async_work); - INIT_LIST_HEAD(&whc->async_list); - INIT_LIST_HEAD(&whc->async_removed_list); - - INIT_WORK(&whc->periodic_work, scan_periodic_work); - for (i = 0; i < 5; i++) - INIT_LIST_HEAD(&whc->periodic_list[i]); - INIT_LIST_HEAD(&whc->periodic_removed_list); - - /* Map HC registers. */ - start = whc->umc->resource.start; - len = whc->umc->resource.end - start + 1; - if (!request_mem_region(start, len, "whci-hc")) { - dev_err(&whc->umc->dev, "can't request HC region\n"); - ret = -EBUSY; - goto error; - } - whc->base_phys = start; - whc->base = ioremap(start, len); - if (!whc->base) { - dev_err(&whc->umc->dev, "ioremap\n"); - ret = -ENOMEM; - goto error; - } - - whc_hw_reset(whc); - - /* Read maximum number of devices, keys and MMC IEs. */ - whcsparams = le_readl(whc->base + WHCSPARAMS); - whc->n_devices = WHCSPARAMS_TO_N_DEVICES(whcsparams); - whc->n_keys = WHCSPARAMS_TO_N_KEYS(whcsparams); - whc->n_mmc_ies = WHCSPARAMS_TO_N_MMC_IES(whcsparams); - - dev_dbg(&whc->umc->dev, "N_DEVICES = %d, N_KEYS = %d, N_MMC_IES = %d\n", - whc->n_devices, whc->n_keys, whc->n_mmc_ies); - - whc->qset_pool = dma_pool_create("qset", &whc->umc->dev, - sizeof(struct whc_qset), 64, 0); - if (whc->qset_pool == NULL) { - ret = -ENOMEM; - goto error; - } - - ret = asl_init(whc); - if (ret < 0) - goto error; - ret = pzl_init(whc); - if (ret < 0) - goto error; - - /* Allocate and initialize a buffer for generic commands, the - Device Information buffer, and the Device Notification - buffer. */ - - whc->gen_cmd_buf = dma_alloc_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN, - &whc->gen_cmd_buf_dma, GFP_KERNEL); - if (whc->gen_cmd_buf == NULL) { - ret = -ENOMEM; - goto error; - } - - whc->dn_buf = dma_alloc_coherent(&whc->umc->dev, - sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES, - &whc->dn_buf_dma, GFP_KERNEL); - if (!whc->dn_buf) { - ret = -ENOMEM; - goto error; - } - whc_hw_init_dn_buf(whc); - - whc->di_buf = dma_alloc_coherent(&whc->umc->dev, - sizeof(struct di_buf_entry) * whc->n_devices, - &whc->di_buf_dma, GFP_KERNEL); - if (!whc->di_buf) { - ret = -ENOMEM; - goto error; - } - whc_hw_init_di_buf(whc); - - return 0; - -error: - whc_clean_up(whc); - return ret; -} - -void whc_clean_up(struct whc *whc) -{ - resource_size_t len; - - if (whc->di_buf) - dma_free_coherent(&whc->umc->dev, sizeof(struct di_buf_entry) * whc->n_devices, - whc->di_buf, whc->di_buf_dma); - if (whc->dn_buf) - dma_free_coherent(&whc->umc->dev, sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES, - whc->dn_buf, whc->dn_buf_dma); - if (whc->gen_cmd_buf) - dma_free_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN, - whc->gen_cmd_buf, whc->gen_cmd_buf_dma); - - pzl_clean_up(whc); - asl_clean_up(whc); - - if (whc->qset_pool) - dma_pool_destroy(whc->qset_pool); - - len = resource_size(&whc->umc->resource); - if (whc->base) - iounmap(whc->base); - if (whc->base_phys) - release_mem_region(whc->base_phys, len); - - if (whc->workqueue) - destroy_workqueue(whc->workqueue); -} diff --git a/ANDROID_3.4.5/drivers/usb/host/whci/int.c b/ANDROID_3.4.5/drivers/usb/host/whci/int.c deleted file mode 100644 index 6aae7002..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/whci/int.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Wireless Host Controller (WHC) interrupt handling. - * - * Copyright (C) 2007 Cambridge Silicon Radio Ltd. - * - * 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, see . - */ -#include -#include -#include - -#include "../../wusbcore/wusbhc.h" - -#include "whcd.h" - -static void transfer_done(struct whc *whc) -{ - queue_work(whc->workqueue, &whc->async_work); - queue_work(whc->workqueue, &whc->periodic_work); -} - -irqreturn_t whc_int_handler(struct usb_hcd *hcd) -{ - struct wusbhc *wusbhc = usb_hcd_to_wusbhc(hcd); - struct whc *whc = wusbhc_to_whc(wusbhc); - u32 sts; - - sts = le_readl(whc->base + WUSBSTS); - if (!(sts & WUSBSTS_INT_MASK)) - return IRQ_NONE; - le_writel(sts & WUSBSTS_INT_MASK, whc->base + WUSBSTS); - - if (sts & WUSBSTS_GEN_CMD_DONE) - wake_up(&whc->cmd_wq); - - if (sts & WUSBSTS_HOST_ERR) - dev_err(&whc->umc->dev, "FIXME: host system error\n"); - - if (sts & WUSBSTS_ASYNC_SCHED_SYNCED) - wake_up(&whc->async_list_wq); - - if (sts & WUSBSTS_PERIODIC_SCHED_SYNCED) - wake_up(&whc->periodic_list_wq); - - if (sts & WUSBSTS_DNTS_INT) - queue_work(whc->workqueue, &whc->dn_work); - - /* - * A transfer completed (see [WHCI] section 4.7.1.2 for when - * this occurs). - */ - if (sts & (WUSBSTS_INT | WUSBSTS_ERR_INT)) - transfer_done(whc); - - return IRQ_HANDLED; -} - -static int process_dn_buf(struct whc *whc) -{ - struct wusbhc *wusbhc = &whc->wusbhc; - struct dn_buf_entry *dn; - int processed = 0; - - for (dn = whc->dn_buf; dn < whc->dn_buf + WHC_N_DN_ENTRIES; dn++) { - if (dn->status & WHC_DN_STATUS_VALID) { - wusbhc_handle_dn(wusbhc, dn->src_addr, - (struct wusb_dn_hdr *)dn->dn_data, - dn->msg_size); - dn->status &= ~WHC_DN_STATUS_VALID; - processed++; - } - } - return processed; -} - -void whc_dn_work(struct work_struct *work) -{ - struct whc *whc = container_of(work, struct whc, dn_work); - int processed; - - do { - processed = process_dn_buf(whc); - } while (processed); -} diff --git a/ANDROID_3.4.5/drivers/usb/host/whci/pzl.c b/ANDROID_3.4.5/drivers/usb/host/whci/pzl.c deleted file mode 100644 index 33c5580b..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/whci/pzl.c +++ /dev/null @@ -1,417 +0,0 @@ -/* - * Wireless Host Controller (WHC) periodic schedule management. - * - * Copyright (C) 2007 Cambridge Silicon Radio Ltd. - * - * 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, see . - */ -#include -#include -#include -#include -#include - -#include "../../wusbcore/wusbhc.h" - -#include "whcd.h" - -static void update_pzl_pointers(struct whc *whc, int period, u64 addr) -{ - switch (period) { - case 0: - whc_qset_set_link_ptr(&whc->pz_list[0], addr); - whc_qset_set_link_ptr(&whc->pz_list[2], addr); - whc_qset_set_link_ptr(&whc->pz_list[4], addr); - whc_qset_set_link_ptr(&whc->pz_list[6], addr); - whc_qset_set_link_ptr(&whc->pz_list[8], addr); - whc_qset_set_link_ptr(&whc->pz_list[10], addr); - whc_qset_set_link_ptr(&whc->pz_list[12], addr); - whc_qset_set_link_ptr(&whc->pz_list[14], addr); - break; - case 1: - whc_qset_set_link_ptr(&whc->pz_list[1], addr); - whc_qset_set_link_ptr(&whc->pz_list[5], addr); - whc_qset_set_link_ptr(&whc->pz_list[9], addr); - whc_qset_set_link_ptr(&whc->pz_list[13], addr); - break; - case 2: - whc_qset_set_link_ptr(&whc->pz_list[3], addr); - whc_qset_set_link_ptr(&whc->pz_list[11], addr); - break; - case 3: - whc_qset_set_link_ptr(&whc->pz_list[7], addr); - break; - case 4: - whc_qset_set_link_ptr(&whc->pz_list[15], addr); - break; - } -} - -/* - * Return the 'period' to use for this qset. The minimum interval for - * the endpoint is used so whatever urbs are submitted the device is - * polled often enough. - */ -static int qset_get_period(struct whc *whc, struct whc_qset *qset) -{ - uint8_t bInterval = qset->ep->desc.bInterval; - - if (bInterval < 6) - bInterval = 6; - if (bInterval > 10) - bInterval = 10; - return bInterval - 6; -} - -static void qset_insert_in_sw_list(struct whc *whc, struct whc_qset *qset) -{ - int period; - - period = qset_get_period(whc, qset); - - qset_clear(whc, qset); - list_move(&qset->list_node, &whc->periodic_list[period]); - qset->in_sw_list = true; -} - -static void pzl_qset_remove(struct whc *whc, struct whc_qset *qset) -{ - list_move(&qset->list_node, &whc->periodic_removed_list); - qset->in_hw_list = false; - qset->in_sw_list = false; -} - -/** - * pzl_process_qset - process any recently inactivated or halted qTDs - * in a qset. - * - * After inactive qTDs are removed, new qTDs can be added if the - * urb queue still contains URBs. - * - * Returns the schedule updates required. - */ -static enum whc_update pzl_process_qset(struct whc *whc, struct whc_qset *qset) -{ - enum whc_update update = 0; - uint32_t status = 0; - - while (qset->ntds) { - struct whc_qtd *td; - int t; - - t = qset->td_start; - td = &qset->qtd[qset->td_start]; - status = le32_to_cpu(td->status); - - /* - * Nothing to do with a still active qTD. - */ - if (status & QTD_STS_ACTIVE) - break; - - if (status & QTD_STS_HALTED) { - /* Ug, an error. */ - process_halted_qtd(whc, qset, td); - /* A halted qTD always triggers an update - because the qset was either removed or - reactivated. */ - update |= WHC_UPDATE_UPDATED; - goto done; - } - - /* Mmm, a completed qTD. */ - process_inactive_qtd(whc, qset, td); - } - - if (!qset->remove) - update |= qset_add_qtds(whc, qset); - -done: - /* - * If there are no qTDs in this qset, remove it from the PZL. - */ - if (qset->remove && qset->ntds == 0) { - pzl_qset_remove(whc, qset); - update |= WHC_UPDATE_REMOVED; - } - - return update; -} - -/** - * pzl_start - start the periodic schedule - * @whc: the WHCI host controller - * - * The PZL must be valid (e.g., all entries in the list should have - * the T bit set). - */ -void pzl_start(struct whc *whc) -{ - le_writeq(whc->pz_list_dma, whc->base + WUSBPERIODICLISTBASE); - - whc_write_wusbcmd(whc, WUSBCMD_PERIODIC_EN, WUSBCMD_PERIODIC_EN); - whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS, - WUSBSTS_PERIODIC_SCHED, WUSBSTS_PERIODIC_SCHED, - 1000, "start PZL"); -} - -/** - * pzl_stop - stop the periodic schedule - * @whc: the WHCI host controller - */ -void pzl_stop(struct whc *whc) -{ - whc_write_wusbcmd(whc, WUSBCMD_PERIODIC_EN, 0); - whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS, - WUSBSTS_PERIODIC_SCHED, 0, - 1000, "stop PZL"); -} - -/** - * pzl_update - request a PZL update and wait for the hardware to be synced - * @whc: the WHCI HC - * @wusbcmd: WUSBCMD value to start the update. - * - * If the WUSB HC is inactive (i.e., the PZL is stopped) then the - * update must be skipped as the hardware may not respond to update - * requests. - */ -void pzl_update(struct whc *whc, uint32_t wusbcmd) -{ - struct wusbhc *wusbhc = &whc->wusbhc; - long t; - - mutex_lock(&wusbhc->mutex); - if (wusbhc->active) { - whc_write_wusbcmd(whc, wusbcmd, wusbcmd); - t = wait_event_timeout( - whc->periodic_list_wq, - (le_readl(whc->base + WUSBCMD) & WUSBCMD_PERIODIC_UPDATED) == 0, - msecs_to_jiffies(1000)); - if (t == 0) - whc_hw_error(whc, "PZL update timeout"); - } - mutex_unlock(&wusbhc->mutex); -} - -static void update_pzl_hw_view(struct whc *whc) -{ - struct whc_qset *qset, *t; - int period; - u64 tmp_qh = 0; - - for (period = 0; period < 5; period++) { - list_for_each_entry_safe(qset, t, &whc->periodic_list[period], list_node) { - whc_qset_set_link_ptr(&qset->qh.link, tmp_qh); - tmp_qh = qset->qset_dma; - qset->in_hw_list = true; - } - update_pzl_pointers(whc, period, tmp_qh); - } -} - -/** - * scan_periodic_work - scan the PZL for qsets to process. - * - * Process each qset in the PZL in turn and then signal the WHC that - * the PZL has been updated. - * - * Then start, stop or update the periodic schedule as required. - */ -void scan_periodic_work(struct work_struct *work) -{ - struct whc *whc = container_of(work, struct whc, periodic_work); - struct whc_qset *qset, *t; - enum whc_update update = 0; - int period; - - spin_lock_irq(&whc->lock); - - for (period = 4; period >= 0; period--) { - list_for_each_entry_safe(qset, t, &whc->periodic_list[period], list_node) { - if (!qset->in_hw_list) - update |= WHC_UPDATE_ADDED; - update |= pzl_process_qset(whc, qset); - } - } - - if (update & (WHC_UPDATE_ADDED | WHC_UPDATE_REMOVED)) - update_pzl_hw_view(whc); - - spin_unlock_irq(&whc->lock); - - if (update) { - uint32_t wusbcmd = WUSBCMD_PERIODIC_UPDATED | WUSBCMD_PERIODIC_SYNCED_DB; - if (update & WHC_UPDATE_REMOVED) - wusbcmd |= WUSBCMD_PERIODIC_QSET_RM; - pzl_update(whc, wusbcmd); - } - - /* - * Now that the PZL is updated, complete the removal of any - * removed qsets. - * - * If the qset was to be reset, do so and reinsert it into the - * PZL if it has pending transfers. - */ - spin_lock_irq(&whc->lock); - - list_for_each_entry_safe(qset, t, &whc->periodic_removed_list, list_node) { - qset_remove_complete(whc, qset); - if (qset->reset) { - qset_reset(whc, qset); - if (!list_empty(&qset->stds)) { - qset_insert_in_sw_list(whc, qset); - queue_work(whc->workqueue, &whc->periodic_work); - } - } - } - - spin_unlock_irq(&whc->lock); -} - -/** - * pzl_urb_enqueue - queue an URB onto the periodic list (PZL) - * @whc: the WHCI host controller - * @urb: the URB to enqueue - * @mem_flags: flags for any memory allocations - * - * The qset for the endpoint is obtained and the urb queued on to it. - * - * Work is scheduled to update the hardware's view of the PZL. - */ -int pzl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags) -{ - struct whc_qset *qset; - int err; - unsigned long flags; - - spin_lock_irqsave(&whc->lock, flags); - - err = usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb); - if (err < 0) { - spin_unlock_irqrestore(&whc->lock, flags); - return err; - } - - qset = get_qset(whc, urb, GFP_ATOMIC); - if (qset == NULL) - err = -ENOMEM; - else - err = qset_add_urb(whc, qset, urb, GFP_ATOMIC); - if (!err) { - if (!qset->in_sw_list && !qset->remove) - qset_insert_in_sw_list(whc, qset); - } else - usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb); - - spin_unlock_irqrestore(&whc->lock, flags); - - if (!err) - queue_work(whc->workqueue, &whc->periodic_work); - - return err; -} - -/** - * pzl_urb_dequeue - remove an URB (qset) from the periodic list - * @whc: the WHCI host controller - * @urb: the URB to dequeue - * @status: the current status of the URB - * - * URBs that do yet have qTDs can simply be removed from the software - * queue, otherwise the qset must be removed so the qTDs can be safely - * removed. - */ -int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status) -{ - struct whc_urb *wurb = urb->hcpriv; - struct whc_qset *qset = wurb->qset; - struct whc_std *std, *t; - bool has_qtd = false; - int ret; - unsigned long flags; - - spin_lock_irqsave(&whc->lock, flags); - - ret = usb_hcd_check_unlink_urb(&whc->wusbhc.usb_hcd, urb, status); - if (ret < 0) - goto out; - - list_for_each_entry_safe(std, t, &qset->stds, list_node) { - if (std->urb == urb) { - if (std->qtd) - has_qtd = true; - qset_free_std(whc, std); - } else - std->qtd = NULL; /* so this std is re-added when the qset is */ - } - - if (has_qtd) { - pzl_qset_remove(whc, qset); - update_pzl_hw_view(whc); - wurb->status = status; - wurb->is_async = false; - queue_work(whc->workqueue, &wurb->dequeue_work); - } else - qset_remove_urb(whc, qset, urb, status); -out: - spin_unlock_irqrestore(&whc->lock, flags); - - return ret; -} - -/** - * pzl_qset_delete - delete a qset from the PZL - */ -void pzl_qset_delete(struct whc *whc, struct whc_qset *qset) -{ - qset->remove = 1; - queue_work(whc->workqueue, &whc->periodic_work); - qset_delete(whc, qset); -} - -/** - * pzl_init - initialize the periodic zone list - * @whc: the WHCI host controller - */ -int pzl_init(struct whc *whc) -{ - int i; - - whc->pz_list = dma_alloc_coherent(&whc->umc->dev, sizeof(u64) * 16, - &whc->pz_list_dma, GFP_KERNEL); - if (whc->pz_list == NULL) - return -ENOMEM; - - /* Set T bit on all elements in PZL. */ - for (i = 0; i < 16; i++) - whc->pz_list[i] = cpu_to_le64(QH_LINK_NTDS(8) | QH_LINK_T); - - le_writeq(whc->pz_list_dma, whc->base + WUSBPERIODICLISTBASE); - - return 0; -} - -/** - * pzl_clean_up - free PZL resources - * @whc: the WHCI host controller - * - * The PZL is stopped and empty. - */ -void pzl_clean_up(struct whc *whc) -{ - if (whc->pz_list) - dma_free_coherent(&whc->umc->dev, sizeof(u64) * 16, whc->pz_list, - whc->pz_list_dma); -} diff --git a/ANDROID_3.4.5/drivers/usb/host/whci/qset.c b/ANDROID_3.4.5/drivers/usb/host/whci/qset.c deleted file mode 100644 index 76083ae9..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/whci/qset.c +++ /dev/null @@ -1,832 +0,0 @@ -/* - * Wireless Host Controller (WHC) qset management. - * - * Copyright (C) 2007 Cambridge Silicon Radio Ltd. - * - * 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, see . - */ -#include -#include -#include -#include -#include - -#include "../../wusbcore/wusbhc.h" - -#include "whcd.h" - -struct whc_qset *qset_alloc(struct whc *whc, gfp_t mem_flags) -{ - struct whc_qset *qset; - dma_addr_t dma; - - qset = dma_pool_alloc(whc->qset_pool, mem_flags, &dma); - if (qset == NULL) - return NULL; - memset(qset, 0, sizeof(struct whc_qset)); - - qset->qset_dma = dma; - qset->whc = whc; - - INIT_LIST_HEAD(&qset->list_node); - INIT_LIST_HEAD(&qset->stds); - - return qset; -} - -/** - * qset_fill_qh - fill the static endpoint state in a qset's QHead - * @qset: the qset whose QH needs initializing with static endpoint - * state - * @urb: an urb for a transfer to this endpoint - */ -static void qset_fill_qh(struct whc *whc, struct whc_qset *qset, struct urb *urb) -{ - struct usb_device *usb_dev = urb->dev; - struct wusb_dev *wusb_dev = usb_dev->wusb_dev; - struct usb_wireless_ep_comp_descriptor *epcd; - bool is_out; - uint8_t phy_rate; - - is_out = usb_pipeout(urb->pipe); - - qset->max_packet = le16_to_cpu(urb->ep->desc.wMaxPacketSize); - - epcd = (struct usb_wireless_ep_comp_descriptor *)qset->ep->extra; - if (epcd) { - qset->max_seq = epcd->bMaxSequence; - qset->max_burst = epcd->bMaxBurst; - } else { - qset->max_seq = 2; - qset->max_burst = 1; - } - - /* - * Initial PHY rate is 53.3 Mbit/s for control endpoints or - * the maximum supported by the device for other endpoints - * (unless limited by the user). - */ - if (usb_pipecontrol(urb->pipe)) - phy_rate = UWB_PHY_RATE_53; - else { - uint16_t phy_rates; - - phy_rates = le16_to_cpu(wusb_dev->wusb_cap_descr->wPHYRates); - phy_rate = fls(phy_rates) - 1; - if (phy_rate > whc->wusbhc.phy_rate) - phy_rate = whc->wusbhc.phy_rate; - } - - qset->qh.info1 = cpu_to_le32( - QH_INFO1_EP(usb_pipeendpoint(urb->pipe)) - | (is_out ? QH_INFO1_DIR_OUT : QH_INFO1_DIR_IN) - | usb_pipe_to_qh_type(urb->pipe) - | QH_INFO1_DEV_INFO_IDX(wusb_port_no_to_idx(usb_dev->portnum)) - | QH_INFO1_MAX_PKT_LEN(qset->max_packet) - ); - qset->qh.info2 = cpu_to_le32( - QH_INFO2_BURST(qset->max_burst) - | QH_INFO2_DBP(0) - | QH_INFO2_MAX_COUNT(3) - | QH_INFO2_MAX_RETRY(3) - | QH_INFO2_MAX_SEQ(qset->max_seq - 1) - ); - /* FIXME: where can we obtain these Tx parameters from? Why - * doesn't the chip know what Tx power to use? It knows the Rx - * strength and can presumably guess the Tx power required - * from that? */ - qset->qh.info3 = cpu_to_le32( - QH_INFO3_TX_RATE(phy_rate) - | QH_INFO3_TX_PWR(0) /* 0 == max power */ - ); - - qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1); -} - -/** - * qset_clear - clear fields in a qset so it may be reinserted into a - * schedule. - * - * The sequence number and current window are not cleared (see - * qset_reset()). - */ -void qset_clear(struct whc *whc, struct whc_qset *qset) -{ - qset->td_start = qset->td_end = qset->ntds = 0; - - qset->qh.link = cpu_to_le64(QH_LINK_NTDS(8) | QH_LINK_T); - qset->qh.status = qset->qh.status & QH_STATUS_SEQ_MASK; - qset->qh.err_count = 0; - qset->qh.scratch[0] = 0; - qset->qh.scratch[1] = 0; - qset->qh.scratch[2] = 0; - - memset(&qset->qh.overlay, 0, sizeof(qset->qh.overlay)); - - init_completion(&qset->remove_complete); -} - -/** - * qset_reset - reset endpoint state in a qset. - * - * Clears the sequence number and current window. This qset must not - * be in the ASL or PZL. - */ -void qset_reset(struct whc *whc, struct whc_qset *qset) -{ - qset->reset = 0; - - qset->qh.status &= ~QH_STATUS_SEQ_MASK; - qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1); -} - -/** - * get_qset - get the qset for an async endpoint - * - * A new qset is created if one does not already exist. - */ -struct whc_qset *get_qset(struct whc *whc, struct urb *urb, - gfp_t mem_flags) -{ - struct whc_qset *qset; - - qset = urb->ep->hcpriv; - if (qset == NULL) { - qset = qset_alloc(whc, mem_flags); - if (qset == NULL) - return NULL; - - qset->ep = urb->ep; - urb->ep->hcpriv = qset; - qset_fill_qh(whc, qset, urb); - } - return qset; -} - -void qset_remove_complete(struct whc *whc, struct whc_qset *qset) -{ - qset->remove = 0; - list_del_init(&qset->list_node); - complete(&qset->remove_complete); -} - -/** - * qset_add_qtds - add qTDs for an URB to a qset - * - * Returns true if the list (ASL/PZL) must be updated because (for a - * WHCI 0.95 controller) an activated qTD was pointed to be iCur. - */ -enum whc_update qset_add_qtds(struct whc *whc, struct whc_qset *qset) -{ - struct whc_std *std; - enum whc_update update = 0; - - list_for_each_entry(std, &qset->stds, list_node) { - struct whc_qtd *qtd; - uint32_t status; - - if (qset->ntds >= WHCI_QSET_TD_MAX - || (qset->pause_after_urb && std->urb != qset->pause_after_urb)) - break; - - if (std->qtd) - continue; /* already has a qTD */ - - qtd = std->qtd = &qset->qtd[qset->td_end]; - - /* Fill in setup bytes for control transfers. */ - if (usb_pipecontrol(std->urb->pipe)) - memcpy(qtd->setup, std->urb->setup_packet, 8); - - status = QTD_STS_ACTIVE | QTD_STS_LEN(std->len); - - if (whc_std_last(std) && usb_pipeout(std->urb->pipe)) - status |= QTD_STS_LAST_PKT; - - /* - * For an IN transfer the iAlt field should be set so - * the h/w will automatically advance to the next - * transfer. However, if there are 8 or more TDs - * remaining in this transfer then iAlt cannot be set - * as it could point to somewhere in this transfer. - */ - if (std->ntds_remaining < WHCI_QSET_TD_MAX) { - int ialt; - ialt = (qset->td_end + std->ntds_remaining) % WHCI_QSET_TD_MAX; - status |= QTD_STS_IALT(ialt); - } else if (usb_pipein(std->urb->pipe)) - qset->pause_after_urb = std->urb; - - if (std->num_pointers) - qtd->options = cpu_to_le32(QTD_OPT_IOC); - else - qtd->options = cpu_to_le32(QTD_OPT_IOC | QTD_OPT_SMALL); - qtd->page_list_ptr = cpu_to_le64(std->dma_addr); - - qtd->status = cpu_to_le32(status); - - if (QH_STATUS_TO_ICUR(qset->qh.status) == qset->td_end) - update = WHC_UPDATE_UPDATED; - - if (++qset->td_end >= WHCI_QSET_TD_MAX) - qset->td_end = 0; - qset->ntds++; - } - - return update; -} - -/** - * qset_remove_qtd - remove the first qTD from a qset. - * - * The qTD might be still active (if it's part of a IN URB that - * resulted in a short read) so ensure it's deactivated. - */ -static void qset_remove_qtd(struct whc *whc, struct whc_qset *qset) -{ - qset->qtd[qset->td_start].status = 0; - - if (++qset->td_start >= WHCI_QSET_TD_MAX) - qset->td_start = 0; - qset->ntds--; -} - -static void qset_copy_bounce_to_sg(struct whc *whc, struct whc_std *std) -{ - struct scatterlist *sg; - void *bounce; - size_t remaining, offset; - - bounce = std->bounce_buf; - remaining = std->len; - - sg = std->bounce_sg; - offset = std->bounce_offset; - - while (remaining) { - size_t len; - - len = min(sg->length - offset, remaining); - memcpy(sg_virt(sg) + offset, bounce, len); - - bounce += len; - remaining -= len; - - offset += len; - if (offset >= sg->length) { - sg = sg_next(sg); - offset = 0; - } - } - -} - -/** - * qset_free_std - remove an sTD and free it. - * @whc: the WHCI host controller - * @std: the sTD to remove and free. - */ -void qset_free_std(struct whc *whc, struct whc_std *std) -{ - list_del(&std->list_node); - if (std->bounce_buf) { - bool is_out = usb_pipeout(std->urb->pipe); - dma_addr_t dma_addr; - - if (std->num_pointers) - dma_addr = le64_to_cpu(std->pl_virt[0].buf_ptr); - else - dma_addr = std->dma_addr; - - dma_unmap_single(whc->wusbhc.dev, dma_addr, - std->len, is_out ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - if (!is_out) - qset_copy_bounce_to_sg(whc, std); - kfree(std->bounce_buf); - } - if (std->pl_virt) { - if (std->dma_addr) - dma_unmap_single(whc->wusbhc.dev, std->dma_addr, - std->num_pointers * sizeof(struct whc_page_list_entry), - DMA_TO_DEVICE); - kfree(std->pl_virt); - std->pl_virt = NULL; - } - kfree(std); -} - -/** - * qset_remove_qtds - remove an URB's qTDs (and sTDs). - */ -static void qset_remove_qtds(struct whc *whc, struct whc_qset *qset, - struct urb *urb) -{ - struct whc_std *std, *t; - - list_for_each_entry_safe(std, t, &qset->stds, list_node) { - if (std->urb != urb) - break; - if (std->qtd != NULL) - qset_remove_qtd(whc, qset); - qset_free_std(whc, std); - } -} - -/** - * qset_free_stds - free any remaining sTDs for an URB. - */ -static void qset_free_stds(struct whc_qset *qset, struct urb *urb) -{ - struct whc_std *std, *t; - - list_for_each_entry_safe(std, t, &qset->stds, list_node) { - if (std->urb == urb) - qset_free_std(qset->whc, std); - } -} - -static int qset_fill_page_list(struct whc *whc, struct whc_std *std, gfp_t mem_flags) -{ - dma_addr_t dma_addr = std->dma_addr; - dma_addr_t sp, ep; - size_t pl_len; - int p; - - /* Short buffers don't need a page list. */ - if (std->len <= WHCI_PAGE_SIZE) { - std->num_pointers = 0; - return 0; - } - - sp = dma_addr & ~(WHCI_PAGE_SIZE-1); - ep = dma_addr + std->len; - std->num_pointers = DIV_ROUND_UP(ep - sp, WHCI_PAGE_SIZE); - - pl_len = std->num_pointers * sizeof(struct whc_page_list_entry); - std->pl_virt = kmalloc(pl_len, mem_flags); - if (std->pl_virt == NULL) - return -ENOMEM; - std->dma_addr = dma_map_single(whc->wusbhc.dev, std->pl_virt, pl_len, DMA_TO_DEVICE); - - for (p = 0; p < std->num_pointers; p++) { - std->pl_virt[p].buf_ptr = cpu_to_le64(dma_addr); - dma_addr = (dma_addr + WHCI_PAGE_SIZE) & ~(WHCI_PAGE_SIZE-1); - } - - return 0; -} - -/** - * urb_dequeue_work - executes asl/pzl update and gives back the urb to the system. - */ -static void urb_dequeue_work(struct work_struct *work) -{ - struct whc_urb *wurb = container_of(work, struct whc_urb, dequeue_work); - struct whc_qset *qset = wurb->qset; - struct whc *whc = qset->whc; - unsigned long flags; - - if (wurb->is_async == true) - asl_update(whc, WUSBCMD_ASYNC_UPDATED - | WUSBCMD_ASYNC_SYNCED_DB - | WUSBCMD_ASYNC_QSET_RM); - else - pzl_update(whc, WUSBCMD_PERIODIC_UPDATED - | WUSBCMD_PERIODIC_SYNCED_DB - | WUSBCMD_PERIODIC_QSET_RM); - - spin_lock_irqsave(&whc->lock, flags); - qset_remove_urb(whc, qset, wurb->urb, wurb->status); - spin_unlock_irqrestore(&whc->lock, flags); -} - -static struct whc_std *qset_new_std(struct whc *whc, struct whc_qset *qset, - struct urb *urb, gfp_t mem_flags) -{ - struct whc_std *std; - - std = kzalloc(sizeof(struct whc_std), mem_flags); - if (std == NULL) - return NULL; - - std->urb = urb; - std->qtd = NULL; - - INIT_LIST_HEAD(&std->list_node); - list_add_tail(&std->list_node, &qset->stds); - - return std; -} - -static int qset_add_urb_sg(struct whc *whc, struct whc_qset *qset, struct urb *urb, - gfp_t mem_flags) -{ - size_t remaining; - struct scatterlist *sg; - int i; - int ntds = 0; - struct whc_std *std = NULL; - struct whc_page_list_entry *entry; - dma_addr_t prev_end = 0; - size_t pl_len; - int p = 0; - - remaining = urb->transfer_buffer_length; - - for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) { - dma_addr_t dma_addr; - size_t dma_remaining; - dma_addr_t sp, ep; - int num_pointers; - - if (remaining == 0) { - break; - } - - dma_addr = sg_dma_address(sg); - dma_remaining = min_t(size_t, sg_dma_len(sg), remaining); - - while (dma_remaining) { - size_t dma_len; - - /* - * We can use the previous std (if it exists) provided that: - * - the previous one ended on a page boundary. - * - the current one begins on a page boundary. - * - the previous one isn't full. - * - * If a new std is needed but the previous one - * was not a whole number of packets then this - * sg list cannot be mapped onto multiple - * qTDs. Return an error and let the caller - * sort it out. - */ - if (!std - || (prev_end & (WHCI_PAGE_SIZE-1)) - || (dma_addr & (WHCI_PAGE_SIZE-1)) - || std->len + WHCI_PAGE_SIZE > QTD_MAX_XFER_SIZE) { - if (std && std->len % qset->max_packet != 0) - return -EINVAL; - std = qset_new_std(whc, qset, urb, mem_flags); - if (std == NULL) { - return -ENOMEM; - } - ntds++; - p = 0; - } - - dma_len = dma_remaining; - - /* - * If the remainder of this element doesn't - * fit in a single qTD, limit the qTD to a - * whole number of packets. This allows the - * remainder to go into the next qTD. - */ - if (std->len + dma_len > QTD_MAX_XFER_SIZE) { - dma_len = (QTD_MAX_XFER_SIZE / qset->max_packet) - * qset->max_packet - std->len; - } - - std->len += dma_len; - std->ntds_remaining = -1; /* filled in later */ - - sp = dma_addr & ~(WHCI_PAGE_SIZE-1); - ep = dma_addr + dma_len; - num_pointers = DIV_ROUND_UP(ep - sp, WHCI_PAGE_SIZE); - std->num_pointers += num_pointers; - - pl_len = std->num_pointers * sizeof(struct whc_page_list_entry); - - std->pl_virt = krealloc(std->pl_virt, pl_len, mem_flags); - if (std->pl_virt == NULL) { - return -ENOMEM; - } - - for (;p < std->num_pointers; p++, entry++) { - std->pl_virt[p].buf_ptr = cpu_to_le64(dma_addr); - dma_addr = (dma_addr + WHCI_PAGE_SIZE) & ~(WHCI_PAGE_SIZE-1); - } - - prev_end = dma_addr = ep; - dma_remaining -= dma_len; - remaining -= dma_len; - } - } - - /* Now the number of stds is know, go back and fill in - std->ntds_remaining. */ - list_for_each_entry(std, &qset->stds, list_node) { - if (std->ntds_remaining == -1) { - pl_len = std->num_pointers * sizeof(struct whc_page_list_entry); - std->ntds_remaining = ntds--; - std->dma_addr = dma_map_single(whc->wusbhc.dev, std->pl_virt, - pl_len, DMA_TO_DEVICE); - } - } - return 0; -} - -/** - * qset_add_urb_sg_linearize - add an urb with sg list, copying the data - * - * If the URB contains an sg list whose elements cannot be directly - * mapped to qTDs then the data must be transferred via bounce - * buffers. - */ -static int qset_add_urb_sg_linearize(struct whc *whc, struct whc_qset *qset, - struct urb *urb, gfp_t mem_flags) -{ - bool is_out = usb_pipeout(urb->pipe); - size_t max_std_len; - size_t remaining; - int ntds = 0; - struct whc_std *std = NULL; - void *bounce = NULL; - struct scatterlist *sg; - int i; - - /* limit maximum bounce buffer to 16 * 3.5 KiB ~= 28 k */ - max_std_len = qset->max_burst * qset->max_packet; - - remaining = urb->transfer_buffer_length; - - for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) { - size_t len; - size_t sg_remaining; - void *orig; - - if (remaining == 0) { - break; - } - - sg_remaining = min_t(size_t, remaining, sg->length); - orig = sg_virt(sg); - - while (sg_remaining) { - if (!std || std->len == max_std_len) { - std = qset_new_std(whc, qset, urb, mem_flags); - if (std == NULL) - return -ENOMEM; - std->bounce_buf = kmalloc(max_std_len, mem_flags); - if (std->bounce_buf == NULL) - return -ENOMEM; - std->bounce_sg = sg; - std->bounce_offset = orig - sg_virt(sg); - bounce = std->bounce_buf; - ntds++; - } - - len = min(sg_remaining, max_std_len - std->len); - - if (is_out) - memcpy(bounce, orig, len); - - std->len += len; - std->ntds_remaining = -1; /* filled in later */ - - bounce += len; - orig += len; - sg_remaining -= len; - remaining -= len; - } - } - - /* - * For each of the new sTDs, map the bounce buffers, create - * page lists (if necessary), and fill in std->ntds_remaining. - */ - list_for_each_entry(std, &qset->stds, list_node) { - if (std->ntds_remaining != -1) - continue; - - std->dma_addr = dma_map_single(&whc->umc->dev, std->bounce_buf, std->len, - is_out ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - - if (qset_fill_page_list(whc, std, mem_flags) < 0) - return -ENOMEM; - - std->ntds_remaining = ntds--; - } - - return 0; -} - -/** - * qset_add_urb - add an urb to the qset's queue. - * - * The URB is chopped into sTDs, one for each qTD that will required. - * At least one qTD (and sTD) is required even if the transfer has no - * data (e.g., for some control transfers). - */ -int qset_add_urb(struct whc *whc, struct whc_qset *qset, struct urb *urb, - gfp_t mem_flags) -{ - struct whc_urb *wurb; - int remaining = urb->transfer_buffer_length; - u64 transfer_dma = urb->transfer_dma; - int ntds_remaining; - int ret; - - wurb = kzalloc(sizeof(struct whc_urb), mem_flags); - if (wurb == NULL) - goto err_no_mem; - urb->hcpriv = wurb; - wurb->qset = qset; - wurb->urb = urb; - INIT_WORK(&wurb->dequeue_work, urb_dequeue_work); - - if (urb->num_sgs) { - ret = qset_add_urb_sg(whc, qset, urb, mem_flags); - if (ret == -EINVAL) { - qset_free_stds(qset, urb); - ret = qset_add_urb_sg_linearize(whc, qset, urb, mem_flags); - } - if (ret < 0) - goto err_no_mem; - return 0; - } - - ntds_remaining = DIV_ROUND_UP(remaining, QTD_MAX_XFER_SIZE); - if (ntds_remaining == 0) - ntds_remaining = 1; - - while (ntds_remaining) { - struct whc_std *std; - size_t std_len; - - std_len = remaining; - if (std_len > QTD_MAX_XFER_SIZE) - std_len = QTD_MAX_XFER_SIZE; - - std = qset_new_std(whc, qset, urb, mem_flags); - if (std == NULL) - goto err_no_mem; - - std->dma_addr = transfer_dma; - std->len = std_len; - std->ntds_remaining = ntds_remaining; - - if (qset_fill_page_list(whc, std, mem_flags) < 0) - goto err_no_mem; - - ntds_remaining--; - remaining -= std_len; - transfer_dma += std_len; - } - - return 0; - -err_no_mem: - qset_free_stds(qset, urb); - return -ENOMEM; -} - -/** - * qset_remove_urb - remove an URB from the urb queue. - * - * The URB is returned to the USB subsystem. - */ -void qset_remove_urb(struct whc *whc, struct whc_qset *qset, - struct urb *urb, int status) -{ - struct wusbhc *wusbhc = &whc->wusbhc; - struct whc_urb *wurb = urb->hcpriv; - - usb_hcd_unlink_urb_from_ep(&wusbhc->usb_hcd, urb); - /* Drop the lock as urb->complete() may enqueue another urb. */ - spin_unlock(&whc->lock); - wusbhc_giveback_urb(wusbhc, urb, status); - spin_lock(&whc->lock); - - kfree(wurb); -} - -/** - * get_urb_status_from_qtd - get the completed urb status from qTD status - * @urb: completed urb - * @status: qTD status - */ -static int get_urb_status_from_qtd(struct urb *urb, u32 status) -{ - if (status & QTD_STS_HALTED) { - if (status & QTD_STS_DBE) - return usb_pipein(urb->pipe) ? -ENOSR : -ECOMM; - else if (status & QTD_STS_BABBLE) - return -EOVERFLOW; - else if (status & QTD_STS_RCE) - return -ETIME; - return -EPIPE; - } - if (usb_pipein(urb->pipe) - && (urb->transfer_flags & URB_SHORT_NOT_OK) - && urb->actual_length < urb->transfer_buffer_length) - return -EREMOTEIO; - return 0; -} - -/** - * process_inactive_qtd - process an inactive (but not halted) qTD. - * - * Update the urb with the transfer bytes from the qTD, if the urb is - * completely transferred or (in the case of an IN only) the LPF is - * set, then the transfer is complete and the urb should be returned - * to the system. - */ -void process_inactive_qtd(struct whc *whc, struct whc_qset *qset, - struct whc_qtd *qtd) -{ - struct whc_std *std = list_first_entry(&qset->stds, struct whc_std, list_node); - struct urb *urb = std->urb; - uint32_t status; - bool complete; - - status = le32_to_cpu(qtd->status); - - urb->actual_length += std->len - QTD_STS_TO_LEN(status); - - if (usb_pipein(urb->pipe) && (status & QTD_STS_LAST_PKT)) - complete = true; - else - complete = whc_std_last(std); - - qset_remove_qtd(whc, qset); - qset_free_std(whc, std); - - /* - * Transfers for this URB are complete? Then return it to the - * USB subsystem. - */ - if (complete) { - qset_remove_qtds(whc, qset, urb); - qset_remove_urb(whc, qset, urb, get_urb_status_from_qtd(urb, status)); - - /* - * If iAlt isn't valid then the hardware didn't - * advance iCur. Adjust the start and end pointers to - * match iCur. - */ - if (!(status & QTD_STS_IALT_VALID)) - qset->td_start = qset->td_end - = QH_STATUS_TO_ICUR(le16_to_cpu(qset->qh.status)); - qset->pause_after_urb = NULL; - } -} - -/** - * process_halted_qtd - process a qset with a halted qtd - * - * Remove all the qTDs for the failed URB and return the failed URB to - * the USB subsystem. Then remove all other qTDs so the qset can be - * removed. - * - * FIXME: this is the point where rate adaptation can be done. If a - * transfer failed because it exceeded the maximum number of retries - * then it could be reactivated with a slower rate without having to - * remove the qset. - */ -void process_halted_qtd(struct whc *whc, struct whc_qset *qset, - struct whc_qtd *qtd) -{ - struct whc_std *std = list_first_entry(&qset->stds, struct whc_std, list_node); - struct urb *urb = std->urb; - int urb_status; - - urb_status = get_urb_status_from_qtd(urb, le32_to_cpu(qtd->status)); - - qset_remove_qtds(whc, qset, urb); - qset_remove_urb(whc, qset, urb, urb_status); - - list_for_each_entry(std, &qset->stds, list_node) { - if (qset->ntds == 0) - break; - qset_remove_qtd(whc, qset); - std->qtd = NULL; - } - - qset->remove = 1; -} - -void qset_free(struct whc *whc, struct whc_qset *qset) -{ - dma_pool_free(whc->qset_pool, qset, qset->qset_dma); -} - -/** - * qset_delete - wait for a qset to be unused, then free it. - */ -void qset_delete(struct whc *whc, struct whc_qset *qset) -{ - wait_for_completion(&qset->remove_complete); - qset_free(whc, qset); -} diff --git a/ANDROID_3.4.5/drivers/usb/host/whci/whcd.h b/ANDROID_3.4.5/drivers/usb/host/whci/whcd.h deleted file mode 100644 index c80c7d93..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/whci/whcd.h +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Wireless Host Controller (WHC) private header. - * - * Copyright (C) 2007 Cambridge Silicon Radio Ltd. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ -#ifndef __WHCD_H -#define __WHCD_H - -#include -#include -#include - -#include "whci-hc.h" - -/* Generic command timeout. */ -#define WHC_GENCMD_TIMEOUT_MS 100 - -struct whc_dbg; - -struct whc { - struct wusbhc wusbhc; - struct umc_dev *umc; - - resource_size_t base_phys; - void __iomem *base; - int irq; - - u8 n_devices; - u8 n_keys; - u8 n_mmc_ies; - - u64 *pz_list; - struct dn_buf_entry *dn_buf; - struct di_buf_entry *di_buf; - dma_addr_t pz_list_dma; - dma_addr_t dn_buf_dma; - dma_addr_t di_buf_dma; - - spinlock_t lock; - struct mutex mutex; - - void * gen_cmd_buf; - dma_addr_t gen_cmd_buf_dma; - wait_queue_head_t cmd_wq; - - struct workqueue_struct *workqueue; - struct work_struct dn_work; - - struct dma_pool *qset_pool; - - struct list_head async_list; - struct list_head async_removed_list; - wait_queue_head_t async_list_wq; - struct work_struct async_work; - - struct list_head periodic_list[5]; - struct list_head periodic_removed_list; - wait_queue_head_t periodic_list_wq; - struct work_struct periodic_work; - - struct whc_dbg *dbg; -}; - -#define wusbhc_to_whc(w) (container_of((w), struct whc, wusbhc)) - -/** - * struct whc_std - a software TD. - * @urb: the URB this sTD is for. - * @offset: start of the URB's data for this TD. - * @len: the length of data in the associated TD. - * @ntds_remaining: number of TDs (starting from this one) in this transfer. - * - * @bounce_buf: a bounce buffer if the std was from an urb with a sg - * list that could not be mapped to qTDs directly. - * @bounce_sg: the first scatterlist element bounce_buf is for. - * @bounce_offset: the offset into bounce_sg for the start of bounce_buf. - * - * Queued URBs may require more TDs than are available in a qset so we - * use a list of these "software TDs" (sTDs) to hold per-TD data. - */ -struct whc_std { - struct urb *urb; - size_t len; - int ntds_remaining; - struct whc_qtd *qtd; - - struct list_head list_node; - int num_pointers; - dma_addr_t dma_addr; - struct whc_page_list_entry *pl_virt; - - void *bounce_buf; - struct scatterlist *bounce_sg; - unsigned bounce_offset; -}; - -/** - * struct whc_urb - per URB host controller structure. - * @urb: the URB this struct is for. - * @qset: the qset associated to the URB. - * @dequeue_work: the work to remove the URB when dequeued. - * @is_async: the URB belongs to async sheduler or not. - * @status: the status to be returned when calling wusbhc_giveback_urb. - */ -struct whc_urb { - struct urb *urb; - struct whc_qset *qset; - struct work_struct dequeue_work; - bool is_async; - int status; -}; - -/** - * whc_std_last - is this sTD the URB's last? - * @std: the sTD to check. - */ -static inline bool whc_std_last(struct whc_std *std) -{ - return std->ntds_remaining <= 1; -} - -enum whc_update { - WHC_UPDATE_ADDED = 0x01, - WHC_UPDATE_REMOVED = 0x02, - WHC_UPDATE_UPDATED = 0x04, -}; - -/* init.c */ -int whc_init(struct whc *whc); -void whc_clean_up(struct whc *whc); - -/* hw.c */ -void whc_write_wusbcmd(struct whc *whc, u32 mask, u32 val); -int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len); -void whc_hw_error(struct whc *whc, const char *reason); - -/* wusb.c */ -int whc_wusbhc_start(struct wusbhc *wusbhc); -void whc_wusbhc_stop(struct wusbhc *wusbhc, int delay); -int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, - u8 handle, struct wuie_hdr *wuie); -int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle); -int whc_bwa_set(struct wusbhc *wusbhc, s8 stream_index, const struct uwb_mas_bm *mas_bm); -int whc_dev_info_set(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev); -int whc_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots); -int whc_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid, - const void *ptk, size_t key_size); -int whc_set_gtk(struct wusbhc *wusbhc, u32 tkid, - const void *gtk, size_t key_size); -int whc_set_cluster_id(struct whc *whc, u8 bcid); - -/* int.c */ -irqreturn_t whc_int_handler(struct usb_hcd *hcd); -void whc_dn_work(struct work_struct *work); - -/* asl.c */ -void asl_start(struct whc *whc); -void asl_stop(struct whc *whc); -int asl_init(struct whc *whc); -void asl_clean_up(struct whc *whc); -int asl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags); -int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status); -void asl_qset_delete(struct whc *whc, struct whc_qset *qset); -void scan_async_work(struct work_struct *work); - -/* pzl.c */ -int pzl_init(struct whc *whc); -void pzl_clean_up(struct whc *whc); -void pzl_start(struct whc *whc); -void pzl_stop(struct whc *whc); -int pzl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags); -int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status); -void pzl_qset_delete(struct whc *whc, struct whc_qset *qset); -void scan_periodic_work(struct work_struct *work); - -/* qset.c */ -struct whc_qset *qset_alloc(struct whc *whc, gfp_t mem_flags); -void qset_free(struct whc *whc, struct whc_qset *qset); -struct whc_qset *get_qset(struct whc *whc, struct urb *urb, gfp_t mem_flags); -void qset_delete(struct whc *whc, struct whc_qset *qset); -void qset_clear(struct whc *whc, struct whc_qset *qset); -void qset_reset(struct whc *whc, struct whc_qset *qset); -int qset_add_urb(struct whc *whc, struct whc_qset *qset, struct urb *urb, - gfp_t mem_flags); -void qset_free_std(struct whc *whc, struct whc_std *std); -void qset_remove_urb(struct whc *whc, struct whc_qset *qset, - struct urb *urb, int status); -void process_halted_qtd(struct whc *whc, struct whc_qset *qset, - struct whc_qtd *qtd); -void process_inactive_qtd(struct whc *whc, struct whc_qset *qset, - struct whc_qtd *qtd); -enum whc_update qset_add_qtds(struct whc *whc, struct whc_qset *qset); -void qset_remove_complete(struct whc *whc, struct whc_qset *qset); -void pzl_update(struct whc *whc, uint32_t wusbcmd); -void asl_update(struct whc *whc, uint32_t wusbcmd); - -/* debug.c */ -void whc_dbg_init(struct whc *whc); -void whc_dbg_clean_up(struct whc *whc); - -#endif /* #ifndef __WHCD_H */ diff --git a/ANDROID_3.4.5/drivers/usb/host/whci/whci-hc.h b/ANDROID_3.4.5/drivers/usb/host/whci/whci-hc.h deleted file mode 100644 index 4d4cbc07..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/whci/whci-hc.h +++ /dev/null @@ -1,414 +0,0 @@ -/* - * Wireless Host Controller (WHC) data structures. - * - * Copyright (C) 2007 Cambridge Silicon Radio Ltd. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ -#ifndef _WHCI_WHCI_HC_H -#define _WHCI_WHCI_HC_H - -#include - -/** - * WHCI_PAGE_SIZE - page size use by WHCI - * - * WHCI assumes that host system uses pages of 4096 octets. - */ -#define WHCI_PAGE_SIZE 4096 - - -/** - * QTD_MAX_TXFER_SIZE - max number of bytes to transfer with a single - * qtd. - * - * This is 2^20 - 1. - */ -#define QTD_MAX_XFER_SIZE 1048575 - - -/** - * struct whc_qtd - Queue Element Transfer Descriptors (qTD) - * - * This describes the data for a bulk, control or interrupt transfer. - * - * [WHCI] section 3.2.4 - */ -struct whc_qtd { - __le32 status; /*< remaining transfer len and transfer status */ - __le32 options; - __le64 page_list_ptr; /*< physical pointer to data buffer page list*/ - __u8 setup[8]; /*< setup data for control transfers */ -} __attribute__((packed)); - -#define QTD_STS_ACTIVE (1 << 31) /* enable execution of transaction */ -#define QTD_STS_HALTED (1 << 30) /* transfer halted */ -#define QTD_STS_DBE (1 << 29) /* data buffer error */ -#define QTD_STS_BABBLE (1 << 28) /* babble detected */ -#define QTD_STS_RCE (1 << 27) /* retry count exceeded */ -#define QTD_STS_LAST_PKT (1 << 26) /* set Last Packet Flag in WUSB header */ -#define QTD_STS_INACTIVE (1 << 25) /* queue set is marked inactive */ -#define QTD_STS_IALT_VALID (1 << 23) /* iAlt field is valid */ -#define QTD_STS_IALT(i) (QTD_STS_IALT_VALID | ((i) << 20)) /* iAlt field */ -#define QTD_STS_LEN(l) ((l) << 0) /* transfer length */ -#define QTD_STS_TO_LEN(s) ((s) & 0x000fffff) - -#define QTD_OPT_IOC (1 << 1) /* page_list_ptr points to buffer directly */ -#define QTD_OPT_SMALL (1 << 0) /* interrupt on complete */ - -/** - * struct whc_itd - Isochronous Queue Element Transfer Descriptors (iTD) - * - * This describes the data and other parameters for an isochronous - * transfer. - * - * [WHCI] section 3.2.5 - */ -struct whc_itd { - __le16 presentation_time; /*< presentation time for OUT transfers */ - __u8 num_segments; /*< number of data segments in segment list */ - __u8 status; /*< command execution status */ - __le32 options; /*< misc transfer options */ - __le64 page_list_ptr; /*< physical pointer to data buffer page list */ - __le64 seg_list_ptr; /*< physical pointer to segment list */ -} __attribute__((packed)); - -#define ITD_STS_ACTIVE (1 << 7) /* enable execution of transaction */ -#define ITD_STS_DBE (1 << 5) /* data buffer error */ -#define ITD_STS_BABBLE (1 << 4) /* babble detected */ -#define ITD_STS_INACTIVE (1 << 1) /* queue set is marked inactive */ - -#define ITD_OPT_IOC (1 << 1) /* interrupt on complete */ -#define ITD_OPT_SMALL (1 << 0) /* page_list_ptr points to buffer directly */ - -/** - * Page list entry. - * - * A TD's page list must contain sufficient page list entries for the - * total data length in the TD. - * - * [WHCI] section 3.2.4.3 - */ -struct whc_page_list_entry { - __le64 buf_ptr; /*< physical pointer to buffer */ -} __attribute__((packed)); - -/** - * struct whc_seg_list_entry - Segment list entry. - * - * Describes a portion of the data buffer described in the containing - * qTD's page list. - * - * seg_ptr = qtd->page_list_ptr[qtd->seg_list_ptr[seg].idx].buf_ptr - * + qtd->seg_list_ptr[seg].offset; - * - * Segments can't cross page boundries. - * - * [WHCI] section 3.2.5.5 - */ -struct whc_seg_list_entry { - __le16 len; /*< segment length */ - __u8 idx; /*< index into page list */ - __u8 status; /*< segment status */ - __le16 offset; /*< 12 bit offset into page */ -} __attribute__((packed)); - -/** - * struct whc_qhead - endpoint and status information for a qset. - * - * [WHCI] section 3.2.6 - */ -struct whc_qhead { - __le64 link; /*< next qset in list */ - __le32 info1; - __le32 info2; - __le32 info3; - __le16 status; - __le16 err_count; /*< transaction error count */ - __le32 cur_window; - __le32 scratch[3]; /*< h/w scratch area */ - union { - struct whc_qtd qtd; - struct whc_itd itd; - } overlay; -} __attribute__((packed)); - -#define QH_LINK_PTR_MASK (~0x03Full) -#define QH_LINK_PTR(ptr) ((ptr) & QH_LINK_PTR_MASK) -#define QH_LINK_IQS (1 << 4) /* isochronous queue set */ -#define QH_LINK_NTDS(n) (((n) - 1) << 1) /* number of TDs in queue set */ -#define QH_LINK_T (1 << 0) /* last queue set in periodic schedule list */ - -#define QH_INFO1_EP(e) ((e) << 0) /* endpoint number */ -#define QH_INFO1_DIR_IN (1 << 4) /* IN transfer */ -#define QH_INFO1_DIR_OUT (0 << 4) /* OUT transfer */ -#define QH_INFO1_TR_TYPE_CTRL (0x0 << 5) /* control transfer */ -#define QH_INFO1_TR_TYPE_ISOC (0x1 << 5) /* isochronous transfer */ -#define QH_INFO1_TR_TYPE_BULK (0x2 << 5) /* bulk transfer */ -#define QH_INFO1_TR_TYPE_INT (0x3 << 5) /* interrupt */ -#define QH_INFO1_TR_TYPE_LP_INT (0x7 << 5) /* low power interrupt */ -#define QH_INFO1_DEV_INFO_IDX(i) ((i) << 8) /* index into device info buffer */ -#define QH_INFO1_SET_INACTIVE (1 << 15) /* set inactive after transfer */ -#define QH_INFO1_MAX_PKT_LEN(l) ((l) << 16) /* maximum packet length */ - -#define QH_INFO2_BURST(b) ((b) << 0) /* maximum burst length */ -#define QH_INFO2_DBP(p) ((p) << 5) /* data burst policy (see [WUSB] table 5-7) */ -#define QH_INFO2_MAX_COUNT(c) ((c) << 8) /* max isoc/int pkts per zone */ -#define QH_INFO2_RQS (1 << 15) /* reactivate queue set */ -#define QH_INFO2_MAX_RETRY(r) ((r) << 16) /* maximum transaction retries */ -#define QH_INFO2_MAX_SEQ(s) ((s) << 20) /* maximum sequence number */ -#define QH_INFO3_MAX_DELAY(d) ((d) << 0) /* maximum stream delay in 125 us units (isoc only) */ -#define QH_INFO3_INTERVAL(i) ((i) << 16) /* segment interval in 125 us units (isoc only) */ - -#define QH_INFO3_TX_RATE(r) ((r) << 24) /* PHY rate (see [ECMA-368] section 10.3.1.1) */ -#define QH_INFO3_TX_PWR(p) ((p) << 29) /* transmit power (see [WUSB] section 5.2.1.2) */ - -#define QH_STATUS_FLOW_CTRL (1 << 15) -#define QH_STATUS_ICUR(i) ((i) << 5) -#define QH_STATUS_TO_ICUR(s) (((s) >> 5) & 0x7) -#define QH_STATUS_SEQ_MASK 0x1f - -/** - * usb_pipe_to_qh_type - USB core pipe type to QH transfer type - * - * Returns the QH type field for a USB core pipe type. - */ -static inline unsigned usb_pipe_to_qh_type(unsigned pipe) -{ - static const unsigned type[] = { - [PIPE_ISOCHRONOUS] = QH_INFO1_TR_TYPE_ISOC, - [PIPE_INTERRUPT] = QH_INFO1_TR_TYPE_INT, - [PIPE_CONTROL] = QH_INFO1_TR_TYPE_CTRL, - [PIPE_BULK] = QH_INFO1_TR_TYPE_BULK, - }; - return type[usb_pipetype(pipe)]; -} - -/** - * Maxiumum number of TDs in a qset. - */ -#define WHCI_QSET_TD_MAX 8 - -/** - * struct whc_qset - WUSB data transfers to a specific endpoint - * @qh: the QHead of this qset - * @qtd: up to 8 qTDs (for qsets for control, bulk and interrupt - * transfers) - * @itd: up to 8 iTDs (for qsets for isochronous transfers) - * @qset_dma: DMA address for this qset - * @whc: WHCI HC this qset is for - * @ep: endpoint - * @stds: list of sTDs queued to this qset - * @ntds: number of qTDs queued (not necessarily the same as nTDs - * field in the QH) - * @td_start: index of the first qTD in the list - * @td_end: index of next free qTD in the list (provided - * ntds < WHCI_QSET_TD_MAX) - * - * Queue Sets (qsets) are added to the asynchronous schedule list - * (ASL) or the periodic zone list (PZL). - * - * qsets may contain up to 8 TDs (either qTDs or iTDs as appropriate). - * Each TD may refer to at most 1 MiB of data. If a single transfer - * has > 8MiB of data, TDs can be reused as they are completed since - * the TD list is used as a circular buffer. Similarly, several - * (smaller) transfers may be queued in a qset. - * - * WHCI controllers may cache portions of the qsets in the ASL and - * PZL, requiring the WHCD to inform the WHC that the lists have been - * updated (fields changed or qsets inserted or removed). For safe - * insertion and removal of qsets from the lists the schedule must be - * stopped to avoid races in updating the QH link pointers. - * - * Since the HC is free to execute qsets in any order, all transfers - * to an endpoint should use the same qset to ensure transfers are - * executed in the order they're submitted. - * - * [WHCI] section 3.2.3 - */ -struct whc_qset { - struct whc_qhead qh; - union { - struct whc_qtd qtd[WHCI_QSET_TD_MAX]; - struct whc_itd itd[WHCI_QSET_TD_MAX]; - }; - - /* private data for WHCD */ - dma_addr_t qset_dma; - struct whc *whc; - struct usb_host_endpoint *ep; - struct list_head stds; - int ntds; - int td_start; - int td_end; - struct list_head list_node; - unsigned in_sw_list:1; - unsigned in_hw_list:1; - unsigned remove:1; - unsigned reset:1; - struct urb *pause_after_urb; - struct completion remove_complete; - uint16_t max_packet; - uint8_t max_burst; - uint8_t max_seq; -}; - -static inline void whc_qset_set_link_ptr(u64 *ptr, u64 target) -{ - if (target) - *ptr = (*ptr & ~(QH_LINK_PTR_MASK | QH_LINK_T)) | QH_LINK_PTR(target); - else - *ptr = QH_LINK_T; -} - -/** - * struct di_buf_entry - Device Information (DI) buffer entry. - * - * There's one of these per connected device. - */ -struct di_buf_entry { - __le32 availability_info[8]; /*< MAS availability information, one MAS per bit */ - __le32 addr_sec_info; /*< addressing and security info */ - __le32 reserved[7]; -} __attribute__((packed)); - -#define WHC_DI_SECURE (1 << 31) -#define WHC_DI_DISABLE (1 << 30) -#define WHC_DI_KEY_IDX(k) ((k) << 8) -#define WHC_DI_KEY_IDX_MASK 0x0000ff00 -#define WHC_DI_DEV_ADDR(a) ((a) << 0) -#define WHC_DI_DEV_ADDR_MASK 0x000000ff - -/** - * struct dn_buf_entry - Device Notification (DN) buffer entry. - * - * [WHCI] section 3.2.8 - */ -struct dn_buf_entry { - __u8 msg_size; /*< number of octets of valid DN data */ - __u8 reserved1; - __u8 src_addr; /*< source address */ - __u8 status; /*< buffer entry status */ - __le32 tkid; /*< TKID for source device, valid if secure bit is set */ - __u8 dn_data[56]; /*< up to 56 octets of DN data */ -} __attribute__((packed)); - -#define WHC_DN_STATUS_VALID (1 << 7) /* buffer entry is valid */ -#define WHC_DN_STATUS_SECURE (1 << 6) /* notification received using secure frame */ - -#define WHC_N_DN_ENTRIES (4096 / sizeof(struct dn_buf_entry)) - -/* The Add MMC IE WUSB Generic Command may take up to 256 bytes of - data. [WHCI] section 2.4.7. */ -#define WHC_GEN_CMD_DATA_LEN 256 - -/* - * HC registers. - * - * [WHCI] section 2.4 - */ - -#define WHCIVERSION 0x00 - -#define WHCSPARAMS 0x04 -# define WHCSPARAMS_TO_N_MMC_IES(p) (((p) >> 16) & 0xff) -# define WHCSPARAMS_TO_N_KEYS(p) (((p) >> 8) & 0xff) -# define WHCSPARAMS_TO_N_DEVICES(p) (((p) >> 0) & 0x7f) - -#define WUSBCMD 0x08 -# define WUSBCMD_BCID(b) ((b) << 16) -# define WUSBCMD_BCID_MASK (0xff << 16) -# define WUSBCMD_ASYNC_QSET_RM (1 << 12) -# define WUSBCMD_PERIODIC_QSET_RM (1 << 11) -# define WUSBCMD_WUSBSI(s) ((s) << 8) -# define WUSBCMD_WUSBSI_MASK (0x7 << 8) -# define WUSBCMD_ASYNC_SYNCED_DB (1 << 7) -# define WUSBCMD_PERIODIC_SYNCED_DB (1 << 6) -# define WUSBCMD_ASYNC_UPDATED (1 << 5) -# define WUSBCMD_PERIODIC_UPDATED (1 << 4) -# define WUSBCMD_ASYNC_EN (1 << 3) -# define WUSBCMD_PERIODIC_EN (1 << 2) -# define WUSBCMD_WHCRESET (1 << 1) -# define WUSBCMD_RUN (1 << 0) - -#define WUSBSTS 0x0c -# define WUSBSTS_ASYNC_SCHED (1 << 15) -# define WUSBSTS_PERIODIC_SCHED (1 << 14) -# define WUSBSTS_DNTS_SCHED (1 << 13) -# define WUSBSTS_HCHALTED (1 << 12) -# define WUSBSTS_GEN_CMD_DONE (1 << 9) -# define WUSBSTS_CHAN_TIME_ROLLOVER (1 << 8) -# define WUSBSTS_DNTS_OVERFLOW (1 << 7) -# define WUSBSTS_BPST_ADJUSTMENT_CHANGED (1 << 6) -# define WUSBSTS_HOST_ERR (1 << 5) -# define WUSBSTS_ASYNC_SCHED_SYNCED (1 << 4) -# define WUSBSTS_PERIODIC_SCHED_SYNCED (1 << 3) -# define WUSBSTS_DNTS_INT (1 << 2) -# define WUSBSTS_ERR_INT (1 << 1) -# define WUSBSTS_INT (1 << 0) -# define WUSBSTS_INT_MASK 0x3ff - -#define WUSBINTR 0x10 -# define WUSBINTR_GEN_CMD_DONE (1 << 9) -# define WUSBINTR_CHAN_TIME_ROLLOVER (1 << 8) -# define WUSBINTR_DNTS_OVERFLOW (1 << 7) -# define WUSBINTR_BPST_ADJUSTMENT_CHANGED (1 << 6) -# define WUSBINTR_HOST_ERR (1 << 5) -# define WUSBINTR_ASYNC_SCHED_SYNCED (1 << 4) -# define WUSBINTR_PERIODIC_SCHED_SYNCED (1 << 3) -# define WUSBINTR_DNTS_INT (1 << 2) -# define WUSBINTR_ERR_INT (1 << 1) -# define WUSBINTR_INT (1 << 0) -# define WUSBINTR_ALL 0x3ff - -#define WUSBGENCMDSTS 0x14 -# define WUSBGENCMDSTS_ACTIVE (1 << 31) -# define WUSBGENCMDSTS_ERROR (1 << 24) -# define WUSBGENCMDSTS_IOC (1 << 23) -# define WUSBGENCMDSTS_MMCIE_ADD 0x01 -# define WUSBGENCMDSTS_MMCIE_RM 0x02 -# define WUSBGENCMDSTS_SET_MAS 0x03 -# define WUSBGENCMDSTS_CHAN_STOP 0x04 -# define WUSBGENCMDSTS_RWP_EN 0x05 - -#define WUSBGENCMDPARAMS 0x18 -#define WUSBGENADDR 0x20 -#define WUSBASYNCLISTADDR 0x28 -#define WUSBDNTSBUFADDR 0x30 -#define WUSBDEVICEINFOADDR 0x38 - -#define WUSBSETSECKEYCMD 0x40 -# define WUSBSETSECKEYCMD_SET (1 << 31) -# define WUSBSETSECKEYCMD_ERASE (1 << 30) -# define WUSBSETSECKEYCMD_GTK (1 << 8) -# define WUSBSETSECKEYCMD_IDX(i) ((i) << 0) - -#define WUSBTKID 0x44 -#define WUSBSECKEY 0x48 -#define WUSBPERIODICLISTBASE 0x58 -#define WUSBMASINDEX 0x60 - -#define WUSBDNTSCTRL 0x64 -# define WUSBDNTSCTRL_ACTIVE (1 << 31) -# define WUSBDNTSCTRL_INTERVAL(i) ((i) << 8) -# define WUSBDNTSCTRL_SLOTS(s) ((s) << 0) - -#define WUSBTIME 0x68 -# define WUSBTIME_CHANNEL_TIME_MASK 0x00ffffff - -#define WUSBBPST 0x6c -#define WUSBDIBUPDATED 0x70 - -#endif /* #ifndef _WHCI_WHCI_HC_H */ diff --git a/ANDROID_3.4.5/drivers/usb/host/whci/wusb.c b/ANDROID_3.4.5/drivers/usb/host/whci/wusb.c deleted file mode 100644 index f24efdeb..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/whci/wusb.c +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Wireless Host Controller (WHC) WUSB operations. - * - * Copyright (C) 2007 Cambridge Silicon Radio Ltd. - * - * 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, see . - */ -#include -#include -#include - -#include "../../wusbcore/wusbhc.h" - -#include "whcd.h" - -static int whc_update_di(struct whc *whc, int idx) -{ - int offset = idx / 32; - u32 bit = 1 << (idx % 32); - - le_writel(bit, whc->base + WUSBDIBUPDATED + offset); - - return whci_wait_for(&whc->umc->dev, - whc->base + WUSBDIBUPDATED + offset, bit, 0, - 100, "DI update"); -} - -/* - * WHCI starts MMCs based on there being a valid GTK so these need - * only start/stop the asynchronous and periodic schedules and send a - * channel stop command. - */ - -int whc_wusbhc_start(struct wusbhc *wusbhc) -{ - struct whc *whc = wusbhc_to_whc(wusbhc); - - asl_start(whc); - pzl_start(whc); - - return 0; -} - -void whc_wusbhc_stop(struct wusbhc *wusbhc, int delay) -{ - struct whc *whc = wusbhc_to_whc(wusbhc); - u32 stop_time, now_time; - int ret; - - pzl_stop(whc); - asl_stop(whc); - - now_time = le_readl(whc->base + WUSBTIME) & WUSBTIME_CHANNEL_TIME_MASK; - stop_time = (now_time + ((delay * 8) << 7)) & 0x00ffffff; - ret = whc_do_gencmd(whc, WUSBGENCMDSTS_CHAN_STOP, stop_time, NULL, 0); - if (ret == 0) - msleep(delay); -} - -int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, - u8 handle, struct wuie_hdr *wuie) -{ - struct whc *whc = wusbhc_to_whc(wusbhc); - u32 params; - - params = (interval << 24) - | (repeat_cnt << 16) - | (wuie->bLength << 8) - | handle; - - return whc_do_gencmd(whc, WUSBGENCMDSTS_MMCIE_ADD, params, wuie, wuie->bLength); -} - -int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle) -{ - struct whc *whc = wusbhc_to_whc(wusbhc); - u32 params; - - params = handle; - - return whc_do_gencmd(whc, WUSBGENCMDSTS_MMCIE_RM, params, NULL, 0); -} - -int whc_bwa_set(struct wusbhc *wusbhc, s8 stream_index, const struct uwb_mas_bm *mas_bm) -{ - struct whc *whc = wusbhc_to_whc(wusbhc); - - if (stream_index >= 0) - whc_write_wusbcmd(whc, WUSBCMD_WUSBSI_MASK, WUSBCMD_WUSBSI(stream_index)); - - return whc_do_gencmd(whc, WUSBGENCMDSTS_SET_MAS, 0, (void *)mas_bm, sizeof(*mas_bm)); -} - -int whc_dev_info_set(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) -{ - struct whc *whc = wusbhc_to_whc(wusbhc); - int idx = wusb_dev->port_idx; - struct di_buf_entry *di = &whc->di_buf[idx]; - int ret; - - mutex_lock(&whc->mutex); - - uwb_mas_bm_copy_le(di->availability_info, &wusb_dev->availability); - di->addr_sec_info &= ~(WHC_DI_DISABLE | WHC_DI_DEV_ADDR_MASK); - di->addr_sec_info |= WHC_DI_DEV_ADDR(wusb_dev->addr); - - ret = whc_update_di(whc, idx); - - mutex_unlock(&whc->mutex); - - return ret; -} - -/* - * Set the number of Device Notification Time Slots (DNTS) and enable - * device notifications. - */ -int whc_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots) -{ - struct whc *whc = wusbhc_to_whc(wusbhc); - u32 dntsctrl; - - dntsctrl = WUSBDNTSCTRL_ACTIVE - | WUSBDNTSCTRL_INTERVAL(interval) - | WUSBDNTSCTRL_SLOTS(slots); - - le_writel(dntsctrl, whc->base + WUSBDNTSCTRL); - - return 0; -} - -static int whc_set_key(struct whc *whc, u8 key_index, uint32_t tkid, - const void *key, size_t key_size, bool is_gtk) -{ - uint32_t setkeycmd; - uint32_t seckey[4]; - int i; - int ret; - - memcpy(seckey, key, key_size); - setkeycmd = WUSBSETSECKEYCMD_SET | WUSBSETSECKEYCMD_IDX(key_index); - if (is_gtk) - setkeycmd |= WUSBSETSECKEYCMD_GTK; - - le_writel(tkid, whc->base + WUSBTKID); - for (i = 0; i < 4; i++) - le_writel(seckey[i], whc->base + WUSBSECKEY + 4*i); - le_writel(setkeycmd, whc->base + WUSBSETSECKEYCMD); - - ret = whci_wait_for(&whc->umc->dev, whc->base + WUSBSETSECKEYCMD, - WUSBSETSECKEYCMD_SET, 0, 100, "set key"); - - return ret; -} - -/** - * whc_set_ptk - set the PTK to use for a device. - * - * The index into the key table for this PTK is the same as the - * device's port index. - */ -int whc_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid, - const void *ptk, size_t key_size) -{ - struct whc *whc = wusbhc_to_whc(wusbhc); - struct di_buf_entry *di = &whc->di_buf[port_idx]; - int ret; - - mutex_lock(&whc->mutex); - - if (ptk) { - ret = whc_set_key(whc, port_idx, tkid, ptk, key_size, false); - if (ret) - goto out; - - di->addr_sec_info &= ~WHC_DI_KEY_IDX_MASK; - di->addr_sec_info |= WHC_DI_SECURE | WHC_DI_KEY_IDX(port_idx); - } else - di->addr_sec_info &= ~WHC_DI_SECURE; - - ret = whc_update_di(whc, port_idx); -out: - mutex_unlock(&whc->mutex); - return ret; -} - -/** - * whc_set_gtk - set the GTK for subsequent broadcast packets - * - * The GTK is stored in the last entry in the key table (the previous - * N_DEVICES entries are for the per-device PTKs). - */ -int whc_set_gtk(struct wusbhc *wusbhc, u32 tkid, - const void *gtk, size_t key_size) -{ - struct whc *whc = wusbhc_to_whc(wusbhc); - int ret; - - mutex_lock(&whc->mutex); - - ret = whc_set_key(whc, whc->n_devices, tkid, gtk, key_size, true); - - mutex_unlock(&whc->mutex); - - return ret; -} - -int whc_set_cluster_id(struct whc *whc, u8 bcid) -{ - whc_write_wusbcmd(whc, WUSBCMD_BCID_MASK, WUSBCMD_BCID(bcid)); - return 0; -} diff --git a/ANDROID_3.4.5/drivers/usb/host/xhci-dbg.c b/ANDROID_3.4.5/drivers/usb/host/xhci-dbg.c deleted file mode 100644 index 4b436f5a..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/xhci-dbg.c +++ /dev/null @@ -1,576 +0,0 @@ -/* - * 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_HSEIE) ? "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) -{ - __le32 __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, int set_num) -{ - struct xhci_intr_reg __iomem *ir_set = &xhci->run_regs->ir_set[set_num]; - void __iomem *addr; - u32 temp; - u64 temp_64; - - 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; - temp_64 = xhci_read_64(xhci, addr); - xhci_dbg(xhci, " %p: ir_set.erst_base = @%08llx\n", - addr, temp_64); - - addr = &ir_set->erst_dequeue; - temp_64 = xhci_read_64(xhci, addr); - xhci_dbg(xhci, " %p: ir_set.erst_dequeue = @%08llx\n", - addr, temp_64); -} - -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 = le32_to_cpu(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 = le64_to_cpu(trb->link.segment_ptr); - xhci_dbg(xhci, "Next ring segment DMA address = 0x%llx\n", address); - - xhci_dbg(xhci, "Interrupter target = 0x%x\n", - GET_INTR_TARGET(le32_to_cpu(trb->link.intr_target))); - xhci_dbg(xhci, "Cycle bit = %u\n", - le32_to_cpu(trb->link.control) & TRB_CYCLE); - xhci_dbg(xhci, "Toggle cycle bit = %u\n", - le32_to_cpu(trb->link.control) & LINK_TOGGLE); - xhci_dbg(xhci, "No Snoop bit = %u\n", - le32_to_cpu(trb->link.control) & TRB_NO_SNOOP); - break; - case TRB_TYPE(TRB_TRANSFER): - address = le64_to_cpu(trb->trans_event.buffer); - /* - * 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 = le64_to_cpu(trb->event_cmd.cmd_trb); - xhci_dbg(xhci, "Command TRB pointer = %llu\n", address); - xhci_dbg(xhci, "Completion status = %u\n", - GET_COMP_CODE(le32_to_cpu(trb->event_cmd.status))); - xhci_dbg(xhci, "Flags = 0x%x\n", - le32_to_cpu(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; - u64 addr = seg->dma; - union xhci_trb *trb = seg->trbs; - - for (i = 0; i < TRBS_PER_SEGMENT; ++i) { - trb = &seg->trbs[i]; - xhci_dbg(xhci, "@%016llx %08x %08x %08x %08x\n", addr, - lower_32_bits(le64_to_cpu(trb->link.segment_ptr)), - upper_32_bits(le64_to_cpu(trb->link.segment_ptr)), - le32_to_cpu(trb->link.intr_target), - le32_to_cpu(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_ep_rings(struct xhci_hcd *xhci, - unsigned int slot_id, unsigned int ep_index, - struct xhci_virt_ep *ep) -{ - int i; - struct xhci_ring *ring; - - if (ep->ep_state & EP_HAS_STREAMS) { - for (i = 1; i < ep->stream_info->num_streams; i++) { - ring = ep->stream_info->stream_rings[i]; - xhci_dbg(xhci, "Dev %d endpoint %d stream ID %d:\n", - slot_id, ep_index, i); - xhci_debug_segment(xhci, ring->deq_seg); - } - } else { - ring = ep->ring; - if (!ring) - return; - xhci_dbg(xhci, "Dev %d endpoint ring %d:\n", - slot_id, ep_index); - xhci_debug_segment(xhci, ring->deq_seg); - } -} - -void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst) -{ - u64 addr = 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, "@%016llx %08x %08x %08x %08x\n", - addr, - lower_32_bits(le64_to_cpu(entry->seg_addr)), - upper_32_bits(le64_to_cpu(entry->seg_addr)), - le32_to_cpu(entry->seg_size), - le32_to_cpu(entry->rsvd)); - addr += sizeof(*entry); - } -} - -void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci) -{ - u64 val; - - val = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); - xhci_dbg(xhci, "// xHC command ring deq ptr low bits + flags = @%08x\n", - lower_32_bits(val)); - xhci_dbg(xhci, "// xHC command ring deq ptr high bits = @%08x\n", - upper_32_bits(val)); -} - -/* Print the last 32 bytes for 64-byte contexts */ -static void dbg_rsvd64(struct xhci_hcd *xhci, u64 *ctx, dma_addr_t dma) -{ - int i; - for (i = 0; i < 4; ++i) { - xhci_dbg(xhci, "@%p (virt) @%08llx " - "(dma) %#08llx - rsvd64[%d]\n", - &ctx[4 + i], (unsigned long long)dma, - ctx[4 + i], i); - dma += 8; - } -} - -char *xhci_get_slot_state(struct xhci_hcd *xhci, - struct xhci_container_ctx *ctx) -{ - struct xhci_slot_ctx *slot_ctx = xhci_get_slot_ctx(xhci, ctx); - - switch (GET_SLOT_STATE(le32_to_cpu(slot_ctx->dev_state))) { - case SLOT_STATE_ENABLED: - return "enabled/disabled"; - case SLOT_STATE_DEFAULT: - return "default"; - case SLOT_STATE_ADDRESSED: - return "addressed"; - case SLOT_STATE_CONFIGURED: - return "configured"; - default: - return "reserved"; - } -} - -static void xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx) -{ - /* Fields are 32 bits wide, DMA addresses are in bytes */ - int field_size = 32 / 8; - int i; - - struct xhci_slot_ctx *slot_ctx = xhci_get_slot_ctx(xhci, ctx); - dma_addr_t dma = ctx->dma + - ((unsigned long)slot_ctx - (unsigned long)ctx->bytes); - int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params); - - xhci_dbg(xhci, "Slot Context:\n"); - xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info\n", - &slot_ctx->dev_info, - (unsigned long long)dma, slot_ctx->dev_info); - dma += field_size; - xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info2\n", - &slot_ctx->dev_info2, - (unsigned long long)dma, slot_ctx->dev_info2); - dma += field_size; - xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tt_info\n", - &slot_ctx->tt_info, - (unsigned long long)dma, slot_ctx->tt_info); - dma += field_size; - xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_state\n", - &slot_ctx->dev_state, - (unsigned long long)dma, slot_ctx->dev_state); - dma += field_size; - for (i = 0; i < 4; ++i) { - xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", - &slot_ctx->reserved[i], (unsigned long long)dma, - slot_ctx->reserved[i], i); - dma += field_size; - } - - if (csz) - dbg_rsvd64(xhci, (u64 *)slot_ctx, dma); -} - -static void xhci_dbg_ep_ctx(struct xhci_hcd *xhci, - struct xhci_container_ctx *ctx, - 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; - int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params); - - if (last_ep < 31) - last_ep_ctx = last_ep + 1; - for (i = 0; i < last_ep_ctx; ++i) { - struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, ctx, i); - dma_addr_t dma = ctx->dma + - ((unsigned long)ep_ctx - (unsigned long)ctx->bytes); - - xhci_dbg(xhci, "Endpoint %02d Context:\n", i); - xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info\n", - &ep_ctx->ep_info, - (unsigned long long)dma, ep_ctx->ep_info); - dma += field_size; - xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info2\n", - &ep_ctx->ep_info2, - (unsigned long long)dma, ep_ctx->ep_info2); - dma += field_size; - xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08llx - deq\n", - &ep_ctx->deq, - (unsigned long long)dma, ep_ctx->deq); - dma += 2*field_size; - xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tx_info\n", - &ep_ctx->tx_info, - (unsigned long long)dma, ep_ctx->tx_info); - dma += field_size; - for (j = 0; j < 3; ++j) { - xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", - &ep_ctx->reserved[j], - (unsigned long long)dma, - ep_ctx->reserved[j], j); - dma += field_size; - } - - if (csz) - dbg_rsvd64(xhci, (u64 *)ep_ctx, dma); - } -} - -void xhci_dbg_ctx(struct xhci_hcd *xhci, - struct xhci_container_ctx *ctx, - unsigned int last_ep) -{ - int i; - /* Fields are 32 bits wide, DMA addresses are in bytes */ - int field_size = 32 / 8; - struct xhci_slot_ctx *slot_ctx; - dma_addr_t dma = ctx->dma; - int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params); - - if (ctx->type == XHCI_CTX_TYPE_INPUT) { - struct xhci_input_control_ctx *ctrl_ctx = - xhci_get_input_control_ctx(xhci, ctx); - xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - drop flags\n", - &ctrl_ctx->drop_flags, (unsigned long long)dma, - ctrl_ctx->drop_flags); - dma += field_size; - xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - add flags\n", - &ctrl_ctx->add_flags, (unsigned long long)dma, - ctrl_ctx->add_flags); - dma += field_size; - for (i = 0; i < 6; ++i) { - xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd2[%d]\n", - &ctrl_ctx->rsvd2[i], (unsigned long long)dma, - ctrl_ctx->rsvd2[i], i); - dma += field_size; - } - - if (csz) - dbg_rsvd64(xhci, (u64 *)ctrl_ctx, dma); - } - - slot_ctx = xhci_get_slot_ctx(xhci, ctx); - xhci_dbg_slot_ctx(xhci, ctx); - xhci_dbg_ep_ctx(xhci, ctx, last_ep); -} diff --git a/ANDROID_3.4.5/drivers/usb/host/xhci-ext-caps.h b/ANDROID_3.4.5/drivers/usb/host/xhci-ext-caps.h deleted file mode 100644 index 377f4242..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/xhci-ext-caps.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * 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 ms to halt an HC */ -#define XHCI_MAX_HALT_USEC (16*1000) -/* 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:3, 5:12, and 17:19 need to be preserved; bits 21:28 should be zero */ -#define XHCI_LEGACY_DISABLE_SMI ((0x7 << 1) + (0xff << 5) + (0x7 << 17)) -#define XHCI_LEGACY_SMI_EVENTS (0x7 << 29) - -/* USB 2.0 xHCI 0.96 L1C capability - section 7.2.2.1.3.2 */ -#define XHCI_L1C (1 << 16) - -/* USB 2.0 xHCI 1.0 hardware LMP capability - section 7.2.2.1.3.2 */ -#define XHCI_HLC (1 << 19) - -/* 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 - -/** - * 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); - ext_offset = 0; - } 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; -} diff --git a/ANDROID_3.4.5/drivers/usb/host/xhci-hub.c b/ANDROID_3.4.5/drivers/usb/host/xhci-hub.c deleted file mode 100644 index bbf3c0c9..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/xhci-hub.c +++ /dev/null @@ -1,1096 +0,0 @@ -/* - * 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 -#include - -#include "xhci.h" - -#define PORT_WAKE_BITS (PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E) -#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \ - PORT_RC | PORT_PLC | PORT_PE) - -/* usb 1.1 root hub device descriptor */ -static u8 usb_bos_descriptor [] = { - USB_DT_BOS_SIZE, /* __u8 bLength, 5 bytes */ - USB_DT_BOS, /* __u8 bDescriptorType */ - 0x0F, 0x00, /* __le16 wTotalLength, 15 bytes */ - 0x1, /* __u8 bNumDeviceCaps */ - /* First device capability */ - USB_DT_USB_SS_CAP_SIZE, /* __u8 bLength, 10 bytes */ - USB_DT_DEVICE_CAPABILITY, /* Device Capability */ - USB_SS_CAP_TYPE, /* bDevCapabilityType, SUPERSPEED_USB */ - 0x00, /* bmAttributes, LTM off by default */ - USB_5GBPS_OPERATION, 0x00, /* wSpeedsSupported, 5Gbps only */ - 0x03, /* bFunctionalitySupport, - USB 3.0 speed only */ - 0x00, /* bU1DevExitLat, set later. */ - 0x00, 0x00 /* __le16 bU2DevExitLat, set later. */ -}; - - -static void xhci_common_hub_descriptor(struct xhci_hcd *xhci, - struct usb_hub_descriptor *desc, int ports) -{ - u16 temp; - - desc->bPwrOn2PwrGood = 10; /* xhci section 5.4.9 says 20ms max */ - desc->bHubContrCurrent = 0; - - desc->bNbrPorts = ports; - temp = 0; - /* Bits 1:0 - support per-port power switching, or power always on */ - if (HCC_PPC(xhci->hcc_params)) - temp |= HUB_CHAR_INDV_PORT_LPSM; - else - temp |= HUB_CHAR_NO_LPSM; - /* Bit 2 - root hubs are not part of a compound device */ - /* Bits 4:3 - individual port over current protection */ - temp |= HUB_CHAR_INDV_PORT_OCPM; - /* Bits 6:5 - no TTs in root ports */ - /* Bit 7 - no port indicators */ - desc->wHubCharacteristics = cpu_to_le16(temp); -} - -/* Fill in the USB 2.0 roothub descriptor */ -static void xhci_usb2_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci, - struct usb_hub_descriptor *desc) -{ - int ports; - u16 temp; - __u8 port_removable[(USB_MAXCHILDREN + 1 + 7) / 8]; - u32 portsc; - unsigned int i; - - ports = xhci->num_usb2_ports; - - xhci_common_hub_descriptor(xhci, desc, ports); - desc->bDescriptorType = USB_DT_HUB; - temp = 1 + (ports / 8); - desc->bDescLength = USB_DT_HUB_NONVAR_SIZE + 2 * temp; - - /* The Device Removable bits are reported on a byte granularity. - * If the port doesn't exist within that byte, the bit is set to 0. - */ - memset(port_removable, 0, sizeof(port_removable)); - for (i = 0; i < ports; i++) { - portsc = xhci_readl(xhci, xhci->usb2_ports[i]); - /* If a device is removable, PORTSC reports a 0, same as in the - * hub descriptor DeviceRemovable bits. - */ - if (portsc & PORT_DEV_REMOVE) - /* This math is hairy because bit 0 of DeviceRemovable - * is reserved, and bit 1 is for port 1, etc. - */ - port_removable[(i + 1) / 8] |= 1 << ((i + 1) % 8); - } - - /* ch11.h defines a hub descriptor that has room for USB_MAXCHILDREN - * ports on it. The USB 2.0 specification says that there are two - * variable length fields at the end of the hub descriptor: - * DeviceRemovable and PortPwrCtrlMask. But since we can have less than - * USB_MAXCHILDREN ports, we may need to use the DeviceRemovable array - * to set PortPwrCtrlMask bits. PortPwrCtrlMask must always be set to - * 0xFF, so we initialize the both arrays (DeviceRemovable and - * PortPwrCtrlMask) to 0xFF. Then we set the DeviceRemovable for each - * set of ports that actually exist. - */ - memset(desc->u.hs.DeviceRemovable, 0xff, - sizeof(desc->u.hs.DeviceRemovable)); - memset(desc->u.hs.PortPwrCtrlMask, 0xff, - sizeof(desc->u.hs.PortPwrCtrlMask)); - - for (i = 0; i < (ports + 1 + 7) / 8; i++) - memset(&desc->u.hs.DeviceRemovable[i], port_removable[i], - sizeof(__u8)); -} - -/* Fill in the USB 3.0 roothub descriptor */ -static void xhci_usb3_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci, - struct usb_hub_descriptor *desc) -{ - int ports; - u16 port_removable; - u32 portsc; - unsigned int i; - - ports = xhci->num_usb3_ports; - xhci_common_hub_descriptor(xhci, desc, ports); - desc->bDescriptorType = USB_DT_SS_HUB; - desc->bDescLength = USB_DT_SS_HUB_SIZE; - - /* header decode latency should be zero for roothubs, - * see section 4.23.5.2. - */ - desc->u.ss.bHubHdrDecLat = 0; - desc->u.ss.wHubDelay = 0; - - port_removable = 0; - /* bit 0 is reserved, bit 1 is for port 1, etc. */ - for (i = 0; i < ports; i++) { - portsc = xhci_readl(xhci, xhci->usb3_ports[i]); - if (portsc & PORT_DEV_REMOVE) - port_removable |= 1 << (i + 1); - } - memset(&desc->u.ss.DeviceRemovable, - (__force __u16) cpu_to_le16(port_removable), - sizeof(__u16)); -} - -static void xhci_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci, - struct usb_hub_descriptor *desc) -{ - - if (hcd->speed == HCD_USB3) - xhci_usb3_hub_descriptor(hcd, xhci, desc); - else - xhci_usb2_hub_descriptor(hcd, xhci, desc); - -} - -static unsigned int xhci_port_speed(unsigned int port_status) -{ - if (DEV_LOWSPEED(port_status)) - return USB_PORT_STAT_LOW_SPEED; - if (DEV_HIGHSPEED(port_status)) - return USB_PORT_STAT_HIGH_SPEED; - /* - * 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_STAT_*_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. - */ -u32 xhci_port_state_to_neutral(u32 state) -{ - /* Save read-only status and port state */ - return (state & XHCI_PORT_RO) | (state & XHCI_PORT_RWS); -} - -/* - * find slot id based on port number. - * @port: The one-based port number from one of the two split roothubs. - */ -int xhci_find_slot_id_by_port(struct usb_hcd *hcd, struct xhci_hcd *xhci, - u16 port) -{ - int slot_id; - int i; - enum usb_device_speed speed; - - slot_id = 0; - for (i = 0; i < MAX_HC_SLOTS; i++) { - if (!xhci->devs[i]) - continue; - speed = xhci->devs[i]->udev->speed; - if (((speed == USB_SPEED_SUPER) == (hcd->speed == HCD_USB3)) - && xhci->devs[i]->fake_port == port) { - slot_id = i; - break; - } - } - - return slot_id; -} - -/* - * Stop device - * It issues stop endpoint command for EP 0 to 30. And wait the last command - * to complete. - * suspend will set to 1, if suspend bit need to set in command. - */ -static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend) -{ - struct xhci_virt_device *virt_dev; - struct xhci_command *cmd; - unsigned long flags; - int timeleft; - int ret; - int i; - - ret = 0; - virt_dev = xhci->devs[slot_id]; - cmd = xhci_alloc_command(xhci, false, true, GFP_NOIO); - if (!cmd) { - xhci_dbg(xhci, "Couldn't allocate command structure.\n"); - return -ENOMEM; - } - - spin_lock_irqsave(&xhci->lock, flags); - for (i = LAST_EP_INDEX; i > 0; i--) { - if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue) - xhci_queue_stop_endpoint(xhci, slot_id, i, suspend); - } - cmd->command_trb = xhci->cmd_ring->enqueue; - list_add_tail(&cmd->cmd_list, &virt_dev->cmd_list); - xhci_queue_stop_endpoint(xhci, slot_id, 0, suspend); - xhci_ring_cmd_db(xhci); - spin_unlock_irqrestore(&xhci->lock, flags); - - /* Wait for last stop endpoint command to finish */ - timeleft = wait_for_completion_interruptible_timeout( - cmd->completion, - USB_CTRL_SET_TIMEOUT); - if (timeleft <= 0) { - xhci_warn(xhci, "%s while waiting for stop endpoint command\n", - timeleft == 0 ? "Timeout" : "Signal"); - spin_lock_irqsave(&xhci->lock, flags); - /* The timeout might have raced with the event ring handler, so - * only delete from the list if the item isn't poisoned. - */ - if (cmd->cmd_list.next != LIST_POISON1) - list_del(&cmd->cmd_list); - spin_unlock_irqrestore(&xhci->lock, flags); - ret = -ETIME; - goto command_cleanup; - } - -command_cleanup: - xhci_free_command(xhci, cmd); - return ret; -} - -/* - * Ring device, it rings the all doorbells unconditionally. - */ -void xhci_ring_device(struct xhci_hcd *xhci, int slot_id) -{ - int i; - - for (i = 0; i < LAST_EP_INDEX + 1; i++) - if (xhci->devs[slot_id]->eps[i].ring && - xhci->devs[slot_id]->eps[i].ring->dequeue) - xhci_ring_ep_doorbell(xhci, slot_id, i, 0); - - return; -} - -static void xhci_disable_port(struct usb_hcd *hcd, struct xhci_hcd *xhci, - u16 wIndex, __le32 __iomem *addr, u32 port_status) -{ - /* Don't allow the USB core to disable SuperSpeed ports. */ - if (hcd->speed == HCD_USB3) { - xhci_dbg(xhci, "Ignoring request to disable " - "SuperSpeed port.\n"); - return; - } - - /* Write 1 to disable the port */ - xhci_writel(xhci, port_status | PORT_PE, addr); - port_status = xhci_readl(xhci, addr); - xhci_dbg(xhci, "disable port, actual port %d status = 0x%x\n", - wIndex, port_status); -} - -static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue, - u16 wIndex, __le32 __iomem *addr, u32 port_status) -{ - char *port_change_bit; - u32 status; - - switch (wValue) { - case USB_PORT_FEAT_C_RESET: - status = PORT_RC; - port_change_bit = "reset"; - break; - case USB_PORT_FEAT_C_BH_PORT_RESET: - status = PORT_WRC; - port_change_bit = "warm(BH) 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; - case USB_PORT_FEAT_C_ENABLE: - status = PORT_PEC; - port_change_bit = "enable/disable"; - break; - case USB_PORT_FEAT_C_SUSPEND: - status = PORT_PLC; - port_change_bit = "suspend/resume"; - break; - case USB_PORT_FEAT_C_PORT_LINK_STATE: - status = PORT_PLC; - port_change_bit = "link state"; - break; - default: - /* Should never happen */ - return; - } - /* Change bits are all write 1 to clear */ - xhci_writel(xhci, port_status | status, addr); - port_status = xhci_readl(xhci, addr); - xhci_dbg(xhci, "clear port %s change, actual port %d status = 0x%x\n", - port_change_bit, wIndex, port_status); -} - -static int xhci_get_ports(struct usb_hcd *hcd, __le32 __iomem ***port_array) -{ - int max_ports; - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - - if (hcd->speed == HCD_USB3) { - max_ports = xhci->num_usb3_ports; - *port_array = xhci->usb3_ports; - } else { - max_ports = xhci->num_usb2_ports; - *port_array = xhci->usb2_ports; - } - - return max_ports; -} - -void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array, - int port_id, u32 link_state) -{ - u32 temp; - - temp = xhci_readl(xhci, port_array[port_id]); - temp = xhci_port_state_to_neutral(temp); - temp &= ~PORT_PLS_MASK; - temp |= PORT_LINK_STROBE | link_state; - xhci_writel(xhci, temp, port_array[port_id]); -} - -void xhci_set_remote_wake_mask(struct xhci_hcd *xhci, - __le32 __iomem **port_array, int port_id, u16 wake_mask) -{ - u32 temp; - - temp = xhci_readl(xhci, port_array[port_id]); - temp = xhci_port_state_to_neutral(temp); - - if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_CONNECT) - temp |= PORT_WKCONN_E; - else - temp &= ~PORT_WKCONN_E; - - if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT) - temp |= PORT_WKDISC_E; - else - temp &= ~PORT_WKDISC_E; - - if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT) - temp |= PORT_WKOC_E; - else - temp &= ~PORT_WKOC_E; - - xhci_writel(xhci, temp, port_array[port_id]); -} - -/* Test and clear port RWC bit */ -void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array, - int port_id, u32 port_bit) -{ - u32 temp; - - temp = xhci_readl(xhci, port_array[port_id]); - if (temp & port_bit) { - temp = xhci_port_state_to_neutral(temp); - temp |= port_bit; - xhci_writel(xhci, temp, port_array[port_id]); - } -} - -/* Updates Link Status for super Speed port */ -static void xhci_hub_report_link_state(u32 *status, u32 status_reg) -{ - u32 pls = status_reg & PORT_PLS_MASK; - - /* resume state is a xHCI internal state. - * Do not report it to usb core. - */ - if (pls == XDEV_RESUME) - return; - - /* When the CAS bit is set then warm reset - * should be performed on port - */ - if (status_reg & PORT_CAS) { - /* The CAS bit can be set while the port is - * in any link state. - * Only roothubs have CAS bit, so we - * pretend to be in compliance mode - * unless we're already in compliance - * or the inactive state. - */ - if (pls != USB_SS_PORT_LS_COMP_MOD && - pls != USB_SS_PORT_LS_SS_INACTIVE) { - pls = USB_SS_PORT_LS_COMP_MOD; - } - /* Return also connection bit - - * hub state machine resets port - * when this bit is set. - */ - pls |= USB_PORT_STAT_CONNECTION; - } - /* update status field */ - *status |= pls; -} - -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 max_ports; - unsigned long flags; - u32 temp, status; - int retval = 0; - __le32 __iomem **port_array; - int slot_id; - struct xhci_bus_state *bus_state; - u16 link_state = 0; - u16 wake_mask = 0; - - max_ports = xhci_get_ports(hcd, &port_array); - bus_state = &xhci->bus_state[hcd_index(hcd)]; - - 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: - /* Check to make sure userspace is asking for the USB 3.0 hub - * descriptor for the USB 3.0 roothub. If not, we stall the - * endpoint, like external hubs do. - */ - if (hcd->speed == HCD_USB3 && - (wLength < USB_DT_SS_HUB_SIZE || - wValue != (USB_DT_SS_HUB << 8))) { - xhci_dbg(xhci, "Wrong hub descriptor type for " - "USB 3.0 roothub.\n"); - goto error; - } - xhci_hub_descriptor(hcd, xhci, - (struct usb_hub_descriptor *) buf); - break; - case DeviceRequest | USB_REQ_GET_DESCRIPTOR: - if ((wValue & 0xff00) != (USB_DT_BOS << 8)) - goto error; - - if (hcd->speed != HCD_USB3) - goto error; - - memcpy(buf, &usb_bos_descriptor, - USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE); - temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params3); - buf[12] = HCS_U1_LATENCY(temp); - put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]); - - spin_unlock_irqrestore(&xhci->lock, flags); - return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE; - case GetPortStatus: - if (!wIndex || wIndex > max_ports) - goto error; - wIndex--; - status = 0; - temp = xhci_readl(xhci, port_array[wIndex]); - if (temp == 0xffffffff) { - retval = -ENODEV; - break; - } - xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp); - - /* wPortChange bits */ - if (temp & PORT_CSC) - status |= USB_PORT_STAT_C_CONNECTION << 16; - if (temp & PORT_PEC) - status |= USB_PORT_STAT_C_ENABLE << 16; - if ((temp & PORT_OCC)) - status |= USB_PORT_STAT_C_OVERCURRENT << 16; - if ((temp & PORT_RC)) - status |= USB_PORT_STAT_C_RESET << 16; - /* USB3.0 only */ - if (hcd->speed == HCD_USB3) { - if ((temp & PORT_PLC)) - status |= USB_PORT_STAT_C_LINK_STATE << 16; - if ((temp & PORT_WRC)) - status |= USB_PORT_STAT_C_BH_RESET << 16; - } - - if (hcd->speed != HCD_USB3) { - if ((temp & PORT_PLS_MASK) == XDEV_U3 - && (temp & PORT_POWER)) - status |= USB_PORT_STAT_SUSPEND; - } - if ((temp & PORT_PLS_MASK) == XDEV_RESUME && - !DEV_SUPERSPEED(temp)) { - if ((temp & PORT_RESET) || !(temp & PORT_PE)) - goto error; - if (time_after_eq(jiffies, - bus_state->resume_done[wIndex])) { - xhci_dbg(xhci, "Resume USB2 port %d\n", - wIndex + 1); - bus_state->resume_done[wIndex] = 0; - clear_bit(wIndex, &bus_state->resuming_ports); - xhci_set_link_state(xhci, port_array, wIndex, - XDEV_U0); - xhci_dbg(xhci, "set port %d resume\n", - wIndex + 1); - slot_id = xhci_find_slot_id_by_port(hcd, xhci, - wIndex + 1); - if (!slot_id) { - xhci_dbg(xhci, "slot_id is zero\n"); - goto error; - } - xhci_ring_device(xhci, slot_id); - bus_state->port_c_suspend |= 1 << wIndex; - bus_state->suspended_ports &= ~(1 << wIndex); - } else { - /* - * The resume has been signaling for less than - * 20ms. Report the port status as SUSPEND, - * let the usbcore check port status again - * and clear resume signaling later. - */ - status |= USB_PORT_STAT_SUSPEND; - } - } - if ((temp & PORT_PLS_MASK) == XDEV_U0 - && (temp & PORT_POWER) - && (bus_state->suspended_ports & (1 << wIndex))) { - bus_state->suspended_ports &= ~(1 << wIndex); - if (hcd->speed != HCD_USB3) - bus_state->port_c_suspend |= 1 << wIndex; - } - if (temp & PORT_CONNECT) { - status |= USB_PORT_STAT_CONNECTION; - status |= xhci_port_speed(temp); - } - if (temp & PORT_PE) - status |= USB_PORT_STAT_ENABLE; - if (temp & PORT_OC) - status |= USB_PORT_STAT_OVERCURRENT; - if (temp & PORT_RESET) - status |= USB_PORT_STAT_RESET; - if (temp & PORT_POWER) { - if (hcd->speed == HCD_USB3) - status |= USB_SS_PORT_STAT_POWER; - else - status |= USB_PORT_STAT_POWER; - } - /* Update Port Link State for super speed ports*/ - if (hcd->speed == HCD_USB3) { - xhci_hub_report_link_state(&status, temp); - } - if (bus_state->port_c_suspend & (1 << wIndex)) - status |= 1 << USB_PORT_FEAT_C_SUSPEND; - xhci_dbg(xhci, "Get port status returned 0x%x\n", status); - put_unaligned(cpu_to_le32(status), (__le32 *) buf); - break; - case SetPortFeature: - if (wValue == USB_PORT_FEAT_LINK_STATE) - link_state = (wIndex & 0xff00) >> 3; - if (wValue == USB_PORT_FEAT_REMOTE_WAKE_MASK) - wake_mask = wIndex & 0xff00; - wIndex &= 0xff; - if (!wIndex || wIndex > max_ports) - goto error; - wIndex--; - temp = xhci_readl(xhci, port_array[wIndex]); - if (temp == 0xffffffff) { - retval = -ENODEV; - break; - } - temp = xhci_port_state_to_neutral(temp); - /* FIXME: What new port features do we need to support? */ - switch (wValue) { - case USB_PORT_FEAT_SUSPEND: - temp = xhci_readl(xhci, port_array[wIndex]); - if ((temp & PORT_PLS_MASK) != XDEV_U0) { - /* Resume the port to U0 first */ - xhci_set_link_state(xhci, port_array, wIndex, - XDEV_U0); - spin_unlock_irqrestore(&xhci->lock, flags); - msleep(10); - spin_lock_irqsave(&xhci->lock, flags); - } - /* In spec software should not attempt to suspend - * a port unless the port reports that it is in the - * enabled (PED = ‘1’,PLS < ‘3’) state. - */ - temp = xhci_readl(xhci, port_array[wIndex]); - if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) - || (temp & PORT_PLS_MASK) >= XDEV_U3) { - xhci_warn(xhci, "USB core suspending device " - "not in U0/U1/U2.\n"); - goto error; - } - - slot_id = xhci_find_slot_id_by_port(hcd, xhci, - wIndex + 1); - if (!slot_id) { - xhci_warn(xhci, "slot_id is zero\n"); - goto error; - } - /* unlock to execute stop endpoint commands */ - spin_unlock_irqrestore(&xhci->lock, flags); - xhci_stop_device(xhci, slot_id, 1); - spin_lock_irqsave(&xhci->lock, flags); - - xhci_set_link_state(xhci, port_array, wIndex, XDEV_U3); - - spin_unlock_irqrestore(&xhci->lock, flags); - msleep(10); /* wait device to enter */ - spin_lock_irqsave(&xhci->lock, flags); - - temp = xhci_readl(xhci, port_array[wIndex]); - bus_state->suspended_ports |= 1 << wIndex; - break; - case USB_PORT_FEAT_LINK_STATE: - temp = xhci_readl(xhci, port_array[wIndex]); - /* Software should not attempt to set - * port link state above '5' (Rx.Detect) and the port - * must be enabled. - */ - if ((temp & PORT_PE) == 0 || - (link_state > USB_SS_PORT_LS_RX_DETECT)) { - xhci_warn(xhci, "Cannot set link state.\n"); - goto error; - } - - if (link_state == USB_SS_PORT_LS_U3) { - slot_id = xhci_find_slot_id_by_port(hcd, xhci, - wIndex + 1); - if (slot_id) { - /* unlock to execute stop endpoint - * commands */ - spin_unlock_irqrestore(&xhci->lock, - flags); - xhci_stop_device(xhci, slot_id, 1); - spin_lock_irqsave(&xhci->lock, flags); - } - } - - xhci_set_link_state(xhci, port_array, wIndex, - link_state); - - spin_unlock_irqrestore(&xhci->lock, flags); - msleep(20); /* wait device to enter */ - spin_lock_irqsave(&xhci->lock, flags); - - temp = xhci_readl(xhci, port_array[wIndex]); - if (link_state == USB_SS_PORT_LS_U3) - bus_state->suspended_ports |= 1 << wIndex; - break; - 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, - port_array[wIndex]); - - temp = xhci_readl(xhci, port_array[wIndex]); - 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, port_array[wIndex]); - - temp = xhci_readl(xhci, port_array[wIndex]); - xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp); - break; - case USB_PORT_FEAT_REMOTE_WAKE_MASK: - xhci_set_remote_wake_mask(xhci, port_array, - wIndex, wake_mask); - temp = xhci_readl(xhci, port_array[wIndex]); - xhci_dbg(xhci, "set port remote wake mask, " - "actual port %d status = 0x%x\n", - wIndex, temp); - break; - case USB_PORT_FEAT_BH_PORT_RESET: - temp |= PORT_WR; - xhci_writel(xhci, temp, port_array[wIndex]); - - temp = xhci_readl(xhci, port_array[wIndex]); - break; - default: - goto error; - } - /* unblock any posted writes */ - temp = xhci_readl(xhci, port_array[wIndex]); - break; - case ClearPortFeature: - if (!wIndex || wIndex > max_ports) - goto error; - wIndex--; - temp = xhci_readl(xhci, port_array[wIndex]); - if (temp == 0xffffffff) { - retval = -ENODEV; - break; - } - /* FIXME: What new port features do we need to support? */ - temp = xhci_port_state_to_neutral(temp); - switch (wValue) { - case USB_PORT_FEAT_SUSPEND: - temp = xhci_readl(xhci, port_array[wIndex]); - xhci_dbg(xhci, "clear USB_PORT_FEAT_SUSPEND\n"); - xhci_dbg(xhci, "PORTSC %04x\n", temp); - if (temp & PORT_RESET) - goto error; - if ((temp & PORT_PLS_MASK) == XDEV_U3) { - if ((temp & PORT_PE) == 0) - goto error; - - xhci_set_link_state(xhci, port_array, wIndex, - XDEV_RESUME); - spin_unlock_irqrestore(&xhci->lock, flags); - msleep(20); - spin_lock_irqsave(&xhci->lock, flags); - xhci_set_link_state(xhci, port_array, wIndex, - XDEV_U0); - } - bus_state->port_c_suspend |= 1 << wIndex; - - slot_id = xhci_find_slot_id_by_port(hcd, xhci, - wIndex + 1); - if (!slot_id) { - xhci_dbg(xhci, "slot_id is zero\n"); - goto error; - } - xhci_ring_device(xhci, slot_id); - break; - case USB_PORT_FEAT_C_SUSPEND: - bus_state->port_c_suspend &= ~(1 << wIndex); - case USB_PORT_FEAT_C_RESET: - case USB_PORT_FEAT_C_BH_PORT_RESET: - case USB_PORT_FEAT_C_CONNECTION: - case USB_PORT_FEAT_C_OVER_CURRENT: - case USB_PORT_FEAT_C_ENABLE: - case USB_PORT_FEAT_C_PORT_LINK_STATE: - xhci_clear_port_change_bit(xhci, wValue, wIndex, - port_array[wIndex], temp); - break; - case USB_PORT_FEAT_ENABLE: - xhci_disable_port(hcd, xhci, wIndex, - port_array[wIndex], temp); - break; - default: - goto error; - } - 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. - * - * 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; - u32 mask; - int i, retval; - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - int max_ports; - __le32 __iomem **port_array; - struct xhci_bus_state *bus_state; - - max_ports = xhci_get_ports(hcd, &port_array); - bus_state = &xhci->bus_state[hcd_index(hcd)]; - - /* Initial status is no changes */ - retval = (max_ports + 8) / 8; - memset(buf, 0, retval); - - /* - * Inform the usbcore about resume-in-progress by returning - * a non-zero value even if there are no status changes. - */ - status = bus_state->resuming_ports; - - mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC; - - spin_lock_irqsave(&xhci->lock, flags); - /* For each port, did anything change? If so, set that bit in buf. */ - for (i = 0; i < max_ports; i++) { - temp = xhci_readl(xhci, port_array[i]); - if (temp == 0xffffffff) { - retval = -ENODEV; - break; - } - if ((temp & mask) != 0 || - (bus_state->port_c_suspend & 1 << i) || - (bus_state->resume_done[i] && time_after_eq( - jiffies, bus_state->resume_done[i]))) { - buf[(i + 1) / 8] |= 1 << (i + 1) % 8; - status = 1; - } - } - spin_unlock_irqrestore(&xhci->lock, flags); - return status ? retval : 0; -} - -#ifdef CONFIG_PM - -int xhci_bus_suspend(struct usb_hcd *hcd) -{ - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - int max_ports, port_index; - __le32 __iomem **port_array; - struct xhci_bus_state *bus_state; - unsigned long flags; - - max_ports = xhci_get_ports(hcd, &port_array); - bus_state = &xhci->bus_state[hcd_index(hcd)]; - - spin_lock_irqsave(&xhci->lock, flags); - - if (hcd->self.root_hub->do_remote_wakeup) { - if (bus_state->resuming_ports) { - spin_unlock_irqrestore(&xhci->lock, flags); - xhci_dbg(xhci, "suspend failed because " - "a port is resuming\n"); - return -EBUSY; - } - } - - port_index = max_ports; - bus_state->bus_suspended = 0; - while (port_index--) { - /* suspend the port if the port is not suspended */ - u32 t1, t2; - int slot_id; - - t1 = xhci_readl(xhci, port_array[port_index]); - t2 = xhci_port_state_to_neutral(t1); - - if ((t1 & PORT_PE) && !(t1 & PORT_PLS_MASK)) { - xhci_dbg(xhci, "port %d not suspended\n", port_index); - slot_id = xhci_find_slot_id_by_port(hcd, xhci, - port_index + 1); - if (slot_id) { - spin_unlock_irqrestore(&xhci->lock, flags); - xhci_stop_device(xhci, slot_id, 1); - spin_lock_irqsave(&xhci->lock, flags); - } - t2 &= ~PORT_PLS_MASK; - t2 |= PORT_LINK_STROBE | XDEV_U3; - set_bit(port_index, &bus_state->bus_suspended); - } - /* USB core sets remote wake mask for USB 3.0 hubs, - * including the USB 3.0 roothub, but only if CONFIG_USB_SUSPEND - * is enabled, so also enable remote wake here. - */ - if (hcd->self.root_hub->do_remote_wakeup) { - if (t1 & PORT_CONNECT) { - t2 |= PORT_WKOC_E | PORT_WKDISC_E; - t2 &= ~PORT_WKCONN_E; - } else { - t2 |= PORT_WKOC_E | PORT_WKCONN_E; - t2 &= ~PORT_WKDISC_E; - } - } else - t2 &= ~PORT_WAKE_BITS; - - t1 = xhci_port_state_to_neutral(t1); - if (t1 != t2) - xhci_writel(xhci, t2, port_array[port_index]); - - if (hcd->speed != HCD_USB3) { - /* enable remote wake up for USB 2.0 */ - __le32 __iomem *addr; - u32 tmp; - - /* Add one to the port status register address to get - * the port power control register address. - */ - addr = port_array[port_index] + 1; - tmp = xhci_readl(xhci, addr); - tmp |= PORT_RWE; - xhci_writel(xhci, tmp, addr); - } - } - hcd->state = HC_STATE_SUSPENDED; - bus_state->next_statechange = jiffies + msecs_to_jiffies(10); - spin_unlock_irqrestore(&xhci->lock, flags); - return 0; -} - -int xhci_bus_resume(struct usb_hcd *hcd) -{ - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - int max_ports, port_index; - __le32 __iomem **port_array; - struct xhci_bus_state *bus_state; - u32 temp; - unsigned long flags; - - max_ports = xhci_get_ports(hcd, &port_array); - bus_state = &xhci->bus_state[hcd_index(hcd)]; - - if (time_before(jiffies, bus_state->next_statechange)) - msleep(5); - - spin_lock_irqsave(&xhci->lock, flags); - if (!HCD_HW_ACCESSIBLE(hcd)) { - spin_unlock_irqrestore(&xhci->lock, flags); - return -ESHUTDOWN; - } - - /* delay the irqs */ - temp = xhci_readl(xhci, &xhci->op_regs->command); - temp &= ~CMD_EIE; - xhci_writel(xhci, temp, &xhci->op_regs->command); - - port_index = max_ports; - while (port_index--) { - /* Check whether need resume ports. If needed - resume port and disable remote wakeup */ - u32 temp; - int slot_id; - - temp = xhci_readl(xhci, port_array[port_index]); - if (DEV_SUPERSPEED(temp)) - temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS); - else - temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); - if (test_bit(port_index, &bus_state->bus_suspended) && - (temp & PORT_PLS_MASK)) { - if (DEV_SUPERSPEED(temp)) { - xhci_set_link_state(xhci, port_array, - port_index, XDEV_U0); - } else { - xhci_set_link_state(xhci, port_array, - port_index, XDEV_RESUME); - - spin_unlock_irqrestore(&xhci->lock, flags); - msleep(20); - spin_lock_irqsave(&xhci->lock, flags); - - xhci_set_link_state(xhci, port_array, - port_index, XDEV_U0); - } - /* wait for the port to enter U0 and report port link - * state change. - */ - spin_unlock_irqrestore(&xhci->lock, flags); - msleep(20); - spin_lock_irqsave(&xhci->lock, flags); - - /* Clear PLC */ - xhci_test_and_clear_bit(xhci, port_array, port_index, - PORT_PLC); - - slot_id = xhci_find_slot_id_by_port(hcd, - xhci, port_index + 1); - if (slot_id) - xhci_ring_device(xhci, slot_id); - } else - xhci_writel(xhci, temp, port_array[port_index]); - - if (hcd->speed != HCD_USB3) { - /* disable remote wake up for USB 2.0 */ - __le32 __iomem *addr; - u32 tmp; - - /* Add one to the port status register address to get - * the port power control register address. - */ - addr = port_array[port_index] + 1; - tmp = xhci_readl(xhci, addr); - tmp &= ~PORT_RWE; - xhci_writel(xhci, tmp, addr); - } - } - - (void) xhci_readl(xhci, &xhci->op_regs->command); - - bus_state->next_statechange = jiffies + msecs_to_jiffies(5); - /* re-enable irqs */ - temp = xhci_readl(xhci, &xhci->op_regs->command); - temp |= CMD_EIE; - xhci_writel(xhci, temp, &xhci->op_regs->command); - temp = xhci_readl(xhci, &xhci->op_regs->command); - - spin_unlock_irqrestore(&xhci->lock, flags); - return 0; -} - -#endif /* CONFIG_PM */ diff --git a/ANDROID_3.4.5/drivers/usb/host/xhci-mem.c b/ANDROID_3.4.5/drivers/usb/host/xhci-mem.c deleted file mode 100644 index 6b908249..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/xhci-mem.c +++ /dev/null @@ -1,2460 +0,0 @@ -/* - * 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 -#include -#include -#include - -#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, - unsigned int cycle_state, gfp_t flags) -{ - struct xhci_segment *seg; - dma_addr_t dma; - int i; - - seg = kzalloc(sizeof *seg, flags); - if (!seg) - return NULL; - - seg->trbs = dma_pool_alloc(xhci->segment_pool, flags, &dma); - if (!seg->trbs) { - kfree(seg); - return NULL; - } - - memset(seg->trbs, 0, SEGMENT_SIZE); - /* If the cycle state is 0, set the cycle bit to 1 for all the TRBs */ - if (cycle_state == 0) { - for (i = 0; i < TRBS_PER_SEGMENT; i++) - seg->trbs[i].link.control |= TRB_CYCLE; - } - seg->dma = dma; - seg->next = NULL; - - return seg; -} - -static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg) -{ - if (seg->trbs) { - dma_pool_free(xhci->segment_pool, seg->trbs, seg->dma); - seg->trbs = NULL; - } - kfree(seg); -} - -static void xhci_free_segments_for_ring(struct xhci_hcd *xhci, - struct xhci_segment *first) -{ - struct xhci_segment *seg; - - seg = first->next; - while (seg != first) { - struct xhci_segment *next = seg->next; - xhci_segment_free(xhci, seg); - seg = next; - } - xhci_segment_free(xhci, first); -} - -/* - * 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, enum xhci_ring_type type) -{ - u32 val; - - if (!prev || !next) - return; - prev->next = next; - if (type != TYPE_EVENT) { - prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr = - cpu_to_le64(next->dma); - - /* Set the last TRB in the segment to have a TRB type ID of Link TRB */ - val = le32_to_cpu(prev->trbs[TRBS_PER_SEGMENT-1].link.control); - val &= ~TRB_TYPE_BITMASK; - val |= TRB_TYPE(TRB_LINK); - /* Always set the chain bit with 0.95 hardware */ - /* Set chain bit for isoc rings on AMD 0.96 host */ - if (xhci_link_trb_quirk(xhci) || - (type == TYPE_ISOC && - (xhci->quirks & XHCI_AMD_0x96_HOST))) - val |= TRB_CHAIN; - prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val); - } -} - -/* - * Link the ring to the new segments. - * Set Toggle Cycle for the new ring if needed. - */ -static void xhci_link_rings(struct xhci_hcd *xhci, struct xhci_ring *ring, - struct xhci_segment *first, struct xhci_segment *last, - unsigned int num_segs) -{ - struct xhci_segment *next; - - if (!ring || !first || !last) - return; - - next = ring->enq_seg->next; - xhci_link_segments(xhci, ring->enq_seg, first, ring->type); - xhci_link_segments(xhci, last, next, ring->type); - ring->num_segs += num_segs; - ring->num_trbs_free += (TRBS_PER_SEGMENT - 1) * num_segs; - - if (ring->type != TYPE_EVENT && ring->enq_seg == ring->last_seg) { - ring->last_seg->trbs[TRBS_PER_SEGMENT-1].link.control - &= ~cpu_to_le32(LINK_TOGGLE); - last->trbs[TRBS_PER_SEGMENT-1].link.control - |= cpu_to_le32(LINK_TOGGLE); - ring->last_seg = last; - } -} - -/* XXX: Do we need the hcd structure in all these functions? */ -void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring) -{ - if (!ring) - return; - - if (ring->first_seg) - xhci_free_segments_for_ring(xhci, ring->first_seg); - - kfree(ring); -} - -static void xhci_initialize_ring_info(struct xhci_ring *ring, - unsigned int cycle_state) -{ - /* 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. - * - * New rings are initialized with cycle state equal to 1; if we are - * handling ring expansion, set the cycle state equal to the old ring. - */ - ring->cycle_state = cycle_state; - /* Not necessary for new rings, but needed for re-initialized rings */ - ring->enq_updates = 0; - ring->deq_updates = 0; - - /* - * Each segment has a link TRB, and leave an extra TRB for SW - * accounting purpose - */ - ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1; -} - -/* Allocate segments and link them for a ring */ -static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci, - struct xhci_segment **first, struct xhci_segment **last, - unsigned int num_segs, unsigned int cycle_state, - enum xhci_ring_type type, gfp_t flags) -{ - struct xhci_segment *prev; - - prev = xhci_segment_alloc(xhci, cycle_state, flags); - if (!prev) - return -ENOMEM; - num_segs--; - - *first = prev; - while (num_segs > 0) { - struct xhci_segment *next; - - next = xhci_segment_alloc(xhci, cycle_state, flags); - if (!next) { - xhci_free_segments_for_ring(xhci, *first); - return -ENOMEM; - } - xhci_link_segments(xhci, prev, next, type); - - prev = next; - num_segs--; - } - xhci_link_segments(xhci, prev, *first, type); - *last = prev; - - return 0; -} - -/** - * 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, unsigned int cycle_state, - enum xhci_ring_type type, gfp_t flags) -{ - struct xhci_ring *ring; - int ret; - - ring = kzalloc(sizeof *(ring), flags); - if (!ring) - return NULL; - - ring->num_segs = num_segs; - INIT_LIST_HEAD(&ring->td_list); - ring->type = type; - if (num_segs == 0) - return ring; - - ret = xhci_alloc_segments_for_ring(xhci, &ring->first_seg, - &ring->last_seg, num_segs, cycle_state, type, flags); - if (ret) - goto fail; - - /* Only event ring does not use link TRB */ - if (type != TYPE_EVENT) { - /* See section 4.9.2.1 and 6.4.4.1 */ - ring->last_seg->trbs[TRBS_PER_SEGMENT - 1].link.control |= - cpu_to_le32(LINK_TOGGLE); - } - xhci_initialize_ring_info(ring, cycle_state); - return ring; - -fail: - xhci_ring_free(xhci, ring); - return NULL; -} - -void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci, - struct xhci_virt_device *virt_dev, - unsigned int ep_index) -{ - int rings_cached; - - rings_cached = virt_dev->num_rings_cached; - if (rings_cached < XHCI_MAX_RINGS_CACHED) { - virt_dev->ring_cache[rings_cached] = - virt_dev->eps[ep_index].ring; - virt_dev->num_rings_cached++; - xhci_dbg(xhci, "Cached old ring, " - "%d ring%s cached\n", - virt_dev->num_rings_cached, - (virt_dev->num_rings_cached > 1) ? "s" : ""); - } else { - xhci_ring_free(xhci, virt_dev->eps[ep_index].ring); - xhci_dbg(xhci, "Ring cache full (%d rings), " - "freeing ring\n", - virt_dev->num_rings_cached); - } - virt_dev->eps[ep_index].ring = NULL; -} - -/* Zero an endpoint ring (except for link TRBs) and move the enqueue and dequeue - * pointers to the beginning of the ring. - */ -static void xhci_reinit_cached_ring(struct xhci_hcd *xhci, - struct xhci_ring *ring, unsigned int cycle_state, - enum xhci_ring_type type) -{ - struct xhci_segment *seg = ring->first_seg; - int i; - - do { - memset(seg->trbs, 0, - sizeof(union xhci_trb)*TRBS_PER_SEGMENT); - if (cycle_state == 0) { - for (i = 0; i < TRBS_PER_SEGMENT; i++) - seg->trbs[i].link.control |= TRB_CYCLE; - } - /* All endpoint rings have link TRBs */ - xhci_link_segments(xhci, seg, seg->next, type); - seg = seg->next; - } while (seg != ring->first_seg); - ring->type = type; - xhci_initialize_ring_info(ring, cycle_state); - /* td list should be empty since all URBs have been cancelled, - * but just in case... - */ - INIT_LIST_HEAD(&ring->td_list); -} - -/* - * Expand an existing ring. - * Look for a cached ring or allocate a new ring which has same segment numbers - * and link the two rings. - */ -int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring, - unsigned int num_trbs, gfp_t flags) -{ - struct xhci_segment *first; - struct xhci_segment *last; - unsigned int num_segs; - unsigned int num_segs_needed; - int ret; - - num_segs_needed = (num_trbs + (TRBS_PER_SEGMENT - 1) - 1) / - (TRBS_PER_SEGMENT - 1); - - /* Allocate number of segments we needed, or double the ring size */ - num_segs = ring->num_segs > num_segs_needed ? - ring->num_segs : num_segs_needed; - - ret = xhci_alloc_segments_for_ring(xhci, &first, &last, - num_segs, ring->cycle_state, ring->type, flags); - if (ret) - return -ENOMEM; - - xhci_link_rings(xhci, ring, first, last, num_segs); - xhci_dbg(xhci, "ring expansion succeed, now has %d segments\n", - ring->num_segs); - - return 0; -} - -#define CTX_SIZE(_hcc) (HCC_64BYTE_CONTEXT(_hcc) ? 64 : 32) - -static struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci, - int type, gfp_t flags) -{ - struct xhci_container_ctx *ctx = kzalloc(sizeof(*ctx), flags); - if (!ctx) - return NULL; - - BUG_ON((type != XHCI_CTX_TYPE_DEVICE) && (type != XHCI_CTX_TYPE_INPUT)); - ctx->type = type; - ctx->size = HCC_64BYTE_CONTEXT(xhci->hcc_params) ? 2048 : 1024; - if (type == XHCI_CTX_TYPE_INPUT) - ctx->size += CTX_SIZE(xhci->hcc_params); - - ctx->bytes = dma_pool_alloc(xhci->device_pool, flags, &ctx->dma); - memset(ctx->bytes, 0, ctx->size); - return ctx; -} - -static void xhci_free_container_ctx(struct xhci_hcd *xhci, - struct xhci_container_ctx *ctx) -{ - if (!ctx) - return; - dma_pool_free(xhci->device_pool, ctx->bytes, ctx->dma); - kfree(ctx); -} - -struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_hcd *xhci, - struct xhci_container_ctx *ctx) -{ - BUG_ON(ctx->type != XHCI_CTX_TYPE_INPUT); - return (struct xhci_input_control_ctx *)ctx->bytes; -} - -struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, - struct xhci_container_ctx *ctx) -{ - if (ctx->type == XHCI_CTX_TYPE_DEVICE) - return (struct xhci_slot_ctx *)ctx->bytes; - - return (struct xhci_slot_ctx *) - (ctx->bytes + CTX_SIZE(xhci->hcc_params)); -} - -struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, - struct xhci_container_ctx *ctx, - unsigned int ep_index) -{ - /* increment ep index by offset of start of ep ctx array */ - ep_index++; - if (ctx->type == XHCI_CTX_TYPE_INPUT) - ep_index++; - - return (struct xhci_ep_ctx *) - (ctx->bytes + (ep_index * CTX_SIZE(xhci->hcc_params))); -} - - -/***************** Streams structures manipulation *************************/ - -static void xhci_free_stream_ctx(struct xhci_hcd *xhci, - unsigned int num_stream_ctxs, - struct xhci_stream_ctx *stream_ctx, dma_addr_t dma) -{ - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); - - if (num_stream_ctxs > MEDIUM_STREAM_ARRAY_SIZE) - dma_free_coherent(&pdev->dev, - sizeof(struct xhci_stream_ctx)*num_stream_ctxs, - stream_ctx, dma); - else if (num_stream_ctxs <= SMALL_STREAM_ARRAY_SIZE) - return dma_pool_free(xhci->small_streams_pool, - stream_ctx, dma); - else - return dma_pool_free(xhci->medium_streams_pool, - stream_ctx, dma); -} - -/* - * The stream context array for each endpoint with bulk streams enabled can - * vary in size, based on: - * - how many streams the endpoint supports, - * - the maximum primary stream array size the host controller supports, - * - and how many streams the device driver asks for. - * - * The stream context array must be a power of 2, and can be as small as - * 64 bytes or as large as 1MB. - */ -static struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci, - unsigned int num_stream_ctxs, dma_addr_t *dma, - gfp_t mem_flags) -{ - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); - - if (num_stream_ctxs > MEDIUM_STREAM_ARRAY_SIZE) - return dma_alloc_coherent(&pdev->dev, - sizeof(struct xhci_stream_ctx)*num_stream_ctxs, - dma, mem_flags); - else if (num_stream_ctxs <= SMALL_STREAM_ARRAY_SIZE) - return dma_pool_alloc(xhci->small_streams_pool, - mem_flags, dma); - else - return dma_pool_alloc(xhci->medium_streams_pool, - mem_flags, dma); -} - -struct xhci_ring *xhci_dma_to_transfer_ring( - struct xhci_virt_ep *ep, - u64 address) -{ - if (ep->ep_state & EP_HAS_STREAMS) - return radix_tree_lookup(&ep->stream_info->trb_address_map, - address >> SEGMENT_SHIFT); - return ep->ring; -} - -/* Only use this when you know stream_info is valid */ -#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING -static struct xhci_ring *dma_to_stream_ring( - struct xhci_stream_info *stream_info, - u64 address) -{ - return radix_tree_lookup(&stream_info->trb_address_map, - address >> SEGMENT_SHIFT); -} -#endif /* CONFIG_USB_XHCI_HCD_DEBUGGING */ - -struct xhci_ring *xhci_stream_id_to_ring( - struct xhci_virt_device *dev, - unsigned int ep_index, - unsigned int stream_id) -{ - struct xhci_virt_ep *ep = &dev->eps[ep_index]; - - if (stream_id == 0) - return ep->ring; - if (!ep->stream_info) - return NULL; - - if (stream_id > ep->stream_info->num_streams) - return NULL; - return ep->stream_info->stream_rings[stream_id]; -} - -#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING -static int xhci_test_radix_tree(struct xhci_hcd *xhci, - unsigned int num_streams, - struct xhci_stream_info *stream_info) -{ - u32 cur_stream; - struct xhci_ring *cur_ring; - u64 addr; - - for (cur_stream = 1; cur_stream < num_streams; cur_stream++) { - struct xhci_ring *mapped_ring; - int trb_size = sizeof(union xhci_trb); - - cur_ring = stream_info->stream_rings[cur_stream]; - for (addr = cur_ring->first_seg->dma; - addr < cur_ring->first_seg->dma + SEGMENT_SIZE; - addr += trb_size) { - mapped_ring = dma_to_stream_ring(stream_info, addr); - if (cur_ring != mapped_ring) { - xhci_warn(xhci, "WARN: DMA address 0x%08llx " - "didn't map to stream ID %u; " - "mapped to ring %p\n", - (unsigned long long) addr, - cur_stream, - mapped_ring); - return -EINVAL; - } - } - /* One TRB after the end of the ring segment shouldn't return a - * pointer to the current ring (although it may be a part of a - * different ring). - */ - mapped_ring = dma_to_stream_ring(stream_info, addr); - if (mapped_ring != cur_ring) { - /* One TRB before should also fail */ - addr = cur_ring->first_seg->dma - trb_size; - mapped_ring = dma_to_stream_ring(stream_info, addr); - } - if (mapped_ring == cur_ring) { - xhci_warn(xhci, "WARN: Bad DMA address 0x%08llx " - "mapped to valid stream ID %u; " - "mapped ring = %p\n", - (unsigned long long) addr, - cur_stream, - mapped_ring); - return -EINVAL; - } - } - return 0; -} -#endif /* CONFIG_USB_XHCI_HCD_DEBUGGING */ - -/* - * Change an endpoint's internal structure so it supports stream IDs. The - * number of requested streams includes stream 0, which cannot be used by device - * drivers. - * - * The number of stream contexts in the stream context array may be bigger than - * the number of streams the driver wants to use. This is because the number of - * stream context array entries must be a power of two. - * - * We need a radix tree for mapping physical addresses of TRBs to which stream - * ID they belong to. We need to do this because the host controller won't tell - * us which stream ring the TRB came from. We could store the stream ID in an - * event data TRB, but that doesn't help us for the cancellation case, since the - * endpoint may stop before it reaches that event data TRB. - * - * The radix tree maps the upper portion of the TRB DMA address to a ring - * segment that has the same upper portion of DMA addresses. For example, say I - * have segments of size 1KB, that are always 64-byte aligned. A segment may - * start at 0x10c91000 and end at 0x10c913f0. If I use the upper 10 bits, the - * key to the stream ID is 0x43244. I can use the DMA address of the TRB to - * pass the radix tree a key to get the right stream ID: - * - * 0x10c90fff >> 10 = 0x43243 - * 0x10c912c0 >> 10 = 0x43244 - * 0x10c91400 >> 10 = 0x43245 - * - * Obviously, only those TRBs with DMA addresses that are within the segment - * will make the radix tree return the stream ID for that ring. - * - * Caveats for the radix tree: - * - * The radix tree uses an unsigned long as a key pair. On 32-bit systems, an - * unsigned long will be 32-bits; on a 64-bit system an unsigned long will be - * 64-bits. Since we only request 32-bit DMA addresses, we can use that as the - * key on 32-bit or 64-bit systems (it would also be fine if we asked for 64-bit - * PCI DMA addresses on a 64-bit system). There might be a problem on 32-bit - * extended systems (where the DMA address can be bigger than 32-bits), - * if we allow the PCI dma mask to be bigger than 32-bits. So don't do that. - */ -struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, - unsigned int num_stream_ctxs, - unsigned int num_streams, gfp_t mem_flags) -{ - struct xhci_stream_info *stream_info; - u32 cur_stream; - struct xhci_ring *cur_ring; - unsigned long key; - u64 addr; - int ret; - - xhci_dbg(xhci, "Allocating %u streams and %u " - "stream context array entries.\n", - num_streams, num_stream_ctxs); - if (xhci->cmd_ring_reserved_trbs == MAX_RSVD_CMD_TRBS) { - xhci_dbg(xhci, "Command ring has no reserved TRBs available\n"); - return NULL; - } - xhci->cmd_ring_reserved_trbs++; - - stream_info = kzalloc(sizeof(struct xhci_stream_info), mem_flags); - if (!stream_info) - goto cleanup_trbs; - - stream_info->num_streams = num_streams; - stream_info->num_stream_ctxs = num_stream_ctxs; - - /* Initialize the array of virtual pointers to stream rings. */ - stream_info->stream_rings = kzalloc( - sizeof(struct xhci_ring *)*num_streams, - mem_flags); - if (!stream_info->stream_rings) - goto cleanup_info; - - /* Initialize the array of DMA addresses for stream rings for the HW. */ - stream_info->stream_ctx_array = xhci_alloc_stream_ctx(xhci, - num_stream_ctxs, &stream_info->ctx_array_dma, - mem_flags); - if (!stream_info->stream_ctx_array) - goto cleanup_ctx; - memset(stream_info->stream_ctx_array, 0, - sizeof(struct xhci_stream_ctx)*num_stream_ctxs); - - /* Allocate everything needed to free the stream rings later */ - stream_info->free_streams_command = - xhci_alloc_command(xhci, true, true, mem_flags); - if (!stream_info->free_streams_command) - goto cleanup_ctx; - - INIT_RADIX_TREE(&stream_info->trb_address_map, GFP_ATOMIC); - - /* Allocate rings for all the streams that the driver will use, - * and add their segment DMA addresses to the radix tree. - * Stream 0 is reserved. - */ - for (cur_stream = 1; cur_stream < num_streams; cur_stream++) { - stream_info->stream_rings[cur_stream] = - xhci_ring_alloc(xhci, 2, 1, TYPE_STREAM, mem_flags); - cur_ring = stream_info->stream_rings[cur_stream]; - if (!cur_ring) - goto cleanup_rings; - cur_ring->stream_id = cur_stream; - /* Set deq ptr, cycle bit, and stream context type */ - addr = cur_ring->first_seg->dma | - SCT_FOR_CTX(SCT_PRI_TR) | - cur_ring->cycle_state; - stream_info->stream_ctx_array[cur_stream].stream_ring = - cpu_to_le64(addr); - xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n", - cur_stream, (unsigned long long) addr); - - key = (unsigned long) - (cur_ring->first_seg->dma >> SEGMENT_SHIFT); - ret = radix_tree_insert(&stream_info->trb_address_map, - key, cur_ring); - if (ret) { - xhci_ring_free(xhci, cur_ring); - stream_info->stream_rings[cur_stream] = NULL; - goto cleanup_rings; - } - } - /* Leave the other unused stream ring pointers in the stream context - * array initialized to zero. This will cause the xHC to give us an - * error if the device asks for a stream ID we don't have setup (if it - * was any other way, the host controller would assume the ring is - * "empty" and wait forever for data to be queued to that stream ID). - */ -#if XHCI_DEBUG - /* Do a little test on the radix tree to make sure it returns the - * correct values. - */ - if (xhci_test_radix_tree(xhci, num_streams, stream_info)) - goto cleanup_rings; -#endif - - return stream_info; - -cleanup_rings: - for (cur_stream = 1; cur_stream < num_streams; cur_stream++) { - cur_ring = stream_info->stream_rings[cur_stream]; - if (cur_ring) { - addr = cur_ring->first_seg->dma; - radix_tree_delete(&stream_info->trb_address_map, - addr >> SEGMENT_SHIFT); - xhci_ring_free(xhci, cur_ring); - stream_info->stream_rings[cur_stream] = NULL; - } - } - xhci_free_command(xhci, stream_info->free_streams_command); -cleanup_ctx: - kfree(stream_info->stream_rings); -cleanup_info: - kfree(stream_info); -cleanup_trbs: - xhci->cmd_ring_reserved_trbs--; - return NULL; -} -/* - * Sets the MaxPStreams field and the Linear Stream Array field. - * Sets the dequeue pointer to the stream context array. - */ -void xhci_setup_streams_ep_input_ctx(struct xhci_hcd *xhci, - struct xhci_ep_ctx *ep_ctx, - struct xhci_stream_info *stream_info) -{ - u32 max_primary_streams; - /* MaxPStreams is the number of stream context array entries, not the - * number we're actually using. Must be in 2^(MaxPstreams + 1) format. - * fls(0) = 0, fls(0x1) = 1, fls(0x10) = 2, fls(0x100) = 3, etc. - */ - max_primary_streams = fls(stream_info->num_stream_ctxs) - 2; - xhci_dbg(xhci, "Setting number of stream ctx array entries to %u\n", - 1 << (max_primary_streams + 1)); - ep_ctx->ep_info &= cpu_to_le32(~EP_MAXPSTREAMS_MASK); - ep_ctx->ep_info |= cpu_to_le32(EP_MAXPSTREAMS(max_primary_streams) - | EP_HAS_LSA); - ep_ctx->deq = cpu_to_le64(stream_info->ctx_array_dma); -} - -/* - * Sets the MaxPStreams field and the Linear Stream Array field to 0. - * Reinstalls the "normal" endpoint ring (at its previous dequeue mark, - * not at the beginning of the ring). - */ -void xhci_setup_no_streams_ep_input_ctx(struct xhci_hcd *xhci, - struct xhci_ep_ctx *ep_ctx, - struct xhci_virt_ep *ep) -{ - dma_addr_t addr; - ep_ctx->ep_info &= cpu_to_le32(~(EP_MAXPSTREAMS_MASK | EP_HAS_LSA)); - addr = xhci_trb_virt_to_dma(ep->ring->deq_seg, ep->ring->dequeue); - ep_ctx->deq = cpu_to_le64(addr | ep->ring->cycle_state); -} - -/* Frees all stream contexts associated with the endpoint, - * - * Caller should fix the endpoint context streams fields. - */ -void xhci_free_stream_info(struct xhci_hcd *xhci, - struct xhci_stream_info *stream_info) -{ - int cur_stream; - struct xhci_ring *cur_ring; - dma_addr_t addr; - - if (!stream_info) - return; - - for (cur_stream = 1; cur_stream < stream_info->num_streams; - cur_stream++) { - cur_ring = stream_info->stream_rings[cur_stream]; - if (cur_ring) { - addr = cur_ring->first_seg->dma; - radix_tree_delete(&stream_info->trb_address_map, - addr >> SEGMENT_SHIFT); - xhci_ring_free(xhci, cur_ring); - stream_info->stream_rings[cur_stream] = NULL; - } - } - xhci_free_command(xhci, stream_info->free_streams_command); - xhci->cmd_ring_reserved_trbs--; - if (stream_info->stream_ctx_array) - xhci_free_stream_ctx(xhci, - stream_info->num_stream_ctxs, - stream_info->stream_ctx_array, - stream_info->ctx_array_dma); - - if (stream_info) - kfree(stream_info->stream_rings); - kfree(stream_info); -} - - -/***************** Device context manipulation *************************/ - -static void xhci_init_endpoint_timer(struct xhci_hcd *xhci, - struct xhci_virt_ep *ep) -{ - init_timer(&ep->stop_cmd_timer); - ep->stop_cmd_timer.data = (unsigned long) ep; - ep->stop_cmd_timer.function = xhci_stop_endpoint_command_watchdog; - ep->xhci = xhci; -} - -static void xhci_free_tt_info(struct xhci_hcd *xhci, - struct xhci_virt_device *virt_dev, - int slot_id) -{ - struct list_head *tt_list_head; - struct xhci_tt_bw_info *tt_info, *next; - bool slot_found = false; - - /* If the device never made it past the Set Address stage, - * it may not have the real_port set correctly. - */ - if (virt_dev->real_port == 0 || - virt_dev->real_port > HCS_MAX_PORTS(xhci->hcs_params1)) { - xhci_dbg(xhci, "Bad real port.\n"); - return; - } - - tt_list_head = &(xhci->rh_bw[virt_dev->real_port - 1].tts); - list_for_each_entry_safe(tt_info, next, tt_list_head, tt_list) { - /* Multi-TT hubs will have more than one entry */ - if (tt_info->slot_id == slot_id) { - slot_found = true; - list_del(&tt_info->tt_list); - kfree(tt_info); - } else if (slot_found) { - break; - } - } -} - -int xhci_alloc_tt_info(struct xhci_hcd *xhci, - struct xhci_virt_device *virt_dev, - struct usb_device *hdev, - struct usb_tt *tt, gfp_t mem_flags) -{ - struct xhci_tt_bw_info *tt_info; - unsigned int num_ports; - int i, j; - - if (!tt->multi) - num_ports = 1; - else - num_ports = hdev->maxchild; - - for (i = 0; i < num_ports; i++, tt_info++) { - struct xhci_interval_bw_table *bw_table; - - tt_info = kzalloc(sizeof(*tt_info), mem_flags); - if (!tt_info) - goto free_tts; - INIT_LIST_HEAD(&tt_info->tt_list); - list_add(&tt_info->tt_list, - &xhci->rh_bw[virt_dev->real_port - 1].tts); - tt_info->slot_id = virt_dev->udev->slot_id; - if (tt->multi) - tt_info->ttport = i+1; - bw_table = &tt_info->bw_table; - for (j = 0; j < XHCI_MAX_INTERVAL; j++) - INIT_LIST_HEAD(&bw_table->interval_bw[j].endpoints); - } - return 0; - -free_tts: - xhci_free_tt_info(xhci, virt_dev, virt_dev->udev->slot_id); - return -ENOMEM; -} - - -/* All the xhci_tds in the ring's TD list should be freed at this point. - * Should be called with xhci->lock held if there is any chance the TT lists - * will be manipulated by the configure endpoint, allocate device, or update - * hub functions while this function is removing the TT entries from the list. - */ -void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) -{ - struct xhci_virt_device *dev; - int i; - int old_active_eps = 0; - - /* Slot ID 0 is reserved */ - if (slot_id == 0 || !xhci->devs[slot_id]) - return; - - dev = xhci->devs[slot_id]; - xhci->dcbaa->dev_context_ptrs[slot_id] = 0; - if (!dev) - return; - - if (dev->tt_info) - old_active_eps = dev->tt_info->active_eps; - - for (i = 0; i < 31; ++i) { - if (dev->eps[i].ring) - xhci_ring_free(xhci, dev->eps[i].ring); - if (dev->eps[i].stream_info) - xhci_free_stream_info(xhci, - dev->eps[i].stream_info); - /* Endpoints on the TT/root port lists should have been removed - * when usb_disable_device() was called for the device. - * We can't drop them anyway, because the udev might have gone - * away by this point, and we can't tell what speed it was. - */ - if (!list_empty(&dev->eps[i].bw_endpoint_list)) - xhci_warn(xhci, "Slot %u endpoint %u " - "not removed from BW list!\n", - slot_id, i); - } - /* If this is a hub, free the TT(s) from the TT list */ - xhci_free_tt_info(xhci, dev, slot_id); - /* If necessary, update the number of active TTs on this root port */ - xhci_update_tt_active_eps(xhci, dev, old_active_eps); - - if (dev->ring_cache) { - for (i = 0; i < dev->num_rings_cached; i++) - xhci_ring_free(xhci, dev->ring_cache[i]); - kfree(dev->ring_cache); - } - - if (dev->in_ctx) - xhci_free_container_ctx(xhci, dev->in_ctx); - if (dev->out_ctx) - xhci_free_container_ctx(xhci, dev->out_ctx); - - kfree(xhci->devs[slot_id]); - xhci->devs[slot_id] = NULL; -} - -int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, - struct usb_device *udev, gfp_t flags) -{ - struct xhci_virt_device *dev; - int i; - - /* 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 = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_DEVICE, flags); - if (!dev->out_ctx) - goto fail; - - xhci_dbg(xhci, "Slot %d output ctx = 0x%llx (dma)\n", slot_id, - (unsigned long long)dev->out_ctx->dma); - - /* Allocate the (input) device context for address device command */ - dev->in_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_INPUT, flags); - if (!dev->in_ctx) - goto fail; - - xhci_dbg(xhci, "Slot %d input ctx = 0x%llx (dma)\n", slot_id, - (unsigned long long)dev->in_ctx->dma); - - /* Initialize the cancellation list and watchdog timers for each ep */ - for (i = 0; i < 31; i++) { - xhci_init_endpoint_timer(xhci, &dev->eps[i]); - INIT_LIST_HEAD(&dev->eps[i].cancelled_td_list); - INIT_LIST_HEAD(&dev->eps[i].bw_endpoint_list); - } - - /* Allocate endpoint 0 ring */ - dev->eps[0].ring = xhci_ring_alloc(xhci, 2, 1, TYPE_CTRL, flags); - if (!dev->eps[0].ring) - goto fail; - - /* Allocate pointers to the ring cache */ - dev->ring_cache = kzalloc( - sizeof(struct xhci_ring *)*XHCI_MAX_RINGS_CACHED, - flags); - if (!dev->ring_cache) - goto fail; - dev->num_rings_cached = 0; - - init_completion(&dev->cmd_completion); - INIT_LIST_HEAD(&dev->cmd_list); - dev->udev = udev; - - /* Point to output device context in dcbaa. */ - xhci->dcbaa->dev_context_ptrs[slot_id] = cpu_to_le64(dev->out_ctx->dma); - xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n", - slot_id, - &xhci->dcbaa->dev_context_ptrs[slot_id], - le64_to_cpu(xhci->dcbaa->dev_context_ptrs[slot_id])); - - return 1; -fail: - xhci_free_virt_device(xhci, slot_id); - return 0; -} - -void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci, - struct usb_device *udev) -{ - struct xhci_virt_device *virt_dev; - struct xhci_ep_ctx *ep0_ctx; - struct xhci_ring *ep_ring; - - virt_dev = xhci->devs[udev->slot_id]; - ep0_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, 0); - ep_ring = virt_dev->eps[0].ring; - /* - * FIXME we don't keep track of the dequeue pointer very well after a - * Set TR dequeue pointer, so we're setting the dequeue pointer of the - * host to our enqueue pointer. This should only be called after a - * configured device has reset, so all control transfers should have - * been completed or cancelled before the reset. - */ - ep0_ctx->deq = cpu_to_le64(xhci_trb_virt_to_dma(ep_ring->enq_seg, - ep_ring->enqueue) - | ep_ring->cycle_state); -} - -/* - * The xHCI roothub may have ports of differing speeds in any order in the port - * status registers. xhci->port_array provides an array of the port speed for - * each offset into the port status registers. - * - * The xHCI hardware wants to know the roothub port number that the USB device - * is attached to (or the roothub port its ancestor hub is attached to). All we - * know is the index of that port under either the USB 2.0 or the USB 3.0 - * roothub, but that doesn't give us the real index into the HW port status - * registers. Scan through the xHCI roothub port array, looking for the Nth - * entry of the correct port speed. Return the port number of that entry. - */ -static u32 xhci_find_real_port_number(struct xhci_hcd *xhci, - struct usb_device *udev) -{ - struct usb_device *top_dev; - unsigned int num_similar_speed_ports; - unsigned int faked_port_num; - int i; - - for (top_dev = udev; top_dev->parent && top_dev->parent->parent; - top_dev = top_dev->parent) - /* Found device below root hub */; - faked_port_num = top_dev->portnum; - for (i = 0, num_similar_speed_ports = 0; - i < HCS_MAX_PORTS(xhci->hcs_params1); i++) { - u8 port_speed = xhci->port_array[i]; - - /* - * Skip ports that don't have known speeds, or have duplicate - * Extended Capabilities port speed entries. - */ - if (port_speed == 0 || port_speed == DUPLICATE_ENTRY) - continue; - - /* - * USB 3.0 ports are always under a USB 3.0 hub. USB 2.0 and - * 1.1 ports are under the USB 2.0 hub. If the port speed - * matches the device speed, it's a similar speed port. - */ - if ((port_speed == 0x03) == (udev->speed == USB_SPEED_SUPER)) - num_similar_speed_ports++; - if (num_similar_speed_ports == faked_port_num) - /* Roothub ports are numbered from 1 to N */ - return i+1; - } - 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 xhci_slot_ctx *slot_ctx; - u32 port_num; - 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 = xhci_get_ep_ctx(xhci, dev->in_ctx, 0); - slot_ctx = xhci_get_slot_ctx(xhci, dev->in_ctx); - - /* 3) Only the control endpoint is valid - one endpoint context */ - slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1) | udev->route); - switch (udev->speed) { - case USB_SPEED_SUPER: - slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_SS); - break; - case USB_SPEED_HIGH: - slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_HS); - break; - case USB_SPEED_FULL: - slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_FS); - break; - case USB_SPEED_LOW: - slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_LS); - break; - case USB_SPEED_WIRELESS: - 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 */ - port_num = xhci_find_real_port_number(xhci, udev); - if (!port_num) - return -EINVAL; - slot_ctx->dev_info2 |= cpu_to_le32(ROOT_HUB_PORT(port_num)); - /* Set the port number in the virtual_device to the faked port number */ - for (top_dev = udev; top_dev->parent && top_dev->parent->parent; - top_dev = top_dev->parent) - /* Found device below root hub */; - dev->fake_port = top_dev->portnum; - dev->real_port = port_num; - xhci_dbg(xhci, "Set root hub portnum to %d\n", port_num); - xhci_dbg(xhci, "Set fake root hub portnum to %d\n", dev->fake_port); - - /* Find the right bandwidth table that this device will be a part of. - * If this is a full speed device attached directly to a root port (or a - * decendent of one), it counts as a primary bandwidth domain, not a - * secondary bandwidth domain under a TT. An xhci_tt_info structure - * will never be created for the HS root hub. - */ - if (!udev->tt || !udev->tt->hub->parent) { - dev->bw_table = &xhci->rh_bw[port_num - 1].bw_table; - } else { - struct xhci_root_port_bw_info *rh_bw; - struct xhci_tt_bw_info *tt_bw; - - rh_bw = &xhci->rh_bw[port_num - 1]; - /* Find the right TT. */ - list_for_each_entry(tt_bw, &rh_bw->tts, tt_list) { - if (tt_bw->slot_id != udev->tt->hub->slot_id) - continue; - - if (!dev->udev->tt->multi || - (udev->tt->multi && - tt_bw->ttport == dev->udev->ttport)) { - dev->bw_table = &tt_bw->bw_table; - dev->tt_info = tt_bw; - break; - } - } - if (!dev->tt_info) - xhci_warn(xhci, "WARN: Didn't find a matching TT\n"); - } - - /* Is this a LS/FS device under an external HS hub? */ - if (udev->tt && udev->tt->hub->parent) { - slot_ctx->tt_info = cpu_to_le32(udev->tt->hub->slot_id | - (udev->ttport << 8)); - if (udev->tt->multi) - slot_ctx->dev_info |= cpu_to_le32(DEV_MTT); - } - 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 = cpu_to_le32(EP_TYPE(CTRL_EP)); - /* - * XXX: Not sure about wireless USB devices. - */ - switch (udev->speed) { - case USB_SPEED_SUPER: - ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(512)); - break; - case USB_SPEED_HIGH: - /* USB core guesses at a 64-byte max packet first for FS devices */ - case USB_SPEED_FULL: - ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(64)); - break; - case USB_SPEED_LOW: - ep0_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(8)); - break; - case USB_SPEED_WIRELESS: - xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n"); - return -EINVAL; - break; - default: - /* New speed? */ - BUG(); - } - /* EP 0 can handle "burst" sizes of 1, so Max Burst Size field is 0 */ - ep0_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(0) | ERROR_COUNT(3)); - - ep0_ctx->deq = cpu_to_le64(dev->eps[0].ring->first_seg->dma | - dev->eps[0].ring->cycle_state); - - /* Steps 7 and 8 were done in xhci_alloc_virt_device() */ - - return 0; -} - -/* - * Convert interval expressed as 2^(bInterval - 1) == interval into - * straight exponent value 2^n == interval. - * - */ -static unsigned int xhci_parse_exponent_interval(struct usb_device *udev, - struct usb_host_endpoint *ep) -{ - unsigned int interval; - - interval = clamp_val(ep->desc.bInterval, 1, 16) - 1; - if (interval != ep->desc.bInterval - 1) - dev_warn(&udev->dev, - "ep %#x - rounding interval to %d %sframes\n", - ep->desc.bEndpointAddress, - 1 << interval, - udev->speed == USB_SPEED_FULL ? "" : "micro"); - - if (udev->speed == USB_SPEED_FULL) { - /* - * Full speed isoc endpoints specify interval in frames, - * not microframes. We are using microframes everywhere, - * so adjust accordingly. - */ - interval += 3; /* 1 frame = 2^3 uframes */ - } - - return interval; -} - -/* - * Convert bInterval expressed in microframes (in 1-255 range) to exponent of - * microframes, rounded down to nearest power of 2. - */ -static unsigned int xhci_microframes_to_exponent(struct usb_device *udev, - struct usb_host_endpoint *ep, unsigned int desc_interval, - unsigned int min_exponent, unsigned int max_exponent) -{ - unsigned int interval; - - interval = fls(desc_interval) - 1; - interval = clamp_val(interval, min_exponent, max_exponent); - if ((1 << interval) != desc_interval) - dev_warn(&udev->dev, - "ep %#x - rounding interval to %d microframes, ep desc says %d microframes\n", - ep->desc.bEndpointAddress, - 1 << interval, - desc_interval); - - return interval; -} - -static unsigned int xhci_parse_microframe_interval(struct usb_device *udev, - struct usb_host_endpoint *ep) -{ - return xhci_microframes_to_exponent(udev, ep, - ep->desc.bInterval, 0, 15); -} - - -static unsigned int xhci_parse_frame_interval(struct usb_device *udev, - struct usb_host_endpoint *ep) -{ - return xhci_microframes_to_exponent(udev, ep, - ep->desc.bInterval * 8, 3, 10); -} - -/* 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 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 = xhci_parse_microframe_interval(udev, ep); - break; - } - /* 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)) { - interval = xhci_parse_exponent_interval(udev, ep); - } - break; - - case USB_SPEED_FULL: - if (usb_endpoint_xfer_isoc(&ep->desc)) { - interval = xhci_parse_exponent_interval(udev, ep); - break; - } - /* - * Fall through for interrupt endpoint interval decoding - * since it uses the same rules as low speed interrupt - * endpoints. - */ - - case USB_SPEED_LOW: - if (usb_endpoint_xfer_int(&ep->desc) || - usb_endpoint_xfer_isoc(&ep->desc)) { - - interval = xhci_parse_frame_interval(udev, ep); - } - break; - - default: - BUG(); - } - return EP_INTERVAL(interval); -} - -/* The "Mult" field in the endpoint context is only set for SuperSpeed isoc eps. - * High speed endpoint descriptors can define "the number of additional - * transaction opportunities per microframe", but that goes in the Max Burst - * endpoint context field. - */ -static u32 xhci_get_endpoint_mult(struct usb_device *udev, - struct usb_host_endpoint *ep) -{ - if (udev->speed != USB_SPEED_SUPER || - !usb_endpoint_xfer_isoc(&ep->desc)) - return 0; - return ep->ss_ep_comp.bmAttributes; -} - -static 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; -} - -/* Return the maximum endpoint service interval time (ESIT) payload. - * Basically, this is the maxpacket size, multiplied by the burst size - * and mult size. - */ -static u32 xhci_get_max_esit_payload(struct xhci_hcd *xhci, - struct usb_device *udev, - struct usb_host_endpoint *ep) -{ - int max_burst; - int max_packet; - - /* Only applies for interrupt or isochronous endpoints */ - if (usb_endpoint_xfer_control(&ep->desc) || - usb_endpoint_xfer_bulk(&ep->desc)) - return 0; - - if (udev->speed == USB_SPEED_SUPER) - return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval); - - max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc)); - max_burst = (usb_endpoint_maxp(&ep->desc) & 0x1800) >> 11; - /* A 0 in max burst means 1 transfer per ESIT */ - return max_packet * (max_burst + 1); -} - -/* Set up an endpoint with one ring segment. Do not allocate stream rings. - * Drivers will have to call usb_alloc_streams() to do that. - */ -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; - enum xhci_ring_type type; - u32 max_esit_payload; - - ep_index = xhci_get_endpoint_index(&ep->desc); - ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index); - - type = usb_endpoint_type(&ep->desc); - /* Set up the endpoint ring */ - virt_dev->eps[ep_index].new_ring = - xhci_ring_alloc(xhci, 2, 1, type, mem_flags); - if (!virt_dev->eps[ep_index].new_ring) { - /* Attempt to use the ring cache */ - if (virt_dev->num_rings_cached == 0) - return -ENOMEM; - virt_dev->eps[ep_index].new_ring = - virt_dev->ring_cache[virt_dev->num_rings_cached]; - virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL; - virt_dev->num_rings_cached--; - xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring, - 1, type); - } - virt_dev->eps[ep_index].skip = false; - ep_ring = virt_dev->eps[ep_index].new_ring; - ep_ctx->deq = cpu_to_le64(ep_ring->first_seg->dma | ep_ring->cycle_state); - - ep_ctx->ep_info = cpu_to_le32(xhci_get_endpoint_interval(udev, ep) - | EP_MULT(xhci_get_endpoint_mult(udev, ep))); - - /* FIXME dig Mult and streams info out of ep companion desc */ - - /* Allow 3 retries for everything but isoc; - * CErr shall be set to 0 for Isoch endpoints. - */ - if (!usb_endpoint_xfer_isoc(&ep->desc)) - ep_ctx->ep_info2 = cpu_to_le32(ERROR_COUNT(3)); - else - ep_ctx->ep_info2 = cpu_to_le32(ERROR_COUNT(0)); - - ep_ctx->ep_info2 |= cpu_to_le32(xhci_get_endpoint_type(udev, ep)); - - /* Set the max packet size and max burst */ - switch (udev->speed) { - case USB_SPEED_SUPER: - max_packet = usb_endpoint_maxp(&ep->desc); - ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet)); - /* dig out max burst from ep companion desc */ - max_packet = ep->ss_ep_comp.bMaxBurst; - ep_ctx->ep_info2 |= cpu_to_le32(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 = (usb_endpoint_maxp(&ep->desc) - & 0x1800) >> 11; - ep_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(max_burst)); - } - /* Fall through */ - case USB_SPEED_FULL: - case USB_SPEED_LOW: - max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc)); - ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet)); - break; - default: - BUG(); - } - max_esit_payload = xhci_get_max_esit_payload(xhci, udev, ep); - ep_ctx->tx_info = cpu_to_le32(MAX_ESIT_PAYLOAD_FOR_EP(max_esit_payload)); - - /* - * XXX no idea how to calculate the average TRB buffer length for bulk - * endpoints, as the driver gives us no clue how big each scatter gather - * list entry (or buffer) is going to be. - * - * For isochronous and interrupt endpoints, we set it to the max - * available, until we have new API in the USB core to allow drivers to - * declare how much bandwidth they actually need. - * - * Normally, it would be calculated by taking the total of the buffer - * lengths in the TD and then dividing by the number of TRBs in a TD, - * including link TRBs, No-op TRBs, and Event data TRBs. Since we don't - * use Event Data TRBs, and we don't chain in a link TRB on short - * transfers, we're basically dividing by 1. - * - * xHCI 1.0 specification indicates that the Average TRB Length should - * be set to 8 for control endpoints. - */ - if (usb_endpoint_xfer_control(&ep->desc) && xhci->hci_version == 0x100) - ep_ctx->tx_info |= cpu_to_le32(AVG_TRB_LENGTH_FOR_EP(8)); - else - ep_ctx->tx_info |= - cpu_to_le32(AVG_TRB_LENGTH_FOR_EP(max_esit_payload)); - - /* 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 = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index); - - ep_ctx->ep_info = 0; - ep_ctx->ep_info2 = 0; - ep_ctx->deq = 0; - ep_ctx->tx_info = 0; - /* Don't free the endpoint ring until the set interface or configuration - * request succeeds. - */ -} - -void xhci_clear_endpoint_bw_info(struct xhci_bw_info *bw_info) -{ - bw_info->ep_interval = 0; - bw_info->mult = 0; - bw_info->num_packets = 0; - bw_info->max_packet_size = 0; - bw_info->type = 0; - bw_info->max_esit_payload = 0; -} - -void xhci_update_bw_info(struct xhci_hcd *xhci, - struct xhci_container_ctx *in_ctx, - struct xhci_input_control_ctx *ctrl_ctx, - struct xhci_virt_device *virt_dev) -{ - struct xhci_bw_info *bw_info; - struct xhci_ep_ctx *ep_ctx; - unsigned int ep_type; - int i; - - for (i = 1; i < 31; ++i) { - bw_info = &virt_dev->eps[i].bw_info; - - /* We can't tell what endpoint type is being dropped, but - * unconditionally clearing the bandwidth info for non-periodic - * endpoints should be harmless because the info will never be - * set in the first place. - */ - if (!EP_IS_ADDED(ctrl_ctx, i) && EP_IS_DROPPED(ctrl_ctx, i)) { - /* Dropped endpoint */ - xhci_clear_endpoint_bw_info(bw_info); - continue; - } - - if (EP_IS_ADDED(ctrl_ctx, i)) { - ep_ctx = xhci_get_ep_ctx(xhci, in_ctx, i); - ep_type = CTX_TO_EP_TYPE(le32_to_cpu(ep_ctx->ep_info2)); - - /* Ignore non-periodic endpoints */ - if (ep_type != ISOC_OUT_EP && ep_type != INT_OUT_EP && - ep_type != ISOC_IN_EP && - ep_type != INT_IN_EP) - continue; - - /* Added or changed endpoint */ - bw_info->ep_interval = CTX_TO_EP_INTERVAL( - le32_to_cpu(ep_ctx->ep_info)); - /* Number of packets and mult are zero-based in the - * input context, but we want one-based for the - * interval table. - */ - bw_info->mult = CTX_TO_EP_MULT( - le32_to_cpu(ep_ctx->ep_info)) + 1; - bw_info->num_packets = CTX_TO_MAX_BURST( - le32_to_cpu(ep_ctx->ep_info2)) + 1; - bw_info->max_packet_size = MAX_PACKET_DECODED( - le32_to_cpu(ep_ctx->ep_info2)); - bw_info->type = ep_type; - bw_info->max_esit_payload = CTX_TO_MAX_ESIT_PAYLOAD( - le32_to_cpu(ep_ctx->tx_info)); - } - } -} - -/* Copy output xhci_ep_ctx to the input xhci_ep_ctx copy. - * Useful when you want to change one particular aspect of the endpoint and then - * issue a configure endpoint command. - */ -void xhci_endpoint_copy(struct xhci_hcd *xhci, - struct xhci_container_ctx *in_ctx, - struct xhci_container_ctx *out_ctx, - unsigned int ep_index) -{ - struct xhci_ep_ctx *out_ep_ctx; - struct xhci_ep_ctx *in_ep_ctx; - - out_ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index); - in_ep_ctx = xhci_get_ep_ctx(xhci, in_ctx, ep_index); - - in_ep_ctx->ep_info = out_ep_ctx->ep_info; - in_ep_ctx->ep_info2 = out_ep_ctx->ep_info2; - in_ep_ctx->deq = out_ep_ctx->deq; - in_ep_ctx->tx_info = out_ep_ctx->tx_info; -} - -/* Copy output xhci_slot_ctx to the input xhci_slot_ctx. - * Useful when you want to change one particular aspect of the endpoint and then - * issue a configure endpoint command. Only the context entries field matters, - * but we'll copy the whole thing anyway. - */ -void xhci_slot_copy(struct xhci_hcd *xhci, - struct xhci_container_ctx *in_ctx, - struct xhci_container_ctx *out_ctx) -{ - struct xhci_slot_ctx *in_slot_ctx; - struct xhci_slot_ctx *out_slot_ctx; - - in_slot_ctx = xhci_get_slot_ctx(xhci, in_ctx); - out_slot_ctx = xhci_get_slot_ctx(xhci, out_ctx); - - in_slot_ctx->dev_info = out_slot_ctx->dev_info; - in_slot_ctx->dev_info2 = out_slot_ctx->dev_info2; - in_slot_ctx->tt_info = out_slot_ctx->tt_info; - in_slot_ctx->dev_state = out_slot_ctx->dev_state; -} - -/* Set up the scratchpad buffer array and scratchpad buffers, if needed. */ -static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags) -{ - int i; - struct device *dev = xhci_to_hcd(xhci)->self.controller; - int num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2); - - xhci_dbg(xhci, "Allocating %d scratchpad buffers\n", num_sp); - - if (!num_sp) - return 0; - - xhci->scratchpad = kzalloc(sizeof(*xhci->scratchpad), flags); - if (!xhci->scratchpad) - goto fail_sp; - - xhci->scratchpad->sp_array = dma_alloc_coherent(dev, - num_sp * sizeof(u64), - &xhci->scratchpad->sp_dma, flags); - if (!xhci->scratchpad->sp_array) - goto fail_sp2; - - xhci->scratchpad->sp_buffers = kzalloc(sizeof(void *) * num_sp, flags); - if (!xhci->scratchpad->sp_buffers) - goto fail_sp3; - - xhci->scratchpad->sp_dma_buffers = - kzalloc(sizeof(dma_addr_t) * num_sp, flags); - - if (!xhci->scratchpad->sp_dma_buffers) - goto fail_sp4; - - xhci->dcbaa->dev_context_ptrs[0] = cpu_to_le64(xhci->scratchpad->sp_dma); - for (i = 0; i < num_sp; i++) { - dma_addr_t dma; - void *buf = dma_alloc_coherent(dev, xhci->page_size, &dma, - flags); - if (!buf) - goto fail_sp5; - - xhci->scratchpad->sp_array[i] = dma; - xhci->scratchpad->sp_buffers[i] = buf; - xhci->scratchpad->sp_dma_buffers[i] = dma; - } - - return 0; - - fail_sp5: - for (i = i - 1; i >= 0; i--) { - dma_free_coherent(dev, xhci->page_size, - xhci->scratchpad->sp_buffers[i], - xhci->scratchpad->sp_dma_buffers[i]); - } - kfree(xhci->scratchpad->sp_dma_buffers); - - fail_sp4: - kfree(xhci->scratchpad->sp_buffers); - - fail_sp3: - dma_free_coherent(dev, num_sp * sizeof(u64), - xhci->scratchpad->sp_array, - xhci->scratchpad->sp_dma); - - fail_sp2: - kfree(xhci->scratchpad); - xhci->scratchpad = NULL; - - fail_sp: - return -ENOMEM; -} - -static void scratchpad_free(struct xhci_hcd *xhci) -{ - int num_sp; - int i; - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); - - if (!xhci->scratchpad) - return; - - num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2); - - for (i = 0; i < num_sp; i++) { - dma_free_coherent(&pdev->dev, xhci->page_size, - xhci->scratchpad->sp_buffers[i], - xhci->scratchpad->sp_dma_buffers[i]); - } - kfree(xhci->scratchpad->sp_dma_buffers); - kfree(xhci->scratchpad->sp_buffers); - dma_free_coherent(&pdev->dev, num_sp * sizeof(u64), - xhci->scratchpad->sp_array, - xhci->scratchpad->sp_dma); - kfree(xhci->scratchpad); - xhci->scratchpad = NULL; -} - -struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci, - bool allocate_in_ctx, bool allocate_completion, - gfp_t mem_flags) -{ - struct xhci_command *command; - - command = kzalloc(sizeof(*command), mem_flags); - if (!command) - return NULL; - - if (allocate_in_ctx) { - command->in_ctx = - xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_INPUT, - mem_flags); - if (!command->in_ctx) { - kfree(command); - return NULL; - } - } - - if (allocate_completion) { - command->completion = - kzalloc(sizeof(struct completion), mem_flags); - if (!command->completion) { - xhci_free_container_ctx(xhci, command->in_ctx); - kfree(command); - return NULL; - } - init_completion(command->completion); - } - - command->status = 0; - INIT_LIST_HEAD(&command->cmd_list); - return command; -} - -void xhci_urb_free_priv(struct xhci_hcd *xhci, struct urb_priv *urb_priv) -{ - if (urb_priv) { - kfree(urb_priv->td[0]); - kfree(urb_priv); - } -} - -void xhci_free_command(struct xhci_hcd *xhci, - struct xhci_command *command) -{ - xhci_free_container_ctx(xhci, - command->in_ctx); - kfree(command->completion); - kfree(command); -} - -void xhci_mem_cleanup(struct xhci_hcd *xhci) -{ - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); - struct dev_info *dev_info, *next; - unsigned long flags; - int size; - int i, j, num_ports; - - /* Free the Event Ring Segment Table and the actual Event Ring */ - size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries); - if (xhci->erst.entries) - dma_free_coherent(&pdev->dev, 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->cmd_ring_reserved_trbs = 0; - 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"); - - if (xhci->small_streams_pool) - dma_pool_destroy(xhci->small_streams_pool); - xhci->small_streams_pool = NULL; - xhci_dbg(xhci, "Freed small stream array pool\n"); - - if (xhci->medium_streams_pool) - dma_pool_destroy(xhci->medium_streams_pool); - xhci->medium_streams_pool = NULL; - xhci_dbg(xhci, "Freed medium stream array pool\n"); - - if (xhci->dcbaa) - dma_free_coherent(&pdev->dev, sizeof(*xhci->dcbaa), - xhci->dcbaa, xhci->dcbaa->dma); - xhci->dcbaa = NULL; - - scratchpad_free(xhci); - - spin_lock_irqsave(&xhci->lock, flags); - list_for_each_entry_safe(dev_info, next, &xhci->lpm_failed_devs, list) { - list_del(&dev_info->list); - kfree(dev_info); - } - spin_unlock_irqrestore(&xhci->lock, flags); - - num_ports = HCS_MAX_PORTS(xhci->hcs_params1); - for (i = 0; i < num_ports; i++) { - struct xhci_interval_bw_table *bwt = &xhci->rh_bw[i].bw_table; - for (j = 0; j < XHCI_MAX_INTERVAL; j++) { - struct list_head *ep = &bwt->interval_bw[j].endpoints; - while (!list_empty(ep)) - list_del_init(ep->next); - } - } - - for (i = 0; i < num_ports; i++) { - struct xhci_tt_bw_info *tt, *n; - list_for_each_entry_safe(tt, n, &xhci->rh_bw[i].tts, tt_list) { - list_del(&tt->tt_list); - kfree(tt); - } - } - - xhci->num_usb2_ports = 0; - xhci->num_usb3_ports = 0; - xhci->num_active_eps = 0; - kfree(xhci->usb2_ports); - kfree(xhci->usb3_ports); - kfree(xhci->port_array); - kfree(xhci->rh_bw); - - xhci->page_size = 0; - xhci->page_shift = 0; - xhci->bus_state[0].bus_suspended = 0; - xhci->bus_state[1].bus_suspended = 0; -} - -static int xhci_test_trb_in_td(struct xhci_hcd *xhci, - struct xhci_segment *input_seg, - union xhci_trb *start_trb, - union xhci_trb *end_trb, - dma_addr_t input_dma, - struct xhci_segment *result_seg, - char *test_name, int test_number) -{ - unsigned long long start_dma; - unsigned long long end_dma; - struct xhci_segment *seg; - - start_dma = xhci_trb_virt_to_dma(input_seg, start_trb); - end_dma = xhci_trb_virt_to_dma(input_seg, end_trb); - - seg = trb_in_td(input_seg, start_trb, end_trb, input_dma); - if (seg != result_seg) { - xhci_warn(xhci, "WARN: %s TRB math test %d failed!\n", - test_name, test_number); - xhci_warn(xhci, "Tested TRB math w/ seg %p and " - "input DMA 0x%llx\n", - input_seg, - (unsigned long long) input_dma); - xhci_warn(xhci, "starting TRB %p (0x%llx DMA), " - "ending TRB %p (0x%llx DMA)\n", - start_trb, start_dma, - end_trb, end_dma); - xhci_warn(xhci, "Expected seg %p, got seg %p\n", - result_seg, seg); - return -1; - } - return 0; -} - -/* TRB math checks for xhci_trb_in_td(), using the command and event rings. */ -static int xhci_check_trb_in_td_math(struct xhci_hcd *xhci, gfp_t mem_flags) -{ - struct { - dma_addr_t input_dma; - struct xhci_segment *result_seg; - } simple_test_vector [] = { - /* A zeroed DMA field should fail */ - { 0, NULL }, - /* One TRB before the ring start should fail */ - { xhci->event_ring->first_seg->dma - 16, NULL }, - /* One byte before the ring start should fail */ - { xhci->event_ring->first_seg->dma - 1, NULL }, - /* Starting TRB should succeed */ - { xhci->event_ring->first_seg->dma, xhci->event_ring->first_seg }, - /* Ending TRB should succeed */ - { xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT - 1)*16, - xhci->event_ring->first_seg }, - /* One byte after the ring end should fail */ - { xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT - 1)*16 + 1, NULL }, - /* One TRB after the ring end should fail */ - { xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT)*16, NULL }, - /* An address of all ones should fail */ - { (dma_addr_t) (~0), NULL }, - }; - struct { - struct xhci_segment *input_seg; - union xhci_trb *start_trb; - union xhci_trb *end_trb; - dma_addr_t input_dma; - struct xhci_segment *result_seg; - } complex_test_vector [] = { - /* Test feeding a valid DMA address from a different ring */ - { .input_seg = xhci->event_ring->first_seg, - .start_trb = xhci->event_ring->first_seg->trbs, - .end_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1], - .input_dma = xhci->cmd_ring->first_seg->dma, - .result_seg = NULL, - }, - /* Test feeding a valid end TRB from a different ring */ - { .input_seg = xhci->event_ring->first_seg, - .start_trb = xhci->event_ring->first_seg->trbs, - .end_trb = &xhci->cmd_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1], - .input_dma = xhci->cmd_ring->first_seg->dma, - .result_seg = NULL, - }, - /* Test feeding a valid start and end TRB from a different ring */ - { .input_seg = xhci->event_ring->first_seg, - .start_trb = xhci->cmd_ring->first_seg->trbs, - .end_trb = &xhci->cmd_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1], - .input_dma = xhci->cmd_ring->first_seg->dma, - .result_seg = NULL, - }, - /* TRB in this ring, but after this TD */ - { .input_seg = xhci->event_ring->first_seg, - .start_trb = &xhci->event_ring->first_seg->trbs[0], - .end_trb = &xhci->event_ring->first_seg->trbs[3], - .input_dma = xhci->event_ring->first_seg->dma + 4*16, - .result_seg = NULL, - }, - /* TRB in this ring, but before this TD */ - { .input_seg = xhci->event_ring->first_seg, - .start_trb = &xhci->event_ring->first_seg->trbs[3], - .end_trb = &xhci->event_ring->first_seg->trbs[6], - .input_dma = xhci->event_ring->first_seg->dma + 2*16, - .result_seg = NULL, - }, - /* TRB in this ring, but after this wrapped TD */ - { .input_seg = xhci->event_ring->first_seg, - .start_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 3], - .end_trb = &xhci->event_ring->first_seg->trbs[1], - .input_dma = xhci->event_ring->first_seg->dma + 2*16, - .result_seg = NULL, - }, - /* TRB in this ring, but before this wrapped TD */ - { .input_seg = xhci->event_ring->first_seg, - .start_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 3], - .end_trb = &xhci->event_ring->first_seg->trbs[1], - .input_dma = xhci->event_ring->first_seg->dma + (TRBS_PER_SEGMENT - 4)*16, - .result_seg = NULL, - }, - /* TRB not in this ring, and we have a wrapped TD */ - { .input_seg = xhci->event_ring->first_seg, - .start_trb = &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 3], - .end_trb = &xhci->event_ring->first_seg->trbs[1], - .input_dma = xhci->cmd_ring->first_seg->dma + 2*16, - .result_seg = NULL, - }, - }; - - unsigned int num_tests; - int i, ret; - - num_tests = ARRAY_SIZE(simple_test_vector); - for (i = 0; i < num_tests; i++) { - ret = xhci_test_trb_in_td(xhci, - xhci->event_ring->first_seg, - xhci->event_ring->first_seg->trbs, - &xhci->event_ring->first_seg->trbs[TRBS_PER_SEGMENT - 1], - simple_test_vector[i].input_dma, - simple_test_vector[i].result_seg, - "Simple", i); - if (ret < 0) - return ret; - } - - num_tests = ARRAY_SIZE(complex_test_vector); - for (i = 0; i < num_tests; i++) { - ret = xhci_test_trb_in_td(xhci, - complex_test_vector[i].input_seg, - complex_test_vector[i].start_trb, - complex_test_vector[i].end_trb, - complex_test_vector[i].input_dma, - complex_test_vector[i].result_seg, - "Complex", i); - if (ret < 0) - return ret; - } - xhci_dbg(xhci, "TRB math tests passed.\n"); - return 0; -} - -static void xhci_set_hc_event_deq(struct xhci_hcd *xhci) -{ - u64 temp; - dma_addr_t deq; - - deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, - xhci->event_ring->dequeue); - if (deq == 0 && !in_interrupt()) - xhci_warn(xhci, "WARN something wrong with SW event ring " - "dequeue ptr.\n"); - /* Update HC event ring dequeue pointer */ - temp = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); - temp &= ERST_PTR_MASK; - /* Don't clear the EHB bit (which is RW1C) because - * there might be more events to service. - */ - temp &= ~ERST_EHB; - xhci_dbg(xhci, "// Write event ring dequeue pointer, " - "preserving EHB bit\n"); - xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp, - &xhci->ir_set->erst_dequeue); -} - -static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, - __le32 __iomem *addr, u8 major_revision) -{ - u32 temp, port_offset, port_count; - int i; - - if (major_revision > 0x03) { - xhci_warn(xhci, "Ignoring unknown port speed, " - "Ext Cap %p, revision = 0x%x\n", - addr, major_revision); - /* Ignoring port protocol we can't understand. FIXME */ - return; - } - - /* Port offset and count in the third dword, see section 7.2 */ - temp = xhci_readl(xhci, addr + 2); - port_offset = XHCI_EXT_PORT_OFF(temp); - port_count = XHCI_EXT_PORT_COUNT(temp); - xhci_dbg(xhci, "Ext Cap %p, port offset = %u, " - "count = %u, revision = 0x%x\n", - addr, port_offset, port_count, major_revision); - /* Port count includes the current port offset */ - if (port_offset == 0 || (port_offset + port_count - 1) > num_ports) - /* WTF? "Valid values are ‘1’ to MaxPorts" */ - return; - - /* Check the host's USB2 LPM capability */ - if ((xhci->hci_version == 0x96) && (major_revision != 0x03) && - (temp & XHCI_L1C)) { - xhci_dbg(xhci, "xHCI 0.96: support USB2 software lpm\n"); - xhci->sw_lpm_support = 1; - } - - if ((xhci->hci_version >= 0x100) && (major_revision != 0x03)) { - xhci_dbg(xhci, "xHCI 1.0: support USB2 software lpm\n"); - xhci->sw_lpm_support = 1; - if (temp & XHCI_HLC) { - xhci_dbg(xhci, "xHCI 1.0: support USB2 hardware lpm\n"); - xhci->hw_lpm_support = 1; - } - } - - port_offset--; - for (i = port_offset; i < (port_offset + port_count); i++) { - /* Duplicate entry. Ignore the port if the revisions differ. */ - if (xhci->port_array[i] != 0) { - xhci_warn(xhci, "Duplicate port entry, Ext Cap %p," - " port %u\n", addr, i); - xhci_warn(xhci, "Port was marked as USB %u, " - "duplicated as USB %u\n", - xhci->port_array[i], major_revision); - /* Only adjust the roothub port counts if we haven't - * found a similar duplicate. - */ - if (xhci->port_array[i] != major_revision && - xhci->port_array[i] != DUPLICATE_ENTRY) { - if (xhci->port_array[i] == 0x03) - xhci->num_usb3_ports--; - else - xhci->num_usb2_ports--; - xhci->port_array[i] = DUPLICATE_ENTRY; - } - /* FIXME: Should we disable the port? */ - continue; - } - xhci->port_array[i] = major_revision; - if (major_revision == 0x03) - xhci->num_usb3_ports++; - else - xhci->num_usb2_ports++; - } - /* FIXME: Should we disable ports not in the Extended Capabilities? */ -} - -/* - * Scan the Extended Capabilities for the "Supported Protocol Capabilities" that - * specify what speeds each port is supposed to be. We can't count on the port - * speed bits in the PORTSC register being correct until a device is connected, - * but we need to set up the two fake roothubs with the correct number of USB - * 3.0 and USB 2.0 ports at host controller initialization time. - */ -static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) -{ - __le32 __iomem *addr; - u32 offset; - unsigned int num_ports; - int i, j, port_index; - - addr = &xhci->cap_regs->hcc_params; - offset = XHCI_HCC_EXT_CAPS(xhci_readl(xhci, addr)); - if (offset == 0) { - xhci_err(xhci, "No Extended Capability registers, " - "unable to set up roothub.\n"); - return -ENODEV; - } - - num_ports = HCS_MAX_PORTS(xhci->hcs_params1); - xhci->port_array = kzalloc(sizeof(*xhci->port_array)*num_ports, flags); - if (!xhci->port_array) - return -ENOMEM; - - xhci->rh_bw = kzalloc(sizeof(*xhci->rh_bw)*num_ports, flags); - if (!xhci->rh_bw) - return -ENOMEM; - for (i = 0; i < num_ports; i++) { - struct xhci_interval_bw_table *bw_table; - - INIT_LIST_HEAD(&xhci->rh_bw[i].tts); - bw_table = &xhci->rh_bw[i].bw_table; - for (j = 0; j < XHCI_MAX_INTERVAL; j++) - INIT_LIST_HEAD(&bw_table->interval_bw[j].endpoints); - } - - /* - * For whatever reason, the first capability offset is from the - * capability register base, not from the HCCPARAMS register. - * See section 5.3.6 for offset calculation. - */ - addr = &xhci->cap_regs->hc_capbase + offset; - while (1) { - u32 cap_id; - - cap_id = xhci_readl(xhci, addr); - if (XHCI_EXT_CAPS_ID(cap_id) == XHCI_EXT_CAPS_PROTOCOL) - xhci_add_in_port(xhci, num_ports, addr, - (u8) XHCI_EXT_PORT_MAJOR(cap_id)); - offset = XHCI_EXT_CAPS_NEXT(cap_id); - if (!offset || (xhci->num_usb2_ports + xhci->num_usb3_ports) - == num_ports) - break; - /* - * Once you're into the Extended Capabilities, the offset is - * always relative to the register holding the offset. - */ - addr += offset; - } - - if (xhci->num_usb2_ports == 0 && xhci->num_usb3_ports == 0) { - xhci_warn(xhci, "No ports on the roothubs?\n"); - return -ENODEV; - } - xhci_dbg(xhci, "Found %u USB 2.0 ports and %u USB 3.0 ports.\n", - xhci->num_usb2_ports, xhci->num_usb3_ports); - - /* Place limits on the number of roothub ports so that the hub - * descriptors aren't longer than the USB core will allocate. - */ - if (xhci->num_usb3_ports > 15) { - xhci_dbg(xhci, "Limiting USB 3.0 roothub ports to 15.\n"); - xhci->num_usb3_ports = 15; - } - if (xhci->num_usb2_ports > USB_MAXCHILDREN) { - xhci_dbg(xhci, "Limiting USB 2.0 roothub ports to %u.\n", - USB_MAXCHILDREN); - xhci->num_usb2_ports = USB_MAXCHILDREN; - } - - /* - * Note we could have all USB 3.0 ports, or all USB 2.0 ports. - * Not sure how the USB core will handle a hub with no ports... - */ - if (xhci->num_usb2_ports) { - xhci->usb2_ports = kmalloc(sizeof(*xhci->usb2_ports)* - xhci->num_usb2_ports, flags); - if (!xhci->usb2_ports) - return -ENOMEM; - - port_index = 0; - for (i = 0; i < num_ports; i++) { - if (xhci->port_array[i] == 0x03 || - xhci->port_array[i] == 0 || - xhci->port_array[i] == DUPLICATE_ENTRY) - continue; - - xhci->usb2_ports[port_index] = - &xhci->op_regs->port_status_base + - NUM_PORT_REGS*i; - xhci_dbg(xhci, "USB 2.0 port at index %u, " - "addr = %p\n", i, - xhci->usb2_ports[port_index]); - port_index++; - if (port_index == xhci->num_usb2_ports) - break; - } - } - if (xhci->num_usb3_ports) { - xhci->usb3_ports = kmalloc(sizeof(*xhci->usb3_ports)* - xhci->num_usb3_ports, flags); - if (!xhci->usb3_ports) - return -ENOMEM; - - port_index = 0; - for (i = 0; i < num_ports; i++) - if (xhci->port_array[i] == 0x03) { - xhci->usb3_ports[port_index] = - &xhci->op_regs->port_status_base + - NUM_PORT_REGS*i; - xhci_dbg(xhci, "USB 3.0 port at index %u, " - "addr = %p\n", i, - xhci->usb3_ports[port_index]); - port_index++; - if (port_index == xhci->num_usb3_ports) - break; - } - } - return 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; - u64 val_64; - struct xhci_segment *seg; - u32 page_size, temp; - 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 = dma_alloc_coherent(dev, sizeof(*xhci->dcbaa), &dma, - GFP_KERNEL); - 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_write_64(xhci, dma, &xhci->op_regs->dcbaa_ptr); - - /* - * 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 */ - xhci->device_pool = dma_pool_create("xHCI input/output contexts", dev, - 2112, 64, xhci->page_size); - if (!xhci->segment_pool || !xhci->device_pool) - goto fail; - - /* Linear stream context arrays don't have any boundary restrictions, - * and only need to be 16-byte aligned. - */ - xhci->small_streams_pool = - dma_pool_create("xHCI 256 byte stream ctx arrays", - dev, SMALL_STREAM_ARRAY_SIZE, 16, 0); - xhci->medium_streams_pool = - dma_pool_create("xHCI 1KB stream ctx arrays", - dev, MEDIUM_STREAM_ARRAY_SIZE, 16, 0); - /* Any stream context array bigger than MEDIUM_STREAM_ARRAY_SIZE - * will be allocated with dma_alloc_coherent() - */ - - if (!xhci->small_streams_pool || !xhci->medium_streams_pool) - goto fail; - - /* Set up the command ring to have one segments for now. */ - xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, 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_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); - val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) | - (xhci->cmd_ring->first_seg->dma & (u64) ~CMD_RING_RSVD_BITS) | - xhci->cmd_ring->cycle_state; - xhci_dbg(xhci, "// Setting command ring address to 0x%x\n", val); - xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring); - 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 __iomem *) xhci->cap_regs + val; - xhci_dbg_regs(xhci); - xhci_print_run_regs(xhci); - /* Set ir_set to interrupt register set 0 */ - xhci->ir_set = &xhci->run_regs->ir_set[0]; - - /* - * 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, 1, TYPE_EVENT, - flags); - if (!xhci->event_ring) - goto fail; - if (xhci_check_trb_in_td_math(xhci, flags) < 0) - goto fail; - - xhci->erst.entries = dma_alloc_coherent(dev, - sizeof(struct xhci_erst_entry) * ERST_NUM_SEGS, &dma, - GFP_KERNEL); - 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 = cpu_to_le64(seg->dma); - entry->seg_size = cpu_to_le32(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_64 = xhci_read_64(xhci, &xhci->ir_set->erst_base); - val_64 &= ERST_PTR_MASK; - val_64 |= (xhci->erst.erst_dma_addr & (u64) ~ERST_PTR_MASK); - xhci_write_64(xhci, val_64, &xhci->ir_set->erst_base); - - /* 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, 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] = NULL; - for (i = 0; i < USB_MAXCHILDREN; ++i) { - xhci->bus_state[0].resume_done[i] = 0; - xhci->bus_state[1].resume_done[i] = 0; - } - - if (scratchpad_alloc(xhci, flags)) - goto fail; - if (xhci_setup_port_arrays(xhci, flags)) - goto fail; - - INIT_LIST_HEAD(&xhci->lpm_failed_devs); - - /* Enable USB 3.0 device notifications for function remote wake, which - * is necessary for allowing USB 3.0 devices to do remote wakeup from - * U3 (device suspend). - */ - temp = xhci_readl(xhci, &xhci->op_regs->dev_notification); - temp &= ~DEV_NOTE_MASK; - temp |= DEV_NOTE_FWAKE; - xhci_writel(xhci, temp, &xhci->op_regs->dev_notification); - - return 0; - -fail: - xhci_warn(xhci, "Couldn't initialize memory\n"); - xhci_halt(xhci); - xhci_reset(xhci); - xhci_mem_cleanup(xhci); - return -ENOMEM; -} diff --git a/ANDROID_3.4.5/drivers/usb/host/xhci-pci.c b/ANDROID_3.4.5/drivers/usb/host/xhci-pci.c deleted file mode 100644 index 19e89216..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/xhci-pci.c +++ /dev/null @@ -1,335 +0,0 @@ -/* - * 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 -#include -#include - -#include "xhci.h" - -/* Device for a quirk */ -#define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73 -#define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000 - -#define PCI_VENDOR_ID_ETRON 0x1b6f -#define PCI_DEVICE_ID_ASROCK_P67 0x7023 - -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; -} - -static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) -{ - struct pci_dev *pdev = to_pci_dev(dev); - - /* Look for vendor-specific quirks */ - if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC && - pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK) { - if (pdev->revision == 0x0) { - xhci->quirks |= XHCI_RESET_EP_QUIRK; - xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure" - " endpoint cmd after reset endpoint\n"); - } - /* Fresco Logic confirms: all revisions of this chip do not - * support MSI, even though some of them claim to in their PCI - * capabilities. - */ - xhci->quirks |= XHCI_BROKEN_MSI; - xhci_dbg(xhci, "QUIRK: Fresco Logic revision %u " - "has broken MSI implementation\n", - pdev->revision); - xhci->quirks |= XHCI_TRUST_TX_LENGTH; - } - - if (pdev->vendor == PCI_VENDOR_ID_NEC) - xhci->quirks |= XHCI_NEC_HOST; - - if (pdev->vendor == PCI_VENDOR_ID_AMD && xhci->hci_version == 0x96) - xhci->quirks |= XHCI_AMD_0x96_HOST; - - /* AMD PLL quirk */ - if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info()) - xhci->quirks |= XHCI_AMD_PLL_FIX; - if (pdev->vendor == PCI_VENDOR_ID_INTEL && - pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI) { - xhci->quirks |= XHCI_SPURIOUS_SUCCESS; - xhci->quirks |= XHCI_EP_LIMIT_QUIRK; - xhci->limit_active_eps = 64; - xhci->quirks |= XHCI_SW_BW_CHECKING; - } - if (pdev->vendor == PCI_VENDOR_ID_ETRON && - pdev->device == PCI_DEVICE_ID_ASROCK_P67) { - xhci->quirks |= XHCI_RESET_ON_RESUME; - xhci_dbg(xhci, "QUIRK: Resetting on resume\n"); - } - if (pdev->vendor == PCI_VENDOR_ID_VIA) - xhci->quirks |= XHCI_RESET_ON_RESUME; -} - -/* called during probe() after chip reset completes */ -static int xhci_pci_setup(struct usb_hcd *hcd) -{ - struct xhci_hcd *xhci; - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - int retval; - - retval = xhci_gen_setup(hcd, xhci_pci_quirks); - if (retval) - return retval; - - xhci = hcd_to_xhci(hcd); - if (!usb_hcd_is_primary_hcd(hcd)) - return 0; - - 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 */ - retval = xhci_pci_reinit(xhci, pdev); - if (!retval) - return retval; - - kfree(xhci); - return retval; -} - -/* - * We need to register our own PCI probe function (instead of the USB core's - * function) in order to create a second roothub under xHCI. - */ -static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - int retval; - struct xhci_hcd *xhci; - struct hc_driver *driver; - struct usb_hcd *hcd; - - driver = (struct hc_driver *)id->driver_data; - /* Register the USB 2.0 roothub. - * FIXME: USB core must know to register the USB 2.0 roothub first. - * This is sort of silly, because we could just set the HCD driver flags - * to say USB 2.0, but I'm not sure what the implications would be in - * the other parts of the HCD code. - */ - retval = usb_hcd_pci_probe(dev, id); - - if (retval) - return retval; - - /* USB 2.0 roothub is stored in the PCI device now. */ - hcd = dev_get_drvdata(&dev->dev); - xhci = hcd_to_xhci(hcd); - xhci->shared_hcd = usb_create_shared_hcd(driver, &dev->dev, - pci_name(dev), hcd); - if (!xhci->shared_hcd) { - retval = -ENOMEM; - goto dealloc_usb2_hcd; - } - - /* Set the xHCI pointer before xhci_pci_setup() (aka hcd_driver.reset) - * is called by usb_add_hcd(). - */ - *((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci; - - retval = usb_add_hcd(xhci->shared_hcd, dev->irq, - IRQF_SHARED); - if (retval) - goto put_usb3_hcd; - /* Roothub already marked as USB 3.0 speed */ - return 0; - -put_usb3_hcd: - usb_put_hcd(xhci->shared_hcd); -dealloc_usb2_hcd: - usb_hcd_pci_remove(dev); - return retval; -} - -static void xhci_pci_remove(struct pci_dev *dev) -{ - struct xhci_hcd *xhci; - - xhci = hcd_to_xhci(pci_get_drvdata(dev)); - if (xhci->shared_hcd) { - usb_remove_hcd(xhci->shared_hcd); - usb_put_hcd(xhci->shared_hcd); - } - usb_hcd_pci_remove(dev); - kfree(xhci); -} - -#ifdef CONFIG_PM -static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) -{ - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - int retval = 0; - - if (hcd->state != HC_STATE_SUSPENDED || - xhci->shared_hcd->state != HC_STATE_SUSPENDED) - return -EINVAL; - - retval = xhci_suspend(xhci); - - return retval; -} - -static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) -{ - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - int retval = 0; - - /* The BIOS on systems with the Intel Panther Point chipset may or may - * not support xHCI natively. That means that during system resume, it - * may switch the ports back to EHCI so that users can use their - * keyboard to select a kernel from GRUB after resume from hibernate. - * - * The BIOS is supposed to remember whether the OS had xHCI ports - * enabled before resume, and switch the ports back to xHCI when the - * BIOS/OS semaphore is written, but we all know we can't trust BIOS - * writers. - * - * Unconditionally switch the ports back to xHCI after a system resume. - * We can't tell whether the EHCI or xHCI controller will be resumed - * first, so we have to do the port switchover in both drivers. Writing - * a '1' to the port switchover registers should have no effect if the - * port was already switched over. - */ - if (usb_is_intel_switchable_xhci(pdev)) - usb_enable_xhci_ports(pdev); - - retval = xhci_resume(xhci, hibernated); - return retval; -} -#endif /* CONFIG_PM */ - -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 | HCD_SHARED, - - /* - * basic lifecycle operations - */ - .reset = xhci_pci_setup, - .start = xhci_run, -#ifdef CONFIG_PM - .pci_suspend = xhci_pci_suspend, - .pci_resume = xhci_pci_resume, -#endif - .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, - .alloc_streams = xhci_alloc_streams, - .free_streams = xhci_free_streams, - .add_endpoint = xhci_add_endpoint, - .drop_endpoint = xhci_drop_endpoint, - .endpoint_reset = xhci_endpoint_reset, - .check_bandwidth = xhci_check_bandwidth, - .reset_bandwidth = xhci_reset_bandwidth, - .address_device = xhci_address_device, - .update_hub_device = xhci_update_hub_device, - .reset_device = xhci_discover_or_reset_device, - - /* - * scheduling support - */ - .get_frame_number = xhci_get_frame, - - /* Root hub support */ - .hub_control = xhci_hub_control, - .hub_status_data = xhci_hub_status_data, - .bus_suspend = xhci_bus_suspend, - .bus_resume = xhci_bus_resume, - /* - * call back when device connected and addressed - */ - .update_device = xhci_update_device, - .set_usb2_hw_lpm = xhci_set_usb2_hardware_lpm, -}; - -/*-------------------------------------------------------------------------*/ - -/* 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 = xhci_pci_probe, - .remove = xhci_pci_remove, - /* suspend and resume implemented later */ - - .shutdown = usb_hcd_pci_shutdown, -#ifdef CONFIG_PM_SLEEP - .driver = { - .pm = &usb_hcd_pci_pm_ops - }, -#endif -}; - -int __init xhci_register_pci(void) -{ - return pci_register_driver(&xhci_pci_driver); -} - -void xhci_unregister_pci(void) -{ - pci_unregister_driver(&xhci_pci_driver); -} diff --git a/ANDROID_3.4.5/drivers/usb/host/xhci-plat.c b/ANDROID_3.4.5/drivers/usb/host/xhci-plat.c deleted file mode 100644 index 689bc18b..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/xhci-plat.c +++ /dev/null @@ -1,205 +0,0 @@ -/* - * xhci-plat.c - xHCI host controller driver platform Bus Glue. - * - * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com - * Author: Sebastian Andrzej Siewior - * - * A lot of code borrowed from the Linux xHCI 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. - */ - -#include -#include -#include - -#include "xhci.h" - -static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) -{ - /* - * As of now platform drivers don't provide MSI support so we ensure - * here that the generic code does not try to make a pci_dev from our - * dev struct in order to setup MSI - */ - xhci->quirks |= XHCI_BROKEN_MSI; -} - -/* called during probe() after chip reset completes */ -static int xhci_plat_setup(struct usb_hcd *hcd) -{ - return xhci_gen_setup(hcd, xhci_plat_quirks); -} - -static const struct hc_driver xhci_plat_xhci_driver = { - .description = "xhci-hcd", - .product_desc = "xHCI Host Controller", - .hcd_priv_size = sizeof(struct xhci_hcd *), - - /* - * generic hardware linkage - */ - .irq = xhci_irq, - .flags = HCD_MEMORY | HCD_USB3 | HCD_SHARED, - - /* - * basic lifecycle operations - */ - .reset = xhci_plat_setup, - .start = xhci_run, - .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, - .alloc_streams = xhci_alloc_streams, - .free_streams = xhci_free_streams, - .add_endpoint = xhci_add_endpoint, - .drop_endpoint = xhci_drop_endpoint, - .endpoint_reset = xhci_endpoint_reset, - .check_bandwidth = xhci_check_bandwidth, - .reset_bandwidth = xhci_reset_bandwidth, - .address_device = xhci_address_device, - .update_hub_device = xhci_update_hub_device, - .reset_device = xhci_discover_or_reset_device, - - /* - * scheduling support - */ - .get_frame_number = xhci_get_frame, - - /* Root hub support */ - .hub_control = xhci_hub_control, - .hub_status_data = xhci_hub_status_data, - .bus_suspend = xhci_bus_suspend, - .bus_resume = xhci_bus_resume, -}; - -static int xhci_plat_probe(struct platform_device *pdev) -{ - const struct hc_driver *driver; - struct xhci_hcd *xhci; - struct resource *res; - struct usb_hcd *hcd; - int ret; - int irq; - - if (usb_disabled()) - return -ENODEV; - - driver = &xhci_plat_xhci_driver; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return -ENODEV; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) - return -ENOMEM; - - hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); - - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, - driver->description)) { - dev_dbg(&pdev->dev, "controller already in use\n"); - ret = -EBUSY; - goto put_hcd; - } - - hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) { - dev_dbg(&pdev->dev, "error mapping memory\n"); - ret = -EFAULT; - goto release_mem_region; - } - - ret = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (ret) - goto unmap_registers; - - /* USB 2.0 roothub is stored in the platform_device now. */ - hcd = dev_get_drvdata(&pdev->dev); - xhci = hcd_to_xhci(hcd); - xhci->shared_hcd = usb_create_shared_hcd(driver, &pdev->dev, - dev_name(&pdev->dev), hcd); - if (!xhci->shared_hcd) { - ret = -ENOMEM; - goto dealloc_usb2_hcd; - } - - /* - * Set the xHCI pointer before xhci_plat_setup() (aka hcd_driver.reset) - * is called by usb_add_hcd(). - */ - *((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci; - - ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED); - if (ret) - goto put_usb3_hcd; - - return 0; - -put_usb3_hcd: - usb_put_hcd(xhci->shared_hcd); - -dealloc_usb2_hcd: - usb_remove_hcd(hcd); - -unmap_registers: - iounmap(hcd->regs); - -release_mem_region: - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - -put_hcd: - usb_put_hcd(hcd); - - return ret; -} - -static int xhci_plat_remove(struct platform_device *dev) -{ - struct usb_hcd *hcd = platform_get_drvdata(dev); - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - - usb_remove_hcd(xhci->shared_hcd); - usb_put_hcd(xhci->shared_hcd); - - usb_remove_hcd(hcd); - iounmap(hcd->regs); - usb_put_hcd(hcd); - kfree(xhci); - - return 0; -} - -static struct platform_driver usb_xhci_driver = { - .probe = xhci_plat_probe, - .remove = xhci_plat_remove, - .driver = { - .name = "xhci-hcd", - }, -}; -MODULE_ALIAS("platform:xhci-hcd"); - -int xhci_register_plat(void) -{ - return platform_driver_register(&usb_xhci_driver); -} - -void xhci_unregister_plat(void) -{ - platform_driver_unregister(&usb_xhci_driver); -} diff --git a/ANDROID_3.4.5/drivers/usb/host/xhci-ring.c b/ANDROID_3.4.5/drivers/usb/host/xhci-ring.c deleted file mode 100644 index 158175bf..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/xhci-ring.c +++ /dev/null @@ -1,3691 +0,0 @@ -/* - * 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. - */ - -/* - * Ring initialization rules: - * 1. Each segment is initialized to zero, except for link TRBs. - * 2. Ring cycle state = 0. This represents Producer Cycle State (PCS) or - * Consumer Cycle State (CCS), depending on ring function. - * 3. Enqueue pointer = dequeue pointer = address of first TRB in the segment. - * - * Ring behavior rules: - * 1. A ring is empty if enqueue == dequeue. This means there will always be at - * least one free TRB in the ring. This is useful if you want to turn that - * into a link TRB and expand the ring. - * 2. When incrementing an enqueue or dequeue pointer, if the next TRB is a - * link TRB, then load the pointer with the address in the link TRB. If the - * link TRB had its toggle bit set, you may need to update the ring cycle - * state (see cycle bit rules). You may have to do this multiple times - * until you reach a non-link TRB. - * 3. A ring is full if enqueue++ (for the definition of increment above) - * equals the dequeue pointer. - * - * Cycle bit rules: - * 1. When a consumer increments a dequeue pointer and encounters a toggle bit - * in a link TRB, it must toggle the ring cycle state. - * 2. When a producer increments an enqueue pointer and encounters a toggle bit - * in a link TRB, it must toggle the ring cycle state. - * - * Producer rules: - * 1. Check if ring is full before you enqueue. - * 2. Write the ring cycle state to the cycle bit in the TRB you're enqueuing. - * Update enqueue pointer between each write (which may update the ring - * cycle state). - * 3. Notify consumer. If SW is producer, it rings the doorbell for command - * and endpoint rings. If HC is the producer for the event ring, - * and it generates an interrupt according to interrupt modulation rules. - * - * Consumer rules: - * 1. Check if TRB belongs to you. If the cycle bit == your ring cycle state, - * the TRB is owned by the consumer. - * 2. Update dequeue pointer (which may update the ring cycle state) and - * continue processing TRBs until you reach a TRB which is not owned by you. - * 3. Notify the producer. SW is the consumer for the event ring, and it - * updates event ring dequeue pointer. HC is the consumer for the command and - * endpoint rings; it generates events on the event ring for these. - */ - -#include -#include -#include "xhci.h" - -static int handle_cmd_in_cmd_wait_list(struct xhci_hcd *xhci, - struct xhci_virt_device *virt_dev, - struct xhci_event_cmd *event); - -/* - * Returns zero if the TRB isn't in this segment, otherwise it returns the DMA - * address of the TRB. - */ -dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, - union xhci_trb *trb) -{ - unsigned long segment_offset; - - if (!seg || !trb || trb < seg->trbs) - return 0; - /* offset in TRBs */ - segment_offset = trb - seg->trbs; - if (segment_offset > TRBS_PER_SEGMENT) - return 0; - return seg->dma + (segment_offset * sizeof(*trb)); -} - -/* Does this link TRB point to the first segment in a ring, - * or was the previous TRB the last TRB on the last segment in the ERST? - */ -static bool last_trb_on_last_seg(struct xhci_hcd *xhci, struct xhci_ring *ring, - struct xhci_segment *seg, union xhci_trb *trb) -{ - if (ring == xhci->event_ring) - return (trb == &seg->trbs[TRBS_PER_SEGMENT]) && - (seg->next == xhci->event_ring->first_seg); - else - return le32_to_cpu(trb->link.control) & LINK_TOGGLE; -} - -/* Is this TRB a link TRB or was the last TRB the last TRB in this event ring - * segment? I.e. would the updated event TRB pointer step off the end of the - * event seg? - */ -static int last_trb(struct xhci_hcd *xhci, struct xhci_ring *ring, - struct xhci_segment *seg, union xhci_trb *trb) -{ - if (ring == xhci->event_ring) - return trb == &seg->trbs[TRBS_PER_SEGMENT]; - else - return TRB_TYPE_LINK_LE32(trb->link.control); -} - -static int enqueue_is_link_trb(struct xhci_ring *ring) -{ - struct xhci_link_trb *link = &ring->enqueue->link; - return TRB_TYPE_LINK_LE32(link->control); -} - -/* Updates trb to point to the next TRB in the ring, and updates seg if the next - * TRB is in a new segment. This does not skip over link TRBs, and it does not - * effect the ring dequeue or enqueue pointers. - */ -static void next_trb(struct xhci_hcd *xhci, - struct xhci_ring *ring, - struct xhci_segment **seg, - union xhci_trb **trb) -{ - if (last_trb(xhci, ring, *seg, *trb)) { - *seg = (*seg)->next; - *trb = ((*seg)->trbs); - } else { - (*trb)++; - } -} - -/* - * See Cycle bit rules. SW is the consumer for the event ring only. - * Don't make a ring full of link TRBs. That would be dumb and this would loop. - */ -static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring) -{ - union xhci_trb *next; - unsigned long long addr; - - ring->deq_updates++; - - /* If this is not event ring, there is one more usable TRB */ - if (ring->type != TYPE_EVENT && - !last_trb(xhci, ring, ring->deq_seg, ring->dequeue)) - ring->num_trbs_free++; - next = ++(ring->dequeue); - - /* Update the dequeue pointer further if that was a link TRB or we're at - * the end of an event ring segment (which doesn't have link TRBS) - */ - while (last_trb(xhci, ring, ring->deq_seg, next)) { - if (ring->type == TYPE_EVENT && last_trb_on_last_seg(xhci, - ring, ring->deq_seg, next)) { - ring->cycle_state = (ring->cycle_state ? 0 : 1); - } - ring->deq_seg = ring->deq_seg->next; - ring->dequeue = ring->deq_seg->trbs; - next = ring->dequeue; - } - addr = (unsigned long long) xhci_trb_virt_to_dma(ring->deq_seg, ring->dequeue); -} - -/* - * See Cycle bit rules. SW is the consumer for the event ring only. - * Don't make a ring full of link TRBs. That would be dumb and this would loop. - * - * If we've just enqueued a TRB that is in the middle of a TD (meaning the - * chain bit is set), then set the chain bit in all the following link TRBs. - * If we've enqueued the last TRB in a TD, make sure the following link TRBs - * have their chain bit cleared (so that each Link TRB is a separate TD). - * - * Section 6.4.4.1 of the 0.95 spec says link TRBs cannot have the chain bit - * set, but other sections talk about dealing with the chain bit set. This was - * fixed in the 0.96 specification errata, but we have to assume that all 0.95 - * xHCI hardware can't handle the chain bit being cleared on a link TRB. - * - * @more_trbs_coming: Will you enqueue more TRBs before calling - * prepare_transfer()? - */ -static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, - bool more_trbs_coming) -{ - u32 chain; - union xhci_trb *next; - unsigned long long addr; - - chain = le32_to_cpu(ring->enqueue->generic.field[3]) & TRB_CHAIN; - /* If this is not event ring, there is one less usable TRB */ - if (ring->type != TYPE_EVENT && - !last_trb(xhci, ring, ring->enq_seg, ring->enqueue)) - ring->num_trbs_free--; - next = ++(ring->enqueue); - - ring->enq_updates++; - /* Update the dequeue pointer further if that was a link TRB or we're at - * the end of an event ring segment (which doesn't have link TRBS) - */ - while (last_trb(xhci, ring, ring->enq_seg, next)) { - if (ring->type != TYPE_EVENT) { - /* - * If the caller doesn't plan on enqueueing more - * TDs before ringing the doorbell, then we - * don't want to give the link TRB to the - * hardware just yet. We'll give the link TRB - * back in prepare_ring() just before we enqueue - * the TD at the top of the ring. - */ - if (!chain && !more_trbs_coming) - break; - - /* If we're not dealing with 0.95 hardware or - * isoc rings on AMD 0.96 host, - * carry over the chain bit of the previous TRB - * (which may mean the chain bit is cleared). - */ - if (!(ring->type == TYPE_ISOC && - (xhci->quirks & XHCI_AMD_0x96_HOST)) - && !xhci_link_trb_quirk(xhci)) { - next->link.control &= - cpu_to_le32(~TRB_CHAIN); - next->link.control |= - cpu_to_le32(chain); - } - /* Give this link TRB to the hardware */ - wmb(); - next->link.control ^= cpu_to_le32(TRB_CYCLE); - - /* Toggle the cycle bit after the last ring segment. */ - if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) { - ring->cycle_state = (ring->cycle_state ? 0 : 1); - } - } - ring->enq_seg = ring->enq_seg->next; - ring->enqueue = ring->enq_seg->trbs; - next = ring->enqueue; - } - addr = (unsigned long long) xhci_trb_virt_to_dma(ring->enq_seg, ring->enqueue); -} - -/* - * Check to see if there's room to enqueue num_trbs on the ring and make sure - * enqueue pointer will not advance into dequeue segment. See rules above. - */ -static inline int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring, - unsigned int num_trbs) -{ - int num_trbs_in_deq_seg; - - if (ring->num_trbs_free < num_trbs) - return 0; - - if (ring->type != TYPE_COMMAND && ring->type != TYPE_EVENT) { - num_trbs_in_deq_seg = ring->dequeue - ring->deq_seg->trbs; - if (ring->num_trbs_free < num_trbs + num_trbs_in_deq_seg) - return 0; - } - - return 1; -} - -/* Ring the host controller doorbell after placing a command on the ring */ -void xhci_ring_cmd_db(struct xhci_hcd *xhci) -{ - xhci_dbg(xhci, "// Ding dong!\n"); - xhci_writel(xhci, DB_VALUE_HOST, &xhci->dba->doorbell[0]); - /* Flush PCI posted writes */ - xhci_readl(xhci, &xhci->dba->doorbell[0]); -} - -void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, - unsigned int slot_id, - unsigned int ep_index, - unsigned int stream_id) -{ - __le32 __iomem *db_addr = &xhci->dba->doorbell[slot_id]; - struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index]; - unsigned int ep_state = ep->ep_state; - - /* Don't ring the doorbell for this endpoint if there are pending - * cancellations because we don't want to interrupt processing. - * We don't want to restart any stream rings if there's a set dequeue - * pointer command pending because the device can choose to start any - * stream once the endpoint is on the HW schedule. - * FIXME - check all the stream rings for pending cancellations. - */ - if ((ep_state & EP_HALT_PENDING) || (ep_state & SET_DEQ_PENDING) || - (ep_state & EP_HALTED)) - return; - xhci_writel(xhci, DB_VALUE(ep_index, stream_id), db_addr); - /* The CPU has better things to do at this point than wait for a - * write-posting flush. It'll get there soon enough. - */ -} - -/* Ring the doorbell for any rings with pending URBs */ -static void ring_doorbell_for_active_rings(struct xhci_hcd *xhci, - unsigned int slot_id, - unsigned int ep_index) -{ - unsigned int stream_id; - struct xhci_virt_ep *ep; - - ep = &xhci->devs[slot_id]->eps[ep_index]; - - /* A ring has pending URBs if its TD list is not empty */ - if (!(ep->ep_state & EP_HAS_STREAMS)) { - if (!(list_empty(&ep->ring->td_list))) - xhci_ring_ep_doorbell(xhci, slot_id, ep_index, 0); - return; - } - - for (stream_id = 1; stream_id < ep->stream_info->num_streams; - stream_id++) { - struct xhci_stream_info *stream_info = ep->stream_info; - if (!list_empty(&stream_info->stream_rings[stream_id]->td_list)) - xhci_ring_ep_doorbell(xhci, slot_id, ep_index, - stream_id); - } -} - -/* - * Find the segment that trb is in. Start searching in start_seg. - * If we must move past a segment that has a link TRB with a toggle cycle state - * bit set, then we will toggle the value pointed at by cycle_state. - */ -static struct xhci_segment *find_trb_seg( - struct xhci_segment *start_seg, - union xhci_trb *trb, int *cycle_state) -{ - struct xhci_segment *cur_seg = start_seg; - struct xhci_generic_trb *generic_trb; - - while (cur_seg->trbs > trb || - &cur_seg->trbs[TRBS_PER_SEGMENT - 1] < trb) { - generic_trb = &cur_seg->trbs[TRBS_PER_SEGMENT - 1].generic; - if (generic_trb->field[3] & cpu_to_le32(LINK_TOGGLE)) - *cycle_state ^= 0x1; - cur_seg = cur_seg->next; - if (cur_seg == start_seg) - /* Looped over the entire list. Oops! */ - return NULL; - } - return cur_seg; -} - - -static struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci, - unsigned int slot_id, unsigned int ep_index, - unsigned int stream_id) -{ - struct xhci_virt_ep *ep; - - ep = &xhci->devs[slot_id]->eps[ep_index]; - /* Common case: no streams */ - if (!(ep->ep_state & EP_HAS_STREAMS)) - return ep->ring; - - if (stream_id == 0) { - xhci_warn(xhci, - "WARN: Slot ID %u, ep index %u has streams, " - "but URB has no stream ID.\n", - slot_id, ep_index); - return NULL; - } - - if (stream_id < ep->stream_info->num_streams) - return ep->stream_info->stream_rings[stream_id]; - - xhci_warn(xhci, - "WARN: Slot ID %u, ep index %u has " - "stream IDs 1 to %u allocated, " - "but stream ID %u is requested.\n", - slot_id, ep_index, - ep->stream_info->num_streams - 1, - stream_id); - return NULL; -} - -/* Get the right ring for the given URB. - * If the endpoint supports streams, boundary check the URB's stream ID. - * If the endpoint doesn't support streams, return the singular endpoint ring. - */ -static struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci, - struct urb *urb) -{ - return xhci_triad_to_transfer_ring(xhci, urb->dev->slot_id, - xhci_get_endpoint_index(&urb->ep->desc), urb->stream_id); -} - -/* - * Move the xHC's endpoint ring dequeue pointer past cur_td. - * Record the new state of the xHC's endpoint ring dequeue segment, - * dequeue pointer, and new consumer cycle state in state. - * Update our internal representation of the ring's dequeue pointer. - * - * We do this in three jumps: - * - First we update our new ring state to be the same as when the xHC stopped. - * - Then we traverse the ring to find the segment that contains - * the last TRB in the TD. We toggle the xHC's new cycle state when we pass - * any link TRBs with the toggle cycle bit set. - * - Finally we move the dequeue state one TRB further, toggling the cycle bit - * if we've moved it past a link TRB with the toggle cycle bit set. - * - * Some of the uses of xhci_generic_trb are grotty, but if they're done - * with correct __le32 accesses they should work fine. Only users of this are - * in here. - */ -void xhci_find_new_dequeue_state(struct xhci_hcd *xhci, - unsigned int slot_id, unsigned int ep_index, - unsigned int stream_id, struct xhci_td *cur_td, - struct xhci_dequeue_state *state) -{ - struct xhci_virt_device *dev = xhci->devs[slot_id]; - struct xhci_ring *ep_ring; - struct xhci_generic_trb *trb; - struct xhci_ep_ctx *ep_ctx; - dma_addr_t addr; - - ep_ring = xhci_triad_to_transfer_ring(xhci, slot_id, - ep_index, stream_id); - if (!ep_ring) { - xhci_warn(xhci, "WARN can't find new dequeue state " - "for invalid stream ID %u.\n", - stream_id); - return; - } - state->new_cycle_state = 0; - xhci_dbg(xhci, "Finding segment containing stopped TRB.\n"); - state->new_deq_seg = find_trb_seg(cur_td->start_seg, - dev->eps[ep_index].stopped_trb, - &state->new_cycle_state); - if (!state->new_deq_seg) { - WARN_ON(1); - return; - } - - /* Dig out the cycle state saved by the xHC during the stop ep cmd */ - xhci_dbg(xhci, "Finding endpoint context\n"); - ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index); - state->new_cycle_state = 0x1 & le64_to_cpu(ep_ctx->deq); - - state->new_deq_ptr = cur_td->last_trb; - xhci_dbg(xhci, "Finding segment containing last TRB in TD.\n"); - state->new_deq_seg = find_trb_seg(state->new_deq_seg, - state->new_deq_ptr, - &state->new_cycle_state); - if (!state->new_deq_seg) { - WARN_ON(1); - return; - } - - trb = &state->new_deq_ptr->generic; - if (TRB_TYPE_LINK_LE32(trb->field[3]) && - (trb->field[3] & cpu_to_le32(LINK_TOGGLE))) - state->new_cycle_state ^= 0x1; - next_trb(xhci, ep_ring, &state->new_deq_seg, &state->new_deq_ptr); - - /* - * If there is only one segment in a ring, find_trb_seg()'s while loop - * will not run, and it will return before it has a chance to see if it - * needs to toggle the cycle bit. It can't tell if the stalled transfer - * ended just before the link TRB on a one-segment ring, or if the TD - * wrapped around the top of the ring, because it doesn't have the TD in - * question. Look for the one-segment case where stalled TRB's address - * is greater than the new dequeue pointer address. - */ - if (ep_ring->first_seg == ep_ring->first_seg->next && - state->new_deq_ptr < dev->eps[ep_index].stopped_trb) - state->new_cycle_state ^= 0x1; - xhci_dbg(xhci, "Cycle state = 0x%x\n", state->new_cycle_state); - - /* Don't update the ring cycle state for the producer (us). */ - xhci_dbg(xhci, "New dequeue segment = %p (virtual)\n", - state->new_deq_seg); - addr = xhci_trb_virt_to_dma(state->new_deq_seg, state->new_deq_ptr); - xhci_dbg(xhci, "New dequeue pointer = 0x%llx (DMA)\n", - (unsigned long long) addr); -} - -/* flip_cycle means flip the cycle bit of all but the first and last TRB. - * (The last TRB actually points to the ring enqueue pointer, which is not part - * of this TD.) This is used to remove partially enqueued isoc TDs from a ring. - */ -static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, - struct xhci_td *cur_td, bool flip_cycle) -{ - struct xhci_segment *cur_seg; - union xhci_trb *cur_trb; - - for (cur_seg = cur_td->start_seg, cur_trb = cur_td->first_trb; - true; - next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) { - if (TRB_TYPE_LINK_LE32(cur_trb->generic.field[3])) { - /* Unchain any chained Link TRBs, but - * leave the pointers intact. - */ - cur_trb->generic.field[3] &= cpu_to_le32(~TRB_CHAIN); - /* Flip the cycle bit (link TRBs can't be the first - * or last TRB). - */ - if (flip_cycle) - cur_trb->generic.field[3] ^= - cpu_to_le32(TRB_CYCLE); - xhci_dbg(xhci, "Cancel (unchain) link TRB\n"); - xhci_dbg(xhci, "Address = %p (0x%llx dma); " - "in seg %p (0x%llx dma)\n", - cur_trb, - (unsigned long long)xhci_trb_virt_to_dma(cur_seg, cur_trb), - cur_seg, - (unsigned long long)cur_seg->dma); - } else { - cur_trb->generic.field[0] = 0; - cur_trb->generic.field[1] = 0; - cur_trb->generic.field[2] = 0; - /* Preserve only the cycle bit of this TRB */ - cur_trb->generic.field[3] &= cpu_to_le32(TRB_CYCLE); - /* Flip the cycle bit except on the first or last TRB */ - if (flip_cycle && cur_trb != cur_td->first_trb && - cur_trb != cur_td->last_trb) - cur_trb->generic.field[3] ^= - cpu_to_le32(TRB_CYCLE); - cur_trb->generic.field[3] |= cpu_to_le32( - TRB_TYPE(TRB_TR_NOOP)); - xhci_dbg(xhci, "TRB to noop at offset 0x%llx\n", - (unsigned long long) - xhci_trb_virt_to_dma(cur_seg, cur_trb)); - } - if (cur_trb == cur_td->last_trb) - break; - } -} - -static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id, - unsigned int ep_index, unsigned int stream_id, - struct xhci_segment *deq_seg, - union xhci_trb *deq_ptr, u32 cycle_state); - -void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, - unsigned int slot_id, unsigned int ep_index, - unsigned int stream_id, - struct xhci_dequeue_state *deq_state) -{ - struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index]; - - xhci_dbg(xhci, "Set TR Deq Ptr cmd, new deq seg = %p (0x%llx dma), " - "new deq ptr = %p (0x%llx dma), new cycle = %u\n", - deq_state->new_deq_seg, - (unsigned long long)deq_state->new_deq_seg->dma, - deq_state->new_deq_ptr, - (unsigned long long)xhci_trb_virt_to_dma(deq_state->new_deq_seg, deq_state->new_deq_ptr), - deq_state->new_cycle_state); - queue_set_tr_deq(xhci, slot_id, ep_index, stream_id, - deq_state->new_deq_seg, - deq_state->new_deq_ptr, - (u32) deq_state->new_cycle_state); - /* Stop the TD queueing code from ringing the doorbell until - * this command completes. The HC won't set the dequeue pointer - * if the ring is running, and ringing the doorbell starts the - * ring running. - */ - ep->ep_state |= SET_DEQ_PENDING; -} - -static void xhci_stop_watchdog_timer_in_irq(struct xhci_hcd *xhci, - struct xhci_virt_ep *ep) -{ - ep->ep_state &= ~EP_HALT_PENDING; - /* Can't del_timer_sync in interrupt, so we attempt to cancel. If the - * timer is running on another CPU, we don't decrement stop_cmds_pending - * (since we didn't successfully stop the watchdog timer). - */ - if (del_timer(&ep->stop_cmd_timer)) - ep->stop_cmds_pending--; -} - -/* Must be called with xhci->lock held in interrupt context */ -static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci, - struct xhci_td *cur_td, int status, char *adjective) -{ - struct usb_hcd *hcd; - struct urb *urb; - struct urb_priv *urb_priv; - - urb = cur_td->urb; - urb_priv = urb->hcpriv; - urb_priv->td_cnt++; - hcd = bus_to_hcd(urb->dev->bus); - - /* Only giveback urb when this is the last td in urb */ - if (urb_priv->td_cnt == urb_priv->length) { - if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { - xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs--; - if (xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs == 0) { - if (xhci->quirks & XHCI_AMD_PLL_FIX) - usb_amd_quirk_pll_enable(); - } - } - usb_hcd_unlink_urb_from_ep(hcd, urb); - - spin_unlock(&xhci->lock); - usb_hcd_giveback_urb(hcd, urb, status); - xhci_urb_free_priv(xhci, urb_priv); - spin_lock(&xhci->lock); - } -} - -/* - * When we get a command completion for a Stop Endpoint Command, we need to - * unlink any cancelled TDs from the ring. There are two ways to do that: - * - * 1. If the HW was in the middle of processing the TD that needs to be - * cancelled, then we must move the ring's dequeue pointer past the last TRB - * in the TD with a Set Dequeue Pointer Command. - * 2. Otherwise, we turn all the TRBs in the TD into No-op TRBs (with the chain - * bit cleared) so that the HW will skip over them. - */ -static void handle_stopped_endpoint(struct xhci_hcd *xhci, - union xhci_trb *trb, struct xhci_event_cmd *event) -{ - unsigned int slot_id; - unsigned int ep_index; - struct xhci_virt_device *virt_dev; - struct xhci_ring *ep_ring; - struct xhci_virt_ep *ep; - struct list_head *entry; - struct xhci_td *cur_td = NULL; - struct xhci_td *last_unlinked_td; - - struct xhci_dequeue_state deq_state; - - if (unlikely(TRB_TO_SUSPEND_PORT( - le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])))) { - slot_id = TRB_TO_SLOT_ID( - le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])); - virt_dev = xhci->devs[slot_id]; - if (virt_dev) - handle_cmd_in_cmd_wait_list(xhci, virt_dev, - event); - else - xhci_warn(xhci, "Stop endpoint command " - "completion for disabled slot %u\n", - slot_id); - return; - } - - memset(&deq_state, 0, sizeof(deq_state)); - slot_id = TRB_TO_SLOT_ID(le32_to_cpu(trb->generic.field[3])); - ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3])); - ep = &xhci->devs[slot_id]->eps[ep_index]; - - if (list_empty(&ep->cancelled_td_list)) { - xhci_stop_watchdog_timer_in_irq(xhci, ep); - ep->stopped_td = NULL; - ep->stopped_trb = NULL; - ring_doorbell_for_active_rings(xhci, slot_id, ep_index); - return; - } - - /* Fix up the ep ring first, so HW stops executing cancelled TDs. - * We have the xHCI lock, so nothing can modify this list until we drop - * it. We're also in the event handler, so we can't get re-interrupted - * if another Stop Endpoint command completes - */ - list_for_each(entry, &ep->cancelled_td_list) { - cur_td = list_entry(entry, struct xhci_td, cancelled_td_list); - xhci_dbg(xhci, "Removing canceled TD starting at 0x%llx (dma).\n", - (unsigned long long)xhci_trb_virt_to_dma( - cur_td->start_seg, cur_td->first_trb)); - ep_ring = xhci_urb_to_transfer_ring(xhci, cur_td->urb); - if (!ep_ring) { - /* This shouldn't happen unless a driver is mucking - * with the stream ID after submission. This will - * leave the TD on the hardware ring, and the hardware - * will try to execute it, and may access a buffer - * that has already been freed. In the best case, the - * hardware will execute it, and the event handler will - * ignore the completion event for that TD, since it was - * removed from the td_list for that endpoint. In - * short, don't muck with the stream ID after - * submission. - */ - xhci_warn(xhci, "WARN Cancelled URB %p " - "has invalid stream ID %u.\n", - cur_td->urb, - cur_td->urb->stream_id); - goto remove_finished_td; - } - /* - * If we stopped on the TD we need to cancel, then we have to - * move the xHC endpoint ring dequeue pointer past this TD. - */ - if (cur_td == ep->stopped_td) - xhci_find_new_dequeue_state(xhci, slot_id, ep_index, - cur_td->urb->stream_id, - cur_td, &deq_state); - else - td_to_noop(xhci, ep_ring, cur_td, false); -remove_finished_td: - /* - * The event handler won't see a completion for this TD anymore, - * so remove it from the endpoint ring's TD list. Keep it in - * the cancelled TD list for URB completion later. - */ - list_del_init(&cur_td->td_list); - } - last_unlinked_td = cur_td; - xhci_stop_watchdog_timer_in_irq(xhci, ep); - - /* If necessary, queue a Set Transfer Ring Dequeue Pointer command */ - if (deq_state.new_deq_ptr && deq_state.new_deq_seg) { - xhci_queue_new_dequeue_state(xhci, - slot_id, ep_index, - ep->stopped_td->urb->stream_id, - &deq_state); - xhci_ring_cmd_db(xhci); - } else { - /* Otherwise ring the doorbell(s) to restart queued transfers */ - ring_doorbell_for_active_rings(xhci, slot_id, ep_index); - } - ep->stopped_td = NULL; - ep->stopped_trb = NULL; - - /* - * Drop the lock and complete the URBs in the cancelled TD list. - * New TDs to be cancelled might be added to the end of the list before - * we can complete all the URBs for the TDs we already unlinked. - * So stop when we've completed the URB for the last TD we unlinked. - */ - do { - cur_td = list_entry(ep->cancelled_td_list.next, - struct xhci_td, cancelled_td_list); - list_del_init(&cur_td->cancelled_td_list); - - /* Clean up the cancelled URB */ - /* Doesn't matter what we pass for status, since the core will - * just overwrite it (because the URB has been unlinked). - */ - xhci_giveback_urb_in_irq(xhci, cur_td, 0, "cancelled"); - - /* Stop processing the cancelled list if the watchdog timer is - * running. - */ - if (xhci->xhc_state & XHCI_STATE_DYING) - return; - } while (cur_td != last_unlinked_td); - - /* Return to the event handler with xhci->lock re-acquired */ -} - -/* Watchdog timer function for when a stop endpoint command fails to complete. - * In this case, we assume the host controller is broken or dying or dead. The - * host may still be completing some other events, so we have to be careful to - * let the event ring handler and the URB dequeueing/enqueueing functions know - * through xhci->state. - * - * The timer may also fire if the host takes a very long time to respond to the - * command, and the stop endpoint command completion handler cannot delete the - * timer before the timer function is called. Another endpoint cancellation may - * sneak in before the timer function can grab the lock, and that may queue - * another stop endpoint command and add the timer back. So we cannot use a - * simple flag to say whether there is a pending stop endpoint command for a - * particular endpoint. - * - * Instead we use a combination of that flag and a counter for the number of - * pending stop endpoint commands. If the timer is the tail end of the last - * stop endpoint command, and the endpoint's command is still pending, we assume - * the host is dying. - */ -void xhci_stop_endpoint_command_watchdog(unsigned long arg) -{ - struct xhci_hcd *xhci; - struct xhci_virt_ep *ep; - struct xhci_virt_ep *temp_ep; - struct xhci_ring *ring; - struct xhci_td *cur_td; - int ret, i, j; - unsigned long flags; - - ep = (struct xhci_virt_ep *) arg; - xhci = ep->xhci; - - spin_lock_irqsave(&xhci->lock, flags); - - ep->stop_cmds_pending--; - if (xhci->xhc_state & XHCI_STATE_DYING) { - xhci_dbg(xhci, "Stop EP timer ran, but another timer marked " - "xHCI as DYING, exiting.\n"); - spin_unlock_irqrestore(&xhci->lock, flags); - return; - } - if (!(ep->stop_cmds_pending == 0 && (ep->ep_state & EP_HALT_PENDING))) { - xhci_dbg(xhci, "Stop EP timer ran, but no command pending, " - "exiting.\n"); - spin_unlock_irqrestore(&xhci->lock, flags); - return; - } - - xhci_warn(xhci, "xHCI host not responding to stop endpoint command.\n"); - xhci_warn(xhci, "Assuming host is dying, halting host.\n"); - /* Oops, HC is dead or dying or at least not responding to the stop - * endpoint command. - */ - xhci->xhc_state |= XHCI_STATE_DYING; - /* Disable interrupts from the host controller and start halting it */ - xhci_quiesce(xhci); - spin_unlock_irqrestore(&xhci->lock, flags); - - ret = xhci_halt(xhci); - - spin_lock_irqsave(&xhci->lock, flags); - if (ret < 0) { - /* This is bad; the host is not responding to commands and it's - * not allowing itself to be halted. At least interrupts are - * disabled. If we call usb_hc_died(), it will attempt to - * disconnect all device drivers under this host. Those - * disconnect() methods will wait for all URBs to be unlinked, - * so we must complete them. - */ - xhci_warn(xhci, "Non-responsive xHCI host is not halting.\n"); - xhci_warn(xhci, "Completing active URBs anyway.\n"); - /* We could turn all TDs on the rings to no-ops. This won't - * help if the host has cached part of the ring, and is slow if - * we want to preserve the cycle bit. Skip it and hope the host - * doesn't touch the memory. - */ - } - for (i = 0; i < MAX_HC_SLOTS; i++) { - if (!xhci->devs[i]) - continue; - for (j = 0; j < 31; j++) { - temp_ep = &xhci->devs[i]->eps[j]; - ring = temp_ep->ring; - if (!ring) - continue; - xhci_dbg(xhci, "Killing URBs for slot ID %u, " - "ep index %u\n", i, j); - while (!list_empty(&ring->td_list)) { - cur_td = list_first_entry(&ring->td_list, - struct xhci_td, - td_list); - list_del_init(&cur_td->td_list); - if (!list_empty(&cur_td->cancelled_td_list)) - list_del_init(&cur_td->cancelled_td_list); - xhci_giveback_urb_in_irq(xhci, cur_td, - -ESHUTDOWN, "killed"); - } - while (!list_empty(&temp_ep->cancelled_td_list)) { - cur_td = list_first_entry( - &temp_ep->cancelled_td_list, - struct xhci_td, - cancelled_td_list); - list_del_init(&cur_td->cancelled_td_list); - xhci_giveback_urb_in_irq(xhci, cur_td, - -ESHUTDOWN, "killed"); - } - } - } - spin_unlock_irqrestore(&xhci->lock, flags); - xhci_dbg(xhci, "Calling usb_hc_died()\n"); - usb_hc_died(xhci_to_hcd(xhci)->primary_hcd); - xhci_dbg(xhci, "xHCI host controller is dead.\n"); -} - - -static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci, - struct xhci_virt_device *dev, - struct xhci_ring *ep_ring, - unsigned int ep_index) -{ - union xhci_trb *dequeue_temp; - int num_trbs_free_temp; - bool revert = false; - - num_trbs_free_temp = ep_ring->num_trbs_free; - dequeue_temp = ep_ring->dequeue; - - /* If we get two back-to-back stalls, and the first stalled transfer - * ends just before a link TRB, the dequeue pointer will be left on - * the link TRB by the code in the while loop. So we have to update - * the dequeue pointer one segment further, or we'll jump off - * the segment into la-la-land. - */ - if (last_trb(xhci, ep_ring, ep_ring->deq_seg, ep_ring->dequeue)) { - ep_ring->deq_seg = ep_ring->deq_seg->next; - ep_ring->dequeue = ep_ring->deq_seg->trbs; - } - - while (ep_ring->dequeue != dev->eps[ep_index].queued_deq_ptr) { - /* We have more usable TRBs */ - ep_ring->num_trbs_free++; - ep_ring->dequeue++; - if (last_trb(xhci, ep_ring, ep_ring->deq_seg, - ep_ring->dequeue)) { - if (ep_ring->dequeue == - dev->eps[ep_index].queued_deq_ptr) - break; - ep_ring->deq_seg = ep_ring->deq_seg->next; - ep_ring->dequeue = ep_ring->deq_seg->trbs; - } - if (ep_ring->dequeue == dequeue_temp) { - revert = true; - break; - } - } - - if (revert) { - xhci_dbg(xhci, "Unable to find new dequeue pointer\n"); - ep_ring->num_trbs_free = num_trbs_free_temp; - } -} - -/* - * When we get a completion for a Set Transfer Ring Dequeue Pointer command, - * we need to clear the set deq pending flag in the endpoint ring state, so that - * the TD queueing code can ring the doorbell again. We also need to ring the - * endpoint doorbell to restart the ring, but only if there aren't more - * cancellations pending. - */ -static void handle_set_deq_completion(struct xhci_hcd *xhci, - struct xhci_event_cmd *event, - union xhci_trb *trb) -{ - unsigned int slot_id; - unsigned int ep_index; - unsigned int stream_id; - struct xhci_ring *ep_ring; - struct xhci_virt_device *dev; - struct xhci_ep_ctx *ep_ctx; - struct xhci_slot_ctx *slot_ctx; - - slot_id = TRB_TO_SLOT_ID(le32_to_cpu(trb->generic.field[3])); - ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3])); - stream_id = TRB_TO_STREAM_ID(le32_to_cpu(trb->generic.field[2])); - dev = xhci->devs[slot_id]; - - ep_ring = xhci_stream_id_to_ring(dev, ep_index, stream_id); - if (!ep_ring) { - xhci_warn(xhci, "WARN Set TR deq ptr command for " - "freed stream ID %u\n", - stream_id); - /* XXX: Harmless??? */ - dev->eps[ep_index].ep_state &= ~SET_DEQ_PENDING; - return; - } - - ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index); - slot_ctx = xhci_get_slot_ctx(xhci, dev->out_ctx); - - if (GET_COMP_CODE(le32_to_cpu(event->status)) != COMP_SUCCESS) { - unsigned int ep_state; - unsigned int slot_state; - - switch (GET_COMP_CODE(le32_to_cpu(event->status))) { - case COMP_TRB_ERR: - xhci_warn(xhci, "WARN Set TR Deq Ptr cmd invalid because " - "of stream ID configuration\n"); - break; - case COMP_CTX_STATE: - xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed due " - "to incorrect slot or ep state.\n"); - ep_state = le32_to_cpu(ep_ctx->ep_info); - ep_state &= EP_STATE_MASK; - slot_state = le32_to_cpu(slot_ctx->dev_state); - slot_state = GET_SLOT_STATE(slot_state); - xhci_dbg(xhci, "Slot state = %u, EP state = %u\n", - slot_state, ep_state); - break; - case COMP_EBADSLT: - xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed because " - "slot %u was not enabled.\n", slot_id); - break; - default: - xhci_warn(xhci, "WARN Set TR Deq Ptr cmd with unknown " - "completion code of %u.\n", - GET_COMP_CODE(le32_to_cpu(event->status))); - break; - } - /* OK what do we do now? The endpoint state is hosed, and we - * should never get to this point if the synchronization between - * queueing, and endpoint state are correct. This might happen - * if the device gets disconnected after we've finished - * cancelling URBs, which might not be an error... - */ - } else { - xhci_dbg(xhci, "Successful Set TR Deq Ptr cmd, deq = @%08llx\n", - le64_to_cpu(ep_ctx->deq)); - if (xhci_trb_virt_to_dma(dev->eps[ep_index].queued_deq_seg, - dev->eps[ep_index].queued_deq_ptr) == - (le64_to_cpu(ep_ctx->deq) & ~(EP_CTX_CYCLE_MASK))) { - /* Update the ring's dequeue segment and dequeue pointer - * to reflect the new position. - */ - update_ring_for_set_deq_completion(xhci, dev, - ep_ring, ep_index); - } else { - xhci_warn(xhci, "Mismatch between completed Set TR Deq " - "Ptr command & xHCI internal state.\n"); - xhci_warn(xhci, "ep deq seg = %p, deq ptr = %p\n", - dev->eps[ep_index].queued_deq_seg, - dev->eps[ep_index].queued_deq_ptr); - } - } - - dev->eps[ep_index].ep_state &= ~SET_DEQ_PENDING; - dev->eps[ep_index].queued_deq_seg = NULL; - dev->eps[ep_index].queued_deq_ptr = NULL; - /* Restart any rings with pending URBs */ - ring_doorbell_for_active_rings(xhci, slot_id, ep_index); -} - -static void handle_reset_ep_completion(struct xhci_hcd *xhci, - struct xhci_event_cmd *event, - union xhci_trb *trb) -{ - int slot_id; - unsigned int ep_index; - - slot_id = TRB_TO_SLOT_ID(le32_to_cpu(trb->generic.field[3])); - ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3])); - /* This command will only fail if the endpoint wasn't halted, - * but we don't care. - */ - xhci_dbg(xhci, "Ignoring reset ep completion code of %u\n", - GET_COMP_CODE(le32_to_cpu(event->status))); - - /* HW with the reset endpoint quirk needs to have a configure endpoint - * command complete before the endpoint can be used. Queue that here - * because the HW can't handle two commands being queued in a row. - */ - if (xhci->quirks & XHCI_RESET_EP_QUIRK) { - xhci_dbg(xhci, "Queueing configure endpoint command\n"); - xhci_queue_configure_endpoint(xhci, - xhci->devs[slot_id]->in_ctx->dma, slot_id, - false); - xhci_ring_cmd_db(xhci); - } else { - /* Clear our internal halted state and restart the ring(s) */ - xhci->devs[slot_id]->eps[ep_index].ep_state &= ~EP_HALTED; - ring_doorbell_for_active_rings(xhci, slot_id, ep_index); - } -} - -/* Check to see if a command in the device's command queue matches this one. - * Signal the completion or free the command, and return 1. Return 0 if the - * completed command isn't at the head of the command list. - */ -static int handle_cmd_in_cmd_wait_list(struct xhci_hcd *xhci, - struct xhci_virt_device *virt_dev, - struct xhci_event_cmd *event) -{ - struct xhci_command *command; - - if (list_empty(&virt_dev->cmd_list)) - return 0; - - command = list_entry(virt_dev->cmd_list.next, - struct xhci_command, cmd_list); - if (xhci->cmd_ring->dequeue != command->command_trb) - return 0; - - command->status = GET_COMP_CODE(le32_to_cpu(event->status)); - list_del(&command->cmd_list); - if (command->completion) - complete(command->completion); - else - xhci_free_command(xhci, command); - return 1; -} - -static void handle_cmd_completion(struct xhci_hcd *xhci, - struct xhci_event_cmd *event) -{ - int slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags)); - u64 cmd_dma; - dma_addr_t cmd_dequeue_dma; - struct xhci_input_control_ctx *ctrl_ctx; - struct xhci_virt_device *virt_dev; - unsigned int ep_index; - struct xhci_ring *ep_ring; - unsigned int ep_state; - - cmd_dma = le64_to_cpu(event->cmd_trb); - cmd_dequeue_dma = xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg, - xhci->cmd_ring->dequeue); - /* Is the command ring deq ptr out of sync with the deq seg ptr? */ - if (cmd_dequeue_dma == 0) { - xhci->error_bitmask |= 1 << 4; - return; - } - /* Does the DMA address match our internal dequeue pointer address? */ - if (cmd_dma != (u64) cmd_dequeue_dma) { - xhci->error_bitmask |= 1 << 5; - return; - } - switch (le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3]) - & TRB_TYPE_BITMASK) { - case TRB_TYPE(TRB_ENABLE_SLOT): - if (GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_SUCCESS) - xhci->slot_id = slot_id; - else - xhci->slot_id = 0; - complete(&xhci->addr_dev); - break; - case TRB_TYPE(TRB_DISABLE_SLOT): - if (xhci->devs[slot_id]) { - if (xhci->quirks & XHCI_EP_LIMIT_QUIRK) - /* Delete default control endpoint resources */ - xhci_free_device_endpoint_resources(xhci, - xhci->devs[slot_id], true); - xhci_free_virt_device(xhci, slot_id); - } - break; - case TRB_TYPE(TRB_CONFIG_EP): - virt_dev = xhci->devs[slot_id]; - if (handle_cmd_in_cmd_wait_list(xhci, virt_dev, event)) - break; - /* - * Configure endpoint commands can come from the USB core - * configuration or alt setting changes, or because the HW - * needed an extra configure endpoint command after a reset - * endpoint command or streams were being configured. - * If the command was for a halted endpoint, the xHCI driver - * is not waiting on the configure endpoint command. - */ - ctrl_ctx = xhci_get_input_control_ctx(xhci, - virt_dev->in_ctx); - /* Input ctx add_flags are the endpoint index plus one */ - ep_index = xhci_last_valid_endpoint(le32_to_cpu(ctrl_ctx->add_flags)) - 1; - /* A usb_set_interface() call directly after clearing a halted - * condition may race on this quirky hardware. Not worth - * worrying about, since this is prototype hardware. Not sure - * if this will work for streams, but streams support was - * untested on this prototype. - */ - if (xhci->quirks & XHCI_RESET_EP_QUIRK && - ep_index != (unsigned int) -1 && - le32_to_cpu(ctrl_ctx->add_flags) - SLOT_FLAG == - le32_to_cpu(ctrl_ctx->drop_flags)) { - ep_ring = xhci->devs[slot_id]->eps[ep_index].ring; - ep_state = xhci->devs[slot_id]->eps[ep_index].ep_state; - if (!(ep_state & EP_HALTED)) - goto bandwidth_change; - xhci_dbg(xhci, "Completed config ep cmd - " - "last ep index = %d, state = %d\n", - ep_index, ep_state); - /* Clear internal halted state and restart ring(s) */ - xhci->devs[slot_id]->eps[ep_index].ep_state &= - ~EP_HALTED; - ring_doorbell_for_active_rings(xhci, slot_id, ep_index); - break; - } -bandwidth_change: - xhci_dbg(xhci, "Completed config ep cmd\n"); - xhci->devs[slot_id]->cmd_status = - GET_COMP_CODE(le32_to_cpu(event->status)); - complete(&xhci->devs[slot_id]->cmd_completion); - break; - case TRB_TYPE(TRB_EVAL_CONTEXT): - virt_dev = xhci->devs[slot_id]; - if (handle_cmd_in_cmd_wait_list(xhci, virt_dev, event)) - break; - xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(le32_to_cpu(event->status)); - complete(&xhci->devs[slot_id]->cmd_completion); - break; - case TRB_TYPE(TRB_ADDR_DEV): - xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(le32_to_cpu(event->status)); - complete(&xhci->addr_dev); - break; - case TRB_TYPE(TRB_STOP_RING): - handle_stopped_endpoint(xhci, xhci->cmd_ring->dequeue, event); - break; - case TRB_TYPE(TRB_SET_DEQ): - handle_set_deq_completion(xhci, event, xhci->cmd_ring->dequeue); - break; - case TRB_TYPE(TRB_CMD_NOOP): - break; - case TRB_TYPE(TRB_RESET_EP): - handle_reset_ep_completion(xhci, event, xhci->cmd_ring->dequeue); - break; - case TRB_TYPE(TRB_RESET_DEV): - xhci_dbg(xhci, "Completed reset device command.\n"); - slot_id = TRB_TO_SLOT_ID( - le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])); - virt_dev = xhci->devs[slot_id]; - if (virt_dev) - handle_cmd_in_cmd_wait_list(xhci, virt_dev, event); - else - xhci_warn(xhci, "Reset device command completion " - "for disabled slot %u\n", slot_id); - break; - case TRB_TYPE(TRB_NEC_GET_FW): - if (!(xhci->quirks & XHCI_NEC_HOST)) { - xhci->error_bitmask |= 1 << 6; - break; - } - xhci_dbg(xhci, "NEC firmware version %2x.%02x\n", - NEC_FW_MAJOR(le32_to_cpu(event->status)), - NEC_FW_MINOR(le32_to_cpu(event->status))); - break; - default: - /* Skip over unknown commands on the event ring */ - xhci->error_bitmask |= 1 << 6; - break; - } - inc_deq(xhci, xhci->cmd_ring); -} - -static void handle_vendor_event(struct xhci_hcd *xhci, - union xhci_trb *event) -{ - u32 trb_type; - - trb_type = TRB_FIELD_TO_TYPE(le32_to_cpu(event->generic.field[3])); - xhci_dbg(xhci, "Vendor specific event TRB type = %u\n", trb_type); - if (trb_type == TRB_NEC_CMD_COMP && (xhci->quirks & XHCI_NEC_HOST)) - handle_cmd_completion(xhci, &event->event_cmd); -} - -/* @port_id: the one-based port ID from the hardware (indexed from array of all - * port registers -- USB 3.0 and USB 2.0). - * - * Returns a zero-based port number, which is suitable for indexing into each of - * the split roothubs' port arrays and bus state arrays. - * Add one to it in order to call xhci_find_slot_id_by_port. - */ -static unsigned int find_faked_portnum_from_hw_portnum(struct usb_hcd *hcd, - struct xhci_hcd *xhci, u32 port_id) -{ - unsigned int i; - unsigned int num_similar_speed_ports = 0; - - /* port_id from the hardware is 1-based, but port_array[], usb3_ports[], - * and usb2_ports are 0-based indexes. Count the number of similar - * speed ports, up to 1 port before this port. - */ - for (i = 0; i < (port_id - 1); i++) { - u8 port_speed = xhci->port_array[i]; - - /* - * Skip ports that don't have known speeds, or have duplicate - * Extended Capabilities port speed entries. - */ - if (port_speed == 0 || port_speed == DUPLICATE_ENTRY) - continue; - - /* - * USB 3.0 ports are always under a USB 3.0 hub. USB 2.0 and - * 1.1 ports are under the USB 2.0 hub. If the port speed - * matches the device speed, it's a similar speed port. - */ - if ((port_speed == 0x03) == (hcd->speed == HCD_USB3)) - num_similar_speed_ports++; - } - return num_similar_speed_ports; -} - -static void handle_device_notification(struct xhci_hcd *xhci, - union xhci_trb *event) -{ - u32 slot_id; - struct usb_device *udev; - - slot_id = TRB_TO_SLOT_ID(event->generic.field[3]); - if (!xhci->devs[slot_id]) { - xhci_warn(xhci, "Device Notification event for " - "unused slot %u\n", slot_id); - return; - } - - xhci_dbg(xhci, "Device Wake Notification event for slot ID %u\n", - slot_id); - udev = xhci->devs[slot_id]->udev; - if (udev && udev->parent) - usb_wakeup_notification(udev->parent, udev->portnum); -} - -static void handle_port_status(struct xhci_hcd *xhci, - union xhci_trb *event) -{ - struct usb_hcd *hcd; - u32 port_id; - u32 temp, temp1; - int max_ports; - int slot_id; - unsigned int faked_port_index; - u8 major_revision; - struct xhci_bus_state *bus_state; - __le32 __iomem **port_array; - bool bogus_port_status = false; - - /* Port status change events always have a successful completion code */ - if (GET_COMP_CODE(le32_to_cpu(event->generic.field[2])) != COMP_SUCCESS) { - xhci_warn(xhci, "WARN: xHC returned failed port status event\n"); - xhci->error_bitmask |= 1 << 8; - } - port_id = GET_PORT_ID(le32_to_cpu(event->generic.field[0])); - xhci_dbg(xhci, "Port Status Change Event for port %d\n", port_id); - - max_ports = HCS_MAX_PORTS(xhci->hcs_params1); - if ((port_id <= 0) || (port_id > max_ports)) { - xhci_warn(xhci, "Invalid port id %d\n", port_id); - bogus_port_status = true; - goto cleanup; - } - - /* Figure out which usb_hcd this port is attached to: - * is it a USB 3.0 port or a USB 2.0/1.1 port? - */ - major_revision = xhci->port_array[port_id - 1]; - if (major_revision == 0) { - xhci_warn(xhci, "Event for port %u not in " - "Extended Capabilities, ignoring.\n", - port_id); - bogus_port_status = true; - goto cleanup; - } - if (major_revision == DUPLICATE_ENTRY) { - xhci_warn(xhci, "Event for port %u duplicated in" - "Extended Capabilities, ignoring.\n", - port_id); - bogus_port_status = true; - goto cleanup; - } - - /* - * Hardware port IDs reported by a Port Status Change Event include USB - * 3.0 and USB 2.0 ports. We want to check if the port has reported a - * resume event, but we first need to translate the hardware port ID - * into the index into the ports on the correct split roothub, and the - * correct bus_state structure. - */ - /* Find the right roothub. */ - hcd = xhci_to_hcd(xhci); - if ((major_revision == 0x03) != (hcd->speed == HCD_USB3)) - hcd = xhci->shared_hcd; - bus_state = &xhci->bus_state[hcd_index(hcd)]; - if (hcd->speed == HCD_USB3) - port_array = xhci->usb3_ports; - else - port_array = xhci->usb2_ports; - /* Find the faked port hub number */ - faked_port_index = find_faked_portnum_from_hw_portnum(hcd, xhci, - port_id); - - temp = xhci_readl(xhci, port_array[faked_port_index]); - if (hcd->state == HC_STATE_SUSPENDED) { - xhci_dbg(xhci, "resume root hub\n"); - usb_hcd_resume_root_hub(hcd); - } - - if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_RESUME) { - xhci_dbg(xhci, "port resume event for port %d\n", port_id); - - temp1 = xhci_readl(xhci, &xhci->op_regs->command); - if (!(temp1 & CMD_RUN)) { - xhci_warn(xhci, "xHC is not running.\n"); - goto cleanup; - } - - if (DEV_SUPERSPEED(temp)) { - xhci_dbg(xhci, "remote wake SS port %d\n", port_id); - /* Set a flag to say the port signaled remote wakeup, - * so we can tell the difference between the end of - * device and host initiated resume. - */ - bus_state->port_remote_wakeup |= 1 << faked_port_index; - xhci_test_and_clear_bit(xhci, port_array, - faked_port_index, PORT_PLC); - xhci_set_link_state(xhci, port_array, faked_port_index, - XDEV_U0); - /* Need to wait until the next link state change - * indicates the device is actually in U0. - */ - bogus_port_status = true; - goto cleanup; - } else { - xhci_dbg(xhci, "resume HS port %d\n", port_id); - bus_state->resume_done[faked_port_index] = jiffies + - msecs_to_jiffies(20); - set_bit(faked_port_index, &bus_state->resuming_ports); - mod_timer(&hcd->rh_timer, - bus_state->resume_done[faked_port_index]); - /* Do the rest in GetPortStatus */ - } - } - - if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_U0 && - DEV_SUPERSPEED(temp)) { - xhci_dbg(xhci, "resume SS port %d finished\n", port_id); - /* We've just brought the device into U0 through either the - * Resume state after a device remote wakeup, or through the - * U3Exit state after a host-initiated resume. If it's a device - * initiated remote wake, don't pass up the link state change, - * so the roothub behavior is consistent with external - * USB 3.0 hub behavior. - */ - slot_id = xhci_find_slot_id_by_port(hcd, xhci, - faked_port_index + 1); - if (slot_id && xhci->devs[slot_id]) - xhci_ring_device(xhci, slot_id); - if (bus_state->port_remote_wakeup && (1 << faked_port_index)) { - bus_state->port_remote_wakeup &= - ~(1 << faked_port_index); - xhci_test_and_clear_bit(xhci, port_array, - faked_port_index, PORT_PLC); - usb_wakeup_notification(hcd->self.root_hub, - faked_port_index + 1); - bogus_port_status = true; - goto cleanup; - } - } - - if (hcd->speed != HCD_USB3) - xhci_test_and_clear_bit(xhci, port_array, faked_port_index, - PORT_PLC); - -cleanup: - /* Update event ring dequeue pointer before dropping the lock */ - inc_deq(xhci, xhci->event_ring); - - /* Don't make the USB core poll the roothub if we got a bad port status - * change event. Besides, at that point we can't tell which roothub - * (USB 2.0 or USB 3.0) to kick. - */ - if (bogus_port_status) - return; - - spin_unlock(&xhci->lock); - /* Pass this up to the core */ - usb_hcd_poll_rh_status(hcd); - spin_lock(&xhci->lock); -} - -/* - * This TD is defined by the TRBs starting at start_trb in start_seg and ending - * at end_trb, which may be in another segment. If the suspect DMA address is a - * TRB in this TD, this function returns that TRB's segment. Otherwise it - * returns 0. - */ -struct xhci_segment *trb_in_td(struct xhci_segment *start_seg, - union xhci_trb *start_trb, - union xhci_trb *end_trb, - dma_addr_t suspect_dma) -{ - dma_addr_t start_dma; - dma_addr_t end_seg_dma; - dma_addr_t end_trb_dma; - struct xhci_segment *cur_seg; - - start_dma = xhci_trb_virt_to_dma(start_seg, start_trb); - cur_seg = start_seg; - - do { - if (start_dma == 0) - return NULL; - /* We may get an event for a Link TRB in the middle of a TD */ - end_seg_dma = xhci_trb_virt_to_dma(cur_seg, - &cur_seg->trbs[TRBS_PER_SEGMENT - 1]); - /* If the end TRB isn't in this segment, this is set to 0 */ - end_trb_dma = xhci_trb_virt_to_dma(cur_seg, end_trb); - - if (end_trb_dma > 0) { - /* The end TRB is in this segment, so suspect should be here */ - if (start_dma <= end_trb_dma) { - if (suspect_dma >= start_dma && suspect_dma <= end_trb_dma) - return cur_seg; - } else { - /* Case for one segment with - * a TD wrapped around to the top - */ - if ((suspect_dma >= start_dma && - suspect_dma <= end_seg_dma) || - (suspect_dma >= cur_seg->dma && - suspect_dma <= end_trb_dma)) - return cur_seg; - } - return NULL; - } else { - /* Might still be somewhere in this segment */ - if (suspect_dma >= start_dma && suspect_dma <= end_seg_dma) - return cur_seg; - } - cur_seg = cur_seg->next; - start_dma = xhci_trb_virt_to_dma(cur_seg, &cur_seg->trbs[0]); - } while (cur_seg != start_seg); - - return NULL; -} - -static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci, - unsigned int slot_id, unsigned int ep_index, - unsigned int stream_id, - struct xhci_td *td, union xhci_trb *event_trb) -{ - struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index]; - ep->ep_state |= EP_HALTED; - ep->stopped_td = td; - ep->stopped_trb = event_trb; - ep->stopped_stream = stream_id; - - xhci_queue_reset_ep(xhci, slot_id, ep_index); - xhci_cleanup_stalled_ring(xhci, td->urb->dev, ep_index); - - ep->stopped_td = NULL; - ep->stopped_trb = NULL; - ep->stopped_stream = 0; - - xhci_ring_cmd_db(xhci); -} - -/* Check if an error has halted the endpoint ring. The class driver will - * cleanup the halt for a non-default control endpoint if we indicate a stall. - * However, a babble and other errors also halt the endpoint ring, and the class - * driver won't clear the halt in that case, so we need to issue a Set Transfer - * Ring Dequeue Pointer command manually. - */ -static int xhci_requires_manual_halt_cleanup(struct xhci_hcd *xhci, - struct xhci_ep_ctx *ep_ctx, - unsigned int trb_comp_code) -{ - /* TRB completion codes that may require a manual halt cleanup */ - if (trb_comp_code == COMP_TX_ERR || - trb_comp_code == COMP_BABBLE || - trb_comp_code == COMP_SPLIT_ERR) - /* The 0.96 spec says a babbling control endpoint - * is not halted. The 0.96 spec says it is. Some HW - * claims to be 0.95 compliant, but it halts the control - * endpoint anyway. Check if a babble halted the - * endpoint. - */ - if ((ep_ctx->ep_info & cpu_to_le32(EP_STATE_MASK)) == - cpu_to_le32(EP_STATE_HALTED)) - return 1; - - return 0; -} - -int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code) -{ - if (trb_comp_code >= 224 && trb_comp_code <= 255) { - /* Vendor defined "informational" completion code, - * treat as not-an-error. - */ - xhci_dbg(xhci, "Vendor defined info completion code %u\n", - trb_comp_code); - xhci_dbg(xhci, "Treating code as success.\n"); - return 1; - } - return 0; -} - -/* - * Finish the td processing, remove the td from td list; - * Return 1 if the urb can be given back. - */ -static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, - union xhci_trb *event_trb, struct xhci_transfer_event *event, - struct xhci_virt_ep *ep, int *status, bool skip) -{ - struct xhci_virt_device *xdev; - struct xhci_ring *ep_ring; - unsigned int slot_id; - int ep_index; - struct urb *urb = NULL; - struct xhci_ep_ctx *ep_ctx; - int ret = 0; - struct urb_priv *urb_priv; - u32 trb_comp_code; - - slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags)); - xdev = xhci->devs[slot_id]; - ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1; - ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer)); - ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); - trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len)); - - if (skip) - goto td_cleanup; - - if (trb_comp_code == COMP_STOP_INVAL || - trb_comp_code == COMP_STOP) { - /* The Endpoint Stop Command completion will take care of any - * stopped TDs. A stopped TD may be restarted, so don't update - * the ring dequeue pointer or take this TD off any lists yet. - */ - ep->stopped_td = td; - ep->stopped_trb = event_trb; - return 0; - } else { - if (trb_comp_code == COMP_STALL) { - /* The transfer is completed from the driver's - * perspective, but we need to issue a set dequeue - * command for this stalled endpoint to move the dequeue - * pointer past the TD. We can't do that here because - * the halt condition must be cleared first. Let the - * USB class driver clear the stall later. - */ - ep->stopped_td = td; - ep->stopped_trb = event_trb; - ep->stopped_stream = ep_ring->stream_id; - } else if (xhci_requires_manual_halt_cleanup(xhci, - ep_ctx, trb_comp_code)) { - /* Other types of errors halt the endpoint, but the - * class driver doesn't call usb_reset_endpoint() unless - * the error is -EPIPE. Clear the halted status in the - * xHCI hardware manually. - */ - xhci_cleanup_halted_endpoint(xhci, - slot_id, ep_index, ep_ring->stream_id, - td, event_trb); - } else { - /* Update ring dequeue pointer */ - while (ep_ring->dequeue != td->last_trb) - inc_deq(xhci, ep_ring); - inc_deq(xhci, ep_ring); - } - -td_cleanup: - /* Clean up the endpoint's TD list */ - urb = td->urb; - urb_priv = urb->hcpriv; - - /* Do one last check of the actual transfer length. - * If the host controller said we transferred more data than - * the buffer length, urb->actual_length will be a very big - * number (since it's unsigned). Play it safe and say we didn't - * transfer anything. - */ - if (urb->actual_length > urb->transfer_buffer_length) { - xhci_warn(xhci, "URB transfer length is wrong, " - "xHC issue? req. len = %u, " - "act. len = %u\n", - urb->transfer_buffer_length, - urb->actual_length); - urb->actual_length = 0; - if (td->urb->transfer_flags & URB_SHORT_NOT_OK) - *status = -EREMOTEIO; - else - *status = 0; - } - list_del_init(&td->td_list); - /* Was this TD slated to be cancelled but completed anyway? */ - if (!list_empty(&td->cancelled_td_list)) - list_del_init(&td->cancelled_td_list); - - urb_priv->td_cnt++; - /* Giveback the urb when all the tds are completed */ - if (urb_priv->td_cnt == urb_priv->length) { - ret = 1; - if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { - xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs--; - if (xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs - == 0) { - if (xhci->quirks & XHCI_AMD_PLL_FIX) - usb_amd_quirk_pll_enable(); - } - } - } - } - - return ret; -} - -/* - * Process control tds, update urb status and actual_length. - */ -static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, - union xhci_trb *event_trb, struct xhci_transfer_event *event, - struct xhci_virt_ep *ep, int *status) -{ - struct xhci_virt_device *xdev; - struct xhci_ring *ep_ring; - unsigned int slot_id; - int ep_index; - struct xhci_ep_ctx *ep_ctx; - u32 trb_comp_code; - - slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags)); - xdev = xhci->devs[slot_id]; - ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1; - ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer)); - ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); - trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len)); - - switch (trb_comp_code) { - case COMP_SUCCESS: - if (event_trb == ep_ring->dequeue) { - xhci_warn(xhci, "WARN: Success on ctrl setup TRB " - "without IOC set??\n"); - *status = -ESHUTDOWN; - } else if (event_trb != td->last_trb) { - xhci_warn(xhci, "WARN: Success on ctrl data TRB " - "without IOC set??\n"); - *status = -ESHUTDOWN; - } else { - *status = 0; - } - break; - case COMP_SHORT_TX: - if (td->urb->transfer_flags & URB_SHORT_NOT_OK) - *status = -EREMOTEIO; - else - *status = 0; - break; - case COMP_STOP_INVAL: - case COMP_STOP: - return finish_td(xhci, td, event_trb, event, ep, status, false); - default: - if (!xhci_requires_manual_halt_cleanup(xhci, - ep_ctx, trb_comp_code)) - break; - xhci_dbg(xhci, "TRB error code %u, " - "halted endpoint index = %u\n", - trb_comp_code, ep_index); - /* else fall through */ - case COMP_STALL: - /* Did we transfer part of the data (middle) phase? */ - if (event_trb != ep_ring->dequeue && - event_trb != td->last_trb) - td->urb->actual_length = - td->urb->transfer_buffer_length - - TRB_LEN(le32_to_cpu(event->transfer_len)); - else - td->urb->actual_length = 0; - - xhci_cleanup_halted_endpoint(xhci, - slot_id, ep_index, 0, td, event_trb); - return finish_td(xhci, td, event_trb, event, ep, status, true); - } - /* - * Did we transfer any data, despite the errors that might have - * happened? I.e. did we get past the setup stage? - */ - if (event_trb != ep_ring->dequeue) { - /* The event was for the status stage */ - if (event_trb == td->last_trb) { - if (td->urb->actual_length != 0) { - /* Don't overwrite a previously set error code - */ - if ((*status == -EINPROGRESS || *status == 0) && - (td->urb->transfer_flags - & URB_SHORT_NOT_OK)) - /* Did we already see a short data - * stage? */ - *status = -EREMOTEIO; - } else { - td->urb->actual_length = - td->urb->transfer_buffer_length; - } - } else { - /* Maybe the event was for the data stage? */ - td->urb->actual_length = - td->urb->transfer_buffer_length - - TRB_LEN(le32_to_cpu(event->transfer_len)); - xhci_dbg(xhci, "Waiting for status " - "stage event\n"); - return 0; - } - } - - return finish_td(xhci, td, event_trb, event, ep, status, false); -} - -/* - * Process isochronous tds, update urb packet status and actual_length. - */ -static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, - union xhci_trb *event_trb, struct xhci_transfer_event *event, - struct xhci_virt_ep *ep, int *status) -{ - struct xhci_ring *ep_ring; - struct urb_priv *urb_priv; - int idx; - int len = 0; - union xhci_trb *cur_trb; - struct xhci_segment *cur_seg; - struct usb_iso_packet_descriptor *frame; - u32 trb_comp_code; - bool skip_td = false; - - ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer)); - trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len)); - urb_priv = td->urb->hcpriv; - idx = urb_priv->td_cnt; - frame = &td->urb->iso_frame_desc[idx]; - - /* handle completion code */ - switch (trb_comp_code) { - case COMP_SUCCESS: - if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) { - frame->status = 0; - break; - } - if ((xhci->quirks & XHCI_TRUST_TX_LENGTH)) - trb_comp_code = COMP_SHORT_TX; - case COMP_SHORT_TX: - frame->status = td->urb->transfer_flags & URB_SHORT_NOT_OK ? - -EREMOTEIO : 0; - break; - case COMP_BW_OVER: - frame->status = -ECOMM; - skip_td = true; - break; - case COMP_BUFF_OVER: - case COMP_BABBLE: - frame->status = -EOVERFLOW; - skip_td = true; - break; - case COMP_DEV_ERR: - case COMP_STALL: - case COMP_TX_ERR: - frame->status = -EPROTO; - skip_td = true; - break; - case COMP_STOP: - case COMP_STOP_INVAL: - break; - default: - frame->status = -1; - break; - } - - if (trb_comp_code == COMP_SUCCESS || skip_td) { - frame->actual_length = frame->length; - td->urb->actual_length += frame->length; - } else { - for (cur_trb = ep_ring->dequeue, - cur_seg = ep_ring->deq_seg; cur_trb != event_trb; - next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) { - if (!TRB_TYPE_NOOP_LE32(cur_trb->generic.field[3]) && - !TRB_TYPE_LINK_LE32(cur_trb->generic.field[3])) - len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])); - } - len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) - - TRB_LEN(le32_to_cpu(event->transfer_len)); - - if (trb_comp_code != COMP_STOP_INVAL) { - frame->actual_length = len; - td->urb->actual_length += len; - } - } - - return finish_td(xhci, td, event_trb, event, ep, status, false); -} - -static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, - struct xhci_transfer_event *event, - struct xhci_virt_ep *ep, int *status) -{ - struct xhci_ring *ep_ring; - struct urb_priv *urb_priv; - struct usb_iso_packet_descriptor *frame; - int idx; - - ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer)); - urb_priv = td->urb->hcpriv; - idx = urb_priv->td_cnt; - frame = &td->urb->iso_frame_desc[idx]; - - /* The transfer is partly done. */ - frame->status = -EXDEV; - - /* calc actual length */ - frame->actual_length = 0; - - /* Update ring dequeue pointer */ - while (ep_ring->dequeue != td->last_trb) - inc_deq(xhci, ep_ring); - inc_deq(xhci, ep_ring); - - return finish_td(xhci, td, NULL, event, ep, status, true); -} - -/* - * Process bulk and interrupt tds, update urb status and actual_length. - */ -static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, - union xhci_trb *event_trb, struct xhci_transfer_event *event, - struct xhci_virt_ep *ep, int *status) -{ - struct xhci_ring *ep_ring; - union xhci_trb *cur_trb; - struct xhci_segment *cur_seg; - u32 trb_comp_code; - - ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer)); - trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len)); - - switch (trb_comp_code) { - case COMP_SUCCESS: - /* Double check that the HW transferred everything. */ - if (event_trb != td->last_trb || - TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { - xhci_warn(xhci, "WARN Successful completion " - "on short TX\n"); - if (td->urb->transfer_flags & URB_SHORT_NOT_OK) - *status = -EREMOTEIO; - else - *status = 0; - if ((xhci->quirks & XHCI_TRUST_TX_LENGTH)) - trb_comp_code = COMP_SHORT_TX; - } else { - *status = 0; - } - break; - case COMP_SHORT_TX: - if (td->urb->transfer_flags & URB_SHORT_NOT_OK) - *status = -EREMOTEIO; - else - *status = 0; - break; - default: - /* Others already handled above */ - break; - } - if (trb_comp_code == COMP_SHORT_TX) - xhci_dbg(xhci, "ep %#x - asked for %d bytes, " - "%d bytes untransferred\n", - td->urb->ep->desc.bEndpointAddress, - td->urb->transfer_buffer_length, - TRB_LEN(le32_to_cpu(event->transfer_len))); - /* Fast path - was this the last TRB in the TD for this URB? */ - if (event_trb == td->last_trb) { - if (TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { - td->urb->actual_length = - td->urb->transfer_buffer_length - - TRB_LEN(le32_to_cpu(event->transfer_len)); - if (td->urb->transfer_buffer_length < - td->urb->actual_length) { - xhci_warn(xhci, "HC gave bad length " - "of %d bytes left\n", - TRB_LEN(le32_to_cpu(event->transfer_len))); - td->urb->actual_length = 0; - if (td->urb->transfer_flags & URB_SHORT_NOT_OK) - *status = -EREMOTEIO; - else - *status = 0; - } - /* Don't overwrite a previously set error code */ - if (*status == -EINPROGRESS) { - if (td->urb->transfer_flags & URB_SHORT_NOT_OK) - *status = -EREMOTEIO; - else - *status = 0; - } - } else { - td->urb->actual_length = - td->urb->transfer_buffer_length; - /* Ignore a short packet completion if the - * untransferred length was zero. - */ - if (*status == -EREMOTEIO) - *status = 0; - } - } else { - /* Slow path - walk the list, starting from the dequeue - * pointer, to get the actual length transferred. - */ - td->urb->actual_length = 0; - for (cur_trb = ep_ring->dequeue, cur_seg = ep_ring->deq_seg; - cur_trb != event_trb; - next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) { - if (!TRB_TYPE_NOOP_LE32(cur_trb->generic.field[3]) && - !TRB_TYPE_LINK_LE32(cur_trb->generic.field[3])) - td->urb->actual_length += - TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])); - } - /* If the ring didn't stop on a Link or No-op TRB, add - * in the actual bytes transferred from the Normal TRB - */ - if (trb_comp_code != COMP_STOP_INVAL) - td->urb->actual_length += - TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) - - TRB_LEN(le32_to_cpu(event->transfer_len)); - } - - return finish_td(xhci, td, event_trb, event, ep, status, false); -} - -/* - * If this function returns an error condition, it means it got a Transfer - * event with a corrupted Slot ID, Endpoint ID, or TRB DMA address. - * At this point, the host controller is probably hosed and should be reset. - */ -static int handle_tx_event(struct xhci_hcd *xhci, - struct xhci_transfer_event *event) -{ - struct xhci_virt_device *xdev; - struct xhci_virt_ep *ep; - struct xhci_ring *ep_ring; - unsigned int slot_id; - int ep_index; - struct xhci_td *td = NULL; - dma_addr_t event_dma; - struct xhci_segment *event_seg; - union xhci_trb *event_trb; - struct urb *urb = NULL; - int status = -EINPROGRESS; - struct urb_priv *urb_priv; - struct xhci_ep_ctx *ep_ctx; - struct list_head *tmp; - u32 trb_comp_code; - int ret = 0; - int td_num = 0; - - slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags)); - xdev = xhci->devs[slot_id]; - if (!xdev) { - xhci_err(xhci, "ERROR Transfer event pointed to bad slot\n"); - xhci_err(xhci, "@%016llx %08x %08x %08x %08x\n", - (unsigned long long) xhci_trb_virt_to_dma( - xhci->event_ring->deq_seg, - xhci->event_ring->dequeue), - lower_32_bits(le64_to_cpu(event->buffer)), - upper_32_bits(le64_to_cpu(event->buffer)), - le32_to_cpu(event->transfer_len), - le32_to_cpu(event->flags)); - xhci_dbg(xhci, "Event ring:\n"); - xhci_debug_segment(xhci, xhci->event_ring->deq_seg); - return -ENODEV; - } - - /* Endpoint ID is 1 based, our index is zero based */ - ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1; - ep = &xdev->eps[ep_index]; - ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer)); - ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); - if (!ep_ring || - (le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK) == - EP_STATE_DISABLED) { - xhci_err(xhci, "ERROR Transfer event for disabled endpoint " - "or incorrect stream ring\n"); - xhci_err(xhci, "@%016llx %08x %08x %08x %08x\n", - (unsigned long long) xhci_trb_virt_to_dma( - xhci->event_ring->deq_seg, - xhci->event_ring->dequeue), - lower_32_bits(le64_to_cpu(event->buffer)), - upper_32_bits(le64_to_cpu(event->buffer)), - le32_to_cpu(event->transfer_len), - le32_to_cpu(event->flags)); - xhci_dbg(xhci, "Event ring:\n"); - xhci_debug_segment(xhci, xhci->event_ring->deq_seg); - return -ENODEV; - } - - /* Count current td numbers if ep->skip is set */ - if (ep->skip) { - list_for_each(tmp, &ep_ring->td_list) - td_num++; - } - - event_dma = le64_to_cpu(event->buffer); - trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len)); - /* Look for common error cases */ - switch (trb_comp_code) { - /* Skip codes that require special handling depending on - * transfer type - */ - case COMP_SUCCESS: - if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) - break; - if (xhci->quirks & XHCI_TRUST_TX_LENGTH) - trb_comp_code = COMP_SHORT_TX; - else - xhci_warn(xhci, "WARN Successful completion on short TX: " - "needs XHCI_TRUST_TX_LENGTH quirk?\n"); - case COMP_SHORT_TX: - break; - case COMP_STOP: - xhci_dbg(xhci, "Stopped on Transfer TRB\n"); - break; - case COMP_STOP_INVAL: - xhci_dbg(xhci, "Stopped on No-op or Link TRB\n"); - break; - case COMP_STALL: - xhci_dbg(xhci, "Stalled endpoint\n"); - ep->ep_state |= EP_HALTED; - status = -EPIPE; - break; - case COMP_TRB_ERR: - xhci_warn(xhci, "WARN: TRB error on endpoint\n"); - status = -EILSEQ; - break; - case COMP_SPLIT_ERR: - case COMP_TX_ERR: - xhci_dbg(xhci, "Transfer error on endpoint\n"); - status = -EPROTO; - break; - case COMP_BABBLE: - xhci_dbg(xhci, "Babble error on endpoint\n"); - status = -EOVERFLOW; - break; - case COMP_DB_ERR: - xhci_warn(xhci, "WARN: HC couldn't access mem fast enough\n"); - status = -ENOSR; - break; - case COMP_BW_OVER: - xhci_warn(xhci, "WARN: bandwidth overrun event on endpoint\n"); - break; - case COMP_BUFF_OVER: - xhci_warn(xhci, "WARN: buffer overrun event on endpoint\n"); - break; - case COMP_UNDERRUN: - /* - * When the Isoch ring is empty, the xHC will generate - * a Ring Overrun Event for IN Isoch endpoint or Ring - * Underrun Event for OUT Isoch endpoint. - */ - xhci_dbg(xhci, "underrun event on endpoint\n"); - if (!list_empty(&ep_ring->td_list)) - xhci_dbg(xhci, "Underrun Event for slot %d ep %d " - "still with TDs queued?\n", - TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), - ep_index); - goto cleanup; - case COMP_OVERRUN: - xhci_dbg(xhci, "overrun event on endpoint\n"); - if (!list_empty(&ep_ring->td_list)) - xhci_dbg(xhci, "Overrun Event for slot %d ep %d " - "still with TDs queued?\n", - TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), - ep_index); - goto cleanup; - case COMP_DEV_ERR: - xhci_warn(xhci, "WARN: detect an incompatible device"); - status = -EPROTO; - break; - case COMP_MISSED_INT: - /* - * When encounter missed service error, one or more isoc tds - * may be missed by xHC. - * Set skip flag of the ep_ring; Complete the missed tds as - * short transfer when process the ep_ring next time. - */ - ep->skip = true; - xhci_dbg(xhci, "Miss service interval error, set skip flag\n"); - goto cleanup; - default: - if (xhci_is_vendor_info_code(xhci, trb_comp_code)) { - status = 0; - break; - } - xhci_warn(xhci, "ERROR Unknown event condition, HC probably " - "busted\n"); - goto cleanup; - } - - do { - /* This TRB should be in the TD at the head of this ring's - * TD list. - */ - if (list_empty(&ep_ring->td_list)) { - xhci_warn(xhci, "WARN Event TRB for slot %d ep %d " - "with no TDs queued?\n", - TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), - ep_index); - xhci_dbg(xhci, "Event TRB with TRB type ID %u\n", - (le32_to_cpu(event->flags) & - TRB_TYPE_BITMASK)>>10); - xhci_print_trb_offsets(xhci, (union xhci_trb *) event); - if (ep->skip) { - ep->skip = false; - xhci_dbg(xhci, "td_list is empty while skip " - "flag set. Clear skip flag.\n"); - } - ret = 0; - goto cleanup; - } - - /* We've skipped all the TDs on the ep ring when ep->skip set */ - if (ep->skip && td_num == 0) { - ep->skip = false; - xhci_dbg(xhci, "All tds on the ep_ring skipped. " - "Clear skip flag.\n"); - ret = 0; - goto cleanup; - } - - td = list_entry(ep_ring->td_list.next, struct xhci_td, td_list); - if (ep->skip) - td_num--; - - /* Is this a TRB in the currently executing TD? */ - event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue, - td->last_trb, event_dma); - - /* - * Skip the Force Stopped Event. The event_trb(event_dma) of FSE - * is not in the current TD pointed by ep_ring->dequeue because - * that the hardware dequeue pointer still at the previous TRB - * of the current TD. The previous TRB maybe a Link TD or the - * last TRB of the previous TD. The command completion handle - * will take care the rest. - */ - if (!event_seg && trb_comp_code == COMP_STOP_INVAL) { - ret = 0; - goto cleanup; - } - - if (!event_seg) { - if (!ep->skip || - !usb_endpoint_xfer_isoc(&td->urb->ep->desc)) { - /* Some host controllers give a spurious - * successful event after a short transfer. - * Ignore it. - */ - if ((xhci->quirks & XHCI_SPURIOUS_SUCCESS) && - ep_ring->last_td_was_short) { - ep_ring->last_td_was_short = false; - ret = 0; - goto cleanup; - } - /* HC is busted, give up! */ - xhci_err(xhci, - "ERROR Transfer event TRB DMA ptr not " - "part of current TD\n"); - return -ESHUTDOWN; - } - - ret = skip_isoc_td(xhci, td, event, ep, &status); - goto cleanup; - } - if (trb_comp_code == COMP_SHORT_TX) - ep_ring->last_td_was_short = true; - else - ep_ring->last_td_was_short = false; - - if (ep->skip) { - xhci_dbg(xhci, "Found td. Clear skip flag.\n"); - ep->skip = false; - } - - event_trb = &event_seg->trbs[(event_dma - event_seg->dma) / - sizeof(*event_trb)]; - /* - * No-op TRB should not trigger interrupts. - * If event_trb is a no-op TRB, it means the - * corresponding TD has been cancelled. Just ignore - * the TD. - */ - if (TRB_TYPE_NOOP_LE32(event_trb->generic.field[3])) { - xhci_dbg(xhci, - "event_trb is a no-op TRB. Skip it\n"); - goto cleanup; - } - - /* Now update the urb's actual_length and give back to - * the core - */ - if (usb_endpoint_xfer_control(&td->urb->ep->desc)) - ret = process_ctrl_td(xhci, td, event_trb, event, ep, - &status); - else if (usb_endpoint_xfer_isoc(&td->urb->ep->desc)) - ret = process_isoc_td(xhci, td, event_trb, event, ep, - &status); - else - ret = process_bulk_intr_td(xhci, td, event_trb, event, - ep, &status); - -cleanup: - /* - * Do not update event ring dequeue pointer if ep->skip is set. - * Will roll back to continue process missed tds. - */ - if (trb_comp_code == COMP_MISSED_INT || !ep->skip) { - inc_deq(xhci, xhci->event_ring); - } - - if (ret) { - urb = td->urb; - urb_priv = urb->hcpriv; - /* Leave the TD around for the reset endpoint function - * to use(but only if it's not a control endpoint, - * since we already queued the Set TR dequeue pointer - * command for stalled control endpoints). - */ - if (usb_endpoint_xfer_control(&urb->ep->desc) || - (trb_comp_code != COMP_STALL && - trb_comp_code != COMP_BABBLE)) - xhci_urb_free_priv(xhci, urb_priv); - - usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb); - if ((urb->actual_length != urb->transfer_buffer_length && - (urb->transfer_flags & - URB_SHORT_NOT_OK)) || - (status != 0 && - !usb_endpoint_xfer_isoc(&urb->ep->desc))) - xhci_dbg(xhci, "Giveback URB %p, len = %d, " - "expected = %x, status = %d\n", - urb, urb->actual_length, - urb->transfer_buffer_length, - status); - spin_unlock(&xhci->lock); - /* EHCI, UHCI, and OHCI always unconditionally set the - * urb->status of an isochronous endpoint to 0. - */ - if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) - status = 0; - usb_hcd_giveback_urb(bus_to_hcd(urb->dev->bus), urb, status); - spin_lock(&xhci->lock); - } - - /* - * If ep->skip is set, it means there are missed tds on the - * endpoint ring need to take care of. - * Process them as short transfer until reach the td pointed by - * the event. - */ - } while (ep->skip && trb_comp_code != COMP_MISSED_INT); - - return 0; -} - -/* - * This function handles all OS-owned events on the event ring. It may drop - * xhci->lock between event processing (e.g. to pass up port status changes). - * Returns >0 for "possibly more events to process" (caller should call again), - * otherwise 0 if done. In future, <0 returns should indicate error code. - */ -static int xhci_handle_event(struct xhci_hcd *xhci) -{ - union xhci_trb *event; - int update_ptrs = 1; - int ret; - - if (!xhci->event_ring || !xhci->event_ring->dequeue) { - xhci->error_bitmask |= 1 << 1; - return 0; - } - - event = xhci->event_ring->dequeue; - /* Does the HC or OS own the TRB? */ - if ((le32_to_cpu(event->event_cmd.flags) & TRB_CYCLE) != - xhci->event_ring->cycle_state) { - xhci->error_bitmask |= 1 << 2; - return 0; - } - - /* - * Barrier between reading the TRB_CYCLE (valid) flag above and any - * speculative reads of the event's flags/data below. - */ - rmb(); - /* FIXME: Handle more event types. */ - switch ((le32_to_cpu(event->event_cmd.flags) & TRB_TYPE_BITMASK)) { - case TRB_TYPE(TRB_COMPLETION): - handle_cmd_completion(xhci, &event->event_cmd); - break; - case TRB_TYPE(TRB_PORT_STATUS): - handle_port_status(xhci, event); - update_ptrs = 0; - break; - case TRB_TYPE(TRB_TRANSFER): - ret = handle_tx_event(xhci, &event->trans_event); - if (ret < 0) - xhci->error_bitmask |= 1 << 9; - else - update_ptrs = 0; - break; - case TRB_TYPE(TRB_DEV_NOTE): - handle_device_notification(xhci, event); - break; - default: - if ((le32_to_cpu(event->event_cmd.flags) & TRB_TYPE_BITMASK) >= - TRB_TYPE(48)) - handle_vendor_event(xhci, event); - else - xhci->error_bitmask |= 1 << 3; - } - /* Any of the above functions may drop and re-acquire the lock, so check - * to make sure a watchdog timer didn't mark the host as non-responsive. - */ - if (xhci->xhc_state & XHCI_STATE_DYING) { - xhci_dbg(xhci, "xHCI host dying, returning from " - "event handler.\n"); - return 0; - } - - if (update_ptrs) - /* Update SW event ring dequeue pointer */ - inc_deq(xhci, xhci->event_ring); - - /* Are there more items on the event ring? Caller will call us again to - * check. - */ - return 1; -} - -/* - * xHCI spec says we can get an interrupt, and if the HC has an error condition, - * we might get bad data out of the event ring. Section 4.10.2.7 has a list of - * indicators of an event TRB error, but we check the status *first* to be safe. - */ -irqreturn_t xhci_irq(struct usb_hcd *hcd) -{ - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - u32 status; - union xhci_trb *trb; - u64 temp_64; - union xhci_trb *event_ring_deq; - dma_addr_t deq; - - spin_lock(&xhci->lock); - trb = xhci->event_ring->dequeue; - /* Check if the xHC generated the interrupt, or the irq is shared */ - status = xhci_readl(xhci, &xhci->op_regs->status); - if (status == 0xffffffff) - goto hw_died; - - if (!(status & STS_EINT)) { - spin_unlock(&xhci->lock); - return IRQ_NONE; - } - if (status & STS_FATAL) { - xhci_warn(xhci, "WARNING: Host System Error\n"); - xhci_halt(xhci); -hw_died: - spin_unlock(&xhci->lock); - return -ESHUTDOWN; - } - - /* - * Clear the op reg interrupt status first, - * so we can receive interrupts from other MSI-X interrupters. - * Write 1 to clear the interrupt status. - */ - status |= STS_EINT; - xhci_writel(xhci, status, &xhci->op_regs->status); - /* FIXME when MSI-X is supported and there are multiple vectors */ - /* Clear the MSI-X event interrupt status */ - - if (hcd->irq) { - u32 irq_pending; - /* Acknowledge the PCI interrupt */ - irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending); - irq_pending |= IMAN_IP; - xhci_writel(xhci, irq_pending, &xhci->ir_set->irq_pending); - } - - if (xhci->xhc_state & XHCI_STATE_DYING) { - xhci_dbg(xhci, "xHCI dying, ignoring interrupt. " - "Shouldn't IRQs be disabled?\n"); - /* Clear the event handler busy flag (RW1C); - * the event ring should be empty. - */ - temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); - xhci_write_64(xhci, temp_64 | ERST_EHB, - &xhci->ir_set->erst_dequeue); - spin_unlock(&xhci->lock); - - return IRQ_HANDLED; - } - - event_ring_deq = xhci->event_ring->dequeue; - /* FIXME this should be a delayed service routine - * that clears the EHB. - */ - while (xhci_handle_event(xhci) > 0) {} - - temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); - /* If necessary, update the HW's version of the event ring deq ptr. */ - if (event_ring_deq != xhci->event_ring->dequeue) { - deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, - xhci->event_ring->dequeue); - if (deq == 0) - xhci_warn(xhci, "WARN something wrong with SW event " - "ring dequeue ptr.\n"); - /* Update HC event ring dequeue pointer */ - temp_64 &= ERST_PTR_MASK; - temp_64 |= ((u64) deq & (u64) ~ERST_PTR_MASK); - } - - /* Clear the event handler busy flag (RW1C); event ring is empty. */ - temp_64 |= ERST_EHB; - xhci_write_64(xhci, temp_64, &xhci->ir_set->erst_dequeue); - - spin_unlock(&xhci->lock); - - return IRQ_HANDLED; -} - -irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd) -{ - return xhci_irq(hcd); -} - -/**** Endpoint Ring Operations ****/ - -/* - * Generic function for queueing a TRB on a ring. - * The caller must have checked to make sure there's room on the ring. - * - * @more_trbs_coming: Will you enqueue more TRBs before calling - * prepare_transfer()? - */ -static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring, - bool more_trbs_coming, - u32 field1, u32 field2, u32 field3, u32 field4) -{ - struct xhci_generic_trb *trb; - - trb = &ring->enqueue->generic; - trb->field[0] = cpu_to_le32(field1); - trb->field[1] = cpu_to_le32(field2); - trb->field[2] = cpu_to_le32(field3); - trb->field[3] = cpu_to_le32(field4); - inc_enq(xhci, ring, more_trbs_coming); -} - -/* - * Does various checks on the endpoint ring, and makes it ready to queue num_trbs. - * FIXME allocate segments if the ring is full. - */ -static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, - u32 ep_state, unsigned int num_trbs, gfp_t mem_flags) -{ - unsigned int num_trbs_needed; - - /* Make sure the endpoint has been added to xHC schedule */ - switch (ep_state) { - case EP_STATE_DISABLED: - /* - * USB core changed config/interfaces without notifying us, - * or hardware is reporting the wrong state. - */ - xhci_warn(xhci, "WARN urb submitted to disabled ep\n"); - return -ENOENT; - case EP_STATE_ERROR: - xhci_warn(xhci, "WARN waiting for error on ep to be cleared\n"); - /* FIXME event handling code for error needs to clear it */ - /* XXX not sure if this should be -ENOENT or not */ - return -EINVAL; - case EP_STATE_HALTED: - xhci_dbg(xhci, "WARN halted endpoint, queueing URB anyway.\n"); - case EP_STATE_STOPPED: - case EP_STATE_RUNNING: - break; - default: - xhci_err(xhci, "ERROR unknown endpoint state for ep\n"); - /* - * FIXME issue Configure Endpoint command to try to get the HC - * back into a known state. - */ - return -EINVAL; - } - - while (1) { - if (room_on_ring(xhci, ep_ring, num_trbs)) - break; - - if (ep_ring == xhci->cmd_ring) { - xhci_err(xhci, "Do not support expand command ring\n"); - return -ENOMEM; - } - - xhci_dbg(xhci, "ERROR no room on ep ring, " - "try ring expansion\n"); - num_trbs_needed = num_trbs - ep_ring->num_trbs_free; - if (xhci_ring_expansion(xhci, ep_ring, num_trbs_needed, - mem_flags)) { - xhci_err(xhci, "Ring expansion failed\n"); - return -ENOMEM; - } - }; - - if (enqueue_is_link_trb(ep_ring)) { - struct xhci_ring *ring = ep_ring; - union xhci_trb *next; - - next = ring->enqueue; - - while (last_trb(xhci, ring, ring->enq_seg, next)) { - /* If we're not dealing with 0.95 hardware or isoc rings - * on AMD 0.96 host, clear the chain bit. - */ - if (!xhci_link_trb_quirk(xhci) && - !(ring->type == TYPE_ISOC && - (xhci->quirks & XHCI_AMD_0x96_HOST))) - next->link.control &= cpu_to_le32(~TRB_CHAIN); - else - next->link.control |= cpu_to_le32(TRB_CHAIN); - - wmb(); - next->link.control ^= cpu_to_le32(TRB_CYCLE); - - /* Toggle the cycle bit after the last ring segment. */ - if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) { - ring->cycle_state = (ring->cycle_state ? 0 : 1); - } - ring->enq_seg = ring->enq_seg->next; - ring->enqueue = ring->enq_seg->trbs; - next = ring->enqueue; - } - } - - return 0; -} - -static int prepare_transfer(struct xhci_hcd *xhci, - struct xhci_virt_device *xdev, - unsigned int ep_index, - unsigned int stream_id, - unsigned int num_trbs, - struct urb *urb, - unsigned int td_index, - gfp_t mem_flags) -{ - int ret; - struct urb_priv *urb_priv; - struct xhci_td *td; - struct xhci_ring *ep_ring; - struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); - - ep_ring = xhci_stream_id_to_ring(xdev, ep_index, stream_id); - if (!ep_ring) { - xhci_dbg(xhci, "Can't prepare ring for bad stream ID %u\n", - stream_id); - return -EINVAL; - } - - ret = prepare_ring(xhci, ep_ring, - le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK, - num_trbs, mem_flags); - if (ret) - return ret; - - urb_priv = urb->hcpriv; - td = urb_priv->td[td_index]; - - INIT_LIST_HEAD(&td->td_list); - INIT_LIST_HEAD(&td->cancelled_td_list); - - if (td_index == 0) { - ret = usb_hcd_link_urb_to_ep(bus_to_hcd(urb->dev->bus), urb); - if (unlikely(ret)) - return ret; - } - - td->urb = urb; - /* Add this TD to the tail of the endpoint ring's TD list */ - list_add_tail(&td->td_list, &ep_ring->td_list); - td->start_seg = ep_ring->enq_seg; - td->first_trb = ep_ring->enqueue; - - urb_priv->td[td_index] = td; - - return 0; -} - -static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb *urb) -{ - int num_sgs, num_trbs, running_total, temp, i; - struct scatterlist *sg; - - sg = NULL; - num_sgs = urb->num_mapped_sgs; - temp = urb->transfer_buffer_length; - - num_trbs = 0; - for_each_sg(urb->sg, sg, num_sgs, i) { - unsigned int len = sg_dma_len(sg); - - /* Scatter gather list entries may cross 64KB boundaries */ - running_total = TRB_MAX_BUFF_SIZE - - (sg_dma_address(sg) & (TRB_MAX_BUFF_SIZE - 1)); - running_total &= TRB_MAX_BUFF_SIZE - 1; - if (running_total != 0) - num_trbs++; - - /* How many more 64KB chunks to transfer, how many more TRBs? */ - while (running_total < sg_dma_len(sg) && running_total < temp) { - num_trbs++; - running_total += TRB_MAX_BUFF_SIZE; - } - len = min_t(int, len, temp); - temp -= len; - if (temp == 0) - break; - } - return num_trbs; -} - -static void check_trb_math(struct urb *urb, int num_trbs, int running_total) -{ - if (num_trbs != 0) - dev_err(&urb->dev->dev, "%s - ep %#x - Miscalculated number of " - "TRBs, %d left\n", __func__, - urb->ep->desc.bEndpointAddress, num_trbs); - if (running_total != urb->transfer_buffer_length) - dev_err(&urb->dev->dev, "%s - ep %#x - Miscalculated tx length, " - "queued %#x (%d), asked for %#x (%d)\n", - __func__, - urb->ep->desc.bEndpointAddress, - running_total, running_total, - urb->transfer_buffer_length, - urb->transfer_buffer_length); -} - -static void giveback_first_trb(struct xhci_hcd *xhci, int slot_id, - unsigned int ep_index, unsigned int stream_id, int start_cycle, - struct xhci_generic_trb *start_trb) -{ - /* - * Pass all the TRBs to the hardware at once and make sure this write - * isn't reordered. - */ - wmb(); - if (start_cycle) - start_trb->field[3] |= cpu_to_le32(start_cycle); - else - start_trb->field[3] &= cpu_to_le32(~TRB_CYCLE); - xhci_ring_ep_doorbell(xhci, slot_id, ep_index, stream_id); -} - -/* - * xHCI uses normal TRBs for both bulk and interrupt. When the interrupt - * endpoint is to be serviced, the xHC will consume (at most) one TD. A TD - * (comprised of sg list entries) can take several service intervals to - * transmit. - */ -int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags, - struct urb *urb, int slot_id, unsigned int ep_index) -{ - struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, - xhci->devs[slot_id]->out_ctx, ep_index); - int xhci_interval; - int ep_interval; - - xhci_interval = EP_INTERVAL_TO_UFRAMES(le32_to_cpu(ep_ctx->ep_info)); - ep_interval = urb->interval; - /* Convert to microframes */ - if (urb->dev->speed == USB_SPEED_LOW || - urb->dev->speed == USB_SPEED_FULL) - ep_interval *= 8; - /* FIXME change this to a warning and a suggestion to use the new API - * to set the polling interval (once the API is added). - */ - if (xhci_interval != ep_interval) { - if (printk_ratelimit()) - dev_dbg(&urb->dev->dev, "Driver uses different interval" - " (%d microframe%s) than xHCI " - "(%d microframe%s)\n", - ep_interval, - ep_interval == 1 ? "" : "s", - xhci_interval, - xhci_interval == 1 ? "" : "s"); - urb->interval = xhci_interval; - /* Convert back to frames for LS/FS devices */ - if (urb->dev->speed == USB_SPEED_LOW || - urb->dev->speed == USB_SPEED_FULL) - urb->interval /= 8; - } - return xhci_queue_bulk_tx(xhci, mem_flags, urb, slot_id, ep_index); -} - -/* - * The TD size is the number of bytes remaining in the TD (including this TRB), - * right shifted by 10. - * It must fit in bits 21:17, so it can't be bigger than 31. - */ -static u32 xhci_td_remainder(unsigned int remainder) -{ - u32 max = (1 << (21 - 17 + 1)) - 1; - - if ((remainder >> 10) >= max) - return max << 17; - else - return (remainder >> 10) << 17; -} - -/* - * For xHCI 1.0 host controllers, TD size is the number of packets remaining in - * the TD (*not* including this TRB). - * - * Total TD packet count = total_packet_count = - * roundup(TD size in bytes / wMaxPacketSize) - * - * Packets transferred up to and including this TRB = packets_transferred = - * rounddown(total bytes transferred including this TRB / wMaxPacketSize) - * - * TD size = total_packet_count - packets_transferred - * - * It must fit in bits 21:17, so it can't be bigger than 31. - */ - -static u32 xhci_v1_0_td_remainder(int running_total, int trb_buff_len, - unsigned int total_packet_count, struct urb *urb) -{ - int packets_transferred; - - /* One TRB with a zero-length data packet. */ - if (running_total == 0 && trb_buff_len == 0) - return 0; - - /* All the TRB queueing functions don't count the current TRB in - * running_total. - */ - packets_transferred = (running_total + trb_buff_len) / - usb_endpoint_maxp(&urb->ep->desc); - - return xhci_td_remainder(total_packet_count - packets_transferred); -} - -static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, - struct urb *urb, int slot_id, unsigned int ep_index) -{ - struct xhci_ring *ep_ring; - unsigned int num_trbs; - struct urb_priv *urb_priv; - struct xhci_td *td; - struct scatterlist *sg; - int num_sgs; - int trb_buff_len, this_sg_len, running_total; - unsigned int total_packet_count; - bool first_trb; - u64 addr; - bool more_trbs_coming; - - struct xhci_generic_trb *start_trb; - int start_cycle; - - ep_ring = xhci_urb_to_transfer_ring(xhci, urb); - if (!ep_ring) - return -EINVAL; - - num_trbs = count_sg_trbs_needed(xhci, urb); - num_sgs = urb->num_mapped_sgs; - total_packet_count = roundup(urb->transfer_buffer_length, - usb_endpoint_maxp(&urb->ep->desc)); - - trb_buff_len = prepare_transfer(xhci, xhci->devs[slot_id], - ep_index, urb->stream_id, - num_trbs, urb, 0, mem_flags); - if (trb_buff_len < 0) - return trb_buff_len; - - urb_priv = urb->hcpriv; - td = urb_priv->td[0]; - - /* - * Don't give the first TRB to the hardware (by toggling the cycle bit) - * until we've finished creating all the other TRBs. The ring's cycle - * state may change as we enqueue the other TRBs, so save it too. - */ - start_trb = &ep_ring->enqueue->generic; - start_cycle = ep_ring->cycle_state; - - running_total = 0; - /* - * How much data is in the first TRB? - * - * There are three forces at work for TRB buffer pointers and lengths: - * 1. We don't want to walk off the end of this sg-list entry buffer. - * 2. The transfer length that the driver requested may be smaller than - * the amount of memory allocated for this scatter-gather list. - * 3. TRBs buffers can't cross 64KB boundaries. - */ - sg = urb->sg; - addr = (u64) sg_dma_address(sg); - this_sg_len = sg_dma_len(sg); - trb_buff_len = TRB_MAX_BUFF_SIZE - (addr & (TRB_MAX_BUFF_SIZE - 1)); - trb_buff_len = min_t(int, trb_buff_len, this_sg_len); - if (trb_buff_len > urb->transfer_buffer_length) - trb_buff_len = urb->transfer_buffer_length; - - first_trb = true; - /* Queue the first TRB, even if it's zero-length */ - do { - u32 field = 0; - u32 length_field = 0; - u32 remainder = 0; - - /* Don't change the cycle bit of the first TRB until later */ - if (first_trb) { - first_trb = false; - if (start_cycle == 0) - field |= 0x1; - } else - field |= ep_ring->cycle_state; - - /* Chain all the TRBs together; clear the chain bit in the last - * TRB to indicate it's the last TRB in the chain. - */ - if (num_trbs > 1) { - field |= TRB_CHAIN; - } else { - /* FIXME - add check for ZERO_PACKET flag before this */ - td->last_trb = ep_ring->enqueue; - field |= TRB_IOC; - } - - /* Only set interrupt on short packet for IN endpoints */ - if (usb_urb_dir_in(urb)) - field |= TRB_ISP; - - if (TRB_MAX_BUFF_SIZE - - (addr & (TRB_MAX_BUFF_SIZE - 1)) < trb_buff_len) { - xhci_warn(xhci, "WARN: sg dma xfer crosses 64KB boundaries!\n"); - xhci_dbg(xhci, "Next boundary at %#x, end dma = %#x\n", - (unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1), - (unsigned int) addr + trb_buff_len); - } - - /* Set the TRB length, TD size, and interrupter fields. */ - if (xhci->hci_version < 0x100) { - remainder = xhci_td_remainder( - urb->transfer_buffer_length - - running_total); - } else { - remainder = xhci_v1_0_td_remainder(running_total, - trb_buff_len, total_packet_count, urb); - } - length_field = TRB_LEN(trb_buff_len) | - remainder | - TRB_INTR_TARGET(0); - - if (num_trbs > 1) - more_trbs_coming = true; - else - more_trbs_coming = false; - queue_trb(xhci, ep_ring, more_trbs_coming, - lower_32_bits(addr), - upper_32_bits(addr), - length_field, - field | TRB_TYPE(TRB_NORMAL)); - --num_trbs; - running_total += trb_buff_len; - - /* Calculate length for next transfer -- - * Are we done queueing all the TRBs for this sg entry? - */ - this_sg_len -= trb_buff_len; - if (this_sg_len == 0) { - --num_sgs; - if (num_sgs == 0) - break; - sg = sg_next(sg); - addr = (u64) sg_dma_address(sg); - this_sg_len = sg_dma_len(sg); - } else { - addr += trb_buff_len; - } - - trb_buff_len = TRB_MAX_BUFF_SIZE - - (addr & (TRB_MAX_BUFF_SIZE - 1)); - trb_buff_len = min_t(int, trb_buff_len, this_sg_len); - if (running_total + trb_buff_len > urb->transfer_buffer_length) - trb_buff_len = - urb->transfer_buffer_length - running_total; - } while (running_total < urb->transfer_buffer_length); - - check_trb_math(urb, num_trbs, running_total); - giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, - start_cycle, start_trb); - return 0; -} - -/* This is very similar to what ehci-q.c qtd_fill() does */ -int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, - struct urb *urb, int slot_id, unsigned int ep_index) -{ - struct xhci_ring *ep_ring; - struct urb_priv *urb_priv; - struct xhci_td *td; - int num_trbs; - struct xhci_generic_trb *start_trb; - bool first_trb; - bool more_trbs_coming; - int start_cycle; - u32 field, length_field; - - int running_total, trb_buff_len, ret; - unsigned int total_packet_count; - u64 addr; - - if (urb->num_sgs) - return queue_bulk_sg_tx(xhci, mem_flags, urb, slot_id, ep_index); - - ep_ring = xhci_urb_to_transfer_ring(xhci, urb); - if (!ep_ring) - return -EINVAL; - - num_trbs = 0; - /* How much data is (potentially) left before the 64KB boundary? */ - running_total = TRB_MAX_BUFF_SIZE - - (urb->transfer_dma & (TRB_MAX_BUFF_SIZE - 1)); - running_total &= TRB_MAX_BUFF_SIZE - 1; - - /* If there's some data on this 64KB chunk, or we have to send a - * zero-length transfer, we need at least one TRB - */ - if (running_total != 0 || urb->transfer_buffer_length == 0) - num_trbs++; - /* How many more 64KB chunks to transfer, how many more TRBs? */ - while (running_total < urb->transfer_buffer_length) { - num_trbs++; - running_total += TRB_MAX_BUFF_SIZE; - } - /* FIXME: this doesn't deal with URB_ZERO_PACKET - need one more */ - - ret = prepare_transfer(xhci, xhci->devs[slot_id], - ep_index, urb->stream_id, - num_trbs, urb, 0, mem_flags); - if (ret < 0) - return ret; - - urb_priv = urb->hcpriv; - td = urb_priv->td[0]; - - /* - * Don't give the first TRB to the hardware (by toggling the cycle bit) - * until we've finished creating all the other TRBs. The ring's cycle - * state may change as we enqueue the other TRBs, so save it too. - */ - start_trb = &ep_ring->enqueue->generic; - start_cycle = ep_ring->cycle_state; - - running_total = 0; - total_packet_count = roundup(urb->transfer_buffer_length, - usb_endpoint_maxp(&urb->ep->desc)); - /* How much data is in the first TRB? */ - addr = (u64) urb->transfer_dma; - trb_buff_len = TRB_MAX_BUFF_SIZE - - (urb->transfer_dma & (TRB_MAX_BUFF_SIZE - 1)); - if (trb_buff_len > urb->transfer_buffer_length) - trb_buff_len = urb->transfer_buffer_length; - - first_trb = true; - - /* Queue the first TRB, even if it's zero-length */ - do { - u32 remainder = 0; - field = 0; - - /* Don't change the cycle bit of the first TRB until later */ - if (first_trb) { - first_trb = false; - if (start_cycle == 0) - field |= 0x1; - } else - field |= ep_ring->cycle_state; - - /* Chain all the TRBs together; clear the chain bit in the last - * TRB to indicate it's the last TRB in the chain. - */ - if (num_trbs > 1) { - field |= TRB_CHAIN; - } else { - /* FIXME - add check for ZERO_PACKET flag before this */ - td->last_trb = ep_ring->enqueue; - field |= TRB_IOC; - } - - /* Only set interrupt on short packet for IN endpoints */ - if (usb_urb_dir_in(urb)) - field |= TRB_ISP; - - /* Set the TRB length, TD size, and interrupter fields. */ - if (xhci->hci_version < 0x100) { - remainder = xhci_td_remainder( - urb->transfer_buffer_length - - running_total); - } else { - remainder = xhci_v1_0_td_remainder(running_total, - trb_buff_len, total_packet_count, urb); - } - length_field = TRB_LEN(trb_buff_len) | - remainder | - TRB_INTR_TARGET(0); - - if (num_trbs > 1) - more_trbs_coming = true; - else - more_trbs_coming = false; - queue_trb(xhci, ep_ring, more_trbs_coming, - lower_32_bits(addr), - upper_32_bits(addr), - length_field, - field | TRB_TYPE(TRB_NORMAL)); - --num_trbs; - running_total += trb_buff_len; - - /* Calculate length for next transfer */ - addr += trb_buff_len; - trb_buff_len = urb->transfer_buffer_length - running_total; - if (trb_buff_len > TRB_MAX_BUFF_SIZE) - trb_buff_len = TRB_MAX_BUFF_SIZE; - } while (running_total < urb->transfer_buffer_length); - - check_trb_math(urb, num_trbs, running_total); - giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, - start_cycle, start_trb); - return 0; -} - -/* Caller must have locked xhci->lock */ -int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, - struct urb *urb, int slot_id, unsigned int ep_index) -{ - struct xhci_ring *ep_ring; - int num_trbs; - int ret; - struct usb_ctrlrequest *setup; - struct xhci_generic_trb *start_trb; - int start_cycle; - u32 field, length_field; - struct urb_priv *urb_priv; - struct xhci_td *td; - - ep_ring = xhci_urb_to_transfer_ring(xhci, urb); - if (!ep_ring) - return -EINVAL; - - /* - * Need to copy setup packet into setup TRB, so we can't use the setup - * DMA address. - */ - if (!urb->setup_packet) - return -EINVAL; - - /* 1 TRB for setup, 1 for status */ - num_trbs = 2; - /* - * Don't need to check if we need additional event data and normal TRBs, - * since data in control transfers will never get bigger than 16MB - * XXX: can we get a buffer that crosses 64KB boundaries? - */ - if (urb->transfer_buffer_length > 0) - num_trbs++; - ret = prepare_transfer(xhci, xhci->devs[slot_id], - ep_index, urb->stream_id, - num_trbs, urb, 0, mem_flags); - if (ret < 0) - return ret; - - urb_priv = urb->hcpriv; - td = urb_priv->td[0]; - - /* - * Don't give the first TRB to the hardware (by toggling the cycle bit) - * until we've finished creating all the other TRBs. The ring's cycle - * state may change as we enqueue the other TRBs, so save it too. - */ - start_trb = &ep_ring->enqueue->generic; - start_cycle = ep_ring->cycle_state; - - /* Queue setup TRB - see section 6.4.1.2.1 */ - /* FIXME better way to translate setup_packet into two u32 fields? */ - setup = (struct usb_ctrlrequest *) urb->setup_packet; - field = 0; - field |= TRB_IDT | TRB_TYPE(TRB_SETUP); - if (start_cycle == 0) - field |= 0x1; - - /* xHCI 1.0 6.4.1.2.1: Transfer Type field */ - if (xhci->hci_version == 0x100) { - if (urb->transfer_buffer_length > 0) { - if (setup->bRequestType & USB_DIR_IN) - field |= TRB_TX_TYPE(TRB_DATA_IN); - else - field |= TRB_TX_TYPE(TRB_DATA_OUT); - } - } - - queue_trb(xhci, ep_ring, true, - setup->bRequestType | setup->bRequest << 8 | le16_to_cpu(setup->wValue) << 16, - le16_to_cpu(setup->wIndex) | le16_to_cpu(setup->wLength) << 16, - TRB_LEN(8) | TRB_INTR_TARGET(0), - /* Immediate data in pointer */ - field); - - /* If there's data, queue data TRBs */ - /* Only set interrupt on short packet for IN endpoints */ - if (usb_urb_dir_in(urb)) - field = TRB_ISP | TRB_TYPE(TRB_DATA); - else - field = TRB_TYPE(TRB_DATA); - - length_field = TRB_LEN(urb->transfer_buffer_length) | - xhci_td_remainder(urb->transfer_buffer_length) | - TRB_INTR_TARGET(0); - if (urb->transfer_buffer_length > 0) { - if (setup->bRequestType & USB_DIR_IN) - field |= TRB_DIR_IN; - queue_trb(xhci, ep_ring, true, - lower_32_bits(urb->transfer_dma), - upper_32_bits(urb->transfer_dma), - length_field, - field | ep_ring->cycle_state); - } - - /* Save the DMA address of the last TRB in the TD */ - td->last_trb = ep_ring->enqueue; - - /* Queue status TRB - see Table 7 and sections 4.11.2.2 and 6.4.1.2.3 */ - /* If the device sent data, the status stage is an OUT transfer */ - if (urb->transfer_buffer_length > 0 && setup->bRequestType & USB_DIR_IN) - field = 0; - else - field = TRB_DIR_IN; - queue_trb(xhci, ep_ring, false, - 0, - 0, - TRB_INTR_TARGET(0), - /* Event on completion */ - field | TRB_IOC | TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state); - - giveback_first_trb(xhci, slot_id, ep_index, 0, - start_cycle, start_trb); - return 0; -} - -static int count_isoc_trbs_needed(struct xhci_hcd *xhci, - struct urb *urb, int i) -{ - int num_trbs = 0; - u64 addr, td_len; - - addr = (u64) (urb->transfer_dma + urb->iso_frame_desc[i].offset); - td_len = urb->iso_frame_desc[i].length; - - num_trbs = DIV_ROUND_UP(td_len + (addr & (TRB_MAX_BUFF_SIZE - 1)), - TRB_MAX_BUFF_SIZE); - if (num_trbs == 0) - num_trbs++; - - return num_trbs; -} - -/* - * The transfer burst count field of the isochronous TRB defines the number of - * bursts that are required to move all packets in this TD. Only SuperSpeed - * devices can burst up to bMaxBurst number of packets per service interval. - * This field is zero based, meaning a value of zero in the field means one - * burst. Basically, for everything but SuperSpeed devices, this field will be - * zero. Only xHCI 1.0 host controllers support this field. - */ -static unsigned int xhci_get_burst_count(struct xhci_hcd *xhci, - struct usb_device *udev, - struct urb *urb, unsigned int total_packet_count) -{ - unsigned int max_burst; - - if (xhci->hci_version < 0x100 || udev->speed != USB_SPEED_SUPER) - return 0; - - max_burst = urb->ep->ss_ep_comp.bMaxBurst; - return roundup(total_packet_count, max_burst + 1) - 1; -} - -/* - * Returns the number of packets in the last "burst" of packets. This field is - * valid for all speeds of devices. USB 2.0 devices can only do one "burst", so - * the last burst packet count is equal to the total number of packets in the - * TD. SuperSpeed endpoints can have up to 3 bursts. All but the last burst - * must contain (bMaxBurst + 1) number of packets, but the last burst can - * contain 1 to (bMaxBurst + 1) packets. - */ -static unsigned int xhci_get_last_burst_packet_count(struct xhci_hcd *xhci, - struct usb_device *udev, - struct urb *urb, unsigned int total_packet_count) -{ - unsigned int max_burst; - unsigned int residue; - - if (xhci->hci_version < 0x100) - return 0; - - switch (udev->speed) { - case USB_SPEED_SUPER: - /* bMaxBurst is zero based: 0 means 1 packet per burst */ - max_burst = urb->ep->ss_ep_comp.bMaxBurst; - residue = total_packet_count % (max_burst + 1); - /* If residue is zero, the last burst contains (max_burst + 1) - * number of packets, but the TLBPC field is zero-based. - */ - if (residue == 0) - return max_burst; - return residue - 1; - default: - if (total_packet_count == 0) - return 0; - return total_packet_count - 1; - } -} - -/* This is for isoc transfer */ -static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, - struct urb *urb, int slot_id, unsigned int ep_index) -{ - struct xhci_ring *ep_ring; - struct urb_priv *urb_priv; - struct xhci_td *td; - int num_tds, trbs_per_td; - struct xhci_generic_trb *start_trb; - bool first_trb; - int start_cycle; - u32 field, length_field; - int running_total, trb_buff_len, td_len, td_remain_len, ret; - u64 start_addr, addr; - int i, j; - bool more_trbs_coming; - - ep_ring = xhci->devs[slot_id]->eps[ep_index].ring; - - num_tds = urb->number_of_packets; - if (num_tds < 1) { - xhci_dbg(xhci, "Isoc URB with zero packets?\n"); - return -EINVAL; - } - - start_addr = (u64) urb->transfer_dma; - start_trb = &ep_ring->enqueue->generic; - start_cycle = ep_ring->cycle_state; - - urb_priv = urb->hcpriv; - /* Queue the first TRB, even if it's zero-length */ - for (i = 0; i < num_tds; i++) { - unsigned int total_packet_count; - unsigned int burst_count; - unsigned int residue; - - first_trb = true; - running_total = 0; - addr = start_addr + urb->iso_frame_desc[i].offset; - td_len = urb->iso_frame_desc[i].length; - td_remain_len = td_len; - total_packet_count = roundup(td_len, - usb_endpoint_maxp(&urb->ep->desc)); - /* A zero-length transfer still involves at least one packet. */ - if (total_packet_count == 0) - total_packet_count++; - burst_count = xhci_get_burst_count(xhci, urb->dev, urb, - total_packet_count); - residue = xhci_get_last_burst_packet_count(xhci, - urb->dev, urb, total_packet_count); - - trbs_per_td = count_isoc_trbs_needed(xhci, urb, i); - - ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, - urb->stream_id, trbs_per_td, urb, i, mem_flags); - if (ret < 0) { - if (i == 0) - return ret; - goto cleanup; - } - - td = urb_priv->td[i]; - for (j = 0; j < trbs_per_td; j++) { - u32 remainder = 0; - field = TRB_TBC(burst_count) | TRB_TLBPC(residue); - - if (first_trb) { - /* Queue the isoc TRB */ - field |= TRB_TYPE(TRB_ISOC); - /* Assume URB_ISO_ASAP is set */ - field |= TRB_SIA; - if (i == 0) { - if (start_cycle == 0) - field |= 0x1; - } else - field |= ep_ring->cycle_state; - first_trb = false; - } else { - /* Queue other normal TRBs */ - field |= TRB_TYPE(TRB_NORMAL); - field |= ep_ring->cycle_state; - } - - /* Only set interrupt on short packet for IN EPs */ - if (usb_urb_dir_in(urb)) - field |= TRB_ISP; - - /* Chain all the TRBs together; clear the chain bit in - * the last TRB to indicate it's the last TRB in the - * chain. - */ - if (j < trbs_per_td - 1) { - field |= TRB_CHAIN; - more_trbs_coming = true; - } else { - td->last_trb = ep_ring->enqueue; - field |= TRB_IOC; - if (xhci->hci_version == 0x100) { - /* Set BEI bit except for the last td */ - if (i < num_tds - 1) - field |= TRB_BEI; - } - more_trbs_coming = false; - } - - /* Calculate TRB length */ - trb_buff_len = TRB_MAX_BUFF_SIZE - - (addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1)); - if (trb_buff_len > td_remain_len) - trb_buff_len = td_remain_len; - - /* Set the TRB length, TD size, & interrupter fields. */ - if (xhci->hci_version < 0x100) { - remainder = xhci_td_remainder( - td_len - running_total); - } else { - remainder = xhci_v1_0_td_remainder( - running_total, trb_buff_len, - total_packet_count, urb); - } - length_field = TRB_LEN(trb_buff_len) | - remainder | - TRB_INTR_TARGET(0); - - queue_trb(xhci, ep_ring, more_trbs_coming, - lower_32_bits(addr), - upper_32_bits(addr), - length_field, - field); - running_total += trb_buff_len; - - addr += trb_buff_len; - td_remain_len -= trb_buff_len; - } - - /* Check TD length */ - if (running_total != td_len) { - xhci_err(xhci, "ISOC TD length unmatch\n"); - ret = -EINVAL; - goto cleanup; - } - } - - if (xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs == 0) { - if (xhci->quirks & XHCI_AMD_PLL_FIX) - usb_amd_quirk_pll_disable(); - } - xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs++; - - giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, - start_cycle, start_trb); - return 0; -cleanup: - /* Clean up a partially enqueued isoc transfer. */ - - for (i--; i >= 0; i--) - list_del_init(&urb_priv->td[i]->td_list); - - /* Use the first TD as a temporary variable to turn the TDs we've queued - * into No-ops with a software-owned cycle bit. That way the hardware - * won't accidentally start executing bogus TDs when we partially - * overwrite them. td->first_trb and td->start_seg are already set. - */ - urb_priv->td[0]->last_trb = ep_ring->enqueue; - /* Every TRB except the first & last will have its cycle bit flipped. */ - td_to_noop(xhci, ep_ring, urb_priv->td[0], true); - - /* Reset the ring enqueue back to the first TRB and its cycle bit. */ - ep_ring->enqueue = urb_priv->td[0]->first_trb; - ep_ring->enq_seg = urb_priv->td[0]->start_seg; - ep_ring->cycle_state = start_cycle; - ep_ring->num_trbs_free = ep_ring->num_trbs_free_temp; - usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb); - return ret; -} - -/* - * Check transfer ring to guarantee there is enough room for the urb. - * Update ISO URB start_frame and interval. - * Update interval as xhci_queue_intr_tx does. Just use xhci frame_index to - * update the urb->start_frame by now. - * Always assume URB_ISO_ASAP set, and NEVER use urb->start_frame as input. - */ -int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, - struct urb *urb, int slot_id, unsigned int ep_index) -{ - struct xhci_virt_device *xdev; - struct xhci_ring *ep_ring; - struct xhci_ep_ctx *ep_ctx; - int start_frame; - int xhci_interval; - int ep_interval; - int num_tds, num_trbs, i; - int ret; - - xdev = xhci->devs[slot_id]; - ep_ring = xdev->eps[ep_index].ring; - ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); - - num_trbs = 0; - num_tds = urb->number_of_packets; - for (i = 0; i < num_tds; i++) - num_trbs += count_isoc_trbs_needed(xhci, urb, i); - - /* Check the ring to guarantee there is enough room for the whole urb. - * Do not insert any td of the urb to the ring if the check failed. - */ - ret = prepare_ring(xhci, ep_ring, le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK, - num_trbs, mem_flags); - if (ret) - return ret; - - start_frame = xhci_readl(xhci, &xhci->run_regs->microframe_index); - start_frame &= 0x3fff; - - urb->start_frame = start_frame; - if (urb->dev->speed == USB_SPEED_LOW || - urb->dev->speed == USB_SPEED_FULL) - urb->start_frame >>= 3; - - xhci_interval = EP_INTERVAL_TO_UFRAMES(le32_to_cpu(ep_ctx->ep_info)); - ep_interval = urb->interval; - /* Convert to microframes */ - if (urb->dev->speed == USB_SPEED_LOW || - urb->dev->speed == USB_SPEED_FULL) - ep_interval *= 8; - /* FIXME change this to a warning and a suggestion to use the new API - * to set the polling interval (once the API is added). - */ - if (xhci_interval != ep_interval) { - if (printk_ratelimit()) - dev_dbg(&urb->dev->dev, "Driver uses different interval" - " (%d microframe%s) than xHCI " - "(%d microframe%s)\n", - ep_interval, - ep_interval == 1 ? "" : "s", - xhci_interval, - xhci_interval == 1 ? "" : "s"); - urb->interval = xhci_interval; - /* Convert back to frames for LS/FS devices */ - if (urb->dev->speed == USB_SPEED_LOW || - urb->dev->speed == USB_SPEED_FULL) - urb->interval /= 8; - } - ep_ring->num_trbs_free_temp = ep_ring->num_trbs_free; - - return xhci_queue_isoc_tx(xhci, mem_flags, urb, slot_id, ep_index); -} - -/**** Command Ring Operations ****/ - -/* Generic function for queueing a command TRB on the command ring. - * Check to make sure there's room on the command ring for one command TRB. - * Also check that there's room reserved for commands that must not fail. - * If this is a command that must not fail, meaning command_must_succeed = TRUE, - * then only check for the number of reserved spots. - * Don't decrement xhci->cmd_ring_reserved_trbs after we've queued the TRB - * because the command event handler may want to resubmit a failed command. - */ -static int queue_command(struct xhci_hcd *xhci, u32 field1, u32 field2, - u32 field3, u32 field4, bool command_must_succeed) -{ - int reserved_trbs = xhci->cmd_ring_reserved_trbs; - int ret; - - if (!command_must_succeed) - reserved_trbs++; - - ret = prepare_ring(xhci, xhci->cmd_ring, EP_STATE_RUNNING, - reserved_trbs, GFP_ATOMIC); - if (ret < 0) { - xhci_err(xhci, "ERR: No room for command on command ring\n"); - if (command_must_succeed) - xhci_err(xhci, "ERR: Reserved TRB counting for " - "unfailable commands failed.\n"); - return ret; - } - queue_trb(xhci, xhci->cmd_ring, false, field1, field2, field3, - field4 | xhci->cmd_ring->cycle_state); - return 0; -} - -/* Queue a slot enable or disable request on the command ring */ -int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id) -{ - return queue_command(xhci, 0, 0, 0, - TRB_TYPE(trb_type) | SLOT_ID_FOR_TRB(slot_id), false); -} - -/* Queue an address device command TRB */ -int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, - u32 slot_id) -{ - return queue_command(xhci, lower_32_bits(in_ctx_ptr), - upper_32_bits(in_ctx_ptr), 0, - TRB_TYPE(TRB_ADDR_DEV) | SLOT_ID_FOR_TRB(slot_id), - false); -} - -int xhci_queue_vendor_command(struct xhci_hcd *xhci, - u32 field1, u32 field2, u32 field3, u32 field4) -{ - return queue_command(xhci, field1, field2, field3, field4, false); -} - -/* Queue a reset device command TRB */ -int xhci_queue_reset_device(struct xhci_hcd *xhci, u32 slot_id) -{ - return queue_command(xhci, 0, 0, 0, - TRB_TYPE(TRB_RESET_DEV) | SLOT_ID_FOR_TRB(slot_id), - false); -} - -/* Queue a configure endpoint command TRB */ -int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, - u32 slot_id, bool command_must_succeed) -{ - return queue_command(xhci, lower_32_bits(in_ctx_ptr), - upper_32_bits(in_ctx_ptr), 0, - TRB_TYPE(TRB_CONFIG_EP) | SLOT_ID_FOR_TRB(slot_id), - command_must_succeed); -} - -/* Queue an evaluate context command TRB */ -int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, - u32 slot_id) -{ - return queue_command(xhci, lower_32_bits(in_ctx_ptr), - upper_32_bits(in_ctx_ptr), 0, - TRB_TYPE(TRB_EVAL_CONTEXT) | SLOT_ID_FOR_TRB(slot_id), - false); -} - -/* - * Suspend is set to indicate "Stop Endpoint Command" is being issued to stop - * activity on an endpoint that is about to be suspended. - */ -int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id, - unsigned int ep_index, int suspend) -{ - u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id); - u32 trb_ep_index = EP_ID_FOR_TRB(ep_index); - u32 type = TRB_TYPE(TRB_STOP_RING); - u32 trb_suspend = SUSPEND_PORT_FOR_TRB(suspend); - - return queue_command(xhci, 0, 0, 0, - trb_slot_id | trb_ep_index | type | trb_suspend, false); -} - -/* Set Transfer Ring Dequeue Pointer command. - * This should not be used for endpoints that have streams enabled. - */ -static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id, - unsigned int ep_index, unsigned int stream_id, - struct xhci_segment *deq_seg, - union xhci_trb *deq_ptr, u32 cycle_state) -{ - dma_addr_t addr; - u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id); - u32 trb_ep_index = EP_ID_FOR_TRB(ep_index); - u32 trb_stream_id = STREAM_ID_FOR_TRB(stream_id); - u32 type = TRB_TYPE(TRB_SET_DEQ); - struct xhci_virt_ep *ep; - - addr = xhci_trb_virt_to_dma(deq_seg, deq_ptr); - if (addr == 0) { - xhci_warn(xhci, "WARN Cannot submit Set TR Deq Ptr\n"); - xhci_warn(xhci, "WARN deq seg = %p, deq pt = %p\n", - deq_seg, deq_ptr); - return 0; - } - ep = &xhci->devs[slot_id]->eps[ep_index]; - if ((ep->ep_state & SET_DEQ_PENDING)) { - xhci_warn(xhci, "WARN Cannot submit Set TR Deq Ptr\n"); - xhci_warn(xhci, "A Set TR Deq Ptr command is pending.\n"); - return 0; - } - ep->queued_deq_seg = deq_seg; - ep->queued_deq_ptr = deq_ptr; - return queue_command(xhci, lower_32_bits(addr) | cycle_state, - upper_32_bits(addr), trb_stream_id, - trb_slot_id | trb_ep_index | type, false); -} - -int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id, - unsigned int ep_index) -{ - u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id); - u32 trb_ep_index = EP_ID_FOR_TRB(ep_index); - u32 type = TRB_TYPE(TRB_RESET_EP); - - return queue_command(xhci, 0, 0, 0, trb_slot_id | trb_ep_index | type, - false); -} diff --git a/ANDROID_3.4.5/drivers/usb/host/xhci.c b/ANDROID_3.4.5/drivers/usb/host/xhci.c deleted file mode 100644 index 9248d496..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/xhci.c +++ /dev/null @@ -1,4114 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include - -#include "xhci.h" - -#define DRIVER_AUTHOR "Sarah Sharp" -#define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver" - -/* Some 0.95 hardware can't handle the chain bit on a Link TRB being cleared */ -static int link_quirk; -module_param(link_quirk, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(link_quirk, "Don't clear the chain bit on a link TRB"); - -/* TODO: copied from ehci-hcd.c - can this be refactored? */ -/* - * handshake - spin reading hc until handshake completes or fails - * @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 - * @usec: timeout in microseconds - * - * Returns negative errno, or zero on success - * - * Success happens when the "mask" bits have the specified value (hardware - * handshake done). There are two failure modes: "usec" have passed (major - * hardware flakeout), or the register reads as all-ones (hardware removed). - */ -static int handshake(struct xhci_hcd *xhci, void __iomem *ptr, - u32 mask, u32 done, int usec) -{ - u32 result; - - do { - result = xhci_readl(xhci, ptr); - if (result == ~(u32)0) /* card removed */ - return -ENODEV; - result &= mask; - if (result == done) - return 0; - udelay(1); - usec--; - } while (usec > 0); - return -ETIMEDOUT; -} - -/* - * Disable interrupts and begin the xHCI halting process. - */ -void xhci_quiesce(struct xhci_hcd *xhci) -{ - u32 halted; - u32 cmd; - u32 mask; - - mask = ~(XHCI_IRQS); - halted = xhci_readl(xhci, &xhci->op_regs->status) & STS_HALT; - if (!halted) - mask &= ~CMD_RUN; - - cmd = xhci_readl(xhci, &xhci->op_regs->command); - cmd &= mask; - xhci_writel(xhci, cmd, &xhci->op_regs->command); -} - -/* - * Force HC into halt state. - * - * Disable any IRQs and clear the run/stop bit. - * HC will complete any current and actively pipelined transactions, and - * should halt within 16 ms of the run/stop bit being cleared. - * Read HC Halted bit in the status register to see when the HC is finished. - */ -int xhci_halt(struct xhci_hcd *xhci) -{ - int ret; - xhci_dbg(xhci, "// Halt the HC\n"); - xhci_quiesce(xhci); - - ret = handshake(xhci, &xhci->op_regs->status, - STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC); - if (!ret) - xhci->xhc_state |= XHCI_STATE_HALTED; - else - xhci_warn(xhci, "Host not halted after %u microseconds.\n", - XHCI_MAX_HALT_USEC); - return ret; -} - -/* - * Set the run bit and wait for the host to be running. - */ -static int xhci_start(struct xhci_hcd *xhci) -{ - u32 temp; - int ret; - - temp = xhci_readl(xhci, &xhci->op_regs->command); - temp |= (CMD_RUN); - xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n", - temp); - xhci_writel(xhci, temp, &xhci->op_regs->command); - - /* - * Wait for the HCHalted Status bit to be 0 to indicate the host is - * running. - */ - ret = handshake(xhci, &xhci->op_regs->status, - STS_HALT, 0, XHCI_MAX_HALT_USEC); - if (ret == -ETIMEDOUT) - xhci_err(xhci, "Host took too long to start, " - "waited %u microseconds.\n", - XHCI_MAX_HALT_USEC); - if (!ret) - xhci->xhc_state &= ~XHCI_STATE_HALTED; - return ret; -} - -/* - * Reset a halted HC. - * - * This resets pipelines, timers, counters, state machines, etc. - * Transactions will be terminated immediately, and operational registers - * will be set to their defaults. - */ -int xhci_reset(struct xhci_hcd *xhci) -{ - u32 command; - u32 state; - int ret, i; - - state = xhci_readl(xhci, &xhci->op_regs->status); - if ((state & STS_HALT) == 0) { - xhci_warn(xhci, "Host controller not halted, aborting reset.\n"); - return 0; - } - - xhci_dbg(xhci, "// Reset the HC\n"); - command = xhci_readl(xhci, &xhci->op_regs->command); - command |= CMD_RESET; - xhci_writel(xhci, command, &xhci->op_regs->command); - - ret = handshake(xhci, &xhci->op_regs->command, - CMD_RESET, 0, 250 * 1000); - if (ret) - return ret; - - xhci_dbg(xhci, "Wait for controller to be ready for doorbell rings\n"); - /* - * xHCI cannot write to any doorbells or operational registers other - * than status until the "Controller Not Ready" flag is cleared. - */ - ret = handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000); - - for (i = 0; i < 2; ++i) { - xhci->bus_state[i].port_c_suspend = 0; - xhci->bus_state[i].suspended_ports = 0; - xhci->bus_state[i].resuming_ports = 0; - } - - return ret; -} - -#ifdef CONFIG_PCI -static int xhci_free_msi(struct xhci_hcd *xhci) -{ - int i; - - if (!xhci->msix_entries) - return -EINVAL; - - for (i = 0; i < xhci->msix_count; i++) - if (xhci->msix_entries[i].vector) - free_irq(xhci->msix_entries[i].vector, - xhci_to_hcd(xhci)); - return 0; -} - -/* - * Set up MSI - */ -static int xhci_setup_msi(struct xhci_hcd *xhci) -{ - int ret; - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); - - ret = pci_enable_msi(pdev); - if (ret) { - xhci_dbg(xhci, "failed to allocate MSI entry\n"); - return ret; - } - - ret = request_irq(pdev->irq, (irq_handler_t)xhci_msi_irq, - 0, "xhci_hcd", xhci_to_hcd(xhci)); - if (ret) { - xhci_dbg(xhci, "disable MSI interrupt\n"); - pci_disable_msi(pdev); - } - - return ret; -} - -/* - * Free IRQs - * free all IRQs request - */ -static void xhci_free_irq(struct xhci_hcd *xhci) -{ - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); - int ret; - - /* return if using legacy interrupt */ - if (xhci_to_hcd(xhci)->irq > 0) - return; - - ret = xhci_free_msi(xhci); - if (!ret) - return; - if (pdev->irq > 0) - free_irq(pdev->irq, xhci_to_hcd(xhci)); - - return; -} - -/* - * Set up MSI-X - */ -static int xhci_setup_msix(struct xhci_hcd *xhci) -{ - int i, ret = 0; - struct usb_hcd *hcd = xhci_to_hcd(xhci); - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - - /* - * calculate number of msi-x vectors supported. - * - HCS_MAX_INTRS: the max number of interrupts the host can handle, - * with max number of interrupters based on the xhci HCSPARAMS1. - * - num_online_cpus: maximum msi-x vectors per CPUs core. - * Add additional 1 vector to ensure always available interrupt. - */ - xhci->msix_count = min(num_online_cpus() + 1, - HCS_MAX_INTRS(xhci->hcs_params1)); - - xhci->msix_entries = - kmalloc((sizeof(struct msix_entry))*xhci->msix_count, - GFP_KERNEL); - if (!xhci->msix_entries) { - xhci_err(xhci, "Failed to allocate MSI-X entries\n"); - return -ENOMEM; - } - - for (i = 0; i < xhci->msix_count; i++) { - xhci->msix_entries[i].entry = i; - xhci->msix_entries[i].vector = 0; - } - - ret = pci_enable_msix(pdev, xhci->msix_entries, xhci->msix_count); - if (ret) { - xhci_dbg(xhci, "Failed to enable MSI-X\n"); - goto free_entries; - } - - for (i = 0; i < xhci->msix_count; i++) { - ret = request_irq(xhci->msix_entries[i].vector, - (irq_handler_t)xhci_msi_irq, - 0, "xhci_hcd", xhci_to_hcd(xhci)); - if (ret) - goto disable_msix; - } - - hcd->msix_enabled = 1; - return ret; - -disable_msix: - xhci_dbg(xhci, "disable MSI-X interrupt\n"); - xhci_free_irq(xhci); - pci_disable_msix(pdev); -free_entries: - kfree(xhci->msix_entries); - xhci->msix_entries = NULL; - return ret; -} - -/* Free any IRQs and disable MSI-X */ -static void xhci_cleanup_msix(struct xhci_hcd *xhci) -{ - struct usb_hcd *hcd = xhci_to_hcd(xhci); - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - - xhci_free_irq(xhci); - - if (xhci->msix_entries) { - pci_disable_msix(pdev); - kfree(xhci->msix_entries); - xhci->msix_entries = NULL; - } else { - pci_disable_msi(pdev); - } - - hcd->msix_enabled = 0; - return; -} - -static void xhci_msix_sync_irqs(struct xhci_hcd *xhci) -{ - int i; - - if (xhci->msix_entries) { - for (i = 0; i < xhci->msix_count; i++) - synchronize_irq(xhci->msix_entries[i].vector); - } -} - -static int xhci_try_enable_msi(struct usb_hcd *hcd) -{ - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); - int ret; - - /* - * Some Fresco Logic host controllers advertise MSI, but fail to - * generate interrupts. Don't even try to enable MSI. - */ - if (xhci->quirks & XHCI_BROKEN_MSI) - return 0; - - /* unregister the legacy interrupt */ - if (hcd->irq) - free_irq(hcd->irq, hcd); - hcd->irq = 0; - - ret = xhci_setup_msix(xhci); - if (ret) - /* fall back to msi*/ - ret = xhci_setup_msi(xhci); - - if (!ret) - /* hcd->irq is 0, we have MSI */ - return 0; - - if (!pdev->irq) { - xhci_err(xhci, "No msi-x/msi found and no IRQ in BIOS\n"); - return -EINVAL; - } - - /* fall back to legacy interrupt*/ - ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED, - hcd->irq_descr, hcd); - if (ret) { - xhci_err(xhci, "request interrupt %d failed\n", - pdev->irq); - return ret; - } - hcd->irq = pdev->irq; - return 0; -} - -#else - -static int xhci_try_enable_msi(struct usb_hcd *hcd) -{ - return 0; -} - -static void xhci_cleanup_msix(struct xhci_hcd *xhci) -{ -} - -static void xhci_msix_sync_irqs(struct xhci_hcd *xhci) -{ -} - -#endif - -/* - * Initialize memory for HCD and xHC (one-time init). - * - * Program the PAGESIZE register, initialize the device context array, create - * device contexts (?), set up a command ring segment (or two?), create event - * ring (one for now). - */ -int xhci_init(struct usb_hcd *hcd) -{ - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - int retval = 0; - - xhci_dbg(xhci, "xhci_init\n"); - spin_lock_init(&xhci->lock); - if (xhci->hci_version == 0x95 && link_quirk) { - xhci_dbg(xhci, "QUIRK: Not clearing Link TRB chain bits.\n"); - xhci->quirks |= XHCI_LINK_TRB_QUIRK; - } else { - xhci_dbg(xhci, "xHCI doesn't need link TRB QUIRK\n"); - } - retval = xhci_mem_init(xhci, GFP_KERNEL); - xhci_dbg(xhci, "Finished xhci_init\n"); - - return retval; -} - -/*-------------------------------------------------------------------------*/ - - -#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING -static void xhci_event_ring_work(unsigned long arg) -{ - unsigned long flags; - int temp; - u64 temp_64; - struct xhci_hcd *xhci = (struct xhci_hcd *) arg; - int i, j; - - xhci_dbg(xhci, "Poll event ring: %lu\n", jiffies); - - spin_lock_irqsave(&xhci->lock, flags); - temp = xhci_readl(xhci, &xhci->op_regs->status); - xhci_dbg(xhci, "op reg status = 0x%x\n", temp); - if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) || - (xhci->xhc_state & XHCI_STATE_HALTED)) { - xhci_dbg(xhci, "HW died, polling stopped.\n"); - spin_unlock_irqrestore(&xhci->lock, flags); - return; - } - - temp = xhci_readl(xhci, &xhci->ir_set->irq_pending); - xhci_dbg(xhci, "ir_set 0 pending = 0x%x\n", temp); - xhci_dbg(xhci, "HC error bitmask = 0x%x\n", xhci->error_bitmask); - xhci->error_bitmask = 0; - xhci_dbg(xhci, "Event ring:\n"); - xhci_debug_segment(xhci, xhci->event_ring->deq_seg); - xhci_dbg_ring_ptrs(xhci, xhci->event_ring); - temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); - temp_64 &= ~ERST_PTR_MASK; - xhci_dbg(xhci, "ERST deq = 64'h%0lx\n", (long unsigned int) temp_64); - xhci_dbg(xhci, "Command ring:\n"); - xhci_debug_segment(xhci, xhci->cmd_ring->deq_seg); - xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring); - xhci_dbg_cmd_ptrs(xhci); - for (i = 0; i < MAX_HC_SLOTS; ++i) { - if (!xhci->devs[i]) - continue; - for (j = 0; j < 31; ++j) { - xhci_dbg_ep_rings(xhci, i, j, &xhci->devs[i]->eps[j]); - } - } - spin_unlock_irqrestore(&xhci->lock, flags); - - if (!xhci->zombie) - mod_timer(&xhci->event_ring_timer, jiffies + POLL_TIMEOUT * HZ); - else - xhci_dbg(xhci, "Quit polling the event ring.\n"); -} -#endif - -static int xhci_run_finished(struct xhci_hcd *xhci) -{ - if (xhci_start(xhci)) { - xhci_halt(xhci); - return -ENODEV; - } - xhci->shared_hcd->state = HC_STATE_RUNNING; - - if (xhci->quirks & XHCI_NEC_HOST) - xhci_ring_cmd_db(xhci); - - xhci_dbg(xhci, "Finished xhci_run for USB3 roothub\n"); - return 0; -} - -/* - * Start the HC after it was halted. - * - * This function is called by the USB core when the HC driver is added. - * Its opposite is xhci_stop(). - * - * xhci_init() must be called once before this function can be called. - * Reset the HC, enable device slot contexts, program DCBAAP, and - * set command ring pointer and event ring pointer. - * - * Setup MSI-X vectors and enable interrupts. - */ -int xhci_run(struct usb_hcd *hcd) -{ - u32 temp; - u64 temp_64; - int ret; - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - - /* Start the xHCI host controller running only after the USB 2.0 roothub - * is setup. - */ - - hcd->uses_new_polling = 1; - if (!usb_hcd_is_primary_hcd(hcd)) - return xhci_run_finished(xhci); - - xhci_dbg(xhci, "xhci_run\n"); - - ret = xhci_try_enable_msi(hcd); - if (ret) - return ret; - -#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING - init_timer(&xhci->event_ring_timer); - xhci->event_ring_timer.data = (unsigned long) xhci; - xhci->event_ring_timer.function = xhci_event_ring_work; - /* Poll the event ring */ - xhci->event_ring_timer.expires = jiffies + POLL_TIMEOUT * HZ; - xhci->zombie = 0; - xhci_dbg(xhci, "Setting event ring polling timer\n"); - add_timer(&xhci->event_ring_timer); -#endif - - xhci_dbg(xhci, "Command ring memory map follows:\n"); - xhci_debug_ring(xhci, xhci->cmd_ring); - xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring); - xhci_dbg_cmd_ptrs(xhci); - - xhci_dbg(xhci, "ERST memory map follows:\n"); - xhci_dbg_erst(xhci, &xhci->erst); - xhci_dbg(xhci, "Event ring:\n"); - xhci_debug_ring(xhci, xhci->event_ring); - xhci_dbg_ring_ptrs(xhci, xhci->event_ring); - temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); - temp_64 &= ~ERST_PTR_MASK; - xhci_dbg(xhci, "ERST deq = 64'h%0lx\n", (long unsigned int) temp_64); - - xhci_dbg(xhci, "// Set the interrupt modulation register\n"); - temp = xhci_readl(xhci, &xhci->ir_set->irq_control); - temp &= ~ER_IRQ_INTERVAL_MASK; - temp |= (u32) 160; - xhci_writel(xhci, temp, &xhci->ir_set->irq_control); - - /* Set the HCD state before we enable the irqs */ - temp = xhci_readl(xhci, &xhci->op_regs->command); - temp |= (CMD_EIE); - xhci_dbg(xhci, "// Enable interrupts, cmd = 0x%x.\n", - temp); - xhci_writel(xhci, temp, &xhci->op_regs->command); - - temp = xhci_readl(xhci, &xhci->ir_set->irq_pending); - xhci_dbg(xhci, "// Enabling event ring interrupter %p by writing 0x%x to irq_pending\n", - xhci->ir_set, (unsigned int) ER_IRQ_ENABLE(temp)); - xhci_writel(xhci, ER_IRQ_ENABLE(temp), - &xhci->ir_set->irq_pending); - xhci_print_ir_set(xhci, 0); - - if (xhci->quirks & XHCI_NEC_HOST) - xhci_queue_vendor_command(xhci, 0, 0, 0, - TRB_TYPE(TRB_NEC_GET_FW)); - - xhci_dbg(xhci, "Finished xhci_run for USB2 roothub\n"); - return 0; -} - -static void xhci_only_stop_hcd(struct usb_hcd *hcd) -{ - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - - spin_lock_irq(&xhci->lock); - xhci_halt(xhci); - - /* The shared_hcd is going to be deallocated shortly (the USB core only - * calls this function when allocation fails in usb_add_hcd(), or - * usb_remove_hcd() is called). So we need to unset xHCI's pointer. - */ - xhci->shared_hcd = NULL; - spin_unlock_irq(&xhci->lock); -} - -/* - * Stop xHCI driver. - * - * This function is called by the USB core when the HC driver is removed. - * Its opposite is xhci_run(). - * - * Disable device contexts, disable IRQs, and quiesce the HC. - * Reset the HC, finish any completed transactions, and cleanup memory. - */ -void xhci_stop(struct usb_hcd *hcd) -{ - u32 temp; - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - - if (!usb_hcd_is_primary_hcd(hcd)) { - xhci_only_stop_hcd(xhci->shared_hcd); - return; - } - - spin_lock_irq(&xhci->lock); - /* Make sure the xHC is halted for a USB3 roothub - * (xhci_stop() could be called as part of failed init). - */ - xhci_halt(xhci); - xhci_reset(xhci); - spin_unlock_irq(&xhci->lock); - - xhci_cleanup_msix(xhci); - -#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING - /* Tell the event ring poll function not to reschedule */ - xhci->zombie = 1; - del_timer_sync(&xhci->event_ring_timer); -#endif - - if (xhci->quirks & XHCI_AMD_PLL_FIX) - usb_amd_dev_put(); - - xhci_dbg(xhci, "// Disabling event ring interrupts\n"); - temp = xhci_readl(xhci, &xhci->op_regs->status); - xhci_writel(xhci, temp & ~STS_EINT, &xhci->op_regs->status); - temp = xhci_readl(xhci, &xhci->ir_set->irq_pending); - xhci_writel(xhci, ER_IRQ_DISABLE(temp), - &xhci->ir_set->irq_pending); - xhci_print_ir_set(xhci, 0); - - xhci_dbg(xhci, "cleaning up memory\n"); - xhci_mem_cleanup(xhci); - xhci_dbg(xhci, "xhci_stop completed - status = %x\n", - xhci_readl(xhci, &xhci->op_regs->status)); -} - -/* - * Shutdown HC (not bus-specific) - * - * This is called when the machine is rebooting or halting. We assume that the - * machine will be powered off, and the HC's internal state will be reset. - * Don't bother to free memory. - * - * This will only ever be called with the main usb_hcd (the USB3 roothub). - */ -void xhci_shutdown(struct usb_hcd *hcd) -{ - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - - spin_lock_irq(&xhci->lock); - xhci_halt(xhci); - spin_unlock_irq(&xhci->lock); - - xhci_cleanup_msix(xhci); - - xhci_dbg(xhci, "xhci_shutdown completed - status = %x\n", - xhci_readl(xhci, &xhci->op_regs->status)); -} - -#ifdef CONFIG_PM -static void xhci_save_registers(struct xhci_hcd *xhci) -{ - xhci->s3.command = xhci_readl(xhci, &xhci->op_regs->command); - xhci->s3.dev_nt = xhci_readl(xhci, &xhci->op_regs->dev_notification); - xhci->s3.dcbaa_ptr = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr); - xhci->s3.config_reg = xhci_readl(xhci, &xhci->op_regs->config_reg); - xhci->s3.erst_size = xhci_readl(xhci, &xhci->ir_set->erst_size); - xhci->s3.erst_base = xhci_read_64(xhci, &xhci->ir_set->erst_base); - xhci->s3.erst_dequeue = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); - xhci->s3.irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending); - xhci->s3.irq_control = xhci_readl(xhci, &xhci->ir_set->irq_control); -} - -static void xhci_restore_registers(struct xhci_hcd *xhci) -{ - xhci_writel(xhci, xhci->s3.command, &xhci->op_regs->command); - xhci_writel(xhci, xhci->s3.dev_nt, &xhci->op_regs->dev_notification); - xhci_write_64(xhci, xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr); - xhci_writel(xhci, xhci->s3.config_reg, &xhci->op_regs->config_reg); - xhci_writel(xhci, xhci->s3.erst_size, &xhci->ir_set->erst_size); - xhci_write_64(xhci, xhci->s3.erst_base, &xhci->ir_set->erst_base); - xhci_write_64(xhci, xhci->s3.erst_dequeue, &xhci->ir_set->erst_dequeue); - xhci_writel(xhci, xhci->s3.irq_pending, &xhci->ir_set->irq_pending); - xhci_writel(xhci, xhci->s3.irq_control, &xhci->ir_set->irq_control); -} - -static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci) -{ - u64 val_64; - - /* step 2: initialize command ring buffer */ - val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); - val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) | - (xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg, - xhci->cmd_ring->dequeue) & - (u64) ~CMD_RING_RSVD_BITS) | - xhci->cmd_ring->cycle_state; - xhci_dbg(xhci, "// Setting command ring address to 0x%llx\n", - (long unsigned long) val_64); - xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring); -} - -/* - * The whole command ring must be cleared to zero when we suspend the host. - * - * The host doesn't save the command ring pointer in the suspend well, so we - * need to re-program it on resume. Unfortunately, the pointer must be 64-byte - * aligned, because of the reserved bits in the command ring dequeue pointer - * register. Therefore, we can't just set the dequeue pointer back in the - * middle of the ring (TRBs are 16-byte aligned). - */ -static void xhci_clear_command_ring(struct xhci_hcd *xhci) -{ - struct xhci_ring *ring; - struct xhci_segment *seg; - - ring = xhci->cmd_ring; - seg = ring->deq_seg; - do { - memset(seg->trbs, 0, - sizeof(union xhci_trb) * (TRBS_PER_SEGMENT - 1)); - seg->trbs[TRBS_PER_SEGMENT - 1].link.control &= - cpu_to_le32(~TRB_CYCLE); - seg = seg->next; - } while (seg != ring->deq_seg); - - /* Reset the software enqueue and dequeue pointers */ - ring->deq_seg = ring->first_seg; - ring->dequeue = ring->first_seg->trbs; - ring->enq_seg = ring->deq_seg; - ring->enqueue = ring->dequeue; - - ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1; - /* - * Ring is now zeroed, so the HW should look for change of ownership - * when the cycle bit is set to 1. - */ - ring->cycle_state = 1; - - /* - * Reset the hardware dequeue pointer. - * Yes, this will need to be re-written after resume, but we're paranoid - * and want to make sure the hardware doesn't access bogus memory - * because, say, the BIOS or an SMI started the host without changing - * the command ring pointers. - */ - xhci_set_cmd_ring_deq(xhci); -} - -/* - * Stop HC (not bus-specific) - * - * This is called when the machine transition into S3/S4 mode. - * - */ -int xhci_suspend(struct xhci_hcd *xhci) -{ - int rc = 0; - struct usb_hcd *hcd = xhci_to_hcd(xhci); - u32 command; - - spin_lock_irq(&xhci->lock); - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); - /* step 1: stop endpoint */ - /* skipped assuming that port suspend has done */ - - /* step 2: clear Run/Stop bit */ - command = xhci_readl(xhci, &xhci->op_regs->command); - command &= ~CMD_RUN; - xhci_writel(xhci, command, &xhci->op_regs->command); - if (handshake(xhci, &xhci->op_regs->status, - STS_HALT, STS_HALT, 100*100)) { - xhci_warn(xhci, "WARN: xHC CMD_RUN timeout\n"); - spin_unlock_irq(&xhci->lock); - return -ETIMEDOUT; - } - xhci_clear_command_ring(xhci); - - /* step 3: save registers */ - xhci_save_registers(xhci); - - /* step 4: set CSS flag */ - command = xhci_readl(xhci, &xhci->op_regs->command); - command |= CMD_CSS; - xhci_writel(xhci, command, &xhci->op_regs->command); - if (handshake(xhci, &xhci->op_regs->status, STS_SAVE, 0, 10 * 1000)) { - xhci_warn(xhci, "WARN: xHC save state timeout\n"); - spin_unlock_irq(&xhci->lock); - return -ETIMEDOUT; - } - spin_unlock_irq(&xhci->lock); - - /* step 5: remove core well power */ - /* synchronize irq when using MSI-X */ - xhci_msix_sync_irqs(xhci); - - return rc; -} - -/* - * start xHC (not bus-specific) - * - * This is called when the machine transition from S3/S4 mode. - * - */ -int xhci_resume(struct xhci_hcd *xhci, bool hibernated) -{ - u32 command, temp = 0; - struct usb_hcd *hcd = xhci_to_hcd(xhci); - struct usb_hcd *secondary_hcd; - int retval = 0; - - /* Wait a bit if either of the roothubs need to settle from the - * transition into bus suspend. - */ - if (time_before(jiffies, xhci->bus_state[0].next_statechange) || - time_before(jiffies, - xhci->bus_state[1].next_statechange)) - msleep(100); - - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); - - spin_lock_irq(&xhci->lock); - if (xhci->quirks & XHCI_RESET_ON_RESUME) - hibernated = true; - - if (!hibernated) { - /* step 1: restore register */ - xhci_restore_registers(xhci); - /* step 2: initialize command ring buffer */ - xhci_set_cmd_ring_deq(xhci); - /* step 3: restore state and start state*/ - /* step 3: set CRS flag */ - command = xhci_readl(xhci, &xhci->op_regs->command); - command |= CMD_CRS; - xhci_writel(xhci, command, &xhci->op_regs->command); - if (handshake(xhci, &xhci->op_regs->status, - STS_RESTORE, 0, 10 * 1000)) { - xhci_warn(xhci, "WARN: xHC restore state timeout\n"); - spin_unlock_irq(&xhci->lock); - return -ETIMEDOUT; - } - temp = xhci_readl(xhci, &xhci->op_regs->status); - } - - /* If restore operation fails, re-initialize the HC during resume */ - if ((temp & STS_SRE) || hibernated) { - /* Let the USB core know _both_ roothubs lost power. */ - usb_root_hub_lost_power(xhci->main_hcd->self.root_hub); - usb_root_hub_lost_power(xhci->shared_hcd->self.root_hub); - - xhci_dbg(xhci, "Stop HCD\n"); - xhci_halt(xhci); - xhci_reset(xhci); - spin_unlock_irq(&xhci->lock); - xhci_cleanup_msix(xhci); - -#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING - /* Tell the event ring poll function not to reschedule */ - xhci->zombie = 1; - del_timer_sync(&xhci->event_ring_timer); -#endif - - xhci_dbg(xhci, "// Disabling event ring interrupts\n"); - temp = xhci_readl(xhci, &xhci->op_regs->status); - xhci_writel(xhci, temp & ~STS_EINT, &xhci->op_regs->status); - temp = xhci_readl(xhci, &xhci->ir_set->irq_pending); - xhci_writel(xhci, ER_IRQ_DISABLE(temp), - &xhci->ir_set->irq_pending); - xhci_print_ir_set(xhci, 0); - - xhci_dbg(xhci, "cleaning up memory\n"); - xhci_mem_cleanup(xhci); - xhci_dbg(xhci, "xhci_stop completed - status = %x\n", - xhci_readl(xhci, &xhci->op_regs->status)); - - /* USB core calls the PCI reinit and start functions twice: - * first with the primary HCD, and then with the secondary HCD. - * If we don't do the same, the host will never be started. - */ - if (!usb_hcd_is_primary_hcd(hcd)) - secondary_hcd = hcd; - else - secondary_hcd = xhci->shared_hcd; - - xhci_dbg(xhci, "Initialize the xhci_hcd\n"); - retval = xhci_init(hcd->primary_hcd); - if (retval) - return retval; - xhci_dbg(xhci, "Start the primary HCD\n"); - retval = xhci_run(hcd->primary_hcd); - if (!retval) { - xhci_dbg(xhci, "Start the secondary HCD\n"); - retval = xhci_run(secondary_hcd); - } - hcd->state = HC_STATE_SUSPENDED; - xhci->shared_hcd->state = HC_STATE_SUSPENDED; - goto done; - } - - /* step 4: set Run/Stop bit */ - command = xhci_readl(xhci, &xhci->op_regs->command); - command |= CMD_RUN; - xhci_writel(xhci, command, &xhci->op_regs->command); - handshake(xhci, &xhci->op_regs->status, STS_HALT, - 0, 250 * 1000); - - /* step 5: walk topology and initialize portsc, - * portpmsc and portli - */ - /* this is done in bus_resume */ - - /* step 6: restart each of the previously - * Running endpoints by ringing their doorbells - */ - - spin_unlock_irq(&xhci->lock); - - done: - if (retval == 0) { - usb_hcd_resume_root_hub(hcd); - usb_hcd_resume_root_hub(xhci->shared_hcd); - } - return retval; -} -#endif /* CONFIG_PM */ - -/*-------------------------------------------------------------------------*/ - -/** - * xhci_get_endpoint_index - Used for passing endpoint bitmasks between the core and - * HCDs. Find the index for an endpoint given its descriptor. Use the return - * value to right shift 1 for the bitmask. - * - * Index = (epnum * 2) + direction - 1, - * where direction = 0 for OUT, 1 for IN. - * For control endpoints, the IN index is used (OUT index is unused), so - * index = (epnum * 2) + direction - 1 = (epnum * 2) + 1 - 1 = (epnum * 2) - */ -unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc) -{ - unsigned int index; - if (usb_endpoint_xfer_control(desc)) - index = (unsigned int) (usb_endpoint_num(desc)*2); - else - index = (unsigned int) (usb_endpoint_num(desc)*2) + - (usb_endpoint_dir_in(desc) ? 1 : 0) - 1; - return index; -} - -/* Find the flag for this endpoint (for use in the control context). Use the - * endpoint index to create a bitmask. The slot context is bit 0, endpoint 0 is - * bit 1, etc. - */ -unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc) -{ - return 1 << (xhci_get_endpoint_index(desc) + 1); -} - -/* Find the flag for this endpoint (for use in the control context). Use the - * endpoint index to create a bitmask. The slot context is bit 0, endpoint 0 is - * bit 1, etc. - */ -unsigned int xhci_get_endpoint_flag_from_index(unsigned int ep_index) -{ - return 1 << (ep_index + 1); -} - -/* Compute the last valid endpoint context index. Basically, this is the - * endpoint index plus one. For slot contexts with more than valid endpoint, - * we find the most significant bit set in the added contexts flags. - * e.g. ep 1 IN (with epnum 0x81) => added_ctxs = 0b1000 - * fls(0b1000) = 4, but the endpoint context index is 3, so subtract one. - */ -unsigned int xhci_last_valid_endpoint(u32 added_ctxs) -{ - return fls(added_ctxs) - 1; -} - -/* Returns 1 if the arguments are OK; - * returns 0 this is a root hub; returns -EINVAL for NULL pointers. - */ -static int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev, - struct usb_host_endpoint *ep, int check_ep, bool check_virt_dev, - const char *func) { - struct xhci_hcd *xhci; - struct xhci_virt_device *virt_dev; - - if (!hcd || (check_ep && !ep) || !udev) { - printk(KERN_DEBUG "xHCI %s called with invalid args\n", - func); - return -EINVAL; - } - if (!udev->parent) { - printk(KERN_DEBUG "xHCI %s called for root hub\n", - func); - return 0; - } - - xhci = hcd_to_xhci(hcd); - if (xhci->xhc_state & XHCI_STATE_HALTED) - return -ENODEV; - - if (check_virt_dev) { - if (!udev->slot_id || !xhci->devs[udev->slot_id]) { - printk(KERN_DEBUG "xHCI %s called with unaddressed " - "device\n", func); - return -EINVAL; - } - - virt_dev = xhci->devs[udev->slot_id]; - if (virt_dev->udev != udev) { - printk(KERN_DEBUG "xHCI %s called with udev and " - "virt_dev does not match\n", func); - return -EINVAL; - } - } - - return 1; -} - -static int xhci_configure_endpoint(struct xhci_hcd *xhci, - struct usb_device *udev, struct xhci_command *command, - bool ctx_change, bool must_succeed); - -/* - * Full speed devices may have a max packet size greater than 8 bytes, but the - * USB core doesn't know that until it reads the first 8 bytes of the - * descriptor. If the usb_device's max packet size changes after that point, - * we need to issue an evaluate context command and wait on it. - */ -static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id, - unsigned int ep_index, struct urb *urb) -{ - struct xhci_container_ctx *in_ctx; - struct xhci_container_ctx *out_ctx; - struct xhci_input_control_ctx *ctrl_ctx; - struct xhci_ep_ctx *ep_ctx; - int max_packet_size; - int hw_max_packet_size; - int ret = 0; - - out_ctx = xhci->devs[slot_id]->out_ctx; - ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index); - hw_max_packet_size = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2)); - max_packet_size = usb_endpoint_maxp(&urb->dev->ep0.desc); - if (hw_max_packet_size != max_packet_size) { - xhci_dbg(xhci, "Max Packet Size for ep 0 changed.\n"); - xhci_dbg(xhci, "Max packet size in usb_device = %d\n", - max_packet_size); - xhci_dbg(xhci, "Max packet size in xHCI HW = %d\n", - hw_max_packet_size); - xhci_dbg(xhci, "Issuing evaluate context command.\n"); - - /* Set up the modified control endpoint 0 */ - xhci_endpoint_copy(xhci, xhci->devs[slot_id]->in_ctx, - xhci->devs[slot_id]->out_ctx, ep_index); - in_ctx = xhci->devs[slot_id]->in_ctx; - ep_ctx = xhci_get_ep_ctx(xhci, in_ctx, ep_index); - ep_ctx->ep_info2 &= cpu_to_le32(~MAX_PACKET_MASK); - ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet_size)); - - /* Set up the input context flags for the command */ - /* FIXME: This won't work if a non-default control endpoint - * changes max packet sizes. - */ - ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); - ctrl_ctx->add_flags = cpu_to_le32(EP0_FLAG); - ctrl_ctx->drop_flags = 0; - - xhci_dbg(xhci, "Slot %d input context\n", slot_id); - xhci_dbg_ctx(xhci, in_ctx, ep_index); - xhci_dbg(xhci, "Slot %d output context\n", slot_id); - xhci_dbg_ctx(xhci, out_ctx, ep_index); - - ret = xhci_configure_endpoint(xhci, urb->dev, NULL, - true, false); - - /* Clean up the input context for later use by bandwidth - * functions. - */ - ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG); - } - return ret; -} - -/* - * non-error returns are a promise to giveback() the urb later - * we drop ownership so next owner (or urb unlink) can get it - */ -int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) -{ - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - struct xhci_td *buffer; - unsigned long flags; - int ret = 0; - unsigned int slot_id, ep_index; - struct urb_priv *urb_priv; - int size, i; - - if (!urb || xhci_check_args(hcd, urb->dev, urb->ep, - true, true, __func__) <= 0) - return -EINVAL; - - slot_id = urb->dev->slot_id; - ep_index = xhci_get_endpoint_index(&urb->ep->desc); - - if (!HCD_HW_ACCESSIBLE(hcd)) { - if (!in_interrupt()) - xhci_dbg(xhci, "urb submitted during PCI suspend\n"); - ret = -ESHUTDOWN; - goto exit; - } - - if (usb_endpoint_xfer_isoc(&urb->ep->desc)) - size = urb->number_of_packets; - else - size = 1; - - urb_priv = kzalloc(sizeof(struct urb_priv) + - size * sizeof(struct xhci_td *), mem_flags); - if (!urb_priv) - return -ENOMEM; - - buffer = kzalloc(size * sizeof(struct xhci_td), mem_flags); - if (!buffer) { - kfree(urb_priv); - return -ENOMEM; - } - - for (i = 0; i < size; i++) { - urb_priv->td[i] = buffer; - buffer++; - } - - urb_priv->length = size; - urb_priv->td_cnt = 0; - urb->hcpriv = urb_priv; - - if (usb_endpoint_xfer_control(&urb->ep->desc)) { - /* Check to see if the max packet size for the default control - * endpoint changed during FS device enumeration - */ - if (urb->dev->speed == USB_SPEED_FULL) { - ret = xhci_check_maxpacket(xhci, slot_id, - ep_index, urb); - if (ret < 0) { - xhci_urb_free_priv(xhci, urb_priv); - urb->hcpriv = NULL; - return ret; - } - } - - /* We have a spinlock and interrupts disabled, so we must pass - * atomic context to this function, which may allocate memory. - */ - spin_lock_irqsave(&xhci->lock, flags); - if (xhci->xhc_state & XHCI_STATE_DYING) - goto dying; - ret = xhci_queue_ctrl_tx(xhci, GFP_ATOMIC, urb, - slot_id, ep_index); - if (ret) - goto free_priv; - spin_unlock_irqrestore(&xhci->lock, flags); - } else if (usb_endpoint_xfer_bulk(&urb->ep->desc)) { - spin_lock_irqsave(&xhci->lock, flags); - if (xhci->xhc_state & XHCI_STATE_DYING) - goto dying; - if (xhci->devs[slot_id]->eps[ep_index].ep_state & - EP_GETTING_STREAMS) { - xhci_warn(xhci, "WARN: Can't enqueue URB while bulk ep " - "is transitioning to using streams.\n"); - ret = -EINVAL; - } else if (xhci->devs[slot_id]->eps[ep_index].ep_state & - EP_GETTING_NO_STREAMS) { - xhci_warn(xhci, "WARN: Can't enqueue URB while bulk ep " - "is transitioning to " - "not having streams.\n"); - ret = -EINVAL; - } else { - ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, - slot_id, ep_index); - } - if (ret) - goto free_priv; - spin_unlock_irqrestore(&xhci->lock, flags); - } else if (usb_endpoint_xfer_int(&urb->ep->desc)) { - spin_lock_irqsave(&xhci->lock, flags); - if (xhci->xhc_state & XHCI_STATE_DYING) - goto dying; - ret = xhci_queue_intr_tx(xhci, GFP_ATOMIC, urb, - slot_id, ep_index); - if (ret) - goto free_priv; - spin_unlock_irqrestore(&xhci->lock, flags); - } else { - spin_lock_irqsave(&xhci->lock, flags); - if (xhci->xhc_state & XHCI_STATE_DYING) - goto dying; - ret = xhci_queue_isoc_tx_prepare(xhci, GFP_ATOMIC, urb, - slot_id, ep_index); - if (ret) - goto free_priv; - spin_unlock_irqrestore(&xhci->lock, flags); - } -exit: - return ret; -dying: - xhci_dbg(xhci, "Ep 0x%x: URB %p submitted for " - "non-responsive xHCI host.\n", - urb->ep->desc.bEndpointAddress, urb); - ret = -ESHUTDOWN; -free_priv: - xhci_urb_free_priv(xhci, urb_priv); - urb->hcpriv = NULL; - spin_unlock_irqrestore(&xhci->lock, flags); - return ret; -} - -/* Get the right ring for the given URB. - * If the endpoint supports streams, boundary check the URB's stream ID. - * If the endpoint doesn't support streams, return the singular endpoint ring. - */ -static struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci, - struct urb *urb) -{ - unsigned int slot_id; - unsigned int ep_index; - unsigned int stream_id; - struct xhci_virt_ep *ep; - - slot_id = urb->dev->slot_id; - ep_index = xhci_get_endpoint_index(&urb->ep->desc); - stream_id = urb->stream_id; - ep = &xhci->devs[slot_id]->eps[ep_index]; - /* Common case: no streams */ - if (!(ep->ep_state & EP_HAS_STREAMS)) - return ep->ring; - - if (stream_id == 0) { - xhci_warn(xhci, - "WARN: Slot ID %u, ep index %u has streams, " - "but URB has no stream ID.\n", - slot_id, ep_index); - return NULL; - } - - if (stream_id < ep->stream_info->num_streams) - return ep->stream_info->stream_rings[stream_id]; - - xhci_warn(xhci, - "WARN: Slot ID %u, ep index %u has " - "stream IDs 1 to %u allocated, " - "but stream ID %u is requested.\n", - slot_id, ep_index, - ep->stream_info->num_streams - 1, - stream_id); - return NULL; -} - -/* - * Remove the URB's TD from the endpoint ring. This may cause the HC to stop - * USB transfers, potentially stopping in the middle of a TRB buffer. The HC - * should pick up where it left off in the TD, unless a Set Transfer Ring - * Dequeue Pointer is issued. - * - * The TRBs that make up the buffers for the canceled URB will be "removed" from - * the ring. Since the ring is a contiguous structure, they can't be physically - * removed. Instead, there are two options: - * - * 1) If the HC is in the middle of processing the URB to be canceled, we - * simply move the ring's dequeue pointer past those TRBs using the Set - * Transfer Ring Dequeue Pointer command. This will be the common case, - * when drivers timeout on the last submitted URB and attempt to cancel. - * - * 2) If the HC is in the middle of a different TD, we turn the TRBs into a - * series of 1-TRB transfer no-op TDs. (No-ops shouldn't be chained.) The - * HC will need to invalidate the any TRBs it has cached after the stop - * endpoint command, as noted in the xHCI 0.95 errata. - * - * 3) The TD may have completed by the time the Stop Endpoint Command - * completes, so software needs to handle that case too. - * - * This function should protect against the TD enqueueing code ringing the - * doorbell while this code is waiting for a Stop Endpoint command to complete. - * It also needs to account for multiple cancellations on happening at the same - * time for the same endpoint. - * - * Note that this function can be called in any context, or so says - * usb_hcd_unlink_urb() - */ -int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) -{ - unsigned long flags; - int ret, i; - u32 temp; - struct xhci_hcd *xhci; - struct urb_priv *urb_priv; - struct xhci_td *td; - unsigned int ep_index; - struct xhci_ring *ep_ring; - struct xhci_virt_ep *ep; - - xhci = hcd_to_xhci(hcd); - spin_lock_irqsave(&xhci->lock, flags); - /* Make sure the URB hasn't completed or been unlinked already */ - ret = usb_hcd_check_unlink_urb(hcd, urb, status); - if (ret || !urb->hcpriv) - goto done; - temp = xhci_readl(xhci, &xhci->op_regs->status); - if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_HALTED)) { - xhci_dbg(xhci, "HW died, freeing TD.\n"); - urb_priv = urb->hcpriv; - for (i = urb_priv->td_cnt; i < urb_priv->length; i++) { - td = urb_priv->td[i]; - if (!list_empty(&td->td_list)) - list_del_init(&td->td_list); - if (!list_empty(&td->cancelled_td_list)) - list_del_init(&td->cancelled_td_list); - } - - usb_hcd_unlink_urb_from_ep(hcd, urb); - spin_unlock_irqrestore(&xhci->lock, flags); - usb_hcd_giveback_urb(hcd, urb, -ESHUTDOWN); - xhci_urb_free_priv(xhci, urb_priv); - return ret; - } - if ((xhci->xhc_state & XHCI_STATE_DYING) || - (xhci->xhc_state & XHCI_STATE_HALTED)) { - xhci_dbg(xhci, "Ep 0x%x: URB %p to be canceled on " - "non-responsive xHCI host.\n", - urb->ep->desc.bEndpointAddress, urb); - /* Let the stop endpoint command watchdog timer (which set this - * state) finish cleaning up the endpoint TD lists. We must - * have caught it in the middle of dropping a lock and giving - * back an URB. - */ - goto done; - } - - ep_index = xhci_get_endpoint_index(&urb->ep->desc); - ep = &xhci->devs[urb->dev->slot_id]->eps[ep_index]; - ep_ring = xhci_urb_to_transfer_ring(xhci, urb); - if (!ep_ring) { - ret = -EINVAL; - goto done; - } - - urb_priv = urb->hcpriv; - i = urb_priv->td_cnt; - if (i < urb_priv->length) - xhci_dbg(xhci, "Cancel URB %p, dev %s, ep 0x%x, " - "starting at offset 0x%llx\n", - urb, urb->dev->devpath, - urb->ep->desc.bEndpointAddress, - (unsigned long long) xhci_trb_virt_to_dma( - urb_priv->td[i]->start_seg, - urb_priv->td[i]->first_trb)); - - for (; i < urb_priv->length; i++) { - td = urb_priv->td[i]; - list_add_tail(&td->cancelled_td_list, &ep->cancelled_td_list); - } - - /* Queue a stop endpoint command, but only if this is - * the first cancellation to be handled. - */ - if (!(ep->ep_state & EP_HALT_PENDING)) { - ep->ep_state |= EP_HALT_PENDING; - ep->stop_cmds_pending++; - ep->stop_cmd_timer.expires = jiffies + - XHCI_STOP_EP_CMD_TIMEOUT * HZ; - add_timer(&ep->stop_cmd_timer); - xhci_queue_stop_endpoint(xhci, urb->dev->slot_id, ep_index, 0); - xhci_ring_cmd_db(xhci); - } -done: - spin_unlock_irqrestore(&xhci->lock, flags); - return ret; -} - -/* Drop an endpoint from a new bandwidth configuration for this device. - * Only one call to this function is allowed per endpoint before - * check_bandwidth() or reset_bandwidth() must be called. - * 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. - * - * The USB core will not allow URBs to be queued to an endpoint that is being - * disabled, so there's no need for mutual exclusion to protect - * the xhci->devs[slot_id] structure. - */ -int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, - struct usb_host_endpoint *ep) -{ - struct xhci_hcd *xhci; - struct xhci_container_ctx *in_ctx, *out_ctx; - struct xhci_input_control_ctx *ctrl_ctx; - struct xhci_slot_ctx *slot_ctx; - unsigned int last_ctx; - unsigned int ep_index; - struct xhci_ep_ctx *ep_ctx; - u32 drop_flag; - u32 new_add_flags, new_drop_flags, new_slot_info; - int ret; - - ret = xhci_check_args(hcd, udev, ep, 1, true, __func__); - if (ret <= 0) - return ret; - xhci = hcd_to_xhci(hcd); - if (xhci->xhc_state & XHCI_STATE_DYING) - return -ENODEV; - - xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev); - drop_flag = xhci_get_endpoint_flag(&ep->desc); - if (drop_flag == SLOT_FLAG || drop_flag == EP0_FLAG) { - xhci_dbg(xhci, "xHCI %s - can't drop slot or ep 0 %#x\n", - __func__, drop_flag); - return 0; - } - - in_ctx = xhci->devs[udev->slot_id]->in_ctx; - out_ctx = xhci->devs[udev->slot_id]->out_ctx; - ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); - ep_index = xhci_get_endpoint_index(&ep->desc); - ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index); - /* If the HC already knows the endpoint is disabled, - * or the HCD has noted it is disabled, ignore this request - */ - if (((ep_ctx->ep_info & cpu_to_le32(EP_STATE_MASK)) == - cpu_to_le32(EP_STATE_DISABLED)) || - le32_to_cpu(ctrl_ctx->drop_flags) & - xhci_get_endpoint_flag(&ep->desc)) { - xhci_warn(xhci, "xHCI %s called with disabled ep %p\n", - __func__, ep); - return 0; - } - - ctrl_ctx->drop_flags |= cpu_to_le32(drop_flag); - new_drop_flags = le32_to_cpu(ctrl_ctx->drop_flags); - - ctrl_ctx->add_flags &= cpu_to_le32(~drop_flag); - new_add_flags = le32_to_cpu(ctrl_ctx->add_flags); - - last_ctx = xhci_last_valid_endpoint(le32_to_cpu(ctrl_ctx->add_flags)); - slot_ctx = xhci_get_slot_ctx(xhci, in_ctx); - /* Update the last valid endpoint context, if we deleted the last one */ - if ((le32_to_cpu(slot_ctx->dev_info) & LAST_CTX_MASK) > - LAST_CTX(last_ctx)) { - slot_ctx->dev_info &= cpu_to_le32(~LAST_CTX_MASK); - slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(last_ctx)); - } - new_slot_info = le32_to_cpu(slot_ctx->dev_info); - - xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep); - - xhci_dbg(xhci, "drop ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x, new slot info = %#x\n", - (unsigned int) ep->desc.bEndpointAddress, - udev->slot_id, - (unsigned int) new_drop_flags, - (unsigned int) new_add_flags, - (unsigned int) new_slot_info); - return 0; -} - -/* Add an endpoint to a new possible bandwidth configuration for this device. - * Only one call to this function is allowed per endpoint before - * check_bandwidth() or reset_bandwidth() must be called. - * 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. - * - * The USB core will not allow URBs to be queued to an endpoint until the - * configuration or alt setting is installed in the device, so there's no need - * for mutual exclusion to protect the xhci->devs[slot_id] structure. - */ -int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, - struct usb_host_endpoint *ep) -{ - struct xhci_hcd *xhci; - struct xhci_container_ctx *in_ctx, *out_ctx; - unsigned int ep_index; - struct xhci_ep_ctx *ep_ctx; - struct xhci_slot_ctx *slot_ctx; - struct xhci_input_control_ctx *ctrl_ctx; - u32 added_ctxs; - unsigned int last_ctx; - u32 new_add_flags, new_drop_flags, new_slot_info; - struct xhci_virt_device *virt_dev; - int ret = 0; - - ret = xhci_check_args(hcd, udev, ep, 1, true, __func__); - if (ret <= 0) { - /* So we won't queue a reset ep command for a root hub */ - ep->hcpriv = NULL; - return ret; - } - xhci = hcd_to_xhci(hcd); - if (xhci->xhc_state & XHCI_STATE_DYING) - return -ENODEV; - - added_ctxs = xhci_get_endpoint_flag(&ep->desc); - last_ctx = xhci_last_valid_endpoint(added_ctxs); - if (added_ctxs == SLOT_FLAG || added_ctxs == EP0_FLAG) { - /* FIXME when we have to issue an evaluate endpoint command to - * deal with ep0 max packet size changing once we get the - * descriptors - */ - xhci_dbg(xhci, "xHCI %s - can't add slot or ep 0 %#x\n", - __func__, added_ctxs); - return 0; - } - - virt_dev = xhci->devs[udev->slot_id]; - in_ctx = virt_dev->in_ctx; - out_ctx = virt_dev->out_ctx; - ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); - ep_index = xhci_get_endpoint_index(&ep->desc); - ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index); - - /* If this endpoint is already in use, and the upper layers are trying - * to add it again without dropping it, reject the addition. - */ - if (virt_dev->eps[ep_index].ring && - !(le32_to_cpu(ctrl_ctx->drop_flags) & - xhci_get_endpoint_flag(&ep->desc))) { - xhci_warn(xhci, "Trying to add endpoint 0x%x " - "without dropping it.\n", - (unsigned int) ep->desc.bEndpointAddress); - return -EINVAL; - } - - /* If the HCD has already noted the endpoint is enabled, - * ignore this request. - */ - if (le32_to_cpu(ctrl_ctx->add_flags) & - xhci_get_endpoint_flag(&ep->desc)) { - xhci_warn(xhci, "xHCI %s called with enabled ep %p\n", - __func__, ep); - return 0; - } - - /* - * Configuration and alternate setting changes must be done in - * process context, not interrupt context (or so documenation - * for usb_set_interface() and usb_set_configuration() claim). - */ - if (xhci_endpoint_init(xhci, virt_dev, udev, ep, GFP_NOIO) < 0) { - dev_dbg(&udev->dev, "%s - could not initialize ep %#x\n", - __func__, ep->desc.bEndpointAddress); - return -ENOMEM; - } - - ctrl_ctx->add_flags |= cpu_to_le32(added_ctxs); - new_add_flags = le32_to_cpu(ctrl_ctx->add_flags); - - /* If xhci_endpoint_disable() was called for this endpoint, but the - * xHC hasn't been notified yet through the check_bandwidth() call, - * this re-adds a new state for the endpoint from the new endpoint - * descriptors. We must drop and re-add this endpoint, so we leave the - * drop flags alone. - */ - new_drop_flags = le32_to_cpu(ctrl_ctx->drop_flags); - - slot_ctx = xhci_get_slot_ctx(xhci, in_ctx); - /* Update the last valid endpoint context, if we just added one past */ - if ((le32_to_cpu(slot_ctx->dev_info) & LAST_CTX_MASK) < - LAST_CTX(last_ctx)) { - slot_ctx->dev_info &= cpu_to_le32(~LAST_CTX_MASK); - slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(last_ctx)); - } - new_slot_info = le32_to_cpu(slot_ctx->dev_info); - - /* Store the usb_device pointer for later use */ - ep->hcpriv = udev; - - xhci_dbg(xhci, "add ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x, new slot info = %#x\n", - (unsigned int) ep->desc.bEndpointAddress, - udev->slot_id, - (unsigned int) new_drop_flags, - (unsigned int) new_add_flags, - (unsigned int) new_slot_info); - return 0; -} - -static void xhci_zero_in_ctx(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev) -{ - struct xhci_input_control_ctx *ctrl_ctx; - struct xhci_ep_ctx *ep_ctx; - struct xhci_slot_ctx *slot_ctx; - int i; - - /* When a device's add flag and drop flag are zero, any subsequent - * configure endpoint command will leave that endpoint's state - * untouched. Make sure we don't leave any old state in the input - * endpoint contexts. - */ - ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); - ctrl_ctx->drop_flags = 0; - ctrl_ctx->add_flags = 0; - slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx); - slot_ctx->dev_info &= cpu_to_le32(~LAST_CTX_MASK); - /* Endpoint 0 is always valid */ - slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1)); - for (i = 1; i < 31; ++i) { - ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, i); - ep_ctx->ep_info = 0; - ep_ctx->ep_info2 = 0; - ep_ctx->deq = 0; - ep_ctx->tx_info = 0; - } -} - -static int xhci_configure_endpoint_result(struct xhci_hcd *xhci, - struct usb_device *udev, u32 *cmd_status) -{ - int ret; - - switch (*cmd_status) { - case COMP_ENOMEM: - dev_warn(&udev->dev, "Not enough host controller resources " - "for new device state.\n"); - ret = -ENOMEM; - /* FIXME: can we allocate more resources for the HC? */ - break; - case COMP_BW_ERR: - case COMP_2ND_BW_ERR: - dev_warn(&udev->dev, "Not enough bandwidth " - "for new device state.\n"); - ret = -ENOSPC; - /* FIXME: can we go back to the old state? */ - break; - case COMP_TRB_ERR: - /* the HCD set up something wrong */ - dev_warn(&udev->dev, "ERROR: Endpoint drop flag = 0, " - "add flag = 1, " - "and endpoint is not disabled.\n"); - ret = -EINVAL; - break; - case COMP_DEV_ERR: - dev_warn(&udev->dev, "ERROR: Incompatible device for endpoint " - "configure command.\n"); - ret = -ENODEV; - break; - case COMP_SUCCESS: - dev_dbg(&udev->dev, "Successful Endpoint Configure command\n"); - ret = 0; - break; - default: - xhci_err(xhci, "ERROR: unexpected command completion " - "code 0x%x.\n", *cmd_status); - ret = -EINVAL; - break; - } - return ret; -} - -static int xhci_evaluate_context_result(struct xhci_hcd *xhci, - struct usb_device *udev, u32 *cmd_status) -{ - int ret; - struct xhci_virt_device *virt_dev = xhci->devs[udev->slot_id]; - - switch (*cmd_status) { - case COMP_EINVAL: - dev_warn(&udev->dev, "WARN: xHCI driver setup invalid evaluate " - "context command.\n"); - ret = -EINVAL; - break; - case COMP_EBADSLT: - dev_warn(&udev->dev, "WARN: slot not enabled for" - "evaluate context command.\n"); - case COMP_CTX_STATE: - dev_warn(&udev->dev, "WARN: invalid context state for " - "evaluate context command.\n"); - xhci_dbg_ctx(xhci, virt_dev->out_ctx, 1); - ret = -EINVAL; - break; - case COMP_DEV_ERR: - dev_warn(&udev->dev, "ERROR: Incompatible device for evaluate " - "context command.\n"); - ret = -ENODEV; - break; - case COMP_MEL_ERR: - /* Max Exit Latency too large error */ - dev_warn(&udev->dev, "WARN: Max Exit Latency too large\n"); - ret = -EINVAL; - break; - case COMP_SUCCESS: - dev_dbg(&udev->dev, "Successful evaluate context command\n"); - ret = 0; - break; - default: - xhci_err(xhci, "ERROR: unexpected command completion " - "code 0x%x.\n", *cmd_status); - ret = -EINVAL; - break; - } - return ret; -} - -static u32 xhci_count_num_new_endpoints(struct xhci_hcd *xhci, - struct xhci_container_ctx *in_ctx) -{ - struct xhci_input_control_ctx *ctrl_ctx; - u32 valid_add_flags; - u32 valid_drop_flags; - - ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); - /* Ignore the slot flag (bit 0), and the default control endpoint flag - * (bit 1). The default control endpoint is added during the Address - * Device command and is never removed until the slot is disabled. - */ - valid_add_flags = ctrl_ctx->add_flags >> 2; - valid_drop_flags = ctrl_ctx->drop_flags >> 2; - - /* Use hweight32 to count the number of ones in the add flags, or - * number of endpoints added. Don't count endpoints that are changed - * (both added and dropped). - */ - return hweight32(valid_add_flags) - - hweight32(valid_add_flags & valid_drop_flags); -} - -static unsigned int xhci_count_num_dropped_endpoints(struct xhci_hcd *xhci, - struct xhci_container_ctx *in_ctx) -{ - struct xhci_input_control_ctx *ctrl_ctx; - u32 valid_add_flags; - u32 valid_drop_flags; - - ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); - valid_add_flags = ctrl_ctx->add_flags >> 2; - valid_drop_flags = ctrl_ctx->drop_flags >> 2; - - return hweight32(valid_drop_flags) - - hweight32(valid_add_flags & valid_drop_flags); -} - -/* - * We need to reserve the new number of endpoints before the configure endpoint - * command completes. We can't subtract the dropped endpoints from the number - * of active endpoints until the command completes because we can oversubscribe - * the host in this case: - * - * - the first configure endpoint command drops more endpoints than it adds - * - a second configure endpoint command that adds more endpoints is queued - * - the first configure endpoint command fails, so the config is unchanged - * - the second command may succeed, even though there isn't enough resources - * - * Must be called with xhci->lock held. - */ -static int xhci_reserve_host_resources(struct xhci_hcd *xhci, - struct xhci_container_ctx *in_ctx) -{ - u32 added_eps; - - added_eps = xhci_count_num_new_endpoints(xhci, in_ctx); - if (xhci->num_active_eps + added_eps > xhci->limit_active_eps) { - xhci_dbg(xhci, "Not enough ep ctxs: " - "%u active, need to add %u, limit is %u.\n", - xhci->num_active_eps, added_eps, - xhci->limit_active_eps); - return -ENOMEM; - } - xhci->num_active_eps += added_eps; - xhci_dbg(xhci, "Adding %u ep ctxs, %u now active.\n", added_eps, - xhci->num_active_eps); - return 0; -} - -/* - * The configure endpoint was failed by the xHC for some other reason, so we - * need to revert the resources that failed configuration would have used. - * - * Must be called with xhci->lock held. - */ -static void xhci_free_host_resources(struct xhci_hcd *xhci, - struct xhci_container_ctx *in_ctx) -{ - u32 num_failed_eps; - - num_failed_eps = xhci_count_num_new_endpoints(xhci, in_ctx); - xhci->num_active_eps -= num_failed_eps; - xhci_dbg(xhci, "Removing %u failed ep ctxs, %u now active.\n", - num_failed_eps, - xhci->num_active_eps); -} - -/* - * Now that the command has completed, clean up the active endpoint count by - * subtracting out the endpoints that were dropped (but not changed). - * - * Must be called with xhci->lock held. - */ -static void xhci_finish_resource_reservation(struct xhci_hcd *xhci, - struct xhci_container_ctx *in_ctx) -{ - u32 num_dropped_eps; - - num_dropped_eps = xhci_count_num_dropped_endpoints(xhci, in_ctx); - xhci->num_active_eps -= num_dropped_eps; - if (num_dropped_eps) - xhci_dbg(xhci, "Removing %u dropped ep ctxs, %u now active.\n", - num_dropped_eps, - xhci->num_active_eps); -} - -unsigned int xhci_get_block_size(struct usb_device *udev) -{ - switch (udev->speed) { - case USB_SPEED_LOW: - case USB_SPEED_FULL: - return FS_BLOCK; - case USB_SPEED_HIGH: - return HS_BLOCK; - case USB_SPEED_SUPER: - return SS_BLOCK; - case USB_SPEED_UNKNOWN: - case USB_SPEED_WIRELESS: - default: - /* Should never happen */ - return 1; - } -} - -unsigned int xhci_get_largest_overhead(struct xhci_interval_bw *interval_bw) -{ - if (interval_bw->overhead[LS_OVERHEAD_TYPE]) - return LS_OVERHEAD; - if (interval_bw->overhead[FS_OVERHEAD_TYPE]) - return FS_OVERHEAD; - return HS_OVERHEAD; -} - -/* If we are changing a LS/FS device under a HS hub, - * make sure (if we are activating a new TT) that the HS bus has enough - * bandwidth for this new TT. - */ -static int xhci_check_tt_bw_table(struct xhci_hcd *xhci, - struct xhci_virt_device *virt_dev, - int old_active_eps) -{ - struct xhci_interval_bw_table *bw_table; - struct xhci_tt_bw_info *tt_info; - - /* Find the bandwidth table for the root port this TT is attached to. */ - bw_table = &xhci->rh_bw[virt_dev->real_port - 1].bw_table; - tt_info = virt_dev->tt_info; - /* If this TT already had active endpoints, the bandwidth for this TT - * has already been added. Removing all periodic endpoints (and thus - * making the TT enactive) will only decrease the bandwidth used. - */ - if (old_active_eps) - return 0; - if (old_active_eps == 0 && tt_info->active_eps != 0) { - if (bw_table->bw_used + TT_HS_OVERHEAD > HS_BW_LIMIT) - return -ENOMEM; - return 0; - } - /* Not sure why we would have no new active endpoints... - * - * Maybe because of an Evaluate Context change for a hub update or a - * control endpoint 0 max packet size change? - * FIXME: skip the bandwidth calculation in that case. - */ - return 0; -} - -static int xhci_check_ss_bw(struct xhci_hcd *xhci, - struct xhci_virt_device *virt_dev) -{ - unsigned int bw_reserved; - - bw_reserved = DIV_ROUND_UP(SS_BW_RESERVED*SS_BW_LIMIT_IN, 100); - if (virt_dev->bw_table->ss_bw_in > (SS_BW_LIMIT_IN - bw_reserved)) - return -ENOMEM; - - bw_reserved = DIV_ROUND_UP(SS_BW_RESERVED*SS_BW_LIMIT_OUT, 100); - if (virt_dev->bw_table->ss_bw_out > (SS_BW_LIMIT_OUT - bw_reserved)) - return -ENOMEM; - - return 0; -} - -/* - * This algorithm is a very conservative estimate of the worst-case scheduling - * scenario for any one interval. The hardware dynamically schedules the - * packets, so we can't tell which microframe could be the limiting factor in - * the bandwidth scheduling. This only takes into account periodic endpoints. - * - * Obviously, we can't solve an NP complete problem to find the minimum worst - * case scenario. Instead, we come up with an estimate that is no less than - * the worst case bandwidth used for any one microframe, but may be an - * over-estimate. - * - * We walk the requirements for each endpoint by interval, starting with the - * smallest interval, and place packets in the schedule where there is only one - * possible way to schedule packets for that interval. In order to simplify - * this algorithm, we record the largest max packet size for each interval, and - * assume all packets will be that size. - * - * For interval 0, we obviously must schedule all packets for each interval. - * The bandwidth for interval 0 is just the amount of data to be transmitted - * (the sum of all max ESIT payload sizes, plus any overhead per packet times - * the number of packets). - * - * For interval 1, we have two possible microframes to schedule those packets - * in. For this algorithm, if we can schedule the same number of packets for - * each possible scheduling opportunity (each microframe), we will do so. The - * remaining number of packets will be saved to be transmitted in the gaps in - * the next interval's scheduling sequence. - * - * As we move those remaining packets to be scheduled with interval 2 packets, - * we have to double the number of remaining packets to transmit. This is - * because the intervals are actually powers of 2, and we would be transmitting - * the previous interval's packets twice in this interval. We also have to be - * sure that when we look at the largest max packet size for this interval, we - * also look at the largest max packet size for the remaining packets and take - * the greater of the two. - * - * The algorithm continues to evenly distribute packets in each scheduling - * opportunity, and push the remaining packets out, until we get to the last - * interval. Then those packets and their associated overhead are just added - * to the bandwidth used. - */ -static int xhci_check_bw_table(struct xhci_hcd *xhci, - struct xhci_virt_device *virt_dev, - int old_active_eps) -{ - unsigned int bw_reserved; - unsigned int max_bandwidth; - unsigned int bw_used; - unsigned int block_size; - struct xhci_interval_bw_table *bw_table; - unsigned int packet_size = 0; - unsigned int overhead = 0; - unsigned int packets_transmitted = 0; - unsigned int packets_remaining = 0; - unsigned int i; - - if (virt_dev->udev->speed == USB_SPEED_SUPER) - return xhci_check_ss_bw(xhci, virt_dev); - - if (virt_dev->udev->speed == USB_SPEED_HIGH) { - max_bandwidth = HS_BW_LIMIT; - /* Convert percent of bus BW reserved to blocks reserved */ - bw_reserved = DIV_ROUND_UP(HS_BW_RESERVED * max_bandwidth, 100); - } else { - max_bandwidth = FS_BW_LIMIT; - bw_reserved = DIV_ROUND_UP(FS_BW_RESERVED * max_bandwidth, 100); - } - - bw_table = virt_dev->bw_table; - /* We need to translate the max packet size and max ESIT payloads into - * the units the hardware uses. - */ - block_size = xhci_get_block_size(virt_dev->udev); - - /* If we are manipulating a LS/FS device under a HS hub, double check - * that the HS bus has enough bandwidth if we are activing a new TT. - */ - if (virt_dev->tt_info) { - xhci_dbg(xhci, "Recalculating BW for rootport %u\n", - virt_dev->real_port); - if (xhci_check_tt_bw_table(xhci, virt_dev, old_active_eps)) { - xhci_warn(xhci, "Not enough bandwidth on HS bus for " - "newly activated TT.\n"); - return -ENOMEM; - } - xhci_dbg(xhci, "Recalculating BW for TT slot %u port %u\n", - virt_dev->tt_info->slot_id, - virt_dev->tt_info->ttport); - } else { - xhci_dbg(xhci, "Recalculating BW for rootport %u\n", - virt_dev->real_port); - } - - /* Add in how much bandwidth will be used for interval zero, or the - * rounded max ESIT payload + number of packets * largest overhead. - */ - bw_used = DIV_ROUND_UP(bw_table->interval0_esit_payload, block_size) + - bw_table->interval_bw[0].num_packets * - xhci_get_largest_overhead(&bw_table->interval_bw[0]); - - for (i = 1; i < XHCI_MAX_INTERVAL; i++) { - unsigned int bw_added; - unsigned int largest_mps; - unsigned int interval_overhead; - - /* - * How many packets could we transmit in this interval? - * If packets didn't fit in the previous interval, we will need - * to transmit that many packets twice within this interval. - */ - packets_remaining = 2 * packets_remaining + - bw_table->interval_bw[i].num_packets; - - /* Find the largest max packet size of this or the previous - * interval. - */ - if (list_empty(&bw_table->interval_bw[i].endpoints)) - largest_mps = 0; - else { - struct xhci_virt_ep *virt_ep; - struct list_head *ep_entry; - - ep_entry = bw_table->interval_bw[i].endpoints.next; - virt_ep = list_entry(ep_entry, - struct xhci_virt_ep, bw_endpoint_list); - /* Convert to blocks, rounding up */ - largest_mps = DIV_ROUND_UP( - virt_ep->bw_info.max_packet_size, - block_size); - } - if (largest_mps > packet_size) - packet_size = largest_mps; - - /* Use the larger overhead of this or the previous interval. */ - interval_overhead = xhci_get_largest_overhead( - &bw_table->interval_bw[i]); - if (interval_overhead > overhead) - overhead = interval_overhead; - - /* How many packets can we evenly distribute across - * (1 << (i + 1)) possible scheduling opportunities? - */ - packets_transmitted = packets_remaining >> (i + 1); - - /* Add in the bandwidth used for those scheduled packets */ - bw_added = packets_transmitted * (overhead + packet_size); - - /* How many packets do we have remaining to transmit? */ - packets_remaining = packets_remaining % (1 << (i + 1)); - - /* What largest max packet size should those packets have? */ - /* If we've transmitted all packets, don't carry over the - * largest packet size. - */ - if (packets_remaining == 0) { - packet_size = 0; - overhead = 0; - } else if (packets_transmitted > 0) { - /* Otherwise if we do have remaining packets, and we've - * scheduled some packets in this interval, take the - * largest max packet size from endpoints with this - * interval. - */ - packet_size = largest_mps; - overhead = interval_overhead; - } - /* Otherwise carry over packet_size and overhead from the last - * time we had a remainder. - */ - bw_used += bw_added; - if (bw_used > max_bandwidth) { - xhci_warn(xhci, "Not enough bandwidth. " - "Proposed: %u, Max: %u\n", - bw_used, max_bandwidth); - return -ENOMEM; - } - } - /* - * Ok, we know we have some packets left over after even-handedly - * scheduling interval 15. We don't know which microframes they will - * fit into, so we over-schedule and say they will be scheduled every - * microframe. - */ - if (packets_remaining > 0) - bw_used += overhead + packet_size; - - if (!virt_dev->tt_info && virt_dev->udev->speed == USB_SPEED_HIGH) { - unsigned int port_index = virt_dev->real_port - 1; - - /* OK, we're manipulating a HS device attached to a - * root port bandwidth domain. Include the number of active TTs - * in the bandwidth used. - */ - bw_used += TT_HS_OVERHEAD * - xhci->rh_bw[port_index].num_active_tts; - } - - xhci_dbg(xhci, "Final bandwidth: %u, Limit: %u, Reserved: %u, " - "Available: %u " "percent\n", - bw_used, max_bandwidth, bw_reserved, - (max_bandwidth - bw_used - bw_reserved) * 100 / - max_bandwidth); - - bw_used += bw_reserved; - if (bw_used > max_bandwidth) { - xhci_warn(xhci, "Not enough bandwidth. Proposed: %u, Max: %u\n", - bw_used, max_bandwidth); - return -ENOMEM; - } - - bw_table->bw_used = bw_used; - return 0; -} - -static bool xhci_is_async_ep(unsigned int ep_type) -{ - return (ep_type != ISOC_OUT_EP && ep_type != INT_OUT_EP && - ep_type != ISOC_IN_EP && - ep_type != INT_IN_EP); -} - -static bool xhci_is_sync_in_ep(unsigned int ep_type) -{ - return (ep_type == ISOC_IN_EP || ep_type != INT_IN_EP); -} - -static unsigned int xhci_get_ss_bw_consumed(struct xhci_bw_info *ep_bw) -{ - unsigned int mps = DIV_ROUND_UP(ep_bw->max_packet_size, SS_BLOCK); - - if (ep_bw->ep_interval == 0) - return SS_OVERHEAD_BURST + - (ep_bw->mult * ep_bw->num_packets * - (SS_OVERHEAD + mps)); - return DIV_ROUND_UP(ep_bw->mult * ep_bw->num_packets * - (SS_OVERHEAD + mps + SS_OVERHEAD_BURST), - 1 << ep_bw->ep_interval); - -} - -void xhci_drop_ep_from_interval_table(struct xhci_hcd *xhci, - struct xhci_bw_info *ep_bw, - struct xhci_interval_bw_table *bw_table, - struct usb_device *udev, - struct xhci_virt_ep *virt_ep, - struct xhci_tt_bw_info *tt_info) -{ - struct xhci_interval_bw *interval_bw; - int normalized_interval; - - if (xhci_is_async_ep(ep_bw->type)) - return; - - if (udev->speed == USB_SPEED_SUPER) { - if (xhci_is_sync_in_ep(ep_bw->type)) - xhci->devs[udev->slot_id]->bw_table->ss_bw_in -= - xhci_get_ss_bw_consumed(ep_bw); - else - xhci->devs[udev->slot_id]->bw_table->ss_bw_out -= - xhci_get_ss_bw_consumed(ep_bw); - return; - } - - /* SuperSpeed endpoints never get added to intervals in the table, so - * this check is only valid for HS/FS/LS devices. - */ - if (list_empty(&virt_ep->bw_endpoint_list)) - return; - /* For LS/FS devices, we need to translate the interval expressed in - * microframes to frames. - */ - if (udev->speed == USB_SPEED_HIGH) - normalized_interval = ep_bw->ep_interval; - else - normalized_interval = ep_bw->ep_interval - 3; - - if (normalized_interval == 0) - bw_table->interval0_esit_payload -= ep_bw->max_esit_payload; - interval_bw = &bw_table->interval_bw[normalized_interval]; - interval_bw->num_packets -= ep_bw->num_packets; - switch (udev->speed) { - case USB_SPEED_LOW: - interval_bw->overhead[LS_OVERHEAD_TYPE] -= 1; - break; - case USB_SPEED_FULL: - interval_bw->overhead[FS_OVERHEAD_TYPE] -= 1; - break; - case USB_SPEED_HIGH: - interval_bw->overhead[HS_OVERHEAD_TYPE] -= 1; - break; - case USB_SPEED_SUPER: - case USB_SPEED_UNKNOWN: - case USB_SPEED_WIRELESS: - /* Should never happen because only LS/FS/HS endpoints will get - * added to the endpoint list. - */ - return; - } - if (tt_info) - tt_info->active_eps -= 1; - list_del_init(&virt_ep->bw_endpoint_list); -} - -static void xhci_add_ep_to_interval_table(struct xhci_hcd *xhci, - struct xhci_bw_info *ep_bw, - struct xhci_interval_bw_table *bw_table, - struct usb_device *udev, - struct xhci_virt_ep *virt_ep, - struct xhci_tt_bw_info *tt_info) -{ - struct xhci_interval_bw *interval_bw; - struct xhci_virt_ep *smaller_ep; - int normalized_interval; - - if (xhci_is_async_ep(ep_bw->type)) - return; - - if (udev->speed == USB_SPEED_SUPER) { - if (xhci_is_sync_in_ep(ep_bw->type)) - xhci->devs[udev->slot_id]->bw_table->ss_bw_in += - xhci_get_ss_bw_consumed(ep_bw); - else - xhci->devs[udev->slot_id]->bw_table->ss_bw_out += - xhci_get_ss_bw_consumed(ep_bw); - return; - } - - /* For LS/FS devices, we need to translate the interval expressed in - * microframes to frames. - */ - if (udev->speed == USB_SPEED_HIGH) - normalized_interval = ep_bw->ep_interval; - else - normalized_interval = ep_bw->ep_interval - 3; - - if (normalized_interval == 0) - bw_table->interval0_esit_payload += ep_bw->max_esit_payload; - interval_bw = &bw_table->interval_bw[normalized_interval]; - interval_bw->num_packets += ep_bw->num_packets; - switch (udev->speed) { - case USB_SPEED_LOW: - interval_bw->overhead[LS_OVERHEAD_TYPE] += 1; - break; - case USB_SPEED_FULL: - interval_bw->overhead[FS_OVERHEAD_TYPE] += 1; - break; - case USB_SPEED_HIGH: - interval_bw->overhead[HS_OVERHEAD_TYPE] += 1; - break; - case USB_SPEED_SUPER: - case USB_SPEED_UNKNOWN: - case USB_SPEED_WIRELESS: - /* Should never happen because only LS/FS/HS endpoints will get - * added to the endpoint list. - */ - return; - } - - if (tt_info) - tt_info->active_eps += 1; - /* Insert the endpoint into the list, largest max packet size first. */ - list_for_each_entry(smaller_ep, &interval_bw->endpoints, - bw_endpoint_list) { - if (ep_bw->max_packet_size >= - smaller_ep->bw_info.max_packet_size) { - /* Add the new ep before the smaller endpoint */ - list_add_tail(&virt_ep->bw_endpoint_list, - &smaller_ep->bw_endpoint_list); - return; - } - } - /* Add the new endpoint at the end of the list. */ - list_add_tail(&virt_ep->bw_endpoint_list, - &interval_bw->endpoints); -} - -void xhci_update_tt_active_eps(struct xhci_hcd *xhci, - struct xhci_virt_device *virt_dev, - int old_active_eps) -{ - struct xhci_root_port_bw_info *rh_bw_info; - if (!virt_dev->tt_info) - return; - - rh_bw_info = &xhci->rh_bw[virt_dev->real_port - 1]; - if (old_active_eps == 0 && - virt_dev->tt_info->active_eps != 0) { - rh_bw_info->num_active_tts += 1; - rh_bw_info->bw_table.bw_used += TT_HS_OVERHEAD; - } else if (old_active_eps != 0 && - virt_dev->tt_info->active_eps == 0) { - rh_bw_info->num_active_tts -= 1; - rh_bw_info->bw_table.bw_used -= TT_HS_OVERHEAD; - } -} - -static int xhci_reserve_bandwidth(struct xhci_hcd *xhci, - struct xhci_virt_device *virt_dev, - struct xhci_container_ctx *in_ctx) -{ - struct xhci_bw_info ep_bw_info[31]; - int i; - struct xhci_input_control_ctx *ctrl_ctx; - int old_active_eps = 0; - - if (virt_dev->tt_info) - old_active_eps = virt_dev->tt_info->active_eps; - - ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); - - for (i = 0; i < 31; i++) { - if (!EP_IS_ADDED(ctrl_ctx, i) && !EP_IS_DROPPED(ctrl_ctx, i)) - continue; - - /* Make a copy of the BW info in case we need to revert this */ - memcpy(&ep_bw_info[i], &virt_dev->eps[i].bw_info, - sizeof(ep_bw_info[i])); - /* Drop the endpoint from the interval table if the endpoint is - * being dropped or changed. - */ - if (EP_IS_DROPPED(ctrl_ctx, i)) - xhci_drop_ep_from_interval_table(xhci, - &virt_dev->eps[i].bw_info, - virt_dev->bw_table, - virt_dev->udev, - &virt_dev->eps[i], - virt_dev->tt_info); - } - /* Overwrite the information stored in the endpoints' bw_info */ - xhci_update_bw_info(xhci, virt_dev->in_ctx, ctrl_ctx, virt_dev); - for (i = 0; i < 31; i++) { - /* Add any changed or added endpoints to the interval table */ - if (EP_IS_ADDED(ctrl_ctx, i)) - xhci_add_ep_to_interval_table(xhci, - &virt_dev->eps[i].bw_info, - virt_dev->bw_table, - virt_dev->udev, - &virt_dev->eps[i], - virt_dev->tt_info); - } - - if (!xhci_check_bw_table(xhci, virt_dev, old_active_eps)) { - /* Ok, this fits in the bandwidth we have. - * Update the number of active TTs. - */ - xhci_update_tt_active_eps(xhci, virt_dev, old_active_eps); - return 0; - } - - /* We don't have enough bandwidth for this, revert the stored info. */ - for (i = 0; i < 31; i++) { - if (!EP_IS_ADDED(ctrl_ctx, i) && !EP_IS_DROPPED(ctrl_ctx, i)) - continue; - - /* Drop the new copies of any added or changed endpoints from - * the interval table. - */ - if (EP_IS_ADDED(ctrl_ctx, i)) { - xhci_drop_ep_from_interval_table(xhci, - &virt_dev->eps[i].bw_info, - virt_dev->bw_table, - virt_dev->udev, - &virt_dev->eps[i], - virt_dev->tt_info); - } - /* Revert the endpoint back to its old information */ - memcpy(&virt_dev->eps[i].bw_info, &ep_bw_info[i], - sizeof(ep_bw_info[i])); - /* Add any changed or dropped endpoints back into the table */ - if (EP_IS_DROPPED(ctrl_ctx, i)) - xhci_add_ep_to_interval_table(xhci, - &virt_dev->eps[i].bw_info, - virt_dev->bw_table, - virt_dev->udev, - &virt_dev->eps[i], - virt_dev->tt_info); - } - return -ENOMEM; -} - - -/* Issue a configure endpoint command or evaluate context command - * and wait for it to finish. - */ -static int xhci_configure_endpoint(struct xhci_hcd *xhci, - struct usb_device *udev, - struct xhci_command *command, - bool ctx_change, bool must_succeed) -{ - int ret; - int timeleft; - unsigned long flags; - struct xhci_container_ctx *in_ctx; - struct completion *cmd_completion; - u32 *cmd_status; - struct xhci_virt_device *virt_dev; - - spin_lock_irqsave(&xhci->lock, flags); - virt_dev = xhci->devs[udev->slot_id]; - - if (command) - in_ctx = command->in_ctx; - else - in_ctx = virt_dev->in_ctx; - - if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK) && - xhci_reserve_host_resources(xhci, in_ctx)) { - spin_unlock_irqrestore(&xhci->lock, flags); - xhci_warn(xhci, "Not enough host resources, " - "active endpoint contexts = %u\n", - xhci->num_active_eps); - return -ENOMEM; - } - if ((xhci->quirks & XHCI_SW_BW_CHECKING) && - xhci_reserve_bandwidth(xhci, virt_dev, in_ctx)) { - if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK)) - xhci_free_host_resources(xhci, in_ctx); - spin_unlock_irqrestore(&xhci->lock, flags); - xhci_warn(xhci, "Not enough bandwidth\n"); - return -ENOMEM; - } - - if (command) { - cmd_completion = command->completion; - cmd_status = &command->status; - command->command_trb = xhci->cmd_ring->enqueue; - - /* Enqueue pointer can be left pointing to the link TRB, - * we must handle that - */ - if (TRB_TYPE_LINK_LE32(command->command_trb->link.control)) - command->command_trb = - xhci->cmd_ring->enq_seg->next->trbs; - - list_add_tail(&command->cmd_list, &virt_dev->cmd_list); - } else { - cmd_completion = &virt_dev->cmd_completion; - cmd_status = &virt_dev->cmd_status; - } - init_completion(cmd_completion); - - if (!ctx_change) - ret = xhci_queue_configure_endpoint(xhci, in_ctx->dma, - udev->slot_id, must_succeed); - else - ret = xhci_queue_evaluate_context(xhci, in_ctx->dma, - udev->slot_id); - if (ret < 0) { - if (command) - list_del(&command->cmd_list); - if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK)) - xhci_free_host_resources(xhci, in_ctx); - spin_unlock_irqrestore(&xhci->lock, flags); - xhci_dbg(xhci, "FIXME allocate a new ring segment\n"); - return -ENOMEM; - } - xhci_ring_cmd_db(xhci); - spin_unlock_irqrestore(&xhci->lock, flags); - - /* Wait for the configure endpoint command to complete */ - timeleft = wait_for_completion_interruptible_timeout( - cmd_completion, - USB_CTRL_SET_TIMEOUT); - if (timeleft <= 0) { - xhci_warn(xhci, "%s while waiting for %s command\n", - timeleft == 0 ? "Timeout" : "Signal", - ctx_change == 0 ? - "configure endpoint" : - "evaluate context"); - /* FIXME cancel the configure endpoint command */ - return -ETIME; - } - - if (!ctx_change) - ret = xhci_configure_endpoint_result(xhci, udev, cmd_status); - else - ret = xhci_evaluate_context_result(xhci, udev, cmd_status); - - if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK)) { - spin_lock_irqsave(&xhci->lock, flags); - /* If the command failed, remove the reserved resources. - * Otherwise, clean up the estimate to include dropped eps. - */ - if (ret) - xhci_free_host_resources(xhci, in_ctx); - else - xhci_finish_resource_reservation(xhci, in_ctx); - spin_unlock_irqrestore(&xhci->lock, flags); - } - return ret; -} - -/* Called after one or more calls to xhci_add_endpoint() or - * xhci_drop_endpoint(). If this call fails, the USB core is expected - * to call xhci_reset_bandwidth(). - * - * Since we are in the middle of changing either configuration or - * installing a new alt setting, the USB core won't allow URBs to be - * enqueued for any endpoint on the old config or interface. Nothing - * else should be touching the xhci->devs[slot_id] structure, so we - * don't need to take the xhci->lock for manipulating that. - */ -int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) -{ - int i; - int ret = 0; - struct xhci_hcd *xhci; - struct xhci_virt_device *virt_dev; - struct xhci_input_control_ctx *ctrl_ctx; - struct xhci_slot_ctx *slot_ctx; - - ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__); - if (ret <= 0) - return ret; - xhci = hcd_to_xhci(hcd); - if (xhci->xhc_state & XHCI_STATE_DYING) - return -ENODEV; - - xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev); - virt_dev = xhci->devs[udev->slot_id]; - - /* See section 4.6.6 - A0 = 1; A1 = D0 = D1 = 0 */ - ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); - ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG); - ctrl_ctx->add_flags &= cpu_to_le32(~EP0_FLAG); - ctrl_ctx->drop_flags &= cpu_to_le32(~(SLOT_FLAG | EP0_FLAG)); - - /* Don't issue the command if there's no endpoints to update. */ - if (ctrl_ctx->add_flags == cpu_to_le32(SLOT_FLAG) && - ctrl_ctx->drop_flags == 0) - return 0; - - xhci_dbg(xhci, "New Input Control Context:\n"); - slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx); - xhci_dbg_ctx(xhci, virt_dev->in_ctx, - LAST_CTX_TO_EP_NUM(le32_to_cpu(slot_ctx->dev_info))); - - ret = xhci_configure_endpoint(xhci, udev, NULL, - false, false); - if (ret) { - /* Callee should call reset_bandwidth() */ - return ret; - } - - xhci_dbg(xhci, "Output context after successful config ep cmd:\n"); - xhci_dbg_ctx(xhci, virt_dev->out_ctx, - LAST_CTX_TO_EP_NUM(le32_to_cpu(slot_ctx->dev_info))); - - /* Free any rings that were dropped, but not changed. */ - for (i = 1; i < 31; ++i) { - if ((le32_to_cpu(ctrl_ctx->drop_flags) & (1 << (i + 1))) && - !(le32_to_cpu(ctrl_ctx->add_flags) & (1 << (i + 1)))) - xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i); - } - xhci_zero_in_ctx(xhci, virt_dev); - /* - * Install any rings for completely new endpoints or changed endpoints, - * and free or cache any old rings from changed endpoints. - */ - for (i = 1; i < 31; ++i) { - if (!virt_dev->eps[i].new_ring) - continue; - /* Only cache or free the old ring if it exists. - * It may not if this is the first add of an endpoint. - */ - if (virt_dev->eps[i].ring) { - xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i); - } - virt_dev->eps[i].ring = virt_dev->eps[i].new_ring; - virt_dev->eps[i].new_ring = NULL; - } - - return ret; -} - -void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) -{ - struct xhci_hcd *xhci; - struct xhci_virt_device *virt_dev; - int i, ret; - - ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__); - if (ret <= 0) - return; - xhci = hcd_to_xhci(hcd); - - xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev); - virt_dev = xhci->devs[udev->slot_id]; - /* Free any rings allocated for added endpoints */ - for (i = 0; i < 31; ++i) { - if (virt_dev->eps[i].new_ring) { - xhci_ring_free(xhci, virt_dev->eps[i].new_ring); - virt_dev->eps[i].new_ring = NULL; - } - } - xhci_zero_in_ctx(xhci, virt_dev); -} - -static void xhci_setup_input_ctx_for_config_ep(struct xhci_hcd *xhci, - struct xhci_container_ctx *in_ctx, - struct xhci_container_ctx *out_ctx, - u32 add_flags, u32 drop_flags) -{ - struct xhci_input_control_ctx *ctrl_ctx; - ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); - ctrl_ctx->add_flags = cpu_to_le32(add_flags); - ctrl_ctx->drop_flags = cpu_to_le32(drop_flags); - xhci_slot_copy(xhci, in_ctx, out_ctx); - ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG); - - xhci_dbg(xhci, "Input Context:\n"); - xhci_dbg_ctx(xhci, in_ctx, xhci_last_valid_endpoint(add_flags)); -} - -static void xhci_setup_input_ctx_for_quirk(struct xhci_hcd *xhci, - unsigned int slot_id, unsigned int ep_index, - struct xhci_dequeue_state *deq_state) -{ - struct xhci_container_ctx *in_ctx; - struct xhci_ep_ctx *ep_ctx; - u32 added_ctxs; - dma_addr_t addr; - - xhci_endpoint_copy(xhci, xhci->devs[slot_id]->in_ctx, - xhci->devs[slot_id]->out_ctx, ep_index); - in_ctx = xhci->devs[slot_id]->in_ctx; - ep_ctx = xhci_get_ep_ctx(xhci, in_ctx, ep_index); - addr = xhci_trb_virt_to_dma(deq_state->new_deq_seg, - deq_state->new_deq_ptr); - if (addr == 0) { - xhci_warn(xhci, "WARN Cannot submit config ep after " - "reset ep command\n"); - xhci_warn(xhci, "WARN deq seg = %p, deq ptr = %p\n", - deq_state->new_deq_seg, - deq_state->new_deq_ptr); - return; - } - ep_ctx->deq = cpu_to_le64(addr | deq_state->new_cycle_state); - - added_ctxs = xhci_get_endpoint_flag_from_index(ep_index); - xhci_setup_input_ctx_for_config_ep(xhci, xhci->devs[slot_id]->in_ctx, - xhci->devs[slot_id]->out_ctx, added_ctxs, added_ctxs); -} - -void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, - struct usb_device *udev, unsigned int ep_index) -{ - struct xhci_dequeue_state deq_state; - struct xhci_virt_ep *ep; - - xhci_dbg(xhci, "Cleaning up stalled endpoint ring\n"); - ep = &xhci->devs[udev->slot_id]->eps[ep_index]; - /* We need to move the HW's dequeue pointer past this TD, - * or it will attempt to resend it on the next doorbell ring. - */ - xhci_find_new_dequeue_state(xhci, udev->slot_id, - ep_index, ep->stopped_stream, ep->stopped_td, - &deq_state); - - /* HW with the reset endpoint quirk will use the saved dequeue state to - * issue a configure endpoint command later. - */ - if (!(xhci->quirks & XHCI_RESET_EP_QUIRK)) { - xhci_dbg(xhci, "Queueing new dequeue state\n"); - xhci_queue_new_dequeue_state(xhci, udev->slot_id, - ep_index, ep->stopped_stream, &deq_state); - } else { - /* Better hope no one uses the input context between now and the - * reset endpoint completion! - * XXX: No idea how this hardware will react when stream rings - * are enabled. - */ - xhci_dbg(xhci, "Setting up input context for " - "configure endpoint command\n"); - xhci_setup_input_ctx_for_quirk(xhci, udev->slot_id, - ep_index, &deq_state); - } -} - -/* Deal with stalled endpoints. The core should have sent the control message - * to clear the halt condition. However, we need to make the xHCI hardware - * reset its sequence number, since a device will expect a sequence number of - * zero after the halt condition is cleared. - * Context: in_interrupt - */ -void xhci_endpoint_reset(struct usb_hcd *hcd, - struct usb_host_endpoint *ep) -{ - struct xhci_hcd *xhci; - struct usb_device *udev; - unsigned int ep_index; - unsigned long flags; - int ret; - struct xhci_virt_ep *virt_ep; - - xhci = hcd_to_xhci(hcd); - udev = (struct usb_device *) ep->hcpriv; - /* Called with a root hub endpoint (or an endpoint that wasn't added - * with xhci_add_endpoint() - */ - if (!ep->hcpriv) - return; - ep_index = xhci_get_endpoint_index(&ep->desc); - virt_ep = &xhci->devs[udev->slot_id]->eps[ep_index]; - if (!virt_ep->stopped_td) { - xhci_dbg(xhci, "Endpoint 0x%x not halted, refusing to reset.\n", - ep->desc.bEndpointAddress); - return; - } - if (usb_endpoint_xfer_control(&ep->desc)) { - xhci_dbg(xhci, "Control endpoint stall already handled.\n"); - return; - } - - xhci_dbg(xhci, "Queueing reset endpoint command\n"); - spin_lock_irqsave(&xhci->lock, flags); - ret = xhci_queue_reset_ep(xhci, udev->slot_id, ep_index); - /* - * Can't change the ring dequeue pointer until it's transitioned to the - * stopped state, which is only upon a successful reset endpoint - * command. Better hope that last command worked! - */ - if (!ret) { - xhci_cleanup_stalled_ring(xhci, udev, ep_index); - kfree(virt_ep->stopped_td); - xhci_ring_cmd_db(xhci); - } - virt_ep->stopped_td = NULL; - virt_ep->stopped_trb = NULL; - virt_ep->stopped_stream = 0; - spin_unlock_irqrestore(&xhci->lock, flags); - - if (ret) - xhci_warn(xhci, "FIXME allocate a new ring segment\n"); -} - -static int xhci_check_streams_endpoint(struct xhci_hcd *xhci, - struct usb_device *udev, struct usb_host_endpoint *ep, - unsigned int slot_id) -{ - int ret; - unsigned int ep_index; - unsigned int ep_state; - - if (!ep) - return -EINVAL; - ret = xhci_check_args(xhci_to_hcd(xhci), udev, ep, 1, true, __func__); - if (ret <= 0) - return -EINVAL; - if (ep->ss_ep_comp.bmAttributes == 0) { - xhci_warn(xhci, "WARN: SuperSpeed Endpoint Companion" - " descriptor for ep 0x%x does not support streams\n", - ep->desc.bEndpointAddress); - return -EINVAL; - } - - ep_index = xhci_get_endpoint_index(&ep->desc); - ep_state = xhci->devs[slot_id]->eps[ep_index].ep_state; - if (ep_state & EP_HAS_STREAMS || - ep_state & EP_GETTING_STREAMS) { - xhci_warn(xhci, "WARN: SuperSpeed bulk endpoint 0x%x " - "already has streams set up.\n", - ep->desc.bEndpointAddress); - xhci_warn(xhci, "Send email to xHCI maintainer and ask for " - "dynamic stream context array reallocation.\n"); - return -EINVAL; - } - if (!list_empty(&xhci->devs[slot_id]->eps[ep_index].ring->td_list)) { - xhci_warn(xhci, "Cannot setup streams for SuperSpeed bulk " - "endpoint 0x%x; URBs are pending.\n", - ep->desc.bEndpointAddress); - return -EINVAL; - } - return 0; -} - -static void xhci_calculate_streams_entries(struct xhci_hcd *xhci, - unsigned int *num_streams, unsigned int *num_stream_ctxs) -{ - unsigned int max_streams; - - /* The stream context array size must be a power of two */ - *num_stream_ctxs = roundup_pow_of_two(*num_streams); - /* - * Find out how many primary stream array entries the host controller - * supports. Later we may use secondary stream arrays (similar to 2nd - * level page entries), but that's an optional feature for xHCI host - * controllers. xHCs must support at least 4 stream IDs. - */ - max_streams = HCC_MAX_PSA(xhci->hcc_params); - if (*num_stream_ctxs > max_streams) { - xhci_dbg(xhci, "xHCI HW only supports %u stream ctx entries.\n", - max_streams); - *num_stream_ctxs = max_streams; - *num_streams = max_streams; - } -} - -/* Returns an error code if one of the endpoint already has streams. - * This does not change any data structures, it only checks and gathers - * information. - */ -static int xhci_calculate_streams_and_bitmask(struct xhci_hcd *xhci, - struct usb_device *udev, - struct usb_host_endpoint **eps, unsigned int num_eps, - unsigned int *num_streams, u32 *changed_ep_bitmask) -{ - unsigned int max_streams; - unsigned int endpoint_flag; - int i; - int ret; - - for (i = 0; i < num_eps; i++) { - ret = xhci_check_streams_endpoint(xhci, udev, - eps[i], udev->slot_id); - if (ret < 0) - return ret; - - max_streams = usb_ss_max_streams(&eps[i]->ss_ep_comp); - if (max_streams < (*num_streams - 1)) { - xhci_dbg(xhci, "Ep 0x%x only supports %u stream IDs.\n", - eps[i]->desc.bEndpointAddress, - max_streams); - *num_streams = max_streams+1; - } - - endpoint_flag = xhci_get_endpoint_flag(&eps[i]->desc); - if (*changed_ep_bitmask & endpoint_flag) - return -EINVAL; - *changed_ep_bitmask |= endpoint_flag; - } - return 0; -} - -static u32 xhci_calculate_no_streams_bitmask(struct xhci_hcd *xhci, - struct usb_device *udev, - struct usb_host_endpoint **eps, unsigned int num_eps) -{ - u32 changed_ep_bitmask = 0; - unsigned int slot_id; - unsigned int ep_index; - unsigned int ep_state; - int i; - - slot_id = udev->slot_id; - if (!xhci->devs[slot_id]) - return 0; - - for (i = 0; i < num_eps; i++) { - ep_index = xhci_get_endpoint_index(&eps[i]->desc); - ep_state = xhci->devs[slot_id]->eps[ep_index].ep_state; - /* Are streams already being freed for the endpoint? */ - if (ep_state & EP_GETTING_NO_STREAMS) { - xhci_warn(xhci, "WARN Can't disable streams for " - "endpoint 0x%x\n, " - "streams are being disabled already.", - eps[i]->desc.bEndpointAddress); - return 0; - } - /* Are there actually any streams to free? */ - if (!(ep_state & EP_HAS_STREAMS) && - !(ep_state & EP_GETTING_STREAMS)) { - xhci_warn(xhci, "WARN Can't disable streams for " - "endpoint 0x%x\n, " - "streams are already disabled!", - eps[i]->desc.bEndpointAddress); - xhci_warn(xhci, "WARN xhci_free_streams() called " - "with non-streams endpoint\n"); - return 0; - } - changed_ep_bitmask |= xhci_get_endpoint_flag(&eps[i]->desc); - } - return changed_ep_bitmask; -} - -/* - * The USB device drivers use this function (though the HCD interface in USB - * core) to prepare a set of bulk endpoints to use streams. Streams are used to - * coordinate mass storage command queueing across multiple endpoints (basically - * a stream ID == a task ID). - * - * Setting up streams involves allocating the same size stream context array - * for each endpoint and issuing a configure endpoint command for all endpoints. - * - * Don't allow the call to succeed if one endpoint only supports one stream - * (which means it doesn't support streams at all). - * - * Drivers may get less stream IDs than they asked for, if the host controller - * hardware or endpoints claim they can't support the number of requested - * stream IDs. - */ -int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, - struct usb_host_endpoint **eps, unsigned int num_eps, - unsigned int num_streams, gfp_t mem_flags) -{ - int i, ret; - struct xhci_hcd *xhci; - struct xhci_virt_device *vdev; - struct xhci_command *config_cmd; - unsigned int ep_index; - unsigned int num_stream_ctxs; - unsigned long flags; - u32 changed_ep_bitmask = 0; - - if (!eps) - return -EINVAL; - - /* Add one to the number of streams requested to account for - * stream 0 that is reserved for xHCI usage. - */ - num_streams += 1; - xhci = hcd_to_xhci(hcd); - xhci_dbg(xhci, "Driver wants %u stream IDs (including stream 0).\n", - num_streams); - - config_cmd = xhci_alloc_command(xhci, true, true, mem_flags); - if (!config_cmd) { - xhci_dbg(xhci, "Could not allocate xHCI command structure.\n"); - return -ENOMEM; - } - - /* Check to make sure all endpoints are not already configured for - * streams. While we're at it, find the maximum number of streams that - * all the endpoints will support and check for duplicate endpoints. - */ - spin_lock_irqsave(&xhci->lock, flags); - ret = xhci_calculate_streams_and_bitmask(xhci, udev, eps, - num_eps, &num_streams, &changed_ep_bitmask); - if (ret < 0) { - xhci_free_command(xhci, config_cmd); - spin_unlock_irqrestore(&xhci->lock, flags); - return ret; - } - if (num_streams <= 1) { - xhci_warn(xhci, "WARN: endpoints can't handle " - "more than one stream.\n"); - xhci_free_command(xhci, config_cmd); - spin_unlock_irqrestore(&xhci->lock, flags); - return -EINVAL; - } - vdev = xhci->devs[udev->slot_id]; - /* Mark each endpoint as being in transition, so - * xhci_urb_enqueue() will reject all URBs. - */ - for (i = 0; i < num_eps; i++) { - ep_index = xhci_get_endpoint_index(&eps[i]->desc); - vdev->eps[ep_index].ep_state |= EP_GETTING_STREAMS; - } - spin_unlock_irqrestore(&xhci->lock, flags); - - /* Setup internal data structures and allocate HW data structures for - * streams (but don't install the HW structures in the input context - * until we're sure all memory allocation succeeded). - */ - xhci_calculate_streams_entries(xhci, &num_streams, &num_stream_ctxs); - xhci_dbg(xhci, "Need %u stream ctx entries for %u stream IDs.\n", - num_stream_ctxs, num_streams); - - for (i = 0; i < num_eps; i++) { - ep_index = xhci_get_endpoint_index(&eps[i]->desc); - vdev->eps[ep_index].stream_info = xhci_alloc_stream_info(xhci, - num_stream_ctxs, - num_streams, mem_flags); - if (!vdev->eps[ep_index].stream_info) - goto cleanup; - /* Set maxPstreams in endpoint context and update deq ptr to - * point to stream context array. FIXME - */ - } - - /* Set up the input context for a configure endpoint command. */ - for (i = 0; i < num_eps; i++) { - struct xhci_ep_ctx *ep_ctx; - - ep_index = xhci_get_endpoint_index(&eps[i]->desc); - ep_ctx = xhci_get_ep_ctx(xhci, config_cmd->in_ctx, ep_index); - - xhci_endpoint_copy(xhci, config_cmd->in_ctx, - vdev->out_ctx, ep_index); - xhci_setup_streams_ep_input_ctx(xhci, ep_ctx, - vdev->eps[ep_index].stream_info); - } - /* Tell the HW to drop its old copy of the endpoint context info - * and add the updated copy from the input context. - */ - xhci_setup_input_ctx_for_config_ep(xhci, config_cmd->in_ctx, - vdev->out_ctx, changed_ep_bitmask, changed_ep_bitmask); - - /* Issue and wait for the configure endpoint command */ - ret = xhci_configure_endpoint(xhci, udev, config_cmd, - false, false); - - /* xHC rejected the configure endpoint command for some reason, so we - * leave the old ring intact and free our internal streams data - * structure. - */ - if (ret < 0) - goto cleanup; - - spin_lock_irqsave(&xhci->lock, flags); - for (i = 0; i < num_eps; i++) { - ep_index = xhci_get_endpoint_index(&eps[i]->desc); - vdev->eps[ep_index].ep_state &= ~EP_GETTING_STREAMS; - xhci_dbg(xhci, "Slot %u ep ctx %u now has streams.\n", - udev->slot_id, ep_index); - vdev->eps[ep_index].ep_state |= EP_HAS_STREAMS; - } - xhci_free_command(xhci, config_cmd); - spin_unlock_irqrestore(&xhci->lock, flags); - - /* Subtract 1 for stream 0, which drivers can't use */ - return num_streams - 1; - -cleanup: - /* If it didn't work, free the streams! */ - for (i = 0; i < num_eps; i++) { - ep_index = xhci_get_endpoint_index(&eps[i]->desc); - xhci_free_stream_info(xhci, vdev->eps[ep_index].stream_info); - vdev->eps[ep_index].stream_info = NULL; - /* FIXME Unset maxPstreams in endpoint context and - * update deq ptr to point to normal string ring. - */ - vdev->eps[ep_index].ep_state &= ~EP_GETTING_STREAMS; - vdev->eps[ep_index].ep_state &= ~EP_HAS_STREAMS; - xhci_endpoint_zero(xhci, vdev, eps[i]); - } - xhci_free_command(xhci, config_cmd); - return -ENOMEM; -} - -/* Transition the endpoint from using streams to being a "normal" endpoint - * without streams. - * - * Modify the endpoint context state, submit a configure endpoint command, - * and free all endpoint rings for streams if that completes successfully. - */ -int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev, - struct usb_host_endpoint **eps, unsigned int num_eps, - gfp_t mem_flags) -{ - int i, ret; - struct xhci_hcd *xhci; - struct xhci_virt_device *vdev; - struct xhci_command *command; - unsigned int ep_index; - unsigned long flags; - u32 changed_ep_bitmask; - - xhci = hcd_to_xhci(hcd); - vdev = xhci->devs[udev->slot_id]; - - /* Set up a configure endpoint command to remove the streams rings */ - spin_lock_irqsave(&xhci->lock, flags); - changed_ep_bitmask = xhci_calculate_no_streams_bitmask(xhci, - udev, eps, num_eps); - if (changed_ep_bitmask == 0) { - spin_unlock_irqrestore(&xhci->lock, flags); - return -EINVAL; - } - - /* Use the xhci_command structure from the first endpoint. We may have - * allocated too many, but the driver may call xhci_free_streams() for - * each endpoint it grouped into one call to xhci_alloc_streams(). - */ - ep_index = xhci_get_endpoint_index(&eps[0]->desc); - command = vdev->eps[ep_index].stream_info->free_streams_command; - for (i = 0; i < num_eps; i++) { - struct xhci_ep_ctx *ep_ctx; - - ep_index = xhci_get_endpoint_index(&eps[i]->desc); - ep_ctx = xhci_get_ep_ctx(xhci, command->in_ctx, ep_index); - xhci->devs[udev->slot_id]->eps[ep_index].ep_state |= - EP_GETTING_NO_STREAMS; - - xhci_endpoint_copy(xhci, command->in_ctx, - vdev->out_ctx, ep_index); - xhci_setup_no_streams_ep_input_ctx(xhci, ep_ctx, - &vdev->eps[ep_index]); - } - xhci_setup_input_ctx_for_config_ep(xhci, command->in_ctx, - vdev->out_ctx, changed_ep_bitmask, changed_ep_bitmask); - spin_unlock_irqrestore(&xhci->lock, flags); - - /* Issue and wait for the configure endpoint command, - * which must succeed. - */ - ret = xhci_configure_endpoint(xhci, udev, command, - false, true); - - /* xHC rejected the configure endpoint command for some reason, so we - * leave the streams rings intact. - */ - if (ret < 0) - return ret; - - spin_lock_irqsave(&xhci->lock, flags); - for (i = 0; i < num_eps; i++) { - ep_index = xhci_get_endpoint_index(&eps[i]->desc); - xhci_free_stream_info(xhci, vdev->eps[ep_index].stream_info); - vdev->eps[ep_index].stream_info = NULL; - /* FIXME Unset maxPstreams in endpoint context and - * update deq ptr to point to normal string ring. - */ - vdev->eps[ep_index].ep_state &= ~EP_GETTING_NO_STREAMS; - vdev->eps[ep_index].ep_state &= ~EP_HAS_STREAMS; - } - spin_unlock_irqrestore(&xhci->lock, flags); - - return 0; -} - -/* - * Deletes endpoint resources for endpoints that were active before a Reset - * Device command, or a Disable Slot command. The Reset Device command leaves - * the control endpoint intact, whereas the Disable Slot command deletes it. - * - * Must be called with xhci->lock held. - */ -void xhci_free_device_endpoint_resources(struct xhci_hcd *xhci, - struct xhci_virt_device *virt_dev, bool drop_control_ep) -{ - int i; - unsigned int num_dropped_eps = 0; - unsigned int drop_flags = 0; - - for (i = (drop_control_ep ? 0 : 1); i < 31; i++) { - if (virt_dev->eps[i].ring) { - drop_flags |= 1 << i; - num_dropped_eps++; - } - } - xhci->num_active_eps -= num_dropped_eps; - if (num_dropped_eps) - xhci_dbg(xhci, "Dropped %u ep ctxs, flags = 0x%x, " - "%u now active.\n", - num_dropped_eps, drop_flags, - xhci->num_active_eps); -} - -/* - * This submits a Reset Device Command, which will set the device state to 0, - * set the device address to 0, and disable all the endpoints except the default - * control endpoint. The USB core should come back and call - * xhci_address_device(), and then re-set up the configuration. If this is - * called because of a usb_reset_and_verify_device(), then the old alternate - * settings will be re-installed through the normal bandwidth allocation - * functions. - * - * Wait for the Reset Device command to finish. Remove all structures - * associated with the endpoints that were disabled. Clear the input device - * structure? Cache the rings? Reset the control endpoint 0 max packet size? - * - * If the virt_dev to be reset does not exist or does not match the udev, - * it means the device is lost, possibly due to the xHC restore error and - * re-initialization during S3/S4. In this case, call xhci_alloc_dev() to - * re-allocate the device. - */ -int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) -{ - int ret, i; - unsigned long flags; - struct xhci_hcd *xhci; - unsigned int slot_id; - struct xhci_virt_device *virt_dev; - struct xhci_command *reset_device_cmd; - int timeleft; - int last_freed_endpoint; - struct xhci_slot_ctx *slot_ctx; - int old_active_eps = 0; - - ret = xhci_check_args(hcd, udev, NULL, 0, false, __func__); - if (ret <= 0) - return ret; - xhci = hcd_to_xhci(hcd); - slot_id = udev->slot_id; - virt_dev = xhci->devs[slot_id]; - if (!virt_dev) { - xhci_dbg(xhci, "The device to be reset with slot ID %u does " - "not exist. Re-allocate the device\n", slot_id); - ret = xhci_alloc_dev(hcd, udev); - if (ret == 1) - return 0; - else - return -EINVAL; - } - - if (virt_dev->udev != udev) { - /* If the virt_dev and the udev does not match, this virt_dev - * may belong to another udev. - * Re-allocate the device. - */ - xhci_dbg(xhci, "The device to be reset with slot ID %u does " - "not match the udev. Re-allocate the device\n", - slot_id); - ret = xhci_alloc_dev(hcd, udev); - if (ret == 1) - return 0; - else - return -EINVAL; - } - - /* If device is not setup, there is no point in resetting it */ - slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx); - if (GET_SLOT_STATE(le32_to_cpu(slot_ctx->dev_state)) == - SLOT_STATE_DISABLED) - return 0; - - xhci_dbg(xhci, "Resetting device with slot ID %u\n", slot_id); - /* Allocate the command structure that holds the struct completion. - * Assume we're in process context, since the normal device reset - * process has to wait for the device anyway. Storage devices are - * reset as part of error handling, so use GFP_NOIO instead of - * GFP_KERNEL. - */ - reset_device_cmd = xhci_alloc_command(xhci, false, true, GFP_NOIO); - if (!reset_device_cmd) { - xhci_dbg(xhci, "Couldn't allocate command structure.\n"); - return -ENOMEM; - } - - /* Attempt to submit the Reset Device command to the command ring */ - spin_lock_irqsave(&xhci->lock, flags); - reset_device_cmd->command_trb = xhci->cmd_ring->enqueue; - - /* Enqueue pointer can be left pointing to the link TRB, - * we must handle that - */ - if (TRB_TYPE_LINK_LE32(reset_device_cmd->command_trb->link.control)) - reset_device_cmd->command_trb = - xhci->cmd_ring->enq_seg->next->trbs; - - list_add_tail(&reset_device_cmd->cmd_list, &virt_dev->cmd_list); - ret = xhci_queue_reset_device(xhci, slot_id); - if (ret) { - xhci_dbg(xhci, "FIXME: allocate a command ring segment\n"); - list_del(&reset_device_cmd->cmd_list); - spin_unlock_irqrestore(&xhci->lock, flags); - goto command_cleanup; - } - xhci_ring_cmd_db(xhci); - spin_unlock_irqrestore(&xhci->lock, flags); - - /* Wait for the Reset Device command to finish */ - timeleft = wait_for_completion_interruptible_timeout( - reset_device_cmd->completion, - USB_CTRL_SET_TIMEOUT); - if (timeleft <= 0) { - xhci_warn(xhci, "%s while waiting for reset device command\n", - timeleft == 0 ? "Timeout" : "Signal"); - spin_lock_irqsave(&xhci->lock, flags); - /* The timeout might have raced with the event ring handler, so - * only delete from the list if the item isn't poisoned. - */ - if (reset_device_cmd->cmd_list.next != LIST_POISON1) - list_del(&reset_device_cmd->cmd_list); - spin_unlock_irqrestore(&xhci->lock, flags); - ret = -ETIME; - goto command_cleanup; - } - - /* The Reset Device command can't fail, according to the 0.95/0.96 spec, - * unless we tried to reset a slot ID that wasn't enabled, - * or the device wasn't in the addressed or configured state. - */ - ret = reset_device_cmd->status; - switch (ret) { - case COMP_EBADSLT: /* 0.95 completion code for bad slot ID */ - case COMP_CTX_STATE: /* 0.96 completion code for same thing */ - xhci_info(xhci, "Can't reset device (slot ID %u) in %s state\n", - slot_id, - xhci_get_slot_state(xhci, virt_dev->out_ctx)); - xhci_info(xhci, "Not freeing device rings.\n"); - /* Don't treat this as an error. May change my mind later. */ - ret = 0; - goto command_cleanup; - case COMP_SUCCESS: - xhci_dbg(xhci, "Successful reset device command.\n"); - break; - default: - if (xhci_is_vendor_info_code(xhci, ret)) - break; - xhci_warn(xhci, "Unknown completion code %u for " - "reset device command.\n", ret); - ret = -EINVAL; - goto command_cleanup; - } - - /* Free up host controller endpoint resources */ - if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK)) { - spin_lock_irqsave(&xhci->lock, flags); - /* Don't delete the default control endpoint resources */ - xhci_free_device_endpoint_resources(xhci, virt_dev, false); - spin_unlock_irqrestore(&xhci->lock, flags); - } - - /* Everything but endpoint 0 is disabled, so free or cache the rings. */ - last_freed_endpoint = 1; - for (i = 1; i < 31; ++i) { - struct xhci_virt_ep *ep = &virt_dev->eps[i]; - - if (ep->ep_state & EP_HAS_STREAMS) { - xhci_free_stream_info(xhci, ep->stream_info); - ep->stream_info = NULL; - ep->ep_state &= ~EP_HAS_STREAMS; - } - - if (ep->ring) { - xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i); - last_freed_endpoint = i; - } - if (!list_empty(&virt_dev->eps[i].bw_endpoint_list)) - xhci_drop_ep_from_interval_table(xhci, - &virt_dev->eps[i].bw_info, - virt_dev->bw_table, - udev, - &virt_dev->eps[i], - virt_dev->tt_info); - xhci_clear_endpoint_bw_info(&virt_dev->eps[i].bw_info); - } - /* If necessary, update the number of active TTs on this root port */ - xhci_update_tt_active_eps(xhci, virt_dev, old_active_eps); - - xhci_dbg(xhci, "Output context after successful reset device cmd:\n"); - xhci_dbg_ctx(xhci, virt_dev->out_ctx, last_freed_endpoint); - ret = 0; - -command_cleanup: - xhci_free_command(xhci, reset_device_cmd); - return ret; -} - -/* - * At this point, the struct usb_device is about to go away, the device has - * disconnected, and all traffic has been stopped and the endpoints have been - * disabled. Free any HC data structures associated with that device. - */ -void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) -{ - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - struct xhci_virt_device *virt_dev; - unsigned long flags; - u32 state; - int i, ret; - - ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__); - /* If the host is halted due to driver unload, we still need to free the - * device. - */ - if (ret <= 0 && ret != -ENODEV) - return; - - virt_dev = xhci->devs[udev->slot_id]; - - /* Stop any wayward timer functions (which may grab the lock) */ - for (i = 0; i < 31; ++i) { - virt_dev->eps[i].ep_state &= ~EP_HALT_PENDING; - del_timer_sync(&virt_dev->eps[i].stop_cmd_timer); - } - - if (udev->usb2_hw_lpm_enabled) { - xhci_set_usb2_hardware_lpm(hcd, udev, 0); - udev->usb2_hw_lpm_enabled = 0; - } - - spin_lock_irqsave(&xhci->lock, flags); - /* Don't disable the slot if the host controller is dead. */ - state = xhci_readl(xhci, &xhci->op_regs->status); - if (state == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) || - (xhci->xhc_state & XHCI_STATE_HALTED)) { - xhci_free_virt_device(xhci, udev->slot_id); - spin_unlock_irqrestore(&xhci->lock, flags); - return; - } - - if (xhci_queue_slot_control(xhci, TRB_DISABLE_SLOT, udev->slot_id)) { - spin_unlock_irqrestore(&xhci->lock, flags); - xhci_dbg(xhci, "FIXME: allocate a command ring segment\n"); - return; - } - xhci_ring_cmd_db(xhci); - spin_unlock_irqrestore(&xhci->lock, flags); - /* - * Event command completion handler will free any data structures - * associated with the slot. XXX Can free sleep? - */ -} - -/* - * Checks if we have enough host controller resources for the default control - * endpoint. - * - * Must be called with xhci->lock held. - */ -static int xhci_reserve_host_control_ep_resources(struct xhci_hcd *xhci) -{ - if (xhci->num_active_eps + 1 > xhci->limit_active_eps) { - xhci_dbg(xhci, "Not enough ep ctxs: " - "%u active, need to add 1, limit is %u.\n", - xhci->num_active_eps, xhci->limit_active_eps); - return -ENOMEM; - } - xhci->num_active_eps += 1; - xhci_dbg(xhci, "Adding 1 ep ctx, %u now active.\n", - xhci->num_active_eps); - return 0; -} - - -/* - * Returns 0 if the xHC ran out of device slots, the Enable Slot command - * timed out, or allocating memory failed. Returns 1 on success. - */ -int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev) -{ - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - unsigned long flags; - int timeleft; - int ret; - - spin_lock_irqsave(&xhci->lock, flags); - ret = xhci_queue_slot_control(xhci, TRB_ENABLE_SLOT, 0); - if (ret) { - spin_unlock_irqrestore(&xhci->lock, flags); - xhci_dbg(xhci, "FIXME: allocate a command ring segment\n"); - return 0; - } - xhci_ring_cmd_db(xhci); - spin_unlock_irqrestore(&xhci->lock, flags); - - /* XXX: how much time for xHC slot assignment? */ - timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev, - USB_CTRL_SET_TIMEOUT); - if (timeleft <= 0) { - xhci_warn(xhci, "%s while waiting for a slot\n", - timeleft == 0 ? "Timeout" : "Signal"); - /* FIXME cancel the enable slot request */ - return 0; - } - - if (!xhci->slot_id) { - xhci_err(xhci, "Error while assigning device slot ID\n"); - return 0; - } - - if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK)) { - spin_lock_irqsave(&xhci->lock, flags); - ret = xhci_reserve_host_control_ep_resources(xhci); - if (ret) { - spin_unlock_irqrestore(&xhci->lock, flags); - xhci_warn(xhci, "Not enough host resources, " - "active endpoint contexts = %u\n", - xhci->num_active_eps); - goto disable_slot; - } - spin_unlock_irqrestore(&xhci->lock, flags); - } - /* Use GFP_NOIO, since this function can be called from - * xhci_discover_or_reset_device(), which may be called as part of - * mass storage driver error handling. - */ - if (!xhci_alloc_virt_device(xhci, xhci->slot_id, udev, GFP_NOIO)) { - xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n"); - goto disable_slot; - } - udev->slot_id = xhci->slot_id; - /* Is this a LS or FS device under a HS hub? */ - /* Hub or peripherial? */ - return 1; - -disable_slot: - /* Disable slot, if we can do it without mem alloc */ - spin_lock_irqsave(&xhci->lock, flags); - if (!xhci_queue_slot_control(xhci, TRB_DISABLE_SLOT, udev->slot_id)) - xhci_ring_cmd_db(xhci); - spin_unlock_irqrestore(&xhci->lock, flags); - return 0; -} - -/* - * Issue an Address Device command (which will issue a SetAddress request to - * the device). - * We should be protected by the usb_address0_mutex in khubd's hub_port_init, so - * we should only issue and wait on one address command at the same time. - * - * We add one to the device address issued by the hardware because the USB core - * uses address 1 for the root hubs (even though they're not really devices). - */ -int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) -{ - unsigned long flags; - int timeleft; - struct xhci_virt_device *virt_dev; - int ret = 0; - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - struct xhci_slot_ctx *slot_ctx; - struct xhci_input_control_ctx *ctrl_ctx; - u64 temp_64; - - if (!udev->slot_id) { - xhci_dbg(xhci, "Bad Slot ID %d\n", udev->slot_id); - return -EINVAL; - } - - virt_dev = xhci->devs[udev->slot_id]; - - if (WARN_ON(!virt_dev)) { - /* - * In plug/unplug torture test with an NEC controller, - * a zero-dereference was observed once due to virt_dev = 0. - * Print useful debug rather than crash if it is observed again! - */ - xhci_warn(xhci, "Virt dev invalid for slot_id 0x%x!\n", - udev->slot_id); - return -EINVAL; - } - - slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx); - /* - * If this is the first Set Address since device plug-in or - * virt_device realloaction after a resume with an xHCI power loss, - * then set up the slot context. - */ - if (!slot_ctx->dev_info) - xhci_setup_addressable_virt_dev(xhci, udev); - /* Otherwise, update the control endpoint ring enqueue pointer. */ - else - xhci_copy_ep0_dequeue_into_input_ctx(xhci, udev); - ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); - ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG); - ctrl_ctx->drop_flags = 0; - - xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id); - xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2); - - spin_lock_irqsave(&xhci->lock, flags); - ret = xhci_queue_address_device(xhci, virt_dev->in_ctx->dma, - udev->slot_id); - if (ret) { - spin_unlock_irqrestore(&xhci->lock, flags); - xhci_dbg(xhci, "FIXME: allocate a command ring segment\n"); - return ret; - } - xhci_ring_cmd_db(xhci); - spin_unlock_irqrestore(&xhci->lock, flags); - - /* ctrl tx can take up to 5 sec; XXX: need more time for xHC? */ - timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev, - USB_CTRL_SET_TIMEOUT); - /* FIXME: From section 4.3.4: "Software shall be responsible for timing - * the SetAddress() "recovery interval" required by USB and aborting the - * command on a timeout. - */ - if (timeleft <= 0) { - xhci_warn(xhci, "%s while waiting for address device command\n", - timeleft == 0 ? "Timeout" : "Signal"); - /* FIXME cancel the address device command */ - return -ETIME; - } - - switch (virt_dev->cmd_status) { - case COMP_CTX_STATE: - case COMP_EBADSLT: - xhci_err(xhci, "Setup ERROR: address device command for slot %d.\n", - udev->slot_id); - ret = -EINVAL; - break; - case COMP_TX_ERR: - dev_warn(&udev->dev, "Device not responding to set address.\n"); - ret = -EPROTO; - break; - case COMP_DEV_ERR: - dev_warn(&udev->dev, "ERROR: Incompatible device for address " - "device command.\n"); - ret = -ENODEV; - break; - case COMP_SUCCESS: - xhci_dbg(xhci, "Successful Address Device command\n"); - break; - default: - xhci_err(xhci, "ERROR: unexpected command completion " - "code 0x%x.\n", virt_dev->cmd_status); - xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id); - xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2); - ret = -EINVAL; - break; - } - if (ret) { - return ret; - } - temp_64 = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr); - xhci_dbg(xhci, "Op regs DCBAA ptr = %#016llx\n", temp_64); - xhci_dbg(xhci, "Slot ID %d dcbaa entry @%p = %#016llx\n", - udev->slot_id, - &xhci->dcbaa->dev_context_ptrs[udev->slot_id], - (unsigned long long) - le64_to_cpu(xhci->dcbaa->dev_context_ptrs[udev->slot_id])); - xhci_dbg(xhci, "Output Context DMA address = %#08llx\n", - (unsigned long long)virt_dev->out_ctx->dma); - xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id); - xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2); - xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id); - xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2); - /* - * USB core uses address 1 for the roothubs, so we add one to the - * address given back to us by the HC. - */ - slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx); - /* Use kernel assigned address for devices; store xHC assigned - * address locally. */ - virt_dev->address = (le32_to_cpu(slot_ctx->dev_state) & DEV_ADDR_MASK) - + 1; - /* Zero the input context control for later use */ - ctrl_ctx->add_flags = 0; - ctrl_ctx->drop_flags = 0; - - xhci_dbg(xhci, "Internal device address = %d\n", virt_dev->address); - - return 0; -} - -#ifdef CONFIG_USB_SUSPEND - -/* BESL to HIRD Encoding array for USB2 LPM */ -static int xhci_besl_encoding[16] = {125, 150, 200, 300, 400, 500, 1000, 2000, - 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000}; - -/* Calculate HIRD/BESL for USB2 PORTPMSC*/ -static int xhci_calculate_hird_besl(struct xhci_hcd *xhci, - struct usb_device *udev) -{ - int u2del, besl, besl_host; - int besl_device = 0; - u32 field; - - u2del = HCS_U2_LATENCY(xhci->hcs_params3); - field = le32_to_cpu(udev->bos->ext_cap->bmAttributes); - - if (field & USB_BESL_SUPPORT) { - for (besl_host = 0; besl_host < 16; besl_host++) { - if (xhci_besl_encoding[besl_host] >= u2del) - break; - } - /* Use baseline BESL value as default */ - if (field & USB_BESL_BASELINE_VALID) - besl_device = USB_GET_BESL_BASELINE(field); - else if (field & USB_BESL_DEEP_VALID) - besl_device = USB_GET_BESL_DEEP(field); - } else { - if (u2del <= 50) - besl_host = 0; - else - besl_host = (u2del - 51) / 75 + 1; - } - - besl = besl_host + besl_device; - if (besl > 15) - besl = 15; - - return besl; -} - -static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd, - struct usb_device *udev) -{ - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - struct dev_info *dev_info; - __le32 __iomem **port_array; - __le32 __iomem *addr, *pm_addr; - u32 temp, dev_id; - unsigned int port_num; - unsigned long flags; - int hird; - int ret; - - if (hcd->speed == HCD_USB3 || !xhci->sw_lpm_support || - !udev->lpm_capable) - return -EINVAL; - - /* we only support lpm for non-hub device connected to root hub yet */ - if (!udev->parent || udev->parent->parent || - udev->descriptor.bDeviceClass == USB_CLASS_HUB) - return -EINVAL; - - spin_lock_irqsave(&xhci->lock, flags); - - /* Look for devices in lpm_failed_devs list */ - dev_id = le16_to_cpu(udev->descriptor.idVendor) << 16 | - le16_to_cpu(udev->descriptor.idProduct); - list_for_each_entry(dev_info, &xhci->lpm_failed_devs, list) { - if (dev_info->dev_id == dev_id) { - ret = -EINVAL; - goto finish; - } - } - - port_array = xhci->usb2_ports; - port_num = udev->portnum - 1; - - if (port_num > HCS_MAX_PORTS(xhci->hcs_params1)) { - xhci_dbg(xhci, "invalid port number %d\n", udev->portnum); - ret = -EINVAL; - goto finish; - } - - /* - * Test USB 2.0 software LPM. - * FIXME: some xHCI 1.0 hosts may implement a new register to set up - * hardware-controlled USB 2.0 LPM. See section 5.4.11 and 4.23.5.1.1.1 - * in the June 2011 errata release. - */ - xhci_dbg(xhci, "test port %d software LPM\n", port_num); - /* - * Set L1 Device Slot and HIRD/BESL. - * Check device's USB 2.0 extension descriptor to determine whether - * HIRD or BESL shoule be used. See USB2.0 LPM errata. - */ - pm_addr = port_array[port_num] + 1; - hird = xhci_calculate_hird_besl(xhci, udev); - temp = PORT_L1DS(udev->slot_id) | PORT_HIRD(hird); - xhci_writel(xhci, temp, pm_addr); - - /* Set port link state to U2(L1) */ - addr = port_array[port_num]; - xhci_set_link_state(xhci, port_array, port_num, XDEV_U2); - - /* wait for ACK */ - spin_unlock_irqrestore(&xhci->lock, flags); - msleep(10); - spin_lock_irqsave(&xhci->lock, flags); - - /* Check L1 Status */ - ret = handshake(xhci, pm_addr, PORT_L1S_MASK, PORT_L1S_SUCCESS, 125); - if (ret != -ETIMEDOUT) { - /* enter L1 successfully */ - temp = xhci_readl(xhci, addr); - xhci_dbg(xhci, "port %d entered L1 state, port status 0x%x\n", - port_num, temp); - ret = 0; - } else { - temp = xhci_readl(xhci, pm_addr); - xhci_dbg(xhci, "port %d software lpm failed, L1 status %d\n", - port_num, temp & PORT_L1S_MASK); - ret = -EINVAL; - } - - /* Resume the port */ - xhci_set_link_state(xhci, port_array, port_num, XDEV_U0); - - spin_unlock_irqrestore(&xhci->lock, flags); - msleep(10); - spin_lock_irqsave(&xhci->lock, flags); - - /* Clear PLC */ - xhci_test_and_clear_bit(xhci, port_array, port_num, PORT_PLC); - - /* Check PORTSC to make sure the device is in the right state */ - if (!ret) { - temp = xhci_readl(xhci, addr); - xhci_dbg(xhci, "resumed port %d status 0x%x\n", port_num, temp); - if (!(temp & PORT_CONNECT) || !(temp & PORT_PE) || - (temp & PORT_PLS_MASK) != XDEV_U0) { - xhci_dbg(xhci, "port L1 resume fail\n"); - ret = -EINVAL; - } - } - - if (ret) { - /* Insert dev to lpm_failed_devs list */ - xhci_warn(xhci, "device LPM test failed, may disconnect and " - "re-enumerate\n"); - dev_info = kzalloc(sizeof(struct dev_info), GFP_ATOMIC); - if (!dev_info) { - ret = -ENOMEM; - goto finish; - } - dev_info->dev_id = dev_id; - INIT_LIST_HEAD(&dev_info->list); - list_add(&dev_info->list, &xhci->lpm_failed_devs); - } else { - xhci_ring_device(xhci, udev->slot_id); - } - -finish: - spin_unlock_irqrestore(&xhci->lock, flags); - return ret; -} - -int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, - struct usb_device *udev, int enable) -{ - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - __le32 __iomem **port_array; - __le32 __iomem *pm_addr; - u32 temp; - unsigned int port_num; - unsigned long flags; - int hird; - - if (hcd->speed == HCD_USB3 || !xhci->hw_lpm_support || - !udev->lpm_capable) - return -EPERM; - - if (!udev->parent || udev->parent->parent || - udev->descriptor.bDeviceClass == USB_CLASS_HUB) - return -EPERM; - - if (udev->usb2_hw_lpm_capable != 1) - return -EPERM; - - spin_lock_irqsave(&xhci->lock, flags); - - port_array = xhci->usb2_ports; - port_num = udev->portnum - 1; - pm_addr = port_array[port_num] + 1; - temp = xhci_readl(xhci, pm_addr); - - xhci_dbg(xhci, "%s port %d USB2 hardware LPM\n", - enable ? "enable" : "disable", port_num); - - hird = xhci_calculate_hird_besl(xhci, udev); - - if (enable) { - temp &= ~PORT_HIRD_MASK; - temp |= PORT_HIRD(hird) | PORT_RWE; - xhci_writel(xhci, temp, pm_addr); - temp = xhci_readl(xhci, pm_addr); - temp |= PORT_HLE; - xhci_writel(xhci, temp, pm_addr); - } else { - temp &= ~(PORT_HLE | PORT_RWE | PORT_HIRD_MASK); - xhci_writel(xhci, temp, pm_addr); - } - - spin_unlock_irqrestore(&xhci->lock, flags); - return 0; -} - -int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev) -{ - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - int ret; - - ret = xhci_usb2_software_lpm_test(hcd, udev); - if (!ret) { - xhci_dbg(xhci, "software LPM test succeed\n"); - if (xhci->hw_lpm_support == 1) { - udev->usb2_hw_lpm_capable = 1; - ret = xhci_set_usb2_hardware_lpm(hcd, udev, 1); - if (!ret) - udev->usb2_hw_lpm_enabled = 1; - } - } - - return 0; -} - -#else - -int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, - struct usb_device *udev, int enable) -{ - return 0; -} - -int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev) -{ - return 0; -} - -#endif /* CONFIG_USB_SUSPEND */ - -/* Once a hub descriptor is fetched for a device, we need to update the xHC's - * internal data structures for the device. - */ -int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, - struct usb_tt *tt, gfp_t mem_flags) -{ - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - struct xhci_virt_device *vdev; - struct xhci_command *config_cmd; - struct xhci_input_control_ctx *ctrl_ctx; - struct xhci_slot_ctx *slot_ctx; - unsigned long flags; - unsigned think_time; - int ret; - - /* Ignore root hubs */ - if (!hdev->parent) - return 0; - - vdev = xhci->devs[hdev->slot_id]; - if (!vdev) { - xhci_warn(xhci, "Cannot update hub desc for unknown device.\n"); - return -EINVAL; - } - config_cmd = xhci_alloc_command(xhci, true, true, mem_flags); - if (!config_cmd) { - xhci_dbg(xhci, "Could not allocate xHCI command structure.\n"); - return -ENOMEM; - } - - spin_lock_irqsave(&xhci->lock, flags); - if (hdev->speed == USB_SPEED_HIGH && - xhci_alloc_tt_info(xhci, vdev, hdev, tt, GFP_ATOMIC)) { - xhci_dbg(xhci, "Could not allocate xHCI TT structure.\n"); - xhci_free_command(xhci, config_cmd); - spin_unlock_irqrestore(&xhci->lock, flags); - return -ENOMEM; - } - - xhci_slot_copy(xhci, config_cmd->in_ctx, vdev->out_ctx); - ctrl_ctx = xhci_get_input_control_ctx(xhci, config_cmd->in_ctx); - ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG); - slot_ctx = xhci_get_slot_ctx(xhci, config_cmd->in_ctx); - slot_ctx->dev_info |= cpu_to_le32(DEV_HUB); - if (tt->multi) - slot_ctx->dev_info |= cpu_to_le32(DEV_MTT); - if (xhci->hci_version > 0x95) { - xhci_dbg(xhci, "xHCI version %x needs hub " - "TT think time and number of ports\n", - (unsigned int) xhci->hci_version); - slot_ctx->dev_info2 |= cpu_to_le32(XHCI_MAX_PORTS(hdev->maxchild)); - /* Set TT think time - convert from ns to FS bit times. - * 0 = 8 FS bit times, 1 = 16 FS bit times, - * 2 = 24 FS bit times, 3 = 32 FS bit times. - * - * xHCI 1.0: this field shall be 0 if the device is not a - * High-spped hub. - */ - think_time = tt->think_time; - if (think_time != 0) - think_time = (think_time / 666) - 1; - if (xhci->hci_version < 0x100 || hdev->speed == USB_SPEED_HIGH) - slot_ctx->tt_info |= - cpu_to_le32(TT_THINK_TIME(think_time)); - } else { - xhci_dbg(xhci, "xHCI version %x doesn't need hub " - "TT think time or number of ports\n", - (unsigned int) xhci->hci_version); - } - slot_ctx->dev_state = 0; - spin_unlock_irqrestore(&xhci->lock, flags); - - xhci_dbg(xhci, "Set up %s for hub device.\n", - (xhci->hci_version > 0x95) ? - "configure endpoint" : "evaluate context"); - xhci_dbg(xhci, "Slot %u Input Context:\n", hdev->slot_id); - xhci_dbg_ctx(xhci, config_cmd->in_ctx, 0); - - /* Issue and wait for the configure endpoint or - * evaluate context command. - */ - if (xhci->hci_version > 0x95) - ret = xhci_configure_endpoint(xhci, hdev, config_cmd, - false, false); - else - ret = xhci_configure_endpoint(xhci, hdev, config_cmd, - true, false); - - xhci_dbg(xhci, "Slot %u Output Context:\n", hdev->slot_id); - xhci_dbg_ctx(xhci, vdev->out_ctx, 0); - - xhci_free_command(xhci, config_cmd); - return ret; -} - -int xhci_get_frame(struct usb_hcd *hcd) -{ - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - /* EHCI mods by the periodic size. Why? */ - return xhci_readl(xhci, &xhci->run_regs->microframe_index) >> 3; -} - -int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) -{ - struct xhci_hcd *xhci; - struct device *dev = hcd->self.controller; - int retval; - u32 temp; - - /* Accept arbitrarily long scatter-gather lists */ - hcd->self.sg_tablesize = ~0; - - if (usb_hcd_is_primary_hcd(hcd)) { - xhci = kzalloc(sizeof(struct xhci_hcd), GFP_KERNEL); - if (!xhci) - return -ENOMEM; - *((struct xhci_hcd **) hcd->hcd_priv) = xhci; - xhci->main_hcd = hcd; - /* Mark the first roothub as being USB 2.0. - * The xHCI driver will register the USB 3.0 roothub. - */ - hcd->speed = HCD_USB2; - hcd->self.root_hub->speed = USB_SPEED_HIGH; - /* - * USB 2.0 roothub under xHCI has an integrated TT, - * (rate matching hub) as opposed to having an OHCI/UHCI - * companion controller. - */ - hcd->has_tt = 1; - } else { - /* xHCI private pointer was set in xhci_pci_probe for the second - * registered roothub. - */ - xhci = hcd_to_xhci(hcd); - temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); - if (HCC_64BIT_ADDR(temp)) { - xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n"); - dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64)); - } else { - dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32)); - } - return 0; - } - - 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->hc_capbase); - xhci->hci_version = HC_VERSION(xhci->hcc_params); - xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hcc_params); - xhci_print_registers(xhci); - - get_quirks(dev, xhci); - - /* Make sure the HC is halted. */ - retval = xhci_halt(xhci); - if (retval) - goto error; - - xhci_dbg(xhci, "Resetting HCD\n"); - /* Reset the internal HC memory state and registers. */ - retval = xhci_reset(xhci); - if (retval) - goto error; - xhci_dbg(xhci, "Reset complete\n"); - - temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); - if (HCC_64BIT_ADDR(temp)) { - xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n"); - dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64)); - } else { - dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32)); - } - - xhci_dbg(xhci, "Calling HCD init\n"); - /* Initialize HCD and host controller data structures. */ - retval = xhci_init(hcd); - if (retval) - goto error; - xhci_dbg(xhci, "Called HCD init\n"); - return 0; -error: - kfree(xhci); - return retval; -} - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_LICENSE("GPL"); - -static int __init xhci_hcd_init(void) -{ - int retval; - - retval = xhci_register_pci(); - if (retval < 0) { - printk(KERN_DEBUG "Problem registering PCI driver."); - return retval; - } - retval = xhci_register_plat(); - if (retval < 0) { - printk(KERN_DEBUG "Problem registering platform driver."); - goto unreg_pci; - } - /* - * Check the compiler generated sizes of structures that must be laid - * out in specific ways for hardware access. - */ - BUILD_BUG_ON(sizeof(struct xhci_doorbell_array) != 256*32/8); - BUILD_BUG_ON(sizeof(struct xhci_slot_ctx) != 8*32/8); - BUILD_BUG_ON(sizeof(struct xhci_ep_ctx) != 8*32/8); - /* xhci_device_control has eight fields, and also - * embeds one xhci_slot_ctx and 31 xhci_ep_ctx - */ - BUILD_BUG_ON(sizeof(struct xhci_stream_ctx) != 4*32/8); - BUILD_BUG_ON(sizeof(union xhci_trb) != 4*32/8); - BUILD_BUG_ON(sizeof(struct xhci_erst_entry) != 4*32/8); - BUILD_BUG_ON(sizeof(struct xhci_cap_regs) != 7*32/8); - BUILD_BUG_ON(sizeof(struct xhci_intr_reg) != 8*32/8); - /* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */ - BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8); - BUILD_BUG_ON(sizeof(struct xhci_doorbell_array) != 256*32/8); - return 0; -unreg_pci: - xhci_unregister_pci(); - return retval; -} -module_init(xhci_hcd_init); - -static void __exit xhci_hcd_cleanup(void) -{ - xhci_unregister_pci(); - xhci_unregister_plat(); -} -module_exit(xhci_hcd_cleanup); diff --git a/ANDROID_3.4.5/drivers/usb/host/xhci.h b/ANDROID_3.4.5/drivers/usb/host/xhci.h deleted file mode 100644 index 59434fe9..00000000 --- a/ANDROID_3.4.5/drivers/usb/host/xhci.h +++ /dev/null @@ -1,1810 +0,0 @@ -/* - * 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. - */ - -#ifndef __LINUX_XHCI_HCD_H -#define __LINUX_XHCI_HCD_H - -#include -#include -#include -#include - -/* Code sharing between pci-quirks and xhci hcd */ -#include "xhci-ext-caps.h" -#include "pci-quirks.h" - -/* xHCI PCI Configuration Registers */ -#define XHCI_SBRN_OFFSET (0x60) - -/* Max number of USB devices for any host controller - limit in section 6.1 */ -#define MAX_HC_SLOTS 256 -/* Section 5.3.3 - MaxPorts */ -#define MAX_HC_PORTS 127 - -/* - * xHCI register interface. - * This corresponds to the eXtensible Host Controller Interface (xHCI) - * Revision 0.95 specification - */ - -/** - * struct xhci_cap_regs - xHCI Host Controller Capability Registers. - * @hc_capbase: length of the capabilities register and HC version number - * @hcs_params1: HCSPARAMS1 - Structural Parameters 1 - * @hcs_params2: HCSPARAMS2 - Structural Parameters 2 - * @hcs_params3: HCSPARAMS3 - Structural Parameters 3 - * @hcc_params: HCCPARAMS - Capability Parameters - * @db_off: DBOFF - Doorbell array offset - * @run_regs_off: RTSOFF - Runtime register space offset - */ -struct xhci_cap_regs { - __le32 hc_capbase; - __le32 hcs_params1; - __le32 hcs_params2; - __le32 hcs_params3; - __le32 hcc_params; - __le32 db_off; - __le32 run_regs_off; - /* Reserved up to (CAPLENGTH - 0x1C) */ -}; - -/* hc_capbase bitmasks */ -/* bits 7:0 - how long is the Capabilities register */ -#define HC_LENGTH(p) XHCI_HC_LENGTH(p) -/* bits 31:16 */ -#define HC_VERSION(p) (((p) >> 16) & 0xffff) - -/* HCSPARAMS1 - hcs_params1 - bitmasks */ -/* bits 0:7, Max Device Slots */ -#define HCS_MAX_SLOTS(p) (((p) >> 0) & 0xff) -#define HCS_SLOTS_MASK 0xff -/* bits 8:18, Max Interrupters */ -#define HCS_MAX_INTRS(p) (((p) >> 8) & 0x7ff) -/* bits 24:31, Max Ports - max value is 0x7F = 127 ports */ -#define HCS_MAX_PORTS(p) (((p) >> 24) & 0x7f) - -/* HCSPARAMS2 - hcs_params2 - bitmasks */ -/* bits 0:3, frames or uframes that SW needs to queue transactions - * ahead of the HW to meet periodic deadlines */ -#define HCS_IST(p) (((p) >> 0) & 0xf) -/* bits 4:7, max number of Event Ring segments */ -#define HCS_ERST_MAX(p) (((p) >> 4) & 0xf) -/* bit 26 Scratchpad restore - for save/restore HW state - not used yet */ -/* bits 27:31 number of Scratchpad buffers SW must allocate for the HW */ -#define HCS_MAX_SCRATCHPAD(p) (((p) >> 27) & 0x1f) - -/* HCSPARAMS3 - hcs_params3 - bitmasks */ -/* bits 0:7, Max U1 to U0 latency for the roothub ports */ -#define HCS_U1_LATENCY(p) (((p) >> 0) & 0xff) -/* bits 16:31, Max U2 to U0 latency for the roothub ports */ -#define HCS_U2_LATENCY(p) (((p) >> 16) & 0xffff) - -/* HCCPARAMS - hcc_params - bitmasks */ -/* true: HC can use 64-bit address pointers */ -#define HCC_64BIT_ADDR(p) ((p) & (1 << 0)) -/* true: HC can do bandwidth negotiation */ -#define HCC_BANDWIDTH_NEG(p) ((p) & (1 << 1)) -/* true: HC uses 64-byte Device Context structures - * FIXME 64-byte context structures aren't supported yet. - */ -#define HCC_64BYTE_CONTEXT(p) ((p) & (1 << 2)) -/* true: HC has port power switches */ -#define HCC_PPC(p) ((p) & (1 << 3)) -/* true: HC has port indicators */ -#define HCS_INDICATOR(p) ((p) & (1 << 4)) -/* true: HC has Light HC Reset Capability */ -#define HCC_LIGHT_RESET(p) ((p) & (1 << 5)) -/* true: HC supports latency tolerance messaging */ -#define HCC_LTC(p) ((p) & (1 << 6)) -/* true: no secondary Stream ID Support */ -#define HCC_NSS(p) ((p) & (1 << 7)) -/* Max size for Primary Stream Arrays - 2^(n+1), where n is bits 12:15 */ -#define HCC_MAX_PSA(p) (1 << ((((p) >> 12) & 0xf) + 1)) -/* Extended Capabilities pointer from PCI base - section 5.3.6 */ -#define HCC_EXT_CAPS(p) XHCI_HCC_EXT_CAPS(p) - -/* db_off bitmask - bits 0:1 reserved */ -#define DBOFF_MASK (~0x3) - -/* run_regs_off bitmask - bits 0:4 reserved */ -#define RTSOFF_MASK (~0x1f) - - -/* Number of registers per port */ -#define NUM_PORT_REGS 4 - -/** - * struct xhci_op_regs - xHCI Host Controller Operational Registers. - * @command: USBCMD - xHC command register - * @status: USBSTS - xHC status register - * @page_size: This indicates the page size that the host controller - * supports. If bit n is set, the HC supports a page size - * of 2^(n+12), up to a 128MB page size. - * 4K is the minimum page size. - * @cmd_ring: CRP - 64-bit Command Ring Pointer - * @dcbaa_ptr: DCBAAP - 64-bit Device Context Base Address Array Pointer - * @config_reg: CONFIG - Configure Register - * @port_status_base: PORTSCn - base address for Port Status and Control - * Each port has a Port Status and Control register, - * followed by a Port Power Management Status and Control - * register, a Port Link Info register, and a reserved - * register. - * @port_power_base: PORTPMSCn - base address for - * Port Power Management Status and Control - * @port_link_base: PORTLIn - base address for Port Link Info (current - * Link PM state and control) for USB 2.1 and USB 3.0 - * devices. - */ -struct xhci_op_regs { - __le32 command; - __le32 status; - __le32 page_size; - __le32 reserved1; - __le32 reserved2; - __le32 dev_notification; - __le64 cmd_ring; - /* rsvd: offset 0x20-2F */ - __le32 reserved3[4]; - __le64 dcbaa_ptr; - __le32 config_reg; - /* rsvd: offset 0x3C-3FF */ - __le32 reserved4[241]; - /* port 1 registers, which serve as a base address for other ports */ - __le32 port_status_base; - __le32 port_power_base; - __le32 port_link_base; - __le32 reserved5; - /* registers for ports 2-255 */ - __le32 reserved6[NUM_PORT_REGS*254]; -}; - -/* USBCMD - USB command - command bitmasks */ -/* start/stop HC execution - do not write unless HC is halted*/ -#define CMD_RUN XHCI_CMD_RUN -/* Reset HC - resets internal HC state machine and all registers (except - * PCI config regs). HC does NOT drive a USB reset on the downstream ports. - * The xHCI driver must reinitialize the xHC after setting this bit. - */ -#define CMD_RESET (1 << 1) -/* Event Interrupt Enable - a '1' allows interrupts from the host controller */ -#define CMD_EIE XHCI_CMD_EIE -/* Host System Error Interrupt Enable - get out-of-band signal for HC errors */ -#define CMD_HSEIE XHCI_CMD_HSEIE -/* bits 4:6 are reserved (and should be preserved on writes). */ -/* light reset (port status stays unchanged) - reset completed when this is 0 */ -#define CMD_LRESET (1 << 7) -/* host controller save/restore state. */ -#define CMD_CSS (1 << 8) -#define CMD_CRS (1 << 9) -/* Enable Wrap Event - '1' means xHC generates an event when MFINDEX wraps. */ -#define CMD_EWE XHCI_CMD_EWE -/* MFINDEX power management - '1' means xHC can stop MFINDEX counter if all root - * hubs are in U3 (selective suspend), disconnect, disabled, or powered-off. - * '0' means the xHC can power it off if all ports are in the disconnect, - * disabled, or powered-off state. - */ -#define CMD_PM_INDEX (1 << 11) -/* bits 12:31 are reserved (and should be preserved on writes). */ - -/* IMAN - Interrupt Management Register */ -#define IMAN_IP (1 << 1) -#define IMAN_IE (1 << 0) - -/* USBSTS - USB status - status bitmasks */ -/* HC not running - set to 1 when run/stop bit is cleared. */ -#define STS_HALT XHCI_STS_HALT -/* serious error, e.g. PCI parity error. The HC will clear the run/stop bit. */ -#define STS_FATAL (1 << 2) -/* event interrupt - clear this prior to clearing any IP flags in IR set*/ -#define STS_EINT (1 << 3) -/* port change detect */ -#define STS_PORT (1 << 4) -/* bits 5:7 reserved and zeroed */ -/* save state status - '1' means xHC is saving state */ -#define STS_SAVE (1 << 8) -/* restore state status - '1' means xHC is restoring state */ -#define STS_RESTORE (1 << 9) -/* true: save or restore error */ -#define STS_SRE (1 << 10) -/* true: Controller Not Ready to accept doorbell or op reg writes after reset */ -#define STS_CNR XHCI_STS_CNR -/* true: internal Host Controller Error - SW needs to reset and reinitialize */ -#define STS_HCE (1 << 12) -/* bits 13:31 reserved and should be preserved */ - -/* - * DNCTRL - Device Notification Control Register - dev_notification bitmasks - * Generate a device notification event when the HC sees a transaction with a - * notification type that matches a bit set in this bit field. - */ -#define DEV_NOTE_MASK (0xffff) -#define ENABLE_DEV_NOTE(x) (1 << (x)) -/* Most of the device notification types should only be used for debug. - * SW does need to pay attention to function wake notifications. - */ -#define DEV_NOTE_FWAKE ENABLE_DEV_NOTE(1) - -/* CRCR - Command Ring Control Register - cmd_ring bitmasks */ -/* bit 0 is the command ring cycle state */ -/* stop ring operation after completion of the currently executing command */ -#define CMD_RING_PAUSE (1 << 1) -/* stop ring immediately - abort the currently executing command */ -#define CMD_RING_ABORT (1 << 2) -/* true: command ring is running */ -#define CMD_RING_RUNNING (1 << 3) -/* bits 4:5 reserved and should be preserved */ -/* Command Ring pointer - bit mask for the lower 32 bits. */ -#define CMD_RING_RSVD_BITS (0x3f) - -/* CONFIG - Configure Register - config_reg bitmasks */ -/* bits 0:7 - maximum number of device slots enabled (NumSlotsEn) */ -#define MAX_DEVS(p) ((p) & 0xff) -/* bits 8:31 - reserved and should be preserved */ - -/* PORTSC - Port Status and Control Register - port_status_base bitmasks */ -/* true: device connected */ -#define PORT_CONNECT (1 << 0) -/* true: port enabled */ -#define PORT_PE (1 << 1) -/* bit 2 reserved and zeroed */ -/* true: port has an over-current condition */ -#define PORT_OC (1 << 3) -/* true: port reset signaling asserted */ -#define PORT_RESET (1 << 4) -/* Port Link State - bits 5:8 - * A read gives the current link PM state of the port, - * a write with Link State Write Strobe set sets the link state. - */ -#define PORT_PLS_MASK (0xf << 5) -#define XDEV_U0 (0x0 << 5) -#define XDEV_U2 (0x2 << 5) -#define XDEV_U3 (0x3 << 5) -#define XDEV_RESUME (0xf << 5) -/* true: port has power (see HCC_PPC) */ -#define PORT_POWER (1 << 9) -/* bits 10:13 indicate device speed: - * 0 - undefined speed - port hasn't be initialized by a reset yet - * 1 - full speed - * 2 - low speed - * 3 - high speed - * 4 - super speed - * 5-15 reserved - */ -#define DEV_SPEED_MASK (0xf << 10) -#define XDEV_FS (0x1 << 10) -#define XDEV_LS (0x2 << 10) -#define XDEV_HS (0x3 << 10) -#define XDEV_SS (0x4 << 10) -#define DEV_UNDEFSPEED(p) (((p) & DEV_SPEED_MASK) == (0x0<<10)) -#define DEV_FULLSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_FS) -#define DEV_LOWSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_LS) -#define DEV_HIGHSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_HS) -#define DEV_SUPERSPEED(p) (((p) & DEV_SPEED_MASK) == XDEV_SS) -/* Bits 20:23 in the Slot Context are the speed for the device */ -#define SLOT_SPEED_FS (XDEV_FS << 10) -#define SLOT_SPEED_LS (XDEV_LS << 10) -#define SLOT_SPEED_HS (XDEV_HS << 10) -#define SLOT_SPEED_SS (XDEV_SS << 10) -/* Port Indicator Control */ -#define PORT_LED_OFF (0 << 14) -#define PORT_LED_AMBER (1 << 14) -#define PORT_LED_GREEN (2 << 14) -#define PORT_LED_MASK (3 << 14) -/* Port Link State Write Strobe - set this when changing link state */ -#define PORT_LINK_STROBE (1 << 16) -/* true: connect status change */ -#define PORT_CSC (1 << 17) -/* true: port enable change */ -#define PORT_PEC (1 << 18) -/* true: warm reset for a USB 3.0 device is done. A "hot" reset puts the port - * into an enabled state, and the device into the default state. A "warm" reset - * also resets the link, forcing the device through the link training sequence. - * SW can also look at the Port Reset register to see when warm reset is done. - */ -#define PORT_WRC (1 << 19) -/* true: over-current change */ -#define PORT_OCC (1 << 20) -/* true: reset change - 1 to 0 transition of PORT_RESET */ -#define PORT_RC (1 << 21) -/* port link status change - set on some port link state transitions: - * Transition Reason - * ------------------------------------------------------------------------------ - * - U3 to Resume Wakeup signaling from a device - * - Resume to Recovery to U0 USB 3.0 device resume - * - Resume to U0 USB 2.0 device resume - * - U3 to Recovery to U0 Software resume of USB 3.0 device complete - * - U3 to U0 Software resume of USB 2.0 device complete - * - U2 to U0 L1 resume of USB 2.1 device complete - * - U0 to U0 (???) L1 entry rejection by USB 2.1 device - * - U0 to disabled L1 entry error with USB 2.1 device - * - Any state to inactive Error on USB 3.0 port - */ -#define PORT_PLC (1 << 22) -/* port configure error change - port failed to configure its link partner */ -#define PORT_CEC (1 << 23) -/* Cold Attach Status - xHC can set this bit to report device attached during - * Sx state. Warm port reset should be perfomed to clear this bit and move port - * to connected state. - */ -#define PORT_CAS (1 << 24) -/* wake on connect (enable) */ -#define PORT_WKCONN_E (1 << 25) -/* wake on disconnect (enable) */ -#define PORT_WKDISC_E (1 << 26) -/* wake on over-current (enable) */ -#define PORT_WKOC_E (1 << 27) -/* bits 28:29 reserved */ -/* true: device is removable - for USB 3.0 roothub emulation */ -#define PORT_DEV_REMOVE (1 << 30) -/* Initiate a warm port reset - complete when PORT_WRC is '1' */ -#define PORT_WR (1 << 31) - -/* We mark duplicate entries with -1 */ -#define DUPLICATE_ENTRY ((u8)(-1)) - -/* Port Power Management Status and Control - port_power_base bitmasks */ -/* Inactivity timer value for transitions into U1, in microseconds. - * Timeout can be up to 127us. 0xFF means an infinite timeout. - */ -#define PORT_U1_TIMEOUT(p) ((p) & 0xff) -/* Inactivity timer value for transitions into U2 */ -#define PORT_U2_TIMEOUT(p) (((p) & 0xff) << 8) -/* Bits 24:31 for port testing */ - -/* USB2 Protocol PORTSPMSC */ -#define PORT_L1S_MASK 7 -#define PORT_L1S_SUCCESS 1 -#define PORT_RWE (1 << 3) -#define PORT_HIRD(p) (((p) & 0xf) << 4) -#define PORT_HIRD_MASK (0xf << 4) -#define PORT_L1DS(p) (((p) & 0xff) << 8) -#define PORT_HLE (1 << 16) - -/** - * struct xhci_intr_reg - Interrupt Register Set - * @irq_pending: IMAN - Interrupt Management Register. Used to enable - * interrupts and check for pending interrupts. - * @irq_control: IMOD - Interrupt Moderation Register. - * Used to throttle interrupts. - * @erst_size: Number of segments in the Event Ring Segment Table (ERST). - * @erst_base: ERST base address. - * @erst_dequeue: Event ring dequeue pointer. - * - * Each interrupter (defined by a MSI-X vector) has an event ring and an Event - * Ring Segment Table (ERST) associated with it. The event ring is comprised of - * multiple segments of the same size. The HC places events on the ring and - * "updates the Cycle bit in the TRBs to indicate to software the current - * position of the Enqueue Pointer." The HCD (Linux) processes those events and - * updates the dequeue pointer. - */ -struct xhci_intr_reg { - __le32 irq_pending; - __le32 irq_control; - __le32 erst_size; - __le32 rsvd; - __le64 erst_base; - __le64 erst_dequeue; -}; - -/* irq_pending bitmasks */ -#define ER_IRQ_PENDING(p) ((p) & 0x1) -/* bits 2:31 need to be preserved */ -/* THIS IS BUGGY - FIXME - IP IS WRITE 1 TO CLEAR */ -#define ER_IRQ_CLEAR(p) ((p) & 0xfffffffe) -#define ER_IRQ_ENABLE(p) ((ER_IRQ_CLEAR(p)) | 0x2) -#define ER_IRQ_DISABLE(p) ((ER_IRQ_CLEAR(p)) & ~(0x2)) - -/* irq_control bitmasks */ -/* Minimum interval between interrupts (in 250ns intervals). The interval - * between interrupts will be longer if there are no events on the event ring. - * Default is 4000 (1 ms). - */ -#define ER_IRQ_INTERVAL_MASK (0xffff) -/* Counter used to count down the time to the next interrupt - HW use only */ -#define ER_IRQ_COUNTER_MASK (0xffff << 16) - -/* erst_size bitmasks */ -/* Preserve bits 16:31 of erst_size */ -#define ERST_SIZE_MASK (0xffff << 16) - -/* erst_dequeue bitmasks */ -/* Dequeue ERST Segment Index (DESI) - Segment number (or alias) - * where the current dequeue pointer lies. This is an optional HW hint. - */ -#define ERST_DESI_MASK (0x7) -/* Event Handler Busy (EHB) - is the event ring scheduled to be serviced by - * a work queue (or delayed service routine)? - */ -#define ERST_EHB (1 << 3) -#define ERST_PTR_MASK (0xf) - -/** - * struct xhci_run_regs - * @microframe_index: - * MFINDEX - current microframe number - * - * Section 5.5 Host Controller Runtime Registers: - * "Software should read and write these registers using only Dword (32 bit) - * or larger accesses" - */ -struct xhci_run_regs { - __le32 microframe_index; - __le32 rsvd[7]; - struct xhci_intr_reg ir_set[128]; -}; - -/** - * struct doorbell_array - * - * Bits 0 - 7: Endpoint target - * Bits 8 - 15: RsvdZ - * Bits 16 - 31: Stream ID - * - * Section 5.6 - */ -struct xhci_doorbell_array { - __le32 doorbell[256]; -}; - -#define DB_VALUE(ep, stream) ((((ep) + 1) & 0xff) | ((stream) << 16)) -#define DB_VALUE_HOST 0x00000000 - -/** - * struct xhci_protocol_caps - * @revision: major revision, minor revision, capability ID, - * and next capability pointer. - * @name_string: Four ASCII characters to say which spec this xHC - * follows, typically "USB ". - * @port_info: Port offset, count, and protocol-defined information. - */ -struct xhci_protocol_caps { - u32 revision; - u32 name_string; - u32 port_info; -}; - -#define XHCI_EXT_PORT_MAJOR(x) (((x) >> 24) & 0xff) -#define XHCI_EXT_PORT_OFF(x) ((x) & 0xff) -#define XHCI_EXT_PORT_COUNT(x) (((x) >> 8) & 0xff) - -/** - * struct xhci_container_ctx - * @type: Type of context. Used to calculated offsets to contained contexts. - * @size: Size of the context data - * @bytes: The raw context data given to HW - * @dma: dma address of the bytes - * - * Represents either a Device or Input context. Holds a pointer to the raw - * memory used for the context (bytes) and dma address of it (dma). - */ -struct xhci_container_ctx { - unsigned type; -#define XHCI_CTX_TYPE_DEVICE 0x1 -#define XHCI_CTX_TYPE_INPUT 0x2 - - int size; - - u8 *bytes; - dma_addr_t dma; -}; - -/** - * struct xhci_slot_ctx - * @dev_info: Route string, device speed, hub info, and last valid endpoint - * @dev_info2: Max exit latency for device number, root hub port number - * @tt_info: tt_info is used to construct split transaction tokens - * @dev_state: slot state and device address - * - * Slot Context - section 6.2.1.1. This assumes the HC uses 32-byte context - * structures. If the HC uses 64-byte contexts, there is an additional 32 bytes - * reserved at the end of the slot context for HC internal use. - */ -struct xhci_slot_ctx { - __le32 dev_info; - __le32 dev_info2; - __le32 tt_info; - __le32 dev_state; - /* offset 0x10 to 0x1f reserved for HC internal use */ - __le32 reserved[4]; -}; - -/* dev_info bitmasks */ -/* Route String - 0:19 */ -#define ROUTE_STRING_MASK (0xfffff) -/* Device speed - values defined by PORTSC Device Speed field - 20:23 */ -#define DEV_SPEED (0xf << 20) -/* bit 24 reserved */ -/* Is this LS/FS device connected through a HS hub? - bit 25 */ -#define DEV_MTT (0x1 << 25) -/* Set if the device is a hub - bit 26 */ -#define DEV_HUB (0x1 << 26) -/* Index of the last valid endpoint context in this device context - 27:31 */ -#define LAST_CTX_MASK (0x1f << 27) -#define LAST_CTX(p) ((p) << 27) -#define LAST_CTX_TO_EP_NUM(p) (((p) >> 27) - 1) -#define SLOT_FLAG (1 << 0) -#define EP0_FLAG (1 << 1) - -/* dev_info2 bitmasks */ -/* Max Exit Latency (ms) - worst case time to wake up all links in dev path */ -#define MAX_EXIT (0xffff) -/* Root hub port number that is needed to access the USB device */ -#define ROOT_HUB_PORT(p) (((p) & 0xff) << 16) -#define DEVINFO_TO_ROOT_HUB_PORT(p) (((p) >> 16) & 0xff) -/* Maximum number of ports under a hub device */ -#define XHCI_MAX_PORTS(p) (((p) & 0xff) << 24) - -/* tt_info bitmasks */ -/* - * TT Hub Slot ID - for low or full speed devices attached to a high-speed hub - * The Slot ID of the hub that isolates the high speed signaling from - * this low or full-speed device. '0' if attached to root hub port. - */ -#define TT_SLOT (0xff) -/* - * The number of the downstream facing port of the high-speed hub - * '0' if the device is not low or full speed. - */ -#define TT_PORT (0xff << 8) -#define TT_THINK_TIME(p) (((p) & 0x3) << 16) - -/* dev_state bitmasks */ -/* USB device address - assigned by the HC */ -#define DEV_ADDR_MASK (0xff) -/* bits 8:26 reserved */ -/* Slot state */ -#define SLOT_STATE (0x1f << 27) -#define GET_SLOT_STATE(p) (((p) & (0x1f << 27)) >> 27) - -#define SLOT_STATE_DISABLED 0 -#define SLOT_STATE_ENABLED SLOT_STATE_DISABLED -#define SLOT_STATE_DEFAULT 1 -#define SLOT_STATE_ADDRESSED 2 -#define SLOT_STATE_CONFIGURED 3 - -/** - * struct xhci_ep_ctx - * @ep_info: endpoint state, streams, mult, and interval information. - * @ep_info2: information on endpoint type, max packet size, max burst size, - * error count, and whether the HC will force an event for all - * transactions. - * @deq: 64-bit ring dequeue pointer address. If the endpoint only - * defines one stream, this points to the endpoint transfer ring. - * Otherwise, it points to a stream context array, which has a - * ring pointer for each flow. - * @tx_info: - * Average TRB lengths for the endpoint ring and - * max payload within an Endpoint Service Interval Time (ESIT). - * - * Endpoint Context - section 6.2.1.2. This assumes the HC uses 32-byte context - * structures. If the HC uses 64-byte contexts, there is an additional 32 bytes - * reserved at the end of the endpoint context for HC internal use. - */ -struct xhci_ep_ctx { - __le32 ep_info; - __le32 ep_info2; - __le64 deq; - __le32 tx_info; - /* offset 0x14 - 0x1f reserved for HC internal use */ - __le32 reserved[3]; -}; - -/* ep_info bitmasks */ -/* - * Endpoint State - bits 0:2 - * 0 - disabled - * 1 - running - * 2 - halted due to halt condition - ok to manipulate endpoint ring - * 3 - stopped - * 4 - TRB error - * 5-7 - reserved - */ -#define EP_STATE_MASK (0xf) -#define EP_STATE_DISABLED 0 -#define EP_STATE_RUNNING 1 -#define EP_STATE_HALTED 2 -#define EP_STATE_STOPPED 3 -#define EP_STATE_ERROR 4 -/* Mult - Max number of burtst within an interval, in EP companion desc. */ -#define EP_MULT(p) (((p) & 0x3) << 8) -#define CTX_TO_EP_MULT(p) (((p) >> 8) & 0x3) -/* bits 10:14 are Max Primary Streams */ -/* bit 15 is Linear Stream Array */ -/* Interval - period between requests to an endpoint - 125u increments. */ -#define EP_INTERVAL(p) (((p) & 0xff) << 16) -#define EP_INTERVAL_TO_UFRAMES(p) (1 << (((p) >> 16) & 0xff)) -#define CTX_TO_EP_INTERVAL(p) (((p) >> 16) & 0xff) -#define EP_MAXPSTREAMS_MASK (0x1f << 10) -#define EP_MAXPSTREAMS(p) (((p) << 10) & EP_MAXPSTREAMS_MASK) -/* Endpoint is set up with a Linear Stream Array (vs. Secondary Stream Array) */ -#define EP_HAS_LSA (1 << 15) - -/* ep_info2 bitmasks */ -/* - * Force Event - generate transfer events for all TRBs for this endpoint - * This will tell the HC to ignore the IOC and ISP flags (for debugging only). - */ -#define FORCE_EVENT (0x1) -#define ERROR_COUNT(p) (((p) & 0x3) << 1) -#define CTX_TO_EP_TYPE(p) (((p) >> 3) & 0x7) -#define EP_TYPE(p) ((p) << 3) -#define ISOC_OUT_EP 1 -#define BULK_OUT_EP 2 -#define INT_OUT_EP 3 -#define CTRL_EP 4 -#define ISOC_IN_EP 5 -#define BULK_IN_EP 6 -#define INT_IN_EP 7 -/* bit 6 reserved */ -/* bit 7 is Host Initiate Disable - for disabling stream selection */ -#define MAX_BURST(p) (((p)&0xff) << 8) -#define CTX_TO_MAX_BURST(p) (((p) >> 8) & 0xff) -#define MAX_PACKET(p) (((p)&0xffff) << 16) -#define MAX_PACKET_MASK (0xffff << 16) -#define MAX_PACKET_DECODED(p) (((p) >> 16) & 0xffff) - -/* Get max packet size from ep desc. Bit 10..0 specify the max packet size. - * USB2.0 spec 9.6.6. - */ -#define GET_MAX_PACKET(p) ((p) & 0x7ff) - -/* tx_info bitmasks */ -#define AVG_TRB_LENGTH_FOR_EP(p) ((p) & 0xffff) -#define MAX_ESIT_PAYLOAD_FOR_EP(p) (((p) & 0xffff) << 16) -#define CTX_TO_MAX_ESIT_PAYLOAD(p) (((p) >> 16) & 0xffff) - -/* deq bitmasks */ -#define EP_CTX_CYCLE_MASK (1 << 0) - - -/** - * struct xhci_input_control_context - * Input control context; see section 6.2.5. - * - * @drop_context: set the bit of the endpoint context you want to disable - * @add_context: set the bit of the endpoint context you want to enable - */ -struct xhci_input_control_ctx { - __le32 drop_flags; - __le32 add_flags; - __le32 rsvd2[6]; -}; - -#define EP_IS_ADDED(ctrl_ctx, i) \ - (le32_to_cpu(ctrl_ctx->add_flags) & (1 << (i + 1))) -#define EP_IS_DROPPED(ctrl_ctx, i) \ - (le32_to_cpu(ctrl_ctx->drop_flags) & (1 << (i + 1))) - -/* Represents everything that is needed to issue a command on the command ring. - * It's useful to pre-allocate these for commands that cannot fail due to - * out-of-memory errors, like freeing streams. - */ -struct xhci_command { - /* Input context for changing device state */ - struct xhci_container_ctx *in_ctx; - u32 status; - /* If completion is null, no one is waiting on this command - * and the structure can be freed after the command completes. - */ - struct completion *completion; - union xhci_trb *command_trb; - struct list_head cmd_list; -}; - -/* drop context bitmasks */ -#define DROP_EP(x) (0x1 << x) -/* add context bitmasks */ -#define ADD_EP(x) (0x1 << x) - -struct xhci_stream_ctx { - /* 64-bit stream ring address, cycle state, and stream type */ - __le64 stream_ring; - /* offset 0x14 - 0x1f reserved for HC internal use */ - __le32 reserved[2]; -}; - -/* Stream Context Types (section 6.4.1) - bits 3:1 of stream ctx deq ptr */ -#define SCT_FOR_CTX(p) (((p) << 1) & 0x7) -/* Secondary stream array type, dequeue pointer is to a transfer ring */ -#define SCT_SEC_TR 0 -/* Primary stream array type, dequeue pointer is to a transfer ring */ -#define SCT_PRI_TR 1 -/* Dequeue pointer is for a secondary stream array (SSA) with 8 entries */ -#define SCT_SSA_8 2 -#define SCT_SSA_16 3 -#define SCT_SSA_32 4 -#define SCT_SSA_64 5 -#define SCT_SSA_128 6 -#define SCT_SSA_256 7 - -/* Assume no secondary streams for now */ -struct xhci_stream_info { - struct xhci_ring **stream_rings; - /* Number of streams, including stream 0 (which drivers can't use) */ - unsigned int num_streams; - /* The stream context array may be bigger than - * the number of streams the driver asked for - */ - struct xhci_stream_ctx *stream_ctx_array; - unsigned int num_stream_ctxs; - dma_addr_t ctx_array_dma; - /* For mapping physical TRB addresses to segments in stream rings */ - struct radix_tree_root trb_address_map; - struct xhci_command *free_streams_command; -}; - -#define SMALL_STREAM_ARRAY_SIZE 256 -#define MEDIUM_STREAM_ARRAY_SIZE 1024 - -/* Some Intel xHCI host controllers need software to keep track of the bus - * bandwidth. Keep track of endpoint info here. Each root port is allocated - * the full bus bandwidth. We must also treat TTs (including each port under a - * multi-TT hub) as a separate bandwidth domain. The direct memory interface - * (DMI) also limits the total bandwidth (across all domains) that can be used. - */ -struct xhci_bw_info { - /* ep_interval is zero-based */ - unsigned int ep_interval; - /* mult and num_packets are one-based */ - unsigned int mult; - unsigned int num_packets; - unsigned int max_packet_size; - unsigned int max_esit_payload; - unsigned int type; -}; - -/* "Block" sizes in bytes the hardware uses for different device speeds. - * The logic in this part of the hardware limits the number of bits the hardware - * can use, so must represent bandwidth in a less precise manner to mimic what - * the scheduler hardware computes. - */ -#define FS_BLOCK 1 -#define HS_BLOCK 4 -#define SS_BLOCK 16 -#define DMI_BLOCK 32 - -/* Each device speed has a protocol overhead (CRC, bit stuffing, etc) associated - * with each byte transferred. SuperSpeed devices have an initial overhead to - * set up bursts. These are in blocks, see above. LS overhead has already been - * translated into FS blocks. - */ -#define DMI_OVERHEAD 8 -#define DMI_OVERHEAD_BURST 4 -#define SS_OVERHEAD 8 -#define SS_OVERHEAD_BURST 32 -#define HS_OVERHEAD 26 -#define FS_OVERHEAD 20 -#define LS_OVERHEAD 128 -/* The TTs need to claim roughly twice as much bandwidth (94 bytes per - * microframe ~= 24Mbps) of the HS bus as the devices can actually use because - * of overhead associated with split transfers crossing microframe boundaries. - * 31 blocks is pure protocol overhead. - */ -#define TT_HS_OVERHEAD (31 + 94) -#define TT_DMI_OVERHEAD (25 + 12) - -/* Bandwidth limits in blocks */ -#define FS_BW_LIMIT 1285 -#define TT_BW_LIMIT 1320 -#define HS_BW_LIMIT 1607 -#define SS_BW_LIMIT_IN 3906 -#define DMI_BW_LIMIT_IN 3906 -#define SS_BW_LIMIT_OUT 3906 -#define DMI_BW_LIMIT_OUT 3906 - -/* Percentage of bus bandwidth reserved for non-periodic transfers */ -#define FS_BW_RESERVED 10 -#define HS_BW_RESERVED 20 -#define SS_BW_RESERVED 10 - -struct xhci_virt_ep { - struct xhci_ring *ring; - /* Related to endpoints that are configured to use stream IDs only */ - struct xhci_stream_info *stream_info; - /* Temporary storage in case the configure endpoint command fails and we - * have to restore the device state to the previous state - */ - struct xhci_ring *new_ring; - unsigned int ep_state; -#define SET_DEQ_PENDING (1 << 0) -#define EP_HALTED (1 << 1) /* For stall handling */ -#define EP_HALT_PENDING (1 << 2) /* For URB cancellation */ -/* Transitioning the endpoint to using streams, don't enqueue URBs */ -#define EP_GETTING_STREAMS (1 << 3) -#define EP_HAS_STREAMS (1 << 4) -/* Transitioning the endpoint to not using streams, don't enqueue URBs */ -#define EP_GETTING_NO_STREAMS (1 << 5) - /* ---- Related to URB cancellation ---- */ - struct list_head cancelled_td_list; - /* The TRB that was last reported in a stopped endpoint ring */ - union xhci_trb *stopped_trb; - struct xhci_td *stopped_td; - unsigned int stopped_stream; - /* Watchdog timer for stop endpoint command to cancel URBs */ - struct timer_list stop_cmd_timer; - int stop_cmds_pending; - struct xhci_hcd *xhci; - /* Dequeue pointer and dequeue segment for a submitted Set TR Dequeue - * command. We'll need to update the ring's dequeue segment and dequeue - * pointer after the command completes. - */ - struct xhci_segment *queued_deq_seg; - union xhci_trb *queued_deq_ptr; - /* - * Sometimes the xHC can not process isochronous endpoint ring quickly - * enough, and it will miss some isoc tds on the ring and generate - * a Missed Service Error Event. - * Set skip flag when receive a Missed Service Error Event and - * process the missed tds on the endpoint ring. - */ - bool skip; - /* Bandwidth checking storage */ - struct xhci_bw_info bw_info; - struct list_head bw_endpoint_list; -}; - -enum xhci_overhead_type { - LS_OVERHEAD_TYPE = 0, - FS_OVERHEAD_TYPE, - HS_OVERHEAD_TYPE, -}; - -struct xhci_interval_bw { - unsigned int num_packets; - /* Sorted by max packet size. - * Head of the list is the greatest max packet size. - */ - struct list_head endpoints; - /* How many endpoints of each speed are present. */ - unsigned int overhead[3]; -}; - -#define XHCI_MAX_INTERVAL 16 - -struct xhci_interval_bw_table { - unsigned int interval0_esit_payload; - struct xhci_interval_bw interval_bw[XHCI_MAX_INTERVAL]; - /* Includes reserved bandwidth for async endpoints */ - unsigned int bw_used; - unsigned int ss_bw_in; - unsigned int ss_bw_out; -}; - - -struct xhci_virt_device { - struct usb_device *udev; - /* - * Commands to the hardware are passed an "input context" that - * tells the hardware what to change in its data structures. - * The hardware will return changes in an "output context" that - * software must allocate for the hardware. We need to keep - * track of input and output contexts separately because - * these commands might fail and we don't trust the hardware. - */ - struct xhci_container_ctx *out_ctx; - /* Used for addressing devices and configuration changes */ - struct xhci_container_ctx *in_ctx; - /* Rings saved to ensure old alt settings can be re-instated */ - struct xhci_ring **ring_cache; - int num_rings_cached; - /* Store xHC assigned device address */ - int address; -#define XHCI_MAX_RINGS_CACHED 31 - struct xhci_virt_ep eps[31]; - struct completion cmd_completion; - /* Status of the last command issued for this device */ - u32 cmd_status; - struct list_head cmd_list; - u8 fake_port; - u8 real_port; - struct xhci_interval_bw_table *bw_table; - struct xhci_tt_bw_info *tt_info; -}; - -/* - * For each roothub, keep track of the bandwidth information for each periodic - * interval. - * - * If a high speed hub is attached to the roothub, each TT associated with that - * hub is a separate bandwidth domain. The interval information for the - * endpoints on the devices under that TT will appear in the TT structure. - */ -struct xhci_root_port_bw_info { - struct list_head tts; - unsigned int num_active_tts; - struct xhci_interval_bw_table bw_table; -}; - -struct xhci_tt_bw_info { - struct list_head tt_list; - int slot_id; - int ttport; - struct xhci_interval_bw_table bw_table; - int active_eps; -}; - - -/** - * struct xhci_device_context_array - * @dev_context_ptr array of 64-bit DMA addresses for device contexts - */ -struct xhci_device_context_array { - /* 64-bit device addresses; we only write 32-bit addresses */ - __le64 dev_context_ptrs[MAX_HC_SLOTS]; - /* private xHCD pointers */ - dma_addr_t dma; -}; -/* TODO: write function to set the 64-bit device DMA address */ -/* - * TODO: change this to be dynamically sized at HC mem init time since the HC - * might not be able to handle the maximum number of devices possible. - */ - - -struct xhci_transfer_event { - /* 64-bit buffer address, or immediate data */ - __le64 buffer; - __le32 transfer_len; - /* This field is interpreted differently based on the type of TRB */ - __le32 flags; -}; - -/** Transfer Event bit fields **/ -#define TRB_TO_EP_ID(p) (((p) >> 16) & 0x1f) - -/* Completion Code - only applicable for some types of TRBs */ -#define COMP_CODE_MASK (0xff << 24) -#define GET_COMP_CODE(p) (((p) & COMP_CODE_MASK) >> 24) -#define COMP_SUCCESS 1 -/* Data Buffer Error */ -#define COMP_DB_ERR 2 -/* Babble Detected Error */ -#define COMP_BABBLE 3 -/* USB Transaction Error */ -#define COMP_TX_ERR 4 -/* TRB Error - some TRB field is invalid */ -#define COMP_TRB_ERR 5 -/* Stall Error - USB device is stalled */ -#define COMP_STALL 6 -/* Resource Error - HC doesn't have memory for that device configuration */ -#define COMP_ENOMEM 7 -/* Bandwidth Error - not enough room in schedule for this dev config */ -#define COMP_BW_ERR 8 -/* No Slots Available Error - HC ran out of device slots */ -#define COMP_ENOSLOTS 9 -/* Invalid Stream Type Error */ -#define COMP_STREAM_ERR 10 -/* Slot Not Enabled Error - doorbell rung for disabled device slot */ -#define COMP_EBADSLT 11 -/* Endpoint Not Enabled Error */ -#define COMP_EBADEP 12 -/* Short Packet */ -#define COMP_SHORT_TX 13 -/* Ring Underrun - doorbell rung for an empty isoc OUT ep ring */ -#define COMP_UNDERRUN 14 -/* Ring Overrun - isoc IN ep ring is empty when ep is scheduled to RX */ -#define COMP_OVERRUN 15 -/* Virtual Function Event Ring Full Error */ -#define COMP_VF_FULL 16 -/* Parameter Error - Context parameter is invalid */ -#define COMP_EINVAL 17 -/* Bandwidth Overrun Error - isoc ep exceeded its allocated bandwidth */ -#define COMP_BW_OVER 18 -/* Context State Error - illegal context state transition requested */ -#define COMP_CTX_STATE 19 -/* No Ping Response Error - HC didn't get PING_RESPONSE in time to TX */ -#define COMP_PING_ERR 20 -/* Event Ring is full */ -#define COMP_ER_FULL 21 -/* Incompatible Device Error */ -#define COMP_DEV_ERR 22 -/* Missed Service Error - HC couldn't service an isoc ep within interval */ -#define COMP_MISSED_INT 23 -/* Successfully stopped command ring */ -#define COMP_CMD_STOP 24 -/* Successfully aborted current command and stopped command ring */ -#define COMP_CMD_ABORT 25 -/* Stopped - transfer was terminated by a stop endpoint command */ -#define COMP_STOP 26 -/* Same as COMP_EP_STOPPED, but the transferred length in the event is invalid */ -#define COMP_STOP_INVAL 27 -/* Control Abort Error - Debug Capability - control pipe aborted */ -#define COMP_DBG_ABORT 28 -/* Max Exit Latency Too Large Error */ -#define COMP_MEL_ERR 29 -/* TRB type 30 reserved */ -/* Isoc Buffer Overrun - an isoc IN ep sent more data than could fit in TD */ -#define COMP_BUFF_OVER 31 -/* Event Lost Error - xHC has an "internal event overrun condition" */ -#define COMP_ISSUES 32 -/* Undefined Error - reported when other error codes don't apply */ -#define COMP_UNKNOWN 33 -/* Invalid Stream ID Error */ -#define COMP_STRID_ERR 34 -/* Secondary Bandwidth Error - may be returned by a Configure Endpoint cmd */ -#define COMP_2ND_BW_ERR 35 -/* Split Transaction Error */ -#define COMP_SPLIT_ERR 36 - -struct xhci_link_trb { - /* 64-bit segment pointer*/ - __le64 segment_ptr; - __le32 intr_target; - __le32 control; -}; - -/* control bitfields */ -#define LINK_TOGGLE (0x1<<1) - -/* Command completion event TRB */ -struct xhci_event_cmd { - /* Pointer to command TRB, or the value passed by the event data trb */ - __le64 cmd_trb; - __le32 status; - __le32 flags; -}; - -/* flags bitmasks */ -/* bits 16:23 are the virtual function ID */ -/* bits 24:31 are the slot ID */ -#define TRB_TO_SLOT_ID(p) (((p) & (0xff<<24)) >> 24) -#define SLOT_ID_FOR_TRB(p) (((p) & 0xff) << 24) - -/* Stop Endpoint TRB - ep_index to endpoint ID for this TRB */ -#define TRB_TO_EP_INDEX(p) ((((p) & (0x1f << 16)) >> 16) - 1) -#define EP_ID_FOR_TRB(p) ((((p) + 1) & 0x1f) << 16) - -#define SUSPEND_PORT_FOR_TRB(p) (((p) & 1) << 23) -#define TRB_TO_SUSPEND_PORT(p) (((p) & (1 << 23)) >> 23) -#define LAST_EP_INDEX 30 - -/* Set TR Dequeue Pointer command TRB fields */ -#define TRB_TO_STREAM_ID(p) ((((p) & (0xffff << 16)) >> 16)) -#define STREAM_ID_FOR_TRB(p) ((((p)) & 0xffff) << 16) - - -/* Port Status Change Event TRB fields */ -/* Port ID - bits 31:24 */ -#define GET_PORT_ID(p) (((p) & (0xff << 24)) >> 24) - -/* Normal TRB fields */ -/* transfer_len bitmasks - bits 0:16 */ -#define TRB_LEN(p) ((p) & 0x1ffff) -/* Interrupter Target - which MSI-X vector to target the completion event at */ -#define TRB_INTR_TARGET(p) (((p) & 0x3ff) << 22) -#define GET_INTR_TARGET(p) (((p) >> 22) & 0x3ff) -#define TRB_TBC(p) (((p) & 0x3) << 7) -#define TRB_TLBPC(p) (((p) & 0xf) << 16) - -/* Cycle bit - indicates TRB ownership by HC or HCD */ -#define TRB_CYCLE (1<<0) -/* - * Force next event data TRB to be evaluated before task switch. - * Used to pass OS data back after a TD completes. - */ -#define TRB_ENT (1<<1) -/* Interrupt on short packet */ -#define TRB_ISP (1<<2) -/* Set PCIe no snoop attribute */ -#define TRB_NO_SNOOP (1<<3) -/* Chain multiple TRBs into a TD */ -#define TRB_CHAIN (1<<4) -/* Interrupt on completion */ -#define TRB_IOC (1<<5) -/* The buffer pointer contains immediate data */ -#define TRB_IDT (1<<6) - -/* Block Event Interrupt */ -#define TRB_BEI (1<<9) - -/* Control transfer TRB specific fields */ -#define TRB_DIR_IN (1<<16) -#define TRB_TX_TYPE(p) ((p) << 16) -#define TRB_DATA_OUT 2 -#define TRB_DATA_IN 3 - -/* Isochronous TRB specific fields */ -#define TRB_SIA (1<<31) - -struct xhci_generic_trb { - __le32 field[4]; -}; - -union xhci_trb { - struct xhci_link_trb link; - struct xhci_transfer_event trans_event; - struct xhci_event_cmd event_cmd; - struct xhci_generic_trb generic; -}; - -/* TRB bit mask */ -#define TRB_TYPE_BITMASK (0xfc00) -#define TRB_TYPE(p) ((p) << 10) -#define TRB_FIELD_TO_TYPE(p) (((p) & TRB_TYPE_BITMASK) >> 10) -/* TRB type IDs */ -/* bulk, interrupt, isoc scatter/gather, and control data stage */ -#define TRB_NORMAL 1 -/* setup stage for control transfers */ -#define TRB_SETUP 2 -/* data stage for control transfers */ -#define TRB_DATA 3 -/* status stage for control transfers */ -#define TRB_STATUS 4 -/* isoc transfers */ -#define TRB_ISOC 5 -/* TRB for linking ring segments */ -#define TRB_LINK 6 -#define TRB_EVENT_DATA 7 -/* Transfer Ring No-op (not for the command ring) */ -#define TRB_TR_NOOP 8 -/* Command TRBs */ -/* Enable Slot Command */ -#define TRB_ENABLE_SLOT 9 -/* Disable Slot Command */ -#define TRB_DISABLE_SLOT 10 -/* Address Device Command */ -#define TRB_ADDR_DEV 11 -/* Configure Endpoint Command */ -#define TRB_CONFIG_EP 12 -/* Evaluate Context Command */ -#define TRB_EVAL_CONTEXT 13 -/* Reset Endpoint Command */ -#define TRB_RESET_EP 14 -/* Stop Transfer Ring Command */ -#define TRB_STOP_RING 15 -/* Set Transfer Ring Dequeue Pointer Command */ -#define TRB_SET_DEQ 16 -/* Reset Device Command */ -#define TRB_RESET_DEV 17 -/* Force Event Command (opt) */ -#define TRB_FORCE_EVENT 18 -/* Negotiate Bandwidth Command (opt) */ -#define TRB_NEG_BANDWIDTH 19 -/* Set Latency Tolerance Value Command (opt) */ -#define TRB_SET_LT 20 -/* Get port bandwidth Command */ -#define TRB_GET_BW 21 -/* Force Header Command - generate a transaction or link management packet */ -#define TRB_FORCE_HEADER 22 -/* No-op Command - not for transfer rings */ -#define TRB_CMD_NOOP 23 -/* TRB IDs 24-31 reserved */ -/* Event TRBS */ -/* Transfer Event */ -#define TRB_TRANSFER 32 -/* Command Completion Event */ -#define TRB_COMPLETION 33 -/* Port Status Change Event */ -#define TRB_PORT_STATUS 34 -/* Bandwidth Request Event (opt) */ -#define TRB_BANDWIDTH_EVENT 35 -/* Doorbell Event (opt) */ -#define TRB_DOORBELL 36 -/* Host Controller Event */ -#define TRB_HC_EVENT 37 -/* Device Notification Event - device sent function wake notification */ -#define TRB_DEV_NOTE 38 -/* MFINDEX Wrap Event - microframe counter wrapped */ -#define TRB_MFINDEX_WRAP 39 -/* TRB IDs 40-47 reserved, 48-63 is vendor-defined */ - -/* Nec vendor-specific command completion event. */ -#define TRB_NEC_CMD_COMP 48 -/* Get NEC firmware revision. */ -#define TRB_NEC_GET_FW 49 - -#define TRB_TYPE_LINK(x) (((x) & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK)) -/* Above, but for __le32 types -- can avoid work by swapping constants: */ -#define TRB_TYPE_LINK_LE32(x) (((x) & cpu_to_le32(TRB_TYPE_BITMASK)) == \ - cpu_to_le32(TRB_TYPE(TRB_LINK))) -#define TRB_TYPE_NOOP_LE32(x) (((x) & cpu_to_le32(TRB_TYPE_BITMASK)) == \ - cpu_to_le32(TRB_TYPE(TRB_TR_NOOP))) - -#define NEC_FW_MINOR(p) (((p) >> 0) & 0xff) -#define NEC_FW_MAJOR(p) (((p) >> 8) & 0xff) - -/* - * TRBS_PER_SEGMENT must be a multiple of 4, - * since the command ring is 64-byte aligned. - * It must also be greater than 16. - */ -#define TRBS_PER_SEGMENT 64 -/* Allow two commands + a link TRB, along with any reserved command TRBs */ -#define MAX_RSVD_CMD_TRBS (TRBS_PER_SEGMENT - 3) -#define SEGMENT_SIZE (TRBS_PER_SEGMENT*16) -#define SEGMENT_SHIFT (__ffs(SEGMENT_SIZE)) -/* TRB buffer pointers can't cross 64KB boundaries */ -#define TRB_MAX_BUFF_SHIFT 16 -#define TRB_MAX_BUFF_SIZE (1 << TRB_MAX_BUFF_SHIFT) - -struct xhci_segment { - union xhci_trb *trbs; - /* private to HCD */ - struct xhci_segment *next; - dma_addr_t dma; -}; - -struct xhci_td { - struct list_head td_list; - struct list_head cancelled_td_list; - struct urb *urb; - struct xhci_segment *start_seg; - union xhci_trb *first_trb; - union xhci_trb *last_trb; -}; - -struct xhci_dequeue_state { - struct xhci_segment *new_deq_seg; - union xhci_trb *new_deq_ptr; - int new_cycle_state; -}; - -enum xhci_ring_type { - TYPE_CTRL = 0, - TYPE_ISOC, - TYPE_BULK, - TYPE_INTR, - TYPE_STREAM, - TYPE_COMMAND, - TYPE_EVENT, -}; - -struct xhci_ring { - struct xhci_segment *first_seg; - struct xhci_segment *last_seg; - union xhci_trb *enqueue; - struct xhci_segment *enq_seg; - unsigned int enq_updates; - union xhci_trb *dequeue; - struct xhci_segment *deq_seg; - unsigned int deq_updates; - struct list_head td_list; - /* - * Write the cycle state into the TRB cycle field to give ownership of - * the TRB to the host controller (if we are the producer), or to check - * if we own the TRB (if we are the consumer). See section 4.9.1. - */ - u32 cycle_state; - unsigned int stream_id; - unsigned int num_segs; - unsigned int num_trbs_free; - unsigned int num_trbs_free_temp; - enum xhci_ring_type type; - bool last_td_was_short; -}; - -struct xhci_erst_entry { - /* 64-bit event ring segment address */ - __le64 seg_addr; - __le32 seg_size; - /* Set to zero */ - __le32 rsvd; -}; - -struct xhci_erst { - struct xhci_erst_entry *entries; - unsigned int num_entries; - /* xhci->event_ring keeps track of segment dma addresses */ - dma_addr_t erst_dma_addr; - /* Num entries the ERST can contain */ - unsigned int erst_size; -}; - -struct xhci_scratchpad { - u64 *sp_array; - dma_addr_t sp_dma; - void **sp_buffers; - dma_addr_t *sp_dma_buffers; -}; - -struct urb_priv { - int length; - int td_cnt; - struct xhci_td *td[0]; -}; - -/* - * Each segment table entry is 4*32bits long. 1K seems like an ok size: - * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table, - * meaning 64 ring segments. - * Initial allocated size of the ERST, in number of entries */ -#define ERST_NUM_SEGS 1 -/* Initial allocated size of the ERST, in number of entries */ -#define ERST_SIZE 64 -/* Initial number of event segment rings allocated */ -#define ERST_ENTRIES 1 -/* Poll every 60 seconds */ -#define POLL_TIMEOUT 60 -/* Stop endpoint command timeout (secs) for URB cancellation watchdog timer */ -#define XHCI_STOP_EP_CMD_TIMEOUT 5 -/* XXX: Make these module parameters */ - -struct s3_save { - u32 command; - u32 dev_nt; - u64 dcbaa_ptr; - u32 config_reg; - u32 irq_pending; - u32 irq_control; - u32 erst_size; - u64 erst_base; - u64 erst_dequeue; -}; - -/* Use for lpm */ -struct dev_info { - u32 dev_id; - struct list_head list; -}; - -struct xhci_bus_state { - unsigned long bus_suspended; - unsigned long next_statechange; - - /* Port suspend arrays are indexed by the portnum of the fake roothub */ - /* ports suspend status arrays - max 31 ports for USB2, 15 for USB3 */ - u32 port_c_suspend; - u32 suspended_ports; - u32 port_remote_wakeup; - unsigned long resume_done[USB_MAXCHILDREN]; - /* which ports have started to resume */ - unsigned long resuming_ports; -}; - -static inline unsigned int hcd_index(struct usb_hcd *hcd) -{ - if (hcd->speed == HCD_USB3) - return 0; - else - return 1; -} - -/* There is one xhci_hcd structure per controller */ -struct xhci_hcd { - struct usb_hcd *main_hcd; - struct usb_hcd *shared_hcd; - /* glue to PCI and HCD framework */ - struct xhci_cap_regs __iomem *cap_regs; - struct xhci_op_regs __iomem *op_regs; - struct xhci_run_regs __iomem *run_regs; - struct xhci_doorbell_array __iomem *dba; - /* Our HCD's current interrupter register set */ - struct xhci_intr_reg __iomem *ir_set; - - /* Cached register copies of read-only HC data */ - __u32 hcs_params1; - __u32 hcs_params2; - __u32 hcs_params3; - __u32 hcc_params; - - spinlock_t lock; - - /* packed release number */ - u8 sbrn; - u16 hci_version; - u8 max_slots; - u8 max_interrupters; - u8 max_ports; - u8 isoc_threshold; - int event_ring_max; - int addr_64; - /* 4KB min, 128MB max */ - int page_size; - /* Valid values are 12 to 20, inclusive */ - int page_shift; - /* msi-x vectors */ - int msix_count; - struct msix_entry *msix_entries; - /* data structures */ - struct xhci_device_context_array *dcbaa; - struct xhci_ring *cmd_ring; - unsigned int cmd_ring_reserved_trbs; - struct xhci_ring *event_ring; - struct xhci_erst erst; - /* Scratchpad */ - struct xhci_scratchpad *scratchpad; - /* Store LPM test failed devices' information */ - struct list_head lpm_failed_devs; - - /* slot enabling and address device helpers */ - struct completion addr_dev; - int slot_id; - /* Internal mirror of the HW's dcbaa */ - struct xhci_virt_device *devs[MAX_HC_SLOTS]; - /* For keeping track of bandwidth domains per roothub. */ - struct xhci_root_port_bw_info *rh_bw; - - /* DMA pools */ - struct dma_pool *device_pool; - struct dma_pool *segment_pool; - struct dma_pool *small_streams_pool; - struct dma_pool *medium_streams_pool; - -#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING - /* Poll the rings - for debugging */ - struct timer_list event_ring_timer; - int zombie; -#endif - /* Host controller watchdog timer structures */ - unsigned int xhc_state; - - u32 command; - struct s3_save s3; -/* Host controller is dying - not responding to commands. "I'm not dead yet!" - * - * xHC interrupts have been disabled and a watchdog timer will (or has already) - * halt the xHCI host, and complete all URBs with an -ESHUTDOWN code. Any code - * that sees this status (other than the timer that set it) should stop touching - * hardware immediately. Interrupt handlers should return immediately when - * they see this status (any time they drop and re-acquire xhci->lock). - * xhci_urb_dequeue() should call usb_hcd_check_unlink_urb() and return without - * putting the TD on the canceled list, etc. - * - * There are no reports of xHCI host controllers that display this issue. - */ -#define XHCI_STATE_DYING (1 << 0) -#define XHCI_STATE_HALTED (1 << 1) - /* Statistics */ - int error_bitmask; - unsigned int quirks; -#define XHCI_LINK_TRB_QUIRK (1 << 0) -#define XHCI_RESET_EP_QUIRK (1 << 1) -#define XHCI_NEC_HOST (1 << 2) -#define XHCI_AMD_PLL_FIX (1 << 3) -#define XHCI_SPURIOUS_SUCCESS (1 << 4) -/* - * Certain Intel host controllers have a limit to the number of endpoint - * contexts they can handle. Ideally, they would signal that they can't handle - * anymore endpoint contexts by returning a Resource Error for the Configure - * Endpoint command, but they don't. Instead they expect software to keep track - * of the number of active endpoints for them, across configure endpoint - * commands, reset device commands, disable slot commands, and address device - * commands. - */ -#define XHCI_EP_LIMIT_QUIRK (1 << 5) -#define XHCI_BROKEN_MSI (1 << 6) -#define XHCI_RESET_ON_RESUME (1 << 7) -#define XHCI_SW_BW_CHECKING (1 << 8) -#define XHCI_AMD_0x96_HOST (1 << 9) -#define XHCI_TRUST_TX_LENGTH (1 << 10) - unsigned int num_active_eps; - unsigned int limit_active_eps; - /* There are two roothubs to keep track of bus suspend info for */ - struct xhci_bus_state bus_state[2]; - /* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */ - u8 *port_array; - /* Array of pointers to USB 3.0 PORTSC registers */ - __le32 __iomem **usb3_ports; - unsigned int num_usb3_ports; - /* Array of pointers to USB 2.0 PORTSC registers */ - __le32 __iomem **usb2_ports; - unsigned int num_usb2_ports; - /* support xHCI 0.96 spec USB2 software LPM */ - unsigned sw_lpm_support:1; - /* support xHCI 1.0 spec USB2 hardware LPM */ - unsigned hw_lpm_support:1; -}; - -/* convert between an HCD pointer and the corresponding EHCI_HCD */ -static inline struct xhci_hcd *hcd_to_xhci(struct usb_hcd *hcd) -{ - return *((struct xhci_hcd **) (hcd->hcd_priv)); -} - -static inline struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci) -{ - return xhci->main_hcd; -} - -#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING -#define XHCI_DEBUG 1 -#else -#define XHCI_DEBUG 0 -#endif - -#define xhci_dbg(xhci, fmt, args...) \ - do { if (XHCI_DEBUG) dev_dbg(xhci_to_hcd(xhci)->self.controller , fmt , ## args); } while (0) -#define xhci_info(xhci, fmt, args...) \ - do { if (XHCI_DEBUG) dev_info(xhci_to_hcd(xhci)->self.controller , fmt , ## args); } while (0) -#define xhci_err(xhci, fmt, args...) \ - dev_err(xhci_to_hcd(xhci)->self.controller , fmt , ## args) -#define xhci_warn(xhci, fmt, args...) \ - dev_warn(xhci_to_hcd(xhci)->self.controller , fmt , ## args) - -/* TODO: copied from ehci.h - can be refactored? */ -/* xHCI spec says all registers are little endian */ -static inline unsigned int xhci_readl(const struct xhci_hcd *xhci, - __le32 __iomem *regs) -{ - return readl(regs); -} -static inline void xhci_writel(struct xhci_hcd *xhci, - const unsigned int val, __le32 __iomem *regs) -{ - writel(val, regs); -} - -/* - * Registers should always be accessed with double word or quad word accesses. - * - * Some xHCI implementations may support 64-bit address pointers. Registers - * with 64-bit address pointers should be written to with dword accesses by - * writing the low dword first (ptr[0]), then the high dword (ptr[1]) second. - * xHCI implementations that do not support 64-bit address pointers will ignore - * the high dword, and write order is irrelevant. - */ -static inline u64 xhci_read_64(const struct xhci_hcd *xhci, - __le64 __iomem *regs) -{ - __u32 __iomem *ptr = (__u32 __iomem *) regs; - u64 val_lo = readl(ptr); - u64 val_hi = readl(ptr + 1); - return val_lo + (val_hi << 32); -} -static inline void xhci_write_64(struct xhci_hcd *xhci, - const u64 val, __le64 __iomem *regs) -{ - __u32 __iomem *ptr = (__u32 __iomem *) regs; - u32 val_lo = lower_32_bits(val); - u32 val_hi = upper_32_bits(val); - - writel(val_lo, ptr); - writel(val_hi, ptr + 1); -} - -static inline int xhci_link_trb_quirk(struct xhci_hcd *xhci) -{ - return xhci->quirks & XHCI_LINK_TRB_QUIRK; -} - -/* xHCI debugging */ -void xhci_print_ir_set(struct xhci_hcd *xhci, int set_num); -void xhci_print_registers(struct xhci_hcd *xhci); -void xhci_dbg_regs(struct xhci_hcd *xhci); -void xhci_print_run_regs(struct xhci_hcd *xhci); -void xhci_print_trb_offsets(struct xhci_hcd *xhci, union xhci_trb *trb); -void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb); -void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg); -void xhci_debug_ring(struct xhci_hcd *xhci, struct xhci_ring *ring); -void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst); -void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci); -void xhci_dbg_ring_ptrs(struct xhci_hcd *xhci, struct xhci_ring *ring); -void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int last_ep); -char *xhci_get_slot_state(struct xhci_hcd *xhci, - struct xhci_container_ctx *ctx); -void xhci_dbg_ep_rings(struct xhci_hcd *xhci, - unsigned int slot_id, unsigned int ep_index, - struct xhci_virt_ep *ep); - -/* xHCI memory management */ -void xhci_mem_cleanup(struct xhci_hcd *xhci); -int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags); -void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id); -int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, struct usb_device *udev, gfp_t flags); -int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev); -void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci, - struct usb_device *udev); -unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc); -unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc); -unsigned int xhci_get_endpoint_flag_from_index(unsigned int ep_index); -unsigned int xhci_last_valid_endpoint(u32 added_ctxs); -void xhci_endpoint_zero(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, struct usb_host_endpoint *ep); -void xhci_drop_ep_from_interval_table(struct xhci_hcd *xhci, - struct xhci_bw_info *ep_bw, - struct xhci_interval_bw_table *bw_table, - struct usb_device *udev, - struct xhci_virt_ep *virt_ep, - struct xhci_tt_bw_info *tt_info); -void xhci_update_tt_active_eps(struct xhci_hcd *xhci, - struct xhci_virt_device *virt_dev, - int old_active_eps); -void xhci_clear_endpoint_bw_info(struct xhci_bw_info *bw_info); -void xhci_update_bw_info(struct xhci_hcd *xhci, - struct xhci_container_ctx *in_ctx, - struct xhci_input_control_ctx *ctrl_ctx, - struct xhci_virt_device *virt_dev); -void xhci_endpoint_copy(struct xhci_hcd *xhci, - struct xhci_container_ctx *in_ctx, - struct xhci_container_ctx *out_ctx, - unsigned int ep_index); -void xhci_slot_copy(struct xhci_hcd *xhci, - struct xhci_container_ctx *in_ctx, - struct xhci_container_ctx *out_ctx); -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); -void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring); -int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring, - unsigned int num_trbs, gfp_t flags); -void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci, - struct xhci_virt_device *virt_dev, - unsigned int ep_index); -struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, - unsigned int num_stream_ctxs, - unsigned int num_streams, gfp_t flags); -void xhci_free_stream_info(struct xhci_hcd *xhci, - struct xhci_stream_info *stream_info); -void xhci_setup_streams_ep_input_ctx(struct xhci_hcd *xhci, - struct xhci_ep_ctx *ep_ctx, - struct xhci_stream_info *stream_info); -void xhci_setup_no_streams_ep_input_ctx(struct xhci_hcd *xhci, - struct xhci_ep_ctx *ep_ctx, - struct xhci_virt_ep *ep); -void xhci_free_device_endpoint_resources(struct xhci_hcd *xhci, - struct xhci_virt_device *virt_dev, bool drop_control_ep); -struct xhci_ring *xhci_dma_to_transfer_ring( - struct xhci_virt_ep *ep, - u64 address); -struct xhci_ring *xhci_stream_id_to_ring( - struct xhci_virt_device *dev, - unsigned int ep_index, - unsigned int stream_id); -struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci, - bool allocate_in_ctx, bool allocate_completion, - gfp_t mem_flags); -void xhci_urb_free_priv(struct xhci_hcd *xhci, struct urb_priv *urb_priv); -void xhci_free_command(struct xhci_hcd *xhci, - struct xhci_command *command); - -#ifdef CONFIG_PCI -/* xHCI PCI glue */ -int xhci_register_pci(void); -void xhci_unregister_pci(void); -#else -static inline int xhci_register_pci(void) { return 0; } -static inline void xhci_unregister_pci(void) {} -#endif - -#if defined(CONFIG_USB_XHCI_PLATFORM) \ - || defined(CONFIG_USB_XHCI_PLATFORM_MODULE) -int xhci_register_plat(void); -void xhci_unregister_plat(void); -#else -static inline int xhci_register_plat(void) -{ return 0; } -static inline void xhci_unregister_plat(void) -{ } -#endif - -/* xHCI host controller glue */ -typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *); -void xhci_quiesce(struct xhci_hcd *xhci); -int xhci_halt(struct xhci_hcd *xhci); -int xhci_reset(struct xhci_hcd *xhci); -int xhci_init(struct usb_hcd *hcd); -int xhci_run(struct usb_hcd *hcd); -void xhci_stop(struct usb_hcd *hcd); -void xhci_shutdown(struct usb_hcd *hcd); -int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks); - -#ifdef CONFIG_PM -int xhci_suspend(struct xhci_hcd *xhci); -int xhci_resume(struct xhci_hcd *xhci, bool hibernated); -#else -#define xhci_suspend NULL -#define xhci_resume NULL -#endif - -int xhci_get_frame(struct usb_hcd *hcd); -irqreturn_t xhci_irq(struct usb_hcd *hcd); -irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd); -int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev); -void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev); -int xhci_alloc_tt_info(struct xhci_hcd *xhci, - struct xhci_virt_device *virt_dev, - struct usb_device *hdev, - struct usb_tt *tt, gfp_t mem_flags); -int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, - struct usb_host_endpoint **eps, unsigned int num_eps, - unsigned int num_streams, gfp_t mem_flags); -int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev, - struct usb_host_endpoint **eps, unsigned int num_eps, - gfp_t mem_flags); -int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev); -int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev); -int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, - struct usb_device *udev, int enable); -int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, - struct usb_tt *tt, gfp_t mem_flags); -int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags); -int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status); -int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep); -int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep); -void xhci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep); -int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev); -int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); -void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); - -/* xHCI ring, segment, TRB, and TD functions */ -dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb); -struct xhci_segment *trb_in_td(struct xhci_segment *start_seg, - union xhci_trb *start_trb, union xhci_trb *end_trb, - dma_addr_t suspect_dma); -int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code); -void xhci_ring_cmd_db(struct xhci_hcd *xhci); -int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id); -int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, - u32 slot_id); -int xhci_queue_vendor_command(struct xhci_hcd *xhci, - u32 field1, u32 field2, u32 field3, u32 field4); -int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id, - unsigned int ep_index, int suspend); -int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, - int slot_id, unsigned int ep_index); -int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, - int slot_id, unsigned int ep_index); -int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, - int slot_id, unsigned int ep_index); -int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, - struct urb *urb, int slot_id, unsigned int ep_index); -int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, - u32 slot_id, bool command_must_succeed); -int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, - u32 slot_id); -int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id, - unsigned int ep_index); -int xhci_queue_reset_device(struct xhci_hcd *xhci, u32 slot_id); -void xhci_find_new_dequeue_state(struct xhci_hcd *xhci, - unsigned int slot_id, unsigned int ep_index, - unsigned int stream_id, struct xhci_td *cur_td, - struct xhci_dequeue_state *state); -void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, - unsigned int slot_id, unsigned int ep_index, - unsigned int stream_id, - struct xhci_dequeue_state *deq_state); -void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, - struct usb_device *udev, unsigned int ep_index); -void xhci_queue_config_ep_quirk(struct xhci_hcd *xhci, - unsigned int slot_id, unsigned int ep_index, - struct xhci_dequeue_state *deq_state); -void xhci_stop_endpoint_command_watchdog(unsigned long arg); -void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id, - unsigned int ep_index, unsigned int stream_id); - -/* xHCI roothub code */ -void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array, - int port_id, u32 link_state); -void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array, - int port_id, u32 port_bit); -int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, - char *buf, u16 wLength); -int xhci_hub_status_data(struct usb_hcd *hcd, char *buf); - -#ifdef CONFIG_PM -int xhci_bus_suspend(struct usb_hcd *hcd); -int xhci_bus_resume(struct usb_hcd *hcd); -#else -#define xhci_bus_suspend NULL -#define xhci_bus_resume NULL -#endif /* CONFIG_PM */ - -u32 xhci_port_state_to_neutral(u32 state); -int xhci_find_slot_id_by_port(struct usb_hcd *hcd, struct xhci_hcd *xhci, - u16 port); -void xhci_ring_device(struct xhci_hcd *xhci, int slot_id); - -/* xHCI contexts */ -struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx); -struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx); -struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int ep_index); - -#endif /* __LINUX_XHCI_HCD_H */ diff --git a/ANDROID_3.4.5/drivers/usb/image/Kconfig b/ANDROID_3.4.5/drivers/usb/image/Kconfig deleted file mode 100644 index 33350f9d..00000000 --- a/ANDROID_3.4.5/drivers/usb/image/Kconfig +++ /dev/null @@ -1,30 +0,0 @@ -# -# USB Imaging devices configuration -# -comment "USB Imaging devices" - depends on USB - -config USB_MDC800 - tristate "USB Mustek MDC800 Digital Camera support" - depends on USB - ---help--- - Say Y here if you want to connect this type of still camera to - your computer's USB port. This driver can be used with gphoto 0.4.3 - and higher (look at ). - To use it create a device node with "mknod /dev/mustek c 180 32" and - configure it in your software. - - To compile this driver as a module, choose M here: the - module will be called mdc800. - -config USB_MICROTEK - tristate "Microtek X6USB scanner support" - depends on USB && SCSI - help - Say Y here if you want support for the Microtek X6USB and - possibly the Phantom 336CX, Phantom C6 and ScanMaker V6U(S)L. - Support for anything but the X6 is experimental. - Please report failures and successes. - The scanner will appear as a scsi generic device to the rest - of the system. Scsi support is required. - This driver can be compiled as a module, called microtek. diff --git a/ANDROID_3.4.5/drivers/usb/image/Makefile b/ANDROID_3.4.5/drivers/usb/image/Makefile deleted file mode 100644 index 4148ae30..00000000 --- a/ANDROID_3.4.5/drivers/usb/image/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# -# Makefile for USB Image drivers -# - -obj-$(CONFIG_USB_MDC800) += mdc800.o -obj-$(CONFIG_USB_MICROTEK) += microtek.o diff --git a/ANDROID_3.4.5/drivers/usb/image/mdc800.c b/ANDROID_3.4.5/drivers/usb/image/mdc800.c deleted file mode 100644 index 575b56c7..00000000 --- a/ANDROID_3.4.5/drivers/usb/image/mdc800.c +++ /dev/null @@ -1,1089 +0,0 @@ -/* - * copyright (C) 1999/2000 by Henning Zabel - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -/* - * USB-Kernel Driver for the Mustek MDC800 Digital Camera - * (c) 1999/2000 Henning Zabel - * - * - * The driver brings the USB functions of the MDC800 to Linux. - * To use the Camera you must support the USB Protocol of the camera - * to the Kernel Node. - * The Driver uses a misc device Node. Create it with : - * mknod /dev/mustek c 180 32 - * - * The driver supports only one camera. - * - * Fix: mdc800 used sleep_on and slept with io_lock held. - * Converted sleep_on to waitqueues with schedule_timeout and made io_lock - * a semaphore from a spinlock. - * by Oliver Neukum - * (02/12/2001) - * - * Identify version on module load. - * (08/04/2001) gb - * - * version 0.7.5 - * Fixed potential SMP races with Spinlocks. - * Thanks to Oliver Neukum who - * noticed the race conditions. - * (30/10/2000) - * - * Fixed: Setting urb->dev before submitting urb. - * by Greg KH - * (13/10/2000) - * - * version 0.7.3 - * bugfix : The mdc800->state field gets set to READY after the - * the diconnect function sets it to NOT_CONNECTED. This makes the - * driver running like the camera is connected and causes some - * hang ups. - * - * version 0.7.1 - * MOD_INC and MOD_DEC are changed in usb_probe to prevent load/unload - * problems when compiled as Module. - * (04/04/2000) - * - * The mdc800 driver gets assigned the USB Minor 32-47. The Registration - * was updated to use these values. - * (26/03/2000) - * - * The Init und Exit Module Function are updated. - * (01/03/2000) - * - * version 0.7.0 - * Rewrite of the driver : The driver now uses URB's. The old stuff - * has been removed. - * - * version 0.6.0 - * Rewrite of this driver: The Emulation of the rs232 protocoll - * has been removed from the driver. A special executeCommand function - * for this driver is included to gphoto. - * The driver supports two kind of communication to bulk endpoints. - * Either with the dev->bus->ops->bulk... or with callback function. - * (09/11/1999) - * - * version 0.5.0: - * first Version that gets a version number. Most of the needed - * functions work. - * (20/10/1999) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* - * Version Information - */ -#define DRIVER_VERSION "v0.7.5 (30/10/2000)" -#define DRIVER_AUTHOR "Henning Zabel " -#define DRIVER_DESC "USB Driver for Mustek MDC800 Digital Camera" - -/* Vendor and Product Information */ -#define MDC800_VENDOR_ID 0x055f -#define MDC800_PRODUCT_ID 0xa800 - -/* Timeouts (msec) */ -#define TO_DOWNLOAD_GET_READY 1500 -#define TO_DOWNLOAD_GET_BUSY 1500 -#define TO_WRITE_GET_READY 1000 -#define TO_DEFAULT_COMMAND 5000 -#define TO_READ_FROM_IRQ TO_DEFAULT_COMMAND -#define TO_GET_READY TO_DEFAULT_COMMAND - -/* Minor Number of the device (create with mknod /dev/mustek c 180 32) */ -#define MDC800_DEVICE_MINOR_BASE 32 - - -/************************************************************************** - Data and structs -***************************************************************************/ - - -typedef enum { - NOT_CONNECTED, READY, WORKING, DOWNLOAD -} mdc800_state; - - -/* Data for the driver */ -struct mdc800_data -{ - struct usb_device * dev; // Device Data - mdc800_state state; - - unsigned int endpoint [4]; - - struct urb * irq_urb; - wait_queue_head_t irq_wait; - int irq_woken; - char* irq_urb_buffer; - - int camera_busy; // is camera busy ? - int camera_request_ready; // Status to synchronize with irq - char camera_response [8]; // last Bytes send after busy - - struct urb * write_urb; - char* write_urb_buffer; - wait_queue_head_t write_wait; - int written; - - - struct urb * download_urb; - char* download_urb_buffer; - wait_queue_head_t download_wait; - int downloaded; - int download_left; // Bytes left to download ? - - - /* Device Data */ - char out [64]; // Answer Buffer - int out_ptr; // Index to the first not readen byte - int out_count; // Bytes in the buffer - - int open; // Camera device open ? - struct mutex io_lock; // IO -lock - - char in [8]; // Command Input Buffer - int in_count; - - int pic_index; // Cache for the Imagesize (-1 for nothing cached ) - int pic_len; - int minor; -}; - - -/* Specification of the Endpoints */ -static struct usb_endpoint_descriptor mdc800_ed [4] = -{ - { - .bLength = 0, - .bDescriptorType = 0, - .bEndpointAddress = 0x01, - .bmAttributes = 0x02, - .wMaxPacketSize = cpu_to_le16(8), - .bInterval = 0, - .bRefresh = 0, - .bSynchAddress = 0, - }, - { - .bLength = 0, - .bDescriptorType = 0, - .bEndpointAddress = 0x82, - .bmAttributes = 0x03, - .wMaxPacketSize = cpu_to_le16(8), - .bInterval = 0, - .bRefresh = 0, - .bSynchAddress = 0, - }, - { - .bLength = 0, - .bDescriptorType = 0, - .bEndpointAddress = 0x03, - .bmAttributes = 0x02, - .wMaxPacketSize = cpu_to_le16(64), - .bInterval = 0, - .bRefresh = 0, - .bSynchAddress = 0, - }, - { - .bLength = 0, - .bDescriptorType = 0, - .bEndpointAddress = 0x84, - .bmAttributes = 0x02, - .wMaxPacketSize = cpu_to_le16(64), - .bInterval = 0, - .bRefresh = 0, - .bSynchAddress = 0, - }, -}; - -/* The Variable used by the driver */ -static struct mdc800_data* mdc800; - - -/*************************************************************************** - The USB Part of the driver -****************************************************************************/ - -static int mdc800_endpoint_equals (struct usb_endpoint_descriptor *a,struct usb_endpoint_descriptor *b) -{ - return ( - ( a->bEndpointAddress == b->bEndpointAddress ) - && ( a->bmAttributes == b->bmAttributes ) - && ( a->wMaxPacketSize == b->wMaxPacketSize ) - ); -} - - -/* - * Checks whether the camera responds busy - */ -static int mdc800_isBusy (char* ch) -{ - int i=0; - while (i<8) - { - if (ch [i] != (char)0x99) - return 0; - i++; - } - return 1; -} - - -/* - * Checks whether the Camera is ready - */ -static int mdc800_isReady (char *ch) -{ - int i=0; - while (i<8) - { - if (ch [i] != (char)0xbb) - return 0; - i++; - } - return 1; -} - - - -/* - * USB IRQ Handler for InputLine - */ -static void mdc800_usb_irq (struct urb *urb) -{ - int data_received=0, wake_up; - unsigned char* b=urb->transfer_buffer; - struct mdc800_data* mdc800=urb->context; - int status = urb->status; - - if (status >= 0) { - - //dbg ("%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]); - - if (mdc800_isBusy (b)) - { - if (!mdc800->camera_busy) - { - mdc800->camera_busy=1; - dbg ("gets busy"); - } - } - else - { - if (mdc800->camera_busy && mdc800_isReady (b)) - { - mdc800->camera_busy=0; - dbg ("gets ready"); - } - } - if (!(mdc800_isBusy (b) || mdc800_isReady (b))) - { - /* Store Data in camera_answer field */ - dbg ("%i %i %i %i %i %i %i %i ",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]); - - memcpy (mdc800->camera_response,b,8); - data_received=1; - } - } - wake_up= ( mdc800->camera_request_ready > 0 ) - && - ( - ((mdc800->camera_request_ready == 1) && (!mdc800->camera_busy)) - || - ((mdc800->camera_request_ready == 2) && data_received) - || - ((mdc800->camera_request_ready == 3) && (mdc800->camera_busy)) - || - (status < 0) - ); - - if (wake_up) - { - mdc800->camera_request_ready=0; - mdc800->irq_woken=1; - wake_up (&mdc800->irq_wait); - } -} - - -/* - * Waits a while until the irq responds that camera is ready - * - * mode : 0: Wait for camera gets ready - * 1: Wait for receiving data - * 2: Wait for camera gets busy - * - * msec: Time to wait - */ -static int mdc800_usb_waitForIRQ (int mode, int msec) -{ - mdc800->camera_request_ready=1+mode; - - wait_event_timeout(mdc800->irq_wait, mdc800->irq_woken, msec*HZ/1000); - mdc800->irq_woken = 0; - - if (mdc800->camera_request_ready>0) - { - mdc800->camera_request_ready=0; - dev_err(&mdc800->dev->dev, "timeout waiting for camera.\n"); - return -1; - } - - if (mdc800->state == NOT_CONNECTED) - { - printk(KERN_WARNING "mdc800: Camera gets disconnected " - "during waiting for irq.\n"); - mdc800->camera_request_ready=0; - return -2; - } - - return 0; -} - - -/* - * The write_urb callback function - */ -static void mdc800_usb_write_notify (struct urb *urb) -{ - struct mdc800_data* mdc800=urb->context; - int status = urb->status; - - if (status != 0) - dev_err(&mdc800->dev->dev, - "writing command fails (status=%i)\n", status); - else - mdc800->state=READY; - mdc800->written = 1; - wake_up (&mdc800->write_wait); -} - - -/* - * The download_urb callback function - */ -static void mdc800_usb_download_notify (struct urb *urb) -{ - struct mdc800_data* mdc800=urb->context; - int status = urb->status; - - if (status == 0) { - /* Fill output buffer with these data */ - memcpy (mdc800->out, urb->transfer_buffer, 64); - mdc800->out_count=64; - mdc800->out_ptr=0; - mdc800->download_left-=64; - if (mdc800->download_left == 0) - { - mdc800->state=READY; - } - } else { - dev_err(&mdc800->dev->dev, - "request bytes fails (status:%i)\n", status); - } - mdc800->downloaded = 1; - wake_up (&mdc800->download_wait); -} - - -/*************************************************************************** - Probing for the Camera - ***************************************************************************/ - -static struct usb_driver mdc800_usb_driver; -static const struct file_operations mdc800_device_ops; -static struct usb_class_driver mdc800_class = { - .name = "mdc800%d", - .fops = &mdc800_device_ops, - .minor_base = MDC800_DEVICE_MINOR_BASE, -}; - - -/* - * Callback to search the Mustek MDC800 on the USB Bus - */ -static int mdc800_usb_probe (struct usb_interface *intf, - const struct usb_device_id *id) -{ - int i,j; - struct usb_host_interface *intf_desc; - struct usb_device *dev = interface_to_usbdev (intf); - int irq_interval=0; - int retval; - - dbg ("(mdc800_usb_probe) called."); - - - if (mdc800->dev != NULL) - { - dev_warn(&intf->dev, "only one Mustek MDC800 is supported.\n"); - return -ENODEV; - } - - if (dev->descriptor.bNumConfigurations != 1) - { - dev_err(&intf->dev, - "probe fails -> wrong Number of Configuration\n"); - return -ENODEV; - } - intf_desc = intf->cur_altsetting; - - if ( - ( intf_desc->desc.bInterfaceClass != 0xff ) - || ( intf_desc->desc.bInterfaceSubClass != 0 ) - || ( intf_desc->desc.bInterfaceProtocol != 0 ) - || ( intf_desc->desc.bNumEndpoints != 4) - ) - { - dev_err(&intf->dev, "probe fails -> wrong Interface\n"); - return -ENODEV; - } - - /* Check the Endpoints */ - for (i=0; i<4; i++) - { - mdc800->endpoint[i]=-1; - for (j=0; j<4; j++) - { - if (mdc800_endpoint_equals (&intf_desc->endpoint [j].desc,&mdc800_ed [i])) - { - mdc800->endpoint[i]=intf_desc->endpoint [j].desc.bEndpointAddress ; - if (i==1) - { - irq_interval=intf_desc->endpoint [j].desc.bInterval; - } - } - } - if (mdc800->endpoint[i] == -1) - { - dev_err(&intf->dev, "probe fails -> Wrong Endpoints.\n"); - return -ENODEV; - } - } - - - dev_info(&intf->dev, "Found Mustek MDC800 on USB.\n"); - - mutex_lock(&mdc800->io_lock); - - retval = usb_register_dev(intf, &mdc800_class); - if (retval) { - dev_err(&intf->dev, "Not able to get a minor for this device.\n"); - mutex_unlock(&mdc800->io_lock); - return -ENODEV; - } - - mdc800->dev=dev; - mdc800->open=0; - - /* Setup URB Structs */ - usb_fill_int_urb ( - mdc800->irq_urb, - mdc800->dev, - usb_rcvintpipe (mdc800->dev,mdc800->endpoint [1]), - mdc800->irq_urb_buffer, - 8, - mdc800_usb_irq, - mdc800, - irq_interval - ); - - usb_fill_bulk_urb ( - mdc800->write_urb, - mdc800->dev, - usb_sndbulkpipe (mdc800->dev, mdc800->endpoint[0]), - mdc800->write_urb_buffer, - 8, - mdc800_usb_write_notify, - mdc800 - ); - - usb_fill_bulk_urb ( - mdc800->download_urb, - mdc800->dev, - usb_rcvbulkpipe (mdc800->dev, mdc800->endpoint [3]), - mdc800->download_urb_buffer, - 64, - mdc800_usb_download_notify, - mdc800 - ); - - mdc800->state=READY; - - mutex_unlock(&mdc800->io_lock); - - usb_set_intfdata(intf, mdc800); - return 0; -} - - -/* - * Disconnect USB device (maybe the MDC800) - */ -static void mdc800_usb_disconnect (struct usb_interface *intf) -{ - struct mdc800_data* mdc800 = usb_get_intfdata(intf); - - dbg ("(mdc800_usb_disconnect) called"); - - if (mdc800) { - if (mdc800->state == NOT_CONNECTED) - return; - - usb_deregister_dev(intf, &mdc800_class); - - /* must be under lock to make sure no URB - is submitted after usb_kill_urb() */ - mutex_lock(&mdc800->io_lock); - mdc800->state=NOT_CONNECTED; - - usb_kill_urb(mdc800->irq_urb); - usb_kill_urb(mdc800->write_urb); - usb_kill_urb(mdc800->download_urb); - mutex_unlock(&mdc800->io_lock); - - mdc800->dev = NULL; - usb_set_intfdata(intf, NULL); - } - dev_info(&intf->dev, "Mustek MDC800 disconnected from USB.\n"); -} - - -/*************************************************************************** - The Misc device Part (file_operations) -****************************************************************************/ - -/* - * This Function calc the Answersize for a command. - */ -static int mdc800_getAnswerSize (char command) -{ - switch ((unsigned char) command) - { - case 0x2a: - case 0x49: - case 0x51: - case 0x0d: - case 0x20: - case 0x07: - case 0x01: - case 0x25: - case 0x00: - return 8; - - case 0x05: - case 0x3e: - return mdc800->pic_len; - - case 0x09: - return 4096; - - default: - return 0; - } -} - - -/* - * Init the device: (1) alloc mem (2) Increase MOD Count .. - */ -static int mdc800_device_open (struct inode* inode, struct file *file) -{ - int retval=0; - int errn=0; - - mutex_lock(&mdc800->io_lock); - - if (mdc800->state == NOT_CONNECTED) - { - errn=-EBUSY; - goto error_out; - } - if (mdc800->open) - { - errn=-EBUSY; - goto error_out; - } - - mdc800->in_count=0; - mdc800->out_count=0; - mdc800->out_ptr=0; - mdc800->pic_index=0; - mdc800->pic_len=-1; - mdc800->download_left=0; - - mdc800->camera_busy=0; - mdc800->camera_request_ready=0; - - retval=0; - mdc800->irq_urb->dev = mdc800->dev; - retval = usb_submit_urb (mdc800->irq_urb, GFP_KERNEL); - if (retval) { - dev_err(&mdc800->dev->dev, - "request USB irq fails (submit_retval=%i).\n", retval); - errn = -EIO; - goto error_out; - } - - mdc800->open=1; - dbg ("Mustek MDC800 device opened."); - -error_out: - mutex_unlock(&mdc800->io_lock); - return errn; -} - - -/* - * Close the Camera and release Memory - */ -static int mdc800_device_release (struct inode* inode, struct file *file) -{ - int retval=0; - dbg ("Mustek MDC800 device closed."); - - mutex_lock(&mdc800->io_lock); - if (mdc800->open && (mdc800->state != NOT_CONNECTED)) - { - usb_kill_urb(mdc800->irq_urb); - usb_kill_urb(mdc800->write_urb); - usb_kill_urb(mdc800->download_urb); - mdc800->open=0; - } - else - { - retval=-EIO; - } - - mutex_unlock(&mdc800->io_lock); - return retval; -} - - -/* - * The Device read callback Function - */ -static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t len, loff_t *pos) -{ - size_t left=len, sts=len; /* single transfer size */ - char __user *ptr = buf; - int retval; - - mutex_lock(&mdc800->io_lock); - if (mdc800->state == NOT_CONNECTED) - { - mutex_unlock(&mdc800->io_lock); - return -EBUSY; - } - if (mdc800->state == WORKING) - { - printk(KERN_WARNING "mdc800: Illegal State \"working\"" - "reached during read ?!\n"); - mutex_unlock(&mdc800->io_lock); - return -EBUSY; - } - if (!mdc800->open) - { - mutex_unlock(&mdc800->io_lock); - return -EBUSY; - } - - while (left) - { - if (signal_pending (current)) - { - mutex_unlock(&mdc800->io_lock); - return -EINTR; - } - - sts=left > (mdc800->out_count-mdc800->out_ptr)?mdc800->out_count-mdc800->out_ptr:left; - - if (sts <= 0) - { - /* Too less Data in buffer */ - if (mdc800->state == DOWNLOAD) - { - mdc800->out_count=0; - mdc800->out_ptr=0; - - /* Download -> Request new bytes */ - mdc800->download_urb->dev = mdc800->dev; - retval = usb_submit_urb (mdc800->download_urb, GFP_KERNEL); - if (retval) { - dev_err(&mdc800->dev->dev, - "Can't submit download urb " - "(retval=%i)\n", retval); - mutex_unlock(&mdc800->io_lock); - return len-left; - } - wait_event_timeout(mdc800->download_wait, mdc800->downloaded, - TO_DOWNLOAD_GET_READY*HZ/1000); - mdc800->downloaded = 0; - if (mdc800->download_urb->status != 0) - { - dev_err(&mdc800->dev->dev, - "request download-bytes fails " - "(status=%i)\n", - mdc800->download_urb->status); - mutex_unlock(&mdc800->io_lock); - return len-left; - } - } - else - { - /* No more bytes -> that's an error*/ - mutex_unlock(&mdc800->io_lock); - return -EIO; - } - } - else - { - /* Copy Bytes */ - if (copy_to_user(ptr, &mdc800->out [mdc800->out_ptr], - sts)) { - mutex_unlock(&mdc800->io_lock); - return -EFAULT; - } - ptr+=sts; - left-=sts; - mdc800->out_ptr+=sts; - } - } - - mutex_unlock(&mdc800->io_lock); - return len-left; -} - - -/* - * The Device write callback Function - * If a 8Byte Command is received, it will be send to the camera. - * After this the driver initiates the request for the answer or - * just waits until the camera becomes ready. - */ -static ssize_t mdc800_device_write (struct file *file, const char __user *buf, size_t len, loff_t *pos) -{ - size_t i=0; - int retval; - - mutex_lock(&mdc800->io_lock); - if (mdc800->state != READY) - { - mutex_unlock(&mdc800->io_lock); - return -EBUSY; - } - if (!mdc800->open ) - { - mutex_unlock(&mdc800->io_lock); - return -EBUSY; - } - - while (iio_lock); - return -EINTR; - } - - if(get_user(c, buf+i)) - { - mutex_unlock(&mdc800->io_lock); - return -EFAULT; - } - - /* check for command start */ - if (c == 0x55) - { - mdc800->in_count=0; - mdc800->out_count=0; - mdc800->out_ptr=0; - mdc800->download_left=0; - } - - /* save command byte */ - if (mdc800->in_count < 8) - { - mdc800->in[mdc800->in_count] = c; - mdc800->in_count++; - } - else - { - mutex_unlock(&mdc800->io_lock); - return -EIO; - } - - /* Command Buffer full ? -> send it to camera */ - if (mdc800->in_count == 8) - { - int answersize; - - if (mdc800_usb_waitForIRQ (0,TO_GET_READY)) - { - dev_err(&mdc800->dev->dev, - "Camera didn't get ready.\n"); - mutex_unlock(&mdc800->io_lock); - return -EIO; - } - - answersize=mdc800_getAnswerSize (mdc800->in[1]); - - mdc800->state=WORKING; - memcpy (mdc800->write_urb->transfer_buffer, mdc800->in,8); - mdc800->write_urb->dev = mdc800->dev; - retval = usb_submit_urb (mdc800->write_urb, GFP_KERNEL); - if (retval) { - dev_err(&mdc800->dev->dev, - "submitting write urb fails " - "(retval=%i)\n", retval); - mutex_unlock(&mdc800->io_lock); - return -EIO; - } - wait_event_timeout(mdc800->write_wait, mdc800->written, TO_WRITE_GET_READY*HZ/1000); - mdc800->written = 0; - if (mdc800->state == WORKING) - { - usb_kill_urb(mdc800->write_urb); - mutex_unlock(&mdc800->io_lock); - return -EIO; - } - - switch ((unsigned char) mdc800->in[1]) - { - case 0x05: /* Download Image */ - case 0x3e: /* Take shot in Fine Mode (WCam Mode) */ - if (mdc800->pic_len < 0) - { - dev_err(&mdc800->dev->dev, - "call 0x07 before " - "0x05,0x3e\n"); - mdc800->state=READY; - mutex_unlock(&mdc800->io_lock); - return -EIO; - } - mdc800->pic_len=-1; - - case 0x09: /* Download Thumbnail */ - mdc800->download_left=answersize+64; - mdc800->state=DOWNLOAD; - mdc800_usb_waitForIRQ (0,TO_DOWNLOAD_GET_BUSY); - break; - - - default: - if (answersize) - { - - if (mdc800_usb_waitForIRQ (1,TO_READ_FROM_IRQ)) - { - dev_err(&mdc800->dev->dev, "requesting answer from irq fails\n"); - mutex_unlock(&mdc800->io_lock); - return -EIO; - } - - /* Write dummy data, (this is ugly but part of the USB Protocol */ - /* if you use endpoint 1 as bulk and not as irq) */ - memcpy (mdc800->out, mdc800->camera_response,8); - - /* This is the interpreted answer */ - memcpy (&mdc800->out[8], mdc800->camera_response,8); - - mdc800->out_ptr=0; - mdc800->out_count=16; - - /* Cache the Imagesize, if command was getImageSize */ - if (mdc800->in [1] == (char) 0x07) - { - mdc800->pic_len=(int) 65536*(unsigned char) mdc800->camera_response[0]+256*(unsigned char) mdc800->camera_response[1]+(unsigned char) mdc800->camera_response[2]; - - dbg ("cached imagesize = %i",mdc800->pic_len); - } - - } - else - { - if (mdc800_usb_waitForIRQ (0,TO_DEFAULT_COMMAND)) - { - dev_err(&mdc800->dev->dev, "Command Timeout.\n"); - mutex_unlock(&mdc800->io_lock); - return -EIO; - } - } - mdc800->state=READY; - break; - } - } - i++; - } - mutex_unlock(&mdc800->io_lock); - return i; -} - - -/*************************************************************************** - Init and Cleanup this driver (Structs and types) -****************************************************************************/ - -/* File Operations of this drivers */ -static const struct file_operations mdc800_device_ops = -{ - .owner = THIS_MODULE, - .read = mdc800_device_read, - .write = mdc800_device_write, - .open = mdc800_device_open, - .release = mdc800_device_release, - .llseek = noop_llseek, -}; - - - -static const struct usb_device_id mdc800_table[] = { - { USB_DEVICE(MDC800_VENDOR_ID, MDC800_PRODUCT_ID) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, mdc800_table); -/* - * USB Driver Struct for this device - */ -static struct usb_driver mdc800_usb_driver = -{ - .name = "mdc800", - .probe = mdc800_usb_probe, - .disconnect = mdc800_usb_disconnect, - .id_table = mdc800_table -}; - - - -/************************************************************************ - Init and Cleanup this driver (Main Functions) -*************************************************************************/ - -static int __init usb_mdc800_init (void) -{ - int retval = -ENODEV; - /* Allocate Memory */ - mdc800=kzalloc (sizeof (struct mdc800_data), GFP_KERNEL); - if (!mdc800) - goto cleanup_on_fail; - - mdc800->dev = NULL; - mdc800->state=NOT_CONNECTED; - mutex_init (&mdc800->io_lock); - - init_waitqueue_head (&mdc800->irq_wait); - init_waitqueue_head (&mdc800->write_wait); - init_waitqueue_head (&mdc800->download_wait); - - mdc800->irq_woken = 0; - mdc800->downloaded = 0; - mdc800->written = 0; - - mdc800->irq_urb_buffer=kmalloc (8, GFP_KERNEL); - if (!mdc800->irq_urb_buffer) - goto cleanup_on_fail; - mdc800->write_urb_buffer=kmalloc (8, GFP_KERNEL); - if (!mdc800->write_urb_buffer) - goto cleanup_on_fail; - mdc800->download_urb_buffer=kmalloc (64, GFP_KERNEL); - if (!mdc800->download_urb_buffer) - goto cleanup_on_fail; - - mdc800->irq_urb=usb_alloc_urb (0, GFP_KERNEL); - if (!mdc800->irq_urb) - goto cleanup_on_fail; - mdc800->download_urb=usb_alloc_urb (0, GFP_KERNEL); - if (!mdc800->download_urb) - goto cleanup_on_fail; - mdc800->write_urb=usb_alloc_urb (0, GFP_KERNEL); - if (!mdc800->write_urb) - goto cleanup_on_fail; - - /* Register the driver */ - retval = usb_register(&mdc800_usb_driver); - if (retval) - goto cleanup_on_fail; - - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - - return 0; - - /* Clean driver up, when something fails */ - -cleanup_on_fail: - - if (mdc800 != NULL) - { - printk(KERN_ERR "mdc800: can't alloc memory!\n"); - - kfree(mdc800->download_urb_buffer); - kfree(mdc800->write_urb_buffer); - kfree(mdc800->irq_urb_buffer); - - usb_free_urb(mdc800->write_urb); - usb_free_urb(mdc800->download_urb); - usb_free_urb(mdc800->irq_urb); - - kfree (mdc800); - } - mdc800 = NULL; - return retval; -} - - -static void __exit usb_mdc800_cleanup (void) -{ - usb_deregister (&mdc800_usb_driver); - - usb_free_urb (mdc800->irq_urb); - usb_free_urb (mdc800->download_urb); - usb_free_urb (mdc800->write_urb); - - kfree (mdc800->irq_urb_buffer); - kfree (mdc800->write_urb_buffer); - kfree (mdc800->download_urb_buffer); - - kfree (mdc800); - mdc800 = NULL; -} - -module_init (usb_mdc800_init); -module_exit (usb_mdc800_cleanup); - -MODULE_AUTHOR( DRIVER_AUTHOR ); -MODULE_DESCRIPTION( DRIVER_DESC ); -MODULE_LICENSE("GPL"); - diff --git a/ANDROID_3.4.5/drivers/usb/image/microtek.c b/ANDROID_3.4.5/drivers/usb/image/microtek.c deleted file mode 100644 index 9c0f8cab..00000000 --- a/ANDROID_3.4.5/drivers/usb/image/microtek.c +++ /dev/null @@ -1,816 +0,0 @@ -/* Driver for Microtek Scanmaker X6 USB scanner, and possibly others. - * - * (C) Copyright 2000 John Fremlin - * (C) Copyright 2000 Oliver Neukum - * - * Parts shamelessly stolen from usb-storage and copyright by their - * authors. Thanks to Matt Dharm for giving us permission! - * - * This driver implements a SCSI host controller driver and a USB - * device driver. To avoid confusion, all the USB related stuff is - * prefixed by mts_usb_ and all the SCSI stuff by mts_scsi_. - * - * Microtek (www.microtek.com) did not release the specifications for - * their USB protocol to us, so we had to reverse engineer them. We - * don't know for which models they are valid. - * - * The X6 USB has three bulk endpoints, one output (0x1) down which - * commands and outgoing data are sent, and two input: 0x82 from which - * normal data is read from the scanner (in packets of maximum 32 - * bytes) and from which the status byte is read, and 0x83 from which - * the results of a scan (or preview) are read in up to 64 * 1024 byte - * chunks by the Windows driver. We don't know how much it is possible - * to read at a time from 0x83. - * - * It seems possible to read (with URB transfers) everything from 0x82 - * in one go, without bothering to read in 32 byte chunks. - * - * There seems to be an optimisation of a further READ implicit if - * you simply read from 0x83. - * - * Guessed protocol: - * - * Send raw SCSI command to EP 0x1 - * - * If there is data to receive: - * If the command was READ datatype=image: - * Read a lot of data from EP 0x83 - * Else: - * Read data from EP 0x82 - * Else: - * If there is data to transmit: - * Write it to EP 0x1 - * - * Read status byte from EP 0x82 - * - * References: - * - * The SCSI command set for the scanner is available from - * ftp://ftp.microtek.com/microtek/devpack/ - * - * Microtek NV sent us a more up to date version of the document. If - * you want it, just send mail. - * - * Status: - * - * Untested with multiple scanners. - * Untested on SMP. - * Untested on a bigendian machine. - * - * History: - * - * 20000417 starting history - * 20000417 fixed load oops - * 20000417 fixed unload oops - * 20000419 fixed READ IMAGE detection - * 20000424 started conversion to use URBs - * 20000502 handled short transfers as errors - * 20000513 rename and organisation of functions (john) - * 20000513 added IDs for all products supported by Windows driver (john) - * 20000514 Rewrote mts_scsi_queuecommand to use URBs (john) - * 20000514 Version 0.0.8j - * 20000514 Fix reporting of non-existent devices to SCSI layer (john) - * 20000514 Added MTS_DEBUG_INT (john) - * 20000514 Changed "usb-microtek" to "microtek" for consistency (john) - * 20000514 Stupid bug fixes (john) - * 20000514 Version 0.0.9j - * 20000515 Put transfer context and URB in mts_desc (john) - * 20000515 Added prelim turn off debugging support (john) - * 20000515 Version 0.0.10j - * 20000515 Fixed up URB allocation (clear URB on alloc) (john) - * 20000515 Version 0.0.11j - * 20000516 Removed unnecessary spinlock in mts_transfer_context (john) - * 20000516 Removed unnecessary up on instance lock in mts_remove_nolock (john) - * 20000516 Implemented (badly) scsi_abort (john) - * 20000516 Version 0.0.12j - * 20000517 Hopefully removed mts_remove_nolock quasideadlock (john) - * 20000517 Added mts_debug_dump to print ll USB info (john) - * 20000518 Tweaks and documentation updates (john) - * 20000518 Version 0.0.13j - * 20000518 Cleaned up abort handling (john) - * 20000523 Removed scsi_command and various scsi_..._resets (john) - * 20000523 Added unlink URB on scsi_abort, now OHCI supports it (john) - * 20000523 Fixed last tiresome compile warning (john) - * 20000523 Version 0.0.14j (though version 0.1 has come out?) - * 20000602 Added primitive reset - * 20000602 Version 0.2.0 - * 20000603 various cosmetic changes - * 20000603 Version 0.2.1 - * 20000620 minor cosmetic changes - * 20000620 Version 0.2.2 - * 20000822 Hopefully fixed deadlock in mts_remove_nolock() - * 20000822 Fixed minor race in mts_transfer_cleanup() - * 20000822 Fixed deadlock on submission error in queuecommand - * 20000822 Version 0.2.3 - * 20000913 Reduced module size if debugging is off - * 20000913 Version 0.2.4 - * 20010210 New abort logic - * 20010210 Version 0.3.0 - * 20010217 Merged scatter/gather - * 20010218 Version 0.4.0 - * 20010218 Cosmetic fixes - * 20010218 Version 0.4.1 - * 20010306 Abort while using scatter/gather - * 20010306 Version 0.4.2 - * 20010311 Remove all timeouts and tidy up generally (john) - * 20010320 check return value of scsi_register() - * 20010320 Version 0.4.3 - * 20010408 Identify version on module load. - * 20011003 Fix multiple requests - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "../../scsi/scsi.h" -#include - -#include "microtek.h" - -/* - * Version Information - */ -#define DRIVER_VERSION "v0.4.3" -#define DRIVER_AUTHOR "John Fremlin , Oliver Neukum " -#define DRIVER_DESC "Microtek Scanmaker X6 USB scanner driver" - -/* Should we do debugging? */ - -//#define MTS_DO_DEBUG - -/* USB layer driver interface */ - -static int mts_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id); -static void mts_usb_disconnect(struct usb_interface *intf); - -static const struct usb_device_id mts_usb_ids[]; - -static struct usb_driver mts_usb_driver = { - .name = "microtekX6", - .probe = mts_usb_probe, - .disconnect = mts_usb_disconnect, - .id_table = mts_usb_ids, -}; - - -/* Internal driver stuff */ - -#define MTS_VERSION "0.4.3" -#define MTS_NAME "microtek usb (rev " MTS_VERSION "): " - -#define MTS_WARNING(x...) \ - printk( KERN_WARNING MTS_NAME x ) -#define MTS_ERROR(x...) \ - printk( KERN_ERR MTS_NAME x ) -#define MTS_INT_ERROR(x...) \ - MTS_ERROR(x) -#define MTS_MESSAGE(x...) \ - printk( KERN_INFO MTS_NAME x ) - -#if defined MTS_DO_DEBUG - -#define MTS_DEBUG(x...) \ - printk( KERN_DEBUG MTS_NAME x ) - -#define MTS_DEBUG_GOT_HERE() \ - MTS_DEBUG("got to %s:%d (%s)\n", __FILE__, (int)__LINE__, __func__ ) -#define MTS_DEBUG_INT() \ - do { MTS_DEBUG_GOT_HERE(); \ - MTS_DEBUG("transfer = 0x%x context = 0x%x\n",(int)transfer,(int)context ); \ - MTS_DEBUG("status = 0x%x data-length = 0x%x sent = 0x%x\n",transfer->status,(int)context->data_length, (int)transfer->actual_length ); \ - mts_debug_dump(context->instance);\ - } while(0) -#else - -#define MTS_NUL_STATEMENT do { } while(0) - -#define MTS_DEBUG(x...) MTS_NUL_STATEMENT -#define MTS_DEBUG_GOT_HERE() MTS_NUL_STATEMENT -#define MTS_DEBUG_INT() MTS_NUL_STATEMENT - -#endif - - - -#define MTS_INT_INIT()\ - struct mts_transfer_context* context = (struct mts_transfer_context*)transfer->context; \ - MTS_DEBUG_INT();\ - -#ifdef MTS_DO_DEBUG - -static inline void mts_debug_dump(struct mts_desc* desc) { - MTS_DEBUG("desc at 0x%x: toggle = %02x%02x\n", - (int)desc, - (int)desc->usb_dev->toggle[1],(int)desc->usb_dev->toggle[0] - ); - MTS_DEBUG("ep_out=%x ep_response=%x ep_image=%x\n", - usb_sndbulkpipe(desc->usb_dev,desc->ep_out), - usb_rcvbulkpipe(desc->usb_dev,desc->ep_response), - usb_rcvbulkpipe(desc->usb_dev,desc->ep_image) - ); -} - - -static inline void mts_show_command(struct scsi_cmnd *srb) -{ - char *what = NULL; - - switch (srb->cmnd[0]) { - case TEST_UNIT_READY: what = "TEST_UNIT_READY"; break; - case REZERO_UNIT: what = "REZERO_UNIT"; break; - case REQUEST_SENSE: what = "REQUEST_SENSE"; break; - case FORMAT_UNIT: what = "FORMAT_UNIT"; break; - case READ_BLOCK_LIMITS: what = "READ_BLOCK_LIMITS"; break; - case REASSIGN_BLOCKS: what = "REASSIGN_BLOCKS"; break; - case READ_6: what = "READ_6"; break; - case WRITE_6: what = "WRITE_6"; break; - case SEEK_6: what = "SEEK_6"; break; - case READ_REVERSE: what = "READ_REVERSE"; break; - case WRITE_FILEMARKS: what = "WRITE_FILEMARKS"; break; - case SPACE: what = "SPACE"; break; - case INQUIRY: what = "INQUIRY"; break; - case RECOVER_BUFFERED_DATA: what = "RECOVER_BUFFERED_DATA"; break; - case MODE_SELECT: what = "MODE_SELECT"; break; - case RESERVE: what = "RESERVE"; break; - case RELEASE: what = "RELEASE"; break; - case COPY: what = "COPY"; break; - case ERASE: what = "ERASE"; break; - case MODE_SENSE: what = "MODE_SENSE"; break; - case START_STOP: what = "START_STOP"; break; - case RECEIVE_DIAGNOSTIC: what = "RECEIVE_DIAGNOSTIC"; break; - case SEND_DIAGNOSTIC: what = "SEND_DIAGNOSTIC"; break; - case ALLOW_MEDIUM_REMOVAL: what = "ALLOW_MEDIUM_REMOVAL"; break; - case SET_WINDOW: what = "SET_WINDOW"; break; - case READ_CAPACITY: what = "READ_CAPACITY"; break; - case READ_10: what = "READ_10"; break; - case WRITE_10: what = "WRITE_10"; break; - case SEEK_10: what = "SEEK_10"; break; - case WRITE_VERIFY: what = "WRITE_VERIFY"; break; - case VERIFY: what = "VERIFY"; break; - case SEARCH_HIGH: what = "SEARCH_HIGH"; break; - case SEARCH_EQUAL: what = "SEARCH_EQUAL"; break; - case SEARCH_LOW: what = "SEARCH_LOW"; break; - case SET_LIMITS: what = "SET_LIMITS"; break; - case READ_POSITION: what = "READ_POSITION"; break; - case SYNCHRONIZE_CACHE: what = "SYNCHRONIZE_CACHE"; break; - case LOCK_UNLOCK_CACHE: what = "LOCK_UNLOCK_CACHE"; break; - case READ_DEFECT_DATA: what = "READ_DEFECT_DATA"; break; - case MEDIUM_SCAN: what = "MEDIUM_SCAN"; break; - case COMPARE: what = "COMPARE"; break; - case COPY_VERIFY: what = "COPY_VERIFY"; break; - case WRITE_BUFFER: what = "WRITE_BUFFER"; break; - case READ_BUFFER: what = "READ_BUFFER"; break; - case UPDATE_BLOCK: what = "UPDATE_BLOCK"; break; - case READ_LONG: what = "READ_LONG"; break; - case WRITE_LONG: what = "WRITE_LONG"; break; - case CHANGE_DEFINITION: what = "CHANGE_DEFINITION"; break; - case WRITE_SAME: what = "WRITE_SAME"; break; - case READ_TOC: what = "READ_TOC"; break; - case LOG_SELECT: what = "LOG_SELECT"; break; - case LOG_SENSE: what = "LOG_SENSE"; break; - case MODE_SELECT_10: what = "MODE_SELECT_10"; break; - case MODE_SENSE_10: what = "MODE_SENSE_10"; break; - case MOVE_MEDIUM: what = "MOVE_MEDIUM"; break; - case READ_12: what = "READ_12"; break; - case WRITE_12: what = "WRITE_12"; break; - case WRITE_VERIFY_12: what = "WRITE_VERIFY_12"; break; - case SEARCH_HIGH_12: what = "SEARCH_HIGH_12"; break; - case SEARCH_EQUAL_12: what = "SEARCH_EQUAL_12"; break; - case SEARCH_LOW_12: what = "SEARCH_LOW_12"; break; - case READ_ELEMENT_STATUS: what = "READ_ELEMENT_STATUS"; break; - case SEND_VOLUME_TAG: what = "SEND_VOLUME_TAG"; break; - case WRITE_LONG_2: what = "WRITE_LONG_2"; break; - default: - MTS_DEBUG("can't decode command\n"); - goto out; - break; - } - MTS_DEBUG( "Command %s (%d bytes)\n", what, srb->cmd_len); - - out: - MTS_DEBUG( " %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - srb->cmnd[0], srb->cmnd[1], srb->cmnd[2], srb->cmnd[3], srb->cmnd[4], srb->cmnd[5], - srb->cmnd[6], srb->cmnd[7], srb->cmnd[8], srb->cmnd[9]); -} - -#else - -static inline void mts_show_command(struct scsi_cmnd * dummy) -{ -} - -static inline void mts_debug_dump(struct mts_desc* dummy) -{ -} - -#endif - -static inline void mts_urb_abort(struct mts_desc* desc) { - MTS_DEBUG_GOT_HERE(); - mts_debug_dump(desc); - - usb_kill_urb( desc->urb ); -} - -static int mts_slave_alloc (struct scsi_device *s) -{ - s->inquiry_len = 0x24; - return 0; -} - -static int mts_slave_configure (struct scsi_device *s) -{ - blk_queue_dma_alignment(s->request_queue, (512 - 1)); - return 0; -} - -static int mts_scsi_abort(struct scsi_cmnd *srb) -{ - struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]); - - MTS_DEBUG_GOT_HERE(); - - mts_urb_abort(desc); - - return FAILED; -} - -static int mts_scsi_host_reset(struct scsi_cmnd *srb) -{ - struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]); - int result; - - MTS_DEBUG_GOT_HERE(); - mts_debug_dump(desc); - - result = usb_lock_device_for_reset(desc->usb_dev, desc->usb_intf); - if (result == 0) { - result = usb_reset_device(desc->usb_dev); - usb_unlock_device(desc->usb_dev); - } - return result ? FAILED : SUCCESS; -} - -static int -mts_scsi_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *srb); - -static void mts_transfer_cleanup( struct urb *transfer ); -static void mts_do_sg(struct urb * transfer); - -static inline -void mts_int_submit_urb (struct urb* transfer, - int pipe, - void* data, - unsigned length, - usb_complete_t callback ) -/* Interrupt context! */ - -/* Holding transfer->context->lock! */ -{ - int res; - - MTS_INT_INIT(); - - usb_fill_bulk_urb(transfer, - context->instance->usb_dev, - pipe, - data, - length, - callback, - context - ); - - res = usb_submit_urb( transfer, GFP_ATOMIC ); - if ( unlikely(res) ) { - MTS_INT_ERROR( "could not submit URB! Error was %d\n",(int)res ); - context->srb->result = DID_ERROR << 16; - mts_transfer_cleanup(transfer); - } -} - - -static void mts_transfer_cleanup( struct urb *transfer ) -/* Interrupt context! */ -{ - MTS_INT_INIT(); - - if ( likely(context->final_callback != NULL) ) - context->final_callback(context->srb); -} - -static void mts_transfer_done( struct urb *transfer ) -{ - MTS_INT_INIT(); - - context->srb->result &= MTS_SCSI_ERR_MASK; - context->srb->result |= (unsigned)(*context->scsi_status)<<1; - - mts_transfer_cleanup(transfer); -} - - -static void mts_get_status( struct urb *transfer ) -/* Interrupt context! */ -{ - MTS_INT_INIT(); - - mts_int_submit_urb(transfer, - usb_rcvbulkpipe(context->instance->usb_dev, - context->instance->ep_response), - context->scsi_status, - 1, - mts_transfer_done ); -} - -static void mts_data_done( struct urb* transfer ) -/* Interrupt context! */ -{ - int status = transfer->status; - MTS_INT_INIT(); - - if ( context->data_length != transfer->actual_length ) { - scsi_set_resid(context->srb, context->data_length - - transfer->actual_length); - } else if ( unlikely(status) ) { - context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16; - } - - mts_get_status(transfer); -} - - -static void mts_command_done( struct urb *transfer ) -/* Interrupt context! */ -{ - int status = transfer->status; - MTS_INT_INIT(); - - if ( unlikely(status) ) { - if (status == -ENOENT) { - /* We are being killed */ - MTS_DEBUG_GOT_HERE(); - context->srb->result = DID_ABORT<<16; - } else { - /* A genuine error has occurred */ - MTS_DEBUG_GOT_HERE(); - - context->srb->result = DID_ERROR<<16; - } - mts_transfer_cleanup(transfer); - - return; - } - - if (context->srb->cmnd[0] == REQUEST_SENSE) { - mts_int_submit_urb(transfer, - context->data_pipe, - context->srb->sense_buffer, - context->data_length, - mts_data_done); - } else { if ( context->data ) { - mts_int_submit_urb(transfer, - context->data_pipe, - context->data, - context->data_length, - scsi_sg_count(context->srb) > 1 ? - mts_do_sg : mts_data_done); - } else { - mts_get_status(transfer); - } - } -} - -static void mts_do_sg (struct urb* transfer) -{ - struct scatterlist * sg; - int status = transfer->status; - MTS_INT_INIT(); - - MTS_DEBUG("Processing fragment %d of %d\n", context->fragment, - scsi_sg_count(context->srb)); - - if (unlikely(status)) { - context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16; - mts_transfer_cleanup(transfer); - } - - sg = scsi_sglist(context->srb); - context->fragment++; - mts_int_submit_urb(transfer, - context->data_pipe, - sg_virt(&sg[context->fragment]), - sg[context->fragment].length, - context->fragment + 1 == scsi_sg_count(context->srb) ? - mts_data_done : mts_do_sg); -} - -static const u8 mts_read_image_sig[] = { 0x28, 00, 00, 00 }; -static const u8 mts_read_image_sig_len = 4; -static const unsigned char mts_direction[256/8] = { - 0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77, - 0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - - -#define MTS_DIRECTION_IS_IN(x) ((mts_direction[x>>3] >> (x & 7)) & 1) - -static void -mts_build_transfer_context(struct scsi_cmnd *srb, struct mts_desc* desc) -{ - int pipe; - struct scatterlist * sg; - - MTS_DEBUG_GOT_HERE(); - - desc->context.instance = desc; - desc->context.srb = srb; - desc->context.fragment = 0; - - if (!scsi_bufflen(srb)) { - desc->context.data = NULL; - desc->context.data_length = 0; - return; - } else { - sg = scsi_sglist(srb); - desc->context.data = sg_virt(&sg[0]); - desc->context.data_length = sg[0].length; - } - - - /* can't rely on srb->sc_data_direction */ - - /* Brutally ripped from usb-storage */ - - if ( !memcmp( srb->cmnd, mts_read_image_sig, mts_read_image_sig_len ) -) { pipe = usb_rcvbulkpipe(desc->usb_dev,desc->ep_image); - MTS_DEBUG( "transferring from desc->ep_image == %d\n", - (int)desc->ep_image ); - } else if ( MTS_DIRECTION_IS_IN(srb->cmnd[0]) ) { - pipe = usb_rcvbulkpipe(desc->usb_dev,desc->ep_response); - MTS_DEBUG( "transferring from desc->ep_response == %d\n", - (int)desc->ep_response); - } else { - MTS_DEBUG("transferring to desc->ep_out == %d\n", - (int)desc->ep_out); - pipe = usb_sndbulkpipe(desc->usb_dev,desc->ep_out); - } - desc->context.data_pipe = pipe; -} - - -static int -mts_scsi_queuecommand_lck(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback) -{ - struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]); - int err = 0; - int res; - - MTS_DEBUG_GOT_HERE(); - mts_show_command(srb); - mts_debug_dump(desc); - - if ( srb->device->lun || srb->device->id || srb->device->channel ) { - - MTS_DEBUG("Command to LUN=%d ID=%d CHANNEL=%d from SCSI layer\n",(int)srb->device->lun,(int)srb->device->id, (int)srb->device->channel ); - - MTS_DEBUG("this device doesn't exist\n"); - - srb->result = DID_BAD_TARGET << 16; - - if(likely(callback != NULL)) - callback(srb); - - goto out; - } - - - usb_fill_bulk_urb(desc->urb, - desc->usb_dev, - usb_sndbulkpipe(desc->usb_dev,desc->ep_out), - srb->cmnd, - srb->cmd_len, - mts_command_done, - &desc->context - ); - - - mts_build_transfer_context( srb, desc ); - desc->context.final_callback = callback; - - /* here we need ATOMIC as we are called with the iolock */ - res=usb_submit_urb(desc->urb, GFP_ATOMIC); - - if(unlikely(res)){ - MTS_ERROR("error %d submitting URB\n",(int)res); - srb->result = DID_ERROR << 16; - - if(likely(callback != NULL)) - callback(srb); - - } -out: - return err; -} - -static DEF_SCSI_QCMD(mts_scsi_queuecommand) - -static struct scsi_host_template mts_scsi_host_template = { - .module = THIS_MODULE, - .name = "microtekX6", - .proc_name = "microtekX6", - .queuecommand = mts_scsi_queuecommand, - .eh_abort_handler = mts_scsi_abort, - .eh_host_reset_handler = mts_scsi_host_reset, - .sg_tablesize = SG_ALL, - .can_queue = 1, - .this_id = -1, - .cmd_per_lun = 1, - .use_clustering = 1, - .emulated = 1, - .slave_alloc = mts_slave_alloc, - .slave_configure = mts_slave_configure, - .max_sectors= 256, /* 128 K */ -}; - -/* The entries of microtek_table must correspond, line-by-line to - the entries of mts_supported_products[]. */ - -static const struct usb_device_id mts_usb_ids[] = -{ - { USB_DEVICE(0x4ce, 0x0300) }, - { USB_DEVICE(0x5da, 0x0094) }, - { USB_DEVICE(0x5da, 0x0099) }, - { USB_DEVICE(0x5da, 0x009a) }, - { USB_DEVICE(0x5da, 0x00a0) }, - { USB_DEVICE(0x5da, 0x00a3) }, - { USB_DEVICE(0x5da, 0x80a3) }, - { USB_DEVICE(0x5da, 0x80ac) }, - { USB_DEVICE(0x5da, 0x00b6) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, mts_usb_ids); - - -static int mts_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - int i; - int ep_out = -1; - int ep_in_set[3]; /* this will break if we have more than three endpoints - which is why we check */ - int *ep_in_current = ep_in_set; - int err_retval = -ENOMEM; - - struct mts_desc * new_desc; - struct usb_device *dev = interface_to_usbdev (intf); - - /* the current altsetting on the interface we're probing */ - struct usb_host_interface *altsetting; - - MTS_DEBUG_GOT_HERE(); - MTS_DEBUG( "usb-device descriptor at %x\n", (int)dev ); - - MTS_DEBUG( "product id = 0x%x, vendor id = 0x%x\n", - le16_to_cpu(dev->descriptor.idProduct), - le16_to_cpu(dev->descriptor.idVendor) ); - - MTS_DEBUG_GOT_HERE(); - - /* the current altsetting on the interface we're probing */ - altsetting = intf->cur_altsetting; - - - /* Check if the config is sane */ - - if ( altsetting->desc.bNumEndpoints != MTS_EP_TOTAL ) { - MTS_WARNING( "expecting %d got %d endpoints! Bailing out.\n", - (int)MTS_EP_TOTAL, (int)altsetting->desc.bNumEndpoints ); - return -ENODEV; - } - - for( i = 0; i < altsetting->desc.bNumEndpoints; i++ ) { - if ((altsetting->endpoint[i].desc.bmAttributes & - USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) { - - MTS_WARNING( "can only deal with bulk endpoints; endpoint %d is not bulk.\n", - (int)altsetting->endpoint[i].desc.bEndpointAddress ); - } else { - if (altsetting->endpoint[i].desc.bEndpointAddress & - USB_DIR_IN) - *ep_in_current++ - = altsetting->endpoint[i].desc.bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK; - else { - if ( ep_out != -1 ) { - MTS_WARNING( "can only deal with one output endpoints. Bailing out." ); - return -ENODEV; - } - - ep_out = altsetting->endpoint[i].desc.bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK; - } - } - - } - - - if ( ep_out == -1 ) { - MTS_WARNING( "couldn't find an output bulk endpoint. Bailing out.\n" ); - return -ENODEV; - } - - - new_desc = kzalloc(sizeof(struct mts_desc), GFP_KERNEL); - if (!new_desc) - goto out; - - new_desc->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!new_desc->urb) - goto out_kfree; - - new_desc->context.scsi_status = kmalloc(1, GFP_KERNEL); - if (!new_desc->context.scsi_status) - goto out_free_urb; - - new_desc->usb_dev = dev; - new_desc->usb_intf = intf; - - /* endpoints */ - new_desc->ep_out = ep_out; - new_desc->ep_response = ep_in_set[0]; - new_desc->ep_image = ep_in_set[1]; - - if ( new_desc->ep_out != MTS_EP_OUT ) - MTS_WARNING( "will this work? Command EP is not usually %d\n", - (int)new_desc->ep_out ); - - if ( new_desc->ep_response != MTS_EP_RESPONSE ) - MTS_WARNING( "will this work? Response EP is not usually %d\n", - (int)new_desc->ep_response ); - - if ( new_desc->ep_image != MTS_EP_IMAGE ) - MTS_WARNING( "will this work? Image data EP is not usually %d\n", - (int)new_desc->ep_image ); - - new_desc->host = scsi_host_alloc(&mts_scsi_host_template, - sizeof(new_desc)); - if (!new_desc->host) - goto out_kfree2; - - new_desc->host->hostdata[0] = (unsigned long)new_desc; - if (scsi_add_host(new_desc->host, &dev->dev)) { - err_retval = -EIO; - goto out_host_put; - } - scsi_scan_host(new_desc->host); - - usb_set_intfdata(intf, new_desc); - return 0; - - out_host_put: - scsi_host_put(new_desc->host); - out_kfree2: - kfree(new_desc->context.scsi_status); - out_free_urb: - usb_free_urb(new_desc->urb); - out_kfree: - kfree(new_desc); - out: - return err_retval; -} - -static void mts_usb_disconnect (struct usb_interface *intf) -{ - struct mts_desc *desc = usb_get_intfdata(intf); - - usb_set_intfdata(intf, NULL); - - usb_kill_urb(desc->urb); - scsi_remove_host(desc->host); - - scsi_host_put(desc->host); - usb_free_urb(desc->urb); - kfree(desc->context.scsi_status); - kfree(desc); -} - -module_usb_driver(mts_usb_driver); - -MODULE_AUTHOR( DRIVER_AUTHOR ); -MODULE_DESCRIPTION( DRIVER_DESC ); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/image/microtek.h b/ANDROID_3.4.5/drivers/usb/image/microtek.h deleted file mode 100644 index ccce318f..00000000 --- a/ANDROID_3.4.5/drivers/usb/image/microtek.h +++ /dev/null @@ -1,54 +0,0 @@ - /* - * Driver for Microtek Scanmaker X6 USB scanner and possibly others. - * - * (C) Copyright 2000 John Fremlin - * (C) Copyright 2000 Oliver Neukum - * - * See microtek.c for history - * - */ - -typedef void (*mts_scsi_cmnd_callback)(struct scsi_cmnd *); - - -struct mts_transfer_context -{ - struct mts_desc* instance; - mts_scsi_cmnd_callback final_callback; - struct scsi_cmnd *srb; - - void* data; - unsigned data_length; - int data_pipe; - int fragment; - - u8 *scsi_status; /* status returned from ep_response after command completion */ -}; - - -struct mts_desc { - struct mts_desc *next; - struct mts_desc *prev; - - struct usb_device *usb_dev; - struct usb_interface *usb_intf; - - /* Endpoint addresses */ - u8 ep_out; - u8 ep_response; - u8 ep_image; - - struct Scsi_Host * host; - - struct urb *urb; - struct mts_transfer_context context; -}; - - -#define MTS_EP_OUT 0x1 -#define MTS_EP_RESPONSE 0x2 -#define MTS_EP_IMAGE 0x3 -#define MTS_EP_TOTAL 0x3 - -#define MTS_SCSI_ERR_MASK ~0x3fu - diff --git a/ANDROID_3.4.5/drivers/usb/misc/Kconfig b/ANDROID_3.4.5/drivers/usb/misc/Kconfig deleted file mode 100644 index 1bfcd02e..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/Kconfig +++ /dev/null @@ -1,246 +0,0 @@ -# -# USB Miscellaneous driver configuration -# -comment "USB Miscellaneous drivers" - depends on USB - -config USB_EMI62 - tristate "EMI 6|2m USB Audio interface support" - depends on USB - ---help--- - This driver loads firmware to Emagic EMI 6|2m low latency USB - Audio and Midi interface. - - After firmware load the device is handled with standard linux - USB Audio driver. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called audio. If you want to compile it as a - module, say M here and read . - -config USB_EMI26 - tristate "EMI 2|6 USB Audio interface support" - depends on USB - ---help--- - This driver loads firmware to Emagic EMI 2|6 low latency USB - Audio interface. - - After firmware load the device is handled with standard linux - USB Audio driver. - - To compile this driver as a module, choose M here: the - module will be called emi26. - -config USB_ADUTUX - tristate "ADU devices from Ontrak Control Systems" - depends on USB - help - Say Y if you want to use an ADU device from Ontrak Control - Systems. - - To compile this driver as a module, choose M here. The module - will be called adutux. - -config USB_SEVSEG - tristate "USB 7-Segment LED Display" - depends on USB - help - Say Y here if you have a USB 7-Segment Display by Delcom - - To compile this driver as a module, choose M here: the - module will be called usbsevseg. - -config USB_RIO500 - tristate "USB Diamond Rio500 support" - depends on USB - help - Say Y here if you want to connect a USB Rio500 mp3 player to your - computer's USB port. Please read - for more information. - - To compile this driver as a module, choose M here: the - module will be called rio500. - -config USB_LEGOTOWER - tristate "USB Lego Infrared Tower support" - depends on USB - help - Say Y here if you want to connect a USB Lego Infrared Tower to your - computer's USB port. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called legousbtower. If you want to compile it as - a module, say M here and read - . - -config USB_LCD - tristate "USB LCD driver support" - depends on USB - help - Say Y here if you want to connect an USBLCD to your computer's - USB port. The USBLCD is a small USB interface board for - alphanumeric LCD modules. See for more - information. - - To compile this driver as a module, choose M here: the - module will be called usblcd. - -config USB_LED - tristate "USB LED driver support" - depends on USB - help - Say Y here if you want to connect an USBLED device to your - computer's USB port. - - To compile this driver as a module, choose M here: the - module will be called usbled. - -config USB_CYPRESS_CY7C63 - tristate "Cypress CY7C63xxx USB driver support" - depends on USB - help - Say Y here if you want to connect a Cypress CY7C63xxx - micro controller to your computer's USB port. Currently this - driver supports the pre-programmed devices (incl. firmware) - by AK Modul-Bus Computer GmbH. - - Please see: http://www.ak-modul-bus.de/stat/mikrocontroller.html - - To compile this driver as a module, choose M here: the - module will be called cypress_cy7c63. - -config USB_CYTHERM - tristate "Cypress USB thermometer driver support" - depends on USB - help - Say Y here if you want to connect a Cypress USB thermometer - device to your computer's USB port. This device is also known - as the Cypress USB Starter kit or demo board. The Elektor - magazine published a modified version of this device in issue - #291. - - To compile this driver as a module, choose M here: the - module will be called cytherm. - -config USB_IDMOUSE - tristate "Siemens ID USB Mouse Fingerprint sensor support" - depends on USB - help - Say Y here if you want to use the fingerprint sensor on - the Siemens ID Mouse. There is also a Siemens ID Mouse - _Professional_, which has not been tested with this driver, - but uses the same sensor and may therefore work. - - This driver creates an entry "/dev/idmouseX" or "/dev/usb/idmouseX", - which can be used by, e.g.,"cat /dev/idmouse0 > fingerprint.pnm". - - See also . - -config USB_FTDI_ELAN - tristate "Elan PCMCIA CardBus Adapter USB Client" - depends on USB - default M - help - ELAN's Uxxx series of adapters are USB to PCMCIA CardBus adapters. - Currently only the U132 adapter is available. - - The U132 is specifically designed for CardBus PC cards that contain - an OHCI host controller. Typical PC cards are the Orange Mobile 3G - Option GlobeTrotter Fusion card. The U132 adapter will *NOT* work - with PC cards that do not contain an OHCI controller. To use a U132 - adapter you will need this "ftdi-elan" module as well as the "u132-hcd" - module which is a USB host controller driver that talks to the OHCI - controller within CardBus card that are inserted in the U132 adapter. - - This driver has been tested with a CardBus OHCI USB adapter, and - worked with a USB PEN Drive inserted into the first USB port of - the PCCARD. A rather pointless thing to do, but useful for testing. - - See also the USB_U132_HCD entry "Elan U132 Adapter Host Controller" - - It is safe to say M here. - -config USB_APPLEDISPLAY - tristate "Apple Cinema Display support" - depends on USB - select BACKLIGHT_LCD_SUPPORT - select BACKLIGHT_CLASS_DEVICE - help - Say Y here if you want to control the backlight of Apple Cinema - Displays over USB. This driver provides a sysfs interface. - -source "drivers/usb/misc/sisusbvga/Kconfig" - -config USB_LD - tristate "USB LD driver" - depends on USB - help - This driver is for generic USB devices that use interrupt transfers, - like LD Didactic's USB devices. - - To compile this driver as a module, choose M here: the - module will be called ldusb. - -config USB_TRANCEVIBRATOR - tristate "PlayStation 2 Trance Vibrator driver support" - depends on USB - help - Say Y here if you want to connect a PlayStation 2 Trance Vibrator - device to your computer's USB port. - - To compile this driver as a module, choose M here: the - module will be called trancevibrator. - -config USB_IOWARRIOR - tristate "IO Warrior driver support" - depends on USB - help - Say Y here if you want to support the IO Warrior devices from Code - Mercenaries. This includes support for the following devices: - IO Warrior 40 - IO Warrior 24 - IO Warrior 56 - IO Warrior 24 Power Vampire - - To compile this driver as a module, choose M here: the - module will be called iowarrior. - -config USB_TEST - tristate "USB testing driver" - depends on USB - help - This driver is for testing host controller software. It is used - with specialized device firmware for regression and stress testing, - to help prevent problems from cropping up with "real" drivers. - - See for more information, - including sample test device firmware and "how to use it". - -config USB_ISIGHTFW - tristate "iSight firmware loading support" - depends on USB - select FW_LOADER - help - This driver loads firmware for USB Apple iSight cameras, allowing - them to be driven by the USB video class driver available at - http://linux-uvc.berlios.de - - The firmware for this driver must be extracted from the MacOS - driver beforehand. Tools for doing so are available at - http://bersace03.free.fr - -config USB_YUREX - tristate "USB YUREX driver support" - depends on USB - help - Say Y here if you want to connect a YUREX to your computer's - USB port. The YUREX is a leg-shakes sensor. See - for further information. - This driver supports read/write of leg-shakes counter and - fasync for the counter update via a device file /dev/yurex*. - - To compile this driver as a module, choose M here: the - module will be called yurex. - diff --git a/ANDROID_3.4.5/drivers/usb/misc/Makefile b/ANDROID_3.4.5/drivers/usb/misc/Makefile deleted file mode 100644 index 796ce7eb..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/Makefile +++ /dev/null @@ -1,29 +0,0 @@ -# -# Makefile for the rest of the USB drivers -# (the ones that don't fit into any other categories) -# - -ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG - -obj-$(CONFIG_USB_ADUTUX) += adutux.o -obj-$(CONFIG_USB_APPLEDISPLAY) += appledisplay.o -obj-$(CONFIG_USB_CYPRESS_CY7C63) += cypress_cy7c63.o -obj-$(CONFIG_USB_CYTHERM) += cytherm.o -obj-$(CONFIG_USB_EMI26) += emi26.o -obj-$(CONFIG_USB_EMI62) += emi62.o -obj-$(CONFIG_USB_FTDI_ELAN) += ftdi-elan.o -obj-$(CONFIG_USB_IDMOUSE) += idmouse.o -obj-$(CONFIG_USB_IOWARRIOR) += iowarrior.o -obj-$(CONFIG_USB_ISIGHTFW) += isight_firmware.o -obj-$(CONFIG_USB_LCD) += usblcd.o -obj-$(CONFIG_USB_LD) += ldusb.o -obj-$(CONFIG_USB_LED) += usbled.o -obj-$(CONFIG_USB_LEGOTOWER) += legousbtower.o -obj-$(CONFIG_USB_RIO500) += rio500.o -obj-$(CONFIG_USB_TEST) += usbtest.o -obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o -obj-$(CONFIG_USB_USS720) += uss720.o -obj-$(CONFIG_USB_SEVSEG) += usbsevseg.o -obj-$(CONFIG_USB_YUREX) += yurex.o - -obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/ diff --git a/ANDROID_3.4.5/drivers/usb/misc/adutux.c b/ANDROID_3.4.5/drivers/usb/misc/adutux.c deleted file mode 100644 index 284b8546..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/adutux.c +++ /dev/null @@ -1,892 +0,0 @@ -/* - * adutux - driver for ADU devices from Ontrak Control Systems - * This is an experimental driver. Use at your own risk. - * This driver is not supported by Ontrak Control Systems. - * - * Copyright (c) 2003 John Homppi (SCO, leave this notice here) - * - * 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. - * - * derived from the Lego USB Tower driver 0.56: - * Copyright (c) 2003 David Glance - * 2001 Juergen Stuber - * that was derived from USB Skeleton driver - 0.5 - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_USB_DEBUG -static int debug = 5; -#else -static int debug = 1; -#endif - -/* Use our own dbg macro */ -#undef dbg -#define dbg(lvl, format, arg...) \ -do { \ - if (debug >= lvl) \ - printk(KERN_DEBUG "%s: " format "\n", __FILE__, ##arg); \ -} while (0) - - -/* Version Information */ -#define DRIVER_VERSION "v0.0.13" -#define DRIVER_AUTHOR "John Homppi" -#define DRIVER_DESC "adutux (see www.ontrak.net)" - -/* Module parameters */ -module_param(debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - -/* Define these values to match your device */ -#define ADU_VENDOR_ID 0x0a07 -#define ADU_PRODUCT_ID 0x0064 - -/* table of devices that work with this driver */ -static const struct usb_device_id device_table[] = { - { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID) }, /* ADU100 */ - { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+20) }, /* ADU120 */ - { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+30) }, /* ADU130 */ - { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+100) }, /* ADU200 */ - { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+108) }, /* ADU208 */ - { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+118) }, /* ADU218 */ - { }/* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, device_table); - -#ifdef CONFIG_USB_DYNAMIC_MINORS -#define ADU_MINOR_BASE 0 -#else -#define ADU_MINOR_BASE 67 -#endif - -/* we can have up to this number of device plugged in at once */ -#define MAX_DEVICES 16 - -#define COMMAND_TIMEOUT (2*HZ) /* 60 second timeout for a command */ - -/* - * The locking scheme is a vanilla 3-lock: - * adu_device.buflock: A spinlock, covers what IRQs touch. - * adutux_mutex: A Static lock to cover open_count. It would also cover - * any globals, but we don't have them in 2.6. - * adu_device.mtx: A mutex to hold across sleepers like copy_from_user. - * It covers all of adu_device, except the open_count - * and what .buflock covers. - */ - -/* Structure to hold all of our device specific stuff */ -struct adu_device { - struct mutex mtx; - struct usb_device* udev; /* save off the usb device pointer */ - struct usb_interface* interface; - unsigned int minor; /* the starting minor number for this device */ - char serial_number[8]; - - int open_count; /* number of times this port has been opened */ - - char* read_buffer_primary; - int read_buffer_length; - char* read_buffer_secondary; - int secondary_head; - int secondary_tail; - spinlock_t buflock; - - wait_queue_head_t read_wait; - wait_queue_head_t write_wait; - - char* interrupt_in_buffer; - struct usb_endpoint_descriptor* interrupt_in_endpoint; - struct urb* interrupt_in_urb; - int read_urb_finished; - - char* interrupt_out_buffer; - struct usb_endpoint_descriptor* interrupt_out_endpoint; - struct urb* interrupt_out_urb; - int out_urb_finished; -}; - -static DEFINE_MUTEX(adutux_mutex); - -static struct usb_driver adu_driver; - -static void adu_debug_data(int level, const char *function, int size, - const unsigned char *data) -{ - int i; - - if (debug < level) - return; - - printk(KERN_DEBUG "%s: %s - length = %d, data = ", - __FILE__, function, size); - for (i = 0; i < size; ++i) - printk("%.2x ", data[i]); - printk("\n"); -} - -/** - * adu_abort_transfers - * aborts transfers and frees associated data structures - */ -static void adu_abort_transfers(struct adu_device *dev) -{ - unsigned long flags; - - dbg(2," %s : enter", __func__); - - if (dev->udev == NULL) { - dbg(1," %s : udev is null", __func__); - goto exit; - } - - /* shutdown transfer */ - - /* XXX Anchor these instead */ - spin_lock_irqsave(&dev->buflock, flags); - if (!dev->read_urb_finished) { - spin_unlock_irqrestore(&dev->buflock, flags); - usb_kill_urb(dev->interrupt_in_urb); - } else - spin_unlock_irqrestore(&dev->buflock, flags); - - spin_lock_irqsave(&dev->buflock, flags); - if (!dev->out_urb_finished) { - spin_unlock_irqrestore(&dev->buflock, flags); - usb_kill_urb(dev->interrupt_out_urb); - } else - spin_unlock_irqrestore(&dev->buflock, flags); - -exit: - dbg(2," %s : leave", __func__); -} - -static void adu_delete(struct adu_device *dev) -{ - dbg(2, "%s enter", __func__); - - /* free data structures */ - usb_free_urb(dev->interrupt_in_urb); - usb_free_urb(dev->interrupt_out_urb); - kfree(dev->read_buffer_primary); - kfree(dev->read_buffer_secondary); - kfree(dev->interrupt_in_buffer); - kfree(dev->interrupt_out_buffer); - kfree(dev); - - dbg(2, "%s : leave", __func__); -} - -static void adu_interrupt_in_callback(struct urb *urb) -{ - struct adu_device *dev = urb->context; - int status = urb->status; - - dbg(4," %s : enter, status %d", __func__, status); - adu_debug_data(5, __func__, urb->actual_length, - urb->transfer_buffer); - - spin_lock(&dev->buflock); - - if (status != 0) { - if ((status != -ENOENT) && (status != -ECONNRESET) && - (status != -ESHUTDOWN)) { - dbg(1," %s : nonzero status received: %d", - __func__, status); - } - goto exit; - } - - if (urb->actual_length > 0 && dev->interrupt_in_buffer[0] != 0x00) { - if (dev->read_buffer_length < - (4 * usb_endpoint_maxp(dev->interrupt_in_endpoint)) - - (urb->actual_length)) { - memcpy (dev->read_buffer_primary + - dev->read_buffer_length, - dev->interrupt_in_buffer, urb->actual_length); - - dev->read_buffer_length += urb->actual_length; - dbg(2," %s reading %d ", __func__, - urb->actual_length); - } else { - dbg(1," %s : read_buffer overflow", __func__); - } - } - -exit: - dev->read_urb_finished = 1; - spin_unlock(&dev->buflock); - /* always wake up so we recover from errors */ - wake_up_interruptible(&dev->read_wait); - adu_debug_data(5, __func__, urb->actual_length, - urb->transfer_buffer); - dbg(4," %s : leave, status %d", __func__, status); -} - -static void adu_interrupt_out_callback(struct urb *urb) -{ - struct adu_device *dev = urb->context; - int status = urb->status; - - dbg(4," %s : enter, status %d", __func__, status); - adu_debug_data(5,__func__, urb->actual_length, urb->transfer_buffer); - - if (status != 0) { - if ((status != -ENOENT) && - (status != -ECONNRESET)) { - dbg(1, " %s :nonzero status received: %d", - __func__, status); - } - goto exit; - } - - spin_lock(&dev->buflock); - dev->out_urb_finished = 1; - wake_up(&dev->write_wait); - spin_unlock(&dev->buflock); -exit: - - adu_debug_data(5, __func__, urb->actual_length, - urb->transfer_buffer); - dbg(4," %s : leave, status %d", __func__, status); -} - -static int adu_open(struct inode *inode, struct file *file) -{ - struct adu_device *dev = NULL; - struct usb_interface *interface; - int subminor; - int retval; - - dbg(2,"%s : enter", __func__); - - subminor = iminor(inode); - - if ((retval = mutex_lock_interruptible(&adutux_mutex))) { - dbg(2, "%s : mutex lock failed", __func__); - goto exit_no_lock; - } - - interface = usb_find_interface(&adu_driver, subminor); - if (!interface) { - printk(KERN_ERR "adutux: %s - error, can't find device for " - "minor %d\n", __func__, subminor); - retval = -ENODEV; - goto exit_no_device; - } - - dev = usb_get_intfdata(interface); - if (!dev || !dev->udev) { - retval = -ENODEV; - goto exit_no_device; - } - - /* check that nobody else is using the device */ - if (dev->open_count) { - retval = -EBUSY; - goto exit_no_device; - } - - ++dev->open_count; - dbg(2,"%s : open count %d", __func__, dev->open_count); - - /* save device in the file's private structure */ - file->private_data = dev; - - /* initialize in direction */ - dev->read_buffer_length = 0; - - /* fixup first read by having urb waiting for it */ - usb_fill_int_urb(dev->interrupt_in_urb,dev->udev, - usb_rcvintpipe(dev->udev, - dev->interrupt_in_endpoint->bEndpointAddress), - dev->interrupt_in_buffer, - usb_endpoint_maxp(dev->interrupt_in_endpoint), - adu_interrupt_in_callback, dev, - dev->interrupt_in_endpoint->bInterval); - dev->read_urb_finished = 0; - if (usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL)) - dev->read_urb_finished = 1; - /* we ignore failure */ - /* end of fixup for first read */ - - /* initialize out direction */ - dev->out_urb_finished = 1; - - retval = 0; - -exit_no_device: - mutex_unlock(&adutux_mutex); -exit_no_lock: - dbg(2,"%s : leave, return value %d ", __func__, retval); - return retval; -} - -static void adu_release_internal(struct adu_device *dev) -{ - dbg(2," %s : enter", __func__); - - /* decrement our usage count for the device */ - --dev->open_count; - dbg(2," %s : open count %d", __func__, dev->open_count); - if (dev->open_count <= 0) { - adu_abort_transfers(dev); - dev->open_count = 0; - } - - dbg(2," %s : leave", __func__); -} - -static int adu_release(struct inode *inode, struct file *file) -{ - struct adu_device *dev; - int retval = 0; - - dbg(2," %s : enter", __func__); - - if (file == NULL) { - dbg(1," %s : file is NULL", __func__); - retval = -ENODEV; - goto exit; - } - - dev = file->private_data; - if (dev == NULL) { - dbg(1," %s : object is NULL", __func__); - retval = -ENODEV; - goto exit; - } - - mutex_lock(&adutux_mutex); /* not interruptible */ - - if (dev->open_count <= 0) { - dbg(1," %s : device not opened", __func__); - retval = -ENODEV; - goto unlock; - } - - adu_release_internal(dev); - if (dev->udev == NULL) { - /* the device was unplugged before the file was released */ - if (!dev->open_count) /* ... and we're the last user */ - adu_delete(dev); - } -unlock: - mutex_unlock(&adutux_mutex); -exit: - dbg(2," %s : leave, return value %d", __func__, retval); - return retval; -} - -static ssize_t adu_read(struct file *file, __user char *buffer, size_t count, - loff_t *ppos) -{ - struct adu_device *dev; - size_t bytes_read = 0; - size_t bytes_to_read = count; - int i; - int retval = 0; - int timeout = 0; - int should_submit = 0; - unsigned long flags; - DECLARE_WAITQUEUE(wait, current); - - dbg(2," %s : enter, count = %Zd, file=%p", __func__, count, file); - - dev = file->private_data; - dbg(2," %s : dev=%p", __func__, dev); - - if (mutex_lock_interruptible(&dev->mtx)) - return -ERESTARTSYS; - - /* verify that the device wasn't unplugged */ - if (dev->udev == NULL) { - retval = -ENODEV; - printk(KERN_ERR "adutux: No device or device unplugged %d\n", - retval); - goto exit; - } - - /* verify that some data was requested */ - if (count == 0) { - dbg(1," %s : read request of 0 bytes", __func__); - goto exit; - } - - timeout = COMMAND_TIMEOUT; - dbg(2," %s : about to start looping", __func__); - while (bytes_to_read) { - int data_in_secondary = dev->secondary_tail - dev->secondary_head; - dbg(2," %s : while, data_in_secondary=%d, status=%d", - __func__, data_in_secondary, - dev->interrupt_in_urb->status); - - if (data_in_secondary) { - /* drain secondary buffer */ - int amount = bytes_to_read < data_in_secondary ? bytes_to_read : data_in_secondary; - i = copy_to_user(buffer, dev->read_buffer_secondary+dev->secondary_head, amount); - if (i) { - retval = -EFAULT; - goto exit; - } - dev->secondary_head += (amount - i); - bytes_read += (amount - i); - bytes_to_read -= (amount - i); - if (i) { - retval = bytes_read ? bytes_read : -EFAULT; - goto exit; - } - } else { - /* we check the primary buffer */ - spin_lock_irqsave (&dev->buflock, flags); - if (dev->read_buffer_length) { - /* we secure access to the primary */ - char *tmp; - dbg(2," %s : swap, read_buffer_length = %d", - __func__, dev->read_buffer_length); - tmp = dev->read_buffer_secondary; - dev->read_buffer_secondary = dev->read_buffer_primary; - dev->read_buffer_primary = tmp; - dev->secondary_head = 0; - dev->secondary_tail = dev->read_buffer_length; - dev->read_buffer_length = 0; - spin_unlock_irqrestore(&dev->buflock, flags); - /* we have a free buffer so use it */ - should_submit = 1; - } else { - /* even the primary was empty - we may need to do IO */ - if (!dev->read_urb_finished) { - /* somebody is doing IO */ - spin_unlock_irqrestore(&dev->buflock, flags); - dbg(2," %s : submitted already", __func__); - } else { - /* we must initiate input */ - dbg(2," %s : initiate input", __func__); - dev->read_urb_finished = 0; - spin_unlock_irqrestore(&dev->buflock, flags); - - usb_fill_int_urb(dev->interrupt_in_urb,dev->udev, - usb_rcvintpipe(dev->udev, - dev->interrupt_in_endpoint->bEndpointAddress), - dev->interrupt_in_buffer, - usb_endpoint_maxp(dev->interrupt_in_endpoint), - adu_interrupt_in_callback, - dev, - dev->interrupt_in_endpoint->bInterval); - retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL); - if (retval) { - dev->read_urb_finished = 1; - if (retval == -ENOMEM) { - retval = bytes_read ? bytes_read : -ENOMEM; - } - dbg(2," %s : submit failed", __func__); - goto exit; - } - } - - /* we wait for I/O to complete */ - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&dev->read_wait, &wait); - spin_lock_irqsave(&dev->buflock, flags); - if (!dev->read_urb_finished) { - spin_unlock_irqrestore(&dev->buflock, flags); - timeout = schedule_timeout(COMMAND_TIMEOUT); - } else { - spin_unlock_irqrestore(&dev->buflock, flags); - set_current_state(TASK_RUNNING); - } - remove_wait_queue(&dev->read_wait, &wait); - - if (timeout <= 0) { - dbg(2," %s : timeout", __func__); - retval = bytes_read ? bytes_read : -ETIMEDOUT; - goto exit; - } - - if (signal_pending(current)) { - dbg(2," %s : signal pending", __func__); - retval = bytes_read ? bytes_read : -EINTR; - goto exit; - } - } - } - } - - retval = bytes_read; - /* if the primary buffer is empty then use it */ - spin_lock_irqsave(&dev->buflock, flags); - if (should_submit && dev->read_urb_finished) { - dev->read_urb_finished = 0; - spin_unlock_irqrestore(&dev->buflock, flags); - usb_fill_int_urb(dev->interrupt_in_urb,dev->udev, - usb_rcvintpipe(dev->udev, - dev->interrupt_in_endpoint->bEndpointAddress), - dev->interrupt_in_buffer, - usb_endpoint_maxp(dev->interrupt_in_endpoint), - adu_interrupt_in_callback, - dev, - dev->interrupt_in_endpoint->bInterval); - if (usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL) != 0) - dev->read_urb_finished = 1; - /* we ignore failure */ - } else { - spin_unlock_irqrestore(&dev->buflock, flags); - } - -exit: - /* unlock the device */ - mutex_unlock(&dev->mtx); - - dbg(2," %s : leave, return value %d", __func__, retval); - return retval; -} - -static ssize_t adu_write(struct file *file, const __user char *buffer, - size_t count, loff_t *ppos) -{ - DECLARE_WAITQUEUE(waita, current); - struct adu_device *dev; - size_t bytes_written = 0; - size_t bytes_to_write; - size_t buffer_size; - unsigned long flags; - int retval; - - dbg(2," %s : enter, count = %Zd", __func__, count); - - dev = file->private_data; - - retval = mutex_lock_interruptible(&dev->mtx); - if (retval) - goto exit_nolock; - - /* verify that the device wasn't unplugged */ - if (dev->udev == NULL) { - retval = -ENODEV; - printk(KERN_ERR "adutux: No device or device unplugged %d\n", - retval); - goto exit; - } - - /* verify that we actually have some data to write */ - if (count == 0) { - dbg(1," %s : write request of 0 bytes", __func__); - goto exit; - } - - while (count > 0) { - add_wait_queue(&dev->write_wait, &waita); - set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irqsave(&dev->buflock, flags); - if (!dev->out_urb_finished) { - spin_unlock_irqrestore(&dev->buflock, flags); - - mutex_unlock(&dev->mtx); - if (signal_pending(current)) { - dbg(1," %s : interrupted", __func__); - set_current_state(TASK_RUNNING); - retval = -EINTR; - goto exit_onqueue; - } - if (schedule_timeout(COMMAND_TIMEOUT) == 0) { - dbg(1, "%s - command timed out.", __func__); - retval = -ETIMEDOUT; - goto exit_onqueue; - } - remove_wait_queue(&dev->write_wait, &waita); - retval = mutex_lock_interruptible(&dev->mtx); - if (retval) { - retval = bytes_written ? bytes_written : retval; - goto exit_nolock; - } - - dbg(4," %s : in progress, count = %Zd", __func__, count); - } else { - spin_unlock_irqrestore(&dev->buflock, flags); - set_current_state(TASK_RUNNING); - remove_wait_queue(&dev->write_wait, &waita); - dbg(4," %s : sending, count = %Zd", __func__, count); - - /* write the data into interrupt_out_buffer from userspace */ - buffer_size = usb_endpoint_maxp(dev->interrupt_out_endpoint); - bytes_to_write = count > buffer_size ? buffer_size : count; - dbg(4," %s : buffer_size = %Zd, count = %Zd, bytes_to_write = %Zd", - __func__, buffer_size, count, bytes_to_write); - - if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write) != 0) { - retval = -EFAULT; - goto exit; - } - - /* send off the urb */ - usb_fill_int_urb( - dev->interrupt_out_urb, - dev->udev, - usb_sndintpipe(dev->udev, dev->interrupt_out_endpoint->bEndpointAddress), - dev->interrupt_out_buffer, - bytes_to_write, - adu_interrupt_out_callback, - dev, - dev->interrupt_out_endpoint->bInterval); - dev->interrupt_out_urb->actual_length = bytes_to_write; - dev->out_urb_finished = 0; - retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL); - if (retval < 0) { - dev->out_urb_finished = 1; - dev_err(&dev->udev->dev, "Couldn't submit " - "interrupt_out_urb %d\n", retval); - goto exit; - } - - buffer += bytes_to_write; - count -= bytes_to_write; - - bytes_written += bytes_to_write; - } - } - mutex_unlock(&dev->mtx); - return bytes_written; - -exit: - mutex_unlock(&dev->mtx); -exit_nolock: - dbg(2," %s : leave, return value %d", __func__, retval); - return retval; - -exit_onqueue: - remove_wait_queue(&dev->write_wait, &waita); - return retval; -} - -/* file operations needed when we register this driver */ -static const struct file_operations adu_fops = { - .owner = THIS_MODULE, - .read = adu_read, - .write = adu_write, - .open = adu_open, - .release = adu_release, - .llseek = noop_llseek, -}; - -/* - * usb class driver info in order to get a minor number from the usb core, - * and to have the device registered with devfs and the driver core - */ -static struct usb_class_driver adu_class = { - .name = "usb/adutux%d", - .fops = &adu_fops, - .minor_base = ADU_MINOR_BASE, -}; - -/** - * adu_probe - * - * Called by the usb core when a new device is connected that it thinks - * this driver might be interested in. - */ -static int adu_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(interface); - struct adu_device *dev = NULL; - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - int retval = -ENODEV; - int in_end_size; - int out_end_size; - int i; - - dbg(2," %s : enter", __func__); - - if (udev == NULL) { - dev_err(&interface->dev, "udev is NULL.\n"); - goto exit; - } - - /* allocate memory for our device state and initialize it */ - dev = kzalloc(sizeof(struct adu_device), GFP_KERNEL); - if (dev == NULL) { - dev_err(&interface->dev, "Out of memory\n"); - retval = -ENOMEM; - goto exit; - } - - mutex_init(&dev->mtx); - spin_lock_init(&dev->buflock); - dev->udev = udev; - init_waitqueue_head(&dev->read_wait); - init_waitqueue_head(&dev->write_wait); - - iface_desc = &interface->altsetting[0]; - - /* set up the endpoint information */ - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - - if (usb_endpoint_is_int_in(endpoint)) - dev->interrupt_in_endpoint = endpoint; - - if (usb_endpoint_is_int_out(endpoint)) - dev->interrupt_out_endpoint = endpoint; - } - if (dev->interrupt_in_endpoint == NULL) { - dev_err(&interface->dev, "interrupt in endpoint not found\n"); - goto error; - } - if (dev->interrupt_out_endpoint == NULL) { - dev_err(&interface->dev, "interrupt out endpoint not found\n"); - goto error; - } - - in_end_size = usb_endpoint_maxp(dev->interrupt_in_endpoint); - out_end_size = usb_endpoint_maxp(dev->interrupt_out_endpoint); - - dev->read_buffer_primary = kmalloc((4 * in_end_size), GFP_KERNEL); - if (!dev->read_buffer_primary) { - dev_err(&interface->dev, "Couldn't allocate read_buffer_primary\n"); - retval = -ENOMEM; - goto error; - } - - /* debug code prime the buffer */ - memset(dev->read_buffer_primary, 'a', in_end_size); - memset(dev->read_buffer_primary + in_end_size, 'b', in_end_size); - memset(dev->read_buffer_primary + (2 * in_end_size), 'c', in_end_size); - memset(dev->read_buffer_primary + (3 * in_end_size), 'd', in_end_size); - - dev->read_buffer_secondary = kmalloc((4 * in_end_size), GFP_KERNEL); - if (!dev->read_buffer_secondary) { - dev_err(&interface->dev, "Couldn't allocate read_buffer_secondary\n"); - retval = -ENOMEM; - goto error; - } - - /* debug code prime the buffer */ - memset(dev->read_buffer_secondary, 'e', in_end_size); - memset(dev->read_buffer_secondary + in_end_size, 'f', in_end_size); - memset(dev->read_buffer_secondary + (2 * in_end_size), 'g', in_end_size); - memset(dev->read_buffer_secondary + (3 * in_end_size), 'h', in_end_size); - - dev->interrupt_in_buffer = kmalloc(in_end_size, GFP_KERNEL); - if (!dev->interrupt_in_buffer) { - dev_err(&interface->dev, "Couldn't allocate interrupt_in_buffer\n"); - goto error; - } - - /* debug code prime the buffer */ - memset(dev->interrupt_in_buffer, 'i', in_end_size); - - dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->interrupt_in_urb) { - dev_err(&interface->dev, "Couldn't allocate interrupt_in_urb\n"); - goto error; - } - dev->interrupt_out_buffer = kmalloc(out_end_size, GFP_KERNEL); - if (!dev->interrupt_out_buffer) { - dev_err(&interface->dev, "Couldn't allocate interrupt_out_buffer\n"); - goto error; - } - dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->interrupt_out_urb) { - dev_err(&interface->dev, "Couldn't allocate interrupt_out_urb\n"); - goto error; - } - - if (!usb_string(udev, udev->descriptor.iSerialNumber, dev->serial_number, - sizeof(dev->serial_number))) { - dev_err(&interface->dev, "Could not retrieve serial number\n"); - goto error; - } - dbg(2," %s : serial_number=%s", __func__, dev->serial_number); - - /* we can register the device now, as it is ready */ - usb_set_intfdata(interface, dev); - - retval = usb_register_dev(interface, &adu_class); - - if (retval) { - /* something prevented us from registering this driver */ - dev_err(&interface->dev, "Not able to get a minor for this device.\n"); - usb_set_intfdata(interface, NULL); - goto error; - } - - dev->minor = interface->minor; - - /* let the user know what node this device is now attached to */ - dev_info(&interface->dev, "ADU%d %s now attached to /dev/usb/adutux%d\n", - udev->descriptor.idProduct, dev->serial_number, - (dev->minor - ADU_MINOR_BASE)); -exit: - dbg(2," %s : leave, return value %p (dev)", __func__, dev); - - return retval; - -error: - adu_delete(dev); - return retval; -} - -/** - * adu_disconnect - * - * Called by the usb core when the device is removed from the system. - */ -static void adu_disconnect(struct usb_interface *interface) -{ - struct adu_device *dev; - int minor; - - dbg(2," %s : enter", __func__); - - dev = usb_get_intfdata(interface); - - mutex_lock(&dev->mtx); /* not interruptible */ - dev->udev = NULL; /* poison */ - minor = dev->minor; - usb_deregister_dev(interface, &adu_class); - mutex_unlock(&dev->mtx); - - mutex_lock(&adutux_mutex); - usb_set_intfdata(interface, NULL); - - /* if the device is not opened, then we clean up right now */ - dbg(2," %s : open count %d", __func__, dev->open_count); - if (!dev->open_count) - adu_delete(dev); - - mutex_unlock(&adutux_mutex); - - dev_info(&interface->dev, "ADU device adutux%d now disconnected\n", - (minor - ADU_MINOR_BASE)); - - dbg(2," %s : leave", __func__); -} - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver adu_driver = { - .name = "adutux", - .probe = adu_probe, - .disconnect = adu_disconnect, - .id_table = device_table, -}; - -module_usb_driver(adu_driver); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/misc/appledisplay.c b/ANDROID_3.4.5/drivers/usb/misc/appledisplay.c deleted file mode 100644 index ac0d75a9..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/appledisplay.c +++ /dev/null @@ -1,381 +0,0 @@ -/* - * Apple Cinema Display driver - * - * Copyright (C) 2006 Michael Hanselmann (linux-kernel@hansmi.ch) - * - * Thanks to Caskey L. Dickson for his work with acdctl. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define APPLE_VENDOR_ID 0x05AC - -#define USB_REQ_GET_REPORT 0x01 -#define USB_REQ_SET_REPORT 0x09 - -#define ACD_USB_TIMEOUT 250 - -#define ACD_USB_EDID 0x0302 -#define ACD_USB_BRIGHTNESS 0x0310 - -#define ACD_BTN_NONE 0 -#define ACD_BTN_BRIGHT_UP 3 -#define ACD_BTN_BRIGHT_DOWN 4 - -#define ACD_URB_BUFFER_LEN 2 -#define ACD_MSG_BUFFER_LEN 2 - -#define APPLEDISPLAY_DEVICE(prod) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ - USB_DEVICE_ID_MATCH_INT_CLASS | \ - USB_DEVICE_ID_MATCH_INT_PROTOCOL, \ - .idVendor = APPLE_VENDOR_ID, \ - .idProduct = (prod), \ - .bInterfaceClass = USB_CLASS_HID, \ - .bInterfaceProtocol = 0x00 - -/* table of devices that work with this driver */ -static const struct usb_device_id appledisplay_table[] = { - { APPLEDISPLAY_DEVICE(0x9218) }, - { APPLEDISPLAY_DEVICE(0x9219) }, - { APPLEDISPLAY_DEVICE(0x921c) }, - { APPLEDISPLAY_DEVICE(0x921d) }, - - /* Terminating entry */ - { } -}; -MODULE_DEVICE_TABLE(usb, appledisplay_table); - -/* Structure to hold all of our device specific stuff */ -struct appledisplay { - struct usb_device *udev; /* usb device */ - struct urb *urb; /* usb request block */ - struct backlight_device *bd; /* backlight device */ - u8 *urbdata; /* interrupt URB data buffer */ - u8 *msgdata; /* control message data buffer */ - - struct delayed_work work; - int button_pressed; - spinlock_t lock; -}; - -static atomic_t count_displays = ATOMIC_INIT(0); -static struct workqueue_struct *wq; - -static void appledisplay_complete(struct urb *urb) -{ - struct appledisplay *pdata = urb->context; - unsigned long flags; - int status = urb->status; - int retval; - - switch (status) { - case 0: - /* success */ - break; - case -EOVERFLOW: - printk(KERN_ERR "appletouch: OVERFLOW with data " - "length %d, actual length is %d\n", - ACD_URB_BUFFER_LEN, pdata->urb->actual_length); - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* This urb is terminated, clean up */ - dbg("%s - urb shuttingdown with status: %d", - __func__, status); - return; - default: - dbg("%s - nonzero urb status received: %d", - __func__, status); - goto exit; - } - - spin_lock_irqsave(&pdata->lock, flags); - - switch(pdata->urbdata[1]) { - case ACD_BTN_BRIGHT_UP: - case ACD_BTN_BRIGHT_DOWN: - pdata->button_pressed = 1; - queue_delayed_work(wq, &pdata->work, 0); - break; - case ACD_BTN_NONE: - default: - pdata->button_pressed = 0; - break; - } - - spin_unlock_irqrestore(&pdata->lock, flags); - -exit: - retval = usb_submit_urb(pdata->urb, GFP_ATOMIC); - if (retval) { - dev_err(&pdata->udev->dev, - "%s - usb_submit_urb failed with result %d\n", - __func__, retval); - } -} - -static int appledisplay_bl_update_status(struct backlight_device *bd) -{ - struct appledisplay *pdata = bl_get_data(bd); - int retval; - - pdata->msgdata[0] = 0x10; - pdata->msgdata[1] = bd->props.brightness; - - retval = usb_control_msg( - pdata->udev, - usb_sndctrlpipe(pdata->udev, 0), - USB_REQ_SET_REPORT, - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - ACD_USB_BRIGHTNESS, - 0, - pdata->msgdata, 2, - ACD_USB_TIMEOUT); - - return retval; -} - -static int appledisplay_bl_get_brightness(struct backlight_device *bd) -{ - struct appledisplay *pdata = bl_get_data(bd); - int retval; - - retval = usb_control_msg( - pdata->udev, - usb_rcvctrlpipe(pdata->udev, 0), - USB_REQ_GET_REPORT, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - ACD_USB_BRIGHTNESS, - 0, - pdata->msgdata, 2, - ACD_USB_TIMEOUT); - - if (retval < 0) - return retval; - else - return pdata->msgdata[1]; -} - -static const struct backlight_ops appledisplay_bl_data = { - .get_brightness = appledisplay_bl_get_brightness, - .update_status = appledisplay_bl_update_status, -}; - -static void appledisplay_work(struct work_struct *work) -{ - struct appledisplay *pdata = - container_of(work, struct appledisplay, work.work); - int retval; - - retval = appledisplay_bl_get_brightness(pdata->bd); - if (retval >= 0) - pdata->bd->props.brightness = retval; - - /* Poll again in about 125ms if there's still a button pressed */ - if (pdata->button_pressed) - schedule_delayed_work(&pdata->work, HZ / 8); -} - -static int appledisplay_probe(struct usb_interface *iface, - const struct usb_device_id *id) -{ - struct backlight_properties props; - struct appledisplay *pdata; - struct usb_device *udev = interface_to_usbdev(iface); - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - int int_in_endpointAddr = 0; - int i, retval = -ENOMEM, brightness; - char bl_name[20]; - - /* set up the endpoint information */ - /* use only the first interrupt-in endpoint */ - iface_desc = iface->cur_altsetting; - for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { - endpoint = &iface_desc->endpoint[i].desc; - if (!int_in_endpointAddr && usb_endpoint_is_int_in(endpoint)) { - /* we found an interrupt in endpoint */ - int_in_endpointAddr = endpoint->bEndpointAddress; - break; - } - } - if (!int_in_endpointAddr) { - dev_err(&iface->dev, "Could not find int-in endpoint\n"); - return -EIO; - } - - /* allocate memory for our device state and initialize it */ - pdata = kzalloc(sizeof(struct appledisplay), GFP_KERNEL); - if (!pdata) { - retval = -ENOMEM; - dev_err(&iface->dev, "Out of memory\n"); - goto error; - } - - pdata->udev = udev; - - spin_lock_init(&pdata->lock); - INIT_DELAYED_WORK(&pdata->work, appledisplay_work); - - /* Allocate buffer for control messages */ - pdata->msgdata = kmalloc(ACD_MSG_BUFFER_LEN, GFP_KERNEL); - if (!pdata->msgdata) { - retval = -ENOMEM; - dev_err(&iface->dev, - "Allocating buffer for control messages failed\n"); - goto error; - } - - /* Allocate interrupt URB */ - pdata->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!pdata->urb) { - retval = -ENOMEM; - dev_err(&iface->dev, "Allocating URB failed\n"); - goto error; - } - - /* Allocate buffer for interrupt data */ - pdata->urbdata = usb_alloc_coherent(pdata->udev, ACD_URB_BUFFER_LEN, - GFP_KERNEL, &pdata->urb->transfer_dma); - if (!pdata->urbdata) { - retval = -ENOMEM; - dev_err(&iface->dev, "Allocating URB buffer failed\n"); - goto error; - } - - /* Configure interrupt URB */ - usb_fill_int_urb(pdata->urb, udev, - usb_rcvintpipe(udev, int_in_endpointAddr), - pdata->urbdata, ACD_URB_BUFFER_LEN, appledisplay_complete, - pdata, 1); - if (usb_submit_urb(pdata->urb, GFP_KERNEL)) { - retval = -EIO; - dev_err(&iface->dev, "Submitting URB failed\n"); - goto error; - } - - /* Register backlight device */ - snprintf(bl_name, sizeof(bl_name), "appledisplay%d", - atomic_inc_return(&count_displays) - 1); - memset(&props, 0, sizeof(struct backlight_properties)); - props.type = BACKLIGHT_RAW; - props.max_brightness = 0xff; - pdata->bd = backlight_device_register(bl_name, NULL, pdata, - &appledisplay_bl_data, &props); - if (IS_ERR(pdata->bd)) { - dev_err(&iface->dev, "Backlight registration failed\n"); - retval = PTR_ERR(pdata->bd); - goto error; - } - - /* Try to get brightness */ - brightness = appledisplay_bl_get_brightness(pdata->bd); - - if (brightness < 0) { - retval = brightness; - dev_err(&iface->dev, - "Error while getting initial brightness: %d\n", retval); - goto error; - } - - /* Set brightness in backlight device */ - pdata->bd->props.brightness = brightness; - - /* save our data pointer in the interface device */ - usb_set_intfdata(iface, pdata); - - printk(KERN_INFO "appledisplay: Apple Cinema Display connected\n"); - - return 0; - -error: - if (pdata) { - if (pdata->urb) { - usb_kill_urb(pdata->urb); - if (pdata->urbdata) - usb_free_coherent(pdata->udev, ACD_URB_BUFFER_LEN, - pdata->urbdata, pdata->urb->transfer_dma); - usb_free_urb(pdata->urb); - } - if (pdata->bd && !IS_ERR(pdata->bd)) - backlight_device_unregister(pdata->bd); - kfree(pdata->msgdata); - } - usb_set_intfdata(iface, NULL); - kfree(pdata); - return retval; -} - -static void appledisplay_disconnect(struct usb_interface *iface) -{ - struct appledisplay *pdata = usb_get_intfdata(iface); - - if (pdata) { - usb_kill_urb(pdata->urb); - cancel_delayed_work(&pdata->work); - backlight_device_unregister(pdata->bd); - usb_free_coherent(pdata->udev, ACD_URB_BUFFER_LEN, - pdata->urbdata, pdata->urb->transfer_dma); - usb_free_urb(pdata->urb); - kfree(pdata->msgdata); - kfree(pdata); - } - - printk(KERN_INFO "appledisplay: Apple Cinema Display disconnected\n"); -} - -static struct usb_driver appledisplay_driver = { - .name = "appledisplay", - .probe = appledisplay_probe, - .disconnect = appledisplay_disconnect, - .id_table = appledisplay_table, -}; - -static int __init appledisplay_init(void) -{ - wq = create_singlethread_workqueue("appledisplay"); - if (!wq) { - printk(KERN_ERR "appledisplay: Could not create work queue\n"); - return -ENOMEM; - } - - return usb_register(&appledisplay_driver); -} - -static void __exit appledisplay_exit(void) -{ - flush_workqueue(wq); - destroy_workqueue(wq); - usb_deregister(&appledisplay_driver); -} - -MODULE_AUTHOR("Michael Hanselmann"); -MODULE_DESCRIPTION("Apple Cinema Display driver"); -MODULE_LICENSE("GPL"); - -module_init(appledisplay_init); -module_exit(appledisplay_exit); diff --git a/ANDROID_3.4.5/drivers/usb/misc/cypress_cy7c63.c b/ANDROID_3.4.5/drivers/usb/misc/cypress_cy7c63.c deleted file mode 100644 index 3f7c1a92..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/cypress_cy7c63.c +++ /dev/null @@ -1,279 +0,0 @@ -/* -* cypress_cy7c63.c -* -* Copyright (c) 2006-2007 Oliver Bock (bock@tfh-berlin.de) -* -* This driver is based on the Cypress USB Driver by Marcus Maul -* (cyport) and the 2.0 version of Greg Kroah-Hartman's -* USB Skeleton driver. -* -* This is a generic driver for the Cypress CY7C63xxx family. -* For the time being it enables you to read from and write to -* the single I/O ports of the device. -* -* Supported vendors: AK Modul-Bus Computer GmbH -* (Firmware "Port-Chip") -* -* Supported devices: CY7C63001A-PC -* CY7C63001C-PXC -* CY7C63001C-SXC -* -* Supported functions: Read/Write Ports -* -* -* For up-to-date information please visit: -* http://www.obock.de/kernel/cypress -* -* 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, version 2. -*/ - -#include -#include -#include -#include -#include - -#define DRIVER_AUTHOR "Oliver Bock (bock@tfh-berlin.de)" -#define DRIVER_DESC "Cypress CY7C63xxx USB driver" - -#define CYPRESS_VENDOR_ID 0xa2c -#define CYPRESS_PRODUCT_ID 0x8 - -#define CYPRESS_READ_PORT 0x4 -#define CYPRESS_WRITE_PORT 0x5 - -#define CYPRESS_READ_RAM 0x2 -#define CYPRESS_WRITE_RAM 0x3 -#define CYPRESS_READ_ROM 0x1 - -#define CYPRESS_READ_PORT_ID0 0 -#define CYPRESS_WRITE_PORT_ID0 0 -#define CYPRESS_READ_PORT_ID1 0x2 -#define CYPRESS_WRITE_PORT_ID1 1 - -#define CYPRESS_MAX_REQSIZE 8 - - -/* table of devices that work with this driver */ -static const struct usb_device_id cypress_table[] = { - { USB_DEVICE(CYPRESS_VENDOR_ID, CYPRESS_PRODUCT_ID) }, - { } -}; -MODULE_DEVICE_TABLE(usb, cypress_table); - -/* structure to hold all of our device specific stuff */ -struct cypress { - struct usb_device * udev; - unsigned char port[2]; -}; - -/* used to send usb control messages to device */ -static int vendor_command(struct cypress *dev, unsigned char request, - unsigned char address, unsigned char data) -{ - int retval = 0; - unsigned int pipe; - unsigned char *iobuf; - - /* allocate some memory for the i/o buffer*/ - iobuf = kzalloc(CYPRESS_MAX_REQSIZE, GFP_KERNEL); - if (!iobuf) { - dev_err(&dev->udev->dev, "Out of memory!\n"); - retval = -ENOMEM; - goto error; - } - - dev_dbg(&dev->udev->dev, "Sending usb_control_msg (data: %d)\n", data); - - /* prepare usb control message and send it upstream */ - pipe = usb_rcvctrlpipe(dev->udev, 0); - retval = usb_control_msg(dev->udev, pipe, request, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER, - address, data, iobuf, CYPRESS_MAX_REQSIZE, - USB_CTRL_GET_TIMEOUT); - - /* store returned data (more READs to be added) */ - switch (request) { - case CYPRESS_READ_PORT: - if (address == CYPRESS_READ_PORT_ID0) { - dev->port[0] = iobuf[1]; - dev_dbg(&dev->udev->dev, - "READ_PORT0 returned: %d\n", - dev->port[0]); - } - else if (address == CYPRESS_READ_PORT_ID1) { - dev->port[1] = iobuf[1]; - dev_dbg(&dev->udev->dev, - "READ_PORT1 returned: %d\n", - dev->port[1]); - } - break; - } - - kfree(iobuf); -error: - return retval; -} - -/* write port value */ -static ssize_t write_port(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count, - int port_num, int write_id) -{ - int value = -1; - int result = 0; - - struct usb_interface *intf = to_usb_interface(dev); - struct cypress *cyp = usb_get_intfdata(intf); - - dev_dbg(&cyp->udev->dev, "WRITE_PORT%d called\n", port_num); - - /* validate input data */ - if (sscanf(buf, "%d", &value) < 1) { - result = -EINVAL; - goto error; - } - if (value < 0 || value > 255) { - result = -EINVAL; - goto error; - } - - result = vendor_command(cyp, CYPRESS_WRITE_PORT, write_id, - (unsigned char)value); - - dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n", result); -error: - return result < 0 ? result : count; -} - -/* attribute callback handler (write) */ -static ssize_t set_port0_handler(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - return write_port(dev, attr, buf, count, 0, CYPRESS_WRITE_PORT_ID0); -} - -/* attribute callback handler (write) */ -static ssize_t set_port1_handler(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - return write_port(dev, attr, buf, count, 1, CYPRESS_WRITE_PORT_ID1); -} - -/* read port value */ -static ssize_t read_port(struct device *dev, struct device_attribute *attr, - char *buf, int port_num, int read_id) -{ - int result = 0; - - struct usb_interface *intf = to_usb_interface(dev); - struct cypress *cyp = usb_get_intfdata(intf); - - dev_dbg(&cyp->udev->dev, "READ_PORT%d called\n", port_num); - - result = vendor_command(cyp, CYPRESS_READ_PORT, read_id, 0); - - dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n", result); - - return sprintf(buf, "%d", cyp->port[port_num]); -} - -/* attribute callback handler (read) */ -static ssize_t get_port0_handler(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return read_port(dev, attr, buf, 0, CYPRESS_READ_PORT_ID0); -} - -/* attribute callback handler (read) */ -static ssize_t get_port1_handler(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return read_port(dev, attr, buf, 1, CYPRESS_READ_PORT_ID1); -} - -static DEVICE_ATTR(port0, S_IRUGO | S_IWUSR, get_port0_handler, set_port0_handler); - -static DEVICE_ATTR(port1, S_IRUGO | S_IWUSR, get_port1_handler, set_port1_handler); - - -static int cypress_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct cypress *dev = NULL; - int retval = -ENOMEM; - - /* allocate memory for our device state and initialize it */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - dev_err(&interface->dev, "Out of memory!\n"); - goto error_mem; - } - - dev->udev = usb_get_dev(interface_to_usbdev(interface)); - - /* save our data pointer in this interface device */ - usb_set_intfdata(interface, dev); - - /* create device attribute files */ - retval = device_create_file(&interface->dev, &dev_attr_port0); - if (retval) - goto error; - retval = device_create_file(&interface->dev, &dev_attr_port1); - if (retval) - goto error; - - /* let the user know that the device is now attached */ - dev_info(&interface->dev, - "Cypress CY7C63xxx device now attached\n"); - return 0; - -error: - device_remove_file(&interface->dev, &dev_attr_port0); - device_remove_file(&interface->dev, &dev_attr_port1); - usb_set_intfdata(interface, NULL); - usb_put_dev(dev->udev); - kfree(dev); - -error_mem: - return retval; -} - -static void cypress_disconnect(struct usb_interface *interface) -{ - struct cypress *dev; - - dev = usb_get_intfdata(interface); - - /* remove device attribute files */ - device_remove_file(&interface->dev, &dev_attr_port0); - device_remove_file(&interface->dev, &dev_attr_port1); - /* the intfdata can be set to NULL only after the - * device files have been removed */ - usb_set_intfdata(interface, NULL); - - usb_put_dev(dev->udev); - - dev_info(&interface->dev, - "Cypress CY7C63xxx device now disconnected\n"); - - kfree(dev); -} - -static struct usb_driver cypress_driver = { - .name = "cypress_cy7c63", - .probe = cypress_probe, - .disconnect = cypress_disconnect, - .id_table = cypress_table, -}; - -module_usb_driver(cypress_driver); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); - -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/misc/cytherm.c b/ANDROID_3.4.5/drivers/usb/misc/cytherm.c deleted file mode 100644 index 5b9831b9..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/cytherm.c +++ /dev/null @@ -1,424 +0,0 @@ -/* -*- linux-c -*- - * Cypress USB Thermometer driver - * - * Copyright (c) 2004 Erik Rigtorp - * - * This driver works with Elektor magazine USB Interface as published in - * issue #291. It should also work with the original starter kit/demo board - * from Cypress. - * - * 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, version 2. - * - */ - - -#include -#include -#include -#include -#include -#include - -#define DRIVER_VERSION "v1.0" -#define DRIVER_AUTHOR "Erik Rigtorp" -#define DRIVER_DESC "Cypress USB Thermometer driver" - -#define USB_SKEL_VENDOR_ID 0x04b4 -#define USB_SKEL_PRODUCT_ID 0x0002 - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) }, - { } -}; -MODULE_DEVICE_TABLE (usb, id_table); - -/* Structure to hold all of our device specific stuff */ -struct usb_cytherm { - struct usb_device *udev; /* save off the usb device pointer */ - struct usb_interface *interface; /* the interface for this device */ - int brightness; -}; - - -/* local function prototypes */ -static int cytherm_probe(struct usb_interface *interface, - const struct usb_device_id *id); -static void cytherm_disconnect(struct usb_interface *interface); - - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver cytherm_driver = { - .name = "cytherm", - .probe = cytherm_probe, - .disconnect = cytherm_disconnect, - .id_table = id_table, -}; - -/* Vendor requests */ -/* They all operate on one byte at a time */ -#define PING 0x00 -#define READ_ROM 0x01 /* Reads form ROM, value = address */ -#define READ_RAM 0x02 /* Reads form RAM, value = address */ -#define WRITE_RAM 0x03 /* Write to RAM, value = address, index = data */ -#define READ_PORT 0x04 /* Reads from port, value = address */ -#define WRITE_PORT 0x05 /* Write to port, value = address, index = data */ - - -/* Send a vendor command to device */ -static int vendor_command(struct usb_device *dev, unsigned char request, - unsigned char value, unsigned char index, - void *buf, int size) -{ - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - request, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER, - value, - index, buf, size, - USB_CTRL_GET_TIMEOUT); -} - - - -#define BRIGHTNESS 0x2c /* RAM location for brightness value */ -#define BRIGHTNESS_SEM 0x2b /* RAM location for brightness semaphore */ - -static ssize_t show_brightness(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct usb_cytherm *cytherm = usb_get_intfdata(intf); - - return sprintf(buf, "%i", cytherm->brightness); -} - -static ssize_t set_brightness(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct usb_cytherm *cytherm = usb_get_intfdata(intf); - - unsigned char *buffer; - int retval; - - buffer = kmalloc(8, GFP_KERNEL); - if (!buffer) { - dev_err(&cytherm->udev->dev, "out of memory\n"); - return 0; - } - - cytherm->brightness = simple_strtoul(buf, NULL, 10); - - if (cytherm->brightness > 0xFF) - cytherm->brightness = 0xFF; - else if (cytherm->brightness < 0) - cytherm->brightness = 0; - - /* Set brightness */ - retval = vendor_command(cytherm->udev, WRITE_RAM, BRIGHTNESS, - cytherm->brightness, buffer, 8); - if (retval) - dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval); - /* Inform µC that we have changed the brightness setting */ - retval = vendor_command(cytherm->udev, WRITE_RAM, BRIGHTNESS_SEM, - 0x01, buffer, 8); - if (retval) - dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval); - - kfree(buffer); - - return count; -} - -static DEVICE_ATTR(brightness, S_IRUGO | S_IWUSR | S_IWGRP, - show_brightness, set_brightness); - - -#define TEMP 0x33 /* RAM location for temperature */ -#define SIGN 0x34 /* RAM location for temperature sign */ - -static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) -{ - - struct usb_interface *intf = to_usb_interface(dev); - struct usb_cytherm *cytherm = usb_get_intfdata(intf); - - int retval; - unsigned char *buffer; - - int temp, sign; - - buffer = kmalloc(8, GFP_KERNEL); - if (!buffer) { - dev_err(&cytherm->udev->dev, "out of memory\n"); - return 0; - } - - /* read temperature */ - retval = vendor_command(cytherm->udev, READ_RAM, TEMP, 0, buffer, 8); - if (retval) - dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval); - temp = buffer[1]; - - /* read sign */ - retval = vendor_command(cytherm->udev, READ_RAM, SIGN, 0, buffer, 8); - if (retval) - dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval); - sign = buffer[1]; - - kfree(buffer); - - return sprintf(buf, "%c%i.%i", sign ? '-' : '+', temp >> 1, - 5*(temp - ((temp >> 1) << 1))); -} - - -static ssize_t set_temp(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - return count; -} - -static DEVICE_ATTR(temp, S_IRUGO, show_temp, set_temp); - - -#define BUTTON 0x7a - -static ssize_t show_button(struct device *dev, struct device_attribute *attr, char *buf) -{ - - struct usb_interface *intf = to_usb_interface(dev); - struct usb_cytherm *cytherm = usb_get_intfdata(intf); - - int retval; - unsigned char *buffer; - - buffer = kmalloc(8, GFP_KERNEL); - if (!buffer) { - dev_err(&cytherm->udev->dev, "out of memory\n"); - return 0; - } - - /* check button */ - retval = vendor_command(cytherm->udev, READ_RAM, BUTTON, 0, buffer, 8); - if (retval) - dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval); - - retval = buffer[1]; - - kfree(buffer); - - if (retval) - return sprintf(buf, "1"); - else - return sprintf(buf, "0"); -} - - -static ssize_t set_button(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - return count; -} - -static DEVICE_ATTR(button, S_IRUGO, show_button, set_button); - - -static ssize_t show_port0(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct usb_cytherm *cytherm = usb_get_intfdata(intf); - - int retval; - unsigned char *buffer; - - buffer = kmalloc(8, GFP_KERNEL); - if (!buffer) { - dev_err(&cytherm->udev->dev, "out of memory\n"); - return 0; - } - - retval = vendor_command(cytherm->udev, READ_PORT, 0, 0, buffer, 8); - if (retval) - dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval); - - retval = buffer[1]; - - kfree(buffer); - - return sprintf(buf, "%d", retval); -} - - -static ssize_t set_port0(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct usb_cytherm *cytherm = usb_get_intfdata(intf); - - unsigned char *buffer; - int retval; - int tmp; - - buffer = kmalloc(8, GFP_KERNEL); - if (!buffer) { - dev_err(&cytherm->udev->dev, "out of memory\n"); - return 0; - } - - tmp = simple_strtoul(buf, NULL, 10); - - if (tmp > 0xFF) - tmp = 0xFF; - else if (tmp < 0) - tmp = 0; - - retval = vendor_command(cytherm->udev, WRITE_PORT, 0, - tmp, buffer, 8); - if (retval) - dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval); - - kfree(buffer); - - return count; -} - -static DEVICE_ATTR(port0, S_IRUGO | S_IWUSR | S_IWGRP, show_port0, set_port0); - -static ssize_t show_port1(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct usb_cytherm *cytherm = usb_get_intfdata(intf); - - int retval; - unsigned char *buffer; - - buffer = kmalloc(8, GFP_KERNEL); - if (!buffer) { - dev_err(&cytherm->udev->dev, "out of memory\n"); - return 0; - } - - retval = vendor_command(cytherm->udev, READ_PORT, 1, 0, buffer, 8); - if (retval) - dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval); - - retval = buffer[1]; - - kfree(buffer); - - return sprintf(buf, "%d", retval); -} - - -static ssize_t set_port1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct usb_cytherm *cytherm = usb_get_intfdata(intf); - - unsigned char *buffer; - int retval; - int tmp; - - buffer = kmalloc(8, GFP_KERNEL); - if (!buffer) { - dev_err(&cytherm->udev->dev, "out of memory\n"); - return 0; - } - - tmp = simple_strtoul(buf, NULL, 10); - - if (tmp > 0xFF) - tmp = 0xFF; - else if (tmp < 0) - tmp = 0; - - retval = vendor_command(cytherm->udev, WRITE_PORT, 1, - tmp, buffer, 8); - if (retval) - dev_dbg(&cytherm->udev->dev, "retval = %d\n", retval); - - kfree(buffer); - - return count; -} - -static DEVICE_ATTR(port1, S_IRUGO | S_IWUSR | S_IWGRP, show_port1, set_port1); - - - -static int cytherm_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(interface); - struct usb_cytherm *dev = NULL; - int retval = -ENOMEM; - - dev = kzalloc (sizeof(struct usb_cytherm), GFP_KERNEL); - if (dev == NULL) { - dev_err (&interface->dev, "Out of memory\n"); - goto error_mem; - } - - dev->udev = usb_get_dev(udev); - - usb_set_intfdata (interface, dev); - - dev->brightness = 0xFF; - - retval = device_create_file(&interface->dev, &dev_attr_brightness); - if (retval) - goto error; - retval = device_create_file(&interface->dev, &dev_attr_temp); - if (retval) - goto error; - retval = device_create_file(&interface->dev, &dev_attr_button); - if (retval) - goto error; - retval = device_create_file(&interface->dev, &dev_attr_port0); - if (retval) - goto error; - retval = device_create_file(&interface->dev, &dev_attr_port1); - if (retval) - goto error; - - dev_info (&interface->dev, - "Cypress thermometer device now attached\n"); - return 0; -error: - device_remove_file(&interface->dev, &dev_attr_brightness); - device_remove_file(&interface->dev, &dev_attr_temp); - device_remove_file(&interface->dev, &dev_attr_button); - device_remove_file(&interface->dev, &dev_attr_port0); - device_remove_file(&interface->dev, &dev_attr_port1); - usb_set_intfdata (interface, NULL); - usb_put_dev(dev->udev); - kfree(dev); -error_mem: - return retval; -} - -static void cytherm_disconnect(struct usb_interface *interface) -{ - struct usb_cytherm *dev; - - dev = usb_get_intfdata (interface); - - device_remove_file(&interface->dev, &dev_attr_brightness); - device_remove_file(&interface->dev, &dev_attr_temp); - device_remove_file(&interface->dev, &dev_attr_button); - device_remove_file(&interface->dev, &dev_attr_port0); - device_remove_file(&interface->dev, &dev_attr_port1); - - /* first remove the files, then NULL the pointer */ - usb_set_intfdata (interface, NULL); - - usb_put_dev(dev->udev); - - kfree(dev); - - dev_info(&interface->dev, "Cypress thermometer now disconnected\n"); -} - -module_usb_driver(cytherm_driver); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/misc/emi26.c b/ANDROID_3.4.5/drivers/usb/misc/emi26.c deleted file mode 100644 index da97dcec..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/emi26.c +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Emagic EMI 2|6 usb audio interface firmware loader. - * Copyright (C) 2002 - * Tapio Laxström (tapio.laxstrom@iptime.fi) - * - * 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, version 2. - * - * emi26.c,v 1.13 2002/03/08 13:10:26 tapio Exp - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define EMI26_VENDOR_ID 0x086a /* Emagic Soft-und Hardware GmBH */ -#define EMI26_PRODUCT_ID 0x0100 /* EMI 2|6 without firmware */ -#define EMI26B_PRODUCT_ID 0x0102 /* EMI 2|6 without firmware */ - -#define ANCHOR_LOAD_INTERNAL 0xA0 /* Vendor specific request code for Anchor Upload/Download (This one is implemented in the core) */ -#define ANCHOR_LOAD_EXTERNAL 0xA3 /* This command is not implemented in the core. Requires firmware */ -#define ANCHOR_LOAD_FPGA 0xA5 /* This command is not implemented in the core. Requires firmware. Emagic extension */ -#define MAX_INTERNAL_ADDRESS 0x1B3F /* This is the highest internal RAM address for the AN2131Q */ -#define CPUCS_REG 0x7F92 /* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */ -#define INTERNAL_RAM(address) (address <= MAX_INTERNAL_ADDRESS) - -static int emi26_writememory( struct usb_device *dev, int address, - const unsigned char *data, int length, - __u8 bRequest); -static int emi26_set_reset(struct usb_device *dev, unsigned char reset_bit); -static int emi26_load_firmware (struct usb_device *dev); -static int emi26_probe(struct usb_interface *intf, const struct usb_device_id *id); -static void emi26_disconnect(struct usb_interface *intf); - -/* thanks to drivers/usb/serial/keyspan_pda.c code */ -static int emi26_writememory (struct usb_device *dev, int address, - const unsigned char *data, int length, - __u8 request) -{ - int result; - unsigned char *buffer = kmemdup(data, length, GFP_KERNEL); - - if (!buffer) { - dev_err(&dev->dev, "kmalloc(%d) failed.\n", length); - return -ENOMEM; - } - /* Note: usb_control_msg returns negative value on error or length of the - * data that was written! */ - result = usb_control_msg (dev, usb_sndctrlpipe(dev, 0), request, 0x40, address, 0, buffer, length, 300); - kfree (buffer); - return result; -} - -/* thanks to drivers/usb/serial/keyspan_pda.c code */ -static int emi26_set_reset (struct usb_device *dev, unsigned char reset_bit) -{ - int response; - dev_info(&dev->dev, "%s - %d\n", __func__, reset_bit); - /* printk(KERN_DEBUG "%s - %d", __func__, reset_bit); */ - response = emi26_writememory (dev, CPUCS_REG, &reset_bit, 1, 0xa0); - if (response < 0) { - dev_err(&dev->dev, "set_reset (%d) failed\n", reset_bit); - } - return response; -} - -#define FW_LOAD_SIZE 1023 - -static int emi26_load_firmware (struct usb_device *dev) -{ - const struct firmware *loader_fw = NULL; - const struct firmware *bitstream_fw = NULL; - const struct firmware *firmware_fw = NULL; - const struct ihex_binrec *rec; - int err; - int i; - __u32 addr; /* Address to write */ - __u8 *buf; - - buf = kmalloc(FW_LOAD_SIZE, GFP_KERNEL); - if (!buf) { - dev_err(&dev->dev, "%s - error loading firmware: error = %d\n", - __func__, -ENOMEM); - err = -ENOMEM; - goto wraperr; - } - - err = request_ihex_firmware(&loader_fw, "emi26/loader.fw", &dev->dev); - if (err) - goto nofw; - - err = request_ihex_firmware(&bitstream_fw, "emi26/bitstream.fw", - &dev->dev); - if (err) - goto nofw; - - err = request_ihex_firmware(&firmware_fw, "emi26/firmware.fw", - &dev->dev); - if (err) { - nofw: - dev_err(&dev->dev, "%s - request_firmware() failed\n", - __func__); - goto wraperr; - } - - /* Assert reset (stop the CPU in the EMI) */ - err = emi26_set_reset(dev,1); - if (err < 0) { - dev_err(&dev->dev,"%s - error loading firmware: error = %d\n", - __func__, err); - goto wraperr; - } - - rec = (const struct ihex_binrec *)loader_fw->data; - /* 1. We need to put the loader for the FPGA into the EZ-USB */ - while (rec) { - err = emi26_writememory(dev, be32_to_cpu(rec->addr), - rec->data, be16_to_cpu(rec->len), - ANCHOR_LOAD_INTERNAL); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); - goto wraperr; - } - rec = ihex_next_binrec(rec); - } - - /* De-assert reset (let the CPU run) */ - err = emi26_set_reset(dev,0); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); - goto wraperr; - } - msleep(250); /* let device settle */ - - /* 2. We upload the FPGA firmware into the EMI - * Note: collect up to 1023 (yes!) bytes and send them with - * a single request. This is _much_ faster! */ - rec = (const struct ihex_binrec *)bitstream_fw->data; - do { - i = 0; - addr = be32_to_cpu(rec->addr); - - /* intel hex records are terminated with type 0 element */ - while (rec && (i + be16_to_cpu(rec->len) < FW_LOAD_SIZE)) { - memcpy(buf + i, rec->data, be16_to_cpu(rec->len)); - i += be16_to_cpu(rec->len); - rec = ihex_next_binrec(rec); - } - err = emi26_writememory(dev, addr, buf, i, ANCHOR_LOAD_FPGA); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); - goto wraperr; - } - } while (rec); - - /* Assert reset (stop the CPU in the EMI) */ - err = emi26_set_reset(dev,1); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); - goto wraperr; - } - - /* 3. We need to put the loader for the firmware into the EZ-USB (again...) */ - for (rec = (const struct ihex_binrec *)loader_fw->data; - rec; rec = ihex_next_binrec(rec)) { - err = emi26_writememory(dev, be32_to_cpu(rec->addr), - rec->data, be16_to_cpu(rec->len), - ANCHOR_LOAD_INTERNAL); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); - goto wraperr; - } - } - msleep(250); /* let device settle */ - - /* De-assert reset (let the CPU run) */ - err = emi26_set_reset(dev,0); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); - goto wraperr; - } - - /* 4. We put the part of the firmware that lies in the external RAM into the EZ-USB */ - - for (rec = (const struct ihex_binrec *)firmware_fw->data; - rec; rec = ihex_next_binrec(rec)) { - if (!INTERNAL_RAM(be32_to_cpu(rec->addr))) { - err = emi26_writememory(dev, be32_to_cpu(rec->addr), - rec->data, be16_to_cpu(rec->len), - ANCHOR_LOAD_EXTERNAL); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); - goto wraperr; - } - } - } - - /* Assert reset (stop the CPU in the EMI) */ - err = emi26_set_reset(dev,1); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); - goto wraperr; - } - - for (rec = (const struct ihex_binrec *)firmware_fw->data; - rec; rec = ihex_next_binrec(rec)) { - if (INTERNAL_RAM(be32_to_cpu(rec->addr))) { - err = emi26_writememory(dev, be32_to_cpu(rec->addr), - rec->data, be16_to_cpu(rec->len), - ANCHOR_LOAD_INTERNAL); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); - goto wraperr; - } - } - } - - /* De-assert reset (let the CPU run) */ - err = emi26_set_reset(dev,0); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); - goto wraperr; - } - msleep(250); /* let device settle */ - - /* return 1 to fail the driver inialization - * and give real driver change to load */ - err = 1; - -wraperr: - release_firmware(loader_fw); - release_firmware(bitstream_fw); - release_firmware(firmware_fw); - - kfree(buf); - return err; -} - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(EMI26_VENDOR_ID, EMI26_PRODUCT_ID) }, - { USB_DEVICE(EMI26_VENDOR_ID, EMI26B_PRODUCT_ID) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, id_table); - -static int emi26_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - - dev_info(&intf->dev, "%s start\n", __func__); - - emi26_load_firmware(dev); - - /* do not return the driver context, let real audio driver do that */ - return -EIO; -} - -static void emi26_disconnect(struct usb_interface *intf) -{ -} - -static struct usb_driver emi26_driver = { - .name = "emi26 - firmware loader", - .probe = emi26_probe, - .disconnect = emi26_disconnect, - .id_table = id_table, -}; - -module_usb_driver(emi26_driver); - -MODULE_AUTHOR("Tapio Laxström"); -MODULE_DESCRIPTION("Emagic EMI 2|6 firmware loader."); -MODULE_LICENSE("GPL"); - -MODULE_FIRMWARE("emi26/loader.fw"); -MODULE_FIRMWARE("emi26/bitstream.fw"); -MODULE_FIRMWARE("emi26/firmware.fw"); -/* vi:ai:syntax=c:sw=8:ts=8:tw=80 - */ diff --git a/ANDROID_3.4.5/drivers/usb/misc/emi62.c b/ANDROID_3.4.5/drivers/usb/misc/emi62.c deleted file mode 100644 index 4e0f167a..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/emi62.c +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Emagic EMI 2|6 usb audio interface firmware loader. - * Copyright (C) 2002 - * Tapio Laxström (tapio.laxstrom@iptime.fi) - * - * 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, version 2. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* include firmware (variables)*/ - -/* FIXME: This is quick and dirty solution! */ -#define SPDIF /* if you want SPDIF comment next line */ -//#undef SPDIF /* if you want MIDI uncomment this line */ - -#ifdef SPDIF -#define FIRMWARE_FW "emi62/spdif.fw" -#else -#define FIRMWARE_FW "emi62/midi.fw" -#endif - -#define EMI62_VENDOR_ID 0x086a /* Emagic Soft-und Hardware GmBH */ -#define EMI62_PRODUCT_ID 0x0110 /* EMI 6|2m without firmware */ - -#define ANCHOR_LOAD_INTERNAL 0xA0 /* Vendor specific request code for Anchor Upload/Download (This one is implemented in the core) */ -#define ANCHOR_LOAD_EXTERNAL 0xA3 /* This command is not implemented in the core. Requires firmware */ -#define ANCHOR_LOAD_FPGA 0xA5 /* This command is not implemented in the core. Requires firmware. Emagic extension */ -#define MAX_INTERNAL_ADDRESS 0x1B3F /* This is the highest internal RAM address for the AN2131Q */ -#define CPUCS_REG 0x7F92 /* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */ -#define INTERNAL_RAM(address) (address <= MAX_INTERNAL_ADDRESS) - -static int emi62_writememory(struct usb_device *dev, int address, - const unsigned char *data, int length, - __u8 bRequest); -static int emi62_set_reset(struct usb_device *dev, unsigned char reset_bit); -static int emi62_load_firmware (struct usb_device *dev); -static int emi62_probe(struct usb_interface *intf, const struct usb_device_id *id); -static void emi62_disconnect(struct usb_interface *intf); - -/* thanks to drivers/usb/serial/keyspan_pda.c code */ -static int emi62_writememory(struct usb_device *dev, int address, - const unsigned char *data, int length, - __u8 request) -{ - int result; - unsigned char *buffer = kmemdup(data, length, GFP_KERNEL); - - if (!buffer) { - err("emi62: kmalloc(%d) failed.", length); - return -ENOMEM; - } - /* Note: usb_control_msg returns negative value on error or length of the - * data that was written! */ - result = usb_control_msg (dev, usb_sndctrlpipe(dev, 0), request, 0x40, address, 0, buffer, length, 300); - kfree (buffer); - return result; -} - -/* thanks to drivers/usb/serial/keyspan_pda.c code */ -static int emi62_set_reset (struct usb_device *dev, unsigned char reset_bit) -{ - int response; - dev_info(&dev->dev, "%s - %d\n", __func__, reset_bit); - - response = emi62_writememory (dev, CPUCS_REG, &reset_bit, 1, 0xa0); - if (response < 0) { - err("emi62: set_reset (%d) failed", reset_bit); - } - return response; -} - -#define FW_LOAD_SIZE 1023 - -static int emi62_load_firmware (struct usb_device *dev) -{ - const struct firmware *loader_fw = NULL; - const struct firmware *bitstream_fw = NULL; - const struct firmware *firmware_fw = NULL; - const struct ihex_binrec *rec; - int err; - int i; - __u32 addr; /* Address to write */ - __u8 *buf; - - dev_dbg(&dev->dev, "load_firmware\n"); - buf = kmalloc(FW_LOAD_SIZE, GFP_KERNEL); - if (!buf) { - err( "%s - error loading firmware: error = %d", __func__, -ENOMEM); - err = -ENOMEM; - goto wraperr; - } - - err = request_ihex_firmware(&loader_fw, "emi62/loader.fw", &dev->dev); - if (err) - goto nofw; - - err = request_ihex_firmware(&bitstream_fw, "emi62/bitstream.fw", - &dev->dev); - if (err) - goto nofw; - - err = request_ihex_firmware(&firmware_fw, FIRMWARE_FW, &dev->dev); - if (err) { - nofw: - err( "%s - request_firmware() failed", __func__); - goto wraperr; - } - - /* Assert reset (stop the CPU in the EMI) */ - err = emi62_set_reset(dev,1); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); - goto wraperr; - } - - rec = (const struct ihex_binrec *)loader_fw->data; - - /* 1. We need to put the loader for the FPGA into the EZ-USB */ - while (rec) { - err = emi62_writememory(dev, be32_to_cpu(rec->addr), - rec->data, be16_to_cpu(rec->len), - ANCHOR_LOAD_INTERNAL); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); - goto wraperr; - } - rec = ihex_next_binrec(rec); - } - - /* De-assert reset (let the CPU run) */ - err = emi62_set_reset(dev,0); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); - goto wraperr; - } - msleep(250); /* let device settle */ - - /* 2. We upload the FPGA firmware into the EMI - * Note: collect up to 1023 (yes!) bytes and send them with - * a single request. This is _much_ faster! */ - rec = (const struct ihex_binrec *)bitstream_fw->data; - do { - i = 0; - addr = be32_to_cpu(rec->addr); - - /* intel hex records are terminated with type 0 element */ - while (rec && (i + be16_to_cpu(rec->len) < FW_LOAD_SIZE)) { - memcpy(buf + i, rec->data, be16_to_cpu(rec->len)); - i += be16_to_cpu(rec->len); - rec = ihex_next_binrec(rec); - } - err = emi62_writememory(dev, addr, buf, i, ANCHOR_LOAD_FPGA); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); - goto wraperr; - } - } while (rec); - - /* Assert reset (stop the CPU in the EMI) */ - err = emi62_set_reset(dev,1); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); - goto wraperr; - } - - /* 3. We need to put the loader for the firmware into the EZ-USB (again...) */ - for (rec = (const struct ihex_binrec *)loader_fw->data; - rec; rec = ihex_next_binrec(rec)) { - err = emi62_writememory(dev, be32_to_cpu(rec->addr), - rec->data, be16_to_cpu(rec->len), - ANCHOR_LOAD_INTERNAL); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); - goto wraperr; - } - } - - /* De-assert reset (let the CPU run) */ - err = emi62_set_reset(dev,0); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); - goto wraperr; - } - msleep(250); /* let device settle */ - - /* 4. We put the part of the firmware that lies in the external RAM into the EZ-USB */ - - for (rec = (const struct ihex_binrec *)firmware_fw->data; - rec; rec = ihex_next_binrec(rec)) { - if (!INTERNAL_RAM(be32_to_cpu(rec->addr))) { - err = emi62_writememory(dev, be32_to_cpu(rec->addr), - rec->data, be16_to_cpu(rec->len), - ANCHOR_LOAD_EXTERNAL); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); - goto wraperr; - } - } - } - - /* Assert reset (stop the CPU in the EMI) */ - err = emi62_set_reset(dev,1); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); - goto wraperr; - } - - for (rec = (const struct ihex_binrec *)firmware_fw->data; - rec; rec = ihex_next_binrec(rec)) { - if (INTERNAL_RAM(be32_to_cpu(rec->addr))) { - err = emi62_writememory(dev, be32_to_cpu(rec->addr), - rec->data, be16_to_cpu(rec->len), - ANCHOR_LOAD_EXTERNAL); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); - goto wraperr; - } - } - } - - /* De-assert reset (let the CPU run) */ - err = emi62_set_reset(dev,0); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); - goto wraperr; - } - msleep(250); /* let device settle */ - - release_firmware(loader_fw); - release_firmware(bitstream_fw); - release_firmware(firmware_fw); - - kfree(buf); - - /* return 1 to fail the driver inialization - * and give real driver change to load */ - return 1; - -wraperr: - release_firmware(loader_fw); - release_firmware(bitstream_fw); - release_firmware(firmware_fw); - - kfree(buf); - dev_err(&dev->dev, "Error\n"); - return err; -} - -static const struct usb_device_id id_table[] __devinitconst = { - { USB_DEVICE(EMI62_VENDOR_ID, EMI62_PRODUCT_ID) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, id_table); - -static int emi62_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - dev_dbg(&intf->dev, "emi62_probe\n"); - - dev_info(&intf->dev, "%s start\n", __func__); - - emi62_load_firmware(dev); - - /* do not return the driver context, let real audio driver do that */ - return -EIO; -} - -static void emi62_disconnect(struct usb_interface *intf) -{ -} - -static struct usb_driver emi62_driver = { - .name = "emi62 - firmware loader", - .probe = emi62_probe, - .disconnect = emi62_disconnect, - .id_table = id_table, -}; - -module_usb_driver(emi62_driver); - -MODULE_AUTHOR("Tapio Laxström"); -MODULE_DESCRIPTION("Emagic EMI 6|2m firmware loader."); -MODULE_LICENSE("GPL"); - -MODULE_FIRMWARE("emi62/loader.fw"); -MODULE_FIRMWARE("emi62/bitstream.fw"); -MODULE_FIRMWARE(FIRMWARE_FW); -/* vi:ai:syntax=c:sw=8:ts=8:tw=80 - */ diff --git a/ANDROID_3.4.5/drivers/usb/misc/ftdi-elan.c b/ANDROID_3.4.5/drivers/usb/misc/ftdi-elan.c deleted file mode 100644 index a4a3c7cd..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/ftdi-elan.c +++ /dev/null @@ -1,2946 +0,0 @@ -/* -* USB FTDI client driver for Elan Digital Systems's Uxxx adapters -* -* Copyright(C) 2006 Elan Digital Systems Limited -* http://www.elandigitalsystems.com -* -* Author and Maintainer - Tony Olech - Elan Digital Systems -* tony.olech@elandigitalsystems.com -* -* This program is free software;you can redistribute it and/or -* modify it under the terms of the GNU General Public License as -* published by the Free Software Foundation, version 2. -* -* -* This driver was written by Tony Olech(tony.olech@elandigitalsystems.com) -* based on various USB client drivers in the 2.6.15 linux kernel -* with constant reference to the 3rd Edition of Linux Device Drivers -* published by O'Reilly -* -* The U132 adapter is a USB to CardBus adapter specifically designed -* for PC cards that contain an OHCI host controller. Typical PC cards -* are the Orange Mobile 3G Option GlobeTrotter Fusion card. -* -* The U132 adapter will *NOT *work with PC cards that do not contain -* an OHCI controller. A simple way to test whether a PC card has an -* OHCI controller as an interface is to insert the PC card directly -* into a laptop(or desktop) with a CardBus slot and if "lspci" shows -* a new USB controller and "lsusb -v" shows a new OHCI Host Controller -* then there is a good chance that the U132 adapter will support the -* PC card.(you also need the specific client driver for the PC card) -* -* Please inform the Author and Maintainer about any PC cards that -* contain OHCI Host Controller and work when directly connected to -* an embedded CardBus slot but do not work when they are connected -* via an ELAN U132 adapter. -* -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -MODULE_AUTHOR("Tony Olech"); -MODULE_DESCRIPTION("FTDI ELAN driver"); -MODULE_LICENSE("GPL"); -#define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444) -static bool distrust_firmware = 1; -module_param(distrust_firmware, bool, 0); -MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren" - "t setup"); -extern struct platform_driver u132_platform_driver; -static struct workqueue_struct *status_queue; -static struct workqueue_struct *command_queue; -static struct workqueue_struct *respond_queue; -/* -* ftdi_module_lock exists to protect access to global variables -* -*/ -static struct mutex ftdi_module_lock; -static int ftdi_instances = 0; -static struct list_head ftdi_static_list; -/* -* end of the global variables protected by ftdi_module_lock -*/ -#include "usb_u132.h" -#include -#include - - /* FIXME ohci.h is ONLY for internal use by the OHCI driver. - * If you're going to try stuff like this, you need to split - * out shareable stuff (register declarations?) into its own - * file, maybe name - */ - -#include "../host/ohci.h" -/* Define these values to match your devices*/ -#define USB_FTDI_ELAN_VENDOR_ID 0x0403 -#define USB_FTDI_ELAN_PRODUCT_ID 0xd6ea -/* table of devices that work with this driver*/ -static const struct usb_device_id ftdi_elan_table[] = { - {USB_DEVICE(USB_FTDI_ELAN_VENDOR_ID, USB_FTDI_ELAN_PRODUCT_ID)}, - { /* Terminating entry */ } -}; - -MODULE_DEVICE_TABLE(usb, ftdi_elan_table); -/* only the jtag(firmware upgrade device) interface requires -* a device file and corresponding minor number, but the -* interface is created unconditionally - I suppose it could -* be configured or not according to a module parameter. -* But since we(now) require one interface per device, -* and since it unlikely that a normal installation would -* require more than a couple of elan-ftdi devices, 8 seems -* like a reasonable limit to have here, and if someone -* really requires more than 8 devices, then they can frig the -* code and recompile -*/ -#define USB_FTDI_ELAN_MINOR_BASE 192 -#define COMMAND_BITS 5 -#define COMMAND_SIZE (1<udev->dev, "FREEING ftdi=%p\n", ftdi); - usb_put_dev(ftdi->udev); - ftdi->disconnected += 1; - mutex_lock(&ftdi_module_lock); - list_del_init(&ftdi->ftdi_list); - ftdi_instances -= 1; - mutex_unlock(&ftdi_module_lock); - kfree(ftdi->bulk_in_buffer); - ftdi->bulk_in_buffer = NULL; -} - -static void ftdi_elan_put_kref(struct usb_ftdi *ftdi) -{ - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_elan_get_kref(struct usb_ftdi *ftdi) -{ - kref_get(&ftdi->kref); -} - -static void ftdi_elan_init_kref(struct usb_ftdi *ftdi) -{ - kref_init(&ftdi->kref); -} - -static void ftdi_status_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) -{ - if (!queue_delayed_work(status_queue, &ftdi->status_work, delta)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_status_queue_work(struct usb_ftdi *ftdi, unsigned int delta) -{ - if (queue_delayed_work(status_queue, &ftdi->status_work, delta)) - kref_get(&ftdi->kref); -} - -static void ftdi_status_cancel_work(struct usb_ftdi *ftdi) -{ - if (cancel_delayed_work(&ftdi->status_work)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_command_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) -{ - if (!queue_delayed_work(command_queue, &ftdi->command_work, delta)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_command_queue_work(struct usb_ftdi *ftdi, unsigned int delta) -{ - if (queue_delayed_work(command_queue, &ftdi->command_work, delta)) - kref_get(&ftdi->kref); -} - -static void ftdi_command_cancel_work(struct usb_ftdi *ftdi) -{ - if (cancel_delayed_work(&ftdi->command_work)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_response_requeue_work(struct usb_ftdi *ftdi, - unsigned int delta) -{ - if (!queue_delayed_work(respond_queue, &ftdi->respond_work, delta)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_respond_queue_work(struct usb_ftdi *ftdi, unsigned int delta) -{ - if (queue_delayed_work(respond_queue, &ftdi->respond_work, delta)) - kref_get(&ftdi->kref); -} - -static void ftdi_response_cancel_work(struct usb_ftdi *ftdi) -{ - if (cancel_delayed_work(&ftdi->respond_work)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -void ftdi_elan_gone_away(struct platform_device *pdev) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - ftdi->gone_away += 1; - ftdi_elan_put_kref(ftdi); -} - - -EXPORT_SYMBOL_GPL(ftdi_elan_gone_away); -static void ftdi_release_platform_dev(struct device *dev) -{ - dev->parent = NULL; -} - -static void ftdi_elan_do_callback(struct usb_ftdi *ftdi, - struct u132_target *target, u8 *buffer, int length); -static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi); -static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi); -static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi); -static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi); -static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi); -static int ftdi_elan_synchronize(struct usb_ftdi *ftdi); -static int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi); -static int ftdi_elan_command_engine(struct usb_ftdi *ftdi); -static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi); -static int ftdi_elan_hcd_init(struct usb_ftdi *ftdi) -{ - int result; - if (ftdi->platform_dev.dev.parent) - return -EBUSY; - ftdi_elan_get_kref(ftdi); - ftdi->platform_data.potpg = 100; - ftdi->platform_data.reset = NULL; - ftdi->platform_dev.id = ftdi->sequence_num; - ftdi->platform_dev.resource = ftdi->resources; - ftdi->platform_dev.num_resources = ARRAY_SIZE(ftdi->resources); - ftdi->platform_dev.dev.platform_data = &ftdi->platform_data; - ftdi->platform_dev.dev.parent = NULL; - ftdi->platform_dev.dev.release = ftdi_release_platform_dev; - ftdi->platform_dev.dev.dma_mask = NULL; - snprintf(ftdi->device_name, sizeof(ftdi->device_name), "u132_hcd"); - ftdi->platform_dev.name = ftdi->device_name; - dev_info(&ftdi->udev->dev, "requesting module '%s'\n", "u132_hcd"); - request_module("u132_hcd"); - dev_info(&ftdi->udev->dev, "registering '%s'\n", - ftdi->platform_dev.name); - result = platform_device_register(&ftdi->platform_dev); - return result; -} - -static void ftdi_elan_abandon_completions(struct usb_ftdi *ftdi) -{ - mutex_lock(&ftdi->u132_lock); - while (ftdi->respond_next > ftdi->respond_head) { - struct u132_respond *respond = &ftdi->respond[RESPOND_MASK & - ftdi->respond_head++]; - *respond->result = -ESHUTDOWN; - *respond->value = 0; - complete(&respond->wait_completion); - } mutex_unlock(&ftdi->u132_lock); -} - -static void ftdi_elan_abandon_targets(struct usb_ftdi *ftdi) -{ - int ed_number = 4; - mutex_lock(&ftdi->u132_lock); - while (ed_number-- > 0) { - struct u132_target *target = &ftdi->target[ed_number]; - if (target->active == 1) { - target->condition_code = TD_DEVNOTRESP; - mutex_unlock(&ftdi->u132_lock); - ftdi_elan_do_callback(ftdi, target, NULL, 0); - mutex_lock(&ftdi->u132_lock); - } - } - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - mutex_unlock(&ftdi->u132_lock); -} - -static void ftdi_elan_flush_targets(struct usb_ftdi *ftdi) -{ - int ed_number = 4; - mutex_lock(&ftdi->u132_lock); - while (ed_number-- > 0) { - struct u132_target *target = &ftdi->target[ed_number]; - target->abandoning = 1; - wait_1:if (target->active == 1) { - int command_size = ftdi->command_next - - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x80 | (ed_number << 5) | 0x4; - command->length = 0x00; - command->address = 0x00; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - mutex_lock(&ftdi->u132_lock); - goto wait_1; - } - } - wait_2:if (target->active == 1) { - int command_size = ftdi->command_next - - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x90 | (ed_number << 5); - command->length = 0x00; - command->address = 0x00; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - mutex_lock(&ftdi->u132_lock); - goto wait_2; - } - } - } - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - mutex_unlock(&ftdi->u132_lock); -} - -static void ftdi_elan_cancel_targets(struct usb_ftdi *ftdi) -{ - int ed_number = 4; - mutex_lock(&ftdi->u132_lock); - while (ed_number-- > 0) { - struct u132_target *target = &ftdi->target[ed_number]; - target->abandoning = 1; - wait:if (target->active == 1) { - int command_size = ftdi->command_next - - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x80 | (ed_number << 5) | 0x4; - command->length = 0x00; - command->address = 0x00; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - mutex_lock(&ftdi->u132_lock); - goto wait; - } - } - } - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - mutex_unlock(&ftdi->u132_lock); -} - -static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi) -{ - ftdi_command_queue_work(ftdi, 0); -} - -static void ftdi_elan_command_work(struct work_struct *work) -{ - struct usb_ftdi *ftdi = - container_of(work, struct usb_ftdi, command_work.work); - - if (ftdi->disconnected > 0) { - ftdi_elan_put_kref(ftdi); - return; - } else { - int retval = ftdi_elan_command_engine(ftdi); - if (retval == -ESHUTDOWN) { - ftdi->disconnected += 1; - } else if (retval == -ENODEV) { - ftdi->disconnected += 1; - } else if (retval) - dev_err(&ftdi->udev->dev, "command error %d\n", retval); - ftdi_command_requeue_work(ftdi, msecs_to_jiffies(10)); - return; - } -} - -static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi) -{ - ftdi_respond_queue_work(ftdi, 0); -} - -static void ftdi_elan_respond_work(struct work_struct *work) -{ - struct usb_ftdi *ftdi = - container_of(work, struct usb_ftdi, respond_work.work); - if (ftdi->disconnected > 0) { - ftdi_elan_put_kref(ftdi); - return; - } else { - int retval = ftdi_elan_respond_engine(ftdi); - if (retval == 0) { - } else if (retval == -ESHUTDOWN) { - ftdi->disconnected += 1; - } else if (retval == -ENODEV) { - ftdi->disconnected += 1; - } else if (retval == -EILSEQ) { - ftdi->disconnected += 1; - } else { - ftdi->disconnected += 1; - dev_err(&ftdi->udev->dev, "respond error %d\n", retval); - } - if (ftdi->disconnected > 0) { - ftdi_elan_abandon_completions(ftdi); - ftdi_elan_abandon_targets(ftdi); - } - ftdi_response_requeue_work(ftdi, msecs_to_jiffies(10)); - return; - } -} - - -/* -* the sw_lock is initially held and will be freed -* after the FTDI has been synchronized -* -*/ -static void ftdi_elan_status_work(struct work_struct *work) -{ - struct usb_ftdi *ftdi = - container_of(work, struct usb_ftdi, status_work.work); - int work_delay_in_msec = 0; - if (ftdi->disconnected > 0) { - ftdi_elan_put_kref(ftdi); - return; - } else if (ftdi->synchronized == 0) { - down(&ftdi->sw_lock); - if (ftdi_elan_synchronize(ftdi) == 0) { - ftdi->synchronized = 1; - ftdi_command_queue_work(ftdi, 1); - ftdi_respond_queue_work(ftdi, 1); - up(&ftdi->sw_lock); - work_delay_in_msec = 100; - } else { - dev_err(&ftdi->udev->dev, "synchronize failed\n"); - up(&ftdi->sw_lock); - work_delay_in_msec = 10 *1000; - } - } else if (ftdi->stuck_status > 0) { - if (ftdi_elan_stuck_waiting(ftdi) == 0) { - ftdi->stuck_status = 0; - ftdi->synchronized = 0; - } else if ((ftdi->stuck_status++ % 60) == 1) { - dev_err(&ftdi->udev->dev, "WRONG type of card inserted " - "- please remove\n"); - } else - dev_err(&ftdi->udev->dev, "WRONG type of card inserted " - "- checked %d times\n", ftdi->stuck_status); - work_delay_in_msec = 100; - } else if (ftdi->enumerated == 0) { - if (ftdi_elan_enumeratePCI(ftdi) == 0) { - ftdi->enumerated = 1; - work_delay_in_msec = 250; - } else - work_delay_in_msec = 1000; - } else if (ftdi->initialized == 0) { - if (ftdi_elan_setupOHCI(ftdi) == 0) { - ftdi->initialized = 1; - work_delay_in_msec = 500; - } else { - dev_err(&ftdi->udev->dev, "initialized failed - trying " - "again in 10 seconds\n"); - work_delay_in_msec = 1 *1000; - } - } else if (ftdi->registered == 0) { - work_delay_in_msec = 10; - if (ftdi_elan_hcd_init(ftdi) == 0) { - ftdi->registered = 1; - } else - dev_err(&ftdi->udev->dev, "register failed\n"); - work_delay_in_msec = 250; - } else { - if (ftdi_elan_checkingPCI(ftdi) == 0) { - work_delay_in_msec = 250; - } else if (ftdi->controlreg & 0x00400000) { - if (ftdi->gone_away > 0) { - dev_err(&ftdi->udev->dev, "PCI device eject con" - "firmed platform_dev.dev.parent=%p plat" - "form_dev.dev=%p\n", - ftdi->platform_dev.dev.parent, - &ftdi->platform_dev.dev); - platform_device_unregister(&ftdi->platform_dev); - ftdi->platform_dev.dev.parent = NULL; - ftdi->registered = 0; - ftdi->enumerated = 0; - ftdi->card_ejected = 0; - ftdi->initialized = 0; - ftdi->gone_away = 0; - } else - ftdi_elan_flush_targets(ftdi); - work_delay_in_msec = 250; - } else { - dev_err(&ftdi->udev->dev, "PCI device has disappeared\n" - ); - ftdi_elan_cancel_targets(ftdi); - work_delay_in_msec = 500; - ftdi->enumerated = 0; - ftdi->initialized = 0; - } - } - if (ftdi->disconnected > 0) { - ftdi_elan_put_kref(ftdi); - return; - } else { - ftdi_status_requeue_work(ftdi, - msecs_to_jiffies(work_delay_in_msec)); - return; - } -} - - -/* -* file_operations for the jtag interface -* -* the usage count for the device is incremented on open() -* and decremented on release() -*/ -static int ftdi_elan_open(struct inode *inode, struct file *file) -{ - int subminor; - struct usb_interface *interface; - - subminor = iminor(inode); - interface = usb_find_interface(&ftdi_elan_driver, subminor); - - if (!interface) { - printk(KERN_ERR "can't find device for minor %d\n", subminor); - return -ENODEV; - } else { - struct usb_ftdi *ftdi = usb_get_intfdata(interface); - if (!ftdi) { - return -ENODEV; - } else { - if (down_interruptible(&ftdi->sw_lock)) { - return -EINTR; - } else { - ftdi_elan_get_kref(ftdi); - file->private_data = ftdi; - return 0; - } - } - } -} - -static int ftdi_elan_release(struct inode *inode, struct file *file) -{ - struct usb_ftdi *ftdi = file->private_data; - if (ftdi == NULL) - return -ENODEV; - up(&ftdi->sw_lock); /* decrement the count on our device */ - ftdi_elan_put_kref(ftdi); - return 0; -} - - -/* -* -* blocking bulk reads are used to get data from the device -* -*/ -static ssize_t ftdi_elan_read(struct file *file, char __user *buffer, - size_t count, loff_t *ppos) -{ - char data[30 *3 + 4]; - char *d = data; - int m = (sizeof(data) - 1) / 3; - int bytes_read = 0; - int retry_on_empty = 10; - int retry_on_timeout = 5; - struct usb_ftdi *ftdi = file->private_data; - if (ftdi->disconnected > 0) { - return -ENODEV; - } - data[0] = 0; - have:if (ftdi->bulk_in_left > 0) { - if (count-- > 0) { - char *p = ++ftdi->bulk_in_last + ftdi->bulk_in_buffer; - ftdi->bulk_in_left -= 1; - if (bytes_read < m) { - d += sprintf(d, " %02X", 0x000000FF & *p); - } else if (bytes_read > m) { - } else - d += sprintf(d, " .."); - if (copy_to_user(buffer++, p, 1)) { - return -EFAULT; - } else { - bytes_read += 1; - goto have; - } - } else - return bytes_read; - } - more:if (count > 0) { - int packet_bytes = 0; - int retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 50); - if (packet_bytes > 2) { - ftdi->bulk_in_left = packet_bytes - 2; - ftdi->bulk_in_last = 1; - goto have; - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - goto more; - } else if (bytes_read > 0) { - return bytes_read; - } else - return retval; - } else if (retval == 0) { - if (retry_on_empty-- > 0) { - goto more; - } else - return bytes_read; - } else - return retval; - } else - return bytes_read; -} - -static void ftdi_elan_write_bulk_callback(struct urb *urb) -{ - struct usb_ftdi *ftdi = urb->context; - int status = urb->status; - - if (status && !(status == -ENOENT || status == -ECONNRESET || - status == -ESHUTDOWN)) { - dev_err(&ftdi->udev->dev, "urb=%p write bulk status received: %" - "d\n", urb, status); - } - usb_free_coherent(urb->dev, urb->transfer_buffer_length, - urb->transfer_buffer, urb->transfer_dma); -} - -static int fill_buffer_with_all_queued_commands(struct usb_ftdi *ftdi, - char *buf, int command_size, int total_size) -{ - int ed_commands = 0; - int b = 0; - int I = command_size; - int i = ftdi->command_head; - while (I-- > 0) { - struct u132_command *command = &ftdi->command[COMMAND_MASK & - i++]; - int F = command->follows; - u8 *f = command->buffer; - if (command->header & 0x80) { - ed_commands |= 1 << (0x3 & (command->header >> 5)); - } - buf[b++] = command->header; - buf[b++] = (command->length >> 0) & 0x00FF; - buf[b++] = (command->length >> 8) & 0x00FF; - buf[b++] = command->address; - buf[b++] = command->width; - while (F-- > 0) { - buf[b++] = *f++; - } - } - return ed_commands; -} - -static int ftdi_elan_total_command_size(struct usb_ftdi *ftdi, int command_size) -{ - int total_size = 0; - int I = command_size; - int i = ftdi->command_head; - while (I-- > 0) { - struct u132_command *command = &ftdi->command[COMMAND_MASK & - i++]; - total_size += 5 + command->follows; - } return total_size; -} - -static int ftdi_elan_command_engine(struct usb_ftdi *ftdi) -{ - int retval; - char *buf; - int ed_commands; - int total_size; - struct urb *urb; - int command_size = ftdi->command_next - ftdi->command_head; - if (command_size == 0) - return 0; - total_size = ftdi_elan_total_command_size(ftdi, command_size); - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - dev_err(&ftdi->udev->dev, "could not get a urb to write %d comm" - "ands totaling %d bytes to the Uxxx\n", command_size, - total_size); - return -ENOMEM; - } - buf = usb_alloc_coherent(ftdi->udev, total_size, GFP_KERNEL, - &urb->transfer_dma); - if (!buf) { - dev_err(&ftdi->udev->dev, "could not get a buffer to write %d c" - "ommands totaling %d bytes to the Uxxx\n", command_size, - total_size); - usb_free_urb(urb); - return -ENOMEM; - } - ed_commands = fill_buffer_with_all_queued_commands(ftdi, buf, - command_size, total_size); - usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, - ftdi->bulk_out_endpointAddr), buf, total_size, - ftdi_elan_write_bulk_callback, ftdi); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - if (ed_commands) { - char diag[40 *3 + 4]; - char *d = diag; - int m = total_size; - u8 *c = buf; - int s = (sizeof(diag) - 1) / 3; - diag[0] = 0; - while (s-- > 0 && m-- > 0) { - if (s > 0 || m == 0) { - d += sprintf(d, " %02X", *c++); - } else - d += sprintf(d, " .."); - } - } - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - dev_err(&ftdi->udev->dev, "failed %d to submit urb %p to write " - "%d commands totaling %d bytes to the Uxxx\n", retval, - urb, command_size, total_size); - usb_free_coherent(ftdi->udev, total_size, buf, urb->transfer_dma); - usb_free_urb(urb); - return retval; - } - usb_free_urb(urb); /* release our reference to this urb, - the USB core will eventually free it entirely */ - ftdi->command_head += command_size; - ftdi_elan_kick_respond_queue(ftdi); - return 0; -} - -static void ftdi_elan_do_callback(struct usb_ftdi *ftdi, - struct u132_target *target, u8 *buffer, int length) -{ - struct urb *urb = target->urb; - int halted = target->halted; - int skipped = target->skipped; - int actual = target->actual; - int non_null = target->non_null; - int toggle_bits = target->toggle_bits; - int error_count = target->error_count; - int condition_code = target->condition_code; - int repeat_number = target->repeat_number; - void (*callback) (void *, struct urb *, u8 *, int, int, int, int, int, - int, int, int, int) = target->callback; - target->active -= 1; - target->callback = NULL; - (*callback) (target->endp, urb, buffer, length, toggle_bits, - error_count, condition_code, repeat_number, halted, skipped, - actual, non_null); -} - -static char *have_ed_set_response(struct usb_ftdi *ftdi, - struct u132_target *target, u16 ed_length, int ed_number, int ed_type, - char *b) -{ - int payload = (ed_length >> 0) & 0x07FF; - mutex_lock(&ftdi->u132_lock); - target->actual = 0; - target->non_null = (ed_length >> 15) & 0x0001; - target->repeat_number = (ed_length >> 11) & 0x000F; - if (ed_type == 0x02) { - if (payload == 0 || target->abandoning > 0) { - target->abandoning = 0; - mutex_unlock(&ftdi->u132_lock); - ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, - payload); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - return ftdi->response; - } else { - ftdi->expected = 4 + payload; - ftdi->ed_found = 1; - mutex_unlock(&ftdi->u132_lock); - return b; - } - } else if (ed_type == 0x03) { - if (payload == 0 || target->abandoning > 0) { - target->abandoning = 0; - mutex_unlock(&ftdi->u132_lock); - ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, - payload); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - return ftdi->response; - } else { - ftdi->expected = 4 + payload; - ftdi->ed_found = 1; - mutex_unlock(&ftdi->u132_lock); - return b; - } - } else if (ed_type == 0x01) { - target->abandoning = 0; - mutex_unlock(&ftdi->u132_lock); - ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, - payload); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - return ftdi->response; - } else { - target->abandoning = 0; - mutex_unlock(&ftdi->u132_lock); - ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, - payload); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - return ftdi->response; - } -} - -static char *have_ed_get_response(struct usb_ftdi *ftdi, - struct u132_target *target, u16 ed_length, int ed_number, int ed_type, - char *b) -{ - mutex_lock(&ftdi->u132_lock); - target->condition_code = TD_DEVNOTRESP; - target->actual = (ed_length >> 0) & 0x01FF; - target->non_null = (ed_length >> 15) & 0x0001; - target->repeat_number = (ed_length >> 11) & 0x000F; - mutex_unlock(&ftdi->u132_lock); - if (target->active) - ftdi_elan_do_callback(ftdi, target, NULL, 0); - target->abandoning = 0; - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - return ftdi->response; -} - - -/* -* The engine tries to empty the FTDI fifo -* -* all responses found in the fifo data are dispatched thus -* the response buffer can only ever hold a maximum sized -* response from the Uxxx. -* -*/ -static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi) -{ - u8 *b = ftdi->response + ftdi->received; - int bytes_read = 0; - int retry_on_empty = 1; - int retry_on_timeout = 3; - int empty_packets = 0; - read:{ - int packet_bytes = 0; - int retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 500); - char diag[30 *3 + 4]; - char *d = diag; - int m = packet_bytes; - u8 *c = ftdi->bulk_in_buffer; - int s = (sizeof(diag) - 1) / 3; - diag[0] = 0; - while (s-- > 0 && m-- > 0) { - if (s > 0 || m == 0) { - d += sprintf(d, " %02X", *c++); - } else - d += sprintf(d, " .."); - } - if (packet_bytes > 2) { - ftdi->bulk_in_left = packet_bytes - 2; - ftdi->bulk_in_last = 1; - goto have; - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - dev_err(&ftdi->udev->dev, "TIMED OUT with packe" - "t_bytes = %d with total %d bytes%s\n", - packet_bytes, bytes_read, diag); - goto more; - } else if (bytes_read > 0) { - dev_err(&ftdi->udev->dev, "ONLY %d bytes%s\n", - bytes_read, diag); - return -ENOMEM; - } else { - dev_err(&ftdi->udev->dev, "TIMED OUT with packe" - "t_bytes = %d with total %d bytes%s\n", - packet_bytes, bytes_read, diag); - return -ENOMEM; - } - } else if (retval == -EILSEQ) { - dev_err(&ftdi->udev->dev, "error = %d with packet_bytes" - " = %d with total %d bytes%s\n", retval, - packet_bytes, bytes_read, diag); - return retval; - } else if (retval) { - dev_err(&ftdi->udev->dev, "error = %d with packet_bytes" - " = %d with total %d bytes%s\n", retval, - packet_bytes, bytes_read, diag); - return retval; - } else if (packet_bytes == 2) { - unsigned char s0 = ftdi->bulk_in_buffer[0]; - unsigned char s1 = ftdi->bulk_in_buffer[1]; - empty_packets += 1; - if (s0 == 0x31 && s1 == 0x60) { - if (retry_on_empty-- > 0) { - goto more; - } else - return 0; - } else if (s0 == 0x31 && s1 == 0x00) { - if (retry_on_empty-- > 0) { - goto more; - } else - return 0; - } else { - if (retry_on_empty-- > 0) { - goto more; - } else - return 0; - } - } else if (packet_bytes == 1) { - if (retry_on_empty-- > 0) { - goto more; - } else - return 0; - } else { - if (retry_on_empty-- > 0) { - goto more; - } else - return 0; - } - } - more:{ - goto read; - } - have:if (ftdi->bulk_in_left > 0) { - u8 c = ftdi->bulk_in_buffer[++ftdi->bulk_in_last]; - bytes_read += 1; - ftdi->bulk_in_left -= 1; - if (ftdi->received == 0 && c == 0xFF) { - goto have; - } else - *b++ = c; - if (++ftdi->received < ftdi->expected) { - goto have; - } else if (ftdi->ed_found) { - int ed_number = (ftdi->response[0] >> 5) & 0x03; - u16 ed_length = (ftdi->response[2] << 8) | - ftdi->response[1]; - struct u132_target *target = &ftdi->target[ed_number]; - int payload = (ed_length >> 0) & 0x07FF; - char diag[30 *3 + 4]; - char *d = diag; - int m = payload; - u8 *c = 4 + ftdi->response; - int s = (sizeof(diag) - 1) / 3; - diag[0] = 0; - while (s-- > 0 && m-- > 0) { - if (s > 0 || m == 0) { - d += sprintf(d, " %02X", *c++); - } else - d += sprintf(d, " .."); - } - ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, - payload); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - b = ftdi->response; - goto have; - } else if (ftdi->expected == 8) { - u8 buscmd; - int respond_head = ftdi->respond_head++; - struct u132_respond *respond = &ftdi->respond[ - RESPOND_MASK & respond_head]; - u32 data = ftdi->response[7]; - data <<= 8; - data |= ftdi->response[6]; - data <<= 8; - data |= ftdi->response[5]; - data <<= 8; - data |= ftdi->response[4]; - *respond->value = data; - *respond->result = 0; - complete(&respond->wait_completion); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - b = ftdi->response; - buscmd = (ftdi->response[0] >> 0) & 0x0F; - if (buscmd == 0x00) { - } else if (buscmd == 0x02) { - } else if (buscmd == 0x06) { - } else if (buscmd == 0x0A) { - } else - dev_err(&ftdi->udev->dev, "Uxxx unknown(%0X) va" - "lue = %08X\n", buscmd, data); - goto have; - } else { - if ((ftdi->response[0] & 0x80) == 0x00) { - ftdi->expected = 8; - goto have; - } else { - int ed_number = (ftdi->response[0] >> 5) & 0x03; - int ed_type = (ftdi->response[0] >> 0) & 0x03; - u16 ed_length = (ftdi->response[2] << 8) | - ftdi->response[1]; - struct u132_target *target = &ftdi->target[ - ed_number]; - target->halted = (ftdi->response[0] >> 3) & - 0x01; - target->skipped = (ftdi->response[0] >> 2) & - 0x01; - target->toggle_bits = (ftdi->response[3] >> 6) - & 0x03; - target->error_count = (ftdi->response[3] >> 4) - & 0x03; - target->condition_code = (ftdi->response[ - 3] >> 0) & 0x0F; - if ((ftdi->response[0] & 0x10) == 0x00) { - b = have_ed_set_response(ftdi, target, - ed_length, ed_number, ed_type, - b); - goto have; - } else { - b = have_ed_get_response(ftdi, target, - ed_length, ed_number, ed_type, - b); - goto have; - } - } - } - } else - goto more; -} - - -/* -* create a urb, and a buffer for it, and copy the data to the urb -* -*/ -static ssize_t ftdi_elan_write(struct file *file, - const char __user *user_buffer, size_t count, - loff_t *ppos) -{ - int retval = 0; - struct urb *urb; - char *buf; - struct usb_ftdi *ftdi = file->private_data; - - if (ftdi->disconnected > 0) { - return -ENODEV; - } - if (count == 0) { - goto exit; - } - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - retval = -ENOMEM; - goto error_1; - } - buf = usb_alloc_coherent(ftdi->udev, count, GFP_KERNEL, - &urb->transfer_dma); - if (!buf) { - retval = -ENOMEM; - goto error_2; - } - if (copy_from_user(buf, user_buffer, count)) { - retval = -EFAULT; - goto error_3; - } - usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, - ftdi->bulk_out_endpointAddr), buf, count, - ftdi_elan_write_bulk_callback, ftdi); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - dev_err(&ftdi->udev->dev, "failed submitting write urb, error %" - "d\n", retval); - goto error_3; - } - usb_free_urb(urb); - -exit: - return count; -error_3: - usb_free_coherent(ftdi->udev, count, buf, urb->transfer_dma); -error_2: - usb_free_urb(urb); -error_1: - return retval; -} - -static const struct file_operations ftdi_elan_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = ftdi_elan_read, - .write = ftdi_elan_write, - .open = ftdi_elan_open, - .release = ftdi_elan_release, -}; - -/* -* usb class driver info in order to get a minor number from the usb core, -* and to have the device registered with the driver core -*/ -static struct usb_class_driver ftdi_elan_jtag_class = { - .name = "ftdi-%d-jtag", - .fops = &ftdi_elan_fops, - .minor_base = USB_FTDI_ELAN_MINOR_BASE, -}; - -/* -* the following definitions are for the -* ELAN FPGA state machgine processor that -* lies on the other side of the FTDI chip -*/ -#define cPCIu132rd 0x0 -#define cPCIu132wr 0x1 -#define cPCIiord 0x2 -#define cPCIiowr 0x3 -#define cPCImemrd 0x6 -#define cPCImemwr 0x7 -#define cPCIcfgrd 0xA -#define cPCIcfgwr 0xB -#define cPCInull 0xF -#define cU132cmd_status 0x0 -#define cU132flash 0x1 -#define cPIDsetup 0x0 -#define cPIDout 0x1 -#define cPIDin 0x2 -#define cPIDinonce 0x3 -#define cCCnoerror 0x0 -#define cCCcrc 0x1 -#define cCCbitstuff 0x2 -#define cCCtoggle 0x3 -#define cCCstall 0x4 -#define cCCnoresp 0x5 -#define cCCbadpid1 0x6 -#define cCCbadpid2 0x7 -#define cCCdataoverrun 0x8 -#define cCCdataunderrun 0x9 -#define cCCbuffoverrun 0xC -#define cCCbuffunderrun 0xD -#define cCCnotaccessed 0xF -static int ftdi_elan_write_reg(struct usb_ftdi *ftdi, u32 data) -{ - wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x00 | cPCIu132wr; - command->length = 0x04; - command->address = 0x00; - command->width = 0x00; - command->follows = 4; - command->value = data; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -static int ftdi_elan_write_config(struct usb_ftdi *ftdi, int config_offset, - u8 width, u32 data) -{ - u8 addressofs = config_offset / 4; - wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x00 | (cPCIcfgwr & 0x0F); - command->length = 0x04; - command->address = addressofs; - command->width = 0x00 | (width & 0x0F); - command->follows = 4; - command->value = data; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -static int ftdi_elan_write_pcimem(struct usb_ftdi *ftdi, int mem_offset, - u8 width, u32 data) -{ - u8 addressofs = mem_offset / 4; - wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x00 | (cPCImemwr & 0x0F); - command->length = 0x04; - command->address = addressofs; - command->width = 0x00 | (width & 0x0F); - command->follows = 4; - command->value = data; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_write_pcimem(struct platform_device *pdev, int mem_offset, - u8 width, u32 data) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_write_pcimem(ftdi, mem_offset, width, data); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_write_pcimem); -static int ftdi_elan_read_reg(struct usb_ftdi *ftdi, u32 *data) -{ - wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - int respond_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - respond_size = ftdi->respond_next - ftdi->respond_head; - if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) - { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - struct u132_respond *respond = &ftdi->respond[ - RESPOND_MASK & ftdi->respond_next]; - int result = -ENODEV; - respond->result = &result; - respond->header = command->header = 0x00 | cPCIu132rd; - command->length = 0x04; - respond->address = command->address = cU132cmd_status; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = NULL; - respond->value = data; - init_completion(&respond->wait_completion); - ftdi->command_next += 1; - ftdi->respond_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - wait_for_completion(&respond->wait_completion); - return result; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -static int ftdi_elan_read_config(struct usb_ftdi *ftdi, int config_offset, - u8 width, u32 *data) -{ - u8 addressofs = config_offset / 4; - wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - int respond_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - respond_size = ftdi->respond_next - ftdi->respond_head; - if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) - { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - struct u132_respond *respond = &ftdi->respond[ - RESPOND_MASK & ftdi->respond_next]; - int result = -ENODEV; - respond->result = &result; - respond->header = command->header = 0x00 | (cPCIcfgrd & - 0x0F); - command->length = 0x04; - respond->address = command->address = addressofs; - command->width = 0x00 | (width & 0x0F); - command->follows = 0; - command->value = 0; - command->buffer = NULL; - respond->value = data; - init_completion(&respond->wait_completion); - ftdi->command_next += 1; - ftdi->respond_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - wait_for_completion(&respond->wait_completion); - return result; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -static int ftdi_elan_read_pcimem(struct usb_ftdi *ftdi, int mem_offset, - u8 width, u32 *data) -{ - u8 addressofs = mem_offset / 4; - wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - int respond_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - respond_size = ftdi->respond_next - ftdi->respond_head; - if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) - { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - struct u132_respond *respond = &ftdi->respond[ - RESPOND_MASK & ftdi->respond_next]; - int result = -ENODEV; - respond->result = &result; - respond->header = command->header = 0x00 | (cPCImemrd & - 0x0F); - command->length = 0x04; - respond->address = command->address = addressofs; - command->width = 0x00 | (width & 0x0F); - command->follows = 0; - command->value = 0; - command->buffer = NULL; - respond->value = data; - init_completion(&respond->wait_completion); - ftdi->command_next += 1; - ftdi->respond_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - wait_for_completion(&respond->wait_completion); - return result; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_read_pcimem(struct platform_device *pdev, int mem_offset, - u8 width, u32 *data) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - if (ftdi->initialized == 0) { - return -ENODEV; - } else - return ftdi_elan_read_pcimem(ftdi, mem_offset, width, data); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_read_pcimem); -static int ftdi_elan_edset_setup(struct usb_ftdi *ftdi, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - u8 ed = ed_number - 1; - wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_target *target = &ftdi->target[ed]; - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x80 | (ed << 5); - command->length = 0x8007; - command->address = (toggle_bits << 6) | (ep_number << 2) - | (address << 0); - command->width = usb_maxpacket(urb->dev, urb->pipe, - usb_pipeout(urb->pipe)); - command->follows = 8; - command->value = 0; - command->buffer = urb->setup_packet; - target->callback = callback; - target->endp = endp; - target->urb = urb; - target->active = 1; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_edset_setup(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_setup(ftdi, ed_number, endp, urb, address, - ep_number, toggle_bits, callback); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_setup); -static int ftdi_elan_edset_input(struct usb_ftdi *ftdi, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - u8 ed = ed_number - 1; - wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_target *target = &ftdi->target[ed]; - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - u32 remaining_length = urb->transfer_buffer_length - - urb->actual_length; - command->header = 0x82 | (ed << 5); - if (remaining_length == 0) { - command->length = 0x0000; - } else if (remaining_length > 1024) { - command->length = 0x8000 | 1023; - } else - command->length = 0x8000 | (remaining_length - - 1); - command->address = (toggle_bits << 6) | (ep_number << 2) - | (address << 0); - command->width = usb_maxpacket(urb->dev, urb->pipe, - usb_pipeout(urb->pipe)); - command->follows = 0; - command->value = 0; - command->buffer = NULL; - target->callback = callback; - target->endp = endp; - target->urb = urb; - target->active = 1; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_edset_input(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_input(ftdi, ed_number, endp, urb, address, - ep_number, toggle_bits, callback); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_input); -static int ftdi_elan_edset_empty(struct usb_ftdi *ftdi, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - u8 ed = ed_number - 1; - wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_target *target = &ftdi->target[ed]; - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x81 | (ed << 5); - command->length = 0x0000; - command->address = (toggle_bits << 6) | (ep_number << 2) - | (address << 0); - command->width = usb_maxpacket(urb->dev, urb->pipe, - usb_pipeout(urb->pipe)); - command->follows = 0; - command->value = 0; - command->buffer = NULL; - target->callback = callback; - target->endp = endp; - target->urb = urb; - target->active = 1; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_edset_empty(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_empty(ftdi, ed_number, endp, urb, address, - ep_number, toggle_bits, callback); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_empty); -static int ftdi_elan_edset_output(struct usb_ftdi *ftdi, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - u8 ed = ed_number - 1; - wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - u8 *b; - u16 urb_size; - int i = 0; - char data[30 *3 + 4]; - char *d = data; - int m = (sizeof(data) - 1) / 3; - int l = 0; - struct u132_target *target = &ftdi->target[ed]; - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x81 | (ed << 5); - command->address = (toggle_bits << 6) | (ep_number << 2) - | (address << 0); - command->width = usb_maxpacket(urb->dev, urb->pipe, - usb_pipeout(urb->pipe)); - command->follows = min_t(u32, 1024, - urb->transfer_buffer_length - - urb->actual_length); - command->value = 0; - command->buffer = urb->transfer_buffer + - urb->actual_length; - command->length = 0x8000 | (command->follows - 1); - b = command->buffer; - urb_size = command->follows; - data[0] = 0; - while (urb_size-- > 0) { - if (i > m) { - } else if (i++ < m) { - int w = sprintf(d, " %02X", *b++); - d += w; - l += w; - } else - d += sprintf(d, " .."); - } - target->callback = callback; - target->endp = endp; - target->urb = urb; - target->active = 1; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_edset_output(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_output(ftdi, ed_number, endp, urb, address, - ep_number, toggle_bits, callback); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_output); -static int ftdi_elan_edset_single(struct usb_ftdi *ftdi, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - u8 ed = ed_number - 1; - wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - u32 remaining_length = urb->transfer_buffer_length - - urb->actual_length; - struct u132_target *target = &ftdi->target[ed]; - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x83 | (ed << 5); - if (remaining_length == 0) { - command->length = 0x0000; - } else if (remaining_length > 1024) { - command->length = 0x8000 | 1023; - } else - command->length = 0x8000 | (remaining_length - - 1); - command->address = (toggle_bits << 6) | (ep_number << 2) - | (address << 0); - command->width = usb_maxpacket(urb->dev, urb->pipe, - usb_pipeout(urb->pipe)); - command->follows = 0; - command->value = 0; - command->buffer = NULL; - target->callback = callback; - target->endp = endp; - target->urb = urb; - target->active = 1; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_edset_single(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_single(ftdi, ed_number, endp, urb, address, - ep_number, toggle_bits, callback); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_single); -static int ftdi_elan_edset_flush(struct usb_ftdi *ftdi, u8 ed_number, - void *endp) -{ - u8 ed = ed_number - 1; - if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - struct u132_target *target = &ftdi->target[ed]; - mutex_lock(&ftdi->u132_lock); - if (target->abandoning > 0) { - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - target->abandoning = 1; - wait_1:if (target->active == 1) { - int command_size = ftdi->command_next - - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = - &ftdi->command[COMMAND_MASK & - ftdi->command_next]; - command->header = 0x80 | (ed << 5) | - 0x4; - command->length = 0x00; - command->address = 0x00; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - mutex_lock(&ftdi->u132_lock); - goto wait_1; - } - } - mutex_unlock(&ftdi->u132_lock); - return 0; - } - } -} - -int usb_ftdi_elan_edset_flush(struct platform_device *pdev, u8 ed_number, - void *endp) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_flush(ftdi, ed_number, endp); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_flush); -static int ftdi_elan_flush_input_fifo(struct usb_ftdi *ftdi) -{ - int retry_on_empty = 10; - int retry_on_timeout = 5; - int retry_on_status = 20; - more:{ - int packet_bytes = 0; - int retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 100); - if (packet_bytes > 2) { - char diag[30 *3 + 4]; - char *d = diag; - int m = (sizeof(diag) - 1) / 3; - char *b = ftdi->bulk_in_buffer; - int bytes_read = 0; - diag[0] = 0; - while (packet_bytes-- > 0) { - char c = *b++; - if (bytes_read < m) { - d += sprintf(d, " %02X", - 0x000000FF & c); - } else if (bytes_read > m) { - } else - d += sprintf(d, " .."); - bytes_read += 1; - continue; - } - goto more; - } else if (packet_bytes > 1) { - char s1 = ftdi->bulk_in_buffer[0]; - char s2 = ftdi->bulk_in_buffer[1]; - if (s1 == 0x31 && s2 == 0x60) { - return 0; - } else if (retry_on_status-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "STATUS ERROR retry l" - "imit reached\n"); - return -EFAULT; - } - } else if (packet_bytes > 0) { - char b1 = ftdi->bulk_in_buffer[0]; - dev_err(&ftdi->udev->dev, "only one byte flushed from F" - "TDI = %02X\n", b1); - if (retry_on_status-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "STATUS ERROR retry l" - "imit reached\n"); - return -EFAULT; - } - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "TIMED OUT retry limi" - "t reached\n"); - return -ENOMEM; - } - } else if (retval == 0) { - if (retry_on_empty-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "empty packet retry l" - "imit reached\n"); - return -ENOMEM; - } - } else { - dev_err(&ftdi->udev->dev, "error = %d\n", retval); - return retval; - } - } - return -1; -} - - -/* -* send the long flush sequence -* -*/ -static int ftdi_elan_synchronize_flush(struct usb_ftdi *ftdi) -{ - int retval; - struct urb *urb; - char *buf; - int I = 257; - int i = 0; - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - dev_err(&ftdi->udev->dev, "could not alloc a urb for flush sequ" - "ence\n"); - return -ENOMEM; - } - buf = usb_alloc_coherent(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma); - if (!buf) { - dev_err(&ftdi->udev->dev, "could not get a buffer for flush seq" - "uence\n"); - usb_free_urb(urb); - return -ENOMEM; - } - while (I-- > 0) - buf[i++] = 0x55; - usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, - ftdi->bulk_out_endpointAddr), buf, i, - ftdi_elan_write_bulk_callback, ftdi); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - dev_err(&ftdi->udev->dev, "failed to submit urb containing the " - "flush sequence\n"); - usb_free_coherent(ftdi->udev, i, buf, urb->transfer_dma); - usb_free_urb(urb); - return -ENOMEM; - } - usb_free_urb(urb); - return 0; -} - - -/* -* send the reset sequence -* -*/ -static int ftdi_elan_synchronize_reset(struct usb_ftdi *ftdi) -{ - int retval; - struct urb *urb; - char *buf; - int I = 4; - int i = 0; - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - dev_err(&ftdi->udev->dev, "could not get a urb for the reset se" - "quence\n"); - return -ENOMEM; - } - buf = usb_alloc_coherent(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma); - if (!buf) { - dev_err(&ftdi->udev->dev, "could not get a buffer for the reset" - " sequence\n"); - usb_free_urb(urb); - return -ENOMEM; - } - buf[i++] = 0x55; - buf[i++] = 0xAA; - buf[i++] = 0x5A; - buf[i++] = 0xA5; - usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, - ftdi->bulk_out_endpointAddr), buf, i, - ftdi_elan_write_bulk_callback, ftdi); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - dev_err(&ftdi->udev->dev, "failed to submit urb containing the " - "reset sequence\n"); - usb_free_coherent(ftdi->udev, i, buf, urb->transfer_dma); - usb_free_urb(urb); - return -ENOMEM; - } - usb_free_urb(urb); - return 0; -} - -static int ftdi_elan_synchronize(struct usb_ftdi *ftdi) -{ - int retval; - int long_stop = 10; - int retry_on_timeout = 5; - int retry_on_empty = 10; - int err_count = 0; - retval = ftdi_elan_flush_input_fifo(ftdi); - if (retval) - return retval; - ftdi->bulk_in_left = 0; - ftdi->bulk_in_last = -1; - while (long_stop-- > 0) { - int read_stop; - int read_stuck; - retval = ftdi_elan_synchronize_flush(ftdi); - if (retval) - return retval; - retval = ftdi_elan_flush_input_fifo(ftdi); - if (retval) - return retval; - reset:retval = ftdi_elan_synchronize_reset(ftdi); - if (retval) - return retval; - read_stop = 100; - read_stuck = 10; - read:{ - int packet_bytes = 0; - retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, - ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 500); - if (packet_bytes > 2) { - char diag[30 *3 + 4]; - char *d = diag; - int m = (sizeof(diag) - 1) / 3; - char *b = ftdi->bulk_in_buffer; - int bytes_read = 0; - unsigned char c = 0; - diag[0] = 0; - while (packet_bytes-- > 0) { - c = *b++; - if (bytes_read < m) { - d += sprintf(d, " %02X", c); - } else if (bytes_read > m) { - } else - d += sprintf(d, " .."); - bytes_read += 1; - continue; - } - if (c == 0x7E) { - return 0; - } else { - if (c == 0x55) { - goto read; - } else if (read_stop-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "retr" - "y limit reached\n"); - continue; - } - } - } else if (packet_bytes > 1) { - unsigned char s1 = ftdi->bulk_in_buffer[0]; - unsigned char s2 = ftdi->bulk_in_buffer[1]; - if (s1 == 0x31 && s2 == 0x00) { - if (read_stuck-- > 0) { - goto read; - } else - goto reset; - } else if (s1 == 0x31 && s2 == 0x60) { - if (read_stop-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "retr" - "y limit reached\n"); - continue; - } - } else { - if (read_stop-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "retr" - "y limit reached\n"); - continue; - } - } - } else if (packet_bytes > 0) { - if (read_stop-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "retry limit " - "reached\n"); - continue; - } - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "TIMED OUT re" - "try limit reached\n"); - continue; - } - } else if (retval == 0) { - if (retry_on_empty-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "empty packet" - " retry limit reached\n"); - continue; - } - } else { - err_count += 1; - dev_err(&ftdi->udev->dev, "error = %d\n", - retval); - if (read_stop-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "retry limit " - "reached\n"); - continue; - } - } - } - } - dev_err(&ftdi->udev->dev, "failed to synchronize\n"); - return -EFAULT; -} - -static int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi) -{ - int retry_on_empty = 10; - int retry_on_timeout = 5; - int retry_on_status = 50; - more:{ - int packet_bytes = 0; - int retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 1000); - if (packet_bytes > 2) { - char diag[30 *3 + 4]; - char *d = diag; - int m = (sizeof(diag) - 1) / 3; - char *b = ftdi->bulk_in_buffer; - int bytes_read = 0; - diag[0] = 0; - while (packet_bytes-- > 0) { - char c = *b++; - if (bytes_read < m) { - d += sprintf(d, " %02X", - 0x000000FF & c); - } else if (bytes_read > m) { - } else - d += sprintf(d, " .."); - bytes_read += 1; - continue; - } - goto more; - } else if (packet_bytes > 1) { - char s1 = ftdi->bulk_in_buffer[0]; - char s2 = ftdi->bulk_in_buffer[1]; - if (s1 == 0x31 && s2 == 0x60) { - return 0; - } else if (retry_on_status-- > 0) { - msleep(5); - goto more; - } else - return -EFAULT; - } else if (packet_bytes > 0) { - char b1 = ftdi->bulk_in_buffer[0]; - dev_err(&ftdi->udev->dev, "only one byte flushed from F" - "TDI = %02X\n", b1); - if (retry_on_status-- > 0) { - msleep(5); - goto more; - } else { - dev_err(&ftdi->udev->dev, "STATUS ERROR retry l" - "imit reached\n"); - return -EFAULT; - } - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "TIMED OUT retry limi" - "t reached\n"); - return -ENOMEM; - } - } else if (retval == 0) { - if (retry_on_empty-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "empty packet retry l" - "imit reached\n"); - return -ENOMEM; - } - } else { - dev_err(&ftdi->udev->dev, "error = %d\n", retval); - return -ENOMEM; - } - } - return -1; -} - -static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi) -{ - int UxxxStatus = ftdi_elan_read_reg(ftdi, &ftdi->controlreg); - if (UxxxStatus) - return UxxxStatus; - if (ftdi->controlreg & 0x00400000) { - if (ftdi->card_ejected) { - } else { - ftdi->card_ejected = 1; - dev_err(&ftdi->udev->dev, "CARD EJECTED - controlreg = " - "%08X\n", ftdi->controlreg); - } - return -ENODEV; - } else { - u8 fn = ftdi->function - 1; - int activePCIfn = fn << 8; - u32 pcidata; - u32 pciVID; - u32 pciPID; - int reg = 0; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - pciVID = pcidata & 0xFFFF; - pciPID = (pcidata >> 16) & 0xFFFF; - if (pciVID == ftdi->platform_data.vendor && pciPID == - ftdi->platform_data.device) { - return 0; - } else { - dev_err(&ftdi->udev->dev, "vendor=%04X pciVID=%04X devi" - "ce=%04X pciPID=%04X\n", - ftdi->platform_data.vendor, pciVID, - ftdi->platform_data.device, pciPID); - return -ENODEV; - } - } -} - - -#define ftdi_read_pcimem(ftdi, member, data) ftdi_elan_read_pcimem(ftdi, \ - offsetof(struct ohci_regs, member), 0, data); -#define ftdi_write_pcimem(ftdi, member, data) ftdi_elan_write_pcimem(ftdi, \ - offsetof(struct ohci_regs, member), 0, data); - -#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR -#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \ - OHCI_INTR_WDH) -static int ftdi_elan_check_controller(struct usb_ftdi *ftdi, int quirk) -{ - int devices = 0; - int retval; - u32 hc_control; - int num_ports; - u32 control; - u32 rh_a = -1; - u32 status; - u32 fminterval; - u32 hc_fminterval; - u32 periodicstart; - u32 cmdstatus; - u32 roothub_a; - int mask = OHCI_INTR_INIT; - int sleep_time = 0; - int reset_timeout = 30; /* ... allow extra time */ - int temp; - retval = ftdi_write_pcimem(ftdi, intrdisable, OHCI_INTR_MIE); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, roothub.a, &rh_a); - if (retval) - return retval; - num_ports = rh_a & RH_A_NDP; - retval = ftdi_read_pcimem(ftdi, fminterval, &hc_fminterval); - if (retval) - return retval; - hc_fminterval &= 0x3fff; - if (hc_fminterval != FI) { - } - hc_fminterval |= FSMP(hc_fminterval) << 16; - retval = ftdi_read_pcimem(ftdi, control, &hc_control); - if (retval) - return retval; - switch (hc_control & OHCI_CTRL_HCFS) { - case OHCI_USB_OPER: - sleep_time = 0; - break; - case OHCI_USB_SUSPEND: - case OHCI_USB_RESUME: - hc_control &= OHCI_CTRL_RWC; - hc_control |= OHCI_USB_RESUME; - sleep_time = 10; - break; - default: - hc_control &= OHCI_CTRL_RWC; - hc_control |= OHCI_USB_RESET; - sleep_time = 50; - break; - } - retval = ftdi_write_pcimem(ftdi, control, hc_control); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - msleep(sleep_time); - retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a); - if (retval) - return retval; - if (!(roothub_a & RH_A_NPS)) { /* power down each port */ - for (temp = 0; temp < num_ports; temp++) { - retval = ftdi_write_pcimem(ftdi, - roothub.portstatus[temp], RH_PS_LSDA); - if (retval) - return retval; - } - } - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - retry:retval = ftdi_read_pcimem(ftdi, cmdstatus, &status); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_HCR); - if (retval) - return retval; - extra:{ - retval = ftdi_read_pcimem(ftdi, cmdstatus, &status); - if (retval) - return retval; - if (0 != (status & OHCI_HCR)) { - if (--reset_timeout == 0) { - dev_err(&ftdi->udev->dev, "USB HC reset timed o" - "ut!\n"); - return -ENODEV; - } else { - msleep(5); - goto extra; - } - } - } - if (quirk & OHCI_QUIRK_INITRESET) { - retval = ftdi_write_pcimem(ftdi, control, hc_control); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - } - retval = ftdi_write_pcimem(ftdi, ed_controlhead, 0x00000000); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, ed_bulkhead, 0x11000000); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, hcca, 0x00000000); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, fminterval, - ((fminterval & FIT) ^ FIT) | hc_fminterval); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, periodicstart, - ((9 *hc_fminterval) / 10) & 0x3fff); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, periodicstart, &periodicstart); - if (retval) - return retval; - if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) { - if (!(quirk & OHCI_QUIRK_INITRESET)) { - quirk |= OHCI_QUIRK_INITRESET; - goto retry; - } else - dev_err(&ftdi->udev->dev, "init err(%08x %04x)\n", - fminterval, periodicstart); - } /* start controller operations */ - hc_control &= OHCI_CTRL_RWC; - hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER; - retval = ftdi_write_pcimem(ftdi, control, hc_control); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_BLF); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, cmdstatus, &cmdstatus); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_DRWE); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, intrstatus, mask); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, intrdisable, - OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO | - OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH | - OHCI_INTR_SO); - if (retval) - return retval; /* handle root hub init quirks ... */ - retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a); - if (retval) - return retval; - roothub_a &= ~(RH_A_PSM | RH_A_OCPM); - if (quirk & OHCI_QUIRK_SUPERIO) { - roothub_a |= RH_A_NOCP; - roothub_a &= ~(RH_A_POTPGT | RH_A_NPS); - retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a); - if (retval) - return retval; - } else if ((quirk & OHCI_QUIRK_AMD756) || distrust_firmware) { - roothub_a |= RH_A_NPS; - retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a); - if (retval) - return retval; - } - retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_LPSC); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, roothub.b, - (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - mdelay((roothub_a >> 23) & 0x1fe); - for (temp = 0; temp < num_ports; temp++) { - u32 portstatus; - retval = ftdi_read_pcimem(ftdi, roothub.portstatus[temp], - &portstatus); - if (retval) - return retval; - if (1 & portstatus) - devices += 1; - } - return devices; -} - -static int ftdi_elan_setup_controller(struct usb_ftdi *ftdi, int fn) -{ - u32 latence_timer; - int UxxxStatus; - u32 pcidata; - int reg = 0; - int activePCIfn = fn << 8; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); - if (UxxxStatus) - return UxxxStatus; - reg = 16; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, - 0xFFFFFFFF); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, - 0xF0000000); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - reg = 12; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &latence_timer); - if (UxxxStatus) - return UxxxStatus; - latence_timer &= 0xFFFF00FF; - latence_timer |= 0x00001600; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, - latence_timer); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - reg = 4; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, - 0x06); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - for (reg = 0; reg <= 0x54; reg += 4) { - UxxxStatus = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (UxxxStatus) - return UxxxStatus; - } - return 0; -} - -static int ftdi_elan_close_controller(struct usb_ftdi *ftdi, int fn) -{ - u32 latence_timer; - int UxxxStatus; - u32 pcidata; - int reg = 0; - int activePCIfn = fn << 8; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); - if (UxxxStatus) - return UxxxStatus; - reg = 16; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, - 0xFFFFFFFF); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, - 0x00000000); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - reg = 12; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &latence_timer); - if (UxxxStatus) - return UxxxStatus; - latence_timer &= 0xFFFF00FF; - latence_timer |= 0x00001600; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, - latence_timer); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - reg = 4; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, - 0x00); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - return 0; -} - -static int ftdi_elan_found_controller(struct usb_ftdi *ftdi, int fn, int quirk) -{ - int result; - int UxxxStatus; - UxxxStatus = ftdi_elan_setup_controller(ftdi, fn); - if (UxxxStatus) - return UxxxStatus; - result = ftdi_elan_check_controller(ftdi, quirk); - UxxxStatus = ftdi_elan_close_controller(ftdi, fn); - if (UxxxStatus) - return UxxxStatus; - return result; -} - -static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi) -{ - u32 controlreg; - u8 sensebits; - int UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000000L); - if (UxxxStatus) - return UxxxStatus; - msleep(750); - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x100); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x500); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020CL | 0x000); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020DL | 0x000); - if (UxxxStatus) - return UxxxStatus; - msleep(250); - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020FL | 0x000); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x800); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - msleep(1000); - sensebits = (controlreg >> 16) & 0x000F; - if (0x0D == sensebits) - return 0; - else - return - ENXIO; -} - -static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi) -{ - int UxxxStatus; - u32 pcidata; - int reg = 0; - u8 fn; - int activePCIfn = 0; - int max_devices = 0; - int controllers = 0; - int unrecognized = 0; - ftdi->function = 0; - for (fn = 0; (fn < 4); fn++) { - u32 pciVID = 0; - u32 pciPID = 0; - int devices = 0; - activePCIfn = fn << 8; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - pciVID = pcidata & 0xFFFF; - pciPID = (pcidata >> 16) & 0xFFFF; - if ((pciVID == PCI_VENDOR_ID_OPTI) && (pciPID == 0xc861)) { - devices = ftdi_elan_found_controller(ftdi, fn, 0); - controllers += 1; - } else if ((pciVID == PCI_VENDOR_ID_NEC) && (pciPID == 0x0035)) - { - devices = ftdi_elan_found_controller(ftdi, fn, 0); - controllers += 1; - } else if ((pciVID == PCI_VENDOR_ID_AL) && (pciPID == 0x5237)) { - devices = ftdi_elan_found_controller(ftdi, fn, 0); - controllers += 1; - } else if ((pciVID == PCI_VENDOR_ID_ATT) && (pciPID == 0x5802)) - { - devices = ftdi_elan_found_controller(ftdi, fn, 0); - controllers += 1; - } else if (pciVID == PCI_VENDOR_ID_AMD && pciPID == 0x740c) { - devices = ftdi_elan_found_controller(ftdi, fn, - OHCI_QUIRK_AMD756); - controllers += 1; - } else if (pciVID == PCI_VENDOR_ID_COMPAQ && pciPID == 0xa0f8) { - devices = ftdi_elan_found_controller(ftdi, fn, - OHCI_QUIRK_ZFMICRO); - controllers += 1; - } else if (0 == pcidata) { - } else - unrecognized += 1; - if (devices > max_devices) { - max_devices = devices; - ftdi->function = fn + 1; - ftdi->platform_data.vendor = pciVID; - ftdi->platform_data.device = pciPID; - } - } - if (ftdi->function > 0) { - UxxxStatus = ftdi_elan_setup_controller(ftdi, - ftdi->function - 1); - if (UxxxStatus) - return UxxxStatus; - return 0; - } else if (controllers > 0) { - return -ENXIO; - } else if (unrecognized > 0) { - return -ENXIO; - } else { - ftdi->enumerated = 0; - return -ENXIO; - } -} - - -/* -* we use only the first bulk-in and bulk-out endpoints -*/ -static int ftdi_elan_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - size_t buffer_size; - int i; - int retval = -ENOMEM; - struct usb_ftdi *ftdi; - - ftdi = kzalloc(sizeof(struct usb_ftdi), GFP_KERNEL); - if (!ftdi) { - printk(KERN_ERR "Out of memory\n"); - return -ENOMEM; - } - - mutex_lock(&ftdi_module_lock); - list_add_tail(&ftdi->ftdi_list, &ftdi_static_list); - ftdi->sequence_num = ++ftdi_instances; - mutex_unlock(&ftdi_module_lock); - ftdi_elan_init_kref(ftdi); - sema_init(&ftdi->sw_lock, 1); - ftdi->udev = usb_get_dev(interface_to_usbdev(interface)); - ftdi->interface = interface; - mutex_init(&ftdi->u132_lock); - ftdi->expected = 4; - iface_desc = interface->cur_altsetting; - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - if (!ftdi->bulk_in_endpointAddr && - usb_endpoint_is_bulk_in(endpoint)) { - buffer_size = usb_endpoint_maxp(endpoint); - ftdi->bulk_in_size = buffer_size; - ftdi->bulk_in_endpointAddr = endpoint->bEndpointAddress; - ftdi->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!ftdi->bulk_in_buffer) { - dev_err(&ftdi->udev->dev, "Could not allocate b" - "ulk_in_buffer\n"); - retval = -ENOMEM; - goto error; - } - } - if (!ftdi->bulk_out_endpointAddr && - usb_endpoint_is_bulk_out(endpoint)) { - ftdi->bulk_out_endpointAddr = - endpoint->bEndpointAddress; - } - } - if (!(ftdi->bulk_in_endpointAddr && ftdi->bulk_out_endpointAddr)) { - dev_err(&ftdi->udev->dev, "Could not find both bulk-in and bulk" - "-out endpoints\n"); - retval = -ENODEV; - goto error; - } - dev_info(&ftdi->udev->dev, "interface %d has I=%02X O=%02X\n", - iface_desc->desc.bInterfaceNumber, ftdi->bulk_in_endpointAddr, - ftdi->bulk_out_endpointAddr); - usb_set_intfdata(interface, ftdi); - if (iface_desc->desc.bInterfaceNumber == 0 && - ftdi->bulk_in_endpointAddr == 0x81 && - ftdi->bulk_out_endpointAddr == 0x02) { - retval = usb_register_dev(interface, &ftdi_elan_jtag_class); - if (retval) { - dev_err(&ftdi->udev->dev, "Not able to get a minor for " - "this device.\n"); - usb_set_intfdata(interface, NULL); - retval = -ENOMEM; - goto error; - } else { - ftdi->class = &ftdi_elan_jtag_class; - dev_info(&ftdi->udev->dev, "USB FDTI=%p JTAG interface " - "%d now attached to ftdi%d\n", ftdi, - iface_desc->desc.bInterfaceNumber, - interface->minor); - return 0; - } - } else if (iface_desc->desc.bInterfaceNumber == 1 && - ftdi->bulk_in_endpointAddr == 0x83 && - ftdi->bulk_out_endpointAddr == 0x04) { - ftdi->class = NULL; - dev_info(&ftdi->udev->dev, "USB FDTI=%p ELAN interface %d now a" - "ctivated\n", ftdi, iface_desc->desc.bInterfaceNumber); - INIT_DELAYED_WORK(&ftdi->status_work, ftdi_elan_status_work); - INIT_DELAYED_WORK(&ftdi->command_work, ftdi_elan_command_work); - INIT_DELAYED_WORK(&ftdi->respond_work, ftdi_elan_respond_work); - ftdi_status_queue_work(ftdi, msecs_to_jiffies(3 *1000)); - return 0; - } else { - dev_err(&ftdi->udev->dev, - "Could not find ELAN's U132 device\n"); - retval = -ENODEV; - goto error; - } - error:if (ftdi) { - ftdi_elan_put_kref(ftdi); - } - return retval; -} - -static void ftdi_elan_disconnect(struct usb_interface *interface) -{ - struct usb_ftdi *ftdi = usb_get_intfdata(interface); - ftdi->disconnected += 1; - if (ftdi->class) { - int minor = interface->minor; - struct usb_class_driver *class = ftdi->class; - usb_set_intfdata(interface, NULL); - usb_deregister_dev(interface, class); - dev_info(&ftdi->udev->dev, "USB FTDI U132 jtag interface on min" - "or %d now disconnected\n", minor); - } else { - ftdi_status_cancel_work(ftdi); - ftdi_command_cancel_work(ftdi); - ftdi_response_cancel_work(ftdi); - ftdi_elan_abandon_completions(ftdi); - ftdi_elan_abandon_targets(ftdi); - if (ftdi->registered) { - platform_device_unregister(&ftdi->platform_dev); - ftdi->synchronized = 0; - ftdi->enumerated = 0; - ftdi->initialized = 0; - ftdi->registered = 0; - } - flush_workqueue(status_queue); - flush_workqueue(command_queue); - flush_workqueue(respond_queue); - ftdi->disconnected += 1; - usb_set_intfdata(interface, NULL); - dev_info(&ftdi->udev->dev, "USB FTDI U132 host controller inter" - "face now disconnected\n"); - } - ftdi_elan_put_kref(ftdi); -} - -static struct usb_driver ftdi_elan_driver = { - .name = "ftdi-elan", - .probe = ftdi_elan_probe, - .disconnect = ftdi_elan_disconnect, - .id_table = ftdi_elan_table, -}; -static int __init ftdi_elan_init(void) -{ - int result; - printk(KERN_INFO "driver %s\n", ftdi_elan_driver.name); - mutex_init(&ftdi_module_lock); - INIT_LIST_HEAD(&ftdi_static_list); - status_queue = create_singlethread_workqueue("ftdi-status-control"); - if (!status_queue) - goto err_status_queue; - command_queue = create_singlethread_workqueue("ftdi-command-engine"); - if (!command_queue) - goto err_command_queue; - respond_queue = create_singlethread_workqueue("ftdi-respond-engine"); - if (!respond_queue) - goto err_respond_queue; - result = usb_register(&ftdi_elan_driver); - if (result) { - destroy_workqueue(status_queue); - destroy_workqueue(command_queue); - destroy_workqueue(respond_queue); - printk(KERN_ERR "usb_register failed. Error number %d\n", - result); - } - return result; - - err_respond_queue: - destroy_workqueue(command_queue); - err_command_queue: - destroy_workqueue(status_queue); - err_status_queue: - printk(KERN_ERR "%s couldn't create workqueue\n", ftdi_elan_driver.name); - return -ENOMEM; -} - -static void __exit ftdi_elan_exit(void) -{ - struct usb_ftdi *ftdi; - struct usb_ftdi *temp; - usb_deregister(&ftdi_elan_driver); - printk(KERN_INFO "ftdi_u132 driver deregistered\n"); - list_for_each_entry_safe(ftdi, temp, &ftdi_static_list, ftdi_list) { - ftdi_status_cancel_work(ftdi); - ftdi_command_cancel_work(ftdi); - ftdi_response_cancel_work(ftdi); - } flush_workqueue(status_queue); - destroy_workqueue(status_queue); - status_queue = NULL; - flush_workqueue(command_queue); - destroy_workqueue(command_queue); - command_queue = NULL; - flush_workqueue(respond_queue); - destroy_workqueue(respond_queue); - respond_queue = NULL; -} - - -module_init(ftdi_elan_init); -module_exit(ftdi_elan_exit); diff --git a/ANDROID_3.4.5/drivers/usb/misc/idmouse.c b/ANDROID_3.4.5/drivers/usb/misc/idmouse.c deleted file mode 100644 index 0dee2469..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/idmouse.c +++ /dev/null @@ -1,436 +0,0 @@ -/* Siemens ID Mouse driver v0.6 - - 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. - - Copyright (C) 2004-5 by Florian 'Floe' Echtler - and Andreas 'ad' Deresch - - Derived from the USB Skeleton driver 1.1, - Copyright (C) 2003 Greg Kroah-Hartman (greg@kroah.com) - - Additional information provided by Martin Reising - - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* image constants */ -#define WIDTH 225 -#define HEIGHT 289 -#define HEADER "P5 225 289 255 " -#define IMGSIZE ((WIDTH * HEIGHT) + sizeof(HEADER)-1) - -/* version information */ -#define DRIVER_VERSION "0.6" -#define DRIVER_SHORT "idmouse" -#define DRIVER_AUTHOR "Florian 'Floe' Echtler " -#define DRIVER_DESC "Siemens ID Mouse FingerTIP Sensor Driver" - -/* minor number for misc USB devices */ -#define USB_IDMOUSE_MINOR_BASE 132 - -/* vendor and device IDs */ -#define ID_SIEMENS 0x0681 -#define ID_IDMOUSE 0x0005 -#define ID_CHERRY 0x0010 - -/* device ID table */ -static const struct usb_device_id idmouse_table[] = { - {USB_DEVICE(ID_SIEMENS, ID_IDMOUSE)}, /* Siemens ID Mouse (Professional) */ - {USB_DEVICE(ID_SIEMENS, ID_CHERRY )}, /* Cherry FingerTIP ID Board */ - {} /* terminating null entry */ -}; - -/* sensor commands */ -#define FTIP_RESET 0x20 -#define FTIP_ACQUIRE 0x21 -#define FTIP_RELEASE 0x22 -#define FTIP_BLINK 0x23 /* LSB of value = blink pulse width */ -#define FTIP_SCROLL 0x24 - -#define ftip_command(dev, command, value, index) \ - usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), command, \ - USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, value, index, NULL, 0, 1000) - -MODULE_DEVICE_TABLE(usb, idmouse_table); -static DEFINE_MUTEX(open_disc_mutex); - -/* structure to hold all of our device specific stuff */ -struct usb_idmouse { - - struct usb_device *udev; /* save off the usb device pointer */ - struct usb_interface *interface; /* the interface for this device */ - - unsigned char *bulk_in_buffer; /* the buffer to receive data */ - size_t bulk_in_size; /* the maximum bulk packet size */ - size_t orig_bi_size; /* same as above, but reported by the device */ - __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ - - int open; /* if the port is open or not */ - int present; /* if the device is not disconnected */ - struct mutex lock; /* locks this structure */ - -}; - -/* local function prototypes */ -static ssize_t idmouse_read(struct file *file, char __user *buffer, - size_t count, loff_t * ppos); - -static int idmouse_open(struct inode *inode, struct file *file); -static int idmouse_release(struct inode *inode, struct file *file); - -static int idmouse_probe(struct usb_interface *interface, - const struct usb_device_id *id); - -static void idmouse_disconnect(struct usb_interface *interface); -static int idmouse_suspend(struct usb_interface *intf, pm_message_t message); -static int idmouse_resume(struct usb_interface *intf); - -/* file operation pointers */ -static const struct file_operations idmouse_fops = { - .owner = THIS_MODULE, - .read = idmouse_read, - .open = idmouse_open, - .release = idmouse_release, - .llseek = default_llseek, -}; - -/* class driver information */ -static struct usb_class_driver idmouse_class = { - .name = "idmouse%d", - .fops = &idmouse_fops, - .minor_base = USB_IDMOUSE_MINOR_BASE, -}; - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver idmouse_driver = { - .name = DRIVER_SHORT, - .probe = idmouse_probe, - .disconnect = idmouse_disconnect, - .suspend = idmouse_suspend, - .resume = idmouse_resume, - .reset_resume = idmouse_resume, - .id_table = idmouse_table, - .supports_autosuspend = 1, -}; - -static int idmouse_create_image(struct usb_idmouse *dev) -{ - int bytes_read; - int bulk_read; - int result; - - memcpy(dev->bulk_in_buffer, HEADER, sizeof(HEADER)-1); - bytes_read = sizeof(HEADER)-1; - - /* reset the device and set a fast blink rate */ - result = ftip_command(dev, FTIP_RELEASE, 0, 0); - if (result < 0) - goto reset; - result = ftip_command(dev, FTIP_BLINK, 1, 0); - if (result < 0) - goto reset; - - /* initialize the sensor - sending this command twice */ - /* significantly reduces the rate of failed reads */ - result = ftip_command(dev, FTIP_ACQUIRE, 0, 0); - if (result < 0) - goto reset; - result = ftip_command(dev, FTIP_ACQUIRE, 0, 0); - if (result < 0) - goto reset; - - /* start the readout - sending this command twice */ - /* presumably enables the high dynamic range mode */ - result = ftip_command(dev, FTIP_RESET, 0, 0); - if (result < 0) - goto reset; - result = ftip_command(dev, FTIP_RESET, 0, 0); - if (result < 0) - goto reset; - - /* loop over a blocking bulk read to get data from the device */ - while (bytes_read < IMGSIZE) { - result = usb_bulk_msg (dev->udev, - usb_rcvbulkpipe (dev->udev, dev->bulk_in_endpointAddr), - dev->bulk_in_buffer + bytes_read, - dev->bulk_in_size, &bulk_read, 5000); - if (result < 0) { - /* Maybe this error was caused by the increased packet size? */ - /* Reset to the original value and tell userspace to retry. */ - if (dev->bulk_in_size != dev->orig_bi_size) { - dev->bulk_in_size = dev->orig_bi_size; - result = -EAGAIN; - } - break; - } - if (signal_pending(current)) { - result = -EINTR; - break; - } - bytes_read += bulk_read; - } - - /* reset the device */ -reset: - ftip_command(dev, FTIP_RELEASE, 0, 0); - - /* check for valid image */ - /* right border should be black (0x00) */ - for (bytes_read = sizeof(HEADER)-1 + WIDTH-1; bytes_read < IMGSIZE; bytes_read += WIDTH) - if (dev->bulk_in_buffer[bytes_read] != 0x00) - return -EAGAIN; - - /* lower border should be white (0xFF) */ - for (bytes_read = IMGSIZE-WIDTH; bytes_read < IMGSIZE-1; bytes_read++) - if (dev->bulk_in_buffer[bytes_read] != 0xFF) - return -EAGAIN; - - /* should be IMGSIZE == 65040 */ - dbg("read %d bytes fingerprint data", bytes_read); - return result; -} - -/* PM operations are nops as this driver does IO only during open() */ -static int idmouse_suspend(struct usb_interface *intf, pm_message_t message) -{ - return 0; -} - -static int idmouse_resume(struct usb_interface *intf) -{ - return 0; -} - -static inline void idmouse_delete(struct usb_idmouse *dev) -{ - kfree(dev->bulk_in_buffer); - kfree(dev); -} - -static int idmouse_open(struct inode *inode, struct file *file) -{ - struct usb_idmouse *dev; - struct usb_interface *interface; - int result; - - /* get the interface from minor number and driver information */ - interface = usb_find_interface (&idmouse_driver, iminor (inode)); - if (!interface) - return -ENODEV; - - mutex_lock(&open_disc_mutex); - /* get the device information block from the interface */ - dev = usb_get_intfdata(interface); - if (!dev) { - mutex_unlock(&open_disc_mutex); - return -ENODEV; - } - - /* lock this device */ - mutex_lock(&dev->lock); - mutex_unlock(&open_disc_mutex); - - /* check if already open */ - if (dev->open) { - - /* already open, so fail */ - result = -EBUSY; - - } else { - - /* create a new image and check for success */ - result = usb_autopm_get_interface(interface); - if (result) - goto error; - result = idmouse_create_image (dev); - if (result) - goto error; - usb_autopm_put_interface(interface); - - /* increment our usage count for the driver */ - ++dev->open; - - /* save our object in the file's private structure */ - file->private_data = dev; - - } - -error: - - /* unlock this device */ - mutex_unlock(&dev->lock); - return result; -} - -static int idmouse_release(struct inode *inode, struct file *file) -{ - struct usb_idmouse *dev; - - dev = file->private_data; - - if (dev == NULL) - return -ENODEV; - - mutex_lock(&open_disc_mutex); - /* lock our device */ - mutex_lock(&dev->lock); - - /* are we really open? */ - if (dev->open <= 0) { - mutex_unlock(&dev->lock); - mutex_unlock(&open_disc_mutex); - return -ENODEV; - } - - --dev->open; - - if (!dev->present) { - /* the device was unplugged before the file was released */ - mutex_unlock(&dev->lock); - mutex_unlock(&open_disc_mutex); - idmouse_delete(dev); - } else { - mutex_unlock(&dev->lock); - mutex_unlock(&open_disc_mutex); - } - return 0; -} - -static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count, - loff_t * ppos) -{ - struct usb_idmouse *dev = file->private_data; - int result; - - /* lock this object */ - mutex_lock(&dev->lock); - - /* verify that the device wasn't unplugged */ - if (!dev->present) { - mutex_unlock(&dev->lock); - return -ENODEV; - } - - result = simple_read_from_buffer(buffer, count, ppos, - dev->bulk_in_buffer, IMGSIZE); - /* unlock the device */ - mutex_unlock(&dev->lock); - return result; -} - -static int idmouse_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(interface); - struct usb_idmouse *dev; - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - int result; - - /* check if we have gotten the data or the hid interface */ - iface_desc = &interface->altsetting[0]; - if (iface_desc->desc.bInterfaceClass != 0x0A) - return -ENODEV; - - /* allocate memory for our device state and initialize it */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) - return -ENOMEM; - - mutex_init(&dev->lock); - dev->udev = udev; - dev->interface = interface; - - /* set up the endpoint information - use only the first bulk-in endpoint */ - endpoint = &iface_desc->endpoint[0].desc; - if (!dev->bulk_in_endpointAddr && usb_endpoint_is_bulk_in(endpoint)) { - /* we found a bulk in endpoint */ - dev->orig_bi_size = usb_endpoint_maxp(endpoint); - dev->bulk_in_size = 0x200; /* works _much_ faster */ - dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; - dev->bulk_in_buffer = - kmalloc(IMGSIZE + dev->bulk_in_size, GFP_KERNEL); - - if (!dev->bulk_in_buffer) { - err("Unable to allocate input buffer."); - idmouse_delete(dev); - return -ENOMEM; - } - } - - if (!(dev->bulk_in_endpointAddr)) { - err("Unable to find bulk-in endpoint."); - idmouse_delete(dev); - return -ENODEV; - } - /* allow device read, write and ioctl */ - dev->present = 1; - - /* we can register the device now, as it is ready */ - usb_set_intfdata(interface, dev); - result = usb_register_dev(interface, &idmouse_class); - if (result) { - /* something prevented us from registering this device */ - err("Unble to allocate minor number."); - usb_set_intfdata(interface, NULL); - idmouse_delete(dev); - return result; - } - - /* be noisy */ - dev_info(&interface->dev,"%s now attached\n",DRIVER_DESC); - - return 0; -} - -static void idmouse_disconnect(struct usb_interface *interface) -{ - struct usb_idmouse *dev; - - /* get device structure */ - dev = usb_get_intfdata(interface); - - /* give back our minor */ - usb_deregister_dev(interface, &idmouse_class); - - mutex_lock(&open_disc_mutex); - usb_set_intfdata(interface, NULL); - /* lock the device */ - mutex_lock(&dev->lock); - mutex_unlock(&open_disc_mutex); - - /* prevent device read, write and ioctl */ - dev->present = 0; - - /* if the device is opened, idmouse_release will clean this up */ - if (!dev->open) { - mutex_unlock(&dev->lock); - idmouse_delete(dev); - } else { - /* unlock */ - mutex_unlock(&dev->lock); - } - - dev_info(&interface->dev, "disconnected\n"); -} - -module_usb_driver(idmouse_driver); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - diff --git a/ANDROID_3.4.5/drivers/usb/misc/iowarrior.c b/ANDROID_3.4.5/drivers/usb/misc/iowarrior.c deleted file mode 100644 index 4fd0dc83..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/iowarrior.c +++ /dev/null @@ -1,930 +0,0 @@ -/* - * Native support for the I/O-Warrior USB devices - * - * Copyright (c) 2003-2005 Code Mercenaries GmbH - * written by Christian Lucht - * - * based on - - * usb-skeleton.c by Greg Kroah-Hartman - * brlvger.c by Stephane Dalton - * and St�hane Doyon - * - * Released under the GPLv2. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* Version Information */ -#define DRIVER_VERSION "v0.4.0" -#define DRIVER_AUTHOR "Christian Lucht " -#define DRIVER_DESC "USB IO-Warrior driver (Linux 2.6.x)" - -#define USB_VENDOR_ID_CODEMERCS 1984 -/* low speed iowarrior */ -#define USB_DEVICE_ID_CODEMERCS_IOW40 0x1500 -#define USB_DEVICE_ID_CODEMERCS_IOW24 0x1501 -#define USB_DEVICE_ID_CODEMERCS_IOWPV1 0x1511 -#define USB_DEVICE_ID_CODEMERCS_IOWPV2 0x1512 -/* full speed iowarrior */ -#define USB_DEVICE_ID_CODEMERCS_IOW56 0x1503 - -/* Get a minor range for your devices from the usb maintainer */ -#ifdef CONFIG_USB_DYNAMIC_MINORS -#define IOWARRIOR_MINOR_BASE 0 -#else -#define IOWARRIOR_MINOR_BASE 208 // SKELETON_MINOR_BASE 192 + 16, not official yet -#endif - -/* interrupt input queue size */ -#define MAX_INTERRUPT_BUFFER 16 -/* - maximum number of urbs that are submitted for writes at the same time, - this applies to the IOWarrior56 only! - IOWarrior24 and IOWarrior40 use synchronous usb_control_msg calls. -*/ -#define MAX_WRITES_IN_FLIGHT 4 - -/* Use our own dbg macro */ -#undef dbg -#define dbg( format, arg... ) do { if( debug ) printk( KERN_DEBUG __FILE__ ": " format "\n" , ## arg ); } while ( 0 ) - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -/* Module parameters */ -static DEFINE_MUTEX(iowarrior_mutex); -static bool debug = 0; -module_param(debug, bool, 0644); -MODULE_PARM_DESC(debug, "debug=1 enables debugging messages"); - -static struct usb_driver iowarrior_driver; -static DEFINE_MUTEX(iowarrior_open_disc_lock); - -/*--------------*/ -/* data */ -/*--------------*/ - -/* Structure to hold all of our device specific stuff */ -struct iowarrior { - struct mutex mutex; /* locks this structure */ - struct usb_device *udev; /* save off the usb device pointer */ - struct usb_interface *interface; /* the interface for this device */ - unsigned char minor; /* the starting minor number for this device */ - struct usb_endpoint_descriptor *int_out_endpoint; /* endpoint for reading (needed for IOW56 only) */ - struct usb_endpoint_descriptor *int_in_endpoint; /* endpoint for reading */ - struct urb *int_in_urb; /* the urb for reading data */ - unsigned char *int_in_buffer; /* buffer for data to be read */ - unsigned char serial_number; /* to detect lost packages */ - unsigned char *read_queue; /* size is MAX_INTERRUPT_BUFFER * packet size */ - wait_queue_head_t read_wait; - wait_queue_head_t write_wait; /* wait-queue for writing to the device */ - atomic_t write_busy; /* number of write-urbs submitted */ - atomic_t read_idx; - atomic_t intr_idx; - spinlock_t intr_idx_lock; /* protects intr_idx */ - atomic_t overflow_flag; /* signals an index 'rollover' */ - int present; /* this is 1 as long as the device is connected */ - int opened; /* this is 1 if the device is currently open */ - char chip_serial[9]; /* the serial number string of the chip connected */ - int report_size; /* number of bytes in a report */ - u16 product_id; -}; - -/*--------------*/ -/* globals */ -/*--------------*/ - -/* - * USB spec identifies 5 second timeouts. - */ -#define GET_TIMEOUT 5 -#define USB_REQ_GET_REPORT 0x01 -//#if 0 -static int usb_get_report(struct usb_device *dev, - struct usb_host_interface *inter, unsigned char type, - unsigned char id, void *buf, int size) -{ - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_REPORT, - USB_DIR_IN | USB_TYPE_CLASS | - USB_RECIP_INTERFACE, (type << 8) + id, - inter->desc.bInterfaceNumber, buf, size, - GET_TIMEOUT*HZ); -} -//#endif - -#define USB_REQ_SET_REPORT 0x09 - -static int usb_set_report(struct usb_interface *intf, unsigned char type, - unsigned char id, void *buf, int size) -{ - return usb_control_msg(interface_to_usbdev(intf), - usb_sndctrlpipe(interface_to_usbdev(intf), 0), - USB_REQ_SET_REPORT, - USB_TYPE_CLASS | USB_RECIP_INTERFACE, - (type << 8) + id, - intf->cur_altsetting->desc.bInterfaceNumber, buf, - size, HZ); -} - -/*---------------------*/ -/* driver registration */ -/*---------------------*/ -/* table of devices that work with this driver */ -static const struct usb_device_id iowarrior_ids[] = { - {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40)}, - {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24)}, - {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOWPV1)}, - {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOWPV2)}, - {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW56)}, - {} /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, iowarrior_ids); - -/* - * USB callback handler for reading data - */ -static void iowarrior_callback(struct urb *urb) -{ - struct iowarrior *dev = urb->context; - int intr_idx; - int read_idx; - int aux_idx; - int offset; - int status = urb->status; - int retval; - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - return; - default: - goto exit; - } - - spin_lock(&dev->intr_idx_lock); - intr_idx = atomic_read(&dev->intr_idx); - /* aux_idx become previous intr_idx */ - aux_idx = (intr_idx == 0) ? (MAX_INTERRUPT_BUFFER - 1) : (intr_idx - 1); - read_idx = atomic_read(&dev->read_idx); - - /* queue is not empty and it's interface 0 */ - if ((intr_idx != read_idx) - && (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0)) { - /* + 1 for serial number */ - offset = aux_idx * (dev->report_size + 1); - if (!memcmp - (dev->read_queue + offset, urb->transfer_buffer, - dev->report_size)) { - /* equal values on interface 0 will be ignored */ - spin_unlock(&dev->intr_idx_lock); - goto exit; - } - } - - /* aux_idx become next intr_idx */ - aux_idx = (intr_idx == (MAX_INTERRUPT_BUFFER - 1)) ? 0 : (intr_idx + 1); - if (read_idx == aux_idx) { - /* queue full, dropping oldest input */ - read_idx = (++read_idx == MAX_INTERRUPT_BUFFER) ? 0 : read_idx; - atomic_set(&dev->read_idx, read_idx); - atomic_set(&dev->overflow_flag, 1); - } - - /* +1 for serial number */ - offset = intr_idx * (dev->report_size + 1); - memcpy(dev->read_queue + offset, urb->transfer_buffer, - dev->report_size); - *(dev->read_queue + offset + (dev->report_size)) = dev->serial_number++; - - atomic_set(&dev->intr_idx, aux_idx); - spin_unlock(&dev->intr_idx_lock); - /* tell the blocking read about the new data */ - wake_up_interruptible(&dev->read_wait); - -exit: - retval = usb_submit_urb(urb, GFP_ATOMIC); - if (retval) - dev_err(&dev->interface->dev, "%s - usb_submit_urb failed with result %d\n", - __func__, retval); - -} - -/* - * USB Callback handler for write-ops - */ -static void iowarrior_write_callback(struct urb *urb) -{ - struct iowarrior *dev; - int status = urb->status; - - dev = urb->context; - /* sync/async unlink faults aren't errors */ - if (status && - !(status == -ENOENT || - status == -ECONNRESET || status == -ESHUTDOWN)) { - dbg("%s - nonzero write bulk status received: %d", - __func__, status); - } - /* free up our allocated buffer */ - usb_free_coherent(urb->dev, urb->transfer_buffer_length, - urb->transfer_buffer, urb->transfer_dma); - /* tell a waiting writer the interrupt-out-pipe is available again */ - atomic_dec(&dev->write_busy); - wake_up_interruptible(&dev->write_wait); -} - -/** - * iowarrior_delete - */ -static inline void iowarrior_delete(struct iowarrior *dev) -{ - dbg("%s - minor %d", __func__, dev->minor); - kfree(dev->int_in_buffer); - usb_free_urb(dev->int_in_urb); - kfree(dev->read_queue); - kfree(dev); -} - -/*---------------------*/ -/* fops implementation */ -/*---------------------*/ - -static int read_index(struct iowarrior *dev) -{ - int intr_idx, read_idx; - - read_idx = atomic_read(&dev->read_idx); - intr_idx = atomic_read(&dev->intr_idx); - - return (read_idx == intr_idx ? -1 : read_idx); -} - -/** - * iowarrior_read - */ -static ssize_t iowarrior_read(struct file *file, char __user *buffer, - size_t count, loff_t *ppos) -{ - struct iowarrior *dev; - int read_idx; - int offset; - - dev = file->private_data; - - /* verify that the device wasn't unplugged */ - if (dev == NULL || !dev->present) - return -ENODEV; - - dbg("%s - minor %d, count = %zd", __func__, dev->minor, count); - - /* read count must be packet size (+ time stamp) */ - if ((count != dev->report_size) - && (count != (dev->report_size + 1))) - return -EINVAL; - - /* repeat until no buffer overrun in callback handler occur */ - do { - atomic_set(&dev->overflow_flag, 0); - if ((read_idx = read_index(dev)) == -1) { - /* queue emty */ - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - else { - //next line will return when there is either new data, or the device is unplugged - int r = wait_event_interruptible(dev->read_wait, - (!dev->present - || (read_idx = - read_index - (dev)) != - -1)); - if (r) { - //we were interrupted by a signal - return -ERESTART; - } - if (!dev->present) { - //The device was unplugged - return -ENODEV; - } - if (read_idx == -1) { - // Can this happen ??? - return 0; - } - } - } - - offset = read_idx * (dev->report_size + 1); - if (copy_to_user(buffer, dev->read_queue + offset, count)) { - return -EFAULT; - } - } while (atomic_read(&dev->overflow_flag)); - - read_idx = ++read_idx == MAX_INTERRUPT_BUFFER ? 0 : read_idx; - atomic_set(&dev->read_idx, read_idx); - return count; -} - -/* - * iowarrior_write - */ -static ssize_t iowarrior_write(struct file *file, - const char __user *user_buffer, - size_t count, loff_t *ppos) -{ - struct iowarrior *dev; - int retval = 0; - char *buf = NULL; /* for IOW24 and IOW56 we need a buffer */ - struct urb *int_out_urb = NULL; - - dev = file->private_data; - - mutex_lock(&dev->mutex); - /* verify that the device wasn't unplugged */ - if (!dev->present) { - retval = -ENODEV; - goto exit; - } - dbg("%s - minor %d, count = %zd", __func__, dev->minor, count); - /* if count is 0 we're already done */ - if (count == 0) { - retval = 0; - goto exit; - } - /* We only accept full reports */ - if (count != dev->report_size) { - retval = -EINVAL; - goto exit; - } - switch (dev->product_id) { - case USB_DEVICE_ID_CODEMERCS_IOW24: - case USB_DEVICE_ID_CODEMERCS_IOWPV1: - case USB_DEVICE_ID_CODEMERCS_IOWPV2: - case USB_DEVICE_ID_CODEMERCS_IOW40: - /* IOW24 and IOW40 use a synchronous call */ - buf = kmalloc(count, GFP_KERNEL); - if (!buf) { - retval = -ENOMEM; - goto exit; - } - if (copy_from_user(buf, user_buffer, count)) { - retval = -EFAULT; - kfree(buf); - goto exit; - } - retval = usb_set_report(dev->interface, 2, 0, buf, count); - kfree(buf); - goto exit; - break; - case USB_DEVICE_ID_CODEMERCS_IOW56: - /* The IOW56 uses asynchronous IO and more urbs */ - if (atomic_read(&dev->write_busy) == MAX_WRITES_IN_FLIGHT) { - /* Wait until we are below the limit for submitted urbs */ - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - goto exit; - } else { - retval = wait_event_interruptible(dev->write_wait, - (!dev->present || (atomic_read (&dev-> write_busy) < MAX_WRITES_IN_FLIGHT))); - if (retval) { - /* we were interrupted by a signal */ - retval = -ERESTART; - goto exit; - } - if (!dev->present) { - /* The device was unplugged */ - retval = -ENODEV; - goto exit; - } - if (!dev->opened) { - /* We were closed while waiting for an URB */ - retval = -ENODEV; - goto exit; - } - } - } - atomic_inc(&dev->write_busy); - int_out_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!int_out_urb) { - retval = -ENOMEM; - dbg("%s Unable to allocate urb ", __func__); - goto error_no_urb; - } - buf = usb_alloc_coherent(dev->udev, dev->report_size, - GFP_KERNEL, &int_out_urb->transfer_dma); - if (!buf) { - retval = -ENOMEM; - dbg("%s Unable to allocate buffer ", __func__); - goto error_no_buffer; - } - usb_fill_int_urb(int_out_urb, dev->udev, - usb_sndintpipe(dev->udev, - dev->int_out_endpoint->bEndpointAddress), - buf, dev->report_size, - iowarrior_write_callback, dev, - dev->int_out_endpoint->bInterval); - int_out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - if (copy_from_user(buf, user_buffer, count)) { - retval = -EFAULT; - goto error; - } - retval = usb_submit_urb(int_out_urb, GFP_KERNEL); - if (retval) { - dbg("%s submit error %d for urb nr.%d", __func__, - retval, atomic_read(&dev->write_busy)); - goto error; - } - /* submit was ok */ - retval = count; - usb_free_urb(int_out_urb); - goto exit; - break; - default: - /* what do we have here ? An unsupported Product-ID ? */ - dev_err(&dev->interface->dev, "%s - not supported for product=0x%x\n", - __func__, dev->product_id); - retval = -EFAULT; - goto exit; - break; - } -error: - usb_free_coherent(dev->udev, dev->report_size, buf, - int_out_urb->transfer_dma); -error_no_buffer: - usb_free_urb(int_out_urb); -error_no_urb: - atomic_dec(&dev->write_busy); - wake_up_interruptible(&dev->write_wait); -exit: - mutex_unlock(&dev->mutex); - return retval; -} - -/** - * iowarrior_ioctl - */ -static long iowarrior_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct iowarrior *dev = NULL; - __u8 *buffer; - __u8 __user *user_buffer; - int retval; - int io_res; /* checks for bytes read/written and copy_to/from_user results */ - - dev = file->private_data; - if (dev == NULL) { - return -ENODEV; - } - - buffer = kzalloc(dev->report_size, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - /* lock this object */ - mutex_lock(&iowarrior_mutex); - mutex_lock(&dev->mutex); - - /* verify that the device wasn't unplugged */ - if (!dev->present) { - retval = -ENODEV; - goto error_out; - } - - dbg("%s - minor %d, cmd 0x%.4x, arg %ld", __func__, dev->minor, cmd, - arg); - - retval = 0; - io_res = 0; - switch (cmd) { - case IOW_WRITE: - if (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW24 || - dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV1 || - dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV2 || - dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW40) { - user_buffer = (__u8 __user *)arg; - io_res = copy_from_user(buffer, user_buffer, - dev->report_size); - if (io_res) { - retval = -EFAULT; - } else { - io_res = usb_set_report(dev->interface, 2, 0, - buffer, - dev->report_size); - if (io_res < 0) - retval = io_res; - } - } else { - retval = -EINVAL; - dev_err(&dev->interface->dev, - "ioctl 'IOW_WRITE' is not supported for product=0x%x.\n", - dev->product_id); - } - break; - case IOW_READ: - user_buffer = (__u8 __user *)arg; - io_res = usb_get_report(dev->udev, - dev->interface->cur_altsetting, 1, 0, - buffer, dev->report_size); - if (io_res < 0) - retval = io_res; - else { - io_res = copy_to_user(user_buffer, buffer, dev->report_size); - if (io_res) - retval = -EFAULT; - } - break; - case IOW_GETINFO: - { - /* Report available information for the device */ - struct iowarrior_info info; - /* needed for power consumption */ - struct usb_config_descriptor *cfg_descriptor = &dev->udev->actconfig->desc; - - memset(&info, 0, sizeof(info)); - /* directly from the descriptor */ - info.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); - info.product = dev->product_id; - info.revision = le16_to_cpu(dev->udev->descriptor.bcdDevice); - - /* 0==UNKNOWN, 1==LOW(usb1.1) ,2=FULL(usb1.1), 3=HIGH(usb2.0) */ - info.speed = le16_to_cpu(dev->udev->speed); - info.if_num = dev->interface->cur_altsetting->desc.bInterfaceNumber; - info.report_size = dev->report_size; - - /* serial number string has been read earlier 8 chars or empty string */ - memcpy(info.serial, dev->chip_serial, - sizeof(dev->chip_serial)); - if (cfg_descriptor == NULL) { - info.power = -1; /* no information available */ - } else { - /* the MaxPower is stored in units of 2mA to make it fit into a byte-value */ - info.power = cfg_descriptor->bMaxPower * 2; - } - io_res = copy_to_user((struct iowarrior_info __user *)arg, &info, - sizeof(struct iowarrior_info)); - if (io_res) - retval = -EFAULT; - break; - } - default: - /* return that we did not understand this ioctl call */ - retval = -ENOTTY; - break; - } -error_out: - /* unlock the device */ - mutex_unlock(&dev->mutex); - mutex_unlock(&iowarrior_mutex); - kfree(buffer); - return retval; -} - -/** - * iowarrior_open - */ -static int iowarrior_open(struct inode *inode, struct file *file) -{ - struct iowarrior *dev = NULL; - struct usb_interface *interface; - int subminor; - int retval = 0; - - dbg("%s", __func__); - - mutex_lock(&iowarrior_mutex); - subminor = iminor(inode); - - interface = usb_find_interface(&iowarrior_driver, subminor); - if (!interface) { - mutex_unlock(&iowarrior_mutex); - err("%s - error, can't find device for minor %d", __func__, - subminor); - return -ENODEV; - } - - mutex_lock(&iowarrior_open_disc_lock); - dev = usb_get_intfdata(interface); - if (!dev) { - mutex_unlock(&iowarrior_open_disc_lock); - mutex_unlock(&iowarrior_mutex); - return -ENODEV; - } - - mutex_lock(&dev->mutex); - mutex_unlock(&iowarrior_open_disc_lock); - - /* Only one process can open each device, no sharing. */ - if (dev->opened) { - retval = -EBUSY; - goto out; - } - - /* setup interrupt handler for receiving values */ - if ((retval = usb_submit_urb(dev->int_in_urb, GFP_KERNEL)) < 0) { - dev_err(&interface->dev, "Error %d while submitting URB\n", retval); - retval = -EFAULT; - goto out; - } - /* increment our usage count for the driver */ - ++dev->opened; - /* save our object in the file's private structure */ - file->private_data = dev; - retval = 0; - -out: - mutex_unlock(&dev->mutex); - mutex_unlock(&iowarrior_mutex); - return retval; -} - -/** - * iowarrior_release - */ -static int iowarrior_release(struct inode *inode, struct file *file) -{ - struct iowarrior *dev; - int retval = 0; - - dev = file->private_data; - if (dev == NULL) { - return -ENODEV; - } - - dbg("%s - minor %d", __func__, dev->minor); - - /* lock our device */ - mutex_lock(&dev->mutex); - - if (dev->opened <= 0) { - retval = -ENODEV; /* close called more than once */ - mutex_unlock(&dev->mutex); - } else { - dev->opened = 0; /* we're closeing now */ - retval = 0; - if (dev->present) { - /* - The device is still connected so we only shutdown - pending read-/write-ops. - */ - usb_kill_urb(dev->int_in_urb); - wake_up_interruptible(&dev->read_wait); - wake_up_interruptible(&dev->write_wait); - mutex_unlock(&dev->mutex); - } else { - /* The device was unplugged, cleanup resources */ - mutex_unlock(&dev->mutex); - iowarrior_delete(dev); - } - } - return retval; -} - -static unsigned iowarrior_poll(struct file *file, poll_table * wait) -{ - struct iowarrior *dev = file->private_data; - unsigned int mask = 0; - - if (!dev->present) - return POLLERR | POLLHUP; - - poll_wait(file, &dev->read_wait, wait); - poll_wait(file, &dev->write_wait, wait); - - if (!dev->present) - return POLLERR | POLLHUP; - - if (read_index(dev) != -1) - mask |= POLLIN | POLLRDNORM; - - if (atomic_read(&dev->write_busy) < MAX_WRITES_IN_FLIGHT) - mask |= POLLOUT | POLLWRNORM; - return mask; -} - -/* - * File operations needed when we register this driver. - * This assumes that this driver NEEDS file operations, - * of course, which means that the driver is expected - * to have a node in the /dev directory. If the USB - * device were for a network interface then the driver - * would use "struct net_driver" instead, and a serial - * device would use "struct tty_driver". - */ -static const struct file_operations iowarrior_fops = { - .owner = THIS_MODULE, - .write = iowarrior_write, - .read = iowarrior_read, - .unlocked_ioctl = iowarrior_ioctl, - .open = iowarrior_open, - .release = iowarrior_release, - .poll = iowarrior_poll, - .llseek = noop_llseek, -}; - -static char *iowarrior_devnode(struct device *dev, umode_t *mode) -{ - return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev)); -} - -/* - * usb class driver info in order to get a minor number from the usb core, - * and to have the device registered with devfs and the driver core - */ -static struct usb_class_driver iowarrior_class = { - .name = "iowarrior%d", - .devnode = iowarrior_devnode, - .fops = &iowarrior_fops, - .minor_base = IOWARRIOR_MINOR_BASE, -}; - -/*---------------------------------*/ -/* probe and disconnect functions */ -/*---------------------------------*/ -/** - * iowarrior_probe - * - * Called by the usb core when a new device is connected that it thinks - * this driver might be interested in. - */ -static int iowarrior_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(interface); - struct iowarrior *dev = NULL; - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - int i; - int retval = -ENOMEM; - - /* allocate memory for our device state and initialize it */ - dev = kzalloc(sizeof(struct iowarrior), GFP_KERNEL); - if (dev == NULL) { - dev_err(&interface->dev, "Out of memory\n"); - return retval; - } - - mutex_init(&dev->mutex); - - atomic_set(&dev->intr_idx, 0); - atomic_set(&dev->read_idx, 0); - spin_lock_init(&dev->intr_idx_lock); - atomic_set(&dev->overflow_flag, 0); - init_waitqueue_head(&dev->read_wait); - atomic_set(&dev->write_busy, 0); - init_waitqueue_head(&dev->write_wait); - - dev->udev = udev; - dev->interface = interface; - - iface_desc = interface->cur_altsetting; - dev->product_id = le16_to_cpu(udev->descriptor.idProduct); - - /* set up the endpoint information */ - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - - if (usb_endpoint_is_int_in(endpoint)) - dev->int_in_endpoint = endpoint; - if (usb_endpoint_is_int_out(endpoint)) - /* this one will match for the IOWarrior56 only */ - dev->int_out_endpoint = endpoint; - } - /* we have to check the report_size often, so remember it in the endianess suitable for our machine */ - dev->report_size = usb_endpoint_maxp(dev->int_in_endpoint); - if ((dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) && - (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56)) - /* IOWarrior56 has wMaxPacketSize different from report size */ - dev->report_size = 7; - - /* create the urb and buffer for reading */ - dev->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->int_in_urb) { - dev_err(&interface->dev, "Couldn't allocate interrupt_in_urb\n"); - goto error; - } - dev->int_in_buffer = kmalloc(dev->report_size, GFP_KERNEL); - if (!dev->int_in_buffer) { - dev_err(&interface->dev, "Couldn't allocate int_in_buffer\n"); - goto error; - } - usb_fill_int_urb(dev->int_in_urb, dev->udev, - usb_rcvintpipe(dev->udev, - dev->int_in_endpoint->bEndpointAddress), - dev->int_in_buffer, dev->report_size, - iowarrior_callback, dev, - dev->int_in_endpoint->bInterval); - /* create an internal buffer for interrupt data from the device */ - dev->read_queue = - kmalloc(((dev->report_size + 1) * MAX_INTERRUPT_BUFFER), - GFP_KERNEL); - if (!dev->read_queue) { - dev_err(&interface->dev, "Couldn't allocate read_queue\n"); - goto error; - } - /* Get the serial-number of the chip */ - memset(dev->chip_serial, 0x00, sizeof(dev->chip_serial)); - usb_string(udev, udev->descriptor.iSerialNumber, dev->chip_serial, - sizeof(dev->chip_serial)); - if (strlen(dev->chip_serial) != 8) - memset(dev->chip_serial, 0x00, sizeof(dev->chip_serial)); - - /* Set the idle timeout to 0, if this is interface 0 */ - if (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) { - usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0x0A, - USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, - 0, NULL, 0, USB_CTRL_SET_TIMEOUT); - } - /* allow device read and ioctl */ - dev->present = 1; - - /* we can register the device now, as it is ready */ - usb_set_intfdata(interface, dev); - - retval = usb_register_dev(interface, &iowarrior_class); - if (retval) { - /* something prevented us from registering this driver */ - dev_err(&interface->dev, "Not able to get a minor for this device.\n"); - usb_set_intfdata(interface, NULL); - goto error; - } - - dev->minor = interface->minor; - - /* let the user know what node this device is now attached to */ - dev_info(&interface->dev, "IOWarrior product=0x%x, serial=%s interface=%d " - "now attached to iowarrior%d\n", dev->product_id, dev->chip_serial, - iface_desc->desc.bInterfaceNumber, dev->minor - IOWARRIOR_MINOR_BASE); - return retval; - -error: - iowarrior_delete(dev); - return retval; -} - -/** - * iowarrior_disconnect - * - * Called by the usb core when the device is removed from the system. - */ -static void iowarrior_disconnect(struct usb_interface *interface) -{ - struct iowarrior *dev; - int minor; - - dev = usb_get_intfdata(interface); - mutex_lock(&iowarrior_open_disc_lock); - usb_set_intfdata(interface, NULL); - - minor = dev->minor; - - /* give back our minor */ - usb_deregister_dev(interface, &iowarrior_class); - - mutex_lock(&dev->mutex); - - /* prevent device read, write and ioctl */ - dev->present = 0; - - mutex_unlock(&dev->mutex); - mutex_unlock(&iowarrior_open_disc_lock); - - if (dev->opened) { - /* There is a process that holds a filedescriptor to the device , - so we only shutdown read-/write-ops going on. - Deleting the device is postponed until close() was called. - */ - usb_kill_urb(dev->int_in_urb); - wake_up_interruptible(&dev->read_wait); - wake_up_interruptible(&dev->write_wait); - } else { - /* no process is using the device, cleanup now */ - iowarrior_delete(dev); - } - - dev_info(&interface->dev, "I/O-Warror #%d now disconnected\n", - minor - IOWARRIOR_MINOR_BASE); -} - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver iowarrior_driver = { - .name = "iowarrior", - .probe = iowarrior_probe, - .disconnect = iowarrior_disconnect, - .id_table = iowarrior_ids, -}; - -module_usb_driver(iowarrior_driver); diff --git a/ANDROID_3.4.5/drivers/usb/misc/isight_firmware.c b/ANDROID_3.4.5/drivers/usb/misc/isight_firmware.c deleted file mode 100644 index 1c61830e..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/isight_firmware.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Driver for loading USB isight firmware - * - * Copyright (C) 2008 Matthew Garrett - * - * 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, version 2. - * - * The USB isight cameras in recent Apples are roughly compatible with the USB - * video class specification, and can be driven by uvcvideo. However, they - * need firmware to be loaded beforehand. After firmware loading, the device - * detaches from the USB bus and reattaches with a new device ID. It can then - * be claimed by the uvc driver. - * - * The firmware is non-free and must be extracted by the user. Tools to do this - * are available at http://bersace03.free.fr/ift/ - * - * The isight firmware loading was reverse engineered by Johannes Berg - * , and this driver is based on code by Ronald - * Bultje - */ - -#include -#include -#include -#include -#include - -static const struct usb_device_id id_table[] = { - {USB_DEVICE(0x05ac, 0x8300)}, - {}, -}; - -MODULE_DEVICE_TABLE(usb, id_table); - -static int isight_firmware_load(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - int llen, len, req, ret = 0; - const struct firmware *firmware; - unsigned char *buf = kmalloc(50, GFP_KERNEL); - unsigned char data[4]; - const u8 *ptr; - - if (!buf) - return -ENOMEM; - - if (request_firmware(&firmware, "isight.fw", &dev->dev) != 0) { - printk(KERN_ERR "Unable to load isight firmware\n"); - ret = -ENODEV; - goto out; - } - - ptr = firmware->data; - - buf[0] = 0x01; - if (usb_control_msg - (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, buf, 1, - 300) != 1) { - printk(KERN_ERR - "Failed to initialise isight firmware loader\n"); - ret = -ENODEV; - goto out; - } - - while (ptr+4 <= firmware->data+firmware->size) { - memcpy(data, ptr, 4); - len = (data[0] << 8 | data[1]); - req = (data[2] << 8 | data[3]); - ptr += 4; - - if (len == 0x8001) - break; /* success */ - else if (len == 0) - continue; - - for (; len > 0; req += 50) { - llen = min(len, 50); - len -= llen; - if (ptr+llen > firmware->data+firmware->size) { - printk(KERN_ERR - "Malformed isight firmware"); - ret = -ENODEV; - goto out; - } - memcpy(buf, ptr, llen); - - ptr += llen; - - if (usb_control_msg - (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, req, 0, - buf, llen, 300) != llen) { - printk(KERN_ERR - "Failed to load isight firmware\n"); - ret = -ENODEV; - goto out; - } - - } - } - - buf[0] = 0x00; - if (usb_control_msg - (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, buf, 1, - 300) != 1) { - printk(KERN_ERR "isight firmware loading completion failed\n"); - ret = -ENODEV; - } - -out: - kfree(buf); - release_firmware(firmware); - return ret; -} - -MODULE_FIRMWARE("isight.fw"); - -static void isight_firmware_disconnect(struct usb_interface *intf) -{ -} - -static struct usb_driver isight_firmware_driver = { - .name = "isight_firmware", - .probe = isight_firmware_load, - .disconnect = isight_firmware_disconnect, - .id_table = id_table, -}; - -module_usb_driver(isight_firmware_driver); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Matthew Garrett "); diff --git a/ANDROID_3.4.5/drivers/usb/misc/ldusb.c b/ANDROID_3.4.5/drivers/usb/misc/ldusb.c deleted file mode 100644 index 5db4ab52..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/ldusb.c +++ /dev/null @@ -1,825 +0,0 @@ -/** - * Generic USB driver for report based interrupt in/out devices - * like LD Didactic's USB devices. LD Didactic's USB devices are - * HID devices which do not use HID report definitons (they use - * raw interrupt in and our reports only for communication). - * - * This driver uses a ring buffer for time critical reading of - * interrupt in reports and provides read and write methods for - * raw interrupt reports (similar to the Windows HID driver). - * Devices based on the book USB COMPLETE by Jan Axelson may need - * such a compatibility to the Windows HID driver. - * - * Copyright (C) 2005 Michael Hund - * - * 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. - * - * Derived from Lego USB Tower driver - * Copyright (C) 2003 David Glance - * 2001-2004 Juergen Stuber - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/* Define these values to match your devices */ -#define USB_VENDOR_ID_LD 0x0f11 /* USB Vendor ID of LD Didactic GmbH */ -#define USB_DEVICE_ID_LD_CASSY 0x1000 /* USB Product ID of CASSY-S modules with 8 bytes endpoint size */ -#define USB_DEVICE_ID_LD_CASSY2 0x1001 /* USB Product ID of CASSY-S modules with 64 bytes endpoint size */ -#define USB_DEVICE_ID_LD_POCKETCASSY 0x1010 /* USB Product ID of Pocket-CASSY */ -#define USB_DEVICE_ID_LD_POCKETCASSY2 0x1011 /* USB Product ID of Pocket-CASSY 2 (reserved) */ -#define USB_DEVICE_ID_LD_MOBILECASSY 0x1020 /* USB Product ID of Mobile-CASSY */ -#define USB_DEVICE_ID_LD_MOBILECASSY2 0x1021 /* USB Product ID of Mobile-CASSY 2 (reserved) */ -#define USB_DEVICE_ID_LD_MICROCASSYVOLTAGE 0x1031 /* USB Product ID of Micro-CASSY Voltage */ -#define USB_DEVICE_ID_LD_MICROCASSYCURRENT 0x1032 /* USB Product ID of Micro-CASSY Current */ -#define USB_DEVICE_ID_LD_MICROCASSYTIME 0x1033 /* USB Product ID of Micro-CASSY Time (reserved) */ -#define USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE 0x1035 /* USB Product ID of Micro-CASSY Temperature */ -#define USB_DEVICE_ID_LD_MICROCASSYPH 0x1038 /* USB Product ID of Micro-CASSY pH */ -#define USB_DEVICE_ID_LD_JWM 0x1080 /* USB Product ID of Joule and Wattmeter */ -#define USB_DEVICE_ID_LD_DMMP 0x1081 /* USB Product ID of Digital Multimeter P (reserved) */ -#define USB_DEVICE_ID_LD_UMIP 0x1090 /* USB Product ID of UMI P */ -#define USB_DEVICE_ID_LD_UMIC 0x10A0 /* USB Product ID of UMI C */ -#define USB_DEVICE_ID_LD_UMIB 0x10B0 /* USB Product ID of UMI B */ -#define USB_DEVICE_ID_LD_XRAY 0x1100 /* USB Product ID of X-Ray Apparatus 55481 */ -#define USB_DEVICE_ID_LD_XRAY2 0x1101 /* USB Product ID of X-Ray Apparatus 554800 */ -#define USB_DEVICE_ID_LD_XRAYCT 0x1110 /* USB Product ID of X-Ray Apparatus CT 554821*/ -#define USB_DEVICE_ID_LD_VIDEOCOM 0x1200 /* USB Product ID of VideoCom */ -#define USB_DEVICE_ID_LD_MOTOR 0x1210 /* USB Product ID of Motor (reserved) */ -#define USB_DEVICE_ID_LD_COM3LAB 0x2000 /* USB Product ID of COM3LAB */ -#define USB_DEVICE_ID_LD_TELEPORT 0x2010 /* USB Product ID of Terminal Adapter */ -#define USB_DEVICE_ID_LD_NETWORKANALYSER 0x2020 /* USB Product ID of Network Analyser */ -#define USB_DEVICE_ID_LD_POWERCONTROL 0x2030 /* USB Product ID of Converter Control Unit */ -#define USB_DEVICE_ID_LD_MACHINETEST 0x2040 /* USB Product ID of Machine Test System */ -#define USB_DEVICE_ID_LD_MOSTANALYSER 0x2050 /* USB Product ID of MOST Protocol Analyser */ -#define USB_DEVICE_ID_LD_MOSTANALYSER2 0x2051 /* USB Product ID of MOST Protocol Analyser 2 */ -#define USB_DEVICE_ID_LD_ABSESP 0x2060 /* USB Product ID of ABS ESP */ -#define USB_DEVICE_ID_LD_AUTODATABUS 0x2070 /* USB Product ID of Automotive Data Buses */ -#define USB_DEVICE_ID_LD_MCT 0x2080 /* USB Product ID of Microcontroller technique */ -#define USB_DEVICE_ID_LD_HYBRID 0x2090 /* USB Product ID of Automotive Hybrid */ -#define USB_DEVICE_ID_LD_HEATCONTROL 0x20A0 /* USB Product ID of Heat control */ - -#define USB_VENDOR_ID_VERNIER 0x08f7 -#define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002 -#define USB_DEVICE_ID_VERNIER_SKIP 0x0003 -#define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004 -#define USB_DEVICE_ID_VERNIER_LCSPEC 0x0006 - -#ifdef CONFIG_USB_DYNAMIC_MINORS -#define USB_LD_MINOR_BASE 0 -#else -#define USB_LD_MINOR_BASE 176 -#endif - -/* table of devices that work with this driver */ -static const struct usb_device_id ld_usb_table[] = { - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY2) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY2) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY2) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYVOLTAGE) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYCURRENT) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTIME) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYPH) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIC) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIB) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY2) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_VIDEOCOM) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOTOR) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_COM3LAB) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_TELEPORT) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_NETWORKANALYSER) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERCONTROL) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETEST) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOSTANALYSER) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOSTANALYSER2) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_ABSESP) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_AUTODATABUS) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MCT) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HYBRID) }, - { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HEATCONTROL) }, - { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) }, - { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) }, - { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) }, - { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LCSPEC) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, ld_usb_table); -MODULE_VERSION("V0.14"); -MODULE_AUTHOR("Michael Hund "); -MODULE_DESCRIPTION("LD USB Driver"); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("LD USB Devices"); - -#ifdef CONFIG_USB_DEBUG - static int debug = 1; -#else - static int debug = 0; -#endif - -/* Use our own dbg macro */ -#define dbg_info(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0) - -/* Module parameters */ -module_param(debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - -/* All interrupt in transfers are collected in a ring buffer to - * avoid racing conditions and get better performance of the driver. - */ -static int ring_buffer_size = 128; -module_param(ring_buffer_size, int, 0); -MODULE_PARM_DESC(ring_buffer_size, "Read ring buffer size in reports"); - -/* The write_buffer can contain more than one interrupt out transfer. - */ -static int write_buffer_size = 10; -module_param(write_buffer_size, int, 0); -MODULE_PARM_DESC(write_buffer_size, "Write buffer size in reports"); - -/* As of kernel version 2.6.4 ehci-hcd uses an - * "only one interrupt transfer per frame" shortcut - * to simplify the scheduling of periodic transfers. - * This conflicts with our standard 1ms intervals for in and out URBs. - * We use default intervals of 2ms for in and 2ms for out transfers, - * which should be fast enough. - * Increase the interval to allow more devices that do interrupt transfers, - * or set to 1 to use the standard interval from the endpoint descriptors. - */ -static int min_interrupt_in_interval = 2; -module_param(min_interrupt_in_interval, int, 0); -MODULE_PARM_DESC(min_interrupt_in_interval, "Minimum interrupt in interval in ms"); - -static int min_interrupt_out_interval = 2; -module_param(min_interrupt_out_interval, int, 0); -MODULE_PARM_DESC(min_interrupt_out_interval, "Minimum interrupt out interval in ms"); - -/* Structure to hold all of our device specific stuff */ -struct ld_usb { - struct mutex mutex; /* locks this structure */ - struct usb_interface* intf; /* save off the usb interface pointer */ - - int open_count; /* number of times this port has been opened */ - - char* ring_buffer; - unsigned int ring_head; - unsigned int ring_tail; - - wait_queue_head_t read_wait; - wait_queue_head_t write_wait; - - char* interrupt_in_buffer; - struct usb_endpoint_descriptor* interrupt_in_endpoint; - struct urb* interrupt_in_urb; - int interrupt_in_interval; - size_t interrupt_in_endpoint_size; - int interrupt_in_running; - int interrupt_in_done; - int buffer_overflow; - spinlock_t rbsl; - - char* interrupt_out_buffer; - struct usb_endpoint_descriptor* interrupt_out_endpoint; - struct urb* interrupt_out_urb; - int interrupt_out_interval; - size_t interrupt_out_endpoint_size; - int interrupt_out_busy; -}; - -static struct usb_driver ld_usb_driver; - -/** - * ld_usb_abort_transfers - * aborts transfers and frees associated data structures - */ -static void ld_usb_abort_transfers(struct ld_usb *dev) -{ - /* shutdown transfer */ - if (dev->interrupt_in_running) { - dev->interrupt_in_running = 0; - if (dev->intf) - usb_kill_urb(dev->interrupt_in_urb); - } - if (dev->interrupt_out_busy) - if (dev->intf) - usb_kill_urb(dev->interrupt_out_urb); -} - -/** - * ld_usb_delete - */ -static void ld_usb_delete(struct ld_usb *dev) -{ - ld_usb_abort_transfers(dev); - - /* free data structures */ - usb_free_urb(dev->interrupt_in_urb); - usb_free_urb(dev->interrupt_out_urb); - kfree(dev->ring_buffer); - kfree(dev->interrupt_in_buffer); - kfree(dev->interrupt_out_buffer); - kfree(dev); -} - -/** - * ld_usb_interrupt_in_callback - */ -static void ld_usb_interrupt_in_callback(struct urb *urb) -{ - struct ld_usb *dev = urb->context; - size_t *actual_buffer; - unsigned int next_ring_head; - int status = urb->status; - int retval; - - if (status) { - if (status == -ENOENT || - status == -ECONNRESET || - status == -ESHUTDOWN) { - goto exit; - } else { - dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n", - __func__, status); - spin_lock(&dev->rbsl); - goto resubmit; /* maybe we can recover */ - } - } - - spin_lock(&dev->rbsl); - if (urb->actual_length > 0) { - next_ring_head = (dev->ring_head+1) % ring_buffer_size; - if (next_ring_head != dev->ring_tail) { - actual_buffer = (size_t*)(dev->ring_buffer + dev->ring_head*(sizeof(size_t)+dev->interrupt_in_endpoint_size)); - /* actual_buffer gets urb->actual_length + interrupt_in_buffer */ - *actual_buffer = urb->actual_length; - memcpy(actual_buffer+1, dev->interrupt_in_buffer, urb->actual_length); - dev->ring_head = next_ring_head; - dbg_info(&dev->intf->dev, "%s: received %d bytes\n", - __func__, urb->actual_length); - } else { - dev_warn(&dev->intf->dev, - "Ring buffer overflow, %d bytes dropped\n", - urb->actual_length); - dev->buffer_overflow = 1; - } - } - -resubmit: - /* resubmit if we're still running */ - if (dev->interrupt_in_running && !dev->buffer_overflow && dev->intf) { - retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC); - if (retval) { - dev_err(&dev->intf->dev, - "usb_submit_urb failed (%d)\n", retval); - dev->buffer_overflow = 1; - } - } - spin_unlock(&dev->rbsl); -exit: - dev->interrupt_in_done = 1; - wake_up_interruptible(&dev->read_wait); -} - -/** - * ld_usb_interrupt_out_callback - */ -static void ld_usb_interrupt_out_callback(struct urb *urb) -{ - struct ld_usb *dev = urb->context; - int status = urb->status; - - /* sync/async unlink faults aren't errors */ - if (status && !(status == -ENOENT || - status == -ECONNRESET || - status == -ESHUTDOWN)) - dbg_info(&dev->intf->dev, - "%s - nonzero write interrupt status received: %d\n", - __func__, status); - - dev->interrupt_out_busy = 0; - wake_up_interruptible(&dev->write_wait); -} - -/** - * ld_usb_open - */ -static int ld_usb_open(struct inode *inode, struct file *file) -{ - struct ld_usb *dev; - int subminor; - int retval; - struct usb_interface *interface; - - nonseekable_open(inode, file); - subminor = iminor(inode); - - interface = usb_find_interface(&ld_usb_driver, subminor); - - if (!interface) { - err("%s - error, can't find device for minor %d\n", - __func__, subminor); - return -ENODEV; - } - - dev = usb_get_intfdata(interface); - - if (!dev) - return -ENODEV; - - /* lock this device */ - if (mutex_lock_interruptible(&dev->mutex)) - return -ERESTARTSYS; - - /* allow opening only once */ - if (dev->open_count) { - retval = -EBUSY; - goto unlock_exit; - } - dev->open_count = 1; - - /* initialize in direction */ - dev->ring_head = 0; - dev->ring_tail = 0; - dev->buffer_overflow = 0; - usb_fill_int_urb(dev->interrupt_in_urb, - interface_to_usbdev(interface), - usb_rcvintpipe(interface_to_usbdev(interface), - dev->interrupt_in_endpoint->bEndpointAddress), - dev->interrupt_in_buffer, - dev->interrupt_in_endpoint_size, - ld_usb_interrupt_in_callback, - dev, - dev->interrupt_in_interval); - - dev->interrupt_in_running = 1; - dev->interrupt_in_done = 0; - - retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL); - if (retval) { - dev_err(&interface->dev, "Couldn't submit interrupt_in_urb %d\n", retval); - dev->interrupt_in_running = 0; - dev->open_count = 0; - goto unlock_exit; - } - - /* save device in the file's private structure */ - file->private_data = dev; - -unlock_exit: - mutex_unlock(&dev->mutex); - - return retval; -} - -/** - * ld_usb_release - */ -static int ld_usb_release(struct inode *inode, struct file *file) -{ - struct ld_usb *dev; - int retval = 0; - - dev = file->private_data; - - if (dev == NULL) { - retval = -ENODEV; - goto exit; - } - - if (mutex_lock_interruptible(&dev->mutex)) { - retval = -ERESTARTSYS; - goto exit; - } - - if (dev->open_count != 1) { - retval = -ENODEV; - goto unlock_exit; - } - if (dev->intf == NULL) { - /* the device was unplugged before the file was released */ - mutex_unlock(&dev->mutex); - /* unlock here as ld_usb_delete frees dev */ - ld_usb_delete(dev); - goto exit; - } - - /* wait until write transfer is finished */ - if (dev->interrupt_out_busy) - wait_event_interruptible_timeout(dev->write_wait, !dev->interrupt_out_busy, 2 * HZ); - ld_usb_abort_transfers(dev); - dev->open_count = 0; - -unlock_exit: - mutex_unlock(&dev->mutex); - -exit: - return retval; -} - -/** - * ld_usb_poll - */ -static unsigned int ld_usb_poll(struct file *file, poll_table *wait) -{ - struct ld_usb *dev; - unsigned int mask = 0; - - dev = file->private_data; - - if (!dev->intf) - return POLLERR | POLLHUP; - - poll_wait(file, &dev->read_wait, wait); - poll_wait(file, &dev->write_wait, wait); - - if (dev->ring_head != dev->ring_tail) - mask |= POLLIN | POLLRDNORM; - if (!dev->interrupt_out_busy) - mask |= POLLOUT | POLLWRNORM; - - return mask; -} - -/** - * ld_usb_read - */ -static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count, - loff_t *ppos) -{ - struct ld_usb *dev; - size_t *actual_buffer; - size_t bytes_to_read; - int retval = 0; - int rv; - - dev = file->private_data; - - /* verify that we actually have some data to read */ - if (count == 0) - goto exit; - - /* lock this object */ - if (mutex_lock_interruptible(&dev->mutex)) { - retval = -ERESTARTSYS; - goto exit; - } - - /* verify that the device wasn't unplugged */ - if (dev->intf == NULL) { - retval = -ENODEV; - err("No device or device unplugged %d\n", retval); - goto unlock_exit; - } - - /* wait for data */ - spin_lock_irq(&dev->rbsl); - if (dev->ring_head == dev->ring_tail) { - dev->interrupt_in_done = 0; - spin_unlock_irq(&dev->rbsl); - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - goto unlock_exit; - } - retval = wait_event_interruptible(dev->read_wait, dev->interrupt_in_done); - if (retval < 0) - goto unlock_exit; - } else { - spin_unlock_irq(&dev->rbsl); - } - - /* actual_buffer contains actual_length + interrupt_in_buffer */ - actual_buffer = (size_t*)(dev->ring_buffer + dev->ring_tail*(sizeof(size_t)+dev->interrupt_in_endpoint_size)); - bytes_to_read = min(count, *actual_buffer); - if (bytes_to_read < *actual_buffer) - dev_warn(&dev->intf->dev, "Read buffer overflow, %zd bytes dropped\n", - *actual_buffer-bytes_to_read); - - /* copy one interrupt_in_buffer from ring_buffer into userspace */ - if (copy_to_user(buffer, actual_buffer+1, bytes_to_read)) { - retval = -EFAULT; - goto unlock_exit; - } - dev->ring_tail = (dev->ring_tail+1) % ring_buffer_size; - - retval = bytes_to_read; - - spin_lock_irq(&dev->rbsl); - if (dev->buffer_overflow) { - dev->buffer_overflow = 0; - spin_unlock_irq(&dev->rbsl); - rv = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL); - if (rv < 0) - dev->buffer_overflow = 1; - } else { - spin_unlock_irq(&dev->rbsl); - } - -unlock_exit: - /* unlock the device */ - mutex_unlock(&dev->mutex); - -exit: - return retval; -} - -/** - * ld_usb_write - */ -static ssize_t ld_usb_write(struct file *file, const char __user *buffer, - size_t count, loff_t *ppos) -{ - struct ld_usb *dev; - size_t bytes_to_write; - int retval = 0; - - dev = file->private_data; - - /* verify that we actually have some data to write */ - if (count == 0) - goto exit; - - /* lock this object */ - if (mutex_lock_interruptible(&dev->mutex)) { - retval = -ERESTARTSYS; - goto exit; - } - - /* verify that the device wasn't unplugged */ - if (dev->intf == NULL) { - retval = -ENODEV; - err("No device or device unplugged %d\n", retval); - goto unlock_exit; - } - - /* wait until previous transfer is finished */ - if (dev->interrupt_out_busy) { - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - goto unlock_exit; - } - retval = wait_event_interruptible(dev->write_wait, !dev->interrupt_out_busy); - if (retval < 0) { - goto unlock_exit; - } - } - - /* write the data into interrupt_out_buffer from userspace */ - bytes_to_write = min(count, write_buffer_size*dev->interrupt_out_endpoint_size); - if (bytes_to_write < count) - dev_warn(&dev->intf->dev, "Write buffer overflow, %zd bytes dropped\n",count-bytes_to_write); - dbg_info(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n", __func__, count, bytes_to_write); - - if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) { - retval = -EFAULT; - goto unlock_exit; - } - - if (dev->interrupt_out_endpoint == NULL) { - /* try HID_REQ_SET_REPORT=9 on control_endpoint instead of interrupt_out_endpoint */ - retval = usb_control_msg(interface_to_usbdev(dev->intf), - usb_sndctrlpipe(interface_to_usbdev(dev->intf), 0), - 9, - USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, - 1 << 8, 0, - dev->interrupt_out_buffer, - bytes_to_write, - USB_CTRL_SET_TIMEOUT * HZ); - if (retval < 0) - err("Couldn't submit HID_REQ_SET_REPORT %d\n", retval); - goto unlock_exit; - } - - /* send off the urb */ - usb_fill_int_urb(dev->interrupt_out_urb, - interface_to_usbdev(dev->intf), - usb_sndintpipe(interface_to_usbdev(dev->intf), - dev->interrupt_out_endpoint->bEndpointAddress), - dev->interrupt_out_buffer, - bytes_to_write, - ld_usb_interrupt_out_callback, - dev, - dev->interrupt_out_interval); - - dev->interrupt_out_busy = 1; - wmb(); - - retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL); - if (retval) { - dev->interrupt_out_busy = 0; - err("Couldn't submit interrupt_out_urb %d\n", retval); - goto unlock_exit; - } - retval = bytes_to_write; - -unlock_exit: - /* unlock the device */ - mutex_unlock(&dev->mutex); - -exit: - return retval; -} - -/* file operations needed when we register this driver */ -static const struct file_operations ld_usb_fops = { - .owner = THIS_MODULE, - .read = ld_usb_read, - .write = ld_usb_write, - .open = ld_usb_open, - .release = ld_usb_release, - .poll = ld_usb_poll, - .llseek = no_llseek, -}; - -/* - * usb class driver info in order to get a minor number from the usb core, - * and to have the device registered with the driver core - */ -static struct usb_class_driver ld_usb_class = { - .name = "ldusb%d", - .fops = &ld_usb_fops, - .minor_base = USB_LD_MINOR_BASE, -}; - -/** - * ld_usb_probe - * - * Called by the usb core when a new device is connected that it thinks - * this driver might be interested in. - */ -static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct ld_usb *dev = NULL; - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - char *buffer; - int i; - int retval = -ENOMEM; - - /* allocate memory for our device state and initialize it */ - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - dev_err(&intf->dev, "Out of memory\n"); - goto exit; - } - mutex_init(&dev->mutex); - spin_lock_init(&dev->rbsl); - dev->intf = intf; - init_waitqueue_head(&dev->read_wait); - init_waitqueue_head(&dev->write_wait); - - /* workaround for early firmware versions on fast computers */ - if ((le16_to_cpu(udev->descriptor.idVendor) == USB_VENDOR_ID_LD) && - ((le16_to_cpu(udev->descriptor.idProduct) == USB_DEVICE_ID_LD_CASSY) || - (le16_to_cpu(udev->descriptor.idProduct) == USB_DEVICE_ID_LD_COM3LAB)) && - (le16_to_cpu(udev->descriptor.bcdDevice) <= 0x103)) { - buffer = kmalloc(256, GFP_KERNEL); - if (buffer == NULL) { - dev_err(&intf->dev, "Couldn't allocate string buffer\n"); - goto error; - } - /* usb_string makes SETUP+STALL to leave always ControlReadLoop */ - usb_string(udev, 255, buffer, 256); - kfree(buffer); - } - - iface_desc = intf->cur_altsetting; - - /* set up the endpoint information */ - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - - if (usb_endpoint_is_int_in(endpoint)) - dev->interrupt_in_endpoint = endpoint; - - if (usb_endpoint_is_int_out(endpoint)) - dev->interrupt_out_endpoint = endpoint; - } - if (dev->interrupt_in_endpoint == NULL) { - dev_err(&intf->dev, "Interrupt in endpoint not found\n"); - goto error; - } - if (dev->interrupt_out_endpoint == NULL) - dev_warn(&intf->dev, "Interrupt out endpoint not found (using control endpoint instead)\n"); - - dev->interrupt_in_endpoint_size = usb_endpoint_maxp(dev->interrupt_in_endpoint); - dev->ring_buffer = kmalloc(ring_buffer_size*(sizeof(size_t)+dev->interrupt_in_endpoint_size), GFP_KERNEL); - if (!dev->ring_buffer) { - dev_err(&intf->dev, "Couldn't allocate ring_buffer\n"); - goto error; - } - dev->interrupt_in_buffer = kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL); - if (!dev->interrupt_in_buffer) { - dev_err(&intf->dev, "Couldn't allocate interrupt_in_buffer\n"); - goto error; - } - dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->interrupt_in_urb) { - dev_err(&intf->dev, "Couldn't allocate interrupt_in_urb\n"); - goto error; - } - dev->interrupt_out_endpoint_size = dev->interrupt_out_endpoint ? usb_endpoint_maxp(dev->interrupt_out_endpoint) : - udev->descriptor.bMaxPacketSize0; - dev->interrupt_out_buffer = kmalloc(write_buffer_size*dev->interrupt_out_endpoint_size, GFP_KERNEL); - if (!dev->interrupt_out_buffer) { - dev_err(&intf->dev, "Couldn't allocate interrupt_out_buffer\n"); - goto error; - } - dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->interrupt_out_urb) { - dev_err(&intf->dev, "Couldn't allocate interrupt_out_urb\n"); - goto error; - } - dev->interrupt_in_interval = min_interrupt_in_interval > dev->interrupt_in_endpoint->bInterval ? min_interrupt_in_interval : dev->interrupt_in_endpoint->bInterval; - if (dev->interrupt_out_endpoint) - dev->interrupt_out_interval = min_interrupt_out_interval > dev->interrupt_out_endpoint->bInterval ? min_interrupt_out_interval : dev->interrupt_out_endpoint->bInterval; - - /* we can register the device now, as it is ready */ - usb_set_intfdata(intf, dev); - - retval = usb_register_dev(intf, &ld_usb_class); - if (retval) { - /* something prevented us from registering this driver */ - dev_err(&intf->dev, "Not able to get a minor for this device.\n"); - usb_set_intfdata(intf, NULL); - goto error; - } - - /* let the user know what node this device is now attached to */ - dev_info(&intf->dev, "LD USB Device #%d now attached to major %d minor %d\n", - (intf->minor - USB_LD_MINOR_BASE), USB_MAJOR, intf->minor); - -exit: - return retval; - -error: - ld_usb_delete(dev); - - return retval; -} - -/** - * ld_usb_disconnect - * - * Called by the usb core when the device is removed from the system. - */ -static void ld_usb_disconnect(struct usb_interface *intf) -{ - struct ld_usb *dev; - int minor; - - dev = usb_get_intfdata(intf); - usb_set_intfdata(intf, NULL); - - minor = intf->minor; - - /* give back our minor */ - usb_deregister_dev(intf, &ld_usb_class); - - mutex_lock(&dev->mutex); - - /* if the device is not opened, then we clean up right now */ - if (!dev->open_count) { - mutex_unlock(&dev->mutex); - ld_usb_delete(dev); - } else { - dev->intf = NULL; - /* wake up pollers */ - wake_up_interruptible_all(&dev->read_wait); - wake_up_interruptible_all(&dev->write_wait); - mutex_unlock(&dev->mutex); - } - - dev_info(&intf->dev, "LD USB Device #%d now disconnected\n", - (minor - USB_LD_MINOR_BASE)); -} - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver ld_usb_driver = { - .name = "ldusb", - .probe = ld_usb_probe, - .disconnect = ld_usb_disconnect, - .id_table = ld_usb_table, -}; - -module_usb_driver(ld_usb_driver); - diff --git a/ANDROID_3.4.5/drivers/usb/misc/legousbtower.c b/ANDROID_3.4.5/drivers/usb/misc/legousbtower.c deleted file mode 100644 index 57522204..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/legousbtower.c +++ /dev/null @@ -1,1052 +0,0 @@ -/* - * LEGO USB Tower driver - * - * Copyright (C) 2003 David Glance - * 2001-2004 Juergen Stuber - * - * 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. - * - * derived from USB Skeleton driver - 0.5 - * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) - * - * History: - * - * 2001-10-13 - 0.1 js - * - first version - * 2001-11-03 - 0.2 js - * - simplified buffering, one-shot URBs for writing - * 2001-11-10 - 0.3 js - * - removed IOCTL (setting power/mode is more complicated, postponed) - * 2001-11-28 - 0.4 js - * - added vendor commands for mode of operation and power level in open - * 2001-12-04 - 0.5 js - * - set IR mode by default (by oversight 0.4 set VLL mode) - * 2002-01-11 - 0.5? pcchan - * - make read buffer reusable and work around bytes_to_write issue between - * uhci and legusbtower - * 2002-09-23 - 0.52 david (david@csse.uwa.edu.au) - * - imported into lejos project - * - changed wake_up to wake_up_interruptible - * - changed to use lego0 rather than tower0 - * - changed dbg() to use __func__ rather than deprecated __func__ - * 2003-01-12 - 0.53 david (david@csse.uwa.edu.au) - * - changed read and write to write everything or - * timeout (from a patch by Chris Riesen and Brett Thaeler driver) - * - added ioctl functionality to set timeouts - * 2003-07-18 - 0.54 davidgsf (david@csse.uwa.edu.au) - * - initial import into LegoUSB project - * - merge of existing LegoUSB.c driver - * 2003-07-18 - 0.56 davidgsf (david@csse.uwa.edu.au) - * - port to 2.6 style driver - * 2004-02-29 - 0.6 Juergen Stuber - * - fix locking - * - unlink read URBs which are no longer needed - * - allow increased buffer size, eliminates need for timeout on write - * - have read URB running continuously - * - added poll - * - forbid seeking - * - added nonblocking I/O - * - changed back __func__ to __func__ - * - read and log tower firmware version - * - reset tower on probe, avoids failure of first write - * 2004-03-09 - 0.7 Juergen Stuber - * - timeout read now only after inactivity, shorten default accordingly - * 2004-03-11 - 0.8 Juergen Stuber - * - log major, minor instead of possibly confusing device filename - * - whitespace cleanup - * 2004-03-12 - 0.9 Juergen Stuber - * - normalize whitespace in debug messages - * - take care about endianness in control message responses - * 2004-03-13 - 0.91 Juergen Stuber - * - make default intervals longer to accommodate current EHCI driver - * 2004-03-19 - 0.92 Juergen Stuber - * - replaced atomic_t by memory barriers - * 2004-04-21 - 0.93 Juergen Stuber - * - wait for completion of write urb in release (needed for remotecontrol) - * - corrected poll for write direction (missing negation) - * 2004-04-22 - 0.94 Juergen Stuber - * - make device locking interruptible - * 2004-04-30 - 0.95 Juergen Stuber - * - check for valid udev on resubmitting and unlinking urbs - * 2004-08-03 - 0.96 Juergen Stuber - * - move reset into open to clean out spurious data - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#ifdef CONFIG_USB_DEBUG - static int debug = 4; -#else - static int debug = 0; -#endif - -/* Use our own dbg macro */ -#undef dbg -#define dbg(lvl, format, arg...) \ -do { \ - if (debug >= lvl) \ - printk(KERN_DEBUG "%s: " format "\n", __FILE__, ##arg); \ -} while (0) - -/* Version Information */ -#define DRIVER_VERSION "v0.96" -#define DRIVER_AUTHOR "Juergen Stuber " -#define DRIVER_DESC "LEGO USB Tower Driver" - -/* Module parameters */ -module_param(debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - -/* The defaults are chosen to work with the latest versions of leJOS and NQC. - */ - -/* Some legacy software likes to receive packets in one piece. - * In this case read_buffer_size should exceed the maximal packet length - * (417 for datalog uploads), and packet_timeout should be set. - */ -static int read_buffer_size = 480; -module_param(read_buffer_size, int, 0); -MODULE_PARM_DESC(read_buffer_size, "Read buffer size"); - -/* Some legacy software likes to send packets in one piece. - * In this case write_buffer_size should exceed the maximal packet length - * (417 for firmware and program downloads). - * A problem with long writes is that the following read may time out - * if the software is not prepared to wait long enough. - */ -static int write_buffer_size = 480; -module_param(write_buffer_size, int, 0); -MODULE_PARM_DESC(write_buffer_size, "Write buffer size"); - -/* Some legacy software expects reads to contain whole LASM packets. - * To achieve this, characters which arrive before a packet timeout - * occurs will be returned in a single read operation. - * A problem with long reads is that the software may time out - * if it is not prepared to wait long enough. - * The packet timeout should be greater than the time between the - * reception of subsequent characters, which should arrive about - * every 5ms for the standard 2400 baud. - * Set it to 0 to disable. - */ -static int packet_timeout = 50; -module_param(packet_timeout, int, 0); -MODULE_PARM_DESC(packet_timeout, "Packet timeout in ms"); - -/* Some legacy software expects blocking reads to time out. - * Timeout occurs after the specified time of read and write inactivity. - * Set it to 0 to disable. - */ -static int read_timeout = 200; -module_param(read_timeout, int, 0); -MODULE_PARM_DESC(read_timeout, "Read timeout in ms"); - -/* As of kernel version 2.6.4 ehci-hcd uses an - * "only one interrupt transfer per frame" shortcut - * to simplify the scheduling of periodic transfers. - * This conflicts with our standard 1ms intervals for in and out URBs. - * We use default intervals of 2ms for in and 8ms for out transfers, - * which is fast enough for 2400 baud and allows a small additional load. - * Increase the interval to allow more devices that do interrupt transfers, - * or set to 0 to use the standard interval from the endpoint descriptors. - */ -static int interrupt_in_interval = 2; -module_param(interrupt_in_interval, int, 0); -MODULE_PARM_DESC(interrupt_in_interval, "Interrupt in interval in ms"); - -static int interrupt_out_interval = 8; -module_param(interrupt_out_interval, int, 0); -MODULE_PARM_DESC(interrupt_out_interval, "Interrupt out interval in ms"); - -/* Define these values to match your device */ -#define LEGO_USB_TOWER_VENDOR_ID 0x0694 -#define LEGO_USB_TOWER_PRODUCT_ID 0x0001 - -/* Vendor requests */ -#define LEGO_USB_TOWER_REQUEST_RESET 0x04 -#define LEGO_USB_TOWER_REQUEST_GET_VERSION 0xFD - -struct tower_reset_reply { - __le16 size; /* little-endian */ - __u8 err_code; - __u8 spare; -} __attribute__ ((packed)); - -struct tower_get_version_reply { - __le16 size; /* little-endian */ - __u8 err_code; - __u8 spare; - __u8 major; - __u8 minor; - __le16 build_no; /* little-endian */ -} __attribute__ ((packed)); - - -/* table of devices that work with this driver */ -static const struct usb_device_id tower_table[] = { - { USB_DEVICE(LEGO_USB_TOWER_VENDOR_ID, LEGO_USB_TOWER_PRODUCT_ID) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, tower_table); -static DEFINE_MUTEX(open_disc_mutex); - -#define LEGO_USB_TOWER_MINOR_BASE 160 - - -/* Structure to hold all of our device specific stuff */ -struct lego_usb_tower { - struct mutex lock; /* locks this structure */ - struct usb_device* udev; /* save off the usb device pointer */ - unsigned char minor; /* the starting minor number for this device */ - - int open_count; /* number of times this port has been opened */ - - char* read_buffer; - size_t read_buffer_length; /* this much came in */ - size_t read_packet_length; /* this much will be returned on read */ - spinlock_t read_buffer_lock; - int packet_timeout_jiffies; - unsigned long read_last_arrival; - - wait_queue_head_t read_wait; - wait_queue_head_t write_wait; - - char* interrupt_in_buffer; - struct usb_endpoint_descriptor* interrupt_in_endpoint; - struct urb* interrupt_in_urb; - int interrupt_in_interval; - int interrupt_in_running; - int interrupt_in_done; - - char* interrupt_out_buffer; - struct usb_endpoint_descriptor* interrupt_out_endpoint; - struct urb* interrupt_out_urb; - int interrupt_out_interval; - int interrupt_out_busy; - -}; - - -/* local function prototypes */ -static ssize_t tower_read (struct file *file, char __user *buffer, size_t count, loff_t *ppos); -static ssize_t tower_write (struct file *file, const char __user *buffer, size_t count, loff_t *ppos); -static inline void tower_delete (struct lego_usb_tower *dev); -static int tower_open (struct inode *inode, struct file *file); -static int tower_release (struct inode *inode, struct file *file); -static unsigned int tower_poll (struct file *file, poll_table *wait); -static loff_t tower_llseek (struct file *file, loff_t off, int whence); - -static void tower_abort_transfers (struct lego_usb_tower *dev); -static void tower_check_for_read_packet (struct lego_usb_tower *dev); -static void tower_interrupt_in_callback (struct urb *urb); -static void tower_interrupt_out_callback (struct urb *urb); - -static int tower_probe (struct usb_interface *interface, const struct usb_device_id *id); -static void tower_disconnect (struct usb_interface *interface); - - -/* file operations needed when we register this driver */ -static const struct file_operations tower_fops = { - .owner = THIS_MODULE, - .read = tower_read, - .write = tower_write, - .open = tower_open, - .release = tower_release, - .poll = tower_poll, - .llseek = tower_llseek, -}; - -static char *legousbtower_devnode(struct device *dev, umode_t *mode) -{ - return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev)); -} - -/* - * usb class driver info in order to get a minor number from the usb core, - * and to have the device registered with the driver core - */ -static struct usb_class_driver tower_class = { - .name = "legousbtower%d", - .devnode = legousbtower_devnode, - .fops = &tower_fops, - .minor_base = LEGO_USB_TOWER_MINOR_BASE, -}; - - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver tower_driver = { - .name = "legousbtower", - .probe = tower_probe, - .disconnect = tower_disconnect, - .id_table = tower_table, -}; - - -/** - * lego_usb_tower_debug_data - */ -static inline void lego_usb_tower_debug_data (int level, const char *function, int size, const unsigned char *data) -{ - int i; - - if (debug < level) - return; - - printk (KERN_DEBUG "%s: %s - length = %d, data = ", __FILE__, function, size); - for (i = 0; i < size; ++i) { - printk ("%.2x ", data[i]); - } - printk ("\n"); -} - - -/** - * tower_delete - */ -static inline void tower_delete (struct lego_usb_tower *dev) -{ - dbg(2, "%s: enter", __func__); - - tower_abort_transfers (dev); - - /* free data structures */ - usb_free_urb(dev->interrupt_in_urb); - usb_free_urb(dev->interrupt_out_urb); - kfree (dev->read_buffer); - kfree (dev->interrupt_in_buffer); - kfree (dev->interrupt_out_buffer); - kfree (dev); - - dbg(2, "%s: leave", __func__); -} - - -/** - * tower_open - */ -static int tower_open (struct inode *inode, struct file *file) -{ - struct lego_usb_tower *dev = NULL; - int subminor; - int retval = 0; - struct usb_interface *interface; - struct tower_reset_reply reset_reply; - int result; - - dbg(2, "%s: enter", __func__); - - nonseekable_open(inode, file); - subminor = iminor(inode); - - interface = usb_find_interface (&tower_driver, subminor); - - if (!interface) { - err ("%s - error, can't find device for minor %d", - __func__, subminor); - retval = -ENODEV; - goto exit; - } - - mutex_lock(&open_disc_mutex); - dev = usb_get_intfdata(interface); - - if (!dev) { - mutex_unlock(&open_disc_mutex); - retval = -ENODEV; - goto exit; - } - - /* lock this device */ - if (mutex_lock_interruptible(&dev->lock)) { - mutex_unlock(&open_disc_mutex); - retval = -ERESTARTSYS; - goto exit; - } - - - /* allow opening only once */ - if (dev->open_count) { - mutex_unlock(&open_disc_mutex); - retval = -EBUSY; - goto unlock_exit; - } - dev->open_count = 1; - mutex_unlock(&open_disc_mutex); - - /* reset the tower */ - result = usb_control_msg (dev->udev, - usb_rcvctrlpipe(dev->udev, 0), - LEGO_USB_TOWER_REQUEST_RESET, - USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, - 0, - 0, - &reset_reply, - sizeof(reset_reply), - 1000); - if (result < 0) { - err("LEGO USB Tower reset control request failed"); - retval = result; - goto unlock_exit; - } - - /* initialize in direction */ - dev->read_buffer_length = 0; - dev->read_packet_length = 0; - usb_fill_int_urb (dev->interrupt_in_urb, - dev->udev, - usb_rcvintpipe(dev->udev, dev->interrupt_in_endpoint->bEndpointAddress), - dev->interrupt_in_buffer, - usb_endpoint_maxp(dev->interrupt_in_endpoint), - tower_interrupt_in_callback, - dev, - dev->interrupt_in_interval); - - dev->interrupt_in_running = 1; - dev->interrupt_in_done = 0; - mb(); - - retval = usb_submit_urb (dev->interrupt_in_urb, GFP_KERNEL); - if (retval) { - err("Couldn't submit interrupt_in_urb %d", retval); - dev->interrupt_in_running = 0; - dev->open_count = 0; - goto unlock_exit; - } - - /* save device in the file's private structure */ - file->private_data = dev; - -unlock_exit: - mutex_unlock(&dev->lock); - -exit: - dbg(2, "%s: leave, return value %d ", __func__, retval); - - return retval; -} - -/** - * tower_release - */ -static int tower_release (struct inode *inode, struct file *file) -{ - struct lego_usb_tower *dev; - int retval = 0; - - dbg(2, "%s: enter", __func__); - - dev = file->private_data; - - if (dev == NULL) { - dbg(1, "%s: object is NULL", __func__); - retval = -ENODEV; - goto exit_nolock; - } - - mutex_lock(&open_disc_mutex); - if (mutex_lock_interruptible(&dev->lock)) { - retval = -ERESTARTSYS; - goto exit; - } - - if (dev->open_count != 1) { - dbg(1, "%s: device not opened exactly once", __func__); - retval = -ENODEV; - goto unlock_exit; - } - if (dev->udev == NULL) { - /* the device was unplugged before the file was released */ - - /* unlock here as tower_delete frees dev */ - mutex_unlock(&dev->lock); - tower_delete (dev); - goto exit; - } - - /* wait until write transfer is finished */ - if (dev->interrupt_out_busy) { - wait_event_interruptible_timeout (dev->write_wait, !dev->interrupt_out_busy, 2 * HZ); - } - tower_abort_transfers (dev); - dev->open_count = 0; - -unlock_exit: - mutex_unlock(&dev->lock); - -exit: - mutex_unlock(&open_disc_mutex); -exit_nolock: - dbg(2, "%s: leave, return value %d", __func__, retval); - return retval; -} - - -/** - * tower_abort_transfers - * aborts transfers and frees associated data structures - */ -static void tower_abort_transfers (struct lego_usb_tower *dev) -{ - dbg(2, "%s: enter", __func__); - - if (dev == NULL) { - dbg(1, "%s: dev is null", __func__); - goto exit; - } - - /* shutdown transfer */ - if (dev->interrupt_in_running) { - dev->interrupt_in_running = 0; - mb(); - if (dev->udev) - usb_kill_urb (dev->interrupt_in_urb); - } - if (dev->interrupt_out_busy && dev->udev) - usb_kill_urb(dev->interrupt_out_urb); - -exit: - dbg(2, "%s: leave", __func__); -} - - -/** - * tower_check_for_read_packet - * - * To get correct semantics for signals and non-blocking I/O - * with packetizing we pretend not to see any data in the read buffer - * until it has been there unchanged for at least - * dev->packet_timeout_jiffies, or until the buffer is full. - */ -static void tower_check_for_read_packet (struct lego_usb_tower *dev) -{ - spin_lock_irq (&dev->read_buffer_lock); - if (!packet_timeout - || time_after(jiffies, dev->read_last_arrival + dev->packet_timeout_jiffies) - || dev->read_buffer_length == read_buffer_size) { - dev->read_packet_length = dev->read_buffer_length; - } - dev->interrupt_in_done = 0; - spin_unlock_irq (&dev->read_buffer_lock); -} - - -/** - * tower_poll - */ -static unsigned int tower_poll (struct file *file, poll_table *wait) -{ - struct lego_usb_tower *dev; - unsigned int mask = 0; - - dbg(2, "%s: enter", __func__); - - dev = file->private_data; - - if (!dev->udev) - return POLLERR | POLLHUP; - - poll_wait(file, &dev->read_wait, wait); - poll_wait(file, &dev->write_wait, wait); - - tower_check_for_read_packet(dev); - if (dev->read_packet_length > 0) { - mask |= POLLIN | POLLRDNORM; - } - if (!dev->interrupt_out_busy) { - mask |= POLLOUT | POLLWRNORM; - } - - dbg(2, "%s: leave, mask = %d", __func__, mask); - - return mask; -} - - -/** - * tower_llseek - */ -static loff_t tower_llseek (struct file *file, loff_t off, int whence) -{ - return -ESPIPE; /* unseekable */ -} - - -/** - * tower_read - */ -static ssize_t tower_read (struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - struct lego_usb_tower *dev; - size_t bytes_to_read; - int i; - int retval = 0; - unsigned long timeout = 0; - - dbg(2, "%s: enter, count = %Zd", __func__, count); - - dev = file->private_data; - - /* lock this object */ - if (mutex_lock_interruptible(&dev->lock)) { - retval = -ERESTARTSYS; - goto exit; - } - - /* verify that the device wasn't unplugged */ - if (dev->udev == NULL) { - retval = -ENODEV; - err("No device or device unplugged %d", retval); - goto unlock_exit; - } - - /* verify that we actually have some data to read */ - if (count == 0) { - dbg(1, "%s: read request of 0 bytes", __func__); - goto unlock_exit; - } - - if (read_timeout) { - timeout = jiffies + read_timeout * HZ / 1000; - } - - /* wait for data */ - tower_check_for_read_packet (dev); - while (dev->read_packet_length == 0) { - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - goto unlock_exit; - } - retval = wait_event_interruptible_timeout(dev->read_wait, dev->interrupt_in_done, dev->packet_timeout_jiffies); - if (retval < 0) { - goto unlock_exit; - } - - /* reset read timeout during read or write activity */ - if (read_timeout - && (dev->read_buffer_length || dev->interrupt_out_busy)) { - timeout = jiffies + read_timeout * HZ / 1000; - } - /* check for read timeout */ - if (read_timeout && time_after (jiffies, timeout)) { - retval = -ETIMEDOUT; - goto unlock_exit; - } - tower_check_for_read_packet (dev); - } - - /* copy the data from read_buffer into userspace */ - bytes_to_read = min(count, dev->read_packet_length); - - if (copy_to_user (buffer, dev->read_buffer, bytes_to_read)) { - retval = -EFAULT; - goto unlock_exit; - } - - spin_lock_irq (&dev->read_buffer_lock); - dev->read_buffer_length -= bytes_to_read; - dev->read_packet_length -= bytes_to_read; - for (i=0; iread_buffer_length; i++) { - dev->read_buffer[i] = dev->read_buffer[i+bytes_to_read]; - } - spin_unlock_irq (&dev->read_buffer_lock); - - retval = bytes_to_read; - -unlock_exit: - /* unlock the device */ - mutex_unlock(&dev->lock); - -exit: - dbg(2, "%s: leave, return value %d", __func__, retval); - return retval; -} - - -/** - * tower_write - */ -static ssize_t tower_write (struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct lego_usb_tower *dev; - size_t bytes_to_write; - int retval = 0; - - dbg(2, "%s: enter, count = %Zd", __func__, count); - - dev = file->private_data; - - /* lock this object */ - if (mutex_lock_interruptible(&dev->lock)) { - retval = -ERESTARTSYS; - goto exit; - } - - /* verify that the device wasn't unplugged */ - if (dev->udev == NULL) { - retval = -ENODEV; - err("No device or device unplugged %d", retval); - goto unlock_exit; - } - - /* verify that we actually have some data to write */ - if (count == 0) { - dbg(1, "%s: write request of 0 bytes", __func__); - goto unlock_exit; - } - - /* wait until previous transfer is finished */ - while (dev->interrupt_out_busy) { - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - goto unlock_exit; - } - retval = wait_event_interruptible (dev->write_wait, !dev->interrupt_out_busy); - if (retval) { - goto unlock_exit; - } - } - - /* write the data into interrupt_out_buffer from userspace */ - bytes_to_write = min_t(int, count, write_buffer_size); - dbg(4, "%s: count = %Zd, bytes_to_write = %Zd", __func__, count, bytes_to_write); - - if (copy_from_user (dev->interrupt_out_buffer, buffer, bytes_to_write)) { - retval = -EFAULT; - goto unlock_exit; - } - - /* send off the urb */ - usb_fill_int_urb(dev->interrupt_out_urb, - dev->udev, - usb_sndintpipe(dev->udev, dev->interrupt_out_endpoint->bEndpointAddress), - dev->interrupt_out_buffer, - bytes_to_write, - tower_interrupt_out_callback, - dev, - dev->interrupt_out_interval); - - dev->interrupt_out_busy = 1; - wmb(); - - retval = usb_submit_urb (dev->interrupt_out_urb, GFP_KERNEL); - if (retval) { - dev->interrupt_out_busy = 0; - err("Couldn't submit interrupt_out_urb %d", retval); - goto unlock_exit; - } - retval = bytes_to_write; - -unlock_exit: - /* unlock the device */ - mutex_unlock(&dev->lock); - -exit: - dbg(2, "%s: leave, return value %d", __func__, retval); - - return retval; -} - - -/** - * tower_interrupt_in_callback - */ -static void tower_interrupt_in_callback (struct urb *urb) -{ - struct lego_usb_tower *dev = urb->context; - int status = urb->status; - int retval; - - dbg(4, "%s: enter, status %d", __func__, status); - - lego_usb_tower_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer); - - if (status) { - if (status == -ENOENT || - status == -ECONNRESET || - status == -ESHUTDOWN) { - goto exit; - } else { - dbg(1, "%s: nonzero status received: %d", __func__, status); - goto resubmit; /* maybe we can recover */ - } - } - - if (urb->actual_length > 0) { - spin_lock (&dev->read_buffer_lock); - if (dev->read_buffer_length + urb->actual_length < read_buffer_size) { - memcpy (dev->read_buffer + dev->read_buffer_length, - dev->interrupt_in_buffer, - urb->actual_length); - dev->read_buffer_length += urb->actual_length; - dev->read_last_arrival = jiffies; - dbg(3, "%s: received %d bytes", __func__, urb->actual_length); - } else { - printk(KERN_WARNING "%s: read_buffer overflow, %d bytes dropped", __func__, urb->actual_length); - } - spin_unlock (&dev->read_buffer_lock); - } - -resubmit: - /* resubmit if we're still running */ - if (dev->interrupt_in_running && dev->udev) { - retval = usb_submit_urb (dev->interrupt_in_urb, GFP_ATOMIC); - if (retval) { - err("%s: usb_submit_urb failed (%d)", __func__, retval); - } - } - -exit: - dev->interrupt_in_done = 1; - wake_up_interruptible (&dev->read_wait); - - lego_usb_tower_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer); - dbg(4, "%s: leave, status %d", __func__, status); -} - - -/** - * tower_interrupt_out_callback - */ -static void tower_interrupt_out_callback (struct urb *urb) -{ - struct lego_usb_tower *dev = urb->context; - int status = urb->status; - - dbg(4, "%s: enter, status %d", __func__, status); - lego_usb_tower_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer); - - /* sync/async unlink faults aren't errors */ - if (status && !(status == -ENOENT || - status == -ECONNRESET || - status == -ESHUTDOWN)) { - dbg(1, "%s - nonzero write bulk status received: %d", - __func__, status); - } - - dev->interrupt_out_busy = 0; - wake_up_interruptible(&dev->write_wait); - - lego_usb_tower_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer); - dbg(4, "%s: leave, status %d", __func__, status); -} - - -/** - * tower_probe - * - * Called by the usb core when a new device is connected that it thinks - * this driver might be interested in. - */ -static int tower_probe (struct usb_interface *interface, const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(interface); - struct lego_usb_tower *dev = NULL; - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor* endpoint; - struct tower_get_version_reply get_version_reply; - int i; - int retval = -ENOMEM; - int result; - - dbg(2, "%s: enter", __func__); - - if (udev == NULL) - dev_info(&interface->dev, "udev is NULL.\n"); - - /* allocate memory for our device state and initialize it */ - - dev = kmalloc (sizeof(struct lego_usb_tower), GFP_KERNEL); - - if (dev == NULL) { - err ("Out of memory"); - goto exit; - } - - mutex_init(&dev->lock); - - dev->udev = udev; - dev->open_count = 0; - - dev->read_buffer = NULL; - dev->read_buffer_length = 0; - dev->read_packet_length = 0; - spin_lock_init (&dev->read_buffer_lock); - dev->packet_timeout_jiffies = packet_timeout * HZ / 1000; - dev->read_last_arrival = jiffies; - - init_waitqueue_head (&dev->read_wait); - init_waitqueue_head (&dev->write_wait); - - dev->interrupt_in_buffer = NULL; - dev->interrupt_in_endpoint = NULL; - dev->interrupt_in_urb = NULL; - dev->interrupt_in_running = 0; - dev->interrupt_in_done = 0; - - dev->interrupt_out_buffer = NULL; - dev->interrupt_out_endpoint = NULL; - dev->interrupt_out_urb = NULL; - dev->interrupt_out_busy = 0; - - iface_desc = interface->cur_altsetting; - - /* set up the endpoint information */ - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - - if (usb_endpoint_xfer_int(endpoint)) { - if (usb_endpoint_dir_in(endpoint)) - dev->interrupt_in_endpoint = endpoint; - else - dev->interrupt_out_endpoint = endpoint; - } - } - if(dev->interrupt_in_endpoint == NULL) { - err("interrupt in endpoint not found"); - goto error; - } - if (dev->interrupt_out_endpoint == NULL) { - err("interrupt out endpoint not found"); - goto error; - } - - dev->read_buffer = kmalloc (read_buffer_size, GFP_KERNEL); - if (!dev->read_buffer) { - err("Couldn't allocate read_buffer"); - goto error; - } - dev->interrupt_in_buffer = kmalloc (usb_endpoint_maxp(dev->interrupt_in_endpoint), GFP_KERNEL); - if (!dev->interrupt_in_buffer) { - err("Couldn't allocate interrupt_in_buffer"); - goto error; - } - dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->interrupt_in_urb) { - err("Couldn't allocate interrupt_in_urb"); - goto error; - } - dev->interrupt_out_buffer = kmalloc (write_buffer_size, GFP_KERNEL); - if (!dev->interrupt_out_buffer) { - err("Couldn't allocate interrupt_out_buffer"); - goto error; - } - dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->interrupt_out_urb) { - err("Couldn't allocate interrupt_out_urb"); - goto error; - } - dev->interrupt_in_interval = interrupt_in_interval ? interrupt_in_interval : dev->interrupt_in_endpoint->bInterval; - dev->interrupt_out_interval = interrupt_out_interval ? interrupt_out_interval : dev->interrupt_out_endpoint->bInterval; - - /* we can register the device now, as it is ready */ - usb_set_intfdata (interface, dev); - - retval = usb_register_dev (interface, &tower_class); - - if (retval) { - /* something prevented us from registering this driver */ - err ("Not able to get a minor for this device."); - usb_set_intfdata (interface, NULL); - goto error; - } - dev->minor = interface->minor; - - /* let the user know what node this device is now attached to */ - dev_info(&interface->dev, "LEGO USB Tower #%d now attached to major " - "%d minor %d\n", (dev->minor - LEGO_USB_TOWER_MINOR_BASE), - USB_MAJOR, dev->minor); - - /* get the firmware version and log it */ - result = usb_control_msg (udev, - usb_rcvctrlpipe(udev, 0), - LEGO_USB_TOWER_REQUEST_GET_VERSION, - USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, - 0, - 0, - &get_version_reply, - sizeof(get_version_reply), - 1000); - if (result < 0) { - err("LEGO USB Tower get version control request failed"); - retval = result; - goto error; - } - dev_info(&interface->dev, "LEGO USB Tower firmware version is %d.%d " - "build %d\n", get_version_reply.major, - get_version_reply.minor, - le16_to_cpu(get_version_reply.build_no)); - - -exit: - dbg(2, "%s: leave, return value 0x%.8lx (dev)", __func__, (long) dev); - - return retval; - -error: - tower_delete(dev); - return retval; -} - - -/** - * tower_disconnect - * - * Called by the usb core when the device is removed from the system. - */ -static void tower_disconnect (struct usb_interface *interface) -{ - struct lego_usb_tower *dev; - int minor; - - dbg(2, "%s: enter", __func__); - - dev = usb_get_intfdata (interface); - mutex_lock(&open_disc_mutex); - usb_set_intfdata (interface, NULL); - - minor = dev->minor; - - /* give back our minor */ - usb_deregister_dev (interface, &tower_class); - - mutex_lock(&dev->lock); - mutex_unlock(&open_disc_mutex); - - /* if the device is not opened, then we clean up right now */ - if (!dev->open_count) { - mutex_unlock(&dev->lock); - tower_delete (dev); - } else { - dev->udev = NULL; - /* wake up pollers */ - wake_up_interruptible_all(&dev->read_wait); - wake_up_interruptible_all(&dev->write_wait); - mutex_unlock(&dev->lock); - } - - dev_info(&interface->dev, "LEGO USB Tower #%d now disconnected\n", - (minor - LEGO_USB_TOWER_MINOR_BASE)); - - dbg(2, "%s: leave", __func__); -} - -module_usb_driver(tower_driver); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif diff --git a/ANDROID_3.4.5/drivers/usb/misc/rio500.c b/ANDROID_3.4.5/drivers/usb/misc/rio500.c deleted file mode 100644 index 487a8ce0..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/rio500.c +++ /dev/null @@ -1,539 +0,0 @@ -/* -*- linux-c -*- */ - -/* - * Driver for USB Rio 500 - * - * Cesar Miquel (miquel@df.uba.ar) - * - * based on hp_scanner.c by David E. Nelson (dnelson@jump.net) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Based upon mouse.c (Brad Keryan) and printer.c (Michael Gee). - * - * Changelog: - * 30/05/2003 replaced lock/unlock kernel with up/down - * Daniele Bellucci bellucda@tiscali.it - * */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rio500_usb.h" - -/* - * Version Information - */ -#define DRIVER_VERSION "v1.1" -#define DRIVER_AUTHOR "Cesar Miquel " -#define DRIVER_DESC "USB Rio 500 driver" - -#define RIO_MINOR 64 - -/* stall/wait timeout for rio */ -#define NAK_TIMEOUT (HZ) - -#define IBUF_SIZE 0x1000 - -/* Size of the rio buffer */ -#define OBUF_SIZE 0x10000 - -struct rio_usb_data { - struct usb_device *rio_dev; /* init: probe_rio */ - unsigned int ifnum; /* Interface number of the USB device */ - int isopen; /* nz if open */ - int present; /* Device is present on the bus */ - char *obuf, *ibuf; /* transfer buffers */ - char bulk_in_ep, bulk_out_ep; /* Endpoint assignments */ - wait_queue_head_t wait_q; /* for timeouts */ - struct mutex lock; /* general race avoidance */ -}; - -static DEFINE_MUTEX(rio500_mutex); -static struct rio_usb_data rio_instance; - -static int open_rio(struct inode *inode, struct file *file) -{ - struct rio_usb_data *rio = &rio_instance; - - /* against disconnect() */ - mutex_lock(&rio500_mutex); - mutex_lock(&(rio->lock)); - - if (rio->isopen || !rio->present) { - mutex_unlock(&(rio->lock)); - mutex_unlock(&rio500_mutex); - return -EBUSY; - } - rio->isopen = 1; - - init_waitqueue_head(&rio->wait_q); - - mutex_unlock(&(rio->lock)); - - dev_info(&rio->rio_dev->dev, "Rio opened.\n"); - mutex_unlock(&rio500_mutex); - - return 0; -} - -static int close_rio(struct inode *inode, struct file *file) -{ - struct rio_usb_data *rio = &rio_instance; - - rio->isopen = 0; - - dev_info(&rio->rio_dev->dev, "Rio closed.\n"); - return 0; -} - -static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct RioCommand rio_cmd; - struct rio_usb_data *rio = &rio_instance; - void __user *data; - unsigned char *buffer; - int result, requesttype; - int retries; - int retval=0; - - mutex_lock(&(rio->lock)); - /* Sanity check to make sure rio is connected, powered, etc */ - if (rio->present == 0 || rio->rio_dev == NULL) { - retval = -ENODEV; - goto err_out; - } - - switch (cmd) { - case RIO_RECV_COMMAND: - data = (void __user *) arg; - if (data == NULL) - break; - if (copy_from_user(&rio_cmd, data, sizeof(struct RioCommand))) { - retval = -EFAULT; - goto err_out; - } - if (rio_cmd.length < 0 || rio_cmd.length > PAGE_SIZE) { - retval = -EINVAL; - goto err_out; - } - buffer = (unsigned char *) __get_free_page(GFP_KERNEL); - if (buffer == NULL) { - retval = -ENOMEM; - goto err_out; - } - if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length)) { - retval = -EFAULT; - free_page((unsigned long) buffer); - goto err_out; - } - - requesttype = rio_cmd.requesttype | USB_DIR_IN | - USB_TYPE_VENDOR | USB_RECIP_DEVICE; - dbg - ("sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x", - requesttype, rio_cmd.request, rio_cmd.value, - rio_cmd.index, rio_cmd.length); - /* Send rio control message */ - retries = 3; - while (retries) { - result = usb_control_msg(rio->rio_dev, - usb_rcvctrlpipe(rio-> rio_dev, 0), - rio_cmd.request, - requesttype, - rio_cmd.value, - rio_cmd.index, buffer, - rio_cmd.length, - jiffies_to_msecs(rio_cmd.timeout)); - if (result == -ETIMEDOUT) - retries--; - else if (result < 0) { - err("Error executing ioctrl. code = %d", result); - retries = 0; - } else { - dbg("Executed ioctl. Result = %d (data=%02x)", - result, buffer[0]); - if (copy_to_user(rio_cmd.buffer, buffer, - rio_cmd.length)) { - free_page((unsigned long) buffer); - retval = -EFAULT; - goto err_out; - } - retries = 0; - } - - /* rio_cmd.buffer contains a raw stream of single byte - data which has been returned from rio. Data is - interpreted at application level. For data that - will be cast to data types longer than 1 byte, data - will be little_endian and will potentially need to - be swapped at the app level */ - - } - free_page((unsigned long) buffer); - break; - - case RIO_SEND_COMMAND: - data = (void __user *) arg; - if (data == NULL) - break; - if (copy_from_user(&rio_cmd, data, sizeof(struct RioCommand))) { - retval = -EFAULT; - goto err_out; - } - if (rio_cmd.length < 0 || rio_cmd.length > PAGE_SIZE) { - retval = -EINVAL; - goto err_out; - } - buffer = (unsigned char *) __get_free_page(GFP_KERNEL); - if (buffer == NULL) { - retval = -ENOMEM; - goto err_out; - } - if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length)) { - free_page((unsigned long)buffer); - retval = -EFAULT; - goto err_out; - } - - requesttype = rio_cmd.requesttype | USB_DIR_OUT | - USB_TYPE_VENDOR | USB_RECIP_DEVICE; - dbg("sending command: reqtype=%0x req=%0x value=%0x index=%0x len=%0x", - requesttype, rio_cmd.request, rio_cmd.value, - rio_cmd.index, rio_cmd.length); - /* Send rio control message */ - retries = 3; - while (retries) { - result = usb_control_msg(rio->rio_dev, - usb_sndctrlpipe(rio-> rio_dev, 0), - rio_cmd.request, - requesttype, - rio_cmd.value, - rio_cmd.index, buffer, - rio_cmd.length, - jiffies_to_msecs(rio_cmd.timeout)); - if (result == -ETIMEDOUT) - retries--; - else if (result < 0) { - err("Error executing ioctrl. code = %d", result); - retries = 0; - } else { - dbg("Executed ioctl. Result = %d", result); - retries = 0; - - } - - } - free_page((unsigned long) buffer); - break; - - default: - retval = -ENOTTY; - break; - } - - -err_out: - mutex_unlock(&(rio->lock)); - return retval; -} - -static ssize_t -write_rio(struct file *file, const char __user *buffer, - size_t count, loff_t * ppos) -{ - DEFINE_WAIT(wait); - struct rio_usb_data *rio = &rio_instance; - - unsigned long copy_size; - unsigned long bytes_written = 0; - unsigned int partial; - - int result = 0; - int maxretry; - int errn = 0; - int intr; - - intr = mutex_lock_interruptible(&(rio->lock)); - if (intr) - return -EINTR; - /* Sanity check to make sure rio is connected, powered, etc */ - if (rio->present == 0 || rio->rio_dev == NULL) { - mutex_unlock(&(rio->lock)); - return -ENODEV; - } - - - - do { - unsigned long thistime; - char *obuf = rio->obuf; - - thistime = copy_size = - (count >= OBUF_SIZE) ? OBUF_SIZE : count; - if (copy_from_user(rio->obuf, buffer, copy_size)) { - errn = -EFAULT; - goto error; - } - maxretry = 5; - while (thistime) { - if (!rio->rio_dev) { - errn = -ENODEV; - goto error; - } - if (signal_pending(current)) { - mutex_unlock(&(rio->lock)); - return bytes_written ? bytes_written : -EINTR; - } - - result = usb_bulk_msg(rio->rio_dev, - usb_sndbulkpipe(rio->rio_dev, 2), - obuf, thistime, &partial, 5000); - - dbg("write stats: result:%d thistime:%lu partial:%u", - result, thistime, partial); - - if (result == -ETIMEDOUT) { /* NAK - so hold for a while */ - if (!maxretry--) { - errn = -ETIME; - goto error; - } - prepare_to_wait(&rio->wait_q, &wait, TASK_INTERRUPTIBLE); - schedule_timeout(NAK_TIMEOUT); - finish_wait(&rio->wait_q, &wait); - continue; - } else if (!result && partial) { - obuf += partial; - thistime -= partial; - } else - break; - }; - if (result) { - err("Write Whoops - %x", result); - errn = -EIO; - goto error; - } - bytes_written += copy_size; - count -= copy_size; - buffer += copy_size; - } while (count > 0); - - mutex_unlock(&(rio->lock)); - - return bytes_written ? bytes_written : -EIO; - -error: - mutex_unlock(&(rio->lock)); - return errn; -} - -static ssize_t -read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos) -{ - DEFINE_WAIT(wait); - struct rio_usb_data *rio = &rio_instance; - ssize_t read_count; - unsigned int partial; - int this_read; - int result; - int maxretry = 10; - char *ibuf; - int intr; - - intr = mutex_lock_interruptible(&(rio->lock)); - if (intr) - return -EINTR; - /* Sanity check to make sure rio is connected, powered, etc */ - if (rio->present == 0 || rio->rio_dev == NULL) { - mutex_unlock(&(rio->lock)); - return -ENODEV; - } - - ibuf = rio->ibuf; - - read_count = 0; - - - while (count > 0) { - if (signal_pending(current)) { - mutex_unlock(&(rio->lock)); - return read_count ? read_count : -EINTR; - } - if (!rio->rio_dev) { - mutex_unlock(&(rio->lock)); - return -ENODEV; - } - this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count; - - result = usb_bulk_msg(rio->rio_dev, - usb_rcvbulkpipe(rio->rio_dev, 1), - ibuf, this_read, &partial, - 8000); - - dbg("read stats: result:%d this_read:%u partial:%u", - result, this_read, partial); - - if (partial) { - count = this_read = partial; - } else if (result == -ETIMEDOUT || result == 15) { /* FIXME: 15 ??? */ - if (!maxretry--) { - mutex_unlock(&(rio->lock)); - err("read_rio: maxretry timeout"); - return -ETIME; - } - prepare_to_wait(&rio->wait_q, &wait, TASK_INTERRUPTIBLE); - schedule_timeout(NAK_TIMEOUT); - finish_wait(&rio->wait_q, &wait); - continue; - } else if (result != -EREMOTEIO) { - mutex_unlock(&(rio->lock)); - err("Read Whoops - result:%u partial:%u this_read:%u", - result, partial, this_read); - return -EIO; - } else { - mutex_unlock(&(rio->lock)); - return (0); - } - - if (this_read) { - if (copy_to_user(buffer, ibuf, this_read)) { - mutex_unlock(&(rio->lock)); - return -EFAULT; - } - count -= this_read; - read_count += this_read; - buffer += this_read; - } - } - mutex_unlock(&(rio->lock)); - return read_count; -} - -static const struct file_operations usb_rio_fops = { - .owner = THIS_MODULE, - .read = read_rio, - .write = write_rio, - .unlocked_ioctl = ioctl_rio, - .open = open_rio, - .release = close_rio, - .llseek = noop_llseek, -}; - -static struct usb_class_driver usb_rio_class = { - .name = "rio500%d", - .fops = &usb_rio_fops, - .minor_base = RIO_MINOR, -}; - -static int probe_rio(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - struct rio_usb_data *rio = &rio_instance; - int retval; - - dev_info(&intf->dev, "USB Rio found at address %d\n", dev->devnum); - - retval = usb_register_dev(intf, &usb_rio_class); - if (retval) { - err("Not able to get a minor for this device."); - return -ENOMEM; - } - - rio->rio_dev = dev; - - if (!(rio->obuf = kmalloc(OBUF_SIZE, GFP_KERNEL))) { - err("probe_rio: Not enough memory for the output buffer"); - usb_deregister_dev(intf, &usb_rio_class); - return -ENOMEM; - } - dbg("probe_rio: obuf address:%p", rio->obuf); - - if (!(rio->ibuf = kmalloc(IBUF_SIZE, GFP_KERNEL))) { - err("probe_rio: Not enough memory for the input buffer"); - usb_deregister_dev(intf, &usb_rio_class); - kfree(rio->obuf); - return -ENOMEM; - } - dbg("probe_rio: ibuf address:%p", rio->ibuf); - - mutex_init(&(rio->lock)); - - usb_set_intfdata (intf, rio); - rio->present = 1; - - return 0; -} - -static void disconnect_rio(struct usb_interface *intf) -{ - struct rio_usb_data *rio = usb_get_intfdata (intf); - - usb_set_intfdata (intf, NULL); - mutex_lock(&rio500_mutex); - if (rio) { - usb_deregister_dev(intf, &usb_rio_class); - - mutex_lock(&(rio->lock)); - if (rio->isopen) { - rio->isopen = 0; - /* better let it finish - the release will do whats needed */ - rio->rio_dev = NULL; - mutex_unlock(&(rio->lock)); - mutex_unlock(&rio500_mutex); - return; - } - kfree(rio->ibuf); - kfree(rio->obuf); - - dev_info(&intf->dev, "USB Rio disconnected.\n"); - - rio->present = 0; - mutex_unlock(&(rio->lock)); - } - mutex_unlock(&rio500_mutex); -} - -static const struct usb_device_id rio_table[] = { - { USB_DEVICE(0x0841, 1) }, /* Rio 500 */ - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, rio_table); - -static struct usb_driver rio_driver = { - .name = "rio500", - .probe = probe_rio, - .disconnect = disconnect_rio, - .id_table = rio_table, -}; - -module_usb_driver(rio_driver); - -MODULE_AUTHOR( DRIVER_AUTHOR ); -MODULE_DESCRIPTION( DRIVER_DESC ); -MODULE_LICENSE("GPL"); - diff --git a/ANDROID_3.4.5/drivers/usb/misc/rio500_usb.h b/ANDROID_3.4.5/drivers/usb/misc/rio500_usb.h deleted file mode 100644 index 359abc98..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/rio500_usb.h +++ /dev/null @@ -1,37 +0,0 @@ -/* ---------------------------------------------------------------------- - - Copyright (C) 2000 Cesar Miquel (miquel@df.uba.ar) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - ---------------------------------------------------------------------- */ - - - -#define RIO_SEND_COMMAND 0x1 -#define RIO_RECV_COMMAND 0x2 - -#define RIO_DIR_OUT 0x0 -#define RIO_DIR_IN 0x1 - -struct RioCommand { - short length; - int request; - int requesttype; - int value; - int index; - void __user *buffer; - int timeout; -}; diff --git a/ANDROID_3.4.5/drivers/usb/misc/sisusbvga/Kconfig b/ANDROID_3.4.5/drivers/usb/misc/sisusbvga/Kconfig deleted file mode 100644 index 30ea7ca6..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/sisusbvga/Kconfig +++ /dev/null @@ -1,46 +0,0 @@ - -config USB_SISUSBVGA - tristate "USB 2.0 SVGA dongle support (Net2280/SiS315)" - 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. - - Note that this device requires a USB 2.0 host controller. It will not - work with USB 1.x controllers. - - To compile this driver as a module, choose M here; the module will be - called sisusbvga. If unsure, say N. - -config USB_SISUSBVGA_CON - bool "Text console and mode switching support" if USB_SISUSBVGA - depends on VT - select FONT_8x16 - ---help--- - Say Y here if you want a VGA text console via the USB dongle or - want to support userland applications that utilize the driver's - display mode switching capabilities. - - Note that this console supports VGA/EGA text mode only. - - By default, the console part of the driver will not kick in when - the driver is initialized. If you want the driver to take over - one or more of the consoles, you need to specify the number of - the first and last consoles (starting at 1) as driver parameters. - - For example, if the driver is compiled as a module: - - modprobe sisusbvga first=1 last=5 - - If you use hotplug, add this to your modutils config files with - the "options" keyword, such as eg. - - options sisusbvga first=1 last=5 - - If the driver is compiled into the kernel image, the parameters - must be given in the kernel command like, such as - - sisusbvga.first=1 sisusbvga.last=5 - - - diff --git a/ANDROID_3.4.5/drivers/usb/misc/sisusbvga/Makefile b/ANDROID_3.4.5/drivers/usb/misc/sisusbvga/Makefile deleted file mode 100644 index 3142476c..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/sisusbvga/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Makefile for the sisusb driver (if driver is inside kernel tree). -# - -obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga.o - -sisusbvga-y := sisusb.o sisusb_init.o sisusb_con.o diff --git a/ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb.c b/ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb.c deleted file mode 100644 index dd573abd..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb.c +++ /dev/null @@ -1,3285 +0,0 @@ -/* - * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles - * - * Main part - * - * Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria - * - * If distributed as part of the Linux kernel, this code is licensed under the - * terms of the GPL v2. - * - * Otherwise, the following license terms apply: - * - * * Redistribution and use in source and binary forms, with or without - * * modification, are permitted provided that the following conditions - * * are met: - * * 1) Redistributions of source code must retain the above copyright - * * notice, this list of conditions and the following disclaimer. - * * 2) Redistributions in binary form must reproduce the above copyright - * * notice, this list of conditions and the following disclaimer in the - * * documentation and/or other materials provided with the distribution. - * * 3) The name of the author may not be used to endorse or promote products - * * derived from this software without specific psisusbr written permission. - * * - * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR - * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Author: Thomas Winischhofer - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sisusb.h" -#include "sisusb_init.h" - -#ifdef INCL_SISUSB_CON -#include -#endif - -#define SISUSB_DONTSYNC - -/* Forward declarations / clean-up routines */ - -#ifdef INCL_SISUSB_CON -static int sisusb_first_vc = 0; -static int sisusb_last_vc = 0; -module_param_named(first, sisusb_first_vc, int, 0); -module_param_named(last, sisusb_last_vc, int, 0); -MODULE_PARM_DESC(first, "Number of first console to take over (1 - MAX_NR_CONSOLES)"); -MODULE_PARM_DESC(last, "Number of last console to take over (1 - MAX_NR_CONSOLES)"); -#endif - -static struct usb_driver sisusb_driver; - -static void -sisusb_free_buffers(struct sisusb_usb_data *sisusb) -{ - int i; - - for (i = 0; i < NUMOBUFS; i++) { - if (sisusb->obuf[i]) { - kfree(sisusb->obuf[i]); - sisusb->obuf[i] = NULL; - } - } - if (sisusb->ibuf) { - kfree(sisusb->ibuf); - sisusb->ibuf = NULL; - } -} - -static void -sisusb_free_urbs(struct sisusb_usb_data *sisusb) -{ - int i; - - for (i = 0; i < NUMOBUFS; i++) { - usb_free_urb(sisusb->sisurbout[i]); - sisusb->sisurbout[i] = NULL; - } - usb_free_urb(sisusb->sisurbin); - sisusb->sisurbin = NULL; -} - -/* Level 0: USB transport layer */ - -/* 1. out-bulks */ - -/* out-urb management */ - -/* Return 1 if all free, 0 otherwise */ -static int -sisusb_all_free(struct sisusb_usb_data *sisusb) -{ - int i; - - for (i = 0; i < sisusb->numobufs; i++) { - - if (sisusb->urbstatus[i] & SU_URB_BUSY) - return 0; - - } - - return 1; -} - -/* Kill all busy URBs */ -static void -sisusb_kill_all_busy(struct sisusb_usb_data *sisusb) -{ - int i; - - if (sisusb_all_free(sisusb)) - return; - - for (i = 0; i < sisusb->numobufs; i++) { - - if (sisusb->urbstatus[i] & SU_URB_BUSY) - usb_kill_urb(sisusb->sisurbout[i]); - - } -} - -/* Return 1 if ok, 0 if error (not all complete within timeout) */ -static int -sisusb_wait_all_out_complete(struct sisusb_usb_data *sisusb) -{ - int timeout = 5 * HZ, i = 1; - - wait_event_timeout(sisusb->wait_q, - (i = sisusb_all_free(sisusb)), - timeout); - - return i; -} - -static int -sisusb_outurb_available(struct sisusb_usb_data *sisusb) -{ - int i; - - for (i = 0; i < sisusb->numobufs; i++) { - - if ((sisusb->urbstatus[i] & (SU_URB_BUSY|SU_URB_ALLOC)) == 0) - return i; - - } - - return -1; -} - -static int -sisusb_get_free_outbuf(struct sisusb_usb_data *sisusb) -{ - int i, timeout = 5 * HZ; - - wait_event_timeout(sisusb->wait_q, - ((i = sisusb_outurb_available(sisusb)) >= 0), - timeout); - - return i; -} - -static int -sisusb_alloc_outbuf(struct sisusb_usb_data *sisusb) -{ - int i; - - i = sisusb_outurb_available(sisusb); - - if (i >= 0) - sisusb->urbstatus[i] |= SU_URB_ALLOC; - - return i; -} - -static void -sisusb_free_outbuf(struct sisusb_usb_data *sisusb, int index) -{ - if ((index >= 0) && (index < sisusb->numobufs)) - sisusb->urbstatus[index] &= ~SU_URB_ALLOC; -} - -/* completion callback */ - -static void -sisusb_bulk_completeout(struct urb *urb) -{ - struct sisusb_urb_context *context = urb->context; - struct sisusb_usb_data *sisusb; - - if (!context) - return; - - sisusb = context->sisusb; - - if (!sisusb || !sisusb->sisusb_dev || !sisusb->present) - return; - -#ifndef SISUSB_DONTSYNC - if (context->actual_length) - *(context->actual_length) += urb->actual_length; -#endif - - sisusb->urbstatus[context->urbindex] &= ~SU_URB_BUSY; - wake_up(&sisusb->wait_q); -} - -static int -sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe, void *data, - int len, int *actual_length, int timeout, unsigned int tflags) -{ - struct urb *urb = sisusb->sisurbout[index]; - int retval, byteswritten = 0; - - /* Set up URB */ - urb->transfer_flags = 0; - - usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len, - sisusb_bulk_completeout, &sisusb->urbout_context[index]); - - urb->transfer_flags |= tflags; - urb->actual_length = 0; - - /* Set up context */ - sisusb->urbout_context[index].actual_length = (timeout) ? - NULL : actual_length; - - /* Declare this urb/buffer in use */ - sisusb->urbstatus[index] |= SU_URB_BUSY; - - /* Submit URB */ - retval = usb_submit_urb(urb, GFP_KERNEL); - - /* If OK, and if timeout > 0, wait for completion */ - if ((retval == 0) && timeout) { - wait_event_timeout(sisusb->wait_q, - (!(sisusb->urbstatus[index] & SU_URB_BUSY)), - timeout); - if (sisusb->urbstatus[index] & SU_URB_BUSY) { - /* URB timed out... kill it and report error */ - usb_kill_urb(urb); - retval = -ETIMEDOUT; - } else { - /* Otherwise, report urb status */ - retval = urb->status; - byteswritten = urb->actual_length; - } - } - - if (actual_length) - *actual_length = byteswritten; - - return retval; -} - -/* 2. in-bulks */ - -/* completion callback */ - -static void -sisusb_bulk_completein(struct urb *urb) -{ - struct sisusb_usb_data *sisusb = urb->context; - - if (!sisusb || !sisusb->sisusb_dev || !sisusb->present) - return; - - sisusb->completein = 1; - wake_up(&sisusb->wait_q); -} - -static int -sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data, - int len, int *actual_length, int timeout, unsigned int tflags) -{ - struct urb *urb = sisusb->sisurbin; - int retval, readbytes = 0; - - urb->transfer_flags = 0; - - usb_fill_bulk_urb(urb, sisusb->sisusb_dev, pipe, data, len, - sisusb_bulk_completein, sisusb); - - urb->transfer_flags |= tflags; - urb->actual_length = 0; - - sisusb->completein = 0; - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval == 0) { - wait_event_timeout(sisusb->wait_q, sisusb->completein, timeout); - if (!sisusb->completein) { - /* URB timed out... kill it and report error */ - usb_kill_urb(urb); - retval = -ETIMEDOUT; - } else { - /* URB completed within timeout */ - retval = urb->status; - readbytes = urb->actual_length; - } - } - - if (actual_length) - *actual_length = readbytes; - - return retval; -} - - -/* Level 1: */ - -/* Send a bulk message of variable size - * - * To copy the data from userspace, give pointer to "userbuffer", - * to copy from (non-DMA) kernel memory, give "kernbuffer". If - * both of these are NULL, it is assumed, that the transfer - * buffer "sisusb->obuf[index]" is set up with the data to send. - * Index is ignored if either kernbuffer or userbuffer is set. - * If async is nonzero, URBs will be sent without waiting for - * completion of the previous URB. - * - * (return 0 on success) - */ - -static int sisusb_send_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len, - char *kernbuffer, const char __user *userbuffer, int index, - ssize_t *bytes_written, unsigned int tflags, int async) -{ - int result = 0, retry, count = len; - int passsize, thispass, transferred_len = 0; - int fromuser = (userbuffer != NULL) ? 1 : 0; - int fromkern = (kernbuffer != NULL) ? 1 : 0; - unsigned int pipe; - char *buffer; - - (*bytes_written) = 0; - - /* Sanity check */ - if (!sisusb || !sisusb->present || !sisusb->sisusb_dev) - return -ENODEV; - - /* If we copy data from kernel or userspace, force the - * allocation of a buffer/urb. If we have the data in - * the transfer buffer[index] already, reuse the buffer/URB - * if the length is > buffer size. (So, transmitting - * large data amounts directly from the transfer buffer - * treats the buffer as a ring buffer. However, we need - * to sync in this case.) - */ - if (fromuser || fromkern) - index = -1; - else if (len > sisusb->obufsize) - async = 0; - - pipe = usb_sndbulkpipe(sisusb->sisusb_dev, ep); - - do { - passsize = thispass = (sisusb->obufsize < count) ? - sisusb->obufsize : count; - - if (index < 0) - index = sisusb_get_free_outbuf(sisusb); - - if (index < 0) - return -EIO; - - buffer = sisusb->obuf[index]; - - if (fromuser) { - - if (copy_from_user(buffer, userbuffer, passsize)) - return -EFAULT; - - userbuffer += passsize; - - } else if (fromkern) { - - memcpy(buffer, kernbuffer, passsize); - kernbuffer += passsize; - - } - - retry = 5; - while (thispass) { - - if (!sisusb->sisusb_dev) - return -ENODEV; - - result = sisusb_bulkout_msg(sisusb, - index, - pipe, - buffer, - thispass, - &transferred_len, - async ? 0 : 5 * HZ, - tflags); - - if (result == -ETIMEDOUT) { - - /* Will not happen if async */ - if (!retry--) - return -ETIME; - - continue; - } - - if ((result == 0) && !async && transferred_len) { - - thispass -= transferred_len; - buffer += transferred_len; - - } else - break; - } - - if (result) - return result; - - (*bytes_written) += passsize; - count -= passsize; - - /* Force new allocation in next iteration */ - if (fromuser || fromkern) - index = -1; - - } while (count > 0); - - if (async) { -#ifdef SISUSB_DONTSYNC - (*bytes_written) = len; - /* Some URBs/buffers might be busy */ -#else - sisusb_wait_all_out_complete(sisusb); - (*bytes_written) = transferred_len; - /* All URBs and all buffers are available */ -#endif - } - - return ((*bytes_written) == len) ? 0 : -EIO; -} - -/* Receive a bulk message of variable size - * - * To copy the data to userspace, give pointer to "userbuffer", - * to copy to kernel memory, give "kernbuffer". One of them - * MUST be set. (There is no technique for letting the caller - * read directly from the ibuf.) - * - */ - -static int sisusb_recv_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len, - void *kernbuffer, char __user *userbuffer, ssize_t *bytes_read, - unsigned int tflags) -{ - int result = 0, retry, count = len; - int bufsize, thispass, transferred_len; - unsigned int pipe; - char *buffer; - - (*bytes_read) = 0; - - /* Sanity check */ - if (!sisusb || !sisusb->present || !sisusb->sisusb_dev) - return -ENODEV; - - pipe = usb_rcvbulkpipe(sisusb->sisusb_dev, ep); - buffer = sisusb->ibuf; - bufsize = sisusb->ibufsize; - - retry = 5; - -#ifdef SISUSB_DONTSYNC - if (!(sisusb_wait_all_out_complete(sisusb))) - return -EIO; -#endif - - while (count > 0) { - - if (!sisusb->sisusb_dev) - return -ENODEV; - - thispass = (bufsize < count) ? bufsize : count; - - result = sisusb_bulkin_msg(sisusb, - pipe, - buffer, - thispass, - &transferred_len, - 5 * HZ, - tflags); - - if (transferred_len) - thispass = transferred_len; - - else if (result == -ETIMEDOUT) { - - if (!retry--) - return -ETIME; - - continue; - - } else - return -EIO; - - - if (thispass) { - - (*bytes_read) += thispass; - count -= thispass; - - if (userbuffer) { - - if (copy_to_user(userbuffer, buffer, thispass)) - return -EFAULT; - - userbuffer += thispass; - - } else { - - memcpy(kernbuffer, buffer, thispass); - kernbuffer += thispass; - - } - - } - - } - - return ((*bytes_read) == len) ? 0 : -EIO; -} - -static int sisusb_send_packet(struct sisusb_usb_data *sisusb, int len, - struct sisusb_packet *packet) -{ - int ret; - ssize_t bytes_transferred = 0; - __le32 tmp; - - if (len == 6) - packet->data = 0; - -#ifdef SISUSB_DONTSYNC - if (!(sisusb_wait_all_out_complete(sisusb))) - return 1; -#endif - - /* Eventually correct endianness */ - SISUSB_CORRECT_ENDIANNESS_PACKET(packet); - - /* 1. send the packet */ - ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_GFX_OUT, len, - (char *)packet, NULL, 0, &bytes_transferred, 0, 0); - - if ((ret == 0) && (len == 6)) { - - /* 2. if packet len == 6, it means we read, so wait for 32bit - * return value and write it to packet->data - */ - ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_GFX_IN, 4, - (char *)&tmp, NULL, &bytes_transferred, 0); - - packet->data = le32_to_cpu(tmp); - } - - return ret; -} - -static int sisusb_send_bridge_packet(struct sisusb_usb_data *sisusb, int len, - struct sisusb_packet *packet, - unsigned int tflags) -{ - int ret; - ssize_t bytes_transferred = 0; - __le32 tmp; - - if (len == 6) - packet->data = 0; - -#ifdef SISUSB_DONTSYNC - if (!(sisusb_wait_all_out_complete(sisusb))) - return 1; -#endif - - /* Eventually correct endianness */ - SISUSB_CORRECT_ENDIANNESS_PACKET(packet); - - /* 1. send the packet */ - ret = sisusb_send_bulk_msg(sisusb, SISUSB_EP_BRIDGE_OUT, len, - (char *)packet, NULL, 0, &bytes_transferred, tflags, 0); - - if ((ret == 0) && (len == 6)) { - - /* 2. if packet len == 6, it means we read, so wait for 32bit - * return value and write it to packet->data - */ - ret = sisusb_recv_bulk_msg(sisusb, SISUSB_EP_BRIDGE_IN, 4, - (char *)&tmp, NULL, &bytes_transferred, 0); - - packet->data = le32_to_cpu(tmp); - } - - return ret; -} - -/* access video memory and mmio (return 0 on success) */ - -/* Low level */ - -/* The following routines assume being used to transfer byte, word, - * long etc. - * This means that - * - the write routines expect "data" in machine endianness format. - * The data will be converted to leXX in sisusb_xxx_packet. - * - the read routines can expect read data in machine-endianess. - */ - -static int sisusb_write_memio_byte(struct sisusb_usb_data *sisusb, int type, - u32 addr, u8 data) -{ - struct sisusb_packet packet; - int ret; - - packet.header = (1 << (addr & 3)) | (type << 6); - packet.address = addr & ~3; - packet.data = data << ((addr & 3) << 3); - ret = sisusb_send_packet(sisusb, 10, &packet); - return ret; -} - -static int sisusb_write_memio_word(struct sisusb_usb_data *sisusb, int type, - u32 addr, u16 data) -{ - struct sisusb_packet packet; - int ret = 0; - - packet.address = addr & ~3; - - switch (addr & 3) { - case 0: - packet.header = (type << 6) | 0x0003; - packet.data = (u32)data; - ret = sisusb_send_packet(sisusb, 10, &packet); - break; - case 1: - packet.header = (type << 6) | 0x0006; - packet.data = (u32)data << 8; - ret = sisusb_send_packet(sisusb, 10, &packet); - break; - case 2: - packet.header = (type << 6) | 0x000c; - packet.data = (u32)data << 16; - ret = sisusb_send_packet(sisusb, 10, &packet); - break; - case 3: - packet.header = (type << 6) | 0x0008; - packet.data = (u32)data << 24; - ret = sisusb_send_packet(sisusb, 10, &packet); - packet.header = (type << 6) | 0x0001; - packet.address = (addr & ~3) + 4; - packet.data = (u32)data >> 8; - ret |= sisusb_send_packet(sisusb, 10, &packet); - } - - return ret; -} - -static int sisusb_write_memio_24bit(struct sisusb_usb_data *sisusb, int type, - u32 addr, u32 data) -{ - struct sisusb_packet packet; - int ret = 0; - - packet.address = addr & ~3; - - switch (addr & 3) { - case 0: - packet.header = (type << 6) | 0x0007; - packet.data = data & 0x00ffffff; - ret = sisusb_send_packet(sisusb, 10, &packet); - break; - case 1: - packet.header = (type << 6) | 0x000e; - packet.data = data << 8; - ret = sisusb_send_packet(sisusb, 10, &packet); - break; - case 2: - packet.header = (type << 6) | 0x000c; - packet.data = data << 16; - ret = sisusb_send_packet(sisusb, 10, &packet); - packet.header = (type << 6) | 0x0001; - packet.address = (addr & ~3) + 4; - packet.data = (data >> 16) & 0x00ff; - ret |= sisusb_send_packet(sisusb, 10, &packet); - break; - case 3: - packet.header = (type << 6) | 0x0008; - packet.data = data << 24; - ret = sisusb_send_packet(sisusb, 10, &packet); - packet.header = (type << 6) | 0x0003; - packet.address = (addr & ~3) + 4; - packet.data = (data >> 8) & 0xffff; - ret |= sisusb_send_packet(sisusb, 10, &packet); - } - - return ret; -} - -static int sisusb_write_memio_long(struct sisusb_usb_data *sisusb, int type, - u32 addr, u32 data) -{ - struct sisusb_packet packet; - int ret = 0; - - packet.address = addr & ~3; - - switch (addr & 3) { - case 0: - packet.header = (type << 6) | 0x000f; - packet.data = data; - ret = sisusb_send_packet(sisusb, 10, &packet); - break; - case 1: - packet.header = (type << 6) | 0x000e; - packet.data = data << 8; - ret = sisusb_send_packet(sisusb, 10, &packet); - packet.header = (type << 6) | 0x0001; - packet.address = (addr & ~3) + 4; - packet.data = data >> 24; - ret |= sisusb_send_packet(sisusb, 10, &packet); - break; - case 2: - packet.header = (type << 6) | 0x000c; - packet.data = data << 16; - ret = sisusb_send_packet(sisusb, 10, &packet); - packet.header = (type << 6) | 0x0003; - packet.address = (addr & ~3) + 4; - packet.data = data >> 16; - ret |= sisusb_send_packet(sisusb, 10, &packet); - break; - case 3: - packet.header = (type << 6) | 0x0008; - packet.data = data << 24; - ret = sisusb_send_packet(sisusb, 10, &packet); - packet.header = (type << 6) | 0x0007; - packet.address = (addr & ~3) + 4; - packet.data = data >> 8; - ret |= sisusb_send_packet(sisusb, 10, &packet); - } - - return ret; -} - -/* The xxx_bulk routines copy a buffer of variable size. They treat the - * buffer as chars, therefore lsb/msb has to be corrected if using the - * byte/word/long/etc routines for speed-up - * - * If data is from userland, set "userbuffer" (and clear "kernbuffer"), - * if data is in kernel space, set "kernbuffer" (and clear "userbuffer"); - * if neither "kernbuffer" nor "userbuffer" are given, it is assumed - * that the data already is in the transfer buffer "sisusb->obuf[index]". - */ - -static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, - char *kernbuffer, int length, - const char __user *userbuffer, int index, - ssize_t *bytes_written) -{ - struct sisusb_packet packet; - int ret = 0; - static int msgcount = 0; - u8 swap8, fromkern = kernbuffer ? 1 : 0; - u16 swap16; - u32 swap32, flag = (length >> 28) & 1; - char buf[4]; - - /* if neither kernbuffer not userbuffer are given, assume - * data in obuf - */ - if (!fromkern && !userbuffer) - kernbuffer = sisusb->obuf[index]; - - (*bytes_written = 0); - - length &= 0x00ffffff; - - while (length) { - - switch (length) { - - case 1: - if (userbuffer) { - if (get_user(swap8, (u8 __user *)userbuffer)) - return -EFAULT; - } else - swap8 = kernbuffer[0]; - - ret = sisusb_write_memio_byte(sisusb, - SISUSB_TYPE_MEM, - addr, swap8); - - if (!ret) - (*bytes_written)++; - - return ret; - - case 2: - if (userbuffer) { - if (get_user(swap16, (u16 __user *)userbuffer)) - return -EFAULT; - } else - swap16 = *((u16 *)kernbuffer); - - ret = sisusb_write_memio_word(sisusb, - SISUSB_TYPE_MEM, - addr, - swap16); - - if (!ret) - (*bytes_written) += 2; - - return ret; - - case 3: - if (userbuffer) { - if (copy_from_user(&buf, userbuffer, 3)) - return -EFAULT; -#ifdef __BIG_ENDIAN - swap32 = (buf[0] << 16) | - (buf[1] << 8) | - buf[2]; -#else - swap32 = (buf[2] << 16) | - (buf[1] << 8) | - buf[0]; -#endif - } else -#ifdef __BIG_ENDIAN - swap32 = (kernbuffer[0] << 16) | - (kernbuffer[1] << 8) | - kernbuffer[2]; -#else - swap32 = (kernbuffer[2] << 16) | - (kernbuffer[1] << 8) | - kernbuffer[0]; -#endif - - ret = sisusb_write_memio_24bit(sisusb, - SISUSB_TYPE_MEM, - addr, - swap32); - - if (!ret) - (*bytes_written) += 3; - - return ret; - - case 4: - if (userbuffer) { - if (get_user(swap32, (u32 __user *)userbuffer)) - return -EFAULT; - } else - swap32 = *((u32 *)kernbuffer); - - ret = sisusb_write_memio_long(sisusb, - SISUSB_TYPE_MEM, - addr, - swap32); - if (!ret) - (*bytes_written) += 4; - - return ret; - - default: - if ((length & ~3) > 0x10000) { - - packet.header = 0x001f; - packet.address = 0x000001d4; - packet.data = addr; - ret = sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - packet.header = 0x001f; - packet.address = 0x000001d0; - packet.data = (length & ~3); - ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - packet.header = 0x001f; - packet.address = 0x000001c0; - packet.data = flag | 0x16; - ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - if (userbuffer) { - ret |= sisusb_send_bulk_msg(sisusb, - SISUSB_EP_GFX_LBULK_OUT, - (length & ~3), - NULL, userbuffer, 0, - bytes_written, 0, 1); - userbuffer += (*bytes_written); - } else if (fromkern) { - ret |= sisusb_send_bulk_msg(sisusb, - SISUSB_EP_GFX_LBULK_OUT, - (length & ~3), - kernbuffer, NULL, 0, - bytes_written, 0, 1); - kernbuffer += (*bytes_written); - } else { - ret |= sisusb_send_bulk_msg(sisusb, - SISUSB_EP_GFX_LBULK_OUT, - (length & ~3), - NULL, NULL, index, - bytes_written, 0, 1); - kernbuffer += ((*bytes_written) & - (sisusb->obufsize-1)); - } - - } else { - - packet.header = 0x001f; - packet.address = 0x00000194; - packet.data = addr; - ret = sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - packet.header = 0x001f; - packet.address = 0x00000190; - packet.data = (length & ~3); - ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - if (sisusb->flagb0 != 0x16) { - packet.header = 0x001f; - packet.address = 0x00000180; - packet.data = flag | 0x16; - ret |= sisusb_send_bridge_packet(sisusb, 10, - &packet, 0); - sisusb->flagb0 = 0x16; - } - if (userbuffer) { - ret |= sisusb_send_bulk_msg(sisusb, - SISUSB_EP_GFX_BULK_OUT, - (length & ~3), - NULL, userbuffer, 0, - bytes_written, 0, 1); - userbuffer += (*bytes_written); - } else if (fromkern) { - ret |= sisusb_send_bulk_msg(sisusb, - SISUSB_EP_GFX_BULK_OUT, - (length & ~3), - kernbuffer, NULL, 0, - bytes_written, 0, 1); - kernbuffer += (*bytes_written); - } else { - ret |= sisusb_send_bulk_msg(sisusb, - SISUSB_EP_GFX_BULK_OUT, - (length & ~3), - NULL, NULL, index, - bytes_written, 0, 1); - kernbuffer += ((*bytes_written) & - (sisusb->obufsize-1)); - } - } - if (ret) { - msgcount++; - if (msgcount < 500) - dev_err(&sisusb->sisusb_dev->dev, "Wrote %zd of %d bytes, error %d\n", - *bytes_written, length, ret); - else if (msgcount == 500) - dev_err(&sisusb->sisusb_dev->dev, "Too many errors, logging stopped\n"); - } - addr += (*bytes_written); - length -= (*bytes_written); - } - - if (ret) - break; - - } - - return ret ? -EIO : 0; -} - -/* Remember: Read data in packet is in machine-endianess! So for - * byte, word, 24bit, long no endian correction is necessary. - */ - -static int sisusb_read_memio_byte(struct sisusb_usb_data *sisusb, int type, - u32 addr, u8 *data) -{ - struct sisusb_packet packet; - int ret; - - CLEARPACKET(&packet); - packet.header = (1 << (addr & 3)) | (type << 6); - packet.address = addr & ~3; - ret = sisusb_send_packet(sisusb, 6, &packet); - *data = (u8)(packet.data >> ((addr & 3) << 3)); - return ret; -} - -static int sisusb_read_memio_word(struct sisusb_usb_data *sisusb, int type, - u32 addr, u16 *data) -{ - struct sisusb_packet packet; - int ret = 0; - - CLEARPACKET(&packet); - - packet.address = addr & ~3; - - switch (addr & 3) { - case 0: - packet.header = (type << 6) | 0x0003; - ret = sisusb_send_packet(sisusb, 6, &packet); - *data = (u16)(packet.data); - break; - case 1: - packet.header = (type << 6) | 0x0006; - ret = sisusb_send_packet(sisusb, 6, &packet); - *data = (u16)(packet.data >> 8); - break; - case 2: - packet.header = (type << 6) | 0x000c; - ret = sisusb_send_packet(sisusb, 6, &packet); - *data = (u16)(packet.data >> 16); - break; - case 3: - packet.header = (type << 6) | 0x0008; - ret = sisusb_send_packet(sisusb, 6, &packet); - *data = (u16)(packet.data >> 24); - packet.header = (type << 6) | 0x0001; - packet.address = (addr & ~3) + 4; - ret |= sisusb_send_packet(sisusb, 6, &packet); - *data |= (u16)(packet.data << 8); - } - - return ret; -} - -static int sisusb_read_memio_24bit(struct sisusb_usb_data *sisusb, int type, - u32 addr, u32 *data) -{ - struct sisusb_packet packet; - int ret = 0; - - packet.address = addr & ~3; - - switch (addr & 3) { - case 0: - packet.header = (type << 6) | 0x0007; - ret = sisusb_send_packet(sisusb, 6, &packet); - *data = packet.data & 0x00ffffff; - break; - case 1: - packet.header = (type << 6) | 0x000e; - ret = sisusb_send_packet(sisusb, 6, &packet); - *data = packet.data >> 8; - break; - case 2: - packet.header = (type << 6) | 0x000c; - ret = sisusb_send_packet(sisusb, 6, &packet); - *data = packet.data >> 16; - packet.header = (type << 6) | 0x0001; - packet.address = (addr & ~3) + 4; - ret |= sisusb_send_packet(sisusb, 6, &packet); - *data |= ((packet.data & 0xff) << 16); - break; - case 3: - packet.header = (type << 6) | 0x0008; - ret = sisusb_send_packet(sisusb, 6, &packet); - *data = packet.data >> 24; - packet.header = (type << 6) | 0x0003; - packet.address = (addr & ~3) + 4; - ret |= sisusb_send_packet(sisusb, 6, &packet); - *data |= ((packet.data & 0xffff) << 8); - } - - return ret; -} - -static int sisusb_read_memio_long(struct sisusb_usb_data *sisusb, int type, - u32 addr, u32 *data) -{ - struct sisusb_packet packet; - int ret = 0; - - packet.address = addr & ~3; - - switch (addr & 3) { - case 0: - packet.header = (type << 6) | 0x000f; - ret = sisusb_send_packet(sisusb, 6, &packet); - *data = packet.data; - break; - case 1: - packet.header = (type << 6) | 0x000e; - ret = sisusb_send_packet(sisusb, 6, &packet); - *data = packet.data >> 8; - packet.header = (type << 6) | 0x0001; - packet.address = (addr & ~3) + 4; - ret |= sisusb_send_packet(sisusb, 6, &packet); - *data |= (packet.data << 24); - break; - case 2: - packet.header = (type << 6) | 0x000c; - ret = sisusb_send_packet(sisusb, 6, &packet); - *data = packet.data >> 16; - packet.header = (type << 6) | 0x0003; - packet.address = (addr & ~3) + 4; - ret |= sisusb_send_packet(sisusb, 6, &packet); - *data |= (packet.data << 16); - break; - case 3: - packet.header = (type << 6) | 0x0008; - ret = sisusb_send_packet(sisusb, 6, &packet); - *data = packet.data >> 24; - packet.header = (type << 6) | 0x0007; - packet.address = (addr & ~3) + 4; - ret |= sisusb_send_packet(sisusb, 6, &packet); - *data |= (packet.data << 8); - } - - return ret; -} - -static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr, - char *kernbuffer, int length, - char __user *userbuffer, ssize_t *bytes_read) -{ - int ret = 0; - char buf[4]; - u16 swap16; - u32 swap32; - - (*bytes_read = 0); - - length &= 0x00ffffff; - - while (length) { - - switch (length) { - - case 1: - - ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, - addr, &buf[0]); - if (!ret) { - (*bytes_read)++; - if (userbuffer) { - if (put_user(buf[0], - (u8 __user *)userbuffer)) { - return -EFAULT; - } - } else { - kernbuffer[0] = buf[0]; - } - } - return ret; - - case 2: - ret |= sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, - addr, &swap16); - if (!ret) { - (*bytes_read) += 2; - if (userbuffer) { - if (put_user(swap16, - (u16 __user *)userbuffer)) - return -EFAULT; - } else { - *((u16 *)kernbuffer) = swap16; - } - } - return ret; - - case 3: - ret |= sisusb_read_memio_24bit(sisusb, SISUSB_TYPE_MEM, - addr, &swap32); - if (!ret) { - (*bytes_read) += 3; -#ifdef __BIG_ENDIAN - buf[0] = (swap32 >> 16) & 0xff; - buf[1] = (swap32 >> 8) & 0xff; - buf[2] = swap32 & 0xff; -#else - buf[2] = (swap32 >> 16) & 0xff; - buf[1] = (swap32 >> 8) & 0xff; - buf[0] = swap32 & 0xff; -#endif - if (userbuffer) { - if (copy_to_user(userbuffer, &buf[0], 3)) - return -EFAULT; - } else { - kernbuffer[0] = buf[0]; - kernbuffer[1] = buf[1]; - kernbuffer[2] = buf[2]; - } - } - return ret; - - default: - ret |= sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, - addr, &swap32); - if (!ret) { - (*bytes_read) += 4; - if (userbuffer) { - if (put_user(swap32, - (u32 __user *)userbuffer)) - return -EFAULT; - - userbuffer += 4; - } else { - *((u32 *)kernbuffer) = swap32; - kernbuffer += 4; - } - addr += 4; - length -= 4; - } - } - - if (ret) - break; - } - - return ret; -} - -/* High level: Gfx (indexed) register access */ - -#ifdef INCL_SISUSB_CON -int -sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data) -{ - return sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, data); -} - -int -sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data) -{ - return sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port, data); -} -#endif - -int -sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 data) -{ - int ret; - ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index); - ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data); - return ret; -} - -int -sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, u8 index, u8 *data) -{ - int ret; - ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, index); - ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, data); - return ret; -} - -int -sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, u8 idx, - u8 myand, u8 myor) -{ - int ret; - u8 tmp; - - ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx); - ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp); - tmp &= myand; - tmp |= myor; - ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp); - return ret; -} - -static int -sisusb_setidxregmask(struct sisusb_usb_data *sisusb, int port, u8 idx, - u8 data, u8 mask) -{ - int ret; - u8 tmp; - ret = sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port, idx); - ret |= sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, &tmp); - tmp &= ~(mask); - tmp |= (data & mask); - ret |= sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, port + 1, tmp); - return ret; -} - -int -sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, u8 index, u8 myor) -{ - return(sisusb_setidxregandor(sisusb, port, index, 0xff, myor)); -} - -int -sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, u8 idx, u8 myand) -{ - return(sisusb_setidxregandor(sisusb, port, idx, myand, 0x00)); -} - -/* Write/read video ram */ - -#ifdef INCL_SISUSB_CON -int -sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data) -{ - return(sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data)); -} - -int -sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data) -{ - return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data)); -} - -int -sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, - u32 dest, int length, size_t *bytes_written) -{ - return(sisusb_write_mem_bulk(sisusb, dest, src, length, NULL, 0, bytes_written)); -} - -#ifdef SISUSBENDIANTEST -int -sisusb_read_memory(struct sisusb_usb_data *sisusb, char *dest, - u32 src, int length, size_t *bytes_written) -{ - return(sisusb_read_mem_bulk(sisusb, src, dest, length, NULL, bytes_written)); -} -#endif -#endif - -#ifdef SISUSBENDIANTEST -static void -sisusb_testreadwrite(struct sisusb_usb_data *sisusb) -{ - static char srcbuffer[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; - char destbuffer[10]; - size_t dummy; - int i,j; - - sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy); - - for(i = 1; i <= 7; i++) { - dev_dbg(&sisusb->sisusb_dev->dev, "sisusb: rwtest %d bytes\n", i); - sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy); - for(j = 0; j < i; j++) { - dev_dbg(&sisusb->sisusb_dev->dev, "rwtest read[%d] = %x\n", j, destbuffer[j]); - } - } -} -#endif - -/* access pci config registers (reg numbers 0, 4, 8, etc) */ - -static int -sisusb_write_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 data) -{ - struct sisusb_packet packet; - int ret; - - packet.header = 0x008f; - packet.address = regnum | 0x10000; - packet.data = data; - ret = sisusb_send_packet(sisusb, 10, &packet); - return ret; -} - -static int -sisusb_read_pci_config(struct sisusb_usb_data *sisusb, int regnum, u32 *data) -{ - struct sisusb_packet packet; - int ret; - - packet.header = 0x008f; - packet.address = (u32)regnum | 0x10000; - ret = sisusb_send_packet(sisusb, 6, &packet); - *data = packet.data; - return ret; -} - -/* Clear video RAM */ - -static int -sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length) -{ - int ret, i; - ssize_t j; - - if (address < sisusb->vrambase) - return 1; - - if (address >= sisusb->vrambase + sisusb->vramsize) - return 1; - - if (address + length > sisusb->vrambase + sisusb->vramsize) - length = sisusb->vrambase + sisusb->vramsize - address; - - if (length <= 0) - return 0; - - /* allocate free buffer/urb and clear the buffer */ - if ((i = sisusb_alloc_outbuf(sisusb)) < 0) - return -EBUSY; - - memset(sisusb->obuf[i], 0, sisusb->obufsize); - - /* We can write a length > buffer size here. The buffer - * data will simply be re-used (like a ring-buffer). - */ - ret = sisusb_write_mem_bulk(sisusb, address, NULL, length, NULL, i, &j); - - /* Free the buffer/urb */ - sisusb_free_outbuf(sisusb, i); - - return ret; -} - -/* Initialize the graphics core (return 0 on success) - * This resets the graphics hardware and puts it into - * a defined mode (640x480@60Hz) - */ - -#define GETREG(r,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_IO, r, d) -#define SETREG(r,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_IO, r, d) -#define SETIREG(r,i,d) sisusb_setidxreg(sisusb, r, i, d) -#define GETIREG(r,i,d) sisusb_getidxreg(sisusb, r, i, d) -#define SETIREGOR(r,i,o) sisusb_setidxregor(sisusb, r, i, o) -#define SETIREGAND(r,i,a) sisusb_setidxregand(sisusb, r, i, a) -#define SETIREGANDOR(r,i,a,o) sisusb_setidxregandor(sisusb, r, i, a, o) -#define READL(a,d) sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d) -#define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d) -#define READB(a,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d) -#define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d) - -static int -sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype) -{ - int ret; - u8 tmp8; - - ret = GETIREG(SISSR, 0x16, &tmp8); - if (ramtype <= 1) { - tmp8 &= 0x3f; - ret |= SETIREG(SISSR, 0x16, tmp8); - tmp8 |= 0x80; - ret |= SETIREG(SISSR, 0x16, tmp8); - } else { - tmp8 |= 0xc0; - ret |= SETIREG(SISSR, 0x16, tmp8); - tmp8 &= 0x0f; - ret |= SETIREG(SISSR, 0x16, tmp8); - tmp8 |= 0x80; - ret |= SETIREG(SISSR, 0x16, tmp8); - tmp8 &= 0x0f; - ret |= SETIREG(SISSR, 0x16, tmp8); - tmp8 |= 0xd0; - ret |= SETIREG(SISSR, 0x16, tmp8); - tmp8 &= 0x0f; - ret |= SETIREG(SISSR, 0x16, tmp8); - tmp8 |= 0xa0; - ret |= SETIREG(SISSR, 0x16, tmp8); - } - return ret; -} - -static int -sisusb_getbuswidth(struct sisusb_usb_data *sisusb, int *bw, int *chab) -{ - int ret; - u8 ramtype, done = 0; - u32 t0, t1, t2, t3; - u32 ramptr = SISUSB_PCI_MEMBASE; - - ret = GETIREG(SISSR, 0x3a, &ramtype); - ramtype &= 3; - - ret |= SETIREG(SISSR, 0x13, 0x00); - - if (ramtype <= 1) { - ret |= SETIREG(SISSR, 0x14, 0x12); - ret |= SETIREGAND(SISSR, 0x15, 0xef); - } else { - ret |= SETIREG(SISSR, 0x14, 0x02); - } - - ret |= sisusb_triggersr16(sisusb, ramtype); - ret |= WRITEL(ramptr + 0, 0x01234567); - ret |= WRITEL(ramptr + 4, 0x456789ab); - ret |= WRITEL(ramptr + 8, 0x89abcdef); - ret |= WRITEL(ramptr + 12, 0xcdef0123); - ret |= WRITEL(ramptr + 16, 0x55555555); - ret |= WRITEL(ramptr + 20, 0x55555555); - ret |= WRITEL(ramptr + 24, 0xffffffff); - ret |= WRITEL(ramptr + 28, 0xffffffff); - ret |= READL(ramptr + 0, &t0); - ret |= READL(ramptr + 4, &t1); - ret |= READL(ramptr + 8, &t2); - ret |= READL(ramptr + 12, &t3); - - if (ramtype <= 1) { - - *chab = 0; *bw = 64; - - if ((t3 != 0xcdef0123) || (t2 != 0x89abcdef)) { - if ((t1 == 0x456789ab) && (t0 == 0x01234567)) { - *chab = 0; *bw = 64; - ret |= SETIREGAND(SISSR, 0x14, 0xfd); - } - } - if ((t1 != 0x456789ab) || (t0 != 0x01234567)) { - *chab = 1; *bw = 64; - ret |= SETIREGANDOR(SISSR, 0x14, 0xfc,0x01); - - ret |= sisusb_triggersr16(sisusb, ramtype); - ret |= WRITEL(ramptr + 0, 0x89abcdef); - ret |= WRITEL(ramptr + 4, 0xcdef0123); - ret |= WRITEL(ramptr + 8, 0x55555555); - ret |= WRITEL(ramptr + 12, 0x55555555); - ret |= WRITEL(ramptr + 16, 0xaaaaaaaa); - ret |= WRITEL(ramptr + 20, 0xaaaaaaaa); - ret |= READL(ramptr + 4, &t1); - - if (t1 != 0xcdef0123) { - *bw = 32; - ret |= SETIREGOR(SISSR, 0x15, 0x10); - } - } - - } else { - - *chab = 0; *bw = 64; /* default: cha, bw = 64 */ - - done = 0; - - if (t1 == 0x456789ab) { - if (t0 == 0x01234567) { - *chab = 0; *bw = 64; - done = 1; - } - } else { - if (t0 == 0x01234567) { - *chab = 0; *bw = 32; - ret |= SETIREG(SISSR, 0x14, 0x00); - done = 1; - } - } - - if (!done) { - ret |= SETIREG(SISSR, 0x14, 0x03); - ret |= sisusb_triggersr16(sisusb, ramtype); - - ret |= WRITEL(ramptr + 0, 0x01234567); - ret |= WRITEL(ramptr + 4, 0x456789ab); - ret |= WRITEL(ramptr + 8, 0x89abcdef); - ret |= WRITEL(ramptr + 12, 0xcdef0123); - ret |= WRITEL(ramptr + 16, 0x55555555); - ret |= WRITEL(ramptr + 20, 0x55555555); - ret |= WRITEL(ramptr + 24, 0xffffffff); - ret |= WRITEL(ramptr + 28, 0xffffffff); - ret |= READL(ramptr + 0, &t0); - ret |= READL(ramptr + 4, &t1); - - if (t1 == 0x456789ab) { - if (t0 == 0x01234567) { - *chab = 1; *bw = 64; - return ret; - } /* else error */ - } else { - if (t0 == 0x01234567) { - *chab = 1; *bw = 32; - ret |= SETIREG(SISSR, 0x14, 0x01); - } /* else error */ - } - } - } - return ret; -} - -static int -sisusb_verify_mclk(struct sisusb_usb_data *sisusb) -{ - int ret = 0; - u32 ramptr = SISUSB_PCI_MEMBASE; - u8 tmp1, tmp2, i, j; - - ret |= WRITEB(ramptr, 0xaa); - ret |= WRITEB(ramptr + 16, 0x55); - ret |= READB(ramptr, &tmp1); - ret |= READB(ramptr + 16, &tmp2); - if ((tmp1 != 0xaa) || (tmp2 != 0x55)) { - for (i = 0, j = 16; i < 2; i++, j += 16) { - ret |= GETIREG(SISSR, 0x21, &tmp1); - ret |= SETIREGAND(SISSR, 0x21, (tmp1 & 0xfb)); - ret |= SETIREGOR(SISSR, 0x3c, 0x01); /* not on 330 */ - ret |= SETIREGAND(SISSR, 0x3c, 0xfe); /* not on 330 */ - ret |= SETIREG(SISSR, 0x21, tmp1); - ret |= WRITEB(ramptr + 16 + j, j); - ret |= READB(ramptr + 16 + j, &tmp1); - if (tmp1 == j) { - ret |= WRITEB(ramptr + j, j); - break; - } - } - } - return ret; -} - -static int -sisusb_set_rank(struct sisusb_usb_data *sisusb, int *iret, int index, - u8 rankno, u8 chab, const u8 dramtype[][5], - int bw) -{ - int ret = 0, ranksize; - u8 tmp; - - *iret = 0; - - if ((rankno == 2) && (dramtype[index][0] == 2)) - return ret; - - ranksize = dramtype[index][3] / 2 * bw / 32; - - if ((ranksize * rankno) > 128) - return ret; - - tmp = 0; - while ((ranksize >>= 1) > 0) tmp += 0x10; - tmp |= ((rankno - 1) << 2); - tmp |= ((bw / 64) & 0x02); - tmp |= (chab & 0x01); - - ret = SETIREG(SISSR, 0x14, tmp); - ret |= sisusb_triggersr16(sisusb, 0); /* sic! */ - - *iret = 1; - - return ret; -} - -static int -sisusb_check_rbc(struct sisusb_usb_data *sisusb, int *iret, u32 inc, int testn) -{ - int ret = 0, i; - u32 j, tmp; - - *iret = 0; - - for (i = 0, j = 0; i < testn; i++) { - ret |= WRITEL(sisusb->vrambase + j, j); - j += inc; - } - - for (i = 0, j = 0; i < testn; i++) { - ret |= READL(sisusb->vrambase + j, &tmp); - if (tmp != j) return ret; - j += inc; - } - - *iret = 1; - return ret; -} - -static int -sisusb_check_ranks(struct sisusb_usb_data *sisusb, int *iret, int rankno, - int idx, int bw, const u8 rtype[][5]) -{ - int ret = 0, i, i2ret; - u32 inc; - - *iret = 0; - - for (i = rankno; i >= 1; i--) { - inc = 1 << (rtype[idx][2] + - rtype[idx][1] + - rtype[idx][0] + - bw / 64 + i); - ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2); - if (!i2ret) - return ret; - } - - inc = 1 << (rtype[idx][2] + bw / 64 + 2); - ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 4); - if (!i2ret) - return ret; - - inc = 1 << (10 + bw / 64); - ret |= sisusb_check_rbc(sisusb, &i2ret, inc, 2); - if (!i2ret) - return ret; - - *iret = 1; - return ret; -} - -static int -sisusb_get_sdram_size(struct sisusb_usb_data *sisusb, int *iret, int bw, - int chab) -{ - int ret = 0, i2ret = 0, i, j; - static const u8 sdramtype[13][5] = { - { 2, 12, 9, 64, 0x35 }, - { 1, 13, 9, 64, 0x44 }, - { 2, 12, 8, 32, 0x31 }, - { 2, 11, 9, 32, 0x25 }, - { 1, 12, 9, 32, 0x34 }, - { 1, 13, 8, 32, 0x40 }, - { 2, 11, 8, 16, 0x21 }, - { 1, 12, 8, 16, 0x30 }, - { 1, 11, 9, 16, 0x24 }, - { 1, 11, 8, 8, 0x20 }, - { 2, 9, 8, 4, 0x01 }, - { 1, 10, 8, 4, 0x10 }, - { 1, 9, 8, 2, 0x00 } - }; - - *iret = 1; /* error */ - - for (i = 0; i < 13; i++) { - ret |= SETIREGANDOR(SISSR, 0x13, 0x80, sdramtype[i][4]); - for (j = 2; j > 0; j--) { - ret |= sisusb_set_rank(sisusb, &i2ret, i, j, - chab, sdramtype, bw); - if (!i2ret) - continue; - - ret |= sisusb_check_ranks(sisusb, &i2ret, j, i, - bw, sdramtype); - if (i2ret) { - *iret = 0; /* ram size found */ - return ret; - } - } - } - - return ret; -} - -static int -sisusb_setup_screen(struct sisusb_usb_data *sisusb, int clrall, int drwfr) -{ - int ret = 0; - u32 address; - int i, length, modex, modey, bpp; - - modex = 640; modey = 480; bpp = 2; - - address = sisusb->vrambase; /* Clear video ram */ - - if (clrall) - length = sisusb->vramsize; - else - length = modex * bpp * modey; - - ret = sisusb_clear_vram(sisusb, address, length); - - if (!ret && drwfr) { - for (i = 0; i < modex; i++) { - address = sisusb->vrambase + (i * bpp); - ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, - address, 0xf100); - address += (modex * (modey-1) * bpp); - ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, - address, 0xf100); - } - for (i = 0; i < modey; i++) { - address = sisusb->vrambase + ((i * modex) * bpp); - ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, - address, 0xf100); - address += ((modex - 1) * bpp); - ret |= sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, - address, 0xf100); - } - } - - return ret; -} - -static int -sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines) -{ - int ret = 0, i, j, modex, modey, bpp, du; - u8 sr31, cr63, tmp8; - static const char attrdata[] = { - 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, - 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, - 0x01,0x00,0x00,0x00 - }; - static const char crtcrdata[] = { - 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e, - 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, - 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3, - 0xff - }; - static const char grcdata[] = { - 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f, - 0xff - }; - static const char crtcdata[] = { - 0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e, - 0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05, - 0x00 - }; - - modex = 640; modey = 480; bpp = 2; - - GETIREG(SISSR, 0x31, &sr31); - GETIREG(SISCR, 0x63, &cr63); - SETIREGOR(SISSR, 0x01, 0x20); - SETIREG(SISCR, 0x63, cr63 & 0xbf); - SETIREGOR(SISCR, 0x17, 0x80); - SETIREGOR(SISSR, 0x1f, 0x04); - SETIREGAND(SISSR, 0x07, 0xfb); - SETIREG(SISSR, 0x00, 0x03); /* seq */ - SETIREG(SISSR, 0x01, 0x21); - SETIREG(SISSR, 0x02, 0x0f); - SETIREG(SISSR, 0x03, 0x00); - SETIREG(SISSR, 0x04, 0x0e); - SETREG(SISMISCW, 0x23); /* misc */ - for (i = 0; i <= 0x18; i++) { /* crtc */ - SETIREG(SISCR, i, crtcrdata[i]); - } - for (i = 0; i <= 0x13; i++) { /* att */ - GETREG(SISINPSTAT, &tmp8); - SETREG(SISAR, i); - SETREG(SISAR, attrdata[i]); - } - GETREG(SISINPSTAT, &tmp8); - SETREG(SISAR, 0x14); - SETREG(SISAR, 0x00); - GETREG(SISINPSTAT, &tmp8); - SETREG(SISAR, 0x20); - GETREG(SISINPSTAT, &tmp8); - for (i = 0; i <= 0x08; i++) { /* grc */ - SETIREG(SISGR, i, grcdata[i]); - } - SETIREGAND(SISGR, 0x05, 0xbf); - for (i = 0x0A; i <= 0x0E; i++) { /* clr ext */ - SETIREG(SISSR, i, 0x00); - } - SETIREGAND(SISSR, 0x37, 0xfe); - SETREG(SISMISCW, 0xef); /* sync */ - SETIREG(SISCR, 0x11, 0x00); /* crtc */ - for (j = 0x00, i = 0; i <= 7; i++, j++) { - SETIREG(SISCR, j, crtcdata[i]); - } - for (j = 0x10; i <= 10; i++, j++) { - SETIREG(SISCR, j, crtcdata[i]); - } - for (j = 0x15; i <= 12; i++, j++) { - SETIREG(SISCR, j, crtcdata[i]); - } - for (j = 0x0A; i <= 15; i++, j++) { - SETIREG(SISSR, j, crtcdata[i]); - } - SETIREG(SISSR, 0x0E, (crtcdata[16] & 0xE0)); - SETIREGANDOR(SISCR, 0x09, 0x5f, ((crtcdata[16] & 0x01) << 5)); - SETIREG(SISCR, 0x14, 0x4f); - du = (modex / 16) * (bpp * 2); /* offset/pitch */ - if (modex % 16) du += bpp; - SETIREGANDOR(SISSR, 0x0e, 0xf0, ((du >> 8) & 0x0f)); - SETIREG(SISCR, 0x13, (du & 0xff)); - du <<= 5; - tmp8 = du >> 8; - if (du & 0xff) tmp8++; - SETIREG(SISSR, 0x10, tmp8); - SETIREG(SISSR, 0x31, 0x00); /* VCLK */ - SETIREG(SISSR, 0x2b, 0x1b); - SETIREG(SISSR, 0x2c, 0xe1); - SETIREG(SISSR, 0x2d, 0x01); - SETIREGAND(SISSR, 0x3d, 0xfe); /* FIFO */ - SETIREG(SISSR, 0x08, 0xae); - SETIREGAND(SISSR, 0x09, 0xf0); - SETIREG(SISSR, 0x08, 0x34); - SETIREGOR(SISSR, 0x3d, 0x01); - SETIREGAND(SISSR, 0x1f, 0x3f); /* mode regs */ - SETIREGANDOR(SISSR, 0x06, 0xc0, 0x0a); - SETIREG(SISCR, 0x19, 0x00); - SETIREGAND(SISCR, 0x1a, 0xfc); - SETIREGAND(SISSR, 0x0f, 0xb7); - SETIREGAND(SISSR, 0x31, 0xfb); - SETIREGANDOR(SISSR, 0x21, 0x1f, 0xa0); - SETIREGAND(SISSR, 0x32, 0xf3); - SETIREGANDOR(SISSR, 0x07, 0xf8, 0x03); - SETIREG(SISCR, 0x52, 0x6c); - - SETIREG(SISCR, 0x0d, 0x00); /* adjust frame */ - SETIREG(SISCR, 0x0c, 0x00); - SETIREG(SISSR, 0x0d, 0x00); - SETIREGAND(SISSR, 0x37, 0xfe); - - SETIREG(SISCR, 0x32, 0x20); - SETIREGAND(SISSR, 0x01, 0xdf); /* enable display */ - SETIREG(SISCR, 0x63, (cr63 & 0xbf)); - SETIREG(SISSR, 0x31, (sr31 & 0xfb)); - - if (touchengines) { - SETIREG(SISSR, 0x20, 0xa1); /* enable engines */ - SETIREGOR(SISSR, 0x1e, 0x5a); - - SETIREG(SISSR, 0x26, 0x01); /* disable cmdqueue */ - SETIREG(SISSR, 0x27, 0x1f); - SETIREG(SISSR, 0x26, 0x00); - } - - SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */ - - return ret; -} - -static int -sisusb_init_gfxcore(struct sisusb_usb_data *sisusb) -{ - int ret = 0, i, j, bw, chab, iret, retry = 3; - u8 tmp8, ramtype; - u32 tmp32; - static const char mclktable[] = { - 0x3b, 0x22, 0x01, 143, - 0x3b, 0x22, 0x01, 143, - 0x3b, 0x22, 0x01, 143, - 0x3b, 0x22, 0x01, 143 - }; - static const char eclktable[] = { - 0x3b, 0x22, 0x01, 143, - 0x3b, 0x22, 0x01, 143, - 0x3b, 0x22, 0x01, 143, - 0x3b, 0x22, 0x01, 143 - }; - static const char ramtypetable1[] = { - 0x00, 0x04, 0x60, 0x60, - 0x0f, 0x0f, 0x1f, 0x1f, - 0xba, 0xba, 0xba, 0xba, - 0xa9, 0xa9, 0xac, 0xac, - 0xa0, 0xa0, 0xa0, 0xa8, - 0x00, 0x00, 0x02, 0x02, - 0x30, 0x30, 0x40, 0x40 - }; - static const char ramtypetable2[] = { - 0x77, 0x77, 0x44, 0x44, - 0x77, 0x77, 0x44, 0x44, - 0x00, 0x00, 0x00, 0x00, - 0x5b, 0x5b, 0xab, 0xab, - 0x00, 0x00, 0xf0, 0xf8 - }; - - while (retry--) { - - /* Enable VGA */ - ret = GETREG(SISVGAEN, &tmp8); - ret |= SETREG(SISVGAEN, (tmp8 | 0x01)); - - /* Enable GPU access to VRAM */ - ret |= GETREG(SISMISCR, &tmp8); - ret |= SETREG(SISMISCW, (tmp8 | 0x01)); - - if (ret) continue; - - /* Reset registers */ - ret |= SETIREGAND(SISCR, 0x5b, 0xdf); - ret |= SETIREG(SISSR, 0x05, 0x86); - ret |= SETIREGOR(SISSR, 0x20, 0x01); - - ret |= SETREG(SISMISCW, 0x67); - - for (i = 0x06; i <= 0x1f; i++) { - ret |= SETIREG(SISSR, i, 0x00); - } - for (i = 0x21; i <= 0x27; i++) { - ret |= SETIREG(SISSR, i, 0x00); - } - for (i = 0x31; i <= 0x3d; i++) { - ret |= SETIREG(SISSR, i, 0x00); - } - for (i = 0x12; i <= 0x1b; i++) { - ret |= SETIREG(SISSR, i, 0x00); - } - for (i = 0x79; i <= 0x7c; i++) { - ret |= SETIREG(SISCR, i, 0x00); - } - - if (ret) continue; - - ret |= SETIREG(SISCR, 0x63, 0x80); - - ret |= GETIREG(SISSR, 0x3a, &ramtype); - ramtype &= 0x03; - - ret |= SETIREG(SISSR, 0x28, mclktable[ramtype * 4]); - ret |= SETIREG(SISSR, 0x29, mclktable[(ramtype * 4) + 1]); - ret |= SETIREG(SISSR, 0x2a, mclktable[(ramtype * 4) + 2]); - - ret |= SETIREG(SISSR, 0x2e, eclktable[ramtype * 4]); - ret |= SETIREG(SISSR, 0x2f, eclktable[(ramtype * 4) + 1]); - ret |= SETIREG(SISSR, 0x30, eclktable[(ramtype * 4) + 2]); - - ret |= SETIREG(SISSR, 0x07, 0x18); - ret |= SETIREG(SISSR, 0x11, 0x0f); - - if (ret) continue; - - for (i = 0x15, j = 0; i <= 0x1b; i++, j++) { - ret |= SETIREG(SISSR, i, ramtypetable1[(j*4) + ramtype]); - } - for (i = 0x40, j = 0; i <= 0x44; i++, j++) { - ret |= SETIREG(SISCR, i, ramtypetable2[(j*4) + ramtype]); - } - - ret |= SETIREG(SISCR, 0x49, 0xaa); - - ret |= SETIREG(SISSR, 0x1f, 0x00); - ret |= SETIREG(SISSR, 0x20, 0xa0); - ret |= SETIREG(SISSR, 0x23, 0xf6); - ret |= SETIREG(SISSR, 0x24, 0x0d); - ret |= SETIREG(SISSR, 0x25, 0x33); - - ret |= SETIREG(SISSR, 0x11, 0x0f); - - ret |= SETIREGOR(SISPART1, 0x2f, 0x01); - - ret |= SETIREGAND(SISCAP, 0x3f, 0xef); - - if (ret) continue; - - ret |= SETIREG(SISPART1, 0x00, 0x00); - - ret |= GETIREG(SISSR, 0x13, &tmp8); - tmp8 >>= 4; - - ret |= SETIREG(SISPART1, 0x02, 0x00); - ret |= SETIREG(SISPART1, 0x2e, 0x08); - - ret |= sisusb_read_pci_config(sisusb, 0x50, &tmp32); - tmp32 &= 0x00f00000; - tmp8 = (tmp32 == 0x100000) ? 0x33 : 0x03; - ret |= SETIREG(SISSR, 0x25, tmp8); - tmp8 = (tmp32 == 0x100000) ? 0xaa : 0x88; - ret |= SETIREG(SISCR, 0x49, tmp8); - - ret |= SETIREG(SISSR, 0x27, 0x1f); - ret |= SETIREG(SISSR, 0x31, 0x00); - ret |= SETIREG(SISSR, 0x32, 0x11); - ret |= SETIREG(SISSR, 0x33, 0x00); - - if (ret) continue; - - ret |= SETIREG(SISCR, 0x83, 0x00); - - ret |= sisusb_set_default_mode(sisusb, 0); - - ret |= SETIREGAND(SISSR, 0x21, 0xdf); - ret |= SETIREGOR(SISSR, 0x01, 0x20); - ret |= SETIREGOR(SISSR, 0x16, 0x0f); - - ret |= sisusb_triggersr16(sisusb, ramtype); - - /* Disable refresh */ - ret |= SETIREGAND(SISSR, 0x17, 0xf8); - ret |= SETIREGOR(SISSR, 0x19, 0x03); - - ret |= sisusb_getbuswidth(sisusb, &bw, &chab); - ret |= sisusb_verify_mclk(sisusb); - - if (ramtype <= 1) { - ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab); - if (iret) { - dev_err(&sisusb->sisusb_dev->dev,"RAM size detection failed, assuming 8MB video RAM\n"); - ret |= SETIREG(SISSR,0x14,0x31); - /* TODO */ - } - } else { - dev_err(&sisusb->sisusb_dev->dev, "DDR RAM device found, assuming 8MB video RAM\n"); - ret |= SETIREG(SISSR,0x14,0x31); - /* *** TODO *** */ - } - - /* Enable refresh */ - ret |= SETIREG(SISSR, 0x16, ramtypetable1[4 + ramtype]); - ret |= SETIREG(SISSR, 0x17, ramtypetable1[8 + ramtype]); - ret |= SETIREG(SISSR, 0x19, ramtypetable1[16 + ramtype]); - - ret |= SETIREGOR(SISSR, 0x21, 0x20); - - ret |= SETIREG(SISSR, 0x22, 0xfb); - ret |= SETIREG(SISSR, 0x21, 0xa5); - - if (ret == 0) - break; - } - - return ret; -} - -#undef SETREG -#undef GETREG -#undef SETIREG -#undef GETIREG -#undef SETIREGOR -#undef SETIREGAND -#undef SETIREGANDOR -#undef READL -#undef WRITEL - -static void -sisusb_get_ramconfig(struct sisusb_usb_data *sisusb) -{ - u8 tmp8, tmp82, ramtype; - int bw = 0; - char *ramtypetext1 = NULL; - const char *ramtypetext2[] = { "SDR SDRAM", "SDR SGRAM", - "DDR SDRAM", "DDR SGRAM" }; - static const int busSDR[4] = {64, 64, 128, 128}; - static const int busDDR[4] = {32, 32, 64, 64}; - static const int busDDRA[4] = {64+32, 64+32 , (64+32)*2, (64+32)*2}; - - sisusb_getidxreg(sisusb, SISSR, 0x14, &tmp8); - sisusb_getidxreg(sisusb, SISSR, 0x15, &tmp82); - sisusb_getidxreg(sisusb, SISSR, 0x3a, &ramtype); - sisusb->vramsize = (1 << ((tmp8 & 0xf0) >> 4)) * 1024 * 1024; - ramtype &= 0x03; - switch ((tmp8 >> 2) & 0x03) { - case 0: ramtypetext1 = "1 ch/1 r"; - if (tmp82 & 0x10) { - bw = 32; - } else { - bw = busSDR[(tmp8 & 0x03)]; - } - break; - case 1: ramtypetext1 = "1 ch/2 r"; - sisusb->vramsize <<= 1; - bw = busSDR[(tmp8 & 0x03)]; - break; - case 2: ramtypetext1 = "asymmeric"; - sisusb->vramsize += sisusb->vramsize/2; - bw = busDDRA[(tmp8 & 0x03)]; - break; - case 3: ramtypetext1 = "2 channel"; - sisusb->vramsize <<= 1; - bw = busDDR[(tmp8 & 0x03)]; - break; - } - - dev_info(&sisusb->sisusb_dev->dev, "%dMB %s %s, bus width %d\n", (sisusb->vramsize >> 20), ramtypetext1, - ramtypetext2[ramtype], bw); -} - -static int -sisusb_do_init_gfxdevice(struct sisusb_usb_data *sisusb) -{ - struct sisusb_packet packet; - int ret; - u32 tmp32; - - /* Do some magic */ - packet.header = 0x001f; - packet.address = 0x00000324; - packet.data = 0x00000004; - ret = sisusb_send_bridge_packet(sisusb, 10, &packet, 0); - - packet.header = 0x001f; - packet.address = 0x00000364; - packet.data = 0x00000004; - ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0); - - packet.header = 0x001f; - packet.address = 0x00000384; - packet.data = 0x00000004; - ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0); - - packet.header = 0x001f; - packet.address = 0x00000100; - packet.data = 0x00000700; - ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0); - - packet.header = 0x000f; - packet.address = 0x00000004; - ret |= sisusb_send_bridge_packet(sisusb, 6, &packet, 0); - packet.data |= 0x17; - ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0); - - /* Init BAR 0 (VRAM) */ - ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32); - ret |= sisusb_write_pci_config(sisusb, 0x10, 0xfffffff0); - ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32); - tmp32 &= 0x0f; - tmp32 |= SISUSB_PCI_MEMBASE; - ret |= sisusb_write_pci_config(sisusb, 0x10, tmp32); - - /* Init BAR 1 (MMIO) */ - ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32); - ret |= sisusb_write_pci_config(sisusb, 0x14, 0xfffffff0); - ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32); - tmp32 &= 0x0f; - tmp32 |= SISUSB_PCI_MMIOBASE; - ret |= sisusb_write_pci_config(sisusb, 0x14, tmp32); - - /* Init BAR 2 (i/o ports) */ - ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32); - ret |= sisusb_write_pci_config(sisusb, 0x18, 0xfffffff0); - ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32); - tmp32 &= 0x0f; - tmp32 |= SISUSB_PCI_IOPORTBASE; - ret |= sisusb_write_pci_config(sisusb, 0x18, tmp32); - - /* Enable memory and i/o access */ - ret |= sisusb_read_pci_config(sisusb, 0x04, &tmp32); - tmp32 |= 0x3; - ret |= sisusb_write_pci_config(sisusb, 0x04, tmp32); - - if (ret == 0) { - /* Some further magic */ - packet.header = 0x001f; - packet.address = 0x00000050; - packet.data = 0x000000ff; - ret |= sisusb_send_bridge_packet(sisusb, 10, &packet, 0); - } - - return ret; -} - -/* Initialize the graphics device (return 0 on success) - * This initializes the net2280 as well as the PCI registers - * of the graphics board. - */ - -static int -sisusb_init_gfxdevice(struct sisusb_usb_data *sisusb, int initscreen) -{ - int ret = 0, test = 0; - u32 tmp32; - - if (sisusb->devinit == 1) { - /* Read PCI BARs and see if they have been set up */ - ret |= sisusb_read_pci_config(sisusb, 0x10, &tmp32); - if (ret) return ret; - if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MEMBASE) test++; - - ret |= sisusb_read_pci_config(sisusb, 0x14, &tmp32); - if (ret) return ret; - if ((tmp32 & 0xfffffff0) == SISUSB_PCI_MMIOBASE) test++; - - ret |= sisusb_read_pci_config(sisusb, 0x18, &tmp32); - if (ret) return ret; - if ((tmp32 & 0xfffffff0) == SISUSB_PCI_IOPORTBASE) test++; - } - - /* No? So reset the device */ - if ((sisusb->devinit == 0) || (test != 3)) { - - ret |= sisusb_do_init_gfxdevice(sisusb); - - if (ret == 0) - sisusb->devinit = 1; - - } - - if (sisusb->devinit) { - /* Initialize the graphics core */ - if (sisusb_init_gfxcore(sisusb) == 0) { - sisusb->gfxinit = 1; - sisusb_get_ramconfig(sisusb); - ret |= sisusb_set_default_mode(sisusb, 1); - ret |= sisusb_setup_screen(sisusb, 1, initscreen); - } - } - - return ret; -} - - -#ifdef INCL_SISUSB_CON - -/* Set up default text mode: - - Set text mode (0x03) - - Upload default font - - Upload user font (if available) -*/ - -int -sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init) -{ - int ret = 0, slot = sisusb->font_slot, i; - const struct font_desc *myfont; - u8 *tempbuf; - u16 *tempbufb; - size_t written; - static const char bootstring[] = "SiSUSB VGA text console, (C) 2005 Thomas Winischhofer."; - static const char bootlogo[] = "(o_ //\\ V_/_"; - - /* sisusb->lock is down */ - - if (!sisusb->SiS_Pr) - return 1; - - sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30; - sisusb->SiS_Pr->sisusb = (void *)sisusb; - - /* Set mode 0x03 */ - SiSUSBSetMode(sisusb->SiS_Pr, 0x03); - - if (!(myfont = find_font("VGA8x16"))) - return 1; - - if (!(tempbuf = vmalloc(8192))) - return 1; - - for (i = 0; i < 256; i++) - memcpy(tempbuf + (i * 32), myfont->data + (i * 16), 16); - - /* Upload default font */ - ret = sisusbcon_do_font_op(sisusb, 1, 0, tempbuf, 8192, 0, 1, NULL, 16, 0); - - vfree(tempbuf); - - /* Upload user font (and reset current slot) */ - if (sisusb->font_backup) { - ret |= sisusbcon_do_font_op(sisusb, 1, 2, sisusb->font_backup, - 8192, sisusb->font_backup_512, 1, NULL, - sisusb->font_backup_height, 0); - if (slot != 2) - sisusbcon_do_font_op(sisusb, 1, 0, NULL, 0, 0, 1, - NULL, 16, 0); - } - - if (init && !sisusb->scrbuf) { - - if ((tempbuf = vmalloc(8192))) { - - i = 4096; - tempbufb = (u16 *)tempbuf; - while (i--) - *(tempbufb++) = 0x0720; - - i = 0; - tempbufb = (u16 *)tempbuf; - while (bootlogo[i]) { - *(tempbufb++) = 0x0700 | bootlogo[i++]; - if (!(i % 4)) - tempbufb += 76; - } - - i = 0; - tempbufb = (u16 *)tempbuf + 6; - while (bootstring[i]) - *(tempbufb++) = 0x0700 | bootstring[i++]; - - ret |= sisusb_copy_memory(sisusb, tempbuf, - sisusb->vrambase, 8192, &written); - - vfree(tempbuf); - - } - - } else if (sisusb->scrbuf) { - - ret |= sisusb_copy_memory(sisusb, (char *)sisusb->scrbuf, - sisusb->vrambase, sisusb->scrbuf_size, &written); - - } - - if (sisusb->sisusb_cursor_size_from >= 0 && - sisusb->sisusb_cursor_size_to >= 0) { - sisusb_setidxreg(sisusb, SISCR, 0x0a, - sisusb->sisusb_cursor_size_from); - sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0xe0, - sisusb->sisusb_cursor_size_to); - } else { - sisusb_setidxreg(sisusb, SISCR, 0x0a, 0x2d); - sisusb_setidxreg(sisusb, SISCR, 0x0b, 0x0e); - sisusb->sisusb_cursor_size_to = -1; - } - - slot = sisusb->sisusb_cursor_loc; - if(slot < 0) slot = 0; - - sisusb->sisusb_cursor_loc = -1; - sisusb->bad_cursor_pos = 1; - - sisusb_set_cursor(sisusb, slot); - - sisusb_setidxreg(sisusb, SISCR, 0x0c, (sisusb->cur_start_addr >> 8)); - sisusb_setidxreg(sisusb, SISCR, 0x0d, (sisusb->cur_start_addr & 0xff)); - - sisusb->textmodedestroyed = 0; - - /* sisusb->lock is down */ - - return ret; -} - -#endif - -/* fops */ - -static int -sisusb_open(struct inode *inode, struct file *file) -{ - struct sisusb_usb_data *sisusb; - struct usb_interface *interface; - int subminor = iminor(inode); - - if (!(interface = usb_find_interface(&sisusb_driver, subminor))) { - return -ENODEV; - } - - if (!(sisusb = usb_get_intfdata(interface))) { - return -ENODEV; - } - - mutex_lock(&sisusb->lock); - - if (!sisusb->present || !sisusb->ready) { - mutex_unlock(&sisusb->lock); - return -ENODEV; - } - - if (sisusb->isopen) { - mutex_unlock(&sisusb->lock); - return -EBUSY; - } - - if (!sisusb->devinit) { - if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH || - sisusb->sisusb_dev->speed == USB_SPEED_SUPER) { - if (sisusb_init_gfxdevice(sisusb, 0)) { - mutex_unlock(&sisusb->lock); - dev_err(&sisusb->sisusb_dev->dev, "Failed to initialize device\n"); - return -EIO; - } - } else { - mutex_unlock(&sisusb->lock); - dev_err(&sisusb->sisusb_dev->dev, "Device not attached to USB 2.0 hub\n"); - return -EIO; - } - } - - /* Increment usage count for our sisusb */ - kref_get(&sisusb->kref); - - sisusb->isopen = 1; - - file->private_data = sisusb; - - mutex_unlock(&sisusb->lock); - - return 0; -} - -void -sisusb_delete(struct kref *kref) -{ - struct sisusb_usb_data *sisusb = to_sisusb_dev(kref); - - if (!sisusb) - return; - - if (sisusb->sisusb_dev) - usb_put_dev(sisusb->sisusb_dev); - - sisusb->sisusb_dev = NULL; - sisusb_free_buffers(sisusb); - sisusb_free_urbs(sisusb); -#ifdef INCL_SISUSB_CON - kfree(sisusb->SiS_Pr); -#endif - kfree(sisusb); -} - -static int -sisusb_release(struct inode *inode, struct file *file) -{ - struct sisusb_usb_data *sisusb; - - if (!(sisusb = file->private_data)) - return -ENODEV; - - mutex_lock(&sisusb->lock); - - if (sisusb->present) { - /* Wait for all URBs to finish if device still present */ - if (!sisusb_wait_all_out_complete(sisusb)) - sisusb_kill_all_busy(sisusb); - } - - sisusb->isopen = 0; - file->private_data = NULL; - - mutex_unlock(&sisusb->lock); - - /* decrement the usage count on our device */ - kref_put(&sisusb->kref, sisusb_delete); - - return 0; -} - -static ssize_t -sisusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - struct sisusb_usb_data *sisusb; - ssize_t bytes_read = 0; - int errno = 0; - u8 buf8; - u16 buf16; - u32 buf32, address; - - if (!(sisusb = file->private_data)) - return -ENODEV; - - mutex_lock(&sisusb->lock); - - /* Sanity check */ - if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) { - mutex_unlock(&sisusb->lock); - return -ENODEV; - } - - if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE && - (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) { - - address = (*ppos) - - SISUSB_PCI_PSEUDO_IOPORTBASE + - SISUSB_PCI_IOPORTBASE; - - /* Read i/o ports - * Byte, word and long(32) can be read. As this - * emulates inX instructions, the data returned is - * in machine-endianness. - */ - switch (count) { - - case 1: - if (sisusb_read_memio_byte(sisusb, - SISUSB_TYPE_IO, - address, &buf8)) - errno = -EIO; - else if (put_user(buf8, (u8 __user *)buffer)) - errno = -EFAULT; - else - bytes_read = 1; - - break; - - case 2: - if (sisusb_read_memio_word(sisusb, - SISUSB_TYPE_IO, - address, &buf16)) - errno = -EIO; - else if (put_user(buf16, (u16 __user *)buffer)) - errno = -EFAULT; - else - bytes_read = 2; - - break; - - case 4: - if (sisusb_read_memio_long(sisusb, - SISUSB_TYPE_IO, - address, &buf32)) - errno = -EIO; - else if (put_user(buf32, (u32 __user *)buffer)) - errno = -EFAULT; - else - bytes_read = 4; - - break; - - default: - errno = -EIO; - - } - - } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE && - (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) { - - address = (*ppos) - - SISUSB_PCI_PSEUDO_MEMBASE + - SISUSB_PCI_MEMBASE; - - /* Read video ram - * Remember: Data delivered is never endian-corrected - */ - errno = sisusb_read_mem_bulk(sisusb, address, - NULL, count, buffer, &bytes_read); - - if (bytes_read) - errno = bytes_read; - - } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE && - (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) { - - address = (*ppos) - - SISUSB_PCI_PSEUDO_MMIOBASE + - SISUSB_PCI_MMIOBASE; - - /* Read MMIO - * Remember: Data delivered is never endian-corrected - */ - errno = sisusb_read_mem_bulk(sisusb, address, - NULL, count, buffer, &bytes_read); - - if (bytes_read) - errno = bytes_read; - - } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE && - (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + 0x5c) { - - if (count != 4) { - mutex_unlock(&sisusb->lock); - return -EINVAL; - } - - address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE; - - /* Read PCI config register - * Return value delivered in machine endianness. - */ - if (sisusb_read_pci_config(sisusb, address, &buf32)) - errno = -EIO; - else if (put_user(buf32, (u32 __user *)buffer)) - errno = -EFAULT; - else - bytes_read = 4; - - } else { - - errno = -EBADFD; - - } - - (*ppos) += bytes_read; - - mutex_unlock(&sisusb->lock); - - return errno ? errno : bytes_read; -} - -static ssize_t -sisusb_write(struct file *file, const char __user *buffer, size_t count, - loff_t *ppos) -{ - struct sisusb_usb_data *sisusb; - int errno = 0; - ssize_t bytes_written = 0; - u8 buf8; - u16 buf16; - u32 buf32, address; - - if (!(sisusb = file->private_data)) - return -ENODEV; - - mutex_lock(&sisusb->lock); - - /* Sanity check */ - if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) { - mutex_unlock(&sisusb->lock); - return -ENODEV; - } - - if ((*ppos) >= SISUSB_PCI_PSEUDO_IOPORTBASE && - (*ppos) < SISUSB_PCI_PSEUDO_IOPORTBASE + 128) { - - address = (*ppos) - - SISUSB_PCI_PSEUDO_IOPORTBASE + - SISUSB_PCI_IOPORTBASE; - - /* Write i/o ports - * Byte, word and long(32) can be written. As this - * emulates outX instructions, the data is expected - * in machine-endianness. - */ - switch (count) { - - case 1: - if (get_user(buf8, (u8 __user *)buffer)) - errno = -EFAULT; - else if (sisusb_write_memio_byte(sisusb, - SISUSB_TYPE_IO, - address, buf8)) - errno = -EIO; - else - bytes_written = 1; - - break; - - case 2: - if (get_user(buf16, (u16 __user *)buffer)) - errno = -EFAULT; - else if (sisusb_write_memio_word(sisusb, - SISUSB_TYPE_IO, - address, buf16)) - errno = -EIO; - else - bytes_written = 2; - - break; - - case 4: - if (get_user(buf32, (u32 __user *)buffer)) - errno = -EFAULT; - else if (sisusb_write_memio_long(sisusb, - SISUSB_TYPE_IO, - address, buf32)) - errno = -EIO; - else - bytes_written = 4; - - break; - - default: - errno = -EIO; - } - - } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MEMBASE && - (*ppos) < SISUSB_PCI_PSEUDO_MEMBASE + sisusb->vramsize) { - - address = (*ppos) - - SISUSB_PCI_PSEUDO_MEMBASE + - SISUSB_PCI_MEMBASE; - - /* Write video ram. - * Buffer is copied 1:1, therefore, on big-endian - * machines, the data must be swapped by userland - * in advance (if applicable; no swapping in 8bpp - * mode or if YUV data is being transferred). - */ - errno = sisusb_write_mem_bulk(sisusb, address, NULL, - count, buffer, 0, &bytes_written); - - if (bytes_written) - errno = bytes_written; - - } else if ((*ppos) >= SISUSB_PCI_PSEUDO_MMIOBASE && - (*ppos) < SISUSB_PCI_PSEUDO_MMIOBASE + SISUSB_PCI_MMIOSIZE) { - - address = (*ppos) - - SISUSB_PCI_PSEUDO_MMIOBASE + - SISUSB_PCI_MMIOBASE; - - /* Write MMIO. - * Buffer is copied 1:1, therefore, on big-endian - * machines, the data must be swapped by userland - * in advance. - */ - errno = sisusb_write_mem_bulk(sisusb, address, NULL, - count, buffer, 0, &bytes_written); - - if (bytes_written) - errno = bytes_written; - - } else if ((*ppos) >= SISUSB_PCI_PSEUDO_PCIBASE && - (*ppos) <= SISUSB_PCI_PSEUDO_PCIBASE + SISUSB_PCI_PCONFSIZE) { - - if (count != 4) { - mutex_unlock(&sisusb->lock); - return -EINVAL; - } - - address = (*ppos) - SISUSB_PCI_PSEUDO_PCIBASE; - - /* Write PCI config register. - * Given value expected in machine endianness. - */ - if (get_user(buf32, (u32 __user *)buffer)) - errno = -EFAULT; - else if (sisusb_write_pci_config(sisusb, address, buf32)) - errno = -EIO; - else - bytes_written = 4; - - - } else { - - /* Error */ - errno = -EBADFD; - - } - - (*ppos) += bytes_written; - - mutex_unlock(&sisusb->lock); - - return errno ? errno : bytes_written; -} - -static loff_t -sisusb_lseek(struct file *file, loff_t offset, int orig) -{ - struct sisusb_usb_data *sisusb; - loff_t ret; - - if (!(sisusb = file->private_data)) - return -ENODEV; - - mutex_lock(&sisusb->lock); - - /* Sanity check */ - if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) { - mutex_unlock(&sisusb->lock); - return -ENODEV; - } - - switch (orig) { - case 0: - file->f_pos = offset; - ret = file->f_pos; - /* never negative, no force_successful_syscall needed */ - break; - case 1: - file->f_pos += offset; - ret = file->f_pos; - /* never negative, no force_successful_syscall needed */ - break; - default: - /* seeking relative to "end of file" is not supported */ - ret = -EINVAL; - } - - mutex_unlock(&sisusb->lock); - return ret; -} - -static int -sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y, - unsigned long arg) -{ - int retval, port, length; - u32 address; - - /* All our commands require the device - * to be initialized. - */ - if (!sisusb->devinit) - return -ENODEV; - - port = y->data3 - - SISUSB_PCI_PSEUDO_IOPORTBASE + - SISUSB_PCI_IOPORTBASE; - - switch (y->operation) { - case SUCMD_GET: - retval = sisusb_getidxreg(sisusb, port, - y->data0, &y->data1); - if (!retval) { - if (copy_to_user((void __user *)arg, y, - sizeof(*y))) - retval = -EFAULT; - } - break; - - case SUCMD_SET: - retval = sisusb_setidxreg(sisusb, port, - y->data0, y->data1); - break; - - case SUCMD_SETOR: - retval = sisusb_setidxregor(sisusb, port, - y->data0, y->data1); - break; - - case SUCMD_SETAND: - retval = sisusb_setidxregand(sisusb, port, - y->data0, y->data1); - break; - - case SUCMD_SETANDOR: - retval = sisusb_setidxregandor(sisusb, port, - y->data0, y->data1, y->data2); - break; - - case SUCMD_SETMASK: - retval = sisusb_setidxregmask(sisusb, port, - y->data0, y->data1, y->data2); - break; - - case SUCMD_CLRSCR: - /* Gfx core must be initialized */ - if (!sisusb->gfxinit) - return -ENODEV; - - length = (y->data0 << 16) | (y->data1 << 8) | y->data2; - address = y->data3 - - SISUSB_PCI_PSEUDO_MEMBASE + - SISUSB_PCI_MEMBASE; - retval = sisusb_clear_vram(sisusb, address, length); - break; - - case SUCMD_HANDLETEXTMODE: - retval = 0; -#ifdef INCL_SISUSB_CON - /* Gfx core must be initialized, SiS_Pr must exist */ - if (!sisusb->gfxinit || !sisusb->SiS_Pr) - return -ENODEV; - - switch (y->data0) { - case 0: - retval = sisusb_reset_text_mode(sisusb, 0); - break; - case 1: - sisusb->textmodedestroyed = 1; - break; - } -#endif - break; - -#ifdef INCL_SISUSB_CON - case SUCMD_SETMODE: - /* Gfx core must be initialized, SiS_Pr must exist */ - if (!sisusb->gfxinit || !sisusb->SiS_Pr) - return -ENODEV; - - retval = 0; - - sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30; - sisusb->SiS_Pr->sisusb = (void *)sisusb; - - if (SiSUSBSetMode(sisusb->SiS_Pr, y->data3)) - retval = -EINVAL; - - break; - - case SUCMD_SETVESAMODE: - /* Gfx core must be initialized, SiS_Pr must exist */ - if (!sisusb->gfxinit || !sisusb->SiS_Pr) - return -ENODEV; - - retval = 0; - - sisusb->SiS_Pr->IOAddress = SISUSB_PCI_IOPORTBASE + 0x30; - sisusb->SiS_Pr->sisusb = (void *)sisusb; - - if (SiSUSBSetVESAMode(sisusb->SiS_Pr, y->data3)) - retval = -EINVAL; - - break; -#endif - - default: - retval = -EINVAL; - } - - if (retval > 0) - retval = -EIO; - - return retval; -} - -static long -sisusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct sisusb_usb_data *sisusb; - struct sisusb_info x; - struct sisusb_command y; - long retval = 0; - u32 __user *argp = (u32 __user *)arg; - - if (!(sisusb = file->private_data)) - return -ENODEV; - - mutex_lock(&sisusb->lock); - - /* Sanity check */ - if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) { - retval = -ENODEV; - goto err_out; - } - - switch (cmd) { - - case SISUSB_GET_CONFIG_SIZE: - - if (put_user(sizeof(x), argp)) - retval = -EFAULT; - - break; - - case SISUSB_GET_CONFIG: - - x.sisusb_id = SISUSB_ID; - x.sisusb_version = SISUSB_VERSION; - x.sisusb_revision = SISUSB_REVISION; - x.sisusb_patchlevel = SISUSB_PATCHLEVEL; - x.sisusb_gfxinit = sisusb->gfxinit; - x.sisusb_vrambase = SISUSB_PCI_PSEUDO_MEMBASE; - x.sisusb_mmiobase = SISUSB_PCI_PSEUDO_MMIOBASE; - x.sisusb_iobase = SISUSB_PCI_PSEUDO_IOPORTBASE; - x.sisusb_pcibase = SISUSB_PCI_PSEUDO_PCIBASE; - x.sisusb_vramsize = sisusb->vramsize; - x.sisusb_minor = sisusb->minor; - x.sisusb_fbdevactive= 0; -#ifdef INCL_SISUSB_CON - x.sisusb_conactive = sisusb->haveconsole ? 1 : 0; -#else - x.sisusb_conactive = 0; -#endif - memset(x.sisusb_reserved, 0, sizeof(x.sisusb_reserved)); - - if (copy_to_user((void __user *)arg, &x, sizeof(x))) - retval = -EFAULT; - - break; - - case SISUSB_COMMAND: - - if (copy_from_user(&y, (void __user *)arg, sizeof(y))) - retval = -EFAULT; - else - retval = sisusb_handle_command(sisusb, &y, arg); - - break; - - default: - retval = -ENOTTY; - break; - } - -err_out: - mutex_unlock(&sisusb->lock); - return retval; -} - -#ifdef SISUSB_NEW_CONFIG_COMPAT -static long -sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg) -{ - long retval; - - switch (cmd) { - case SISUSB_GET_CONFIG_SIZE: - case SISUSB_GET_CONFIG: - case SISUSB_COMMAND: - retval = sisusb_ioctl(f, cmd, arg); - return retval; - - default: - return -ENOIOCTLCMD; - } -} -#endif - -static const struct file_operations usb_sisusb_fops = { - .owner = THIS_MODULE, - .open = sisusb_open, - .release = sisusb_release, - .read = sisusb_read, - .write = sisusb_write, - .llseek = sisusb_lseek, -#ifdef SISUSB_NEW_CONFIG_COMPAT - .compat_ioctl = sisusb_compat_ioctl, -#endif - .unlocked_ioctl = sisusb_ioctl -}; - -static struct usb_class_driver usb_sisusb_class = { - .name = "sisusbvga%d", - .fops = &usb_sisusb_fops, - .minor_base = SISUSB_MINOR -}; - -static int sisusb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - struct sisusb_usb_data *sisusb; - int retval = 0, i; - - dev_info(&dev->dev, "USB2VGA dongle found at address %d\n", - dev->devnum); - - /* Allocate memory for our private */ - if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) { - dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for private data\n"); - return -ENOMEM; - } - kref_init(&sisusb->kref); - - mutex_init(&(sisusb->lock)); - - /* Register device */ - if ((retval = usb_register_dev(intf, &usb_sisusb_class))) { - dev_err(&sisusb->sisusb_dev->dev, "Failed to get a minor for device %d\n", - dev->devnum); - retval = -ENODEV; - goto error_1; - } - - sisusb->sisusb_dev = dev; - sisusb->minor = intf->minor; - sisusb->vrambase = SISUSB_PCI_MEMBASE; - sisusb->mmiobase = SISUSB_PCI_MMIOBASE; - sisusb->mmiosize = SISUSB_PCI_MMIOSIZE; - sisusb->ioportbase = SISUSB_PCI_IOPORTBASE; - /* Everything else is zero */ - - /* Allocate buffers */ - sisusb->ibufsize = SISUSB_IBUF_SIZE; - if (!(sisusb->ibuf = kmalloc(SISUSB_IBUF_SIZE, GFP_KERNEL))) { - dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for input buffer"); - retval = -ENOMEM; - goto error_2; - } - - sisusb->numobufs = 0; - sisusb->obufsize = SISUSB_OBUF_SIZE; - for (i = 0; i < NUMOBUFS; i++) { - if (!(sisusb->obuf[i] = kmalloc(SISUSB_OBUF_SIZE, GFP_KERNEL))) { - if (i == 0) { - dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for output buffer\n"); - retval = -ENOMEM; - goto error_3; - } - break; - } else - sisusb->numobufs++; - - } - - /* Allocate URBs */ - if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) { - dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n"); - retval = -ENOMEM; - goto error_3; - } - sisusb->completein = 1; - - for (i = 0; i < sisusb->numobufs; i++) { - if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) { - dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n"); - retval = -ENOMEM; - goto error_4; - } - sisusb->urbout_context[i].sisusb = (void *)sisusb; - sisusb->urbout_context[i].urbindex = i; - sisusb->urbstatus[i] = 0; - } - - dev_info(&sisusb->sisusb_dev->dev, "Allocated %d output buffers\n", sisusb->numobufs); - -#ifdef INCL_SISUSB_CON - /* Allocate our SiS_Pr */ - if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) { - dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate SiS_Pr\n"); - } -#endif - - /* Do remaining init stuff */ - - init_waitqueue_head(&sisusb->wait_q); - - usb_set_intfdata(intf, sisusb); - - usb_get_dev(sisusb->sisusb_dev); - - sisusb->present = 1; - - if (dev->speed == USB_SPEED_HIGH || dev->speed == USB_SPEED_SUPER) { - int initscreen = 1; -#ifdef INCL_SISUSB_CON - if (sisusb_first_vc > 0 && - sisusb_last_vc > 0 && - sisusb_first_vc <= sisusb_last_vc && - sisusb_last_vc <= MAX_NR_CONSOLES) - initscreen = 0; -#endif - if (sisusb_init_gfxdevice(sisusb, initscreen)) - dev_err(&sisusb->sisusb_dev->dev, "Failed to early initialize device\n"); - - } else - dev_info(&sisusb->sisusb_dev->dev, "Not attached to USB 2.0 hub, deferring init\n"); - - sisusb->ready = 1; - -#ifdef SISUSBENDIANTEST - dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST ***\n"); - sisusb_testreadwrite(sisusb); - dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST END ***\n"); -#endif - -#ifdef INCL_SISUSB_CON - sisusb_console_init(sisusb, sisusb_first_vc, sisusb_last_vc); -#endif - - return 0; - -error_4: - sisusb_free_urbs(sisusb); -error_3: - sisusb_free_buffers(sisusb); -error_2: - usb_deregister_dev(intf, &usb_sisusb_class); -error_1: - kfree(sisusb); - return retval; -} - -static void sisusb_disconnect(struct usb_interface *intf) -{ - struct sisusb_usb_data *sisusb; - - /* This should *not* happen */ - if (!(sisusb = usb_get_intfdata(intf))) - return; - -#ifdef INCL_SISUSB_CON - sisusb_console_exit(sisusb); -#endif - - usb_deregister_dev(intf, &usb_sisusb_class); - - mutex_lock(&sisusb->lock); - - /* Wait for all URBs to complete and kill them in case (MUST do) */ - if (!sisusb_wait_all_out_complete(sisusb)) - sisusb_kill_all_busy(sisusb); - - usb_set_intfdata(intf, NULL); - - sisusb->present = 0; - sisusb->ready = 0; - - mutex_unlock(&sisusb->lock); - - /* decrement our usage count */ - kref_put(&sisusb->kref, sisusb_delete); -} - -static const struct usb_device_id sisusb_table[] = { - { USB_DEVICE(0x0711, 0x0550) }, - { USB_DEVICE(0x0711, 0x0900) }, - { USB_DEVICE(0x0711, 0x0901) }, - { USB_DEVICE(0x0711, 0x0902) }, - { USB_DEVICE(0x0711, 0x0903) }, - { USB_DEVICE(0x0711, 0x0918) }, - { USB_DEVICE(0x0711, 0x0920) }, - { USB_DEVICE(0x182d, 0x021c) }, - { USB_DEVICE(0x182d, 0x0269) }, - { } -}; - -MODULE_DEVICE_TABLE (usb, sisusb_table); - -static struct usb_driver sisusb_driver = { - .name = "sisusb", - .probe = sisusb_probe, - .disconnect = sisusb_disconnect, - .id_table = sisusb_table, -}; - -static int __init usb_sisusb_init(void) -{ - -#ifdef INCL_SISUSB_CON - sisusb_init_concode(); -#endif - - return usb_register(&sisusb_driver); -} - -static void __exit usb_sisusb_exit(void) -{ - usb_deregister(&sisusb_driver); -} - -module_init(usb_sisusb_init); -module_exit(usb_sisusb_exit); - -MODULE_AUTHOR("Thomas Winischhofer "); -MODULE_DESCRIPTION("sisusbvga - Driver for Net2280/SiS315-based USB2VGA dongles"); -MODULE_LICENSE("GPL"); - diff --git a/ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb.h b/ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb.h deleted file mode 100644 index 55492a59..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb.h +++ /dev/null @@ -1,311 +0,0 @@ -/* - * sisusb - usb kernel driver for Net2280/SiS315 based USB2VGA dongles - * - * Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria - * - * If distributed as part of the Linux kernel, this code is licensed under the - * terms of the GPL v2. - * - * Otherwise, the following license terms apply: - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1) Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2) Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3) The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Author: Thomas Winischhofer - * - */ - -#ifndef _SISUSB_H_ -#define _SISUSB_H_ - -#ifdef CONFIG_COMPAT -#define SISUSB_NEW_CONFIG_COMPAT -#endif - -#include - -/* For older kernels, support for text consoles is by default - * off. To enable text console support, change the following: - */ -/* #define CONFIG_USB_SISUSBVGA_CON */ - -/* Version Information */ - -#define SISUSB_VERSION 0 -#define SISUSB_REVISION 0 -#define SISUSB_PATCHLEVEL 8 - -/* Include console and mode switching code? */ - -#ifdef CONFIG_USB_SISUSBVGA_CON -#define INCL_SISUSB_CON 1 -#endif - -#include -#include -#include "sisusb_struct.h" - -/* USB related */ - -#define SISUSB_MINOR 133 /* official */ - -/* Size of the sisusb input/output buffers */ -#define SISUSB_IBUF_SIZE 0x01000 -#define SISUSB_OBUF_SIZE 0x10000 /* fixed */ - -#define NUMOBUFS 8 /* max number of output buffers/output URBs */ - -/* About endianness: - * - * 1) I/O ports, PCI config registers. The read/write() - * calls emulate inX/outX. Hence, the data is - * expected/delivered in machine endiannes by this - * driver. - * 2) Video memory. The data is copied 1:1. There is - * no swapping. Ever. This means for userland that - * the data has to be prepared properly. (Hint: - * think graphics data format, command queue, - * hardware cursor.) - * 3) MMIO. Data is copied 1:1. MMIO must be swapped - * properly by userland. - * - */ - -#ifdef __BIG_ENDIAN -#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) \ - do { \ - p->header = cpu_to_le16(p->header); \ - p->address = cpu_to_le32(p->address); \ - p->data = cpu_to_le32(p->data); \ - } while(0) -#else -#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) -#endif - -struct sisusb_usb_data; - -struct sisusb_urb_context { /* urb->context for outbound bulk URBs */ - struct sisusb_usb_data *sisusb; - int urbindex; - int *actual_length; -}; - -struct sisusb_usb_data { - struct usb_device *sisusb_dev; - struct usb_interface *interface; - struct kref kref; - wait_queue_head_t wait_q; /* for syncind and timeouts */ - struct mutex lock; /* general race avoidance */ - unsigned int ifnum; /* interface number of the USB device */ - int minor; /* minor (for logging clarity) */ - int isopen; /* !=0 if open */ - int present; /* !=0 if device is present on the bus */ - int ready; /* !=0 if device is ready for userland */ - int numobufs; /* number of obufs = number of out urbs */ - char *obuf[NUMOBUFS], *ibuf; /* transfer buffers */ - int obufsize, ibufsize; - struct urb *sisurbout[NUMOBUFS]; - struct urb *sisurbin; - unsigned char urbstatus[NUMOBUFS]; - unsigned char completein; - struct sisusb_urb_context urbout_context[NUMOBUFS]; - unsigned long flagb0; - unsigned long vrambase; /* framebuffer base */ - unsigned int vramsize; /* framebuffer size (bytes) */ - unsigned long mmiobase; - unsigned int mmiosize; - unsigned long ioportbase; - unsigned char devinit; /* device initialized? */ - unsigned char gfxinit; /* graphics core initialized? */ - unsigned short chipid, chipvendor; - unsigned short chiprevision; -#ifdef INCL_SISUSB_CON - struct SiS_Private *SiS_Pr; - unsigned long scrbuf; - unsigned int scrbuf_size; - int haveconsole, con_first, con_last; - int havethisconsole[MAX_NR_CONSOLES]; - int textmodedestroyed; - unsigned int sisusb_num_columns; /* real number, not vt's idea */ - int cur_start_addr, con_rolled_over; - int sisusb_cursor_loc, bad_cursor_pos; - int sisusb_cursor_size_from; - int sisusb_cursor_size_to; - int current_font_height, current_font_512; - int font_backup_size, font_backup_height, font_backup_512; - char *font_backup; - int font_slot; - struct vc_data *sisusb_display_fg; - int is_gfx; - int con_blanked; -#endif -}; - -#define to_sisusb_dev(d) container_of(d, struct sisusb_usb_data, kref) - -/* USB transport related */ - -/* urbstatus */ -#define SU_URB_BUSY 1 -#define SU_URB_ALLOC 2 - -/* Endpoints */ - -#define SISUSB_EP_GFX_IN 0x0e /* gfx std packet out(0e)/in(8e) */ -#define SISUSB_EP_GFX_OUT 0x0e - -#define SISUSB_EP_GFX_BULK_OUT 0x01 /* gfx mem bulk out/in */ -#define SISUSB_EP_GFX_BULK_IN 0x02 /* ? 2 is "OUT" ? */ - -#define SISUSB_EP_GFX_LBULK_OUT 0x03 /* gfx large mem bulk out */ - -#define SISUSB_EP_UNKNOWN_04 0x04 /* ? 4 is "OUT" ? - unused */ - -#define SISUSB_EP_BRIDGE_IN 0x0d /* Net2280 out(0d)/in(8d) */ -#define SISUSB_EP_BRIDGE_OUT 0x0d - -#define SISUSB_TYPE_MEM 0 -#define SISUSB_TYPE_IO 1 - -struct sisusb_packet { - unsigned short header; - u32 address; - u32 data; -} __attribute__ ((__packed__)); - -#define CLEARPACKET(packet) memset(packet, 0, 10) - -/* PCI bridge related */ - -#define SISUSB_PCI_MEMBASE 0xd0000000 -#define SISUSB_PCI_MMIOBASE 0xe4000000 -#define SISUSB_PCI_IOPORTBASE 0x0000d000 - -#define SISUSB_PCI_PSEUDO_MEMBASE 0x10000000 -#define SISUSB_PCI_PSEUDO_MMIOBASE 0x20000000 -#define SISUSB_PCI_PSEUDO_IOPORTBASE 0x0000d000 -#define SISUSB_PCI_PSEUDO_PCIBASE 0x00010000 - -#define SISUSB_PCI_MMIOSIZE (128*1024) -#define SISUSB_PCI_PCONFSIZE 0x5c - -/* graphics core related */ - -#define AROFFSET 0x40 -#define ARROFFSET 0x41 -#define GROFFSET 0x4e -#define SROFFSET 0x44 -#define CROFFSET 0x54 -#define MISCROFFSET 0x4c -#define MISCWOFFSET 0x42 -#define INPUTSTATOFFSET 0x5A -#define PART1OFFSET 0x04 -#define PART2OFFSET 0x10 -#define PART3OFFSET 0x12 -#define PART4OFFSET 0x14 -#define PART5OFFSET 0x16 -#define CAPTUREOFFSET 0x00 -#define VIDEOOFFSET 0x02 -#define COLREGOFFSET 0x48 -#define PELMASKOFFSET 0x46 -#define VGAENABLE 0x43 - -#define SISAR SISUSB_PCI_IOPORTBASE + AROFFSET -#define SISARR SISUSB_PCI_IOPORTBASE + ARROFFSET -#define SISGR SISUSB_PCI_IOPORTBASE + GROFFSET -#define SISSR SISUSB_PCI_IOPORTBASE + SROFFSET -#define SISCR SISUSB_PCI_IOPORTBASE + CROFFSET -#define SISMISCR SISUSB_PCI_IOPORTBASE + MISCROFFSET -#define SISMISCW SISUSB_PCI_IOPORTBASE + MISCWOFFSET -#define SISINPSTAT SISUSB_PCI_IOPORTBASE + INPUTSTATOFFSET -#define SISPART1 SISUSB_PCI_IOPORTBASE + PART1OFFSET -#define SISPART2 SISUSB_PCI_IOPORTBASE + PART2OFFSET -#define SISPART3 SISUSB_PCI_IOPORTBASE + PART3OFFSET -#define SISPART4 SISUSB_PCI_IOPORTBASE + PART4OFFSET -#define SISPART5 SISUSB_PCI_IOPORTBASE + PART5OFFSET -#define SISCAP SISUSB_PCI_IOPORTBASE + CAPTUREOFFSET -#define SISVID SISUSB_PCI_IOPORTBASE + VIDEOOFFSET -#define SISCOLIDXR SISUSB_PCI_IOPORTBASE + COLREGOFFSET - 1 -#define SISCOLIDX SISUSB_PCI_IOPORTBASE + COLREGOFFSET -#define SISCOLDATA SISUSB_PCI_IOPORTBASE + COLREGOFFSET + 1 -#define SISCOL2IDX SISPART5 -#define SISCOL2DATA SISPART5 + 1 -#define SISPEL SISUSB_PCI_IOPORTBASE + PELMASKOFFSET -#define SISVGAEN SISUSB_PCI_IOPORTBASE + VGAENABLE -#define SISDACA SISCOLIDX -#define SISDACD SISCOLDATA - -/* ioctl related */ - -/* Structure argument for SISUSB_GET_INFO ioctl */ -struct sisusb_info { - __u32 sisusb_id; /* for identifying sisusb */ -#define SISUSB_ID 0x53495355 /* Identify myself with 'SISU' */ - __u8 sisusb_version; - __u8 sisusb_revision; - __u8 sisusb_patchlevel; - __u8 sisusb_gfxinit; /* graphics core initialized? */ - - __u32 sisusb_vrambase; - __u32 sisusb_mmiobase; - __u32 sisusb_iobase; - __u32 sisusb_pcibase; - - __u32 sisusb_vramsize; /* framebuffer size in bytes */ - - __u32 sisusb_minor; - - __u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */ - - __u32 sisusb_conactive; /* != 0 if console driver active */ - - __u8 sisusb_reserved[28]; /* for future use */ -}; - -struct sisusb_command { - __u8 operation; /* see below */ - __u8 data0; /* operation dependent */ - __u8 data1; /* operation dependent */ - __u8 data2; /* operation dependent */ - __u32 data3; /* operation dependent */ - __u32 data4; /* for future use */ -}; - -#define SUCMD_GET 0x01 /* for all: data0 = index, data3 = port */ -#define SUCMD_SET 0x02 /* data1 = value */ -#define SUCMD_SETOR 0x03 /* data1 = or */ -#define SUCMD_SETAND 0x04 /* data1 = and */ -#define SUCMD_SETANDOR 0x05 /* data1 = and, data2 = or */ -#define SUCMD_SETMASK 0x06 /* data1 = data, data2 = mask */ - -#define SUCMD_CLRSCR 0x07 /* data0:1:2 = length, data3 = address */ - -#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */ - -#define SUCMD_SETMODE 0x09 /* Set a display mode (data3 = SiS mode) */ -#define SUCMD_SETVESAMODE 0x0a /* Set a display mode (data3 = VESA mode) */ - -#define SISUSB_COMMAND _IOWR(0xF3,0x3D,struct sisusb_command) -#define SISUSB_GET_CONFIG_SIZE _IOR(0xF3,0x3E,__u32) -#define SISUSB_GET_CONFIG _IOR(0xF3,0x3F,struct sisusb_info) - -#endif /* SISUSB_H */ diff --git a/ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb_con.c b/ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb_con.c deleted file mode 100644 index 411e605f..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb_con.c +++ /dev/null @@ -1,1564 +0,0 @@ -/* - * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles - * - * VGA text mode console part - * - * Copyright (C) 2005 by Thomas Winischhofer, Vienna, Austria - * - * If distributed as part of the Linux kernel, this code is licensed under the - * terms of the GPL v2. - * - * Otherwise, the following license terms apply: - * - * * Redistribution and use in source and binary forms, with or without - * * modification, are permitted provided that the following conditions - * * are met: - * * 1) Redistributions of source code must retain the above copyright - * * notice, this list of conditions and the following disclaimer. - * * 2) Redistributions in binary form must reproduce the above copyright - * * notice, this list of conditions and the following disclaimer in the - * * documentation and/or other materials provided with the distribution. - * * 3) The name of the author may not be used to endorse or promote products - * * derived from this software without specific psisusbr written permission. - * * - * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR - * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Author: Thomas Winischhofer - * - * Portions based on vgacon.c which are - * Created 28 Sep 1997 by Geert Uytterhoeven - * Rewritten by Martin Mares , July 1998 - * based on code Copyright (C) 1991, 1992 Linus Torvalds - * 1995 Jay Estabrook - * - * A note on using in_atomic() in here: We can't handle console - * calls from non-schedulable context due to our USB-dependend - * nature. For now, this driver just ignores any calls if it - * detects this state. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sisusb.h" -#include "sisusb_init.h" - -#ifdef INCL_SISUSB_CON - -#define sisusbcon_writew(val, addr) (*(addr) = (val)) -#define sisusbcon_readw(addr) (*(addr)) -#define sisusbcon_memmovew(d, s, c) memmove(d, s, c) -#define sisusbcon_memcpyw(d, s, c) memcpy(d, s, c) - -/* vc_data -> sisusb conversion table */ -static struct sisusb_usb_data *mysisusbs[MAX_NR_CONSOLES]; - -/* Forward declaration */ -static const struct consw sisusb_con; - -static inline void -sisusbcon_memsetw(u16 *s, u16 c, unsigned int count) -{ - count /= 2; - while (count--) - sisusbcon_writew(c, s++); -} - -static inline void -sisusb_initialize(struct sisusb_usb_data *sisusb) -{ - /* Reset cursor and start address */ - if (sisusb_setidxreg(sisusb, SISCR, 0x0c, 0x00)) - return; - if (sisusb_setidxreg(sisusb, SISCR, 0x0d, 0x00)) - return; - if (sisusb_setidxreg(sisusb, SISCR, 0x0e, 0x00)) - return; - sisusb_setidxreg(sisusb, SISCR, 0x0f, 0x00); -} - -static inline void -sisusbcon_set_start_address(struct sisusb_usb_data *sisusb, struct vc_data *c) -{ - sisusb->cur_start_addr = (c->vc_visible_origin - sisusb->scrbuf) / 2; - - sisusb_setidxreg(sisusb, SISCR, 0x0c, (sisusb->cur_start_addr >> 8)); - sisusb_setidxreg(sisusb, SISCR, 0x0d, (sisusb->cur_start_addr & 0xff)); -} - -void -sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location) -{ - if (sisusb->sisusb_cursor_loc == location) - return; - - sisusb->sisusb_cursor_loc = location; - - /* Hardware bug: Text cursor appears twice or not at all - * at some positions. Work around it with the cursor skew - * bits. - */ - - if ((location & 0x0007) == 0x0007) { - sisusb->bad_cursor_pos = 1; - location--; - if (sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0x1f, 0x20)) - return; - } else if (sisusb->bad_cursor_pos) { - if (sisusb_setidxregand(sisusb, SISCR, 0x0b, 0x1f)) - return; - sisusb->bad_cursor_pos = 0; - } - - if (sisusb_setidxreg(sisusb, SISCR, 0x0e, (location >> 8))) - return; - sisusb_setidxreg(sisusb, SISCR, 0x0f, (location & 0xff)); -} - -static inline struct sisusb_usb_data * -sisusb_get_sisusb(unsigned short console) -{ - return mysisusbs[console]; -} - -static inline int -sisusb_sisusb_valid(struct sisusb_usb_data *sisusb) -{ - if (!sisusb->present || !sisusb->ready || !sisusb->sisusb_dev) - return 0; - - return 1; -} - -static struct sisusb_usb_data * -sisusb_get_sisusb_lock_and_check(unsigned short console) -{ - struct sisusb_usb_data *sisusb; - - /* We can't handle console calls in non-schedulable - * context due to our locks and the USB transport. - * So we simply ignore them. This should only affect - * some calls to printk. - */ - if (in_atomic()) - return NULL; - - if (!(sisusb = sisusb_get_sisusb(console))) - return NULL; - - mutex_lock(&sisusb->lock); - - if (!sisusb_sisusb_valid(sisusb) || - !sisusb->havethisconsole[console]) { - mutex_unlock(&sisusb->lock); - return NULL; - } - - return sisusb; -} - -static int -sisusb_is_inactive(struct vc_data *c, struct sisusb_usb_data *sisusb) -{ - if (sisusb->is_gfx || - sisusb->textmodedestroyed || - c->vc_mode != KD_TEXT) - return 1; - - return 0; -} - -/* con_startup console interface routine */ -static const char * -sisusbcon_startup(void) -{ - return "SISUSBCON"; -} - -/* con_init console interface routine */ -static void -sisusbcon_init(struct vc_data *c, int init) -{ - struct sisusb_usb_data *sisusb; - int cols, rows; - - /* This is called by take_over_console(), - * ie by us/under our control. It is - * only called after text mode and fonts - * are set up/restored. - */ - - if (!(sisusb = sisusb_get_sisusb(c->vc_num))) - return; - - mutex_lock(&sisusb->lock); - - if (!sisusb_sisusb_valid(sisusb)) { - mutex_unlock(&sisusb->lock); - return; - } - - c->vc_can_do_color = 1; - - c->vc_complement_mask = 0x7700; - - c->vc_hi_font_mask = sisusb->current_font_512 ? 0x0800 : 0; - - sisusb->haveconsole = 1; - - sisusb->havethisconsole[c->vc_num] = 1; - - /* We only support 640x400 */ - c->vc_scan_lines = 400; - - c->vc_font.height = sisusb->current_font_height; - - /* We only support width = 8 */ - cols = 80; - rows = c->vc_scan_lines / c->vc_font.height; - - /* Increment usage count for our sisusb. - * Doing so saves us from upping/downing - * the disconnect semaphore; we can't - * lose our sisusb until this is undone - * in con_deinit. For all other console - * interface functions, it suffices to - * use sisusb->lock and do a quick check - * of sisusb for device disconnection. - */ - kref_get(&sisusb->kref); - - if (!*c->vc_uni_pagedir_loc) - con_set_default_unimap(c); - - mutex_unlock(&sisusb->lock); - - if (init) { - c->vc_cols = cols; - c->vc_rows = rows; - } else - vc_resize(c, cols, rows); -} - -/* con_deinit console interface routine */ -static void -sisusbcon_deinit(struct vc_data *c) -{ - struct sisusb_usb_data *sisusb; - int i; - - /* This is called by take_over_console() - * and others, ie not under our control. - */ - - if (!(sisusb = sisusb_get_sisusb(c->vc_num))) - return; - - mutex_lock(&sisusb->lock); - - /* Clear ourselves in mysisusbs */ - mysisusbs[c->vc_num] = NULL; - - sisusb->havethisconsole[c->vc_num] = 0; - - /* Free our font buffer if all consoles are gone */ - if (sisusb->font_backup) { - for(i = 0; i < MAX_NR_CONSOLES; i++) { - if (sisusb->havethisconsole[c->vc_num]) - break; - } - if (i == MAX_NR_CONSOLES) { - vfree(sisusb->font_backup); - sisusb->font_backup = NULL; - } - } - - mutex_unlock(&sisusb->lock); - - /* decrement the usage count on our sisusb */ - kref_put(&sisusb->kref, sisusb_delete); -} - -/* interface routine */ -static u8 -sisusbcon_build_attr(struct vc_data *c, u8 color, u8 intensity, - u8 blink, u8 underline, u8 reverse, u8 unused) -{ - u8 attr = color; - - if (underline) - attr = (attr & 0xf0) | c->vc_ulcolor; - else if (intensity == 0) - attr = (attr & 0xf0) | c->vc_halfcolor; - - if (reverse) - attr = ((attr) & 0x88) | - ((((attr) >> 4) | - ((attr) << 4)) & 0x77); - - if (blink) - attr ^= 0x80; - - if (intensity == 2) - attr ^= 0x08; - - return attr; -} - -/* Interface routine */ -static void -sisusbcon_invert_region(struct vc_data *vc, u16 *p, int count) -{ - /* Invert a region. This is called with a pointer - * to the console's internal screen buffer. So we - * simply do the inversion there and rely on - * a call to putc(s) to update the real screen. - */ - - while (count--) { - u16 a = sisusbcon_readw(p); - - a = ((a) & 0x88ff) | - (((a) & 0x7000) >> 4) | - (((a) & 0x0700) << 4); - - sisusbcon_writew(a, p++); - } -} - -#define SISUSB_VADDR(x,y) \ - ((u16 *)c->vc_origin + \ - (y) * sisusb->sisusb_num_columns + \ - (x)) - -#define SISUSB_HADDR(x,y) \ - ((u16 *)(sisusb->vrambase + (c->vc_origin - sisusb->scrbuf)) + \ - (y) * sisusb->sisusb_num_columns + \ - (x)) - -/* Interface routine */ -static void -sisusbcon_putc(struct vc_data *c, int ch, int y, int x) -{ - struct sisusb_usb_data *sisusb; - ssize_t written; - - if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) - return; - - /* sisusb->lock is down */ - if (sisusb_is_inactive(c, sisusb)) { - mutex_unlock(&sisusb->lock); - return; - } - - - sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y), - (long)SISUSB_HADDR(x, y), 2, &written); - - mutex_unlock(&sisusb->lock); -} - -/* Interface routine */ -static void -sisusbcon_putcs(struct vc_data *c, const unsigned short *s, - int count, int y, int x) -{ - struct sisusb_usb_data *sisusb; - ssize_t written; - u16 *dest; - int i; - - if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) - return; - - /* sisusb->lock is down */ - - /* Need to put the characters into the buffer ourselves, - * because the vt does this AFTER calling us. - */ - - dest = SISUSB_VADDR(x, y); - - for (i = count; i > 0; i--) - sisusbcon_writew(sisusbcon_readw(s++), dest++); - - if (sisusb_is_inactive(c, sisusb)) { - mutex_unlock(&sisusb->lock); - return; - } - - sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(x, y), - (long)SISUSB_HADDR(x, y), count * 2, &written); - - mutex_unlock(&sisusb->lock); -} - -/* Interface routine */ -static void -sisusbcon_clear(struct vc_data *c, int y, int x, int height, int width) -{ - struct sisusb_usb_data *sisusb; - u16 eattr = c->vc_video_erase_char; - ssize_t written; - int i, length, cols; - u16 *dest; - - if (width <= 0 || height <= 0) - return; - - if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) - return; - - /* sisusb->lock is down */ - - /* Need to clear buffer ourselves, because the vt does - * this AFTER calling us. - */ - - dest = SISUSB_VADDR(x, y); - - cols = sisusb->sisusb_num_columns; - - if (width > cols) - width = cols; - - if (x == 0 && width >= c->vc_cols) { - - sisusbcon_memsetw(dest, eattr, height * cols * 2); - - } else { - - for (i = height; i > 0; i--, dest += cols) - sisusbcon_memsetw(dest, eattr, width * 2); - - } - - if (sisusb_is_inactive(c, sisusb)) { - mutex_unlock(&sisusb->lock); - return; - } - - length = ((height * cols) - x - (cols - width - x)) * 2; - - - sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(x, y), - (long)SISUSB_HADDR(x, y), length, &written); - - mutex_unlock(&sisusb->lock); -} - -/* Interface routine */ -static void -sisusbcon_bmove(struct vc_data *c, int sy, int sx, - int dy, int dx, int height, int width) -{ - struct sisusb_usb_data *sisusb; - ssize_t written; - int cols, length; - - if (width <= 0 || height <= 0) - return; - - if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) - return; - - /* sisusb->lock is down */ - - cols = sisusb->sisusb_num_columns; - - if (sisusb_is_inactive(c, sisusb)) { - mutex_unlock(&sisusb->lock); - return; - } - - length = ((height * cols) - dx - (cols - width - dx)) * 2; - - - sisusb_copy_memory(sisusb, (unsigned char *)SISUSB_VADDR(dx, dy), - (long)SISUSB_HADDR(dx, dy), length, &written); - - mutex_unlock(&sisusb->lock); -} - -/* interface routine */ -static int -sisusbcon_switch(struct vc_data *c) -{ - struct sisusb_usb_data *sisusb; - ssize_t written; - int length; - - /* Returnvalue 0 means we have fully restored screen, - * and vt doesn't need to call do_update_region(). - * Returnvalue != 0 naturally means the opposite. - */ - - if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) - return 0; - - /* sisusb->lock is down */ - - /* Don't write to screen if in gfx mode */ - if (sisusb_is_inactive(c, sisusb)) { - mutex_unlock(&sisusb->lock); - return 0; - } - - /* That really should not happen. It would mean we are - * being called while the vc is using its private buffer - * as origin. - */ - if (c->vc_origin == (unsigned long)c->vc_screenbuf) { - mutex_unlock(&sisusb->lock); - dev_dbg(&sisusb->sisusb_dev->dev, "ASSERT ORIGIN != SCREENBUF!\n"); - return 0; - } - - /* Check that we don't copy too much */ - length = min((int)c->vc_screenbuf_size, - (int)(sisusb->scrbuf + sisusb->scrbuf_size - c->vc_origin)); - - /* Restore the screen contents */ - sisusbcon_memcpyw((u16 *)c->vc_origin, (u16 *)c->vc_screenbuf, - length); - - sisusb_copy_memory(sisusb, (unsigned char *)c->vc_origin, - (long)SISUSB_HADDR(0, 0), - length, &written); - - mutex_unlock(&sisusb->lock); - - return 0; -} - -/* interface routine */ -static void -sisusbcon_save_screen(struct vc_data *c) -{ - struct sisusb_usb_data *sisusb; - int length; - - /* Save the current screen contents to vc's private - * buffer. - */ - - if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) - return; - - /* sisusb->lock is down */ - - if (sisusb_is_inactive(c, sisusb)) { - mutex_unlock(&sisusb->lock); - return; - } - - /* Check that we don't copy too much */ - length = min((int)c->vc_screenbuf_size, - (int)(sisusb->scrbuf + sisusb->scrbuf_size - c->vc_origin)); - - /* Save the screen contents to vc's private buffer */ - sisusbcon_memcpyw((u16 *)c->vc_screenbuf, (u16 *)c->vc_origin, - length); - - mutex_unlock(&sisusb->lock); -} - -/* interface routine */ -static int -sisusbcon_set_palette(struct vc_data *c, unsigned char *table) -{ - struct sisusb_usb_data *sisusb; - int i, j; - - /* Return value not used by vt */ - - if (!CON_IS_VISIBLE(c)) - return -EINVAL; - - if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) - return -EINVAL; - - /* sisusb->lock is down */ - - if (sisusb_is_inactive(c, sisusb)) { - mutex_unlock(&sisusb->lock); - return -EINVAL; - } - - for (i = j = 0; i < 16; i++) { - if (sisusb_setreg(sisusb, SISCOLIDX, table[i])) - break; - if (sisusb_setreg(sisusb, SISCOLDATA, c->vc_palette[j++] >> 2)) - break; - if (sisusb_setreg(sisusb, SISCOLDATA, c->vc_palette[j++] >> 2)) - break; - if (sisusb_setreg(sisusb, SISCOLDATA, c->vc_palette[j++] >> 2)) - break; - } - - mutex_unlock(&sisusb->lock); - - return 0; -} - -/* interface routine */ -static int -sisusbcon_blank(struct vc_data *c, int blank, int mode_switch) -{ - struct sisusb_usb_data *sisusb; - u8 sr1, cr17, pmreg, cr63; - ssize_t written; - int ret = 0; - - if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) - return 0; - - /* sisusb->lock is down */ - - if (mode_switch) - sisusb->is_gfx = blank ? 1 : 0; - - if (sisusb_is_inactive(c, sisusb)) { - mutex_unlock(&sisusb->lock); - return 0; - } - - switch (blank) { - - case 1: /* Normal blanking: Clear screen */ - case -1: - sisusbcon_memsetw((u16 *)c->vc_origin, - c->vc_video_erase_char, - c->vc_screenbuf_size); - sisusb_copy_memory(sisusb, - (unsigned char *)c->vc_origin, - (u32)(sisusb->vrambase + - (c->vc_origin - sisusb->scrbuf)), - c->vc_screenbuf_size, &written); - sisusb->con_blanked = 1; - ret = 1; - break; - - default: /* VESA blanking */ - switch (blank) { - case 0: /* Unblank */ - sr1 = 0x00; - cr17 = 0x80; - pmreg = 0x00; - cr63 = 0x00; - ret = 1; - sisusb->con_blanked = 0; - break; - case VESA_VSYNC_SUSPEND + 1: - sr1 = 0x20; - cr17 = 0x80; - pmreg = 0x80; - cr63 = 0x40; - break; - case VESA_HSYNC_SUSPEND + 1: - sr1 = 0x20; - cr17 = 0x80; - pmreg = 0x40; - cr63 = 0x40; - break; - case VESA_POWERDOWN + 1: - sr1 = 0x20; - cr17 = 0x00; - pmreg = 0xc0; - cr63 = 0x40; - break; - default: - mutex_unlock(&sisusb->lock); - return -EINVAL; - } - - sisusb_setidxregandor(sisusb, SISSR, 0x01, ~0x20, sr1); - sisusb_setidxregandor(sisusb, SISCR, 0x17, 0x7f, cr17); - sisusb_setidxregandor(sisusb, SISSR, 0x1f, 0x3f, pmreg); - sisusb_setidxregandor(sisusb, SISCR, 0x63, 0xbf, cr63); - - } - - mutex_unlock(&sisusb->lock); - - return ret; -} - -/* interface routine */ -static int -sisusbcon_scrolldelta(struct vc_data *c, int lines) -{ - struct sisusb_usb_data *sisusb; - int margin = c->vc_size_row * 4; - int ul, we, p, st; - - /* The return value does not seem to be used */ - - if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) - return 0; - - /* sisusb->lock is down */ - - if (sisusb_is_inactive(c, sisusb)) { - mutex_unlock(&sisusb->lock); - return 0; - } - - if (!lines) /* Turn scrollback off */ - c->vc_visible_origin = c->vc_origin; - else { - - if (sisusb->con_rolled_over > - (c->vc_scr_end - sisusb->scrbuf) + margin) { - - ul = c->vc_scr_end - sisusb->scrbuf; - we = sisusb->con_rolled_over + c->vc_size_row; - - } else { - - ul = 0; - we = sisusb->scrbuf_size; - - } - - p = (c->vc_visible_origin - sisusb->scrbuf - ul + we) % we + - lines * c->vc_size_row; - - st = (c->vc_origin - sisusb->scrbuf - ul + we) % we; - - if (st < 2 * margin) - margin = 0; - - if (p < margin) - p = 0; - - if (p > st - margin) - p = st; - - c->vc_visible_origin = sisusb->scrbuf + (p + ul) % we; - } - - sisusbcon_set_start_address(sisusb, c); - - mutex_unlock(&sisusb->lock); - - return 1; -} - -/* Interface routine */ -static void -sisusbcon_cursor(struct vc_data *c, int mode) -{ - struct sisusb_usb_data *sisusb; - int from, to, baseline; - - if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) - return; - - /* sisusb->lock is down */ - - if (sisusb_is_inactive(c, sisusb)) { - mutex_unlock(&sisusb->lock); - return; - } - - if (c->vc_origin != c->vc_visible_origin) { - c->vc_visible_origin = c->vc_origin; - sisusbcon_set_start_address(sisusb, c); - } - - if (mode == CM_ERASE) { - sisusb_setidxregor(sisusb, SISCR, 0x0a, 0x20); - sisusb->sisusb_cursor_size_to = -1; - mutex_unlock(&sisusb->lock); - return; - } - - sisusb_set_cursor(sisusb, (c->vc_pos - sisusb->scrbuf) / 2); - - baseline = c->vc_font.height - (c->vc_font.height < 10 ? 1 : 2); - - switch (c->vc_cursor_type & 0x0f) { - case CUR_BLOCK: from = 1; - to = c->vc_font.height; - break; - case CUR_TWO_THIRDS: from = c->vc_font.height / 3; - to = baseline; - break; - case CUR_LOWER_HALF: from = c->vc_font.height / 2; - to = baseline; - break; - case CUR_LOWER_THIRD: from = (c->vc_font.height * 2) / 3; - to = baseline; - break; - case CUR_NONE: from = 31; - to = 30; - break; - default: - case CUR_UNDERLINE: from = baseline - 1; - to = baseline; - break; - } - - if (sisusb->sisusb_cursor_size_from != from || - sisusb->sisusb_cursor_size_to != to) { - - sisusb_setidxreg(sisusb, SISCR, 0x0a, from); - sisusb_setidxregandor(sisusb, SISCR, 0x0b, 0xe0, to); - - sisusb->sisusb_cursor_size_from = from; - sisusb->sisusb_cursor_size_to = to; - } - - mutex_unlock(&sisusb->lock); -} - -static int -sisusbcon_scroll_area(struct vc_data *c, struct sisusb_usb_data *sisusb, - int t, int b, int dir, int lines) -{ - int cols = sisusb->sisusb_num_columns; - int length = ((b - t) * cols) * 2; - u16 eattr = c->vc_video_erase_char; - ssize_t written; - - /* sisusb->lock is down */ - - /* Scroll an area which does not match the - * visible screen's dimensions. This needs - * to be done separately, as it does not - * use hardware panning. - */ - - switch (dir) { - - case SM_UP: - sisusbcon_memmovew(SISUSB_VADDR(0, t), - SISUSB_VADDR(0, t + lines), - (b - t - lines) * cols * 2); - sisusbcon_memsetw(SISUSB_VADDR(0, b - lines), eattr, - lines * cols * 2); - break; - - case SM_DOWN: - sisusbcon_memmovew(SISUSB_VADDR(0, t + lines), - SISUSB_VADDR(0, t), - (b - t - lines) * cols * 2); - sisusbcon_memsetw(SISUSB_VADDR(0, t), eattr, - lines * cols * 2); - break; - } - - sisusb_copy_memory(sisusb, (char *)SISUSB_VADDR(0, t), - (long)SISUSB_HADDR(0, t), length, &written); - - mutex_unlock(&sisusb->lock); - - return 1; -} - -/* Interface routine */ -static int -sisusbcon_scroll(struct vc_data *c, int t, int b, int dir, int lines) -{ - struct sisusb_usb_data *sisusb; - u16 eattr = c->vc_video_erase_char; - ssize_t written; - int copyall = 0; - unsigned long oldorigin; - unsigned int delta = lines * c->vc_size_row; - u32 originoffset; - - /* Returning != 0 means we have done the scrolling successfully. - * Returning 0 makes vt do the scrolling on its own. - * Note that con_scroll is only called if the console is - * visible. In that case, the origin should be our buffer, - * not the vt's private one. - */ - - if (!lines) - return 1; - - if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) - return 0; - - /* sisusb->lock is down */ - - if (sisusb_is_inactive(c, sisusb)) { - mutex_unlock(&sisusb->lock); - return 0; - } - - /* Special case */ - if (t || b != c->vc_rows) - return sisusbcon_scroll_area(c, sisusb, t, b, dir, lines); - - if (c->vc_origin != c->vc_visible_origin) { - c->vc_visible_origin = c->vc_origin; - sisusbcon_set_start_address(sisusb, c); - } - - /* limit amount to maximum realistic size */ - if (lines > c->vc_rows) - lines = c->vc_rows; - - oldorigin = c->vc_origin; - - switch (dir) { - - case SM_UP: - - if (c->vc_scr_end + delta >= - sisusb->scrbuf + sisusb->scrbuf_size) { - sisusbcon_memcpyw((u16 *)sisusb->scrbuf, - (u16 *)(oldorigin + delta), - c->vc_screenbuf_size - delta); - c->vc_origin = sisusb->scrbuf; - sisusb->con_rolled_over = oldorigin - sisusb->scrbuf; - copyall = 1; - } else - c->vc_origin += delta; - - sisusbcon_memsetw( - (u16 *)(c->vc_origin + c->vc_screenbuf_size - delta), - eattr, delta); - - break; - - case SM_DOWN: - - if (oldorigin - delta < sisusb->scrbuf) { - sisusbcon_memmovew((u16 *)(sisusb->scrbuf + - sisusb->scrbuf_size - - c->vc_screenbuf_size + - delta), - (u16 *)oldorigin, - c->vc_screenbuf_size - delta); - c->vc_origin = sisusb->scrbuf + - sisusb->scrbuf_size - - c->vc_screenbuf_size; - sisusb->con_rolled_over = 0; - copyall = 1; - } else - c->vc_origin -= delta; - - c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; - - scr_memsetw((u16 *)(c->vc_origin), eattr, delta); - - break; - } - - originoffset = (u32)(c->vc_origin - sisusb->scrbuf); - - if (copyall) - sisusb_copy_memory(sisusb, - (char *)c->vc_origin, - (u32)(sisusb->vrambase + originoffset), - c->vc_screenbuf_size, &written); - else if (dir == SM_UP) - sisusb_copy_memory(sisusb, - (char *)c->vc_origin + c->vc_screenbuf_size - delta, - (u32)sisusb->vrambase + originoffset + - c->vc_screenbuf_size - delta, - delta, &written); - else - sisusb_copy_memory(sisusb, - (char *)c->vc_origin, - (u32)(sisusb->vrambase + originoffset), - delta, &written); - - c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; - c->vc_visible_origin = c->vc_origin; - - sisusbcon_set_start_address(sisusb, c); - - c->vc_pos = c->vc_pos - oldorigin + c->vc_origin; - - mutex_unlock(&sisusb->lock); - - return 1; -} - -/* Interface routine */ -static int -sisusbcon_set_origin(struct vc_data *c) -{ - struct sisusb_usb_data *sisusb; - - /* Returning != 0 means we were successful. - * Returning 0 will vt make to use its own - * screenbuffer as the origin. - */ - - if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) - return 0; - - /* sisusb->lock is down */ - - if (sisusb_is_inactive(c, sisusb) || sisusb->con_blanked) { - mutex_unlock(&sisusb->lock); - return 0; - } - - c->vc_origin = c->vc_visible_origin = sisusb->scrbuf; - - sisusbcon_set_start_address(sisusb, c); - - sisusb->con_rolled_over = 0; - - mutex_unlock(&sisusb->lock); - - return 1; -} - -/* Interface routine */ -static int -sisusbcon_resize(struct vc_data *c, unsigned int newcols, unsigned int newrows, - unsigned int user) -{ - struct sisusb_usb_data *sisusb; - int fh; - - if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) - return -ENODEV; - - fh = sisusb->current_font_height; - - mutex_unlock(&sisusb->lock); - - /* We are quite unflexible as regards resizing. The vt code - * handles sizes where the line length isn't equal the pitch - * quite badly. As regards the rows, our panning tricks only - * work well if the number of rows equals the visible number - * of rows. - */ - - if (newcols != 80 || c->vc_scan_lines / fh != newrows) - return -EINVAL; - - return 0; -} - -int -sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot, - u8 *arg, int cmapsz, int ch512, int dorecalc, - struct vc_data *c, int fh, int uplock) -{ - int font_select = 0x00, i, err = 0; - u32 offset = 0; - u8 dummy; - - /* sisusb->lock is down */ - - /* - * The default font is kept in slot 0. - * A user font is loaded in slot 2 (256 ch) - * or 2+3 (512 ch). - */ - - if ((slot != 0 && slot != 2) || !fh) { - if (uplock) - mutex_unlock(&sisusb->lock); - return -EINVAL; - } - - if (set) - sisusb->font_slot = slot; - - /* Default font is always 256 */ - if (slot == 0) - ch512 = 0; - else - offset = 4 * cmapsz; - - font_select = (slot == 0) ? 0x00 : (ch512 ? 0x0e : 0x0a); - - err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x01); /* Reset */ - err |= sisusb_setidxreg(sisusb, SISSR, 0x02, 0x04); /* Write to plane 2 */ - err |= sisusb_setidxreg(sisusb, SISSR, 0x04, 0x07); /* Memory mode a0-bf */ - err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x03); /* Reset */ - - if (err) - goto font_op_error; - - err |= sisusb_setidxreg(sisusb, SISGR, 0x04, 0x03); /* Select plane read 2 */ - err |= sisusb_setidxreg(sisusb, SISGR, 0x05, 0x00); /* Disable odd/even */ - err |= sisusb_setidxreg(sisusb, SISGR, 0x06, 0x00); /* Address range a0-bf */ - - if (err) - goto font_op_error; - - if (arg) { - if (set) - for (i = 0; i < cmapsz; i++) { - err |= sisusb_writeb(sisusb, - sisusb->vrambase + offset + i, - arg[i]); - if (err) - break; - } - else - for (i = 0; i < cmapsz; i++) { - err |= sisusb_readb(sisusb, - sisusb->vrambase + offset + i, - &arg[i]); - if (err) - break; - } - - /* - * In 512-character mode, the character map is not contiguous if - * we want to remain EGA compatible -- which we do - */ - - if (ch512) { - if (set) - for (i = 0; i < cmapsz; i++) { - err |= sisusb_writeb(sisusb, - sisusb->vrambase + offset + - (2 * cmapsz) + i, - arg[cmapsz + i]); - if (err) - break; - } - else - for (i = 0; i < cmapsz; i++) { - err |= sisusb_readb(sisusb, - sisusb->vrambase + offset + - (2 * cmapsz) + i, - &arg[cmapsz + i]); - if (err) - break; - } - } - } - - if (err) - goto font_op_error; - - err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x01); /* Reset */ - err |= sisusb_setidxreg(sisusb, SISSR, 0x02, 0x03); /* Write to planes 0+1 */ - err |= sisusb_setidxreg(sisusb, SISSR, 0x04, 0x03); /* Memory mode a0-bf */ - if (set) - sisusb_setidxreg(sisusb, SISSR, 0x03, font_select); - err |= sisusb_setidxreg(sisusb, SISSR, 0x00, 0x03); /* Reset end */ - - if (err) - goto font_op_error; - - err |= sisusb_setidxreg(sisusb, SISGR, 0x04, 0x00); /* Select plane read 0 */ - err |= sisusb_setidxreg(sisusb, SISGR, 0x05, 0x10); /* Enable odd/even */ - err |= sisusb_setidxreg(sisusb, SISGR, 0x06, 0x06); /* Address range b8-bf */ - - if (err) - goto font_op_error; - - if ((set) && (ch512 != sisusb->current_font_512)) { - - /* Font is shared among all our consoles. - * And so is the hi_font_mask. - */ - for (i = 0; i < MAX_NR_CONSOLES; i++) { - struct vc_data *d = vc_cons[i].d; - if (d && d->vc_sw == &sisusb_con) - d->vc_hi_font_mask = ch512 ? 0x0800 : 0; - } - - sisusb->current_font_512 = ch512; - - /* color plane enable register: - 256-char: enable intensity bit - 512-char: disable intensity bit */ - sisusb_getreg(sisusb, SISINPSTAT, &dummy); - sisusb_setreg(sisusb, SISAR, 0x12); - sisusb_setreg(sisusb, SISAR, ch512 ? 0x07 : 0x0f); - - sisusb_getreg(sisusb, SISINPSTAT, &dummy); - sisusb_setreg(sisusb, SISAR, 0x20); - sisusb_getreg(sisusb, SISINPSTAT, &dummy); - } - - if (dorecalc) { - - /* - * Adjust the screen to fit a font of a certain height - */ - - unsigned char ovr, vde, fsr; - int rows = 0, maxscan = 0; - - if (c) { - - /* Number of video rows */ - rows = c->vc_scan_lines / fh; - /* Scan lines to actually display-1 */ - maxscan = rows * fh - 1; - - /*printk(KERN_DEBUG "sisusb recalc rows %d maxscan %d fh %d sl %d\n", - rows, maxscan, fh, c->vc_scan_lines);*/ - - sisusb_getidxreg(sisusb, SISCR, 0x07, &ovr); - vde = maxscan & 0xff; - ovr = (ovr & 0xbd) | - ((maxscan & 0x100) >> 7) | - ((maxscan & 0x200) >> 3); - sisusb_setidxreg(sisusb, SISCR, 0x07, ovr); - sisusb_setidxreg(sisusb, SISCR, 0x12, vde); - - } - - sisusb_getidxreg(sisusb, SISCR, 0x09, &fsr); - fsr = (fsr & 0xe0) | (fh - 1); - sisusb_setidxreg(sisusb, SISCR, 0x09, fsr); - sisusb->current_font_height = fh; - - sisusb->sisusb_cursor_size_from = -1; - sisusb->sisusb_cursor_size_to = -1; - - } - - if (uplock) - mutex_unlock(&sisusb->lock); - - if (dorecalc && c) { - int rows = c->vc_scan_lines / fh; - - /* Now adjust our consoles' size */ - - for (i = 0; i < MAX_NR_CONSOLES; i++) { - struct vc_data *vc = vc_cons[i].d; - - if (vc && vc->vc_sw == &sisusb_con) { - if (CON_IS_VISIBLE(vc)) { - vc->vc_sw->con_cursor(vc, CM_DRAW); - } - vc->vc_font.height = fh; - vc_resize(vc, 0, rows); - } - } - } - - return 0; - -font_op_error: - if (uplock) - mutex_unlock(&sisusb->lock); - - return -EIO; -} - -/* Interface routine */ -static int -sisusbcon_font_set(struct vc_data *c, struct console_font *font, - unsigned flags) -{ - struct sisusb_usb_data *sisusb; - unsigned charcount = font->charcount; - - if (font->width != 8 || (charcount != 256 && charcount != 512)) - return -EINVAL; - - if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) - return -ENODEV; - - /* sisusb->lock is down */ - - /* Save the user-provided font into a buffer. This - * is used for restoring text mode after quitting - * from X and for the con_getfont routine. - */ - if (sisusb->font_backup) { - if (sisusb->font_backup_size < charcount) { - vfree(sisusb->font_backup); - sisusb->font_backup = NULL; - } - } - - if (!sisusb->font_backup) - sisusb->font_backup = vmalloc(charcount * 32); - - if (sisusb->font_backup) { - memcpy(sisusb->font_backup, font->data, charcount * 32); - sisusb->font_backup_size = charcount; - sisusb->font_backup_height = font->height; - sisusb->font_backup_512 = (charcount == 512) ? 1 : 0; - } - - /* do_font_op ups sisusb->lock */ - - return sisusbcon_do_font_op(sisusb, 1, 2, font->data, - 8192, (charcount == 512), - (!(flags & KD_FONT_FLAG_DONT_RECALC)) ? 1 : 0, - c, font->height, 1); -} - -/* Interface routine */ -static int -sisusbcon_font_get(struct vc_data *c, struct console_font *font) -{ - struct sisusb_usb_data *sisusb; - - if (!(sisusb = sisusb_get_sisusb_lock_and_check(c->vc_num))) - return -ENODEV; - - /* sisusb->lock is down */ - - font->width = 8; - font->height = c->vc_font.height; - font->charcount = 256; - - if (!font->data) { - mutex_unlock(&sisusb->lock); - return 0; - } - - if (!sisusb->font_backup) { - mutex_unlock(&sisusb->lock); - return -ENODEV; - } - - /* Copy 256 chars only, like vgacon */ - memcpy(font->data, sisusb->font_backup, 256 * 32); - - mutex_unlock(&sisusb->lock); - - return 0; -} - -/* - * The console `switch' structure for the sisusb console - */ - -static const struct consw sisusb_con = { - .owner = THIS_MODULE, - .con_startup = sisusbcon_startup, - .con_init = sisusbcon_init, - .con_deinit = sisusbcon_deinit, - .con_clear = sisusbcon_clear, - .con_putc = sisusbcon_putc, - .con_putcs = sisusbcon_putcs, - .con_cursor = sisusbcon_cursor, - .con_scroll = sisusbcon_scroll, - .con_bmove = sisusbcon_bmove, - .con_switch = sisusbcon_switch, - .con_blank = sisusbcon_blank, - .con_font_set = sisusbcon_font_set, - .con_font_get = sisusbcon_font_get, - .con_set_palette = sisusbcon_set_palette, - .con_scrolldelta = sisusbcon_scrolldelta, - .con_build_attr = sisusbcon_build_attr, - .con_invert_region = sisusbcon_invert_region, - .con_set_origin = sisusbcon_set_origin, - .con_save_screen = sisusbcon_save_screen, - .con_resize = sisusbcon_resize, -}; - -/* Our very own dummy console driver */ - -static const char *sisusbdummycon_startup(void) -{ - return "SISUSBVGADUMMY"; -} - -static void sisusbdummycon_init(struct vc_data *vc, int init) -{ - vc->vc_can_do_color = 1; - if (init) { - vc->vc_cols = 80; - vc->vc_rows = 25; - } else - vc_resize(vc, 80, 25); -} - -static int sisusbdummycon_dummy(void) -{ - return 0; -} - -#define SISUSBCONDUMMY (void *)sisusbdummycon_dummy - -static const struct consw sisusb_dummy_con = { - .owner = THIS_MODULE, - .con_startup = sisusbdummycon_startup, - .con_init = sisusbdummycon_init, - .con_deinit = SISUSBCONDUMMY, - .con_clear = SISUSBCONDUMMY, - .con_putc = SISUSBCONDUMMY, - .con_putcs = SISUSBCONDUMMY, - .con_cursor = SISUSBCONDUMMY, - .con_scroll = SISUSBCONDUMMY, - .con_bmove = SISUSBCONDUMMY, - .con_switch = SISUSBCONDUMMY, - .con_blank = SISUSBCONDUMMY, - .con_font_set = SISUSBCONDUMMY, - .con_font_get = SISUSBCONDUMMY, - .con_font_default = SISUSBCONDUMMY, - .con_font_copy = SISUSBCONDUMMY, - .con_set_palette = SISUSBCONDUMMY, - .con_scrolldelta = SISUSBCONDUMMY, -}; - -int -sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last) -{ - int i, ret; - - mutex_lock(&sisusb->lock); - - /* Erm.. that should not happen */ - if (sisusb->haveconsole || !sisusb->SiS_Pr) { - mutex_unlock(&sisusb->lock); - return 1; - } - - sisusb->con_first = first; - sisusb->con_last = last; - - if (first > last || - first > MAX_NR_CONSOLES || - last > MAX_NR_CONSOLES) { - mutex_unlock(&sisusb->lock); - return 1; - } - - /* If gfxcore not initialized or no consoles given, quit graciously */ - if (!sisusb->gfxinit || first < 1 || last < 1) { - mutex_unlock(&sisusb->lock); - return 0; - } - - sisusb->sisusb_cursor_loc = -1; - sisusb->sisusb_cursor_size_from = -1; - sisusb->sisusb_cursor_size_to = -1; - - /* Set up text mode (and upload default font) */ - if (sisusb_reset_text_mode(sisusb, 1)) { - mutex_unlock(&sisusb->lock); - dev_err(&sisusb->sisusb_dev->dev, "Failed to set up text mode\n"); - return 1; - } - - /* Initialize some gfx registers */ - sisusb_initialize(sisusb); - - for (i = first - 1; i <= last - 1; i++) { - /* Save sisusb for our interface routines */ - mysisusbs[i] = sisusb; - } - - /* Initial console setup */ - sisusb->sisusb_num_columns = 80; - - /* Use a 32K buffer (matches b8000-bffff area) */ - sisusb->scrbuf_size = 32 * 1024; - - /* Allocate screen buffer */ - if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) { - mutex_unlock(&sisusb->lock); - dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate screen buffer\n"); - return 1; - } - - mutex_unlock(&sisusb->lock); - - /* Now grab the desired console(s) */ - ret = take_over_console(&sisusb_con, first - 1, last - 1, 0); - - if (!ret) - sisusb->haveconsole = 1; - else { - for (i = first - 1; i <= last - 1; i++) - mysisusbs[i] = NULL; - } - - return ret; -} - -void -sisusb_console_exit(struct sisusb_usb_data *sisusb) -{ - int i; - - /* This is called if the device is disconnected - * and while disconnect and lock semaphores - * are up. This should be save because we - * can't lose our sisusb any other way but by - * disconnection (and hence, the disconnect - * sema is for protecting all other access - * functions from disconnection, not the - * other way round). - */ - - /* Now what do we do in case of disconnection: - * One alternative would be to simply call - * give_up_console(). Nah, not a good idea. - * give_up_console() is obviously buggy as it - * only discards the consw pointer from the - * driver_map, but doesn't adapt vc->vc_sw - * of the affected consoles. Hence, the next - * call to any of the console functions will - * eventually take a trip to oops county. - * Also, give_up_console for some reason - * doesn't decrement our module refcount. - * Instead, we switch our consoles to a private - * dummy console. This, of course, keeps our - * refcount up as well, but it works perfectly. - */ - - if (sisusb->haveconsole) { - for (i = 0; i < MAX_NR_CONSOLES; i++) - if (sisusb->havethisconsole[i]) - take_over_console(&sisusb_dummy_con, i, i, 0); - /* At this point, con_deinit for all our - * consoles is executed by take_over_console(). - */ - sisusb->haveconsole = 0; - } - - vfree((void *)sisusb->scrbuf); - sisusb->scrbuf = 0; - - vfree(sisusb->font_backup); - sisusb->font_backup = NULL; -} - -void __init sisusb_init_concode(void) -{ - int i; - - for (i = 0; i < MAX_NR_CONSOLES; i++) - mysisusbs[i] = NULL; -} - -#endif /* INCL_CON */ - - - diff --git a/ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb_init.c b/ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb_init.c deleted file mode 100644 index cb8a3d91..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb_init.c +++ /dev/null @@ -1,959 +0,0 @@ -/* - * sisusb - usb kernel driver for SiS315(E) based USB2VGA dongles - * - * Display mode initializing code - * - * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria - * - * If distributed as part of the Linux kernel, this code is licensed under the - * terms of the GPL v2. - * - * Otherwise, the following license terms apply: - * - * * Redistribution and use in source and binary forms, with or without - * * modification, are permitted provided that the following conditions - * * are met: - * * 1) Redistributions of source code must retain the above copyright - * * notice, this list of conditions and the following disclaimer. - * * 2) Redistributions in binary form must reproduce the above copyright - * * notice, this list of conditions and the following disclaimer in the - * * documentation and/or other materials provided with the distribution. - * * 3) The name of the author may not be used to endorse or promote products - * * derived from this software without specific prior written permission. - * * - * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Author: Thomas Winischhofer - * - */ - -#include -#include -#include -#include -#include -#include - -#include "sisusb.h" - -#ifdef INCL_SISUSB_CON - -#include "sisusb_init.h" - -/*********************************************/ -/* POINTER INITIALIZATION */ -/*********************************************/ - -static void SiSUSB_InitPtr(struct SiS_Private *SiS_Pr) -{ - SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo; - SiS_Pr->SiS_StandTable = SiSUSB_StandTable; - - SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable; - SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable; - SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex; - SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table; - - SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData; -} - -/*********************************************/ -/* HELPER: SetReg, GetReg */ -/*********************************************/ - -static void -SiS_SetReg(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short index, unsigned short data) -{ - sisusb_setidxreg(SiS_Pr->sisusb, port, index, data); -} - -static void -SiS_SetRegByte(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short data) -{ - sisusb_setreg(SiS_Pr->sisusb, port, data); -} - -static unsigned char -SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port, unsigned short index) -{ - u8 data; - - sisusb_getidxreg(SiS_Pr->sisusb, port, index, &data); - - return data; -} - -static unsigned char -SiS_GetRegByte(struct SiS_Private *SiS_Pr, unsigned long port) -{ - u8 data; - - sisusb_getreg(SiS_Pr->sisusb, port, &data); - - return data; -} - -static void -SiS_SetRegANDOR(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short index, unsigned short DataAND, - unsigned short DataOR) -{ - sisusb_setidxregandor(SiS_Pr->sisusb, port, index, DataAND, DataOR); -} - -static void -SiS_SetRegAND(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short index, unsigned short DataAND) -{ - sisusb_setidxregand(SiS_Pr->sisusb, port, index, DataAND); -} - -static void -SiS_SetRegOR(struct SiS_Private *SiS_Pr, unsigned long port, - unsigned short index, unsigned short DataOR) -{ - sisusb_setidxregor(SiS_Pr->sisusb, port, index, DataOR); -} - -/*********************************************/ -/* HELPER: DisplayOn, DisplayOff */ -/*********************************************/ - -static void SiS_DisplayOn(struct SiS_Private *SiS_Pr) -{ - SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0xDF); -} - -/*********************************************/ -/* HELPER: Init Port Addresses */ -/*********************************************/ - -static void SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr) -{ - SiS_Pr->SiS_P3c4 = BaseAddr + 0x14; - SiS_Pr->SiS_P3d4 = BaseAddr + 0x24; - SiS_Pr->SiS_P3c0 = BaseAddr + 0x10; - SiS_Pr->SiS_P3ce = BaseAddr + 0x1e; - SiS_Pr->SiS_P3c2 = BaseAddr + 0x12; - SiS_Pr->SiS_P3ca = BaseAddr + 0x1a; - SiS_Pr->SiS_P3c6 = BaseAddr + 0x16; - SiS_Pr->SiS_P3c7 = BaseAddr + 0x17; - SiS_Pr->SiS_P3c8 = BaseAddr + 0x18; - SiS_Pr->SiS_P3c9 = BaseAddr + 0x19; - SiS_Pr->SiS_P3cb = BaseAddr + 0x1b; - SiS_Pr->SiS_P3cc = BaseAddr + 0x1c; - SiS_Pr->SiS_P3cd = BaseAddr + 0x1d; - SiS_Pr->SiS_P3da = BaseAddr + 0x2a; - SiS_Pr->SiS_Part1Port = BaseAddr + SIS_CRT2_PORT_04; -} - -/*********************************************/ -/* HELPER: GetSysFlags */ -/*********************************************/ - -static void SiS_GetSysFlags(struct SiS_Private *SiS_Pr) -{ - SiS_Pr->SiS_MyCR63 = 0x63; -} - -/*********************************************/ -/* HELPER: Init PCI & Engines */ -/*********************************************/ - -static void SiSInitPCIetc(struct SiS_Private *SiS_Pr) -{ - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x20, 0xa1); - /* - Enable 2D (0x40) - * - Enable 3D (0x02) - * - Enable 3D vertex command fetch (0x10) - * - Enable 3D command parser (0x08) - * - Enable 3D G/L transformation engine (0x80) - */ - SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1E, 0xDA); -} - -/*********************************************/ -/* HELPER: SET SEGMENT REGISTERS */ -/*********************************************/ - -static void SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value) -{ - unsigned short temp; - - value &= 0x00ff; - temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb) & 0xf0; - temp |= (value >> 4); - SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb, temp); - temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd) & 0xf0; - temp |= (value & 0x0f); - SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp); -} - -static void SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value) -{ - unsigned short temp; - - value &= 0x00ff; - temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb) & 0x0f; - temp |= (value & 0xf0); - SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cb, temp); - temp = SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd) & 0x0f; - temp |= (value << 4); - SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp); -} - -static void SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value) -{ - SiS_SetSegRegLower(SiS_Pr, value); - SiS_SetSegRegUpper(SiS_Pr, value); -} - -static void SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr) -{ - SiS_SetSegmentReg(SiS_Pr, 0); -} - -static void -SiS_SetSegmentRegOver(struct SiS_Private *SiS_Pr, unsigned short value) -{ - unsigned short temp = value >> 8; - - temp &= 0x07; - temp |= (temp << 4); - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1d, temp); - SiS_SetSegmentReg(SiS_Pr, value); -} - -static void SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr) -{ - SiS_SetSegmentRegOver(SiS_Pr, 0); -} - -static void SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr) -{ - SiS_ResetSegmentReg(SiS_Pr); - SiS_ResetSegmentRegOver(SiS_Pr); -} - -/*********************************************/ -/* HELPER: SearchModeID */ -/*********************************************/ - -static int -SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo, - unsigned short *ModeIdIndex) -{ - if ((*ModeNo) <= 0x13) { - - if ((*ModeNo) != 0x03) - return 0; - - (*ModeIdIndex) = 0; - - } else { - - for (*ModeIdIndex = 0;; (*ModeIdIndex)++) { - - if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == - (*ModeNo)) - break; - - if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == - 0xFF) - return 0; - } - - } - - return 1; -} - -/*********************************************/ -/* HELPER: ENABLE CRT1 */ -/*********************************************/ - -static void SiS_HandleCRT1(struct SiS_Private *SiS_Pr) -{ - /* Enable CRT1 gating */ - SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, SiS_Pr->SiS_MyCR63, 0xbf); -} - -/*********************************************/ -/* HELPER: GetColorDepth */ -/*********************************************/ - -static unsigned short -SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex) -{ - static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8 }; - unsigned short modeflag; - short index; - - if (ModeNo <= 0x13) { - modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - } else { - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - } - - index = (modeflag & ModeTypeMask) - ModeEGA; - if (index < 0) - index = 0; - return ColorDepth[index]; -} - -/*********************************************/ -/* HELPER: GetOffset */ -/*********************************************/ - -static unsigned short -SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex, unsigned short rrti) -{ - unsigned short xres, temp, colordepth, infoflag; - - infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag; - xres = SiS_Pr->SiS_RefIndex[rrti].XRes; - - colordepth = SiS_GetColorDepth(SiS_Pr, ModeNo, ModeIdIndex); - - temp = xres / 16; - - if (infoflag & InterlaceMode) - temp <<= 1; - - temp *= colordepth; - - if (xres % 16) - temp += (colordepth >> 1); - - return temp; -} - -/*********************************************/ -/* SEQ */ -/*********************************************/ - -static void -SiS_SetSeqRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) -{ - unsigned char SRdata; - int i; - - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x00, 0x03); - - SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20; - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, SRdata); - - for (i = 2; i <= 4; i++) { - SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i - 1]; - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, SRdata); - } -} - -/*********************************************/ -/* MISC */ -/*********************************************/ - -static void -SiS_SetMiscRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) -{ - unsigned char Miscdata = SiS_Pr->SiS_StandTable[StandTableIndex].MISC; - - SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c2, Miscdata); -} - -/*********************************************/ -/* CRTC */ -/*********************************************/ - -static void -SiS_SetCRTCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) -{ - unsigned char CRTCdata; - unsigned short i; - - SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f); - - for (i = 0; i <= 0x18; i++) { - CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i]; - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, i, CRTCdata); - } -} - -/*********************************************/ -/* ATT */ -/*********************************************/ - -static void -SiS_SetATTRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) -{ - unsigned char ARdata; - unsigned short i; - - for (i = 0; i <= 0x13; i++) { - ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i]; - SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da); - SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, i); - SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, ARdata); - } - SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da); - SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, 0x14); - SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, 0x00); - - SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da); - SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, 0x20); - SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da); -} - -/*********************************************/ -/* GRC */ -/*********************************************/ - -static void -SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex) -{ - unsigned char GRdata; - unsigned short i; - - for (i = 0; i <= 0x08; i++) { - GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i]; - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3ce, i, GRdata); - } - - if (SiS_Pr->SiS_ModeType > ModeVGA) { - /* 256 color disable */ - SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3ce, 0x05, 0xBF); - } -} - -/*********************************************/ -/* CLEAR EXTENDED REGISTERS */ -/*********************************************/ - -static void SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo) -{ - int i; - - for (i = 0x0A; i <= 0x0E; i++) { - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, 0x00); - } - - SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x37, 0xFE); -} - -/*********************************************/ -/* Get rate index */ -/*********************************************/ - -static unsigned short -SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex) -{ - unsigned short rrti, i, index, temp; - - if (ModeNo <= 0x13) - return 0xFFFF; - - index = SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x33) & 0x0F; - if (index > 0) - index--; - - rrti = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex; - ModeNo = SiS_Pr->SiS_RefIndex[rrti].ModeID; - - i = 0; - do { - if (SiS_Pr->SiS_RefIndex[rrti + i].ModeID != ModeNo) - break; - - temp = - SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask; - if (temp < SiS_Pr->SiS_ModeType) - break; - - i++; - index--; - } while (index != 0xFFFF); - - i--; - - return (rrti + i); -} - -/*********************************************/ -/* SYNC */ -/*********************************************/ - -static void SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti) -{ - unsigned short sync = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag >> 8; - sync &= 0xC0; - sync |= 0x2f; - SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c2, sync); -} - -/*********************************************/ -/* CRTC/2 */ -/*********************************************/ - -static void -SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex, unsigned short rrti) -{ - unsigned char index; - unsigned short temp, i, j, modeflag; - - SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f); - - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - - index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRT1CRTC; - - for (i = 0, j = 0; i <= 7; i++, j++) { - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j, - SiS_Pr->SiS_CRT1Table[index].CR[i]); - } - for (j = 0x10; i <= 10; i++, j++) { - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j, - SiS_Pr->SiS_CRT1Table[index].CR[i]); - } - for (j = 0x15; i <= 12; i++, j++) { - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j, - SiS_Pr->SiS_CRT1Table[index].CR[i]); - } - for (j = 0x0A; i <= 15; i++, j++) { - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, j, - SiS_Pr->SiS_CRT1Table[index].CR[i]); - } - - temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0; - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, temp); - - temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5; - if (modeflag & DoubleScanMode) - temp |= 0x80; - SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x09, 0x5F, temp); - - if (SiS_Pr->SiS_ModeType > ModeVGA) - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x14, 0x4F); -} - -/*********************************************/ -/* OFFSET & PITCH */ -/*********************************************/ -/* (partly overruled by SetPitch() in XF86) */ -/*********************************************/ - -static void -SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex, unsigned short rrti) -{ - unsigned short du = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, rrti); - unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag; - unsigned short temp; - - temp = (du >> 8) & 0x0f; - SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, 0xF0, temp); - - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x13, (du & 0xFF)); - - if (infoflag & InterlaceMode) - du >>= 1; - - du <<= 5; - temp = (du >> 8) & 0xff; - if (du & 0xff) - temp++; - temp++; - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x10, temp); -} - -/*********************************************/ -/* VCLK */ -/*********************************************/ - -static void -SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short rrti) -{ - unsigned short index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK; - unsigned short clka = SiS_Pr->SiS_VCLKData[index].SR2B; - unsigned short clkb = SiS_Pr->SiS_VCLKData[index].SR2C; - - SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xCF); - - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2B, clka); - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2C, clkb); - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2D, 0x01); -} - -/*********************************************/ -/* FIFO */ -/*********************************************/ - -static void -SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short mi) -{ - unsigned short modeflag = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag; - - /* disable auto-threshold */ - SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x3D, 0xFE); - - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x08, 0xAE); - SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x09, 0xF0); - - if (ModeNo <= 0x13) - return; - - if ((!(modeflag & DoubleScanMode)) || (!(modeflag & HalfDCLK))) { - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x08, 0x34); - SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x3D, 0x01); - } -} - -/*********************************************/ -/* MODE REGISTERS */ -/*********************************************/ - -static void -SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short rrti) -{ - unsigned short data = 0, VCLK = 0, index = 0; - - if (ModeNo > 0x13) { - index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK; - VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK; - } - - if (VCLK >= 166) - data |= 0x0c; - SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x32, 0xf3, data); - - if (VCLK >= 166) - SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1f, 0xe7); - - /* DAC speed */ - data = 0x03; - if (VCLK >= 260) - data = 0x00; - else if (VCLK >= 160) - data = 0x01; - else if (VCLK >= 135) - data = 0x02; - - SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x07, 0xF8, data); -} - -static void -SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex, unsigned short rrti) -{ - unsigned short data, infoflag = 0, modeflag; - - if (ModeNo <= 0x13) - modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag; - else { - modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag; - infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag; - } - - /* Disable DPMS */ - SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x1F, 0x3F); - - data = 0; - if (ModeNo > 0x13) { - if (SiS_Pr->SiS_ModeType > ModeEGA) { - data |= 0x02; - data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2); - } - if (infoflag & InterlaceMode) - data |= 0x20; - } - SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x06, 0xC0, data); - - data = 0; - if (infoflag & InterlaceMode) { - /* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */ - unsigned short hrs = - (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) | - ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2)) - - 3; - unsigned short hto = - (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) | - ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8)) - + 5; - data = hrs - (hto >> 1) + 3; - } - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x19, (data & 0xFF)); - SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x1a, 0xFC, (data >> 8)); - - if (modeflag & HalfDCLK) - SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0x08); - - data = 0; - if (modeflag & LineCompareOff) - data = 0x08; - SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0F, 0xB7, data); - - if ((SiS_Pr->SiS_ModeType == ModeEGA) && (ModeNo > 0x13)) - SiS_SetRegOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0F, 0x40); - - SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xfb); - - data = 0x60; - if (SiS_Pr->SiS_ModeType != ModeText) { - data ^= 0x60; - if (SiS_Pr->SiS_ModeType != ModeEGA) - data ^= 0xA0; - } - SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x21, 0x1F, data); - - SiS_SetVCLKState(SiS_Pr, ModeNo, rrti); - - if (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x31) & 0x40) - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x52, 0x2c); - else - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x52, 0x6c); -} - -/*********************************************/ -/* LOAD DAC */ -/*********************************************/ - -static void -SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData, - unsigned short shiftflag, unsigned short dl, unsigned short ah, - unsigned short al, unsigned short dh) -{ - unsigned short d1, d2, d3; - - switch (dl) { - case 0: - d1 = dh; - d2 = ah; - d3 = al; - break; - case 1: - d1 = ah; - d2 = al; - d3 = dh; - break; - default: - d1 = al; - d2 = dh; - d3 = ah; - } - SiS_SetRegByte(SiS_Pr, DACData, (d1 << shiftflag)); - SiS_SetRegByte(SiS_Pr, DACData, (d2 << shiftflag)); - SiS_SetRegByte(SiS_Pr, DACData, (d3 << shiftflag)); -} - -static void -SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short mi) -{ - unsigned short data, data2, time, i, j, k, m, n, o; - unsigned short si, di, bx, sf; - unsigned long DACAddr, DACData; - const unsigned char *table = NULL; - - if (ModeNo < 0x13) - data = SiS_Pr->SiS_SModeIDTable[mi].St_ModeFlag; - else - data = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag; - - data &= DACInfoFlag; - - j = time = 64; - if (data == 0x00) - table = SiS_MDA_DAC; - else if (data == 0x08) - table = SiS_CGA_DAC; - else if (data == 0x10) - table = SiS_EGA_DAC; - else { - j = 16; - time = 256; - table = SiS_VGA_DAC; - } - - DACAddr = SiS_Pr->SiS_P3c8; - DACData = SiS_Pr->SiS_P3c9; - sf = 0; - SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c6, 0xFF); - - SiS_SetRegByte(SiS_Pr, DACAddr, 0x00); - - for (i = 0; i < j; i++) { - data = table[i]; - for (k = 0; k < 3; k++) { - data2 = 0; - if (data & 0x01) - data2 += 0x2A; - if (data & 0x02) - data2 += 0x15; - SiS_SetRegByte(SiS_Pr, DACData, (data2 << sf)); - data >>= 2; - } - } - - if (time == 256) { - for (i = 16; i < 32; i++) { - data = table[i] << sf; - for (k = 0; k < 3; k++) - SiS_SetRegByte(SiS_Pr, DACData, data); - } - si = 32; - for (m = 0; m < 9; m++) { - di = si; - bx = si + 4; - for (n = 0; n < 3; n++) { - for (o = 0; o < 5; o++) { - SiS_WriteDAC(SiS_Pr, DACData, sf, n, - table[di], table[bx], - table[si]); - si++; - } - si -= 2; - for (o = 0; o < 3; o++) { - SiS_WriteDAC(SiS_Pr, DACData, sf, n, - table[di], table[si], - table[bx]); - si--; - } - } - si += 5; - } - } -} - -/*********************************************/ -/* SET CRT1 REGISTER GROUP */ -/*********************************************/ - -static void -SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo, - unsigned short ModeIdIndex) -{ - unsigned short StandTableIndex, rrti; - - SiS_Pr->SiS_CRT1Mode = ModeNo; - - if (ModeNo <= 0x13) - StandTableIndex = 0; - else - StandTableIndex = 1; - - SiS_ResetSegmentRegisters(SiS_Pr); - SiS_SetSeqRegs(SiS_Pr, StandTableIndex); - SiS_SetMiscRegs(SiS_Pr, StandTableIndex); - SiS_SetCRTCRegs(SiS_Pr, StandTableIndex); - SiS_SetATTRegs(SiS_Pr, StandTableIndex); - SiS_SetGRCRegs(SiS_Pr, StandTableIndex); - SiS_ClearExt1Regs(SiS_Pr, ModeNo); - - rrti = SiS_GetRatePtr(SiS_Pr, ModeNo, ModeIdIndex); - - if (rrti != 0xFFFF) { - SiS_SetCRT1Sync(SiS_Pr, rrti); - SiS_SetCRT1CRTC(SiS_Pr, ModeNo, ModeIdIndex, rrti); - SiS_SetCRT1Offset(SiS_Pr, ModeNo, ModeIdIndex, rrti); - SiS_SetCRT1VCLK(SiS_Pr, ModeNo, rrti); - } - - SiS_SetCRT1FIFO_310(SiS_Pr, ModeNo, ModeIdIndex); - - SiS_SetCRT1ModeRegs(SiS_Pr, ModeNo, ModeIdIndex, rrti); - - SiS_LoadDAC(SiS_Pr, ModeNo, ModeIdIndex); - - SiS_DisplayOn(SiS_Pr); -} - -/*********************************************/ -/* SiSSetMode() */ -/*********************************************/ - -int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo) -{ - unsigned short ModeIdIndex; - unsigned long BaseAddr = SiS_Pr->IOAddress; - - SiSUSB_InitPtr(SiS_Pr); - SiSUSBRegInit(SiS_Pr, BaseAddr); - SiS_GetSysFlags(SiS_Pr); - - if (!(SiS_SearchModeID(SiS_Pr, &ModeNo, &ModeIdIndex))) - return 0; - - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x05, 0x86); - - SiSInitPCIetc(SiS_Pr); - - ModeNo &= 0x7f; - - SiS_Pr->SiS_ModeType = - SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask; - - SiS_Pr->SiS_SetFlag = LowModeTests; - - /* Set mode on CRT1 */ - SiS_SetCRT1Group(SiS_Pr, ModeNo, ModeIdIndex); - - SiS_HandleCRT1(SiS_Pr); - - SiS_DisplayOn(SiS_Pr); - SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c6, 0xFF); - - /* Store mode number */ - SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x34, ModeNo); - - return 1; -} - -int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo) -{ - unsigned short ModeNo = 0; - int i; - - SiSUSB_InitPtr(SiS_Pr); - - if (VModeNo == 0x03) { - - ModeNo = 0x03; - - } else { - - i = 0; - do { - - if (SiS_Pr->SiS_EModeIDTable[i].Ext_VESAID == VModeNo) { - ModeNo = SiS_Pr->SiS_EModeIDTable[i].Ext_ModeID; - break; - } - - } while (SiS_Pr->SiS_EModeIDTable[i++].Ext_ModeID != 0xff); - - } - - if (!ModeNo) - return 0; - - return SiSUSBSetMode(SiS_Pr, ModeNo); -} - -#endif /* INCL_SISUSB_CON */ diff --git a/ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb_init.h b/ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb_init.h deleted file mode 100644 index c46ce42d..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb_init.h +++ /dev/null @@ -1,841 +0,0 @@ -/* $XFree86$ */ -/* $XdotOrg$ */ -/* - * Data and prototypes for init.c - * - * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria - * - * If distributed as part of the Linux kernel, the following license terms - * apply: - * - * * 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 named License, - * * or any later version. - * * - * * This program is distributed in the hope that it will be useful, - * * but WITHOUT ANY WARRANTY; without even the implied warranty of - * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * * GNU General Public License for more details. - * * - * * You should have received a copy of the GNU General Public License - * * along with this program; if not, write to the Free Software - * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA - * - * Otherwise, the following license terms apply: - * - * * Redistribution and use in source and binary forms, with or without - * * modification, are permitted provided that the following conditions - * * are met: - * * 1) Redistributions of source code must retain the above copyright - * * notice, this list of conditions and the following disclaimer. - * * 2) Redistributions in binary form must reproduce the above copyright - * * notice, this list of conditions and the following disclaimer in the - * * documentation and/or other materials provided with the distribution. - * * 3) The name of the author may not be used to endorse or promote products - * * derived from this software without specific prior written permission. - * * - * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Author: Thomas Winischhofer - * - */ - -#ifndef _SISUSB_INIT_H_ -#define _SISUSB_INIT_H_ - -/* SiS_ModeType */ -#define ModeText 0x00 -#define ModeCGA 0x01 -#define ModeEGA 0x02 -#define ModeVGA 0x03 -#define Mode15Bpp 0x04 -#define Mode16Bpp 0x05 -#define Mode24Bpp 0x06 -#define Mode32Bpp 0x07 - -#define ModeTypeMask 0x07 -#define IsTextMode 0x07 - -#define DACInfoFlag 0x0018 -#define MemoryInfoFlag 0x01E0 -#define MemorySizeShift 5 - -/* modeflag */ -#define Charx8Dot 0x0200 -#define LineCompareOff 0x0400 -#define CRT2Mode 0x0800 -#define HalfDCLK 0x1000 -#define NoSupportSimuTV 0x2000 -#define NoSupportLCDScale 0x4000 /* SiS bridge: No scaling possible (no matter what panel) */ -#define DoubleScanMode 0x8000 - -/* Infoflag */ -#define SupportTV 0x0008 -#define SupportTV1024 0x0800 -#define SupportCHTV 0x0800 -#define Support64048060Hz 0x0800 /* Special for 640x480 LCD */ -#define SupportHiVision 0x0010 -#define SupportYPbPr750p 0x1000 -#define SupportLCD 0x0020 -#define SupportRAMDAC2 0x0040 /* All (<= 100Mhz) */ -#define SupportRAMDAC2_135 0x0100 /* All except DH (<= 135Mhz) */ -#define SupportRAMDAC2_162 0x0200 /* B, C (<= 162Mhz) */ -#define SupportRAMDAC2_202 0x0400 /* C (<= 202Mhz) */ -#define InterlaceMode 0x0080 -#define SyncPP 0x0000 -#define SyncPN 0x4000 -#define SyncNP 0x8000 -#define SyncNN 0xc000 - -/* SetFlag */ -#define ProgrammingCRT2 0x0001 -#define LowModeTests 0x0002 -#define LCDVESATiming 0x0008 -#define EnableLVDSDDA 0x0010 -#define SetDispDevSwitchFlag 0x0020 -#define CheckWinDos 0x0040 -#define SetDOSMode 0x0080 - -/* Index in ModeResInfo table */ -#define SIS_RI_320x200 0 -#define SIS_RI_320x240 1 -#define SIS_RI_320x400 2 -#define SIS_RI_400x300 3 -#define SIS_RI_512x384 4 -#define SIS_RI_640x400 5 -#define SIS_RI_640x480 6 -#define SIS_RI_800x600 7 -#define SIS_RI_1024x768 8 -#define SIS_RI_1280x1024 9 -#define SIS_RI_1600x1200 10 -#define SIS_RI_1920x1440 11 -#define SIS_RI_2048x1536 12 -#define SIS_RI_720x480 13 -#define SIS_RI_720x576 14 -#define SIS_RI_1280x960 15 -#define SIS_RI_800x480 16 -#define SIS_RI_1024x576 17 -#define SIS_RI_1280x720 18 -#define SIS_RI_856x480 19 -#define SIS_RI_1280x768 20 -#define SIS_RI_1400x1050 21 -#define SIS_RI_1152x864 22 /* Up to here SiS conforming */ -#define SIS_RI_848x480 23 -#define SIS_RI_1360x768 24 -#define SIS_RI_1024x600 25 -#define SIS_RI_1152x768 26 -#define SIS_RI_768x576 27 -#define SIS_RI_1360x1024 28 -#define SIS_RI_1680x1050 29 -#define SIS_RI_1280x800 30 -#define SIS_RI_1920x1080 31 -#define SIS_RI_960x540 32 -#define SIS_RI_960x600 33 - -#define SIS_VIDEO_CAPTURE 0x00 - 0x30 -#define SIS_VIDEO_PLAYBACK 0x02 - 0x30 -#define SIS_CRT2_PORT_04 0x04 - 0x30 - -/* Mode numbers */ -static const unsigned short ModeIndex_320x200[] = { 0x59, 0x41, 0x00, 0x4f }; -static const unsigned short ModeIndex_320x240[] = { 0x50, 0x56, 0x00, 0x53 }; -static const unsigned short ModeIndex_400x300[] = { 0x51, 0x57, 0x00, 0x54 }; -static const unsigned short ModeIndex_512x384[] = { 0x52, 0x58, 0x00, 0x5c }; -static const unsigned short ModeIndex_640x400[] = { 0x2f, 0x5d, 0x00, 0x5e }; -static const unsigned short ModeIndex_640x480[] = { 0x2e, 0x44, 0x00, 0x62 }; -static const unsigned short ModeIndex_720x480[] = { 0x31, 0x33, 0x00, 0x35 }; -static const unsigned short ModeIndex_720x576[] = { 0x32, 0x34, 0x00, 0x36 }; -static const unsigned short ModeIndex_768x576[] = { 0x5f, 0x60, 0x00, 0x61 }; -static const unsigned short ModeIndex_800x480[] = { 0x70, 0x7a, 0x00, 0x76 }; -static const unsigned short ModeIndex_800x600[] = { 0x30, 0x47, 0x00, 0x63 }; -static const unsigned short ModeIndex_848x480[] = { 0x39, 0x3b, 0x00, 0x3e }; -static const unsigned short ModeIndex_856x480[] = { 0x3f, 0x42, 0x00, 0x45 }; -static const unsigned short ModeIndex_960x540[] = { 0x1d, 0x1e, 0x00, 0x1f }; -static const unsigned short ModeIndex_960x600[] = { 0x20, 0x21, 0x00, 0x22 }; -static const unsigned short ModeIndex_1024x768[] = { 0x38, 0x4a, 0x00, 0x64 }; -static const unsigned short ModeIndex_1024x576[] = { 0x71, 0x74, 0x00, 0x77 }; -static const unsigned short ModeIndex_1152x864[] = { 0x29, 0x2a, 0x00, 0x2b }; -static const unsigned short ModeIndex_1280x720[] = { 0x79, 0x75, 0x00, 0x78 }; -static const unsigned short ModeIndex_1280x768[] = { 0x23, 0x24, 0x00, 0x25 }; -static const unsigned short ModeIndex_1280x1024[] = { 0x3a, 0x4d, 0x00, 0x65 }; - -static const unsigned char SiS_MDA_DAC[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F -}; - -static const unsigned char SiS_CGA_DAC[] = { - 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, - 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, - 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, - 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, - 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, - 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, - 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, - 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F -}; - -static const unsigned char SiS_EGA_DAC[] = { - 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15, - 0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35, - 0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D, - 0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D, - 0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17, - 0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37, - 0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F, - 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F -}; - -static const unsigned char SiS_VGA_DAC[] = { - 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15, - 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F, - 0x00, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x18, - 0x1C, 0x20, 0x24, 0x28, 0x2D, 0x32, 0x38, 0x3F, - 0x00, 0x10, 0x1F, 0x2F, 0x3F, 0x1F, 0x27, 0x2F, - 0x37, 0x3F, 0x2D, 0x31, 0x36, 0x3A, 0x3F, 0x00, - 0x07, 0x0E, 0x15, 0x1C, 0x0E, 0x11, 0x15, 0x18, - 0x1C, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x00, 0x04, - 0x08, 0x0C, 0x10, 0x08, 0x0A, 0x0C, 0x0E, 0x10, - 0x0B, 0x0C, 0x0D, 0x0F, 0x10 -}; - -static const struct SiS_St SiSUSB_SModeIDTable[] = { - {0x03, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x01, 0x03, 0x40}, - {0xff, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} -}; - -static const struct SiS_StResInfo_S SiSUSB_StResInfo[] = { - {640, 400}, - {640, 350}, - {720, 400}, - {720, 350}, - {640, 480} -}; - -static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] = { - {320, 200, 8, 8}, /* 0x00 */ - {320, 240, 8, 8}, /* 0x01 */ - {320, 400, 8, 8}, /* 0x02 */ - {400, 300, 8, 8}, /* 0x03 */ - {512, 384, 8, 8}, /* 0x04 */ - {640, 400, 8, 16}, /* 0x05 */ - {640, 480, 8, 16}, /* 0x06 */ - {800, 600, 8, 16}, /* 0x07 */ - {1024, 768, 8, 16}, /* 0x08 */ - {1280, 1024, 8, 16}, /* 0x09 */ - {1600, 1200, 8, 16}, /* 0x0a */ - {1920, 1440, 8, 16}, /* 0x0b */ - {2048, 1536, 8, 16}, /* 0x0c */ - {720, 480, 8, 16}, /* 0x0d */ - {720, 576, 8, 16}, /* 0x0e */ - {1280, 960, 8, 16}, /* 0x0f */ - {800, 480, 8, 16}, /* 0x10 */ - {1024, 576, 8, 16}, /* 0x11 */ - {1280, 720, 8, 16}, /* 0x12 */ - {856, 480, 8, 16}, /* 0x13 */ - {1280, 768, 8, 16}, /* 0x14 */ - {1400, 1050, 8, 16}, /* 0x15 */ - {1152, 864, 8, 16}, /* 0x16 */ - {848, 480, 8, 16}, /* 0x17 */ - {1360, 768, 8, 16}, /* 0x18 */ - {1024, 600, 8, 16}, /* 0x19 */ - {1152, 768, 8, 16}, /* 0x1a */ - {768, 576, 8, 16}, /* 0x1b */ - {1360, 1024, 8, 16}, /* 0x1c */ - {1680, 1050, 8, 16}, /* 0x1d */ - {1280, 800, 8, 16}, /* 0x1e */ - {1920, 1080, 8, 16}, /* 0x1f */ - {960, 540, 8, 16}, /* 0x20 */ - {960, 600, 8, 16} /* 0x21 */ -}; - -static const struct SiS_StandTable SiSUSB_StandTable[] = { - /* MD_3_400 - mode 0x03 - 400 */ - { - 0x50, 0x18, 0x10, 0x1000, - {0x00, 0x03, 0x00, 0x02}, - 0x67, - {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, - 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, - 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, - 0xff}, - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x0c, 0x00, 0x0f, 0x08}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff} - }, - /* Generic for VGA and higher */ - { - 0x00, 0x00, 0x00, 0x0000, - {0x01, 0x0f, 0x00, 0x0e}, - 0x23, - {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, - 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3, - 0xff}, - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x01, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff} - } -}; - -static const struct SiS_Ext SiSUSB_EModeIDTable[] = { - {0x2e, 0x0a1b, 0x0101, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x8 */ - {0x2f, 0x0a1b, 0x0100, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x05, 0x10, 0}, /* 640x400x8 */ - {0x30, 0x2a1b, 0x0103, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x8 */ - {0x31, 0x4a1b, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x8 */ - {0x32, 0x4a1b, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x8 */ - {0x33, 0x4a1d, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x16 */ - {0x34, 0x6a1d, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x16 */ - {0x35, 0x4a1f, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1}, /* 720x480x32 */ - {0x36, 0x6a1f, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1}, /* 720x576x32 */ - {0x38, 0x0a1b, 0x0105, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x8 */ - {0x3a, 0x0e3b, 0x0107, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x8 */ - {0x41, 0x9a1d, 0x010e, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x16 */ - {0x44, 0x0a1d, 0x0111, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x16 */ - {0x47, 0x2a1d, 0x0114, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x16 */ - {0x4a, 0x0a3d, 0x0117, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x16 */ - {0x4d, 0x0e7d, 0x011a, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x16 */ - {0x50, 0x9a1b, 0x0132, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x8 */ - {0x51, 0xba1b, 0x0133, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x8 */ - {0x52, 0xba1b, 0x0134, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x8 */ - {0x56, 0x9a1d, 0x0135, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x16 */ - {0x57, 0xba1d, 0x0136, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x16 */ - {0x58, 0xba1d, 0x0137, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x16 */ - {0x59, 0x9a1b, 0x0138, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x8 */ - {0x5c, 0xba1f, 0x0000, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4}, /* 512x384x32 */ - {0x5d, 0x0a1d, 0x0139, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0}, /* 640x400x16 */ - {0x5e, 0x0a1f, 0x0000, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0}, /* 640x400x32 */ - {0x62, 0x0a3f, 0x013a, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2}, /* 640x480x32 */ - {0x63, 0x2a3f, 0x013b, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3}, /* 800x600x32 */ - {0x64, 0x0a7f, 0x013c, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4}, /* 1024x768x32 */ - {0x65, 0x0eff, 0x013d, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8}, /* 1280x1024x32 */ - {0x70, 0x6a1b, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x8 */ - {0x71, 0x4a1b, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x8 */ - {0x74, 0x4a1d, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x16 */ - {0x75, 0x0a3d, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x16 */ - {0x76, 0x6a1f, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x32 */ - {0x77, 0x4a1f, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1}, /* 1024x576x32 */ - {0x78, 0x0a3f, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x32 */ - {0x79, 0x0a3b, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5}, /* 1280x720x8 */ - {0x7a, 0x6a1d, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1}, /* 800x480x16 */ - {0x23, 0x0e3b, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x8 */ - {0x24, 0x0e7d, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x16 */ - {0x25, 0x0eff, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6}, /* 1280x768x32 */ - {0x39, 0x6a1b, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, -1}, /* 848x480 */ - {0x3b, 0x6a3d, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, - -1}, - {0x3e, 0x6a7f, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, - -1}, - {0x3f, 0x6a1b, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, -1}, /* 856x480 */ - {0x42, 0x6a3d, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, - -1}, - {0x45, 0x6a7f, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, - -1}, - {0x4f, 0x9a1f, 0x0000, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0}, /* 320x200x32 */ - {0x53, 0x9a1f, 0x0000, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2}, /* 320x240x32 */ - {0x54, 0xba1f, 0x0000, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3}, /* 400x300x32 */ - {0x5f, 0x6a1b, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, -1}, /* 768x576 */ - {0x60, 0x6a1d, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, - -1}, - {0x61, 0x6a3f, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, - -1}, - {0x1d, 0x6a1b, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, -1}, /* 960x540 */ - {0x1e, 0x6a3d, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, - -1}, - {0x1f, 0x6a7f, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, - -1}, - {0x20, 0x6a1b, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, -1}, /* 960x600 */ - {0x21, 0x6a3d, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, - -1}, - {0x22, 0x6a7f, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, - -1}, - {0x29, 0x4e1b, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, -1}, /* 1152x864 */ - {0x2a, 0x4e3d, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, - -1}, - {0x2b, 0x4e7f, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, - -1}, - {0xff, 0x0000, 0x0000, 0, 0x00, 0x00, 0x00, 0x00, 0x00, -1} -}; - -static const struct SiS_Ext2 SiSUSB_RefIndex[] = { - {0x085f, 0x0d, 0x03, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */ - {0x0067, 0x0e, 0x04, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */ - {0x0067, 0x0f, 0x08, 0x48, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */ - {0x0067, 0x10, 0x07, 0x8b, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */ - {0x0047, 0x11, 0x0a, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */ - {0x0047, 0x12, 0x0d, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */ - {0x0047, 0x13, 0x13, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */ - {0x0107, 0x14, 0x1c, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */ - {0xc85f, 0x05, 0x00, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */ - {0xc067, 0x06, 0x02, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */ - {0xc067, 0x07, 0x02, 0x47, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */ - {0xc067, 0x08, 0x03, 0x8a, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */ - {0xc047, 0x09, 0x05, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */ - {0xc047, 0x0a, 0x09, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */ - {0xc047, 0x0b, 0x0e, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */ - {0xc047, 0x0c, 0x15, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */ - {0x487f, 0x04, 0x00, 0x00, 0x00, 0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */ - {0xc06f, 0x3c, 0x01, 0x06, 0x13, 0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */ - {0x006f, 0x3d, 0x6f, 0x06, 0x14, 0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */ - {0x0087, 0x15, 0x06, 0x00, 0x06, 0x38, 1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */ - {0xc877, 0x16, 0x0b, 0x06, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */ - {0xc067, 0x17, 0x0f, 0x49, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */ - {0x0067, 0x18, 0x11, 0x00, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */ - {0x0047, 0x19, 0x16, 0x8c, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */ - {0x0107, 0x1a, 0x1b, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */ - {0x0107, 0x1b, 0x1f, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */ - {0x407f, 0x00, 0x00, 0x00, 0x00, 0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */ - {0xc07f, 0x01, 0x00, 0x04, 0x04, 0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */ - {0x007f, 0x02, 0x04, 0x05, 0x05, 0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */ - {0xc077, 0x03, 0x0b, 0x06, 0x06, 0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */ - {0x0077, 0x32, 0x40, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */ - {0x0047, 0x33, 0x07, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */ - {0x0047, 0x34, 0x0a, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */ - {0x0077, 0x35, 0x0b, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */ - {0x0047, 0x36, 0x11, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */ - {0x0047, 0x37, 0x16, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */ - {0x1137, 0x38, 0x19, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */ - {0x1107, 0x39, 0x1e, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */ - {0x1307, 0x3a, 0x20, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */ - {0x0077, 0x42, 0x5b, 0x08, 0x11, 0x23, 1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */ - {0x0087, 0x45, 0x57, 0x00, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi */ - {0xc067, 0x46, 0x55, 0x0b, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz */ - {0x0087, 0x47, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi */ - {0xc067, 0x48, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz */ - {0x006f, 0x4d, 0x71, 0x06, 0x15, 0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz */ - {0x0067, 0x52, 0x6a, 0x00, 0x1c, 0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */ - {0x0077, 0x53, 0x6b, 0x0b, 0x1d, 0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */ - {0x0087, 0x1c, 0x11, 0x00, 0x07, 0x3a, 1280, 1024, 0x30, 0x00, 0x00}, /* 0x2f */ - {0x0137, 0x1d, 0x19, 0x07, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x30 */ - {0x0107, 0x1e, 0x1e, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x31 */ - {0x0207, 0x1f, 0x20, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00}, /* 0x32 */ - {0x0127, 0x54, 0x6d, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz */ - {0x0127, 0x44, 0x19, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz */ - {0x0127, 0x4a, 0x1e, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz */ - {0xffff, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x00, 0x00} -}; - -static const struct SiS_CRT1Table SiSUSB_CRT1Table[] = { - {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f, - 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x00, - 0x00}}, /* 0x0 */ - {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e, - 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00, - 0x00}}, /* 0x1 */ - {{0x3d, 0x31, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0, - 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x05, - 0x01}}, /* 0x2 */ - {{0x4f, 0x3f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5, - 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x01, - 0x01}}, /* 0x3 */ - {{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, - 0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x05, - 0x00}}, /* 0x4 */ - {{0x5f, 0x4f, 0x4f, 0x83, 0x55, 0x81, 0x0b, 0x3e, - 0xe9, 0x8b, 0xdf, 0xe8, 0x0c, 0x00, 0x00, 0x05, - 0x00}}, /* 0x5 */ - {{0x63, 0x4f, 0x4f, 0x87, 0x56, 0x9b, 0x06, 0x3e, - 0xe8, 0x8a, 0xdf, 0xe7, 0x07, 0x00, 0x00, 0x01, - 0x00}}, /* 0x6 */ - {{0x64, 0x4f, 0x4f, 0x88, 0x55, 0x9d, 0xf2, 0x1f, - 0xe0, 0x83, 0xdf, 0xdf, 0xf3, 0x10, 0x00, 0x01, - 0x00}}, /* 0x7 */ - {{0x63, 0x4f, 0x4f, 0x87, 0x5a, 0x81, 0xfb, 0x1f, - 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05, - 0x00}}, /* 0x8 */ - {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0xfb, 0x1f, - 0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05, - 0x61}}, /* 0x9 */ - {{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0x01, 0x3e, - 0xe0, 0x83, 0xdf, 0xdf, 0x02, 0x00, 0x00, 0x05, - 0x61}}, /* 0xa */ - {{0x67, 0x4f, 0x4f, 0x8b, 0x58, 0x81, 0x0d, 0x3e, - 0xe0, 0x83, 0xdf, 0xdf, 0x0e, 0x00, 0x00, 0x05, - 0x61}}, /* 0xb */ - {{0x65, 0x4f, 0x4f, 0x89, 0x57, 0x9f, 0xfb, 0x1f, - 0xe6, 0x8a, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x01, - 0x00}}, /* 0xc */ - {{0x7b, 0x63, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0, - 0x58, 0x8a, 0x57, 0x57, 0x70, 0x20, 0x00, 0x05, - 0x01}}, /* 0xd */ - {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0, - 0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x06, - 0x01}}, /* 0xe */ - {{0x7d, 0x63, 0x63, 0x81, 0x6e, 0x1d, 0x98, 0xf0, - 0x7c, 0x82, 0x57, 0x57, 0x99, 0x00, 0x00, 0x06, - 0x01}}, /* 0xf */ - {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xf0, - 0x58, 0x8b, 0x57, 0x57, 0x70, 0x20, 0x00, 0x06, - 0x01}}, /* 0x10 */ - {{0x7e, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xf0, - 0x58, 0x8b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06, - 0x01}}, /* 0x11 */ - {{0x81, 0x63, 0x63, 0x85, 0x6d, 0x18, 0x7a, 0xf0, - 0x58, 0x8b, 0x57, 0x57, 0x7b, 0x20, 0x00, 0x06, - 0x61}}, /* 0x12 */ - {{0x83, 0x63, 0x63, 0x87, 0x6e, 0x19, 0x81, 0xf0, - 0x58, 0x8b, 0x57, 0x57, 0x82, 0x20, 0x00, 0x06, - 0x61}}, /* 0x13 */ - {{0x85, 0x63, 0x63, 0x89, 0x6f, 0x1a, 0x91, 0xf0, - 0x58, 0x8b, 0x57, 0x57, 0x92, 0x20, 0x00, 0x06, - 0x61}}, /* 0x14 */ - {{0x99, 0x7f, 0x7f, 0x9d, 0x84, 0x1a, 0x96, 0x1f, - 0x7f, 0x83, 0x7f, 0x7f, 0x97, 0x10, 0x00, 0x02, - 0x00}}, /* 0x15 */ - {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, - 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, - 0x01}}, /* 0x16 */ - {{0xa1, 0x7f, 0x7f, 0x85, 0x86, 0x97, 0x24, 0xf5, - 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, - 0x01}}, /* 0x17 */ - {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf5, - 0x00, 0x83, 0xff, 0xff, 0x1f, 0x10, 0x00, 0x02, - 0x01}}, /* 0x18 */ - {{0xa7, 0x7f, 0x7f, 0x8b, 0x89, 0x95, 0x26, 0xf5, - 0x00, 0x83, 0xff, 0xff, 0x27, 0x10, 0x00, 0x02, - 0x01}}, /* 0x19 */ - {{0xa9, 0x7f, 0x7f, 0x8d, 0x8c, 0x9a, 0x2c, 0xf5, - 0x00, 0x83, 0xff, 0xff, 0x2d, 0x14, 0x00, 0x02, - 0x62}}, /* 0x1a */ - {{0xab, 0x7f, 0x7f, 0x8f, 0x8d, 0x9b, 0x35, 0xf5, - 0x00, 0x83, 0xff, 0xff, 0x36, 0x14, 0x00, 0x02, - 0x62}}, /* 0x1b */ - {{0xcf, 0x9f, 0x9f, 0x93, 0xb2, 0x01, 0x14, 0xba, - 0x00, 0x83, 0xff, 0xff, 0x15, 0x00, 0x00, 0x03, - 0x00}}, /* 0x1c */ - {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0x5a, - 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, - 0x01}}, /* 0x1d */ - {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0x5a, - 0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07, - 0x01}}, /* 0x1e */ - {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0x5a, - 0x00, 0x83, 0xff, 0xff, 0x2f, 0x09, 0x00, 0x07, - 0x01}}, /* 0x1f */ - {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, - 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, - 0x00}}, /* 0x20 */ - {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, - 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, - 0x00}}, /* 0x21 */ - {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, - 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, - 0x00}}, /* 0x22 */ - {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, - 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, - 0x00}}, /* 0x23 */ - {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, - 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, - 0x00}}, /* 0x24 */ - {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, - 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, - 0x00}}, /* 0x25 */ - {{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10, - 0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04, - 0x00}}, /* 0x26 */ - {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, - 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, - 0x00}}, /* 0x27 */ - {{0x43, 0xef, 0xef, 0x87, 0x06, 0x00, 0xd4, 0x1f, - 0xa0, 0x83, 0x9f, 0x9f, 0xd5, 0x1f, 0x41, 0x05, - 0x63}}, /* 0x28 */ - {{0x45, 0xef, 0xef, 0x89, 0x07, 0x01, 0xd9, 0x1f, - 0xa0, 0x83, 0x9f, 0x9f, 0xda, 0x1f, 0x41, 0x05, - 0x63}}, /* 0x29 */ - {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, - 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, - 0x00}}, /* 0x2a */ - {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, - 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, - 0x00}}, /* 0x2b */ - {{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f, - 0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01, - 0x00}}, /* 0x2c */ - {{0x59, 0xff, 0xff, 0x9d, 0x17, 0x13, 0x33, 0xba, - 0x00, 0x83, 0xff, 0xff, 0x34, 0x0f, 0x41, 0x05, - 0x44}}, /* 0x2d */ - {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x38, 0xba, - 0x00, 0x83, 0xff, 0xff, 0x39, 0x0f, 0x41, 0x05, - 0x44}}, /* 0x2e */ - {{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x3d, 0xba, - 0x00, 0x83, 0xff, 0xff, 0x3e, 0x0f, 0x41, 0x05, - 0x44}}, /* 0x2f */ - {{0x5d, 0xff, 0xff, 0x81, 0x19, 0x95, 0x41, 0xba, - 0x00, 0x84, 0xff, 0xff, 0x42, 0x0f, 0x41, 0x05, - 0x44}}, /* 0x30 */ - {{0x55, 0xff, 0xff, 0x99, 0x0d, 0x0c, 0x3e, 0xba, - 0x00, 0x84, 0xff, 0xff, 0x3f, 0x0f, 0x41, 0x05, - 0x00}}, /* 0x31 */ - {{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xba, - 0x27, 0x8b, 0xdf, 0xdf, 0x73, 0x00, 0x00, 0x06, - 0x01}}, /* 0x32 */ - {{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xba, - 0x26, 0x89, 0xdf, 0xdf, 0x6f, 0x00, 0x00, 0x06, - 0x01}}, /* 0x33 */ - {{0x7f, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xba, - 0x29, 0x8c, 0xdf, 0xdf, 0x75, 0x00, 0x00, 0x06, - 0x01}}, /* 0x34 */ - {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf1, - 0xaf, 0x85, 0x3f, 0x3f, 0x25, 0x30, 0x00, 0x02, - 0x01}}, /* 0x35 */ - {{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf1, - 0xad, 0x81, 0x3f, 0x3f, 0x1f, 0x30, 0x00, 0x02, - 0x01}}, /* 0x36 */ - {{0xa7, 0x7f, 0x7f, 0x88, 0x89, 0x95, 0x26, 0xf1, - 0xb1, 0x85, 0x3f, 0x3f, 0x27, 0x30, 0x00, 0x02, - 0x01}}, /* 0x37 */ - {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0xc4, - 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, - 0x01}}, /* 0x38 */ - {{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0xd4, - 0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07, - 0x01}}, /* 0x39 */ - {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0xd4, - 0x7d, 0x81, 0xcf, 0xcf, 0x2f, 0x21, 0x00, 0x07, - 0x01}}, /* 0x3a */ - {{0xdc, 0x9f, 0x9f, 0x80, 0xaf, 0x9d, 0xe6, 0xff, - 0xc0, 0x83, 0xbf, 0xbf, 0xe7, 0x10, 0x00, 0x07, - 0x01}}, /* 0x3b */ - {{0x6b, 0x59, 0x59, 0x8f, 0x5e, 0x8c, 0x0b, 0x3e, - 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05, - 0x00}}, /* 0x3c */ - {{0x6d, 0x59, 0x59, 0x91, 0x60, 0x89, 0x53, 0xf0, - 0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05, - 0x41}}, /* 0x3d */ - {{0x86, 0x6a, 0x6a, 0x8a, 0x74, 0x06, 0x8c, 0x15, - 0x4f, 0x83, 0xef, 0xef, 0x8d, 0x30, 0x00, 0x02, - 0x00}}, /* 0x3e */ - {{0x81, 0x6a, 0x6a, 0x85, 0x70, 0x00, 0x0f, 0x3e, - 0xeb, 0x8e, 0xdf, 0xdf, 0x10, 0x00, 0x00, 0x02, - 0x00}}, /* 0x3f */ - {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x1e, 0xf1, - 0xae, 0x85, 0x57, 0x57, 0x1f, 0x30, 0x00, 0x02, - 0x01}}, /* 0x40 */ - {{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5, - 0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02, - 0x01}}, /* 0x41 */ - {{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x20, 0xf5, - 0x03, 0x88, 0xff, 0xff, 0x21, 0x10, 0x00, 0x07, - 0x01}}, /* 0x42 */ - {{0xe6, 0xae, 0xae, 0x8a, 0xbd, 0x90, 0x3d, 0x10, - 0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x00, 0x03, - 0x00}}, /* 0x43 */ - {{0xc3, 0x8f, 0x8f, 0x87, 0x9b, 0x0b, 0x82, 0xef, - 0x60, 0x83, 0x5f, 0x5f, 0x83, 0x10, 0x00, 0x07, - 0x01}}, /* 0x44 */ - {{0x86, 0x69, 0x69, 0x8A, 0x74, 0x06, 0x8C, 0x15, - 0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02, - 0x00}}, /* 0x45 */ - {{0x83, 0x69, 0x69, 0x87, 0x6f, 0x1d, 0x03, 0x3E, - 0xE5, 0x8d, 0xDF, 0xe4, 0x04, 0x00, 0x00, 0x06, - 0x00}}, /* 0x46 */ - {{0x86, 0x6A, 0x6A, 0x8A, 0x74, 0x06, 0x8C, 0x15, - 0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02, - 0x00}}, /* 0x47 */ - {{0x81, 0x6A, 0x6A, 0x85, 0x70, 0x00, 0x0F, 0x3E, - 0xEB, 0x8E, 0xDF, 0xDF, 0x10, 0x00, 0x00, 0x02, - 0x00}}, /* 0x48 */ - {{0xdd, 0xa9, 0xa9, 0x81, 0xb4, 0x97, 0x26, 0xfd, - 0x01, 0x8d, 0xff, 0x00, 0x27, 0x10, 0x00, 0x03, - 0x01}}, /* 0x49 */ - {{0xd9, 0x8f, 0x8f, 0x9d, 0xba, 0x0a, 0x8a, 0xff, - 0x60, 0x8b, 0x5f, 0x5f, 0x8b, 0x10, 0x00, 0x03, - 0x01}}, /* 0x4a */ - {{0xea, 0xae, 0xae, 0x8e, 0xba, 0x82, 0x40, 0x10, - 0x1b, 0x87, 0x19, 0x1a, 0x41, 0x0f, 0x00, 0x03, - 0x00}}, /* 0x4b */ - {{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0xf1, 0xff, - 0xc0, 0x83, 0xbf, 0xbf, 0xf2, 0x10, 0x00, 0x07, - 0x01}}, /* 0x4c */ - {{0x75, 0x5f, 0x5f, 0x99, 0x66, 0x90, 0x53, 0xf0, - 0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05, - 0x41}}, - {{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e, - 0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00, - 0x00}}, /* 0x4e */ - {{0xcd, 0x9f, 0x9f, 0x91, 0xab, 0x1c, 0x3a, 0xff, - 0x20, 0x83, 0x1f, 0x1f, 0x3b, 0x10, 0x00, 0x07, - 0x21}}, /* 0x4f */ - {{0x15, 0xd1, 0xd1, 0x99, 0xe2, 0x19, 0x3d, 0x10, - 0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x01, 0x0c, - 0x20}}, /* 0x50 */ - {{0x0e, 0xef, 0xef, 0x92, 0xfe, 0x03, 0x30, 0xf0, - 0x1e, 0x83, 0x1b, 0x1c, 0x31, 0x00, 0x01, 0x00, - 0x61}}, /* 0x51 */ - {{0x85, 0x77, 0x77, 0x89, 0x7d, 0x01, 0x31, 0xf0, - 0x1e, 0x84, 0x1b, 0x1c, 0x32, 0x00, 0x00, 0x02, - 0x41}}, /* 0x52 */ - {{0x87, 0x77, 0x77, 0x8b, 0x81, 0x0b, 0x68, 0xf0, - 0x5a, 0x80, 0x57, 0x57, 0x69, 0x00, 0x00, 0x02, - 0x01}}, /* 0x53 */ - {{0xcd, 0x8f, 0x8f, 0x91, 0x9b, 0x1b, 0x7a, 0xff, - 0x64, 0x8c, 0x5f, 0x62, 0x7b, 0x10, 0x00, 0x07, - 0x41}} /* 0x54 */ -}; - -static const struct SiS_VCLKData SiSUSB_VCLKData[] = { - {0x1b, 0xe1, 25}, /* 0x00 */ - {0x4e, 0xe4, 28}, /* 0x01 */ - {0x57, 0xe4, 31}, /* 0x02 */ - {0xc3, 0xc8, 36}, /* 0x03 */ - {0x42, 0xe2, 40}, /* 0x04 */ - {0xfe, 0xcd, 43}, /* 0x05 */ - {0x5d, 0xc4, 44}, /* 0x06 */ - {0x52, 0xe2, 49}, /* 0x07 */ - {0x53, 0xe2, 50}, /* 0x08 */ - {0x74, 0x67, 52}, /* 0x09 */ - {0x6d, 0x66, 56}, /* 0x0a */ - {0x5a, 0x64, 65}, /* 0x0b */ - {0x46, 0x44, 67}, /* 0x0c */ - {0xb1, 0x46, 68}, /* 0x0d */ - {0xd3, 0x4a, 72}, /* 0x0e */ - {0x29, 0x61, 75}, /* 0x0f */ - {0x6e, 0x46, 76}, /* 0x10 */ - {0x2b, 0x61, 78}, /* 0x11 */ - {0x31, 0x42, 79}, /* 0x12 */ - {0xab, 0x44, 83}, /* 0x13 */ - {0x46, 0x25, 84}, /* 0x14 */ - {0x78, 0x29, 86}, /* 0x15 */ - {0x62, 0x44, 94}, /* 0x16 */ - {0x2b, 0x41, 104}, /* 0x17 */ - {0x3a, 0x23, 105}, /* 0x18 */ - {0x70, 0x44, 108}, /* 0x19 */ - {0x3c, 0x23, 109}, /* 0x1a */ - {0x5e, 0x43, 113}, /* 0x1b */ - {0xbc, 0x44, 116}, /* 0x1c */ - {0xe0, 0x46, 132}, /* 0x1d */ - {0x54, 0x42, 135}, /* 0x1e */ - {0xea, 0x2a, 139}, /* 0x1f */ - {0x41, 0x22, 157}, /* 0x20 */ - {0x70, 0x24, 162}, /* 0x21 */ - {0x30, 0x21, 175}, /* 0x22 */ - {0x4e, 0x22, 189}, /* 0x23 */ - {0xde, 0x26, 194}, /* 0x24 */ - {0x62, 0x06, 202}, /* 0x25 */ - {0x3f, 0x03, 229}, /* 0x26 */ - {0xb8, 0x06, 234}, /* 0x27 */ - {0x34, 0x02, 253}, /* 0x28 */ - {0x58, 0x04, 255}, /* 0x29 */ - {0x24, 0x01, 265}, /* 0x2a */ - {0x9b, 0x02, 267}, /* 0x2b */ - {0x70, 0x05, 270}, /* 0x2c */ - {0x25, 0x01, 272}, /* 0x2d */ - {0x9c, 0x02, 277}, /* 0x2e */ - {0x27, 0x01, 286}, /* 0x2f */ - {0x3c, 0x02, 291}, /* 0x30 */ - {0xef, 0x0a, 292}, /* 0x31 */ - {0xf6, 0x0a, 310}, /* 0x32 */ - {0x95, 0x01, 315}, /* 0x33 */ - {0xf0, 0x09, 324}, /* 0x34 */ - {0xfe, 0x0a, 331}, /* 0x35 */ - {0xf3, 0x09, 332}, /* 0x36 */ - {0xea, 0x08, 340}, /* 0x37 */ - {0xe8, 0x07, 376}, /* 0x38 */ - {0xde, 0x06, 389}, /* 0x39 */ - {0x52, 0x2a, 54}, /* 0x3a 301 TV */ - {0x52, 0x6a, 27}, /* 0x3b 301 TV */ - {0x62, 0x24, 70}, /* 0x3c 301 TV */ - {0x62, 0x64, 70}, /* 0x3d 301 TV */ - {0xa8, 0x4c, 30}, /* 0x3e 301 TV */ - {0x20, 0x26, 33}, /* 0x3f 301 TV */ - {0x31, 0xc2, 39}, /* 0x40 */ - {0x60, 0x36, 30}, /* 0x41 Chrontel */ - {0x40, 0x4a, 28}, /* 0x42 Chrontel */ - {0x9f, 0x46, 44}, /* 0x43 Chrontel */ - {0x97, 0x2c, 26}, /* 0x44 */ - {0x44, 0xe4, 25}, /* 0x45 Chrontel */ - {0x7e, 0x32, 47}, /* 0x46 Chrontel */ - {0x8a, 0x24, 31}, /* 0x47 Chrontel */ - {0x97, 0x2c, 26}, /* 0x48 Chrontel */ - {0xce, 0x3c, 39}, /* 0x49 */ - {0x52, 0x4a, 36}, /* 0x4a Chrontel */ - {0x34, 0x61, 95}, /* 0x4b */ - {0x78, 0x27, 108}, /* 0x4c - was 102 */ - {0x66, 0x43, 123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */ - {0x41, 0x4e, 21}, /* 0x4e */ - {0xa1, 0x4a, 29}, /* 0x4f Chrontel */ - {0x19, 0x42, 42}, /* 0x50 */ - {0x54, 0x46, 58}, /* 0x51 Chrontel */ - {0x25, 0x42, 61}, /* 0x52 */ - {0x44, 0x44, 66}, /* 0x53 Chrontel */ - {0x3a, 0x62, 70}, /* 0x54 Chrontel */ - {0x62, 0xc6, 34}, /* 0x55 848x480-60 */ - {0x6a, 0xc6, 37}, /* 0x56 848x480-75 - TEMP */ - {0xbf, 0xc8, 35}, /* 0x57 856x480-38i,60 */ - {0x30, 0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */ - {0x52, 0x07, 149}, /* 0x59 1280x960-85 */ - {0x56, 0x07, 156}, /* 0x5a 1400x1050-75 */ - {0x70, 0x29, 81}, /* 0x5b 1280x768 LCD */ - {0x45, 0x25, 83}, /* 0x5c 1280x800 */ - {0x70, 0x0a, 147}, /* 0x5d 1680x1050 */ - {0x70, 0x24, 162}, /* 0x5e 1600x1200 */ - {0x5a, 0x64, 65}, /* 0x5f 1280x720 - temp */ - {0x63, 0x46, 68}, /* 0x60 1280x768_2 */ - {0x31, 0x42, 79}, /* 0x61 1280x768_3 - temp */ - {0, 0, 0}, /* 0x62 - custom (will be filled out at run-time) */ - {0x5a, 0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */ - {0x70, 0x28, 90}, /* 0x64 1152x864@60 */ - {0x41, 0xc4, 32}, /* 0x65 848x480@60 */ - {0x5c, 0xc6, 32}, /* 0x66 856x480@60 */ - {0x76, 0xe7, 27}, /* 0x67 720x480@60 */ - {0x5f, 0xc6, 33}, /* 0x68 720/768x576@60 */ - {0x52, 0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */ - {0x7c, 0x6b, 38}, /* 0x6a 960x540@60 */ - {0xe3, 0x56, 41}, /* 0x6b 960x600@60 */ - {0x45, 0x25, 83}, /* 0x6c 1280x800 */ - {0x70, 0x28, 90}, /* 0x6d 1152x864@60 */ - {0x15, 0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */ - {0x5f, 0xc6, 33}, /* 0x6f 720x576@60 */ - {0x37, 0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */ - {0x2b, 0xc2, 35} /* 0x71 768@576@60 */ -}; - -int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo); -int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo); - -extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data); -extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 * data); -extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port, - u8 index, u8 data); -extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port, - u8 index, u8 * data); -extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port, - u8 idx, u8 myand, u8 myor); -extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port, - u8 index, u8 myor); -extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port, - u8 idx, u8 myand); - -void sisusb_delete(struct kref *kref); -int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data); -int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 * data); -int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src, - u32 dest, int length, size_t * bytes_written); -int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init); -int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot, - u8 * arg, int cmapsz, int ch512, int dorecalc, - struct vc_data *c, int fh, int uplock); -void sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location); -int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last); -void sisusb_console_exit(struct sisusb_usb_data *sisusb); -void sisusb_init_concode(void); - -#endif diff --git a/ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb_struct.h b/ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb_struct.h deleted file mode 100644 index 1c4240e8..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/sisusbvga/sisusb_struct.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * General structure definitions for universal mode switching modules - * - * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria - * - * If distributed as part of the Linux kernel, the following license terms - * apply: - * - * * 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 named License, - * * or any later version. - * * - * * This program is distributed in the hope that it will be useful, - * * but WITHOUT ANY WARRANTY; without even the implied warranty of - * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * * GNU General Public License for more details. - * * - * * You should have received a copy of the GNU General Public License - * * along with this program; if not, write to the Free Software - * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA - * - * Otherwise, the following license terms apply: - * - * * Redistribution and use in source and binary forms, with or without - * * modification, are permitted provided that the following conditions - * * are met: - * * 1) Redistributions of source code must retain the above copyright - * * notice, this list of conditions and the following disclaimer. - * * 2) Redistributions in binary form must reproduce the above copyright - * * notice, this list of conditions and the following disclaimer in the - * * documentation and/or other materials provided with the distribution. - * * 3) The name of the author may not be used to endorse or promote products - * * derived from this software without specific prior written permission. - * * - * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Author: Thomas Winischhofer - * - */ - -#ifndef _SISUSB_STRUCT_H_ -#define _SISUSB_STRUCT_H_ - -struct SiS_St { - unsigned char St_ModeID; - unsigned short St_ModeFlag; - unsigned char St_StTableIndex; - unsigned char St_CRT2CRTC; - unsigned char St_ResInfo; - unsigned char VB_StTVFlickerIndex; - unsigned char VB_StTVEdgeIndex; - unsigned char VB_StTVYFilterIndex; - unsigned char St_PDC; -}; - -struct SiS_StandTable { - unsigned char CRT_COLS; - unsigned char ROWS; - unsigned char CHAR_HEIGHT; - unsigned short CRT_LEN; - unsigned char SR[4]; - unsigned char MISC; - unsigned char CRTC[0x19]; - unsigned char ATTR[0x14]; - unsigned char GRC[9]; -}; - -struct SiS_StResInfo_S { - unsigned short HTotal; - unsigned short VTotal; -}; - -struct SiS_Ext { - unsigned char Ext_ModeID; - unsigned short Ext_ModeFlag; - unsigned short Ext_VESAID; - unsigned char Ext_RESINFO; - unsigned char VB_ExtTVFlickerIndex; - unsigned char VB_ExtTVEdgeIndex; - unsigned char VB_ExtTVYFilterIndex; - unsigned char VB_ExtTVYFilterIndexROM661; - unsigned char REFindex; - char ROMMODEIDX661; -}; - -struct SiS_Ext2 { - unsigned short Ext_InfoFlag; - unsigned char Ext_CRT1CRTC; - unsigned char Ext_CRTVCLK; - unsigned char Ext_CRT2CRTC; - unsigned char Ext_CRT2CRTC_NS; - unsigned char ModeID; - unsigned short XRes; - unsigned short YRes; - unsigned char Ext_PDC; - unsigned char Ext_FakeCRT2CRTC; - unsigned char Ext_FakeCRT2Clk; -}; - -struct SiS_CRT1Table { - unsigned char CR[17]; -}; - -struct SiS_VCLKData { - unsigned char SR2B, SR2C; - unsigned short CLOCK; -}; - -struct SiS_ModeResInfo { - unsigned short HTotal; - unsigned short VTotal; - unsigned char XChar; - unsigned char YChar; -}; - -struct SiS_Private { - void *sisusb; - - unsigned long IOAddress; - - unsigned long SiS_P3c4; - unsigned long SiS_P3d4; - unsigned long SiS_P3c0; - unsigned long SiS_P3ce; - unsigned long SiS_P3c2; - unsigned long SiS_P3ca; - unsigned long SiS_P3c6; - unsigned long SiS_P3c7; - unsigned long SiS_P3c8; - unsigned long SiS_P3c9; - unsigned long SiS_P3cb; - unsigned long SiS_P3cc; - unsigned long SiS_P3cd; - unsigned long SiS_P3da; - unsigned long SiS_Part1Port; - - unsigned char SiS_MyCR63; - unsigned short SiS_CRT1Mode; - unsigned short SiS_ModeType; - unsigned short SiS_SetFlag; - - const struct SiS_StandTable *SiS_StandTable; - const struct SiS_St *SiS_SModeIDTable; - const struct SiS_Ext *SiS_EModeIDTable; - const struct SiS_Ext2 *SiS_RefIndex; - const struct SiS_CRT1Table *SiS_CRT1Table; - const struct SiS_VCLKData *SiS_VCLKData; - const struct SiS_ModeResInfo *SiS_ModeResInfo; -}; - -#endif diff --git a/ANDROID_3.4.5/drivers/usb/misc/trancevibrator.c b/ANDROID_3.4.5/drivers/usb/misc/trancevibrator.c deleted file mode 100644 index 741efed4..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/trancevibrator.c +++ /dev/null @@ -1,144 +0,0 @@ -/* - * PlayStation 2 Trance Vibrator driver - * - * Copyright (C) 2006 Sam Hocevar - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* Standard include files */ -#include -#include -#include -#include -#include -#include - -/* Version Information */ -#define DRIVER_VERSION "v1.1" -#define DRIVER_AUTHOR "Sam Hocevar, sam@zoy.org" -#define DRIVER_DESC "PlayStation 2 Trance Vibrator driver" - -#define TRANCEVIBRATOR_VENDOR_ID 0x0b49 /* ASCII Corporation */ -#define TRANCEVIBRATOR_PRODUCT_ID 0x064f /* Trance Vibrator */ - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(TRANCEVIBRATOR_VENDOR_ID, TRANCEVIBRATOR_PRODUCT_ID) }, - { }, -}; -MODULE_DEVICE_TABLE (usb, id_table); - -/* Driver-local specific stuff */ -struct trancevibrator { - struct usb_device *udev; - unsigned int speed; -}; - -static ssize_t show_speed(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct trancevibrator *tv = usb_get_intfdata(intf); - - return sprintf(buf, "%d\n", tv->speed); -} - -static ssize_t set_speed(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct trancevibrator *tv = usb_get_intfdata(intf); - int temp, retval, old; - - temp = simple_strtoul(buf, NULL, 10); - if (temp > 255) - temp = 255; - else if (temp < 0) - temp = 0; - old = tv->speed; - tv->speed = temp; - - dev_dbg(&tv->udev->dev, "speed = %d\n", tv->speed); - - /* Set speed */ - retval = usb_control_msg(tv->udev, usb_sndctrlpipe(tv->udev, 0), - 0x01, /* vendor request: set speed */ - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER, - tv->speed, /* speed value */ - 0, NULL, 0, USB_CTRL_GET_TIMEOUT); - if (retval) { - tv->speed = old; - dev_dbg(&tv->udev->dev, "retval = %d\n", retval); - return retval; - } - return count; -} - -static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR, show_speed, set_speed); - -static int tv_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(interface); - struct trancevibrator *dev; - int retval; - - dev = kzalloc(sizeof(struct trancevibrator), GFP_KERNEL); - if (dev == NULL) { - dev_err(&interface->dev, "Out of memory\n"); - retval = -ENOMEM; - goto error; - } - - dev->udev = usb_get_dev(udev); - usb_set_intfdata(interface, dev); - retval = device_create_file(&interface->dev, &dev_attr_speed); - if (retval) - goto error_create_file; - - return 0; - -error_create_file: - usb_put_dev(udev); - usb_set_intfdata(interface, NULL); -error: - kfree(dev); - return retval; -} - -static void tv_disconnect(struct usb_interface *interface) -{ - struct trancevibrator *dev; - - dev = usb_get_intfdata (interface); - device_remove_file(&interface->dev, &dev_attr_speed); - usb_set_intfdata(interface, NULL); - usb_put_dev(dev->udev); - kfree(dev); -} - -/* USB subsystem object */ -static struct usb_driver tv_driver = { - .name = "trancevibrator", - .probe = tv_probe, - .disconnect = tv_disconnect, - .id_table = id_table, -}; - -module_usb_driver(tv_driver); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/misc/usb_u132.h b/ANDROID_3.4.5/drivers/usb/misc/usb_u132.h deleted file mode 100644 index dc2e5a31..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/usb_u132.h +++ /dev/null @@ -1,101 +0,0 @@ -/* -* Common Header File for the Elan Digital Systems U132 adapter -* this file should be included by both the "ftdi-u132" and -* the "u132-hcd" modules. -* -* Copyright(C) 2006 Elan Digital Systems Limited -*(http://www.elandigitalsystems.com) -* -* Author and Maintainer - Tony Olech - Elan Digital Systems -*(tony.olech@elandigitalsystems.com) -* -* This program is free software;you can redistribute it and/or -* modify it under the terms of the GNU General Public License as -* published by the Free Software Foundation, version 2. -* -* -* The driver was written by Tony Olech(tony.olech@elandigitalsystems.com) -* based on various USB client drivers in the 2.6.15 linux kernel -* with constant reference to the 3rd Edition of Linux Device Drivers -* published by O'Reilly -* -* The U132 adapter is a USB to CardBus adapter specifically designed -* for PC cards that contain an OHCI host controller. Typical PC cards -* are the Orange Mobile 3G Option GlobeTrotter Fusion card. -* -* The U132 adapter will *NOT *work with PC cards that do not contain -* an OHCI controller. A simple way to test whether a PC card has an -* OHCI controller as an interface is to insert the PC card directly -* into a laptop(or desktop) with a CardBus slot and if "lspci" shows -* a new USB controller and "lsusb -v" shows a new OHCI Host Controller -* then there is a good chance that the U132 adapter will support the -* PC card.(you also need the specific client driver for the PC card) -* -* Please inform the Author and Maintainer about any PC cards that -* contain OHCI Host Controller and work when directly connected to -* an embedded CardBus slot but do not work when they are connected -* via an ELAN U132 adapter. -* -* The driver consists of two modules, the "ftdi-u132" module is -* a USB client driver that interfaces to the FTDI chip within -* the U132 adapter manufactured by Elan Digital Systems, and the -* "u132-hcd" module is a USB host controller driver that talks -* to the OHCI controller within CardBus card that are inserted -* in the U132 adapter. -* -* The "ftdi-u132" module should be loaded automatically by the -* hot plug system when the U132 adapter is plugged in. The module -* initialises the adapter which mostly consists of synchronising -* the FTDI chip, before continuously polling the adapter to detect -* PC card insertions. As soon as a PC card containing a recognised -* OHCI controller is seen the "ftdi-u132" module explicitly requests -* the kernel to load the "u132-hcd" module. -* -* The "ftdi-u132" module provides the interface to the inserted -* PC card and the "u132-hcd" module uses the API to send and receive -* data. The API features call-backs, so that part of the "u132-hcd" -* module code will run in the context of one of the kernel threads -* of the "ftdi-u132" module. -* -*/ -int ftdi_elan_switch_on_diagnostics(int number); -void ftdi_elan_gone_away(struct platform_device *pdev); -void start_usb_lock_device_tracing(void); -struct u132_platform_data { - u16 vendor; - u16 device; - u8 potpg; - void (*port_power) (struct device *dev, int is_on); - void (*reset) (struct device *dev); -}; -int usb_ftdi_elan_edset_single(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)); -int usb_ftdi_elan_edset_output(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)); -int usb_ftdi_elan_edset_empty(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)); -int usb_ftdi_elan_edset_input(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)); -int usb_ftdi_elan_edset_setup(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)); -int usb_ftdi_elan_edset_flush(struct platform_device *pdev, u8 ed_number, - void *endp); -int usb_ftdi_elan_read_pcimem(struct platform_device *pdev, int mem_offset, - u8 width, u32 *data); -int usb_ftdi_elan_write_pcimem(struct platform_device *pdev, int mem_offset, - u8 width, u32 data); diff --git a/ANDROID_3.4.5/drivers/usb/misc/usblcd.c b/ANDROID_3.4.5/drivers/usb/misc/usblcd.c deleted file mode 100644 index e2b4bd31..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/usblcd.c +++ /dev/null @@ -1,457 +0,0 @@ -/***************************************************************************** - * USBLCD Kernel Driver * - * Version 1.05 * - * (C) 2005 Georges Toth * - * * - * This file is licensed under the GPL. See COPYING in the package. * - * Based on usb-skeleton.c 2.0 by Greg Kroah-Hartman (greg@kroah.com) * - * * - * * - * 28.02.05 Complete rewrite of the original usblcd.c driver, * - * based on usb_skeleton.c. * - * This new driver allows more than one USB-LCD to be connected * - * and controlled, at once * - *****************************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRIVER_VERSION "USBLCD Driver Version 1.05" - -#define USBLCD_MINOR 144 - -#define IOCTL_GET_HARD_VERSION 1 -#define IOCTL_GET_DRV_VERSION 2 - - -static DEFINE_MUTEX(lcd_mutex); -static const struct usb_device_id id_table[] = { - { .idVendor = 0x10D2, .match_flags = USB_DEVICE_ID_MATCH_VENDOR, }, - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -static DEFINE_MUTEX(open_disc_mutex); - - -struct usb_lcd { - struct usb_device *udev; /* init: probe_lcd */ - struct usb_interface *interface; /* the interface for - this device */ - unsigned char *bulk_in_buffer; /* the buffer to receive - data */ - size_t bulk_in_size; /* the size of the - receive buffer */ - __u8 bulk_in_endpointAddr; /* the address of the - bulk in endpoint */ - __u8 bulk_out_endpointAddr; /* the address of the - bulk out endpoint */ - struct kref kref; - struct semaphore limit_sem; /* to stop writes at - full throttle from - using up all RAM */ - struct usb_anchor submitted; /* URBs to wait for - before suspend */ -}; -#define to_lcd_dev(d) container_of(d, struct usb_lcd, kref) - -#define USB_LCD_CONCURRENT_WRITES 5 - -static struct usb_driver lcd_driver; - - -static void lcd_delete(struct kref *kref) -{ - struct usb_lcd *dev = to_lcd_dev(kref); - - usb_put_dev(dev->udev); - kfree(dev->bulk_in_buffer); - kfree(dev); -} - - -static int lcd_open(struct inode *inode, struct file *file) -{ - struct usb_lcd *dev; - struct usb_interface *interface; - int subminor, r; - - mutex_lock(&lcd_mutex); - subminor = iminor(inode); - - interface = usb_find_interface(&lcd_driver, subminor); - if (!interface) { - mutex_unlock(&lcd_mutex); - err("USBLCD: %s - error, can't find device for minor %d", - __func__, subminor); - return -ENODEV; - } - - mutex_lock(&open_disc_mutex); - dev = usb_get_intfdata(interface); - if (!dev) { - mutex_unlock(&open_disc_mutex); - mutex_unlock(&lcd_mutex); - return -ENODEV; - } - - /* increment our usage count for the device */ - kref_get(&dev->kref); - mutex_unlock(&open_disc_mutex); - - /* grab a power reference */ - r = usb_autopm_get_interface(interface); - if (r < 0) { - kref_put(&dev->kref, lcd_delete); - mutex_unlock(&lcd_mutex); - return r; - } - - /* save our object in the file's private structure */ - file->private_data = dev; - mutex_unlock(&lcd_mutex); - - return 0; -} - -static int lcd_release(struct inode *inode, struct file *file) -{ - struct usb_lcd *dev; - - dev = file->private_data; - if (dev == NULL) - return -ENODEV; - - /* decrement the count on our device */ - usb_autopm_put_interface(dev->interface); - kref_put(&dev->kref, lcd_delete); - return 0; -} - -static ssize_t lcd_read(struct file *file, char __user * buffer, - size_t count, loff_t *ppos) -{ - struct usb_lcd *dev; - int retval = 0; - int bytes_read; - - dev = file->private_data; - - /* do a blocking bulk read to get data from the device */ - retval = usb_bulk_msg(dev->udev, - usb_rcvbulkpipe(dev->udev, - dev->bulk_in_endpointAddr), - dev->bulk_in_buffer, - min(dev->bulk_in_size, count), - &bytes_read, 10000); - - /* if the read was successful, copy the data to userspace */ - if (!retval) { - if (copy_to_user(buffer, dev->bulk_in_buffer, bytes_read)) - retval = -EFAULT; - else - retval = bytes_read; - } - - return retval; -} - -static long lcd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct usb_lcd *dev; - u16 bcdDevice; - char buf[30]; - - dev = file->private_data; - if (dev == NULL) - return -ENODEV; - - switch (cmd) { - case IOCTL_GET_HARD_VERSION: - mutex_lock(&lcd_mutex); - bcdDevice = le16_to_cpu((dev->udev)->descriptor.bcdDevice); - sprintf(buf, "%1d%1d.%1d%1d", - (bcdDevice & 0xF000)>>12, - (bcdDevice & 0xF00)>>8, - (bcdDevice & 0xF0)>>4, - (bcdDevice & 0xF)); - mutex_unlock(&lcd_mutex); - if (copy_to_user((void __user *)arg, buf, strlen(buf)) != 0) - return -EFAULT; - break; - case IOCTL_GET_DRV_VERSION: - sprintf(buf, DRIVER_VERSION); - if (copy_to_user((void __user *)arg, buf, strlen(buf)) != 0) - return -EFAULT; - break; - default: - return -ENOTTY; - break; - } - - return 0; -} - -static void lcd_write_bulk_callback(struct urb *urb) -{ - struct usb_lcd *dev; - int status = urb->status; - - dev = urb->context; - - /* sync/async unlink faults aren't errors */ - if (status && - !(status == -ENOENT || - status == -ECONNRESET || - status == -ESHUTDOWN)) { - dbg("USBLCD: %s - nonzero write bulk status received: %d", - __func__, status); - } - - /* free up our allocated buffer */ - usb_free_coherent(urb->dev, urb->transfer_buffer_length, - urb->transfer_buffer, urb->transfer_dma); - up(&dev->limit_sem); -} - -static ssize_t lcd_write(struct file *file, const char __user * user_buffer, - size_t count, loff_t *ppos) -{ - struct usb_lcd *dev; - int retval = 0, r; - struct urb *urb = NULL; - char *buf = NULL; - - dev = file->private_data; - - /* verify that we actually have some data to write */ - if (count == 0) - goto exit; - - r = down_interruptible(&dev->limit_sem); - if (r < 0) - return -EINTR; - - /* create a urb, and a buffer for it, and copy the data to the urb */ - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - retval = -ENOMEM; - goto err_no_buf; - } - - buf = usb_alloc_coherent(dev->udev, count, GFP_KERNEL, - &urb->transfer_dma); - if (!buf) { - retval = -ENOMEM; - goto error; - } - - if (copy_from_user(buf, user_buffer, count)) { - retval = -EFAULT; - goto error; - } - - /* initialize the urb properly */ - usb_fill_bulk_urb(urb, dev->udev, - usb_sndbulkpipe(dev->udev, - dev->bulk_out_endpointAddr), - buf, count, lcd_write_bulk_callback, dev); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - usb_anchor_urb(urb, &dev->submitted); - - /* send the data out the bulk port */ - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - err("USBLCD: %s - failed submitting write urb, error %d", - __func__, retval); - goto error_unanchor; - } - - /* release our reference to this urb, - the USB core will eventually free it entirely */ - usb_free_urb(urb); - -exit: - return count; -error_unanchor: - usb_unanchor_urb(urb); -error: - usb_free_coherent(dev->udev, count, buf, urb->transfer_dma); - usb_free_urb(urb); -err_no_buf: - up(&dev->limit_sem); - return retval; -} - -static const struct file_operations lcd_fops = { - .owner = THIS_MODULE, - .read = lcd_read, - .write = lcd_write, - .open = lcd_open, - .unlocked_ioctl = lcd_ioctl, - .release = lcd_release, - .llseek = noop_llseek, -}; - -/* - * usb class driver info in order to get a minor number from the usb core, - * and to have the device registered with the driver core - */ -static struct usb_class_driver lcd_class = { - .name = "lcd%d", - .fops = &lcd_fops, - .minor_base = USBLCD_MINOR, -}; - -static int lcd_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_lcd *dev = NULL; - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - size_t buffer_size; - int i; - int retval = -ENOMEM; - - /* allocate memory for our device state and initialize it */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - err("Out of memory"); - goto error; - } - kref_init(&dev->kref); - sema_init(&dev->limit_sem, USB_LCD_CONCURRENT_WRITES); - init_usb_anchor(&dev->submitted); - - dev->udev = usb_get_dev(interface_to_usbdev(interface)); - dev->interface = interface; - - if (le16_to_cpu(dev->udev->descriptor.idProduct) != 0x0001) { - dev_warn(&interface->dev, "USBLCD model not supported.\n"); - retval = -ENODEV; - goto error; - } - - /* set up the endpoint information */ - /* use only the first bulk-in and bulk-out endpoints */ - iface_desc = interface->cur_altsetting; - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - - if (!dev->bulk_in_endpointAddr && - usb_endpoint_is_bulk_in(endpoint)) { - /* we found a bulk in endpoint */ - buffer_size = usb_endpoint_maxp(endpoint); - dev->bulk_in_size = buffer_size; - dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; - dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!dev->bulk_in_buffer) { - err("Could not allocate bulk_in_buffer"); - goto error; - } - } - - if (!dev->bulk_out_endpointAddr && - usb_endpoint_is_bulk_out(endpoint)) { - /* we found a bulk out endpoint */ - dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; - } - } - if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) { - err("Could not find both bulk-in and bulk-out endpoints"); - goto error; - } - - /* save our data pointer in this interface device */ - usb_set_intfdata(interface, dev); - - /* we can register the device now, as it is ready */ - retval = usb_register_dev(interface, &lcd_class); - if (retval) { - /* something prevented us from registering this driver */ - err("Not able to get a minor for this device."); - usb_set_intfdata(interface, NULL); - goto error; - } - - i = le16_to_cpu(dev->udev->descriptor.bcdDevice); - - dev_info(&interface->dev, "USBLCD Version %1d%1d.%1d%1d found " - "at address %d\n", (i & 0xF000)>>12, (i & 0xF00)>>8, - (i & 0xF0)>>4, (i & 0xF), dev->udev->devnum); - - /* let the user know what node this device is now attached to */ - dev_info(&interface->dev, "USB LCD device now attached to USBLCD-%d\n", - interface->minor); - return 0; - -error: - if (dev) - kref_put(&dev->kref, lcd_delete); - return retval; -} - -static void lcd_draw_down(struct usb_lcd *dev) -{ - int time; - - time = usb_wait_anchor_empty_timeout(&dev->submitted, 1000); - if (!time) - usb_kill_anchored_urbs(&dev->submitted); -} - -static int lcd_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct usb_lcd *dev = usb_get_intfdata(intf); - - if (!dev) - return 0; - lcd_draw_down(dev); - return 0; -} - -static int lcd_resume(struct usb_interface *intf) -{ - return 0; -} - -static void lcd_disconnect(struct usb_interface *interface) -{ - struct usb_lcd *dev; - int minor = interface->minor; - - mutex_lock(&open_disc_mutex); - dev = usb_get_intfdata(interface); - usb_set_intfdata(interface, NULL); - mutex_unlock(&open_disc_mutex); - - /* give back our minor */ - usb_deregister_dev(interface, &lcd_class); - - /* decrement our usage count */ - kref_put(&dev->kref, lcd_delete); - - dev_info(&interface->dev, "USB LCD #%d now disconnected\n", minor); -} - -static struct usb_driver lcd_driver = { - .name = "usblcd", - .probe = lcd_probe, - .disconnect = lcd_disconnect, - .suspend = lcd_suspend, - .resume = lcd_resume, - .id_table = id_table, - .supports_autosuspend = 1, -}; - -module_usb_driver(lcd_driver); - -MODULE_AUTHOR("Georges Toth "); -MODULE_DESCRIPTION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/misc/usbled.c b/ANDROID_3.4.5/drivers/usb/misc/usbled.c deleted file mode 100644 index 12d03e7a..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/usbled.c +++ /dev/null @@ -1,240 +0,0 @@ -/* - * USB LED driver - * - * Copyright (C) 2004 Greg Kroah-Hartman (greg@kroah.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#include -#include -#include -#include -#include -#include - - -#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com" -#define DRIVER_DESC "USB LED Driver" - -enum led_type { - DELCOM_VISUAL_SIGNAL_INDICATOR, - DREAM_CHEEKY_WEBMAIL_NOTIFIER, -}; - -/* table of devices that work with this driver */ -static const struct usb_device_id id_table[] = { - { USB_DEVICE(0x0fc5, 0x1223), - .driver_info = DELCOM_VISUAL_SIGNAL_INDICATOR }, - { USB_DEVICE(0x1d34, 0x0004), - .driver_info = DREAM_CHEEKY_WEBMAIL_NOTIFIER }, - { USB_DEVICE(0x1d34, 0x000a), - .driver_info = DREAM_CHEEKY_WEBMAIL_NOTIFIER }, - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -struct usb_led { - struct usb_device *udev; - unsigned char blue; - unsigned char red; - unsigned char green; - enum led_type type; -}; - -static void change_color(struct usb_led *led) -{ - int retval = 0; - unsigned char *buffer; - - buffer = kmalloc(8, GFP_KERNEL); - if (!buffer) { - dev_err(&led->udev->dev, "out of memory\n"); - return; - } - - switch (led->type) { - case DELCOM_VISUAL_SIGNAL_INDICATOR: { - unsigned char color = 0x07; - - if (led->blue) - color &= ~0x04; - if (led->red) - color &= ~0x02; - if (led->green) - color &= ~0x01; - dev_dbg(&led->udev->dev, - "blue = %d, red = %d, green = %d, color = %.2x\n", - led->blue, led->red, led->green, color); - - retval = usb_control_msg(led->udev, - usb_sndctrlpipe(led->udev, 0), - 0x12, - 0xc8, - (0x02 * 0x100) + 0x0a, - (0x00 * 0x100) + color, - buffer, - 8, - 2000); - break; - } - - case DREAM_CHEEKY_WEBMAIL_NOTIFIER: - dev_dbg(&led->udev->dev, - "red = %d, green = %d, blue = %d\n", - led->red, led->green, led->blue); - - buffer[0] = led->red; - buffer[1] = led->green; - buffer[2] = led->blue; - buffer[3] = buffer[4] = buffer[5] = 0; - buffer[6] = 0x1a; - buffer[7] = 0x05; - - retval = usb_control_msg(led->udev, - usb_sndctrlpipe(led->udev, 0), - 0x09, - 0x21, - 0x200, - 0, - buffer, - 8, - 2000); - break; - - default: - dev_err(&led->udev->dev, "unknown device type %d\n", led->type); - } - - if (retval) - dev_dbg(&led->udev->dev, "retval = %d\n", retval); - kfree(buffer); -} - -#define show_set(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr,\ - char *buf) \ -{ \ - struct usb_interface *intf = to_usb_interface(dev); \ - struct usb_led *led = usb_get_intfdata(intf); \ - \ - return sprintf(buf, "%d\n", led->value); \ -} \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr,\ - const char *buf, size_t count) \ -{ \ - struct usb_interface *intf = to_usb_interface(dev); \ - struct usb_led *led = usb_get_intfdata(intf); \ - int temp = simple_strtoul(buf, NULL, 10); \ - \ - led->value = temp; \ - change_color(led); \ - return count; \ -} \ -static DEVICE_ATTR(value, S_IRUGO | S_IWUSR, show_##value, set_##value); -show_set(blue); -show_set(red); -show_set(green); - -static int led_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(interface); - struct usb_led *dev = NULL; - int retval = -ENOMEM; - - dev = kzalloc(sizeof(struct usb_led), GFP_KERNEL); - if (dev == NULL) { - dev_err(&interface->dev, "out of memory\n"); - goto error_mem; - } - - dev->udev = usb_get_dev(udev); - dev->type = id->driver_info; - - usb_set_intfdata(interface, dev); - - retval = device_create_file(&interface->dev, &dev_attr_blue); - if (retval) - goto error; - retval = device_create_file(&interface->dev, &dev_attr_red); - if (retval) - goto error; - retval = device_create_file(&interface->dev, &dev_attr_green); - if (retval) - goto error; - - if (dev->type == DREAM_CHEEKY_WEBMAIL_NOTIFIER) { - unsigned char *enable; - - enable = kmemdup("\x1f\x02\0\x5f\0\0\x1a\x03", 8, GFP_KERNEL); - if (!enable) { - dev_err(&interface->dev, "out of memory\n"); - retval = -ENOMEM; - goto error; - } - - retval = usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - 0x09, - 0x21, - 0x200, - 0, - enable, - 8, - 2000); - - kfree(enable); - if (retval != 8) - goto error; - } - - dev_info(&interface->dev, "USB LED device now attached\n"); - return 0; - -error: - device_remove_file(&interface->dev, &dev_attr_blue); - device_remove_file(&interface->dev, &dev_attr_red); - device_remove_file(&interface->dev, &dev_attr_green); - usb_set_intfdata(interface, NULL); - usb_put_dev(dev->udev); - kfree(dev); -error_mem: - return retval; -} - -static void led_disconnect(struct usb_interface *interface) -{ - struct usb_led *dev; - - dev = usb_get_intfdata(interface); - - device_remove_file(&interface->dev, &dev_attr_blue); - device_remove_file(&interface->dev, &dev_attr_red); - device_remove_file(&interface->dev, &dev_attr_green); - - /* first remove the files, then set the pointer to NULL */ - usb_set_intfdata(interface, NULL); - - usb_put_dev(dev->udev); - - kfree(dev); - - dev_info(&interface->dev, "USB LED now disconnected\n"); -} - -static struct usb_driver led_driver = { - .name = "usbled", - .probe = led_probe, - .disconnect = led_disconnect, - .id_table = id_table, -}; - -module_usb_driver(led_driver); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/misc/usbsevseg.c b/ANDROID_3.4.5/drivers/usb/misc/usbsevseg.c deleted file mode 100644 index b2d82b93..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/usbsevseg.c +++ /dev/null @@ -1,444 +0,0 @@ -/* - * USB 7 Segment Driver - * - * Copyright (C) 2008 Harrison Metzger - * Based on usbled.c by Greg Kroah-Hartman (greg@kroah.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#include -#include -#include -#include -#include -#include -#include - - -#define DRIVER_AUTHOR "Harrison Metzger " -#define DRIVER_DESC "USB 7 Segment Driver" - -#define VENDOR_ID 0x0fc5 -#define PRODUCT_ID 0x1227 -#define MAXLEN 8 - -/* table of devices that work with this driver */ -static const struct usb_device_id id_table[] = { - { USB_DEVICE(VENDOR_ID, PRODUCT_ID) }, - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -/* the different text display modes the device is capable of */ -static char *display_textmodes[] = {"raw", "hex", "ascii", NULL}; - -struct usb_sevsegdev { - struct usb_device *udev; - struct usb_interface *intf; - - u8 powered; - u8 mode_msb; - u8 mode_lsb; - u8 decimals[MAXLEN]; - u8 textmode; - u8 text[MAXLEN]; - u16 textlength; - - u8 shadow_power; /* for PM */ - u8 has_interface_pm; -}; - -/* sysfs_streq can't replace this completely - * If the device was in hex mode, and the user wanted a 0, - * if str commands are used, we would assume the end of string - * so mem commands are used. - */ -inline size_t my_memlen(const char *buf, size_t count) -{ - if (count > 0 && buf[count-1] == '\n') - return count - 1; - else - return count; -} - -static void update_display_powered(struct usb_sevsegdev *mydev) -{ - int rc; - - if (mydev->powered && !mydev->has_interface_pm) { - rc = usb_autopm_get_interface(mydev->intf); - if (rc < 0) - return; - mydev->has_interface_pm = 1; - } - - if (mydev->shadow_power != 1) - return; - - rc = usb_control_msg(mydev->udev, - usb_sndctrlpipe(mydev->udev, 0), - 0x12, - 0x48, - (80 * 0x100) + 10, /* (power mode) */ - (0x00 * 0x100) + (mydev->powered ? 1 : 0), - NULL, - 0, - 2000); - if (rc < 0) - dev_dbg(&mydev->udev->dev, "power retval = %d\n", rc); - - if (!mydev->powered && mydev->has_interface_pm) { - usb_autopm_put_interface(mydev->intf); - mydev->has_interface_pm = 0; - } -} - -static void update_display_mode(struct usb_sevsegdev *mydev) -{ - int rc; - - if(mydev->shadow_power != 1) - return; - - rc = usb_control_msg(mydev->udev, - usb_sndctrlpipe(mydev->udev, 0), - 0x12, - 0x48, - (82 * 0x100) + 10, /* (set mode) */ - (mydev->mode_msb * 0x100) + mydev->mode_lsb, - NULL, - 0, - 2000); - - if (rc < 0) - dev_dbg(&mydev->udev->dev, "mode retval = %d\n", rc); -} - -static void update_display_visual(struct usb_sevsegdev *mydev, gfp_t mf) -{ - int rc; - int i; - unsigned char *buffer; - u8 decimals = 0; - - if(mydev->shadow_power != 1) - return; - - buffer = kzalloc(MAXLEN, mf); - if (!buffer) { - dev_err(&mydev->udev->dev, "out of memory\n"); - return; - } - - /* The device is right to left, where as you write left to right */ - for (i = 0; i < mydev->textlength; i++) - buffer[i] = mydev->text[mydev->textlength-1-i]; - - rc = usb_control_msg(mydev->udev, - usb_sndctrlpipe(mydev->udev, 0), - 0x12, - 0x48, - (85 * 0x100) + 10, /* (write text) */ - (0 * 0x100) + mydev->textmode, /* mode */ - buffer, - mydev->textlength, - 2000); - - if (rc < 0) - dev_dbg(&mydev->udev->dev, "write retval = %d\n", rc); - - kfree(buffer); - - /* The device is right to left, where as you write left to right */ - for (i = 0; i < sizeof(mydev->decimals); i++) - decimals |= mydev->decimals[i] << i; - - rc = usb_control_msg(mydev->udev, - usb_sndctrlpipe(mydev->udev, 0), - 0x12, - 0x48, - (86 * 0x100) + 10, /* (set decimal) */ - (0 * 0x100) + decimals, /* decimals */ - NULL, - 0, - 2000); - - if (rc < 0) - dev_dbg(&mydev->udev->dev, "decimal retval = %d\n", rc); -} - -#define MYDEV_ATTR_SIMPLE_UNSIGNED(name, update_fcn) \ -static ssize_t show_attr_##name(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct usb_interface *intf = to_usb_interface(dev); \ - struct usb_sevsegdev *mydev = usb_get_intfdata(intf); \ - \ - return sprintf(buf, "%u\n", mydev->name); \ -} \ - \ -static ssize_t set_attr_##name(struct device *dev, \ - struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - struct usb_interface *intf = to_usb_interface(dev); \ - struct usb_sevsegdev *mydev = usb_get_intfdata(intf); \ - \ - mydev->name = simple_strtoul(buf, NULL, 10); \ - update_fcn(mydev); \ - \ - return count; \ -} \ -static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_attr_##name, set_attr_##name); - -static ssize_t show_attr_text(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct usb_sevsegdev *mydev = usb_get_intfdata(intf); - - return snprintf(buf, mydev->textlength, "%s\n", mydev->text); -} - -static ssize_t set_attr_text(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct usb_sevsegdev *mydev = usb_get_intfdata(intf); - size_t end = my_memlen(buf, count); - - if (end > sizeof(mydev->text)) - return -EINVAL; - - memset(mydev->text, 0, sizeof(mydev->text)); - mydev->textlength = end; - - if (end > 0) - memcpy(mydev->text, buf, end); - - update_display_visual(mydev, GFP_KERNEL); - return count; -} - -static DEVICE_ATTR(text, S_IRUGO | S_IWUSR, show_attr_text, set_attr_text); - -static ssize_t show_attr_decimals(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct usb_sevsegdev *mydev = usb_get_intfdata(intf); - int i; - int pos; - - for (i = 0; i < sizeof(mydev->decimals); i++) { - pos = sizeof(mydev->decimals) - 1 - i; - if (mydev->decimals[i] == 0) - buf[pos] = '0'; - else if (mydev->decimals[i] == 1) - buf[pos] = '1'; - else - buf[pos] = 'x'; - } - - buf[sizeof(mydev->decimals)] = '\n'; - return sizeof(mydev->decimals) + 1; -} - -static ssize_t set_attr_decimals(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct usb_sevsegdev *mydev = usb_get_intfdata(intf); - size_t end = my_memlen(buf, count); - int i; - - if (end > sizeof(mydev->decimals)) - return -EINVAL; - - for (i = 0; i < end; i++) - if (buf[i] != '0' && buf[i] != '1') - return -EINVAL; - - memset(mydev->decimals, 0, sizeof(mydev->decimals)); - for (i = 0; i < end; i++) - if (buf[i] == '1') - mydev->decimals[end-1-i] = 1; - - update_display_visual(mydev, GFP_KERNEL); - - return count; -} - -static DEVICE_ATTR(decimals, S_IRUGO | S_IWUSR, show_attr_decimals, set_attr_decimals); - -static ssize_t show_attr_textmode(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct usb_sevsegdev *mydev = usb_get_intfdata(intf); - int i; - - buf[0] = 0; - - for (i = 0; display_textmodes[i]; i++) { - if (mydev->textmode == i) { - strcat(buf, " ["); - strcat(buf, display_textmodes[i]); - strcat(buf, "] "); - } else { - strcat(buf, " "); - strcat(buf, display_textmodes[i]); - strcat(buf, " "); - } - } - strcat(buf, "\n"); - - - return strlen(buf); -} - -static ssize_t set_attr_textmode(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct usb_interface *intf = to_usb_interface(dev); - struct usb_sevsegdev *mydev = usb_get_intfdata(intf); - int i; - - for (i = 0; display_textmodes[i]; i++) { - if (sysfs_streq(display_textmodes[i], buf)) { - mydev->textmode = i; - update_display_visual(mydev, GFP_KERNEL); - return count; - } - } - - return -EINVAL; -} - -static DEVICE_ATTR(textmode, S_IRUGO | S_IWUSR, show_attr_textmode, set_attr_textmode); - - -MYDEV_ATTR_SIMPLE_UNSIGNED(powered, update_display_powered); -MYDEV_ATTR_SIMPLE_UNSIGNED(mode_msb, update_display_mode); -MYDEV_ATTR_SIMPLE_UNSIGNED(mode_lsb, update_display_mode); - -static struct attribute *dev_attrs[] = { - &dev_attr_powered.attr, - &dev_attr_text.attr, - &dev_attr_textmode.attr, - &dev_attr_decimals.attr, - &dev_attr_mode_msb.attr, - &dev_attr_mode_lsb.attr, - NULL -}; - -static struct attribute_group dev_attr_grp = { - .attrs = dev_attrs, -}; - -static int sevseg_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(interface); - struct usb_sevsegdev *mydev = NULL; - int rc = -ENOMEM; - - mydev = kzalloc(sizeof(struct usb_sevsegdev), GFP_KERNEL); - if (mydev == NULL) { - dev_err(&interface->dev, "Out of memory\n"); - goto error_mem; - } - - mydev->udev = usb_get_dev(udev); - mydev->intf = interface; - usb_set_intfdata(interface, mydev); - - /* PM */ - mydev->shadow_power = 1; /* currently active */ - mydev->has_interface_pm = 0; /* have not issued autopm_get */ - - /*set defaults */ - mydev->textmode = 0x02; /* ascii mode */ - mydev->mode_msb = 0x06; /* 6 characters */ - mydev->mode_lsb = 0x3f; /* scanmode for 6 chars */ - - rc = sysfs_create_group(&interface->dev.kobj, &dev_attr_grp); - if (rc) - goto error; - - dev_info(&interface->dev, "USB 7 Segment device now attached\n"); - return 0; - -error: - usb_set_intfdata(interface, NULL); - usb_put_dev(mydev->udev); - kfree(mydev); -error_mem: - return rc; -} - -static void sevseg_disconnect(struct usb_interface *interface) -{ - struct usb_sevsegdev *mydev; - - mydev = usb_get_intfdata(interface); - sysfs_remove_group(&interface->dev.kobj, &dev_attr_grp); - usb_set_intfdata(interface, NULL); - usb_put_dev(mydev->udev); - kfree(mydev); - dev_info(&interface->dev, "USB 7 Segment now disconnected\n"); -} - -static int sevseg_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct usb_sevsegdev *mydev; - - mydev = usb_get_intfdata(intf); - mydev->shadow_power = 0; - - return 0; -} - -static int sevseg_resume(struct usb_interface *intf) -{ - struct usb_sevsegdev *mydev; - - mydev = usb_get_intfdata(intf); - mydev->shadow_power = 1; - update_display_mode(mydev); - update_display_visual(mydev, GFP_NOIO); - - return 0; -} - -static int sevseg_reset_resume(struct usb_interface *intf) -{ - struct usb_sevsegdev *mydev; - - mydev = usb_get_intfdata(intf); - mydev->shadow_power = 1; - update_display_mode(mydev); - update_display_visual(mydev, GFP_NOIO); - - return 0; -} - -static struct usb_driver sevseg_driver = { - .name = "usbsevseg", - .probe = sevseg_probe, - .disconnect = sevseg_disconnect, - .suspend = sevseg_suspend, - .resume = sevseg_resume, - .reset_resume = sevseg_reset_resume, - .id_table = id_table, - .supports_autosuspend = 1, -}; - -module_usb_driver(sevseg_driver); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/misc/usbtest.c b/ANDROID_3.4.5/drivers/usb/misc/usbtest.c deleted file mode 100644 index 055b84ad..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/usbtest.c +++ /dev/null @@ -1,2529 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - - -/*-------------------------------------------------------------------------*/ - -/* FIXME make these public somewhere; usbdevfs.h? */ -struct usbtest_param { - /* inputs */ - unsigned test_num; /* 0..(TEST_CASES-1) */ - unsigned iterations; - unsigned length; - unsigned vary; - unsigned sglen; - - /* outputs */ - struct timeval duration; -}; -#define USBTEST_REQUEST _IOWR('U', 100, struct usbtest_param) - -/*-------------------------------------------------------------------------*/ - -#define GENERIC /* let probe() bind using module params */ - -/* Some devices that can be used for testing will have "real" drivers. - * Entries for those need to be enabled here by hand, after disabling - * that "real" driver. - */ -//#define IBOT2 /* grab iBOT2 webcams */ -//#define KEYSPAN_19Qi /* grab un-renumerated serial adapter */ - -/*-------------------------------------------------------------------------*/ - -struct usbtest_info { - const char *name; - u8 ep_in; /* bulk/intr source */ - u8 ep_out; /* bulk/intr sink */ - unsigned autoconf:1; - unsigned ctrl_out:1; - unsigned iso:1; /* try iso in/out */ - int alt; -}; - -/* this is accessed only through usbfs ioctl calls. - * one ioctl to issue a test ... one lock per device. - * tests create other threads if they need them. - * urbs and buffers are allocated dynamically, - * and data generated deterministically. - */ -struct usbtest_dev { - struct usb_interface *intf; - struct usbtest_info *info; - int in_pipe; - int out_pipe; - int in_iso_pipe; - int out_iso_pipe; - struct usb_endpoint_descriptor *iso_in, *iso_out; - struct mutex lock; - -#define TBUF_SIZE 256 - u8 *buf; -}; - -static struct usb_device *testdev_to_usbdev(struct usbtest_dev *test) -{ - return interface_to_usbdev(test->intf); -} - -/* set up all urbs so they can be used with either bulk or interrupt */ -#define INTERRUPT_RATE 1 /* msec/transfer */ - -#define ERROR(tdev, fmt, args...) \ - dev_err(&(tdev)->intf->dev , fmt , ## args) -#define WARNING(tdev, fmt, args...) \ - dev_warn(&(tdev)->intf->dev , fmt , ## args) - -#define GUARD_BYTE 0xA5 - -/*-------------------------------------------------------------------------*/ - -static int -get_endpoints(struct usbtest_dev *dev, struct usb_interface *intf) -{ - int tmp; - struct usb_host_interface *alt; - struct usb_host_endpoint *in, *out; - struct usb_host_endpoint *iso_in, *iso_out; - struct usb_device *udev; - - for (tmp = 0; tmp < intf->num_altsetting; tmp++) { - unsigned ep; - - in = out = NULL; - iso_in = iso_out = NULL; - alt = intf->altsetting + tmp; - - /* take the first altsetting with in-bulk + out-bulk; - * ignore other endpoints and altsettings. - */ - for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) { - struct usb_host_endpoint *e; - - e = alt->endpoint + ep; - switch (e->desc.bmAttributes) { - case USB_ENDPOINT_XFER_BULK: - break; - case USB_ENDPOINT_XFER_ISOC: - if (dev->info->iso) - goto try_iso; - /* FALLTHROUGH */ - default: - continue; - } - if (usb_endpoint_dir_in(&e->desc)) { - if (!in) - in = e; - } else { - if (!out) - out = e; - } - continue; -try_iso: - if (usb_endpoint_dir_in(&e->desc)) { - if (!iso_in) - iso_in = e; - } else { - if (!iso_out) - iso_out = e; - } - } - if ((in && out) || iso_in || iso_out) - goto found; - } - return -EINVAL; - -found: - udev = testdev_to_usbdev(dev); - if (alt->desc.bAlternateSetting != 0) { - tmp = usb_set_interface(udev, - alt->desc.bInterfaceNumber, - alt->desc.bAlternateSetting); - if (tmp < 0) - return tmp; - } - - if (in) { - dev->in_pipe = usb_rcvbulkpipe(udev, - in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); - dev->out_pipe = usb_sndbulkpipe(udev, - out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); - } - if (iso_in) { - dev->iso_in = &iso_in->desc; - dev->in_iso_pipe = usb_rcvisocpipe(udev, - iso_in->desc.bEndpointAddress - & USB_ENDPOINT_NUMBER_MASK); - } - - if (iso_out) { - dev->iso_out = &iso_out->desc; - dev->out_iso_pipe = usb_sndisocpipe(udev, - iso_out->desc.bEndpointAddress - & USB_ENDPOINT_NUMBER_MASK); - } - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* Support for testing basic non-queued I/O streams. - * - * These just package urbs as requests that can be easily canceled. - * Each urb's data buffer is dynamically allocated; callers can fill - * them with non-zero test data (or test for it) when appropriate. - */ - -static void simple_callback(struct urb *urb) -{ - complete(urb->context); -} - -static struct urb *usbtest_alloc_urb( - struct usb_device *udev, - int pipe, - unsigned long bytes, - unsigned transfer_flags, - unsigned offset) -{ - struct urb *urb; - - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return urb; - usb_fill_bulk_urb(urb, udev, pipe, NULL, bytes, simple_callback, NULL); - urb->interval = (udev->speed == USB_SPEED_HIGH) - ? (INTERRUPT_RATE << 3) - : INTERRUPT_RATE; - urb->transfer_flags = transfer_flags; - if (usb_pipein(pipe)) - urb->transfer_flags |= URB_SHORT_NOT_OK; - - if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) - urb->transfer_buffer = usb_alloc_coherent(udev, bytes + offset, - GFP_KERNEL, &urb->transfer_dma); - else - urb->transfer_buffer = kmalloc(bytes + offset, GFP_KERNEL); - - if (!urb->transfer_buffer) { - usb_free_urb(urb); - return NULL; - } - - /* To test unaligned transfers add an offset and fill the - unused memory with a guard value */ - if (offset) { - memset(urb->transfer_buffer, GUARD_BYTE, offset); - urb->transfer_buffer += offset; - if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) - urb->transfer_dma += offset; - } - - /* For inbound transfers use guard byte so that test fails if - data not correctly copied */ - memset(urb->transfer_buffer, - usb_pipein(urb->pipe) ? GUARD_BYTE : 0, - bytes); - return urb; -} - -static struct urb *simple_alloc_urb( - struct usb_device *udev, - int pipe, - unsigned long bytes) -{ - return usbtest_alloc_urb(udev, pipe, bytes, URB_NO_TRANSFER_DMA_MAP, 0); -} - -static unsigned pattern; -static unsigned mod_pattern; -module_param_named(pattern, mod_pattern, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(mod_pattern, "i/o pattern (0 == zeroes)"); - -static inline void simple_fill_buf(struct urb *urb) -{ - unsigned i; - u8 *buf = urb->transfer_buffer; - unsigned len = urb->transfer_buffer_length; - - switch (pattern) { - default: - /* FALLTHROUGH */ - case 0: - memset(buf, 0, len); - break; - case 1: /* mod63 */ - for (i = 0; i < len; i++) - *buf++ = (u8) (i % 63); - break; - } -} - -static inline unsigned long buffer_offset(void *buf) -{ - return (unsigned long)buf & (ARCH_KMALLOC_MINALIGN - 1); -} - -static int check_guard_bytes(struct usbtest_dev *tdev, struct urb *urb) -{ - u8 *buf = urb->transfer_buffer; - u8 *guard = buf - buffer_offset(buf); - unsigned i; - - for (i = 0; guard < buf; i++, guard++) { - if (*guard != GUARD_BYTE) { - ERROR(tdev, "guard byte[%d] %d (not %d)\n", - i, *guard, GUARD_BYTE); - return -EINVAL; - } - } - return 0; -} - -static int simple_check_buf(struct usbtest_dev *tdev, struct urb *urb) -{ - unsigned i; - u8 expected; - u8 *buf = urb->transfer_buffer; - unsigned len = urb->actual_length; - - int ret = check_guard_bytes(tdev, urb); - if (ret) - return ret; - - for (i = 0; i < len; i++, buf++) { - switch (pattern) { - /* all-zeroes has no synchronization issues */ - case 0: - expected = 0; - break; - /* mod63 stays in sync with short-terminated transfers, - * or otherwise when host and gadget agree on how large - * each usb transfer request should be. resync is done - * with set_interface or set_config. - */ - case 1: /* mod63 */ - expected = i % 63; - break; - /* always fail unsupported patterns */ - default: - expected = !*buf; - break; - } - if (*buf == expected) - continue; - ERROR(tdev, "buf[%d] = %d (not %d)\n", i, *buf, expected); - return -EINVAL; - } - return 0; -} - -static void simple_free_urb(struct urb *urb) -{ - unsigned long offset = buffer_offset(urb->transfer_buffer); - - if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) - usb_free_coherent( - urb->dev, - urb->transfer_buffer_length + offset, - urb->transfer_buffer - offset, - urb->transfer_dma - offset); - else - kfree(urb->transfer_buffer - offset); - usb_free_urb(urb); -} - -static int simple_io( - struct usbtest_dev *tdev, - struct urb *urb, - int iterations, - int vary, - int expected, - const char *label -) -{ - struct usb_device *udev = urb->dev; - int max = urb->transfer_buffer_length; - struct completion completion; - int retval = 0; - - urb->context = &completion; - while (retval == 0 && iterations-- > 0) { - init_completion(&completion); - if (usb_pipeout(urb->pipe)) { - simple_fill_buf(urb); - urb->transfer_flags |= URB_ZERO_PACKET; - } - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval != 0) - break; - - /* NOTE: no timeouts; can't be broken out of by interrupt */ - wait_for_completion(&completion); - retval = urb->status; - urb->dev = udev; - if (retval == 0 && usb_pipein(urb->pipe)) - retval = simple_check_buf(tdev, urb); - - if (vary) { - int len = urb->transfer_buffer_length; - - len += vary; - len %= max; - if (len == 0) - len = (vary < max) ? vary : max; - urb->transfer_buffer_length = len; - } - - /* FIXME if endpoint halted, clear halt (and log) */ - } - urb->transfer_buffer_length = max; - - if (expected != retval) - dev_err(&udev->dev, - "%s failed, iterations left %d, status %d (not %d)\n", - label, iterations, retval, expected); - return retval; -} - - -/*-------------------------------------------------------------------------*/ - -/* We use scatterlist primitives to test queued I/O. - * Yes, this also tests the scatterlist primitives. - */ - -static void free_sglist(struct scatterlist *sg, int nents) -{ - unsigned i; - - if (!sg) - return; - for (i = 0; i < nents; i++) { - if (!sg_page(&sg[i])) - continue; - kfree(sg_virt(&sg[i])); - } - kfree(sg); -} - -static struct scatterlist * -alloc_sglist(int nents, int max, int vary) -{ - struct scatterlist *sg; - unsigned i; - unsigned size = max; - - sg = kmalloc_array(nents, sizeof *sg, GFP_KERNEL); - if (!sg) - return NULL; - sg_init_table(sg, nents); - - for (i = 0; i < nents; i++) { - char *buf; - unsigned j; - - buf = kzalloc(size, GFP_KERNEL); - if (!buf) { - free_sglist(sg, i); - return NULL; - } - - /* kmalloc pages are always physically contiguous! */ - sg_set_buf(&sg[i], buf, size); - - switch (pattern) { - case 0: - /* already zeroed */ - break; - case 1: - for (j = 0; j < size; j++) - *buf++ = (u8) (j % 63); - break; - } - - if (vary) { - size += vary; - size %= max; - if (size == 0) - size = (vary < max) ? vary : max; - } - } - - return sg; -} - -static int perform_sglist( - struct usbtest_dev *tdev, - unsigned iterations, - int pipe, - struct usb_sg_request *req, - struct scatterlist *sg, - int nents -) -{ - struct usb_device *udev = testdev_to_usbdev(tdev); - int retval = 0; - - while (retval == 0 && iterations-- > 0) { - retval = usb_sg_init(req, udev, pipe, - (udev->speed == USB_SPEED_HIGH) - ? (INTERRUPT_RATE << 3) - : INTERRUPT_RATE, - sg, nents, 0, GFP_KERNEL); - - if (retval) - break; - usb_sg_wait(req); - retval = req->status; - - /* FIXME check resulting data pattern */ - - /* FIXME if endpoint halted, clear halt (and log) */ - } - - /* FIXME for unlink or fault handling tests, don't report - * failure if retval is as we expected ... - */ - if (retval) - ERROR(tdev, "perform_sglist failed, " - "iterations left %d, status %d\n", - iterations, retval); - return retval; -} - - -/*-------------------------------------------------------------------------*/ - -/* unqueued control message testing - * - * there's a nice set of device functional requirements in chapter 9 of the - * usb 2.0 spec, which we can apply to ANY device, even ones that don't use - * special test firmware. - * - * we know the device is configured (or suspended) by the time it's visible - * through usbfs. we can't change that, so we won't test enumeration (which - * worked 'well enough' to get here, this time), power management (ditto), - * or remote wakeup (which needs human interaction). - */ - -static unsigned realworld = 1; -module_param(realworld, uint, 0); -MODULE_PARM_DESC(realworld, "clear to demand stricter spec compliance"); - -static int get_altsetting(struct usbtest_dev *dev) -{ - struct usb_interface *iface = dev->intf; - struct usb_device *udev = interface_to_usbdev(iface); - int retval; - - retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - USB_REQ_GET_INTERFACE, USB_DIR_IN|USB_RECIP_INTERFACE, - 0, iface->altsetting[0].desc.bInterfaceNumber, - dev->buf, 1, USB_CTRL_GET_TIMEOUT); - switch (retval) { - case 1: - return dev->buf[0]; - case 0: - retval = -ERANGE; - /* FALLTHROUGH */ - default: - return retval; - } -} - -static int set_altsetting(struct usbtest_dev *dev, int alternate) -{ - struct usb_interface *iface = dev->intf; - struct usb_device *udev; - - if (alternate < 0 || alternate >= 256) - return -EINVAL; - - udev = interface_to_usbdev(iface); - return usb_set_interface(udev, - iface->altsetting[0].desc.bInterfaceNumber, - alternate); -} - -static int is_good_config(struct usbtest_dev *tdev, int len) -{ - struct usb_config_descriptor *config; - - if (len < sizeof *config) - return 0; - config = (struct usb_config_descriptor *) tdev->buf; - - switch (config->bDescriptorType) { - case USB_DT_CONFIG: - case USB_DT_OTHER_SPEED_CONFIG: - if (config->bLength != 9) { - ERROR(tdev, "bogus config descriptor length\n"); - return 0; - } - /* this bit 'must be 1' but often isn't */ - if (!realworld && !(config->bmAttributes & 0x80)) { - ERROR(tdev, "high bit of config attributes not set\n"); - return 0; - } - if (config->bmAttributes & 0x1f) { /* reserved == 0 */ - ERROR(tdev, "reserved config bits set\n"); - return 0; - } - break; - default: - return 0; - } - - if (le16_to_cpu(config->wTotalLength) == len) /* read it all */ - return 1; - if (le16_to_cpu(config->wTotalLength) >= TBUF_SIZE) /* max partial read */ - return 1; - ERROR(tdev, "bogus config descriptor read size\n"); - return 0; -} - -/* sanity test for standard requests working with usb_control_mesg() and some - * of the utility functions which use it. - * - * this doesn't test how endpoint halts behave or data toggles get set, since - * we won't do I/O to bulk/interrupt endpoints here (which is how to change - * halt or toggle). toggle testing is impractical without support from hcds. - * - * this avoids failing devices linux would normally work with, by not testing - * config/altsetting operations for devices that only support their defaults. - * such devices rarely support those needless operations. - * - * NOTE that since this is a sanity test, it's not examining boundary cases - * to see if usbcore, hcd, and device all behave right. such testing would - * involve varied read sizes and other operation sequences. - */ -static int ch9_postconfig(struct usbtest_dev *dev) -{ - struct usb_interface *iface = dev->intf; - struct usb_device *udev = interface_to_usbdev(iface); - int i, alt, retval; - - /* [9.2.3] if there's more than one altsetting, we need to be able to - * set and get each one. mostly trusts the descriptors from usbcore. - */ - for (i = 0; i < iface->num_altsetting; i++) { - - /* 9.2.3 constrains the range here */ - alt = iface->altsetting[i].desc.bAlternateSetting; - if (alt < 0 || alt >= iface->num_altsetting) { - dev_err(&iface->dev, - "invalid alt [%d].bAltSetting = %d\n", - i, alt); - } - - /* [real world] get/set unimplemented if there's only one */ - if (realworld && iface->num_altsetting == 1) - continue; - - /* [9.4.10] set_interface */ - retval = set_altsetting(dev, alt); - if (retval) { - dev_err(&iface->dev, "can't set_interface = %d, %d\n", - alt, retval); - return retval; - } - - /* [9.4.4] get_interface always works */ - retval = get_altsetting(dev); - if (retval != alt) { - dev_err(&iface->dev, "get alt should be %d, was %d\n", - alt, retval); - return (retval < 0) ? retval : -EDOM; - } - - } - - /* [real world] get_config unimplemented if there's only one */ - if (!realworld || udev->descriptor.bNumConfigurations != 1) { - int expected = udev->actconfig->desc.bConfigurationValue; - - /* [9.4.2] get_configuration always works - * ... although some cheap devices (like one TI Hub I've got) - * won't return config descriptors except before set_config. - */ - retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - USB_REQ_GET_CONFIGURATION, - USB_DIR_IN | USB_RECIP_DEVICE, - 0, 0, dev->buf, 1, USB_CTRL_GET_TIMEOUT); - if (retval != 1 || dev->buf[0] != expected) { - dev_err(&iface->dev, "get config --> %d %d (1 %d)\n", - retval, dev->buf[0], expected); - return (retval < 0) ? retval : -EDOM; - } - } - - /* there's always [9.4.3] a device descriptor [9.6.1] */ - retval = usb_get_descriptor(udev, USB_DT_DEVICE, 0, - dev->buf, sizeof udev->descriptor); - if (retval != sizeof udev->descriptor) { - dev_err(&iface->dev, "dev descriptor --> %d\n", retval); - return (retval < 0) ? retval : -EDOM; - } - - /* there's always [9.4.3] at least one config descriptor [9.6.3] */ - for (i = 0; i < udev->descriptor.bNumConfigurations; i++) { - retval = usb_get_descriptor(udev, USB_DT_CONFIG, i, - dev->buf, TBUF_SIZE); - if (!is_good_config(dev, retval)) { - dev_err(&iface->dev, - "config [%d] descriptor --> %d\n", - i, retval); - return (retval < 0) ? retval : -EDOM; - } - - /* FIXME cross-checking udev->config[i] to make sure usbcore - * parsed it right (etc) would be good testing paranoia - */ - } - - /* and sometimes [9.2.6.6] speed dependent descriptors */ - if (le16_to_cpu(udev->descriptor.bcdUSB) == 0x0200) { - struct usb_qualifier_descriptor *d = NULL; - - /* device qualifier [9.6.2] */ - retval = usb_get_descriptor(udev, - USB_DT_DEVICE_QUALIFIER, 0, dev->buf, - sizeof(struct usb_qualifier_descriptor)); - if (retval == -EPIPE) { - if (udev->speed == USB_SPEED_HIGH) { - dev_err(&iface->dev, - "hs dev qualifier --> %d\n", - retval); - return (retval < 0) ? retval : -EDOM; - } - /* usb2.0 but not high-speed capable; fine */ - } else if (retval != sizeof(struct usb_qualifier_descriptor)) { - dev_err(&iface->dev, "dev qualifier --> %d\n", retval); - return (retval < 0) ? retval : -EDOM; - } else - d = (struct usb_qualifier_descriptor *) dev->buf; - - /* might not have [9.6.2] any other-speed configs [9.6.4] */ - if (d) { - unsigned max = d->bNumConfigurations; - for (i = 0; i < max; i++) { - retval = usb_get_descriptor(udev, - USB_DT_OTHER_SPEED_CONFIG, i, - dev->buf, TBUF_SIZE); - if (!is_good_config(dev, retval)) { - dev_err(&iface->dev, - "other speed config --> %d\n", - retval); - return (retval < 0) ? retval : -EDOM; - } - } - } - } - /* FIXME fetch strings from at least the device descriptor */ - - /* [9.4.5] get_status always works */ - retval = usb_get_status(udev, USB_RECIP_DEVICE, 0, dev->buf); - if (retval != 2) { - dev_err(&iface->dev, "get dev status --> %d\n", retval); - return (retval < 0) ? retval : -EDOM; - } - - /* FIXME configuration.bmAttributes says if we could try to set/clear - * the device's remote wakeup feature ... if we can, test that here - */ - - retval = usb_get_status(udev, USB_RECIP_INTERFACE, - iface->altsetting[0].desc.bInterfaceNumber, dev->buf); - if (retval != 2) { - dev_err(&iface->dev, "get interface status --> %d\n", retval); - return (retval < 0) ? retval : -EDOM; - } - /* FIXME get status for each endpoint in the interface */ - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* use ch9 requests to test whether: - * (a) queues work for control, keeping N subtests queued and - * active (auto-resubmit) for M loops through the queue. - * (b) protocol stalls (control-only) will autorecover. - * it's not like bulk/intr; no halt clearing. - * (c) short control reads are reported and handled. - * (d) queues are always processed in-order - */ - -struct ctrl_ctx { - spinlock_t lock; - struct usbtest_dev *dev; - struct completion complete; - unsigned count; - unsigned pending; - int status; - struct urb **urb; - struct usbtest_param *param; - int last; -}; - -#define NUM_SUBCASES 15 /* how many test subcases here? */ - -struct subcase { - struct usb_ctrlrequest setup; - int number; - int expected; -}; - -static void ctrl_complete(struct urb *urb) -{ - struct ctrl_ctx *ctx = urb->context; - struct usb_ctrlrequest *reqp; - struct subcase *subcase; - int status = urb->status; - - reqp = (struct usb_ctrlrequest *)urb->setup_packet; - subcase = container_of(reqp, struct subcase, setup); - - spin_lock(&ctx->lock); - ctx->count--; - ctx->pending--; - - /* queue must transfer and complete in fifo order, unless - * usb_unlink_urb() is used to unlink something not at the - * physical queue head (not tested). - */ - if (subcase->number > 0) { - if ((subcase->number - ctx->last) != 1) { - ERROR(ctx->dev, - "subcase %d completed out of order, last %d\n", - subcase->number, ctx->last); - status = -EDOM; - ctx->last = subcase->number; - goto error; - } - } - ctx->last = subcase->number; - - /* succeed or fault in only one way? */ - if (status == subcase->expected) - status = 0; - - /* async unlink for cleanup? */ - else if (status != -ECONNRESET) { - - /* some faults are allowed, not required */ - if (subcase->expected > 0 && ( - ((status == -subcase->expected /* happened */ - || status == 0)))) /* didn't */ - status = 0; - /* sometimes more than one fault is allowed */ - else if (subcase->number == 12 && status == -EPIPE) - status = 0; - else - ERROR(ctx->dev, "subtest %d error, status %d\n", - subcase->number, status); - } - - /* unexpected status codes mean errors; ideally, in hardware */ - if (status) { -error: - if (ctx->status == 0) { - int i; - - ctx->status = status; - ERROR(ctx->dev, "control queue %02x.%02x, err %d, " - "%d left, subcase %d, len %d/%d\n", - reqp->bRequestType, reqp->bRequest, - status, ctx->count, subcase->number, - urb->actual_length, - urb->transfer_buffer_length); - - /* FIXME this "unlink everything" exit route should - * be a separate test case. - */ - - /* unlink whatever's still pending */ - for (i = 1; i < ctx->param->sglen; i++) { - struct urb *u = ctx->urb[ - (i + subcase->number) - % ctx->param->sglen]; - - if (u == urb || !u->dev) - continue; - spin_unlock(&ctx->lock); - status = usb_unlink_urb(u); - spin_lock(&ctx->lock); - switch (status) { - case -EINPROGRESS: - case -EBUSY: - case -EIDRM: - continue; - default: - ERROR(ctx->dev, "urb unlink --> %d\n", - status); - } - } - status = ctx->status; - } - } - - /* resubmit if we need to, else mark this as done */ - if ((status == 0) && (ctx->pending < ctx->count)) { - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status != 0) { - ERROR(ctx->dev, - "can't resubmit ctrl %02x.%02x, err %d\n", - reqp->bRequestType, reqp->bRequest, status); - urb->dev = NULL; - } else - ctx->pending++; - } else - urb->dev = NULL; - - /* signal completion when nothing's queued */ - if (ctx->pending == 0) - complete(&ctx->complete); - spin_unlock(&ctx->lock); -} - -static int -test_ctrl_queue(struct usbtest_dev *dev, struct usbtest_param *param) -{ - struct usb_device *udev = testdev_to_usbdev(dev); - struct urb **urb; - struct ctrl_ctx context; - int i; - - if (param->sglen == 0 || param->iterations > UINT_MAX / param->sglen) - return -EOPNOTSUPP; - - spin_lock_init(&context.lock); - context.dev = dev; - init_completion(&context.complete); - context.count = param->sglen * param->iterations; - context.pending = 0; - context.status = -ENOMEM; - context.param = param; - context.last = -1; - - /* allocate and init the urbs we'll queue. - * as with bulk/intr sglists, sglen is the queue depth; it also - * controls which subtests run (more tests than sglen) or rerun. - */ - urb = kcalloc(param->sglen, sizeof(struct urb *), GFP_KERNEL); - if (!urb) - return -ENOMEM; - for (i = 0; i < param->sglen; i++) { - int pipe = usb_rcvctrlpipe(udev, 0); - unsigned len; - struct urb *u; - struct usb_ctrlrequest req; - struct subcase *reqp; - - /* sign of this variable means: - * -: tested code must return this (negative) error code - * +: tested code may return this (negative too) error code - */ - int expected = 0; - - /* requests here are mostly expected to succeed on any - * device, but some are chosen to trigger protocol stalls - * or short reads. - */ - memset(&req, 0, sizeof req); - req.bRequest = USB_REQ_GET_DESCRIPTOR; - req.bRequestType = USB_DIR_IN|USB_RECIP_DEVICE; - - switch (i % NUM_SUBCASES) { - case 0: /* get device descriptor */ - req.wValue = cpu_to_le16(USB_DT_DEVICE << 8); - len = sizeof(struct usb_device_descriptor); - break; - case 1: /* get first config descriptor (only) */ - req.wValue = cpu_to_le16((USB_DT_CONFIG << 8) | 0); - len = sizeof(struct usb_config_descriptor); - break; - case 2: /* get altsetting (OFTEN STALLS) */ - req.bRequest = USB_REQ_GET_INTERFACE; - req.bRequestType = USB_DIR_IN|USB_RECIP_INTERFACE; - /* index = 0 means first interface */ - len = 1; - expected = EPIPE; - break; - case 3: /* get interface status */ - req.bRequest = USB_REQ_GET_STATUS; - req.bRequestType = USB_DIR_IN|USB_RECIP_INTERFACE; - /* interface 0 */ - len = 2; - break; - case 4: /* get device status */ - req.bRequest = USB_REQ_GET_STATUS; - req.bRequestType = USB_DIR_IN|USB_RECIP_DEVICE; - len = 2; - break; - case 5: /* get device qualifier (MAY STALL) */ - req.wValue = cpu_to_le16 (USB_DT_DEVICE_QUALIFIER << 8); - len = sizeof(struct usb_qualifier_descriptor); - if (udev->speed != USB_SPEED_HIGH) - expected = EPIPE; - break; - case 6: /* get first config descriptor, plus interface */ - req.wValue = cpu_to_le16((USB_DT_CONFIG << 8) | 0); - len = sizeof(struct usb_config_descriptor); - len += sizeof(struct usb_interface_descriptor); - break; - case 7: /* get interface descriptor (ALWAYS STALLS) */ - req.wValue = cpu_to_le16 (USB_DT_INTERFACE << 8); - /* interface == 0 */ - len = sizeof(struct usb_interface_descriptor); - expected = -EPIPE; - break; - /* NOTE: two consecutive stalls in the queue here. - * that tests fault recovery a bit more aggressively. */ - case 8: /* clear endpoint halt (MAY STALL) */ - req.bRequest = USB_REQ_CLEAR_FEATURE; - req.bRequestType = USB_RECIP_ENDPOINT; - /* wValue 0 == ep halt */ - /* wIndex 0 == ep0 (shouldn't halt!) */ - len = 0; - pipe = usb_sndctrlpipe(udev, 0); - expected = EPIPE; - break; - case 9: /* get endpoint status */ - req.bRequest = USB_REQ_GET_STATUS; - req.bRequestType = USB_DIR_IN|USB_RECIP_ENDPOINT; - /* endpoint 0 */ - len = 2; - break; - case 10: /* trigger short read (EREMOTEIO) */ - req.wValue = cpu_to_le16((USB_DT_CONFIG << 8) | 0); - len = 1024; - expected = -EREMOTEIO; - break; - /* NOTE: two consecutive _different_ faults in the queue. */ - case 11: /* get endpoint descriptor (ALWAYS STALLS) */ - req.wValue = cpu_to_le16(USB_DT_ENDPOINT << 8); - /* endpoint == 0 */ - len = sizeof(struct usb_interface_descriptor); - expected = EPIPE; - break; - /* NOTE: sometimes even a third fault in the queue! */ - case 12: /* get string 0 descriptor (MAY STALL) */ - req.wValue = cpu_to_le16(USB_DT_STRING << 8); - /* string == 0, for language IDs */ - len = sizeof(struct usb_interface_descriptor); - /* may succeed when > 4 languages */ - expected = EREMOTEIO; /* or EPIPE, if no strings */ - break; - case 13: /* short read, resembling case 10 */ - req.wValue = cpu_to_le16((USB_DT_CONFIG << 8) | 0); - /* last data packet "should" be DATA1, not DATA0 */ - if (udev->speed == USB_SPEED_SUPER) - len = 1024 - 512; - else - len = 1024 - udev->descriptor.bMaxPacketSize0; - expected = -EREMOTEIO; - break; - case 14: /* short read; try to fill the last packet */ - req.wValue = cpu_to_le16((USB_DT_DEVICE << 8) | 0); - /* device descriptor size == 18 bytes */ - len = udev->descriptor.bMaxPacketSize0; - if (udev->speed == USB_SPEED_SUPER) - len = 512; - switch (len) { - case 8: - len = 24; - break; - case 16: - len = 32; - break; - } - expected = -EREMOTEIO; - break; - default: - ERROR(dev, "bogus number of ctrl queue testcases!\n"); - context.status = -EINVAL; - goto cleanup; - } - req.wLength = cpu_to_le16(len); - urb[i] = u = simple_alloc_urb(udev, pipe, len); - if (!u) - goto cleanup; - - reqp = kmalloc(sizeof *reqp, GFP_KERNEL); - if (!reqp) - goto cleanup; - reqp->setup = req; - reqp->number = i % NUM_SUBCASES; - reqp->expected = expected; - u->setup_packet = (char *) &reqp->setup; - - u->context = &context; - u->complete = ctrl_complete; - } - - /* queue the urbs */ - context.urb = urb; - spin_lock_irq(&context.lock); - for (i = 0; i < param->sglen; i++) { - context.status = usb_submit_urb(urb[i], GFP_ATOMIC); - if (context.status != 0) { - ERROR(dev, "can't submit urb[%d], status %d\n", - i, context.status); - context.count = context.pending; - break; - } - context.pending++; - } - spin_unlock_irq(&context.lock); - - /* FIXME set timer and time out; provide a disconnect hook */ - - /* wait for the last one to complete */ - if (context.pending > 0) - wait_for_completion(&context.complete); - -cleanup: - for (i = 0; i < param->sglen; i++) { - if (!urb[i]) - continue; - urb[i]->dev = udev; - kfree(urb[i]->setup_packet); - simple_free_urb(urb[i]); - } - kfree(urb); - return context.status; -} -#undef NUM_SUBCASES - - -/*-------------------------------------------------------------------------*/ - -static void unlink1_callback(struct urb *urb) -{ - int status = urb->status; - - /* we "know" -EPIPE (stall) never happens */ - if (!status) - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) { - urb->status = status; - complete(urb->context); - } -} - -static int unlink1(struct usbtest_dev *dev, int pipe, int size, int async) -{ - struct urb *urb; - struct completion completion; - int retval = 0; - - init_completion(&completion); - urb = simple_alloc_urb(testdev_to_usbdev(dev), pipe, size); - if (!urb) - return -ENOMEM; - urb->context = &completion; - urb->complete = unlink1_callback; - - /* keep the endpoint busy. there are lots of hc/hcd-internal - * states, and testing should get to all of them over time. - * - * FIXME want additional tests for when endpoint is STALLing - * due to errors, or is just NAKing requests. - */ - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval != 0) { - dev_err(&dev->intf->dev, "submit fail %d\n", retval); - return retval; - } - - /* unlinking that should always work. variable delay tests more - * hcd states and code paths, even with little other system load. - */ - msleep(jiffies % (2 * INTERRUPT_RATE)); - if (async) { - 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); - - wait_for_completion(&completion); - retval = urb->status; - simple_free_urb(urb); - - if (async) - return (retval == -ECONNRESET) ? 0 : retval - 1000; - else - return (retval == -ENOENT || retval == -EPERM) ? - 0 : retval - 2000; -} - -static int unlink_simple(struct usbtest_dev *dev, int pipe, int len) -{ - int retval = 0; - - /* test sync and async paths */ - retval = unlink1(dev, pipe, len, 1); - if (!retval) - retval = unlink1(dev, pipe, len, 0); - return retval; -} - -/*-------------------------------------------------------------------------*/ - -struct queued_ctx { - struct completion complete; - atomic_t pending; - unsigned num; - int status; - struct urb **urbs; -}; - -static void unlink_queued_callback(struct urb *urb) -{ - int status = urb->status; - struct queued_ctx *ctx = urb->context; - - if (ctx->status) - goto done; - if (urb == ctx->urbs[ctx->num - 4] || urb == ctx->urbs[ctx->num - 2]) { - if (status == -ECONNRESET) - goto done; - /* What error should we report if the URB completed normally? */ - } - if (status != 0) - ctx->status = status; - - done: - if (atomic_dec_and_test(&ctx->pending)) - complete(&ctx->complete); -} - -static int unlink_queued(struct usbtest_dev *dev, int pipe, unsigned num, - unsigned size) -{ - struct queued_ctx ctx; - struct usb_device *udev = testdev_to_usbdev(dev); - void *buf; - dma_addr_t buf_dma; - int i; - int retval = -ENOMEM; - - init_completion(&ctx.complete); - atomic_set(&ctx.pending, 1); /* One more than the actual value */ - ctx.num = num; - ctx.status = 0; - - buf = usb_alloc_coherent(udev, size, GFP_KERNEL, &buf_dma); - if (!buf) - return retval; - memset(buf, 0, size); - - /* Allocate and init the urbs we'll queue */ - ctx.urbs = kcalloc(num, sizeof(struct urb *), GFP_KERNEL); - if (!ctx.urbs) - goto free_buf; - for (i = 0; i < num; i++) { - ctx.urbs[i] = usb_alloc_urb(0, GFP_KERNEL); - if (!ctx.urbs[i]) - goto free_urbs; - usb_fill_bulk_urb(ctx.urbs[i], udev, pipe, buf, size, - unlink_queued_callback, &ctx); - ctx.urbs[i]->transfer_dma = buf_dma; - ctx.urbs[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; - } - - /* Submit all the URBs and then unlink URBs num - 4 and num - 2. */ - for (i = 0; i < num; i++) { - atomic_inc(&ctx.pending); - retval = usb_submit_urb(ctx.urbs[i], GFP_KERNEL); - if (retval != 0) { - dev_err(&dev->intf->dev, "submit urbs[%d] fail %d\n", - i, retval); - atomic_dec(&ctx.pending); - ctx.status = retval; - break; - } - } - if (i == num) { - usb_unlink_urb(ctx.urbs[num - 4]); - usb_unlink_urb(ctx.urbs[num - 2]); - } else { - while (--i >= 0) - usb_unlink_urb(ctx.urbs[i]); - } - - if (atomic_dec_and_test(&ctx.pending)) /* The extra count */ - complete(&ctx.complete); - wait_for_completion(&ctx.complete); - retval = ctx.status; - - free_urbs: - for (i = 0; i < num; i++) - usb_free_urb(ctx.urbs[i]); - kfree(ctx.urbs); - free_buf: - usb_free_coherent(udev, size, buf, buf_dma); - return retval; -} - -/*-------------------------------------------------------------------------*/ - -static int verify_not_halted(struct usbtest_dev *tdev, int ep, struct urb *urb) -{ - int retval; - u16 status; - - /* shouldn't look or act halted */ - retval = usb_get_status(urb->dev, USB_RECIP_ENDPOINT, ep, &status); - if (retval < 0) { - ERROR(tdev, "ep %02x couldn't get no-halt status, %d\n", - ep, retval); - return retval; - } - if (status != 0) { - ERROR(tdev, "ep %02x bogus status: %04x != 0\n", ep, status); - return -EINVAL; - } - retval = simple_io(tdev, urb, 1, 0, 0, __func__); - if (retval != 0) - return -EINVAL; - return 0; -} - -static int verify_halted(struct usbtest_dev *tdev, int ep, struct urb *urb) -{ - int retval; - u16 status; - - /* should look and act halted */ - retval = usb_get_status(urb->dev, USB_RECIP_ENDPOINT, ep, &status); - if (retval < 0) { - ERROR(tdev, "ep %02x couldn't get halt status, %d\n", - ep, retval); - return retval; - } - le16_to_cpus(&status); - if (status != 1) { - ERROR(tdev, "ep %02x bogus status: %04x != 1\n", ep, status); - return -EINVAL; - } - retval = simple_io(tdev, urb, 1, 0, -EPIPE, __func__); - if (retval != -EPIPE) - return -EINVAL; - retval = simple_io(tdev, urb, 1, 0, -EPIPE, "verify_still_halted"); - if (retval != -EPIPE) - return -EINVAL; - return 0; -} - -static int test_halt(struct usbtest_dev *tdev, int ep, struct urb *urb) -{ - int retval; - - /* shouldn't look or act halted now */ - retval = verify_not_halted(tdev, ep, urb); - if (retval < 0) - return retval; - - /* set halt (protocol test only), verify it worked */ - retval = usb_control_msg(urb->dev, usb_sndctrlpipe(urb->dev, 0), - USB_REQ_SET_FEATURE, USB_RECIP_ENDPOINT, - USB_ENDPOINT_HALT, ep, - NULL, 0, USB_CTRL_SET_TIMEOUT); - if (retval < 0) { - ERROR(tdev, "ep %02x couldn't set halt, %d\n", ep, retval); - return retval; - } - retval = verify_halted(tdev, ep, urb); - if (retval < 0) - return retval; - - /* clear halt (tests API + protocol), verify it worked */ - retval = usb_clear_halt(urb->dev, urb->pipe); - if (retval < 0) { - ERROR(tdev, "ep %02x couldn't clear halt, %d\n", ep, retval); - return retval; - } - retval = verify_not_halted(tdev, ep, urb); - if (retval < 0) - return retval; - - /* NOTE: could also verify SET_INTERFACE clear halts ... */ - - return 0; -} - -static int halt_simple(struct usbtest_dev *dev) -{ - int ep; - int retval = 0; - struct urb *urb; - struct usb_device *udev = testdev_to_usbdev(dev); - - if (udev->speed == USB_SPEED_SUPER) - urb = simple_alloc_urb(udev, 0, 1024); - else - urb = simple_alloc_urb(udev, 0, 512); - if (urb == NULL) - return -ENOMEM; - - if (dev->in_pipe) { - ep = usb_pipeendpoint(dev->in_pipe) | USB_DIR_IN; - urb->pipe = dev->in_pipe; - retval = test_halt(dev, ep, urb); - if (retval < 0) - goto done; - } - - if (dev->out_pipe) { - ep = usb_pipeendpoint(dev->out_pipe); - urb->pipe = dev->out_pipe; - retval = test_halt(dev, ep, urb); - } -done: - simple_free_urb(urb); - return retval; -} - -/*-------------------------------------------------------------------------*/ - -/* Control OUT tests use the vendor control requests from Intel's - * USB 2.0 compliance test device: write a buffer, read it back. - * - * Intel's spec only _requires_ that it work for one packet, which - * is pretty weak. Some HCDs place limits here; most devices will - * need to be able to handle more than one OUT data packet. We'll - * try whatever we're told to try. - */ -static int ctrl_out(struct usbtest_dev *dev, - unsigned count, unsigned length, unsigned vary, unsigned offset) -{ - unsigned i, j, len; - int retval; - u8 *buf; - char *what = "?"; - struct usb_device *udev; - - if (length < 1 || length > 0xffff || vary >= length) - return -EINVAL; - - buf = kmalloc(length + offset, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - buf += offset; - udev = testdev_to_usbdev(dev); - len = length; - retval = 0; - - /* NOTE: hardware might well act differently if we pushed it - * with lots back-to-back queued requests. - */ - for (i = 0; i < count; i++) { - /* write patterned data */ - for (j = 0; j < len; j++) - buf[j] = i + j; - retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0x5b, USB_DIR_OUT|USB_TYPE_VENDOR, - 0, 0, buf, len, USB_CTRL_SET_TIMEOUT); - if (retval != len) { - what = "write"; - if (retval >= 0) { - ERROR(dev, "ctrl_out, wlen %d (expected %d)\n", - retval, len); - retval = -EBADMSG; - } - break; - } - - /* read it back -- assuming nothing intervened!! */ - retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - 0x5c, USB_DIR_IN|USB_TYPE_VENDOR, - 0, 0, buf, len, USB_CTRL_GET_TIMEOUT); - if (retval != len) { - what = "read"; - if (retval >= 0) { - ERROR(dev, "ctrl_out, rlen %d (expected %d)\n", - retval, len); - retval = -EBADMSG; - } - break; - } - - /* fail if we can't verify */ - for (j = 0; j < len; j++) { - if (buf[j] != (u8) (i + j)) { - ERROR(dev, "ctrl_out, byte %d is %d not %d\n", - j, buf[j], (u8) i + j); - retval = -EBADMSG; - break; - } - } - if (retval < 0) { - what = "verify"; - break; - } - - len += vary; - - /* [real world] the "zero bytes IN" case isn't really used. - * hardware can easily trip up in this weird case, since its - * status stage is IN, not OUT like other ep0in transfers. - */ - if (len > length) - len = realworld ? 1 : 0; - } - - if (retval < 0) - ERROR(dev, "ctrl_out %s failed, code %d, count %d\n", - what, retval, i); - - kfree(buf - offset); - return retval; -} - -/*-------------------------------------------------------------------------*/ - -/* ISO tests ... mimics common usage - * - buffer length is split into N packets (mostly maxpacket sized) - * - multi-buffers according to sglen - */ - -struct iso_context { - unsigned count; - unsigned pending; - spinlock_t lock; - struct completion done; - int submit_error; - unsigned long errors; - unsigned long packet_count; - struct usbtest_dev *dev; -}; - -static void iso_callback(struct urb *urb) -{ - struct iso_context *ctx = urb->context; - - spin_lock(&ctx->lock); - ctx->count--; - - ctx->packet_count += urb->number_of_packets; - if (urb->error_count > 0) - ctx->errors += urb->error_count; - else if (urb->status != 0) - ctx->errors += urb->number_of_packets; - else if (urb->actual_length != urb->transfer_buffer_length) - ctx->errors++; - else if (check_guard_bytes(ctx->dev, urb) != 0) - ctx->errors++; - - if (urb->status == 0 && ctx->count > (ctx->pending - 1) - && !ctx->submit_error) { - int status = usb_submit_urb(urb, GFP_ATOMIC); - switch (status) { - case 0: - goto done; - default: - dev_err(&ctx->dev->intf->dev, - "iso resubmit err %d\n", - status); - /* FALLTHROUGH */ - case -ENODEV: /* disconnected */ - case -ESHUTDOWN: /* endpoint disabled */ - ctx->submit_error = 1; - break; - } - } - - ctx->pending--; - if (ctx->pending == 0) { - if (ctx->errors) - dev_err(&ctx->dev->intf->dev, - "iso test, %lu errors out of %lu\n", - ctx->errors, ctx->packet_count); - complete(&ctx->done); - } -done: - spin_unlock(&ctx->lock); -} - -static struct urb *iso_alloc_urb( - struct usb_device *udev, - int pipe, - struct usb_endpoint_descriptor *desc, - long bytes, - unsigned offset -) -{ - struct urb *urb; - unsigned i, maxp, packets; - - if (bytes < 0 || !desc) - return NULL; - maxp = 0x7ff & usb_endpoint_maxp(desc); - maxp *= 1 + (0x3 & (usb_endpoint_maxp(desc) >> 11)); - packets = DIV_ROUND_UP(bytes, maxp); - - urb = usb_alloc_urb(packets, GFP_KERNEL); - if (!urb) - return urb; - urb->dev = udev; - urb->pipe = pipe; - - urb->number_of_packets = packets; - urb->transfer_buffer_length = bytes; - urb->transfer_buffer = usb_alloc_coherent(udev, bytes + offset, - GFP_KERNEL, - &urb->transfer_dma); - if (!urb->transfer_buffer) { - usb_free_urb(urb); - return NULL; - } - if (offset) { - memset(urb->transfer_buffer, GUARD_BYTE, offset); - urb->transfer_buffer += offset; - urb->transfer_dma += offset; - } - /* For inbound transfers use guard byte so that test fails if - data not correctly copied */ - memset(urb->transfer_buffer, - usb_pipein(urb->pipe) ? GUARD_BYTE : 0, - bytes); - - for (i = 0; i < packets; i++) { - /* here, only the last packet will be short */ - urb->iso_frame_desc[i].length = min((unsigned) bytes, maxp); - bytes -= urb->iso_frame_desc[i].length; - - urb->iso_frame_desc[i].offset = maxp * i; - } - - urb->complete = iso_callback; - /* urb->context = SET BY CALLER */ - urb->interval = 1 << (desc->bInterval - 1); - urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - return urb; -} - -static int -test_iso_queue(struct usbtest_dev *dev, struct usbtest_param *param, - int pipe, struct usb_endpoint_descriptor *desc, unsigned offset) -{ - struct iso_context context; - struct usb_device *udev; - unsigned i; - unsigned long packets = 0; - int status = 0; - struct urb *urbs[10]; /* FIXME no limit */ - - if (param->sglen > 10) - return -EDOM; - - memset(&context, 0, sizeof context); - context.count = param->iterations * param->sglen; - context.dev = dev; - init_completion(&context.done); - spin_lock_init(&context.lock); - - memset(urbs, 0, sizeof urbs); - udev = testdev_to_usbdev(dev); - dev_info(&dev->intf->dev, - "... iso period %d %sframes, wMaxPacket %04x\n", - 1 << (desc->bInterval - 1), - (udev->speed == USB_SPEED_HIGH) ? "micro" : "", - usb_endpoint_maxp(desc)); - - for (i = 0; i < param->sglen; i++) { - urbs[i] = iso_alloc_urb(udev, pipe, desc, - param->length, offset); - if (!urbs[i]) { - status = -ENOMEM; - goto fail; - } - packets += urbs[i]->number_of_packets; - urbs[i]->context = &context; - } - packets *= param->iterations; - dev_info(&dev->intf->dev, - "... total %lu msec (%lu packets)\n", - (packets * (1 << (desc->bInterval - 1))) - / ((udev->speed == USB_SPEED_HIGH) ? 8 : 1), - packets); - - spin_lock_irq(&context.lock); - for (i = 0; i < param->sglen; i++) { - ++context.pending; - status = usb_submit_urb(urbs[i], GFP_ATOMIC); - if (status < 0) { - ERROR(dev, "submit iso[%d], error %d\n", i, status); - if (i == 0) { - spin_unlock_irq(&context.lock); - goto fail; - } - - simple_free_urb(urbs[i]); - urbs[i] = NULL; - context.pending--; - context.submit_error = 1; - break; - } - } - spin_unlock_irq(&context.lock); - - wait_for_completion(&context.done); - - for (i = 0; i < param->sglen; i++) { - if (urbs[i]) - simple_free_urb(urbs[i]); - } - /* - * Isochronous transfers are expected to fail sometimes. As an - * arbitrary limit, we will report an error if any submissions - * fail or if the transfer failure rate is > 10%. - */ - if (status != 0) - ; - else if (context.submit_error) - status = -EACCES; - else if (context.errors > context.packet_count / 10) - status = -EIO; - return status; - -fail: - for (i = 0; i < param->sglen; i++) { - if (urbs[i]) - simple_free_urb(urbs[i]); - } - return status; -} - -static int test_unaligned_bulk( - struct usbtest_dev *tdev, - int pipe, - unsigned length, - int iterations, - unsigned transfer_flags, - const char *label) -{ - int retval; - struct urb *urb = usbtest_alloc_urb( - testdev_to_usbdev(tdev), pipe, length, transfer_flags, 1); - - if (!urb) - return -ENOMEM; - - retval = simple_io(tdev, urb, iterations, 0, 0, label); - simple_free_urb(urb); - return retval; -} - -/*-------------------------------------------------------------------------*/ - -/* We only have this one interface to user space, through usbfs. - * User mode code can scan usbfs to find N different devices (maybe on - * different busses) to use when testing, and allocate one thread per - * test. So discovery is simplified, and we have no device naming issues. - * - * Don't use these only as stress/load tests. Use them along with with - * other USB bus activity: plugging, unplugging, mousing, mp3 playback, - * video capture, and so on. Run different tests at different times, in - * different sequences. Nothing here should interact with other devices, - * except indirectly by consuming USB bandwidth and CPU resources for test - * threads and request completion. But the only way to know that for sure - * is to test when HC queues are in use by many devices. - * - * WARNING: Because usbfs grabs udev->dev.sem before calling this ioctl(), - * it locks out usbcore in certain code paths. Notably, if you disconnect - * the device-under-test, khubd will wait block forever waiting for the - * ioctl to complete ... so that usb_disconnect() can abort the pending - * urbs and then call usbtest_disconnect(). To abort a test, you're best - * off just killing the userspace task and waiting for it to exit. - */ - -static int -usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf) -{ - struct usbtest_dev *dev = usb_get_intfdata(intf); - struct usb_device *udev = testdev_to_usbdev(dev); - struct usbtest_param *param = buf; - int retval = -EOPNOTSUPP; - struct urb *urb; - struct scatterlist *sg; - struct usb_sg_request req; - struct timeval start; - unsigned i; - - /* FIXME USBDEVFS_CONNECTINFO doesn't say how fast the device is. */ - - pattern = mod_pattern; - - if (code != USBTEST_REQUEST) - return -EOPNOTSUPP; - - if (param->iterations <= 0) - return -EINVAL; - - if (mutex_lock_interruptible(&dev->lock)) - return -ERESTARTSYS; - - /* FIXME: What if a system sleep starts while a test is running? */ - - /* some devices, like ez-usb default devices, need a non-default - * altsetting to have any active endpoints. some tests change - * altsettings; force a default so most tests don't need to check. - */ - if (dev->info->alt >= 0) { - int res; - - if (intf->altsetting->desc.bInterfaceNumber) { - mutex_unlock(&dev->lock); - return -ENODEV; - } - res = set_altsetting(dev, dev->info->alt); - if (res) { - dev_err(&intf->dev, - "set altsetting to %d failed, %d\n", - dev->info->alt, res); - mutex_unlock(&dev->lock); - return res; - } - } - - /* - * Just a bunch of test cases that every HCD is expected to handle. - * - * Some may need specific firmware, though it'd be good to have - * one firmware image to handle all the test cases. - * - * FIXME add more tests! cancel requests, verify the data, control - * queueing, concurrent read+write threads, and so on. - */ - do_gettimeofday(&start); - switch (param->test_num) { - - case 0: - dev_info(&intf->dev, "TEST 0: NOP\n"); - retval = 0; - break; - - /* Simple non-queued bulk I/O tests */ - case 1: - if (dev->out_pipe == 0) - break; - dev_info(&intf->dev, - "TEST 1: write %d bytes %u times\n", - param->length, param->iterations); - urb = simple_alloc_urb(udev, dev->out_pipe, param->length); - if (!urb) { - retval = -ENOMEM; - break; - } - /* FIRMWARE: bulk sink (maybe accepts short writes) */ - retval = simple_io(dev, urb, param->iterations, 0, 0, "test1"); - simple_free_urb(urb); - break; - case 2: - if (dev->in_pipe == 0) - break; - dev_info(&intf->dev, - "TEST 2: read %d bytes %u times\n", - param->length, param->iterations); - urb = simple_alloc_urb(udev, dev->in_pipe, param->length); - if (!urb) { - retval = -ENOMEM; - break; - } - /* FIRMWARE: bulk source (maybe generates short writes) */ - retval = simple_io(dev, urb, param->iterations, 0, 0, "test2"); - simple_free_urb(urb); - break; - case 3: - if (dev->out_pipe == 0 || param->vary == 0) - break; - dev_info(&intf->dev, - "TEST 3: write/%d 0..%d bytes %u times\n", - param->vary, param->length, param->iterations); - urb = simple_alloc_urb(udev, dev->out_pipe, param->length); - if (!urb) { - retval = -ENOMEM; - break; - } - /* FIRMWARE: bulk sink (maybe accepts short writes) */ - retval = simple_io(dev, urb, param->iterations, param->vary, - 0, "test3"); - simple_free_urb(urb); - break; - case 4: - if (dev->in_pipe == 0 || param->vary == 0) - break; - dev_info(&intf->dev, - "TEST 4: read/%d 0..%d bytes %u times\n", - param->vary, param->length, param->iterations); - urb = simple_alloc_urb(udev, dev->in_pipe, param->length); - if (!urb) { - retval = -ENOMEM; - break; - } - /* FIRMWARE: bulk source (maybe generates short writes) */ - retval = simple_io(dev, urb, param->iterations, param->vary, - 0, "test4"); - simple_free_urb(urb); - break; - - /* Queued bulk I/O tests */ - case 5: - if (dev->out_pipe == 0 || param->sglen == 0) - break; - dev_info(&intf->dev, - "TEST 5: write %d sglists %d entries of %d bytes\n", - param->iterations, - param->sglen, param->length); - sg = alloc_sglist(param->sglen, param->length, 0); - if (!sg) { - retval = -ENOMEM; - break; - } - /* FIRMWARE: bulk sink (maybe accepts short writes) */ - retval = perform_sglist(dev, param->iterations, dev->out_pipe, - &req, sg, param->sglen); - free_sglist(sg, param->sglen); - break; - - case 6: - if (dev->in_pipe == 0 || param->sglen == 0) - break; - dev_info(&intf->dev, - "TEST 6: read %d sglists %d entries of %d bytes\n", - param->iterations, - param->sglen, param->length); - sg = alloc_sglist(param->sglen, param->length, 0); - if (!sg) { - retval = -ENOMEM; - break; - } - /* FIRMWARE: bulk source (maybe generates short writes) */ - retval = perform_sglist(dev, param->iterations, dev->in_pipe, - &req, sg, param->sglen); - free_sglist(sg, param->sglen); - break; - case 7: - if (dev->out_pipe == 0 || param->sglen == 0 || param->vary == 0) - break; - dev_info(&intf->dev, - "TEST 7: write/%d %d sglists %d entries 0..%d bytes\n", - param->vary, param->iterations, - param->sglen, param->length); - sg = alloc_sglist(param->sglen, param->length, param->vary); - if (!sg) { - retval = -ENOMEM; - break; - } - /* FIRMWARE: bulk sink (maybe accepts short writes) */ - retval = perform_sglist(dev, param->iterations, dev->out_pipe, - &req, sg, param->sglen); - free_sglist(sg, param->sglen); - break; - case 8: - if (dev->in_pipe == 0 || param->sglen == 0 || param->vary == 0) - break; - dev_info(&intf->dev, - "TEST 8: read/%d %d sglists %d entries 0..%d bytes\n", - param->vary, param->iterations, - param->sglen, param->length); - sg = alloc_sglist(param->sglen, param->length, param->vary); - if (!sg) { - retval = -ENOMEM; - break; - } - /* FIRMWARE: bulk source (maybe generates short writes) */ - retval = perform_sglist(dev, param->iterations, dev->in_pipe, - &req, sg, param->sglen); - free_sglist(sg, param->sglen); - break; - - /* non-queued sanity tests for control (chapter 9 subset) */ - case 9: - retval = 0; - dev_info(&intf->dev, - "TEST 9: ch9 (subset) control tests, %d times\n", - param->iterations); - for (i = param->iterations; retval == 0 && i--; /* NOP */) - retval = ch9_postconfig(dev); - if (retval) - dev_err(&intf->dev, "ch9 subset failed, " - "iterations left %d\n", i); - break; - - /* queued control messaging */ - case 10: - retval = 0; - dev_info(&intf->dev, - "TEST 10: queue %d control calls, %d times\n", - param->sglen, - param->iterations); - retval = test_ctrl_queue(dev, param); - break; - - /* simple non-queued unlinks (ring with one urb) */ - case 11: - if (dev->in_pipe == 0 || !param->length) - break; - retval = 0; - dev_info(&intf->dev, "TEST 11: unlink %d reads of %d\n", - param->iterations, param->length); - for (i = param->iterations; retval == 0 && i--; /* NOP */) - retval = unlink_simple(dev, dev->in_pipe, - param->length); - if (retval) - dev_err(&intf->dev, "unlink reads failed %d, " - "iterations left %d\n", retval, i); - break; - case 12: - if (dev->out_pipe == 0 || !param->length) - break; - retval = 0; - dev_info(&intf->dev, "TEST 12: unlink %d writes of %d\n", - param->iterations, param->length); - for (i = param->iterations; retval == 0 && i--; /* NOP */) - retval = unlink_simple(dev, dev->out_pipe, - param->length); - if (retval) - dev_err(&intf->dev, "unlink writes failed %d, " - "iterations left %d\n", retval, i); - break; - - /* ep halt tests */ - case 13: - if (dev->out_pipe == 0 && dev->in_pipe == 0) - break; - retval = 0; - dev_info(&intf->dev, "TEST 13: set/clear %d halts\n", - param->iterations); - for (i = param->iterations; retval == 0 && i--; /* NOP */) - retval = halt_simple(dev); - - if (retval) - ERROR(dev, "halts failed, iterations left %d\n", i); - break; - - /* control write tests */ - case 14: - if (!dev->info->ctrl_out) - break; - dev_info(&intf->dev, "TEST 14: %d ep0out, %d..%d vary %d\n", - param->iterations, - realworld ? 1 : 0, param->length, - param->vary); - retval = ctrl_out(dev, param->iterations, - param->length, param->vary, 0); - break; - - /* iso write tests */ - case 15: - if (dev->out_iso_pipe == 0 || param->sglen == 0) - break; - dev_info(&intf->dev, - "TEST 15: write %d iso, %d entries of %d bytes\n", - param->iterations, - param->sglen, param->length); - /* FIRMWARE: iso sink */ - retval = test_iso_queue(dev, param, - dev->out_iso_pipe, dev->iso_out, 0); - break; - - /* iso read tests */ - case 16: - if (dev->in_iso_pipe == 0 || param->sglen == 0) - break; - dev_info(&intf->dev, - "TEST 16: read %d iso, %d entries of %d bytes\n", - param->iterations, - param->sglen, param->length); - /* FIRMWARE: iso source */ - retval = test_iso_queue(dev, param, - dev->in_iso_pipe, dev->iso_in, 0); - break; - - /* FIXME scatterlist cancel (needs helper thread) */ - - /* Tests for bulk I/O using DMA mapping by core and odd address */ - case 17: - if (dev->out_pipe == 0) - break; - dev_info(&intf->dev, - "TEST 17: write odd addr %d bytes %u times core map\n", - param->length, param->iterations); - - retval = test_unaligned_bulk( - dev, dev->out_pipe, - param->length, param->iterations, - 0, "test17"); - break; - - case 18: - if (dev->in_pipe == 0) - break; - dev_info(&intf->dev, - "TEST 18: read odd addr %d bytes %u times core map\n", - param->length, param->iterations); - - retval = test_unaligned_bulk( - dev, dev->in_pipe, - param->length, param->iterations, - 0, "test18"); - break; - - /* Tests for bulk I/O using premapped coherent buffer and odd address */ - case 19: - if (dev->out_pipe == 0) - break; - dev_info(&intf->dev, - "TEST 19: write odd addr %d bytes %u times premapped\n", - param->length, param->iterations); - - retval = test_unaligned_bulk( - dev, dev->out_pipe, - param->length, param->iterations, - URB_NO_TRANSFER_DMA_MAP, "test19"); - break; - - case 20: - if (dev->in_pipe == 0) - break; - dev_info(&intf->dev, - "TEST 20: read odd addr %d bytes %u times premapped\n", - param->length, param->iterations); - - retval = test_unaligned_bulk( - dev, dev->in_pipe, - param->length, param->iterations, - URB_NO_TRANSFER_DMA_MAP, "test20"); - break; - - /* control write tests with unaligned buffer */ - case 21: - if (!dev->info->ctrl_out) - break; - dev_info(&intf->dev, - "TEST 21: %d ep0out odd addr, %d..%d vary %d\n", - param->iterations, - realworld ? 1 : 0, param->length, - param->vary); - retval = ctrl_out(dev, param->iterations, - param->length, param->vary, 1); - break; - - /* unaligned iso tests */ - case 22: - if (dev->out_iso_pipe == 0 || param->sglen == 0) - break; - dev_info(&intf->dev, - "TEST 22: write %d iso odd, %d entries of %d bytes\n", - param->iterations, - param->sglen, param->length); - retval = test_iso_queue(dev, param, - dev->out_iso_pipe, dev->iso_out, 1); - break; - - case 23: - if (dev->in_iso_pipe == 0 || param->sglen == 0) - break; - dev_info(&intf->dev, - "TEST 23: read %d iso odd, %d entries of %d bytes\n", - param->iterations, - param->sglen, param->length); - retval = test_iso_queue(dev, param, - dev->in_iso_pipe, dev->iso_in, 1); - break; - - /* unlink URBs from a bulk-OUT queue */ - case 24: - if (dev->out_pipe == 0 || !param->length || param->sglen < 4) - break; - retval = 0; - dev_info(&intf->dev, "TEST 17: unlink from %d queues of " - "%d %d-byte writes\n", - param->iterations, param->sglen, param->length); - for (i = param->iterations; retval == 0 && i > 0; --i) { - retval = unlink_queued(dev, dev->out_pipe, - param->sglen, param->length); - if (retval) { - dev_err(&intf->dev, - "unlink queued writes failed %d, " - "iterations left %d\n", retval, i); - break; - } - } - break; - - } - do_gettimeofday(¶m->duration); - param->duration.tv_sec -= start.tv_sec; - param->duration.tv_usec -= start.tv_usec; - if (param->duration.tv_usec < 0) { - param->duration.tv_usec += 1000 * 1000; - param->duration.tv_sec -= 1; - } - mutex_unlock(&dev->lock); - return retval; -} - -/*-------------------------------------------------------------------------*/ - -static unsigned force_interrupt; -module_param(force_interrupt, uint, 0); -MODULE_PARM_DESC(force_interrupt, "0 = test default; else interrupt"); - -#ifdef GENERIC -static unsigned short vendor; -module_param(vendor, ushort, 0); -MODULE_PARM_DESC(vendor, "vendor code (from usb-if)"); - -static unsigned short product; -module_param(product, ushort, 0); -MODULE_PARM_DESC(product, "product code (from vendor)"); -#endif - -static int -usbtest_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_device *udev; - struct usbtest_dev *dev; - struct usbtest_info *info; - char *rtest, *wtest; - char *irtest, *iwtest; - - udev = interface_to_usbdev(intf); - -#ifdef GENERIC - /* specify devices by module parameters? */ - if (id->match_flags == 0) { - /* vendor match required, product match optional */ - if (!vendor || le16_to_cpu(udev->descriptor.idVendor) != (u16)vendor) - return -ENODEV; - if (product && le16_to_cpu(udev->descriptor.idProduct) != (u16)product) - return -ENODEV; - dev_info(&intf->dev, "matched module params, " - "vend=0x%04x prod=0x%04x\n", - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct)); - } -#endif - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - info = (struct usbtest_info *) id->driver_info; - dev->info = info; - mutex_init(&dev->lock); - - dev->intf = intf; - - /* cacheline-aligned scratch for i/o */ - dev->buf = kmalloc(TBUF_SIZE, GFP_KERNEL); - if (dev->buf == NULL) { - kfree(dev); - return -ENOMEM; - } - - /* NOTE this doesn't yet test the handful of difference that are - * visible with high speed interrupts: bigger maxpacket (1K) and - * "high bandwidth" modes (up to 3 packets/uframe). - */ - rtest = wtest = ""; - irtest = iwtest = ""; - if (force_interrupt || udev->speed == USB_SPEED_LOW) { - if (info->ep_in) { - dev->in_pipe = usb_rcvintpipe(udev, info->ep_in); - rtest = " intr-in"; - } - if (info->ep_out) { - dev->out_pipe = usb_sndintpipe(udev, info->ep_out); - wtest = " intr-out"; - } - } else { - if (info->autoconf) { - int status; - - status = get_endpoints(dev, intf); - if (status < 0) { - WARNING(dev, "couldn't get endpoints, %d\n", - status); - kfree(dev->buf); - kfree(dev); - return status; - } - /* may find bulk or ISO pipes */ - } else { - if (info->ep_in) - dev->in_pipe = usb_rcvbulkpipe(udev, - info->ep_in); - if (info->ep_out) - dev->out_pipe = usb_sndbulkpipe(udev, - info->ep_out); - } - if (dev->in_pipe) - rtest = " bulk-in"; - if (dev->out_pipe) - wtest = " bulk-out"; - if (dev->in_iso_pipe) - irtest = " iso-in"; - if (dev->out_iso_pipe) - iwtest = " iso-out"; - } - - usb_set_intfdata(intf, dev); - dev_info(&intf->dev, "%s\n", info->name); - dev_info(&intf->dev, "%s {control%s%s%s%s%s} tests%s\n", - usb_speed_string(udev->speed), - info->ctrl_out ? " in/out" : "", - rtest, wtest, - irtest, iwtest, - info->alt >= 0 ? " (+alt)" : ""); - return 0; -} - -static int usbtest_suspend(struct usb_interface *intf, pm_message_t message) -{ - return 0; -} - -static int usbtest_resume(struct usb_interface *intf) -{ - return 0; -} - - -static void usbtest_disconnect(struct usb_interface *intf) -{ - struct usbtest_dev *dev = usb_get_intfdata(intf); - - usb_set_intfdata(intf, NULL); - dev_dbg(&intf->dev, "disconnect\n"); - kfree(dev); -} - -/* Basic testing only needs a device that can source or sink bulk traffic. - * Any device can test control transfers (default with GENERIC binding). - * - * Several entries work with the default EP0 implementation that's built - * into EZ-USB chips. There's a default vendor ID which can be overridden - * by (very) small config EEPROMS, but otherwise all these devices act - * identically until firmware is loaded: only EP0 works. It turns out - * to be easy to make other endpoints work, without modifying that EP0 - * behavior. For now, we expect that kind of firmware. - */ - -/* an21xx or fx versions of ez-usb */ -static struct usbtest_info ez1_info = { - .name = "EZ-USB device", - .ep_in = 2, - .ep_out = 2, - .alt = 1, -}; - -/* fx2 version of ez-usb */ -static struct usbtest_info ez2_info = { - .name = "FX2 device", - .ep_in = 6, - .ep_out = 2, - .alt = 1, -}; - -/* ezusb family device with dedicated usb test firmware, - */ -static struct usbtest_info fw_info = { - .name = "usb test device", - .ep_in = 2, - .ep_out = 2, - .alt = 1, - .autoconf = 1, /* iso and ctrl_out need autoconf */ - .ctrl_out = 1, - .iso = 1, /* iso_ep's are #8 in/out */ -}; - -/* peripheral running Linux and 'zero.c' test firmware, or - * its user-mode cousin. different versions of this use - * different hardware with the same vendor/product codes. - * host side MUST rely on the endpoint descriptors. - */ -static struct usbtest_info gz_info = { - .name = "Linux gadget zero", - .autoconf = 1, - .ctrl_out = 1, - .alt = 0, -}; - -static struct usbtest_info um_info = { - .name = "Linux user mode test driver", - .autoconf = 1, - .alt = -1, -}; - -static struct usbtest_info um2_info = { - .name = "Linux user mode ISO test driver", - .autoconf = 1, - .iso = 1, - .alt = -1, -}; - -#ifdef IBOT2 -/* this is a nice source of high speed bulk data; - * uses an FX2, with firmware provided in the device - */ -static struct usbtest_info ibot2_info = { - .name = "iBOT2 webcam", - .ep_in = 2, - .alt = -1, -}; -#endif - -#ifdef GENERIC -/* we can use any device to test control traffic */ -static struct usbtest_info generic_info = { - .name = "Generic USB device", - .alt = -1, -}; -#endif - - -static const struct usb_device_id id_table[] = { - - /*-------------------------------------------------------------*/ - - /* EZ-USB devices which download firmware to replace (or in our - * case augment) the default device implementation. - */ - - /* generic EZ-USB FX controller */ - { USB_DEVICE(0x0547, 0x2235), - .driver_info = (unsigned long) &ez1_info, - }, - - /* CY3671 development board with EZ-USB FX */ - { USB_DEVICE(0x0547, 0x0080), - .driver_info = (unsigned long) &ez1_info, - }, - - /* generic EZ-USB FX2 controller (or development board) */ - { USB_DEVICE(0x04b4, 0x8613), - .driver_info = (unsigned long) &ez2_info, - }, - - /* re-enumerated usb test device firmware */ - { USB_DEVICE(0xfff0, 0xfff0), - .driver_info = (unsigned long) &fw_info, - }, - - /* "Gadget Zero" firmware runs under Linux */ - { USB_DEVICE(0x0525, 0xa4a0), - .driver_info = (unsigned long) &gz_info, - }, - - /* so does a user-mode variant */ - { USB_DEVICE(0x0525, 0xa4a4), - .driver_info = (unsigned long) &um_info, - }, - - /* ... and a user-mode variant that talks iso */ - { USB_DEVICE(0x0525, 0xa4a3), - .driver_info = (unsigned long) &um2_info, - }, - -#ifdef KEYSPAN_19Qi - /* Keyspan 19qi uses an21xx (original EZ-USB) */ - /* this does not coexist with the real Keyspan 19qi driver! */ - { USB_DEVICE(0x06cd, 0x010b), - .driver_info = (unsigned long) &ez1_info, - }, -#endif - - /*-------------------------------------------------------------*/ - -#ifdef IBOT2 - /* iBOT2 makes a nice source of high speed bulk-in data */ - /* this does not coexist with a real iBOT2 driver! */ - { USB_DEVICE(0x0b62, 0x0059), - .driver_info = (unsigned long) &ibot2_info, - }, -#endif - - /*-------------------------------------------------------------*/ - -#ifdef GENERIC - /* module params can specify devices to use for control tests */ - { .driver_info = (unsigned long) &generic_info, }, -#endif - - /*-------------------------------------------------------------*/ - - { } -}; -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver usbtest_driver = { - .name = "usbtest", - .id_table = id_table, - .probe = usbtest_probe, - .unlocked_ioctl = usbtest_ioctl, - .disconnect = usbtest_disconnect, - .suspend = usbtest_suspend, - .resume = usbtest_resume, -}; - -/*-------------------------------------------------------------------------*/ - -static int __init usbtest_init(void) -{ -#ifdef GENERIC - if (vendor) - pr_debug("params: vend=0x%04x prod=0x%04x\n", vendor, product); -#endif - return usb_register(&usbtest_driver); -} -module_init(usbtest_init); - -static void __exit usbtest_exit(void) -{ - usb_deregister(&usbtest_driver); -} -module_exit(usbtest_exit); - -MODULE_DESCRIPTION("USB Core/HCD Testing Driver"); -MODULE_LICENSE("GPL"); - diff --git a/ANDROID_3.4.5/drivers/usb/misc/uss720.c b/ANDROID_3.4.5/drivers/usb/misc/uss720.c deleted file mode 100644 index 8b1d94a7..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/uss720.c +++ /dev/null @@ -1,825 +0,0 @@ -/*****************************************************************************/ - -/* - * uss720.c -- USS720 USB Parport Cable. - * - * Copyright (C) 1999, 2005, 2010 - * Thomas Sailer (t.sailer@alumni.ethz.ch) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Based on parport_pc.c - * - * History: - * 0.1 04.08.1999 Created - * 0.2 07.08.1999 Some fixes mainly suggested by Tim Waugh - * Interrupt handling currently disabled because - * usb_request_irq crashes somewhere within ohci.c - * for no apparent reason (that is for me, anyway) - * ECP currently untested - * 0.3 10.08.1999 fixing merge errors - * 0.4 13.08.1999 Added Vendor/Product ID of Brad Hard's cable - * 0.5 20.09.1999 usb_control_msg wrapper used - * Nov01.2000 usb_device_table support by Adam J. Richter - * 08.04.2001 Identify version on module load. gb - * 0.6 02.09.2005 Fix "scheduling in interrupt" problem by making save/restore - * context asynchronous - * - */ - -/*****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Version Information - */ -#define DRIVER_VERSION "v0.6" -#define DRIVER_AUTHOR "Thomas M. Sailer, t.sailer@alumni.ethz.ch" -#define DRIVER_DESC "USB Parport Cable driver for Cables using the Lucent Technologies USS720 Chip" - -/* --------------------------------------------------------------------- */ - -struct parport_uss720_private { - struct usb_device *usbdev; - struct parport *pp; - struct kref ref_count; - __u8 reg[7]; /* USB registers */ - struct list_head asynclist; - spinlock_t asynclock; -}; - -struct uss720_async_request { - struct parport_uss720_private *priv; - struct kref ref_count; - struct list_head asynclist; - struct completion compl; - struct urb *urb; - struct usb_ctrlrequest dr; - __u8 reg[7]; -}; - -/* --------------------------------------------------------------------- */ - -static void destroy_priv(struct kref *kref) -{ - struct parport_uss720_private *priv = container_of(kref, struct parport_uss720_private, ref_count); - - usb_put_dev(priv->usbdev); - kfree(priv); - dbg("destroying priv datastructure"); -} - -static void destroy_async(struct kref *kref) -{ - struct uss720_async_request *rq = container_of(kref, struct uss720_async_request, ref_count); - struct parport_uss720_private *priv = rq->priv; - unsigned long flags; - - if (likely(rq->urb)) - usb_free_urb(rq->urb); - spin_lock_irqsave(&priv->asynclock, flags); - list_del_init(&rq->asynclist); - spin_unlock_irqrestore(&priv->asynclock, flags); - kfree(rq); - kref_put(&priv->ref_count, destroy_priv); -} - -/* --------------------------------------------------------------------- */ - -static void async_complete(struct urb *urb) -{ - struct uss720_async_request *rq; - struct parport *pp; - struct parport_uss720_private *priv; - int status = urb->status; - - rq = urb->context; - priv = rq->priv; - pp = priv->pp; - if (status) { - err("async_complete: urb error %d", status); - } else if (rq->dr.bRequest == 3) { - memcpy(priv->reg, rq->reg, sizeof(priv->reg)); -#if 0 - dbg("async_complete regs %02x %02x %02x %02x %02x %02x %02x", - (unsigned int)priv->reg[0], (unsigned int)priv->reg[1], (unsigned int)priv->reg[2], - (unsigned int)priv->reg[3], (unsigned int)priv->reg[4], (unsigned int)priv->reg[5], - (unsigned int)priv->reg[6]); -#endif - /* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */ - if (rq->reg[2] & rq->reg[1] & 0x10 && pp) - parport_generic_irq(pp); - } - complete(&rq->compl); - kref_put(&rq->ref_count, destroy_async); -} - -static struct uss720_async_request *submit_async_request(struct parport_uss720_private *priv, - __u8 request, __u8 requesttype, __u16 value, __u16 index, - gfp_t mem_flags) -{ - struct usb_device *usbdev; - struct uss720_async_request *rq; - unsigned long flags; - int ret; - - if (!priv) - return NULL; - usbdev = priv->usbdev; - if (!usbdev) - return NULL; - rq = kmalloc(sizeof(struct uss720_async_request), mem_flags); - if (!rq) { - err("submit_async_request out of memory"); - return NULL; - } - kref_init(&rq->ref_count); - INIT_LIST_HEAD(&rq->asynclist); - init_completion(&rq->compl); - kref_get(&priv->ref_count); - rq->priv = priv; - rq->urb = usb_alloc_urb(0, mem_flags); - if (!rq->urb) { - kref_put(&rq->ref_count, destroy_async); - err("submit_async_request out of memory"); - return NULL; - } - rq->dr.bRequestType = requesttype; - rq->dr.bRequest = request; - rq->dr.wValue = cpu_to_le16(value); - rq->dr.wIndex = cpu_to_le16(index); - rq->dr.wLength = cpu_to_le16((request == 3) ? sizeof(rq->reg) : 0); - usb_fill_control_urb(rq->urb, usbdev, (requesttype & 0x80) ? usb_rcvctrlpipe(usbdev, 0) : usb_sndctrlpipe(usbdev, 0), - (unsigned char *)&rq->dr, - (request == 3) ? rq->reg : NULL, (request == 3) ? sizeof(rq->reg) : 0, async_complete, rq); - /* rq->urb->transfer_flags |= URB_ASYNC_UNLINK; */ - spin_lock_irqsave(&priv->asynclock, flags); - list_add_tail(&rq->asynclist, &priv->asynclist); - spin_unlock_irqrestore(&priv->asynclock, flags); - kref_get(&rq->ref_count); - ret = usb_submit_urb(rq->urb, mem_flags); - if (!ret) - return rq; - destroy_async(&rq->ref_count); - err("submit_async_request submit_urb failed with %d", ret); - return NULL; -} - -static unsigned int kill_all_async_requests_priv(struct parport_uss720_private *priv) -{ - struct uss720_async_request *rq; - unsigned long flags; - unsigned int ret = 0; - - spin_lock_irqsave(&priv->asynclock, flags); - list_for_each_entry(rq, &priv->asynclist, asynclist) { - usb_unlink_urb(rq->urb); - ret++; - } - spin_unlock_irqrestore(&priv->asynclock, flags); - return ret; -} - -/* --------------------------------------------------------------------- */ - -static int get_1284_register(struct parport *pp, unsigned char reg, unsigned char *val, gfp_t mem_flags) -{ - struct parport_uss720_private *priv; - struct uss720_async_request *rq; - static const unsigned char regindex[9] = { - 4, 0, 1, 5, 5, 0, 2, 3, 6 - }; - int ret; - - if (!pp) - return -EIO; - priv = pp->private_data; - rq = submit_async_request(priv, 3, 0xc0, ((unsigned int)reg) << 8, 0, mem_flags); - if (!rq) { - err("get_1284_register(%u) failed", (unsigned int)reg); - return -EIO; - } - if (!val) { - kref_put(&rq->ref_count, destroy_async); - return 0; - } - if (wait_for_completion_timeout(&rq->compl, HZ)) { - ret = rq->urb->status; - *val = priv->reg[(reg >= 9) ? 0 : regindex[reg]]; - if (ret) - printk(KERN_WARNING "get_1284_register: " - "usb error %d\n", ret); - kref_put(&rq->ref_count, destroy_async); - return ret; - } - printk(KERN_WARNING "get_1284_register timeout\n"); - kill_all_async_requests_priv(priv); - return -EIO; -} - -static int set_1284_register(struct parport *pp, unsigned char reg, unsigned char val, gfp_t mem_flags) -{ - struct parport_uss720_private *priv; - struct uss720_async_request *rq; - - if (!pp) - return -EIO; - priv = pp->private_data; - rq = submit_async_request(priv, 4, 0x40, (((unsigned int)reg) << 8) | val, 0, mem_flags); - if (!rq) { - err("set_1284_register(%u,%u) failed", (unsigned int)reg, (unsigned int)val); - return -EIO; - } - kref_put(&rq->ref_count, destroy_async); - return 0; -} - -/* --------------------------------------------------------------------- */ - -/* ECR modes */ -#define ECR_SPP 00 -#define ECR_PS2 01 -#define ECR_PPF 02 -#define ECR_ECP 03 -#define ECR_EPP 04 - -/* Safely change the mode bits in the ECR */ -static int change_mode(struct parport *pp, int m) -{ - struct parport_uss720_private *priv = pp->private_data; - int mode; - __u8 reg; - - if (get_1284_register(pp, 6, ®, GFP_KERNEL)) - return -EIO; - /* Bits <7:5> contain the mode. */ - mode = (priv->reg[2] >> 5) & 0x7; - if (mode == m) - return 0; - /* We have to go through mode 000 or 001 */ - if (mode > ECR_PS2 && m > ECR_PS2) - if (change_mode(pp, ECR_PS2)) - return -EIO; - - if (m <= ECR_PS2 && !(priv->reg[1] & 0x20)) { - /* This mode resets the FIFO, so we may - * have to wait for it to drain first. */ - unsigned long expire = jiffies + pp->physport->cad->timeout; - switch (mode) { - case ECR_PPF: /* Parallel Port FIFO mode */ - case ECR_ECP: /* ECP Parallel Port mode */ - /* Poll slowly. */ - for (;;) { - if (get_1284_register(pp, 6, ®, GFP_KERNEL)) - return -EIO; - if (priv->reg[2] & 0x01) - break; - if (time_after_eq (jiffies, expire)) - /* The FIFO is stuck. */ - return -EBUSY; - msleep_interruptible(10); - if (signal_pending (current)) - break; - } - } - } - /* Set the mode. */ - if (set_1284_register(pp, 6, m << 5, GFP_KERNEL)) - return -EIO; - if (get_1284_register(pp, 6, ®, GFP_KERNEL)) - return -EIO; - return 0; -} - -/* - * Clear TIMEOUT BIT in EPP MODE - */ -static int clear_epp_timeout(struct parport *pp) -{ - unsigned char stat; - - if (get_1284_register(pp, 1, &stat, GFP_KERNEL)) - return 1; - return stat & 1; -} - -/* - * Access functions. - */ -#if 0 -static int uss720_irq(int usbstatus, void *buffer, int len, void *dev_id) -{ - struct parport *pp = (struct parport *)dev_id; - struct parport_uss720_private *priv = pp->private_data; - - if (usbstatus != 0 || len < 4 || !buffer) - return 1; - memcpy(priv->reg, buffer, 4); - /* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */ - if (priv->reg[2] & priv->reg[1] & 0x10) - parport_generic_irq(pp); - return 1; -} -#endif - -static void parport_uss720_write_data(struct parport *pp, unsigned char d) -{ - set_1284_register(pp, 0, d, GFP_KERNEL); -} - -static unsigned char parport_uss720_read_data(struct parport *pp) -{ - unsigned char ret; - - if (get_1284_register(pp, 0, &ret, GFP_KERNEL)) - return 0; - return ret; -} - -static void parport_uss720_write_control(struct parport *pp, unsigned char d) -{ - struct parport_uss720_private *priv = pp->private_data; - - d = (d & 0xf) | (priv->reg[1] & 0xf0); - if (set_1284_register(pp, 2, d, GFP_KERNEL)) - return; - priv->reg[1] = d; -} - -static unsigned char parport_uss720_read_control(struct parport *pp) -{ - struct parport_uss720_private *priv = pp->private_data; - return priv->reg[1] & 0xf; /* Use soft copy */ -} - -static unsigned char parport_uss720_frob_control(struct parport *pp, unsigned char mask, unsigned char val) -{ - struct parport_uss720_private *priv = pp->private_data; - unsigned char d; - - mask &= 0x0f; - val &= 0x0f; - d = (priv->reg[1] & (~mask)) ^ val; - if (set_1284_register(pp, 2, d, GFP_KERNEL)) - return 0; - priv->reg[1] = d; - return d & 0xf; -} - -static unsigned char parport_uss720_read_status(struct parport *pp) -{ - unsigned char ret; - - if (get_1284_register(pp, 1, &ret, GFP_KERNEL)) - return 0; - return ret & 0xf8; -} - -static void parport_uss720_disable_irq(struct parport *pp) -{ - struct parport_uss720_private *priv = pp->private_data; - unsigned char d; - - d = priv->reg[1] & ~0x10; - if (set_1284_register(pp, 2, d, GFP_KERNEL)) - return; - priv->reg[1] = d; -} - -static void parport_uss720_enable_irq(struct parport *pp) -{ - struct parport_uss720_private *priv = pp->private_data; - unsigned char d; - - d = priv->reg[1] | 0x10; - if (set_1284_register(pp, 2, d, GFP_KERNEL)) - return; - priv->reg[1] = d; -} - -static void parport_uss720_data_forward (struct parport *pp) -{ - struct parport_uss720_private *priv = pp->private_data; - unsigned char d; - - d = priv->reg[1] & ~0x20; - if (set_1284_register(pp, 2, d, GFP_KERNEL)) - return; - priv->reg[1] = d; -} - -static void parport_uss720_data_reverse (struct parport *pp) -{ - struct parport_uss720_private *priv = pp->private_data; - unsigned char d; - - d = priv->reg[1] | 0x20; - if (set_1284_register(pp, 2, d, GFP_KERNEL)) - return; - priv->reg[1] = d; -} - -static void parport_uss720_init_state(struct pardevice *dev, struct parport_state *s) -{ - s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0); - s->u.pc.ecr = 0x24; -} - -static void parport_uss720_save_state(struct parport *pp, struct parport_state *s) -{ - struct parport_uss720_private *priv = pp->private_data; - -#if 0 - if (get_1284_register(pp, 2, NULL, GFP_ATOMIC)) - return; -#endif - s->u.pc.ctr = priv->reg[1]; - s->u.pc.ecr = priv->reg[2]; -} - -static void parport_uss720_restore_state(struct parport *pp, struct parport_state *s) -{ - struct parport_uss720_private *priv = pp->private_data; - - set_1284_register(pp, 2, s->u.pc.ctr, GFP_ATOMIC); - set_1284_register(pp, 6, s->u.pc.ecr, GFP_ATOMIC); - get_1284_register(pp, 2, NULL, GFP_ATOMIC); - priv->reg[1] = s->u.pc.ctr; - priv->reg[2] = s->u.pc.ecr; -} - -static size_t parport_uss720_epp_read_data(struct parport *pp, void *buf, size_t length, int flags) -{ - struct parport_uss720_private *priv = pp->private_data; - size_t got = 0; - - if (change_mode(pp, ECR_EPP)) - return 0; - for (; got < length; got++) { - if (get_1284_register(pp, 4, (char *)buf, GFP_KERNEL)) - break; - buf++; - if (priv->reg[0] & 0x01) { - clear_epp_timeout(pp); - break; - } - } - change_mode(pp, ECR_PS2); - return got; -} - -static size_t parport_uss720_epp_write_data(struct parport *pp, const void *buf, size_t length, int flags) -{ -#if 0 - struct parport_uss720_private *priv = pp->private_data; - size_t written = 0; - - if (change_mode(pp, ECR_EPP)) - return 0; - for (; written < length; written++) { - if (set_1284_register(pp, 4, (char *)buf, GFP_KERNEL)) - break; - ((char*)buf)++; - if (get_1284_register(pp, 1, NULL, GFP_KERNEL)) - break; - if (priv->reg[0] & 0x01) { - clear_epp_timeout(pp); - break; - } - } - change_mode(pp, ECR_PS2); - return written; -#else - struct parport_uss720_private *priv = pp->private_data; - struct usb_device *usbdev = priv->usbdev; - int rlen; - int i; - - if (!usbdev) - return 0; - if (change_mode(pp, ECR_EPP)) - return 0; - i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buf, length, &rlen, 20000); - if (i) - printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %Zu rlen %u\n", buf, length, rlen); - change_mode(pp, ECR_PS2); - return rlen; -#endif -} - -static size_t parport_uss720_epp_read_addr(struct parport *pp, void *buf, size_t length, int flags) -{ - struct parport_uss720_private *priv = pp->private_data; - size_t got = 0; - - if (change_mode(pp, ECR_EPP)) - return 0; - for (; got < length; got++) { - if (get_1284_register(pp, 3, (char *)buf, GFP_KERNEL)) - break; - buf++; - if (priv->reg[0] & 0x01) { - clear_epp_timeout(pp); - break; - } - } - change_mode(pp, ECR_PS2); - return got; -} - -static size_t parport_uss720_epp_write_addr(struct parport *pp, const void *buf, size_t length, int flags) -{ - struct parport_uss720_private *priv = pp->private_data; - size_t written = 0; - - if (change_mode(pp, ECR_EPP)) - return 0; - for (; written < length; written++) { - if (set_1284_register(pp, 3, *(char *)buf, GFP_KERNEL)) - break; - buf++; - if (get_1284_register(pp, 1, NULL, GFP_KERNEL)) - break; - if (priv->reg[0] & 0x01) { - clear_epp_timeout(pp); - break; - } - } - change_mode(pp, ECR_PS2); - return written; -} - -static size_t parport_uss720_ecp_write_data(struct parport *pp, const void *buffer, size_t len, int flags) -{ - struct parport_uss720_private *priv = pp->private_data; - struct usb_device *usbdev = priv->usbdev; - int rlen; - int i; - - if (!usbdev) - return 0; - if (change_mode(pp, ECR_ECP)) - return 0; - i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buffer, len, &rlen, 20000); - if (i) - printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %Zu rlen %u\n", buffer, len, rlen); - change_mode(pp, ECR_PS2); - return rlen; -} - -static size_t parport_uss720_ecp_read_data(struct parport *pp, void *buffer, size_t len, int flags) -{ - struct parport_uss720_private *priv = pp->private_data; - struct usb_device *usbdev = priv->usbdev; - int rlen; - int i; - - if (!usbdev) - return 0; - if (change_mode(pp, ECR_ECP)) - return 0; - i = usb_bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, 2), buffer, len, &rlen, 20000); - if (i) - printk(KERN_ERR "uss720: recvbulk ep 2 buf %p len %Zu rlen %u\n", buffer, len, rlen); - change_mode(pp, ECR_PS2); - return rlen; -} - -static size_t parport_uss720_ecp_write_addr(struct parport *pp, const void *buffer, size_t len, int flags) -{ - size_t written = 0; - - if (change_mode(pp, ECR_ECP)) - return 0; - for (; written < len; written++) { - if (set_1284_register(pp, 5, *(char *)buffer, GFP_KERNEL)) - break; - buffer++; - } - change_mode(pp, ECR_PS2); - return written; -} - -static size_t parport_uss720_write_compat(struct parport *pp, const void *buffer, size_t len, int flags) -{ - struct parport_uss720_private *priv = pp->private_data; - struct usb_device *usbdev = priv->usbdev; - int rlen; - int i; - - if (!usbdev) - return 0; - if (change_mode(pp, ECR_PPF)) - return 0; - i = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), (void *)buffer, len, &rlen, 20000); - if (i) - printk(KERN_ERR "uss720: sendbulk ep 1 buf %p len %Zu rlen %u\n", buffer, len, rlen); - change_mode(pp, ECR_PS2); - return rlen; -} - -/* --------------------------------------------------------------------- */ - -static struct parport_operations parport_uss720_ops = -{ - .owner = THIS_MODULE, - .write_data = parport_uss720_write_data, - .read_data = parport_uss720_read_data, - - .write_control = parport_uss720_write_control, - .read_control = parport_uss720_read_control, - .frob_control = parport_uss720_frob_control, - - .read_status = parport_uss720_read_status, - - .enable_irq = parport_uss720_enable_irq, - .disable_irq = parport_uss720_disable_irq, - - .data_forward = parport_uss720_data_forward, - .data_reverse = parport_uss720_data_reverse, - - .init_state = parport_uss720_init_state, - .save_state = parport_uss720_save_state, - .restore_state = parport_uss720_restore_state, - - .epp_write_data = parport_uss720_epp_write_data, - .epp_read_data = parport_uss720_epp_read_data, - .epp_write_addr = parport_uss720_epp_write_addr, - .epp_read_addr = parport_uss720_epp_read_addr, - - .ecp_write_data = parport_uss720_ecp_write_data, - .ecp_read_data = parport_uss720_ecp_read_data, - .ecp_write_addr = parport_uss720_ecp_write_addr, - - .compat_write_data = parport_uss720_write_compat, - .nibble_read_data = parport_ieee1284_read_nibble, - .byte_read_data = parport_ieee1284_read_byte, -}; - -/* --------------------------------------------------------------------- */ - -static int uss720_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *usbdev = usb_get_dev(interface_to_usbdev(intf)); - struct usb_host_interface *interface; - struct usb_host_endpoint *endpoint; - struct parport_uss720_private *priv; - struct parport *pp; - unsigned char reg; - int i; - - dbg("probe: vendor id 0x%x, device id 0x%x\n", - le16_to_cpu(usbdev->descriptor.idVendor), - le16_to_cpu(usbdev->descriptor.idProduct)); - - /* our known interfaces have 3 alternate settings */ - if (intf->num_altsetting != 3) { - usb_put_dev(usbdev); - return -ENODEV; - } - i = usb_set_interface(usbdev, intf->altsetting->desc.bInterfaceNumber, 2); - dbg("set inteface result %d", i); - - interface = intf->cur_altsetting; - - /* - * Allocate parport interface - */ - if (!(priv = kzalloc(sizeof(struct parport_uss720_private), GFP_KERNEL))) { - usb_put_dev(usbdev); - return -ENOMEM; - } - priv->pp = NULL; - priv->usbdev = usbdev; - kref_init(&priv->ref_count); - spin_lock_init(&priv->asynclock); - INIT_LIST_HEAD(&priv->asynclist); - if (!(pp = parport_register_port(0, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &parport_uss720_ops))) { - printk(KERN_WARNING "uss720: could not register parport\n"); - goto probe_abort; - } - - priv->pp = pp; - pp->private_data = priv; - pp->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP | PARPORT_MODE_ECP | PARPORT_MODE_COMPAT; - - /* set the USS720 control register to manual mode, no ECP compression, enable all ints */ - set_1284_register(pp, 7, 0x00, GFP_KERNEL); - set_1284_register(pp, 6, 0x30, GFP_KERNEL); /* PS/2 mode */ - set_1284_register(pp, 2, 0x0c, GFP_KERNEL); - /* debugging */ - get_1284_register(pp, 0, ®, GFP_KERNEL); - dbg("reg: %02x %02x %02x %02x %02x %02x %02x", - priv->reg[0], priv->reg[1], priv->reg[2], priv->reg[3], priv->reg[4], priv->reg[5], priv->reg[6]); - - endpoint = &interface->endpoint[2]; - dbg("epaddr %d interval %d", endpoint->desc.bEndpointAddress, endpoint->desc.bInterval); - parport_announce_port(pp); - - usb_set_intfdata(intf, pp); - return 0; - -probe_abort: - kill_all_async_requests_priv(priv); - kref_put(&priv->ref_count, destroy_priv); - return -ENODEV; -} - -static void uss720_disconnect(struct usb_interface *intf) -{ - struct parport *pp = usb_get_intfdata(intf); - struct parport_uss720_private *priv; - struct usb_device *usbdev; - - dbg("disconnect"); - usb_set_intfdata(intf, NULL); - if (pp) { - priv = pp->private_data; - usbdev = priv->usbdev; - priv->usbdev = NULL; - priv->pp = NULL; - dbg("parport_remove_port"); - parport_remove_port(pp); - parport_put_port(pp); - kill_all_async_requests_priv(priv); - kref_put(&priv->ref_count, destroy_priv); - } - dbg("disconnect done"); -} - -/* table of cables that work through this driver */ -static const struct usb_device_id uss720_table[] = { - { USB_DEVICE(0x047e, 0x1001) }, - { USB_DEVICE(0x0557, 0x2001) }, - { USB_DEVICE(0x0729, 0x1284) }, - { USB_DEVICE(0x1293, 0x0002) }, - { USB_DEVICE(0x050d, 0x0002) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, uss720_table); - - -static struct usb_driver uss720_driver = { - .name = "uss720", - .probe = uss720_probe, - .disconnect = uss720_disconnect, - .id_table = uss720_table, -}; - -/* --------------------------------------------------------------------- */ - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -static int __init uss720_init(void) -{ - int retval; - retval = usb_register(&uss720_driver); - if (retval) - goto out; - - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - printk(KERN_INFO KBUILD_MODNAME ": NOTE: this is a special purpose " - "driver to allow nonstandard\n"); - printk(KERN_INFO KBUILD_MODNAME ": protocols (eg. bitbang) over " - "USS720 usb to parallel cables\n"); - printk(KERN_INFO KBUILD_MODNAME ": If you just want to connect to a " - "printer, use usblp instead\n"); -out: - return retval; -} - -static void __exit uss720_cleanup(void) -{ - usb_deregister(&uss720_driver); -} - -module_init(uss720_init); -module_exit(uss720_cleanup); - -/* --------------------------------------------------------------------- */ diff --git a/ANDROID_3.4.5/drivers/usb/misc/yurex.c b/ANDROID_3.4.5/drivers/usb/misc/yurex.c deleted file mode 100644 index 70201462..00000000 --- a/ANDROID_3.4.5/drivers/usb/misc/yurex.c +++ /dev/null @@ -1,540 +0,0 @@ -/* - * Driver for Meywa-Denki & KAYAC YUREX - * - * Copyright (C) 2010 Tomoki Sekiyama (tomoki.sekiyama@gmail.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRIVER_AUTHOR "Tomoki Sekiyama" -#define DRIVER_DESC "Driver for Meywa-Denki & KAYAC YUREX" - -#define YUREX_VENDOR_ID 0x0c45 -#define YUREX_PRODUCT_ID 0x1010 - -#define CMD_ACK '!' -#define CMD_ANIMATE 'A' -#define CMD_COUNT 'C' -#define CMD_LED 'L' -#define CMD_READ 'R' -#define CMD_SET 'S' -#define CMD_VERSION 'V' -#define CMD_EOF 0x0d -#define CMD_PADDING 0xff - -#define YUREX_BUF_SIZE 8 -#define YUREX_WRITE_TIMEOUT (HZ*2) - -/* table of devices that work with this driver */ -static struct usb_device_id yurex_table[] = { - { USB_DEVICE(YUREX_VENDOR_ID, YUREX_PRODUCT_ID) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, yurex_table); - -#ifdef CONFIG_USB_DYNAMIC_MINORS -#define YUREX_MINOR_BASE 0 -#else -#define YUREX_MINOR_BASE 192 -#endif - -/* Structure to hold all of our device specific stuff */ -struct usb_yurex { - struct usb_device *udev; - struct usb_interface *interface; - __u8 int_in_endpointAddr; - struct urb *urb; /* URB for interrupt in */ - unsigned char *int_buffer; /* buffer for intterupt in */ - struct urb *cntl_urb; /* URB for control msg */ - struct usb_ctrlrequest *cntl_req; /* req for control msg */ - unsigned char *cntl_buffer; /* buffer for control msg */ - - struct kref kref; - struct mutex io_mutex; - struct fasync_struct *async_queue; - wait_queue_head_t waitq; - - spinlock_t lock; - __s64 bbu; /* BBU from device */ -}; -#define to_yurex_dev(d) container_of(d, struct usb_yurex, kref) - -static struct usb_driver yurex_driver; -static const struct file_operations yurex_fops; - - -static void yurex_control_callback(struct urb *urb) -{ - struct usb_yurex *dev = urb->context; - int status = urb->status; - - if (status) { - err("%s - control failed: %d\n", __func__, status); - wake_up_interruptible(&dev->waitq); - return; - } - /* on success, sender woken up by CMD_ACK int in, or timeout */ -} - -static void yurex_delete(struct kref *kref) -{ - struct usb_yurex *dev = to_yurex_dev(kref); - - dbg("yurex_delete"); - - usb_put_dev(dev->udev); - if (dev->cntl_urb) { - usb_kill_urb(dev->cntl_urb); - kfree(dev->cntl_req); - if (dev->cntl_buffer) - usb_free_coherent(dev->udev, YUREX_BUF_SIZE, - dev->cntl_buffer, dev->cntl_urb->transfer_dma); - usb_free_urb(dev->cntl_urb); - } - if (dev->urb) { - usb_kill_urb(dev->urb); - if (dev->int_buffer) - usb_free_coherent(dev->udev, YUREX_BUF_SIZE, - dev->int_buffer, dev->urb->transfer_dma); - usb_free_urb(dev->urb); - } - kfree(dev); -} - -/* - * usb class driver info in order to get a minor number from the usb core, - * and to have the device registered with the driver core - */ -static struct usb_class_driver yurex_class = { - .name = "yurex%d", - .fops = &yurex_fops, - .minor_base = YUREX_MINOR_BASE, -}; - -static void yurex_interrupt(struct urb *urb) -{ - struct usb_yurex *dev = urb->context; - unsigned char *buf = dev->int_buffer; - int status = urb->status; - unsigned long flags; - int retval, i; - - switch (status) { - case 0: /*success*/ - break; - case -EOVERFLOW: - err("%s - overflow with length %d, actual length is %d", - __func__, YUREX_BUF_SIZE, dev->urb->actual_length); - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - case -EILSEQ: - /* The device is terminated, clean up */ - return; - default: - err("%s - unknown status received: %d", __func__, status); - goto exit; - } - - /* handle received message */ - switch (buf[0]) { - case CMD_COUNT: - case CMD_READ: - if (buf[6] == CMD_EOF) { - spin_lock_irqsave(&dev->lock, flags); - dev->bbu = 0; - for (i = 1; i < 6; i++) { - dev->bbu += buf[i]; - if (i != 5) - dev->bbu <<= 8; - } - dbg("%s count: %lld", __func__, dev->bbu); - spin_unlock_irqrestore(&dev->lock, flags); - - kill_fasync(&dev->async_queue, SIGIO, POLL_IN); - } - else - dbg("data format error - no EOF"); - break; - case CMD_ACK: - dbg("%s ack: %c", __func__, buf[1]); - wake_up_interruptible(&dev->waitq); - break; - } - -exit: - retval = usb_submit_urb(dev->urb, GFP_ATOMIC); - if (retval) { - err("%s - usb_submit_urb failed: %d", - __func__, retval); - } -} - -static int yurex_probe(struct usb_interface *interface, const struct usb_device_id *id) -{ - struct usb_yurex *dev; - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - int retval = -ENOMEM; - int i; - DEFINE_WAIT(wait); - - /* allocate memory for our device state and initialize it */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - err("Out of memory"); - goto error; - } - kref_init(&dev->kref); - mutex_init(&dev->io_mutex); - spin_lock_init(&dev->lock); - init_waitqueue_head(&dev->waitq); - - dev->udev = usb_get_dev(interface_to_usbdev(interface)); - dev->interface = interface; - - /* set up the endpoint information */ - iface_desc = interface->cur_altsetting; - for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { - endpoint = &iface_desc->endpoint[i].desc; - - if (usb_endpoint_is_int_in(endpoint)) { - dev->int_in_endpointAddr = endpoint->bEndpointAddress; - break; - } - } - if (!dev->int_in_endpointAddr) { - retval = -ENODEV; - err("Could not find endpoints"); - goto error; - } - - - /* allocate control URB */ - dev->cntl_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->cntl_urb) { - err("Could not allocate control URB"); - goto error; - } - - /* allocate buffer for control req */ - dev->cntl_req = kmalloc(YUREX_BUF_SIZE, GFP_KERNEL); - if (!dev->cntl_req) { - err("Could not allocate cntl_req"); - goto error; - } - - /* allocate buffer for control msg */ - dev->cntl_buffer = usb_alloc_coherent(dev->udev, YUREX_BUF_SIZE, - GFP_KERNEL, - &dev->cntl_urb->transfer_dma); - if (!dev->cntl_buffer) { - err("Could not allocate cntl_buffer"); - goto error; - } - - /* configure control URB */ - dev->cntl_req->bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | - USB_RECIP_INTERFACE; - dev->cntl_req->bRequest = HID_REQ_SET_REPORT; - dev->cntl_req->wValue = cpu_to_le16((HID_OUTPUT_REPORT + 1) << 8); - dev->cntl_req->wIndex = cpu_to_le16(iface_desc->desc.bInterfaceNumber); - dev->cntl_req->wLength = cpu_to_le16(YUREX_BUF_SIZE); - - usb_fill_control_urb(dev->cntl_urb, dev->udev, - usb_sndctrlpipe(dev->udev, 0), - (void *)dev->cntl_req, dev->cntl_buffer, - YUREX_BUF_SIZE, yurex_control_callback, dev); - dev->cntl_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - - /* allocate interrupt URB */ - dev->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->urb) { - err("Could not allocate URB"); - goto error; - } - - /* allocate buffer for interrupt in */ - dev->int_buffer = usb_alloc_coherent(dev->udev, YUREX_BUF_SIZE, - GFP_KERNEL, &dev->urb->transfer_dma); - if (!dev->int_buffer) { - err("Could not allocate int_buffer"); - goto error; - } - - /* configure interrupt URB */ - usb_fill_int_urb(dev->urb, dev->udev, - usb_rcvintpipe(dev->udev, dev->int_in_endpointAddr), - dev->int_buffer, YUREX_BUF_SIZE, yurex_interrupt, - dev, 1); - dev->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - if (usb_submit_urb(dev->urb, GFP_KERNEL)) { - retval = -EIO; - err("Could not submitting URB"); - goto error; - } - - /* save our data pointer in this interface device */ - usb_set_intfdata(interface, dev); - - /* we can register the device now, as it is ready */ - retval = usb_register_dev(interface, &yurex_class); - if (retval) { - err("Not able to get a minor for this device."); - usb_set_intfdata(interface, NULL); - goto error; - } - - dev->bbu = -1; - - dev_info(&interface->dev, - "USB YUREX device now attached to Yurex #%d\n", - interface->minor); - - return 0; - -error: - if (dev) - /* this frees allocated memory */ - kref_put(&dev->kref, yurex_delete); - return retval; -} - -static void yurex_disconnect(struct usb_interface *interface) -{ - struct usb_yurex *dev; - int minor = interface->minor; - - dev = usb_get_intfdata(interface); - usb_set_intfdata(interface, NULL); - - /* give back our minor */ - usb_deregister_dev(interface, &yurex_class); - - /* prevent more I/O from starting */ - mutex_lock(&dev->io_mutex); - dev->interface = NULL; - mutex_unlock(&dev->io_mutex); - - /* wakeup waiters */ - kill_fasync(&dev->async_queue, SIGIO, POLL_IN); - wake_up_interruptible(&dev->waitq); - - /* decrement our usage count */ - kref_put(&dev->kref, yurex_delete); - - dev_info(&interface->dev, "USB YUREX #%d now disconnected\n", minor); -} - -static struct usb_driver yurex_driver = { - .name = "yurex", - .probe = yurex_probe, - .disconnect = yurex_disconnect, - .id_table = yurex_table, -}; - - -static int yurex_fasync(int fd, struct file *file, int on) -{ - struct usb_yurex *dev; - - dev = (struct usb_yurex *)file->private_data; - return fasync_helper(fd, file, on, &dev->async_queue); -} - -static int yurex_open(struct inode *inode, struct file *file) -{ - struct usb_yurex *dev; - struct usb_interface *interface; - int subminor; - int retval = 0; - - subminor = iminor(inode); - - interface = usb_find_interface(&yurex_driver, subminor); - if (!interface) { - err("%s - error, can't find device for minor %d", - __func__, subminor); - retval = -ENODEV; - goto exit; - } - - dev = usb_get_intfdata(interface); - if (!dev) { - retval = -ENODEV; - goto exit; - } - - /* increment our usage count for the device */ - kref_get(&dev->kref); - - /* save our object in the file's private structure */ - mutex_lock(&dev->io_mutex); - file->private_data = dev; - mutex_unlock(&dev->io_mutex); - -exit: - return retval; -} - -static int yurex_release(struct inode *inode, struct file *file) -{ - struct usb_yurex *dev; - - dev = (struct usb_yurex *)file->private_data; - if (dev == NULL) - return -ENODEV; - - yurex_fasync(-1, file, 0); - - /* decrement the count on our device */ - kref_put(&dev->kref, yurex_delete); - return 0; -} - -static ssize_t yurex_read(struct file *file, char *buffer, size_t count, loff_t *ppos) -{ - struct usb_yurex *dev; - int retval = 0; - int bytes_read = 0; - char in_buffer[20]; - unsigned long flags; - - dev = (struct usb_yurex *)file->private_data; - - mutex_lock(&dev->io_mutex); - if (!dev->interface) { /* already disconnected */ - retval = -ENODEV; - goto exit; - } - - spin_lock_irqsave(&dev->lock, flags); - bytes_read = snprintf(in_buffer, 20, "%lld\n", dev->bbu); - spin_unlock_irqrestore(&dev->lock, flags); - - if (*ppos < bytes_read) { - if (copy_to_user(buffer, in_buffer + *ppos, bytes_read - *ppos)) - retval = -EFAULT; - else { - retval = bytes_read - *ppos; - *ppos += bytes_read; - } - } - -exit: - mutex_unlock(&dev->io_mutex); - return retval; -} - -static ssize_t yurex_write(struct file *file, const char *user_buffer, size_t count, loff_t *ppos) -{ - struct usb_yurex *dev; - int i, set = 0, retval = 0; - char buffer[16]; - char *data = buffer; - unsigned long long c, c2 = 0; - signed long timeout = 0; - DEFINE_WAIT(wait); - - count = min(sizeof(buffer), count); - dev = (struct usb_yurex *)file->private_data; - - /* verify that we actually have some data to write */ - if (count == 0) - goto error; - - mutex_lock(&dev->io_mutex); - if (!dev->interface) { /* alreaday disconnected */ - mutex_unlock(&dev->io_mutex); - retval = -ENODEV; - goto error; - } - - if (copy_from_user(buffer, user_buffer, count)) { - mutex_unlock(&dev->io_mutex); - retval = -EFAULT; - goto error; - } - memset(dev->cntl_buffer, CMD_PADDING, YUREX_BUF_SIZE); - - switch (buffer[0]) { - case CMD_ANIMATE: - case CMD_LED: - dev->cntl_buffer[0] = buffer[0]; - dev->cntl_buffer[1] = buffer[1]; - dev->cntl_buffer[2] = CMD_EOF; - break; - case CMD_READ: - case CMD_VERSION: - dev->cntl_buffer[0] = buffer[0]; - dev->cntl_buffer[1] = 0x00; - dev->cntl_buffer[2] = CMD_EOF; - break; - case CMD_SET: - data++; - /* FALL THROUGH */ - case '0' ... '9': - set = 1; - c = c2 = simple_strtoull(data, NULL, 0); - dev->cntl_buffer[0] = CMD_SET; - for (i = 1; i < 6; i++) { - dev->cntl_buffer[i] = (c>>32) & 0xff; - c <<= 8; - } - buffer[6] = CMD_EOF; - break; - default: - mutex_unlock(&dev->io_mutex); - return -EINVAL; - } - - /* send the data as the control msg */ - prepare_to_wait(&dev->waitq, &wait, TASK_INTERRUPTIBLE); - dbg("%s - submit %c", __func__, dev->cntl_buffer[0]); - retval = usb_submit_urb(dev->cntl_urb, GFP_KERNEL); - if (retval >= 0) - timeout = schedule_timeout(YUREX_WRITE_TIMEOUT); - finish_wait(&dev->waitq, &wait); - - mutex_unlock(&dev->io_mutex); - - if (retval < 0) { - err("%s - failed to send bulk msg, error %d", __func__, retval); - goto error; - } - if (set && timeout) - dev->bbu = c2; - return timeout ? count : -EIO; - -error: - return retval; -} - -static const struct file_operations yurex_fops = { - .owner = THIS_MODULE, - .read = yurex_read, - .write = yurex_write, - .open = yurex_open, - .release = yurex_release, - .fasync = yurex_fasync, - .llseek = default_llseek, -}; - -module_usb_driver(yurex_driver); - -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/mon/Kconfig b/ANDROID_3.4.5/drivers/usb/mon/Kconfig deleted file mode 100644 index 635745f5..00000000 --- a/ANDROID_3.4.5/drivers/usb/mon/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# -# USB Monitor configuration -# - -config USB_MON - tristate "USB Monitor" - depends on USB - help - If you select this option, a component which captures the USB traffic - between peripheral-specific drivers and HC drivers will be built. - For more information, see . - - If unsure, say Y, if allowed, otherwise M. diff --git a/ANDROID_3.4.5/drivers/usb/mon/Makefile b/ANDROID_3.4.5/drivers/usb/mon/Makefile deleted file mode 100644 index 8ed24ab0..00000000 --- a/ANDROID_3.4.5/drivers/usb/mon/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Makefile for USB monitor -# - -usbmon-y := mon_main.o mon_stat.o mon_text.o mon_bin.o - -obj-$(CONFIG_USB_MON) += usbmon.o diff --git a/ANDROID_3.4.5/drivers/usb/mon/mon_bin.c b/ANDROID_3.4.5/drivers/usb/mon/mon_bin.c deleted file mode 100644 index 91cd8507..00000000 --- a/ANDROID_3.4.5/drivers/usb/mon/mon_bin.c +++ /dev/null @@ -1,1389 +0,0 @@ -/* - * The USB Monitor, inspired by Dave Harding's USBMon. - * - * This is a binary format reader. - * - * Copyright (C) 2006 Paolo Abeni (paolo.abeni@email.it) - * Copyright (C) 2006,2007 Pete Zaitcev (zaitcev@redhat.com) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "usb_mon.h" - -/* - * Defined by USB 2.0 clause 9.3, table 9.2. - */ -#define SETUP_LEN 8 - -/* ioctl macros */ -#define MON_IOC_MAGIC 0x92 - -#define MON_IOCQ_URB_LEN _IO(MON_IOC_MAGIC, 1) -/* #2 used to be MON_IOCX_URB, removed before it got into Linus tree */ -#define MON_IOCG_STATS _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats) -#define MON_IOCT_RING_SIZE _IO(MON_IOC_MAGIC, 4) -#define MON_IOCQ_RING_SIZE _IO(MON_IOC_MAGIC, 5) -#define MON_IOCX_GET _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get) -#define MON_IOCX_MFETCH _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch) -#define MON_IOCH_MFLUSH _IO(MON_IOC_MAGIC, 8) -/* #9 was MON_IOCT_SETAPI */ -#define MON_IOCX_GETX _IOW(MON_IOC_MAGIC, 10, struct mon_bin_get) - -#ifdef CONFIG_COMPAT -#define MON_IOCX_GET32 _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get32) -#define MON_IOCX_MFETCH32 _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch32) -#define MON_IOCX_GETX32 _IOW(MON_IOC_MAGIC, 10, struct mon_bin_get32) -#endif - -/* - * Some architectures have enormous basic pages (16KB for ia64, 64KB for ppc). - * But it's all right. Just use a simple way to make sure the chunk is never - * smaller than a page. - * - * N.B. An application does not know our chunk size. - * - * Woops, get_zeroed_page() returns a single page. I guess we're stuck with - * page-sized chunks for the time being. - */ -#define CHUNK_SIZE PAGE_SIZE -#define CHUNK_ALIGN(x) (((x)+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1)) - -/* - * The magic limit was calculated so that it allows the monitoring - * application to pick data once in two ticks. This way, another application, - * which presumably drives the bus, gets to hog CPU, yet we collect our data. - * If HZ is 100, a 480 mbit/s bus drives 614 KB every jiffy. USB has an - * enormous overhead built into the bus protocol, so we need about 1000 KB. - * - * This is still too much for most cases, where we just snoop a few - * descriptor fetches for enumeration. So, the default is a "reasonable" - * amount for systems with HZ=250 and incomplete bus saturation. - * - * XXX What about multi-megabyte URBs which take minutes to transfer? - */ -#define BUFF_MAX CHUNK_ALIGN(1200*1024) -#define BUFF_DFL CHUNK_ALIGN(300*1024) -#define BUFF_MIN CHUNK_ALIGN(8*1024) - -/* - * The per-event API header (2 per URB). - * - * This structure is seen in userland as defined by the documentation. - */ -struct mon_bin_hdr { - u64 id; /* URB ID - from submission to callback */ - unsigned char type; /* Same as in text API; extensible. */ - unsigned char xfer_type; /* ISO, Intr, Control, Bulk */ - unsigned char epnum; /* Endpoint number and transfer direction */ - unsigned char devnum; /* Device address */ - unsigned short busnum; /* Bus number */ - char flag_setup; - char flag_data; - s64 ts_sec; /* gettimeofday */ - s32 ts_usec; /* gettimeofday */ - int status; - unsigned int len_urb; /* Length of data (submitted or actual) */ - unsigned int len_cap; /* Delivered length */ - union { - unsigned char setup[SETUP_LEN]; /* Only for Control S-type */ - struct iso_rec { - int error_count; - int numdesc; - } iso; - } s; - int interval; - int start_frame; - unsigned int xfer_flags; - unsigned int ndesc; /* Actual number of ISO descriptors */ -}; - -/* - * ISO vector, packed into the head of data stream. - * This has to take 16 bytes to make sure that the end of buffer - * wrap is not happening in the middle of a descriptor. - */ -struct mon_bin_isodesc { - int iso_status; - unsigned int iso_off; - unsigned int iso_len; - u32 _pad; -}; - -/* per file statistic */ -struct mon_bin_stats { - u32 queued; - u32 dropped; -}; - -struct mon_bin_get { - struct mon_bin_hdr __user *hdr; /* Can be 48 bytes or 64. */ - void __user *data; - size_t alloc; /* Length of data (can be zero) */ -}; - -struct mon_bin_mfetch { - u32 __user *offvec; /* Vector of events fetched */ - u32 nfetch; /* Number of events to fetch (out: fetched) */ - u32 nflush; /* Number of events to flush */ -}; - -#ifdef CONFIG_COMPAT -struct mon_bin_get32 { - u32 hdr32; - u32 data32; - u32 alloc32; -}; - -struct mon_bin_mfetch32 { - u32 offvec32; - u32 nfetch32; - u32 nflush32; -}; -#endif - -/* Having these two values same prevents wrapping of the mon_bin_hdr */ -#define PKT_ALIGN 64 -#define PKT_SIZE 64 - -#define PKT_SZ_API0 48 /* API 0 (2.6.20) size */ -#define PKT_SZ_API1 64 /* API 1 size: extra fields */ - -#define ISODESC_MAX 128 /* Same number as usbfs allows, 2048 bytes. */ - -/* max number of USB bus supported */ -#define MON_BIN_MAX_MINOR 128 - -/* - * The buffer: map of used pages. - */ -struct mon_pgmap { - struct page *pg; - unsigned char *ptr; /* XXX just use page_to_virt everywhere? */ -}; - -/* - * This gets associated with an open file struct. - */ -struct mon_reader_bin { - /* The buffer: one per open. */ - spinlock_t b_lock; /* Protect b_cnt, b_in */ - unsigned int b_size; /* Current size of the buffer - bytes */ - unsigned int b_cnt; /* Bytes used */ - unsigned int b_in, b_out; /* Offsets into buffer - bytes */ - unsigned int b_read; /* Amount of read data in curr. pkt. */ - struct mon_pgmap *b_vec; /* The map array */ - wait_queue_head_t b_wait; /* Wait for data here */ - - struct mutex fetch_lock; /* Protect b_read, b_out */ - int mmap_active; - - /* A list of these is needed for "bus 0". Some time later. */ - struct mon_reader r; - - /* Stats */ - unsigned int cnt_lost; -}; - -static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp, - unsigned int offset) -{ - return (struct mon_bin_hdr *) - (rp->b_vec[offset / CHUNK_SIZE].ptr + offset % CHUNK_SIZE); -} - -#define MON_RING_EMPTY(rp) ((rp)->b_cnt == 0) - -static unsigned char xfer_to_pipe[4] = { - PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT -}; - -static struct class *mon_bin_class; -static dev_t mon_bin_dev0; -static struct cdev mon_bin_cdev; - -static void mon_buff_area_fill(const struct mon_reader_bin *rp, - unsigned int offset, unsigned int size); -static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp); -static int mon_alloc_buff(struct mon_pgmap *map, int npages); -static void mon_free_buff(struct mon_pgmap *map, int npages); - -/* - * This is a "chunked memcpy". It does not manipulate any counters. - */ -static unsigned int mon_copy_to_buff(const struct mon_reader_bin *this, - unsigned int off, const unsigned char *from, unsigned int length) -{ - unsigned int step_len; - unsigned char *buf; - unsigned int in_page; - - while (length) { - /* - * Determine step_len. - */ - step_len = length; - in_page = CHUNK_SIZE - (off & (CHUNK_SIZE-1)); - if (in_page < step_len) - step_len = in_page; - - /* - * Copy data and advance pointers. - */ - buf = this->b_vec[off / CHUNK_SIZE].ptr + off % CHUNK_SIZE; - memcpy(buf, from, step_len); - if ((off += step_len) >= this->b_size) off = 0; - from += step_len; - length -= step_len; - } - return off; -} - -/* - * This is a little worse than the above because it's "chunked copy_to_user". - * The return value is an error code, not an offset. - */ -static int copy_from_buf(const struct mon_reader_bin *this, unsigned int off, - char __user *to, int length) -{ - unsigned int step_len; - unsigned char *buf; - unsigned int in_page; - - while (length) { - /* - * Determine step_len. - */ - step_len = length; - in_page = CHUNK_SIZE - (off & (CHUNK_SIZE-1)); - if (in_page < step_len) - step_len = in_page; - - /* - * Copy data and advance pointers. - */ - buf = this->b_vec[off / CHUNK_SIZE].ptr + off % CHUNK_SIZE; - if (copy_to_user(to, buf, step_len)) - return -EINVAL; - if ((off += step_len) >= this->b_size) off = 0; - to += step_len; - length -= step_len; - } - return 0; -} - -/* - * Allocate an (aligned) area in the buffer. - * This is called under b_lock. - * Returns ~0 on failure. - */ -static unsigned int mon_buff_area_alloc(struct mon_reader_bin *rp, - unsigned int size) -{ - unsigned int offset; - - size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1); - if (rp->b_cnt + size > rp->b_size) - return ~0; - offset = rp->b_in; - rp->b_cnt += size; - if ((rp->b_in += size) >= rp->b_size) - rp->b_in -= rp->b_size; - return offset; -} - -/* - * This is the same thing as mon_buff_area_alloc, only it does not allow - * buffers to wrap. This is needed by applications which pass references - * into mmap-ed buffers up their stacks (libpcap can do that). - * - * Currently, we always have the header stuck with the data, although - * it is not strictly speaking necessary. - * - * When a buffer would wrap, we place a filler packet to mark the space. - */ -static unsigned int mon_buff_area_alloc_contiguous(struct mon_reader_bin *rp, - unsigned int size) -{ - unsigned int offset; - unsigned int fill_size; - - size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1); - if (rp->b_cnt + size > rp->b_size) - return ~0; - if (rp->b_in + size > rp->b_size) { - /* - * This would wrap. Find if we still have space after - * skipping to the end of the buffer. If we do, place - * a filler packet and allocate a new packet. - */ - fill_size = rp->b_size - rp->b_in; - if (rp->b_cnt + size + fill_size > rp->b_size) - return ~0; - mon_buff_area_fill(rp, rp->b_in, fill_size); - - offset = 0; - rp->b_in = size; - rp->b_cnt += size + fill_size; - } else if (rp->b_in + size == rp->b_size) { - offset = rp->b_in; - rp->b_in = 0; - rp->b_cnt += size; - } else { - offset = rp->b_in; - rp->b_in += size; - rp->b_cnt += size; - } - return offset; -} - -/* - * Return a few (kilo-)bytes to the head of the buffer. - * This is used if a data fetch fails. - */ -static void mon_buff_area_shrink(struct mon_reader_bin *rp, unsigned int size) -{ - - /* size &= ~(PKT_ALIGN-1); -- we're called with aligned size */ - rp->b_cnt -= size; - if (rp->b_in < size) - rp->b_in += rp->b_size; - rp->b_in -= size; -} - -/* - * This has to be called under both b_lock and fetch_lock, because - * it accesses both b_cnt and b_out. - */ -static void mon_buff_area_free(struct mon_reader_bin *rp, unsigned int size) -{ - - size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1); - rp->b_cnt -= size; - if ((rp->b_out += size) >= rp->b_size) - rp->b_out -= rp->b_size; -} - -static void mon_buff_area_fill(const struct mon_reader_bin *rp, - unsigned int offset, unsigned int size) -{ - struct mon_bin_hdr *ep; - - ep = MON_OFF2HDR(rp, offset); - memset(ep, 0, PKT_SIZE); - ep->type = '@'; - ep->len_cap = size - PKT_SIZE; -} - -static inline char mon_bin_get_setup(unsigned char *setupb, - const struct urb *urb, char ev_type) -{ - - if (urb->setup_packet == NULL) - return 'Z'; - memcpy(setupb, urb->setup_packet, SETUP_LEN); - return 0; -} - -static unsigned int mon_bin_get_data(const struct mon_reader_bin *rp, - unsigned int offset, struct urb *urb, unsigned int length, - char *flag) -{ - int i; - struct scatterlist *sg; - unsigned int this_len; - - *flag = 0; - if (urb->num_sgs == 0) { - if (urb->transfer_buffer == NULL) { - *flag = 'Z'; - return length; - } - mon_copy_to_buff(rp, offset, urb->transfer_buffer, length); - length = 0; - - } else { - /* If IOMMU coalescing occurred, we cannot trust sg_page */ - if (urb->transfer_flags & URB_DMA_SG_COMBINED) { - *flag = 'D'; - return length; - } - - /* Copy up to the first non-addressable segment */ - for_each_sg(urb->sg, sg, urb->num_sgs, i) { - if (length == 0 || PageHighMem(sg_page(sg))) - break; - this_len = min_t(unsigned int, sg->length, length); - offset = mon_copy_to_buff(rp, offset, sg_virt(sg), - this_len); - length -= this_len; - } - if (i == 0) - *flag = 'D'; - } - - return length; -} - -/* - * This is the look-ahead pass in case of 'C Zi', when actual_length cannot - * be used to determine the length of the whole contiguous buffer. - */ -static unsigned int mon_bin_collate_isodesc(const struct mon_reader_bin *rp, - struct urb *urb, unsigned int ndesc) -{ - struct usb_iso_packet_descriptor *fp; - unsigned int length; - - length = 0; - fp = urb->iso_frame_desc; - while (ndesc-- != 0) { - if (fp->actual_length != 0) { - if (fp->offset + fp->actual_length > length) - length = fp->offset + fp->actual_length; - } - fp++; - } - return length; -} - -static void mon_bin_get_isodesc(const struct mon_reader_bin *rp, - unsigned int offset, struct urb *urb, char ev_type, unsigned int ndesc) -{ - struct mon_bin_isodesc *dp; - struct usb_iso_packet_descriptor *fp; - - fp = urb->iso_frame_desc; - while (ndesc-- != 0) { - dp = (struct mon_bin_isodesc *) - (rp->b_vec[offset / CHUNK_SIZE].ptr + offset % CHUNK_SIZE); - dp->iso_status = fp->status; - dp->iso_off = fp->offset; - dp->iso_len = (ev_type == 'S') ? fp->length : fp->actual_length; - dp->_pad = 0; - if ((offset += sizeof(struct mon_bin_isodesc)) >= rp->b_size) - offset = 0; - fp++; - } -} - -static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb, - char ev_type, int status) -{ - const struct usb_endpoint_descriptor *epd = &urb->ep->desc; - struct timeval ts; - unsigned long flags; - unsigned int urb_length; - unsigned int offset; - unsigned int length; - unsigned int delta; - unsigned int ndesc, lendesc; - unsigned char dir; - struct mon_bin_hdr *ep; - char data_tag = 0; - - do_gettimeofday(&ts); - - spin_lock_irqsave(&rp->b_lock, flags); - - /* - * Find the maximum allowable length, then allocate space. - */ - urb_length = (ev_type == 'S') ? - urb->transfer_buffer_length : urb->actual_length; - length = urb_length; - - if (usb_endpoint_xfer_isoc(epd)) { - if (urb->number_of_packets < 0) { - ndesc = 0; - } else if (urb->number_of_packets >= ISODESC_MAX) { - ndesc = ISODESC_MAX; - } else { - ndesc = urb->number_of_packets; - } - if (ev_type == 'C' && usb_urb_dir_in(urb)) - length = mon_bin_collate_isodesc(rp, urb, ndesc); - } else { - ndesc = 0; - } - lendesc = ndesc*sizeof(struct mon_bin_isodesc); - - /* not an issue unless there's a subtle bug in a HCD somewhere */ - if (length >= urb->transfer_buffer_length) - length = urb->transfer_buffer_length; - - if (length >= rp->b_size/5) - length = rp->b_size/5; - - if (usb_urb_dir_in(urb)) { - if (ev_type == 'S') { - length = 0; - data_tag = '<'; - } - /* Cannot rely on endpoint number in case of control ep.0 */ - dir = USB_DIR_IN; - } else { - if (ev_type == 'C') { - length = 0; - data_tag = '>'; - } - dir = 0; - } - - if (rp->mmap_active) { - offset = mon_buff_area_alloc_contiguous(rp, - length + PKT_SIZE + lendesc); - } else { - offset = mon_buff_area_alloc(rp, length + PKT_SIZE + lendesc); - } - if (offset == ~0) { - rp->cnt_lost++; - spin_unlock_irqrestore(&rp->b_lock, flags); - return; - } - - ep = MON_OFF2HDR(rp, offset); - if ((offset += PKT_SIZE) >= rp->b_size) offset = 0; - - /* - * Fill the allocated area. - */ - memset(ep, 0, PKT_SIZE); - ep->type = ev_type; - ep->xfer_type = xfer_to_pipe[usb_endpoint_type(epd)]; - ep->epnum = dir | usb_endpoint_num(epd); - ep->devnum = urb->dev->devnum; - ep->busnum = urb->dev->bus->busnum; - ep->id = (unsigned long) urb; - ep->ts_sec = ts.tv_sec; - ep->ts_usec = ts.tv_usec; - ep->status = status; - ep->len_urb = urb_length; - ep->len_cap = length + lendesc; - ep->xfer_flags = urb->transfer_flags; - - if (usb_endpoint_xfer_int(epd)) { - ep->interval = urb->interval; - } else if (usb_endpoint_xfer_isoc(epd)) { - ep->interval = urb->interval; - ep->start_frame = urb->start_frame; - ep->s.iso.error_count = urb->error_count; - ep->s.iso.numdesc = urb->number_of_packets; - } - - if (usb_endpoint_xfer_control(epd) && ev_type == 'S') { - ep->flag_setup = mon_bin_get_setup(ep->s.setup, urb, ev_type); - } else { - ep->flag_setup = '-'; - } - - if (ndesc != 0) { - ep->ndesc = ndesc; - mon_bin_get_isodesc(rp, offset, urb, ev_type, ndesc); - if ((offset += lendesc) >= rp->b_size) - offset -= rp->b_size; - } - - if (length != 0) { - length = mon_bin_get_data(rp, offset, urb, length, - &ep->flag_data); - if (length > 0) { - delta = (ep->len_cap + PKT_ALIGN-1) & ~(PKT_ALIGN-1); - ep->len_cap -= length; - delta -= (ep->len_cap + PKT_ALIGN-1) & ~(PKT_ALIGN-1); - mon_buff_area_shrink(rp, delta); - } - } else { - ep->flag_data = data_tag; - } - - spin_unlock_irqrestore(&rp->b_lock, flags); - - wake_up(&rp->b_wait); -} - -static void mon_bin_submit(void *data, struct urb *urb) -{ - struct mon_reader_bin *rp = data; - mon_bin_event(rp, urb, 'S', -EINPROGRESS); -} - -static void mon_bin_complete(void *data, struct urb *urb, int status) -{ - struct mon_reader_bin *rp = data; - mon_bin_event(rp, urb, 'C', status); -} - -static void mon_bin_error(void *data, struct urb *urb, int error) -{ - struct mon_reader_bin *rp = data; - struct timeval ts; - unsigned long flags; - unsigned int offset; - struct mon_bin_hdr *ep; - - do_gettimeofday(&ts); - - spin_lock_irqsave(&rp->b_lock, flags); - - offset = mon_buff_area_alloc(rp, PKT_SIZE); - if (offset == ~0) { - /* Not incrementing cnt_lost. Just because. */ - spin_unlock_irqrestore(&rp->b_lock, flags); - return; - } - - ep = MON_OFF2HDR(rp, offset); - - memset(ep, 0, PKT_SIZE); - ep->type = 'E'; - ep->xfer_type = xfer_to_pipe[usb_endpoint_type(&urb->ep->desc)]; - ep->epnum = usb_urb_dir_in(urb) ? USB_DIR_IN : 0; - ep->epnum |= usb_endpoint_num(&urb->ep->desc); - ep->devnum = urb->dev->devnum; - ep->busnum = urb->dev->bus->busnum; - ep->id = (unsigned long) urb; - ep->ts_sec = ts.tv_sec; - ep->ts_usec = ts.tv_usec; - ep->status = error; - - ep->flag_setup = '-'; - ep->flag_data = 'E'; - - spin_unlock_irqrestore(&rp->b_lock, flags); - - wake_up(&rp->b_wait); -} - -static int mon_bin_open(struct inode *inode, struct file *file) -{ - struct mon_bus *mbus; - struct mon_reader_bin *rp; - size_t size; - int rc; - - mutex_lock(&mon_lock); - if ((mbus = mon_bus_lookup(iminor(inode))) == NULL) { - mutex_unlock(&mon_lock); - return -ENODEV; - } - if (mbus != &mon_bus0 && mbus->u_bus == NULL) { - printk(KERN_ERR TAG ": consistency error on open\n"); - mutex_unlock(&mon_lock); - return -ENODEV; - } - - rp = kzalloc(sizeof(struct mon_reader_bin), GFP_KERNEL); - if (rp == NULL) { - rc = -ENOMEM; - goto err_alloc; - } - spin_lock_init(&rp->b_lock); - init_waitqueue_head(&rp->b_wait); - mutex_init(&rp->fetch_lock); - rp->b_size = BUFF_DFL; - - size = sizeof(struct mon_pgmap) * (rp->b_size/CHUNK_SIZE); - if ((rp->b_vec = kzalloc(size, GFP_KERNEL)) == NULL) { - rc = -ENOMEM; - goto err_allocvec; - } - - if ((rc = mon_alloc_buff(rp->b_vec, rp->b_size/CHUNK_SIZE)) < 0) - goto err_allocbuff; - - rp->r.m_bus = mbus; - rp->r.r_data = rp; - rp->r.rnf_submit = mon_bin_submit; - rp->r.rnf_error = mon_bin_error; - rp->r.rnf_complete = mon_bin_complete; - - mon_reader_add(mbus, &rp->r); - - file->private_data = rp; - mutex_unlock(&mon_lock); - return 0; - -err_allocbuff: - kfree(rp->b_vec); -err_allocvec: - kfree(rp); -err_alloc: - mutex_unlock(&mon_lock); - return rc; -} - -/* - * Extract an event from buffer and copy it to user space. - * Wait if there is no event ready. - * Returns zero or error. - */ -static int mon_bin_get_event(struct file *file, struct mon_reader_bin *rp, - struct mon_bin_hdr __user *hdr, unsigned int hdrbytes, - void __user *data, unsigned int nbytes) -{ - unsigned long flags; - struct mon_bin_hdr *ep; - size_t step_len; - unsigned int offset; - int rc; - - mutex_lock(&rp->fetch_lock); - - if ((rc = mon_bin_wait_event(file, rp)) < 0) { - mutex_unlock(&rp->fetch_lock); - return rc; - } - - ep = MON_OFF2HDR(rp, rp->b_out); - - if (copy_to_user(hdr, ep, hdrbytes)) { - mutex_unlock(&rp->fetch_lock); - return -EFAULT; - } - - step_len = min(ep->len_cap, nbytes); - if ((offset = rp->b_out + PKT_SIZE) >= rp->b_size) offset = 0; - - if (copy_from_buf(rp, offset, data, step_len)) { - mutex_unlock(&rp->fetch_lock); - return -EFAULT; - } - - spin_lock_irqsave(&rp->b_lock, flags); - mon_buff_area_free(rp, PKT_SIZE + ep->len_cap); - spin_unlock_irqrestore(&rp->b_lock, flags); - rp->b_read = 0; - - mutex_unlock(&rp->fetch_lock); - return 0; -} - -static int mon_bin_release(struct inode *inode, struct file *file) -{ - struct mon_reader_bin *rp = file->private_data; - struct mon_bus* mbus = rp->r.m_bus; - - mutex_lock(&mon_lock); - - if (mbus->nreaders <= 0) { - printk(KERN_ERR TAG ": consistency error on close\n"); - mutex_unlock(&mon_lock); - return 0; - } - mon_reader_del(mbus, &rp->r); - - mon_free_buff(rp->b_vec, rp->b_size/CHUNK_SIZE); - kfree(rp->b_vec); - kfree(rp); - - mutex_unlock(&mon_lock); - return 0; -} - -static ssize_t mon_bin_read(struct file *file, char __user *buf, - size_t nbytes, loff_t *ppos) -{ - struct mon_reader_bin *rp = file->private_data; - unsigned int hdrbytes = PKT_SZ_API0; - unsigned long flags; - struct mon_bin_hdr *ep; - unsigned int offset; - size_t step_len; - char *ptr; - ssize_t done = 0; - int rc; - - mutex_lock(&rp->fetch_lock); - - if ((rc = mon_bin_wait_event(file, rp)) < 0) { - mutex_unlock(&rp->fetch_lock); - return rc; - } - - ep = MON_OFF2HDR(rp, rp->b_out); - - if (rp->b_read < hdrbytes) { - step_len = min(nbytes, (size_t)(hdrbytes - rp->b_read)); - ptr = ((char *)ep) + rp->b_read; - if (step_len && copy_to_user(buf, ptr, step_len)) { - mutex_unlock(&rp->fetch_lock); - return -EFAULT; - } - nbytes -= step_len; - buf += step_len; - rp->b_read += step_len; - done += step_len; - } - - if (rp->b_read >= hdrbytes) { - step_len = ep->len_cap; - step_len -= rp->b_read - hdrbytes; - if (step_len > nbytes) - step_len = nbytes; - offset = rp->b_out + PKT_SIZE; - offset += rp->b_read - hdrbytes; - if (offset >= rp->b_size) - offset -= rp->b_size; - if (copy_from_buf(rp, offset, buf, step_len)) { - mutex_unlock(&rp->fetch_lock); - return -EFAULT; - } - nbytes -= step_len; - buf += step_len; - rp->b_read += step_len; - done += step_len; - } - - /* - * Check if whole packet was read, and if so, jump to the next one. - */ - if (rp->b_read >= hdrbytes + ep->len_cap) { - spin_lock_irqsave(&rp->b_lock, flags); - mon_buff_area_free(rp, PKT_SIZE + ep->len_cap); - spin_unlock_irqrestore(&rp->b_lock, flags); - rp->b_read = 0; - } - - mutex_unlock(&rp->fetch_lock); - return done; -} - -/* - * Remove at most nevents from chunked buffer. - * Returns the number of removed events. - */ -static int mon_bin_flush(struct mon_reader_bin *rp, unsigned nevents) -{ - unsigned long flags; - struct mon_bin_hdr *ep; - int i; - - mutex_lock(&rp->fetch_lock); - spin_lock_irqsave(&rp->b_lock, flags); - for (i = 0; i < nevents; ++i) { - if (MON_RING_EMPTY(rp)) - break; - - ep = MON_OFF2HDR(rp, rp->b_out); - mon_buff_area_free(rp, PKT_SIZE + ep->len_cap); - } - spin_unlock_irqrestore(&rp->b_lock, flags); - rp->b_read = 0; - mutex_unlock(&rp->fetch_lock); - return i; -} - -/* - * Fetch at most max event offsets into the buffer and put them into vec. - * The events are usually freed later with mon_bin_flush. - * Return the effective number of events fetched. - */ -static int mon_bin_fetch(struct file *file, struct mon_reader_bin *rp, - u32 __user *vec, unsigned int max) -{ - unsigned int cur_out; - unsigned int bytes, avail; - unsigned int size; - unsigned int nevents; - struct mon_bin_hdr *ep; - unsigned long flags; - int rc; - - mutex_lock(&rp->fetch_lock); - - if ((rc = mon_bin_wait_event(file, rp)) < 0) { - mutex_unlock(&rp->fetch_lock); - return rc; - } - - spin_lock_irqsave(&rp->b_lock, flags); - avail = rp->b_cnt; - spin_unlock_irqrestore(&rp->b_lock, flags); - - cur_out = rp->b_out; - nevents = 0; - bytes = 0; - while (bytes < avail) { - if (nevents >= max) - break; - - ep = MON_OFF2HDR(rp, cur_out); - if (put_user(cur_out, &vec[nevents])) { - mutex_unlock(&rp->fetch_lock); - return -EFAULT; - } - - nevents++; - size = ep->len_cap + PKT_SIZE; - size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1); - if ((cur_out += size) >= rp->b_size) - cur_out -= rp->b_size; - bytes += size; - } - - mutex_unlock(&rp->fetch_lock); - return nevents; -} - -/* - * Count events. This is almost the same as the above mon_bin_fetch, - * only we do not store offsets into user vector, and we have no limit. - */ -static int mon_bin_queued(struct mon_reader_bin *rp) -{ - unsigned int cur_out; - unsigned int bytes, avail; - unsigned int size; - unsigned int nevents; - struct mon_bin_hdr *ep; - unsigned long flags; - - mutex_lock(&rp->fetch_lock); - - spin_lock_irqsave(&rp->b_lock, flags); - avail = rp->b_cnt; - spin_unlock_irqrestore(&rp->b_lock, flags); - - cur_out = rp->b_out; - nevents = 0; - bytes = 0; - while (bytes < avail) { - ep = MON_OFF2HDR(rp, cur_out); - - nevents++; - size = ep->len_cap + PKT_SIZE; - size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1); - if ((cur_out += size) >= rp->b_size) - cur_out -= rp->b_size; - bytes += size; - } - - mutex_unlock(&rp->fetch_lock); - return nevents; -} - -/* - */ -static long mon_bin_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct mon_reader_bin *rp = file->private_data; - // struct mon_bus* mbus = rp->r.m_bus; - int ret = 0; - struct mon_bin_hdr *ep; - unsigned long flags; - - switch (cmd) { - - case MON_IOCQ_URB_LEN: - /* - * N.B. This only returns the size of data, without the header. - */ - spin_lock_irqsave(&rp->b_lock, flags); - if (!MON_RING_EMPTY(rp)) { - ep = MON_OFF2HDR(rp, rp->b_out); - ret = ep->len_cap; - } - spin_unlock_irqrestore(&rp->b_lock, flags); - break; - - case MON_IOCQ_RING_SIZE: - ret = rp->b_size; - break; - - case MON_IOCT_RING_SIZE: - /* - * Changing the buffer size will flush it's contents; the new - * buffer is allocated before releasing the old one to be sure - * the device will stay functional also in case of memory - * pressure. - */ - { - int size; - struct mon_pgmap *vec; - - if (arg < BUFF_MIN || arg > BUFF_MAX) - return -EINVAL; - - size = CHUNK_ALIGN(arg); - if ((vec = kzalloc(sizeof(struct mon_pgmap) * (size/CHUNK_SIZE), - GFP_KERNEL)) == NULL) { - ret = -ENOMEM; - break; - } - - ret = mon_alloc_buff(vec, size/CHUNK_SIZE); - if (ret < 0) { - kfree(vec); - break; - } - - mutex_lock(&rp->fetch_lock); - spin_lock_irqsave(&rp->b_lock, flags); - mon_free_buff(rp->b_vec, rp->b_size/CHUNK_SIZE); - kfree(rp->b_vec); - rp->b_vec = vec; - rp->b_size = size; - rp->b_read = rp->b_in = rp->b_out = rp->b_cnt = 0; - rp->cnt_lost = 0; - spin_unlock_irqrestore(&rp->b_lock, flags); - mutex_unlock(&rp->fetch_lock); - } - break; - - case MON_IOCH_MFLUSH: - ret = mon_bin_flush(rp, arg); - break; - - case MON_IOCX_GET: - case MON_IOCX_GETX: - { - struct mon_bin_get getb; - - if (copy_from_user(&getb, (void __user *)arg, - sizeof(struct mon_bin_get))) - return -EFAULT; - - if (getb.alloc > 0x10000000) /* Want to cast to u32 */ - return -EINVAL; - ret = mon_bin_get_event(file, rp, getb.hdr, - (cmd == MON_IOCX_GET)? PKT_SZ_API0: PKT_SZ_API1, - getb.data, (unsigned int)getb.alloc); - } - break; - - case MON_IOCX_MFETCH: - { - struct mon_bin_mfetch mfetch; - struct mon_bin_mfetch __user *uptr; - - uptr = (struct mon_bin_mfetch __user *)arg; - - if (copy_from_user(&mfetch, uptr, sizeof(mfetch))) - return -EFAULT; - - if (mfetch.nflush) { - ret = mon_bin_flush(rp, mfetch.nflush); - if (ret < 0) - return ret; - if (put_user(ret, &uptr->nflush)) - return -EFAULT; - } - ret = mon_bin_fetch(file, rp, mfetch.offvec, mfetch.nfetch); - if (ret < 0) - return ret; - if (put_user(ret, &uptr->nfetch)) - return -EFAULT; - ret = 0; - } - break; - - case MON_IOCG_STATS: { - struct mon_bin_stats __user *sp; - unsigned int nevents; - unsigned int ndropped; - - spin_lock_irqsave(&rp->b_lock, flags); - ndropped = rp->cnt_lost; - rp->cnt_lost = 0; - spin_unlock_irqrestore(&rp->b_lock, flags); - nevents = mon_bin_queued(rp); - - sp = (struct mon_bin_stats __user *)arg; - if (put_user(ndropped, &sp->dropped)) - return -EFAULT; - if (put_user(nevents, &sp->queued)) - return -EFAULT; - - } - break; - - default: - return -ENOTTY; - } - - return ret; -} - -#ifdef CONFIG_COMPAT -static long mon_bin_compat_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct mon_reader_bin *rp = file->private_data; - int ret; - - switch (cmd) { - - case MON_IOCX_GET32: - case MON_IOCX_GETX32: - { - struct mon_bin_get32 getb; - - if (copy_from_user(&getb, (void __user *)arg, - sizeof(struct mon_bin_get32))) - return -EFAULT; - - ret = mon_bin_get_event(file, rp, compat_ptr(getb.hdr32), - (cmd == MON_IOCX_GET32)? PKT_SZ_API0: PKT_SZ_API1, - compat_ptr(getb.data32), getb.alloc32); - if (ret < 0) - return ret; - } - return 0; - - case MON_IOCX_MFETCH32: - { - struct mon_bin_mfetch32 mfetch; - struct mon_bin_mfetch32 __user *uptr; - - uptr = (struct mon_bin_mfetch32 __user *) compat_ptr(arg); - - if (copy_from_user(&mfetch, uptr, sizeof(mfetch))) - return -EFAULT; - - if (mfetch.nflush32) { - ret = mon_bin_flush(rp, mfetch.nflush32); - if (ret < 0) - return ret; - if (put_user(ret, &uptr->nflush32)) - return -EFAULT; - } - ret = mon_bin_fetch(file, rp, compat_ptr(mfetch.offvec32), - mfetch.nfetch32); - if (ret < 0) - return ret; - if (put_user(ret, &uptr->nfetch32)) - return -EFAULT; - } - return 0; - - case MON_IOCG_STATS: - return mon_bin_ioctl(file, cmd, (unsigned long) compat_ptr(arg)); - - case MON_IOCQ_URB_LEN: - case MON_IOCQ_RING_SIZE: - case MON_IOCT_RING_SIZE: - case MON_IOCH_MFLUSH: - return mon_bin_ioctl(file, cmd, arg); - - default: - ; - } - return -ENOTTY; -} -#endif /* CONFIG_COMPAT */ - -static unsigned int -mon_bin_poll(struct file *file, struct poll_table_struct *wait) -{ - struct mon_reader_bin *rp = file->private_data; - unsigned int mask = 0; - unsigned long flags; - - if (file->f_mode & FMODE_READ) - poll_wait(file, &rp->b_wait, wait); - - spin_lock_irqsave(&rp->b_lock, flags); - if (!MON_RING_EMPTY(rp)) - mask |= POLLIN | POLLRDNORM; /* readable */ - spin_unlock_irqrestore(&rp->b_lock, flags); - return mask; -} - -/* - * open and close: just keep track of how many times the device is - * mapped, to use the proper memory allocation function. - */ -static void mon_bin_vma_open(struct vm_area_struct *vma) -{ - struct mon_reader_bin *rp = vma->vm_private_data; - rp->mmap_active++; -} - -static void mon_bin_vma_close(struct vm_area_struct *vma) -{ - struct mon_reader_bin *rp = vma->vm_private_data; - rp->mmap_active--; -} - -/* - * Map ring pages to user space. - */ -static int mon_bin_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - struct mon_reader_bin *rp = vma->vm_private_data; - unsigned long offset, chunk_idx; - struct page *pageptr; - - offset = vmf->pgoff << PAGE_SHIFT; - if (offset >= rp->b_size) - return VM_FAULT_SIGBUS; - chunk_idx = offset / CHUNK_SIZE; - pageptr = rp->b_vec[chunk_idx].pg; - get_page(pageptr); - vmf->page = pageptr; - return 0; -} - -static const struct vm_operations_struct mon_bin_vm_ops = { - .open = mon_bin_vma_open, - .close = mon_bin_vma_close, - .fault = mon_bin_vma_fault, -}; - -static int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma) -{ - /* don't do anything here: "fault" will set up page table entries */ - vma->vm_ops = &mon_bin_vm_ops; - vma->vm_flags |= VM_RESERVED; - vma->vm_private_data = filp->private_data; - mon_bin_vma_open(vma); - return 0; -} - -static const struct file_operations mon_fops_binary = { - .owner = THIS_MODULE, - .open = mon_bin_open, - .llseek = no_llseek, - .read = mon_bin_read, - /* .write = mon_text_write, */ - .poll = mon_bin_poll, - .unlocked_ioctl = mon_bin_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = mon_bin_compat_ioctl, -#endif - .release = mon_bin_release, - .mmap = mon_bin_mmap, -}; - -static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp) -{ - DECLARE_WAITQUEUE(waita, current); - unsigned long flags; - - add_wait_queue(&rp->b_wait, &waita); - set_current_state(TASK_INTERRUPTIBLE); - - spin_lock_irqsave(&rp->b_lock, flags); - while (MON_RING_EMPTY(rp)) { - spin_unlock_irqrestore(&rp->b_lock, flags); - - if (file->f_flags & O_NONBLOCK) { - set_current_state(TASK_RUNNING); - remove_wait_queue(&rp->b_wait, &waita); - return -EWOULDBLOCK; /* Same as EAGAIN in Linux */ - } - schedule(); - if (signal_pending(current)) { - remove_wait_queue(&rp->b_wait, &waita); - return -EINTR; - } - set_current_state(TASK_INTERRUPTIBLE); - - spin_lock_irqsave(&rp->b_lock, flags); - } - spin_unlock_irqrestore(&rp->b_lock, flags); - - set_current_state(TASK_RUNNING); - remove_wait_queue(&rp->b_wait, &waita); - return 0; -} - -static int mon_alloc_buff(struct mon_pgmap *map, int npages) -{ - int n; - unsigned long vaddr; - - for (n = 0; n < npages; n++) { - vaddr = get_zeroed_page(GFP_KERNEL); - if (vaddr == 0) { - while (n-- != 0) - free_page((unsigned long) map[n].ptr); - return -ENOMEM; - } - map[n].ptr = (unsigned char *) vaddr; - map[n].pg = virt_to_page((void *) vaddr); - } - return 0; -} - -static void mon_free_buff(struct mon_pgmap *map, int npages) -{ - int n; - - for (n = 0; n < npages; n++) - free_page((unsigned long) map[n].ptr); -} - -int mon_bin_add(struct mon_bus *mbus, const struct usb_bus *ubus) -{ - struct device *dev; - unsigned minor = ubus? ubus->busnum: 0; - - if (minor >= MON_BIN_MAX_MINOR) - return 0; - - dev = device_create(mon_bin_class, ubus ? ubus->controller : NULL, - MKDEV(MAJOR(mon_bin_dev0), minor), NULL, - "usbmon%d", minor); - if (IS_ERR(dev)) - return 0; - - mbus->classdev = dev; - return 1; -} - -void mon_bin_del(struct mon_bus *mbus) -{ - device_destroy(mon_bin_class, mbus->classdev->devt); -} - -int __init mon_bin_init(void) -{ - int rc; - - mon_bin_class = class_create(THIS_MODULE, "usbmon"); - if (IS_ERR(mon_bin_class)) { - rc = PTR_ERR(mon_bin_class); - goto err_class; - } - - rc = alloc_chrdev_region(&mon_bin_dev0, 0, MON_BIN_MAX_MINOR, "usbmon"); - if (rc < 0) - goto err_dev; - - cdev_init(&mon_bin_cdev, &mon_fops_binary); - mon_bin_cdev.owner = THIS_MODULE; - - rc = cdev_add(&mon_bin_cdev, mon_bin_dev0, MON_BIN_MAX_MINOR); - if (rc < 0) - goto err_add; - - return 0; - -err_add: - unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR); -err_dev: - class_destroy(mon_bin_class); -err_class: - return rc; -} - -void mon_bin_exit(void) -{ - cdev_del(&mon_bin_cdev); - unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR); - class_destroy(mon_bin_class); -} diff --git a/ANDROID_3.4.5/drivers/usb/mon/mon_main.c b/ANDROID_3.4.5/drivers/usb/mon/mon_main.c deleted file mode 100644 index 10405119..00000000 --- a/ANDROID_3.4.5/drivers/usb/mon/mon_main.c +++ /dev/null @@ -1,431 +0,0 @@ -/* - * The USB Monitor, inspired by Dave Harding's USBMon. - * - * mon_main.c: Main file, module initiation and exit, registrations, etc. - * - * Copyright (C) 2005 Pete Zaitcev (zaitcev@redhat.com) - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "usb_mon.h" - - -static void mon_stop(struct mon_bus *mbus); -static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus); -static void mon_bus_drop(struct kref *r); -static void mon_bus_init(struct usb_bus *ubus); - -DEFINE_MUTEX(mon_lock); - -struct mon_bus mon_bus0; /* Pseudo bus meaning "all buses" */ -static LIST_HEAD(mon_buses); /* All buses we know: struct mon_bus */ - -/* - * Link a reader into the bus. - * - * This must be called with mon_lock taken because of mbus->ref. - */ -void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r) -{ - unsigned long flags; - struct list_head *p; - - spin_lock_irqsave(&mbus->lock, flags); - if (mbus->nreaders == 0) { - if (mbus == &mon_bus0) { - list_for_each (p, &mon_buses) { - struct mon_bus *m1; - m1 = list_entry(p, struct mon_bus, bus_link); - m1->u_bus->monitored = 1; - } - } else { - mbus->u_bus->monitored = 1; - } - } - mbus->nreaders++; - list_add_tail(&r->r_link, &mbus->r_list); - spin_unlock_irqrestore(&mbus->lock, flags); - - kref_get(&mbus->ref); -} - -/* - * Unlink reader from the bus. - * - * This is called with mon_lock taken, so we can decrement mbus->ref. - */ -void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r) -{ - unsigned long flags; - - spin_lock_irqsave(&mbus->lock, flags); - list_del(&r->r_link); - --mbus->nreaders; - if (mbus->nreaders == 0) - mon_stop(mbus); - spin_unlock_irqrestore(&mbus->lock, flags); - - kref_put(&mbus->ref, mon_bus_drop); -} - -/* - */ -static void mon_bus_submit(struct mon_bus *mbus, struct urb *urb) -{ - unsigned long flags; - struct list_head *pos; - struct mon_reader *r; - - spin_lock_irqsave(&mbus->lock, flags); - mbus->cnt_events++; - list_for_each (pos, &mbus->r_list) { - r = list_entry(pos, struct mon_reader, r_link); - r->rnf_submit(r->r_data, urb); - } - spin_unlock_irqrestore(&mbus->lock, flags); -} - -static void mon_submit(struct usb_bus *ubus, struct urb *urb) -{ - struct mon_bus *mbus; - - if ((mbus = ubus->mon_bus) != NULL) - mon_bus_submit(mbus, urb); - mon_bus_submit(&mon_bus0, urb); -} - -/* - */ -static void mon_bus_submit_error(struct mon_bus *mbus, struct urb *urb, int error) -{ - unsigned long flags; - struct list_head *pos; - struct mon_reader *r; - - spin_lock_irqsave(&mbus->lock, flags); - mbus->cnt_events++; - list_for_each (pos, &mbus->r_list) { - r = list_entry(pos, struct mon_reader, r_link); - r->rnf_error(r->r_data, urb, error); - } - spin_unlock_irqrestore(&mbus->lock, flags); -} - -static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error) -{ - struct mon_bus *mbus; - - if ((mbus = ubus->mon_bus) != NULL) - mon_bus_submit_error(mbus, urb, error); - mon_bus_submit_error(&mon_bus0, urb, error); -} - -/* - */ -static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb, int status) -{ - unsigned long flags; - struct list_head *pos; - struct mon_reader *r; - - spin_lock_irqsave(&mbus->lock, flags); - mbus->cnt_events++; - list_for_each (pos, &mbus->r_list) { - r = list_entry(pos, struct mon_reader, r_link); - r->rnf_complete(r->r_data, urb, status); - } - spin_unlock_irqrestore(&mbus->lock, flags); -} - -static void mon_complete(struct usb_bus *ubus, struct urb *urb, int status) -{ - struct mon_bus *mbus; - - if ((mbus = ubus->mon_bus) != NULL) - mon_bus_complete(mbus, urb, status); - mon_bus_complete(&mon_bus0, urb, status); -} - -/* int (*unlink_urb) (struct urb *urb, int status); */ - -/* - * Stop monitoring. - */ -static void mon_stop(struct mon_bus *mbus) -{ - struct usb_bus *ubus; - struct list_head *p; - - if (mbus == &mon_bus0) { - list_for_each (p, &mon_buses) { - mbus = list_entry(p, struct mon_bus, bus_link); - /* - * We do not change nreaders here, so rely on mon_lock. - */ - if (mbus->nreaders == 0 && (ubus = mbus->u_bus) != NULL) - ubus->monitored = 0; - } - } else { - /* - * A stop can be called for a dissolved mon_bus in case of - * a reader staying across an rmmod foo_hcd, so test ->u_bus. - */ - if (mon_bus0.nreaders == 0 && (ubus = mbus->u_bus) != NULL) { - ubus->monitored = 0; - mb(); - } - } -} - -/* - * Add a USB bus (usually by a modprobe foo-hcd) - * - * This does not return an error code because the core cannot care less - * if monitoring is not established. - */ -static void mon_bus_add(struct usb_bus *ubus) -{ - mon_bus_init(ubus); - mutex_lock(&mon_lock); - if (mon_bus0.nreaders != 0) - ubus->monitored = 1; - mutex_unlock(&mon_lock); -} - -/* - * Remove a USB bus (either from rmmod foo-hcd or from a hot-remove event). - */ -static void mon_bus_remove(struct usb_bus *ubus) -{ - struct mon_bus *mbus = ubus->mon_bus; - - mutex_lock(&mon_lock); - list_del(&mbus->bus_link); - if (mbus->text_inited) - mon_text_del(mbus); - if (mbus->bin_inited) - mon_bin_del(mbus); - - mon_dissolve(mbus, ubus); - kref_put(&mbus->ref, mon_bus_drop); - mutex_unlock(&mon_lock); -} - -static int mon_notify(struct notifier_block *self, unsigned long action, - void *dev) -{ - switch (action) { - case USB_BUS_ADD: - mon_bus_add(dev); - break; - case USB_BUS_REMOVE: - mon_bus_remove(dev); - } - return NOTIFY_OK; -} - -static struct notifier_block mon_nb = { - .notifier_call = mon_notify, -}; - -/* - * Ops - */ -static struct usb_mon_operations mon_ops_0 = { - .urb_submit = mon_submit, - .urb_submit_error = mon_submit_error, - .urb_complete = mon_complete, -}; - -/* - * Tear usb_bus and mon_bus apart. - */ -static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus) -{ - - if (ubus->monitored) { - ubus->monitored = 0; - mb(); - } - - ubus->mon_bus = NULL; - mbus->u_bus = NULL; - mb(); - - /* We want synchronize_irq() here, but that needs an argument. */ -} - -/* - */ -static void mon_bus_drop(struct kref *r) -{ - struct mon_bus *mbus = container_of(r, struct mon_bus, ref); - kfree(mbus); -} - -/* - * Initialize a bus for us: - * - allocate mon_bus - * - refcount USB bus struct - * - link - */ -static void mon_bus_init(struct usb_bus *ubus) -{ - struct mon_bus *mbus; - - if ((mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL) - goto err_alloc; - kref_init(&mbus->ref); - spin_lock_init(&mbus->lock); - INIT_LIST_HEAD(&mbus->r_list); - - /* - * We don't need to take a reference to ubus, because we receive - * a notification if the bus is about to be removed. - */ - mbus->u_bus = ubus; - ubus->mon_bus = mbus; - - mbus->text_inited = mon_text_add(mbus, ubus); - mbus->bin_inited = mon_bin_add(mbus, ubus); - - mutex_lock(&mon_lock); - list_add_tail(&mbus->bus_link, &mon_buses); - mutex_unlock(&mon_lock); - return; - -err_alloc: - return; -} - -static void mon_bus0_init(void) -{ - struct mon_bus *mbus = &mon_bus0; - - kref_init(&mbus->ref); - spin_lock_init(&mbus->lock); - INIT_LIST_HEAD(&mbus->r_list); - - mbus->text_inited = mon_text_add(mbus, NULL); - mbus->bin_inited = mon_bin_add(mbus, NULL); -} - -/* - * Search a USB bus by number. Notice that USB bus numbers start from one, - * which we may later use to identify "all" with zero. - * - * This function must be called with mon_lock held. - * - * This is obviously inefficient and may be revised in the future. - */ -struct mon_bus *mon_bus_lookup(unsigned int num) -{ - struct list_head *p; - struct mon_bus *mbus; - - if (num == 0) { - return &mon_bus0; - } - list_for_each (p, &mon_buses) { - mbus = list_entry(p, struct mon_bus, bus_link); - if (mbus->u_bus->busnum == num) { - return mbus; - } - } - return NULL; -} - -static int __init mon_init(void) -{ - struct usb_bus *ubus; - int rc; - - if ((rc = mon_text_init()) != 0) - goto err_text; - if ((rc = mon_bin_init()) != 0) - goto err_bin; - - mon_bus0_init(); - - if (usb_mon_register(&mon_ops_0) != 0) { - printk(KERN_NOTICE TAG ": unable to register with the core\n"); - rc = -ENODEV; - goto err_reg; - } - // MOD_INC_USE_COUNT(which_module?); - - mutex_lock(&usb_bus_list_lock); - list_for_each_entry (ubus, &usb_bus_list, bus_list) { - mon_bus_init(ubus); - } - usb_register_notify(&mon_nb); - mutex_unlock(&usb_bus_list_lock); - return 0; - -err_reg: - mon_bin_exit(); -err_bin: - mon_text_exit(); -err_text: - return rc; -} - -static void __exit mon_exit(void) -{ - struct mon_bus *mbus; - struct list_head *p; - - usb_unregister_notify(&mon_nb); - usb_mon_deregister(); - - mutex_lock(&mon_lock); - - while (!list_empty(&mon_buses)) { - p = mon_buses.next; - mbus = list_entry(p, struct mon_bus, bus_link); - list_del(p); - - if (mbus->text_inited) - mon_text_del(mbus); - if (mbus->bin_inited) - mon_bin_del(mbus); - - /* - * This never happens, because the open/close paths in - * file level maintain module use counters and so rmmod fails - * before reaching here. However, better be safe... - */ - if (mbus->nreaders) { - printk(KERN_ERR TAG - ": Outstanding opens (%d) on usb%d, leaking...\n", - mbus->nreaders, mbus->u_bus->busnum); - atomic_set(&mbus->ref.refcount, 2); /* Force leak */ - } - - mon_dissolve(mbus, mbus->u_bus); - kref_put(&mbus->ref, mon_bus_drop); - } - - mbus = &mon_bus0; - if (mbus->text_inited) - mon_text_del(mbus); - if (mbus->bin_inited) - mon_bin_del(mbus); - - mutex_unlock(&mon_lock); - - mon_text_exit(); - mon_bin_exit(); -} - -module_init(mon_init); -module_exit(mon_exit); - -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/mon/mon_stat.c b/ANDROID_3.4.5/drivers/usb/mon/mon_stat.c deleted file mode 100644 index ebd6189a..00000000 --- a/ANDROID_3.4.5/drivers/usb/mon/mon_stat.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * The USB Monitor, inspired by Dave Harding's USBMon. - * - * This is the 's' or 'stat' reader which debugs usbmon itself. - * Note that this code blows through locks, so make sure that - * /dbg/usbmon/0s is well protected from non-root users. - * - */ - -#include -#include -#include -#include -#include -#include - -#include "usb_mon.h" - -#define STAT_BUF_SIZE 80 - -struct snap { - int slen; - char str[STAT_BUF_SIZE]; -}; - -static int mon_stat_open(struct inode *inode, struct file *file) -{ - struct mon_bus *mbus; - struct snap *sp; - - if ((sp = kmalloc(sizeof(struct snap), GFP_KERNEL)) == NULL) - return -ENOMEM; - - mbus = inode->i_private; - - sp->slen = snprintf(sp->str, STAT_BUF_SIZE, - "nreaders %d events %u text_lost %u\n", - mbus->nreaders, mbus->cnt_events, mbus->cnt_text_lost); - - file->private_data = sp; - return 0; -} - -static ssize_t mon_stat_read(struct file *file, char __user *buf, - size_t nbytes, loff_t *ppos) -{ - struct snap *sp = file->private_data; - - return simple_read_from_buffer(buf, nbytes, ppos, sp->str, sp->slen); -} - -static int mon_stat_release(struct inode *inode, struct file *file) -{ - struct snap *sp = file->private_data; - file->private_data = NULL; - kfree(sp); - return 0; -} - -const struct file_operations mon_fops_stat = { - .owner = THIS_MODULE, - .open = mon_stat_open, - .llseek = no_llseek, - .read = mon_stat_read, - /* .write = mon_stat_write, */ - /* .poll = mon_stat_poll, */ - /* .unlocked_ioctl = mon_stat_ioctl, */ - .release = mon_stat_release, -}; diff --git a/ANDROID_3.4.5/drivers/usb/mon/mon_text.c b/ANDROID_3.4.5/drivers/usb/mon/mon_text.c deleted file mode 100644 index ad408251..00000000 --- a/ANDROID_3.4.5/drivers/usb/mon/mon_text.c +++ /dev/null @@ -1,761 +0,0 @@ -/* - * The USB Monitor, inspired by Dave Harding's USBMon. - * - * This is a text format reader. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "usb_mon.h" - -/* - * No, we do not want arbitrarily long data strings. - * Use the binary interface if you want to capture bulk data! - */ -#define DATA_MAX 32 - -/* - * Defined by USB 2.0 clause 9.3, table 9.2. - */ -#define SETUP_MAX 8 - -/* - * This limit exists to prevent OOMs when the user process stops reading. - * If usbmon were available to unprivileged processes, it might be open - * to a local DoS. But we have to keep to root in order to prevent - * password sniffing from HID devices. - */ -#define EVENT_MAX (4*PAGE_SIZE / sizeof(struct mon_event_text)) - -/* - * Potentially unlimited number; we limit it for similar allocations. - * The usbfs limits this to 128, but we're not quite as generous. - */ -#define ISODESC_MAX 5 - -#define PRINTF_DFL 250 /* with 5 ISOs segs */ - -struct mon_iso_desc { - int status; - unsigned int offset; - unsigned int length; /* Unsigned here, signed in URB. Historic. */ -}; - -struct mon_event_text { - struct list_head e_link; - int type; /* submit, complete, etc. */ - unsigned long id; /* From pointer, most of the time */ - unsigned int tstamp; - int busnum; - char devnum; - char epnum; - char is_in; - char xfertype; - int length; /* Depends on type: xfer length or act length */ - int status; - int interval; - int start_frame; - int error_count; - char setup_flag; - char data_flag; - int numdesc; /* Full number */ - struct mon_iso_desc isodesc[ISODESC_MAX]; - unsigned char setup[SETUP_MAX]; - unsigned char data[DATA_MAX]; -}; - -#define SLAB_NAME_SZ 30 -struct mon_reader_text { - struct kmem_cache *e_slab; - int nevents; - struct list_head e_list; - struct mon_reader r; /* In C, parent class can be placed anywhere */ - - wait_queue_head_t wait; - int printf_size; - char *printf_buf; - struct mutex printf_lock; - - char slab_name[SLAB_NAME_SZ]; -}; - -static struct dentry *mon_dir; /* Usually /sys/kernel/debug/usbmon */ - -static void mon_text_ctor(void *); - -struct mon_text_ptr { - int cnt, limit; - char *pbuf; -}; - -static struct mon_event_text * - mon_text_read_wait(struct mon_reader_text *rp, struct file *file); -static void mon_text_read_head_t(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep); -static void mon_text_read_head_u(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep); -static void mon_text_read_statset(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep); -static void mon_text_read_intstat(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep); -static void mon_text_read_isostat(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep); -static void mon_text_read_isodesc(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep); -static void mon_text_read_data(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep); - -/* - * mon_text_submit - * mon_text_complete - * - * May be called from an interrupt. - * - * This is called with the whole mon_bus locked, so no additional lock. - */ - -static inline char mon_text_get_setup(struct mon_event_text *ep, - struct urb *urb, char ev_type, struct mon_bus *mbus) -{ - - if (ep->xfertype != USB_ENDPOINT_XFER_CONTROL || ev_type != 'S') - return '-'; - - if (urb->setup_packet == NULL) - return 'Z'; /* '0' would be not as pretty. */ - - memcpy(ep->setup, urb->setup_packet, SETUP_MAX); - return 0; -} - -static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb, - int len, char ev_type, struct mon_bus *mbus) -{ - void *src; - - if (len <= 0) - return 'L'; - if (len >= DATA_MAX) - len = DATA_MAX; - - if (ep->is_in) { - if (ev_type != 'C') - return '<'; - } else { - if (ev_type != 'S') - return '>'; - } - - if (urb->num_sgs == 0) { - src = urb->transfer_buffer; - if (src == NULL) - return 'Z'; /* '0' would be not as pretty. */ - } else { - struct scatterlist *sg = urb->sg; - - if (PageHighMem(sg_page(sg))) - return 'D'; - - /* For the text interface we copy only the first sg buffer */ - len = min_t(int, sg->length, len); - src = sg_virt(sg); - } - - memcpy(ep->data, src, len); - return 0; -} - -static inline unsigned int mon_get_timestamp(void) -{ - struct timeval tval; - unsigned int stamp; - - do_gettimeofday(&tval); - stamp = tval.tv_sec & 0xFFF; /* 2^32 = 4294967296. Limit to 4096s. */ - stamp = stamp * 1000000 + tval.tv_usec; - return stamp; -} - -static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, - char ev_type, int status) -{ - struct mon_event_text *ep; - unsigned int stamp; - struct usb_iso_packet_descriptor *fp; - struct mon_iso_desc *dp; - int i, ndesc; - - stamp = mon_get_timestamp(); - - if (rp->nevents >= EVENT_MAX || - (ep = kmem_cache_alloc(rp->e_slab, GFP_ATOMIC)) == NULL) { - rp->r.m_bus->cnt_text_lost++; - return; - } - - ep->type = ev_type; - ep->id = (unsigned long) urb; - ep->busnum = urb->dev->bus->busnum; - ep->devnum = urb->dev->devnum; - ep->epnum = usb_endpoint_num(&urb->ep->desc); - ep->xfertype = usb_endpoint_type(&urb->ep->desc); - ep->is_in = usb_urb_dir_in(urb); - ep->tstamp = stamp; - ep->length = (ev_type == 'S') ? - urb->transfer_buffer_length : urb->actual_length; - /* Collecting status makes debugging sense for submits, too */ - ep->status = status; - - if (ep->xfertype == USB_ENDPOINT_XFER_INT) { - ep->interval = urb->interval; - } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) { - ep->interval = urb->interval; - ep->start_frame = urb->start_frame; - ep->error_count = urb->error_count; - } - ep->numdesc = urb->number_of_packets; - if (ep->xfertype == USB_ENDPOINT_XFER_ISOC && - urb->number_of_packets > 0) { - if ((ndesc = urb->number_of_packets) > ISODESC_MAX) - ndesc = ISODESC_MAX; - fp = urb->iso_frame_desc; - dp = ep->isodesc; - for (i = 0; i < ndesc; i++) { - dp->status = fp->status; - dp->offset = fp->offset; - dp->length = (ev_type == 'S') ? - fp->length : fp->actual_length; - fp++; - dp++; - } - /* Wasteful, but simple to understand: ISO 'C' is sparse. */ - if (ev_type == 'C') - ep->length = urb->transfer_buffer_length; - } - - ep->setup_flag = mon_text_get_setup(ep, urb, ev_type, rp->r.m_bus); - ep->data_flag = mon_text_get_data(ep, urb, ep->length, ev_type, - rp->r.m_bus); - - rp->nevents++; - list_add_tail(&ep->e_link, &rp->e_list); - wake_up(&rp->wait); -} - -static void mon_text_submit(void *data, struct urb *urb) -{ - struct mon_reader_text *rp = data; - mon_text_event(rp, urb, 'S', -EINPROGRESS); -} - -static void mon_text_complete(void *data, struct urb *urb, int status) -{ - struct mon_reader_text *rp = data; - mon_text_event(rp, urb, 'C', status); -} - -static void mon_text_error(void *data, struct urb *urb, int error) -{ - struct mon_reader_text *rp = data; - struct mon_event_text *ep; - - if (rp->nevents >= EVENT_MAX || - (ep = kmem_cache_alloc(rp->e_slab, GFP_ATOMIC)) == NULL) { - rp->r.m_bus->cnt_text_lost++; - return; - } - - ep->type = 'E'; - ep->id = (unsigned long) urb; - ep->busnum = urb->dev->bus->busnum; - ep->devnum = urb->dev->devnum; - ep->epnum = usb_endpoint_num(&urb->ep->desc); - ep->xfertype = usb_endpoint_type(&urb->ep->desc); - ep->is_in = usb_urb_dir_in(urb); - ep->tstamp = mon_get_timestamp(); - ep->length = 0; - ep->status = error; - - ep->setup_flag = '-'; - ep->data_flag = 'E'; - - rp->nevents++; - list_add_tail(&ep->e_link, &rp->e_list); - wake_up(&rp->wait); -} - -/* - * Fetch next event from the circular buffer. - */ -static struct mon_event_text *mon_text_fetch(struct mon_reader_text *rp, - struct mon_bus *mbus) -{ - struct list_head *p; - unsigned long flags; - - spin_lock_irqsave(&mbus->lock, flags); - if (list_empty(&rp->e_list)) { - spin_unlock_irqrestore(&mbus->lock, flags); - return NULL; - } - p = rp->e_list.next; - list_del(p); - --rp->nevents; - spin_unlock_irqrestore(&mbus->lock, flags); - return list_entry(p, struct mon_event_text, e_link); -} - -/* - */ -static int mon_text_open(struct inode *inode, struct file *file) -{ - struct mon_bus *mbus; - struct mon_reader_text *rp; - int rc; - - mutex_lock(&mon_lock); - mbus = inode->i_private; - - rp = kzalloc(sizeof(struct mon_reader_text), GFP_KERNEL); - if (rp == NULL) { - rc = -ENOMEM; - goto err_alloc; - } - INIT_LIST_HEAD(&rp->e_list); - init_waitqueue_head(&rp->wait); - mutex_init(&rp->printf_lock); - - rp->printf_size = PRINTF_DFL; - rp->printf_buf = kmalloc(rp->printf_size, GFP_KERNEL); - if (rp->printf_buf == NULL) { - rc = -ENOMEM; - goto err_alloc_pr; - } - - rp->r.m_bus = mbus; - rp->r.r_data = rp; - rp->r.rnf_submit = mon_text_submit; - rp->r.rnf_error = mon_text_error; - rp->r.rnf_complete = mon_text_complete; - - snprintf(rp->slab_name, SLAB_NAME_SZ, "mon_text_%p", rp); - rp->e_slab = kmem_cache_create(rp->slab_name, - sizeof(struct mon_event_text), sizeof(long), 0, - mon_text_ctor); - if (rp->e_slab == NULL) { - rc = -ENOMEM; - goto err_slab; - } - - mon_reader_add(mbus, &rp->r); - - file->private_data = rp; - mutex_unlock(&mon_lock); - return 0; - -// err_busy: -// kmem_cache_destroy(rp->e_slab); -err_slab: - kfree(rp->printf_buf); -err_alloc_pr: - kfree(rp); -err_alloc: - mutex_unlock(&mon_lock); - return rc; -} - -/* - * For simplicity, we read one record in one system call and throw out - * what does not fit. This means that the following does not work: - * dd if=/dbg/usbmon/0t bs=10 - * Also, we do not allow seeks and do not bother advancing the offset. - */ -static ssize_t mon_text_read_t(struct file *file, char __user *buf, - size_t nbytes, loff_t *ppos) -{ - struct mon_reader_text *rp = file->private_data; - struct mon_event_text *ep; - struct mon_text_ptr ptr; - - if (IS_ERR(ep = mon_text_read_wait(rp, file))) - return PTR_ERR(ep); - mutex_lock(&rp->printf_lock); - ptr.cnt = 0; - ptr.pbuf = rp->printf_buf; - ptr.limit = rp->printf_size; - - mon_text_read_head_t(rp, &ptr, ep); - mon_text_read_statset(rp, &ptr, ep); - ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt, - " %d", ep->length); - mon_text_read_data(rp, &ptr, ep); - - if (copy_to_user(buf, rp->printf_buf, ptr.cnt)) - ptr.cnt = -EFAULT; - mutex_unlock(&rp->printf_lock); - kmem_cache_free(rp->e_slab, ep); - return ptr.cnt; -} - -static ssize_t mon_text_read_u(struct file *file, char __user *buf, - size_t nbytes, loff_t *ppos) -{ - struct mon_reader_text *rp = file->private_data; - struct mon_event_text *ep; - struct mon_text_ptr ptr; - - if (IS_ERR(ep = mon_text_read_wait(rp, file))) - return PTR_ERR(ep); - mutex_lock(&rp->printf_lock); - ptr.cnt = 0; - ptr.pbuf = rp->printf_buf; - ptr.limit = rp->printf_size; - - mon_text_read_head_u(rp, &ptr, ep); - if (ep->type == 'E') { - mon_text_read_statset(rp, &ptr, ep); - } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) { - mon_text_read_isostat(rp, &ptr, ep); - mon_text_read_isodesc(rp, &ptr, ep); - } else if (ep->xfertype == USB_ENDPOINT_XFER_INT) { - mon_text_read_intstat(rp, &ptr, ep); - } else { - mon_text_read_statset(rp, &ptr, ep); - } - ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt, - " %d", ep->length); - mon_text_read_data(rp, &ptr, ep); - - if (copy_to_user(buf, rp->printf_buf, ptr.cnt)) - ptr.cnt = -EFAULT; - mutex_unlock(&rp->printf_lock); - kmem_cache_free(rp->e_slab, ep); - return ptr.cnt; -} - -static struct mon_event_text *mon_text_read_wait(struct mon_reader_text *rp, - struct file *file) -{ - struct mon_bus *mbus = rp->r.m_bus; - DECLARE_WAITQUEUE(waita, current); - struct mon_event_text *ep; - - add_wait_queue(&rp->wait, &waita); - set_current_state(TASK_INTERRUPTIBLE); - while ((ep = mon_text_fetch(rp, mbus)) == NULL) { - if (file->f_flags & O_NONBLOCK) { - set_current_state(TASK_RUNNING); - remove_wait_queue(&rp->wait, &waita); - return ERR_PTR(-EWOULDBLOCK); - } - /* - * We do not count nwaiters, because ->release is supposed - * to be called when all openers are gone only. - */ - schedule(); - if (signal_pending(current)) { - remove_wait_queue(&rp->wait, &waita); - return ERR_PTR(-EINTR); - } - set_current_state(TASK_INTERRUPTIBLE); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&rp->wait, &waita); - return ep; -} - -static void mon_text_read_head_t(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep) -{ - char udir, utype; - - udir = (ep->is_in ? 'i' : 'o'); - switch (ep->xfertype) { - case USB_ENDPOINT_XFER_ISOC: utype = 'Z'; break; - case USB_ENDPOINT_XFER_INT: utype = 'I'; break; - case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break; - default: /* PIPE_BULK */ utype = 'B'; - } - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, - "%lx %u %c %c%c:%03u:%02u", - ep->id, ep->tstamp, ep->type, - utype, udir, ep->devnum, ep->epnum); -} - -static void mon_text_read_head_u(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep) -{ - char udir, utype; - - udir = (ep->is_in ? 'i' : 'o'); - switch (ep->xfertype) { - case USB_ENDPOINT_XFER_ISOC: utype = 'Z'; break; - case USB_ENDPOINT_XFER_INT: utype = 'I'; break; - case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break; - default: /* PIPE_BULK */ utype = 'B'; - } - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, - "%lx %u %c %c%c:%d:%03u:%u", - ep->id, ep->tstamp, ep->type, - utype, udir, ep->busnum, ep->devnum, ep->epnum); -} - -static void mon_text_read_statset(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep) -{ - - if (ep->setup_flag == 0) { /* Setup packet is present and captured */ - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, - " s %02x %02x %04x %04x %04x", - ep->setup[0], - ep->setup[1], - (ep->setup[3] << 8) | ep->setup[2], - (ep->setup[5] << 8) | ep->setup[4], - (ep->setup[7] << 8) | ep->setup[6]); - } else if (ep->setup_flag != '-') { /* Unable to capture setup packet */ - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, - " %c __ __ ____ ____ ____", ep->setup_flag); - } else { /* No setup for this kind of URB */ - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, - " %d", ep->status); - } -} - -static void mon_text_read_intstat(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep) -{ - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, - " %d:%d", ep->status, ep->interval); -} - -static void mon_text_read_isostat(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep) -{ - if (ep->type == 'S') { - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, - " %d:%d:%d", ep->status, ep->interval, ep->start_frame); - } else { - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, - " %d:%d:%d:%d", - ep->status, ep->interval, ep->start_frame, ep->error_count); - } -} - -static void mon_text_read_isodesc(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep) -{ - int ndesc; /* Display this many */ - int i; - const struct mon_iso_desc *dp; - - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, - " %d", ep->numdesc); - ndesc = ep->numdesc; - if (ndesc > ISODESC_MAX) - ndesc = ISODESC_MAX; - if (ndesc < 0) - ndesc = 0; - dp = ep->isodesc; - for (i = 0; i < ndesc; i++) { - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, - " %d:%u:%u", dp->status, dp->offset, dp->length); - dp++; - } -} - -static void mon_text_read_data(struct mon_reader_text *rp, - struct mon_text_ptr *p, const struct mon_event_text *ep) -{ - int data_len, i; - - if ((data_len = ep->length) > 0) { - if (ep->data_flag == 0) { - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, - " ="); - if (data_len >= DATA_MAX) - data_len = DATA_MAX; - for (i = 0; i < data_len; i++) { - if (i % 4 == 0) { - p->cnt += snprintf(p->pbuf + p->cnt, - p->limit - p->cnt, - " "); - } - p->cnt += snprintf(p->pbuf + p->cnt, - p->limit - p->cnt, - "%02x", ep->data[i]); - } - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, - "\n"); - } else { - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, - " %c\n", ep->data_flag); - } - } else { - p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt, "\n"); - } -} - -static int mon_text_release(struct inode *inode, struct file *file) -{ - struct mon_reader_text *rp = file->private_data; - struct mon_bus *mbus; - /* unsigned long flags; */ - struct list_head *p; - struct mon_event_text *ep; - - mutex_lock(&mon_lock); - mbus = inode->i_private; - - if (mbus->nreaders <= 0) { - printk(KERN_ERR TAG ": consistency error on close\n"); - mutex_unlock(&mon_lock); - return 0; - } - mon_reader_del(mbus, &rp->r); - - /* - * In theory, e_list is protected by mbus->lock. However, - * after mon_reader_del has finished, the following is the case: - * - we are not on reader list anymore, so new events won't be added; - * - whole mbus may be dropped if it was orphaned. - * So, we better not touch mbus. - */ - /* spin_lock_irqsave(&mbus->lock, flags); */ - while (!list_empty(&rp->e_list)) { - p = rp->e_list.next; - ep = list_entry(p, struct mon_event_text, e_link); - list_del(p); - --rp->nevents; - kmem_cache_free(rp->e_slab, ep); - } - /* spin_unlock_irqrestore(&mbus->lock, flags); */ - - kmem_cache_destroy(rp->e_slab); - kfree(rp->printf_buf); - kfree(rp); - - mutex_unlock(&mon_lock); - return 0; -} - -static const struct file_operations mon_fops_text_t = { - .owner = THIS_MODULE, - .open = mon_text_open, - .llseek = no_llseek, - .read = mon_text_read_t, - .release = mon_text_release, -}; - -static const struct file_operations mon_fops_text_u = { - .owner = THIS_MODULE, - .open = mon_text_open, - .llseek = no_llseek, - .read = mon_text_read_u, - .release = mon_text_release, -}; - -int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus) -{ - struct dentry *d; - enum { NAMESZ = 10 }; - char name[NAMESZ]; - int busnum = ubus? ubus->busnum: 0; - int rc; - - if (mon_dir == NULL) - return 0; - - if (ubus != NULL) { - rc = snprintf(name, NAMESZ, "%dt", busnum); - if (rc <= 0 || rc >= NAMESZ) - goto err_print_t; - d = debugfs_create_file(name, 0600, mon_dir, mbus, - &mon_fops_text_t); - if (d == NULL) - goto err_create_t; - mbus->dent_t = d; - } - - rc = snprintf(name, NAMESZ, "%du", busnum); - if (rc <= 0 || rc >= NAMESZ) - goto err_print_u; - d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text_u); - if (d == NULL) - goto err_create_u; - mbus->dent_u = d; - - rc = snprintf(name, NAMESZ, "%ds", busnum); - if (rc <= 0 || rc >= NAMESZ) - goto err_print_s; - d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_stat); - if (d == NULL) - goto err_create_s; - mbus->dent_s = d; - - return 1; - -err_create_s: -err_print_s: - debugfs_remove(mbus->dent_u); - mbus->dent_u = NULL; -err_create_u: -err_print_u: - if (ubus != NULL) { - debugfs_remove(mbus->dent_t); - mbus->dent_t = NULL; - } -err_create_t: -err_print_t: - return 0; -} - -void mon_text_del(struct mon_bus *mbus) -{ - debugfs_remove(mbus->dent_u); - if (mbus->dent_t != NULL) - debugfs_remove(mbus->dent_t); - debugfs_remove(mbus->dent_s); -} - -/* - * Slab interface: constructor. - */ -static void mon_text_ctor(void *mem) -{ - /* - * Nothing to initialize. No, really! - * So, we fill it with garbage to emulate a reused object. - */ - memset(mem, 0xe5, sizeof(struct mon_event_text)); -} - -int __init mon_text_init(void) -{ - struct dentry *mondir; - - mondir = debugfs_create_dir("usbmon", usb_debug_root); - if (IS_ERR(mondir)) { - /* debugfs not available, but we can use usbmon without it */ - return 0; - } - if (mondir == NULL) { - printk(KERN_NOTICE TAG ": unable to create usbmon directory\n"); - return -ENOMEM; - } - mon_dir = mondir; - return 0; -} - -void mon_text_exit(void) -{ - debugfs_remove(mon_dir); -} diff --git a/ANDROID_3.4.5/drivers/usb/mon/usb_mon.h b/ANDROID_3.4.5/drivers/usb/mon/usb_mon.h deleted file mode 100644 index df9a4df3..00000000 --- a/ANDROID_3.4.5/drivers/usb/mon/usb_mon.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * The USB Monitor, inspired by Dave Harding's USBMon. - * - * Copyright (C) 2005 Pete Zaitcev (zaitcev@redhat.com) - */ - -#ifndef __USB_MON_H -#define __USB_MON_H - -#include -#include -#include -/* #include */ /* We use struct pointers only in this header */ - -#define TAG "usbmon" - -struct mon_bus { - struct list_head bus_link; - spinlock_t lock; - struct usb_bus *u_bus; - - int text_inited; - int bin_inited; - struct dentry *dent_s; /* Debugging file */ - struct dentry *dent_t; /* Text interface file */ - struct dentry *dent_u; /* Second text interface file */ - struct device *classdev; /* Device in usbmon class */ - - /* Ref */ - int nreaders; /* Under mon_lock AND mbus->lock */ - struct list_head r_list; /* Chain of readers (usually one) */ - struct kref ref; /* Under mon_lock */ - - /* Stats */ - unsigned int cnt_events; - unsigned int cnt_text_lost; -}; - -/* - * An instance of a process which opened a file (but can fork later) - */ -struct mon_reader { - struct list_head r_link; - struct mon_bus *m_bus; - void *r_data; /* Use container_of instead? */ - - void (*rnf_submit)(void *data, struct urb *urb); - void (*rnf_error)(void *data, struct urb *urb, int error); - void (*rnf_complete)(void *data, struct urb *urb, int status); -}; - -void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r); -void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r); - -struct mon_bus *mon_bus_lookup(unsigned int num); - -int /*bool*/ mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus); -void mon_text_del(struct mon_bus *mbus); -int /*bool*/ mon_bin_add(struct mon_bus *mbus, const struct usb_bus *ubus); -void mon_bin_del(struct mon_bus *mbus); - -int __init mon_text_init(void); -void mon_text_exit(void); -int __init mon_bin_init(void); -void mon_bin_exit(void); - -/* - */ -extern struct mutex mon_lock; - -extern const struct file_operations mon_fops_stat; - -extern struct mon_bus mon_bus0; /* Only for redundant checks */ - -#endif /* __USB_MON_H */ diff --git a/ANDROID_3.4.5/drivers/usb/musb/Kconfig b/ANDROID_3.4.5/drivers/usb/musb/Kconfig deleted file mode 100644 index f70cab3b..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/Kconfig +++ /dev/null @@ -1,117 +0,0 @@ -# -# USB Dual Role (OTG-ready) Controller Drivers -# for silicon based on Mentor Graphics INVENTRA designs -# - -# (M)HDRC = (Multipoint) Highspeed Dual-Role Controller -config USB_MUSB_HDRC - tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)' - depends on USB && USB_GADGET - select NOP_USB_XCEIV if (ARCH_DAVINCI || MACH_OMAP3EVM || BLACKFIN) - select TWL4030_USB if MACH_OMAP_3430SDP - select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA - select USB_OTG_UTILS - select USB_GADGET_DUALSPEED - help - Say Y here if your system has a dual role high speed USB - controller based on the Mentor Graphics silicon IP. Then - configure options to match your silicon and the board - it's being used with, including the USB peripheral role, - or the USB host role, or both. - - Texas Instruments familiies using this IP include DaVinci - (35x, 644x ...), OMAP 243x, OMAP 3, and TUSB 6010. - - Analog Devices parts using this IP include Blackfin BF54x, - BF525 and BF527. - - If you do not know what this is, please say N. - - To compile this driver as a module, choose M here; the - module will be called "musb-hdrc". - -if USB_MUSB_HDRC - -choice - prompt "Platform Glue Layer" - -config USB_MUSB_DAVINCI - tristate "DaVinci" - depends on ARCH_DAVINCI_DMx - -config USB_MUSB_DA8XX - tristate "DA8xx/OMAP-L1x" - depends on ARCH_DAVINCI_DA8XX - -config USB_MUSB_TUSB6010 - tristate "TUSB6010" - -config USB_MUSB_OMAP2PLUS - tristate "OMAP2430 and onwards" - depends on ARCH_OMAP2PLUS - -config USB_MUSB_AM35X - tristate "AM35x" - depends on ARCH_OMAP - -config USB_MUSB_BLACKFIN - tristate "Blackfin" - depends on (BF54x && !BF544) || (BF52x && ! BF522 && !BF523) - -config USB_MUSB_UX500 - tristate "U8500 and U5500" - depends on (ARCH_U8500 && AB8500_USB) - -endchoice - -choice - prompt 'MUSB DMA mode' - default USB_UX500_DMA if USB_MUSB_UX500 - default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN - default USB_TI_CPPI_DMA if USB_MUSB_DAVINCI - default USB_TUSB_OMAP_DMA if USB_MUSB_TUSB6010 - default MUSB_PIO_ONLY if USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X - help - Unfortunately, only one option can be enabled here. Ideally one - should be able to build all these drivers into one kernel to - allow using DMA on multiplatform kernels. - -config USB_UX500_DMA - bool 'ST Ericsson U8500 and U5500' - depends on USB_MUSB_UX500 - help - Enable DMA transfers on UX500 platforms. - -config USB_INVENTRA_DMA - bool 'Inventra' - depends on USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN - help - Enable DMA transfers using Mentor's engine. - -config USB_TI_CPPI_DMA - bool 'TI CPPI (Davinci)' - depends on USB_MUSB_DAVINCI - help - Enable DMA transfers when TI CPPI DMA is available. - -config USB_TUSB_OMAP_DMA - bool 'TUSB 6010' - depends on USB_MUSB_TUSB6010 - depends on ARCH_OMAP - help - Enable DMA transfers on TUSB 6010 when OMAP DMA is available. - -config MUSB_PIO_ONLY - bool 'Disable DMA (always use PIO)' - help - All data is copied between memory and FIFO by the CPU. - DMA controllers are ignored. - - Do not choose this unless DMA support for your SOC or board - is unavailable (or unstable). When DMA is enabled at compile time, - you can still disable it at run time using the "use_dma=n" module - parameter. - -endchoice - -endif # USB_MUSB_HDRC diff --git a/ANDROID_3.4.5/drivers/usb/musb/Makefile b/ANDROID_3.4.5/drivers/usb/musb/Makefile deleted file mode 100644 index 88bfb9de..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# -# for USB OTG silicon based on Mentor Graphics INVENTRA designs -# - -obj-$(CONFIG_USB_MUSB_HDRC) += musb_hdrc.o - -musb_hdrc-y := musb_core.o - -musb_hdrc-y += musb_gadget_ep0.o musb_gadget.o -musb_hdrc-y += musb_virthub.o musb_host.o -musb_hdrc-$(CONFIG_DEBUG_FS) += musb_debugfs.o - -# Hardware Glue Layer -obj-$(CONFIG_USB_MUSB_OMAP2PLUS) += omap2430.o -obj-$(CONFIG_USB_MUSB_AM35X) += am35x.o -obj-$(CONFIG_USB_MUSB_TUSB6010) += tusb6010.o -obj-$(CONFIG_USB_MUSB_DAVINCI) += davinci.o -obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.o -obj-$(CONFIG_USB_MUSB_BLACKFIN) += blackfin.o -obj-$(CONFIG_USB_MUSB_UX500) += ux500.o - -# the kconfig must guarantee that only one of the -# possible I/O schemes will be enabled at a time ... -# PIO only, or DMA (several potential schemes). -# though PIO is always there to back up DMA, and for ep0 - -musb_hdrc-$(CONFIG_USB_INVENTRA_DMA) += musbhsdma.o -musb_hdrc-$(CONFIG_USB_TI_CPPI_DMA) += cppi_dma.o -musb_hdrc-$(CONFIG_USB_TUSB_OMAP_DMA) += tusb6010_omap.o -musb_hdrc-$(CONFIG_USB_UX500_DMA) += ux500_dma.o diff --git a/ANDROID_3.4.5/drivers/usb/musb/am35x.c b/ANDROID_3.4.5/drivers/usb/musb/am35x.c deleted file mode 100644 index 9f3eda91..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/am35x.c +++ /dev/null @@ -1,656 +0,0 @@ -/* - * Texas Instruments AM35x "glue layer" - * - * Copyright (c) 2010, by Texas Instruments - * - * Based on the DA8xx "glue layer" code. - * Copyright (c) 2008-2009, MontaVista Software, Inc. - * - * This file is part of the Inventra Controller Driver for Linux. - * - * The Inventra Controller Driver for Linux 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. - * - * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not, - * write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include "musb_core.h" - -/* - * AM35x specific definitions - */ -/* USB 2.0 OTG module registers */ -#define USB_REVISION_REG 0x00 -#define USB_CTRL_REG 0x04 -#define USB_STAT_REG 0x08 -#define USB_EMULATION_REG 0x0c -/* 0x10 Reserved */ -#define USB_AUTOREQ_REG 0x14 -#define USB_SRP_FIX_TIME_REG 0x18 -#define USB_TEARDOWN_REG 0x1c -#define EP_INTR_SRC_REG 0x20 -#define EP_INTR_SRC_SET_REG 0x24 -#define EP_INTR_SRC_CLEAR_REG 0x28 -#define EP_INTR_MASK_REG 0x2c -#define EP_INTR_MASK_SET_REG 0x30 -#define EP_INTR_MASK_CLEAR_REG 0x34 -#define EP_INTR_SRC_MASKED_REG 0x38 -#define CORE_INTR_SRC_REG 0x40 -#define CORE_INTR_SRC_SET_REG 0x44 -#define CORE_INTR_SRC_CLEAR_REG 0x48 -#define CORE_INTR_MASK_REG 0x4c -#define CORE_INTR_MASK_SET_REG 0x50 -#define CORE_INTR_MASK_CLEAR_REG 0x54 -#define CORE_INTR_SRC_MASKED_REG 0x58 -/* 0x5c Reserved */ -#define USB_END_OF_INTR_REG 0x60 - -/* Control register bits */ -#define AM35X_SOFT_RESET_MASK 1 - -/* USB interrupt register bits */ -#define AM35X_INTR_USB_SHIFT 16 -#define AM35X_INTR_USB_MASK (0x1ff << AM35X_INTR_USB_SHIFT) -#define AM35X_INTR_DRVVBUS 0x100 -#define AM35X_INTR_RX_SHIFT 16 -#define AM35X_INTR_TX_SHIFT 0 -#define AM35X_TX_EP_MASK 0xffff /* EP0 + 15 Tx EPs */ -#define AM35X_RX_EP_MASK 0xfffe /* 15 Rx EPs */ -#define AM35X_TX_INTR_MASK (AM35X_TX_EP_MASK << AM35X_INTR_TX_SHIFT) -#define AM35X_RX_INTR_MASK (AM35X_RX_EP_MASK << AM35X_INTR_RX_SHIFT) - -#define USB_MENTOR_CORE_OFFSET 0x400 - -struct am35x_glue { - struct device *dev; - struct platform_device *musb; - struct clk *phy_clk; - struct clk *clk; -}; -#define glue_to_musb(g) platform_get_drvdata(g->musb) - -/* - * am35x_musb_enable - enable interrupts - */ -static void am35x_musb_enable(struct musb *musb) -{ - void __iomem *reg_base = musb->ctrl_base; - u32 epmask; - - /* Workaround: setup IRQs through both register sets. */ - epmask = ((musb->epmask & AM35X_TX_EP_MASK) << AM35X_INTR_TX_SHIFT) | - ((musb->epmask & AM35X_RX_EP_MASK) << AM35X_INTR_RX_SHIFT); - - musb_writel(reg_base, EP_INTR_MASK_SET_REG, epmask); - musb_writel(reg_base, CORE_INTR_MASK_SET_REG, AM35X_INTR_USB_MASK); - - /* Force the DRVVBUS IRQ so we can start polling for ID change. */ - if (is_otg_enabled(musb)) - musb_writel(reg_base, CORE_INTR_SRC_SET_REG, - AM35X_INTR_DRVVBUS << AM35X_INTR_USB_SHIFT); -} - -/* - * am35x_musb_disable - disable HDRC and flush interrupts - */ -static void am35x_musb_disable(struct musb *musb) -{ - void __iomem *reg_base = musb->ctrl_base; - - musb_writel(reg_base, CORE_INTR_MASK_CLEAR_REG, AM35X_INTR_USB_MASK); - musb_writel(reg_base, EP_INTR_MASK_CLEAR_REG, - AM35X_TX_INTR_MASK | AM35X_RX_INTR_MASK); - musb_writeb(musb->mregs, MUSB_DEVCTL, 0); - musb_writel(reg_base, USB_END_OF_INTR_REG, 0); -} - -#define portstate(stmt) stmt - -static void am35x_musb_set_vbus(struct musb *musb, int is_on) -{ - WARN_ON(is_on && is_peripheral_active(musb)); -} - -#define POLL_SECONDS 2 - -static struct timer_list otg_workaround; - -static void otg_timer(unsigned long _musb) -{ - struct musb *musb = (void *)_musb; - void __iomem *mregs = musb->mregs; - u8 devctl; - unsigned long flags; - - /* - * We poll because AM35x's won't expose several OTG-critical - * status change events (from the transceiver) otherwise. - */ - devctl = musb_readb(mregs, MUSB_DEVCTL); - dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl, - otg_state_string(musb->xceiv->state)); - - spin_lock_irqsave(&musb->lock, flags); - 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_DEV_MODE(musb); - } else { - musb->xceiv->state = OTG_STATE_A_IDLE; - MUSB_HST_MODE(musb); - } - break; - case OTG_STATE_A_WAIT_VFALL: - musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; - musb_writel(musb->ctrl_base, CORE_INTR_SRC_SET_REG, - MUSB_INTR_VBUSERROR << AM35X_INTR_USB_SHIFT); - break; - case OTG_STATE_B_IDLE: - if (!is_peripheral_enabled(musb)) - break; - - devctl = musb_readb(mregs, MUSB_DEVCTL); - if (devctl & MUSB_DEVCTL_BDEVICE) - mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); - else - musb->xceiv->state = OTG_STATE_A_IDLE; - break; - default: - break; - } - spin_unlock_irqrestore(&musb->lock, flags); -} - -static void am35x_musb_try_idle(struct musb *musb, unsigned long timeout) -{ - static unsigned long last_timer; - - if (!is_otg_enabled(musb)) - return; - - if (timeout == 0) - timeout = jiffies + msecs_to_jiffies(3); - - /* 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)) { - dev_dbg(musb->controller, "%s active, deleting timer\n", - otg_state_string(musb->xceiv->state)); - del_timer(&otg_workaround); - last_timer = jiffies; - return; - } - - if (time_after(last_timer, timeout) && timer_pending(&otg_workaround)) { - dev_dbg(musb->controller, "Longer idle timer already pending, ignoring...\n"); - return; - } - last_timer = timeout; - - dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", - otg_state_string(musb->xceiv->state), - jiffies_to_msecs(timeout - jiffies)); - mod_timer(&otg_workaround, timeout); -} - -static irqreturn_t am35x_musb_interrupt(int irq, void *hci) -{ - struct musb *musb = hci; - void __iomem *reg_base = musb->ctrl_base; - struct device *dev = musb->controller; - struct musb_hdrc_platform_data *plat = dev->platform_data; - struct omap_musb_board_data *data = plat->board_data; - struct usb_otg *otg = musb->xceiv->otg; - unsigned long flags; - irqreturn_t ret = IRQ_NONE; - u32 epintr, usbintr; - - spin_lock_irqsave(&musb->lock, flags); - - /* Get endpoint interrupts */ - epintr = musb_readl(reg_base, EP_INTR_SRC_MASKED_REG); - - if (epintr) { - musb_writel(reg_base, EP_INTR_SRC_CLEAR_REG, epintr); - - musb->int_rx = - (epintr & AM35X_RX_INTR_MASK) >> AM35X_INTR_RX_SHIFT; - musb->int_tx = - (epintr & AM35X_TX_INTR_MASK) >> AM35X_INTR_TX_SHIFT; - } - - /* Get usb core interrupts */ - usbintr = musb_readl(reg_base, CORE_INTR_SRC_MASKED_REG); - if (!usbintr && !epintr) - goto eoi; - - if (usbintr) { - musb_writel(reg_base, CORE_INTR_SRC_CLEAR_REG, usbintr); - - musb->int_usb = - (usbintr & AM35X_INTR_USB_MASK) >> AM35X_INTR_USB_SHIFT; - } - /* - * DRVVBUS IRQs are the only proxy we have (a very poor one!) for - * AM35x's missing ID change IRQ. We need an ID change IRQ to - * switch appropriately between halves of the OTG state machine. - * Managing DEVCTL.SESSION per Mentor docs requires that we know its - * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set. - * Also, DRVVBUS pulses for SRP (but not at 5V) ... - */ - if (usbintr & (AM35X_INTR_DRVVBUS << AM35X_INTR_USB_SHIFT)) { - int drvvbus = musb_readl(reg_base, USB_STAT_REG); - void __iomem *mregs = musb->mregs; - u8 devctl = musb_readb(mregs, MUSB_DEVCTL); - int err; - - err = is_host_enabled(musb) && (musb->int_usb & - MUSB_INTR_VBUSERROR); - if (err) { - /* - * The Mentor core doesn't debounce VBUS as needed - * to cope with device connect current spikes. This - * means it's not uncommon for bus-powered devices - * to get VBUS errors during enumeration. - * - * This is a workaround, but newer RTL from Mentor - * seems to allow a better one: "re"-starting sessions - * without waiting for VBUS to stop registering in - * devctl. - */ - musb->int_usb &= ~MUSB_INTR_VBUSERROR; - 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_HST_MODE(musb); - otg->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); - otg->default_a = 0; - musb->xceiv->state = OTG_STATE_B_IDLE; - portstate(musb->port1_status &= ~USB_PORT_STAT_POWER); - } - - /* NOTE: this must complete power-on within 100 ms. */ - dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n", - drvvbus ? "on" : "off", - otg_state_string(musb->xceiv->state), - err ? " ERROR" : "", - devctl); - ret = IRQ_HANDLED; - } - - if (musb->int_tx || musb->int_rx || musb->int_usb) - ret |= musb_interrupt(musb); - -eoi: - /* EOI needs to be written for the IRQ to be re-asserted. */ - if (ret == IRQ_HANDLED || epintr || usbintr) { - /* clear level interrupt */ - if (data->clear_irq) - data->clear_irq(); - /* write EOI */ - musb_writel(reg_base, USB_END_OF_INTR_REG, 0); - } - - /* Poll for ID change */ - if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE) - mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); - - spin_unlock_irqrestore(&musb->lock, flags); - - return ret; -} - -static int am35x_musb_set_mode(struct musb *musb, u8 musb_mode) -{ - struct device *dev = musb->controller; - struct musb_hdrc_platform_data *plat = dev->platform_data; - struct omap_musb_board_data *data = plat->board_data; - int retval = 0; - - if (data->set_mode) - data->set_mode(musb_mode); - else - retval = -EIO; - - return retval; -} - -static int am35x_musb_init(struct musb *musb) -{ - struct device *dev = musb->controller; - struct musb_hdrc_platform_data *plat = dev->platform_data; - struct omap_musb_board_data *data = plat->board_data; - void __iomem *reg_base = musb->ctrl_base; - u32 rev; - - musb->mregs += USB_MENTOR_CORE_OFFSET; - - /* Returns zero if e.g. not clocked */ - rev = musb_readl(reg_base, USB_REVISION_REG); - if (!rev) - return -ENODEV; - - usb_nop_xceiv_register(); - musb->xceiv = usb_get_transceiver(); - if (!musb->xceiv) - return -ENODEV; - - if (is_host_enabled(musb)) - setup_timer(&otg_workaround, otg_timer, (unsigned long) musb); - - /* Reset the musb */ - if (data->reset) - data->reset(); - - /* Reset the controller */ - musb_writel(reg_base, USB_CTRL_REG, AM35X_SOFT_RESET_MASK); - - /* Start the on-chip PHY and its PLL. */ - if (data->set_phy_power) - data->set_phy_power(1); - - msleep(5); - - musb->isr = am35x_musb_interrupt; - - /* clear level interrupt */ - if (data->clear_irq) - data->clear_irq(); - - return 0; -} - -static int am35x_musb_exit(struct musb *musb) -{ - struct device *dev = musb->controller; - struct musb_hdrc_platform_data *plat = dev->platform_data; - struct omap_musb_board_data *data = plat->board_data; - - if (is_host_enabled(musb)) - del_timer_sync(&otg_workaround); - - /* Shutdown the on-chip PHY and its PLL. */ - if (data->set_phy_power) - data->set_phy_power(0); - - usb_put_transceiver(musb->xceiv); - usb_nop_xceiv_unregister(); - - return 0; -} - -/* AM35x supports only 32bit read operation */ -void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) -{ - void __iomem *fifo = hw_ep->fifo; - u32 val; - int i; - - /* Read for 32bit-aligned destination address */ - if (likely((0x03 & (unsigned long) dst) == 0) && len >= 4) { - readsl(fifo, dst, len >> 2); - dst += len & ~0x03; - len &= 0x03; - } - /* - * Now read the remaining 1 to 3 byte or complete length if - * unaligned address. - */ - if (len > 4) { - for (i = 0; i < (len >> 2); i++) { - *(u32 *) dst = musb_readl(fifo, 0); - dst += 4; - } - len &= 0x03; - } - if (len > 0) { - val = musb_readl(fifo, 0); - memcpy(dst, &val, len); - } -} - -static const struct musb_platform_ops am35x_ops = { - .init = am35x_musb_init, - .exit = am35x_musb_exit, - - .enable = am35x_musb_enable, - .disable = am35x_musb_disable, - - .set_mode = am35x_musb_set_mode, - .try_idle = am35x_musb_try_idle, - - .set_vbus = am35x_musb_set_vbus, -}; - -static u64 am35x_dmamask = DMA_BIT_MASK(32); - -static int __devinit am35x_probe(struct platform_device *pdev) -{ - struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; - struct platform_device *musb; - struct am35x_glue *glue; - - struct clk *phy_clk; - struct clk *clk; - - int ret = -ENOMEM; - - glue = kzalloc(sizeof(*glue), GFP_KERNEL); - if (!glue) { - dev_err(&pdev->dev, "failed to allocate glue context\n"); - goto err0; - } - - musb = platform_device_alloc("musb-hdrc", -1); - if (!musb) { - dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err1; - } - - phy_clk = clk_get(&pdev->dev, "fck"); - if (IS_ERR(phy_clk)) { - dev_err(&pdev->dev, "failed to get PHY clock\n"); - ret = PTR_ERR(phy_clk); - goto err2; - } - - clk = clk_get(&pdev->dev, "ick"); - if (IS_ERR(clk)) { - dev_err(&pdev->dev, "failed to get clock\n"); - ret = PTR_ERR(clk); - goto err3; - } - - ret = clk_enable(phy_clk); - if (ret) { - dev_err(&pdev->dev, "failed to enable PHY clock\n"); - goto err4; - } - - ret = clk_enable(clk); - if (ret) { - dev_err(&pdev->dev, "failed to enable clock\n"); - goto err5; - } - - musb->dev.parent = &pdev->dev; - musb->dev.dma_mask = &am35x_dmamask; - musb->dev.coherent_dma_mask = am35x_dmamask; - - glue->dev = &pdev->dev; - glue->musb = musb; - glue->phy_clk = phy_clk; - glue->clk = clk; - - pdata->platform_ops = &am35x_ops; - - platform_set_drvdata(pdev, glue); - - ret = platform_device_add_resources(musb, pdev->resource, - pdev->num_resources); - if (ret) { - dev_err(&pdev->dev, "failed to add resources\n"); - goto err6; - } - - ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); - if (ret) { - dev_err(&pdev->dev, "failed to add platform_data\n"); - goto err6; - } - - ret = platform_device_add(musb); - if (ret) { - dev_err(&pdev->dev, "failed to register musb device\n"); - goto err6; - } - - return 0; - -err6: - clk_disable(clk); - -err5: - clk_disable(phy_clk); - -err4: - clk_put(clk); - -err3: - clk_put(phy_clk); - -err2: - platform_device_put(musb); - -err1: - kfree(glue); - -err0: - return ret; -} - -static int __devexit am35x_remove(struct platform_device *pdev) -{ - struct am35x_glue *glue = platform_get_drvdata(pdev); - - platform_device_del(glue->musb); - platform_device_put(glue->musb); - clk_disable(glue->clk); - clk_disable(glue->phy_clk); - clk_put(glue->clk); - clk_put(glue->phy_clk); - kfree(glue); - - return 0; -} - -#ifdef CONFIG_PM -static int am35x_suspend(struct device *dev) -{ - struct am35x_glue *glue = dev_get_drvdata(dev); - struct musb_hdrc_platform_data *plat = dev->platform_data; - struct omap_musb_board_data *data = plat->board_data; - - /* Shutdown the on-chip PHY and its PLL. */ - if (data->set_phy_power) - data->set_phy_power(0); - - clk_disable(glue->phy_clk); - clk_disable(glue->clk); - - return 0; -} - -static int am35x_resume(struct device *dev) -{ - struct am35x_glue *glue = dev_get_drvdata(dev); - struct musb_hdrc_platform_data *plat = dev->platform_data; - struct omap_musb_board_data *data = plat->board_data; - int ret; - - /* Start the on-chip PHY and its PLL. */ - if (data->set_phy_power) - data->set_phy_power(1); - - ret = clk_enable(glue->phy_clk); - if (ret) { - dev_err(dev, "failed to enable PHY clock\n"); - return ret; - } - - ret = clk_enable(glue->clk); - if (ret) { - dev_err(dev, "failed to enable clock\n"); - return ret; - } - - return 0; -} - -static struct dev_pm_ops am35x_pm_ops = { - .suspend = am35x_suspend, - .resume = am35x_resume, -}; - -#define DEV_PM_OPS &am35x_pm_ops -#else -#define DEV_PM_OPS NULL -#endif - -static struct platform_driver am35x_driver = { - .probe = am35x_probe, - .remove = __devexit_p(am35x_remove), - .driver = { - .name = "musb-am35x", - .pm = DEV_PM_OPS, - }, -}; - -MODULE_DESCRIPTION("AM35x MUSB Glue Layer"); -MODULE_AUTHOR("Ajay Kumar Gupta "); -MODULE_LICENSE("GPL v2"); - -static int __init am35x_init(void) -{ - return platform_driver_register(&am35x_driver); -} -module_init(am35x_init); - -static void __exit am35x_exit(void) -{ - platform_driver_unregister(&am35x_driver); -} -module_exit(am35x_exit); diff --git a/ANDROID_3.4.5/drivers/usb/musb/blackfin.c b/ANDROID_3.4.5/drivers/usb/musb/blackfin.c deleted file mode 100644 index a087ed6c..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/blackfin.c +++ /dev/null @@ -1,600 +0,0 @@ -/* - * MUSB OTG controller driver for Blackfin Processors - * - * Copyright 2006-2008 Analog Devices Inc. - * - * Enter bugs at http://blackfin.uclinux.org/ - * - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "musb_core.h" -#include "musbhsdma.h" -#include "blackfin.h" - -struct bfin_glue { - struct device *dev; - struct platform_device *musb; -}; -#define glue_to_musb(g) platform_get_drvdata(g->musb) - -/* - * Load an endpoint's FIFO - */ -void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) -{ - struct musb *musb = hw_ep->musb; - void __iomem *fifo = hw_ep->fifo; - void __iomem *epio = hw_ep->regs; - u8 epnum = hw_ep->epnum; - - prefetch((u8 *)src); - - musb_writew(epio, MUSB_TXCOUNT, len); - - dev_dbg(musb->controller, "TX ep%d fifo %p count %d buf %p, epio %p\n", - hw_ep->epnum, fifo, len, src, epio); - - dump_fifo_data(src, len); - - if (!ANOMALY_05000380 && epnum != 0) { - u16 dma_reg; - - flush_dcache_range((unsigned long)src, - (unsigned long)(src + len)); - - /* Setup DMA address register */ - dma_reg = (u32)src; - bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_LOW), dma_reg); - SSYNC(); - - dma_reg = (u32)src >> 16; - bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_HIGH), dma_reg); - SSYNC(); - - /* Setup DMA count register */ - bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_LOW), len); - bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_HIGH), 0); - SSYNC(); - - /* Enable the DMA */ - dma_reg = (epnum << 4) | DMA_ENA | INT_ENA | DIRECTION; - bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), dma_reg); - SSYNC(); - - /* Wait for compelete */ - while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << epnum))) - cpu_relax(); - - /* acknowledge dma interrupt */ - bfin_write_USB_DMA_INTERRUPT(1 << epnum); - SSYNC(); - - /* Reset DMA */ - bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), 0); - SSYNC(); - } else { - SSYNC(); - - if (unlikely((unsigned long)src & 0x01)) - outsw_8((unsigned long)fifo, src, (len + 1) >> 1); - else - outsw((unsigned long)fifo, src, (len + 1) >> 1); - } -} -/* - * Unload an endpoint's FIFO - */ -void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) -{ - struct musb *musb = hw_ep->musb; - void __iomem *fifo = hw_ep->fifo; - u8 epnum = hw_ep->epnum; - - if (ANOMALY_05000467 && epnum != 0) { - u16 dma_reg; - - invalidate_dcache_range((unsigned long)dst, - (unsigned long)(dst + len)); - - /* Setup DMA address register */ - dma_reg = (u32)dst; - bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_LOW), dma_reg); - SSYNC(); - - dma_reg = (u32)dst >> 16; - bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_HIGH), dma_reg); - SSYNC(); - - /* Setup DMA count register */ - bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_LOW), len); - bfin_write16(USB_DMA_REG(epnum, USB_DMAx_COUNT_HIGH), 0); - SSYNC(); - - /* Enable the DMA */ - dma_reg = (epnum << 4) | DMA_ENA | INT_ENA; - bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), dma_reg); - SSYNC(); - - /* Wait for compelete */ - while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << epnum))) - cpu_relax(); - - /* acknowledge dma interrupt */ - bfin_write_USB_DMA_INTERRUPT(1 << epnum); - SSYNC(); - - /* Reset DMA */ - bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), 0); - SSYNC(); - } else { - SSYNC(); - /* Read the last byte of packet with odd size from address fifo + 4 - * to trigger 1 byte access to EP0 FIFO. - */ - if (len == 1) - *dst = (u8)inw((unsigned long)fifo + 4); - else { - if (unlikely((unsigned long)dst & 0x01)) - insw_8((unsigned long)fifo, dst, len >> 1); - else - insw((unsigned long)fifo, dst, len >> 1); - - if (len & 0x01) - *(dst + len - 1) = (u8)inw((unsigned long)fifo + 4); - } - } - dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n", - 'R', hw_ep->epnum, fifo, len, dst); - - dump_fifo_data(dst, len); -} - -static irqreturn_t blackfin_interrupt(int irq, void *__hci) -{ - unsigned long flags; - irqreturn_t retval = IRQ_NONE; - struct musb *musb = __hci; - - spin_lock_irqsave(&musb->lock, flags); - - musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); - musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); - musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); - - if (musb->int_usb || musb->int_tx || musb->int_rx) { - musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb); - musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx); - musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx); - retval = musb_interrupt(musb); - } - - /* Start sampling ID pin, when plug is removed from MUSB */ - if ((is_otg_enabled(musb) && (musb->xceiv->state == OTG_STATE_B_IDLE - || musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) || - (musb->int_usb & MUSB_INTR_DISCONNECT && is_host_active(musb))) { - mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); - musb->a_wait_bcon = TIMER_DELAY; - } - - spin_unlock_irqrestore(&musb->lock, flags); - - return retval; -} - -static void musb_conn_timer_handler(unsigned long _musb) -{ - struct musb *musb = (void *)_musb; - unsigned long flags; - u16 val; - static u8 toggle; - - spin_lock_irqsave(&musb->lock, flags); - switch (musb->xceiv->state) { - case OTG_STATE_A_IDLE: - case OTG_STATE_A_WAIT_BCON: - /* Start a new session */ - val = musb_readw(musb->mregs, MUSB_DEVCTL); - val &= ~MUSB_DEVCTL_SESSION; - musb_writew(musb->mregs, MUSB_DEVCTL, val); - val |= MUSB_DEVCTL_SESSION; - musb_writew(musb->mregs, MUSB_DEVCTL, val); - /* Check if musb is host or peripheral. */ - 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; - } else { - gpio_set_value(musb->config->gpio_vrsel, 0); - /* Ignore VBUSERROR and SUSPEND IRQ */ - val = musb_readb(musb->mregs, MUSB_INTRUSBE); - val &= ~MUSB_INTR_VBUSERROR; - musb_writeb(musb->mregs, MUSB_INTRUSBE, val); - - val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR; - musb_writeb(musb->mregs, MUSB_INTRUSB, val); - if (is_otg_enabled(musb)) - musb->xceiv->state = OTG_STATE_B_IDLE; - else - musb_writeb(musb->mregs, MUSB_POWER, MUSB_POWER_HSENAB); - } - mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); - break; - case OTG_STATE_B_IDLE: - - if (!is_peripheral_enabled(musb)) - break; - /* Start a new session. It seems that MUSB needs taking - * some time to recognize the type of the plug inserted? - */ - val = musb_readw(musb->mregs, MUSB_DEVCTL); - val |= MUSB_DEVCTL_SESSION; - musb_writew(musb->mregs, MUSB_DEVCTL, val); - 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; - } else { - gpio_set_value(musb->config->gpio_vrsel, 0); - - /* Ignore VBUSERROR and SUSPEND IRQ */ - val = musb_readb(musb->mregs, MUSB_INTRUSBE); - val &= ~MUSB_INTR_VBUSERROR; - musb_writeb(musb->mregs, MUSB_INTRUSBE, val); - - val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR; - musb_writeb(musb->mregs, MUSB_INTRUSB, val); - - /* Toggle the Soft Conn bit, so that we can response to - * the inserting of either A-plug or B-plug. - */ - if (toggle) { - val = musb_readb(musb->mregs, MUSB_POWER); - val &= ~MUSB_POWER_SOFTCONN; - musb_writeb(musb->mregs, MUSB_POWER, val); - toggle = 0; - } else { - val = musb_readb(musb->mregs, MUSB_POWER); - val |= MUSB_POWER_SOFTCONN; - musb_writeb(musb->mregs, MUSB_POWER, val); - toggle = 1; - } - /* The delay time is set to 1/4 second by default, - * shortening it, if accelerating A-plug detection - * is needed in OTG mode. - */ - mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY / 4); - } - break; - default: - dev_dbg(musb->controller, "%s state not handled\n", - otg_state_string(musb->xceiv->state)); - break; - } - spin_unlock_irqrestore(&musb->lock, flags); - - dev_dbg(musb->controller, "state is %s\n", - otg_state_string(musb->xceiv->state)); -} - -static void bfin_musb_enable(struct musb *musb) -{ - if (!is_otg_enabled(musb) && is_host_enabled(musb)) { - mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); - musb->a_wait_bcon = TIMER_DELAY; - } -} - -static void bfin_musb_disable(struct musb *musb) -{ -} - -static void bfin_musb_set_vbus(struct musb *musb, int is_on) -{ - int value = musb->config->gpio_vrsel_active; - if (!is_on) - value = !value; - gpio_set_value(musb->config->gpio_vrsel, value); - - dev_dbg(musb->controller, "VBUS %s, devctl %02x " - /* otg %3x conf %08x prcm %08x */ "\n", - otg_state_string(musb->xceiv->state), - musb_readb(musb->mregs, MUSB_DEVCTL)); -} - -static int bfin_musb_set_power(struct usb_phy *x, unsigned mA) -{ - return 0; -} - -static void bfin_musb_try_idle(struct musb *musb, unsigned long timeout) -{ - if (!is_otg_enabled(musb) && is_host_enabled(musb)) - mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); -} - -static int bfin_musb_vbus_status(struct musb *musb) -{ - return 0; -} - -static int bfin_musb_set_mode(struct musb *musb, u8 musb_mode) -{ - return -EIO; -} - -static int bfin_musb_adjust_channel_params(struct dma_channel *channel, - u16 packet_sz, u8 *mode, - dma_addr_t *dma_addr, u32 *len) -{ - struct musb_dma_channel *musb_channel = channel->private_data; - - /* - * Anomaly 05000450 might cause data corruption when using DMA - * MODE 1 transmits with short packet. So to work around this, - * we truncate all MODE 1 transfers down to a multiple of the - * max packet size, and then do the last short packet transfer - * (if there is any) using MODE 0. - */ - if (ANOMALY_05000450) { - if (musb_channel->transmit && *mode == 1) - *len = *len - (*len % packet_sz); - } - - return 0; -} - -static void bfin_musb_reg_init(struct musb *musb) -{ - if (ANOMALY_05000346) { - bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value); - SSYNC(); - } - - if (ANOMALY_05000347) { - bfin_write_USB_APHY_CNTRL(0x0); - SSYNC(); - } - - /* Configure PLL oscillator register */ - bfin_write_USB_PLLOSC_CTRL(0x3080 | - ((480/musb->config->clkin) << 1)); - SSYNC(); - - bfin_write_USB_SRP_CLKDIV((get_sclk()/1000) / 32 - 1); - SSYNC(); - - bfin_write_USB_EP_NI0_RXMAXP(64); - SSYNC(); - - bfin_write_USB_EP_NI0_TXMAXP(64); - SSYNC(); - - /* Route INTRUSB/INTR_RX/INTR_TX to USB_INT0*/ - bfin_write_USB_GLOBINTR(0x7); - SSYNC(); - - bfin_write_USB_GLOBAL_CTL(GLOBAL_ENA | EP1_TX_ENA | EP2_TX_ENA | - EP3_TX_ENA | EP4_TX_ENA | EP5_TX_ENA | - EP6_TX_ENA | EP7_TX_ENA | EP1_RX_ENA | - EP2_RX_ENA | EP3_RX_ENA | EP4_RX_ENA | - EP5_RX_ENA | EP6_RX_ENA | EP7_RX_ENA); - SSYNC(); -} - -static int bfin_musb_init(struct musb *musb) -{ - - /* - * Rev 1.0 BF549 EZ-KITs require PE7 to be high for both DEVICE - * and OTG HOST modes, while rev 1.1 and greater require PE7 to - * be low for DEVICE mode and high for HOST mode. We set it high - * here because we are in host mode - */ - - if (gpio_request(musb->config->gpio_vrsel, "USB_VRSEL")) { - printk(KERN_ERR "Failed ro request USB_VRSEL GPIO_%d\n", - musb->config->gpio_vrsel); - return -ENODEV; - } - gpio_direction_output(musb->config->gpio_vrsel, 0); - - usb_nop_xceiv_register(); - musb->xceiv = usb_get_transceiver(); - if (!musb->xceiv) { - gpio_free(musb->config->gpio_vrsel); - return -ENODEV; - } - - bfin_musb_reg_init(musb); - - if (is_host_enabled(musb)) { - setup_timer(&musb_conn_timer, - musb_conn_timer_handler, (unsigned long) musb); - } - if (is_peripheral_enabled(musb)) - musb->xceiv->set_power = bfin_musb_set_power; - - musb->isr = blackfin_interrupt; - musb->double_buffer_not_ok = true; - - return 0; -} - -static int bfin_musb_exit(struct musb *musb) -{ - gpio_free(musb->config->gpio_vrsel); - - usb_put_transceiver(musb->xceiv); - usb_nop_xceiv_unregister(); - return 0; -} - -static const struct musb_platform_ops bfin_ops = { - .init = bfin_musb_init, - .exit = bfin_musb_exit, - - .enable = bfin_musb_enable, - .disable = bfin_musb_disable, - - .set_mode = bfin_musb_set_mode, - .try_idle = bfin_musb_try_idle, - - .vbus_status = bfin_musb_vbus_status, - .set_vbus = bfin_musb_set_vbus, - - .adjust_channel_params = bfin_musb_adjust_channel_params, -}; - -static u64 bfin_dmamask = DMA_BIT_MASK(32); - -static int __devinit bfin_probe(struct platform_device *pdev) -{ - struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; - struct platform_device *musb; - struct bfin_glue *glue; - - int ret = -ENOMEM; - - glue = kzalloc(sizeof(*glue), GFP_KERNEL); - if (!glue) { - dev_err(&pdev->dev, "failed to allocate glue context\n"); - goto err0; - } - - musb = platform_device_alloc("musb-hdrc", -1); - if (!musb) { - dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err1; - } - - musb->dev.parent = &pdev->dev; - musb->dev.dma_mask = &bfin_dmamask; - musb->dev.coherent_dma_mask = bfin_dmamask; - - glue->dev = &pdev->dev; - glue->musb = musb; - - pdata->platform_ops = &bfin_ops; - - platform_set_drvdata(pdev, glue); - - ret = platform_device_add_resources(musb, pdev->resource, - pdev->num_resources); - if (ret) { - dev_err(&pdev->dev, "failed to add resources\n"); - goto err2; - } - - ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); - if (ret) { - dev_err(&pdev->dev, "failed to add platform_data\n"); - goto err2; - } - - ret = platform_device_add(musb); - if (ret) { - dev_err(&pdev->dev, "failed to register musb device\n"); - goto err2; - } - - return 0; - -err2: - platform_device_put(musb); - -err1: - kfree(glue); - -err0: - return ret; -} - -static int __devexit bfin_remove(struct platform_device *pdev) -{ - struct bfin_glue *glue = platform_get_drvdata(pdev); - - platform_device_del(glue->musb); - platform_device_put(glue->musb); - kfree(glue); - - return 0; -} - -#ifdef CONFIG_PM -static int bfin_suspend(struct device *dev) -{ - struct bfin_glue *glue = dev_get_drvdata(dev); - struct musb *musb = glue_to_musb(glue); - - if (is_host_active(musb)) - /* - * During hibernate gpio_vrsel will change from high to low - * low which will generate wakeup event resume the system - * immediately. Set it to 0 before hibernate to avoid this - * wakeup event. - */ - gpio_set_value(musb->config->gpio_vrsel, 0); - - return 0; -} - -static int bfin_resume(struct device *dev) -{ - struct bfin_glue *glue = dev_get_drvdata(dev); - struct musb *musb = glue_to_musb(glue); - - bfin_musb_reg_init(musb); - - return 0; -} - -static struct dev_pm_ops bfin_pm_ops = { - .suspend = bfin_suspend, - .resume = bfin_resume, -}; - -#define DEV_PM_OPS &bfin_pm_ops -#else -#define DEV_PM_OPS NULL -#endif - -static struct platform_driver bfin_driver = { - .probe = bfin_probe, - .remove = __exit_p(bfin_remove), - .driver = { - .name = "musb-blackfin", - .pm = DEV_PM_OPS, - }, -}; - -MODULE_DESCRIPTION("Blackfin MUSB Glue Layer"); -MODULE_AUTHOR("Bryan Wy "); -MODULE_LICENSE("GPL v2"); - -static int __init bfin_init(void) -{ - return platform_driver_register(&bfin_driver); -} -module_init(bfin_init); - -static void __exit bfin_exit(void) -{ - platform_driver_unregister(&bfin_driver); -} -module_exit(bfin_exit); diff --git a/ANDROID_3.4.5/drivers/usb/musb/blackfin.h b/ANDROID_3.4.5/drivers/usb/musb/blackfin.h deleted file mode 100644 index c84dae54..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/blackfin.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2007 by Analog Devices, Inc. - * - * The Inventra Controller Driver for Linux 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 __MUSB_BLACKFIN_H__ -#define __MUSB_BLACKFIN_H__ - -/* - * Blackfin specific definitions - */ - -/* Anomalies notes: - * - * 05000450 - USB DMA Mode 1 Short Packet Data Corruption: - * MUSB driver is designed to transfer buffer of N * maxpacket size - * in DMA mode 1 and leave the rest of the data to the next - * transfer in DMA mode 0, so we never transmit a short packet in - * DMA mode 1. - * - * 05000463 - This anomaly doesn't affect this driver since it - * never uses L1 or L2 memory as data destination. - * - * 05000464 - This anomaly doesn't affect this driver since it - * never uses L1 or L2 memory as data source. - * - * 05000465 - The anomaly can be seen when SCLK is over 100 MHz, and there is - * no way to workaround for bulk endpoints. Since the wMaxPackSize - * of bulk is less than or equal to 512, while the fifo size of - * endpoint 5, 6, 7 is 1024, the double buffer mode is enabled - * automatically when these endpoints are used for bulk OUT. - * - * 05000466 - This anomaly doesn't affect this driver since it never mixes - * concurrent DMA and core accesses to the TX endpoint FIFOs. - * - * 05000467 - The workaround for this anomaly will introduce another - * anomaly - 05000465. - */ - -/* The Mentor USB DMA engine on BF52x (silicon v0.0 and v0.1) seems to be - * unstable in host mode. This may be caused by Anomaly 05000380. After - * digging out the root cause, we will change this number accordingly. - * So, need to either use silicon v0.2+ or disable DMA mode in MUSB. - */ -#if ANOMALY_05000380 && defined(CONFIG_BF52x) && \ - !defined(CONFIG_MUSB_PIO_ONLY) -# error "Please use PIO mode in MUSB driver on bf52x chip v0.0 and v0.1" -#endif - -#undef DUMP_FIFO_DATA -#ifdef DUMP_FIFO_DATA -static void dump_fifo_data(u8 *buf, u16 len) -{ - u8 *tmp = buf; - int i; - - for (i = 0; i < len; i++) { - if (!(i % 16) && i) - pr_debug("\n"); - pr_debug("%02x ", *tmp++); - } - pr_debug("\n"); -} -#else -#define dump_fifo_data(buf, len) do {} while (0) -#endif - - -#define USB_DMA_BASE USB_DMA_INTERRUPT -#define USB_DMAx_CTRL 0x04 -#define USB_DMAx_ADDR_LOW 0x08 -#define USB_DMAx_ADDR_HIGH 0x0C -#define USB_DMAx_COUNT_LOW 0x10 -#define USB_DMAx_COUNT_HIGH 0x14 - -#define USB_DMA_REG(ep, reg) (USB_DMA_BASE + 0x20 * ep + reg) - -/* Almost 1 second */ -#define TIMER_DELAY (1 * HZ) - -static struct timer_list musb_conn_timer; - -#endif /* __MUSB_BLACKFIN_H__ */ diff --git a/ANDROID_3.4.5/drivers/usb/musb/cppi_dma.c b/ANDROID_3.4.5/drivers/usb/musb/cppi_dma.c deleted file mode 100644 index 66bc3760..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/cppi_dma.c +++ /dev/null @@ -1,1563 +0,0 @@ -/* - * Copyright (C) 2005-2006 by Texas Instruments - * - * This file implements a DMA interface using TI's CPPI DMA. - * For now it's DaVinci-only, but CPPI isn't specific to DaVinci or USB. - * The TUSB6020, using VLYNQ, has CPPI that looks much like DaVinci. - */ - -#include -#include -#include - -#include "musb_core.h" -#include "musb_debug.h" -#include "cppi_dma.h" - - -/* CPPI DMA status 7-mar-2006: - * - * - See musb_{host,gadget}.c for more info - * - * - Correct RX DMA generally forces the engine into irq-per-packet mode, - * which can easily saturate the CPU under non-mass-storage loads. - * - * NOTES 24-aug-2006 (2.6.18-rc4): - * - * - peripheral RXDMA wedged in a test with packets of length 512/512/1. - * evidently after the 1 byte packet was received and acked, the queue - * of BDs got garbaged so it wouldn't empty the fifo. (rxcsr 0x2003, - * and RX DMA0: 4 left, 80000000 8feff880, 8feff860 8feff860; 8f321401 - * 004001ff 00000001 .. 8feff860) Host was just getting NAKed on tx - * of its next (512 byte) packet. IRQ issues? - * - * REVISIT: the "transfer DMA" glue between CPPI and USB fifos will - * evidently also directly update the RX and TX CSRs ... so audit all - * host and peripheral side DMA code to avoid CSR access after DMA has - * been started. - */ - -/* REVISIT now we can avoid preallocating these descriptors; or - * more simply, switch to a global freelist not per-channel ones. - * Note: at full speed, 64 descriptors == 4K bulk data. - */ -#define NUM_TXCHAN_BD 64 -#define NUM_RXCHAN_BD 64 - -static inline void cpu_drain_writebuffer(void) -{ - wmb(); -#ifdef CONFIG_CPU_ARM926T - /* REVISIT this "should not be needed", - * but lack of it sure seemed to hurt ... - */ - asm("mcr p15, 0, r0, c7, c10, 4 @ drain write buffer\n"); -#endif -} - -static inline struct cppi_descriptor *cppi_bd_alloc(struct cppi_channel *c) -{ - struct cppi_descriptor *bd = c->freelist; - - if (bd) - c->freelist = bd->next; - return bd; -} - -static inline void -cppi_bd_free(struct cppi_channel *c, struct cppi_descriptor *bd) -{ - if (!bd) - return; - bd->next = c->freelist; - c->freelist = bd; -} - -/* - * Start DMA controller - * - * Initialize the DMA controller as necessary. - */ - -/* zero out entire rx state RAM entry for the channel */ -static void cppi_reset_rx(struct cppi_rx_stateram __iomem *rx) -{ - musb_writel(&rx->rx_skipbytes, 0, 0); - musb_writel(&rx->rx_head, 0, 0); - musb_writel(&rx->rx_sop, 0, 0); - musb_writel(&rx->rx_current, 0, 0); - musb_writel(&rx->rx_buf_current, 0, 0); - musb_writel(&rx->rx_len_len, 0, 0); - musb_writel(&rx->rx_cnt_cnt, 0, 0); -} - -/* zero out entire tx state RAM entry for the channel */ -static void cppi_reset_tx(struct cppi_tx_stateram __iomem *tx, u32 ptr) -{ - musb_writel(&tx->tx_head, 0, 0); - musb_writel(&tx->tx_buf, 0, 0); - musb_writel(&tx->tx_current, 0, 0); - musb_writel(&tx->tx_buf_current, 0, 0); - musb_writel(&tx->tx_info, 0, 0); - musb_writel(&tx->tx_rem_len, 0, 0); - /* musb_writel(&tx->tx_dummy, 0, 0); */ - musb_writel(&tx->tx_complete, 0, ptr); -} - -static void __init cppi_pool_init(struct cppi *cppi, struct cppi_channel *c) -{ - int j; - - /* initialize channel fields */ - c->head = NULL; - c->tail = NULL; - c->last_processed = NULL; - c->channel.status = MUSB_DMA_STATUS_UNKNOWN; - c->controller = cppi; - c->is_rndis = 0; - c->freelist = NULL; - - /* build the BD Free list for the channel */ - for (j = 0; j < NUM_TXCHAN_BD + 1; j++) { - struct cppi_descriptor *bd; - dma_addr_t dma; - - bd = dma_pool_alloc(cppi->pool, GFP_KERNEL, &dma); - bd->dma = dma; - cppi_bd_free(c, bd); - } -} - -static int cppi_channel_abort(struct dma_channel *); - -static void cppi_pool_free(struct cppi_channel *c) -{ - struct cppi *cppi = c->controller; - struct cppi_descriptor *bd; - - (void) cppi_channel_abort(&c->channel); - c->channel.status = MUSB_DMA_STATUS_UNKNOWN; - c->controller = NULL; - - /* free all its bds */ - bd = c->last_processed; - do { - if (bd) - dma_pool_free(cppi->pool, bd, bd->dma); - bd = cppi_bd_alloc(c); - } while (bd); - c->last_processed = NULL; -} - -static int __init cppi_controller_start(struct dma_controller *c) -{ - struct cppi *controller; - void __iomem *tibase; - int i; - - controller = container_of(c, struct cppi, controller); - - /* do whatever is necessary to start controller */ - for (i = 0; i < ARRAY_SIZE(controller->tx); i++) { - controller->tx[i].transmit = true; - controller->tx[i].index = i; - } - for (i = 0; i < ARRAY_SIZE(controller->rx); i++) { - controller->rx[i].transmit = false; - controller->rx[i].index = i; - } - - /* setup BD list on a per channel basis */ - for (i = 0; i < ARRAY_SIZE(controller->tx); i++) - cppi_pool_init(controller, controller->tx + i); - for (i = 0; i < ARRAY_SIZE(controller->rx); i++) - cppi_pool_init(controller, controller->rx + i); - - tibase = controller->tibase; - INIT_LIST_HEAD(&controller->tx_complete); - - /* initialise tx/rx channel head pointers to zero */ - for (i = 0; i < ARRAY_SIZE(controller->tx); i++) { - struct cppi_channel *tx_ch = controller->tx + i; - struct cppi_tx_stateram __iomem *tx; - - INIT_LIST_HEAD(&tx_ch->tx_complete); - - tx = tibase + DAVINCI_TXCPPI_STATERAM_OFFSET(i); - tx_ch->state_ram = tx; - cppi_reset_tx(tx, 0); - } - for (i = 0; i < ARRAY_SIZE(controller->rx); i++) { - struct cppi_channel *rx_ch = controller->rx + i; - struct cppi_rx_stateram __iomem *rx; - - INIT_LIST_HEAD(&rx_ch->tx_complete); - - rx = tibase + DAVINCI_RXCPPI_STATERAM_OFFSET(i); - rx_ch->state_ram = rx; - cppi_reset_rx(rx); - } - - /* enable individual cppi channels */ - musb_writel(tibase, DAVINCI_TXCPPI_INTENAB_REG, - DAVINCI_DMA_ALL_CHANNELS_ENABLE); - musb_writel(tibase, DAVINCI_RXCPPI_INTENAB_REG, - DAVINCI_DMA_ALL_CHANNELS_ENABLE); - - /* enable tx/rx CPPI control */ - musb_writel(tibase, DAVINCI_TXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_ENABLE); - musb_writel(tibase, DAVINCI_RXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_ENABLE); - - /* disable RNDIS mode, also host rx RNDIS autorequest */ - musb_writel(tibase, DAVINCI_RNDIS_REG, 0); - musb_writel(tibase, DAVINCI_AUTOREQ_REG, 0); - - return 0; -} - -/* - * Stop DMA controller - * - * De-Init the DMA controller as necessary. - */ - -static int cppi_controller_stop(struct dma_controller *c) -{ - struct cppi *controller; - void __iomem *tibase; - int i; - struct musb *musb; - - controller = container_of(c, struct cppi, controller); - musb = controller->musb; - - tibase = controller->tibase; - /* DISABLE INDIVIDUAL CHANNEL Interrupts */ - musb_writel(tibase, DAVINCI_TXCPPI_INTCLR_REG, - DAVINCI_DMA_ALL_CHANNELS_ENABLE); - musb_writel(tibase, DAVINCI_RXCPPI_INTCLR_REG, - DAVINCI_DMA_ALL_CHANNELS_ENABLE); - - dev_dbg(musb->controller, "Tearing down RX and TX Channels\n"); - for (i = 0; i < ARRAY_SIZE(controller->tx); i++) { - /* FIXME restructure of txdma to use bds like rxdma */ - controller->tx[i].last_processed = NULL; - cppi_pool_free(controller->tx + i); - } - for (i = 0; i < ARRAY_SIZE(controller->rx); i++) - cppi_pool_free(controller->rx + i); - - /* in Tx Case proper teardown is supported. We resort to disabling - * Tx/Rx CPPI after cleanup of Tx channels. Before TX teardown is - * complete TX CPPI cannot be disabled. - */ - /*disable tx/rx cppi */ - musb_writel(tibase, DAVINCI_TXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE); - musb_writel(tibase, DAVINCI_RXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE); - - return 0; -} - -/* While dma channel is allocated, we only want the core irqs active - * for fault reports, otherwise we'd get irqs that we don't care about. - * Except for TX irqs, where dma done != fifo empty and reusable ... - * - * NOTE: docs don't say either way, but irq masking **enables** irqs. - * - * REVISIT same issue applies to pure PIO usage too, and non-cppi dma... - */ -static inline void core_rxirq_disable(void __iomem *tibase, unsigned epnum) -{ - musb_writel(tibase, DAVINCI_USB_INT_MASK_CLR_REG, 1 << (epnum + 8)); -} - -static inline void core_rxirq_enable(void __iomem *tibase, unsigned epnum) -{ - musb_writel(tibase, DAVINCI_USB_INT_MASK_SET_REG, 1 << (epnum + 8)); -} - - -/* - * Allocate a CPPI Channel for DMA. With CPPI, channels are bound to - * each transfer direction of a non-control endpoint, so allocating - * (and deallocating) is mostly a way to notice bad housekeeping on - * the software side. We assume the irqs are always active. - */ -static struct dma_channel * -cppi_channel_allocate(struct dma_controller *c, - struct musb_hw_ep *ep, u8 transmit) -{ - struct cppi *controller; - u8 index; - struct cppi_channel *cppi_ch; - void __iomem *tibase; - struct musb *musb; - - controller = container_of(c, struct cppi, controller); - tibase = controller->tibase; - musb = controller->musb; - - /* ep0 doesn't use DMA; remember cppi indices are 0..N-1 */ - index = ep->epnum - 1; - - /* return the corresponding CPPI Channel Handle, and - * probably disable the non-CPPI irq until we need it. - */ - if (transmit) { - if (index >= ARRAY_SIZE(controller->tx)) { - dev_dbg(musb->controller, "no %cX%d CPPI channel\n", 'T', index); - return NULL; - } - cppi_ch = controller->tx + index; - } else { - if (index >= ARRAY_SIZE(controller->rx)) { - dev_dbg(musb->controller, "no %cX%d CPPI channel\n", 'R', index); - return NULL; - } - cppi_ch = controller->rx + index; - core_rxirq_disable(tibase, ep->epnum); - } - - /* REVISIT make this an error later once the same driver code works - * with the other DMA engine too - */ - if (cppi_ch->hw_ep) - dev_dbg(musb->controller, "re-allocating DMA%d %cX channel %p\n", - index, transmit ? 'T' : 'R', cppi_ch); - cppi_ch->hw_ep = ep; - cppi_ch->channel.status = MUSB_DMA_STATUS_FREE; - cppi_ch->channel.max_len = 0x7fffffff; - - dev_dbg(musb->controller, "Allocate CPPI%d %cX\n", index, transmit ? 'T' : 'R'); - return &cppi_ch->channel; -} - -/* Release a CPPI Channel. */ -static void cppi_channel_release(struct dma_channel *channel) -{ - struct cppi_channel *c; - void __iomem *tibase; - - /* REVISIT: for paranoia, check state and abort if needed... */ - - c = container_of(channel, struct cppi_channel, channel); - tibase = c->controller->tibase; - if (!c->hw_ep) - dev_dbg(c->controller->musb->controller, - "releasing idle DMA channel %p\n", c); - else if (!c->transmit) - core_rxirq_enable(tibase, c->index + 1); - - /* for now, leave its cppi IRQ enabled (we won't trigger it) */ - c->hw_ep = NULL; - channel->status = MUSB_DMA_STATUS_UNKNOWN; -} - -/* Context: controller irqlocked */ -static void -cppi_dump_rx(int level, struct cppi_channel *c, const char *tag) -{ - void __iomem *base = c->controller->mregs; - struct cppi_rx_stateram __iomem *rx = c->state_ram; - - musb_ep_select(base, c->index + 1); - - dev_dbg(c->controller->musb->controller, - "RX DMA%d%s: %d left, csr %04x, " - "%08x H%08x S%08x C%08x, " - "B%08x L%08x %08x .. %08x" - "\n", - c->index, tag, - musb_readl(c->controller->tibase, - DAVINCI_RXCPPI_BUFCNT0_REG + 4 * c->index), - musb_readw(c->hw_ep->regs, MUSB_RXCSR), - - musb_readl(&rx->rx_skipbytes, 0), - musb_readl(&rx->rx_head, 0), - musb_readl(&rx->rx_sop, 0), - musb_readl(&rx->rx_current, 0), - - musb_readl(&rx->rx_buf_current, 0), - musb_readl(&rx->rx_len_len, 0), - musb_readl(&rx->rx_cnt_cnt, 0), - musb_readl(&rx->rx_complete, 0) - ); -} - -/* Context: controller irqlocked */ -static void -cppi_dump_tx(int level, struct cppi_channel *c, const char *tag) -{ - void __iomem *base = c->controller->mregs; - struct cppi_tx_stateram __iomem *tx = c->state_ram; - - musb_ep_select(base, c->index + 1); - - dev_dbg(c->controller->musb->controller, - "TX DMA%d%s: csr %04x, " - "H%08x S%08x C%08x %08x, " - "F%08x L%08x .. %08x" - "\n", - c->index, tag, - musb_readw(c->hw_ep->regs, MUSB_TXCSR), - - musb_readl(&tx->tx_head, 0), - musb_readl(&tx->tx_buf, 0), - musb_readl(&tx->tx_current, 0), - musb_readl(&tx->tx_buf_current, 0), - - musb_readl(&tx->tx_info, 0), - musb_readl(&tx->tx_rem_len, 0), - /* dummy/unused word 6 */ - musb_readl(&tx->tx_complete, 0) - ); -} - -/* Context: controller irqlocked */ -static inline void -cppi_rndis_update(struct cppi_channel *c, int is_rx, - void __iomem *tibase, int is_rndis) -{ - /* we may need to change the rndis flag for this cppi channel */ - if (c->is_rndis != is_rndis) { - u32 value = musb_readl(tibase, DAVINCI_RNDIS_REG); - u32 temp = 1 << (c->index); - - if (is_rx) - temp <<= 16; - if (is_rndis) - value |= temp; - else - value &= ~temp; - musb_writel(tibase, DAVINCI_RNDIS_REG, value); - c->is_rndis = is_rndis; - } -} - -#ifdef CONFIG_USB_MUSB_DEBUG -static void cppi_dump_rxbd(const char *tag, struct cppi_descriptor *bd) -{ - pr_debug("RXBD/%s %08x: " - "nxt %08x buf %08x off.blen %08x opt.plen %08x\n", - tag, bd->dma, - bd->hw_next, bd->hw_bufp, bd->hw_off_len, - bd->hw_options); -} -#endif - -static void cppi_dump_rxq(int level, const char *tag, struct cppi_channel *rx) -{ -#ifdef CONFIG_USB_MUSB_DEBUG - struct cppi_descriptor *bd; - - if (!_dbg_level(level)) - return; - cppi_dump_rx(level, rx, tag); - if (rx->last_processed) - cppi_dump_rxbd("last", rx->last_processed); - for (bd = rx->head; bd; bd = bd->next) - cppi_dump_rxbd("active", bd); -#endif -} - - -/* NOTE: DaVinci autoreq is ignored except for host side "RNDIS" mode RX; - * so we won't ever use it (see "CPPI RX Woes" below). - */ -static inline int cppi_autoreq_update(struct cppi_channel *rx, - void __iomem *tibase, int onepacket, unsigned n_bds) -{ - u32 val; - -#ifdef RNDIS_RX_IS_USABLE - u32 tmp; - /* assert(is_host_active(musb)) */ - - /* start from "AutoReq never" */ - tmp = musb_readl(tibase, DAVINCI_AUTOREQ_REG); - val = tmp & ~((0x3) << (rx->index * 2)); - - /* HCD arranged reqpkt for packet #1. we arrange int - * for all but the last one, maybe in two segments. - */ - if (!onepacket) { -#if 0 - /* use two segments, autoreq "all" then the last "never" */ - val |= ((0x3) << (rx->index * 2)); - n_bds--; -#else - /* one segment, autoreq "all-but-last" */ - val |= ((0x1) << (rx->index * 2)); -#endif - } - - if (val != tmp) { - int n = 100; - - /* make sure that autoreq is updated before continuing */ - musb_writel(tibase, DAVINCI_AUTOREQ_REG, val); - do { - tmp = musb_readl(tibase, DAVINCI_AUTOREQ_REG); - if (tmp == val) - break; - cpu_relax(); - } while (n-- > 0); - } -#endif - - /* REQPKT is turned off after each segment */ - if (n_bds && rx->channel.actual_len) { - void __iomem *regs = rx->hw_ep->regs; - - val = musb_readw(regs, MUSB_RXCSR); - if (!(val & MUSB_RXCSR_H_REQPKT)) { - val |= MUSB_RXCSR_H_REQPKT | MUSB_RXCSR_H_WZC_BITS; - musb_writew(regs, MUSB_RXCSR, val); - /* flush writebuffer */ - val = musb_readw(regs, MUSB_RXCSR); - } - } - return n_bds; -} - - -/* Buffer enqueuing Logic: - * - * - RX builds new queues each time, to help handle routine "early - * termination" cases (faults, including errors and short reads) - * more correctly. - * - * - for now, TX reuses the same queue of BDs every time - * - * REVISIT long term, we want a normal dynamic model. - * ... the goal will be to append to the - * existing queue, processing completed "dma buffers" (segments) on the fly. - * - * Otherwise we force an IRQ latency between requests, which slows us a lot - * (especially in "transparent" dma). Unfortunately that model seems to be - * inherent in the DMA model from the Mentor code, except in the rare case - * of transfers big enough (~128+ KB) that we could append "middle" segments - * in the TX paths. (RX can't do this, see below.) - * - * That's true even in the CPPI- friendly iso case, where most urbs have - * several small segments provided in a group and where the "packet at a time" - * "transparent" DMA model is always correct, even on the RX side. - */ - -/* - * CPPI TX: - * ======== - * TX is a lot more reasonable than RX; it doesn't need to run in - * irq-per-packet mode very often. RNDIS mode seems to behave too - * (except how it handles the exactly-N-packets case). Building a - * txdma queue with multiple requests (urb or usb_request) looks - * like it would work ... but fault handling would need much testing. - * - * The main issue with TX mode RNDIS relates to transfer lengths that - * are an exact multiple of the packet length. It appears that there's - * a hiccup in that case (maybe the DMA completes before the ZLP gets - * written?) boiling down to not being able to rely on CPPI writing any - * terminating zero length packet before the next transfer is written. - * So that's punted to PIO; better yet, gadget drivers can avoid it. - * - * Plus, there's allegedly an undocumented constraint that rndis transfer - * length be a multiple of 64 bytes ... but the chip doesn't act that - * way, and we really don't _want_ that behavior anyway. - * - * On TX, "transparent" mode works ... although experiments have shown - * problems trying to use the SOP/EOP bits in different USB packets. - * - * REVISIT try to handle terminating zero length packets using CPPI - * instead of doing it by PIO after an IRQ. (Meanwhile, make Ethernet - * links avoid that issue by forcing them to avoid zlps.) - */ -static void -cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx) -{ - unsigned maxpacket = tx->maxpacket; - dma_addr_t addr = tx->buf_dma + tx->offset; - size_t length = tx->buf_len - tx->offset; - struct cppi_descriptor *bd; - unsigned n_bds; - unsigned i; - struct cppi_tx_stateram __iomem *tx_ram = tx->state_ram; - int rndis; - - /* TX can use the CPPI "rndis" mode, where we can probably fit this - * transfer in one BD and one IRQ. The only time we would NOT want - * to use it is when hardware constraints prevent it, or if we'd - * trigger the "send a ZLP?" confusion. - */ - rndis = (maxpacket & 0x3f) == 0 - && length > maxpacket - && length < 0xffff - && (length % maxpacket) != 0; - - if (rndis) { - maxpacket = length; - n_bds = 1; - } else { - n_bds = length / maxpacket; - if (!length || (length % maxpacket)) - n_bds++; - n_bds = min(n_bds, (unsigned) NUM_TXCHAN_BD); - length = min(n_bds * maxpacket, length); - } - - dev_dbg(musb->controller, "TX DMA%d, pktSz %d %s bds %d dma 0x%llx len %u\n", - tx->index, - maxpacket, - rndis ? "rndis" : "transparent", - n_bds, - (unsigned long long)addr, length); - - cppi_rndis_update(tx, 0, musb->ctrl_base, rndis); - - /* assuming here that channel_program is called during - * transfer initiation ... current code maintains state - * for one outstanding request only (no queues, not even - * the implicit ones of an iso urb). - */ - - bd = tx->freelist; - tx->head = bd; - tx->last_processed = NULL; - - /* FIXME use BD pool like RX side does, and just queue - * the minimum number for this request. - */ - - /* Prepare queue of BDs first, then hand it to hardware. - * All BDs except maybe the last should be of full packet - * size; for RNDIS there _is_ only that last packet. - */ - for (i = 0; i < n_bds; ) { - if (++i < n_bds && bd->next) - bd->hw_next = bd->next->dma; - else - bd->hw_next = 0; - - bd->hw_bufp = tx->buf_dma + tx->offset; - - /* FIXME set EOP only on the last packet, - * SOP only on the first ... avoid IRQs - */ - if ((tx->offset + maxpacket) <= tx->buf_len) { - tx->offset += maxpacket; - bd->hw_off_len = maxpacket; - bd->hw_options = CPPI_SOP_SET | CPPI_EOP_SET - | CPPI_OWN_SET | maxpacket; - } else { - /* only this one may be a partial USB Packet */ - u32 partial_len; - - partial_len = tx->buf_len - tx->offset; - tx->offset = tx->buf_len; - bd->hw_off_len = partial_len; - - bd->hw_options = CPPI_SOP_SET | CPPI_EOP_SET - | CPPI_OWN_SET | partial_len; - if (partial_len == 0) - bd->hw_options |= CPPI_ZERO_SET; - } - - dev_dbg(musb->controller, "TXBD %p: nxt %08x buf %08x len %04x opt %08x\n", - bd, bd->hw_next, bd->hw_bufp, - bd->hw_off_len, bd->hw_options); - - /* update the last BD enqueued to the list */ - tx->tail = bd; - bd = bd->next; - } - - /* BDs live in DMA-coherent memory, but writes might be pending */ - cpu_drain_writebuffer(); - - /* Write to the HeadPtr in state RAM to trigger */ - musb_writel(&tx_ram->tx_head, 0, (u32)tx->freelist->dma); - - cppi_dump_tx(5, tx, "/S"); -} - -/* - * CPPI RX Woes: - * ============= - * Consider a 1KB bulk RX buffer in two scenarios: (a) it's fed two 300 byte - * packets back-to-back, and (b) it's fed two 512 byte packets back-to-back. - * (Full speed transfers have similar scenarios.) - * - * The correct behavior for Linux is that (a) fills the buffer with 300 bytes, - * and the next packet goes into a buffer that's queued later; while (b) fills - * the buffer with 1024 bytes. How to do that with CPPI? - * - * - RX queues in "rndis" mode -- one single BD -- handle (a) correctly, but - * (b) loses **BADLY** because nothing (!) happens when that second packet - * fills the buffer, much less when a third one arrives. (Which makes this - * not a "true" RNDIS mode. In the RNDIS protocol short-packet termination - * is optional, and it's fine if peripherals -- not hosts! -- pad messages - * out to end-of-buffer. Standard PCI host controller DMA descriptors - * implement that mode by default ... which is no accident.) - * - * - RX queues in "transparent" mode -- two BDs with 512 bytes each -- have - * converse problems: (b) is handled right, but (a) loses badly. CPPI RX - * ignores SOP/EOP markings and processes both of those BDs; so both packets - * are loaded into the buffer (with a 212 byte gap between them), and the next - * buffer queued will NOT get its 300 bytes of data. (It seems like SOP/EOP - * are intended as outputs for RX queues, not inputs...) - * - * - A variant of "transparent" mode -- one BD at a time -- is the only way to - * reliably make both cases work, with software handling both cases correctly - * and at the significant penalty of needing an IRQ per packet. (The lack of - * I/O overlap can be slightly ameliorated by enabling double buffering.) - * - * So how to get rid of IRQ-per-packet? The transparent multi-BD case could - * be used in special cases like mass storage, which sets URB_SHORT_NOT_OK - * (or maybe its peripheral side counterpart) to flag (a) scenarios as errors - * with guaranteed driver level fault recovery and scrubbing out what's left - * of that garbaged datastream. - * - * But there seems to be no way to identify the cases where CPPI RNDIS mode - * is appropriate -- which do NOT include RNDIS host drivers, but do include - * the CDC Ethernet driver! -- and the documentation is incomplete/wrong. - * So we can't _ever_ use RX RNDIS mode ... except by using a heuristic - * that applies best on the peripheral side (and which could fail rudely). - * - * Leaving only "transparent" mode; we avoid multi-bd modes in almost all - * cases other than mass storage class. Otherwise we're correct but slow, - * since CPPI penalizes our need for a "true RNDIS" default mode. - */ - - -/* Heuristic, intended to kick in for ethernet/rndis peripheral ONLY - * - * IFF - * (a) peripheral mode ... since rndis peripherals could pad their - * writes to hosts, causing i/o failure; or we'd have to cope with - * a largely unknowable variety of host side protocol variants - * (b) and short reads are NOT errors ... since full reads would - * cause those same i/o failures - * (c) and read length is - * - less than 64KB (max per cppi descriptor) - * - not a multiple of 4096 (g_zero default, full reads typical) - * - N (>1) packets long, ditto (full reads not EXPECTED) - * THEN - * try rx rndis mode - * - * Cost of heuristic failing: RXDMA wedges at the end of transfers that - * fill out the whole buffer. Buggy host side usb network drivers could - * trigger that, but "in the field" such bugs seem to be all but unknown. - * - * So this module parameter lets the heuristic be disabled. When using - * gadgetfs, the heuristic will probably need to be disabled. - */ -static bool cppi_rx_rndis = 1; - -module_param(cppi_rx_rndis, bool, 0); -MODULE_PARM_DESC(cppi_rx_rndis, "enable/disable RX RNDIS heuristic"); - - -/** - * cppi_next_rx_segment - dma read for the next chunk of a buffer - * @musb: the controller - * @rx: dma channel - * @onepacket: true unless caller treats short reads as errors, and - * performs fault recovery above usbcore. - * Context: controller irqlocked - * - * See above notes about why we can't use multi-BD RX queues except in - * rare cases (mass storage class), and can never use the hardware "rndis" - * mode (since it's not a "true" RNDIS mode) with complete safety.. - * - * It's ESSENTIAL that callers specify "onepacket" mode unless they kick in - * code to recover from corrupted datastreams after each short transfer. - */ -static void -cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket) -{ - unsigned maxpacket = rx->maxpacket; - dma_addr_t addr = rx->buf_dma + rx->offset; - size_t length = rx->buf_len - rx->offset; - struct cppi_descriptor *bd, *tail; - unsigned n_bds; - unsigned i; - void __iomem *tibase = musb->ctrl_base; - int is_rndis = 0; - struct cppi_rx_stateram __iomem *rx_ram = rx->state_ram; - - if (onepacket) { - /* almost every USB driver, host or peripheral side */ - n_bds = 1; - - /* maybe apply the heuristic above */ - if (cppi_rx_rndis - && is_peripheral_active(musb) - && length > maxpacket - && (length & ~0xffff) == 0 - && (length & 0x0fff) != 0 - && (length & (maxpacket - 1)) == 0) { - maxpacket = length; - is_rndis = 1; - } - } else { - /* virtually nothing except mass storage class */ - if (length > 0xffff) { - n_bds = 0xffff / maxpacket; - length = n_bds * maxpacket; - } else { - n_bds = length / maxpacket; - if (length % maxpacket) - n_bds++; - } - if (n_bds == 1) - onepacket = 1; - else - n_bds = min(n_bds, (unsigned) NUM_RXCHAN_BD); - } - - /* In host mode, autorequest logic can generate some IN tokens; it's - * tricky since we can't leave REQPKT set in RXCSR after the transfer - * finishes. So: multipacket transfers involve two or more segments. - * And always at least two IRQs ... RNDIS mode is not an option. - */ - if (is_host_active(musb)) - n_bds = cppi_autoreq_update(rx, tibase, onepacket, n_bds); - - cppi_rndis_update(rx, 1, musb->ctrl_base, is_rndis); - - length = min(n_bds * maxpacket, length); - - dev_dbg(musb->controller, "RX DMA%d seg, maxp %d %s bds %d (cnt %d) " - "dma 0x%llx len %u %u/%u\n", - rx->index, maxpacket, - onepacket - ? (is_rndis ? "rndis" : "onepacket") - : "multipacket", - n_bds, - musb_readl(tibase, - DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4)) - & 0xffff, - (unsigned long long)addr, length, - rx->channel.actual_len, rx->buf_len); - - /* only queue one segment at a time, since the hardware prevents - * correct queue shutdown after unexpected short packets - */ - bd = cppi_bd_alloc(rx); - rx->head = bd; - - /* Build BDs for all packets in this segment */ - for (i = 0, tail = NULL; bd && i < n_bds; i++, tail = bd) { - u32 bd_len; - - if (i) { - bd = cppi_bd_alloc(rx); - if (!bd) - break; - tail->next = bd; - tail->hw_next = bd->dma; - } - bd->hw_next = 0; - - /* all but the last packet will be maxpacket size */ - if (maxpacket < length) - bd_len = maxpacket; - else - bd_len = length; - - bd->hw_bufp = addr; - addr += bd_len; - rx->offset += bd_len; - - bd->hw_off_len = (0 /*offset*/ << 16) + bd_len; - bd->buflen = bd_len; - - bd->hw_options = CPPI_OWN_SET | (i == 0 ? length : 0); - length -= bd_len; - } - - /* we always expect at least one reusable BD! */ - if (!tail) { - WARNING("rx dma%d -- no BDs? need %d\n", rx->index, n_bds); - return; - } else if (i < n_bds) - WARNING("rx dma%d -- only %d of %d BDs\n", rx->index, i, n_bds); - - tail->next = NULL; - tail->hw_next = 0; - - bd = rx->head; - rx->tail = tail; - - /* short reads and other faults should terminate this entire - * dma segment. we want one "dma packet" per dma segment, not - * one per USB packet, terminating the whole queue at once... - * NOTE that current hardware seems to ignore SOP and EOP. - */ - bd->hw_options |= CPPI_SOP_SET; - tail->hw_options |= CPPI_EOP_SET; - -#ifdef CONFIG_USB_MUSB_DEBUG - if (_dbg_level(5)) { - struct cppi_descriptor *d; - - for (d = rx->head; d; d = d->next) - cppi_dump_rxbd("S", d); - } -#endif - - /* in case the preceding transfer left some state... */ - tail = rx->last_processed; - if (tail) { - tail->next = bd; - tail->hw_next = bd->dma; - } - - core_rxirq_enable(tibase, rx->index + 1); - - /* BDs live in DMA-coherent memory, but writes might be pending */ - cpu_drain_writebuffer(); - - /* REVISIT specs say to write this AFTER the BUFCNT register - * below ... but that loses badly. - */ - musb_writel(&rx_ram->rx_head, 0, bd->dma); - - /* bufferCount must be at least 3, and zeroes on completion - * unless it underflows below zero, or stops at two, or keeps - * growing ... grr. - */ - i = musb_readl(tibase, - DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4)) - & 0xffff; - - if (!i) - musb_writel(tibase, - DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4), - n_bds + 2); - else if (n_bds > (i - 3)) - musb_writel(tibase, - DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4), - n_bds - (i - 3)); - - i = musb_readl(tibase, - DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4)) - & 0xffff; - if (i < (2 + n_bds)) { - dev_dbg(musb->controller, "bufcnt%d underrun - %d (for %d)\n", - rx->index, i, n_bds); - musb_writel(tibase, - DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4), - n_bds + 2); - } - - cppi_dump_rx(4, rx, "/S"); -} - -/** - * cppi_channel_program - program channel for data transfer - * @ch: the channel - * @maxpacket: max packet size - * @mode: For RX, 1 unless the usb protocol driver promised to treat - * all short reads as errors and kick in high level fault recovery. - * For TX, ignored because of RNDIS mode races/glitches. - * @dma_addr: dma address of buffer - * @len: length of buffer - * Context: controller irqlocked - */ -static int cppi_channel_program(struct dma_channel *ch, - u16 maxpacket, u8 mode, - dma_addr_t dma_addr, u32 len) -{ - struct cppi_channel *cppi_ch; - struct cppi *controller; - struct musb *musb; - - cppi_ch = container_of(ch, struct cppi_channel, channel); - controller = cppi_ch->controller; - musb = controller->musb; - - switch (ch->status) { - case MUSB_DMA_STATUS_BUS_ABORT: - case MUSB_DMA_STATUS_CORE_ABORT: - /* fault irq handler should have handled cleanup */ - WARNING("%cX DMA%d not cleaned up after abort!\n", - cppi_ch->transmit ? 'T' : 'R', - cppi_ch->index); - /* WARN_ON(1); */ - break; - case MUSB_DMA_STATUS_BUSY: - WARNING("program active channel? %cX DMA%d\n", - cppi_ch->transmit ? 'T' : 'R', - cppi_ch->index); - /* WARN_ON(1); */ - break; - case MUSB_DMA_STATUS_UNKNOWN: - dev_dbg(musb->controller, "%cX DMA%d not allocated!\n", - cppi_ch->transmit ? 'T' : 'R', - cppi_ch->index); - /* FALLTHROUGH */ - case MUSB_DMA_STATUS_FREE: - break; - } - - ch->status = MUSB_DMA_STATUS_BUSY; - - /* set transfer parameters, then queue up its first segment */ - cppi_ch->buf_dma = dma_addr; - cppi_ch->offset = 0; - cppi_ch->maxpacket = maxpacket; - cppi_ch->buf_len = len; - cppi_ch->channel.actual_len = 0; - - /* TX channel? or RX? */ - if (cppi_ch->transmit) - cppi_next_tx_segment(musb, cppi_ch); - else - cppi_next_rx_segment(musb, cppi_ch, mode); - - return true; -} - -static bool cppi_rx_scan(struct cppi *cppi, unsigned ch) -{ - struct cppi_channel *rx = &cppi->rx[ch]; - struct cppi_rx_stateram __iomem *state = rx->state_ram; - struct cppi_descriptor *bd; - struct cppi_descriptor *last = rx->last_processed; - bool completed = false; - bool acked = false; - int i; - dma_addr_t safe2ack; - void __iomem *regs = rx->hw_ep->regs; - struct musb *musb = cppi->musb; - - cppi_dump_rx(6, rx, "/K"); - - bd = last ? last->next : rx->head; - if (!bd) - return false; - - /* run through all completed BDs */ - for (i = 0, safe2ack = musb_readl(&state->rx_complete, 0); - (safe2ack || completed) && bd && i < NUM_RXCHAN_BD; - i++, bd = bd->next) { - u16 len; - - /* catch latest BD writes from CPPI */ - rmb(); - if (!completed && (bd->hw_options & CPPI_OWN_SET)) - break; - - dev_dbg(musb->controller, "C/RXBD %llx: nxt %08x buf %08x " - "off.len %08x opt.len %08x (%d)\n", - (unsigned long long)bd->dma, bd->hw_next, bd->hw_bufp, - bd->hw_off_len, bd->hw_options, - rx->channel.actual_len); - - /* actual packet received length */ - if ((bd->hw_options & CPPI_SOP_SET) && !completed) - len = bd->hw_off_len & CPPI_RECV_PKTLEN_MASK; - else - len = 0; - - if (bd->hw_options & CPPI_EOQ_MASK) - completed = true; - - if (!completed && len < bd->buflen) { - /* NOTE: when we get a short packet, RXCSR_H_REQPKT - * must have been cleared, and no more DMA packets may - * active be in the queue... TI docs didn't say, but - * CPPI ignores those BDs even though OWN is still set. - */ - completed = true; - dev_dbg(musb->controller, "rx short %d/%d (%d)\n", - len, bd->buflen, - rx->channel.actual_len); - } - - /* If we got here, we expect to ack at least one BD; meanwhile - * CPPI may completing other BDs while we scan this list... - * - * RACE: we can notice OWN cleared before CPPI raises the - * matching irq by writing that BD as the completion pointer. - * In such cases, stop scanning and wait for the irq, avoiding - * lost acks and states where BD ownership is unclear. - */ - if (bd->dma == safe2ack) { - musb_writel(&state->rx_complete, 0, safe2ack); - safe2ack = musb_readl(&state->rx_complete, 0); - acked = true; - if (bd->dma == safe2ack) - safe2ack = 0; - } - - rx->channel.actual_len += len; - - cppi_bd_free(rx, last); - last = bd; - - /* stop scanning on end-of-segment */ - if (bd->hw_next == 0) - completed = true; - } - rx->last_processed = last; - - /* dma abort, lost ack, or ... */ - if (!acked && last) { - int csr; - - if (safe2ack == 0 || safe2ack == rx->last_processed->dma) - musb_writel(&state->rx_complete, 0, safe2ack); - if (safe2ack == 0) { - cppi_bd_free(rx, last); - rx->last_processed = NULL; - - /* if we land here on the host side, H_REQPKT will - * be clear and we need to restart the queue... - */ - WARN_ON(rx->head); - } - musb_ep_select(cppi->mregs, rx->index + 1); - csr = musb_readw(regs, MUSB_RXCSR); - if (csr & MUSB_RXCSR_DMAENAB) { - dev_dbg(musb->controller, "list%d %p/%p, last %llx%s, csr %04x\n", - rx->index, - rx->head, rx->tail, - rx->last_processed - ? (unsigned long long) - rx->last_processed->dma - : 0, - completed ? ", completed" : "", - csr); - cppi_dump_rxq(4, "/what?", rx); - } - } - if (!completed) { - int csr; - - rx->head = bd; - - /* REVISIT seems like "autoreq all but EOP" doesn't... - * setting it here "should" be racey, but seems to work - */ - csr = musb_readw(rx->hw_ep->regs, MUSB_RXCSR); - if (is_host_active(cppi->musb) - && bd - && !(csr & MUSB_RXCSR_H_REQPKT)) { - csr |= MUSB_RXCSR_H_REQPKT; - musb_writew(regs, MUSB_RXCSR, - MUSB_RXCSR_H_WZC_BITS | csr); - csr = musb_readw(rx->hw_ep->regs, MUSB_RXCSR); - } - } else { - rx->head = NULL; - rx->tail = NULL; - } - - cppi_dump_rx(6, rx, completed ? "/completed" : "/cleaned"); - return completed; -} - -irqreturn_t cppi_interrupt(int irq, void *dev_id) -{ - struct musb *musb = dev_id; - struct cppi *cppi; - void __iomem *tibase; - struct musb_hw_ep *hw_ep = NULL; - u32 rx, tx; - int i, index; - unsigned long uninitialized_var(flags); - - cppi = container_of(musb->dma_controller, struct cppi, controller); - if (cppi->irq) - spin_lock_irqsave(&musb->lock, flags); - - tibase = musb->ctrl_base; - - tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG); - rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG); - - if (!tx && !rx) { - if (cppi->irq) - spin_unlock_irqrestore(&musb->lock, flags); - return IRQ_NONE; - } - - dev_dbg(musb->controller, "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; - struct cppi_tx_stateram __iomem *tx_ram; - bool completed = false; - struct cppi_descriptor *bd; - - if (!(tx & 1)) - continue; - - tx_ch = cppi->tx + index; - tx_ram = tx_ch->state_ram; - - /* FIXME need a cppi_tx_scan() routine, which - * can also be called from abort code - */ - - cppi_dump_tx(5, tx_ch, "/E"); - - bd = tx_ch->head; - - /* - * If Head is null then this could mean that a abort interrupt - * that needs to be acknowledged. - */ - if (NULL == bd) { - dev_dbg(musb->controller, "null BD\n"); - musb_writel(&tx_ram->tx_complete, 0, 0); - continue; - } - - /* run through all completed BDs */ - for (i = 0; !completed && bd && i < NUM_TXCHAN_BD; - i++, bd = bd->next) { - u16 len; - - /* catch latest BD writes from CPPI */ - rmb(); - if (bd->hw_options & CPPI_OWN_SET) - break; - - dev_dbg(musb->controller, "C/TXBD %p n %x b %x off %x opt %x\n", - bd, bd->hw_next, bd->hw_bufp, - bd->hw_off_len, bd->hw_options); - - len = bd->hw_off_len & CPPI_BUFFER_LEN_MASK; - tx_ch->channel.actual_len += len; - - tx_ch->last_processed = bd; - - /* write completion register to acknowledge - * processing of completed BDs, and possibly - * release the IRQ; EOQ might not be set ... - * - * REVISIT use the same ack strategy as rx - * - * REVISIT have observed bit 18 set; huh?? - */ - /* if ((bd->hw_options & CPPI_EOQ_MASK)) */ - musb_writel(&tx_ram->tx_complete, 0, bd->dma); - - /* stop scanning on end-of-segment */ - if (bd->hw_next == 0) - completed = true; - } - - /* on end of segment, maybe go to next one */ - if (completed) { - /* cppi_dump_tx(4, tx_ch, "/complete"); */ - - /* transfer more, or report completion */ - if (tx_ch->offset >= tx_ch->buf_len) { - tx_ch->head = NULL; - tx_ch->tail = NULL; - tx_ch->channel.status = MUSB_DMA_STATUS_FREE; - - hw_ep = tx_ch->hw_ep; - - musb_dma_completion(musb, index + 1, 1); - - } else { - /* Bigger transfer than we could fit in - * that first batch of descriptors... - */ - cppi_next_tx_segment(musb, tx_ch); - } - } else - tx_ch->head = bd; - } - - /* Start processing the RX block */ - for (index = 0; rx; rx = rx >> 1, index++) { - - if (rx & 1) { - struct cppi_channel *rx_ch; - - rx_ch = cppi->rx + index; - - /* let incomplete dma segments finish */ - if (!cppi_rx_scan(cppi, index)) - continue; - - /* start another dma segment if needed */ - if (rx_ch->channel.actual_len != rx_ch->buf_len - && rx_ch->channel.actual_len - == rx_ch->offset) { - cppi_next_rx_segment(musb, rx_ch, 1); - continue; - } - - /* all segments completed! */ - rx_ch->channel.status = MUSB_DMA_STATUS_FREE; - - hw_ep = rx_ch->hw_ep; - - core_rxirq_disable(tibase, index + 1); - musb_dma_completion(musb, index + 1, 0); - } - } - - /* write to CPPI EOI register to re-enable interrupts */ - musb_writel(tibase, DAVINCI_CPPI_EOI_REG, 0); - - if (cppi->irq) - spin_unlock_irqrestore(&musb->lock, flags); - - return IRQ_HANDLED; -} - -/* Instantiate a software object representing a DMA controller. */ -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_byname(pdev, "dma"); - - controller = kzalloc(sizeof *controller, GFP_KERNEL); - if (!controller) - return NULL; - - controller->mregs = mregs; - controller->tibase = mregs - DAVINCI_BASE_OFFSET; - - controller->musb = musb; - controller->controller.start = cppi_controller_start; - controller->controller.stop = cppi_controller_stop; - controller->controller.channel_alloc = cppi_channel_allocate; - controller->controller.channel_release = cppi_channel_release; - controller->controller.channel_program = cppi_channel_program; - controller->controller.channel_abort = cppi_channel_abort; - - /* NOTE: allocating from on-chip SRAM would give the least - * contention for memory access, if that ever matters here. - */ - - /* setup BufferPool */ - controller->pool = dma_pool_create("cppi", - controller->musb->controller, - sizeof(struct cppi_descriptor), - CPPI_DESCRIPTOR_ALIGN, 0); - if (!controller->pool) { - kfree(controller); - 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; -} - -/* - * Destroy a previously-instantiated DMA controller. - */ -void dma_controller_destroy(struct dma_controller *c) -{ - struct cppi *cppi; - - 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); - - kfree(cppi); -} - -/* - * Context: controller irqlocked, endpoint selected - */ -static int cppi_channel_abort(struct dma_channel *channel) -{ - struct cppi_channel *cppi_ch; - struct cppi *controller; - void __iomem *mbase; - void __iomem *tibase; - void __iomem *regs; - u32 value; - struct cppi_descriptor *queue; - - cppi_ch = container_of(channel, struct cppi_channel, channel); - - controller = cppi_ch->controller; - - switch (channel->status) { - case MUSB_DMA_STATUS_BUS_ABORT: - case MUSB_DMA_STATUS_CORE_ABORT: - /* from RX or TX fault irq handler */ - case MUSB_DMA_STATUS_BUSY: - /* the hardware needs shutting down */ - regs = cppi_ch->hw_ep->regs; - break; - case MUSB_DMA_STATUS_UNKNOWN: - case MUSB_DMA_STATUS_FREE: - return 0; - default: - return -EINVAL; - } - - if (!cppi_ch->transmit && cppi_ch->head) - cppi_dump_rxq(3, "/abort", cppi_ch); - - mbase = controller->mregs; - tibase = controller->tibase; - - queue = cppi_ch->head; - cppi_ch->head = NULL; - cppi_ch->tail = NULL; - - /* REVISIT should rely on caller having done this, - * and caller should rely on us not changing it. - * peripheral code is safe ... check host too. - */ - musb_ep_select(mbase, cppi_ch->index + 1); - - if (cppi_ch->transmit) { - struct cppi_tx_stateram __iomem *tx_ram; - /* REVISIT put timeouts on these controller handshakes */ - - cppi_dump_tx(6, cppi_ch, " (teardown)"); - - /* teardown DMA engine then usb core */ - do { - value = musb_readl(tibase, DAVINCI_TXCPPI_TEAR_REG); - } while (!(value & CPPI_TEAR_READY)); - musb_writel(tibase, DAVINCI_TXCPPI_TEAR_REG, cppi_ch->index); - - tx_ram = cppi_ch->state_ram; - do { - value = musb_readl(&tx_ram->tx_complete, 0); - } while (0xFFFFFFFC != value); - - /* FIXME clean up the transfer state ... here? - * the completion routine should get called with - * an appropriate status code. - */ - - value = musb_readw(regs, MUSB_TXCSR); - value &= ~MUSB_TXCSR_DMAENAB; - value |= MUSB_TXCSR_FLUSHFIFO; - musb_writew(regs, MUSB_TXCSR, value); - musb_writew(regs, MUSB_TXCSR, value); - - /* - * 1. Write to completion Ptr value 0x1(bit 0 set) - * (write back mode) - * 2. Wait for abort interrupt and then put the channel in - * compare mode by writing 1 to the tx_complete register. - */ - cppi_reset_tx(tx_ram, 1); - cppi_ch->head = NULL; - musb_writel(&tx_ram->tx_complete, 0, 1); - cppi_dump_tx(5, cppi_ch, " (done teardown)"); - - /* REVISIT tx side _should_ clean up the same way - * as the RX side ... this does no cleanup at all! - */ - - } else /* RX */ { - u16 csr; - - /* NOTE: docs don't guarantee any of this works ... we - * expect that if the usb core stops telling the cppi core - * to pull more data from it, then it'll be safe to flush - * current RX DMA state iff any pending fifo transfer is done. - */ - - core_rxirq_disable(tibase, cppi_ch->index + 1); - - /* for host, ensure ReqPkt is never set again */ - if (is_host_active(cppi_ch->controller->musb)) { - value = musb_readl(tibase, DAVINCI_AUTOREQ_REG); - value &= ~((0x3) << (cppi_ch->index * 2)); - musb_writel(tibase, DAVINCI_AUTOREQ_REG, value); - } - - csr = musb_readw(regs, MUSB_RXCSR); - - /* for host, clear (just) ReqPkt at end of current packet(s) */ - if (is_host_active(cppi_ch->controller->musb)) { - csr |= MUSB_RXCSR_H_WZC_BITS; - csr &= ~MUSB_RXCSR_H_REQPKT; - } else - csr |= MUSB_RXCSR_P_WZC_BITS; - - /* clear dma enable */ - csr &= ~(MUSB_RXCSR_DMAENAB); - musb_writew(regs, MUSB_RXCSR, csr); - csr = musb_readw(regs, MUSB_RXCSR); - - /* Quiesce: wait for current dma to finish (if not cleanup). - * We can't use bit zero of stateram->rx_sop, since that - * refers to an entire "DMA packet" not just emptying the - * current fifo. Most segments need multiple usb packets. - */ - if (channel->status == MUSB_DMA_STATUS_BUSY) - udelay(50); - - /* scan the current list, reporting any data that was - * transferred and acking any IRQ - */ - cppi_rx_scan(controller, cppi_ch->index); - - /* clobber the existing state once it's idle - * - * NOTE: arguably, we should also wait for all the other - * RX channels to quiesce (how??) and then temporarily - * disable RXCPPI_CTRL_REG ... but it seems that we can - * rely on the controller restarting from state ram, with - * only RXCPPI_BUFCNT state being bogus. BUFCNT will - * correct itself after the next DMA transfer though. - * - * REVISIT does using rndis mode change that? - */ - cppi_reset_rx(cppi_ch->state_ram); - - /* next DMA request _should_ load cppi head ptr */ - - /* ... we don't "free" that list, only mutate it in place. */ - cppi_dump_rx(5, cppi_ch, " (done abort)"); - - /* clean up previously pending bds */ - cppi_bd_free(cppi_ch, cppi_ch->last_processed); - cppi_ch->last_processed = NULL; - - while (queue) { - struct cppi_descriptor *tmp = queue->next; - - cppi_bd_free(cppi_ch, queue); - queue = tmp; - } - } - - channel->status = MUSB_DMA_STATUS_FREE; - cppi_ch->buf_dma = 0; - cppi_ch->offset = 0; - cppi_ch->buf_len = 0; - cppi_ch->maxpacket = 0; - return 0; -} - -/* TBD Queries: - * - * Power Management ... probably turn off cppi during suspend, restart; - * check state ram? Clocking is presumably shared with usb core. - */ diff --git a/ANDROID_3.4.5/drivers/usb/musb/cppi_dma.h b/ANDROID_3.4.5/drivers/usb/musb/cppi_dma.h deleted file mode 100644 index 59bf949e..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/cppi_dma.h +++ /dev/null @@ -1,134 +0,0 @@ -/* Copyright (C) 2005-2006 by Texas Instruments */ - -#ifndef _CPPI_DMA_H_ -#define _CPPI_DMA_H_ - -#include -#include -#include -#include - -#include "musb_dma.h" -#include "musb_core.h" - - -/* FIXME fully isolate CPPI from DaVinci ... the "CPPI generic" registers - * would seem to be shared with the TUSB6020 (over VLYNQ). - */ - -#include "davinci.h" - - -/* CPPI RX/TX state RAM */ - -struct cppi_tx_stateram { - u32 tx_head; /* "DMA packet" head descriptor */ - u32 tx_buf; - u32 tx_current; /* current descriptor */ - u32 tx_buf_current; - u32 tx_info; /* flags, remaining buflen */ - u32 tx_rem_len; - u32 tx_dummy; /* unused */ - u32 tx_complete; -}; - -struct cppi_rx_stateram { - u32 rx_skipbytes; - u32 rx_head; - u32 rx_sop; /* "DMA packet" head descriptor */ - u32 rx_current; /* current descriptor */ - u32 rx_buf_current; - u32 rx_len_len; - u32 rx_cnt_cnt; - u32 rx_complete; -}; - -/* hw_options bits in CPPI buffer descriptors */ -#define CPPI_SOP_SET ((u32)(1 << 31)) -#define CPPI_EOP_SET ((u32)(1 << 30)) -#define CPPI_OWN_SET ((u32)(1 << 29)) /* owned by cppi */ -#define CPPI_EOQ_MASK ((u32)(1 << 28)) -#define CPPI_ZERO_SET ((u32)(1 << 23)) /* rx saw zlp; tx issues one */ -#define CPPI_RXABT_MASK ((u32)(1 << 19)) /* need more rx buffers */ - -#define CPPI_RECV_PKTLEN_MASK 0xFFFF -#define CPPI_BUFFER_LEN_MASK 0xFFFF - -#define CPPI_TEAR_READY ((u32)(1 << 31)) - -/* CPPI data structure definitions */ - -#define CPPI_DESCRIPTOR_ALIGN 16 /* bytes; 5-dec docs say 4-byte align */ - -struct cppi_descriptor { - /* hardware overlay */ - u32 hw_next; /* next buffer descriptor Pointer */ - u32 hw_bufp; /* i/o buffer pointer */ - u32 hw_off_len; /* buffer_offset16, buffer_length16 */ - u32 hw_options; /* flags: SOP, EOP etc*/ - - struct cppi_descriptor *next; - dma_addr_t dma; /* address of this descriptor */ - u32 buflen; /* for RX: original buffer length */ -} __attribute__ ((aligned(CPPI_DESCRIPTOR_ALIGN))); - - -struct cppi; - -/* CPPI Channel Control structure */ -struct cppi_channel { - struct dma_channel channel; - - /* back pointer to the DMA controller structure */ - struct cppi *controller; - - /* which direction of which endpoint? */ - struct musb_hw_ep *hw_ep; - bool transmit; - u8 index; - - /* DMA modes: RNDIS or "transparent" */ - u8 is_rndis; - - /* book keeping for current transfer request */ - dma_addr_t buf_dma; - u32 buf_len; - u32 maxpacket; - u32 offset; /* dma requested */ - - void __iomem *state_ram; /* CPPI state */ - - struct cppi_descriptor *freelist; - - /* BD management fields */ - struct cppi_descriptor *head; - struct cppi_descriptor *tail; - struct cppi_descriptor *last_processed; - - /* use tx_complete in host role to track endpoints waiting for - * FIFONOTEMPTY to clear. - */ - struct list_head tx_complete; -}; - -/* CPPI DMA controller object */ -struct cppi { - struct dma_controller controller; - struct musb *musb; - void __iomem *mregs; /* Mentor regs */ - void __iomem *tibase; /* TI/CPPI regs */ - - int irq; - - struct cppi_channel tx[4]; - struct cppi_channel rx[4]; - - struct dma_pool *pool; - - struct list_head tx_complete; -}; - -/* CPPI IRQ handler */ -extern irqreturn_t cppi_interrupt(int, void *); - -#endif /* end of ifndef _CPPI_DMA_H_ */ diff --git a/ANDROID_3.4.5/drivers/usb/musb/da8xx.c b/ANDROID_3.4.5/drivers/usb/musb/da8xx.c deleted file mode 100644 index 8bd9566f..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/da8xx.c +++ /dev/null @@ -1,601 +0,0 @@ -/* - * Texas Instruments DA8xx/OMAP-L1x "glue layer" - * - * Copyright (c) 2008-2009 MontaVista Software, Inc. - * - * Based on the DaVinci "glue layer" code. - * Copyright (C) 2005-2006 by Texas Instruments - * - * This file is part of the Inventra Controller Driver for Linux. - * - * The Inventra Controller Driver for Linux 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. - * - * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not, - * write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "musb_core.h" - -/* - * DA8XX specific definitions - */ - -/* USB 2.0 OTG module registers */ -#define DA8XX_USB_REVISION_REG 0x00 -#define DA8XX_USB_CTRL_REG 0x04 -#define DA8XX_USB_STAT_REG 0x08 -#define DA8XX_USB_EMULATION_REG 0x0c -#define DA8XX_USB_MODE_REG 0x10 /* Transparent, CDC, [Generic] RNDIS */ -#define DA8XX_USB_AUTOREQ_REG 0x14 -#define DA8XX_USB_SRP_FIX_TIME_REG 0x18 -#define DA8XX_USB_TEARDOWN_REG 0x1c -#define DA8XX_USB_INTR_SRC_REG 0x20 -#define DA8XX_USB_INTR_SRC_SET_REG 0x24 -#define DA8XX_USB_INTR_SRC_CLEAR_REG 0x28 -#define DA8XX_USB_INTR_MASK_REG 0x2c -#define DA8XX_USB_INTR_MASK_SET_REG 0x30 -#define DA8XX_USB_INTR_MASK_CLEAR_REG 0x34 -#define DA8XX_USB_INTR_SRC_MASKED_REG 0x38 -#define DA8XX_USB_END_OF_INTR_REG 0x3c -#define DA8XX_USB_GENERIC_RNDIS_EP_SIZE_REG(n) (0x50 + (((n) - 1) << 2)) - -/* Control register bits */ -#define DA8XX_SOFT_RESET_MASK 1 - -#define DA8XX_USB_TX_EP_MASK 0x1f /* EP0 + 4 Tx EPs */ -#define DA8XX_USB_RX_EP_MASK 0x1e /* 4 Rx EPs */ - -/* USB interrupt register bits */ -#define DA8XX_INTR_USB_SHIFT 16 -#define DA8XX_INTR_USB_MASK (0x1ff << DA8XX_INTR_USB_SHIFT) /* 8 Mentor */ - /* interrupts and DRVVBUS interrupt */ -#define DA8XX_INTR_DRVVBUS 0x100 -#define DA8XX_INTR_RX_SHIFT 8 -#define DA8XX_INTR_RX_MASK (DA8XX_USB_RX_EP_MASK << DA8XX_INTR_RX_SHIFT) -#define DA8XX_INTR_TX_SHIFT 0 -#define DA8XX_INTR_TX_MASK (DA8XX_USB_TX_EP_MASK << DA8XX_INTR_TX_SHIFT) - -#define DA8XX_MENTOR_CORE_OFFSET 0x400 - -#define CFGCHIP2 IO_ADDRESS(DA8XX_SYSCFG0_BASE + DA8XX_CFGCHIP2_REG) - -struct da8xx_glue { - struct device *dev; - struct platform_device *musb; - struct clk *clk; -}; - -/* - * REVISIT (PM): we should be able to keep the PHY in low power mode most - * of the time (24 MHz oscillator and PLL off, etc.) by setting POWER.D0 - * and, when in host mode, autosuspending idle root ports... PHY_PLLON - * (overriding SUSPENDM?) then likely needs to stay off. - */ - -static inline void phy_on(void) -{ - u32 cfgchip2 = __raw_readl(CFGCHIP2); - - /* - * Start the on-chip PHY and its PLL. - */ - cfgchip2 &= ~(CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN); - cfgchip2 |= CFGCHIP2_PHY_PLLON; - __raw_writel(cfgchip2, CFGCHIP2); - - pr_info("Waiting for USB PHY clock good...\n"); - while (!(__raw_readl(CFGCHIP2) & CFGCHIP2_PHYCLKGD)) - cpu_relax(); -} - -static inline void phy_off(void) -{ - u32 cfgchip2 = __raw_readl(CFGCHIP2); - - /* - * Ensure that USB 1.1 reference clock is not being sourced from - * USB 2.0 PHY. Otherwise do not power down the PHY. - */ - if (!(cfgchip2 & CFGCHIP2_USB1PHYCLKMUX) && - (cfgchip2 & CFGCHIP2_USB1SUSPENDM)) { - pr_warning("USB 1.1 clocked from USB 2.0 PHY -- " - "can't power it down\n"); - return; - } - - /* - * Power down the on-chip PHY. - */ - cfgchip2 |= CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN; - __raw_writel(cfgchip2, CFGCHIP2); -} - -/* - * Because we don't set CTRL.UINT, it's "important" to: - * - not read/write INTRUSB/INTRUSBE (except during - * initial setup, as a workaround); - * - use INTSET/INTCLR instead. - */ - -/** - * da8xx_musb_enable - enable interrupts - */ -static void da8xx_musb_enable(struct musb *musb) -{ - void __iomem *reg_base = musb->ctrl_base; - u32 mask; - - /* Workaround: setup IRQs through both register sets. */ - mask = ((musb->epmask & DA8XX_USB_TX_EP_MASK) << DA8XX_INTR_TX_SHIFT) | - ((musb->epmask & DA8XX_USB_RX_EP_MASK) << DA8XX_INTR_RX_SHIFT) | - DA8XX_INTR_USB_MASK; - musb_writel(reg_base, DA8XX_USB_INTR_MASK_SET_REG, mask); - - /* Force the DRVVBUS IRQ so we can start polling for ID change. */ - if (is_otg_enabled(musb)) - musb_writel(reg_base, DA8XX_USB_INTR_SRC_SET_REG, - DA8XX_INTR_DRVVBUS << DA8XX_INTR_USB_SHIFT); -} - -/** - * da8xx_musb_disable - disable HDRC and flush interrupts - */ -static void da8xx_musb_disable(struct musb *musb) -{ - void __iomem *reg_base = musb->ctrl_base; - - musb_writel(reg_base, DA8XX_USB_INTR_MASK_CLEAR_REG, - DA8XX_INTR_USB_MASK | - DA8XX_INTR_TX_MASK | DA8XX_INTR_RX_MASK); - musb_writeb(musb->mregs, MUSB_DEVCTL, 0); - musb_writel(reg_base, DA8XX_USB_END_OF_INTR_REG, 0); -} - -#define portstate(stmt) stmt - -static void da8xx_musb_set_vbus(struct musb *musb, int is_on) -{ - WARN_ON(is_on && is_peripheral_active(musb)); -} - -#define POLL_SECONDS 2 - -static struct timer_list otg_workaround; - -static void otg_timer(unsigned long _musb) -{ - struct musb *musb = (void *)_musb; - void __iomem *mregs = musb->mregs; - u8 devctl; - unsigned long flags; - - /* - * We poll because DaVinci's won't expose several OTG-critical - * status change events (from the transceiver) otherwise. - */ - devctl = musb_readb(mregs, MUSB_DEVCTL); - dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl, - otg_state_string(musb->xceiv->state)); - - spin_lock_irqsave(&musb->lock, flags); - 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_DEV_MODE(musb); - } else { - musb->xceiv->state = OTG_STATE_A_IDLE; - MUSB_HST_MODE(musb); - } - break; - case OTG_STATE_A_WAIT_VFALL: - /* - * Wait till VBUS falls below SessionEnd (~0.2 V); the 1.3 - * RTL seems to mis-handle session "start" otherwise (or in - * our case "recover"), in routine "VBUS was valid by the time - * VBUSERR got reported during enumeration" cases. - */ - if (devctl & MUSB_DEVCTL_VBUS) { - mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); - break; - } - musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; - musb_writel(musb->ctrl_base, DA8XX_USB_INTR_SRC_SET_REG, - MUSB_INTR_VBUSERROR << DA8XX_INTR_USB_SHIFT); - break; - case OTG_STATE_B_IDLE: - if (!is_peripheral_enabled(musb)) - break; - - /* - * There's no ID-changed IRQ, so we have no good way to tell - * when to switch to the A-Default state machine (by setting - * the DEVCTL.Session bit). - * - * Workaround: whenever we're in B_IDLE, try setting the - * session flag every few seconds. If it works, ID was - * grounded and we're now in the A-Default state machine. - * - * NOTE: setting the session flag is _supposed_ to trigger - * SRP but clearly it doesn't. - */ - musb_writeb(mregs, MUSB_DEVCTL, devctl | MUSB_DEVCTL_SESSION); - devctl = musb_readb(mregs, MUSB_DEVCTL); - if (devctl & MUSB_DEVCTL_BDEVICE) - mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); - else - musb->xceiv->state = OTG_STATE_A_IDLE; - break; - default: - break; - } - spin_unlock_irqrestore(&musb->lock, flags); -} - -static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout) -{ - static unsigned long last_timer; - - if (!is_otg_enabled(musb)) - return; - - if (timeout == 0) - timeout = jiffies + msecs_to_jiffies(3); - - /* 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)) { - dev_dbg(musb->controller, "%s active, deleting timer\n", - otg_state_string(musb->xceiv->state)); - del_timer(&otg_workaround); - last_timer = jiffies; - return; - } - - if (time_after(last_timer, timeout) && timer_pending(&otg_workaround)) { - dev_dbg(musb->controller, "Longer idle timer already pending, ignoring...\n"); - return; - } - last_timer = timeout; - - dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", - otg_state_string(musb->xceiv->state), - jiffies_to_msecs(timeout - jiffies)); - mod_timer(&otg_workaround, timeout); -} - -static irqreturn_t da8xx_musb_interrupt(int irq, void *hci) -{ - struct musb *musb = hci; - void __iomem *reg_base = musb->ctrl_base; - struct usb_otg *otg = musb->xceiv->otg; - unsigned long flags; - irqreturn_t ret = IRQ_NONE; - u32 status; - - spin_lock_irqsave(&musb->lock, flags); - - /* - * NOTE: DA8XX shadows the Mentor IRQs. Don't manage them through - * the Mentor registers (except for setup), use the TI ones and EOI. - */ - - /* Acknowledge and handle non-CPPI interrupts */ - status = musb_readl(reg_base, DA8XX_USB_INTR_SRC_MASKED_REG); - if (!status) - goto eoi; - - musb_writel(reg_base, DA8XX_USB_INTR_SRC_CLEAR_REG, status); - dev_dbg(musb->controller, "USB IRQ %08x\n", status); - - musb->int_rx = (status & DA8XX_INTR_RX_MASK) >> DA8XX_INTR_RX_SHIFT; - musb->int_tx = (status & DA8XX_INTR_TX_MASK) >> DA8XX_INTR_TX_SHIFT; - musb->int_usb = (status & DA8XX_INTR_USB_MASK) >> DA8XX_INTR_USB_SHIFT; - - /* - * DRVVBUS IRQs are the only proxy we have (a very poor one!) for - * DA8xx's missing ID change IRQ. We need an ID change IRQ to - * switch appropriately between halves of the OTG state machine. - * Managing DEVCTL.Session per Mentor docs requires that we know its - * value but DEVCTL.BDevice is invalid without DEVCTL.Session set. - * Also, DRVVBUS pulses for SRP (but not at 5 V)... - */ - if (status & (DA8XX_INTR_DRVVBUS << DA8XX_INTR_USB_SHIFT)) { - int drvvbus = musb_readl(reg_base, DA8XX_USB_STAT_REG); - void __iomem *mregs = musb->mregs; - u8 devctl = musb_readb(mregs, MUSB_DEVCTL); - int err; - - err = is_host_enabled(musb) && (musb->int_usb & - MUSB_INTR_VBUSERROR); - if (err) { - /* - * The Mentor core doesn't debounce VBUS as needed - * to cope with device connect current spikes. This - * means it's not uncommon for bus-powered devices - * to get VBUS errors during enumeration. - * - * This is a workaround, but newer RTL from Mentor - * seems to allow a better one: "re"-starting sessions - * without waiting for VBUS to stop registering in - * devctl. - */ - musb->int_usb &= ~MUSB_INTR_VBUSERROR; - 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_HST_MODE(musb); - otg->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); - otg->default_a = 0; - musb->xceiv->state = OTG_STATE_B_IDLE; - portstate(musb->port1_status &= ~USB_PORT_STAT_POWER); - } - - dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n", - drvvbus ? "on" : "off", - otg_state_string(musb->xceiv->state), - err ? " ERROR" : "", - devctl); - ret = IRQ_HANDLED; - } - - if (musb->int_tx || musb->int_rx || musb->int_usb) - ret |= musb_interrupt(musb); - - eoi: - /* EOI needs to be written for the IRQ to be re-asserted. */ - if (ret == IRQ_HANDLED || status) - musb_writel(reg_base, DA8XX_USB_END_OF_INTR_REG, 0); - - /* Poll for ID change */ - if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE) - mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); - - spin_unlock_irqrestore(&musb->lock, flags); - - return ret; -} - -static int da8xx_musb_set_mode(struct musb *musb, u8 musb_mode) -{ - u32 cfgchip2 = __raw_readl(CFGCHIP2); - - cfgchip2 &= ~CFGCHIP2_OTGMODE; - switch (musb_mode) { - case MUSB_HOST: /* Force VBUS valid, ID = 0 */ - cfgchip2 |= CFGCHIP2_FORCE_HOST; - break; - case MUSB_PERIPHERAL: /* Force VBUS valid, ID = 1 */ - cfgchip2 |= CFGCHIP2_FORCE_DEVICE; - break; - case MUSB_OTG: /* Don't override the VBUS/ID comparators */ - cfgchip2 |= CFGCHIP2_NO_OVERRIDE; - break; - default: - dev_dbg(musb->controller, "Trying to set unsupported mode %u\n", musb_mode); - } - - __raw_writel(cfgchip2, CFGCHIP2); - return 0; -} - -static int da8xx_musb_init(struct musb *musb) -{ - void __iomem *reg_base = musb->ctrl_base; - u32 rev; - - musb->mregs += DA8XX_MENTOR_CORE_OFFSET; - - /* Returns zero if e.g. not clocked */ - rev = musb_readl(reg_base, DA8XX_USB_REVISION_REG); - if (!rev) - goto fail; - - usb_nop_xceiv_register(); - musb->xceiv = usb_get_transceiver(); - if (!musb->xceiv) - goto fail; - - if (is_host_enabled(musb)) - setup_timer(&otg_workaround, otg_timer, (unsigned long)musb); - - /* Reset the controller */ - musb_writel(reg_base, DA8XX_USB_CTRL_REG, DA8XX_SOFT_RESET_MASK); - - /* Start the on-chip PHY and its PLL. */ - phy_on(); - - msleep(5); - - /* NOTE: IRQs are in mixed mode, not bypass to pure MUSB */ - pr_debug("DA8xx OTG revision %08x, PHY %03x, control %02x\n", - rev, __raw_readl(CFGCHIP2), - musb_readb(reg_base, DA8XX_USB_CTRL_REG)); - - musb->isr = da8xx_musb_interrupt; - return 0; -fail: - return -ENODEV; -} - -static int da8xx_musb_exit(struct musb *musb) -{ - if (is_host_enabled(musb)) - del_timer_sync(&otg_workaround); - - phy_off(); - - usb_put_transceiver(musb->xceiv); - usb_nop_xceiv_unregister(); - - return 0; -} - -static const struct musb_platform_ops da8xx_ops = { - .init = da8xx_musb_init, - .exit = da8xx_musb_exit, - - .enable = da8xx_musb_enable, - .disable = da8xx_musb_disable, - - .set_mode = da8xx_musb_set_mode, - .try_idle = da8xx_musb_try_idle, - - .set_vbus = da8xx_musb_set_vbus, -}; - -static u64 da8xx_dmamask = DMA_BIT_MASK(32); - -static int __devinit da8xx_probe(struct platform_device *pdev) -{ - struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; - struct platform_device *musb; - struct da8xx_glue *glue; - - struct clk *clk; - - int ret = -ENOMEM; - - glue = kzalloc(sizeof(*glue), GFP_KERNEL); - if (!glue) { - dev_err(&pdev->dev, "failed to allocate glue context\n"); - goto err0; - } - - musb = platform_device_alloc("musb-hdrc", -1); - if (!musb) { - dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err1; - } - - clk = clk_get(&pdev->dev, "usb20"); - if (IS_ERR(clk)) { - dev_err(&pdev->dev, "failed to get clock\n"); - ret = PTR_ERR(clk); - goto err2; - } - - ret = clk_enable(clk); - if (ret) { - dev_err(&pdev->dev, "failed to enable clock\n"); - goto err3; - } - - musb->dev.parent = &pdev->dev; - musb->dev.dma_mask = &da8xx_dmamask; - musb->dev.coherent_dma_mask = da8xx_dmamask; - - glue->dev = &pdev->dev; - glue->musb = musb; - glue->clk = clk; - - pdata->platform_ops = &da8xx_ops; - - platform_set_drvdata(pdev, glue); - - ret = platform_device_add_resources(musb, pdev->resource, - pdev->num_resources); - if (ret) { - dev_err(&pdev->dev, "failed to add resources\n"); - goto err4; - } - - ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); - if (ret) { - dev_err(&pdev->dev, "failed to add platform_data\n"); - goto err4; - } - - ret = platform_device_add(musb); - if (ret) { - dev_err(&pdev->dev, "failed to register musb device\n"); - goto err4; - } - - return 0; - -err4: - clk_disable(clk); - -err3: - clk_put(clk); - -err2: - platform_device_put(musb); - -err1: - kfree(glue); - -err0: - return ret; -} - -static int __devexit da8xx_remove(struct platform_device *pdev) -{ - struct da8xx_glue *glue = platform_get_drvdata(pdev); - - platform_device_del(glue->musb); - platform_device_put(glue->musb); - clk_disable(glue->clk); - clk_put(glue->clk); - kfree(glue); - - return 0; -} - -static struct platform_driver da8xx_driver = { - .probe = da8xx_probe, - .remove = __devexit_p(da8xx_remove), - .driver = { - .name = "musb-da8xx", - }, -}; - -MODULE_DESCRIPTION("DA8xx/OMAP-L1x MUSB Glue Layer"); -MODULE_AUTHOR("Sergei Shtylyov "); -MODULE_LICENSE("GPL v2"); - -static int __init da8xx_init(void) -{ - return platform_driver_register(&da8xx_driver); -} -module_init(da8xx_init); - -static void __exit da8xx_exit(void) -{ - platform_driver_unregister(&da8xx_driver); -} -module_exit(da8xx_exit); diff --git a/ANDROID_3.4.5/drivers/usb/musb/davinci.c b/ANDROID_3.4.5/drivers/usb/musb/davinci.c deleted file mode 100644 index 9d63ba4d..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/davinci.c +++ /dev/null @@ -1,635 +0,0 @@ -/* - * Copyright (C) 2005-2006 by Texas Instruments - * - * This file is part of the Inventra Controller Driver for Linux. - * - * The Inventra Controller Driver for Linux 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. - * - * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not, - * write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include "musb_core.h" - -#ifdef CONFIG_MACH_DAVINCI_EVM -#define GPIO_nVBUS_DRV 160 -#endif - -#include "davinci.h" -#include "cppi_dma.h" - - -#define USB_PHY_CTRL IO_ADDRESS(USBPHY_CTL_PADDR) -#define DM355_DEEPSLEEP IO_ADDRESS(DM355_DEEPSLEEP_PADDR) - -struct davinci_glue { - struct device *dev; - struct platform_device *musb; - struct clk *clk; -}; - -/* REVISIT (PM) we should be able to keep the PHY in low power mode most - * of the time (24 MHZ oscillator and PLL off, etc) by setting POWER.D0 - * and, when in host mode, autosuspending idle root ports... PHYPLLON - * (overriding SUSPENDM?) then likely needs to stay off. - */ - -static inline void phy_on(void) -{ - u32 phy_ctrl = __raw_readl(USB_PHY_CTRL); - - /* power everything up; start the on-chip PHY and its PLL */ - phy_ctrl &= ~(USBPHY_OSCPDWN | USBPHY_OTGPDWN | USBPHY_PHYPDWN); - phy_ctrl |= USBPHY_SESNDEN | USBPHY_VBDTCTEN | USBPHY_PHYPLLON; - __raw_writel(phy_ctrl, USB_PHY_CTRL); - - /* wait for PLL to lock before proceeding */ - while ((__raw_readl(USB_PHY_CTRL) & USBPHY_PHYCLKGD) == 0) - cpu_relax(); -} - -static inline void phy_off(void) -{ - u32 phy_ctrl = __raw_readl(USB_PHY_CTRL); - - /* powerdown the on-chip PHY, its PLL, and the OTG block */ - phy_ctrl &= ~(USBPHY_SESNDEN | USBPHY_VBDTCTEN | USBPHY_PHYPLLON); - phy_ctrl |= USBPHY_OSCPDWN | USBPHY_OTGPDWN | USBPHY_PHYPDWN; - __raw_writel(phy_ctrl, USB_PHY_CTRL); -} - -static int dma_off = 1; - -static void davinci_musb_enable(struct musb *musb) -{ - u32 tmp, old, val; - - /* workaround: setup irqs through both register sets */ - tmp = (musb->epmask & DAVINCI_USB_TX_ENDPTS_MASK) - << DAVINCI_USB_TXINT_SHIFT; - musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_SET_REG, tmp); - old = tmp; - tmp = (musb->epmask & (0xfffe & DAVINCI_USB_RX_ENDPTS_MASK)) - << DAVINCI_USB_RXINT_SHIFT; - musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_SET_REG, tmp); - tmp |= old; - - val = ~MUSB_INTR_SOF; - tmp |= ((val & 0x01ff) << DAVINCI_USB_USBINT_SHIFT); - musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_SET_REG, tmp); - - if (is_dma_capable() && !dma_off) - printk(KERN_WARNING "%s %s: dma not reactivated\n", - __FILE__, __func__); - else - dma_off = 0; - - /* force a DRVVBUS irq so we can start polling for ID change */ - if (is_otg_enabled(musb)) - musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG, - DAVINCI_INTR_DRVVBUS << DAVINCI_USB_USBINT_SHIFT); -} - -/* - * Disable the HDRC and flush interrupts - */ -static void davinci_musb_disable(struct musb *musb) -{ - /* because we don't set CTRLR.UINT, "important" to: - * - not read/write INTRUSB/INTRUSBE - * - (except during initial setup, as workaround) - * - use INTSETR/INTCLRR instead - */ - musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_CLR_REG, - DAVINCI_USB_USBINT_MASK - | DAVINCI_USB_TXINT_MASK - | DAVINCI_USB_RXINT_MASK); - musb_writeb(musb->mregs, MUSB_DEVCTL, 0); - musb_writel(musb->ctrl_base, DAVINCI_USB_EOI_REG, 0); - - if (is_dma_capable() && !dma_off) - WARNING("dma still active\n"); -} - - -#define portstate(stmt) stmt - -/* - * VBUS SWITCHING IS BOARD-SPECIFIC ... at least for the DM6446 EVM, - * which doesn't wire DRVVBUS to the FET that switches it. Unclear - * if that's a problem with the DM6446 chip or just with that board. - * - * In either case, the DM355 EVM automates DRVVBUS the normal way, - * when J10 is out, and TI documents it as handling OTG. - */ - -#ifdef CONFIG_MACH_DAVINCI_EVM - -static int vbus_state = -1; - -/* I2C operations are always synchronous, and require a task context. - * With unloaded systems, using the shared workqueue seems to suffice - * to satisfy the 100msec A_WAIT_VRISE timeout... - */ -static void evm_deferred_drvvbus(struct work_struct *ignored) -{ - gpio_set_value_cansleep(GPIO_nVBUS_DRV, vbus_state); - vbus_state = !vbus_state; -} - -#endif /* EVM */ - -static void davinci_musb_source_power(struct musb *musb, int is_on, int immediate) -{ -#ifdef CONFIG_MACH_DAVINCI_EVM - if (is_on) - is_on = 1; - - if (vbus_state == is_on) - return; - vbus_state = !is_on; /* 0/1 vs "-1 == unknown/init" */ - - if (machine_is_davinci_evm()) { - static DECLARE_WORK(evm_vbus_work, evm_deferred_drvvbus); - - if (immediate) - gpio_set_value_cansleep(GPIO_nVBUS_DRV, vbus_state); - else - schedule_work(&evm_vbus_work); - } - if (immediate) - vbus_state = is_on; -#endif -} - -static void davinci_musb_set_vbus(struct musb *musb, int is_on) -{ - WARN_ON(is_on && is_peripheral_active(musb)); - davinci_musb_source_power(musb, is_on, 0); -} - - -#define POLL_SECONDS 2 - -static struct timer_list otg_workaround; - -static void otg_timer(unsigned long _musb) -{ - struct musb *musb = (void *)_musb; - void __iomem *mregs = musb->mregs; - u8 devctl; - unsigned long flags; - - /* We poll because DaVinci's won't expose several OTG-critical - * status change events (from the transceiver) otherwise. - */ - devctl = musb_readb(mregs, MUSB_DEVCTL); - dev_dbg(musb->controller, "poll devctl %02x (%s)\n", devctl, - otg_state_string(musb->xceiv->state)); - - spin_lock_irqsave(&musb->lock, flags); - 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 - * case "recover"), in routine "VBUS was valid by the time - * VBUSERR got reported during enumeration" cases. - */ - if (devctl & MUSB_DEVCTL_VBUS) { - mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); - break; - } - 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; - case OTG_STATE_B_IDLE: - if (!is_peripheral_enabled(musb)) - break; - - /* There's no ID-changed IRQ, so we have no good way to tell - * when to switch to the A-Default state machine (by setting - * the DEVCTL.SESSION flag). - * - * Workaround: whenever we're in B_IDLE, try setting the - * session flag every few seconds. If it works, ID was - * grounded and we're now in the A-Default state machine. - * - * NOTE setting the session flag is _supposed_ to trigger - * SRP, but clearly it doesn't. - */ - musb_writeb(mregs, MUSB_DEVCTL, - devctl | MUSB_DEVCTL_SESSION); - devctl = musb_readb(mregs, MUSB_DEVCTL); - if (devctl & MUSB_DEVCTL_BDEVICE) - mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); - else - musb->xceiv->state = OTG_STATE_A_IDLE; - break; - default: - break; - } - spin_unlock_irqrestore(&musb->lock, flags); -} - -static irqreturn_t davinci_musb_interrupt(int irq, void *__hci) -{ - unsigned long flags; - irqreturn_t retval = IRQ_NONE; - struct musb *musb = __hci; - struct usb_otg *otg = musb->xceiv->otg; - void __iomem *tibase = musb->ctrl_base; - struct cppi *cppi; - u32 tmp; - - spin_lock_irqsave(&musb->lock, flags); - - /* NOTE: DaVinci shadows the Mentor IRQs. Don't manage them through - * the Mentor registers (except for setup), use the TI ones and EOI. - * - * Docs describe irq "vector" registers associated with the CPPI and - * USB EOI registers. These hold a bitmask corresponding to the - * current IRQ, not an irq handler address. Would using those bits - * resolve some of the races observed in this dispatch code?? - */ - - /* CPPI interrupts share the same IRQ line, but have their own - * mask, state, "vector", and EOI registers. - */ - 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); - musb_writel(tibase, DAVINCI_USB_INT_SRC_CLR_REG, tmp); - dev_dbg(musb->controller, "IRQ %08x\n", tmp); - - musb->int_rx = (tmp & DAVINCI_USB_RXINT_MASK) - >> DAVINCI_USB_RXINT_SHIFT; - musb->int_tx = (tmp & DAVINCI_USB_TXINT_MASK) - >> DAVINCI_USB_TXINT_SHIFT; - musb->int_usb = (tmp & DAVINCI_USB_USBINT_MASK) - >> DAVINCI_USB_USBINT_SHIFT; - - /* DRVVBUS irqs are the only proxy we have (a very poor one!) for - * DaVinci's missing ID change IRQ. We need an ID change IRQ to - * switch appropriately between halves of the OTG state machine. - * Managing DEVCTL.SESSION per Mentor docs requires we know its - * value, but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set. - * Also, DRVVBUS pulses for SRP (but not at 5V) ... - */ - if (tmp & (DAVINCI_INTR_DRVVBUS << DAVINCI_USB_USBINT_SHIFT)) { - int drvvbus = musb_readl(tibase, DAVINCI_USB_STAT_REG); - void __iomem *mregs = musb->mregs; - u8 devctl = musb_readb(mregs, MUSB_DEVCTL); - int err = musb->int_usb & MUSB_INTR_VBUSERROR; - - err = is_host_enabled(musb) - && (musb->int_usb & MUSB_INTR_VBUSERROR); - if (err) { - /* The Mentor core doesn't debounce VBUS as needed - * to cope with device connect current spikes. This - * means it's not uncommon for bus-powered devices - * to get VBUS errors during enumeration. - * - * This is a workaround, but newer RTL from Mentor - * seems to allow a better one: "re"starting sessions - * without waiting (on EVM, a **long** time) for VBUS - * to stop registering in devctl. - */ - musb->int_usb &= ~MUSB_INTR_VBUSERROR; - 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_HST_MODE(musb); - otg->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); - otg->default_a = 0; - musb->xceiv->state = OTG_STATE_B_IDLE; - portstate(musb->port1_status &= ~USB_PORT_STAT_POWER); - } - - /* NOTE: this must complete poweron within 100 msec - * (OTG_TIME_A_WAIT_VRISE) but we don't check for that. - */ - davinci_musb_source_power(musb, drvvbus, 0); - dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n", - drvvbus ? "on" : "off", - otg_state_string(musb->xceiv->state), - err ? " ERROR" : "", - devctl); - retval = IRQ_HANDLED; - } - - if (musb->int_tx || musb->int_rx || musb->int_usb) - retval |= musb_interrupt(musb); - - /* irq stays asserted until EOI is written */ - musb_writel(tibase, DAVINCI_USB_EOI_REG, 0); - - /* poll for ID change */ - if (is_otg_enabled(musb) - && musb->xceiv->state == OTG_STATE_B_IDLE) - mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); - - spin_unlock_irqrestore(&musb->lock, flags); - - return retval; -} - -static int davinci_musb_set_mode(struct musb *musb, u8 mode) -{ - /* EVM can't do this (right?) */ - return -EIO; -} - -static int davinci_musb_init(struct musb *musb) -{ - void __iomem *tibase = musb->ctrl_base; - u32 revision; - - usb_nop_xceiv_register(); - musb->xceiv = usb_get_transceiver(); - if (!musb->xceiv) - goto unregister; - - musb->mregs += DAVINCI_BASE_OFFSET; - - /* returns zero if e.g. not clocked */ - revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG); - if (revision == 0) - goto fail; - - if (is_host_enabled(musb)) - setup_timer(&otg_workaround, otg_timer, (unsigned long) musb); - - davinci_musb_source_power(musb, 0, 1); - - /* dm355 EVM swaps D+/D- for signal integrity, and - * is clocked from the main 24 MHz crystal. - */ - if (machine_is_davinci_dm355_evm()) { - u32 phy_ctrl = __raw_readl(USB_PHY_CTRL); - - phy_ctrl &= ~(3 << 9); - phy_ctrl |= USBPHY_DATAPOL; - __raw_writel(phy_ctrl, USB_PHY_CTRL); - } - - /* On dm355, the default-A state machine needs DRVVBUS control. - * If we won't be a host, there's no need to turn it on. - */ - if (cpu_is_davinci_dm355()) { - u32 deepsleep = __raw_readl(DM355_DEEPSLEEP); - - if (is_host_enabled(musb)) { - deepsleep &= ~DRVVBUS_OVERRIDE; - } else { - deepsleep &= ~DRVVBUS_FORCE; - deepsleep |= DRVVBUS_OVERRIDE; - } - __raw_writel(deepsleep, DM355_DEEPSLEEP); - } - - /* reset the controller */ - musb_writel(tibase, DAVINCI_USB_CTRL_REG, 0x1); - - /* start the on-chip PHY and its PLL */ - phy_on(); - - msleep(5); - - /* NOTE: irqs are in mixed mode, not bypass to pure-musb */ - pr_debug("DaVinci OTG revision %08x phy %03x control %02x\n", - revision, __raw_readl(USB_PHY_CTRL), - musb_readb(tibase, DAVINCI_USB_CTRL_REG)); - - musb->isr = davinci_musb_interrupt; - return 0; - -fail: - usb_put_transceiver(musb->xceiv); -unregister: - usb_nop_xceiv_unregister(); - return -ENODEV; -} - -static int davinci_musb_exit(struct musb *musb) -{ - if (is_host_enabled(musb)) - del_timer_sync(&otg_workaround); - - /* force VBUS off */ - if (cpu_is_davinci_dm355()) { - u32 deepsleep = __raw_readl(DM355_DEEPSLEEP); - - deepsleep &= ~DRVVBUS_FORCE; - deepsleep |= DRVVBUS_OVERRIDE; - __raw_writel(deepsleep, DM355_DEEPSLEEP); - } - - davinci_musb_source_power(musb, 0 /*off*/, 1); - - /* delay, to avoid problems with module reload */ - if (is_host_enabled(musb) && musb->xceiv->otg->default_a) { - int maxdelay = 30; - u8 devctl, warn = 0; - - /* if there's no peripheral connected, this can take a - * long time to fall, especially on EVM with huge C133. - */ - do { - devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - if (!(devctl & MUSB_DEVCTL_VBUS)) - break; - if ((devctl & MUSB_DEVCTL_VBUS) != warn) { - warn = devctl & MUSB_DEVCTL_VBUS; - dev_dbg(musb->controller, "VBUS %d\n", - warn >> MUSB_DEVCTL_VBUS_SHIFT); - } - msleep(1000); - maxdelay--; - } while (maxdelay > 0); - - /* in OTG mode, another host might be connected */ - if (devctl & MUSB_DEVCTL_VBUS) - dev_dbg(musb->controller, "VBUS off timeout (devctl %02x)\n", devctl); - } - - phy_off(); - - usb_put_transceiver(musb->xceiv); - usb_nop_xceiv_unregister(); - - return 0; -} - -static const struct musb_platform_ops davinci_ops = { - .init = davinci_musb_init, - .exit = davinci_musb_exit, - - .enable = davinci_musb_enable, - .disable = davinci_musb_disable, - - .set_mode = davinci_musb_set_mode, - - .set_vbus = davinci_musb_set_vbus, -}; - -static u64 davinci_dmamask = DMA_BIT_MASK(32); - -static int __devinit davinci_probe(struct platform_device *pdev) -{ - struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; - struct platform_device *musb; - struct davinci_glue *glue; - struct clk *clk; - - int ret = -ENOMEM; - - glue = kzalloc(sizeof(*glue), GFP_KERNEL); - if (!glue) { - dev_err(&pdev->dev, "failed to allocate glue context\n"); - goto err0; - } - - musb = platform_device_alloc("musb-hdrc", -1); - if (!musb) { - dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err1; - } - - clk = clk_get(&pdev->dev, "usb"); - if (IS_ERR(clk)) { - dev_err(&pdev->dev, "failed to get clock\n"); - ret = PTR_ERR(clk); - goto err2; - } - - ret = clk_enable(clk); - if (ret) { - dev_err(&pdev->dev, "failed to enable clock\n"); - goto err3; - } - - musb->dev.parent = &pdev->dev; - musb->dev.dma_mask = &davinci_dmamask; - musb->dev.coherent_dma_mask = davinci_dmamask; - - glue->dev = &pdev->dev; - glue->musb = musb; - glue->clk = clk; - - pdata->platform_ops = &davinci_ops; - - platform_set_drvdata(pdev, glue); - - ret = platform_device_add_resources(musb, pdev->resource, - pdev->num_resources); - if (ret) { - dev_err(&pdev->dev, "failed to add resources\n"); - goto err4; - } - - ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); - if (ret) { - dev_err(&pdev->dev, "failed to add platform_data\n"); - goto err4; - } - - ret = platform_device_add(musb); - if (ret) { - dev_err(&pdev->dev, "failed to register musb device\n"); - goto err4; - } - - return 0; - -err4: - clk_disable(clk); - -err3: - clk_put(clk); - -err2: - platform_device_put(musb); - -err1: - kfree(glue); - -err0: - return ret; -} - -static int __devexit davinci_remove(struct platform_device *pdev) -{ - struct davinci_glue *glue = platform_get_drvdata(pdev); - - platform_device_del(glue->musb); - platform_device_put(glue->musb); - clk_disable(glue->clk); - clk_put(glue->clk); - kfree(glue); - - return 0; -} - -static struct platform_driver davinci_driver = { - .probe = davinci_probe, - .remove = __devexit_p(davinci_remove), - .driver = { - .name = "musb-davinci", - }, -}; - -MODULE_DESCRIPTION("DaVinci MUSB Glue Layer"); -MODULE_AUTHOR("Felipe Balbi "); -MODULE_LICENSE("GPL v2"); - -static int __init davinci_init(void) -{ - return platform_driver_register(&davinci_driver); -} -module_init(davinci_init); - -static void __exit davinci_exit(void) -{ - platform_driver_unregister(&davinci_driver); -} -module_exit(davinci_exit); diff --git a/ANDROID_3.4.5/drivers/usb/musb/davinci.h b/ANDROID_3.4.5/drivers/usb/musb/davinci.h deleted file mode 100644 index 371baa0e..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/davinci.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2005-2006 by Texas Instruments - * - * The Inventra Controller Driver for Linux 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 __MUSB_HDRDF_H__ -#define __MUSB_HDRDF_H__ - -/* - * DaVinci-specific definitions - */ - -/* Integrated highspeed/otg PHY */ -#define USBPHY_CTL_PADDR 0x01c40034 -#define USBPHY_DATAPOL BIT(11) /* (dm355) switch D+/D- */ -#define USBPHY_PHYCLKGD BIT(8) -#define USBPHY_SESNDEN BIT(7) /* v(sess_end) comparator */ -#define USBPHY_VBDTCTEN BIT(6) /* v(bus) comparator */ -#define USBPHY_VBUSSENS BIT(5) /* (dm355,ro) is vbus > 0.5V */ -#define USBPHY_PHYPLLON BIT(4) /* override pll suspend */ -#define USBPHY_CLKO1SEL BIT(3) -#define USBPHY_OSCPDWN BIT(2) -#define USBPHY_OTGPDWN BIT(1) -#define USBPHY_PHYPDWN BIT(0) - -#define DM355_DEEPSLEEP_PADDR 0x01c40048 -#define DRVVBUS_FORCE BIT(2) -#define DRVVBUS_OVERRIDE BIT(1) - -/* For now include usb OTG module registers here */ -#define DAVINCI_USB_VERSION_REG 0x00 -#define DAVINCI_USB_CTRL_REG 0x04 -#define DAVINCI_USB_STAT_REG 0x08 -#define DAVINCI_RNDIS_REG 0x10 -#define DAVINCI_AUTOREQ_REG 0x14 -#define DAVINCI_USB_INT_SOURCE_REG 0x20 -#define DAVINCI_USB_INT_SET_REG 0x24 -#define DAVINCI_USB_INT_SRC_CLR_REG 0x28 -#define DAVINCI_USB_INT_MASK_REG 0x2c -#define DAVINCI_USB_INT_MASK_SET_REG 0x30 -#define DAVINCI_USB_INT_MASK_CLR_REG 0x34 -#define DAVINCI_USB_INT_SRC_MASKED_REG 0x38 -#define DAVINCI_USB_EOI_REG 0x3c -#define DAVINCI_USB_EOI_INTVEC 0x40 - -/* BEGIN CPPI-generic (?) */ - -/* CPPI related registers */ -#define DAVINCI_TXCPPI_CTRL_REG 0x80 -#define DAVINCI_TXCPPI_TEAR_REG 0x84 -#define DAVINCI_CPPI_EOI_REG 0x88 -#define DAVINCI_CPPI_INTVEC_REG 0x8c -#define DAVINCI_TXCPPI_MASKED_REG 0x90 -#define DAVINCI_TXCPPI_RAW_REG 0x94 -#define DAVINCI_TXCPPI_INTENAB_REG 0x98 -#define DAVINCI_TXCPPI_INTCLR_REG 0x9c - -#define DAVINCI_RXCPPI_CTRL_REG 0xC0 -#define DAVINCI_RXCPPI_MASKED_REG 0xD0 -#define DAVINCI_RXCPPI_RAW_REG 0xD4 -#define DAVINCI_RXCPPI_INTENAB_REG 0xD8 -#define DAVINCI_RXCPPI_INTCLR_REG 0xDC - -#define DAVINCI_RXCPPI_BUFCNT0_REG 0xE0 -#define DAVINCI_RXCPPI_BUFCNT1_REG 0xE4 -#define DAVINCI_RXCPPI_BUFCNT2_REG 0xE8 -#define DAVINCI_RXCPPI_BUFCNT3_REG 0xEC - -/* CPPI state RAM entries */ -#define DAVINCI_CPPI_STATERAM_BASE_OFFSET 0x100 - -#define DAVINCI_TXCPPI_STATERAM_OFFSET(chnum) \ - (DAVINCI_CPPI_STATERAM_BASE_OFFSET + ((chnum) * 0x40)) -#define DAVINCI_RXCPPI_STATERAM_OFFSET(chnum) \ - (DAVINCI_CPPI_STATERAM_BASE_OFFSET + 0x20 + ((chnum) * 0x40)) - -/* CPPI masks */ -#define DAVINCI_DMA_CTRL_ENABLE 1 -#define DAVINCI_DMA_CTRL_DISABLE 0 - -#define DAVINCI_DMA_ALL_CHANNELS_ENABLE 0xF -#define DAVINCI_DMA_ALL_CHANNELS_DISABLE 0xF - -/* END CPPI-generic (?) */ - -#define DAVINCI_USB_TX_ENDPTS_MASK 0x1f /* ep0 + 4 tx */ -#define DAVINCI_USB_RX_ENDPTS_MASK 0x1e /* 4 rx */ - -#define DAVINCI_USB_USBINT_SHIFT 16 -#define DAVINCI_USB_TXINT_SHIFT 0 -#define DAVINCI_USB_RXINT_SHIFT 8 - -#define DAVINCI_INTR_DRVVBUS 0x0100 - -#define DAVINCI_USB_USBINT_MASK 0x01ff0000 /* 8 Mentor, DRVVBUS */ -#define DAVINCI_USB_TXINT_MASK \ - (DAVINCI_USB_TX_ENDPTS_MASK << DAVINCI_USB_TXINT_SHIFT) -#define DAVINCI_USB_RXINT_MASK \ - (DAVINCI_USB_RX_ENDPTS_MASK << DAVINCI_USB_RXINT_SHIFT) - -#define DAVINCI_BASE_OFFSET 0x400 - -#endif /* __MUSB_HDRDF_H__ */ diff --git a/ANDROID_3.4.5/drivers/usb/musb/musb_core.c b/ANDROID_3.4.5/drivers/usb/musb/musb_core.c deleted file mode 100644 index 66aaccf0..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/musb_core.c +++ /dev/null @@ -1,2416 +0,0 @@ -/* - * MUSB OTG driver core code - * - * Copyright 2005 Mentor Graphics Corporation - * Copyright (C) 2005-2006 by Texas Instruments - * Copyright (C) 2006-2007 Nokia Corporation - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -/* - * Inventra (Multipoint) Dual-Role Controller Driver for Linux. - * - * This consists of a Host Controller Driver (HCD) and a peripheral - * controller driver implementing the "Gadget" API; OTG support is - * in the works. These are normal Linux-USB controller drivers which - * use IRQs and have no dedicated thread. - * - * This version of the driver has only been used with products from - * Texas Instruments. Those products integrate the Inventra logic - * with other DMA, IRQ, and bus modules, as well as other logic that - * needs to be reflected in this driver. - * - * - * NOTE: the original Mentor code here was pretty much a collection - * of mechanisms that don't seem to have been fully integrated/working - * for *any* Linux kernel version. This version aims at Linux 2.6.now, - * Key open issues include: - * - * - Lack of host-side transaction scheduling, for all transfer types. - * The hardware doesn't do it; instead, software must. - * - * This is not an issue for OTG devices that don't support external - * hubs, but for more "normal" USB hosts it's a user issue that the - * "multipoint" support doesn't scale in the expected ways. That - * includes DaVinci EVM in a common non-OTG mode. - * - * * Control and bulk use dedicated endpoints, and there's as - * yet no mechanism to either (a) reclaim the hardware when - * peripherals are NAKing, which gets complicated with bulk - * endpoints, or (b) use more than a single bulk endpoint in - * each direction. - * - * RESULT: one device may be perceived as blocking another one. - * - * * Interrupt and isochronous will dynamically allocate endpoint - * hardware, but (a) there's no record keeping for bandwidth; - * (b) in the common case that few endpoints are available, there - * is no mechanism to reuse endpoints to talk to multiple devices. - * - * RESULT: At one extreme, bandwidth can be overcommitted in - * some hardware configurations, no faults will be reported. - * At the other extreme, the bandwidth capabilities which do - * exist tend to be severely undercommitted. You can't yet hook - * up both a keyboard and a mouse to an external USB hub. - */ - -/* - * This gets many kinds of configuration information: - * - Kconfig for everything user-configurable - * - platform_device for addressing, irq, and platform_data - * - platform_data is mostly for board-specific informarion - * (plus recentrly, SOC or family details) - * - * Most of the conditional compilation will (someday) vanish. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "musb_core.h" - -#define TA_WAIT_BCON(m) max_t(int, (m)->a_wait_bcon, OTG_TIME_A_WAIT_BCON) - - -#define DRIVER_AUTHOR "Mentor Graphics, Texas Instruments, Nokia" -#define DRIVER_DESC "Inventra Dual-Role USB Controller Driver" - -#define MUSB_VERSION "6.0" - -#define DRIVER_INFO DRIVER_DESC ", v" MUSB_VERSION - -#define MUSB_DRIVER_NAME "musb-hdrc" -const char musb_driver_name[] = MUSB_DRIVER_NAME; - -MODULE_DESCRIPTION(DRIVER_INFO); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" MUSB_DRIVER_NAME); - - -/*-------------------------------------------------------------------------*/ - -static inline struct musb *dev_to_musb(struct device *dev) -{ - return dev_get_drvdata(dev); -} - -/*-------------------------------------------------------------------------*/ - -#ifndef CONFIG_BLACKFIN -static int musb_ulpi_read(struct usb_phy *phy, u32 offset) -{ - void __iomem *addr = phy->io_priv; - int i = 0; - u8 r; - u8 power; - int ret; - - pm_runtime_get_sync(phy->io_dev); - - /* Make sure the transceiver is not in low power mode */ - power = musb_readb(addr, MUSB_POWER); - power &= ~MUSB_POWER_SUSPENDM; - musb_writeb(addr, MUSB_POWER, power); - - /* REVISIT: musbhdrc_ulpi_an.pdf recommends setting the - * ULPICarKitControlDisableUTMI after clearing POWER_SUSPENDM. - */ - - musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)offset); - musb_writeb(addr, MUSB_ULPI_REG_CONTROL, - MUSB_ULPI_REG_REQ | MUSB_ULPI_RDN_WR); - - while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL) - & MUSB_ULPI_REG_CMPLT)) { - i++; - if (i == 10000) { - ret = -ETIMEDOUT; - goto out; - } - - } - r = musb_readb(addr, MUSB_ULPI_REG_CONTROL); - r &= ~MUSB_ULPI_REG_CMPLT; - musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r); - - ret = musb_readb(addr, MUSB_ULPI_REG_DATA); - -out: - pm_runtime_put(phy->io_dev); - - return ret; -} - -static int musb_ulpi_write(struct usb_phy *phy, u32 offset, u32 data) -{ - void __iomem *addr = phy->io_priv; - int i = 0; - u8 r = 0; - u8 power; - int ret = 0; - - pm_runtime_get_sync(phy->io_dev); - - /* Make sure the transceiver is not in low power mode */ - power = musb_readb(addr, MUSB_POWER); - power &= ~MUSB_POWER_SUSPENDM; - musb_writeb(addr, MUSB_POWER, power); - - musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)offset); - musb_writeb(addr, MUSB_ULPI_REG_DATA, (u8)data); - musb_writeb(addr, MUSB_ULPI_REG_CONTROL, MUSB_ULPI_REG_REQ); - - while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL) - & MUSB_ULPI_REG_CMPLT)) { - i++; - if (i == 10000) { - ret = -ETIMEDOUT; - goto out; - } - } - - r = musb_readb(addr, MUSB_ULPI_REG_CONTROL); - r &= ~MUSB_ULPI_REG_CMPLT; - musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r); - -out: - pm_runtime_put(phy->io_dev); - - return ret; -} -#else -#define musb_ulpi_read NULL -#define musb_ulpi_write NULL -#endif - -static struct usb_phy_io_ops musb_ulpi_access = { - .read = musb_ulpi_read, - .write = musb_ulpi_write, -}; - -/*-------------------------------------------------------------------------*/ - -#if !defined(CONFIG_USB_MUSB_TUSB6010) && !defined(CONFIG_USB_MUSB_BLACKFIN) - -/* - * Load an endpoint's FIFO - */ -void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src) -{ - struct musb *musb = hw_ep->musb; - void __iomem *fifo = hw_ep->fifo; - - prefetch((u8 *)src); - - dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n", - 'T', hw_ep->epnum, fifo, len, src); - - /* we can't assume unaligned reads work */ - if (likely((0x01 & (unsigned long) src) == 0)) { - u16 index = 0; - - /* best case is 32bit-aligned source address */ - if ((0x02 & (unsigned long) src) == 0) { - if (len >= 4) { - writesl(fifo, src + index, len >> 2); - index += len & ~0x03; - } - if (len & 0x02) { - musb_writew(fifo, 0, *(u16 *)&src[index]); - index += 2; - } - } else { - if (len >= 2) { - writesw(fifo, src + index, len >> 1); - index += len & ~0x01; - } - } - if (len & 0x01) - musb_writeb(fifo, 0, src[index]); - } else { - /* byte aligned */ - writesb(fifo, src, len); - } -} - -#if !defined(CONFIG_USB_MUSB_AM35X) -/* - * Unload an endpoint's FIFO - */ -void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) -{ - struct musb *musb = hw_ep->musb; - void __iomem *fifo = hw_ep->fifo; - - dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n", - 'R', hw_ep->epnum, fifo, len, dst); - - /* we can't assume unaligned writes work */ - if (likely((0x01 & (unsigned long) dst) == 0)) { - u16 index = 0; - - /* best case is 32bit-aligned destination address */ - if ((0x02 & (unsigned long) dst) == 0) { - if (len >= 4) { - readsl(fifo, dst, len >> 2); - index = len & ~0x03; - } - if (len & 0x02) { - *(u16 *)&dst[index] = musb_readw(fifo, 0); - index += 2; - } - } else { - if (len >= 2) { - readsw(fifo, dst, len >> 1); - index = len & ~0x01; - } - } - if (len & 0x01) - dst[index] = musb_readb(fifo, 0); - } else { - /* byte aligned */ - readsb(fifo, dst, len); - } -} -#endif - -#endif /* normal PIO */ - - -/*-------------------------------------------------------------------------*/ - -/* for high speed test mode; see USB 2.0 spec 7.1.20 */ -static const u8 musb_test_packet[53] = { - /* implicit SYNC then DATA0 to start */ - - /* JKJKJKJK x9 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* JJKKJJKK x8 */ - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - /* JJJJKKKK x8 */ - 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, - /* JJJJJJJKKKKKKK x8 */ - 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* JJJJJJJK x8 */ - 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, - /* JKKKKKKK x10, JK */ - 0xfc, 0x7e, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0x7e - - /* implicit CRC16 then EOP to end */ -}; - -void musb_load_testpacket(struct musb *musb) -{ - void __iomem *regs = musb->endpoints[0].regs; - - musb_ep_select(musb->mregs, 0); - musb_write_fifo(musb->control_ep, - sizeof(musb_test_packet), musb_test_packet); - musb_writew(regs, MUSB_CSR0, MUSB_CSR0_TXPKTRDY); -} - -/*-------------------------------------------------------------------------*/ - -/* - * Handles OTG hnp timeouts, such as b_ase0_brst - */ -void musb_otg_timer_func(unsigned long data) -{ - struct musb *musb = (struct musb *)data; - unsigned long flags; - - spin_lock_irqsave(&musb->lock, flags); - switch (musb->xceiv->state) { - case OTG_STATE_B_WAIT_ACON: - dev_dbg(musb->controller, "HNP: b_wait_acon timeout; back to b_peripheral\n"); - musb_g_disconnect(musb); - musb->xceiv->state = OTG_STATE_B_PERIPHERAL; - musb->is_active = 0; - break; - case OTG_STATE_A_SUSPEND: - case OTG_STATE_A_WAIT_BCON: - dev_dbg(musb->controller, "HNP: %s timeout\n", - otg_state_string(musb->xceiv->state)); - musb_platform_set_vbus(musb, 0); - musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; - break; - default: - dev_dbg(musb->controller, "HNP: Unhandled mode %s\n", - otg_state_string(musb->xceiv->state)); - } - musb->ignore_disconnect = 0; - spin_unlock_irqrestore(&musb->lock, flags); -} - -/* - * Stops the HNP transition. Caller must take care of locking. - */ -void musb_hnp_stop(struct musb *musb) -{ - struct usb_hcd *hcd = musb_to_hcd(musb); - void __iomem *mbase = musb->mregs; - u8 reg; - - dev_dbg(musb->controller, "HNP: stop from %s\n", otg_state_string(musb->xceiv->state)); - - switch (musb->xceiv->state) { - case OTG_STATE_A_PERIPHERAL: - musb_g_disconnect(musb); - dev_dbg(musb->controller, "HNP: back to %s\n", - otg_state_string(musb->xceiv->state)); - break; - case OTG_STATE_B_HOST: - dev_dbg(musb->controller, "HNP: Disabling HR\n"); - hcd->self.is_b_host = 0; - musb->xceiv->state = OTG_STATE_B_PERIPHERAL; - MUSB_DEV_MODE(musb); - reg = musb_readb(mbase, MUSB_POWER); - reg |= MUSB_POWER_SUSPENDM; - musb_writeb(mbase, MUSB_POWER, reg); - /* REVISIT: Start SESSION_REQUEST here? */ - break; - default: - dev_dbg(musb->controller, "HNP: Stopping in unknown state %s\n", - otg_state_string(musb->xceiv->state)); - } - - /* - * When returning to A state after HNP, avoid hub_port_rebounce(), - * which cause occasional OPT A "Did not receive reset after connect" - * errors. - */ - musb->port1_status &= ~(USB_PORT_STAT_C_CONNECTION << 16); -} - -/* - * Interrupt Service Routine to record USB "global" interrupts. - * Since these do not happen often and signify things of - * paramount importance, it seems OK to check them individually; - * the order of the tests is specified in the manual - * - * @param musb instance pointer - * @param int_usb register contents - * @param devctl - * @param power - */ - -static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, - u8 devctl, u8 power) -{ - struct usb_otg *otg = musb->xceiv->otg; - irqreturn_t handled = IRQ_NONE; - - dev_dbg(musb->controller, "<== Power=%02x, DevCtl=%02x, int_usb=0x%x\n", power, devctl, - int_usb); - - /* in host mode, the peripheral may issue remote wakeup. - * in peripheral mode, the host may resume the link. - * spurious RESUME irqs happen too, paired with SUSPEND. - */ - if (int_usb & MUSB_INTR_RESUME) { - handled = IRQ_HANDLED; - dev_dbg(musb->controller, "RESUME (%s)\n", otg_state_string(musb->xceiv->state)); - - if (devctl & MUSB_DEVCTL_HM) { - void __iomem *mbase = musb->mregs; - - switch (musb->xceiv->state) { - case OTG_STATE_A_SUSPEND: - /* remote wakeup? later, GetPortStatus - * will stop RESUME signaling - */ - - if (power & MUSB_POWER_SUSPENDM) { - /* spurious */ - musb->int_usb &= ~MUSB_INTR_SUSPEND; - dev_dbg(musb->controller, "Spurious SUSPENDM\n"); - break; - } - - power &= ~MUSB_POWER_SUSPENDM; - musb_writeb(mbase, MUSB_POWER, - power | MUSB_POWER_RESUME); - - musb->port1_status |= - (USB_PORT_STAT_C_SUSPEND << 16) - | MUSB_PORT_STAT_RESUME; - musb->rh_timer = jiffies - + msecs_to_jiffies(20); - - 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->is_active = 1; - MUSB_DEV_MODE(musb); - break; - default: - WARNING("bogus %s RESUME (%s)\n", - "host", - otg_state_string(musb->xceiv->state)); - } - } else { - switch (musb->xceiv->state) { - case OTG_STATE_A_SUSPEND: - /* possibly DISCONNECT is upcoming */ - musb->xceiv->state = OTG_STATE_A_HOST; - usb_hcd_resume_root_hub(musb_to_hcd(musb)); - break; - case OTG_STATE_B_WAIT_ACON: - case OTG_STATE_B_PERIPHERAL: - /* disconnect while suspended? we may - * not get a disconnect irq... - */ - if ((devctl & MUSB_DEVCTL_VBUS) - != (3 << MUSB_DEVCTL_VBUS_SHIFT) - ) { - musb->int_usb |= MUSB_INTR_DISCONNECT; - musb->int_usb &= ~MUSB_INTR_SUSPEND; - break; - } - musb_g_resume(musb); - break; - case OTG_STATE_B_IDLE: - musb->int_usb &= ~MUSB_INTR_SUSPEND; - break; - default: - WARNING("bogus %s RESUME (%s)\n", - "peripheral", - otg_state_string(musb->xceiv->state)); - } - } - } - - /* see manual for the order of the tests */ - if (int_usb & MUSB_INTR_SESSREQ) { - void __iomem *mbase = musb->mregs; - - if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS - && (devctl & MUSB_DEVCTL_BDEVICE)) { - dev_dbg(musb->controller, "SessReq while on B state\n"); - return IRQ_HANDLED; - } - - dev_dbg(musb->controller, "SESSION_REQUEST (%s)\n", - otg_state_string(musb->xceiv->state)); - - /* IRQ arrives from ID pin sense or (later, if VBUS power - * is removed) SRP. responses are time critical: - * - turn on VBUS (with silicon-specific mechanism) - * - go through A_WAIT_VRISE - * - ... to A_WAIT_BCON. - * a_wait_vrise_tmout triggers VBUS_ERROR transitions - */ - musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION); - musb->ep0_stage = MUSB_EP0_START; - musb->xceiv->state = OTG_STATE_A_IDLE; - MUSB_HST_MODE(musb); - musb_platform_set_vbus(musb, 1); - - handled = IRQ_HANDLED; - } - - if (int_usb & MUSB_INTR_VBUSERROR) { - int ignore = 0; - - /* During connection as an A-Device, we may see a short - * current spikes causing voltage drop, because of cable - * and peripheral capacitance combined with vbus draw. - * (So: less common with truly self-powered devices, where - * vbus doesn't act like a power supply.) - * - * Such spikes are short; usually less than ~500 usec, max - * of ~2 msec. That is, they're not sustained overcurrent - * errors, though they're reported using VBUSERROR irqs. - * - * Workarounds: (a) hardware: use self powered devices. - * (b) software: ignore non-repeated VBUS errors. - * - * REVISIT: do delays from lots of DEBUG_KERNEL checks - * make trouble here, keeping VBUS < 4.4V ? - */ - 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 - * stayed ok at the other end of the link, and - * another reset is due (at least for high speed, - * to redo the chirp etc), it might work OK... - */ - case OTG_STATE_A_WAIT_BCON: - case OTG_STATE_A_WAIT_VRISE: - if (musb->vbuserr_retry) { - void __iomem *mbase = musb->mregs; - - musb->vbuserr_retry--; - ignore = 1; - devctl |= MUSB_DEVCTL_SESSION; - musb_writeb(mbase, MUSB_DEVCTL, devctl); - } else { - musb->port1_status |= - USB_PORT_STAT_OVERCURRENT - | (USB_PORT_STAT_C_OVERCURRENT << 16); - } - break; - default: - break; - } - - dev_dbg(musb->controller, "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n", - otg_state_string(musb->xceiv->state), - devctl, - ({ char *s; - switch (devctl & MUSB_DEVCTL_VBUS) { - case 0 << MUSB_DEVCTL_VBUS_SHIFT: - s = "vbuserr_retry, - musb->port1_status); - - /* go through A_WAIT_VFALL then start a new session */ - if (!ignore) - musb_platform_set_vbus(musb, 0); - handled = IRQ_HANDLED; - } - - if (int_usb & MUSB_INTR_SUSPEND) { - dev_dbg(musb->controller, "SUSPEND (%s) devctl %02x power %02x\n", - otg_state_string(musb->xceiv->state), devctl, power); - handled = IRQ_HANDLED; - - switch (musb->xceiv->state) { - case OTG_STATE_A_PERIPHERAL: - /* 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; - case OTG_STATE_B_IDLE: - if (!musb->is_active) - break; - case OTG_STATE_B_PERIPHERAL: - musb_g_suspend(musb); - musb->is_active = is_otg_enabled(musb) - && otg->gadget->b_hnp_enable; - if (musb->is_active) { - musb->xceiv->state = OTG_STATE_B_WAIT_ACON; - dev_dbg(musb->controller, "HNP: Setting timer for b_ase0_brst\n"); - mod_timer(&musb->otg_timer, jiffies - + msecs_to_jiffies( - OTG_TIME_B_ASE0_BRST)); - } - break; - case OTG_STATE_A_WAIT_BCON: - if (musb->a_wait_bcon != 0) - musb_platform_try_idle(musb, jiffies - + msecs_to_jiffies(musb->a_wait_bcon)); - break; - case OTG_STATE_A_HOST: - musb->xceiv->state = OTG_STATE_A_SUSPEND; - musb->is_active = is_otg_enabled(musb) - && otg->host->b_hnp_enable; - break; - case OTG_STATE_B_HOST: - /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */ - dev_dbg(musb->controller, "REVISIT: SUSPEND as B_HOST\n"); - break; - default: - /* "should not happen" */ - musb->is_active = 0; - break; - } - } - - if (int_usb & MUSB_INTR_CONNECT) { - struct usb_hcd *hcd = musb_to_hcd(musb); - - handled = IRQ_HANDLED; - musb->is_active = 1; - - musb->ep0_stage = MUSB_EP0_START; - - /* flush endpoints when transitioning from Device Mode */ - if (is_peripheral_active(musb)) { - /* REVISIT HNP; just force disconnect */ - } - musb_writew(musb->mregs, MUSB_INTRTXE, musb->epmask); - musb_writew(musb->mregs, MUSB_INTRRXE, musb->epmask & 0xfffe); - musb_writeb(musb->mregs, MUSB_INTRUSBE, 0xf7); - musb->port1_status &= ~(USB_PORT_STAT_LOW_SPEED - |USB_PORT_STAT_HIGH_SPEED - |USB_PORT_STAT_ENABLE - ); - musb->port1_status |= USB_PORT_STAT_CONNECTION - |(USB_PORT_STAT_C_CONNECTION << 16); - - /* high vs full speed is just a guess until after reset */ - 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) { - dev_dbg(musb->controller, "HNP: SUSPEND+CONNECT, now b_host\n"); - int_usb &= ~MUSB_INTR_SUSPEND; - goto b_host; - } else - dev_dbg(musb->controller, "CONNECT as b_peripheral???\n"); - break; - case OTG_STATE_B_WAIT_ACON: - dev_dbg(musb->controller, "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); - - dev_dbg(musb->controller, "CONNECT (%s) devctl %02x\n", - otg_state_string(musb->xceiv->state), devctl); - } - - if ((int_usb & MUSB_INTR_DISCONNECT) && !musb->ignore_disconnect) { - dev_dbg(musb->controller, "DISCONNECT (%s) as %s, devctl %02x\n", - otg_state_string(musb->xceiv->state), - MUSB_MODE(musb), devctl); - handled = IRQ_HANDLED; - - switch (musb->xceiv->state) { - case OTG_STATE_A_HOST: - case OTG_STATE_A_SUSPEND: - usb_hcd_resume_root_hub(musb_to_hcd(musb)); - musb_root_disconnect(musb); - if (musb->a_wait_bcon != 0 && is_otg_enabled(musb)) - musb_platform_try_idle(musb, jiffies - + msecs_to_jiffies(musb->a_wait_bcon)); - break; - case OTG_STATE_B_HOST: - /* 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); - musb_root_disconnect(musb); - /* FALLTHROUGH */ - case OTG_STATE_B_WAIT_ACON: - /* FALLTHROUGH */ - case OTG_STATE_B_PERIPHERAL: - case OTG_STATE_B_IDLE: - musb_g_disconnect(musb); - break; - default: - WARNING("unhandled DISCONNECT transition (%s)\n", - otg_state_string(musb->xceiv->state)); - break; - } - } - - /* mentor saves a bit: bus reset and babble share the same irq. - * only host sees babble; only peripheral sees bus reset. - */ - if (int_usb & MUSB_INTR_RESET) { - handled = IRQ_HANDLED; - if (is_host_capable() && (devctl & MUSB_DEVCTL_HM) != 0) { - /* - * Looks like non-HS BABBLE can be ignored, but - * HS BABBLE is an error condition. For HS the solution - * is to avoid babble in the first place and fix what - * caused BABBLE. When HS BABBLE happens we can only - * stop the session. - */ - if (devctl & (MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV)) - dev_dbg(musb->controller, "BABBLE devctl: %02x\n", devctl); - else { - ERR("Stopping host session -- babble\n"); - musb_writeb(musb->mregs, MUSB_DEVCTL, 0); - } - } else if (is_peripheral_capable()) { - dev_dbg(musb->controller, "BUS RESET as %s\n", - otg_state_string(musb->xceiv->state)); - switch (musb->xceiv->state) { - case OTG_STATE_A_SUSPEND: - /* We need to ignore disconnect on suspend - * otherwise tusb 2.0 won't reconnect after a - * power cycle, which breaks otg compliance. - */ - musb->ignore_disconnect = 1; - musb_g_reset(musb); - /* FALLTHROUGH */ - case OTG_STATE_A_WAIT_BCON: /* OPT TD.4.7-900ms */ - /* never use invalid T(a_wait_bcon) */ - dev_dbg(musb->controller, "HNP: in %s, %d msec timeout\n", - otg_state_string(musb->xceiv->state), - TA_WAIT_BCON(musb)); - mod_timer(&musb->otg_timer, jiffies - + msecs_to_jiffies(TA_WAIT_BCON(musb))); - break; - case OTG_STATE_A_PERIPHERAL: - musb->ignore_disconnect = 0; - del_timer(&musb->otg_timer); - musb_g_reset(musb); - break; - case OTG_STATE_B_WAIT_ACON: - dev_dbg(musb->controller, "HNP: RESET (%s), to b_peripheral\n", - otg_state_string(musb->xceiv->state)); - musb->xceiv->state = OTG_STATE_B_PERIPHERAL; - musb_g_reset(musb); - break; - case OTG_STATE_B_IDLE: - musb->xceiv->state = OTG_STATE_B_PERIPHERAL; - /* FALLTHROUGH */ - case OTG_STATE_B_PERIPHERAL: - musb_g_reset(musb); - break; - default: - dev_dbg(musb->controller, "Unhandled BUS RESET as %s\n", - otg_state_string(musb->xceiv->state)); - } - } - } - -#if 0 -/* REVISIT ... this would be for multiplexing periodic endpoints, or - * supporting transfer phasing to prevent exceeding ISO bandwidth - * limits of a given frame or microframe. - * - * It's not needed for peripheral side, which dedicates endpoints; - * though it _might_ use SOF irqs for other purposes. - * - * And it's not currently needed for host side, which also dedicates - * endpoints, relies on TX/RX interval registers, and isn't claimed - * to support ISO transfers yet. - */ - if (int_usb & MUSB_INTR_SOF) { - void __iomem *mbase = musb->mregs; - struct musb_hw_ep *ep; - u8 epnum; - u16 frame; - - dev_dbg(musb->controller, "START_OF_FRAME\n"); - handled = IRQ_HANDLED; - - /* start any periodic Tx transfers waiting for current frame */ - frame = musb_readw(mbase, MUSB_FRAME); - ep = musb->endpoints; - for (epnum = 1; (epnum < musb->nr_endpoints) - && (musb->epmask >= (1 << epnum)); - epnum++, ep++) { - /* - * FIXME handle framecounter wraps (12 bits) - * eliminate duplicated StartUrb logic - */ - if (ep->dwWaitFrame >= frame) { - ep->dwWaitFrame = 0; - pr_debug("SOF --> periodic TX%s on %d\n", - ep->tx_channel ? " DMA" : "", - epnum); - if (!ep->tx_channel) - musb_h_tx_start(musb, epnum); - else - cppi_hostdma_start(musb, epnum); - } - } /* end of for loop */ - } -#endif - - schedule_work(&musb->irq_work); - - return handled; -} - -/*-------------------------------------------------------------------------*/ - -/* -* Program the HDRC to start (enable interrupts, dma, etc.). -*/ -void musb_start(struct musb *musb) -{ - void __iomem *regs = musb->mregs; - u8 devctl = musb_readb(regs, MUSB_DEVCTL); - - dev_dbg(musb->controller, "<== devctl %02x\n", devctl); - - /* Set INT enable registers, enable interrupts */ - musb_writew(regs, MUSB_INTRTXE, musb->epmask); - musb_writew(regs, MUSB_INTRRXE, musb->epmask & 0xfffe); - musb_writeb(regs, MUSB_INTRUSBE, 0xf7); - - musb_writeb(regs, MUSB_TESTMODE, 0); - - /* put into basic highspeed mode and start session */ - musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE - | MUSB_POWER_HSENAB - /* ENSUSPEND wedges tusb */ - /* | MUSB_POWER_ENSUSPEND */ - ); - - musb->is_active = 0; - devctl = musb_readb(regs, MUSB_DEVCTL); - devctl &= ~MUSB_DEVCTL_SESSION; - - if (is_otg_enabled(musb)) { - /* session started after: - * (a) ID-grounded irq, host mode; - * (b) vbus present/connect IRQ, peripheral mode; - * (c) peripheral initiates, using SRP - */ - if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) - musb->is_active = 1; - else - devctl |= MUSB_DEVCTL_SESSION; - - } else if (is_host_enabled(musb)) { - /* assume ID pin is hard-wired to ground */ - devctl |= MUSB_DEVCTL_SESSION; - - } else /* peripheral is enabled */ { - if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) - musb->is_active = 1; - } - musb_platform_enable(musb); - musb_writeb(regs, MUSB_DEVCTL, devctl); -} - - -static void musb_generic_disable(struct musb *musb) -{ - void __iomem *mbase = musb->mregs; - u16 temp; - - /* disable interrupts */ - musb_writeb(mbase, MUSB_INTRUSBE, 0); - musb_writew(mbase, MUSB_INTRTXE, 0); - musb_writew(mbase, MUSB_INTRRXE, 0); - - /* off */ - musb_writeb(mbase, MUSB_DEVCTL, 0); - - /* flush pending interrupts */ - temp = musb_readb(mbase, MUSB_INTRUSB); - temp = musb_readw(mbase, MUSB_INTRTX); - temp = musb_readw(mbase, MUSB_INTRRX); - -} - -/* - * Make the HDRC stop (disable interrupts, etc.); - * reversible by musb_start - * called on gadget driver unregister - * with controller locked, irqs blocked - * acts as a NOP unless some role activated the hardware - */ -void musb_stop(struct musb *musb) -{ - /* stop IRQs, timers, ... */ - musb_platform_disable(musb); - musb_generic_disable(musb); - dev_dbg(musb->controller, "HDRC disabled\n"); - - /* FIXME - * - mark host and/or peripheral drivers unusable/inactive - * - disable DMA (and enable it in HdrcStart) - * - make sure we can musb_start() after musb_stop(); with - * OTG mode, gadget driver module rmmod/modprobe cycles that - * - ... - */ - musb_platform_try_idle(musb, 0); -} - -static void musb_shutdown(struct platform_device *pdev) -{ - struct musb *musb = dev_to_musb(&pdev->dev); - unsigned long flags; - - pm_runtime_get_sync(musb->controller); - - musb_gadget_cleanup(musb); - - spin_lock_irqsave(&musb->lock, flags); - musb_platform_disable(musb); - musb_generic_disable(musb); - spin_unlock_irqrestore(&musb->lock, flags); - - if (!is_otg_enabled(musb) && is_host_enabled(musb)) - usb_remove_hcd(musb_to_hcd(musb)); - musb_writeb(musb->mregs, MUSB_DEVCTL, 0); - musb_platform_exit(musb); - - pm_runtime_put(musb->controller); - /* FIXME power down */ -} - - -/*-------------------------------------------------------------------------*/ - -/* - * The silicon either has hard-wired endpoint configurations, or else - * "dynamic fifo" sizing. The driver has support for both, though at this - * writing only the dynamic sizing is very well tested. Since we switched - * away from compile-time hardware parameters, we can no longer rely on - * dead code elimination to leave only the relevant one in the object file. - * - * We don't currently use dynamic fifo setup capability to do anything - * more than selecting one of a bunch of predefined configurations. - */ -#if defined(CONFIG_USB_MUSB_TUSB6010) \ - || defined(CONFIG_USB_MUSB_TUSB6010_MODULE) \ - || defined(CONFIG_USB_MUSB_OMAP2PLUS) \ - || defined(CONFIG_USB_MUSB_OMAP2PLUS_MODULE) \ - || defined(CONFIG_USB_MUSB_AM35X) \ - || defined(CONFIG_USB_MUSB_AM35X_MODULE) -static ushort __devinitdata fifo_mode = 4; -#elif defined(CONFIG_USB_MUSB_UX500) \ - || defined(CONFIG_USB_MUSB_UX500_MODULE) -static ushort __devinitdata fifo_mode = 5; -#else -static ushort __devinitdata fifo_mode = 2; -#endif - -/* "modprobe ... fifo_mode=1" etc */ -module_param(fifo_mode, ushort, 0); -MODULE_PARM_DESC(fifo_mode, "initial endpoint configuration"); - -/* - * tables defining fifo_mode values. define more if you like. - * for host side, make sure both halves of ep1 are set up. - */ - -/* mode 0 - fits in 2KB */ -static struct musb_fifo_cfg __devinitdata mode_0_cfg[] = { -{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, }, -{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, }, -{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, }, -}; - -/* mode 1 - fits in 4KB */ -static struct musb_fifo_cfg __devinitdata mode_1_cfg[] = { -{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE, }, -{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE, }, -{ .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, .mode = BUF_DOUBLE, }, -{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, }, -{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, }, -}; - -/* mode 2 - fits in 4KB */ -static struct musb_fifo_cfg __devinitdata mode_2_cfg[] = { -{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, }, -{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, }, -}; - -/* mode 3 - fits in 4KB */ -static struct musb_fifo_cfg __devinitdata mode_3_cfg[] = { -{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE, }, -{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE, }, -{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, }, -{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, }, -}; - -/* mode 4 - fits in 16KB */ -static struct musb_fifo_cfg __devinitdata mode_4_cfg[] = { -{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 3, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 3, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 4, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 4, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 5, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 5, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 6, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 6, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 7, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 7, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 8, .style = FIFO_TX, .maxpacket = 512, }, -{ .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 = 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, }, -}; - -/* mode 5 - fits in 8KB */ -static struct musb_fifo_cfg __devinitdata mode_5_cfg[] = { -{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 3, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 3, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 4, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 4, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 5, .style = FIFO_TX, .maxpacket = 512, }, -{ .hw_ep_num = 5, .style = FIFO_RX, .maxpacket = 512, }, -{ .hw_ep_num = 6, .style = FIFO_TX, .maxpacket = 32, }, -{ .hw_ep_num = 6, .style = FIFO_RX, .maxpacket = 32, }, -{ .hw_ep_num = 7, .style = FIFO_TX, .maxpacket = 32, }, -{ .hw_ep_num = 7, .style = FIFO_RX, .maxpacket = 32, }, -{ .hw_ep_num = 8, .style = FIFO_TX, .maxpacket = 32, }, -{ .hw_ep_num = 8, .style = FIFO_RX, .maxpacket = 32, }, -{ .hw_ep_num = 9, .style = FIFO_TX, .maxpacket = 32, }, -{ .hw_ep_num = 9, .style = FIFO_RX, .maxpacket = 32, }, -{ .hw_ep_num = 10, .style = FIFO_TX, .maxpacket = 32, }, -{ .hw_ep_num = 10, .style = FIFO_RX, .maxpacket = 32, }, -{ .hw_ep_num = 11, .style = FIFO_TX, .maxpacket = 32, }, -{ .hw_ep_num = 11, .style = FIFO_RX, .maxpacket = 32, }, -{ .hw_ep_num = 12, .style = FIFO_TX, .maxpacket = 32, }, -{ .hw_ep_num = 12, .style = FIFO_RX, .maxpacket = 32, }, -{ .hw_ep_num = 13, .style = FIFO_RXTX, .maxpacket = 512, }, -{ .hw_ep_num = 14, .style = FIFO_RXTX, .maxpacket = 1024, }, -{ .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, }, -}; - -/* - * configure a fifo; for non-shared endpoints, this may be called - * once for a tx fifo and once for an rx fifo. - * - * returns negative errno or offset for next fifo. - */ -static int __devinit -fifo_setup(struct musb *musb, struct musb_hw_ep *hw_ep, - const struct musb_fifo_cfg *cfg, u16 offset) -{ - void __iomem *mbase = musb->mregs; - int size = 0; - u16 maxpacket = cfg->maxpacket; - u16 c_off = offset >> 3; - u8 c_size; - - /* expect hw_ep has already been zero-initialized */ - - size = ffs(max(maxpacket, (u16) 8)) - 1; - maxpacket = 1 << size; - - c_size = size - 3; - if (cfg->mode == BUF_DOUBLE) { - if ((offset + (maxpacket << 1)) > - (1 << (musb->config->ram_bits + 2))) - return -EMSGSIZE; - c_size |= MUSB_FIFOSZ_DPB; - } else { - if ((offset + maxpacket) > (1 << (musb->config->ram_bits + 2))) - return -EMSGSIZE; - } - - /* configure the FIFO */ - musb_writeb(mbase, MUSB_INDEX, hw_ep->epnum); - - /* EP0 reserved endpoint for control, bidirectional; - * EP1 reserved for bulk, two unidirection halves. - */ - if (hw_ep->epnum == 1) - musb->bulk_ep = hw_ep; - /* REVISIT error check: be sure ep0 can both rx and tx ... */ - switch (cfg->style) { - case FIFO_TX: - musb_write_txfifosz(mbase, c_size); - musb_write_txfifoadd(mbase, c_off); - hw_ep->tx_double_buffered = !!(c_size & MUSB_FIFOSZ_DPB); - hw_ep->max_packet_sz_tx = maxpacket; - break; - case FIFO_RX: - musb_write_rxfifosz(mbase, c_size); - musb_write_rxfifoadd(mbase, c_off); - hw_ep->rx_double_buffered = !!(c_size & MUSB_FIFOSZ_DPB); - hw_ep->max_packet_sz_rx = maxpacket; - break; - case FIFO_RXTX: - musb_write_txfifosz(mbase, c_size); - musb_write_txfifoadd(mbase, c_off); - hw_ep->rx_double_buffered = !!(c_size & MUSB_FIFOSZ_DPB); - hw_ep->max_packet_sz_rx = maxpacket; - - musb_write_rxfifosz(mbase, c_size); - musb_write_rxfifoadd(mbase, c_off); - hw_ep->tx_double_buffered = hw_ep->rx_double_buffered; - hw_ep->max_packet_sz_tx = maxpacket; - - hw_ep->is_shared_fifo = true; - break; - } - - /* NOTE rx and tx endpoint irqs aren't managed separately, - * which happens to be ok - */ - musb->epmask |= (1 << hw_ep->epnum); - - return offset + (maxpacket << ((c_size & MUSB_FIFOSZ_DPB) ? 1 : 0)); -} - -static struct musb_fifo_cfg __devinitdata ep0_cfg = { - .style = FIFO_RXTX, .maxpacket = 64, -}; - -static int __devinit ep_config_from_table(struct musb *musb) -{ - const struct musb_fifo_cfg *cfg; - unsigned i, n; - int offset; - struct musb_hw_ep *hw_ep = musb->endpoints; - - if (musb->config->fifo_cfg) { - cfg = musb->config->fifo_cfg; - n = musb->config->fifo_cfg_size; - goto done; - } - - switch (fifo_mode) { - default: - fifo_mode = 0; - /* FALLTHROUGH */ - case 0: - cfg = mode_0_cfg; - n = ARRAY_SIZE(mode_0_cfg); - break; - case 1: - cfg = mode_1_cfg; - n = ARRAY_SIZE(mode_1_cfg); - break; - case 2: - cfg = mode_2_cfg; - n = ARRAY_SIZE(mode_2_cfg); - break; - case 3: - cfg = mode_3_cfg; - n = ARRAY_SIZE(mode_3_cfg); - break; - case 4: - cfg = mode_4_cfg; - n = ARRAY_SIZE(mode_4_cfg); - break; - case 5: - cfg = mode_5_cfg; - n = ARRAY_SIZE(mode_5_cfg); - break; - } - - printk(KERN_DEBUG "%s: setup fifo_mode %d\n", - musb_driver_name, fifo_mode); - - -done: - offset = fifo_setup(musb, hw_ep, &ep0_cfg, 0); - /* assert(offset > 0) */ - - /* NOTE: for RTL versions >= 1.400 EPINFO and RAMINFO would - * be better than static musb->config->num_eps and DYN_FIFO_SIZE... - */ - - for (i = 0; i < n; i++) { - u8 epn = cfg->hw_ep_num; - - if (epn >= musb->config->num_eps) { - pr_debug("%s: invalid ep %d\n", - musb_driver_name, epn); - return -EINVAL; - } - offset = fifo_setup(musb, hw_ep + epn, cfg++, offset); - if (offset < 0) { - pr_debug("%s: mem overrun, ep %d\n", - musb_driver_name, epn); - return -EINVAL; - } - epn++; - musb->nr_endpoints = max(epn, musb->nr_endpoints); - } - - printk(KERN_DEBUG "%s: %d/%d max ep, %d/%d memory\n", - musb_driver_name, - n + 1, musb->config->num_eps * 2 - 1, - offset, (1 << (musb->config->ram_bits + 2))); - - if (!musb->bulk_ep) { - pr_debug("%s: missing bulk\n", musb_driver_name); - return -EINVAL; - } - - return 0; -} - - -/* - * ep_config_from_hw - when MUSB_C_DYNFIFO_DEF is false - * @param musb the controller - */ -static int __devinit ep_config_from_hw(struct musb *musb) -{ - u8 epnum = 0; - struct musb_hw_ep *hw_ep; - void *mbase = musb->mregs; - int ret = 0; - - dev_dbg(musb->controller, "<== static silicon ep config\n"); - - /* FIXME pick up ep0 maxpacket size */ - - for (epnum = 1; epnum < musb->config->num_eps; epnum++) { - musb_ep_select(mbase, epnum); - hw_ep = musb->endpoints + epnum; - - ret = musb_read_fifosize(musb, hw_ep, epnum); - if (ret < 0) - break; - - /* FIXME set up hw_ep->{rx,tx}_double_buffered */ - - /* pick an RX/TX endpoint for bulk */ - if (hw_ep->max_packet_sz_tx < 512 - || hw_ep->max_packet_sz_rx < 512) - continue; - - /* REVISIT: this algorithm is lazy, we should at least - * try to pick a double buffered endpoint. - */ - if (musb->bulk_ep) - continue; - musb->bulk_ep = hw_ep; - } - - if (!musb->bulk_ep) { - pr_debug("%s: missing bulk\n", musb_driver_name); - return -EINVAL; - } - - return 0; -} - -enum { MUSB_CONTROLLER_MHDRC, MUSB_CONTROLLER_HDRC, }; - -/* Initialize MUSB (M)HDRC part of the USB hardware subsystem; - * configure endpoints, or take their config from silicon - */ -static int __devinit musb_core_init(u16 musb_type, struct musb *musb) -{ - u8 reg; - char *type; - char aInfo[90], aRevision[32], aDate[12]; - void __iomem *mbase = musb->mregs; - int status = 0; - int i; - - /* log core options (read using indexed model) */ - reg = musb_read_configdata(mbase); - - strcpy(aInfo, (reg & MUSB_CONFIGDATA_UTMIDW) ? "UTMI-16" : "UTMI-8"); - if (reg & MUSB_CONFIGDATA_DYNFIFO) { - strcat(aInfo, ", dyn FIFOs"); - musb->dyn_fifo = true; - } - if (reg & MUSB_CONFIGDATA_MPRXE) { - strcat(aInfo, ", bulk combine"); - musb->bulk_combine = true; - } - if (reg & MUSB_CONFIGDATA_MPTXE) { - strcat(aInfo, ", bulk split"); - musb->bulk_split = true; - } - if (reg & MUSB_CONFIGDATA_HBRXE) { - strcat(aInfo, ", HB-ISO Rx"); - musb->hb_iso_rx = true; - } - if (reg & MUSB_CONFIGDATA_HBTXE) { - strcat(aInfo, ", HB-ISO Tx"); - musb->hb_iso_tx = true; - } - if (reg & MUSB_CONFIGDATA_SOFTCONE) - strcat(aInfo, ", SoftConn"); - - printk(KERN_DEBUG "%s: ConfigData=0x%02x (%s)\n", - musb_driver_name, reg, aInfo); - - aDate[0] = 0; - if (MUSB_CONTROLLER_MHDRC == musb_type) { - musb->is_multipoint = 1; - type = "M"; - } else { - musb->is_multipoint = 0; - type = ""; -#ifndef CONFIG_USB_OTG_BLACKLIST_HUB - printk(KERN_ERR - "%s: kernel must blacklist external hubs\n", - musb_driver_name); -#endif - } - - /* log release info */ - musb->hwvers = musb_read_hwvers(mbase); - snprintf(aRevision, 32, "%d.%d%s", MUSB_HWVERS_MAJOR(musb->hwvers), - MUSB_HWVERS_MINOR(musb->hwvers), - (musb->hwvers & MUSB_HWVERS_RC) ? "RC" : ""); - printk(KERN_DEBUG "%s: %sHDRC RTL version %s %s\n", - musb_driver_name, type, aRevision, aDate); - - /* configure ep0 */ - musb_configure_ep0(musb); - - /* discover endpoint configuration */ - musb->nr_endpoints = 1; - musb->epmask = 1; - - if (musb->dyn_fifo) - status = ep_config_from_table(musb); - else - status = ep_config_from_hw(musb); - - if (status < 0) - return status; - - /* finish init, and print endpoint config */ - for (i = 0; i < musb->nr_endpoints; i++) { - struct musb_hw_ep *hw_ep = musb->endpoints + i; - - hw_ep->fifo = MUSB_FIFO_OFFSET(i) + mbase; -#if defined(CONFIG_USB_MUSB_TUSB6010) || defined (CONFIG_USB_MUSB_TUSB6010_MODULE) - hw_ep->fifo_async = musb->async + 0x400 + MUSB_FIFO_OFFSET(i); - hw_ep->fifo_sync = musb->sync + 0x400 + MUSB_FIFO_OFFSET(i); - hw_ep->fifo_sync_va = - musb->sync_va + 0x400 + MUSB_FIFO_OFFSET(i); - - if (i == 0) - hw_ep->conf = mbase - 0x400 + TUSB_EP0_CONF; - else - hw_ep->conf = mbase + 0x400 + (((i - 1) & 0xf) << 2); -#endif - - hw_ep->regs = MUSB_EP_OFFSET(i, 0) + mbase; - hw_ep->target_regs = musb_read_target_reg_base(i, mbase); - hw_ep->rx_reinit = 1; - hw_ep->tx_reinit = 1; - - if (hw_ep->max_packet_sz_tx) { - dev_dbg(musb->controller, - "%s: hw_ep %d%s, %smax %d\n", - musb_driver_name, i, - hw_ep->is_shared_fifo ? "shared" : "tx", - hw_ep->tx_double_buffered - ? "doublebuffer, " : "", - hw_ep->max_packet_sz_tx); - } - if (hw_ep->max_packet_sz_rx && !hw_ep->is_shared_fifo) { - dev_dbg(musb->controller, - "%s: hw_ep %d%s, %smax %d\n", - musb_driver_name, i, - "rx", - hw_ep->rx_double_buffered - ? "doublebuffer, " : "", - hw_ep->max_packet_sz_rx); - } - if (!(hw_ep->max_packet_sz_tx || hw_ep->max_packet_sz_rx)) - dev_dbg(musb->controller, "hw_ep %d not configured\n", i); - } - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -#if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430) || \ - defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_U8500) - -static irqreturn_t generic_interrupt(int irq, void *__hci) -{ - unsigned long flags; - irqreturn_t retval = IRQ_NONE; - struct musb *musb = __hci; - - spin_lock_irqsave(&musb->lock, flags); - - musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); - musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); - musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); - - if (musb->int_usb || musb->int_tx || musb->int_rx) - retval = musb_interrupt(musb); - - spin_unlock_irqrestore(&musb->lock, flags); - - return retval; -} - -#else -#define generic_interrupt NULL -#endif - -/* - * handle all the irqs defined by the HDRC core. for now we expect: other - * irq sources (phy, dma, etc) will be handled first, musb->int_* values - * will be assigned, and the irq will already have been acked. - * - * called in irq context with spinlock held, irqs blocked - */ -irqreturn_t musb_interrupt(struct musb *musb) -{ - irqreturn_t retval = IRQ_NONE; - u8 devctl, power; - int ep_num; - u32 reg; - - devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - power = musb_readb(musb->mregs, MUSB_POWER); - - dev_dbg(musb->controller, "** IRQ %s usb%04x tx%04x rx%04x\n", - (devctl & MUSB_DEVCTL_HM) ? "host" : "peripheral", - musb->int_usb, musb->int_tx, musb->int_rx); - - /* the core can interrupt us for multiple reasons; docs have - * a generic interrupt flowchart to follow - */ - if (musb->int_usb) - retval |= musb_stage0_irq(musb, musb->int_usb, - devctl, power); - - /* "stage 1" is handling endpoint irqs */ - - /* handle endpoint 0 first */ - if (musb->int_tx & 1) { - if (devctl & MUSB_DEVCTL_HM) - retval |= musb_h_ep0_irq(musb); - else - retval |= musb_g_ep0_irq(musb); - } - - /* RX on endpoints 1-15 */ - reg = musb->int_rx >> 1; - ep_num = 1; - while (reg) { - if (reg & 1) { - /* musb_ep_select(musb->mregs, ep_num); */ - /* REVISIT just retval = ep->rx_irq(...) */ - retval = IRQ_HANDLED; - if (devctl & MUSB_DEVCTL_HM) { - if (is_host_capable()) - musb_host_rx(musb, ep_num); - } else { - if (is_peripheral_capable()) - musb_g_rx(musb, ep_num); - } - } - - reg >>= 1; - ep_num++; - } - - /* TX on endpoints 1-15 */ - reg = musb->int_tx >> 1; - ep_num = 1; - while (reg) { - if (reg & 1) { - /* musb_ep_select(musb->mregs, ep_num); */ - /* REVISIT just retval |= ep->tx_irq(...) */ - retval = IRQ_HANDLED; - if (devctl & MUSB_DEVCTL_HM) { - if (is_host_capable()) - musb_host_tx(musb, ep_num); - } else { - if (is_peripheral_capable()) - musb_g_tx(musb, ep_num); - } - } - reg >>= 1; - ep_num++; - } - - return retval; -} -EXPORT_SYMBOL_GPL(musb_interrupt); - -#ifndef CONFIG_MUSB_PIO_ONLY -static bool __devinitdata use_dma = 1; - -/* "modprobe ... use_dma=0" etc */ -module_param(use_dma, bool, 0); -MODULE_PARM_DESC(use_dma, "enable/disable use of DMA"); - -void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit) -{ - u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - - /* called with controller lock already held */ - - if (!epnum) { -#ifndef CONFIG_USB_TUSB_OMAP_DMA - if (!is_cppi_enabled()) { - /* endpoint 0 */ - if (devctl & MUSB_DEVCTL_HM) - musb_h_ep0_irq(musb); - else - musb_g_ep0_irq(musb); - } -#endif - } else { - /* endpoints 1..15 */ - if (transmit) { - if (devctl & MUSB_DEVCTL_HM) { - if (is_host_capable()) - musb_host_tx(musb, epnum); - } else { - if (is_peripheral_capable()) - musb_g_tx(musb, epnum); - } - } else { - /* receive */ - if (devctl & MUSB_DEVCTL_HM) { - if (is_host_capable()) - musb_host_rx(musb, epnum); - } else { - if (is_peripheral_capable()) - musb_g_rx(musb, epnum); - } - } - } -} -EXPORT_SYMBOL_GPL(musb_dma_completion); - -#else -#define use_dma 0 -#endif - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_SYSFS - -static ssize_t -musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct musb *musb = dev_to_musb(dev); - unsigned long flags; - int ret = -EINVAL; - - spin_lock_irqsave(&musb->lock, flags); - ret = sprintf(buf, "%s\n", otg_state_string(musb->xceiv->state)); - spin_unlock_irqrestore(&musb->lock, flags); - - return ret; -} - -static ssize_t -musb_mode_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t n) -{ - struct musb *musb = dev_to_musb(dev); - unsigned long flags; - int status; - - spin_lock_irqsave(&musb->lock, flags); - if (sysfs_streq(buf, "host")) - status = musb_platform_set_mode(musb, MUSB_HOST); - else if (sysfs_streq(buf, "peripheral")) - status = musb_platform_set_mode(musb, MUSB_PERIPHERAL); - else if (sysfs_streq(buf, "otg")) - status = musb_platform_set_mode(musb, MUSB_OTG); - else - status = -EINVAL; - spin_unlock_irqrestore(&musb->lock, flags); - - return (status == 0) ? n : status; -} -static DEVICE_ATTR(mode, 0644, musb_mode_show, musb_mode_store); - -static ssize_t -musb_vbus_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t n) -{ - struct musb *musb = dev_to_musb(dev); - unsigned long flags; - unsigned long val; - - if (sscanf(buf, "%lu", &val) < 1) { - dev_err(dev, "Invalid VBUS timeout ms value\n"); - return -EINVAL; - } - - spin_lock_irqsave(&musb->lock, flags); - /* 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); - - return n; -} - -static ssize_t -musb_vbus_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct musb *musb = dev_to_musb(dev); - unsigned long flags; - unsigned long val; - int vbus; - - 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 msec\n", - vbus ? "on" : "off", val); -} -static DEVICE_ATTR(vbus, 0644, musb_vbus_show, musb_vbus_store); - -/* Gadget drivers can't know that a host is connected so they might want - * to start SRP, but users can. This allows userspace to trigger SRP. - */ -static ssize_t -musb_srp_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t n) -{ - struct musb *musb = dev_to_musb(dev); - unsigned short srp; - - if (sscanf(buf, "%hu", &srp) != 1 - || (srp != 1)) { - dev_err(dev, "SRP: Value must be 1\n"); - return -EINVAL; - } - - if (srp == 1) - musb_g_wakeup(musb); - - return n; -} -static DEVICE_ATTR(srp, 0644, NULL, musb_srp_store); - -static struct attribute *musb_attributes[] = { - &dev_attr_mode.attr, - &dev_attr_vbus.attr, - &dev_attr_srp.attr, - NULL -}; - -static const struct attribute_group musb_attr_group = { - .attrs = musb_attributes, -}; - -#endif /* sysfs */ - -/* Only used to provide driver mode change events */ -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; - sysfs_notify(&musb->controller->kobj, NULL, "mode"); - } -} - -/* -------------------------------------------------------------------------- - * Init support - */ - -static struct musb *__devinit -allocate_instance(struct device *dev, - struct musb_hdrc_config *config, void __iomem *mbase) -{ - struct musb *musb; - struct musb_hw_ep *ep; - int epnum; - struct usb_hcd *hcd; - - hcd = usb_create_hcd(&musb_hc_driver, dev, dev_name(dev)); - if (!hcd) - return NULL; - /* usbcore sets dev->driver_data to hcd, and sometimes uses that... */ - - musb = hcd_to_musb(hcd); - INIT_LIST_HEAD(&musb->control); - INIT_LIST_HEAD(&musb->in_bulk); - INIT_LIST_HEAD(&musb->out_bulk); - - hcd->uses_new_polling = 1; - hcd->has_tt = 1; - - musb->vbuserr_retry = VBUSERR_RETRY_COUNT; - musb->a_wait_bcon = OTG_TIME_A_WAIT_BCON; - dev_set_drvdata(dev, musb); - musb->mregs = mbase; - musb->ctrl_base = mbase; - musb->nIrq = -ENODEV; - musb->config = config; - BUG_ON(musb->config->num_eps > MUSB_C_NUM_EPS); - for (epnum = 0, ep = musb->endpoints; - epnum < musb->config->num_eps; - epnum++, ep++) { - ep->musb = musb; - ep->epnum = epnum; - } - - musb->controller = dev; - - return musb; -} - -static void musb_free(struct musb *musb) -{ - /* this has multiple entry modes. it handles fault cleanup after - * probe(), where things may be partially set up, as well as rmmod - * cleanup after everything's been de-activated. - */ - -#ifdef CONFIG_SYSFS - sysfs_remove_group(&musb->controller->kobj, &musb_attr_group); -#endif - - if (musb->nIrq >= 0) { - if (musb->irq_wake) - disable_irq_wake(musb->nIrq); - free_irq(musb->nIrq, musb); - } - if (is_dma_capable() && musb->dma_controller) { - struct dma_controller *c = musb->dma_controller; - - (void) c->stop(c); - dma_controller_destroy(c); - } - - kfree(musb); -} - -/* - * Perform generic per-controller initialization. - * - * @pDevice: the controller (already clocked, etc) - * @nIrq: irq - * @mregs: virtual address of controller registers, - * not yet corrected for platform-specific offsets - */ -static int __devinit -musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) -{ - int status; - struct musb *musb; - struct musb_hdrc_platform_data *plat = dev->platform_data; - - /* The driver might handle more features than the board; OK. - * Fail when the board needs a feature that's not enabled. - */ - if (!plat) { - dev_dbg(dev, "no platform_data?\n"); - status = -ENODEV; - goto fail0; - } - - /* allocate */ - musb = allocate_instance(dev, plat->config, ctrl); - if (!musb) { - status = -ENOMEM; - goto fail0; - } - - pm_runtime_use_autosuspend(musb->controller); - pm_runtime_set_autosuspend_delay(musb->controller, 200); - pm_runtime_enable(musb->controller); - - spin_lock_init(&musb->lock); - musb->board_mode = plat->mode; - musb->board_set_power = plat->set_power; - musb->min_power = plat->min_power; - musb->ops = plat->platform_ops; - - /* 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() - * - stops powering VBUS - * - * There are various transceiver 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); - if (status < 0) - goto fail1; - - if (!musb->isr) { - status = -ENODEV; - goto fail2; - } - - if (!musb->xceiv->io_ops) { - musb->xceiv->io_dev = musb->controller; - musb->xceiv->io_priv = musb->mregs; - musb->xceiv->io_ops = &musb_ulpi_access; - } - - pm_runtime_get_sync(musb->controller); - -#ifndef CONFIG_MUSB_PIO_ONLY - if (use_dma && dev->dma_mask) { - struct dma_controller *c; - - c = dma_controller_create(musb, musb->mregs); - musb->dma_controller = c; - if (c) - (void) c->start(c); - } -#endif - /* ideally this would be abstracted in platform setup */ - if (!is_dma_capable() || !musb->dma_controller) - dev->dma_mask = NULL; - - /* be sure interrupts are disabled before connecting ISR */ - musb_platform_disable(musb); - musb_generic_disable(musb); - - /* setup musb parts of the core (especially endpoints) */ - status = musb_core_init(plat->config->multipoint - ? MUSB_CONTROLLER_MHDRC - : MUSB_CONTROLLER_HDRC, musb); - if (status < 0) - goto fail3; - - setup_timer(&musb->otg_timer, musb_otg_timer_func, (unsigned long) musb); - - /* Init IRQ workqueue before request_irq */ - INIT_WORK(&musb->irq_work, musb_irq_work); - - /* attach to the IRQ */ - if (request_irq(nIrq, musb->isr, 0, dev_name(dev), musb)) { - dev_err(dev, "request_irq %d failed!\n", nIrq); - status = -ENODEV; - goto fail3; - } - musb->nIrq = nIrq; -/* FIXME this handles wakeup irqs wrong */ - if (enable_irq_wake(nIrq) == 0) { - musb->irq_wake = 1; - device_init_wakeup(dev, 1); - } else { - musb->irq_wake = 0; - } - - /* host side needs more setup */ - if (is_host_enabled(musb)) { - struct usb_hcd *hcd = musb_to_hcd(musb); - - otg_set_host(musb->xceiv->otg, &hcd->self); - - if (is_otg_enabled(musb)) - hcd->self.otg_port = 1; - musb->xceiv->otg->host = &hcd->self; - hcd->power_budget = 2 * (plat->power ? : 250); - - /* program PHY to use external vBus if required */ - if (plat->extvbus) { - u8 busctl = musb_read_ulpi_buscontrol(musb->mregs); - busctl |= MUSB_ULPI_USE_EXTVBUS; - musb_write_ulpi_buscontrol(musb->mregs, busctl); - } - } - - /* For the host-only role, we can activate right away. - * (We expect the ID pin to be forcibly grounded!!) - * Otherwise, wait till the gadget driver hooks up. - */ - if (!is_otg_enabled(musb) && is_host_enabled(musb)) { - struct usb_hcd *hcd = musb_to_hcd(musb); - - MUSB_HST_MODE(musb); - musb->xceiv->otg->default_a = 1; - musb->xceiv->state = OTG_STATE_A_IDLE; - - status = usb_add_hcd(musb_to_hcd(musb), 0, 0); - - hcd->self.uses_pio_for_control = 1; - dev_dbg(musb->controller, "%s mode, status %d, devctl %02x %c\n", - "HOST", status, - musb_readb(musb->mregs, MUSB_DEVCTL), - (musb_readb(musb->mregs, MUSB_DEVCTL) - & MUSB_DEVCTL_BDEVICE - ? 'B' : 'A')); - - } else /* peripheral is enabled */ { - MUSB_DEV_MODE(musb); - musb->xceiv->otg->default_a = 0; - musb->xceiv->state = OTG_STATE_B_IDLE; - - status = musb_gadget_setup(musb); - - dev_dbg(musb->controller, "%s mode, status %d, dev%02x\n", - is_otg_enabled(musb) ? "OTG" : "PERIPHERAL", - status, - musb_readb(musb->mregs, MUSB_DEVCTL)); - - } - if (status < 0) - goto fail3; - - status = musb_init_debugfs(musb); - if (status < 0) - goto fail4; - -#ifdef CONFIG_SYSFS - status = sysfs_create_group(&musb->controller->kobj, &musb_attr_group); - if (status) - goto fail5; -#endif - - pm_runtime_put(musb->controller); - - dev_info(dev, "USB %s mode controller at %p using %s, IRQ %d\n", - ({char *s; - switch (musb->board_mode) { - case MUSB_HOST: s = "Host"; break; - case MUSB_PERIPHERAL: s = "Peripheral"; break; - default: s = "OTG"; break; - }; s; }), - ctrl, - (is_dma_capable() && musb->dma_controller) - ? "DMA" : "PIO", - musb->nIrq); - - return 0; - -fail5: - musb_exit_debugfs(musb); - -fail4: - if (!is_otg_enabled(musb) && is_host_enabled(musb)) - usb_remove_hcd(musb_to_hcd(musb)); - else - musb_gadget_cleanup(musb); - -fail3: - pm_runtime_put_sync(musb->controller); - -fail2: - if (musb->irq_wake) - device_init_wakeup(dev, 0); - musb_platform_exit(musb); - -fail1: - dev_err(musb->controller, - "musb_init_controller failed with status %d\n", status); - - musb_free(musb); - -fail0: - - return status; - -} - -/*-------------------------------------------------------------------------*/ - -/* all implementations (PCI bridge to FPGA, VLYNQ, etc) should just - * bridge to a platform device; this driver then suffices. - */ - -#ifndef CONFIG_MUSB_PIO_ONLY -static u64 *orig_dma_mask; -#endif - -static int __devinit musb_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - int irq = platform_get_irq_byname(pdev, "mc"); - int status; - struct resource *iomem; - void __iomem *base; - - iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iomem || irq <= 0) - return -ENODEV; - - base = ioremap(iomem->start, resource_size(iomem)); - if (!base) { - dev_err(dev, "ioremap failed\n"); - return -ENOMEM; - } - -#ifndef CONFIG_MUSB_PIO_ONLY - /* clobbered by use_dma=n */ - orig_dma_mask = dev->dma_mask; -#endif - status = musb_init_controller(dev, irq, base); - if (status < 0) - iounmap(base); - - return status; -} - -static int __devexit musb_remove(struct platform_device *pdev) -{ - struct musb *musb = dev_to_musb(&pdev->dev); - void __iomem *ctrl_base = musb->ctrl_base; - - /* this gets called on rmmod. - * - Host mode: host may still be active - * - Peripheral mode: peripheral is deactivated (or never-activated) - * - OTG mode: both roles are deactivated (or never-activated) - */ - musb_exit_debugfs(musb); - musb_shutdown(pdev); - - musb_free(musb); - iounmap(ctrl_base); - device_init_wakeup(&pdev->dev, 0); -#ifndef CONFIG_MUSB_PIO_ONLY - pdev->dev.dma_mask = orig_dma_mask; -#endif - return 0; -} - -#ifdef CONFIG_PM - -static void musb_save_context(struct musb *musb) -{ - int i; - void __iomem *musb_base = musb->mregs; - void __iomem *epio; - - if (is_host_enabled(musb)) { - musb->context.frame = musb_readw(musb_base, MUSB_FRAME); - musb->context.testmode = musb_readb(musb_base, MUSB_TESTMODE); - musb->context.busctl = musb_read_ulpi_buscontrol(musb->mregs); - } - musb->context.power = musb_readb(musb_base, MUSB_POWER); - musb->context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE); - musb->context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE); - musb->context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE); - musb->context.index = musb_readb(musb_base, MUSB_INDEX); - musb->context.devctl = musb_readb(musb_base, MUSB_DEVCTL); - - for (i = 0; i < musb->config->num_eps; ++i) { - struct musb_hw_ep *hw_ep; - - hw_ep = &musb->endpoints[i]; - if (!hw_ep) - continue; - - epio = hw_ep->regs; - if (!epio) - continue; - - musb_writeb(musb_base, MUSB_INDEX, i); - musb->context.index_regs[i].txmaxp = - musb_readw(epio, MUSB_TXMAXP); - musb->context.index_regs[i].txcsr = - musb_readw(epio, MUSB_TXCSR); - musb->context.index_regs[i].rxmaxp = - musb_readw(epio, MUSB_RXMAXP); - musb->context.index_regs[i].rxcsr = - musb_readw(epio, MUSB_RXCSR); - - if (musb->dyn_fifo) { - musb->context.index_regs[i].txfifoadd = - musb_read_txfifoadd(musb_base); - musb->context.index_regs[i].rxfifoadd = - musb_read_rxfifoadd(musb_base); - musb->context.index_regs[i].txfifosz = - musb_read_txfifosz(musb_base); - musb->context.index_regs[i].rxfifosz = - musb_read_rxfifosz(musb_base); - } - if (is_host_enabled(musb)) { - musb->context.index_regs[i].txtype = - musb_readb(epio, MUSB_TXTYPE); - musb->context.index_regs[i].txinterval = - musb_readb(epio, MUSB_TXINTERVAL); - musb->context.index_regs[i].rxtype = - musb_readb(epio, MUSB_RXTYPE); - musb->context.index_regs[i].rxinterval = - musb_readb(epio, MUSB_RXINTERVAL); - - musb->context.index_regs[i].txfunaddr = - musb_read_txfunaddr(musb_base, i); - musb->context.index_regs[i].txhubaddr = - musb_read_txhubaddr(musb_base, i); - musb->context.index_regs[i].txhubport = - musb_read_txhubport(musb_base, i); - - musb->context.index_regs[i].rxfunaddr = - musb_read_rxfunaddr(musb_base, i); - musb->context.index_regs[i].rxhubaddr = - musb_read_rxhubaddr(musb_base, i); - musb->context.index_regs[i].rxhubport = - musb_read_rxhubport(musb_base, i); - } - } -} - -static void musb_restore_context(struct musb *musb) -{ - int i; - void __iomem *musb_base = musb->mregs; - void __iomem *ep_target_regs; - void __iomem *epio; - - if (is_host_enabled(musb)) { - musb_writew(musb_base, MUSB_FRAME, musb->context.frame); - musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode); - musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl); - } - musb_writeb(musb_base, MUSB_POWER, musb->context.power); - musb_writew(musb_base, MUSB_INTRTXE, musb->context.intrtxe); - musb_writew(musb_base, MUSB_INTRRXE, musb->context.intrrxe); - musb_writeb(musb_base, MUSB_INTRUSBE, musb->context.intrusbe); - musb_writeb(musb_base, MUSB_DEVCTL, musb->context.devctl); - - for (i = 0; i < musb->config->num_eps; ++i) { - struct musb_hw_ep *hw_ep; - - hw_ep = &musb->endpoints[i]; - if (!hw_ep) - continue; - - epio = hw_ep->regs; - if (!epio) - continue; - - musb_writeb(musb_base, MUSB_INDEX, i); - musb_writew(epio, MUSB_TXMAXP, - musb->context.index_regs[i].txmaxp); - musb_writew(epio, MUSB_TXCSR, - musb->context.index_regs[i].txcsr); - musb_writew(epio, MUSB_RXMAXP, - musb->context.index_regs[i].rxmaxp); - musb_writew(epio, MUSB_RXCSR, - musb->context.index_regs[i].rxcsr); - - if (musb->dyn_fifo) { - musb_write_txfifosz(musb_base, - musb->context.index_regs[i].txfifosz); - musb_write_rxfifosz(musb_base, - musb->context.index_regs[i].rxfifosz); - musb_write_txfifoadd(musb_base, - musb->context.index_regs[i].txfifoadd); - musb_write_rxfifoadd(musb_base, - musb->context.index_regs[i].rxfifoadd); - } - - if (is_host_enabled(musb)) { - musb_writeb(epio, MUSB_TXTYPE, - musb->context.index_regs[i].txtype); - musb_writeb(epio, MUSB_TXINTERVAL, - musb->context.index_regs[i].txinterval); - musb_writeb(epio, MUSB_RXTYPE, - musb->context.index_regs[i].rxtype); - musb_writeb(epio, MUSB_RXINTERVAL, - - musb->context.index_regs[i].rxinterval); - musb_write_txfunaddr(musb_base, i, - musb->context.index_regs[i].txfunaddr); - musb_write_txhubaddr(musb_base, i, - musb->context.index_regs[i].txhubaddr); - musb_write_txhubport(musb_base, i, - musb->context.index_regs[i].txhubport); - - ep_target_regs = - musb_read_target_reg_base(i, musb_base); - - musb_write_rxfunaddr(ep_target_regs, - musb->context.index_regs[i].rxfunaddr); - musb_write_rxhubaddr(ep_target_regs, - musb->context.index_regs[i].rxhubaddr); - musb_write_rxhubport(ep_target_regs, - musb->context.index_regs[i].rxhubport); - } - } - musb_writeb(musb_base, MUSB_INDEX, musb->context.index); -} - -static int musb_suspend(struct device *dev) -{ - struct musb *musb = dev_to_musb(dev); - unsigned long flags; - - spin_lock_irqsave(&musb->lock, flags); - - if (is_peripheral_active(musb)) { - /* FIXME force disconnect unless we know USB will wake - * the system up quickly enough to respond ... - */ - } else if (is_host_active(musb)) { - /* we know all the children are suspended; sometimes - * they will even be wakeup-enabled. - */ - } - - spin_unlock_irqrestore(&musb->lock, flags); - return 0; -} - -static int musb_resume_noirq(struct device *dev) -{ - /* for static cmos like DaVinci, register values were preserved - * unless for some reason the whole soc powered down or the USB - * module got reset through the PSC (vs just being disabled). - */ - return 0; -} - -static int musb_runtime_suspend(struct device *dev) -{ - struct musb *musb = dev_to_musb(dev); - - musb_save_context(musb); - - return 0; -} - -static int musb_runtime_resume(struct device *dev) -{ - struct musb *musb = dev_to_musb(dev); - static int first = 1; - - /* - * When pm_runtime_get_sync called for the first time in driver - * init, some of the structure is still not initialized which is - * used in restore function. But clock needs to be - * enabled before any register access, so - * pm_runtime_get_sync has to be called. - * Also context restore without save does not make - * any sense - */ - if (!first) - musb_restore_context(musb); - first = 0; - - return 0; -} - -static const struct dev_pm_ops musb_dev_pm_ops = { - .suspend = musb_suspend, - .resume_noirq = musb_resume_noirq, - .runtime_suspend = musb_runtime_suspend, - .runtime_resume = musb_runtime_resume, -}; - -#define MUSB_DEV_PM_OPS (&musb_dev_pm_ops) -#else -#define MUSB_DEV_PM_OPS NULL -#endif - -static struct platform_driver musb_driver = { - .driver = { - .name = (char *)musb_driver_name, - .bus = &platform_bus_type, - .owner = THIS_MODULE, - .pm = MUSB_DEV_PM_OPS, - }, - .probe = musb_probe, - .remove = __devexit_p(musb_remove), - .shutdown = musb_shutdown, -}; - -/*-------------------------------------------------------------------------*/ - -static int __init musb_init(void) -{ - if (usb_disabled()) - return 0; - - pr_info("%s: version " MUSB_VERSION ", " - "?dma?" - ", " - "otg (peripheral+host)", - musb_driver_name); - return platform_driver_register(&musb_driver); -} -module_init(musb_init); - -static void __exit musb_cleanup(void) -{ - platform_driver_unregister(&musb_driver); -} -module_exit(musb_cleanup); diff --git a/ANDROID_3.4.5/drivers/usb/musb/musb_core.h b/ANDROID_3.4.5/drivers/usb/musb/musb_core.h deleted file mode 100644 index f4a40f00..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/musb_core.h +++ /dev/null @@ -1,606 +0,0 @@ -/* - * MUSB OTG driver defines - * - * Copyright 2005 Mentor Graphics Corporation - * Copyright (C) 2005-2006 by Texas Instruments - * Copyright (C) 2006-2007 Nokia Corporation - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef __MUSB_CORE_H__ -#define __MUSB_CORE_H__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct musb; -struct musb_hw_ep; -struct musb_ep; - -/* Helper defines for struct musb->hwvers */ -#define MUSB_HWVERS_MAJOR(x) ((x >> 10) & 0x1f) -#define MUSB_HWVERS_MINOR(x) (x & 0x3ff) -#define MUSB_HWVERS_RC 0x8000 -#define MUSB_HWVERS_1300 0x52C -#define MUSB_HWVERS_1400 0x590 -#define MUSB_HWVERS_1800 0x720 -#define MUSB_HWVERS_1900 0x784 -#define MUSB_HWVERS_2000 0x800 - -#include "musb_debug.h" -#include "musb_dma.h" - -#include "musb_io.h" -#include "musb_regs.h" - -#include "musb_gadget.h" -#include -#include "musb_host.h" - -#define is_peripheral_enabled(musb) ((musb)->board_mode != MUSB_HOST) -#define is_host_enabled(musb) ((musb)->board_mode != MUSB_PERIPHERAL) -#define is_otg_enabled(musb) ((musb)->board_mode == MUSB_OTG) - -/* NOTE: otg and peripheral-only state machines start at B_IDLE. - * OTG or host-only go to A_IDLE when ID is sensed. - */ -#define is_peripheral_active(m) (!(m)->is_host) -#define is_host_active(m) ((m)->is_host) - -#ifndef CONFIG_HAVE_CLK -/* Dummy stub for clk framework */ -#define clk_get(dev, id) NULL -#define clk_put(clock) do {} while (0) -#define clk_enable(clock) do {} while (0) -#define clk_disable(clock) do {} while (0) -#endif - -#ifdef CONFIG_PROC_FS -#include -#define MUSB_CONFIG_PROC_FS -#endif - -/****************************** PERIPHERAL ROLE *****************************/ - -#define is_peripheral_capable() (1) - -extern irqreturn_t musb_g_ep0_irq(struct musb *); -extern void musb_g_tx(struct musb *, u8); -extern void musb_g_rx(struct musb *, u8); -extern void musb_g_reset(struct musb *); -extern void musb_g_suspend(struct musb *); -extern void musb_g_resume(struct musb *); -extern void musb_g_wakeup(struct musb *); -extern void musb_g_disconnect(struct musb *); - -/****************************** HOST ROLE ***********************************/ - -#define is_host_capable() (1) - -extern irqreturn_t musb_h_ep0_irq(struct musb *); -extern void musb_host_tx(struct musb *, u8); -extern void musb_host_rx(struct musb *, u8); - -/****************************** CONSTANTS ********************************/ - -#ifndef MUSB_C_NUM_EPS -#define MUSB_C_NUM_EPS ((u8)16) -#endif - -#ifndef MUSB_MAX_END0_PACKET -#define MUSB_MAX_END0_PACKET ((u16)MUSB_EP0_FIFOSIZE) -#endif - -/* host side ep0 states */ -enum musb_h_ep0_state { - MUSB_EP0_IDLE, - MUSB_EP0_START, /* expect ack of setup */ - MUSB_EP0_IN, /* expect IN DATA */ - MUSB_EP0_OUT, /* expect ack of OUT DATA */ - MUSB_EP0_STATUS, /* expect ack of STATUS */ -} __attribute__ ((packed)); - -/* peripheral side ep0 states */ -enum musb_g_ep0_state { - 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) */ - MUSB_EP0_STAGE_STATUSOUT, /* (after IN data) */ - MUSB_EP0_STAGE_ACKWAIT, /* after zlp, before statusin */ -} __attribute__ ((packed)); - -/* - * 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 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 ********************************/ - -/* Endpoint registers (other than dynfifo setup) can be accessed either - * directly with the "flat" model, or after setting up an index register. - */ - -#if defined(CONFIG_ARCH_DAVINCI) || defined(CONFIG_SOC_OMAP2430) \ - || defined(CONFIG_SOC_OMAP3430) || defined(CONFIG_BLACKFIN) \ - || defined(CONFIG_ARCH_OMAP4) -/* REVISIT indexed access seemed to - * misbehave (on DaVinci) for at least peripheral IN ... - */ -#define MUSB_FLAT_REG -#endif - -/* TUSB mapping: "flat" plus ep0 special cases */ -#if defined(CONFIG_USB_MUSB_TUSB6010) || \ - defined(CONFIG_USB_MUSB_TUSB6010_MODULE) -#define musb_ep_select(_mbase, _epnum) \ - musb_writeb((_mbase), MUSB_INDEX, (_epnum)) -#define MUSB_EP_OFFSET MUSB_TUSB_OFFSET - -/* "flat" mapping: each endpoint has its own i/o address */ -#elif defined(MUSB_FLAT_REG) -#define musb_ep_select(_mbase, _epnum) (((void)(_mbase)), ((void)(_epnum))) -#define MUSB_EP_OFFSET MUSB_FLAT_OFFSET - -/* "indexed" mapping: INDEX register controls register bank select */ -#else -#define musb_ep_select(_mbase, _epnum) \ - musb_writeb((_mbase), MUSB_INDEX, (_epnum)) -#define MUSB_EP_OFFSET MUSB_INDEXED_OFFSET -#endif - -/****************************** FUNCTIONS ********************************/ - -#define MUSB_HST_MODE(_musb)\ - { (_musb)->is_host = true; } -#define MUSB_DEV_MODE(_musb) \ - { (_musb)->is_host = false; } - -#define test_devctl_hst_mode(_x) \ - (musb_readb((_x)->mregs, MUSB_DEVCTL)&MUSB_DEVCTL_HM) - -#define MUSB_MODE(musb) ((musb)->is_host ? "Host" : "Peripheral") - -/******************************** TYPES *************************************/ - -/** - * struct musb_platform_ops - Operations passed to musb_core by HW glue layer - * @init: turns on clocks, sets up platform-specific registers, etc - * @exit: undoes @init - * @set_mode: forcefully changes operating mode - * @try_ilde: tries to idle the IP - * @vbus_status: returns vbus status if possible - * @set_vbus: forces vbus status - * @adjust_channel_params: pre check for standard dma channel_program func - */ -struct musb_platform_ops { - int (*init)(struct musb *musb); - int (*exit)(struct musb *musb); - - void (*enable)(struct musb *musb); - void (*disable)(struct musb *musb); - - int (*set_mode)(struct musb *musb, u8 mode); - void (*try_idle)(struct musb *musb, unsigned long timeout); - - int (*vbus_status)(struct musb *musb); - void (*set_vbus)(struct musb *musb, int on); - - int (*adjust_channel_params)(struct dma_channel *channel, - u16 packet_sz, u8 *mode, - dma_addr_t *dma_addr, u32 *len); -}; - -/* - * struct musb_hw_ep - endpoint hardware (bidirectional) - * - * Ordered slightly for better cacheline locality. - */ -struct musb_hw_ep { - struct musb *musb; - void __iomem *fifo; - void __iomem *regs; - -#if defined(CONFIG_USB_MUSB_TUSB6010) || \ - defined(CONFIG_USB_MUSB_TUSB6010_MODULE) - void __iomem *conf; -#endif - - /* index in musb->endpoints[] */ - u8 epnum; - - /* hardware configuration, possibly dynamic */ - bool is_shared_fifo; - bool tx_double_buffered; - bool rx_double_buffered; - u16 max_packet_sz_tx; - u16 max_packet_sz_rx; - - struct dma_channel *tx_channel; - struct dma_channel *rx_channel; - -#if defined(CONFIG_USB_MUSB_TUSB6010) || \ - defined(CONFIG_USB_MUSB_TUSB6010_MODULE) - /* TUSB has "asynchronous" and "synchronous" dma modes */ - dma_addr_t fifo_async; - dma_addr_t fifo_sync; - void __iomem *fifo_sync_va; -#endif - - void __iomem *target_regs; - - /* currently scheduled peripheral endpoint */ - struct musb_qh *in_qh; - struct musb_qh *out_qh; - - u8 rx_reinit; - u8 tx_reinit; - - /* peripheral side */ - struct musb_ep ep_in; /* TX */ - struct musb_ep ep_out; /* RX */ -}; - -static inline struct musb_request *next_in_request(struct musb_hw_ep *hw_ep) -{ - return next_request(&hw_ep->ep_in); -} - -static inline struct musb_request *next_out_request(struct musb_hw_ep *hw_ep) -{ - return next_request(&hw_ep->ep_out); -} - -struct musb_csr_regs { - /* FIFO registers */ - u16 txmaxp, txcsr, rxmaxp, rxcsr; - u16 rxfifoadd, txfifoadd; - u8 txtype, txinterval, rxtype, rxinterval; - u8 rxfifosz, txfifosz; - u8 txfunaddr, txhubaddr, txhubport; - u8 rxfunaddr, rxhubaddr, rxhubport; -}; - -struct musb_context_registers { - - u8 power; - u16 intrtxe, intrrxe; - u8 intrusbe; - u16 frame; - u8 index, testmode; - - u8 devctl, busctl, misc; - u32 otg_interfsel; - - struct musb_csr_regs index_regs[MUSB_C_NUM_EPS]; -}; - -/* - * struct musb - Driver instance data. - */ -struct musb { - /* device lock */ - spinlock_t lock; - - const struct musb_platform_ops *ops; - struct musb_context_registers context; - - irqreturn_t (*isr)(int, void *); - struct work_struct irq_work; - struct work_struct otg_notifier_work; - u16 hwvers; - -/* this hub status bit is reserved by USB 2.0 and not seen by usbcore */ -#define MUSB_PORT_STAT_RESUME (1 << 31) - - u32 port1_status; - - unsigned long rh_timer; - - enum musb_h_ep0_state ep0_stage; - - /* bulk traffic normally dedicates endpoint hardware, and each - * direction has its own ring of host side endpoints. - * we try to progress the transfer at the head of each endpoint's - * queue until it completes or NAKs too much; then we try the next - * endpoint. - */ - struct musb_hw_ep *bulk_ep; - - 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; - struct notifier_block nb; - - struct dma_controller *dma_controller; - - struct device *controller; - void __iomem *ctrl_base; - void __iomem *mregs; - -#if defined(CONFIG_USB_MUSB_TUSB6010) || \ - defined(CONFIG_USB_MUSB_TUSB6010_MODULE) - dma_addr_t async; - dma_addr_t sync; - void __iomem *sync_va; -#endif - - /* passed down from chip/board specific irq handlers */ - u8 int_usb; - u16 int_rx; - u16 int_tx; - - struct usb_phy *xceiv; - u8 xceiv_event; - - int nIrq; - unsigned irq_wake:1; - - struct musb_hw_ep endpoints[MUSB_C_NUM_EPS]; -#define control_ep endpoints - -#define VBUSERR_RETRY_COUNT 3 - u16 vbuserr_retry; - u16 epmask; - u8 nr_endpoints; - - u8 board_mode; /* enum musb_mode */ - int (*board_set_power)(int state); - - u8 min_power; /* vbus for periph, in mA/2 */ - - bool is_host; - - int a_wait_bcon; /* VBUS timeout in msecs */ - unsigned long idle_timeout; /* Next timeout in jiffies */ - - /* active means connected and not suspended */ - unsigned is_active:1; - - 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? */ - unsigned dyn_fifo:1; /* dynamic FIFO supported? */ - - unsigned bulk_split:1; -#define can_bulk_split(musb,type) \ - (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_split) - - unsigned bulk_combine:1; -#define can_bulk_combine(musb,type) \ - (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_combine) - - /* is_suspended means USB B_PERIPHERAL suspend */ - unsigned is_suspended:1; - - /* may_wakeup means remote wakeup is enabled */ - unsigned may_wakeup:1; - - /* is_self_powered is reported in device status and the - * config descriptor. is_bus_powered means B_PERIPHERAL - * draws some VBUS current; both can be true. - */ - unsigned is_self_powered:1; - unsigned is_bus_powered:1; - - unsigned set_address:1; - unsigned test_mode:1; - unsigned softconnect:1; - - u8 address; - u8 test_mode_nr; - u16 ackpend; /* ep0 */ - enum musb_g_ep0_state ep0_state; - struct usb_gadget g; /* the gadget */ - struct usb_gadget_driver *gadget_driver; /* its driver */ - - /* - * FIXME: Remove this flag. - * - * This is only added to allow Blackfin to work - * with current driver. For some unknown reason - * Blackfin doesn't work with double buffering - * and that's enabled by default. - * - * We added this flag to forcefully disable double - * buffering until we get it working. - */ - unsigned double_buffer_not_ok:1; - - struct musb_hdrc_config *config; - -#ifdef MUSB_CONFIG_PROC_FS - struct proc_dir_entry *proc_entry; -#endif -}; - -static inline struct musb *gadget_to_musb(struct usb_gadget *g) -{ - return container_of(g, struct musb, g); -} - -#ifdef CONFIG_BLACKFIN -static inline int musb_read_fifosize(struct musb *musb, - struct musb_hw_ep *hw_ep, u8 epnum) -{ - musb->nr_endpoints++; - musb->epmask |= (1 << epnum); - - if (epnum < 5) { - hw_ep->max_packet_sz_tx = 128; - hw_ep->max_packet_sz_rx = 128; - } else { - hw_ep->max_packet_sz_tx = 1024; - hw_ep->max_packet_sz_rx = 1024; - } - hw_ep->is_shared_fifo = false; - - return 0; -} - -static inline void musb_configure_ep0(struct musb *musb) -{ - musb->endpoints[0].max_packet_sz_tx = MUSB_EP0_FIFOSIZE; - musb->endpoints[0].max_packet_sz_rx = MUSB_EP0_FIFOSIZE; - musb->endpoints[0].is_shared_fifo = true; -} - -#else - -static inline int musb_read_fifosize(struct musb *musb, - struct musb_hw_ep *hw_ep, u8 epnum) -{ - void *mbase = musb->mregs; - u8 reg = 0; - - /* read from core using indexed model */ - reg = musb_readb(mbase, MUSB_EP_OFFSET(epnum, MUSB_FIFOSIZE)); - /* 0's returned when no more endpoints */ - if (!reg) - return -ENODEV; - - musb->nr_endpoints++; - musb->epmask |= (1 << epnum); - - hw_ep->max_packet_sz_tx = 1 << (reg & 0x0f); - - /* shared TX/RX FIFO? */ - if ((reg & 0xf0) == 0xf0) { - hw_ep->max_packet_sz_rx = hw_ep->max_packet_sz_tx; - hw_ep->is_shared_fifo = true; - return 0; - } else { - hw_ep->max_packet_sz_rx = 1 << ((reg & 0xf0) >> 4); - hw_ep->is_shared_fifo = false; - } - - return 0; -} - -static inline void musb_configure_ep0(struct musb *musb) -{ - musb->endpoints[0].max_packet_sz_tx = MUSB_EP0_FIFOSIZE; - musb->endpoints[0].max_packet_sz_rx = MUSB_EP0_FIFOSIZE; - musb->endpoints[0].is_shared_fifo = true; -} -#endif /* CONFIG_BLACKFIN */ - - -/***************************** Glue it together *****************************/ - -extern const char musb_driver_name[]; - -extern void musb_start(struct musb *musb); -extern void musb_stop(struct musb *musb); - -extern void musb_write_fifo(struct musb_hw_ep *ep, u16 len, const u8 *src); -extern void musb_read_fifo(struct musb_hw_ep *ep, u16 len, u8 *dst); - -extern void musb_load_testpacket(struct musb *); - -extern irqreturn_t musb_interrupt(struct musb *); - -extern void musb_hnp_stop(struct musb *musb); - -static inline void musb_platform_set_vbus(struct musb *musb, int is_on) -{ - if (musb->ops->set_vbus) - musb->ops->set_vbus(musb, is_on); -} - -static inline void musb_platform_enable(struct musb *musb) -{ - if (musb->ops->enable) - musb->ops->enable(musb); -} - -static inline void musb_platform_disable(struct musb *musb) -{ - if (musb->ops->disable) - musb->ops->disable(musb); -} - -static inline int musb_platform_set_mode(struct musb *musb, u8 mode) -{ - if (!musb->ops->set_mode) - return 0; - - return musb->ops->set_mode(musb, mode); -} - -static inline void musb_platform_try_idle(struct musb *musb, - unsigned long timeout) -{ - if (musb->ops->try_idle) - musb->ops->try_idle(musb, timeout); -} - -static inline int musb_platform_get_vbus_status(struct musb *musb) -{ - if (!musb->ops->vbus_status) - return 0; - - return musb->ops->vbus_status(musb); -} - -static inline int musb_platform_init(struct musb *musb) -{ - if (!musb->ops->init) - return -EINVAL; - - return musb->ops->init(musb); -} - -static inline int musb_platform_exit(struct musb *musb) -{ - if (!musb->ops->exit) - return -EINVAL; - - return musb->ops->exit(musb); -} - -#endif /* __MUSB_CORE_H__ */ diff --git a/ANDROID_3.4.5/drivers/usb/musb/musb_debug.h b/ANDROID_3.4.5/drivers/usb/musb/musb_debug.h deleted file mode 100644 index 27ba8f79..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/musb_debug.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * MUSB OTG driver debug defines - * - * Copyright 2005 Mentor Graphics Corporation - * Copyright (C) 2005-2006 by Texas Instruments - * Copyright (C) 2006-2007 Nokia Corporation - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef __MUSB_LINUX_DEBUG_H__ -#define __MUSB_LINUX_DEBUG_H__ - -#define yprintk(facility, format, args...) \ - do { printk(facility "%s %d: " format , \ - __func__, __LINE__ , ## args); } while (0) -#define WARNING(fmt, args...) yprintk(KERN_WARNING, fmt, ## args) -#define INFO(fmt, args...) yprintk(KERN_INFO, fmt, ## args) -#define ERR(fmt, args...) yprintk(KERN_ERR, fmt, ## args) - -#ifdef CONFIG_DEBUG_FS -int musb_init_debugfs(struct musb *musb); -void musb_exit_debugfs(struct musb *musb); -#else -static inline int musb_init_debugfs(struct musb *musb) -{ - return 0; -} -static inline void musb_exit_debugfs(struct musb *musb) -{ -} -#endif - -#endif /* __MUSB_LINUX_DEBUG_H__ */ diff --git a/ANDROID_3.4.5/drivers/usb/musb/musb_debugfs.c b/ANDROID_3.4.5/drivers/usb/musb/musb_debugfs.c deleted file mode 100644 index 40a37c91..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/musb_debugfs.c +++ /dev/null @@ -1,278 +0,0 @@ -/* - * MUSB OTG driver debugfs support - * - * Copyright 2010 Nokia Corporation - * Contact: Felipe Balbi - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include -#include -#include -#include - -#include - -#include "musb_core.h" -#include "musb_debug.h" - -struct musb_register_map { - char *name; - unsigned offset; - unsigned size; -}; - -static const struct musb_register_map musb_regmap[] = { - { "FAddr", 0x00, 8 }, - { "Power", 0x01, 8 }, - { "Frame", 0x0c, 16 }, - { "Index", 0x0e, 8 }, - { "Testmode", 0x0f, 8 }, - { "TxMaxPp", 0x10, 16 }, - { "TxCSRp", 0x12, 16 }, - { "RxMaxPp", 0x14, 16 }, - { "RxCSR", 0x16, 16 }, - { "RxCount", 0x18, 16 }, - { "ConfigData", 0x1f, 8 }, - { "DevCtl", 0x60, 8 }, - { "MISC", 0x61, 8 }, - { "TxFIFOsz", 0x62, 8 }, - { "RxFIFOsz", 0x63, 8 }, - { "TxFIFOadd", 0x64, 16 }, - { "RxFIFOadd", 0x66, 16 }, - { "VControl", 0x68, 32 }, - { "HWVers", 0x6C, 16 }, - { "EPInfo", 0x78, 8 }, - { "RAMInfo", 0x79, 8 }, - { "LinkInfo", 0x7A, 8 }, - { "VPLen", 0x7B, 8 }, - { "HS_EOF1", 0x7C, 8 }, - { "FS_EOF1", 0x7D, 8 }, - { "LS_EOF1", 0x7E, 8 }, - { "SOFT_RST", 0x7F, 8 }, - { "DMA_CNTLch0", 0x204, 16 }, - { "DMA_ADDRch0", 0x208, 32 }, - { "DMA_COUNTch0", 0x20C, 32 }, - { "DMA_CNTLch1", 0x214, 16 }, - { "DMA_ADDRch1", 0x218, 32 }, - { "DMA_COUNTch1", 0x21C, 32 }, - { "DMA_CNTLch2", 0x224, 16 }, - { "DMA_ADDRch2", 0x228, 32 }, - { "DMA_COUNTch2", 0x22C, 32 }, - { "DMA_CNTLch3", 0x234, 16 }, - { "DMA_ADDRch3", 0x238, 32 }, - { "DMA_COUNTch3", 0x23C, 32 }, - { "DMA_CNTLch4", 0x244, 16 }, - { "DMA_ADDRch4", 0x248, 32 }, - { "DMA_COUNTch4", 0x24C, 32 }, - { "DMA_CNTLch5", 0x254, 16 }, - { "DMA_ADDRch5", 0x258, 32 }, - { "DMA_COUNTch5", 0x25C, 32 }, - { "DMA_CNTLch6", 0x264, 16 }, - { "DMA_ADDRch6", 0x268, 32 }, - { "DMA_COUNTch6", 0x26C, 32 }, - { "DMA_CNTLch7", 0x274, 16 }, - { "DMA_ADDRch7", 0x278, 32 }, - { "DMA_COUNTch7", 0x27C, 32 }, - { } /* Terminating Entry */ -}; - -static struct dentry *musb_debugfs_root; - -static int musb_regdump_show(struct seq_file *s, void *unused) -{ - struct musb *musb = s->private; - unsigned i; - - seq_printf(s, "MUSB (M)HDRC Register Dump\n"); - - for (i = 0; i < ARRAY_SIZE(musb_regmap); i++) { - switch (musb_regmap[i].size) { - case 8: - seq_printf(s, "%-12s: %02x\n", musb_regmap[i].name, - musb_readb(musb->mregs, musb_regmap[i].offset)); - break; - case 16: - seq_printf(s, "%-12s: %04x\n", musb_regmap[i].name, - musb_readw(musb->mregs, musb_regmap[i].offset)); - break; - case 32: - seq_printf(s, "%-12s: %08x\n", musb_regmap[i].name, - musb_readl(musb->mregs, musb_regmap[i].offset)); - break; - } - } - - return 0; -} - -static int musb_regdump_open(struct inode *inode, struct file *file) -{ - return single_open(file, musb_regdump_show, inode->i_private); -} - -static int musb_test_mode_show(struct seq_file *s, void *unused) -{ - struct musb *musb = s->private; - unsigned test; - - test = musb_readb(musb->mregs, MUSB_TESTMODE); - - if (test & MUSB_TEST_FORCE_HOST) - seq_printf(s, "force host\n"); - - if (test & MUSB_TEST_FIFO_ACCESS) - seq_printf(s, "fifo access\n"); - - if (test & MUSB_TEST_FORCE_FS) - seq_printf(s, "force full-speed\n"); - - if (test & MUSB_TEST_FORCE_HS) - seq_printf(s, "force high-speed\n"); - - if (test & MUSB_TEST_PACKET) - seq_printf(s, "test packet\n"); - - if (test & MUSB_TEST_K) - seq_printf(s, "test K\n"); - - if (test & MUSB_TEST_J) - seq_printf(s, "test J\n"); - - if (test & MUSB_TEST_SE0_NAK) - seq_printf(s, "test SE0 NAK\n"); - - return 0; -} - -static const struct file_operations musb_regdump_fops = { - .open = musb_regdump_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int musb_test_mode_open(struct inode *inode, struct file *file) -{ - return single_open(file, musb_test_mode_show, inode->i_private); -} - -static ssize_t musb_test_mode_write(struct file *file, - const char __user *ubuf, size_t count, loff_t *ppos) -{ - struct seq_file *s = file->private_data; - struct musb *musb = s->private; - u8 test = 0; - char buf[18]; - - memset(buf, 0x00, sizeof(buf)); - - if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) - return -EFAULT; - - if (!strncmp(buf, "force host", 9)) - test = MUSB_TEST_FORCE_HOST; - - if (!strncmp(buf, "fifo access", 11)) - test = MUSB_TEST_FIFO_ACCESS; - - if (!strncmp(buf, "force full-speed", 15)) - test = MUSB_TEST_FORCE_FS; - - if (!strncmp(buf, "force high-speed", 15)) - test = MUSB_TEST_FORCE_HS; - - if (!strncmp(buf, "test packet", 10)) { - test = MUSB_TEST_PACKET; - musb_load_testpacket(musb); - } - - if (!strncmp(buf, "test K", 6)) - test = MUSB_TEST_K; - - if (!strncmp(buf, "test J", 6)) - test = MUSB_TEST_J; - - if (!strncmp(buf, "test SE0 NAK", 12)) - test = MUSB_TEST_SE0_NAK; - - musb_writeb(musb->mregs, MUSB_TESTMODE, test); - - return count; -} - -static const struct file_operations musb_test_mode_fops = { - .open = musb_test_mode_open, - .write = musb_test_mode_write, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -int __devinit musb_init_debugfs(struct musb *musb) -{ - struct dentry *root; - struct dentry *file; - int ret; - - root = debugfs_create_dir("musb", NULL); - if (!root) { - ret = -ENOMEM; - goto err0; - } - - file = debugfs_create_file("regdump", S_IRUGO, root, musb, - &musb_regdump_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, - root, musb, &musb_test_mode_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } - - musb_debugfs_root = root; - - return 0; - -err1: - debugfs_remove_recursive(root); - -err0: - return ret; -} - -void /* __init_or_exit */ musb_exit_debugfs(struct musb *musb) -{ - debugfs_remove_recursive(musb_debugfs_root); -} diff --git a/ANDROID_3.4.5/drivers/usb/musb/musb_dma.h b/ANDROID_3.4.5/drivers/usb/musb/musb_dma.h deleted file mode 100644 index 3a97c4e2..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/musb_dma.h +++ /dev/null @@ -1,186 +0,0 @@ -/* - * MUSB OTG driver DMA controller abstraction - * - * Copyright 2005 Mentor Graphics Corporation - * Copyright (C) 2005-2006 by Texas Instruments - * Copyright (C) 2006-2007 Nokia Corporation - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef __MUSB_DMA_H__ -#define __MUSB_DMA_H__ - -struct musb_hw_ep; - -/* - * DMA Controller Abstraction - * - * DMA Controllers are abstracted to allow use of a variety of different - * implementations of DMA, as allowed by the Inventra USB cores. On the - * host side, usbcore sets up the DMA mappings and flushes caches; on the - * peripheral side, the gadget controller driver does. Responsibilities - * of a DMA controller driver include: - * - * - Handling the details of moving multiple USB packets - * in cooperation with the Inventra USB core, including especially - * the correct RX side treatment of short packets and buffer-full - * states (both of which terminate transfers). - * - * - Knowing the correlation between dma channels and the - * Inventra core's local endpoint resources and data direction. - * - * - Maintaining a list of allocated/available channels. - * - * - Updating channel status on interrupts, - * whether shared with the Inventra core or separate. - */ - -#define DMA_ADDR_INVALID (~(dma_addr_t)0) - -#ifndef CONFIG_MUSB_PIO_ONLY -#define is_dma_capable() (1) -#else -#define is_dma_capable() (0) -#endif - -#ifdef CONFIG_USB_TI_CPPI_DMA -#define is_cppi_enabled() 1 -#else -#define is_cppi_enabled() 0 -#endif - -#ifdef CONFIG_USB_TUSB_OMAP_DMA -#define tusb_dma_omap() 1 -#else -#define tusb_dma_omap() 0 -#endif - -/* Anomaly 05000456 - USB Receive Interrupt Is Not Generated in DMA Mode 1 - * Only allow DMA mode 1 to be used when the USB will actually generate the - * interrupts we expect. - */ -#ifdef CONFIG_BLACKFIN -# undef USE_MODE1 -# if !ANOMALY_05000456 -# define USE_MODE1 -# endif -#endif - -/* - * DMA channel status ... updated by the dma controller driver whenever that - * status changes, and protected by the overall controller spinlock. - */ -enum dma_channel_status { - /* unallocated */ - MUSB_DMA_STATUS_UNKNOWN, - /* allocated ... but not busy, no errors */ - MUSB_DMA_STATUS_FREE, - /* busy ... transactions are active */ - MUSB_DMA_STATUS_BUSY, - /* transaction(s) aborted due to ... dma or memory bus error */ - MUSB_DMA_STATUS_BUS_ABORT, - /* transaction(s) aborted due to ... core error or USB fault */ - MUSB_DMA_STATUS_CORE_ABORT -}; - -struct dma_controller; - -/** - * struct dma_channel - A DMA channel. - * @private_data: channel-private data - * @max_len: the maximum number of bytes the channel can move in one - * transaction (typically representing many USB maximum-sized packets) - * @actual_len: how many bytes have been transferred - * @status: current channel status (updated e.g. on interrupt) - * @desired_mode: true if mode 1 is desired; false if mode 0 is desired - * - * channels are associated with an endpoint for the duration of at least - * one usb transfer. - */ -struct dma_channel { - void *private_data; - /* FIXME not void* private_data, but a dma_controller * */ - size_t max_len; - size_t actual_len; - enum dma_channel_status status; - bool desired_mode; -}; - -/* - * dma_channel_status - return status of dma channel - * @c: the channel - * - * Returns the software's view of the channel status. If that status is BUSY - * then it's possible that the hardware has completed (or aborted) a transfer, - * so the driver needs to update that status. - */ -static inline enum dma_channel_status -dma_channel_status(struct dma_channel *c) -{ - return (is_dma_capable() && c) ? c->status : MUSB_DMA_STATUS_UNKNOWN; -} - -/** - * struct dma_controller - A DMA Controller. - * @start: call this to start a DMA controller; - * return 0 on success, else negative errno - * @stop: call this to stop a DMA controller - * return 0 on success, else negative errno - * @channel_alloc: call this to allocate a DMA channel - * @channel_release: call this to release a DMA channel - * @channel_abort: call this to abort a pending DMA transaction, - * returning it to FREE (but allocated) state - * - * Controllers manage dma channels. - */ -struct dma_controller { - int (*start)(struct dma_controller *); - int (*stop)(struct dma_controller *); - struct dma_channel *(*channel_alloc)(struct dma_controller *, - struct musb_hw_ep *, u8 is_tx); - void (*channel_release)(struct dma_channel *); - int (*channel_program)(struct dma_channel *channel, - u16 maxpacket, u8 mode, - dma_addr_t dma_addr, - u32 length); - int (*channel_abort)(struct dma_channel *); - int (*is_compatible)(struct dma_channel *channel, - u16 maxpacket, - void *buf, u32 length); -}; - -/* called after channel_program(), may indicate a fault */ -extern void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit); - - -extern struct dma_controller *__init -dma_controller_create(struct musb *, void __iomem *); - -extern void dma_controller_destroy(struct dma_controller *); - -#endif /* __MUSB_DMA_H__ */ diff --git a/ANDROID_3.4.5/drivers/usb/musb/musb_gadget.c b/ANDROID_3.4.5/drivers/usb/musb/musb_gadget.c deleted file mode 100644 index 95918dac..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/musb_gadget.c +++ /dev/null @@ -1,2239 +0,0 @@ -/* - * MUSB OTG driver peripheral support - * - * Copyright 2005 Mentor Graphics Corporation - * Copyright (C) 2005-2006 by Texas Instruments - * Copyright (C) 2006-2007 Nokia Corporation - * Copyright (C) 2009 MontaVista Software, Inc. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "musb_core.h" - - -/* MUSB PERIPHERAL status 3-mar-2006: - * - * - EP0 seems solid. It passes both USBCV and usbtest control cases. - * Minor glitches: - * - * + remote wakeup to Linux hosts work, but saw USBCV failures; - * in one test run (operator error?) - * + endpoint halt tests -- in both usbtest and usbcv -- seem - * to break when dma is enabled ... is something wrongly - * clearing SENDSTALL? - * - * - Mass storage behaved ok when last tested. Network traffic patterns - * (with lots of short transfers etc) need retesting; they turn up the - * worst cases of the DMA, since short packets are typical but are not - * required. - * - * - TX/IN - * + both pio and dma behave in with network and g_zero tests - * + no cppi throughput issues other than no-hw-queueing - * + failed with FLAT_REG (DaVinci) - * + seems to behave with double buffering, PIO -and- CPPI - * + with gadgetfs + AIO, requests got lost? - * - * - RX/OUT - * + both pio and dma behave in with network and g_zero tests - * + dma is slow in typical case (short_not_ok is clear) - * + double buffering ok with PIO - * + double buffering *FAILS* with CPPI, wrong data bytes sometimes - * + request lossage observed with gadgetfs - * - * - ISO not tested ... might work, but only weakly isochronous - * - * - Gadget driver disabling of softconnect during bind() is ignored; so - * drivers can't hold off host requests until userspace is ready. - * (Workaround: they can turn it off later.) - * - * - PORTABILITY (assumes PIO works): - * + DaVinci, basically works with cppi dma - * + OMAP 2430, ditto with mentor dma - * + TUSB 6010, platform-specific dma in the works - */ - -/* ----------------------------------------------------------------------- */ - -#define is_buffer_mapped(req) (is_dma_capable() && \ - (req->map_state != UN_MAPPED)) - -/* Maps the buffer to dma */ - -static inline void map_dma_buffer(struct musb_request *request, - struct musb *musb, struct musb_ep *musb_ep) -{ - int compatible = true; - struct dma_controller *dma = musb->dma_controller; - - request->map_state = UN_MAPPED; - - if (!is_dma_capable() || !musb_ep->dma) - return; - - /* Check if DMA engine can handle this request. - * DMA code must reject the USB request explicitly. - * Default behaviour is to map the request. - */ - if (dma->is_compatible) - compatible = dma->is_compatible(musb_ep->dma, - musb_ep->packet_sz, request->request.buf, - request->request.length); - if (!compatible) - return; - - if (request->request.dma == DMA_ADDR_INVALID) { - request->request.dma = dma_map_single( - musb->controller, - request->request.buf, - request->request.length, - request->tx - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - request->map_state = MUSB_MAPPED; - } else { - dma_sync_single_for_device(musb->controller, - request->request.dma, - request->request.length, - request->tx - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - request->map_state = PRE_MAPPED; - } -} - -/* Unmap the buffer from dma and maps it back to cpu */ -static inline void unmap_dma_buffer(struct musb_request *request, - struct musb *musb) -{ - if (!is_buffer_mapped(request)) - return; - - if (request->request.dma == DMA_ADDR_INVALID) { - dev_vdbg(musb->controller, - "not unmapping a never mapped buffer\n"); - return; - } - if (request->map_state == MUSB_MAPPED) { - dma_unmap_single(musb->controller, - request->request.dma, - request->request.length, - request->tx - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - request->request.dma = DMA_ADDR_INVALID; - } else { /* PRE_MAPPED */ - dma_sync_single_for_cpu(musb->controller, - request->request.dma, - request->request.length, - request->tx - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - } - request->map_state = UN_MAPPED; -} - -/* - * Immediately complete a request. - * - * @param request the request to complete - * @param status the status to complete the request with - * Context: controller locked, IRQs blocked. - */ -void musb_g_giveback( - struct musb_ep *ep, - struct usb_request *request, - int status) -__releases(ep->musb->lock) -__acquires(ep->musb->lock) -{ - struct musb_request *req; - struct musb *musb; - int busy = ep->busy; - - req = to_musb_request(request); - - list_del(&req->list); - if (req->request.status == -EINPROGRESS) - req->request.status = status; - musb = req->musb; - - ep->busy = 1; - spin_unlock(&musb->lock); - unmap_dma_buffer(req, musb); - if (request->status == 0) - dev_dbg(musb->controller, "%s done request %p, %d/%d\n", - ep->end_point.name, request, - req->request.actual, req->request.length); - else - dev_dbg(musb->controller, "%s request %p, %d/%d fault %d\n", - ep->end_point.name, request, - req->request.actual, req->request.length, - request->status); - req->request.complete(&req->ep->end_point, &req->request); - spin_lock(&musb->lock); - ep->busy = busy; -} - -/* ----------------------------------------------------------------------- */ - -/* - * Abort requests queued to an endpoint using the status. Synchronous. - * caller locked controller and blocked irqs, and selected this ep. - */ -static void nuke(struct musb_ep *ep, const int status) -{ - struct musb *musb = ep->musb; - struct musb_request *req = NULL; - void __iomem *epio = ep->musb->endpoints[ep->current_epnum].regs; - - ep->busy = 1; - - if (is_dma_capable() && ep->dma) { - struct dma_controller *c = ep->musb->dma_controller; - int value; - - if (ep->is_in) { - /* - * The programming guide says that we must not clear - * the DMAMODE bit before DMAENAB, so we only - * clear it in the second write... - */ - musb_writew(epio, MUSB_TXCSR, - MUSB_TXCSR_DMAMODE | MUSB_TXCSR_FLUSHFIFO); - musb_writew(epio, MUSB_TXCSR, - 0 | MUSB_TXCSR_FLUSHFIFO); - } else { - musb_writew(epio, MUSB_RXCSR, - 0 | MUSB_RXCSR_FLUSHFIFO); - musb_writew(epio, MUSB_RXCSR, - 0 | MUSB_RXCSR_FLUSHFIFO); - } - - value = c->channel_abort(ep->dma); - dev_dbg(musb->controller, "%s: abort DMA --> %d\n", - ep->name, value); - c->channel_release(ep->dma); - ep->dma = NULL; - } - - while (!list_empty(&ep->req_list)) { - req = list_first_entry(&ep->req_list, struct musb_request, list); - musb_g_giveback(ep, &req->request, status); - } -} - -/* ----------------------------------------------------------------------- */ - -/* Data transfers - pure PIO, pure DMA, or mixed mode */ - -/* - * This assumes the separate CPPI engine is responding to DMA requests - * from the usb core ... sequenced a bit differently from mentor dma. - */ - -static inline int max_ep_writesize(struct musb *musb, struct musb_ep *ep) -{ - if (can_bulk_split(musb, ep->type)) - return ep->hw_ep->max_packet_sz_tx; - else - return ep->packet_sz; -} - - -#ifdef CONFIG_USB_INVENTRA_DMA - -/* Peripheral tx (IN) using Mentor DMA works as follows: - Only mode 0 is used for transfers <= wPktSize, - mode 1 is used for larger transfers, - - One of the following happens: - - Host sends IN token which causes an endpoint interrupt - -> TxAvail - -> if DMA is currently busy, exit. - -> if queue is non-empty, txstate(). - - - Request is queued by the gadget driver. - -> if queue was previously empty, txstate() - - txstate() - -> start - /\ -> setup DMA - | (data is transferred to the FIFO, then sent out when - | IN token(s) are recd from Host. - | -> DMA interrupt on completion - | calls TxAvail. - | -> stop DMA, ~DMAENAB, - | -> set TxPktRdy for last short pkt or zlp - | -> Complete Request - | -> Continue next request (call txstate) - |___________________________________| - - * Non-Mentor DMA engines can of course work differently, such as by - * upleveling from irq-per-packet to irq-per-buffer. - */ - -#endif - -/* - * An endpoint is transmitting data. This can be called either from - * the IRQ routine or from ep.queue() to kickstart a request on an - * endpoint. - * - * Context: controller locked, IRQs blocked, endpoint selected - */ -static void txstate(struct musb *musb, struct musb_request *req) -{ - u8 epnum = req->epnum; - struct musb_ep *musb_ep; - void __iomem *epio = musb->endpoints[epnum].regs; - struct usb_request *request; - u16 fifo_count = 0, csr; - int use_dma = 0; - - musb_ep = req->ep; - - /* we shouldn't get here while DMA is active ... but we do ... */ - if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) { - dev_dbg(musb->controller, "dma pending...\n"); - return; - } - - /* read TXCSR before */ - csr = musb_readw(epio, MUSB_TXCSR); - - request = &req->request; - fifo_count = min(max_ep_writesize(musb, musb_ep), - (int)(request->length - request->actual)); - - if (csr & MUSB_TXCSR_TXPKTRDY) { - dev_dbg(musb->controller, "%s old packet still ready , txcsr %03x\n", - musb_ep->end_point.name, csr); - return; - } - - if (csr & MUSB_TXCSR_P_SENDSTALL) { - dev_dbg(musb->controller, "%s stalling, txcsr %03x\n", - musb_ep->end_point.name, csr); - return; - } - - dev_dbg(musb->controller, "hw_ep%d, maxpacket %d, fifo count %d, txcsr %03x\n", - epnum, musb_ep->packet_sz, fifo_count, - csr); - -#ifndef CONFIG_MUSB_PIO_ONLY - if (is_buffer_mapped(req)) { - struct dma_controller *c = musb->dma_controller; - size_t request_size; - - /* setup DMA, then program endpoint CSR */ - request_size = min_t(size_t, request->length - request->actual, - musb_ep->dma->max_len); - - use_dma = (request->dma != DMA_ADDR_INVALID); - - /* MUSB_TXCSR_P_ISO is still set correctly */ - -#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) - { - if (request_size < musb_ep->packet_sz) - musb_ep->dma->desired_mode = 0; - else - musb_ep->dma->desired_mode = 1; - - use_dma = use_dma && c->channel_program( - musb_ep->dma, musb_ep->packet_sz, - musb_ep->dma->desired_mode, - request->dma + request->actual, request_size); - if (use_dma) { - if (musb_ep->dma->desired_mode == 0) { - /* - * We must not clear the DMAMODE bit - * before the DMAENAB bit -- and the - * latter doesn't always get cleared - * before we get here... - */ - csr &= ~(MUSB_TXCSR_AUTOSET - | MUSB_TXCSR_DMAENAB); - musb_writew(epio, MUSB_TXCSR, csr - | MUSB_TXCSR_P_WZC_BITS); - csr &= ~MUSB_TXCSR_DMAMODE; - csr |= (MUSB_TXCSR_DMAENAB | - MUSB_TXCSR_MODE); - /* against programming guide */ - } else { - csr |= (MUSB_TXCSR_DMAENAB - | MUSB_TXCSR_DMAMODE - | MUSB_TXCSR_MODE); - if (!musb_ep->hb_mult) - csr |= MUSB_TXCSR_AUTOSET; - } - csr &= ~MUSB_TXCSR_P_UNDERRUN; - - musb_writew(epio, MUSB_TXCSR, csr); - } - } - -#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_DMAENAB | MUSB_TXCSR_DMAMODE | - MUSB_TXCSR_MODE; - musb_writew(epio, MUSB_TXCSR, - (MUSB_TXCSR_P_WZC_BITS & ~MUSB_TXCSR_P_UNDERRUN) - | csr); - - /* ensure writebuffer is empty */ - csr = musb_readw(epio, MUSB_TXCSR); - - /* NOTE host side sets DMAENAB later than this; both are - * OK since the transfer dma glue (between CPPI and Mentor - * fifos) just tells CPPI it could start. Data only moves - * to the USB TX fifo when both fifos are ready. - */ - - /* "mode" is irrelevant here; handle terminating ZLPs like - * PIO does, since the hardware RNDIS mode seems unreliable - * except for the last-packet-is-already-short case. - */ - use_dma = use_dma && c->channel_program( - musb_ep->dma, musb_ep->packet_sz, - 0, - request->dma + request->actual, - request_size); - if (!use_dma) { - c->channel_release(musb_ep->dma); - musb_ep->dma = NULL; - csr &= ~MUSB_TXCSR_DMAENAB; - musb_writew(epio, MUSB_TXCSR, csr); - /* invariant: prequest->buf is non-null */ - } -#elif defined(CONFIG_USB_TUSB_OMAP_DMA) - use_dma = use_dma && c->channel_program( - musb_ep->dma, musb_ep->packet_sz, - request->zero, - request->dma + request->actual, - request_size); -#endif - } -#endif - - if (!use_dma) { - /* - * Unmap the dma buffer back to cpu if dma channel - * programming fails - */ - unmap_dma_buffer(req, musb); - - musb_write_fifo(musb_ep->hw_ep, fifo_count, - (u8 *) (request->buf + request->actual)); - request->actual += fifo_count; - csr |= MUSB_TXCSR_TXPKTRDY; - csr &= ~MUSB_TXCSR_P_UNDERRUN; - musb_writew(epio, MUSB_TXCSR, csr); - } - - /* host may already have the data when this message shows... */ - dev_dbg(musb->controller, "%s TX/IN %s len %d/%d, txcsr %04x, fifo %d/%d\n", - musb_ep->end_point.name, use_dma ? "dma" : "pio", - request->actual, request->length, - musb_readw(epio, MUSB_TXCSR), - fifo_count, - musb_readw(epio, MUSB_TXMAXP)); -} - -/* - * FIFO state update (e.g. data ready). - * Called from IRQ, with controller locked. - */ -void musb_g_tx(struct musb *musb, u8 epnum) -{ - u16 csr; - struct musb_request *req; - struct usb_request *request; - u8 __iomem *mbase = musb->mregs; - struct musb_ep *musb_ep = &musb->endpoints[epnum].ep_in; - void __iomem *epio = musb->endpoints[epnum].regs; - struct dma_channel *dma; - - musb_ep_select(mbase, epnum); - req = next_request(musb_ep); - request = &req->request; - - csr = musb_readw(epio, MUSB_TXCSR); - dev_dbg(musb->controller, "<== %s, txcsr %04x\n", musb_ep->end_point.name, csr); - - dma = is_dma_capable() ? musb_ep->dma : NULL; - - /* - * REVISIT: for high bandwidth, MUSB_TXCSR_P_INCOMPTX - * probably rates reporting as a host error. - */ - if (csr & MUSB_TXCSR_P_SENTSTALL) { - csr |= MUSB_TXCSR_P_WZC_BITS; - csr &= ~MUSB_TXCSR_P_SENTSTALL; - musb_writew(epio, MUSB_TXCSR, csr); - return; - } - - if (csr & MUSB_TXCSR_P_UNDERRUN) { - /* We NAKed, no big deal... little reason to care. */ - csr |= MUSB_TXCSR_P_WZC_BITS; - csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY); - musb_writew(epio, MUSB_TXCSR, csr); - dev_vdbg(musb->controller, "underrun on ep%d, req %p\n", - epnum, request); - } - - if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { - /* - * SHOULD NOT HAPPEN... has with CPPI though, after - * changing SENDSTALL (and other cases); harmless? - */ - dev_dbg(musb->controller, "%s dma still busy?\n", musb_ep->end_point.name); - return; - } - - if (request) { - u8 is_dma = 0; - - if (dma && (csr & MUSB_TXCSR_DMAENAB)) { - is_dma = 1; - csr |= MUSB_TXCSR_P_WZC_BITS; - csr &= ~(MUSB_TXCSR_DMAENAB | MUSB_TXCSR_P_UNDERRUN | - MUSB_TXCSR_TXPKTRDY | MUSB_TXCSR_AUTOSET); - musb_writew(epio, MUSB_TXCSR, csr); - /* Ensure writebuffer is empty. */ - csr = musb_readw(epio, MUSB_TXCSR); - request->actual += musb_ep->dma->actual_len; - dev_dbg(musb->controller, "TXCSR%d %04x, DMA off, len %zu, req %p\n", - epnum, csr, musb_ep->dma->actual_len, request); - } - - /* - * First, maybe a terminating short packet. Some DMA - * engines might handle this by themselves. - */ - if ((request->zero && request->length - && (request->length % musb_ep->packet_sz == 0) - && (request->actual == request->length)) -#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) - || (is_dma && (!dma->desired_mode || - (request->actual & - (musb_ep->packet_sz - 1)))) -#endif - ) { - /* - * On DMA completion, FIFO may not be - * available yet... - */ - if (csr & MUSB_TXCSR_TXPKTRDY) - return; - - dev_dbg(musb->controller, "sending zero pkt\n"); - musb_writew(epio, MUSB_TXCSR, MUSB_TXCSR_MODE - | MUSB_TXCSR_TXPKTRDY); - request->zero = 0; - } - - if (request->actual == request->length) { - musb_g_giveback(musb_ep, request, 0); - /* - * In the giveback function the MUSB lock is - * released and acquired after sometime. During - * this time period the INDEX register could get - * changed by the gadget_queue function especially - * on SMP systems. Reselect the INDEX to be sure - * we are reading/modifying the right registers - */ - musb_ep_select(mbase, epnum); - req = musb_ep->desc ? next_request(musb_ep) : NULL; - if (!req) { - dev_dbg(musb->controller, "%s idle now\n", - musb_ep->end_point.name); - return; - } - } - - txstate(musb, req); - } -} - -/* ------------------------------------------------------------ */ - -#ifdef CONFIG_USB_INVENTRA_DMA - -/* Peripheral rx (OUT) using Mentor DMA works as follows: - - Only mode 0 is used. - - - Request is queued by the gadget class driver. - -> if queue was previously empty, rxstate() - - - Host sends OUT token which causes an endpoint interrupt - /\ -> RxReady - | -> if request queued, call rxstate - | /\ -> setup DMA - | | -> DMA interrupt on completion - | | -> RxReady - | | -> stop DMA - | | -> ack the read - | | -> if data recd = max expected - | | by the request, or host - | | sent a short packet, - | | complete the request, - | | and start the next one. - | |_____________________________________| - | else just wait for the host - | to send the next OUT token. - |__________________________________________________| - - * Non-Mentor DMA engines can of course work differently. - */ - -#endif - -/* - * Context: controller locked, IRQs blocked, endpoint selected - */ -static void rxstate(struct musb *musb, struct musb_request *req) -{ - const u8 epnum = req->epnum; - struct usb_request *request = &req->request; - struct musb_ep *musb_ep; - void __iomem *epio = musb->endpoints[epnum].regs; - unsigned fifo_count = 0; - u16 len; - u16 csr = musb_readw(epio, MUSB_RXCSR); - struct musb_hw_ep *hw_ep = &musb->endpoints[epnum]; - u8 use_mode_1; - - if (hw_ep->is_shared_fifo) - musb_ep = &hw_ep->ep_in; - else - musb_ep = &hw_ep->ep_out; - - len = musb_ep->packet_sz; - - /* We shouldn't get here while DMA is active, but we do... */ - if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) { - dev_dbg(musb->controller, "DMA pending...\n"); - return; - } - - if (csr & MUSB_RXCSR_P_SENDSTALL) { - dev_dbg(musb->controller, "%s stalling, RXCSR %04x\n", - musb_ep->end_point.name, csr); - return; - } - - if (is_cppi_enabled() && is_buffer_mapped(req)) { - struct dma_controller *c = musb->dma_controller; - struct dma_channel *channel = musb_ep->dma; - - /* NOTE: CPPI won't actually stop advancing the DMA - * queue after short packet transfers, so this is almost - * always going to run as IRQ-per-packet DMA so that - * faults will be handled correctly. - */ - if (c->channel_program(channel, - musb_ep->packet_sz, - !request->short_not_ok, - request->dma + request->actual, - request->length - request->actual)) { - - /* make sure that if an rxpkt arrived after the irq, - * the cppi engine will be ready to take it as soon - * as DMA is enabled - */ - csr &= ~(MUSB_RXCSR_AUTOCLEAR - | MUSB_RXCSR_DMAMODE); - csr |= MUSB_RXCSR_DMAENAB | MUSB_RXCSR_P_WZC_BITS; - musb_writew(epio, MUSB_RXCSR, csr); - return; - } - } - - if (csr & MUSB_RXCSR_RXPKTRDY) { - len = musb_readw(epio, MUSB_RXCOUNT); - - /* - * Enable Mode 1 on RX transfers only when short_not_ok flag - * is set. Currently short_not_ok flag is set only from - * file_storage and f_mass_storage drivers - */ - - if (request->short_not_ok && len == musb_ep->packet_sz) - use_mode_1 = 1; - else - use_mode_1 = 0; - - if (request->actual < request->length) { -#ifdef CONFIG_USB_INVENTRA_DMA - if (is_buffer_mapped(req)) { - struct dma_controller *c; - struct dma_channel *channel; - int use_dma = 0; - - c = musb->dma_controller; - channel = musb_ep->dma; - - /* We use DMA Req mode 0 in rx_csr, and DMA controller operates in - * mode 0 only. So we do not get endpoint interrupts due to DMA - * completion. We only get interrupts from DMA controller. - * - * We could operate in DMA mode 1 if we knew the size of the tranfer - * in advance. For mass storage class, request->length = what the host - * sends, so that'd work. But for pretty much everything else, - * request->length is routinely more than what the host sends. For - * most these gadgets, end of is signified either by a short packet, - * or filling the last byte of the buffer. (Sending extra data in - * that last pckate should trigger an overflow fault.) But in mode 1, - * we don't get DMA completion interrupt for short packets. - * - * Theoretically, we could enable DMAReq irq (MUSB_RXCSR_DMAMODE = 1), - * to get endpoint interrupt on every DMA req, but that didn't seem - * to work reliably. - * - * REVISIT an updated g_file_storage can set req->short_not_ok, which - * then becomes usable as a runtime "use mode 1" hint... - */ - - /* Experimental: Mode1 works with mass storage use cases */ - if (use_mode_1) { - csr |= MUSB_RXCSR_AUTOCLEAR; - musb_writew(epio, MUSB_RXCSR, csr); - csr |= MUSB_RXCSR_DMAENAB; - musb_writew(epio, MUSB_RXCSR, csr); - - /* - * this special sequence (enabling and then - * disabling MUSB_RXCSR_DMAMODE) is required - * to get DMAReq to activate - */ - musb_writew(epio, MUSB_RXCSR, - csr | MUSB_RXCSR_DMAMODE); - musb_writew(epio, MUSB_RXCSR, csr); - - } else { - if (!musb_ep->hb_mult && - musb_ep->hw_ep->rx_double_buffered) - csr |= MUSB_RXCSR_AUTOCLEAR; - csr |= MUSB_RXCSR_DMAENAB; - musb_writew(epio, MUSB_RXCSR, csr); - } - - if (request->actual < request->length) { - int transfer_size = 0; - if (use_mode_1) { - transfer_size = min(request->length - request->actual, - channel->max_len); - musb_ep->dma->desired_mode = 1; - } else { - transfer_size = min(request->length - request->actual, - (unsigned)len); - musb_ep->dma->desired_mode = 0; - } - - use_dma = c->channel_program( - channel, - musb_ep->packet_sz, - channel->desired_mode, - request->dma - + request->actual, - transfer_size); - } - - if (use_dma) - return; - } -#elif defined(CONFIG_USB_UX500_DMA) - if ((is_buffer_mapped(req)) && - (request->actual < request->length)) { - - struct dma_controller *c; - struct dma_channel *channel; - int transfer_size = 0; - - c = musb->dma_controller; - channel = musb_ep->dma; - - /* In case first packet is short */ - if (len < musb_ep->packet_sz) - transfer_size = len; - else if (request->short_not_ok) - transfer_size = min(request->length - - request->actual, - channel->max_len); - else - transfer_size = min(request->length - - request->actual, - (unsigned)len); - - csr &= ~MUSB_RXCSR_DMAMODE; - csr |= (MUSB_RXCSR_DMAENAB | - MUSB_RXCSR_AUTOCLEAR); - - musb_writew(epio, MUSB_RXCSR, csr); - - if (transfer_size <= musb_ep->packet_sz) { - musb_ep->dma->desired_mode = 0; - } else { - musb_ep->dma->desired_mode = 1; - /* Mode must be set after DMAENAB */ - csr |= MUSB_RXCSR_DMAMODE; - musb_writew(epio, MUSB_RXCSR, csr); - } - - if (c->channel_program(channel, - musb_ep->packet_sz, - channel->desired_mode, - request->dma - + request->actual, - transfer_size)) - - return; - } -#endif /* Mentor's DMA */ - - fifo_count = request->length - request->actual; - dev_dbg(musb->controller, "%s OUT/RX pio fifo %d/%d, maxpacket %d\n", - musb_ep->end_point.name, - len, fifo_count, - musb_ep->packet_sz); - - fifo_count = min_t(unsigned, len, fifo_count); - -#ifdef CONFIG_USB_TUSB_OMAP_DMA - if (tusb_dma_omap() && is_buffer_mapped(req)) { - struct dma_controller *c = musb->dma_controller; - struct dma_channel *channel = musb_ep->dma; - u32 dma_addr = request->dma + request->actual; - int ret; - - ret = c->channel_program(channel, - musb_ep->packet_sz, - channel->desired_mode, - dma_addr, - fifo_count); - if (ret) - return; - } -#endif - /* - * Unmap the dma buffer back to cpu if dma channel - * programming fails. This buffer is mapped if the - * channel allocation is successful - */ - if (is_buffer_mapped(req)) { - unmap_dma_buffer(req, musb); - - /* - * Clear DMAENAB and AUTOCLEAR for the - * PIO mode transfer - */ - csr &= ~(MUSB_RXCSR_DMAENAB | MUSB_RXCSR_AUTOCLEAR); - musb_writew(epio, MUSB_RXCSR, csr); - } - - musb_read_fifo(musb_ep->hw_ep, fifo_count, (u8 *) - (request->buf + request->actual)); - request->actual += fifo_count; - - /* REVISIT if we left anything in the fifo, flush - * it and report -EOVERFLOW - */ - - /* ack the read! */ - csr |= MUSB_RXCSR_P_WZC_BITS; - csr &= ~MUSB_RXCSR_RXPKTRDY; - musb_writew(epio, MUSB_RXCSR, csr); - } - } - - /* reach the end or short packet detected */ - if (request->actual == request->length || len < musb_ep->packet_sz) - musb_g_giveback(musb_ep, request, 0); -} - -/* - * Data ready for a request; called from IRQ - */ -void musb_g_rx(struct musb *musb, u8 epnum) -{ - u16 csr; - struct musb_request *req; - struct usb_request *request; - void __iomem *mbase = musb->mregs; - struct musb_ep *musb_ep; - void __iomem *epio = musb->endpoints[epnum].regs; - struct dma_channel *dma; - struct musb_hw_ep *hw_ep = &musb->endpoints[epnum]; - - if (hw_ep->is_shared_fifo) - musb_ep = &hw_ep->ep_in; - else - musb_ep = &hw_ep->ep_out; - - musb_ep_select(mbase, epnum); - - req = next_request(musb_ep); - if (!req) - return; - - request = &req->request; - - csr = musb_readw(epio, MUSB_RXCSR); - dma = is_dma_capable() ? musb_ep->dma : NULL; - - dev_dbg(musb->controller, "<== %s, rxcsr %04x%s %p\n", musb_ep->end_point.name, - csr, dma ? " (dma)" : "", request); - - if (csr & MUSB_RXCSR_P_SENTSTALL) { - csr |= MUSB_RXCSR_P_WZC_BITS; - csr &= ~MUSB_RXCSR_P_SENTSTALL; - musb_writew(epio, MUSB_RXCSR, csr); - return; - } - - if (csr & MUSB_RXCSR_P_OVERRUN) { - /* csr |= MUSB_RXCSR_P_WZC_BITS; */ - csr &= ~MUSB_RXCSR_P_OVERRUN; - musb_writew(epio, MUSB_RXCSR, csr); - - dev_dbg(musb->controller, "%s iso overrun on %p\n", musb_ep->name, request); - if (request->status == -EINPROGRESS) - request->status = -EOVERFLOW; - } - if (csr & MUSB_RXCSR_INCOMPRX) { - /* REVISIT not necessarily an error */ - dev_dbg(musb->controller, "%s, incomprx\n", musb_ep->end_point.name); - } - - if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { - /* "should not happen"; likely RXPKTRDY pending for DMA */ - dev_dbg(musb->controller, "%s busy, csr %04x\n", - musb_ep->end_point.name, csr); - return; - } - - if (dma && (csr & MUSB_RXCSR_DMAENAB)) { - csr &= ~(MUSB_RXCSR_AUTOCLEAR - | MUSB_RXCSR_DMAENAB - | MUSB_RXCSR_DMAMODE); - musb_writew(epio, MUSB_RXCSR, - MUSB_RXCSR_P_WZC_BITS | csr); - - request->actual += musb_ep->dma->actual_len; - - dev_dbg(musb->controller, "RXCSR%d %04x, dma off, %04x, len %zu, req %p\n", - epnum, csr, - musb_readw(epio, MUSB_RXCSR), - musb_ep->dma->actual_len, request); - -#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA) || \ - defined(CONFIG_USB_UX500_DMA) - /* Autoclear doesn't clear RxPktRdy for short packets */ - if ((dma->desired_mode == 0 && !hw_ep->rx_double_buffered) - || (dma->actual_len - & (musb_ep->packet_sz - 1))) { - /* ack the read! */ - csr &= ~MUSB_RXCSR_RXPKTRDY; - musb_writew(epio, MUSB_RXCSR, csr); - } - - /* incomplete, and not short? wait for next IN packet */ - if ((request->actual < request->length) - && (musb_ep->dma->actual_len - == musb_ep->packet_sz)) { - /* In double buffer case, continue to unload fifo if - * there is Rx packet in FIFO. - **/ - csr = musb_readw(epio, MUSB_RXCSR); - if ((csr & MUSB_RXCSR_RXPKTRDY) && - hw_ep->rx_double_buffered) - goto exit; - return; - } -#endif - musb_g_giveback(musb_ep, request, 0); - /* - * In the giveback function the MUSB lock is - * released and acquired after sometime. During - * this time period the INDEX register could get - * changed by the gadget_queue function especially - * on SMP systems. Reselect the INDEX to be sure - * we are reading/modifying the right registers - */ - musb_ep_select(mbase, epnum); - - req = next_request(musb_ep); - if (!req) - return; - } -#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_TUSB_OMAP_DMA) || \ - defined(CONFIG_USB_UX500_DMA) -exit: -#endif - /* Analyze request */ - rxstate(musb, req); -} - -/* ------------------------------------------------------------ */ - -static int musb_gadget_enable(struct usb_ep *ep, - const struct usb_endpoint_descriptor *desc) -{ - unsigned long flags; - struct musb_ep *musb_ep; - struct musb_hw_ep *hw_ep; - void __iomem *regs; - struct musb *musb; - void __iomem *mbase; - u8 epnum; - u16 csr; - unsigned tmp; - int status = -EINVAL; - - if (!ep || !desc) - return -EINVAL; - - musb_ep = to_musb_ep(ep); - hw_ep = musb_ep->hw_ep; - regs = hw_ep->regs; - musb = musb_ep->musb; - mbase = musb->mregs; - epnum = musb_ep->current_epnum; - - spin_lock_irqsave(&musb->lock, flags); - - if (musb_ep->desc) { - status = -EBUSY; - goto fail; - } - musb_ep->type = usb_endpoint_type(desc); - - /* check direction and (later) maxpacket size against endpoint */ - if (usb_endpoint_num(desc) != epnum) - goto fail; - - /* REVISIT this rules out high bandwidth periodic transfers */ - tmp = usb_endpoint_maxp(desc); - if (tmp & ~0x07ff) { - int ok; - - if (usb_endpoint_dir_in(desc)) - ok = musb->hb_iso_tx; - else - ok = musb->hb_iso_rx; - - if (!ok) { - dev_dbg(musb->controller, "no support for high bandwidth ISO\n"); - goto fail; - } - musb_ep->hb_mult = (tmp >> 11) & 3; - } else { - musb_ep->hb_mult = 0; - } - - musb_ep->packet_sz = tmp & 0x7ff; - tmp = musb_ep->packet_sz * (musb_ep->hb_mult + 1); - - /* enable the interrupts for the endpoint, set the endpoint - * packet size (or fail), set the mode, clear the fifo - */ - musb_ep_select(mbase, epnum); - if (usb_endpoint_dir_in(desc)) { - u16 int_txe = musb_readw(mbase, MUSB_INTRTXE); - - if (hw_ep->is_shared_fifo) - musb_ep->is_in = 1; - if (!musb_ep->is_in) - goto fail; - - if (tmp > hw_ep->max_packet_sz_tx) { - dev_dbg(musb->controller, "packet size beyond hardware FIFO size\n"); - goto fail; - } - - int_txe |= (1 << epnum); - musb_writew(mbase, MUSB_INTRTXE, int_txe); - - /* REVISIT if can_bulk_split(), use by updating "tmp"; - * likewise high bandwidth periodic tx - */ - /* Set TXMAXP with the FIFO size of the endpoint - * to disable double buffering mode. - */ - if (musb->double_buffer_not_ok) - musb_writew(regs, MUSB_TXMAXP, hw_ep->max_packet_sz_tx); - else - musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz - | (musb_ep->hb_mult << 11)); - - csr = MUSB_TXCSR_MODE | MUSB_TXCSR_CLRDATATOG; - if (musb_readw(regs, MUSB_TXCSR) - & MUSB_TXCSR_FIFONOTEMPTY) - csr |= MUSB_TXCSR_FLUSHFIFO; - if (musb_ep->type == USB_ENDPOINT_XFER_ISOC) - csr |= MUSB_TXCSR_P_ISO; - - /* set twice in case of double buffering */ - musb_writew(regs, MUSB_TXCSR, csr); - /* REVISIT may be inappropriate w/o FIFONOTEMPTY ... */ - musb_writew(regs, MUSB_TXCSR, csr); - - } else { - u16 int_rxe = musb_readw(mbase, MUSB_INTRRXE); - - if (hw_ep->is_shared_fifo) - musb_ep->is_in = 0; - if (musb_ep->is_in) - goto fail; - - if (tmp > hw_ep->max_packet_sz_rx) { - dev_dbg(musb->controller, "packet size beyond hardware FIFO size\n"); - goto fail; - } - - int_rxe |= (1 << epnum); - musb_writew(mbase, MUSB_INTRRXE, int_rxe); - - /* REVISIT if can_bulk_combine() use by updating "tmp" - * likewise high bandwidth periodic rx - */ - /* Set RXMAXP with the FIFO size of the endpoint - * to disable double buffering mode. - */ - if (musb->double_buffer_not_ok) - musb_writew(regs, MUSB_RXMAXP, hw_ep->max_packet_sz_tx); - else - musb_writew(regs, MUSB_RXMAXP, musb_ep->packet_sz - | (musb_ep->hb_mult << 11)); - - /* force shared fifo to OUT-only mode */ - if (hw_ep->is_shared_fifo) { - csr = musb_readw(regs, MUSB_TXCSR); - csr &= ~(MUSB_TXCSR_MODE | MUSB_TXCSR_TXPKTRDY); - musb_writew(regs, MUSB_TXCSR, csr); - } - - csr = MUSB_RXCSR_FLUSHFIFO | MUSB_RXCSR_CLRDATATOG; - if (musb_ep->type == USB_ENDPOINT_XFER_ISOC) - csr |= MUSB_RXCSR_P_ISO; - else if (musb_ep->type == USB_ENDPOINT_XFER_INT) - csr |= MUSB_RXCSR_DISNYET; - - /* set twice in case of double buffering */ - musb_writew(regs, MUSB_RXCSR, csr); - musb_writew(regs, MUSB_RXCSR, csr); - } - - /* NOTE: all the I/O code _should_ work fine without DMA, in case - * for some reason you run out of channels here. - */ - if (is_dma_capable() && musb->dma_controller) { - struct dma_controller *c = musb->dma_controller; - - musb_ep->dma = c->channel_alloc(c, hw_ep, - (desc->bEndpointAddress & USB_DIR_IN)); - } else - musb_ep->dma = NULL; - - musb_ep->desc = desc; - musb_ep->busy = 0; - musb_ep->wedged = 0; - status = 0; - - pr_debug("%s periph: enabled %s for %s %s, %smaxpacket %d\n", - musb_driver_name, musb_ep->end_point.name, - ({ char *s; switch (musb_ep->type) { - case USB_ENDPOINT_XFER_BULK: s = "bulk"; break; - case USB_ENDPOINT_XFER_INT: s = "int"; break; - default: s = "iso"; break; - }; s; }), - musb_ep->is_in ? "IN" : "OUT", - musb_ep->dma ? "dma, " : "", - musb_ep->packet_sz); - - schedule_work(&musb->irq_work); - -fail: - spin_unlock_irqrestore(&musb->lock, flags); - return status; -} - -/* - * Disable an endpoint flushing all requests queued. - */ -static int musb_gadget_disable(struct usb_ep *ep) -{ - unsigned long flags; - struct musb *musb; - u8 epnum; - struct musb_ep *musb_ep; - void __iomem *epio; - int status = 0; - - musb_ep = to_musb_ep(ep); - musb = musb_ep->musb; - epnum = musb_ep->current_epnum; - epio = musb->endpoints[epnum].regs; - - spin_lock_irqsave(&musb->lock, flags); - musb_ep_select(musb->mregs, epnum); - - /* zero the endpoint sizes */ - if (musb_ep->is_in) { - u16 int_txe = musb_readw(musb->mregs, MUSB_INTRTXE); - int_txe &= ~(1 << epnum); - musb_writew(musb->mregs, MUSB_INTRTXE, int_txe); - musb_writew(epio, MUSB_TXMAXP, 0); - } else { - u16 int_rxe = musb_readw(musb->mregs, MUSB_INTRRXE); - int_rxe &= ~(1 << epnum); - musb_writew(musb->mregs, MUSB_INTRRXE, int_rxe); - musb_writew(epio, MUSB_RXMAXP, 0); - } - - musb_ep->desc = NULL; - musb_ep->end_point.desc = NULL; - - /* abort all pending DMA and requests */ - nuke(musb_ep, -ESHUTDOWN); - - schedule_work(&musb->irq_work); - - spin_unlock_irqrestore(&(musb->lock), flags); - - dev_dbg(musb->controller, "%s\n", musb_ep->end_point.name); - - return status; -} - -/* - * Allocate a request for an endpoint. - * Reused by ep0 code. - */ -struct usb_request *musb_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) -{ - struct musb_ep *musb_ep = to_musb_ep(ep); - struct musb *musb = musb_ep->musb; - struct musb_request *request = NULL; - - request = kzalloc(sizeof *request, gfp_flags); - if (!request) { - dev_dbg(musb->controller, "not enough memory\n"); - return NULL; - } - - request->request.dma = DMA_ADDR_INVALID; - request->epnum = musb_ep->current_epnum; - request->ep = musb_ep; - - return &request->request; -} - -/* - * Free a request - * Reused by ep0 code. - */ -void musb_free_request(struct usb_ep *ep, struct usb_request *req) -{ - kfree(to_musb_request(req)); -} - -static LIST_HEAD(buffers); - -struct free_record { - struct list_head list; - struct device *dev; - unsigned bytes; - dma_addr_t dma; -}; - -/* - * Context: controller locked, IRQs blocked. - */ -void musb_ep_restart(struct musb *musb, struct musb_request *req) -{ - dev_dbg(musb->controller, "<== %s request %p len %u on hw_ep%d\n", - req->tx ? "TX/IN" : "RX/OUT", - &req->request, req->request.length, req->epnum); - - musb_ep_select(musb->mregs, req->epnum); - if (req->tx) - txstate(musb, req); - else - rxstate(musb, req); -} - -static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req, - gfp_t gfp_flags) -{ - struct musb_ep *musb_ep; - struct musb_request *request; - struct musb *musb; - int status = 0; - unsigned long lockflags; - - if (!ep || !req) - return -EINVAL; - if (!req->buf) - return -ENODATA; - - musb_ep = to_musb_ep(ep); - musb = musb_ep->musb; - - request = to_musb_request(req); - request->musb = musb; - - if (request->ep != musb_ep) - return -EINVAL; - - dev_dbg(musb->controller, "<== to %s request=%p\n", ep->name, req); - - /* request is mine now... */ - request->request.actual = 0; - request->request.status = -EINPROGRESS; - request->epnum = musb_ep->current_epnum; - request->tx = musb_ep->is_in; - - map_dma_buffer(request, musb, musb_ep); - - spin_lock_irqsave(&musb->lock, lockflags); - - /* don't queue if the ep is down */ - if (!musb_ep->desc) { - dev_dbg(musb->controller, "req %p queued to %s while ep %s\n", - req, ep->name, "disabled"); - status = -ESHUTDOWN; - goto cleanup; - } - - /* add request to the list */ - list_add_tail(&request->list, &musb_ep->req_list); - - /* it this is the head of the queue, start i/o ... */ - if (!musb_ep->busy && &request->list == musb_ep->req_list.next) - musb_ep_restart(musb, request); - -cleanup: - spin_unlock_irqrestore(&musb->lock, lockflags); - return status; -} - -static int musb_gadget_dequeue(struct usb_ep *ep, struct usb_request *request) -{ - struct musb_ep *musb_ep = to_musb_ep(ep); - struct musb_request *req = to_musb_request(request); - struct musb_request *r; - unsigned long flags; - int status = 0; - struct musb *musb = musb_ep->musb; - - if (!ep || !request || to_musb_request(request)->ep != musb_ep) - return -EINVAL; - - spin_lock_irqsave(&musb->lock, flags); - - list_for_each_entry(r, &musb_ep->req_list, list) { - if (r == req) - break; - } - if (r != req) { - dev_dbg(musb->controller, "request %p not queued to %s\n", request, ep->name); - status = -EINVAL; - goto done; - } - - /* if the hardware doesn't have the request, easy ... */ - if (musb_ep->req_list.next != &req->list || musb_ep->busy) - musb_g_giveback(musb_ep, request, -ECONNRESET); - - /* ... else abort the dma transfer ... */ - else if (is_dma_capable() && musb_ep->dma) { - struct dma_controller *c = musb->dma_controller; - - musb_ep_select(musb->mregs, musb_ep->current_epnum); - if (c->channel_abort) - status = c->channel_abort(musb_ep->dma); - else - status = -EBUSY; - if (status == 0) - musb_g_giveback(musb_ep, request, -ECONNRESET); - } else { - /* NOTE: by sticking to easily tested hardware/driver states, - * we leave counting of in-flight packets imprecise. - */ - musb_g_giveback(musb_ep, request, -ECONNRESET); - } - -done: - spin_unlock_irqrestore(&musb->lock, flags); - return status; -} - -/* - * Set or clear the halt bit of an endpoint. A halted enpoint won't tx/rx any - * data but will queue requests. - * - * exported to ep0 code - */ -static int musb_gadget_set_halt(struct usb_ep *ep, int value) -{ - struct musb_ep *musb_ep = to_musb_ep(ep); - u8 epnum = musb_ep->current_epnum; - struct musb *musb = musb_ep->musb; - void __iomem *epio = musb->endpoints[epnum].regs; - void __iomem *mbase; - unsigned long flags; - u16 csr; - struct musb_request *request; - int status = 0; - - if (!ep) - return -EINVAL; - mbase = musb->mregs; - - spin_lock_irqsave(&musb->lock, flags); - - if ((USB_ENDPOINT_XFER_ISOC == musb_ep->type)) { - status = -EINVAL; - goto done; - } - - musb_ep_select(mbase, epnum); - - request = next_request(musb_ep); - if (value) { - if (request) { - dev_dbg(musb->controller, "request in progress, cannot halt %s\n", - ep->name); - status = -EAGAIN; - goto done; - } - /* Cannot portably stall with non-empty FIFO */ - if (musb_ep->is_in) { - csr = musb_readw(epio, MUSB_TXCSR); - if (csr & MUSB_TXCSR_FIFONOTEMPTY) { - dev_dbg(musb->controller, "FIFO busy, cannot halt %s\n", ep->name); - status = -EAGAIN; - goto done; - } - } - } else - musb_ep->wedged = 0; - - /* set/clear the stall and toggle bits */ - dev_dbg(musb->controller, "%s: %s stall\n", ep->name, value ? "set" : "clear"); - if (musb_ep->is_in) { - csr = musb_readw(epio, MUSB_TXCSR); - csr |= MUSB_TXCSR_P_WZC_BITS - | MUSB_TXCSR_CLRDATATOG; - if (value) - csr |= MUSB_TXCSR_P_SENDSTALL; - else - csr &= ~(MUSB_TXCSR_P_SENDSTALL - | MUSB_TXCSR_P_SENTSTALL); - csr &= ~MUSB_TXCSR_TXPKTRDY; - musb_writew(epio, MUSB_TXCSR, csr); - } else { - csr = musb_readw(epio, MUSB_RXCSR); - csr |= MUSB_RXCSR_P_WZC_BITS - | MUSB_RXCSR_FLUSHFIFO - | MUSB_RXCSR_CLRDATATOG; - if (value) - csr |= MUSB_RXCSR_P_SENDSTALL; - else - csr &= ~(MUSB_RXCSR_P_SENDSTALL - | MUSB_RXCSR_P_SENTSTALL); - musb_writew(epio, MUSB_RXCSR, csr); - } - - /* maybe start the first request in the queue */ - if (!musb_ep->busy && !value && request) { - dev_dbg(musb->controller, "restarting the request\n"); - musb_ep_restart(musb, request); - } - -done: - spin_unlock_irqrestore(&musb->lock, flags); - return status; -} - -/* - * Sets the halt feature with the clear requests ignored - */ -static int musb_gadget_set_wedge(struct usb_ep *ep) -{ - struct musb_ep *musb_ep = to_musb_ep(ep); - - if (!ep) - return -EINVAL; - - musb_ep->wedged = 1; - - return usb_ep_set_halt(ep); -} - -static int musb_gadget_fifo_status(struct usb_ep *ep) -{ - struct musb_ep *musb_ep = to_musb_ep(ep); - void __iomem *epio = musb_ep->hw_ep->regs; - int retval = -EINVAL; - - if (musb_ep->desc && !musb_ep->is_in) { - struct musb *musb = musb_ep->musb; - int epnum = musb_ep->current_epnum; - void __iomem *mbase = musb->mregs; - unsigned long flags; - - spin_lock_irqsave(&musb->lock, flags); - - musb_ep_select(mbase, epnum); - /* FIXME return zero unless RXPKTRDY is set */ - retval = musb_readw(epio, MUSB_RXCOUNT); - - spin_unlock_irqrestore(&musb->lock, flags); - } - return retval; -} - -static void musb_gadget_fifo_flush(struct usb_ep *ep) -{ - struct musb_ep *musb_ep = to_musb_ep(ep); - struct musb *musb = musb_ep->musb; - u8 epnum = musb_ep->current_epnum; - void __iomem *epio = musb->endpoints[epnum].regs; - void __iomem *mbase; - unsigned long flags; - u16 csr, int_txe; - - mbase = musb->mregs; - - spin_lock_irqsave(&musb->lock, flags); - musb_ep_select(mbase, (u8) epnum); - - /* disable interrupts */ - int_txe = musb_readw(mbase, MUSB_INTRTXE); - musb_writew(mbase, MUSB_INTRTXE, int_txe & ~(1 << epnum)); - - if (musb_ep->is_in) { - csr = musb_readw(epio, MUSB_TXCSR); - if (csr & MUSB_TXCSR_FIFONOTEMPTY) { - csr |= MUSB_TXCSR_FLUSHFIFO | MUSB_TXCSR_P_WZC_BITS; - /* - * Setting both TXPKTRDY and FLUSHFIFO makes controller - * to interrupt current FIFO loading, but not flushing - * the already loaded ones. - */ - csr &= ~MUSB_TXCSR_TXPKTRDY; - musb_writew(epio, MUSB_TXCSR, csr); - /* REVISIT may be inappropriate w/o FIFONOTEMPTY ... */ - musb_writew(epio, MUSB_TXCSR, csr); - } - } else { - csr = musb_readw(epio, MUSB_RXCSR); - csr |= MUSB_RXCSR_FLUSHFIFO | MUSB_RXCSR_P_WZC_BITS; - musb_writew(epio, MUSB_RXCSR, csr); - musb_writew(epio, MUSB_RXCSR, csr); - } - - /* re-enable interrupt */ - musb_writew(mbase, MUSB_INTRTXE, int_txe); - spin_unlock_irqrestore(&musb->lock, flags); -} - -static const struct usb_ep_ops musb_ep_ops = { - .enable = musb_gadget_enable, - .disable = musb_gadget_disable, - .alloc_request = musb_alloc_request, - .free_request = musb_free_request, - .queue = musb_gadget_queue, - .dequeue = musb_gadget_dequeue, - .set_halt = musb_gadget_set_halt, - .set_wedge = musb_gadget_set_wedge, - .fifo_status = musb_gadget_fifo_status, - .fifo_flush = musb_gadget_fifo_flush -}; - -/* ----------------------------------------------------------------------- */ - -static int musb_gadget_get_frame(struct usb_gadget *gadget) -{ - struct musb *musb = gadget_to_musb(gadget); - - return (int)musb_readw(musb->mregs, MUSB_FRAME); -} - -static int musb_gadget_wakeup(struct usb_gadget *gadget) -{ - struct musb *musb = gadget_to_musb(gadget); - void __iomem *mregs = musb->mregs; - unsigned long flags; - int status = -EINVAL; - u8 power, devctl; - int retries; - - spin_lock_irqsave(&musb->lock, flags); - - 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 - * doesn't affect OTG transitions. - */ - if (musb->may_wakeup && musb->is_suspended) - break; - goto done; - case OTG_STATE_B_IDLE: - /* Start SRP ... OTG not required. */ - devctl = musb_readb(mregs, MUSB_DEVCTL); - dev_dbg(musb->controller, "Sending SRP: devctl: %02x\n", devctl); - devctl |= MUSB_DEVCTL_SESSION; - musb_writeb(mregs, MUSB_DEVCTL, devctl); - devctl = musb_readb(mregs, MUSB_DEVCTL); - retries = 100; - while (!(devctl & MUSB_DEVCTL_SESSION)) { - devctl = musb_readb(mregs, MUSB_DEVCTL); - if (retries-- < 1) - break; - } - retries = 10000; - while (devctl & MUSB_DEVCTL_SESSION) { - devctl = musb_readb(mregs, MUSB_DEVCTL); - if (retries-- < 1) - break; - } - - spin_unlock_irqrestore(&musb->lock, flags); - otg_start_srp(musb->xceiv->otg); - spin_lock_irqsave(&musb->lock, flags); - - /* Block idling for at least 1s */ - musb_platform_try_idle(musb, - jiffies + msecs_to_jiffies(1 * HZ)); - - status = 0; - goto done; - default: - dev_dbg(musb->controller, "Unhandled wake: %s\n", - otg_state_string(musb->xceiv->state)); - goto done; - } - - status = 0; - - power = musb_readb(mregs, MUSB_POWER); - power |= MUSB_POWER_RESUME; - musb_writeb(mregs, MUSB_POWER, power); - dev_dbg(musb->controller, "issue wakeup\n"); - - /* FIXME do this next chunk in a timer callback, no udelay */ - mdelay(2); - - power = musb_readb(mregs, MUSB_POWER); - power &= ~MUSB_POWER_RESUME; - musb_writeb(mregs, MUSB_POWER, power); -done: - spin_unlock_irqrestore(&musb->lock, flags); - return status; -} - -static int -musb_gadget_set_self_powered(struct usb_gadget *gadget, int is_selfpowered) -{ - struct musb *musb = gadget_to_musb(gadget); - - musb->is_self_powered = !!is_selfpowered; - return 0; -} - -static void musb_pullup(struct musb *musb, int is_on) -{ - u8 power; - - power = musb_readb(musb->mregs, MUSB_POWER); - if (is_on) - power |= MUSB_POWER_SOFTCONN; - else - power &= ~MUSB_POWER_SOFTCONN; - - /* FIXME if on, HdrcStart; if off, HdrcStop */ - - dev_dbg(musb->controller, "gadget D+ pullup %s\n", - is_on ? "on" : "off"); - musb_writeb(musb->mregs, MUSB_POWER, power); -} - -#if 0 -static int musb_gadget_vbus_session(struct usb_gadget *gadget, int is_active) -{ - dev_dbg(musb->controller, "<= %s =>\n", __func__); - - /* - * FIXME iff driver's softconnect flag is set (as it is during probe, - * though that can clear it), just musb_pullup(). - */ - - return -EINVAL; -} -#endif - -static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) -{ - struct musb *musb = gadget_to_musb(gadget); - - if (!musb->xceiv->set_power) - return -EOPNOTSUPP; - return usb_phy_set_power(musb->xceiv, mA); -} - -static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on) -{ - struct musb *musb = gadget_to_musb(gadget); - unsigned long flags; - - is_on = !!is_on; - - pm_runtime_get_sync(musb->controller); - - /* NOTE: this assumes we are sensing vbus; we'd rather - * not pullup unless the B-session is active. - */ - spin_lock_irqsave(&musb->lock, flags); - if (is_on != musb->softconnect) { - musb->softconnect = is_on; - musb_pullup(musb, is_on); - } - spin_unlock_irqrestore(&musb->lock, flags); - - pm_runtime_put(musb->controller); - - return 0; -} - -static int musb_gadget_start(struct usb_gadget *g, - struct usb_gadget_driver *driver); -static int musb_gadget_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver); - -static const struct usb_gadget_ops musb_gadget_operations = { - .get_frame = musb_gadget_get_frame, - .wakeup = musb_gadget_wakeup, - .set_selfpowered = musb_gadget_set_self_powered, - /* .vbus_session = musb_gadget_vbus_session, */ - .vbus_draw = musb_gadget_vbus_draw, - .pullup = musb_gadget_pullup, - .udc_start = musb_gadget_start, - .udc_stop = musb_gadget_stop, -}; - -/* ----------------------------------------------------------------------- */ - -/* Registration */ - -/* Only this registration code "knows" the rule (from USB standards) - * about there being only one external upstream port. It assumes - * all peripheral ports are external... - */ - -static void musb_gadget_release(struct device *dev) -{ - /* kref_put(WHAT) */ - dev_dbg(dev, "%s\n", __func__); -} - - -static void __devinit -init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in) -{ - struct musb_hw_ep *hw_ep = musb->endpoints + epnum; - - memset(ep, 0, sizeof *ep); - - ep->current_epnum = epnum; - ep->musb = musb; - ep->hw_ep = hw_ep; - ep->is_in = is_in; - - INIT_LIST_HEAD(&ep->req_list); - - sprintf(ep->name, "ep%d%s", epnum, - (!epnum || hw_ep->is_shared_fifo) ? "" : ( - is_in ? "in" : "out")); - ep->end_point.name = ep->name; - INIT_LIST_HEAD(&ep->end_point.ep_list); - if (!epnum) { - ep->end_point.maxpacket = 64; - ep->end_point.ops = &musb_g_ep0_ops; - musb->g.ep0 = &ep->end_point; - } else { - if (is_in) - ep->end_point.maxpacket = hw_ep->max_packet_sz_tx; - else - ep->end_point.maxpacket = hw_ep->max_packet_sz_rx; - ep->end_point.ops = &musb_ep_ops; - list_add_tail(&ep->end_point.ep_list, &musb->g.ep_list); - } -} - -/* - * Initialize the endpoints exposed to peripheral drivers, with backlinks - * to the rest of the driver state. - */ -static inline void __devinit musb_g_init_endpoints(struct musb *musb) -{ - u8 epnum; - struct musb_hw_ep *hw_ep; - unsigned count = 0; - - /* initialize endpoint list just once */ - INIT_LIST_HEAD(&(musb->g.ep_list)); - - for (epnum = 0, hw_ep = musb->endpoints; - epnum < musb->nr_endpoints; - epnum++, hw_ep++) { - if (hw_ep->is_shared_fifo /* || !epnum */) { - init_peripheral_ep(musb, &hw_ep->ep_in, epnum, 0); - count++; - } else { - if (hw_ep->max_packet_sz_tx) { - init_peripheral_ep(musb, &hw_ep->ep_in, - epnum, 1); - count++; - } - if (hw_ep->max_packet_sz_rx) { - init_peripheral_ep(musb, &hw_ep->ep_out, - epnum, 0); - count++; - } - } - } -} - -/* called once during driver setup to initialize and link into - * the driver model; memory is zeroed. - */ -int __devinit musb_gadget_setup(struct musb *musb) -{ - int status; - - /* REVISIT minor race: if (erroneously) setting up two - * musb peripherals at the same time, only the bus lock - * is probably held. - */ - - musb->g.ops = &musb_gadget_operations; - musb->g.max_speed = USB_SPEED_HIGH; - musb->g.speed = USB_SPEED_UNKNOWN; - - /* this "gadget" abstracts/virtualizes the controller */ - dev_set_name(&musb->g.dev, "gadget"); - musb->g.dev.parent = musb->controller; - musb->g.dev.dma_mask = musb->controller->dma_mask; - musb->g.dev.release = musb_gadget_release; - musb->g.name = musb_driver_name; - - if (is_otg_enabled(musb)) - musb->g.is_otg = 1; - - musb_g_init_endpoints(musb); - - musb->is_active = 0; - musb_platform_try_idle(musb, 0); - - status = device_register(&musb->g.dev); - if (status != 0) { - put_device(&musb->g.dev); - return status; - } - status = usb_add_gadget_udc(musb->controller, &musb->g); - if (status) - goto err; - - return 0; -err: - musb->g.dev.parent = NULL; - device_unregister(&musb->g.dev); - return status; -} - -void musb_gadget_cleanup(struct musb *musb) -{ - usb_del_gadget_udc(&musb->g); - if (musb->g.dev.parent) - device_unregister(&musb->g.dev); -} - -/* - * Register the gadget driver. Used by gadget drivers when - * registering themselves with the controller. - * - * -EINVAL something went wrong (not driver) - * -EBUSY another gadget is already using the controller - * -ENOMEM no memory to perform the operation - * - * @param driver the gadget driver - * @return <0 if error, 0 if everything is fine - */ -static int musb_gadget_start(struct usb_gadget *g, - struct usb_gadget_driver *driver) -{ - struct musb *musb = gadget_to_musb(g); - struct usb_otg *otg = musb->xceiv->otg; - unsigned long flags; - int retval = -EINVAL; - - if (driver->max_speed < USB_SPEED_HIGH) - goto err0; - - pm_runtime_get_sync(musb->controller); - - dev_dbg(musb->controller, "registering driver %s\n", driver->function); - - musb->softconnect = 0; - musb->gadget_driver = driver; - - spin_lock_irqsave(&musb->lock, flags); - musb->is_active = 1; - - otg_set_peripheral(otg, &musb->g); - musb->xceiv->state = OTG_STATE_B_IDLE; - - /* - * FIXME this ignores the softconnect flag. Drivers are - * allowed hold the peripheral inactive until for example - * userspace hooks up printer hardware or DSP codecs, so - * hosts only see fully functional devices. - */ - - if (!is_otg_enabled(musb)) - musb_start(musb); - - spin_unlock_irqrestore(&musb->lock, flags); - - if (is_otg_enabled(musb)) { - struct usb_hcd *hcd = musb_to_hcd(musb); - - dev_dbg(musb->controller, "OTG startup...\n"); - - /* REVISIT: funcall to other code, which also - * handles power budgeting ... this way also - * ensures HdrcStart is indirectly called. - */ - retval = usb_add_hcd(musb_to_hcd(musb), 0, 0); - if (retval < 0) { - dev_dbg(musb->controller, "add_hcd failed, %d\n", retval); - goto err2; - } - - if ((musb->xceiv->last_event == USB_EVENT_ID) - && otg->set_vbus) - otg_set_vbus(otg, 1); - - hcd->self.uses_pio_for_control = 1; - } - if (musb->xceiv->last_event == USB_EVENT_NONE) - pm_runtime_put(musb->controller); - - return 0; - -err2: - if (!is_otg_enabled(musb)) - musb_stop(musb); -err0: - return retval; -} - -static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver) -{ - int i; - struct musb_hw_ep *hw_ep; - - /* don't disconnect if it's not connected */ - if (musb->g.speed == USB_SPEED_UNKNOWN) - driver = NULL; - else - musb->g.speed = USB_SPEED_UNKNOWN; - - /* deactivate the hardware */ - if (musb->softconnect) { - musb->softconnect = 0; - musb_pullup(musb, 0); - } - musb_stop(musb); - - /* killing any outstanding requests will quiesce the driver; - * then report disconnect - */ - if (driver) { - for (i = 0, hw_ep = musb->endpoints; - i < musb->nr_endpoints; - i++, hw_ep++) { - musb_ep_select(musb->mregs, i); - if (hw_ep->is_shared_fifo /* || !epnum */) { - nuke(&hw_ep->ep_in, -ESHUTDOWN); - } else { - if (hw_ep->max_packet_sz_tx) - nuke(&hw_ep->ep_in, -ESHUTDOWN); - if (hw_ep->max_packet_sz_rx) - nuke(&hw_ep->ep_out, -ESHUTDOWN); - } - } - } -} - -/* - * Unregister the gadget driver. Used by gadget drivers when - * unregistering themselves from the controller. - * - * @param driver the gadget driver to unregister - */ -static int musb_gadget_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver) -{ - struct musb *musb = gadget_to_musb(g); - unsigned long flags; - - if (musb->xceiv->last_event == USB_EVENT_NONE) - pm_runtime_get_sync(musb->controller); - - /* - * REVISIT always use otg_set_peripheral() here too; - * this needs to shut down the OTG engine. - */ - - spin_lock_irqsave(&musb->lock, flags); - - musb_hnp_stop(musb); - - (void) musb_gadget_vbus_draw(&musb->g, 0); - - musb->xceiv->state = OTG_STATE_UNDEFINED; - stop_activity(musb, driver); - otg_set_peripheral(musb->xceiv->otg, NULL); - - dev_dbg(musb->controller, "unregistering driver %s\n", driver->function); - - musb->is_active = 0; - musb_platform_try_idle(musb, 0); - spin_unlock_irqrestore(&musb->lock, flags); - - if (is_otg_enabled(musb)) { - usb_remove_hcd(musb_to_hcd(musb)); - /* FIXME we need to be able to register another - * gadget driver here and have everything work; - * that currently misbehaves. - */ - } - - if (!is_otg_enabled(musb)) - musb_stop(musb); - - pm_runtime_put(musb->controller); - - return 0; -} - -/* ----------------------------------------------------------------------- */ - -/* lifecycle operations called through plat_uds.c */ - -void musb_g_resume(struct musb *musb) -{ - musb->is_suspended = 0; - switch (musb->xceiv->state) { - case OTG_STATE_B_IDLE: - break; - case OTG_STATE_B_WAIT_ACON: - case OTG_STATE_B_PERIPHERAL: - musb->is_active = 1; - if (musb->gadget_driver && musb->gadget_driver->resume) { - spin_unlock(&musb->lock); - musb->gadget_driver->resume(&musb->g); - spin_lock(&musb->lock); - } - break; - default: - WARNING("unhandled RESUME transition (%s)\n", - otg_state_string(musb->xceiv->state)); - } -} - -/* called when SOF packets stop for 3+ msec */ -void musb_g_suspend(struct musb *musb) -{ - u8 devctl; - - devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - dev_dbg(musb->controller, "devctl %02x\n", devctl); - - switch (musb->xceiv->state) { - case OTG_STATE_B_IDLE: - if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) - musb->xceiv->state = OTG_STATE_B_PERIPHERAL; - break; - case OTG_STATE_B_PERIPHERAL: - musb->is_suspended = 1; - if (musb->gadget_driver && musb->gadget_driver->suspend) { - spin_unlock(&musb->lock); - musb->gadget_driver->suspend(&musb->g); - spin_lock(&musb->lock); - } - break; - default: - /* REVISIT if B_HOST, clear DEVCTL.HOSTREQ; - * A_PERIPHERAL may need care too - */ - WARNING("unhandled SUSPEND transition (%s)\n", - otg_state_string(musb->xceiv->state)); - } -} - -/* Called during SRP */ -void musb_g_wakeup(struct musb *musb) -{ - musb_gadget_wakeup(&musb->g); -} - -/* called when VBUS drops below session threshold, and in other cases */ -void musb_g_disconnect(struct musb *musb) -{ - void __iomem *mregs = musb->mregs; - u8 devctl = musb_readb(mregs, MUSB_DEVCTL); - - dev_dbg(musb->controller, "devctl %02x\n", devctl); - - /* clear HR */ - musb_writeb(mregs, MUSB_DEVCTL, devctl & MUSB_DEVCTL_SESSION); - - /* don't draw vbus until new b-default session */ - (void) musb_gadget_vbus_draw(&musb->g, 0); - - musb->g.speed = USB_SPEED_UNKNOWN; - if (musb->gadget_driver && musb->gadget_driver->disconnect) { - spin_unlock(&musb->lock); - musb->gadget_driver->disconnect(&musb->g); - spin_lock(&musb->lock); - } - - switch (musb->xceiv->state) { - default: - dev_dbg(musb->controller, "Unhandled disconnect %s, setting a_idle\n", - otg_state_string(musb->xceiv->state)); - musb->xceiv->state = OTG_STATE_A_IDLE; - MUSB_HST_MODE(musb); - break; - case OTG_STATE_A_PERIPHERAL: - musb->xceiv->state = OTG_STATE_A_WAIT_BCON; - MUSB_HST_MODE(musb); - break; - case OTG_STATE_B_WAIT_ACON: - case OTG_STATE_B_HOST: - case OTG_STATE_B_PERIPHERAL: - case OTG_STATE_B_IDLE: - musb->xceiv->state = OTG_STATE_B_IDLE; - break; - case OTG_STATE_B_SRP_INIT: - break; - } - - musb->is_active = 0; -} - -void musb_g_reset(struct musb *musb) -__releases(musb->lock) -__acquires(musb->lock) -{ - void __iomem *mbase = musb->mregs; - u8 devctl = musb_readb(mbase, MUSB_DEVCTL); - u8 power; - - dev_dbg(musb->controller, "<== %s addr=%x driver '%s'\n", - (devctl & MUSB_DEVCTL_BDEVICE) - ? "B-Device" : "A-Device", - musb_readb(mbase, MUSB_FADDR), - musb->gadget_driver - ? musb->gadget_driver->driver.name - : NULL - ); - - /* report disconnect, if we didn't already (flushing EP state) */ - if (musb->g.speed != USB_SPEED_UNKNOWN) - musb_g_disconnect(musb); - - /* clear HR */ - else if (devctl & MUSB_DEVCTL_HR) - musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION); - - - /* what speed did we negotiate? */ - power = musb_readb(mbase, MUSB_POWER); - musb->g.speed = (power & MUSB_POWER_HSMODE) - ? USB_SPEED_HIGH : USB_SPEED_FULL; - - /* start in USB_STATE_DEFAULT */ - musb->is_active = 1; - musb->is_suspended = 0; - MUSB_DEV_MODE(musb); - musb->address = 0; - musb->ep0_state = MUSB_EP0_STAGE_SETUP; - - musb->may_wakeup = 0; - musb->g.b_hnp_enable = 0; - musb->g.a_alt_hnp_support = 0; - musb->g.a_hnp_support = 0; - - /* Normal reset, as B-Device; - * or else after HNP, as A-Device - */ - if (devctl & MUSB_DEVCTL_BDEVICE) { - 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->g.is_a_peripheral = 1; - } else - WARN_ON(1); - - /* start with default limits on VBUS power draw */ - (void) musb_gadget_vbus_draw(&musb->g, - is_otg_enabled(musb) ? 8 : 100); -} diff --git a/ANDROID_3.4.5/drivers/usb/musb/musb_gadget.h b/ANDROID_3.4.5/drivers/usb/musb/musb_gadget.h deleted file mode 100644 index 66b7c5e0..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/musb_gadget.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * MUSB OTG driver peripheral defines - * - * Copyright 2005 Mentor Graphics Corporation - * Copyright (C) 2005-2006 by Texas Instruments - * Copyright (C) 2006-2007 Nokia Corporation - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef __MUSB_GADGET_H -#define __MUSB_GADGET_H - -#include - -enum buffer_map_state { - UN_MAPPED = 0, - PRE_MAPPED, - MUSB_MAPPED -}; - -struct musb_request { - struct usb_request request; - struct list_head list; - struct musb_ep *ep; - struct musb *musb; - u8 tx; /* endpoint direction */ - u8 epnum; - enum buffer_map_state map_state; -}; - -static inline struct musb_request *to_musb_request(struct usb_request *req) -{ - return req ? container_of(req, struct musb_request, request) : NULL; -} - -extern struct usb_request * -musb_alloc_request(struct usb_ep *ep, gfp_t gfp_flags); -extern void musb_free_request(struct usb_ep *ep, struct usb_request *req); - - -/* - * struct musb_ep - peripheral side view of endpoint rx or tx side - */ -struct musb_ep { - /* stuff towards the head is basically write-once. */ - struct usb_ep end_point; - char name[12]; - struct musb_hw_ep *hw_ep; - struct musb *musb; - u8 current_epnum; - - /* ... when enabled/disabled ... */ - u8 type; - u8 is_in; - u16 packet_sz; - const struct usb_endpoint_descriptor *desc; - struct dma_channel *dma; - - /* later things are modified based on usage */ - struct list_head req_list; - - u8 wedged; - - /* true if lock must be dropped but req_list may not be advanced */ - u8 busy; - - u8 hb_mult; -}; - -static inline struct musb_ep *to_musb_ep(struct usb_ep *ep) -{ - return ep ? container_of(ep, struct musb_ep, end_point) : NULL; -} - -static inline struct musb_request *next_request(struct musb_ep *ep) -{ - struct list_head *queue = &ep->req_list; - - if (list_empty(queue)) - return NULL; - return container_of(queue->next, struct musb_request, list); -} - -extern void musb_g_tx(struct musb *musb, u8 epnum); -extern void musb_g_rx(struct musb *musb, u8 epnum); - -extern const struct usb_ep_ops musb_g_ep0_ops; - -extern int musb_gadget_setup(struct musb *); -extern void musb_gadget_cleanup(struct musb *); - -extern void musb_g_giveback(struct musb_ep *, struct usb_request *, int); - -extern void musb_ep_restart(struct musb *, struct musb_request *); - -#endif /* __MUSB_GADGET_H */ diff --git a/ANDROID_3.4.5/drivers/usb/musb/musb_gadget_ep0.c b/ANDROID_3.4.5/drivers/usb/musb/musb_gadget_ep0.c deleted file mode 100644 index e40d7647..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/musb_gadget_ep0.c +++ /dev/null @@ -1,1083 +0,0 @@ -/* - * MUSB OTG peripheral driver ep0 handling - * - * 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. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include -#include -#include -#include -#include - -#include "musb_core.h" - -/* ep0 is always musb->endpoints[0].ep_in */ -#define next_ep0_request(musb) next_in_request(&(musb)->endpoints[0]) - -/* - * locking note: we use only the controller lock, for simpler correctness. - * It's always held with IRQs blocked. - * - * It protects the ep0 request queue as well as ep0_state, not just the - * controller and indexed registers. And that lock stays held unless it - * needs to be dropped to allow reentering this driver ... like upcalls to - * the gadget driver, or adjusting endpoint halt status. - */ - -static char *decode_ep0stage(u8 stage) -{ - switch (stage) { - 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"; - case MUSB_EP0_STAGE_STATUSIN: return "in/status"; - case MUSB_EP0_STAGE_STATUSOUT: return "out/status"; - default: return "?"; - } -} - -/* handle a standard GET_STATUS request - * Context: caller holds controller lock - */ -static int service_tx_status_request( - struct musb *musb, - const struct usb_ctrlrequest *ctrlrequest) -{ - void __iomem *mbase = musb->mregs; - int handled = 1; - u8 result[2], epnum = 0; - const u8 recip = ctrlrequest->bRequestType & USB_RECIP_MASK; - - result[1] = 0; - - switch (recip) { - case USB_RECIP_DEVICE: - result[0] = musb->is_self_powered << USB_DEVICE_SELF_POWERED; - result[0] |= musb->may_wakeup << USB_DEVICE_REMOTE_WAKEUP; - if (musb->g.is_otg) { - result[0] |= musb->g.b_hnp_enable - << USB_DEVICE_B_HNP_ENABLE; - result[0] |= musb->g.a_alt_hnp_support - << USB_DEVICE_A_ALT_HNP_SUPPORT; - result[0] |= musb->g.a_hnp_support - << USB_DEVICE_A_HNP_SUPPORT; - } - break; - - case USB_RECIP_INTERFACE: - result[0] = 0; - break; - - case USB_RECIP_ENDPOINT: { - int is_in; - struct musb_ep *ep; - u16 tmp; - void __iomem *regs; - - epnum = (u8) ctrlrequest->wIndex; - if (!epnum) { - result[0] = 0; - break; - } - - is_in = epnum & USB_DIR_IN; - if (is_in) { - epnum &= 0x0f; - ep = &musb->endpoints[epnum].ep_in; - } else { - ep = &musb->endpoints[epnum].ep_out; - } - regs = musb->endpoints[epnum].regs; - - if (epnum >= MUSB_C_NUM_EPS || !ep->desc) { - handled = -EINVAL; - break; - } - - musb_ep_select(mbase, epnum); - if (is_in) - tmp = musb_readw(regs, MUSB_TXCSR) - & MUSB_TXCSR_P_SENDSTALL; - else - tmp = musb_readw(regs, MUSB_RXCSR) - & MUSB_RXCSR_P_SENDSTALL; - musb_ep_select(mbase, 0); - - result[0] = tmp ? 1 : 0; - } break; - - default: - /* class, vendor, etc ... delegate */ - handled = 0; - break; - } - - /* fill up the fifo; caller updates csr0 */ - if (handled > 0) { - u16 len = le16_to_cpu(ctrlrequest->wLength); - - if (len > 2) - len = 2; - musb_write_fifo(&musb->endpoints[0], len, result); - } - - return handled; -} - -/* - * handle a control-IN request, the end0 buffer contains the current request - * that is supposed to be a standard control request. Assumes the fifo to - * be at least 2 bytes long. - * - * @return 0 if the request was NOT HANDLED, - * < 0 when error - * > 0 when the request is processed - * - * Context: caller holds controller lock - */ -static int -service_in_request(struct musb *musb, const struct usb_ctrlrequest *ctrlrequest) -{ - int handled = 0; /* not handled */ - - if ((ctrlrequest->bRequestType & USB_TYPE_MASK) - == USB_TYPE_STANDARD) { - switch (ctrlrequest->bRequest) { - case USB_REQ_GET_STATUS: - handled = service_tx_status_request(musb, - ctrlrequest); - break; - - /* case USB_REQ_SYNC_FRAME: */ - - default: - break; - } - } - return handled; -} - -/* - * Context: caller holds controller lock - */ -static void musb_g_ep0_giveback(struct musb *musb, struct usb_request *req) -{ - musb_g_giveback(&musb->endpoints[0].ep_in, req, 0); -} - -/* - * Tries to start B-device HNP negotiation if enabled via sysfs - */ -static inline void musb_try_b_hnp_enable(struct musb *musb) -{ - void __iomem *mbase = musb->mregs; - u8 devctl; - - dev_dbg(musb->controller, "HNP: Setting HR\n"); - devctl = musb_readb(mbase, MUSB_DEVCTL); - musb_writeb(mbase, MUSB_DEVCTL, devctl | MUSB_DEVCTL_HR); -} - -/* - * Handle all control requests with no DATA stage, including standard - * requests such as: - * USB_REQ_SET_CONFIGURATION, USB_REQ_SET_INTERFACE, unrecognized - * always delegated to the gadget driver - * USB_REQ_SET_ADDRESS, USB_REQ_CLEAR_FEATURE, USB_REQ_SET_FEATURE - * always handled here, except for class/vendor/... features - * - * Context: caller holds controller lock - */ -static int -service_zero_data_request(struct musb *musb, - struct usb_ctrlrequest *ctrlrequest) -__releases(musb->lock) -__acquires(musb->lock) -{ - int handled = -EINVAL; - void __iomem *mbase = musb->mregs; - const u8 recip = ctrlrequest->bRequestType & USB_RECIP_MASK; - - /* the gadget driver handles everything except what we MUST handle */ - if ((ctrlrequest->bRequestType & USB_TYPE_MASK) - == USB_TYPE_STANDARD) { - switch (ctrlrequest->bRequest) { - case USB_REQ_SET_ADDRESS: - /* change it after the status stage */ - musb->set_address = true; - musb->address = (u8) (ctrlrequest->wValue & 0x7f); - handled = 1; - break; - - case USB_REQ_CLEAR_FEATURE: - switch (recip) { - case USB_RECIP_DEVICE: - if (ctrlrequest->wValue - != USB_DEVICE_REMOTE_WAKEUP) - break; - musb->may_wakeup = 0; - handled = 1; - break; - case USB_RECIP_INTERFACE: - break; - case USB_RECIP_ENDPOINT:{ - const u8 epnum = - ctrlrequest->wIndex & 0x0f; - struct musb_ep *musb_ep; - struct musb_hw_ep *ep; - struct musb_request *request; - void __iomem *regs; - int is_in; - u16 csr; - - if (epnum == 0 || epnum >= MUSB_C_NUM_EPS || - ctrlrequest->wValue != USB_ENDPOINT_HALT) - break; - - ep = musb->endpoints + epnum; - regs = ep->regs; - is_in = ctrlrequest->wIndex & USB_DIR_IN; - if (is_in) - musb_ep = &ep->ep_in; - else - musb_ep = &ep->ep_out; - if (!musb_ep->desc) - break; - - handled = 1; - /* Ignore request if endpoint is wedged */ - if (musb_ep->wedged) - break; - - musb_ep_select(mbase, epnum); - if (is_in) { - csr = musb_readw(regs, MUSB_TXCSR); - csr |= MUSB_TXCSR_CLRDATATOG | - MUSB_TXCSR_P_WZC_BITS; - csr &= ~(MUSB_TXCSR_P_SENDSTALL | - MUSB_TXCSR_P_SENTSTALL | - MUSB_TXCSR_TXPKTRDY); - musb_writew(regs, MUSB_TXCSR, csr); - } else { - csr = musb_readw(regs, MUSB_RXCSR); - csr |= MUSB_RXCSR_CLRDATATOG | - MUSB_RXCSR_P_WZC_BITS; - csr &= ~(MUSB_RXCSR_P_SENDSTALL | - MUSB_RXCSR_P_SENTSTALL); - musb_writew(regs, MUSB_RXCSR, csr); - } - - /* Maybe start the first request in the queue */ - request = next_request(musb_ep); - if (!musb_ep->busy && request) { - dev_dbg(musb->controller, "restarting the request\n"); - musb_ep_restart(musb, request); - } - - /* select ep0 again */ - musb_ep_select(mbase, 0); - } break; - default: - /* class, vendor, etc ... delegate */ - handled = 0; - break; - } - break; - - case USB_REQ_SET_FEATURE: - switch (recip) { - case USB_RECIP_DEVICE: - handled = 1; - switch (ctrlrequest->wValue) { - case USB_DEVICE_REMOTE_WAKEUP: - musb->may_wakeup = 1; - break; - case USB_DEVICE_TEST_MODE: - if (musb->g.speed != USB_SPEED_HIGH) - goto stall; - if (ctrlrequest->wIndex & 0xff) - goto stall; - - switch (ctrlrequest->wIndex >> 8) { - case 1: - pr_debug("TEST_J\n"); - /* TEST_J */ - musb->test_mode_nr = - MUSB_TEST_J; - break; - case 2: - /* TEST_K */ - pr_debug("TEST_K\n"); - musb->test_mode_nr = - MUSB_TEST_K; - break; - case 3: - /* TEST_SE0_NAK */ - pr_debug("TEST_SE0_NAK\n"); - musb->test_mode_nr = - MUSB_TEST_SE0_NAK; - break; - case 4: - /* TEST_PACKET */ - pr_debug("TEST_PACKET\n"); - musb->test_mode_nr = - MUSB_TEST_PACKET; - break; - - case 0xc0: - /* TEST_FORCE_HS */ - pr_debug("TEST_FORCE_HS\n"); - musb->test_mode_nr = - MUSB_TEST_FORCE_HS; - break; - case 0xc1: - /* TEST_FORCE_FS */ - pr_debug("TEST_FORCE_FS\n"); - musb->test_mode_nr = - MUSB_TEST_FORCE_FS; - break; - case 0xc2: - /* TEST_FIFO_ACCESS */ - pr_debug("TEST_FIFO_ACCESS\n"); - musb->test_mode_nr = - MUSB_TEST_FIFO_ACCESS; - break; - case 0xc3: - /* TEST_FORCE_HOST */ - pr_debug("TEST_FORCE_HOST\n"); - musb->test_mode_nr = - MUSB_TEST_FORCE_HOST; - break; - default: - goto stall; - } - - /* enter test mode after irq */ - if (handled > 0) - musb->test_mode = true; - break; - case USB_DEVICE_B_HNP_ENABLE: - if (!musb->g.is_otg) - goto stall; - musb->g.b_hnp_enable = 1; - musb_try_b_hnp_enable(musb); - break; - case USB_DEVICE_A_HNP_SUPPORT: - if (!musb->g.is_otg) - goto stall; - musb->g.a_hnp_support = 1; - break; - case USB_DEVICE_A_ALT_HNP_SUPPORT: - if (!musb->g.is_otg) - goto stall; - musb->g.a_alt_hnp_support = 1; - break; - case USB_DEVICE_DEBUG_MODE: - handled = 0; - break; -stall: - default: - handled = -EINVAL; - break; - } - break; - - case USB_RECIP_INTERFACE: - break; - - case USB_RECIP_ENDPOINT:{ - const u8 epnum = - ctrlrequest->wIndex & 0x0f; - struct musb_ep *musb_ep; - struct musb_hw_ep *ep; - void __iomem *regs; - int is_in; - u16 csr; - - if (epnum == 0 || epnum >= MUSB_C_NUM_EPS || - ctrlrequest->wValue != USB_ENDPOINT_HALT) - break; - - ep = musb->endpoints + epnum; - regs = ep->regs; - is_in = ctrlrequest->wIndex & USB_DIR_IN; - if (is_in) - musb_ep = &ep->ep_in; - else - musb_ep = &ep->ep_out; - if (!musb_ep->desc) - break; - - musb_ep_select(mbase, epnum); - if (is_in) { - csr = musb_readw(regs, MUSB_TXCSR); - if (csr & MUSB_TXCSR_FIFONOTEMPTY) - csr |= MUSB_TXCSR_FLUSHFIFO; - csr |= MUSB_TXCSR_P_SENDSTALL - | MUSB_TXCSR_CLRDATATOG - | MUSB_TXCSR_P_WZC_BITS; - musb_writew(regs, MUSB_TXCSR, csr); - } else { - csr = musb_readw(regs, MUSB_RXCSR); - csr |= MUSB_RXCSR_P_SENDSTALL - | MUSB_RXCSR_FLUSHFIFO - | MUSB_RXCSR_CLRDATATOG - | MUSB_RXCSR_P_WZC_BITS; - musb_writew(regs, MUSB_RXCSR, csr); - } - - /* select ep0 again */ - musb_ep_select(mbase, 0); - handled = 1; - } break; - - default: - /* class, vendor, etc ... delegate */ - handled = 0; - break; - } - break; - default: - /* delegate SET_CONFIGURATION, etc */ - handled = 0; - } - } else - handled = 0; - return handled; -} - -/* we have an ep0out data packet - * Context: caller holds controller lock - */ -static void ep0_rxstate(struct musb *musb) -{ - void __iomem *regs = musb->control_ep->regs; - struct musb_request *request; - struct usb_request *req; - u16 count, csr; - - request = next_ep0_request(musb); - req = &request->request; - - /* read packet and ack; or stall because of gadget driver bug: - * should have provided the rx buffer before setup() returned. - */ - if (req) { - void *buf = req->buf + req->actual; - unsigned len = req->length - req->actual; - - /* read the buffer */ - count = musb_readb(regs, MUSB_COUNT0); - if (count > len) { - req->status = -EOVERFLOW; - count = len; - } - musb_read_fifo(&musb->endpoints[0], count, buf); - req->actual += count; - csr = MUSB_CSR0_P_SVDRXPKTRDY; - if (count < 64 || req->actual == req->length) { - musb->ep0_state = MUSB_EP0_STAGE_STATUSIN; - csr |= MUSB_CSR0_P_DATAEND; - } else - req = NULL; - } else - csr = MUSB_CSR0_P_SVDRXPKTRDY | MUSB_CSR0_P_SENDSTALL; - - - /* Completion handler may choose to stall, e.g. because the - * message just received holds invalid data. - */ - if (req) { - musb->ackpend = csr; - musb_g_ep0_giveback(musb, req); - if (!musb->ackpend) - return; - musb->ackpend = 0; - } - musb_ep_select(musb->mregs, 0); - musb_writew(regs, MUSB_CSR0, csr); -} - -/* - * transmitting to the host (IN), this code might be called from IRQ - * and from kernel thread. - * - * Context: caller holds controller lock - */ -static void ep0_txstate(struct musb *musb) -{ - void __iomem *regs = musb->control_ep->regs; - struct musb_request *req = next_ep0_request(musb); - struct usb_request *request; - u16 csr = MUSB_CSR0_TXPKTRDY; - u8 *fifo_src; - u8 fifo_count; - - if (!req) { - /* WARN_ON(1); */ - dev_dbg(musb->controller, "odd; csr0 %04x\n", musb_readw(regs, MUSB_CSR0)); - return; - } - - request = &req->request; - - /* load the data */ - fifo_src = (u8 *) request->buf + request->actual; - fifo_count = min((unsigned) MUSB_EP0_FIFOSIZE, - request->length - request->actual); - musb_write_fifo(&musb->endpoints[0], fifo_count, fifo_src); - request->actual += fifo_count; - - /* update the flags */ - if (fifo_count < MUSB_MAX_END0_PACKET - || (request->actual == request->length - && !request->zero)) { - musb->ep0_state = MUSB_EP0_STAGE_STATUSOUT; - csr |= MUSB_CSR0_P_DATAEND; - } else - request = NULL; - - /* report completions as soon as the fifo's loaded; there's no - * win in waiting till this last packet gets acked. (other than - * very precise fault reporting, needed by USB TMC; possible with - * this hardware, but not usable from portable gadget drivers.) - */ - if (request) { - musb->ackpend = csr; - musb_g_ep0_giveback(musb, request); - if (!musb->ackpend) - return; - musb->ackpend = 0; - } - - /* send it out, triggering a "txpktrdy cleared" irq */ - musb_ep_select(musb->mregs, 0); - musb_writew(regs, MUSB_CSR0, csr); -} - -/* - * Read a SETUP packet (struct usb_ctrlrequest) from the hardware. - * Fields are left in USB byte-order. - * - * Context: caller holds controller lock. - */ -static void -musb_read_setup(struct musb *musb, struct usb_ctrlrequest *req) -{ - struct musb_request *r; - void __iomem *regs = musb->control_ep->regs; - - musb_read_fifo(&musb->endpoints[0], sizeof *req, (u8 *)req); - - /* NOTE: earlier 2.6 versions changed setup packets to host - * order, but now USB packets always stay in USB byte order. - */ - dev_dbg(musb->controller, "SETUP req%02x.%02x v%04x i%04x l%d\n", - req->bRequestType, - req->bRequest, - le16_to_cpu(req->wValue), - le16_to_cpu(req->wIndex), - le16_to_cpu(req->wLength)); - - /* clean up any leftover transfers */ - r = next_ep0_request(musb); - if (r) - musb_g_ep0_giveback(musb, &r->request); - - /* For zero-data requests we want to delay the STATUS stage to - * avoid SETUPEND errors. If we read data (OUT), delay accepting - * packets until there's a buffer to store them in. - * - * If we write data, the controller acts happier if we enable - * the TX FIFO right away, and give the controller a moment - * to switch modes... - */ - musb->set_address = false; - musb->ackpend = MUSB_CSR0_P_SVDRXPKTRDY; - if (req->wLength == 0) { - if (req->bRequestType & USB_DIR_IN) - musb->ackpend |= MUSB_CSR0_TXPKTRDY; - musb->ep0_state = MUSB_EP0_STAGE_ACKWAIT; - } else if (req->bRequestType & USB_DIR_IN) { - musb->ep0_state = MUSB_EP0_STAGE_TX; - musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SVDRXPKTRDY); - while ((musb_readw(regs, MUSB_CSR0) - & MUSB_CSR0_RXPKTRDY) != 0) - cpu_relax(); - musb->ackpend = 0; - } else - musb->ep0_state = MUSB_EP0_STAGE_RX; -} - -static int -forward_to_driver(struct musb *musb, const struct usb_ctrlrequest *ctrlrequest) -__releases(musb->lock) -__acquires(musb->lock) -{ - int retval; - if (!musb->gadget_driver) - return -EOPNOTSUPP; - spin_unlock(&musb->lock); - retval = musb->gadget_driver->setup(&musb->g, ctrlrequest); - spin_lock(&musb->lock); - return retval; -} - -/* - * Handle peripheral ep0 interrupt - * - * Context: irq handler; we won't re-enter the driver that way. - */ -irqreturn_t musb_g_ep0_irq(struct musb *musb) -{ - u16 csr; - u16 len; - void __iomem *mbase = musb->mregs; - void __iomem *regs = musb->endpoints[0].regs; - irqreturn_t retval = IRQ_NONE; - - musb_ep_select(mbase, 0); /* select ep0 */ - csr = musb_readw(regs, MUSB_CSR0); - len = musb_readb(regs, MUSB_COUNT0); - - dev_dbg(musb->controller, "csr %04x, count %d, myaddr %d, ep0stage %s\n", - csr, len, - musb_readb(mbase, MUSB_FADDR), - decode_ep0stage(musb->ep0_state)); - - if (csr & MUSB_CSR0_P_DATAEND) { - /* - * If DATAEND is set we should not call the callback, - * hence the status stage is not complete. - */ - return IRQ_HANDLED; - } - - /* I sent a stall.. need to acknowledge it now.. */ - if (csr & MUSB_CSR0_P_SENTSTALL) { - musb_writew(regs, MUSB_CSR0, - csr & ~MUSB_CSR0_P_SENTSTALL); - retval = IRQ_HANDLED; - musb->ep0_state = MUSB_EP0_STAGE_IDLE; - csr = musb_readw(regs, MUSB_CSR0); - } - - /* request ended "early" */ - if (csr & MUSB_CSR0_P_SETUPEND) { - musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SVDSETUPEND); - retval = IRQ_HANDLED; - /* 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\n", - decode_ep0stage(musb->ep0_state)); - } - csr = musb_readw(regs, MUSB_CSR0); - /* NOTE: request may need completion */ - } - - /* docs from Mentor only describe tx, rx, and idle/setup states. - * we need to handle nuances around status stages, and also the - * case where status and setup stages come back-to-back ... - */ - switch (musb->ep0_state) { - - case MUSB_EP0_STAGE_TX: - /* irq on clearing txpktrdy */ - if ((csr & MUSB_CSR0_TXPKTRDY) == 0) { - ep0_txstate(musb); - retval = IRQ_HANDLED; - } - break; - - case MUSB_EP0_STAGE_RX: - /* irq on set rxpktrdy */ - if (csr & MUSB_CSR0_RXPKTRDY) { - ep0_rxstate(musb); - retval = IRQ_HANDLED; - } - break; - - case MUSB_EP0_STAGE_STATUSIN: - /* end of sequence #2 (OUT/RX state) or #3 (no data) */ - - /* update address (if needed) only @ the end of the - * status phase per usb spec, which also guarantees - * we get 10 msec to receive this irq... until this - * is done we won't see the next packet. - */ - if (musb->set_address) { - musb->set_address = false; - musb_writeb(mbase, MUSB_FADDR, musb->address); - } - - /* enter test mode if needed (exit by reset) */ - else if (musb->test_mode) { - dev_dbg(musb->controller, "entering TESTMODE\n"); - - if (MUSB_TEST_PACKET == musb->test_mode_nr) - musb_load_testpacket(musb); - - musb_writeb(mbase, MUSB_TESTMODE, - musb->test_mode_nr); - } - /* FALLTHROUGH */ - - case MUSB_EP0_STAGE_STATUSOUT: - /* end of sequence #1: write to host (TX state) */ - { - struct musb_request *req; - - req = next_ep0_request(musb); - if (req) - musb_g_ep0_giveback(musb, &req->request); - } - - /* - * 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; - - if (len != 8) { - ERR("SETUP packet len %d != 8 ?\n", len); - break; - } - musb_read_setup(musb, &setup); - retval = IRQ_HANDLED; - - /* sometimes the RESET won't be reported */ - if (unlikely(musb->g.speed == USB_SPEED_UNKNOWN)) { - u8 power; - - printk(KERN_NOTICE "%s: peripheral reset " - "irq lost!\n", - musb_driver_name); - power = musb_readb(mbase, MUSB_POWER); - musb->g.speed = (power & MUSB_POWER_HSMODE) - ? USB_SPEED_HIGH : USB_SPEED_FULL; - - } - - switch (musb->ep0_state) { - - /* sequence #3 (no data stage), includes requests - * we can't forward (notably SET_ADDRESS and the - * device/endpoint feature set/clear operations) - * plus SET_CONFIGURATION and others we must - */ - case MUSB_EP0_STAGE_ACKWAIT: - handled = service_zero_data_request( - musb, &setup); - - /* - * We're expecting no data in any case, so - * always set the DATAEND bit -- doing this - * here helps avoid SetupEnd interrupt coming - * in the idle stage when we're stalling... - */ - musb->ackpend |= MUSB_CSR0_P_DATAEND; - - /* status stage might be immediate */ - if (handled > 0) - musb->ep0_state = - MUSB_EP0_STAGE_STATUSIN; - break; - - /* sequence #1 (IN to host), includes GET_STATUS - * requests that we can't forward, GET_DESCRIPTOR - * and others that we must - */ - case MUSB_EP0_STAGE_TX: - handled = service_in_request(musb, &setup); - if (handled > 0) { - musb->ackpend = MUSB_CSR0_TXPKTRDY - | MUSB_CSR0_P_DATAEND; - musb->ep0_state = - MUSB_EP0_STAGE_STATUSOUT; - } - break; - - /* sequence #2 (OUT from host), always forward */ - default: /* MUSB_EP0_STAGE_RX */ - break; - } - - dev_dbg(musb->controller, "handled %d, csr %04x, ep0stage %s\n", - handled, csr, - decode_ep0stage(musb->ep0_state)); - - /* unless we need to delegate this to the gadget - * driver, we know how to wrap this up: csr0 has - * not yet been written. - */ - if (handled < 0) - goto stall; - else if (handled > 0) - goto finish; - - handled = forward_to_driver(musb, &setup); - if (handled < 0) { - musb_ep_select(mbase, 0); -stall: - dev_dbg(musb->controller, "stall (%d)\n", handled); - musb->ackpend |= MUSB_CSR0_P_SENDSTALL; - musb->ep0_state = MUSB_EP0_STAGE_IDLE; -finish: - musb_writew(regs, MUSB_CSR0, - musb->ackpend); - musb->ackpend = 0; - } - } - break; - - case MUSB_EP0_STAGE_ACKWAIT: - /* This should not happen. But happens with tusb6010 with - * g_file_storage and high speed. Do nothing. - */ - retval = IRQ_HANDLED; - break; - - default: - /* "can't happen" */ - WARN_ON(1); - musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SENDSTALL); - musb->ep0_state = MUSB_EP0_STAGE_IDLE; - break; - } - - return retval; -} - - -static int -musb_g_ep0_enable(struct usb_ep *ep, const struct usb_endpoint_descriptor *desc) -{ - /* always enabled */ - return -EINVAL; -} - -static int musb_g_ep0_disable(struct usb_ep *e) -{ - /* always enabled */ - return -EINVAL; -} - -static int -musb_g_ep0_queue(struct usb_ep *e, struct usb_request *r, gfp_t gfp_flags) -{ - struct musb_ep *ep; - struct musb_request *req; - struct musb *musb; - int status; - unsigned long lockflags; - void __iomem *regs; - - if (!e || !r) - return -EINVAL; - - ep = to_musb_ep(e); - musb = ep->musb; - regs = musb->control_ep->regs; - - req = to_musb_request(r); - req->musb = musb; - req->request.actual = 0; - req->request.status = -EINPROGRESS; - req->tx = ep->is_in; - - spin_lock_irqsave(&musb->lock, lockflags); - - if (!list_empty(&ep->req_list)) { - status = -EBUSY; - goto cleanup; - } - - switch (musb->ep0_state) { - case MUSB_EP0_STAGE_RX: /* control-OUT data */ - case MUSB_EP0_STAGE_TX: /* control-IN data */ - case MUSB_EP0_STAGE_ACKWAIT: /* zero-length data */ - status = 0; - break; - default: - dev_dbg(musb->controller, "ep0 request queued in state %d\n", - musb->ep0_state); - status = -EINVAL; - goto cleanup; - } - - /* add request to the list */ - list_add_tail(&req->list, &ep->req_list); - - dev_dbg(musb->controller, "queue to %s (%s), length=%d\n", - ep->name, ep->is_in ? "IN/TX" : "OUT/RX", - req->request.length); - - musb_ep_select(musb->mregs, 0); - - /* sequence #1, IN ... start writing the data */ - if (musb->ep0_state == MUSB_EP0_STAGE_TX) - ep0_txstate(musb); - - /* sequence #3, no-data ... issue IN status */ - else if (musb->ep0_state == MUSB_EP0_STAGE_ACKWAIT) { - if (req->request.length) - status = -EINVAL; - else { - musb->ep0_state = MUSB_EP0_STAGE_STATUSIN; - musb_writew(regs, MUSB_CSR0, - musb->ackpend | MUSB_CSR0_P_DATAEND); - musb->ackpend = 0; - musb_g_ep0_giveback(ep->musb, r); - } - - /* else for sequence #2 (OUT), caller provides a buffer - * before the next packet arrives. deferred responses - * (after SETUP is acked) are racey. - */ - } else if (musb->ackpend) { - musb_writew(regs, MUSB_CSR0, musb->ackpend); - musb->ackpend = 0; - } - -cleanup: - spin_unlock_irqrestore(&musb->lock, lockflags); - return status; -} - -static int musb_g_ep0_dequeue(struct usb_ep *ep, struct usb_request *req) -{ - /* we just won't support this */ - return -EINVAL; -} - -static int musb_g_ep0_halt(struct usb_ep *e, int value) -{ - struct musb_ep *ep; - struct musb *musb; - void __iomem *base, *regs; - unsigned long flags; - int status; - u16 csr; - - if (!e || !value) - return -EINVAL; - - ep = to_musb_ep(e); - musb = ep->musb; - base = musb->mregs; - regs = musb->control_ep->regs; - status = 0; - - spin_lock_irqsave(&musb->lock, flags); - - if (!list_empty(&ep->req_list)) { - status = -EBUSY; - goto cleanup; - } - - musb_ep_select(base, 0); - csr = musb->ackpend; - - switch (musb->ep0_state) { - - /* Stalls are usually issued after parsing SETUP packet, either - * directly in irq context from setup() or else later. - */ - case MUSB_EP0_STAGE_TX: /* control-IN data */ - case MUSB_EP0_STAGE_ACKWAIT: /* STALL for zero-length data */ - case MUSB_EP0_STAGE_RX: /* control-OUT data */ - csr = musb_readw(regs, MUSB_CSR0); - /* FALLTHROUGH */ - - /* It's also OK to issue stalls during callbacks when a non-empty - * DATA stage buffer has been read (or even written). - */ - case MUSB_EP0_STAGE_STATUSIN: /* control-OUT status */ - case MUSB_EP0_STAGE_STATUSOUT: /* control-IN status */ - - csr |= MUSB_CSR0_P_SENDSTALL; - musb_writew(regs, MUSB_CSR0, csr); - musb->ep0_state = MUSB_EP0_STAGE_IDLE; - musb->ackpend = 0; - break; - default: - dev_dbg(musb->controller, "ep0 can't halt in state %d\n", musb->ep0_state); - status = -EINVAL; - } - -cleanup: - spin_unlock_irqrestore(&musb->lock, flags); - return status; -} - -const struct usb_ep_ops musb_g_ep0_ops = { - .enable = musb_g_ep0_enable, - .disable = musb_g_ep0_disable, - .alloc_request = musb_alloc_request, - .free_request = musb_free_request, - .queue = musb_g_ep0_queue, - .dequeue = musb_g_ep0_dequeue, - .set_halt = musb_g_ep0_halt, -}; diff --git a/ANDROID_3.4.5/drivers/usb/musb/musb_host.c b/ANDROID_3.4.5/drivers/usb/musb/musb_host.c deleted file mode 100644 index ef8d7448..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/musb_host.c +++ /dev/null @@ -1,2331 +0,0 @@ -/* - * MUSB OTG driver host support - * - * 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. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "musb_core.h" -#include "musb_host.h" - - -/* MUSB HOST status 22-mar-2006 - * - * - There's still lots of partial code duplication for fault paths, so - * they aren't handled as consistently as they need to be. - * - * - PIO mostly behaved when last tested. - * + including ep0, with all usbtest cases 9, 10 - * + usbtest 14 (ep0out) doesn't seem to run at all - * + double buffered OUT/TX endpoints saw stalls(!) with certain usbtest - * configurations, but otherwise double buffering passes basic tests. - * + for 2.6.N, for N > ~10, needs API changes for hcd framework. - * - * - DMA (CPPI) ... partially behaves, not currently recommended - * + about 1/15 the speed of typical EHCI implementations (PCI) - * + RX, all too often reqpkt seems to misbehave after tx - * + TX, no known issues (other than evident silicon issue) - * - * - DMA (Mentor/OMAP) ...has at least toggle update problems - * - * - [23-feb-2009] minimal traffic scheduling to avoid bulk RX packet - * starvation ... nothing yet for TX, interrupt, or bulk. - * - * - Not tested with HNP, but some SRP paths seem to behave. - * - * NOTE 24-August-2006: - * - * - Bulk traffic finally uses both sides of hardware ep1, freeing up an - * extra endpoint for periodic use enabling hub + keybd + mouse. That - * mostly works, except that with "usbnet" it's easy to trigger cases - * with "ping" where RX loses. (a) ping to davinci, even "ping -f", - * fine; but (b) ping _from_ davinci, even "ping -c 1", ICMP RX loses - * although ARP RX wins. (That test was done with a full speed link.) - */ - - -/* - * NOTE on endpoint usage: - * - * CONTROL transfers all go through ep0. BULK ones go through dedicated IN - * and OUT endpoints ... hardware is dedicated for those "async" queue(s). - * (Yes, bulk _could_ use more of the endpoints than that, and would even - * benefit from it.) - * - * INTERUPPT and ISOCHRONOUS transfers are scheduled to the other endpoints. - * So far that scheduling is both dumb and optimistic: the endpoint will be - * "claimed" until its software queue is no longer refilled. No multiplexing - * of transfers between endpoints, or anything clever. - */ - - -static void musb_ep_program(struct musb *musb, u8 epnum, - struct urb *urb, int is_out, - u8 *buf, u32 offset, u32 len); - -/* - * Clear TX fifo. Needed to avoid BABBLE errors. - */ -static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep) -{ - struct musb *musb = ep->musb; - void __iomem *epio = ep->regs; - u16 csr; - u16 lastcsr = 0; - int retries = 1000; - - csr = musb_readw(epio, MUSB_TXCSR); - while (csr & MUSB_TXCSR_FIFONOTEMPTY) { - if (csr != lastcsr) - dev_dbg(musb->controller, "Host TX FIFONOTEMPTY csr: %02x\n", csr); - lastcsr = csr; - csr |= MUSB_TXCSR_FLUSHFIFO; - musb_writew(epio, MUSB_TXCSR, csr); - csr = musb_readw(epio, MUSB_TXCSR); - if (WARN(retries-- < 1, - "Could not flush host TX%d fifo: csr: %04x\n", - ep->epnum, csr)) - return; - mdelay(1); - } -} - -static void musb_h_ep0_flush_fifo(struct musb_hw_ep *ep) -{ - void __iomem *epio = ep->regs; - u16 csr; - int retries = 5; - - /* scrub any data left in the fifo */ - do { - csr = musb_readw(epio, MUSB_TXCSR); - if (!(csr & (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_RXPKTRDY))) - break; - musb_writew(epio, MUSB_TXCSR, MUSB_CSR0_FLUSHFIFO); - csr = musb_readw(epio, MUSB_TXCSR); - udelay(10); - } while (--retries); - - WARN(!retries, "Could not flush host TX%d fifo: csr: %04x\n", - ep->epnum, csr); - - /* and reset for the next transfer */ - musb_writew(epio, MUSB_TXCSR, 0); -} - -/* - * Start transmit. Caller is responsible for locking shared resources. - * musb must be locked. - */ -static inline void musb_h_tx_start(struct musb_hw_ep *ep) -{ - u16 txcsr; - - /* NOTE: no locks here; caller should lock and select EP */ - if (ep->epnum) { - txcsr = musb_readw(ep->regs, MUSB_TXCSR); - txcsr |= MUSB_TXCSR_TXPKTRDY | MUSB_TXCSR_H_WZC_BITS; - musb_writew(ep->regs, MUSB_TXCSR, txcsr); - } else { - txcsr = MUSB_CSR0_H_SETUPPKT | MUSB_CSR0_TXPKTRDY; - musb_writew(ep->regs, MUSB_CSR0, txcsr); - } - -} - -static inline void musb_h_tx_dma_start(struct musb_hw_ep *ep) -{ - u16 txcsr; - - /* NOTE: no locks here; caller should lock and select EP */ - txcsr = musb_readw(ep->regs, MUSB_TXCSR); - txcsr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_H_WZC_BITS; - if (is_cppi_enabled()) - txcsr |= MUSB_TXCSR_DMAMODE; - 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. - * - * Context: controller locked, irqs blocked - */ -static void -musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh) -{ - u16 frame; - u32 len; - void __iomem *mbase = musb->mregs; - struct urb *urb = next_urb(qh); - void *buf = urb->transfer_buffer; - u32 offset = 0; - struct musb_hw_ep *hw_ep = qh->hw_ep; - unsigned pipe = urb->pipe; - u8 address = usb_pipedevice(pipe); - int epnum = hw_ep->epnum; - - /* initialize software qh state */ - qh->offset = 0; - qh->segsize = 0; - - /* gather right source of data */ - switch (qh->type) { - case USB_ENDPOINT_XFER_CONTROL: - /* control transfers always start with SETUP */ - is_in = 0; - musb->ep0_stage = MUSB_EP0_START; - buf = urb->setup_packet; - len = 8; - break; - case USB_ENDPOINT_XFER_ISOC: - qh->iso_idx = 0; - qh->frame = 0; - offset = urb->iso_frame_desc[0].offset; - len = urb->iso_frame_desc[0].length; - break; - default: /* bulk, interrupt */ - /* actual_length may be nonzero on retry paths */ - buf = urb->transfer_buffer + urb->actual_length; - len = urb->transfer_buffer_length - urb->actual_length; - } - - dev_dbg(musb->controller, "qh %p urb %p dev%d ep%d%s%s, hw_ep %d, %p/%d\n", - qh, urb, address, qh->epnum, - is_in ? "in" : "out", - ({char *s; switch (qh->type) { - case USB_ENDPOINT_XFER_CONTROL: s = ""; break; - case USB_ENDPOINT_XFER_BULK: s = "-bulk"; break; - case USB_ENDPOINT_XFER_ISOC: s = "-iso"; break; - default: s = "-intr"; break; - }; s; }), - epnum, buf + offset, len); - - /* Configure endpoint */ - 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 */ - if (is_in) - return; - - /* determine if the time is right for a periodic transfer */ - switch (qh->type) { - case USB_ENDPOINT_XFER_ISOC: - case USB_ENDPOINT_XFER_INT: - dev_dbg(musb->controller, "check whether there's still time for periodic Tx\n"); - frame = musb_readw(mbase, MUSB_FRAME); - /* FIXME this doesn't implement that scheduling policy ... - * or handle framecounter wrapping - */ - if ((urb->transfer_flags & URB_ISO_ASAP) - || (frame >= urb->start_frame)) { - /* REVISIT the SOF irq handler shouldn't duplicate - * this code; and we don't init urb->start_frame... - */ - qh->frame = 0; - goto start; - } else { - qh->frame = urb->start_frame; - /* enable SOF interrupt so we can count down */ - dev_dbg(musb->controller, "SOF for %d\n", epnum); -#if 1 /* ifndef CONFIG_ARCH_DAVINCI */ - musb_writeb(mbase, MUSB_INTRUSBE, 0xff); -#endif - } - break; - default: -start: - dev_dbg(musb->controller, "Start TX%d %s\n", epnum, - hw_ep->tx_channel ? "dma" : "pio"); - - if (!hw_ep->tx_channel) - musb_h_tx_start(hw_ep); - else if (is_cppi_enabled() || tusb_dma_omap()) - musb_h_tx_dma_start(hw_ep); - } -} - -/* 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) -{ - dev_dbg(musb->controller, - "complete %p %pF (%d), dev%d ep%d%s, %d/%d\n", - urb, urb->complete, status, - usb_pipedevice(urb->pipe), - usb_pipeendpoint(urb->pipe), - usb_pipein(urb->pipe) ? "in" : "out", - urb->actual_length, urb->transfer_buffer_length - ); - - usb_hcd_unlink_urb_from_ep(musb_to_hcd(musb), urb); - spin_unlock(&musb->lock); - usb_hcd_giveback_urb(musb_to_hcd(musb), urb, status); - spin_lock(&musb->lock); -} - -/* For bulk/interrupt endpoints only */ -static inline void musb_save_toggle(struct musb_qh *qh, int is_in, - struct urb *urb) -{ - void __iomem *epio = qh->hw_ep->regs; - u16 csr; - - /* - * FIXME: the current Mentor DMA code seems to have - * problems getting toggle correct. - */ - - if (is_in) - csr = musb_readw(epio, MUSB_RXCSR) & MUSB_RXCSR_H_DATATOGGLE; - else - csr = musb_readw(epio, MUSB_TXCSR) & MUSB_TXCSR_H_DATATOGGLE; - - usb_settoggle(urb->dev, qh->epnum, !is_in, csr ? 1 : 0); -} - -/* - * 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; - 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(qh, is_in, urb); - break; - case USB_ENDPOINT_XFER_ISOC: - if (status == 0 && urb->error_count) - status = -EXDEV; - break; - } - - qh->is_ready = 0; - musb_giveback(musb, urb, status); - qh->is_ready = ready; - - /* reclaim resources (and bandwidth) ASAP; deschedule it, and - * invalidate qh as soon as list_empty(&hep->urb_list) - */ - if (list_empty(&qh->hep->urb_list)) { - struct list_head *head; - - if (is_in) - ep->rx_reinit = 1; - else - ep->tx_reinit = 1; - - /* Clobber old pointers to this qh */ - musb_ep_set_qh(ep, is_in, NULL); - qh->hep->hcpriv = NULL; - - switch (qh->type) { - - case USB_ENDPOINT_XFER_CONTROL: - case USB_ENDPOINT_XFER_BULK: - /* fifo policy for these lists, except that NAKing - * should rotate a qh to the end (for fairness). - */ - if (qh->mux == 1) { - head = qh->ring.prev; - list_del(&qh->ring); - kfree(qh); - qh = first_qh(head); - break; - } - - case USB_ENDPOINT_XFER_ISOC: - case USB_ENDPOINT_XFER_INT: - /* this is where periodic bandwidth should be - * de-allocated if it's tracked and allocated; - * and where we'd update the schedule tree... - */ - kfree(qh); - qh = NULL; - break; - } - } - - if (qh != NULL && qh->is_ready) { - dev_dbg(musb->controller, "... next ep%d %cX urb %p\n", - hw_ep->epnum, is_in ? 'R' : 'T', next_urb(qh)); - musb_start_urb(musb, is_in, qh); - } -} - -static u16 musb_h_flush_rxfifo(struct musb_hw_ep *hw_ep, u16 csr) -{ - /* we don't want fifo to fill itself again; - * ignore dma (various models), - * leave toggle alone (may not have been saved yet) - */ - csr |= MUSB_RXCSR_FLUSHFIFO | MUSB_RXCSR_RXPKTRDY; - csr &= ~(MUSB_RXCSR_H_REQPKT - | MUSB_RXCSR_H_AUTOREQ - | MUSB_RXCSR_AUTOCLEAR); - - /* write 2x to allow double buffering */ - musb_writew(hw_ep->regs, MUSB_RXCSR, csr); - musb_writew(hw_ep->regs, MUSB_RXCSR, csr); - - /* flush writebuffer */ - return musb_readw(hw_ep->regs, MUSB_RXCSR); -} - -/* - * PIO RX for a packet (or part of it). - */ -static bool -musb_host_packet_rx(struct musb *musb, struct urb *urb, u8 epnum, u8 iso_err) -{ - u16 rx_count; - u8 *buf; - u16 csr; - bool done = false; - u32 length; - int do_flush = 0; - struct musb_hw_ep *hw_ep = musb->endpoints + epnum; - void __iomem *epio = hw_ep->regs; - struct musb_qh *qh = hw_ep->in_qh; - int pipe = urb->pipe; - void *buffer = urb->transfer_buffer; - - /* musb_ep_select(mbase, epnum); */ - rx_count = musb_readw(epio, MUSB_RXCOUNT); - dev_dbg(musb->controller, "RX%d count %d, buffer %p len %d/%d\n", epnum, rx_count, - urb->transfer_buffer, qh->offset, - urb->transfer_buffer_length); - - /* unload FIFO */ - if (usb_pipeisoc(pipe)) { - int status = 0; - struct usb_iso_packet_descriptor *d; - - if (iso_err) { - status = -EILSEQ; - urb->error_count++; - } - - d = urb->iso_frame_desc + qh->iso_idx; - buf = buffer + d->offset; - length = d->length; - if (rx_count > length) { - if (status == 0) { - status = -EOVERFLOW; - urb->error_count++; - } - dev_dbg(musb->controller, "** OVERFLOW %d into %d\n", rx_count, length); - do_flush = 1; - } else - length = rx_count; - urb->actual_length += length; - d->actual_length = length; - - d->status = status; - - /* see if we are done */ - done = (++qh->iso_idx >= urb->number_of_packets); - } else { - /* non-isoch */ - buf = buffer + qh->offset; - length = urb->transfer_buffer_length - qh->offset; - if (rx_count > length) { - if (urb->status == -EINPROGRESS) - urb->status = -EOVERFLOW; - dev_dbg(musb->controller, "** OVERFLOW %d into %d\n", rx_count, length); - do_flush = 1; - } else - length = rx_count; - urb->actual_length += length; - qh->offset += length; - - /* see if we are done */ - done = (urb->actual_length == urb->transfer_buffer_length) - || (rx_count < qh->maxpacket) - || (urb->status != -EINPROGRESS); - if (done - && (urb->status == -EINPROGRESS) - && (urb->transfer_flags & URB_SHORT_NOT_OK) - && (urb->actual_length - < urb->transfer_buffer_length)) - urb->status = -EREMOTEIO; - } - - musb_read_fifo(hw_ep, length, buf); - - csr = musb_readw(epio, MUSB_RXCSR); - csr |= MUSB_RXCSR_H_WZC_BITS; - if (unlikely(do_flush)) - musb_h_flush_rxfifo(hw_ep, csr); - else { - /* REVISIT this assumes AUTOCLEAR is never set */ - csr &= ~(MUSB_RXCSR_RXPKTRDY | MUSB_RXCSR_H_REQPKT); - if (!done) - csr |= MUSB_RXCSR_H_REQPKT; - musb_writew(epio, MUSB_RXCSR, csr); - } - - return done; -} - -/* we don't always need to reinit a given side of an endpoint... - * when we do, use tx/rx reinit routine and then construct a new CSR - * to address data toggle, NYET, and DMA or PIO. - * - * it's possible that driver bugs (especially for DMA) or aborting a - * transfer might have left the endpoint busier than it should be. - * the busy/not-empty tests are basically paranoia. - */ -static void -musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep) -{ - u16 csr; - - /* NOTE: we know the "rx" fifo reinit never triggers for ep0. - * That always uses tx_reinit since ep0 repurposes TX register - * offsets; the initial SETUP packet is also a kind of OUT. - */ - - /* if programmed for Tx, put it in RX mode */ - if (ep->is_shared_fifo) { - csr = musb_readw(ep->regs, MUSB_TXCSR); - if (csr & MUSB_TXCSR_MODE) { - musb_h_tx_flush_fifo(ep); - csr = musb_readw(ep->regs, MUSB_TXCSR); - musb_writew(ep->regs, MUSB_TXCSR, - csr | MUSB_TXCSR_FRCDATATOG); - } - - /* - * Clear the MODE bit (and everything else) to enable Rx. - * NOTE: we mustn't clear the DMAMODE bit before DMAENAB. - */ - if (csr & MUSB_TXCSR_DMAMODE) - musb_writew(ep->regs, MUSB_TXCSR, MUSB_TXCSR_DMAMODE); - musb_writew(ep->regs, MUSB_TXCSR, 0); - - /* scrub all previous state, clearing toggle */ - } else { - csr = musb_readw(ep->regs, MUSB_RXCSR); - if (csr & MUSB_RXCSR_RXPKTRDY) - WARNING("rx%d, packet/%d ready?\n", ep->epnum, - musb_readw(ep->regs, MUSB_RXCOUNT)); - - musb_h_flush_rxfifo(ep, MUSB_RXCSR_CLRDATATOG); - } - - /* target addr and (for multipoint) hub addr/port */ - if (musb->is_multipoint) { - musb_write_rxfunaddr(ep->target_regs, qh->addr_reg); - musb_write_rxhubaddr(ep->target_regs, qh->h_addr_reg); - musb_write_rxhubport(ep->target_regs, qh->h_port_reg); - - } else - musb_writeb(musb->mregs, MUSB_FADDR, qh->addr_reg); - - /* protocol/endpoint, interval/NAKlimit, i/o size */ - 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 */ - /* Set RXMAXP with the FIFO size of the endpoint - * to disable double buffer mode. - */ - if (musb->double_buffer_not_ok) - musb_writew(ep->regs, MUSB_RXMAXP, ep->max_packet_sz_rx); - else - musb_writew(ep->regs, MUSB_RXMAXP, - qh->maxpacket | ((qh->hb_mult - 1) << 11)); - - ep->rx_reinit = 0; -} - -static bool musb_tx_dma_program(struct dma_controller *dma, - struct musb_hw_ep *hw_ep, struct musb_qh *qh, - struct urb *urb, u32 offset, u32 length) -{ - struct dma_channel *channel = hw_ep->tx_channel; - void __iomem *epio = hw_ep->regs; - u16 pkt_size = qh->maxpacket; - u16 csr; - u8 mode; - -#ifdef CONFIG_USB_INVENTRA_DMA - if (length > channel->max_len) - length = channel->max_len; - - csr = musb_readw(epio, MUSB_TXCSR); - if (length > pkt_size) { - mode = 1; - 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); - csr |= MUSB_TXCSR_DMAENAB; /* against programmer's guide */ - } - channel->desired_mode = mode; - musb_writew(epio, MUSB_TXCSR, csr); -#else - if (!is_cppi_enabled() && !tusb_dma_omap()) - return false; - - channel->actual_len = 0; - - /* - * TX uses "RNDIS" mode automatically but needs help - * to identify the zero-length-final-packet case. - */ - mode = (urb->transfer_flags & URB_ZERO_PACKET) ? 1 : 0; -#endif - - qh->segsize = length; - - /* - * Ensure the data reaches to main memory before starting - * DMA transfer - */ - wmb(); - - if (!dma->channel_program(channel, pkt_size, mode, - urb->transfer_dma + offset, length)) { - dma->channel_release(channel); - hw_ep->tx_channel = NULL; - - csr = musb_readw(epio, MUSB_TXCSR); - csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAENAB); - musb_writew(epio, MUSB_TXCSR, csr | MUSB_TXCSR_H_WZC_BITS); - return false; - } - return true; -} - -/* - * Program an HDRC endpoint as per the given URB - * Context: irqs blocked, controller lock held - */ -static void musb_ep_program(struct musb *musb, u8 epnum, - struct urb *urb, int is_out, - u8 *buf, u32 offset, u32 len) -{ - struct dma_controller *dma_controller; - struct dma_channel *dma_channel; - u8 dma_ok; - void __iomem *mbase = musb->mregs; - struct musb_hw_ep *hw_ep = musb->endpoints + epnum; - void __iomem *epio = hw_ep->regs; - struct musb_qh *qh = musb_ep_get_qh(hw_ep, !is_out); - u16 packet_sz = qh->maxpacket; - - dev_dbg(musb->controller, "%s hw%d urb %p spd%d dev%d ep%d%s " - "h_addr%02x h_port%02x bytes %d\n", - is_out ? "-->" : "<--", - epnum, urb, urb->dev->speed, - qh->addr_reg, qh->epnum, is_out ? "out" : "in", - qh->h_addr_reg, qh->h_port_reg, - len); - - musb_ep_select(mbase, epnum); - - /* candidate for DMA? */ - dma_controller = musb->dma_controller; - if (is_dma_capable() && epnum && dma_controller) { - dma_channel = is_out ? hw_ep->tx_channel : hw_ep->rx_channel; - if (!dma_channel) { - dma_channel = dma_controller->channel_alloc( - dma_controller, hw_ep, is_out); - if (is_out) - hw_ep->tx_channel = dma_channel; - else - hw_ep->rx_channel = dma_channel; - } - } else - dma_channel = NULL; - - /* make sure we clear DMAEnab, autoSet bits from previous run */ - - /* OUT/transmit/EP0 or IN/receive? */ - if (is_out) { - u16 csr; - u16 int_txe; - u16 load_count; - - csr = musb_readw(epio, MUSB_TXCSR); - - /* disable interrupt in case we flush */ - int_txe = musb_readw(mbase, MUSB_INTRTXE); - musb_writew(mbase, MUSB_INTRTXE, int_txe & ~(1 << epnum)); - - /* general endpoint setup */ - if (epnum) { - /* flush all old state, set default */ - musb_h_tx_flush_fifo(hw_ep); - - /* - * We must not clear the DMAMODE bit before or in - * the same cycle with the DMAENAB bit, so we clear - * the latter first... - */ - csr &= ~(MUSB_TXCSR_H_NAKTIMEOUT - | MUSB_TXCSR_AUTOSET - | MUSB_TXCSR_DMAENAB - | MUSB_TXCSR_FRCDATATOG - | MUSB_TXCSR_H_RXSTALL - | MUSB_TXCSR_H_ERROR - | MUSB_TXCSR_TXPKTRDY - ); - csr |= MUSB_TXCSR_MODE; - - if (usb_gettoggle(urb->dev, qh->epnum, 1)) - csr |= MUSB_TXCSR_H_WR_DATATOGGLE - | MUSB_TXCSR_H_DATATOGGLE; - else - csr |= MUSB_TXCSR_CLRDATATOG; - - musb_writew(epio, MUSB_TXCSR, csr); - /* REVISIT may need to clear FLUSHFIFO ... */ - csr &= ~MUSB_TXCSR_DMAMODE; - musb_writew(epio, MUSB_TXCSR, csr); - csr = musb_readw(epio, MUSB_TXCSR); - } else { - /* endpoint 0: just flush */ - musb_h_ep0_flush_fifo(hw_ep); - } - - /* target addr and (for multipoint) hub addr/port */ - if (musb->is_multipoint) { - musb_write_txfunaddr(mbase, epnum, qh->addr_reg); - musb_write_txhubaddr(mbase, epnum, qh->h_addr_reg); - musb_write_txhubport(mbase, epnum, qh->h_port_reg); -/* FIXME if !epnum, do the same for RX ... */ - } else - musb_writeb(mbase, MUSB_FADDR, qh->addr_reg); - - /* protocol/endpoint/interval/NAKlimit */ - if (epnum) { - musb_writeb(epio, MUSB_TXTYPE, qh->type_reg); - if (musb->double_buffer_not_ok) - musb_writew(epio, MUSB_TXMAXP, - hw_ep->max_packet_sz_tx); - else if (can_bulk_split(musb, qh->type)) - musb_writew(epio, MUSB_TXMAXP, packet_sz - | ((hw_ep->max_packet_sz_tx / - packet_sz) - 1) << 11); - else - musb_writew(epio, MUSB_TXMAXP, - qh->maxpacket | - ((qh->hb_mult - 1) << 11)); - musb_writeb(epio, MUSB_TXINTERVAL, qh->intv_reg); - } else { - musb_writeb(epio, MUSB_NAKLIMIT0, qh->intv_reg); - if (musb->is_multipoint) - musb_writeb(epio, MUSB_TYPE0, - qh->type_reg); - } - - if (can_bulk_split(musb, qh->type)) - load_count = min((u32) hw_ep->max_packet_sz_tx, - len); - else - load_count = min((u32) packet_sz, len); - - if (dma_channel && musb_tx_dma_program(dma_controller, - hw_ep, qh, urb, offset, len)) - load_count = 0; - - if (load_count) { - /* PIO to load FIFO */ - qh->segsize = load_count; - musb_write_fifo(hw_ep, load_count, buf); - } - - /* re-enable interrupt */ - musb_writew(mbase, MUSB_INTRTXE, int_txe); - - /* IN/receive */ - } else { - u16 csr; - - if (hw_ep->rx_reinit) { - musb_rx_reinit(musb, qh, hw_ep); - - /* init new state: toggle and NYET, maybe DMA later */ - if (usb_gettoggle(urb->dev, qh->epnum, 0)) - csr = MUSB_RXCSR_H_WR_DATATOGGLE - | MUSB_RXCSR_H_DATATOGGLE; - else - csr = 0; - if (qh->type == USB_ENDPOINT_XFER_INT) - csr |= MUSB_RXCSR_DISNYET; - - } else { - csr = musb_readw(hw_ep->regs, MUSB_RXCSR); - - if (csr & (MUSB_RXCSR_RXPKTRDY - | MUSB_RXCSR_DMAENAB - | MUSB_RXCSR_H_REQPKT)) - ERR("broken !rx_reinit, ep%d csr %04x\n", - hw_ep->epnum, csr); - - /* scrub any stale state, leaving toggle alone */ - csr &= MUSB_RXCSR_DISNYET; - } - - /* kick things off */ - - if ((is_cppi_enabled() || tusb_dma_omap()) && dma_channel) { - /* Candidate for DMA */ - dma_channel->actual_len = 0L; - qh->segsize = len; - - /* AUTOREQ is in a DMA register */ - musb_writew(hw_ep->regs, MUSB_RXCSR, csr); - csr = musb_readw(hw_ep->regs, MUSB_RXCSR); - - /* - * Unless caller treats short RX transfers as - * errors, we dare not queue multiple transfers. - */ - dma_ok = dma_controller->channel_program(dma_channel, - packet_sz, !(urb->transfer_flags & - URB_SHORT_NOT_OK), - urb->transfer_dma + offset, - qh->segsize); - if (!dma_ok) { - dma_controller->channel_release(dma_channel); - hw_ep->rx_channel = dma_channel = NULL; - } else - csr |= MUSB_RXCSR_DMAENAB; - } - - csr |= MUSB_RXCSR_H_REQPKT; - dev_dbg(musb->controller, "RXCSR%d := %04x\n", epnum, csr); - musb_writew(hw_ep->regs, MUSB_RXCSR, csr); - csr = musb_readw(hw_ep->regs, MUSB_RXCSR); - } -} - - -/* - * Service the default endpoint (ep0) as host. - * Return true until it's time to start the status stage. - */ -static bool musb_h_ep0_continue(struct musb *musb, u16 len, struct urb *urb) -{ - bool more = false; - u8 *fifo_dest = NULL; - u16 fifo_count = 0; - struct musb_hw_ep *hw_ep = musb->control_ep; - struct musb_qh *qh = hw_ep->in_qh; - struct usb_ctrlrequest *request; - - switch (musb->ep0_stage) { - case MUSB_EP0_IN: - fifo_dest = urb->transfer_buffer + urb->actual_length; - fifo_count = min_t(size_t, len, urb->transfer_buffer_length - - urb->actual_length); - if (fifo_count < len) - urb->status = -EOVERFLOW; - - musb_read_fifo(hw_ep, fifo_count, fifo_dest); - - urb->actual_length += fifo_count; - if (len < qh->maxpacket) { - /* always terminate on short read; it's - * rarely reported as an error. - */ - } else if (urb->actual_length < - urb->transfer_buffer_length) - more = true; - break; - case MUSB_EP0_START: - request = (struct usb_ctrlrequest *) urb->setup_packet; - - if (!request->wLength) { - dev_dbg(musb->controller, "start no-DATA\n"); - break; - } else if (request->bRequestType & USB_DIR_IN) { - dev_dbg(musb->controller, "start IN-DATA\n"); - musb->ep0_stage = MUSB_EP0_IN; - more = true; - break; - } else { - dev_dbg(musb->controller, "start OUT-DATA\n"); - musb->ep0_stage = MUSB_EP0_OUT; - more = true; - } - /* FALLTHROUGH */ - case MUSB_EP0_OUT: - fifo_count = min_t(size_t, qh->maxpacket, - urb->transfer_buffer_length - - urb->actual_length); - if (fifo_count) { - fifo_dest = (u8 *) (urb->transfer_buffer - + urb->actual_length); - dev_dbg(musb->controller, "Sending %d byte%s to ep0 fifo %p\n", - fifo_count, - (fifo_count == 1) ? "" : "s", - fifo_dest); - musb_write_fifo(hw_ep, fifo_count, fifo_dest); - - urb->actual_length += fifo_count; - more = true; - } - break; - default: - ERR("bogus ep0 stage %d\n", musb->ep0_stage); - break; - } - - return more; -} - -/* - * Handle default endpoint interrupt as host. Only called in IRQ time - * from musb_interrupt(). - * - * called with controller irqlocked - */ -irqreturn_t musb_h_ep0_irq(struct musb *musb) -{ - struct urb *urb; - u16 csr, len; - int status = 0; - void __iomem *mbase = musb->mregs; - struct musb_hw_ep *hw_ep = musb->control_ep; - void __iomem *epio = hw_ep->regs; - struct musb_qh *qh = hw_ep->in_qh; - bool complete = false; - irqreturn_t retval = IRQ_NONE; - - /* ep0 only has one queue, "in" */ - urb = next_urb(qh); - - musb_ep_select(mbase, 0); - csr = musb_readw(epio, MUSB_CSR0); - len = (csr & MUSB_CSR0_RXPKTRDY) - ? musb_readb(epio, MUSB_COUNT0) - : 0; - - dev_dbg(musb->controller, "<== csr0 %04x, qh %p, count %d, urb %p, stage %d\n", - csr, qh, len, urb, musb->ep0_stage); - - /* if we just did status stage, we are done */ - if (MUSB_EP0_STATUS == musb->ep0_stage) { - retval = IRQ_HANDLED; - complete = true; - } - - /* prepare status */ - if (csr & MUSB_CSR0_H_RXSTALL) { - dev_dbg(musb->controller, "STALLING ENDPOINT\n"); - status = -EPIPE; - - } else if (csr & MUSB_CSR0_H_ERROR) { - dev_dbg(musb->controller, "no response, csr0 %04x\n", csr); - status = -EPROTO; - - } else if (csr & MUSB_CSR0_H_NAKTIMEOUT) { - dev_dbg(musb->controller, "control NAK timeout\n"); - - /* NOTE: this code path would be a good place to PAUSE a - * control transfer, if another one is queued, so that - * ep0 is more likely to stay busy. That's already done - * for bulk RX transfers. - * - * if (qh->ring.next != &musb->control), then - * we have a candidate... NAKing is *NOT* an error - */ - musb_writew(epio, MUSB_CSR0, 0); - retval = IRQ_HANDLED; - } - - if (status) { - dev_dbg(musb->controller, "aborting\n"); - retval = IRQ_HANDLED; - if (urb) - urb->status = status; - complete = true; - - /* use the proper sequence to abort the transfer */ - if (csr & MUSB_CSR0_H_REQPKT) { - csr &= ~MUSB_CSR0_H_REQPKT; - musb_writew(epio, MUSB_CSR0, csr); - csr &= ~MUSB_CSR0_H_NAKTIMEOUT; - musb_writew(epio, MUSB_CSR0, csr); - } else { - musb_h_ep0_flush_fifo(hw_ep); - } - - musb_writeb(epio, MUSB_NAKLIMIT0, 0); - - /* clear it */ - musb_writew(epio, MUSB_CSR0, 0); - } - - if (unlikely(!urb)) { - /* stop endpoint since we have no place for its data, this - * SHOULD NEVER HAPPEN! */ - ERR("no URB for end 0\n"); - - musb_h_ep0_flush_fifo(hw_ep); - goto done; - } - - if (!complete) { - /* call common logic and prepare response */ - if (musb_h_ep0_continue(musb, len, urb)) { - /* more packets required */ - csr = (MUSB_EP0_IN == musb->ep0_stage) - ? MUSB_CSR0_H_REQPKT : MUSB_CSR0_TXPKTRDY; - } else { - /* data transfer complete; perform status phase */ - if (usb_pipeout(urb->pipe) - || !urb->transfer_buffer_length) - csr = MUSB_CSR0_H_STATUSPKT - | MUSB_CSR0_H_REQPKT; - else - csr = MUSB_CSR0_H_STATUSPKT - | MUSB_CSR0_TXPKTRDY; - - /* flag status stage */ - musb->ep0_stage = MUSB_EP0_STATUS; - - dev_dbg(musb->controller, "ep0 STATUS, csr %04x\n", csr); - - } - musb_writew(epio, MUSB_CSR0, csr); - retval = IRQ_HANDLED; - } else - musb->ep0_stage = MUSB_EP0_IDLE; - - /* call completion handler if done */ - if (complete) - musb_advance_schedule(musb, urb, hw_ep, 1); -done: - return retval; -} - - -#ifdef CONFIG_USB_INVENTRA_DMA - -/* Host side TX (OUT) using Mentor DMA works as follows: - submit_urb -> - - if queue was empty, Program Endpoint - - ... which starts DMA to fifo in mode 1 or 0 - - DMA Isr (transfer complete) -> TxAvail() - - Stop DMA (~DmaEnab) (<--- Alert ... currently happens - only in musb_cleanup_urb) - - TxPktRdy has to be set in mode 0 or for - short packets in mode 1. -*/ - -#endif - -/* Service a Tx-Available or dma completion irq for the endpoint */ -void musb_host_tx(struct musb *musb, u8 epnum) -{ - int pipe; - bool done = false; - u16 tx_csr; - size_t length = 0; - size_t offset = 0; - struct musb_hw_ep *hw_ep = musb->endpoints + epnum; - void __iomem *epio = hw_ep->regs; - 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; - bool transfer_pending = false; - - musb_ep_select(mbase, epnum); - tx_csr = musb_readw(epio, MUSB_TXCSR); - - /* with CPPI, DMA sometimes triggers "extra" irqs */ - if (!urb) { - dev_dbg(musb->controller, "extra TX%d ready, csr %04x\n", epnum, tx_csr); - return; - } - - pipe = urb->pipe; - dma = is_dma_capable() ? hw_ep->tx_channel : NULL; - dev_dbg(musb->controller, "OUT/TX%d end, csr %04x%s\n", epnum, tx_csr, - dma ? ", dma" : ""); - - /* check for errors */ - if (tx_csr & MUSB_TXCSR_H_RXSTALL) { - /* dma was disabled, fifo flushed */ - dev_dbg(musb->controller, "TX end %d stall\n", epnum); - - /* stall; record URB status */ - status = -EPIPE; - - } else if (tx_csr & MUSB_TXCSR_H_ERROR) { - /* (NON-ISO) dma was disabled, fifo flushed */ - dev_dbg(musb->controller, "TX 3strikes on ep=%d\n", epnum); - - status = -ETIMEDOUT; - - } else if (tx_csr & MUSB_TXCSR_H_NAKTIMEOUT) { - dev_dbg(musb->controller, "TX end=%d device not responding\n", epnum); - - /* NOTE: this code path would be a good place to PAUSE a - * transfer, if there's some other (nonperiodic) tx urb - * that could use this fifo. (dma complicates it...) - * That's already done for bulk RX transfers. - * - * if (bulk && qh->ring.next != &musb->out_bulk), then - * we have a candidate... NAKing is *NOT* an error - */ - musb_ep_select(mbase, epnum); - musb_writew(epio, MUSB_TXCSR, - MUSB_TXCSR_H_WZC_BITS - | MUSB_TXCSR_TXPKTRDY); - return; - } - - if (status) { - if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { - dma->status = MUSB_DMA_STATUS_CORE_ABORT; - (void) musb->dma_controller->channel_abort(dma); - } - - /* do the proper sequence to abort the transfer in the - * usb core; the dma engine should already be stopped. - */ - musb_h_tx_flush_fifo(hw_ep); - tx_csr &= ~(MUSB_TXCSR_AUTOSET - | MUSB_TXCSR_DMAENAB - | MUSB_TXCSR_H_ERROR - | MUSB_TXCSR_H_RXSTALL - | MUSB_TXCSR_H_NAKTIMEOUT - ); - - musb_ep_select(mbase, epnum); - musb_writew(epio, MUSB_TXCSR, tx_csr); - /* REVISIT may need to clear FLUSHFIFO ... */ - musb_writew(epio, MUSB_TXCSR, tx_csr); - musb_writeb(epio, MUSB_TXINTERVAL, 0); - - done = true; - } - - /* second cppi case */ - if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { - dev_dbg(musb->controller, "extra TX%d ready, csr %04x\n", epnum, tx_csr); - return; - } - - if (is_dma_capable() && dma && !status) { - /* - * DMA has completed. But if we're using DMA mode 1 (multi - * packet DMA), we need a terminal TXPKTRDY interrupt before - * we can consider this transfer completed, lest we trash - * its last packet when writing the next URB's data. So we - * switch back to mode 0 to get that interrupt; we'll come - * back here once it happens. - */ - if (tx_csr & MUSB_TXCSR_DMAMODE) { - /* - * We shouldn't clear DMAMODE with DMAENAB set; so - * clear them in a safe order. That should be OK - * once TXPKTRDY has been set (and I've never seen - * it being 0 at this moment -- DMA interrupt latency - * is significant) but if it hasn't been then we have - * no choice but to stop being polite and ignore the - * programmer's guide... :-) - * - * Note that we must write TXCSR with TXPKTRDY cleared - * in order not to re-trigger the packet send (this bit - * can't be cleared by CPU), and there's another caveat: - * TXPKTRDY may be set shortly and then cleared in the - * double-buffered FIFO mode, so we do an extra TXCSR - * read for debouncing... - */ - tx_csr &= musb_readw(epio, MUSB_TXCSR); - if (tx_csr & MUSB_TXCSR_TXPKTRDY) { - tx_csr &= ~(MUSB_TXCSR_DMAENAB | - MUSB_TXCSR_TXPKTRDY); - musb_writew(epio, MUSB_TXCSR, - tx_csr | MUSB_TXCSR_H_WZC_BITS); - } - tx_csr &= ~(MUSB_TXCSR_DMAMODE | - MUSB_TXCSR_TXPKTRDY); - musb_writew(epio, MUSB_TXCSR, - tx_csr | MUSB_TXCSR_H_WZC_BITS); - - /* - * There is no guarantee that we'll get an interrupt - * after clearing DMAMODE as we might have done this - * too late (after TXPKTRDY was cleared by controller). - * Re-read TXCSR as we have spoiled its previous value. - */ - tx_csr = musb_readw(epio, MUSB_TXCSR); - } - - /* - * We may get here from a DMA completion or TXPKTRDY interrupt. - * In any case, we must check the FIFO status here and bail out - * only if the FIFO still has data -- that should prevent the - * "missed" TXPKTRDY interrupts and deal with double-buffered - * FIFO mode too... - */ - if (tx_csr & (MUSB_TXCSR_FIFONOTEMPTY | MUSB_TXCSR_TXPKTRDY)) { - dev_dbg(musb->controller, "DMA complete but packet still in FIFO, " - "CSR %04x\n", tx_csr); - return; - } - } - - if (!status || dma || usb_pipeisoc(pipe)) { - if (dma) - length = dma->actual_len; - else - length = qh->segsize; - qh->offset += length; - - if (usb_pipeisoc(pipe)) { - struct usb_iso_packet_descriptor *d; - - d = urb->iso_frame_desc + qh->iso_idx; - d->actual_length = length; - d->status = status; - if (++qh->iso_idx >= urb->number_of_packets) { - done = true; - } else { - d++; - offset = d->offset; - length = d->length; - } - } else if (dma && urb->transfer_buffer_length == qh->offset) { - done = true; - } else { - /* see if we need to send more data, or ZLP */ - if (qh->segsize < qh->maxpacket) - done = true; - else if (qh->offset == urb->transfer_buffer_length - && !(urb->transfer_flags - & URB_ZERO_PACKET)) - done = true; - if (!done) { - offset = qh->offset; - length = urb->transfer_buffer_length - offset; - transfer_pending = true; - } - } - } - - /* urb->status != -EINPROGRESS means request has been faulted, - * so we must abort this transfer after cleanup - */ - if (urb->status != -EINPROGRESS) { - done = true; - if (status == 0) - status = urb->status; - } - - if (done) { - /* set status */ - urb->status = status; - urb->actual_length = qh->offset; - musb_advance_schedule(musb, urb, hw_ep, USB_DIR_OUT); - return; - } else if ((usb_pipeisoc(pipe) || transfer_pending) && dma) { - if (musb_tx_dma_program(musb->dma_controller, hw_ep, qh, urb, - offset, length)) { - if (is_cppi_enabled() || tusb_dma_omap()) - musb_h_tx_dma_start(hw_ep); - return; - } - } else if (tx_csr & MUSB_TXCSR_DMAENAB) { - dev_dbg(musb->controller, "not complete, but DMA enabled?\n"); - return; - } - - /* - * PIO: start next packet in this URB. - * - * REVISIT: some docs say that when hw_ep->tx_double_buffered, - * (and presumably, FIFO is not half-full) we should write *two* - * packets before updating TXCSR; other docs disagree... - */ - if (length > qh->maxpacket) - length = qh->maxpacket; - /* Unmap the buffer so that CPU can use it */ - usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb); - musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset); - qh->segsize = length; - - musb_ep_select(mbase, epnum); - musb_writew(epio, MUSB_TXCSR, - MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY); -} - - -#ifdef CONFIG_USB_INVENTRA_DMA - -/* Host side RX (IN) using Mentor DMA works as follows: - submit_urb -> - - if queue was empty, ProgramEndpoint - - first IN token is sent out (by setting ReqPkt) - LinuxIsr -> RxReady() - /\ => first packet is received - | - Set in mode 0 (DmaEnab, ~ReqPkt) - | -> DMA Isr (transfer complete) -> RxReady() - | - Ack receive (~RxPktRdy), turn off DMA (~DmaEnab) - | - if urb not complete, send next IN token (ReqPkt) - | | else complete urb. - | | - --------------------------- - * - * Nuances of mode 1: - * For short packets, no ack (+RxPktRdy) is sent automatically - * (even if AutoClear is ON) - * For full packets, ack (~RxPktRdy) and next IN token (+ReqPkt) is sent - * automatically => major problem, as collecting the next packet becomes - * difficult. Hence mode 1 is not used. - * - * REVISIT - * All we care about at this driver level is that - * (a) all URBs terminate with REQPKT cleared and fifo(s) empty; - * (b) termination conditions are: short RX, or buffer full; - * (c) fault modes include - * - iff URB_SHORT_NOT_OK, short RX status is -EREMOTEIO. - * (and that endpoint's dma queue stops immediately) - * - overflow (full, PLUS more bytes in the terminal packet) - * - * So for example, usb-storage sets URB_SHORT_NOT_OK, and would - * thus be a great candidate for using mode 1 ... for all but the - * last packet of one URB's transfer. - */ - -#endif - -/* Schedule next QH from musb->in_bulk and move the current qh to - * the end; avoids starvation for other endpoints. - */ -static void musb_bulk_rx_nak_timeout(struct musb *musb, struct musb_hw_ep *ep) -{ - struct dma_channel *dma; - struct urb *urb; - void __iomem *mbase = musb->mregs; - void __iomem *epio = ep->regs; - struct musb_qh *cur_qh, *next_qh; - u16 rx_csr; - - musb_ep_select(mbase, ep->epnum); - dma = is_dma_capable() ? ep->rx_channel : NULL; - - /* clear nak timeout bit */ - rx_csr = musb_readw(epio, MUSB_RXCSR); - rx_csr |= MUSB_RXCSR_H_WZC_BITS; - rx_csr &= ~MUSB_RXCSR_DATAERROR; - musb_writew(epio, MUSB_RXCSR, rx_csr); - - cur_qh = first_qh(&musb->in_bulk); - if (cur_qh) { - urb = next_urb(cur_qh); - if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { - dma->status = MUSB_DMA_STATUS_CORE_ABORT; - musb->dma_controller->channel_abort(dma); - urb->actual_length += dma->actual_len; - dma->actual_len = 0L; - } - musb_save_toggle(cur_qh, 1, urb); - - /* move cur_qh to end of queue */ - list_move_tail(&cur_qh->ring, &musb->in_bulk); - - /* get the next qh from musb->in_bulk */ - next_qh = first_qh(&musb->in_bulk); - - /* set rx_reinit and schedule the next qh */ - ep->rx_reinit = 1; - musb_start_urb(musb, 1, next_qh); - } -} - -/* - * Service an RX interrupt for the given IN endpoint; docs cover bulk, iso, - * and high-bandwidth IN transfer cases. - */ -void musb_host_rx(struct musb *musb, u8 epnum) -{ - struct urb *urb; - struct musb_hw_ep *hw_ep = musb->endpoints + epnum; - void __iomem *epio = hw_ep->regs; - struct musb_qh *qh = hw_ep->in_qh; - size_t xfer_len; - void __iomem *mbase = musb->mregs; - int pipe; - u16 rx_csr, val; - bool iso_err = false; - bool done = false; - u32 status; - struct dma_channel *dma; - - musb_ep_select(mbase, epnum); - - urb = next_urb(qh); - dma = is_dma_capable() ? hw_ep->rx_channel : NULL; - status = 0; - xfer_len = 0; - - rx_csr = musb_readw(epio, MUSB_RXCSR); - val = rx_csr; - - if (unlikely(!urb)) { - /* REVISIT -- THIS SHOULD NEVER HAPPEN ... but, at least - * usbtest #11 (unlinks) triggers it regularly, sometimes - * with fifo full. (Only with DMA??) - */ - dev_dbg(musb->controller, "BOGUS RX%d ready, csr %04x, count %d\n", epnum, val, - musb_readw(epio, MUSB_RXCOUNT)); - musb_h_flush_rxfifo(hw_ep, MUSB_RXCSR_CLRDATATOG); - return; - } - - pipe = urb->pipe; - - dev_dbg(musb->controller, "<== hw %d rxcsr %04x, urb actual %d (+dma %zu)\n", - epnum, rx_csr, urb->actual_length, - dma ? dma->actual_len : 0); - - /* check for errors, concurrent stall & unlink is not really - * handled yet! */ - if (rx_csr & MUSB_RXCSR_H_RXSTALL) { - dev_dbg(musb->controller, "RX end %d STALL\n", epnum); - - /* stall; record URB status */ - status = -EPIPE; - - } else if (rx_csr & MUSB_RXCSR_H_ERROR) { - dev_dbg(musb->controller, "end %d RX proto error\n", epnum); - - status = -EPROTO; - musb_writeb(epio, MUSB_RXINTERVAL, 0); - - } else if (rx_csr & MUSB_RXCSR_DATAERROR) { - - if (USB_ENDPOINT_XFER_ISOC != qh->type) { - dev_dbg(musb->controller, "RX end %d NAK timeout\n", epnum); - - /* NOTE: NAKing is *NOT* an error, so we want to - * continue. Except ... if there's a request for - * another QH, use that instead of starving it. - * - * Devices like Ethernet and serial adapters keep - * reads posted at all times, which will starve - * other devices without this logic. - */ - if (usb_pipebulk(urb->pipe) - && qh->mux == 1 - && !list_is_singular(&musb->in_bulk)) { - musb_bulk_rx_nak_timeout(musb, hw_ep); - return; - } - musb_ep_select(mbase, epnum); - rx_csr |= MUSB_RXCSR_H_WZC_BITS; - rx_csr &= ~MUSB_RXCSR_DATAERROR; - musb_writew(epio, MUSB_RXCSR, rx_csr); - - goto finish; - } else { - dev_dbg(musb->controller, "RX end %d ISO data error\n", epnum); - /* packet error reported later */ - iso_err = true; - } - } else if (rx_csr & MUSB_RXCSR_INCOMPRX) { - dev_dbg(musb->controller, "end %d high bandwidth incomplete ISO packet RX\n", - epnum); - status = -EPROTO; - } - - /* faults abort the transfer */ - if (status) { - /* clean up dma and collect transfer count */ - if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { - dma->status = MUSB_DMA_STATUS_CORE_ABORT; - (void) musb->dma_controller->channel_abort(dma); - xfer_len = dma->actual_len; - } - musb_h_flush_rxfifo(hw_ep, MUSB_RXCSR_CLRDATATOG); - musb_writeb(epio, MUSB_RXINTERVAL, 0); - done = true; - goto finish; - } - - if (unlikely(dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY)) { - /* SHOULD NEVER HAPPEN ... but at least DaVinci has done it */ - ERR("RX%d dma busy, csr %04x\n", epnum, rx_csr); - goto finish; - } - - /* thorough shutdown for now ... given more precise fault handling - * and better queueing support, we might keep a DMA pipeline going - * while processing this irq for earlier completions. - */ - - /* FIXME this is _way_ too much in-line logic for Mentor DMA */ - -#ifndef CONFIG_USB_INVENTRA_DMA - if (rx_csr & MUSB_RXCSR_H_REQPKT) { - /* REVISIT this happened for a while on some short reads... - * the cleanup still needs investigation... looks bad... - * and also duplicates dma cleanup code above ... plus, - * shouldn't this be the "half full" double buffer case? - */ - if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { - dma->status = MUSB_DMA_STATUS_CORE_ABORT; - (void) musb->dma_controller->channel_abort(dma); - xfer_len = dma->actual_len; - done = true; - } - - dev_dbg(musb->controller, "RXCSR%d %04x, reqpkt, len %zu%s\n", epnum, rx_csr, - xfer_len, dma ? ", dma" : ""); - rx_csr &= ~MUSB_RXCSR_H_REQPKT; - - musb_ep_select(mbase, epnum); - musb_writew(epio, MUSB_RXCSR, - MUSB_RXCSR_H_WZC_BITS | rx_csr); - } -#endif - if (dma && (rx_csr & MUSB_RXCSR_DMAENAB)) { - xfer_len = dma->actual_len; - - val &= ~(MUSB_RXCSR_DMAENAB - | MUSB_RXCSR_H_AUTOREQ - | MUSB_RXCSR_AUTOCLEAR - | MUSB_RXCSR_RXPKTRDY); - musb_writew(hw_ep->regs, MUSB_RXCSR, val); - -#ifdef CONFIG_USB_INVENTRA_DMA - if (usb_pipeisoc(pipe)) { - struct usb_iso_packet_descriptor *d; - - d = urb->iso_frame_desc + qh->iso_idx; - d->actual_length = xfer_len; - - /* even if there was an error, we did the dma - * for iso_frame_desc->length - */ - if (d->status != -EILSEQ && d->status != -EOVERFLOW) - d->status = 0; - - if (++qh->iso_idx >= urb->number_of_packets) - done = true; - else - done = false; - - } else { - /* done if urb buffer is full or short packet is recd */ - done = (urb->actual_length + xfer_len >= - urb->transfer_buffer_length - || dma->actual_len < qh->maxpacket); - } - - /* send IN token for next packet, without AUTOREQ */ - if (!done) { - val |= MUSB_RXCSR_H_REQPKT; - musb_writew(epio, MUSB_RXCSR, - MUSB_RXCSR_H_WZC_BITS | val); - } - - dev_dbg(musb->controller, "ep %d dma %s, rxcsr %04x, rxcount %d\n", epnum, - done ? "off" : "reset", - musb_readw(epio, MUSB_RXCSR), - musb_readw(epio, MUSB_RXCOUNT)); -#else - done = true; -#endif - } else if (urb->status == -EINPROGRESS) { - /* if no errors, be sure a packet is ready for unloading */ - if (unlikely(!(rx_csr & MUSB_RXCSR_RXPKTRDY))) { - status = -EPROTO; - ERR("Rx interrupt with no errors or packet!\n"); - - /* FIXME this is another "SHOULD NEVER HAPPEN" */ - -/* SCRUB (RX) */ - /* do the proper sequence to abort the transfer */ - musb_ep_select(mbase, epnum); - val &= ~MUSB_RXCSR_H_REQPKT; - musb_writew(epio, MUSB_RXCSR, val); - goto finish; - } - - /* we are expecting IN packets */ -#ifdef CONFIG_USB_INVENTRA_DMA - if (dma) { - struct dma_controller *c; - u16 rx_count; - int ret, length; - dma_addr_t buf; - - rx_count = musb_readw(epio, MUSB_RXCOUNT); - - dev_dbg(musb->controller, "RX%d count %d, buffer 0x%x len %d/%d\n", - epnum, rx_count, - urb->transfer_dma - + urb->actual_length, - qh->offset, - urb->transfer_buffer_length); - - c = musb->dma_controller; - - if (usb_pipeisoc(pipe)) { - int d_status = 0; - struct usb_iso_packet_descriptor *d; - - d = urb->iso_frame_desc + qh->iso_idx; - - if (iso_err) { - d_status = -EILSEQ; - urb->error_count++; - } - if (rx_count > d->length) { - if (d_status == 0) { - d_status = -EOVERFLOW; - urb->error_count++; - } - dev_dbg(musb->controller, "** OVERFLOW %d into %d\n",\ - rx_count, d->length); - - length = d->length; - } else - length = rx_count; - d->status = d_status; - buf = urb->transfer_dma + d->offset; - } else { - length = rx_count; - buf = urb->transfer_dma + - urb->actual_length; - } - - dma->desired_mode = 0; -#ifdef USE_MODE1 - /* because of the issue below, mode 1 will - * only rarely behave with correct semantics. - */ - if ((urb->transfer_flags & - URB_SHORT_NOT_OK) - && (urb->transfer_buffer_length - - urb->actual_length) - > qh->maxpacket) - dma->desired_mode = 1; - if (rx_count < hw_ep->max_packet_sz_rx) { - length = rx_count; - dma->desired_mode = 0; - } else { - length = urb->transfer_buffer_length; - } -#endif - -/* Disadvantage of using mode 1: - * It's basically usable only for mass storage class; essentially all - * other protocols also terminate transfers on short packets. - * - * Details: - * An extra IN token is sent at the end of the transfer (due to AUTOREQ) - * If you try to use mode 1 for (transfer_buffer_length - 512), and try - * to use the extra IN token to grab the last packet using mode 0, then - * the problem is that you cannot be sure when the device will send the - * last packet and RxPktRdy set. Sometimes the packet is recd too soon - * such that it gets lost when RxCSR is re-set at the end of the mode 1 - * transfer, while sometimes it is recd just a little late so that if you - * try to configure for mode 0 soon after the mode 1 transfer is - * completed, you will find rxcount 0. Okay, so you might think why not - * wait for an interrupt when the pkt is recd. Well, you won't get any! - */ - - val = musb_readw(epio, MUSB_RXCSR); - val &= ~MUSB_RXCSR_H_REQPKT; - - if (dma->desired_mode == 0) - val &= ~MUSB_RXCSR_H_AUTOREQ; - else - val |= MUSB_RXCSR_H_AUTOREQ; - 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); - - /* REVISIT if when actual_length != 0, - * transfer_buffer_length needs to be - * adjusted first... - */ - ret = c->channel_program( - dma, qh->maxpacket, - dma->desired_mode, buf, length); - - if (!ret) { - c->channel_release(dma); - hw_ep->rx_channel = NULL; - dma = NULL; - /* REVISIT reset CSR */ - } - } -#endif /* Mentor DMA */ - - if (!dma) { - /* Unmap the buffer so that CPU can use it */ - usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb); - done = musb_host_packet_rx(musb, urb, - epnum, iso_err); - dev_dbg(musb->controller, "read %spacket\n", done ? "last " : ""); - } - } - -finish: - urb->actual_length += xfer_len; - qh->offset += xfer_len; - if (done) { - if (urb->status == -EINPROGRESS) - urb->status = status; - musb_advance_schedule(musb, urb, hw_ep, USB_DIR_IN); - } -} - -/* schedule nodes correspond to peripheral endpoints, like an OHCI QH. - * the software schedule associates multiple such nodes with a given - * host side hardware endpoint + direction; scheduling may activate - * that hardware endpoint. - */ -static int musb_schedule( - struct musb *musb, - struct musb_qh *qh, - int is_in) -{ - int idle; - int best_diff; - int best_end, epnum; - struct musb_hw_ep *hw_ep = NULL; - struct list_head *head = NULL; - u8 toggle; - u8 txtype; - struct urb *urb = next_urb(qh); - - /* use fixed hardware for control and bulk */ - if (qh->type == USB_ENDPOINT_XFER_CONTROL) { - head = &musb->control; - hw_ep = musb->control_ep; - goto success; - } - - /* else, periodic transfers get muxed to other endpoints */ - - /* - * We know this qh hasn't been scheduled, so all we need to do - * is choose which hardware endpoint to put it on ... - * - * REVISIT what we really want here is a regular schedule tree - * like e.g. OHCI uses. - */ - best_diff = 4096; - best_end = -1; - - for (epnum = 1, hw_ep = musb->endpoints + 1; - epnum < musb->nr_endpoints; - epnum++, hw_ep++) { - int diff; - - 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; - else - diff = hw_ep->max_packet_sz_tx; - diff -= (qh->maxpacket * qh->hb_mult); - - if (diff >= 0 && best_diff > diff) { - - /* - * Mentor controller has a bug in that if we schedule - * a BULK Tx transfer on an endpoint that had earlier - * handled ISOC then the BULK transfer has to start on - * a zero toggle. If the BULK transfer starts on a 1 - * toggle then this transfer will fail as the mentor - * controller starts the Bulk transfer on a 0 toggle - * irrespective of the programming of the toggle bits - * in the TXCSR register. Check for this condition - * while allocating the EP for a Tx Bulk transfer. If - * so skip this EP. - */ - hw_ep = musb->endpoints + epnum; - toggle = usb_gettoggle(urb->dev, qh->epnum, !is_in); - txtype = (musb_readb(hw_ep->regs, MUSB_TXTYPE) - >> 4) & 0x3; - if (!is_in && (qh->type == USB_ENDPOINT_XFER_BULK) && - toggle && (txtype == USB_ENDPOINT_XFER_ISOC)) - continue; - - best_diff = diff; - best_end = epnum; - } - } - /* use bulk reserved ep1 if no other ep is free */ - if (best_end < 0 && qh->type == USB_ENDPOINT_XFER_BULK) { - hw_ep = musb->bulk_ep; - if (is_in) - head = &musb->in_bulk; - else - head = &musb->out_bulk; - - /* Enable bulk RX NAK timeout scheme when bulk requests are - * multiplexed. This scheme doen't work in high speed to full - * speed scenario as NAK interrupts are not coming from a - * full speed device connected to a high speed device. - * NAK timeout interval is 8 (128 uframe or 16ms) for HS and - * 4 (8 frame or 8ms) for FS device. - */ - if (is_in && qh->dev) - qh->intv_reg = - (USB_SPEED_HIGH == qh->dev->speed) ? 8 : 4; - goto success; - } else if (best_end < 0) { - return -ENOSPC; - } - - idle = 1; - qh->mux = 0; - hw_ep = musb->endpoints + best_end; - dev_dbg(musb->controller, "qh %p periodic slot %d\n", qh, best_end); -success: - if (head) { - idle = list_empty(head); - list_add_tail(&qh->ring, head); - qh->mux = 1; - } - qh->hw_ep = hw_ep; - qh->hep->hcpriv = qh; - if (idle) - musb_start_urb(musb, is_in, qh); - return 0; -} - -static int musb_urb_enqueue( - struct usb_hcd *hcd, - struct urb *urb, - gfp_t mem_flags) -{ - unsigned long flags; - struct musb *musb = hcd_to_musb(hcd); - struct usb_host_endpoint *hep = urb->ep; - struct musb_qh *qh; - struct usb_endpoint_descriptor *epd = &hep->desc; - int ret; - unsigned type_reg; - unsigned interval; - - /* host role must be active */ - if (!is_host_active(musb) || !musb->is_active) - return -ENODEV; - - spin_lock_irqsave(&musb->lock, flags); - ret = usb_hcd_link_urb_to_ep(hcd, urb); - qh = ret ? NULL : hep->hcpriv; - if (qh) - urb->hcpriv = qh; - spin_unlock_irqrestore(&musb->lock, flags); - - /* DMA mapping was already done, if needed, and this urb is on - * hep->urb_list now ... so we're done, unless hep wasn't yet - * scheduled onto a live qh. - * - * REVISIT best to keep hep->hcpriv valid until the endpoint gets - * disabled, testing for empty qh->ring and avoiding qh setup costs - * except for the first urb queued after a config change. - */ - if (qh || ret) - return ret; - - /* Allocate and initialize qh, minimizing the work done each time - * hw_ep gets reprogrammed, or with irqs blocked. Then schedule it. - * - * REVISIT consider a dedicated qh kmem_cache, so it's harder - * for bugs in other kernel code to break this driver... - */ - qh = kzalloc(sizeof *qh, mem_flags); - if (!qh) { - spin_lock_irqsave(&musb->lock, flags); - usb_hcd_unlink_urb_from_ep(hcd, urb); - spin_unlock_irqrestore(&musb->lock, flags); - return -ENOMEM; - } - - qh->hep = hep; - qh->dev = urb->dev; - INIT_LIST_HEAD(&qh->ring); - qh->is_ready = 1; - - qh->maxpacket = usb_endpoint_maxp(epd); - qh->type = usb_endpoint_type(epd); - - /* 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); - - /* NOTE: urb->dev->devnum is wrong during SET_ADDRESS */ - qh->addr_reg = (u8) usb_pipedevice(urb->pipe); - - /* precompute rxtype/txtype/type0 register */ - type_reg = (qh->type << 4) | qh->epnum; - switch (urb->dev->speed) { - case USB_SPEED_LOW: - type_reg |= 0xc0; - break; - case USB_SPEED_FULL: - type_reg |= 0x80; - break; - default: - type_reg |= 0x40; - } - qh->type_reg = type_reg; - - /* Precompute RXINTERVAL/TXINTERVAL register */ - switch (qh->type) { - case USB_ENDPOINT_XFER_INT: - /* - * Full/low speeds use the linear encoding, - * high speed uses the logarithmic encoding. - */ - if (urb->dev->speed <= USB_SPEED_FULL) { - interval = max_t(u8, epd->bInterval, 1); - break; - } - /* FALLTHROUGH */ - case USB_ENDPOINT_XFER_ISOC: - /* ISO always uses logarithmic encoding */ - interval = min_t(u8, epd->bInterval, 16); - break; - default: - /* REVISIT we actually want to use NAK limits, hinting to the - * transfer scheduling logic to try some other qh, e.g. try - * for 2 msec first: - * - * interval = (USB_SPEED_HIGH == urb->dev->speed) ? 16 : 2; - * - * The downside of disabling this is that transfer scheduling - * gets VERY unfair for nonperiodic transfers; a misbehaving - * peripheral could make that hurt. That's perfectly normal - * for reads from network or serial adapters ... so we have - * partial NAKlimit support for bulk RX. - * - * The upside of disabling it is simpler transfer scheduling. - */ - interval = 0; - } - qh->intv_reg = interval; - - /* precompute addressing for external hub/tt ports */ - if (musb->is_multipoint) { - struct usb_device *parent = urb->dev->parent; - - if (parent != hcd->self.root_hub) { - qh->h_addr_reg = (u8) parent->devnum; - - /* set up tt info if needed */ - if (urb->dev->tt) { - qh->h_port_reg = (u8) urb->dev->ttport; - if (urb->dev->tt->hub) - qh->h_addr_reg = - (u8) urb->dev->tt->hub->devnum; - if (urb->dev->tt->multi) - qh->h_addr_reg |= 0x80; - } - } - } - - /* invariant: hep->hcpriv is null OR the qh that's already scheduled. - * until we get real dma queues (with an entry for each urb/buffer), - * we only have work to do in the former case. - */ - spin_lock_irqsave(&musb->lock, flags); - if (hep->hcpriv) { - /* some concurrent activity submitted another urb to hep... - * odd, rare, error prone, but legal. - */ - kfree(qh); - qh = NULL; - ret = 0; - } else - ret = musb_schedule(musb, qh, - epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK); - - if (ret == 0) { - urb->hcpriv = qh; - /* FIXME set urb->start_frame for iso/intr, it's tested in - * musb_start_urb(), but otherwise only konicawc cares ... - */ - } - spin_unlock_irqrestore(&musb->lock, flags); - -done: - if (ret != 0) { - spin_lock_irqsave(&musb->lock, flags); - usb_hcd_unlink_urb_from_ep(hcd, urb); - spin_unlock_irqrestore(&musb->lock, flags); - kfree(qh); - } - return ret; -} - - -/* - * abort a transfer that's at the head of a hardware queue. - * 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) -{ - struct musb_hw_ep *ep = qh->hw_ep; - struct musb *musb = ep->musb; - void __iomem *epio = ep->regs; - unsigned hw_end = ep->epnum; - void __iomem *regs = ep->musb->mregs; - int is_in = usb_pipein(urb->pipe); - int status = 0; - u16 csr; - - musb_ep_select(regs, hw_end); - - if (is_dma_capable()) { - struct dma_channel *dma; - - dma = is_in ? ep->rx_channel : ep->tx_channel; - if (dma) { - status = ep->musb->dma_controller->channel_abort(dma); - dev_dbg(musb->controller, - "abort %cX%d DMA for urb %p --> %d\n", - is_in ? 'R' : 'T', ep->epnum, - urb, status); - urb->actual_length += dma->actual_len; - } - } - - /* turn off DMA requests, discard state, stop polling ... */ - if (ep->epnum && is_in) { - /* giveback saves bulk toggle */ - csr = musb_h_flush_rxfifo(ep, 0); - - /* REVISIT we still get an irq; should likely clear the - * endpoint's irq status here to avoid bogus irqs. - * clearing that status is platform-specific... - */ - } else if (ep->epnum) { - musb_h_tx_flush_fifo(ep); - csr = musb_readw(epio, MUSB_TXCSR); - csr &= ~(MUSB_TXCSR_AUTOSET - | MUSB_TXCSR_DMAENAB - | MUSB_TXCSR_H_RXSTALL - | MUSB_TXCSR_H_NAKTIMEOUT - | MUSB_TXCSR_H_ERROR - | MUSB_TXCSR_TXPKTRDY); - musb_writew(epio, MUSB_TXCSR, csr); - /* REVISIT may need to clear FLUSHFIFO ... */ - musb_writew(epio, MUSB_TXCSR, csr); - /* flush cpu writebuffer */ - csr = musb_readw(epio, MUSB_TXCSR); - } else { - musb_h_ep0_flush_fifo(ep); - } - if (status == 0) - musb_advance_schedule(ep->musb, urb, ep, is_in); - return status; -} - -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; - unsigned long flags; - int is_in = usb_pipein(urb->pipe); - int ret; - - dev_dbg(musb->controller, "urb=%p, dev%d ep%d%s\n", urb, - usb_pipedevice(urb->pipe), - usb_pipeendpoint(urb->pipe), - is_in ? "in" : "out"); - - spin_lock_irqsave(&musb->lock, flags); - ret = usb_hcd_check_unlink_urb(hcd, urb, status); - if (ret) - goto done; - - qh = urb->hcpriv; - if (!qh) - goto done; - - /* - * 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 - * 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 - || musb_ep_get_qh(qh->hw_ep, is_in) != qh) { - int ready = qh->is_ready; - - qh->is_ready = 0; - musb_giveback(musb, urb, 0); - qh->is_ready = ready; - - /* If nothing else (usually musb_giveback) is using it - * and its URB list has emptied, recycle this qh. - */ - if (ready && list_empty(&qh->hep->urb_list)) { - qh->hep->hcpriv = NULL; - list_del(&qh->ring); - kfree(qh); - } - } else - ret = musb_cleanup_urb(urb, qh); -done: - spin_unlock_irqrestore(&musb->lock, flags); - return ret; -} - -/* disable an endpoint */ -static void -musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep) -{ - u8 is_in = hep->desc.bEndpointAddress & USB_DIR_IN; - unsigned long flags; - struct musb *musb = hcd_to_musb(hcd); - struct musb_qh *qh; - struct urb *urb; - - spin_lock_irqsave(&musb->lock, flags); - - qh = hep->hcpriv; - if (qh == NULL) - goto exit; - - /* NOTE: qh is invalid unless !list_empty(&hep->urb_list) */ - - /* Kick the first URB off the hardware, if needed */ - qh->is_ready = 0; - if (musb_ep_get_qh(qh->hw_ep, is_in) == qh) { - urb = next_urb(qh); - - /* make software (then hardware) stop ASAP */ - if (!urb->unlinked) - urb->status = -ESHUTDOWN; - - /* cleanup */ - 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. - */ - while (!list_empty(&hep->urb_list)) { - urb = next_urb(qh); - urb->status = -ESHUTDOWN; - musb_advance_schedule(musb, urb, qh->hw_ep, is_in); - } - } else { - /* Just empty the queue; the hardware is busy with - * other transfers, and since !qh->is_ready nothing - * will activate any of these as it advances. - */ - while (!list_empty(&hep->urb_list)) - musb_giveback(musb, next_urb(qh), -ESHUTDOWN); - - hep->hcpriv = NULL; - list_del(&qh->ring); - kfree(qh); - } -exit: - spin_unlock_irqrestore(&musb->lock, flags); -} - -static int musb_h_get_frame_number(struct usb_hcd *hcd) -{ - struct musb *musb = hcd_to_musb(hcd); - - return musb_readw(musb->mregs, MUSB_FRAME); -} - -static int musb_h_start(struct usb_hcd *hcd) -{ - struct musb *musb = hcd_to_musb(hcd); - - /* NOTE: musb_start() is called when the hub driver turns - * on port power, or when (OTG) peripheral starts. - */ - hcd->state = HC_STATE_RUNNING; - musb->port1_status = 0; - return 0; -} - -static void musb_h_stop(struct usb_hcd *hcd) -{ - musb_stop(hcd_to_musb(hcd)); - hcd->state = HC_STATE_HALT; -} - -static int musb_bus_suspend(struct usb_hcd *hcd) -{ - struct musb *musb = hcd_to_musb(hcd); - u8 devctl; - - if (!is_host_active(musb)) - return 0; - - switch (musb->xceiv->state) { - case OTG_STATE_A_SUSPEND: - return 0; - case OTG_STATE_A_WAIT_VRISE: - /* ID could be grounded even if there's no device - * on the other end of the cable. NOTE that the - * A_WAIT_VRISE timers are messy with MUSB... - */ - devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) - musb->xceiv->state = OTG_STATE_A_WAIT_BCON; - break; - default: - break; - } - - if (musb->is_active) { - WARNING("trying to suspend as %s while active\n", - otg_state_string(musb->xceiv->state)); - return -EBUSY; - } else - return 0; -} - -static int musb_bus_resume(struct usb_hcd *hcd) -{ - /* resuming child port does the work */ - return 0; -} - -const struct hc_driver musb_hc_driver = { - .description = "musb-hcd", - .product_desc = "MUSB HDRC host driver", - .hcd_priv_size = sizeof(struct musb), - .flags = HCD_USB2 | HCD_MEMORY, - - /* not using irq handler or reset hooks from usbcore, since - * those must be shared with peripheral code for OTG configs - */ - - .start = musb_h_start, - .stop = musb_h_stop, - - .get_frame_number = musb_h_get_frame_number, - - .urb_enqueue = musb_urb_enqueue, - .urb_dequeue = musb_urb_dequeue, - .endpoint_disable = musb_h_disable, - - .hub_status_data = musb_hub_status_data, - .hub_control = musb_hub_control, - .bus_suspend = musb_bus_suspend, - .bus_resume = musb_bus_resume, - /* .start_port_reset = NULL, */ - /* .hub_irq_enable = NULL, */ -}; diff --git a/ANDROID_3.4.5/drivers/usb/musb/musb_host.h b/ANDROID_3.4.5/drivers/usb/musb/musb_host.h deleted file mode 100644 index 622d09fb..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/musb_host.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * MUSB OTG driver host defines - * - * Copyright 2005 Mentor Graphics Corporation - * Copyright (C) 2005-2006 by Texas Instruments - * Copyright (C) 2006-2007 Nokia Corporation - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef _MUSB_HOST_H -#define _MUSB_HOST_H - -static inline struct usb_hcd *musb_to_hcd(struct musb *musb) -{ - return container_of((void *) musb, struct usb_hcd, hcd_priv); -} - -static inline struct musb *hcd_to_musb(struct usb_hcd *hcd) -{ - return (struct musb *) (hcd->hcd_priv); -} - -/* stored in "usb_host_endpoint.hcpriv" for scheduled endpoints */ -struct musb_qh { - struct usb_host_endpoint *hep; /* usbcore info */ - struct usb_device *dev; - struct musb_hw_ep *hw_ep; /* current binding */ - - struct list_head ring; /* of musb_qh */ - /* struct musb_qh *next; */ /* for periodic tree */ - u8 mux; /* qh multiplexed to hw_ep */ - - unsigned offset; /* in urb->transfer_buffer */ - unsigned segsize; /* current xfer fragment */ - - u8 type_reg; /* {rx,tx} type register */ - u8 intv_reg; /* {rx,tx} interval register */ - u8 addr_reg; /* device address register */ - u8 h_addr_reg; /* hub address register */ - u8 h_port_reg; /* hub port register */ - - 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[] */ -}; - -/* map from control or bulk queue head to the first qh on that ring */ -static inline struct musb_qh *first_qh(struct list_head *q) -{ - if (list_empty(q)) - return NULL; - return list_entry(q->next, struct musb_qh, ring); -} - - -extern void musb_root_disconnect(struct musb *musb); - -struct usb_hcd; - -extern int musb_hub_status_data(struct usb_hcd *hcd, char *buf); -extern int musb_hub_control(struct usb_hcd *hcd, - u16 typeReq, u16 wValue, u16 wIndex, - char *buf, u16 wLength); - -extern const struct hc_driver musb_hc_driver; - -static inline struct urb *next_urb(struct musb_qh *qh) -{ - struct list_head *queue; - - if (!qh) - return NULL; - queue = &qh->hep->urb_list; - if (list_empty(queue)) - return NULL; - return list_entry(queue->next, struct urb, urb_list); -} - -#endif /* _MUSB_HOST_H */ diff --git a/ANDROID_3.4.5/drivers/usb/musb/musb_io.h b/ANDROID_3.4.5/drivers/usb/musb/musb_io.h deleted file mode 100644 index 1d5eda26..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/musb_io.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * MUSB OTG driver register I/O - * - * Copyright 2005 Mentor Graphics Corporation - * Copyright (C) 2005-2006 by Texas Instruments - * Copyright (C) 2006-2007 Nokia Corporation - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef __MUSB_LINUX_PLATFORM_ARCH_H__ -#define __MUSB_LINUX_PLATFORM_ARCH_H__ - -#include - -#if !defined(CONFIG_ARM) && !defined(CONFIG_SUPERH) \ - && !defined(CONFIG_AVR32) && !defined(CONFIG_PPC32) \ - && !defined(CONFIG_PPC64) && !defined(CONFIG_BLACKFIN) \ - && !defined(CONFIG_MIPS) -static inline void readsl(const void __iomem *addr, void *buf, int len) - { insl((unsigned long)addr, buf, len); } -static inline void readsw(const void __iomem *addr, void *buf, int len) - { insw((unsigned long)addr, buf, len); } -static inline void readsb(const void __iomem *addr, void *buf, int len) - { insb((unsigned long)addr, buf, len); } - -static inline void writesl(const void __iomem *addr, const void *buf, int len) - { outsl((unsigned long)addr, buf, len); } -static inline void writesw(const void __iomem *addr, const void *buf, int len) - { outsw((unsigned long)addr, buf, len); } -static inline void writesb(const void __iomem *addr, const void *buf, int len) - { outsb((unsigned long)addr, buf, len); } - -#endif - -#ifndef CONFIG_BLACKFIN - -/* NOTE: these offsets are all in bytes */ - -static inline u16 musb_readw(const void __iomem *addr, unsigned offset) - { return __raw_readw(addr + offset); } - -static inline u32 musb_readl(const void __iomem *addr, unsigned offset) - { return __raw_readl(addr + offset); } - - -static inline void musb_writew(void __iomem *addr, unsigned offset, u16 data) - { __raw_writew(data, addr + offset); } - -static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data) - { __raw_writel(data, addr + offset); } - - -#if defined(CONFIG_USB_MUSB_TUSB6010) || defined (CONFIG_USB_MUSB_TUSB6010_MODULE) - -/* - * TUSB6010 doesn't allow 8-bit access; 16-bit access is the minimum. - */ -static inline u8 musb_readb(const void __iomem *addr, unsigned offset) -{ - u16 tmp; - u8 val; - - tmp = __raw_readw(addr + (offset & ~1)); - if (offset & 1) - val = (tmp >> 8); - else - val = tmp & 0xff; - - return val; -} - -static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data) -{ - u16 tmp; - - tmp = __raw_readw(addr + (offset & ~1)); - if (offset & 1) - tmp = (data << 8) | (tmp & 0xff); - else - tmp = (tmp & 0xff00) | data; - - __raw_writew(tmp, addr + (offset & ~1)); -} - -#else - -static inline u8 musb_readb(const void __iomem *addr, unsigned offset) - { return __raw_readb(addr + offset); } - -static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data) - { __raw_writeb(data, addr + offset); } - -#endif /* CONFIG_USB_MUSB_TUSB6010 */ - -#else - -static inline u8 musb_readb(const void __iomem *addr, unsigned offset) - { return (u8) (bfin_read16(addr + offset)); } - -static inline u16 musb_readw(const void __iomem *addr, unsigned offset) - { return bfin_read16(addr + offset); } - -static inline u32 musb_readl(const void __iomem *addr, unsigned offset) - { return (u32) (bfin_read16(addr + offset)); } - -static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data) - { bfin_write16(addr + offset, (u16) data); } - -static inline void musb_writew(void __iomem *addr, unsigned offset, u16 data) - { bfin_write16(addr + offset, data); } - -static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data) - { bfin_write16(addr + offset, (u16) data); } - -#endif /* CONFIG_BLACKFIN */ - -#endif diff --git a/ANDROID_3.4.5/drivers/usb/musb/musb_regs.h b/ANDROID_3.4.5/drivers/usb/musb/musb_regs.h deleted file mode 100644 index 03f2655a..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/musb_regs.h +++ /dev/null @@ -1,645 +0,0 @@ -/* - * MUSB OTG driver register defines - * - * Copyright 2005 Mentor Graphics Corporation - * Copyright (C) 2005-2006 by Texas Instruments - * Copyright (C) 2006-2007 Nokia Corporation - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef __MUSB_REGS_H__ -#define __MUSB_REGS_H__ - -#define MUSB_EP0_FIFOSIZE 64 /* This is non-configurable */ - -/* - * MUSB Register bits - */ - -/* POWER */ -#define MUSB_POWER_ISOUPDATE 0x80 -#define MUSB_POWER_SOFTCONN 0x40 -#define MUSB_POWER_HSENAB 0x20 -#define MUSB_POWER_HSMODE 0x10 -#define MUSB_POWER_RESET 0x08 -#define MUSB_POWER_RESUME 0x04 -#define MUSB_POWER_SUSPENDM 0x02 -#define MUSB_POWER_ENSUSPEND 0x01 - -/* INTRUSB */ -#define MUSB_INTR_SUSPEND 0x01 -#define MUSB_INTR_RESUME 0x02 -#define MUSB_INTR_RESET 0x04 -#define MUSB_INTR_BABBLE 0x04 -#define MUSB_INTR_SOF 0x08 -#define MUSB_INTR_CONNECT 0x10 -#define MUSB_INTR_DISCONNECT 0x20 -#define MUSB_INTR_SESSREQ 0x40 -#define MUSB_INTR_VBUSERROR 0x80 /* For SESSION end */ - -/* DEVCTL */ -#define MUSB_DEVCTL_BDEVICE 0x80 -#define MUSB_DEVCTL_FSDEV 0x40 -#define MUSB_DEVCTL_LSDEV 0x20 -#define MUSB_DEVCTL_VBUS 0x18 -#define MUSB_DEVCTL_VBUS_SHIFT 3 -#define MUSB_DEVCTL_HM 0x04 -#define MUSB_DEVCTL_HR 0x02 -#define MUSB_DEVCTL_SESSION 0x01 - -/* MUSB ULPI VBUSCONTROL */ -#define MUSB_ULPI_USE_EXTVBUS 0x01 -#define MUSB_ULPI_USE_EXTVBUSIND 0x02 -/* ULPI_REG_CONTROL */ -#define MUSB_ULPI_REG_REQ (1 << 0) -#define MUSB_ULPI_REG_CMPLT (1 << 1) -#define MUSB_ULPI_RDN_WR (1 << 2) - -/* TESTMODE */ -#define MUSB_TEST_FORCE_HOST 0x80 -#define MUSB_TEST_FIFO_ACCESS 0x40 -#define MUSB_TEST_FORCE_FS 0x20 -#define MUSB_TEST_FORCE_HS 0x10 -#define MUSB_TEST_PACKET 0x08 -#define MUSB_TEST_K 0x04 -#define MUSB_TEST_J 0x02 -#define MUSB_TEST_SE0_NAK 0x01 - -/* Allocate for double-packet buffering (effectively doubles assigned _SIZE) */ -#define MUSB_FIFOSZ_DPB 0x10 -/* Allocation size (8, 16, 32, ... 4096) */ -#define MUSB_FIFOSZ_SIZE 0x0f - -/* CSR0 */ -#define MUSB_CSR0_FLUSHFIFO 0x0100 -#define MUSB_CSR0_TXPKTRDY 0x0002 -#define MUSB_CSR0_RXPKTRDY 0x0001 - -/* CSR0 in Peripheral mode */ -#define MUSB_CSR0_P_SVDSETUPEND 0x0080 -#define MUSB_CSR0_P_SVDRXPKTRDY 0x0040 -#define MUSB_CSR0_P_SENDSTALL 0x0020 -#define MUSB_CSR0_P_SETUPEND 0x0010 -#define MUSB_CSR0_P_DATAEND 0x0008 -#define MUSB_CSR0_P_SENTSTALL 0x0004 - -/* CSR0 in Host mode */ -#define MUSB_CSR0_H_DIS_PING 0x0800 -#define MUSB_CSR0_H_WR_DATATOGGLE 0x0400 /* Set to allow setting: */ -#define MUSB_CSR0_H_DATATOGGLE 0x0200 /* Data toggle control */ -#define MUSB_CSR0_H_NAKTIMEOUT 0x0080 -#define MUSB_CSR0_H_STATUSPKT 0x0040 -#define MUSB_CSR0_H_REQPKT 0x0020 -#define MUSB_CSR0_H_ERROR 0x0010 -#define MUSB_CSR0_H_SETUPPKT 0x0008 -#define MUSB_CSR0_H_RXSTALL 0x0004 - -/* CSR0 bits to avoid zeroing (write zero clears, write 1 ignored) */ -#define MUSB_CSR0_P_WZC_BITS \ - (MUSB_CSR0_P_SENTSTALL) -#define MUSB_CSR0_H_WZC_BITS \ - (MUSB_CSR0_H_NAKTIMEOUT | MUSB_CSR0_H_RXSTALL \ - | MUSB_CSR0_RXPKTRDY) - -/* TxType/RxType */ -#define MUSB_TYPE_SPEED 0xc0 -#define MUSB_TYPE_SPEED_SHIFT 6 -#define MUSB_TYPE_PROTO 0x30 /* Implicitly zero for ep0 */ -#define MUSB_TYPE_PROTO_SHIFT 4 -#define MUSB_TYPE_REMOTE_END 0xf /* Implicitly zero for ep0 */ - -/* CONFIGDATA */ -#define MUSB_CONFIGDATA_MPRXE 0x80 /* Auto bulk pkt combining */ -#define MUSB_CONFIGDATA_MPTXE 0x40 /* Auto bulk pkt splitting */ -#define MUSB_CONFIGDATA_BIGENDIAN 0x20 -#define MUSB_CONFIGDATA_HBRXE 0x10 /* HB-ISO for RX */ -#define MUSB_CONFIGDATA_HBTXE 0x08 /* HB-ISO for TX */ -#define MUSB_CONFIGDATA_DYNFIFO 0x04 /* Dynamic FIFO sizing */ -#define MUSB_CONFIGDATA_SOFTCONE 0x02 /* SoftConnect */ -#define MUSB_CONFIGDATA_UTMIDW 0x01 /* Data width 0/1 => 8/16bits */ - -/* TXCSR in Peripheral and Host mode */ -#define MUSB_TXCSR_AUTOSET 0x8000 -#define MUSB_TXCSR_DMAENAB 0x1000 -#define MUSB_TXCSR_FRCDATATOG 0x0800 -#define MUSB_TXCSR_DMAMODE 0x0400 -#define MUSB_TXCSR_CLRDATATOG 0x0040 -#define MUSB_TXCSR_FLUSHFIFO 0x0008 -#define MUSB_TXCSR_FIFONOTEMPTY 0x0002 -#define MUSB_TXCSR_TXPKTRDY 0x0001 - -/* TXCSR in Peripheral mode */ -#define MUSB_TXCSR_P_ISO 0x4000 -#define MUSB_TXCSR_P_INCOMPTX 0x0080 -#define MUSB_TXCSR_P_SENTSTALL 0x0020 -#define MUSB_TXCSR_P_SENDSTALL 0x0010 -#define MUSB_TXCSR_P_UNDERRUN 0x0004 - -/* TXCSR in Host mode */ -#define MUSB_TXCSR_H_WR_DATATOGGLE 0x0200 -#define MUSB_TXCSR_H_DATATOGGLE 0x0100 -#define MUSB_TXCSR_H_NAKTIMEOUT 0x0080 -#define MUSB_TXCSR_H_RXSTALL 0x0020 -#define MUSB_TXCSR_H_ERROR 0x0004 - -/* TXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */ -#define MUSB_TXCSR_P_WZC_BITS \ - (MUSB_TXCSR_P_INCOMPTX | MUSB_TXCSR_P_SENTSTALL \ - | MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_FIFONOTEMPTY) -#define MUSB_TXCSR_H_WZC_BITS \ - (MUSB_TXCSR_H_NAKTIMEOUT | MUSB_TXCSR_H_RXSTALL \ - | MUSB_TXCSR_H_ERROR | MUSB_TXCSR_FIFONOTEMPTY) - -/* RXCSR in Peripheral and Host mode */ -#define MUSB_RXCSR_AUTOCLEAR 0x8000 -#define MUSB_RXCSR_DMAENAB 0x2000 -#define MUSB_RXCSR_DISNYET 0x1000 -#define MUSB_RXCSR_PID_ERR 0x1000 -#define MUSB_RXCSR_DMAMODE 0x0800 -#define MUSB_RXCSR_INCOMPRX 0x0100 -#define MUSB_RXCSR_CLRDATATOG 0x0080 -#define MUSB_RXCSR_FLUSHFIFO 0x0010 -#define MUSB_RXCSR_DATAERROR 0x0008 -#define MUSB_RXCSR_FIFOFULL 0x0002 -#define MUSB_RXCSR_RXPKTRDY 0x0001 - -/* RXCSR in Peripheral mode */ -#define MUSB_RXCSR_P_ISO 0x4000 -#define MUSB_RXCSR_P_SENTSTALL 0x0040 -#define MUSB_RXCSR_P_SENDSTALL 0x0020 -#define MUSB_RXCSR_P_OVERRUN 0x0004 - -/* RXCSR in Host mode */ -#define MUSB_RXCSR_H_AUTOREQ 0x4000 -#define MUSB_RXCSR_H_WR_DATATOGGLE 0x0400 -#define MUSB_RXCSR_H_DATATOGGLE 0x0200 -#define MUSB_RXCSR_H_RXSTALL 0x0040 -#define MUSB_RXCSR_H_REQPKT 0x0020 -#define MUSB_RXCSR_H_ERROR 0x0004 - -/* RXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */ -#define MUSB_RXCSR_P_WZC_BITS \ - (MUSB_RXCSR_P_SENTSTALL | MUSB_RXCSR_P_OVERRUN \ - | MUSB_RXCSR_RXPKTRDY) -#define MUSB_RXCSR_H_WZC_BITS \ - (MUSB_RXCSR_H_RXSTALL | MUSB_RXCSR_H_ERROR \ - | MUSB_RXCSR_DATAERROR | MUSB_RXCSR_RXPKTRDY) - -/* HUBADDR */ -#define MUSB_HUBADDR_MULTI_TT 0x80 - - -#ifndef CONFIG_BLACKFIN - -/* - * Common USB registers - */ - -#define MUSB_FADDR 0x00 /* 8-bit */ -#define MUSB_POWER 0x01 /* 8-bit */ - -#define MUSB_INTRTX 0x02 /* 16-bit */ -#define MUSB_INTRRX 0x04 -#define MUSB_INTRTXE 0x06 -#define MUSB_INTRRXE 0x08 -#define MUSB_INTRUSB 0x0A /* 8 bit */ -#define MUSB_INTRUSBE 0x0B /* 8 bit */ -#define MUSB_FRAME 0x0C -#define MUSB_INDEX 0x0E /* 8 bit */ -#define MUSB_TESTMODE 0x0F /* 8 bit */ - -/* Get offset for a given FIFO from musb->mregs */ -#if defined(CONFIG_USB_MUSB_TUSB6010) || \ - defined(CONFIG_USB_MUSB_TUSB6010_MODULE) -#define MUSB_FIFO_OFFSET(epnum) (0x200 + ((epnum) * 0x20)) -#else -#define MUSB_FIFO_OFFSET(epnum) (0x20 + ((epnum) * 4)) -#endif - -/* - * Additional Control Registers - */ - -#define MUSB_DEVCTL 0x60 /* 8 bit */ - -/* These are always controlled through the INDEX register */ -#define MUSB_TXFIFOSZ 0x62 /* 8-bit (see masks) */ -#define MUSB_RXFIFOSZ 0x63 /* 8-bit (see masks) */ -#define MUSB_TXFIFOADD 0x64 /* 16-bit offset shifted right 3 */ -#define MUSB_RXFIFOADD 0x66 /* 16-bit offset shifted right 3 */ - -/* REVISIT: vctrl/vstatus: optional vendor utmi+phy register at 0x68 */ -#define MUSB_HWVERS 0x6C /* 8 bit */ -#define MUSB_ULPI_BUSCONTROL 0x70 /* 8 bit */ -#define MUSB_ULPI_INT_MASK 0x72 /* 8 bit */ -#define MUSB_ULPI_INT_SRC 0x73 /* 8 bit */ -#define MUSB_ULPI_REG_DATA 0x74 /* 8 bit */ -#define MUSB_ULPI_REG_ADDR 0x75 /* 8 bit */ -#define MUSB_ULPI_REG_CONTROL 0x76 /* 8 bit */ -#define MUSB_ULPI_RAW_DATA 0x77 /* 8 bit */ - -#define MUSB_EPINFO 0x78 /* 8 bit */ -#define MUSB_RAMINFO 0x79 /* 8 bit */ -#define MUSB_LINKINFO 0x7a /* 8 bit */ -#define MUSB_VPLEN 0x7b /* 8 bit */ -#define MUSB_HS_EOF1 0x7c /* 8 bit */ -#define MUSB_FS_EOF1 0x7d /* 8 bit */ -#define MUSB_LS_EOF1 0x7e /* 8 bit */ - -/* Offsets to endpoint registers */ -#define MUSB_TXMAXP 0x00 -#define MUSB_TXCSR 0x02 -#define MUSB_CSR0 MUSB_TXCSR /* Re-used for EP0 */ -#define MUSB_RXMAXP 0x04 -#define MUSB_RXCSR 0x06 -#define MUSB_RXCOUNT 0x08 -#define MUSB_COUNT0 MUSB_RXCOUNT /* Re-used for EP0 */ -#define MUSB_TXTYPE 0x0A -#define MUSB_TYPE0 MUSB_TXTYPE /* Re-used for EP0 */ -#define MUSB_TXINTERVAL 0x0B -#define MUSB_NAKLIMIT0 MUSB_TXINTERVAL /* Re-used for EP0 */ -#define MUSB_RXTYPE 0x0C -#define MUSB_RXINTERVAL 0x0D -#define MUSB_FIFOSIZE 0x0F -#define MUSB_CONFIGDATA MUSB_FIFOSIZE /* Re-used for EP0 */ - -/* Offsets to endpoint registers in indexed model (using INDEX register) */ -#define MUSB_INDEXED_OFFSET(_epnum, _offset) \ - (0x10 + (_offset)) - -/* Offsets to endpoint registers in flat models */ -#define MUSB_FLAT_OFFSET(_epnum, _offset) \ - (0x100 + (0x10*(_epnum)) + (_offset)) - -#if defined(CONFIG_USB_MUSB_TUSB6010) || \ - defined(CONFIG_USB_MUSB_TUSB6010_MODULE) -/* TUSB6010 EP0 configuration register is special */ -#define MUSB_TUSB_OFFSET(_epnum, _offset) \ - (0x10 + _offset) -#include "tusb6010.h" /* Needed "only" for TUSB_EP0_CONF */ -#endif - -#define MUSB_TXCSR_MODE 0x2000 - -/* "bus control"/target registers, for host side multipoint (external hubs) */ -#define MUSB_TXFUNCADDR 0x00 -#define MUSB_TXHUBADDR 0x02 -#define MUSB_TXHUBPORT 0x03 - -#define MUSB_RXFUNCADDR 0x04 -#define MUSB_RXHUBADDR 0x06 -#define MUSB_RXHUBPORT 0x07 - -#define MUSB_BUSCTL_OFFSET(_epnum, _offset) \ - (0x80 + (8*(_epnum)) + (_offset)) - -static inline void musb_write_txfifosz(void __iomem *mbase, u8 c_size) -{ - musb_writeb(mbase, MUSB_TXFIFOSZ, c_size); -} - -static inline void musb_write_txfifoadd(void __iomem *mbase, u16 c_off) -{ - musb_writew(mbase, MUSB_TXFIFOADD, c_off); -} - -static inline void musb_write_rxfifosz(void __iomem *mbase, u8 c_size) -{ - musb_writeb(mbase, MUSB_RXFIFOSZ, c_size); -} - -static inline void musb_write_rxfifoadd(void __iomem *mbase, u16 c_off) -{ - musb_writew(mbase, MUSB_RXFIFOADD, c_off); -} - -static inline void musb_write_ulpi_buscontrol(void __iomem *mbase, u8 val) -{ - musb_writeb(mbase, MUSB_ULPI_BUSCONTROL, val); -} - -static inline u8 musb_read_txfifosz(void __iomem *mbase) -{ - return musb_readb(mbase, MUSB_TXFIFOSZ); -} - -static inline u16 musb_read_txfifoadd(void __iomem *mbase) -{ - return musb_readw(mbase, MUSB_TXFIFOADD); -} - -static inline u8 musb_read_rxfifosz(void __iomem *mbase) -{ - return musb_readb(mbase, MUSB_RXFIFOSZ); -} - -static inline u16 musb_read_rxfifoadd(void __iomem *mbase) -{ - return musb_readw(mbase, MUSB_RXFIFOADD); -} - -static inline u8 musb_read_ulpi_buscontrol(void __iomem *mbase) -{ - return musb_readb(mbase, MUSB_ULPI_BUSCONTROL); -} - -static inline u8 musb_read_configdata(void __iomem *mbase) -{ - musb_writeb(mbase, MUSB_INDEX, 0); - return musb_readb(mbase, 0x10 + MUSB_CONFIGDATA); -} - -static inline u16 musb_read_hwvers(void __iomem *mbase) -{ - return musb_readw(mbase, MUSB_HWVERS); -} - -static inline void __iomem *musb_read_target_reg_base(u8 i, void __iomem *mbase) -{ - return (MUSB_BUSCTL_OFFSET(i, 0) + mbase); -} - -static inline void musb_write_rxfunaddr(void __iomem *ep_target_regs, - u8 qh_addr_reg) -{ - musb_writeb(ep_target_regs, MUSB_RXFUNCADDR, qh_addr_reg); -} - -static inline void musb_write_rxhubaddr(void __iomem *ep_target_regs, - u8 qh_h_addr_reg) -{ - musb_writeb(ep_target_regs, MUSB_RXHUBADDR, qh_h_addr_reg); -} - -static inline void musb_write_rxhubport(void __iomem *ep_target_regs, - u8 qh_h_port_reg) -{ - musb_writeb(ep_target_regs, MUSB_RXHUBPORT, qh_h_port_reg); -} - -static inline void musb_write_txfunaddr(void __iomem *mbase, u8 epnum, - u8 qh_addr_reg) -{ - musb_writeb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXFUNCADDR), - qh_addr_reg); -} - -static inline void musb_write_txhubaddr(void __iomem *mbase, u8 epnum, - u8 qh_addr_reg) -{ - musb_writeb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBADDR), - qh_addr_reg); -} - -static inline void musb_write_txhubport(void __iomem *mbase, u8 epnum, - u8 qh_h_port_reg) -{ - musb_writeb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBPORT), - qh_h_port_reg); -} - -static inline u8 musb_read_rxfunaddr(void __iomem *mbase, u8 epnum) -{ - return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXFUNCADDR)); -} - -static inline u8 musb_read_rxhubaddr(void __iomem *mbase, u8 epnum) -{ - return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXHUBADDR)); -} - -static inline u8 musb_read_rxhubport(void __iomem *mbase, u8 epnum) -{ - return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXHUBPORT)); -} - -static inline u8 musb_read_txfunaddr(void __iomem *mbase, u8 epnum) -{ - return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXFUNCADDR)); -} - -static inline u8 musb_read_txhubaddr(void __iomem *mbase, u8 epnum) -{ - return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBADDR)); -} - -static inline u8 musb_read_txhubport(void __iomem *mbase, u8 epnum) -{ - return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBPORT)); -} - -#else /* CONFIG_BLACKFIN */ - -#define USB_BASE USB_FADDR -#define USB_OFFSET(reg) (reg - USB_BASE) - -/* - * Common USB registers - */ -#define MUSB_FADDR USB_OFFSET(USB_FADDR) /* 8-bit */ -#define MUSB_POWER USB_OFFSET(USB_POWER) /* 8-bit */ -#define MUSB_INTRTX USB_OFFSET(USB_INTRTX) /* 16-bit */ -#define MUSB_INTRRX USB_OFFSET(USB_INTRRX) -#define MUSB_INTRTXE USB_OFFSET(USB_INTRTXE) -#define MUSB_INTRRXE USB_OFFSET(USB_INTRRXE) -#define MUSB_INTRUSB USB_OFFSET(USB_INTRUSB) /* 8 bit */ -#define MUSB_INTRUSBE USB_OFFSET(USB_INTRUSBE)/* 8 bit */ -#define MUSB_FRAME USB_OFFSET(USB_FRAME) -#define MUSB_INDEX USB_OFFSET(USB_INDEX) /* 8 bit */ -#define MUSB_TESTMODE USB_OFFSET(USB_TESTMODE)/* 8 bit */ - -/* Get offset for a given FIFO from musb->mregs */ -#define MUSB_FIFO_OFFSET(epnum) \ - (USB_OFFSET(USB_EP0_FIFO) + ((epnum) * 8)) - -/* - * Additional Control Registers - */ - -#define MUSB_DEVCTL USB_OFFSET(USB_OTG_DEV_CTL) /* 8 bit */ - -#define MUSB_LINKINFO USB_OFFSET(USB_LINKINFO)/* 8 bit */ -#define MUSB_VPLEN USB_OFFSET(USB_VPLEN) /* 8 bit */ -#define MUSB_HS_EOF1 USB_OFFSET(USB_HS_EOF1) /* 8 bit */ -#define MUSB_FS_EOF1 USB_OFFSET(USB_FS_EOF1) /* 8 bit */ -#define MUSB_LS_EOF1 USB_OFFSET(USB_LS_EOF1) /* 8 bit */ - -/* Offsets to endpoint registers */ -#define MUSB_TXMAXP 0x00 -#define MUSB_TXCSR 0x04 -#define MUSB_CSR0 MUSB_TXCSR /* Re-used for EP0 */ -#define MUSB_RXMAXP 0x08 -#define MUSB_RXCSR 0x0C -#define MUSB_RXCOUNT 0x10 -#define MUSB_COUNT0 MUSB_RXCOUNT /* Re-used for EP0 */ -#define MUSB_TXTYPE 0x14 -#define MUSB_TYPE0 MUSB_TXTYPE /* Re-used for EP0 */ -#define MUSB_TXINTERVAL 0x18 -#define MUSB_NAKLIMIT0 MUSB_TXINTERVAL /* Re-used for EP0 */ -#define MUSB_RXTYPE 0x1C -#define MUSB_RXINTERVAL 0x20 -#define MUSB_TXCOUNT 0x28 - -/* Offsets to endpoint registers in indexed model (using INDEX register) */ -#define MUSB_INDEXED_OFFSET(_epnum, _offset) \ - (0x40 + (_offset)) - -/* Offsets to endpoint registers in flat models */ -#define MUSB_FLAT_OFFSET(_epnum, _offset) \ - (USB_OFFSET(USB_EP_NI0_TXMAXP) + (0x40 * (_epnum)) + (_offset)) - -/* Not implemented - HW has separate Tx/Rx FIFO */ -#define MUSB_TXCSR_MODE 0x0000 - -static inline void musb_write_txfifosz(void __iomem *mbase, u8 c_size) -{ -} - -static inline void musb_write_txfifoadd(void __iomem *mbase, u16 c_off) -{ -} - -static inline void musb_write_rxfifosz(void __iomem *mbase, u8 c_size) -{ -} - -static inline void musb_write_rxfifoadd(void __iomem *mbase, u16 c_off) -{ -} - -static inline void musb_write_ulpi_buscontrol(void __iomem *mbase, u8 val) -{ -} - -static inline u8 musb_read_txfifosz(void __iomem *mbase) -{ - return 0; -} - -static inline u16 musb_read_txfifoadd(void __iomem *mbase) -{ - return 0; -} - -static inline u8 musb_read_rxfifosz(void __iomem *mbase) -{ - return 0; -} - -static inline u16 musb_read_rxfifoadd(void __iomem *mbase) -{ - return 0; -} - -static inline u8 musb_read_ulpi_buscontrol(void __iomem *mbase) -{ - return 0; -} - -static inline u8 musb_read_configdata(void __iomem *mbase) -{ - return 0; -} - -static inline u16 musb_read_hwvers(void __iomem *mbase) -{ - /* - * This register is invisible on Blackfin, actually the MUSB - * RTL version of Blackfin is 1.9, so just harcode its value. - */ - return MUSB_HWVERS_1900; -} - -static inline void __iomem *musb_read_target_reg_base(u8 i, void __iomem *mbase) -{ - return NULL; -} - -static inline void musb_write_rxfunaddr(void __iomem *ep_target_regs, - u8 qh_addr_req) -{ -} - -static inline void musb_write_rxhubaddr(void __iomem *ep_target_regs, - u8 qh_h_addr_reg) -{ -} - -static inline void musb_write_rxhubport(void __iomem *ep_target_regs, - u8 qh_h_port_reg) -{ -} - -static inline void musb_write_txfunaddr(void __iomem *mbase, u8 epnum, - u8 qh_addr_reg) -{ -} - -static inline void musb_write_txhubaddr(void __iomem *mbase, u8 epnum, - u8 qh_addr_reg) -{ -} - -static inline void musb_write_txhubport(void __iomem *mbase, u8 epnum, - u8 qh_h_port_reg) -{ -} - -static inline u8 musb_read_rxfunaddr(void __iomem *mbase, u8 epnum) -{ - return 0; -} - -static inline u8 musb_read_rxhubaddr(void __iomem *mbase, u8 epnum) -{ - return 0; -} - -static inline u8 musb_read_rxhubport(void __iomem *mbase, u8 epnum) -{ - return 0; -} - -static inline u8 musb_read_txfunaddr(void __iomem *mbase, u8 epnum) -{ - return 0; -} - -static inline u8 musb_read_txhubaddr(void __iomem *mbase, u8 epnum) -{ - return 0; -} - -static inline u8 musb_read_txhubport(void __iomem *mbase, u8 epnum) -{ - return 0; -} - -#endif /* CONFIG_BLACKFIN */ - -#endif /* __MUSB_REGS_H__ */ diff --git a/ANDROID_3.4.5/drivers/usb/musb/musb_virthub.c b/ANDROID_3.4.5/drivers/usb/musb/musb_virthub.c deleted file mode 100644 index 22ec3e37..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/musb_virthub.c +++ /dev/null @@ -1,435 +0,0 @@ -/* - * MUSB OTG driver virtual root hub support - * - * Copyright 2005 Mentor Graphics Corporation - * Copyright (C) 2005-2006 by Texas Instruments - * Copyright (C) 2006-2007 Nokia Corporation - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "musb_core.h" - - -static void musb_port_suspend(struct musb *musb, bool do_suspend) -{ - struct usb_otg *otg = musb->xceiv->otg; - u8 power; - void __iomem *mbase = musb->mregs; - - if (!is_host_active(musb)) - return; - - /* NOTE: this doesn't necessarily put PHY into low power mode, - * turning off its clock; that's a function of PHY integration and - * MUSB_POWER_ENSUSPEND. PHY may need a clock (sigh) to detect - * SE0 changing to connect (J) or wakeup (K) states. - */ - power = musb_readb(mbase, MUSB_POWER); - if (do_suspend) { - int retries = 10000; - - power &= ~MUSB_POWER_RESUME; - power |= MUSB_POWER_SUSPENDM; - musb_writeb(mbase, MUSB_POWER, power); - - /* Needed for OPT A tests */ - power = musb_readb(mbase, MUSB_POWER); - while (power & MUSB_POWER_SUSPENDM) { - power = musb_readb(mbase, MUSB_POWER); - if (retries-- < 1) - break; - } - - dev_dbg(musb->controller, "Root port suspended, power %02x\n", power); - - musb->port1_status |= USB_PORT_STAT_SUSPEND; - switch (musb->xceiv->state) { - case OTG_STATE_A_HOST: - musb->xceiv->state = OTG_STATE_A_SUSPEND; - musb->is_active = is_otg_enabled(musb) - && otg->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; - case OTG_STATE_B_HOST: - musb->xceiv->state = OTG_STATE_B_WAIT_ACON; - musb->is_active = is_otg_enabled(musb) - && otg->host->b_hnp_enable; - musb_platform_try_idle(musb, 0); - break; - default: - dev_dbg(musb->controller, "bogus rh suspend? %s\n", - otg_state_string(musb->xceiv->state)); - } - } else if (power & MUSB_POWER_SUSPENDM) { - power &= ~MUSB_POWER_SUSPENDM; - power |= MUSB_POWER_RESUME; - musb_writeb(mbase, MUSB_POWER, power); - - dev_dbg(musb->controller, "Root port resuming, power %02x\n", power); - - /* later, GetPortStatus will stop RESUME signaling */ - musb->port1_status |= MUSB_PORT_STAT_RESUME; - musb->rh_timer = jiffies + msecs_to_jiffies(20); - } -} - -static void musb_port_reset(struct musb *musb, bool do_reset) -{ - u8 power; - void __iomem *mbase = musb->mregs; - - if (musb->xceiv->state == OTG_STATE_B_IDLE) { - dev_dbg(musb->controller, "HNP: Returning from HNP; no hub reset from b_idle\n"); - musb->port1_status &= ~USB_PORT_STAT_RESET; - return; - } - - if (!is_host_active(musb)) - return; - - /* NOTE: caller guarantees it will turn off the reset when - * the appropriate amount of time has passed - */ - power = musb_readb(mbase, MUSB_POWER); - if (do_reset) { - - /* - * If RESUME is set, we must make sure it stays minimum 20 ms. - * Then we must clear RESUME and wait a bit to let musb start - * generating SOFs. If we don't do this, OPT HS A 6.8 tests - * fail with "Error! Did not receive an SOF before suspend - * detected". - */ - if (power & MUSB_POWER_RESUME) { - while (time_before(jiffies, musb->rh_timer)) - msleep(1); - musb_writeb(mbase, MUSB_POWER, - power & ~MUSB_POWER_RESUME); - msleep(1); - } - - musb->ignore_disconnect = true; - power &= 0xf0; - musb_writeb(mbase, MUSB_POWER, - power | MUSB_POWER_RESET); - - musb->port1_status |= USB_PORT_STAT_RESET; - musb->port1_status &= ~USB_PORT_STAT_ENABLE; - musb->rh_timer = jiffies + msecs_to_jiffies(50); - } else { - dev_dbg(musb->controller, "root port reset stopped\n"); - musb_writeb(mbase, MUSB_POWER, - power & ~MUSB_POWER_RESET); - - musb->ignore_disconnect = false; - - power = musb_readb(mbase, MUSB_POWER); - if (power & MUSB_POWER_HSMODE) { - dev_dbg(musb->controller, "high-speed device connected\n"); - musb->port1_status |= USB_PORT_STAT_HIGH_SPEED; - } - - musb->port1_status &= ~USB_PORT_STAT_RESET; - musb->port1_status |= USB_PORT_STAT_ENABLE - | (USB_PORT_STAT_C_RESET << 16) - | (USB_PORT_STAT_C_ENABLE << 16); - usb_hcd_poll_rh_status(musb_to_hcd(musb)); - - musb->vbuserr_retry = VBUSERR_RETRY_COUNT; - } -} - -void musb_root_disconnect(struct musb *musb) -{ - struct usb_otg *otg = musb->xceiv->otg; - - musb->port1_status = USB_PORT_STAT_POWER - | (USB_PORT_STAT_C_CONNECTION << 16); - - usb_hcd_poll_rh_status(musb_to_hcd(musb)); - musb->is_active = 0; - - switch (musb->xceiv->state) { - case OTG_STATE_A_SUSPEND: - if (is_otg_enabled(musb) - && otg->host->b_hnp_enable) { - musb->xceiv->state = OTG_STATE_A_PERIPHERAL; - musb->g.is_a_peripheral = 1; - break; - } - /* 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; - break; - default: - dev_dbg(musb->controller, "host disconnect (%s)\n", - otg_state_string(musb->xceiv->state)); - } -} - - -/*---------------------------------------------------------------------*/ - -/* Caller may or may not hold musb->lock */ -int musb_hub_status_data(struct usb_hcd *hcd, char *buf) -{ - struct musb *musb = hcd_to_musb(hcd); - int retval = 0; - - /* called in_irq() via usb_hcd_poll_rh_status() */ - if (musb->port1_status & 0xffff0000) { - *buf = 0x02; - retval = 1; - } - return retval; -} - -int musb_hub_control( - struct usb_hcd *hcd, - u16 typeReq, - u16 wValue, - u16 wIndex, - char *buf, - u16 wLength) -{ - struct musb *musb = hcd_to_musb(hcd); - u32 temp; - int retval = 0; - unsigned long flags; - - spin_lock_irqsave(&musb->lock, flags); - - if (unlikely(!HCD_HW_ACCESSIBLE(hcd))) { - spin_unlock_irqrestore(&musb->lock, flags); - return -ESHUTDOWN; - } - - /* hub features: always zero, setting is a NOP - * port features: reported, sometimes updated when host is active - * no indicators - */ - switch (typeReq) { - case ClearHubFeature: - case SetHubFeature: - switch (wValue) { - case C_HUB_OVER_CURRENT: - case C_HUB_LOCAL_POWER: - break; - default: - goto error; - } - break; - case ClearPortFeature: - if ((wIndex & 0xff) != 1) - goto error; - - switch (wValue) { - case USB_PORT_FEAT_ENABLE: - break; - case USB_PORT_FEAT_SUSPEND: - musb_port_suspend(musb, false); - break; - case USB_PORT_FEAT_POWER: - if (!(is_otg_enabled(musb) && hcd->self.is_b_host)) - musb_platform_set_vbus(musb, 0); - break; - case USB_PORT_FEAT_C_CONNECTION: - case USB_PORT_FEAT_C_ENABLE: - case USB_PORT_FEAT_C_OVER_CURRENT: - case USB_PORT_FEAT_C_RESET: - case USB_PORT_FEAT_C_SUSPEND: - break; - default: - goto error; - } - dev_dbg(musb->controller, "clear feature %d\n", wValue); - musb->port1_status &= ~(1 << wValue); - break; - case GetHubDescriptor: - { - struct usb_hub_descriptor *desc = (void *)buf; - - desc->bDescLength = 9; - desc->bDescriptorType = 0x29; - desc->bNbrPorts = 1; - desc->wHubCharacteristics = cpu_to_le16( - 0x0001 /* per-port power switching */ - | 0x0010 /* no overcurrent reporting */ - ); - desc->bPwrOn2PwrGood = 5; /* msec/2 */ - desc->bHubContrCurrent = 0; - - /* workaround bogus struct definition */ - desc->u.hs.DeviceRemovable[0] = 0x02; /* port 1 */ - desc->u.hs.DeviceRemovable[1] = 0xff; - } - break; - case GetHubStatus: - temp = 0; - *(__le32 *) buf = cpu_to_le32(temp); - break; - case GetPortStatus: - if (wIndex != 1) - goto error; - - /* finish RESET signaling? */ - if ((musb->port1_status & USB_PORT_STAT_RESET) - && time_after_eq(jiffies, musb->rh_timer)) - musb_port_reset(musb, false); - - /* finish RESUME signaling? */ - if ((musb->port1_status & MUSB_PORT_STAT_RESUME) - && time_after_eq(jiffies, musb->rh_timer)) { - u8 power; - - power = musb_readb(musb->mregs, MUSB_POWER); - power &= ~MUSB_POWER_RESUME; - dev_dbg(musb->controller, "root port resume stopped, power %02x\n", - power); - musb_writeb(musb->mregs, MUSB_POWER, power); - - /* ISSUE: DaVinci (RTL 1.300) disconnects after - * resume of high speed peripherals (but not full - * speed ones). - */ - - musb->is_active = 1; - musb->port1_status &= ~(USB_PORT_STAT_SUSPEND - | MUSB_PORT_STAT_RESUME); - 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; - } - - put_unaligned(cpu_to_le32(musb->port1_status - & ~MUSB_PORT_STAT_RESUME), - (__le32 *) buf); - - /* port change status is more interesting */ - dev_dbg(musb->controller, "port status %08x\n", - musb->port1_status); - break; - case SetPortFeature: - if ((wIndex & 0xff) != 1) - goto error; - - switch (wValue) { - case USB_PORT_FEAT_POWER: - /* NOTE: this controller has a strange state machine - * that involves "requesting sessions" according to - * magic side effects from incompletely-described - * rules about startup... - * - * This call is what really starts the host mode; be - * very careful about side effects if you reorder any - * initialization logic, e.g. for OTG, or change any - * logic relating to VBUS power-up. - */ - if (!(is_otg_enabled(musb) && hcd->self.is_b_host)) - musb_start(musb); - break; - case USB_PORT_FEAT_RESET: - musb_port_reset(musb, true); - break; - case USB_PORT_FEAT_SUSPEND: - musb_port_suspend(musb, true); - break; - case USB_PORT_FEAT_TEST: - if (unlikely(is_host_active(musb))) - goto error; - - wIndex >>= 8; - switch (wIndex) { - case 1: - pr_debug("TEST_J\n"); - temp = MUSB_TEST_J; - break; - case 2: - pr_debug("TEST_K\n"); - temp = MUSB_TEST_K; - break; - case 3: - pr_debug("TEST_SE0_NAK\n"); - temp = MUSB_TEST_SE0_NAK; - break; - case 4: - pr_debug("TEST_PACKET\n"); - temp = MUSB_TEST_PACKET; - musb_load_testpacket(musb); - break; - case 5: - pr_debug("TEST_FORCE_ENABLE\n"); - temp = MUSB_TEST_FORCE_HOST - | MUSB_TEST_FORCE_HS; - - musb_writeb(musb->mregs, MUSB_DEVCTL, - MUSB_DEVCTL_SESSION); - break; - case 6: - pr_debug("TEST_FIFO_ACCESS\n"); - temp = MUSB_TEST_FIFO_ACCESS; - break; - default: - goto error; - } - musb_writeb(musb->mregs, MUSB_TESTMODE, temp); - break; - default: - goto error; - } - dev_dbg(musb->controller, "set feature %d\n", wValue); - musb->port1_status |= 1 << wValue; - break; - - default: -error: - /* "protocol stall" on error */ - retval = -EPIPE; - } - spin_unlock_irqrestore(&musb->lock, flags); - return retval; -} diff --git a/ANDROID_3.4.5/drivers/usb/musb/musbhsdma.c b/ANDROID_3.4.5/drivers/usb/musb/musbhsdma.c deleted file mode 100644 index 57a60858..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/musbhsdma.c +++ /dev/null @@ -1,422 +0,0 @@ -/* - * MUSB OTG driver - support for Mentor's DMA controller - * - * Copyright 2005 Mentor Graphics Corporation - * Copyright (C) 2005-2007 by Texas Instruments - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ -#include -#include -#include -#include -#include "musb_core.h" -#include "musbhsdma.h" - -static int dma_controller_start(struct dma_controller *c) -{ - /* nothing to do */ - return 0; -} - -static void dma_channel_release(struct dma_channel *channel); - -static int dma_controller_stop(struct dma_controller *c) -{ - struct musb_dma_controller *controller = container_of(c, - struct musb_dma_controller, controller); - struct musb *musb = controller->private_data; - struct dma_channel *channel; - u8 bit; - - if (controller->used_channels != 0) { - dev_err(musb->controller, - "Stopping DMA controller while channel active\n"); - - for (bit = 0; bit < MUSB_HSDMA_CHANNELS; bit++) { - if (controller->used_channels & (1 << bit)) { - channel = &controller->channel[bit].channel; - dma_channel_release(channel); - - if (!controller->used_channels) - break; - } - } - } - - return 0; -} - -static struct dma_channel *dma_channel_allocate(struct dma_controller *c, - struct musb_hw_ep *hw_ep, u8 transmit) -{ - struct musb_dma_controller *controller = container_of(c, - struct musb_dma_controller, controller); - struct musb_dma_channel *musb_channel = NULL; - struct dma_channel *channel = NULL; - u8 bit; - - for (bit = 0; bit < MUSB_HSDMA_CHANNELS; bit++) { - if (!(controller->used_channels & (1 << bit))) { - controller->used_channels |= (1 << bit); - musb_channel = &(controller->channel[bit]); - musb_channel->controller = controller; - musb_channel->idx = bit; - musb_channel->epnum = hw_ep->epnum; - musb_channel->transmit = transmit; - channel = &(musb_channel->channel); - channel->private_data = musb_channel; - channel->status = MUSB_DMA_STATUS_FREE; - channel->max_len = 0x100000; - /* Tx => mode 1; Rx => mode 0 */ - channel->desired_mode = transmit; - channel->actual_len = 0; - break; - } - } - - return channel; -} - -static void dma_channel_release(struct dma_channel *channel) -{ - struct musb_dma_channel *musb_channel = channel->private_data; - - channel->actual_len = 0; - musb_channel->start_addr = 0; - musb_channel->len = 0; - - musb_channel->controller->used_channels &= - ~(1 << musb_channel->idx); - - channel->status = MUSB_DMA_STATUS_UNKNOWN; -} - -static void configure_channel(struct dma_channel *channel, - u16 packet_sz, u8 mode, - dma_addr_t dma_addr, u32 len) -{ - struct musb_dma_channel *musb_channel = channel->private_data; - struct musb_dma_controller *controller = musb_channel->controller; - struct musb *musb = controller->private_data; - void __iomem *mbase = controller->base; - u8 bchannel = musb_channel->idx; - u16 csr = 0; - - dev_dbg(musb->controller, "%p, pkt_sz %d, addr 0x%x, len %d, mode %d\n", - channel, packet_sz, dma_addr, len, mode); - - if (mode) { - csr |= 1 << MUSB_HSDMA_MODE1_SHIFT; - BUG_ON(len < packet_sz); - } - csr |= MUSB_HSDMA_BURSTMODE_INCR16 - << MUSB_HSDMA_BURSTMODE_SHIFT; - - csr |= (musb_channel->epnum << MUSB_HSDMA_ENDPOINT_SHIFT) - | (1 << MUSB_HSDMA_ENABLE_SHIFT) - | (1 << MUSB_HSDMA_IRQENABLE_SHIFT) - | (musb_channel->transmit - ? (1 << MUSB_HSDMA_TRANSMIT_SHIFT) - : 0); - - /* address/count */ - musb_write_hsdma_addr(mbase, bchannel, dma_addr); - musb_write_hsdma_count(mbase, bchannel, len); - - /* control (this should start things) */ - musb_writew(mbase, - MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_CONTROL), - csr); -} - -static int dma_channel_program(struct dma_channel *channel, - u16 packet_sz, u8 mode, - dma_addr_t dma_addr, u32 len) -{ - struct musb_dma_channel *musb_channel = channel->private_data; - struct musb_dma_controller *controller = musb_channel->controller; - struct musb *musb = controller->private_data; - - dev_dbg(musb->controller, "ep%d-%s pkt_sz %d, dma_addr 0x%x length %d, mode %d\n", - musb_channel->epnum, - musb_channel->transmit ? "Tx" : "Rx", - packet_sz, dma_addr, len, mode); - - BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN || - channel->status == MUSB_DMA_STATUS_BUSY); - - /* Let targets check/tweak the arguments */ - if (musb->ops->adjust_channel_params) { - int ret = musb->ops->adjust_channel_params(channel, - packet_sz, &mode, &dma_addr, &len); - if (ret) - return ret; - } - - /* - * The DMA engine in RTL1.8 and above cannot handle - * DMA addresses that are not aligned to a 4 byte boundary. - * It ends up masking the last two bits of the address - * programmed in DMA_ADDR. - * - * Fail such DMA transfers, so that the backup PIO mode - * can carry out the transfer - */ - if ((musb->hwvers >= MUSB_HWVERS_1800) && (dma_addr % 4)) - return false; - - channel->actual_len = 0; - musb_channel->start_addr = dma_addr; - musb_channel->len = len; - musb_channel->max_packet_sz = packet_sz; - channel->status = MUSB_DMA_STATUS_BUSY; - - configure_channel(channel, packet_sz, mode, dma_addr, len); - - return true; -} - -static int dma_channel_abort(struct dma_channel *channel) -{ - struct musb_dma_channel *musb_channel = channel->private_data; - void __iomem *mbase = musb_channel->controller->base; - - u8 bchannel = musb_channel->idx; - int offset; - u16 csr; - - if (channel->status == MUSB_DMA_STATUS_BUSY) { - if (musb_channel->transmit) { - offset = MUSB_EP_OFFSET(musb_channel->epnum, - MUSB_TXCSR); - - /* - * The programming guide says that we must clear - * the DMAENAB bit before the DMAMODE bit... - */ - csr = musb_readw(mbase, offset); - csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAENAB); - musb_writew(mbase, offset, csr); - csr &= ~MUSB_TXCSR_DMAMODE; - musb_writew(mbase, offset, csr); - } else { - offset = MUSB_EP_OFFSET(musb_channel->epnum, - MUSB_RXCSR); - - csr = musb_readw(mbase, offset); - csr &= ~(MUSB_RXCSR_AUTOCLEAR | - MUSB_RXCSR_DMAENAB | - MUSB_RXCSR_DMAMODE); - musb_writew(mbase, offset, csr); - } - - musb_writew(mbase, - MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_CONTROL), - 0); - musb_write_hsdma_addr(mbase, bchannel, 0); - musb_write_hsdma_count(mbase, bchannel, 0); - channel->status = MUSB_DMA_STATUS_FREE; - } - - return 0; -} - -static irqreturn_t dma_controller_irq(int irq, void *private_data) -{ - struct musb_dma_controller *controller = private_data; - struct musb *musb = controller->private_data; - struct musb_dma_channel *musb_channel; - struct dma_channel *channel; - - void __iomem *mbase = controller->base; - - irqreturn_t retval = IRQ_NONE; - - unsigned long flags; - - u8 bchannel; - u8 int_hsdma; - - u32 addr, count; - u16 csr; - - spin_lock_irqsave(&musb->lock, flags); - - int_hsdma = musb_readb(mbase, MUSB_HSDMA_INTR); - -#ifdef CONFIG_BLACKFIN - /* Clear DMA interrupt flags */ - musb_writeb(mbase, MUSB_HSDMA_INTR, int_hsdma); -#endif - - if (!int_hsdma) { - dev_dbg(musb->controller, "spurious DMA irq\n"); - - for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) { - musb_channel = (struct musb_dma_channel *) - &(controller->channel[bchannel]); - channel = &musb_channel->channel; - if (channel->status == MUSB_DMA_STATUS_BUSY) { - count = musb_read_hsdma_count(mbase, bchannel); - - if (count == 0) - int_hsdma |= (1 << bchannel); - } - } - - dev_dbg(musb->controller, "int_hsdma = 0x%x\n", int_hsdma); - - if (!int_hsdma) - goto done; - } - - for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) { - if (int_hsdma & (1 << bchannel)) { - musb_channel = (struct musb_dma_channel *) - &(controller->channel[bchannel]); - channel = &musb_channel->channel; - - csr = musb_readw(mbase, - MUSB_HSDMA_CHANNEL_OFFSET(bchannel, - MUSB_HSDMA_CONTROL)); - - if (csr & (1 << MUSB_HSDMA_BUSERROR_SHIFT)) { - musb_channel->channel.status = - MUSB_DMA_STATUS_BUS_ABORT; - } else { - u8 devctl; - - addr = musb_read_hsdma_addr(mbase, - bchannel); - channel->actual_len = addr - - musb_channel->start_addr; - - dev_dbg(musb->controller, "ch %p, 0x%x -> 0x%x (%zu / %d) %s\n", - channel, musb_channel->start_addr, - addr, channel->actual_len, - musb_channel->len, - (channel->actual_len - < musb_channel->len) ? - "=> reconfig 0" : "=> complete"); - - devctl = musb_readb(mbase, MUSB_DEVCTL); - - channel->status = MUSB_DMA_STATUS_FREE; - - /* completed */ - if ((devctl & MUSB_DEVCTL_HM) - && (musb_channel->transmit) - && ((channel->desired_mode == 0) - || (channel->actual_len & - (musb_channel->max_packet_sz - 1))) - ) { - u8 epnum = musb_channel->epnum; - int offset = MUSB_EP_OFFSET(epnum, - MUSB_TXCSR); - u16 txcsr; - - /* - * The programming guide says that we - * must clear DMAENAB before DMAMODE. - */ - musb_ep_select(mbase, epnum); - txcsr = musb_readw(mbase, offset); - txcsr &= ~(MUSB_TXCSR_DMAENAB - | MUSB_TXCSR_AUTOSET); - musb_writew(mbase, offset, txcsr); - /* Send out the packet */ - txcsr &= ~MUSB_TXCSR_DMAMODE; - txcsr |= MUSB_TXCSR_TXPKTRDY; - musb_writew(mbase, offset, txcsr); - } - musb_dma_completion(musb, musb_channel->epnum, - musb_channel->transmit); - } - } - } - - retval = IRQ_HANDLED; -done: - spin_unlock_irqrestore(&musb->lock, flags); - return retval; -} - -void dma_controller_destroy(struct dma_controller *c) -{ - struct musb_dma_controller *controller = container_of(c, - struct musb_dma_controller, controller); - - if (!controller) - return; - - if (controller->irq) - free_irq(controller->irq, c); - - kfree(controller); -} - -struct dma_controller *__init -dma_controller_create(struct musb *musb, void __iomem *base) -{ - struct musb_dma_controller *controller; - struct device *dev = musb->controller; - struct platform_device *pdev = to_platform_device(dev); - int irq = platform_get_irq_byname(pdev, "dma"); - - if (irq == 0) { - dev_err(dev, "No DMA interrupt line!\n"); - return NULL; - } - - controller = kzalloc(sizeof(*controller), GFP_KERNEL); - if (!controller) - return NULL; - - controller->channel_count = MUSB_HSDMA_CHANNELS; - controller->private_data = musb; - controller->base = base; - - controller->controller.start = dma_controller_start; - controller->controller.stop = dma_controller_stop; - controller->controller.channel_alloc = dma_channel_allocate; - controller->controller.channel_release = dma_channel_release; - controller->controller.channel_program = dma_channel_program; - controller->controller.channel_abort = dma_channel_abort; - - if (request_irq(irq, dma_controller_irq, 0, - dev_name(musb->controller), &controller->controller)) { - dev_err(dev, "request_irq %d failed!\n", irq); - dma_controller_destroy(&controller->controller); - - return NULL; - } - - controller->irq = irq; - - return &controller->controller; -} diff --git a/ANDROID_3.4.5/drivers/usb/musb/musbhsdma.h b/ANDROID_3.4.5/drivers/usb/musb/musbhsdma.h deleted file mode 100644 index 320fd4af..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/musbhsdma.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * MUSB OTG driver - support for Mentor's DMA controller - * - * Copyright 2005 Mentor Graphics Corporation - * Copyright (C) 2005-2007 by Texas Instruments - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430) -#include "omap2430.h" -#endif - -#ifndef CONFIG_BLACKFIN - -#define MUSB_HSDMA_BASE 0x200 -#define MUSB_HSDMA_INTR (MUSB_HSDMA_BASE + 0) -#define MUSB_HSDMA_CONTROL 0x4 -#define MUSB_HSDMA_ADDRESS 0x8 -#define MUSB_HSDMA_COUNT 0xc - -#define MUSB_HSDMA_CHANNEL_OFFSET(_bchannel, _offset) \ - (MUSB_HSDMA_BASE + (_bchannel << 4) + _offset) - -#define musb_read_hsdma_addr(mbase, bchannel) \ - musb_readl(mbase, \ - MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDRESS)) - -#define musb_write_hsdma_addr(mbase, bchannel, addr) \ - musb_writel(mbase, \ - MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDRESS), \ - addr) - -#define musb_read_hsdma_count(mbase, bchannel) \ - musb_readl(mbase, \ - MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT)) - -#define musb_write_hsdma_count(mbase, bchannel, len) \ - musb_writel(mbase, \ - MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT), \ - len) -#else - -#define MUSB_HSDMA_BASE 0x400 -#define MUSB_HSDMA_INTR (MUSB_HSDMA_BASE + 0) -#define MUSB_HSDMA_CONTROL 0x04 -#define MUSB_HSDMA_ADDR_LOW 0x08 -#define MUSB_HSDMA_ADDR_HIGH 0x0C -#define MUSB_HSDMA_COUNT_LOW 0x10 -#define MUSB_HSDMA_COUNT_HIGH 0x14 - -#define MUSB_HSDMA_CHANNEL_OFFSET(_bchannel, _offset) \ - (MUSB_HSDMA_BASE + (_bchannel * 0x20) + _offset) - -static inline u32 musb_read_hsdma_addr(void __iomem *mbase, u8 bchannel) -{ - u32 addr = musb_readw(mbase, - MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDR_HIGH)); - - addr = addr << 16; - - addr |= musb_readw(mbase, - MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDR_LOW)); - - return addr; -} - -static inline void musb_write_hsdma_addr(void __iomem *mbase, - u8 bchannel, dma_addr_t dma_addr) -{ - musb_writew(mbase, - MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDR_LOW), - dma_addr); - musb_writew(mbase, - MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDR_HIGH), - (dma_addr >> 16)); -} - -static inline u32 musb_read_hsdma_count(void __iomem *mbase, u8 bchannel) -{ - u32 count = musb_readw(mbase, - MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_HIGH)); - - count = count << 16; - - count |= musb_readw(mbase, - MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_LOW)); - - return count; -} - -static inline void musb_write_hsdma_count(void __iomem *mbase, - u8 bchannel, u32 len) -{ - musb_writew(mbase, - MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_LOW),len); - musb_writew(mbase, - MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_HIGH), - (len >> 16)); -} - -#endif /* CONFIG_BLACKFIN */ - -/* control register (16-bit): */ -#define MUSB_HSDMA_ENABLE_SHIFT 0 -#define MUSB_HSDMA_TRANSMIT_SHIFT 1 -#define MUSB_HSDMA_MODE1_SHIFT 2 -#define MUSB_HSDMA_IRQENABLE_SHIFT 3 -#define MUSB_HSDMA_ENDPOINT_SHIFT 4 -#define MUSB_HSDMA_BUSERROR_SHIFT 8 -#define MUSB_HSDMA_BURSTMODE_SHIFT 9 -#define MUSB_HSDMA_BURSTMODE (3 << MUSB_HSDMA_BURSTMODE_SHIFT) -#define MUSB_HSDMA_BURSTMODE_UNSPEC 0 -#define MUSB_HSDMA_BURSTMODE_INCR4 1 -#define MUSB_HSDMA_BURSTMODE_INCR8 2 -#define MUSB_HSDMA_BURSTMODE_INCR16 3 - -#define MUSB_HSDMA_CHANNELS 8 - -struct musb_dma_controller; - -struct musb_dma_channel { - struct dma_channel channel; - struct musb_dma_controller *controller; - u32 start_addr; - u32 len; - u16 max_packet_sz; - u8 idx; - u8 epnum; - u8 transmit; -}; - -struct musb_dma_controller { - struct dma_controller controller; - struct musb_dma_channel channel[MUSB_HSDMA_CHANNELS]; - void *private_data; - void __iomem *base; - u8 channel_count; - u8 used_channels; - u8 irq; -}; diff --git a/ANDROID_3.4.5/drivers/usb/musb/omap2430.c b/ANDROID_3.4.5/drivers/usb/musb/omap2430.c deleted file mode 100644 index c7785e81..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/omap2430.c +++ /dev/null @@ -1,555 +0,0 @@ -/* - * Copyright (C) 2005-2007 by Texas Instruments - * Some code has been taken from tusb6010.c - * Copyrights for that are attributable to: - * Copyright (C) 2006 Nokia Corporation - * Tony Lindgren - * - * This file is part of the Inventra Controller Driver for Linux. - * - * The Inventra Controller Driver for Linux 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. - * - * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not, - * write to the Free Software Foundation, Inc., 59 Temple Place, - * Suite 330, Boston, MA 02111-1307 USA - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "musb_core.h" -#include "omap2430.h" - -struct omap2430_glue { - struct device *dev; - struct platform_device *musb; -}; -#define glue_to_musb(g) platform_get_drvdata(g->musb) - -static struct timer_list musb_idle_timer; - -static void musb_do_idle(unsigned long _musb) -{ - struct musb *musb = (void *)_musb; - unsigned long flags; - u8 power; - u8 devctl; - - spin_lock_irqsave(&musb->lock, flags); - - switch (musb->xceiv->state) { - case OTG_STATE_A_WAIT_BCON: - - devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - if (devctl & MUSB_DEVCTL_BDEVICE) { - musb->xceiv->state = OTG_STATE_B_IDLE; - MUSB_DEV_MODE(musb); - } else { - musb->xceiv->state = OTG_STATE_A_IDLE; - MUSB_HST_MODE(musb); - } - break; - case OTG_STATE_A_SUSPEND: - /* finish RESUME signaling? */ - if (musb->port1_status & MUSB_PORT_STAT_RESUME) { - power = musb_readb(musb->mregs, MUSB_POWER); - power &= ~MUSB_POWER_RESUME; - dev_dbg(musb->controller, "root port resume stopped, power %02x\n", power); - musb_writeb(musb->mregs, MUSB_POWER, power); - musb->is_active = 1; - musb->port1_status &= ~(USB_PORT_STAT_SUSPEND - | MUSB_PORT_STAT_RESUME); - 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; - } - break; - case OTG_STATE_A_HOST: - devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - if (devctl & MUSB_DEVCTL_BDEVICE) - musb->xceiv->state = OTG_STATE_B_IDLE; - else - musb->xceiv->state = OTG_STATE_A_WAIT_BCON; - default: - break; - } - spin_unlock_irqrestore(&musb->lock, flags); -} - - -static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout) -{ - unsigned long default_timeout = jiffies + msecs_to_jiffies(3); - static unsigned long last_timer; - - if (timeout == 0) - timeout = default_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))) { - dev_dbg(musb->controller, "%s active, deleting timer\n", - otg_state_string(musb->xceiv->state)); - del_timer(&musb_idle_timer); - last_timer = jiffies; - return; - } - - if (time_after(last_timer, timeout)) { - if (!timer_pending(&musb_idle_timer)) - last_timer = timeout; - else { - dev_dbg(musb->controller, "Longer idle timer already pending, ignoring\n"); - return; - } - } - last_timer = timeout; - - dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n", - otg_state_string(musb->xceiv->state), - (unsigned long)jiffies_to_msecs(timeout - jiffies)); - mod_timer(&musb_idle_timer, timeout); -} - -static void omap2430_musb_set_vbus(struct musb *musb, int is_on) -{ - struct usb_otg *otg = musb->xceiv->otg; - u8 devctl; - unsigned long timeout = jiffies + msecs_to_jiffies(1000); - int ret = 1; - /* HDRC controls CPEN, but beware current surges during device - * connect. They can trigger transient overcurrent conditions - * that must be ignored. - */ - - devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - - if (is_on) { - if (musb->xceiv->state == OTG_STATE_A_IDLE) { - /* start the session */ - devctl |= MUSB_DEVCTL_SESSION; - musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); - /* - * Wait for the musb to set as A device to enable the - * VBUS - */ - while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) { - - cpu_relax(); - - if (time_after(jiffies, timeout)) { - dev_err(musb->controller, - "configured as A device timeout"); - ret = -EINVAL; - break; - } - } - - if (ret && otg->set_vbus) - otg_set_vbus(otg, 1); - } else { - musb->is_active = 1; - otg->default_a = 1; - musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; - devctl |= MUSB_DEVCTL_SESSION; - MUSB_HST_MODE(musb); - } - } else { - musb->is_active = 0; - - /* NOTE: we're skipping A_WAIT_VFALL -> A_IDLE and - * jumping right to B_IDLE... - */ - - otg->default_a = 0; - musb->xceiv->state = OTG_STATE_B_IDLE; - devctl &= ~MUSB_DEVCTL_SESSION; - - MUSB_DEV_MODE(musb); - } - musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); - - dev_dbg(musb->controller, "VBUS %s, devctl %02x " - /* otg %3x conf %08x prcm %08x */ "\n", - otg_state_string(musb->xceiv->state), - musb_readb(musb->mregs, MUSB_DEVCTL)); -} - -static int omap2430_musb_set_mode(struct musb *musb, u8 musb_mode) -{ - u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - - devctl |= MUSB_DEVCTL_SESSION; - musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); - - return 0; -} - -static inline void omap2430_low_level_exit(struct musb *musb) -{ - u32 l; - - /* in any role */ - l = musb_readl(musb->mregs, OTG_FORCESTDBY); - l |= ENABLEFORCE; /* enable MSTANDBY */ - musb_writel(musb->mregs, OTG_FORCESTDBY, l); -} - -static inline void omap2430_low_level_init(struct musb *musb) -{ - u32 l; - - l = musb_readl(musb->mregs, OTG_FORCESTDBY); - l &= ~ENABLEFORCE; /* disable MSTANDBY */ - musb_writel(musb->mregs, OTG_FORCESTDBY, l); -} - -static int musb_otg_notifications(struct notifier_block *nb, - unsigned long event, void *unused) -{ - struct musb *musb = container_of(nb, struct musb, nb); - - musb->xceiv_event = event; - schedule_work(&musb->otg_notifier_work); - - return NOTIFY_OK; -} - -static void musb_otg_notifier_work(struct work_struct *data_notifier_work) -{ - struct musb *musb = container_of(data_notifier_work, struct musb, otg_notifier_work); - struct device *dev = musb->controller; - struct musb_hdrc_platform_data *pdata = dev->platform_data; - struct omap_musb_board_data *data = pdata->board_data; - - switch (musb->xceiv_event) { - case USB_EVENT_ID: - dev_dbg(musb->controller, "ID GND\n"); - - if (!is_otg_enabled(musb) || musb->gadget_driver) { - pm_runtime_get_sync(musb->controller); - usb_phy_init(musb->xceiv); - omap2430_musb_set_vbus(musb, 1); - } - break; - - case USB_EVENT_VBUS: - dev_dbg(musb->controller, "VBUS Connect\n"); - - if (musb->gadget_driver) - pm_runtime_get_sync(musb->controller); - usb_phy_init(musb->xceiv); - break; - - case USB_EVENT_NONE: - dev_dbg(musb->controller, "VBUS Disconnect\n"); - - if (is_otg_enabled(musb) || is_peripheral_enabled(musb)) - if (musb->gadget_driver) { - pm_runtime_mark_last_busy(musb->controller); - pm_runtime_put_autosuspend(musb->controller); - } - - if (data->interface_type == MUSB_INTERFACE_UTMI) { - if (musb->xceiv->otg->set_vbus) - otg_set_vbus(musb->xceiv->otg, 0); - } - usb_phy_shutdown(musb->xceiv); - break; - default: - dev_dbg(musb->controller, "ID float\n"); - } -} - -static int omap2430_musb_init(struct musb *musb) -{ - u32 l; - int status = 0; - struct device *dev = musb->controller; - struct musb_hdrc_platform_data *plat = dev->platform_data; - struct omap_musb_board_data *data = plat->board_data; - - /* 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 = usb_get_transceiver(); - if (!musb->xceiv) { - pr_err("HS USB OTG: no transceiver configured\n"); - return -ENODEV; - } - - INIT_WORK(&musb->otg_notifier_work, musb_otg_notifier_work); - - status = pm_runtime_get_sync(dev); - if (status < 0) { - dev_err(dev, "pm_runtime_get_sync FAILED %d\n", status); - goto err1; - } - - l = musb_readl(musb->mregs, OTG_INTERFSEL); - - if (data->interface_type == MUSB_INTERFACE_UTMI) { - /* OMAP4 uses Internal PHY GS70 which uses UTMI interface */ - l &= ~ULPI_12PIN; /* Disable ULPI */ - l |= UTMI_8BIT; /* Enable UTMI */ - } else { - l |= ULPI_12PIN; - } - - musb_writel(musb->mregs, OTG_INTERFSEL, l); - - pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, " - "sysstatus 0x%x, intrfsel 0x%x, simenable 0x%x\n", - musb_readl(musb->mregs, OTG_REVISION), - musb_readl(musb->mregs, OTG_SYSCONFIG), - musb_readl(musb->mregs, OTG_SYSSTATUS), - musb_readl(musb->mregs, OTG_INTERFSEL), - musb_readl(musb->mregs, OTG_SIMENABLE)); - - musb->nb.notifier_call = musb_otg_notifications; - status = usb_register_notifier(musb->xceiv, &musb->nb); - - if (status) - dev_dbg(musb->controller, "notification register failed\n"); - - setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); - - pm_runtime_put_noidle(musb->controller); - return 0; - -err1: - return status; -} - -static void omap2430_musb_enable(struct musb *musb) -{ - u8 devctl; - unsigned long timeout = jiffies + msecs_to_jiffies(1000); - struct device *dev = musb->controller; - struct musb_hdrc_platform_data *pdata = dev->platform_data; - struct omap_musb_board_data *data = pdata->board_data; - - switch (musb->xceiv->last_event) { - - case USB_EVENT_ID: - usb_phy_init(musb->xceiv); - if (data->interface_type != MUSB_INTERFACE_UTMI) - break; - devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - /* start the session */ - devctl |= MUSB_DEVCTL_SESSION; - musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); - while (musb_readb(musb->mregs, MUSB_DEVCTL) & - MUSB_DEVCTL_BDEVICE) { - cpu_relax(); - - if (time_after(jiffies, timeout)) { - dev_err(dev, "configured as A device timeout"); - break; - } - } - break; - - case USB_EVENT_VBUS: - usb_phy_init(musb->xceiv); - break; - - default: - break; - } -} - -static void omap2430_musb_disable(struct musb *musb) -{ - if (musb->xceiv->last_event) - usb_phy_shutdown(musb->xceiv); -} - -static int omap2430_musb_exit(struct musb *musb) -{ - del_timer_sync(&musb_idle_timer); - cancel_work_sync(&musb->otg_notifier_work); - - omap2430_low_level_exit(musb); - usb_put_transceiver(musb->xceiv); - - return 0; -} - -static const struct musb_platform_ops omap2430_ops = { - .init = omap2430_musb_init, - .exit = omap2430_musb_exit, - - .set_mode = omap2430_musb_set_mode, - .try_idle = omap2430_musb_try_idle, - - .set_vbus = omap2430_musb_set_vbus, - - .enable = omap2430_musb_enable, - .disable = omap2430_musb_disable, -}; - -static u64 omap2430_dmamask = DMA_BIT_MASK(32); - -static int __devinit omap2430_probe(struct platform_device *pdev) -{ - struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; - struct platform_device *musb; - struct omap2430_glue *glue; - int ret = -ENOMEM; - - glue = kzalloc(sizeof(*glue), GFP_KERNEL); - if (!glue) { - dev_err(&pdev->dev, "failed to allocate glue context\n"); - goto err0; - } - - musb = platform_device_alloc("musb-hdrc", -1); - if (!musb) { - dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err1; - } - - musb->dev.parent = &pdev->dev; - musb->dev.dma_mask = &omap2430_dmamask; - musb->dev.coherent_dma_mask = omap2430_dmamask; - - glue->dev = &pdev->dev; - glue->musb = musb; - - pdata->platform_ops = &omap2430_ops; - - platform_set_drvdata(pdev, glue); - - ret = platform_device_add_resources(musb, pdev->resource, - pdev->num_resources); - if (ret) { - dev_err(&pdev->dev, "failed to add resources\n"); - goto err2; - } - - ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); - if (ret) { - dev_err(&pdev->dev, "failed to add platform_data\n"); - goto err2; - } - - pm_runtime_enable(&pdev->dev); - - ret = platform_device_add(musb); - if (ret) { - dev_err(&pdev->dev, "failed to register musb device\n"); - goto err2; - } - - return 0; - -err2: - platform_device_put(musb); - -err1: - kfree(glue); - -err0: - return ret; -} - -static int __devexit omap2430_remove(struct platform_device *pdev) -{ - struct omap2430_glue *glue = platform_get_drvdata(pdev); - - platform_device_del(glue->musb); - platform_device_put(glue->musb); - kfree(glue); - - return 0; -} - -#ifdef CONFIG_PM - -static int omap2430_runtime_suspend(struct device *dev) -{ - struct omap2430_glue *glue = dev_get_drvdata(dev); - struct musb *musb = glue_to_musb(glue); - - if (musb) { - musb->context.otg_interfsel = musb_readl(musb->mregs, - OTG_INTERFSEL); - - omap2430_low_level_exit(musb); - usb_phy_set_suspend(musb->xceiv, 1); - } - - return 0; -} - -static int omap2430_runtime_resume(struct device *dev) -{ - struct omap2430_glue *glue = dev_get_drvdata(dev); - struct musb *musb = glue_to_musb(glue); - - if (musb) { - omap2430_low_level_init(musb); - musb_writel(musb->mregs, OTG_INTERFSEL, - musb->context.otg_interfsel); - - usb_phy_set_suspend(musb->xceiv, 0); - } - - return 0; -} - -static struct dev_pm_ops omap2430_pm_ops = { - .runtime_suspend = omap2430_runtime_suspend, - .runtime_resume = omap2430_runtime_resume, -}; - -#define DEV_PM_OPS (&omap2430_pm_ops) -#else -#define DEV_PM_OPS NULL -#endif - -static struct platform_driver omap2430_driver = { - .probe = omap2430_probe, - .remove = __devexit_p(omap2430_remove), - .driver = { - .name = "musb-omap2430", - .pm = DEV_PM_OPS, - }, -}; - -MODULE_DESCRIPTION("OMAP2PLUS MUSB Glue Layer"); -MODULE_AUTHOR("Felipe Balbi "); -MODULE_LICENSE("GPL v2"); - -static int __init omap2430_init(void) -{ - return platform_driver_register(&omap2430_driver); -} -module_init(omap2430_init); - -static void __exit omap2430_exit(void) -{ - platform_driver_unregister(&omap2430_driver); -} -module_exit(omap2430_exit); diff --git a/ANDROID_3.4.5/drivers/usb/musb/omap2430.h b/ANDROID_3.4.5/drivers/usb/musb/omap2430.h deleted file mode 100644 index 40b3c02a..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/omap2430.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2005-2006 by Texas Instruments - * - * The Inventra Controller Driver for Linux 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 __MUSB_OMAP243X_H__ -#define __MUSB_OMAP243X_H__ - -#include - -/* - * OMAP2430-specific definitions - */ - -#define OTG_REVISION 0x400 - -#define OTG_SYSCONFIG 0x404 -# define MIDLEMODE 12 /* bit position */ -# define FORCESTDBY (0 << MIDLEMODE) -# define NOSTDBY (1 << MIDLEMODE) -# define SMARTSTDBY (2 << MIDLEMODE) - -# define SIDLEMODE 3 /* bit position */ -# define FORCEIDLE (0 << SIDLEMODE) -# define NOIDLE (1 << SIDLEMODE) -# define SMARTIDLE (2 << SIDLEMODE) - -# define ENABLEWAKEUP (1 << 2) -# define SOFTRST (1 << 1) -# define AUTOIDLE (1 << 0) - -#define OTG_SYSSTATUS 0x408 -# define RESETDONE (1 << 0) - -#define OTG_INTERFSEL 0x40c -# define EXTCP (1 << 2) -# define PHYSEL 0 /* bit position */ -# define UTMI_8BIT (0 << PHYSEL) -# define ULPI_12PIN (1 << PHYSEL) -# define ULPI_8PIN (2 << PHYSEL) - -#define OTG_SIMENABLE 0x410 -# define TM1 (1 << 0) - -#define OTG_FORCESTDBY 0x414 -# define ENABLEFORCE (1 << 0) - -#endif /* __MUSB_OMAP243X_H__ */ diff --git a/ANDROID_3.4.5/drivers/usb/musb/tusb6010.c b/ANDROID_3.4.5/drivers/usb/musb/tusb6010.c deleted file mode 100644 index de135594..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/tusb6010.c +++ /dev/null @@ -1,1265 +0,0 @@ -/* - * TUSB6010 USB 2.0 OTG Dual Role controller - * - * Copyright (C) 2006 Nokia Corporation - * Tony Lindgren - * - * 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. - * - * Notes: - * - Driver assumes that interface to external host (main CPU) is - * configured for NOR FLASH interface instead of VLYNQ serial - * interface. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "musb_core.h" - -struct tusb6010_glue { - struct device *dev; - struct platform_device *musb; -}; - -static void tusb_musb_set_vbus(struct musb *musb, int is_on); - -#define TUSB_REV_MAJOR(reg_val) ((reg_val >> 4) & 0xf) -#define TUSB_REV_MINOR(reg_val) (reg_val & 0xf) - -/* - * Checks the revision. We need to use the DMA register as 3.0 does not - * have correct versions for TUSB_PRCM_REV or TUSB_INT_CTRL_REV. - */ -u8 tusb_get_revision(struct musb *musb) -{ - void __iomem *tbase = musb->ctrl_base; - u32 die_id; - u8 rev; - - rev = musb_readl(tbase, TUSB_DMA_CTRL_REV) & 0xff; - if (TUSB_REV_MAJOR(rev) == 3) { - die_id = TUSB_DIDR1_HI_CHIP_REV(musb_readl(tbase, - TUSB_DIDR1_HI)); - if (die_id >= TUSB_DIDR1_HI_REV_31) - rev |= 1; - } - - return rev; -} -EXPORT_SYMBOL_GPL(tusb_get_revision); - -static int tusb_print_revision(struct musb *musb) -{ - void __iomem *tbase = musb->ctrl_base; - u8 rev; - - rev = tusb_get_revision(musb); - - pr_info("tusb: %s%i.%i %s%i.%i %s%i.%i %s%i.%i %s%i %s%i.%i\n", - "prcm", - TUSB_REV_MAJOR(musb_readl(tbase, TUSB_PRCM_REV)), - TUSB_REV_MINOR(musb_readl(tbase, TUSB_PRCM_REV)), - "int", - TUSB_REV_MAJOR(musb_readl(tbase, TUSB_INT_CTRL_REV)), - TUSB_REV_MINOR(musb_readl(tbase, TUSB_INT_CTRL_REV)), - "gpio", - TUSB_REV_MAJOR(musb_readl(tbase, TUSB_GPIO_REV)), - TUSB_REV_MINOR(musb_readl(tbase, TUSB_GPIO_REV)), - "dma", - TUSB_REV_MAJOR(musb_readl(tbase, TUSB_DMA_CTRL_REV)), - TUSB_REV_MINOR(musb_readl(tbase, TUSB_DMA_CTRL_REV)), - "dieid", - TUSB_DIDR1_HI_CHIP_REV(musb_readl(tbase, TUSB_DIDR1_HI)), - "rev", - TUSB_REV_MAJOR(rev), TUSB_REV_MINOR(rev)); - - return tusb_get_revision(musb); -} - -#define WBUS_QUIRK_MASK (TUSB_PHY_OTG_CTRL_TESTM2 | TUSB_PHY_OTG_CTRL_TESTM1 \ - | TUSB_PHY_OTG_CTRL_TESTM0) - -/* - * Workaround for spontaneous WBUS wake-up issue #2 for tusb3.0. - * Disables power detection in PHY for the duration of idle. - */ -static void tusb_wbus_quirk(struct musb *musb, int enabled) -{ - void __iomem *tbase = musb->ctrl_base; - static u32 phy_otg_ctrl, phy_otg_ena; - u32 tmp; - - if (enabled) { - phy_otg_ctrl = musb_readl(tbase, TUSB_PHY_OTG_CTRL); - phy_otg_ena = musb_readl(tbase, TUSB_PHY_OTG_CTRL_ENABLE); - tmp = TUSB_PHY_OTG_CTRL_WRPROTECT - | phy_otg_ena | WBUS_QUIRK_MASK; - musb_writel(tbase, TUSB_PHY_OTG_CTRL, tmp); - tmp = phy_otg_ena & ~WBUS_QUIRK_MASK; - tmp |= TUSB_PHY_OTG_CTRL_WRPROTECT | TUSB_PHY_OTG_CTRL_TESTM2; - musb_writel(tbase, TUSB_PHY_OTG_CTRL_ENABLE, tmp); - dev_dbg(musb->controller, "Enabled tusb wbus quirk ctrl %08x ena %08x\n", - musb_readl(tbase, TUSB_PHY_OTG_CTRL), - musb_readl(tbase, TUSB_PHY_OTG_CTRL_ENABLE)); - } else if (musb_readl(tbase, TUSB_PHY_OTG_CTRL_ENABLE) - & TUSB_PHY_OTG_CTRL_TESTM2) { - tmp = TUSB_PHY_OTG_CTRL_WRPROTECT | phy_otg_ctrl; - musb_writel(tbase, TUSB_PHY_OTG_CTRL, tmp); - tmp = TUSB_PHY_OTG_CTRL_WRPROTECT | phy_otg_ena; - musb_writel(tbase, TUSB_PHY_OTG_CTRL_ENABLE, tmp); - dev_dbg(musb->controller, "Disabled tusb wbus quirk ctrl %08x ena %08x\n", - musb_readl(tbase, TUSB_PHY_OTG_CTRL), - musb_readl(tbase, TUSB_PHY_OTG_CTRL_ENABLE)); - phy_otg_ctrl = 0; - phy_otg_ena = 0; - } -} - -/* - * TUSB 6010 may use a parallel bus that doesn't support byte ops; - * so both loading and unloading FIFOs need explicit byte counts. - */ - -static inline void -tusb_fifo_write_unaligned(void __iomem *fifo, const u8 *buf, u16 len) -{ - u32 val; - int i; - - if (len > 4) { - for (i = 0; i < (len >> 2); i++) { - memcpy(&val, buf, 4); - musb_writel(fifo, 0, val); - buf += 4; - } - len %= 4; - } - if (len > 0) { - /* Write the rest 1 - 3 bytes to FIFO */ - memcpy(&val, buf, len); - musb_writel(fifo, 0, val); - } -} - -static inline void tusb_fifo_read_unaligned(void __iomem *fifo, - void __iomem *buf, u16 len) -{ - u32 val; - int i; - - if (len > 4) { - for (i = 0; i < (len >> 2); i++) { - val = musb_readl(fifo, 0); - memcpy(buf, &val, 4); - buf += 4; - } - len %= 4; - } - if (len > 0) { - /* Read the rest 1 - 3 bytes from FIFO */ - val = musb_readl(fifo, 0); - memcpy(buf, &val, len); - } -} - -void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *buf) -{ - struct musb *musb = hw_ep->musb; - void __iomem *ep_conf = hw_ep->conf; - void __iomem *fifo = hw_ep->fifo; - u8 epnum = hw_ep->epnum; - - prefetch(buf); - - dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n", - 'T', epnum, fifo, len, buf); - - if (epnum) - musb_writel(ep_conf, TUSB_EP_TX_OFFSET, - TUSB_EP_CONFIG_XFR_SIZE(len)); - else - musb_writel(ep_conf, 0, TUSB_EP0_CONFIG_DIR_TX | - TUSB_EP0_CONFIG_XFR_SIZE(len)); - - if (likely((0x01 & (unsigned long) buf) == 0)) { - - /* Best case is 32bit-aligned destination address */ - if ((0x02 & (unsigned long) buf) == 0) { - if (len >= 4) { - writesl(fifo, buf, len >> 2); - buf += (len & ~0x03); - len &= 0x03; - } - } else { - if (len >= 2) { - u32 val; - int i; - - /* Cannot use writesw, fifo is 32-bit */ - for (i = 0; i < (len >> 2); i++) { - val = (u32)(*(u16 *)buf); - buf += 2; - val |= (*(u16 *)buf) << 16; - buf += 2; - musb_writel(fifo, 0, val); - } - len &= 0x03; - } - } - } - - if (len > 0) - tusb_fifo_write_unaligned(fifo, buf, len); -} - -void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf) -{ - struct musb *musb = hw_ep->musb; - void __iomem *ep_conf = hw_ep->conf; - void __iomem *fifo = hw_ep->fifo; - u8 epnum = hw_ep->epnum; - - dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n", - 'R', epnum, fifo, len, buf); - - if (epnum) - musb_writel(ep_conf, TUSB_EP_RX_OFFSET, - TUSB_EP_CONFIG_XFR_SIZE(len)); - else - musb_writel(ep_conf, 0, TUSB_EP0_CONFIG_XFR_SIZE(len)); - - if (likely((0x01 & (unsigned long) buf) == 0)) { - - /* Best case is 32bit-aligned destination address */ - if ((0x02 & (unsigned long) buf) == 0) { - if (len >= 4) { - readsl(fifo, buf, len >> 2); - buf += (len & ~0x03); - len &= 0x03; - } - } else { - if (len >= 2) { - u32 val; - int i; - - /* Cannot use readsw, fifo is 32-bit */ - for (i = 0; i < (len >> 2); i++) { - val = musb_readl(fifo, 0); - *(u16 *)buf = (u16)(val & 0xffff); - buf += 2; - *(u16 *)buf = (u16)(val >> 16); - buf += 2; - } - len &= 0x03; - } - } - } - - if (len > 0) - tusb_fifo_read_unaligned(fifo, buf, len); -} - -static struct musb *the_musb; - -/* This is used by gadget drivers, and OTG transceiver logic, allowing - * at most mA current to be drawn from VBUS during a Default-B session - * (that is, while VBUS exceeds 4.4V). In Default-A (including pure host - * mode), or low power Default-B sessions, something else supplies power. - * Caller must take care of locking. - */ -static int tusb_draw_power(struct usb_phy *x, unsigned mA) -{ - struct musb *musb = the_musb; - void __iomem *tbase = musb->ctrl_base; - u32 reg; - - /* tps65030 seems to consume max 100mA, with maybe 60mA available - * (measured on one board) for things other than tps and tusb. - * - * Boards sharing the CPU clock with CLKIN will need to prevent - * certain idle sleep states while the USB link is active. - * - * REVISIT we could use VBUS to supply only _one_ of { 1.5V, 3.3V }. - * The actual current usage would be very board-specific. For now, - * it's simpler to just use an aggregate (also board-specific). - */ - if (x->otg->default_a || mA < (musb->min_power << 1)) - mA = 0; - - reg = musb_readl(tbase, TUSB_PRCM_MNGMT); - if (mA) { - musb->is_bus_powered = 1; - reg |= TUSB_PRCM_MNGMT_15_SW_EN | TUSB_PRCM_MNGMT_33_SW_EN; - } else { - musb->is_bus_powered = 0; - reg &= ~(TUSB_PRCM_MNGMT_15_SW_EN | TUSB_PRCM_MNGMT_33_SW_EN); - } - musb_writel(tbase, TUSB_PRCM_MNGMT, reg); - - dev_dbg(musb->controller, "draw max %d mA VBUS\n", mA); - return 0; -} - -/* workaround for issue 13: change clock during chip idle - * (to be fixed in rev3 silicon) ... symptoms include disconnect - * or looping suspend/resume cycles - */ -static void tusb_set_clock_source(struct musb *musb, unsigned mode) -{ - void __iomem *tbase = musb->ctrl_base; - u32 reg; - - reg = musb_readl(tbase, TUSB_PRCM_CONF); - reg &= ~TUSB_PRCM_CONF_SYS_CLKSEL(0x3); - - /* 0 = refclk (clkin, XI) - * 1 = PHY 60 MHz (internal PLL) - * 2 = not supported - * 3 = what? - */ - if (mode > 0) - reg |= TUSB_PRCM_CONF_SYS_CLKSEL(mode & 0x3); - - musb_writel(tbase, TUSB_PRCM_CONF, reg); - - /* FIXME tusb6010_platform_retime(mode == 0); */ -} - -/* - * Idle TUSB6010 until next wake-up event; NOR access always wakes. - * Other code ensures that we idle unless we're connected _and_ the - * USB link is not suspended ... and tells us the relevant wakeup - * events. SW_EN for voltage is handled separately. - */ -static void tusb_allow_idle(struct musb *musb, u32 wakeup_enables) -{ - void __iomem *tbase = musb->ctrl_base; - u32 reg; - - if ((wakeup_enables & TUSB_PRCM_WBUS) - && (tusb_get_revision(musb) == TUSB_REV_30)) - tusb_wbus_quirk(musb, 1); - - tusb_set_clock_source(musb, 0); - - wakeup_enables |= TUSB_PRCM_WNORCS; - musb_writel(tbase, TUSB_PRCM_WAKEUP_MASK, ~wakeup_enables); - - /* REVISIT writeup of WID implies that if WID set and ID is grounded, - * TUSB_PHY_OTG_CTRL.TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP must be cleared. - * Presumably that's mostly to save power, hence WID is immaterial ... - */ - - reg = musb_readl(tbase, TUSB_PRCM_MNGMT); - /* issue 4: when driving vbus, use hipower (vbus_det) comparator */ - if (is_host_active(musb)) { - reg |= TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN; - reg &= ~TUSB_PRCM_MNGMT_OTG_SESS_END_EN; - } else { - reg |= TUSB_PRCM_MNGMT_OTG_SESS_END_EN; - reg &= ~TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN; - } - reg |= TUSB_PRCM_MNGMT_PM_IDLE | TUSB_PRCM_MNGMT_DEV_IDLE; - musb_writel(tbase, TUSB_PRCM_MNGMT, reg); - - dev_dbg(musb->controller, "idle, wake on %02x\n", wakeup_enables); -} - -/* - * Updates cable VBUS status. Caller must take care of locking. - */ -static int tusb_musb_vbus_status(struct musb *musb) -{ - void __iomem *tbase = musb->ctrl_base; - u32 otg_stat, prcm_mngmt; - int ret = 0; - - otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT); - prcm_mngmt = musb_readl(tbase, TUSB_PRCM_MNGMT); - - /* Temporarily enable VBUS detection if it was disabled for - * suspend mode. Unless it's enabled otg_stat and devctl will - * not show correct VBUS state. - */ - if (!(prcm_mngmt & TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN)) { - u32 tmp = prcm_mngmt; - tmp |= TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN; - musb_writel(tbase, TUSB_PRCM_MNGMT, tmp); - otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT); - musb_writel(tbase, TUSB_PRCM_MNGMT, prcm_mngmt); - } - - if (otg_stat & TUSB_DEV_OTG_STAT_VBUS_VALID) - ret = 1; - - return ret; -} - -static struct timer_list musb_idle_timer; - -static void musb_do_idle(unsigned long _musb) -{ - struct musb *musb = (void *)_musb; - unsigned long flags; - - spin_lock_irqsave(&musb->lock, flags); - - switch (musb->xceiv->state) { - case OTG_STATE_A_WAIT_BCON: - if ((musb->a_wait_bcon != 0) - && (musb->idle_timeout == 0 - || time_after(jiffies, musb->idle_timeout))) { - dev_dbg(musb->controller, "Nothing connected %s, turning off VBUS\n", - otg_state_string(musb->xceiv->state)); - } - /* FALLTHROUGH */ - case OTG_STATE_A_IDLE: - tusb_musb_set_vbus(musb, 0); - default: - break; - } - - if (!musb->is_active) { - u32 wakeups; - - /* wait until khubd handles port change status */ - if (is_host_active(musb) && (musb->port1_status >> 16)) - goto done; - - if (is_peripheral_enabled(musb) && !musb->gadget_driver) { - wakeups = 0; - } else { - wakeups = TUSB_PRCM_WHOSTDISCON - | TUSB_PRCM_WBUS - | TUSB_PRCM_WVBUS; - if (is_otg_enabled(musb)) - wakeups |= TUSB_PRCM_WID; - } - tusb_allow_idle(musb, wakeups); - } -done: - spin_unlock_irqrestore(&musb->lock, flags); -} - -/* - * Maybe put TUSB6010 into idle mode mode depending on USB link status, - * like "disconnected" or "suspended". We'll be woken out of it by - * connect, resume, or disconnect. - * - * Needs to be called as the last function everywhere where there is - * register access to TUSB6010 because of NOR flash wake-up. - * Caller should own controller spinlock. - * - * Delay because peripheral enables D+ pullup 3msec after SE0, and - * we don't want to treat that full speed J as a wakeup event. - * ... peripherals must draw only suspend current after 10 msec. - */ -static void tusb_musb_try_idle(struct musb *musb, unsigned long timeout) -{ - unsigned long default_timeout = jiffies + msecs_to_jiffies(3); - static unsigned long last_timer; - - if (timeout == 0) - timeout = default_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))) { - dev_dbg(musb->controller, "%s active, deleting timer\n", - otg_state_string(musb->xceiv->state)); - del_timer(&musb_idle_timer); - last_timer = jiffies; - return; - } - - if (time_after(last_timer, timeout)) { - if (!timer_pending(&musb_idle_timer)) - last_timer = timeout; - else { - dev_dbg(musb->controller, "Longer idle timer already pending, ignoring\n"); - return; - } - } - last_timer = timeout; - - dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n", - otg_state_string(musb->xceiv->state), - (unsigned long)jiffies_to_msecs(timeout - jiffies)); - mod_timer(&musb_idle_timer, timeout); -} - -/* ticks of 60 MHz clock */ -#define DEVCLOCK 60000000 -#define OTG_TIMER_MS(msecs) ((msecs) \ - ? (TUSB_DEV_OTG_TIMER_VAL((DEVCLOCK/1000)*(msecs)) \ - | TUSB_DEV_OTG_TIMER_ENABLE) \ - : 0) - -static void tusb_musb_set_vbus(struct musb *musb, int is_on) -{ - void __iomem *tbase = musb->ctrl_base; - u32 conf, prcm, timer; - u8 devctl; - struct usb_otg *otg = musb->xceiv->otg; - - /* HDRC controls CPEN, but beware current surges during device - * connect. They can trigger transient overcurrent conditions - * that must be ignored. - */ - - prcm = musb_readl(tbase, TUSB_PRCM_MNGMT); - conf = musb_readl(tbase, TUSB_DEV_CONF); - devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - - if (is_on) { - timer = OTG_TIMER_MS(OTG_TIME_A_WAIT_VRISE); - otg->default_a = 1; - musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; - devctl |= MUSB_DEVCTL_SESSION; - - conf |= TUSB_DEV_CONF_USB_HOST_MODE; - MUSB_HST_MODE(musb); - } else { - u32 otg_stat; - - timer = 0; - - /* 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) { - case OTG_STATE_A_WAIT_VRISE: - case OTG_STATE_A_WAIT_BCON: - musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; - break; - case OTG_STATE_A_WAIT_VFALL: - musb->xceiv->state = OTG_STATE_A_IDLE; - break; - default: - musb->xceiv->state = OTG_STATE_A_IDLE; - } - musb->is_active = 0; - otg->default_a = 1; - MUSB_HST_MODE(musb); - } else { - musb->is_active = 0; - otg->default_a = 0; - musb->xceiv->state = OTG_STATE_B_IDLE; - MUSB_DEV_MODE(musb); - } - - devctl &= ~MUSB_DEVCTL_SESSION; - conf &= ~TUSB_DEV_CONF_USB_HOST_MODE; - } - prcm &= ~(TUSB_PRCM_MNGMT_15_SW_EN | TUSB_PRCM_MNGMT_33_SW_EN); - - musb_writel(tbase, TUSB_PRCM_MNGMT, prcm); - musb_writel(tbase, TUSB_DEV_OTG_TIMER, timer); - musb_writel(tbase, TUSB_DEV_CONF, conf); - musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); - - dev_dbg(musb->controller, "VBUS %s, devctl %02x otg %3x conf %08x prcm %08x\n", - otg_state_string(musb->xceiv->state), - musb_readb(musb->mregs, MUSB_DEVCTL), - musb_readl(tbase, TUSB_DEV_OTG_STAT), - conf, prcm); -} - -/* - * Sets the mode to OTG, peripheral or host by changing the ID detection. - * Caller must take care of locking. - * - * Note that if a mini-A cable is plugged in the ID line will stay down as - * the weak ID pull-up is not able to pull the ID up. - * - * REVISIT: It would be possible to add support for changing between host - * and peripheral modes in non-OTG configurations by reconfiguring hardware - * and then setting musb->board_mode. For now, only support OTG mode. - */ -static int tusb_musb_set_mode(struct musb *musb, u8 musb_mode) -{ - void __iomem *tbase = musb->ctrl_base; - u32 otg_stat, phy_otg_ctrl, phy_otg_ena, dev_conf; - - if (musb->board_mode != MUSB_OTG) { - ERR("Changing mode currently only supported in OTG mode\n"); - return -EINVAL; - } - - otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT); - phy_otg_ctrl = musb_readl(tbase, TUSB_PHY_OTG_CTRL); - phy_otg_ena = musb_readl(tbase, TUSB_PHY_OTG_CTRL_ENABLE); - dev_conf = musb_readl(tbase, TUSB_DEV_CONF); - - switch (musb_mode) { - - case MUSB_HOST: /* Disable PHY ID detect, ground ID */ - phy_otg_ctrl &= ~TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP; - phy_otg_ena |= TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP; - dev_conf |= TUSB_DEV_CONF_ID_SEL; - dev_conf &= ~TUSB_DEV_CONF_SOFT_ID; - break; - case MUSB_PERIPHERAL: /* Disable PHY ID detect, keep ID pull-up on */ - phy_otg_ctrl |= TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP; - phy_otg_ena |= TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP; - dev_conf |= (TUSB_DEV_CONF_ID_SEL | TUSB_DEV_CONF_SOFT_ID); - break; - case MUSB_OTG: /* Use PHY ID detection */ - phy_otg_ctrl |= TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP; - phy_otg_ena |= TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP; - dev_conf &= ~(TUSB_DEV_CONF_ID_SEL | TUSB_DEV_CONF_SOFT_ID); - break; - - default: - dev_dbg(musb->controller, "Trying to set mode %i\n", musb_mode); - return -EINVAL; - } - - musb_writel(tbase, TUSB_PHY_OTG_CTRL, - TUSB_PHY_OTG_CTRL_WRPROTECT | phy_otg_ctrl); - musb_writel(tbase, TUSB_PHY_OTG_CTRL_ENABLE, - TUSB_PHY_OTG_CTRL_WRPROTECT | phy_otg_ena); - musb_writel(tbase, TUSB_DEV_CONF, dev_conf); - - otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT); - if ((musb_mode == MUSB_PERIPHERAL) && - !(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS)) - INFO("Cannot be peripheral with mini-A cable " - "otg_stat: %08x\n", otg_stat); - - return 0; -} - -static inline unsigned long -tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase) -{ - u32 otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT); - unsigned long idle_timeout = 0; - struct usb_otg *otg = musb->xceiv->otg; - - /* ID pin */ - if ((int_src & TUSB_INT_SRC_ID_STATUS_CHNG)) { - int default_a; - - if (is_otg_enabled(musb)) - default_a = !(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS); - else - default_a = is_host_enabled(musb); - dev_dbg(musb->controller, "Default-%c\n", default_a ? 'A' : 'B'); - otg->default_a = default_a; - tusb_musb_set_vbus(musb, default_a); - - /* Don't allow idling immediately */ - if (default_a) - idle_timeout = jiffies + (HZ * 3); - } - - /* VBUS state change */ - if (int_src & TUSB_INT_SRC_VBUS_SENSE_CHNG) { - - /* B-dev state machine: no vbus ~= disconnect */ - if ((is_otg_enabled(musb) && !otg->default_a) - || !is_host_enabled(musb)) { - /* ? musb_root_disconnect(musb); */ - musb->port1_status &= - ~(USB_PORT_STAT_CONNECTION - | USB_PORT_STAT_ENABLE - | USB_PORT_STAT_LOW_SPEED - | USB_PORT_STAT_HIGH_SPEED - | USB_PORT_STAT_TEST - ); - - if (otg_stat & TUSB_DEV_OTG_STAT_SESS_END) { - dev_dbg(musb->controller, "Forcing disconnect (no interrupt)\n"); - if (musb->xceiv->state != OTG_STATE_B_IDLE) { - /* INTR_DISCONNECT can hide... */ - musb->xceiv->state = OTG_STATE_B_IDLE; - musb->int_usb |= MUSB_INTR_DISCONNECT; - } - musb->is_active = 0; - } - dev_dbg(musb->controller, "vbus change, %s, otg %03x\n", - otg_state_string(musb->xceiv->state), otg_stat); - idle_timeout = jiffies + (1 * HZ); - schedule_work(&musb->irq_work); - - } else /* A-dev state machine */ { - dev_dbg(musb->controller, "vbus change, %s, otg %03x\n", - otg_state_string(musb->xceiv->state), otg_stat); - - switch (musb->xceiv->state) { - case OTG_STATE_A_IDLE: - dev_dbg(musb->controller, "Got SRP, turning on VBUS\n"); - musb_platform_set_vbus(musb, 1); - - /* CONNECT can wake if a_wait_bcon is set */ - if (musb->a_wait_bcon != 0) - musb->is_active = 0; - else - musb->is_active = 1; - - /* - * OPT FS A TD.4.6 needs few seconds for - * A_WAIT_VRISE - */ - idle_timeout = jiffies + (2 * HZ); - - break; - case OTG_STATE_A_WAIT_VRISE: - /* ignore; A-session-valid < VBUS_VALID/2, - * we monitor this with the timer - */ - break; - case OTG_STATE_A_WAIT_VFALL: - /* REVISIT this irq triggers during short - * spikes caused by enumeration ... - */ - if (musb->vbuserr_retry) { - musb->vbuserr_retry--; - tusb_musb_set_vbus(musb, 1); - } else { - musb->vbuserr_retry - = VBUSERR_RETRY_COUNT; - tusb_musb_set_vbus(musb, 0); - } - break; - default: - break; - } - } - } - - /* OTG timer expiration */ - if (int_src & TUSB_INT_SRC_OTG_TIMEOUT) { - u8 devctl; - - dev_dbg(musb->controller, "%s timer, %03x\n", - otg_state_string(musb->xceiv->state), otg_stat); - - 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 - */ - devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - if (otg_stat & TUSB_DEV_OTG_STAT_VBUS_VALID) { - if ((devctl & MUSB_DEVCTL_VBUS) - != MUSB_DEVCTL_VBUS) { - dev_dbg(musb->controller, "devctl %02x\n", devctl); - break; - } - musb->xceiv->state = OTG_STATE_A_WAIT_BCON; - musb->is_active = 0; - idle_timeout = jiffies - + msecs_to_jiffies(musb->a_wait_bcon); - } else { - /* REVISIT report overcurrent to hub? */ - ERR("vbus too slow, devctl %02x\n", devctl); - tusb_musb_set_vbus(musb, 0); - } - break; - case OTG_STATE_A_WAIT_BCON: - if (musb->a_wait_bcon != 0) - idle_timeout = jiffies - + msecs_to_jiffies(musb->a_wait_bcon); - break; - case OTG_STATE_A_SUSPEND: - break; - case OTG_STATE_B_WAIT_ACON: - break; - default: - break; - } - } - schedule_work(&musb->irq_work); - - return idle_timeout; -} - -static irqreturn_t tusb_musb_interrupt(int irq, void *__hci) -{ - struct musb *musb = __hci; - void __iomem *tbase = musb->ctrl_base; - unsigned long flags, idle_timeout = 0; - u32 int_mask, int_src; - - spin_lock_irqsave(&musb->lock, flags); - - /* Mask all interrupts to allow using both edge and level GPIO irq */ - int_mask = musb_readl(tbase, TUSB_INT_MASK); - musb_writel(tbase, TUSB_INT_MASK, ~TUSB_INT_MASK_RESERVED_BITS); - - int_src = musb_readl(tbase, TUSB_INT_SRC) & ~TUSB_INT_SRC_RESERVED_BITS; - dev_dbg(musb->controller, "TUSB IRQ %08x\n", int_src); - - musb->int_usb = (u8) int_src; - - /* Acknowledge wake-up source interrupts */ - if (int_src & TUSB_INT_SRC_DEV_WAKEUP) { - u32 reg; - u32 i; - - if (tusb_get_revision(musb) == TUSB_REV_30) - tusb_wbus_quirk(musb, 0); - - /* there are issues re-locking the PLL on wakeup ... */ - - /* work around issue 8 */ - for (i = 0xf7f7f7; i > 0xf7f7f7 - 1000; i--) { - musb_writel(tbase, TUSB_SCRATCH_PAD, 0); - musb_writel(tbase, TUSB_SCRATCH_PAD, i); - reg = musb_readl(tbase, TUSB_SCRATCH_PAD); - if (reg == i) - break; - dev_dbg(musb->controller, "TUSB NOR not ready\n"); - } - - /* work around issue 13 (2nd half) */ - tusb_set_clock_source(musb, 1); - - reg = musb_readl(tbase, TUSB_PRCM_WAKEUP_SOURCE); - musb_writel(tbase, TUSB_PRCM_WAKEUP_CLEAR, reg); - if (reg & ~TUSB_PRCM_WNORCS) { - musb->is_active = 1; - schedule_work(&musb->irq_work); - } - dev_dbg(musb->controller, "wake %sactive %02x\n", - musb->is_active ? "" : "in", reg); - - /* REVISIT host side TUSB_PRCM_WHOSTDISCON, TUSB_PRCM_WBUS */ - } - - if (int_src & TUSB_INT_SRC_USB_IP_CONN) - del_timer(&musb_idle_timer); - - /* OTG state change reports (annoyingly) not issued by Mentor core */ - if (int_src & (TUSB_INT_SRC_VBUS_SENSE_CHNG - | TUSB_INT_SRC_OTG_TIMEOUT - | TUSB_INT_SRC_ID_STATUS_CHNG)) - idle_timeout = tusb_otg_ints(musb, int_src, tbase); - - /* TX dma callback must be handled here, RX dma callback is - * handled in tusb_omap_dma_cb. - */ - if ((int_src & TUSB_INT_SRC_TXRX_DMA_DONE)) { - u32 dma_src = musb_readl(tbase, TUSB_DMA_INT_SRC); - u32 real_dma_src = musb_readl(tbase, TUSB_DMA_INT_MASK); - - dev_dbg(musb->controller, "DMA IRQ %08x\n", dma_src); - real_dma_src = ~real_dma_src & dma_src; - if (tusb_dma_omap() && real_dma_src) { - int tx_source = (real_dma_src & 0xffff); - int i; - - for (i = 1; i <= 15; i++) { - if (tx_source & (1 << i)) { - dev_dbg(musb->controller, "completing ep%i %s\n", i, "tx"); - musb_dma_completion(musb, i, 1); - } - } - } - musb_writel(tbase, TUSB_DMA_INT_CLEAR, dma_src); - } - - /* EP interrupts. In OCP mode tusb6010 mirrors the MUSB interrupts */ - if (int_src & (TUSB_INT_SRC_USB_IP_TX | TUSB_INT_SRC_USB_IP_RX)) { - u32 musb_src = musb_readl(tbase, TUSB_USBIP_INT_SRC); - - musb_writel(tbase, TUSB_USBIP_INT_CLEAR, musb_src); - musb->int_rx = (((musb_src >> 16) & 0xffff) << 1); - musb->int_tx = (musb_src & 0xffff); - } else { - musb->int_rx = 0; - musb->int_tx = 0; - } - - if (int_src & (TUSB_INT_SRC_USB_IP_TX | TUSB_INT_SRC_USB_IP_RX | 0xff)) - musb_interrupt(musb); - - /* Acknowledge TUSB interrupts. Clear only non-reserved bits */ - musb_writel(tbase, TUSB_INT_SRC_CLEAR, - int_src & ~TUSB_INT_MASK_RESERVED_BITS); - - tusb_musb_try_idle(musb, idle_timeout); - - musb_writel(tbase, TUSB_INT_MASK, int_mask); - spin_unlock_irqrestore(&musb->lock, flags); - - return IRQ_HANDLED; -} - -static int dma_off; - -/* - * Enables TUSB6010. Caller must take care of locking. - * REVISIT: - * - Check what is unnecessary in MGC_HdrcStart() - */ -static void tusb_musb_enable(struct musb *musb) -{ - void __iomem *tbase = musb->ctrl_base; - - /* Setup TUSB6010 main interrupt mask. Enable all interrupts except SOF. - * REVISIT: Enable and deal with TUSB_INT_SRC_USB_IP_SOF */ - musb_writel(tbase, TUSB_INT_MASK, TUSB_INT_SRC_USB_IP_SOF); - - /* Setup TUSB interrupt, disable DMA and GPIO interrupts */ - musb_writel(tbase, TUSB_USBIP_INT_MASK, 0); - musb_writel(tbase, TUSB_DMA_INT_MASK, 0x7fffffff); - musb_writel(tbase, TUSB_GPIO_INT_MASK, 0x1ff); - - /* Clear all subsystem interrups */ - musb_writel(tbase, TUSB_USBIP_INT_CLEAR, 0x7fffffff); - musb_writel(tbase, TUSB_DMA_INT_CLEAR, 0x7fffffff); - musb_writel(tbase, TUSB_GPIO_INT_CLEAR, 0x1ff); - - /* Acknowledge pending interrupt(s) */ - musb_writel(tbase, TUSB_INT_SRC_CLEAR, ~TUSB_INT_MASK_RESERVED_BITS); - - /* Only 0 clock cycles for minimum interrupt de-assertion time and - * interrupt polarity active low seems to work reliably here */ - musb_writel(tbase, TUSB_INT_CTRL_CONF, - TUSB_INT_CTRL_CONF_INT_RELCYC(0)); - - irq_set_irq_type(musb->nIrq, IRQ_TYPE_LEVEL_LOW); - - /* maybe force into the Default-A OTG state machine */ - if (!(musb_readl(tbase, TUSB_DEV_OTG_STAT) - & TUSB_DEV_OTG_STAT_ID_STATUS)) - musb_writel(tbase, TUSB_INT_SRC_SET, - TUSB_INT_SRC_ID_STATUS_CHNG); - - if (is_dma_capable() && dma_off) - printk(KERN_WARNING "%s %s: dma not reactivated\n", - __FILE__, __func__); - else - dma_off = 1; -} - -/* - * Disables TUSB6010. Caller must take care of locking. - */ -static void tusb_musb_disable(struct musb *musb) -{ - void __iomem *tbase = musb->ctrl_base; - - /* FIXME stop DMA, IRQs, timers, ... */ - - /* disable all IRQs */ - musb_writel(tbase, TUSB_INT_MASK, ~TUSB_INT_MASK_RESERVED_BITS); - musb_writel(tbase, TUSB_USBIP_INT_MASK, 0x7fffffff); - musb_writel(tbase, TUSB_DMA_INT_MASK, 0x7fffffff); - musb_writel(tbase, TUSB_GPIO_INT_MASK, 0x1ff); - - del_timer(&musb_idle_timer); - - if (is_dma_capable() && !dma_off) { - printk(KERN_WARNING "%s %s: dma still active\n", - __FILE__, __func__); - dma_off = 1; - } -} - -/* - * Sets up TUSB6010 CPU interface specific signals and registers - * Note: Settings optimized for OMAP24xx - */ -static void tusb_setup_cpu_interface(struct musb *musb) -{ - void __iomem *tbase = musb->ctrl_base; - - /* - * Disable GPIO[5:0] pullups (used as output DMA requests) - * Don't disable GPIO[7:6] as they are needed for wake-up. - */ - musb_writel(tbase, TUSB_PULLUP_1_CTRL, 0x0000003F); - - /* Disable all pullups on NOR IF, DMAREQ0 and DMAREQ1 */ - musb_writel(tbase, TUSB_PULLUP_2_CTRL, 0x01FFFFFF); - - /* Turn GPIO[5:0] to DMAREQ[5:0] signals */ - musb_writel(tbase, TUSB_GPIO_CONF, TUSB_GPIO_CONF_DMAREQ(0x3f)); - - /* Burst size 16x16 bits, all six DMA requests enabled, DMA request - * de-assertion time 2 system clocks p 62 */ - musb_writel(tbase, TUSB_DMA_REQ_CONF, - TUSB_DMA_REQ_CONF_BURST_SIZE(2) | - TUSB_DMA_REQ_CONF_DMA_REQ_EN(0x3f) | - TUSB_DMA_REQ_CONF_DMA_REQ_ASSER(2)); - - /* Set 0 wait count for synchronous burst access */ - musb_writel(tbase, TUSB_WAIT_COUNT, 1); -} - -static int tusb_musb_start(struct musb *musb) -{ - void __iomem *tbase = musb->ctrl_base; - int ret = 0; - unsigned long flags; - u32 reg; - - if (musb->board_set_power) - ret = musb->board_set_power(1); - if (ret != 0) { - printk(KERN_ERR "tusb: Cannot enable TUSB6010\n"); - return ret; - } - - spin_lock_irqsave(&musb->lock, flags); - - if (musb_readl(tbase, TUSB_PROD_TEST_RESET) != - TUSB_PROD_TEST_RESET_VAL) { - printk(KERN_ERR "tusb: Unable to detect TUSB6010\n"); - goto err; - } - - ret = tusb_print_revision(musb); - if (ret < 2) { - printk(KERN_ERR "tusb: Unsupported TUSB6010 revision %i\n", - ret); - goto err; - } - - /* The uint bit for "USB non-PDR interrupt enable" has to be 1 when - * NOR FLASH interface is used */ - musb_writel(tbase, TUSB_VLYNQ_CTRL, 8); - - /* Select PHY free running 60MHz as a system clock */ - tusb_set_clock_source(musb, 1); - - /* VBus valid timer 1us, disable DFT/Debug and VLYNQ clocks for - * power saving, enable VBus detect and session end comparators, - * enable IDpullup, enable VBus charging */ - musb_writel(tbase, TUSB_PRCM_MNGMT, - TUSB_PRCM_MNGMT_VBUS_VALID_TIMER(0xa) | - TUSB_PRCM_MNGMT_VBUS_VALID_FLT_EN | - TUSB_PRCM_MNGMT_OTG_SESS_END_EN | - TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN | - TUSB_PRCM_MNGMT_OTG_ID_PULLUP); - tusb_setup_cpu_interface(musb); - - /* simplify: always sense/pullup ID pins, as if in OTG mode */ - reg = musb_readl(tbase, TUSB_PHY_OTG_CTRL_ENABLE); - reg |= TUSB_PHY_OTG_CTRL_WRPROTECT | TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP; - musb_writel(tbase, TUSB_PHY_OTG_CTRL_ENABLE, reg); - - reg = musb_readl(tbase, TUSB_PHY_OTG_CTRL); - reg |= TUSB_PHY_OTG_CTRL_WRPROTECT | TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP; - musb_writel(tbase, TUSB_PHY_OTG_CTRL, reg); - - spin_unlock_irqrestore(&musb->lock, flags); - - return 0; - -err: - spin_unlock_irqrestore(&musb->lock, flags); - - if (musb->board_set_power) - musb->board_set_power(0); - - return -ENODEV; -} - -static int tusb_musb_init(struct musb *musb) -{ - struct platform_device *pdev; - struct resource *mem; - void __iomem *sync = NULL; - int ret; - - usb_nop_xceiv_register(); - musb->xceiv = usb_get_transceiver(); - if (!musb->xceiv) - return -ENODEV; - - pdev = to_platform_device(musb->controller); - - /* dma address for async dma */ - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - musb->async = mem->start; - - /* dma address for sync dma */ - mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!mem) { - pr_debug("no sync dma resource?\n"); - ret = -ENODEV; - goto done; - } - musb->sync = mem->start; - - sync = ioremap(mem->start, resource_size(mem)); - if (!sync) { - pr_debug("ioremap for sync failed\n"); - ret = -ENOMEM; - goto done; - } - musb->sync_va = sync; - - /* Offsets from base: VLYNQ at 0x000, MUSB regs at 0x400, - * FIFOs at 0x600, TUSB at 0x800 - */ - musb->mregs += TUSB_BASE_OFFSET; - - ret = tusb_musb_start(musb); - if (ret) { - printk(KERN_ERR "Could not start tusb6010 (%d)\n", - ret); - goto done; - } - musb->isr = tusb_musb_interrupt; - - 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_put_transceiver(musb->xceiv); - usb_nop_xceiv_unregister(); - } - return ret; -} - -static int tusb_musb_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_put_transceiver(musb->xceiv); - usb_nop_xceiv_unregister(); - return 0; -} - -static const struct musb_platform_ops tusb_ops = { - .init = tusb_musb_init, - .exit = tusb_musb_exit, - - .enable = tusb_musb_enable, - .disable = tusb_musb_disable, - - .set_mode = tusb_musb_set_mode, - .try_idle = tusb_musb_try_idle, - - .vbus_status = tusb_musb_vbus_status, - .set_vbus = tusb_musb_set_vbus, -}; - -static u64 tusb_dmamask = DMA_BIT_MASK(32); - -static int __devinit tusb_probe(struct platform_device *pdev) -{ - struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; - struct platform_device *musb; - struct tusb6010_glue *glue; - - int ret = -ENOMEM; - - glue = kzalloc(sizeof(*glue), GFP_KERNEL); - if (!glue) { - dev_err(&pdev->dev, "failed to allocate glue context\n"); - goto err0; - } - - musb = platform_device_alloc("musb-hdrc", -1); - if (!musb) { - dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err1; - } - - musb->dev.parent = &pdev->dev; - musb->dev.dma_mask = &tusb_dmamask; - musb->dev.coherent_dma_mask = tusb_dmamask; - - glue->dev = &pdev->dev; - glue->musb = musb; - - pdata->platform_ops = &tusb_ops; - - platform_set_drvdata(pdev, glue); - - ret = platform_device_add_resources(musb, pdev->resource, - pdev->num_resources); - if (ret) { - dev_err(&pdev->dev, "failed to add resources\n"); - goto err2; - } - - ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); - if (ret) { - dev_err(&pdev->dev, "failed to add platform_data\n"); - goto err2; - } - - ret = platform_device_add(musb); - if (ret) { - dev_err(&pdev->dev, "failed to register musb device\n"); - goto err1; - } - - return 0; - -err2: - platform_device_put(musb); - -err1: - kfree(glue); - -err0: - return ret; -} - -static int __devexit tusb_remove(struct platform_device *pdev) -{ - struct tusb6010_glue *glue = platform_get_drvdata(pdev); - - platform_device_del(glue->musb); - platform_device_put(glue->musb); - kfree(glue); - - return 0; -} - -static struct platform_driver tusb_driver = { - .probe = tusb_probe, - .remove = __devexit_p(tusb_remove), - .driver = { - .name = "musb-tusb", - }, -}; - -MODULE_DESCRIPTION("TUSB6010 MUSB Glue Layer"); -MODULE_AUTHOR("Felipe Balbi "); -MODULE_LICENSE("GPL v2"); - -static int __init tusb_init(void) -{ - return platform_driver_register(&tusb_driver); -} -module_init(tusb_init); - -static void __exit tusb_exit(void) -{ - platform_driver_unregister(&tusb_driver); -} -module_exit(tusb_exit); diff --git a/ANDROID_3.4.5/drivers/usb/musb/tusb6010.h b/ANDROID_3.4.5/drivers/usb/musb/tusb6010.h deleted file mode 100644 index 35c933a5..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/tusb6010.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Definitions for TUSB6010 USB 2.0 OTG Dual Role controller - * - * Copyright (C) 2006 Nokia Corporation - * Tony Lindgren - * - * 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 __TUSB6010_H__ -#define __TUSB6010_H__ - -extern u8 tusb_get_revision(struct musb *musb); - -#ifdef CONFIG_USB_TUSB6010 -#define musb_in_tusb() 1 -#else -#define musb_in_tusb() 0 -#endif - -#ifdef CONFIG_USB_TUSB_OMAP_DMA -#define tusb_dma_omap() 1 -#else -#define tusb_dma_omap() 0 -#endif - -/* VLYNQ control register. 32-bit at offset 0x000 */ -#define TUSB_VLYNQ_CTRL 0x004 - -/* Mentor Graphics OTG core registers. 8,- 16- and 32-bit at offset 0x400 */ -#define TUSB_BASE_OFFSET 0x400 - -/* FIFO registers 32-bit at offset 0x600 */ -#define TUSB_FIFO_BASE 0x600 - -/* Device System & Control registers. 32-bit at offset 0x800 */ -#define TUSB_SYS_REG_BASE 0x800 - -#define TUSB_DEV_CONF (TUSB_SYS_REG_BASE + 0x000) -#define TUSB_DEV_CONF_USB_HOST_MODE (1 << 16) -#define TUSB_DEV_CONF_PROD_TEST_MODE (1 << 15) -#define TUSB_DEV_CONF_SOFT_ID (1 << 1) -#define TUSB_DEV_CONF_ID_SEL (1 << 0) - -#define TUSB_PHY_OTG_CTRL_ENABLE (TUSB_SYS_REG_BASE + 0x004) -#define TUSB_PHY_OTG_CTRL (TUSB_SYS_REG_BASE + 0x008) -#define TUSB_PHY_OTG_CTRL_WRPROTECT (0xa5 << 24) -#define TUSB_PHY_OTG_CTRL_OTG_ID_PULLUP (1 << 23) -#define TUSB_PHY_OTG_CTRL_OTG_VBUS_DET_EN (1 << 19) -#define TUSB_PHY_OTG_CTRL_OTG_SESS_END_EN (1 << 18) -#define TUSB_PHY_OTG_CTRL_TESTM2 (1 << 17) -#define TUSB_PHY_OTG_CTRL_TESTM1 (1 << 16) -#define TUSB_PHY_OTG_CTRL_TESTM0 (1 << 15) -#define TUSB_PHY_OTG_CTRL_TX_DATA2 (1 << 14) -#define TUSB_PHY_OTG_CTRL_TX_GZ2 (1 << 13) -#define TUSB_PHY_OTG_CTRL_TX_ENABLE2 (1 << 12) -#define TUSB_PHY_OTG_CTRL_DM_PULLDOWN (1 << 11) -#define TUSB_PHY_OTG_CTRL_DP_PULLDOWN (1 << 10) -#define TUSB_PHY_OTG_CTRL_OSC_EN (1 << 9) -#define TUSB_PHY_OTG_CTRL_PHYREF_CLKSEL(v) (((v) & 3) << 7) -#define TUSB_PHY_OTG_CTRL_PD (1 << 6) -#define TUSB_PHY_OTG_CTRL_PLL_ON (1 << 5) -#define TUSB_PHY_OTG_CTRL_EXT_RPU (1 << 4) -#define TUSB_PHY_OTG_CTRL_PWR_GOOD (1 << 3) -#define TUSB_PHY_OTG_CTRL_RESET (1 << 2) -#define TUSB_PHY_OTG_CTRL_SUSPENDM (1 << 1) -#define TUSB_PHY_OTG_CTRL_CLK_MODE (1 << 0) - -/*OTG status register */ -#define TUSB_DEV_OTG_STAT (TUSB_SYS_REG_BASE + 0x00c) -#define TUSB_DEV_OTG_STAT_PWR_CLK_GOOD (1 << 8) -#define TUSB_DEV_OTG_STAT_SESS_END (1 << 7) -#define TUSB_DEV_OTG_STAT_SESS_VALID (1 << 6) -#define TUSB_DEV_OTG_STAT_VBUS_VALID (1 << 5) -#define TUSB_DEV_OTG_STAT_VBUS_SENSE (1 << 4) -#define TUSB_DEV_OTG_STAT_ID_STATUS (1 << 3) -#define TUSB_DEV_OTG_STAT_HOST_DISCON (1 << 2) -#define TUSB_DEV_OTG_STAT_LINE_STATE (3 << 0) -#define TUSB_DEV_OTG_STAT_DP_ENABLE (1 << 1) -#define TUSB_DEV_OTG_STAT_DM_ENABLE (1 << 0) - -#define TUSB_DEV_OTG_TIMER (TUSB_SYS_REG_BASE + 0x010) -# define TUSB_DEV_OTG_TIMER_ENABLE (1 << 31) -# define TUSB_DEV_OTG_TIMER_VAL(v) ((v) & 0x07ffffff) -#define TUSB_PRCM_REV (TUSB_SYS_REG_BASE + 0x014) - -/* PRCM configuration register */ -#define TUSB_PRCM_CONF (TUSB_SYS_REG_BASE + 0x018) -#define TUSB_PRCM_CONF_SFW_CPEN (1 << 24) -#define TUSB_PRCM_CONF_SYS_CLKSEL(v) (((v) & 3) << 16) - -/* PRCM management register */ -#define TUSB_PRCM_MNGMT (TUSB_SYS_REG_BASE + 0x01c) -#define TUSB_PRCM_MNGMT_SRP_FIX_TIMER(v) (((v) & 0xf) << 25) -#define TUSB_PRCM_MNGMT_SRP_FIX_EN (1 << 24) -#define TUSB_PRCM_MNGMT_VBUS_VALID_TIMER(v) (((v) & 0xf) << 20) -#define TUSB_PRCM_MNGMT_VBUS_VALID_FLT_EN (1 << 19) -#define TUSB_PRCM_MNGMT_DFT_CLK_DIS (1 << 18) -#define TUSB_PRCM_MNGMT_VLYNQ_CLK_DIS (1 << 17) -#define TUSB_PRCM_MNGMT_OTG_SESS_END_EN (1 << 10) -#define TUSB_PRCM_MNGMT_OTG_VBUS_DET_EN (1 << 9) -#define TUSB_PRCM_MNGMT_OTG_ID_PULLUP (1 << 8) -#define TUSB_PRCM_MNGMT_15_SW_EN (1 << 4) -#define TUSB_PRCM_MNGMT_33_SW_EN (1 << 3) -#define TUSB_PRCM_MNGMT_5V_CPEN (1 << 2) -#define TUSB_PRCM_MNGMT_PM_IDLE (1 << 1) -#define TUSB_PRCM_MNGMT_DEV_IDLE (1 << 0) - -/* Wake-up source clear and mask registers */ -#define TUSB_PRCM_WAKEUP_SOURCE (TUSB_SYS_REG_BASE + 0x020) -#define TUSB_PRCM_WAKEUP_CLEAR (TUSB_SYS_REG_BASE + 0x028) -#define TUSB_PRCM_WAKEUP_MASK (TUSB_SYS_REG_BASE + 0x02c) -#define TUSB_PRCM_WAKEUP_RESERVED_BITS (0xffffe << 13) -#define TUSB_PRCM_WGPIO_7 (1 << 12) -#define TUSB_PRCM_WGPIO_6 (1 << 11) -#define TUSB_PRCM_WGPIO_5 (1 << 10) -#define TUSB_PRCM_WGPIO_4 (1 << 9) -#define TUSB_PRCM_WGPIO_3 (1 << 8) -#define TUSB_PRCM_WGPIO_2 (1 << 7) -#define TUSB_PRCM_WGPIO_1 (1 << 6) -#define TUSB_PRCM_WGPIO_0 (1 << 5) -#define TUSB_PRCM_WHOSTDISCON (1 << 4) /* Host disconnect */ -#define TUSB_PRCM_WBUS (1 << 3) /* USB bus resume */ -#define TUSB_PRCM_WNORCS (1 << 2) /* NOR chip select */ -#define TUSB_PRCM_WVBUS (1 << 1) /* OTG PHY VBUS */ -#define TUSB_PRCM_WID (1 << 0) /* OTG PHY ID detect */ - -#define TUSB_PULLUP_1_CTRL (TUSB_SYS_REG_BASE + 0x030) -#define TUSB_PULLUP_2_CTRL (TUSB_SYS_REG_BASE + 0x034) -#define TUSB_INT_CTRL_REV (TUSB_SYS_REG_BASE + 0x038) -#define TUSB_INT_CTRL_CONF (TUSB_SYS_REG_BASE + 0x03c) -#define TUSB_USBIP_INT_SRC (TUSB_SYS_REG_BASE + 0x040) -#define TUSB_USBIP_INT_SET (TUSB_SYS_REG_BASE + 0x044) -#define TUSB_USBIP_INT_CLEAR (TUSB_SYS_REG_BASE + 0x048) -#define TUSB_USBIP_INT_MASK (TUSB_SYS_REG_BASE + 0x04c) -#define TUSB_DMA_INT_SRC (TUSB_SYS_REG_BASE + 0x050) -#define TUSB_DMA_INT_SET (TUSB_SYS_REG_BASE + 0x054) -#define TUSB_DMA_INT_CLEAR (TUSB_SYS_REG_BASE + 0x058) -#define TUSB_DMA_INT_MASK (TUSB_SYS_REG_BASE + 0x05c) -#define TUSB_GPIO_INT_SRC (TUSB_SYS_REG_BASE + 0x060) -#define TUSB_GPIO_INT_SET (TUSB_SYS_REG_BASE + 0x064) -#define TUSB_GPIO_INT_CLEAR (TUSB_SYS_REG_BASE + 0x068) -#define TUSB_GPIO_INT_MASK (TUSB_SYS_REG_BASE + 0x06c) - -/* NOR flash interrupt source registers */ -#define TUSB_INT_SRC (TUSB_SYS_REG_BASE + 0x070) -#define TUSB_INT_SRC_SET (TUSB_SYS_REG_BASE + 0x074) -#define TUSB_INT_SRC_CLEAR (TUSB_SYS_REG_BASE + 0x078) -#define TUSB_INT_MASK (TUSB_SYS_REG_BASE + 0x07c) -#define TUSB_INT_SRC_TXRX_DMA_DONE (1 << 24) -#define TUSB_INT_SRC_USB_IP_CORE (1 << 17) -#define TUSB_INT_SRC_OTG_TIMEOUT (1 << 16) -#define TUSB_INT_SRC_VBUS_SENSE_CHNG (1 << 15) -#define TUSB_INT_SRC_ID_STATUS_CHNG (1 << 14) -#define TUSB_INT_SRC_DEV_WAKEUP (1 << 13) -#define TUSB_INT_SRC_DEV_READY (1 << 12) -#define TUSB_INT_SRC_USB_IP_TX (1 << 9) -#define TUSB_INT_SRC_USB_IP_RX (1 << 8) -#define TUSB_INT_SRC_USB_IP_VBUS_ERR (1 << 7) -#define TUSB_INT_SRC_USB_IP_VBUS_REQ (1 << 6) -#define TUSB_INT_SRC_USB_IP_DISCON (1 << 5) -#define TUSB_INT_SRC_USB_IP_CONN (1 << 4) -#define TUSB_INT_SRC_USB_IP_SOF (1 << 3) -#define TUSB_INT_SRC_USB_IP_RST_BABBLE (1 << 2) -#define TUSB_INT_SRC_USB_IP_RESUME (1 << 1) -#define TUSB_INT_SRC_USB_IP_SUSPEND (1 << 0) - -/* NOR flash interrupt registers reserved bits. Must be written as 0 */ -#define TUSB_INT_MASK_RESERVED_17 (0x3fff << 17) -#define TUSB_INT_MASK_RESERVED_13 (1 << 13) -#define TUSB_INT_MASK_RESERVED_8 (0xf << 8) -#define TUSB_INT_SRC_RESERVED_26 (0x1f << 26) -#define TUSB_INT_SRC_RESERVED_18 (0x3f << 18) -#define TUSB_INT_SRC_RESERVED_10 (0x03 << 10) - -/* Reserved bits for NOR flash interrupt mask and clear register */ -#define TUSB_INT_MASK_RESERVED_BITS (TUSB_INT_MASK_RESERVED_17 | \ - TUSB_INT_MASK_RESERVED_13 | \ - TUSB_INT_MASK_RESERVED_8) - -/* Reserved bits for NOR flash interrupt status register */ -#define TUSB_INT_SRC_RESERVED_BITS (TUSB_INT_SRC_RESERVED_26 | \ - TUSB_INT_SRC_RESERVED_18 | \ - TUSB_INT_SRC_RESERVED_10) - -#define TUSB_GPIO_REV (TUSB_SYS_REG_BASE + 0x080) -#define TUSB_GPIO_CONF (TUSB_SYS_REG_BASE + 0x084) -#define TUSB_DMA_CTRL_REV (TUSB_SYS_REG_BASE + 0x100) -#define TUSB_DMA_REQ_CONF (TUSB_SYS_REG_BASE + 0x104) -#define TUSB_EP0_CONF (TUSB_SYS_REG_BASE + 0x108) -#define TUSB_DMA_EP_MAP (TUSB_SYS_REG_BASE + 0x148) - -/* Offsets from each ep base register */ -#define TUSB_EP_TX_OFFSET 0x10c /* EP_IN in docs */ -#define TUSB_EP_RX_OFFSET 0x14c /* EP_OUT in docs */ -#define TUSB_EP_MAX_PACKET_SIZE_OFFSET 0x188 - -#define TUSB_WAIT_COUNT (TUSB_SYS_REG_BASE + 0x1c8) -#define TUSB_SCRATCH_PAD (TUSB_SYS_REG_BASE + 0x1c4) -#define TUSB_PROD_TEST_RESET (TUSB_SYS_REG_BASE + 0x1d8) - -/* Device System & Control register bitfields */ -#define TUSB_INT_CTRL_CONF_INT_RELCYC(v) (((v) & 0x7) << 18) -#define TUSB_INT_CTRL_CONF_INT_POLARITY (1 << 17) -#define TUSB_INT_CTRL_CONF_INT_MODE (1 << 16) -#define TUSB_GPIO_CONF_DMAREQ(v) (((v) & 0x3f) << 24) -#define TUSB_DMA_REQ_CONF_BURST_SIZE(v) (((v) & 3) << 26) -#define TUSB_DMA_REQ_CONF_DMA_REQ_EN(v) (((v) & 0x3f) << 20) -#define TUSB_DMA_REQ_CONF_DMA_REQ_ASSER(v) (((v) & 0xf) << 16) -#define TUSB_EP0_CONFIG_SW_EN (1 << 8) -#define TUSB_EP0_CONFIG_DIR_TX (1 << 7) -#define TUSB_EP0_CONFIG_XFR_SIZE(v) ((v) & 0x7f) -#define TUSB_EP_CONFIG_SW_EN (1 << 31) -#define TUSB_EP_CONFIG_XFR_SIZE(v) ((v) & 0x7fffffff) -#define TUSB_PROD_TEST_RESET_VAL 0xa596 -#define TUSB_EP_FIFO(ep) (TUSB_FIFO_BASE + (ep) * 0x20) - -#define TUSB_DIDR1_LO (TUSB_SYS_REG_BASE + 0x1f8) -#define TUSB_DIDR1_HI (TUSB_SYS_REG_BASE + 0x1fc) -#define TUSB_DIDR1_HI_CHIP_REV(v) (((v) >> 17) & 0xf) -#define TUSB_DIDR1_HI_REV_20 0 -#define TUSB_DIDR1_HI_REV_30 1 -#define TUSB_DIDR1_HI_REV_31 2 - -#define TUSB_REV_10 0x10 -#define TUSB_REV_20 0x20 -#define TUSB_REV_30 0x30 -#define TUSB_REV_31 0x31 - -#endif /* __TUSB6010_H__ */ diff --git a/ANDROID_3.4.5/drivers/usb/musb/tusb6010_omap.c b/ANDROID_3.4.5/drivers/usb/musb/tusb6010_omap.c deleted file mode 100644 index b67b4bc5..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/tusb6010_omap.c +++ /dev/null @@ -1,727 +0,0 @@ -/* - * TUSB6010 USB 2.0 OTG Dual Role controller OMAP DMA interface - * - * Copyright (C) 2006 Nokia Corporation - * Tony Lindgren - * - * 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. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "musb_core.h" -#include "tusb6010.h" - -#define to_chdat(c) ((struct tusb_omap_dma_ch *)(c)->private_data) - -#define MAX_DMAREQ 5 /* REVISIT: Really 6, but req5 not OK */ - -struct tusb_omap_dma_ch { - struct musb *musb; - void __iomem *tbase; - unsigned long phys_offset; - int epnum; - u8 tx; - struct musb_hw_ep *hw_ep; - - int ch; - s8 dmareq; - s8 sync_dev; - - struct tusb_omap_dma *tusb_dma; - - dma_addr_t dma_addr; - - u32 len; - u16 packet_sz; - u16 transfer_packet_sz; - u32 transfer_len; - u32 completed_len; -}; - -struct tusb_omap_dma { - struct dma_controller controller; - struct musb *musb; - void __iomem *tbase; - - int ch; - s8 dmareq; - s8 sync_dev; - unsigned multichannel:1; -}; - -static int tusb_omap_dma_start(struct dma_controller *c) -{ - struct tusb_omap_dma *tusb_dma; - - tusb_dma = container_of(c, struct tusb_omap_dma, controller); - - /* dev_dbg(musb->controller, "ep%i ch: %i\n", chdat->epnum, chdat->ch); */ - - return 0; -} - -static int tusb_omap_dma_stop(struct dma_controller *c) -{ - struct tusb_omap_dma *tusb_dma; - - tusb_dma = container_of(c, struct tusb_omap_dma, controller); - - /* dev_dbg(musb->controller, "ep%i ch: %i\n", chdat->epnum, chdat->ch); */ - - return 0; -} - -/* - * Allocate dmareq0 to the current channel unless it's already taken - */ -static inline int tusb_omap_use_shared_dmareq(struct tusb_omap_dma_ch *chdat) -{ - u32 reg = musb_readl(chdat->tbase, TUSB_DMA_EP_MAP); - - if (reg != 0) { - dev_dbg(chdat->musb->controller, "ep%i dmareq0 is busy for ep%i\n", - chdat->epnum, reg & 0xf); - return -EAGAIN; - } - - if (chdat->tx) - reg = (1 << 4) | chdat->epnum; - else - reg = chdat->epnum; - - musb_writel(chdat->tbase, TUSB_DMA_EP_MAP, reg); - - return 0; -} - -static inline void tusb_omap_free_shared_dmareq(struct tusb_omap_dma_ch *chdat) -{ - u32 reg = musb_readl(chdat->tbase, TUSB_DMA_EP_MAP); - - if ((reg & 0xf) != chdat->epnum) { - printk(KERN_ERR "ep%i trying to release dmareq0 for ep%i\n", - chdat->epnum, reg & 0xf); - return; - } - musb_writel(chdat->tbase, TUSB_DMA_EP_MAP, 0); -} - -/* - * See also musb_dma_completion in plat_uds.c and musb_g_[tx|rx]() in - * musb_gadget.c. - */ -static void tusb_omap_dma_cb(int lch, u16 ch_status, void *data) -{ - struct dma_channel *channel = (struct dma_channel *)data; - struct tusb_omap_dma_ch *chdat = to_chdat(channel); - struct tusb_omap_dma *tusb_dma = chdat->tusb_dma; - struct musb *musb = chdat->musb; - struct device *dev = musb->controller; - struct musb_hw_ep *hw_ep = chdat->hw_ep; - void __iomem *ep_conf = hw_ep->conf; - void __iomem *mbase = musb->mregs; - unsigned long remaining, flags, pio; - int ch; - - spin_lock_irqsave(&musb->lock, flags); - - if (tusb_dma->multichannel) - ch = chdat->ch; - else - ch = tusb_dma->ch; - - if (ch_status != OMAP_DMA_BLOCK_IRQ) - printk(KERN_ERR "TUSB DMA error status: %i\n", ch_status); - - dev_dbg(musb->controller, "ep%i %s dma callback ch: %i status: %x\n", - chdat->epnum, chdat->tx ? "tx" : "rx", - ch, ch_status); - - if (chdat->tx) - remaining = musb_readl(ep_conf, TUSB_EP_TX_OFFSET); - else - remaining = musb_readl(ep_conf, TUSB_EP_RX_OFFSET); - - remaining = TUSB_EP_CONFIG_XFR_SIZE(remaining); - - /* HW issue #10: XFR_SIZE may get corrupt on DMA (both async & sync) */ - if (unlikely(remaining > chdat->transfer_len)) { - dev_dbg(musb->controller, "Corrupt %s dma ch%i XFR_SIZE: 0x%08lx\n", - chdat->tx ? "tx" : "rx", chdat->ch, - remaining); - remaining = 0; - } - - channel->actual_len = chdat->transfer_len - remaining; - pio = chdat->len - channel->actual_len; - - dev_dbg(musb->controller, "DMA remaining %lu/%u\n", remaining, chdat->transfer_len); - - /* Transfer remaining 1 - 31 bytes */ - if (pio > 0 && pio < 32) { - u8 *buf; - - dev_dbg(musb->controller, "Using PIO for remaining %lu bytes\n", pio); - buf = phys_to_virt((u32)chdat->dma_addr) + chdat->transfer_len; - if (chdat->tx) { - dma_unmap_single(dev, chdat->dma_addr, - chdat->transfer_len, - DMA_TO_DEVICE); - musb_write_fifo(hw_ep, pio, buf); - } else { - dma_unmap_single(dev, chdat->dma_addr, - chdat->transfer_len, - DMA_FROM_DEVICE); - musb_read_fifo(hw_ep, pio, buf); - } - channel->actual_len += pio; - } - - if (!tusb_dma->multichannel) - tusb_omap_free_shared_dmareq(chdat); - - channel->status = MUSB_DMA_STATUS_FREE; - - /* Handle only RX callbacks here. TX callbacks must be handled based - * on the TUSB DMA status interrupt. - * REVISIT: Use both TUSB DMA status interrupt and OMAP DMA callback - * interrupt for RX and TX. - */ - if (!chdat->tx) - musb_dma_completion(musb, chdat->epnum, chdat->tx); - - /* We must terminate short tx transfers manually by setting TXPKTRDY. - * REVISIT: This same problem may occur with other MUSB dma as well. - * Easy to test with g_ether by pinging the MUSB board with ping -s54. - */ - if ((chdat->transfer_len < chdat->packet_sz) - || (chdat->transfer_len % chdat->packet_sz != 0)) { - u16 csr; - - if (chdat->tx) { - dev_dbg(musb->controller, "terminating short tx packet\n"); - musb_ep_select(mbase, chdat->epnum); - csr = musb_readw(hw_ep->regs, MUSB_TXCSR); - csr |= MUSB_TXCSR_MODE | MUSB_TXCSR_TXPKTRDY - | MUSB_TXCSR_P_WZC_BITS; - musb_writew(hw_ep->regs, MUSB_TXCSR, csr); - } - } - - spin_unlock_irqrestore(&musb->lock, flags); -} - -static int tusb_omap_dma_program(struct dma_channel *channel, u16 packet_sz, - u8 rndis_mode, dma_addr_t dma_addr, u32 len) -{ - struct tusb_omap_dma_ch *chdat = to_chdat(channel); - struct tusb_omap_dma *tusb_dma = chdat->tusb_dma; - struct musb *musb = chdat->musb; - struct device *dev = musb->controller; - struct musb_hw_ep *hw_ep = chdat->hw_ep; - void __iomem *mbase = musb->mregs; - void __iomem *ep_conf = hw_ep->conf; - dma_addr_t fifo = hw_ep->fifo_sync; - struct omap_dma_channel_params dma_params; - u32 dma_remaining; - int src_burst, dst_burst; - u16 csr; - int ch; - s8 dmareq; - s8 sync_dev; - - if (unlikely(dma_addr & 0x1) || (len < 32) || (len > packet_sz)) - return false; - - /* - * HW issue #10: Async dma will eventually corrupt the XFR_SIZE - * register which will cause missed DMA interrupt. We could try to - * use a timer for the callback, but it is unsafe as the XFR_SIZE - * register is corrupt, and we won't know if the DMA worked. - */ - if (dma_addr & 0x2) - return false; - - /* - * Because of HW issue #10, it seems like mixing sync DMA and async - * PIO access can confuse the DMA. Make sure XFR_SIZE is reset before - * using the channel for DMA. - */ - if (chdat->tx) - dma_remaining = musb_readl(ep_conf, TUSB_EP_TX_OFFSET); - else - dma_remaining = musb_readl(ep_conf, TUSB_EP_RX_OFFSET); - - dma_remaining = TUSB_EP_CONFIG_XFR_SIZE(dma_remaining); - if (dma_remaining) { - dev_dbg(musb->controller, "Busy %s dma ch%i, not using: %08x\n", - chdat->tx ? "tx" : "rx", chdat->ch, - dma_remaining); - return false; - } - - chdat->transfer_len = len & ~0x1f; - - if (len < packet_sz) - chdat->transfer_packet_sz = chdat->transfer_len; - else - chdat->transfer_packet_sz = packet_sz; - - if (tusb_dma->multichannel) { - ch = chdat->ch; - dmareq = chdat->dmareq; - sync_dev = chdat->sync_dev; - } else { - if (tusb_omap_use_shared_dmareq(chdat) != 0) { - dev_dbg(musb->controller, "could not get dma for ep%i\n", chdat->epnum); - return false; - } - if (tusb_dma->ch < 0) { - /* REVISIT: This should get blocked earlier, happens - * with MSC ErrorRecoveryTest - */ - WARN_ON(1); - return false; - } - - ch = tusb_dma->ch; - dmareq = tusb_dma->dmareq; - sync_dev = tusb_dma->sync_dev; - omap_set_dma_callback(ch, tusb_omap_dma_cb, channel); - } - - chdat->packet_sz = packet_sz; - chdat->len = len; - channel->actual_len = 0; - chdat->dma_addr = dma_addr; - channel->status = MUSB_DMA_STATUS_BUSY; - - /* Since we're recycling dma areas, we need to clean or invalidate */ - if (chdat->tx) - dma_map_single(dev, phys_to_virt(dma_addr), len, - DMA_TO_DEVICE); - else - dma_map_single(dev, phys_to_virt(dma_addr), len, - DMA_FROM_DEVICE); - - /* Use 16-bit transfer if dma_addr is not 32-bit aligned */ - if ((dma_addr & 0x3) == 0) { - dma_params.data_type = OMAP_DMA_DATA_TYPE_S32; - dma_params.elem_count = 8; /* Elements in frame */ - } else { - dma_params.data_type = OMAP_DMA_DATA_TYPE_S16; - dma_params.elem_count = 16; /* Elements in frame */ - fifo = hw_ep->fifo_async; - } - - dma_params.frame_count = chdat->transfer_len / 32; /* Burst sz frame */ - - dev_dbg(musb->controller, "ep%i %s dma ch%i dma: %08x len: %u(%u) packet_sz: %i(%i)\n", - chdat->epnum, chdat->tx ? "tx" : "rx", - ch, dma_addr, chdat->transfer_len, len, - chdat->transfer_packet_sz, packet_sz); - - /* - * Prepare omap DMA for transfer - */ - if (chdat->tx) { - dma_params.src_amode = OMAP_DMA_AMODE_POST_INC; - dma_params.src_start = (unsigned long)dma_addr; - dma_params.src_ei = 0; - dma_params.src_fi = 0; - - dma_params.dst_amode = OMAP_DMA_AMODE_DOUBLE_IDX; - dma_params.dst_start = (unsigned long)fifo; - dma_params.dst_ei = 1; - dma_params.dst_fi = -31; /* Loop 32 byte window */ - - dma_params.trigger = sync_dev; - dma_params.sync_mode = OMAP_DMA_SYNC_FRAME; - dma_params.src_or_dst_synch = 0; /* Dest sync */ - - src_burst = OMAP_DMA_DATA_BURST_16; /* 16x32 read */ - dst_burst = OMAP_DMA_DATA_BURST_8; /* 8x32 write */ - } else { - dma_params.src_amode = OMAP_DMA_AMODE_DOUBLE_IDX; - dma_params.src_start = (unsigned long)fifo; - dma_params.src_ei = 1; - dma_params.src_fi = -31; /* Loop 32 byte window */ - - dma_params.dst_amode = OMAP_DMA_AMODE_POST_INC; - dma_params.dst_start = (unsigned long)dma_addr; - dma_params.dst_ei = 0; - dma_params.dst_fi = 0; - - dma_params.trigger = sync_dev; - dma_params.sync_mode = OMAP_DMA_SYNC_FRAME; - dma_params.src_or_dst_synch = 1; /* Source sync */ - - src_burst = OMAP_DMA_DATA_BURST_8; /* 8x32 read */ - dst_burst = OMAP_DMA_DATA_BURST_16; /* 16x32 write */ - } - - dev_dbg(musb->controller, "ep%i %s using %i-bit %s dma from 0x%08lx to 0x%08lx\n", - chdat->epnum, chdat->tx ? "tx" : "rx", - (dma_params.data_type == OMAP_DMA_DATA_TYPE_S32) ? 32 : 16, - ((dma_addr & 0x3) == 0) ? "sync" : "async", - dma_params.src_start, dma_params.dst_start); - - omap_set_dma_params(ch, &dma_params); - omap_set_dma_src_burst_mode(ch, src_burst); - omap_set_dma_dest_burst_mode(ch, dst_burst); - omap_set_dma_write_mode(ch, OMAP_DMA_WRITE_LAST_NON_POSTED); - - /* - * Prepare MUSB for DMA transfer - */ - if (chdat->tx) { - musb_ep_select(mbase, chdat->epnum); - csr = musb_readw(hw_ep->regs, MUSB_TXCSR); - csr |= (MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAENAB - | MUSB_TXCSR_DMAMODE | MUSB_TXCSR_MODE); - csr &= ~MUSB_TXCSR_P_UNDERRUN; - musb_writew(hw_ep->regs, MUSB_TXCSR, csr); - } else { - musb_ep_select(mbase, chdat->epnum); - csr = musb_readw(hw_ep->regs, MUSB_RXCSR); - csr |= MUSB_RXCSR_DMAENAB; - csr &= ~(MUSB_RXCSR_AUTOCLEAR | MUSB_RXCSR_DMAMODE); - musb_writew(hw_ep->regs, MUSB_RXCSR, - csr | MUSB_RXCSR_P_WZC_BITS); - } - - /* - * Start DMA transfer - */ - omap_start_dma(ch); - - if (chdat->tx) { - /* Send transfer_packet_sz packets at a time */ - musb_writel(ep_conf, TUSB_EP_MAX_PACKET_SIZE_OFFSET, - chdat->transfer_packet_sz); - - musb_writel(ep_conf, TUSB_EP_TX_OFFSET, - TUSB_EP_CONFIG_XFR_SIZE(chdat->transfer_len)); - } else { - /* Receive transfer_packet_sz packets at a time */ - musb_writel(ep_conf, TUSB_EP_MAX_PACKET_SIZE_OFFSET, - chdat->transfer_packet_sz << 16); - - musb_writel(ep_conf, TUSB_EP_RX_OFFSET, - TUSB_EP_CONFIG_XFR_SIZE(chdat->transfer_len)); - } - - return true; -} - -static int tusb_omap_dma_abort(struct dma_channel *channel) -{ - struct tusb_omap_dma_ch *chdat = to_chdat(channel); - struct tusb_omap_dma *tusb_dma = chdat->tusb_dma; - - if (!tusb_dma->multichannel) { - if (tusb_dma->ch >= 0) { - omap_stop_dma(tusb_dma->ch); - omap_free_dma(tusb_dma->ch); - tusb_dma->ch = -1; - } - - tusb_dma->dmareq = -1; - tusb_dma->sync_dev = -1; - } - - channel->status = MUSB_DMA_STATUS_FREE; - - return 0; -} - -static inline int tusb_omap_dma_allocate_dmareq(struct tusb_omap_dma_ch *chdat) -{ - u32 reg = musb_readl(chdat->tbase, TUSB_DMA_EP_MAP); - int i, dmareq_nr = -1; - - const int sync_dev[6] = { - OMAP24XX_DMA_EXT_DMAREQ0, - OMAP24XX_DMA_EXT_DMAREQ1, - OMAP242X_DMA_EXT_DMAREQ2, - OMAP242X_DMA_EXT_DMAREQ3, - OMAP242X_DMA_EXT_DMAREQ4, - OMAP242X_DMA_EXT_DMAREQ5, - }; - - for (i = 0; i < MAX_DMAREQ; i++) { - int cur = (reg & (0xf << (i * 5))) >> (i * 5); - if (cur == 0) { - dmareq_nr = i; - break; - } - } - - if (dmareq_nr == -1) - return -EAGAIN; - - reg |= (chdat->epnum << (dmareq_nr * 5)); - if (chdat->tx) - reg |= ((1 << 4) << (dmareq_nr * 5)); - musb_writel(chdat->tbase, TUSB_DMA_EP_MAP, reg); - - chdat->dmareq = dmareq_nr; - chdat->sync_dev = sync_dev[chdat->dmareq]; - - return 0; -} - -static inline void tusb_omap_dma_free_dmareq(struct tusb_omap_dma_ch *chdat) -{ - u32 reg; - - if (!chdat || chdat->dmareq < 0) - return; - - reg = musb_readl(chdat->tbase, TUSB_DMA_EP_MAP); - reg &= ~(0x1f << (chdat->dmareq * 5)); - musb_writel(chdat->tbase, TUSB_DMA_EP_MAP, reg); - - chdat->dmareq = -1; - chdat->sync_dev = -1; -} - -static struct dma_channel *dma_channel_pool[MAX_DMAREQ]; - -static struct dma_channel * -tusb_omap_dma_allocate(struct dma_controller *c, - struct musb_hw_ep *hw_ep, - u8 tx) -{ - int ret, i; - const char *dev_name; - struct tusb_omap_dma *tusb_dma; - struct musb *musb; - void __iomem *tbase; - struct dma_channel *channel = NULL; - struct tusb_omap_dma_ch *chdat = NULL; - u32 reg; - - tusb_dma = container_of(c, struct tusb_omap_dma, controller); - musb = tusb_dma->musb; - tbase = musb->ctrl_base; - - reg = musb_readl(tbase, TUSB_DMA_INT_MASK); - if (tx) - reg &= ~(1 << hw_ep->epnum); - else - reg &= ~(1 << (hw_ep->epnum + 15)); - musb_writel(tbase, TUSB_DMA_INT_MASK, reg); - - /* REVISIT: Why does dmareq5 not work? */ - if (hw_ep->epnum == 0) { - dev_dbg(musb->controller, "Not allowing DMA for ep0 %s\n", tx ? "tx" : "rx"); - return NULL; - } - - for (i = 0; i < MAX_DMAREQ; i++) { - struct dma_channel *ch = dma_channel_pool[i]; - if (ch->status == MUSB_DMA_STATUS_UNKNOWN) { - ch->status = MUSB_DMA_STATUS_FREE; - channel = ch; - chdat = ch->private_data; - break; - } - } - - if (!channel) - return NULL; - - if (tx) { - chdat->tx = 1; - dev_name = "TUSB transmit"; - } else { - chdat->tx = 0; - dev_name = "TUSB receive"; - } - - chdat->musb = tusb_dma->musb; - chdat->tbase = tusb_dma->tbase; - chdat->hw_ep = hw_ep; - chdat->epnum = hw_ep->epnum; - chdat->dmareq = -1; - chdat->completed_len = 0; - chdat->tusb_dma = tusb_dma; - - channel->max_len = 0x7fffffff; - channel->desired_mode = 0; - channel->actual_len = 0; - - if (tusb_dma->multichannel) { - ret = tusb_omap_dma_allocate_dmareq(chdat); - if (ret != 0) - goto free_dmareq; - - ret = omap_request_dma(chdat->sync_dev, dev_name, - tusb_omap_dma_cb, channel, &chdat->ch); - if (ret != 0) - goto free_dmareq; - } else if (tusb_dma->ch == -1) { - tusb_dma->dmareq = 0; - tusb_dma->sync_dev = OMAP24XX_DMA_EXT_DMAREQ0; - - /* Callback data gets set later in the shared dmareq case */ - ret = omap_request_dma(tusb_dma->sync_dev, "TUSB shared", - tusb_omap_dma_cb, NULL, &tusb_dma->ch); - if (ret != 0) - goto free_dmareq; - - chdat->dmareq = -1; - chdat->ch = -1; - } - - dev_dbg(musb->controller, "ep%i %s dma: %s dma%i dmareq%i sync%i\n", - chdat->epnum, - chdat->tx ? "tx" : "rx", - chdat->ch >= 0 ? "dedicated" : "shared", - chdat->ch >= 0 ? chdat->ch : tusb_dma->ch, - chdat->dmareq >= 0 ? chdat->dmareq : tusb_dma->dmareq, - chdat->sync_dev >= 0 ? chdat->sync_dev : tusb_dma->sync_dev); - - return channel; - -free_dmareq: - tusb_omap_dma_free_dmareq(chdat); - - dev_dbg(musb->controller, "ep%i: Could not get a DMA channel\n", chdat->epnum); - channel->status = MUSB_DMA_STATUS_UNKNOWN; - - return NULL; -} - -static void tusb_omap_dma_release(struct dma_channel *channel) -{ - struct tusb_omap_dma_ch *chdat = to_chdat(channel); - struct musb *musb = chdat->musb; - void __iomem *tbase = musb->ctrl_base; - u32 reg; - - dev_dbg(musb->controller, "ep%i ch%i\n", chdat->epnum, chdat->ch); - - reg = musb_readl(tbase, TUSB_DMA_INT_MASK); - if (chdat->tx) - reg |= (1 << chdat->epnum); - else - reg |= (1 << (chdat->epnum + 15)); - musb_writel(tbase, TUSB_DMA_INT_MASK, reg); - - reg = musb_readl(tbase, TUSB_DMA_INT_CLEAR); - if (chdat->tx) - reg |= (1 << chdat->epnum); - else - reg |= (1 << (chdat->epnum + 15)); - musb_writel(tbase, TUSB_DMA_INT_CLEAR, reg); - - channel->status = MUSB_DMA_STATUS_UNKNOWN; - - if (chdat->ch >= 0) { - omap_stop_dma(chdat->ch); - omap_free_dma(chdat->ch); - chdat->ch = -1; - } - - if (chdat->dmareq >= 0) - tusb_omap_dma_free_dmareq(chdat); - - channel = NULL; -} - -void dma_controller_destroy(struct dma_controller *c) -{ - struct tusb_omap_dma *tusb_dma; - int i; - - tusb_dma = container_of(c, struct tusb_omap_dma, controller); - for (i = 0; i < MAX_DMAREQ; i++) { - struct dma_channel *ch = dma_channel_pool[i]; - if (ch) { - kfree(ch->private_data); - kfree(ch); - } - } - - if (tusb_dma && !tusb_dma->multichannel && tusb_dma->ch >= 0) - omap_free_dma(tusb_dma->ch); - - kfree(tusb_dma); -} - -struct dma_controller *__init -dma_controller_create(struct musb *musb, void __iomem *base) -{ - void __iomem *tbase = musb->ctrl_base; - struct tusb_omap_dma *tusb_dma; - int i; - - /* REVISIT: Get dmareq lines used from board-*.c */ - - musb_writel(musb->ctrl_base, TUSB_DMA_INT_MASK, 0x7fffffff); - musb_writel(musb->ctrl_base, TUSB_DMA_EP_MAP, 0); - - musb_writel(tbase, TUSB_DMA_REQ_CONF, - TUSB_DMA_REQ_CONF_BURST_SIZE(2) - | TUSB_DMA_REQ_CONF_DMA_REQ_EN(0x3f) - | TUSB_DMA_REQ_CONF_DMA_REQ_ASSER(2)); - - tusb_dma = kzalloc(sizeof(struct tusb_omap_dma), GFP_KERNEL); - if (!tusb_dma) - goto out; - - tusb_dma->musb = musb; - tusb_dma->tbase = musb->ctrl_base; - - tusb_dma->ch = -1; - tusb_dma->dmareq = -1; - tusb_dma->sync_dev = -1; - - tusb_dma->controller.start = tusb_omap_dma_start; - tusb_dma->controller.stop = tusb_omap_dma_stop; - tusb_dma->controller.channel_alloc = tusb_omap_dma_allocate; - tusb_dma->controller.channel_release = tusb_omap_dma_release; - tusb_dma->controller.channel_program = tusb_omap_dma_program; - tusb_dma->controller.channel_abort = tusb_omap_dma_abort; - - if (tusb_get_revision(musb) >= TUSB_REV_30) - tusb_dma->multichannel = 1; - - for (i = 0; i < MAX_DMAREQ; i++) { - struct dma_channel *ch; - struct tusb_omap_dma_ch *chdat; - - ch = kzalloc(sizeof(struct dma_channel), GFP_KERNEL); - if (!ch) - goto cleanup; - - dma_channel_pool[i] = ch; - - chdat = kzalloc(sizeof(struct tusb_omap_dma_ch), GFP_KERNEL); - if (!chdat) - goto cleanup; - - ch->status = MUSB_DMA_STATUS_UNKNOWN; - ch->private_data = chdat; - } - - return &tusb_dma->controller; - -cleanup: - dma_controller_destroy(&tusb_dma->controller); -out: - return NULL; -} diff --git a/ANDROID_3.4.5/drivers/usb/musb/ux500.c b/ANDROID_3.4.5/drivers/usb/musb/ux500.c deleted file mode 100644 index aa09dd41..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/ux500.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (C) 2010 ST-Ericsson AB - * Mian Yousaf Kaukab - * - * Based on omap2430.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include - -#include "musb_core.h" - -struct ux500_glue { - struct device *dev; - struct platform_device *musb; - struct clk *clk; -}; -#define glue_to_musb(g) platform_get_drvdata(g->musb) - -static int ux500_musb_init(struct musb *musb) -{ - musb->xceiv = usb_get_transceiver(); - if (!musb->xceiv) { - pr_err("HS USB OTG: no transceiver configured\n"); - return -ENODEV; - } - - return 0; -} - -static int ux500_musb_exit(struct musb *musb) -{ - usb_put_transceiver(musb->xceiv); - - return 0; -} - -static const struct musb_platform_ops ux500_ops = { - .init = ux500_musb_init, - .exit = ux500_musb_exit, -}; - -static int __devinit ux500_probe(struct platform_device *pdev) -{ - struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; - struct platform_device *musb; - struct ux500_glue *glue; - struct clk *clk; - - int ret = -ENOMEM; - - glue = kzalloc(sizeof(*glue), GFP_KERNEL); - if (!glue) { - dev_err(&pdev->dev, "failed to allocate glue context\n"); - goto err0; - } - - musb = platform_device_alloc("musb-hdrc", -1); - if (!musb) { - dev_err(&pdev->dev, "failed to allocate musb device\n"); - goto err1; - } - - clk = clk_get(&pdev->dev, "usb"); - if (IS_ERR(clk)) { - dev_err(&pdev->dev, "failed to get clock\n"); - ret = PTR_ERR(clk); - goto err2; - } - - ret = clk_enable(clk); - if (ret) { - dev_err(&pdev->dev, "failed to enable clock\n"); - goto err3; - } - - musb->dev.parent = &pdev->dev; - musb->dev.dma_mask = pdev->dev.dma_mask; - musb->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask; - - glue->dev = &pdev->dev; - glue->musb = musb; - glue->clk = clk; - - pdata->platform_ops = &ux500_ops; - - platform_set_drvdata(pdev, glue); - - ret = platform_device_add_resources(musb, pdev->resource, - pdev->num_resources); - if (ret) { - dev_err(&pdev->dev, "failed to add resources\n"); - goto err4; - } - - ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); - if (ret) { - dev_err(&pdev->dev, "failed to add platform_data\n"); - goto err4; - } - - ret = platform_device_add(musb); - if (ret) { - dev_err(&pdev->dev, "failed to register musb device\n"); - goto err4; - } - - return 0; - -err4: - clk_disable(clk); - -err3: - clk_put(clk); - -err2: - platform_device_put(musb); - -err1: - kfree(glue); - -err0: - return ret; -} - -static int __devexit ux500_remove(struct platform_device *pdev) -{ - struct ux500_glue *glue = platform_get_drvdata(pdev); - - platform_device_del(glue->musb); - platform_device_put(glue->musb); - clk_disable(glue->clk); - clk_put(glue->clk); - kfree(glue); - - return 0; -} - -#ifdef CONFIG_PM -static int ux500_suspend(struct device *dev) -{ - struct ux500_glue *glue = dev_get_drvdata(dev); - struct musb *musb = glue_to_musb(glue); - - usb_phy_set_suspend(musb->xceiv, 1); - clk_disable(glue->clk); - - return 0; -} - -static int ux500_resume(struct device *dev) -{ - struct ux500_glue *glue = dev_get_drvdata(dev); - struct musb *musb = glue_to_musb(glue); - int ret; - - ret = clk_enable(glue->clk); - if (ret) { - dev_err(dev, "failed to enable clock\n"); - return ret; - } - - usb_phy_set_suspend(musb->xceiv, 0); - - return 0; -} - -static const struct dev_pm_ops ux500_pm_ops = { - .suspend = ux500_suspend, - .resume = ux500_resume, -}; - -#define DEV_PM_OPS (&ux500_pm_ops) -#else -#define DEV_PM_OPS NULL -#endif - -static struct platform_driver ux500_driver = { - .probe = ux500_probe, - .remove = __devexit_p(ux500_remove), - .driver = { - .name = "musb-ux500", - .pm = DEV_PM_OPS, - }, -}; - -MODULE_DESCRIPTION("UX500 MUSB Glue Layer"); -MODULE_AUTHOR("Mian Yousaf Kaukab "); -MODULE_LICENSE("GPL v2"); - -static int __init ux500_init(void) -{ - return platform_driver_register(&ux500_driver); -} -module_init(ux500_init); - -static void __exit ux500_exit(void) -{ - platform_driver_unregister(&ux500_driver); -} -module_exit(ux500_exit); diff --git a/ANDROID_3.4.5/drivers/usb/musb/ux500_dma.c b/ANDROID_3.4.5/drivers/usb/musb/ux500_dma.c deleted file mode 100644 index d05c7fbb..00000000 --- a/ANDROID_3.4.5/drivers/usb/musb/ux500_dma.c +++ /dev/null @@ -1,393 +0,0 @@ -/* - * drivers/usb/musb/ux500_dma.c - * - * U8500 and U5500 DMA support code - * - * Copyright (C) 2009 STMicroelectronics - * Copyright (C) 2011 ST-Ericsson SA - * Authors: - * Mian Yousaf Kaukab - * Praveena Nadahally - * Rajaram Regupathy - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include "musb_core.h" - -struct ux500_dma_channel { - struct dma_channel channel; - struct ux500_dma_controller *controller; - struct musb_hw_ep *hw_ep; - struct dma_chan *dma_chan; - unsigned int cur_len; - dma_cookie_t cookie; - u8 ch_num; - u8 is_tx; - u8 is_allocated; -}; - -struct ux500_dma_controller { - struct dma_controller controller; - struct ux500_dma_channel rx_channel[UX500_MUSB_DMA_NUM_RX_CHANNELS]; - struct ux500_dma_channel tx_channel[UX500_MUSB_DMA_NUM_TX_CHANNELS]; - u32 num_rx_channels; - u32 num_tx_channels; - void *private_data; - dma_addr_t phy_base; -}; - -/* Work function invoked from DMA callback to handle rx transfers. */ -void ux500_dma_callback(void *private_data) -{ - struct dma_channel *channel = private_data; - struct ux500_dma_channel *ux500_channel = channel->private_data; - struct musb_hw_ep *hw_ep = ux500_channel->hw_ep; - struct musb *musb = hw_ep->musb; - unsigned long flags; - - dev_dbg(musb->controller, "DMA rx transfer done on hw_ep=%d\n", - hw_ep->epnum); - - spin_lock_irqsave(&musb->lock, flags); - ux500_channel->channel.actual_len = ux500_channel->cur_len; - ux500_channel->channel.status = MUSB_DMA_STATUS_FREE; - musb_dma_completion(musb, hw_ep->epnum, - ux500_channel->is_tx); - spin_unlock_irqrestore(&musb->lock, flags); - -} - -static bool ux500_configure_channel(struct dma_channel *channel, - u16 packet_sz, u8 mode, - dma_addr_t dma_addr, u32 len) -{ - struct ux500_dma_channel *ux500_channel = channel->private_data; - struct musb_hw_ep *hw_ep = ux500_channel->hw_ep; - struct dma_chan *dma_chan = ux500_channel->dma_chan; - struct dma_async_tx_descriptor *dma_desc; - enum dma_transfer_direction direction; - struct scatterlist sg; - struct dma_slave_config slave_conf; - enum dma_slave_buswidth addr_width; - dma_addr_t usb_fifo_addr = (MUSB_FIFO_OFFSET(hw_ep->epnum) + - ux500_channel->controller->phy_base); - struct musb *musb = ux500_channel->controller->private_data; - - dev_dbg(musb->controller, - "packet_sz=%d, mode=%d, dma_addr=0x%x, len=%d is_tx=%d\n", - packet_sz, mode, dma_addr, len, ux500_channel->is_tx); - - ux500_channel->cur_len = len; - - sg_init_table(&sg, 1); - sg_set_page(&sg, pfn_to_page(PFN_DOWN(dma_addr)), len, - offset_in_page(dma_addr)); - sg_dma_address(&sg) = dma_addr; - sg_dma_len(&sg) = len; - - direction = ux500_channel->is_tx ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; - addr_width = (len & 0x3) ? DMA_SLAVE_BUSWIDTH_1_BYTE : - DMA_SLAVE_BUSWIDTH_4_BYTES; - - slave_conf.direction = direction; - slave_conf.src_addr = usb_fifo_addr; - slave_conf.src_addr_width = addr_width; - slave_conf.src_maxburst = 16; - slave_conf.dst_addr = usb_fifo_addr; - slave_conf.dst_addr_width = addr_width; - slave_conf.dst_maxburst = 16; - slave_conf.device_fc = false; - - dma_chan->device->device_control(dma_chan, DMA_SLAVE_CONFIG, - (unsigned long) &slave_conf); - - dma_desc = dmaengine_prep_slave_sg(dma_chan, &sg, 1, direction, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!dma_desc) - return false; - - dma_desc->callback = ux500_dma_callback; - dma_desc->callback_param = channel; - ux500_channel->cookie = dma_desc->tx_submit(dma_desc); - - dma_async_issue_pending(dma_chan); - - return true; -} - -static struct dma_channel *ux500_dma_channel_allocate(struct dma_controller *c, - struct musb_hw_ep *hw_ep, u8 is_tx) -{ - struct ux500_dma_controller *controller = container_of(c, - struct ux500_dma_controller, controller); - struct ux500_dma_channel *ux500_channel = NULL; - struct musb *musb = controller->private_data; - u8 ch_num = hw_ep->epnum - 1; - u32 max_ch; - - /* Max 8 DMA channels (0 - 7). Each DMA channel can only be allocated - * to specified hw_ep. For example DMA channel 0 can only be allocated - * to hw_ep 1 and 9. - */ - if (ch_num > 7) - ch_num -= 8; - - max_ch = is_tx ? controller->num_tx_channels : - controller->num_rx_channels; - - if (ch_num >= max_ch) - return NULL; - - ux500_channel = is_tx ? &(controller->tx_channel[ch_num]) : - &(controller->rx_channel[ch_num]) ; - - /* Check if channel is already used. */ - if (ux500_channel->is_allocated) - return NULL; - - ux500_channel->hw_ep = hw_ep; - ux500_channel->is_allocated = 1; - - dev_dbg(musb->controller, "hw_ep=%d, is_tx=0x%x, channel=%d\n", - hw_ep->epnum, is_tx, ch_num); - - return &(ux500_channel->channel); -} - -static void ux500_dma_channel_release(struct dma_channel *channel) -{ - struct ux500_dma_channel *ux500_channel = channel->private_data; - struct musb *musb = ux500_channel->controller->private_data; - - dev_dbg(musb->controller, "channel=%d\n", ux500_channel->ch_num); - - if (ux500_channel->is_allocated) { - ux500_channel->is_allocated = 0; - channel->status = MUSB_DMA_STATUS_FREE; - channel->actual_len = 0; - } -} - -static int ux500_dma_is_compatible(struct dma_channel *channel, - u16 maxpacket, void *buf, u32 length) -{ - if ((maxpacket & 0x3) || - ((int)buf & 0x3) || - (length < 512) || - (length & 0x3)) - return false; - else - return true; -} - -static int ux500_dma_channel_program(struct dma_channel *channel, - u16 packet_sz, u8 mode, - dma_addr_t dma_addr, u32 len) -{ - int ret; - - BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN || - channel->status == MUSB_DMA_STATUS_BUSY); - - if (!ux500_dma_is_compatible(channel, packet_sz, (void *)dma_addr, len)) - return false; - - channel->status = MUSB_DMA_STATUS_BUSY; - channel->actual_len = 0; - ret = ux500_configure_channel(channel, packet_sz, mode, dma_addr, len); - if (!ret) - channel->status = MUSB_DMA_STATUS_FREE; - - return ret; -} - -static int ux500_dma_channel_abort(struct dma_channel *channel) -{ - struct ux500_dma_channel *ux500_channel = channel->private_data; - struct ux500_dma_controller *controller = ux500_channel->controller; - struct musb *musb = controller->private_data; - void __iomem *epio = musb->endpoints[ux500_channel->hw_ep->epnum].regs; - u16 csr; - - dev_dbg(musb->controller, "channel=%d, is_tx=%d\n", - ux500_channel->ch_num, ux500_channel->is_tx); - - if (channel->status == MUSB_DMA_STATUS_BUSY) { - if (ux500_channel->is_tx) { - csr = musb_readw(epio, MUSB_TXCSR); - csr &= ~(MUSB_TXCSR_AUTOSET | - MUSB_TXCSR_DMAENAB | - MUSB_TXCSR_DMAMODE); - musb_writew(epio, MUSB_TXCSR, csr); - } else { - csr = musb_readw(epio, MUSB_RXCSR); - csr &= ~(MUSB_RXCSR_AUTOCLEAR | - MUSB_RXCSR_DMAENAB | - MUSB_RXCSR_DMAMODE); - musb_writew(epio, MUSB_RXCSR, csr); - } - - ux500_channel->dma_chan->device-> - device_control(ux500_channel->dma_chan, - DMA_TERMINATE_ALL, 0); - channel->status = MUSB_DMA_STATUS_FREE; - } - return 0; -} - -static int ux500_dma_controller_stop(struct dma_controller *c) -{ - struct ux500_dma_controller *controller = container_of(c, - struct ux500_dma_controller, controller); - struct ux500_dma_channel *ux500_channel; - struct dma_channel *channel; - u8 ch_num; - - for (ch_num = 0; ch_num < controller->num_rx_channels; ch_num++) { - channel = &controller->rx_channel[ch_num].channel; - ux500_channel = channel->private_data; - - ux500_dma_channel_release(channel); - - if (ux500_channel->dma_chan) - dma_release_channel(ux500_channel->dma_chan); - } - - for (ch_num = 0; ch_num < controller->num_tx_channels; ch_num++) { - channel = &controller->tx_channel[ch_num].channel; - ux500_channel = channel->private_data; - - ux500_dma_channel_release(channel); - - if (ux500_channel->dma_chan) - dma_release_channel(ux500_channel->dma_chan); - } - - return 0; -} - -static int ux500_dma_controller_start(struct dma_controller *c) -{ - struct ux500_dma_controller *controller = container_of(c, - struct ux500_dma_controller, controller); - struct ux500_dma_channel *ux500_channel = NULL; - struct musb *musb = controller->private_data; - struct device *dev = musb->controller; - struct musb_hdrc_platform_data *plat = dev->platform_data; - struct ux500_musb_board_data *data = plat->board_data; - struct dma_channel *dma_channel = NULL; - u32 ch_num; - u8 dir; - u8 is_tx = 0; - - void **param_array; - struct ux500_dma_channel *channel_array; - u32 ch_count; - dma_cap_mask_t mask; - - if ((data->num_rx_channels > UX500_MUSB_DMA_NUM_RX_CHANNELS) || - (data->num_tx_channels > UX500_MUSB_DMA_NUM_TX_CHANNELS)) - return -EINVAL; - - controller->num_rx_channels = data->num_rx_channels; - controller->num_tx_channels = data->num_tx_channels; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - /* Prepare the loop for RX channels */ - channel_array = controller->rx_channel; - ch_count = data->num_rx_channels; - param_array = data->dma_rx_param_array; - - for (dir = 0; dir < 2; dir++) { - for (ch_num = 0; ch_num < ch_count; ch_num++) { - ux500_channel = &channel_array[ch_num]; - ux500_channel->controller = controller; - ux500_channel->ch_num = ch_num; - ux500_channel->is_tx = is_tx; - - dma_channel = &(ux500_channel->channel); - dma_channel->private_data = ux500_channel; - dma_channel->status = MUSB_DMA_STATUS_FREE; - dma_channel->max_len = SZ_16M; - - ux500_channel->dma_chan = dma_request_channel(mask, - data->dma_filter, - param_array[ch_num]); - if (!ux500_channel->dma_chan) { - ERR("Dma pipe allocation error dir=%d ch=%d\n", - dir, ch_num); - - /* Release already allocated channels */ - ux500_dma_controller_stop(c); - - return -EBUSY; - } - - } - - /* Prepare the loop for TX channels */ - channel_array = controller->tx_channel; - ch_count = data->num_tx_channels; - param_array = data->dma_tx_param_array; - is_tx = 1; - } - - return 0; -} - -void dma_controller_destroy(struct dma_controller *c) -{ - struct ux500_dma_controller *controller = container_of(c, - struct ux500_dma_controller, controller); - - kfree(controller); -} - -struct dma_controller *__init -dma_controller_create(struct musb *musb, void __iomem *base) -{ - struct ux500_dma_controller *controller; - struct platform_device *pdev = to_platform_device(musb->controller); - struct resource *iomem; - - controller = kzalloc(sizeof(*controller), GFP_KERNEL); - if (!controller) - return NULL; - - controller->private_data = musb; - - /* Save physical address for DMA controller. */ - iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - controller->phy_base = (dma_addr_t) iomem->start; - - controller->controller.start = ux500_dma_controller_start; - controller->controller.stop = ux500_dma_controller_stop; - controller->controller.channel_alloc = ux500_dma_channel_allocate; - controller->controller.channel_release = ux500_dma_channel_release; - controller->controller.channel_program = ux500_dma_channel_program; - controller->controller.channel_abort = ux500_dma_channel_abort; - controller->controller.is_compatible = ux500_dma_is_compatible; - - return &controller->controller; -} diff --git a/ANDROID_3.4.5/drivers/usb/otg/Kconfig b/ANDROID_3.4.5/drivers/usb/otg/Kconfig deleted file mode 100644 index c2902a86..00000000 --- a/ANDROID_3.4.5/drivers/usb/otg/Kconfig +++ /dev/null @@ -1,139 +0,0 @@ -# -# USB OTG infrastructure may be needed for peripheral-only, host-only, -# or OTG-capable configurations when OTG transceivers or controllers -# are used. -# - -comment "OTG and related infrastructure" - -config USB_OTG_UTILS - bool - help - Select this to make sure the build includes objects from - the OTG infrastructure directory. - -config USB_OTG_WAKELOCK - bool "Hold a wakelock when USB connected" - depends on WAKELOCK - select USB_OTG_UTILS - help - Select this to automatically hold a wakelock when USB is - connected, preventing suspend. - -if USB || USB_GADGET - -# -# USB Transceiver Drivers -# -config USB_GPIO_VBUS - tristate "GPIO based peripheral-only VBUS sensing 'transceiver'" - depends on GENERIC_GPIO - select USB_OTG_UTILS - help - Provides simple GPIO VBUS sensing for controllers with an - internal transceiver via the usb_phy interface, and - optionally control of a D+ pullup GPIO as well as a VBUS - current limit regulator. - -config ISP1301_OMAP - tristate "Philips ISP1301 with OMAP OTG" - depends on I2C && ARCH_OMAP_OTG - select USB_OTG_UTILS - help - If you say yes here you get support for the Philips ISP1301 - USB-On-The-Go transceiver working with the OMAP OTG controller. - The ISP1301 is a full speed USB transceiver which is used in - products including H2, H3, and H4 development boards for Texas - Instruments OMAP processors. - - This driver can also be built as a module. If so, the module - will be called isp1301_omap. - -config USB_ULPI - bool "Generic ULPI Transceiver Driver" - depends on ARM - select USB_OTG_UTILS - help - Enable this to support ULPI connected USB OTG transceivers which - are likely found on embedded boards. - -config USB_ULPI_VIEWPORT - bool - depends on USB_ULPI - help - Provides read/write operations to the ULPI phy register set for - controllers with a viewport register (e.g. Chipidea/ARC controllers). - -config TWL4030_USB - tristate "TWL4030 USB Transceiver Driver" - depends on TWL4030_CORE && REGULATOR_TWL4030 - select USB_OTG_UTILS - help - Enable this to support the USB OTG transceiver on TWL4030 - family chips (including the TWL5030 and TPS659x0 devices). - This transceiver supports high and full speed devices plus, - in host mode, low speed. - -config TWL6030_USB - tristate "TWL6030 USB Transceiver Driver" - depends on TWL4030_CORE - select USB_OTG_UTILS - help - Enable this to support the USB OTG transceiver on TWL6030 - family chips. This TWL6030 transceiver has the VBUS and ID GND - and OTG SRP events capabilities. For all other transceiver functionality - UTMI PHY is embedded in OMAP4430. The internal PHY configurations APIs - are hooked to this driver through platform_data structure. - The definition of internal PHY APIs are in the mach-omap2 layer. - -config NOP_USB_XCEIV - tristate "NOP USB Transceiver Driver" - select USB_OTG_UTILS - help - This driver is to be used by all the usb transceiver which are either - built-in with usb ip or which are autonomous and doesn't require any - phy programming such as ISP1x04 etc. - -config USB_MSM_OTG - tristate "OTG support for Qualcomm on-chip USB controller" - depends on (USB || USB_GADGET) && ARCH_MSM - select USB_OTG_UTILS - help - Enable this to support the USB OTG transceiver on MSM chips. It - handles PHY initialization, clock management, and workarounds - required after resetting the hardware and power management. - This driver is required even for peripheral only or host only - mode configurations. - This driver is not supported on boards like trout which - has an external PHY. - -config AB8500_USB - tristate "AB8500 USB Transceiver Driver" - depends on AB8500_CORE - select USB_OTG_UTILS - help - Enable this to support the USB OTG transceiver in AB8500 chip. - This transceiver supports high and full speed devices plus, - in host mode, low speed. - -config FSL_USB2_OTG - bool "Freescale USB OTG Transceiver Driver" - depends on USB_EHCI_FSL && USB_GADGET_FSL_USB2 && USB_SUSPEND - select USB_OTG - select USB_OTG_UTILS - help - Enable this to support Freescale USB OTG transceiver. - -config USB_MV_OTG - tristate "Marvell USB OTG support" - depends on USB_EHCI_MV && USB_MV_UDC && USB_SUSPEND - select USB_OTG - select USB_OTG_UTILS - help - Say Y here if you want to build Marvell USB OTG transciever - driver in kernel (including PXA and MMP series). This driver - implements role switch between EHCI host driver and gadget driver. - - To compile this driver as a module, choose M here. - -endif # USB || OTG diff --git a/ANDROID_3.4.5/drivers/usb/otg/Makefile b/ANDROID_3.4.5/drivers/usb/otg/Makefile deleted file mode 100644 index 638d040c..00000000 --- a/ANDROID_3.4.5/drivers/usb/otg/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -# -# OTG infrastructure and transceiver drivers -# - -ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG -ccflags-$(CONFIG_USB_GADGET_DEBUG) += -DDEBUG - -# infrastructure -obj-$(CONFIG_USB_OTG_UTILS) += otg.o -obj-$(CONFIG_USB_OTG_WAKELOCK) += otg-wakelock.o - -# transceiver drivers -obj-$(CONFIG_USB_GPIO_VBUS) += gpio_vbus.o -obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o -obj-$(CONFIG_TWL4030_USB) += twl4030-usb.o -obj-$(CONFIG_TWL6030_USB) += twl6030-usb.o -obj-$(CONFIG_NOP_USB_XCEIV) += nop-usb-xceiv.o -obj-$(CONFIG_USB_ULPI) += ulpi.o -obj-$(CONFIG_USB_ULPI_VIEWPORT) += ulpi_viewport.o -obj-$(CONFIG_USB_MSM_OTG) += msm_otg.o -obj-$(CONFIG_AB8500_USB) += ab8500-usb.o -fsl_usb2_otg-objs := fsl_otg.o otg_fsm.o -obj-$(CONFIG_FSL_USB2_OTG) += fsl_usb2_otg.o -obj-$(CONFIG_USB_MV_OTG) += mv_otg.o diff --git a/ANDROID_3.4.5/drivers/usb/otg/ab8500-usb.c b/ANDROID_3.4.5/drivers/usb/otg/ab8500-usb.c deleted file mode 100644 index a84af677..00000000 --- a/ANDROID_3.4.5/drivers/usb/otg/ab8500-usb.c +++ /dev/null @@ -1,596 +0,0 @@ -/* - * drivers/usb/otg/ab8500_usb.c - * - * USB transceiver driver for AB8500 chip - * - * Copyright (C) 2010 ST-Ericsson AB - * Mian Yousaf Kaukab - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define AB8500_MAIN_WD_CTRL_REG 0x01 -#define AB8500_USB_LINE_STAT_REG 0x80 -#define AB8500_USB_PHY_CTRL_REG 0x8A - -#define AB8500_BIT_OTG_STAT_ID (1 << 0) -#define AB8500_BIT_PHY_CTRL_HOST_EN (1 << 0) -#define AB8500_BIT_PHY_CTRL_DEVICE_EN (1 << 1) -#define AB8500_BIT_WD_CTRL_ENABLE (1 << 0) -#define AB8500_BIT_WD_CTRL_KICK (1 << 1) - -#define AB8500_V1x_LINK_STAT_WAIT (HZ/10) -#define AB8500_WD_KICK_DELAY_US 100 /* usec */ -#define AB8500_WD_V11_DISABLE_DELAY_US 100 /* usec */ -#define AB8500_WD_V10_DISABLE_DELAY_MS 100 /* ms */ - -/* Usb line status register */ -enum ab8500_usb_link_status { - USB_LINK_NOT_CONFIGURED = 0, - USB_LINK_STD_HOST_NC, - USB_LINK_STD_HOST_C_NS, - USB_LINK_STD_HOST_C_S, - USB_LINK_HOST_CHG_NM, - USB_LINK_HOST_CHG_HS, - USB_LINK_HOST_CHG_HS_CHIRP, - USB_LINK_DEDICATED_CHG, - USB_LINK_ACA_RID_A, - USB_LINK_ACA_RID_B, - USB_LINK_ACA_RID_C_NM, - USB_LINK_ACA_RID_C_HS, - USB_LINK_ACA_RID_C_HS_CHIRP, - USB_LINK_HM_IDGND, - USB_LINK_RESERVED, - USB_LINK_NOT_VALID_LINK -}; - -struct ab8500_usb { - struct usb_phy phy; - struct device *dev; - int irq_num_id_rise; - int irq_num_id_fall; - int irq_num_vbus_rise; - int irq_num_vbus_fall; - int irq_num_link_status; - unsigned vbus_draw; - struct delayed_work dwork; - struct work_struct phy_dis_work; - unsigned long link_status_wait; - int rev; -}; - -static inline struct ab8500_usb *phy_to_ab(struct usb_phy *x) -{ - return container_of(x, struct ab8500_usb, phy); -} - -static void ab8500_usb_wd_workaround(struct ab8500_usb *ab) -{ - abx500_set_register_interruptible(ab->dev, - AB8500_SYS_CTRL2_BLOCK, - AB8500_MAIN_WD_CTRL_REG, - AB8500_BIT_WD_CTRL_ENABLE); - - udelay(AB8500_WD_KICK_DELAY_US); - - abx500_set_register_interruptible(ab->dev, - AB8500_SYS_CTRL2_BLOCK, - AB8500_MAIN_WD_CTRL_REG, - (AB8500_BIT_WD_CTRL_ENABLE - | AB8500_BIT_WD_CTRL_KICK)); - - if (ab->rev > 0x10) /* v1.1 v2.0 */ - udelay(AB8500_WD_V11_DISABLE_DELAY_US); - else /* v1.0 */ - msleep(AB8500_WD_V10_DISABLE_DELAY_MS); - - abx500_set_register_interruptible(ab->dev, - AB8500_SYS_CTRL2_BLOCK, - AB8500_MAIN_WD_CTRL_REG, - 0); -} - -static void ab8500_usb_phy_ctrl(struct ab8500_usb *ab, bool sel_host, - bool enable) -{ - u8 ctrl_reg; - abx500_get_register_interruptible(ab->dev, - AB8500_USB, - AB8500_USB_PHY_CTRL_REG, - &ctrl_reg); - if (sel_host) { - if (enable) - ctrl_reg |= AB8500_BIT_PHY_CTRL_HOST_EN; - else - ctrl_reg &= ~AB8500_BIT_PHY_CTRL_HOST_EN; - } else { - if (enable) - ctrl_reg |= AB8500_BIT_PHY_CTRL_DEVICE_EN; - else - ctrl_reg &= ~AB8500_BIT_PHY_CTRL_DEVICE_EN; - } - - abx500_set_register_interruptible(ab->dev, - AB8500_USB, - AB8500_USB_PHY_CTRL_REG, - ctrl_reg); - - /* Needed to enable the phy.*/ - if (enable) - ab8500_usb_wd_workaround(ab); -} - -#define ab8500_usb_host_phy_en(ab) ab8500_usb_phy_ctrl(ab, true, true) -#define ab8500_usb_host_phy_dis(ab) ab8500_usb_phy_ctrl(ab, true, false) -#define ab8500_usb_peri_phy_en(ab) ab8500_usb_phy_ctrl(ab, false, true) -#define ab8500_usb_peri_phy_dis(ab) ab8500_usb_phy_ctrl(ab, false, false) - -static int ab8500_usb_link_status_update(struct ab8500_usb *ab) -{ - u8 reg; - enum ab8500_usb_link_status lsts; - void *v = NULL; - enum usb_phy_events event; - - abx500_get_register_interruptible(ab->dev, - AB8500_USB, - AB8500_USB_LINE_STAT_REG, - ®); - - lsts = (reg >> 3) & 0x0F; - - switch (lsts) { - case USB_LINK_NOT_CONFIGURED: - case USB_LINK_RESERVED: - case USB_LINK_NOT_VALID_LINK: - /* TODO: Disable regulators. */ - ab8500_usb_host_phy_dis(ab); - ab8500_usb_peri_phy_dis(ab); - ab->phy.state = OTG_STATE_B_IDLE; - ab->phy.otg->default_a = false; - ab->vbus_draw = 0; - event = USB_EVENT_NONE; - break; - - case USB_LINK_STD_HOST_NC: - case USB_LINK_STD_HOST_C_NS: - case USB_LINK_STD_HOST_C_S: - case USB_LINK_HOST_CHG_NM: - case USB_LINK_HOST_CHG_HS: - case USB_LINK_HOST_CHG_HS_CHIRP: - if (ab->phy.otg->gadget) { - /* TODO: Enable regulators. */ - ab8500_usb_peri_phy_en(ab); - v = ab->phy.otg->gadget; - } - event = USB_EVENT_VBUS; - break; - - case USB_LINK_HM_IDGND: - if (ab->phy.otg->host) { - /* TODO: Enable regulators. */ - ab8500_usb_host_phy_en(ab); - v = ab->phy.otg->host; - } - ab->phy.state = OTG_STATE_A_IDLE; - ab->phy.otg->default_a = true; - event = USB_EVENT_ID; - break; - - case USB_LINK_ACA_RID_A: - case USB_LINK_ACA_RID_B: - /* TODO */ - case USB_LINK_ACA_RID_C_NM: - case USB_LINK_ACA_RID_C_HS: - case USB_LINK_ACA_RID_C_HS_CHIRP: - case USB_LINK_DEDICATED_CHG: - /* TODO: vbus_draw */ - event = USB_EVENT_CHARGER; - break; - } - - atomic_notifier_call_chain(&ab->phy.notifier, event, v); - - return 0; -} - -static void ab8500_usb_delayed_work(struct work_struct *work) -{ - struct ab8500_usb *ab = container_of(work, struct ab8500_usb, - dwork.work); - - ab8500_usb_link_status_update(ab); -} - -static irqreturn_t ab8500_usb_v1x_common_irq(int irq, void *data) -{ - struct ab8500_usb *ab = (struct ab8500_usb *) data; - - /* Wait for link status to become stable. */ - schedule_delayed_work(&ab->dwork, ab->link_status_wait); - - return IRQ_HANDLED; -} - -static irqreturn_t ab8500_usb_v1x_vbus_fall_irq(int irq, void *data) -{ - struct ab8500_usb *ab = (struct ab8500_usb *) data; - - /* Link status will not be updated till phy is disabled. */ - ab8500_usb_peri_phy_dis(ab); - - /* Wait for link status to become stable. */ - schedule_delayed_work(&ab->dwork, ab->link_status_wait); - - return IRQ_HANDLED; -} - -static irqreturn_t ab8500_usb_v20_irq(int irq, void *data) -{ - struct ab8500_usb *ab = (struct ab8500_usb *) data; - - ab8500_usb_link_status_update(ab); - - return IRQ_HANDLED; -} - -static void ab8500_usb_phy_disable_work(struct work_struct *work) -{ - struct ab8500_usb *ab = container_of(work, struct ab8500_usb, - phy_dis_work); - - if (!ab->phy.otg->host) - ab8500_usb_host_phy_dis(ab); - - if (!ab->phy.otg->gadget) - ab8500_usb_peri_phy_dis(ab); -} - -static int ab8500_usb_set_power(struct usb_phy *phy, unsigned mA) -{ - struct ab8500_usb *ab; - - if (!phy) - return -ENODEV; - - ab = phy_to_ab(phy); - - ab->vbus_draw = mA; - - if (mA) - atomic_notifier_call_chain(&ab->phy.notifier, - USB_EVENT_ENUMERATED, ab->phy.otg->gadget); - return 0; -} - -/* TODO: Implement some way for charging or other drivers to read - * ab->vbus_draw. - */ - -static int ab8500_usb_set_suspend(struct usb_phy *x, int suspend) -{ - /* TODO */ - return 0; -} - -static int ab8500_usb_set_peripheral(struct usb_otg *otg, - struct usb_gadget *gadget) -{ - struct ab8500_usb *ab; - - if (!otg) - return -ENODEV; - - ab = phy_to_ab(otg->phy); - - /* Some drivers call this function in atomic context. - * Do not update ab8500 registers directly till this - * is fixed. - */ - - if (!gadget) { - /* TODO: Disable regulators. */ - otg->gadget = NULL; - schedule_work(&ab->phy_dis_work); - } else { - otg->gadget = gadget; - otg->phy->state = OTG_STATE_B_IDLE; - - /* Phy will not be enabled if cable is already - * plugged-in. Schedule to enable phy. - * Use same delay to avoid any race condition. - */ - schedule_delayed_work(&ab->dwork, ab->link_status_wait); - } - - return 0; -} - -static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host) -{ - struct ab8500_usb *ab; - - if (!otg) - return -ENODEV; - - ab = phy_to_ab(otg->phy); - - /* Some drivers call this function in atomic context. - * Do not update ab8500 registers directly till this - * is fixed. - */ - - if (!host) { - /* TODO: Disable regulators. */ - otg->host = NULL; - schedule_work(&ab->phy_dis_work); - } else { - otg->host = host; - /* Phy will not be enabled if cable is already - * plugged-in. Schedule to enable phy. - * Use same delay to avoid any race condition. - */ - schedule_delayed_work(&ab->dwork, ab->link_status_wait); - } - - return 0; -} - -static void ab8500_usb_irq_free(struct ab8500_usb *ab) -{ - if (ab->rev < 0x20) { - free_irq(ab->irq_num_id_rise, ab); - free_irq(ab->irq_num_id_fall, ab); - free_irq(ab->irq_num_vbus_rise, ab); - free_irq(ab->irq_num_vbus_fall, ab); - } else { - free_irq(ab->irq_num_link_status, ab); - } -} - -static int ab8500_usb_v1x_res_setup(struct platform_device *pdev, - struct ab8500_usb *ab) -{ - int err; - - ab->irq_num_id_rise = platform_get_irq_byname(pdev, "ID_WAKEUP_R"); - if (ab->irq_num_id_rise < 0) { - dev_err(&pdev->dev, "ID rise irq not found\n"); - return ab->irq_num_id_rise; - } - err = request_threaded_irq(ab->irq_num_id_rise, NULL, - ab8500_usb_v1x_common_irq, - IRQF_NO_SUSPEND | IRQF_SHARED, - "usb-id-rise", ab); - if (err < 0) { - dev_err(ab->dev, "request_irq failed for ID rise irq\n"); - goto fail0; - } - - ab->irq_num_id_fall = platform_get_irq_byname(pdev, "ID_WAKEUP_F"); - if (ab->irq_num_id_fall < 0) { - dev_err(&pdev->dev, "ID fall irq not found\n"); - return ab->irq_num_id_fall; - } - err = request_threaded_irq(ab->irq_num_id_fall, NULL, - ab8500_usb_v1x_common_irq, - IRQF_NO_SUSPEND | IRQF_SHARED, - "usb-id-fall", ab); - if (err < 0) { - dev_err(ab->dev, "request_irq failed for ID fall irq\n"); - goto fail1; - } - - ab->irq_num_vbus_rise = platform_get_irq_byname(pdev, "VBUS_DET_R"); - if (ab->irq_num_vbus_rise < 0) { - dev_err(&pdev->dev, "VBUS rise irq not found\n"); - return ab->irq_num_vbus_rise; - } - err = request_threaded_irq(ab->irq_num_vbus_rise, NULL, - ab8500_usb_v1x_common_irq, - IRQF_NO_SUSPEND | IRQF_SHARED, - "usb-vbus-rise", ab); - if (err < 0) { - dev_err(ab->dev, "request_irq failed for Vbus rise irq\n"); - goto fail2; - } - - ab->irq_num_vbus_fall = platform_get_irq_byname(pdev, "VBUS_DET_F"); - if (ab->irq_num_vbus_fall < 0) { - dev_err(&pdev->dev, "VBUS fall irq not found\n"); - return ab->irq_num_vbus_fall; - } - err = request_threaded_irq(ab->irq_num_vbus_fall, NULL, - ab8500_usb_v1x_vbus_fall_irq, - IRQF_NO_SUSPEND | IRQF_SHARED, - "usb-vbus-fall", ab); - if (err < 0) { - dev_err(ab->dev, "request_irq failed for Vbus fall irq\n"); - goto fail3; - } - - return 0; -fail3: - free_irq(ab->irq_num_vbus_rise, ab); -fail2: - free_irq(ab->irq_num_id_fall, ab); -fail1: - free_irq(ab->irq_num_id_rise, ab); -fail0: - return err; -} - -static int ab8500_usb_v2_res_setup(struct platform_device *pdev, - struct ab8500_usb *ab) -{ - int err; - - ab->irq_num_link_status = platform_get_irq_byname(pdev, - "USB_LINK_STATUS"); - if (ab->irq_num_link_status < 0) { - dev_err(&pdev->dev, "Link status irq not found\n"); - return ab->irq_num_link_status; - } - - err = request_threaded_irq(ab->irq_num_link_status, NULL, - ab8500_usb_v20_irq, - IRQF_NO_SUSPEND | IRQF_SHARED, - "usb-link-status", ab); - if (err < 0) { - dev_err(ab->dev, - "request_irq failed for link status irq\n"); - return err; - } - - return 0; -} - -static int __devinit ab8500_usb_probe(struct platform_device *pdev) -{ - struct ab8500_usb *ab; - struct usb_otg *otg; - int err; - int rev; - - rev = abx500_get_chip_id(&pdev->dev); - if (rev < 0) { - dev_err(&pdev->dev, "Chip id read failed\n"); - return rev; - } else if (rev < 0x10) { - dev_err(&pdev->dev, "Unsupported AB8500 chip\n"); - return -ENODEV; - } - - ab = kzalloc(sizeof *ab, GFP_KERNEL); - if (!ab) - return -ENOMEM; - - otg = kzalloc(sizeof *otg, GFP_KERNEL); - if (!otg) { - kfree(ab); - return -ENOMEM; - } - - ab->dev = &pdev->dev; - ab->rev = rev; - ab->phy.dev = ab->dev; - ab->phy.otg = otg; - ab->phy.label = "ab8500"; - ab->phy.set_suspend = ab8500_usb_set_suspend; - ab->phy.set_power = ab8500_usb_set_power; - ab->phy.state = OTG_STATE_UNDEFINED; - - otg->phy = &ab->phy; - otg->set_host = ab8500_usb_set_host; - otg->set_peripheral = ab8500_usb_set_peripheral; - - platform_set_drvdata(pdev, ab); - - ATOMIC_INIT_NOTIFIER_HEAD(&ab->phy.notifier); - - /* v1: Wait for link status to become stable. - * all: Updates form set_host and set_peripheral as they are atomic. - */ - INIT_DELAYED_WORK(&ab->dwork, ab8500_usb_delayed_work); - - /* all: Disable phy when called from set_host and set_peripheral */ - INIT_WORK(&ab->phy_dis_work, ab8500_usb_phy_disable_work); - - if (ab->rev < 0x20) { - err = ab8500_usb_v1x_res_setup(pdev, ab); - ab->link_status_wait = AB8500_V1x_LINK_STAT_WAIT; - } else { - err = ab8500_usb_v2_res_setup(pdev, ab); - } - - if (err < 0) - goto fail0; - - err = usb_set_transceiver(&ab->phy); - if (err) { - dev_err(&pdev->dev, "Can't register transceiver\n"); - goto fail1; - } - - dev_info(&pdev->dev, "AB8500 usb driver initialized\n"); - - return 0; -fail1: - ab8500_usb_irq_free(ab); -fail0: - kfree(otg); - kfree(ab); - return err; -} - -static int __devexit ab8500_usb_remove(struct platform_device *pdev) -{ - struct ab8500_usb *ab = platform_get_drvdata(pdev); - - ab8500_usb_irq_free(ab); - - cancel_delayed_work_sync(&ab->dwork); - - cancel_work_sync(&ab->phy_dis_work); - - usb_set_transceiver(NULL); - - ab8500_usb_host_phy_dis(ab); - ab8500_usb_peri_phy_dis(ab); - - platform_set_drvdata(pdev, NULL); - - kfree(ab->phy.otg); - kfree(ab); - - return 0; -} - -static struct platform_driver ab8500_usb_driver = { - .probe = ab8500_usb_probe, - .remove = __devexit_p(ab8500_usb_remove), - .driver = { - .name = "ab8500-usb", - .owner = THIS_MODULE, - }, -}; - -static int __init ab8500_usb_init(void) -{ - return platform_driver_register(&ab8500_usb_driver); -} -subsys_initcall(ab8500_usb_init); - -static void __exit ab8500_usb_exit(void) -{ - platform_driver_unregister(&ab8500_usb_driver); -} -module_exit(ab8500_usb_exit); - -MODULE_ALIAS("platform:ab8500_usb"); -MODULE_AUTHOR("ST-Ericsson AB"); -MODULE_DESCRIPTION("AB8500 usb transceiver driver"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/otg/fsl_otg.c b/ANDROID_3.4.5/drivers/usb/otg/fsl_otg.c deleted file mode 100644 index be4a63e8..00000000 --- a/ANDROID_3.4.5/drivers/usb/otg/fsl_otg.c +++ /dev/null @@ -1,1169 +0,0 @@ -/* - * Copyright (C) 2007,2008 Freescale semiconductor, Inc. - * - * Author: Li Yang - * Jerry Huang - * - * Initialization based on code from Shlomi Gridish. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "fsl_otg.h" - -#define DRIVER_VERSION "Rev. 1.55" -#define DRIVER_AUTHOR "Jerry Huang/Li Yang" -#define DRIVER_DESC "Freescale USB OTG Transceiver Driver" -#define DRIVER_INFO DRIVER_DESC " " DRIVER_VERSION - -static const char driver_name[] = "fsl-usb2-otg"; - -const pm_message_t otg_suspend_state = { - .event = 1, -}; - -#define HA_DATA_PULSE - -static struct usb_dr_mmap *usb_dr_regs; -static struct fsl_otg *fsl_otg_dev; -static int srp_wait_done; - -/* FSM timers */ -struct fsl_otg_timer *a_wait_vrise_tmr, *a_wait_bcon_tmr, *a_aidl_bdis_tmr, - *b_ase0_brst_tmr, *b_se0_srp_tmr; - -/* Driver specific timers */ -struct fsl_otg_timer *b_data_pulse_tmr, *b_vbus_pulse_tmr, *b_srp_fail_tmr, - *b_srp_wait_tmr, *a_wait_enum_tmr; - -static struct list_head active_timers; - -static struct fsl_otg_config fsl_otg_initdata = { - .otg_port = 1, -}; - -#ifdef CONFIG_PPC32 -static u32 _fsl_readl_be(const unsigned __iomem *p) -{ - return in_be32(p); -} - -static u32 _fsl_readl_le(const unsigned __iomem *p) -{ - return in_le32(p); -} - -static void _fsl_writel_be(u32 v, unsigned __iomem *p) -{ - out_be32(p, v); -} - -static void _fsl_writel_le(u32 v, unsigned __iomem *p) -{ - out_le32(p, v); -} - -static u32 (*_fsl_readl)(const unsigned __iomem *p); -static void (*_fsl_writel)(u32 v, unsigned __iomem *p); - -#define fsl_readl(p) (*_fsl_readl)((p)) -#define fsl_writel(v, p) (*_fsl_writel)((v), (p)) - -#else -#define fsl_readl(addr) readl(addr) -#define fsl_writel(val, addr) writel(val, addr) -#endif /* CONFIG_PPC32 */ - -/* Routines to access transceiver ULPI registers */ -u8 view_ulpi(u8 addr) -{ - u32 temp; - - temp = 0x40000000 | (addr << 16); - fsl_writel(temp, &usb_dr_regs->ulpiview); - udelay(1000); - while (temp & 0x40) - temp = fsl_readl(&usb_dr_regs->ulpiview); - return (le32_to_cpu(temp) & 0x0000ff00) >> 8; -} - -int write_ulpi(u8 addr, u8 data) -{ - u32 temp; - - temp = 0x60000000 | (addr << 16) | data; - fsl_writel(temp, &usb_dr_regs->ulpiview); - return 0; -} - -/* -------------------------------------------------------------*/ -/* Operations that will be called from OTG Finite State Machine */ - -/* Charge vbus for vbus pulsing in SRP */ -void fsl_otg_chrg_vbus(int on) -{ - u32 tmp; - - tmp = fsl_readl(&usb_dr_regs->otgsc) & ~OTGSC_INTSTS_MASK; - - if (on) - /* stop discharging, start charging */ - tmp = (tmp & ~OTGSC_CTRL_VBUS_DISCHARGE) | - OTGSC_CTRL_VBUS_CHARGE; - else - /* stop charging */ - tmp &= ~OTGSC_CTRL_VBUS_CHARGE; - - fsl_writel(tmp, &usb_dr_regs->otgsc); -} - -/* Discharge vbus through a resistor to ground */ -void fsl_otg_dischrg_vbus(int on) -{ - u32 tmp; - - tmp = fsl_readl(&usb_dr_regs->otgsc) & ~OTGSC_INTSTS_MASK; - - if (on) - /* stop charging, start discharging */ - tmp = (tmp & ~OTGSC_CTRL_VBUS_CHARGE) | - OTGSC_CTRL_VBUS_DISCHARGE; - else - /* stop discharging */ - tmp &= ~OTGSC_CTRL_VBUS_DISCHARGE; - - fsl_writel(tmp, &usb_dr_regs->otgsc); -} - -/* A-device driver vbus, controlled through PP bit in PORTSC */ -void fsl_otg_drv_vbus(int on) -{ - u32 tmp; - - if (on) { - tmp = fsl_readl(&usb_dr_regs->portsc) & ~PORTSC_W1C_BITS; - fsl_writel(tmp | PORTSC_PORT_POWER, &usb_dr_regs->portsc); - } else { - tmp = fsl_readl(&usb_dr_regs->portsc) & - ~PORTSC_W1C_BITS & ~PORTSC_PORT_POWER; - fsl_writel(tmp, &usb_dr_regs->portsc); - } -} - -/* - * Pull-up D+, signalling connect by periperal. Also used in - * data-line pulsing in SRP - */ -void fsl_otg_loc_conn(int on) -{ - u32 tmp; - - tmp = fsl_readl(&usb_dr_regs->otgsc) & ~OTGSC_INTSTS_MASK; - - if (on) - tmp |= OTGSC_CTRL_DATA_PULSING; - else - tmp &= ~OTGSC_CTRL_DATA_PULSING; - - fsl_writel(tmp, &usb_dr_regs->otgsc); -} - -/* - * Generate SOF by host. This is controlled through suspend/resume the - * port. In host mode, controller will automatically send SOF. - * Suspend will block the data on the port. - */ -void fsl_otg_loc_sof(int on) -{ - u32 tmp; - - tmp = fsl_readl(&fsl_otg_dev->dr_mem_map->portsc) & ~PORTSC_W1C_BITS; - if (on) - tmp |= PORTSC_PORT_FORCE_RESUME; - else - tmp |= PORTSC_PORT_SUSPEND; - - fsl_writel(tmp, &fsl_otg_dev->dr_mem_map->portsc); - -} - -/* Start SRP pulsing by data-line pulsing, followed with v-bus pulsing. */ -void fsl_otg_start_pulse(void) -{ - u32 tmp; - - srp_wait_done = 0; -#ifdef HA_DATA_PULSE - tmp = fsl_readl(&usb_dr_regs->otgsc) & ~OTGSC_INTSTS_MASK; - tmp |= OTGSC_HA_DATA_PULSE; - fsl_writel(tmp, &usb_dr_regs->otgsc); -#else - fsl_otg_loc_conn(1); -#endif - - fsl_otg_add_timer(b_data_pulse_tmr); -} - -void b_data_pulse_end(unsigned long foo) -{ -#ifdef HA_DATA_PULSE -#else - fsl_otg_loc_conn(0); -#endif - - /* Do VBUS pulse after data pulse */ - fsl_otg_pulse_vbus(); -} - -void fsl_otg_pulse_vbus(void) -{ - srp_wait_done = 0; - fsl_otg_chrg_vbus(1); - /* start the timer to end vbus charge */ - fsl_otg_add_timer(b_vbus_pulse_tmr); -} - -void b_vbus_pulse_end(unsigned long foo) -{ - fsl_otg_chrg_vbus(0); - - /* - * As USB3300 using the same a_sess_vld and b_sess_vld voltage - * we need to discharge the bus for a while to distinguish - * residual voltage of vbus pulsing and A device pull up - */ - fsl_otg_dischrg_vbus(1); - fsl_otg_add_timer(b_srp_wait_tmr); -} - -void b_srp_end(unsigned long foo) -{ - fsl_otg_dischrg_vbus(0); - srp_wait_done = 1; - - if ((fsl_otg_dev->phy.state == OTG_STATE_B_SRP_INIT) && - fsl_otg_dev->fsm.b_sess_vld) - fsl_otg_dev->fsm.b_srp_done = 1; -} - -/* - * Workaround for a_host suspending too fast. When a_bus_req=0, - * a_host will start by SRP. It needs to set b_hnp_enable before - * actually suspending to start HNP - */ -void a_wait_enum(unsigned long foo) -{ - VDBG("a_wait_enum timeout\n"); - if (!fsl_otg_dev->phy.otg->host->b_hnp_enable) - fsl_otg_add_timer(a_wait_enum_tmr); - else - otg_statemachine(&fsl_otg_dev->fsm); -} - -/* The timeout callback function to set time out bit */ -void set_tmout(unsigned long indicator) -{ - *(int *)indicator = 1; -} - -/* Initialize timers */ -int fsl_otg_init_timers(struct otg_fsm *fsm) -{ - /* FSM used timers */ - a_wait_vrise_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_VRISE, - (unsigned long)&fsm->a_wait_vrise_tmout); - if (!a_wait_vrise_tmr) - return -ENOMEM; - - a_wait_bcon_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_BCON, - (unsigned long)&fsm->a_wait_bcon_tmout); - if (!a_wait_bcon_tmr) - return -ENOMEM; - - a_aidl_bdis_tmr = otg_timer_initializer(&set_tmout, TA_AIDL_BDIS, - (unsigned long)&fsm->a_aidl_bdis_tmout); - if (!a_aidl_bdis_tmr) - return -ENOMEM; - - b_ase0_brst_tmr = otg_timer_initializer(&set_tmout, TB_ASE0_BRST, - (unsigned long)&fsm->b_ase0_brst_tmout); - if (!b_ase0_brst_tmr) - return -ENOMEM; - - b_se0_srp_tmr = otg_timer_initializer(&set_tmout, TB_SE0_SRP, - (unsigned long)&fsm->b_se0_srp); - if (!b_se0_srp_tmr) - return -ENOMEM; - - b_srp_fail_tmr = otg_timer_initializer(&set_tmout, TB_SRP_FAIL, - (unsigned long)&fsm->b_srp_done); - if (!b_srp_fail_tmr) - return -ENOMEM; - - a_wait_enum_tmr = otg_timer_initializer(&a_wait_enum, 10, - (unsigned long)&fsm); - if (!a_wait_enum_tmr) - return -ENOMEM; - - /* device driver used timers */ - b_srp_wait_tmr = otg_timer_initializer(&b_srp_end, TB_SRP_WAIT, 0); - if (!b_srp_wait_tmr) - return -ENOMEM; - - b_data_pulse_tmr = otg_timer_initializer(&b_data_pulse_end, - TB_DATA_PLS, 0); - if (!b_data_pulse_tmr) - return -ENOMEM; - - b_vbus_pulse_tmr = otg_timer_initializer(&b_vbus_pulse_end, - TB_VBUS_PLS, 0); - if (!b_vbus_pulse_tmr) - return -ENOMEM; - - return 0; -} - -/* Uninitialize timers */ -void fsl_otg_uninit_timers(void) -{ - /* FSM used timers */ - if (a_wait_vrise_tmr != NULL) - kfree(a_wait_vrise_tmr); - if (a_wait_bcon_tmr != NULL) - kfree(a_wait_bcon_tmr); - if (a_aidl_bdis_tmr != NULL) - kfree(a_aidl_bdis_tmr); - if (b_ase0_brst_tmr != NULL) - kfree(b_ase0_brst_tmr); - if (b_se0_srp_tmr != NULL) - kfree(b_se0_srp_tmr); - if (b_srp_fail_tmr != NULL) - kfree(b_srp_fail_tmr); - if (a_wait_enum_tmr != NULL) - kfree(a_wait_enum_tmr); - - /* device driver used timers */ - if (b_srp_wait_tmr != NULL) - kfree(b_srp_wait_tmr); - if (b_data_pulse_tmr != NULL) - kfree(b_data_pulse_tmr); - if (b_vbus_pulse_tmr != NULL) - kfree(b_vbus_pulse_tmr); -} - -/* Add timer to timer list */ -void fsl_otg_add_timer(void *gtimer) -{ - struct fsl_otg_timer *timer = gtimer; - struct fsl_otg_timer *tmp_timer; - - /* - * Check if the timer is already in the active list, - * if so update timer count - */ - list_for_each_entry(tmp_timer, &active_timers, list) - if (tmp_timer == timer) { - timer->count = timer->expires; - return; - } - timer->count = timer->expires; - list_add_tail(&timer->list, &active_timers); -} - -/* Remove timer from the timer list; clear timeout status */ -void fsl_otg_del_timer(void *gtimer) -{ - struct fsl_otg_timer *timer = gtimer; - struct fsl_otg_timer *tmp_timer, *del_tmp; - - list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) - if (tmp_timer == timer) - list_del(&timer->list); -} - -/* - * Reduce timer count by 1, and find timeout conditions. - * Called by fsl_otg 1ms timer interrupt - */ -int fsl_otg_tick_timer(void) -{ - struct fsl_otg_timer *tmp_timer, *del_tmp; - int expired = 0; - - list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) { - tmp_timer->count--; - /* check if timer expires */ - if (!tmp_timer->count) { - list_del(&tmp_timer->list); - tmp_timer->function(tmp_timer->data); - expired = 1; - } - } - - return expired; -} - -/* Reset controller, not reset the bus */ -void otg_reset_controller(void) -{ - u32 command; - - command = fsl_readl(&usb_dr_regs->usbcmd); - command |= (1 << 1); - fsl_writel(command, &usb_dr_regs->usbcmd); - while (fsl_readl(&usb_dr_regs->usbcmd) & (1 << 1)) - ; -} - -/* Call suspend/resume routines in host driver */ -int fsl_otg_start_host(struct otg_fsm *fsm, int on) -{ - struct usb_otg *otg = fsm->otg; - struct device *dev; - struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy); - u32 retval = 0; - - if (!otg->host) - return -ENODEV; - dev = otg->host->controller; - - /* - * Update a_vbus_vld state as a_vbus_vld int is disabled - * in device mode - */ - fsm->a_vbus_vld = - !!(fsl_readl(&usb_dr_regs->otgsc) & OTGSC_STS_A_VBUS_VALID); - if (on) { - /* start fsl usb host controller */ - if (otg_dev->host_working) - goto end; - else { - otg_reset_controller(); - VDBG("host on......\n"); - if (dev->driver->pm && dev->driver->pm->resume) { - retval = dev->driver->pm->resume(dev); - if (fsm->id) { - /* default-b */ - fsl_otg_drv_vbus(1); - /* - * Workaround: b_host can't driver - * vbus, but PP in PORTSC needs to - * be 1 for host to work. - * So we set drv_vbus bit in - * transceiver to 0 thru ULPI. - */ - write_ulpi(0x0c, 0x20); - } - } - - otg_dev->host_working = 1; - } - } else { - /* stop fsl usb host controller */ - if (!otg_dev->host_working) - goto end; - else { - VDBG("host off......\n"); - if (dev && dev->driver) { - if (dev->driver->pm && dev->driver->pm->suspend) - retval = dev->driver->pm->suspend(dev); - if (fsm->id) - /* default-b */ - fsl_otg_drv_vbus(0); - } - otg_dev->host_working = 0; - } - } -end: - return retval; -} - -/* - * Call suspend and resume function in udc driver - * to stop and start udc driver. - */ -int fsl_otg_start_gadget(struct otg_fsm *fsm, int on) -{ - struct usb_otg *otg = fsm->otg; - struct device *dev; - - if (!otg->gadget || !otg->gadget->dev.parent) - return -ENODEV; - - VDBG("gadget %s\n", on ? "on" : "off"); - dev = otg->gadget->dev.parent; - - if (on) { - if (dev->driver->resume) - dev->driver->resume(dev); - } else { - if (dev->driver->suspend) - dev->driver->suspend(dev, otg_suspend_state); - } - - return 0; -} - -/* - * Called by initialization code of host driver. Register host controller - * to the OTG. Suspend host for OTG role detection. - */ -static int fsl_otg_set_host(struct usb_otg *otg, struct usb_bus *host) -{ - struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy); - - if (!otg || otg_dev != fsl_otg_dev) - return -ENODEV; - - otg->host = host; - - otg_dev->fsm.a_bus_drop = 0; - otg_dev->fsm.a_bus_req = 1; - - if (host) { - VDBG("host off......\n"); - - otg->host->otg_port = fsl_otg_initdata.otg_port; - otg->host->is_b_host = otg_dev->fsm.id; - /* - * must leave time for khubd to finish its thing - * before yanking the host driver out from under it, - * so suspend the host after a short delay. - */ - otg_dev->host_working = 1; - schedule_delayed_work(&otg_dev->otg_event, 100); - return 0; - } else { - /* host driver going away */ - if (!(fsl_readl(&otg_dev->dr_mem_map->otgsc) & - OTGSC_STS_USB_ID)) { - /* Mini-A cable connected */ - struct otg_fsm *fsm = &otg_dev->fsm; - - otg->phy->state = OTG_STATE_UNDEFINED; - fsm->protocol = PROTO_UNDEF; - } - } - - otg_dev->host_working = 0; - - otg_statemachine(&otg_dev->fsm); - - return 0; -} - -/* Called by initialization code of udc. Register udc to OTG. */ -static int fsl_otg_set_peripheral(struct usb_otg *otg, - struct usb_gadget *gadget) -{ - struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy); - - VDBG("otg_dev 0x%x\n", (int)otg_dev); - VDBG("fsl_otg_dev 0x%x\n", (int)fsl_otg_dev); - - if (!otg || otg_dev != fsl_otg_dev) - return -ENODEV; - - if (!gadget) { - if (!otg->default_a) - otg->gadget->ops->vbus_draw(otg->gadget, 0); - usb_gadget_vbus_disconnect(otg->gadget); - otg->gadget = 0; - otg_dev->fsm.b_bus_req = 0; - otg_statemachine(&otg_dev->fsm); - return 0; - } - - otg->gadget = gadget; - otg->gadget->is_a_peripheral = !otg_dev->fsm.id; - - otg_dev->fsm.b_bus_req = 1; - - /* start the gadget right away if the ID pin says Mini-B */ - DBG("ID pin=%d\n", otg_dev->fsm.id); - if (otg_dev->fsm.id == 1) { - fsl_otg_start_host(&otg_dev->fsm, 0); - otg_drv_vbus(&otg_dev->fsm, 0); - fsl_otg_start_gadget(&otg_dev->fsm, 1); - } - - return 0; -} - -/* Set OTG port power, only for B-device */ -static int fsl_otg_set_power(struct usb_phy *phy, unsigned mA) -{ - if (!fsl_otg_dev) - return -ENODEV; - if (phy->state == OTG_STATE_B_PERIPHERAL) - pr_info("FSL OTG: Draw %d mA\n", mA); - - return 0; -} - -/* - * Delayed pin detect interrupt processing. - * - * When the Mini-A cable is disconnected from the board, - * the pin-detect interrupt happens before the disconnect - * interrupts for the connected device(s). In order to - * process the disconnect interrupt(s) prior to switching - * roles, the pin-detect interrupts are delayed, and handled - * by this routine. - */ -static void fsl_otg_event(struct work_struct *work) -{ - struct fsl_otg *og = container_of(work, struct fsl_otg, otg_event.work); - struct otg_fsm *fsm = &og->fsm; - - if (fsm->id) { /* switch to gadget */ - fsl_otg_start_host(fsm, 0); - otg_drv_vbus(fsm, 0); - fsl_otg_start_gadget(fsm, 1); - } -} - -/* B-device start SRP */ -static int fsl_otg_start_srp(struct usb_otg *otg) -{ - struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy); - - if (!otg || otg_dev != fsl_otg_dev - || otg->phy->state != OTG_STATE_B_IDLE) - return -ENODEV; - - otg_dev->fsm.b_bus_req = 1; - otg_statemachine(&otg_dev->fsm); - - return 0; -} - -/* A_host suspend will call this function to start hnp */ -static int fsl_otg_start_hnp(struct usb_otg *otg) -{ - struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy); - - if (!otg || otg_dev != fsl_otg_dev) - return -ENODEV; - - DBG("start_hnp...n"); - - /* clear a_bus_req to enter a_suspend state */ - otg_dev->fsm.a_bus_req = 0; - otg_statemachine(&otg_dev->fsm); - - return 0; -} - -/* - * Interrupt handler. OTG/host/peripheral share the same int line. - * OTG driver clears OTGSC interrupts and leaves USB interrupts - * intact. It needs to have knowledge of some USB interrupts - * such as port change. - */ -irqreturn_t fsl_otg_isr(int irq, void *dev_id) -{ - struct otg_fsm *fsm = &((struct fsl_otg *)dev_id)->fsm; - struct usb_otg *otg = ((struct fsl_otg *)dev_id)->phy.otg; - u32 otg_int_src, otg_sc; - - otg_sc = fsl_readl(&usb_dr_regs->otgsc); - otg_int_src = otg_sc & OTGSC_INTSTS_MASK & (otg_sc >> 8); - - /* Only clear otg interrupts */ - fsl_writel(otg_sc, &usb_dr_regs->otgsc); - - /*FIXME: ID change not generate when init to 0 */ - fsm->id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0; - otg->default_a = (fsm->id == 0); - - /* process OTG interrupts */ - if (otg_int_src) { - if (otg_int_src & OTGSC_INTSTS_USB_ID) { - fsm->id = (otg_sc & OTGSC_STS_USB_ID) ? 1 : 0; - otg->default_a = (fsm->id == 0); - /* clear conn information */ - if (fsm->id) - fsm->b_conn = 0; - else - fsm->a_conn = 0; - - if (otg->host) - otg->host->is_b_host = fsm->id; - if (otg->gadget) - otg->gadget->is_a_peripheral = !fsm->id; - VDBG("ID int (ID is %d)\n", fsm->id); - - if (fsm->id) { /* switch to gadget */ - schedule_delayed_work( - &((struct fsl_otg *)dev_id)->otg_event, - 100); - } else { /* switch to host */ - cancel_delayed_work(& - ((struct fsl_otg *)dev_id)-> - otg_event); - fsl_otg_start_gadget(fsm, 0); - otg_drv_vbus(fsm, 1); - fsl_otg_start_host(fsm, 1); - } - return IRQ_HANDLED; - } - } - return IRQ_NONE; -} - -static struct otg_fsm_ops fsl_otg_ops = { - .chrg_vbus = fsl_otg_chrg_vbus, - .drv_vbus = fsl_otg_drv_vbus, - .loc_conn = fsl_otg_loc_conn, - .loc_sof = fsl_otg_loc_sof, - .start_pulse = fsl_otg_start_pulse, - - .add_timer = fsl_otg_add_timer, - .del_timer = fsl_otg_del_timer, - - .start_host = fsl_otg_start_host, - .start_gadget = fsl_otg_start_gadget, -}; - -/* Initialize the global variable fsl_otg_dev and request IRQ for OTG */ -static int fsl_otg_conf(struct platform_device *pdev) -{ - struct fsl_otg *fsl_otg_tc; - int status; - - if (fsl_otg_dev) - return 0; - - /* allocate space to fsl otg device */ - fsl_otg_tc = kzalloc(sizeof(struct fsl_otg), GFP_KERNEL); - if (!fsl_otg_tc) - return -ENOMEM; - - fsl_otg_tc->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL); - if (!fsl_otg_tc->phy.otg) { - kfree(fsl_otg_tc); - return -ENOMEM; - } - - INIT_DELAYED_WORK(&fsl_otg_tc->otg_event, fsl_otg_event); - - INIT_LIST_HEAD(&active_timers); - status = fsl_otg_init_timers(&fsl_otg_tc->fsm); - if (status) { - pr_info("Couldn't init OTG timers\n"); - goto err; - } - spin_lock_init(&fsl_otg_tc->fsm.lock); - - /* Set OTG state machine operations */ - fsl_otg_tc->fsm.ops = &fsl_otg_ops; - - /* initialize the otg structure */ - fsl_otg_tc->phy.label = DRIVER_DESC; - fsl_otg_tc->phy.set_power = fsl_otg_set_power; - - fsl_otg_tc->phy.otg->phy = &fsl_otg_tc->phy; - fsl_otg_tc->phy.otg->set_host = fsl_otg_set_host; - fsl_otg_tc->phy.otg->set_peripheral = fsl_otg_set_peripheral; - fsl_otg_tc->phy.otg->start_hnp = fsl_otg_start_hnp; - fsl_otg_tc->phy.otg->start_srp = fsl_otg_start_srp; - - fsl_otg_dev = fsl_otg_tc; - - /* Store the otg transceiver */ - status = usb_set_transceiver(&fsl_otg_tc->phy); - if (status) { - pr_warn(FSL_OTG_NAME ": unable to register OTG transceiver.\n"); - goto err; - } - - return 0; -err: - fsl_otg_uninit_timers(); - kfree(fsl_otg_tc->phy.otg); - kfree(fsl_otg_tc); - return status; -} - -/* OTG Initialization */ -int usb_otg_start(struct platform_device *pdev) -{ - struct fsl_otg *p_otg; - struct usb_phy *otg_trans = usb_get_transceiver(); - struct otg_fsm *fsm; - int status; - struct resource *res; - u32 temp; - struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; - - p_otg = container_of(otg_trans, struct fsl_otg, phy); - fsm = &p_otg->fsm; - - /* Initialize the state machine structure with default values */ - SET_OTG_STATE(otg_trans, OTG_STATE_UNDEFINED); - fsm->otg = p_otg->phy.otg; - - /* We don't require predefined MEM/IRQ resource index */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENXIO; - - /* We don't request_mem_region here to enable resource sharing - * with host/device */ - - usb_dr_regs = ioremap(res->start, sizeof(struct usb_dr_mmap)); - p_otg->dr_mem_map = (struct usb_dr_mmap *)usb_dr_regs; - pdata->regs = (void *)usb_dr_regs; - - if (pdata->init && pdata->init(pdev) != 0) - return -EINVAL; - - if (pdata->big_endian_mmio) { - _fsl_readl = _fsl_readl_be; - _fsl_writel = _fsl_writel_be; - } else { - _fsl_readl = _fsl_readl_le; - _fsl_writel = _fsl_writel_le; - } - - /* request irq */ - p_otg->irq = platform_get_irq(pdev, 0); - status = request_irq(p_otg->irq, fsl_otg_isr, - IRQF_SHARED, driver_name, p_otg); - if (status) { - dev_dbg(p_otg->phy.dev, "can't get IRQ %d, error %d\n", - p_otg->irq, status); - iounmap(p_otg->dr_mem_map); - kfree(p_otg->phy.otg); - kfree(p_otg); - return status; - } - - /* stop the controller */ - temp = fsl_readl(&p_otg->dr_mem_map->usbcmd); - temp &= ~USB_CMD_RUN_STOP; - fsl_writel(temp, &p_otg->dr_mem_map->usbcmd); - - /* reset the controller */ - temp = fsl_readl(&p_otg->dr_mem_map->usbcmd); - temp |= USB_CMD_CTRL_RESET; - fsl_writel(temp, &p_otg->dr_mem_map->usbcmd); - - /* wait reset completed */ - while (fsl_readl(&p_otg->dr_mem_map->usbcmd) & USB_CMD_CTRL_RESET) - ; - - /* configure the VBUSHS as IDLE(both host and device) */ - temp = USB_MODE_STREAM_DISABLE | (pdata->es ? USB_MODE_ES : 0); - fsl_writel(temp, &p_otg->dr_mem_map->usbmode); - - /* configure PHY interface */ - temp = fsl_readl(&p_otg->dr_mem_map->portsc); - temp &= ~(PORTSC_PHY_TYPE_SEL | PORTSC_PTW); - switch (pdata->phy_mode) { - case FSL_USB2_PHY_ULPI: - temp |= PORTSC_PTS_ULPI; - break; - case FSL_USB2_PHY_UTMI_WIDE: - temp |= PORTSC_PTW_16BIT; - /* fall through */ - case FSL_USB2_PHY_UTMI: - temp |= PORTSC_PTS_UTMI; - /* fall through */ - default: - break; - } - fsl_writel(temp, &p_otg->dr_mem_map->portsc); - - if (pdata->have_sysif_regs) { - /* configure control enable IO output, big endian register */ - temp = __raw_readl(&p_otg->dr_mem_map->control); - temp |= USB_CTRL_IOENB; - __raw_writel(temp, &p_otg->dr_mem_map->control); - } - - /* disable all interrupt and clear all OTGSC status */ - temp = fsl_readl(&p_otg->dr_mem_map->otgsc); - temp &= ~OTGSC_INTERRUPT_ENABLE_BITS_MASK; - temp |= OTGSC_INTERRUPT_STATUS_BITS_MASK | OTGSC_CTRL_VBUS_DISCHARGE; - fsl_writel(temp, &p_otg->dr_mem_map->otgsc); - - /* - * The identification (id) input is FALSE when a Mini-A plug is inserted - * in the devices Mini-AB receptacle. Otherwise, this input is TRUE. - * Also: record initial state of ID pin - */ - if (fsl_readl(&p_otg->dr_mem_map->otgsc) & OTGSC_STS_USB_ID) { - p_otg->phy.state = OTG_STATE_UNDEFINED; - p_otg->fsm.id = 1; - } else { - p_otg->phy.state = OTG_STATE_A_IDLE; - p_otg->fsm.id = 0; - } - - DBG("initial ID pin=%d\n", p_otg->fsm.id); - - /* enable OTG ID pin interrupt */ - temp = fsl_readl(&p_otg->dr_mem_map->otgsc); - temp |= OTGSC_INTR_USB_ID_EN; - temp &= ~(OTGSC_CTRL_VBUS_DISCHARGE | OTGSC_INTR_1MS_TIMER_EN); - fsl_writel(temp, &p_otg->dr_mem_map->otgsc); - - return 0; -} - -/* - * state file in sysfs - */ -static int show_fsl_usb2_otg_state(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct otg_fsm *fsm = &fsl_otg_dev->fsm; - char *next = buf; - unsigned size = PAGE_SIZE; - unsigned long flags; - int t; - - spin_lock_irqsave(&fsm->lock, flags); - - /* basic driver infomation */ - t = scnprintf(next, size, - DRIVER_DESC "\n" "fsl_usb2_otg version: %s\n\n", - DRIVER_VERSION); - size -= t; - next += t; - - /* Registers */ - t = scnprintf(next, size, - "OTGSC: 0x%08x\n" - "PORTSC: 0x%08x\n" - "USBMODE: 0x%08x\n" - "USBCMD: 0x%08x\n" - "USBSTS: 0x%08x\n" - "USBINTR: 0x%08x\n", - fsl_readl(&usb_dr_regs->otgsc), - fsl_readl(&usb_dr_regs->portsc), - fsl_readl(&usb_dr_regs->usbmode), - fsl_readl(&usb_dr_regs->usbcmd), - fsl_readl(&usb_dr_regs->usbsts), - fsl_readl(&usb_dr_regs->usbintr)); - size -= t; - next += t; - - /* State */ - t = scnprintf(next, size, - "OTG state: %s\n\n", - otg_state_string(fsl_otg_dev->phy.state)); - size -= t; - next += t; - - /* State Machine Variables */ - t = scnprintf(next, size, - "a_bus_req: %d\n" - "b_bus_req: %d\n" - "a_bus_resume: %d\n" - "a_bus_suspend: %d\n" - "a_conn: %d\n" - "a_sess_vld: %d\n" - "a_srp_det: %d\n" - "a_vbus_vld: %d\n" - "b_bus_resume: %d\n" - "b_bus_suspend: %d\n" - "b_conn: %d\n" - "b_se0_srp: %d\n" - "b_sess_end: %d\n" - "b_sess_vld: %d\n" - "id: %d\n", - fsm->a_bus_req, - fsm->b_bus_req, - fsm->a_bus_resume, - fsm->a_bus_suspend, - fsm->a_conn, - fsm->a_sess_vld, - fsm->a_srp_det, - fsm->a_vbus_vld, - fsm->b_bus_resume, - fsm->b_bus_suspend, - fsm->b_conn, - fsm->b_se0_srp, - fsm->b_sess_end, - fsm->b_sess_vld, - fsm->id); - size -= t; - next += t; - - spin_unlock_irqrestore(&fsm->lock, flags); - - return PAGE_SIZE - size; -} - -static DEVICE_ATTR(fsl_usb2_otg_state, S_IRUGO, show_fsl_usb2_otg_state, NULL); - - -/* Char driver interface to control some OTG input */ - -/* - * Handle some ioctl command, such as get otg - * status and set host suspend - */ -static long fsl_otg_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - u32 retval = 0; - - switch (cmd) { - case GET_OTG_STATUS: - retval = fsl_otg_dev->host_working; - break; - - case SET_A_SUSPEND_REQ: - fsl_otg_dev->fsm.a_suspend_req = arg; - break; - - case SET_A_BUS_DROP: - fsl_otg_dev->fsm.a_bus_drop = arg; - break; - - case SET_A_BUS_REQ: - fsl_otg_dev->fsm.a_bus_req = arg; - break; - - case SET_B_BUS_REQ: - fsl_otg_dev->fsm.b_bus_req = arg; - break; - - default: - break; - } - - otg_statemachine(&fsl_otg_dev->fsm); - - return retval; -} - -static int fsl_otg_open(struct inode *inode, struct file *file) -{ - return 0; -} - -static int fsl_otg_release(struct inode *inode, struct file *file) -{ - return 0; -} - -static const struct file_operations otg_fops = { - .owner = THIS_MODULE, - .llseek = NULL, - .read = NULL, - .write = NULL, - .unlocked_ioctl = fsl_otg_ioctl, - .open = fsl_otg_open, - .release = fsl_otg_release, -}; - -static int __devinit fsl_otg_probe(struct platform_device *pdev) -{ - int ret; - - if (!pdev->dev.platform_data) - return -ENODEV; - - /* configure the OTG */ - ret = fsl_otg_conf(pdev); - if (ret) { - dev_err(&pdev->dev, "Couldn't configure OTG module\n"); - return ret; - } - - /* start OTG */ - ret = usb_otg_start(pdev); - if (ret) { - dev_err(&pdev->dev, "Can't init FSL OTG device\n"); - return ret; - } - - ret = register_chrdev(FSL_OTG_MAJOR, FSL_OTG_NAME, &otg_fops); - if (ret) { - dev_err(&pdev->dev, "unable to register FSL OTG device\n"); - return ret; - } - - ret = device_create_file(&pdev->dev, &dev_attr_fsl_usb2_otg_state); - if (ret) - dev_warn(&pdev->dev, "Can't register sysfs attribute\n"); - - return ret; -} - -static int __devexit fsl_otg_remove(struct platform_device *pdev) -{ - struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; - - usb_set_transceiver(NULL); - free_irq(fsl_otg_dev->irq, fsl_otg_dev); - - iounmap((void *)usb_dr_regs); - - fsl_otg_uninit_timers(); - kfree(fsl_otg_dev->phy.otg); - kfree(fsl_otg_dev); - - device_remove_file(&pdev->dev, &dev_attr_fsl_usb2_otg_state); - - unregister_chrdev(FSL_OTG_MAJOR, FSL_OTG_NAME); - - if (pdata->exit) - pdata->exit(pdev); - - return 0; -} - -struct platform_driver fsl_otg_driver = { - .probe = fsl_otg_probe, - .remove = __devexit_p(fsl_otg_remove), - .driver = { - .name = driver_name, - .owner = THIS_MODULE, - }, -}; - -module_platform_driver(fsl_otg_driver); - -MODULE_DESCRIPTION(DRIVER_INFO); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/otg/fsl_otg.h b/ANDROID_3.4.5/drivers/usb/otg/fsl_otg.h deleted file mode 100644 index ca266280..00000000 --- a/ANDROID_3.4.5/drivers/usb/otg/fsl_otg.h +++ /dev/null @@ -1,406 +0,0 @@ -/* Copyright (C) 2007,2008 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "otg_fsm.h" -#include -#include - -/* USB Command Register Bit Masks */ -#define USB_CMD_RUN_STOP (0x1<<0) -#define USB_CMD_CTRL_RESET (0x1<<1) -#define USB_CMD_PERIODIC_SCHEDULE_EN (0x1<<4) -#define USB_CMD_ASYNC_SCHEDULE_EN (0x1<<5) -#define USB_CMD_INT_AA_DOORBELL (0x1<<6) -#define USB_CMD_ASP (0x3<<8) -#define USB_CMD_ASYNC_SCH_PARK_EN (0x1<<11) -#define USB_CMD_SUTW (0x1<<13) -#define USB_CMD_ATDTW (0x1<<14) -#define USB_CMD_ITC (0xFF<<16) - -/* bit 15,3,2 are frame list size */ -#define USB_CMD_FRAME_SIZE_1024 (0x0<<15 | 0x0<<2) -#define USB_CMD_FRAME_SIZE_512 (0x0<<15 | 0x1<<2) -#define USB_CMD_FRAME_SIZE_256 (0x0<<15 | 0x2<<2) -#define USB_CMD_FRAME_SIZE_128 (0x0<<15 | 0x3<<2) -#define USB_CMD_FRAME_SIZE_64 (0x1<<15 | 0x0<<2) -#define USB_CMD_FRAME_SIZE_32 (0x1<<15 | 0x1<<2) -#define USB_CMD_FRAME_SIZE_16 (0x1<<15 | 0x2<<2) -#define USB_CMD_FRAME_SIZE_8 (0x1<<15 | 0x3<<2) - -/* bit 9-8 are async schedule park mode count */ -#define USB_CMD_ASP_00 (0x0<<8) -#define USB_CMD_ASP_01 (0x1<<8) -#define USB_CMD_ASP_10 (0x2<<8) -#define USB_CMD_ASP_11 (0x3<<8) -#define USB_CMD_ASP_BIT_POS (8) - -/* bit 23-16 are interrupt threshold control */ -#define USB_CMD_ITC_NO_THRESHOLD (0x00<<16) -#define USB_CMD_ITC_1_MICRO_FRM (0x01<<16) -#define USB_CMD_ITC_2_MICRO_FRM (0x02<<16) -#define USB_CMD_ITC_4_MICRO_FRM (0x04<<16) -#define USB_CMD_ITC_8_MICRO_FRM (0x08<<16) -#define USB_CMD_ITC_16_MICRO_FRM (0x10<<16) -#define USB_CMD_ITC_32_MICRO_FRM (0x20<<16) -#define USB_CMD_ITC_64_MICRO_FRM (0x40<<16) -#define USB_CMD_ITC_BIT_POS (16) - -/* USB Status Register Bit Masks */ -#define USB_STS_INT (0x1<<0) -#define USB_STS_ERR (0x1<<1) -#define USB_STS_PORT_CHANGE (0x1<<2) -#define USB_STS_FRM_LST_ROLL (0x1<<3) -#define USB_STS_SYS_ERR (0x1<<4) -#define USB_STS_IAA (0x1<<5) -#define USB_STS_RESET_RECEIVED (0x1<<6) -#define USB_STS_SOF (0x1<<7) -#define USB_STS_DCSUSPEND (0x1<<8) -#define USB_STS_HC_HALTED (0x1<<12) -#define USB_STS_RCL (0x1<<13) -#define USB_STS_PERIODIC_SCHEDULE (0x1<<14) -#define USB_STS_ASYNC_SCHEDULE (0x1<<15) - -/* USB Interrupt Enable Register Bit Masks */ -#define USB_INTR_INT_EN (0x1<<0) -#define USB_INTR_ERR_INT_EN (0x1<<1) -#define USB_INTR_PC_DETECT_EN (0x1<<2) -#define USB_INTR_FRM_LST_ROLL_EN (0x1<<3) -#define USB_INTR_SYS_ERR_EN (0x1<<4) -#define USB_INTR_ASYN_ADV_EN (0x1<<5) -#define USB_INTR_RESET_EN (0x1<<6) -#define USB_INTR_SOF_EN (0x1<<7) -#define USB_INTR_DEVICE_SUSPEND (0x1<<8) - -/* Device Address bit masks */ -#define USB_DEVICE_ADDRESS_MASK (0x7F<<25) -#define USB_DEVICE_ADDRESS_BIT_POS (25) -/* PORTSC Register Bit Masks,Only one PORT in OTG mode*/ -#define PORTSC_CURRENT_CONNECT_STATUS (0x1<<0) -#define PORTSC_CONNECT_STATUS_CHANGE (0x1<<1) -#define PORTSC_PORT_ENABLE (0x1<<2) -#define PORTSC_PORT_EN_DIS_CHANGE (0x1<<3) -#define PORTSC_OVER_CURRENT_ACT (0x1<<4) -#define PORTSC_OVER_CUURENT_CHG (0x1<<5) -#define PORTSC_PORT_FORCE_RESUME (0x1<<6) -#define PORTSC_PORT_SUSPEND (0x1<<7) -#define PORTSC_PORT_RESET (0x1<<8) -#define PORTSC_LINE_STATUS_BITS (0x3<<10) -#define PORTSC_PORT_POWER (0x1<<12) -#define PORTSC_PORT_INDICTOR_CTRL (0x3<<14) -#define PORTSC_PORT_TEST_CTRL (0xF<<16) -#define PORTSC_WAKE_ON_CONNECT_EN (0x1<<20) -#define PORTSC_WAKE_ON_CONNECT_DIS (0x1<<21) -#define PORTSC_WAKE_ON_OVER_CURRENT (0x1<<22) -#define PORTSC_PHY_LOW_POWER_SPD (0x1<<23) -#define PORTSC_PORT_FORCE_FULL_SPEED (0x1<<24) -#define PORTSC_PORT_SPEED_MASK (0x3<<26) -#define PORTSC_TRANSCEIVER_WIDTH (0x1<<28) -#define PORTSC_PHY_TYPE_SEL (0x3<<30) -/* bit 11-10 are line status */ -#define PORTSC_LINE_STATUS_SE0 (0x0<<10) -#define PORTSC_LINE_STATUS_JSTATE (0x1<<10) -#define PORTSC_LINE_STATUS_KSTATE (0x2<<10) -#define PORTSC_LINE_STATUS_UNDEF (0x3<<10) -#define PORTSC_LINE_STATUS_BIT_POS (10) - -/* bit 15-14 are port indicator control */ -#define PORTSC_PIC_OFF (0x0<<14) -#define PORTSC_PIC_AMBER (0x1<<14) -#define PORTSC_PIC_GREEN (0x2<<14) -#define PORTSC_PIC_UNDEF (0x3<<14) -#define PORTSC_PIC_BIT_POS (14) - -/* bit 19-16 are port test control */ -#define PORTSC_PTC_DISABLE (0x0<<16) -#define PORTSC_PTC_JSTATE (0x1<<16) -#define PORTSC_PTC_KSTATE (0x2<<16) -#define PORTSC_PTC_SEQNAK (0x3<<16) -#define PORTSC_PTC_PACKET (0x4<<16) -#define PORTSC_PTC_FORCE_EN (0x5<<16) -#define PORTSC_PTC_BIT_POS (16) - -/* bit 27-26 are port speed */ -#define PORTSC_PORT_SPEED_FULL (0x0<<26) -#define PORTSC_PORT_SPEED_LOW (0x1<<26) -#define PORTSC_PORT_SPEED_HIGH (0x2<<26) -#define PORTSC_PORT_SPEED_UNDEF (0x3<<26) -#define PORTSC_SPEED_BIT_POS (26) - -/* bit 28 is parallel transceiver width for UTMI interface */ -#define PORTSC_PTW (0x1<<28) -#define PORTSC_PTW_8BIT (0x0<<28) -#define PORTSC_PTW_16BIT (0x1<<28) - -/* bit 31-30 are port transceiver select */ -#define PORTSC_PTS_UTMI (0x0<<30) -#define PORTSC_PTS_ULPI (0x2<<30) -#define PORTSC_PTS_FSLS_SERIAL (0x3<<30) -#define PORTSC_PTS_BIT_POS (30) - -#define PORTSC_W1C_BITS \ - (PORTSC_CONNECT_STATUS_CHANGE | \ - PORTSC_PORT_EN_DIS_CHANGE | \ - PORTSC_OVER_CUURENT_CHG) - -/* OTG Status Control Register Bit Masks */ -#define OTGSC_CTRL_VBUS_DISCHARGE (0x1<<0) -#define OTGSC_CTRL_VBUS_CHARGE (0x1<<1) -#define OTGSC_CTRL_OTG_TERMINATION (0x1<<3) -#define OTGSC_CTRL_DATA_PULSING (0x1<<4) -#define OTGSC_CTRL_ID_PULL_EN (0x1<<5) -#define OTGSC_HA_DATA_PULSE (0x1<<6) -#define OTGSC_HA_BA (0x1<<7) -#define OTGSC_STS_USB_ID (0x1<<8) -#define OTGSC_STS_A_VBUS_VALID (0x1<<9) -#define OTGSC_STS_A_SESSION_VALID (0x1<<10) -#define OTGSC_STS_B_SESSION_VALID (0x1<<11) -#define OTGSC_STS_B_SESSION_END (0x1<<12) -#define OTGSC_STS_1MS_TOGGLE (0x1<<13) -#define OTGSC_STS_DATA_PULSING (0x1<<14) -#define OTGSC_INTSTS_USB_ID (0x1<<16) -#define OTGSC_INTSTS_A_VBUS_VALID (0x1<<17) -#define OTGSC_INTSTS_A_SESSION_VALID (0x1<<18) -#define OTGSC_INTSTS_B_SESSION_VALID (0x1<<19) -#define OTGSC_INTSTS_B_SESSION_END (0x1<<20) -#define OTGSC_INTSTS_1MS (0x1<<21) -#define OTGSC_INTSTS_DATA_PULSING (0x1<<22) -#define OTGSC_INTR_USB_ID_EN (0x1<<24) -#define OTGSC_INTR_A_VBUS_VALID_EN (0x1<<25) -#define OTGSC_INTR_A_SESSION_VALID_EN (0x1<<26) -#define OTGSC_INTR_B_SESSION_VALID_EN (0x1<<27) -#define OTGSC_INTR_B_SESSION_END_EN (0x1<<28) -#define OTGSC_INTR_1MS_TIMER_EN (0x1<<29) -#define OTGSC_INTR_DATA_PULSING_EN (0x1<<30) -#define OTGSC_INTSTS_MASK (0x00ff0000) - -/* USB MODE Register Bit Masks */ -#define USB_MODE_CTRL_MODE_IDLE (0x0<<0) -#define USB_MODE_CTRL_MODE_DEVICE (0x2<<0) -#define USB_MODE_CTRL_MODE_HOST (0x3<<0) -#define USB_MODE_CTRL_MODE_RSV (0x1<<0) -#define USB_MODE_SETUP_LOCK_OFF (0x1<<3) -#define USB_MODE_STREAM_DISABLE (0x1<<4) -#define USB_MODE_ES (0x1<<2) /* Endian Select */ - -/* control Register Bit Masks */ -#define USB_CTRL_IOENB (0x1<<2) -#define USB_CTRL_ULPI_INT0EN (0x1<<0) - -/* BCSR5 */ -#define BCSR5_INT_USB (0x02) - -/* USB module clk cfg */ -#define SCCR_OFFS (0xA08) -#define SCCR_USB_CLK_DISABLE (0x00000000) /* USB clk disable */ -#define SCCR_USB_MPHCM_11 (0x00c00000) -#define SCCR_USB_MPHCM_01 (0x00400000) -#define SCCR_USB_MPHCM_10 (0x00800000) -#define SCCR_USB_DRCM_11 (0x00300000) -#define SCCR_USB_DRCM_01 (0x00100000) -#define SCCR_USB_DRCM_10 (0x00200000) - -#define SICRL_OFFS (0x114) -#define SICRL_USB0 (0x40000000) -#define SICRL_USB1 (0x20000000) - -#define SICRH_OFFS (0x118) -#define SICRH_USB_UTMI (0x00020000) - -/* OTG interrupt enable bit masks */ -#define OTGSC_INTERRUPT_ENABLE_BITS_MASK \ - (OTGSC_INTR_USB_ID_EN | \ - OTGSC_INTR_1MS_TIMER_EN | \ - OTGSC_INTR_A_VBUS_VALID_EN | \ - OTGSC_INTR_A_SESSION_VALID_EN | \ - OTGSC_INTR_B_SESSION_VALID_EN | \ - OTGSC_INTR_B_SESSION_END_EN | \ - OTGSC_INTR_DATA_PULSING_EN) - -/* OTG interrupt status bit masks */ -#define OTGSC_INTERRUPT_STATUS_BITS_MASK \ - (OTGSC_INTSTS_USB_ID | \ - OTGSC_INTR_1MS_TIMER_EN | \ - OTGSC_INTSTS_A_VBUS_VALID | \ - OTGSC_INTSTS_A_SESSION_VALID | \ - OTGSC_INTSTS_B_SESSION_VALID | \ - OTGSC_INTSTS_B_SESSION_END | \ - OTGSC_INTSTS_DATA_PULSING) - -/* - * A-DEVICE timing constants - */ - -/* Wait for VBUS Rise */ -#define TA_WAIT_VRISE (100) /* a_wait_vrise 100 ms, section: 6.6.5.1 */ - -/* Wait for B-Connect */ -#define TA_WAIT_BCON (10000) /* a_wait_bcon > 1 sec, section: 6.6.5.2 - * This is only used to get out of - * OTG_STATE_A_WAIT_BCON state if there was - * no connection for these many milliseconds - */ - -/* A-Idle to B-Disconnect */ -/* It is necessary for this timer to be more than 750 ms because of a bug in OPT - * test 5.4 in which B OPT disconnects after 750 ms instead of 75ms as stated - * in the test description - */ -#define TA_AIDL_BDIS (5000) /* a_suspend minimum 200 ms, section: 6.6.5.3 */ - -/* B-Idle to A-Disconnect */ -#define TA_BIDL_ADIS (12) /* 3 to 200 ms */ - -/* B-device timing constants */ - - -/* Data-Line Pulse Time*/ -#define TB_DATA_PLS (10) /* b_srp_init,continue 5~10ms, section:5.3.3 */ -#define TB_DATA_PLS_MIN (5) /* minimum 5 ms */ -#define TB_DATA_PLS_MAX (10) /* maximum 10 ms */ - -/* SRP Initiate Time */ -#define TB_SRP_INIT (100) /* b_srp_init,maximum 100 ms, section:5.3.8 */ - -/* SRP Fail Time */ -#define TB_SRP_FAIL (7000) /* b_srp_init,Fail time 5~30s, section:6.8.2.2*/ - -/* SRP result wait time */ -#define TB_SRP_WAIT (60) - -/* VBus time */ -#define TB_VBUS_PLS (30) /* time to keep vbus pulsing asserted */ - -/* Discharge time */ -/* This time should be less than 10ms. It varies from system to system. */ -#define TB_VBUS_DSCHRG (8) - -/* A-SE0 to B-Reset */ -#define TB_ASE0_BRST (20) /* b_wait_acon, mini 3.125 ms,section:6.8.2.4 */ - -/* A bus suspend timer before we can switch to b_wait_aconn */ -#define TB_A_SUSPEND (7) -#define TB_BUS_RESUME (12) - -/* SE0 Time Before SRP */ -#define TB_SE0_SRP (2) /* b_idle,minimum 2 ms, section:5.3.2 */ - -#define SET_OTG_STATE(otg_ptr, newstate) ((otg_ptr)->state = newstate) - -struct usb_dr_mmap { - /* Capability register */ - u8 res1[256]; - u16 caplength; /* Capability Register Length */ - u16 hciversion; /* Host Controller Interface Version */ - u32 hcsparams; /* Host Controller Structual Parameters */ - u32 hccparams; /* Host Controller Capability Parameters */ - u8 res2[20]; - u32 dciversion; /* Device Controller Interface Version */ - u32 dccparams; /* Device Controller Capability Parameters */ - u8 res3[24]; - /* Operation register */ - u32 usbcmd; /* USB Command Register */ - u32 usbsts; /* USB Status Register */ - u32 usbintr; /* USB Interrupt Enable Register */ - u32 frindex; /* Frame Index Register */ - u8 res4[4]; - u32 deviceaddr; /* Device Address */ - u32 endpointlistaddr; /* Endpoint List Address Register */ - u8 res5[4]; - u32 burstsize; /* Master Interface Data Burst Size Register */ - u32 txttfilltuning; /* Transmit FIFO Tuning Controls Register */ - u8 res6[8]; - u32 ulpiview; /* ULPI register access */ - u8 res7[12]; - u32 configflag; /* Configure Flag Register */ - u32 portsc; /* Port 1 Status and Control Register */ - u8 res8[28]; - u32 otgsc; /* On-The-Go Status and Control */ - u32 usbmode; /* USB Mode Register */ - u32 endptsetupstat; /* Endpoint Setup Status Register */ - u32 endpointprime; /* Endpoint Initialization Register */ - u32 endptflush; /* Endpoint Flush Register */ - u32 endptstatus; /* Endpoint Status Register */ - u32 endptcomplete; /* Endpoint Complete Register */ - u32 endptctrl[6]; /* Endpoint Control Registers */ - u8 res9[552]; - u32 snoop1; - u32 snoop2; - u32 age_cnt_thresh; /* Age Count Threshold Register */ - u32 pri_ctrl; /* Priority Control Register */ - u32 si_ctrl; /* System Interface Control Register */ - u8 res10[236]; - u32 control; /* General Purpose Control Register */ -}; - -struct fsl_otg_timer { - unsigned long expires; /* Number of count increase to timeout */ - unsigned long count; /* Tick counter */ - void (*function)(unsigned long); /* Timeout function */ - unsigned long data; /* Data passed to function */ - struct list_head list; -}; - -inline struct fsl_otg_timer *otg_timer_initializer -(void (*function)(unsigned long), unsigned long expires, unsigned long data) -{ - struct fsl_otg_timer *timer; - - timer = kmalloc(sizeof(struct fsl_otg_timer), GFP_KERNEL); - if (!timer) - return NULL; - timer->function = function; - timer->expires = expires; - timer->data = data; - return timer; -} - -struct fsl_otg { - struct usb_phy phy; - struct otg_fsm fsm; - struct usb_dr_mmap *dr_mem_map; - struct delayed_work otg_event; - - /* used for usb host */ - struct work_struct work_wq; - u8 host_working; - - int irq; -}; - -struct fsl_otg_config { - u8 otg_port; -}; - -/* For SRP and HNP handle */ -#define FSL_OTG_MAJOR 240 -#define FSL_OTG_NAME "fsl-usb2-otg" -/* Command to OTG driver ioctl */ -#define OTG_IOCTL_MAGIC FSL_OTG_MAJOR -/* if otg work as host, it should return 1, otherwise return 0 */ -#define GET_OTG_STATUS _IOR(OTG_IOCTL_MAGIC, 1, int) -#define SET_A_SUSPEND_REQ _IOW(OTG_IOCTL_MAGIC, 2, int) -#define SET_A_BUS_DROP _IOW(OTG_IOCTL_MAGIC, 3, int) -#define SET_A_BUS_REQ _IOW(OTG_IOCTL_MAGIC, 4, int) -#define SET_B_BUS_REQ _IOW(OTG_IOCTL_MAGIC, 5, int) -#define GET_A_SUSPEND_REQ _IOR(OTG_IOCTL_MAGIC, 6, int) -#define GET_A_BUS_DROP _IOR(OTG_IOCTL_MAGIC, 7, int) -#define GET_A_BUS_REQ _IOR(OTG_IOCTL_MAGIC, 8, int) -#define GET_B_BUS_REQ _IOR(OTG_IOCTL_MAGIC, 9, int) - -void fsl_otg_add_timer(void *timer); -void fsl_otg_del_timer(void *timer); -void fsl_otg_pulse_vbus(void); diff --git a/ANDROID_3.4.5/drivers/usb/otg/gpio_vbus.c b/ANDROID_3.4.5/drivers/usb/otg/gpio_vbus.c deleted file mode 100644 index fe208643..00000000 --- a/ANDROID_3.4.5/drivers/usb/otg/gpio_vbus.c +++ /dev/null @@ -1,381 +0,0 @@ -/* - * gpio-vbus.c - simple GPIO VBUS sensing driver for B peripheral devices - * - * Copyright (c) 2008 Philipp Zabel - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - - -/* - * A simple GPIO VBUS sensing driver for B peripheral only devices - * with internal transceivers. It can control a D+ pullup GPIO and - * a regulator to limit the current drawn from VBUS. - * - * Needs to be loaded before the UDC driver that will use it. - */ -struct gpio_vbus_data { - struct usb_phy phy; - struct device *dev; - struct regulator *vbus_draw; - int vbus_draw_enabled; - unsigned mA; - struct delayed_work work; -}; - - -/* - * This driver relies on "both edges" triggering. VBUS has 100 msec to - * stabilize, so the peripheral controller driver may need to cope with - * some bouncing due to current surges (e.g. charging local capacitance) - * and contact chatter. - * - * REVISIT in desperate straits, toggling between rising and falling - * edges might be workable. - */ -#define VBUS_IRQ_FLAGS \ - ( IRQF_SAMPLE_RANDOM | IRQF_SHARED \ - | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING ) - - -/* interface to regulator framework */ -static void set_vbus_draw(struct gpio_vbus_data *gpio_vbus, unsigned mA) -{ - struct regulator *vbus_draw = gpio_vbus->vbus_draw; - int enabled; - - if (!vbus_draw) - return; - - enabled = gpio_vbus->vbus_draw_enabled; - if (mA) { - regulator_set_current_limit(vbus_draw, 0, 1000 * mA); - if (!enabled) { - regulator_enable(vbus_draw); - gpio_vbus->vbus_draw_enabled = 1; - } - } else { - if (enabled) { - regulator_disable(vbus_draw); - gpio_vbus->vbus_draw_enabled = 0; - } - } - gpio_vbus->mA = mA; -} - -static int is_vbus_powered(struct gpio_vbus_mach_info *pdata) -{ - int vbus; - - vbus = gpio_get_value(pdata->gpio_vbus); - if (pdata->gpio_vbus_inverted) - vbus = !vbus; - - return vbus; -} - -static void gpio_vbus_work(struct work_struct *work) -{ - struct gpio_vbus_data *gpio_vbus = - container_of(work, struct gpio_vbus_data, work.work); - struct gpio_vbus_mach_info *pdata = gpio_vbus->dev->platform_data; - int gpio, status; - - if (!gpio_vbus->phy.otg->gadget) - return; - - /* Peripheral controllers which manage the pullup themselves won't have - * gpio_pullup configured here. If it's configured here, we'll do what - * isp1301_omap::b_peripheral() does and enable the pullup here... although - * that may complicate usb_gadget_{,dis}connect() support. - */ - gpio = pdata->gpio_pullup; - if (is_vbus_powered(pdata)) { - status = USB_EVENT_VBUS; - gpio_vbus->phy.state = OTG_STATE_B_PERIPHERAL; - gpio_vbus->phy.last_event = status; - usb_gadget_vbus_connect(gpio_vbus->phy.otg->gadget); - - /* drawing a "unit load" is *always* OK, except for OTG */ - set_vbus_draw(gpio_vbus, 100); - - /* optionally enable D+ pullup */ - if (gpio_is_valid(gpio)) - gpio_set_value(gpio, !pdata->gpio_pullup_inverted); - - atomic_notifier_call_chain(&gpio_vbus->phy.notifier, - status, gpio_vbus->phy.otg->gadget); - } else { - /* optionally disable D+ pullup */ - if (gpio_is_valid(gpio)) - gpio_set_value(gpio, pdata->gpio_pullup_inverted); - - set_vbus_draw(gpio_vbus, 0); - - usb_gadget_vbus_disconnect(gpio_vbus->phy.otg->gadget); - status = USB_EVENT_NONE; - gpio_vbus->phy.state = OTG_STATE_B_IDLE; - gpio_vbus->phy.last_event = status; - - atomic_notifier_call_chain(&gpio_vbus->phy.notifier, - status, gpio_vbus->phy.otg->gadget); - } -} - -/* VBUS change IRQ handler */ -static irqreturn_t gpio_vbus_irq(int irq, void *data) -{ - struct platform_device *pdev = data; - struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data; - struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev); - struct usb_otg *otg = gpio_vbus->phy.otg; - - dev_dbg(&pdev->dev, "VBUS %s (gadget: %s)\n", - is_vbus_powered(pdata) ? "supplied" : "inactive", - otg->gadget ? otg->gadget->name : "none"); - - if (otg->gadget) - schedule_delayed_work(&gpio_vbus->work, msecs_to_jiffies(100)); - - return IRQ_HANDLED; -} - -/* OTG transceiver interface */ - -/* bind/unbind the peripheral controller */ -static int gpio_vbus_set_peripheral(struct usb_otg *otg, - struct usb_gadget *gadget) -{ - struct gpio_vbus_data *gpio_vbus; - struct gpio_vbus_mach_info *pdata; - struct platform_device *pdev; - int gpio, irq; - - gpio_vbus = container_of(otg->phy, struct gpio_vbus_data, phy); - pdev = to_platform_device(gpio_vbus->dev); - pdata = gpio_vbus->dev->platform_data; - irq = gpio_to_irq(pdata->gpio_vbus); - gpio = pdata->gpio_pullup; - - if (!gadget) { - dev_dbg(&pdev->dev, "unregistering gadget '%s'\n", - otg->gadget->name); - - /* optionally disable D+ pullup */ - if (gpio_is_valid(gpio)) - gpio_set_value(gpio, pdata->gpio_pullup_inverted); - - set_vbus_draw(gpio_vbus, 0); - - usb_gadget_vbus_disconnect(otg->gadget); - otg->phy->state = OTG_STATE_UNDEFINED; - - otg->gadget = NULL; - return 0; - } - - otg->gadget = gadget; - dev_dbg(&pdev->dev, "registered gadget '%s'\n", gadget->name); - - /* initialize connection state */ - gpio_vbus_irq(irq, pdev); - return 0; -} - -/* effective for B devices, ignored for A-peripheral */ -static int gpio_vbus_set_power(struct usb_phy *phy, unsigned mA) -{ - struct gpio_vbus_data *gpio_vbus; - - gpio_vbus = container_of(phy, struct gpio_vbus_data, phy); - - if (phy->state == OTG_STATE_B_PERIPHERAL) - set_vbus_draw(gpio_vbus, mA); - return 0; -} - -/* for non-OTG B devices: set/clear transceiver suspend mode */ -static int gpio_vbus_set_suspend(struct usb_phy *phy, int suspend) -{ - struct gpio_vbus_data *gpio_vbus; - - gpio_vbus = container_of(phy, struct gpio_vbus_data, phy); - - /* draw max 0 mA from vbus in suspend mode; or the previously - * recorded amount of current if not suspended - * - * NOTE: high powered configs (mA > 100) may draw up to 2.5 mA - * if they're wake-enabled ... we don't handle that yet. - */ - return gpio_vbus_set_power(phy, suspend ? 0 : gpio_vbus->mA); -} - -/* platform driver interface */ - -static int __init gpio_vbus_probe(struct platform_device *pdev) -{ - struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data; - struct gpio_vbus_data *gpio_vbus; - struct resource *res; - int err, gpio, irq; - - if (!pdata || !gpio_is_valid(pdata->gpio_vbus)) - return -EINVAL; - gpio = pdata->gpio_vbus; - - gpio_vbus = kzalloc(sizeof(struct gpio_vbus_data), GFP_KERNEL); - if (!gpio_vbus) - return -ENOMEM; - - gpio_vbus->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL); - if (!gpio_vbus->phy.otg) { - kfree(gpio_vbus); - return -ENOMEM; - } - - platform_set_drvdata(pdev, gpio_vbus); - gpio_vbus->dev = &pdev->dev; - gpio_vbus->phy.label = "gpio-vbus"; - gpio_vbus->phy.set_power = gpio_vbus_set_power; - gpio_vbus->phy.set_suspend = gpio_vbus_set_suspend; - gpio_vbus->phy.state = OTG_STATE_UNDEFINED; - - gpio_vbus->phy.otg->phy = &gpio_vbus->phy; - gpio_vbus->phy.otg->set_peripheral = gpio_vbus_set_peripheral; - - err = gpio_request(gpio, "vbus_detect"); - if (err) { - dev_err(&pdev->dev, "can't request vbus gpio %d, err: %d\n", - gpio, err); - goto err_gpio; - } - gpio_direction_input(gpio); - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (res) { - irq = res->start; - res->flags &= IRQF_TRIGGER_MASK; - res->flags |= IRQF_SAMPLE_RANDOM | IRQF_SHARED; - } else - irq = gpio_to_irq(gpio); - - /* if data line pullup is in use, initialize it to "not pulling up" */ - gpio = pdata->gpio_pullup; - if (gpio_is_valid(gpio)) { - err = gpio_request(gpio, "udc_pullup"); - if (err) { - dev_err(&pdev->dev, - "can't request pullup gpio %d, err: %d\n", - gpio, err); - gpio_free(pdata->gpio_vbus); - goto err_gpio; - } - gpio_direction_output(gpio, pdata->gpio_pullup_inverted); - } - - err = request_irq(irq, gpio_vbus_irq, VBUS_IRQ_FLAGS, - "vbus_detect", pdev); - if (err) { - dev_err(&pdev->dev, "can't request irq %i, err: %d\n", - irq, err); - goto err_irq; - } - - ATOMIC_INIT_NOTIFIER_HEAD(&gpio_vbus->phy.notifier); - - INIT_DELAYED_WORK(&gpio_vbus->work, gpio_vbus_work); - - gpio_vbus->vbus_draw = regulator_get(&pdev->dev, "vbus_draw"); - if (IS_ERR(gpio_vbus->vbus_draw)) { - dev_dbg(&pdev->dev, "can't get vbus_draw regulator, err: %ld\n", - PTR_ERR(gpio_vbus->vbus_draw)); - gpio_vbus->vbus_draw = NULL; - } - - /* only active when a gadget is registered */ - err = usb_set_transceiver(&gpio_vbus->phy); - if (err) { - dev_err(&pdev->dev, "can't register transceiver, err: %d\n", - err); - goto err_otg; - } - - return 0; -err_otg: - free_irq(irq, &pdev->dev); -err_irq: - if (gpio_is_valid(pdata->gpio_pullup)) - gpio_free(pdata->gpio_pullup); - gpio_free(pdata->gpio_vbus); -err_gpio: - platform_set_drvdata(pdev, NULL); - kfree(gpio_vbus->phy.otg); - kfree(gpio_vbus); - return err; -} - -static int __exit gpio_vbus_remove(struct platform_device *pdev) -{ - struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev); - struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data; - int gpio = pdata->gpio_vbus; - - regulator_put(gpio_vbus->vbus_draw); - - usb_set_transceiver(NULL); - - free_irq(gpio_to_irq(gpio), &pdev->dev); - if (gpio_is_valid(pdata->gpio_pullup)) - gpio_free(pdata->gpio_pullup); - gpio_free(gpio); - platform_set_drvdata(pdev, NULL); - kfree(gpio_vbus->phy.otg); - kfree(gpio_vbus); - - return 0; -} - -/* NOTE: the gpio-vbus device may *NOT* be hotplugged */ - -MODULE_ALIAS("platform:gpio-vbus"); - -static struct platform_driver gpio_vbus_driver = { - .driver = { - .name = "gpio-vbus", - .owner = THIS_MODULE, - }, - .remove = __exit_p(gpio_vbus_remove), -}; - -static int __init gpio_vbus_init(void) -{ - return platform_driver_probe(&gpio_vbus_driver, gpio_vbus_probe); -} -module_init(gpio_vbus_init); - -static void __exit gpio_vbus_exit(void) -{ - platform_driver_unregister(&gpio_vbus_driver); -} -module_exit(gpio_vbus_exit); - -MODULE_DESCRIPTION("simple GPIO controlled OTG transceiver driver"); -MODULE_AUTHOR("Philipp Zabel"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/otg/isp1301_omap.c b/ANDROID_3.4.5/drivers/usb/otg/isp1301_omap.c deleted file mode 100644 index 70cf5d7b..00000000 --- a/ANDROID_3.4.5/drivers/usb/otg/isp1301_omap.c +++ /dev/null @@ -1,1656 +0,0 @@ -/* - * isp1301_omap - ISP 1301 USB transceiver, talking to OMAP OTG controller - * - * Copyright (C) 2004 Texas Instruments - * Copyright (C) 2004 David Brownell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - - -#ifndef DEBUG -#undef VERBOSE -#endif - - -#define DRIVER_VERSION "24 August 2004" -#define DRIVER_NAME (isp1301_driver.driver.name) - -MODULE_DESCRIPTION("ISP1301 USB OTG Transceiver Driver"); -MODULE_LICENSE("GPL"); - -struct isp1301 { - struct usb_phy phy; - struct i2c_client *client; - void (*i2c_release)(struct device *dev); - - int irq_type; - - u32 last_otg_ctrl; - unsigned working:1; - - struct timer_list timer; - - /* use keventd context to change the state for us */ - struct work_struct work; - - unsigned long todo; -# define WORK_UPDATE_ISP 0 /* update ISP from OTG */ -# define WORK_UPDATE_OTG 1 /* update OTG from ISP */ -# define WORK_HOST_RESUME 4 /* resume host */ -# define WORK_TIMER 6 /* timer fired */ -# define WORK_STOP 7 /* don't resubmit */ -}; - - -/* bits in OTG_CTRL */ - -#define OTG_XCEIV_OUTPUTS \ - (OTG_ASESSVLD|OTG_BSESSEND|OTG_BSESSVLD|OTG_VBUSVLD|OTG_ID) -#define OTG_XCEIV_INPUTS \ - (OTG_PULLDOWN|OTG_PULLUP|OTG_DRV_VBUS|OTG_PD_VBUS|OTG_PU_VBUS|OTG_PU_ID) -#define OTG_CTRL_BITS \ - (OTG_A_BUSREQ|OTG_A_SETB_HNPEN|OTG_B_BUSREQ|OTG_B_HNPEN|OTG_BUSDROP) - /* and OTG_PULLUP is sometimes written */ - -#define OTG_CTRL_MASK (OTG_DRIVER_SEL| \ - OTG_XCEIV_OUTPUTS|OTG_XCEIV_INPUTS| \ - OTG_CTRL_BITS) - - -/*-------------------------------------------------------------------------*/ - -/* board-specific PM hooks */ - -#if defined(CONFIG_MACH_OMAP_H2) || defined(CONFIG_MACH_OMAP_H3) - -#if defined(CONFIG_TPS65010) || defined(CONFIG_TPS65010_MODULE) - -#include - -#else - -static inline int tps65010_set_vbus_draw(unsigned mA) -{ - pr_debug("tps65010: draw %d mA (STUB)\n", mA); - return 0; -} - -#endif - -static void enable_vbus_draw(struct isp1301 *isp, unsigned mA) -{ - int status = tps65010_set_vbus_draw(mA); - if (status < 0) - pr_debug(" VBUS %d mA error %d\n", mA, status); -} - -#else - -static void enable_vbus_draw(struct isp1301 *isp, unsigned mA) -{ - /* H4 controls this by DIP switch S2.4; no soft control. - * ON means the charger is always enabled. Leave it OFF - * unless the OTG port is used only in B-peripheral mode. - */ -} - -#endif - -static void enable_vbus_source(struct isp1301 *isp) -{ - /* this board won't supply more than 8mA vbus power. - * some boards can switch a 100ma "unit load" (or more). - */ -} - - -/* products will deliver OTG messages with LEDs, GUI, etc */ -static inline void notresponding(struct isp1301 *isp) -{ - printk(KERN_NOTICE "OTG device not responding.\n"); -} - - -/*-------------------------------------------------------------------------*/ - -static struct i2c_driver isp1301_driver; - -/* smbus apis are used for portability */ - -static inline u8 -isp1301_get_u8(struct isp1301 *isp, u8 reg) -{ - return i2c_smbus_read_byte_data(isp->client, reg + 0); -} - -static inline int -isp1301_get_u16(struct isp1301 *isp, u8 reg) -{ - return i2c_smbus_read_word_data(isp->client, reg); -} - -static inline int -isp1301_set_bits(struct isp1301 *isp, u8 reg, u8 bits) -{ - return i2c_smbus_write_byte_data(isp->client, reg + 0, bits); -} - -static inline int -isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits) -{ - return i2c_smbus_write_byte_data(isp->client, reg + 1, bits); -} - -/*-------------------------------------------------------------------------*/ - -/* identification */ -#define ISP1301_VENDOR_ID 0x00 /* u16 read */ -#define ISP1301_PRODUCT_ID 0x02 /* u16 read */ -#define ISP1301_BCD_DEVICE 0x14 /* u16 read */ - -#define I2C_VENDOR_ID_PHILIPS 0x04cc -#define I2C_PRODUCT_ID_PHILIPS_1301 0x1301 - -/* operational registers */ -#define ISP1301_MODE_CONTROL_1 0x04 /* u8 read, set, +1 clear */ -# define MC1_SPEED (1 << 0) -# define MC1_SUSPEND (1 << 1) -# define MC1_DAT_SE0 (1 << 2) -# define MC1_TRANSPARENT (1 << 3) -# define MC1_BDIS_ACON_EN (1 << 4) -# define MC1_OE_INT_EN (1 << 5) -# define MC1_UART_EN (1 << 6) -# define MC1_MASK 0x7f -#define ISP1301_MODE_CONTROL_2 0x12 /* u8 read, set, +1 clear */ -# define MC2_GLOBAL_PWR_DN (1 << 0) -# define MC2_SPD_SUSP_CTRL (1 << 1) -# define MC2_BI_DI (1 << 2) -# define MC2_TRANSP_BDIR0 (1 << 3) -# define MC2_TRANSP_BDIR1 (1 << 4) -# define MC2_AUDIO_EN (1 << 5) -# define MC2_PSW_EN (1 << 6) -# define MC2_EN2V7 (1 << 7) -#define ISP1301_OTG_CONTROL_1 0x06 /* u8 read, set, +1 clear */ -# define OTG1_DP_PULLUP (1 << 0) -# define OTG1_DM_PULLUP (1 << 1) -# define OTG1_DP_PULLDOWN (1 << 2) -# define OTG1_DM_PULLDOWN (1 << 3) -# define OTG1_ID_PULLDOWN (1 << 4) -# define OTG1_VBUS_DRV (1 << 5) -# define OTG1_VBUS_DISCHRG (1 << 6) -# define OTG1_VBUS_CHRG (1 << 7) -#define ISP1301_OTG_STATUS 0x10 /* u8 readonly */ -# define OTG_B_SESS_END (1 << 6) -# define OTG_B_SESS_VLD (1 << 7) - -#define ISP1301_INTERRUPT_SOURCE 0x08 /* u8 read */ -#define ISP1301_INTERRUPT_LATCH 0x0A /* u8 read, set, +1 clear */ - -#define ISP1301_INTERRUPT_FALLING 0x0C /* u8 read, set, +1 clear */ -#define ISP1301_INTERRUPT_RISING 0x0E /* u8 read, set, +1 clear */ - -/* same bitfields in all interrupt registers */ -# define INTR_VBUS_VLD (1 << 0) -# define INTR_SESS_VLD (1 << 1) -# define INTR_DP_HI (1 << 2) -# define INTR_ID_GND (1 << 3) -# define INTR_DM_HI (1 << 4) -# define INTR_ID_FLOAT (1 << 5) -# define INTR_BDIS_ACON (1 << 6) -# define INTR_CR_INT (1 << 7) - -/*-------------------------------------------------------------------------*/ - -static inline const char *state_name(struct isp1301 *isp) -{ - return otg_state_string(isp->phy.state); -} - -/*-------------------------------------------------------------------------*/ - -/* NOTE: some of this ISP1301 setup is specific to H2 boards; - * not everything is guarded by board-specific checks, or even using - * omap_usb_config data to deduce MC1_DAT_SE0 and MC2_BI_DI. - * - * ALSO: this currently doesn't use ISP1301 low-power modes - * while OTG is running. - */ - -static void power_down(struct isp1301 *isp) -{ - isp->phy.state = OTG_STATE_UNDEFINED; - - // isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN); - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND); - - isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_ID_PULLDOWN); - isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); -} - -static void power_up(struct isp1301 *isp) -{ - // isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN); - isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND); - - /* do this only when cpu is driving transceiver, - * so host won't see a low speed device... - */ - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); -} - -#define NO_HOST_SUSPEND - -static int host_suspend(struct isp1301 *isp) -{ -#ifdef NO_HOST_SUSPEND - return 0; -#else - struct device *dev; - - if (!isp->phy.otg->host) - return -ENODEV; - - /* Currently ASSUMES only the OTG port matters; - * other ports could be active... - */ - dev = isp->phy.otg->host->controller; - return dev->driver->suspend(dev, 3, 0); -#endif -} - -static int host_resume(struct isp1301 *isp) -{ -#ifdef NO_HOST_SUSPEND - return 0; -#else - struct device *dev; - - if (!isp->phy.otg->host) - return -ENODEV; - - dev = isp->phy.otg->host->controller; - return dev->driver->resume(dev, 0); -#endif -} - -static int gadget_suspend(struct isp1301 *isp) -{ - isp->phy.otg->gadget->b_hnp_enable = 0; - isp->phy.otg->gadget->a_hnp_support = 0; - isp->phy.otg->gadget->a_alt_hnp_support = 0; - return usb_gadget_vbus_disconnect(isp->phy.otg->gadget); -} - -/*-------------------------------------------------------------------------*/ - -#define TIMER_MINUTES 10 -#define TIMER_JIFFIES (TIMER_MINUTES * 60 * HZ) - -/* Almost all our I2C messaging comes from a work queue's task context. - * NOTE: guaranteeing certain response times might mean we shouldn't - * share keventd's work queue; a realtime task might be safest. - */ -static void isp1301_defer_work(struct isp1301 *isp, int work) -{ - int status; - - if (isp && !test_and_set_bit(work, &isp->todo)) { - (void) get_device(&isp->client->dev); - status = schedule_work(&isp->work); - if (!status && !isp->working) - dev_vdbg(&isp->client->dev, - "work item %d may be lost\n", work); - } -} - -/* called from irq handlers */ -static void a_idle(struct isp1301 *isp, const char *tag) -{ - u32 l; - - if (isp->phy.state == OTG_STATE_A_IDLE) - return; - - isp->phy.otg->default_a = 1; - if (isp->phy.otg->host) { - isp->phy.otg->host->is_b_host = 0; - host_suspend(isp); - } - if (isp->phy.otg->gadget) { - isp->phy.otg->gadget->is_a_peripheral = 1; - gadget_suspend(isp); - } - isp->phy.state = OTG_STATE_A_IDLE; - l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS; - omap_writel(l, OTG_CTRL); - isp->last_otg_ctrl = l; - pr_debug(" --> %s/%s\n", state_name(isp), tag); -} - -/* called from irq handlers */ -static void b_idle(struct isp1301 *isp, const char *tag) -{ - u32 l; - - if (isp->phy.state == OTG_STATE_B_IDLE) - return; - - isp->phy.otg->default_a = 0; - if (isp->phy.otg->host) { - isp->phy.otg->host->is_b_host = 1; - host_suspend(isp); - } - if (isp->phy.otg->gadget) { - isp->phy.otg->gadget->is_a_peripheral = 0; - gadget_suspend(isp); - } - isp->phy.state = OTG_STATE_B_IDLE; - l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS; - omap_writel(l, OTG_CTRL); - isp->last_otg_ctrl = l; - pr_debug(" --> %s/%s\n", state_name(isp), tag); -} - -static void -dump_regs(struct isp1301 *isp, const char *label) -{ -#ifdef DEBUG - u8 ctrl = isp1301_get_u8(isp, ISP1301_OTG_CONTROL_1); - u8 status = isp1301_get_u8(isp, ISP1301_OTG_STATUS); - u8 src = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE); - - pr_debug("otg: %06x, %s %s, otg/%02x stat/%02x.%02x\n", - omap_readl(OTG_CTRL), label, state_name(isp), - ctrl, status, src); - /* mode control and irq enables don't change much */ -#endif -} - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_USB_OTG - -/* - * The OMAP OTG controller handles most of the OTG state transitions. - * - * We translate isp1301 outputs (mostly voltage comparator status) into - * OTG inputs; OTG outputs (mostly pullup/pulldown controls) and HNP state - * flags into isp1301 inputs ... and infer state transitions. - */ - -#ifdef VERBOSE - -static void check_state(struct isp1301 *isp, const char *tag) -{ - enum usb_otg_state state = OTG_STATE_UNDEFINED; - u8 fsm = omap_readw(OTG_TEST) & 0x0ff; - unsigned extra = 0; - - switch (fsm) { - - /* default-b */ - case 0x0: - state = OTG_STATE_B_IDLE; - break; - case 0x3: - case 0x7: - extra = 1; - case 0x1: - state = OTG_STATE_B_PERIPHERAL; - break; - case 0x11: - state = OTG_STATE_B_SRP_INIT; - break; - - /* extra dual-role default-b states */ - case 0x12: - case 0x13: - case 0x16: - extra = 1; - case 0x17: - state = OTG_STATE_B_WAIT_ACON; - break; - case 0x34: - state = OTG_STATE_B_HOST; - break; - - /* default-a */ - case 0x36: - state = OTG_STATE_A_IDLE; - break; - case 0x3c: - state = OTG_STATE_A_WAIT_VFALL; - break; - case 0x7d: - state = OTG_STATE_A_VBUS_ERR; - break; - case 0x9e: - case 0x9f: - extra = 1; - case 0x89: - state = OTG_STATE_A_PERIPHERAL; - break; - case 0xb7: - state = OTG_STATE_A_WAIT_VRISE; - break; - case 0xb8: - state = OTG_STATE_A_WAIT_BCON; - break; - case 0xb9: - state = OTG_STATE_A_HOST; - break; - case 0xba: - state = OTG_STATE_A_SUSPEND; - break; - default: - break; - } - if (isp->phy.state == state && !extra) - return; - pr_debug("otg: %s FSM %s/%02x, %s, %06x\n", tag, - otg_state_string(state), fsm, state_name(isp), - omap_readl(OTG_CTRL)); -} - -#else - -static inline void check_state(struct isp1301 *isp, const char *tag) { } - -#endif - -/* outputs from ISP1301_INTERRUPT_SOURCE */ -static void update_otg1(struct isp1301 *isp, u8 int_src) -{ - u32 otg_ctrl; - - otg_ctrl = omap_readl(OTG_CTRL) & OTG_CTRL_MASK; - otg_ctrl &= ~OTG_XCEIV_INPUTS; - otg_ctrl &= ~(OTG_ID|OTG_ASESSVLD|OTG_VBUSVLD); - - if (int_src & INTR_SESS_VLD) - otg_ctrl |= OTG_ASESSVLD; - else if (isp->phy.state == OTG_STATE_A_WAIT_VFALL) { - a_idle(isp, "vfall"); - otg_ctrl &= ~OTG_CTRL_BITS; - } - if (int_src & INTR_VBUS_VLD) - otg_ctrl |= OTG_VBUSVLD; - if (int_src & INTR_ID_GND) { /* default-A */ - if (isp->phy.state == OTG_STATE_B_IDLE - || isp->phy.state - == OTG_STATE_UNDEFINED) { - a_idle(isp, "init"); - return; - } - } else { /* default-B */ - otg_ctrl |= OTG_ID; - if (isp->phy.state == OTG_STATE_A_IDLE - || isp->phy.state == OTG_STATE_UNDEFINED) { - b_idle(isp, "init"); - return; - } - } - omap_writel(otg_ctrl, OTG_CTRL); -} - -/* outputs from ISP1301_OTG_STATUS */ -static void update_otg2(struct isp1301 *isp, u8 otg_status) -{ - u32 otg_ctrl; - - otg_ctrl = omap_readl(OTG_CTRL) & OTG_CTRL_MASK; - otg_ctrl &= ~OTG_XCEIV_INPUTS; - otg_ctrl &= ~(OTG_BSESSVLD | OTG_BSESSEND); - if (otg_status & OTG_B_SESS_VLD) - otg_ctrl |= OTG_BSESSVLD; - else if (otg_status & OTG_B_SESS_END) - otg_ctrl |= OTG_BSESSEND; - omap_writel(otg_ctrl, OTG_CTRL); -} - -/* inputs going to ISP1301 */ -static void otg_update_isp(struct isp1301 *isp) -{ - u32 otg_ctrl, otg_change; - u8 set = OTG1_DM_PULLDOWN, clr = OTG1_DM_PULLUP; - - otg_ctrl = omap_readl(OTG_CTRL); - otg_change = otg_ctrl ^ isp->last_otg_ctrl; - isp->last_otg_ctrl = otg_ctrl; - otg_ctrl = otg_ctrl & OTG_XCEIV_INPUTS; - - switch (isp->phy.state) { - case OTG_STATE_B_IDLE: - case OTG_STATE_B_PERIPHERAL: - case OTG_STATE_B_SRP_INIT: - if (!(otg_ctrl & OTG_PULLUP)) { - // if (otg_ctrl & OTG_B_HNPEN) { - if (isp->phy.otg->gadget->b_hnp_enable) { - isp->phy.state = OTG_STATE_B_WAIT_ACON; - pr_debug(" --> b_wait_acon\n"); - } - goto pulldown; - } -pullup: - set |= OTG1_DP_PULLUP; - clr |= OTG1_DP_PULLDOWN; - break; - case OTG_STATE_A_SUSPEND: - case OTG_STATE_A_PERIPHERAL: - if (otg_ctrl & OTG_PULLUP) - goto pullup; - /* FALLTHROUGH */ - // case OTG_STATE_B_WAIT_ACON: - default: -pulldown: - set |= OTG1_DP_PULLDOWN; - clr |= OTG1_DP_PULLUP; - break; - } - -# define toggle(OTG,ISP) do { \ - if (otg_ctrl & OTG) set |= ISP; \ - else clr |= ISP; \ - } while (0) - - if (!(isp->phy.otg->host)) - otg_ctrl &= ~OTG_DRV_VBUS; - - switch (isp->phy.state) { - case OTG_STATE_A_SUSPEND: - if (otg_ctrl & OTG_DRV_VBUS) { - set |= OTG1_VBUS_DRV; - break; - } - /* HNP failed for some reason (A_AIDL_BDIS timeout) */ - notresponding(isp); - - /* FALLTHROUGH */ - case OTG_STATE_A_VBUS_ERR: - isp->phy.state = OTG_STATE_A_WAIT_VFALL; - pr_debug(" --> a_wait_vfall\n"); - /* FALLTHROUGH */ - case OTG_STATE_A_WAIT_VFALL: - /* FIXME usbcore thinks port power is still on ... */ - clr |= OTG1_VBUS_DRV; - break; - case OTG_STATE_A_IDLE: - if (otg_ctrl & OTG_DRV_VBUS) { - isp->phy.state = OTG_STATE_A_WAIT_VRISE; - pr_debug(" --> a_wait_vrise\n"); - } - /* FALLTHROUGH */ - default: - toggle(OTG_DRV_VBUS, OTG1_VBUS_DRV); - } - - toggle(OTG_PU_VBUS, OTG1_VBUS_CHRG); - toggle(OTG_PD_VBUS, OTG1_VBUS_DISCHRG); - -# undef toggle - - isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, set); - isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, clr); - - /* HNP switch to host or peripheral; and SRP */ - if (otg_change & OTG_PULLUP) { - u32 l; - - switch (isp->phy.state) { - case OTG_STATE_B_IDLE: - if (clr & OTG1_DP_PULLUP) - break; - isp->phy.state = OTG_STATE_B_PERIPHERAL; - pr_debug(" --> b_peripheral\n"); - break; - case OTG_STATE_A_SUSPEND: - if (clr & OTG1_DP_PULLUP) - break; - isp->phy.state = OTG_STATE_A_PERIPHERAL; - pr_debug(" --> a_peripheral\n"); - break; - default: - break; - } - l = omap_readl(OTG_CTRL); - l |= OTG_PULLUP; - omap_writel(l, OTG_CTRL); - } - - check_state(isp, __func__); - dump_regs(isp, "otg->isp1301"); -} - -static irqreturn_t omap_otg_irq(int irq, void *_isp) -{ - u16 otg_irq = omap_readw(OTG_IRQ_SRC); - u32 otg_ctrl; - int ret = IRQ_NONE; - struct isp1301 *isp = _isp; - struct usb_otg *otg = isp->phy.otg; - - /* update ISP1301 transceiver from OTG controller */ - if (otg_irq & OPRT_CHG) { - omap_writew(OPRT_CHG, OTG_IRQ_SRC); - isp1301_defer_work(isp, WORK_UPDATE_ISP); - ret = IRQ_HANDLED; - - /* SRP to become b_peripheral failed */ - } else if (otg_irq & B_SRP_TMROUT) { - pr_debug("otg: B_SRP_TIMEOUT, %06x\n", omap_readl(OTG_CTRL)); - notresponding(isp); - - /* gadget drivers that care should monitor all kinds of - * remote wakeup (SRP, normal) using their own timer - * to give "check cable and A-device" messages. - */ - if (isp->phy.state == OTG_STATE_B_SRP_INIT) - b_idle(isp, "srp_timeout"); - - omap_writew(B_SRP_TMROUT, OTG_IRQ_SRC); - ret = IRQ_HANDLED; - - /* HNP to become b_host failed */ - } else if (otg_irq & B_HNP_FAIL) { - pr_debug("otg: %s B_HNP_FAIL, %06x\n", - state_name(isp), omap_readl(OTG_CTRL)); - notresponding(isp); - - otg_ctrl = omap_readl(OTG_CTRL); - otg_ctrl |= OTG_BUSDROP; - otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; - omap_writel(otg_ctrl, OTG_CTRL); - - /* subset of b_peripheral()... */ - isp->phy.state = OTG_STATE_B_PERIPHERAL; - pr_debug(" --> b_peripheral\n"); - - omap_writew(B_HNP_FAIL, OTG_IRQ_SRC); - ret = IRQ_HANDLED; - - /* detect SRP from B-device ... */ - } else if (otg_irq & A_SRP_DETECT) { - pr_debug("otg: %s SRP_DETECT, %06x\n", - state_name(isp), omap_readl(OTG_CTRL)); - - isp1301_defer_work(isp, WORK_UPDATE_OTG); - switch (isp->phy.state) { - case OTG_STATE_A_IDLE: - if (!otg->host) - break; - isp1301_defer_work(isp, WORK_HOST_RESUME); - otg_ctrl = omap_readl(OTG_CTRL); - otg_ctrl |= OTG_A_BUSREQ; - otg_ctrl &= ~(OTG_BUSDROP|OTG_B_BUSREQ) - & ~OTG_XCEIV_INPUTS - & OTG_CTRL_MASK; - omap_writel(otg_ctrl, OTG_CTRL); - break; - default: - break; - } - - omap_writew(A_SRP_DETECT, OTG_IRQ_SRC); - ret = IRQ_HANDLED; - - /* timer expired: T(a_wait_bcon) and maybe T(a_wait_vrise) - * we don't track them separately - */ - } else if (otg_irq & A_REQ_TMROUT) { - otg_ctrl = omap_readl(OTG_CTRL); - pr_info("otg: BCON_TMOUT from %s, %06x\n", - state_name(isp), otg_ctrl); - notresponding(isp); - - otg_ctrl |= OTG_BUSDROP; - otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; - omap_writel(otg_ctrl, OTG_CTRL); - isp->phy.state = OTG_STATE_A_WAIT_VFALL; - - omap_writew(A_REQ_TMROUT, OTG_IRQ_SRC); - ret = IRQ_HANDLED; - - /* A-supplied voltage fell too low; overcurrent */ - } else if (otg_irq & A_VBUS_ERR) { - otg_ctrl = omap_readl(OTG_CTRL); - printk(KERN_ERR "otg: %s, VBUS_ERR %04x ctrl %06x\n", - state_name(isp), otg_irq, otg_ctrl); - - otg_ctrl |= OTG_BUSDROP; - otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; - omap_writel(otg_ctrl, OTG_CTRL); - isp->phy.state = OTG_STATE_A_VBUS_ERR; - - omap_writew(A_VBUS_ERR, OTG_IRQ_SRC); - ret = IRQ_HANDLED; - - /* switch driver; the transceiver code activates it, - * ungating the udc clock or resuming OHCI. - */ - } else if (otg_irq & DRIVER_SWITCH) { - int kick = 0; - - otg_ctrl = omap_readl(OTG_CTRL); - printk(KERN_NOTICE "otg: %s, SWITCH to %s, ctrl %06x\n", - state_name(isp), - (otg_ctrl & OTG_DRIVER_SEL) - ? "gadget" : "host", - otg_ctrl); - isp1301_defer_work(isp, WORK_UPDATE_ISP); - - /* role is peripheral */ - if (otg_ctrl & OTG_DRIVER_SEL) { - switch (isp->phy.state) { - case OTG_STATE_A_IDLE: - b_idle(isp, __func__); - break; - default: - break; - } - isp1301_defer_work(isp, WORK_UPDATE_ISP); - - /* role is host */ - } else { - if (!(otg_ctrl & OTG_ID)) { - otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS; - omap_writel(otg_ctrl | OTG_A_BUSREQ, OTG_CTRL); - } - - if (otg->host) { - switch (isp->phy.state) { - case OTG_STATE_B_WAIT_ACON: - isp->phy.state = OTG_STATE_B_HOST; - pr_debug(" --> b_host\n"); - kick = 1; - break; - case OTG_STATE_A_WAIT_BCON: - isp->phy.state = OTG_STATE_A_HOST; - pr_debug(" --> a_host\n"); - break; - case OTG_STATE_A_PERIPHERAL: - isp->phy.state = OTG_STATE_A_WAIT_BCON; - pr_debug(" --> a_wait_bcon\n"); - break; - default: - break; - } - isp1301_defer_work(isp, WORK_HOST_RESUME); - } - } - - omap_writew(DRIVER_SWITCH, OTG_IRQ_SRC); - ret = IRQ_HANDLED; - - if (kick) - usb_bus_start_enum(otg->host, otg->host->otg_port); - } - - check_state(isp, __func__); - return ret; -} - -static struct platform_device *otg_dev; - -static int isp1301_otg_init(struct isp1301 *isp) -{ - u32 l; - - if (!otg_dev) - return -ENODEV; - - dump_regs(isp, __func__); - /* some of these values are board-specific... */ - l = omap_readl(OTG_SYSCON_2); - l |= OTG_EN - /* for B-device: */ - | SRP_GPDATA /* 9msec Bdev D+ pulse */ - | SRP_GPDVBUS /* discharge after VBUS pulse */ - // | (3 << 24) /* 2msec VBUS pulse */ - /* for A-device: */ - | (0 << 20) /* 200ms nominal A_WAIT_VRISE timer */ - | SRP_DPW /* detect 167+ns SRP pulses */ - | SRP_DATA | SRP_VBUS /* accept both kinds of SRP pulse */ - ; - omap_writel(l, OTG_SYSCON_2); - - update_otg1(isp, isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE)); - update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS)); - - check_state(isp, __func__); - pr_debug("otg: %s, %s %06x\n", - state_name(isp), __func__, omap_readl(OTG_CTRL)); - - omap_writew(DRIVER_SWITCH | OPRT_CHG - | B_SRP_TMROUT | B_HNP_FAIL - | A_VBUS_ERR | A_SRP_DETECT | A_REQ_TMROUT, OTG_IRQ_EN); - - l = omap_readl(OTG_SYSCON_2); - l |= OTG_EN; - omap_writel(l, OTG_SYSCON_2); - - return 0; -} - -static int otg_probe(struct platform_device *dev) -{ - // struct omap_usb_config *config = dev->platform_data; - - otg_dev = dev; - return 0; -} - -static int otg_remove(struct platform_device *dev) -{ - otg_dev = NULL; - return 0; -} - -static struct platform_driver omap_otg_driver = { - .probe = otg_probe, - .remove = otg_remove, - .driver = { - .owner = THIS_MODULE, - .name = "omap_otg", - }, -}; - -static int otg_bind(struct isp1301 *isp) -{ - int status; - - if (otg_dev) - return -EBUSY; - - status = platform_driver_register(&omap_otg_driver); - if (status < 0) - return status; - - if (otg_dev) - status = request_irq(otg_dev->resource[1].start, omap_otg_irq, - 0, DRIVER_NAME, isp); - else - status = -ENODEV; - - if (status < 0) - platform_driver_unregister(&omap_otg_driver); - return status; -} - -static void otg_unbind(struct isp1301 *isp) -{ - if (!otg_dev) - return; - free_irq(otg_dev->resource[1].start, isp); -} - -#else - -/* OTG controller isn't clocked */ - -#endif /* CONFIG_USB_OTG */ - -/*-------------------------------------------------------------------------*/ - -static void b_peripheral(struct isp1301 *isp) -{ - u32 l; - - l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS; - omap_writel(l, OTG_CTRL); - - usb_gadget_vbus_connect(isp->phy.otg->gadget); - -#ifdef CONFIG_USB_OTG - enable_vbus_draw(isp, 8); - otg_update_isp(isp); -#else - enable_vbus_draw(isp, 100); - /* UDC driver just set OTG_BSESSVLD */ - isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLUP); - isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLDOWN); - isp->phy.state = OTG_STATE_B_PERIPHERAL; - pr_debug(" --> b_peripheral\n"); - dump_regs(isp, "2periph"); -#endif -} - -static void isp_update_otg(struct isp1301 *isp, u8 stat) -{ - struct usb_otg *otg = isp->phy.otg; - u8 isp_stat, isp_bstat; - enum usb_otg_state state = isp->phy.state; - - if (stat & INTR_BDIS_ACON) - pr_debug("OTG: BDIS_ACON, %s\n", state_name(isp)); - - /* start certain state transitions right away */ - isp_stat = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE); - if (isp_stat & INTR_ID_GND) { - if (otg->default_a) { - switch (state) { - case OTG_STATE_B_IDLE: - a_idle(isp, "idle"); - /* FALLTHROUGH */ - case OTG_STATE_A_IDLE: - enable_vbus_source(isp); - /* FALLTHROUGH */ - case OTG_STATE_A_WAIT_VRISE: - /* we skip over OTG_STATE_A_WAIT_BCON, since - * the HC will transition to A_HOST (or - * A_SUSPEND!) without our noticing except - * when HNP is used. - */ - if (isp_stat & INTR_VBUS_VLD) - isp->phy.state = OTG_STATE_A_HOST; - break; - case OTG_STATE_A_WAIT_VFALL: - if (!(isp_stat & INTR_SESS_VLD)) - a_idle(isp, "vfell"); - break; - default: - if (!(isp_stat & INTR_VBUS_VLD)) - isp->phy.state = OTG_STATE_A_VBUS_ERR; - break; - } - isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS); - } else { - switch (state) { - case OTG_STATE_B_PERIPHERAL: - case OTG_STATE_B_HOST: - case OTG_STATE_B_WAIT_ACON: - usb_gadget_vbus_disconnect(otg->gadget); - break; - default: - break; - } - if (state != OTG_STATE_A_IDLE) - a_idle(isp, "id"); - if (otg->host && state == OTG_STATE_A_IDLE) - isp1301_defer_work(isp, WORK_HOST_RESUME); - isp_bstat = 0; - } - } else { - u32 l; - - /* if user unplugged mini-A end of cable, - * don't bypass A_WAIT_VFALL. - */ - if (otg->default_a) { - switch (state) { - default: - isp->phy.state = OTG_STATE_A_WAIT_VFALL; - break; - case OTG_STATE_A_WAIT_VFALL: - state = OTG_STATE_A_IDLE; - /* khubd may take a while to notice and - * handle this disconnect, so don't go - * to B_IDLE quite yet. - */ - break; - case OTG_STATE_A_IDLE: - host_suspend(isp); - isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, - MC1_BDIS_ACON_EN); - isp->phy.state = OTG_STATE_B_IDLE; - l = omap_readl(OTG_CTRL) & OTG_CTRL_MASK; - l &= ~OTG_CTRL_BITS; - omap_writel(l, OTG_CTRL); - break; - case OTG_STATE_B_IDLE: - break; - } - } - isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS); - - switch (isp->phy.state) { - case OTG_STATE_B_PERIPHERAL: - case OTG_STATE_B_WAIT_ACON: - case OTG_STATE_B_HOST: - if (likely(isp_bstat & OTG_B_SESS_VLD)) - break; - enable_vbus_draw(isp, 0); -#ifndef CONFIG_USB_OTG - /* UDC driver will clear OTG_BSESSVLD */ - isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, - OTG1_DP_PULLDOWN); - isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, - OTG1_DP_PULLUP); - dump_regs(isp, __func__); -#endif - /* FALLTHROUGH */ - case OTG_STATE_B_SRP_INIT: - b_idle(isp, __func__); - l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS; - omap_writel(l, OTG_CTRL); - /* FALLTHROUGH */ - case OTG_STATE_B_IDLE: - if (otg->gadget && (isp_bstat & OTG_B_SESS_VLD)) { -#ifdef CONFIG_USB_OTG - update_otg1(isp, isp_stat); - update_otg2(isp, isp_bstat); -#endif - b_peripheral(isp); - } else if (!(isp_stat & (INTR_VBUS_VLD|INTR_SESS_VLD))) - isp_bstat |= OTG_B_SESS_END; - break; - case OTG_STATE_A_WAIT_VFALL: - break; - default: - pr_debug("otg: unsupported b-device %s\n", - state_name(isp)); - break; - } - } - - if (state != isp->phy.state) - pr_debug(" isp, %s -> %s\n", - otg_state_string(state), state_name(isp)); - -#ifdef CONFIG_USB_OTG - /* update the OTG controller state to match the isp1301; may - * trigger OPRT_CHG irqs for changes going to the isp1301. - */ - update_otg1(isp, isp_stat); - update_otg2(isp, isp_bstat); - check_state(isp, __func__); -#endif - - dump_regs(isp, "isp1301->otg"); -} - -/*-------------------------------------------------------------------------*/ - -static u8 isp1301_clear_latch(struct isp1301 *isp) -{ - u8 latch = isp1301_get_u8(isp, ISP1301_INTERRUPT_LATCH); - isp1301_clear_bits(isp, ISP1301_INTERRUPT_LATCH, latch); - return latch; -} - -static void -isp1301_work(struct work_struct *work) -{ - struct isp1301 *isp = container_of(work, struct isp1301, work); - int stop; - - /* implicit lock: we're the only task using this device */ - isp->working = 1; - do { - stop = test_bit(WORK_STOP, &isp->todo); - -#ifdef CONFIG_USB_OTG - /* transfer state from otg engine to isp1301 */ - if (test_and_clear_bit(WORK_UPDATE_ISP, &isp->todo)) { - otg_update_isp(isp); - put_device(&isp->client->dev); - } -#endif - /* transfer state from isp1301 to otg engine */ - if (test_and_clear_bit(WORK_UPDATE_OTG, &isp->todo)) { - u8 stat = isp1301_clear_latch(isp); - - isp_update_otg(isp, stat); - put_device(&isp->client->dev); - } - - if (test_and_clear_bit(WORK_HOST_RESUME, &isp->todo)) { - u32 otg_ctrl; - - /* - * skip A_WAIT_VRISE; hc transitions invisibly - * skip A_WAIT_BCON; same. - */ - switch (isp->phy.state) { - case OTG_STATE_A_WAIT_BCON: - case OTG_STATE_A_WAIT_VRISE: - isp->phy.state = OTG_STATE_A_HOST; - pr_debug(" --> a_host\n"); - otg_ctrl = omap_readl(OTG_CTRL); - otg_ctrl |= OTG_A_BUSREQ; - otg_ctrl &= ~(OTG_BUSDROP|OTG_B_BUSREQ) - & OTG_CTRL_MASK; - omap_writel(otg_ctrl, OTG_CTRL); - break; - case OTG_STATE_B_WAIT_ACON: - isp->phy.state = OTG_STATE_B_HOST; - pr_debug(" --> b_host (acon)\n"); - break; - case OTG_STATE_B_HOST: - case OTG_STATE_B_IDLE: - case OTG_STATE_A_IDLE: - break; - default: - pr_debug(" host resume in %s\n", - state_name(isp)); - } - host_resume(isp); - // mdelay(10); - put_device(&isp->client->dev); - } - - if (test_and_clear_bit(WORK_TIMER, &isp->todo)) { -#ifdef VERBOSE - dump_regs(isp, "timer"); - if (!stop) - mod_timer(&isp->timer, jiffies + TIMER_JIFFIES); -#endif - put_device(&isp->client->dev); - } - - if (isp->todo) - dev_vdbg(&isp->client->dev, - "work done, todo = 0x%lx\n", - isp->todo); - if (stop) { - dev_dbg(&isp->client->dev, "stop\n"); - break; - } - } while (isp->todo); - isp->working = 0; -} - -static irqreturn_t isp1301_irq(int irq, void *isp) -{ - isp1301_defer_work(isp, WORK_UPDATE_OTG); - return IRQ_HANDLED; -} - -static void isp1301_timer(unsigned long _isp) -{ - isp1301_defer_work((void *)_isp, WORK_TIMER); -} - -/*-------------------------------------------------------------------------*/ - -static void isp1301_release(struct device *dev) -{ - struct isp1301 *isp; - - isp = dev_get_drvdata(dev); - - /* FIXME -- not with a "new style" driver, it doesn't!! */ - - /* ugly -- i2c hijacks our memory hook to wait_for_completion() */ - if (isp->i2c_release) - isp->i2c_release(dev); - kfree(isp->phy.otg); - kfree (isp); -} - -static struct isp1301 *the_transceiver; - -static int __exit isp1301_remove(struct i2c_client *i2c) -{ - struct isp1301 *isp; - - isp = i2c_get_clientdata(i2c); - - isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0); - isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0); - free_irq(i2c->irq, isp); -#ifdef CONFIG_USB_OTG - otg_unbind(isp); -#endif - if (machine_is_omap_h2()) - gpio_free(2); - - isp->timer.data = 0; - set_bit(WORK_STOP, &isp->todo); - del_timer_sync(&isp->timer); - flush_work_sync(&isp->work); - - put_device(&i2c->dev); - the_transceiver = NULL; - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* NOTE: three modes are possible here, only one of which - * will be standards-conformant on any given system: - * - * - OTG mode (dual-role), required if there's a Mini-AB connector - * - HOST mode, for when there's one or more A (host) connectors - * - DEVICE mode, for when there's a B/Mini-B (device) connector - * - * As a rule, you won't have an isp1301 chip unless it's there to - * support the OTG mode. Other modes help testing USB controllers - * in isolation from (full) OTG support, or maybe so later board - * revisions can help to support those feature. - */ - -#ifdef CONFIG_USB_OTG - -static int isp1301_otg_enable(struct isp1301 *isp) -{ - power_up(isp); - isp1301_otg_init(isp); - - /* NOTE: since we don't change this, this provides - * a few more interrupts than are strictly needed. - */ - isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING, - INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND); - isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING, - INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND); - - dev_info(&isp->client->dev, "ready for dual-role USB ...\n"); - - return 0; -} - -#endif - -/* add or disable the host device+driver */ -static int -isp1301_set_host(struct usb_otg *otg, struct usb_bus *host) -{ - struct isp1301 *isp = container_of(otg->phy, struct isp1301, phy); - - if (!otg || isp != the_transceiver) - return -ENODEV; - - if (!host) { - omap_writew(0, OTG_IRQ_EN); - power_down(isp); - otg->host = NULL; - return 0; - } - -#ifdef CONFIG_USB_OTG - otg->host = host; - dev_dbg(&isp->client->dev, "registered host\n"); - host_suspend(isp); - if (otg->gadget) - return isp1301_otg_enable(isp); - return 0; - -#elif !defined(CONFIG_USB_GADGET_OMAP) - // FIXME update its refcount - otg->host = host; - - power_up(isp); - - if (machine_is_omap_h2()) - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); - - dev_info(&isp->client->dev, "A-Host sessions ok\n"); - isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING, - INTR_ID_GND); - isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING, - INTR_ID_GND); - - /* If this has a Mini-AB connector, this mode is highly - * nonstandard ... but can be handy for testing, especially with - * the Mini-A end of an OTG cable. (Or something nonstandard - * like MiniB-to-StandardB, maybe built with a gender mender.) - */ - isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_VBUS_DRV); - - dump_regs(isp, __func__); - - return 0; - -#else - dev_dbg(&isp->client->dev, "host sessions not allowed\n"); - return -EINVAL; -#endif - -} - -static int -isp1301_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) -{ - struct isp1301 *isp = container_of(otg->phy, struct isp1301, phy); -#ifndef CONFIG_USB_OTG - u32 l; -#endif - - if (!otg || isp != the_transceiver) - return -ENODEV; - - if (!gadget) { - omap_writew(0, OTG_IRQ_EN); - if (!otg->default_a) - enable_vbus_draw(isp, 0); - usb_gadget_vbus_disconnect(otg->gadget); - otg->gadget = NULL; - power_down(isp); - return 0; - } - -#ifdef CONFIG_USB_OTG - otg->gadget = gadget; - dev_dbg(&isp->client->dev, "registered gadget\n"); - /* gadget driver may be suspended until vbus_connect () */ - if (otg->host) - return isp1301_otg_enable(isp); - return 0; - -#elif !defined(CONFIG_USB_OHCI_HCD) && !defined(CONFIG_USB_OHCI_HCD_MODULE) - otg->gadget = gadget; - // FIXME update its refcount - - l = omap_readl(OTG_CTRL) & OTG_CTRL_MASK; - l &= ~(OTG_XCEIV_OUTPUTS|OTG_CTRL_BITS); - l |= OTG_ID; - omap_writel(l, OTG_CTRL); - - power_up(isp); - isp->phy.state = OTG_STATE_B_IDLE; - - if (machine_is_omap_h2() || machine_is_omap_h3()) - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0); - - isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING, - INTR_SESS_VLD); - isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING, - INTR_VBUS_VLD); - dev_info(&isp->client->dev, "B-Peripheral sessions ok\n"); - dump_regs(isp, __func__); - - /* If this has a Mini-AB connector, this mode is highly - * nonstandard ... but can be handy for testing, so long - * as you don't plug a Mini-A cable into the jack. - */ - if (isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE) & INTR_VBUS_VLD) - b_peripheral(isp); - - return 0; - -#else - dev_dbg(&isp->client->dev, "peripheral sessions not allowed\n"); - return -EINVAL; -#endif -} - - -/*-------------------------------------------------------------------------*/ - -static int -isp1301_set_power(struct usb_phy *dev, unsigned mA) -{ - if (!the_transceiver) - return -ENODEV; - if (dev->state == OTG_STATE_B_PERIPHERAL) - enable_vbus_draw(the_transceiver, mA); - return 0; -} - -static int -isp1301_start_srp(struct usb_otg *otg) -{ - struct isp1301 *isp = container_of(otg->phy, struct isp1301, phy); - u32 otg_ctrl; - - if (!otg || isp != the_transceiver - || isp->phy.state != OTG_STATE_B_IDLE) - return -ENODEV; - - otg_ctrl = omap_readl(OTG_CTRL); - if (!(otg_ctrl & OTG_BSESSEND)) - return -EINVAL; - - otg_ctrl |= OTG_B_BUSREQ; - otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK; - omap_writel(otg_ctrl, OTG_CTRL); - isp->phy.state = OTG_STATE_B_SRP_INIT; - - pr_debug("otg: SRP, %s ... %06x\n", state_name(isp), - omap_readl(OTG_CTRL)); -#ifdef CONFIG_USB_OTG - check_state(isp, __func__); -#endif - return 0; -} - -static int -isp1301_start_hnp(struct usb_otg *otg) -{ -#ifdef CONFIG_USB_OTG - struct isp1301 *isp = container_of(otg->phy, struct isp1301, phy); - u32 l; - - if (!otg || isp != the_transceiver) - return -ENODEV; - if (otg->default_a && (otg->host == NULL || !otg->host->b_hnp_enable)) - return -ENOTCONN; - if (!otg->default_a && (otg->gadget == NULL - || !otg->gadget->b_hnp_enable)) - return -ENOTCONN; - - /* We want hardware to manage most HNP protocol timings. - * So do this part as early as possible... - */ - switch (isp->phy.state) { - case OTG_STATE_B_HOST: - isp->phy.state = OTG_STATE_B_PERIPHERAL; - /* caller will suspend next */ - break; - case OTG_STATE_A_HOST: -#if 0 - /* autoconnect mode avoids irq latency bugs */ - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, - MC1_BDIS_ACON_EN); -#endif - /* caller must suspend then clear A_BUSREQ */ - usb_gadget_vbus_connect(otg->gadget); - l = omap_readl(OTG_CTRL); - l |= OTG_A_SETB_HNPEN; - omap_writel(l, OTG_CTRL); - - break; - case OTG_STATE_A_PERIPHERAL: - /* initiated by B-Host suspend */ - break; - default: - return -EILSEQ; - } - pr_debug("otg: HNP %s, %06x ...\n", - state_name(isp), omap_readl(OTG_CTRL)); - check_state(isp, __func__); - return 0; -#else - /* srp-only */ - return -EINVAL; -#endif -} - -/*-------------------------------------------------------------------------*/ - -static int __devinit -isp1301_probe(struct i2c_client *i2c, const struct i2c_device_id *id) -{ - int status; - struct isp1301 *isp; - - if (the_transceiver) - return 0; - - isp = kzalloc(sizeof *isp, GFP_KERNEL); - if (!isp) - return 0; - - isp->phy.otg = kzalloc(sizeof *isp->phy.otg, GFP_KERNEL); - if (!isp->phy.otg) { - kfree(isp); - return 0; - } - - INIT_WORK(&isp->work, isp1301_work); - init_timer(&isp->timer); - isp->timer.function = isp1301_timer; - isp->timer.data = (unsigned long) isp; - - i2c_set_clientdata(i2c, isp); - isp->client = i2c; - - /* verify the chip (shouldn't be necessary) */ - status = isp1301_get_u16(isp, ISP1301_VENDOR_ID); - if (status != I2C_VENDOR_ID_PHILIPS) { - dev_dbg(&i2c->dev, "not philips id: %d\n", status); - goto fail; - } - status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID); - if (status != I2C_PRODUCT_ID_PHILIPS_1301) { - dev_dbg(&i2c->dev, "not isp1301, %d\n", status); - goto fail; - } - isp->i2c_release = i2c->dev.release; - i2c->dev.release = isp1301_release; - - /* initial development used chiprev 2.00 */ - status = i2c_smbus_read_word_data(i2c, ISP1301_BCD_DEVICE); - dev_info(&i2c->dev, "chiprev %x.%02x, driver " DRIVER_VERSION "\n", - status >> 8, status & 0xff); - - /* make like power-on reset */ - isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_MASK); - - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, MC2_BI_DI); - isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, ~MC2_BI_DI); - - isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, - OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN); - isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, - ~(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN)); - - isp1301_clear_bits(isp, ISP1301_INTERRUPT_LATCH, ~0); - isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0); - isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0); - -#ifdef CONFIG_USB_OTG - status = otg_bind(isp); - if (status < 0) { - dev_dbg(&i2c->dev, "can't bind OTG\n"); - goto fail; - } -#endif - - if (machine_is_omap_h2()) { - /* full speed signaling by default */ - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, - MC1_SPEED); - isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, - MC2_SPD_SUSP_CTRL); - - /* IRQ wired at M14 */ - omap_cfg_reg(M14_1510_GPIO2); - if (gpio_request(2, "isp1301") == 0) - gpio_direction_input(2); - isp->irq_type = IRQF_TRIGGER_FALLING; - } - - isp->irq_type |= IRQF_SAMPLE_RANDOM; - status = request_irq(i2c->irq, isp1301_irq, - isp->irq_type, DRIVER_NAME, isp); - if (status < 0) { - dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n", - i2c->irq, status); - goto fail; - } - - isp->phy.dev = &i2c->dev; - isp->phy.label = DRIVER_NAME; - isp->phy.set_power = isp1301_set_power, - - isp->phy.otg->phy = &isp->phy; - isp->phy.otg->set_host = isp1301_set_host, - isp->phy.otg->set_peripheral = isp1301_set_peripheral, - isp->phy.otg->start_srp = isp1301_start_srp, - isp->phy.otg->start_hnp = isp1301_start_hnp, - - enable_vbus_draw(isp, 0); - power_down(isp); - the_transceiver = isp; - -#ifdef CONFIG_USB_OTG - update_otg1(isp, isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE)); - update_otg2(isp, isp1301_get_u8(isp, ISP1301_OTG_STATUS)); -#endif - - dump_regs(isp, __func__); - -#ifdef VERBOSE - mod_timer(&isp->timer, jiffies + TIMER_JIFFIES); - dev_dbg(&i2c->dev, "scheduled timer, %d min\n", TIMER_MINUTES); -#endif - - status = usb_set_transceiver(&isp->phy); - if (status < 0) - dev_err(&i2c->dev, "can't register transceiver, %d\n", - status); - - return 0; - -fail: - kfree(isp->phy.otg); - kfree(isp); - return -ENODEV; -} - -static const struct i2c_device_id isp1301_id[] = { - { "isp1301_omap", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, isp1301_id); - -static struct i2c_driver isp1301_driver = { - .driver = { - .name = "isp1301_omap", - }, - .probe = isp1301_probe, - .remove = __exit_p(isp1301_remove), - .id_table = isp1301_id, -}; - -/*-------------------------------------------------------------------------*/ - -static int __init isp_init(void) -{ - return i2c_add_driver(&isp1301_driver); -} -subsys_initcall(isp_init); - -static void __exit isp_exit(void) -{ - if (the_transceiver) - usb_set_transceiver(NULL); - i2c_del_driver(&isp1301_driver); -} -module_exit(isp_exit); - diff --git a/ANDROID_3.4.5/drivers/usb/otg/msm_otg.c b/ANDROID_3.4.5/drivers/usb/otg/msm_otg.c deleted file mode 100644 index 1d0347c2..00000000 --- a/ANDROID_3.4.5/drivers/usb/otg/msm_otg.c +++ /dev/null @@ -1,1773 +0,0 @@ -/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define MSM_USB_BASE (motg->regs) -#define DRIVER_NAME "msm_otg" - -#define ULPI_IO_TIMEOUT_USEC (10 * 1000) - -#define USB_PHY_3P3_VOL_MIN 3050000 /* uV */ -#define USB_PHY_3P3_VOL_MAX 3300000 /* uV */ -#define USB_PHY_3P3_HPM_LOAD 50000 /* uA */ -#define USB_PHY_3P3_LPM_LOAD 4000 /* uA */ - -#define USB_PHY_1P8_VOL_MIN 1800000 /* uV */ -#define USB_PHY_1P8_VOL_MAX 1800000 /* uV */ -#define USB_PHY_1P8_HPM_LOAD 50000 /* uA */ -#define USB_PHY_1P8_LPM_LOAD 4000 /* uA */ - -#define USB_PHY_VDD_DIG_VOL_MIN 1000000 /* uV */ -#define USB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */ - -static struct regulator *hsusb_3p3; -static struct regulator *hsusb_1p8; -static struct regulator *hsusb_vddcx; - -static int msm_hsusb_init_vddcx(struct msm_otg *motg, int init) -{ - int ret = 0; - - if (init) { - hsusb_vddcx = regulator_get(motg->phy.dev, "HSUSB_VDDCX"); - if (IS_ERR(hsusb_vddcx)) { - dev_err(motg->phy.dev, "unable to get hsusb vddcx\n"); - return PTR_ERR(hsusb_vddcx); - } - - ret = regulator_set_voltage(hsusb_vddcx, - USB_PHY_VDD_DIG_VOL_MIN, - USB_PHY_VDD_DIG_VOL_MAX); - if (ret) { - dev_err(motg->phy.dev, "unable to set the voltage " - "for hsusb vddcx\n"); - regulator_put(hsusb_vddcx); - return ret; - } - - ret = regulator_enable(hsusb_vddcx); - if (ret) { - dev_err(motg->phy.dev, "unable to enable hsusb vddcx\n"); - regulator_put(hsusb_vddcx); - } - } else { - ret = regulator_set_voltage(hsusb_vddcx, 0, - USB_PHY_VDD_DIG_VOL_MAX); - if (ret) - dev_err(motg->phy.dev, "unable to set the voltage " - "for hsusb vddcx\n"); - ret = regulator_disable(hsusb_vddcx); - if (ret) - dev_err(motg->phy.dev, "unable to disable hsusb vddcx\n"); - - regulator_put(hsusb_vddcx); - } - - return ret; -} - -static int msm_hsusb_ldo_init(struct msm_otg *motg, int init) -{ - int rc = 0; - - if (init) { - hsusb_3p3 = regulator_get(motg->phy.dev, "HSUSB_3p3"); - if (IS_ERR(hsusb_3p3)) { - dev_err(motg->phy.dev, "unable to get hsusb 3p3\n"); - return PTR_ERR(hsusb_3p3); - } - - rc = regulator_set_voltage(hsusb_3p3, USB_PHY_3P3_VOL_MIN, - USB_PHY_3P3_VOL_MAX); - if (rc) { - dev_err(motg->phy.dev, "unable to set voltage level " - "for hsusb 3p3\n"); - goto put_3p3; - } - rc = regulator_enable(hsusb_3p3); - if (rc) { - dev_err(motg->phy.dev, "unable to enable the hsusb 3p3\n"); - goto put_3p3; - } - hsusb_1p8 = regulator_get(motg->phy.dev, "HSUSB_1p8"); - if (IS_ERR(hsusb_1p8)) { - dev_err(motg->phy.dev, "unable to get hsusb 1p8\n"); - rc = PTR_ERR(hsusb_1p8); - goto disable_3p3; - } - rc = regulator_set_voltage(hsusb_1p8, USB_PHY_1P8_VOL_MIN, - USB_PHY_1P8_VOL_MAX); - if (rc) { - dev_err(motg->phy.dev, "unable to set voltage level " - "for hsusb 1p8\n"); - goto put_1p8; - } - rc = regulator_enable(hsusb_1p8); - if (rc) { - dev_err(motg->phy.dev, "unable to enable the hsusb 1p8\n"); - goto put_1p8; - } - - return 0; - } - - regulator_disable(hsusb_1p8); -put_1p8: - regulator_put(hsusb_1p8); -disable_3p3: - regulator_disable(hsusb_3p3); -put_3p3: - regulator_put(hsusb_3p3); - return rc; -} - -#ifdef CONFIG_PM_SLEEP -#define USB_PHY_SUSP_DIG_VOL 500000 -static int msm_hsusb_config_vddcx(int high) -{ - int max_vol = USB_PHY_VDD_DIG_VOL_MAX; - int min_vol; - int ret; - - if (high) - min_vol = USB_PHY_VDD_DIG_VOL_MIN; - else - min_vol = USB_PHY_SUSP_DIG_VOL; - - ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol); - if (ret) { - pr_err("%s: unable to set the voltage for regulator " - "HSUSB_VDDCX\n", __func__); - return ret; - } - - pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol); - - return ret; -} -#endif - -static int msm_hsusb_ldo_set_mode(int on) -{ - int ret = 0; - - if (!hsusb_1p8 || IS_ERR(hsusb_1p8)) { - pr_err("%s: HSUSB_1p8 is not initialized\n", __func__); - return -ENODEV; - } - - if (!hsusb_3p3 || IS_ERR(hsusb_3p3)) { - pr_err("%s: HSUSB_3p3 is not initialized\n", __func__); - return -ENODEV; - } - - if (on) { - ret = regulator_set_optimum_mode(hsusb_1p8, - USB_PHY_1P8_HPM_LOAD); - if (ret < 0) { - pr_err("%s: Unable to set HPM of the regulator " - "HSUSB_1p8\n", __func__); - return ret; - } - ret = regulator_set_optimum_mode(hsusb_3p3, - USB_PHY_3P3_HPM_LOAD); - if (ret < 0) { - pr_err("%s: Unable to set HPM of the regulator " - "HSUSB_3p3\n", __func__); - regulator_set_optimum_mode(hsusb_1p8, - USB_PHY_1P8_LPM_LOAD); - return ret; - } - } else { - ret = regulator_set_optimum_mode(hsusb_1p8, - USB_PHY_1P8_LPM_LOAD); - if (ret < 0) - pr_err("%s: Unable to set LPM of the regulator " - "HSUSB_1p8\n", __func__); - ret = regulator_set_optimum_mode(hsusb_3p3, - USB_PHY_3P3_LPM_LOAD); - if (ret < 0) - pr_err("%s: Unable to set LPM of the regulator " - "HSUSB_3p3\n", __func__); - } - - pr_debug("reg (%s)\n", on ? "HPM" : "LPM"); - return ret < 0 ? ret : 0; -} - -static int ulpi_read(struct usb_phy *phy, u32 reg) -{ - struct msm_otg *motg = container_of(phy, struct msm_otg, phy); - int cnt = 0; - - /* initiate read operation */ - writel(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg), - USB_ULPI_VIEWPORT); - - /* wait for completion */ - while (cnt < ULPI_IO_TIMEOUT_USEC) { - if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN)) - break; - udelay(1); - cnt++; - } - - if (cnt >= ULPI_IO_TIMEOUT_USEC) { - dev_err(phy->dev, "ulpi_read: timeout %08x\n", - readl(USB_ULPI_VIEWPORT)); - return -ETIMEDOUT; - } - return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT)); -} - -static int ulpi_write(struct usb_phy *phy, u32 val, u32 reg) -{ - struct msm_otg *motg = container_of(phy, struct msm_otg, phy); - int cnt = 0; - - /* initiate write operation */ - writel(ULPI_RUN | ULPI_WRITE | - ULPI_ADDR(reg) | ULPI_DATA(val), - USB_ULPI_VIEWPORT); - - /* wait for completion */ - while (cnt < ULPI_IO_TIMEOUT_USEC) { - if (!(readl(USB_ULPI_VIEWPORT) & ULPI_RUN)) - break; - udelay(1); - cnt++; - } - - if (cnt >= ULPI_IO_TIMEOUT_USEC) { - dev_err(phy->dev, "ulpi_write: timeout\n"); - return -ETIMEDOUT; - } - return 0; -} - -static struct usb_phy_io_ops msm_otg_io_ops = { - .read = ulpi_read, - .write = ulpi_write, -}; - -static void ulpi_init(struct msm_otg *motg) -{ - struct msm_otg_platform_data *pdata = motg->pdata; - int *seq = pdata->phy_init_seq; - - if (!seq) - return; - - while (seq[0] >= 0) { - dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n", - seq[0], seq[1]); - ulpi_write(&motg->phy, seq[0], seq[1]); - seq += 2; - } -} - -static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert) -{ - int ret; - - if (assert) { - ret = clk_reset(motg->clk, CLK_RESET_ASSERT); - if (ret) - dev_err(motg->phy.dev, "usb hs_clk assert failed\n"); - } else { - ret = clk_reset(motg->clk, CLK_RESET_DEASSERT); - if (ret) - dev_err(motg->phy.dev, "usb hs_clk deassert failed\n"); - } - return ret; -} - -static int msm_otg_phy_clk_reset(struct msm_otg *motg) -{ - int ret; - - ret = clk_reset(motg->phy_reset_clk, CLK_RESET_ASSERT); - if (ret) { - dev_err(motg->phy.dev, "usb phy clk assert failed\n"); - return ret; - } - usleep_range(10000, 12000); - ret = clk_reset(motg->phy_reset_clk, CLK_RESET_DEASSERT); - if (ret) - dev_err(motg->phy.dev, "usb phy clk deassert failed\n"); - return ret; -} - -static int msm_otg_phy_reset(struct msm_otg *motg) -{ - u32 val; - int ret; - int retries; - - ret = msm_otg_link_clk_reset(motg, 1); - if (ret) - return ret; - ret = msm_otg_phy_clk_reset(motg); - if (ret) - return ret; - ret = msm_otg_link_clk_reset(motg, 0); - if (ret) - return ret; - - val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK; - writel(val | PORTSC_PTS_ULPI, USB_PORTSC); - - for (retries = 3; retries > 0; retries--) { - ret = ulpi_write(&motg->phy, ULPI_FUNC_CTRL_SUSPENDM, - ULPI_CLR(ULPI_FUNC_CTRL)); - if (!ret) - break; - ret = msm_otg_phy_clk_reset(motg); - if (ret) - return ret; - } - if (!retries) - return -ETIMEDOUT; - - /* This reset calibrates the phy, if the above write succeeded */ - ret = msm_otg_phy_clk_reset(motg); - if (ret) - return ret; - - for (retries = 3; retries > 0; retries--) { - ret = ulpi_read(&motg->phy, ULPI_DEBUG); - if (ret != -ETIMEDOUT) - break; - ret = msm_otg_phy_clk_reset(motg); - if (ret) - return ret; - } - if (!retries) - return -ETIMEDOUT; - - dev_info(motg->phy.dev, "phy_reset: success\n"); - return 0; -} - -#define LINK_RESET_TIMEOUT_USEC (250 * 1000) -static int msm_otg_reset(struct usb_phy *phy) -{ - struct msm_otg *motg = container_of(phy, struct msm_otg, phy); - struct msm_otg_platform_data *pdata = motg->pdata; - int cnt = 0; - int ret; - u32 val = 0; - u32 ulpi_val = 0; - - ret = msm_otg_phy_reset(motg); - if (ret) { - dev_err(phy->dev, "phy_reset failed\n"); - return ret; - } - - ulpi_init(motg); - - writel(USBCMD_RESET, USB_USBCMD); - while (cnt < LINK_RESET_TIMEOUT_USEC) { - if (!(readl(USB_USBCMD) & USBCMD_RESET)) - break; - udelay(1); - cnt++; - } - if (cnt >= LINK_RESET_TIMEOUT_USEC) - return -ETIMEDOUT; - - /* select ULPI phy */ - writel(0x80000000, USB_PORTSC); - - msleep(100); - - writel(0x0, USB_AHBBURST); - writel(0x00, USB_AHBMODE); - - if (pdata->otg_control == OTG_PHY_CONTROL) { - val = readl(USB_OTGSC); - if (pdata->mode == USB_OTG) { - ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID; - val |= OTGSC_IDIE | OTGSC_BSVIE; - } else if (pdata->mode == USB_PERIPHERAL) { - ulpi_val = ULPI_INT_SESS_VALID; - val |= OTGSC_BSVIE; - } - writel(val, USB_OTGSC); - ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_RISE); - ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL); - } - - return 0; -} - -#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000) -#define PHY_RESUME_TIMEOUT_USEC (100 * 1000) - -#ifdef CONFIG_PM_SLEEP -static int msm_otg_suspend(struct msm_otg *motg) -{ - struct usb_phy *phy = &motg->phy; - struct usb_bus *bus = phy->otg->host; - struct msm_otg_platform_data *pdata = motg->pdata; - int cnt = 0; - - if (atomic_read(&motg->in_lpm)) - return 0; - - disable_irq(motg->irq); - /* - * Chipidea 45-nm PHY suspend sequence: - * - * Interrupt Latch Register auto-clear feature is not present - * in all PHY versions. Latch register is clear on read type. - * Clear latch register to avoid spurious wakeup from - * low power mode (LPM). - * - * PHY comparators are disabled when PHY enters into low power - * mode (LPM). Keep PHY comparators ON in LPM only when we expect - * VBUS/Id notifications from USB PHY. Otherwise turn off USB - * PHY comparators. This save significant amount of power. - * - * PLL is not turned off when PHY enters into low power mode (LPM). - * Disable PLL for maximum power savings. - */ - - if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY) { - ulpi_read(phy, 0x14); - if (pdata->otg_control == OTG_PHY_CONTROL) - ulpi_write(phy, 0x01, 0x30); - ulpi_write(phy, 0x08, 0x09); - } - - /* - * PHY may take some time or even fail to enter into low power - * mode (LPM). Hence poll for 500 msec and reset the PHY and link - * in failure case. - */ - writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC); - while (cnt < PHY_SUSPEND_TIMEOUT_USEC) { - if (readl(USB_PORTSC) & PORTSC_PHCD) - break; - udelay(1); - cnt++; - } - - if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) { - dev_err(phy->dev, "Unable to suspend PHY\n"); - msm_otg_reset(phy); - enable_irq(motg->irq); - return -ETIMEDOUT; - } - - /* - * PHY has capability to generate interrupt asynchronously in low - * power mode (LPM). This interrupt is level triggered. So USB IRQ - * line must be disabled till async interrupt enable bit is cleared - * in USBCMD register. Assert STP (ULPI interface STOP signal) to - * block data communication from PHY. - */ - writel(readl(USB_USBCMD) | ASYNC_INTR_CTRL | ULPI_STP_CTRL, USB_USBCMD); - - if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY && - motg->pdata->otg_control == OTG_PMIC_CONTROL) - writel(readl(USB_PHY_CTRL) | PHY_RETEN, USB_PHY_CTRL); - - clk_disable(motg->pclk); - clk_disable(motg->clk); - if (motg->core_clk) - clk_disable(motg->core_clk); - - if (!IS_ERR(motg->pclk_src)) - clk_disable(motg->pclk_src); - - if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY && - motg->pdata->otg_control == OTG_PMIC_CONTROL) { - msm_hsusb_ldo_set_mode(0); - msm_hsusb_config_vddcx(0); - } - - if (device_may_wakeup(phy->dev)) - enable_irq_wake(motg->irq); - if (bus) - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags); - - atomic_set(&motg->in_lpm, 1); - enable_irq(motg->irq); - - dev_info(phy->dev, "USB in low power mode\n"); - - return 0; -} - -static int msm_otg_resume(struct msm_otg *motg) -{ - struct usb_phy *phy = &motg->phy; - struct usb_bus *bus = phy->otg->host; - int cnt = 0; - unsigned temp; - - if (!atomic_read(&motg->in_lpm)) - return 0; - - if (!IS_ERR(motg->pclk_src)) - clk_enable(motg->pclk_src); - - clk_enable(motg->pclk); - clk_enable(motg->clk); - if (motg->core_clk) - clk_enable(motg->core_clk); - - if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY && - motg->pdata->otg_control == OTG_PMIC_CONTROL) { - msm_hsusb_ldo_set_mode(1); - msm_hsusb_config_vddcx(1); - writel(readl(USB_PHY_CTRL) & ~PHY_RETEN, USB_PHY_CTRL); - } - - temp = readl(USB_USBCMD); - temp &= ~ASYNC_INTR_CTRL; - temp &= ~ULPI_STP_CTRL; - writel(temp, USB_USBCMD); - - /* - * PHY comes out of low power mode (LPM) in case of wakeup - * from asynchronous interrupt. - */ - if (!(readl(USB_PORTSC) & PORTSC_PHCD)) - goto skip_phy_resume; - - writel(readl(USB_PORTSC) & ~PORTSC_PHCD, USB_PORTSC); - while (cnt < PHY_RESUME_TIMEOUT_USEC) { - if (!(readl(USB_PORTSC) & PORTSC_PHCD)) - break; - udelay(1); - cnt++; - } - - if (cnt >= PHY_RESUME_TIMEOUT_USEC) { - /* - * This is a fatal error. Reset the link and - * PHY. USB state can not be restored. Re-insertion - * of USB cable is the only way to get USB working. - */ - dev_err(phy->dev, "Unable to resume USB." - "Re-plugin the cable\n"); - msm_otg_reset(phy); - } - -skip_phy_resume: - if (device_may_wakeup(phy->dev)) - disable_irq_wake(motg->irq); - if (bus) - set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags); - - atomic_set(&motg->in_lpm, 0); - - if (motg->async_int) { - motg->async_int = 0; - pm_runtime_put(phy->dev); - enable_irq(motg->irq); - } - - dev_info(phy->dev, "USB exited from low power mode\n"); - - return 0; -} -#endif - -static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA) -{ - if (motg->cur_power == mA) - return; - - /* TODO: Notify PMIC about available current */ - dev_info(motg->phy.dev, "Avail curr from USB = %u\n", mA); - motg->cur_power = mA; -} - -static int msm_otg_set_power(struct usb_phy *phy, unsigned mA) -{ - struct msm_otg *motg = container_of(phy, struct msm_otg, phy); - - /* - * Gadget driver uses set_power method to notify about the - * available current based on suspend/configured states. - * - * IDEV_CHG can be drawn irrespective of suspend/un-configured - * states when CDP/ACA is connected. - */ - if (motg->chg_type == USB_SDP_CHARGER) - msm_otg_notify_charger(motg, mA); - - return 0; -} - -static void msm_otg_start_host(struct usb_phy *phy, int on) -{ - struct msm_otg *motg = container_of(phy, struct msm_otg, phy); - struct msm_otg_platform_data *pdata = motg->pdata; - struct usb_hcd *hcd; - - if (!phy->otg->host) - return; - - hcd = bus_to_hcd(phy->otg->host); - - if (on) { - dev_dbg(phy->dev, "host on\n"); - - if (pdata->vbus_power) - pdata->vbus_power(1); - /* - * Some boards have a switch cotrolled by gpio - * to enable/disable internal HUB. Enable internal - * HUB before kicking the host. - */ - if (pdata->setup_gpio) - pdata->setup_gpio(OTG_STATE_A_HOST); -#ifdef CONFIG_USB - usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); -#endif - } else { - dev_dbg(phy->dev, "host off\n"); - -#ifdef CONFIG_USB - usb_remove_hcd(hcd); -#endif - if (pdata->setup_gpio) - pdata->setup_gpio(OTG_STATE_UNDEFINED); - if (pdata->vbus_power) - pdata->vbus_power(0); - } -} - -static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host) -{ - struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy); - struct usb_hcd *hcd; - - /* - * Fail host registration if this board can support - * only peripheral configuration. - */ - if (motg->pdata->mode == USB_PERIPHERAL) { - dev_info(otg->phy->dev, "Host mode is not supported\n"); - return -ENODEV; - } - - if (!host) { - if (otg->phy->state == OTG_STATE_A_HOST) { - pm_runtime_get_sync(otg->phy->dev); - msm_otg_start_host(otg->phy, 0); - otg->host = NULL; - otg->phy->state = OTG_STATE_UNDEFINED; - schedule_work(&motg->sm_work); - } else { - otg->host = NULL; - } - - return 0; - } - - hcd = bus_to_hcd(host); - hcd->power_budget = motg->pdata->power_budget; - - otg->host = host; - dev_dbg(otg->phy->dev, "host driver registered w/ tranceiver\n"); - - /* - * Kick the state machine work, if peripheral is not supported - * or peripheral is already registered with us. - */ - if (motg->pdata->mode == USB_HOST || otg->gadget) { - pm_runtime_get_sync(otg->phy->dev); - schedule_work(&motg->sm_work); - } - - return 0; -} - -static void msm_otg_start_peripheral(struct usb_phy *phy, int on) -{ - struct msm_otg *motg = container_of(phy, struct msm_otg, phy); - struct msm_otg_platform_data *pdata = motg->pdata; - - if (!phy->otg->gadget) - return; - - if (on) { - dev_dbg(phy->dev, "gadget on\n"); - /* - * Some boards have a switch cotrolled by gpio - * to enable/disable internal HUB. Disable internal - * HUB before kicking the gadget. - */ - if (pdata->setup_gpio) - pdata->setup_gpio(OTG_STATE_B_PERIPHERAL); - usb_gadget_vbus_connect(phy->otg->gadget); - } else { - dev_dbg(phy->dev, "gadget off\n"); - usb_gadget_vbus_disconnect(phy->otg->gadget); - if (pdata->setup_gpio) - pdata->setup_gpio(OTG_STATE_UNDEFINED); - } - -} - -static int msm_otg_set_peripheral(struct usb_otg *otg, - struct usb_gadget *gadget) -{ - struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy); - - /* - * Fail peripheral registration if this board can support - * only host configuration. - */ - if (motg->pdata->mode == USB_HOST) { - dev_info(otg->phy->dev, "Peripheral mode is not supported\n"); - return -ENODEV; - } - - if (!gadget) { - if (otg->phy->state == OTG_STATE_B_PERIPHERAL) { - pm_runtime_get_sync(otg->phy->dev); - msm_otg_start_peripheral(otg->phy, 0); - otg->gadget = NULL; - otg->phy->state = OTG_STATE_UNDEFINED; - schedule_work(&motg->sm_work); - } else { - otg->gadget = NULL; - } - - return 0; - } - otg->gadget = gadget; - dev_dbg(otg->phy->dev, "peripheral driver registered w/ tranceiver\n"); - - /* - * Kick the state machine work, if host is not supported - * or host is already registered with us. - */ - if (motg->pdata->mode == USB_PERIPHERAL || otg->host) { - pm_runtime_get_sync(otg->phy->dev); - schedule_work(&motg->sm_work); - } - - return 0; -} - -static bool msm_chg_check_secondary_det(struct msm_otg *motg) -{ - struct usb_phy *phy = &motg->phy; - u32 chg_det; - bool ret = false; - - switch (motg->pdata->phy_type) { - case CI_45NM_INTEGRATED_PHY: - chg_det = ulpi_read(phy, 0x34); - ret = chg_det & (1 << 4); - break; - case SNPS_28NM_INTEGRATED_PHY: - chg_det = ulpi_read(phy, 0x87); - ret = chg_det & 1; - break; - default: - break; - } - return ret; -} - -static void msm_chg_enable_secondary_det(struct msm_otg *motg) -{ - struct usb_phy *phy = &motg->phy; - u32 chg_det; - - switch (motg->pdata->phy_type) { - case CI_45NM_INTEGRATED_PHY: - chg_det = ulpi_read(phy, 0x34); - /* Turn off charger block */ - chg_det |= ~(1 << 1); - ulpi_write(phy, chg_det, 0x34); - udelay(20); - /* control chg block via ULPI */ - chg_det &= ~(1 << 3); - ulpi_write(phy, chg_det, 0x34); - /* put it in host mode for enabling D- source */ - chg_det &= ~(1 << 2); - ulpi_write(phy, chg_det, 0x34); - /* Turn on chg detect block */ - chg_det &= ~(1 << 1); - ulpi_write(phy, chg_det, 0x34); - udelay(20); - /* enable chg detection */ - chg_det &= ~(1 << 0); - ulpi_write(phy, chg_det, 0x34); - break; - case SNPS_28NM_INTEGRATED_PHY: - /* - * Configure DM as current source, DP as current sink - * and enable battery charging comparators. - */ - ulpi_write(phy, 0x8, 0x85); - ulpi_write(phy, 0x2, 0x85); - ulpi_write(phy, 0x1, 0x85); - break; - default: - break; - } -} - -static bool msm_chg_check_primary_det(struct msm_otg *motg) -{ - struct usb_phy *phy = &motg->phy; - u32 chg_det; - bool ret = false; - - switch (motg->pdata->phy_type) { - case CI_45NM_INTEGRATED_PHY: - chg_det = ulpi_read(phy, 0x34); - ret = chg_det & (1 << 4); - break; - case SNPS_28NM_INTEGRATED_PHY: - chg_det = ulpi_read(phy, 0x87); - ret = chg_det & 1; - break; - default: - break; - } - return ret; -} - -static void msm_chg_enable_primary_det(struct msm_otg *motg) -{ - struct usb_phy *phy = &motg->phy; - u32 chg_det; - - switch (motg->pdata->phy_type) { - case CI_45NM_INTEGRATED_PHY: - chg_det = ulpi_read(phy, 0x34); - /* enable chg detection */ - chg_det &= ~(1 << 0); - ulpi_write(phy, chg_det, 0x34); - break; - case SNPS_28NM_INTEGRATED_PHY: - /* - * Configure DP as current source, DM as current sink - * and enable battery charging comparators. - */ - ulpi_write(phy, 0x2, 0x85); - ulpi_write(phy, 0x1, 0x85); - break; - default: - break; - } -} - -static bool msm_chg_check_dcd(struct msm_otg *motg) -{ - struct usb_phy *phy = &motg->phy; - u32 line_state; - bool ret = false; - - switch (motg->pdata->phy_type) { - case CI_45NM_INTEGRATED_PHY: - line_state = ulpi_read(phy, 0x15); - ret = !(line_state & 1); - break; - case SNPS_28NM_INTEGRATED_PHY: - line_state = ulpi_read(phy, 0x87); - ret = line_state & 2; - break; - default: - break; - } - return ret; -} - -static void msm_chg_disable_dcd(struct msm_otg *motg) -{ - struct usb_phy *phy = &motg->phy; - u32 chg_det; - - switch (motg->pdata->phy_type) { - case CI_45NM_INTEGRATED_PHY: - chg_det = ulpi_read(phy, 0x34); - chg_det &= ~(1 << 5); - ulpi_write(phy, chg_det, 0x34); - break; - case SNPS_28NM_INTEGRATED_PHY: - ulpi_write(phy, 0x10, 0x86); - break; - default: - break; - } -} - -static void msm_chg_enable_dcd(struct msm_otg *motg) -{ - struct usb_phy *phy = &motg->phy; - u32 chg_det; - - switch (motg->pdata->phy_type) { - case CI_45NM_INTEGRATED_PHY: - chg_det = ulpi_read(phy, 0x34); - /* Turn on D+ current source */ - chg_det |= (1 << 5); - ulpi_write(phy, chg_det, 0x34); - break; - case SNPS_28NM_INTEGRATED_PHY: - /* Data contact detection enable */ - ulpi_write(phy, 0x10, 0x85); - break; - default: - break; - } -} - -static void msm_chg_block_on(struct msm_otg *motg) -{ - struct usb_phy *phy = &motg->phy; - u32 func_ctrl, chg_det; - - /* put the controller in non-driving mode */ - func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL); - func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK; - func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING; - ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL); - - switch (motg->pdata->phy_type) { - case CI_45NM_INTEGRATED_PHY: - chg_det = ulpi_read(phy, 0x34); - /* control chg block via ULPI */ - chg_det &= ~(1 << 3); - ulpi_write(phy, chg_det, 0x34); - /* Turn on chg detect block */ - chg_det &= ~(1 << 1); - ulpi_write(phy, chg_det, 0x34); - udelay(20); - break; - case SNPS_28NM_INTEGRATED_PHY: - /* Clear charger detecting control bits */ - ulpi_write(phy, 0x3F, 0x86); - /* Clear alt interrupt latch and enable bits */ - ulpi_write(phy, 0x1F, 0x92); - ulpi_write(phy, 0x1F, 0x95); - udelay(100); - break; - default: - break; - } -} - -static void msm_chg_block_off(struct msm_otg *motg) -{ - struct usb_phy *phy = &motg->phy; - u32 func_ctrl, chg_det; - - switch (motg->pdata->phy_type) { - case CI_45NM_INTEGRATED_PHY: - chg_det = ulpi_read(phy, 0x34); - /* Turn off charger block */ - chg_det |= ~(1 << 1); - ulpi_write(phy, chg_det, 0x34); - break; - case SNPS_28NM_INTEGRATED_PHY: - /* Clear charger detecting control bits */ - ulpi_write(phy, 0x3F, 0x86); - /* Clear alt interrupt latch and enable bits */ - ulpi_write(phy, 0x1F, 0x92); - ulpi_write(phy, 0x1F, 0x95); - break; - default: - break; - } - - /* put the controller in normal mode */ - func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL); - func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK; - func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL; - ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL); -} - -#define MSM_CHG_DCD_POLL_TIME (100 * HZ/1000) /* 100 msec */ -#define MSM_CHG_DCD_MAX_RETRIES 6 /* Tdcd_tmout = 6 * 100 msec */ -#define MSM_CHG_PRIMARY_DET_TIME (40 * HZ/1000) /* TVDPSRC_ON */ -#define MSM_CHG_SECONDARY_DET_TIME (40 * HZ/1000) /* TVDMSRC_ON */ -static void msm_chg_detect_work(struct work_struct *w) -{ - struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work); - struct usb_phy *phy = &motg->phy; - bool is_dcd, tmout, vout; - unsigned long delay; - - dev_dbg(phy->dev, "chg detection work\n"); - switch (motg->chg_state) { - case USB_CHG_STATE_UNDEFINED: - pm_runtime_get_sync(phy->dev); - msm_chg_block_on(motg); - msm_chg_enable_dcd(motg); - motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD; - motg->dcd_retries = 0; - delay = MSM_CHG_DCD_POLL_TIME; - break; - case USB_CHG_STATE_WAIT_FOR_DCD: - is_dcd = msm_chg_check_dcd(motg); - tmout = ++motg->dcd_retries == MSM_CHG_DCD_MAX_RETRIES; - if (is_dcd || tmout) { - msm_chg_disable_dcd(motg); - msm_chg_enable_primary_det(motg); - delay = MSM_CHG_PRIMARY_DET_TIME; - motg->chg_state = USB_CHG_STATE_DCD_DONE; - } else { - delay = MSM_CHG_DCD_POLL_TIME; - } - break; - case USB_CHG_STATE_DCD_DONE: - vout = msm_chg_check_primary_det(motg); - if (vout) { - msm_chg_enable_secondary_det(motg); - delay = MSM_CHG_SECONDARY_DET_TIME; - motg->chg_state = USB_CHG_STATE_PRIMARY_DONE; - } else { - motg->chg_type = USB_SDP_CHARGER; - motg->chg_state = USB_CHG_STATE_DETECTED; - delay = 0; - } - break; - case USB_CHG_STATE_PRIMARY_DONE: - vout = msm_chg_check_secondary_det(motg); - if (vout) - motg->chg_type = USB_DCP_CHARGER; - else - motg->chg_type = USB_CDP_CHARGER; - motg->chg_state = USB_CHG_STATE_SECONDARY_DONE; - /* fall through */ - case USB_CHG_STATE_SECONDARY_DONE: - motg->chg_state = USB_CHG_STATE_DETECTED; - case USB_CHG_STATE_DETECTED: - msm_chg_block_off(motg); - dev_dbg(phy->dev, "charger = %d\n", motg->chg_type); - schedule_work(&motg->sm_work); - return; - default: - return; - } - - schedule_delayed_work(&motg->chg_work, delay); -} - -/* - * We support OTG, Peripheral only and Host only configurations. In case - * of OTG, mode switch (host-->peripheral/peripheral-->host) can happen - * via Id pin status or user request (debugfs). Id/BSV interrupts are not - * enabled when switch is controlled by user and default mode is supplied - * by board file, which can be changed by userspace later. - */ -static void msm_otg_init_sm(struct msm_otg *motg) -{ - struct msm_otg_platform_data *pdata = motg->pdata; - u32 otgsc = readl(USB_OTGSC); - - switch (pdata->mode) { - case USB_OTG: - if (pdata->otg_control == OTG_PHY_CONTROL) { - if (otgsc & OTGSC_ID) - set_bit(ID, &motg->inputs); - else - clear_bit(ID, &motg->inputs); - - if (otgsc & OTGSC_BSV) - set_bit(B_SESS_VLD, &motg->inputs); - else - clear_bit(B_SESS_VLD, &motg->inputs); - } else if (pdata->otg_control == OTG_USER_CONTROL) { - if (pdata->default_mode == USB_HOST) { - clear_bit(ID, &motg->inputs); - } else if (pdata->default_mode == USB_PERIPHERAL) { - set_bit(ID, &motg->inputs); - set_bit(B_SESS_VLD, &motg->inputs); - } else { - set_bit(ID, &motg->inputs); - clear_bit(B_SESS_VLD, &motg->inputs); - } - } - break; - case USB_HOST: - clear_bit(ID, &motg->inputs); - break; - case USB_PERIPHERAL: - set_bit(ID, &motg->inputs); - if (otgsc & OTGSC_BSV) - set_bit(B_SESS_VLD, &motg->inputs); - else - clear_bit(B_SESS_VLD, &motg->inputs); - break; - default: - break; - } -} - -static void msm_otg_sm_work(struct work_struct *w) -{ - struct msm_otg *motg = container_of(w, struct msm_otg, sm_work); - struct usb_otg *otg = motg->phy.otg; - - switch (otg->phy->state) { - case OTG_STATE_UNDEFINED: - dev_dbg(otg->phy->dev, "OTG_STATE_UNDEFINED state\n"); - msm_otg_reset(otg->phy); - msm_otg_init_sm(motg); - otg->phy->state = OTG_STATE_B_IDLE; - /* FALL THROUGH */ - case OTG_STATE_B_IDLE: - dev_dbg(otg->phy->dev, "OTG_STATE_B_IDLE state\n"); - if (!test_bit(ID, &motg->inputs) && otg->host) { - /* disable BSV bit */ - writel(readl(USB_OTGSC) & ~OTGSC_BSVIE, USB_OTGSC); - msm_otg_start_host(otg->phy, 1); - otg->phy->state = OTG_STATE_A_HOST; - } else if (test_bit(B_SESS_VLD, &motg->inputs)) { - switch (motg->chg_state) { - case USB_CHG_STATE_UNDEFINED: - msm_chg_detect_work(&motg->chg_work.work); - break; - case USB_CHG_STATE_DETECTED: - switch (motg->chg_type) { - case USB_DCP_CHARGER: - msm_otg_notify_charger(motg, - IDEV_CHG_MAX); - break; - case USB_CDP_CHARGER: - msm_otg_notify_charger(motg, - IDEV_CHG_MAX); - msm_otg_start_peripheral(otg->phy, 1); - otg->phy->state - = OTG_STATE_B_PERIPHERAL; - break; - case USB_SDP_CHARGER: - msm_otg_notify_charger(motg, IUNIT); - msm_otg_start_peripheral(otg->phy, 1); - otg->phy->state - = OTG_STATE_B_PERIPHERAL; - break; - default: - break; - } - break; - default: - break; - } - } else { - /* - * If charger detection work is pending, decrement - * the pm usage counter to balance with the one that - * is incremented in charger detection work. - */ - if (cancel_delayed_work_sync(&motg->chg_work)) { - pm_runtime_put_sync(otg->phy->dev); - msm_otg_reset(otg->phy); - } - msm_otg_notify_charger(motg, 0); - motg->chg_state = USB_CHG_STATE_UNDEFINED; - motg->chg_type = USB_INVALID_CHARGER; - } - pm_runtime_put_sync(otg->phy->dev); - break; - case OTG_STATE_B_PERIPHERAL: - dev_dbg(otg->phy->dev, "OTG_STATE_B_PERIPHERAL state\n"); - if (!test_bit(B_SESS_VLD, &motg->inputs) || - !test_bit(ID, &motg->inputs)) { - msm_otg_notify_charger(motg, 0); - msm_otg_start_peripheral(otg->phy, 0); - motg->chg_state = USB_CHG_STATE_UNDEFINED; - motg->chg_type = USB_INVALID_CHARGER; - otg->phy->state = OTG_STATE_B_IDLE; - msm_otg_reset(otg->phy); - schedule_work(w); - } - break; - case OTG_STATE_A_HOST: - dev_dbg(otg->phy->dev, "OTG_STATE_A_HOST state\n"); - if (test_bit(ID, &motg->inputs)) { - msm_otg_start_host(otg->phy, 0); - otg->phy->state = OTG_STATE_B_IDLE; - msm_otg_reset(otg->phy); - schedule_work(w); - } - break; - default: - break; - } -} - -static irqreturn_t msm_otg_irq(int irq, void *data) -{ - struct msm_otg *motg = data; - struct usb_phy *phy = &motg->phy; - u32 otgsc = 0; - - if (atomic_read(&motg->in_lpm)) { - disable_irq_nosync(irq); - motg->async_int = 1; - pm_runtime_get(phy->dev); - return IRQ_HANDLED; - } - - otgsc = readl(USB_OTGSC); - if (!(otgsc & (OTGSC_IDIS | OTGSC_BSVIS))) - return IRQ_NONE; - - if ((otgsc & OTGSC_IDIS) && (otgsc & OTGSC_IDIE)) { - if (otgsc & OTGSC_ID) - set_bit(ID, &motg->inputs); - else - clear_bit(ID, &motg->inputs); - dev_dbg(phy->dev, "ID set/clear\n"); - pm_runtime_get_noresume(phy->dev); - } else if ((otgsc & OTGSC_BSVIS) && (otgsc & OTGSC_BSVIE)) { - if (otgsc & OTGSC_BSV) - set_bit(B_SESS_VLD, &motg->inputs); - else - clear_bit(B_SESS_VLD, &motg->inputs); - dev_dbg(phy->dev, "BSV set/clear\n"); - pm_runtime_get_noresume(phy->dev); - } - - writel(otgsc, USB_OTGSC); - schedule_work(&motg->sm_work); - return IRQ_HANDLED; -} - -static int msm_otg_mode_show(struct seq_file *s, void *unused) -{ - struct msm_otg *motg = s->private; - struct usb_otg *otg = motg->phy.otg; - - switch (otg->phy->state) { - case OTG_STATE_A_HOST: - seq_printf(s, "host\n"); - break; - case OTG_STATE_B_PERIPHERAL: - seq_printf(s, "peripheral\n"); - break; - default: - seq_printf(s, "none\n"); - break; - } - - return 0; -} - -static int msm_otg_mode_open(struct inode *inode, struct file *file) -{ - return single_open(file, msm_otg_mode_show, inode->i_private); -} - -static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf, - size_t count, loff_t *ppos) -{ - struct seq_file *s = file->private_data; - struct msm_otg *motg = s->private; - char buf[16]; - struct usb_otg *otg = motg->phy.otg; - int status = count; - enum usb_mode_type req_mode; - - memset(buf, 0x00, sizeof(buf)); - - if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) { - status = -EFAULT; - goto out; - } - - if (!strncmp(buf, "host", 4)) { - req_mode = USB_HOST; - } else if (!strncmp(buf, "peripheral", 10)) { - req_mode = USB_PERIPHERAL; - } else if (!strncmp(buf, "none", 4)) { - req_mode = USB_NONE; - } else { - status = -EINVAL; - goto out; - } - - switch (req_mode) { - case USB_NONE: - switch (otg->phy->state) { - case OTG_STATE_A_HOST: - case OTG_STATE_B_PERIPHERAL: - set_bit(ID, &motg->inputs); - clear_bit(B_SESS_VLD, &motg->inputs); - break; - default: - goto out; - } - break; - case USB_PERIPHERAL: - switch (otg->phy->state) { - case OTG_STATE_B_IDLE: - case OTG_STATE_A_HOST: - set_bit(ID, &motg->inputs); - set_bit(B_SESS_VLD, &motg->inputs); - break; - default: - goto out; - } - break; - case USB_HOST: - switch (otg->phy->state) { - case OTG_STATE_B_IDLE: - case OTG_STATE_B_PERIPHERAL: - clear_bit(ID, &motg->inputs); - break; - default: - goto out; - } - break; - default: - goto out; - } - - pm_runtime_get_sync(otg->phy->dev); - schedule_work(&motg->sm_work); -out: - return status; -} - -const struct file_operations msm_otg_mode_fops = { - .open = msm_otg_mode_open, - .read = seq_read, - .write = msm_otg_mode_write, - .llseek = seq_lseek, - .release = single_release, -}; - -static struct dentry *msm_otg_dbg_root; -static struct dentry *msm_otg_dbg_mode; - -static int msm_otg_debugfs_init(struct msm_otg *motg) -{ - msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL); - - if (!msm_otg_dbg_root || IS_ERR(msm_otg_dbg_root)) - return -ENODEV; - - msm_otg_dbg_mode = debugfs_create_file("mode", S_IRUGO | S_IWUSR, - msm_otg_dbg_root, motg, &msm_otg_mode_fops); - if (!msm_otg_dbg_mode) { - debugfs_remove(msm_otg_dbg_root); - msm_otg_dbg_root = NULL; - return -ENODEV; - } - - return 0; -} - -static void msm_otg_debugfs_cleanup(void) -{ - debugfs_remove(msm_otg_dbg_mode); - debugfs_remove(msm_otg_dbg_root); -} - -static int __init msm_otg_probe(struct platform_device *pdev) -{ - int ret = 0; - struct resource *res; - struct msm_otg *motg; - struct usb_phy *phy; - - dev_info(&pdev->dev, "msm_otg probe\n"); - if (!pdev->dev.platform_data) { - dev_err(&pdev->dev, "No platform data given. Bailing out\n"); - return -ENODEV; - } - - motg = kzalloc(sizeof(struct msm_otg), GFP_KERNEL); - if (!motg) { - dev_err(&pdev->dev, "unable to allocate msm_otg\n"); - return -ENOMEM; - } - - motg->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL); - if (!motg->phy.otg) { - dev_err(&pdev->dev, "unable to allocate msm_otg\n"); - return -ENOMEM; - } - - motg->pdata = pdev->dev.platform_data; - phy = &motg->phy; - phy->dev = &pdev->dev; - - motg->phy_reset_clk = clk_get(&pdev->dev, "usb_phy_clk"); - if (IS_ERR(motg->phy_reset_clk)) { - dev_err(&pdev->dev, "failed to get usb_phy_clk\n"); - ret = PTR_ERR(motg->phy_reset_clk); - goto free_motg; - } - - motg->clk = clk_get(&pdev->dev, "usb_hs_clk"); - if (IS_ERR(motg->clk)) { - dev_err(&pdev->dev, "failed to get usb_hs_clk\n"); - ret = PTR_ERR(motg->clk); - goto put_phy_reset_clk; - } - clk_set_rate(motg->clk, 60000000); - - /* - * If USB Core is running its protocol engine based on CORE CLK, - * CORE CLK must be running at >55Mhz for correct HSUSB - * operation and USB core cannot tolerate frequency changes on - * CORE CLK. For such USB cores, vote for maximum clk frequency - * on pclk source - */ - if (motg->pdata->pclk_src_name) { - motg->pclk_src = clk_get(&pdev->dev, - motg->pdata->pclk_src_name); - if (IS_ERR(motg->pclk_src)) - goto put_clk; - clk_set_rate(motg->pclk_src, INT_MAX); - clk_enable(motg->pclk_src); - } else - motg->pclk_src = ERR_PTR(-ENOENT); - - - motg->pclk = clk_get(&pdev->dev, "usb_hs_pclk"); - if (IS_ERR(motg->pclk)) { - dev_err(&pdev->dev, "failed to get usb_hs_pclk\n"); - ret = PTR_ERR(motg->pclk); - goto put_pclk_src; - } - - /* - * USB core clock is not present on all MSM chips. This - * clock is introduced to remove the dependency on AXI - * bus frequency. - */ - motg->core_clk = clk_get(&pdev->dev, "usb_hs_core_clk"); - if (IS_ERR(motg->core_clk)) - motg->core_clk = NULL; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "failed to get platform resource mem\n"); - ret = -ENODEV; - goto put_core_clk; - } - - motg->regs = ioremap(res->start, resource_size(res)); - if (!motg->regs) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto put_core_clk; - } - dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs); - - motg->irq = platform_get_irq(pdev, 0); - if (!motg->irq) { - dev_err(&pdev->dev, "platform_get_irq failed\n"); - ret = -ENODEV; - goto free_regs; - } - - clk_enable(motg->clk); - clk_enable(motg->pclk); - - ret = msm_hsusb_init_vddcx(motg, 1); - if (ret) { - dev_err(&pdev->dev, "hsusb vddcx configuration failed\n"); - goto free_regs; - } - - ret = msm_hsusb_ldo_init(motg, 1); - if (ret) { - dev_err(&pdev->dev, "hsusb vreg configuration failed\n"); - goto vddcx_exit; - } - ret = msm_hsusb_ldo_set_mode(1); - if (ret) { - dev_err(&pdev->dev, "hsusb vreg enable failed\n"); - goto ldo_exit; - } - - if (motg->core_clk) - clk_enable(motg->core_clk); - - writel(0, USB_USBINTR); - writel(0, USB_OTGSC); - - INIT_WORK(&motg->sm_work, msm_otg_sm_work); - INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work); - ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED, - "msm_otg", motg); - if (ret) { - dev_err(&pdev->dev, "request irq failed\n"); - goto disable_clks; - } - - phy->init = msm_otg_reset; - phy->set_power = msm_otg_set_power; - - phy->io_ops = &msm_otg_io_ops; - - phy->otg->phy = &motg->phy; - phy->otg->set_host = msm_otg_set_host; - phy->otg->set_peripheral = msm_otg_set_peripheral; - - ret = usb_set_transceiver(&motg->phy); - if (ret) { - dev_err(&pdev->dev, "usb_set_transceiver failed\n"); - goto free_irq; - } - - platform_set_drvdata(pdev, motg); - device_init_wakeup(&pdev->dev, 1); - - if (motg->pdata->mode == USB_OTG && - motg->pdata->otg_control == OTG_USER_CONTROL) { - ret = msm_otg_debugfs_init(motg); - if (ret) - dev_dbg(&pdev->dev, "mode debugfs file is" - "not available\n"); - } - - pm_runtime_set_active(&pdev->dev); - pm_runtime_enable(&pdev->dev); - - return 0; -free_irq: - free_irq(motg->irq, motg); -disable_clks: - clk_disable(motg->pclk); - clk_disable(motg->clk); -ldo_exit: - msm_hsusb_ldo_init(motg, 0); -vddcx_exit: - msm_hsusb_init_vddcx(motg, 0); -free_regs: - iounmap(motg->regs); -put_core_clk: - if (motg->core_clk) - clk_put(motg->core_clk); - clk_put(motg->pclk); -put_pclk_src: - if (!IS_ERR(motg->pclk_src)) { - clk_disable(motg->pclk_src); - clk_put(motg->pclk_src); - } -put_clk: - clk_put(motg->clk); -put_phy_reset_clk: - clk_put(motg->phy_reset_clk); -free_motg: - kfree(motg->phy.otg); - kfree(motg); - return ret; -} - -static int __devexit msm_otg_remove(struct platform_device *pdev) -{ - struct msm_otg *motg = platform_get_drvdata(pdev); - struct usb_phy *phy = &motg->phy; - int cnt = 0; - - if (phy->otg->host || phy->otg->gadget) - return -EBUSY; - - msm_otg_debugfs_cleanup(); - cancel_delayed_work_sync(&motg->chg_work); - cancel_work_sync(&motg->sm_work); - - pm_runtime_resume(&pdev->dev); - - device_init_wakeup(&pdev->dev, 0); - pm_runtime_disable(&pdev->dev); - - usb_set_transceiver(NULL); - free_irq(motg->irq, motg); - - /* - * Put PHY in low power mode. - */ - ulpi_read(phy, 0x14); - ulpi_write(phy, 0x08, 0x09); - - writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC); - while (cnt < PHY_SUSPEND_TIMEOUT_USEC) { - if (readl(USB_PORTSC) & PORTSC_PHCD) - break; - udelay(1); - cnt++; - } - if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) - dev_err(phy->dev, "Unable to suspend PHY\n"); - - clk_disable(motg->pclk); - clk_disable(motg->clk); - if (motg->core_clk) - clk_disable(motg->core_clk); - if (!IS_ERR(motg->pclk_src)) { - clk_disable(motg->pclk_src); - clk_put(motg->pclk_src); - } - msm_hsusb_ldo_init(motg, 0); - - iounmap(motg->regs); - pm_runtime_set_suspended(&pdev->dev); - - clk_put(motg->phy_reset_clk); - clk_put(motg->pclk); - clk_put(motg->clk); - if (motg->core_clk) - clk_put(motg->core_clk); - - kfree(motg->phy.otg); - kfree(motg); - - return 0; -} - -#ifdef CONFIG_PM_RUNTIME -static int msm_otg_runtime_idle(struct device *dev) -{ - struct msm_otg *motg = dev_get_drvdata(dev); - struct usb_otg *otg = motg->phy.otg; - - dev_dbg(dev, "OTG runtime idle\n"); - - /* - * It is observed some times that a spurious interrupt - * comes when PHY is put into LPM immediately after PHY reset. - * This 1 sec delay also prevents entering into LPM immediately - * after asynchronous interrupt. - */ - if (otg->phy->state != OTG_STATE_UNDEFINED) - pm_schedule_suspend(dev, 1000); - - return -EAGAIN; -} - -static int msm_otg_runtime_suspend(struct device *dev) -{ - struct msm_otg *motg = dev_get_drvdata(dev); - - dev_dbg(dev, "OTG runtime suspend\n"); - return msm_otg_suspend(motg); -} - -static int msm_otg_runtime_resume(struct device *dev) -{ - struct msm_otg *motg = dev_get_drvdata(dev); - - dev_dbg(dev, "OTG runtime resume\n"); - return msm_otg_resume(motg); -} -#endif - -#ifdef CONFIG_PM_SLEEP -static int msm_otg_pm_suspend(struct device *dev) -{ - struct msm_otg *motg = dev_get_drvdata(dev); - - dev_dbg(dev, "OTG PM suspend\n"); - return msm_otg_suspend(motg); -} - -static int msm_otg_pm_resume(struct device *dev) -{ - struct msm_otg *motg = dev_get_drvdata(dev); - int ret; - - dev_dbg(dev, "OTG PM resume\n"); - - ret = msm_otg_resume(motg); - if (ret) - return ret; - - /* - * Runtime PM Documentation recommends bringing the - * device to full powered state upon resume. - */ - pm_runtime_disable(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - - return 0; -} -#endif - -#ifdef CONFIG_PM -static const struct dev_pm_ops msm_otg_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume) - SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume, - msm_otg_runtime_idle) -}; -#endif - -static struct platform_driver msm_otg_driver = { - .remove = __devexit_p(msm_otg_remove), - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, -#ifdef CONFIG_PM - .pm = &msm_otg_dev_pm_ops, -#endif - }, -}; - -static int __init msm_otg_init(void) -{ - return platform_driver_probe(&msm_otg_driver, msm_otg_probe); -} - -static void __exit msm_otg_exit(void) -{ - platform_driver_unregister(&msm_otg_driver); -} - -module_init(msm_otg_init); -module_exit(msm_otg_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("MSM USB transceiver driver"); diff --git a/ANDROID_3.4.5/drivers/usb/otg/mv_otg.c b/ANDROID_3.4.5/drivers/usb/otg/mv_otg.c deleted file mode 100644 index 6cc6c3ff..00000000 --- a/ANDROID_3.4.5/drivers/usb/otg/mv_otg.c +++ /dev/null @@ -1,973 +0,0 @@ -/* - * Copyright (C) 2011 Marvell International Ltd. All rights reserved. - * Author: Chao Xie - * Neil Zhang - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "mv_otg.h" - -#define DRIVER_DESC "Marvell USB OTG transceiver driver" -#define DRIVER_VERSION "Jan 20, 2010" - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); - -static const char driver_name[] = "mv-otg"; - -static char *state_string[] = { - "undefined", - "b_idle", - "b_srp_init", - "b_peripheral", - "b_wait_acon", - "b_host", - "a_idle", - "a_wait_vrise", - "a_wait_bcon", - "a_host", - "a_suspend", - "a_peripheral", - "a_wait_vfall", - "a_vbus_err" -}; - -static int mv_otg_set_vbus(struct usb_otg *otg, bool on) -{ - struct mv_otg *mvotg = container_of(otg->phy, struct mv_otg, phy); - if (mvotg->pdata->set_vbus == NULL) - return -ENODEV; - - return mvotg->pdata->set_vbus(on); -} - -static int mv_otg_set_host(struct usb_otg *otg, - struct usb_bus *host) -{ - otg->host = host; - - return 0; -} - -static int mv_otg_set_peripheral(struct usb_otg *otg, - struct usb_gadget *gadget) -{ - otg->gadget = gadget; - - return 0; -} - -static void mv_otg_run_state_machine(struct mv_otg *mvotg, - unsigned long delay) -{ - dev_dbg(&mvotg->pdev->dev, "transceiver is updated\n"); - if (!mvotg->qwork) - return; - - queue_delayed_work(mvotg->qwork, &mvotg->work, delay); -} - -static void mv_otg_timer_await_bcon(unsigned long data) -{ - struct mv_otg *mvotg = (struct mv_otg *) data; - - mvotg->otg_ctrl.a_wait_bcon_timeout = 1; - - dev_info(&mvotg->pdev->dev, "B Device No Response!\n"); - - if (spin_trylock(&mvotg->wq_lock)) { - mv_otg_run_state_machine(mvotg, 0); - spin_unlock(&mvotg->wq_lock); - } -} - -static int mv_otg_cancel_timer(struct mv_otg *mvotg, unsigned int id) -{ - struct timer_list *timer; - - if (id >= OTG_TIMER_NUM) - return -EINVAL; - - timer = &mvotg->otg_ctrl.timer[id]; - - if (timer_pending(timer)) - del_timer(timer); - - return 0; -} - -static int mv_otg_set_timer(struct mv_otg *mvotg, unsigned int id, - unsigned long interval, - void (*callback) (unsigned long)) -{ - struct timer_list *timer; - - if (id >= OTG_TIMER_NUM) - return -EINVAL; - - timer = &mvotg->otg_ctrl.timer[id]; - if (timer_pending(timer)) { - dev_err(&mvotg->pdev->dev, "Timer%d is already running\n", id); - return -EBUSY; - } - - init_timer(timer); - timer->data = (unsigned long) mvotg; - timer->function = callback; - timer->expires = jiffies + interval; - add_timer(timer); - - return 0; -} - -static int mv_otg_reset(struct mv_otg *mvotg) -{ - unsigned int loops; - u32 tmp; - - /* Stop the controller */ - tmp = readl(&mvotg->op_regs->usbcmd); - tmp &= ~USBCMD_RUN_STOP; - writel(tmp, &mvotg->op_regs->usbcmd); - - /* Reset the controller to get default values */ - writel(USBCMD_CTRL_RESET, &mvotg->op_regs->usbcmd); - - loops = 500; - while (readl(&mvotg->op_regs->usbcmd) & USBCMD_CTRL_RESET) { - if (loops == 0) { - dev_err(&mvotg->pdev->dev, - "Wait for RESET completed TIMEOUT\n"); - return -ETIMEDOUT; - } - loops--; - udelay(20); - } - - writel(0x0, &mvotg->op_regs->usbintr); - tmp = readl(&mvotg->op_regs->usbsts); - writel(tmp, &mvotg->op_regs->usbsts); - - return 0; -} - -static void mv_otg_init_irq(struct mv_otg *mvotg) -{ - u32 otgsc; - - mvotg->irq_en = OTGSC_INTR_A_SESSION_VALID - | OTGSC_INTR_A_VBUS_VALID; - mvotg->irq_status = OTGSC_INTSTS_A_SESSION_VALID - | OTGSC_INTSTS_A_VBUS_VALID; - - if (mvotg->pdata->vbus == NULL) { - mvotg->irq_en |= OTGSC_INTR_B_SESSION_VALID - | OTGSC_INTR_B_SESSION_END; - mvotg->irq_status |= OTGSC_INTSTS_B_SESSION_VALID - | OTGSC_INTSTS_B_SESSION_END; - } - - if (mvotg->pdata->id == NULL) { - mvotg->irq_en |= OTGSC_INTR_USB_ID; - mvotg->irq_status |= OTGSC_INTSTS_USB_ID; - } - - otgsc = readl(&mvotg->op_regs->otgsc); - otgsc |= mvotg->irq_en; - writel(otgsc, &mvotg->op_regs->otgsc); -} - -static void mv_otg_start_host(struct mv_otg *mvotg, int on) -{ -#ifdef CONFIG_USB - struct usb_otg *otg = mvotg->phy.otg; - struct usb_hcd *hcd; - - if (!otg->host) - return; - - dev_info(&mvotg->pdev->dev, "%s host\n", on ? "start" : "stop"); - - hcd = bus_to_hcd(otg->host); - - if (on) - usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); - else - usb_remove_hcd(hcd); -#endif /* CONFIG_USB */ -} - -static void mv_otg_start_periphrals(struct mv_otg *mvotg, int on) -{ - struct usb_otg *otg = mvotg->phy.otg; - - if (!otg->gadget) - return; - - dev_info(mvotg->phy.dev, "gadget %s\n", on ? "on" : "off"); - - if (on) - usb_gadget_vbus_connect(otg->gadget); - else - usb_gadget_vbus_disconnect(otg->gadget); -} - -static void otg_clock_enable(struct mv_otg *mvotg) -{ - unsigned int i; - - for (i = 0; i < mvotg->clknum; i++) - clk_enable(mvotg->clk[i]); -} - -static void otg_clock_disable(struct mv_otg *mvotg) -{ - unsigned int i; - - for (i = 0; i < mvotg->clknum; i++) - clk_disable(mvotg->clk[i]); -} - -static int mv_otg_enable_internal(struct mv_otg *mvotg) -{ - int retval = 0; - - if (mvotg->active) - return 0; - - dev_dbg(&mvotg->pdev->dev, "otg enabled\n"); - - otg_clock_enable(mvotg); - if (mvotg->pdata->phy_init) { - retval = mvotg->pdata->phy_init(mvotg->phy_regs); - if (retval) { - dev_err(&mvotg->pdev->dev, - "init phy error %d\n", retval); - otg_clock_disable(mvotg); - return retval; - } - } - mvotg->active = 1; - - return 0; - -} - -static int mv_otg_enable(struct mv_otg *mvotg) -{ - if (mvotg->clock_gating) - return mv_otg_enable_internal(mvotg); - - return 0; -} - -static void mv_otg_disable_internal(struct mv_otg *mvotg) -{ - if (mvotg->active) { - dev_dbg(&mvotg->pdev->dev, "otg disabled\n"); - if (mvotg->pdata->phy_deinit) - mvotg->pdata->phy_deinit(mvotg->phy_regs); - otg_clock_disable(mvotg); - mvotg->active = 0; - } -} - -static void mv_otg_disable(struct mv_otg *mvotg) -{ - if (mvotg->clock_gating) - mv_otg_disable_internal(mvotg); -} - -static void mv_otg_update_inputs(struct mv_otg *mvotg) -{ - struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl; - u32 otgsc; - - otgsc = readl(&mvotg->op_regs->otgsc); - - if (mvotg->pdata->vbus) { - if (mvotg->pdata->vbus->poll() == VBUS_HIGH) { - otg_ctrl->b_sess_vld = 1; - otg_ctrl->b_sess_end = 0; - } else { - otg_ctrl->b_sess_vld = 0; - otg_ctrl->b_sess_end = 1; - } - } else { - otg_ctrl->b_sess_vld = !!(otgsc & OTGSC_STS_B_SESSION_VALID); - otg_ctrl->b_sess_end = !!(otgsc & OTGSC_STS_B_SESSION_END); - } - - if (mvotg->pdata->id) - otg_ctrl->id = !!mvotg->pdata->id->poll(); - else - otg_ctrl->id = !!(otgsc & OTGSC_STS_USB_ID); - - if (mvotg->pdata->otg_force_a_bus_req && !otg_ctrl->id) - otg_ctrl->a_bus_req = 1; - - otg_ctrl->a_sess_vld = !!(otgsc & OTGSC_STS_A_SESSION_VALID); - otg_ctrl->a_vbus_vld = !!(otgsc & OTGSC_STS_A_VBUS_VALID); - - dev_dbg(&mvotg->pdev->dev, "%s: ", __func__); - dev_dbg(&mvotg->pdev->dev, "id %d\n", otg_ctrl->id); - dev_dbg(&mvotg->pdev->dev, "b_sess_vld %d\n", otg_ctrl->b_sess_vld); - dev_dbg(&mvotg->pdev->dev, "b_sess_end %d\n", otg_ctrl->b_sess_end); - dev_dbg(&mvotg->pdev->dev, "a_vbus_vld %d\n", otg_ctrl->a_vbus_vld); - dev_dbg(&mvotg->pdev->dev, "a_sess_vld %d\n", otg_ctrl->a_sess_vld); -} - -static void mv_otg_update_state(struct mv_otg *mvotg) -{ - struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl; - struct usb_phy *phy = &mvotg->phy; - int old_state = phy->state; - - switch (old_state) { - case OTG_STATE_UNDEFINED: - phy->state = OTG_STATE_B_IDLE; - /* FALL THROUGH */ - case OTG_STATE_B_IDLE: - if (otg_ctrl->id == 0) - phy->state = OTG_STATE_A_IDLE; - else if (otg_ctrl->b_sess_vld) - phy->state = OTG_STATE_B_PERIPHERAL; - break; - case OTG_STATE_B_PERIPHERAL: - if (!otg_ctrl->b_sess_vld || otg_ctrl->id == 0) - phy->state = OTG_STATE_B_IDLE; - break; - case OTG_STATE_A_IDLE: - if (otg_ctrl->id) - phy->state = OTG_STATE_B_IDLE; - else if (!(otg_ctrl->a_bus_drop) && - (otg_ctrl->a_bus_req || otg_ctrl->a_srp_det)) - phy->state = OTG_STATE_A_WAIT_VRISE; - break; - case OTG_STATE_A_WAIT_VRISE: - if (otg_ctrl->a_vbus_vld) - phy->state = OTG_STATE_A_WAIT_BCON; - break; - case OTG_STATE_A_WAIT_BCON: - if (otg_ctrl->id || otg_ctrl->a_bus_drop - || otg_ctrl->a_wait_bcon_timeout) { - mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER); - mvotg->otg_ctrl.a_wait_bcon_timeout = 0; - phy->state = OTG_STATE_A_WAIT_VFALL; - otg_ctrl->a_bus_req = 0; - } else if (!otg_ctrl->a_vbus_vld) { - mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER); - mvotg->otg_ctrl.a_wait_bcon_timeout = 0; - phy->state = OTG_STATE_A_VBUS_ERR; - } else if (otg_ctrl->b_conn) { - mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER); - mvotg->otg_ctrl.a_wait_bcon_timeout = 0; - phy->state = OTG_STATE_A_HOST; - } - break; - case OTG_STATE_A_HOST: - if (otg_ctrl->id || !otg_ctrl->b_conn - || otg_ctrl->a_bus_drop) - phy->state = OTG_STATE_A_WAIT_BCON; - else if (!otg_ctrl->a_vbus_vld) - phy->state = OTG_STATE_A_VBUS_ERR; - break; - case OTG_STATE_A_WAIT_VFALL: - if (otg_ctrl->id - || (!otg_ctrl->b_conn && otg_ctrl->a_sess_vld) - || otg_ctrl->a_bus_req) - phy->state = OTG_STATE_A_IDLE; - break; - case OTG_STATE_A_VBUS_ERR: - if (otg_ctrl->id || otg_ctrl->a_clr_err - || otg_ctrl->a_bus_drop) { - otg_ctrl->a_clr_err = 0; - phy->state = OTG_STATE_A_WAIT_VFALL; - } - break; - default: - break; - } -} - -static void mv_otg_work(struct work_struct *work) -{ - struct mv_otg *mvotg; - struct usb_phy *phy; - struct usb_otg *otg; - int old_state; - - mvotg = container_of((struct delayed_work *)work, struct mv_otg, work); - -run: - /* work queue is single thread, or we need spin_lock to protect */ - phy = &mvotg->phy; - otg = phy->otg; - old_state = phy->state; - - if (!mvotg->active) - return; - - mv_otg_update_inputs(mvotg); - mv_otg_update_state(mvotg); - - if (old_state != phy->state) { - dev_info(&mvotg->pdev->dev, "change from state %s to %s\n", - state_string[old_state], - state_string[phy->state]); - - switch (phy->state) { - case OTG_STATE_B_IDLE: - otg->default_a = 0; - if (old_state == OTG_STATE_B_PERIPHERAL) - mv_otg_start_periphrals(mvotg, 0); - mv_otg_reset(mvotg); - mv_otg_disable(mvotg); - break; - case OTG_STATE_B_PERIPHERAL: - mv_otg_enable(mvotg); - mv_otg_start_periphrals(mvotg, 1); - break; - case OTG_STATE_A_IDLE: - otg->default_a = 1; - mv_otg_enable(mvotg); - if (old_state == OTG_STATE_A_WAIT_VFALL) - mv_otg_start_host(mvotg, 0); - mv_otg_reset(mvotg); - break; - case OTG_STATE_A_WAIT_VRISE: - mv_otg_set_vbus(otg, 1); - break; - case OTG_STATE_A_WAIT_BCON: - if (old_state != OTG_STATE_A_HOST) - mv_otg_start_host(mvotg, 1); - mv_otg_set_timer(mvotg, A_WAIT_BCON_TIMER, - T_A_WAIT_BCON, - mv_otg_timer_await_bcon); - /* - * Now, we directly enter A_HOST. So set b_conn = 1 - * here. In fact, it need host driver to notify us. - */ - mvotg->otg_ctrl.b_conn = 1; - break; - case OTG_STATE_A_HOST: - break; - case OTG_STATE_A_WAIT_VFALL: - /* - * Now, we has exited A_HOST. So set b_conn = 0 - * here. In fact, it need host driver to notify us. - */ - mvotg->otg_ctrl.b_conn = 0; - mv_otg_set_vbus(otg, 0); - break; - case OTG_STATE_A_VBUS_ERR: - break; - default: - break; - } - goto run; - } -} - -static irqreturn_t mv_otg_irq(int irq, void *dev) -{ - struct mv_otg *mvotg = dev; - u32 otgsc; - - otgsc = readl(&mvotg->op_regs->otgsc); - writel(otgsc, &mvotg->op_regs->otgsc); - - /* - * if we have vbus, then the vbus detection for B-device - * will be done by mv_otg_inputs_irq(). - */ - if (mvotg->pdata->vbus) - if ((otgsc & OTGSC_STS_USB_ID) && - !(otgsc & OTGSC_INTSTS_USB_ID)) - return IRQ_NONE; - - if ((otgsc & mvotg->irq_status) == 0) - return IRQ_NONE; - - mv_otg_run_state_machine(mvotg, 0); - - return IRQ_HANDLED; -} - -static irqreturn_t mv_otg_inputs_irq(int irq, void *dev) -{ - struct mv_otg *mvotg = dev; - - /* The clock may disabled at this time */ - if (!mvotg->active) { - mv_otg_enable(mvotg); - mv_otg_init_irq(mvotg); - } - - mv_otg_run_state_machine(mvotg, 0); - - return IRQ_HANDLED; -} - -static ssize_t -get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct mv_otg *mvotg = dev_get_drvdata(dev); - return scnprintf(buf, PAGE_SIZE, "%d\n", - mvotg->otg_ctrl.a_bus_req); -} - -static ssize_t -set_a_bus_req(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct mv_otg *mvotg = dev_get_drvdata(dev); - - if (count > 2) - return -1; - - /* We will use this interface to change to A device */ - if (mvotg->phy.state != OTG_STATE_B_IDLE - && mvotg->phy.state != OTG_STATE_A_IDLE) - return -1; - - /* The clock may disabled and we need to set irq for ID detected */ - mv_otg_enable(mvotg); - mv_otg_init_irq(mvotg); - - if (buf[0] == '1') { - mvotg->otg_ctrl.a_bus_req = 1; - mvotg->otg_ctrl.a_bus_drop = 0; - dev_dbg(&mvotg->pdev->dev, - "User request: a_bus_req = 1\n"); - - if (spin_trylock(&mvotg->wq_lock)) { - mv_otg_run_state_machine(mvotg, 0); - spin_unlock(&mvotg->wq_lock); - } - } - - return count; -} - -static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUSR, get_a_bus_req, - set_a_bus_req); - -static ssize_t -set_a_clr_err(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct mv_otg *mvotg = dev_get_drvdata(dev); - if (!mvotg->phy.otg->default_a) - return -1; - - if (count > 2) - return -1; - - if (buf[0] == '1') { - mvotg->otg_ctrl.a_clr_err = 1; - dev_dbg(&mvotg->pdev->dev, - "User request: a_clr_err = 1\n"); - } - - if (spin_trylock(&mvotg->wq_lock)) { - mv_otg_run_state_machine(mvotg, 0); - spin_unlock(&mvotg->wq_lock); - } - - return count; -} - -static DEVICE_ATTR(a_clr_err, S_IWUSR, NULL, set_a_clr_err); - -static ssize_t -get_a_bus_drop(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct mv_otg *mvotg = dev_get_drvdata(dev); - return scnprintf(buf, PAGE_SIZE, "%d\n", - mvotg->otg_ctrl.a_bus_drop); -} - -static ssize_t -set_a_bus_drop(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct mv_otg *mvotg = dev_get_drvdata(dev); - if (!mvotg->phy.otg->default_a) - return -1; - - if (count > 2) - return -1; - - if (buf[0] == '0') { - mvotg->otg_ctrl.a_bus_drop = 0; - dev_dbg(&mvotg->pdev->dev, - "User request: a_bus_drop = 0\n"); - } else if (buf[0] == '1') { - mvotg->otg_ctrl.a_bus_drop = 1; - mvotg->otg_ctrl.a_bus_req = 0; - dev_dbg(&mvotg->pdev->dev, - "User request: a_bus_drop = 1\n"); - dev_dbg(&mvotg->pdev->dev, - "User request: and a_bus_req = 0\n"); - } - - if (spin_trylock(&mvotg->wq_lock)) { - mv_otg_run_state_machine(mvotg, 0); - spin_unlock(&mvotg->wq_lock); - } - - return count; -} - -static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUSR, - get_a_bus_drop, set_a_bus_drop); - -static struct attribute *inputs_attrs[] = { - &dev_attr_a_bus_req.attr, - &dev_attr_a_clr_err.attr, - &dev_attr_a_bus_drop.attr, - NULL, -}; - -static struct attribute_group inputs_attr_group = { - .name = "inputs", - .attrs = inputs_attrs, -}; - -int mv_otg_remove(struct platform_device *pdev) -{ - struct mv_otg *mvotg = platform_get_drvdata(pdev); - int clk_i; - - sysfs_remove_group(&mvotg->pdev->dev.kobj, &inputs_attr_group); - - if (mvotg->irq) - free_irq(mvotg->irq, mvotg); - - if (mvotg->pdata->vbus) - free_irq(mvotg->pdata->vbus->irq, mvotg); - if (mvotg->pdata->id) - free_irq(mvotg->pdata->id->irq, mvotg); - - if (mvotg->qwork) { - flush_workqueue(mvotg->qwork); - destroy_workqueue(mvotg->qwork); - } - - mv_otg_disable(mvotg); - - if (mvotg->cap_regs) - iounmap(mvotg->cap_regs); - - if (mvotg->phy_regs) - iounmap(mvotg->phy_regs); - - for (clk_i = 0; clk_i <= mvotg->clknum; clk_i++) - clk_put(mvotg->clk[clk_i]); - - usb_set_transceiver(NULL); - platform_set_drvdata(pdev, NULL); - - kfree(mvotg->phy.otg); - kfree(mvotg); - - return 0; -} - -static int mv_otg_probe(struct platform_device *pdev) -{ - struct mv_usb_platform_data *pdata = pdev->dev.platform_data; - struct mv_otg *mvotg; - struct usb_otg *otg; - struct resource *r; - int retval = 0, clk_i, i; - size_t size; - - if (pdata == NULL) { - dev_err(&pdev->dev, "failed to get platform data\n"); - return -ENODEV; - } - - size = sizeof(*mvotg) + sizeof(struct clk *) * pdata->clknum; - mvotg = kzalloc(size, GFP_KERNEL); - if (!mvotg) { - dev_err(&pdev->dev, "failed to allocate memory!\n"); - return -ENOMEM; - } - - otg = kzalloc(sizeof *otg, GFP_KERNEL); - if (!otg) { - kfree(mvotg); - return -ENOMEM; - } - - platform_set_drvdata(pdev, mvotg); - - mvotg->pdev = pdev; - mvotg->pdata = pdata; - - mvotg->clknum = pdata->clknum; - for (clk_i = 0; clk_i < mvotg->clknum; clk_i++) { - mvotg->clk[clk_i] = clk_get(&pdev->dev, pdata->clkname[clk_i]); - if (IS_ERR(mvotg->clk[clk_i])) { - retval = PTR_ERR(mvotg->clk[clk_i]); - goto err_put_clk; - } - } - - mvotg->qwork = create_singlethread_workqueue("mv_otg_queue"); - if (!mvotg->qwork) { - dev_dbg(&pdev->dev, "cannot create workqueue for OTG\n"); - retval = -ENOMEM; - goto err_put_clk; - } - - INIT_DELAYED_WORK(&mvotg->work, mv_otg_work); - - /* OTG common part */ - mvotg->pdev = pdev; - mvotg->phy.dev = &pdev->dev; - mvotg->phy.otg = otg; - mvotg->phy.label = driver_name; - mvotg->phy.state = OTG_STATE_UNDEFINED; - - otg->phy = &mvotg->phy; - otg->set_host = mv_otg_set_host; - otg->set_peripheral = mv_otg_set_peripheral; - otg->set_vbus = mv_otg_set_vbus; - - for (i = 0; i < OTG_TIMER_NUM; i++) - init_timer(&mvotg->otg_ctrl.timer[i]); - - r = platform_get_resource_byname(mvotg->pdev, - IORESOURCE_MEM, "phyregs"); - if (r == NULL) { - dev_err(&pdev->dev, "no phy I/O memory resource defined\n"); - retval = -ENODEV; - goto err_destroy_workqueue; - } - - mvotg->phy_regs = ioremap(r->start, resource_size(r)); - if (mvotg->phy_regs == NULL) { - dev_err(&pdev->dev, "failed to map phy I/O memory\n"); - retval = -EFAULT; - goto err_destroy_workqueue; - } - - r = platform_get_resource_byname(mvotg->pdev, - IORESOURCE_MEM, "capregs"); - if (r == NULL) { - dev_err(&pdev->dev, "no I/O memory resource defined\n"); - retval = -ENODEV; - goto err_unmap_phyreg; - } - - mvotg->cap_regs = ioremap(r->start, resource_size(r)); - if (mvotg->cap_regs == NULL) { - dev_err(&pdev->dev, "failed to map I/O memory\n"); - retval = -EFAULT; - goto err_unmap_phyreg; - } - - /* we will acces controller register, so enable the udc controller */ - retval = mv_otg_enable_internal(mvotg); - if (retval) { - dev_err(&pdev->dev, "mv otg enable error %d\n", retval); - goto err_unmap_capreg; - } - - mvotg->op_regs = - (struct mv_otg_regs __iomem *) ((unsigned long) mvotg->cap_regs - + (readl(mvotg->cap_regs) & CAPLENGTH_MASK)); - - if (pdata->id) { - retval = request_threaded_irq(pdata->id->irq, NULL, - mv_otg_inputs_irq, - IRQF_ONESHOT, "id", mvotg); - if (retval) { - dev_info(&pdev->dev, - "Failed to request irq for ID\n"); - pdata->id = NULL; - } - } - - if (pdata->vbus) { - mvotg->clock_gating = 1; - retval = request_threaded_irq(pdata->vbus->irq, NULL, - mv_otg_inputs_irq, - IRQF_ONESHOT, "vbus", mvotg); - if (retval) { - dev_info(&pdev->dev, - "Failed to request irq for VBUS, " - "disable clock gating\n"); - mvotg->clock_gating = 0; - pdata->vbus = NULL; - } - } - - if (pdata->disable_otg_clock_gating) - mvotg->clock_gating = 0; - - mv_otg_reset(mvotg); - mv_otg_init_irq(mvotg); - - r = platform_get_resource(mvotg->pdev, IORESOURCE_IRQ, 0); - if (r == NULL) { - dev_err(&pdev->dev, "no IRQ resource defined\n"); - retval = -ENODEV; - goto err_disable_clk; - } - - mvotg->irq = r->start; - if (request_irq(mvotg->irq, mv_otg_irq, IRQF_SHARED, - driver_name, mvotg)) { - dev_err(&pdev->dev, "Request irq %d for OTG failed\n", - mvotg->irq); - mvotg->irq = 0; - retval = -ENODEV; - goto err_disable_clk; - } - - retval = usb_set_transceiver(&mvotg->phy); - if (retval < 0) { - dev_err(&pdev->dev, "can't register transceiver, %d\n", - retval); - goto err_free_irq; - } - - retval = sysfs_create_group(&pdev->dev.kobj, &inputs_attr_group); - if (retval < 0) { - dev_dbg(&pdev->dev, - "Can't register sysfs attr group: %d\n", retval); - goto err_set_transceiver; - } - - spin_lock_init(&mvotg->wq_lock); - if (spin_trylock(&mvotg->wq_lock)) { - mv_otg_run_state_machine(mvotg, 2 * HZ); - spin_unlock(&mvotg->wq_lock); - } - - dev_info(&pdev->dev, - "successful probe OTG device %s clock gating.\n", - mvotg->clock_gating ? "with" : "without"); - - return 0; - -err_set_transceiver: - usb_set_transceiver(NULL); -err_free_irq: - free_irq(mvotg->irq, mvotg); -err_disable_clk: - if (pdata->vbus) - free_irq(pdata->vbus->irq, mvotg); - if (pdata->id) - free_irq(pdata->id->irq, mvotg); - mv_otg_disable_internal(mvotg); -err_unmap_capreg: - iounmap(mvotg->cap_regs); -err_unmap_phyreg: - iounmap(mvotg->phy_regs); -err_destroy_workqueue: - flush_workqueue(mvotg->qwork); - destroy_workqueue(mvotg->qwork); -err_put_clk: - for (clk_i--; clk_i >= 0; clk_i--) - clk_put(mvotg->clk[clk_i]); - - platform_set_drvdata(pdev, NULL); - kfree(otg); - kfree(mvotg); - - return retval; -} - -#ifdef CONFIG_PM -static int mv_otg_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct mv_otg *mvotg = platform_get_drvdata(pdev); - - if (mvotg->phy.state != OTG_STATE_B_IDLE) { - dev_info(&pdev->dev, - "OTG state is not B_IDLE, it is %d!\n", - mvotg->phy.state); - return -EAGAIN; - } - - if (!mvotg->clock_gating) - mv_otg_disable_internal(mvotg); - - return 0; -} - -static int mv_otg_resume(struct platform_device *pdev) -{ - struct mv_otg *mvotg = platform_get_drvdata(pdev); - u32 otgsc; - - if (!mvotg->clock_gating) { - mv_otg_enable_internal(mvotg); - - otgsc = readl(&mvotg->op_regs->otgsc); - otgsc |= mvotg->irq_en; - writel(otgsc, &mvotg->op_regs->otgsc); - - if (spin_trylock(&mvotg->wq_lock)) { - mv_otg_run_state_machine(mvotg, 0); - spin_unlock(&mvotg->wq_lock); - } - } - return 0; -} -#endif - -static struct platform_driver mv_otg_driver = { - .probe = mv_otg_probe, - .remove = __exit_p(mv_otg_remove), - .driver = { - .owner = THIS_MODULE, - .name = driver_name, - }, -#ifdef CONFIG_PM - .suspend = mv_otg_suspend, - .resume = mv_otg_resume, -#endif -}; - -static int __init mv_otg_init(void) -{ - return platform_driver_register(&mv_otg_driver); -} - -static void __exit mv_otg_exit(void) -{ - platform_driver_unregister(&mv_otg_driver); -} - -module_init(mv_otg_init); -module_exit(mv_otg_exit); diff --git a/ANDROID_3.4.5/drivers/usb/otg/mv_otg.h b/ANDROID_3.4.5/drivers/usb/otg/mv_otg.h deleted file mode 100644 index 8a9e351b..00000000 --- a/ANDROID_3.4.5/drivers/usb/otg/mv_otg.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (C) 2011 Marvell International Ltd. All rights reserved. - * - * 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. - */ - -#ifndef __MV_USB_OTG_CONTROLLER__ -#define __MV_USB_OTG_CONTROLLER__ - -#include - -/* Command Register Bit Masks */ -#define USBCMD_RUN_STOP (0x00000001) -#define USBCMD_CTRL_RESET (0x00000002) - -/* otgsc Register Bit Masks */ -#define OTGSC_CTRL_VUSB_DISCHARGE 0x00000001 -#define OTGSC_CTRL_VUSB_CHARGE 0x00000002 -#define OTGSC_CTRL_OTG_TERM 0x00000008 -#define OTGSC_CTRL_DATA_PULSING 0x00000010 -#define OTGSC_STS_USB_ID 0x00000100 -#define OTGSC_STS_A_VBUS_VALID 0x00000200 -#define OTGSC_STS_A_SESSION_VALID 0x00000400 -#define OTGSC_STS_B_SESSION_VALID 0x00000800 -#define OTGSC_STS_B_SESSION_END 0x00001000 -#define OTGSC_STS_1MS_TOGGLE 0x00002000 -#define OTGSC_STS_DATA_PULSING 0x00004000 -#define OTGSC_INTSTS_USB_ID 0x00010000 -#define OTGSC_INTSTS_A_VBUS_VALID 0x00020000 -#define OTGSC_INTSTS_A_SESSION_VALID 0x00040000 -#define OTGSC_INTSTS_B_SESSION_VALID 0x00080000 -#define OTGSC_INTSTS_B_SESSION_END 0x00100000 -#define OTGSC_INTSTS_1MS 0x00200000 -#define OTGSC_INTSTS_DATA_PULSING 0x00400000 -#define OTGSC_INTR_USB_ID 0x01000000 -#define OTGSC_INTR_A_VBUS_VALID 0x02000000 -#define OTGSC_INTR_A_SESSION_VALID 0x04000000 -#define OTGSC_INTR_B_SESSION_VALID 0x08000000 -#define OTGSC_INTR_B_SESSION_END 0x10000000 -#define OTGSC_INTR_1MS_TIMER 0x20000000 -#define OTGSC_INTR_DATA_PULSING 0x40000000 - -#define CAPLENGTH_MASK (0xff) - -/* Timer's interval, unit 10ms */ -#define T_A_WAIT_VRISE 100 -#define T_A_WAIT_BCON 2000 -#define T_A_AIDL_BDIS 100 -#define T_A_BIDL_ADIS 20 -#define T_B_ASE0_BRST 400 -#define T_B_SE0_SRP 300 -#define T_B_SRP_FAIL 2000 -#define T_B_DATA_PLS 10 -#define T_B_SRP_INIT 100 -#define T_A_SRP_RSPNS 10 -#define T_A_DRV_RSM 5 - -enum otg_function { - OTG_B_DEVICE = 0, - OTG_A_DEVICE -}; - -enum mv_otg_timer { - A_WAIT_BCON_TIMER = 0, - OTG_TIMER_NUM -}; - -/* PXA OTG state machine */ -struct mv_otg_ctrl { - /* internal variables */ - u8 a_set_b_hnp_en; /* A-Device set b_hnp_en */ - u8 b_srp_done; - u8 b_hnp_en; - - /* OTG inputs */ - u8 a_bus_drop; - u8 a_bus_req; - u8 a_clr_err; - u8 a_bus_resume; - u8 a_bus_suspend; - u8 a_conn; - u8 a_sess_vld; - u8 a_srp_det; - u8 a_vbus_vld; - u8 b_bus_req; /* B-Device Require Bus */ - u8 b_bus_resume; - u8 b_bus_suspend; - u8 b_conn; - u8 b_se0_srp; - u8 b_sess_end; - u8 b_sess_vld; - u8 id; - u8 a_suspend_req; - - /*Timer event */ - u8 a_aidl_bdis_timeout; - u8 b_ase0_brst_timeout; - u8 a_bidl_adis_timeout; - u8 a_wait_bcon_timeout; - - struct timer_list timer[OTG_TIMER_NUM]; -}; - -#define VUSBHS_MAX_PORTS 8 - -struct mv_otg_regs { - u32 usbcmd; /* Command register */ - u32 usbsts; /* Status register */ - u32 usbintr; /* Interrupt enable */ - u32 frindex; /* Frame index */ - u32 reserved1[1]; - u32 deviceaddr; /* Device Address */ - u32 eplistaddr; /* Endpoint List Address */ - u32 ttctrl; /* HOST TT status and control */ - u32 burstsize; /* Programmable Burst Size */ - u32 txfilltuning; /* Host Transmit Pre-Buffer Packet Tuning */ - u32 reserved[4]; - u32 epnak; /* Endpoint NAK */ - u32 epnaken; /* Endpoint NAK Enable */ - u32 configflag; /* Configured Flag register */ - u32 portsc[VUSBHS_MAX_PORTS]; /* Port Status/Control x, x = 1..8 */ - u32 otgsc; - u32 usbmode; /* USB Host/Device mode */ - u32 epsetupstat; /* Endpoint Setup Status */ - u32 epprime; /* Endpoint Initialize */ - u32 epflush; /* Endpoint De-initialize */ - u32 epstatus; /* Endpoint Status */ - u32 epcomplete; /* Endpoint Interrupt On Complete */ - u32 epctrlx[16]; /* Endpoint Control, where x = 0.. 15 */ - u32 mcr; /* Mux Control */ - u32 isr; /* Interrupt Status */ - u32 ier; /* Interrupt Enable */ -}; - -struct mv_otg { - struct usb_phy phy; - struct mv_otg_ctrl otg_ctrl; - - /* base address */ - void __iomem *phy_regs; - void __iomem *cap_regs; - struct mv_otg_regs __iomem *op_regs; - - struct platform_device *pdev; - int irq; - u32 irq_status; - u32 irq_en; - - struct delayed_work work; - struct workqueue_struct *qwork; - - spinlock_t wq_lock; - - struct mv_usb_platform_data *pdata; - - unsigned int active; - unsigned int clock_gating; - unsigned int clknum; - struct clk *clk[0]; -}; - -#endif diff --git a/ANDROID_3.4.5/drivers/usb/otg/nop-usb-xceiv.c b/ANDROID_3.4.5/drivers/usb/otg/nop-usb-xceiv.c deleted file mode 100644 index 58b26df6..00000000 --- a/ANDROID_3.4.5/drivers/usb/otg/nop-usb-xceiv.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * drivers/usb/otg/nop-usb-xceiv.c - * - * NOP USB transceiver for all USB transceiver which are either built-in - * into USB IP or which are mostly autonomous. - * - * Copyright (C) 2009 Texas Instruments Inc - * Author: Ajay Kumar Gupta - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Current status: - * This provides a "nop" transceiver for PHYs which are - * autonomous such as isp1504, isp1707, etc. - */ - -#include -#include -#include -#include -#include - -struct nop_usb_xceiv { - struct usb_phy phy; - struct device *dev; -}; - -static struct platform_device *pd; - -void usb_nop_xceiv_register(void) -{ - if (pd) - return; - pd = platform_device_register_simple("nop_usb_xceiv", -1, NULL, 0); - if (!pd) { - printk(KERN_ERR "Unable to register usb nop transceiver\n"); - return; - } -} -EXPORT_SYMBOL(usb_nop_xceiv_register); - -void usb_nop_xceiv_unregister(void) -{ - platform_device_unregister(pd); - pd = NULL; -} -EXPORT_SYMBOL(usb_nop_xceiv_unregister); - -static int nop_set_suspend(struct usb_phy *x, int suspend) -{ - return 0; -} - -static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) -{ - if (!otg) - return -ENODEV; - - if (!gadget) { - otg->gadget = NULL; - return -ENODEV; - } - - otg->gadget = gadget; - otg->phy->state = OTG_STATE_B_IDLE; - return 0; -} - -static int nop_set_host(struct usb_otg *otg, struct usb_bus *host) -{ - if (!otg) - return -ENODEV; - - if (!host) { - otg->host = NULL; - return -ENODEV; - } - - otg->host = host; - return 0; -} - -static int __devinit nop_usb_xceiv_probe(struct platform_device *pdev) -{ - struct nop_usb_xceiv *nop; - int err; - - nop = kzalloc(sizeof *nop, GFP_KERNEL); - if (!nop) - return -ENOMEM; - - nop->phy.otg = kzalloc(sizeof *nop->phy.otg, GFP_KERNEL); - if (!nop->phy.otg) { - kfree(nop); - return -ENOMEM; - } - - nop->dev = &pdev->dev; - nop->phy.dev = nop->dev; - nop->phy.label = "nop-xceiv"; - nop->phy.set_suspend = nop_set_suspend; - nop->phy.state = OTG_STATE_UNDEFINED; - - nop->phy.otg->phy = &nop->phy; - nop->phy.otg->set_host = nop_set_host; - nop->phy.otg->set_peripheral = nop_set_peripheral; - - err = usb_set_transceiver(&nop->phy); - if (err) { - dev_err(&pdev->dev, "can't register transceiver, err: %d\n", - err); - goto exit; - } - - platform_set_drvdata(pdev, nop); - - ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier); - - return 0; -exit: - kfree(nop->phy.otg); - kfree(nop); - return err; -} - -static int __devexit nop_usb_xceiv_remove(struct platform_device *pdev) -{ - struct nop_usb_xceiv *nop = platform_get_drvdata(pdev); - - usb_set_transceiver(NULL); - - platform_set_drvdata(pdev, NULL); - kfree(nop->phy.otg); - kfree(nop); - - return 0; -} - -static struct platform_driver nop_usb_xceiv_driver = { - .probe = nop_usb_xceiv_probe, - .remove = __devexit_p(nop_usb_xceiv_remove), - .driver = { - .name = "nop_usb_xceiv", - .owner = THIS_MODULE, - }, -}; - -static int __init nop_usb_xceiv_init(void) -{ - return platform_driver_register(&nop_usb_xceiv_driver); -} -subsys_initcall(nop_usb_xceiv_init); - -static void __exit nop_usb_xceiv_exit(void) -{ - platform_driver_unregister(&nop_usb_xceiv_driver); -} -module_exit(nop_usb_xceiv_exit); - -MODULE_ALIAS("platform:nop_usb_xceiv"); -MODULE_AUTHOR("Texas Instruments Inc"); -MODULE_DESCRIPTION("NOP USB Transceiver driver"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/otg/otg-wakelock.c b/ANDROID_3.4.5/drivers/usb/otg/otg-wakelock.c deleted file mode 100644 index e17e2729..00000000 --- a/ANDROID_3.4.5/drivers/usb/otg/otg-wakelock.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * otg-wakelock.c - * - * Copyright (C) 2011 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#define TEMPORARY_HOLD_TIME 2000 - -static bool enabled = true; -static struct usb_phy *otgwl_xceiv; -static struct notifier_block otgwl_nb; - -/* - * otgwl_spinlock is held while the VBUS lock is grabbed or dropped and the - * held field is updated to match. - */ - -static DEFINE_SPINLOCK(otgwl_spinlock); - -/* - * Only one lock, but since these 3 fields are associated with each other... - */ - -struct otgwl_lock { - char name[40]; - struct wake_lock wakelock; - bool held; -}; - -/* - * VBUS present lock. Also used as a timed lock on charger - * connect/disconnect and USB host disconnect, to allow the system - * to react to the change in power. - */ - -static struct otgwl_lock vbus_lock; - -static void otgwl_hold(struct otgwl_lock *lock) -{ - if (!lock->held) { - wake_lock(&lock->wakelock); - lock->held = true; - } -} - -static void otgwl_temporary_hold(struct otgwl_lock *lock) -{ - wake_lock_timeout(&lock->wakelock, - msecs_to_jiffies(TEMPORARY_HOLD_TIME)); - lock->held = false; -} - -static void otgwl_drop(struct otgwl_lock *lock) -{ - if (lock->held) { - wake_unlock(&lock->wakelock); - lock->held = false; - } -} - -static void otgwl_handle_event(unsigned long event) -{ - unsigned long irqflags; - - spin_lock_irqsave(&otgwl_spinlock, irqflags); - - if (!enabled) { - otgwl_drop(&vbus_lock); - spin_unlock_irqrestore(&otgwl_spinlock, irqflags); - return; - } - - switch (event) { - case USB_EVENT_VBUS: - case USB_EVENT_ENUMERATED: - otgwl_hold(&vbus_lock); - break; - - case USB_EVENT_NONE: - case USB_EVENT_ID: - case USB_EVENT_CHARGER: - otgwl_temporary_hold(&vbus_lock); - break; - - default: - break; - } - - spin_unlock_irqrestore(&otgwl_spinlock, irqflags); -} - -static int otgwl_otg_notifications(struct notifier_block *nb, - unsigned long event, void *unused) -{ - otgwl_handle_event(event); - return NOTIFY_OK; -} - -static int set_enabled(const char *val, const struct kernel_param *kp) -{ - int rv = param_set_bool(val, kp); - - if (rv) - return rv; - - if (otgwl_xceiv) - otgwl_handle_event(otgwl_xceiv->last_event); - - return 0; -} - -static struct kernel_param_ops enabled_param_ops = { - .set = set_enabled, - .get = param_get_bool, -}; - -module_param_cb(enabled, &enabled_param_ops, &enabled, 0644); -MODULE_PARM_DESC(enabled, "enable wakelock when VBUS present"); - -static int __init otg_wakelock_init(void) -{ - int ret; - - otgwl_xceiv = usb_get_transceiver(); - - if (!otgwl_xceiv) { - pr_err("%s: No USB transceiver found\n", __func__); - return -ENODEV; - } - - snprintf(vbus_lock.name, sizeof(vbus_lock.name), "vbus-%s", - dev_name(otgwl_xceiv->dev)); - wake_lock_init(&vbus_lock.wakelock, WAKE_LOCK_SUSPEND, - vbus_lock.name); - - otgwl_nb.notifier_call = otgwl_otg_notifications; - ret = usb_register_notifier(otgwl_xceiv, &otgwl_nb); - - if (ret) { - pr_err("%s: usb_register_notifier on transceiver %s" - " failed\n", __func__, - dev_name(otgwl_xceiv->dev)); - otgwl_xceiv = NULL; - wake_lock_destroy(&vbus_lock.wakelock); - return ret; - } - - otgwl_handle_event(otgwl_xceiv->last_event); - return ret; -} - -late_initcall(otg_wakelock_init); diff --git a/ANDROID_3.4.5/drivers/usb/otg/otg.c b/ANDROID_3.4.5/drivers/usb/otg/otg.c deleted file mode 100644 index 801e597a..00000000 --- a/ANDROID_3.4.5/drivers/usb/otg/otg.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * otg.c -- USB OTG utility code - * - * Copyright (C) 2004 Texas Instruments - * - * 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 -#include -#include - -#include - -static struct usb_phy *phy; - -/** - * usb_get_transceiver - find the (single) USB transceiver - * - * Returns the transceiver driver, after getting a refcount to it; or - * null if there is no such transceiver. The caller is responsible for - * calling usb_put_transceiver() to release that count. - * - * For use by USB host and peripheral drivers. - */ -struct usb_phy *usb_get_transceiver(void) -{ - if (phy) - get_device(phy->dev); - return phy; -} -EXPORT_SYMBOL(usb_get_transceiver); - -/** - * usb_put_transceiver - release the (single) USB transceiver - * @x: the transceiver returned by usb_get_transceiver() - * - * Releases a refcount the caller received from usb_get_transceiver(). - * - * For use by USB host and peripheral drivers. - */ -void usb_put_transceiver(struct usb_phy *x) -{ - if (x) - put_device(x->dev); -} -EXPORT_SYMBOL(usb_put_transceiver); - -/** - * usb_set_transceiver - declare the (single) USB transceiver - * @x: the USB transceiver to be used; or NULL - * - * This call is exclusively for use by transceiver drivers, which - * coordinate the activities of drivers for host and peripheral - * controllers, and in some cases for VBUS current regulation. - */ -int usb_set_transceiver(struct usb_phy *x) -{ - if (phy && x) - return -EBUSY; - phy = x; - return 0; -} -EXPORT_SYMBOL(usb_set_transceiver); - -const char *otg_state_string(enum usb_otg_state state) -{ - switch (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"; - case OTG_STATE_A_HOST: - return "a_host"; - case OTG_STATE_A_SUSPEND: - return "a_suspend"; - case OTG_STATE_A_PERIPHERAL: - return "a_peripheral"; - case OTG_STATE_A_WAIT_VFALL: - return "a_wait_vfall"; - case OTG_STATE_A_VBUS_ERR: - return "a_vbus_err"; - case OTG_STATE_B_IDLE: - return "b_idle"; - case OTG_STATE_B_SRP_INIT: - return "b_srp_init"; - case OTG_STATE_B_PERIPHERAL: - return "b_peripheral"; - case OTG_STATE_B_WAIT_ACON: - return "b_wait_acon"; - case OTG_STATE_B_HOST: - return "b_host"; - default: - return "UNDEFINED"; - } -} -EXPORT_SYMBOL(otg_state_string); diff --git a/ANDROID_3.4.5/drivers/usb/otg/otg_fsm.c b/ANDROID_3.4.5/drivers/usb/otg/otg_fsm.c deleted file mode 100644 index ade131a8..00000000 --- a/ANDROID_3.4.5/drivers/usb/otg/otg_fsm.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - * OTG Finite State Machine from OTG spec - * - * Copyright (C) 2007,2008 Freescale Semiconductor, Inc. - * - * Author: Li Yang - * Jerry Huang - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "otg_fsm.h" - -/* Change USB protocol when there is a protocol change */ -static int otg_set_protocol(struct otg_fsm *fsm, int protocol) -{ - int ret = 0; - - if (fsm->protocol != protocol) { - VDBG("Changing role fsm->protocol= %d; new protocol= %d\n", - fsm->protocol, protocol); - /* stop old protocol */ - if (fsm->protocol == PROTO_HOST) - ret = fsm->ops->start_host(fsm, 0); - else if (fsm->protocol == PROTO_GADGET) - ret = fsm->ops->start_gadget(fsm, 0); - if (ret) - return ret; - - /* start new protocol */ - if (protocol == PROTO_HOST) - ret = fsm->ops->start_host(fsm, 1); - else if (protocol == PROTO_GADGET) - ret = fsm->ops->start_gadget(fsm, 1); - if (ret) - return ret; - - fsm->protocol = protocol; - return 0; - } - - return 0; -} - -static int state_changed; - -/* Called when leaving a state. Do state clean up jobs here */ -void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state) -{ - switch (old_state) { - case OTG_STATE_B_IDLE: - otg_del_timer(fsm, b_se0_srp_tmr); - fsm->b_se0_srp = 0; - break; - case OTG_STATE_B_SRP_INIT: - fsm->b_srp_done = 0; - break; - case OTG_STATE_B_PERIPHERAL: - break; - case OTG_STATE_B_WAIT_ACON: - otg_del_timer(fsm, b_ase0_brst_tmr); - fsm->b_ase0_brst_tmout = 0; - break; - case OTG_STATE_B_HOST: - break; - case OTG_STATE_A_IDLE: - break; - case OTG_STATE_A_WAIT_VRISE: - otg_del_timer(fsm, a_wait_vrise_tmr); - fsm->a_wait_vrise_tmout = 0; - break; - case OTG_STATE_A_WAIT_BCON: - otg_del_timer(fsm, a_wait_bcon_tmr); - fsm->a_wait_bcon_tmout = 0; - break; - case OTG_STATE_A_HOST: - otg_del_timer(fsm, a_wait_enum_tmr); - break; - case OTG_STATE_A_SUSPEND: - otg_del_timer(fsm, a_aidl_bdis_tmr); - fsm->a_aidl_bdis_tmout = 0; - fsm->a_suspend_req = 0; - break; - case OTG_STATE_A_PERIPHERAL: - break; - case OTG_STATE_A_WAIT_VFALL: - otg_del_timer(fsm, a_wait_vrise_tmr); - break; - case OTG_STATE_A_VBUS_ERR: - break; - default: - break; - } -} - -/* Called when entering a state */ -int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state) -{ - state_changed = 1; - if (fsm->otg->phy->state == new_state) - return 0; - VDBG("Set state: %s\n", otg_state_string(new_state)); - otg_leave_state(fsm, fsm->otg->phy->state); - switch (new_state) { - case OTG_STATE_B_IDLE: - otg_drv_vbus(fsm, 0); - otg_chrg_vbus(fsm, 0); - otg_loc_conn(fsm, 0); - otg_loc_sof(fsm, 0); - otg_set_protocol(fsm, PROTO_UNDEF); - otg_add_timer(fsm, b_se0_srp_tmr); - break; - case OTG_STATE_B_SRP_INIT: - otg_start_pulse(fsm); - otg_loc_sof(fsm, 0); - otg_set_protocol(fsm, PROTO_UNDEF); - otg_add_timer(fsm, b_srp_fail_tmr); - break; - case OTG_STATE_B_PERIPHERAL: - otg_chrg_vbus(fsm, 0); - otg_loc_conn(fsm, 1); - otg_loc_sof(fsm, 0); - otg_set_protocol(fsm, PROTO_GADGET); - break; - case OTG_STATE_B_WAIT_ACON: - otg_chrg_vbus(fsm, 0); - otg_loc_conn(fsm, 0); - otg_loc_sof(fsm, 0); - otg_set_protocol(fsm, PROTO_HOST); - otg_add_timer(fsm, b_ase0_brst_tmr); - fsm->a_bus_suspend = 0; - break; - case OTG_STATE_B_HOST: - otg_chrg_vbus(fsm, 0); - otg_loc_conn(fsm, 0); - otg_loc_sof(fsm, 1); - otg_set_protocol(fsm, PROTO_HOST); - usb_bus_start_enum(fsm->otg->host, - fsm->otg->host->otg_port); - break; - case OTG_STATE_A_IDLE: - otg_drv_vbus(fsm, 0); - otg_chrg_vbus(fsm, 0); - otg_loc_conn(fsm, 0); - otg_loc_sof(fsm, 0); - otg_set_protocol(fsm, PROTO_HOST); - break; - case OTG_STATE_A_WAIT_VRISE: - otg_drv_vbus(fsm, 1); - otg_loc_conn(fsm, 0); - otg_loc_sof(fsm, 0); - otg_set_protocol(fsm, PROTO_HOST); - otg_add_timer(fsm, a_wait_vrise_tmr); - break; - case OTG_STATE_A_WAIT_BCON: - otg_drv_vbus(fsm, 1); - otg_loc_conn(fsm, 0); - otg_loc_sof(fsm, 0); - otg_set_protocol(fsm, PROTO_HOST); - otg_add_timer(fsm, a_wait_bcon_tmr); - break; - case OTG_STATE_A_HOST: - otg_drv_vbus(fsm, 1); - otg_loc_conn(fsm, 0); - otg_loc_sof(fsm, 1); - otg_set_protocol(fsm, PROTO_HOST); - /* - * When HNP is triggered while a_bus_req = 0, a_host will - * suspend too fast to complete a_set_b_hnp_en - */ - if (!fsm->a_bus_req || fsm->a_suspend_req) - otg_add_timer(fsm, a_wait_enum_tmr); - break; - case OTG_STATE_A_SUSPEND: - otg_drv_vbus(fsm, 1); - otg_loc_conn(fsm, 0); - otg_loc_sof(fsm, 0); - otg_set_protocol(fsm, PROTO_HOST); - otg_add_timer(fsm, a_aidl_bdis_tmr); - - break; - case OTG_STATE_A_PERIPHERAL: - otg_loc_conn(fsm, 1); - otg_loc_sof(fsm, 0); - otg_set_protocol(fsm, PROTO_GADGET); - otg_drv_vbus(fsm, 1); - break; - case OTG_STATE_A_WAIT_VFALL: - otg_drv_vbus(fsm, 0); - otg_loc_conn(fsm, 0); - otg_loc_sof(fsm, 0); - otg_set_protocol(fsm, PROTO_HOST); - break; - case OTG_STATE_A_VBUS_ERR: - otg_drv_vbus(fsm, 0); - otg_loc_conn(fsm, 0); - otg_loc_sof(fsm, 0); - otg_set_protocol(fsm, PROTO_UNDEF); - break; - default: - break; - } - - fsm->otg->phy->state = new_state; - return 0; -} - -/* State change judgement */ -int otg_statemachine(struct otg_fsm *fsm) -{ - enum usb_otg_state state; - unsigned long flags; - - spin_lock_irqsave(&fsm->lock, flags); - - state = fsm->otg->phy->state; - state_changed = 0; - /* State machine state change judgement */ - - switch (state) { - case OTG_STATE_UNDEFINED: - VDBG("fsm->id = %d\n", fsm->id); - if (fsm->id) - otg_set_state(fsm, OTG_STATE_B_IDLE); - else - otg_set_state(fsm, OTG_STATE_A_IDLE); - break; - case OTG_STATE_B_IDLE: - if (!fsm->id) - otg_set_state(fsm, OTG_STATE_A_IDLE); - else if (fsm->b_sess_vld && fsm->otg->gadget) - otg_set_state(fsm, OTG_STATE_B_PERIPHERAL); - else if (fsm->b_bus_req && fsm->b_sess_end && fsm->b_se0_srp) - otg_set_state(fsm, OTG_STATE_B_SRP_INIT); - break; - case OTG_STATE_B_SRP_INIT: - if (!fsm->id || fsm->b_srp_done) - otg_set_state(fsm, OTG_STATE_B_IDLE); - break; - case OTG_STATE_B_PERIPHERAL: - if (!fsm->id || !fsm->b_sess_vld) - otg_set_state(fsm, OTG_STATE_B_IDLE); - else if (fsm->b_bus_req && fsm->otg-> - gadget->b_hnp_enable && fsm->a_bus_suspend) - otg_set_state(fsm, OTG_STATE_B_WAIT_ACON); - break; - case OTG_STATE_B_WAIT_ACON: - if (fsm->a_conn) - otg_set_state(fsm, OTG_STATE_B_HOST); - else if (!fsm->id || !fsm->b_sess_vld) - otg_set_state(fsm, OTG_STATE_B_IDLE); - else if (fsm->a_bus_resume || fsm->b_ase0_brst_tmout) { - fsm->b_ase0_brst_tmout = 0; - otg_set_state(fsm, OTG_STATE_B_PERIPHERAL); - } - break; - case OTG_STATE_B_HOST: - if (!fsm->id || !fsm->b_sess_vld) - otg_set_state(fsm, OTG_STATE_B_IDLE); - else if (!fsm->b_bus_req || !fsm->a_conn) - otg_set_state(fsm, OTG_STATE_B_PERIPHERAL); - break; - case OTG_STATE_A_IDLE: - if (fsm->id) - otg_set_state(fsm, OTG_STATE_B_IDLE); - else if (!fsm->a_bus_drop && (fsm->a_bus_req || fsm->a_srp_det)) - otg_set_state(fsm, OTG_STATE_A_WAIT_VRISE); - break; - case OTG_STATE_A_WAIT_VRISE: - if (fsm->id || fsm->a_bus_drop || fsm->a_vbus_vld || - fsm->a_wait_vrise_tmout) { - otg_set_state(fsm, OTG_STATE_A_WAIT_BCON); - } - break; - case OTG_STATE_A_WAIT_BCON: - if (!fsm->a_vbus_vld) - otg_set_state(fsm, OTG_STATE_A_VBUS_ERR); - else if (fsm->b_conn) - otg_set_state(fsm, OTG_STATE_A_HOST); - else if (fsm->id | fsm->a_bus_drop | fsm->a_wait_bcon_tmout) - otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); - break; - case OTG_STATE_A_HOST: - if ((!fsm->a_bus_req || fsm->a_suspend_req) && - fsm->otg->host->b_hnp_enable) - otg_set_state(fsm, OTG_STATE_A_SUSPEND); - else if (fsm->id || !fsm->b_conn || fsm->a_bus_drop) - otg_set_state(fsm, OTG_STATE_A_WAIT_BCON); - else if (!fsm->a_vbus_vld) - otg_set_state(fsm, OTG_STATE_A_VBUS_ERR); - break; - case OTG_STATE_A_SUSPEND: - if (!fsm->b_conn && fsm->otg->host->b_hnp_enable) - otg_set_state(fsm, OTG_STATE_A_PERIPHERAL); - else if (!fsm->b_conn && !fsm->otg->host->b_hnp_enable) - otg_set_state(fsm, OTG_STATE_A_WAIT_BCON); - else if (fsm->a_bus_req || fsm->b_bus_resume) - otg_set_state(fsm, OTG_STATE_A_HOST); - else if (fsm->id || fsm->a_bus_drop || fsm->a_aidl_bdis_tmout) - otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); - else if (!fsm->a_vbus_vld) - otg_set_state(fsm, OTG_STATE_A_VBUS_ERR); - break; - case OTG_STATE_A_PERIPHERAL: - if (fsm->id || fsm->a_bus_drop) - otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); - else if (fsm->b_bus_suspend) - otg_set_state(fsm, OTG_STATE_A_WAIT_BCON); - else if (!fsm->a_vbus_vld) - otg_set_state(fsm, OTG_STATE_A_VBUS_ERR); - break; - case OTG_STATE_A_WAIT_VFALL: - if (fsm->id || fsm->a_bus_req || (!fsm->a_sess_vld && - !fsm->b_conn)) - otg_set_state(fsm, OTG_STATE_A_IDLE); - break; - case OTG_STATE_A_VBUS_ERR: - if (fsm->id || fsm->a_bus_drop || fsm->a_clr_err) - otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); - break; - default: - break; - } - spin_unlock_irqrestore(&fsm->lock, flags); - - VDBG("quit statemachine, changed = %d\n", state_changed); - return state_changed; -} diff --git a/ANDROID_3.4.5/drivers/usb/otg/otg_fsm.h b/ANDROID_3.4.5/drivers/usb/otg/otg_fsm.h deleted file mode 100644 index c30a2e1d..00000000 --- a/ANDROID_3.4.5/drivers/usb/otg/otg_fsm.h +++ /dev/null @@ -1,154 +0,0 @@ -/* Copyright (C) 2007,2008 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#undef DEBUG -#undef VERBOSE - -#ifdef DEBUG -#define DBG(fmt, args...) printk(KERN_DEBUG "[%s] " fmt , \ - __func__, ## args) -#else -#define DBG(fmt, args...) do {} while (0) -#endif - -#ifdef VERBOSE -#define VDBG DBG -#else -#define VDBG(stuff...) do {} while (0) -#endif - -#ifdef VERBOSE -#define MPC_LOC printk("Current Location [%s]:[%d]\n", __FILE__, __LINE__) -#else -#define MPC_LOC do {} while (0) -#endif - -#define PROTO_UNDEF (0) -#define PROTO_HOST (1) -#define PROTO_GADGET (2) - -/* OTG state machine according to the OTG spec */ -struct otg_fsm { - /* Input */ - int a_bus_resume; - int a_bus_suspend; - int a_conn; - int a_sess_vld; - int a_srp_det; - int a_vbus_vld; - int b_bus_resume; - int b_bus_suspend; - int b_conn; - int b_se0_srp; - int b_sess_end; - int b_sess_vld; - int id; - - /* Internal variables */ - int a_set_b_hnp_en; - int b_srp_done; - int b_hnp_enable; - - /* Timeout indicator for timers */ - int a_wait_vrise_tmout; - int a_wait_bcon_tmout; - int a_aidl_bdis_tmout; - int b_ase0_brst_tmout; - - /* Informative variables */ - int a_bus_drop; - int a_bus_req; - int a_clr_err; - int a_suspend_req; - int b_bus_req; - - /* Output */ - int drv_vbus; - int loc_conn; - int loc_sof; - - struct otg_fsm_ops *ops; - struct usb_otg *otg; - - /* Current usb protocol used: 0:undefine; 1:host; 2:client */ - int protocol; - spinlock_t lock; -}; - -struct otg_fsm_ops { - void (*chrg_vbus)(int on); - void (*drv_vbus)(int on); - void (*loc_conn)(int on); - void (*loc_sof)(int on); - void (*start_pulse)(void); - void (*add_timer)(void *timer); - void (*del_timer)(void *timer); - int (*start_host)(struct otg_fsm *fsm, int on); - int (*start_gadget)(struct otg_fsm *fsm, int on); -}; - - -static inline void otg_chrg_vbus(struct otg_fsm *fsm, int on) -{ - fsm->ops->chrg_vbus(on); -} - -static inline void otg_drv_vbus(struct otg_fsm *fsm, int on) -{ - if (fsm->drv_vbus != on) { - fsm->drv_vbus = on; - fsm->ops->drv_vbus(on); - } -} - -static inline void otg_loc_conn(struct otg_fsm *fsm, int on) -{ - if (fsm->loc_conn != on) { - fsm->loc_conn = on; - fsm->ops->loc_conn(on); - } -} - -static inline void otg_loc_sof(struct otg_fsm *fsm, int on) -{ - if (fsm->loc_sof != on) { - fsm->loc_sof = on; - fsm->ops->loc_sof(on); - } -} - -static inline void otg_start_pulse(struct otg_fsm *fsm) -{ - fsm->ops->start_pulse(); -} - -static inline void otg_add_timer(struct otg_fsm *fsm, void *timer) -{ - fsm->ops->add_timer(timer); -} - -static inline void otg_del_timer(struct otg_fsm *fsm, void *timer) -{ - fsm->ops->del_timer(timer); -} - -int otg_statemachine(struct otg_fsm *fsm); - -/* Defined by device specific driver, for different timer implementation */ -extern struct fsl_otg_timer *a_wait_vrise_tmr, *a_wait_bcon_tmr, - *a_aidl_bdis_tmr, *b_ase0_brst_tmr, *b_se0_srp_tmr, *b_srp_fail_tmr, - *a_wait_enum_tmr; diff --git a/ANDROID_3.4.5/drivers/usb/otg/twl4030-usb.c b/ANDROID_3.4.5/drivers/usb/otg/twl4030-usb.c deleted file mode 100644 index c4a86da8..00000000 --- a/ANDROID_3.4.5/drivers/usb/otg/twl4030-usb.c +++ /dev/null @@ -1,734 +0,0 @@ -/* - * twl4030_usb - TWL4030 USB transceiver, talking to OMAP OTG controller - * - * Copyright (C) 2004-2007 Texas Instruments - * Copyright (C) 2008 Nokia Corporation - * Contact: Felipe Balbi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Current status: - * - HS USB ULPI mode works. - * - 3-pin mode support may be added in future. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Register defines */ - -#define MCPC_CTRL 0x30 -#define MCPC_CTRL_RTSOL (1 << 7) -#define MCPC_CTRL_EXTSWR (1 << 6) -#define MCPC_CTRL_EXTSWC (1 << 5) -#define MCPC_CTRL_VOICESW (1 << 4) -#define MCPC_CTRL_OUT64K (1 << 3) -#define MCPC_CTRL_RTSCTSSW (1 << 2) -#define MCPC_CTRL_HS_UART (1 << 0) - -#define MCPC_IO_CTRL 0x33 -#define MCPC_IO_CTRL_MICBIASEN (1 << 5) -#define MCPC_IO_CTRL_CTS_NPU (1 << 4) -#define MCPC_IO_CTRL_RXD_PU (1 << 3) -#define MCPC_IO_CTRL_TXDTYP (1 << 2) -#define MCPC_IO_CTRL_CTSTYP (1 << 1) -#define MCPC_IO_CTRL_RTSTYP (1 << 0) - -#define MCPC_CTRL2 0x36 -#define MCPC_CTRL2_MCPC_CK_EN (1 << 0) - -#define OTHER_FUNC_CTRL 0x80 -#define OTHER_FUNC_CTRL_BDIS_ACON_EN (1 << 4) -#define OTHER_FUNC_CTRL_FIVEWIRE_MODE (1 << 2) - -#define OTHER_IFC_CTRL 0x83 -#define OTHER_IFC_CTRL_OE_INT_EN (1 << 6) -#define OTHER_IFC_CTRL_CEA2011_MODE (1 << 5) -#define OTHER_IFC_CTRL_FSLSSERIALMODE_4PIN (1 << 4) -#define OTHER_IFC_CTRL_HIZ_ULPI_60MHZ_OUT (1 << 3) -#define OTHER_IFC_CTRL_HIZ_ULPI (1 << 2) -#define OTHER_IFC_CTRL_ALT_INT_REROUTE (1 << 0) - -#define OTHER_INT_EN_RISE 0x86 -#define OTHER_INT_EN_FALL 0x89 -#define OTHER_INT_STS 0x8C -#define OTHER_INT_LATCH 0x8D -#define OTHER_INT_VB_SESS_VLD (1 << 7) -#define OTHER_INT_DM_HI (1 << 6) /* not valid for "latch" reg */ -#define OTHER_INT_DP_HI (1 << 5) /* not valid for "latch" reg */ -#define OTHER_INT_BDIS_ACON (1 << 3) /* not valid for "fall" regs */ -#define OTHER_INT_MANU (1 << 1) -#define OTHER_INT_ABNORMAL_STRESS (1 << 0) - -#define ID_STATUS 0x96 -#define ID_RES_FLOAT (1 << 4) -#define ID_RES_440K (1 << 3) -#define ID_RES_200K (1 << 2) -#define ID_RES_102K (1 << 1) -#define ID_RES_GND (1 << 0) - -#define POWER_CTRL 0xAC -#define POWER_CTRL_OTG_ENAB (1 << 5) - -#define OTHER_IFC_CTRL2 0xAF -#define OTHER_IFC_CTRL2_ULPI_STP_LOW (1 << 4) -#define OTHER_IFC_CTRL2_ULPI_TXEN_POL (1 << 3) -#define OTHER_IFC_CTRL2_ULPI_4PIN_2430 (1 << 2) -#define OTHER_IFC_CTRL2_USB_INT_OUTSEL_MASK (3 << 0) /* bits 0 and 1 */ -#define OTHER_IFC_CTRL2_USB_INT_OUTSEL_INT1N (0 << 0) -#define OTHER_IFC_CTRL2_USB_INT_OUTSEL_INT2N (1 << 0) - -#define REG_CTRL_EN 0xB2 -#define REG_CTRL_ERROR 0xB5 -#define ULPI_I2C_CONFLICT_INTEN (1 << 0) - -#define OTHER_FUNC_CTRL2 0xB8 -#define OTHER_FUNC_CTRL2_VBAT_TIMER_EN (1 << 0) - -/* following registers do not have separate _clr and _set registers */ -#define VBUS_DEBOUNCE 0xC0 -#define ID_DEBOUNCE 0xC1 -#define VBAT_TIMER 0xD3 -#define PHY_PWR_CTRL 0xFD -#define PHY_PWR_PHYPWD (1 << 0) -#define PHY_CLK_CTRL 0xFE -#define PHY_CLK_CTRL_CLOCKGATING_EN (1 << 2) -#define PHY_CLK_CTRL_CLK32K_EN (1 << 1) -#define REQ_PHY_DPLL_CLK (1 << 0) -#define PHY_CLK_CTRL_STS 0xFF -#define PHY_DPLL_CLK (1 << 0) - -/* In module TWL4030_MODULE_PM_MASTER */ -#define STS_HW_CONDITIONS 0x0F - -/* In module TWL4030_MODULE_PM_RECEIVER */ -#define VUSB_DEDICATED1 0x7D -#define VUSB_DEDICATED2 0x7E -#define VUSB1V5_DEV_GRP 0x71 -#define VUSB1V5_TYPE 0x72 -#define VUSB1V5_REMAP 0x73 -#define VUSB1V8_DEV_GRP 0x74 -#define VUSB1V8_TYPE 0x75 -#define VUSB1V8_REMAP 0x76 -#define VUSB3V1_DEV_GRP 0x77 -#define VUSB3V1_TYPE 0x78 -#define VUSB3V1_REMAP 0x79 - -/* In module TWL4030_MODULE_INTBR */ -#define PMBR1 0x0D -#define GPIO_USB_4PIN_ULPI_2430C (3 << 0) - -struct twl4030_usb { - struct usb_phy phy; - struct device *dev; - - /* TWL4030 internal USB regulator supplies */ - struct regulator *usb1v5; - struct regulator *usb1v8; - struct regulator *usb3v1; - - /* for vbus reporting with irqs disabled */ - spinlock_t lock; - - /* pin configuration */ - enum twl4030_usb_mode usb_mode; - - int irq; - u8 linkstat; - bool vbus_supplied; - u8 asleep; - bool irq_enabled; -}; - -/* internal define on top of container_of */ -#define phy_to_twl(x) container_of((x), struct twl4030_usb, phy) - -/*-------------------------------------------------------------------------*/ - -static int twl4030_i2c_write_u8_verify(struct twl4030_usb *twl, - u8 module, u8 data, u8 address) -{ - u8 check; - - if ((twl_i2c_write_u8(module, data, address) >= 0) && - (twl_i2c_read_u8(module, &check, address) >= 0) && - (check == data)) - return 0; - dev_dbg(twl->dev, "Write%d[%d,0x%x] wrote %02x but read %02x\n", - 1, module, address, check, data); - - /* Failed once: Try again */ - if ((twl_i2c_write_u8(module, data, address) >= 0) && - (twl_i2c_read_u8(module, &check, address) >= 0) && - (check == data)) - return 0; - dev_dbg(twl->dev, "Write%d[%d,0x%x] wrote %02x but read %02x\n", - 2, module, address, check, data); - - /* Failed again: Return error */ - return -EBUSY; -} - -#define twl4030_usb_write_verify(twl, address, data) \ - twl4030_i2c_write_u8_verify(twl, TWL4030_MODULE_USB, (data), (address)) - -static inline int twl4030_usb_write(struct twl4030_usb *twl, - u8 address, u8 data) -{ - int ret = 0; - - ret = twl_i2c_write_u8(TWL4030_MODULE_USB, data, address); - if (ret < 0) - dev_dbg(twl->dev, - "TWL4030:USB:Write[0x%x] Error %d\n", address, ret); - return ret; -} - -static inline int twl4030_readb(struct twl4030_usb *twl, u8 module, u8 address) -{ - u8 data; - int ret = 0; - - ret = twl_i2c_read_u8(module, &data, address); - if (ret >= 0) - ret = data; - else - dev_dbg(twl->dev, - "TWL4030:readb[0x%x,0x%x] Error %d\n", - module, address, ret); - - return ret; -} - -static inline int twl4030_usb_read(struct twl4030_usb *twl, u8 address) -{ - return twl4030_readb(twl, TWL4030_MODULE_USB, address); -} - -/*-------------------------------------------------------------------------*/ - -static inline int -twl4030_usb_set_bits(struct twl4030_usb *twl, u8 reg, u8 bits) -{ - return twl4030_usb_write(twl, ULPI_SET(reg), bits); -} - -static inline int -twl4030_usb_clear_bits(struct twl4030_usb *twl, u8 reg, u8 bits) -{ - return twl4030_usb_write(twl, ULPI_CLR(reg), bits); -} - -/*-------------------------------------------------------------------------*/ - -static enum usb_phy_events twl4030_usb_linkstat(struct twl4030_usb *twl) -{ - int status; - int linkstat = USB_EVENT_NONE; - struct usb_otg *otg = twl->phy.otg; - - twl->vbus_supplied = false; - - /* - * For ID/VBUS sensing, see manual section 15.4.8 ... - * except when using only battery backup power, two - * comparators produce VBUS_PRES and ID_PRES signals, - * which don't match docs elsewhere. But ... BIT(7) - * and BIT(2) of STS_HW_CONDITIONS, respectively, do - * seem to match up. If either is true the USB_PRES - * signal is active, the OTG module is activated, and - * its interrupt may be raised (may wake the system). - */ - status = twl4030_readb(twl, TWL4030_MODULE_PM_MASTER, - STS_HW_CONDITIONS); - if (status < 0) - dev_err(twl->dev, "USB link status err %d\n", status); - else if (status & (BIT(7) | BIT(2))) { - if (status & (BIT(7))) - twl->vbus_supplied = true; - - if (status & BIT(2)) - linkstat = USB_EVENT_ID; - else - linkstat = USB_EVENT_VBUS; - } else - linkstat = USB_EVENT_NONE; - - dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n", - status, status, linkstat); - - twl->phy.last_event = linkstat; - - /* REVISIT this assumes host and peripheral controllers - * are registered, and that both are active... - */ - - spin_lock_irq(&twl->lock); - twl->linkstat = linkstat; - if (linkstat == USB_EVENT_ID) { - otg->default_a = true; - twl->phy.state = OTG_STATE_A_IDLE; - } else { - otg->default_a = false; - twl->phy.state = OTG_STATE_B_IDLE; - } - spin_unlock_irq(&twl->lock); - - return linkstat; -} - -static void twl4030_usb_set_mode(struct twl4030_usb *twl, int mode) -{ - twl->usb_mode = mode; - - switch (mode) { - case T2_USB_MODE_ULPI: - twl4030_usb_clear_bits(twl, ULPI_IFC_CTRL, - ULPI_IFC_CTRL_CARKITMODE); - twl4030_usb_set_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB); - twl4030_usb_clear_bits(twl, ULPI_FUNC_CTRL, - ULPI_FUNC_CTRL_XCVRSEL_MASK | - ULPI_FUNC_CTRL_OPMODE_MASK); - break; - case -1: - /* FIXME: power on defaults */ - break; - default: - dev_err(twl->dev, "unsupported T2 transceiver mode %d\n", - mode); - break; - }; -} - -static void twl4030_i2c_access(struct twl4030_usb *twl, int on) -{ - unsigned long timeout; - int val = twl4030_usb_read(twl, PHY_CLK_CTRL); - - if (val >= 0) { - if (on) { - /* enable DPLL to access PHY registers over I2C */ - val |= REQ_PHY_DPLL_CLK; - WARN_ON(twl4030_usb_write_verify(twl, PHY_CLK_CTRL, - (u8)val) < 0); - - timeout = jiffies + HZ; - while (!(twl4030_usb_read(twl, PHY_CLK_CTRL_STS) & - PHY_DPLL_CLK) - && time_before(jiffies, timeout)) - udelay(10); - if (!(twl4030_usb_read(twl, PHY_CLK_CTRL_STS) & - PHY_DPLL_CLK)) - dev_err(twl->dev, "Timeout setting T2 HSUSB " - "PHY DPLL clock\n"); - } else { - /* let ULPI control the DPLL clock */ - val &= ~REQ_PHY_DPLL_CLK; - WARN_ON(twl4030_usb_write_verify(twl, PHY_CLK_CTRL, - (u8)val) < 0); - } - } -} - -static void __twl4030_phy_power(struct twl4030_usb *twl, int on) -{ - u8 pwr = twl4030_usb_read(twl, PHY_PWR_CTRL); - - if (on) - pwr &= ~PHY_PWR_PHYPWD; - else - pwr |= PHY_PWR_PHYPWD; - - WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0); -} - -static void twl4030_phy_power(struct twl4030_usb *twl, int on) -{ - if (on) { - regulator_enable(twl->usb3v1); - regulator_enable(twl->usb1v8); - /* - * Disabling usb3v1 regulator (= writing 0 to VUSB3V1_DEV_GRP - * in twl4030) resets the VUSB_DEDICATED2 register. This reset - * enables VUSB3V1_SLEEP bit that remaps usb3v1 ACTIVE state to - * SLEEP. We work around this by clearing the bit after usv3v1 - * is re-activated. This ensures that VUSB3V1 is really active. - */ - twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, - VUSB_DEDICATED2); - regulator_enable(twl->usb1v5); - __twl4030_phy_power(twl, 1); - twl4030_usb_write(twl, PHY_CLK_CTRL, - twl4030_usb_read(twl, PHY_CLK_CTRL) | - (PHY_CLK_CTRL_CLOCKGATING_EN | - PHY_CLK_CTRL_CLK32K_EN)); - } else { - __twl4030_phy_power(twl, 0); - regulator_disable(twl->usb1v5); - regulator_disable(twl->usb1v8); - regulator_disable(twl->usb3v1); - } -} - -static void twl4030_phy_suspend(struct twl4030_usb *twl, int controller_off) -{ - if (twl->asleep) - return; - - twl4030_phy_power(twl, 0); - twl->asleep = 1; - dev_dbg(twl->dev, "%s\n", __func__); -} - -static void __twl4030_phy_resume(struct twl4030_usb *twl) -{ - twl4030_phy_power(twl, 1); - twl4030_i2c_access(twl, 1); - twl4030_usb_set_mode(twl, twl->usb_mode); - if (twl->usb_mode == T2_USB_MODE_ULPI) - twl4030_i2c_access(twl, 0); -} - -static void twl4030_phy_resume(struct twl4030_usb *twl) -{ - if (!twl->asleep) - return; - __twl4030_phy_resume(twl); - twl->asleep = 0; - dev_dbg(twl->dev, "%s\n", __func__); -} - -static int twl4030_usb_ldo_init(struct twl4030_usb *twl) -{ - /* Enable writing to power configuration registers */ - twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, - TWL4030_PM_MASTER_KEY_CFG1, - TWL4030_PM_MASTER_PROTECT_KEY); - - twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, - TWL4030_PM_MASTER_KEY_CFG2, - TWL4030_PM_MASTER_PROTECT_KEY); - - /* Keep VUSB3V1 LDO in sleep state until VBUS/ID change detected*/ - /*twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2);*/ - - /* input to VUSB3V1 LDO is from VBAT, not VBUS */ - twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x14, VUSB_DEDICATED1); - - /* Initialize 3.1V regulator */ - twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_DEV_GRP); - - twl->usb3v1 = regulator_get(twl->dev, "usb3v1"); - if (IS_ERR(twl->usb3v1)) - return -ENODEV; - - twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_TYPE); - - /* Initialize 1.5V regulator */ - twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_DEV_GRP); - - twl->usb1v5 = regulator_get(twl->dev, "usb1v5"); - if (IS_ERR(twl->usb1v5)) - goto fail1; - - twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_TYPE); - - /* Initialize 1.8V regulator */ - twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_DEV_GRP); - - twl->usb1v8 = regulator_get(twl->dev, "usb1v8"); - if (IS_ERR(twl->usb1v8)) - goto fail2; - - twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE); - - /* disable access to power configuration registers */ - twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, - TWL4030_PM_MASTER_PROTECT_KEY); - - return 0; - -fail2: - regulator_put(twl->usb1v5); - twl->usb1v5 = NULL; -fail1: - regulator_put(twl->usb3v1); - twl->usb3v1 = NULL; - return -ENODEV; -} - -static ssize_t twl4030_usb_vbus_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct twl4030_usb *twl = dev_get_drvdata(dev); - unsigned long flags; - int ret = -EINVAL; - - spin_lock_irqsave(&twl->lock, flags); - ret = sprintf(buf, "%s\n", - twl->vbus_supplied ? "on" : "off"); - spin_unlock_irqrestore(&twl->lock, flags); - - return ret; -} -static DEVICE_ATTR(vbus, 0444, twl4030_usb_vbus_show, NULL); - -static irqreturn_t twl4030_usb_irq(int irq, void *_twl) -{ - struct twl4030_usb *twl = _twl; - int status; - - status = twl4030_usb_linkstat(twl); - if (status >= 0) { - /* FIXME add a set_power() method so that B-devices can - * configure the charger appropriately. It's not always - * correct to consume VBUS power, and how much current to - * consume is a function of the USB configuration chosen - * by the host. - * - * REVISIT usb_gadget_vbus_connect(...) as needed, ditto - * its disconnect() sibling, when changing to/from the - * USB_LINK_VBUS state. musb_hdrc won't care until it - * starts to handle softconnect right. - */ - if (status == USB_EVENT_NONE) - twl4030_phy_suspend(twl, 0); - else - twl4030_phy_resume(twl); - - atomic_notifier_call_chain(&twl->phy.notifier, status, - twl->phy.otg->gadget); - } - sysfs_notify(&twl->dev->kobj, NULL, "vbus"); - - return IRQ_HANDLED; -} - -static void twl4030_usb_phy_init(struct twl4030_usb *twl) -{ - int status; - - status = twl4030_usb_linkstat(twl); - if (status >= 0) { - if (status == USB_EVENT_NONE) { - __twl4030_phy_power(twl, 0); - twl->asleep = 1; - } else { - __twl4030_phy_resume(twl); - twl->asleep = 0; - } - - atomic_notifier_call_chain(&twl->phy.notifier, status, - twl->phy.otg->gadget); - } - sysfs_notify(&twl->dev->kobj, NULL, "vbus"); -} - -static int twl4030_set_suspend(struct usb_phy *x, int suspend) -{ - struct twl4030_usb *twl = phy_to_twl(x); - - if (suspend) - twl4030_phy_suspend(twl, 1); - else - twl4030_phy_resume(twl); - - return 0; -} - -static int twl4030_set_peripheral(struct usb_otg *otg, - struct usb_gadget *gadget) -{ - if (!otg) - return -ENODEV; - - otg->gadget = gadget; - if (!gadget) - otg->phy->state = OTG_STATE_UNDEFINED; - - return 0; -} - -static int twl4030_set_host(struct usb_otg *otg, struct usb_bus *host) -{ - if (!otg) - return -ENODEV; - - otg->host = host; - if (!host) - otg->phy->state = OTG_STATE_UNDEFINED; - - return 0; -} - -static int __devinit twl4030_usb_probe(struct platform_device *pdev) -{ - struct twl4030_usb_data *pdata = pdev->dev.platform_data; - struct twl4030_usb *twl; - int status, err; - struct usb_otg *otg; - - if (!pdata) { - dev_dbg(&pdev->dev, "platform_data not available\n"); - return -EINVAL; - } - - twl = kzalloc(sizeof *twl, GFP_KERNEL); - if (!twl) - return -ENOMEM; - - otg = kzalloc(sizeof *otg, GFP_KERNEL); - if (!otg) { - kfree(twl); - return -ENOMEM; - } - - twl->dev = &pdev->dev; - twl->irq = platform_get_irq(pdev, 0); - twl->usb_mode = pdata->usb_mode; - twl->vbus_supplied = false; - twl->asleep = 1; - - twl->phy.dev = twl->dev; - twl->phy.label = "twl4030"; - twl->phy.otg = otg; - twl->phy.set_suspend = twl4030_set_suspend; - - otg->phy = &twl->phy; - otg->set_host = twl4030_set_host; - otg->set_peripheral = twl4030_set_peripheral; - - /* init spinlock for workqueue */ - spin_lock_init(&twl->lock); - - err = twl4030_usb_ldo_init(twl); - if (err) { - dev_err(&pdev->dev, "ldo init failed\n"); - kfree(otg); - kfree(twl); - return err; - } - usb_set_transceiver(&twl->phy); - - platform_set_drvdata(pdev, twl); - if (device_create_file(&pdev->dev, &dev_attr_vbus)) - dev_warn(&pdev->dev, "could not create sysfs file\n"); - - ATOMIC_INIT_NOTIFIER_HEAD(&twl->phy.notifier); - - /* Our job is to use irqs and status from the power module - * to keep the transceiver disabled when nothing's connected. - * - * FIXME we actually shouldn't start enabling it until the - * USB controller drivers have said they're ready, by calling - * set_host() and/or set_peripheral() ... OTG_capable boards - * need both handles, otherwise just one suffices. - */ - twl->irq_enabled = true; - status = request_threaded_irq(twl->irq, NULL, twl4030_usb_irq, - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, - "twl4030_usb", twl); - if (status < 0) { - dev_dbg(&pdev->dev, "can't get IRQ %d, err %d\n", - twl->irq, status); - kfree(otg); - kfree(twl); - return status; - } - - /* Power down phy or make it work according to - * current link state. - */ - twl4030_usb_phy_init(twl); - - dev_info(&pdev->dev, "Initialized TWL4030 USB module\n"); - return 0; -} - -static int __exit twl4030_usb_remove(struct platform_device *pdev) -{ - struct twl4030_usb *twl = platform_get_drvdata(pdev); - int val; - - free_irq(twl->irq, twl); - device_remove_file(twl->dev, &dev_attr_vbus); - - /* set transceiver mode to power on defaults */ - twl4030_usb_set_mode(twl, -1); - - /* autogate 60MHz ULPI clock, - * clear dpll clock request for i2c access, - * disable 32KHz - */ - val = twl4030_usb_read(twl, PHY_CLK_CTRL); - if (val >= 0) { - val |= PHY_CLK_CTRL_CLOCKGATING_EN; - val &= ~(PHY_CLK_CTRL_CLK32K_EN | REQ_PHY_DPLL_CLK); - twl4030_usb_write(twl, PHY_CLK_CTRL, (u8)val); - } - - /* disable complete OTG block */ - twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB); - - if (!twl->asleep) - twl4030_phy_power(twl, 0); - regulator_put(twl->usb1v5); - regulator_put(twl->usb1v8); - regulator_put(twl->usb3v1); - - kfree(twl->phy.otg); - kfree(twl); - - return 0; -} - -static struct platform_driver twl4030_usb_driver = { - .probe = twl4030_usb_probe, - .remove = __exit_p(twl4030_usb_remove), - .driver = { - .name = "twl4030_usb", - .owner = THIS_MODULE, - }, -}; - -static int __init twl4030_usb_init(void) -{ - return platform_driver_register(&twl4030_usb_driver); -} -subsys_initcall(twl4030_usb_init); - -static void __exit twl4030_usb_exit(void) -{ - platform_driver_unregister(&twl4030_usb_driver); -} -module_exit(twl4030_usb_exit); - -MODULE_ALIAS("platform:twl4030_usb"); -MODULE_AUTHOR("Texas Instruments, Inc, Nokia Corporation"); -MODULE_DESCRIPTION("TWL4030 USB transceiver driver"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/otg/twl6030-usb.c b/ANDROID_3.4.5/drivers/usb/otg/twl6030-usb.c deleted file mode 100644 index e3fa387c..00000000 --- a/ANDROID_3.4.5/drivers/usb/otg/twl6030-usb.c +++ /dev/null @@ -1,539 +0,0 @@ -/* - * twl6030_usb - TWL6030 USB transceiver, talking to OMAP OTG driver. - * - * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Author: Hema HK - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* usb register definitions */ -#define USB_VENDOR_ID_LSB 0x00 -#define USB_VENDOR_ID_MSB 0x01 -#define USB_PRODUCT_ID_LSB 0x02 -#define USB_PRODUCT_ID_MSB 0x03 -#define USB_VBUS_CTRL_SET 0x04 -#define USB_VBUS_CTRL_CLR 0x05 -#define USB_ID_CTRL_SET 0x06 -#define USB_ID_CTRL_CLR 0x07 -#define USB_VBUS_INT_SRC 0x08 -#define USB_VBUS_INT_LATCH_SET 0x09 -#define USB_VBUS_INT_LATCH_CLR 0x0A -#define USB_VBUS_INT_EN_LO_SET 0x0B -#define USB_VBUS_INT_EN_LO_CLR 0x0C -#define USB_VBUS_INT_EN_HI_SET 0x0D -#define USB_VBUS_INT_EN_HI_CLR 0x0E -#define USB_ID_INT_SRC 0x0F -#define USB_ID_INT_LATCH_SET 0x10 -#define USB_ID_INT_LATCH_CLR 0x11 - -#define USB_ID_INT_EN_LO_SET 0x12 -#define USB_ID_INT_EN_LO_CLR 0x13 -#define USB_ID_INT_EN_HI_SET 0x14 -#define USB_ID_INT_EN_HI_CLR 0x15 -#define USB_OTG_ADP_CTRL 0x16 -#define USB_OTG_ADP_HIGH 0x17 -#define USB_OTG_ADP_LOW 0x18 -#define USB_OTG_ADP_RISE 0x19 -#define USB_OTG_REVISION 0x1A - -/* to be moved to LDO */ -#define TWL6030_MISC2 0xE5 -#define TWL6030_CFG_LDO_PD2 0xF5 -#define TWL6030_BACKUP_REG 0xFA - -#define STS_HW_CONDITIONS 0x21 - -/* In module TWL6030_MODULE_PM_MASTER */ -#define STS_HW_CONDITIONS 0x21 -#define STS_USB_ID BIT(2) - -/* In module TWL6030_MODULE_PM_RECEIVER */ -#define VUSB_CFG_TRANS 0x71 -#define VUSB_CFG_STATE 0x72 -#define VUSB_CFG_VOLTAGE 0x73 - -/* in module TWL6030_MODULE_MAIN_CHARGE */ - -#define CHARGERUSB_CTRL1 0x8 - -#define CONTROLLER_STAT1 0x03 -#define VBUS_DET BIT(2) - -struct twl6030_usb { - struct usb_phy phy; - struct device *dev; - - /* for vbus reporting with irqs disabled */ - spinlock_t lock; - - struct regulator *usb3v3; - - /* used to set vbus, in atomic path */ - struct work_struct set_vbus_work; - - int irq1; - int irq2; - u8 linkstat; - u8 asleep; - bool irq_enabled; - bool vbus_enable; - unsigned long features; -}; - -#define phy_to_twl(x) container_of((x), struct twl6030_usb, phy) - -/*-------------------------------------------------------------------------*/ - -static inline int twl6030_writeb(struct twl6030_usb *twl, u8 module, - u8 data, u8 address) -{ - int ret = 0; - - ret = twl_i2c_write_u8(module, data, address); - if (ret < 0) - dev_err(twl->dev, - "Write[0x%x] Error %d\n", address, ret); - return ret; -} - -static inline u8 twl6030_readb(struct twl6030_usb *twl, u8 module, u8 address) -{ - u8 data, ret = 0; - - ret = twl_i2c_read_u8(module, &data, address); - if (ret >= 0) - ret = data; - else - dev_err(twl->dev, - "readb[0x%x,0x%x] Error %d\n", - module, address, ret); - return ret; -} - -static int twl6030_phy_init(struct usb_phy *x) -{ - struct twl6030_usb *twl; - struct device *dev; - struct twl4030_usb_data *pdata; - - twl = phy_to_twl(x); - dev = twl->dev; - pdata = dev->platform_data; - - if (twl->linkstat == USB_EVENT_ID) - pdata->phy_power(twl->dev, 1, 1); - else - pdata->phy_power(twl->dev, 0, 1); - - return 0; -} - -static void twl6030_phy_shutdown(struct usb_phy *x) -{ - struct twl6030_usb *twl; - struct device *dev; - struct twl4030_usb_data *pdata; - - twl = phy_to_twl(x); - dev = twl->dev; - pdata = dev->platform_data; - pdata->phy_power(twl->dev, 0, 0); -} - -static int twl6030_phy_suspend(struct usb_phy *x, int suspend) -{ - struct twl6030_usb *twl = phy_to_twl(x); - struct device *dev = twl->dev; - struct twl4030_usb_data *pdata = dev->platform_data; - - pdata->phy_suspend(dev, suspend); - - return 0; -} - -static int twl6030_start_srp(struct usb_otg *otg) -{ - struct twl6030_usb *twl = phy_to_twl(otg->phy); - - twl6030_writeb(twl, TWL_MODULE_USB, 0x24, USB_VBUS_CTRL_SET); - twl6030_writeb(twl, TWL_MODULE_USB, 0x84, USB_VBUS_CTRL_SET); - - mdelay(100); - twl6030_writeb(twl, TWL_MODULE_USB, 0xa0, USB_VBUS_CTRL_CLR); - - return 0; -} - -static int twl6030_usb_ldo_init(struct twl6030_usb *twl) -{ - char *regulator_name; - - if (twl->features & TWL6025_SUBCLASS) - regulator_name = "ldousb"; - else - regulator_name = "vusb"; - - /* Set to OTG_REV 1.3 and turn on the ID_WAKEUP_COMP */ - twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_BACKUP_REG); - - /* Program CFG_LDO_PD2 register and set VUSB bit */ - twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_CFG_LDO_PD2); - - /* Program MISC2 register and set bit VUSB_IN_VBAT */ - twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x10, TWL6030_MISC2); - - twl->usb3v3 = regulator_get(twl->dev, regulator_name); - if (IS_ERR(twl->usb3v3)) - return -ENODEV; - - /* Program the USB_VBUS_CTRL_SET and set VBUS_ACT_COMP bit */ - twl6030_writeb(twl, TWL_MODULE_USB, 0x4, USB_VBUS_CTRL_SET); - - /* - * Program the USB_ID_CTRL_SET register to enable GND drive - * and the ID comparators - */ - twl6030_writeb(twl, TWL_MODULE_USB, 0x14, USB_ID_CTRL_SET); - - return 0; -} - -static ssize_t twl6030_usb_vbus_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct twl6030_usb *twl = dev_get_drvdata(dev); - unsigned long flags; - int ret = -EINVAL; - - spin_lock_irqsave(&twl->lock, flags); - - switch (twl->linkstat) { - case USB_EVENT_VBUS: - ret = snprintf(buf, PAGE_SIZE, "vbus\n"); - break; - case USB_EVENT_ID: - ret = snprintf(buf, PAGE_SIZE, "id\n"); - break; - case USB_EVENT_NONE: - ret = snprintf(buf, PAGE_SIZE, "none\n"); - break; - default: - ret = snprintf(buf, PAGE_SIZE, "UNKNOWN\n"); - } - spin_unlock_irqrestore(&twl->lock, flags); - - return ret; -} -static DEVICE_ATTR(vbus, 0444, twl6030_usb_vbus_show, NULL); - -static irqreturn_t twl6030_usb_irq(int irq, void *_twl) -{ - struct twl6030_usb *twl = _twl; - struct usb_otg *otg = twl->phy.otg; - int status; - u8 vbus_state, hw_state; - - hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS); - - vbus_state = twl6030_readb(twl, TWL_MODULE_MAIN_CHARGE, - CONTROLLER_STAT1); - if (!(hw_state & STS_USB_ID)) { - if (vbus_state & VBUS_DET) { - regulator_enable(twl->usb3v3); - twl->asleep = 1; - status = USB_EVENT_VBUS; - otg->default_a = false; - twl->phy.state = OTG_STATE_B_IDLE; - twl->linkstat = status; - twl->phy.last_event = status; - atomic_notifier_call_chain(&twl->phy.notifier, - status, otg->gadget); - } else { - status = USB_EVENT_NONE; - twl->linkstat = status; - twl->phy.last_event = status; - atomic_notifier_call_chain(&twl->phy.notifier, - status, otg->gadget); - if (twl->asleep) { - regulator_disable(twl->usb3v3); - twl->asleep = 0; - } - } - } - sysfs_notify(&twl->dev->kobj, NULL, "vbus"); - - return IRQ_HANDLED; -} - -static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl) -{ - struct twl6030_usb *twl = _twl; - struct usb_otg *otg = twl->phy.otg; - int status = USB_EVENT_NONE; - u8 hw_state; - - hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS); - - if (hw_state & STS_USB_ID) { - - regulator_enable(twl->usb3v3); - twl->asleep = 1; - twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_CLR, 0x1); - twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET, - 0x10); - status = USB_EVENT_ID; - otg->default_a = true; - twl->phy.state = OTG_STATE_A_IDLE; - twl->linkstat = status; - twl->phy.last_event = status; - atomic_notifier_call_chain(&twl->phy.notifier, status, - otg->gadget); - } else { - twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_CLR, - 0x10); - twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET, - 0x1); - } - twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_LATCH_CLR, status); - - return IRQ_HANDLED; -} - -static int twl6030_set_peripheral(struct usb_otg *otg, - struct usb_gadget *gadget) -{ - if (!otg) - return -ENODEV; - - otg->gadget = gadget; - if (!gadget) - otg->phy->state = OTG_STATE_UNDEFINED; - - return 0; -} - -static int twl6030_enable_irq(struct usb_phy *x) -{ - struct twl6030_usb *twl = phy_to_twl(x); - - twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET, 0x1); - twl6030_interrupt_unmask(0x05, REG_INT_MSK_LINE_C); - twl6030_interrupt_unmask(0x05, REG_INT_MSK_STS_C); - - twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK, - REG_INT_MSK_LINE_C); - twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK, - REG_INT_MSK_STS_C); - twl6030_usb_irq(twl->irq2, twl); - twl6030_usbotg_irq(twl->irq1, twl); - - return 0; -} - -static void otg_set_vbus_work(struct work_struct *data) -{ - struct twl6030_usb *twl = container_of(data, struct twl6030_usb, - set_vbus_work); - - /* - * Start driving VBUS. Set OPA_MODE bit in CHARGERUSB_CTRL1 - * register. This enables boost mode. - */ - - if (twl->vbus_enable) - twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x40, - CHARGERUSB_CTRL1); - else - twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x00, - CHARGERUSB_CTRL1); -} - -static int twl6030_set_vbus(struct usb_otg *otg, bool enabled) -{ - struct twl6030_usb *twl = phy_to_twl(otg->phy); - - twl->vbus_enable = enabled; - schedule_work(&twl->set_vbus_work); - - return 0; -} - -static int twl6030_set_host(struct usb_otg *otg, struct usb_bus *host) -{ - if (!otg) - return -ENODEV; - - otg->host = host; - if (!host) - otg->phy->state = OTG_STATE_UNDEFINED; - return 0; -} - -static int __devinit twl6030_usb_probe(struct platform_device *pdev) -{ - struct twl6030_usb *twl; - int status, err; - struct twl4030_usb_data *pdata; - struct usb_otg *otg; - struct device *dev = &pdev->dev; - pdata = dev->platform_data; - - twl = kzalloc(sizeof *twl, GFP_KERNEL); - if (!twl) - return -ENOMEM; - - otg = kzalloc(sizeof *otg, GFP_KERNEL); - if (!otg) { - kfree(twl); - return -ENOMEM; - } - - twl->dev = &pdev->dev; - twl->irq1 = platform_get_irq(pdev, 0); - twl->irq2 = platform_get_irq(pdev, 1); - twl->features = pdata->features; - - twl->phy.dev = twl->dev; - twl->phy.label = "twl6030"; - twl->phy.otg = otg; - twl->phy.init = twl6030_phy_init; - twl->phy.shutdown = twl6030_phy_shutdown; - twl->phy.set_suspend = twl6030_phy_suspend; - - otg->phy = &twl->phy; - otg->set_host = twl6030_set_host; - otg->set_peripheral = twl6030_set_peripheral; - otg->set_vbus = twl6030_set_vbus; - otg->start_srp = twl6030_start_srp; - - /* init spinlock for workqueue */ - spin_lock_init(&twl->lock); - - err = twl6030_usb_ldo_init(twl); - if (err) { - dev_err(&pdev->dev, "ldo init failed\n"); - kfree(otg); - kfree(twl); - return err; - } - usb_set_transceiver(&twl->phy); - - platform_set_drvdata(pdev, twl); - if (device_create_file(&pdev->dev, &dev_attr_vbus)) - dev_warn(&pdev->dev, "could not create sysfs file\n"); - - ATOMIC_INIT_NOTIFIER_HEAD(&twl->phy.notifier); - - INIT_WORK(&twl->set_vbus_work, otg_set_vbus_work); - - twl->irq_enabled = true; - status = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq, - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, - "twl6030_usb", twl); - if (status < 0) { - dev_err(&pdev->dev, "can't get IRQ %d, err %d\n", - twl->irq1, status); - device_remove_file(twl->dev, &dev_attr_vbus); - kfree(otg); - kfree(twl); - return status; - } - - status = request_threaded_irq(twl->irq2, NULL, twl6030_usb_irq, - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, - "twl6030_usb", twl); - if (status < 0) { - dev_err(&pdev->dev, "can't get IRQ %d, err %d\n", - twl->irq2, status); - free_irq(twl->irq1, twl); - device_remove_file(twl->dev, &dev_attr_vbus); - kfree(otg); - kfree(twl); - return status; - } - - twl->asleep = 0; - pdata->phy_init(dev); - twl6030_phy_suspend(&twl->phy, 0); - twl6030_enable_irq(&twl->phy); - dev_info(&pdev->dev, "Initialized TWL6030 USB module\n"); - - return 0; -} - -static int __exit twl6030_usb_remove(struct platform_device *pdev) -{ - struct twl6030_usb *twl = platform_get_drvdata(pdev); - - struct twl4030_usb_data *pdata; - struct device *dev = &pdev->dev; - pdata = dev->platform_data; - - twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK, - REG_INT_MSK_LINE_C); - twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK, - REG_INT_MSK_STS_C); - free_irq(twl->irq1, twl); - free_irq(twl->irq2, twl); - regulator_put(twl->usb3v3); - pdata->phy_exit(twl->dev); - device_remove_file(twl->dev, &dev_attr_vbus); - cancel_work_sync(&twl->set_vbus_work); - kfree(twl->phy.otg); - kfree(twl); - - return 0; -} - -static struct platform_driver twl6030_usb_driver = { - .probe = twl6030_usb_probe, - .remove = __exit_p(twl6030_usb_remove), - .driver = { - .name = "twl6030_usb", - .owner = THIS_MODULE, - }, -}; - -static int __init twl6030_usb_init(void) -{ - return platform_driver_register(&twl6030_usb_driver); -} -subsys_initcall(twl6030_usb_init); - -static void __exit twl6030_usb_exit(void) -{ - platform_driver_unregister(&twl6030_usb_driver); -} -module_exit(twl6030_usb_exit); - -MODULE_ALIAS("platform:twl6030_usb"); -MODULE_AUTHOR("Hema HK "); -MODULE_DESCRIPTION("TWL6030 USB transceiver driver"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/otg/ulpi.c b/ANDROID_3.4.5/drivers/usb/otg/ulpi.c deleted file mode 100644 index 217339dd..00000000 --- a/ANDROID_3.4.5/drivers/usb/otg/ulpi.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Generic ULPI USB transceiver support - * - * Copyright (C) 2009 Daniel Mack - * - * Based on sources from - * - * Sascha Hauer - * Freescale Semiconductors - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include - - -struct ulpi_info { - unsigned int id; - char *name; -}; - -#define ULPI_ID(vendor, product) (((vendor) << 16) | (product)) -#define ULPI_INFO(_id, _name) \ - { \ - .id = (_id), \ - .name = (_name), \ - } - -/* ULPI hardcoded IDs, used for probing */ -static struct ulpi_info ulpi_ids[] = { - ULPI_INFO(ULPI_ID(0x04cc, 0x1504), "NXP ISP1504"), - ULPI_INFO(ULPI_ID(0x0424, 0x0006), "SMSC USB331x"), -}; - -static int ulpi_set_otg_flags(struct usb_phy *phy) -{ - unsigned int flags = ULPI_OTG_CTRL_DP_PULLDOWN | - ULPI_OTG_CTRL_DM_PULLDOWN; - - if (phy->flags & ULPI_OTG_ID_PULLUP) - flags |= ULPI_OTG_CTRL_ID_PULLUP; - - /* - * ULPI Specification rev.1.1 default - * for Dp/DmPulldown is enabled. - */ - if (phy->flags & ULPI_OTG_DP_PULLDOWN_DIS) - flags &= ~ULPI_OTG_CTRL_DP_PULLDOWN; - - if (phy->flags & ULPI_OTG_DM_PULLDOWN_DIS) - flags &= ~ULPI_OTG_CTRL_DM_PULLDOWN; - - if (phy->flags & ULPI_OTG_EXTVBUSIND) - flags |= ULPI_OTG_CTRL_EXTVBUSIND; - - return usb_phy_io_write(phy, flags, ULPI_OTG_CTRL); -} - -static int ulpi_set_fc_flags(struct usb_phy *phy) -{ - unsigned int flags = 0; - - /* - * ULPI Specification rev.1.1 default - * for XcvrSelect is Full Speed. - */ - if (phy->flags & ULPI_FC_HS) - flags |= ULPI_FUNC_CTRL_HIGH_SPEED; - else if (phy->flags & ULPI_FC_LS) - flags |= ULPI_FUNC_CTRL_LOW_SPEED; - else if (phy->flags & ULPI_FC_FS4LS) - flags |= ULPI_FUNC_CTRL_FS4LS; - else - flags |= ULPI_FUNC_CTRL_FULL_SPEED; - - if (phy->flags & ULPI_FC_TERMSEL) - flags |= ULPI_FUNC_CTRL_TERMSELECT; - - /* - * ULPI Specification rev.1.1 default - * for OpMode is Normal Operation. - */ - if (phy->flags & ULPI_FC_OP_NODRV) - flags |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING; - else if (phy->flags & ULPI_FC_OP_DIS_NRZI) - flags |= ULPI_FUNC_CTRL_OPMODE_DISABLE_NRZI; - else if (phy->flags & ULPI_FC_OP_NSYNC_NEOP) - flags |= ULPI_FUNC_CTRL_OPMODE_NOSYNC_NOEOP; - else - flags |= ULPI_FUNC_CTRL_OPMODE_NORMAL; - - /* - * ULPI Specification rev.1.1 default - * for SuspendM is Powered. - */ - flags |= ULPI_FUNC_CTRL_SUSPENDM; - - return usb_phy_io_write(phy, flags, ULPI_FUNC_CTRL); -} - -static int ulpi_set_ic_flags(struct usb_phy *phy) -{ - unsigned int flags = 0; - - if (phy->flags & ULPI_IC_AUTORESUME) - flags |= ULPI_IFC_CTRL_AUTORESUME; - - if (phy->flags & ULPI_IC_EXTVBUS_INDINV) - flags |= ULPI_IFC_CTRL_EXTERNAL_VBUS; - - if (phy->flags & ULPI_IC_IND_PASSTHRU) - flags |= ULPI_IFC_CTRL_PASSTHRU; - - if (phy->flags & ULPI_IC_PROTECT_DIS) - flags |= ULPI_IFC_CTRL_PROTECT_IFC_DISABLE; - - return usb_phy_io_write(phy, flags, ULPI_IFC_CTRL); -} - -static int ulpi_set_flags(struct usb_phy *phy) -{ - int ret; - - ret = ulpi_set_otg_flags(phy); - if (ret) - return ret; - - ret = ulpi_set_ic_flags(phy); - if (ret) - return ret; - - return ulpi_set_fc_flags(phy); -} - -static int ulpi_check_integrity(struct usb_phy *phy) -{ - int ret, i; - unsigned int val = 0x55; - - for (i = 0; i < 2; i++) { - ret = usb_phy_io_write(phy, val, ULPI_SCRATCH); - if (ret < 0) - return ret; - - ret = usb_phy_io_read(phy, ULPI_SCRATCH); - if (ret < 0) - return ret; - - if (ret != val) { - pr_err("ULPI integrity check: failed!"); - return -ENODEV; - } - val = val << 1; - } - - pr_info("ULPI integrity check: passed.\n"); - - return 0; -} - -static int ulpi_init(struct usb_phy *phy) -{ - int i, vid, pid, ret; - u32 ulpi_id = 0; - - for (i = 0; i < 4; i++) { - ret = usb_phy_io_read(phy, ULPI_PRODUCT_ID_HIGH - i); - if (ret < 0) - return ret; - ulpi_id = (ulpi_id << 8) | ret; - } - vid = ulpi_id & 0xffff; - pid = ulpi_id >> 16; - - pr_info("ULPI transceiver vendor/product ID 0x%04x/0x%04x\n", vid, pid); - - for (i = 0; i < ARRAY_SIZE(ulpi_ids); i++) { - if (ulpi_ids[i].id == ULPI_ID(vid, pid)) { - pr_info("Found %s ULPI transceiver.\n", - ulpi_ids[i].name); - break; - } - } - - ret = ulpi_check_integrity(phy); - if (ret) - return ret; - - return ulpi_set_flags(phy); -} - -static int ulpi_set_host(struct usb_otg *otg, struct usb_bus *host) -{ - struct usb_phy *phy = otg->phy; - unsigned int flags = usb_phy_io_read(phy, ULPI_IFC_CTRL); - - if (!host) { - otg->host = NULL; - return 0; - } - - otg->host = host; - - flags &= ~(ULPI_IFC_CTRL_6_PIN_SERIAL_MODE | - ULPI_IFC_CTRL_3_PIN_SERIAL_MODE | - ULPI_IFC_CTRL_CARKITMODE); - - if (phy->flags & ULPI_IC_6PIN_SERIAL) - flags |= ULPI_IFC_CTRL_6_PIN_SERIAL_MODE; - else if (phy->flags & ULPI_IC_3PIN_SERIAL) - flags |= ULPI_IFC_CTRL_3_PIN_SERIAL_MODE; - else if (phy->flags & ULPI_IC_CARKIT) - flags |= ULPI_IFC_CTRL_CARKITMODE; - - return usb_phy_io_write(phy, flags, ULPI_IFC_CTRL); -} - -static int ulpi_set_vbus(struct usb_otg *otg, bool on) -{ - struct usb_phy *phy = otg->phy; - unsigned int flags = usb_phy_io_read(phy, ULPI_OTG_CTRL); - - flags &= ~(ULPI_OTG_CTRL_DRVVBUS | ULPI_OTG_CTRL_DRVVBUS_EXT); - - if (on) { - if (phy->flags & ULPI_OTG_DRVVBUS) - flags |= ULPI_OTG_CTRL_DRVVBUS; - - if (phy->flags & ULPI_OTG_DRVVBUS_EXT) - flags |= ULPI_OTG_CTRL_DRVVBUS_EXT; - } - - return usb_phy_io_write(phy, flags, ULPI_OTG_CTRL); -} - -struct usb_phy * -otg_ulpi_create(struct usb_phy_io_ops *ops, - unsigned int flags) -{ - struct usb_phy *phy; - struct usb_otg *otg; - - phy = kzalloc(sizeof(*phy), GFP_KERNEL); - if (!phy) - return NULL; - - otg = kzalloc(sizeof(*otg), GFP_KERNEL); - if (!otg) { - kfree(phy); - return NULL; - } - - phy->label = "ULPI"; - phy->flags = flags; - phy->io_ops = ops; - phy->otg = otg; - phy->init = ulpi_init; - - otg->phy = phy; - otg->set_host = ulpi_set_host; - otg->set_vbus = ulpi_set_vbus; - - return phy; -} -EXPORT_SYMBOL_GPL(otg_ulpi_create); - diff --git a/ANDROID_3.4.5/drivers/usb/otg/ulpi_viewport.c b/ANDROID_3.4.5/drivers/usb/otg/ulpi_viewport.c deleted file mode 100644 index c5ba7e54..00000000 --- a/ANDROID_3.4.5/drivers/usb/otg/ulpi_viewport.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2011 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * 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. - * - */ - -#include -#include -#include -#include -#include - -#define ULPI_VIEW_WAKEUP (1 << 31) -#define ULPI_VIEW_RUN (1 << 30) -#define ULPI_VIEW_WRITE (1 << 29) -#define ULPI_VIEW_READ (0 << 29) -#define ULPI_VIEW_ADDR(x) (((x) & 0xff) << 16) -#define ULPI_VIEW_DATA_READ(x) (((x) >> 8) & 0xff) -#define ULPI_VIEW_DATA_WRITE(x) ((x) & 0xff) - -static int ulpi_viewport_wait(void __iomem *view, u32 mask) -{ - unsigned long usec = 2000; - - while (usec--) { - if (!(readl(view) & mask)) - return 0; - - udelay(1); - }; - - return -ETIMEDOUT; -} - -static int ulpi_viewport_read(struct usb_phy *otg, u32 reg) -{ - int ret; - void __iomem *view = otg->io_priv; - - writel(ULPI_VIEW_WAKEUP | ULPI_VIEW_WRITE, view); - ret = ulpi_viewport_wait(view, ULPI_VIEW_WAKEUP); - if (ret) - return ret; - - writel(ULPI_VIEW_RUN | ULPI_VIEW_READ | ULPI_VIEW_ADDR(reg), view); - ret = ulpi_viewport_wait(view, ULPI_VIEW_RUN); - if (ret) - return ret; - - return ULPI_VIEW_DATA_READ(readl(view)); -} - -static int ulpi_viewport_write(struct usb_phy *otg, u32 val, u32 reg) -{ - int ret; - void __iomem *view = otg->io_priv; - - writel(ULPI_VIEW_WAKEUP | ULPI_VIEW_WRITE, view); - ret = ulpi_viewport_wait(view, ULPI_VIEW_WAKEUP); - if (ret) - return ret; - - writel(ULPI_VIEW_RUN | ULPI_VIEW_WRITE | ULPI_VIEW_DATA_WRITE(val) | - ULPI_VIEW_ADDR(reg), view); - - return ulpi_viewport_wait(view, ULPI_VIEW_RUN); -} - -struct usb_phy_io_ops ulpi_viewport_access_ops = { - .read = ulpi_viewport_read, - .write = ulpi_viewport_write, -}; diff --git a/ANDROID_3.4.5/drivers/usb/renesas_usbhs/Kconfig b/ANDROID_3.4.5/drivers/usb/renesas_usbhs/Kconfig deleted file mode 100644 index 6f4afa43..00000000 --- a/ANDROID_3.4.5/drivers/usb/renesas_usbhs/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -# -# Renesas USBHS Controller Drivers -# - -config USB_RENESAS_USBHS - tristate 'Renesas USBHS controller' - depends on USB && USB_GADGET - default n - help - Renesas USBHS is a discrete USB host and peripheral controller chip - that supports both full and high speed USB 2.0 data transfers. - It has nine or more configurable endpoints, and endpoint zero. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "renesas_usbhs" diff --git a/ANDROID_3.4.5/drivers/usb/renesas_usbhs/Makefile b/ANDROID_3.4.5/drivers/usb/renesas_usbhs/Makefile deleted file mode 100644 index bc8aef43..00000000 --- a/ANDROID_3.4.5/drivers/usb/renesas_usbhs/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# for Renesas USB -# - -obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs.o - -renesas_usbhs-y := common.o mod.o pipe.o fifo.o - -ifneq ($(CONFIG_USB_RENESAS_USBHS_HCD),) - renesas_usbhs-y += mod_host.o -endif - -ifneq ($(CONFIG_USB_RENESAS_USBHS_UDC),) - renesas_usbhs-y += mod_gadget.o -endif diff --git a/ANDROID_3.4.5/drivers/usb/renesas_usbhs/common.c b/ANDROID_3.4.5/drivers/usb/renesas_usbhs/common.c deleted file mode 100644 index a165490b..00000000 --- a/ANDROID_3.4.5/drivers/usb/renesas_usbhs/common.c +++ /dev/null @@ -1,648 +0,0 @@ -/* - * Renesas USB driver - * - * Copyright (C) 2011 Renesas Solutions Corp. - * Kuninori Morimoto - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -#include -#include -#include -#include -#include -#include "./common.h" - -/* - * image of renesas_usbhs - * - * ex) gadget case - - * mod.c - * mod_gadget.c - * mod_host.c pipe.c fifo.c - * - * +-------+ +-----------+ - * | pipe0 |------>| fifo pio | - * +------------+ +-------+ +-----------+ - * | mod_gadget |=====> | pipe1 |--+ - * +------------+ +-------+ | +-----------+ - * | pipe2 | | +-| fifo dma0 | - * +------------+ +-------+ | | +-----------+ - * | mod_host | | pipe3 |<-|--+ - * +------------+ +-------+ | +-----------+ - * | .... | +--->| fifo dma1 | - * | .... | +-----------+ - */ - - -#define USBHSF_RUNTIME_PWCTRL (1 << 0) - -/* status */ -#define usbhsc_flags_init(p) do {(p)->flags = 0; } while (0) -#define usbhsc_flags_set(p, b) ((p)->flags |= (b)) -#define usbhsc_flags_clr(p, b) ((p)->flags &= ~(b)) -#define usbhsc_flags_has(p, b) ((p)->flags & (b)) - -/* - * platform call back - * - * renesas usb support platform callback function. - * Below macro call it. - * if platform doesn't have callback, it return 0 (no error) - */ -#define usbhs_platform_call(priv, func, args...)\ - (!(priv) ? -ENODEV : \ - !((priv)->pfunc.func) ? 0 : \ - (priv)->pfunc.func(args)) - -/* - * common functions - */ -u16 usbhs_read(struct usbhs_priv *priv, u32 reg) -{ - return ioread16(priv->base + reg); -} - -void usbhs_write(struct usbhs_priv *priv, u32 reg, u16 data) -{ - iowrite16(data, priv->base + reg); -} - -void usbhs_bset(struct usbhs_priv *priv, u32 reg, u16 mask, u16 data) -{ - u16 val = usbhs_read(priv, reg); - - val &= ~mask; - val |= data & mask; - - usbhs_write(priv, reg, val); -} - -struct usbhs_priv *usbhs_pdev_to_priv(struct platform_device *pdev) -{ - return dev_get_drvdata(&pdev->dev); -} - -/* - * syscfg functions - */ -static void usbhs_sys_clock_ctrl(struct usbhs_priv *priv, int enable) -{ - usbhs_bset(priv, SYSCFG, SCKE, enable ? SCKE : 0); -} - -void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable) -{ - u16 mask = DCFM | DRPD | DPRPU | HSE | USBE; - u16 val = DCFM | DRPD | HSE | USBE; - int has_otg = usbhs_get_dparam(priv, has_otg); - - if (has_otg) - usbhs_bset(priv, DVSTCTR, (EXTLP | PWEN), (EXTLP | PWEN)); - - /* - * if enable - * - * - select Host mode - * - D+ Line/D- Line Pull-down - */ - usbhs_bset(priv, SYSCFG, mask, enable ? val : 0); -} - -void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable) -{ - u16 mask = DCFM | DRPD | DPRPU | HSE | USBE; - u16 val = DPRPU | HSE | USBE; - - /* - * if enable - * - * - select Function mode - * - D+ Line Pull-up - */ - usbhs_bset(priv, SYSCFG, mask, enable ? val : 0); -} - -void usbhs_sys_set_test_mode(struct usbhs_priv *priv, u16 mode) -{ - usbhs_write(priv, TESTMODE, mode); -} - -/* - * frame functions - */ -int usbhs_frame_get_num(struct usbhs_priv *priv) -{ - return usbhs_read(priv, FRMNUM) & FRNM_MASK; -} - -/* - * usb request functions - */ -void usbhs_usbreq_get_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req) -{ - u16 val; - - val = usbhs_read(priv, USBREQ); - req->bRequest = (val >> 8) & 0xFF; - req->bRequestType = (val >> 0) & 0xFF; - - req->wValue = usbhs_read(priv, USBVAL); - req->wIndex = usbhs_read(priv, USBINDX); - req->wLength = usbhs_read(priv, USBLENG); -} - -void usbhs_usbreq_set_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req) -{ - usbhs_write(priv, USBREQ, (req->bRequest << 8) | req->bRequestType); - usbhs_write(priv, USBVAL, req->wValue); - usbhs_write(priv, USBINDX, req->wIndex); - usbhs_write(priv, USBLENG, req->wLength); - - usbhs_bset(priv, DCPCTR, SUREQ, SUREQ); -} - -/* - * bus/vbus functions - */ -void usbhs_bus_send_sof_enable(struct usbhs_priv *priv) -{ - u16 status = usbhs_read(priv, DVSTCTR) & (USBRST | UACT); - - if (status != USBRST) { - struct device *dev = usbhs_priv_to_dev(priv); - dev_err(dev, "usbhs should be reset\n"); - } - - usbhs_bset(priv, DVSTCTR, (USBRST | UACT), UACT); -} - -void usbhs_bus_send_reset(struct usbhs_priv *priv) -{ - usbhs_bset(priv, DVSTCTR, (USBRST | UACT), USBRST); -} - -int usbhs_bus_get_speed(struct usbhs_priv *priv) -{ - u16 dvstctr = usbhs_read(priv, DVSTCTR); - - switch (RHST & dvstctr) { - case RHST_LOW_SPEED: - return USB_SPEED_LOW; - case RHST_FULL_SPEED: - return USB_SPEED_FULL; - case RHST_HIGH_SPEED: - return USB_SPEED_HIGH; - } - - return USB_SPEED_UNKNOWN; -} - -int usbhs_vbus_ctrl(struct usbhs_priv *priv, int enable) -{ - struct platform_device *pdev = usbhs_priv_to_pdev(priv); - - return usbhs_platform_call(priv, set_vbus, pdev, enable); -} - -static void usbhsc_bus_init(struct usbhs_priv *priv) -{ - usbhs_write(priv, DVSTCTR, 0); - - usbhs_vbus_ctrl(priv, 0); -} - -/* - * device configuration - */ -int usbhs_set_device_config(struct usbhs_priv *priv, int devnum, - u16 upphub, u16 hubport, u16 speed) -{ - struct device *dev = usbhs_priv_to_dev(priv); - u16 usbspd = 0; - u32 reg = DEVADD0 + (2 * devnum); - - if (devnum > 10) { - dev_err(dev, "cannot set speed to unknown device %d\n", devnum); - return -EIO; - } - - if (upphub > 0xA) { - dev_err(dev, "unsupported hub number %d\n", upphub); - return -EIO; - } - - switch (speed) { - case USB_SPEED_LOW: - usbspd = USBSPD_SPEED_LOW; - break; - case USB_SPEED_FULL: - usbspd = USBSPD_SPEED_FULL; - break; - case USB_SPEED_HIGH: - usbspd = USBSPD_SPEED_HIGH; - break; - default: - dev_err(dev, "unsupported speed %d\n", speed); - return -EIO; - } - - usbhs_write(priv, reg, UPPHUB(upphub) | - HUBPORT(hubport)| - USBSPD(usbspd)); - - return 0; -} - -/* - * local functions - */ -static void usbhsc_set_buswait(struct usbhs_priv *priv) -{ - int wait = usbhs_get_dparam(priv, buswait_bwait); - - /* set bus wait if platform have */ - if (wait) - usbhs_bset(priv, BUSWAIT, 0x000F, wait); -} - -/* - * platform default param - */ -static u32 usbhsc_default_pipe_type[] = { - USB_ENDPOINT_XFER_CONTROL, - USB_ENDPOINT_XFER_ISOC, - USB_ENDPOINT_XFER_ISOC, - USB_ENDPOINT_XFER_BULK, - USB_ENDPOINT_XFER_BULK, - USB_ENDPOINT_XFER_BULK, - USB_ENDPOINT_XFER_INT, - USB_ENDPOINT_XFER_INT, - USB_ENDPOINT_XFER_INT, - USB_ENDPOINT_XFER_INT, -}; - -/* - * power control - */ -static void usbhsc_power_ctrl(struct usbhs_priv *priv, int enable) -{ - struct platform_device *pdev = usbhs_priv_to_pdev(priv); - struct device *dev = usbhs_priv_to_dev(priv); - - if (enable) { - /* enable PM */ - pm_runtime_get_sync(dev); - - /* enable platform power */ - usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable); - - /* USB on */ - usbhs_sys_clock_ctrl(priv, enable); - } else { - /* USB off */ - usbhs_sys_clock_ctrl(priv, enable); - - /* disable platform power */ - usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable); - - /* disable PM */ - pm_runtime_put_sync(dev); - } -} - -/* - * hotplug - */ -static void usbhsc_hotplug(struct usbhs_priv *priv) -{ - struct platform_device *pdev = usbhs_priv_to_pdev(priv); - struct usbhs_mod *mod = usbhs_mod_get_current(priv); - int id; - int enable; - int ret; - - /* - * get vbus status from platform - */ - enable = usbhs_platform_call(priv, get_vbus, pdev); - - /* - * get id from platform - */ - id = usbhs_platform_call(priv, get_id, pdev); - - if (enable && !mod) { - ret = usbhs_mod_change(priv, id); - if (ret < 0) - return; - - dev_dbg(&pdev->dev, "%s enable\n", __func__); - - /* power on */ - if (usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) - usbhsc_power_ctrl(priv, enable); - - /* bus init */ - usbhsc_set_buswait(priv); - usbhsc_bus_init(priv); - - /* module start */ - usbhs_mod_call(priv, start, priv); - - } else if (!enable && mod) { - dev_dbg(&pdev->dev, "%s disable\n", __func__); - - /* module stop */ - usbhs_mod_call(priv, stop, priv); - - /* bus init */ - usbhsc_bus_init(priv); - - /* power off */ - if (usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) - usbhsc_power_ctrl(priv, enable); - - usbhs_mod_change(priv, -1); - - /* reset phy for next connection */ - usbhs_platform_call(priv, phy_reset, pdev); - } -} - -/* - * notify hotplug - */ -static void usbhsc_notify_hotplug(struct work_struct *work) -{ - struct usbhs_priv *priv = container_of(work, - struct usbhs_priv, - notify_hotplug_work.work); - usbhsc_hotplug(priv); -} - -static int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev) -{ - struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); - int delay = usbhs_get_dparam(priv, detection_delay); - - /* - * This functions will be called in interrupt. - * To make sure safety context, - * use workqueue for usbhs_notify_hotplug - */ - schedule_delayed_work(&priv->notify_hotplug_work, - msecs_to_jiffies(delay)); - return 0; -} - -/* - * platform functions - */ -static int usbhs_probe(struct platform_device *pdev) -{ - struct renesas_usbhs_platform_info *info = pdev->dev.platform_data; - struct renesas_usbhs_driver_callback *dfunc; - struct usbhs_priv *priv; - struct resource *res, *irq_res; - int ret; - - /* check platform information */ - if (!info || - !info->platform_callback.get_id) { - dev_err(&pdev->dev, "no platform information\n"); - return -EINVAL; - } - - /* platform data */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res || !irq_res) { - dev_err(&pdev->dev, "Not enough Renesas USB platform resources.\n"); - return -ENODEV; - } - - /* usb private data */ - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(&pdev->dev, "Could not allocate priv\n"); - return -ENOMEM; - } - - priv->base = ioremap_nocache(res->start, resource_size(res)); - if (!priv->base) { - dev_err(&pdev->dev, "ioremap error.\n"); - ret = -ENOMEM; - goto probe_end_kfree; - } - - /* - * care platform info - */ - memcpy(&priv->pfunc, - &info->platform_callback, - sizeof(struct renesas_usbhs_platform_callback)); - memcpy(&priv->dparam, - &info->driver_param, - sizeof(struct renesas_usbhs_driver_param)); - - /* set driver callback functions for platform */ - dfunc = &info->driver_callback; - dfunc->notify_hotplug = usbhsc_drvcllbck_notify_hotplug; - - /* set default param if platform doesn't have */ - if (!priv->dparam.pipe_type) { - priv->dparam.pipe_type = usbhsc_default_pipe_type; - priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_default_pipe_type); - } - if (!priv->dparam.pio_dma_border) - priv->dparam.pio_dma_border = 64; /* 64byte */ - - /* FIXME */ - /* runtime power control ? */ - if (priv->pfunc.get_vbus) - usbhsc_flags_set(priv, USBHSF_RUNTIME_PWCTRL); - - /* - * priv settings - */ - priv->irq = irq_res->start; - if (irq_res->flags & IORESOURCE_IRQ_SHAREABLE) - priv->irqflags = IRQF_SHARED; - priv->pdev = pdev; - INIT_DELAYED_WORK(&priv->notify_hotplug_work, usbhsc_notify_hotplug); - spin_lock_init(usbhs_priv_to_lock(priv)); - - /* call pipe and module init */ - ret = usbhs_pipe_probe(priv); - if (ret < 0) - goto probe_end_iounmap; - - ret = usbhs_fifo_probe(priv); - if (ret < 0) - goto probe_end_pipe_exit; - - ret = usbhs_mod_probe(priv); - if (ret < 0) - goto probe_end_fifo_exit; - - /* dev_set_drvdata should be called after usbhs_mod_init */ - dev_set_drvdata(&pdev->dev, priv); - - /* - * deviece reset here because - * USB device might be used in boot loader. - */ - usbhs_sys_clock_ctrl(priv, 0); - - /* - * platform call - * - * USB phy setup might depend on CPU/Board. - * If platform has its callback functions, - * call it here. - */ - ret = usbhs_platform_call(priv, hardware_init, pdev); - if (ret < 0) { - dev_err(&pdev->dev, "platform prove failed.\n"); - goto probe_end_mod_exit; - } - - /* reset phy for connection */ - usbhs_platform_call(priv, phy_reset, pdev); - - /* power control */ - pm_runtime_enable(&pdev->dev); - if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) { - usbhsc_power_ctrl(priv, 1); - usbhs_mod_autonomy_mode(priv); - } - - /* - * manual call notify_hotplug for cold plug - */ - ret = usbhsc_drvcllbck_notify_hotplug(pdev); - if (ret < 0) - goto probe_end_call_remove; - - dev_info(&pdev->dev, "probed\n"); - - return ret; - -probe_end_call_remove: - usbhs_platform_call(priv, hardware_exit, pdev); -probe_end_mod_exit: - usbhs_mod_remove(priv); -probe_end_fifo_exit: - usbhs_fifo_remove(priv); -probe_end_pipe_exit: - usbhs_pipe_remove(priv); -probe_end_iounmap: - iounmap(priv->base); -probe_end_kfree: - kfree(priv); - - dev_info(&pdev->dev, "probe failed\n"); - - return ret; -} - -static int __devexit usbhs_remove(struct platform_device *pdev) -{ - struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); - struct renesas_usbhs_platform_info *info = pdev->dev.platform_data; - struct renesas_usbhs_driver_callback *dfunc = &info->driver_callback; - - dev_dbg(&pdev->dev, "usb remove\n"); - - dfunc->notify_hotplug = NULL; - - /* power off */ - if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) - usbhsc_power_ctrl(priv, 0); - - pm_runtime_disable(&pdev->dev); - - usbhs_platform_call(priv, hardware_exit, pdev); - usbhs_mod_remove(priv); - usbhs_fifo_remove(priv); - usbhs_pipe_remove(priv); - iounmap(priv->base); - kfree(priv); - - return 0; -} - -static int usbhsc_suspend(struct device *dev) -{ - struct usbhs_priv *priv = dev_get_drvdata(dev); - struct usbhs_mod *mod = usbhs_mod_get_current(priv); - - if (mod) { - usbhs_mod_call(priv, stop, priv); - usbhs_mod_change(priv, -1); - } - - if (mod || !usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) - usbhsc_power_ctrl(priv, 0); - - return 0; -} - -static int usbhsc_resume(struct device *dev) -{ - struct usbhs_priv *priv = dev_get_drvdata(dev); - struct platform_device *pdev = usbhs_priv_to_pdev(priv); - - usbhs_platform_call(priv, phy_reset, pdev); - - if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) - usbhsc_power_ctrl(priv, 1); - - usbhsc_hotplug(priv); - - return 0; -} - -static int usbhsc_runtime_nop(struct device *dev) -{ - /* Runtime PM callback shared between ->runtime_suspend() - * and ->runtime_resume(). Simply returns success. - * - * This driver re-initializes all registers after - * pm_runtime_get_sync() anyway so there is no need - * to save and restore registers here. - */ - return 0; -} - -static const struct dev_pm_ops usbhsc_pm_ops = { - .suspend = usbhsc_suspend, - .resume = usbhsc_resume, - .runtime_suspend = usbhsc_runtime_nop, - .runtime_resume = usbhsc_runtime_nop, -}; - -static struct platform_driver renesas_usbhs_driver = { - .driver = { - .name = "renesas_usbhs", - .pm = &usbhsc_pm_ops, - }, - .probe = usbhs_probe, - .remove = __devexit_p(usbhs_remove), -}; - -module_platform_driver(renesas_usbhs_driver); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Renesas USB driver"); -MODULE_AUTHOR("Kuninori Morimoto "); diff --git a/ANDROID_3.4.5/drivers/usb/renesas_usbhs/common.h b/ANDROID_3.4.5/drivers/usb/renesas_usbhs/common.h deleted file mode 100644 index 3f3ccd35..00000000 --- a/ANDROID_3.4.5/drivers/usb/renesas_usbhs/common.h +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Renesas USB driver - * - * Copyright (C) 2011 Renesas Solutions Corp. - * Kuninori Morimoto - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -#ifndef RENESAS_USB_DRIVER_H -#define RENESAS_USB_DRIVER_H - -#include -#include - -struct usbhs_priv; - -#include "./mod.h" -#include "./pipe.h" - -/* - * - * register define - * - */ -#define SYSCFG 0x0000 -#define BUSWAIT 0x0002 -#define DVSTCTR 0x0008 -#define TESTMODE 0x000C -#define CFIFO 0x0014 -#define CFIFOSEL 0x0020 -#define CFIFOCTR 0x0022 -#define D0FIFO 0x0100 -#define D0FIFOSEL 0x0028 -#define D0FIFOCTR 0x002A -#define D1FIFO 0x0120 -#define D1FIFOSEL 0x002C -#define D1FIFOCTR 0x002E -#define INTENB0 0x0030 -#define INTENB1 0x0032 -#define BRDYENB 0x0036 -#define NRDYENB 0x0038 -#define BEMPENB 0x003A -#define INTSTS0 0x0040 -#define INTSTS1 0x0042 -#define BRDYSTS 0x0046 -#define NRDYSTS 0x0048 -#define BEMPSTS 0x004A -#define FRMNUM 0x004C -#define USBREQ 0x0054 /* USB request type register */ -#define USBVAL 0x0056 /* USB request value register */ -#define USBINDX 0x0058 /* USB request index register */ -#define USBLENG 0x005A /* USB request length register */ -#define DCPCFG 0x005C -#define DCPMAXP 0x005E -#define DCPCTR 0x0060 -#define PIPESEL 0x0064 -#define PIPECFG 0x0068 -#define PIPEBUF 0x006A -#define PIPEMAXP 0x006C -#define PIPEPERI 0x006E -#define PIPEnCTR 0x0070 -#define PIPE1TRE 0x0090 -#define PIPE1TRN 0x0092 -#define PIPE2TRE 0x0094 -#define PIPE2TRN 0x0096 -#define PIPE3TRE 0x0098 -#define PIPE3TRN 0x009A -#define PIPE4TRE 0x009C -#define PIPE4TRN 0x009E -#define PIPE5TRE 0x00A0 -#define PIPE5TRN 0x00A2 -#define PIPEBTRE 0x00A4 -#define PIPEBTRN 0x00A6 -#define PIPECTRE 0x00A8 -#define PIPECTRN 0x00AA -#define PIPEDTRE 0x00AC -#define PIPEDTRN 0x00AE -#define PIPEETRE 0x00B0 -#define PIPEETRN 0x00B2 -#define PIPEFTRE 0x00B4 -#define PIPEFTRN 0x00B6 -#define PIPE9TRE 0x00B8 -#define PIPE9TRN 0x00BA -#define PIPEATRE 0x00BC -#define PIPEATRN 0x00BE -#define DEVADD0 0x00D0 /* Device address n configuration */ -#define DEVADD1 0x00D2 -#define DEVADD2 0x00D4 -#define DEVADD3 0x00D6 -#define DEVADD4 0x00D8 -#define DEVADD5 0x00DA -#define DEVADD6 0x00DC -#define DEVADD7 0x00DE -#define DEVADD8 0x00E0 -#define DEVADD9 0x00E2 -#define DEVADDA 0x00E4 - -/* SYSCFG */ -#define SCKE (1 << 10) /* USB Module Clock Enable */ -#define HSE (1 << 7) /* High-Speed Operation Enable */ -#define DCFM (1 << 6) /* Controller Function Select */ -#define DRPD (1 << 5) /* D+ Line/D- Line Resistance Control */ -#define DPRPU (1 << 4) /* D+ Line Resistance Control */ -#define USBE (1 << 0) /* USB Module Operation Enable */ - -/* DVSTCTR */ -#define EXTLP (1 << 10) /* Controls the EXTLP pin output state */ -#define PWEN (1 << 9) /* Controls the PWEN pin output state */ -#define USBRST (1 << 6) /* Bus Reset Output */ -#define UACT (1 << 4) /* USB Bus Enable */ -#define RHST (0x7) /* Reset Handshake */ -#define RHST_LOW_SPEED 1 /* Low-speed connection */ -#define RHST_FULL_SPEED 2 /* Full-speed connection */ -#define RHST_HIGH_SPEED 3 /* High-speed connection */ - -/* CFIFOSEL */ -#define DREQE (1 << 12) /* DMA Transfer Request Enable */ -#define MBW_32 (0x2 << 10) /* CFIFO Port Access Bit Width */ - -/* CFIFOCTR */ -#define BVAL (1 << 15) /* Buffer Memory Enable Flag */ -#define BCLR (1 << 14) /* CPU buffer clear */ -#define FRDY (1 << 13) /* FIFO Port Ready */ -#define DTLN_MASK (0x0FFF) /* Receive Data Length */ - -/* INTENB0 */ -#define VBSE (1 << 15) /* Enable IRQ VBUS_0 and VBUSIN_0 */ -#define RSME (1 << 14) /* Enable IRQ Resume */ -#define SOFE (1 << 13) /* Enable IRQ Frame Number Update */ -#define DVSE (1 << 12) /* Enable IRQ Device State Transition */ -#define CTRE (1 << 11) /* Enable IRQ Control Stage Transition */ -#define BEMPE (1 << 10) /* Enable IRQ Buffer Empty */ -#define NRDYE (1 << 9) /* Enable IRQ Buffer Not Ready Response */ -#define BRDYE (1 << 8) /* Enable IRQ Buffer Ready */ - -/* INTENB1 */ -#define BCHGE (1 << 14) /* USB Bus Change Interrupt Enable */ -#define DTCHE (1 << 12) /* Disconnection Detect Interrupt Enable */ -#define ATTCHE (1 << 11) /* Connection Detect Interrupt Enable */ -#define EOFERRE (1 << 6) /* EOF Error Detect Interrupt Enable */ -#define SIGNE (1 << 5) /* Setup Transaction Error Interrupt Enable */ -#define SACKE (1 << 4) /* Setup Transaction ACK Interrupt Enable */ - -/* INTSTS0 */ -#define VBINT (1 << 15) /* VBUS0_0 and VBUS1_0 Interrupt Status */ -#define DVST (1 << 12) /* Device State Transition Interrupt Status */ -#define CTRT (1 << 11) /* Control Stage Interrupt Status */ -#define BEMP (1 << 10) /* Buffer Empty Interrupt Status */ -#define BRDY (1 << 8) /* Buffer Ready Interrupt Status */ -#define VBSTS (1 << 7) /* VBUS_0 and VBUSIN_0 Input Status */ -#define VALID (1 << 3) /* USB Request Receive */ - -#define DVSQ_MASK (0x3 << 4) /* Device State */ -#define POWER_STATE (0 << 4) -#define DEFAULT_STATE (1 << 4) -#define ADDRESS_STATE (2 << 4) -#define CONFIGURATION_STATE (3 << 4) - -#define CTSQ_MASK (0x7) /* Control Transfer Stage */ -#define IDLE_SETUP_STAGE 0 /* Idle stage or setup stage */ -#define READ_DATA_STAGE 1 /* Control read data stage */ -#define READ_STATUS_STAGE 2 /* Control read status stage */ -#define WRITE_DATA_STAGE 3 /* Control write data stage */ -#define WRITE_STATUS_STAGE 4 /* Control write status stage */ -#define NODATA_STATUS_STAGE 5 /* Control write NoData status stage */ -#define SEQUENCE_ERROR 6 /* Control transfer sequence error */ - -/* INTSTS1 */ -#define OVRCR (1 << 15) /* OVRCR Interrupt Status */ -#define BCHG (1 << 14) /* USB Bus Change Interrupt Status */ -#define DTCH (1 << 12) /* USB Disconnection Detect Interrupt Status */ -#define ATTCH (1 << 11) /* ATTCH Interrupt Status */ -#define EOFERR (1 << 6) /* EOF Error Detect Interrupt Status */ -#define SIGN (1 << 5) /* Setup Transaction Error Interrupt Status */ -#define SACK (1 << 4) /* Setup Transaction ACK Response Interrupt Status */ - -/* PIPECFG */ -/* DCPCFG */ -#define TYPE_NONE (0 << 14) /* Transfer Type */ -#define TYPE_BULK (1 << 14) -#define TYPE_INT (2 << 14) -#define TYPE_ISO (3 << 14) -#define DBLB (1 << 9) /* Double Buffer Mode */ -#define SHTNAK (1 << 7) /* Pipe Disable in Transfer End */ -#define DIR_OUT (1 << 4) /* Transfer Direction */ - -/* PIPEMAXP */ -/* DCPMAXP */ -#define DEVSEL_MASK (0xF << 12) /* Device Select */ -#define DCP_MAXP_MASK (0x7F) -#define PIPE_MAXP_MASK (0x7FF) - -/* PIPEBUF */ -#define BUFSIZE_SHIFT 10 -#define BUFSIZE_MASK (0x1F << BUFSIZE_SHIFT) -#define BUFNMB_MASK (0xFF) - -/* PIPEnCTR */ -/* DCPCTR */ -#define BSTS (1 << 15) /* Buffer Status */ -#define SUREQ (1 << 14) /* Sending SETUP Token */ -#define CSSTS (1 << 12) /* CSSTS Status */ -#define ACLRM (1 << 9) /* Buffer Auto-Clear Mode */ -#define SQCLR (1 << 8) /* Toggle Bit Clear */ -#define SQSET (1 << 7) /* Toggle Bit Set */ -#define PBUSY (1 << 5) /* Pipe Busy */ -#define PID_MASK (0x3) /* Response PID */ -#define PID_NAK 0 -#define PID_BUF 1 -#define PID_STALL10 2 -#define PID_STALL11 3 - -#define CCPL (1 << 2) /* Control Transfer End Enable */ - -/* PIPEnTRE */ -#define TRENB (1 << 9) /* Transaction Counter Enable */ -#define TRCLR (1 << 8) /* Transaction Counter Clear */ - -/* FRMNUM */ -#define FRNM_MASK (0x7FF) - -/* DEVADDn */ -#define UPPHUB(x) (((x) & 0xF) << 11) /* HUB Register */ -#define HUBPORT(x) (((x) & 0x7) << 8) /* HUB Port for Target Device */ -#define USBSPD(x) (((x) & 0x3) << 6) /* Device Transfer Rate */ -#define USBSPD_SPEED_LOW 0x1 -#define USBSPD_SPEED_FULL 0x2 -#define USBSPD_SPEED_HIGH 0x3 - -/* - * struct - */ -struct usbhs_priv { - - void __iomem *base; - unsigned int irq; - unsigned long irqflags; - - struct renesas_usbhs_platform_callback pfunc; - struct renesas_usbhs_driver_param dparam; - - struct delayed_work notify_hotplug_work; - struct platform_device *pdev; - - spinlock_t lock; - - u32 flags; - - /* - * module control - */ - struct usbhs_mod_info mod_info; - - /* - * pipe control - */ - struct usbhs_pipe_info pipe_info; - - /* - * fifo control - */ - struct usbhs_fifo_info fifo_info; -}; - -/* - * common - */ -u16 usbhs_read(struct usbhs_priv *priv, u32 reg); -void usbhs_write(struct usbhs_priv *priv, u32 reg, u16 data); -void usbhs_bset(struct usbhs_priv *priv, u32 reg, u16 mask, u16 data); - -#define usbhs_lock(p, f) spin_lock_irqsave(usbhs_priv_to_lock(p), f) -#define usbhs_unlock(p, f) spin_unlock_irqrestore(usbhs_priv_to_lock(p), f) - -/* - * sysconfig - */ -void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable); -void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable); -void usbhs_sys_set_test_mode(struct usbhs_priv *priv, u16 mode); - -/* - * usb request - */ -void usbhs_usbreq_get_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req); -void usbhs_usbreq_set_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req); - -/* - * bus - */ -void usbhs_bus_send_sof_enable(struct usbhs_priv *priv); -void usbhs_bus_send_reset(struct usbhs_priv *priv); -int usbhs_bus_get_speed(struct usbhs_priv *priv); -int usbhs_vbus_ctrl(struct usbhs_priv *priv, int enable); - -/* - * frame - */ -int usbhs_frame_get_num(struct usbhs_priv *priv); - -/* - * device config - */ -int usbhs_set_device_config(struct usbhs_priv *priv, int devnum, u16 upphub, - u16 hubport, u16 speed); - -/* - * data - */ -struct usbhs_priv *usbhs_pdev_to_priv(struct platform_device *pdev); -#define usbhs_get_dparam(priv, param) (priv->dparam.param) -#define usbhs_priv_to_pdev(priv) (priv->pdev) -#define usbhs_priv_to_dev(priv) (&priv->pdev->dev) -#define usbhs_priv_to_lock(priv) (&priv->lock) - -#endif /* RENESAS_USB_DRIVER_H */ diff --git a/ANDROID_3.4.5/drivers/usb/renesas_usbhs/fifo.c b/ANDROID_3.4.5/drivers/usb/renesas_usbhs/fifo.c deleted file mode 100644 index 6ec7f838..00000000 --- a/ANDROID_3.4.5/drivers/usb/renesas_usbhs/fifo.c +++ /dev/null @@ -1,1193 +0,0 @@ -/* - * Renesas USB driver - * - * Copyright (C) 2011 Renesas Solutions Corp. - * Kuninori Morimoto - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -#include -#include -#include -#include "./common.h" -#include "./pipe.h" - -#define usbhsf_get_cfifo(p) (&((p)->fifo_info.cfifo)) -#define usbhsf_get_d0fifo(p) (&((p)->fifo_info.d0fifo)) -#define usbhsf_get_d1fifo(p) (&((p)->fifo_info.d1fifo)) -#define usbhsf_is_cfifo(p, f) (usbhsf_get_cfifo(p) == f) - -#define usbhsf_fifo_is_busy(f) ((f)->pipe) /* see usbhs_pipe_select_fifo */ - -/* - * packet initialize - */ -void usbhs_pkt_init(struct usbhs_pkt *pkt) -{ - pkt->dma = DMA_ADDR_INVALID; - INIT_LIST_HEAD(&pkt->node); -} - -/* - * packet control function - */ -static int usbhsf_null_handle(struct usbhs_pkt *pkt, int *is_done) -{ - struct usbhs_priv *priv = usbhs_pipe_to_priv(pkt->pipe); - struct device *dev = usbhs_priv_to_dev(priv); - - dev_err(dev, "null handler\n"); - - return -EINVAL; -} - -static struct usbhs_pkt_handle usbhsf_null_handler = { - .prepare = usbhsf_null_handle, - .try_run = usbhsf_null_handle, -}; - -void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt, - void (*done)(struct usbhs_priv *priv, - struct usbhs_pkt *pkt), - void *buf, int len, int zero, int sequence) -{ - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - struct device *dev = usbhs_priv_to_dev(priv); - unsigned long flags; - - if (!done) { - dev_err(dev, "no done function\n"); - return; - } - - /******************** spin lock ********************/ - usbhs_lock(priv, flags); - - if (!pipe->handler) { - dev_err(dev, "no handler function\n"); - pipe->handler = &usbhsf_null_handler; - } - - list_move_tail(&pkt->node, &pipe->list); - - /* - * each pkt must hold own handler. - * because handler might be changed by its situation. - * dma handler -> pio handler. - */ - pkt->pipe = pipe; - pkt->buf = buf; - pkt->handler = pipe->handler; - pkt->length = len; - pkt->zero = zero; - pkt->actual = 0; - pkt->done = done; - pkt->sequence = sequence; - - usbhs_unlock(priv, flags); - /******************** spin unlock ******************/ -} - -static void __usbhsf_pkt_del(struct usbhs_pkt *pkt) -{ - list_del_init(&pkt->node); -} - -static struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe) -{ - if (list_empty(&pipe->list)) - return NULL; - - return list_first_entry(&pipe->list, struct usbhs_pkt, node); -} - -struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt) -{ - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - unsigned long flags; - - /******************** spin lock ********************/ - usbhs_lock(priv, flags); - - if (!pkt) - pkt = __usbhsf_pkt_get(pipe); - - if (pkt) - __usbhsf_pkt_del(pkt); - - usbhs_unlock(priv, flags); - /******************** spin unlock ******************/ - - return pkt; -} - -enum { - USBHSF_PKT_PREPARE, - USBHSF_PKT_TRY_RUN, - USBHSF_PKT_DMA_DONE, -}; - -static int usbhsf_pkt_handler(struct usbhs_pipe *pipe, int type) -{ - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - struct usbhs_pkt *pkt; - struct device *dev = usbhs_priv_to_dev(priv); - int (*func)(struct usbhs_pkt *pkt, int *is_done); - unsigned long flags; - int ret = 0; - int is_done = 0; - - /******************** spin lock ********************/ - usbhs_lock(priv, flags); - - pkt = __usbhsf_pkt_get(pipe); - if (!pkt) - goto __usbhs_pkt_handler_end; - - switch (type) { - case USBHSF_PKT_PREPARE: - func = pkt->handler->prepare; - break; - case USBHSF_PKT_TRY_RUN: - func = pkt->handler->try_run; - break; - case USBHSF_PKT_DMA_DONE: - func = pkt->handler->dma_done; - break; - default: - dev_err(dev, "unknown pkt hander\n"); - goto __usbhs_pkt_handler_end; - } - - ret = func(pkt, &is_done); - - if (is_done) - __usbhsf_pkt_del(pkt); - -__usbhs_pkt_handler_end: - usbhs_unlock(priv, flags); - /******************** spin unlock ******************/ - - if (is_done) { - pkt->done(priv, pkt); - usbhs_pkt_start(pipe); - } - - return ret; -} - -void usbhs_pkt_start(struct usbhs_pipe *pipe) -{ - usbhsf_pkt_handler(pipe, USBHSF_PKT_PREPARE); -} - -/* - * irq enable/disable function - */ -#define usbhsf_irq_empty_ctrl(p, e) usbhsf_irq_callback_ctrl(p, bempsts, e) -#define usbhsf_irq_ready_ctrl(p, e) usbhsf_irq_callback_ctrl(p, brdysts, e) -#define usbhsf_irq_callback_ctrl(pipe, status, enable) \ - ({ \ - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); \ - struct usbhs_mod *mod = usbhs_mod_get_current(priv); \ - u16 status = (1 << usbhs_pipe_number(pipe)); \ - if (!mod) \ - return; \ - if (enable) \ - mod->irq_##status |= status; \ - else \ - mod->irq_##status &= ~status; \ - usbhs_irq_callback_update(priv, mod); \ - }) - -static void usbhsf_tx_irq_ctrl(struct usbhs_pipe *pipe, int enable) -{ - /* - * And DCP pipe can NOT use "ready interrupt" for "send" - * it should use "empty" interrupt. - * see - * "Operation" - "Interrupt Function" - "BRDY Interrupt" - * - * on the other hand, normal pipe can use "ready interrupt" for "send" - * even though it is single/double buffer - */ - if (usbhs_pipe_is_dcp(pipe)) - usbhsf_irq_empty_ctrl(pipe, enable); - else - usbhsf_irq_ready_ctrl(pipe, enable); -} - -static void usbhsf_rx_irq_ctrl(struct usbhs_pipe *pipe, int enable) -{ - usbhsf_irq_ready_ctrl(pipe, enable); -} - -/* - * FIFO ctrl - */ -static void usbhsf_send_terminator(struct usbhs_pipe *pipe, - struct usbhs_fifo *fifo) -{ - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - - usbhs_bset(priv, fifo->ctr, BVAL, BVAL); -} - -static int usbhsf_fifo_barrier(struct usbhs_priv *priv, - struct usbhs_fifo *fifo) -{ - int timeout = 1024; - - do { - /* The FIFO port is accessible */ - if (usbhs_read(priv, fifo->ctr) & FRDY) - return 0; - - udelay(10); - } while (timeout--); - - return -EBUSY; -} - -static void usbhsf_fifo_clear(struct usbhs_pipe *pipe, - struct usbhs_fifo *fifo) -{ - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - - if (!usbhs_pipe_is_dcp(pipe)) - usbhsf_fifo_barrier(priv, fifo); - - usbhs_write(priv, fifo->ctr, BCLR); -} - -static int usbhsf_fifo_rcv_len(struct usbhs_priv *priv, - struct usbhs_fifo *fifo) -{ - return usbhs_read(priv, fifo->ctr) & DTLN_MASK; -} - -static void usbhsf_fifo_unselect(struct usbhs_pipe *pipe, - struct usbhs_fifo *fifo) -{ - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - - usbhs_pipe_select_fifo(pipe, NULL); - usbhs_write(priv, fifo->sel, 0); -} - -static int usbhsf_fifo_select(struct usbhs_pipe *pipe, - struct usbhs_fifo *fifo, - int write) -{ - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - struct device *dev = usbhs_priv_to_dev(priv); - int timeout = 1024; - u16 mask = ((1 << 5) | 0xF); /* mask of ISEL | CURPIPE */ - u16 base = usbhs_pipe_number(pipe); /* CURPIPE */ - - if (usbhs_pipe_is_busy(pipe) || - usbhsf_fifo_is_busy(fifo)) - return -EBUSY; - - if (usbhs_pipe_is_dcp(pipe)) { - base |= (1 == write) << 5; /* ISEL */ - - if (usbhs_mod_is_host(priv)) - usbhs_dcp_dir_for_host(pipe, write); - } - - /* "base" will be used below */ - if (usbhs_get_dparam(priv, has_sudmac) && !usbhsf_is_cfifo(priv, fifo)) - usbhs_write(priv, fifo->sel, base); - else - usbhs_write(priv, fifo->sel, base | MBW_32); - - /* check ISEL and CURPIPE value */ - while (timeout--) { - if (base == (mask & usbhs_read(priv, fifo->sel))) { - usbhs_pipe_select_fifo(pipe, fifo); - return 0; - } - udelay(10); - } - - dev_err(dev, "fifo select error\n"); - - return -EIO; -} - -/* - * DCP status stage - */ -static int usbhs_dcp_dir_switch_to_write(struct usbhs_pkt *pkt, int *is_done) -{ - struct usbhs_pipe *pipe = pkt->pipe; - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */ - struct device *dev = usbhs_priv_to_dev(priv); - int ret; - - usbhs_pipe_disable(pipe); - - ret = usbhsf_fifo_select(pipe, fifo, 1); - if (ret < 0) { - dev_err(dev, "%s() faile\n", __func__); - return ret; - } - - usbhs_pipe_sequence_data1(pipe); /* DATA1 */ - - usbhsf_fifo_clear(pipe, fifo); - usbhsf_send_terminator(pipe, fifo); - - usbhsf_fifo_unselect(pipe, fifo); - - usbhsf_tx_irq_ctrl(pipe, 1); - usbhs_pipe_enable(pipe); - - return ret; -} - -static int usbhs_dcp_dir_switch_to_read(struct usbhs_pkt *pkt, int *is_done) -{ - struct usbhs_pipe *pipe = pkt->pipe; - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */ - struct device *dev = usbhs_priv_to_dev(priv); - int ret; - - usbhs_pipe_disable(pipe); - - ret = usbhsf_fifo_select(pipe, fifo, 0); - if (ret < 0) { - dev_err(dev, "%s() fail\n", __func__); - return ret; - } - - usbhs_pipe_sequence_data1(pipe); /* DATA1 */ - usbhsf_fifo_clear(pipe, fifo); - - usbhsf_fifo_unselect(pipe, fifo); - - usbhsf_rx_irq_ctrl(pipe, 1); - usbhs_pipe_enable(pipe); - - return ret; - -} - -static int usbhs_dcp_dir_switch_done(struct usbhs_pkt *pkt, int *is_done) -{ - struct usbhs_pipe *pipe = pkt->pipe; - - if (pkt->handler == &usbhs_dcp_status_stage_in_handler) - usbhsf_tx_irq_ctrl(pipe, 0); - else - usbhsf_rx_irq_ctrl(pipe, 0); - - pkt->actual = pkt->length; - *is_done = 1; - - return 0; -} - -struct usbhs_pkt_handle usbhs_dcp_status_stage_in_handler = { - .prepare = usbhs_dcp_dir_switch_to_write, - .try_run = usbhs_dcp_dir_switch_done, -}; - -struct usbhs_pkt_handle usbhs_dcp_status_stage_out_handler = { - .prepare = usbhs_dcp_dir_switch_to_read, - .try_run = usbhs_dcp_dir_switch_done, -}; - -/* - * DCP data stage (push) - */ -static int usbhsf_dcp_data_stage_try_push(struct usbhs_pkt *pkt, int *is_done) -{ - struct usbhs_pipe *pipe = pkt->pipe; - - usbhs_pipe_sequence_data1(pipe); /* DATA1 */ - - /* - * change handler to PIO push - */ - pkt->handler = &usbhs_fifo_pio_push_handler; - - return pkt->handler->prepare(pkt, is_done); -} - -struct usbhs_pkt_handle usbhs_dcp_data_stage_out_handler = { - .prepare = usbhsf_dcp_data_stage_try_push, -}; - -/* - * DCP data stage (pop) - */ -static int usbhsf_dcp_data_stage_prepare_pop(struct usbhs_pkt *pkt, - int *is_done) -{ - struct usbhs_pipe *pipe = pkt->pipe; - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); - - if (usbhs_pipe_is_busy(pipe)) - return 0; - - /* - * prepare pop for DCP should - * - change DCP direction, - * - clear fifo - * - DATA1 - */ - usbhs_pipe_disable(pipe); - - usbhs_pipe_sequence_data1(pipe); /* DATA1 */ - - usbhsf_fifo_select(pipe, fifo, 0); - usbhsf_fifo_clear(pipe, fifo); - usbhsf_fifo_unselect(pipe, fifo); - - /* - * change handler to PIO pop - */ - pkt->handler = &usbhs_fifo_pio_pop_handler; - - return pkt->handler->prepare(pkt, is_done); -} - -struct usbhs_pkt_handle usbhs_dcp_data_stage_in_handler = { - .prepare = usbhsf_dcp_data_stage_prepare_pop, -}; - -/* - * PIO push handler - */ -static int usbhsf_pio_try_push(struct usbhs_pkt *pkt, int *is_done) -{ - struct usbhs_pipe *pipe = pkt->pipe; - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - struct device *dev = usbhs_priv_to_dev(priv); - struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */ - void __iomem *addr = priv->base + fifo->port; - u8 *buf; - int maxp = usbhs_pipe_get_maxpacket(pipe); - int total_len; - int i, ret, len; - int is_short; - - usbhs_pipe_data_sequence(pipe, pkt->sequence); - pkt->sequence = -1; /* -1 sequence will be ignored */ - - ret = usbhsf_fifo_select(pipe, fifo, 1); - if (ret < 0) - return 0; - - ret = usbhs_pipe_is_accessible(pipe); - if (ret < 0) { - /* inaccessible pipe is not an error */ - ret = 0; - goto usbhs_fifo_write_busy; - } - - ret = usbhsf_fifo_barrier(priv, fifo); - if (ret < 0) - goto usbhs_fifo_write_busy; - - buf = pkt->buf + pkt->actual; - len = pkt->length - pkt->actual; - len = min(len, maxp); - total_len = len; - is_short = total_len < maxp; - - /* - * FIXME - * - * 32-bit access only - */ - if (len >= 4 && !((unsigned long)buf & 0x03)) { - iowrite32_rep(addr, buf, len / 4); - len %= 4; - buf += total_len - len; - } - - /* the rest operation */ - for (i = 0; i < len; i++) - iowrite8(buf[i], addr + (0x03 - (i & 0x03))); - - /* - * variable update - */ - pkt->actual += total_len; - - if (pkt->actual < pkt->length) - *is_done = 0; /* there are remainder data */ - else if (is_short) - *is_done = 1; /* short packet */ - else - *is_done = !pkt->zero; /* send zero packet ? */ - - /* - * pipe/irq handling - */ - if (is_short) - usbhsf_send_terminator(pipe, fifo); - - usbhsf_tx_irq_ctrl(pipe, !*is_done); - usbhs_pipe_enable(pipe); - - dev_dbg(dev, " send %d (%d/ %d/ %d/ %d)\n", - usbhs_pipe_number(pipe), - pkt->length, pkt->actual, *is_done, pkt->zero); - - /* - * Transmission end - */ - if (*is_done) { - if (usbhs_pipe_is_dcp(pipe)) - usbhs_dcp_control_transfer_done(pipe); - } - - usbhsf_fifo_unselect(pipe, fifo); - - return 0; - -usbhs_fifo_write_busy: - usbhsf_fifo_unselect(pipe, fifo); - - /* - * pipe is busy. - * retry in interrupt - */ - usbhsf_tx_irq_ctrl(pipe, 1); - - return ret; -} - -struct usbhs_pkt_handle usbhs_fifo_pio_push_handler = { - .prepare = usbhsf_pio_try_push, - .try_run = usbhsf_pio_try_push, -}; - -/* - * PIO pop handler - */ -static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done) -{ - struct usbhs_pipe *pipe = pkt->pipe; - - if (usbhs_pipe_is_busy(pipe)) - return 0; - - /* - * pipe enable to prepare packet receive - */ - usbhs_pipe_data_sequence(pipe, pkt->sequence); - pkt->sequence = -1; /* -1 sequence will be ignored */ - - usbhs_pipe_enable(pipe); - usbhsf_rx_irq_ctrl(pipe, 1); - - return 0; -} - -static int usbhsf_pio_try_pop(struct usbhs_pkt *pkt, int *is_done) -{ - struct usbhs_pipe *pipe = pkt->pipe; - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - struct device *dev = usbhs_priv_to_dev(priv); - struct usbhs_fifo *fifo = usbhsf_get_cfifo(priv); /* CFIFO */ - void __iomem *addr = priv->base + fifo->port; - u8 *buf; - u32 data = 0; - int maxp = usbhs_pipe_get_maxpacket(pipe); - int rcv_len, len; - int i, ret; - int total_len = 0; - - ret = usbhsf_fifo_select(pipe, fifo, 0); - if (ret < 0) - return 0; - - ret = usbhsf_fifo_barrier(priv, fifo); - if (ret < 0) - goto usbhs_fifo_read_busy; - - rcv_len = usbhsf_fifo_rcv_len(priv, fifo); - - buf = pkt->buf + pkt->actual; - len = pkt->length - pkt->actual; - len = min(len, rcv_len); - total_len = len; - - /* - * update actual length first here to decide disable pipe. - * if this pipe keeps BUF status and all data were popped, - * then, next interrupt/token will be issued again - */ - pkt->actual += total_len; - - if ((pkt->actual == pkt->length) || /* receive all data */ - (total_len < maxp)) { /* short packet */ - *is_done = 1; - usbhsf_rx_irq_ctrl(pipe, 0); - usbhs_pipe_disable(pipe); /* disable pipe first */ - } - - /* - * Buffer clear if Zero-Length packet - * - * see - * "Operation" - "FIFO Buffer Memory" - "FIFO Port Function" - */ - if (0 == rcv_len) { - pkt->zero = 1; - usbhsf_fifo_clear(pipe, fifo); - goto usbhs_fifo_read_end; - } - - /* - * FIXME - * - * 32-bit access only - */ - if (len >= 4 && !((unsigned long)buf & 0x03)) { - ioread32_rep(addr, buf, len / 4); - len %= 4; - buf += total_len - len; - } - - /* the rest operation */ - for (i = 0; i < len; i++) { - if (!(i & 0x03)) - data = ioread32(addr); - - buf[i] = (data >> ((i & 0x03) * 8)) & 0xff; - } - -usbhs_fifo_read_end: - dev_dbg(dev, " recv %d (%d/ %d/ %d/ %d)\n", - usbhs_pipe_number(pipe), - pkt->length, pkt->actual, *is_done, pkt->zero); - -usbhs_fifo_read_busy: - usbhsf_fifo_unselect(pipe, fifo); - - return ret; -} - -struct usbhs_pkt_handle usbhs_fifo_pio_pop_handler = { - .prepare = usbhsf_prepare_pop, - .try_run = usbhsf_pio_try_pop, -}; - -/* - * DCP ctrol statge handler - */ -static int usbhsf_ctrl_stage_end(struct usbhs_pkt *pkt, int *is_done) -{ - usbhs_dcp_control_transfer_done(pkt->pipe); - - *is_done = 1; - - return 0; -} - -struct usbhs_pkt_handle usbhs_ctrl_stage_end_handler = { - .prepare = usbhsf_ctrl_stage_end, - .try_run = usbhsf_ctrl_stage_end, -}; - -/* - * DMA fifo functions - */ -static struct dma_chan *usbhsf_dma_chan_get(struct usbhs_fifo *fifo, - struct usbhs_pkt *pkt) -{ - if (&usbhs_fifo_dma_push_handler == pkt->handler) - return fifo->tx_chan; - - if (&usbhs_fifo_dma_pop_handler == pkt->handler) - return fifo->rx_chan; - - return NULL; -} - -static struct usbhs_fifo *usbhsf_get_dma_fifo(struct usbhs_priv *priv, - struct usbhs_pkt *pkt) -{ - struct usbhs_fifo *fifo; - - /* DMA :: D0FIFO */ - fifo = usbhsf_get_d0fifo(priv); - if (usbhsf_dma_chan_get(fifo, pkt) && - !usbhsf_fifo_is_busy(fifo)) - return fifo; - - /* DMA :: D1FIFO */ - fifo = usbhsf_get_d1fifo(priv); - if (usbhsf_dma_chan_get(fifo, pkt) && - !usbhsf_fifo_is_busy(fifo)) - return fifo; - - return NULL; -} - -#define usbhsf_dma_start(p, f) __usbhsf_dma_ctrl(p, f, DREQE) -#define usbhsf_dma_stop(p, f) __usbhsf_dma_ctrl(p, f, 0) -static void __usbhsf_dma_ctrl(struct usbhs_pipe *pipe, - struct usbhs_fifo *fifo, - u16 dreqe) -{ - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - - usbhs_bset(priv, fifo->sel, DREQE, dreqe); -} - -#define usbhsf_dma_map(p) __usbhsf_dma_map_ctrl(p, 1) -#define usbhsf_dma_unmap(p) __usbhsf_dma_map_ctrl(p, 0) -static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map) -{ - struct usbhs_pipe *pipe = pkt->pipe; - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); - - return info->dma_map_ctrl(pkt, map); -} - -static void usbhsf_dma_complete(void *arg); -static void xfer_work(struct work_struct *work) -{ - struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work); - struct usbhs_pipe *pipe = pkt->pipe; - struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe); - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - struct scatterlist sg; - struct dma_async_tx_descriptor *desc; - struct dma_chan *chan = usbhsf_dma_chan_get(fifo, pkt); - struct device *dev = usbhs_priv_to_dev(priv); - enum dma_transfer_direction dir; - dma_cookie_t cookie; - - dir = usbhs_pipe_is_dir_in(pipe) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV; - - sg_init_table(&sg, 1); - sg_set_page(&sg, virt_to_page(pkt->dma), - pkt->length, offset_in_page(pkt->dma)); - sg_dma_address(&sg) = pkt->dma + pkt->actual; - sg_dma_len(&sg) = pkt->trans; - - desc = dmaengine_prep_slave_sg(chan, &sg, 1, dir, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) - return; - - desc->callback = usbhsf_dma_complete; - desc->callback_param = pipe; - - cookie = desc->tx_submit(desc); - if (cookie < 0) { - dev_err(dev, "Failed to submit dma descriptor\n"); - return; - } - - dev_dbg(dev, " %s %d (%d/ %d)\n", - fifo->name, usbhs_pipe_number(pipe), pkt->length, pkt->zero); - - usbhsf_dma_start(pipe, fifo); - dma_async_issue_pending(chan); -} - -/* - * DMA push handler - */ -static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done) -{ - struct usbhs_pipe *pipe = pkt->pipe; - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - struct usbhs_fifo *fifo; - int len = pkt->length - pkt->actual; - int ret; - - if (usbhs_pipe_is_busy(pipe)) - return 0; - - /* use PIO if packet is less than pio_dma_border or pipe is DCP */ - if ((len < usbhs_get_dparam(priv, pio_dma_border)) || - usbhs_pipe_is_dcp(pipe)) - goto usbhsf_pio_prepare_push; - - if (len % 4) /* 32bit alignment */ - goto usbhsf_pio_prepare_push; - - if ((uintptr_t)(pkt->buf + pkt->actual) & 0x7) /* 8byte alignment */ - goto usbhsf_pio_prepare_push; - - /* get enable DMA fifo */ - fifo = usbhsf_get_dma_fifo(priv, pkt); - if (!fifo) - goto usbhsf_pio_prepare_push; - - if (usbhsf_dma_map(pkt) < 0) - goto usbhsf_pio_prepare_push; - - ret = usbhsf_fifo_select(pipe, fifo, 0); - if (ret < 0) - goto usbhsf_pio_prepare_push_unmap; - - pkt->trans = len; - - INIT_WORK(&pkt->work, xfer_work); - schedule_work(&pkt->work); - - return 0; - -usbhsf_pio_prepare_push_unmap: - usbhsf_dma_unmap(pkt); -usbhsf_pio_prepare_push: - /* - * change handler to PIO - */ - pkt->handler = &usbhs_fifo_pio_push_handler; - - return pkt->handler->prepare(pkt, is_done); -} - -static int usbhsf_dma_push_done(struct usbhs_pkt *pkt, int *is_done) -{ - struct usbhs_pipe *pipe = pkt->pipe; - - pkt->actual = pkt->trans; - - *is_done = !pkt->zero; /* send zero packet ? */ - - usbhsf_dma_stop(pipe, pipe->fifo); - usbhsf_dma_unmap(pkt); - usbhsf_fifo_unselect(pipe, pipe->fifo); - - return 0; -} - -struct usbhs_pkt_handle usbhs_fifo_dma_push_handler = { - .prepare = usbhsf_dma_prepare_push, - .dma_done = usbhsf_dma_push_done, -}; - -/* - * DMA pop handler - */ -static int usbhsf_dma_try_pop(struct usbhs_pkt *pkt, int *is_done) -{ - struct usbhs_pipe *pipe = pkt->pipe; - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - struct usbhs_fifo *fifo; - int len, ret; - - if (usbhs_pipe_is_busy(pipe)) - return 0; - - if (usbhs_pipe_is_dcp(pipe)) - goto usbhsf_pio_prepare_pop; - - /* get enable DMA fifo */ - fifo = usbhsf_get_dma_fifo(priv, pkt); - if (!fifo) - goto usbhsf_pio_prepare_pop; - - if ((uintptr_t)(pkt->buf + pkt->actual) & 0x7) /* 8byte alignment */ - goto usbhsf_pio_prepare_pop; - - ret = usbhsf_fifo_select(pipe, fifo, 0); - if (ret < 0) - goto usbhsf_pio_prepare_pop; - - /* use PIO if packet is less than pio_dma_border */ - len = usbhsf_fifo_rcv_len(priv, fifo); - len = min(pkt->length - pkt->actual, len); - if (len % 4) /* 32bit alignment */ - goto usbhsf_pio_prepare_pop_unselect; - - if (len < usbhs_get_dparam(priv, pio_dma_border)) - goto usbhsf_pio_prepare_pop_unselect; - - ret = usbhsf_fifo_barrier(priv, fifo); - if (ret < 0) - goto usbhsf_pio_prepare_pop_unselect; - - if (usbhsf_dma_map(pkt) < 0) - goto usbhsf_pio_prepare_pop_unselect; - - /* DMA */ - - /* - * usbhs_fifo_dma_pop_handler :: prepare - * enabled irq to come here. - * but it is no longer needed for DMA. disable it. - */ - usbhsf_rx_irq_ctrl(pipe, 0); - - pkt->trans = len; - - INIT_WORK(&pkt->work, xfer_work); - schedule_work(&pkt->work); - - return 0; - -usbhsf_pio_prepare_pop_unselect: - usbhsf_fifo_unselect(pipe, fifo); -usbhsf_pio_prepare_pop: - - /* - * change handler to PIO - */ - pkt->handler = &usbhs_fifo_pio_pop_handler; - - return pkt->handler->try_run(pkt, is_done); -} - -static int usbhsf_dma_pop_done(struct usbhs_pkt *pkt, int *is_done) -{ - struct usbhs_pipe *pipe = pkt->pipe; - int maxp = usbhs_pipe_get_maxpacket(pipe); - - usbhsf_dma_stop(pipe, pipe->fifo); - usbhsf_dma_unmap(pkt); - usbhsf_fifo_unselect(pipe, pipe->fifo); - - pkt->actual += pkt->trans; - - if ((pkt->actual == pkt->length) || /* receive all data */ - (pkt->trans < maxp)) { /* short packet */ - *is_done = 1; - } else { - /* re-enable */ - usbhsf_prepare_pop(pkt, is_done); - } - - return 0; -} - -struct usbhs_pkt_handle usbhs_fifo_dma_pop_handler = { - .prepare = usbhsf_prepare_pop, - .try_run = usbhsf_dma_try_pop, - .dma_done = usbhsf_dma_pop_done -}; - -/* - * DMA setting - */ -static bool usbhsf_dma_filter(struct dma_chan *chan, void *param) -{ - struct sh_dmae_slave *slave = param; - - /* - * FIXME - * - * usbhs doesn't recognize id = 0 as valid DMA - */ - if (0 == slave->slave_id) - return false; - - chan->private = slave; - - return true; -} - -static void usbhsf_dma_quit(struct usbhs_priv *priv, struct usbhs_fifo *fifo) -{ - if (fifo->tx_chan) - dma_release_channel(fifo->tx_chan); - if (fifo->rx_chan) - dma_release_channel(fifo->rx_chan); - - fifo->tx_chan = NULL; - fifo->rx_chan = NULL; -} - -static void usbhsf_dma_init(struct usbhs_priv *priv, - struct usbhs_fifo *fifo) -{ - struct device *dev = usbhs_priv_to_dev(priv); - dma_cap_mask_t mask; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - fifo->tx_chan = dma_request_channel(mask, usbhsf_dma_filter, - &fifo->tx_slave); - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - fifo->rx_chan = dma_request_channel(mask, usbhsf_dma_filter, - &fifo->rx_slave); - - if (fifo->tx_chan || fifo->rx_chan) - dev_dbg(dev, "enable DMAEngine (%s%s%s)\n", - fifo->name, - fifo->tx_chan ? "[TX]" : " ", - fifo->rx_chan ? "[RX]" : " "); -} - -/* - * irq functions - */ -static int usbhsf_irq_empty(struct usbhs_priv *priv, - struct usbhs_irq_state *irq_state) -{ - struct usbhs_pipe *pipe; - struct device *dev = usbhs_priv_to_dev(priv); - int i, ret; - - if (!irq_state->bempsts) { - dev_err(dev, "debug %s !!\n", __func__); - return -EIO; - } - - dev_dbg(dev, "irq empty [0x%04x]\n", irq_state->bempsts); - - /* - * search interrupted "pipe" - * not "uep". - */ - usbhs_for_each_pipe_with_dcp(pipe, priv, i) { - if (!(irq_state->bempsts & (1 << i))) - continue; - - ret = usbhsf_pkt_handler(pipe, USBHSF_PKT_TRY_RUN); - if (ret < 0) - dev_err(dev, "irq_empty run_error %d : %d\n", i, ret); - } - - return 0; -} - -static int usbhsf_irq_ready(struct usbhs_priv *priv, - struct usbhs_irq_state *irq_state) -{ - struct usbhs_pipe *pipe; - struct device *dev = usbhs_priv_to_dev(priv); - int i, ret; - - if (!irq_state->brdysts) { - dev_err(dev, "debug %s !!\n", __func__); - return -EIO; - } - - dev_dbg(dev, "irq ready [0x%04x]\n", irq_state->brdysts); - - /* - * search interrupted "pipe" - * not "uep". - */ - usbhs_for_each_pipe_with_dcp(pipe, priv, i) { - if (!(irq_state->brdysts & (1 << i))) - continue; - - ret = usbhsf_pkt_handler(pipe, USBHSF_PKT_TRY_RUN); - if (ret < 0) - dev_err(dev, "irq_ready run_error %d : %d\n", i, ret); - } - - return 0; -} - -static void usbhsf_dma_complete(void *arg) -{ - struct usbhs_pipe *pipe = arg; - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - struct device *dev = usbhs_priv_to_dev(priv); - int ret; - - ret = usbhsf_pkt_handler(pipe, USBHSF_PKT_DMA_DONE); - if (ret < 0) - dev_err(dev, "dma_complete run_error %d : %d\n", - usbhs_pipe_number(pipe), ret); -} - -/* - * fifo init - */ -void usbhs_fifo_init(struct usbhs_priv *priv) -{ - struct usbhs_mod *mod = usbhs_mod_get_current(priv); - struct usbhs_fifo *cfifo = usbhsf_get_cfifo(priv); - struct usbhs_fifo *d0fifo = usbhsf_get_d0fifo(priv); - struct usbhs_fifo *d1fifo = usbhsf_get_d1fifo(priv); - - mod->irq_empty = usbhsf_irq_empty; - mod->irq_ready = usbhsf_irq_ready; - mod->irq_bempsts = 0; - mod->irq_brdysts = 0; - - cfifo->pipe = NULL; - cfifo->tx_chan = NULL; - cfifo->rx_chan = NULL; - - d0fifo->pipe = NULL; - d0fifo->tx_chan = NULL; - d0fifo->rx_chan = NULL; - - d1fifo->pipe = NULL; - d1fifo->tx_chan = NULL; - d1fifo->rx_chan = NULL; - - usbhsf_dma_init(priv, usbhsf_get_d0fifo(priv)); - usbhsf_dma_init(priv, usbhsf_get_d1fifo(priv)); -} - -void usbhs_fifo_quit(struct usbhs_priv *priv) -{ - struct usbhs_mod *mod = usbhs_mod_get_current(priv); - - mod->irq_empty = NULL; - mod->irq_ready = NULL; - mod->irq_bempsts = 0; - mod->irq_brdysts = 0; - - usbhsf_dma_quit(priv, usbhsf_get_d0fifo(priv)); - usbhsf_dma_quit(priv, usbhsf_get_d1fifo(priv)); -} - -int usbhs_fifo_probe(struct usbhs_priv *priv) -{ - struct usbhs_fifo *fifo; - - /* CFIFO */ - fifo = usbhsf_get_cfifo(priv); - fifo->name = "CFIFO"; - fifo->port = CFIFO; - fifo->sel = CFIFOSEL; - fifo->ctr = CFIFOCTR; - - /* D0FIFO */ - fifo = usbhsf_get_d0fifo(priv); - fifo->name = "D0FIFO"; - fifo->port = D0FIFO; - fifo->sel = D0FIFOSEL; - fifo->ctr = D0FIFOCTR; - fifo->tx_slave.slave_id = usbhs_get_dparam(priv, d0_tx_id); - fifo->rx_slave.slave_id = usbhs_get_dparam(priv, d0_rx_id); - - /* D1FIFO */ - fifo = usbhsf_get_d1fifo(priv); - fifo->name = "D1FIFO"; - fifo->port = D1FIFO; - fifo->sel = D1FIFOSEL; - fifo->ctr = D1FIFOCTR; - fifo->tx_slave.slave_id = usbhs_get_dparam(priv, d1_tx_id); - fifo->rx_slave.slave_id = usbhs_get_dparam(priv, d1_rx_id); - - return 0; -} - -void usbhs_fifo_remove(struct usbhs_priv *priv) -{ -} diff --git a/ANDROID_3.4.5/drivers/usb/renesas_usbhs/fifo.h b/ANDROID_3.4.5/drivers/usb/renesas_usbhs/fifo.h deleted file mode 100644 index c31731a8..00000000 --- a/ANDROID_3.4.5/drivers/usb/renesas_usbhs/fifo.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Renesas USB driver - * - * Copyright (C) 2011 Renesas Solutions Corp. - * Kuninori Morimoto - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -#ifndef RENESAS_USB_FIFO_H -#define RENESAS_USB_FIFO_H - -#include -#include -#include -#include -#include "pipe.h" - -#define DMA_ADDR_INVALID (~(dma_addr_t)0) - -struct usbhs_fifo { - char *name; - u32 port; /* xFIFO */ - u32 sel; /* xFIFOSEL */ - u32 ctr; /* xFIFOCTR */ - - struct usbhs_pipe *pipe; - - struct dma_chan *tx_chan; - struct dma_chan *rx_chan; - - struct sh_dmae_slave tx_slave; - struct sh_dmae_slave rx_slave; -}; - -struct usbhs_fifo_info { - struct usbhs_fifo cfifo; - struct usbhs_fifo d0fifo; - struct usbhs_fifo d1fifo; -}; - -struct usbhs_pkt_handle; -struct usbhs_pkt { - struct list_head node; - struct usbhs_pipe *pipe; - struct usbhs_pkt_handle *handler; - void (*done)(struct usbhs_priv *priv, - struct usbhs_pkt *pkt); - struct work_struct work; - dma_addr_t dma; - void *buf; - int length; - int trans; - int actual; - int zero; - int sequence; -}; - -struct usbhs_pkt_handle { - int (*prepare)(struct usbhs_pkt *pkt, int *is_done); - int (*try_run)(struct usbhs_pkt *pkt, int *is_done); - int (*dma_done)(struct usbhs_pkt *pkt, int *is_done); -}; - -/* - * fifo - */ -int usbhs_fifo_probe(struct usbhs_priv *priv); -void usbhs_fifo_remove(struct usbhs_priv *priv); -void usbhs_fifo_init(struct usbhs_priv *priv); -void usbhs_fifo_quit(struct usbhs_priv *priv); - -/* - * packet info - */ -extern struct usbhs_pkt_handle usbhs_fifo_pio_push_handler; -extern struct usbhs_pkt_handle usbhs_fifo_pio_pop_handler; -extern struct usbhs_pkt_handle usbhs_ctrl_stage_end_handler; - -extern struct usbhs_pkt_handle usbhs_fifo_dma_push_handler; -extern struct usbhs_pkt_handle usbhs_fifo_dma_pop_handler; - -extern struct usbhs_pkt_handle usbhs_dcp_status_stage_in_handler; -extern struct usbhs_pkt_handle usbhs_dcp_status_stage_out_handler; - -extern struct usbhs_pkt_handle usbhs_dcp_data_stage_in_handler; -extern struct usbhs_pkt_handle usbhs_dcp_data_stage_out_handler; - -void usbhs_pkt_init(struct usbhs_pkt *pkt); -void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt, - void (*done)(struct usbhs_priv *priv, - struct usbhs_pkt *pkt), - void *buf, int len, int zero, int sequence); -struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt); -void usbhs_pkt_start(struct usbhs_pipe *pipe); - -#endif /* RENESAS_USB_FIFO_H */ diff --git a/ANDROID_3.4.5/drivers/usb/renesas_usbhs/mod.c b/ANDROID_3.4.5/drivers/usb/renesas_usbhs/mod.c deleted file mode 100644 index 0871e816..00000000 --- a/ANDROID_3.4.5/drivers/usb/renesas_usbhs/mod.c +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Renesas USB driver - * - * Copyright (C) 2011 Renesas Solutions Corp. - * Kuninori Morimoto - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -#include - -#include "./common.h" -#include "./mod.h" - -#define usbhs_priv_to_modinfo(priv) (&priv->mod_info) -#define usbhs_mod_info_call(priv, func, param...) \ -({ \ - struct usbhs_mod_info *info; \ - info = usbhs_priv_to_modinfo(priv); \ - !info->func ? 0 : \ - info->func(param); \ -}) - -/* - * autonomy - * - * these functions are used if platform doesn't have external phy. - * -> there is no "notify_hotplug" callback from platform - * -> call "notify_hotplug" by itself - * -> use own interrupt to connect/disconnect - * -> it mean module clock is always ON - * ~~~~~~~~~~~~~~~~~~~~~~~~~ - */ -static int usbhsm_autonomy_get_vbus(struct platform_device *pdev) -{ - struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); - - return VBSTS & usbhs_read(priv, INTSTS0); -} - -static int usbhsm_autonomy_irq_vbus(struct usbhs_priv *priv, - struct usbhs_irq_state *irq_state) -{ - struct platform_device *pdev = usbhs_priv_to_pdev(priv); - - renesas_usbhs_call_notify_hotplug(pdev); - - return 0; -} - -void usbhs_mod_autonomy_mode(struct usbhs_priv *priv) -{ - struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); - - info->irq_vbus = usbhsm_autonomy_irq_vbus; - priv->pfunc.get_vbus = usbhsm_autonomy_get_vbus; - - usbhs_irq_callback_update(priv, NULL); -} - -/* - * host / gadget functions - * - * renesas_usbhs host/gadget can register itself by below functions. - * these functions are called when probe - * - */ -void usbhs_mod_register(struct usbhs_priv *priv, struct usbhs_mod *mod, int id) -{ - struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); - - info->mod[id] = mod; - mod->priv = priv; -} - -struct usbhs_mod *usbhs_mod_get(struct usbhs_priv *priv, int id) -{ - struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); - struct usbhs_mod *ret = NULL; - - switch (id) { - case USBHS_HOST: - case USBHS_GADGET: - ret = info->mod[id]; - break; - } - - return ret; -} - -int usbhs_mod_is_host(struct usbhs_priv *priv) -{ - struct usbhs_mod *mod = usbhs_mod_get_current(priv); - struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); - - if (!mod) - return -EINVAL; - - return info->mod[USBHS_HOST] == mod; -} - -struct usbhs_mod *usbhs_mod_get_current(struct usbhs_priv *priv) -{ - struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); - - return info->curt; -} - -int usbhs_mod_change(struct usbhs_priv *priv, int id) -{ - struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); - struct usbhs_mod *mod = NULL; - int ret = 0; - - /* id < 0 mean no current */ - switch (id) { - case USBHS_HOST: - case USBHS_GADGET: - mod = info->mod[id]; - break; - default: - ret = -EINVAL; - } - info->curt = mod; - - return ret; -} - -static irqreturn_t usbhs_interrupt(int irq, void *data); -int usbhs_mod_probe(struct usbhs_priv *priv) -{ - struct device *dev = usbhs_priv_to_dev(priv); - int ret; - - /* - * install host/gadget driver - */ - ret = usbhs_mod_host_probe(priv); - if (ret < 0) - return ret; - - ret = usbhs_mod_gadget_probe(priv); - if (ret < 0) - goto mod_init_host_err; - - /* irq settings */ - ret = request_irq(priv->irq, usbhs_interrupt, - priv->irqflags, dev_name(dev), priv); - if (ret) { - dev_err(dev, "irq request err\n"); - goto mod_init_gadget_err; - } - - return ret; - -mod_init_gadget_err: - usbhs_mod_gadget_remove(priv); -mod_init_host_err: - usbhs_mod_host_remove(priv); - - return ret; -} - -void usbhs_mod_remove(struct usbhs_priv *priv) -{ - usbhs_mod_host_remove(priv); - usbhs_mod_gadget_remove(priv); - free_irq(priv->irq, priv); -} - -/* - * status functions - */ -int usbhs_status_get_device_state(struct usbhs_irq_state *irq_state) -{ - int state = irq_state->intsts0 & DVSQ_MASK; - - switch (state) { - case POWER_STATE: - case DEFAULT_STATE: - case ADDRESS_STATE: - case CONFIGURATION_STATE: - return state; - } - - return -EIO; -} - -int usbhs_status_get_ctrl_stage(struct usbhs_irq_state *irq_state) -{ - /* - * return value - * - * IDLE_SETUP_STAGE - * READ_DATA_STAGE - * READ_STATUS_STAGE - * WRITE_DATA_STAGE - * WRITE_STATUS_STAGE - * NODATA_STATUS_STAGE - * SEQUENCE_ERROR - */ - return (int)irq_state->intsts0 & CTSQ_MASK; -} - -static void usbhs_status_get_each_irq(struct usbhs_priv *priv, - struct usbhs_irq_state *state) -{ - struct usbhs_mod *mod = usbhs_mod_get_current(priv); - - state->intsts0 = usbhs_read(priv, INTSTS0); - state->intsts1 = usbhs_read(priv, INTSTS1); - - /* mask */ - if (mod) { - state->brdysts = usbhs_read(priv, BRDYSTS); - state->nrdysts = usbhs_read(priv, NRDYSTS); - state->bempsts = usbhs_read(priv, BEMPSTS); - - state->bempsts &= mod->irq_bempsts; - state->brdysts &= mod->irq_brdysts; - } -} - -/* - * interrupt - */ -#define INTSTS0_MAGIC 0xF800 /* acknowledge magical interrupt sources */ -#define INTSTS1_MAGIC 0xA870 /* acknowledge magical interrupt sources */ -static irqreturn_t usbhs_interrupt(int irq, void *data) -{ - struct usbhs_priv *priv = data; - struct usbhs_irq_state irq_state; - - usbhs_status_get_each_irq(priv, &irq_state); - - /* - * clear interrupt - * - * The hardware is _very_ picky to clear interrupt bit. - * Especially INTSTS0_MAGIC, INTSTS1_MAGIC value. - * - * see - * "Operation" - * - "Control Transfer (DCP)" - * - Function :: VALID bit should 0 - */ - usbhs_write(priv, INTSTS0, ~irq_state.intsts0 & INTSTS0_MAGIC); - usbhs_write(priv, INTSTS1, ~irq_state.intsts1 & INTSTS1_MAGIC); - - usbhs_write(priv, BRDYSTS, 0); - usbhs_write(priv, NRDYSTS, 0); - usbhs_write(priv, BEMPSTS, 0); - - /* - * call irq callback functions - * see also - * usbhs_irq_setting_update - */ - - /* INTSTS0 */ - if (irq_state.intsts0 & VBINT) - usbhs_mod_info_call(priv, irq_vbus, priv, &irq_state); - - if (irq_state.intsts0 & DVST) - usbhs_mod_call(priv, irq_dev_state, priv, &irq_state); - - if (irq_state.intsts0 & CTRT) - usbhs_mod_call(priv, irq_ctrl_stage, priv, &irq_state); - - if (irq_state.intsts0 & BEMP) - usbhs_mod_call(priv, irq_empty, priv, &irq_state); - - if (irq_state.intsts0 & BRDY) - usbhs_mod_call(priv, irq_ready, priv, &irq_state); - - /* INTSTS1 */ - if (irq_state.intsts1 & ATTCH) - usbhs_mod_call(priv, irq_attch, priv, &irq_state); - - if (irq_state.intsts1 & DTCH) - usbhs_mod_call(priv, irq_dtch, priv, &irq_state); - - if (irq_state.intsts1 & SIGN) - usbhs_mod_call(priv, irq_sign, priv, &irq_state); - - if (irq_state.intsts1 & SACK) - usbhs_mod_call(priv, irq_sack, priv, &irq_state); - - return IRQ_HANDLED; -} - -void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod) -{ - u16 intenb0 = 0; - u16 intenb1 = 0; - struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); - - /* - * BEMPENB/BRDYENB are picky. - * below method is required - * - * - clear INTSTS0 - * - update BEMPENB/BRDYENB - * - update INTSTS0 - */ - usbhs_write(priv, INTENB0, 0); - usbhs_write(priv, INTENB1, 0); - - usbhs_write(priv, BEMPENB, 0); - usbhs_write(priv, BRDYENB, 0); - - /* - * see also - * usbhs_interrupt - */ - - /* - * it don't enable DVSE (intenb0) here - * but "mod->irq_dev_state" will be called. - */ - if (info->irq_vbus) - intenb0 |= VBSE; - - if (mod) { - /* - * INTSTS0 - */ - if (mod->irq_ctrl_stage) - intenb0 |= CTRE; - - if (mod->irq_empty && mod->irq_bempsts) { - usbhs_write(priv, BEMPENB, mod->irq_bempsts); - intenb0 |= BEMPE; - } - - if (mod->irq_ready && mod->irq_brdysts) { - usbhs_write(priv, BRDYENB, mod->irq_brdysts); - intenb0 |= BRDYE; - } - - /* - * INTSTS1 - */ - if (mod->irq_attch) - intenb1 |= ATTCHE; - - if (mod->irq_dtch) - intenb1 |= DTCHE; - - if (mod->irq_sign) - intenb1 |= SIGNE; - - if (mod->irq_sack) - intenb1 |= SACKE; - } - - if (intenb0) - usbhs_write(priv, INTENB0, intenb0); - - if (intenb1) - usbhs_write(priv, INTENB1, intenb1); -} diff --git a/ANDROID_3.4.5/drivers/usb/renesas_usbhs/mod.h b/ANDROID_3.4.5/drivers/usb/renesas_usbhs/mod.h deleted file mode 100644 index 6c687553..00000000 --- a/ANDROID_3.4.5/drivers/usb/renesas_usbhs/mod.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Renesas USB driver - * - * Copyright (C) 2011 Renesas Solutions Corp. - * Kuninori Morimoto - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -#ifndef RENESAS_USB_MOD_H -#define RENESAS_USB_MOD_H - -#include -#include -#include "./common.h" - -/* - * struct - */ -struct usbhs_irq_state { - u16 intsts0; - u16 intsts1; - u16 brdysts; - u16 nrdysts; - u16 bempsts; -}; - -struct usbhs_mod { - char *name; - - /* - * entry point from common.c - */ - int (*start)(struct usbhs_priv *priv); - int (*stop)(struct usbhs_priv *priv); - - /* - * INTSTS0 - */ - - /* DVST (DVSQ) */ - int (*irq_dev_state)(struct usbhs_priv *priv, - struct usbhs_irq_state *irq_state); - - /* CTRT (CTSQ) */ - int (*irq_ctrl_stage)(struct usbhs_priv *priv, - struct usbhs_irq_state *irq_state); - - /* BEMP / BEMPSTS */ - int (*irq_empty)(struct usbhs_priv *priv, - struct usbhs_irq_state *irq_state); - u16 irq_bempsts; - - /* BRDY / BRDYSTS */ - int (*irq_ready)(struct usbhs_priv *priv, - struct usbhs_irq_state *irq_state); - u16 irq_brdysts; - - /* - * INTSTS1 - */ - - /* ATTCHE */ - int (*irq_attch)(struct usbhs_priv *priv, - struct usbhs_irq_state *irq_state); - - /* DTCHE */ - int (*irq_dtch)(struct usbhs_priv *priv, - struct usbhs_irq_state *irq_state); - - /* SIGN */ - int (*irq_sign)(struct usbhs_priv *priv, - struct usbhs_irq_state *irq_state); - - /* SACK */ - int (*irq_sack)(struct usbhs_priv *priv, - struct usbhs_irq_state *irq_state); - - struct usbhs_priv *priv; -}; - -struct usbhs_mod_info { - struct usbhs_mod *mod[USBHS_MAX]; - struct usbhs_mod *curt; /* current mod */ - - /* - * INTSTS0 :: VBINT - * - * This function will be used as autonomy mode - * when platform cannot call notify_hotplug. - * - * This callback cannot be member of "struct usbhs_mod" - * because it will be used even though - * host/gadget has not been selected. - */ - int (*irq_vbus)(struct usbhs_priv *priv, - struct usbhs_irq_state *irq_state); -}; - -/* - * for host/gadget module - */ -struct usbhs_mod *usbhs_mod_get(struct usbhs_priv *priv, int id); -struct usbhs_mod *usbhs_mod_get_current(struct usbhs_priv *priv); -void usbhs_mod_register(struct usbhs_priv *priv, struct usbhs_mod *usb, int id); -int usbhs_mod_is_host(struct usbhs_priv *priv); -int usbhs_mod_change(struct usbhs_priv *priv, int id); -int usbhs_mod_probe(struct usbhs_priv *priv); -void usbhs_mod_remove(struct usbhs_priv *priv); - -void usbhs_mod_autonomy_mode(struct usbhs_priv *priv); - -/* - * status functions - */ -int usbhs_status_get_device_state(struct usbhs_irq_state *irq_state); -int usbhs_status_get_ctrl_stage(struct usbhs_irq_state *irq_state); - -/* - * callback functions - */ -void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod); - - -#define usbhs_mod_call(priv, func, param...) \ - ({ \ - struct usbhs_mod *mod; \ - mod = usbhs_mod_get_current(priv); \ - !mod ? -ENODEV : \ - !mod->func ? 0 : \ - mod->func(param); \ - }) - -/* - * host / gadget control - */ -#if defined(CONFIG_USB_RENESAS_USBHS_HCD) || \ - defined(CONFIG_USB_RENESAS_USBHS_HCD_MODULE) -extern int usbhs_mod_host_probe(struct usbhs_priv *priv); -extern int usbhs_mod_host_remove(struct usbhs_priv *priv); -#else -static inline int usbhs_mod_host_probe(struct usbhs_priv *priv) -{ - return 0; -} -static inline void usbhs_mod_host_remove(struct usbhs_priv *priv) -{ -} -#endif - -#if defined(CONFIG_USB_RENESAS_USBHS_UDC) || \ - defined(CONFIG_USB_RENESAS_USBHS_UDC_MODULE) -extern int usbhs_mod_gadget_probe(struct usbhs_priv *priv); -extern void usbhs_mod_gadget_remove(struct usbhs_priv *priv); -#else -static inline int usbhs_mod_gadget_probe(struct usbhs_priv *priv) -{ - return 0; -} -static inline void usbhs_mod_gadget_remove(struct usbhs_priv *priv) -{ -} -#endif - -#endif /* RENESAS_USB_MOD_H */ diff --git a/ANDROID_3.4.5/drivers/usb/renesas_usbhs/mod_gadget.c b/ANDROID_3.4.5/drivers/usb/renesas_usbhs/mod_gadget.c deleted file mode 100644 index 00bd2a5e..00000000 --- a/ANDROID_3.4.5/drivers/usb/renesas_usbhs/mod_gadget.c +++ /dev/null @@ -1,1021 +0,0 @@ -/* - * Renesas USB driver - * - * Copyright (C) 2011 Renesas Solutions Corp. - * Kuninori Morimoto - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -#include -#include -#include -#include -#include -#include -#include -#include "common.h" - -/* - * struct - */ -struct usbhsg_request { - struct usb_request req; - struct usbhs_pkt pkt; -}; - -#define EP_NAME_SIZE 8 -struct usbhsg_gpriv; -struct usbhsg_uep { - struct usb_ep ep; - struct usbhs_pipe *pipe; - - char ep_name[EP_NAME_SIZE]; - - struct usbhsg_gpriv *gpriv; -}; - -struct usbhsg_gpriv { - struct usb_gadget gadget; - struct usbhs_mod mod; - - struct usbhsg_uep *uep; - int uep_size; - - struct usb_gadget_driver *driver; - - u32 status; -#define USBHSG_STATUS_STARTED (1 << 0) -#define USBHSG_STATUS_REGISTERD (1 << 1) -#define USBHSG_STATUS_WEDGE (1 << 2) -}; - -struct usbhsg_recip_handle { - char *name; - int (*device)(struct usbhs_priv *priv, struct usbhsg_uep *uep, - struct usb_ctrlrequest *ctrl); - int (*interface)(struct usbhs_priv *priv, struct usbhsg_uep *uep, - struct usb_ctrlrequest *ctrl); - int (*endpoint)(struct usbhs_priv *priv, struct usbhsg_uep *uep, - struct usb_ctrlrequest *ctrl); -}; - -/* - * macro - */ -#define usbhsg_priv_to_gpriv(priv) \ - container_of( \ - usbhs_mod_get(priv, USBHS_GADGET), \ - struct usbhsg_gpriv, mod) - -#define __usbhsg_for_each_uep(start, pos, g, i) \ - for (i = start, pos = (g)->uep + i; \ - i < (g)->uep_size; \ - i++, pos = (g)->uep + i) - -#define usbhsg_for_each_uep(pos, gpriv, i) \ - __usbhsg_for_each_uep(1, pos, gpriv, i) - -#define usbhsg_for_each_uep_with_dcp(pos, gpriv, i) \ - __usbhsg_for_each_uep(0, pos, gpriv, i) - -#define usbhsg_gadget_to_gpriv(g)\ - container_of(g, struct usbhsg_gpriv, gadget) - -#define usbhsg_req_to_ureq(r)\ - container_of(r, struct usbhsg_request, req) - -#define usbhsg_ep_to_uep(e) container_of(e, struct usbhsg_uep, ep) -#define usbhsg_gpriv_to_dev(gp) usbhs_priv_to_dev((gp)->mod.priv) -#define usbhsg_gpriv_to_priv(gp) ((gp)->mod.priv) -#define usbhsg_gpriv_to_dcp(gp) ((gp)->uep) -#define usbhsg_gpriv_to_nth_uep(gp, i) ((gp)->uep + i) -#define usbhsg_uep_to_gpriv(u) ((u)->gpriv) -#define usbhsg_uep_to_pipe(u) ((u)->pipe) -#define usbhsg_pipe_to_uep(p) ((p)->mod_private) -#define usbhsg_is_dcp(u) ((u) == usbhsg_gpriv_to_dcp((u)->gpriv)) - -#define usbhsg_ureq_to_pkt(u) (&(u)->pkt) -#define usbhsg_pkt_to_ureq(i) \ - container_of(i, struct usbhsg_request, pkt) - -#define usbhsg_is_not_connected(gp) ((gp)->gadget.speed == USB_SPEED_UNKNOWN) - -/* status */ -#define usbhsg_status_init(gp) do {(gp)->status = 0; } while (0) -#define usbhsg_status_set(gp, b) (gp->status |= b) -#define usbhsg_status_clr(gp, b) (gp->status &= ~b) -#define usbhsg_status_has(gp, b) (gp->status & b) - -/* - * queue push/pop - */ -static void usbhsg_queue_pop(struct usbhsg_uep *uep, - struct usbhsg_request *ureq, - int status) -{ - struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); - struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); - struct device *dev = usbhsg_gpriv_to_dev(gpriv); - - dev_dbg(dev, "pipe %d : queue pop\n", usbhs_pipe_number(pipe)); - - ureq->req.status = status; - ureq->req.complete(&uep->ep, &ureq->req); -} - -static void usbhsg_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt) -{ - struct usbhs_pipe *pipe = pkt->pipe; - struct usbhsg_uep *uep = usbhsg_pipe_to_uep(pipe); - struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt); - - ureq->req.actual = pkt->actual; - - usbhsg_queue_pop(uep, ureq, 0); -} - -static void usbhsg_queue_push(struct usbhsg_uep *uep, - struct usbhsg_request *ureq) -{ - struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); - struct device *dev = usbhsg_gpriv_to_dev(gpriv); - struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); - struct usbhs_pkt *pkt = usbhsg_ureq_to_pkt(ureq); - struct usb_request *req = &ureq->req; - - req->actual = 0; - req->status = -EINPROGRESS; - usbhs_pkt_push(pipe, pkt, usbhsg_queue_done, - req->buf, req->length, req->zero, -1); - usbhs_pkt_start(pipe); - - dev_dbg(dev, "pipe %d : queue push (%d)\n", - usbhs_pipe_number(pipe), - req->length); -} - -/* - * dma map/unmap - */ -static int usbhsg_dma_map_ctrl(struct usbhs_pkt *pkt, int map) -{ - struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt); - struct usb_request *req = &ureq->req; - struct usbhs_pipe *pipe = pkt->pipe; - struct usbhsg_uep *uep = usbhsg_pipe_to_uep(pipe); - struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); - enum dma_data_direction dir; - int ret = 0; - - dir = usbhs_pipe_is_dir_host(pipe); - - if (map) { - /* it can not use scatter/gather */ - WARN_ON(req->num_sgs); - - ret = usb_gadget_map_request(&gpriv->gadget, req, dir); - if (ret < 0) - return ret; - - pkt->dma = req->dma; - } else { - usb_gadget_unmap_request(&gpriv->gadget, req, dir); - } - - return ret; -} - -/* - * USB_TYPE_STANDARD / clear feature functions - */ -static int usbhsg_recip_handler_std_control_done(struct usbhs_priv *priv, - struct usbhsg_uep *uep, - struct usb_ctrlrequest *ctrl) -{ - struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); - struct usbhsg_uep *dcp = usbhsg_gpriv_to_dcp(gpriv); - struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(dcp); - - usbhs_dcp_control_transfer_done(pipe); - - return 0; -} - -static int usbhsg_recip_handler_std_clear_endpoint(struct usbhs_priv *priv, - struct usbhsg_uep *uep, - struct usb_ctrlrequest *ctrl) -{ - struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); - struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); - - if (!usbhsg_status_has(gpriv, USBHSG_STATUS_WEDGE)) { - usbhs_pipe_disable(pipe); - usbhs_pipe_sequence_data0(pipe); - usbhs_pipe_enable(pipe); - } - - usbhsg_recip_handler_std_control_done(priv, uep, ctrl); - - usbhs_pkt_start(pipe); - - return 0; -} - -struct usbhsg_recip_handle req_clear_feature = { - .name = "clear feature", - .device = usbhsg_recip_handler_std_control_done, - .interface = usbhsg_recip_handler_std_control_done, - .endpoint = usbhsg_recip_handler_std_clear_endpoint, -}; - -/* - * USB_TYPE_STANDARD / set feature functions - */ -static int usbhsg_recip_handler_std_set_device(struct usbhs_priv *priv, - struct usbhsg_uep *uep, - struct usb_ctrlrequest *ctrl) -{ - switch (le16_to_cpu(ctrl->wValue)) { - case USB_DEVICE_TEST_MODE: - usbhsg_recip_handler_std_control_done(priv, uep, ctrl); - udelay(100); - usbhs_sys_set_test_mode(priv, le16_to_cpu(ctrl->wIndex >> 8)); - break; - default: - usbhsg_recip_handler_std_control_done(priv, uep, ctrl); - break; - } - - return 0; -} - -static int usbhsg_recip_handler_std_set_endpoint(struct usbhs_priv *priv, - struct usbhsg_uep *uep, - struct usb_ctrlrequest *ctrl) -{ - struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); - - usbhs_pipe_stall(pipe); - - usbhsg_recip_handler_std_control_done(priv, uep, ctrl); - - return 0; -} - -struct usbhsg_recip_handle req_set_feature = { - .name = "set feature", - .device = usbhsg_recip_handler_std_set_device, - .interface = usbhsg_recip_handler_std_control_done, - .endpoint = usbhsg_recip_handler_std_set_endpoint, -}; - -/* - * USB_TYPE_STANDARD / get status functions - */ -static void __usbhsg_recip_send_complete(struct usb_ep *ep, - struct usb_request *req) -{ - struct usbhsg_request *ureq = usbhsg_req_to_ureq(req); - - /* free allocated recip-buffer/usb_request */ - kfree(ureq->pkt.buf); - usb_ep_free_request(ep, req); -} - -static void __usbhsg_recip_send_status(struct usbhsg_gpriv *gpriv, - unsigned short status) -{ - struct usbhsg_uep *dcp = usbhsg_gpriv_to_dcp(gpriv); - struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(dcp); - struct device *dev = usbhsg_gpriv_to_dev(gpriv); - struct usb_request *req; - unsigned short *buf; - - /* alloc new usb_request for recip */ - req = usb_ep_alloc_request(&dcp->ep, GFP_ATOMIC); - if (!req) { - dev_err(dev, "recip request allocation fail\n"); - return; - } - - /* alloc recip data buffer */ - buf = kmalloc(sizeof(*buf), GFP_ATOMIC); - if (!buf) { - usb_ep_free_request(&dcp->ep, req); - dev_err(dev, "recip data allocation fail\n"); - return; - } - - /* recip data is status */ - *buf = cpu_to_le16(status); - - /* allocated usb_request/buffer will be freed */ - req->complete = __usbhsg_recip_send_complete; - req->buf = buf; - req->length = sizeof(*buf); - req->zero = 0; - - /* push packet */ - pipe->handler = &usbhs_fifo_pio_push_handler; - usbhsg_queue_push(dcp, usbhsg_req_to_ureq(req)); -} - -static int usbhsg_recip_handler_std_get_device(struct usbhs_priv *priv, - struct usbhsg_uep *uep, - struct usb_ctrlrequest *ctrl) -{ - struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); - unsigned short status = 1 << USB_DEVICE_SELF_POWERED; - - __usbhsg_recip_send_status(gpriv, status); - - return 0; -} - -static int usbhsg_recip_handler_std_get_interface(struct usbhs_priv *priv, - struct usbhsg_uep *uep, - struct usb_ctrlrequest *ctrl) -{ - struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); - unsigned short status = 0; - - __usbhsg_recip_send_status(gpriv, status); - - return 0; -} - -static int usbhsg_recip_handler_std_get_endpoint(struct usbhs_priv *priv, - struct usbhsg_uep *uep, - struct usb_ctrlrequest *ctrl) -{ - struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); - struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); - unsigned short status = 0; - - if (usbhs_pipe_is_stall(pipe)) - status = 1 << USB_ENDPOINT_HALT; - - __usbhsg_recip_send_status(gpriv, status); - - return 0; -} - -struct usbhsg_recip_handle req_get_status = { - .name = "get status", - .device = usbhsg_recip_handler_std_get_device, - .interface = usbhsg_recip_handler_std_get_interface, - .endpoint = usbhsg_recip_handler_std_get_endpoint, -}; - -/* - * USB_TYPE handler - */ -static int usbhsg_recip_run_handle(struct usbhs_priv *priv, - struct usbhsg_recip_handle *handler, - struct usb_ctrlrequest *ctrl) -{ - struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); - struct device *dev = usbhsg_gpriv_to_dev(gpriv); - struct usbhsg_uep *uep; - struct usbhs_pipe *pipe; - int recip = ctrl->bRequestType & USB_RECIP_MASK; - int nth = le16_to_cpu(ctrl->wIndex) & USB_ENDPOINT_NUMBER_MASK; - int ret = 0; - int (*func)(struct usbhs_priv *priv, struct usbhsg_uep *uep, - struct usb_ctrlrequest *ctrl); - char *msg; - - uep = usbhsg_gpriv_to_nth_uep(gpriv, nth); - pipe = usbhsg_uep_to_pipe(uep); - if (!pipe) { - dev_err(dev, "wrong recip request\n"); - return -EINVAL; - } - - switch (recip) { - case USB_RECIP_DEVICE: - msg = "DEVICE"; - func = handler->device; - break; - case USB_RECIP_INTERFACE: - msg = "INTERFACE"; - func = handler->interface; - break; - case USB_RECIP_ENDPOINT: - msg = "ENDPOINT"; - func = handler->endpoint; - break; - default: - dev_warn(dev, "unsupported RECIP(%d)\n", recip); - func = NULL; - ret = -EINVAL; - } - - if (func) { - dev_dbg(dev, "%s (pipe %d :%s)\n", handler->name, nth, msg); - ret = func(priv, uep, ctrl); - } - - return ret; -} - -/* - * irq functions - * - * it will be called from usbhs_interrupt - */ -static int usbhsg_irq_dev_state(struct usbhs_priv *priv, - struct usbhs_irq_state *irq_state) -{ - struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); - struct device *dev = usbhsg_gpriv_to_dev(gpriv); - - gpriv->gadget.speed = usbhs_bus_get_speed(priv); - - dev_dbg(dev, "state = %x : speed : %d\n", - usbhs_status_get_device_state(irq_state), - gpriv->gadget.speed); - - return 0; -} - -static int usbhsg_irq_ctrl_stage(struct usbhs_priv *priv, - struct usbhs_irq_state *irq_state) -{ - struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); - struct usbhsg_uep *dcp = usbhsg_gpriv_to_dcp(gpriv); - struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(dcp); - struct device *dev = usbhsg_gpriv_to_dev(gpriv); - struct usb_ctrlrequest ctrl; - struct usbhsg_recip_handle *recip_handler = NULL; - int stage = usbhs_status_get_ctrl_stage(irq_state); - int ret = 0; - - dev_dbg(dev, "stage = %d\n", stage); - - /* - * see Manual - * - * "Operation" - * - "Interrupt Function" - * - "Control Transfer Stage Transition Interrupt" - * - Fig. "Control Transfer Stage Transitions" - */ - - switch (stage) { - case READ_DATA_STAGE: - pipe->handler = &usbhs_fifo_pio_push_handler; - break; - case WRITE_DATA_STAGE: - pipe->handler = &usbhs_fifo_pio_pop_handler; - break; - case NODATA_STATUS_STAGE: - pipe->handler = &usbhs_ctrl_stage_end_handler; - break; - default: - return ret; - } - - /* - * get usb request - */ - usbhs_usbreq_get_val(priv, &ctrl); - - switch (ctrl.bRequestType & USB_TYPE_MASK) { - case USB_TYPE_STANDARD: - switch (ctrl.bRequest) { - case USB_REQ_CLEAR_FEATURE: - recip_handler = &req_clear_feature; - break; - case USB_REQ_SET_FEATURE: - recip_handler = &req_set_feature; - break; - case USB_REQ_GET_STATUS: - recip_handler = &req_get_status; - break; - } - } - - /* - * setup stage / run recip - */ - if (recip_handler) - ret = usbhsg_recip_run_handle(priv, recip_handler, &ctrl); - else - ret = gpriv->driver->setup(&gpriv->gadget, &ctrl); - - if (ret < 0) - usbhs_pipe_stall(pipe); - - return ret; -} - -/* - * - * usb_dcp_ops - * - */ -static int usbhsg_pipe_disable(struct usbhsg_uep *uep) -{ - struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); - struct usbhs_pkt *pkt; - - while (1) { - pkt = usbhs_pkt_pop(pipe, NULL); - if (!pkt) - break; - - usbhsg_queue_pop(uep, usbhsg_pkt_to_ureq(pkt), -ECONNRESET); - } - - usbhs_pipe_disable(pipe); - - return 0; -} - -static void usbhsg_uep_init(struct usbhsg_gpriv *gpriv) -{ - int i; - struct usbhsg_uep *uep; - - usbhsg_for_each_uep_with_dcp(uep, gpriv, i) - uep->pipe = NULL; -} - -/* - * - * usb_ep_ops - * - */ -static int usbhsg_ep_enable(struct usb_ep *ep, - const struct usb_endpoint_descriptor *desc) -{ - struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); - struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); - struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); - struct usbhs_pipe *pipe; - int ret = -EIO; - - /* - * if it already have pipe, - * nothing to do - */ - if (uep->pipe) { - usbhs_pipe_clear(uep->pipe); - usbhs_pipe_sequence_data0(uep->pipe); - return 0; - } - - pipe = usbhs_pipe_malloc(priv, - usb_endpoint_type(desc), - usb_endpoint_dir_in(desc)); - if (pipe) { - uep->pipe = pipe; - pipe->mod_private = uep; - - /* set epnum / maxp */ - usbhs_pipe_config_update(pipe, 0, - usb_endpoint_num(desc), - usb_endpoint_maxp(desc)); - - /* - * usbhs_fifo_dma_push/pop_handler try to - * use dmaengine if possible. - * It will use pio handler if impossible. - */ - if (usb_endpoint_dir_in(desc)) - pipe->handler = &usbhs_fifo_dma_push_handler; - else - pipe->handler = &usbhs_fifo_dma_pop_handler; - - ret = 0; - } - - return ret; -} - -static int usbhsg_ep_disable(struct usb_ep *ep) -{ - struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); - - return usbhsg_pipe_disable(uep); -} - -static struct usb_request *usbhsg_ep_alloc_request(struct usb_ep *ep, - gfp_t gfp_flags) -{ - struct usbhsg_request *ureq; - - ureq = kzalloc(sizeof *ureq, gfp_flags); - if (!ureq) - return NULL; - - usbhs_pkt_init(usbhsg_ureq_to_pkt(ureq)); - - return &ureq->req; -} - -static void usbhsg_ep_free_request(struct usb_ep *ep, - struct usb_request *req) -{ - struct usbhsg_request *ureq = usbhsg_req_to_ureq(req); - - WARN_ON(!list_empty(&ureq->pkt.node)); - kfree(ureq); -} - -static int usbhsg_ep_queue(struct usb_ep *ep, struct usb_request *req, - gfp_t gfp_flags) -{ - struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); - struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); - struct usbhsg_request *ureq = usbhsg_req_to_ureq(req); - struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); - - /* param check */ - if (usbhsg_is_not_connected(gpriv) || - unlikely(!gpriv->driver) || - unlikely(!pipe)) - return -ESHUTDOWN; - - usbhsg_queue_push(uep, ureq); - - return 0; -} - -static int usbhsg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) -{ - struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); - struct usbhsg_request *ureq = usbhsg_req_to_ureq(req); - struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); - - usbhs_pkt_pop(pipe, usbhsg_ureq_to_pkt(ureq)); - usbhsg_queue_pop(uep, ureq, -ECONNRESET); - - return 0; -} - -static int __usbhsg_ep_set_halt_wedge(struct usb_ep *ep, int halt, int wedge) -{ - struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); - struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); - struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); - struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); - struct device *dev = usbhsg_gpriv_to_dev(gpriv); - unsigned long flags; - - usbhsg_pipe_disable(uep); - - dev_dbg(dev, "set halt %d (pipe %d)\n", - halt, usbhs_pipe_number(pipe)); - - /******************** spin lock ********************/ - usbhs_lock(priv, flags); - - if (halt) - usbhs_pipe_stall(pipe); - else - usbhs_pipe_disable(pipe); - - if (halt && wedge) - usbhsg_status_set(gpriv, USBHSG_STATUS_WEDGE); - else - usbhsg_status_clr(gpriv, USBHSG_STATUS_WEDGE); - - usbhs_unlock(priv, flags); - /******************** spin unlock ******************/ - - return 0; -} - -static int usbhsg_ep_set_halt(struct usb_ep *ep, int value) -{ - return __usbhsg_ep_set_halt_wedge(ep, value, 0); -} - -static int usbhsg_ep_set_wedge(struct usb_ep *ep) -{ - return __usbhsg_ep_set_halt_wedge(ep, 1, 1); -} - -static struct usb_ep_ops usbhsg_ep_ops = { - .enable = usbhsg_ep_enable, - .disable = usbhsg_ep_disable, - - .alloc_request = usbhsg_ep_alloc_request, - .free_request = usbhsg_ep_free_request, - - .queue = usbhsg_ep_queue, - .dequeue = usbhsg_ep_dequeue, - - .set_halt = usbhsg_ep_set_halt, - .set_wedge = usbhsg_ep_set_wedge, -}; - -/* - * usb module start/end - */ -static int usbhsg_try_start(struct usbhs_priv *priv, u32 status) -{ - struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); - struct usbhsg_uep *dcp = usbhsg_gpriv_to_dcp(gpriv); - struct usbhs_mod *mod = usbhs_mod_get_current(priv); - struct device *dev = usbhs_priv_to_dev(priv); - unsigned long flags; - int ret = 0; - - /******************** spin lock ********************/ - usbhs_lock(priv, flags); - - usbhsg_status_set(gpriv, status); - if (!(usbhsg_status_has(gpriv, USBHSG_STATUS_STARTED) && - usbhsg_status_has(gpriv, USBHSG_STATUS_REGISTERD))) - ret = -1; /* not ready */ - - usbhs_unlock(priv, flags); - /******************** spin unlock ********************/ - - if (ret < 0) - return 0; /* not ready is not error */ - - /* - * enable interrupt and systems if ready - */ - dev_dbg(dev, "start gadget\n"); - - /* - * pipe initialize and enable DCP - */ - usbhs_pipe_init(priv, - usbhsg_dma_map_ctrl); - usbhs_fifo_init(priv); - usbhsg_uep_init(gpriv); - - /* dcp init */ - dcp->pipe = usbhs_dcp_malloc(priv); - dcp->pipe->mod_private = dcp; - usbhs_pipe_config_update(dcp->pipe, 0, 0, 64); - - /* - * system config enble - * - HI speed - * - function - * - usb module - */ - usbhs_sys_function_ctrl(priv, 1); - - /* - * enable irq callback - */ - mod->irq_dev_state = usbhsg_irq_dev_state; - mod->irq_ctrl_stage = usbhsg_irq_ctrl_stage; - usbhs_irq_callback_update(priv, mod); - - return 0; -} - -static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status) -{ - struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); - struct usbhs_mod *mod = usbhs_mod_get_current(priv); - struct usbhsg_uep *dcp = usbhsg_gpriv_to_dcp(gpriv); - struct device *dev = usbhs_priv_to_dev(priv); - unsigned long flags; - int ret = 0; - - /******************** spin lock ********************/ - usbhs_lock(priv, flags); - - usbhsg_status_clr(gpriv, status); - if (!usbhsg_status_has(gpriv, USBHSG_STATUS_STARTED) && - !usbhsg_status_has(gpriv, USBHSG_STATUS_REGISTERD)) - ret = -1; /* already done */ - - usbhs_unlock(priv, flags); - /******************** spin unlock ********************/ - - if (ret < 0) - return 0; /* already done is not error */ - - /* - * disable interrupt and systems if 1st try - */ - usbhs_fifo_quit(priv); - - /* disable all irq */ - mod->irq_dev_state = NULL; - mod->irq_ctrl_stage = NULL; - usbhs_irq_callback_update(priv, mod); - - gpriv->gadget.speed = USB_SPEED_UNKNOWN; - - /* disable sys */ - usbhs_sys_set_test_mode(priv, 0); - usbhs_sys_function_ctrl(priv, 0); - - usbhsg_pipe_disable(dcp); - - dev_dbg(dev, "stop gadget\n"); - - return 0; -} - -/* - * - * linux usb function - * - */ -static int usbhsg_gadget_start(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) -{ - struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); - struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); - - if (!driver || - !driver->setup || - driver->max_speed < USB_SPEED_FULL) - return -EINVAL; - - /* first hook up the driver ... */ - gpriv->driver = driver; - gpriv->gadget.dev.driver = &driver->driver; - - return usbhsg_try_start(priv, USBHSG_STATUS_REGISTERD); -} - -static int usbhsg_gadget_stop(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) -{ - struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); - struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); - - if (!driver || - !driver->unbind) - return -EINVAL; - - usbhsg_try_stop(priv, USBHSG_STATUS_REGISTERD); - gpriv->gadget.dev.driver = NULL; - gpriv->driver = NULL; - - return 0; -} - -/* - * usb gadget ops - */ -static int usbhsg_get_frame(struct usb_gadget *gadget) -{ - struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); - struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); - - return usbhs_frame_get_num(priv); -} - -static struct usb_gadget_ops usbhsg_gadget_ops = { - .get_frame = usbhsg_get_frame, - .udc_start = usbhsg_gadget_start, - .udc_stop = usbhsg_gadget_stop, -}; - -static int usbhsg_start(struct usbhs_priv *priv) -{ - return usbhsg_try_start(priv, USBHSG_STATUS_STARTED); -} - -static int usbhsg_stop(struct usbhs_priv *priv) -{ - struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); - - /* cable disconnect */ - if (gpriv->driver && - gpriv->driver->disconnect) - gpriv->driver->disconnect(&gpriv->gadget); - - return usbhsg_try_stop(priv, USBHSG_STATUS_STARTED); -} - -static void usbhs_mod_gadget_release(struct device *pdev) -{ - /* do nothing */ -} - -int usbhs_mod_gadget_probe(struct usbhs_priv *priv) -{ - struct usbhsg_gpriv *gpriv; - struct usbhsg_uep *uep; - struct device *dev = usbhs_priv_to_dev(priv); - int pipe_size = usbhs_get_dparam(priv, pipe_size); - int i; - int ret; - - gpriv = kzalloc(sizeof(struct usbhsg_gpriv), GFP_KERNEL); - if (!gpriv) { - dev_err(dev, "Could not allocate gadget priv\n"); - return -ENOMEM; - } - - uep = kzalloc(sizeof(struct usbhsg_uep) * pipe_size, GFP_KERNEL); - if (!uep) { - dev_err(dev, "Could not allocate ep\n"); - ret = -ENOMEM; - goto usbhs_mod_gadget_probe_err_gpriv; - } - - /* - * CAUTION - * - * There is no guarantee that it is possible to access usb module here. - * Don't accesses to it. - * The accesse will be enable after "usbhsg_start" - */ - - /* - * register itself - */ - usbhs_mod_register(priv, &gpriv->mod, USBHS_GADGET); - - /* init gpriv */ - gpriv->mod.name = "gadget"; - gpriv->mod.start = usbhsg_start; - gpriv->mod.stop = usbhsg_stop; - gpriv->uep = uep; - gpriv->uep_size = pipe_size; - usbhsg_status_init(gpriv); - - /* - * init gadget - */ - dev_set_name(&gpriv->gadget.dev, "gadget"); - gpriv->gadget.dev.parent = dev; - gpriv->gadget.dev.release = usbhs_mod_gadget_release; - gpriv->gadget.name = "renesas_usbhs_udc"; - gpriv->gadget.ops = &usbhsg_gadget_ops; - gpriv->gadget.max_speed = USB_SPEED_HIGH; - ret = device_register(&gpriv->gadget.dev); - if (ret < 0) - goto err_add_udc; - - INIT_LIST_HEAD(&gpriv->gadget.ep_list); - - /* - * init usb_ep - */ - usbhsg_for_each_uep_with_dcp(uep, gpriv, i) { - uep->gpriv = gpriv; - snprintf(uep->ep_name, EP_NAME_SIZE, "ep%d", i); - - uep->ep.name = uep->ep_name; - uep->ep.ops = &usbhsg_ep_ops; - INIT_LIST_HEAD(&uep->ep.ep_list); - - /* init DCP */ - if (usbhsg_is_dcp(uep)) { - gpriv->gadget.ep0 = &uep->ep; - uep->ep.maxpacket = 64; - } - /* init normal pipe */ - else { - uep->ep.maxpacket = 512; - list_add_tail(&uep->ep.ep_list, &gpriv->gadget.ep_list); - } - } - - ret = usb_add_gadget_udc(dev, &gpriv->gadget); - if (ret) - goto err_register; - - - dev_info(dev, "gadget probed\n"); - - return 0; - -err_register: - device_unregister(&gpriv->gadget.dev); -err_add_udc: - kfree(gpriv->uep); - -usbhs_mod_gadget_probe_err_gpriv: - kfree(gpriv); - - return ret; -} - -void usbhs_mod_gadget_remove(struct usbhs_priv *priv) -{ - struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); - - usb_del_gadget_udc(&gpriv->gadget); - - device_unregister(&gpriv->gadget.dev); - - kfree(gpriv->uep); - kfree(gpriv); -} diff --git a/ANDROID_3.4.5/drivers/usb/renesas_usbhs/mod_host.c b/ANDROID_3.4.5/drivers/usb/renesas_usbhs/mod_host.c deleted file mode 100644 index 1834cf50..00000000 --- a/ANDROID_3.4.5/drivers/usb/renesas_usbhs/mod_host.c +++ /dev/null @@ -1,1560 +0,0 @@ -/* - * Renesas USB driver - * - * Copyright (C) 2011 Renesas Solutions Corp. - * Kuninori Morimoto - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -#include -#include -#include -#include -#include -#include -#include -#include "common.h" - -/* - *** HARDWARE LIMITATION *** - * - * 1) renesas_usbhs has a limited number of controllable devices. - * it can control only 9 devices in generally. - * see DEVADDn / DCPMAXP / PIPEMAXP. - * - * 2) renesas_usbhs pipe number is limited. - * the pipe will be re-used for each devices. - * so, software should control DATA0/1 sequence of each devices. - */ - - -/* - * image of mod_host - * - * +--------+ - * | udev 0 | --> it is used when set address - * +--------+ - * - * +--------+ pipes are reused for each uep. - * | udev 1 |-+- [uep 0 (dcp) ] --+ pipe will be switched when - * +--------+ | | other device requested - * +- [uep 1 (bulk)] --|---+ +--------------+ - * | +--------------> | pipe0 (dcp) | - * +- [uep 2 (bulk)] -@ | +--------------+ - * | | pipe1 (isoc) | - * +--------+ | +--------------+ - * | udev 2 |-+- [uep 0 (dcp) ] -@ +----------> | pipe2 (bulk) | - * +--------+ | +--------------+ - * +- [uep 1 (int) ] ----+ +------> | pipe3 (bulk) | - * | | +--------------+ - * +--------+ +-----|------> | pipe4 (int) | - * | udev 3 |-+- [uep 0 (dcp) ] -@ | +--------------+ - * +--------+ | | | .... | - * +- [uep 1 (bulk)] -@ | | .... | - * | | - * +- [uep 2 (bulk)]-----------+ - * - * @ : uep requested free pipe, but all have been used. - * now it is waiting for free pipe - */ - - -/* - * struct - */ -struct usbhsh_request { - struct urb *urb; - struct usbhs_pkt pkt; -}; - -struct usbhsh_device { - struct usb_device *usbv; - struct list_head ep_list_head; /* list of usbhsh_ep */ -}; - -struct usbhsh_ep { - struct usbhs_pipe *pipe; /* attached pipe */ - struct usbhsh_device *udev; /* attached udev */ - struct usb_host_endpoint *ep; - struct list_head ep_list; /* list to usbhsh_device */ -}; - -#define USBHSH_DEVICE_MAX 10 /* see DEVADDn / DCPMAXP / PIPEMAXP */ -#define USBHSH_PORT_MAX 7 /* see DEVADDn :: HUBPORT */ -struct usbhsh_hpriv { - struct usbhs_mod mod; - struct usbhs_pipe *dcp; - - struct usbhsh_device udev[USBHSH_DEVICE_MAX]; - - u32 port_stat; /* USB_PORT_STAT_xxx */ - - struct completion setup_ack_done; -}; - - -static const char usbhsh_hcd_name[] = "renesas_usbhs host"; - -/* - * macro - */ -#define usbhsh_priv_to_hpriv(priv) \ - container_of(usbhs_mod_get(priv, USBHS_HOST), struct usbhsh_hpriv, mod) - -#define __usbhsh_for_each_udev(start, pos, h, i) \ - for (i = start, pos = (h)->udev + i; \ - i < USBHSH_DEVICE_MAX; \ - i++, pos = (h)->udev + i) - -#define usbhsh_for_each_udev(pos, hpriv, i) \ - __usbhsh_for_each_udev(1, pos, hpriv, i) - -#define usbhsh_for_each_udev_with_dev0(pos, hpriv, i) \ - __usbhsh_for_each_udev(0, pos, hpriv, i) - -#define usbhsh_hcd_to_hpriv(h) (struct usbhsh_hpriv *)((h)->hcd_priv) -#define usbhsh_hcd_to_dev(h) ((h)->self.controller) - -#define usbhsh_hpriv_to_priv(h) ((h)->mod.priv) -#define usbhsh_hpriv_to_dcp(h) ((h)->dcp) -#define usbhsh_hpriv_to_hcd(h) \ - container_of((void *)h, struct usb_hcd, hcd_priv) - -#define usbhsh_ep_to_uep(u) ((u)->hcpriv) -#define usbhsh_uep_to_pipe(u) ((u)->pipe) -#define usbhsh_uep_to_udev(u) ((u)->udev) -#define usbhsh_uep_to_ep(u) ((u)->ep) - -#define usbhsh_urb_to_ureq(u) ((u)->hcpriv) -#define usbhsh_urb_to_usbv(u) ((u)->dev) - -#define usbhsh_usbv_to_udev(d) dev_get_drvdata(&(d)->dev) - -#define usbhsh_udev_to_usbv(h) ((h)->usbv) -#define usbhsh_udev_is_used(h) usbhsh_udev_to_usbv(h) - -#define usbhsh_pipe_to_uep(p) ((p)->mod_private) - -#define usbhsh_device_parent(d) (usbhsh_usbv_to_udev((d)->usbv->parent)) -#define usbhsh_device_hubport(d) ((d)->usbv->portnum) -#define usbhsh_device_number(h, d) ((int)((d) - (h)->udev)) -#define usbhsh_device_nth(h, d) ((h)->udev + d) -#define usbhsh_device0(h) usbhsh_device_nth(h, 0) - -#define usbhsh_port_stat_init(h) ((h)->port_stat = 0) -#define usbhsh_port_stat_set(h, s) ((h)->port_stat |= (s)) -#define usbhsh_port_stat_clear(h, s) ((h)->port_stat &= ~(s)) -#define usbhsh_port_stat_get(h) ((h)->port_stat) - -#define usbhsh_pkt_to_ureq(p) \ - container_of((void *)p, struct usbhsh_request, pkt) - -/* - * req alloc/free - */ -static struct usbhsh_request *usbhsh_ureq_alloc(struct usbhsh_hpriv *hpriv, - struct urb *urb, - gfp_t mem_flags) -{ - struct usbhsh_request *ureq; - struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); - struct device *dev = usbhs_priv_to_dev(priv); - - ureq = kzalloc(sizeof(struct usbhsh_request), mem_flags); - if (!ureq) { - dev_err(dev, "ureq alloc fail\n"); - return NULL; - } - - usbhs_pkt_init(&ureq->pkt); - ureq->urb = urb; - usbhsh_urb_to_ureq(urb) = ureq; - - return ureq; -} - -static void usbhsh_ureq_free(struct usbhsh_hpriv *hpriv, - struct usbhsh_request *ureq) -{ - usbhsh_urb_to_ureq(ureq->urb) = NULL; - ureq->urb = NULL; - - kfree(ureq); -} - -/* - * status - */ -static int usbhsh_is_running(struct usbhsh_hpriv *hpriv) -{ - /* - * we can decide some device is attached or not - * by checking mod.irq_attch - * see - * usbhsh_irq_attch() - * usbhsh_irq_dtch() - */ - return (hpriv->mod.irq_attch == NULL); -} - -/* - * pipe control - */ -static void usbhsh_endpoint_sequence_save(struct usbhsh_hpriv *hpriv, - struct urb *urb, - struct usbhs_pkt *pkt) -{ - int len = urb->actual_length; - int maxp = usb_endpoint_maxp(&urb->ep->desc); - int t = 0; - - /* DCP is out of sequence control */ - if (usb_pipecontrol(urb->pipe)) - return; - - /* - * renesas_usbhs pipe has a limitation in a number. - * So, driver should re-use the limited pipe for each device/endpoint. - * DATA0/1 sequence should be saved for it. - * see [image of mod_host] - * [HARDWARE LIMITATION] - */ - - /* - * next sequence depends on actual_length - * - * ex) actual_length = 1147, maxp = 512 - * data0 : 512 - * data1 : 512 - * data0 : 123 - * data1 is the next sequence - */ - t = len / maxp; - if (len % maxp) - t++; - if (pkt->zero) - t++; - t %= 2; - - if (t) - usb_dotoggle(urb->dev, - usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe)); -} - -static struct usbhsh_device *usbhsh_device_get(struct usbhsh_hpriv *hpriv, - struct urb *urb); - -static int usbhsh_pipe_attach(struct usbhsh_hpriv *hpriv, - struct urb *urb) -{ - struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); - struct usbhsh_ep *uep = usbhsh_ep_to_uep(urb->ep); - struct usbhsh_device *udev = usbhsh_device_get(hpriv, urb); - struct usbhs_pipe *pipe; - struct usb_endpoint_descriptor *desc = &urb->ep->desc; - struct device *dev = usbhs_priv_to_dev(priv); - unsigned long flags; - int dir_in_req = !!usb_pipein(urb->pipe); - int is_dcp = usb_endpoint_xfer_control(desc); - int i, dir_in; - int ret = -EBUSY; - - /******************** spin lock ********************/ - usbhs_lock(priv, flags); - - if (unlikely(usbhsh_uep_to_pipe(uep))) { - dev_err(dev, "uep already has pipe\n"); - goto usbhsh_pipe_attach_done; - } - - usbhs_for_each_pipe_with_dcp(pipe, priv, i) { - - /* check pipe type */ - if (!usbhs_pipe_type_is(pipe, usb_endpoint_type(desc))) - continue; - - /* check pipe direction if normal pipe */ - if (!is_dcp) { - dir_in = !!usbhs_pipe_is_dir_in(pipe); - if (0 != (dir_in - dir_in_req)) - continue; - } - - /* check pipe is free */ - if (usbhsh_pipe_to_uep(pipe)) - continue; - - /* - * attach pipe to uep - * - * usbhs_pipe_config_update() should be called after - * usbhs_set_device_config() - * see - * DCPMAXP/PIPEMAXP - */ - usbhsh_uep_to_pipe(uep) = pipe; - usbhsh_pipe_to_uep(pipe) = uep; - - usbhs_pipe_config_update(pipe, - usbhsh_device_number(hpriv, udev), - usb_endpoint_num(desc), - usb_endpoint_maxp(desc)); - - dev_dbg(dev, "%s [%d-%d(%s:%s)]\n", __func__, - usbhsh_device_number(hpriv, udev), - usb_endpoint_num(desc), - usbhs_pipe_name(pipe), - dir_in_req ? "in" : "out"); - - ret = 0; - break; - } - -usbhsh_pipe_attach_done: - usbhs_unlock(priv, flags); - /******************** spin unlock ******************/ - - return ret; -} - -static void usbhsh_pipe_detach(struct usbhsh_hpriv *hpriv, - struct usbhsh_ep *uep) -{ - struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); - struct usbhs_pipe *pipe; - struct device *dev = usbhs_priv_to_dev(priv); - unsigned long flags; - - /******************** spin lock ********************/ - usbhs_lock(priv, flags); - - pipe = usbhsh_uep_to_pipe(uep); - - if (unlikely(!pipe)) { - dev_err(dev, "uep doens't have pipe\n"); - } else { - struct usb_host_endpoint *ep = usbhsh_uep_to_ep(uep); - struct usbhsh_device *udev = usbhsh_uep_to_udev(uep); - - /* detach pipe from uep */ - usbhsh_uep_to_pipe(uep) = NULL; - usbhsh_pipe_to_uep(pipe) = NULL; - - dev_dbg(dev, "%s [%d-%d(%s)]\n", __func__, - usbhsh_device_number(hpriv, udev), - usb_endpoint_num(&ep->desc), - usbhs_pipe_name(pipe)); - } - - usbhs_unlock(priv, flags); - /******************** spin unlock ******************/ -} - -/* - * endpoint control - */ -static int usbhsh_endpoint_attach(struct usbhsh_hpriv *hpriv, - struct urb *urb, - gfp_t mem_flags) -{ - struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); - struct usbhsh_device *udev = usbhsh_device_get(hpriv, urb); - struct usb_host_endpoint *ep = urb->ep; - struct usbhsh_ep *uep; - struct device *dev = usbhs_priv_to_dev(priv); - struct usb_endpoint_descriptor *desc = &ep->desc; - unsigned long flags; - - uep = kzalloc(sizeof(struct usbhsh_ep), mem_flags); - if (!uep) { - dev_err(dev, "usbhsh_ep alloc fail\n"); - return -ENOMEM; - } - - /******************** spin lock ********************/ - usbhs_lock(priv, flags); - - /* - * init endpoint - */ - INIT_LIST_HEAD(&uep->ep_list); - list_add_tail(&uep->ep_list, &udev->ep_list_head); - - usbhsh_uep_to_udev(uep) = udev; - usbhsh_uep_to_ep(uep) = ep; - usbhsh_ep_to_uep(ep) = uep; - - usbhs_unlock(priv, flags); - /******************** spin unlock ******************/ - - dev_dbg(dev, "%s [%d-%d]\n", __func__, - usbhsh_device_number(hpriv, udev), - usb_endpoint_num(desc)); - - return 0; -} - -static void usbhsh_endpoint_detach(struct usbhsh_hpriv *hpriv, - struct usb_host_endpoint *ep) -{ - struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); - struct device *dev = usbhs_priv_to_dev(priv); - struct usbhsh_ep *uep = usbhsh_ep_to_uep(ep); - unsigned long flags; - - if (!uep) - return; - - dev_dbg(dev, "%s [%d-%d]\n", __func__, - usbhsh_device_number(hpriv, usbhsh_uep_to_udev(uep)), - usb_endpoint_num(&ep->desc)); - - if (usbhsh_uep_to_pipe(uep)) - usbhsh_pipe_detach(hpriv, uep); - - /******************** spin lock ********************/ - usbhs_lock(priv, flags); - - /* remove this endpoint from udev */ - list_del_init(&uep->ep_list); - - usbhsh_uep_to_udev(uep) = NULL; - usbhsh_uep_to_ep(uep) = NULL; - usbhsh_ep_to_uep(ep) = NULL; - - usbhs_unlock(priv, flags); - /******************** spin unlock ******************/ - - kfree(uep); -} - -static void usbhsh_endpoint_detach_all(struct usbhsh_hpriv *hpriv, - struct usbhsh_device *udev) -{ - struct usbhsh_ep *uep, *next; - - list_for_each_entry_safe(uep, next, &udev->ep_list_head, ep_list) - usbhsh_endpoint_detach(hpriv, usbhsh_uep_to_ep(uep)); -} - -/* - * device control - */ -static int usbhsh_connected_to_rhdev(struct usb_hcd *hcd, - struct usbhsh_device *udev) -{ - struct usb_device *usbv = usbhsh_udev_to_usbv(udev); - - return hcd->self.root_hub == usbv->parent; -} - -static int usbhsh_device_has_endpoint(struct usbhsh_device *udev) -{ - return !list_empty(&udev->ep_list_head); -} - -static struct usbhsh_device *usbhsh_device_get(struct usbhsh_hpriv *hpriv, - struct urb *urb) -{ - struct usb_device *usbv = usbhsh_urb_to_usbv(urb); - struct usbhsh_device *udev = usbhsh_usbv_to_udev(usbv); - - /* usbhsh_device_attach() is still not called */ - if (!udev) - return NULL; - - /* if it is device0, return it */ - if (0 == usb_pipedevice(urb->pipe)) - return usbhsh_device0(hpriv); - - /* return attached device */ - return udev; -} - -static struct usbhsh_device *usbhsh_device_attach(struct usbhsh_hpriv *hpriv, - struct urb *urb) -{ - struct usbhsh_device *udev = NULL; - struct usbhsh_device *udev0 = usbhsh_device0(hpriv); - struct usbhsh_device *pos; - struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); - struct device *dev = usbhsh_hcd_to_dev(hcd); - struct usb_device *usbv = usbhsh_urb_to_usbv(urb); - struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); - unsigned long flags; - u16 upphub, hubport; - int i; - - /* - * This function should be called only while urb is pointing to device0. - * It will attach unused usbhsh_device to urb (usbv), - * and initialize device0. - * You can use usbhsh_device_get() to get "current" udev, - * and usbhsh_usbv_to_udev() is for "attached" udev. - */ - if (0 != usb_pipedevice(urb->pipe)) { - dev_err(dev, "%s fail: urb isn't pointing device0\n", __func__); - return NULL; - } - - /******************** spin lock ********************/ - usbhs_lock(priv, flags); - - /* - * find unused device - */ - usbhsh_for_each_udev(pos, hpriv, i) { - if (usbhsh_udev_is_used(pos)) - continue; - udev = pos; - break; - } - - if (udev) { - /* - * usbhsh_usbv_to_udev() - * usbhsh_udev_to_usbv() - * will be enable - */ - dev_set_drvdata(&usbv->dev, udev); - udev->usbv = usbv; - } - - usbhs_unlock(priv, flags); - /******************** spin unlock ******************/ - - if (!udev) { - dev_err(dev, "no free usbhsh_device\n"); - return NULL; - } - - if (usbhsh_device_has_endpoint(udev)) { - dev_warn(dev, "udev have old endpoint\n"); - usbhsh_endpoint_detach_all(hpriv, udev); - } - - if (usbhsh_device_has_endpoint(udev0)) { - dev_warn(dev, "udev0 have old endpoint\n"); - usbhsh_endpoint_detach_all(hpriv, udev0); - } - - /* uep will be attached */ - INIT_LIST_HEAD(&udev0->ep_list_head); - INIT_LIST_HEAD(&udev->ep_list_head); - - /* - * set device0 config - */ - usbhs_set_device_config(priv, - 0, 0, 0, usbv->speed); - - /* - * set new device config - */ - upphub = 0; - hubport = 0; - if (!usbhsh_connected_to_rhdev(hcd, udev)) { - /* if udev is not connected to rhdev, it means parent is Hub */ - struct usbhsh_device *parent = usbhsh_device_parent(udev); - - upphub = usbhsh_device_number(hpriv, parent); - hubport = usbhsh_device_hubport(udev); - - dev_dbg(dev, "%s connecte to Hub [%d:%d](%p)\n", __func__, - upphub, hubport, parent); - } - - usbhs_set_device_config(priv, - usbhsh_device_number(hpriv, udev), - upphub, hubport, usbv->speed); - - dev_dbg(dev, "%s [%d](%p)\n", __func__, - usbhsh_device_number(hpriv, udev), udev); - - return udev; -} - -static void usbhsh_device_detach(struct usbhsh_hpriv *hpriv, - struct usbhsh_device *udev) -{ - struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); - struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); - struct device *dev = usbhsh_hcd_to_dev(hcd); - struct usb_device *usbv = usbhsh_udev_to_usbv(udev); - unsigned long flags; - - dev_dbg(dev, "%s [%d](%p)\n", __func__, - usbhsh_device_number(hpriv, udev), udev); - - if (usbhsh_device_has_endpoint(udev)) { - dev_warn(dev, "udev still have endpoint\n"); - usbhsh_endpoint_detach_all(hpriv, udev); - } - - /* - * There is nothing to do if it is device0. - * see - * usbhsh_device_attach() - * usbhsh_device_get() - */ - if (0 == usbhsh_device_number(hpriv, udev)) - return; - - /******************** spin lock ********************/ - usbhs_lock(priv, flags); - - /* - * usbhsh_usbv_to_udev() - * usbhsh_udev_to_usbv() - * will be disable - */ - dev_set_drvdata(&usbv->dev, NULL); - udev->usbv = NULL; - - usbhs_unlock(priv, flags); - /******************** spin unlock ******************/ -} - -/* - * queue push/pop - */ -static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt) -{ - struct usbhsh_request *ureq = usbhsh_pkt_to_ureq(pkt); - struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); - struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); - struct urb *urb = ureq->urb; - struct device *dev = usbhs_priv_to_dev(priv); - int status = 0; - - dev_dbg(dev, "%s\n", __func__); - - if (!urb) { - dev_warn(dev, "pkt doesn't have urb\n"); - return; - } - - if (!usbhsh_is_running(hpriv)) - status = -ESHUTDOWN; - - urb->actual_length = pkt->actual; - usbhsh_ureq_free(hpriv, ureq); - - usbhsh_endpoint_sequence_save(hpriv, urb, pkt); - usbhsh_pipe_detach(hpriv, usbhsh_ep_to_uep(urb->ep)); - - usb_hcd_unlink_urb_from_ep(hcd, urb); - usb_hcd_giveback_urb(hcd, urb, status); -} - -static int usbhsh_queue_push(struct usb_hcd *hcd, - struct urb *urb, - gfp_t mem_flags) -{ - struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); - struct usbhsh_ep *uep = usbhsh_ep_to_uep(urb->ep); - struct usbhs_pipe *pipe = usbhsh_uep_to_pipe(uep); - struct device *dev = usbhsh_hcd_to_dev(hcd); - struct usbhsh_request *ureq; - void *buf; - int len, sequence; - - if (usb_pipeisoc(urb->pipe)) { - dev_err(dev, "pipe iso is not supported now\n"); - return -EIO; - } - - /* this ureq will be freed on usbhsh_queue_done() */ - ureq = usbhsh_ureq_alloc(hpriv, urb, mem_flags); - if (unlikely(!ureq)) { - dev_err(dev, "ureq alloc fail\n"); - return -ENOMEM; - } - - if (usb_pipein(urb->pipe)) - pipe->handler = &usbhs_fifo_pio_pop_handler; - else - pipe->handler = &usbhs_fifo_pio_push_handler; - - buf = (void *)(urb->transfer_buffer + urb->actual_length); - len = urb->transfer_buffer_length - urb->actual_length; - - sequence = usb_gettoggle(urb->dev, - usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe)); - - dev_dbg(dev, "%s\n", __func__); - usbhs_pkt_push(pipe, &ureq->pkt, usbhsh_queue_done, - buf, len, (urb->transfer_flags & URB_ZERO_PACKET), - sequence); - - usbhs_pkt_start(pipe); - - return 0; -} - -static void usbhsh_queue_force_pop(struct usbhs_priv *priv, - struct usbhs_pipe *pipe) -{ - struct usbhs_pkt *pkt; - - while (1) { - pkt = usbhs_pkt_pop(pipe, NULL); - if (!pkt) - break; - - /* - * if all packet are gone, usbhsh_endpoint_disable() - * will be called. - * then, attached device/endpoint/pipe will be detached - */ - usbhsh_queue_done(priv, pkt); - } -} - -static void usbhsh_queue_force_pop_all(struct usbhs_priv *priv) -{ - struct usbhs_pipe *pos; - int i; - - usbhs_for_each_pipe_with_dcp(pos, priv, i) - usbhsh_queue_force_pop(priv, pos); -} - -/* - * DCP setup stage - */ -static int usbhsh_is_request_address(struct urb *urb) -{ - struct usb_ctrlrequest *req; - - req = (struct usb_ctrlrequest *)urb->setup_packet; - - if ((DeviceOutRequest == req->bRequestType << 8) && - (USB_REQ_SET_ADDRESS == req->bRequest)) - return 1; - else - return 0; -} - -static void usbhsh_setup_stage_packet_push(struct usbhsh_hpriv *hpriv, - struct urb *urb, - struct usbhs_pipe *pipe) -{ - struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); - struct usb_ctrlrequest req; - struct device *dev = usbhs_priv_to_dev(priv); - - /* - * wait setup packet ACK - * see - * usbhsh_irq_setup_ack() - * usbhsh_irq_setup_err() - */ - init_completion(&hpriv->setup_ack_done); - - /* copy original request */ - memcpy(&req, urb->setup_packet, sizeof(struct usb_ctrlrequest)); - - /* - * renesas_usbhs can not use original usb address. - * see HARDWARE LIMITATION. - * modify usb address here to use attached device. - * see usbhsh_device_attach() - */ - if (usbhsh_is_request_address(urb)) { - struct usb_device *usbv = usbhsh_urb_to_usbv(urb); - struct usbhsh_device *udev = usbhsh_usbv_to_udev(usbv); - - /* udev is a attached device */ - req.wValue = usbhsh_device_number(hpriv, udev); - dev_dbg(dev, "create new address - %d\n", req.wValue); - } - - /* set request */ - usbhs_usbreq_set_val(priv, &req); - - /* - * wait setup packet ACK - */ - wait_for_completion(&hpriv->setup_ack_done); - - dev_dbg(dev, "%s done\n", __func__); -} - -/* - * DCP data stage - */ -static void usbhsh_data_stage_packet_done(struct usbhs_priv *priv, - struct usbhs_pkt *pkt) -{ - struct usbhsh_request *ureq = usbhsh_pkt_to_ureq(pkt); - struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); - - /* this ureq was connected to urb when usbhsh_urb_enqueue() */ - - usbhsh_ureq_free(hpriv, ureq); -} - -static int usbhsh_data_stage_packet_push(struct usbhsh_hpriv *hpriv, - struct urb *urb, - struct usbhs_pipe *pipe, - gfp_t mem_flags) - -{ - struct usbhsh_request *ureq; - - /* this ureq will be freed on usbhsh_data_stage_packet_done() */ - ureq = usbhsh_ureq_alloc(hpriv, urb, mem_flags); - if (unlikely(!ureq)) - return -ENOMEM; - - if (usb_pipein(urb->pipe)) - pipe->handler = &usbhs_dcp_data_stage_in_handler; - else - pipe->handler = &usbhs_dcp_data_stage_out_handler; - - usbhs_pkt_push(pipe, &ureq->pkt, - usbhsh_data_stage_packet_done, - urb->transfer_buffer, - urb->transfer_buffer_length, - (urb->transfer_flags & URB_ZERO_PACKET), - -1); - - return 0; -} - -/* - * DCP status stage - */ -static int usbhsh_status_stage_packet_push(struct usbhsh_hpriv *hpriv, - struct urb *urb, - struct usbhs_pipe *pipe, - gfp_t mem_flags) -{ - struct usbhsh_request *ureq; - - /* This ureq will be freed on usbhsh_queue_done() */ - ureq = usbhsh_ureq_alloc(hpriv, urb, mem_flags); - if (unlikely(!ureq)) - return -ENOMEM; - - if (usb_pipein(urb->pipe)) - pipe->handler = &usbhs_dcp_status_stage_in_handler; - else - pipe->handler = &usbhs_dcp_status_stage_out_handler; - - usbhs_pkt_push(pipe, &ureq->pkt, - usbhsh_queue_done, - NULL, - urb->transfer_buffer_length, - 0, -1); - - return 0; -} - -static int usbhsh_dcp_queue_push(struct usb_hcd *hcd, - struct urb *urb, - gfp_t mflags) -{ - struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); - struct usbhsh_ep *uep = usbhsh_ep_to_uep(urb->ep); - struct usbhs_pipe *pipe = usbhsh_uep_to_pipe(uep); - struct device *dev = usbhsh_hcd_to_dev(hcd); - int ret; - - dev_dbg(dev, "%s\n", __func__); - - /* - * setup stage - * - * usbhsh_send_setup_stage_packet() wait SACK/SIGN - */ - usbhsh_setup_stage_packet_push(hpriv, urb, pipe); - - /* - * data stage - * - * It is pushed only when urb has buffer. - */ - if (urb->transfer_buffer_length) { - ret = usbhsh_data_stage_packet_push(hpriv, urb, pipe, mflags); - if (ret < 0) { - dev_err(dev, "data stage failed\n"); - return ret; - } - } - - /* - * status stage - */ - ret = usbhsh_status_stage_packet_push(hpriv, urb, pipe, mflags); - if (ret < 0) { - dev_err(dev, "status stage failed\n"); - return ret; - } - - /* - * start pushed packets - */ - usbhs_pkt_start(pipe); - - return 0; -} - -/* - * dma map functions - */ -static int usbhsh_dma_map_ctrl(struct usbhs_pkt *pkt, int map) -{ - return 0; -} - -/* - * for hc_driver - */ -static int usbhsh_host_start(struct usb_hcd *hcd) -{ - return 0; -} - -static void usbhsh_host_stop(struct usb_hcd *hcd) -{ -} - -static int usbhsh_urb_enqueue(struct usb_hcd *hcd, - struct urb *urb, - gfp_t mem_flags) -{ - struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); - struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); - struct device *dev = usbhs_priv_to_dev(priv); - struct usb_host_endpoint *ep = urb->ep; - struct usbhsh_device *new_udev = NULL; - int is_dir_in = usb_pipein(urb->pipe); - int i; - int ret; - - dev_dbg(dev, "%s (%s)\n", __func__, is_dir_in ? "in" : "out"); - - if (!usbhsh_is_running(hpriv)) { - ret = -EIO; - dev_err(dev, "host is not running\n"); - goto usbhsh_urb_enqueue_error_not_linked; - } - - ret = usb_hcd_link_urb_to_ep(hcd, urb); - if (ret) { - dev_err(dev, "urb link failed\n"); - goto usbhsh_urb_enqueue_error_not_linked; - } - - /* - * attach udev if needed - * see [image of mod_host] - */ - if (!usbhsh_device_get(hpriv, urb)) { - new_udev = usbhsh_device_attach(hpriv, urb); - if (!new_udev) { - ret = -EIO; - dev_err(dev, "device attach failed\n"); - goto usbhsh_urb_enqueue_error_not_linked; - } - } - - /* - * attach endpoint if needed - * see [image of mod_host] - */ - if (!usbhsh_ep_to_uep(ep)) { - ret = usbhsh_endpoint_attach(hpriv, urb, mem_flags); - if (ret < 0) { - dev_err(dev, "endpoint attach failed\n"); - goto usbhsh_urb_enqueue_error_free_device; - } - } - - /* - * attach pipe to endpoint - * see [image of mod_host] - */ - for (i = 0; i < 1024; i++) { - ret = usbhsh_pipe_attach(hpriv, urb); - if (ret < 0) - msleep(100); - else - break; - } - if (ret < 0) { - dev_err(dev, "pipe attach failed\n"); - goto usbhsh_urb_enqueue_error_free_endpoint; - } - - /* - * push packet - */ - if (usb_pipecontrol(urb->pipe)) - ret = usbhsh_dcp_queue_push(hcd, urb, mem_flags); - else - ret = usbhsh_queue_push(hcd, urb, mem_flags); - - return ret; - -usbhsh_urb_enqueue_error_free_endpoint: - usbhsh_endpoint_detach(hpriv, ep); -usbhsh_urb_enqueue_error_free_device: - if (new_udev) - usbhsh_device_detach(hpriv, new_udev); -usbhsh_urb_enqueue_error_not_linked: - - dev_dbg(dev, "%s error\n", __func__); - - return ret; -} - -static int usbhsh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) -{ - struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); - struct usbhsh_request *ureq = usbhsh_urb_to_ureq(urb); - - if (ureq) { - struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); - struct usbhs_pkt *pkt = &ureq->pkt; - - usbhs_pkt_pop(pkt->pipe, pkt); - usbhsh_queue_done(priv, pkt); - } - - return 0; -} - -static void usbhsh_endpoint_disable(struct usb_hcd *hcd, - struct usb_host_endpoint *ep) -{ - struct usbhsh_ep *uep = usbhsh_ep_to_uep(ep); - struct usbhsh_device *udev; - struct usbhsh_hpriv *hpriv; - - /* - * this function might be called manytimes by same hcd/ep - * in-endpoint == out-endpoint if ep == dcp. - */ - if (!uep) - return; - - udev = usbhsh_uep_to_udev(uep); - hpriv = usbhsh_hcd_to_hpriv(hcd); - - usbhsh_endpoint_detach(hpriv, ep); - - /* - * if there is no endpoint, - * free device - */ - if (!usbhsh_device_has_endpoint(udev)) - usbhsh_device_detach(hpriv, udev); -} - -static int usbhsh_hub_status_data(struct usb_hcd *hcd, char *buf) -{ - struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); - struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); - struct device *dev = usbhs_priv_to_dev(priv); - int roothub_id = 1; /* only 1 root hub */ - - /* - * does port stat was changed ? - * check USB_PORT_STAT_C_xxx << 16 - */ - if (usbhsh_port_stat_get(hpriv) & 0xFFFF0000) - *buf = (1 << roothub_id); - else - *buf = 0; - - dev_dbg(dev, "%s (%02x)\n", __func__, *buf); - - return !!(*buf); -} - -static int __usbhsh_hub_hub_feature(struct usbhsh_hpriv *hpriv, - u16 typeReq, u16 wValue, - u16 wIndex, char *buf, u16 wLength) -{ - struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); - struct device *dev = usbhs_priv_to_dev(priv); - - switch (wValue) { - case C_HUB_OVER_CURRENT: - case C_HUB_LOCAL_POWER: - dev_dbg(dev, "%s :: C_HUB_xx\n", __func__); - return 0; - } - - return -EPIPE; -} - -static int __usbhsh_hub_port_feature(struct usbhsh_hpriv *hpriv, - u16 typeReq, u16 wValue, - u16 wIndex, char *buf, u16 wLength) -{ - struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); - struct device *dev = usbhs_priv_to_dev(priv); - int enable = (typeReq == SetPortFeature); - int speed, i, timeout = 128; - int roothub_id = 1; /* only 1 root hub */ - - /* common error */ - if (wIndex > roothub_id || wLength != 0) - return -EPIPE; - - /* check wValue */ - switch (wValue) { - case USB_PORT_FEAT_POWER: - usbhs_vbus_ctrl(priv, enable); - dev_dbg(dev, "%s :: USB_PORT_FEAT_POWER\n", __func__); - break; - - case USB_PORT_FEAT_ENABLE: - case USB_PORT_FEAT_SUSPEND: - case USB_PORT_FEAT_C_ENABLE: - case USB_PORT_FEAT_C_SUSPEND: - case USB_PORT_FEAT_C_CONNECTION: - case USB_PORT_FEAT_C_OVER_CURRENT: - case USB_PORT_FEAT_C_RESET: - dev_dbg(dev, "%s :: USB_PORT_FEAT_xxx\n", __func__); - break; - - case USB_PORT_FEAT_RESET: - if (!enable) - break; - - usbhsh_port_stat_clear(hpriv, - USB_PORT_STAT_HIGH_SPEED | - USB_PORT_STAT_LOW_SPEED); - - usbhsh_queue_force_pop_all(priv); - - usbhs_bus_send_reset(priv); - msleep(20); - usbhs_bus_send_sof_enable(priv); - - for (i = 0; i < timeout ; i++) { - switch (usbhs_bus_get_speed(priv)) { - case USB_SPEED_LOW: - speed = USB_PORT_STAT_LOW_SPEED; - goto got_usb_bus_speed; - case USB_SPEED_HIGH: - speed = USB_PORT_STAT_HIGH_SPEED; - goto got_usb_bus_speed; - case USB_SPEED_FULL: - speed = 0; - goto got_usb_bus_speed; - } - - msleep(20); - } - return -EPIPE; - -got_usb_bus_speed: - usbhsh_port_stat_set(hpriv, speed); - usbhsh_port_stat_set(hpriv, USB_PORT_STAT_ENABLE); - - dev_dbg(dev, "%s :: USB_PORT_FEAT_RESET (speed = %d)\n", - __func__, speed); - - /* status change is not needed */ - return 0; - - default: - return -EPIPE; - } - - /* set/clear status */ - if (enable) - usbhsh_port_stat_set(hpriv, (1 << wValue)); - else - usbhsh_port_stat_clear(hpriv, (1 << wValue)); - - return 0; -} - -static int __usbhsh_hub_get_status(struct usbhsh_hpriv *hpriv, - u16 typeReq, u16 wValue, - u16 wIndex, char *buf, u16 wLength) -{ - struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); - struct usb_hub_descriptor *desc = (struct usb_hub_descriptor *)buf; - struct device *dev = usbhs_priv_to_dev(priv); - int roothub_id = 1; /* only 1 root hub */ - - switch (typeReq) { - case GetHubStatus: - dev_dbg(dev, "%s :: GetHubStatus\n", __func__); - - *buf = 0x00; - break; - - case GetPortStatus: - if (wIndex != roothub_id) - return -EPIPE; - - dev_dbg(dev, "%s :: GetPortStatus\n", __func__); - *(__le32 *)buf = cpu_to_le32(usbhsh_port_stat_get(hpriv)); - break; - - case GetHubDescriptor: - desc->bDescriptorType = 0x29; - desc->bHubContrCurrent = 0; - desc->bNbrPorts = roothub_id; - desc->bDescLength = 9; - desc->bPwrOn2PwrGood = 0; - desc->wHubCharacteristics = cpu_to_le16(0x0011); - desc->u.hs.DeviceRemovable[0] = (roothub_id << 1); - desc->u.hs.DeviceRemovable[1] = ~0; - dev_dbg(dev, "%s :: GetHubDescriptor\n", __func__); - break; - } - - return 0; -} - -static int usbhsh_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, - u16 wIndex, char *buf, u16 wLength) -{ - struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); - struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); - struct device *dev = usbhs_priv_to_dev(priv); - int ret = -EPIPE; - - switch (typeReq) { - - /* Hub Feature */ - case ClearHubFeature: - case SetHubFeature: - ret = __usbhsh_hub_hub_feature(hpriv, typeReq, - wValue, wIndex, buf, wLength); - break; - - /* Port Feature */ - case SetPortFeature: - case ClearPortFeature: - ret = __usbhsh_hub_port_feature(hpriv, typeReq, - wValue, wIndex, buf, wLength); - break; - - /* Get status */ - case GetHubStatus: - case GetPortStatus: - case GetHubDescriptor: - ret = __usbhsh_hub_get_status(hpriv, typeReq, - wValue, wIndex, buf, wLength); - break; - } - - dev_dbg(dev, "typeReq = %x, ret = %d, port_stat = %x\n", - typeReq, ret, usbhsh_port_stat_get(hpriv)); - - return ret; -} - -static struct hc_driver usbhsh_driver = { - .description = usbhsh_hcd_name, - .hcd_priv_size = sizeof(struct usbhsh_hpriv), - - /* - * generic hardware linkage - */ - .flags = HCD_USB2, - - .start = usbhsh_host_start, - .stop = usbhsh_host_stop, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = usbhsh_urb_enqueue, - .urb_dequeue = usbhsh_urb_dequeue, - .endpoint_disable = usbhsh_endpoint_disable, - - /* - * root hub - */ - .hub_status_data = usbhsh_hub_status_data, - .hub_control = usbhsh_hub_control, -}; - -/* - * interrupt functions - */ -static int usbhsh_irq_attch(struct usbhs_priv *priv, - struct usbhs_irq_state *irq_state) -{ - struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); - struct device *dev = usbhs_priv_to_dev(priv); - - dev_dbg(dev, "device attached\n"); - - usbhsh_port_stat_set(hpriv, USB_PORT_STAT_CONNECTION); - usbhsh_port_stat_set(hpriv, USB_PORT_STAT_C_CONNECTION << 16); - - /* - * attch interrupt might happen infinitely on some device - * (on self power USB hub ?) - * disable it here. - * - * usbhsh_is_running() becomes effective - * according to this process. - * see - * usbhsh_is_running() - * usbhsh_urb_enqueue() - */ - hpriv->mod.irq_attch = NULL; - usbhs_irq_callback_update(priv, &hpriv->mod); - - return 0; -} - -static int usbhsh_irq_dtch(struct usbhs_priv *priv, - struct usbhs_irq_state *irq_state) -{ - struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); - struct device *dev = usbhs_priv_to_dev(priv); - - dev_dbg(dev, "device detached\n"); - - usbhsh_port_stat_clear(hpriv, USB_PORT_STAT_CONNECTION); - usbhsh_port_stat_set(hpriv, USB_PORT_STAT_C_CONNECTION << 16); - - /* - * enable attch interrupt again - * - * usbhsh_is_running() becomes invalid - * according to this process. - * see - * usbhsh_is_running() - * usbhsh_urb_enqueue() - */ - hpriv->mod.irq_attch = usbhsh_irq_attch; - usbhs_irq_callback_update(priv, &hpriv->mod); - - /* - * usbhsh_queue_force_pop_all() should be called - * after usbhsh_is_running() becomes invalid. - */ - usbhsh_queue_force_pop_all(priv); - - return 0; -} - -static int usbhsh_irq_setup_ack(struct usbhs_priv *priv, - struct usbhs_irq_state *irq_state) -{ - struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); - struct device *dev = usbhs_priv_to_dev(priv); - - dev_dbg(dev, "setup packet OK\n"); - - complete(&hpriv->setup_ack_done); /* see usbhsh_urb_enqueue() */ - - return 0; -} - -static int usbhsh_irq_setup_err(struct usbhs_priv *priv, - struct usbhs_irq_state *irq_state) -{ - struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); - struct device *dev = usbhs_priv_to_dev(priv); - - dev_dbg(dev, "setup packet Err\n"); - - complete(&hpriv->setup_ack_done); /* see usbhsh_urb_enqueue() */ - - return 0; -} - -/* - * module start/stop - */ -static void usbhsh_pipe_init_for_host(struct usbhs_priv *priv) -{ - struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); - struct usbhs_pipe *pipe; - u32 *pipe_type = usbhs_get_dparam(priv, pipe_type); - int pipe_size = usbhs_get_dparam(priv, pipe_size); - int old_type, dir_in, i; - - /* init all pipe */ - old_type = USB_ENDPOINT_XFER_CONTROL; - for (i = 0; i < pipe_size; i++) { - - /* - * data "output" will be finished as soon as possible, - * but there is no guaranty at data "input" case. - * - * "input" needs "standby" pipe. - * So, "input" direction pipe > "output" direction pipe - * is good idea. - * - * 1st USB_ENDPOINT_XFER_xxx will be output direction, - * and the other will be input direction here. - * - * ex) - * ... - * USB_ENDPOINT_XFER_ISOC -> dir out - * USB_ENDPOINT_XFER_ISOC -> dir in - * USB_ENDPOINT_XFER_BULK -> dir out - * USB_ENDPOINT_XFER_BULK -> dir in - * USB_ENDPOINT_XFER_BULK -> dir in - * ... - */ - dir_in = (pipe_type[i] == old_type); - old_type = pipe_type[i]; - - if (USB_ENDPOINT_XFER_CONTROL == pipe_type[i]) { - pipe = usbhs_dcp_malloc(priv); - usbhsh_hpriv_to_dcp(hpriv) = pipe; - } else { - pipe = usbhs_pipe_malloc(priv, - pipe_type[i], - dir_in); - } - - pipe->mod_private = NULL; - } -} - -static int usbhsh_start(struct usbhs_priv *priv) -{ - struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); - struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); - struct usbhs_mod *mod = usbhs_mod_get_current(priv); - struct device *dev = usbhs_priv_to_dev(priv); - int ret; - - /* add hcd */ - ret = usb_add_hcd(hcd, 0, 0); - if (ret < 0) - return 0; - - /* - * pipe initialize and enable DCP - */ - usbhs_pipe_init(priv, - usbhsh_dma_map_ctrl); - usbhs_fifo_init(priv); - usbhsh_pipe_init_for_host(priv); - - /* - * system config enble - * - HI speed - * - host - * - usb module - */ - usbhs_sys_host_ctrl(priv, 1); - - /* - * enable irq callback - */ - mod->irq_attch = usbhsh_irq_attch; - mod->irq_dtch = usbhsh_irq_dtch; - mod->irq_sack = usbhsh_irq_setup_ack; - mod->irq_sign = usbhsh_irq_setup_err; - usbhs_irq_callback_update(priv, mod); - - dev_dbg(dev, "start host\n"); - - return ret; -} - -static int usbhsh_stop(struct usbhs_priv *priv) -{ - struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); - struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); - struct usbhs_mod *mod = usbhs_mod_get_current(priv); - struct device *dev = usbhs_priv_to_dev(priv); - - /* - * disable irq callback - */ - mod->irq_attch = NULL; - mod->irq_dtch = NULL; - mod->irq_sack = NULL; - mod->irq_sign = NULL; - usbhs_irq_callback_update(priv, mod); - - usb_remove_hcd(hcd); - - /* disable sys */ - usbhs_sys_host_ctrl(priv, 0); - - dev_dbg(dev, "quit host\n"); - - return 0; -} - -int usbhs_mod_host_probe(struct usbhs_priv *priv) -{ - struct usbhsh_hpriv *hpriv; - struct usb_hcd *hcd; - struct usbhsh_device *udev; - struct device *dev = usbhs_priv_to_dev(priv); - int i; - - /* initialize hcd */ - hcd = usb_create_hcd(&usbhsh_driver, dev, usbhsh_hcd_name); - if (!hcd) { - dev_err(dev, "Failed to create hcd\n"); - return -ENOMEM; - } - hcd->has_tt = 1; /* for low/full speed */ - - /* - * CAUTION - * - * There is no guarantee that it is possible to access usb module here. - * Don't accesses to it. - * The accesse will be enable after "usbhsh_start" - */ - - hpriv = usbhsh_hcd_to_hpriv(hcd); - - /* - * register itself - */ - usbhs_mod_register(priv, &hpriv->mod, USBHS_HOST); - - /* init hpriv */ - hpriv->mod.name = "host"; - hpriv->mod.start = usbhsh_start; - hpriv->mod.stop = usbhsh_stop; - usbhsh_port_stat_init(hpriv); - - /* init all device */ - usbhsh_for_each_udev_with_dev0(udev, hpriv, i) { - udev->usbv = NULL; - INIT_LIST_HEAD(&udev->ep_list_head); - } - - dev_info(dev, "host probed\n"); - - return 0; -} - -int usbhs_mod_host_remove(struct usbhs_priv *priv) -{ - struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); - struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); - - usb_put_hcd(hcd); - - return 0; -} diff --git a/ANDROID_3.4.5/drivers/usb/renesas_usbhs/pipe.c b/ANDROID_3.4.5/drivers/usb/renesas_usbhs/pipe.c deleted file mode 100644 index feb06d6d..00000000 --- a/ANDROID_3.4.5/drivers/usb/renesas_usbhs/pipe.c +++ /dev/null @@ -1,725 +0,0 @@ -/* - * Renesas USB driver - * - * Copyright (C) 2011 Renesas Solutions Corp. - * Kuninori Morimoto - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -#include -#include -#include "./common.h" -#include "./pipe.h" - -/* - * macros - */ -#define usbhsp_addr_offset(p) ((usbhs_pipe_number(p) - 1) * 2) - -#define usbhsp_flags_set(p, f) ((p)->flags |= USBHS_PIPE_FLAGS_##f) -#define usbhsp_flags_clr(p, f) ((p)->flags &= ~USBHS_PIPE_FLAGS_##f) -#define usbhsp_flags_has(p, f) ((p)->flags & USBHS_PIPE_FLAGS_##f) -#define usbhsp_flags_init(p) do {(p)->flags = 0; } while (0) - -/* - * for debug - */ -static char *usbhsp_pipe_name[] = { - [USB_ENDPOINT_XFER_CONTROL] = "DCP", - [USB_ENDPOINT_XFER_BULK] = "BULK", - [USB_ENDPOINT_XFER_INT] = "INT", - [USB_ENDPOINT_XFER_ISOC] = "ISO", -}; - -char *usbhs_pipe_name(struct usbhs_pipe *pipe) -{ - return usbhsp_pipe_name[usbhs_pipe_type(pipe)]; -} - -/* - * DCPCTR/PIPEnCTR functions - */ -static void usbhsp_pipectrl_set(struct usbhs_pipe *pipe, u16 mask, u16 val) -{ - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - int offset = usbhsp_addr_offset(pipe); - - if (usbhs_pipe_is_dcp(pipe)) - usbhs_bset(priv, DCPCTR, mask, val); - else - usbhs_bset(priv, PIPEnCTR + offset, mask, val); -} - -static u16 usbhsp_pipectrl_get(struct usbhs_pipe *pipe) -{ - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - int offset = usbhsp_addr_offset(pipe); - - if (usbhs_pipe_is_dcp(pipe)) - return usbhs_read(priv, DCPCTR); - else - return usbhs_read(priv, PIPEnCTR + offset); -} - -/* - * DCP/PIPE functions - */ -static void __usbhsp_pipe_xxx_set(struct usbhs_pipe *pipe, - u16 dcp_reg, u16 pipe_reg, - u16 mask, u16 val) -{ - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - - if (usbhs_pipe_is_dcp(pipe)) - usbhs_bset(priv, dcp_reg, mask, val); - else - usbhs_bset(priv, pipe_reg, mask, val); -} - -/* - * DCPCFG/PIPECFG functions - */ -static void usbhsp_pipe_cfg_set(struct usbhs_pipe *pipe, u16 mask, u16 val) -{ - __usbhsp_pipe_xxx_set(pipe, DCPCFG, PIPECFG, mask, val); -} - -/* - * PIPEBUF - */ -static void usbhsp_pipe_buf_set(struct usbhs_pipe *pipe, u16 mask, u16 val) -{ - if (usbhs_pipe_is_dcp(pipe)) - return; - - __usbhsp_pipe_xxx_set(pipe, 0, PIPEBUF, mask, val); -} - -/* - * DCPMAXP/PIPEMAXP - */ -static void usbhsp_pipe_maxp_set(struct usbhs_pipe *pipe, u16 mask, u16 val) -{ - __usbhsp_pipe_xxx_set(pipe, DCPMAXP, PIPEMAXP, mask, val); -} - -/* - * pipe control functions - */ -static void usbhsp_pipe_select(struct usbhs_pipe *pipe) -{ - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - - /* - * On pipe, this is necessary before - * accesses to below registers. - * - * PIPESEL : usbhsp_pipe_select - * PIPECFG : usbhsp_pipe_cfg_xxx - * PIPEBUF : usbhsp_pipe_buf_xxx - * PIPEMAXP : usbhsp_pipe_maxp_xxx - * PIPEPERI - */ - - /* - * if pipe is dcp, no pipe is selected. - * it is no problem, because dcp have its register - */ - usbhs_write(priv, PIPESEL, 0xF & usbhs_pipe_number(pipe)); -} - -static int usbhsp_pipe_barrier(struct usbhs_pipe *pipe) -{ - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - int timeout = 1024; - u16 val; - - /* - * make sure.... - * - * Modify these bits when CSSTS = 0, PID = NAK, and no pipe number is - * specified by the CURPIPE bits. - * When changing the setting of this bit after changing - * the PID bits for the selected pipe from BUF to NAK, - * check that CSSTS = 0 and PBUSY = 0. - */ - - /* - * CURPIPE bit = 0 - * - * see also - * "Operation" - * - "Pipe Control" - * - "Pipe Control Registers Switching Procedure" - */ - usbhs_write(priv, CFIFOSEL, 0); - usbhs_pipe_disable(pipe); - - do { - val = usbhsp_pipectrl_get(pipe); - val &= CSSTS | PID_MASK; - if (!val) - return 0; - - udelay(10); - - } while (timeout--); - - return -EBUSY; -} - -int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe) -{ - u16 val; - - val = usbhsp_pipectrl_get(pipe); - if (val & BSTS) - return 0; - - return -EBUSY; -} - -/* - * PID ctrl - */ -static void __usbhsp_pid_try_nak_if_stall(struct usbhs_pipe *pipe) -{ - u16 pid = usbhsp_pipectrl_get(pipe); - - pid &= PID_MASK; - - /* - * see - * "Pipe n Control Register" - "PID" - */ - switch (pid) { - case PID_STALL11: - usbhsp_pipectrl_set(pipe, PID_MASK, PID_STALL10); - /* fall-through */ - case PID_STALL10: - usbhsp_pipectrl_set(pipe, PID_MASK, PID_NAK); - } -} - -void usbhs_pipe_disable(struct usbhs_pipe *pipe) -{ - int timeout = 1024; - u16 val; - - /* see "Pipe n Control Register" - "PID" */ - __usbhsp_pid_try_nak_if_stall(pipe); - - usbhsp_pipectrl_set(pipe, PID_MASK, PID_NAK); - - do { - val = usbhsp_pipectrl_get(pipe); - val &= PBUSY; - if (!val) - break; - - udelay(10); - } while (timeout--); -} - -void usbhs_pipe_enable(struct usbhs_pipe *pipe) -{ - /* see "Pipe n Control Register" - "PID" */ - __usbhsp_pid_try_nak_if_stall(pipe); - - usbhsp_pipectrl_set(pipe, PID_MASK, PID_BUF); -} - -void usbhs_pipe_stall(struct usbhs_pipe *pipe) -{ - u16 pid = usbhsp_pipectrl_get(pipe); - - pid &= PID_MASK; - - /* - * see - * "Pipe n Control Register" - "PID" - */ - switch (pid) { - case PID_NAK: - usbhsp_pipectrl_set(pipe, PID_MASK, PID_STALL10); - break; - case PID_BUF: - usbhsp_pipectrl_set(pipe, PID_MASK, PID_STALL11); - break; - } -} - -int usbhs_pipe_is_stall(struct usbhs_pipe *pipe) -{ - u16 pid = usbhsp_pipectrl_get(pipe) & PID_MASK; - - return (int)(pid == PID_STALL10 || pid == PID_STALL11); -} - -/* - * pipe setup - */ -static int usbhsp_possible_double_buffer(struct usbhs_pipe *pipe) -{ - /* - * only ISO / BULK pipe can use double buffer - */ - if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK) || - usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_ISOC)) - return 1; - - return 0; -} - -static u16 usbhsp_setup_pipecfg(struct usbhs_pipe *pipe, - int is_host, - int dir_in) -{ - u16 type = 0; - u16 bfre = 0; - u16 dblb = 0; - u16 cntmd = 0; - u16 dir = 0; - u16 epnum = 0; - u16 shtnak = 0; - u16 type_array[] = { - [USB_ENDPOINT_XFER_BULK] = TYPE_BULK, - [USB_ENDPOINT_XFER_INT] = TYPE_INT, - [USB_ENDPOINT_XFER_ISOC] = TYPE_ISO, - }; - int is_double = usbhsp_possible_double_buffer(pipe); - - if (usbhs_pipe_is_dcp(pipe)) - return -EINVAL; - - /* - * PIPECFG - * - * see - * - "Register Descriptions" - "PIPECFG" register - * - "Features" - "Pipe configuration" - * - "Operation" - "Pipe Control" - */ - - /* TYPE */ - type = type_array[usbhs_pipe_type(pipe)]; - - /* BFRE */ - if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_ISOC) || - usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK)) - bfre = 0; /* FIXME */ - - /* DBLB */ - if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_ISOC) || - usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK)) - dblb = (is_double) ? DBLB : 0; - - /* CNTMD */ - if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK)) - cntmd = 0; /* FIXME */ - - /* DIR */ - if (dir_in) - usbhsp_flags_set(pipe, IS_DIR_HOST); - - if (!!is_host ^ !!dir_in) - dir |= DIR_OUT; - - if (!dir) - usbhsp_flags_set(pipe, IS_DIR_IN); - - /* SHTNAK */ - if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK) && - !dir) - shtnak = SHTNAK; - - /* EPNUM */ - epnum = 0; /* see usbhs_pipe_config_update() */ - - return type | - bfre | - dblb | - cntmd | - dir | - shtnak | - epnum; -} - -static u16 usbhsp_setup_pipebuff(struct usbhs_pipe *pipe) -{ - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); - struct device *dev = usbhs_priv_to_dev(priv); - int pipe_num = usbhs_pipe_number(pipe); - int is_double = usbhsp_possible_double_buffer(pipe); - u16 buff_size; - u16 bufnmb; - u16 bufnmb_cnt; - - /* - * PIPEBUF - * - * see - * - "Register Descriptions" - "PIPEBUF" register - * - "Features" - "Pipe configuration" - * - "Operation" - "FIFO Buffer Memory" - * - "Operation" - "Pipe Control" - * - * ex) if pipe6 - pipe9 are USB_ENDPOINT_XFER_INT (SH7724) - * - * BUFNMB: PIPE - * 0: pipe0 (DCP 256byte) - * 1: - - * 2: - - * 3: - - * 4: pipe6 (INT 64byte) - * 5: pipe7 (INT 64byte) - * 6: pipe8 (INT 64byte) - * 7: pipe9 (INT 64byte) - * 8 - xx: free (for BULK, ISOC) - */ - - /* - * FIXME - * - * it doesn't have good buffer allocator - * - * DCP : 256 byte - * BULK: 512 byte - * INT : 64 byte - * ISOC: 512 byte - */ - if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_CONTROL)) - buff_size = 256; - else if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_INT)) - buff_size = 64; - else - buff_size = 512; - - /* change buff_size to register value */ - bufnmb_cnt = (buff_size / 64) - 1; - - /* BUFNMB has been reserved for INT pipe - * see above */ - if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_INT)) { - bufnmb = pipe_num - 2; - } else { - bufnmb = info->bufnmb_last; - info->bufnmb_last += bufnmb_cnt + 1; - - /* - * double buffer - */ - if (is_double) - info->bufnmb_last += bufnmb_cnt + 1; - } - - dev_dbg(dev, "pipe : %d : buff_size 0x%x: bufnmb 0x%x\n", - pipe_num, buff_size, bufnmb); - - return (0x1f & bufnmb_cnt) << 10 | - (0xff & bufnmb) << 0; -} - -void usbhs_pipe_config_update(struct usbhs_pipe *pipe, u16 devsel, - u16 epnum, u16 maxp) -{ - if (devsel > 0xA) { - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - struct device *dev = usbhs_priv_to_dev(priv); - - dev_err(dev, "devsel error %d\n", devsel); - - devsel = 0; - } - - usbhsp_pipe_barrier(pipe); - - pipe->maxp = maxp; - - usbhsp_pipe_select(pipe); - usbhsp_pipe_maxp_set(pipe, 0xFFFF, - (devsel << 12) | - maxp); - - if (!usbhs_pipe_is_dcp(pipe)) - usbhsp_pipe_cfg_set(pipe, 0x000F, epnum); -} - -/* - * pipe control - */ -int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe) -{ - /* - * see - * usbhs_pipe_config_update() - * usbhs_dcp_malloc() - */ - return pipe->maxp; -} - -int usbhs_pipe_is_dir_in(struct usbhs_pipe *pipe) -{ - return usbhsp_flags_has(pipe, IS_DIR_IN); -} - -int usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe) -{ - return usbhsp_flags_has(pipe, IS_DIR_HOST); -} - -void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int sequence) -{ - u16 mask = (SQCLR | SQSET); - u16 val; - - /* - * sequence - * 0 : data0 - * 1 : data1 - * -1 : no change - */ - switch (sequence) { - case 0: - val = SQCLR; - break; - case 1: - val = SQSET; - break; - default: - return; - } - - usbhsp_pipectrl_set(pipe, mask, val); -} - -void usbhs_pipe_clear(struct usbhs_pipe *pipe) -{ - usbhsp_pipectrl_set(pipe, ACLRM, ACLRM); - usbhsp_pipectrl_set(pipe, ACLRM, 0); -} - -static struct usbhs_pipe *usbhsp_get_pipe(struct usbhs_priv *priv, u32 type) -{ - struct usbhs_pipe *pos, *pipe; - int i; - - /* - * find target pipe - */ - pipe = NULL; - usbhs_for_each_pipe_with_dcp(pos, priv, i) { - if (!usbhs_pipe_type_is(pos, type)) - continue; - if (usbhsp_flags_has(pos, IS_USED)) - continue; - - pipe = pos; - break; - } - - if (!pipe) - return NULL; - - /* - * initialize pipe flags - */ - usbhsp_flags_init(pipe); - usbhsp_flags_set(pipe, IS_USED); - - return pipe; -} - -void usbhs_pipe_init(struct usbhs_priv *priv, - int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map)) -{ - struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); - struct usbhs_pipe *pipe; - int i; - - /* - * FIXME - * - * driver needs good allocator. - * - * find first free buffer area (BULK, ISOC) - * (DCP, INT area is fixed) - * - * buffer number 0 - 3 have been reserved for DCP - * see - * usbhsp_to_bufnmb - */ - info->bufnmb_last = 4; - usbhs_for_each_pipe_with_dcp(pipe, priv, i) { - if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_INT)) - info->bufnmb_last++; - - usbhsp_flags_init(pipe); - pipe->fifo = NULL; - pipe->mod_private = NULL; - INIT_LIST_HEAD(&pipe->list); - - /* pipe force init */ - usbhs_pipe_clear(pipe); - } - - info->dma_map_ctrl = dma_map_ctrl; -} - -struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv, - int endpoint_type, - int dir_in) -{ - struct device *dev = usbhs_priv_to_dev(priv); - struct usbhs_pipe *pipe; - int is_host = usbhs_mod_is_host(priv); - int ret; - u16 pipecfg, pipebuf; - - pipe = usbhsp_get_pipe(priv, endpoint_type); - if (!pipe) { - dev_err(dev, "can't get pipe (%s)\n", - usbhsp_pipe_name[endpoint_type]); - return NULL; - } - - INIT_LIST_HEAD(&pipe->list); - - usbhs_pipe_disable(pipe); - - /* make sure pipe is not busy */ - ret = usbhsp_pipe_barrier(pipe); - if (ret < 0) { - dev_err(dev, "pipe setup failed %d\n", usbhs_pipe_number(pipe)); - return NULL; - } - - pipecfg = usbhsp_setup_pipecfg(pipe, is_host, dir_in); - pipebuf = usbhsp_setup_pipebuff(pipe); - - usbhsp_pipe_select(pipe); - usbhsp_pipe_cfg_set(pipe, 0xFFFF, pipecfg); - usbhsp_pipe_buf_set(pipe, 0xFFFF, pipebuf); - - usbhs_pipe_sequence_data0(pipe); - - dev_dbg(dev, "enable pipe %d : %s (%s)\n", - usbhs_pipe_number(pipe), - usbhs_pipe_name(pipe), - usbhs_pipe_is_dir_in(pipe) ? "in" : "out"); - - /* - * epnum / maxp are still not set to this pipe. - * call usbhs_pipe_config_update() after this function !! - */ - - return pipe; -} - -void usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo) -{ - if (pipe->fifo) - pipe->fifo->pipe = NULL; - - pipe->fifo = fifo; - - if (fifo) - fifo->pipe = pipe; -} - - -/* - * dcp control - */ -struct usbhs_pipe *usbhs_dcp_malloc(struct usbhs_priv *priv) -{ - struct usbhs_pipe *pipe; - - pipe = usbhsp_get_pipe(priv, USB_ENDPOINT_XFER_CONTROL); - if (!pipe) - return NULL; - - INIT_LIST_HEAD(&pipe->list); - - /* - * call usbhs_pipe_config_update() after this function !! - */ - - return pipe; -} - -void usbhs_dcp_control_transfer_done(struct usbhs_pipe *pipe) -{ - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - - WARN_ON(!usbhs_pipe_is_dcp(pipe)); - - usbhs_pipe_enable(pipe); - - if (!usbhs_mod_is_host(priv)) /* funconly */ - usbhsp_pipectrl_set(pipe, CCPL, CCPL); -} - -void usbhs_dcp_dir_for_host(struct usbhs_pipe *pipe, int dir_out) -{ - usbhsp_pipe_cfg_set(pipe, DIR_OUT, - dir_out ? DIR_OUT : 0); -} - -/* - * pipe module function - */ -int usbhs_pipe_probe(struct usbhs_priv *priv) -{ - struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); - struct usbhs_pipe *pipe; - struct device *dev = usbhs_priv_to_dev(priv); - u32 *pipe_type = usbhs_get_dparam(priv, pipe_type); - int pipe_size = usbhs_get_dparam(priv, pipe_size); - int i; - - /* This driver expects 1st pipe is DCP */ - if (pipe_type[0] != USB_ENDPOINT_XFER_CONTROL) { - dev_err(dev, "1st PIPE is not DCP\n"); - return -EINVAL; - } - - info->pipe = kzalloc(sizeof(struct usbhs_pipe) * pipe_size, GFP_KERNEL); - if (!info->pipe) { - dev_err(dev, "Could not allocate pipe\n"); - return -ENOMEM; - } - - info->size = pipe_size; - - /* - * init pipe - */ - usbhs_for_each_pipe_with_dcp(pipe, priv, i) { - pipe->priv = priv; - - usbhs_pipe_type(pipe) = - pipe_type[i] & USB_ENDPOINT_XFERTYPE_MASK; - - dev_dbg(dev, "pipe %x\t: %s\n", - i, usbhsp_pipe_name[pipe_type[i]]); - } - - return 0; -} - -void usbhs_pipe_remove(struct usbhs_priv *priv) -{ - struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); - - kfree(info->pipe); -} diff --git a/ANDROID_3.4.5/drivers/usb/renesas_usbhs/pipe.h b/ANDROID_3.4.5/drivers/usb/renesas_usbhs/pipe.h deleted file mode 100644 index fa18b7dc..00000000 --- a/ANDROID_3.4.5/drivers/usb/renesas_usbhs/pipe.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Renesas USB driver - * - * Copyright (C) 2011 Renesas Solutions Corp. - * Kuninori Morimoto - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -#ifndef RENESAS_USB_PIPE_H -#define RENESAS_USB_PIPE_H - -#include "./common.h" -#include "./fifo.h" - -/* - * struct - */ -struct usbhs_pipe { - u32 pipe_type; /* USB_ENDPOINT_XFER_xxx */ - - struct usbhs_priv *priv; - struct usbhs_fifo *fifo; - struct list_head list; - - int maxp; - - u32 flags; -#define USBHS_PIPE_FLAGS_IS_USED (1 << 0) -#define USBHS_PIPE_FLAGS_IS_DIR_IN (1 << 1) -#define USBHS_PIPE_FLAGS_IS_DIR_HOST (1 << 2) - - struct usbhs_pkt_handle *handler; - - void *mod_private; -}; - -struct usbhs_pipe_info { - struct usbhs_pipe *pipe; - int size; /* array size of "pipe" */ - int bufnmb_last; /* FIXME : driver needs good allocator */ - - int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map); -}; - -/* - * pipe list - */ -#define __usbhs_for_each_pipe(start, pos, info, i) \ - for (i = start, pos = (info)->pipe; \ - i < (info)->size; \ - i++, pos = (info)->pipe + i) - -#define usbhs_for_each_pipe(pos, priv, i) \ - __usbhs_for_each_pipe(1, pos, &((priv)->pipe_info), i) - -#define usbhs_for_each_pipe_with_dcp(pos, priv, i) \ - __usbhs_for_each_pipe(0, pos, &((priv)->pipe_info), i) - -/* - * data - */ -#define usbhs_priv_to_pipeinfo(pr) (&(pr)->pipe_info) - -/* - * pipe control - */ -char *usbhs_pipe_name(struct usbhs_pipe *pipe); -struct usbhs_pipe -*usbhs_pipe_malloc(struct usbhs_priv *priv, int endpoint_type, int dir_in); -int usbhs_pipe_probe(struct usbhs_priv *priv); -void usbhs_pipe_remove(struct usbhs_priv *priv); -int usbhs_pipe_is_dir_in(struct usbhs_pipe *pipe); -int usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe); -void usbhs_pipe_init(struct usbhs_priv *priv, - int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map)); -int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe); -void usbhs_pipe_clear(struct usbhs_pipe *pipe); -int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe); -void usbhs_pipe_enable(struct usbhs_pipe *pipe); -void usbhs_pipe_disable(struct usbhs_pipe *pipe); -void usbhs_pipe_stall(struct usbhs_pipe *pipe); -int usbhs_pipe_is_stall(struct usbhs_pipe *pipe); -void usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo); -void usbhs_pipe_config_update(struct usbhs_pipe *pipe, u16 devsel, - u16 epnum, u16 maxp); - -#define usbhs_pipe_sequence_data0(pipe) usbhs_pipe_data_sequence(pipe, 0) -#define usbhs_pipe_sequence_data1(pipe) usbhs_pipe_data_sequence(pipe, 1) -void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int data); - -#define usbhs_pipe_to_priv(p) ((p)->priv) -#define usbhs_pipe_number(p) (int)((p) - (p)->priv->pipe_info.pipe) -#define usbhs_pipe_is_dcp(p) ((p)->priv->pipe_info.pipe == (p)) -#define usbhs_pipe_to_fifo(p) ((p)->fifo) -#define usbhs_pipe_is_busy(p) usbhs_pipe_to_fifo(p) - -#define usbhs_pipe_type(p) ((p)->pipe_type) -#define usbhs_pipe_type_is(p, t) ((p)->pipe_type == t) - -/* - * dcp control - */ -struct usbhs_pipe *usbhs_dcp_malloc(struct usbhs_priv *priv); -void usbhs_dcp_control_transfer_done(struct usbhs_pipe *pipe); -void usbhs_dcp_dir_for_host(struct usbhs_pipe *pipe, int dir_out); - -#endif /* RENESAS_USB_PIPE_H */ diff --git a/ANDROID_3.4.5/drivers/usb/serial/Kconfig b/ANDROID_3.4.5/drivers/usb/serial/Kconfig deleted file mode 100644 index 7141d659..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/Kconfig +++ /dev/null @@ -1,682 +0,0 @@ -# -# USB Serial device configuration -# - -menuconfig USB_SERIAL - tristate "USB Serial Converter support" - depends on USB - ---help--- - Say Y here if you have a USB device that provides normal serial - ports, or acts like a serial device, and you want to connect it to - your USB bus. - - Please read for more - information on the specifics of the different devices that are - supported, and on how to use them. - - To compile this driver as a module, choose M here: the - module will be called usbserial. - -if USB_SERIAL - -config USB_SERIAL_CONSOLE - bool "USB Serial Console device support" - depends on USB_SERIAL=y - ---help--- - If you say Y here, it will be possible to use a USB to serial - converter port as the system console (the system console is the - device which receives all kernel messages and warnings and which - allows logins in single user mode). This could be useful if some - terminal or printer is connected to that serial port. - - Even if you say Y here, the currently visible virtual console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttyUSB0". (Try "man bootparam" or see the documentation of - your boot loader (lilo or loadlin) about how to pass options to the - kernel at boot time.) - - If you don't have a VGA card installed and you say Y here, the - kernel will automatically use the first USB to serial converter - port, /dev/ttyUSB0, as system console. - - If unsure, say N. - -config USB_EZUSB - bool "Functions for loading firmware on EZUSB chips" - help - Say Y here if you need EZUSB device support. - -config USB_SERIAL_GENERIC - bool "USB Generic Serial Driver" - help - Say Y here if you want to use the generic USB serial driver. Please - read for more information on - using this driver. It is recommended that the "USB Serial converter - support" be compiled as a module for this driver to be used - properly. - -config USB_SERIAL_AIRCABLE - tristate "USB AIRcable Bluetooth Dongle Driver" - help - Say Y here if you want to use USB AIRcable Bluetooth Dongle. - - To compile this driver as a module, choose M here: the module - will be called aircable. - -config USB_SERIAL_ARK3116 - tristate "USB ARK Micro 3116 USB Serial Driver" - help - Say Y here if you want to use a ARK Micro 3116 USB to Serial - device. - - To compile this driver as a module, choose M here: the - module will be called ark3116 - -config USB_SERIAL_BELKIN - tristate "USB Belkin and Peracom Single Port Serial Driver" - help - Say Y here if you want to use a Belkin USB Serial single port - adaptor (F5U103 is one of the model numbers) or the Peracom single - port USB to serial adapter. - - To compile this driver as a module, choose M here: the - module will be called belkin_sa. - -config USB_SERIAL_CH341 - tristate "USB Winchiphead CH341 Single Port Serial Driver" - help - Say Y here if you want to use a Winchiphead CH341 single port - USB to serial adapter. - - To compile this driver as a module, choose M here: the - module will be called ch341. - -config USB_SERIAL_WHITEHEAT - tristate "USB ConnectTech WhiteHEAT Serial Driver" - select USB_EZUSB - help - Say Y here if you want to use a ConnectTech WhiteHEAT 4 port - USB to serial converter device. - - To compile this driver as a module, choose M here: the - module will be called whiteheat. - -config USB_SERIAL_DIGI_ACCELEPORT - tristate "USB Digi International AccelePort USB Serial Driver" - ---help--- - Say Y here if you want to use Digi AccelePort USB 2 or 4 devices, - 2 port (plus parallel port) and 4 port USB serial converters. The - parallel port on the USB 2 appears as a third serial port on Linux. - The Digi Acceleport USB 8 is not yet supported by this driver. - - This driver works under SMP with the usb-uhci driver. It does not - work under SMP with the uhci driver. - - To compile this driver as a module, choose M here: the - module will be called digi_acceleport. - -config USB_SERIAL_CP210X - tristate "USB CP210x family of UART Bridge Controllers" - help - Say Y here if you want to use a CP2101/CP2102/CP2103 based USB - to RS232 converters. - - To compile this driver as a module, choose M here: the - module will be called cp210x. - -config USB_SERIAL_CYPRESS_M8 - tristate "USB Cypress M8 USB Serial Driver" - help - Say Y here if you want to use a device that contains the Cypress - USB to Serial microcontroller, such as the DeLorme Earthmate GPS. - - Attempted SMP support... send bug reports! - - Supported microcontrollers in the CY4601 family are: - CY7C63741 CY7C63742 CY7C63743 CY7C64013 - - To compile this driver as a module, choose M here: the - module will be called cypress_m8. - -config USB_SERIAL_EMPEG - tristate "USB Empeg empeg-car Mark I/II Driver" - help - Say Y here if you want to connect to your Empeg empeg-car Mark I/II - mp3 player via USB. The driver uses a single ttyUSB{0,1,2,...} - device node. See for more - tidbits of information. - - To compile this driver as a module, choose M here: the - module will be called empeg. - -config USB_SERIAL_FTDI_SIO - tristate "USB FTDI Single Port Serial Driver" - ---help--- - Say Y here if you want to use a FTDI SIO single port USB to serial - converter device. The implementation I have is called the USC-1000. - This driver has also be tested with the 245 and 232 devices. - - See for more - information on this driver and the device. - - To compile this driver as a module, choose M here: the - module will be called ftdi_sio. - -config USB_SERIAL_FUNSOFT - tristate "USB Fundamental Software Dongle Driver" - ---help--- - Say Y here if you want to use the Fundamental Software dongle. - - To compile this driver as a module, choose M here: the - module will be called funsoft. - -config USB_SERIAL_VISOR - tristate "USB Handspring Visor / Palm m50x / Sony Clie Driver" - help - Say Y here if you want to connect to your HandSpring Visor, Palm - m500 or m505 through its USB docking station. See - for more information on using this - driver. - - To compile this driver as a module, choose M here: the - module will be called visor. - -config USB_SERIAL_IPAQ - tristate "USB PocketPC PDA Driver" - help - Say Y here if you want to connect to your Compaq iPAQ, HP Jornada - or any other PDA running Windows CE 3.0 or PocketPC 2002 - using a USB cradle/cable. For information on using the driver, - read . - - To compile this driver as a module, choose M here: the - module will be called ipaq. - -config USB_SERIAL_IR - tristate "USB IR Dongle Serial Driver" - help - Say Y here if you want to enable simple serial support for USB IrDA - devices. This is useful if you do not want to use the full IrDA - stack. - - To compile this driver as a module, choose M here: the - module will be called ir-usb. - -config USB_SERIAL_EDGEPORT - tristate "USB Inside Out Edgeport Serial Driver" - ---help--- - Say Y here if you want to use any of the following devices from - Inside Out Networks (Digi): - Edgeport/4 - Rapidport/4 - Edgeport/4t - Edgeport/2 - Edgeport/4i - Edgeport/2i - Edgeport/421 - Edgeport/21 - Edgeport/8 - Edgeport/8 Dual - Edgeport/2D8 - Edgeport/4D8 - Edgeport/8i - Edgeport/2 DIN - Edgeport/4 DIN - Edgeport/16 Dual - - To compile this driver as a module, choose M here: the - module will be called io_edgeport. - -config USB_SERIAL_EDGEPORT_TI - tristate "USB Inside Out Edgeport Serial Driver (TI devices)" - help - Say Y here if you want to use any of the devices from Inside Out - Networks (Digi) that are not supported by the io_edgeport driver. - This includes the Edgeport/1 device. - - To compile this driver as a module, choose M here: the - module will be called io_ti. - -config USB_SERIAL_F81232 - tristate "USB Fintek F81232 Single Port Serial Driver" - help - Say Y here if you want to use the Fintek F81232 single - port usb to serial adapter. - - To compile this driver as a module, choose M here: the - module will be called f81232. - -config USB_SERIAL_GARMIN - tristate "USB Garmin GPS driver" - help - Say Y here if you want to connect to your Garmin GPS. - Should work with most Garmin GPS devices which have a native USB port. - - See for the latest - version of the driver. - - To compile this driver as a module, choose M here: the - module will be called garmin_gps. - -config USB_SERIAL_IPW - tristate "USB IPWireless (3G UMTS TDD) Driver" - select USB_SERIAL_WWAN - help - Say Y here if you want to use a IPWireless USB modem such as - the ones supplied by Axity3G/Sentech South Africa. - - To compile this driver as a module, choose M here: the - module will be called ipw. - -config USB_SERIAL_IUU - tristate "USB Infinity USB Unlimited Phoenix Driver" - help - Say Y here if you want to use a IUU in phoenix mode and get - an extra ttyUSBx device. More information available on - http://eczema.ecze.com/iuu_phoenix.html - - To compile this driver as a module, choose M here: the - module will be called iuu_phoenix.o - -config USB_SERIAL_KEYSPAN_PDA - tristate "USB Keyspan PDA Single Port Serial Driver" - select USB_EZUSB - help - Say Y here if you want to use a Keyspan PDA single port USB to - serial converter device. This driver makes use of firmware - developed from scratch by Brian Warner. - - To compile this driver as a module, choose M here: the - module will be called keyspan_pda. - -config USB_SERIAL_KEYSPAN - tristate "USB Keyspan USA-xxx Serial Driver" - select USB_EZUSB - ---help--- - Say Y here if you want to use Keyspan USB to serial converter - devices. This driver makes use of Keyspan's official firmware - and was developed with their support. You must also include - firmware to support your particular device(s). - - See for more information. - - To compile this driver as a module, choose M here: the - module will be called keyspan. - -config USB_SERIAL_KEYSPAN_MPR - bool "USB Keyspan MPR Firmware" - depends on USB_SERIAL_KEYSPAN && FIRMWARE_IN_KERNEL - help - Say Y here to include firmware for the Keyspan MPR converter. - -config USB_SERIAL_KEYSPAN_USA28 - bool "USB Keyspan USA-28 Firmware" - depends on USB_SERIAL_KEYSPAN && FIRMWARE_IN_KERNEL - help - Say Y here to include firmware for the USA-28 converter. - -config USB_SERIAL_KEYSPAN_USA28X - bool "USB Keyspan USA-28X Firmware" - depends on USB_SERIAL_KEYSPAN && FIRMWARE_IN_KERNEL - help - Say Y here to include firmware for the USA-28X converter. - Be sure you have a USA-28X, there are also 28XA and 28XB - models, the label underneath has the actual part number. - -config USB_SERIAL_KEYSPAN_USA28XA - bool "USB Keyspan USA-28XA Firmware" - depends on USB_SERIAL_KEYSPAN && FIRMWARE_IN_KERNEL - help - Say Y here to include firmware for the USA-28XA converter. - Be sure you have a USA-28XA, there are also 28X and 28XB - models, the label underneath has the actual part number. - -config USB_SERIAL_KEYSPAN_USA28XB - bool "USB Keyspan USA-28XB Firmware" - depends on USB_SERIAL_KEYSPAN && FIRMWARE_IN_KERNEL - help - Say Y here to include firmware for the USA-28XB converter. - Be sure you have a USA-28XB, there are also 28X and 28XA - models, the label underneath has the actual part number. - -config USB_SERIAL_KEYSPAN_USA19 - bool "USB Keyspan USA-19 Firmware" - depends on USB_SERIAL_KEYSPAN && FIRMWARE_IN_KERNEL - help - Say Y here to include firmware for the USA-19 converter. - -config USB_SERIAL_KEYSPAN_USA18X - bool "USB Keyspan USA-18X Firmware" - depends on USB_SERIAL_KEYSPAN && FIRMWARE_IN_KERNEL - help - Say Y here to include firmware for the USA-18X converter. - -config USB_SERIAL_KEYSPAN_USA19W - bool "USB Keyspan USA-19W Firmware" - depends on USB_SERIAL_KEYSPAN && FIRMWARE_IN_KERNEL - help - Say Y here to include firmware for the USA-19W converter. - -config USB_SERIAL_KEYSPAN_USA19QW - bool "USB Keyspan USA-19QW Firmware" - depends on USB_SERIAL_KEYSPAN && FIRMWARE_IN_KERNEL - help - Say Y here to include firmware for the USA-19QW converter. - -config USB_SERIAL_KEYSPAN_USA19QI - bool "USB Keyspan USA-19QI Firmware" - depends on USB_SERIAL_KEYSPAN && FIRMWARE_IN_KERNEL - help - Say Y here to include firmware for the USA-19QI converter. - -config USB_SERIAL_KEYSPAN_USA49W - bool "USB Keyspan USA-49W Firmware" - depends on USB_SERIAL_KEYSPAN && FIRMWARE_IN_KERNEL - help - Say Y here to include firmware for the USA-49W converter. - -config USB_SERIAL_KEYSPAN_USA49WLC - bool "USB Keyspan USA-49WLC Firmware" - depends on USB_SERIAL_KEYSPAN && FIRMWARE_IN_KERNEL - help - Say Y here to include firmware for the USA-49WLC converter. - -config USB_SERIAL_KLSI - tristate "USB KL5KUSB105 (Palmconnect) Driver" - ---help--- - Say Y here if you want to use a KL5KUSB105 - based single port - serial adapter. The most widely known -- and currently the only - tested -- device in this category is the PalmConnect USB Serial - adapter sold by Palm Inc. for use with their Palm III and Palm V - series PDAs. - - Please read for more - information. - - To compile this driver as a module, choose M here: the - module will be called kl5kusb105. - -config USB_SERIAL_KOBIL_SCT - tristate "USB KOBIL chipcard reader" - ---help--- - Say Y here if you want to use one of the following KOBIL USB chipcard - readers: - - - USB TWIN - - KAAN Standard Plus - - KAAN SIM - - SecOVID Reader Plus - - B1 Professional - - KAAN Professional - - Note that you need a current CT-API. - To compile this driver as a module, choose M here: the - module will be called kobil_sct. - -config USB_SERIAL_MCT_U232 - tristate "USB MCT Single Port Serial Driver" - ---help--- - Say Y here if you want to use a USB Serial single port adapter from - Magic Control Technology Corp. (U232 is one of the model numbers). - - This driver also works with Sitecom U232-P25 and D-Link DU-H3SP USB - BAY, Belkin F5U109, and Belkin F5U409 devices. - - To compile this driver as a module, choose M here: the - module will be called mct_u232. - -config USB_SERIAL_METRO - tristate "USB Metrologic Instruments USB-POS Barcode Scanner Driver" - ---help--- - Say Y here if you want to use a USB POS Metrologic barcode scanner. - - To compile this driver as a module, choose M here: the - module will be called metro-usb. - -config USB_SERIAL_MOS7720 - tristate "USB Moschip 7720 Serial Driver" - ---help--- - Say Y here if you want to use USB Serial single and double - port adapters from Moschip Semiconductor Tech. - - To compile this driver as a module, choose M here: the - module will be called mos7720. - -config USB_SERIAL_MOS7715_PARPORT - bool "Support for parallel port on the Moschip 7715" - depends on USB_SERIAL_MOS7720 - depends on PARPORT=y || PARPORT=USB_SERIAL_MOS7720 - select PARPORT_NOT_PC - ---help--- - Say Y if you have a Moschip 7715 device and would like to use - the parallel port it provides. The port will register with - the parport subsystem as a low-level driver. - -config USB_SERIAL_MOS7840 - tristate "USB Moschip 7840/7820 USB Serial Driver" - ---help--- - Say Y here if you want to use a MCS7840 Quad-Serial or MCS7820 - Dual-Serial port device from MosChip Semiconductor. - - The MCS7840 and MCS7820 have been developed to connect a wide range - of standard serial devices to a USB host. The MCS7840 has a USB - device controller connected to four (4) individual UARTs while the - MCS7820 controller connects to two (2) individual UARTs. - - To compile this driver as a module, choose M here: the - module will be called mos7840. If unsure, choose N. - -config USB_SERIAL_MOTOROLA - tristate "USB Motorola Phone modem driver" - ---help--- - Say Y here if you want to use a Motorola phone with a USB - connector as a modem link. - - To compile this driver as a module, choose M here: the - module will be called moto_modem. If unsure, choose N. - -config USB_SERIAL_NAVMAN - tristate "USB Navman GPS device" - help - To compile this driver as a module, choose M here: the - module will be called navman. - -config USB_SERIAL_PL2303 - tristate "USB Prolific 2303 Single Port Serial Driver" - help - Say Y here if you want to use the PL2303 USB Serial single port - adapter from Prolific. - - To compile this driver as a module, choose M here: the - module will be called pl2303. - -config USB_SERIAL_OTI6858 - tristate "USB Ours Technology Inc. OTi-6858 USB To RS232 Bridge Controller" - help - Say Y here if you want to use the OTi-6858 single port USB to serial - converter device. - - To compile this driver as a module, choose M here: the - module will be called oti6858. - -config USB_SERIAL_QCAUX - tristate "USB Qualcomm Auxiliary Serial Port Driver" - help - Say Y here if you want to use the auxiliary serial ports provided - by many modems based on Qualcomm chipsets. These ports often use - a proprietary protocol called DM and cannot be used for AT- or - PPP-based communication. - - To compile this driver as a module, choose M here: the - module will be called qcaux. If unsure, choose N. - -config USB_SERIAL_QUALCOMM - tristate "USB Qualcomm Serial modem" - select USB_SERIAL_WWAN - help - Say Y here if you have a Qualcomm USB modem device. These are - usually wireless cellular modems. - - To compile this driver as a module, choose M here: the - module will be called qcserial. - -config USB_SERIAL_SPCP8X5 - tristate "USB SPCP8x5 USB To Serial Driver" - help - Say Y here if you want to use the spcp8x5 converter chip. This is - commonly found in some Z-Wave USB devices. - - To compile this driver as a module, choose M here: the - module will be called spcp8x5. - -config USB_SERIAL_HP4X - tristate "USB HP4x Calculators support" - help - Say Y here if you want to use an Hewlett-Packard 4x Calculator. - - To compile this driver as a module, choose M here: the - module will be called hp4x. - -config USB_SERIAL_SAFE - tristate "USB Safe Serial (Encapsulated) Driver" - -config USB_SERIAL_SAFE_PADDED - bool "USB Secure Encapsulated Driver - Padded" - depends on USB_SERIAL_SAFE - -config USB_SERIAL_SIEMENS_MPI - tristate "USB Siemens MPI driver" - help - Say M here if you want to use a Siemens USB/MPI adapter. - - To compile this driver as a module, choose M here: the - module will be called siemens_mpi. - -config USB_SERIAL_SIERRAWIRELESS - tristate "USB Sierra Wireless Driver" - help - Say M here if you want to use Sierra Wireless devices. - - Many devices have a feature known as TRU-Install. For those devices - to work properly, the USB Storage Sierra feature must be enabled. - - To compile this driver as a module, choose M here: the - module will be called sierra. - -config USB_SERIAL_SYMBOL - tristate "USB Symbol Barcode driver (serial mode)" - help - Say Y here if you want to use a Symbol USB Barcode device - in serial emulation mode. - - To compile this driver as a module, choose M here: the - module will be called symbolserial. - -config USB_SERIAL_TI - tristate "USB TI 3410/5052 Serial Driver" - help - Say Y here if you want to use the TI USB 3410 or 5052 - serial devices. - - To compile this driver as a module, choose M here: the - module will be called ti_usb_3410_5052. - -config USB_SERIAL_CYBERJACK - tristate "USB REINER SCT cyberJack pinpad/e-com chipcard reader" - ---help--- - Say Y here if you want to use a cyberJack pinpad/e-com USB chipcard - reader. This is an interface to ISO 7816 compatible contact-based - chipcards, e.g. GSM SIMs. - - To compile this driver as a module, choose M here: the - module will be called cyberjack. - - If unsure, say N. - -config USB_SERIAL_XIRCOM - tristate "USB Xircom / Entregra Single Port Serial Driver" - select USB_EZUSB - help - Say Y here if you want to use a Xircom or Entregra single port USB to - serial converter device. This driver makes use of firmware - developed from scratch by Brian Warner. - - To compile this driver as a module, choose M here: the - module will be called keyspan_pda. - -config USB_SERIAL_WWAN - tristate - -config USB_SERIAL_OPTION - tristate "USB driver for GSM and CDMA modems" - select USB_SERIAL_WWAN - help - Say Y here if you have a GSM or CDMA modem that's connected to USB. - - This driver also supports several PCMCIA cards which have a - built-in OHCI-USB adapter and an internally-connected GSM modem. - The USB bus on these cards is not accessible externally. - - Supported devices include (some of?) those made by: - Option, Huawei, Audiovox, Novatel Wireless, or Anydata. - - To compile this driver as a module, choose M here: the - module will be called option. - - If this driver doesn't recognize your device, - it might be accessible via the FTDI_SIO driver. - -config USB_SERIAL_OMNINET - tristate "USB ZyXEL omni.net LCD Plus Driver" - help - Say Y here if you want to use a ZyXEL omni.net LCD ISDN TA. - - To compile this driver as a module, choose M here: the - module will be called omninet. - -config USB_SERIAL_OPTICON - tristate "USB Opticon Barcode driver (serial mode)" - help - Say Y here if you want to use a Opticon USB Barcode device - in serial emulation mode. - - To compile this driver as a module, choose M here: the - module will be called opticon. - -config USB_SERIAL_VIVOPAY_SERIAL - tristate "USB ViVOpay serial interface driver" - help - Say Y here if you want to use a ViVOtech ViVOpay USB device. - - To compile this driver as a module, choose M here: the - module will be called vivopay-serial. - -config USB_SERIAL_ZIO - tristate "ZIO Motherboard USB serial interface driver" - help - Say Y here if you want to use ZIO Motherboard. - - To compile this driver as a module, choose M here: the - module will be called zio. - -config USB_SERIAL_SSU100 - tristate "USB Quatech SSU-100 Single Port Serial Driver" - help - Say Y here if you want to use the Quatech SSU-100 single - port usb to serial adapter. - - To compile this driver as a module, choose M here: the - module will be called ssu100. - -config USB_SERIAL_DEBUG - tristate "USB Debugging Device" - help - Say Y here if you have a USB debugging device used to receive - debugging data from another machine. The most common of these - devices is the NetChip TurboCONNECT device. - - To compile this driver as a module, choose M here: the - module will be called usb-debug. - -endif # USB_SERIAL diff --git a/ANDROID_3.4.5/drivers/usb/serial/Makefile b/ANDROID_3.4.5/drivers/usb/serial/Makefile deleted file mode 100644 index d0bd3be2..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/Makefile +++ /dev/null @@ -1,65 +0,0 @@ -# -# Makefile for the USB serial device drivers. -# - -# Object file lists. - -obj-$(CONFIG_USB_SERIAL) += usbserial.o - -usbserial-y := usb-serial.o generic.o bus.o - -usbserial-$(CONFIG_USB_SERIAL_CONSOLE) += console.o -usbserial-$(CONFIG_USB_EZUSB) += ezusb.o - -obj-$(CONFIG_USB_SERIAL_AIRCABLE) += aircable.o -obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o -obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o -obj-$(CONFIG_USB_SERIAL_CH341) += ch341.o -obj-$(CONFIG_USB_SERIAL_CP210X) += cp210x.o -obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o -obj-$(CONFIG_USB_SERIAL_CYPRESS_M8) += cypress_m8.o -obj-$(CONFIG_USB_SERIAL_DEBUG) += usb_debug.o -obj-$(CONFIG_USB_SERIAL_DIGI_ACCELEPORT) += digi_acceleport.o -obj-$(CONFIG_USB_SERIAL_EDGEPORT) += io_edgeport.o -obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI) += io_ti.o -obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o -obj-$(CONFIG_USB_SERIAL_F81232) += f81232.o -obj-$(CONFIG_USB_SERIAL_FTDI_SIO) += ftdi_sio.o -obj-$(CONFIG_USB_SERIAL_FUNSOFT) += funsoft.o -obj-$(CONFIG_USB_SERIAL_GARMIN) += garmin_gps.o -obj-$(CONFIG_USB_SERIAL_HP4X) += hp4x.o -obj-$(CONFIG_USB_SERIAL_IPAQ) += ipaq.o -obj-$(CONFIG_USB_SERIAL_IPW) += ipw.o -obj-$(CONFIG_USB_SERIAL_IR) += ir-usb.o -obj-$(CONFIG_USB_SERIAL_IUU) += iuu_phoenix.o -obj-$(CONFIG_USB_SERIAL_KEYSPAN) += keyspan.o -obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o -obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o -obj-$(CONFIG_USB_SERIAL_KOBIL_SCT) += kobil_sct.o -obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o -obj-$(CONFIG_USB_SERIAL_METRO) += metro-usb.o -obj-$(CONFIG_USB_SERIAL_MOS7720) += mos7720.o -obj-$(CONFIG_USB_SERIAL_MOS7840) += mos7840.o -obj-$(CONFIG_USB_SERIAL_MOTOROLA) += moto_modem.o -obj-$(CONFIG_USB_SERIAL_NAVMAN) += navman.o -obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o -obj-$(CONFIG_USB_SERIAL_OPTICON) += opticon.o -obj-$(CONFIG_USB_SERIAL_OPTION) += option.o -obj-$(CONFIG_USB_SERIAL_OTI6858) += oti6858.o -obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o -obj-$(CONFIG_USB_SERIAL_QCAUX) += qcaux.o -obj-$(CONFIG_USB_SERIAL_QUALCOMM) += qcserial.o -obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o -obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI) += siemens_mpi.o -obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o -obj-$(CONFIG_USB_SERIAL_SPCP8X5) += spcp8x5.o -obj-$(CONFIG_USB_SERIAL_SSU100) += ssu100.o -obj-$(CONFIG_USB_SERIAL_SYMBOL) += symbolserial.o -obj-$(CONFIG_USB_SERIAL_WWAN) += usb_wwan.o -obj-$(CONFIG_USB_SERIAL_TI) += ti_usb_3410_5052.o -obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o -obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o -obj-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda.o -obj-$(CONFIG_USB_SERIAL_VIVOPAY_SERIAL) += vivopay-serial.o -obj-$(CONFIG_USB_SERIAL_ZIO) += zio.o -obj-m += via_option.o diff --git a/ANDROID_3.4.5/drivers/usb/serial/Makefile-keyspan_pda_fw b/ANDROID_3.4.5/drivers/usb/serial/Makefile-keyspan_pda_fw deleted file mode 100644 index c20baf72..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/Makefile-keyspan_pda_fw +++ /dev/null @@ -1,16 +0,0 @@ - -# some rules to handle the quirks of the 'as31' assembler, like -# insisting upon fixed suffixes for the input and output files, -# and its lack of preprocessor support - -all: keyspan_pda_fw.h - -%.asm: %.S - gcc -x assembler-with-cpp -P -E -o $@ $< - -%.hex: %.asm - as31 -l $< - mv $*.obj $@ - -%_fw.h: %.hex ezusb_convert.pl - perl ezusb_convert.pl $* < $< > $@ diff --git a/ANDROID_3.4.5/drivers/usb/serial/aircable.c b/ANDROID_3.4.5/drivers/usb/serial/aircable.c deleted file mode 100644 index eec4fb9a..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/aircable.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * AIRcable USB Bluetooth Dongle Driver. - * - * Copyright (C) 2010 Johan Hovold - * Copyright (C) 2006 Manuel Francisco Naranjo (naranjo.manuel@gmail.com) - * - * 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. - * - * The device works as an standard CDC device, it has 2 interfaces, the first - * one is for firmware access and the second is the serial one. - * The protocol is very simply, there are two posibilities reading or writing. - * When writing the first urb must have a Header that starts with 0x20 0x29 the - * next two bytes must say how much data will be sended. - * When reading the process is almost equal except that the header starts with - * 0x00 0x20. - * - * The device simply need some stuff to understand data coming from the usb - * buffer: The First and Second byte is used for a Header, the Third and Fourth - * tells the device the amount of information the package holds. - * Packages are 60 bytes long Header Stuff. - * When writing to the device the first two bytes of the header are 0x20 0x29 - * When reading the bytes are 0x00 0x20, or 0x00 0x10, there is an strange - * situation, when too much data arrives to the device because it sends the data - * but with out the header. I will use a simply hack to override this situation, - * if there is data coming that does not contain any header, then that is data - * that must go directly to the tty, as there is no documentation about if there - * is any other control code, I will simply check for the first - * one. - * - * The driver registers himself with the USB-serial core and the USB Core. I had - * to implement a probe function against USB-serial, because other way, the - * driver was attaching himself to both interfaces. I have tryed with different - * configurations of usb_serial_driver with out exit, only the probe function - * could handle this correctly. - * - * I have taken some info from a Greg Kroah-Hartman article: - * http://www.linuxjournal.com/article/6573 - * And from Linux Device Driver Kit CD, which is a great work, the authors taken - * the work to recompile lots of information an knowladge in drivers development - * and made it all avaible inside a cd. - * URL: http://kernel.org/pub/linux/kernel/people/gregkh/ddk/ - * - */ - -#include -#include -#include -#include -#include -#include -#include - -static bool debug; - -/* Vendor and Product ID */ -#define AIRCABLE_VID 0x16CA -#define AIRCABLE_USB_PID 0x1502 - -/* Protocol Stuff */ -#define HCI_HEADER_LENGTH 0x4 -#define TX_HEADER_0 0x20 -#define TX_HEADER_1 0x29 -#define RX_HEADER_0 0x00 -#define RX_HEADER_1 0x20 -#define HCI_COMPLETE_FRAME 64 - -/* rx_flags */ -#define THROTTLED 0x01 -#define ACTUALLY_THROTTLED 0x02 - -/* - * Version Information - */ -#define DRIVER_VERSION "v2.0" -#define DRIVER_AUTHOR "Naranjo, Manuel Francisco , Johan Hovold " -#define DRIVER_DESC "AIRcable USB Driver" - -/* ID table that will be registered with USB core */ -static const struct usb_device_id id_table[] = { - { USB_DEVICE(AIRCABLE_VID, AIRCABLE_USB_PID) }, - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -static int aircable_prepare_write_buffer(struct usb_serial_port *port, - void *dest, size_t size) -{ - int count; - unsigned char *buf = dest; - - count = kfifo_out_locked(&port->write_fifo, buf + HCI_HEADER_LENGTH, - size - HCI_HEADER_LENGTH, &port->lock); - buf[0] = TX_HEADER_0; - buf[1] = TX_HEADER_1; - put_unaligned_le16(count, &buf[2]); - - return count + HCI_HEADER_LENGTH; -} - -static int aircable_probe(struct usb_serial *serial, - const struct usb_device_id *id) -{ - struct usb_host_interface *iface_desc = serial->interface-> - cur_altsetting; - struct usb_endpoint_descriptor *endpoint; - int num_bulk_out = 0; - int i; - - for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { - endpoint = &iface_desc->endpoint[i].desc; - if (usb_endpoint_is_bulk_out(endpoint)) { - dbg("found bulk out on endpoint %d", i); - ++num_bulk_out; - } - } - - if (num_bulk_out == 0) { - dbg("Invalid interface, discarding"); - return -ENODEV; - } - - return 0; -} - -static int aircable_process_packet(struct tty_struct *tty, - struct usb_serial_port *port, int has_headers, - char *packet, int len) -{ - if (has_headers) { - len -= HCI_HEADER_LENGTH; - packet += HCI_HEADER_LENGTH; - } - if (len <= 0) { - dbg("%s - malformed packet", __func__); - return 0; - } - - tty_insert_flip_string(tty, packet, len); - - return len; -} - -static void aircable_process_read_urb(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - char *data = (char *)urb->transfer_buffer; - struct tty_struct *tty; - int has_headers; - int count; - int len; - int i; - - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - - has_headers = (urb->actual_length > 2 && data[0] == RX_HEADER_0); - - count = 0; - for (i = 0; i < urb->actual_length; i += HCI_COMPLETE_FRAME) { - len = min_t(int, urb->actual_length - i, HCI_COMPLETE_FRAME); - count += aircable_process_packet(tty, port, has_headers, - &data[i], len); - } - - if (count) - tty_flip_buffer_push(tty); - tty_kref_put(tty); -} - -static struct usb_driver aircable_driver = { - .name = "aircable", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - -static struct usb_serial_driver aircable_device = { - .driver = { - .owner = THIS_MODULE, - .name = "aircable", - }, - .id_table = id_table, - .num_ports = 1, - .bulk_out_size = HCI_COMPLETE_FRAME, - .probe = aircable_probe, - .process_read_urb = aircable_process_read_urb, - .prepare_write_buffer = aircable_prepare_write_buffer, - .throttle = usb_serial_generic_throttle, - .unthrottle = usb_serial_generic_unthrottle, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &aircable_device, NULL -}; - -module_usb_serial_driver(aircable_driver, serial_drivers); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/ark3116.c b/ANDROID_3.4.5/drivers/usb/serial/ark3116.c deleted file mode 100644 index f99f4710..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/ark3116.c +++ /dev/null @@ -1,859 +0,0 @@ -/* - * Copyright (C) 2009 by Bart Hartgers (bart.hartgers+ark3116@gmail.com) - * Original version: - * Copyright (C) 2006 - * Simon Schulz (ark3116_driver auctionant.de) - * - * ark3116 - * - implements a driver for the arkmicro ark3116 chipset (vendor=0x6547, - * productid=0x0232) (used in a datacable called KQ-U8A) - * - * Supports full modem status lines, break, hardware flow control. Does not - * support software flow control, since I do not know how to enable it in hw. - * - * This driver is a essentially new implementation. I initially dug - * into the old ark3116.c driver and suddenly realized the ark3116 is - * a 16450 with a USB interface glued to it. See comments at the - * bottom of this file. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static bool debug; -/* - * Version information - */ - -#define DRIVER_VERSION "v0.7" -#define DRIVER_AUTHOR "Bart Hartgers " -#define DRIVER_DESC "USB ARK3116 serial/IrDA driver" -#define DRIVER_DEV_DESC "ARK3116 RS232/IrDA" -#define DRIVER_NAME "ark3116" - -/* usb timeout of 1 second */ -#define ARK_TIMEOUT (1*HZ) - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(0x6547, 0x0232) }, - { USB_DEVICE(0x18ec, 0x3118) }, /* USB to IrDA adapter */ - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -static int is_irda(struct usb_serial *serial) -{ - struct usb_device *dev = serial->dev; - if (le16_to_cpu(dev->descriptor.idVendor) == 0x18ec && - le16_to_cpu(dev->descriptor.idProduct) == 0x3118) - return 1; - return 0; -} - -struct ark3116_private { - wait_queue_head_t delta_msr_wait; - struct async_icount icount; - int irda; /* 1 for irda device */ - - /* protects hw register updates */ - struct mutex hw_lock; - - int quot; /* baudrate divisor */ - __u32 lcr; /* line control register value */ - __u32 hcr; /* handshake control register (0x8) - * value */ - __u32 mcr; /* modem contol register value */ - - /* protects the status values below */ - spinlock_t status_lock; - __u32 msr; /* modem status register value */ - __u32 lsr; /* line status register value */ -}; - -static int ark3116_write_reg(struct usb_serial *serial, - unsigned reg, __u8 val) -{ - int result; - /* 0xfe 0x40 are magic values taken from original driver */ - result = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - 0xfe, 0x40, val, reg, - NULL, 0, ARK_TIMEOUT); - return result; -} - -static int ark3116_read_reg(struct usb_serial *serial, - unsigned reg, unsigned char *buf) -{ - int result; - /* 0xfe 0xc0 are magic values taken from original driver */ - result = usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), - 0xfe, 0xc0, 0, reg, - buf, 1, ARK_TIMEOUT); - if (result < 0) - return result; - else - return buf[0]; -} - -static inline int calc_divisor(int bps) -{ - /* Original ark3116 made some exceptions in rounding here - * because windows did the same. Assume that is not really - * necessary. - * Crystal is 12MHz, probably because of USB, but we divide by 4? - */ - return (12000000 + 2*bps) / (4*bps); -} - -static int ark3116_attach(struct usb_serial *serial) -{ - struct usb_serial_port *port = serial->port[0]; - struct ark3116_private *priv; - - /* make sure we have our end-points */ - if ((serial->num_bulk_in == 0) || - (serial->num_bulk_out == 0) || - (serial->num_interrupt_in == 0)) { - dev_err(&serial->dev->dev, - "%s - missing endpoint - " - "bulk in: %d, bulk out: %d, int in %d\n", - KBUILD_MODNAME, - serial->num_bulk_in, - serial->num_bulk_out, - serial->num_interrupt_in); - return -EINVAL; - } - - priv = kzalloc(sizeof(struct ark3116_private), - GFP_KERNEL); - if (!priv) - return -ENOMEM; - - init_waitqueue_head(&priv->delta_msr_wait); - mutex_init(&priv->hw_lock); - spin_lock_init(&priv->status_lock); - - priv->irda = is_irda(serial); - - usb_set_serial_port_data(port, priv); - - /* setup the hardware */ - ark3116_write_reg(serial, UART_IER, 0); - /* disable DMA */ - ark3116_write_reg(serial, UART_FCR, 0); - /* handshake control */ - priv->hcr = 0; - ark3116_write_reg(serial, 0x8 , 0); - /* modem control */ - priv->mcr = 0; - ark3116_write_reg(serial, UART_MCR, 0); - - if (!(priv->irda)) { - ark3116_write_reg(serial, 0xb , 0); - } else { - ark3116_write_reg(serial, 0xb , 1); - ark3116_write_reg(serial, 0xc , 0); - ark3116_write_reg(serial, 0xd , 0x41); - ark3116_write_reg(serial, 0xa , 1); - } - - /* setup baudrate */ - ark3116_write_reg(serial, UART_LCR, UART_LCR_DLAB); - - /* setup for 9600 8N1 */ - priv->quot = calc_divisor(9600); - ark3116_write_reg(serial, UART_DLL, priv->quot & 0xff); - ark3116_write_reg(serial, UART_DLM, (priv->quot>>8) & 0xff); - - priv->lcr = UART_LCR_WLEN8; - ark3116_write_reg(serial, UART_LCR, UART_LCR_WLEN8); - - ark3116_write_reg(serial, 0xe, 0); - - if (priv->irda) - ark3116_write_reg(serial, 0x9, 0); - - dev_info(&serial->dev->dev, - "%s using %s mode\n", - KBUILD_MODNAME, - priv->irda ? "IrDA" : "RS232"); - return 0; -} - -static void ark3116_release(struct usb_serial *serial) -{ - struct usb_serial_port *port = serial->port[0]; - struct ark3116_private *priv = usb_get_serial_port_data(port); - - /* device is closed, so URBs and DMA should be down */ - - usb_set_serial_port_data(port, NULL); - - mutex_destroy(&priv->hw_lock); - - kfree(priv); -} - -static void ark3116_init_termios(struct tty_struct *tty) -{ - struct ktermios *termios = tty->termios; - *termios = tty_std_termios; - termios->c_cflag = B9600 | CS8 - | CREAD | HUPCL | CLOCAL; - termios->c_ispeed = 9600; - termios->c_ospeed = 9600; -} - -static void ark3116_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old_termios) -{ - struct usb_serial *serial = port->serial; - struct ark3116_private *priv = usb_get_serial_port_data(port); - struct ktermios *termios = tty->termios; - unsigned int cflag = termios->c_cflag; - int bps = tty_get_baud_rate(tty); - int quot; - __u8 lcr, hcr, eval; - - /* set data bit count */ - switch (cflag & CSIZE) { - case CS5: - lcr = UART_LCR_WLEN5; - break; - case CS6: - lcr = UART_LCR_WLEN6; - break; - case CS7: - lcr = UART_LCR_WLEN7; - break; - default: - case CS8: - lcr = UART_LCR_WLEN8; - break; - } - if (cflag & CSTOPB) - lcr |= UART_LCR_STOP; - if (cflag & PARENB) - lcr |= UART_LCR_PARITY; - if (!(cflag & PARODD)) - lcr |= UART_LCR_EPAR; -#ifdef CMSPAR - if (cflag & CMSPAR) - lcr |= UART_LCR_SPAR; -#endif - /* handshake control */ - hcr = (cflag & CRTSCTS) ? 0x03 : 0x00; - - /* calc baudrate */ - dbg("%s - setting bps to %d", __func__, bps); - eval = 0; - switch (bps) { - case 0: - quot = calc_divisor(9600); - break; - default: - if ((bps < 75) || (bps > 3000000)) - bps = 9600; - quot = calc_divisor(bps); - break; - case 460800: - eval = 1; - quot = calc_divisor(bps); - break; - case 921600: - eval = 2; - quot = calc_divisor(bps); - break; - } - - /* Update state: synchronize */ - mutex_lock(&priv->hw_lock); - - /* keep old LCR_SBC bit */ - lcr |= (priv->lcr & UART_LCR_SBC); - - dbg("%s - setting hcr:0x%02x,lcr:0x%02x,quot:%d", - __func__, hcr, lcr, quot); - - /* handshake control */ - if (priv->hcr != hcr) { - priv->hcr = hcr; - ark3116_write_reg(serial, 0x8, hcr); - } - - /* baudrate */ - if (priv->quot != quot) { - priv->quot = quot; - priv->lcr = lcr; /* need to write lcr anyway */ - - /* disable DMA since transmit/receive is - * shadowed by UART_DLL - */ - ark3116_write_reg(serial, UART_FCR, 0); - - ark3116_write_reg(serial, UART_LCR, - lcr|UART_LCR_DLAB); - ark3116_write_reg(serial, UART_DLL, quot & 0xff); - ark3116_write_reg(serial, UART_DLM, (quot>>8) & 0xff); - - /* restore lcr */ - ark3116_write_reg(serial, UART_LCR, lcr); - /* magic baudrate thingy: not sure what it does, - * but windows does this as well. - */ - ark3116_write_reg(serial, 0xe, eval); - - /* enable DMA */ - ark3116_write_reg(serial, UART_FCR, UART_FCR_DMA_SELECT); - } else if (priv->lcr != lcr) { - priv->lcr = lcr; - ark3116_write_reg(serial, UART_LCR, lcr); - } - - mutex_unlock(&priv->hw_lock); - - /* check for software flow control */ - if (I_IXOFF(tty) || I_IXON(tty)) { - dev_warn(&serial->dev->dev, - "%s: don't know how to do software flow control\n", - KBUILD_MODNAME); - } - - /* Don't rewrite B0 */ - if (tty_termios_baud_rate(termios)) - tty_termios_encode_baud_rate(termios, bps, bps); -} - -static void ark3116_close(struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - - if (serial->dev) { - /* disable DMA */ - ark3116_write_reg(serial, UART_FCR, 0); - - /* deactivate interrupts */ - ark3116_write_reg(serial, UART_IER, 0); - - usb_serial_generic_close(port); - if (serial->num_interrupt_in) - usb_kill_urb(port->interrupt_in_urb); - } - -} - -static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct ark3116_private *priv = usb_get_serial_port_data(port); - struct usb_serial *serial = port->serial; - unsigned char *buf; - int result; - - buf = kmalloc(1, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - result = usb_serial_generic_open(tty, port); - if (result) { - dbg("%s - usb_serial_generic_open failed: %d", - __func__, result); - goto err_out; - } - - /* remove any data still left: also clears error state */ - ark3116_read_reg(serial, UART_RX, buf); - - /* read modem status */ - priv->msr = ark3116_read_reg(serial, UART_MSR, buf); - /* read line status */ - priv->lsr = ark3116_read_reg(serial, UART_LSR, buf); - - result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - if (result) { - dev_err(&port->dev, "submit irq_in urb failed %d\n", - result); - ark3116_close(port); - goto err_out; - } - - /* activate interrupts */ - ark3116_write_reg(port->serial, UART_IER, UART_IER_MSI|UART_IER_RLSI); - - /* enable DMA */ - ark3116_write_reg(port->serial, UART_FCR, UART_FCR_DMA_SELECT); - - /* setup termios */ - if (tty) - ark3116_set_termios(tty, port, NULL); - -err_out: - kfree(buf); - return result; -} - -static int ark3116_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct ark3116_private *priv = usb_get_serial_port_data(port); - struct async_icount cnow = priv->icount; - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - icount->rx = cnow.rx; - icount->tx = cnow.tx; - icount->frame = cnow.frame; - icount->overrun = cnow.overrun; - icount->parity = cnow.parity; - icount->brk = cnow.brk; - icount->buf_overrun = cnow.buf_overrun; - return 0; -} - -static int ark3116_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - struct ark3116_private *priv = usb_get_serial_port_data(port); - struct serial_struct serstruct; - void __user *user_arg = (void __user *)arg; - - switch (cmd) { - case TIOCGSERIAL: - /* XXX: Some of these values are probably wrong. */ - memset(&serstruct, 0, sizeof(serstruct)); - serstruct.type = PORT_16654; - serstruct.line = port->serial->minor; - serstruct.port = port->number; - serstruct.custom_divisor = 0; - serstruct.baud_base = 460800; - - if (copy_to_user(user_arg, &serstruct, sizeof(serstruct))) - return -EFAULT; - - return 0; - case TIOCSSERIAL: - if (copy_from_user(&serstruct, user_arg, sizeof(serstruct))) - return -EFAULT; - return 0; - case TIOCMIWAIT: - for (;;) { - struct async_icount prev = priv->icount; - interruptible_sleep_on(&priv->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - if ((prev.rng == priv->icount.rng) && - (prev.dsr == priv->icount.dsr) && - (prev.dcd == priv->icount.dcd) && - (prev.cts == priv->icount.cts)) - return -EIO; - if ((arg & TIOCM_RNG && - (prev.rng != priv->icount.rng)) || - (arg & TIOCM_DSR && - (prev.dsr != priv->icount.dsr)) || - (arg & TIOCM_CD && - (prev.dcd != priv->icount.dcd)) || - (arg & TIOCM_CTS && - (prev.cts != priv->icount.cts))) - return 0; - } - break; - } - - return -ENOIOCTLCMD; -} - -static int ark3116_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct ark3116_private *priv = usb_get_serial_port_data(port); - __u32 status; - __u32 ctrl; - unsigned long flags; - - mutex_lock(&priv->hw_lock); - ctrl = priv->mcr; - mutex_unlock(&priv->hw_lock); - - spin_lock_irqsave(&priv->status_lock, flags); - status = priv->msr; - spin_unlock_irqrestore(&priv->status_lock, flags); - - return (status & UART_MSR_DSR ? TIOCM_DSR : 0) | - (status & UART_MSR_CTS ? TIOCM_CTS : 0) | - (status & UART_MSR_RI ? TIOCM_RI : 0) | - (status & UART_MSR_DCD ? TIOCM_CD : 0) | - (ctrl & UART_MCR_DTR ? TIOCM_DTR : 0) | - (ctrl & UART_MCR_RTS ? TIOCM_RTS : 0) | - (ctrl & UART_MCR_OUT1 ? TIOCM_OUT1 : 0) | - (ctrl & UART_MCR_OUT2 ? TIOCM_OUT2 : 0); -} - -static int ark3116_tiocmset(struct tty_struct *tty, - unsigned set, unsigned clr) -{ - struct usb_serial_port *port = tty->driver_data; - struct ark3116_private *priv = usb_get_serial_port_data(port); - - /* we need to take the mutex here, to make sure that the value - * in priv->mcr is actually the one that is in the hardware - */ - - mutex_lock(&priv->hw_lock); - - if (set & TIOCM_RTS) - priv->mcr |= UART_MCR_RTS; - if (set & TIOCM_DTR) - priv->mcr |= UART_MCR_DTR; - if (set & TIOCM_OUT1) - priv->mcr |= UART_MCR_OUT1; - if (set & TIOCM_OUT2) - priv->mcr |= UART_MCR_OUT2; - if (clr & TIOCM_RTS) - priv->mcr &= ~UART_MCR_RTS; - if (clr & TIOCM_DTR) - priv->mcr &= ~UART_MCR_DTR; - if (clr & TIOCM_OUT1) - priv->mcr &= ~UART_MCR_OUT1; - if (clr & TIOCM_OUT2) - priv->mcr &= ~UART_MCR_OUT2; - - ark3116_write_reg(port->serial, UART_MCR, priv->mcr); - - mutex_unlock(&priv->hw_lock); - - return 0; -} - -static void ark3116_break_ctl(struct tty_struct *tty, int break_state) -{ - struct usb_serial_port *port = tty->driver_data; - struct ark3116_private *priv = usb_get_serial_port_data(port); - - /* LCR is also used for other things: protect access */ - mutex_lock(&priv->hw_lock); - - if (break_state) - priv->lcr |= UART_LCR_SBC; - else - priv->lcr &= ~UART_LCR_SBC; - - ark3116_write_reg(port->serial, UART_LCR, priv->lcr); - - mutex_unlock(&priv->hw_lock); -} - -static void ark3116_update_msr(struct usb_serial_port *port, __u8 msr) -{ - struct ark3116_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - - spin_lock_irqsave(&priv->status_lock, flags); - priv->msr = msr; - spin_unlock_irqrestore(&priv->status_lock, flags); - - if (msr & UART_MSR_ANY_DELTA) { - /* update input line counters */ - if (msr & UART_MSR_DCTS) - priv->icount.cts++; - if (msr & UART_MSR_DDSR) - priv->icount.dsr++; - if (msr & UART_MSR_DDCD) - priv->icount.dcd++; - if (msr & UART_MSR_TERI) - priv->icount.rng++; - wake_up_interruptible(&priv->delta_msr_wait); - } -} - -static void ark3116_update_lsr(struct usb_serial_port *port, __u8 lsr) -{ - struct ark3116_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - - spin_lock_irqsave(&priv->status_lock, flags); - /* combine bits */ - priv->lsr |= lsr; - spin_unlock_irqrestore(&priv->status_lock, flags); - - if (lsr&UART_LSR_BRK_ERROR_BITS) { - if (lsr & UART_LSR_BI) - priv->icount.brk++; - if (lsr & UART_LSR_FE) - priv->icount.frame++; - if (lsr & UART_LSR_PE) - priv->icount.parity++; - if (lsr & UART_LSR_OE) - priv->icount.overrun++; - } -} - -static void ark3116_read_int_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - int status = urb->status; - const __u8 *data = urb->transfer_buffer; - int result; - - switch (status) { - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); - return; - default: - dbg("%s - nonzero urb status received: %d", - __func__, status); - break; - case 0: /* success */ - /* discovered this by trail and error... */ - if ((urb->actual_length == 4) && (data[0] == 0xe8)) { - const __u8 id = data[1]&UART_IIR_ID; - dbg("%s: iir=%02x", __func__, data[1]); - if (id == UART_IIR_MSI) { - dbg("%s: msr=%02x", __func__, data[3]); - ark3116_update_msr(port, data[3]); - break; - } else if (id == UART_IIR_RLSI) { - dbg("%s: lsr=%02x", __func__, data[2]); - ark3116_update_lsr(port, data[2]); - break; - } - } - /* - * Not sure what this data meant... - */ - usb_serial_debug_data(debug, &port->dev, - __func__, - urb->actual_length, - urb->transfer_buffer); - break; - } - - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) - dev_err(&urb->dev->dev, - "%s - Error %d submitting interrupt urb\n", - __func__, result); -} - - -/* Data comes in via the bulk (data) URB, erors/interrupts via the int URB. - * This means that we cannot be sure which data byte has an associated error - * condition, so we report an error for all data in the next bulk read. - * - * Actually, there might even be a window between the bulk data leaving the - * ark and reading/resetting the lsr in the read_bulk_callback where an - * interrupt for the next data block could come in. - * Without somekind of ordering on the ark, we would have to report the - * error for the next block of data as well... - * For now, let's pretend this can't happen. - */ -static void ark3116_process_read_urb(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct ark3116_private *priv = usb_get_serial_port_data(port); - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - char tty_flag = TTY_NORMAL; - unsigned long flags; - __u32 lsr; - - /* update line status */ - spin_lock_irqsave(&priv->status_lock, flags); - lsr = priv->lsr; - priv->lsr &= ~UART_LSR_BRK_ERROR_BITS; - spin_unlock_irqrestore(&priv->status_lock, flags); - - if (!urb->actual_length) - return; - - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - - if (lsr & UART_LSR_BRK_ERROR_BITS) { - if (lsr & UART_LSR_BI) - tty_flag = TTY_BREAK; - else if (lsr & UART_LSR_PE) - tty_flag = TTY_PARITY; - else if (lsr & UART_LSR_FE) - tty_flag = TTY_FRAME; - - /* overrun is special, not associated with a char */ - if (lsr & UART_LSR_OE) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } - tty_insert_flip_string_fixed_flag(tty, data, tty_flag, - urb->actual_length); - tty_flip_buffer_push(tty); - tty_kref_put(tty); -} - -static struct usb_driver ark3116_driver = { - .name = "ark3116", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - -static struct usb_serial_driver ark3116_device = { - .driver = { - .owner = THIS_MODULE, - .name = "ark3116", - }, - .id_table = id_table, - .num_ports = 1, - .attach = ark3116_attach, - .release = ark3116_release, - .set_termios = ark3116_set_termios, - .init_termios = ark3116_init_termios, - .ioctl = ark3116_ioctl, - .tiocmget = ark3116_tiocmget, - .tiocmset = ark3116_tiocmset, - .get_icount = ark3116_get_icount, - .open = ark3116_open, - .close = ark3116_close, - .break_ctl = ark3116_break_ctl, - .read_int_callback = ark3116_read_int_callback, - .process_read_urb = ark3116_process_read_urb, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &ark3116_device, NULL -}; - -module_usb_serial_driver(ark3116_driver, serial_drivers); - -MODULE_LICENSE("GPL"); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable debug"); - -/* - * The following describes what I learned from studying the old - * ark3116.c driver, disassembling the windows driver, and some lucky - * guesses. Since I do not have any datasheet or other - * documentation, inaccuracies are almost guaranteed. - * - * Some specs for the ARK3116 can be found here: - * http://web.archive.org/web/20060318000438/ - * www.arkmicro.com/en/products/view.php?id=10 - * On that page, 2 GPIO pins are mentioned: I assume these are the - * OUT1 and OUT2 pins of the UART, so I added support for those - * through the MCR. Since the pins are not available on my hardware, - * I could not verify this. - * Also, it states there is "on-chip hardware flow control". I have - * discovered how to enable that. Unfortunately, I do not know how to - * enable XON/XOFF (software) flow control, which would need support - * from the chip as well to work. Because of the wording on the web - * page there is a real possibility the chip simply does not support - * software flow control. - * - * I got my ark3116 as part of a mobile phone adapter cable. On the - * PCB, the following numbered contacts are present: - * - * 1:- +5V - * 2:o DTR - * 3:i RX - * 4:i DCD - * 5:o RTS - * 6:o TX - * 7:i RI - * 8:i DSR - * 10:- 0V - * 11:i CTS - * - * On my chip, all signals seem to be 3.3V, but 5V tolerant. But that - * may be different for the one you have ;-). - * - * The windows driver limits the registers to 0-F, so I assume there - * are actually 16 present on the device. - * - * On an UART interrupt, 4 bytes of data come in on the interrupt - * endpoint. The bytes are 0xe8 IIR LSR MSR. - * - * The baudrate seems to be generated from the 12MHz crystal, using - * 4-times subsampling. So quot=12e6/(4*baud). Also see description - * of register E. - * - * Registers 0-7: - * These seem to be the same as for a regular 16450. The FCR is set - * to UART_FCR_DMA_SELECT (0x8), I guess to enable transfers between - * the UART and the USB bridge/DMA engine. - * - * Register 8: - * By trial and error, I found out that bit 0 enables hardware CTS, - * stopping TX when CTS is +5V. Bit 1 does the same for RTS, making - * RTS +5V when the 3116 cannot transfer the data to the USB bus - * (verified by disabling the reading URB). Note that as far as I can - * tell, the windows driver does NOT use this, so there might be some - * hardware bug or something. - * - * According to a patch provided here - * (http://lkml.org/lkml/2009/7/26/56), the ARK3116 can also be used - * as an IrDA dongle. Since I do not have such a thing, I could not - * investigate that aspect. However, I can speculate ;-). - * - * - IrDA encodes data differently than RS232. Most likely, one of - * the bits in registers 9..E enables the IR ENDEC (encoder/decoder). - * - Depending on the IR transceiver, the input and output need to be - * inverted, so there are probably bits for that as well. - * - IrDA is half-duplex, so there should be a bit for selecting that. - * - * This still leaves at least two registers unaccounted for. Perhaps - * The chip can do XON/XOFF or CRC in HW? - * - * Register 9: - * Set to 0x00 for IrDA, when the baudrate is initialised. - * - * Register A: - * Set to 0x01 for IrDA, at init. - * - * Register B: - * Set to 0x01 for IrDA, 0x00 for RS232, at init. - * - * Register C: - * Set to 00 for IrDA, at init. - * - * Register D: - * Set to 0x41 for IrDA, at init. - * - * Register E: - * Somekind of baudrate override. The windows driver seems to set - * this to 0x00 for normal baudrates, 0x01 for 460800, 0x02 for 921600. - * Since 460800 and 921600 cannot be obtained by dividing 3MHz by an integer, - * it could be somekind of subdivisor thingy. - * However,it does not seem to do anything: selecting 921600 (divisor 3, - * reg E=2), still gets 1 MHz. I also checked if registers 9, C or F would - * work, but they don't. - * - * Register F: unknown - */ diff --git a/ANDROID_3.4.5/drivers/usb/serial/belkin_sa.c b/ANDROID_3.4.5/drivers/usb/serial/belkin_sa.c deleted file mode 100644 index a52e0d2c..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/belkin_sa.c +++ /dev/null @@ -1,535 +0,0 @@ -/* - * Belkin USB Serial Adapter Driver - * - * Copyright (C) 2000 William Greathouse (wgreathouse@smva.com) - * Copyright (C) 2000-2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com) - * - * This program is largely derived from work by the linux-usb group - * and associated source files. Please see the usb/serial files for - * individual credits and copyrights. - * - * 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. - * - * See Documentation/usb/usb-serial.txt for more information on using this - * driver - * - * TODO: - * -- Add true modem contol line query capability. Currently we track the - * states reported by the interrupt and the states we request. - * -- Add support for flush commands - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "belkin_sa.h" - -static bool debug; - -/* - * Version Information - */ -#define DRIVER_VERSION "v1.3" -#define DRIVER_AUTHOR "William Greathouse " -#define DRIVER_DESC "USB Belkin Serial converter driver" - -/* function prototypes for a Belkin USB Serial Adapter F5U103 */ -static int belkin_sa_startup(struct usb_serial *serial); -static void belkin_sa_release(struct usb_serial *serial); -static int belkin_sa_open(struct tty_struct *tty, - struct usb_serial_port *port); -static void belkin_sa_close(struct usb_serial_port *port); -static void belkin_sa_read_int_callback(struct urb *urb); -static void belkin_sa_process_read_urb(struct urb *urb); -static void belkin_sa_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios * old); -static void belkin_sa_break_ctl(struct tty_struct *tty, int break_state); -static int belkin_sa_tiocmget(struct tty_struct *tty); -static int belkin_sa_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear); - - -static const struct usb_device_id id_table_combined[] = { - { USB_DEVICE(BELKIN_SA_VID, BELKIN_SA_PID) }, - { USB_DEVICE(BELKIN_OLD_VID, BELKIN_OLD_PID) }, - { USB_DEVICE(PERACOM_VID, PERACOM_PID) }, - { USB_DEVICE(GOHUBS_VID, GOHUBS_PID) }, - { USB_DEVICE(GOHUBS_VID, HANDYLINK_PID) }, - { USB_DEVICE(BELKIN_DOCKSTATION_VID, BELKIN_DOCKSTATION_PID) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, id_table_combined); - -static struct usb_driver belkin_driver = { - .name = "belkin", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; - -/* All of the device info needed for the serial converters */ -static struct usb_serial_driver belkin_device = { - .driver = { - .owner = THIS_MODULE, - .name = "belkin", - }, - .description = "Belkin / Peracom / GoHubs USB Serial Adapter", - .id_table = id_table_combined, - .num_ports = 1, - .open = belkin_sa_open, - .close = belkin_sa_close, - .read_int_callback = belkin_sa_read_int_callback, - .process_read_urb = belkin_sa_process_read_urb, - .set_termios = belkin_sa_set_termios, - .break_ctl = belkin_sa_break_ctl, - .tiocmget = belkin_sa_tiocmget, - .tiocmset = belkin_sa_tiocmset, - .attach = belkin_sa_startup, - .release = belkin_sa_release, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &belkin_device, NULL -}; - -struct belkin_sa_private { - spinlock_t lock; - unsigned long control_state; - unsigned char last_lsr; - unsigned char last_msr; - int bad_flow_control; -}; - - -/* - * *************************************************************************** - * Belkin USB Serial Adapter F5U103 specific driver functions - * *************************************************************************** - */ - -#define WDR_TIMEOUT 5000 /* default urb timeout */ - -/* assumes that struct usb_serial *serial is available */ -#define BSA_USB_CMD(c, v) usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), \ - (c), BELKIN_SA_SET_REQUEST_TYPE, \ - (v), 0, NULL, 0, WDR_TIMEOUT) - -/* do some startup allocations not currently performed by usb_serial_probe() */ -static int belkin_sa_startup(struct usb_serial *serial) -{ - struct usb_device *dev = serial->dev; - struct belkin_sa_private *priv; - - /* allocate the private data structure */ - priv = kmalloc(sizeof(struct belkin_sa_private), GFP_KERNEL); - if (!priv) - return -1; /* error */ - /* set initial values for control structures */ - spin_lock_init(&priv->lock); - priv->control_state = 0; - priv->last_lsr = 0; - priv->last_msr = 0; - /* see comments at top of file */ - priv->bad_flow_control = - (le16_to_cpu(dev->descriptor.bcdDevice) <= 0x0206) ? 1 : 0; - dev_info(&dev->dev, "bcdDevice: %04x, bfc: %d\n", - le16_to_cpu(dev->descriptor.bcdDevice), - priv->bad_flow_control); - - init_waitqueue_head(&serial->port[0]->write_wait); - usb_set_serial_port_data(serial->port[0], priv); - - return 0; -} - -static void belkin_sa_release(struct usb_serial *serial) -{ - int i; - - dbg("%s", __func__); - - for (i = 0; i < serial->num_ports; ++i) - kfree(usb_get_serial_port_data(serial->port[i])); -} - -static int belkin_sa_open(struct tty_struct *tty, - struct usb_serial_port *port) -{ - int retval; - - dbg("%s port %d", __func__, port->number); - - retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - if (retval) { - dev_err(&port->dev, "usb_submit_urb(read int) failed\n"); - return retval; - } - - retval = usb_serial_generic_open(tty, port); - if (retval) - usb_kill_urb(port->interrupt_in_urb); - - return retval; -} - -static void belkin_sa_close(struct usb_serial_port *port) -{ - dbg("%s port %d", __func__, port->number); - - usb_serial_generic_close(port); - usb_kill_urb(port->interrupt_in_urb); -} - -static void belkin_sa_read_int_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct belkin_sa_private *priv; - unsigned char *data = urb->transfer_buffer; - int retval; - int status = urb->status; - unsigned long flags; - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); - return; - default: - dbg("%s - nonzero urb status received: %d", - __func__, status); - goto exit; - } - - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); - - /* Handle known interrupt data */ - /* ignore data[0] and data[1] */ - - priv = usb_get_serial_port_data(port); - spin_lock_irqsave(&priv->lock, flags); - priv->last_msr = data[BELKIN_SA_MSR_INDEX]; - - /* Record Control Line states */ - if (priv->last_msr & BELKIN_SA_MSR_DSR) - priv->control_state |= TIOCM_DSR; - else - priv->control_state &= ~TIOCM_DSR; - - if (priv->last_msr & BELKIN_SA_MSR_CTS) - priv->control_state |= TIOCM_CTS; - else - priv->control_state &= ~TIOCM_CTS; - - if (priv->last_msr & BELKIN_SA_MSR_RI) - priv->control_state |= TIOCM_RI; - else - priv->control_state &= ~TIOCM_RI; - - if (priv->last_msr & BELKIN_SA_MSR_CD) - priv->control_state |= TIOCM_CD; - else - priv->control_state &= ~TIOCM_CD; - - priv->last_lsr = data[BELKIN_SA_LSR_INDEX]; - spin_unlock_irqrestore(&priv->lock, flags); -exit: - retval = usb_submit_urb(urb, GFP_ATOMIC); - if (retval) - dev_err(&port->dev, "%s - usb_submit_urb failed with " - "result %d\n", __func__, retval); -} - -static void belkin_sa_process_read_urb(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct belkin_sa_private *priv = usb_get_serial_port_data(port); - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - unsigned long flags; - unsigned char status; - char tty_flag; - - /* Update line status */ - tty_flag = TTY_NORMAL; - - spin_lock_irqsave(&priv->lock, flags); - status = priv->last_lsr; - priv->last_lsr &= ~BELKIN_SA_LSR_ERR; - spin_unlock_irqrestore(&priv->lock, flags); - - if (!urb->actual_length) - return; - - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - - if (status & BELKIN_SA_LSR_ERR) { - /* Break takes precedence over parity, which takes precedence - * over framing errors. */ - if (status & BELKIN_SA_LSR_BI) - tty_flag = TTY_BREAK; - else if (status & BELKIN_SA_LSR_PE) - tty_flag = TTY_PARITY; - else if (status & BELKIN_SA_LSR_FE) - tty_flag = TTY_FRAME; - dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag); - - /* Overrun is special, not associated with a char. */ - if (status & BELKIN_SA_LSR_OE) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } - - tty_insert_flip_string_fixed_flag(tty, data, tty_flag, - urb->actual_length); - tty_flip_buffer_push(tty); - tty_kref_put(tty); -} - -static void belkin_sa_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) -{ - struct usb_serial *serial = port->serial; - struct belkin_sa_private *priv = usb_get_serial_port_data(port); - unsigned int iflag; - unsigned int cflag; - unsigned int old_iflag = 0; - unsigned int old_cflag = 0; - __u16 urb_value = 0; /* Will hold the new flags */ - unsigned long flags; - unsigned long control_state; - int bad_flow_control; - speed_t baud; - struct ktermios *termios = tty->termios; - - iflag = termios->c_iflag; - cflag = termios->c_cflag; - - termios->c_cflag &= ~CMSPAR; - - /* get a local copy of the current port settings */ - spin_lock_irqsave(&priv->lock, flags); - control_state = priv->control_state; - bad_flow_control = priv->bad_flow_control; - spin_unlock_irqrestore(&priv->lock, flags); - - old_iflag = old_termios->c_iflag; - old_cflag = old_termios->c_cflag; - - /* Set the baud rate */ - if ((cflag & CBAUD) != (old_cflag & CBAUD)) { - /* reassert DTR and (maybe) RTS on transition from B0 */ - if ((old_cflag & CBAUD) == B0) { - control_state |= (TIOCM_DTR|TIOCM_RTS); - if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 1) < 0) - dev_err(&port->dev, "Set DTR error\n"); - /* don't set RTS if using hardware flow control */ - if (!(old_cflag & CRTSCTS)) - if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST - , 1) < 0) - dev_err(&port->dev, "Set RTS error\n"); - } - } - - baud = tty_get_baud_rate(tty); - if (baud) { - urb_value = BELKIN_SA_BAUD(baud); - /* Clip to maximum speed */ - if (urb_value == 0) - urb_value = 1; - /* Turn it back into a resulting real baud rate */ - baud = BELKIN_SA_BAUD(urb_value); - - /* Report the actual baud rate back to the caller */ - tty_encode_baud_rate(tty, baud, baud); - if (BSA_USB_CMD(BELKIN_SA_SET_BAUDRATE_REQUEST, urb_value) < 0) - dev_err(&port->dev, "Set baudrate error\n"); - } else { - /* Disable flow control */ - if (BSA_USB_CMD(BELKIN_SA_SET_FLOW_CTRL_REQUEST, - BELKIN_SA_FLOW_NONE) < 0) - dev_err(&port->dev, "Disable flowcontrol error\n"); - /* Drop RTS and DTR */ - control_state &= ~(TIOCM_DTR | TIOCM_RTS); - if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 0) < 0) - dev_err(&port->dev, "DTR LOW error\n"); - if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 0) < 0) - dev_err(&port->dev, "RTS LOW error\n"); - } - - /* set the parity */ - if ((cflag ^ old_cflag) & (PARENB | PARODD)) { - if (cflag & PARENB) - urb_value = (cflag & PARODD) ? BELKIN_SA_PARITY_ODD - : BELKIN_SA_PARITY_EVEN; - else - urb_value = BELKIN_SA_PARITY_NONE; - if (BSA_USB_CMD(BELKIN_SA_SET_PARITY_REQUEST, urb_value) < 0) - dev_err(&port->dev, "Set parity error\n"); - } - - /* set the number of data bits */ - if ((cflag & CSIZE) != (old_cflag & CSIZE)) { - switch (cflag & CSIZE) { - case CS5: - urb_value = BELKIN_SA_DATA_BITS(5); - break; - case CS6: - urb_value = BELKIN_SA_DATA_BITS(6); - break; - case CS7: - urb_value = BELKIN_SA_DATA_BITS(7); - break; - case CS8: - urb_value = BELKIN_SA_DATA_BITS(8); - break; - default: dbg("CSIZE was not CS5-CS8, using default of 8"); - urb_value = BELKIN_SA_DATA_BITS(8); - break; - } - if (BSA_USB_CMD(BELKIN_SA_SET_DATA_BITS_REQUEST, urb_value) < 0) - dev_err(&port->dev, "Set data bits error\n"); - } - - /* set the number of stop bits */ - if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) { - urb_value = (cflag & CSTOPB) ? BELKIN_SA_STOP_BITS(2) - : BELKIN_SA_STOP_BITS(1); - if (BSA_USB_CMD(BELKIN_SA_SET_STOP_BITS_REQUEST, - urb_value) < 0) - dev_err(&port->dev, "Set stop bits error\n"); - } - - /* Set flow control */ - if (((iflag ^ old_iflag) & (IXOFF | IXON)) || - ((cflag ^ old_cflag) & CRTSCTS)) { - urb_value = 0; - if ((iflag & IXOFF) || (iflag & IXON)) - urb_value |= (BELKIN_SA_FLOW_OXON | BELKIN_SA_FLOW_IXON); - else - urb_value &= ~(BELKIN_SA_FLOW_OXON | BELKIN_SA_FLOW_IXON); - - if (cflag & CRTSCTS) - urb_value |= (BELKIN_SA_FLOW_OCTS | BELKIN_SA_FLOW_IRTS); - else - urb_value &= ~(BELKIN_SA_FLOW_OCTS | BELKIN_SA_FLOW_IRTS); - - if (bad_flow_control) - urb_value &= ~(BELKIN_SA_FLOW_IRTS); - - if (BSA_USB_CMD(BELKIN_SA_SET_FLOW_CTRL_REQUEST, urb_value) < 0) - dev_err(&port->dev, "Set flow control error\n"); - } - - /* save off the modified port settings */ - spin_lock_irqsave(&priv->lock, flags); - priv->control_state = control_state; - spin_unlock_irqrestore(&priv->lock, flags); -} - -static void belkin_sa_break_ctl(struct tty_struct *tty, int break_state) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; - - if (BSA_USB_CMD(BELKIN_SA_SET_BREAK_REQUEST, break_state ? 1 : 0) < 0) - dev_err(&port->dev, "Set break_ctl %d\n", break_state); -} - -static int belkin_sa_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct belkin_sa_private *priv = usb_get_serial_port_data(port); - unsigned long control_state; - unsigned long flags; - - dbg("%s", __func__); - - spin_lock_irqsave(&priv->lock, flags); - control_state = priv->control_state; - spin_unlock_irqrestore(&priv->lock, flags); - - return control_state; -} - -static int belkin_sa_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; - struct belkin_sa_private *priv = usb_get_serial_port_data(port); - unsigned long control_state; - unsigned long flags; - int retval; - int rts = 0; - int dtr = 0; - - dbg("%s", __func__); - - spin_lock_irqsave(&priv->lock, flags); - control_state = priv->control_state; - - if (set & TIOCM_RTS) { - control_state |= TIOCM_RTS; - rts = 1; - } - if (set & TIOCM_DTR) { - control_state |= TIOCM_DTR; - dtr = 1; - } - if (clear & TIOCM_RTS) { - control_state &= ~TIOCM_RTS; - rts = 0; - } - if (clear & TIOCM_DTR) { - control_state &= ~TIOCM_DTR; - dtr = 0; - } - - priv->control_state = control_state; - spin_unlock_irqrestore(&priv->lock, flags); - - retval = BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, rts); - if (retval < 0) { - dev_err(&port->dev, "Set RTS error %d\n", retval); - goto exit; - } - - retval = BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, dtr); - if (retval < 0) { - dev_err(&port->dev, "Set DTR error %d\n", retval); - goto exit; - } -exit: - return retval; -} - -module_usb_serial_driver(belkin_driver, serial_drivers); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/belkin_sa.h b/ANDROID_3.4.5/drivers/usb/serial/belkin_sa.h deleted file mode 100644 index c74b58ab..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/belkin_sa.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Definitions for Belkin USB Serial Adapter Driver - * - * Copyright (C) 2000 - * William Greathouse (wgreathouse@smva.com) - * - * This program is largely derived from work by the linux-usb group - * and associated source files. Please see the usb/serial files for - * individual credits and copyrights. - * - * 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. - * - * See Documentation/usb/usb-serial.txt for more information on using this - * driver - * - * 12-Mar-2001 gkh - * Added GoHubs GO-COM232 device id. - * - * 06-Nov-2000 gkh - * Added old Belkin and Peracom device ids, which this driver supports - * - * 12-Oct-2000 William Greathouse - * First cut at supporting Belkin USB Serial Adapter F5U103 - * I did not have a copy of the original work to support this - * adapter, so pardon any stupid mistakes. All of the information - * I am using to write this driver was acquired by using a modified - * UsbSnoop on Windows2000. - * - */ - -#ifndef __LINUX_USB_SERIAL_BSA_H -#define __LINUX_USB_SERIAL_BSA_H - -#define BELKIN_DOCKSTATION_VID 0x050d /* Vendor Id */ -#define BELKIN_DOCKSTATION_PID 0x1203 /* Product Id */ - -#define BELKIN_SA_VID 0x050d /* Vendor Id */ -#define BELKIN_SA_PID 0x0103 /* Product Id */ - -#define BELKIN_OLD_VID 0x056c /* Belkin's "old" vendor id */ -#define BELKIN_OLD_PID 0x8007 /* Belkin's "old" single port serial converter's id */ - -#define PERACOM_VID 0x0565 /* Peracom's vendor id */ -#define PERACOM_PID 0x0001 /* Peracom's single port serial converter's id */ - -#define GOHUBS_VID 0x0921 /* GoHubs vendor id */ -#define GOHUBS_PID 0x1000 /* GoHubs single port serial converter's id (identical to the Peracom device) */ -#define HANDYLINK_PID 0x1200 /* HandyLink USB's id (identical to the Peracom device) */ - -/* Vendor Request Interface */ -#define BELKIN_SA_SET_BAUDRATE_REQUEST 0 /* Set baud rate */ -#define BELKIN_SA_SET_STOP_BITS_REQUEST 1 /* Set stop bits (1,2) */ -#define BELKIN_SA_SET_DATA_BITS_REQUEST 2 /* Set data bits (5,6,7,8) */ -#define BELKIN_SA_SET_PARITY_REQUEST 3 /* Set parity (None, Even, Odd) */ - -#define BELKIN_SA_SET_DTR_REQUEST 10 /* Set DTR state */ -#define BELKIN_SA_SET_RTS_REQUEST 11 /* Set RTS state */ -#define BELKIN_SA_SET_BREAK_REQUEST 12 /* Set BREAK state */ - -#define BELKIN_SA_SET_FLOW_CTRL_REQUEST 16 /* Set flow control mode */ - - -#ifdef WHEN_I_LEARN_THIS -#define BELKIN_SA_SET_MAGIC_REQUEST 17 /* I don't know, possibly flush */ - /* (always in Wininit sequence before flow control) */ -#define BELKIN_SA_RESET xx /* Reset the port */ -#define BELKIN_SA_GET_MODEM_STATUS xx /* Force return of modem status register */ -#endif - -#define BELKIN_SA_SET_REQUEST_TYPE 0x40 - -#define BELKIN_SA_BAUD(b) (230400/b) - -#define BELKIN_SA_STOP_BITS(b) (b-1) - -#define BELKIN_SA_DATA_BITS(b) (b-5) - -#define BELKIN_SA_PARITY_NONE 0 -#define BELKIN_SA_PARITY_EVEN 1 -#define BELKIN_SA_PARITY_ODD 2 -#define BELKIN_SA_PARITY_MARK 3 -#define BELKIN_SA_PARITY_SPACE 4 - -#define BELKIN_SA_FLOW_NONE 0x0000 /* No flow control */ -#define BELKIN_SA_FLOW_OCTS 0x0001 /* use CTS input to throttle output */ -#define BELKIN_SA_FLOW_ODSR 0x0002 /* use DSR input to throttle output */ -#define BELKIN_SA_FLOW_IDSR 0x0004 /* use DSR input to enable receive */ -#define BELKIN_SA_FLOW_IDTR 0x0008 /* use DTR output for input flow control */ -#define BELKIN_SA_FLOW_IRTS 0x0010 /* use RTS output for input flow control */ -#define BELKIN_SA_FLOW_ORTS 0x0020 /* use RTS to indicate data available to send */ -#define BELKIN_SA_FLOW_ERRSUB 0x0040 /* ???? guess ???? substitute inline errors */ -#define BELKIN_SA_FLOW_OXON 0x0080 /* use XON/XOFF for output flow control */ -#define BELKIN_SA_FLOW_IXON 0x0100 /* use XON/XOFF for input flow control */ - -/* - * It seems that the interrupt pipe is closely modelled after the - * 16550 register layout. This is probably because the adapter can - * be used in a "DOS" environment to simulate a standard hardware port. - */ -#define BELKIN_SA_LSR_INDEX 2 /* Line Status Register */ -#define BELKIN_SA_LSR_RDR 0x01 /* receive data ready */ -#define BELKIN_SA_LSR_OE 0x02 /* overrun error */ -#define BELKIN_SA_LSR_PE 0x04 /* parity error */ -#define BELKIN_SA_LSR_FE 0x08 /* framing error */ -#define BELKIN_SA_LSR_BI 0x10 /* break indicator */ -#define BELKIN_SA_LSR_THE 0x20 /* tx holding register empty */ -#define BELKIN_SA_LSR_TE 0x40 /* transmit register empty */ -#define BELKIN_SA_LSR_ERR 0x80 /* OE | PE | FE | BI */ - -#define BELKIN_SA_MSR_INDEX 3 /* Modem Status Register */ -#define BELKIN_SA_MSR_DCTS 0x01 /* Delta CTS */ -#define BELKIN_SA_MSR_DDSR 0x02 /* Delta DSR */ -#define BELKIN_SA_MSR_DRI 0x04 /* Delta RI */ -#define BELKIN_SA_MSR_DCD 0x08 /* Delta CD */ -#define BELKIN_SA_MSR_CTS 0x10 /* Current CTS */ -#define BELKIN_SA_MSR_DSR 0x20 /* Current DSR */ -#define BELKIN_SA_MSR_RI 0x40 /* Current RI */ -#define BELKIN_SA_MSR_CD 0x80 /* Current CD */ - -#endif /* __LINUX_USB_SERIAL_BSA_H */ - diff --git a/ANDROID_3.4.5/drivers/usb/serial/bus.c b/ANDROID_3.4.5/drivers/usb/serial/bus.c deleted file mode 100644 index ed8adb05..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/bus.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * USB Serial Converter Bus specific functions - * - * Copyright (C) 2002 Greg Kroah-Hartman (greg@kroah.com) - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include - -static int usb_serial_device_match(struct device *dev, - struct device_driver *drv) -{ - struct usb_serial_driver *driver; - const struct usb_serial_port *port; - - /* - * drivers are already assigned to ports in serial_probe so it's - * a simple check here. - */ - port = to_usb_serial_port(dev); - if (!port) - return 0; - - driver = to_usb_serial_driver(drv); - - if (driver == port->serial->type) - return 1; - - return 0; -} - -static ssize_t show_port_number(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct usb_serial_port *port = to_usb_serial_port(dev); - - return sprintf(buf, "%d\n", port->number - port->serial->minor); -} - -static DEVICE_ATTR(port_number, S_IRUGO, show_port_number, NULL); - -static int usb_serial_device_probe(struct device *dev) -{ - struct usb_serial_driver *driver; - struct usb_serial_port *port; - int retval = 0; - int minor; - - port = to_usb_serial_port(dev); - if (!port) { - retval = -ENODEV; - goto exit; - } - - driver = port->serial->type; - if (driver->port_probe) { - retval = driver->port_probe(port); - if (retval) - goto exit; - } - - retval = device_create_file(dev, &dev_attr_port_number); - if (retval) { - if (driver->port_remove) - retval = driver->port_remove(port); - goto exit; - } - - minor = port->number; - tty_register_device(usb_serial_tty_driver, minor, dev); - dev_info(&port->serial->dev->dev, - "%s converter now attached to ttyUSB%d\n", - driver->description, minor); - -exit: - return retval; -} - -static int usb_serial_device_remove(struct device *dev) -{ - struct usb_serial_driver *driver; - struct usb_serial_port *port; - int retval = 0; - int minor; - - port = to_usb_serial_port(dev); - if (!port) - return -ENODEV; - - device_remove_file(&port->dev, &dev_attr_port_number); - - driver = port->serial->type; - if (driver->port_remove) - retval = driver->port_remove(port); - - minor = port->number; - tty_unregister_device(usb_serial_tty_driver, minor); - dev_info(dev, "%s converter now disconnected from ttyUSB%d\n", - driver->description, minor); - - return retval; -} - -#ifdef CONFIG_HOTPLUG -static ssize_t store_new_id(struct device_driver *driver, - const char *buf, size_t count) -{ - struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver); - ssize_t retval = usb_store_new_id(&usb_drv->dynids, driver, buf, count); - - if (retval >= 0 && usb_drv->usb_driver != NULL) - retval = usb_store_new_id(&usb_drv->usb_driver->dynids, - &usb_drv->usb_driver->drvwrap.driver, - buf, count); - return retval; -} - -static struct driver_attribute drv_attrs[] = { - __ATTR(new_id, S_IWUSR, NULL, store_new_id), - __ATTR_NULL, -}; - -static void free_dynids(struct usb_serial_driver *drv) -{ - struct usb_dynid *dynid, *n; - - spin_lock(&drv->dynids.lock); - list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) { - list_del(&dynid->node); - kfree(dynid); - } - spin_unlock(&drv->dynids.lock); -} - -#else -static struct driver_attribute drv_attrs[] = { - __ATTR_NULL, -}; -static inline void free_dynids(struct usb_serial_driver *drv) -{ -} -#endif - -struct bus_type usb_serial_bus_type = { - .name = "usb-serial", - .match = usb_serial_device_match, - .probe = usb_serial_device_probe, - .remove = usb_serial_device_remove, - .drv_attrs = drv_attrs, -}; - -int usb_serial_bus_register(struct usb_serial_driver *driver) -{ - int retval; - - driver->driver.bus = &usb_serial_bus_type; - spin_lock_init(&driver->dynids.lock); - INIT_LIST_HEAD(&driver->dynids.list); - - retval = driver_register(&driver->driver); - - return retval; -} - -void usb_serial_bus_deregister(struct usb_serial_driver *driver) -{ - free_dynids(driver); - driver_unregister(&driver->driver); -} - diff --git a/ANDROID_3.4.5/drivers/usb/serial/ch341.c b/ANDROID_3.4.5/drivers/usb/serial/ch341.c deleted file mode 100644 index aaab32db..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/ch341.c +++ /dev/null @@ -1,660 +0,0 @@ -/* - * Copyright 2007, Frank A Kingswood - * Copyright 2007, Werner Cornelius - * Copyright 2009, Boris Hajduk - * - * ch341.c implements a serial port driver for the Winchiphead CH341. - * - * The CH341 device can be used to implement an RS232 asynchronous - * serial port, an IEEE-1284 parallel printer port or a memory-like - * interface. In all cases the CH341 supports an I2C interface as well. - * This driver only supports the asynchronous serial interface. - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEFAULT_BAUD_RATE 9600 -#define DEFAULT_TIMEOUT 1000 - -/* flags for IO-Bits */ -#define CH341_BIT_RTS (1 << 6) -#define CH341_BIT_DTR (1 << 5) - -/******************************/ -/* interrupt pipe definitions */ -/******************************/ -/* always 4 interrupt bytes */ -/* first irq byte normally 0x08 */ -/* second irq byte base 0x7d + below */ -/* third irq byte base 0x94 + below */ -/* fourth irq byte normally 0xee */ - -/* second interrupt byte */ -#define CH341_MULT_STAT 0x04 /* multiple status since last interrupt event */ - -/* status returned in third interrupt answer byte, inverted in data - from irq */ -#define CH341_BIT_CTS 0x01 -#define CH341_BIT_DSR 0x02 -#define CH341_BIT_RI 0x04 -#define CH341_BIT_DCD 0x08 -#define CH341_BITS_MODEM_STAT 0x0f /* all bits */ - -/*******************************/ -/* baudrate calculation factor */ -/*******************************/ -#define CH341_BAUDBASE_FACTOR 1532620800 -#define CH341_BAUDBASE_DIVMAX 3 - -/* Break support - the information used to implement this was gleaned from - * the Net/FreeBSD uchcom.c driver by Takanori Watanabe. Domo arigato. - */ - -#define CH341_REQ_WRITE_REG 0x9A -#define CH341_REQ_READ_REG 0x95 -#define CH341_REG_BREAK1 0x05 -#define CH341_REG_BREAK2 0x18 -#define CH341_NBREAK_BITS_REG1 0x01 -#define CH341_NBREAK_BITS_REG2 0x40 - - -static bool debug; - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(0x4348, 0x5523) }, - { USB_DEVICE(0x1a86, 0x7523) }, - { USB_DEVICE(0x1a86, 0x5523) }, - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -struct ch341_private { - spinlock_t lock; /* access lock */ - wait_queue_head_t delta_msr_wait; /* wait queue for modem status */ - unsigned baud_rate; /* set baud rate */ - u8 line_control; /* set line control value RTS/DTR */ - u8 line_status; /* active status of modem control inputs */ - u8 multi_status_change; /* status changed multiple since last call */ -}; - -static int ch341_control_out(struct usb_device *dev, u8 request, - u16 value, u16 index) -{ - int r; - dbg("ch341_control_out(%02x,%02x,%04x,%04x)", USB_DIR_OUT|0x40, - (int)request, (int)value, (int)index); - - r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, - value, index, NULL, 0, DEFAULT_TIMEOUT); - - return r; -} - -static int ch341_control_in(struct usb_device *dev, - u8 request, u16 value, u16 index, - char *buf, unsigned bufsize) -{ - int r; - dbg("ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)", USB_DIR_IN|0x40, - (int)request, (int)value, (int)index, buf, (int)bufsize); - - r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - value, index, buf, bufsize, DEFAULT_TIMEOUT); - return r; -} - -static int ch341_set_baudrate(struct usb_device *dev, - struct ch341_private *priv) -{ - short a, b; - int r; - unsigned long factor; - short divisor; - - dbg("ch341_set_baudrate(%d)", priv->baud_rate); - - if (!priv->baud_rate) - return -EINVAL; - factor = (CH341_BAUDBASE_FACTOR / priv->baud_rate); - divisor = CH341_BAUDBASE_DIVMAX; - - while ((factor > 0xfff0) && divisor) { - factor >>= 3; - divisor--; - } - - if (factor > 0xfff0) - return -EINVAL; - - factor = 0x10000 - factor; - a = (factor & 0xff00) | divisor; - b = factor & 0xff; - - r = ch341_control_out(dev, 0x9a, 0x1312, a); - if (!r) - r = ch341_control_out(dev, 0x9a, 0x0f2c, b); - - return r; -} - -static int ch341_set_handshake(struct usb_device *dev, u8 control) -{ - dbg("ch341_set_handshake(0x%02x)", control); - return ch341_control_out(dev, 0xa4, ~control, 0); -} - -static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv) -{ - char *buffer; - int r; - const unsigned size = 8; - unsigned long flags; - - dbg("ch341_get_status()"); - - buffer = kmalloc(size, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - r = ch341_control_in(dev, 0x95, 0x0706, 0, buffer, size); - if (r < 0) - goto out; - - /* setup the private status if available */ - if (r == 2) { - r = 0; - spin_lock_irqsave(&priv->lock, flags); - priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT; - priv->multi_status_change = 0; - spin_unlock_irqrestore(&priv->lock, flags); - } else - r = -EPROTO; - -out: kfree(buffer); - return r; -} - -/* -------------------------------------------------------------------------- */ - -static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) -{ - char *buffer; - int r; - const unsigned size = 8; - - dbg("ch341_configure()"); - - buffer = kmalloc(size, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - /* expect two bytes 0x27 0x00 */ - r = ch341_control_in(dev, 0x5f, 0, 0, buffer, size); - if (r < 0) - goto out; - - r = ch341_control_out(dev, 0xa1, 0, 0); - if (r < 0) - goto out; - - r = ch341_set_baudrate(dev, priv); - if (r < 0) - goto out; - - /* expect two bytes 0x56 0x00 */ - r = ch341_control_in(dev, 0x95, 0x2518, 0, buffer, size); - if (r < 0) - goto out; - - r = ch341_control_out(dev, 0x9a, 0x2518, 0x0050); - if (r < 0) - goto out; - - /* expect 0xff 0xee */ - r = ch341_get_status(dev, priv); - if (r < 0) - goto out; - - r = ch341_control_out(dev, 0xa1, 0x501f, 0xd90a); - if (r < 0) - goto out; - - r = ch341_set_baudrate(dev, priv); - if (r < 0) - goto out; - - r = ch341_set_handshake(dev, priv->line_control); - if (r < 0) - goto out; - - /* expect 0x9f 0xee */ - r = ch341_get_status(dev, priv); - -out: kfree(buffer); - return r; -} - -/* allocate private data */ -static int ch341_attach(struct usb_serial *serial) -{ - struct ch341_private *priv; - int r; - - dbg("ch341_attach()"); - - /* private data */ - priv = kzalloc(sizeof(struct ch341_private), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - spin_lock_init(&priv->lock); - init_waitqueue_head(&priv->delta_msr_wait); - priv->baud_rate = DEFAULT_BAUD_RATE; - priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR; - - r = ch341_configure(serial->dev, priv); - if (r < 0) - goto error; - - usb_set_serial_port_data(serial->port[0], priv); - return 0; - -error: kfree(priv); - return r; -} - -static int ch341_carrier_raised(struct usb_serial_port *port) -{ - struct ch341_private *priv = usb_get_serial_port_data(port); - if (priv->line_status & CH341_BIT_DCD) - return 1; - return 0; -} - -static void ch341_dtr_rts(struct usb_serial_port *port, int on) -{ - struct ch341_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - /* drop DTR and RTS */ - spin_lock_irqsave(&priv->lock, flags); - if (on) - priv->line_control |= CH341_BIT_RTS | CH341_BIT_DTR; - else - priv->line_control &= ~(CH341_BIT_RTS | CH341_BIT_DTR); - spin_unlock_irqrestore(&priv->lock, flags); - ch341_set_handshake(port->serial->dev, priv->line_control); - wake_up_interruptible(&priv->delta_msr_wait); -} - -static void ch341_close(struct usb_serial_port *port) -{ - dbg("%s - port %d", __func__, port->number); - - usb_serial_generic_close(port); - usb_kill_urb(port->interrupt_in_urb); -} - - -/* open this device, set default parameters */ -static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - struct ch341_private *priv = usb_get_serial_port_data(serial->port[0]); - int r; - - dbg("ch341_open()"); - - priv->baud_rate = DEFAULT_BAUD_RATE; - - r = ch341_configure(serial->dev, priv); - if (r) - goto out; - - r = ch341_set_handshake(serial->dev, priv->line_control); - if (r) - goto out; - - r = ch341_set_baudrate(serial->dev, priv); - if (r) - goto out; - - dbg("%s - submitting interrupt urb", __func__); - r = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - if (r) { - dev_err(&port->dev, "%s - failed submitting interrupt urb," - " error %d\n", __func__, r); - ch341_close(port); - goto out; - } - - r = usb_serial_generic_open(tty, port); - -out: return r; -} - -/* Old_termios contains the original termios settings and - * tty->termios contains the new setting to be used. - */ -static void ch341_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) -{ - struct ch341_private *priv = usb_get_serial_port_data(port); - unsigned baud_rate; - unsigned long flags; - - dbg("ch341_set_termios()"); - - baud_rate = tty_get_baud_rate(tty); - - priv->baud_rate = baud_rate; - - if (baud_rate) { - spin_lock_irqsave(&priv->lock, flags); - priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS); - spin_unlock_irqrestore(&priv->lock, flags); - ch341_set_baudrate(port->serial->dev, priv); - } else { - spin_lock_irqsave(&priv->lock, flags); - priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS); - spin_unlock_irqrestore(&priv->lock, flags); - } - - ch341_set_handshake(port->serial->dev, priv->line_control); - - /* Unimplemented: - * (cflag & CSIZE) : data bits [5, 8] - * (cflag & PARENB) : parity {NONE, EVEN, ODD} - * (cflag & CSTOPB) : stop bits [1, 2] - */ -} - -static void ch341_break_ctl(struct tty_struct *tty, int break_state) -{ - const uint16_t ch341_break_reg = - CH341_REG_BREAK1 | ((uint16_t) CH341_REG_BREAK2 << 8); - struct usb_serial_port *port = tty->driver_data; - int r; - uint16_t reg_contents; - uint8_t *break_reg; - - dbg("%s()", __func__); - - break_reg = kmalloc(2, GFP_KERNEL); - if (!break_reg) { - dev_err(&port->dev, "%s - kmalloc failed\n", __func__); - return; - } - - r = ch341_control_in(port->serial->dev, CH341_REQ_READ_REG, - ch341_break_reg, 0, break_reg, 2); - if (r < 0) { - dev_err(&port->dev, "%s - USB control read error (%d)\n", - __func__, r); - goto out; - } - dbg("%s - initial ch341 break register contents - reg1: %x, reg2: %x", - __func__, break_reg[0], break_reg[1]); - if (break_state != 0) { - dbg("%s - Enter break state requested", __func__); - break_reg[0] &= ~CH341_NBREAK_BITS_REG1; - break_reg[1] &= ~CH341_NBREAK_BITS_REG2; - } else { - dbg("%s - Leave break state requested", __func__); - break_reg[0] |= CH341_NBREAK_BITS_REG1; - break_reg[1] |= CH341_NBREAK_BITS_REG2; - } - dbg("%s - New ch341 break register contents - reg1: %x, reg2: %x", - __func__, break_reg[0], break_reg[1]); - reg_contents = get_unaligned_le16(break_reg); - r = ch341_control_out(port->serial->dev, CH341_REQ_WRITE_REG, - ch341_break_reg, reg_contents); - if (r < 0) - dev_err(&port->dev, "%s - USB control write error (%d)\n", - __func__, r); -out: - kfree(break_reg); -} - -static int ch341_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct ch341_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - u8 control; - - spin_lock_irqsave(&priv->lock, flags); - if (set & TIOCM_RTS) - priv->line_control |= CH341_BIT_RTS; - if (set & TIOCM_DTR) - priv->line_control |= CH341_BIT_DTR; - if (clear & TIOCM_RTS) - priv->line_control &= ~CH341_BIT_RTS; - if (clear & TIOCM_DTR) - priv->line_control &= ~CH341_BIT_DTR; - control = priv->line_control; - spin_unlock_irqrestore(&priv->lock, flags); - - return ch341_set_handshake(port->serial->dev, control); -} - -static void ch341_read_int_callback(struct urb *urb) -{ - struct usb_serial_port *port = (struct usb_serial_port *) urb->context; - unsigned char *data = urb->transfer_buffer; - unsigned int actual_length = urb->actual_length; - int status; - - dbg("%s (%d)", __func__, port->number); - - switch (urb->status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, - urb->status); - return; - default: - dbg("%s - nonzero urb status received: %d", __func__, - urb->status); - goto exit; - } - - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, urb->transfer_buffer); - - if (actual_length >= 4) { - struct ch341_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - u8 prev_line_status = priv->line_status; - - spin_lock_irqsave(&priv->lock, flags); - priv->line_status = (~(data[2])) & CH341_BITS_MODEM_STAT; - if ((data[1] & CH341_MULT_STAT)) - priv->multi_status_change = 1; - spin_unlock_irqrestore(&priv->lock, flags); - - if ((priv->line_status ^ prev_line_status) & CH341_BIT_DCD) { - struct tty_struct *tty = tty_port_tty_get(&port->port); - if (tty) - usb_serial_handle_dcd_change(port, tty, - priv->line_status & CH341_BIT_DCD); - tty_kref_put(tty); - } - - wake_up_interruptible(&priv->delta_msr_wait); - } - -exit: - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) - dev_err(&urb->dev->dev, - "%s - usb_submit_urb failed with result %d\n", - __func__, status); -} - -static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) -{ - struct ch341_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - u8 prevstatus; - u8 status; - u8 changed; - u8 multi_change = 0; - - spin_lock_irqsave(&priv->lock, flags); - prevstatus = priv->line_status; - priv->multi_status_change = 0; - spin_unlock_irqrestore(&priv->lock, flags); - - while (!multi_change) { - interruptible_sleep_on(&priv->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - - spin_lock_irqsave(&priv->lock, flags); - status = priv->line_status; - multi_change = priv->multi_status_change; - spin_unlock_irqrestore(&priv->lock, flags); - - changed = prevstatus ^ status; - - if (((arg & TIOCM_RNG) && (changed & CH341_BIT_RI)) || - ((arg & TIOCM_DSR) && (changed & CH341_BIT_DSR)) || - ((arg & TIOCM_CD) && (changed & CH341_BIT_DCD)) || - ((arg & TIOCM_CTS) && (changed & CH341_BIT_CTS))) { - return 0; - } - prevstatus = status; - } - - return 0; -} - -static int ch341_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd); - - switch (cmd) { - case TIOCMIWAIT: - dbg("%s (%d) TIOCMIWAIT", __func__, port->number); - return wait_modem_info(port, arg); - - default: - dbg("%s not supported = 0x%04x", __func__, cmd); - break; - } - - return -ENOIOCTLCMD; -} - -static int ch341_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct ch341_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - u8 mcr; - u8 status; - unsigned int result; - - dbg("%s (%d)", __func__, port->number); - - spin_lock_irqsave(&priv->lock, flags); - mcr = priv->line_control; - status = priv->line_status; - spin_unlock_irqrestore(&priv->lock, flags); - - result = ((mcr & CH341_BIT_DTR) ? TIOCM_DTR : 0) - | ((mcr & CH341_BIT_RTS) ? TIOCM_RTS : 0) - | ((status & CH341_BIT_CTS) ? TIOCM_CTS : 0) - | ((status & CH341_BIT_DSR) ? TIOCM_DSR : 0) - | ((status & CH341_BIT_RI) ? TIOCM_RI : 0) - | ((status & CH341_BIT_DCD) ? TIOCM_CD : 0); - - dbg("%s - result = %x", __func__, result); - - return result; -} - - -static int ch341_reset_resume(struct usb_interface *intf) -{ - struct usb_device *dev = interface_to_usbdev(intf); - struct usb_serial *serial = NULL; - struct ch341_private *priv; - - serial = usb_get_intfdata(intf); - priv = usb_get_serial_port_data(serial->port[0]); - - /*reconfigure ch341 serial port after bus-reset*/ - ch341_configure(dev, priv); - - usb_serial_resume(intf); - - return 0; -} - -static struct usb_driver ch341_driver = { - .name = "ch341", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .reset_resume = ch341_reset_resume, - .id_table = id_table, - .supports_autosuspend = 1, -}; - -static struct usb_serial_driver ch341_device = { - .driver = { - .owner = THIS_MODULE, - .name = "ch341-uart", - }, - .id_table = id_table, - .num_ports = 1, - .open = ch341_open, - .dtr_rts = ch341_dtr_rts, - .carrier_raised = ch341_carrier_raised, - .close = ch341_close, - .ioctl = ch341_ioctl, - .set_termios = ch341_set_termios, - .break_ctl = ch341_break_ctl, - .tiocmget = ch341_tiocmget, - .tiocmset = ch341_tiocmset, - .read_int_callback = ch341_read_int_callback, - .attach = ch341_attach, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &ch341_device, NULL -}; - -module_usb_serial_driver(ch341_driver, serial_drivers); - -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/console.c b/ANDROID_3.4.5/drivers/usb/serial/console.c deleted file mode 100644 index 1ee6b2ab..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/console.c +++ /dev/null @@ -1,317 +0,0 @@ -/* - * USB Serial Console driver - * - * Copyright (C) 2001 - 2002 Greg Kroah-Hartman (greg@kroah.com) - * - * 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. - * - * Thanks to Randy Dunlap for the original version of this code. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static int debug; - -struct usbcons_info { - int magic; - int break_flag; - struct usb_serial_port *port; -}; - -static struct usbcons_info usbcons_info; -static struct console usbcons; - -/* - * ------------------------------------------------------------ - * USB Serial console driver - * - * Much of the code here is copied from drivers/char/serial.c - * and implements a phony serial console in the same way that - * serial.c does so that in case some software queries it, - * it will get the same results. - * - * Things that are different from the way the serial port code - * does things, is that we call the lower level usb-serial - * driver code to initialize the device, and we set the initial - * console speeds based on the command line arguments. - * ------------------------------------------------------------ - */ - - -/* - * The parsing of the command line works exactly like the - * serial.c code, except that the specifier is "ttyUSB" instead - * of "ttyS". - */ -static int usb_console_setup(struct console *co, char *options) -{ - struct usbcons_info *info = &usbcons_info; - int baud = 9600; - int bits = 8; - int parity = 'n'; - int doflow = 0; - int cflag = CREAD | HUPCL | CLOCAL; - char *s; - struct usb_serial *serial; - struct usb_serial_port *port; - int retval; - struct tty_struct *tty = NULL; - struct ktermios dummy; - - dbg("%s", __func__); - - if (options) { - baud = simple_strtoul(options, NULL, 10); - s = options; - while (*s >= '0' && *s <= '9') - s++; - if (*s) - parity = *s++; - if (*s) - bits = *s++ - '0'; - if (*s) - doflow = (*s++ == 'r'); - } - - /* Sane default */ - if (baud == 0) - baud = 9600; - - switch (bits) { - case 7: - cflag |= CS7; - break; - default: - case 8: - cflag |= CS8; - break; - } - switch (parity) { - case 'o': case 'O': - cflag |= PARODD; - break; - case 'e': case 'E': - cflag |= PARENB; - break; - } - co->cflag = cflag; - - /* - * no need to check the index here: if the index is wrong, console - * code won't call us - */ - serial = usb_serial_get_by_index(co->index); - if (serial == NULL) { - /* no device is connected yet, sorry :( */ - err("No USB device connected to ttyUSB%i", co->index); - return -ENODEV; - } - - retval = usb_autopm_get_interface(serial->interface); - if (retval) - goto error_get_interface; - - port = serial->port[co->index - serial->minor]; - tty_port_tty_set(&port->port, NULL); - - info->port = port; - - ++port->port.count; - if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) { - if (serial->type->set_termios) { - /* - * allocate a fake tty so the driver can initialize - * the termios structure, then later call set_termios to - * configure according to command line arguments - */ - tty = kzalloc(sizeof(*tty), GFP_KERNEL); - if (!tty) { - retval = -ENOMEM; - err("no more memory"); - goto reset_open_count; - } - kref_init(&tty->kref); - tty_port_tty_set(&port->port, tty); - tty->driver = usb_serial_tty_driver; - tty->index = co->index; - if (tty_init_termios(tty)) { - retval = -ENOMEM; - err("no more memory"); - goto free_tty; - } - } - - /* only call the device specific open if this - * is the first time the port is opened */ - if (serial->type->open) - retval = serial->type->open(NULL, port); - else - retval = usb_serial_generic_open(NULL, port); - - if (retval) { - err("could not open USB console port"); - goto fail; - } - - if (serial->type->set_termios) { - tty->termios->c_cflag = cflag; - tty_termios_encode_baud_rate(tty->termios, baud, baud); - memset(&dummy, 0, sizeof(struct ktermios)); - serial->type->set_termios(tty, port, &dummy); - - tty_port_tty_set(&port->port, NULL); - kfree(tty); - } - set_bit(ASYNCB_INITIALIZED, &port->port.flags); - } - /* Now that any required fake tty operations are completed restore - * the tty port count */ - --port->port.count; - /* The console is special in terms of closing the device so - * indicate this port is now acting as a system console. */ - port->port.console = 1; - - mutex_unlock(&serial->disc_mutex); - return retval; - - fail: - tty_port_tty_set(&port->port, NULL); - free_tty: - kfree(tty); - reset_open_count: - port->port.count = 0; - usb_autopm_put_interface(serial->interface); - error_get_interface: - usb_serial_put(serial); - mutex_unlock(&serial->disc_mutex); - return retval; -} - -static void usb_console_write(struct console *co, - const char *buf, unsigned count) -{ - static struct usbcons_info *info = &usbcons_info; - struct usb_serial_port *port = info->port; - struct usb_serial *serial; - int retval = -ENODEV; - - if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED) - return; - serial = port->serial; - - if (count == 0) - return; - - dbg("%s - port %d, %d byte(s)", __func__, port->number, count); - - if (!port->port.console) { - dbg("%s - port not opened", __func__); - return; - } - - while (count) { - unsigned int i; - unsigned int lf; - /* search for LF so we can insert CR if necessary */ - for (i = 0, lf = 0 ; i < count ; i++) { - if (*(buf + i) == 10) { - lf = 1; - i++; - break; - } - } - /* pass on to the driver specific version of this function if - it is available */ - if (serial->type->write) - retval = serial->type->write(NULL, port, buf, i); - else - retval = usb_serial_generic_write(NULL, port, buf, i); - dbg("%s - return value : %d", __func__, retval); - if (lf) { - /* append CR after LF */ - unsigned char cr = 13; - if (serial->type->write) - retval = serial->type->write(NULL, - port, &cr, 1); - else - retval = usb_serial_generic_write(NULL, - port, &cr, 1); - dbg("%s - return value : %d", __func__, retval); - } - buf += i; - count -= i; - } -} - -static struct tty_driver *usb_console_device(struct console *co, int *index) -{ - struct tty_driver **p = (struct tty_driver **)co->data; - - if (!*p) - return NULL; - - *index = co->index; - return *p; -} - -static struct console usbcons = { - .name = "ttyUSB", - .write = usb_console_write, - .device = usb_console_device, - .setup = usb_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &usb_serial_tty_driver, -}; - -void usb_serial_console_disconnect(struct usb_serial *serial) -{ - if (serial && serial->port && serial->port[0] - && serial->port[0] == usbcons_info.port) { - usb_serial_console_exit(); - usb_serial_put(serial); - } -} - -void usb_serial_console_init(int serial_debug, int minor) -{ - debug = serial_debug; - - if (minor == 0) { - /* - * Call register_console() if this is the first device plugged - * in. If we call it earlier, then the callback to - * console_setup() will fail, as there is not a device seen by - * the USB subsystem yet. - */ - /* - * Register console. - * NOTES: - * console_setup() is called (back) immediately (from - * register_console). console_write() is called immediately - * from register_console iff CON_PRINTBUFFER is set in flags. - */ - dbg("registering the USB serial console."); - register_console(&usbcons); - } -} - -void usb_serial_console_exit(void) -{ - if (usbcons_info.port) { - unregister_console(&usbcons); - usbcons_info.port->port.console = 0; - usbcons_info.port = NULL; - } -} - diff --git a/ANDROID_3.4.5/drivers/usb/serial/cp210x.c b/ANDROID_3.4.5/drivers/usb/serial/cp210x.c deleted file mode 100644 index 53e7e692..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/cp210x.c +++ /dev/null @@ -1,913 +0,0 @@ -/* - * Silicon Laboratories CP210x USB to RS232 serial adaptor driver - * - * Copyright (C) 2005 Craig Shelley (craig@microtron.org.uk) - * - * 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. - * - * Support to set flow control line levels using TIOCMGET and TIOCMSET - * thanks to Karl Hiramoto karl@hiramoto.org. RTSCTS hardware flow - * control thanks to Munir Nassar nassarmu@real-time.com - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Version Information - */ -#define DRIVER_VERSION "v0.09" -#define DRIVER_DESC "Silicon Labs CP210x RS232 serial adaptor driver" - -/* - * Function Prototypes - */ -static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *); -static void cp210x_close(struct usb_serial_port *); -static void cp210x_get_termios(struct tty_struct *, - struct usb_serial_port *port); -static void cp210x_get_termios_port(struct usb_serial_port *port, - unsigned int *cflagp, unsigned int *baudp); -static void cp210x_change_speed(struct tty_struct *, struct usb_serial_port *, - struct ktermios *); -static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *, - struct ktermios*); -static int cp210x_tiocmget(struct tty_struct *); -static int cp210x_tiocmset(struct tty_struct *, unsigned int, unsigned int); -static int cp210x_tiocmset_port(struct usb_serial_port *port, - unsigned int, unsigned int); -static void cp210x_break_ctl(struct tty_struct *, int); -static int cp210x_startup(struct usb_serial *); -static void cp210x_release(struct usb_serial *); -static void cp210x_dtr_rts(struct usb_serial_port *p, int on); - -static bool debug; - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(0x045B, 0x0053) }, /* Renesas RX610 RX-Stick */ - { USB_DEVICE(0x0471, 0x066A) }, /* AKTAKOM ACE-1001 cable */ - { USB_DEVICE(0x0489, 0xE000) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */ - { USB_DEVICE(0x0489, 0xE003) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */ - { USB_DEVICE(0x0745, 0x1000) }, /* CipherLab USB CCD Barcode Scanner 1000 */ - { USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */ - { USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */ - { USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */ - { USB_DEVICE(0x0BED, 0x1101) }, /* MEI series 2000 Combo Acceptor */ - { USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */ - { USB_DEVICE(0x0FCF, 0x1004) }, /* Dynastream ANT2USB */ - { USB_DEVICE(0x0FCF, 0x1006) }, /* Dynastream ANT development board */ - { USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */ - { USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */ - { USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */ - { USB_DEVICE(0x10C4, 0x0F91) }, /* Vstabi */ - { USB_DEVICE(0x10C4, 0x1101) }, /* Arkham Technology DS101 Bus Monitor */ - { USB_DEVICE(0x10C4, 0x1601) }, /* Arkham Technology DS101 Adapter */ - { USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */ - { USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */ - { USB_DEVICE(0x10C4, 0x8044) }, /* Cygnal Debug Adapter */ - { USB_DEVICE(0x10C4, 0x804E) }, /* Software Bisque Paramount ME build-in converter */ - { USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */ - { USB_DEVICE(0x10C4, 0x8054) }, /* Enfora GSM2228 */ - { USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */ - { USB_DEVICE(0x10C4, 0x806F) }, /* IMS USB to RS422 Converter Cable */ - { USB_DEVICE(0x10C4, 0x807A) }, /* Crumb128 board */ - { USB_DEVICE(0x10C4, 0x80C4) }, /* Cygnal Integrated Products, Inc., Optris infrared thermometer */ - { USB_DEVICE(0x10C4, 0x80CA) }, /* Degree Controls Inc */ - { USB_DEVICE(0x10C4, 0x80DD) }, /* Tracient RFID */ - { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */ - { USB_DEVICE(0x10C4, 0x8115) }, /* Arygon NFC/Mifare Reader */ - { USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */ - { USB_DEVICE(0x10C4, 0x813F) }, /* Tams Master Easy Control */ - { USB_DEVICE(0x10C4, 0x814A) }, /* West Mountain Radio RIGblaster P&P */ - { USB_DEVICE(0x10C4, 0x814B) }, /* West Mountain Radio RIGtalk */ - { USB_DEVICE(0x10C4, 0x8156) }, /* B&G H3000 link cable */ - { USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */ - { USB_DEVICE(0x10C4, 0x815F) }, /* Timewave HamLinkUSB */ - { USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */ - { USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */ - { USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */ - { USB_DEVICE(0x10C4, 0x81A9) }, /* Multiplex RC Interface */ - { USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */ - { USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */ - { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */ - { USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */ - { USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */ - { USB_DEVICE(0x10C4, 0x81E8) }, /* Zephyr Bioharness */ - { USB_DEVICE(0x10C4, 0x81F2) }, /* C1007 HF band RFID controller */ - { USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */ - { USB_DEVICE(0x10C4, 0x822B) }, /* Modem EDGE(GSM) Comander 2 */ - { USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demonstration module */ - { USB_DEVICE(0x10C4, 0x8293) }, /* Telegesis ETRX2USB */ - { USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */ - { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */ - { USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */ - { USB_DEVICE(0x10C4, 0x83A8) }, /* Amber Wireless AMB2560 */ - { USB_DEVICE(0x10C4, 0x83D8) }, /* DekTec DTA Plus VHF/UHF Booster/Attenuator */ - { USB_DEVICE(0x10C4, 0x8411) }, /* Kyocera GPS Module */ - { USB_DEVICE(0x10C4, 0x8418) }, /* IRZ Automation Teleport SG-10 GSM/GPRS Modem */ - { USB_DEVICE(0x10C4, 0x846E) }, /* BEI USB Sensor Interface (VCP) */ - { USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */ - { USB_DEVICE(0x10C4, 0x85EA) }, /* AC-Services IBUS-IF */ - { USB_DEVICE(0x10C4, 0x85EB) }, /* AC-Services CIS-IBUS */ - { USB_DEVICE(0x10C4, 0x8664) }, /* AC-Services CAN-IF */ - { USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */ - { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ - { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ - { USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */ - { USB_DEVICE(0x10C4, 0xEA80) }, /* Silicon Labs factory default */ - { USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */ - { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */ - { USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */ - { USB_DEVICE(0x10C4, 0xF003) }, /* Elan Digital Systems USBpulse100 */ - { USB_DEVICE(0x10C4, 0xF004) }, /* Elan Digital Systems USBcount50 */ - { USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */ - { USB_DEVICE(0x10CE, 0xEA6A) }, /* Silicon Labs MobiData GPRS USB Modem 100EU */ - { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */ - { USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */ - { USB_DEVICE(0x166A, 0x0201) }, /* Clipsal 5500PACA C-Bus Pascal Automation Controller */ - { USB_DEVICE(0x166A, 0x0301) }, /* Clipsal 5800PC C-Bus Wireless PC Interface */ - { USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */ - { USB_DEVICE(0x166A, 0x0304) }, /* Clipsal 5000CT2 C-Bus Black and White Touchscreen */ - { USB_DEVICE(0x166A, 0x0305) }, /* Clipsal C-5000CT2 C-Bus Spectrum Colour Touchscreen */ - { USB_DEVICE(0x166A, 0x0401) }, /* Clipsal L51xx C-Bus Architectural Dimmer */ - { USB_DEVICE(0x166A, 0x0101) }, /* Clipsal 5560884 C-Bus Multi-room Audio Matrix Switcher */ - { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */ - { USB_DEVICE(0x16DC, 0x0010) }, /* W-IE-NE-R Plein & Baus GmbH PL512 Power Supply */ - { USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */ - { USB_DEVICE(0x16DC, 0x0012) }, /* W-IE-NE-R Plein & Baus GmbH MPOD Multi Channel Power Supply */ - { USB_DEVICE(0x16DC, 0x0015) }, /* W-IE-NE-R Plein & Baus GmbH CML Control, Monitoring and Data Logger */ - { USB_DEVICE(0x17A8, 0x0001) }, /* Kamstrup Optical Eye/3-wire */ - { USB_DEVICE(0x17A8, 0x0005) }, /* Kamstrup M-Bus Master MultiPort 250D */ - { USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */ - { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */ - { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */ - { USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */ - { USB_DEVICE(0x1E29, 0x0102) }, /* Festo CPX-USB */ - { USB_DEVICE(0x1E29, 0x0501) }, /* Festo CMSP */ - { USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */ - { USB_DEVICE(0x3195, 0xF280) }, /* Link Instruments MSO-28 */ - { USB_DEVICE(0x3195, 0xF281) }, /* Link Instruments MSO-28 */ - { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */ - { } /* Terminating Entry */ -}; - -MODULE_DEVICE_TABLE(usb, id_table); - -struct cp210x_port_private { - __u8 bInterfaceNumber; -}; - -static struct usb_driver cp210x_driver = { - .name = "cp210x", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - -static struct usb_serial_driver cp210x_device = { - .driver = { - .owner = THIS_MODULE, - .name = "cp210x", - }, - .id_table = id_table, - .num_ports = 1, - .bulk_in_size = 256, - .bulk_out_size = 256, - .open = cp210x_open, - .close = cp210x_close, - .break_ctl = cp210x_break_ctl, - .set_termios = cp210x_set_termios, - .tiocmget = cp210x_tiocmget, - .tiocmset = cp210x_tiocmset, - .attach = cp210x_startup, - .release = cp210x_release, - .dtr_rts = cp210x_dtr_rts -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &cp210x_device, NULL -}; - -/* Config request types */ -#define REQTYPE_HOST_TO_DEVICE 0x41 -#define REQTYPE_DEVICE_TO_HOST 0xc1 - -/* Config request codes */ -#define CP210X_IFC_ENABLE 0x00 -#define CP210X_SET_BAUDDIV 0x01 -#define CP210X_GET_BAUDDIV 0x02 -#define CP210X_SET_LINE_CTL 0x03 -#define CP210X_GET_LINE_CTL 0x04 -#define CP210X_SET_BREAK 0x05 -#define CP210X_IMM_CHAR 0x06 -#define CP210X_SET_MHS 0x07 -#define CP210X_GET_MDMSTS 0x08 -#define CP210X_SET_XON 0x09 -#define CP210X_SET_XOFF 0x0A -#define CP210X_SET_EVENTMASK 0x0B -#define CP210X_GET_EVENTMASK 0x0C -#define CP210X_SET_CHAR 0x0D -#define CP210X_GET_CHARS 0x0E -#define CP210X_GET_PROPS 0x0F -#define CP210X_GET_COMM_STATUS 0x10 -#define CP210X_RESET 0x11 -#define CP210X_PURGE 0x12 -#define CP210X_SET_FLOW 0x13 -#define CP210X_GET_FLOW 0x14 -#define CP210X_EMBED_EVENTS 0x15 -#define CP210X_GET_EVENTSTATE 0x16 -#define CP210X_SET_CHARS 0x19 -#define CP210X_GET_BAUDRATE 0x1D -#define CP210X_SET_BAUDRATE 0x1E - -/* CP210X_IFC_ENABLE */ -#define UART_ENABLE 0x0001 -#define UART_DISABLE 0x0000 - -/* CP210X_(SET|GET)_BAUDDIV */ -#define BAUD_RATE_GEN_FREQ 0x384000 - -/* CP210X_(SET|GET)_LINE_CTL */ -#define BITS_DATA_MASK 0X0f00 -#define BITS_DATA_5 0X0500 -#define BITS_DATA_6 0X0600 -#define BITS_DATA_7 0X0700 -#define BITS_DATA_8 0X0800 -#define BITS_DATA_9 0X0900 - -#define BITS_PARITY_MASK 0x00f0 -#define BITS_PARITY_NONE 0x0000 -#define BITS_PARITY_ODD 0x0010 -#define BITS_PARITY_EVEN 0x0020 -#define BITS_PARITY_MARK 0x0030 -#define BITS_PARITY_SPACE 0x0040 - -#define BITS_STOP_MASK 0x000f -#define BITS_STOP_1 0x0000 -#define BITS_STOP_1_5 0x0001 -#define BITS_STOP_2 0x0002 - -/* CP210X_SET_BREAK */ -#define BREAK_ON 0x0001 -#define BREAK_OFF 0x0000 - -/* CP210X_(SET_MHS|GET_MDMSTS) */ -#define CONTROL_DTR 0x0001 -#define CONTROL_RTS 0x0002 -#define CONTROL_CTS 0x0010 -#define CONTROL_DSR 0x0020 -#define CONTROL_RING 0x0040 -#define CONTROL_DCD 0x0080 -#define CONTROL_WRITE_DTR 0x0100 -#define CONTROL_WRITE_RTS 0x0200 - -/* - * cp210x_get_config - * Reads from the CP210x configuration registers - * 'size' is specified in bytes. - * 'data' is a pointer to a pre-allocated array of integers large - * enough to hold 'size' bytes (with 4 bytes to each integer) - */ -static int cp210x_get_config(struct usb_serial_port *port, u8 request, - unsigned int *data, int size) -{ - struct usb_serial *serial = port->serial; - struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); - __le32 *buf; - int result, i, length; - - /* Number of integers required to contain the array */ - length = (((size - 1) | 3) + 1)/4; - - buf = kcalloc(length, sizeof(__le32), GFP_KERNEL); - if (!buf) { - dev_err(&port->dev, "%s - out of memory.\n", __func__); - return -ENOMEM; - } - - /* Issue the request, attempting to read 'size' bytes */ - result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - request, REQTYPE_DEVICE_TO_HOST, 0x0000, - port_priv->bInterfaceNumber, buf, size, - USB_CTRL_GET_TIMEOUT); - - /* Convert data into an array of integers */ - for (i = 0; i < length; i++) - data[i] = le32_to_cpu(buf[i]); - - kfree(buf); - - if (result != size) { - dbg("%s - Unable to send config request, " - "request=0x%x size=%d result=%d", - __func__, request, size, result); - if (result > 0) - result = -EPROTO; - - return result; - } - - return 0; -} - -/* - * cp210x_set_config - * Writes to the CP210x configuration registers - * Values less than 16 bits wide are sent directly - * 'size' is specified in bytes. - */ -static int cp210x_set_config(struct usb_serial_port *port, u8 request, - unsigned int *data, int size) -{ - struct usb_serial *serial = port->serial; - struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); - __le32 *buf; - int result, i, length; - - /* Number of integers required to contain the array */ - length = (((size - 1) | 3) + 1)/4; - - buf = kmalloc(length * sizeof(__le32), GFP_KERNEL); - if (!buf) { - dev_err(&port->dev, "%s - out of memory.\n", - __func__); - return -ENOMEM; - } - - /* Array of integers into bytes */ - for (i = 0; i < length; i++) - buf[i] = cpu_to_le32(data[i]); - - if (size > 2) { - result = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - request, REQTYPE_HOST_TO_DEVICE, 0x0000, - port_priv->bInterfaceNumber, buf, size, - USB_CTRL_SET_TIMEOUT); - } else { - result = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - request, REQTYPE_HOST_TO_DEVICE, data[0], - port_priv->bInterfaceNumber, NULL, 0, - USB_CTRL_SET_TIMEOUT); - } - - kfree(buf); - - if ((size > 2 && result != size) || result < 0) { - dbg("%s - Unable to send request, " - "request=0x%x size=%d result=%d", - __func__, request, size, result); - if (result > 0) - result = -EPROTO; - - return result; - } - - return 0; -} - -/* - * cp210x_set_config_single - * Convenience function for calling cp210x_set_config on single data values - * without requiring an integer pointer - */ -static inline int cp210x_set_config_single(struct usb_serial_port *port, - u8 request, unsigned int data) -{ - return cp210x_set_config(port, request, &data, 2); -} - -/* - * cp210x_quantise_baudrate - * Quantises the baud rate as per AN205 Table 1 - */ -static unsigned int cp210x_quantise_baudrate(unsigned int baud) { - if (baud <= 300) - baud = 300; - else if (baud <= 600) baud = 600; - else if (baud <= 1200) baud = 1200; - else if (baud <= 1800) baud = 1800; - else if (baud <= 2400) baud = 2400; - else if (baud <= 4000) baud = 4000; - else if (baud <= 4803) baud = 4800; - else if (baud <= 7207) baud = 7200; - else if (baud <= 9612) baud = 9600; - else if (baud <= 14428) baud = 14400; - else if (baud <= 16062) baud = 16000; - else if (baud <= 19250) baud = 19200; - else if (baud <= 28912) baud = 28800; - else if (baud <= 38601) baud = 38400; - else if (baud <= 51558) baud = 51200; - else if (baud <= 56280) baud = 56000; - else if (baud <= 58053) baud = 57600; - else if (baud <= 64111) baud = 64000; - else if (baud <= 77608) baud = 76800; - else if (baud <= 117028) baud = 115200; - else if (baud <= 129347) baud = 128000; - else if (baud <= 156868) baud = 153600; - else if (baud <= 237832) baud = 230400; - else if (baud <= 254234) baud = 250000; - else if (baud <= 273066) baud = 256000; - else if (baud <= 491520) baud = 460800; - else if (baud <= 567138) baud = 500000; - else if (baud <= 670254) baud = 576000; - else if (baud < 1000000) - baud = 921600; - else if (baud > 2000000) - baud = 2000000; - return baud; -} - -static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - int result; - - dbg("%s - port %d", __func__, port->number); - - result = cp210x_set_config_single(port, CP210X_IFC_ENABLE, - UART_ENABLE); - if (result) { - dev_err(&port->dev, "%s - Unable to enable UART\n", __func__); - return result; - } - - /* Configure the termios structure */ - cp210x_get_termios(tty, port); - - /* The baud rate must be initialised on cp2104 */ - if (tty) - cp210x_change_speed(tty, port, NULL); - - return usb_serial_generic_open(tty, port); -} - -static void cp210x_close(struct usb_serial_port *port) -{ - dbg("%s - port %d", __func__, port->number); - - usb_serial_generic_close(port); - - mutex_lock(&port->serial->disc_mutex); - if (!port->serial->disconnected) - cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE); - mutex_unlock(&port->serial->disc_mutex); -} - -/* - * cp210x_get_termios - * Reads the baud rate, data bits, parity, stop bits and flow control mode - * from the device, corrects any unsupported values, and configures the - * termios structure to reflect the state of the device - */ -static void cp210x_get_termios(struct tty_struct *tty, - struct usb_serial_port *port) -{ - unsigned int baud; - - if (tty) { - cp210x_get_termios_port(tty->driver_data, - &tty->termios->c_cflag, &baud); - tty_encode_baud_rate(tty, baud, baud); - } - - else { - unsigned int cflag; - cflag = 0; - cp210x_get_termios_port(port, &cflag, &baud); - } -} - -/* - * cp210x_get_termios_port - * This is the heart of cp210x_get_termios which always uses a &usb_serial_port. - */ -static void cp210x_get_termios_port(struct usb_serial_port *port, - unsigned int *cflagp, unsigned int *baudp) -{ - unsigned int cflag, modem_ctl[4]; - unsigned int baud; - unsigned int bits; - - dbg("%s - port %d", __func__, port->number); - - cp210x_get_config(port, CP210X_GET_BAUDRATE, &baud, 4); - - dbg("%s - baud rate = %d", __func__, baud); - *baudp = baud; - - cflag = *cflagp; - - cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2); - cflag &= ~CSIZE; - switch (bits & BITS_DATA_MASK) { - case BITS_DATA_5: - dbg("%s - data bits = 5", __func__); - cflag |= CS5; - break; - case BITS_DATA_6: - dbg("%s - data bits = 6", __func__); - cflag |= CS6; - break; - case BITS_DATA_7: - dbg("%s - data bits = 7", __func__); - cflag |= CS7; - break; - case BITS_DATA_8: - dbg("%s - data bits = 8", __func__); - cflag |= CS8; - break; - case BITS_DATA_9: - dbg("%s - data bits = 9 (not supported, using 8 data bits)", - __func__); - cflag |= CS8; - bits &= ~BITS_DATA_MASK; - bits |= BITS_DATA_8; - cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); - break; - default: - dbg("%s - Unknown number of data bits, using 8", __func__); - cflag |= CS8; - bits &= ~BITS_DATA_MASK; - bits |= BITS_DATA_8; - cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); - break; - } - - switch (bits & BITS_PARITY_MASK) { - case BITS_PARITY_NONE: - dbg("%s - parity = NONE", __func__); - cflag &= ~PARENB; - break; - case BITS_PARITY_ODD: - dbg("%s - parity = ODD", __func__); - cflag |= (PARENB|PARODD); - break; - case BITS_PARITY_EVEN: - dbg("%s - parity = EVEN", __func__); - cflag &= ~PARODD; - cflag |= PARENB; - break; - case BITS_PARITY_MARK: - dbg("%s - parity = MARK", __func__); - cflag |= (PARENB|PARODD|CMSPAR); - break; - case BITS_PARITY_SPACE: - dbg("%s - parity = SPACE", __func__); - cflag &= ~PARODD; - cflag |= (PARENB|CMSPAR); - break; - default: - dbg("%s - Unknown parity mode, disabling parity", __func__); - cflag &= ~PARENB; - bits &= ~BITS_PARITY_MASK; - cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); - break; - } - - cflag &= ~CSTOPB; - switch (bits & BITS_STOP_MASK) { - case BITS_STOP_1: - dbg("%s - stop bits = 1", __func__); - break; - case BITS_STOP_1_5: - dbg("%s - stop bits = 1.5 (not supported, using 1 stop bit)", - __func__); - bits &= ~BITS_STOP_MASK; - cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); - break; - case BITS_STOP_2: - dbg("%s - stop bits = 2", __func__); - cflag |= CSTOPB; - break; - default: - dbg("%s - Unknown number of stop bits, using 1 stop bit", - __func__); - bits &= ~BITS_STOP_MASK; - cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); - break; - } - - cp210x_get_config(port, CP210X_GET_FLOW, modem_ctl, 16); - if (modem_ctl[0] & 0x0008) { - dbg("%s - flow control = CRTSCTS", __func__); - cflag |= CRTSCTS; - } else { - dbg("%s - flow control = NONE", __func__); - cflag &= ~CRTSCTS; - } - - *cflagp = cflag; -} - -/* - * CP2101 supports the following baud rates: - * - * 300, 600, 1200, 1800, 2400, 4800, 7200, 9600, 14400, 19200, 28800, - * 38400, 56000, 57600, 115200, 128000, 230400, 460800, 921600 - * - * CP2102 and CP2103 support the following additional rates: - * - * 4000, 16000, 51200, 64000, 76800, 153600, 250000, 256000, 500000, - * 576000 - * - * The device will map a requested rate to a supported one, but the result - * of requests for rates greater than 1053257 is undefined (see AN205). - * - * CP2104, CP2105 and CP2110 support most rates up to 2M, 921k and 1M baud, - * respectively, with an error less than 1%. The actual rates are determined - * by - * - * div = round(freq / (2 x prescale x request)) - * actual = freq / (2 x prescale x div) - * - * For CP2104 and CP2105 freq is 48Mhz and prescale is 4 for request <= 365bps - * or 1 otherwise. - * For CP2110 freq is 24Mhz and prescale is 4 for request <= 300bps or 1 - * otherwise. - */ -static void cp210x_change_speed(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) -{ - u32 baud; - - baud = tty->termios->c_ospeed; - - /* This maps the requested rate to a rate valid on cp2102 or cp2103, - * or to an arbitrary rate in [1M,2M]. - * - * NOTE: B0 is not implemented. - */ - baud = cp210x_quantise_baudrate(baud); - - dbg("%s - setting baud rate to %u", __func__, baud); - if (cp210x_set_config(port, CP210X_SET_BAUDRATE, &baud, - sizeof(baud))) { - dev_warn(&port->dev, "failed to set baud rate to %u\n", baud); - if (old_termios) - baud = old_termios->c_ospeed; - else - baud = 9600; - } - - tty_encode_baud_rate(tty, baud, baud); -} - -static void cp210x_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) -{ - unsigned int cflag, old_cflag; - unsigned int bits; - unsigned int modem_ctl[4]; - - dbg("%s - port %d", __func__, port->number); - - if (!tty) - return; - - cflag = tty->termios->c_cflag; - old_cflag = old_termios->c_cflag; - - if (tty->termios->c_ospeed != old_termios->c_ospeed) - cp210x_change_speed(tty, port, old_termios); - - /* If the number of data bits is to be updated */ - if ((cflag & CSIZE) != (old_cflag & CSIZE)) { - cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2); - bits &= ~BITS_DATA_MASK; - switch (cflag & CSIZE) { - case CS5: - bits |= BITS_DATA_5; - dbg("%s - data bits = 5", __func__); - break; - case CS6: - bits |= BITS_DATA_6; - dbg("%s - data bits = 6", __func__); - break; - case CS7: - bits |= BITS_DATA_7; - dbg("%s - data bits = 7", __func__); - break; - case CS8: - bits |= BITS_DATA_8; - dbg("%s - data bits = 8", __func__); - break; - /*case CS9: - bits |= BITS_DATA_9; - dbg("%s - data bits = 9", __func__); - break;*/ - default: - dbg("cp210x driver does not " - "support the number of bits requested," - " using 8 bit mode"); - bits |= BITS_DATA_8; - break; - } - if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) - dbg("Number of data bits requested " - "not supported by device"); - } - - if ((cflag & (PARENB|PARODD|CMSPAR)) != - (old_cflag & (PARENB|PARODD|CMSPAR))) { - cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2); - bits &= ~BITS_PARITY_MASK; - if (cflag & PARENB) { - if (cflag & CMSPAR) { - if (cflag & PARODD) { - bits |= BITS_PARITY_MARK; - dbg("%s - parity = MARK", __func__); - } else { - bits |= BITS_PARITY_SPACE; - dbg("%s - parity = SPACE", __func__); - } - } else { - if (cflag & PARODD) { - bits |= BITS_PARITY_ODD; - dbg("%s - parity = ODD", __func__); - } else { - bits |= BITS_PARITY_EVEN; - dbg("%s - parity = EVEN", __func__); - } - } - } - if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) - dbg("Parity mode not supported by device"); - } - - if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) { - cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2); - bits &= ~BITS_STOP_MASK; - if (cflag & CSTOPB) { - bits |= BITS_STOP_2; - dbg("%s - stop bits = 2", __func__); - } else { - bits |= BITS_STOP_1; - dbg("%s - stop bits = 1", __func__); - } - if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) - dbg("Number of stop bits requested " - "not supported by device"); - } - - if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) { - cp210x_get_config(port, CP210X_GET_FLOW, modem_ctl, 16); - dbg("%s - read modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x", - __func__, modem_ctl[0], modem_ctl[1], - modem_ctl[2], modem_ctl[3]); - - if (cflag & CRTSCTS) { - modem_ctl[0] &= ~0x7B; - modem_ctl[0] |= 0x09; - modem_ctl[1] = 0x80; - dbg("%s - flow control = CRTSCTS", __func__); - } else { - modem_ctl[0] &= ~0x7B; - modem_ctl[0] |= 0x01; - modem_ctl[1] |= 0x40; - dbg("%s - flow control = NONE", __func__); - } - - dbg("%s - write modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x", - __func__, modem_ctl[0], modem_ctl[1], - modem_ctl[2], modem_ctl[3]); - cp210x_set_config(port, CP210X_SET_FLOW, modem_ctl, 16); - } - -} - -static int cp210x_tiocmset (struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - return cp210x_tiocmset_port(port, set, clear); -} - -static int cp210x_tiocmset_port(struct usb_serial_port *port, - unsigned int set, unsigned int clear) -{ - unsigned int control = 0; - - dbg("%s - port %d", __func__, port->number); - - if (set & TIOCM_RTS) { - control |= CONTROL_RTS; - control |= CONTROL_WRITE_RTS; - } - if (set & TIOCM_DTR) { - control |= CONTROL_DTR; - control |= CONTROL_WRITE_DTR; - } - if (clear & TIOCM_RTS) { - control &= ~CONTROL_RTS; - control |= CONTROL_WRITE_RTS; - } - if (clear & TIOCM_DTR) { - control &= ~CONTROL_DTR; - control |= CONTROL_WRITE_DTR; - } - - dbg("%s - control = 0x%.4x", __func__, control); - - return cp210x_set_config(port, CP210X_SET_MHS, &control, 2); -} - -static void cp210x_dtr_rts(struct usb_serial_port *p, int on) -{ - if (on) - cp210x_tiocmset_port(p, TIOCM_DTR|TIOCM_RTS, 0); - else - cp210x_tiocmset_port(p, 0, TIOCM_DTR|TIOCM_RTS); -} - -static int cp210x_tiocmget (struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - unsigned int control; - int result; - - dbg("%s - port %d", __func__, port->number); - - cp210x_get_config(port, CP210X_GET_MDMSTS, &control, 1); - - result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0) - |((control & CONTROL_RTS) ? TIOCM_RTS : 0) - |((control & CONTROL_CTS) ? TIOCM_CTS : 0) - |((control & CONTROL_DSR) ? TIOCM_DSR : 0) - |((control & CONTROL_RING)? TIOCM_RI : 0) - |((control & CONTROL_DCD) ? TIOCM_CD : 0); - - dbg("%s - control = 0x%.2x", __func__, control); - - return result; -} - -static void cp210x_break_ctl (struct tty_struct *tty, int break_state) -{ - struct usb_serial_port *port = tty->driver_data; - unsigned int state; - - dbg("%s - port %d", __func__, port->number); - if (break_state == 0) - state = BREAK_OFF; - else - state = BREAK_ON; - dbg("%s - turning break %s", __func__, - state == BREAK_OFF ? "off" : "on"); - cp210x_set_config(port, CP210X_SET_BREAK, &state, 2); -} - -static int cp210x_startup(struct usb_serial *serial) -{ - struct cp210x_port_private *port_priv; - int i; - - /* cp210x buffers behave strangely unless device is reset */ - usb_reset_device(serial->dev); - - for (i = 0; i < serial->num_ports; i++) { - port_priv = kzalloc(sizeof(*port_priv), GFP_KERNEL); - if (!port_priv) - return -ENOMEM; - - memset(port_priv, 0x00, sizeof(*port_priv)); - port_priv->bInterfaceNumber = - serial->interface->cur_altsetting->desc.bInterfaceNumber; - - usb_set_serial_port_data(serial->port[i], port_priv); - } - - return 0; -} - -static void cp210x_release(struct usb_serial *serial) -{ - struct cp210x_port_private *port_priv; - int i; - - for (i = 0; i < serial->num_ports; i++) { - port_priv = usb_get_serial_port_data(serial->port[i]); - kfree(port_priv); - usb_set_serial_port_data(serial->port[i], NULL); - } -} - -module_usb_serial_driver(cp210x_driver, serial_drivers); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable verbose debugging messages"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/cyberjack.c b/ANDROID_3.4.5/drivers/usb/serial/cyberjack.c deleted file mode 100644 index d39b9418..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/cyberjack.c +++ /dev/null @@ -1,486 +0,0 @@ -/* - * REINER SCT cyberJack pinpad/e-com USB Chipcard Reader Driver - * - * Copyright (C) 2001 REINER SCT - * Author: Matthias Bruestle - * - * Contact: support@reiner-sct.com (see MAINTAINERS) - * - * This program is largely derived from work by the linux-usb group - * and associated source files. Please see the usb/serial files for - * individual credits and copyrights. - * - * 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. - * - * Thanks to Greg Kroah-Hartman (greg@kroah.com) for his help and - * patience. - * - * In case of problems, please write to the contact e-mail address - * mentioned above. - * - * Please note that later models of the cyberjack reader family are - * supported by a libusb-based userspace device driver. - * - * Homepage: http://www.reiner-sct.de/support/treiber_cyberjack.php#linux - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define CYBERJACK_LOCAL_BUF_SIZE 32 - -static bool debug; - -/* - * Version Information - */ -#define DRIVER_VERSION "v1.01" -#define DRIVER_AUTHOR "Matthias Bruestle" -#define DRIVER_DESC "REINER SCT cyberJack pinpad/e-com USB Chipcard Reader Driver" - - -#define CYBERJACK_VENDOR_ID 0x0C4B -#define CYBERJACK_PRODUCT_ID 0x0100 - -/* Function prototypes */ -static int cyberjack_startup(struct usb_serial *serial); -static void cyberjack_disconnect(struct usb_serial *serial); -static void cyberjack_release(struct usb_serial *serial); -static int cyberjack_open(struct tty_struct *tty, - struct usb_serial_port *port); -static void cyberjack_close(struct usb_serial_port *port); -static int cyberjack_write(struct tty_struct *tty, - struct usb_serial_port *port, const unsigned char *buf, int count); -static int cyberjack_write_room(struct tty_struct *tty); -static void cyberjack_read_int_callback(struct urb *urb); -static void cyberjack_read_bulk_callback(struct urb *urb); -static void cyberjack_write_bulk_callback(struct urb *urb); - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(CYBERJACK_VENDOR_ID, CYBERJACK_PRODUCT_ID) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver cyberjack_driver = { - .name = "cyberjack", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - -static struct usb_serial_driver cyberjack_device = { - .driver = { - .owner = THIS_MODULE, - .name = "cyberjack", - }, - .description = "Reiner SCT Cyberjack USB card reader", - .id_table = id_table, - .num_ports = 1, - .attach = cyberjack_startup, - .disconnect = cyberjack_disconnect, - .release = cyberjack_release, - .open = cyberjack_open, - .close = cyberjack_close, - .write = cyberjack_write, - .write_room = cyberjack_write_room, - .read_int_callback = cyberjack_read_int_callback, - .read_bulk_callback = cyberjack_read_bulk_callback, - .write_bulk_callback = cyberjack_write_bulk_callback, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &cyberjack_device, NULL -}; - -struct cyberjack_private { - spinlock_t lock; /* Lock for SMP */ - short rdtodo; /* Bytes still to read */ - unsigned char wrbuf[5*64]; /* Buffer for collecting data to write */ - short wrfilled; /* Overall data size we already got */ - short wrsent; /* Data already sent */ -}; - -/* do some startup allocations not currently performed by usb_serial_probe() */ -static int cyberjack_startup(struct usb_serial *serial) -{ - struct cyberjack_private *priv; - int i; - - dbg("%s", __func__); - - /* allocate the private data structure */ - priv = kmalloc(sizeof(struct cyberjack_private), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - /* set initial values */ - spin_lock_init(&priv->lock); - priv->rdtodo = 0; - priv->wrfilled = 0; - priv->wrsent = 0; - usb_set_serial_port_data(serial->port[0], priv); - - init_waitqueue_head(&serial->port[0]->write_wait); - - for (i = 0; i < serial->num_ports; ++i) { - int result; - result = usb_submit_urb(serial->port[i]->interrupt_in_urb, - GFP_KERNEL); - if (result) - dev_err(&serial->dev->dev, - "usb_submit_urb(read int) failed\n"); - dbg("%s - usb_submit_urb(int urb)", __func__); - } - - return 0; -} - -static void cyberjack_disconnect(struct usb_serial *serial) -{ - int i; - - dbg("%s", __func__); - - for (i = 0; i < serial->num_ports; ++i) - usb_kill_urb(serial->port[i]->interrupt_in_urb); -} - -static void cyberjack_release(struct usb_serial *serial) -{ - int i; - - dbg("%s", __func__); - - for (i = 0; i < serial->num_ports; ++i) { - /* My special items, the standard routines free my urbs */ - kfree(usb_get_serial_port_data(serial->port[i])); - } -} - -static int cyberjack_open(struct tty_struct *tty, - struct usb_serial_port *port) -{ - struct cyberjack_private *priv; - unsigned long flags; - int result = 0; - - dbg("%s - port %d", __func__, port->number); - - dbg("%s - usb_clear_halt", __func__); - usb_clear_halt(port->serial->dev, port->write_urb->pipe); - - priv = usb_get_serial_port_data(port); - spin_lock_irqsave(&priv->lock, flags); - priv->rdtodo = 0; - priv->wrfilled = 0; - priv->wrsent = 0; - spin_unlock_irqrestore(&priv->lock, flags); - - return result; -} - -static void cyberjack_close(struct usb_serial_port *port) -{ - dbg("%s - port %d", __func__, port->number); - - if (port->serial->dev) { - /* shutdown any bulk reads that might be going on */ - usb_kill_urb(port->write_urb); - usb_kill_urb(port->read_urb); - } -} - -static int cyberjack_write(struct tty_struct *tty, - struct usb_serial_port *port, const unsigned char *buf, int count) -{ - struct cyberjack_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - int result; - int wrexpected; - - dbg("%s - port %d", __func__, port->number); - - if (count == 0) { - dbg("%s - write request of 0 bytes", __func__); - return 0; - } - - if (!test_and_clear_bit(0, &port->write_urbs_free)) { - dbg("%s - already writing", __func__); - return 0; - } - - spin_lock_irqsave(&priv->lock, flags); - - if (count+priv->wrfilled > sizeof(priv->wrbuf)) { - /* To much data for buffer. Reset buffer. */ - priv->wrfilled = 0; - spin_unlock_irqrestore(&priv->lock, flags); - set_bit(0, &port->write_urbs_free); - return 0; - } - - /* Copy data */ - memcpy(priv->wrbuf + priv->wrfilled, buf, count); - - usb_serial_debug_data(debug, &port->dev, __func__, count, - priv->wrbuf + priv->wrfilled); - priv->wrfilled += count; - - if (priv->wrfilled >= 3) { - wrexpected = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3; - dbg("%s - expected data: %d", __func__, wrexpected); - } else - wrexpected = sizeof(priv->wrbuf); - - if (priv->wrfilled >= wrexpected) { - /* We have enough data to begin transmission */ - int length; - - dbg("%s - transmitting data (frame 1)", __func__); - length = (wrexpected > port->bulk_out_size) ? - port->bulk_out_size : wrexpected; - - memcpy(port->write_urb->transfer_buffer, priv->wrbuf, length); - priv->wrsent = length; - - /* set up our urb */ - port->write_urb->transfer_buffer_length = length; - - /* send the data out the bulk port */ - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (result) { - dev_err(&port->dev, - "%s - failed submitting write urb, error %d", - __func__, result); - /* Throw away data. No better idea what to do with it. */ - priv->wrfilled = 0; - priv->wrsent = 0; - spin_unlock_irqrestore(&priv->lock, flags); - set_bit(0, &port->write_urbs_free); - return 0; - } - - dbg("%s - priv->wrsent=%d", __func__, priv->wrsent); - dbg("%s - priv->wrfilled=%d", __func__, priv->wrfilled); - - if (priv->wrsent >= priv->wrfilled) { - dbg("%s - buffer cleaned", __func__); - memset(priv->wrbuf, 0, sizeof(priv->wrbuf)); - priv->wrfilled = 0; - priv->wrsent = 0; - } - } - - spin_unlock_irqrestore(&priv->lock, flags); - - return count; -} - -static int cyberjack_write_room(struct tty_struct *tty) -{ - /* FIXME: .... */ - return CYBERJACK_LOCAL_BUF_SIZE; -} - -static void cyberjack_read_int_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct cyberjack_private *priv = usb_get_serial_port_data(port); - unsigned char *data = urb->transfer_buffer; - int status = urb->status; - int result; - - dbg("%s - port %d", __func__, port->number); - - /* the urb might have been killed. */ - if (status) - return; - - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); - - /* React only to interrupts signaling a bulk_in transfer */ - if (urb->actual_length == 4 && data[0] == 0x01) { - short old_rdtodo; - - /* This is a announcement of coming bulk_ins. */ - unsigned short size = ((unsigned short)data[3]<<8)+data[2]+3; - - spin_lock(&priv->lock); - - old_rdtodo = priv->rdtodo; - - if (old_rdtodo + size < old_rdtodo) { - dbg("To many bulk_in urbs to do."); - spin_unlock(&priv->lock); - goto resubmit; - } - - /* "+=" is probably more fault tollerant than "=" */ - priv->rdtodo += size; - - dbg("%s - rdtodo: %d", __func__, priv->rdtodo); - - spin_unlock(&priv->lock); - - if (!old_rdtodo) { - result = usb_submit_urb(port->read_urb, GFP_ATOMIC); - if (result) - dev_err(&port->dev, "%s - failed resubmitting " - "read urb, error %d\n", - __func__, result); - dbg("%s - usb_submit_urb(read urb)", __func__); - } - } - -resubmit: - result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); - if (result) - dev_err(&port->dev, "usb_submit_urb(read int) failed\n"); - dbg("%s - usb_submit_urb(int urb)", __func__); -} - -static void cyberjack_read_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct cyberjack_private *priv = usb_get_serial_port_data(port); - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - short todo; - int result; - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); - if (status) { - dbg("%s - nonzero read bulk status received: %d", - __func__, status); - return; - } - - tty = tty_port_tty_get(&port->port); - if (!tty) { - dbg("%s - ignoring since device not open", __func__); - return; - } - if (urb->actual_length) { - tty_insert_flip_string(tty, data, urb->actual_length); - tty_flip_buffer_push(tty); - } - tty_kref_put(tty); - - spin_lock(&priv->lock); - - /* Reduce urbs to do by one. */ - priv->rdtodo -= urb->actual_length; - /* Just to be sure */ - if (priv->rdtodo < 0) - priv->rdtodo = 0; - todo = priv->rdtodo; - - spin_unlock(&priv->lock); - - dbg("%s - rdtodo: %d", __func__, todo); - - /* Continue to read if we have still urbs to do. */ - if (todo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/) { - result = usb_submit_urb(port->read_urb, GFP_ATOMIC); - if (result) - dev_err(&port->dev, "%s - failed resubmitting read " - "urb, error %d\n", __func__, result); - dbg("%s - usb_submit_urb(read urb)", __func__); - } -} - -static void cyberjack_write_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct cyberjack_private *priv = usb_get_serial_port_data(port); - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - - set_bit(0, &port->write_urbs_free); - if (status) { - dbg("%s - nonzero write bulk status received: %d", - __func__, status); - return; - } - - spin_lock(&priv->lock); - - /* only do something if we have more data to send */ - if (priv->wrfilled) { - int length, blksize, result; - - dbg("%s - transmitting data (frame n)", __func__); - - length = ((priv->wrfilled - priv->wrsent) > port->bulk_out_size) ? - port->bulk_out_size : (priv->wrfilled - priv->wrsent); - - memcpy(port->write_urb->transfer_buffer, - priv->wrbuf + priv->wrsent, length); - priv->wrsent += length; - - /* set up our urb */ - port->write_urb->transfer_buffer_length = length; - - /* send the data out the bulk port */ - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (result) { - dev_err(&port->dev, - "%s - failed submitting write urb, error %d\n", - __func__, result); - /* Throw away data. No better idea what to do with it. */ - priv->wrfilled = 0; - priv->wrsent = 0; - goto exit; - } - - dbg("%s - priv->wrsent=%d", __func__, priv->wrsent); - dbg("%s - priv->wrfilled=%d", __func__, priv->wrfilled); - - blksize = ((int)priv->wrbuf[2]<<8)+priv->wrbuf[1]+3; - - if (priv->wrsent >= priv->wrfilled || - priv->wrsent >= blksize) { - dbg("%s - buffer cleaned", __func__); - memset(priv->wrbuf, 0, sizeof(priv->wrbuf)); - priv->wrfilled = 0; - priv->wrsent = 0; - } - } - -exit: - spin_unlock(&priv->lock); - usb_serial_port_softint(port); -} - -module_usb_serial_driver(cyberjack_driver, serial_drivers); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/cypress_m8.c b/ANDROID_3.4.5/drivers/usb/serial/cypress_m8.c deleted file mode 100644 index afc886c7..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/cypress_m8.c +++ /dev/null @@ -1,1363 +0,0 @@ -/* - * USB Cypress M8 driver - * - * Copyright (C) 2004 - * Lonnie Mendez (dignome@gmail.com) - * Copyright (C) 2003,2004 - * Neil Whelchel (koyama@firstlight.net) - * - * 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. - * - * See Documentation/usb/usb-serial.txt for more information on using this - * driver - * - * See http://geocities.com/i0xox0i for information on this driver and the - * earthmate usb device. - */ - -/* Thanks to Neil Whelchel for writing the first cypress m8 implementation - for linux. */ -/* Thanks to cypress for providing references for the hid reports. */ -/* Thanks to Jiang Zhang for providing links and for general help. */ -/* Code originates and was built up from ftdi_sio, belkin, pl2303 and others.*/ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cypress_m8.h" - - -static bool debug; -static bool stats; -static int interval; -static bool unstable_bauds; - -/* - * Version Information - */ -#define DRIVER_VERSION "v1.10" -#define DRIVER_AUTHOR "Lonnie Mendez , Neil Whelchel " -#define DRIVER_DESC "Cypress USB to Serial Driver" - -/* write buffer size defines */ -#define CYPRESS_BUF_SIZE 1024 - -static const struct usb_device_id id_table_earthmate[] = { - { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) }, - { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) }, - { } /* Terminating entry */ -}; - -static const struct usb_device_id id_table_cyphidcomrs232[] = { - { USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) }, - { USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) }, - { } /* Terminating entry */ -}; - -static const struct usb_device_id id_table_nokiaca42v2[] = { - { USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) }, - { } /* Terminating entry */ -}; - -static const struct usb_device_id id_table_combined[] = { - { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) }, - { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) }, - { USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) }, - { USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) }, - { USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, id_table_combined); - -static struct usb_driver cypress_driver = { - .name = "cypress", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; - -enum packet_format { - packet_format_1, /* b0:status, b1:payload count */ - packet_format_2 /* b0[7:3]:status, b0[2:0]:payload count */ -}; - -struct cypress_private { - spinlock_t lock; /* private lock */ - int chiptype; /* identifier of device, for quirks/etc */ - int bytes_in; /* used for statistics */ - int bytes_out; /* used for statistics */ - int cmd_count; /* used for statistics */ - int cmd_ctrl; /* always set this to 1 before issuing a command */ - struct kfifo write_fifo; /* write fifo */ - int write_urb_in_use; /* write urb in use indicator */ - int write_urb_interval; /* interval to use for write urb */ - int read_urb_interval; /* interval to use for read urb */ - int comm_is_ok; /* true if communication is (still) ok */ - int termios_initialized; - __u8 line_control; /* holds dtr / rts value */ - __u8 current_status; /* received from last read - info on dsr,cts,cd,ri,etc */ - __u8 current_config; /* stores the current configuration byte */ - __u8 rx_flags; /* throttling - used from whiteheat/ftdi_sio */ - enum packet_format pkt_fmt; /* format to use for packet send / receive */ - int get_cfg_unsafe; /* If true, the CYPRESS_GET_CONFIG is unsafe */ - int baud_rate; /* stores current baud rate in - integer form */ - int isthrottled; /* if throttled, discard reads */ - wait_queue_head_t delta_msr_wait; /* used for TIOCMIWAIT */ - char prev_status, diff_status; /* used for TIOCMIWAIT */ - /* we pass a pointer to this as the argument sent to - cypress_set_termios old_termios */ - struct ktermios tmp_termios; /* stores the old termios settings */ -}; - -/* function prototypes for the Cypress USB to serial device */ -static int cypress_earthmate_startup(struct usb_serial *serial); -static int cypress_hidcom_startup(struct usb_serial *serial); -static int cypress_ca42v2_startup(struct usb_serial *serial); -static void cypress_release(struct usb_serial *serial); -static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port); -static void cypress_close(struct usb_serial_port *port); -static void cypress_dtr_rts(struct usb_serial_port *port, int on); -static int cypress_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count); -static void cypress_send(struct usb_serial_port *port); -static int cypress_write_room(struct tty_struct *tty); -static int cypress_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); -static void cypress_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old); -static int cypress_tiocmget(struct tty_struct *tty); -static int cypress_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear); -static int cypress_chars_in_buffer(struct tty_struct *tty); -static void cypress_throttle(struct tty_struct *tty); -static void cypress_unthrottle(struct tty_struct *tty); -static void cypress_set_dead(struct usb_serial_port *port); -static void cypress_read_int_callback(struct urb *urb); -static void cypress_write_int_callback(struct urb *urb); - -static struct usb_serial_driver cypress_earthmate_device = { - .driver = { - .owner = THIS_MODULE, - .name = "earthmate", - }, - .description = "DeLorme Earthmate USB", - .id_table = id_table_earthmate, - .num_ports = 1, - .attach = cypress_earthmate_startup, - .release = cypress_release, - .open = cypress_open, - .close = cypress_close, - .dtr_rts = cypress_dtr_rts, - .write = cypress_write, - .write_room = cypress_write_room, - .ioctl = cypress_ioctl, - .set_termios = cypress_set_termios, - .tiocmget = cypress_tiocmget, - .tiocmset = cypress_tiocmset, - .chars_in_buffer = cypress_chars_in_buffer, - .throttle = cypress_throttle, - .unthrottle = cypress_unthrottle, - .read_int_callback = cypress_read_int_callback, - .write_int_callback = cypress_write_int_callback, -}; - -static struct usb_serial_driver cypress_hidcom_device = { - .driver = { - .owner = THIS_MODULE, - .name = "cyphidcom", - }, - .description = "HID->COM RS232 Adapter", - .id_table = id_table_cyphidcomrs232, - .num_ports = 1, - .attach = cypress_hidcom_startup, - .release = cypress_release, - .open = cypress_open, - .close = cypress_close, - .dtr_rts = cypress_dtr_rts, - .write = cypress_write, - .write_room = cypress_write_room, - .ioctl = cypress_ioctl, - .set_termios = cypress_set_termios, - .tiocmget = cypress_tiocmget, - .tiocmset = cypress_tiocmset, - .chars_in_buffer = cypress_chars_in_buffer, - .throttle = cypress_throttle, - .unthrottle = cypress_unthrottle, - .read_int_callback = cypress_read_int_callback, - .write_int_callback = cypress_write_int_callback, -}; - -static struct usb_serial_driver cypress_ca42v2_device = { - .driver = { - .owner = THIS_MODULE, - .name = "nokiaca42v2", - }, - .description = "Nokia CA-42 V2 Adapter", - .id_table = id_table_nokiaca42v2, - .num_ports = 1, - .attach = cypress_ca42v2_startup, - .release = cypress_release, - .open = cypress_open, - .close = cypress_close, - .dtr_rts = cypress_dtr_rts, - .write = cypress_write, - .write_room = cypress_write_room, - .ioctl = cypress_ioctl, - .set_termios = cypress_set_termios, - .tiocmget = cypress_tiocmget, - .tiocmset = cypress_tiocmset, - .chars_in_buffer = cypress_chars_in_buffer, - .throttle = cypress_throttle, - .unthrottle = cypress_unthrottle, - .read_int_callback = cypress_read_int_callback, - .write_int_callback = cypress_write_int_callback, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &cypress_earthmate_device, &cypress_hidcom_device, - &cypress_ca42v2_device, NULL -}; - -/***************************************************************************** - * Cypress serial helper functions - *****************************************************************************/ - - -static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate) -{ - struct cypress_private *priv; - priv = usb_get_serial_port_data(port); - - if (unstable_bauds) - return new_rate; - - /* - * The general purpose firmware for the Cypress M8 allows for - * a maximum speed of 57600bps (I have no idea whether DeLorme - * chose to use the general purpose firmware or not), if you - * need to modify this speed setting for your own project - * please add your own chiptype and modify the code likewise. - * The Cypress HID->COM device will work successfully up to - * 115200bps (but the actual throughput is around 3kBps). - */ - if (port->serial->dev->speed == USB_SPEED_LOW) { - /* - * Mike Isely 2-Feb-2008: The - * Cypress app note that describes this mechanism - * states the the low-speed part can't handle more - * than 800 bytes/sec, in which case 4800 baud is the - * safest speed for a part like that. - */ - if (new_rate > 4800) { - dbg("%s - failed setting baud rate, device incapable " - "speed %d", __func__, new_rate); - return -1; - } - } - switch (priv->chiptype) { - case CT_EARTHMATE: - if (new_rate <= 600) { - /* 300 and 600 baud rates are supported under - * the generic firmware, but are not used with - * NMEA and SiRF protocols */ - dbg("%s - failed setting baud rate, unsupported speed " - "of %d on Earthmate GPS", __func__, new_rate); - return -1; - } - break; - default: - break; - } - return new_rate; -} - - -/* This function can either set or retrieve the current serial line settings */ -static int cypress_serial_control(struct tty_struct *tty, - struct usb_serial_port *port, speed_t baud_rate, int data_bits, - int stop_bits, int parity_enable, int parity_type, int reset, - int cypress_request_type) -{ - int new_baudrate = 0, retval = 0, tries = 0; - struct cypress_private *priv; - u8 *feature_buffer; - const unsigned int feature_len = 5; - unsigned long flags; - - dbg("%s", __func__); - - priv = usb_get_serial_port_data(port); - - if (!priv->comm_is_ok) - return -ENODEV; - - feature_buffer = kcalloc(feature_len, sizeof(u8), GFP_KERNEL); - if (!feature_buffer) - return -ENOMEM; - - switch (cypress_request_type) { - case CYPRESS_SET_CONFIG: - /* 0 means 'Hang up' so doesn't change the true bit rate */ - new_baudrate = priv->baud_rate; - if (baud_rate && baud_rate != priv->baud_rate) { - dbg("%s - baud rate is changing", __func__); - retval = analyze_baud_rate(port, baud_rate); - if (retval >= 0) { - new_baudrate = retval; - dbg("%s - New baud rate set to %d", - __func__, new_baudrate); - } - } - dbg("%s - baud rate is being sent as %d", - __func__, new_baudrate); - - /* fill the feature_buffer with new configuration */ - put_unaligned_le32(new_baudrate, feature_buffer); - feature_buffer[4] |= data_bits; /* assign data bits in 2 bit space ( max 3 ) */ - /* 1 bit gap */ - feature_buffer[4] |= (stop_bits << 3); /* assign stop bits in 1 bit space */ - feature_buffer[4] |= (parity_enable << 4); /* assign parity flag in 1 bit space */ - feature_buffer[4] |= (parity_type << 5); /* assign parity type in 1 bit space */ - /* 1 bit gap */ - feature_buffer[4] |= (reset << 7); /* assign reset at end of byte, 1 bit space */ - - dbg("%s - device is being sent this feature report:", - __func__); - dbg("%s - %02X - %02X - %02X - %02X - %02X", __func__, - feature_buffer[0], feature_buffer[1], - feature_buffer[2], feature_buffer[3], - feature_buffer[4]); - - do { - retval = usb_control_msg(port->serial->dev, - usb_sndctrlpipe(port->serial->dev, 0), - HID_REQ_SET_REPORT, - USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS, - 0x0300, 0, feature_buffer, - feature_len, 500); - - if (tries++ >= 3) - break; - - } while (retval != feature_len && - retval != -ENODEV); - - if (retval != feature_len) { - dev_err(&port->dev, "%s - failed sending serial " - "line settings - %d\n", __func__, retval); - cypress_set_dead(port); - } else { - spin_lock_irqsave(&priv->lock, flags); - priv->baud_rate = new_baudrate; - priv->current_config = feature_buffer[4]; - spin_unlock_irqrestore(&priv->lock, flags); - /* If we asked for a speed change encode it */ - if (baud_rate) - tty_encode_baud_rate(tty, - new_baudrate, new_baudrate); - } - break; - case CYPRESS_GET_CONFIG: - if (priv->get_cfg_unsafe) { - /* Not implemented for this device, - and if we try to do it we're likely - to crash the hardware. */ - retval = -ENOTTY; - goto out; - } - dbg("%s - retreiving serial line settings", __func__); - do { - retval = usb_control_msg(port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0), - HID_REQ_GET_REPORT, - USB_DIR_IN | USB_RECIP_INTERFACE | USB_TYPE_CLASS, - 0x0300, 0, feature_buffer, - feature_len, 500); - - if (tries++ >= 3) - break; - } while (retval != feature_len - && retval != -ENODEV); - - if (retval != feature_len) { - dev_err(&port->dev, "%s - failed to retrieve serial " - "line settings - %d\n", __func__, retval); - cypress_set_dead(port); - goto out; - } else { - spin_lock_irqsave(&priv->lock, flags); - /* store the config in one byte, and later - use bit masks to check values */ - priv->current_config = feature_buffer[4]; - priv->baud_rate = get_unaligned_le32(feature_buffer); - spin_unlock_irqrestore(&priv->lock, flags); - } - } - spin_lock_irqsave(&priv->lock, flags); - ++priv->cmd_count; - spin_unlock_irqrestore(&priv->lock, flags); -out: - kfree(feature_buffer); - return retval; -} /* cypress_serial_control */ - - -static void cypress_set_dead(struct usb_serial_port *port) -{ - struct cypress_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - if (!priv->comm_is_ok) { - spin_unlock_irqrestore(&priv->lock, flags); - return; - } - priv->comm_is_ok = 0; - spin_unlock_irqrestore(&priv->lock, flags); - - dev_err(&port->dev, "cypress_m8 suspending failing port %d - " - "interval might be too short\n", port->number); -} - - -/***************************************************************************** - * Cypress serial driver functions - *****************************************************************************/ - - -static int generic_startup(struct usb_serial *serial) -{ - struct cypress_private *priv; - struct usb_serial_port *port = serial->port[0]; - - dbg("%s - port %d", __func__, port->number); - - priv = kzalloc(sizeof(struct cypress_private), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->comm_is_ok = !0; - spin_lock_init(&priv->lock); - if (kfifo_alloc(&priv->write_fifo, CYPRESS_BUF_SIZE, GFP_KERNEL)) { - kfree(priv); - return -ENOMEM; - } - init_waitqueue_head(&priv->delta_msr_wait); - - usb_reset_configuration(serial->dev); - - priv->cmd_ctrl = 0; - priv->line_control = 0; - priv->termios_initialized = 0; - priv->rx_flags = 0; - /* Default packet format setting is determined by packet size. - Anything with a size larger then 9 must have a separate - count field since the 3 bit count field is otherwise too - small. Otherwise we can use the slightly more compact - format. This is in accordance with the cypress_m8 serial - converter app note. */ - if (port->interrupt_out_size > 9) - priv->pkt_fmt = packet_format_1; - else - priv->pkt_fmt = packet_format_2; - - if (interval > 0) { - priv->write_urb_interval = interval; - priv->read_urb_interval = interval; - dbg("%s - port %d read & write intervals forced to %d", - __func__, port->number, interval); - } else { - priv->write_urb_interval = port->interrupt_out_urb->interval; - priv->read_urb_interval = port->interrupt_in_urb->interval; - dbg("%s - port %d intervals: read=%d write=%d", - __func__, port->number, - priv->read_urb_interval, priv->write_urb_interval); - } - usb_set_serial_port_data(port, priv); - - return 0; -} - - -static int cypress_earthmate_startup(struct usb_serial *serial) -{ - struct cypress_private *priv; - struct usb_serial_port *port = serial->port[0]; - - dbg("%s", __func__); - - if (generic_startup(serial)) { - dbg("%s - Failed setting up port %d", __func__, - port->number); - return 1; - } - - priv = usb_get_serial_port_data(port); - priv->chiptype = CT_EARTHMATE; - /* All Earthmate devices use the separated-count packet - format! Idiotic. */ - priv->pkt_fmt = packet_format_1; - if (serial->dev->descriptor.idProduct != - cpu_to_le16(PRODUCT_ID_EARTHMATEUSB)) { - /* The old original USB Earthmate seemed able to - handle GET_CONFIG requests; everything they've - produced since that time crashes if this command is - attempted :-( */ - dbg("%s - Marking this device as unsafe for GET_CONFIG " - "commands", __func__); - priv->get_cfg_unsafe = !0; - } - - return 0; -} /* cypress_earthmate_startup */ - - -static int cypress_hidcom_startup(struct usb_serial *serial) -{ - struct cypress_private *priv; - - dbg("%s", __func__); - - if (generic_startup(serial)) { - dbg("%s - Failed setting up port %d", __func__, - serial->port[0]->number); - return 1; - } - - priv = usb_get_serial_port_data(serial->port[0]); - priv->chiptype = CT_CYPHIDCOM; - - return 0; -} /* cypress_hidcom_startup */ - - -static int cypress_ca42v2_startup(struct usb_serial *serial) -{ - struct cypress_private *priv; - - dbg("%s", __func__); - - if (generic_startup(serial)) { - dbg("%s - Failed setting up port %d", __func__, - serial->port[0]->number); - return 1; - } - - priv = usb_get_serial_port_data(serial->port[0]); - priv->chiptype = CT_CA42V2; - - return 0; -} /* cypress_ca42v2_startup */ - - -static void cypress_release(struct usb_serial *serial) -{ - struct cypress_private *priv; - - dbg("%s - port %d", __func__, serial->port[0]->number); - - /* all open ports are closed at this point */ - - priv = usb_get_serial_port_data(serial->port[0]); - - if (priv) { - kfifo_free(&priv->write_fifo); - kfree(priv); - } -} - - -static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct cypress_private *priv = usb_get_serial_port_data(port); - struct usb_serial *serial = port->serial; - unsigned long flags; - int result = 0; - - dbg("%s - port %d", __func__, port->number); - - if (!priv->comm_is_ok) - return -EIO; - - /* clear halts before open */ - usb_clear_halt(serial->dev, 0x81); - usb_clear_halt(serial->dev, 0x02); - - spin_lock_irqsave(&priv->lock, flags); - /* reset read/write statistics */ - priv->bytes_in = 0; - priv->bytes_out = 0; - priv->cmd_count = 0; - priv->rx_flags = 0; - spin_unlock_irqrestore(&priv->lock, flags); - - /* Set termios */ - cypress_send(port); - - if (tty) - cypress_set_termios(tty, port, &priv->tmp_termios); - - /* setup the port and start reading from the device */ - if (!port->interrupt_in_urb) { - dev_err(&port->dev, "%s - interrupt_in_urb is empty!\n", - __func__); - return -1; - } - - usb_fill_int_urb(port->interrupt_in_urb, serial->dev, - usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress), - port->interrupt_in_urb->transfer_buffer, - port->interrupt_in_urb->transfer_buffer_length, - cypress_read_int_callback, port, priv->read_urb_interval); - result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - - if (result) { - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", - __func__, result); - cypress_set_dead(port); - } - port->port.drain_delay = 256; - return result; -} /* cypress_open */ - -static void cypress_dtr_rts(struct usb_serial_port *port, int on) -{ - struct cypress_private *priv = usb_get_serial_port_data(port); - /* drop dtr and rts */ - spin_lock_irq(&priv->lock); - if (on == 0) - priv->line_control = 0; - else - priv->line_control = CONTROL_DTR | CONTROL_RTS; - priv->cmd_ctrl = 1; - spin_unlock_irq(&priv->lock); - cypress_write(NULL, port, NULL, 0); -} - -static void cypress_close(struct usb_serial_port *port) -{ - struct cypress_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - /* writing is potentially harmful, lock must be taken */ - mutex_lock(&port->serial->disc_mutex); - if (port->serial->disconnected) { - mutex_unlock(&port->serial->disc_mutex); - return; - } - spin_lock_irqsave(&priv->lock, flags); - kfifo_reset_out(&priv->write_fifo); - spin_unlock_irqrestore(&priv->lock, flags); - - dbg("%s - stopping urbs", __func__); - usb_kill_urb(port->interrupt_in_urb); - usb_kill_urb(port->interrupt_out_urb); - - if (stats) - dev_info(&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n", - priv->bytes_in, priv->bytes_out, priv->cmd_count); - mutex_unlock(&port->serial->disc_mutex); -} /* cypress_close */ - - -static int cypress_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - struct cypress_private *priv = usb_get_serial_port_data(port); - - dbg("%s - port %d, %d bytes", __func__, port->number, count); - - /* line control commands, which need to be executed immediately, - are not put into the buffer for obvious reasons. - */ - if (priv->cmd_ctrl) { - count = 0; - goto finish; - } - - if (!count) - return count; - - count = kfifo_in_locked(&priv->write_fifo, buf, count, &priv->lock); - -finish: - cypress_send(port); - - return count; -} /* cypress_write */ - - -static void cypress_send(struct usb_serial_port *port) -{ - int count = 0, result, offset, actual_size; - struct cypress_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - - if (!priv->comm_is_ok) - return; - - dbg("%s - port %d", __func__, port->number); - dbg("%s - interrupt out size is %d", __func__, - port->interrupt_out_size); - - spin_lock_irqsave(&priv->lock, flags); - if (priv->write_urb_in_use) { - dbg("%s - can't write, urb in use", __func__); - spin_unlock_irqrestore(&priv->lock, flags); - return; - } - spin_unlock_irqrestore(&priv->lock, flags); - - /* clear buffer */ - memset(port->interrupt_out_urb->transfer_buffer, 0, - port->interrupt_out_size); - - spin_lock_irqsave(&priv->lock, flags); - switch (priv->pkt_fmt) { - default: - case packet_format_1: - /* this is for the CY7C64013... */ - offset = 2; - port->interrupt_out_buffer[0] = priv->line_control; - break; - case packet_format_2: - /* this is for the CY7C63743... */ - offset = 1; - port->interrupt_out_buffer[0] = priv->line_control; - break; - } - - if (priv->line_control & CONTROL_RESET) - priv->line_control &= ~CONTROL_RESET; - - if (priv->cmd_ctrl) { - priv->cmd_count++; - dbg("%s - line control command being issued", __func__); - spin_unlock_irqrestore(&priv->lock, flags); - goto send; - } else - spin_unlock_irqrestore(&priv->lock, flags); - - count = kfifo_out_locked(&priv->write_fifo, - &port->interrupt_out_buffer[offset], - port->interrupt_out_size - offset, - &priv->lock); - if (count == 0) - return; - - switch (priv->pkt_fmt) { - default: - case packet_format_1: - port->interrupt_out_buffer[1] = count; - break; - case packet_format_2: - port->interrupt_out_buffer[0] |= count; - } - - dbg("%s - count is %d", __func__, count); - -send: - spin_lock_irqsave(&priv->lock, flags); - priv->write_urb_in_use = 1; - spin_unlock_irqrestore(&priv->lock, flags); - - if (priv->cmd_ctrl) - actual_size = 1; - else - actual_size = count + - (priv->pkt_fmt == packet_format_1 ? 2 : 1); - - usb_serial_debug_data(debug, &port->dev, __func__, - port->interrupt_out_size, - port->interrupt_out_urb->transfer_buffer); - - usb_fill_int_urb(port->interrupt_out_urb, port->serial->dev, - usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress), - port->interrupt_out_buffer, port->interrupt_out_size, - cypress_write_int_callback, port, priv->write_urb_interval); - result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC); - if (result) { - dev_err_console(port, - "%s - failed submitting write urb, error %d\n", - __func__, result); - priv->write_urb_in_use = 0; - cypress_set_dead(port); - } - - spin_lock_irqsave(&priv->lock, flags); - if (priv->cmd_ctrl) - priv->cmd_ctrl = 0; - - /* do not count the line control and size bytes */ - priv->bytes_out += count; - spin_unlock_irqrestore(&priv->lock, flags); - - usb_serial_port_softint(port); -} /* cypress_send */ - - -/* returns how much space is available in the soft buffer */ -static int cypress_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct cypress_private *priv = usb_get_serial_port_data(port); - int room = 0; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&priv->lock, flags); - room = kfifo_avail(&priv->write_fifo); - spin_unlock_irqrestore(&priv->lock, flags); - - dbg("%s - returns %d", __func__, room); - return room; -} - - -static int cypress_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct cypress_private *priv = usb_get_serial_port_data(port); - __u8 status, control; - unsigned int result = 0; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&priv->lock, flags); - control = priv->line_control; - status = priv->current_status; - spin_unlock_irqrestore(&priv->lock, flags); - - result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0) - | ((control & CONTROL_RTS) ? TIOCM_RTS : 0) - | ((status & UART_CTS) ? TIOCM_CTS : 0) - | ((status & UART_DSR) ? TIOCM_DSR : 0) - | ((status & UART_RI) ? TIOCM_RI : 0) - | ((status & UART_CD) ? TIOCM_CD : 0); - - dbg("%s - result = %x", __func__, result); - - return result; -} - - -static int cypress_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct cypress_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&priv->lock, flags); - if (set & TIOCM_RTS) - priv->line_control |= CONTROL_RTS; - if (set & TIOCM_DTR) - priv->line_control |= CONTROL_DTR; - if (clear & TIOCM_RTS) - priv->line_control &= ~CONTROL_RTS; - if (clear & TIOCM_DTR) - priv->line_control &= ~CONTROL_DTR; - priv->cmd_ctrl = 1; - spin_unlock_irqrestore(&priv->lock, flags); - - return cypress_write(tty, port, NULL, 0); -} - - -static int cypress_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - struct cypress_private *priv = usb_get_serial_port_data(port); - - dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd); - - switch (cmd) { - /* This code comes from drivers/char/serial.c and ftdi_sio.c */ - case TIOCMIWAIT: - while (priv != NULL) { - interruptible_sleep_on(&priv->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - else { - char diff = priv->diff_status; - if (diff == 0) - return -EIO; /* no change => error */ - - /* consume all events */ - priv->diff_status = 0; - - /* return 0 if caller wanted to know about - these bits */ - if (((arg & TIOCM_RNG) && (diff & UART_RI)) || - ((arg & TIOCM_DSR) && (diff & UART_DSR)) || - ((arg & TIOCM_CD) && (diff & UART_CD)) || - ((arg & TIOCM_CTS) && (diff & UART_CTS))) - return 0; - /* otherwise caller can't care less about what - * happened, and so we continue to wait for - * more events. - */ - } - } - return 0; - default: - break; - } - dbg("%s - arg not supported - it was 0x%04x - check include/asm/ioctls.h", __func__, cmd); - return -ENOIOCTLCMD; -} /* cypress_ioctl */ - - -static void cypress_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) -{ - struct cypress_private *priv = usb_get_serial_port_data(port); - int data_bits, stop_bits, parity_type, parity_enable; - unsigned cflag, iflag; - unsigned long flags; - __u8 oldlines; - int linechange = 0; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&priv->lock, flags); - /* We can't clean this one up as we don't know the device type - early enough */ - if (!priv->termios_initialized) { - if (priv->chiptype == CT_EARTHMATE) { - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = B4800 | CS8 | CREAD | HUPCL | - CLOCAL; - tty->termios->c_ispeed = 4800; - tty->termios->c_ospeed = 4800; - } else if (priv->chiptype == CT_CYPHIDCOM) { - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | - CLOCAL; - tty->termios->c_ispeed = 9600; - tty->termios->c_ospeed = 9600; - } else if (priv->chiptype == CT_CA42V2) { - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | - CLOCAL; - tty->termios->c_ispeed = 9600; - tty->termios->c_ospeed = 9600; - } - priv->termios_initialized = 1; - } - spin_unlock_irqrestore(&priv->lock, flags); - - /* Unsupported features need clearing */ - tty->termios->c_cflag &= ~(CMSPAR|CRTSCTS); - - cflag = tty->termios->c_cflag; - iflag = tty->termios->c_iflag; - - /* check if there are new settings */ - if (old_termios) { - spin_lock_irqsave(&priv->lock, flags); - priv->tmp_termios = *(tty->termios); - spin_unlock_irqrestore(&priv->lock, flags); - } - - /* set number of data bits, parity, stop bits */ - /* when parity is disabled the parity type bit is ignored */ - - /* 1 means 2 stop bits, 0 means 1 stop bit */ - stop_bits = cflag & CSTOPB ? 1 : 0; - - if (cflag & PARENB) { - parity_enable = 1; - /* 1 means odd parity, 0 means even parity */ - parity_type = cflag & PARODD ? 1 : 0; - } else - parity_enable = parity_type = 0; - - switch (cflag & CSIZE) { - case CS5: - data_bits = 0; - break; - case CS6: - data_bits = 1; - break; - case CS7: - data_bits = 2; - break; - case CS8: - data_bits = 3; - break; - default: - dev_err(&port->dev, "%s - CSIZE was set, but not CS5-CS8\n", - __func__); - data_bits = 3; - } - spin_lock_irqsave(&priv->lock, flags); - oldlines = priv->line_control; - if ((cflag & CBAUD) == B0) { - /* drop dtr and rts */ - dbg("%s - dropping the lines, baud rate 0bps", __func__); - priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); - } else - priv->line_control = (CONTROL_DTR | CONTROL_RTS); - spin_unlock_irqrestore(&priv->lock, flags); - - dbg("%s - sending %d stop_bits, %d parity_enable, %d parity_type, " - "%d data_bits (+5)", __func__, stop_bits, - parity_enable, parity_type, data_bits); - - cypress_serial_control(tty, port, tty_get_baud_rate(tty), - data_bits, stop_bits, - parity_enable, parity_type, - 0, CYPRESS_SET_CONFIG); - - /* we perform a CYPRESS_GET_CONFIG so that the current settings are - * filled into the private structure this should confirm that all is - * working if it returns what we just set */ - cypress_serial_control(tty, port, 0, 0, 0, 0, 0, 0, CYPRESS_GET_CONFIG); - - /* Here we can define custom tty settings for devices; the main tty - * termios flag base comes from empeg.c */ - - spin_lock_irqsave(&priv->lock, flags); - if (priv->chiptype == CT_EARTHMATE && priv->baud_rate == 4800) { - dbg("Using custom termios settings for a baud rate of " - "4800bps."); - /* define custom termios settings for NMEA protocol */ - - tty->termios->c_iflag /* input modes - */ - &= ~(IGNBRK /* disable ignore break */ - | BRKINT /* disable break causes interrupt */ - | PARMRK /* disable mark parity errors */ - | ISTRIP /* disable clear high bit of input char */ - | INLCR /* disable translate NL to CR */ - | IGNCR /* disable ignore CR */ - | ICRNL /* disable translate CR to NL */ - | IXON); /* disable enable XON/XOFF flow control */ - - tty->termios->c_oflag /* output modes */ - &= ~OPOST; /* disable postprocess output char */ - - tty->termios->c_lflag /* line discipline modes */ - &= ~(ECHO /* disable echo input characters */ - | ECHONL /* disable echo new line */ - | ICANON /* disable erase, kill, werase, and rprnt - special characters */ - | ISIG /* disable interrupt, quit, and suspend - special characters */ - | IEXTEN); /* disable non-POSIX special characters */ - } /* CT_CYPHIDCOM: Application should handle this for device */ - - linechange = (priv->line_control != oldlines); - spin_unlock_irqrestore(&priv->lock, flags); - - /* if necessary, set lines */ - if (linechange) { - priv->cmd_ctrl = 1; - cypress_write(tty, port, NULL, 0); - } -} /* cypress_set_termios */ - - -/* returns amount of data still left in soft buffer */ -static int cypress_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct cypress_private *priv = usb_get_serial_port_data(port); - int chars = 0; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&priv->lock, flags); - chars = kfifo_len(&priv->write_fifo); - spin_unlock_irqrestore(&priv->lock, flags); - - dbg("%s - returns %d", __func__, chars); - return chars; -} - - -static void cypress_throttle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct cypress_private *priv = usb_get_serial_port_data(port); - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irq(&priv->lock); - priv->rx_flags = THROTTLED; - spin_unlock_irq(&priv->lock); -} - - -static void cypress_unthrottle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct cypress_private *priv = usb_get_serial_port_data(port); - int actually_throttled, result; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irq(&priv->lock); - actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED; - priv->rx_flags = 0; - spin_unlock_irq(&priv->lock); - - if (!priv->comm_is_ok) - return; - - if (actually_throttled) { - result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - if (result) { - dev_err(&port->dev, "%s - failed submitting read urb, " - "error %d\n", __func__, result); - cypress_set_dead(port); - } - } -} - - -static void cypress_read_int_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct cypress_private *priv = usb_get_serial_port_data(port); - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - unsigned long flags; - char tty_flag = TTY_NORMAL; - int havedata = 0; - int bytes = 0; - int result; - int i = 0; - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - - switch (status) { - case 0: /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* precursor to disconnect so just go away */ - return; - case -EPIPE: - /* Can't call usb_clear_halt while in_interrupt */ - /* FALLS THROUGH */ - default: - /* something ugly is going on... */ - dev_err(&urb->dev->dev, - "%s - unexpected nonzero read status received: %d\n", - __func__, status); - cypress_set_dead(port); - return; - } - - spin_lock_irqsave(&priv->lock, flags); - if (priv->rx_flags & THROTTLED) { - dbg("%s - now throttling", __func__); - priv->rx_flags |= ACTUALLY_THROTTLED; - spin_unlock_irqrestore(&priv->lock, flags); - return; - } - spin_unlock_irqrestore(&priv->lock, flags); - - tty = tty_port_tty_get(&port->port); - if (!tty) { - dbg("%s - bad tty pointer - exiting", __func__); - return; - } - - spin_lock_irqsave(&priv->lock, flags); - result = urb->actual_length; - switch (priv->pkt_fmt) { - default: - case packet_format_1: - /* This is for the CY7C64013... */ - priv->current_status = data[0] & 0xF8; - bytes = data[1] + 2; - i = 2; - if (bytes > 2) - havedata = 1; - break; - case packet_format_2: - /* This is for the CY7C63743... */ - priv->current_status = data[0] & 0xF8; - bytes = (data[0] & 0x07) + 1; - i = 1; - if (bytes > 1) - havedata = 1; - break; - } - spin_unlock_irqrestore(&priv->lock, flags); - if (result < bytes) { - dbg("%s - wrong packet size - received %d bytes but packet " - "said %d bytes", __func__, result, bytes); - goto continue_read; - } - - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); - - spin_lock_irqsave(&priv->lock, flags); - /* check to see if status has changed */ - if (priv->current_status != priv->prev_status) { - priv->diff_status |= priv->current_status ^ - priv->prev_status; - wake_up_interruptible(&priv->delta_msr_wait); - priv->prev_status = priv->current_status; - } - spin_unlock_irqrestore(&priv->lock, flags); - - /* hangup, as defined in acm.c... this might be a bad place for it - * though */ - if (tty && !(tty->termios->c_cflag & CLOCAL) && - !(priv->current_status & UART_CD)) { - dbg("%s - calling hangup", __func__); - tty_hangup(tty); - goto continue_read; - } - - /* There is one error bit... I'm assuming it is a parity error - * indicator as the generic firmware will set this bit to 1 if a - * parity error occurs. - * I can not find reference to any other error events. */ - spin_lock_irqsave(&priv->lock, flags); - if (priv->current_status & CYP_ERROR) { - spin_unlock_irqrestore(&priv->lock, flags); - tty_flag = TTY_PARITY; - dbg("%s - Parity Error detected", __func__); - } else - spin_unlock_irqrestore(&priv->lock, flags); - - /* process read if there is data other than line status */ - if (tty && bytes > i) { - tty_insert_flip_string_fixed_flag(tty, data + i, - tty_flag, bytes - i); - tty_flip_buffer_push(tty); - } - - spin_lock_irqsave(&priv->lock, flags); - /* control and status byte(s) are also counted */ - priv->bytes_in += bytes; - spin_unlock_irqrestore(&priv->lock, flags); - -continue_read: - tty_kref_put(tty); - - /* Continue trying to always read */ - - if (priv->comm_is_ok) { - usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev, - usb_rcvintpipe(port->serial->dev, - port->interrupt_in_endpointAddress), - port->interrupt_in_urb->transfer_buffer, - port->interrupt_in_urb->transfer_buffer_length, - cypress_read_int_callback, port, - priv->read_urb_interval); - result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); - if (result && result != -EPERM) { - dev_err(&urb->dev->dev, "%s - failed resubmitting " - "read urb, error %d\n", __func__, - result); - cypress_set_dead(port); - } - } -} /* cypress_read_int_callback */ - - -static void cypress_write_int_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct cypress_private *priv = usb_get_serial_port_data(port); - int result; - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); - priv->write_urb_in_use = 0; - return; - case -EPIPE: /* no break needed; clear halt and resubmit */ - if (!priv->comm_is_ok) - break; - usb_clear_halt(port->serial->dev, 0x02); - /* error in the urb, so we have to resubmit it */ - dbg("%s - nonzero write bulk status received: %d", - __func__, status); - port->interrupt_out_urb->transfer_buffer_length = 1; - result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC); - if (!result) - return; - dev_err(&urb->dev->dev, - "%s - failed resubmitting write urb, error %d\n", - __func__, result); - cypress_set_dead(port); - break; - default: - dev_err(&urb->dev->dev, - "%s - unexpected nonzero write status received: %d\n", - __func__, status); - cypress_set_dead(port); - break; - } - priv->write_urb_in_use = 0; - - /* send any buffered data */ - cypress_send(port); -} - -module_usb_serial_driver(cypress_driver, serial_drivers); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); -module_param(stats, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(stats, "Enable statistics or not"); -module_param(interval, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(interval, "Overrides interrupt interval"); -module_param(unstable_bauds, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(unstable_bauds, "Allow unstable baud rates"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/cypress_m8.h b/ANDROID_3.4.5/drivers/usb/serial/cypress_m8.h deleted file mode 100644 index 67cf6082..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/cypress_m8.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef CYPRESS_M8_H -#define CYPRESS_M8_H - -/* - * definitions and function prototypes used for the cypress USB to Serial - * controller - */ - -/* - * For sending our feature buffer - controlling serial communication states. - * Linux HID has no support for serial devices so we do this through the driver - */ -#define HID_REQ_GET_REPORT 0x01 -#define HID_REQ_SET_REPORT 0x09 - -/* List other cypress USB to Serial devices here, and add them to the id_table */ - -/* DeLorme Earthmate USB - a GPS device */ -#define VENDOR_ID_DELORME 0x1163 -#define PRODUCT_ID_EARTHMATEUSB 0x0100 -#define PRODUCT_ID_EARTHMATEUSB_LT20 0x0200 - -/* Cypress HID->COM RS232 Adapter */ -#define VENDOR_ID_CYPRESS 0x04b4 -#define PRODUCT_ID_CYPHIDCOM 0x5500 - -/* Powercom UPS, chip CY7C63723 */ -#define VENDOR_ID_POWERCOM 0x0d9f -#define PRODUCT_ID_UPS 0x0002 - -/* Nokia CA-42 USB to serial cable */ -#define VENDOR_ID_DAZZLE 0x07d0 -#define PRODUCT_ID_CA42 0x4101 -/* End of device listing */ - -/* Used for setting / requesting serial line settings */ -#define CYPRESS_SET_CONFIG 0x01 -#define CYPRESS_GET_CONFIG 0x02 - -/* Used for throttle control */ -#define THROTTLED 0x1 -#define ACTUALLY_THROTTLED 0x2 - -/* - * chiptypes - used in case firmware differs from the generic form ... offering - * different baud speeds/etc. - */ -#define CT_EARTHMATE 0x01 -#define CT_CYPHIDCOM 0x02 -#define CT_CA42V2 0x03 -#define CT_GENERIC 0x0F -/* End of chiptype definitions */ - -/* RS-232 serial data communication protocol definitions */ -/* these are sent / read at byte 0 of the input/output hid reports */ -/* You can find these values defined in the CY4601 USB to Serial design notes */ - -#define CONTROL_DTR 0x20 /* data terminal ready - flow control - host to device */ -#define UART_DSR 0x20 /* data set ready - flow control - device to host */ -#define CONTROL_RTS 0x10 /* request to send - flow control - host to device */ -#define UART_CTS 0x10 /* clear to send - flow control - device to host */ -#define UART_RI 0x10 /* ring indicator - modem - device to host */ -#define UART_CD 0x40 /* carrier detect - modem - device to host */ -#define CYP_ERROR 0x08 /* received from input report - device to host */ -/* Note - the below has nothing to do with the "feature report" reset */ -#define CONTROL_RESET 0x08 /* sent with output report - host to device */ - -/* End of RS-232 protocol definitions */ - -#endif /* CYPRESS_M8_H */ diff --git a/ANDROID_3.4.5/drivers/usb/serial/digi_acceleport.c b/ANDROID_3.4.5/drivers/usb/serial/digi_acceleport.c deleted file mode 100644 index 999f91bf..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/digi_acceleport.c +++ /dev/null @@ -1,1590 +0,0 @@ -/* -* Digi AccelePort USB-4 and USB-2 Serial Converters -* -* Copyright 2000 by Digi International -* -* 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. -* -* Shamelessly based on Brian Warner's keyspan_pda.c and Greg Kroah-Hartman's -* usb-serial driver. -* -* Peter Berger (pberger@brimson.com) -* Al Borchers (borchers@steinerpoint.com) -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Defines */ - -/* - * Version Information - */ -#define DRIVER_VERSION "v1.80.1.2" -#define DRIVER_AUTHOR "Peter Berger , Al Borchers " -#define DRIVER_DESC "Digi AccelePort USB-2/USB-4 Serial Converter driver" - -/* port output buffer length -- must be <= transfer buffer length - 2 */ -/* so we can be sure to send the full buffer in one urb */ -#define DIGI_OUT_BUF_SIZE 8 - -/* port input buffer length -- must be >= transfer buffer length - 3 */ -/* so we can be sure to hold at least one full buffer from one urb */ -#define DIGI_IN_BUF_SIZE 64 - -/* retry timeout while sleeping */ -#define DIGI_RETRY_TIMEOUT (HZ/10) - -/* timeout while waiting for tty output to drain in close */ -/* this delay is used twice in close, so the total delay could */ -/* be twice this value */ -#define DIGI_CLOSE_TIMEOUT (5*HZ) - - -/* AccelePort USB Defines */ - -/* ids */ -#define DIGI_VENDOR_ID 0x05c5 -#define DIGI_2_ID 0x0002 /* USB-2 */ -#define DIGI_4_ID 0x0004 /* USB-4 */ - -/* commands - * "INB": can be used on the in-band endpoint - * "OOB": can be used on the out-of-band endpoint - */ -#define DIGI_CMD_SET_BAUD_RATE 0 /* INB, OOB */ -#define DIGI_CMD_SET_WORD_SIZE 1 /* INB, OOB */ -#define DIGI_CMD_SET_PARITY 2 /* INB, OOB */ -#define DIGI_CMD_SET_STOP_BITS 3 /* INB, OOB */ -#define DIGI_CMD_SET_INPUT_FLOW_CONTROL 4 /* INB, OOB */ -#define DIGI_CMD_SET_OUTPUT_FLOW_CONTROL 5 /* INB, OOB */ -#define DIGI_CMD_SET_DTR_SIGNAL 6 /* INB, OOB */ -#define DIGI_CMD_SET_RTS_SIGNAL 7 /* INB, OOB */ -#define DIGI_CMD_READ_INPUT_SIGNALS 8 /* OOB */ -#define DIGI_CMD_IFLUSH_FIFO 9 /* OOB */ -#define DIGI_CMD_RECEIVE_ENABLE 10 /* INB, OOB */ -#define DIGI_CMD_BREAK_CONTROL 11 /* INB, OOB */ -#define DIGI_CMD_LOCAL_LOOPBACK 12 /* INB, OOB */ -#define DIGI_CMD_TRANSMIT_IDLE 13 /* INB, OOB */ -#define DIGI_CMD_READ_UART_REGISTER 14 /* OOB */ -#define DIGI_CMD_WRITE_UART_REGISTER 15 /* INB, OOB */ -#define DIGI_CMD_AND_UART_REGISTER 16 /* INB, OOB */ -#define DIGI_CMD_OR_UART_REGISTER 17 /* INB, OOB */ -#define DIGI_CMD_SEND_DATA 18 /* INB */ -#define DIGI_CMD_RECEIVE_DATA 19 /* INB */ -#define DIGI_CMD_RECEIVE_DISABLE 20 /* INB */ -#define DIGI_CMD_GET_PORT_TYPE 21 /* OOB */ - -/* baud rates */ -#define DIGI_BAUD_50 0 -#define DIGI_BAUD_75 1 -#define DIGI_BAUD_110 2 -#define DIGI_BAUD_150 3 -#define DIGI_BAUD_200 4 -#define DIGI_BAUD_300 5 -#define DIGI_BAUD_600 6 -#define DIGI_BAUD_1200 7 -#define DIGI_BAUD_1800 8 -#define DIGI_BAUD_2400 9 -#define DIGI_BAUD_4800 10 -#define DIGI_BAUD_7200 11 -#define DIGI_BAUD_9600 12 -#define DIGI_BAUD_14400 13 -#define DIGI_BAUD_19200 14 -#define DIGI_BAUD_28800 15 -#define DIGI_BAUD_38400 16 -#define DIGI_BAUD_57600 17 -#define DIGI_BAUD_76800 18 -#define DIGI_BAUD_115200 19 -#define DIGI_BAUD_153600 20 -#define DIGI_BAUD_230400 21 -#define DIGI_BAUD_460800 22 - -/* arguments */ -#define DIGI_WORD_SIZE_5 0 -#define DIGI_WORD_SIZE_6 1 -#define DIGI_WORD_SIZE_7 2 -#define DIGI_WORD_SIZE_8 3 - -#define DIGI_PARITY_NONE 0 -#define DIGI_PARITY_ODD 1 -#define DIGI_PARITY_EVEN 2 -#define DIGI_PARITY_MARK 3 -#define DIGI_PARITY_SPACE 4 - -#define DIGI_STOP_BITS_1 0 -#define DIGI_STOP_BITS_2 1 - -#define DIGI_INPUT_FLOW_CONTROL_XON_XOFF 1 -#define DIGI_INPUT_FLOW_CONTROL_RTS 2 -#define DIGI_INPUT_FLOW_CONTROL_DTR 4 - -#define DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF 1 -#define DIGI_OUTPUT_FLOW_CONTROL_CTS 2 -#define DIGI_OUTPUT_FLOW_CONTROL_DSR 4 - -#define DIGI_DTR_INACTIVE 0 -#define DIGI_DTR_ACTIVE 1 -#define DIGI_DTR_INPUT_FLOW_CONTROL 2 - -#define DIGI_RTS_INACTIVE 0 -#define DIGI_RTS_ACTIVE 1 -#define DIGI_RTS_INPUT_FLOW_CONTROL 2 -#define DIGI_RTS_TOGGLE 3 - -#define DIGI_FLUSH_TX 1 -#define DIGI_FLUSH_RX 2 -#define DIGI_RESUME_TX 4 /* clears xoff condition */ - -#define DIGI_TRANSMIT_NOT_IDLE 0 -#define DIGI_TRANSMIT_IDLE 1 - -#define DIGI_DISABLE 0 -#define DIGI_ENABLE 1 - -#define DIGI_DEASSERT 0 -#define DIGI_ASSERT 1 - -/* in band status codes */ -#define DIGI_OVERRUN_ERROR 4 -#define DIGI_PARITY_ERROR 8 -#define DIGI_FRAMING_ERROR 16 -#define DIGI_BREAK_ERROR 32 - -/* out of band status */ -#define DIGI_NO_ERROR 0 -#define DIGI_BAD_FIRST_PARAMETER 1 -#define DIGI_BAD_SECOND_PARAMETER 2 -#define DIGI_INVALID_LINE 3 -#define DIGI_INVALID_OPCODE 4 - -/* input signals */ -#define DIGI_READ_INPUT_SIGNALS_SLOT 1 -#define DIGI_READ_INPUT_SIGNALS_ERR 2 -#define DIGI_READ_INPUT_SIGNALS_BUSY 4 -#define DIGI_READ_INPUT_SIGNALS_PE 8 -#define DIGI_READ_INPUT_SIGNALS_CTS 16 -#define DIGI_READ_INPUT_SIGNALS_DSR 32 -#define DIGI_READ_INPUT_SIGNALS_RI 64 -#define DIGI_READ_INPUT_SIGNALS_DCD 128 - - -/* Structures */ - -struct digi_serial { - spinlock_t ds_serial_lock; - struct usb_serial_port *ds_oob_port; /* out-of-band port */ - int ds_oob_port_num; /* index of out-of-band port */ - int ds_device_started; -}; - -struct digi_port { - spinlock_t dp_port_lock; - int dp_port_num; - int dp_out_buf_len; - unsigned char dp_out_buf[DIGI_OUT_BUF_SIZE]; - int dp_write_urb_in_use; - unsigned int dp_modem_signals; - wait_queue_head_t dp_modem_change_wait; - int dp_transmit_idle; - wait_queue_head_t dp_transmit_idle_wait; - int dp_throttled; - int dp_throttle_restart; - wait_queue_head_t dp_flush_wait; - wait_queue_head_t dp_close_wait; /* wait queue for close */ - struct work_struct dp_wakeup_work; - struct usb_serial_port *dp_port; -}; - - -/* Local Function Declarations */ - -static void digi_wakeup_write(struct usb_serial_port *port); -static void digi_wakeup_write_lock(struct work_struct *work); -static int digi_write_oob_command(struct usb_serial_port *port, - unsigned char *buf, int count, int interruptible); -static int digi_write_inb_command(struct usb_serial_port *port, - unsigned char *buf, int count, unsigned long timeout); -static int digi_set_modem_signals(struct usb_serial_port *port, - unsigned int modem_signals, int interruptible); -static int digi_transmit_idle(struct usb_serial_port *port, - unsigned long timeout); -static void digi_rx_throttle(struct tty_struct *tty); -static void digi_rx_unthrottle(struct tty_struct *tty); -static void digi_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios); -static void digi_break_ctl(struct tty_struct *tty, int break_state); -static int digi_tiocmget(struct tty_struct *tty); -static int digi_tiocmset(struct tty_struct *tty, unsigned int set, - unsigned int clear); -static int digi_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count); -static void digi_write_bulk_callback(struct urb *urb); -static int digi_write_room(struct tty_struct *tty); -static int digi_chars_in_buffer(struct tty_struct *tty); -static int digi_open(struct tty_struct *tty, struct usb_serial_port *port); -static void digi_close(struct usb_serial_port *port); -static void digi_dtr_rts(struct usb_serial_port *port, int on); -static int digi_startup_device(struct usb_serial *serial); -static int digi_startup(struct usb_serial *serial); -static void digi_disconnect(struct usb_serial *serial); -static void digi_release(struct usb_serial *serial); -static void digi_read_bulk_callback(struct urb *urb); -static int digi_read_inb_callback(struct urb *urb); -static int digi_read_oob_callback(struct urb *urb); - - -/* Statics */ - -static bool debug; - -static const struct usb_device_id id_table_combined[] = { - { USB_DEVICE(DIGI_VENDOR_ID, DIGI_2_ID) }, - { USB_DEVICE(DIGI_VENDOR_ID, DIGI_4_ID) }, - { } /* Terminating entry */ -}; - -static const struct usb_device_id id_table_2[] = { - { USB_DEVICE(DIGI_VENDOR_ID, DIGI_2_ID) }, - { } /* Terminating entry */ -}; - -static const struct usb_device_id id_table_4[] = { - { USB_DEVICE(DIGI_VENDOR_ID, DIGI_4_ID) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, id_table_combined); - -static struct usb_driver digi_driver = { - .name = "digi_acceleport", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; - - -/* device info needed for the Digi serial converter */ - -static struct usb_serial_driver digi_acceleport_2_device = { - .driver = { - .owner = THIS_MODULE, - .name = "digi_2", - }, - .description = "Digi 2 port USB adapter", - .id_table = id_table_2, - .num_ports = 3, - .open = digi_open, - .close = digi_close, - .dtr_rts = digi_dtr_rts, - .write = digi_write, - .write_room = digi_write_room, - .write_bulk_callback = digi_write_bulk_callback, - .read_bulk_callback = digi_read_bulk_callback, - .chars_in_buffer = digi_chars_in_buffer, - .throttle = digi_rx_throttle, - .unthrottle = digi_rx_unthrottle, - .set_termios = digi_set_termios, - .break_ctl = digi_break_ctl, - .tiocmget = digi_tiocmget, - .tiocmset = digi_tiocmset, - .attach = digi_startup, - .disconnect = digi_disconnect, - .release = digi_release, -}; - -static struct usb_serial_driver digi_acceleport_4_device = { - .driver = { - .owner = THIS_MODULE, - .name = "digi_4", - }, - .description = "Digi 4 port USB adapter", - .id_table = id_table_4, - .num_ports = 4, - .open = digi_open, - .close = digi_close, - .write = digi_write, - .write_room = digi_write_room, - .write_bulk_callback = digi_write_bulk_callback, - .read_bulk_callback = digi_read_bulk_callback, - .chars_in_buffer = digi_chars_in_buffer, - .throttle = digi_rx_throttle, - .unthrottle = digi_rx_unthrottle, - .set_termios = digi_set_termios, - .break_ctl = digi_break_ctl, - .tiocmget = digi_tiocmget, - .tiocmset = digi_tiocmset, - .attach = digi_startup, - .disconnect = digi_disconnect, - .release = digi_release, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &digi_acceleport_2_device, &digi_acceleport_4_device, NULL -}; - -/* Functions */ - -/* - * Cond Wait Interruptible Timeout Irqrestore - * - * Do spin_unlock_irqrestore and interruptible_sleep_on_timeout - * so that wake ups are not lost if they occur between the unlock - * and the sleep. In other words, spin_unlock_irqrestore and - * interruptible_sleep_on_timeout are "atomic" with respect to - * wake ups. This is used to implement condition variables. - * - * interruptible_sleep_on_timeout is deprecated and has been replaced - * with the equivalent code. - */ - -static long cond_wait_interruptible_timeout_irqrestore( - wait_queue_head_t *q, long timeout, - spinlock_t *lock, unsigned long flags) -__releases(lock) -{ - DEFINE_WAIT(wait); - - prepare_to_wait(q, &wait, TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(lock, flags); - timeout = schedule_timeout(timeout); - finish_wait(q, &wait); - - return timeout; -} - - -/* - * Digi Wakeup Write - * - * Wake up port, line discipline, and tty processes sleeping - * on writes. - */ - -static void digi_wakeup_write_lock(struct work_struct *work) -{ - struct digi_port *priv = - container_of(work, struct digi_port, dp_wakeup_work); - struct usb_serial_port *port = priv->dp_port; - unsigned long flags; - - spin_lock_irqsave(&priv->dp_port_lock, flags); - digi_wakeup_write(port); - spin_unlock_irqrestore(&priv->dp_port_lock, flags); -} - -static void digi_wakeup_write(struct usb_serial_port *port) -{ - struct tty_struct *tty = tty_port_tty_get(&port->port); - if (tty) { - tty_wakeup(tty); - tty_kref_put(tty); - } -} - - -/* - * Digi Write OOB Command - * - * Write commands on the out of band port. Commands are 4 - * bytes each, multiple commands can be sent at once, and - * no command will be split across USB packets. Returns 0 - * if successful, -EINTR if interrupted while sleeping and - * the interruptible flag is true, or a negative error - * returned by usb_submit_urb. - */ - -static int digi_write_oob_command(struct usb_serial_port *port, - unsigned char *buf, int count, int interruptible) -{ - - int ret = 0; - int len; - struct usb_serial_port *oob_port = (struct usb_serial_port *)((struct digi_serial *)(usb_get_serial_data(port->serial)))->ds_oob_port; - struct digi_port *oob_priv = usb_get_serial_port_data(oob_port); - unsigned long flags = 0; - - dbg("digi_write_oob_command: TOP: port=%d, count=%d", oob_priv->dp_port_num, count); - - spin_lock_irqsave(&oob_priv->dp_port_lock, flags); - while (count > 0) { - while (oob_priv->dp_write_urb_in_use) { - cond_wait_interruptible_timeout_irqrestore( - &oob_port->write_wait, DIGI_RETRY_TIMEOUT, - &oob_priv->dp_port_lock, flags); - if (interruptible && signal_pending(current)) - return -EINTR; - spin_lock_irqsave(&oob_priv->dp_port_lock, flags); - } - - /* len must be a multiple of 4, so commands are not split */ - len = min(count, oob_port->bulk_out_size); - if (len > 4) - len &= ~3; - memcpy(oob_port->write_urb->transfer_buffer, buf, len); - oob_port->write_urb->transfer_buffer_length = len; - ret = usb_submit_urb(oob_port->write_urb, GFP_ATOMIC); - if (ret == 0) { - oob_priv->dp_write_urb_in_use = 1; - count -= len; - buf += len; - } - } - spin_unlock_irqrestore(&oob_priv->dp_port_lock, flags); - if (ret) - dev_err(&port->dev, "%s: usb_submit_urb failed, ret=%d\n", - __func__, ret); - return ret; - -} - - -/* - * Digi Write In Band Command - * - * Write commands on the given port. Commands are 4 - * bytes each, multiple commands can be sent at once, and - * no command will be split across USB packets. If timeout - * is non-zero, write in band command will return after - * waiting unsuccessfully for the URB status to clear for - * timeout ticks. Returns 0 if successful, or a negative - * error returned by digi_write. - */ - -static int digi_write_inb_command(struct usb_serial_port *port, - unsigned char *buf, int count, unsigned long timeout) -{ - int ret = 0; - int len; - struct digi_port *priv = usb_get_serial_port_data(port); - unsigned char *data = port->write_urb->transfer_buffer; - unsigned long flags = 0; - - dbg("digi_write_inb_command: TOP: port=%d, count=%d", - priv->dp_port_num, count); - - if (timeout) - timeout += jiffies; - else - timeout = ULONG_MAX; - - spin_lock_irqsave(&priv->dp_port_lock, flags); - while (count > 0 && ret == 0) { - while (priv->dp_write_urb_in_use && - time_before(jiffies, timeout)) { - cond_wait_interruptible_timeout_irqrestore( - &port->write_wait, DIGI_RETRY_TIMEOUT, - &priv->dp_port_lock, flags); - if (signal_pending(current)) - return -EINTR; - spin_lock_irqsave(&priv->dp_port_lock, flags); - } - - /* len must be a multiple of 4 and small enough to */ - /* guarantee the write will send buffered data first, */ - /* so commands are in order with data and not split */ - len = min(count, port->bulk_out_size-2-priv->dp_out_buf_len); - if (len > 4) - len &= ~3; - - /* write any buffered data first */ - if (priv->dp_out_buf_len > 0) { - data[0] = DIGI_CMD_SEND_DATA; - data[1] = priv->dp_out_buf_len; - memcpy(data + 2, priv->dp_out_buf, - priv->dp_out_buf_len); - memcpy(data + 2 + priv->dp_out_buf_len, buf, len); - port->write_urb->transfer_buffer_length - = priv->dp_out_buf_len + 2 + len; - } else { - memcpy(data, buf, len); - port->write_urb->transfer_buffer_length = len; - } - - ret = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (ret == 0) { - priv->dp_write_urb_in_use = 1; - priv->dp_out_buf_len = 0; - count -= len; - buf += len; - } - - } - spin_unlock_irqrestore(&priv->dp_port_lock, flags); - - if (ret) - dev_err(&port->dev, - "%s: usb_submit_urb failed, ret=%d, port=%d\n", - __func__, ret, priv->dp_port_num); - return ret; -} - - -/* - * Digi Set Modem Signals - * - * Sets or clears DTR and RTS on the port, according to the - * modem_signals argument. Use TIOCM_DTR and TIOCM_RTS flags - * for the modem_signals argument. Returns 0 if successful, - * -EINTR if interrupted while sleeping, or a non-zero error - * returned by usb_submit_urb. - */ - -static int digi_set_modem_signals(struct usb_serial_port *port, - unsigned int modem_signals, int interruptible) -{ - - int ret; - struct digi_port *port_priv = usb_get_serial_port_data(port); - struct usb_serial_port *oob_port = (struct usb_serial_port *) ((struct digi_serial *)(usb_get_serial_data(port->serial)))->ds_oob_port; - struct digi_port *oob_priv = usb_get_serial_port_data(oob_port); - unsigned char *data = oob_port->write_urb->transfer_buffer; - unsigned long flags = 0; - - - dbg("digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x", - port_priv->dp_port_num, modem_signals); - - spin_lock_irqsave(&oob_priv->dp_port_lock, flags); - spin_lock(&port_priv->dp_port_lock); - - while (oob_priv->dp_write_urb_in_use) { - spin_unlock(&port_priv->dp_port_lock); - cond_wait_interruptible_timeout_irqrestore( - &oob_port->write_wait, DIGI_RETRY_TIMEOUT, - &oob_priv->dp_port_lock, flags); - if (interruptible && signal_pending(current)) - return -EINTR; - spin_lock_irqsave(&oob_priv->dp_port_lock, flags); - spin_lock(&port_priv->dp_port_lock); - } - data[0] = DIGI_CMD_SET_DTR_SIGNAL; - data[1] = port_priv->dp_port_num; - data[2] = (modem_signals & TIOCM_DTR) ? - DIGI_DTR_ACTIVE : DIGI_DTR_INACTIVE; - data[3] = 0; - data[4] = DIGI_CMD_SET_RTS_SIGNAL; - data[5] = port_priv->dp_port_num; - data[6] = (modem_signals & TIOCM_RTS) ? - DIGI_RTS_ACTIVE : DIGI_RTS_INACTIVE; - data[7] = 0; - - oob_port->write_urb->transfer_buffer_length = 8; - - ret = usb_submit_urb(oob_port->write_urb, GFP_ATOMIC); - if (ret == 0) { - oob_priv->dp_write_urb_in_use = 1; - port_priv->dp_modem_signals = - (port_priv->dp_modem_signals&~(TIOCM_DTR|TIOCM_RTS)) - | (modem_signals&(TIOCM_DTR|TIOCM_RTS)); - } - spin_unlock(&port_priv->dp_port_lock); - spin_unlock_irqrestore(&oob_priv->dp_port_lock, flags); - if (ret) - dev_err(&port->dev, "%s: usb_submit_urb failed, ret=%d\n", - __func__, ret); - return ret; -} - -/* - * Digi Transmit Idle - * - * Digi transmit idle waits, up to timeout ticks, for the transmitter - * to go idle. It returns 0 if successful or a negative error. - * - * There are race conditions here if more than one process is calling - * digi_transmit_idle on the same port at the same time. However, this - * is only called from close, and only one process can be in close on a - * port at a time, so its ok. - */ - -static int digi_transmit_idle(struct usb_serial_port *port, - unsigned long timeout) -{ - int ret; - unsigned char buf[2]; - struct digi_port *priv = usb_get_serial_port_data(port); - unsigned long flags = 0; - - spin_lock_irqsave(&priv->dp_port_lock, flags); - priv->dp_transmit_idle = 0; - spin_unlock_irqrestore(&priv->dp_port_lock, flags); - - buf[0] = DIGI_CMD_TRANSMIT_IDLE; - buf[1] = 0; - - timeout += jiffies; - - ret = digi_write_inb_command(port, buf, 2, timeout - jiffies); - if (ret != 0) - return ret; - - spin_lock_irqsave(&priv->dp_port_lock, flags); - - while (time_before(jiffies, timeout) && !priv->dp_transmit_idle) { - cond_wait_interruptible_timeout_irqrestore( - &priv->dp_transmit_idle_wait, DIGI_RETRY_TIMEOUT, - &priv->dp_port_lock, flags); - if (signal_pending(current)) - return -EINTR; - spin_lock_irqsave(&priv->dp_port_lock, flags); - } - priv->dp_transmit_idle = 0; - spin_unlock_irqrestore(&priv->dp_port_lock, flags); - return 0; - -} - - -static void digi_rx_throttle(struct tty_struct *tty) -{ - unsigned long flags; - struct usb_serial_port *port = tty->driver_data; - struct digi_port *priv = usb_get_serial_port_data(port); - - - dbg("digi_rx_throttle: TOP: port=%d", priv->dp_port_num); - - /* stop receiving characters by not resubmitting the read urb */ - spin_lock_irqsave(&priv->dp_port_lock, flags); - priv->dp_throttled = 1; - priv->dp_throttle_restart = 0; - spin_unlock_irqrestore(&priv->dp_port_lock, flags); -} - - -static void digi_rx_unthrottle(struct tty_struct *tty) -{ - int ret = 0; - unsigned long flags; - struct usb_serial_port *port = tty->driver_data; - struct digi_port *priv = usb_get_serial_port_data(port); - - dbg("digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num); - - spin_lock_irqsave(&priv->dp_port_lock, flags); - - /* restart read chain */ - if (priv->dp_throttle_restart) - ret = usb_submit_urb(port->read_urb, GFP_ATOMIC); - - /* turn throttle off */ - priv->dp_throttled = 0; - priv->dp_throttle_restart = 0; - - spin_unlock_irqrestore(&priv->dp_port_lock, flags); - - if (ret) - dev_err(&port->dev, - "%s: usb_submit_urb failed, ret=%d, port=%d\n", - __func__, ret, priv->dp_port_num); -} - - -static void digi_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) -{ - struct digi_port *priv = usb_get_serial_port_data(port); - unsigned int iflag = tty->termios->c_iflag; - unsigned int cflag = tty->termios->c_cflag; - unsigned int old_iflag = old_termios->c_iflag; - unsigned int old_cflag = old_termios->c_cflag; - unsigned char buf[32]; - unsigned int modem_signals; - int arg, ret; - int i = 0; - speed_t baud; - - dbg("digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, old_cflag=0x%x", priv->dp_port_num, iflag, old_iflag, cflag, old_cflag); - - /* set baud rate */ - baud = tty_get_baud_rate(tty); - if (baud != tty_termios_baud_rate(old_termios)) { - arg = -1; - - /* reassert DTR and (maybe) RTS on transition from B0 */ - if ((old_cflag&CBAUD) == B0) { - /* don't set RTS if using hardware flow control */ - /* and throttling input */ - modem_signals = TIOCM_DTR; - if (!(tty->termios->c_cflag & CRTSCTS) || - !test_bit(TTY_THROTTLED, &tty->flags)) - modem_signals |= TIOCM_RTS; - digi_set_modem_signals(port, modem_signals, 1); - } - switch (baud) { - /* drop DTR and RTS on transition to B0 */ - case 0: digi_set_modem_signals(port, 0, 1); break; - case 50: arg = DIGI_BAUD_50; break; - case 75: arg = DIGI_BAUD_75; break; - case 110: arg = DIGI_BAUD_110; break; - case 150: arg = DIGI_BAUD_150; break; - case 200: arg = DIGI_BAUD_200; break; - case 300: arg = DIGI_BAUD_300; break; - case 600: arg = DIGI_BAUD_600; break; - case 1200: arg = DIGI_BAUD_1200; break; - case 1800: arg = DIGI_BAUD_1800; break; - case 2400: arg = DIGI_BAUD_2400; break; - case 4800: arg = DIGI_BAUD_4800; break; - case 9600: arg = DIGI_BAUD_9600; break; - case 19200: arg = DIGI_BAUD_19200; break; - case 38400: arg = DIGI_BAUD_38400; break; - case 57600: arg = DIGI_BAUD_57600; break; - case 115200: arg = DIGI_BAUD_115200; break; - case 230400: arg = DIGI_BAUD_230400; break; - case 460800: arg = DIGI_BAUD_460800; break; - default: - arg = DIGI_BAUD_9600; - baud = 9600; - break; - } - if (arg != -1) { - buf[i++] = DIGI_CMD_SET_BAUD_RATE; - buf[i++] = priv->dp_port_num; - buf[i++] = arg; - buf[i++] = 0; - } - } - /* set parity */ - tty->termios->c_cflag &= ~CMSPAR; - - if ((cflag&(PARENB|PARODD)) != (old_cflag&(PARENB|PARODD))) { - if (cflag&PARENB) { - if (cflag&PARODD) - arg = DIGI_PARITY_ODD; - else - arg = DIGI_PARITY_EVEN; - } else { - arg = DIGI_PARITY_NONE; - } - buf[i++] = DIGI_CMD_SET_PARITY; - buf[i++] = priv->dp_port_num; - buf[i++] = arg; - buf[i++] = 0; - } - /* set word size */ - if ((cflag&CSIZE) != (old_cflag&CSIZE)) { - arg = -1; - switch (cflag&CSIZE) { - case CS5: arg = DIGI_WORD_SIZE_5; break; - case CS6: arg = DIGI_WORD_SIZE_6; break; - case CS7: arg = DIGI_WORD_SIZE_7; break; - case CS8: arg = DIGI_WORD_SIZE_8; break; - default: - dbg("digi_set_termios: can't handle word size %d", - (cflag&CSIZE)); - break; - } - - if (arg != -1) { - buf[i++] = DIGI_CMD_SET_WORD_SIZE; - buf[i++] = priv->dp_port_num; - buf[i++] = arg; - buf[i++] = 0; - } - - } - - /* set stop bits */ - if ((cflag&CSTOPB) != (old_cflag&CSTOPB)) { - - if ((cflag&CSTOPB)) - arg = DIGI_STOP_BITS_2; - else - arg = DIGI_STOP_BITS_1; - - buf[i++] = DIGI_CMD_SET_STOP_BITS; - buf[i++] = priv->dp_port_num; - buf[i++] = arg; - buf[i++] = 0; - - } - - /* set input flow control */ - if ((iflag&IXOFF) != (old_iflag&IXOFF) - || (cflag&CRTSCTS) != (old_cflag&CRTSCTS)) { - arg = 0; - if (iflag&IXOFF) - arg |= DIGI_INPUT_FLOW_CONTROL_XON_XOFF; - else - arg &= ~DIGI_INPUT_FLOW_CONTROL_XON_XOFF; - - if (cflag&CRTSCTS) { - arg |= DIGI_INPUT_FLOW_CONTROL_RTS; - - /* On USB-4 it is necessary to assert RTS prior */ - /* to selecting RTS input flow control. */ - buf[i++] = DIGI_CMD_SET_RTS_SIGNAL; - buf[i++] = priv->dp_port_num; - buf[i++] = DIGI_RTS_ACTIVE; - buf[i++] = 0; - - } else { - arg &= ~DIGI_INPUT_FLOW_CONTROL_RTS; - } - buf[i++] = DIGI_CMD_SET_INPUT_FLOW_CONTROL; - buf[i++] = priv->dp_port_num; - buf[i++] = arg; - buf[i++] = 0; - } - - /* set output flow control */ - if ((iflag & IXON) != (old_iflag & IXON) - || (cflag & CRTSCTS) != (old_cflag & CRTSCTS)) { - arg = 0; - if (iflag & IXON) - arg |= DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF; - else - arg &= ~DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF; - - if (cflag & CRTSCTS) { - arg |= DIGI_OUTPUT_FLOW_CONTROL_CTS; - } else { - arg &= ~DIGI_OUTPUT_FLOW_CONTROL_CTS; - tty->hw_stopped = 0; - } - - buf[i++] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL; - buf[i++] = priv->dp_port_num; - buf[i++] = arg; - buf[i++] = 0; - } - - /* set receive enable/disable */ - if ((cflag & CREAD) != (old_cflag & CREAD)) { - if (cflag & CREAD) - arg = DIGI_ENABLE; - else - arg = DIGI_DISABLE; - - buf[i++] = DIGI_CMD_RECEIVE_ENABLE; - buf[i++] = priv->dp_port_num; - buf[i++] = arg; - buf[i++] = 0; - } - ret = digi_write_oob_command(port, buf, i, 1); - if (ret != 0) - dbg("digi_set_termios: write oob failed, ret=%d", ret); - tty_encode_baud_rate(tty, baud, baud); -} - - -static void digi_break_ctl(struct tty_struct *tty, int break_state) -{ - struct usb_serial_port *port = tty->driver_data; - unsigned char buf[4]; - - buf[0] = DIGI_CMD_BREAK_CONTROL; - buf[1] = 2; /* length */ - buf[2] = break_state ? 1 : 0; - buf[3] = 0; /* pad */ - digi_write_inb_command(port, buf, 4, 0); -} - - -static int digi_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct digi_port *priv = usb_get_serial_port_data(port); - unsigned int val; - unsigned long flags; - - dbg("%s: TOP: port=%d", __func__, priv->dp_port_num); - - spin_lock_irqsave(&priv->dp_port_lock, flags); - val = priv->dp_modem_signals; - spin_unlock_irqrestore(&priv->dp_port_lock, flags); - return val; -} - - -static int digi_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct digi_port *priv = usb_get_serial_port_data(port); - unsigned int val; - unsigned long flags; - - dbg("%s: TOP: port=%d", __func__, priv->dp_port_num); - - spin_lock_irqsave(&priv->dp_port_lock, flags); - val = (priv->dp_modem_signals & ~clear) | set; - spin_unlock_irqrestore(&priv->dp_port_lock, flags); - return digi_set_modem_signals(port, val, 1); -} - - -static int digi_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - - int ret, data_len, new_len; - struct digi_port *priv = usb_get_serial_port_data(port); - unsigned char *data = port->write_urb->transfer_buffer; - unsigned long flags = 0; - - dbg("digi_write: TOP: port=%d, count=%d, in_interrupt=%ld", - priv->dp_port_num, count, in_interrupt()); - - /* copy user data (which can sleep) before getting spin lock */ - count = min(count, port->bulk_out_size-2); - count = min(64, count); - - /* be sure only one write proceeds at a time */ - /* there are races on the port private buffer */ - spin_lock_irqsave(&priv->dp_port_lock, flags); - - /* wait for urb status clear to submit another urb */ - if (priv->dp_write_urb_in_use) { - /* buffer data if count is 1 (probably put_char) if possible */ - if (count == 1 && priv->dp_out_buf_len < DIGI_OUT_BUF_SIZE) { - priv->dp_out_buf[priv->dp_out_buf_len++] = *buf; - new_len = 1; - } else { - new_len = 0; - } - spin_unlock_irqrestore(&priv->dp_port_lock, flags); - return new_len; - } - - /* allow space for any buffered data and for new data, up to */ - /* transfer buffer size - 2 (for command and length bytes) */ - new_len = min(count, port->bulk_out_size-2-priv->dp_out_buf_len); - data_len = new_len + priv->dp_out_buf_len; - - if (data_len == 0) { - spin_unlock_irqrestore(&priv->dp_port_lock, flags); - return 0; - } - - port->write_urb->transfer_buffer_length = data_len+2; - - *data++ = DIGI_CMD_SEND_DATA; - *data++ = data_len; - - /* copy in buffered data first */ - memcpy(data, priv->dp_out_buf, priv->dp_out_buf_len); - data += priv->dp_out_buf_len; - - /* copy in new data */ - memcpy(data, buf, new_len); - - ret = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (ret == 0) { - priv->dp_write_urb_in_use = 1; - ret = new_len; - priv->dp_out_buf_len = 0; - } - - /* return length of new data written, or error */ - spin_unlock_irqrestore(&priv->dp_port_lock, flags); - if (ret < 0) - dev_err_console(port, - "%s: usb_submit_urb failed, ret=%d, port=%d\n", - __func__, ret, priv->dp_port_num); - dbg("digi_write: returning %d", ret); - return ret; - -} - -static void digi_write_bulk_callback(struct urb *urb) -{ - - struct usb_serial_port *port = urb->context; - struct usb_serial *serial; - struct digi_port *priv; - struct digi_serial *serial_priv; - int ret = 0; - int status = urb->status; - - dbg("digi_write_bulk_callback: TOP, status=%d", status); - - /* port and serial sanity check */ - if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) { - pr_err("%s: port or port->private is NULL, status=%d\n", - __func__, status); - return; - } - serial = port->serial; - if (serial == NULL || (serial_priv = usb_get_serial_data(serial)) == NULL) { - dev_err(&port->dev, - "%s: serial or serial->private is NULL, status=%d\n", - __func__, status); - return; - } - - /* handle oob callback */ - if (priv->dp_port_num == serial_priv->ds_oob_port_num) { - dbg("digi_write_bulk_callback: oob callback"); - spin_lock(&priv->dp_port_lock); - priv->dp_write_urb_in_use = 0; - wake_up_interruptible(&port->write_wait); - spin_unlock(&priv->dp_port_lock); - return; - } - - /* try to send any buffered data on this port */ - spin_lock(&priv->dp_port_lock); - priv->dp_write_urb_in_use = 0; - if (priv->dp_out_buf_len > 0) { - *((unsigned char *)(port->write_urb->transfer_buffer)) - = (unsigned char)DIGI_CMD_SEND_DATA; - *((unsigned char *)(port->write_urb->transfer_buffer) + 1) - = (unsigned char)priv->dp_out_buf_len; - port->write_urb->transfer_buffer_length = - priv->dp_out_buf_len + 2; - memcpy(port->write_urb->transfer_buffer + 2, priv->dp_out_buf, - priv->dp_out_buf_len); - ret = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (ret == 0) { - priv->dp_write_urb_in_use = 1; - priv->dp_out_buf_len = 0; - } - } - /* wake up processes sleeping on writes immediately */ - digi_wakeup_write(port); - /* also queue up a wakeup at scheduler time, in case we */ - /* lost the race in write_chan(). */ - schedule_work(&priv->dp_wakeup_work); - - spin_unlock(&priv->dp_port_lock); - if (ret && ret != -EPERM) - dev_err_console(port, - "%s: usb_submit_urb failed, ret=%d, port=%d\n", - __func__, ret, priv->dp_port_num); -} - -static int digi_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct digi_port *priv = usb_get_serial_port_data(port); - int room; - unsigned long flags = 0; - - spin_lock_irqsave(&priv->dp_port_lock, flags); - - if (priv->dp_write_urb_in_use) - room = 0; - else - room = port->bulk_out_size - 2 - priv->dp_out_buf_len; - - spin_unlock_irqrestore(&priv->dp_port_lock, flags); - dbg("digi_write_room: port=%d, room=%d", priv->dp_port_num, room); - return room; - -} - -static int digi_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct digi_port *priv = usb_get_serial_port_data(port); - - if (priv->dp_write_urb_in_use) { - dbg("digi_chars_in_buffer: port=%d, chars=%d", - priv->dp_port_num, port->bulk_out_size - 2); - /* return(port->bulk_out_size - 2); */ - return 256; - } else { - dbg("digi_chars_in_buffer: port=%d, chars=%d", - priv->dp_port_num, priv->dp_out_buf_len); - return priv->dp_out_buf_len; - } - -} - -static void digi_dtr_rts(struct usb_serial_port *port, int on) -{ - /* Adjust DTR and RTS */ - digi_set_modem_signals(port, on * (TIOCM_DTR|TIOCM_RTS), 1); -} - -static int digi_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - int ret; - unsigned char buf[32]; - struct digi_port *priv = usb_get_serial_port_data(port); - struct ktermios not_termios; - - dbg("digi_open: TOP: port=%d", priv->dp_port_num); - - /* be sure the device is started up */ - if (digi_startup_device(port->serial) != 0) - return -ENXIO; - - /* read modem signals automatically whenever they change */ - buf[0] = DIGI_CMD_READ_INPUT_SIGNALS; - buf[1] = priv->dp_port_num; - buf[2] = DIGI_ENABLE; - buf[3] = 0; - - /* flush fifos */ - buf[4] = DIGI_CMD_IFLUSH_FIFO; - buf[5] = priv->dp_port_num; - buf[6] = DIGI_FLUSH_TX | DIGI_FLUSH_RX; - buf[7] = 0; - - ret = digi_write_oob_command(port, buf, 8, 1); - if (ret != 0) - dbg("digi_open: write oob failed, ret=%d", ret); - - /* set termios settings */ - if (tty) { - not_termios.c_cflag = ~tty->termios->c_cflag; - not_termios.c_iflag = ~tty->termios->c_iflag; - digi_set_termios(tty, port, ¬_termios); - } - return 0; -} - - -static void digi_close(struct usb_serial_port *port) -{ - DEFINE_WAIT(wait); - int ret; - unsigned char buf[32]; - struct digi_port *priv = usb_get_serial_port_data(port); - - dbg("digi_close: TOP: port=%d", priv->dp_port_num); - - mutex_lock(&port->serial->disc_mutex); - /* if disconnected, just clear flags */ - if (port->serial->disconnected) - goto exit; - - if (port->serial->dev) { - /* FIXME: Transmit idle belongs in the wait_unti_sent path */ - digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT); - - /* disable input flow control */ - buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL; - buf[1] = priv->dp_port_num; - buf[2] = DIGI_DISABLE; - buf[3] = 0; - - /* disable output flow control */ - buf[4] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL; - buf[5] = priv->dp_port_num; - buf[6] = DIGI_DISABLE; - buf[7] = 0; - - /* disable reading modem signals automatically */ - buf[8] = DIGI_CMD_READ_INPUT_SIGNALS; - buf[9] = priv->dp_port_num; - buf[10] = DIGI_DISABLE; - buf[11] = 0; - - /* disable receive */ - buf[12] = DIGI_CMD_RECEIVE_ENABLE; - buf[13] = priv->dp_port_num; - buf[14] = DIGI_DISABLE; - buf[15] = 0; - - /* flush fifos */ - buf[16] = DIGI_CMD_IFLUSH_FIFO; - buf[17] = priv->dp_port_num; - buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX; - buf[19] = 0; - - ret = digi_write_oob_command(port, buf, 20, 0); - if (ret != 0) - dbg("digi_close: write oob failed, ret=%d", ret); - - /* wait for final commands on oob port to complete */ - prepare_to_wait(&priv->dp_flush_wait, &wait, - TASK_INTERRUPTIBLE); - schedule_timeout(DIGI_CLOSE_TIMEOUT); - finish_wait(&priv->dp_flush_wait, &wait); - - /* shutdown any outstanding bulk writes */ - usb_kill_urb(port->write_urb); - } -exit: - spin_lock_irq(&priv->dp_port_lock); - priv->dp_write_urb_in_use = 0; - wake_up_interruptible(&priv->dp_close_wait); - spin_unlock_irq(&priv->dp_port_lock); - mutex_unlock(&port->serial->disc_mutex); - dbg("digi_close: done"); -} - - -/* - * Digi Startup Device - * - * Starts reads on all ports. Must be called AFTER startup, with - * urbs initialized. Returns 0 if successful, non-zero error otherwise. - */ - -static int digi_startup_device(struct usb_serial *serial) -{ - int i, ret = 0; - struct digi_serial *serial_priv = usb_get_serial_data(serial); - struct usb_serial_port *port; - - /* be sure this happens exactly once */ - spin_lock(&serial_priv->ds_serial_lock); - if (serial_priv->ds_device_started) { - spin_unlock(&serial_priv->ds_serial_lock); - return 0; - } - serial_priv->ds_device_started = 1; - spin_unlock(&serial_priv->ds_serial_lock); - - /* start reading from each bulk in endpoint for the device */ - /* set USB_DISABLE_SPD flag for write bulk urbs */ - for (i = 0; i < serial->type->num_ports + 1; i++) { - port = serial->port[i]; - ret = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (ret != 0) { - dev_err(&port->dev, - "%s: usb_submit_urb failed, ret=%d, port=%d\n", - __func__, ret, i); - break; - } - } - return ret; -} - - -static int digi_startup(struct usb_serial *serial) -{ - - int i; - struct digi_port *priv; - struct digi_serial *serial_priv; - - dbg("digi_startup: TOP"); - - /* allocate the private data structures for all ports */ - /* number of regular ports + 1 for the out-of-band port */ - for (i = 0; i < serial->type->num_ports + 1; i++) { - /* allocate port private structure */ - priv = kmalloc(sizeof(struct digi_port), GFP_KERNEL); - if (priv == NULL) { - while (--i >= 0) - kfree(usb_get_serial_port_data(serial->port[i])); - return 1; /* error */ - } - - /* initialize port private structure */ - spin_lock_init(&priv->dp_port_lock); - priv->dp_port_num = i; - priv->dp_out_buf_len = 0; - priv->dp_write_urb_in_use = 0; - priv->dp_modem_signals = 0; - init_waitqueue_head(&priv->dp_modem_change_wait); - priv->dp_transmit_idle = 0; - init_waitqueue_head(&priv->dp_transmit_idle_wait); - priv->dp_throttled = 0; - priv->dp_throttle_restart = 0; - init_waitqueue_head(&priv->dp_flush_wait); - init_waitqueue_head(&priv->dp_close_wait); - INIT_WORK(&priv->dp_wakeup_work, digi_wakeup_write_lock); - priv->dp_port = serial->port[i]; - /* initialize write wait queue for this port */ - init_waitqueue_head(&serial->port[i]->write_wait); - - usb_set_serial_port_data(serial->port[i], priv); - } - - /* allocate serial private structure */ - serial_priv = kmalloc(sizeof(struct digi_serial), GFP_KERNEL); - if (serial_priv == NULL) { - for (i = 0; i < serial->type->num_ports + 1; i++) - kfree(usb_get_serial_port_data(serial->port[i])); - return 1; /* error */ - } - - /* initialize serial private structure */ - spin_lock_init(&serial_priv->ds_serial_lock); - serial_priv->ds_oob_port_num = serial->type->num_ports; - serial_priv->ds_oob_port = serial->port[serial_priv->ds_oob_port_num]; - serial_priv->ds_device_started = 0; - usb_set_serial_data(serial, serial_priv); - - return 0; -} - - -static void digi_disconnect(struct usb_serial *serial) -{ - int i; - dbg("digi_disconnect: TOP, in_interrupt()=%ld", in_interrupt()); - - /* stop reads and writes on all ports */ - for (i = 0; i < serial->type->num_ports + 1; i++) { - usb_kill_urb(serial->port[i]->read_urb); - usb_kill_urb(serial->port[i]->write_urb); - } -} - - -static void digi_release(struct usb_serial *serial) -{ - int i; - dbg("digi_release: TOP, in_interrupt()=%ld", in_interrupt()); - - /* free the private data structures for all ports */ - /* number of regular ports + 1 for the out-of-band port */ - for (i = 0; i < serial->type->num_ports + 1; i++) - kfree(usb_get_serial_port_data(serial->port[i])); - kfree(usb_get_serial_data(serial)); -} - - -static void digi_read_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct digi_port *priv; - struct digi_serial *serial_priv; - int ret; - int status = urb->status; - - dbg("digi_read_bulk_callback: TOP"); - - /* port sanity check, do not resubmit if port is not valid */ - if (port == NULL) - return; - priv = usb_get_serial_port_data(port); - if (priv == NULL) { - dev_err(&port->dev, "%s: port->private is NULL, status=%d\n", - __func__, status); - return; - } - if (port->serial == NULL || - (serial_priv = usb_get_serial_data(port->serial)) == NULL) { - dev_err(&port->dev, "%s: serial is bad or serial->private " - "is NULL, status=%d\n", __func__, status); - return; - } - - /* do not resubmit urb if it has any status error */ - if (status) { - dev_err(&port->dev, - "%s: nonzero read bulk status: status=%d, port=%d\n", - __func__, status, priv->dp_port_num); - return; - } - - /* handle oob or inb callback, do not resubmit if error */ - if (priv->dp_port_num == serial_priv->ds_oob_port_num) { - if (digi_read_oob_callback(urb) != 0) - return; - } else { - if (digi_read_inb_callback(urb) != 0) - return; - } - - /* continue read */ - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret != 0 && ret != -EPERM) { - dev_err(&port->dev, - "%s: failed resubmitting urb, ret=%d, port=%d\n", - __func__, ret, priv->dp_port_num); - } - -} - -/* - * Digi Read INB Callback - * - * Digi Read INB Callback handles reads on the in band ports, sending - * the data on to the tty subsystem. When called we know port and - * port->private are not NULL and port->serial has been validated. - * It returns 0 if successful, 1 if successful but the port is - * throttled, and -1 if the sanity checks failed. - */ - -static int digi_read_inb_callback(struct urb *urb) -{ - - struct usb_serial_port *port = urb->context; - struct tty_struct *tty; - struct digi_port *priv = usb_get_serial_port_data(port); - int opcode = ((unsigned char *)urb->transfer_buffer)[0]; - int len = ((unsigned char *)urb->transfer_buffer)[1]; - int port_status = ((unsigned char *)urb->transfer_buffer)[2]; - unsigned char *data = ((unsigned char *)urb->transfer_buffer) + 3; - int flag, throttled; - int status = urb->status; - - /* do not process callbacks on closed ports */ - /* but do continue the read chain */ - if (urb->status == -ENOENT) - return 0; - - /* short/multiple packet check */ - if (urb->actual_length != len + 2) { - dev_err(&port->dev, "%s: INCOMPLETE OR MULTIPLE PACKET, " - "status=%d, port=%d, opcode=%d, len=%d, " - "actual_length=%d, status=%d\n", __func__, status, - priv->dp_port_num, opcode, len, urb->actual_length, - port_status); - return -1; - } - - tty = tty_port_tty_get(&port->port); - spin_lock(&priv->dp_port_lock); - - /* check for throttle; if set, do not resubmit read urb */ - /* indicate the read chain needs to be restarted on unthrottle */ - throttled = priv->dp_throttled; - if (throttled) - priv->dp_throttle_restart = 1; - - /* receive data */ - if (tty && opcode == DIGI_CMD_RECEIVE_DATA) { - /* get flag from port_status */ - flag = 0; - - /* overrun is special, not associated with a char */ - if (port_status & DIGI_OVERRUN_ERROR) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - - /* break takes precedence over parity, */ - /* which takes precedence over framing errors */ - if (port_status & DIGI_BREAK_ERROR) - flag = TTY_BREAK; - else if (port_status & DIGI_PARITY_ERROR) - flag = TTY_PARITY; - else if (port_status & DIGI_FRAMING_ERROR) - flag = TTY_FRAME; - - /* data length is len-1 (one byte of len is port_status) */ - --len; - if (len > 0) { - tty_insert_flip_string_fixed_flag(tty, data, flag, - len); - tty_flip_buffer_push(tty); - } - } - spin_unlock(&priv->dp_port_lock); - tty_kref_put(tty); - - if (opcode == DIGI_CMD_RECEIVE_DISABLE) - dbg("%s: got RECEIVE_DISABLE", __func__); - else if (opcode != DIGI_CMD_RECEIVE_DATA) - dbg("%s: unknown opcode: %d", __func__, opcode); - - return throttled ? 1 : 0; - -} - - -/* - * Digi Read OOB Callback - * - * Digi Read OOB Callback handles reads on the out of band port. - * When called we know port and port->private are not NULL and - * the port->serial is valid. It returns 0 if successful, and - * -1 if the sanity checks failed. - */ - -static int digi_read_oob_callback(struct urb *urb) -{ - - struct usb_serial_port *port = urb->context; - struct usb_serial *serial = port->serial; - struct tty_struct *tty; - struct digi_port *priv = usb_get_serial_port_data(port); - int opcode, line, status, val; - int i; - unsigned int rts; - - dbg("digi_read_oob_callback: port=%d, len=%d", - priv->dp_port_num, urb->actual_length); - - /* handle each oob command */ - for (i = 0; i < urb->actual_length - 3;) { - opcode = ((unsigned char *)urb->transfer_buffer)[i++]; - line = ((unsigned char *)urb->transfer_buffer)[i++]; - status = ((unsigned char *)urb->transfer_buffer)[i++]; - val = ((unsigned char *)urb->transfer_buffer)[i++]; - - dbg("digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d", - opcode, line, status, val); - - if (status != 0 || line >= serial->type->num_ports) - continue; - - port = serial->port[line]; - - priv = usb_get_serial_port_data(port); - if (priv == NULL) - return -1; - - tty = tty_port_tty_get(&port->port); - - rts = 0; - if (tty) - rts = tty->termios->c_cflag & CRTSCTS; - - if (tty && opcode == DIGI_CMD_READ_INPUT_SIGNALS) { - spin_lock(&priv->dp_port_lock); - /* convert from digi flags to termiox flags */ - if (val & DIGI_READ_INPUT_SIGNALS_CTS) { - priv->dp_modem_signals |= TIOCM_CTS; - /* port must be open to use tty struct */ - if (rts) { - tty->hw_stopped = 0; - digi_wakeup_write(port); - } - } else { - priv->dp_modem_signals &= ~TIOCM_CTS; - /* port must be open to use tty struct */ - if (rts) - tty->hw_stopped = 1; - } - if (val & DIGI_READ_INPUT_SIGNALS_DSR) - priv->dp_modem_signals |= TIOCM_DSR; - else - priv->dp_modem_signals &= ~TIOCM_DSR; - if (val & DIGI_READ_INPUT_SIGNALS_RI) - priv->dp_modem_signals |= TIOCM_RI; - else - priv->dp_modem_signals &= ~TIOCM_RI; - if (val & DIGI_READ_INPUT_SIGNALS_DCD) - priv->dp_modem_signals |= TIOCM_CD; - else - priv->dp_modem_signals &= ~TIOCM_CD; - - wake_up_interruptible(&priv->dp_modem_change_wait); - spin_unlock(&priv->dp_port_lock); - } else if (opcode == DIGI_CMD_TRANSMIT_IDLE) { - spin_lock(&priv->dp_port_lock); - priv->dp_transmit_idle = 1; - wake_up_interruptible(&priv->dp_transmit_idle_wait); - spin_unlock(&priv->dp_port_lock); - } else if (opcode == DIGI_CMD_IFLUSH_FIFO) { - wake_up_interruptible(&priv->dp_flush_wait); - } - tty_kref_put(tty); - } - return 0; - -} - -module_usb_serial_driver(digi_driver, serial_drivers); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/empeg.c b/ANDROID_3.4.5/drivers/usb/serial/empeg.c deleted file mode 100644 index 5b99fc09..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/empeg.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * USB Empeg empeg-car player driver - * - * Copyright (C) 2000, 2001 - * Gary Brubaker (xavyer@ix.netcom.com) - * - * Copyright (C) 1999 - 2001 - * Greg Kroah-Hartman (greg@kroah.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, as published by - * the Free Software Foundation, version 2. - * - * See Documentation/usb/usb-serial.txt for more information on using this - * driver - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static bool debug; - -/* - * Version Information - */ -#define DRIVER_VERSION "v1.3" -#define DRIVER_AUTHOR "Greg Kroah-Hartman , Gary Brubaker " -#define DRIVER_DESC "USB Empeg Mark I/II Driver" - -#define EMPEG_VENDOR_ID 0x084f -#define EMPEG_PRODUCT_ID 0x0001 - -/* function prototypes for an empeg-car player */ -static int empeg_startup(struct usb_serial *serial); -static void empeg_init_termios(struct tty_struct *tty); - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(EMPEG_VENDOR_ID, EMPEG_PRODUCT_ID) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver empeg_driver = { - .name = "empeg", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - -static struct usb_serial_driver empeg_device = { - .driver = { - .owner = THIS_MODULE, - .name = "empeg", - }, - .id_table = id_table, - .num_ports = 1, - .bulk_out_size = 256, - .throttle = usb_serial_generic_throttle, - .unthrottle = usb_serial_generic_unthrottle, - .attach = empeg_startup, - .init_termios = empeg_init_termios, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &empeg_device, NULL -}; - -static int empeg_startup(struct usb_serial *serial) -{ - int r; - - dbg("%s", __func__); - - if (serial->dev->actconfig->desc.bConfigurationValue != 1) { - dev_err(&serial->dev->dev, "active config #%d != 1 ??\n", - serial->dev->actconfig->desc.bConfigurationValue); - return -ENODEV; - } - dbg("%s - reset config", __func__); - r = usb_reset_configuration(serial->dev); - - /* continue on with initialization */ - return r; -} - -static void empeg_init_termios(struct tty_struct *tty) -{ - struct ktermios *termios = tty->termios; - - /* - * The empeg-car player wants these particular tty settings. - * You could, for example, change the baud rate, however the - * player only supports 115200 (currently), so there is really - * no point in support for changes to the tty settings. - * (at least for now) - * - * The default requirements for this device are: - */ - termios->c_iflag - &= ~(IGNBRK /* disable ignore break */ - | BRKINT /* disable break causes interrupt */ - | PARMRK /* disable mark parity errors */ - | ISTRIP /* disable clear high bit of input characters */ - | INLCR /* disable translate NL to CR */ - | IGNCR /* disable ignore CR */ - | ICRNL /* disable translate CR to NL */ - | IXON); /* disable enable XON/XOFF flow control */ - - termios->c_oflag - &= ~OPOST; /* disable postprocess output characters */ - - termios->c_lflag - &= ~(ECHO /* disable echo input characters */ - | ECHONL /* disable echo new line */ - | ICANON /* disable erase, kill, werase, and rprnt special characters */ - | ISIG /* disable interrupt, quit, and suspend special characters */ - | IEXTEN); /* disable non-POSIX special characters */ - - termios->c_cflag - &= ~(CSIZE /* no size */ - | PARENB /* disable parity bit */ - | CBAUD); /* clear current baud rate */ - - termios->c_cflag - |= CS8; /* character size 8 bits */ - - tty_encode_baud_rate(tty, 115200, 115200); -} - -module_usb_serial_driver(empeg_driver, serial_drivers); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/ezusb.c b/ANDROID_3.4.5/drivers/usb/serial/ezusb.c deleted file mode 100644 index 3cfc762f..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/ezusb.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * EZ-USB specific functions used by some of the USB to Serial drivers. - * - * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */ -#define CPUCS_REG 0x7F92 - -int ezusb_writememory(struct usb_serial *serial, int address, - unsigned char *data, int length, __u8 request) -{ - int result; - unsigned char *transfer_buffer; - - /* dbg("ezusb_writememory %x, %d", address, length); */ - if (!serial->dev) { - printk(KERN_ERR "ezusb: %s - no physical device present, " - "failing.\n", __func__); - return -ENODEV; - } - - transfer_buffer = kmemdup(data, length, GFP_KERNEL); - if (!transfer_buffer) { - dev_err(&serial->dev->dev, "%s - kmalloc(%d) failed.\n", - __func__, length); - return -ENOMEM; - } - result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - request, 0x40, address, 0, transfer_buffer, length, 3000); - kfree(transfer_buffer); - return result; -} -EXPORT_SYMBOL_GPL(ezusb_writememory); - -int ezusb_set_reset(struct usb_serial *serial, unsigned char reset_bit) -{ - int response; - - /* dbg("%s - %d", __func__, reset_bit); */ - response = ezusb_writememory(serial, CPUCS_REG, &reset_bit, 1, 0xa0); - if (response < 0) - dev_err(&serial->dev->dev, "%s- %d failed\n", - __func__, reset_bit); - return response; -} -EXPORT_SYMBOL_GPL(ezusb_set_reset); - diff --git a/ANDROID_3.4.5/drivers/usb/serial/ezusb_convert.pl b/ANDROID_3.4.5/drivers/usb/serial/ezusb_convert.pl deleted file mode 100644 index 13f11469..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/ezusb_convert.pl +++ /dev/null @@ -1,50 +0,0 @@ -#! /usr/bin/perl -w - - -# convert an Intel HEX file into a set of C records usable by the firmware -# loading code in usb-serial.c (or others) - -# accepts the .hex file(s) on stdin, a basename (to name the initialized -# array) as an argument, and prints the .h file to stdout. Typical usage: -# perl ezusb_convert.pl foo fw_foo.h - - -my $basename = $ARGV[0]; -die "no base name specified" unless $basename; - -while () { - # ':' '\r' - # len, type, crc are 2-char hex, addr is 4-char hex. type is 00 for - # normal records, 01 for EOF - my($lenstring, $addrstring, $typestring, $reststring, $doscrap) = - /^:(\w\w)(\w\w\w\w)(\w\w)(\w+)(\r?)$/; - die "malformed line: $_" unless $reststring; - last if $typestring eq '01'; - my($len) = hex($lenstring); - my($addr) = hex($addrstring); - my(@bytes) = unpack("C*", pack("H".(2*$len), $reststring)); - #pop(@bytes); # last byte is a CRC - push(@records, [$addr, \@bytes]); -} - -@sorted_records = sort { $a->[0] <=> $b->[0] } @records; - -print <<"EOF"; -/* - * ${basename}_fw.h - * - * Generated from ${basename}.s by ezusb_convert.pl - * This file is presumed to be under the same copyright as the source file - * from which it was derived. - */ - -EOF - -print "static const struct ezusb_hex_record ${basename}_firmware[] = {\n"; -foreach $r (@sorted_records) { - printf("{ 0x%04x,\t%d,\t{", $r->[0], scalar(@{$r->[1]})); - print join(", ", map {sprintf('0x%02x', $_);} @{$r->[1]}); - print "} },\n"; -} -print "{ 0xffff,\t0,\t{0x00} }\n"; -print "};\n"; diff --git a/ANDROID_3.4.5/drivers/usb/serial/f81232.c b/ANDROID_3.4.5/drivers/usb/serial/f81232.c deleted file mode 100644 index 88c0b196..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/f81232.c +++ /dev/null @@ -1,405 +0,0 @@ -/* - * Fintek F81232 USB to serial adaptor driver - * - * Copyright (C) 2012 Greg Kroah-Hartman (gregkh@linuxfoundation.org) - * Copyright (C) 2012 Linux Foundation - * - * 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static bool debug; - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(0x1934, 0x0706) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, id_table); - -#define CONTROL_DTR 0x01 -#define CONTROL_RTS 0x02 - -#define UART_STATE 0x08 -#define UART_STATE_TRANSIENT_MASK 0x74 -#define UART_DCD 0x01 -#define UART_DSR 0x02 -#define UART_BREAK_ERROR 0x04 -#define UART_RING 0x08 -#define UART_FRAME_ERROR 0x10 -#define UART_PARITY_ERROR 0x20 -#define UART_OVERRUN_ERROR 0x40 -#define UART_CTS 0x80 - -struct f81232_private { - spinlock_t lock; - wait_queue_head_t delta_msr_wait; - u8 line_control; - u8 line_status; -}; - -static void f81232_update_line_status(struct usb_serial_port *port, - unsigned char *data, - unsigned int actual_length) -{ -} - -static void f81232_read_int_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - unsigned char *data = urb->transfer_buffer; - unsigned int actual_length = urb->actual_length; - int status = urb->status; - int retval; - - dbg("%s (%d)", __func__, port->number); - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, - status); - return; - default: - dbg("%s - nonzero urb status received: %d", __func__, - status); - goto exit; - } - - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, urb->transfer_buffer); - - f81232_update_line_status(port, data, actual_length); - -exit: - retval = usb_submit_urb(urb, GFP_ATOMIC); - if (retval) - dev_err(&urb->dev->dev, - "%s - usb_submit_urb failed with result %d\n", - __func__, retval); -} - -static void f81232_process_read_urb(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct f81232_private *priv = usb_get_serial_port_data(port); - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - char tty_flag = TTY_NORMAL; - unsigned long flags; - u8 line_status; - int i; - - /* update line status */ - spin_lock_irqsave(&priv->lock, flags); - line_status = priv->line_status; - priv->line_status &= ~UART_STATE_TRANSIENT_MASK; - spin_unlock_irqrestore(&priv->lock, flags); - wake_up_interruptible(&priv->delta_msr_wait); - - if (!urb->actual_length) - return; - - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - - /* break takes precedence over parity, */ - /* which takes precedence over framing errors */ - if (line_status & UART_BREAK_ERROR) - tty_flag = TTY_BREAK; - else if (line_status & UART_PARITY_ERROR) - tty_flag = TTY_PARITY; - else if (line_status & UART_FRAME_ERROR) - tty_flag = TTY_FRAME; - dbg("%s - tty_flag = %d", __func__, tty_flag); - - /* overrun is special, not associated with a char */ - if (line_status & UART_OVERRUN_ERROR) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - - if (port->port.console && port->sysrq) { - for (i = 0; i < urb->actual_length; ++i) - if (!usb_serial_handle_sysrq_char(port, data[i])) - tty_insert_flip_char(tty, data[i], tty_flag); - } else { - tty_insert_flip_string_fixed_flag(tty, data, tty_flag, - urb->actual_length); - } - - tty_flip_buffer_push(tty); - tty_kref_put(tty); -} - -static int set_control_lines(struct usb_device *dev, u8 value) -{ - /* FIXME - Stubbed out for now */ - return 0; -} - -static void f81232_break_ctl(struct tty_struct *tty, int break_state) -{ - /* FIXME - Stubbed out for now */ - - /* - * break_state = -1 to turn on break, and 0 to turn off break - * see drivers/char/tty_io.c to see it used. - * last_set_data_urb_value NEVER has the break bit set in it. - */ -} - -static void f81232_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) -{ - /* FIXME - Stubbed out for now */ - - /* Don't change anything if nothing has changed */ - if (!tty_termios_hw_change(tty->termios, old_termios)) - return; - - /* Do the real work here... */ -} - -static int f81232_tiocmget(struct tty_struct *tty) -{ - /* FIXME - Stubbed out for now */ - return 0; -} - -static int f81232_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - /* FIXME - Stubbed out for now */ - return 0; -} - -static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct ktermios tmp_termios; - int result; - - /* Setup termios */ - if (tty) - f81232_set_termios(tty, port, &tmp_termios); - - dbg("%s - submitting interrupt urb", __func__); - result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - if (result) { - dev_err(&port->dev, "%s - failed submitting interrupt urb," - " error %d\n", __func__, result); - return result; - } - - result = usb_serial_generic_open(tty, port); - if (result) { - usb_kill_urb(port->interrupt_in_urb); - return result; - } - - port->port.drain_delay = 256; - return 0; -} - -static void f81232_close(struct usb_serial_port *port) -{ - usb_serial_generic_close(port); - usb_kill_urb(port->interrupt_in_urb); -} - -static void f81232_dtr_rts(struct usb_serial_port *port, int on) -{ - struct f81232_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - u8 control; - - spin_lock_irqsave(&priv->lock, flags); - /* Change DTR and RTS */ - if (on) - priv->line_control |= (CONTROL_DTR | CONTROL_RTS); - else - priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); - control = priv->line_control; - spin_unlock_irqrestore(&priv->lock, flags); - set_control_lines(port->serial->dev, control); -} - -static int f81232_carrier_raised(struct usb_serial_port *port) -{ - struct f81232_private *priv = usb_get_serial_port_data(port); - if (priv->line_status & UART_DCD) - return 1; - return 0; -} - -static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) -{ - struct f81232_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - unsigned int prevstatus; - unsigned int status; - unsigned int changed; - - spin_lock_irqsave(&priv->lock, flags); - prevstatus = priv->line_status; - spin_unlock_irqrestore(&priv->lock, flags); - - while (1) { - interruptible_sleep_on(&priv->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - - spin_lock_irqsave(&priv->lock, flags); - status = priv->line_status; - spin_unlock_irqrestore(&priv->lock, flags); - - changed = prevstatus ^ status; - - if (((arg & TIOCM_RNG) && (changed & UART_RING)) || - ((arg & TIOCM_DSR) && (changed & UART_DSR)) || - ((arg & TIOCM_CD) && (changed & UART_DCD)) || - ((arg & TIOCM_CTS) && (changed & UART_CTS))) { - return 0; - } - prevstatus = status; - } - /* NOTREACHED */ - return 0; -} - -static int f81232_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct serial_struct ser; - struct usb_serial_port *port = tty->driver_data; - dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd); - - switch (cmd) { - case TIOCGSERIAL: - memset(&ser, 0, sizeof ser); - ser.type = PORT_16654; - ser.line = port->serial->minor; - ser.port = port->number; - ser.baud_base = 460800; - - if (copy_to_user((void __user *)arg, &ser, sizeof ser)) - return -EFAULT; - - return 0; - - case TIOCMIWAIT: - dbg("%s (%d) TIOCMIWAIT", __func__, port->number); - return wait_modem_info(port, arg); - default: - dbg("%s not supported = 0x%04x", __func__, cmd); - break; - } - return -ENOIOCTLCMD; -} - -static int f81232_startup(struct usb_serial *serial) -{ - struct f81232_private *priv; - int i; - - for (i = 0; i < serial->num_ports; ++i) { - priv = kzalloc(sizeof(struct f81232_private), GFP_KERNEL); - if (!priv) - goto cleanup; - spin_lock_init(&priv->lock); - init_waitqueue_head(&priv->delta_msr_wait); - usb_set_serial_port_data(serial->port[i], priv); - } - return 0; - -cleanup: - for (--i; i >= 0; --i) { - priv = usb_get_serial_port_data(serial->port[i]); - kfree(priv); - usb_set_serial_port_data(serial->port[i], NULL); - } - return -ENOMEM; -} - -static void f81232_release(struct usb_serial *serial) -{ - int i; - struct f81232_private *priv; - - for (i = 0; i < serial->num_ports; ++i) { - priv = usb_get_serial_port_data(serial->port[i]); - kfree(priv); - } -} - -static struct usb_driver f81232_driver = { - .name = "f81232", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .no_dynamic_id = 1, - .supports_autosuspend = 1, -}; - -static struct usb_serial_driver f81232_device = { - .driver = { - .owner = THIS_MODULE, - .name = "f81232", - }, - .id_table = id_table, - .usb_driver = &f81232_driver, - .num_ports = 1, - .bulk_in_size = 256, - .bulk_out_size = 256, - .open = f81232_open, - .close = f81232_close, - .dtr_rts = f81232_dtr_rts, - .carrier_raised = f81232_carrier_raised, - .ioctl = f81232_ioctl, - .break_ctl = f81232_break_ctl, - .set_termios = f81232_set_termios, - .tiocmget = f81232_tiocmget, - .tiocmset = f81232_tiocmset, - .process_read_urb = f81232_process_read_urb, - .read_int_callback = f81232_read_int_callback, - .attach = f81232_startup, - .release = f81232_release, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &f81232_device, - NULL, -}; - -module_usb_serial_driver(f81232_driver, serial_drivers); - -MODULE_DESCRIPTION("Fintek F81232 USB to serial adaptor driver"); -MODULE_AUTHOR("Greg Kroah-Hartman -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ftdi_sio.h" -#include "ftdi_sio_ids.h" - -/* - * Version Information - */ -#define DRIVER_VERSION "v1.6.0" -#define DRIVER_AUTHOR "Greg Kroah-Hartman , Bill Ryder , Kuba Ober , Andreas Mohr, Johan Hovold " -#define DRIVER_DESC "USB FTDI Serial Converters Driver" - -static bool debug; -static __u16 vendor = FTDI_VID; -static __u16 product; - -struct ftdi_private { - struct kref kref; - enum ftdi_chip_type chip_type; - /* type of device, either SIO or FT8U232AM */ - int baud_base; /* baud base clock for divisor setting */ - int custom_divisor; /* custom_divisor kludge, this is for - baud_base (different from what goes to the - chip!) */ - __u16 last_set_data_urb_value ; - /* the last data state set - needed for doing - * a break - */ - int flags; /* some ASYNC_xxxx flags are supported */ - unsigned long last_dtr_rts; /* saved modem control outputs */ - struct async_icount icount; - wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ - char prev_status; /* Used for TIOCMIWAIT */ - bool dev_gone; /* Used to abort TIOCMIWAIT */ - char transmit_empty; /* If transmitter is empty or not */ - struct usb_serial_port *port; - __u16 interface; /* FT2232C, FT2232H or FT4232H port interface - (0 for FT232/245) */ - - speed_t force_baud; /* if non-zero, force the baud rate to - this value */ - int force_rtscts; /* if non-zero, force RTS-CTS to always - be enabled */ - - unsigned int latency; /* latency setting in use */ - unsigned short max_packet_size; - struct mutex cfg_lock; /* Avoid mess by parallel calls of config ioctl() and change_speed() */ -}; - -/* struct ftdi_sio_quirk is used by devices requiring special attention. */ -struct ftdi_sio_quirk { - int (*probe)(struct usb_serial *); - /* Special settings for probed ports. */ - void (*port_probe)(struct ftdi_private *); -}; - -static int ftdi_jtag_probe(struct usb_serial *serial); -static int ftdi_mtxorb_hack_setup(struct usb_serial *serial); -static int ftdi_NDI_device_setup(struct usb_serial *serial); -static int ftdi_stmclite_probe(struct usb_serial *serial); -static int ftdi_8u2232c_probe(struct usb_serial *serial); -static void ftdi_USB_UIRT_setup(struct ftdi_private *priv); -static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv); - -static struct ftdi_sio_quirk ftdi_jtag_quirk = { - .probe = ftdi_jtag_probe, -}; - -static struct ftdi_sio_quirk ftdi_mtxorb_hack_quirk = { - .probe = ftdi_mtxorb_hack_setup, -}; - -static struct ftdi_sio_quirk ftdi_NDI_device_quirk = { - .probe = ftdi_NDI_device_setup, -}; - -static struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = { - .port_probe = ftdi_USB_UIRT_setup, -}; - -static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = { - .port_probe = ftdi_HE_TIRA1_setup, -}; - -static struct ftdi_sio_quirk ftdi_stmclite_quirk = { - .probe = ftdi_stmclite_probe, -}; - -static struct ftdi_sio_quirk ftdi_8u2232c_quirk = { - .probe = ftdi_8u2232c_probe, -}; - -/* - * The 8U232AM has the same API as the sio except for: - * - it can support MUCH higher baudrates; up to: - * o 921600 for RS232 and 2000000 for RS422/485 at 48MHz - * o 230400 at 12MHz - * so .. 8U232AM's baudrate setting codes are different - * - it has a two byte status code. - * - it returns characters every 16ms (the FTDI does it every 40ms) - * - * the bcdDevice value is used to differentiate FT232BM and FT245BM from - * the earlier FT8U232AM and FT8U232BM. For now, include all known VID/PID - * combinations in both tables. - * FIXME: perhaps bcdDevice can also identify 12MHz FT8U232AM devices, - * but I don't know if those ever went into mass production. [Ian Abbott] - */ - - - -/* - * Device ID not listed? Test via module params product/vendor or - * /sys/bus/usb/ftdi_sio/new_id, then send patch/report! - */ -static struct usb_device_id id_table_combined [] = { - { USB_DEVICE(FTDI_VID, FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CTI_MINI_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CTI_NANO_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CANDAPTER_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_NXTCAM_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_1_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_2_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_3_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_4_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_5_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_6_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_7_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_USINT_CAT_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_USINT_WKEY_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_USINT_RS232_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_IPLUS2_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_DMX4ALL) }, - { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_232RL_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) , - .driver_info = (kernel_ulong_t)&ftdi_8u2232c_quirk }, - { USB_DEVICE(FTDI_VID, FTDI_4232H_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_232H_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_FTX_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_SNIFFER_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_THROTTLE_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GATEWAY_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_PID) }, - { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, - { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_SPROG_II) }, - { USB_DEVICE(FTDI_VID, FTDI_LENZ_LIUSB_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_XF_547_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_XF_633_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_XF_631_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_XF_635_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_XF_640_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_XF_642_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_DSS20_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_URBAN_0_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_URBAN_1_PID) }, - { USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_VNHCPCUSB_D_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_MTXORB_0_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_MTXORB_1_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_MTXORB_2_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_MTXORB_3_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_MTXORB_4_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_R2000KU_TRUE_RNG) }, - { USB_DEVICE(FTDI_VID, FTDI_VARDAAN_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0100_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0101_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0102_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0103_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0104_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0105_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0106_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0107_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0108_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0109_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010A_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010B_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010C_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010D_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010E_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_010F_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0110_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0111_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0112_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0113_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0114_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0115_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0116_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0117_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0118_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0119_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011A_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011B_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011C_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011D_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011E_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_011F_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0120_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0121_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0122_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0123_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0124_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0125_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0126_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0127_PID), - .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0128_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0129_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012A_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012B_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012C_PID), - .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012D_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012E_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_012F_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0130_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0131_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0132_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0133_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0134_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0135_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0136_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0137_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0138_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0139_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013A_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013B_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013C_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013D_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013E_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_013F_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0140_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0141_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0142_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0143_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0144_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0145_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0146_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0147_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0148_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0149_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014A_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014B_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014C_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014D_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014E_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_014F_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0150_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0151_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0152_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0153_PID), - .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0154_PID), - .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0155_PID), - .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0156_PID), - .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0157_PID), - .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0158_PID), - .driver_info = (kernel_ulong_t)&ftdi_mtxorb_hack_quirk }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0159_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015A_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015B_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015C_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015D_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015E_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_015F_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0160_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0161_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0162_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0163_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0164_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0165_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0166_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0167_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0168_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0169_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016A_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016B_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016C_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016D_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016E_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_016F_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0170_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0171_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0172_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0173_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0174_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0175_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0176_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0177_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0178_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0179_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017A_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017B_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017C_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017D_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017E_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_017F_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0180_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0181_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0182_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0183_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0184_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0185_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0186_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0187_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0188_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0189_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018A_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018B_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018C_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018D_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018E_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_018F_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0190_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0191_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0192_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0193_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0194_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0195_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0196_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0197_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0198_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_0199_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019A_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019B_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019C_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019D_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019E_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_019F_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A0_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A1_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A2_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A3_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A4_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A5_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A6_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A7_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A8_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01A9_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AA_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AB_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AC_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AD_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AE_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01AF_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B0_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B1_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B2_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B3_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B4_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B5_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B6_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B7_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B8_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01B9_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BA_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BB_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BC_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BD_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BE_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01BF_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C0_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C1_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C2_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C3_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C4_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C5_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C6_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C7_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C8_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01C9_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CA_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CB_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CC_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CD_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CE_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01CF_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D0_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D1_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D2_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D3_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D4_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D5_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D6_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D7_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D8_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01D9_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DA_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DB_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DC_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DD_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DE_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01DF_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E0_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E1_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E2_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E3_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E4_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E5_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E6_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E7_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E8_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01E9_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EA_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EB_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EC_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01ED_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EE_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01EF_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F0_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F1_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F2_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F3_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F4_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F5_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F6_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F7_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F8_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01F9_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FA_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FB_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FC_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FD_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FE_PID) }, - { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FF_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_TNC_X_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_USBX_707_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2103_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2104_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2106_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_1_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_2_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2202_1_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2202_2_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2203_1_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2203_2_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_1_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_2_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_3_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2401_4_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_1_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_2_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_3_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2402_4_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_1_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_2_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_3_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2403_4_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_1_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_2_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_3_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_4_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_5_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_6_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_7_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2801_8_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_1_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_2_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_3_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_4_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_5_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_6_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_7_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2802_8_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_1_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_2_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_3_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_4_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_5_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_6_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_7_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_8_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_1_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_2_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_3_PID) }, - { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_4_PID) }, - { USB_DEVICE(IDTECH_VID, IDTECH_IDT1221U_PID) }, - { USB_DEVICE(OCT_VID, OCT_US101_PID) }, - { USB_DEVICE(OCT_VID, OCT_DK201_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_HE_TIRA1_PID), - .driver_info = (kernel_ulong_t)&ftdi_HE_TIRA1_quirk }, - { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID), - .driver_info = (kernel_ulong_t)&ftdi_USB_UIRT_quirk }, - { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_1) }, - { USB_DEVICE(FTDI_VID, PROTEGO_R2X0) }, - { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_3) }, - { USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_4) }, - { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E808_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E809_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80A_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80B_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80C_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80D_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80E_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80F_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E888_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E889_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88A_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88B_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88C_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88D_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88E_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88F_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_UM100_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_UR100_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_ALC8500_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_PYRAMID_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1000PC_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_IBS_US485_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_IBS_PICPRO_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_IBS_PCMCIA_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_IBS_PK1_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_IBS_RS232MON_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_IBS_APP70_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_TAVIR_STK500_PID) }, - /* - * ELV devices: - */ - { USB_DEVICE(FTDI_VID, FTDI_ELV_USR_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_MSM1_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_KL100_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_WS550_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_EC3000_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_WS888_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_TWS550_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_FEM_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_UDF77_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_UIO88_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_UAD8_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_UDA7_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_USI2_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_UTP8_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_WS444PC_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1010PC_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_HS485_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_UMS100_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_TFD128_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_FM3RX_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELV_WS777_PID) }, - { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) }, - { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) }, - { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) }, - { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) }, - { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CCSMACHX_2_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CCSLOAD_N_GO_3_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CCSICDU64_4_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CCSPRIME8_5_PID) }, - { USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) }, - { USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) }, - { USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) }, - { USB_DEVICE(FALCOM_VID, FALCOM_TWIST_PID) }, - { USB_DEVICE(FALCOM_VID, FALCOM_SAMBA_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_SUUNTO_SPORTS_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_OCEANIC_PID) }, - { USB_DEVICE(TTI_VID, TTI_QL355P_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) }, - { USB_DEVICE(ACTON_VID, ACTON_SPECTRAPRO_PID) }, - { USB_DEVICE(CONTEC_VID, CONTEC_COM1USBH_PID) }, - { USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) }, - { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) }, - { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) }, - { USB_DEVICE(BANDB_VID, BANDB_USOPTL4_PID) }, - { USB_DEVICE(BANDB_VID, BANDB_USPTL4_PID) }, - { USB_DEVICE(BANDB_VID, BANDB_USO9ML2DR_2_PID) }, - { USB_DEVICE(BANDB_VID, BANDB_USO9ML2DR_PID) }, - { USB_DEVICE(BANDB_VID, BANDB_USOPTL4DR2_PID) }, - { USB_DEVICE(BANDB_VID, BANDB_USOPTL4DR_PID) }, - { USB_DEVICE(BANDB_VID, BANDB_485USB9F_2W_PID) }, - { USB_DEVICE(BANDB_VID, BANDB_485USB9F_4W_PID) }, - { USB_DEVICE(BANDB_VID, BANDB_232USB9M_PID) }, - { USB_DEVICE(BANDB_VID, BANDB_485USBTB_2W_PID) }, - { USB_DEVICE(BANDB_VID, BANDB_485USBTB_4W_PID) }, - { USB_DEVICE(BANDB_VID, BANDB_TTL5USB9M_PID) }, - { USB_DEVICE(BANDB_VID, BANDB_TTL3USB9M_PID) }, - { USB_DEVICE(BANDB_VID, BANDB_ZZ_PROG1_USB_PID) }, - { USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) }, - { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_3_PID) }, - { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) }, - { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_1_PID) }, - { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_2_PID) }, - { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_3_PID) }, - { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_4_PID) }, - { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_5_PID) }, - { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_6_PID) }, - { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_7_PID) }, - { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_MHAM_KW_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_MHAM_YS_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y6_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y8_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_MHAM_IC_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_MHAM_DB9_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_MHAM_RS232_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_MHAM_Y9_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_TERATRONIK_VCP_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_TERATRONIK_D2XX_PID) }, - { USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) }, - { USB_DEVICE(EVOLUTION_VID, EVO_HYBRID_PID) }, - { USB_DEVICE(EVOLUTION_VID, EVO_RCM4_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ARTEMIS_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16C_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HR_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HRC_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16IC_PID) }, - { USB_DEVICE(KOBIL_VID, KOBIL_CONV_B1_PID) }, - { USB_DEVICE(KOBIL_VID, KOBIL_CONV_KAAN_PID) }, - { USB_DEVICE(POSIFLEX_VID, POSIFLEX_PP7000_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_TTUSB_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ECLO_COM_1WIRE_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_777_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_8900F_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_PCDJ_DAC2_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_RRCIRKITS_LOCOBUFFER_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ASK_RDR400_PID) }, - { USB_DEVICE(ICOM_VID, ICOM_ID_1_PID) }, - { USB_DEVICE(ICOM_VID, ICOM_OPC_U_UC_PID) }, - { USB_DEVICE(ICOM_VID, ICOM_ID_RP2C1_PID) }, - { USB_DEVICE(ICOM_VID, ICOM_ID_RP2C2_PID) }, - { USB_DEVICE(ICOM_VID, ICOM_ID_RP2D_PID) }, - { USB_DEVICE(ICOM_VID, ICOM_ID_RP2VT_PID) }, - { USB_DEVICE(ICOM_VID, ICOM_ID_RP2VR_PID) }, - { USB_DEVICE(ICOM_VID, ICOM_ID_RP4KVT_PID) }, - { USB_DEVICE(ICOM_VID, ICOM_ID_RP4KVR_PID) }, - { USB_DEVICE(ICOM_VID, ICOM_ID_RP2KVT_PID) }, - { USB_DEVICE(ICOM_VID, ICOM_ID_RP2KVR_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_YEI_SERVOCENTER31_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_THORLABS_PID) }, - { USB_DEVICE(TESTO_VID, TESTO_USB_INTERFACE_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_GAMMA_SCOUT_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13M_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13U_PID) }, - { USB_DEVICE(ELEKTOR_VID, ELEKTOR_FT323R_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_NDI_HUC_PID), - .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, - { USB_DEVICE(FTDI_VID, FTDI_NDI_SPECTRA_SCU_PID), - .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, - { USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_2_PID), - .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, - { USB_DEVICE(FTDI_VID, FTDI_NDI_FUTURE_3_PID), - .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, - { USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID), - .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, - { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) }, - { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_SERIAL_VX7_PID) }, - { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_CT29B_PID) }, - { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_RTS01_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) }, - { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_PROPOX_JTAGCABLEII_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_PROPOX_ISPCABLEIII_PID) }, - { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_H_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(FIC_VID, FIC_NEO1973_DEBUG_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(FTDI_VID, FTDI_OOCDLINK_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(FTDI_VID, LMI_LM3S_DEVEL_BOARD_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(FTDI_VID, LMI_LM3S_EVAL_BOARD_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(FTDI_VID, LMI_LM3S_ICDI_BOARD_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) }, - { USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) }, - - /* Papouch devices based on FTDI chip */ - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_AP485_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB422_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485_2_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_AP485_2_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB422_2_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485S_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB485C_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_LEC_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SB232_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_TMU_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_IRAMP_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_DRAK5_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO8x8_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO4x4_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO2x2_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO10x1_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO30x3_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO60x3_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO2x16_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO3x32_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_DRAK6_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_UPSUSB_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_MU_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_SIMUKEY_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_AD4USB_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_GMUX_PID) }, - { USB_DEVICE(PAPOUCH_VID, PAPOUCH_GMSR_PID) }, - - { USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DGQG_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DUSB_PID) }, - { USB_DEVICE(ALTI2_VID, ALTI2_N3_PID) }, - { USB_DEVICE(FTDI_VID, DIEBOLD_BCS_SE923_PID) }, - { USB_DEVICE(ATMEL_VID, STK541_PID) }, - { USB_DEVICE(DE_VID, STB_PID) }, - { USB_DEVICE(DE_VID, WHT_PID) }, - { USB_DEVICE(ADI_VID, ADI_GNICE_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(ADI_VID, ADI_GNICEPLUS_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(MICROCHIP_VID, MICROCHIP_USB_BOARD_PID) }, - { USB_DEVICE(JETI_VID, JETI_SPC1201_PID) }, - { USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) }, - { USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) }, - { USB_DEVICE(PI_VID, PI_E861_PID) }, - { USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) }, - { USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(FTDI_VID, TI_XDS100V2_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(FTDI_VID, HAMEG_HO820_PID) }, - { USB_DEVICE(FTDI_VID, HAMEG_HO720_PID) }, - { USB_DEVICE(FTDI_VID, HAMEG_HO730_PID) }, - { USB_DEVICE(FTDI_VID, HAMEG_HO870_PID) }, - { USB_DEVICE(FTDI_VID, MJSG_GENERIC_PID) }, - { USB_DEVICE(FTDI_VID, MJSG_SR_RADIO_PID) }, - { USB_DEVICE(FTDI_VID, MJSG_HD_RADIO_PID) }, - { USB_DEVICE(FTDI_VID, MJSG_XM_RADIO_PID) }, - { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_ST_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SLITE_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH2_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH4_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(FTDI_VID, SEGWAY_RMP200_PID) }, - { USB_DEVICE(FTDI_VID, ACCESIO_COM4SM_PID) }, - { USB_DEVICE(IONICS_VID, IONICS_PLUGCOMPUTER_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_24_MASTER_WING_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_PC_WING_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_USB_DMX_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MIDI_TIMECODE_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MINI_WING_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MAXI_WING_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_MEDIA_WING_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CHAMSYS_WING_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LOGBOOKML_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LS_LOGBOOK_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CINTERION_MC55I_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) }, - { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(ST_VID, ST_STMCLT1030_PID), - .driver_info = (kernel_ulong_t)&ftdi_stmclite_quirk }, - { USB_DEVICE(FTDI_VID, FTDI_RF_R106) }, - { USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID), - .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, - { USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) }, - { }, /* Optional parameter entry */ - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, id_table_combined); - -static struct usb_driver ftdi_driver = { - .name = "ftdi_sio", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; - -static const char *ftdi_chip_name[] = { - [SIO] = "SIO", /* the serial part of FT8U100AX */ - [FT8U232AM] = "FT8U232AM", - [FT232BM] = "FT232BM", - [FT2232C] = "FT2232C", - [FT232RL] = "FT232RL", - [FT2232H] = "FT2232H", - [FT4232H] = "FT4232H", - [FT232H] = "FT232H", - [FTX] = "FT-X" -}; - - -/* Used for TIOCMIWAIT */ -#define FTDI_STATUS_B0_MASK (FTDI_RS0_CTS | FTDI_RS0_DSR | FTDI_RS0_RI | FTDI_RS0_RLSD) -#define FTDI_STATUS_B1_MASK (FTDI_RS_BI) -/* End TIOCMIWAIT */ - -#define FTDI_IMPL_ASYNC_FLAGS = (ASYNC_SPD_HI | ASYNC_SPD_VHI \ - | ASYNC_SPD_CUST | ASYNC_SPD_SHI | ASYNC_SPD_WARP) - -/* function prototypes for a FTDI serial converter */ -static int ftdi_sio_probe(struct usb_serial *serial, - const struct usb_device_id *id); -static int ftdi_sio_port_probe(struct usb_serial_port *port); -static int ftdi_sio_port_remove(struct usb_serial_port *port); -static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port); -static void ftdi_close(struct usb_serial_port *port); -static void ftdi_dtr_rts(struct usb_serial_port *port, int on); -static void ftdi_process_read_urb(struct urb *urb); -static int ftdi_prepare_write_buffer(struct usb_serial_port *port, - void *dest, size_t size); -static void ftdi_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old); -static int ftdi_tiocmget(struct tty_struct *tty); -static int ftdi_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear); -static int ftdi_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount); -static int ftdi_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); -static void ftdi_break_ctl(struct tty_struct *tty, int break_state); - -static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base); -static unsigned short int ftdi_232am_baud_to_divisor(int baud); -static __u32 ftdi_232bm_baud_base_to_divisor(int baud, int base); -static __u32 ftdi_232bm_baud_to_divisor(int baud); -static __u32 ftdi_2232h_baud_base_to_divisor(int baud, int base); -static __u32 ftdi_2232h_baud_to_divisor(int baud); - -static struct usb_serial_driver ftdi_sio_device = { - .driver = { - .owner = THIS_MODULE, - .name = "ftdi_sio", - }, - .description = "FTDI USB Serial Device", - .id_table = id_table_combined, - .num_ports = 1, - .bulk_in_size = 512, - .bulk_out_size = 256, - .probe = ftdi_sio_probe, - .port_probe = ftdi_sio_port_probe, - .port_remove = ftdi_sio_port_remove, - .open = ftdi_open, - .close = ftdi_close, - .dtr_rts = ftdi_dtr_rts, - .throttle = usb_serial_generic_throttle, - .unthrottle = usb_serial_generic_unthrottle, - .process_read_urb = ftdi_process_read_urb, - .prepare_write_buffer = ftdi_prepare_write_buffer, - .tiocmget = ftdi_tiocmget, - .tiocmset = ftdi_tiocmset, - .get_icount = ftdi_get_icount, - .ioctl = ftdi_ioctl, - .set_termios = ftdi_set_termios, - .break_ctl = ftdi_break_ctl, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &ftdi_sio_device, NULL -}; - - -#define WDR_TIMEOUT 5000 /* default urb timeout */ -#define WDR_SHORT_TIMEOUT 1000 /* shorter urb timeout */ - -/* High and low are for DTR, RTS etc etc */ -#define HIGH 1 -#define LOW 0 - -/* - * *************************************************************************** - * Utility functions - * *************************************************************************** - */ - -static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base) -{ - unsigned short int divisor; - /* divisor shifted 3 bits to the left */ - int divisor3 = base / 2 / baud; - if ((divisor3 & 0x7) == 7) - divisor3++; /* round x.7/8 up to x+1 */ - divisor = divisor3 >> 3; - divisor3 &= 0x7; - if (divisor3 == 1) - divisor |= 0xc000; - else if (divisor3 >= 4) - divisor |= 0x4000; - else if (divisor3 != 0) - divisor |= 0x8000; - else if (divisor == 1) - divisor = 0; /* special case for maximum baud rate */ - return divisor; -} - -static unsigned short int ftdi_232am_baud_to_divisor(int baud) -{ - return ftdi_232am_baud_base_to_divisor(baud, 48000000); -} - -static __u32 ftdi_232bm_baud_base_to_divisor(int baud, int base) -{ - static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; - __u32 divisor; - /* divisor shifted 3 bits to the left */ - int divisor3 = base / 2 / baud; - divisor = divisor3 >> 3; - divisor |= (__u32)divfrac[divisor3 & 0x7] << 14; - /* Deal with special cases for highest baud rates. */ - if (divisor == 1) - divisor = 0; - else if (divisor == 0x4001) - divisor = 1; - return divisor; -} - -static __u32 ftdi_232bm_baud_to_divisor(int baud) -{ - return ftdi_232bm_baud_base_to_divisor(baud, 48000000); -} - -static __u32 ftdi_2232h_baud_base_to_divisor(int baud, int base) -{ - static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 }; - __u32 divisor; - int divisor3; - - /* hi-speed baud rate is 10-bit sampling instead of 16-bit */ - divisor3 = base * 8 / (baud * 10); - - divisor = divisor3 >> 3; - divisor |= (__u32)divfrac[divisor3 & 0x7] << 14; - /* Deal with special cases for highest baud rates. */ - if (divisor == 1) - divisor = 0; - else if (divisor == 0x4001) - divisor = 1; - /* - * Set this bit to turn off a divide by 2.5 on baud rate generator - * This enables baud rates up to 12Mbaud but cannot reach below 1200 - * baud with this bit set - */ - divisor |= 0x00020000; - return divisor; -} - -static __u32 ftdi_2232h_baud_to_divisor(int baud) -{ - return ftdi_2232h_baud_base_to_divisor(baud, 120000000); -} - -#define set_mctrl(port, set) update_mctrl((port), (set), 0) -#define clear_mctrl(port, clear) update_mctrl((port), 0, (clear)) - -static int update_mctrl(struct usb_serial_port *port, unsigned int set, - unsigned int clear) -{ - struct ftdi_private *priv = usb_get_serial_port_data(port); - unsigned urb_value; - int rv; - - if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) { - dbg("%s - DTR|RTS not being set|cleared", __func__); - return 0; /* no change */ - } - - clear &= ~set; /* 'set' takes precedence over 'clear' */ - urb_value = 0; - if (clear & TIOCM_DTR) - urb_value |= FTDI_SIO_SET_DTR_LOW; - if (clear & TIOCM_RTS) - urb_value |= FTDI_SIO_SET_RTS_LOW; - if (set & TIOCM_DTR) - urb_value |= FTDI_SIO_SET_DTR_HIGH; - if (set & TIOCM_RTS) - urb_value |= FTDI_SIO_SET_RTS_HIGH; - rv = usb_control_msg(port->serial->dev, - usb_sndctrlpipe(port->serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, - FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, - urb_value, priv->interface, - NULL, 0, WDR_TIMEOUT); - if (rv < 0) { - dbg("%s Error from MODEM_CTRL urb: DTR %s, RTS %s", - __func__, - (set & TIOCM_DTR) ? "HIGH" : - (clear & TIOCM_DTR) ? "LOW" : "unchanged", - (set & TIOCM_RTS) ? "HIGH" : - (clear & TIOCM_RTS) ? "LOW" : "unchanged"); - } else { - dbg("%s - DTR %s, RTS %s", __func__, - (set & TIOCM_DTR) ? "HIGH" : - (clear & TIOCM_DTR) ? "LOW" : "unchanged", - (set & TIOCM_RTS) ? "HIGH" : - (clear & TIOCM_RTS) ? "LOW" : "unchanged"); - /* FIXME: locking on last_dtr_rts */ - priv->last_dtr_rts = (priv->last_dtr_rts & ~clear) | set; - } - return rv; -} - - -static __u32 get_ftdi_divisor(struct tty_struct *tty, - struct usb_serial_port *port) -{ - struct ftdi_private *priv = usb_get_serial_port_data(port); - __u32 div_value = 0; - int div_okay = 1; - int baud; - - /* - * The logic involved in setting the baudrate can be cleanly split into - * 3 steps. - * 1. Standard baud rates are set in tty->termios->c_cflag - * 2. If these are not enough, you can set any speed using alt_speed as - * follows: - * - set tty->termios->c_cflag speed to B38400 - * - set your real speed in tty->alt_speed; it gets ignored when - * alt_speed==0, (or) - * - call TIOCSSERIAL ioctl with (struct serial_struct) set as - * follows: - * flags & ASYNC_SPD_MASK == ASYNC_SPD_[HI, VHI, SHI, WARP], - * this just sets alt_speed to (HI: 57600, VHI: 115200, - * SHI: 230400, WARP: 460800) - * ** Steps 1, 2 are done courtesy of tty_get_baud_rate - * 3. You can also set baud rate by setting custom divisor as follows - * - set tty->termios->c_cflag speed to B38400 - * - call TIOCSSERIAL ioctl with (struct serial_struct) set as - * follows: - * o flags & ASYNC_SPD_MASK == ASYNC_SPD_CUST - * o custom_divisor set to baud_base / your_new_baudrate - * ** Step 3 is done courtesy of code borrowed from serial.c - * I should really spend some time and separate + move this common - * code to serial.c, it is replicated in nearly every serial driver - * you see. - */ - - /* 1. Get the baud rate from the tty settings, this observes - alt_speed hack */ - - baud = tty_get_baud_rate(tty); - dbg("%s - tty_get_baud_rate reports speed %d", __func__, baud); - - /* 2. Observe async-compatible custom_divisor hack, update baudrate - if needed */ - - if (baud == 38400 && - ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) && - (priv->custom_divisor)) { - baud = priv->baud_base / priv->custom_divisor; - dbg("%s - custom divisor %d sets baud rate to %d", - __func__, priv->custom_divisor, baud); - } - - /* 3. Convert baudrate to device-specific divisor */ - - if (!baud) - baud = 9600; - switch (priv->chip_type) { - case SIO: /* SIO chip */ - switch (baud) { - case 300: div_value = ftdi_sio_b300; break; - case 600: div_value = ftdi_sio_b600; break; - case 1200: div_value = ftdi_sio_b1200; break; - case 2400: div_value = ftdi_sio_b2400; break; - case 4800: div_value = ftdi_sio_b4800; break; - case 9600: div_value = ftdi_sio_b9600; break; - case 19200: div_value = ftdi_sio_b19200; break; - case 38400: div_value = ftdi_sio_b38400; break; - case 57600: div_value = ftdi_sio_b57600; break; - case 115200: div_value = ftdi_sio_b115200; break; - } /* baud */ - if (div_value == 0) { - dbg("%s - Baudrate (%d) requested is not supported", - __func__, baud); - div_value = ftdi_sio_b9600; - baud = 9600; - div_okay = 0; - } - break; - case FT8U232AM: /* 8U232AM chip */ - if (baud <= 3000000) { - div_value = ftdi_232am_baud_to_divisor(baud); - } else { - dbg("%s - Baud rate too high!", __func__); - baud = 9600; - div_value = ftdi_232am_baud_to_divisor(9600); - div_okay = 0; - } - break; - case FT232BM: /* FT232BM chip */ - case FT2232C: /* FT2232C chip */ - case FT232RL: /* FT232RL chip */ - case FTX: /* FT-X series */ - if (baud <= 3000000) { - __u16 product_id = le16_to_cpu( - port->serial->dev->descriptor.idProduct); - if (((FTDI_NDI_HUC_PID == product_id) || - (FTDI_NDI_SPECTRA_SCU_PID == product_id) || - (FTDI_NDI_FUTURE_2_PID == product_id) || - (FTDI_NDI_FUTURE_3_PID == product_id) || - (FTDI_NDI_AURORA_SCU_PID == product_id)) && - (baud == 19200)) { - baud = 1200000; - } - div_value = ftdi_232bm_baud_to_divisor(baud); - } else { - dbg("%s - Baud rate too high!", __func__); - div_value = ftdi_232bm_baud_to_divisor(9600); - div_okay = 0; - baud = 9600; - } - break; - case FT2232H: /* FT2232H chip */ - case FT4232H: /* FT4232H chip */ - case FT232H: /* FT232H chip */ - if ((baud <= 12000000) && (baud >= 1200)) { - div_value = ftdi_2232h_baud_to_divisor(baud); - } else if (baud < 1200) { - div_value = ftdi_232bm_baud_to_divisor(baud); - } else { - dbg("%s - Baud rate too high!", __func__); - div_value = ftdi_232bm_baud_to_divisor(9600); - div_okay = 0; - baud = 9600; - } - break; - } /* priv->chip_type */ - - if (div_okay) { - dbg("%s - Baud rate set to %d (divisor 0x%lX) on chip %s", - __func__, baud, (unsigned long)div_value, - ftdi_chip_name[priv->chip_type]); - } - - tty_encode_baud_rate(tty, baud, baud); - return div_value; -} - -static int change_speed(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct ftdi_private *priv = usb_get_serial_port_data(port); - __u16 urb_value; - __u16 urb_index; - __u32 urb_index_value; - int rv; - - urb_index_value = get_ftdi_divisor(tty, port); - urb_value = (__u16)urb_index_value; - urb_index = (__u16)(urb_index_value >> 16); - if ((priv->chip_type == FT2232C) || (priv->chip_type == FT2232H) || - (priv->chip_type == FT4232H) || (priv->chip_type == FT232H)) { - /* Probably the BM type needs the MSB of the encoded fractional - * divider also moved like for the chips above. Any infos? */ - urb_index = (__u16)((urb_index << 8) | priv->interface); - } - - rv = usb_control_msg(port->serial->dev, - usb_sndctrlpipe(port->serial->dev, 0), - FTDI_SIO_SET_BAUDRATE_REQUEST, - FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE, - urb_value, urb_index, - NULL, 0, WDR_SHORT_TIMEOUT); - return rv; -} - -static int write_latency_timer(struct usb_serial_port *port) -{ - struct ftdi_private *priv = usb_get_serial_port_data(port); - struct usb_device *udev = port->serial->dev; - int rv; - int l = priv->latency; - - if (priv->flags & ASYNC_LOW_LATENCY) - l = 1; - - dbg("%s: setting latency timer = %i", __func__, l); - - rv = usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - FTDI_SIO_SET_LATENCY_TIMER_REQUEST, - FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE, - l, priv->interface, - NULL, 0, WDR_TIMEOUT); - if (rv < 0) - dev_err(&port->dev, "Unable to write latency timer: %i\n", rv); - return rv; -} - -static int read_latency_timer(struct usb_serial_port *port) -{ - struct ftdi_private *priv = usb_get_serial_port_data(port); - struct usb_device *udev = port->serial->dev; - unsigned char *buf; - int rv; - - dbg("%s", __func__); - - buf = kmalloc(1, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - rv = usb_control_msg(udev, - usb_rcvctrlpipe(udev, 0), - FTDI_SIO_GET_LATENCY_TIMER_REQUEST, - FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE, - 0, priv->interface, - buf, 1, WDR_TIMEOUT); - if (rv < 0) - dev_err(&port->dev, "Unable to read latency timer: %i\n", rv); - else - priv->latency = buf[0]; - - kfree(buf); - - return rv; -} - -static int get_serial_info(struct usb_serial_port *port, - struct serial_struct __user *retinfo) -{ - struct ftdi_private *priv = usb_get_serial_port_data(port); - struct serial_struct tmp; - - if (!retinfo) - return -EFAULT; - memset(&tmp, 0, sizeof(tmp)); - tmp.flags = priv->flags; - tmp.baud_base = priv->baud_base; - tmp.custom_divisor = priv->custom_divisor; - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - return 0; -} - -static int set_serial_info(struct tty_struct *tty, - struct usb_serial_port *port, struct serial_struct __user *newinfo) -{ - struct ftdi_private *priv = usb_get_serial_port_data(port); - struct serial_struct new_serial; - struct ftdi_private old_priv; - - if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) - return -EFAULT; - - mutex_lock(&priv->cfg_lock); - old_priv = *priv; - - /* Do error checking and permission checking */ - - if (!capable(CAP_SYS_ADMIN)) { - if (((new_serial.flags & ~ASYNC_USR_MASK) != - (priv->flags & ~ASYNC_USR_MASK))) { - mutex_unlock(&priv->cfg_lock); - return -EPERM; - } - priv->flags = ((priv->flags & ~ASYNC_USR_MASK) | - (new_serial.flags & ASYNC_USR_MASK)); - priv->custom_divisor = new_serial.custom_divisor; - goto check_and_exit; - } - - if (new_serial.baud_base != priv->baud_base) { - mutex_unlock(&priv->cfg_lock); - return -EINVAL; - } - - /* Make the changes - these are privileged changes! */ - - priv->flags = ((priv->flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS)); - priv->custom_divisor = new_serial.custom_divisor; - - write_latency_timer(port); - -check_and_exit: - if ((old_priv.flags & ASYNC_SPD_MASK) != - (priv->flags & ASYNC_SPD_MASK)) { - if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - tty->alt_speed = 57600; - else if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - tty->alt_speed = 115200; - else if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) - tty->alt_speed = 230400; - else if ((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) - tty->alt_speed = 460800; - else - tty->alt_speed = 0; - } - if (((old_priv.flags & ASYNC_SPD_MASK) != - (priv->flags & ASYNC_SPD_MASK)) || - (((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) && - (old_priv.custom_divisor != priv->custom_divisor))) { - change_speed(tty, port); - mutex_unlock(&priv->cfg_lock); - } - else - mutex_unlock(&priv->cfg_lock); - return 0; -} - -static int get_lsr_info(struct usb_serial_port *port, - struct serial_struct __user *retinfo) -{ - struct ftdi_private *priv = usb_get_serial_port_data(port); - unsigned int result = 0; - - if (!retinfo) - return -EFAULT; - - if (priv->transmit_empty) - result = TIOCSER_TEMT; - - if (copy_to_user(retinfo, &result, sizeof(unsigned int))) - return -EFAULT; - return 0; -} - - -/* Determine type of FTDI chip based on USB config and descriptor. */ -static void ftdi_determine_type(struct usb_serial_port *port) -{ - struct ftdi_private *priv = usb_get_serial_port_data(port); - struct usb_serial *serial = port->serial; - struct usb_device *udev = serial->dev; - unsigned version; - unsigned interfaces; - - /* Assume it is not the original SIO device for now. */ - priv->baud_base = 48000000 / 2; - - version = le16_to_cpu(udev->descriptor.bcdDevice); - interfaces = udev->actconfig->desc.bNumInterfaces; - dbg("%s: bcdDevice = 0x%x, bNumInterfaces = %u", __func__, - version, interfaces); - if (interfaces > 1) { - int inter; - - /* Multiple interfaces.*/ - if (version == 0x0800) { - priv->chip_type = FT4232H; - /* Hi-speed - baud clock runs at 120MHz */ - priv->baud_base = 120000000 / 2; - } else if (version == 0x0700) { - priv->chip_type = FT2232H; - /* Hi-speed - baud clock runs at 120MHz */ - priv->baud_base = 120000000 / 2; - } else - priv->chip_type = FT2232C; - - /* Determine interface code. */ - inter = serial->interface->altsetting->desc.bInterfaceNumber; - if (inter == 0) { - priv->interface = INTERFACE_A; - } else if (inter == 1) { - priv->interface = INTERFACE_B; - } else if (inter == 2) { - priv->interface = INTERFACE_C; - } else if (inter == 3) { - priv->interface = INTERFACE_D; - } - /* BM-type devices have a bug where bcdDevice gets set - * to 0x200 when iSerialNumber is 0. */ - if (version < 0x500) { - dbg("%s: something fishy - bcdDevice too low for multi-interface device", - __func__); - } - } else if (version < 0x200) { - /* Old device. Assume it's the original SIO. */ - priv->chip_type = SIO; - priv->baud_base = 12000000 / 16; - } else if (version < 0x400) { - /* Assume it's an FT8U232AM (or FT8U245AM) */ - /* (It might be a BM because of the iSerialNumber bug, - * but it will still work as an AM device.) */ - priv->chip_type = FT8U232AM; - } else if (version < 0x600) { - /* Assume it's an FT232BM (or FT245BM) */ - priv->chip_type = FT232BM; - } else if (version < 0x900) { - /* Assume it's an FT232RL */ - priv->chip_type = FT232RL; - } else if (version < 0x1000) { - /* Assume it's an FT232H */ - priv->chip_type = FT232H; - } else { - /* Assume it's an FT-X series device */ - priv->chip_type = FTX; - } - - dev_info(&udev->dev, "Detected %s\n", ftdi_chip_name[priv->chip_type]); -} - - -/* Determine the maximum packet size for the device. This depends on the chip - * type and the USB host capabilities. The value should be obtained from the - * device descriptor as the chip will use the appropriate values for the host.*/ -static void ftdi_set_max_packet_size(struct usb_serial_port *port) -{ - struct ftdi_private *priv = usb_get_serial_port_data(port); - struct usb_serial *serial = port->serial; - struct usb_device *udev = serial->dev; - - struct usb_interface *interface = serial->interface; - struct usb_endpoint_descriptor *ep_desc = &interface->cur_altsetting->endpoint[1].desc; - - unsigned num_endpoints; - int i; - - num_endpoints = interface->cur_altsetting->desc.bNumEndpoints; - dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints); - - /* NOTE: some customers have programmed FT232R/FT245R devices - * with an endpoint size of 0 - not good. In this case, we - * want to override the endpoint descriptor setting and use a - * value of 64 for wMaxPacketSize */ - for (i = 0; i < num_endpoints; i++) { - dev_info(&udev->dev, "Endpoint %d MaxPacketSize %d\n", i+1, - interface->cur_altsetting->endpoint[i].desc.wMaxPacketSize); - ep_desc = &interface->cur_altsetting->endpoint[i].desc; - if (ep_desc->wMaxPacketSize == 0) { - ep_desc->wMaxPacketSize = cpu_to_le16(0x40); - dev_info(&udev->dev, "Overriding wMaxPacketSize on endpoint %d\n", i); - } - } - - /* set max packet size based on descriptor */ - priv->max_packet_size = usb_endpoint_maxp(ep_desc); - - dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size); -} - - -/* - * *************************************************************************** - * Sysfs Attribute - * *************************************************************************** - */ - -static ssize_t show_latency_timer(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct usb_serial_port *port = to_usb_serial_port(dev); - struct ftdi_private *priv = usb_get_serial_port_data(port); - if (priv->flags & ASYNC_LOW_LATENCY) - return sprintf(buf, "1\n"); - else - return sprintf(buf, "%i\n", priv->latency); -} - - -/* Write a new value of the latency timer, in units of milliseconds. */ -static ssize_t store_latency_timer(struct device *dev, - struct device_attribute *attr, const char *valbuf, - size_t count) -{ - struct usb_serial_port *port = to_usb_serial_port(dev); - struct ftdi_private *priv = usb_get_serial_port_data(port); - int v = simple_strtoul(valbuf, NULL, 10); - int rv; - - priv->latency = v; - rv = write_latency_timer(port); - if (rv < 0) - return -EIO; - return count; -} - -/* Write an event character directly to the FTDI register. The ASCII - value is in the low 8 bits, with the enable bit in the 9th bit. */ -static ssize_t store_event_char(struct device *dev, - struct device_attribute *attr, const char *valbuf, size_t count) -{ - struct usb_serial_port *port = to_usb_serial_port(dev); - struct ftdi_private *priv = usb_get_serial_port_data(port); - struct usb_device *udev = port->serial->dev; - int v = simple_strtoul(valbuf, NULL, 10); - int rv; - - dbg("%s: setting event char = %i", __func__, v); - - rv = usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), - FTDI_SIO_SET_EVENT_CHAR_REQUEST, - FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE, - v, priv->interface, - NULL, 0, WDR_TIMEOUT); - if (rv < 0) { - dbg("Unable to write event character: %i", rv); - return -EIO; - } - - return count; -} - -static DEVICE_ATTR(latency_timer, S_IWUSR | S_IRUGO, show_latency_timer, - store_latency_timer); -static DEVICE_ATTR(event_char, S_IWUSR, NULL, store_event_char); - -static int create_sysfs_attrs(struct usb_serial_port *port) -{ - struct ftdi_private *priv = usb_get_serial_port_data(port); - int retval = 0; - - dbg("%s", __func__); - - /* XXX I've no idea if the original SIO supports the event_char - * sysfs parameter, so I'm playing it safe. */ - if (priv->chip_type != SIO) { - dbg("sysfs attributes for %s", ftdi_chip_name[priv->chip_type]); - retval = device_create_file(&port->dev, &dev_attr_event_char); - if ((!retval) && - (priv->chip_type == FT232BM || - priv->chip_type == FT2232C || - priv->chip_type == FT232RL || - priv->chip_type == FT2232H || - priv->chip_type == FT4232H || - priv->chip_type == FT232H || - priv->chip_type == FTX)) { - retval = device_create_file(&port->dev, - &dev_attr_latency_timer); - } - } - return retval; -} - -static void remove_sysfs_attrs(struct usb_serial_port *port) -{ - struct ftdi_private *priv = usb_get_serial_port_data(port); - - dbg("%s", __func__); - - /* XXX see create_sysfs_attrs */ - if (priv->chip_type != SIO) { - device_remove_file(&port->dev, &dev_attr_event_char); - if (priv->chip_type == FT232BM || - priv->chip_type == FT2232C || - priv->chip_type == FT232RL || - priv->chip_type == FT2232H || - priv->chip_type == FT4232H || - priv->chip_type == FT232H || - priv->chip_type == FTX) { - device_remove_file(&port->dev, &dev_attr_latency_timer); - } - } - -} - -/* - * *************************************************************************** - * FTDI driver specific functions - * *************************************************************************** - */ - -/* Probe function to check for special devices */ -static int ftdi_sio_probe(struct usb_serial *serial, - const struct usb_device_id *id) -{ - struct ftdi_sio_quirk *quirk = - (struct ftdi_sio_quirk *)id->driver_info; - - if (quirk && quirk->probe) { - int ret = quirk->probe(serial); - if (ret != 0) - return ret; - } - - usb_set_serial_data(serial, (void *)id->driver_info); - - return 0; -} - -static int ftdi_sio_port_probe(struct usb_serial_port *port) -{ - struct ftdi_private *priv; - struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial); - - - dbg("%s", __func__); - - priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL); - if (!priv) { - dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", __func__, - sizeof(struct ftdi_private)); - return -ENOMEM; - } - - kref_init(&priv->kref); - mutex_init(&priv->cfg_lock); - memset(&priv->icount, 0x00, sizeof(priv->icount)); - init_waitqueue_head(&priv->delta_msr_wait); - - priv->flags = ASYNC_LOW_LATENCY; - priv->dev_gone = false; - - if (quirk && quirk->port_probe) - quirk->port_probe(priv); - - priv->port = port; - usb_set_serial_port_data(port, priv); - - ftdi_determine_type(port); - ftdi_set_max_packet_size(port); - if (read_latency_timer(port) < 0) - priv->latency = 16; - write_latency_timer(port); - create_sysfs_attrs(port); - return 0; -} - -/* Setup for the USB-UIRT device, which requires hardwired - * baudrate (38400 gets mapped to 312500) */ -/* Called from usbserial:serial_probe */ -static void ftdi_USB_UIRT_setup(struct ftdi_private *priv) -{ - dbg("%s", __func__); - - priv->flags |= ASYNC_SPD_CUST; - priv->custom_divisor = 77; - priv->force_baud = 38400; -} - -/* Setup for the HE-TIRA1 device, which requires hardwired - * baudrate (38400 gets mapped to 100000) and RTS-CTS enabled. */ - -static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv) -{ - dbg("%s", __func__); - - priv->flags |= ASYNC_SPD_CUST; - priv->custom_divisor = 240; - priv->force_baud = 38400; - priv->force_rtscts = 1; -} - -/* - * Module parameter to control latency timer for NDI FTDI-based USB devices. - * If this value is not set in /etc/modprobe.d/ its value will be set - * to 1ms. - */ -static int ndi_latency_timer = 1; - -/* Setup for the NDI FTDI-based USB devices, which requires hardwired - * baudrate (19200 gets mapped to 1200000). - * - * Called from usbserial:serial_probe. - */ -static int ftdi_NDI_device_setup(struct usb_serial *serial) -{ - struct usb_device *udev = serial->dev; - int latency = ndi_latency_timer; - - if (latency == 0) - latency = 1; - if (latency > 99) - latency = 99; - - dbg("%s setting NDI device latency to %d", __func__, latency); - dev_info(&udev->dev, "NDI device with a latency value of %d", latency); - - /* FIXME: errors are not returned */ - usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - FTDI_SIO_SET_LATENCY_TIMER_REQUEST, - FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE, - latency, 0, NULL, 0, WDR_TIMEOUT); - return 0; -} - -/* - * First port on JTAG adaptors such as Olimex arm-usb-ocd or the FIC/OpenMoko - * Neo1973 Debug Board is reserved for JTAG interface and can be accessed from - * userspace using openocd. - */ -static int ftdi_jtag_probe(struct usb_serial *serial) -{ - struct usb_device *udev = serial->dev; - struct usb_interface *interface = serial->interface; - - dbg("%s", __func__); - - if (interface == udev->actconfig->interface[0]) { - dev_info(&udev->dev, - "Ignoring serial port reserved for JTAG\n"); - return -ENODEV; - } - - return 0; -} - -static int ftdi_8u2232c_probe(struct usb_serial *serial) -{ - struct usb_device *udev = serial->dev; - - dbg("%s", __func__); - - if ((udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems")) || - (udev->product && !strcmp(udev->product, "BeagleBone/XDS100"))) - return ftdi_jtag_probe(serial); - - return 0; -} - -/* - * First and second port on STMCLiteadaptors is reserved for JTAG interface - * and the forth port for pio - */ -static int ftdi_stmclite_probe(struct usb_serial *serial) -{ - struct usb_device *udev = serial->dev; - struct usb_interface *interface = serial->interface; - - dbg("%s", __func__); - - if (interface == udev->actconfig->interface[2]) - return 0; - - dev_info(&udev->dev, "Ignoring serial port reserved for JTAG\n"); - - return -ENODEV; -} - -/* - * The Matrix Orbital VK204-25-USB has an invalid IN endpoint. - * We have to correct it if we want to read from it. - */ -static int ftdi_mtxorb_hack_setup(struct usb_serial *serial) -{ - struct usb_host_endpoint *ep = serial->dev->ep_in[1]; - struct usb_endpoint_descriptor *ep_desc = &ep->desc; - - if (ep->enabled && ep_desc->wMaxPacketSize == 0) { - ep_desc->wMaxPacketSize = cpu_to_le16(0x40); - dev_info(&serial->dev->dev, - "Fixing invalid wMaxPacketSize on read pipe\n"); - } - - return 0; -} - -static void ftdi_sio_priv_release(struct kref *k) -{ - struct ftdi_private *priv = container_of(k, struct ftdi_private, kref); - - kfree(priv); -} - -static int ftdi_sio_port_remove(struct usb_serial_port *port) -{ - struct ftdi_private *priv = usb_get_serial_port_data(port); - - dbg("%s", __func__); - - priv->dev_gone = true; - wake_up_interruptible_all(&priv->delta_msr_wait); - - remove_sysfs_attrs(port); - - kref_put(&priv->kref, ftdi_sio_priv_release); - - return 0; -} - -static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct ktermios dummy; - struct usb_device *dev = port->serial->dev; - struct ftdi_private *priv = usb_get_serial_port_data(port); - int result; - - dbg("%s", __func__); - - /* No error checking for this (will get errors later anyway) */ - /* See ftdi_sio.h for description of what is reset */ - usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, - FTDI_SIO_RESET_SIO, - priv->interface, NULL, 0, WDR_TIMEOUT); - - /* Termios defaults are set by usb_serial_init. We don't change - port->tty->termios - this would lose speed settings, etc. - This is same behaviour as serial.c/rs_open() - Kuba */ - - /* ftdi_set_termios will send usb control messages */ - if (tty) { - memset(&dummy, 0, sizeof(dummy)); - ftdi_set_termios(tty, port, &dummy); - } - - /* Start reading from the device */ - result = usb_serial_generic_open(tty, port); - if (!result) - kref_get(&priv->kref); - - return result; -} - -static void ftdi_dtr_rts(struct usb_serial_port *port, int on) -{ - struct ftdi_private *priv = usb_get_serial_port_data(port); - - mutex_lock(&port->serial->disc_mutex); - if (!port->serial->disconnected) { - /* Disable flow control */ - if (!on && usb_control_msg(port->serial->dev, - usb_sndctrlpipe(port->serial->dev, 0), - FTDI_SIO_SET_FLOW_CTRL_REQUEST, - FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, priv->interface, NULL, 0, - WDR_TIMEOUT) < 0) { - dev_err(&port->dev, "error from flowcontrol urb\n"); - } - /* drop RTS and DTR */ - if (on) - set_mctrl(port, TIOCM_DTR | TIOCM_RTS); - else - clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); - } - mutex_unlock(&port->serial->disc_mutex); -} - -/* - * usbserial:__serial_close only calls ftdi_close if the point is open - * - * This only gets called when it is the last close - */ -static void ftdi_close(struct usb_serial_port *port) -{ - struct ftdi_private *priv = usb_get_serial_port_data(port); - - dbg("%s", __func__); - - usb_serial_generic_close(port); - kref_put(&priv->kref, ftdi_sio_priv_release); -} - -/* The SIO requires the first byte to have: - * B0 1 - * B1 0 - * B2..7 length of message excluding byte 0 - * - * The new devices do not require this byte - */ -static int ftdi_prepare_write_buffer(struct usb_serial_port *port, - void *dest, size_t size) -{ - struct ftdi_private *priv; - int count; - unsigned long flags; - - priv = usb_get_serial_port_data(port); - - if (priv->chip_type == SIO) { - unsigned char *buffer = dest; - int i, len, c; - - count = 0; - spin_lock_irqsave(&port->lock, flags); - for (i = 0; i < size - 1; i += priv->max_packet_size) { - len = min_t(int, size - i, priv->max_packet_size) - 1; - c = kfifo_out(&port->write_fifo, &buffer[i + 1], len); - if (!c) - break; - priv->icount.tx += c; - buffer[i] = (c << 2) + 1; - count += c + 1; - } - spin_unlock_irqrestore(&port->lock, flags); - } else { - count = kfifo_out_locked(&port->write_fifo, dest, size, - &port->lock); - priv->icount.tx += count; - } - - return count; -} - -#define FTDI_RS_ERR_MASK (FTDI_RS_BI | FTDI_RS_PE | FTDI_RS_FE | FTDI_RS_OE) - -static int ftdi_process_packet(struct tty_struct *tty, - struct usb_serial_port *port, struct ftdi_private *priv, - char *packet, int len) -{ - int i; - char status; - char flag; - char *ch; - - dbg("%s - port %d", __func__, port->number); - - if (len < 2) { - dbg("malformed packet"); - return 0; - } - - /* Compare new line status to the old one, signal if different/ - N.B. packet may be processed more than once, but differences - are only processed once. */ - status = packet[0] & FTDI_STATUS_B0_MASK; - if (status != priv->prev_status) { - char diff_status = status ^ priv->prev_status; - - if (diff_status & FTDI_RS0_CTS) - priv->icount.cts++; - if (diff_status & FTDI_RS0_DSR) - priv->icount.dsr++; - if (diff_status & FTDI_RS0_RI) - priv->icount.rng++; - if (diff_status & FTDI_RS0_RLSD) - priv->icount.dcd++; - - wake_up_interruptible_all(&priv->delta_msr_wait); - priv->prev_status = status; - } - - flag = TTY_NORMAL; - if (packet[1] & FTDI_RS_ERR_MASK) { - /* Break takes precedence over parity, which takes precedence - * over framing errors */ - if (packet[1] & FTDI_RS_BI) { - flag = TTY_BREAK; - priv->icount.brk++; - usb_serial_handle_break(port); - } else if (packet[1] & FTDI_RS_PE) { - flag = TTY_PARITY; - priv->icount.parity++; - } else if (packet[1] & FTDI_RS_FE) { - flag = TTY_FRAME; - priv->icount.frame++; - } - /* Overrun is special, not associated with a char */ - if (packet[1] & FTDI_RS_OE) { - priv->icount.overrun++; - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } - } - - /* save if the transmitter is empty or not */ - if (packet[1] & FTDI_RS_TEMT) - priv->transmit_empty = 1; - else - priv->transmit_empty = 0; - - len -= 2; - if (!len) - return 0; /* status only */ - priv->icount.rx += len; - ch = packet + 2; - - if (port->port.console && port->sysrq) { - for (i = 0; i < len; i++, ch++) { - if (!usb_serial_handle_sysrq_char(port, *ch)) - tty_insert_flip_char(tty, *ch, flag); - } - } else { - tty_insert_flip_string_fixed_flag(tty, ch, flag, len); - } - - return len; -} - -static void ftdi_process_read_urb(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct tty_struct *tty; - struct ftdi_private *priv = usb_get_serial_port_data(port); - char *data = (char *)urb->transfer_buffer; - int i; - int len; - int count = 0; - - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - - for (i = 0; i < urb->actual_length; i += priv->max_packet_size) { - len = min_t(int, urb->actual_length - i, priv->max_packet_size); - count += ftdi_process_packet(tty, port, priv, &data[i], len); - } - - if (count) - tty_flip_buffer_push(tty); - tty_kref_put(tty); -} - -static void ftdi_break_ctl(struct tty_struct *tty, int break_state) -{ - struct usb_serial_port *port = tty->driver_data; - struct ftdi_private *priv = usb_get_serial_port_data(port); - __u16 urb_value; - - /* break_state = -1 to turn on break, and 0 to turn off break */ - /* see drivers/char/tty_io.c to see it used */ - /* last_set_data_urb_value NEVER has the break bit set in it */ - - if (break_state) - urb_value = priv->last_set_data_urb_value | FTDI_SIO_SET_BREAK; - else - urb_value = priv->last_set_data_urb_value; - - if (usb_control_msg(port->serial->dev, - usb_sndctrlpipe(port->serial->dev, 0), - FTDI_SIO_SET_DATA_REQUEST, - FTDI_SIO_SET_DATA_REQUEST_TYPE, - urb_value , priv->interface, - NULL, 0, WDR_TIMEOUT) < 0) { - dev_err(&port->dev, "%s FAILED to enable/disable break state " - "(state was %d)\n", __func__, break_state); - } - - dbg("%s break state is %d - urb is %d", __func__, - break_state, urb_value); - -} - -/* old_termios contains the original termios settings and tty->termios contains - * the new setting to be used - * WARNING: set_termios calls this with old_termios in kernel space - */ -static void ftdi_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) -{ - struct usb_device *dev = port->serial->dev; - struct ftdi_private *priv = usb_get_serial_port_data(port); - struct ktermios *termios = tty->termios; - unsigned int cflag = termios->c_cflag; - __u16 urb_value; /* will hold the new flags */ - - /* Added for xon/xoff support */ - unsigned int iflag = termios->c_iflag; - unsigned char vstop; - unsigned char vstart; - - dbg("%s", __func__); - - /* Force baud rate if this device requires it, unless it is set to - B0. */ - if (priv->force_baud && ((termios->c_cflag & CBAUD) != B0)) { - dbg("%s: forcing baud rate for this device", __func__); - tty_encode_baud_rate(tty, priv->force_baud, - priv->force_baud); - } - - /* Force RTS-CTS if this device requires it. */ - if (priv->force_rtscts) { - dbg("%s: forcing rtscts for this device", __func__); - termios->c_cflag |= CRTSCTS; - } - - cflag = termios->c_cflag; - - if (old_termios == 0) - goto no_skip; - - if (old_termios->c_cflag == termios->c_cflag - && old_termios->c_ispeed == termios->c_ispeed - && old_termios->c_ospeed == termios->c_ospeed) - goto no_c_cflag_changes; - - /* NOTE These routines can get interrupted by - ftdi_sio_read_bulk_callback - need to examine what this means - - don't see any problems yet */ - - if ((old_termios->c_cflag & (CSIZE|PARODD|PARENB|CMSPAR|CSTOPB)) == - (termios->c_cflag & (CSIZE|PARODD|PARENB|CMSPAR|CSTOPB))) - goto no_data_parity_stop_changes; - -no_skip: - /* Set number of data bits, parity, stop bits */ - - urb_value = 0; - urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 : - FTDI_SIO_SET_DATA_STOP_BITS_1); - if (cflag & PARENB) { - if (cflag & CMSPAR) - urb_value |= cflag & PARODD ? - FTDI_SIO_SET_DATA_PARITY_MARK : - FTDI_SIO_SET_DATA_PARITY_SPACE; - else - urb_value |= cflag & PARODD ? - FTDI_SIO_SET_DATA_PARITY_ODD : - FTDI_SIO_SET_DATA_PARITY_EVEN; - } else { - urb_value |= FTDI_SIO_SET_DATA_PARITY_NONE; - } - if (cflag & CSIZE) { - switch (cflag & CSIZE) { - case CS7: urb_value |= 7; dbg("Setting CS7"); break; - case CS8: urb_value |= 8; dbg("Setting CS8"); break; - default: - dev_err(&port->dev, "CSIZE was set but not CS7-CS8\n"); - } - } - - /* This is needed by the break command since it uses the same command - - but is or'ed with this value */ - priv->last_set_data_urb_value = urb_value; - - if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - FTDI_SIO_SET_DATA_REQUEST, - FTDI_SIO_SET_DATA_REQUEST_TYPE, - urb_value , priv->interface, - NULL, 0, WDR_SHORT_TIMEOUT) < 0) { - dev_err(&port->dev, "%s FAILED to set " - "databits/stopbits/parity\n", __func__); - } - - /* Now do the baudrate */ -no_data_parity_stop_changes: - if ((cflag & CBAUD) == B0) { - /* Disable flow control */ - if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - FTDI_SIO_SET_FLOW_CTRL_REQUEST, - FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, priv->interface, - NULL, 0, WDR_TIMEOUT) < 0) { - dev_err(&port->dev, - "%s error from disable flowcontrol urb\n", - __func__); - } - /* Drop RTS and DTR */ - clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); - } else { - /* set the baudrate determined before */ - mutex_lock(&priv->cfg_lock); - if (change_speed(tty, port)) - dev_err(&port->dev, "%s urb failed to set baudrate\n", - __func__); - mutex_unlock(&priv->cfg_lock); - /* Ensure RTS and DTR are raised when baudrate changed from 0 */ - if (!old_termios || (old_termios->c_cflag & CBAUD) == B0) - set_mctrl(port, TIOCM_DTR | TIOCM_RTS); - } - - /* Set flow control */ - /* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */ -no_c_cflag_changes: - if (cflag & CRTSCTS) { - dbg("%s Setting to CRTSCTS flow control", __func__); - if (usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), - FTDI_SIO_SET_FLOW_CTRL_REQUEST, - FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0 , (FTDI_SIO_RTS_CTS_HS | priv->interface), - NULL, 0, WDR_TIMEOUT) < 0) { - dev_err(&port->dev, - "urb failed to set to rts/cts flow control\n"); - } - - } else { - /* - * Xon/Xoff code - * - * Check the IXOFF status in the iflag component of the - * termios structure. If IXOFF is not set, the pre-xon/xoff - * code is executed. - */ - if (iflag & IXOFF) { - dbg("%s request to enable xonxoff iflag=%04x", - __func__, iflag); - /* Try to enable the XON/XOFF on the ftdi_sio - * Set the vstart and vstop -- could have been done up - * above where a lot of other dereferencing is done but - * that would be very inefficient as vstart and vstop - * are not always needed. - */ - vstart = termios->c_cc[VSTART]; - vstop = termios->c_cc[VSTOP]; - urb_value = (vstop << 8) | (vstart); - - if (usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), - FTDI_SIO_SET_FLOW_CTRL_REQUEST, - FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - urb_value , (FTDI_SIO_XON_XOFF_HS - | priv->interface), - NULL, 0, WDR_TIMEOUT) < 0) { - dev_err(&port->dev, "urb failed to set to " - "xon/xoff flow control\n"); - } - } else { - /* else clause to only run if cflag ! CRTSCTS and iflag - * ! XOFF. CHECKME Assuming XON/XOFF handled by tty - * stack - not by device */ - dbg("%s Turning off hardware flow control", __func__); - if (usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), - FTDI_SIO_SET_FLOW_CTRL_REQUEST, - FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, priv->interface, - NULL, 0, WDR_TIMEOUT) < 0) { - dev_err(&port->dev, - "urb failed to clear flow control\n"); - } - } - - } -} - -static int ftdi_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct ftdi_private *priv = usb_get_serial_port_data(port); - unsigned char *buf; - int len; - int ret; - - dbg("%s TIOCMGET", __func__); - - buf = kmalloc(2, GFP_KERNEL); - if (!buf) - return -ENOMEM; - /* - * The 8U232AM returns a two byte value (the SIO a 1 byte value) in - * the same format as the data returned from the in point. - */ - switch (priv->chip_type) { - case SIO: - len = 1; - break; - case FT8U232AM: - case FT232BM: - case FT2232C: - case FT232RL: - case FT2232H: - case FT4232H: - case FT232H: - case FTX: - len = 2; - break; - default: - ret = -EFAULT; - goto out; - } - - ret = usb_control_msg(port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0), - FTDI_SIO_GET_MODEM_STATUS_REQUEST, - FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, - 0, priv->interface, - buf, len, WDR_TIMEOUT); - if (ret < 0) - goto out; - - ret = (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) | - (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) | - (buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) | - (buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0) | - priv->last_dtr_rts; -out: - kfree(buf); - return ret; -} - -static int ftdi_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - dbg("%s TIOCMSET", __func__); - return update_mctrl(port, set, clear); -} - -static int ftdi_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct ftdi_private *priv = usb_get_serial_port_data(port); - struct async_icount *ic = &priv->icount; - - icount->cts = ic->cts; - icount->dsr = ic->dsr; - icount->rng = ic->rng; - icount->dcd = ic->dcd; - icount->tx = ic->tx; - icount->rx = ic->rx; - icount->frame = ic->frame; - icount->parity = ic->parity; - icount->overrun = ic->overrun; - icount->brk = ic->brk; - icount->buf_overrun = ic->buf_overrun; - return 0; -} - -static int ftdi_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - struct ftdi_private *priv = usb_get_serial_port_data(port); - struct async_icount cnow; - struct async_icount cprev; - - dbg("%s cmd 0x%04x", __func__, cmd); - - /* Based on code from acm.c and others */ - switch (cmd) { - - case TIOCGSERIAL: /* gets serial port data */ - return get_serial_info(port, - (struct serial_struct __user *) arg); - - case TIOCSSERIAL: /* sets serial port data */ - return set_serial_info(tty, port, - (struct serial_struct __user *) arg); - - /* - * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - * - mask passed in arg for lines of interest - * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) - * Caller should use TIOCGICOUNT to see which one it was. - * - * This code is borrowed from linux/drivers/char/serial.c - */ - case TIOCMIWAIT: - cprev = priv->icount; - while (!priv->dev_gone) { - interruptible_sleep_on(&priv->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - cnow = priv->icount; - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { - return 0; - } - cprev = cnow; - } - return -EIO; - break; - case TIOCSERGETLSR: - return get_lsr_info(port, (struct serial_struct __user *)arg); - break; - default: - break; - } - /* This is not necessarily an error - turns out the higher layers - * will do some ioctls themselves (see comment above) - */ - dbg("%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h", __func__, cmd); - return -ENOIOCTLCMD; -} - -static int __init ftdi_init(void) -{ - int retval; - - dbg("%s", __func__); - if (vendor > 0 && product > 0) { - /* Add user specified VID/PID to reserved element of table. */ - int i; - for (i = 0; id_table_combined[i].idVendor; i++) - ; - id_table_combined[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE; - id_table_combined[i].idVendor = vendor; - id_table_combined[i].idProduct = product; - } - retval = usb_serial_register_drivers(&ftdi_driver, serial_drivers); - if (retval == 0) - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return retval; -} - -static void __exit ftdi_exit(void) -{ - dbg("%s", __func__); - - usb_serial_deregister_drivers(&ftdi_driver, serial_drivers); -} - - -module_init(ftdi_init); -module_exit(ftdi_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); -module_param(vendor, ushort, 0); -MODULE_PARM_DESC(vendor, "User specified vendor ID (default=" - __MODULE_STRING(FTDI_VID)")"); -module_param(product, ushort, 0); -MODULE_PARM_DESC(product, "User specified product ID"); - -module_param(ndi_latency_timer, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(ndi_latency_timer, "NDI device latency timer override"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/ftdi_sio.h b/ANDROID_3.4.5/drivers/usb/serial/ftdi_sio.h deleted file mode 100644 index ed58c6fa..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/ftdi_sio.h +++ /dev/null @@ -1,564 +0,0 @@ -/* - * Driver definitions for the FTDI USB Single Port Serial Converter - - * known as FTDI_SIO (Serial Input/Output application of the chipset) - * - * For USB vendor/product IDs (VID/PID), please see ftdi_sio_ids.h - * - * - * The example I have is known as the USC-1000 which is available from - * http://www.dse.co.nz - cat no XH4214 It looks similar to this: - * http://www.dansdata.com/usbser.htm but I can't be sure There are other - * USC-1000s which don't look like my device though so beware! - * - * The device is based on the FTDI FT8U100AX chip. It has a DB25 on one side, - * USB on the other. - * - * Thanx to FTDI (http://www.ftdichip.com) for so kindly providing details - * of the protocol required to talk to the device and ongoing assistence - * during development. - * - * Bill Ryder - bryder@sgi.com formerly of Silicon Graphics, Inc.- wrote the - * FTDI_SIO implementation. - * - */ - -/* Commands */ -#define FTDI_SIO_RESET 0 /* Reset the port */ -#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ -#define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */ -#define FTDI_SIO_SET_BAUD_RATE 3 /* Set baud rate */ -#define FTDI_SIO_SET_DATA 4 /* Set the data characteristics of - the port */ -#define FTDI_SIO_GET_MODEM_STATUS 5 /* Retrieve current value of modem - status register */ -#define FTDI_SIO_SET_EVENT_CHAR 6 /* Set the event character */ -#define FTDI_SIO_SET_ERROR_CHAR 7 /* Set the error character */ -#define FTDI_SIO_SET_LATENCY_TIMER 9 /* Set the latency timer */ -#define FTDI_SIO_GET_LATENCY_TIMER 10 /* Get the latency timer */ - -/* Interface indices for FT2232, FT2232H and FT4232H devices */ -#define INTERFACE_A 1 -#define INTERFACE_B 2 -#define INTERFACE_C 3 -#define INTERFACE_D 4 - - -/* - * BmRequestType: 1100 0000b - * bRequest: FTDI_E2_READ - * wValue: 0 - * wIndex: Address of word to read - * wLength: 2 - * Data: Will return a word of data from E2Address - * - */ - -/* Port Identifier Table */ -#define PIT_DEFAULT 0 /* SIOA */ -#define PIT_SIOA 1 /* SIOA */ -/* The device this driver is tested with one has only one port */ -#define PIT_SIOB 2 /* SIOB */ -#define PIT_PARALLEL 3 /* Parallel */ - -/* FTDI_SIO_RESET */ -#define FTDI_SIO_RESET_REQUEST FTDI_SIO_RESET -#define FTDI_SIO_RESET_REQUEST_TYPE 0x40 -#define FTDI_SIO_RESET_SIO 0 -#define FTDI_SIO_RESET_PURGE_RX 1 -#define FTDI_SIO_RESET_PURGE_TX 2 - -/* - * BmRequestType: 0100 0000B - * bRequest: FTDI_SIO_RESET - * wValue: Control Value - * 0 = Reset SIO - * 1 = Purge RX buffer - * 2 = Purge TX buffer - * wIndex: Port - * wLength: 0 - * Data: None - * - * The Reset SIO command has this effect: - * - * Sets flow control set to 'none' - * Event char = $0D - * Event trigger = disabled - * Purge RX buffer - * Purge TX buffer - * Clear DTR - * Clear RTS - * baud and data format not reset - * - * The Purge RX and TX buffer commands affect nothing except the buffers - * - */ - -/* FTDI_SIO_SET_BAUDRATE */ -#define FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE 0x40 -#define FTDI_SIO_SET_BAUDRATE_REQUEST 3 - -/* - * BmRequestType: 0100 0000B - * bRequest: FTDI_SIO_SET_BAUDRATE - * wValue: BaudDivisor value - see below - * wIndex: Port - * wLength: 0 - * Data: None - * The BaudDivisor values are calculated as follows: - * - BaseClock is either 12000000 or 48000000 depending on the device. - * FIXME: I wish I knew how to detect old chips to select proper base clock! - * - BaudDivisor is a fixed point number encoded in a funny way. - * (--WRONG WAY OF THINKING--) - * BaudDivisor is a fixed point number encoded with following bit weighs: - * (-2)(-1)(13..0). It is a radical with a denominator of 4, so values - * end with 0.0 (00...), 0.25 (10...), 0.5 (01...), and 0.75 (11...). - * (--THE REALITY--) - * The both-bits-set has quite different meaning from 0.75 - the chip - * designers have decided it to mean 0.125 instead of 0.75. - * This info looked up in FTDI application note "FT8U232 DEVICES \ Data Rates - * and Flow Control Consideration for USB to RS232". - * - BaudDivisor = (BaseClock / 16) / BaudRate, where the (=) operation should - * automagically re-encode the resulting value to take fractions into - * consideration. - * As all values are integers, some bit twiddling is in order: - * BaudDivisor = (BaseClock / 16 / BaudRate) | - * (((BaseClock / 2 / BaudRate) & 4) ? 0x4000 // 0.5 - * : ((BaseClock / 2 / BaudRate) & 2) ? 0x8000 // 0.25 - * : ((BaseClock / 2 / BaudRate) & 1) ? 0xc000 // 0.125 - * : 0) - * - * For the FT232BM, a 17th divisor bit was introduced to encode the multiples - * of 0.125 missing from the FT8U232AM. Bits 16 to 14 are coded as follows - * (the first four codes are the same as for the FT8U232AM, where bit 16 is - * always 0): - * 000 - add .000 to divisor - * 001 - add .500 to divisor - * 010 - add .250 to divisor - * 011 - add .125 to divisor - * 100 - add .375 to divisor - * 101 - add .625 to divisor - * 110 - add .750 to divisor - * 111 - add .875 to divisor - * Bits 15 to 0 of the 17-bit divisor are placed in the urb value. Bit 16 is - * placed in bit 0 of the urb index. - * - * Note that there are a couple of special cases to support the highest baud - * rates. If the calculated divisor value is 1, this needs to be replaced with - * 0. Additionally for the FT232BM, if the calculated divisor value is 0x4001 - * (1.5), this needs to be replaced with 0x0001 (1) (but this divisor value is - * not supported by the FT8U232AM). - */ - -enum ftdi_chip_type { - SIO = 1, - FT8U232AM = 2, - FT232BM = 3, - FT2232C = 4, - FT232RL = 5, - FT2232H = 6, - FT4232H = 7, - FT232H = 8, - FTX = 9, -}; - -enum ftdi_sio_baudrate { - ftdi_sio_b300 = 0, - ftdi_sio_b600 = 1, - ftdi_sio_b1200 = 2, - ftdi_sio_b2400 = 3, - ftdi_sio_b4800 = 4, - ftdi_sio_b9600 = 5, - ftdi_sio_b19200 = 6, - ftdi_sio_b38400 = 7, - ftdi_sio_b57600 = 8, - ftdi_sio_b115200 = 9 -}; - -/* - * The ftdi_8U232AM_xxMHz_byyy constants have been removed. The encoded divisor - * values are calculated internally. - */ -#define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA -#define FTDI_SIO_SET_DATA_REQUEST_TYPE 0x40 -#define FTDI_SIO_SET_DATA_PARITY_NONE (0x0 << 8) -#define FTDI_SIO_SET_DATA_PARITY_ODD (0x1 << 8) -#define FTDI_SIO_SET_DATA_PARITY_EVEN (0x2 << 8) -#define FTDI_SIO_SET_DATA_PARITY_MARK (0x3 << 8) -#define FTDI_SIO_SET_DATA_PARITY_SPACE (0x4 << 8) -#define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11) -#define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11) -#define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11) -#define FTDI_SIO_SET_BREAK (0x1 << 14) -/* FTDI_SIO_SET_DATA */ - -/* - * BmRequestType: 0100 0000B - * bRequest: FTDI_SIO_SET_DATA - * wValue: Data characteristics (see below) - * wIndex: Port - * wLength: 0 - * Data: No - * - * Data characteristics - * - * B0..7 Number of data bits - * B8..10 Parity - * 0 = None - * 1 = Odd - * 2 = Even - * 3 = Mark - * 4 = Space - * B11..13 Stop Bits - * 0 = 1 - * 1 = 1.5 - * 2 = 2 - * B14 - * 1 = TX ON (break) - * 0 = TX OFF (normal state) - * B15 Reserved - * - */ - - - -/* FTDI_SIO_MODEM_CTRL */ -#define FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE 0x40 -#define FTDI_SIO_SET_MODEM_CTRL_REQUEST FTDI_SIO_MODEM_CTRL - -/* - * BmRequestType: 0100 0000B - * bRequest: FTDI_SIO_MODEM_CTRL - * wValue: ControlValue (see below) - * wIndex: Port - * wLength: 0 - * Data: None - * - * NOTE: If the device is in RTS/CTS flow control, the RTS set by this - * command will be IGNORED without an error being returned - * Also - you can not set DTR and RTS with one control message - */ - -#define FTDI_SIO_SET_DTR_MASK 0x1 -#define FTDI_SIO_SET_DTR_HIGH (1 | (FTDI_SIO_SET_DTR_MASK << 8)) -#define FTDI_SIO_SET_DTR_LOW (0 | (FTDI_SIO_SET_DTR_MASK << 8)) -#define FTDI_SIO_SET_RTS_MASK 0x2 -#define FTDI_SIO_SET_RTS_HIGH (2 | (FTDI_SIO_SET_RTS_MASK << 8)) -#define FTDI_SIO_SET_RTS_LOW (0 | (FTDI_SIO_SET_RTS_MASK << 8)) - -/* - * ControlValue - * B0 DTR state - * 0 = reset - * 1 = set - * B1 RTS state - * 0 = reset - * 1 = set - * B2..7 Reserved - * B8 DTR state enable - * 0 = ignore - * 1 = use DTR state - * B9 RTS state enable - * 0 = ignore - * 1 = use RTS state - * B10..15 Reserved - */ - -/* FTDI_SIO_SET_FLOW_CTRL */ -#define FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE 0x40 -#define FTDI_SIO_SET_FLOW_CTRL_REQUEST FTDI_SIO_SET_FLOW_CTRL -#define FTDI_SIO_DISABLE_FLOW_CTRL 0x0 -#define FTDI_SIO_RTS_CTS_HS (0x1 << 8) -#define FTDI_SIO_DTR_DSR_HS (0x2 << 8) -#define FTDI_SIO_XON_XOFF_HS (0x4 << 8) -/* - * BmRequestType: 0100 0000b - * bRequest: FTDI_SIO_SET_FLOW_CTRL - * wValue: Xoff/Xon - * wIndex: Protocol/Port - hIndex is protocol / lIndex is port - * wLength: 0 - * Data: None - * - * hIndex protocol is: - * B0 Output handshaking using RTS/CTS - * 0 = disabled - * 1 = enabled - * B1 Output handshaking using DTR/DSR - * 0 = disabled - * 1 = enabled - * B2 Xon/Xoff handshaking - * 0 = disabled - * 1 = enabled - * - * A value of zero in the hIndex field disables handshaking - * - * If Xon/Xoff handshaking is specified, the hValue field should contain the - * XOFF character and the lValue field contains the XON character. - */ - -/* - * FTDI_SIO_GET_LATENCY_TIMER - * - * Set the timeout interval. The FTDI collects data from the slave - * device, transmitting it to the host when either A) 62 bytes are - * received, or B) the timeout interval has elapsed and the buffer - * contains at least 1 byte. Setting this value to a small number - * can dramatically improve performance for applications which send - * small packets, since the default value is 16ms. - */ -#define FTDI_SIO_GET_LATENCY_TIMER_REQUEST FTDI_SIO_GET_LATENCY_TIMER -#define FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE 0xC0 - -/* - * BmRequestType: 1100 0000b - * bRequest: FTDI_SIO_GET_LATENCY_TIMER - * wValue: 0 - * wIndex: Port - * wLength: 0 - * Data: latency (on return) - */ - -/* - * FTDI_SIO_SET_LATENCY_TIMER - * - * Set the timeout interval. The FTDI collects data from the slave - * device, transmitting it to the host when either A) 62 bytes are - * received, or B) the timeout interval has elapsed and the buffer - * contains at least 1 byte. Setting this value to a small number - * can dramatically improve performance for applications which send - * small packets, since the default value is 16ms. - */ -#define FTDI_SIO_SET_LATENCY_TIMER_REQUEST FTDI_SIO_SET_LATENCY_TIMER -#define FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE 0x40 - -/* - * BmRequestType: 0100 0000b - * bRequest: FTDI_SIO_SET_LATENCY_TIMER - * wValue: Latency (milliseconds) - * wIndex: Port - * wLength: 0 - * Data: None - * - * wValue: - * B0..7 Latency timer - * B8..15 0 - * - */ - -/* - * FTDI_SIO_SET_EVENT_CHAR - * - * Set the special event character for the specified communications port. - * If the device sees this character it will immediately return the - * data read so far - rather than wait 40ms or until 62 bytes are read - * which is what normally happens. - */ - - -#define FTDI_SIO_SET_EVENT_CHAR_REQUEST FTDI_SIO_SET_EVENT_CHAR -#define FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE 0x40 - - -/* - * BmRequestType: 0100 0000b - * bRequest: FTDI_SIO_SET_EVENT_CHAR - * wValue: EventChar - * wIndex: Port - * wLength: 0 - * Data: None - * - * wValue: - * B0..7 Event Character - * B8 Event Character Processing - * 0 = disabled - * 1 = enabled - * B9..15 Reserved - * - */ - -/* FTDI_SIO_SET_ERROR_CHAR */ - -/* - * Set the parity error replacement character for the specified communications - * port - */ - -/* - * BmRequestType: 0100 0000b - * bRequest: FTDI_SIO_SET_EVENT_CHAR - * wValue: Error Char - * wIndex: Port - * wLength: 0 - * Data: None - * - *Error Char - * B0..7 Error Character - * B8 Error Character Processing - * 0 = disabled - * 1 = enabled - * B9..15 Reserved - * - */ - -/* FTDI_SIO_GET_MODEM_STATUS */ -/* Retrieve the current value of the modem status register */ - -#define FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE 0xc0 -#define FTDI_SIO_GET_MODEM_STATUS_REQUEST FTDI_SIO_GET_MODEM_STATUS -#define FTDI_SIO_CTS_MASK 0x10 -#define FTDI_SIO_DSR_MASK 0x20 -#define FTDI_SIO_RI_MASK 0x40 -#define FTDI_SIO_RLSD_MASK 0x80 -/* - * BmRequestType: 1100 0000b - * bRequest: FTDI_SIO_GET_MODEM_STATUS - * wValue: zero - * wIndex: Port - * wLength: 1 - * Data: Status - * - * One byte of data is returned - * B0..3 0 - * B4 CTS - * 0 = inactive - * 1 = active - * B5 DSR - * 0 = inactive - * 1 = active - * B6 Ring Indicator (RI) - * 0 = inactive - * 1 = active - * B7 Receive Line Signal Detect (RLSD) - * 0 = inactive - * 1 = active - */ - - - -/* Descriptors returned by the device - * - * Device Descriptor - * - * Offset Field Size Value Description - * 0 bLength 1 0x12 Size of descriptor in bytes - * 1 bDescriptorType 1 0x01 DEVICE Descriptor Type - * 2 bcdUSB 2 0x0110 USB Spec Release Number - * 4 bDeviceClass 1 0x00 Class Code - * 5 bDeviceSubClass 1 0x00 SubClass Code - * 6 bDeviceProtocol 1 0x00 Protocol Code - * 7 bMaxPacketSize0 1 0x08 Maximum packet size for endpoint 0 - * 8 idVendor 2 0x0403 Vendor ID - * 10 idProduct 2 0x8372 Product ID (FTDI_SIO_PID) - * 12 bcdDevice 2 0x0001 Device release number - * 14 iManufacturer 1 0x01 Index of man. string desc - * 15 iProduct 1 0x02 Index of prod string desc - * 16 iSerialNumber 1 0x02 Index of serial nmr string desc - * 17 bNumConfigurations 1 0x01 Number of possible configurations - * - * Configuration Descriptor - * - * Offset Field Size Value - * 0 bLength 1 0x09 Size of descriptor in bytes - * 1 bDescriptorType 1 0x02 CONFIGURATION Descriptor Type - * 2 wTotalLength 2 0x0020 Total length of data - * 4 bNumInterfaces 1 0x01 Number of interfaces supported - * 5 bConfigurationValue 1 0x01 Argument for SetCOnfiguration() req - * 6 iConfiguration 1 0x02 Index of config string descriptor - * 7 bmAttributes 1 0x20 Config characteristics Remote Wakeup - * 8 MaxPower 1 0x1E Max power consumption - * - * Interface Descriptor - * - * Offset Field Size Value - * 0 bLength 1 0x09 Size of descriptor in bytes - * 1 bDescriptorType 1 0x04 INTERFACE Descriptor Type - * 2 bInterfaceNumber 1 0x00 Number of interface - * 3 bAlternateSetting 1 0x00 Value used to select alternate - * 4 bNumEndpoints 1 0x02 Number of endpoints - * 5 bInterfaceClass 1 0xFF Class Code - * 6 bInterfaceSubClass 1 0xFF Subclass Code - * 7 bInterfaceProtocol 1 0xFF Protocol Code - * 8 iInterface 1 0x02 Index of interface string description - * - * IN Endpoint Descriptor - * - * Offset Field Size Value - * 0 bLength 1 0x07 Size of descriptor in bytes - * 1 bDescriptorType 1 0x05 ENDPOINT descriptor type - * 2 bEndpointAddress 1 0x82 Address of endpoint - * 3 bmAttributes 1 0x02 Endpoint attributes - Bulk - * 4 bNumEndpoints 2 0x0040 maximum packet size - * 5 bInterval 1 0x00 Interval for polling endpoint - * - * OUT Endpoint Descriptor - * - * Offset Field Size Value - * 0 bLength 1 0x07 Size of descriptor in bytes - * 1 bDescriptorType 1 0x05 ENDPOINT descriptor type - * 2 bEndpointAddress 1 0x02 Address of endpoint - * 3 bmAttributes 1 0x02 Endpoint attributes - Bulk - * 4 bNumEndpoints 2 0x0040 maximum packet size - * 5 bInterval 1 0x00 Interval for polling endpoint - * - * DATA FORMAT - * - * IN Endpoint - * - * The device reserves the first two bytes of data on this endpoint to contain - * the current values of the modem and line status registers. In the absence of - * data, the device generates a message consisting of these two status bytes - * every 40 ms - * - * Byte 0: Modem Status - * - * Offset Description - * B0 Reserved - must be 1 - * B1 Reserved - must be 0 - * B2 Reserved - must be 0 - * B3 Reserved - must be 0 - * B4 Clear to Send (CTS) - * B5 Data Set Ready (DSR) - * B6 Ring Indicator (RI) - * B7 Receive Line Signal Detect (RLSD) - * - * Byte 1: Line Status - * - * Offset Description - * B0 Data Ready (DR) - * B1 Overrun Error (OE) - * B2 Parity Error (PE) - * B3 Framing Error (FE) - * B4 Break Interrupt (BI) - * B5 Transmitter Holding Register (THRE) - * B6 Transmitter Empty (TEMT) - * B7 Error in RCVR FIFO - * - */ -#define FTDI_RS0_CTS (1 << 4) -#define FTDI_RS0_DSR (1 << 5) -#define FTDI_RS0_RI (1 << 6) -#define FTDI_RS0_RLSD (1 << 7) - -#define FTDI_RS_DR 1 -#define FTDI_RS_OE (1<<1) -#define FTDI_RS_PE (1<<2) -#define FTDI_RS_FE (1<<3) -#define FTDI_RS_BI (1<<4) -#define FTDI_RS_THRE (1<<5) -#define FTDI_RS_TEMT (1<<6) -#define FTDI_RS_FIFO (1<<7) - -/* - * OUT Endpoint - * - * This device reserves the first bytes of data on this endpoint contain the - * length and port identifier of the message. For the FTDI USB Serial converter - * the port identifier is always 1. - * - * Byte 0: Line Status - * - * Offset Description - * B0 Reserved - must be 1 - * B1 Reserved - must be 0 - * B2..7 Length of message - (not including Byte 0) - * - */ diff --git a/ANDROID_3.4.5/drivers/usb/serial/ftdi_sio_ids.h b/ANDROID_3.4.5/drivers/usb/serial/ftdi_sio_ids.h deleted file mode 100644 index 5661c7e2..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/ftdi_sio_ids.h +++ /dev/null @@ -1,1218 +0,0 @@ -/* - * vendor/product IDs (VID/PID) of devices using FTDI USB serial converters. - * Please keep numerically sorted within individual areas, thanks! - * - * Philipp Gühring - pg@futureware.at - added the Device ID of the USB relais - * from Rudolf Gugler - * - */ - - -/**********************************/ -/***** devices using FTDI VID *****/ -/**********************************/ - - -#define FTDI_VID 0x0403 /* Vendor Id */ - - -/*** "original" FTDI device PIDs ***/ - -#define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */ -#define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */ -#define FTDI_8U2232C_PID 0x6010 /* Dual channel device */ -#define FTDI_4232H_PID 0x6011 /* Quad channel hi-speed device */ -#define FTDI_232H_PID 0x6014 /* Single channel hi-speed device */ -#define FTDI_FTX_PID 0x6015 /* FT-X series (FT201X, FT230X, FT231X, etc) */ -#define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */ -#define FTDI_232RL_PID 0xFBFA /* Product ID for FT232RL */ - - -/*** third-party PIDs (using FTDI_VID) ***/ - -#define FTDI_LUMEL_PD12_PID 0x6002 - -/* - * Marvell OpenRD Base, Client - * http://www.open-rd.org - * OpenRD Base, Client use VID 0x0403 - */ -#define MARVELL_OPENRD_PID 0x9e90 - -/* www.candapter.com Ewert Energy Systems CANdapter device */ -#define FTDI_CANDAPTER_PID 0x9F80 /* Product Id */ - -/* - * Texas Instruments XDS100v2 JTAG / BeagleBone A3 - * http://processors.wiki.ti.com/index.php/XDS100 - * http://beagleboard.org/bone - */ -#define TI_XDS100V2_PID 0xa6d0 - -#define FTDI_NXTCAM_PID 0xABB8 /* NXTCam for Mindstorms NXT */ - -/* US Interface Navigator (http://www.usinterface.com/) */ -#define FTDI_USINT_CAT_PID 0xb810 /* Navigator CAT and 2nd PTT lines */ -#define FTDI_USINT_WKEY_PID 0xb811 /* Navigator WKEY and FSK lines */ -#define FTDI_USINT_RS232_PID 0xb812 /* Navigator RS232 and CONFIG lines */ - -/* OOCDlink by Joern Kaipf - * (http://www.joernonline.de/) */ -#define FTDI_OOCDLINK_PID 0xbaf8 /* Amontec JTAGkey */ - -/* Luminary Micro Stellaris Boards, VID = FTDI_VID */ -/* FTDI 2332C Dual channel device, side A=245 FIFO (JTAG), Side B=RS232 UART */ -#define LMI_LM3S_DEVEL_BOARD_PID 0xbcd8 -#define LMI_LM3S_EVAL_BOARD_PID 0xbcd9 -#define LMI_LM3S_ICDI_BOARD_PID 0xbcda - -#define FTDI_TURTELIZER_PID 0xBDC8 /* JTAG/RS-232 adapter by egnite GmbH */ - -/* OpenDCC (www.opendcc.de) product id */ -#define FTDI_OPENDCC_PID 0xBFD8 -#define FTDI_OPENDCC_SNIFFER_PID 0xBFD9 -#define FTDI_OPENDCC_THROTTLE_PID 0xBFDA -#define FTDI_OPENDCC_GATEWAY_PID 0xBFDB -#define FTDI_OPENDCC_GBM_PID 0xBFDC - -/* - * RR-CirKits LocoBuffer USB (http://www.rr-cirkits.com) - */ -#define FTDI_RRCIRKITS_LOCOBUFFER_PID 0xc7d0 /* LocoBuffer USB */ - -/* DMX4ALL DMX Interfaces */ -#define FTDI_DMX4ALL 0xC850 - -/* - * ASK.fr devices - */ -#define FTDI_ASK_RDR400_PID 0xC991 /* ASK RDR 400 series card reader */ - -/* www.starting-point-systems.com µChameleon device */ -#define FTDI_MICRO_CHAMELEON_PID 0xCAA0 /* Product Id */ - -/* - * Tactrix OpenPort (ECU) devices. - * OpenPort 1.3M submitted by Donour Sizemore. - * OpenPort 1.3S and 1.3U submitted by Ian Abbott. - */ -#define FTDI_TACTRIX_OPENPORT_13M_PID 0xCC48 /* OpenPort 1.3 Mitsubishi */ -#define FTDI_TACTRIX_OPENPORT_13S_PID 0xCC49 /* OpenPort 1.3 Subaru */ -#define FTDI_TACTRIX_OPENPORT_13U_PID 0xCC4A /* OpenPort 1.3 Universal */ - -#define FTDI_DISTORTEC_JTAG_LOCK_PICK_PID 0xCFF8 - -/* SCS HF Radio Modems PID's (http://www.scs-ptc.com) */ -/* the VID is the standard ftdi vid (FTDI_VID) */ -#define FTDI_SCS_DEVICE_0_PID 0xD010 /* SCS PTC-IIusb */ -#define FTDI_SCS_DEVICE_1_PID 0xD011 /* SCS Tracker / DSP TNC */ -#define FTDI_SCS_DEVICE_2_PID 0xD012 -#define FTDI_SCS_DEVICE_3_PID 0xD013 -#define FTDI_SCS_DEVICE_4_PID 0xD014 -#define FTDI_SCS_DEVICE_5_PID 0xD015 -#define FTDI_SCS_DEVICE_6_PID 0xD016 -#define FTDI_SCS_DEVICE_7_PID 0xD017 - -/* iPlus device */ -#define FTDI_IPLUS_PID 0xD070 /* Product Id */ -#define FTDI_IPLUS2_PID 0xD071 /* Product Id */ - -/* - * Gamma Scout (http://gamma-scout.com/). Submitted by rsc@runtux.com. - */ -#define FTDI_GAMMA_SCOUT_PID 0xD678 /* Gamma Scout online */ - -/* Propox devices */ -#define FTDI_PROPOX_JTAGCABLEII_PID 0xD738 -#define FTDI_PROPOX_ISPCABLEIII_PID 0xD739 - -/* Lenz LI-USB Computer Interface. */ -#define FTDI_LENZ_LIUSB_PID 0xD780 - -/* Vardaan Enterprises Serial Interface VEUSB422R3 */ -#define FTDI_VARDAAN_PID 0xF070 - -/* - * Xsens Technologies BV products (http://www.xsens.com). - */ -#define XSENS_CONVERTER_0_PID 0xD388 -#define XSENS_CONVERTER_1_PID 0xD389 -#define XSENS_CONVERTER_2_PID 0xD38A -#define XSENS_CONVERTER_3_PID 0xD38B -#define XSENS_CONVERTER_4_PID 0xD38C -#define XSENS_CONVERTER_5_PID 0xD38D -#define XSENS_CONVERTER_6_PID 0xD38E -#define XSENS_CONVERTER_7_PID 0xD38F - -/* - * NDI (www.ndigital.com) product ids - */ -#define FTDI_NDI_HUC_PID 0xDA70 /* NDI Host USB Converter */ -#define FTDI_NDI_SPECTRA_SCU_PID 0xDA71 /* NDI Spectra SCU */ -#define FTDI_NDI_FUTURE_2_PID 0xDA72 /* NDI future device #2 */ -#define FTDI_NDI_FUTURE_3_PID 0xDA73 /* NDI future device #3 */ -#define FTDI_NDI_AURORA_SCU_PID 0xDA74 /* NDI Aurora SCU */ - -/* - * ChamSys Limited (www.chamsys.co.uk) USB wing/interface product IDs - */ -#define FTDI_CHAMSYS_24_MASTER_WING_PID 0xDAF8 -#define FTDI_CHAMSYS_PC_WING_PID 0xDAF9 -#define FTDI_CHAMSYS_USB_DMX_PID 0xDAFA -#define FTDI_CHAMSYS_MIDI_TIMECODE_PID 0xDAFB -#define FTDI_CHAMSYS_MINI_WING_PID 0xDAFC -#define FTDI_CHAMSYS_MAXI_WING_PID 0xDAFD -#define FTDI_CHAMSYS_MEDIA_WING_PID 0xDAFE -#define FTDI_CHAMSYS_WING_PID 0xDAFF - -/* - * Westrex International devices submitted by Cory Lee - */ -#define FTDI_WESTREX_MODEL_777_PID 0xDC00 /* Model 777 */ -#define FTDI_WESTREX_MODEL_8900F_PID 0xDC01 /* Model 8900F */ - -/* - * ACG Identification Technologies GmbH products (http://www.acg.de/). - * Submitted by anton -at- goto10 -dot- org. - */ -#define FTDI_ACG_HFDUAL_PID 0xDD20 /* HF Dual ISO Reader (RFID) */ - -/* - * Definitions for Artemis astronomical USB based cameras - * Check it at http://www.artemisccd.co.uk/ - */ -#define FTDI_ARTEMIS_PID 0xDF28 /* All Artemis Cameras */ - -/* - * Definitions for ATIK Instruments astronomical USB based cameras - * Check it at http://www.atik-instruments.com/ - */ -#define FTDI_ATIK_ATK16_PID 0xDF30 /* ATIK ATK-16 Grayscale Camera */ -#define FTDI_ATIK_ATK16C_PID 0xDF32 /* ATIK ATK-16C Colour Camera */ -#define FTDI_ATIK_ATK16HR_PID 0xDF31 /* ATIK ATK-16HR Grayscale Camera */ -#define FTDI_ATIK_ATK16HRC_PID 0xDF33 /* ATIK ATK-16HRC Colour Camera */ -#define FTDI_ATIK_ATK16IC_PID 0xDF35 /* ATIK ATK-16IC Grayscale Camera */ - -/* - * Yost Engineering, Inc. products (www.yostengineering.com). - * PID 0xE050 submitted by Aaron Prose. - */ -#define FTDI_YEI_SERVOCENTER31_PID 0xE050 /* YEI ServoCenter3.1 USB */ - -/* - * ELV USB devices submitted by Christian Abt of ELV (www.elv.de). - * All of these devices use FTDI's vendor ID (0x0403). - * Further IDs taken from ELV Windows .inf file. - * - * The previously included PID for the UO 100 module was incorrect. - * In fact, that PID was for ELV's UR 100 USB-RS232 converter (0xFB58). - * - * Armin Laeuger originally sent the PID for the UM 100 module. - */ -#define FTDI_ELV_USR_PID 0xE000 /* ELV Universal-Sound-Recorder */ -#define FTDI_ELV_MSM1_PID 0xE001 /* ELV Mini-Sound-Modul */ -#define FTDI_ELV_KL100_PID 0xE002 /* ELV Kfz-Leistungsmesser KL 100 */ -#define FTDI_ELV_WS550_PID 0xE004 /* WS 550 */ -#define FTDI_ELV_EC3000_PID 0xE006 /* ENERGY CONTROL 3000 USB */ -#define FTDI_ELV_WS888_PID 0xE008 /* WS 888 */ -#define FTDI_ELV_TWS550_PID 0xE009 /* Technoline WS 550 */ -#define FTDI_ELV_FEM_PID 0xE00A /* Funk Energie Monitor */ -#define FTDI_ELV_FHZ1300PC_PID 0xE0E8 /* FHZ 1300 PC */ -#define FTDI_ELV_WS500_PID 0xE0E9 /* PC-Wetterstation (WS 500) */ -#define FTDI_ELV_HS485_PID 0xE0EA /* USB to RS-485 adapter */ -#define FTDI_ELV_UMS100_PID 0xE0EB /* ELV USB Master-Slave Schaltsteckdose UMS 100 */ -#define FTDI_ELV_TFD128_PID 0xE0EC /* ELV Temperatur-Feuchte-Datenlogger TFD 128 */ -#define FTDI_ELV_FM3RX_PID 0xE0ED /* ELV Messwertuebertragung FM3 RX */ -#define FTDI_ELV_WS777_PID 0xE0EE /* Conrad WS 777 */ -#define FTDI_ELV_EM1010PC_PID 0xE0EF /* Energy monitor EM 1010 PC */ -#define FTDI_ELV_CSI8_PID 0xE0F0 /* Computer-Schalt-Interface (CSI 8) */ -#define FTDI_ELV_EM1000DL_PID 0xE0F1 /* PC-Datenlogger fuer Energiemonitor (EM 1000 DL) */ -#define FTDI_ELV_PCK100_PID 0xE0F2 /* PC-Kabeltester (PCK 100) */ -#define FTDI_ELV_RFP500_PID 0xE0F3 /* HF-Leistungsmesser (RFP 500) */ -#define FTDI_ELV_FS20SIG_PID 0xE0F4 /* Signalgeber (FS 20 SIG) */ -#define FTDI_ELV_UTP8_PID 0xE0F5 /* ELV UTP 8 */ -#define FTDI_ELV_WS300PC_PID 0xE0F6 /* PC-Wetterstation (WS 300 PC) */ -#define FTDI_ELV_WS444PC_PID 0xE0F7 /* Conrad WS 444 PC */ -#define FTDI_PHI_FISCO_PID 0xE40B /* PHI Fisco USB to Serial cable */ -#define FTDI_ELV_UAD8_PID 0xF068 /* USB-AD-Wandler (UAD 8) */ -#define FTDI_ELV_UDA7_PID 0xF069 /* USB-DA-Wandler (UDA 7) */ -#define FTDI_ELV_USI2_PID 0xF06A /* USB-Schrittmotoren-Interface (USI 2) */ -#define FTDI_ELV_T1100_PID 0xF06B /* Thermometer (T 1100) */ -#define FTDI_ELV_PCD200_PID 0xF06C /* PC-Datenlogger (PCD 200) */ -#define FTDI_ELV_ULA200_PID 0xF06D /* USB-LCD-Ansteuerung (ULA 200) */ -#define FTDI_ELV_ALC8500_PID 0xF06E /* ALC 8500 Expert */ -#define FTDI_ELV_FHZ1000PC_PID 0xF06F /* FHZ 1000 PC */ -#define FTDI_ELV_UR100_PID 0xFB58 /* USB-RS232-Umsetzer (UR 100) */ -#define FTDI_ELV_UM100_PID 0xFB5A /* USB-Modul UM 100 */ -#define FTDI_ELV_UO100_PID 0xFB5B /* USB-Modul UO 100 */ -/* Additional ELV PIDs that default to using the FTDI D2XX drivers on - * MS Windows, rather than the FTDI Virtual Com Port drivers. - * Maybe these will be easier to use with the libftdi/libusb user-space - * drivers, or possibly the Comedi drivers in some cases. */ -#define FTDI_ELV_CLI7000_PID 0xFB59 /* Computer-Light-Interface (CLI 7000) */ -#define FTDI_ELV_PPS7330_PID 0xFB5C /* Processor-Power-Supply (PPS 7330) */ -#define FTDI_ELV_TFM100_PID 0xFB5D /* Temperatur-Feuchte-Messgeraet (TFM 100) */ -#define FTDI_ELV_UDF77_PID 0xFB5E /* USB DCF Funkuhr (UDF 77) */ -#define FTDI_ELV_UIO88_PID 0xFB5F /* USB-I/O Interface (UIO 88) */ - -/* - * EVER Eco Pro UPS (http://www.ever.com.pl/) - */ - -#define EVER_ECO_PRO_CDS 0xe520 /* RS-232 converter */ - -/* - * Active Robots product ids. - */ -#define FTDI_ACTIVE_ROBOTS_PID 0xE548 /* USB comms board */ - -/* Pyramid Computer GmbH */ -#define FTDI_PYRAMID_PID 0xE6C8 /* Pyramid Appliance Display */ - -/* www.elsterelectricity.com Elster Unicom III Optical Probe */ -#define FTDI_ELSTER_UNICOM_PID 0xE700 /* Product Id */ - -/* - * Gude Analog- und Digitalsysteme GmbH - */ -#define FTDI_GUDEADS_E808_PID 0xE808 -#define FTDI_GUDEADS_E809_PID 0xE809 -#define FTDI_GUDEADS_E80A_PID 0xE80A -#define FTDI_GUDEADS_E80B_PID 0xE80B -#define FTDI_GUDEADS_E80C_PID 0xE80C -#define FTDI_GUDEADS_E80D_PID 0xE80D -#define FTDI_GUDEADS_E80E_PID 0xE80E -#define FTDI_GUDEADS_E80F_PID 0xE80F -#define FTDI_GUDEADS_E888_PID 0xE888 /* Expert ISDN Control USB */ -#define FTDI_GUDEADS_E889_PID 0xE889 /* USB RS-232 OptoBridge */ -#define FTDI_GUDEADS_E88A_PID 0xE88A -#define FTDI_GUDEADS_E88B_PID 0xE88B -#define FTDI_GUDEADS_E88C_PID 0xE88C -#define FTDI_GUDEADS_E88D_PID 0xE88D -#define FTDI_GUDEADS_E88E_PID 0xE88E -#define FTDI_GUDEADS_E88F_PID 0xE88F - -/* - * Eclo (http://www.eclo.pt/) product IDs. - * PID 0xEA90 submitted by Martin Grill. - */ -#define FTDI_ECLO_COM_1WIRE_PID 0xEA90 /* COM to 1-Wire USB adaptor */ - -/* TNC-X USB-to-packet-radio adapter, versions prior to 3.0 (DLP module) */ -#define FTDI_TNC_X_PID 0xEBE0 - -/* - * Teratronik product ids. - * Submitted by O. Wölfelschneider. - */ -#define FTDI_TERATRONIK_VCP_PID 0xEC88 /* Teratronik device (preferring VCP driver on windows) */ -#define FTDI_TERATRONIK_D2XX_PID 0xEC89 /* Teratronik device (preferring D2XX driver on windows) */ - -/* Rig Expert Ukraine devices */ -#define FTDI_REU_TINY_PID 0xED22 /* RigExpert Tiny */ - -/* - * Hameg HO820 and HO870 interface (using VID 0x0403) - */ -#define HAMEG_HO820_PID 0xed74 -#define HAMEG_HO730_PID 0xed73 -#define HAMEG_HO720_PID 0xed72 -#define HAMEG_HO870_PID 0xed71 - -/* - * MaxStream devices www.maxstream.net - */ -#define FTDI_MAXSTREAM_PID 0xEE18 /* Xbee PKG-U Module */ - -/* - * microHAM product IDs (http://www.microham.com). - * Submitted by Justin Burket (KL1RL) - * and Mike Studer (K6EEP) . - * Ian Abbott added a few more from the driver INF file. - */ -#define FTDI_MHAM_KW_PID 0xEEE8 /* USB-KW interface */ -#define FTDI_MHAM_YS_PID 0xEEE9 /* USB-YS interface */ -#define FTDI_MHAM_Y6_PID 0xEEEA /* USB-Y6 interface */ -#define FTDI_MHAM_Y8_PID 0xEEEB /* USB-Y8 interface */ -#define FTDI_MHAM_IC_PID 0xEEEC /* USB-IC interface */ -#define FTDI_MHAM_DB9_PID 0xEEED /* USB-DB9 interface */ -#define FTDI_MHAM_RS232_PID 0xEEEE /* USB-RS232 interface */ -#define FTDI_MHAM_Y9_PID 0xEEEF /* USB-Y9 interface */ - -/* Domintell products http://www.domintell.com */ -#define FTDI_DOMINTELL_DGQG_PID 0xEF50 /* Master */ -#define FTDI_DOMINTELL_DUSB_PID 0xEF51 /* DUSB01 module */ - -/* - * The following are the values for the Perle Systems - * UltraPort USB serial converters - */ -#define FTDI_PERLE_ULTRAPORT_PID 0xF0C0 /* Perle UltraPort Product Id */ - -/* Sprog II (Andrew Crosland's SprogII DCC interface) */ -#define FTDI_SPROG_II 0xF0C8 - -/* an infrared receiver for user access control with IR tags */ -#define FTDI_PIEGROUP_PID 0xF208 /* Product Id */ - -/* ACT Solutions HomePro ZWave interface - (http://www.act-solutions.com/HomePro-Product-Matrix.html) */ -#define FTDI_ACTZWAVE_PID 0xF2D0 - -/* - * 4N-GALAXY.DE PIDs for CAN-USB, USB-RS232, USB-RS422, USB-RS485, - * USB-TTY aktiv, USB-TTY passiv. Some PIDs are used by several devices - * and I'm not entirely sure which are used by which. - */ -#define FTDI_4N_GALAXY_DE_1_PID 0xF3C0 -#define FTDI_4N_GALAXY_DE_2_PID 0xF3C1 -#define FTDI_4N_GALAXY_DE_3_PID 0xF3C2 - -/* - * Linx Technologies product ids - */ -#define LINX_SDMUSBQSS_PID 0xF448 /* Linx SDM-USB-QS-S */ -#define LINX_MASTERDEVEL2_PID 0xF449 /* Linx Master Development 2.0 */ -#define LINX_FUTURE_0_PID 0xF44A /* Linx future device */ -#define LINX_FUTURE_1_PID 0xF44B /* Linx future device */ -#define LINX_FUTURE_2_PID 0xF44C /* Linx future device */ - -/* - * Oceanic product ids - */ -#define FTDI_OCEANIC_PID 0xF460 /* Oceanic dive instrument */ - -/* - * SUUNTO product ids - */ -#define FTDI_SUUNTO_SPORTS_PID 0xF680 /* Suunto Sports instrument */ - -/* USB-UIRT - An infrared receiver and transmitter using the 8U232AM chip */ -/* http://www.usbuirt.com/ */ -#define FTDI_USB_UIRT_PID 0xF850 /* Product Id */ - -/* CCS Inc. ICDU/ICDU40 product ID - - * the FT232BM is used in an in-circuit-debugger unit for PIC16's/PIC18's */ -#define FTDI_CCSICDU20_0_PID 0xF9D0 -#define FTDI_CCSICDU40_1_PID 0xF9D1 -#define FTDI_CCSMACHX_2_PID 0xF9D2 -#define FTDI_CCSLOAD_N_GO_3_PID 0xF9D3 -#define FTDI_CCSICDU64_4_PID 0xF9D4 -#define FTDI_CCSPRIME8_5_PID 0xF9D5 - -/* - * The following are the values for the Matrix Orbital LCD displays, - * which are the FT232BM ( similar to the 8U232AM ) - */ -#define FTDI_MTXORB_0_PID 0xFA00 /* Matrix Orbital Product Id */ -#define FTDI_MTXORB_1_PID 0xFA01 /* Matrix Orbital Product Id */ -#define FTDI_MTXORB_2_PID 0xFA02 /* Matrix Orbital Product Id */ -#define FTDI_MTXORB_3_PID 0xFA03 /* Matrix Orbital Product Id */ -#define FTDI_MTXORB_4_PID 0xFA04 /* Matrix Orbital Product Id */ -#define FTDI_MTXORB_5_PID 0xFA05 /* Matrix Orbital Product Id */ -#define FTDI_MTXORB_6_PID 0xFA06 /* Matrix Orbital Product Id */ - -/* - * Home Electronics (www.home-electro.com) USB gadgets - */ -#define FTDI_HE_TIRA1_PID 0xFA78 /* Tira-1 IR transceiver */ - -/* Inside Accesso contactless reader (http://www.insidecontactless.com/) */ -#define INSIDE_ACCESSO 0xFAD0 - -/* - * ThorLabs USB motor drivers - */ -#define FTDI_THORLABS_PID 0xfaf0 /* ThorLabs USB motor drivers */ - -/* - * Protego product ids - */ -#define PROTEGO_SPECIAL_1 0xFC70 /* special/unknown device */ -#define PROTEGO_R2X0 0xFC71 /* R200-USB TRNG unit (R210, R220, and R230) */ -#define PROTEGO_SPECIAL_3 0xFC72 /* special/unknown device */ -#define PROTEGO_SPECIAL_4 0xFC73 /* special/unknown device */ - -/* - * Sony Ericsson product ids - */ -#define FTDI_DSS20_PID 0xFC82 /* DSS-20 Sync Station for Sony Ericsson P800 */ -#define FTDI_URBAN_0_PID 0xFC8A /* Sony Ericsson Urban, uart #0 */ -#define FTDI_URBAN_1_PID 0xFC8B /* Sony Ericsson Urban, uart #1 */ - -/* www.irtrans.de device */ -#define FTDI_IRTRANS_PID 0xFC60 /* Product Id */ - -/* - * RM Michaelides CANview USB (http://www.rmcan.com) (FTDI_VID) - * CAN fieldbus interface adapter, added by port GmbH www.port.de) - * Ian Abbott changed the macro names for consistency. - */ -#define FTDI_RM_CANVIEW_PID 0xfd60 /* Product Id */ -/* www.thoughttechnology.com/ TT-USB provide with procomp use ftdi_sio */ -#define FTDI_TTUSB_PID 0xFF20 /* Product Id */ - -#define FTDI_USBX_707_PID 0xF857 /* ADSTech IR Blaster USBX-707 (FTDI_VID) */ - -#define FTDI_RELAIS_PID 0xFA10 /* Relais device from Rudolf Gugler */ - -/* - * PCDJ use ftdi based dj-controllers. The following PID is - * for their DAC-2 device http://www.pcdjhardware.com/DAC2.asp - * (the VID is the standard ftdi vid (FTDI_VID), PID sent by Wouter Paesen) - */ -#define FTDI_PCDJ_DAC2_PID 0xFA88 - -#define FTDI_R2000KU_TRUE_RNG 0xFB80 /* R2000KU TRUE RNG (FTDI_VID) */ - -/* - * DIEBOLD BCS SE923 (FTDI_VID) - */ -#define DIEBOLD_BCS_SE923_PID 0xfb99 - -/* www.crystalfontz.com devices - * - thanx for providing free devices for evaluation ! - * they use the ftdi chipset for the USB interface - * and the vendor id is the same - */ -#define FTDI_XF_632_PID 0xFC08 /* 632: 16x2 Character Display */ -#define FTDI_XF_634_PID 0xFC09 /* 634: 20x4 Character Display */ -#define FTDI_XF_547_PID 0xFC0A /* 547: Two line Display */ -#define FTDI_XF_633_PID 0xFC0B /* 633: 16x2 Character Display with Keys */ -#define FTDI_XF_631_PID 0xFC0C /* 631: 20x2 Character Display */ -#define FTDI_XF_635_PID 0xFC0D /* 635: 20x4 Character Display */ -#define FTDI_XF_640_PID 0xFC0E /* 640: Two line Display */ -#define FTDI_XF_642_PID 0xFC0F /* 642: Two line Display */ - -/* - * Video Networks Limited / Homechoice in the UK use an ftdi-based device - * for their 1Mb broadband internet service. The following PID is exhibited - * by the usb device supplied (the VID is the standard ftdi vid (FTDI_VID) - */ -#define FTDI_VNHCPCUSB_D_PID 0xfe38 /* Product Id */ - -/* AlphaMicro Components AMC-232USB01 device (FTDI_VID) */ -#define FTDI_AMC232_PID 0xFF00 /* Product Id */ - -/* - * IBS elektronik product ids (FTDI_VID) - * Submitted by Thomas Schleusener - */ -#define FTDI_IBS_US485_PID 0xff38 /* IBS US485 (USB<-->RS422/485 interface) */ -#define FTDI_IBS_PICPRO_PID 0xff39 /* IBS PIC-Programmer */ -#define FTDI_IBS_PCMCIA_PID 0xff3a /* IBS Card reader for PCMCIA SRAM-cards */ -#define FTDI_IBS_PK1_PID 0xff3b /* IBS PK1 - Particel counter */ -#define FTDI_IBS_RS232MON_PID 0xff3c /* IBS RS232 - Monitor */ -#define FTDI_IBS_APP70_PID 0xff3d /* APP 70 (dust monitoring system) */ -#define FTDI_IBS_PEDO_PID 0xff3e /* IBS PEDO-Modem (RF modem 868.35 MHz) */ -#define FTDI_IBS_PROD_PID 0xff3f /* future device */ -/* www.canusb.com Lawicel CANUSB device (FTDI_VID) */ -#define FTDI_CANUSB_PID 0xFFA8 /* Product Id */ - -/* - * TavIR AVR product ids (FTDI_VID) - */ -#define FTDI_TAVIR_STK500_PID 0xFA33 /* STK500 AVR programmer */ - - - -/********************************/ -/** third-party VID/PID combos **/ -/********************************/ - - - -/* - * Atmel STK541 - */ -#define ATMEL_VID 0x03eb /* Vendor ID */ -#define STK541_PID 0x2109 /* Zigbee Controller */ - -/* - * Blackfin gnICE JTAG - * http://docs.blackfin.uclinux.org/doku.php?id=hw:jtag:gnice - */ -#define ADI_VID 0x0456 -#define ADI_GNICE_PID 0xF000 -#define ADI_GNICEPLUS_PID 0xF001 - -/* - * Microchip Technology, Inc. - * - * MICROCHIP_VID (0x04D8) and MICROCHIP_USB_BOARD_PID (0x000A) are also used by: - * Hornby Elite - Digital Command Control Console - * http://www.hornby.com/hornby-dcc/controllers/ - */ -#define MICROCHIP_VID 0x04D8 -#define MICROCHIP_USB_BOARD_PID 0x000A /* CDC RS-232 Emulation Demo */ - -/* - * RATOC REX-USB60F - */ -#define RATOC_VENDOR_ID 0x0584 -#define RATOC_PRODUCT_ID_USB60F 0xb020 - -/* - * Acton Research Corp. - */ -#define ACTON_VID 0x0647 /* Vendor ID */ -#define ACTON_SPECTRAPRO_PID 0x0100 - -/* - * Contec products (http://www.contec.com) - * Submitted by Daniel Sangorrin - */ -#define CONTEC_VID 0x06CE /* Vendor ID */ -#define CONTEC_COM1USBH_PID 0x8311 /* COM-1(USB)H */ - -/* - * Definitions for B&B Electronics products. - */ -#define BANDB_VID 0x0856 /* B&B Electronics Vendor ID */ -#define BANDB_USOTL4_PID 0xAC01 /* USOTL4 Isolated RS-485 Converter */ -#define BANDB_USTL4_PID 0xAC02 /* USTL4 RS-485 Converter */ -#define BANDB_USO9ML2_PID 0xAC03 /* USO9ML2 Isolated RS-232 Converter */ -#define BANDB_USOPTL4_PID 0xAC11 -#define BANDB_USPTL4_PID 0xAC12 -#define BANDB_USO9ML2DR_2_PID 0xAC16 -#define BANDB_USO9ML2DR_PID 0xAC17 -#define BANDB_USOPTL4DR2_PID 0xAC18 /* USOPTL4R-2 2-port Isolated RS-232 Converter */ -#define BANDB_USOPTL4DR_PID 0xAC19 -#define BANDB_485USB9F_2W_PID 0xAC25 -#define BANDB_485USB9F_4W_PID 0xAC26 -#define BANDB_232USB9M_PID 0xAC27 -#define BANDB_485USBTB_2W_PID 0xAC33 -#define BANDB_485USBTB_4W_PID 0xAC34 -#define BANDB_TTL5USB9M_PID 0xAC49 -#define BANDB_TTL3USB9M_PID 0xAC50 -#define BANDB_ZZ_PROG1_USB_PID 0xBA02 - -/* - * Intrepid Control Systems (http://www.intrepidcs.com/) ValueCAN and NeoVI - */ -#define INTREPID_VID 0x093C -#define INTREPID_VALUECAN_PID 0x0601 -#define INTREPID_NEOVI_PID 0x0701 - -/* - * Definitions for ID TECH (www.idt-net.com) devices - */ -#define IDTECH_VID 0x0ACD /* ID TECH Vendor ID */ -#define IDTECH_IDT1221U_PID 0x0300 /* IDT1221U USB to RS-232 adapter */ - -/* - * Definitions for Omnidirectional Control Technology, Inc. devices - */ -#define OCT_VID 0x0B39 /* OCT vendor ID */ -/* Note: OCT US101 is also rebadged as Dick Smith Electronics (NZ) XH6381 */ -/* Also rebadged as Dick Smith Electronics (Aus) XH6451 */ -/* Also rebadged as SIIG Inc. model US2308 hardware version 1 */ -#define OCT_DK201_PID 0x0103 /* OCT DK201 USB docking station */ -#define OCT_US101_PID 0x0421 /* OCT US101 USB to RS-232 */ - -/* - * Definitions for Icom Inc. devices - */ -#define ICOM_VID 0x0C26 /* Icom vendor ID */ -/* Note: ID-1 is a communications tranceiver for HAM-radio operators */ -#define ICOM_ID_1_PID 0x0004 /* ID-1 USB to RS-232 */ -/* Note: OPC is an Optional cable to connect an Icom Tranceiver */ -#define ICOM_OPC_U_UC_PID 0x0018 /* OPC-478UC, OPC-1122U cloning cable */ -/* Note: ID-RP* devices are Icom Repeater Devices for HAM-radio */ -#define ICOM_ID_RP2C1_PID 0x0009 /* ID-RP2C Asset 1 to RS-232 */ -#define ICOM_ID_RP2C2_PID 0x000A /* ID-RP2C Asset 2 to RS-232 */ -#define ICOM_ID_RP2D_PID 0x000B /* ID-RP2D configuration port*/ -#define ICOM_ID_RP2VT_PID 0x000C /* ID-RP2V Transmit config port */ -#define ICOM_ID_RP2VR_PID 0x000D /* ID-RP2V Receive config port */ -#define ICOM_ID_RP4KVT_PID 0x0010 /* ID-RP4000V Transmit config port */ -#define ICOM_ID_RP4KVR_PID 0x0011 /* ID-RP4000V Receive config port */ -#define ICOM_ID_RP2KVT_PID 0x0012 /* ID-RP2000V Transmit config port */ -#define ICOM_ID_RP2KVR_PID 0x0013 /* ID-RP2000V Receive config port */ - -/* - * GN Otometrics (http://www.otometrics.com) - * Submitted by Ville Sundberg. - */ -#define GN_OTOMETRICS_VID 0x0c33 /* Vendor ID */ -#define AURICAL_USB_PID 0x0010 /* Aurical USB Audiometer */ - -/* - * The following are the values for the Sealevel SeaLINK+ adapters. - * (Original list sent by Tuan Hoang. Ian Abbott renamed the macros and - * removed some PIDs that don't seem to match any existing products.) - */ -#define SEALEVEL_VID 0x0c52 /* Sealevel Vendor ID */ -#define SEALEVEL_2101_PID 0x2101 /* SeaLINK+232 (2101/2105) */ -#define SEALEVEL_2102_PID 0x2102 /* SeaLINK+485 (2102) */ -#define SEALEVEL_2103_PID 0x2103 /* SeaLINK+232I (2103) */ -#define SEALEVEL_2104_PID 0x2104 /* SeaLINK+485I (2104) */ -#define SEALEVEL_2106_PID 0x9020 /* SeaLINK+422 (2106) */ -#define SEALEVEL_2201_1_PID 0x2211 /* SeaPORT+2/232 (2201) Port 1 */ -#define SEALEVEL_2201_2_PID 0x2221 /* SeaPORT+2/232 (2201) Port 2 */ -#define SEALEVEL_2202_1_PID 0x2212 /* SeaPORT+2/485 (2202) Port 1 */ -#define SEALEVEL_2202_2_PID 0x2222 /* SeaPORT+2/485 (2202) Port 2 */ -#define SEALEVEL_2203_1_PID 0x2213 /* SeaPORT+2 (2203) Port 1 */ -#define SEALEVEL_2203_2_PID 0x2223 /* SeaPORT+2 (2203) Port 2 */ -#define SEALEVEL_2401_1_PID 0x2411 /* SeaPORT+4/232 (2401) Port 1 */ -#define SEALEVEL_2401_2_PID 0x2421 /* SeaPORT+4/232 (2401) Port 2 */ -#define SEALEVEL_2401_3_PID 0x2431 /* SeaPORT+4/232 (2401) Port 3 */ -#define SEALEVEL_2401_4_PID 0x2441 /* SeaPORT+4/232 (2401) Port 4 */ -#define SEALEVEL_2402_1_PID 0x2412 /* SeaPORT+4/485 (2402) Port 1 */ -#define SEALEVEL_2402_2_PID 0x2422 /* SeaPORT+4/485 (2402) Port 2 */ -#define SEALEVEL_2402_3_PID 0x2432 /* SeaPORT+4/485 (2402) Port 3 */ -#define SEALEVEL_2402_4_PID 0x2442 /* SeaPORT+4/485 (2402) Port 4 */ -#define SEALEVEL_2403_1_PID 0x2413 /* SeaPORT+4 (2403) Port 1 */ -#define SEALEVEL_2403_2_PID 0x2423 /* SeaPORT+4 (2403) Port 2 */ -#define SEALEVEL_2403_3_PID 0x2433 /* SeaPORT+4 (2403) Port 3 */ -#define SEALEVEL_2403_4_PID 0x2443 /* SeaPORT+4 (2403) Port 4 */ -#define SEALEVEL_2801_1_PID 0X2811 /* SeaLINK+8/232 (2801) Port 1 */ -#define SEALEVEL_2801_2_PID 0X2821 /* SeaLINK+8/232 (2801) Port 2 */ -#define SEALEVEL_2801_3_PID 0X2831 /* SeaLINK+8/232 (2801) Port 3 */ -#define SEALEVEL_2801_4_PID 0X2841 /* SeaLINK+8/232 (2801) Port 4 */ -#define SEALEVEL_2801_5_PID 0X2851 /* SeaLINK+8/232 (2801) Port 5 */ -#define SEALEVEL_2801_6_PID 0X2861 /* SeaLINK+8/232 (2801) Port 6 */ -#define SEALEVEL_2801_7_PID 0X2871 /* SeaLINK+8/232 (2801) Port 7 */ -#define SEALEVEL_2801_8_PID 0X2881 /* SeaLINK+8/232 (2801) Port 8 */ -#define SEALEVEL_2802_1_PID 0X2812 /* SeaLINK+8/485 (2802) Port 1 */ -#define SEALEVEL_2802_2_PID 0X2822 /* SeaLINK+8/485 (2802) Port 2 */ -#define SEALEVEL_2802_3_PID 0X2832 /* SeaLINK+8/485 (2802) Port 3 */ -#define SEALEVEL_2802_4_PID 0X2842 /* SeaLINK+8/485 (2802) Port 4 */ -#define SEALEVEL_2802_5_PID 0X2852 /* SeaLINK+8/485 (2802) Port 5 */ -#define SEALEVEL_2802_6_PID 0X2862 /* SeaLINK+8/485 (2802) Port 6 */ -#define SEALEVEL_2802_7_PID 0X2872 /* SeaLINK+8/485 (2802) Port 7 */ -#define SEALEVEL_2802_8_PID 0X2882 /* SeaLINK+8/485 (2802) Port 8 */ -#define SEALEVEL_2803_1_PID 0X2813 /* SeaLINK+8 (2803) Port 1 */ -#define SEALEVEL_2803_2_PID 0X2823 /* SeaLINK+8 (2803) Port 2 */ -#define SEALEVEL_2803_3_PID 0X2833 /* SeaLINK+8 (2803) Port 3 */ -#define SEALEVEL_2803_4_PID 0X2843 /* SeaLINK+8 (2803) Port 4 */ -#define SEALEVEL_2803_5_PID 0X2853 /* SeaLINK+8 (2803) Port 5 */ -#define SEALEVEL_2803_6_PID 0X2863 /* SeaLINK+8 (2803) Port 6 */ -#define SEALEVEL_2803_7_PID 0X2873 /* SeaLINK+8 (2803) Port 7 */ -#define SEALEVEL_2803_8_PID 0X2883 /* SeaLINK+8 (2803) Port 8 */ -#define SEALEVEL_2803R_1_PID 0Xa02a /* SeaLINK+8 (2803-ROHS) Port 1+2 */ -#define SEALEVEL_2803R_2_PID 0Xa02b /* SeaLINK+8 (2803-ROHS) Port 3+4 */ -#define SEALEVEL_2803R_3_PID 0Xa02c /* SeaLINK+8 (2803-ROHS) Port 5+6 */ -#define SEALEVEL_2803R_4_PID 0Xa02d /* SeaLINK+8 (2803-ROHS) Port 7+8 */ - -/* - * JETI SPECTROMETER SPECBOS 1201 - * http://www.jeti.com/cms/index.php/instruments/other-instruments/specbos-2101 - */ -#define JETI_VID 0x0c6c -#define JETI_SPC1201_PID 0x04b2 - -/* - * FTDI USB UART chips used in construction projects from the - * Elektor Electronics magazine (http://www.elektor.com/) - */ -#define ELEKTOR_VID 0x0C7D -#define ELEKTOR_FT323R_PID 0x0005 /* RFID-Reader, issue 09-2006 */ - -/* - * Posiflex inc retail equipment (http://www.posiflex.com.tw) - */ -#define POSIFLEX_VID 0x0d3a /* Vendor ID */ -#define POSIFLEX_PP7000_PID 0x0300 /* PP-7000II thermal printer */ - -/* - * The following are the values for two KOBIL chipcard terminals. - */ -#define KOBIL_VID 0x0d46 /* KOBIL Vendor ID */ -#define KOBIL_CONV_B1_PID 0x2020 /* KOBIL Konverter for B1 */ -#define KOBIL_CONV_KAAN_PID 0x2021 /* KOBIL_Konverter for KAAN */ - -#define FTDI_NF_RIC_VID 0x0DCD /* Vendor Id */ -#define FTDI_NF_RIC_PID 0x0001 /* Product Id */ - -/* - * Falcom Wireless Communications GmbH - */ -#define FALCOM_VID 0x0F94 /* Vendor Id */ -#define FALCOM_TWIST_PID 0x0001 /* Falcom Twist USB GPRS modem */ -#define FALCOM_SAMBA_PID 0x0005 /* Falcom Samba USB GPRS modem */ - -/* Larsen and Brusgaard AltiTrack/USBtrack */ -#define LARSENBRUSGAARD_VID 0x0FD8 -#define LB_ALTITRACK_PID 0x0001 - -/* - * TTi (Thurlby Thandar Instruments) - */ -#define TTI_VID 0x103E /* Vendor Id */ -#define TTI_QL355P_PID 0x03E8 /* TTi QL355P power supply */ - -/* Interbiometrics USB I/O Board */ -/* Developed for Interbiometrics by Rudolf Gugler */ -#define INTERBIOMETRICS_VID 0x1209 -#define INTERBIOMETRICS_IOBOARD_PID 0x1002 -#define INTERBIOMETRICS_MINI_IOBOARD_PID 0x1006 - -/* - * Testo products (http://www.testo.com/) - * Submitted by Colin Leroy - */ -#define TESTO_VID 0x128D -#define TESTO_USB_INTERFACE_PID 0x0001 - -/* - * Mobility Electronics products. - */ -#define MOBILITY_VID 0x1342 -#define MOBILITY_USB_SERIAL_PID 0x0202 /* EasiDock USB 200 serial */ - -/* - * FIC / OpenMoko, Inc. http://wiki.openmoko.org/wiki/Neo1973_Debug_Board_v3 - * Submitted by Harald Welte - */ -#define FIC_VID 0x1457 -#define FIC_NEO1973_DEBUG_PID 0x5118 - -/* Olimex */ -#define OLIMEX_VID 0x15BA -#define OLIMEX_ARM_USB_OCD_PID 0x0003 -#define OLIMEX_ARM_USB_OCD_H_PID 0x002b - -/* - * Telldus Technologies - */ -#define TELLDUS_VID 0x1781 /* Vendor ID */ -#define TELLDUS_TELLSTICK_PID 0x0C30 /* RF control dongle 433 MHz using FT232RL */ - -/* - * RT Systems programming cables for various ham radios - */ -#define RTSYSTEMS_VID 0x2100 /* Vendor ID */ -#define RTSYSTEMS_SERIAL_VX7_PID 0x9e52 /* Serial converter for VX-7 Radios using FT232RL */ -#define RTSYSTEMS_CT29B_PID 0x9e54 /* CT29B Radio Cable */ -#define RTSYSTEMS_RTS01_PID 0x9e57 /* USB-RTS01 Radio Cable */ - - -/* - * Physik Instrumente - * http://www.physikinstrumente.com/en/products/ - */ -#define PI_VID 0x1a72 /* Vendor ID */ -#define PI_E861_PID 0x1008 /* E-861 piezo controller USB connection */ - -/* - * Bayer Ascensia Contour blood glucose meter USB-converter cable. - * http://winglucofacts.com/cables/ - */ -#define BAYER_VID 0x1A79 -#define BAYER_CONTOUR_CABLE_PID 0x6001 - -/* - * The following are the values for the Matrix Orbital FTDI Range - * Anything in this range will use an FT232RL. - */ -#define MTXORB_VID 0x1B3D -#define MTXORB_FTDI_RANGE_0100_PID 0x0100 -#define MTXORB_FTDI_RANGE_0101_PID 0x0101 -#define MTXORB_FTDI_RANGE_0102_PID 0x0102 -#define MTXORB_FTDI_RANGE_0103_PID 0x0103 -#define MTXORB_FTDI_RANGE_0104_PID 0x0104 -#define MTXORB_FTDI_RANGE_0105_PID 0x0105 -#define MTXORB_FTDI_RANGE_0106_PID 0x0106 -#define MTXORB_FTDI_RANGE_0107_PID 0x0107 -#define MTXORB_FTDI_RANGE_0108_PID 0x0108 -#define MTXORB_FTDI_RANGE_0109_PID 0x0109 -#define MTXORB_FTDI_RANGE_010A_PID 0x010A -#define MTXORB_FTDI_RANGE_010B_PID 0x010B -#define MTXORB_FTDI_RANGE_010C_PID 0x010C -#define MTXORB_FTDI_RANGE_010D_PID 0x010D -#define MTXORB_FTDI_RANGE_010E_PID 0x010E -#define MTXORB_FTDI_RANGE_010F_PID 0x010F -#define MTXORB_FTDI_RANGE_0110_PID 0x0110 -#define MTXORB_FTDI_RANGE_0111_PID 0x0111 -#define MTXORB_FTDI_RANGE_0112_PID 0x0112 -#define MTXORB_FTDI_RANGE_0113_PID 0x0113 -#define MTXORB_FTDI_RANGE_0114_PID 0x0114 -#define MTXORB_FTDI_RANGE_0115_PID 0x0115 -#define MTXORB_FTDI_RANGE_0116_PID 0x0116 -#define MTXORB_FTDI_RANGE_0117_PID 0x0117 -#define MTXORB_FTDI_RANGE_0118_PID 0x0118 -#define MTXORB_FTDI_RANGE_0119_PID 0x0119 -#define MTXORB_FTDI_RANGE_011A_PID 0x011A -#define MTXORB_FTDI_RANGE_011B_PID 0x011B -#define MTXORB_FTDI_RANGE_011C_PID 0x011C -#define MTXORB_FTDI_RANGE_011D_PID 0x011D -#define MTXORB_FTDI_RANGE_011E_PID 0x011E -#define MTXORB_FTDI_RANGE_011F_PID 0x011F -#define MTXORB_FTDI_RANGE_0120_PID 0x0120 -#define MTXORB_FTDI_RANGE_0121_PID 0x0121 -#define MTXORB_FTDI_RANGE_0122_PID 0x0122 -#define MTXORB_FTDI_RANGE_0123_PID 0x0123 -#define MTXORB_FTDI_RANGE_0124_PID 0x0124 -#define MTXORB_FTDI_RANGE_0125_PID 0x0125 -#define MTXORB_FTDI_RANGE_0126_PID 0x0126 -#define MTXORB_FTDI_RANGE_0127_PID 0x0127 -#define MTXORB_FTDI_RANGE_0128_PID 0x0128 -#define MTXORB_FTDI_RANGE_0129_PID 0x0129 -#define MTXORB_FTDI_RANGE_012A_PID 0x012A -#define MTXORB_FTDI_RANGE_012B_PID 0x012B -#define MTXORB_FTDI_RANGE_012C_PID 0x012C -#define MTXORB_FTDI_RANGE_012D_PID 0x012D -#define MTXORB_FTDI_RANGE_012E_PID 0x012E -#define MTXORB_FTDI_RANGE_012F_PID 0x012F -#define MTXORB_FTDI_RANGE_0130_PID 0x0130 -#define MTXORB_FTDI_RANGE_0131_PID 0x0131 -#define MTXORB_FTDI_RANGE_0132_PID 0x0132 -#define MTXORB_FTDI_RANGE_0133_PID 0x0133 -#define MTXORB_FTDI_RANGE_0134_PID 0x0134 -#define MTXORB_FTDI_RANGE_0135_PID 0x0135 -#define MTXORB_FTDI_RANGE_0136_PID 0x0136 -#define MTXORB_FTDI_RANGE_0137_PID 0x0137 -#define MTXORB_FTDI_RANGE_0138_PID 0x0138 -#define MTXORB_FTDI_RANGE_0139_PID 0x0139 -#define MTXORB_FTDI_RANGE_013A_PID 0x013A -#define MTXORB_FTDI_RANGE_013B_PID 0x013B -#define MTXORB_FTDI_RANGE_013C_PID 0x013C -#define MTXORB_FTDI_RANGE_013D_PID 0x013D -#define MTXORB_FTDI_RANGE_013E_PID 0x013E -#define MTXORB_FTDI_RANGE_013F_PID 0x013F -#define MTXORB_FTDI_RANGE_0140_PID 0x0140 -#define MTXORB_FTDI_RANGE_0141_PID 0x0141 -#define MTXORB_FTDI_RANGE_0142_PID 0x0142 -#define MTXORB_FTDI_RANGE_0143_PID 0x0143 -#define MTXORB_FTDI_RANGE_0144_PID 0x0144 -#define MTXORB_FTDI_RANGE_0145_PID 0x0145 -#define MTXORB_FTDI_RANGE_0146_PID 0x0146 -#define MTXORB_FTDI_RANGE_0147_PID 0x0147 -#define MTXORB_FTDI_RANGE_0148_PID 0x0148 -#define MTXORB_FTDI_RANGE_0149_PID 0x0149 -#define MTXORB_FTDI_RANGE_014A_PID 0x014A -#define MTXORB_FTDI_RANGE_014B_PID 0x014B -#define MTXORB_FTDI_RANGE_014C_PID 0x014C -#define MTXORB_FTDI_RANGE_014D_PID 0x014D -#define MTXORB_FTDI_RANGE_014E_PID 0x014E -#define MTXORB_FTDI_RANGE_014F_PID 0x014F -#define MTXORB_FTDI_RANGE_0150_PID 0x0150 -#define MTXORB_FTDI_RANGE_0151_PID 0x0151 -#define MTXORB_FTDI_RANGE_0152_PID 0x0152 -#define MTXORB_FTDI_RANGE_0153_PID 0x0153 -#define MTXORB_FTDI_RANGE_0154_PID 0x0154 -#define MTXORB_FTDI_RANGE_0155_PID 0x0155 -#define MTXORB_FTDI_RANGE_0156_PID 0x0156 -#define MTXORB_FTDI_RANGE_0157_PID 0x0157 -#define MTXORB_FTDI_RANGE_0158_PID 0x0158 -#define MTXORB_FTDI_RANGE_0159_PID 0x0159 -#define MTXORB_FTDI_RANGE_015A_PID 0x015A -#define MTXORB_FTDI_RANGE_015B_PID 0x015B -#define MTXORB_FTDI_RANGE_015C_PID 0x015C -#define MTXORB_FTDI_RANGE_015D_PID 0x015D -#define MTXORB_FTDI_RANGE_015E_PID 0x015E -#define MTXORB_FTDI_RANGE_015F_PID 0x015F -#define MTXORB_FTDI_RANGE_0160_PID 0x0160 -#define MTXORB_FTDI_RANGE_0161_PID 0x0161 -#define MTXORB_FTDI_RANGE_0162_PID 0x0162 -#define MTXORB_FTDI_RANGE_0163_PID 0x0163 -#define MTXORB_FTDI_RANGE_0164_PID 0x0164 -#define MTXORB_FTDI_RANGE_0165_PID 0x0165 -#define MTXORB_FTDI_RANGE_0166_PID 0x0166 -#define MTXORB_FTDI_RANGE_0167_PID 0x0167 -#define MTXORB_FTDI_RANGE_0168_PID 0x0168 -#define MTXORB_FTDI_RANGE_0169_PID 0x0169 -#define MTXORB_FTDI_RANGE_016A_PID 0x016A -#define MTXORB_FTDI_RANGE_016B_PID 0x016B -#define MTXORB_FTDI_RANGE_016C_PID 0x016C -#define MTXORB_FTDI_RANGE_016D_PID 0x016D -#define MTXORB_FTDI_RANGE_016E_PID 0x016E -#define MTXORB_FTDI_RANGE_016F_PID 0x016F -#define MTXORB_FTDI_RANGE_0170_PID 0x0170 -#define MTXORB_FTDI_RANGE_0171_PID 0x0171 -#define MTXORB_FTDI_RANGE_0172_PID 0x0172 -#define MTXORB_FTDI_RANGE_0173_PID 0x0173 -#define MTXORB_FTDI_RANGE_0174_PID 0x0174 -#define MTXORB_FTDI_RANGE_0175_PID 0x0175 -#define MTXORB_FTDI_RANGE_0176_PID 0x0176 -#define MTXORB_FTDI_RANGE_0177_PID 0x0177 -#define MTXORB_FTDI_RANGE_0178_PID 0x0178 -#define MTXORB_FTDI_RANGE_0179_PID 0x0179 -#define MTXORB_FTDI_RANGE_017A_PID 0x017A -#define MTXORB_FTDI_RANGE_017B_PID 0x017B -#define MTXORB_FTDI_RANGE_017C_PID 0x017C -#define MTXORB_FTDI_RANGE_017D_PID 0x017D -#define MTXORB_FTDI_RANGE_017E_PID 0x017E -#define MTXORB_FTDI_RANGE_017F_PID 0x017F -#define MTXORB_FTDI_RANGE_0180_PID 0x0180 -#define MTXORB_FTDI_RANGE_0181_PID 0x0181 -#define MTXORB_FTDI_RANGE_0182_PID 0x0182 -#define MTXORB_FTDI_RANGE_0183_PID 0x0183 -#define MTXORB_FTDI_RANGE_0184_PID 0x0184 -#define MTXORB_FTDI_RANGE_0185_PID 0x0185 -#define MTXORB_FTDI_RANGE_0186_PID 0x0186 -#define MTXORB_FTDI_RANGE_0187_PID 0x0187 -#define MTXORB_FTDI_RANGE_0188_PID 0x0188 -#define MTXORB_FTDI_RANGE_0189_PID 0x0189 -#define MTXORB_FTDI_RANGE_018A_PID 0x018A -#define MTXORB_FTDI_RANGE_018B_PID 0x018B -#define MTXORB_FTDI_RANGE_018C_PID 0x018C -#define MTXORB_FTDI_RANGE_018D_PID 0x018D -#define MTXORB_FTDI_RANGE_018E_PID 0x018E -#define MTXORB_FTDI_RANGE_018F_PID 0x018F -#define MTXORB_FTDI_RANGE_0190_PID 0x0190 -#define MTXORB_FTDI_RANGE_0191_PID 0x0191 -#define MTXORB_FTDI_RANGE_0192_PID 0x0192 -#define MTXORB_FTDI_RANGE_0193_PID 0x0193 -#define MTXORB_FTDI_RANGE_0194_PID 0x0194 -#define MTXORB_FTDI_RANGE_0195_PID 0x0195 -#define MTXORB_FTDI_RANGE_0196_PID 0x0196 -#define MTXORB_FTDI_RANGE_0197_PID 0x0197 -#define MTXORB_FTDI_RANGE_0198_PID 0x0198 -#define MTXORB_FTDI_RANGE_0199_PID 0x0199 -#define MTXORB_FTDI_RANGE_019A_PID 0x019A -#define MTXORB_FTDI_RANGE_019B_PID 0x019B -#define MTXORB_FTDI_RANGE_019C_PID 0x019C -#define MTXORB_FTDI_RANGE_019D_PID 0x019D -#define MTXORB_FTDI_RANGE_019E_PID 0x019E -#define MTXORB_FTDI_RANGE_019F_PID 0x019F -#define MTXORB_FTDI_RANGE_01A0_PID 0x01A0 -#define MTXORB_FTDI_RANGE_01A1_PID 0x01A1 -#define MTXORB_FTDI_RANGE_01A2_PID 0x01A2 -#define MTXORB_FTDI_RANGE_01A3_PID 0x01A3 -#define MTXORB_FTDI_RANGE_01A4_PID 0x01A4 -#define MTXORB_FTDI_RANGE_01A5_PID 0x01A5 -#define MTXORB_FTDI_RANGE_01A6_PID 0x01A6 -#define MTXORB_FTDI_RANGE_01A7_PID 0x01A7 -#define MTXORB_FTDI_RANGE_01A8_PID 0x01A8 -#define MTXORB_FTDI_RANGE_01A9_PID 0x01A9 -#define MTXORB_FTDI_RANGE_01AA_PID 0x01AA -#define MTXORB_FTDI_RANGE_01AB_PID 0x01AB -#define MTXORB_FTDI_RANGE_01AC_PID 0x01AC -#define MTXORB_FTDI_RANGE_01AD_PID 0x01AD -#define MTXORB_FTDI_RANGE_01AE_PID 0x01AE -#define MTXORB_FTDI_RANGE_01AF_PID 0x01AF -#define MTXORB_FTDI_RANGE_01B0_PID 0x01B0 -#define MTXORB_FTDI_RANGE_01B1_PID 0x01B1 -#define MTXORB_FTDI_RANGE_01B2_PID 0x01B2 -#define MTXORB_FTDI_RANGE_01B3_PID 0x01B3 -#define MTXORB_FTDI_RANGE_01B4_PID 0x01B4 -#define MTXORB_FTDI_RANGE_01B5_PID 0x01B5 -#define MTXORB_FTDI_RANGE_01B6_PID 0x01B6 -#define MTXORB_FTDI_RANGE_01B7_PID 0x01B7 -#define MTXORB_FTDI_RANGE_01B8_PID 0x01B8 -#define MTXORB_FTDI_RANGE_01B9_PID 0x01B9 -#define MTXORB_FTDI_RANGE_01BA_PID 0x01BA -#define MTXORB_FTDI_RANGE_01BB_PID 0x01BB -#define MTXORB_FTDI_RANGE_01BC_PID 0x01BC -#define MTXORB_FTDI_RANGE_01BD_PID 0x01BD -#define MTXORB_FTDI_RANGE_01BE_PID 0x01BE -#define MTXORB_FTDI_RANGE_01BF_PID 0x01BF -#define MTXORB_FTDI_RANGE_01C0_PID 0x01C0 -#define MTXORB_FTDI_RANGE_01C1_PID 0x01C1 -#define MTXORB_FTDI_RANGE_01C2_PID 0x01C2 -#define MTXORB_FTDI_RANGE_01C3_PID 0x01C3 -#define MTXORB_FTDI_RANGE_01C4_PID 0x01C4 -#define MTXORB_FTDI_RANGE_01C5_PID 0x01C5 -#define MTXORB_FTDI_RANGE_01C6_PID 0x01C6 -#define MTXORB_FTDI_RANGE_01C7_PID 0x01C7 -#define MTXORB_FTDI_RANGE_01C8_PID 0x01C8 -#define MTXORB_FTDI_RANGE_01C9_PID 0x01C9 -#define MTXORB_FTDI_RANGE_01CA_PID 0x01CA -#define MTXORB_FTDI_RANGE_01CB_PID 0x01CB -#define MTXORB_FTDI_RANGE_01CC_PID 0x01CC -#define MTXORB_FTDI_RANGE_01CD_PID 0x01CD -#define MTXORB_FTDI_RANGE_01CE_PID 0x01CE -#define MTXORB_FTDI_RANGE_01CF_PID 0x01CF -#define MTXORB_FTDI_RANGE_01D0_PID 0x01D0 -#define MTXORB_FTDI_RANGE_01D1_PID 0x01D1 -#define MTXORB_FTDI_RANGE_01D2_PID 0x01D2 -#define MTXORB_FTDI_RANGE_01D3_PID 0x01D3 -#define MTXORB_FTDI_RANGE_01D4_PID 0x01D4 -#define MTXORB_FTDI_RANGE_01D5_PID 0x01D5 -#define MTXORB_FTDI_RANGE_01D6_PID 0x01D6 -#define MTXORB_FTDI_RANGE_01D7_PID 0x01D7 -#define MTXORB_FTDI_RANGE_01D8_PID 0x01D8 -#define MTXORB_FTDI_RANGE_01D9_PID 0x01D9 -#define MTXORB_FTDI_RANGE_01DA_PID 0x01DA -#define MTXORB_FTDI_RANGE_01DB_PID 0x01DB -#define MTXORB_FTDI_RANGE_01DC_PID 0x01DC -#define MTXORB_FTDI_RANGE_01DD_PID 0x01DD -#define MTXORB_FTDI_RANGE_01DE_PID 0x01DE -#define MTXORB_FTDI_RANGE_01DF_PID 0x01DF -#define MTXORB_FTDI_RANGE_01E0_PID 0x01E0 -#define MTXORB_FTDI_RANGE_01E1_PID 0x01E1 -#define MTXORB_FTDI_RANGE_01E2_PID 0x01E2 -#define MTXORB_FTDI_RANGE_01E3_PID 0x01E3 -#define MTXORB_FTDI_RANGE_01E4_PID 0x01E4 -#define MTXORB_FTDI_RANGE_01E5_PID 0x01E5 -#define MTXORB_FTDI_RANGE_01E6_PID 0x01E6 -#define MTXORB_FTDI_RANGE_01E7_PID 0x01E7 -#define MTXORB_FTDI_RANGE_01E8_PID 0x01E8 -#define MTXORB_FTDI_RANGE_01E9_PID 0x01E9 -#define MTXORB_FTDI_RANGE_01EA_PID 0x01EA -#define MTXORB_FTDI_RANGE_01EB_PID 0x01EB -#define MTXORB_FTDI_RANGE_01EC_PID 0x01EC -#define MTXORB_FTDI_RANGE_01ED_PID 0x01ED -#define MTXORB_FTDI_RANGE_01EE_PID 0x01EE -#define MTXORB_FTDI_RANGE_01EF_PID 0x01EF -#define MTXORB_FTDI_RANGE_01F0_PID 0x01F0 -#define MTXORB_FTDI_RANGE_01F1_PID 0x01F1 -#define MTXORB_FTDI_RANGE_01F2_PID 0x01F2 -#define MTXORB_FTDI_RANGE_01F3_PID 0x01F3 -#define MTXORB_FTDI_RANGE_01F4_PID 0x01F4 -#define MTXORB_FTDI_RANGE_01F5_PID 0x01F5 -#define MTXORB_FTDI_RANGE_01F6_PID 0x01F6 -#define MTXORB_FTDI_RANGE_01F7_PID 0x01F7 -#define MTXORB_FTDI_RANGE_01F8_PID 0x01F8 -#define MTXORB_FTDI_RANGE_01F9_PID 0x01F9 -#define MTXORB_FTDI_RANGE_01FA_PID 0x01FA -#define MTXORB_FTDI_RANGE_01FB_PID 0x01FB -#define MTXORB_FTDI_RANGE_01FC_PID 0x01FC -#define MTXORB_FTDI_RANGE_01FD_PID 0x01FD -#define MTXORB_FTDI_RANGE_01FE_PID 0x01FE -#define MTXORB_FTDI_RANGE_01FF_PID 0x01FF - - - -/* - * The Mobility Lab (TML) - * Submitted by Pierre Castella - */ -#define TML_VID 0x1B91 /* Vendor ID */ -#define TML_USB_SERIAL_PID 0x0064 /* USB - Serial Converter */ - -/* Alti-2 products http://www.alti-2.com */ -#define ALTI2_VID 0x1BC9 -#define ALTI2_N3_PID 0x6001 /* Neptune 3 */ - -/* - * Ionics PlugComputer - */ -#define IONICS_VID 0x1c0c -#define IONICS_PLUGCOMPUTER_PID 0x0102 - -/* - * Dresden Elektronik Sensor Terminal Board - */ -#define DE_VID 0x1cf1 /* Vendor ID */ -#define STB_PID 0x0001 /* Sensor Terminal Board */ -#define WHT_PID 0x0004 /* Wireless Handheld Terminal */ - -/* - * STMicroelectonics - */ -#define ST_VID 0x0483 -#define ST_STMCLT1030_PID 0x3747 /* ST Micro Connect Lite STMCLT1030 */ - -/* - * Papouch products (http://www.papouch.com/) - * Submitted by Folkert van Heusden - */ - -#define PAPOUCH_VID 0x5050 /* Vendor ID */ -#define PAPOUCH_SB485_PID 0x0100 /* Papouch SB485 USB-485/422 Converter */ -#define PAPOUCH_AP485_PID 0x0101 /* AP485 USB-RS485 Converter */ -#define PAPOUCH_SB422_PID 0x0102 /* Papouch SB422 USB-RS422 Converter */ -#define PAPOUCH_SB485_2_PID 0x0103 /* Papouch SB485 USB-485/422 Converter */ -#define PAPOUCH_AP485_2_PID 0x0104 /* AP485 USB-RS485 Converter */ -#define PAPOUCH_SB422_2_PID 0x0105 /* Papouch SB422 USB-RS422 Converter */ -#define PAPOUCH_SB485S_PID 0x0106 /* Papouch SB485S USB-485/422 Converter */ -#define PAPOUCH_SB485C_PID 0x0107 /* Papouch SB485C USB-485/422 Converter */ -#define PAPOUCH_LEC_PID 0x0300 /* LEC USB Converter */ -#define PAPOUCH_SB232_PID 0x0301 /* Papouch SB232 USB-RS232 Converter */ -#define PAPOUCH_TMU_PID 0x0400 /* TMU USB Thermometer */ -#define PAPOUCH_IRAMP_PID 0x0500 /* Papouch IRAmp Duplex */ -#define PAPOUCH_DRAK5_PID 0x0700 /* Papouch DRAK5 */ -#define PAPOUCH_QUIDO8x8_PID 0x0800 /* Papouch Quido 8/8 Module */ -#define PAPOUCH_QUIDO4x4_PID 0x0900 /* Papouch Quido 4/4 Module */ -#define PAPOUCH_QUIDO2x2_PID 0x0a00 /* Papouch Quido 2/2 Module */ -#define PAPOUCH_QUIDO10x1_PID 0x0b00 /* Papouch Quido 10/1 Module */ -#define PAPOUCH_QUIDO30x3_PID 0x0c00 /* Papouch Quido 30/3 Module */ -#define PAPOUCH_QUIDO60x3_PID 0x0d00 /* Papouch Quido 60(100)/3 Module */ -#define PAPOUCH_QUIDO2x16_PID 0x0e00 /* Papouch Quido 2/16 Module */ -#define PAPOUCH_QUIDO3x32_PID 0x0f00 /* Papouch Quido 3/32 Module */ -#define PAPOUCH_DRAK6_PID 0x1000 /* Papouch DRAK6 */ -#define PAPOUCH_UPSUSB_PID 0x8000 /* Papouch UPS-USB adapter */ -#define PAPOUCH_MU_PID 0x8001 /* MU controller */ -#define PAPOUCH_SIMUKEY_PID 0x8002 /* Papouch SimuKey */ -#define PAPOUCH_AD4USB_PID 0x8003 /* AD4USB Measurement Module */ -#define PAPOUCH_GMUX_PID 0x8004 /* Papouch GOLIATH MUX */ -#define PAPOUCH_GMSR_PID 0x8005 /* Papouch GOLIATH MSR */ - -/* - * Marvell SheevaPlug - */ -#define MARVELL_VID 0x9e88 -#define MARVELL_SHEEVAPLUG_PID 0x9e8f - -/* - * Evolution Robotics products (http://www.evolution.com/). - * Submitted by Shawn M. Lavelle. - */ -#define EVOLUTION_VID 0xDEEE /* Vendor ID */ -#define EVOLUTION_ER1_PID 0x0300 /* ER1 Control Module */ -#define EVO_8U232AM_PID 0x02FF /* Evolution robotics RCM2 (FT232AM)*/ -#define EVO_HYBRID_PID 0x0302 /* Evolution robotics RCM4 PID (FT232BM)*/ -#define EVO_RCM4_PID 0x0303 /* Evolution robotics RCM4 PID */ - -/* - * MJS Gadgets HD Radio / XM Radio / Sirius Radio interfaces (using VID 0x0403) - */ -#define MJSG_GENERIC_PID 0x9378 -#define MJSG_SR_RADIO_PID 0x9379 -#define MJSG_XM_RADIO_PID 0x937A -#define MJSG_HD_RADIO_PID 0x937C - -/* - * D.O.Tec products (http://www.directout.eu) - */ -#define FTDI_DOTEC_PID 0x9868 - -/* - * Xverve Signalyzer tools (http://www.signalyzer.com/) - */ -#define XVERVE_SIGNALYZER_ST_PID 0xBCA0 -#define XVERVE_SIGNALYZER_SLITE_PID 0xBCA1 -#define XVERVE_SIGNALYZER_SH2_PID 0xBCA2 -#define XVERVE_SIGNALYZER_SH4_PID 0xBCA4 - -/* - * Segway Robotic Mobility Platform USB interface (using VID 0x0403) - * Submitted by John G. Rogers - */ -#define SEGWAY_RMP200_PID 0xe729 - - -/* - * Accesio USB Data Acquisition products (http://www.accesio.com/) - */ -#define ACCESIO_COM4SM_PID 0xD578 - -/* www.sciencescope.co.uk educational dataloggers */ -#define FTDI_SCIENCESCOPE_LOGBOOKML_PID 0xFF18 -#define FTDI_SCIENCESCOPE_LS_LOGBOOK_PID 0xFF1C -#define FTDI_SCIENCESCOPE_HS_LOGBOOK_PID 0xFF1D - -/* - * Milkymist One JTAG/Serial - */ -#define QIHARDWARE_VID 0x20B7 -#define MILKYMISTONE_JTAGSERIAL_PID 0x0713 - -/* - * CTI GmbH RS485 Converter http://www.cti-lean.com/ - */ -/* USB-485-Mini*/ -#define FTDI_CTI_MINI_PID 0xF608 -/* USB-Nano-485*/ -#define FTDI_CTI_NANO_PID 0xF60B - -/* - * ZeitControl cardsystems GmbH rfid-readers http://zeitconrol.de - */ -/* TagTracer MIFARE*/ -#define FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID 0xF7C0 - -/* - * Rainforest Automation - */ -/* ZigBee controller */ -#define FTDI_RF_R106 0x8A28 - -/* - * Product: HCP HIT GPRS modem - * Manufacturer: HCP d.o.o. - * ATI command output: Cinterion MC55i - */ -#define FTDI_CINTERION_MC55I_PID 0xA951 diff --git a/ANDROID_3.4.5/drivers/usb/serial/funsoft.c b/ANDROID_3.4.5/drivers/usb/serial/funsoft.c deleted file mode 100644 index 4577b360..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/funsoft.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Funsoft Serial USB driver - * - * Copyright (C) 2006 Greg Kroah-Hartman - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include - -static bool debug; - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(0x1404, 0xcddc) }, - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver funsoft_driver = { - .name = "funsoft", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - -static struct usb_serial_driver funsoft_device = { - .driver = { - .owner = THIS_MODULE, - .name = "funsoft", - }, - .id_table = id_table, - .num_ports = 1, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &funsoft_device, NULL -}; - -module_usb_serial_driver(funsoft_driver, serial_drivers); - -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/garmin_gps.c b/ANDROID_3.4.5/drivers/usb/serial/garmin_gps.c deleted file mode 100644 index e8eb6347..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/garmin_gps.c +++ /dev/null @@ -1,1528 +0,0 @@ -/* - * Garmin GPS driver - * - * Copyright (C) 2006-2011 Hermann Kneissel herkne@gmx.de - * - * The latest version of the driver can be found at - * http://sourceforge.net/projects/garmin-gps/ - * - * This driver has been derived from v2.1 of the visor driver. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* the mode to be set when the port ist opened */ -static int initial_mode = 1; - -/* debug flag */ -static bool debug; - -#define GARMIN_VENDOR_ID 0x091E - -/* - * Version Information - */ - -#define VERSION_MAJOR 0 -#define VERSION_MINOR 36 - -#define _STR(s) #s -#define _DRIVER_VERSION(a, b) "v" _STR(a) "." _STR(b) -#define DRIVER_VERSION _DRIVER_VERSION(VERSION_MAJOR, VERSION_MINOR) -#define DRIVER_AUTHOR "hermann kneissel" -#define DRIVER_DESC "garmin gps driver" - -/* error codes returned by the driver */ -#define EINVPKT 1000 /* invalid packet structure */ - - -/* size of the header of a packet using the usb protocol */ -#define GARMIN_PKTHDR_LENGTH 12 - -/* max. possible size of a packet using the serial protocol */ -#define MAX_SERIAL_PKT_SIZ (3 + 255 + 3) - -/* max. possible size of a packet with worst case stuffing */ -#define MAX_SERIAL_PKT_SIZ_STUFFED (MAX_SERIAL_PKT_SIZ + 256) - -/* size of a buffer able to hold a complete (no stuffing) packet - * (the document protocol does not contain packets with a larger - * size, but in theory a packet may be 64k+12 bytes - if in - * later protocol versions larger packet sizes occur, this value - * should be increased accordingly, so the input buffer is always - * large enough the store a complete packet inclusive header) */ -#define GPS_IN_BUFSIZ (GARMIN_PKTHDR_LENGTH+MAX_SERIAL_PKT_SIZ) - -/* size of a buffer able to hold a complete (incl. stuffing) packet */ -#define GPS_OUT_BUFSIZ (GARMIN_PKTHDR_LENGTH+MAX_SERIAL_PKT_SIZ_STUFFED) - -/* where to place the packet id of a serial packet, so we can - * prepend the usb-packet header without the need to move the - * packets data */ -#define GSP_INITIAL_OFFSET (GARMIN_PKTHDR_LENGTH-2) - -/* max. size of incoming private packets (header+1 param) */ -#define PRIVPKTSIZ (GARMIN_PKTHDR_LENGTH+4) - -#define GARMIN_LAYERID_TRANSPORT 0 -#define GARMIN_LAYERID_APPL 20 -/* our own layer-id to use for some control mechanisms */ -#define GARMIN_LAYERID_PRIVATE 0x01106E4B - -#define GARMIN_PKTID_PVT_DATA 51 -#define GARMIN_PKTID_L001_COMMAND_DATA 10 - -#define CMND_ABORT_TRANSFER 0 - -/* packet ids used in private layer */ -#define PRIV_PKTID_SET_DEBUG 1 -#define PRIV_PKTID_SET_MODE 2 -#define PRIV_PKTID_INFO_REQ 3 -#define PRIV_PKTID_INFO_RESP 4 -#define PRIV_PKTID_RESET_REQ 5 -#define PRIV_PKTID_SET_DEF_MODE 6 - - -#define ETX 0x03 -#define DLE 0x10 -#define ACK 0x06 -#define NAK 0x15 - -/* structure used to queue incoming packets */ -struct garmin_packet { - struct list_head list; - int seq; - /* the real size of the data array, always > 0 */ - int size; - __u8 data[1]; -}; - -/* structure used to keep the current state of the driver */ -struct garmin_data { - __u8 state; - __u16 flags; - __u8 mode; - __u8 count; - __u8 pkt_id; - __u32 serial_num; - struct timer_list timer; - struct usb_serial_port *port; - int seq_counter; - int insize; - int outsize; - __u8 inbuffer [GPS_IN_BUFSIZ]; /* tty -> usb */ - __u8 outbuffer[GPS_OUT_BUFSIZ]; /* usb -> tty */ - __u8 privpkt[4*6]; - spinlock_t lock; - struct list_head pktlist; -}; - - -#define STATE_NEW 0 -#define STATE_INITIAL_DELAY 1 -#define STATE_TIMEOUT 2 -#define STATE_SESSION_REQ1 3 -#define STATE_SESSION_REQ2 4 -#define STATE_ACTIVE 5 - -#define STATE_RESET 8 -#define STATE_DISCONNECTED 9 -#define STATE_WAIT_TTY_ACK 10 -#define STATE_GSP_WAIT_DATA 11 - -#define MODE_NATIVE 0 -#define MODE_GARMIN_SERIAL 1 - -/* Flags used in garmin_data.flags: */ -#define FLAGS_SESSION_REPLY_MASK 0x00C0 -#define FLAGS_SESSION_REPLY1_SEEN 0x0080 -#define FLAGS_SESSION_REPLY2_SEEN 0x0040 -#define FLAGS_BULK_IN_ACTIVE 0x0020 -#define FLAGS_BULK_IN_RESTART 0x0010 -#define FLAGS_THROTTLED 0x0008 -#define APP_REQ_SEEN 0x0004 -#define APP_RESP_SEEN 0x0002 -#define CLEAR_HALT_REQUIRED 0x0001 - -#define FLAGS_QUEUING 0x0100 -#define FLAGS_DROP_DATA 0x0800 - -#define FLAGS_GSP_SKIP 0x1000 -#define FLAGS_GSP_DLESEEN 0x2000 - - - - - - -/* function prototypes */ -static int gsp_next_packet(struct garmin_data *garmin_data_p); -static int garmin_write_bulk(struct usb_serial_port *port, - const unsigned char *buf, int count, - int dismiss_ack); - -/* some special packets to be send or received */ -static unsigned char const GARMIN_START_SESSION_REQ[] - = { 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0 }; -static unsigned char const GARMIN_START_SESSION_REPLY[] - = { 0, 0, 0, 0, 6, 0, 0, 0, 4, 0, 0, 0 }; -static unsigned char const GARMIN_BULK_IN_AVAIL_REPLY[] - = { 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0 }; -static unsigned char const GARMIN_APP_LAYER_REPLY[] - = { 0x14, 0, 0, 0 }; -static unsigned char const GARMIN_START_PVT_REQ[] - = { 20, 0, 0, 0, 10, 0, 0, 0, 2, 0, 0, 0, 49, 0 }; -static unsigned char const GARMIN_STOP_PVT_REQ[] - = { 20, 0, 0, 0, 10, 0, 0, 0, 2, 0, 0, 0, 50, 0 }; -static unsigned char const GARMIN_STOP_TRANSFER_REQ[] - = { 20, 0, 0, 0, 10, 0, 0, 0, 2, 0, 0, 0, 0, 0 }; -static unsigned char const GARMIN_STOP_TRANSFER_REQ_V2[] - = { 20, 0, 0, 0, 10, 0, 0, 0, 1, 0, 0, 0, 0 }; -static unsigned char const PRIVATE_REQ[] - = { 0x4B, 0x6E, 0x10, 0x01, 0xFF, 0, 0, 0, 0xFF, 0, 0, 0 }; - - - -static const struct usb_device_id id_table[] = { - /* the same device id seems to be used by all - usb enabled GPS devices */ - { USB_DEVICE(GARMIN_VENDOR_ID, 3) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver garmin_driver = { - .name = "garmin_gps", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - - -static inline int getLayerId(const __u8 *usbPacket) -{ - return __le32_to_cpup((__le32 *)(usbPacket)); -} - -static inline int getPacketId(const __u8 *usbPacket) -{ - return __le32_to_cpup((__le32 *)(usbPacket+4)); -} - -static inline int getDataLength(const __u8 *usbPacket) -{ - return __le32_to_cpup((__le32 *)(usbPacket+8)); -} - - -/* - * check if the usb-packet in buf contains an abort-transfer command. - * (if yes, all queued data will be dropped) - */ -static inline int isAbortTrfCmnd(const unsigned char *buf) -{ - if (0 == memcmp(buf, GARMIN_STOP_TRANSFER_REQ, - sizeof(GARMIN_STOP_TRANSFER_REQ)) || - 0 == memcmp(buf, GARMIN_STOP_TRANSFER_REQ_V2, - sizeof(GARMIN_STOP_TRANSFER_REQ_V2))) - return 1; - else - return 0; -} - - - -static void send_to_tty(struct usb_serial_port *port, - char *data, unsigned int actual_length) -{ - struct tty_struct *tty = tty_port_tty_get(&port->port); - - if (tty && actual_length) { - - usb_serial_debug_data(debug, &port->dev, - __func__, actual_length, data); - - tty_insert_flip_string(tty, data, actual_length); - tty_flip_buffer_push(tty); - } - tty_kref_put(tty); -} - - -/****************************************************************************** - * packet queue handling - ******************************************************************************/ - -/* - * queue a received (usb-)packet for later processing - */ -static int pkt_add(struct garmin_data *garmin_data_p, - unsigned char *data, unsigned int data_length) -{ - int state = 0; - int result = 0; - unsigned long flags; - struct garmin_packet *pkt; - - /* process only packets containg data ... */ - if (data_length) { - pkt = kmalloc(sizeof(struct garmin_packet)+data_length, - GFP_ATOMIC); - if (pkt == NULL) { - dev_err(&garmin_data_p->port->dev, "out of memory\n"); - return 0; - } - pkt->size = data_length; - memcpy(pkt->data, data, data_length); - - spin_lock_irqsave(&garmin_data_p->lock, flags); - garmin_data_p->flags |= FLAGS_QUEUING; - result = list_empty(&garmin_data_p->pktlist); - pkt->seq = garmin_data_p->seq_counter++; - list_add_tail(&pkt->list, &garmin_data_p->pktlist); - state = garmin_data_p->state; - spin_unlock_irqrestore(&garmin_data_p->lock, flags); - - dbg("%s - added: pkt: %d - %d bytes", - __func__, pkt->seq, data_length); - - /* in serial mode, if someone is waiting for data from - the device, convert and send the next packet to tty. */ - if (result && (state == STATE_GSP_WAIT_DATA)) - gsp_next_packet(garmin_data_p); - } - return result; -} - - -/* get the next pending packet */ -static struct garmin_packet *pkt_pop(struct garmin_data *garmin_data_p) -{ - unsigned long flags; - struct garmin_packet *result = NULL; - - spin_lock_irqsave(&garmin_data_p->lock, flags); - if (!list_empty(&garmin_data_p->pktlist)) { - result = (struct garmin_packet *)garmin_data_p->pktlist.next; - list_del(&result->list); - } - spin_unlock_irqrestore(&garmin_data_p->lock, flags); - return result; -} - - -/* free up all queued data */ -static void pkt_clear(struct garmin_data *garmin_data_p) -{ - unsigned long flags; - struct garmin_packet *result = NULL; - - dbg("%s", __func__); - - spin_lock_irqsave(&garmin_data_p->lock, flags); - while (!list_empty(&garmin_data_p->pktlist)) { - result = (struct garmin_packet *)garmin_data_p->pktlist.next; - list_del(&result->list); - kfree(result); - } - spin_unlock_irqrestore(&garmin_data_p->lock, flags); -} - - -/****************************************************************************** - * garmin serial protocol handling handling - ******************************************************************************/ - -/* send an ack packet back to the tty */ -static int gsp_send_ack(struct garmin_data *garmin_data_p, __u8 pkt_id) -{ - __u8 pkt[10]; - __u8 cksum = 0; - __u8 *ptr = pkt; - unsigned l = 0; - - dbg("%s - pkt-id: 0x%X.", __func__, 0xFF & pkt_id); - - *ptr++ = DLE; - *ptr++ = ACK; - cksum += ACK; - - *ptr++ = 2; - cksum += 2; - - *ptr++ = pkt_id; - cksum += pkt_id; - - if (pkt_id == DLE) - *ptr++ = DLE; - - *ptr++ = 0; - *ptr++ = 0xFF & (-cksum); - *ptr++ = DLE; - *ptr++ = ETX; - - l = ptr-pkt; - - send_to_tty(garmin_data_p->port, pkt, l); - return 0; -} - - - -/* - * called for a complete packet received from tty layer - * - * the complete packet (pktid ... cksum) is in garmin_data_p->inbuf starting - * at GSP_INITIAL_OFFSET. - * - * count - number of bytes in the input buffer including space reserved for - * the usb header: GSP_INITIAL_OFFSET + number of bytes in packet - * (including pkt-id, data-length a. cksum) - */ -static int gsp_rec_packet(struct garmin_data *garmin_data_p, int count) -{ - unsigned long flags; - const __u8 *recpkt = garmin_data_p->inbuffer+GSP_INITIAL_OFFSET; - __le32 *usbdata = (__le32 *) garmin_data_p->inbuffer; - - int cksum = 0; - int n = 0; - int pktid = recpkt[0]; - int size = recpkt[1]; - - usb_serial_debug_data(debug, &garmin_data_p->port->dev, - __func__, count-GSP_INITIAL_OFFSET, recpkt); - - if (size != (count-GSP_INITIAL_OFFSET-3)) { - dbg("%s - invalid size, expected %d bytes, got %d", - __func__, size, (count-GSP_INITIAL_OFFSET-3)); - return -EINVPKT; - } - - cksum += *recpkt++; - cksum += *recpkt++; - - /* sanity check, remove after test ... */ - if ((__u8 *)&(usbdata[3]) != recpkt) { - dbg("%s - ptr mismatch %p - %p", - __func__, &(usbdata[4]), recpkt); - return -EINVPKT; - } - - while (n < size) { - cksum += *recpkt++; - n++; - } - - if ((0xff & (cksum + *recpkt)) != 0) { - dbg("%s - invalid checksum, expected %02x, got %02x", - __func__, 0xff & -cksum, 0xff & *recpkt); - return -EINVPKT; - } - - usbdata[0] = __cpu_to_le32(GARMIN_LAYERID_APPL); - usbdata[1] = __cpu_to_le32(pktid); - usbdata[2] = __cpu_to_le32(size); - - garmin_write_bulk(garmin_data_p->port, garmin_data_p->inbuffer, - GARMIN_PKTHDR_LENGTH+size, 0); - - /* if this was an abort-transfer command, flush all - queued data. */ - if (isAbortTrfCmnd(garmin_data_p->inbuffer)) { - spin_lock_irqsave(&garmin_data_p->lock, flags); - garmin_data_p->flags |= FLAGS_DROP_DATA; - spin_unlock_irqrestore(&garmin_data_p->lock, flags); - pkt_clear(garmin_data_p); - } - - return count; -} - - - -/* - * Called for data received from tty - * - * buf contains the data read, it may span more than one packet or even - * incomplete packets - * - * input record should be a serial-record, but it may not be complete. - * Copy it into our local buffer, until an etx is seen (or an error - * occurs). - * Once the record is complete, convert into a usb packet and send it - * to the bulk pipe, send an ack back to the tty. - * - * If the input is an ack, just send the last queued packet to the - * tty layer. - * - * if the input is an abort command, drop all queued data. - */ - -static int gsp_receive(struct garmin_data *garmin_data_p, - const unsigned char *buf, int count) -{ - unsigned long flags; - int offs = 0; - int ack_or_nak_seen = 0; - __u8 *dest; - int size; - /* dleSeen: set if last byte read was a DLE */ - int dleSeen; - /* skip: if set, skip incoming data until possible start of - * new packet - */ - int skip; - __u8 data; - - spin_lock_irqsave(&garmin_data_p->lock, flags); - dest = garmin_data_p->inbuffer; - size = garmin_data_p->insize; - dleSeen = garmin_data_p->flags & FLAGS_GSP_DLESEEN; - skip = garmin_data_p->flags & FLAGS_GSP_SKIP; - spin_unlock_irqrestore(&garmin_data_p->lock, flags); - - /* dbg("%s - dle=%d skip=%d size=%d count=%d", - __func__, dleSeen, skip, size, count); */ - - if (size == 0) - size = GSP_INITIAL_OFFSET; - - while (offs < count) { - - data = *(buf+offs); - offs++; - - if (data == DLE) { - if (skip) { /* start of a new pkt */ - skip = 0; - size = GSP_INITIAL_OFFSET; - dleSeen = 1; - } else if (dleSeen) { - dest[size++] = data; - dleSeen = 0; - } else { - dleSeen = 1; - } - } else if (data == ETX) { - if (dleSeen) { - /* packet complete */ - - data = dest[GSP_INITIAL_OFFSET]; - - if (data == ACK) { - ack_or_nak_seen = ACK; - dbg("ACK packet complete."); - } else if (data == NAK) { - ack_or_nak_seen = NAK; - dbg("NAK packet complete."); - } else { - dbg("packet complete - id=0x%X.", - 0xFF & data); - gsp_rec_packet(garmin_data_p, size); - } - - skip = 1; - size = GSP_INITIAL_OFFSET; - dleSeen = 0; - } else { - dest[size++] = data; - } - } else if (!skip) { - - if (dleSeen) { - size = GSP_INITIAL_OFFSET; - dleSeen = 0; - } - - dest[size++] = data; - } - - if (size >= GPS_IN_BUFSIZ) { - dbg("%s - packet too large.", __func__); - skip = 1; - size = GSP_INITIAL_OFFSET; - dleSeen = 0; - } - } - - spin_lock_irqsave(&garmin_data_p->lock, flags); - - garmin_data_p->insize = size; - - /* copy flags back to structure */ - if (skip) - garmin_data_p->flags |= FLAGS_GSP_SKIP; - else - garmin_data_p->flags &= ~FLAGS_GSP_SKIP; - - if (dleSeen) - garmin_data_p->flags |= FLAGS_GSP_DLESEEN; - else - garmin_data_p->flags &= ~FLAGS_GSP_DLESEEN; - - spin_unlock_irqrestore(&garmin_data_p->lock, flags); - - if (ack_or_nak_seen) { - if (gsp_next_packet(garmin_data_p) > 0) - garmin_data_p->state = STATE_ACTIVE; - else - garmin_data_p->state = STATE_GSP_WAIT_DATA; - } - return count; -} - - - -/* - * Sends a usb packet to the tty - * - * Assumes, that all packages and at an usb-packet boundary. - * - * return <0 on error, 0 if packet is incomplete or > 0 if packet was sent - */ -static int gsp_send(struct garmin_data *garmin_data_p, - const unsigned char *buf, int count) -{ - const unsigned char *src; - unsigned char *dst; - int pktid = 0; - int datalen = 0; - int cksum = 0; - int i = 0; - int k; - - dbg("%s - state %d - %d bytes.", __func__, - garmin_data_p->state, count); - - k = garmin_data_p->outsize; - if ((k+count) > GPS_OUT_BUFSIZ) { - dbg("packet too large"); - garmin_data_p->outsize = 0; - return -4; - } - - memcpy(garmin_data_p->outbuffer+k, buf, count); - k += count; - garmin_data_p->outsize = k; - - if (k >= GARMIN_PKTHDR_LENGTH) { - pktid = getPacketId(garmin_data_p->outbuffer); - datalen = getDataLength(garmin_data_p->outbuffer); - i = GARMIN_PKTHDR_LENGTH + datalen; - if (k < i) - return 0; - } else { - return 0; - } - - dbg("%s - %d bytes in buffer, %d bytes in pkt.", __func__, k, i); - - /* garmin_data_p->outbuffer now contains a complete packet */ - - usb_serial_debug_data(debug, &garmin_data_p->port->dev, - __func__, k, garmin_data_p->outbuffer); - - garmin_data_p->outsize = 0; - - if (GARMIN_LAYERID_APPL != getLayerId(garmin_data_p->outbuffer)) { - dbg("not an application packet (%d)", - getLayerId(garmin_data_p->outbuffer)); - return -1; - } - - if (pktid > 255) { - dbg("packet-id %d too large", pktid); - return -2; - } - - if (datalen > 255) { - dbg("packet-size %d too large", datalen); - return -3; - } - - /* the serial protocol should be able to handle this packet */ - - k = 0; - src = garmin_data_p->outbuffer+GARMIN_PKTHDR_LENGTH; - for (i = 0; i < datalen; i++) { - if (*src++ == DLE) - k++; - } - - src = garmin_data_p->outbuffer+GARMIN_PKTHDR_LENGTH; - if (k > (GARMIN_PKTHDR_LENGTH-2)) { - /* can't add stuffing DLEs in place, move data to end - of buffer ... */ - dst = garmin_data_p->outbuffer+GPS_OUT_BUFSIZ-datalen; - memcpy(dst, src, datalen); - src = dst; - } - - dst = garmin_data_p->outbuffer; - - *dst++ = DLE; - *dst++ = pktid; - cksum += pktid; - *dst++ = datalen; - cksum += datalen; - if (datalen == DLE) - *dst++ = DLE; - - for (i = 0; i < datalen; i++) { - __u8 c = *src++; - *dst++ = c; - cksum += c; - if (c == DLE) - *dst++ = DLE; - } - - cksum = 0xFF & -cksum; - *dst++ = cksum; - if (cksum == DLE) - *dst++ = DLE; - *dst++ = DLE; - *dst++ = ETX; - - i = dst-garmin_data_p->outbuffer; - - send_to_tty(garmin_data_p->port, garmin_data_p->outbuffer, i); - - garmin_data_p->pkt_id = pktid; - garmin_data_p->state = STATE_WAIT_TTY_ACK; - - return i; -} - - -/* - * Process the next pending data packet - if there is one - */ -static int gsp_next_packet(struct garmin_data *garmin_data_p) -{ - int result = 0; - struct garmin_packet *pkt = NULL; - - while ((pkt = pkt_pop(garmin_data_p)) != NULL) { - dbg("%s - next pkt: %d", __func__, pkt->seq); - result = gsp_send(garmin_data_p, pkt->data, pkt->size); - if (result > 0) { - kfree(pkt); - return result; - } - kfree(pkt); - } - return result; -} - - - -/****************************************************************************** - * garmin native mode - ******************************************************************************/ - - -/* - * Called for data received from tty - * - * The input data is expected to be in garmin usb-packet format. - * - * buf contains the data read, it may span more than one packet - * or even incomplete packets - */ -static int nat_receive(struct garmin_data *garmin_data_p, - const unsigned char *buf, int count) -{ - unsigned long flags; - __u8 *dest; - int offs = 0; - int result = count; - int len; - - while (offs < count) { - /* if buffer contains header, copy rest of data */ - if (garmin_data_p->insize >= GARMIN_PKTHDR_LENGTH) - len = GARMIN_PKTHDR_LENGTH - +getDataLength(garmin_data_p->inbuffer); - else - len = GARMIN_PKTHDR_LENGTH; - - if (len >= GPS_IN_BUFSIZ) { - /* seems to be an invalid packet, ignore rest - of input */ - dbg("%s - packet size too large: %d", __func__, len); - garmin_data_p->insize = 0; - count = 0; - result = -EINVPKT; - } else { - len -= garmin_data_p->insize; - if (len > (count-offs)) - len = (count-offs); - if (len > 0) { - dest = garmin_data_p->inbuffer - + garmin_data_p->insize; - memcpy(dest, buf+offs, len); - garmin_data_p->insize += len; - offs += len; - } - } - - /* do we have a complete packet ? */ - if (garmin_data_p->insize >= GARMIN_PKTHDR_LENGTH) { - len = GARMIN_PKTHDR_LENGTH+ - getDataLength(garmin_data_p->inbuffer); - if (garmin_data_p->insize >= len) { - garmin_write_bulk(garmin_data_p->port, - garmin_data_p->inbuffer, - len, 0); - garmin_data_p->insize = 0; - - /* if this was an abort-transfer command, - flush all queued data. */ - if (isAbortTrfCmnd(garmin_data_p->inbuffer)) { - spin_lock_irqsave(&garmin_data_p->lock, - flags); - garmin_data_p->flags |= FLAGS_DROP_DATA; - spin_unlock_irqrestore( - &garmin_data_p->lock, flags); - pkt_clear(garmin_data_p); - } - } - } - } - return result; -} - - -/****************************************************************************** - * private packets - ******************************************************************************/ - -static void priv_status_resp(struct usb_serial_port *port) -{ - struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - __le32 *pkt = (__le32 *)garmin_data_p->privpkt; - - pkt[0] = __cpu_to_le32(GARMIN_LAYERID_PRIVATE); - pkt[1] = __cpu_to_le32(PRIV_PKTID_INFO_RESP); - pkt[2] = __cpu_to_le32(12); - pkt[3] = __cpu_to_le32(VERSION_MAJOR << 16 | VERSION_MINOR); - pkt[4] = __cpu_to_le32(garmin_data_p->mode); - pkt[5] = __cpu_to_le32(garmin_data_p->serial_num); - - send_to_tty(port, (__u8 *)pkt, 6 * 4); -} - - -/****************************************************************************** - * Garmin specific driver functions - ******************************************************************************/ - -static int process_resetdev_request(struct usb_serial_port *port) -{ - unsigned long flags; - int status; - struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - - spin_lock_irqsave(&garmin_data_p->lock, flags); - garmin_data_p->flags &= ~(CLEAR_HALT_REQUIRED); - garmin_data_p->state = STATE_RESET; - garmin_data_p->serial_num = 0; - spin_unlock_irqrestore(&garmin_data_p->lock, flags); - - usb_kill_urb(port->interrupt_in_urb); - dbg("%s - usb_reset_device", __func__); - status = usb_reset_device(port->serial->dev); - if (status) - dbg("%s - usb_reset_device failed: %d", - __func__, status); - return status; -} - - - -/* - * clear all cached data - */ -static int garmin_clear(struct garmin_data *garmin_data_p) -{ - unsigned long flags; - int status = 0; - - /* flush all queued data */ - pkt_clear(garmin_data_p); - - spin_lock_irqsave(&garmin_data_p->lock, flags); - garmin_data_p->insize = 0; - garmin_data_p->outsize = 0; - spin_unlock_irqrestore(&garmin_data_p->lock, flags); - - return status; -} - - -static int garmin_init_session(struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - int status = 0; - int i = 0; - - if (status == 0) { - usb_kill_urb(port->interrupt_in_urb); - - dbg("%s - adding interrupt input", __func__); - status = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - if (status) - dev_err(&serial->dev->dev, - "%s - failed submitting interrupt urb, error %d\n", - __func__, status); - } - - /* - * using the initialization method from gpsbabel. See comments in - * gpsbabel/jeeps/gpslibusb.c gusb_reset_toggles() - */ - if (status == 0) { - dbg("%s - starting session ...", __func__); - garmin_data_p->state = STATE_ACTIVE; - - for (i = 0; i < 3; i++) { - status = garmin_write_bulk(port, - GARMIN_START_SESSION_REQ, - sizeof(GARMIN_START_SESSION_REQ), 0); - - if (status < 0) - break; - } - - if (status > 0) - status = 0; - } - - return status; -} - - - -static int garmin_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - unsigned long flags; - int status = 0; - struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&garmin_data_p->lock, flags); - garmin_data_p->mode = initial_mode; - garmin_data_p->count = 0; - garmin_data_p->flags &= FLAGS_SESSION_REPLY1_SEEN; - spin_unlock_irqrestore(&garmin_data_p->lock, flags); - - /* shutdown any bulk reads that might be going on */ - usb_kill_urb(port->write_urb); - usb_kill_urb(port->read_urb); - - if (garmin_data_p->state == STATE_RESET) - status = garmin_init_session(port); - - garmin_data_p->state = STATE_ACTIVE; - return status; -} - - -static void garmin_close(struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - - dbg("%s - port %d - mode=%d state=%d flags=0x%X", __func__, - port->number, garmin_data_p->mode, - garmin_data_p->state, garmin_data_p->flags); - - if (!serial) - return; - - mutex_lock(&port->serial->disc_mutex); - - if (!port->serial->disconnected) - garmin_clear(garmin_data_p); - - /* shutdown our urbs */ - usb_kill_urb(port->read_urb); - usb_kill_urb(port->write_urb); - - /* keep reset state so we know that we must start a new session */ - if (garmin_data_p->state != STATE_RESET) - garmin_data_p->state = STATE_DISCONNECTED; - - mutex_unlock(&port->serial->disc_mutex); -} - - -static void garmin_write_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - - if (port) { - struct garmin_data *garmin_data_p = - usb_get_serial_port_data(port); - - dbg("%s - port %d", __func__, port->number); - - if (GARMIN_LAYERID_APPL == getLayerId(urb->transfer_buffer)) { - - if (garmin_data_p->mode == MODE_GARMIN_SERIAL) { - gsp_send_ack(garmin_data_p, - ((__u8 *)urb->transfer_buffer)[4]); - } - } - usb_serial_port_softint(port); - } - - /* Ignore errors that resulted from garmin_write_bulk with - dismiss_ack = 1 */ - - /* free up the transfer buffer, as usb_free_urb() does not do this */ - kfree(urb->transfer_buffer); -} - - -static int garmin_write_bulk(struct usb_serial_port *port, - const unsigned char *buf, int count, - int dismiss_ack) -{ - unsigned long flags; - struct usb_serial *serial = port->serial; - struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - struct urb *urb; - unsigned char *buffer; - int status; - - dbg("%s - port %d, state %d", __func__, port->number, - garmin_data_p->state); - - spin_lock_irqsave(&garmin_data_p->lock, flags); - garmin_data_p->flags &= ~FLAGS_DROP_DATA; - spin_unlock_irqrestore(&garmin_data_p->lock, flags); - - buffer = kmalloc(count, GFP_ATOMIC); - if (!buffer) { - dev_err(&port->dev, "out of memory\n"); - return -ENOMEM; - } - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - dev_err(&port->dev, "no more free urbs\n"); - kfree(buffer); - return -ENOMEM; - } - - memcpy(buffer, buf, count); - - usb_serial_debug_data(debug, &port->dev, __func__, count, buffer); - - usb_fill_bulk_urb(urb, serial->dev, - usb_sndbulkpipe(serial->dev, - port->bulk_out_endpointAddress), - buffer, count, - garmin_write_bulk_callback, - dismiss_ack ? NULL : port); - urb->transfer_flags |= URB_ZERO_PACKET; - - if (GARMIN_LAYERID_APPL == getLayerId(buffer)) { - - spin_lock_irqsave(&garmin_data_p->lock, flags); - garmin_data_p->flags |= APP_REQ_SEEN; - spin_unlock_irqrestore(&garmin_data_p->lock, flags); - - if (garmin_data_p->mode == MODE_GARMIN_SERIAL) { - pkt_clear(garmin_data_p); - garmin_data_p->state = STATE_GSP_WAIT_DATA; - } - } - - /* send it down the pipe */ - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) { - dev_err(&port->dev, - "%s - usb_submit_urb(write bulk) failed with status = %d\n", - __func__, status); - count = status; - } - - /* we are done with this urb, so let the host driver - * really free it when it is finished with it */ - usb_free_urb(urb); - - return count; -} - -static int garmin_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - int pktid, pktsiz, len; - struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - __le32 *privpkt = (__le32 *)garmin_data_p->privpkt; - - usb_serial_debug_data(debug, &port->dev, __func__, count, buf); - - if (garmin_data_p->state == STATE_RESET) - return -EIO; - - /* check for our private packets */ - if (count >= GARMIN_PKTHDR_LENGTH) { - len = PRIVPKTSIZ; - if (count < len) - len = count; - - memcpy(garmin_data_p->privpkt, buf, len); - - pktsiz = getDataLength(garmin_data_p->privpkt); - pktid = getPacketId(garmin_data_p->privpkt); - - if (count == (GARMIN_PKTHDR_LENGTH+pktsiz) - && GARMIN_LAYERID_PRIVATE == - getLayerId(garmin_data_p->privpkt)) { - - dbg("%s - processing private request %d", - __func__, pktid); - - /* drop all unfinished transfers */ - garmin_clear(garmin_data_p); - - switch (pktid) { - - case PRIV_PKTID_SET_DEBUG: - if (pktsiz != 4) - return -EINVPKT; - debug = __le32_to_cpu(privpkt[3]); - dbg("%s - debug level set to 0x%X", - __func__, debug); - break; - - case PRIV_PKTID_SET_MODE: - if (pktsiz != 4) - return -EINVPKT; - garmin_data_p->mode = __le32_to_cpu(privpkt[3]); - dbg("%s - mode set to %d", - __func__, garmin_data_p->mode); - break; - - case PRIV_PKTID_INFO_REQ: - priv_status_resp(port); - break; - - case PRIV_PKTID_RESET_REQ: - process_resetdev_request(port); - break; - - case PRIV_PKTID_SET_DEF_MODE: - if (pktsiz != 4) - return -EINVPKT; - initial_mode = __le32_to_cpu(privpkt[3]); - dbg("%s - initial_mode set to %d", - __func__, - garmin_data_p->mode); - break; - } - return count; - } - } - - if (garmin_data_p->mode == MODE_GARMIN_SERIAL) { - return gsp_receive(garmin_data_p, buf, count); - } else { /* MODE_NATIVE */ - return nat_receive(garmin_data_p, buf, count); - } -} - - -static int garmin_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - /* - * Report back the bytes currently available in the output buffer. - */ - struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - return GPS_OUT_BUFSIZ-garmin_data_p->outsize; -} - - -static void garmin_read_process(struct garmin_data *garmin_data_p, - unsigned char *data, unsigned data_length, - int bulk_data) -{ - unsigned long flags; - - if (garmin_data_p->flags & FLAGS_DROP_DATA) { - /* abort-transfer cmd is actice */ - dbg("%s - pkt dropped", __func__); - } else if (garmin_data_p->state != STATE_DISCONNECTED && - garmin_data_p->state != STATE_RESET) { - - /* if throttling is active or postprecessing is required - put the received data in the input queue, otherwise - send it directly to the tty port */ - if (garmin_data_p->flags & FLAGS_QUEUING) { - pkt_add(garmin_data_p, data, data_length); - } else if (bulk_data || - getLayerId(data) == GARMIN_LAYERID_APPL) { - - spin_lock_irqsave(&garmin_data_p->lock, flags); - garmin_data_p->flags |= APP_RESP_SEEN; - spin_unlock_irqrestore(&garmin_data_p->lock, flags); - - if (garmin_data_p->mode == MODE_GARMIN_SERIAL) { - pkt_add(garmin_data_p, data, data_length); - } else { - send_to_tty(garmin_data_p->port, data, - data_length); - } - } - /* ignore system layer packets ... */ - } -} - - -static void garmin_read_bulk_callback(struct urb *urb) -{ - unsigned long flags; - struct usb_serial_port *port = urb->context; - struct usb_serial *serial = port->serial; - struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - unsigned char *data = urb->transfer_buffer; - int status = urb->status; - int retval; - - dbg("%s - port %d", __func__, port->number); - - if (!serial) { - dbg("%s - bad serial pointer, exiting", __func__); - return; - } - - if (status) { - dbg("%s - nonzero read bulk status received: %d", - __func__, status); - return; - } - - usb_serial_debug_data(debug, &port->dev, - __func__, urb->actual_length, data); - - garmin_read_process(garmin_data_p, data, urb->actual_length, 1); - - if (urb->actual_length == 0 && - 0 != (garmin_data_p->flags & FLAGS_BULK_IN_RESTART)) { - spin_lock_irqsave(&garmin_data_p->lock, flags); - garmin_data_p->flags &= ~FLAGS_BULK_IN_RESTART; - spin_unlock_irqrestore(&garmin_data_p->lock, flags); - retval = usb_submit_urb(port->read_urb, GFP_ATOMIC); - if (retval) - dev_err(&port->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, retval); - } else if (urb->actual_length > 0) { - /* Continue trying to read until nothing more is received */ - if (0 == (garmin_data_p->flags & FLAGS_THROTTLED)) { - retval = usb_submit_urb(port->read_urb, GFP_ATOMIC); - if (retval) - dev_err(&port->dev, - "%s - failed resubmitting read urb, " - "error %d\n", __func__, retval); - } - } else { - dbg("%s - end of bulk data", __func__); - spin_lock_irqsave(&garmin_data_p->lock, flags); - garmin_data_p->flags &= ~FLAGS_BULK_IN_ACTIVE; - spin_unlock_irqrestore(&garmin_data_p->lock, flags); - } -} - - -static void garmin_read_int_callback(struct urb *urb) -{ - unsigned long flags; - int retval; - struct usb_serial_port *port = urb->context; - struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - unsigned char *data = urb->transfer_buffer; - int status = urb->status; - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); - return; - default: - dbg("%s - nonzero urb status received: %d", - __func__, status); - return; - } - - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, urb->transfer_buffer); - - if (urb->actual_length == sizeof(GARMIN_BULK_IN_AVAIL_REPLY) && - 0 == memcmp(data, GARMIN_BULK_IN_AVAIL_REPLY, - sizeof(GARMIN_BULK_IN_AVAIL_REPLY))) { - - dbg("%s - bulk data available.", __func__); - - if (0 == (garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE)) { - - /* bulk data available */ - retval = usb_submit_urb(port->read_urb, GFP_ATOMIC); - if (retval) { - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", - __func__, retval); - } else { - spin_lock_irqsave(&garmin_data_p->lock, flags); - garmin_data_p->flags |= FLAGS_BULK_IN_ACTIVE; - spin_unlock_irqrestore(&garmin_data_p->lock, - flags); - } - } else { - /* bulk-in transfer still active */ - spin_lock_irqsave(&garmin_data_p->lock, flags); - garmin_data_p->flags |= FLAGS_BULK_IN_RESTART; - spin_unlock_irqrestore(&garmin_data_p->lock, flags); - } - - } else if (urb->actual_length == (4+sizeof(GARMIN_START_SESSION_REPLY)) - && 0 == memcmp(data, GARMIN_START_SESSION_REPLY, - sizeof(GARMIN_START_SESSION_REPLY))) { - - spin_lock_irqsave(&garmin_data_p->lock, flags); - garmin_data_p->flags |= FLAGS_SESSION_REPLY1_SEEN; - spin_unlock_irqrestore(&garmin_data_p->lock, flags); - - /* save the serial number */ - garmin_data_p->serial_num = __le32_to_cpup( - (__le32 *)(data+GARMIN_PKTHDR_LENGTH)); - - dbg("%s - start-of-session reply seen - serial %u.", - __func__, garmin_data_p->serial_num); - } - - garmin_read_process(garmin_data_p, data, urb->actual_length, 0); - - retval = usb_submit_urb(urb, GFP_ATOMIC); - if (retval) - dev_err(&urb->dev->dev, - "%s - Error %d submitting interrupt urb\n", - __func__, retval); -} - - -/* - * Sends the next queued packt to the tty port (garmin native mode only) - * and then sets a timer to call itself again until all queued data - * is sent. - */ -static int garmin_flush_queue(struct garmin_data *garmin_data_p) -{ - unsigned long flags; - struct garmin_packet *pkt; - - if ((garmin_data_p->flags & FLAGS_THROTTLED) == 0) { - pkt = pkt_pop(garmin_data_p); - if (pkt != NULL) { - send_to_tty(garmin_data_p->port, pkt->data, pkt->size); - kfree(pkt); - mod_timer(&garmin_data_p->timer, (1)+jiffies); - - } else { - spin_lock_irqsave(&garmin_data_p->lock, flags); - garmin_data_p->flags &= ~FLAGS_QUEUING; - spin_unlock_irqrestore(&garmin_data_p->lock, flags); - } - } - return 0; -} - - -static void garmin_throttle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - - dbg("%s - port %d", __func__, port->number); - /* set flag, data received will be put into a queue - for later processing */ - spin_lock_irq(&garmin_data_p->lock); - garmin_data_p->flags |= FLAGS_QUEUING|FLAGS_THROTTLED; - spin_unlock_irq(&garmin_data_p->lock); -} - - -static void garmin_unthrottle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - int status; - - dbg("%s - port %d", __func__, port->number); - spin_lock_irq(&garmin_data_p->lock); - garmin_data_p->flags &= ~FLAGS_THROTTLED; - spin_unlock_irq(&garmin_data_p->lock); - - /* in native mode send queued data to tty, in - serial mode nothing needs to be done here */ - if (garmin_data_p->mode == MODE_NATIVE) - garmin_flush_queue(garmin_data_p); - - if (0 != (garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE)) { - status = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (status) - dev_err(&port->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, status); - } -} - -/* - * The timer is currently only used to send queued packets to - * the tty in cases where the protocol provides no own handshaking - * to initiate the transfer. - */ -static void timeout_handler(unsigned long data) -{ - struct garmin_data *garmin_data_p = (struct garmin_data *) data; - - /* send the next queued packet to the tty port */ - if (garmin_data_p->mode == MODE_NATIVE) - if (garmin_data_p->flags & FLAGS_QUEUING) - garmin_flush_queue(garmin_data_p); -} - - - -static int garmin_attach(struct usb_serial *serial) -{ - int status = 0; - struct usb_serial_port *port = serial->port[0]; - struct garmin_data *garmin_data_p = NULL; - - dbg("%s", __func__); - - garmin_data_p = kzalloc(sizeof(struct garmin_data), GFP_KERNEL); - if (garmin_data_p == NULL) { - dev_err(&port->dev, "%s - Out of memory\n", __func__); - return -ENOMEM; - } - init_timer(&garmin_data_p->timer); - spin_lock_init(&garmin_data_p->lock); - INIT_LIST_HEAD(&garmin_data_p->pktlist); - /* garmin_data_p->timer.expires = jiffies + session_timeout; */ - garmin_data_p->timer.data = (unsigned long)garmin_data_p; - garmin_data_p->timer.function = timeout_handler; - garmin_data_p->port = port; - garmin_data_p->state = 0; - garmin_data_p->flags = 0; - garmin_data_p->count = 0; - usb_set_serial_port_data(port, garmin_data_p); - - status = garmin_init_session(port); - - return status; -} - - -static void garmin_disconnect(struct usb_serial *serial) -{ - struct usb_serial_port *port = serial->port[0]; - struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - - dbg("%s", __func__); - - usb_kill_urb(port->interrupt_in_urb); - del_timer_sync(&garmin_data_p->timer); -} - - -static void garmin_release(struct usb_serial *serial) -{ - struct usb_serial_port *port = serial->port[0]; - struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - - dbg("%s", __func__); - - kfree(garmin_data_p); -} - - -/* All of the device info needed */ -static struct usb_serial_driver garmin_device = { - .driver = { - .owner = THIS_MODULE, - .name = "garmin_gps", - }, - .description = "Garmin GPS usb/tty", - .id_table = id_table, - .num_ports = 1, - .open = garmin_open, - .close = garmin_close, - .throttle = garmin_throttle, - .unthrottle = garmin_unthrottle, - .attach = garmin_attach, - .disconnect = garmin_disconnect, - .release = garmin_release, - .write = garmin_write, - .write_room = garmin_write_room, - .write_bulk_callback = garmin_write_bulk_callback, - .read_bulk_callback = garmin_read_bulk_callback, - .read_int_callback = garmin_read_int_callback, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &garmin_device, NULL -}; - -module_usb_serial_driver(garmin_driver, serial_drivers); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IWUSR | S_IRUGO); -MODULE_PARM_DESC(debug, "Debug enabled or not"); -module_param(initial_mode, int, S_IRUGO); -MODULE_PARM_DESC(initial_mode, "Initial mode"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/generic.c b/ANDROID_3.4.5/drivers/usb/serial/generic.c deleted file mode 100644 index 664deb63..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/generic.c +++ /dev/null @@ -1,580 +0,0 @@ -/* - * USB Serial Converter Generic functions - * - * Copyright (C) 2010 - 2011 Johan Hovold (jhovold@gmail.com) - * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com) - * - * 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int debug; - -#ifdef CONFIG_USB_SERIAL_GENERIC - -static int generic_probe(struct usb_interface *interface, - const struct usb_device_id *id); - -static __u16 vendor = 0x05f9; -static __u16 product = 0xffff; - -module_param(vendor, ushort, 0); -MODULE_PARM_DESC(vendor, "User specified USB idVendor"); - -module_param(product, ushort, 0); -MODULE_PARM_DESC(product, "User specified USB idProduct"); - -static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */ - -/* we want to look at all devices, as the vendor/product id can change - * depending on the command line argument */ -static const struct usb_device_id generic_serial_ids[] = { - {.driver_info = 42}, - {} -}; - -static struct usb_driver generic_driver = { - .name = "usbserial_generic", - .probe = generic_probe, - .disconnect = usb_serial_disconnect, - .id_table = generic_serial_ids, -}; - -/* All of the device info needed for the Generic Serial Converter */ -struct usb_serial_driver usb_serial_generic_device = { - .driver = { - .owner = THIS_MODULE, - .name = "generic", - }, - .id_table = generic_device_ids, - .num_ports = 1, - .disconnect = usb_serial_generic_disconnect, - .release = usb_serial_generic_release, - .throttle = usb_serial_generic_throttle, - .unthrottle = usb_serial_generic_unthrottle, - .resume = usb_serial_generic_resume, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &usb_serial_generic_device, NULL -}; - -static int generic_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - const struct usb_device_id *id_pattern; - - id_pattern = usb_match_id(interface, generic_device_ids); - if (id_pattern != NULL) - return usb_serial_probe(interface, id); - return -ENODEV; -} -#endif - -int usb_serial_generic_register(int _debug) -{ - int retval = 0; - - debug = _debug; -#ifdef CONFIG_USB_SERIAL_GENERIC - generic_device_ids[0].idVendor = vendor; - generic_device_ids[0].idProduct = product; - generic_device_ids[0].match_flags = - USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT; - - /* register our generic driver with ourselves */ - retval = usb_serial_register_drivers(&generic_driver, serial_drivers); -#endif - return retval; -} - -void usb_serial_generic_deregister(void) -{ -#ifdef CONFIG_USB_SERIAL_GENERIC - /* remove our generic driver */ - usb_serial_deregister_drivers(&generic_driver, serial_drivers); -#endif -} - -int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - int result = 0; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - /* clear the throttle flags */ - spin_lock_irqsave(&port->lock, flags); - port->throttled = 0; - port->throttle_req = 0; - spin_unlock_irqrestore(&port->lock, flags); - - /* if we have a bulk endpoint, start reading from it */ - if (port->bulk_in_size) - result = usb_serial_generic_submit_read_urbs(port, GFP_KERNEL); - - return result; -} -EXPORT_SYMBOL_GPL(usb_serial_generic_open); - -static void generic_cleanup(struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - unsigned long flags; - int i; - - dbg("%s - port %d", __func__, port->number); - - if (serial->dev) { - /* shutdown any bulk transfers that might be going on */ - if (port->bulk_out_size) { - usb_kill_urb(port->write_urb); - for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) - usb_kill_urb(port->write_urbs[i]); - - spin_lock_irqsave(&port->lock, flags); - kfifo_reset_out(&port->write_fifo); - spin_unlock_irqrestore(&port->lock, flags); - } - if (port->bulk_in_size) { - for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) - usb_kill_urb(port->read_urbs[i]); - } - } -} - -void usb_serial_generic_close(struct usb_serial_port *port) -{ - dbg("%s - port %d", __func__, port->number); - generic_cleanup(port); -} -EXPORT_SYMBOL_GPL(usb_serial_generic_close); - -int usb_serial_generic_prepare_write_buffer(struct usb_serial_port *port, - void *dest, size_t size) -{ - return kfifo_out_locked(&port->write_fifo, dest, size, &port->lock); -} - -/** - * usb_serial_generic_write_start - kick off an URB write - * @port: Pointer to the &struct usb_serial_port data - * - * Returns zero on success, or a negative errno value - */ -static int usb_serial_generic_write_start(struct usb_serial_port *port) -{ - struct urb *urb; - int count, result; - unsigned long flags; - int i; - - if (test_and_set_bit_lock(USB_SERIAL_WRITE_BUSY, &port->flags)) - return 0; -retry: - spin_lock_irqsave(&port->lock, flags); - if (!port->write_urbs_free || !kfifo_len(&port->write_fifo)) { - clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags); - spin_unlock_irqrestore(&port->lock, flags); - return 0; - } - i = (int)find_first_bit(&port->write_urbs_free, - ARRAY_SIZE(port->write_urbs)); - spin_unlock_irqrestore(&port->lock, flags); - - urb = port->write_urbs[i]; - count = port->serial->type->prepare_write_buffer(port, - urb->transfer_buffer, - port->bulk_out_size); - urb->transfer_buffer_length = count; - usb_serial_debug_data(debug, &port->dev, __func__, count, - urb->transfer_buffer); - spin_lock_irqsave(&port->lock, flags); - port->tx_bytes += count; - spin_unlock_irqrestore(&port->lock, flags); - - clear_bit(i, &port->write_urbs_free); - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) { - dev_err_console(port, "%s - error submitting urb: %d\n", - __func__, result); - set_bit(i, &port->write_urbs_free); - spin_lock_irqsave(&port->lock, flags); - port->tx_bytes -= count; - spin_unlock_irqrestore(&port->lock, flags); - - clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags); - return result; - } - - /* Try sending off another urb, unless in irq context (in which case - * there will be no free urb). */ - if (!in_irq()) - goto retry; - - clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags); - - return 0; -} - -/** - * usb_serial_generic_write - generic write function for serial USB devices - * @tty: Pointer to &struct tty_struct for the device - * @port: Pointer to the &usb_serial_port structure for the device - * @buf: Pointer to the data to write - * @count: Number of bytes to write - * - * Returns the number of characters actually written, which may be anything - * from zero to @count. If an error occurs, it returns the negative errno - * value. - */ -int usb_serial_generic_write(struct tty_struct *tty, - struct usb_serial_port *port, const unsigned char *buf, int count) -{ - int result; - - dbg("%s - port %d", __func__, port->number); - - /* only do something if we have a bulk out endpoint */ - if (!port->bulk_out_size) - return -ENODEV; - - if (!count) - return 0; - - count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock); - result = usb_serial_generic_write_start(port); - if (result) - return result; - - return count; -} -EXPORT_SYMBOL_GPL(usb_serial_generic_write); - -int usb_serial_generic_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - unsigned long flags; - int room; - - dbg("%s - port %d", __func__, port->number); - - if (!port->bulk_out_size) - return 0; - - spin_lock_irqsave(&port->lock, flags); - room = kfifo_avail(&port->write_fifo); - spin_unlock_irqrestore(&port->lock, flags); - - dbg("%s - returns %d", __func__, room); - return room; -} - -int usb_serial_generic_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - unsigned long flags; - int chars; - - dbg("%s - port %d", __func__, port->number); - - if (!port->bulk_out_size) - return 0; - - spin_lock_irqsave(&port->lock, flags); - chars = kfifo_len(&port->write_fifo) + port->tx_bytes; - spin_unlock_irqrestore(&port->lock, flags); - - dbg("%s - returns %d", __func__, chars); - return chars; -} - -static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port, - int index, gfp_t mem_flags) -{ - int res; - - if (!test_and_clear_bit(index, &port->read_urbs_free)) - return 0; - - dbg("%s - port %d, urb %d\n", __func__, port->number, index); - - res = usb_submit_urb(port->read_urbs[index], mem_flags); - if (res) { - if (res != -EPERM) { - dev_err(&port->dev, - "%s - usb_submit_urb failed: %d\n", - __func__, res); - } - set_bit(index, &port->read_urbs_free); - return res; - } - - return 0; -} - -int usb_serial_generic_submit_read_urbs(struct usb_serial_port *port, - gfp_t mem_flags) -{ - int res; - int i; - - dbg("%s - port %d", __func__, port->number); - - for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) { - res = usb_serial_generic_submit_read_urb(port, i, mem_flags); - if (res) - goto err; - } - - return 0; -err: - for (; i >= 0; --i) - usb_kill_urb(port->read_urbs[i]); - - return res; -} -EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urbs); - -void usb_serial_generic_process_read_urb(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct tty_struct *tty; - char *ch = (char *)urb->transfer_buffer; - int i; - - if (!urb->actual_length) - return; - - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - - /* The per character mucking around with sysrq path it too slow for - stuff like 3G modems, so shortcircuit it in the 99.9999999% of cases - where the USB serial is not a console anyway */ - if (!port->port.console || !port->sysrq) - tty_insert_flip_string(tty, ch, urb->actual_length); - else { - for (i = 0; i < urb->actual_length; i++, ch++) { - if (!usb_serial_handle_sysrq_char(port, *ch)) - tty_insert_flip_char(tty, *ch, TTY_NORMAL); - } - } - tty_flip_buffer_push(tty); - tty_kref_put(tty); -} -EXPORT_SYMBOL_GPL(usb_serial_generic_process_read_urb); - -void usb_serial_generic_read_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - unsigned char *data = urb->transfer_buffer; - unsigned long flags; - int i; - - for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) { - if (urb == port->read_urbs[i]) - break; - } - set_bit(i, &port->read_urbs_free); - - dbg("%s - port %d, urb %d, len %d\n", __func__, port->number, i, - urb->actual_length); - if (urb->status) { - dbg("%s - non-zero urb status: %d\n", __func__, urb->status); - return; - } - - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); - port->serial->type->process_read_urb(urb); - - /* Throttle the device if requested by tty */ - spin_lock_irqsave(&port->lock, flags); - port->throttled = port->throttle_req; - if (!port->throttled) { - spin_unlock_irqrestore(&port->lock, flags); - usb_serial_generic_submit_read_urb(port, i, GFP_ATOMIC); - } else - spin_unlock_irqrestore(&port->lock, flags); -} -EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback); - -void usb_serial_generic_write_bulk_callback(struct urb *urb) -{ - unsigned long flags; - struct usb_serial_port *port = urb->context; - int status = urb->status; - int i; - - dbg("%s - port %d", __func__, port->number); - - for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) - if (port->write_urbs[i] == urb) - break; - - spin_lock_irqsave(&port->lock, flags); - port->tx_bytes -= urb->transfer_buffer_length; - set_bit(i, &port->write_urbs_free); - spin_unlock_irqrestore(&port->lock, flags); - - if (status) { - dbg("%s - non-zero urb status: %d", __func__, status); - - spin_lock_irqsave(&port->lock, flags); - kfifo_reset_out(&port->write_fifo); - spin_unlock_irqrestore(&port->lock, flags); - } else { - usb_serial_generic_write_start(port); - } - - usb_serial_port_softint(port); -} -EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback); - -void usb_serial_generic_throttle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - /* Set the throttle request flag. It will be picked up - * by usb_serial_generic_read_bulk_callback(). */ - spin_lock_irqsave(&port->lock, flags); - port->throttle_req = 1; - spin_unlock_irqrestore(&port->lock, flags); -} -EXPORT_SYMBOL_GPL(usb_serial_generic_throttle); - -void usb_serial_generic_unthrottle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - int was_throttled; - - dbg("%s - port %d", __func__, port->number); - - /* Clear the throttle flags */ - spin_lock_irq(&port->lock); - was_throttled = port->throttled; - port->throttled = port->throttle_req = 0; - spin_unlock_irq(&port->lock); - - if (was_throttled) - usb_serial_generic_submit_read_urbs(port, GFP_KERNEL); -} -EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle); - -#ifdef CONFIG_MAGIC_SYSRQ -int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch) -{ - if (port->sysrq && port->port.console) { - if (ch && time_before(jiffies, port->sysrq)) { - handle_sysrq(ch); - port->sysrq = 0; - return 1; - } - port->sysrq = 0; - } - return 0; -} -#else -int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch) -{ - return 0; -} -#endif -EXPORT_SYMBOL_GPL(usb_serial_handle_sysrq_char); - -int usb_serial_handle_break(struct usb_serial_port *port) -{ - if (!port->sysrq) { - port->sysrq = jiffies + HZ*5; - return 1; - } - port->sysrq = 0; - return 0; -} -EXPORT_SYMBOL_GPL(usb_serial_handle_break); - -/** - * usb_serial_handle_dcd_change - handle a change of carrier detect state - * @port: usb_serial_port structure for the open port - * @tty: tty_struct structure for the port - * @status: new carrier detect status, nonzero if active - */ -void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port, - struct tty_struct *tty, unsigned int status) -{ - struct tty_port *port = &usb_port->port; - - dbg("%s - port %d, status %d", __func__, usb_port->number, status); - - if (status) - wake_up_interruptible(&port->open_wait); - else if (tty && !C_CLOCAL(tty)) - tty_hangup(tty); -} -EXPORT_SYMBOL_GPL(usb_serial_handle_dcd_change); - -int usb_serial_generic_resume(struct usb_serial *serial) -{ - struct usb_serial_port *port; - int i, c = 0, r; - - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) - continue; - - if (port->bulk_in_size) { - r = usb_serial_generic_submit_read_urbs(port, - GFP_NOIO); - if (r < 0) - c++; - } - - if (port->bulk_out_size) { - r = usb_serial_generic_write_start(port); - if (r < 0) - c++; - } - } - - return c ? -EIO : 0; -} -EXPORT_SYMBOL_GPL(usb_serial_generic_resume); - -void usb_serial_generic_disconnect(struct usb_serial *serial) -{ - int i; - - dbg("%s", __func__); - - /* stop reads and writes on all ports */ - for (i = 0; i < serial->num_ports; ++i) - generic_cleanup(serial->port[i]); -} -EXPORT_SYMBOL_GPL(usb_serial_generic_disconnect); - -void usb_serial_generic_release(struct usb_serial *serial) -{ - dbg("%s", __func__); -} diff --git a/ANDROID_3.4.5/drivers/usb/serial/hp4x.c b/ANDROID_3.4.5/drivers/usb/serial/hp4x.c deleted file mode 100644 index 2563e788..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/hp4x.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * HP4x Calculators Serial USB driver - * - * Copyright (C) 2005 Arthur Huillet (ahuillet@users.sf.net) - * Copyright (C) 2001-2005 Greg Kroah-Hartman (greg@kroah.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * See Documentation/usb/usb-serial.txt for more information on using this - * driver - */ - -#include -#include -#include -#include -#include -#include - -/* - * Version Information - */ -#define DRIVER_VERSION "v1.00" -#define DRIVER_DESC "HP4x (48/49) Generic Serial driver" - -#define HP_VENDOR_ID 0x03f0 -#define HP49GP_PRODUCT_ID 0x0121 - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(HP_VENDOR_ID, HP49GP_PRODUCT_ID) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver hp49gp_driver = { - .name = "hp4X", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - -static struct usb_serial_driver hp49gp_device = { - .driver = { - .owner = THIS_MODULE, - .name = "hp4X", - }, - .id_table = id_table, - .num_ports = 1, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &hp49gp_device, NULL -}; - -module_usb_serial_driver(hp49gp_driver, serial_drivers); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/io_16654.h b/ANDROID_3.4.5/drivers/usb/serial/io_16654.h deleted file mode 100644 index a53abc95..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/io_16654.h +++ /dev/null @@ -1,195 +0,0 @@ -/************************************************************************ - * - * 16654.H Definitions for 16C654 UART used on EdgePorts - * - * Copyright (C) 1998 Inside Out Networks, Inc. - * 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. - * - ************************************************************************/ - -#if !defined(_16654_H) -#define _16654_H - -/************************************************************************ - * - * D e f i n e s / T y p e d e f s - * - ************************************************************************/ - - // - // UART register numbers - // Numbers 0-7 are passed to the Edgeport directly. Numbers 8 and - // above are used internally to indicate that we must enable access - // to them via LCR bit 0x80 or LCR = 0xBF. - // The register number sent to the Edgeport is then (x & 0x7). - // - // Driver must not access registers that affect operation of the - // the EdgePort firmware -- that includes THR, RHR, IER, FCR. - - -#define THR 0 // ! Transmit Holding Register (Write) -#define RDR 0 // ! Receive Holding Register (Read) -#define IER 1 // ! Interrupt Enable Register -#define FCR 2 // ! Fifo Control Register (Write) -#define ISR 2 // Interrupt Status Register (Read) -#define LCR 3 // Line Control Register -#define MCR 4 // Modem Control Register -#define LSR 5 // Line Status Register -#define MSR 6 // Modem Status Register -#define SPR 7 // ScratchPad Register -#define DLL 8 // Bank2[ 0 ] Divisor Latch LSB -#define DLM 9 // Bank2[ 1 ] Divisor Latch MSB -#define EFR 10 // Bank2[ 2 ] Extended Function Register -//efine unused 11 // Bank2[ 3 ] -#define XON1 12 // Bank2[ 4 ] Xon-1 -#define XON2 13 // Bank2[ 5 ] Xon-2 -#define XOFF1 14 // Bank2[ 6 ] Xoff-1 -#define XOFF2 15 // Bank2[ 7 ] Xoff-2 - -#define NUM_16654_REGS 16 - -#define IS_REG_2ND_BANK(x) ((x) >= 8) - - // - // Bit definitions for each register - // - -#define IER_RX 0x01 // Enable receive interrupt -#define IER_TX 0x02 // Enable transmit interrupt -#define IER_RXS 0x04 // Enable receive status interrupt -#define IER_MDM 0x08 // Enable modem status interrupt -#define IER_SLEEP 0x10 // Enable sleep mode -#define IER_XOFF 0x20 // Enable s/w flow control (XOFF) interrupt -#define IER_RTS 0x40 // Enable RTS interrupt -#define IER_CTS 0x80 // Enable CTS interrupt -#define IER_ENABLE_ALL 0xFF // Enable all ints - - -#define FCR_FIFO_EN 0x01 // Enable FIFOs -#define FCR_RXCLR 0x02 // Reset Rx FIFO -#define FCR_TXCLR 0x04 // Reset Tx FIFO -#define FCR_DMA_BLK 0x08 // Enable DMA block mode -#define FCR_TX_LEVEL_MASK 0x30 // Mask for Tx FIFO Level -#define FCR_TX_LEVEL_8 0x00 // Tx FIFO Level = 8 bytes -#define FCR_TX_LEVEL_16 0x10 // Tx FIFO Level = 16 bytes -#define FCR_TX_LEVEL_32 0x20 // Tx FIFO Level = 32 bytes -#define FCR_TX_LEVEL_56 0x30 // Tx FIFO Level = 56 bytes -#define FCR_RX_LEVEL_MASK 0xC0 // Mask for Rx FIFO Level -#define FCR_RX_LEVEL_8 0x00 // Rx FIFO Level = 8 bytes -#define FCR_RX_LEVEL_16 0x40 // Rx FIFO Level = 16 bytes -#define FCR_RX_LEVEL_56 0x80 // Rx FIFO Level = 56 bytes -#define FCR_RX_LEVEL_60 0xC0 // Rx FIFO Level = 60 bytes - - -#define ISR_INT_MDM_STATUS 0x00 // Modem status int pending -#define ISR_INT_NONE 0x01 // No interrupt pending -#define ISR_INT_TXRDY 0x02 // Tx ready int pending -#define ISR_INT_RXRDY 0x04 // Rx ready int pending -#define ISR_INT_LINE_STATUS 0x06 // Line status int pending -#define ISR_INT_RX_TIMEOUT 0x0C // Rx timeout int pending -#define ISR_INT_RX_XOFF 0x10 // Rx Xoff int pending -#define ISR_INT_RTS_CTS 0x20 // RTS/CTS change int pending -#define ISR_FIFO_ENABLED 0xC0 // Bits set if FIFOs enabled -#define ISR_INT_BITS_MASK 0x3E // Mask to isolate valid int causes - - -#define LCR_BITS_5 0x00 // 5 bits/char -#define LCR_BITS_6 0x01 // 6 bits/char -#define LCR_BITS_7 0x02 // 7 bits/char -#define LCR_BITS_8 0x03 // 8 bits/char -#define LCR_BITS_MASK 0x03 // Mask for bits/char field - -#define LCR_STOP_1 0x00 // 1 stop bit -#define LCR_STOP_1_5 0x04 // 1.5 stop bits (if 5 bits/char) -#define LCR_STOP_2 0x04 // 2 stop bits (if 6-8 bits/char) -#define LCR_STOP_MASK 0x04 // Mask for stop bits field - -#define LCR_PAR_NONE 0x00 // No parity -#define LCR_PAR_ODD 0x08 // Odd parity -#define LCR_PAR_EVEN 0x18 // Even parity -#define LCR_PAR_MARK 0x28 // Force parity bit to 1 -#define LCR_PAR_SPACE 0x38 // Force parity bit to 0 -#define LCR_PAR_MASK 0x38 // Mask for parity field - -#define LCR_SET_BREAK 0x40 // Set Break condition -#define LCR_DL_ENABLE 0x80 // Enable access to divisor latch - -#define LCR_ACCESS_EFR 0xBF // Load this value to access DLL,DLM, - // and also the '654-only registers - // EFR, XON1, XON2, XOFF1, XOFF2 - - -#define MCR_DTR 0x01 // Assert DTR -#define MCR_RTS 0x02 // Assert RTS -#define MCR_OUT1 0x04 // Loopback only: Sets state of RI -#define MCR_MASTER_IE 0x08 // Enable interrupt outputs -#define MCR_LOOPBACK 0x10 // Set internal (digital) loopback mode -#define MCR_XON_ANY 0x20 // Enable any char to exit XOFF mode -#define MCR_IR_ENABLE 0x40 // Enable IrDA functions -#define MCR_BRG_DIV_4 0x80 // Divide baud rate clk by /4 instead of /1 - - -#define LSR_RX_AVAIL 0x01 // Rx data available -#define LSR_OVER_ERR 0x02 // Rx overrun -#define LSR_PAR_ERR 0x04 // Rx parity error -#define LSR_FRM_ERR 0x08 // Rx framing error -#define LSR_BREAK 0x10 // Rx break condition detected -#define LSR_TX_EMPTY 0x20 // Tx Fifo empty -#define LSR_TX_ALL_EMPTY 0x40 // Tx Fifo and shift register empty -#define LSR_FIFO_ERR 0x80 // Rx Fifo contains at least 1 erred char - - -#define EDGEPORT_MSR_DELTA_CTS 0x01 // CTS changed from last read -#define EDGEPORT_MSR_DELTA_DSR 0x02 // DSR changed from last read -#define EDGEPORT_MSR_DELTA_RI 0x04 // RI changed from 0 -> 1 -#define EDGEPORT_MSR_DELTA_CD 0x08 // CD changed from last read -#define EDGEPORT_MSR_CTS 0x10 // Current state of CTS -#define EDGEPORT_MSR_DSR 0x20 // Current state of DSR -#define EDGEPORT_MSR_RI 0x40 // Current state of RI -#define EDGEPORT_MSR_CD 0x80 // Current state of CD - - - - // Tx Rx - //------------------------------- -#define EFR_SWFC_NONE 0x00 // None None -#define EFR_SWFC_RX1 0x02 // None XOFF1 -#define EFR_SWFC_RX2 0x01 // None XOFF2 -#define EFR_SWFC_RX12 0x03 // None XOFF1 & XOFF2 -#define EFR_SWFC_TX1 0x08 // XOFF1 None -#define EFR_SWFC_TX1_RX1 0x0a // XOFF1 XOFF1 -#define EFR_SWFC_TX1_RX2 0x09 // XOFF1 XOFF2 -#define EFR_SWFC_TX1_RX12 0x0b // XOFF1 XOFF1 & XOFF2 -#define EFR_SWFC_TX2 0x04 // XOFF2 None -#define EFR_SWFC_TX2_RX1 0x06 // XOFF2 XOFF1 -#define EFR_SWFC_TX2_RX2 0x05 // XOFF2 XOFF2 -#define EFR_SWFC_TX2_RX12 0x07 // XOFF2 XOFF1 & XOFF2 -#define EFR_SWFC_TX12 0x0c // XOFF1 & XOFF2 None -#define EFR_SWFC_TX12_RX1 0x0e // XOFF1 & XOFF2 XOFF1 -#define EFR_SWFC_TX12_RX2 0x0d // XOFF1 & XOFF2 XOFF2 -#define EFR_SWFC_TX12_RX12 0x0f // XOFF1 & XOFF2 XOFF1 & XOFF2 - -#define EFR_TX_FC_MASK 0x0c // Mask to isolate Rx flow control -#define EFR_TX_FC_NONE 0x00 // No Tx Xon/Xoff flow control -#define EFR_TX_FC_X1 0x08 // Transmit Xon1/Xoff1 -#define EFR_TX_FC_X2 0x04 // Transmit Xon2/Xoff2 -#define EFR_TX_FC_X1_2 0x0c // Transmit Xon1&2/Xoff1&2 - -#define EFR_RX_FC_MASK 0x03 // Mask to isolate Rx flow control -#define EFR_RX_FC_NONE 0x00 // No Rx Xon/Xoff flow control -#define EFR_RX_FC_X1 0x02 // Receiver compares Xon1/Xoff1 -#define EFR_RX_FC_X2 0x01 // Receiver compares Xon2/Xoff2 -#define EFR_RX_FC_X1_2 0x03 // Receiver compares Xon1&2/Xoff1&2 - - -#define EFR_SWFC_MASK 0x0F // Mask for software flow control field -#define EFR_ENABLE_16654 0x10 // Enable 16C654 features -#define EFR_SPEC_DETECT 0x20 // Enable special character detect interrupt -#define EFR_AUTO_RTS 0x40 // Use RTS for Rx flow control -#define EFR_AUTO_CTS 0x80 // Use CTS for Tx flow control - -#endif // if !defined(_16654_H) - diff --git a/ANDROID_3.4.5/drivers/usb/serial/io_edgeport.c b/ANDROID_3.4.5/drivers/usb/serial/io_edgeport.c deleted file mode 100644 index 323e8723..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/io_edgeport.c +++ /dev/null @@ -1,3195 +0,0 @@ -/* - * Edgeport USB Serial Converter driver - * - * Copyright (C) 2000 Inside Out Networks, All rights reserved. - * Copyright (C) 2001-2002 Greg Kroah-Hartman - * - * 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. - * - * Supports the following devices: - * Edgeport/4 - * Edgeport/4t - * Edgeport/2 - * Edgeport/4i - * Edgeport/2i - * Edgeport/421 - * Edgeport/21 - * Rapidport/4 - * Edgeport/8 - * Edgeport/2D8 - * Edgeport/4D8 - * Edgeport/8i - * - * For questions or problems with this driver, contact Inside Out - * Networks technical support, or Peter Berger , - * or Al Borchers . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "io_edgeport.h" -#include "io_ionsp.h" /* info for the iosp messages */ -#include "io_16654.h" /* 16654 UART defines */ - -/* - * Version Information - */ -#define DRIVER_VERSION "v2.7" -#define DRIVER_AUTHOR "Greg Kroah-Hartman and David Iacovelli" -#define DRIVER_DESC "Edgeport USB Serial Driver" - -#define MAX_NAME_LEN 64 - -#define CHASE_TIMEOUT (5*HZ) /* 5 seconds */ -#define OPEN_TIMEOUT (5*HZ) /* 5 seconds */ -#define COMMAND_TIMEOUT (5*HZ) /* 5 seconds */ - -/* receive port state */ -enum RXSTATE { - EXPECT_HDR1 = 0, /* Expect header byte 1 */ - EXPECT_HDR2 = 1, /* Expect header byte 2 */ - EXPECT_DATA = 2, /* Expect 'RxBytesRemaining' data */ - EXPECT_HDR3 = 3, /* Expect header byte 3 (for status hdrs only) */ -}; - - -/* Transmit Fifo - * This Transmit queue is an extension of the edgeport Rx buffer. - * The maximum amount of data buffered in both the edgeport - * Rx buffer (maxTxCredits) and this buffer will never exceed maxTxCredits. - */ -struct TxFifo { - unsigned int head; /* index to head pointer (write) */ - unsigned int tail; /* index to tail pointer (read) */ - unsigned int count; /* Bytes in queue */ - unsigned int size; /* Max size of queue (equal to Max number of TxCredits) */ - unsigned char *fifo; /* allocated Buffer */ -}; - -/* This structure holds all of the local port information */ -struct edgeport_port { - __u16 txCredits; /* our current credits for this port */ - __u16 maxTxCredits; /* the max size of the port */ - - struct TxFifo txfifo; /* transmit fifo -- size will be maxTxCredits */ - struct urb *write_urb; /* write URB for this port */ - bool write_in_progress; /* 'true' while a write URB is outstanding */ - spinlock_t ep_lock; - - __u8 shadowLCR; /* last LCR value received */ - __u8 shadowMCR; /* last MCR value received */ - __u8 shadowMSR; /* last MSR value received */ - __u8 shadowLSR; /* last LSR value received */ - __u8 shadowXonChar; /* last value set as XON char in Edgeport */ - __u8 shadowXoffChar; /* last value set as XOFF char in Edgeport */ - __u8 validDataMask; - __u32 baudRate; - - bool open; - bool openPending; - bool commandPending; - bool closePending; - bool chaseResponsePending; - - wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */ - wait_queue_head_t wait_open; /* for handling sleeping while waiting for open to finish */ - wait_queue_head_t wait_command; /* for handling sleeping while waiting for command to finish */ - wait_queue_head_t delta_msr_wait; /* for handling sleeping while waiting for msr change to happen */ - - struct async_icount icount; - struct usb_serial_port *port; /* loop back to the owner of this object */ -}; - - -/* This structure holds all of the individual device information */ -struct edgeport_serial { - char name[MAX_NAME_LEN+2]; /* string name of this device */ - - struct edge_manuf_descriptor manuf_descriptor; /* the manufacturer descriptor */ - struct edge_boot_descriptor boot_descriptor; /* the boot firmware descriptor */ - struct edgeport_product_info product_info; /* Product Info */ - struct edge_compatibility_descriptor epic_descriptor; /* Edgeport compatible descriptor */ - int is_epic; /* flag if EPiC device or not */ - - __u8 interrupt_in_endpoint; /* the interrupt endpoint handle */ - unsigned char *interrupt_in_buffer; /* the buffer we use for the interrupt endpoint */ - struct urb *interrupt_read_urb; /* our interrupt urb */ - - __u8 bulk_in_endpoint; /* the bulk in endpoint handle */ - unsigned char *bulk_in_buffer; /* the buffer we use for the bulk in endpoint */ - struct urb *read_urb; /* our bulk read urb */ - bool read_in_progress; - spinlock_t es_lock; - - __u8 bulk_out_endpoint; /* the bulk out endpoint handle */ - - __s16 rxBytesAvail; /* the number of bytes that we need to read from this device */ - - enum RXSTATE rxState; /* the current state of the bulk receive processor */ - __u8 rxHeader1; /* receive header byte 1 */ - __u8 rxHeader2; /* receive header byte 2 */ - __u8 rxHeader3; /* receive header byte 3 */ - __u8 rxPort; /* the port that we are currently receiving data for */ - __u8 rxStatusCode; /* the receive status code */ - __u8 rxStatusParam; /* the receive status paramater */ - __s16 rxBytesRemaining; /* the number of port bytes left to read */ - struct usb_serial *serial; /* loop back to the owner of this object */ -}; - -/* baud rate information */ -struct divisor_table_entry { - __u32 BaudRate; - __u16 Divisor; -}; - -/* - * Define table of divisors for Rev A EdgePort/4 hardware - * These assume a 3.6864MHz crystal, the standard /16, and - * MCR.7 = 0. - */ - -static const struct divisor_table_entry divisor_table[] = { - { 50, 4608}, - { 75, 3072}, - { 110, 2095}, /* 2094.545455 => 230450 => .0217 % over */ - { 134, 1713}, /* 1713.011152 => 230398.5 => .00065% under */ - { 150, 1536}, - { 300, 768}, - { 600, 384}, - { 1200, 192}, - { 1800, 128}, - { 2400, 96}, - { 4800, 48}, - { 7200, 32}, - { 9600, 24}, - { 14400, 16}, - { 19200, 12}, - { 38400, 6}, - { 57600, 4}, - { 115200, 2}, - { 230400, 1}, -}; - -/* local variables */ -static bool debug; - -/* Number of outstanding Command Write Urbs */ -static atomic_t CmdUrbs = ATOMIC_INIT(0); - - -/* local function prototypes */ - -/* function prototypes for all URB callbacks */ -static void edge_interrupt_callback(struct urb *urb); -static void edge_bulk_in_callback(struct urb *urb); -static void edge_bulk_out_data_callback(struct urb *urb); -static void edge_bulk_out_cmd_callback(struct urb *urb); - -/* function prototypes for the usbserial callbacks */ -static int edge_open(struct tty_struct *tty, struct usb_serial_port *port); -static void edge_close(struct usb_serial_port *port); -static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count); -static int edge_write_room(struct tty_struct *tty); -static int edge_chars_in_buffer(struct tty_struct *tty); -static void edge_throttle(struct tty_struct *tty); -static void edge_unthrottle(struct tty_struct *tty); -static void edge_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old_termios); -static int edge_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); -static void edge_break(struct tty_struct *tty, int break_state); -static int edge_tiocmget(struct tty_struct *tty); -static int edge_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear); -static int edge_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount); -static int edge_startup(struct usb_serial *serial); -static void edge_disconnect(struct usb_serial *serial); -static void edge_release(struct usb_serial *serial); - -#include "io_tables.h" /* all of the devices that this driver supports */ - -/* function prototypes for all of our local functions */ - -static void process_rcvd_data(struct edgeport_serial *edge_serial, - unsigned char *buffer, __u16 bufferLength); -static void process_rcvd_status(struct edgeport_serial *edge_serial, - __u8 byte2, __u8 byte3); -static void edge_tty_recv(struct device *dev, struct tty_struct *tty, - unsigned char *data, int length); -static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr); -static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData, - __u8 lsr, __u8 data); -static int send_iosp_ext_cmd(struct edgeport_port *edge_port, __u8 command, - __u8 param); -static int calc_baud_rate_divisor(int baud_rate, int *divisor); -static int send_cmd_write_baud_rate(struct edgeport_port *edge_port, - int baudRate); -static void change_port_settings(struct tty_struct *tty, - struct edgeport_port *edge_port, - struct ktermios *old_termios); -static int send_cmd_write_uart_register(struct edgeport_port *edge_port, - __u8 regNum, __u8 regValue); -static int write_cmd_usb(struct edgeport_port *edge_port, - unsigned char *buffer, int writeLength); -static void send_more_port_data(struct edgeport_serial *edge_serial, - struct edgeport_port *edge_port); - -static int sram_write(struct usb_serial *serial, __u16 extAddr, __u16 addr, - __u16 length, const __u8 *data); -static int rom_read(struct usb_serial *serial, __u16 extAddr, __u16 addr, - __u16 length, __u8 *data); -static int rom_write(struct usb_serial *serial, __u16 extAddr, __u16 addr, - __u16 length, const __u8 *data); -static void get_manufacturing_desc(struct edgeport_serial *edge_serial); -static void get_boot_desc(struct edgeport_serial *edge_serial); -static void load_application_firmware(struct edgeport_serial *edge_serial); - -static void unicode_to_ascii(char *string, int buflen, - __le16 *unicode, int unicode_size); - - -/* ************************************************************************ */ -/* ************************************************************************ */ -/* ************************************************************************ */ -/* ************************************************************************ */ - -/************************************************************************ - * * - * update_edgeport_E2PROM() Compare current versions of * - * Boot ROM and Manufacture * - * Descriptors with versions * - * embedded in this driver * - * * - ************************************************************************/ -static void update_edgeport_E2PROM(struct edgeport_serial *edge_serial) -{ - __u32 BootCurVer; - __u32 BootNewVer; - __u8 BootMajorVersion; - __u8 BootMinorVersion; - __u16 BootBuildNumber; - __u32 Bootaddr; - const struct ihex_binrec *rec; - const struct firmware *fw; - const char *fw_name; - int response; - - switch (edge_serial->product_info.iDownloadFile) { - case EDGE_DOWNLOAD_FILE_I930: - fw_name = "edgeport/boot.fw"; - break; - case EDGE_DOWNLOAD_FILE_80251: - fw_name = "edgeport/boot2.fw"; - break; - default: - return; - } - - response = request_ihex_firmware(&fw, fw_name, - &edge_serial->serial->dev->dev); - if (response) { - printk(KERN_ERR "Failed to load image \"%s\" err %d\n", - fw_name, response); - return; - } - - rec = (const struct ihex_binrec *)fw->data; - BootMajorVersion = rec->data[0]; - BootMinorVersion = rec->data[1]; - BootBuildNumber = (rec->data[2] << 8) | rec->data[3]; - - /* Check Boot Image Version */ - BootCurVer = (edge_serial->boot_descriptor.MajorVersion << 24) + - (edge_serial->boot_descriptor.MinorVersion << 16) + - le16_to_cpu(edge_serial->boot_descriptor.BuildNumber); - - BootNewVer = (BootMajorVersion << 24) + - (BootMinorVersion << 16) + - BootBuildNumber; - - dbg("Current Boot Image version %d.%d.%d", - edge_serial->boot_descriptor.MajorVersion, - edge_serial->boot_descriptor.MinorVersion, - le16_to_cpu(edge_serial->boot_descriptor.BuildNumber)); - - - if (BootNewVer > BootCurVer) { - dbg("**Update Boot Image from %d.%d.%d to %d.%d.%d", - edge_serial->boot_descriptor.MajorVersion, - edge_serial->boot_descriptor.MinorVersion, - le16_to_cpu(edge_serial->boot_descriptor.BuildNumber), - BootMajorVersion, BootMinorVersion, BootBuildNumber); - - dbg("Downloading new Boot Image"); - - for (rec = ihex_next_binrec(rec); rec; - rec = ihex_next_binrec(rec)) { - Bootaddr = be32_to_cpu(rec->addr); - response = rom_write(edge_serial->serial, - Bootaddr >> 16, - Bootaddr & 0xFFFF, - be16_to_cpu(rec->len), - &rec->data[0]); - if (response < 0) { - dev_err(&edge_serial->serial->dev->dev, - "rom_write failed (%x, %x, %d)\n", - Bootaddr >> 16, Bootaddr & 0xFFFF, - be16_to_cpu(rec->len)); - break; - } - } - } else { - dbg("Boot Image -- already up to date"); - } - release_firmware(fw); -} - -#if 0 -/************************************************************************ - * - * Get string descriptor from device - * - ************************************************************************/ -static int get_string_desc(struct usb_device *dev, int Id, - struct usb_string_descriptor **pRetDesc) -{ - struct usb_string_descriptor StringDesc; - struct usb_string_descriptor *pStringDesc; - - dbg("%s - USB String ID = %d", __func__, Id); - - if (!usb_get_descriptor(dev, USB_DT_STRING, Id, &StringDesc, - sizeof(StringDesc))) - return 0; - - pStringDesc = kmalloc(StringDesc.bLength, GFP_KERNEL); - if (!pStringDesc) - return -1; - - if (!usb_get_descriptor(dev, USB_DT_STRING, Id, pStringDesc, - StringDesc.bLength)) { - kfree(pStringDesc); - return -1; - } - - *pRetDesc = pStringDesc; - return 0; -} -#endif - -static void dump_product_info(struct edgeport_product_info *product_info) -{ - /* Dump Product Info structure */ - dbg("**Product Information:"); - dbg(" ProductId %x", product_info->ProductId); - dbg(" NumPorts %d", product_info->NumPorts); - dbg(" ProdInfoVer %d", product_info->ProdInfoVer); - dbg(" IsServer %d", product_info->IsServer); - dbg(" IsRS232 %d", product_info->IsRS232); - dbg(" IsRS422 %d", product_info->IsRS422); - dbg(" IsRS485 %d", product_info->IsRS485); - dbg(" RomSize %d", product_info->RomSize); - dbg(" RamSize %d", product_info->RamSize); - dbg(" CpuRev %x", product_info->CpuRev); - dbg(" BoardRev %x", product_info->BoardRev); - dbg(" BootMajorVersion %d.%d.%d", product_info->BootMajorVersion, - product_info->BootMinorVersion, - le16_to_cpu(product_info->BootBuildNumber)); - dbg(" FirmwareMajorVersion %d.%d.%d", - product_info->FirmwareMajorVersion, - product_info->FirmwareMinorVersion, - le16_to_cpu(product_info->FirmwareBuildNumber)); - dbg(" ManufactureDescDate %d/%d/%d", - product_info->ManufactureDescDate[0], - product_info->ManufactureDescDate[1], - product_info->ManufactureDescDate[2]+1900); - dbg(" iDownloadFile 0x%x", product_info->iDownloadFile); - dbg(" EpicVer %d", product_info->EpicVer); -} - -static void get_product_info(struct edgeport_serial *edge_serial) -{ - struct edgeport_product_info *product_info = &edge_serial->product_info; - - memset(product_info, 0, sizeof(struct edgeport_product_info)); - - product_info->ProductId = (__u16)(le16_to_cpu(edge_serial->serial->dev->descriptor.idProduct) & ~ION_DEVICE_ID_80251_NETCHIP); - product_info->NumPorts = edge_serial->manuf_descriptor.NumPorts; - product_info->ProdInfoVer = 0; - - product_info->RomSize = edge_serial->manuf_descriptor.RomSize; - product_info->RamSize = edge_serial->manuf_descriptor.RamSize; - product_info->CpuRev = edge_serial->manuf_descriptor.CpuRev; - product_info->BoardRev = edge_serial->manuf_descriptor.BoardRev; - - product_info->BootMajorVersion = - edge_serial->boot_descriptor.MajorVersion; - product_info->BootMinorVersion = - edge_serial->boot_descriptor.MinorVersion; - product_info->BootBuildNumber = - edge_serial->boot_descriptor.BuildNumber; - - memcpy(product_info->ManufactureDescDate, - edge_serial->manuf_descriptor.DescDate, - sizeof(edge_serial->manuf_descriptor.DescDate)); - - /* check if this is 2nd generation hardware */ - if (le16_to_cpu(edge_serial->serial->dev->descriptor.idProduct) - & ION_DEVICE_ID_80251_NETCHIP) - product_info->iDownloadFile = EDGE_DOWNLOAD_FILE_80251; - else - product_info->iDownloadFile = EDGE_DOWNLOAD_FILE_I930; - - /* Determine Product type and set appropriate flags */ - switch (DEVICE_ID_FROM_USB_PRODUCT_ID(product_info->ProductId)) { - case ION_DEVICE_ID_EDGEPORT_COMPATIBLE: - case ION_DEVICE_ID_EDGEPORT_4T: - case ION_DEVICE_ID_EDGEPORT_4: - case ION_DEVICE_ID_EDGEPORT_2: - case ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU: - case ION_DEVICE_ID_EDGEPORT_8: - case ION_DEVICE_ID_EDGEPORT_421: - case ION_DEVICE_ID_EDGEPORT_21: - case ION_DEVICE_ID_EDGEPORT_2_DIN: - case ION_DEVICE_ID_EDGEPORT_4_DIN: - case ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU: - product_info->IsRS232 = 1; - break; - - case ION_DEVICE_ID_EDGEPORT_2I: /* Edgeport/2 RS422/RS485 */ - product_info->IsRS422 = 1; - product_info->IsRS485 = 1; - break; - - case ION_DEVICE_ID_EDGEPORT_8I: /* Edgeport/4 RS422 */ - case ION_DEVICE_ID_EDGEPORT_4I: /* Edgeport/4 RS422 */ - product_info->IsRS422 = 1; - break; - } - - dump_product_info(product_info); -} - -static int get_epic_descriptor(struct edgeport_serial *ep) -{ - int result; - struct usb_serial *serial = ep->serial; - struct edgeport_product_info *product_info = &ep->product_info; - struct edge_compatibility_descriptor *epic = &ep->epic_descriptor; - struct edge_compatibility_bits *bits; - - ep->is_epic = 0; - result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - USB_REQUEST_ION_GET_EPIC_DESC, - 0xC0, 0x00, 0x00, - &ep->epic_descriptor, - sizeof(struct edge_compatibility_descriptor), - 300); - - dbg("%s result = %d", __func__, result); - - if (result > 0) { - ep->is_epic = 1; - memset(product_info, 0, sizeof(struct edgeport_product_info)); - - product_info->NumPorts = epic->NumPorts; - product_info->ProdInfoVer = 0; - product_info->FirmwareMajorVersion = epic->MajorVersion; - product_info->FirmwareMinorVersion = epic->MinorVersion; - product_info->FirmwareBuildNumber = epic->BuildNumber; - product_info->iDownloadFile = epic->iDownloadFile; - product_info->EpicVer = epic->EpicVer; - product_info->Epic = epic->Supports; - product_info->ProductId = ION_DEVICE_ID_EDGEPORT_COMPATIBLE; - dump_product_info(product_info); - - bits = &ep->epic_descriptor.Supports; - dbg("**EPIC descriptor:"); - dbg(" VendEnableSuspend: %s", bits->VendEnableSuspend ? "TRUE": "FALSE"); - dbg(" IOSPOpen : %s", bits->IOSPOpen ? "TRUE": "FALSE"); - dbg(" IOSPClose : %s", bits->IOSPClose ? "TRUE": "FALSE"); - dbg(" IOSPChase : %s", bits->IOSPChase ? "TRUE": "FALSE"); - dbg(" IOSPSetRxFlow : %s", bits->IOSPSetRxFlow ? "TRUE": "FALSE"); - dbg(" IOSPSetTxFlow : %s", bits->IOSPSetTxFlow ? "TRUE": "FALSE"); - dbg(" IOSPSetXChar : %s", bits->IOSPSetXChar ? "TRUE": "FALSE"); - dbg(" IOSPRxCheck : %s", bits->IOSPRxCheck ? "TRUE": "FALSE"); - dbg(" IOSPSetClrBreak : %s", bits->IOSPSetClrBreak ? "TRUE": "FALSE"); - dbg(" IOSPWriteMCR : %s", bits->IOSPWriteMCR ? "TRUE": "FALSE"); - dbg(" IOSPWriteLCR : %s", bits->IOSPWriteLCR ? "TRUE": "FALSE"); - dbg(" IOSPSetBaudRate : %s", bits->IOSPSetBaudRate ? "TRUE": "FALSE"); - dbg(" TrueEdgeport : %s", bits->TrueEdgeport ? "TRUE": "FALSE"); - } - - return result; -} - - -/************************************************************************/ -/************************************************************************/ -/* U S B C A L L B A C K F U N C T I O N S */ -/* U S B C A L L B A C K F U N C T I O N S */ -/************************************************************************/ -/************************************************************************/ - -/***************************************************************************** - * edge_interrupt_callback - * this is the callback function for when we have received data on the - * interrupt endpoint. - *****************************************************************************/ -static void edge_interrupt_callback(struct urb *urb) -{ - struct edgeport_serial *edge_serial = urb->context; - struct edgeport_port *edge_port; - struct usb_serial_port *port; - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - int length = urb->actual_length; - int bytes_avail; - int position; - int txCredits; - int portNumber; - int result; - int status = urb->status; - - dbg("%s", __func__); - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); - return; - default: - dbg("%s - nonzero urb status received: %d", __func__, status); - goto exit; - } - - /* process this interrupt-read even if there are no ports open */ - if (length) { - usb_serial_debug_data(debug, &edge_serial->serial->dev->dev, - __func__, length, data); - - if (length > 1) { - bytes_avail = data[0] | (data[1] << 8); - if (bytes_avail) { - spin_lock(&edge_serial->es_lock); - edge_serial->rxBytesAvail += bytes_avail; - dbg("%s - bytes_avail=%d, rxBytesAvail=%d, read_in_progress=%d", __func__, bytes_avail, edge_serial->rxBytesAvail, edge_serial->read_in_progress); - - if (edge_serial->rxBytesAvail > 0 && - !edge_serial->read_in_progress) { - dbg("%s - posting a read", __func__); - edge_serial->read_in_progress = true; - - /* we have pending bytes on the - bulk in pipe, send a request */ - result = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC); - if (result) { - dev_err(&edge_serial->serial->dev->dev, "%s - usb_submit_urb(read bulk) failed with result = %d\n", __func__, result); - edge_serial->read_in_progress = false; - } - } - spin_unlock(&edge_serial->es_lock); - } - } - /* grab the txcredits for the ports if available */ - position = 2; - portNumber = 0; - while ((position < length) && - (portNumber < edge_serial->serial->num_ports)) { - txCredits = data[position] | (data[position+1] << 8); - if (txCredits) { - port = edge_serial->serial->port[portNumber]; - edge_port = usb_get_serial_port_data(port); - if (edge_port->open) { - spin_lock(&edge_port->ep_lock); - edge_port->txCredits += txCredits; - spin_unlock(&edge_port->ep_lock); - dbg("%s - txcredits for port%d = %d", - __func__, portNumber, - edge_port->txCredits); - - /* tell the tty driver that something - has changed */ - tty = tty_port_tty_get( - &edge_port->port->port); - if (tty) { - tty_wakeup(tty); - tty_kref_put(tty); - } - /* Since we have more credit, check - if more data can be sent */ - send_more_port_data(edge_serial, - edge_port); - } - } - position += 2; - ++portNumber; - } - } - -exit: - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) - dev_err(&urb->dev->dev, - "%s - Error %d submitting control urb\n", - __func__, result); -} - - -/***************************************************************************** - * edge_bulk_in_callback - * this is the callback function for when we have received data on the - * bulk in endpoint. - *****************************************************************************/ -static void edge_bulk_in_callback(struct urb *urb) -{ - struct edgeport_serial *edge_serial = urb->context; - unsigned char *data = urb->transfer_buffer; - int retval; - __u16 raw_data_length; - int status = urb->status; - - dbg("%s", __func__); - - if (status) { - dbg("%s - nonzero read bulk status received: %d", - __func__, status); - edge_serial->read_in_progress = false; - return; - } - - if (urb->actual_length == 0) { - dbg("%s - read bulk callback with no data", __func__); - edge_serial->read_in_progress = false; - return; - } - - raw_data_length = urb->actual_length; - - usb_serial_debug_data(debug, &edge_serial->serial->dev->dev, - __func__, raw_data_length, data); - - spin_lock(&edge_serial->es_lock); - - /* decrement our rxBytes available by the number that we just got */ - edge_serial->rxBytesAvail -= raw_data_length; - - dbg("%s - Received = %d, rxBytesAvail %d", __func__, - raw_data_length, edge_serial->rxBytesAvail); - - process_rcvd_data(edge_serial, data, urb->actual_length); - - /* check to see if there's any more data for us to read */ - if (edge_serial->rxBytesAvail > 0) { - dbg("%s - posting a read", __func__); - retval = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC); - if (retval) { - dev_err(&urb->dev->dev, - "%s - usb_submit_urb(read bulk) failed, " - "retval = %d\n", __func__, retval); - edge_serial->read_in_progress = false; - } - } else { - edge_serial->read_in_progress = false; - } - - spin_unlock(&edge_serial->es_lock); -} - - -/***************************************************************************** - * edge_bulk_out_data_callback - * this is the callback function for when we have finished sending - * serial data on the bulk out endpoint. - *****************************************************************************/ -static void edge_bulk_out_data_callback(struct urb *urb) -{ - struct edgeport_port *edge_port = urb->context; - struct tty_struct *tty; - int status = urb->status; - - dbg("%s", __func__); - - if (status) { - dbg("%s - nonzero write bulk status received: %d", - __func__, status); - } - - tty = tty_port_tty_get(&edge_port->port->port); - - if (tty && edge_port->open) { - /* let the tty driver wakeup if it has a special - write_wakeup function */ - tty_wakeup(tty); - } - tty_kref_put(tty); - - /* Release the Write URB */ - edge_port->write_in_progress = false; - - /* Check if more data needs to be sent */ - send_more_port_data((struct edgeport_serial *) - (usb_get_serial_data(edge_port->port->serial)), edge_port); -} - - -/***************************************************************************** - * BulkOutCmdCallback - * this is the callback function for when we have finished sending a - * command on the bulk out endpoint. - *****************************************************************************/ -static void edge_bulk_out_cmd_callback(struct urb *urb) -{ - struct edgeport_port *edge_port = urb->context; - struct tty_struct *tty; - int status = urb->status; - - dbg("%s", __func__); - - atomic_dec(&CmdUrbs); - dbg("%s - FREE URB %p (outstanding %d)", __func__, - urb, atomic_read(&CmdUrbs)); - - - /* clean up the transfer buffer */ - kfree(urb->transfer_buffer); - - /* Free the command urb */ - usb_free_urb(urb); - - if (status) { - dbg("%s - nonzero write bulk status received: %d", - __func__, status); - return; - } - - /* Get pointer to tty */ - tty = tty_port_tty_get(&edge_port->port->port); - - /* tell the tty driver that something has changed */ - if (tty && edge_port->open) - tty_wakeup(tty); - tty_kref_put(tty); - - /* we have completed the command */ - edge_port->commandPending = false; - wake_up(&edge_port->wait_command); -} - - -/***************************************************************************** - * Driver tty interface functions - *****************************************************************************/ - -/***************************************************************************** - * SerialOpen - * this function is called by the tty driver when a port is opened - * If successful, we return 0 - * Otherwise we return a negative error number. - *****************************************************************************/ -static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - struct usb_serial *serial; - struct edgeport_serial *edge_serial; - int response; - - dbg("%s - port %d", __func__, port->number); - - if (edge_port == NULL) - return -ENODEV; - - /* see if we've set up our endpoint info yet (can't set it up - in edge_startup as the structures were not set up at that time.) */ - serial = port->serial; - edge_serial = usb_get_serial_data(serial); - if (edge_serial == NULL) - return -ENODEV; - if (edge_serial->interrupt_in_buffer == NULL) { - struct usb_serial_port *port0 = serial->port[0]; - - /* not set up yet, so do it now */ - edge_serial->interrupt_in_buffer = - port0->interrupt_in_buffer; - edge_serial->interrupt_in_endpoint = - port0->interrupt_in_endpointAddress; - edge_serial->interrupt_read_urb = port0->interrupt_in_urb; - edge_serial->bulk_in_buffer = port0->bulk_in_buffer; - edge_serial->bulk_in_endpoint = - port0->bulk_in_endpointAddress; - edge_serial->read_urb = port0->read_urb; - edge_serial->bulk_out_endpoint = - port0->bulk_out_endpointAddress; - - /* set up our interrupt urb */ - usb_fill_int_urb(edge_serial->interrupt_read_urb, - serial->dev, - usb_rcvintpipe(serial->dev, - port0->interrupt_in_endpointAddress), - port0->interrupt_in_buffer, - edge_serial->interrupt_read_urb->transfer_buffer_length, - edge_interrupt_callback, edge_serial, - edge_serial->interrupt_read_urb->interval); - - /* set up our bulk in urb */ - usb_fill_bulk_urb(edge_serial->read_urb, serial->dev, - usb_rcvbulkpipe(serial->dev, - port0->bulk_in_endpointAddress), - port0->bulk_in_buffer, - edge_serial->read_urb->transfer_buffer_length, - edge_bulk_in_callback, edge_serial); - edge_serial->read_in_progress = false; - - /* start interrupt read for this edgeport - * this interrupt will continue as long - * as the edgeport is connected */ - response = usb_submit_urb(edge_serial->interrupt_read_urb, - GFP_KERNEL); - if (response) { - dev_err(&port->dev, - "%s - Error %d submitting control urb\n", - __func__, response); - } - } - - /* initialize our wait queues */ - init_waitqueue_head(&edge_port->wait_open); - init_waitqueue_head(&edge_port->wait_chase); - init_waitqueue_head(&edge_port->delta_msr_wait); - init_waitqueue_head(&edge_port->wait_command); - - /* initialize our icount structure */ - memset(&(edge_port->icount), 0x00, sizeof(edge_port->icount)); - - /* initialize our port settings */ - edge_port->txCredits = 0; /* Can't send any data yet */ - /* Must always set this bit to enable ints! */ - edge_port->shadowMCR = MCR_MASTER_IE; - edge_port->chaseResponsePending = false; - - /* send a open port command */ - edge_port->openPending = true; - edge_port->open = false; - response = send_iosp_ext_cmd(edge_port, IOSP_CMD_OPEN_PORT, 0); - - if (response < 0) { - dev_err(&port->dev, "%s - error sending open port command\n", - __func__); - edge_port->openPending = false; - return -ENODEV; - } - - /* now wait for the port to be completely opened */ - wait_event_timeout(edge_port->wait_open, !edge_port->openPending, - OPEN_TIMEOUT); - - if (!edge_port->open) { - /* open timed out */ - dbg("%s - open timedout", __func__); - edge_port->openPending = false; - return -ENODEV; - } - - /* create the txfifo */ - edge_port->txfifo.head = 0; - edge_port->txfifo.tail = 0; - edge_port->txfifo.count = 0; - edge_port->txfifo.size = edge_port->maxTxCredits; - edge_port->txfifo.fifo = kmalloc(edge_port->maxTxCredits, GFP_KERNEL); - - if (!edge_port->txfifo.fifo) { - dbg("%s - no memory", __func__); - edge_close(port); - return -ENOMEM; - } - - /* Allocate a URB for the write */ - edge_port->write_urb = usb_alloc_urb(0, GFP_KERNEL); - edge_port->write_in_progress = false; - - if (!edge_port->write_urb) { - dbg("%s - no memory", __func__); - edge_close(port); - return -ENOMEM; - } - - dbg("%s(%d) - Initialize TX fifo to %d bytes", - __func__, port->number, edge_port->maxTxCredits); - - dbg("%s exited", __func__); - - return 0; -} - - -/************************************************************************ - * - * block_until_chase_response - * - * This function will block the close until one of the following: - * 1. Response to our Chase comes from Edgeport - * 2. A timeout of 10 seconds without activity has expired - * (1K of Edgeport data @ 2400 baud ==> 4 sec to empty) - * - ************************************************************************/ -static void block_until_chase_response(struct edgeport_port *edge_port) -{ - DEFINE_WAIT(wait); - __u16 lastCredits; - int timeout = 1*HZ; - int loop = 10; - - while (1) { - /* Save Last credits */ - lastCredits = edge_port->txCredits; - - /* Did we get our Chase response */ - if (!edge_port->chaseResponsePending) { - dbg("%s - Got Chase Response", __func__); - - /* did we get all of our credit back? */ - if (edge_port->txCredits == edge_port->maxTxCredits) { - dbg("%s - Got all credits", __func__); - return; - } - } - - /* Block the thread for a while */ - prepare_to_wait(&edge_port->wait_chase, &wait, - TASK_UNINTERRUPTIBLE); - schedule_timeout(timeout); - finish_wait(&edge_port->wait_chase, &wait); - - if (lastCredits == edge_port->txCredits) { - /* No activity.. count down. */ - loop--; - if (loop == 0) { - edge_port->chaseResponsePending = false; - dbg("%s - Chase TIMEOUT", __func__); - return; - } - } else { - /* Reset timeout value back to 10 seconds */ - dbg("%s - Last %d, Current %d", __func__, - lastCredits, edge_port->txCredits); - loop = 10; - } - } -} - - -/************************************************************************ - * - * block_until_tx_empty - * - * This function will block the close until one of the following: - * 1. TX count are 0 - * 2. The edgeport has stopped - * 3. A timeout of 3 seconds without activity has expired - * - ************************************************************************/ -static void block_until_tx_empty(struct edgeport_port *edge_port) -{ - DEFINE_WAIT(wait); - struct TxFifo *fifo = &edge_port->txfifo; - __u32 lastCount; - int timeout = HZ/10; - int loop = 30; - - while (1) { - /* Save Last count */ - lastCount = fifo->count; - - /* Is the Edgeport Buffer empty? */ - if (lastCount == 0) { - dbg("%s - TX Buffer Empty", __func__); - return; - } - - /* Block the thread for a while */ - prepare_to_wait(&edge_port->wait_chase, &wait, - TASK_UNINTERRUPTIBLE); - schedule_timeout(timeout); - finish_wait(&edge_port->wait_chase, &wait); - - dbg("%s wait", __func__); - - if (lastCount == fifo->count) { - /* No activity.. count down. */ - loop--; - if (loop == 0) { - dbg("%s - TIMEOUT", __func__); - return; - } - } else { - /* Reset timeout value back to seconds */ - loop = 30; - } - } -} - - -/***************************************************************************** - * edge_close - * this function is called by the tty driver when a port is closed - *****************************************************************************/ -static void edge_close(struct usb_serial_port *port) -{ - struct edgeport_serial *edge_serial; - struct edgeport_port *edge_port; - int status; - - dbg("%s - port %d", __func__, port->number); - - edge_serial = usb_get_serial_data(port->serial); - edge_port = usb_get_serial_port_data(port); - if (edge_serial == NULL || edge_port == NULL) - return; - - /* block until tx is empty */ - block_until_tx_empty(edge_port); - - edge_port->closePending = true; - - if ((!edge_serial->is_epic) || - ((edge_serial->is_epic) && - (edge_serial->epic_descriptor.Supports.IOSPChase))) { - /* flush and chase */ - edge_port->chaseResponsePending = true; - - dbg("%s - Sending IOSP_CMD_CHASE_PORT", __func__); - status = send_iosp_ext_cmd(edge_port, IOSP_CMD_CHASE_PORT, 0); - if (status == 0) - /* block until chase finished */ - block_until_chase_response(edge_port); - else - edge_port->chaseResponsePending = false; - } - - if ((!edge_serial->is_epic) || - ((edge_serial->is_epic) && - (edge_serial->epic_descriptor.Supports.IOSPClose))) { - /* close the port */ - dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __func__); - send_iosp_ext_cmd(edge_port, IOSP_CMD_CLOSE_PORT, 0); - } - - /* port->close = true; */ - edge_port->closePending = false; - edge_port->open = false; - edge_port->openPending = false; - - usb_kill_urb(edge_port->write_urb); - - if (edge_port->write_urb) { - /* if this urb had a transfer buffer already - (old transfer) free it */ - kfree(edge_port->write_urb->transfer_buffer); - usb_free_urb(edge_port->write_urb); - edge_port->write_urb = NULL; - } - kfree(edge_port->txfifo.fifo); - edge_port->txfifo.fifo = NULL; - - dbg("%s exited", __func__); -} - -/***************************************************************************** - * SerialWrite - * this function is called by the tty driver when data should be written - * to the port. - * If successful, we return the number of bytes written, otherwise we - * return a negative error number. - *****************************************************************************/ -static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *data, int count) -{ - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - struct TxFifo *fifo; - int copySize; - int bytesleft; - int firsthalf; - int secondhalf; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - if (edge_port == NULL) - return -ENODEV; - - /* get a pointer to the Tx fifo */ - fifo = &edge_port->txfifo; - - spin_lock_irqsave(&edge_port->ep_lock, flags); - - /* calculate number of bytes to put in fifo */ - copySize = min((unsigned int)count, - (edge_port->txCredits - fifo->count)); - - dbg("%s(%d) of %d byte(s) Fifo room %d -- will copy %d bytes", - __func__, port->number, count, - edge_port->txCredits - fifo->count, copySize); - - /* catch writes of 0 bytes which the tty driver likes to give us, - and when txCredits is empty */ - if (copySize == 0) { - dbg("%s - copySize = Zero", __func__); - goto finish_write; - } - - /* queue the data - * since we can never overflow the buffer we do not have to check for a - * full condition - * - * the copy is done is two parts -- first fill to the end of the buffer - * then copy the reset from the start of the buffer - */ - bytesleft = fifo->size - fifo->head; - firsthalf = min(bytesleft, copySize); - dbg("%s - copy %d bytes of %d into fifo ", __func__, - firsthalf, bytesleft); - - /* now copy our data */ - memcpy(&fifo->fifo[fifo->head], data, firsthalf); - usb_serial_debug_data(debug, &port->dev, __func__, - firsthalf, &fifo->fifo[fifo->head]); - - /* update the index and size */ - fifo->head += firsthalf; - fifo->count += firsthalf; - - /* wrap the index */ - if (fifo->head == fifo->size) - fifo->head = 0; - - secondhalf = copySize-firsthalf; - - if (secondhalf) { - dbg("%s - copy rest of data %d", __func__, secondhalf); - memcpy(&fifo->fifo[fifo->head], &data[firsthalf], secondhalf); - usb_serial_debug_data(debug, &port->dev, __func__, - secondhalf, &fifo->fifo[fifo->head]); - /* update the index and size */ - fifo->count += secondhalf; - fifo->head += secondhalf; - /* No need to check for wrap since we can not get to end of - * the fifo in this part - */ - } - -finish_write: - spin_unlock_irqrestore(&edge_port->ep_lock, flags); - - send_more_port_data((struct edgeport_serial *) - usb_get_serial_data(port->serial), edge_port); - - dbg("%s wrote %d byte(s) TxCredits %d, Fifo %d", __func__, - copySize, edge_port->txCredits, fifo->count); - - return copySize; -} - - -/************************************************************************ - * - * send_more_port_data() - * - * This routine attempts to write additional UART transmit data - * to a port over the USB bulk pipe. It is called (1) when new - * data has been written to a port's TxBuffer from higher layers - * (2) when the peripheral sends us additional TxCredits indicating - * that it can accept more Tx data for a given port; and (3) when - * a bulk write completes successfully and we want to see if we - * can transmit more. - * - ************************************************************************/ -static void send_more_port_data(struct edgeport_serial *edge_serial, - struct edgeport_port *edge_port) -{ - struct TxFifo *fifo = &edge_port->txfifo; - struct urb *urb; - unsigned char *buffer; - int status; - int count; - int bytesleft; - int firsthalf; - int secondhalf; - unsigned long flags; - - dbg("%s(%d)", __func__, edge_port->port->number); - - spin_lock_irqsave(&edge_port->ep_lock, flags); - - if (edge_port->write_in_progress || - !edge_port->open || - (fifo->count == 0)) { - dbg("%s(%d) EXIT - fifo %d, PendingWrite = %d", - __func__, edge_port->port->number, - fifo->count, edge_port->write_in_progress); - goto exit_send; - } - - /* since the amount of data in the fifo will always fit into the - * edgeport buffer we do not need to check the write length - * - * Do we have enough credits for this port to make it worthwhile - * to bother queueing a write. If it's too small, say a few bytes, - * it's better to wait for more credits so we can do a larger write. - */ - if (edge_port->txCredits < EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(edge_port->maxTxCredits, EDGE_FW_BULK_MAX_PACKET_SIZE)) { - dbg("%s(%d) Not enough credit - fifo %d TxCredit %d", - __func__, edge_port->port->number, fifo->count, - edge_port->txCredits); - goto exit_send; - } - - /* lock this write */ - edge_port->write_in_progress = true; - - /* get a pointer to the write_urb */ - urb = edge_port->write_urb; - - /* make sure transfer buffer is freed */ - kfree(urb->transfer_buffer); - urb->transfer_buffer = NULL; - - /* build the data header for the buffer and port that we are about - to send out */ - count = fifo->count; - buffer = kmalloc(count+2, GFP_ATOMIC); - if (buffer == NULL) { - dev_err_console(edge_port->port, - "%s - no more kernel memory...\n", __func__); - edge_port->write_in_progress = false; - goto exit_send; - } - buffer[0] = IOSP_BUILD_DATA_HDR1(edge_port->port->number - - edge_port->port->serial->minor, count); - buffer[1] = IOSP_BUILD_DATA_HDR2(edge_port->port->number - - edge_port->port->serial->minor, count); - - /* now copy our data */ - bytesleft = fifo->size - fifo->tail; - firsthalf = min(bytesleft, count); - memcpy(&buffer[2], &fifo->fifo[fifo->tail], firsthalf); - fifo->tail += firsthalf; - fifo->count -= firsthalf; - if (fifo->tail == fifo->size) - fifo->tail = 0; - - secondhalf = count-firsthalf; - if (secondhalf) { - memcpy(&buffer[2+firsthalf], &fifo->fifo[fifo->tail], - secondhalf); - fifo->tail += secondhalf; - fifo->count -= secondhalf; - } - - if (count) - usb_serial_debug_data(debug, &edge_port->port->dev, - __func__, count, &buffer[2]); - - /* fill up the urb with all of our data and submit it */ - usb_fill_bulk_urb(urb, edge_serial->serial->dev, - usb_sndbulkpipe(edge_serial->serial->dev, - edge_serial->bulk_out_endpoint), - buffer, count+2, - edge_bulk_out_data_callback, edge_port); - - /* decrement the number of credits we have by the number we just sent */ - edge_port->txCredits -= count; - edge_port->icount.tx += count; - - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) { - /* something went wrong */ - dev_err_console(edge_port->port, - "%s - usb_submit_urb(write bulk) failed, status = %d, data lost\n", - __func__, status); - edge_port->write_in_progress = false; - - /* revert the credits as something bad happened. */ - edge_port->txCredits += count; - edge_port->icount.tx -= count; - } - dbg("%s wrote %d byte(s) TxCredit %d, Fifo %d", - __func__, count, edge_port->txCredits, fifo->count); - -exit_send: - spin_unlock_irqrestore(&edge_port->ep_lock, flags); -} - - -/***************************************************************************** - * edge_write_room - * this function is called by the tty driver when it wants to know how - * many bytes of data we can accept for a specific port. If successful, - * we return the amount of room that we have for this port (the txCredits) - * otherwise we return a negative error number. - *****************************************************************************/ -static int edge_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - int room; - unsigned long flags; - - dbg("%s", __func__); - - if (edge_port == NULL) - return 0; - if (edge_port->closePending) - return 0; - - dbg("%s - port %d", __func__, port->number); - - if (!edge_port->open) { - dbg("%s - port not opened", __func__); - return 0; - } - - /* total of both buffers is still txCredit */ - spin_lock_irqsave(&edge_port->ep_lock, flags); - room = edge_port->txCredits - edge_port->txfifo.count; - spin_unlock_irqrestore(&edge_port->ep_lock, flags); - - dbg("%s - returns %d", __func__, room); - return room; -} - - -/***************************************************************************** - * edge_chars_in_buffer - * this function is called by the tty driver when it wants to know how - * many bytes of data we currently have outstanding in the port (data that - * has been written, but hasn't made it out the port yet) - * If successful, we return the number of bytes left to be written in the - * system, - * Otherwise we return a negative error number. - *****************************************************************************/ -static int edge_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - int num_chars; - unsigned long flags; - - dbg("%s", __func__); - - if (edge_port == NULL) - return 0; - if (edge_port->closePending) - return 0; - - if (!edge_port->open) { - dbg("%s - port not opened", __func__); - return 0; - } - - spin_lock_irqsave(&edge_port->ep_lock, flags); - num_chars = edge_port->maxTxCredits - edge_port->txCredits + - edge_port->txfifo.count; - spin_unlock_irqrestore(&edge_port->ep_lock, flags); - if (num_chars) { - dbg("%s(port %d) - returns %d", __func__, - port->number, num_chars); - } - - return num_chars; -} - - -/***************************************************************************** - * SerialThrottle - * this function is called by the tty driver when it wants to stop the data - * being read from the port. - *****************************************************************************/ -static void edge_throttle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - int status; - - dbg("%s - port %d", __func__, port->number); - - if (edge_port == NULL) - return; - - if (!edge_port->open) { - dbg("%s - port not opened", __func__); - return; - } - - /* if we are implementing XON/XOFF, send the stop character */ - if (I_IXOFF(tty)) { - unsigned char stop_char = STOP_CHAR(tty); - status = edge_write(tty, port, &stop_char, 1); - if (status <= 0) - return; - } - - /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { - edge_port->shadowMCR &= ~MCR_RTS; - status = send_cmd_write_uart_register(edge_port, MCR, - edge_port->shadowMCR); - if (status != 0) - return; - } -} - - -/***************************************************************************** - * edge_unthrottle - * this function is called by the tty driver when it wants to resume the - * data being read from the port (called after SerialThrottle is called) - *****************************************************************************/ -static void edge_unthrottle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - int status; - - dbg("%s - port %d", __func__, port->number); - - if (edge_port == NULL) - return; - - if (!edge_port->open) { - dbg("%s - port not opened", __func__); - return; - } - - /* if we are implementing XON/XOFF, send the start character */ - if (I_IXOFF(tty)) { - unsigned char start_char = START_CHAR(tty); - status = edge_write(tty, port, &start_char, 1); - if (status <= 0) - return; - } - /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { - edge_port->shadowMCR |= MCR_RTS; - send_cmd_write_uart_register(edge_port, MCR, - edge_port->shadowMCR); - } -} - - -/***************************************************************************** - * SerialSetTermios - * this function is called by the tty driver when it wants to change - * the termios structure - *****************************************************************************/ -static void edge_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) -{ - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - unsigned int cflag; - - cflag = tty->termios->c_cflag; - dbg("%s - clfag %08x iflag %08x", __func__, - tty->termios->c_cflag, tty->termios->c_iflag); - dbg("%s - old clfag %08x old iflag %08x", __func__, - old_termios->c_cflag, old_termios->c_iflag); - - dbg("%s - port %d", __func__, port->number); - - if (edge_port == NULL) - return; - - if (!edge_port->open) { - dbg("%s - port not opened", __func__); - return; - } - - /* change the port settings to the new ones specified */ - change_port_settings(tty, edge_port, old_termios); -} - - -/***************************************************************************** - * get_lsr_info - get line status register info - * - * Purpose: Let user call ioctl() to get info when the UART physically - * is emptied. On bus types like RS485, the transmitter must - * release the bus after transmitting. This must be done when - * the transmit shift register is empty, not be done when the - * transmit holding register is empty. This functionality - * allows an RS485 driver to be written in user space. - *****************************************************************************/ -static int get_lsr_info(struct edgeport_port *edge_port, - unsigned int __user *value) -{ - unsigned int result = 0; - unsigned long flags; - - spin_lock_irqsave(&edge_port->ep_lock, flags); - if (edge_port->maxTxCredits == edge_port->txCredits && - edge_port->txfifo.count == 0) { - dbg("%s -- Empty", __func__); - result = TIOCSER_TEMT; - } - spin_unlock_irqrestore(&edge_port->ep_lock, flags); - - if (copy_to_user(value, &result, sizeof(int))) - return -EFAULT; - return 0; -} - -static int edge_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - unsigned int mcr; - - dbg("%s - port %d", __func__, port->number); - - mcr = edge_port->shadowMCR; - if (set & TIOCM_RTS) - mcr |= MCR_RTS; - if (set & TIOCM_DTR) - mcr |= MCR_DTR; - if (set & TIOCM_LOOP) - mcr |= MCR_LOOPBACK; - - if (clear & TIOCM_RTS) - mcr &= ~MCR_RTS; - if (clear & TIOCM_DTR) - mcr &= ~MCR_DTR; - if (clear & TIOCM_LOOP) - mcr &= ~MCR_LOOPBACK; - - edge_port->shadowMCR = mcr; - - send_cmd_write_uart_register(edge_port, MCR, edge_port->shadowMCR); - - return 0; -} - -static int edge_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - unsigned int result = 0; - unsigned int msr; - unsigned int mcr; - - dbg("%s - port %d", __func__, port->number); - - msr = edge_port->shadowMSR; - mcr = edge_port->shadowMCR; - result = ((mcr & MCR_DTR) ? TIOCM_DTR: 0) /* 0x002 */ - | ((mcr & MCR_RTS) ? TIOCM_RTS: 0) /* 0x004 */ - | ((msr & EDGEPORT_MSR_CTS) ? TIOCM_CTS: 0) /* 0x020 */ - | ((msr & EDGEPORT_MSR_CD) ? TIOCM_CAR: 0) /* 0x040 */ - | ((msr & EDGEPORT_MSR_RI) ? TIOCM_RI: 0) /* 0x080 */ - | ((msr & EDGEPORT_MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */ - - - dbg("%s -- %x", __func__, result); - - return result; -} - -static int edge_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - struct async_icount cnow; - cnow = edge_port->icount; - - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - icount->rx = cnow.rx; - icount->tx = cnow.tx; - icount->frame = cnow.frame; - icount->overrun = cnow.overrun; - icount->parity = cnow.parity; - icount->brk = cnow.brk; - icount->buf_overrun = cnow.buf_overrun; - - dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", - __func__, port->number, icount->rx, icount->tx); - return 0; -} - -static int get_serial_info(struct edgeport_port *edge_port, - struct serial_struct __user *retinfo) -{ - struct serial_struct tmp; - - if (!retinfo) - return -EFAULT; - - memset(&tmp, 0, sizeof(tmp)); - - tmp.type = PORT_16550A; - tmp.line = edge_port->port->serial->minor; - tmp.port = edge_port->port->number; - tmp.irq = 0; - tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; - tmp.xmit_fifo_size = edge_port->maxTxCredits; - tmp.baud_base = 9600; - tmp.close_delay = 5*HZ; - tmp.closing_wait = 30*HZ; - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - return 0; -} - - -/***************************************************************************** - * SerialIoctl - * this function handles any ioctl calls to the driver - *****************************************************************************/ -static int edge_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - DEFINE_WAIT(wait); - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - struct async_icount cnow; - struct async_icount cprev; - - dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd); - - switch (cmd) { - case TIOCSERGETLSR: - dbg("%s (%d) TIOCSERGETLSR", __func__, port->number); - return get_lsr_info(edge_port, (unsigned int __user *) arg); - - case TIOCGSERIAL: - dbg("%s (%d) TIOCGSERIAL", __func__, port->number); - return get_serial_info(edge_port, (struct serial_struct __user *) arg); - - case TIOCMIWAIT: - dbg("%s (%d) TIOCMIWAIT", __func__, port->number); - cprev = edge_port->icount; - while (1) { - prepare_to_wait(&edge_port->delta_msr_wait, - &wait, TASK_INTERRUPTIBLE); - schedule(); - finish_wait(&edge_port->delta_msr_wait, &wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - cnow = edge_port->icount; - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { - return 0; - } - cprev = cnow; - } - /* NOTREACHED */ - break; - - } - return -ENOIOCTLCMD; -} - - -/***************************************************************************** - * SerialBreak - * this function sends a break to the port - *****************************************************************************/ -static void edge_break(struct tty_struct *tty, int break_state) -{ - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - struct edgeport_serial *edge_serial = usb_get_serial_data(port->serial); - int status; - - if ((!edge_serial->is_epic) || - ((edge_serial->is_epic) && - (edge_serial->epic_descriptor.Supports.IOSPChase))) { - /* flush and chase */ - edge_port->chaseResponsePending = true; - - dbg("%s - Sending IOSP_CMD_CHASE_PORT", __func__); - status = send_iosp_ext_cmd(edge_port, IOSP_CMD_CHASE_PORT, 0); - if (status == 0) { - /* block until chase finished */ - block_until_chase_response(edge_port); - } else { - edge_port->chaseResponsePending = false; - } - } - - if ((!edge_serial->is_epic) || - ((edge_serial->is_epic) && - (edge_serial->epic_descriptor.Supports.IOSPSetClrBreak))) { - if (break_state == -1) { - dbg("%s - Sending IOSP_CMD_SET_BREAK", __func__); - status = send_iosp_ext_cmd(edge_port, - IOSP_CMD_SET_BREAK, 0); - } else { - dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __func__); - status = send_iosp_ext_cmd(edge_port, - IOSP_CMD_CLEAR_BREAK, 0); - } - if (status) - dbg("%s - error sending break set/clear command.", - __func__); - } -} - - -/***************************************************************************** - * process_rcvd_data - * this function handles the data received on the bulk in pipe. - *****************************************************************************/ -static void process_rcvd_data(struct edgeport_serial *edge_serial, - unsigned char *buffer, __u16 bufferLength) -{ - struct usb_serial_port *port; - struct edgeport_port *edge_port; - struct tty_struct *tty; - __u16 lastBufferLength; - __u16 rxLen; - - dbg("%s", __func__); - - lastBufferLength = bufferLength + 1; - - while (bufferLength > 0) { - /* failsafe incase we get a message that we don't understand */ - if (lastBufferLength == bufferLength) { - dbg("%s - stuck in loop, exiting it.", __func__); - break; - } - lastBufferLength = bufferLength; - - switch (edge_serial->rxState) { - case EXPECT_HDR1: - edge_serial->rxHeader1 = *buffer; - ++buffer; - --bufferLength; - - if (bufferLength == 0) { - edge_serial->rxState = EXPECT_HDR2; - break; - } - /* otherwise, drop on through */ - case EXPECT_HDR2: - edge_serial->rxHeader2 = *buffer; - ++buffer; - --bufferLength; - - dbg("%s - Hdr1=%02X Hdr2=%02X", __func__, - edge_serial->rxHeader1, edge_serial->rxHeader2); - /* Process depending on whether this header is - * data or status */ - - if (IS_CMD_STAT_HDR(edge_serial->rxHeader1)) { - /* Decode this status header and go to - * EXPECT_HDR1 (if we can process the status - * with only 2 bytes), or go to EXPECT_HDR3 to - * get the third byte. */ - edge_serial->rxPort = - IOSP_GET_HDR_PORT(edge_serial->rxHeader1); - edge_serial->rxStatusCode = - IOSP_GET_STATUS_CODE( - edge_serial->rxHeader1); - - if (!IOSP_STATUS_IS_2BYTE( - edge_serial->rxStatusCode)) { - /* This status needs additional bytes. - * Save what we have and then wait for - * more data. - */ - edge_serial->rxStatusParam - = edge_serial->rxHeader2; - edge_serial->rxState = EXPECT_HDR3; - break; - } - /* We have all the header bytes, process the - status now */ - process_rcvd_status(edge_serial, - edge_serial->rxHeader2, 0); - edge_serial->rxState = EXPECT_HDR1; - break; - } else { - edge_serial->rxPort = - IOSP_GET_HDR_PORT(edge_serial->rxHeader1); - edge_serial->rxBytesRemaining = - IOSP_GET_HDR_DATA_LEN( - edge_serial->rxHeader1, - edge_serial->rxHeader2); - dbg("%s - Data for Port %u Len %u", - __func__, - edge_serial->rxPort, - edge_serial->rxBytesRemaining); - - /* ASSERT(DevExt->RxPort < DevExt->NumPorts); - * ASSERT(DevExt->RxBytesRemaining < - * IOSP_MAX_DATA_LENGTH); - */ - - if (bufferLength == 0) { - edge_serial->rxState = EXPECT_DATA; - break; - } - /* Else, drop through */ - } - case EXPECT_DATA: /* Expect data */ - if (bufferLength < edge_serial->rxBytesRemaining) { - rxLen = bufferLength; - /* Expect data to start next buffer */ - edge_serial->rxState = EXPECT_DATA; - } else { - /* BufLen >= RxBytesRemaining */ - rxLen = edge_serial->rxBytesRemaining; - /* Start another header next time */ - edge_serial->rxState = EXPECT_HDR1; - } - - bufferLength -= rxLen; - edge_serial->rxBytesRemaining -= rxLen; - - /* spit this data back into the tty driver if this - port is open */ - if (rxLen) { - port = edge_serial->serial->port[ - edge_serial->rxPort]; - edge_port = usb_get_serial_port_data(port); - if (edge_port->open) { - tty = tty_port_tty_get( - &edge_port->port->port); - if (tty) { - dbg("%s - Sending %d bytes to TTY for port %d", - __func__, rxLen, edge_serial->rxPort); - edge_tty_recv(&edge_serial->serial->dev->dev, tty, buffer, rxLen); - tty_kref_put(tty); - } - edge_port->icount.rx += rxLen; - } - buffer += rxLen; - } - break; - - case EXPECT_HDR3: /* Expect 3rd byte of status header */ - edge_serial->rxHeader3 = *buffer; - ++buffer; - --bufferLength; - - /* We have all the header bytes, process the - status now */ - process_rcvd_status(edge_serial, - edge_serial->rxStatusParam, - edge_serial->rxHeader3); - edge_serial->rxState = EXPECT_HDR1; - break; - } - } -} - - -/***************************************************************************** - * process_rcvd_status - * this function handles the any status messages received on the - * bulk in pipe. - *****************************************************************************/ -static void process_rcvd_status(struct edgeport_serial *edge_serial, - __u8 byte2, __u8 byte3) -{ - struct usb_serial_port *port; - struct edgeport_port *edge_port; - struct tty_struct *tty; - __u8 code = edge_serial->rxStatusCode; - - /* switch the port pointer to the one being currently talked about */ - port = edge_serial->serial->port[edge_serial->rxPort]; - edge_port = usb_get_serial_port_data(port); - if (edge_port == NULL) { - dev_err(&edge_serial->serial->dev->dev, - "%s - edge_port == NULL for port %d\n", - __func__, edge_serial->rxPort); - return; - } - - dbg("%s - port %d", __func__, edge_serial->rxPort); - - if (code == IOSP_EXT_STATUS) { - switch (byte2) { - case IOSP_EXT_STATUS_CHASE_RSP: - /* we want to do EXT status regardless of port - * open/closed */ - dbg("%s - Port %u EXT CHASE_RSP Data = %02x", - __func__, edge_serial->rxPort, byte3); - /* Currently, the only EXT_STATUS is Chase, so process - * here instead of one more call to one more subroutine - * If/when more EXT_STATUS, there'll be more work to do - * Also, we currently clear flag and close the port - * regardless of content of above's Byte3. - * We could choose to do something else when Byte3 says - * Timeout on Chase from Edgeport, like wait longer in - * block_until_chase_response, but for now we don't. - */ - edge_port->chaseResponsePending = false; - wake_up(&edge_port->wait_chase); - return; - - case IOSP_EXT_STATUS_RX_CHECK_RSP: - dbg("%s ========== Port %u CHECK_RSP Sequence = %02x =============", __func__, edge_serial->rxPort, byte3); - /* Port->RxCheckRsp = true; */ - return; - } - } - - if (code == IOSP_STATUS_OPEN_RSP) { - edge_port->txCredits = GET_TX_BUFFER_SIZE(byte3); - edge_port->maxTxCredits = edge_port->txCredits; - dbg("%s - Port %u Open Response Initial MSR = %02x TxBufferSize = %d", __func__, edge_serial->rxPort, byte2, edge_port->txCredits); - handle_new_msr(edge_port, byte2); - - /* send the current line settings to the port so we are - in sync with any further termios calls */ - tty = tty_port_tty_get(&edge_port->port->port); - if (tty) { - change_port_settings(tty, - edge_port, tty->termios); - tty_kref_put(tty); - } - - /* we have completed the open */ - edge_port->openPending = false; - edge_port->open = true; - wake_up(&edge_port->wait_open); - return; - } - - /* If port is closed, silently discard all rcvd status. We can - * have cases where buffered status is received AFTER the close - * port command is sent to the Edgeport. - */ - if (!edge_port->open || edge_port->closePending) - return; - - switch (code) { - /* Not currently sent by Edgeport */ - case IOSP_STATUS_LSR: - dbg("%s - Port %u LSR Status = %02x", - __func__, edge_serial->rxPort, byte2); - handle_new_lsr(edge_port, false, byte2, 0); - break; - - case IOSP_STATUS_LSR_DATA: - dbg("%s - Port %u LSR Status = %02x, Data = %02x", - __func__, edge_serial->rxPort, byte2, byte3); - /* byte2 is LSR Register */ - /* byte3 is broken data byte */ - handle_new_lsr(edge_port, true, byte2, byte3); - break; - /* - * case IOSP_EXT_4_STATUS: - * dbg("%s - Port %u LSR Status = %02x Data = %02x", - * __func__, edge_serial->rxPort, byte2, byte3); - * break; - */ - case IOSP_STATUS_MSR: - dbg("%s - Port %u MSR Status = %02x", - __func__, edge_serial->rxPort, byte2); - /* - * Process this new modem status and generate appropriate - * events, etc, based on the new status. This routine - * also saves the MSR in Port->ShadowMsr. - */ - handle_new_msr(edge_port, byte2); - break; - - default: - dbg("%s - Unrecognized IOSP status code %u", __func__, code); - break; - } -} - - -/***************************************************************************** - * edge_tty_recv - * this function passes data on to the tty flip buffer - *****************************************************************************/ -static void edge_tty_recv(struct device *dev, struct tty_struct *tty, - unsigned char *data, int length) -{ - int cnt; - - cnt = tty_insert_flip_string(tty, data, length); - if (cnt < length) { - dev_err(dev, "%s - dropping data, %d bytes lost\n", - __func__, length - cnt); - } - data += cnt; - length -= cnt; - - tty_flip_buffer_push(tty); -} - - -/***************************************************************************** - * handle_new_msr - * this function handles any change to the msr register for a port. - *****************************************************************************/ -static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr) -{ - struct async_icount *icount; - - dbg("%s %02x", __func__, newMsr); - - if (newMsr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR | - EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) { - icount = &edge_port->icount; - - /* update input line counters */ - if (newMsr & EDGEPORT_MSR_DELTA_CTS) - icount->cts++; - if (newMsr & EDGEPORT_MSR_DELTA_DSR) - icount->dsr++; - if (newMsr & EDGEPORT_MSR_DELTA_CD) - icount->dcd++; - if (newMsr & EDGEPORT_MSR_DELTA_RI) - icount->rng++; - wake_up_interruptible(&edge_port->delta_msr_wait); - } - - /* Save the new modem status */ - edge_port->shadowMSR = newMsr & 0xf0; -} - - -/***************************************************************************** - * handle_new_lsr - * this function handles any change to the lsr register for a port. - *****************************************************************************/ -static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData, - __u8 lsr, __u8 data) -{ - __u8 newLsr = (__u8) (lsr & (__u8) - (LSR_OVER_ERR | LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK)); - struct async_icount *icount; - - dbg("%s - %02x", __func__, newLsr); - - edge_port->shadowLSR = lsr; - - if (newLsr & LSR_BREAK) { - /* - * Parity and Framing errors only count if they - * occur exclusive of a break being - * received. - */ - newLsr &= (__u8)(LSR_OVER_ERR | LSR_BREAK); - } - - /* Place LSR data byte into Rx buffer */ - if (lsrData) { - struct tty_struct *tty = - tty_port_tty_get(&edge_port->port->port); - if (tty) { - edge_tty_recv(&edge_port->port->dev, tty, &data, 1); - tty_kref_put(tty); - } - } - /* update input line counters */ - icount = &edge_port->icount; - if (newLsr & LSR_BREAK) - icount->brk++; - if (newLsr & LSR_OVER_ERR) - icount->overrun++; - if (newLsr & LSR_PAR_ERR) - icount->parity++; - if (newLsr & LSR_FRM_ERR) - icount->frame++; -} - - -/**************************************************************************** - * sram_write - * writes a number of bytes to the Edgeport device's sram starting at the - * given address. - * If successful returns the number of bytes written, otherwise it returns - * a negative error number of the problem. - ****************************************************************************/ -static int sram_write(struct usb_serial *serial, __u16 extAddr, __u16 addr, - __u16 length, const __u8 *data) -{ - int result; - __u16 current_length; - unsigned char *transfer_buffer; - - dbg("%s - %x, %x, %d", __func__, extAddr, addr, length); - - transfer_buffer = kmalloc(64, GFP_KERNEL); - if (!transfer_buffer) { - dev_err(&serial->dev->dev, "%s - kmalloc(%d) failed.\n", - __func__, 64); - return -ENOMEM; - } - - /* need to split these writes up into 64 byte chunks */ - result = 0; - while (length > 0) { - if (length > 64) - current_length = 64; - else - current_length = length; - -/* dbg("%s - writing %x, %x, %d", __func__, - extAddr, addr, current_length); */ - memcpy(transfer_buffer, data, current_length); - result = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - USB_REQUEST_ION_WRITE_RAM, - 0x40, addr, extAddr, transfer_buffer, - current_length, 300); - if (result < 0) - break; - length -= current_length; - addr += current_length; - data += current_length; - } - - kfree(transfer_buffer); - return result; -} - - -/**************************************************************************** - * rom_write - * writes a number of bytes to the Edgeport device's ROM starting at the - * given address. - * If successful returns the number of bytes written, otherwise it returns - * a negative error number of the problem. - ****************************************************************************/ -static int rom_write(struct usb_serial *serial, __u16 extAddr, __u16 addr, - __u16 length, const __u8 *data) -{ - int result; - __u16 current_length; - unsigned char *transfer_buffer; - -/* dbg("%s - %x, %x, %d", __func__, extAddr, addr, length); */ - - transfer_buffer = kmalloc(64, GFP_KERNEL); - if (!transfer_buffer) { - dev_err(&serial->dev->dev, "%s - kmalloc(%d) failed.\n", - __func__, 64); - return -ENOMEM; - } - - /* need to split these writes up into 64 byte chunks */ - result = 0; - while (length > 0) { - if (length > 64) - current_length = 64; - else - current_length = length; -/* dbg("%s - writing %x, %x, %d", __func__, - extAddr, addr, current_length); */ - memcpy(transfer_buffer, data, current_length); - result = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - USB_REQUEST_ION_WRITE_ROM, 0x40, - addr, extAddr, - transfer_buffer, current_length, 300); - if (result < 0) - break; - length -= current_length; - addr += current_length; - data += current_length; - } - - kfree(transfer_buffer); - return result; -} - - -/**************************************************************************** - * rom_read - * reads a number of bytes from the Edgeport device starting at the given - * address. - * If successful returns the number of bytes read, otherwise it returns - * a negative error number of the problem. - ****************************************************************************/ -static int rom_read(struct usb_serial *serial, __u16 extAddr, - __u16 addr, __u16 length, __u8 *data) -{ - int result; - __u16 current_length; - unsigned char *transfer_buffer; - - dbg("%s - %x, %x, %d", __func__, extAddr, addr, length); - - transfer_buffer = kmalloc(64, GFP_KERNEL); - if (!transfer_buffer) { - dev_err(&serial->dev->dev, - "%s - kmalloc(%d) failed.\n", __func__, 64); - return -ENOMEM; - } - - /* need to split these reads up into 64 byte chunks */ - result = 0; - while (length > 0) { - if (length > 64) - current_length = 64; - else - current_length = length; -/* dbg("%s - %x, %x, %d", __func__, - extAddr, addr, current_length); */ - result = usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), - USB_REQUEST_ION_READ_ROM, - 0xC0, addr, extAddr, transfer_buffer, - current_length, 300); - if (result < 0) - break; - memcpy(data, transfer_buffer, current_length); - length -= current_length; - addr += current_length; - data += current_length; - } - - kfree(transfer_buffer); - return result; -} - - -/**************************************************************************** - * send_iosp_ext_cmd - * Is used to send a IOSP message to the Edgeport device - ****************************************************************************/ -static int send_iosp_ext_cmd(struct edgeport_port *edge_port, - __u8 command, __u8 param) -{ - unsigned char *buffer; - unsigned char *currentCommand; - int length = 0; - int status = 0; - - dbg("%s - %d, %d", __func__, command, param); - - buffer = kmalloc(10, GFP_ATOMIC); - if (!buffer) { - dev_err(&edge_port->port->dev, - "%s - kmalloc(%d) failed.\n", __func__, 10); - return -ENOMEM; - } - - currentCommand = buffer; - - MAKE_CMD_EXT_CMD(¤tCommand, &length, - edge_port->port->number - edge_port->port->serial->minor, - command, param); - - status = write_cmd_usb(edge_port, buffer, length); - if (status) { - /* something bad happened, let's free up the memory */ - kfree(buffer); - } - - return status; -} - - -/***************************************************************************** - * write_cmd_usb - * this function writes the given buffer out to the bulk write endpoint. - *****************************************************************************/ -static int write_cmd_usb(struct edgeport_port *edge_port, - unsigned char *buffer, int length) -{ - struct edgeport_serial *edge_serial = - usb_get_serial_data(edge_port->port->serial); - int status = 0; - struct urb *urb; - - usb_serial_debug_data(debug, &edge_port->port->dev, - __func__, length, buffer); - - /* Allocate our next urb */ - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) - return -ENOMEM; - - atomic_inc(&CmdUrbs); - dbg("%s - ALLOCATE URB %p (outstanding %d)", - __func__, urb, atomic_read(&CmdUrbs)); - - usb_fill_bulk_urb(urb, edge_serial->serial->dev, - usb_sndbulkpipe(edge_serial->serial->dev, - edge_serial->bulk_out_endpoint), - buffer, length, edge_bulk_out_cmd_callback, edge_port); - - edge_port->commandPending = true; - status = usb_submit_urb(urb, GFP_ATOMIC); - - if (status) { - /* something went wrong */ - dev_err(&edge_port->port->dev, - "%s - usb_submit_urb(write command) failed, status = %d\n", - __func__, status); - usb_kill_urb(urb); - usb_free_urb(urb); - atomic_dec(&CmdUrbs); - return status; - } - -#if 0 - wait_event(&edge_port->wait_command, !edge_port->commandPending); - - if (edge_port->commandPending) { - /* command timed out */ - dbg("%s - command timed out", __func__); - status = -EINVAL; - } -#endif - return status; -} - - -/***************************************************************************** - * send_cmd_write_baud_rate - * this function sends the proper command to change the baud rate of the - * specified port. - *****************************************************************************/ -static int send_cmd_write_baud_rate(struct edgeport_port *edge_port, - int baudRate) -{ - struct edgeport_serial *edge_serial = - usb_get_serial_data(edge_port->port->serial); - unsigned char *cmdBuffer; - unsigned char *currCmd; - int cmdLen = 0; - int divisor; - int status; - unsigned char number = - edge_port->port->number - edge_port->port->serial->minor; - - if (edge_serial->is_epic && - !edge_serial->epic_descriptor.Supports.IOSPSetBaudRate) { - dbg("SendCmdWriteBaudRate - NOT Setting baud rate for port = %d, baud = %d", - edge_port->port->number, baudRate); - return 0; - } - - dbg("%s - port = %d, baud = %d", __func__, - edge_port->port->number, baudRate); - - status = calc_baud_rate_divisor(baudRate, &divisor); - if (status) { - dev_err(&edge_port->port->dev, "%s - bad baud rate\n", - __func__); - return status; - } - - /* Alloc memory for the string of commands. */ - cmdBuffer = kmalloc(0x100, GFP_ATOMIC); - if (!cmdBuffer) { - dev_err(&edge_port->port->dev, - "%s - kmalloc(%d) failed.\n", __func__, 0x100); - return -ENOMEM; - } - currCmd = cmdBuffer; - - /* Enable access to divisor latch */ - MAKE_CMD_WRITE_REG(&currCmd, &cmdLen, number, LCR, LCR_DL_ENABLE); - - /* Write the divisor itself */ - MAKE_CMD_WRITE_REG(&currCmd, &cmdLen, number, DLL, LOW8(divisor)); - MAKE_CMD_WRITE_REG(&currCmd, &cmdLen, number, DLM, HIGH8(divisor)); - - /* Restore original value to disable access to divisor latch */ - MAKE_CMD_WRITE_REG(&currCmd, &cmdLen, number, LCR, - edge_port->shadowLCR); - - status = write_cmd_usb(edge_port, cmdBuffer, cmdLen); - if (status) { - /* something bad happened, let's free up the memory */ - kfree(cmdBuffer); - } - - return status; -} - - -/***************************************************************************** - * calc_baud_rate_divisor - * this function calculates the proper baud rate divisor for the specified - * baud rate. - *****************************************************************************/ -static int calc_baud_rate_divisor(int baudrate, int *divisor) -{ - int i; - __u16 custom; - - - dbg("%s - %d", __func__, baudrate); - - for (i = 0; i < ARRAY_SIZE(divisor_table); i++) { - if (divisor_table[i].BaudRate == baudrate) { - *divisor = divisor_table[i].Divisor; - return 0; - } - } - - /* We have tried all of the standard baud rates - * lets try to calculate the divisor for this baud rate - * Make sure the baud rate is reasonable */ - if (baudrate > 50 && baudrate < 230400) { - /* get divisor */ - custom = (__u16)((230400L + baudrate/2) / baudrate); - - *divisor = custom; - - dbg("%s - Baud %d = %d", __func__, baudrate, custom); - return 0; - } - - return -1; -} - - -/***************************************************************************** - * send_cmd_write_uart_register - * this function builds up a uart register message and sends to the device. - *****************************************************************************/ -static int send_cmd_write_uart_register(struct edgeport_port *edge_port, - __u8 regNum, __u8 regValue) -{ - struct edgeport_serial *edge_serial = - usb_get_serial_data(edge_port->port->serial); - unsigned char *cmdBuffer; - unsigned char *currCmd; - unsigned long cmdLen = 0; - int status; - - dbg("%s - write to %s register 0x%02x", - (regNum == MCR) ? "MCR" : "LCR", __func__, regValue); - - if (edge_serial->is_epic && - !edge_serial->epic_descriptor.Supports.IOSPWriteMCR && - regNum == MCR) { - dbg("SendCmdWriteUartReg - Not writing to MCR Register"); - return 0; - } - - if (edge_serial->is_epic && - !edge_serial->epic_descriptor.Supports.IOSPWriteLCR && - regNum == LCR) { - dbg("SendCmdWriteUartReg - Not writing to LCR Register"); - return 0; - } - - /* Alloc memory for the string of commands. */ - cmdBuffer = kmalloc(0x10, GFP_ATOMIC); - if (cmdBuffer == NULL) - return -ENOMEM; - - currCmd = cmdBuffer; - - /* Build a cmd in the buffer to write the given register */ - MAKE_CMD_WRITE_REG(&currCmd, &cmdLen, - edge_port->port->number - edge_port->port->serial->minor, - regNum, regValue); - - status = write_cmd_usb(edge_port, cmdBuffer, cmdLen); - if (status) { - /* something bad happened, let's free up the memory */ - kfree(cmdBuffer); - } - - return status; -} - - -/***************************************************************************** - * change_port_settings - * This routine is called to set the UART on the device to match the - * specified new settings. - *****************************************************************************/ - -static void change_port_settings(struct tty_struct *tty, - struct edgeport_port *edge_port, struct ktermios *old_termios) -{ - struct edgeport_serial *edge_serial = - usb_get_serial_data(edge_port->port->serial); - int baud; - unsigned cflag; - __u8 mask = 0xff; - __u8 lData; - __u8 lParity; - __u8 lStop; - __u8 rxFlow; - __u8 txFlow; - int status; - - dbg("%s - port %d", __func__, edge_port->port->number); - - if (!edge_port->open && - !edge_port->openPending) { - dbg("%s - port not opened", __func__); - return; - } - - cflag = tty->termios->c_cflag; - - switch (cflag & CSIZE) { - case CS5: - lData = LCR_BITS_5; mask = 0x1f; - dbg("%s - data bits = 5", __func__); - break; - case CS6: - lData = LCR_BITS_6; mask = 0x3f; - dbg("%s - data bits = 6", __func__); - break; - case CS7: - lData = LCR_BITS_7; mask = 0x7f; - dbg("%s - data bits = 7", __func__); - break; - default: - case CS8: - lData = LCR_BITS_8; - dbg("%s - data bits = 8", __func__); - break; - } - - lParity = LCR_PAR_NONE; - if (cflag & PARENB) { - if (cflag & CMSPAR) { - if (cflag & PARODD) { - lParity = LCR_PAR_MARK; - dbg("%s - parity = mark", __func__); - } else { - lParity = LCR_PAR_SPACE; - dbg("%s - parity = space", __func__); - } - } else if (cflag & PARODD) { - lParity = LCR_PAR_ODD; - dbg("%s - parity = odd", __func__); - } else { - lParity = LCR_PAR_EVEN; - dbg("%s - parity = even", __func__); - } - } else { - dbg("%s - parity = none", __func__); - } - - if (cflag & CSTOPB) { - lStop = LCR_STOP_2; - dbg("%s - stop bits = 2", __func__); - } else { - lStop = LCR_STOP_1; - dbg("%s - stop bits = 1", __func__); - } - - /* figure out the flow control settings */ - rxFlow = txFlow = 0x00; - if (cflag & CRTSCTS) { - rxFlow |= IOSP_RX_FLOW_RTS; - txFlow |= IOSP_TX_FLOW_CTS; - dbg("%s - RTS/CTS is enabled", __func__); - } else { - dbg("%s - RTS/CTS is disabled", __func__); - } - - /* if we are implementing XON/XOFF, set the start and stop character - in the device */ - if (I_IXOFF(tty) || I_IXON(tty)) { - unsigned char stop_char = STOP_CHAR(tty); - unsigned char start_char = START_CHAR(tty); - - if ((!edge_serial->is_epic) || - ((edge_serial->is_epic) && - (edge_serial->epic_descriptor.Supports.IOSPSetXChar))) { - send_iosp_ext_cmd(edge_port, - IOSP_CMD_SET_XON_CHAR, start_char); - send_iosp_ext_cmd(edge_port, - IOSP_CMD_SET_XOFF_CHAR, stop_char); - } - - /* if we are implementing INBOUND XON/XOFF */ - if (I_IXOFF(tty)) { - rxFlow |= IOSP_RX_FLOW_XON_XOFF; - dbg("%s - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", - __func__, start_char, stop_char); - } else { - dbg("%s - INBOUND XON/XOFF is disabled", __func__); - } - - /* if we are implementing OUTBOUND XON/XOFF */ - if (I_IXON(tty)) { - txFlow |= IOSP_TX_FLOW_XON_XOFF; - dbg("%s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", - __func__, start_char, stop_char); - } else { - dbg("%s - OUTBOUND XON/XOFF is disabled", __func__); - } - } - - /* Set flow control to the configured value */ - if ((!edge_serial->is_epic) || - ((edge_serial->is_epic) && - (edge_serial->epic_descriptor.Supports.IOSPSetRxFlow))) - send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow); - if ((!edge_serial->is_epic) || - ((edge_serial->is_epic) && - (edge_serial->epic_descriptor.Supports.IOSPSetTxFlow))) - send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_TX_FLOW, txFlow); - - - edge_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK); - edge_port->shadowLCR |= (lData | lParity | lStop); - - edge_port->validDataMask = mask; - - /* Send the updated LCR value to the EdgePort */ - status = send_cmd_write_uart_register(edge_port, LCR, - edge_port->shadowLCR); - if (status != 0) - return; - - /* set up the MCR register and send it to the EdgePort */ - edge_port->shadowMCR = MCR_MASTER_IE; - if (cflag & CBAUD) - edge_port->shadowMCR |= (MCR_DTR | MCR_RTS); - - status = send_cmd_write_uart_register(edge_port, MCR, - edge_port->shadowMCR); - if (status != 0) - return; - - /* Determine divisor based on baud rate */ - baud = tty_get_baud_rate(tty); - if (!baud) { - /* pick a default, any default... */ - baud = 9600; - } - - dbg("%s - baud rate = %d", __func__, baud); - status = send_cmd_write_baud_rate(edge_port, baud); - if (status == -1) { - /* Speed change was not possible - put back the old speed */ - baud = tty_termios_baud_rate(old_termios); - tty_encode_baud_rate(tty, baud, baud); - } -} - - -/**************************************************************************** - * unicode_to_ascii - * Turns a string from Unicode into ASCII. - * Doesn't do a good job with any characters that are outside the normal - * ASCII range, but it's only for debugging... - * NOTE: expects the unicode in LE format - ****************************************************************************/ -static void unicode_to_ascii(char *string, int buflen, - __le16 *unicode, int unicode_size) -{ - int i; - - if (buflen <= 0) /* never happens, but... */ - return; - --buflen; /* space for nul */ - - for (i = 0; i < unicode_size; i++) { - if (i >= buflen) - break; - string[i] = (char)(le16_to_cpu(unicode[i])); - } - string[i] = 0x00; -} - - -/**************************************************************************** - * get_manufacturing_desc - * reads in the manufacturing descriptor and stores it into the serial - * structure. - ****************************************************************************/ -static void get_manufacturing_desc(struct edgeport_serial *edge_serial) -{ - int response; - - dbg("getting manufacturer descriptor"); - - response = rom_read(edge_serial->serial, - (EDGE_MANUF_DESC_ADDR & 0xffff0000) >> 16, - (__u16)(EDGE_MANUF_DESC_ADDR & 0x0000ffff), - EDGE_MANUF_DESC_LEN, - (__u8 *)(&edge_serial->manuf_descriptor)); - - if (response < 1) - dev_err(&edge_serial->serial->dev->dev, - "error in getting manufacturer descriptor\n"); - else { - char string[30]; - dbg("**Manufacturer Descriptor"); - dbg(" RomSize: %dK", - edge_serial->manuf_descriptor.RomSize); - dbg(" RamSize: %dK", - edge_serial->manuf_descriptor.RamSize); - dbg(" CpuRev: %d", - edge_serial->manuf_descriptor.CpuRev); - dbg(" BoardRev: %d", - edge_serial->manuf_descriptor.BoardRev); - dbg(" NumPorts: %d", - edge_serial->manuf_descriptor.NumPorts); - dbg(" DescDate: %d/%d/%d", - edge_serial->manuf_descriptor.DescDate[0], - edge_serial->manuf_descriptor.DescDate[1], - edge_serial->manuf_descriptor.DescDate[2]+1900); - unicode_to_ascii(string, sizeof(string), - edge_serial->manuf_descriptor.SerialNumber, - edge_serial->manuf_descriptor.SerNumLength/2); - dbg(" SerialNumber: %s", string); - unicode_to_ascii(string, sizeof(string), - edge_serial->manuf_descriptor.AssemblyNumber, - edge_serial->manuf_descriptor.AssemblyNumLength/2); - dbg(" AssemblyNumber: %s", string); - unicode_to_ascii(string, sizeof(string), - edge_serial->manuf_descriptor.OemAssyNumber, - edge_serial->manuf_descriptor.OemAssyNumLength/2); - dbg(" OemAssyNumber: %s", string); - dbg(" UartType: %d", - edge_serial->manuf_descriptor.UartType); - dbg(" IonPid: %d", - edge_serial->manuf_descriptor.IonPid); - dbg(" IonConfig: %d", - edge_serial->manuf_descriptor.IonConfig); - } -} - - -/**************************************************************************** - * get_boot_desc - * reads in the bootloader descriptor and stores it into the serial - * structure. - ****************************************************************************/ -static void get_boot_desc(struct edgeport_serial *edge_serial) -{ - int response; - - dbg("getting boot descriptor"); - - response = rom_read(edge_serial->serial, - (EDGE_BOOT_DESC_ADDR & 0xffff0000) >> 16, - (__u16)(EDGE_BOOT_DESC_ADDR & 0x0000ffff), - EDGE_BOOT_DESC_LEN, - (__u8 *)(&edge_serial->boot_descriptor)); - - if (response < 1) - dev_err(&edge_serial->serial->dev->dev, - "error in getting boot descriptor\n"); - else { - dbg("**Boot Descriptor:"); - dbg(" BootCodeLength: %d", - le16_to_cpu(edge_serial->boot_descriptor.BootCodeLength)); - dbg(" MajorVersion: %d", - edge_serial->boot_descriptor.MajorVersion); - dbg(" MinorVersion: %d", - edge_serial->boot_descriptor.MinorVersion); - dbg(" BuildNumber: %d", - le16_to_cpu(edge_serial->boot_descriptor.BuildNumber)); - dbg(" Capabilities: 0x%x", - le16_to_cpu(edge_serial->boot_descriptor.Capabilities)); - dbg(" UConfig0: %d", - edge_serial->boot_descriptor.UConfig0); - dbg(" UConfig1: %d", - edge_serial->boot_descriptor.UConfig1); - } -} - - -/**************************************************************************** - * load_application_firmware - * This is called to load the application firmware to the device - ****************************************************************************/ -static void load_application_firmware(struct edgeport_serial *edge_serial) -{ - const struct ihex_binrec *rec; - const struct firmware *fw; - const char *fw_name; - const char *fw_info; - int response; - __u32 Operaddr; - __u16 build; - - switch (edge_serial->product_info.iDownloadFile) { - case EDGE_DOWNLOAD_FILE_I930: - fw_info = "downloading firmware version (930)"; - fw_name = "edgeport/down.fw"; - break; - - case EDGE_DOWNLOAD_FILE_80251: - fw_info = "downloading firmware version (80251)"; - fw_name = "edgeport/down2.fw"; - break; - - case EDGE_DOWNLOAD_FILE_NONE: - dbg("No download file specified, skipping download"); - return; - - default: - return; - } - - response = request_ihex_firmware(&fw, fw_name, - &edge_serial->serial->dev->dev); - if (response) { - printk(KERN_ERR "Failed to load image \"%s\" err %d\n", - fw_name, response); - return; - } - - rec = (const struct ihex_binrec *)fw->data; - build = (rec->data[2] << 8) | rec->data[3]; - - dbg("%s %d.%d.%d", fw_info, rec->data[0], rec->data[1], build); - - edge_serial->product_info.FirmwareMajorVersion = rec->data[0]; - edge_serial->product_info.FirmwareMinorVersion = rec->data[1]; - edge_serial->product_info.FirmwareBuildNumber = cpu_to_le16(build); - - for (rec = ihex_next_binrec(rec); rec; - rec = ihex_next_binrec(rec)) { - Operaddr = be32_to_cpu(rec->addr); - response = sram_write(edge_serial->serial, - Operaddr >> 16, - Operaddr & 0xFFFF, - be16_to_cpu(rec->len), - &rec->data[0]); - if (response < 0) { - dev_err(&edge_serial->serial->dev->dev, - "sram_write failed (%x, %x, %d)\n", - Operaddr >> 16, Operaddr & 0xFFFF, - be16_to_cpu(rec->len)); - break; - } - } - - dbg("sending exec_dl_code"); - response = usb_control_msg (edge_serial->serial->dev, - usb_sndctrlpipe(edge_serial->serial->dev, 0), - USB_REQUEST_ION_EXEC_DL_CODE, - 0x40, 0x4000, 0x0001, NULL, 0, 3000); - - release_firmware(fw); -} - - -/**************************************************************************** - * edge_startup - ****************************************************************************/ -static int edge_startup(struct usb_serial *serial) -{ - struct edgeport_serial *edge_serial; - struct edgeport_port *edge_port; - struct usb_device *dev; - int i, j; - int response; - bool interrupt_in_found; - bool bulk_in_found; - bool bulk_out_found; - static __u32 descriptor[3] = { EDGE_COMPATIBILITY_MASK0, - EDGE_COMPATIBILITY_MASK1, - EDGE_COMPATIBILITY_MASK2 }; - - dev = serial->dev; - - /* create our private serial structure */ - edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL); - if (edge_serial == NULL) { - dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__); - return -ENOMEM; - } - spin_lock_init(&edge_serial->es_lock); - edge_serial->serial = serial; - usb_set_serial_data(serial, edge_serial); - - /* get the name for the device from the device */ - i = usb_string(dev, dev->descriptor.iManufacturer, - &edge_serial->name[0], MAX_NAME_LEN+1); - if (i < 0) - i = 0; - edge_serial->name[i++] = ' '; - usb_string(dev, dev->descriptor.iProduct, - &edge_serial->name[i], MAX_NAME_LEN+2 - i); - - dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name); - - /* Read the epic descriptor */ - if (get_epic_descriptor(edge_serial) <= 0) { - /* memcpy descriptor to Supports structures */ - memcpy(&edge_serial->epic_descriptor.Supports, descriptor, - sizeof(struct edge_compatibility_bits)); - - /* get the manufacturing descriptor for this device */ - get_manufacturing_desc(edge_serial); - - /* get the boot descriptor */ - get_boot_desc(edge_serial); - - get_product_info(edge_serial); - } - - /* set the number of ports from the manufacturing description */ - /* serial->num_ports = serial->product_info.NumPorts; */ - if ((!edge_serial->is_epic) && - (edge_serial->product_info.NumPorts != serial->num_ports)) { - dev_warn(&serial->dev->dev, "Device Reported %d serial ports " - "vs. core thinking we have %d ports, email " - "greg@kroah.com this information.\n", - edge_serial->product_info.NumPorts, - serial->num_ports); - } - - dbg("%s - time 1 %ld", __func__, jiffies); - - /* If not an EPiC device */ - if (!edge_serial->is_epic) { - /* now load the application firmware into this device */ - load_application_firmware(edge_serial); - - dbg("%s - time 2 %ld", __func__, jiffies); - - /* Check current Edgeport EEPROM and update if necessary */ - update_edgeport_E2PROM(edge_serial); - - dbg("%s - time 3 %ld", __func__, jiffies); - - /* set the configuration to use #1 */ -/* dbg("set_configuration 1"); */ -/* usb_set_configuration (dev, 1); */ - } - dbg(" FirmwareMajorVersion %d.%d.%d", - edge_serial->product_info.FirmwareMajorVersion, - edge_serial->product_info.FirmwareMinorVersion, - le16_to_cpu(edge_serial->product_info.FirmwareBuildNumber)); - - /* we set up the pointers to the endpoints in the edge_open function, - * as the structures aren't created yet. */ - - /* set up our port private structures */ - for (i = 0; i < serial->num_ports; ++i) { - edge_port = kzalloc(sizeof(struct edgeport_port), GFP_KERNEL); - if (edge_port == NULL) { - dev_err(&serial->dev->dev, "%s - Out of memory\n", - __func__); - for (j = 0; j < i; ++j) { - kfree(usb_get_serial_port_data(serial->port[j])); - usb_set_serial_port_data(serial->port[j], - NULL); - } - usb_set_serial_data(serial, NULL); - kfree(edge_serial); - return -ENOMEM; - } - spin_lock_init(&edge_port->ep_lock); - edge_port->port = serial->port[i]; - usb_set_serial_port_data(serial->port[i], edge_port); - } - - response = 0; - - if (edge_serial->is_epic) { - /* EPIC thing, set up our interrupt polling now and our read - * urb, so that the device knows it really is connected. */ - interrupt_in_found = bulk_in_found = bulk_out_found = false; - for (i = 0; i < serial->interface->altsetting[0] - .desc.bNumEndpoints; ++i) { - struct usb_endpoint_descriptor *endpoint; - int buffer_size; - - endpoint = &serial->interface->altsetting[0]. - endpoint[i].desc; - buffer_size = usb_endpoint_maxp(endpoint); - if (!interrupt_in_found && - (usb_endpoint_is_int_in(endpoint))) { - /* we found a interrupt in endpoint */ - dbg("found interrupt in"); - - /* not set up yet, so do it now */ - edge_serial->interrupt_read_urb = - usb_alloc_urb(0, GFP_KERNEL); - if (!edge_serial->interrupt_read_urb) { - dev_err(&dev->dev, "out of memory\n"); - return -ENOMEM; - } - edge_serial->interrupt_in_buffer = - kmalloc(buffer_size, GFP_KERNEL); - if (!edge_serial->interrupt_in_buffer) { - dev_err(&dev->dev, "out of memory\n"); - usb_free_urb(edge_serial->interrupt_read_urb); - return -ENOMEM; - } - edge_serial->interrupt_in_endpoint = - endpoint->bEndpointAddress; - - /* set up our interrupt urb */ - usb_fill_int_urb( - edge_serial->interrupt_read_urb, - dev, - usb_rcvintpipe(dev, - endpoint->bEndpointAddress), - edge_serial->interrupt_in_buffer, - buffer_size, - edge_interrupt_callback, - edge_serial, - endpoint->bInterval); - - interrupt_in_found = true; - } - - if (!bulk_in_found && - (usb_endpoint_is_bulk_in(endpoint))) { - /* we found a bulk in endpoint */ - dbg("found bulk in"); - - /* not set up yet, so do it now */ - edge_serial->read_urb = - usb_alloc_urb(0, GFP_KERNEL); - if (!edge_serial->read_urb) { - dev_err(&dev->dev, "out of memory\n"); - return -ENOMEM; - } - edge_serial->bulk_in_buffer = - kmalloc(buffer_size, GFP_KERNEL); - if (!edge_serial->bulk_in_buffer) { - dev_err(&dev->dev, "out of memory\n"); - usb_free_urb(edge_serial->read_urb); - return -ENOMEM; - } - edge_serial->bulk_in_endpoint = - endpoint->bEndpointAddress; - - /* set up our bulk in urb */ - usb_fill_bulk_urb(edge_serial->read_urb, dev, - usb_rcvbulkpipe(dev, - endpoint->bEndpointAddress), - edge_serial->bulk_in_buffer, - usb_endpoint_maxp(endpoint), - edge_bulk_in_callback, - edge_serial); - bulk_in_found = true; - } - - if (!bulk_out_found && - (usb_endpoint_is_bulk_out(endpoint))) { - /* we found a bulk out endpoint */ - dbg("found bulk out"); - edge_serial->bulk_out_endpoint = - endpoint->bEndpointAddress; - bulk_out_found = true; - } - } - - if (!interrupt_in_found || !bulk_in_found || !bulk_out_found) { - dev_err(&dev->dev, "Error - the proper endpoints " - "were not found!\n"); - return -ENODEV; - } - - /* start interrupt read for this edgeport this interrupt will - * continue as long as the edgeport is connected */ - response = usb_submit_urb(edge_serial->interrupt_read_urb, - GFP_KERNEL); - if (response) - dev_err(&dev->dev, - "%s - Error %d submitting control urb\n", - __func__, response); - } - return response; -} - - -/**************************************************************************** - * edge_disconnect - * This function is called whenever the device is removed from the usb bus. - ****************************************************************************/ -static void edge_disconnect(struct usb_serial *serial) -{ - struct edgeport_serial *edge_serial = usb_get_serial_data(serial); - - dbg("%s", __func__); - - /* stop reads and writes on all ports */ - /* free up our endpoint stuff */ - if (edge_serial->is_epic) { - usb_kill_urb(edge_serial->interrupt_read_urb); - usb_free_urb(edge_serial->interrupt_read_urb); - kfree(edge_serial->interrupt_in_buffer); - - usb_kill_urb(edge_serial->read_urb); - usb_free_urb(edge_serial->read_urb); - kfree(edge_serial->bulk_in_buffer); - } -} - - -/**************************************************************************** - * edge_release - * This function is called when the device structure is deallocated. - ****************************************************************************/ -static void edge_release(struct usb_serial *serial) -{ - struct edgeport_serial *edge_serial = usb_get_serial_data(serial); - int i; - - dbg("%s", __func__); - - for (i = 0; i < serial->num_ports; ++i) - kfree(usb_get_serial_port_data(serial->port[i])); - - kfree(edge_serial); -} - -module_usb_serial_driver(io_driver, serial_drivers); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE("edgeport/boot.fw"); -MODULE_FIRMWARE("edgeport/boot2.fw"); -MODULE_FIRMWARE("edgeport/down.fw"); -MODULE_FIRMWARE("edgeport/down2.fw"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/io_edgeport.h b/ANDROID_3.4.5/drivers/usb/serial/io_edgeport.h deleted file mode 100644 index ad9c1d47..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/io_edgeport.h +++ /dev/null @@ -1,134 +0,0 @@ -/************************************************************************ - * - * io_edgeport.h Edgeport Linux Interface definitions - * - * Copyright (C) 2000 Inside Out Networks, Inc. - * - * 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. - * - * - ************************************************************************/ - -#if !defined(_IO_EDGEPORT_H_) -#define _IO_EDGEPORT_H_ - - -#define MAX_RS232_PORTS 8 /* Max # of RS-232 ports per device */ - -/* typedefs that the insideout headers need */ -#ifndef LOW8 - #define LOW8(a) ((unsigned char)(a & 0xff)) -#endif -#ifndef HIGH8 - #define HIGH8(a) ((unsigned char)((a & 0xff00) >> 8)) -#endif - -#ifndef __KERNEL__ -#define __KERNEL__ -#endif - -#include "io_usbvend.h" - - - -/* The following table is used to map the USBx port number to - * the device serial number (or physical USB path), */ -#define MAX_EDGEPORTS 64 - -struct comMapper { - char SerialNumber[MAX_SERIALNUMBER_LEN+1]; /* Serial number/usb path */ - int numPorts; /* Number of ports */ - int Original[MAX_RS232_PORTS]; /* Port numbers set by IOCTL */ - int Port[MAX_RS232_PORTS]; /* Actual used port numbers */ -}; - - -#define EDGEPORT_CONFIG_DEVICE "/proc/edgeport" - -/* /proc/edgeport Interface - * This interface uses read/write/lseek interface to talk to the edgeport driver - * the following read functions are supported: */ -#define PROC_GET_MAPPING_TO_PATH 1 -#define PROC_GET_COM_ENTRY 2 -#define PROC_GET_EDGE_MANUF_DESCRIPTOR 3 -#define PROC_GET_BOOT_DESCRIPTOR 4 -#define PROC_GET_PRODUCT_INFO 5 -#define PROC_GET_STRINGS 6 -#define PROC_GET_CURRENT_COM_MAPPING 7 - -/* The parameters to the lseek() for the read is: */ -#define PROC_READ_SETUP(Command, Argument) ((Command) + ((Argument)<<8)) - - -/* the following write functions are supported: */ -#define PROC_SET_COM_MAPPING 1 -#define PROC_SET_COM_ENTRY 2 - - -/* The following structure is passed to the write */ -struct procWrite { - int Command; - union { - struct comMapper Entry; - int ComMappingBasedOnUSBPort; /* Boolean value */ - } u; -}; - -/* - * Product information read from the Edgeport - */ -struct edgeport_product_info { - __u16 ProductId; /* Product Identifier */ - __u8 NumPorts; /* Number of ports on edgeport */ - __u8 ProdInfoVer; /* What version of structure is this? */ - - __u32 IsServer :1; /* Set if Server */ - __u32 IsRS232 :1; /* Set if RS-232 ports exist */ - __u32 IsRS422 :1; /* Set if RS-422 ports exist */ - __u32 IsRS485 :1; /* Set if RS-485 ports exist */ - __u32 IsReserved :28; /* Reserved for later expansion */ - - __u8 RomSize; /* Size of ROM/E2PROM in K */ - __u8 RamSize; /* Size of external RAM in K */ - __u8 CpuRev; /* CPU revision level (chg only if s/w visible) */ - __u8 BoardRev; /* PCB revision level (chg only if s/w visible) */ - - __u8 BootMajorVersion; /* Boot Firmware version: xx. */ - __u8 BootMinorVersion; /* yy. */ - __le16 BootBuildNumber; /* zzzz (LE format) */ - - __u8 FirmwareMajorVersion; /* Operational Firmware version:xx. */ - __u8 FirmwareMinorVersion; /* yy. */ - __le16 FirmwareBuildNumber; /* zzzz (LE format) */ - - __u8 ManufactureDescDate[3]; /* MM/DD/YY when descriptor template was compiled */ - __u8 HardwareType; - - __u8 iDownloadFile; /* What to download to EPiC device */ - __u8 EpicVer; /* What version of EPiC spec this device supports */ - - struct edge_compatibility_bits Epic; -}; - -/* - * Edgeport Stringblock String locations - */ -#define EDGESTRING_MANUFNAME 1 /* Manufacture Name */ -#define EDGESTRING_PRODNAME 2 /* Product Name */ -#define EDGESTRING_SERIALNUM 3 /* Serial Number */ -#define EDGESTRING_ASSEMNUM 4 /* Assembly Number */ -#define EDGESTRING_OEMASSEMNUM 5 /* OEM Assembly Number */ -#define EDGESTRING_MANUFDATE 6 /* Manufacture Date */ -#define EDGESTRING_ORIGSERIALNUM 7 /* Serial Number */ - -struct string_block { - __u16 NumStrings; /* Number of strings in block */ - __u16 Strings[1]; /* Start of string block */ -}; - - - -#endif diff --git a/ANDROID_3.4.5/drivers/usb/serial/io_ionsp.h b/ANDROID_3.4.5/drivers/usb/serial/io_ionsp.h deleted file mode 100644 index 5cc591ba..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/io_ionsp.h +++ /dev/null @@ -1,455 +0,0 @@ -/************************************************************************ - * - * IONSP.H Definitions for I/O Networks Serial Protocol - * - * Copyright (C) 1997-1998 Inside Out Networks, Inc. - * - * 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. - * - * These definitions are used by both kernel-mode driver and the - * peripheral firmware and MUST be kept in sync. - * - ************************************************************************/ - -/************************************************************************ - -The data to and from all ports on the peripheral is multiplexed -through a single endpoint pair (EP1 since it supports 64-byte -MaxPacketSize). Therefore, the data, commands, and status for -each port must be preceded by a short header identifying the -destination port. The header also identifies the bytes that follow -as data or as command/status info. - -Header format, first byte: - - CLLLLPPP - -------- - | | |------ Port Number: 0-7 - | |--------- Length: MSB bits of length - |----------- Data/Command: 0 = Data header - 1 = Cmd / Status (Cmd if OUT, Status if IN) - -This gives 2 possible formats: - - - Data header: 0LLLLPPP LLLLLLLL - ============ - - Where (LLLL,LLLLLLL) is 12-bit length of data that follows for - port number (PPP). The length is 0-based (0-FFF means 0-4095 - bytes). The ~4K limit allows the host driver (which deals in - transfer requests instead of individual packets) to write a - large chunk of data in a single request. Note, however, that - the length must always be <= the current TxCredits for a given - port due to buffering limitations on the peripheral. - - - Cmd/Status header: 1ccccPPP [ CCCCCCCC, Params ]... - ================== - - Where (cccc) or (cccc,CCCCCCCC) is the cmd or status identifier. - Frequently-used values are encoded as (cccc), longer ones using - (cccc,CCCCCCCC). Subsequent bytes are optional parameters and are - specific to the cmd or status code. This may include a length - for command and status codes that need variable-length parameters. - - -In addition, we use another interrupt pipe (endpoint) which the host polls -periodically for flow control information. The peripheral, when there has -been a change, sends the following 10-byte packet: - - RRRRRRRRRRRRRRRR - T0T0T0T0T0T0T0T0 - T1T1T1T1T1T1T1T1 - T2T2T2T2T2T2T2T2 - T3T3T3T3T3T3T3T3 - -The first field is the 16-bit RxBytesAvail field, which indicates the -number of bytes which may be read by the host from EP1. This is necessary: -(a) because OSR2.1 has a bug which causes data loss if the peripheral returns -fewer bytes than the host expects to read, and (b) because, on Microsoft -platforms at least, an outstanding read posted on EP1 consumes about 35% of -the CPU just polling the device for data. - -The next 4 fields are the 16-bit TxCredits for each port, which indicate how -many bytes the host is allowed to send on EP1 for transmit to a given port. -After an OPEN_PORT command, the Edgeport sends the initial TxCredits for that -port. - -All 16-bit fields are sent in little-endian (Intel) format. - -************************************************************************/ - -// -// Define format of InterruptStatus packet returned from the -// Interrupt pipe -// - -struct int_status_pkt { - __u16 RxBytesAvail; // Additional bytes available to - // be read from Bulk IN pipe - __u16 TxCredits[MAX_RS232_PORTS]; // Additional space available in - // given port's TxBuffer -}; - - -#define GET_INT_STATUS_SIZE(NumPorts) (sizeof(__u16) + (sizeof(__u16) * (NumPorts))) - - - -// -// Define cmd/status header values and macros to extract them. -// -// Data: 0LLLLPPP LLLLLLLL -// Cmd/Stat: 1ccccPPP CCCCCCCC - -#define IOSP_DATA_HDR_SIZE 2 -#define IOSP_CMD_HDR_SIZE 2 - -#define IOSP_MAX_DATA_LENGTH 0x0FFF // 12 bits -> 4K - -#define IOSP_PORT_MASK 0x07 // Mask to isolate port number -#define IOSP_CMD_STAT_BIT 0x80 // If set, this is command/status header - -#define IS_CMD_STAT_HDR(Byte1) ((Byte1) & IOSP_CMD_STAT_BIT) -#define IS_DATA_HDR(Byte1) (!IS_CMD_STAT_HDR(Byte1)) - -#define IOSP_GET_HDR_PORT(Byte1) ((__u8) ((Byte1) & IOSP_PORT_MASK)) -#define IOSP_GET_HDR_DATA_LEN(Byte1, Byte2) ((__u16) (((__u16)((Byte1) & 0x78)) << 5) | (Byte2)) -#define IOSP_GET_STATUS_CODE(Byte1) ((__u8) (((Byte1) & 0x78) >> 3)) - - -// -// These macros build the 1st and 2nd bytes for a data header -// -#define IOSP_BUILD_DATA_HDR1(Port, Len) ((__u8) (((Port) | ((__u8) (((__u16) (Len)) >> 5) & 0x78)))) -#define IOSP_BUILD_DATA_HDR2(Port, Len) ((__u8) (Len)) - - -// -// These macros build the 1st and 2nd bytes for a command header -// -#define IOSP_BUILD_CMD_HDR1(Port, Cmd) ((__u8) (IOSP_CMD_STAT_BIT | (Port) | ((__u8) ((Cmd) << 3)))) - - -//-------------------------------------------------------------- -// -// Define values for commands and command parameters -// (sent from Host to Edgeport) -// -// 1ccccPPP P1P1P1P1 [ P2P2P2P2P2 ]... -// -// cccc: 00-07 2-byte commands. Write UART register 0-7 with -// value in P1. See 16650.H for definitions of -// UART register numbers and contents. -// -// 08-0B 3-byte commands: ==== P1 ==== ==== P2 ==== -// 08 available for expansion -// 09 1-param commands Command Code Param -// 0A available for expansion -// 0B available for expansion -// -// 0C-0D 4-byte commands. P1 = extended cmd and P2,P3 = params -// Currently unimplemented. -// -// 0E-0F N-byte commands: P1 = num bytes after P1 (ie, TotalLen - 2) -// P2 = extended cmd, P3..Pn = parameters. -// Currently unimplemented. -// - -#define IOSP_WRITE_UART_REG(n) ((n) & 0x07) // UartReg[ n ] := P1 - -// Register numbers and contents -// defined in 16554.H. - -// 0x08 // Available for expansion. -#define IOSP_EXT_CMD 0x09 // P1 = Command code (defined below) - -// P2 = Parameter - -// -// Extended Command values, used with IOSP_EXT_CMD, may -// or may not use parameter P2. -// - -#define IOSP_CMD_OPEN_PORT 0x00 // Enable ints, init UART. (NO PARAM) -#define IOSP_CMD_CLOSE_PORT 0x01 // Disable ints, flush buffers. (NO PARAM) -#define IOSP_CMD_CHASE_PORT 0x02 // Wait for Edgeport TX buffers to empty. (NO PARAM) -#define IOSP_CMD_SET_RX_FLOW 0x03 // Set Rx Flow Control in Edgeport -#define IOSP_CMD_SET_TX_FLOW 0x04 // Set Tx Flow Control in Edgeport -#define IOSP_CMD_SET_XON_CHAR 0x05 // Set XON Character in Edgeport -#define IOSP_CMD_SET_XOFF_CHAR 0x06 // Set XOFF Character in Edgeport -#define IOSP_CMD_RX_CHECK_REQ 0x07 // Request Edgeport to insert a Checkpoint into - -// the receive data stream (Parameter = 1 byte sequence number) - -#define IOSP_CMD_SET_BREAK 0x08 // Turn on the BREAK (LCR bit 6) -#define IOSP_CMD_CLEAR_BREAK 0x09 // Turn off the BREAK (LCR bit 6) - - -// -// Define macros to simplify building of IOSP cmds -// - -#define MAKE_CMD_WRITE_REG(ppBuf, pLen, Port, Reg, Val) \ -do { \ - (*(ppBuf))[0] = IOSP_BUILD_CMD_HDR1((Port), \ - IOSP_WRITE_UART_REG(Reg)); \ - (*(ppBuf))[1] = (Val); \ - \ - *ppBuf += 2; \ - *pLen += 2; \ -} while (0) - -#define MAKE_CMD_EXT_CMD(ppBuf, pLen, Port, ExtCmd, Param) \ -do { \ - (*(ppBuf))[0] = IOSP_BUILD_CMD_HDR1((Port), IOSP_EXT_CMD); \ - (*(ppBuf))[1] = (ExtCmd); \ - (*(ppBuf))[2] = (Param); \ - \ - *ppBuf += 3; \ - *pLen += 3; \ -} while (0) - - - -//-------------------------------------------------------------- -// -// Define format of flow control commands -// (sent from Host to Edgeport) -// -// 11001PPP FlowCmd FlowTypes -// -// Note that the 'FlowTypes' parameter is a bit mask; that is, -// more than one flow control type can be active at the same time. -// FlowTypes = 0 means 'no flow control'. -// - -// -// IOSP_CMD_SET_RX_FLOW -// -// Tells Edgeport how it can stop incoming UART data -// -// Example for Port 0 -// P0 = 11001000 -// P1 = IOSP_CMD_SET_RX_FLOW -// P2 = Bit mask as follows: - -#define IOSP_RX_FLOW_RTS 0x01 // Edgeport drops RTS to stop incoming data -#define IOSP_RX_FLOW_DTR 0x02 // Edgeport drops DTR to stop incoming data -#define IOSP_RX_FLOW_DSR_SENSITIVITY 0x04 // Ignores Rx data unless DSR high - -// Not currently implemented by firmware. -#define IOSP_RX_FLOW_XON_XOFF 0x08 // Edgeport sends XOFF char to stop incoming data. - -// Host must have previously programmed the -// XON/XOFF values with SET_XON/SET_XOFF -// before enabling this bit. - -// -// IOSP_CMD_SET_TX_FLOW -// -// Tells Edgeport what signal(s) will stop it from transmitting UART data -// -// Example for Port 0 -// P0 = 11001000 -// P1 = IOSP_CMD_SET_TX_FLOW -// P2 = Bit mask as follows: - -#define IOSP_TX_FLOW_CTS 0x01 // Edgeport stops Tx if CTS low -#define IOSP_TX_FLOW_DSR 0x02 // Edgeport stops Tx if DSR low -#define IOSP_TX_FLOW_DCD 0x04 // Edgeport stops Tx if DCD low -#define IOSP_TX_FLOW_XON_XOFF 0x08 // Edgeport stops Tx upon receiving XOFF char. - -// Host must have previously programmed the -// XON/XOFF values with SET_XON/SET_XOFF -// before enabling this bit. -#define IOSP_TX_FLOW_XOFF_CONTINUE 0x10 // If not set, Edgeport stops Tx when - -// sending XOFF in order to fix broken -// systems that interpret the next -// received char as XON. -// If set, Edgeport continues Tx -// normally after transmitting XOFF. -// Not currently implemented by firmware. -#define IOSP_TX_TOGGLE_RTS 0x20 // Edgeport drives RTS as a true half-duplex - -// Request-to-Send signal: it is raised before -// beginning transmission and lowered after -// the last Tx char leaves the UART. -// Not currently implemented by firmware. - -// -// IOSP_CMD_SET_XON_CHAR -// -// Sets the character which Edgeport transmits/interprets as XON. -// Note: This command MUST be sent before sending a SET_RX_FLOW or -// SET_TX_FLOW with the XON_XOFF bit set. -// -// Example for Port 0 -// P0 = 11001000 -// P1 = IOSP_CMD_SET_XON_CHAR -// P2 = 0x11 - - -// -// IOSP_CMD_SET_XOFF_CHAR -// -// Sets the character which Edgeport transmits/interprets as XOFF. -// Note: This command must be sent before sending a SET_RX_FLOW or -// SET_TX_FLOW with the XON_XOFF bit set. -// -// Example for Port 0 -// P0 = 11001000 -// P1 = IOSP_CMD_SET_XOFF_CHAR -// P2 = 0x13 - - -// -// IOSP_CMD_RX_CHECK_REQ -// -// This command is used to assist in the implementation of the -// IOCTL_SERIAL_PURGE Windows IOCTL. -// This IOSP command tries to place a marker at the end of the RX -// queue in the Edgeport. If the Edgeport RX queue is full then -// the Check will be discarded. -// It is up to the device driver to timeout waiting for the -// RX_CHECK_RSP. If a RX_CHECK_RSP is received, the driver is -// sure that all data has been received from the edgeport and -// may now purge any internal RX buffers. -// Note tat the sequence numbers may be used to detect lost -// CHECK_REQs. - -// Example for Port 0 -// P0 = 11001000 -// P1 = IOSP_CMD_RX_CHECK_REQ -// P2 = Sequence number - - -// Response will be: -// P1 = IOSP_EXT_RX_CHECK_RSP -// P2 = Request Sequence number - - - -//-------------------------------------------------------------- -// -// Define values for status and status parameters -// (received by Host from Edgeport) -// -// 1ssssPPP P1P1P1P1 [ P2P2P2P2P2 ]... -// -// ssss: 00-07 2-byte status. ssss identifies which UART register -// has changed value, and the new value is in P1. -// Note that the ssss values do not correspond to the -// 16554 register numbers given in 16554.H. Instead, -// see below for definitions of the ssss numbers -// used in this status message. -// -// 08-0B 3-byte status: ==== P1 ==== ==== P2 ==== -// 08 LSR_DATA: New LSR Errored byte -// 09 1-param responses Response Code Param -// 0A OPEN_RSP: InitialMsr TxBufferSize -// 0B available for expansion -// -// 0C-0D 4-byte status. P1 = extended status code and P2,P3 = params -// Not currently implemented. -// -// 0E-0F N-byte status: P1 = num bytes after P1 (ie, TotalLen - 2) -// P2 = extended status, P3..Pn = parameters. -// Not currently implemented. -// - -/**************************************************** - * SSSS values for 2-byte status messages (0-8) - ****************************************************/ - -#define IOSP_STATUS_LSR 0x00 // P1 is new value of LSR register. - -// Bits defined in 16554.H. Edgeport -// returns this in order to report -// line status errors (overrun, -// parity, framing, break). This form -// is used when a errored receive data -// character was NOT present in the -// UART when the LSR error occurred -// (ie, when LSR bit 0 = 0). - -#define IOSP_STATUS_MSR 0x01 // P1 is new value of MSR register. - -// Bits defined in 16554.H. Edgeport -// returns this in order to report -// changes in modem status lines -// (CTS, DSR, RI, CD) -// - -// 0x02 // Available for future expansion -// 0x03 // -// 0x04 // -// 0x05 // -// 0x06 // -// 0x07 // - - -/**************************************************** - * SSSS values for 3-byte status messages (8-A) - ****************************************************/ - -#define IOSP_STATUS_LSR_DATA 0x08 // P1 is new value of LSR register (same as STATUS_LSR) - -// P2 is errored character read from -// RxFIFO after LSR reported an error. - -#define IOSP_EXT_STATUS 0x09 // P1 is status/response code, param in P2. - - -// Response Codes (P1 values) for 3-byte status messages - -#define IOSP_EXT_STATUS_CHASE_RSP 0 // Reply to CHASE_PORT cmd. P2 is outcome: -#define IOSP_EXT_STATUS_CHASE_PASS 0 // P2 = 0: All Tx data drained successfully -#define IOSP_EXT_STATUS_CHASE_FAIL 1 // P2 = 1: Timed out (stuck due to flow - -// control from remote device). - -#define IOSP_EXT_STATUS_RX_CHECK_RSP 1 // Reply to RX_CHECK cmd. P2 is sequence number - - -#define IOSP_STATUS_OPEN_RSP 0x0A // Reply to OPEN_PORT cmd. - -// P1 is Initial MSR value -// P2 is encoded TxBuffer Size: -// TxBufferSize = (P2 + 1) * 64 - -// 0x0B // Available for future expansion - -#define GET_TX_BUFFER_SIZE(P2) (((P2) + 1) * 64) - - - - -/**************************************************** - * SSSS values for 4-byte status messages - ****************************************************/ - -#define IOSP_EXT4_STATUS 0x0C // Extended status code in P1, - -// Params in P2, P3 -// Currently unimplemented. - -// 0x0D // Currently unused, available. - - - -// -// Macros to parse status messages -// - -#define IOSP_GET_STATUS_LEN(code) ((code) < 8 ? 2 : ((code) < 0x0A ? 3 : 4)) - -#define IOSP_STATUS_IS_2BYTE(code) ((code) < 0x08) -#define IOSP_STATUS_IS_3BYTE(code) (((code) >= 0x08) && ((code) <= 0x0B)) -#define IOSP_STATUS_IS_4BYTE(code) (((code) >= 0x0C) && ((code) <= 0x0D)) - diff --git a/ANDROID_3.4.5/drivers/usb/serial/io_tables.h b/ANDROID_3.4.5/drivers/usb/serial/io_tables.h deleted file mode 100644 index d0e7c9af..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/io_tables.h +++ /dev/null @@ -1,227 +0,0 @@ -/* - * IO Edgeport Driver tables - * - * Copyright (C) 2001 - * Greg Kroah-Hartman (greg@kroah.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - */ - -#ifndef IO_TABLES_H -#define IO_TABLES_H - -static const struct usb_device_id edgeport_2port_id_table[] = { - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_421) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_21) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2_DIN) }, - { } -}; - -static const struct usb_device_id edgeport_4port_id_table[] = { - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_RAPIDPORT_4) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4T) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_MT4X56USB) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4_DIN) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_22I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_4) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_COMPATIBLE) }, - { } -}; - -static const struct usb_device_id edgeport_8port_id_table[] = { - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) }, - { } -}; - -static const struct usb_device_id Epic_port_id_table[] = { - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) }, - { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) }, - { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) }, - { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) }, - { } -}; - -/* Devices that this driver supports */ -static const struct usb_device_id id_table_combined[] = { - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_RAPIDPORT_4) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4T) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_MT4X56USB) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_421) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_21) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2_DIN) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4_DIN) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_22I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_4) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_COMPATIBLE) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) }, - { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) }, - { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) }, - { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, id_table_combined); - -static struct usb_driver io_driver = { - .name = "io_edgeport", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; - -static struct usb_serial_driver edgeport_2port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "edgeport_2", - }, - .description = "Edgeport 2 port adapter", - .id_table = edgeport_2port_id_table, - .num_ports = 2, - .open = edge_open, - .close = edge_close, - .throttle = edge_throttle, - .unthrottle = edge_unthrottle, - .attach = edge_startup, - .disconnect = edge_disconnect, - .release = edge_release, - .ioctl = edge_ioctl, - .set_termios = edge_set_termios, - .tiocmget = edge_tiocmget, - .tiocmset = edge_tiocmset, - .get_icount = edge_get_icount, - .write = edge_write, - .write_room = edge_write_room, - .chars_in_buffer = edge_chars_in_buffer, - .break_ctl = edge_break, - .read_int_callback = edge_interrupt_callback, - .read_bulk_callback = edge_bulk_in_callback, - .write_bulk_callback = edge_bulk_out_data_callback, -}; - -static struct usb_serial_driver edgeport_4port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "edgeport_4", - }, - .description = "Edgeport 4 port adapter", - .id_table = edgeport_4port_id_table, - .num_ports = 4, - .open = edge_open, - .close = edge_close, - .throttle = edge_throttle, - .unthrottle = edge_unthrottle, - .attach = edge_startup, - .disconnect = edge_disconnect, - .release = edge_release, - .ioctl = edge_ioctl, - .set_termios = edge_set_termios, - .tiocmget = edge_tiocmget, - .tiocmset = edge_tiocmset, - .get_icount = edge_get_icount, - .write = edge_write, - .write_room = edge_write_room, - .chars_in_buffer = edge_chars_in_buffer, - .break_ctl = edge_break, - .read_int_callback = edge_interrupt_callback, - .read_bulk_callback = edge_bulk_in_callback, - .write_bulk_callback = edge_bulk_out_data_callback, -}; - -static struct usb_serial_driver edgeport_8port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "edgeport_8", - }, - .description = "Edgeport 8 port adapter", - .id_table = edgeport_8port_id_table, - .num_ports = 8, - .open = edge_open, - .close = edge_close, - .throttle = edge_throttle, - .unthrottle = edge_unthrottle, - .attach = edge_startup, - .disconnect = edge_disconnect, - .release = edge_release, - .ioctl = edge_ioctl, - .set_termios = edge_set_termios, - .tiocmget = edge_tiocmget, - .tiocmset = edge_tiocmset, - .get_icount = edge_get_icount, - .write = edge_write, - .write_room = edge_write_room, - .chars_in_buffer = edge_chars_in_buffer, - .break_ctl = edge_break, - .read_int_callback = edge_interrupt_callback, - .read_bulk_callback = edge_bulk_in_callback, - .write_bulk_callback = edge_bulk_out_data_callback, -}; - -static struct usb_serial_driver epic_device = { - .driver = { - .owner = THIS_MODULE, - .name = "epic", - }, - .description = "EPiC device", - .id_table = Epic_port_id_table, - .num_ports = 1, - .open = edge_open, - .close = edge_close, - .throttle = edge_throttle, - .unthrottle = edge_unthrottle, - .attach = edge_startup, - .disconnect = edge_disconnect, - .release = edge_release, - .ioctl = edge_ioctl, - .set_termios = edge_set_termios, - .tiocmget = edge_tiocmget, - .tiocmset = edge_tiocmset, - .get_icount = edge_get_icount, - .write = edge_write, - .write_room = edge_write_room, - .chars_in_buffer = edge_chars_in_buffer, - .break_ctl = edge_break, - .read_int_callback = edge_interrupt_callback, - .read_bulk_callback = edge_bulk_in_callback, - .write_bulk_callback = edge_bulk_out_data_callback, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &edgeport_2port_device, &edgeport_4port_device, - &edgeport_8port_device, &epic_device, NULL -}; - -#endif - diff --git a/ANDROID_3.4.5/drivers/usb/serial/io_ti.c b/ANDROID_3.4.5/drivers/usb/serial/io_ti.c deleted file mode 100644 index 40a95a7f..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/io_ti.c +++ /dev/null @@ -1,2804 +0,0 @@ -/* - * Edgeport USB Serial Converter driver - * - * Copyright (C) 2000-2002 Inside Out Networks, All rights reserved. - * Copyright (C) 2001-2002 Greg Kroah-Hartman - * - * 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. - * - * Supports the following devices: - * EP/1 EP/2 EP/4 EP/21 EP/22 EP/221 EP/42 EP/421 WATCHPORT - * - * For questions or problems with this driver, contact Inside Out - * Networks technical support, or Peter Berger , - * or Al Borchers . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "io_16654.h" -#include "io_usbvend.h" -#include "io_ti.h" - -/* - * Version Information - */ -#define DRIVER_VERSION "v0.7mode043006" -#define DRIVER_AUTHOR "Greg Kroah-Hartman and David Iacovelli" -#define DRIVER_DESC "Edgeport USB Serial Driver" - -#define EPROM_PAGE_SIZE 64 - - -/* different hardware types */ -#define HARDWARE_TYPE_930 0 -#define HARDWARE_TYPE_TIUMP 1 - -/* IOCTL_PRIVATE_TI_GET_MODE Definitions */ -#define TI_MODE_CONFIGURING 0 /* Device has not entered start device */ -#define TI_MODE_BOOT 1 /* Staying in boot mode */ -#define TI_MODE_DOWNLOAD 2 /* Made it to download mode */ -#define TI_MODE_TRANSITIONING 3 /* Currently in boot mode but - transitioning to download mode */ - -/* read urb state */ -#define EDGE_READ_URB_RUNNING 0 -#define EDGE_READ_URB_STOPPING 1 -#define EDGE_READ_URB_STOPPED 2 - -#define EDGE_CLOSING_WAIT 4000 /* in .01 sec */ - -#define EDGE_OUT_BUF_SIZE 1024 - - -/* Product information read from the Edgeport */ -struct product_info { - int TiMode; /* Current TI Mode */ - __u8 hardware_type; /* Type of hardware */ -} __attribute__((packed)); - -struct edgeport_port { - __u16 uart_base; - __u16 dma_address; - __u8 shadow_msr; - __u8 shadow_mcr; - __u8 shadow_lsr; - __u8 lsr_mask; - __u32 ump_read_timeout; /* Number of milliseconds the UMP will - wait without data before completing - a read short */ - int baud_rate; - int close_pending; - int lsr_event; - struct async_icount icount; - wait_queue_head_t delta_msr_wait; /* for handling sleeping while - waiting for msr change to - happen */ - struct edgeport_serial *edge_serial; - struct usb_serial_port *port; - __u8 bUartMode; /* Port type, 0: RS232, etc. */ - spinlock_t ep_lock; - int ep_read_urb_state; - int ep_write_urb_in_use; - struct kfifo write_fifo; -}; - -struct edgeport_serial { - struct product_info product_info; - u8 TI_I2C_Type; /* Type of I2C in UMP */ - u8 TiReadI2C; /* Set to TRUE if we have read the - I2c in Boot Mode */ - struct mutex es_lock; - int num_ports_open; - struct usb_serial *serial; -}; - - -/* Devices that this driver supports */ -static const struct usb_device_id edgeport_1port_id_table[] = { - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_1) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_PROXIMITY) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_MOTION) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_MOISTURE) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_TEMPERATURE) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_HUMIDITY) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_POWER) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_LIGHT) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_RADIATION) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_DISTANCE) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_ACCELERATION) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_PROX_DIST) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_PLUS_PWR_HP4CD) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_PLUS_PWR_PCI) }, - { } -}; - -static const struct usb_device_id edgeport_2port_id_table[] = { - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2C) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_42) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_221C) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22C) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21C) }, - /* The 4, 8 and 16 port devices show up as multiple 2 port devices */ - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4S) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_8) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_8S) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_416) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_416B) }, - { } -}; - -/* Devices that this driver supports */ -static const struct usb_device_id id_table_combined[] = { - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_1) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_PROXIMITY) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_MOTION) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_MOISTURE) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_TEMPERATURE) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_HUMIDITY) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_POWER) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_LIGHT) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_RADIATION) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_DISTANCE) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_ACCELERATION) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_PROX_DIST) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_PLUS_PWR_HP4CD) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_PLUS_PWR_PCI) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2C) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_42) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_221C) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22C) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21C) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4S) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_8) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_8S) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_416) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_416B) }, - { } -}; - -MODULE_DEVICE_TABLE(usb, id_table_combined); - -static struct usb_driver io_driver = { - .name = "io_ti", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; - - -static unsigned char OperationalMajorVersion; -static unsigned char OperationalMinorVersion; -static unsigned short OperationalBuildNumber; - -static bool debug; - -static int closing_wait = EDGE_CLOSING_WAIT; -static bool ignore_cpu_rev; -static int default_uart_mode; /* RS232 */ - -static void edge_tty_recv(struct device *dev, struct tty_struct *tty, - unsigned char *data, int length); - -static void stop_read(struct edgeport_port *edge_port); -static int restart_read(struct edgeport_port *edge_port); - -static void edge_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios); -static void edge_send(struct tty_struct *tty); - -/* sysfs attributes */ -static int edge_create_sysfs_attrs(struct usb_serial_port *port); -static int edge_remove_sysfs_attrs(struct usb_serial_port *port); - - -static int ti_vread_sync(struct usb_device *dev, __u8 request, - __u16 value, __u16 index, u8 *data, int size) -{ - int status; - - status = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request, - (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN), - value, index, data, size, 1000); - if (status < 0) - return status; - if (status != size) { - dbg("%s - wanted to write %d, but only wrote %d", - __func__, size, status); - return -ECOMM; - } - return 0; -} - -static int ti_vsend_sync(struct usb_device *dev, __u8 request, - __u16 value, __u16 index, u8 *data, int size) -{ - int status; - - status = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request, - (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT), - value, index, data, size, 1000); - if (status < 0) - return status; - if (status != size) { - dbg("%s - wanted to write %d, but only wrote %d", - __func__, size, status); - return -ECOMM; - } - return 0; -} - -static int send_cmd(struct usb_device *dev, __u8 command, - __u8 moduleid, __u16 value, u8 *data, - int size) -{ - return ti_vsend_sync(dev, command, value, moduleid, data, size); -} - -/* clear tx/rx buffers and fifo in TI UMP */ -static int purge_port(struct usb_serial_port *port, __u16 mask) -{ - int port_number = port->number - port->serial->minor; - - dbg("%s - port %d, mask %x", __func__, port_number, mask); - - return send_cmd(port->serial->dev, - UMPC_PURGE_PORT, - (__u8)(UMPM_UART1_PORT + port_number), - mask, - NULL, - 0); -} - -/** - * read_download_mem - Read edgeport memory from TI chip - * @dev: usb device pointer - * @start_address: Device CPU address at which to read - * @length: Length of above data - * @address_type: Can read both XDATA and I2C - * @buffer: pointer to input data buffer - */ -static int read_download_mem(struct usb_device *dev, int start_address, - int length, __u8 address_type, __u8 *buffer) -{ - int status = 0; - __u8 read_length; - __be16 be_start_address; - - dbg("%s - @ %x for %d", __func__, start_address, length); - - /* Read in blocks of 64 bytes - * (TI firmware can't handle more than 64 byte reads) - */ - while (length) { - if (length > 64) - read_length = 64; - else - read_length = (__u8)length; - - if (read_length > 1) { - dbg("%s - @ %x for %d", __func__, - start_address, read_length); - } - be_start_address = cpu_to_be16(start_address); - status = ti_vread_sync(dev, UMPC_MEMORY_READ, - (__u16)address_type, - (__force __u16)be_start_address, - buffer, read_length); - - if (status) { - dbg("%s - ERROR %x", __func__, status); - return status; - } - - if (read_length > 1) - usb_serial_debug_data(debug, &dev->dev, __func__, - read_length, buffer); - - /* Update pointers/length */ - start_address += read_length; - buffer += read_length; - length -= read_length; - } - - return status; -} - -static int read_ram(struct usb_device *dev, int start_address, - int length, __u8 *buffer) -{ - return read_download_mem(dev, start_address, length, - DTK_ADDR_SPACE_XDATA, buffer); -} - -/* Read edgeport memory to a given block */ -static int read_boot_mem(struct edgeport_serial *serial, - int start_address, int length, __u8 *buffer) -{ - int status = 0; - int i; - - for (i = 0; i < length; i++) { - status = ti_vread_sync(serial->serial->dev, - UMPC_MEMORY_READ, serial->TI_I2C_Type, - (__u16)(start_address+i), &buffer[i], 0x01); - if (status) { - dbg("%s - ERROR %x", __func__, status); - return status; - } - } - - dbg("%s - start_address = %x, length = %d", - __func__, start_address, length); - usb_serial_debug_data(debug, &serial->serial->dev->dev, - __func__, length, buffer); - - serial->TiReadI2C = 1; - - return status; -} - -/* Write given block to TI EPROM memory */ -static int write_boot_mem(struct edgeport_serial *serial, - int start_address, int length, __u8 *buffer) -{ - int status = 0; - int i; - u8 *temp; - - /* Must do a read before write */ - if (!serial->TiReadI2C) { - temp = kmalloc(1, GFP_KERNEL); - if (!temp) { - dev_err(&serial->serial->dev->dev, - "%s - out of memory\n", __func__); - return -ENOMEM; - } - status = read_boot_mem(serial, 0, 1, temp); - kfree(temp); - if (status) - return status; - } - - for (i = 0; i < length; ++i) { - status = ti_vsend_sync(serial->serial->dev, - UMPC_MEMORY_WRITE, buffer[i], - (__u16)(i + start_address), NULL, 0); - if (status) - return status; - } - - dbg("%s - start_sddr = %x, length = %d", - __func__, start_address, length); - usb_serial_debug_data(debug, &serial->serial->dev->dev, - __func__, length, buffer); - - return status; -} - - -/* Write edgeport I2C memory to TI chip */ -static int write_i2c_mem(struct edgeport_serial *serial, - int start_address, int length, __u8 address_type, __u8 *buffer) -{ - int status = 0; - int write_length; - __be16 be_start_address; - - /* We can only send a maximum of 1 aligned byte page at a time */ - - /* calculate the number of bytes left in the first page */ - write_length = EPROM_PAGE_SIZE - - (start_address & (EPROM_PAGE_SIZE - 1)); - - if (write_length > length) - write_length = length; - - dbg("%s - BytesInFirstPage Addr = %x, length = %d", - __func__, start_address, write_length); - usb_serial_debug_data(debug, &serial->serial->dev->dev, - __func__, write_length, buffer); - - /* Write first page */ - be_start_address = cpu_to_be16(start_address); - status = ti_vsend_sync(serial->serial->dev, - UMPC_MEMORY_WRITE, (__u16)address_type, - (__force __u16)be_start_address, - buffer, write_length); - if (status) { - dbg("%s - ERROR %d", __func__, status); - return status; - } - - length -= write_length; - start_address += write_length; - buffer += write_length; - - /* We should be aligned now -- can write - max page size bytes at a time */ - while (length) { - if (length > EPROM_PAGE_SIZE) - write_length = EPROM_PAGE_SIZE; - else - write_length = length; - - dbg("%s - Page Write Addr = %x, length = %d", - __func__, start_address, write_length); - usb_serial_debug_data(debug, &serial->serial->dev->dev, - __func__, write_length, buffer); - - /* Write next page */ - be_start_address = cpu_to_be16(start_address); - status = ti_vsend_sync(serial->serial->dev, UMPC_MEMORY_WRITE, - (__u16)address_type, - (__force __u16)be_start_address, - buffer, write_length); - if (status) { - dev_err(&serial->serial->dev->dev, "%s - ERROR %d\n", - __func__, status); - return status; - } - - length -= write_length; - start_address += write_length; - buffer += write_length; - } - return status; -} - -/* Examine the UMP DMA registers and LSR - * - * Check the MSBit of the X and Y DMA byte count registers. - * A zero in this bit indicates that the TX DMA buffers are empty - * then check the TX Empty bit in the UART. - */ -static int tx_active(struct edgeport_port *port) -{ - int status; - struct out_endpoint_desc_block *oedb; - __u8 *lsr; - int bytes_left = 0; - - oedb = kmalloc(sizeof(*oedb), GFP_KERNEL); - if (!oedb) { - dev_err(&port->port->dev, "%s - out of memory\n", __func__); - return -ENOMEM; - } - - lsr = kmalloc(1, GFP_KERNEL); /* Sigh, that's right, just one byte, - as not all platforms can do DMA - from stack */ - if (!lsr) { - kfree(oedb); - return -ENOMEM; - } - /* Read the DMA Count Registers */ - status = read_ram(port->port->serial->dev, port->dma_address, - sizeof(*oedb), (void *)oedb); - if (status) - goto exit_is_tx_active; - - dbg("%s - XByteCount 0x%X", __func__, oedb->XByteCount); - - /* and the LSR */ - status = read_ram(port->port->serial->dev, - port->uart_base + UMPMEM_OFFS_UART_LSR, 1, lsr); - - if (status) - goto exit_is_tx_active; - dbg("%s - LSR = 0x%X", __func__, *lsr); - - /* If either buffer has data or we are transmitting then return TRUE */ - if ((oedb->XByteCount & 0x80) != 0) - bytes_left += 64; - - if ((*lsr & UMP_UART_LSR_TX_MASK) == 0) - bytes_left += 1; - - /* We return Not Active if we get any kind of error */ -exit_is_tx_active: - dbg("%s - return %d", __func__, bytes_left); - - kfree(lsr); - kfree(oedb); - return bytes_left; -} - -static void chase_port(struct edgeport_port *port, unsigned long timeout, - int flush) -{ - int baud_rate; - struct tty_struct *tty = tty_port_tty_get(&port->port->port); - wait_queue_t wait; - unsigned long flags; - - if (!timeout) - timeout = (HZ * EDGE_CLOSING_WAIT)/100; - - /* wait for data to drain from the buffer */ - spin_lock_irqsave(&port->ep_lock, flags); - init_waitqueue_entry(&wait, current); - add_wait_queue(&tty->write_wait, &wait); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (kfifo_len(&port->write_fifo) == 0 - || timeout == 0 || signal_pending(current) - || !usb_get_intfdata(port->port->serial->interface)) - /* disconnect */ - break; - spin_unlock_irqrestore(&port->ep_lock, flags); - timeout = schedule_timeout(timeout); - spin_lock_irqsave(&port->ep_lock, flags); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&tty->write_wait, &wait); - if (flush) - kfifo_reset_out(&port->write_fifo); - spin_unlock_irqrestore(&port->ep_lock, flags); - tty_kref_put(tty); - - /* wait for data to drain from the device */ - timeout += jiffies; - while ((long)(jiffies - timeout) < 0 && !signal_pending(current) - && usb_get_intfdata(port->port->serial->interface)) { - /* not disconnected */ - if (!tx_active(port)) - break; - msleep(10); - } - - /* disconnected */ - if (!usb_get_intfdata(port->port->serial->interface)) - return; - - /* wait one more character time, based on baud rate */ - /* (tx_active doesn't seem to wait for the last byte) */ - baud_rate = port->baud_rate; - if (baud_rate == 0) - baud_rate = 50; - msleep(max(1, DIV_ROUND_UP(10000, baud_rate))); -} - -static int choose_config(struct usb_device *dev) -{ - /* - * There may be multiple configurations on this device, in which case - * we would need to read and parse all of them to find out which one - * we want. However, we just support one config at this point, - * configuration # 1, which is Config Descriptor 0. - */ - - dbg("%s - Number of Interfaces = %d", - __func__, dev->config->desc.bNumInterfaces); - dbg("%s - MAX Power = %d", - __func__, dev->config->desc.bMaxPower * 2); - - if (dev->config->desc.bNumInterfaces != 1) { - dev_err(&dev->dev, "%s - bNumInterfaces is not 1, ERROR!\n", - __func__); - return -ENODEV; - } - - return 0; -} - -static int read_rom(struct edgeport_serial *serial, - int start_address, int length, __u8 *buffer) -{ - int status; - - if (serial->product_info.TiMode == TI_MODE_DOWNLOAD) { - status = read_download_mem(serial->serial->dev, - start_address, - length, - serial->TI_I2C_Type, - buffer); - } else { - status = read_boot_mem(serial, start_address, length, - buffer); - } - return status; -} - -static int write_rom(struct edgeport_serial *serial, int start_address, - int length, __u8 *buffer) -{ - if (serial->product_info.TiMode == TI_MODE_BOOT) - return write_boot_mem(serial, start_address, length, - buffer); - - if (serial->product_info.TiMode == TI_MODE_DOWNLOAD) - return write_i2c_mem(serial, start_address, length, - serial->TI_I2C_Type, buffer); - return -EINVAL; -} - - - -/* Read a descriptor header from I2C based on type */ -static int get_descriptor_addr(struct edgeport_serial *serial, - int desc_type, struct ti_i2c_desc *rom_desc) -{ - int start_address; - int status; - - /* Search for requested descriptor in I2C */ - start_address = 2; - do { - status = read_rom(serial, - start_address, - sizeof(struct ti_i2c_desc), - (__u8 *)rom_desc); - if (status) - return 0; - - if (rom_desc->Type == desc_type) - return start_address; - - start_address = start_address + sizeof(struct ti_i2c_desc) - + rom_desc->Size; - - } while ((start_address < TI_MAX_I2C_SIZE) && rom_desc->Type); - - return 0; -} - -/* Validate descriptor checksum */ -static int valid_csum(struct ti_i2c_desc *rom_desc, __u8 *buffer) -{ - __u16 i; - __u8 cs = 0; - - for (i = 0; i < rom_desc->Size; i++) - cs = (__u8)(cs + buffer[i]); - - if (cs != rom_desc->CheckSum) { - dbg("%s - Mismatch %x - %x", __func__, rom_desc->CheckSum, cs); - return -EINVAL; - } - return 0; -} - -/* Make sure that the I2C image is good */ -static int check_i2c_image(struct edgeport_serial *serial) -{ - struct device *dev = &serial->serial->dev->dev; - int status = 0; - struct ti_i2c_desc *rom_desc; - int start_address = 2; - __u8 *buffer; - __u16 ttype; - - rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL); - if (!rom_desc) { - dev_err(dev, "%s - out of memory\n", __func__); - return -ENOMEM; - } - buffer = kmalloc(TI_MAX_I2C_SIZE, GFP_KERNEL); - if (!buffer) { - dev_err(dev, "%s - out of memory when allocating buffer\n", - __func__); - kfree(rom_desc); - return -ENOMEM; - } - - /* Read the first byte (Signature0) must be 0x52 or 0x10 */ - status = read_rom(serial, 0, 1, buffer); - if (status) - goto out; - - if (*buffer != UMP5152 && *buffer != UMP3410) { - dev_err(dev, "%s - invalid buffer signature\n", __func__); - status = -ENODEV; - goto out; - } - - do { - /* Validate the I2C */ - status = read_rom(serial, - start_address, - sizeof(struct ti_i2c_desc), - (__u8 *)rom_desc); - if (status) - break; - - if ((start_address + sizeof(struct ti_i2c_desc) + - rom_desc->Size) > TI_MAX_I2C_SIZE) { - status = -ENODEV; - dbg("%s - structure too big, erroring out.", __func__); - break; - } - - dbg("%s Type = 0x%x", __func__, rom_desc->Type); - - /* Skip type 2 record */ - ttype = rom_desc->Type & 0x0f; - if (ttype != I2C_DESC_TYPE_FIRMWARE_BASIC - && ttype != I2C_DESC_TYPE_FIRMWARE_AUTO) { - /* Read the descriptor data */ - status = read_rom(serial, start_address + - sizeof(struct ti_i2c_desc), - rom_desc->Size, buffer); - if (status) - break; - - status = valid_csum(rom_desc, buffer); - if (status) - break; - } - start_address = start_address + sizeof(struct ti_i2c_desc) + - rom_desc->Size; - - } while ((rom_desc->Type != I2C_DESC_TYPE_ION) && - (start_address < TI_MAX_I2C_SIZE)); - - if ((rom_desc->Type != I2C_DESC_TYPE_ION) || - (start_address > TI_MAX_I2C_SIZE)) - status = -ENODEV; - -out: - kfree(buffer); - kfree(rom_desc); - return status; -} - -static int get_manuf_info(struct edgeport_serial *serial, __u8 *buffer) -{ - int status; - int start_address; - struct ti_i2c_desc *rom_desc; - struct edge_ti_manuf_descriptor *desc; - - rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL); - if (!rom_desc) { - dev_err(&serial->serial->dev->dev, "%s - out of memory\n", - __func__); - return -ENOMEM; - } - start_address = get_descriptor_addr(serial, I2C_DESC_TYPE_ION, - rom_desc); - - if (!start_address) { - dbg("%s - Edge Descriptor not found in I2C", __func__); - status = -ENODEV; - goto exit; - } - - /* Read the descriptor data */ - status = read_rom(serial, start_address+sizeof(struct ti_i2c_desc), - rom_desc->Size, buffer); - if (status) - goto exit; - - status = valid_csum(rom_desc, buffer); - - desc = (struct edge_ti_manuf_descriptor *)buffer; - dbg("%s - IonConfig 0x%x", __func__, desc->IonConfig); - dbg("%s - Version %d", __func__, desc->Version); - dbg("%s - Cpu/Board 0x%x", __func__, desc->CpuRev_BoardRev); - dbg("%s - NumPorts %d", __func__, desc->NumPorts); - dbg("%s - NumVirtualPorts %d", __func__, desc->NumVirtualPorts); - dbg("%s - TotalPorts %d", __func__, desc->TotalPorts); - -exit: - kfree(rom_desc); - return status; -} - -/* Build firmware header used for firmware update */ -static int build_i2c_fw_hdr(__u8 *header, struct device *dev) -{ - __u8 *buffer; - int buffer_size; - int i; - int err; - __u8 cs = 0; - struct ti_i2c_desc *i2c_header; - struct ti_i2c_image_header *img_header; - struct ti_i2c_firmware_rec *firmware_rec; - const struct firmware *fw; - const char *fw_name = "edgeport/down3.bin"; - - /* In order to update the I2C firmware we must change the type 2 record - * to type 0xF2. This will force the UMP to come up in Boot Mode. - * Then while in boot mode, the driver will download the latest - * firmware (padded to 15.5k) into the UMP ram. And finally when the - * device comes back up in download mode the driver will cause the new - * firmware to be copied from the UMP Ram to I2C and the firmware will - * update the record type from 0xf2 to 0x02. - */ - - /* Allocate a 15.5k buffer + 2 bytes for version number - * (Firmware Record) */ - buffer_size = (((1024 * 16) - 512 ) + - sizeof(struct ti_i2c_firmware_rec)); - - buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!buffer) { - dev_err(dev, "%s - out of memory\n", __func__); - return -ENOMEM; - } - - // Set entire image of 0xffs - memset(buffer, 0xff, buffer_size); - - err = request_firmware(&fw, fw_name, dev); - if (err) { - printk(KERN_ERR "Failed to load image \"%s\" err %d\n", - fw_name, err); - kfree(buffer); - return err; - } - - /* Save Download Version Number */ - OperationalMajorVersion = fw->data[0]; - OperationalMinorVersion = fw->data[1]; - OperationalBuildNumber = fw->data[2] | (fw->data[3] << 8); - - /* Copy version number into firmware record */ - firmware_rec = (struct ti_i2c_firmware_rec *)buffer; - - firmware_rec->Ver_Major = OperationalMajorVersion; - firmware_rec->Ver_Minor = OperationalMinorVersion; - - /* Pointer to fw_down memory image */ - img_header = (struct ti_i2c_image_header *)&fw->data[4]; - - memcpy(buffer + sizeof(struct ti_i2c_firmware_rec), - &fw->data[4 + sizeof(struct ti_i2c_image_header)], - le16_to_cpu(img_header->Length)); - - release_firmware(fw); - - for (i=0; i < buffer_size; i++) { - cs = (__u8)(cs + buffer[i]); - } - - kfree(buffer); - - /* Build new header */ - i2c_header = (struct ti_i2c_desc *)header; - firmware_rec = (struct ti_i2c_firmware_rec*)i2c_header->Data; - - i2c_header->Type = I2C_DESC_TYPE_FIRMWARE_BLANK; - i2c_header->Size = (__u16)buffer_size; - i2c_header->CheckSum = cs; - firmware_rec->Ver_Major = OperationalMajorVersion; - firmware_rec->Ver_Minor = OperationalMinorVersion; - - return 0; -} - -/* Try to figure out what type of I2c we have */ -static int i2c_type_bootmode(struct edgeport_serial *serial) -{ - int status; - u8 *data; - - data = kmalloc(1, GFP_KERNEL); - if (!data) { - dev_err(&serial->serial->dev->dev, - "%s - out of memory\n", __func__); - return -ENOMEM; - } - - /* Try to read type 2 */ - status = ti_vread_sync(serial->serial->dev, UMPC_MEMORY_READ, - DTK_ADDR_SPACE_I2C_TYPE_II, 0, data, 0x01); - if (status) - dbg("%s - read 2 status error = %d", __func__, status); - else - dbg("%s - read 2 data = 0x%x", __func__, *data); - if ((!status) && (*data == UMP5152 || *data == UMP3410)) { - dbg("%s - ROM_TYPE_II", __func__); - serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II; - goto out; - } - - /* Try to read type 3 */ - status = ti_vread_sync(serial->serial->dev, UMPC_MEMORY_READ, - DTK_ADDR_SPACE_I2C_TYPE_III, 0, data, 0x01); - if (status) - dbg("%s - read 3 status error = %d", __func__, status); - else - dbg("%s - read 2 data = 0x%x", __func__, *data); - if ((!status) && (*data == UMP5152 || *data == UMP3410)) { - dbg("%s - ROM_TYPE_III", __func__); - serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_III; - goto out; - } - - dbg("%s - Unknown", __func__); - serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II; - status = -ENODEV; -out: - kfree(data); - return status; -} - -static int bulk_xfer(struct usb_serial *serial, void *buffer, - int length, int *num_sent) -{ - int status; - - status = usb_bulk_msg(serial->dev, - usb_sndbulkpipe(serial->dev, - serial->port[0]->bulk_out_endpointAddress), - buffer, length, num_sent, 1000); - return status; -} - -/* Download given firmware image to the device (IN BOOT MODE) */ -static int download_code(struct edgeport_serial *serial, __u8 *image, - int image_length) -{ - int status = 0; - int pos; - int transfer; - int done; - - /* Transfer firmware image */ - for (pos = 0; pos < image_length; ) { - /* Read the next buffer from file */ - transfer = image_length - pos; - if (transfer > EDGE_FW_BULK_MAX_PACKET_SIZE) - transfer = EDGE_FW_BULK_MAX_PACKET_SIZE; - - /* Transfer data */ - status = bulk_xfer(serial->serial, &image[pos], - transfer, &done); - if (status) - break; - /* Advance buffer pointer */ - pos += done; - } - - return status; -} - -/* FIXME!!! */ -static int config_boot_dev(struct usb_device *dev) -{ - return 0; -} - -static int ti_cpu_rev(struct edge_ti_manuf_descriptor *desc) -{ - return TI_GET_CPU_REVISION(desc->CpuRev_BoardRev); -} - -/** - * DownloadTIFirmware - Download run-time operating firmware to the TI5052 - * - * This routine downloads the main operating code into the TI5052, using the - * boot code already burned into E2PROM or ROM. - */ -static int download_fw(struct edgeport_serial *serial) -{ - struct device *dev = &serial->serial->dev->dev; - int status = 0; - int start_address; - struct edge_ti_manuf_descriptor *ti_manuf_desc; - struct usb_interface_descriptor *interface; - int download_cur_ver; - int download_new_ver; - - /* This routine is entered by both the BOOT mode and the Download mode - * We can determine which code is running by the reading the config - * descriptor and if we have only one bulk pipe it is in boot mode - */ - serial->product_info.hardware_type = HARDWARE_TYPE_TIUMP; - - /* Default to type 2 i2c */ - serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II; - - status = choose_config(serial->serial->dev); - if (status) - return status; - - interface = &serial->serial->interface->cur_altsetting->desc; - if (!interface) { - dev_err(dev, "%s - no interface set, error!\n", __func__); - return -ENODEV; - } - - /* - * Setup initial mode -- the default mode 0 is TI_MODE_CONFIGURING - * if we have more than one endpoint we are definitely in download - * mode - */ - if (interface->bNumEndpoints > 1) - serial->product_info.TiMode = TI_MODE_DOWNLOAD; - else - /* Otherwise we will remain in configuring mode */ - serial->product_info.TiMode = TI_MODE_CONFIGURING; - - /********************************************************************/ - /* Download Mode */ - /********************************************************************/ - if (serial->product_info.TiMode == TI_MODE_DOWNLOAD) { - struct ti_i2c_desc *rom_desc; - - dbg("%s - RUNNING IN DOWNLOAD MODE", __func__); - - status = check_i2c_image(serial); - if (status) { - dbg("%s - DOWNLOAD MODE -- BAD I2C", __func__); - return status; - } - - /* Validate Hardware version number - * Read Manufacturing Descriptor from TI Based Edgeport - */ - ti_manuf_desc = kmalloc(sizeof(*ti_manuf_desc), GFP_KERNEL); - if (!ti_manuf_desc) { - dev_err(dev, "%s - out of memory.\n", __func__); - return -ENOMEM; - } - status = get_manuf_info(serial, (__u8 *)ti_manuf_desc); - if (status) { - kfree(ti_manuf_desc); - return status; - } - - /* Check version number of ION descriptor */ - if (!ignore_cpu_rev && ti_cpu_rev(ti_manuf_desc) < 2) { - dbg("%s - Wrong CPU Rev %d (Must be 2)", - __func__, ti_cpu_rev(ti_manuf_desc)); - kfree(ti_manuf_desc); - return -EINVAL; - } - - rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL); - if (!rom_desc) { - dev_err(dev, "%s - out of memory.\n", __func__); - kfree(ti_manuf_desc); - return -ENOMEM; - } - - /* Search for type 2 record (firmware record) */ - start_address = get_descriptor_addr(serial, - I2C_DESC_TYPE_FIRMWARE_BASIC, rom_desc); - if (start_address != 0) { - struct ti_i2c_firmware_rec *firmware_version; - u8 *record; - - dbg("%s - Found Type FIRMWARE (Type 2) record", - __func__); - - firmware_version = kmalloc(sizeof(*firmware_version), - GFP_KERNEL); - if (!firmware_version) { - dev_err(dev, "%s - out of memory.\n", __func__); - kfree(rom_desc); - kfree(ti_manuf_desc); - return -ENOMEM; - } - - /* Validate version number - * Read the descriptor data - */ - status = read_rom(serial, start_address + - sizeof(struct ti_i2c_desc), - sizeof(struct ti_i2c_firmware_rec), - (__u8 *)firmware_version); - if (status) { - kfree(firmware_version); - kfree(rom_desc); - kfree(ti_manuf_desc); - return status; - } - - /* Check version number of download with current - version in I2c */ - download_cur_ver = (firmware_version->Ver_Major << 8) + - (firmware_version->Ver_Minor); - download_new_ver = (OperationalMajorVersion << 8) + - (OperationalMinorVersion); - - dbg("%s - >> FW Versions Device %d.%d Driver %d.%d", - __func__, - firmware_version->Ver_Major, - firmware_version->Ver_Minor, - OperationalMajorVersion, - OperationalMinorVersion); - - /* Check if we have an old version in the I2C and - update if necessary */ - if (download_cur_ver < download_new_ver) { - dbg("%s - Update I2C dld from %d.%d to %d.%d", - __func__, - firmware_version->Ver_Major, - firmware_version->Ver_Minor, - OperationalMajorVersion, - OperationalMinorVersion); - - record = kmalloc(1, GFP_KERNEL); - if (!record) { - dev_err(dev, "%s - out of memory.\n", - __func__); - kfree(firmware_version); - kfree(rom_desc); - kfree(ti_manuf_desc); - return -ENOMEM; - } - /* In order to update the I2C firmware we must - * change the type 2 record to type 0xF2. This - * will force the UMP to come up in Boot Mode. - * Then while in boot mode, the driver will - * download the latest firmware (padded to - * 15.5k) into the UMP ram. Finally when the - * device comes back up in download mode the - * driver will cause the new firmware to be - * copied from the UMP Ram to I2C and the - * firmware will update the record type from - * 0xf2 to 0x02. - */ - *record = I2C_DESC_TYPE_FIRMWARE_BLANK; - - /* Change the I2C Firmware record type to - 0xf2 to trigger an update */ - status = write_rom(serial, start_address, - sizeof(*record), record); - if (status) { - kfree(record); - kfree(firmware_version); - kfree(rom_desc); - kfree(ti_manuf_desc); - return status; - } - - /* verify the write -- must do this in order - * for write to complete before we do the - * hardware reset - */ - status = read_rom(serial, - start_address, - sizeof(*record), - record); - if (status) { - kfree(record); - kfree(firmware_version); - kfree(rom_desc); - kfree(ti_manuf_desc); - return status; - } - - if (*record != I2C_DESC_TYPE_FIRMWARE_BLANK) { - dev_err(dev, - "%s - error resetting device\n", - __func__); - kfree(record); - kfree(firmware_version); - kfree(rom_desc); - kfree(ti_manuf_desc); - return -ENODEV; - } - - dbg("%s - HARDWARE RESET", __func__); - - /* Reset UMP -- Back to BOOT MODE */ - status = ti_vsend_sync(serial->serial->dev, - UMPC_HARDWARE_RESET, - 0, 0, NULL, 0); - - dbg("%s - HARDWARE RESET return %d", - __func__, status); - - /* return an error on purpose. */ - kfree(record); - kfree(firmware_version); - kfree(rom_desc); - kfree(ti_manuf_desc); - return -ENODEV; - } - kfree(firmware_version); - } - /* Search for type 0xF2 record (firmware blank record) */ - else if ((start_address = get_descriptor_addr(serial, I2C_DESC_TYPE_FIRMWARE_BLANK, rom_desc)) != 0) { -#define HEADER_SIZE (sizeof(struct ti_i2c_desc) + \ - sizeof(struct ti_i2c_firmware_rec)) - __u8 *header; - __u8 *vheader; - - header = kmalloc(HEADER_SIZE, GFP_KERNEL); - if (!header) { - dev_err(dev, "%s - out of memory.\n", __func__); - kfree(rom_desc); - kfree(ti_manuf_desc); - return -ENOMEM; - } - - vheader = kmalloc(HEADER_SIZE, GFP_KERNEL); - if (!vheader) { - dev_err(dev, "%s - out of memory.\n", __func__); - kfree(header); - kfree(rom_desc); - kfree(ti_manuf_desc); - return -ENOMEM; - } - - dbg("%s - Found Type BLANK FIRMWARE (Type F2) record", - __func__); - - /* - * In order to update the I2C firmware we must change - * the type 2 record to type 0xF2. This will force the - * UMP to come up in Boot Mode. Then while in boot - * mode, the driver will download the latest firmware - * (padded to 15.5k) into the UMP ram. Finally when the - * device comes back up in download mode the driver - * will cause the new firmware to be copied from the - * UMP Ram to I2C and the firmware will update the - * record type from 0xf2 to 0x02. - */ - status = build_i2c_fw_hdr(header, dev); - if (status) { - kfree(vheader); - kfree(header); - kfree(rom_desc); - kfree(ti_manuf_desc); - return -EINVAL; - } - - /* Update I2C with type 0xf2 record with correct - size and checksum */ - status = write_rom(serial, - start_address, - HEADER_SIZE, - header); - if (status) { - kfree(vheader); - kfree(header); - kfree(rom_desc); - kfree(ti_manuf_desc); - return -EINVAL; - } - - /* verify the write -- must do this in order for - write to complete before we do the hardware reset */ - status = read_rom(serial, start_address, - HEADER_SIZE, vheader); - - if (status) { - dbg("%s - can't read header back", __func__); - kfree(vheader); - kfree(header); - kfree(rom_desc); - kfree(ti_manuf_desc); - return status; - } - if (memcmp(vheader, header, HEADER_SIZE)) { - dbg("%s - write download record failed", - __func__); - kfree(vheader); - kfree(header); - kfree(rom_desc); - kfree(ti_manuf_desc); - return -EINVAL; - } - - kfree(vheader); - kfree(header); - - dbg("%s - Start firmware update", __func__); - - /* Tell firmware to copy download image into I2C */ - status = ti_vsend_sync(serial->serial->dev, - UMPC_COPY_DNLD_TO_I2C, 0, 0, NULL, 0); - - dbg("%s - Update complete 0x%x", __func__, status); - if (status) { - dev_err(dev, - "%s - UMPC_COPY_DNLD_TO_I2C failed\n", - __func__); - kfree(rom_desc); - kfree(ti_manuf_desc); - return status; - } - } - - // The device is running the download code - kfree(rom_desc); - kfree(ti_manuf_desc); - return 0; - } - - /********************************************************************/ - /* Boot Mode */ - /********************************************************************/ - dbg("%s - RUNNING IN BOOT MODE", __func__); - - /* Configure the TI device so we can use the BULK pipes for download */ - status = config_boot_dev(serial->serial->dev); - if (status) - return status; - - if (le16_to_cpu(serial->serial->dev->descriptor.idVendor) - != USB_VENDOR_ID_ION) { - dbg("%s - VID = 0x%x", __func__, - le16_to_cpu(serial->serial->dev->descriptor.idVendor)); - serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II; - goto stayinbootmode; - } - - /* We have an ION device (I2c Must be programmed) - Determine I2C image type */ - if (i2c_type_bootmode(serial)) - goto stayinbootmode; - - /* Check for ION Vendor ID and that the I2C is valid */ - if (!check_i2c_image(serial)) { - struct ti_i2c_image_header *header; - int i; - __u8 cs = 0; - __u8 *buffer; - int buffer_size; - int err; - const struct firmware *fw; - const char *fw_name = "edgeport/down3.bin"; - - /* Validate Hardware version number - * Read Manufacturing Descriptor from TI Based Edgeport - */ - ti_manuf_desc = kmalloc(sizeof(*ti_manuf_desc), GFP_KERNEL); - if (!ti_manuf_desc) { - dev_err(dev, "%s - out of memory.\n", __func__); - return -ENOMEM; - } - status = get_manuf_info(serial, (__u8 *)ti_manuf_desc); - if (status) { - kfree(ti_manuf_desc); - goto stayinbootmode; - } - - /* Check for version 2 */ - if (!ignore_cpu_rev && ti_cpu_rev(ti_manuf_desc) < 2) { - dbg("%s - Wrong CPU Rev %d (Must be 2)", - __func__, ti_cpu_rev(ti_manuf_desc)); - kfree(ti_manuf_desc); - goto stayinbootmode; - } - - kfree(ti_manuf_desc); - - /* - * In order to update the I2C firmware we must change the type - * 2 record to type 0xF2. This will force the UMP to come up - * in Boot Mode. Then while in boot mode, the driver will - * download the latest firmware (padded to 15.5k) into the - * UMP ram. Finally when the device comes back up in download - * mode the driver will cause the new firmware to be copied - * from the UMP Ram to I2C and the firmware will update the - * record type from 0xf2 to 0x02. - * - * Do we really have to copy the whole firmware image, - * or could we do this in place! - */ - - /* Allocate a 15.5k buffer + 3 byte header */ - buffer_size = (((1024 * 16) - 512) + - sizeof(struct ti_i2c_image_header)); - buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!buffer) { - dev_err(dev, "%s - out of memory\n", __func__); - return -ENOMEM; - } - - /* Initialize the buffer to 0xff (pad the buffer) */ - memset(buffer, 0xff, buffer_size); - - err = request_firmware(&fw, fw_name, dev); - if (err) { - printk(KERN_ERR "Failed to load image \"%s\" err %d\n", - fw_name, err); - kfree(buffer); - return err; - } - memcpy(buffer, &fw->data[4], fw->size - 4); - release_firmware(fw); - - for (i = sizeof(struct ti_i2c_image_header); - i < buffer_size; i++) { - cs = (__u8)(cs + buffer[i]); - } - - header = (struct ti_i2c_image_header *)buffer; - - /* update length and checksum after padding */ - header->Length = cpu_to_le16((__u16)(buffer_size - - sizeof(struct ti_i2c_image_header))); - header->CheckSum = cs; - - /* Download the operational code */ - dbg("%s - Downloading operational code image (TI UMP)", - __func__); - status = download_code(serial, buffer, buffer_size); - - kfree(buffer); - - if (status) { - dbg("%s - Error downloading operational code image", - __func__); - return status; - } - - /* Device will reboot */ - serial->product_info.TiMode = TI_MODE_TRANSITIONING; - - dbg("%s - Download successful -- Device rebooting...", - __func__); - - /* return an error on purpose */ - return -ENODEV; - } - -stayinbootmode: - /* Eprom is invalid or blank stay in boot mode */ - dbg("%s - STAYING IN BOOT MODE", __func__); - serial->product_info.TiMode = TI_MODE_BOOT; - - return 0; -} - - -static int ti_do_config(struct edgeport_port *port, int feature, int on) -{ - int port_number = port->port->number - port->port->serial->minor; - on = !!on; /* 1 or 0 not bitmask */ - return send_cmd(port->port->serial->dev, - feature, (__u8)(UMPM_UART1_PORT + port_number), - on, NULL, 0); -} - - -static int restore_mcr(struct edgeport_port *port, __u8 mcr) -{ - int status = 0; - - dbg("%s - %x", __func__, mcr); - - status = ti_do_config(port, UMPC_SET_CLR_DTR, mcr & MCR_DTR); - if (status) - return status; - status = ti_do_config(port, UMPC_SET_CLR_RTS, mcr & MCR_RTS); - if (status) - return status; - return ti_do_config(port, UMPC_SET_CLR_LOOPBACK, mcr & MCR_LOOPBACK); -} - -/* Convert TI LSR to standard UART flags */ -static __u8 map_line_status(__u8 ti_lsr) -{ - __u8 lsr = 0; - -#define MAP_FLAG(flagUmp, flagUart) \ - if (ti_lsr & flagUmp) \ - lsr |= flagUart; - - MAP_FLAG(UMP_UART_LSR_OV_MASK, LSR_OVER_ERR) /* overrun */ - MAP_FLAG(UMP_UART_LSR_PE_MASK, LSR_PAR_ERR) /* parity error */ - MAP_FLAG(UMP_UART_LSR_FE_MASK, LSR_FRM_ERR) /* framing error */ - MAP_FLAG(UMP_UART_LSR_BR_MASK, LSR_BREAK) /* break detected */ - MAP_FLAG(UMP_UART_LSR_RX_MASK, LSR_RX_AVAIL) /* rx data available */ - MAP_FLAG(UMP_UART_LSR_TX_MASK, LSR_TX_EMPTY) /* tx hold reg empty */ - -#undef MAP_FLAG - - return lsr; -} - -static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr) -{ - struct async_icount *icount; - struct tty_struct *tty; - - dbg("%s - %02x", __func__, msr); - - if (msr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR | - EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) { - icount = &edge_port->icount; - - /* update input line counters */ - if (msr & EDGEPORT_MSR_DELTA_CTS) - icount->cts++; - if (msr & EDGEPORT_MSR_DELTA_DSR) - icount->dsr++; - if (msr & EDGEPORT_MSR_DELTA_CD) - icount->dcd++; - if (msr & EDGEPORT_MSR_DELTA_RI) - icount->rng++; - wake_up_interruptible(&edge_port->delta_msr_wait); - } - - /* Save the new modem status */ - edge_port->shadow_msr = msr & 0xf0; - - tty = tty_port_tty_get(&edge_port->port->port); - /* handle CTS flow control */ - if (tty && C_CRTSCTS(tty)) { - if (msr & EDGEPORT_MSR_CTS) { - tty->hw_stopped = 0; - tty_wakeup(tty); - } else { - tty->hw_stopped = 1; - } - } - tty_kref_put(tty); -} - -static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data, - __u8 lsr, __u8 data) -{ - struct async_icount *icount; - __u8 new_lsr = (__u8)(lsr & (__u8)(LSR_OVER_ERR | LSR_PAR_ERR | - LSR_FRM_ERR | LSR_BREAK)); - struct tty_struct *tty; - - dbg("%s - %02x", __func__, new_lsr); - - edge_port->shadow_lsr = lsr; - - if (new_lsr & LSR_BREAK) - /* - * Parity and Framing errors only count if they - * occur exclusive of a break being received. - */ - new_lsr &= (__u8)(LSR_OVER_ERR | LSR_BREAK); - - /* Place LSR data byte into Rx buffer */ - if (lsr_data) { - tty = tty_port_tty_get(&edge_port->port->port); - if (tty) { - edge_tty_recv(&edge_port->port->dev, tty, &data, 1); - tty_kref_put(tty); - } - } - - /* update input line counters */ - icount = &edge_port->icount; - if (new_lsr & LSR_BREAK) - icount->brk++; - if (new_lsr & LSR_OVER_ERR) - icount->overrun++; - if (new_lsr & LSR_PAR_ERR) - icount->parity++; - if (new_lsr & LSR_FRM_ERR) - icount->frame++; -} - - -static void edge_interrupt_callback(struct urb *urb) -{ - struct edgeport_serial *edge_serial = urb->context; - struct usb_serial_port *port; - struct edgeport_port *edge_port; - unsigned char *data = urb->transfer_buffer; - int length = urb->actual_length; - int port_number; - int function; - int retval; - __u8 lsr; - __u8 msr; - int status = urb->status; - - dbg("%s", __func__); - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); - return; - default: - dev_err(&urb->dev->dev, "%s - nonzero urb status received: " - "%d\n", __func__, status); - goto exit; - } - - if (!length) { - dbg("%s - no data in urb", __func__); - goto exit; - } - - usb_serial_debug_data(debug, &edge_serial->serial->dev->dev, - __func__, length, data); - - if (length != 2) { - dbg("%s - expecting packet of size 2, got %d", - __func__, length); - goto exit; - } - - port_number = TIUMP_GET_PORT_FROM_CODE(data[0]); - function = TIUMP_GET_FUNC_FROM_CODE(data[0]); - dbg("%s - port_number %d, function %d, info 0x%x", - __func__, port_number, function, data[1]); - port = edge_serial->serial->port[port_number]; - edge_port = usb_get_serial_port_data(port); - if (!edge_port) { - dbg("%s - edge_port not found", __func__); - return; - } - switch (function) { - case TIUMP_INTERRUPT_CODE_LSR: - lsr = map_line_status(data[1]); - if (lsr & UMP_UART_LSR_DATA_MASK) { - /* Save the LSR event for bulk read - completion routine */ - dbg("%s - LSR Event Port %u LSR Status = %02x", - __func__, port_number, lsr); - edge_port->lsr_event = 1; - edge_port->lsr_mask = lsr; - } else { - dbg("%s - ===== Port %d LSR Status = %02x ======", - __func__, port_number, lsr); - handle_new_lsr(edge_port, 0, lsr, 0); - } - break; - - case TIUMP_INTERRUPT_CODE_MSR: /* MSR */ - /* Copy MSR from UMP */ - msr = data[1]; - dbg("%s - ===== Port %u MSR Status = %02x ======", - __func__, port_number, msr); - handle_new_msr(edge_port, msr); - break; - - default: - dev_err(&urb->dev->dev, - "%s - Unknown Interrupt code from UMP %x\n", - __func__, data[1]); - break; - - } - -exit: - retval = usb_submit_urb(urb, GFP_ATOMIC); - if (retval) - dev_err(&urb->dev->dev, - "%s - usb_submit_urb failed with result %d\n", - __func__, retval); -} - -static void edge_bulk_in_callback(struct urb *urb) -{ - struct edgeport_port *edge_port = urb->context; - unsigned char *data = urb->transfer_buffer; - struct tty_struct *tty; - int retval = 0; - int port_number; - int status = urb->status; - - dbg("%s", __func__); - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); - return; - default: - dev_err(&urb->dev->dev, - "%s - nonzero read bulk status received: %d\n", - __func__, status); - } - - if (status == -EPIPE) - goto exit; - - if (status) { - dev_err(&urb->dev->dev, "%s - stopping read!\n", __func__); - return; - } - - port_number = edge_port->port->number - edge_port->port->serial->minor; - - if (edge_port->lsr_event) { - edge_port->lsr_event = 0; - dbg("%s ===== Port %u LSR Status = %02x, Data = %02x ======", - __func__, port_number, edge_port->lsr_mask, *data); - handle_new_lsr(edge_port, 1, edge_port->lsr_mask, *data); - /* Adjust buffer length/pointer */ - --urb->actual_length; - ++data; - } - - tty = tty_port_tty_get(&edge_port->port->port); - if (tty && urb->actual_length) { - usb_serial_debug_data(debug, &edge_port->port->dev, - __func__, urb->actual_length, data); - if (edge_port->close_pending) - dbg("%s - close pending, dropping data on the floor", - __func__); - else - edge_tty_recv(&edge_port->port->dev, tty, data, - urb->actual_length); - edge_port->icount.rx += urb->actual_length; - } - tty_kref_put(tty); - -exit: - /* continue read unless stopped */ - spin_lock(&edge_port->ep_lock); - if (edge_port->ep_read_urb_state == EDGE_READ_URB_RUNNING) - retval = usb_submit_urb(urb, GFP_ATOMIC); - else if (edge_port->ep_read_urb_state == EDGE_READ_URB_STOPPING) - edge_port->ep_read_urb_state = EDGE_READ_URB_STOPPED; - - spin_unlock(&edge_port->ep_lock); - if (retval) - dev_err(&urb->dev->dev, - "%s - usb_submit_urb failed with result %d\n", - __func__, retval); -} - -static void edge_tty_recv(struct device *dev, struct tty_struct *tty, - unsigned char *data, int length) -{ - int queued; - - queued = tty_insert_flip_string(tty, data, length); - if (queued < length) - dev_err(dev, "%s - dropping data, %d bytes lost\n", - __func__, length - queued); - tty_flip_buffer_push(tty); -} - -static void edge_bulk_out_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - int status = urb->status; - struct tty_struct *tty; - - dbg("%s - port %d", __func__, port->number); - - edge_port->ep_write_urb_in_use = 0; - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); - return; - default: - dev_err_console(port, "%s - nonzero write bulk status " - "received: %d\n", __func__, status); - } - - /* send any buffered data */ - tty = tty_port_tty_get(&port->port); - edge_send(tty); - tty_kref_put(tty); -} - -static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - struct edgeport_serial *edge_serial; - struct usb_device *dev; - struct urb *urb; - int port_number; - int status; - u16 open_settings; - u8 transaction_timeout; - - dbg("%s - port %d", __func__, port->number); - - if (edge_port == NULL) - return -ENODEV; - - port_number = port->number - port->serial->minor; - switch (port_number) { - case 0: - edge_port->uart_base = UMPMEM_BASE_UART1; - edge_port->dma_address = UMPD_OEDB1_ADDRESS; - break; - case 1: - edge_port->uart_base = UMPMEM_BASE_UART2; - edge_port->dma_address = UMPD_OEDB2_ADDRESS; - break; - default: - dev_err(&port->dev, "Unknown port number!!!\n"); - return -ENODEV; - } - - dbg("%s - port_number = %d, uart_base = %04x, dma_address = %04x", - __func__, port_number, edge_port->uart_base, - edge_port->dma_address); - - dev = port->serial->dev; - - memset(&(edge_port->icount), 0x00, sizeof(edge_port->icount)); - init_waitqueue_head(&edge_port->delta_msr_wait); - - /* turn off loopback */ - status = ti_do_config(edge_port, UMPC_SET_CLR_LOOPBACK, 0); - if (status) { - dev_err(&port->dev, - "%s - cannot send clear loopback command, %d\n", - __func__, status); - return status; - } - - /* set up the port settings */ - if (tty) - edge_set_termios(tty, port, tty->termios); - - /* open up the port */ - - /* milliseconds to timeout for DMA transfer */ - transaction_timeout = 2; - - edge_port->ump_read_timeout = - max(20, ((transaction_timeout * 3) / 2)); - - /* milliseconds to timeout for DMA transfer */ - open_settings = (u8)(UMP_DMA_MODE_CONTINOUS | - UMP_PIPE_TRANS_TIMEOUT_ENA | - (transaction_timeout << 2)); - - dbg("%s - Sending UMPC_OPEN_PORT", __func__); - - /* Tell TI to open and start the port */ - status = send_cmd(dev, UMPC_OPEN_PORT, - (u8)(UMPM_UART1_PORT + port_number), open_settings, NULL, 0); - if (status) { - dev_err(&port->dev, "%s - cannot send open command, %d\n", - __func__, status); - return status; - } - - /* Start the DMA? */ - status = send_cmd(dev, UMPC_START_PORT, - (u8)(UMPM_UART1_PORT + port_number), 0, NULL, 0); - if (status) { - dev_err(&port->dev, "%s - cannot send start DMA command, %d\n", - __func__, status); - return status; - } - - /* Clear TX and RX buffers in UMP */ - status = purge_port(port, UMP_PORT_DIR_OUT | UMP_PORT_DIR_IN); - if (status) { - dev_err(&port->dev, - "%s - cannot send clear buffers command, %d\n", - __func__, status); - return status; - } - - /* Read Initial MSR */ - status = ti_vread_sync(dev, UMPC_READ_MSR, 0, - (__u16)(UMPM_UART1_PORT + port_number), - &edge_port->shadow_msr, 1); - if (status) { - dev_err(&port->dev, "%s - cannot send read MSR command, %d\n", - __func__, status); - return status; - } - - dbg("ShadowMSR 0x%X", edge_port->shadow_msr); - - /* Set Initial MCR */ - edge_port->shadow_mcr = MCR_RTS | MCR_DTR; - dbg("ShadowMCR 0x%X", edge_port->shadow_mcr); - - edge_serial = edge_port->edge_serial; - if (mutex_lock_interruptible(&edge_serial->es_lock)) - return -ERESTARTSYS; - if (edge_serial->num_ports_open == 0) { - /* we are the first port to open, post the interrupt urb */ - urb = edge_serial->serial->port[0]->interrupt_in_urb; - if (!urb) { - dev_err(&port->dev, - "%s - no interrupt urb present, exiting\n", - __func__); - status = -EINVAL; - goto release_es_lock; - } - urb->context = edge_serial; - status = usb_submit_urb(urb, GFP_KERNEL); - if (status) { - dev_err(&port->dev, - "%s - usb_submit_urb failed with value %d\n", - __func__, status); - goto release_es_lock; - } - } - - /* - * reset the data toggle on the bulk endpoints to work around bug in - * host controllers where things get out of sync some times - */ - usb_clear_halt(dev, port->write_urb->pipe); - usb_clear_halt(dev, port->read_urb->pipe); - - /* start up our bulk read urb */ - urb = port->read_urb; - if (!urb) { - dev_err(&port->dev, "%s - no read urb present, exiting\n", - __func__); - status = -EINVAL; - goto unlink_int_urb; - } - edge_port->ep_read_urb_state = EDGE_READ_URB_RUNNING; - urb->context = edge_port; - status = usb_submit_urb(urb, GFP_KERNEL); - if (status) { - dev_err(&port->dev, - "%s - read bulk usb_submit_urb failed with value %d\n", - __func__, status); - goto unlink_int_urb; - } - - ++edge_serial->num_ports_open; - - dbg("%s - exited", __func__); - - goto release_es_lock; - -unlink_int_urb: - if (edge_port->edge_serial->num_ports_open == 0) - usb_kill_urb(port->serial->port[0]->interrupt_in_urb); -release_es_lock: - mutex_unlock(&edge_serial->es_lock); - return status; -} - -static void edge_close(struct usb_serial_port *port) -{ - struct edgeport_serial *edge_serial; - struct edgeport_port *edge_port; - int port_number; - int status; - - dbg("%s - port %d", __func__, port->number); - - edge_serial = usb_get_serial_data(port->serial); - edge_port = usb_get_serial_port_data(port); - if (edge_serial == NULL || edge_port == NULL) - return; - - /* The bulkreadcompletion routine will check - * this flag and dump add read data */ - edge_port->close_pending = 1; - - /* chase the port close and flush */ - chase_port(edge_port, (HZ * closing_wait) / 100, 1); - - usb_kill_urb(port->read_urb); - usb_kill_urb(port->write_urb); - edge_port->ep_write_urb_in_use = 0; - - /* assuming we can still talk to the device, - * send a close port command to it */ - dbg("%s - send umpc_close_port", __func__); - port_number = port->number - port->serial->minor; - status = send_cmd(port->serial->dev, - UMPC_CLOSE_PORT, - (__u8)(UMPM_UART1_PORT + port_number), - 0, - NULL, - 0); - mutex_lock(&edge_serial->es_lock); - --edge_port->edge_serial->num_ports_open; - if (edge_port->edge_serial->num_ports_open <= 0) { - /* last port is now closed, let's shut down our interrupt urb */ - usb_kill_urb(port->serial->port[0]->interrupt_in_urb); - edge_port->edge_serial->num_ports_open = 0; - } - mutex_unlock(&edge_serial->es_lock); - edge_port->close_pending = 0; - - dbg("%s - exited", __func__); -} - -static int edge_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *data, int count) -{ - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - - dbg("%s - port %d", __func__, port->number); - - if (count == 0) { - dbg("%s - write request of 0 bytes", __func__); - return 0; - } - - if (edge_port == NULL) - return -ENODEV; - if (edge_port->close_pending == 1) - return -ENODEV; - - count = kfifo_in_locked(&edge_port->write_fifo, data, count, - &edge_port->ep_lock); - edge_send(tty); - - return count; -} - -static void edge_send(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - int count, result; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - unsigned long flags; - - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&edge_port->ep_lock, flags); - - if (edge_port->ep_write_urb_in_use) { - spin_unlock_irqrestore(&edge_port->ep_lock, flags); - return; - } - - count = kfifo_out(&edge_port->write_fifo, - port->write_urb->transfer_buffer, - port->bulk_out_size); - - if (count == 0) { - spin_unlock_irqrestore(&edge_port->ep_lock, flags); - return; - } - - edge_port->ep_write_urb_in_use = 1; - - spin_unlock_irqrestore(&edge_port->ep_lock, flags); - - usb_serial_debug_data(debug, &port->dev, __func__, count, - port->write_urb->transfer_buffer); - - /* set up our urb */ - port->write_urb->transfer_buffer_length = count; - - /* send the data out the bulk port */ - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (result) { - dev_err_console(port, - "%s - failed submitting write urb, error %d\n", - __func__, result); - edge_port->ep_write_urb_in_use = 0; - /* TODO: reschedule edge_send */ - } else - edge_port->icount.tx += count; - - /* wakeup any process waiting for writes to complete */ - /* there is now more room in the buffer for new writes */ - if (tty) - tty_wakeup(tty); -} - -static int edge_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - int room = 0; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - if (edge_port == NULL) - return 0; - if (edge_port->close_pending == 1) - return 0; - - spin_lock_irqsave(&edge_port->ep_lock, flags); - room = kfifo_avail(&edge_port->write_fifo); - spin_unlock_irqrestore(&edge_port->ep_lock, flags); - - dbg("%s - returns %d", __func__, room); - return room; -} - -static int edge_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - int chars = 0; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - if (edge_port == NULL) - return 0; - if (edge_port->close_pending == 1) - return 0; - - spin_lock_irqsave(&edge_port->ep_lock, flags); - chars = kfifo_len(&edge_port->write_fifo); - spin_unlock_irqrestore(&edge_port->ep_lock, flags); - - dbg("%s - returns %d", __func__, chars); - return chars; -} - -static void edge_throttle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - int status; - - dbg("%s - port %d", __func__, port->number); - - if (edge_port == NULL) - return; - - /* if we are implementing XON/XOFF, send the stop character */ - if (I_IXOFF(tty)) { - unsigned char stop_char = STOP_CHAR(tty); - status = edge_write(tty, port, &stop_char, 1); - if (status <= 0) { - dev_err(&port->dev, "%s - failed to write stop character, %d\n", __func__, status); - } - } - - /* if we are implementing RTS/CTS, stop reads */ - /* and the Edgeport will clear the RTS line */ - if (C_CRTSCTS(tty)) - stop_read(edge_port); - -} - -static void edge_unthrottle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - int status; - - dbg("%s - port %d", __func__, port->number); - - if (edge_port == NULL) - return; - - /* if we are implementing XON/XOFF, send the start character */ - if (I_IXOFF(tty)) { - unsigned char start_char = START_CHAR(tty); - status = edge_write(tty, port, &start_char, 1); - if (status <= 0) { - dev_err(&port->dev, "%s - failed to write start character, %d\n", __func__, status); - } - } - /* if we are implementing RTS/CTS, restart reads */ - /* are the Edgeport will assert the RTS line */ - if (C_CRTSCTS(tty)) { - status = restart_read(edge_port); - if (status) - dev_err(&port->dev, - "%s - read bulk usb_submit_urb failed: %d\n", - __func__, status); - } - -} - -static void stop_read(struct edgeport_port *edge_port) -{ - unsigned long flags; - - spin_lock_irqsave(&edge_port->ep_lock, flags); - - if (edge_port->ep_read_urb_state == EDGE_READ_URB_RUNNING) - edge_port->ep_read_urb_state = EDGE_READ_URB_STOPPING; - edge_port->shadow_mcr &= ~MCR_RTS; - - spin_unlock_irqrestore(&edge_port->ep_lock, flags); -} - -static int restart_read(struct edgeport_port *edge_port) -{ - struct urb *urb; - int status = 0; - unsigned long flags; - - spin_lock_irqsave(&edge_port->ep_lock, flags); - - if (edge_port->ep_read_urb_state == EDGE_READ_URB_STOPPED) { - urb = edge_port->port->read_urb; - status = usb_submit_urb(urb, GFP_ATOMIC); - } - edge_port->ep_read_urb_state = EDGE_READ_URB_RUNNING; - edge_port->shadow_mcr |= MCR_RTS; - - spin_unlock_irqrestore(&edge_port->ep_lock, flags); - - return status; -} - -static void change_port_settings(struct tty_struct *tty, - struct edgeport_port *edge_port, struct ktermios *old_termios) -{ - struct ump_uart_config *config; - int baud; - unsigned cflag; - int status; - int port_number = edge_port->port->number - - edge_port->port->serial->minor; - - dbg("%s - port %d", __func__, edge_port->port->number); - - config = kmalloc (sizeof (*config), GFP_KERNEL); - if (!config) { - *tty->termios = *old_termios; - dev_err(&edge_port->port->dev, "%s - out of memory\n", - __func__); - return; - } - - cflag = tty->termios->c_cflag; - - config->wFlags = 0; - - /* These flags must be set */ - config->wFlags |= UMP_MASK_UART_FLAGS_RECEIVE_MS_INT; - config->wFlags |= UMP_MASK_UART_FLAGS_AUTO_START_ON_ERR; - config->bUartMode = (__u8)(edge_port->bUartMode); - - switch (cflag & CSIZE) { - case CS5: - config->bDataBits = UMP_UART_CHAR5BITS; - dbg("%s - data bits = 5", __func__); - break; - case CS6: - config->bDataBits = UMP_UART_CHAR6BITS; - dbg("%s - data bits = 6", __func__); - break; - case CS7: - config->bDataBits = UMP_UART_CHAR7BITS; - dbg("%s - data bits = 7", __func__); - break; - default: - case CS8: - config->bDataBits = UMP_UART_CHAR8BITS; - dbg("%s - data bits = 8", __func__); - break; - } - - if (cflag & PARENB) { - if (cflag & PARODD) { - config->wFlags |= UMP_MASK_UART_FLAGS_PARITY; - config->bParity = UMP_UART_ODDPARITY; - dbg("%s - parity = odd", __func__); - } else { - config->wFlags |= UMP_MASK_UART_FLAGS_PARITY; - config->bParity = UMP_UART_EVENPARITY; - dbg("%s - parity = even", __func__); - } - } else { - config->bParity = UMP_UART_NOPARITY; - dbg("%s - parity = none", __func__); - } - - if (cflag & CSTOPB) { - config->bStopBits = UMP_UART_STOPBIT2; - dbg("%s - stop bits = 2", __func__); - } else { - config->bStopBits = UMP_UART_STOPBIT1; - dbg("%s - stop bits = 1", __func__); - } - - /* figure out the flow control settings */ - if (cflag & CRTSCTS) { - config->wFlags |= UMP_MASK_UART_FLAGS_OUT_X_CTS_FLOW; - config->wFlags |= UMP_MASK_UART_FLAGS_RTS_FLOW; - dbg("%s - RTS/CTS is enabled", __func__); - } else { - dbg("%s - RTS/CTS is disabled", __func__); - tty->hw_stopped = 0; - restart_read(edge_port); - } - - /* if we are implementing XON/XOFF, set the start and stop - character in the device */ - config->cXon = START_CHAR(tty); - config->cXoff = STOP_CHAR(tty); - - /* if we are implementing INBOUND XON/XOFF */ - if (I_IXOFF(tty)) { - config->wFlags |= UMP_MASK_UART_FLAGS_IN_X; - dbg("%s - INBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", - __func__, config->cXon, config->cXoff); - } else - dbg("%s - INBOUND XON/XOFF is disabled", __func__); - - /* if we are implementing OUTBOUND XON/XOFF */ - if (I_IXON(tty)) { - config->wFlags |= UMP_MASK_UART_FLAGS_OUT_X; - dbg("%s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x", - __func__, config->cXon, config->cXoff); - } else - dbg("%s - OUTBOUND XON/XOFF is disabled", __func__); - - tty->termios->c_cflag &= ~CMSPAR; - - /* Round the baud rate */ - baud = tty_get_baud_rate(tty); - if (!baud) { - /* pick a default, any default... */ - baud = 9600; - } else - tty_encode_baud_rate(tty, baud, baud); - - edge_port->baud_rate = baud; - config->wBaudRate = (__u16)((461550L + baud/2) / baud); - - /* FIXME: Recompute actual baud from divisor here */ - - dbg("%s - baud rate = %d, wBaudRate = %d", __func__, baud, - config->wBaudRate); - - dbg("wBaudRate: %d", (int)(461550L / config->wBaudRate)); - dbg("wFlags: 0x%x", config->wFlags); - dbg("bDataBits: %d", config->bDataBits); - dbg("bParity: %d", config->bParity); - dbg("bStopBits: %d", config->bStopBits); - dbg("cXon: %d", config->cXon); - dbg("cXoff: %d", config->cXoff); - dbg("bUartMode: %d", config->bUartMode); - - /* move the word values into big endian mode */ - cpu_to_be16s(&config->wFlags); - cpu_to_be16s(&config->wBaudRate); - - status = send_cmd(edge_port->port->serial->dev, UMPC_SET_CONFIG, - (__u8)(UMPM_UART1_PORT + port_number), - 0, (__u8 *)config, sizeof(*config)); - if (status) - dbg("%s - error %d when trying to write config to device", - __func__, status); - kfree(config); -} - -static void edge_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) -{ - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - unsigned int cflag; - - cflag = tty->termios->c_cflag; - - dbg("%s - clfag %08x iflag %08x", __func__, - tty->termios->c_cflag, tty->termios->c_iflag); - dbg("%s - old clfag %08x old iflag %08x", __func__, - old_termios->c_cflag, old_termios->c_iflag); - dbg("%s - port %d", __func__, port->number); - - if (edge_port == NULL) - return; - /* change the port settings to the new ones specified */ - change_port_settings(tty, edge_port, old_termios); -} - -static int edge_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - unsigned int mcr; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&edge_port->ep_lock, flags); - mcr = edge_port->shadow_mcr; - if (set & TIOCM_RTS) - mcr |= MCR_RTS; - if (set & TIOCM_DTR) - mcr |= MCR_DTR; - if (set & TIOCM_LOOP) - mcr |= MCR_LOOPBACK; - - if (clear & TIOCM_RTS) - mcr &= ~MCR_RTS; - if (clear & TIOCM_DTR) - mcr &= ~MCR_DTR; - if (clear & TIOCM_LOOP) - mcr &= ~MCR_LOOPBACK; - - edge_port->shadow_mcr = mcr; - spin_unlock_irqrestore(&edge_port->ep_lock, flags); - - restore_mcr(edge_port, mcr); - return 0; -} - -static int edge_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - unsigned int result = 0; - unsigned int msr; - unsigned int mcr; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&edge_port->ep_lock, flags); - - msr = edge_port->shadow_msr; - mcr = edge_port->shadow_mcr; - result = ((mcr & MCR_DTR) ? TIOCM_DTR: 0) /* 0x002 */ - | ((mcr & MCR_RTS) ? TIOCM_RTS: 0) /* 0x004 */ - | ((msr & EDGEPORT_MSR_CTS) ? TIOCM_CTS: 0) /* 0x020 */ - | ((msr & EDGEPORT_MSR_CD) ? TIOCM_CAR: 0) /* 0x040 */ - | ((msr & EDGEPORT_MSR_RI) ? TIOCM_RI: 0) /* 0x080 */ - | ((msr & EDGEPORT_MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */ - - - dbg("%s -- %x", __func__, result); - spin_unlock_irqrestore(&edge_port->ep_lock, flags); - - return result; -} - -static int edge_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - struct async_icount *ic = &edge_port->icount; - - icount->cts = ic->cts; - icount->dsr = ic->dsr; - icount->rng = ic->rng; - icount->dcd = ic->dcd; - icount->tx = ic->tx; - icount->rx = ic->rx; - icount->frame = ic->frame; - icount->parity = ic->parity; - icount->overrun = ic->overrun; - icount->brk = ic->brk; - icount->buf_overrun = ic->buf_overrun; - return 0; -} - -static int get_serial_info(struct edgeport_port *edge_port, - struct serial_struct __user *retinfo) -{ - struct serial_struct tmp; - - if (!retinfo) - return -EFAULT; - - memset(&tmp, 0, sizeof(tmp)); - - tmp.type = PORT_16550A; - tmp.line = edge_port->port->serial->minor; - tmp.port = edge_port->port->number; - tmp.irq = 0; - tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; - tmp.xmit_fifo_size = edge_port->port->bulk_out_size; - tmp.baud_base = 9600; - tmp.close_delay = 5*HZ; - tmp.closing_wait = closing_wait; - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - return 0; -} - -static int edge_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - struct async_icount cnow; - struct async_icount cprev; - - dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd); - - switch (cmd) { - case TIOCGSERIAL: - dbg("%s - (%d) TIOCGSERIAL", __func__, port->number); - return get_serial_info(edge_port, - (struct serial_struct __user *) arg); - case TIOCMIWAIT: - dbg("%s - (%d) TIOCMIWAIT", __func__, port->number); - cprev = edge_port->icount; - while (1) { - interruptible_sleep_on(&edge_port->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - cnow = edge_port->icount; - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { - return 0; - } - cprev = cnow; - } - /* not reached */ - break; - } - return -ENOIOCTLCMD; -} - -static void edge_break(struct tty_struct *tty, int break_state) -{ - struct usb_serial_port *port = tty->driver_data; - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - int status; - int bv = 0; /* Off */ - - dbg("%s - state = %d", __func__, break_state); - - /* chase the port close */ - chase_port(edge_port, 0, 0); - - if (break_state == -1) - bv = 1; /* On */ - status = ti_do_config(edge_port, UMPC_SET_CLR_BREAK, bv); - if (status) - dbg("%s - error %d sending break set/clear command.", - __func__, status); -} - -static int edge_startup(struct usb_serial *serial) -{ - struct edgeport_serial *edge_serial; - struct edgeport_port *edge_port; - struct usb_device *dev; - int status; - int i; - - dev = serial->dev; - - /* create our private serial structure */ - edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL); - if (edge_serial == NULL) { - dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__); - return -ENOMEM; - } - mutex_init(&edge_serial->es_lock); - edge_serial->serial = serial; - usb_set_serial_data(serial, edge_serial); - - status = download_fw(edge_serial); - if (status) { - kfree(edge_serial); - return status; - } - - /* set up our port private structures */ - for (i = 0; i < serial->num_ports; ++i) { - edge_port = kzalloc(sizeof(struct edgeport_port), GFP_KERNEL); - if (edge_port == NULL) { - dev_err(&serial->dev->dev, "%s - Out of memory\n", - __func__); - goto cleanup; - } - spin_lock_init(&edge_port->ep_lock); - if (kfifo_alloc(&edge_port->write_fifo, EDGE_OUT_BUF_SIZE, - GFP_KERNEL)) { - dev_err(&serial->dev->dev, "%s - Out of memory\n", - __func__); - kfree(edge_port); - goto cleanup; - } - edge_port->port = serial->port[i]; - edge_port->edge_serial = edge_serial; - usb_set_serial_port_data(serial->port[i], edge_port); - edge_port->bUartMode = default_uart_mode; - } - - return 0; - -cleanup: - for (--i; i >= 0; --i) { - edge_port = usb_get_serial_port_data(serial->port[i]); - kfifo_free(&edge_port->write_fifo); - kfree(edge_port); - usb_set_serial_port_data(serial->port[i], NULL); - } - kfree(edge_serial); - usb_set_serial_data(serial, NULL); - return -ENOMEM; -} - -static void edge_disconnect(struct usb_serial *serial) -{ - dbg("%s", __func__); -} - -static void edge_release(struct usb_serial *serial) -{ - int i; - struct edgeport_port *edge_port; - - dbg("%s", __func__); - - for (i = 0; i < serial->num_ports; ++i) { - edge_port = usb_get_serial_port_data(serial->port[i]); - kfifo_free(&edge_port->write_fifo); - kfree(edge_port); - } - kfree(usb_get_serial_data(serial)); -} - - -/* Sysfs Attributes */ - -static ssize_t show_uart_mode(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct usb_serial_port *port = to_usb_serial_port(dev); - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - - return sprintf(buf, "%d\n", edge_port->bUartMode); -} - -static ssize_t store_uart_mode(struct device *dev, - struct device_attribute *attr, const char *valbuf, size_t count) -{ - struct usb_serial_port *port = to_usb_serial_port(dev); - struct edgeport_port *edge_port = usb_get_serial_port_data(port); - unsigned int v = simple_strtoul(valbuf, NULL, 0); - - dbg("%s: setting uart_mode = %d", __func__, v); - - if (v < 256) - edge_port->bUartMode = v; - else - dev_err(dev, "%s - uart_mode %d is invalid\n", __func__, v); - - return count; -} - -static DEVICE_ATTR(uart_mode, S_IWUSR | S_IRUGO, show_uart_mode, - store_uart_mode); - -static int edge_create_sysfs_attrs(struct usb_serial_port *port) -{ - return device_create_file(&port->dev, &dev_attr_uart_mode); -} - -static int edge_remove_sysfs_attrs(struct usb_serial_port *port) -{ - device_remove_file(&port->dev, &dev_attr_uart_mode); - return 0; -} - - -static struct usb_serial_driver edgeport_1port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "edgeport_ti_1", - }, - .description = "Edgeport TI 1 port adapter", - .id_table = edgeport_1port_id_table, - .num_ports = 1, - .open = edge_open, - .close = edge_close, - .throttle = edge_throttle, - .unthrottle = edge_unthrottle, - .attach = edge_startup, - .disconnect = edge_disconnect, - .release = edge_release, - .port_probe = edge_create_sysfs_attrs, - .port_remove = edge_remove_sysfs_attrs, - .ioctl = edge_ioctl, - .set_termios = edge_set_termios, - .tiocmget = edge_tiocmget, - .tiocmset = edge_tiocmset, - .get_icount = edge_get_icount, - .write = edge_write, - .write_room = edge_write_room, - .chars_in_buffer = edge_chars_in_buffer, - .break_ctl = edge_break, - .read_int_callback = edge_interrupt_callback, - .read_bulk_callback = edge_bulk_in_callback, - .write_bulk_callback = edge_bulk_out_callback, -}; - -static struct usb_serial_driver edgeport_2port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "edgeport_ti_2", - }, - .description = "Edgeport TI 2 port adapter", - .id_table = edgeport_2port_id_table, - .num_ports = 2, - .open = edge_open, - .close = edge_close, - .throttle = edge_throttle, - .unthrottle = edge_unthrottle, - .attach = edge_startup, - .disconnect = edge_disconnect, - .release = edge_release, - .port_probe = edge_create_sysfs_attrs, - .port_remove = edge_remove_sysfs_attrs, - .ioctl = edge_ioctl, - .set_termios = edge_set_termios, - .tiocmget = edge_tiocmget, - .tiocmset = edge_tiocmset, - .write = edge_write, - .write_room = edge_write_room, - .chars_in_buffer = edge_chars_in_buffer, - .break_ctl = edge_break, - .read_int_callback = edge_interrupt_callback, - .read_bulk_callback = edge_bulk_in_callback, - .write_bulk_callback = edge_bulk_out_callback, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &edgeport_1port_device, &edgeport_2port_device, NULL -}; - -module_usb_serial_driver(io_driver, serial_drivers); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE("edgeport/down3.bin"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - -module_param(closing_wait, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(closing_wait, "Maximum wait for data to drain, in .01 secs"); - -module_param(ignore_cpu_rev, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(ignore_cpu_rev, - "Ignore the cpu revision when connecting to a device"); - -module_param(default_uart_mode, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(default_uart_mode, "Default uart_mode, 0=RS232, ..."); diff --git a/ANDROID_3.4.5/drivers/usb/serial/io_ti.h b/ANDROID_3.4.5/drivers/usb/serial/io_ti.h deleted file mode 100644 index 1bd67b24..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/io_ti.h +++ /dev/null @@ -1,186 +0,0 @@ -/***************************************************************************** - * - * Copyright (C) 1997-2002 Inside Out Networks, Inc. - * - * 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. - * - * - * Feb-16-2001 DMI Added I2C structure definitions - * May-29-2002 gkh Ported to Linux - * - * - ******************************************************************************/ - -#ifndef _IO_TI_H_ -#define _IO_TI_H_ - -/* Address Space */ -#define DTK_ADDR_SPACE_XDATA 0x03 /* Addr is placed in XDATA space */ -#define DTK_ADDR_SPACE_I2C_TYPE_II 0x82 /* Addr is placed in I2C area */ -#define DTK_ADDR_SPACE_I2C_TYPE_III 0x83 /* Addr is placed in I2C area */ - -/* UART Defines */ -#define UMPMEM_BASE_UART1 0xFFA0 /* UMP UART1 base address */ -#define UMPMEM_BASE_UART2 0xFFB0 /* UMP UART2 base address */ -#define UMPMEM_OFFS_UART_LSR 0x05 /* UMP UART LSR register offset */ - -/* Bits per character */ -#define UMP_UART_CHAR5BITS 0x00 -#define UMP_UART_CHAR6BITS 0x01 -#define UMP_UART_CHAR7BITS 0x02 -#define UMP_UART_CHAR8BITS 0x03 - -/* Parity */ -#define UMP_UART_NOPARITY 0x00 -#define UMP_UART_ODDPARITY 0x01 -#define UMP_UART_EVENPARITY 0x02 -#define UMP_UART_MARKPARITY 0x03 -#define UMP_UART_SPACEPARITY 0x04 - -/* Stop bits */ -#define UMP_UART_STOPBIT1 0x00 -#define UMP_UART_STOPBIT15 0x01 -#define UMP_UART_STOPBIT2 0x02 - -/* Line status register masks */ -#define UMP_UART_LSR_OV_MASK 0x01 -#define UMP_UART_LSR_PE_MASK 0x02 -#define UMP_UART_LSR_FE_MASK 0x04 -#define UMP_UART_LSR_BR_MASK 0x08 -#define UMP_UART_LSR_ER_MASK 0x0F -#define UMP_UART_LSR_RX_MASK 0x10 -#define UMP_UART_LSR_TX_MASK 0x20 - -#define UMP_UART_LSR_DATA_MASK (LSR_PAR_ERR | LSR_FRM_ERR | LSR_BREAK) - -/* Port Settings Constants) */ -#define UMP_MASK_UART_FLAGS_RTS_FLOW 0x0001 -#define UMP_MASK_UART_FLAGS_RTS_DISABLE 0x0002 -#define UMP_MASK_UART_FLAGS_PARITY 0x0008 -#define UMP_MASK_UART_FLAGS_OUT_X_DSR_FLOW 0x0010 -#define UMP_MASK_UART_FLAGS_OUT_X_CTS_FLOW 0x0020 -#define UMP_MASK_UART_FLAGS_OUT_X 0x0040 -#define UMP_MASK_UART_FLAGS_OUT_XA 0x0080 -#define UMP_MASK_UART_FLAGS_IN_X 0x0100 -#define UMP_MASK_UART_FLAGS_DTR_FLOW 0x0800 -#define UMP_MASK_UART_FLAGS_DTR_DISABLE 0x1000 -#define UMP_MASK_UART_FLAGS_RECEIVE_MS_INT 0x2000 -#define UMP_MASK_UART_FLAGS_AUTO_START_ON_ERR 0x4000 - -#define UMP_DMA_MODE_CONTINOUS 0x01 -#define UMP_PIPE_TRANS_TIMEOUT_ENA 0x80 -#define UMP_PIPE_TRANSFER_MODE_MASK 0x03 -#define UMP_PIPE_TRANS_TIMEOUT_MASK 0x7C - -/* Purge port Direction Mask Bits */ -#define UMP_PORT_DIR_OUT 0x01 -#define UMP_PORT_DIR_IN 0x02 - -/* Address of Port 0 */ -#define UMPM_UART1_PORT 0x03 - -/* Commands */ -#define UMPC_SET_CONFIG 0x05 -#define UMPC_OPEN_PORT 0x06 -#define UMPC_CLOSE_PORT 0x07 -#define UMPC_START_PORT 0x08 -#define UMPC_STOP_PORT 0x09 -#define UMPC_TEST_PORT 0x0A -#define UMPC_PURGE_PORT 0x0B - -/* Force the Firmware to complete the current Read */ -#define UMPC_COMPLETE_READ 0x80 -/* Force UMP back into BOOT Mode */ -#define UMPC_HARDWARE_RESET 0x81 -/* - * Copy current download image to type 0xf2 record in 16k I2C - * firmware will change 0xff record to type 2 record when complete - */ -#define UMPC_COPY_DNLD_TO_I2C 0x82 - -/* - * Special function register commands - * wIndex is register address - * wValue is MSB/LSB mask/data - */ -#define UMPC_WRITE_SFR 0x83 /* Write SFR Register */ - -/* wIndex is register address */ -#define UMPC_READ_SFR 0x84 /* Read SRF Register */ - -/* Set or Clear DTR (wValue bit 0 Set/Clear) wIndex ModuleID (port) */ -#define UMPC_SET_CLR_DTR 0x85 - -/* Set or Clear RTS (wValue bit 0 Set/Clear) wIndex ModuleID (port) */ -#define UMPC_SET_CLR_RTS 0x86 - -/* Set or Clear LOOPBACK (wValue bit 0 Set/Clear) wIndex ModuleID (port) */ -#define UMPC_SET_CLR_LOOPBACK 0x87 - -/* Set or Clear BREAK (wValue bit 0 Set/Clear) wIndex ModuleID (port) */ -#define UMPC_SET_CLR_BREAK 0x88 - -/* Read MSR wIndex ModuleID (port) */ -#define UMPC_READ_MSR 0x89 - -/* Toolkit commands */ -/* Read-write group */ -#define UMPC_MEMORY_READ 0x92 -#define UMPC_MEMORY_WRITE 0x93 - -/* - * UMP DMA Definitions - */ -#define UMPD_OEDB1_ADDRESS 0xFF08 -#define UMPD_OEDB2_ADDRESS 0xFF10 - -struct out_endpoint_desc_block { - __u8 Configuration; - __u8 XBufAddr; - __u8 XByteCount; - __u8 Unused1; - __u8 Unused2; - __u8 YBufAddr; - __u8 YByteCount; - __u8 BufferSize; -} __attribute__((packed)); - - -/* - * TYPE DEFINITIONS - * Structures for Firmware commands - */ -/* UART settings */ -struct ump_uart_config { - __u16 wBaudRate; /* Baud rate */ - __u16 wFlags; /* Bitmap mask of flags */ - __u8 bDataBits; /* 5..8 - data bits per character */ - __u8 bParity; /* Parity settings */ - __u8 bStopBits; /* Stop bits settings */ - char cXon; /* XON character */ - char cXoff; /* XOFF character */ - __u8 bUartMode; /* Will be updated when a user */ - /* interface is defined */ -} __attribute__((packed)); - - -/* - * TYPE DEFINITIONS - * Structures for USB interrupts - */ -/* Interrupt packet structure */ -struct ump_interrupt { - __u8 bICode; /* Interrupt code (interrupt num) */ - __u8 bIInfo; /* Interrupt information */ -} __attribute__((packed)); - - -#define TIUMP_GET_PORT_FROM_CODE(c) (((c) >> 4) - 3) -#define TIUMP_GET_FUNC_FROM_CODE(c) ((c) & 0x0f) -#define TIUMP_INTERRUPT_CODE_LSR 0x03 -#define TIUMP_INTERRUPT_CODE_MSR 0x04 - -#endif diff --git a/ANDROID_3.4.5/drivers/usb/serial/io_usbvend.h b/ANDROID_3.4.5/drivers/usb/serial/io_usbvend.h deleted file mode 100644 index 51f83fbb..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/io_usbvend.h +++ /dev/null @@ -1,683 +0,0 @@ -/************************************************************************ - * - * USBVEND.H Vendor-specific USB definitions - * - * NOTE: This must be kept in sync with the Edgeport firmware and - * must be kept backward-compatible with older firmware. - * - ************************************************************************ - * - * Copyright (C) 1998 Inside Out Networks, Inc. - * 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. - * - ************************************************************************/ - -#if !defined(_USBVEND_H) -#define _USBVEND_H - -/************************************************************************ - * - * D e f i n e s / T y p e d e f s - * - ************************************************************************/ - -// -// Definitions of USB product IDs -// - -#define USB_VENDOR_ID_ION 0x1608 // Our VID -#define USB_VENDOR_ID_TI 0x0451 // TI VID -#define USB_VENDOR_ID_AXIOHM 0x05D9 /* Axiohm VID */ - -// -// Definitions of USB product IDs (PID) -// We break the USB-defined PID into an OEM Id field (upper 6 bits) -// and a Device Id (bottom 10 bits). The Device Id defines what -// device this actually is regardless of what the OEM wants to -// call it. -// - -// ION-device OEM IDs -#define ION_OEM_ID_ION 0 // 00h Inside Out Networks -#define ION_OEM_ID_NLYNX 1 // 01h NLynx Systems -#define ION_OEM_ID_GENERIC 2 // 02h Generic OEM -#define ION_OEM_ID_MAC 3 // 03h Mac Version -#define ION_OEM_ID_MEGAWOLF 4 // 04h Lupusb OEM Mac version (MegaWolf) -#define ION_OEM_ID_MULTITECH 5 // 05h Multitech Rapidports -#define ION_OEM_ID_AGILENT 6 // 06h AGILENT board - - -// ION-device Device IDs -// Product IDs - assigned to match middle digit of serial number (No longer true) - -#define ION_DEVICE_ID_80251_NETCHIP 0x020 // This bit is set in the PID if this edgeport hardware$ - // is based on the 80251+Netchip. - -#define ION_DEVICE_ID_GENERATION_1 0x00 // Value for 930 based edgeports -#define ION_DEVICE_ID_GENERATION_2 0x01 // Value for 80251+Netchip. -#define ION_DEVICE_ID_GENERATION_3 0x02 // Value for Texas Instruments TUSB5052 chip -#define ION_DEVICE_ID_GENERATION_4 0x03 // Watchport Family of products -#define ION_GENERATION_MASK 0x03 - -#define ION_DEVICE_ID_HUB_MASK 0x0080 // This bit in the PID designates a HUB device - // for example 8C would be a 421 4 port hub - // and 8D would be a 2 port embedded hub - -#define EDGEPORT_DEVICE_ID_MASK 0x0ff // Not including OEM or GENERATION fields - -#define ION_DEVICE_ID_UNCONFIGURED_EDGE_DEVICE 0x000 // In manufacturing only -#define ION_DEVICE_ID_EDGEPORT_4 0x001 // Edgeport/4 RS232 -#define ION_DEVICE_ID_EDGEPORT_8R 0x002 // Edgeport with RJ45 no Ring -#define ION_DEVICE_ID_RAPIDPORT_4 0x003 // Rapidport/4 -#define ION_DEVICE_ID_EDGEPORT_4T 0x004 // Edgeport/4 RS232 for Telxon (aka "Fleetport") -#define ION_DEVICE_ID_EDGEPORT_2 0x005 // Edgeport/2 RS232 -#define ION_DEVICE_ID_EDGEPORT_4I 0x006 // Edgeport/4 RS422 -#define ION_DEVICE_ID_EDGEPORT_2I 0x007 // Edgeport/2 RS422/RS485 -#define ION_DEVICE_ID_EDGEPORT_8RR 0x008 // Edgeport with RJ45 with Data and RTS/CTS only -// ION_DEVICE_ID_EDGEPORT_8_HANDBUILT 0x009 // Hand-built Edgeport/8 (Placeholder, used in middle digit of serial number only!) -// ION_DEVICE_ID_MULTIMODEM_4X56 0x00A // MultiTech version of RP/4 (Placeholder, used in middle digit of serial number only!) -#define ION_DEVICE_ID_EDGEPORT_PARALLEL_PORT 0x00B // Edgeport/(4)21 Parallel port (USS720) -#define ION_DEVICE_ID_EDGEPORT_421 0x00C // Edgeport/421 Hub+RS232+Parallel -#define ION_DEVICE_ID_EDGEPORT_21 0x00D // Edgeport/21 RS232+Parallel -#define ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU 0x00E // Half of an Edgeport/8 (the kind with 2 EP/4s on 1 PCB) -#define ION_DEVICE_ID_EDGEPORT_8 0x00F // Edgeport/8 (single-CPU) -#define ION_DEVICE_ID_EDGEPORT_2_DIN 0x010 // Edgeport/2 RS232 with Apple DIN connector -#define ION_DEVICE_ID_EDGEPORT_4_DIN 0x011 // Edgeport/4 RS232 with Apple DIN connector -#define ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU 0x012 // Half of an Edgeport/16 (the kind with 2 EP/8s) -#define ION_DEVICE_ID_EDGEPORT_COMPATIBLE 0x013 // Edgeport Compatible, for NCR, Axiohm etc. testing -#define ION_DEVICE_ID_EDGEPORT_8I 0x014 // Edgeport/8 RS422 (single-CPU) -#define ION_DEVICE_ID_EDGEPORT_1 0x015 // Edgeport/1 RS232 -#define ION_DEVICE_ID_EPOS44 0x016 // Half of an EPOS/44 (TIUMP BASED) -#define ION_DEVICE_ID_EDGEPORT_42 0x017 // Edgeport/42 -#define ION_DEVICE_ID_EDGEPORT_412_8 0x018 // Edgeport/412 8 port part -#define ION_DEVICE_ID_EDGEPORT_412_4 0x019 // Edgeport/412 4 port part -#define ION_DEVICE_ID_EDGEPORT_22I 0x01A // Edgeport/22I is an Edgeport/4 with ports 1&2 RS422 and ports 3&4 RS232 - -// Compact Form factor TI based devices 2c, 21c, 22c, 221c -#define ION_DEVICE_ID_EDGEPORT_2C 0x01B // Edgeport/2c is a TI based Edgeport/2 - Small I2c -#define ION_DEVICE_ID_EDGEPORT_221C 0x01C // Edgeport/221c is a TI based Edgeport/2 with lucent chip and - // 2 external hub ports - Large I2C -#define ION_DEVICE_ID_EDGEPORT_22C 0x01D // Edgeport/22c is a TI based Edgeport/2 with - // 2 external hub ports - Large I2C -#define ION_DEVICE_ID_EDGEPORT_21C 0x01E // Edgeport/21c is a TI based Edgeport/2 with lucent chip - // Small I2C - - -/* - * DANGER DANGER The 0x20 bit was used to indicate a 8251/netchip GEN 2 device. - * Since the MAC, Linux, and Optimal drivers still used the old code - * I suggest that you skip the 0x20 bit when creating new PIDs - */ - - -// Generation 3 devices -- 3410 based edgport/1 (256 byte I2C) -#define ION_DEVICE_ID_TI3410_EDGEPORT_1 0x040 // Edgeport/1 RS232 -#define ION_DEVICE_ID_TI3410_EDGEPORT_1I 0x041 // Edgeport/1i- RS422 model - -// Ti based software switchable RS232/RS422/RS485 devices -#define ION_DEVICE_ID_EDGEPORT_4S 0x042 // Edgeport/4s - software switchable model -#define ION_DEVICE_ID_EDGEPORT_8S 0x043 // Edgeport/8s - software switchable model - -// Usb to Ethernet dongle -#define ION_DEVICE_ID_EDGEPORT_E 0x0E0 // Edgeport/E Usb to Ethernet - -// Edgeport TI based devices -#define ION_DEVICE_ID_TI_EDGEPORT_4 0x0201 // Edgeport/4 RS232 -#define ION_DEVICE_ID_TI_EDGEPORT_2 0x0205 // Edgeport/2 RS232 -#define ION_DEVICE_ID_TI_EDGEPORT_4I 0x0206 // Edgeport/4i RS422 -#define ION_DEVICE_ID_TI_EDGEPORT_2I 0x0207 // Edgeport/2i RS422/RS485 -#define ION_DEVICE_ID_TI_EDGEPORT_421 0x020C // Edgeport/421 4 hub 2 RS232 + Parallel (lucent on a different hub port) -#define ION_DEVICE_ID_TI_EDGEPORT_21 0x020D // Edgeport/21 2 RS232 + Parallel (lucent on a different hub port) -#define ION_DEVICE_ID_TI_EDGEPORT_416 0x0212 // Edgeport/416 -#define ION_DEVICE_ID_TI_EDGEPORT_1 0x0215 // Edgeport/1 RS232 -#define ION_DEVICE_ID_TI_EDGEPORT_42 0x0217 // Edgeport/42 4 hub 2 RS232 -#define ION_DEVICE_ID_TI_EDGEPORT_22I 0x021A // Edgeport/22I is an Edgeport/4 with ports 1&2 RS422 and ports 3&4 RS232 -#define ION_DEVICE_ID_TI_EDGEPORT_2C 0x021B // Edgeport/2c RS232 -#define ION_DEVICE_ID_TI_EDGEPORT_221C 0x021C // Edgeport/221c is a TI based Edgeport/2 with lucent chip and - // 2 external hub ports - Large I2C -#define ION_DEVICE_ID_TI_EDGEPORT_22C 0x021D // Edgeport/22c is a TI based Edgeport/2 with - // 2 external hub ports - Large I2C -#define ION_DEVICE_ID_TI_EDGEPORT_21C 0x021E // Edgeport/21c is a TI based Edgeport/2 with lucent chip - -// Generation 3 devices -- 3410 based edgport/1 (256 byte I2C) -#define ION_DEVICE_ID_TI_TI3410_EDGEPORT_1 0x0240 // Edgeport/1 RS232 -#define ION_DEVICE_ID_TI_TI3410_EDGEPORT_1I 0x0241 // Edgeport/1i- RS422 model - -// Ti based software switchable RS232/RS422/RS485 devices -#define ION_DEVICE_ID_TI_EDGEPORT_4S 0x0242 // Edgeport/4s - software switchable model -#define ION_DEVICE_ID_TI_EDGEPORT_8S 0x0243 // Edgeport/8s - software switchable model -#define ION_DEVICE_ID_TI_EDGEPORT_8 0x0244 // Edgeport/8 (single-CPU) -#define ION_DEVICE_ID_TI_EDGEPORT_416B 0x0247 // Edgeport/416 - - -/************************************************************************ - * - * Generation 4 devices - * - ************************************************************************/ - -// Watchport based on 3410 both 1-wire and binary products (16K I2C) -#define ION_DEVICE_ID_WP_UNSERIALIZED 0x300 // Watchport based on 3410 both 1-wire and binary products -#define ION_DEVICE_ID_WP_PROXIMITY 0x301 // Watchport/P Discontinued -#define ION_DEVICE_ID_WP_MOTION 0x302 // Watchport/M -#define ION_DEVICE_ID_WP_MOISTURE 0x303 // Watchport/W -#define ION_DEVICE_ID_WP_TEMPERATURE 0x304 // Watchport/T -#define ION_DEVICE_ID_WP_HUMIDITY 0x305 // Watchport/H - -#define ION_DEVICE_ID_WP_POWER 0x306 // Watchport -#define ION_DEVICE_ID_WP_LIGHT 0x307 // Watchport -#define ION_DEVICE_ID_WP_RADIATION 0x308 // Watchport -#define ION_DEVICE_ID_WP_ACCELERATION 0x309 // Watchport/A -#define ION_DEVICE_ID_WP_DISTANCE 0x30A // Watchport/D Discontinued -#define ION_DEVICE_ID_WP_PROX_DIST 0x30B // Watchport/D uses distance sensor - // Default to /P function - -#define ION_DEVICE_ID_PLUS_PWR_HP4CD 0x30C // 5052 Plus Power HubPort/4CD+ (for Dell) -#define ION_DEVICE_ID_PLUS_PWR_HP4C 0x30D // 5052 Plus Power HubPort/4C+ -#define ION_DEVICE_ID_PLUS_PWR_PCI 0x30E // 3410 Plus Power PCI Host Controller 4 port - - -// -// Definitions for AXIOHM USB product IDs -// -#define USB_VENDOR_ID_AXIOHM 0x05D9 // Axiohm VID - -#define AXIOHM_DEVICE_ID_MASK 0xffff -#define AXIOHM_DEVICE_ID_EPIC_A758 0xA758 -#define AXIOHM_DEVICE_ID_EPIC_A794 0xA794 -#define AXIOHM_DEVICE_ID_EPIC_A225 0xA225 - - -// -// Definitions for NCR USB product IDs -// -#define USB_VENDOR_ID_NCR 0x0404 // NCR VID - -#define NCR_DEVICE_ID_MASK 0xffff -#define NCR_DEVICE_ID_EPIC_0202 0x0202 -#define NCR_DEVICE_ID_EPIC_0203 0x0203 -#define NCR_DEVICE_ID_EPIC_0310 0x0310 -#define NCR_DEVICE_ID_EPIC_0311 0x0311 -#define NCR_DEVICE_ID_EPIC_0312 0x0312 - - -// -// Definitions for SYMBOL USB product IDs -// -#define USB_VENDOR_ID_SYMBOL 0x05E0 // Symbol VID -#define SYMBOL_DEVICE_ID_MASK 0xffff -#define SYMBOL_DEVICE_ID_KEYFOB 0x0700 - - -// -// Definitions for other product IDs -#define ION_DEVICE_ID_MT4X56USB 0x1403 // OEM device - - -#define GENERATION_ID_FROM_USB_PRODUCT_ID(ProductId) \ - ((__u16) ((ProductId >> 8) & (ION_GENERATION_MASK))) - -#define MAKE_USB_PRODUCT_ID(OemId, DeviceId) \ - ((__u16) (((OemId) << 10) || (DeviceId))) - -#define DEVICE_ID_FROM_USB_PRODUCT_ID(ProductId) \ - ((__u16) ((ProductId) & (EDGEPORT_DEVICE_ID_MASK))) - -#define OEM_ID_FROM_USB_PRODUCT_ID(ProductId) \ - ((__u16) (((ProductId) >> 10) & 0x3F)) - -// -// Definitions of parameters for download code. Note that these are -// specific to a given version of download code and must change if the -// corresponding download code changes. -// - -// TxCredits value below which driver won't bother sending (to prevent too many small writes). -// Send only if above 25% -#define EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(InitialCredit, MaxPacketSize) (max(((InitialCredit) / 4), (MaxPacketSize))) - -#define EDGE_FW_BULK_MAX_PACKET_SIZE 64 // Max Packet Size for Bulk In Endpoint (EP1) -#define EDGE_FW_BULK_READ_BUFFER_SIZE 1024 // Size to use for Bulk reads - -#define EDGE_FW_INT_MAX_PACKET_SIZE 32 // Max Packet Size for Interrupt In Endpoint - // Note that many units were shipped with MPS=16, we - // force an upgrade to this value). -#define EDGE_FW_INT_INTERVAL 2 // 2ms polling on IntPipe - - -// -// Definitions of I/O Networks vendor-specific requests -// for default endpoint -// -// bmRequestType = 01000000 Set vendor-specific, to device -// bmRequestType = 11000000 Get vendor-specific, to device -// -// These are the definitions for the bRequest field for the -// above bmRequestTypes. -// -// For the read/write Edgeport memory commands, the parameters -// are as follows: -// wValue = 16-bit address -// wIndex = unused (though we could put segment 00: or FF: here) -// wLength = # bytes to read/write (max 64) -// - -#define USB_REQUEST_ION_RESET_DEVICE 0 // Warm reboot Edgeport, retaining USB address -#define USB_REQUEST_ION_GET_EPIC_DESC 1 // Get Edgeport Compatibility Descriptor -// unused 2 // Unused, available -#define USB_REQUEST_ION_READ_RAM 3 // Read EdgePort RAM at specified addr -#define USB_REQUEST_ION_WRITE_RAM 4 // Write EdgePort RAM at specified addr -#define USB_REQUEST_ION_READ_ROM 5 // Read EdgePort ROM at specified addr -#define USB_REQUEST_ION_WRITE_ROM 6 // Write EdgePort ROM at specified addr -#define USB_REQUEST_ION_EXEC_DL_CODE 7 // Begin execution of RAM-based download - // code by jumping to address in wIndex:wValue -// 8 // Unused, available -#define USB_REQUEST_ION_ENABLE_SUSPEND 9 // Enable/Disable suspend feature - // (wValue != 0: Enable; wValue = 0: Disable) - -#define USB_REQUEST_ION_SEND_IOSP 10 // Send an IOSP command to the edgeport over the control pipe -#define USB_REQUEST_ION_RECV_IOSP 11 // Receive an IOSP command from the edgeport over the control pipe - - -#define USB_REQUEST_ION_DIS_INT_TIMER 0x80 // Sent to Axiohm to enable/ disable - // interrupt token timer - // wValue = 1, enable (default) - // wValue = 0, disable - -// -// Define parameter values for our vendor-specific commands -// - -// -// Edgeport Compatibility Descriptor -// -// This descriptor is only returned by Edgeport-compatible devices -// supporting the EPiC spec. True ION devices do not return this -// descriptor, but instead return STALL on receipt of the -// GET_EPIC_DESC command. The driver interprets a STALL to mean that -// this is a "real" Edgeport. -// - -struct edge_compatibility_bits { - // This __u32 defines which Vendor-specific commands/functionality - // the device supports on the default EP0 pipe. - - __u32 VendEnableSuspend : 1; // 0001 Set if device supports ION_ENABLE_SUSPEND - __u32 VendUnused : 31; // Available for future expansion, must be 0 - - // This __u32 defines which IOSP commands are supported over the - // bulk pipe EP1. - - // xxxx Set if device supports: - __u32 IOSPOpen : 1; // 0001 OPEN / OPEN_RSP (Currently must be 1) - __u32 IOSPClose : 1; // 0002 CLOSE - __u32 IOSPChase : 1; // 0004 CHASE / CHASE_RSP - __u32 IOSPSetRxFlow : 1; // 0008 SET_RX_FLOW - __u32 IOSPSetTxFlow : 1; // 0010 SET_TX_FLOW - __u32 IOSPSetXChar : 1; // 0020 SET_XON_CHAR/SET_XOFF_CHAR - __u32 IOSPRxCheck : 1; // 0040 RX_CHECK_REQ/RX_CHECK_RSP - __u32 IOSPSetClrBreak : 1; // 0080 SET_BREAK/CLEAR_BREAK - __u32 IOSPWriteMCR : 1; // 0100 MCR register writes (set/clr DTR/RTS) - __u32 IOSPWriteLCR : 1; // 0200 LCR register writes (wordlen/stop/parity) - __u32 IOSPSetBaudRate : 1; // 0400 setting Baud rate (writes to LCR.80h and DLL/DLM register) - __u32 IOSPDisableIntPipe : 1; // 0800 Do not use the interrupt pipe for TxCredits or RxButesAvailable - __u32 IOSPRxDataAvail : 1; // 1000 Return status of RX Fifo (Data available in Fifo) - __u32 IOSPTxPurge : 1; // 2000 Purge TXBuffer and/or Fifo in Edgeport hardware - __u32 IOSPUnused : 18; // Available for future expansion, must be 0 - - // This __u32 defines which 'general' features are supported - - __u32 TrueEdgeport : 1; // 0001 Set if device is a 'real' Edgeport - // (Used only by driver, NEVER set by an EPiC device) - __u32 GenUnused : 31; // Available for future expansion, must be 0 -}; - -#define EDGE_COMPATIBILITY_MASK0 0x0001 -#define EDGE_COMPATIBILITY_MASK1 0x3FFF -#define EDGE_COMPATIBILITY_MASK2 0x0001 - -struct edge_compatibility_descriptor { - __u8 Length; // Descriptor Length (per USB spec) - __u8 DescType; // Descriptor Type (per USB spec, =DEVICE type) - __u8 EpicVer; // Version of EPiC spec supported - // (Currently must be 1) - __u8 NumPorts; // Number of serial ports supported - __u8 iDownloadFile; // Index of string containing download code filename - // 0=no download, FF=download compiled into driver. - __u8 Unused[3]; // Available for future expansion, must be 0 - // (Currently must be 0). - __u8 MajorVersion; // Firmware version: xx. - __u8 MinorVersion; // yy. - __le16 BuildNumber; // zzzz (LE format) - - // The following structure contains __u32s, with each bit - // specifying whether the EPiC device supports the given - // command or functionality. - struct edge_compatibility_bits Supports; -}; - -// Values for iDownloadFile -#define EDGE_DOWNLOAD_FILE_NONE 0 // No download requested -#define EDGE_DOWNLOAD_FILE_INTERNAL 0xFF // Download the file compiled into driver (930 version) -#define EDGE_DOWNLOAD_FILE_I930 0xFF // Download the file compiled into driver (930 version) -#define EDGE_DOWNLOAD_FILE_80251 0xFE // Download the file compiled into driver (80251 version) - - - -/* - * Special addresses for READ/WRITE_RAM/ROM - */ - -// Version 1 (original) format of DeviceParams -#define EDGE_MANUF_DESC_ADDR_V1 0x00FF7F00 -#define EDGE_MANUF_DESC_LEN_V1 sizeof(EDGE_MANUF_DESCRIPTOR_V1) - -// Version 2 format of DeviceParams. This format is longer (3C0h) -// and starts lower in memory, at the uppermost 1K in ROM. -#define EDGE_MANUF_DESC_ADDR 0x00FF7C00 -#define EDGE_MANUF_DESC_LEN sizeof(struct edge_manuf_descriptor) - -// Boot params descriptor -#define EDGE_BOOT_DESC_ADDR 0x00FF7FC0 -#define EDGE_BOOT_DESC_LEN sizeof(struct edge_boot_descriptor) - -// Define the max block size that may be read or written -// in a read/write RAM/ROM command. -#define MAX_SIZE_REQ_ION_READ_MEM ((__u16)64) -#define MAX_SIZE_REQ_ION_WRITE_MEM ((__u16)64) - - -// -// Notes for the following two ION vendor-specific param descriptors: -// -// 1. These have a standard USB descriptor header so they look like a -// normal descriptor. -// 2. Any strings in the structures are in USB-defined string -// descriptor format, so that they may be separately retrieved, -// if necessary, with a minimum of work on the 930. This also -// requires them to be in UNICODE format, which, for English at -// least, simply means extending each __u8 into a __u16. -// 3. For all fields, 00 means 'uninitialized'. -// 4. All unused areas should be set to 00 for future expansion. -// - -// This structure is ver 2 format. It contains ALL USB descriptors as -// well as the configuration parameters that were in the original V1 -// structure. It is NOT modified when new boot code is downloaded; rather, -// these values are set or modified by manufacturing. It is located at -// xC00-xFBF (length 3C0h) in the ROM. -// This structure is a superset of the v1 structure and is arranged so -// that all of the v1 fields remain at the same address. We are just -// adding more room to the front of the structure to hold the descriptors. -// -// The actual contents of this structure are defined in a 930 assembly -// file, converted to a binary image, and then written by the serialization -// program. The C definition of this structure just defines a dummy -// area for general USB descriptors and the descriptor tables (the root -// descriptor starts at xC00). At the bottom of the structure are the -// fields inherited from the v1 structure. - -#define MAX_SERIALNUMBER_LEN 12 -#define MAX_ASSEMBLYNUMBER_LEN 14 - -struct edge_manuf_descriptor { - - __u16 RootDescTable[0x10]; // C00 Root of descriptor tables (just a placeholder) - __u8 DescriptorArea[0x2E0]; // C20 Descriptors go here, up to 2E0h (just a placeholder) - - // Start of v1-compatible section - __u8 Length; // F00 Desc length for what follows, per USB (= C0h ) - __u8 DescType; // F01 Desc type, per USB (=DEVICE type) - __u8 DescVer; // F02 Desc version/format (currently 2) - __u8 NumRootDescEntries; // F03 # entries in RootDescTable - - __u8 RomSize; // F04 Size of ROM/E2PROM in K - __u8 RamSize; // F05 Size of external RAM in K - __u8 CpuRev; // F06 CPU revision level (chg only if s/w visible) - __u8 BoardRev; // F07 PCB revision level (chg only if s/w visible) - - __u8 NumPorts; // F08 Number of ports - __u8 DescDate[3]; // F09 MM/DD/YY when descriptor template was compiler, - // so host can track changes to USB-only descriptors. - - __u8 SerNumLength; // F0C USB string descriptor len - __u8 SerNumDescType; // F0D USB descriptor type (=STRING type) - __le16 SerialNumber[MAX_SERIALNUMBER_LEN]; // F0E "01-01-000100" Unicode Serial Number - - __u8 AssemblyNumLength; // F26 USB string descriptor len - __u8 AssemblyNumDescType; // F27 USB descriptor type (=STRING type) - __le16 AssemblyNumber[MAX_ASSEMBLYNUMBER_LEN]; // F28 "350-1000-01-A " assembly number - - __u8 OemAssyNumLength; // F44 USB string descriptor len - __u8 OemAssyNumDescType; // F45 USB descriptor type (=STRING type) - __le16 OemAssyNumber[MAX_ASSEMBLYNUMBER_LEN]; // F46 "xxxxxxxxxxxxxx" OEM assembly number - - __u8 ManufDateLength; // F62 USB string descriptor len - __u8 ManufDateDescType; // F63 USB descriptor type (=STRING type) - __le16 ManufDate[6]; // F64 "MMDDYY" manufacturing date - - __u8 Reserved3[0x4D]; // F70 -- unused, set to 0 -- - - __u8 UartType; // FBD Uart Type - __u8 IonPid; // FBE Product ID, == LSB of USB DevDesc.PID - // (Note: Edgeport/4s before 11/98 will have - // 00 here instead of 01) - __u8 IonConfig; // FBF Config byte for ION manufacturing use - // FBF end of structure, total len = 3C0h - -}; - - -#define MANUF_DESC_VER_1 1 // Original definition of MANUF_DESC -#define MANUF_DESC_VER_2 2 // Ver 2, starts at xC00h len 3C0h - - -// Uart Types -// Note: Since this field was added only recently, all Edgeport/4 units -// shipped before 11/98 will have 00 in this field. Therefore, -// both 00 and 01 values mean '654. -#define MANUF_UART_EXAR_654_EARLY 0 // Exar 16C654 in Edgeport/4s before 11/98 -#define MANUF_UART_EXAR_654 1 // Exar 16C654 -#define MANUF_UART_EXAR_2852 2 // Exar 16C2852 - -// -// Note: The CpuRev and BoardRev values do not conform to manufacturing -// revisions; they are to be incremented only when the CPU or hardware -// changes in a software-visible way, such that the 930 software or -// the host driver needs to handle the hardware differently. -// - -// Values of bottom 5 bits of CpuRev & BoardRev for -// Implementation 0 (ie, 930-based) -#define MANUF_CPU_REV_AD4 1 // 930 AD4, with EP1 Rx bug (needs RXSPM) -#define MANUF_CPU_REV_AD5 2 // 930 AD5, with above bug (supposedly) fixed -#define MANUF_CPU_80251 0x20 // Intel 80251 - - -#define MANUF_BOARD_REV_A 1 // Original version, == Manuf Rev A -#define MANUF_BOARD_REV_B 2 // Manuf Rev B, wakeup interrupt works -#define MANUF_BOARD_REV_C 3 // Manuf Rev C, 2/4 ports, rs232/rs422 -#define MANUF_BOARD_REV_GENERATION_2 0x20 // Second generaiton edgeport - - -// Values of bottom 5 bits of CpuRev & BoardRev for -// Implementation 1 (ie, 251+Netchip-based) -#define MANUF_CPU_REV_1 1 // C251TB Rev 1 (Need actual Intel rev here) - -#define MANUF_BOARD_REV_A 1 // First rev of 251+Netchip design - -#define MANUF_SERNUM_LENGTH sizeof(((struct edge_manuf_descriptor *)0)->SerialNumber) -#define MANUF_ASSYNUM_LENGTH sizeof(((struct edge_manuf_descriptor *)0)->AssemblyNumber) -#define MANUF_OEMASSYNUM_LENGTH sizeof(((struct edge_manuf_descriptor *)0)->OemAssyNumber) -#define MANUF_MANUFDATE_LENGTH sizeof(((struct edge_manuf_descriptor *)0)->ManufDate) - -#define MANUF_ION_CONFIG_DIAG_NO_LOOP 0x20 // As below but no ext loopback test -#define MANUF_ION_CONFIG_DIAG 0x40 // 930 based device: 1=Run h/w diags, 0=norm - // TIUMP Device : 1=IONSERIAL needs to run Final Test -#define MANUF_ION_CONFIG_MASTER 0x80 // 930 based device: 1=Master mode, 0=Normal - // TIUMP Device : 1=First device on a multi TIUMP Device - -// -// This structure describes parameters for the boot code, and -// is programmed along with new boot code. These are values -// which are specific to a given build of the boot code. It -// is exactly 64 bytes long and is fixed at address FF:xFC0 -// - FF:xFFF. Note that the 930-mandated UCONFIG bytes are -// included in this structure. -// -struct edge_boot_descriptor { - __u8 Length; // C0 Desc length, per USB (= 40h) - __u8 DescType; // C1 Desc type, per USB (= DEVICE type) - __u8 DescVer; // C2 Desc version/format - __u8 Reserved1; // C3 -- unused, set to 0 -- - - __le16 BootCodeLength; // C4 Boot code goes from FF:0000 to FF:(len-1) - // (LE format) - - __u8 MajorVersion; // C6 Firmware version: xx. - __u8 MinorVersion; // C7 yy. - __le16 BuildNumber; // C8 zzzz (LE format) - - __u16 EnumRootDescTable; // CA Root of ROM-based descriptor table - __u8 NumDescTypes; // CC Number of supported descriptor types - - __u8 Reserved4; // CD Fix Compiler Packing - - __le16 Capabilities; // CE-CF Capabilities flags (LE format) - __u8 Reserved2[0x28]; // D0 -- unused, set to 0 -- - __u8 UConfig0; // F8 930-defined CPU configuration byte 0 - __u8 UConfig1; // F9 930-defined CPU configuration byte 1 - __u8 Reserved3[6]; // FA -- unused, set to 0 -- - // FF end of structure, total len = 80 -}; - - -#define BOOT_DESC_VER_1 1 // Original definition of BOOT_PARAMS -#define BOOT_DESC_VER_2 2 // 2nd definition, descriptors not included in boot - - - // Capabilities flags - -#define BOOT_CAP_RESET_CMD 0x0001 // If set, boot correctly supports ION_RESET_DEVICE - - -/************************************************************************ - T I U M P D E F I N I T I O N S - ***********************************************************************/ - -// Chip definitions in I2C -#define UMP5152 0x52 -#define UMP3410 0x10 - - -//************************************************************************ -// TI I2C Format Definitions -//************************************************************************ -#define I2C_DESC_TYPE_INFO_BASIC 0x01 -#define I2C_DESC_TYPE_FIRMWARE_BASIC 0x02 -#define I2C_DESC_TYPE_DEVICE 0x03 -#define I2C_DESC_TYPE_CONFIG 0x04 -#define I2C_DESC_TYPE_STRING 0x05 -#define I2C_DESC_TYPE_FIRMWARE_AUTO 0x07 // for 3410 download -#define I2C_DESC_TYPE_CONFIG_KLUDGE 0x14 // for 3410 -#define I2C_DESC_TYPE_WATCHPORT_VERSION 0x15 // firmware version number for watchport -#define I2C_DESC_TYPE_WATCHPORT_CALIBRATION_DATA 0x16 // Watchport Calibration Data - -#define I2C_DESC_TYPE_FIRMWARE_BLANK 0xf2 - -// Special section defined by ION -#define I2C_DESC_TYPE_ION 0 // Not defined by TI - - -struct ti_i2c_desc { - __u8 Type; // Type of descriptor - __u16 Size; // Size of data only not including header - __u8 CheckSum; // Checksum (8 bit sum of data only) - __u8 Data[0]; // Data starts here -} __attribute__((packed)); - -// for 5152 devices only (type 2 record) -// for 3410 the version is stored in the WATCHPORT_FIRMWARE_VERSION descriptor -struct ti_i2c_firmware_rec { - __u8 Ver_Major; // Firmware Major version number - __u8 Ver_Minor; // Firmware Minor version number - __u8 Data[0]; // Download starts here -} __attribute__((packed)); - - -struct watchport_firmware_version { -// Added 2 bytes for version number - __u8 Version_Major; // Download Version (for Watchport) - __u8 Version_Minor; -} __attribute__((packed)); - - -// Structure of header of download image in fw_down.h -struct ti_i2c_image_header { - __le16 Length; - __u8 CheckSum; -} __attribute__((packed)); - -struct ti_basic_descriptor { - __u8 Power; // Self powered - // bit 7: 1 - power switching supported - // 0 - power switching not supported - // - // bit 0: 1 - self powered - // 0 - bus powered - // - // - __u16 HubVid; // VID HUB - __u16 HubPid; // PID HUB - __u16 DevPid; // PID Edgeport - __u8 HubTime; // Time for power on to power good - __u8 HubCurrent; // HUB Current = 100ma -} __attribute__((packed)); - - -// CPU / Board Rev Definitions -#define TI_CPU_REV_5052 2 // 5052 based edgeports -#define TI_CPU_REV_3410 3 // 3410 based edgeports - -#define TI_BOARD_REV_TI_EP 0 // Basic ti based edgeport -#define TI_BOARD_REV_COMPACT 1 // Compact board -#define TI_BOARD_REV_WATCHPORT 2 // Watchport - - -#define TI_GET_CPU_REVISION(x) (__u8)((((x)>>4)&0x0f)) -#define TI_GET_BOARD_REVISION(x) (__u8)(((x)&0x0f)) - -#define TI_I2C_SIZE_MASK 0x1f // 5 bits -#define TI_GET_I2C_SIZE(x) ((((x) & TI_I2C_SIZE_MASK)+1)*256) - -#define TI_MAX_I2C_SIZE (16 * 1024) - -#define TI_MANUF_VERSION_0 0 - -// IonConig2 flags -#define TI_CONFIG2_RS232 0x01 -#define TI_CONFIG2_RS422 0x02 -#define TI_CONFIG2_RS485 0x04 -#define TI_CONFIG2_SWITCHABLE 0x08 - -#define TI_CONFIG2_WATCHPORT 0x10 - - -struct edge_ti_manuf_descriptor { - __u8 IonConfig; // Config byte for ION manufacturing use - __u8 IonConfig2; // Expansion - __u8 Version; // Version - __u8 CpuRev_BoardRev; // CPU revision level (0xF0) and Board Rev Level (0x0F) - __u8 NumPorts; // Number of ports for this UMP - __u8 NumVirtualPorts; // Number of Virtual ports - __u8 HubConfig1; // Used to configure the Hub - __u8 HubConfig2; // Used to configure the Hub - __u8 TotalPorts; // Total Number of Com Ports for the entire device (All UMPs) - __u8 Reserved; // Reserved -} __attribute__((packed)); - - -#endif // if !defined(_USBVEND_H) diff --git a/ANDROID_3.4.5/drivers/usb/serial/ipaq.c b/ANDROID_3.4.5/drivers/usb/serial/ipaq.c deleted file mode 100644 index 10c02b8b..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/ipaq.c +++ /dev/null @@ -1,670 +0,0 @@ -/* - * USB Compaq iPAQ driver - * - * Copyright (C) 2001 - 2002 - * Ganesh Varadarajan - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define KP_RETRIES 100 - -/* - * Version Information - */ - -#define DRIVER_VERSION "v1.0" -#define DRIVER_AUTHOR "Ganesh Varadarajan " -#define DRIVER_DESC "USB PocketPC PDA driver" - -static __u16 product, vendor; -static bool debug; -static int connect_retries = KP_RETRIES; -static int initial_wait; - -/* Function prototypes for an ipaq */ -static int ipaq_open(struct tty_struct *tty, - struct usb_serial_port *port); -static int ipaq_calc_num_ports(struct usb_serial *serial); -static int ipaq_startup(struct usb_serial *serial); - -static struct usb_device_id ipaq_id_table [] = { - /* The first entry is a placeholder for the insmod-specified device */ - { USB_DEVICE(0x049F, 0x0003) }, - { USB_DEVICE(0x0104, 0x00BE) }, /* Socket USB Sync */ - { USB_DEVICE(0x03F0, 0x1016) }, /* HP USB Sync */ - { USB_DEVICE(0x03F0, 0x1116) }, /* HP USB Sync 1611 */ - { USB_DEVICE(0x03F0, 0x1216) }, /* HP USB Sync 1612 */ - { USB_DEVICE(0x03F0, 0x2016) }, /* HP USB Sync 1620 */ - { USB_DEVICE(0x03F0, 0x2116) }, /* HP USB Sync 1621 */ - { USB_DEVICE(0x03F0, 0x2216) }, /* HP USB Sync 1622 */ - { USB_DEVICE(0x03F0, 0x3016) }, /* HP USB Sync 1630 */ - { USB_DEVICE(0x03F0, 0x3116) }, /* HP USB Sync 1631 */ - { USB_DEVICE(0x03F0, 0x3216) }, /* HP USB Sync 1632 */ - { USB_DEVICE(0x03F0, 0x4016) }, /* HP USB Sync 1640 */ - { USB_DEVICE(0x03F0, 0x4116) }, /* HP USB Sync 1641 */ - { USB_DEVICE(0x03F0, 0x4216) }, /* HP USB Sync 1642 */ - { USB_DEVICE(0x03F0, 0x5016) }, /* HP USB Sync 1650 */ - { USB_DEVICE(0x03F0, 0x5116) }, /* HP USB Sync 1651 */ - { USB_DEVICE(0x03F0, 0x5216) }, /* HP USB Sync 1652 */ - { USB_DEVICE(0x0409, 0x00D5) }, /* NEC USB Sync */ - { USB_DEVICE(0x0409, 0x00D6) }, /* NEC USB Sync */ - { USB_DEVICE(0x0409, 0x00D7) }, /* NEC USB Sync */ - { USB_DEVICE(0x0409, 0x8024) }, /* NEC USB Sync */ - { USB_DEVICE(0x0409, 0x8025) }, /* NEC USB Sync */ - { USB_DEVICE(0x043E, 0x9C01) }, /* LGE USB Sync */ - { USB_DEVICE(0x045E, 0x00CE) }, /* Microsoft USB Sync */ - { USB_DEVICE(0x045E, 0x0400) }, /* Windows Powered Pocket PC 2002 */ - { USB_DEVICE(0x045E, 0x0401) }, /* Windows Powered Pocket PC 2002 */ - { USB_DEVICE(0x045E, 0x0402) }, /* Windows Powered Pocket PC 2002 */ - { USB_DEVICE(0x045E, 0x0403) }, /* Windows Powered Pocket PC 2002 */ - { USB_DEVICE(0x045E, 0x0404) }, /* Windows Powered Pocket PC 2002 */ - { USB_DEVICE(0x045E, 0x0405) }, /* Windows Powered Pocket PC 2002 */ - { USB_DEVICE(0x045E, 0x0406) }, /* Windows Powered Pocket PC 2002 */ - { USB_DEVICE(0x045E, 0x0407) }, /* Windows Powered Pocket PC 2002 */ - { USB_DEVICE(0x045E, 0x0408) }, /* Windows Powered Pocket PC 2002 */ - { USB_DEVICE(0x045E, 0x0409) }, /* Windows Powered Pocket PC 2002 */ - { USB_DEVICE(0x045E, 0x040A) }, /* Windows Powered Pocket PC 2002 */ - { USB_DEVICE(0x045E, 0x040B) }, /* Windows Powered Pocket PC 2002 */ - { USB_DEVICE(0x045E, 0x040C) }, /* Windows Powered Pocket PC 2002 */ - { USB_DEVICE(0x045E, 0x040D) }, /* Windows Powered Pocket PC 2002 */ - { USB_DEVICE(0x045E, 0x040E) }, /* Windows Powered Pocket PC 2002 */ - { USB_DEVICE(0x045E, 0x040F) }, /* Windows Powered Pocket PC 2002 */ - { USB_DEVICE(0x045E, 0x0410) }, /* Windows Powered Pocket PC 2002 */ - { USB_DEVICE(0x045E, 0x0411) }, /* Windows Powered Pocket PC 2002 */ - { USB_DEVICE(0x045E, 0x0412) }, /* Windows Powered Pocket PC 2002 */ - { USB_DEVICE(0x045E, 0x0413) }, /* Windows Powered Pocket PC 2002 */ - { USB_DEVICE(0x045E, 0x0414) }, /* Windows Powered Pocket PC 2002 */ - { USB_DEVICE(0x045E, 0x0415) }, /* Windows Powered Pocket PC 2002 */ - { USB_DEVICE(0x045E, 0x0416) }, /* Windows Powered Pocket PC 2002 */ - { USB_DEVICE(0x045E, 0x0417) }, /* Windows Powered Pocket PC 2002 */ - { USB_DEVICE(0x045E, 0x0432) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0433) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0434) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0435) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0436) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0437) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0438) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0439) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x043A) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x043B) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x043C) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x043D) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x043E) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x043F) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0440) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0441) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0442) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0443) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0444) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0445) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0446) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0447) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0448) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0449) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x044A) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x044B) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x044C) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x044D) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x044E) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x044F) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0450) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0451) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0452) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0453) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0454) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0455) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0456) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0457) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0458) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0459) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x045A) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x045B) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x045C) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x045D) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x045E) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x045F) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0460) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0461) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0462) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0463) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0464) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0465) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0466) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0467) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0468) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0469) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x046A) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x046B) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x046C) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x046D) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x046E) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x046F) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0470) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0471) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0472) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0473) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0474) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0475) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0476) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0477) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0478) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x0479) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x047A) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x047B) }, /* Windows Powered Pocket PC 2003 */ - { USB_DEVICE(0x045E, 0x04C8) }, /* Windows Powered Smartphone 2002 */ - { USB_DEVICE(0x045E, 0x04C9) }, /* Windows Powered Smartphone 2002 */ - { USB_DEVICE(0x045E, 0x04CA) }, /* Windows Powered Smartphone 2002 */ - { USB_DEVICE(0x045E, 0x04CB) }, /* Windows Powered Smartphone 2002 */ - { USB_DEVICE(0x045E, 0x04CC) }, /* Windows Powered Smartphone 2002 */ - { USB_DEVICE(0x045E, 0x04CD) }, /* Windows Powered Smartphone 2002 */ - { USB_DEVICE(0x045E, 0x04CE) }, /* Windows Powered Smartphone 2002 */ - { USB_DEVICE(0x045E, 0x04D7) }, /* Windows Powered Smartphone 2003 */ - { USB_DEVICE(0x045E, 0x04D8) }, /* Windows Powered Smartphone 2003 */ - { USB_DEVICE(0x045E, 0x04D9) }, /* Windows Powered Smartphone 2003 */ - { USB_DEVICE(0x045E, 0x04DA) }, /* Windows Powered Smartphone 2003 */ - { USB_DEVICE(0x045E, 0x04DB) }, /* Windows Powered Smartphone 2003 */ - { USB_DEVICE(0x045E, 0x04DC) }, /* Windows Powered Smartphone 2003 */ - { USB_DEVICE(0x045E, 0x04DD) }, /* Windows Powered Smartphone 2003 */ - { USB_DEVICE(0x045E, 0x04DE) }, /* Windows Powered Smartphone 2003 */ - { USB_DEVICE(0x045E, 0x04DF) }, /* Windows Powered Smartphone 2003 */ - { USB_DEVICE(0x045E, 0x04E0) }, /* Windows Powered Smartphone 2003 */ - { USB_DEVICE(0x045E, 0x04E1) }, /* Windows Powered Smartphone 2003 */ - { USB_DEVICE(0x045E, 0x04E2) }, /* Windows Powered Smartphone 2003 */ - { USB_DEVICE(0x045E, 0x04E3) }, /* Windows Powered Smartphone 2003 */ - { USB_DEVICE(0x045E, 0x04E4) }, /* Windows Powered Smartphone 2003 */ - { USB_DEVICE(0x045E, 0x04E5) }, /* Windows Powered Smartphone 2003 */ - { USB_DEVICE(0x045E, 0x04E6) }, /* Windows Powered Smartphone 2003 */ - { USB_DEVICE(0x045E, 0x04E7) }, /* Windows Powered Smartphone 2003 */ - { USB_DEVICE(0x045E, 0x04E8) }, /* Windows Powered Smartphone 2003 */ - { USB_DEVICE(0x045E, 0x04E9) }, /* Windows Powered Smartphone 2003 */ - { USB_DEVICE(0x045E, 0x04EA) }, /* Windows Powered Smartphone 2003 */ - { USB_DEVICE(0x049F, 0x0003) }, /* Compaq iPAQ USB Sync */ - { USB_DEVICE(0x049F, 0x0032) }, /* Compaq iPAQ USB Sync */ - { USB_DEVICE(0x04A4, 0x0014) }, /* Hitachi USB Sync */ - { USB_DEVICE(0x04AD, 0x0301) }, /* USB Sync 0301 */ - { USB_DEVICE(0x04AD, 0x0302) }, /* USB Sync 0302 */ - { USB_DEVICE(0x04AD, 0x0303) }, /* USB Sync 0303 */ - { USB_DEVICE(0x04AD, 0x0306) }, /* GPS Pocket PC USB Sync */ - { USB_DEVICE(0x04B7, 0x0531) }, /* MyGuide 7000 XL USB Sync */ - { USB_DEVICE(0x04C5, 0x1058) }, /* FUJITSU USB Sync */ - { USB_DEVICE(0x04C5, 0x1079) }, /* FUJITSU USB Sync */ - { USB_DEVICE(0x04DA, 0x2500) }, /* Panasonic USB Sync */ - { USB_DEVICE(0x04DD, 0x9102) }, /* SHARP WS003SH USB Modem */ - { USB_DEVICE(0x04DD, 0x9121) }, /* SHARP WS004SH USB Modem */ - { USB_DEVICE(0x04DD, 0x9123) }, /* SHARP WS007SH USB Modem */ - { USB_DEVICE(0x04DD, 0x9151) }, /* SHARP S01SH USB Modem */ - { USB_DEVICE(0x04DD, 0x91AC) }, /* SHARP WS011SH USB Modem */ - { USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */ - { USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */ - { USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */ - { USB_DEVICE(0x04E8, 0x5F03) }, /* Samsung NEXiO USB Sync */ - { USB_DEVICE(0x04E8, 0x5F04) }, /* Samsung NEXiO USB Sync */ - { USB_DEVICE(0x04E8, 0x6611) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x04E8, 0x6613) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x04E8, 0x6615) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x04E8, 0x6617) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x04E8, 0x6619) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x04E8, 0x661B) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x04E8, 0x662E) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x04E8, 0x6630) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x04E8, 0x6632) }, /* Samsung MITs USB Sync */ - { USB_DEVICE(0x04f1, 0x3011) }, /* JVC USB Sync */ - { USB_DEVICE(0x04F1, 0x3012) }, /* JVC USB Sync */ - { USB_DEVICE(0x0502, 0x1631) }, /* c10 Series */ - { USB_DEVICE(0x0502, 0x1632) }, /* c20 Series */ - { USB_DEVICE(0x0502, 0x16E1) }, /* Acer n10 Handheld USB Sync */ - { USB_DEVICE(0x0502, 0x16E2) }, /* Acer n20 Handheld USB Sync */ - { USB_DEVICE(0x0502, 0x16E3) }, /* Acer n30 Handheld USB Sync */ - { USB_DEVICE(0x0536, 0x01A0) }, /* HHP PDT */ - { USB_DEVICE(0x0543, 0x0ED9) }, /* ViewSonic Color Pocket PC V35 */ - { USB_DEVICE(0x0543, 0x1527) }, /* ViewSonic Color Pocket PC V36 */ - { USB_DEVICE(0x0543, 0x1529) }, /* ViewSonic Color Pocket PC V37 */ - { USB_DEVICE(0x0543, 0x152B) }, /* ViewSonic Color Pocket PC V38 */ - { USB_DEVICE(0x0543, 0x152E) }, /* ViewSonic Pocket PC */ - { USB_DEVICE(0x0543, 0x1921) }, /* ViewSonic Communicator Pocket PC */ - { USB_DEVICE(0x0543, 0x1922) }, /* ViewSonic Smartphone */ - { USB_DEVICE(0x0543, 0x1923) }, /* ViewSonic Pocket PC V30 */ - { USB_DEVICE(0x05E0, 0x2000) }, /* Symbol USB Sync */ - { USB_DEVICE(0x05E0, 0x2001) }, /* Symbol USB Sync 0x2001 */ - { USB_DEVICE(0x05E0, 0x2002) }, /* Symbol USB Sync 0x2002 */ - { USB_DEVICE(0x05E0, 0x2003) }, /* Symbol USB Sync 0x2003 */ - { USB_DEVICE(0x05E0, 0x2004) }, /* Symbol USB Sync 0x2004 */ - { USB_DEVICE(0x05E0, 0x2005) }, /* Symbol USB Sync 0x2005 */ - { USB_DEVICE(0x05E0, 0x2006) }, /* Symbol USB Sync 0x2006 */ - { USB_DEVICE(0x05E0, 0x2007) }, /* Symbol USB Sync 0x2007 */ - { USB_DEVICE(0x05E0, 0x2008) }, /* Symbol USB Sync 0x2008 */ - { USB_DEVICE(0x05E0, 0x2009) }, /* Symbol USB Sync 0x2009 */ - { USB_DEVICE(0x05E0, 0x200A) }, /* Symbol USB Sync 0x200A */ - { USB_DEVICE(0x067E, 0x1001) }, /* Intermec Mobile Computer */ - { USB_DEVICE(0x07CF, 0x2001) }, /* CASIO USB Sync 2001 */ - { USB_DEVICE(0x07CF, 0x2002) }, /* CASIO USB Sync 2002 */ - { USB_DEVICE(0x07CF, 0x2003) }, /* CASIO USB Sync 2003 */ - { USB_DEVICE(0x0930, 0x0700) }, /* TOSHIBA USB Sync 0700 */ - { USB_DEVICE(0x0930, 0x0705) }, /* TOSHIBA Pocket PC e310 */ - { USB_DEVICE(0x0930, 0x0706) }, /* TOSHIBA Pocket PC e740 */ - { USB_DEVICE(0x0930, 0x0707) }, /* TOSHIBA Pocket PC e330 Series */ - { USB_DEVICE(0x0930, 0x0708) }, /* TOSHIBA Pocket PC e350 Series */ - { USB_DEVICE(0x0930, 0x0709) }, /* TOSHIBA Pocket PC e750 Series */ - { USB_DEVICE(0x0930, 0x070A) }, /* TOSHIBA Pocket PC e400 Series */ - { USB_DEVICE(0x0930, 0x070B) }, /* TOSHIBA Pocket PC e800 Series */ - { USB_DEVICE(0x094B, 0x0001) }, /* Linkup Systems USB Sync */ - { USB_DEVICE(0x0960, 0x0065) }, /* BCOM USB Sync 0065 */ - { USB_DEVICE(0x0960, 0x0066) }, /* BCOM USB Sync 0066 */ - { USB_DEVICE(0x0960, 0x0067) }, /* BCOM USB Sync 0067 */ - { USB_DEVICE(0x0961, 0x0010) }, /* Portatec USB Sync */ - { USB_DEVICE(0x099E, 0x0052) }, /* Trimble GeoExplorer */ - { USB_DEVICE(0x099E, 0x4000) }, /* TDS Data Collector */ - { USB_DEVICE(0x0B05, 0x4200) }, /* ASUS USB Sync */ - { USB_DEVICE(0x0B05, 0x4201) }, /* ASUS USB Sync */ - { USB_DEVICE(0x0B05, 0x4202) }, /* ASUS USB Sync */ - { USB_DEVICE(0x0B05, 0x420F) }, /* ASUS USB Sync */ - { USB_DEVICE(0x0B05, 0x9200) }, /* ASUS USB Sync */ - { USB_DEVICE(0x0B05, 0x9202) }, /* ASUS USB Sync */ - { USB_DEVICE(0x0BB4, 0x00CE) }, /* HTC USB Sync */ - { USB_DEVICE(0x0BB4, 0x00CF) }, /* HTC USB Modem */ - { USB_DEVICE(0x0BB4, 0x0A01) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A02) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A03) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A04) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A05) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A06) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A07) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A08) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A09) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A0A) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A0B) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A0C) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A0D) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A0E) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A0F) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A10) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A11) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A12) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A13) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A14) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A15) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A16) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A17) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A18) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A19) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A1A) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A1B) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A1C) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A1D) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A1E) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A1F) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A20) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A21) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A22) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A23) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A24) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A25) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A26) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A27) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A28) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A29) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A2A) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A2B) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A2C) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A2D) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A2E) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A2F) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A30) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A31) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A32) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A33) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A34) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A35) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A36) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A37) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A38) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A39) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A3A) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A3B) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A3C) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A3D) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A3E) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A3F) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A40) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A41) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A42) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A43) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A44) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A45) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A46) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A47) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A48) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A49) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A4A) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A4B) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A4C) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A4D) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A4E) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A4F) }, /* PocketPC USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A50) }, /* HTC SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A51) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A52) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A53) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A54) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A55) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A56) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A57) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A58) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A59) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A5A) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A5B) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A5C) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A5D) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A5E) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A5F) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A60) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A61) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A62) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A63) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A64) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A65) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A66) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A67) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A68) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A69) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A6A) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A6B) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A6C) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A6D) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A6E) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A6F) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A70) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A71) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A72) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A73) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A74) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A75) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A76) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A77) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A78) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A79) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A7A) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A7B) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A7C) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A7D) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A7E) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A7F) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A80) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A81) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A82) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A83) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A84) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A85) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A86) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A87) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A88) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A89) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A8A) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A8B) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A8C) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A8D) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A8E) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A8F) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A90) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A91) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A92) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A93) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A94) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A95) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A96) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A97) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A98) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A99) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A9A) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A9B) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A9C) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A9D) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A9E) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0A9F) }, /* SmartPhone USB Sync */ - { USB_DEVICE(0x0BB4, 0x0BCE) }, /* "High Tech Computer Corp" */ - { USB_DEVICE(0x0BF8, 0x1001) }, /* Fujitsu Siemens Computers USB Sync */ - { USB_DEVICE(0x0C44, 0x03A2) }, /* Motorola iDEN Smartphone */ - { USB_DEVICE(0x0C8E, 0x6000) }, /* Cesscom Luxian Series */ - { USB_DEVICE(0x0CAD, 0x9001) }, /* Motorola PowerPad Pocket PC Device */ - { USB_DEVICE(0x0F4E, 0x0200) }, /* Freedom Scientific USB Sync */ - { USB_DEVICE(0x0F98, 0x0201) }, /* Cyberbank USB Sync */ - { USB_DEVICE(0x0FB8, 0x3001) }, /* Wistron USB Sync */ - { USB_DEVICE(0x0FB8, 0x3002) }, /* Wistron USB Sync */ - { USB_DEVICE(0x0FB8, 0x3003) }, /* Wistron USB Sync */ - { USB_DEVICE(0x0FB8, 0x4001) }, /* Wistron USB Sync */ - { USB_DEVICE(0x1066, 0x00CE) }, /* E-TEN USB Sync */ - { USB_DEVICE(0x1066, 0x0300) }, /* E-TEN P3XX Pocket PC */ - { USB_DEVICE(0x1066, 0x0500) }, /* E-TEN P5XX Pocket PC */ - { USB_DEVICE(0x1066, 0x0600) }, /* E-TEN P6XX Pocket PC */ - { USB_DEVICE(0x1066, 0x0700) }, /* E-TEN P7XX Pocket PC */ - { USB_DEVICE(0x1114, 0x0001) }, /* Psion Teklogix Sync 753x */ - { USB_DEVICE(0x1114, 0x0004) }, /* Psion Teklogix Sync netBookPro */ - { USB_DEVICE(0x1114, 0x0006) }, /* Psion Teklogix Sync 7525 */ - { USB_DEVICE(0x1182, 0x1388) }, /* VES USB Sync */ - { USB_DEVICE(0x11D9, 0x1002) }, /* Rugged Pocket PC 2003 */ - { USB_DEVICE(0x11D9, 0x1003) }, /* Rugged Pocket PC 2003 */ - { USB_DEVICE(0x1231, 0xCE01) }, /* USB Sync 03 */ - { USB_DEVICE(0x1231, 0xCE02) }, /* USB Sync 03 */ - { USB_DEVICE(0x1690, 0x0601) }, /* Askey USB Sync */ - { USB_DEVICE(0x22B8, 0x4204) }, /* Motorola MPx200 Smartphone */ - { USB_DEVICE(0x22B8, 0x4214) }, /* Motorola MPc GSM */ - { USB_DEVICE(0x22B8, 0x4224) }, /* Motorola MPx220 Smartphone */ - { USB_DEVICE(0x22B8, 0x4234) }, /* Motorola MPc CDMA */ - { USB_DEVICE(0x22B8, 0x4244) }, /* Motorola MPx100 Smartphone */ - { USB_DEVICE(0x3340, 0x011C) }, /* Mio DigiWalker PPC StrongARM */ - { USB_DEVICE(0x3340, 0x0326) }, /* Mio DigiWalker 338 */ - { USB_DEVICE(0x3340, 0x0426) }, /* Mio DigiWalker 338 */ - { USB_DEVICE(0x3340, 0x043A) }, /* Mio DigiWalker USB Sync */ - { USB_DEVICE(0x3340, 0x051C) }, /* MiTAC USB Sync 528 */ - { USB_DEVICE(0x3340, 0x053A) }, /* Mio DigiWalker SmartPhone USB Sync */ - { USB_DEVICE(0x3340, 0x071C) }, /* MiTAC USB Sync */ - { USB_DEVICE(0x3340, 0x0B1C) }, /* Generic PPC StrongARM */ - { USB_DEVICE(0x3340, 0x0E3A) }, /* Generic PPC USB Sync */ - { USB_DEVICE(0x3340, 0x0F1C) }, /* Itautec USB Sync */ - { USB_DEVICE(0x3340, 0x0F3A) }, /* Generic SmartPhone USB Sync */ - { USB_DEVICE(0x3340, 0x1326) }, /* Itautec USB Sync */ - { USB_DEVICE(0x3340, 0x191C) }, /* YAKUMO USB Sync */ - { USB_DEVICE(0x3340, 0x2326) }, /* Vobis USB Sync */ - { USB_DEVICE(0x3340, 0x3326) }, /* MEDION Winodws Moble USB Sync */ - { USB_DEVICE(0x3708, 0x20CE) }, /* Legend USB Sync */ - { USB_DEVICE(0x3708, 0x21CE) }, /* Lenovo USB Sync */ - { USB_DEVICE(0x4113, 0x0210) }, /* Mobile Media Technology USB Sync */ - { USB_DEVICE(0x4113, 0x0211) }, /* Mobile Media Technology USB Sync */ - { USB_DEVICE(0x4113, 0x0400) }, /* Mobile Media Technology USB Sync */ - { USB_DEVICE(0x4113, 0x0410) }, /* Mobile Media Technology USB Sync */ - { USB_DEVICE(0x413C, 0x4001) }, /* Dell Axim USB Sync */ - { USB_DEVICE(0x413C, 0x4002) }, /* Dell Axim USB Sync */ - { USB_DEVICE(0x413C, 0x4003) }, /* Dell Axim USB Sync */ - { USB_DEVICE(0x413C, 0x4004) }, /* Dell Axim USB Sync */ - { USB_DEVICE(0x413C, 0x4005) }, /* Dell Axim USB Sync */ - { USB_DEVICE(0x413C, 0x4006) }, /* Dell Axim USB Sync */ - { USB_DEVICE(0x413C, 0x4007) }, /* Dell Axim USB Sync */ - { USB_DEVICE(0x413C, 0x4008) }, /* Dell Axim USB Sync */ - { USB_DEVICE(0x413C, 0x4009) }, /* Dell Axim USB Sync */ - { USB_DEVICE(0x4505, 0x0010) }, /* Smartphone */ - { USB_DEVICE(0x5E04, 0xCE00) }, /* SAGEM Wireless Assistant */ - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, ipaq_id_table); - -static struct usb_driver ipaq_driver = { - .name = "ipaq", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = ipaq_id_table, -}; - - -/* All of the device info needed for the Compaq iPAQ */ -static struct usb_serial_driver ipaq_device = { - .driver = { - .owner = THIS_MODULE, - .name = "ipaq", - }, - .description = "PocketPC PDA", - .id_table = ipaq_id_table, - .bulk_in_size = 256, - .bulk_out_size = 256, - .open = ipaq_open, - .attach = ipaq_startup, - .calc_num_ports = ipaq_calc_num_ports, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &ipaq_device, NULL -}; - -static int ipaq_open(struct tty_struct *tty, - struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - int result = 0; - int retries = connect_retries; - - dbg("%s - port %d", __func__, port->number); - - msleep(1000*initial_wait); - - /* - * Send out control message observed in win98 sniffs. Not sure what - * it does, but from empirical observations, it seems that the device - * will start the chat sequence once one of these messages gets - * through. Since this has a reasonably high failure rate, we retry - * several times. - */ - while (retries--) { - result = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21, - 0x1, 0, NULL, 0, 100); - if (!result) - break; - - msleep(1000); - } - if (!retries && result) { - dev_err(&port->dev, "%s - failed doing control urb, error %d\n", - __func__, result); - return result; - } - - return usb_serial_generic_open(tty, port); -} - -static int ipaq_calc_num_ports(struct usb_serial *serial) -{ - /* - * some devices have 3 endpoints, the 3rd of which - * must be ignored as it would make the core - * create a second port which oopses when used - */ - int ipaq_num_ports = 1; - - dbg("%s - numberofendpoints: %d", __FUNCTION__, - (int)serial->interface->cur_altsetting->desc.bNumEndpoints); - - /* - * a few devices have 4 endpoints, seemingly Yakuma devices, - * and we need the second pair, so let them have 2 ports - * - * TODO: can we drop port 1 ? - */ - if (serial->interface->cur_altsetting->desc.bNumEndpoints > 3) { - ipaq_num_ports = 2; - } - - return ipaq_num_ports; -} - - -static int ipaq_startup(struct usb_serial *serial) -{ - dbg("%s", __func__); - - /* Some of the devices in ipaq_id_table[] are composite, and we - * shouldn't bind to all the interfaces. This test will rule out - * some obviously invalid possibilities. - */ - if (serial->num_bulk_in < serial->num_ports || - serial->num_bulk_out < serial->num_ports) - return -ENODEV; - - if (serial->dev->actconfig->desc.bConfigurationValue != 1) { - /* - * FIXME: HP iPaq rx3715, possibly others, have 1 config that - * is labeled as 2 - */ - - dev_err(&serial->dev->dev, "active config #%d != 1 ??\n", - serial->dev->actconfig->desc.bConfigurationValue); - return -ENODEV; - } - - dbg("%s - iPAQ module configured for %d ports", - __FUNCTION__, serial->num_ports); - - return usb_reset_configuration(serial->dev); -} - -static int __init ipaq_init(void) -{ - int retval; - - if (vendor) { - ipaq_id_table[0].idVendor = vendor; - ipaq_id_table[0].idProduct = product; - } - - retval = usb_serial_register_drivers(&ipaq_driver, serial_drivers); - if (retval == 0) - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return retval; -} - -static void __exit ipaq_exit(void) -{ - usb_serial_deregister_drivers(&ipaq_driver, serial_drivers); -} - - -module_init(ipaq_init); -module_exit(ipaq_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - -module_param(vendor, ushort, 0); -MODULE_PARM_DESC(vendor, "User specified USB idVendor"); - -module_param(product, ushort, 0); -MODULE_PARM_DESC(product, "User specified USB idProduct"); - -module_param(connect_retries, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(connect_retries, - "Maximum number of connect retries (one second each)"); - -module_param(initial_wait, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(initial_wait, - "Time to wait before attempting a connection (in seconds)"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/ipw.c b/ANDROID_3.4.5/drivers/usb/serial/ipw.c deleted file mode 100644 index 76a06406..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/ipw.c +++ /dev/null @@ -1,344 +0,0 @@ -/* - * IPWireless 3G UMTS TDD Modem driver (USB connected) - * - * Copyright (C) 2004 Roelf Diedericks - * Copyright (C) 2004 Greg Kroah-Hartman - * - * 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. - * - * All information about the device was acquired using SnoopyPro - * on MSFT's O/S, and examing the MSFT drivers' debug output - * (insanely left _on_ in the enduser version) - * - * It was written out of frustration with the IPWireless USB modem - * supplied by Axity3G/Sentech South Africa not supporting - * Linux whatsoever. - * - * Nobody provided any proprietary information that was not already - * available for this device. - * - * The modem adheres to the "3GPP TS 27.007 AT command set for 3G - * User Equipment (UE)" standard, available from - * http://www.3gpp.org/ftp/Specs/html-info/27007.htm - * - * The code was only tested the IPWireless handheld modem distributed - * in South Africa by Sentech. - * - * It may work for Woosh Inc in .nz too, as it appears they use the - * same kit. - * - * There is still some work to be done in terms of handling - * DCD, DTR, RTS, CTS which are currently faked. - * It's good enough for PPP at this point. It's based off all kinds of - * code found in usb/serial and usb/class - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "usb-wwan.h" - -/* - * Version Information - */ -#define DRIVER_VERSION "v0.4" -#define DRIVER_AUTHOR "Roelf Diedericks" -#define DRIVER_DESC "IPWireless tty driver" - -#define IPW_TTY_MAJOR 240 /* real device node major id, experimental range */ -#define IPW_TTY_MINORS 256 /* we support 256 devices, dunno why, it'd be insane :) */ - -#define USB_IPW_MAGIC 0x6d02 /* magic number for ipw struct */ - - -/* Message sizes */ -#define EVENT_BUFFER_SIZE 0xFF -#define CHAR2INT16(c1, c0) (((u32)((c1) & 0xff) << 8) + (u32)((c0) & 0xff)) - -/* vendor/product pairs that are known work with this driver*/ -#define IPW_VID 0x0bc3 -#define IPW_PID 0x0001 - - -/* Vendor commands: */ - -/* baud rates */ -enum { - ipw_sio_b256000 = 0x000e, - ipw_sio_b128000 = 0x001d, - ipw_sio_b115200 = 0x0020, - ipw_sio_b57600 = 0x0040, - ipw_sio_b56000 = 0x0042, - ipw_sio_b38400 = 0x0060, - ipw_sio_b19200 = 0x00c0, - ipw_sio_b14400 = 0x0100, - ipw_sio_b9600 = 0x0180, - ipw_sio_b4800 = 0x0300, - ipw_sio_b2400 = 0x0600, - ipw_sio_b1200 = 0x0c00, - ipw_sio_b600 = 0x1800 -}; - -/* data bits */ -#define ipw_dtb_7 0x700 -#define ipw_dtb_8 0x810 /* ok so the define is misleading, I know, but forces 8,n,1 */ - /* I mean, is there a point to any other setting these days? :) */ - -/* usb control request types : */ -#define IPW_SIO_RXCTL 0x00 /* control bulk rx channel transmissions, value=1/0 (on/off) */ -#define IPW_SIO_SET_BAUD 0x01 /* set baud, value=requested ipw_sio_bxxxx */ -#define IPW_SIO_SET_LINE 0x03 /* set databits, parity. value=ipw_dtb_x */ -#define IPW_SIO_SET_PIN 0x03 /* set/clear dtr/rts value=ipw_pin_xxx */ -#define IPW_SIO_POLL 0x08 /* get serial port status byte, call with value=0 */ -#define IPW_SIO_INIT 0x11 /* initializes ? value=0 (appears as first thing todo on open) */ -#define IPW_SIO_PURGE 0x12 /* purge all transmissions?, call with value=numchar_to_purge */ -#define IPW_SIO_HANDFLOW 0x13 /* set xon/xoff limits value=0, and a buffer of 0x10 bytes */ -#define IPW_SIO_SETCHARS 0x13 /* set the flowcontrol special chars, value=0, buf=6 bytes, */ - /* last 2 bytes contain flowcontrol chars e.g. 00 00 00 00 11 13 */ - -/* values used for request IPW_SIO_SET_PIN */ -#define IPW_PIN_SETDTR 0x101 -#define IPW_PIN_SETRTS 0x202 -#define IPW_PIN_CLRDTR 0x100 -#define IPW_PIN_CLRRTS 0x200 /* unconfirmed */ - -/* values used for request IPW_SIO_RXCTL */ -#define IPW_RXBULK_ON 1 -#define IPW_RXBULK_OFF 0 - -/* various 16 byte hardcoded transferbuffers used by flow control */ -#define IPW_BYTES_FLOWINIT { 0x01, 0, 0, 0, 0x40, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0 } - -/* Interpretation of modem status lines */ -/* These need sorting out by individually connecting pins and checking - * results. FIXME! - * When data is being sent we see 0x30 in the lower byte; this must - * contain DSR and CTS ... - */ -#define IPW_DSR ((1<<4) | (1<<5)) -#define IPW_CTS ((1<<5) | (1<<4)) - -#define IPW_WANTS_TO_SEND 0x30 - -static const struct usb_device_id usb_ipw_ids[] = { - { USB_DEVICE(IPW_VID, IPW_PID) }, - { }, -}; - -MODULE_DEVICE_TABLE(usb, usb_ipw_ids); - -static struct usb_driver usb_ipw_driver = { - .name = "ipwtty", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = usb_ipw_ids, -}; - -static bool debug; - -static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct usb_device *dev = port->serial->dev; - u8 buf_flow_static[16] = IPW_BYTES_FLOWINIT; - u8 *buf_flow_init; - int result; - - dbg("%s", __func__); - - buf_flow_init = kmemdup(buf_flow_static, 16, GFP_KERNEL); - if (!buf_flow_init) - return -ENOMEM; - - /* --1: Tell the modem to initialize (we think) From sniffs this is - * always the first thing that gets sent to the modem during - * opening of the device */ - dbg("%s: Sending SIO_INIT (we guess)", __func__); - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - IPW_SIO_INIT, - USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, - 0, - 0, /* index */ - NULL, - 0, - 100000); - if (result < 0) - dev_err(&port->dev, - "Init of modem failed (error = %d)\n", result); - - /* reset the bulk pipes */ - usb_clear_halt(dev, - usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress)); - usb_clear_halt(dev, - usb_sndbulkpipe(dev, port->bulk_out_endpointAddress)); - - /*--2: Start reading from the device */ - dbg("%s: setting up bulk read callback", __func__); - usb_wwan_open(tty, port); - - /*--3: Tell the modem to open the floodgates on the rx bulk channel */ - dbg("%s:asking modem for RxRead (RXBULK_ON)", __func__); - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - IPW_SIO_RXCTL, - USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, - IPW_RXBULK_ON, - 0, /* index */ - NULL, - 0, - 100000); - if (result < 0) - dev_err(&port->dev, - "Enabling bulk RxRead failed (error = %d)\n", result); - - /*--4: setup the initial flowcontrol */ - dbg("%s:setting init flowcontrol (%s)", __func__, buf_flow_init); - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - IPW_SIO_HANDFLOW, - USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, - 0, - 0, - buf_flow_init, - 0x10, - 200000); - if (result < 0) - dev_err(&port->dev, - "initial flowcontrol failed (error = %d)\n", result); - - kfree(buf_flow_init); - return 0; -} - -/* fake probe - only to allocate data structures */ -static int ipw_probe(struct usb_serial *serial, const struct usb_device_id *id) -{ - struct usb_wwan_intf_private *data; - - data = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL); - if (!data) - return -ENOMEM; - - spin_lock_init(&data->susp_lock); - usb_set_serial_data(serial, data); - return 0; -} - -static void ipw_release(struct usb_serial *serial) -{ - struct usb_wwan_intf_private *data = usb_get_serial_data(serial); - - usb_wwan_release(serial); - usb_set_serial_data(serial, NULL); - kfree(data); -} - -static void ipw_dtr_rts(struct usb_serial_port *port, int on) -{ - struct usb_device *dev = port->serial->dev; - int result; - - dbg("%s: on = %d", __func__, on); - - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - IPW_SIO_SET_PIN, - USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, - on ? IPW_PIN_SETDTR : IPW_PIN_CLRDTR, - 0, - NULL, - 0, - 200000); - if (result < 0) - dev_err(&port->dev, "setting dtr failed (error = %d)\n", - result); - - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - IPW_SIO_SET_PIN, USB_TYPE_VENDOR | - USB_RECIP_INTERFACE | USB_DIR_OUT, - on ? IPW_PIN_SETRTS : IPW_PIN_CLRRTS, - 0, - NULL, - 0, - 200000); - if (result < 0) - dev_err(&port->dev, "setting rts failed (error = %d)\n", - result); -} - -static void ipw_close(struct usb_serial_port *port) -{ - struct usb_device *dev = port->serial->dev; - int result; - - /*--3: purge */ - dbg("%s:sending purge", __func__); - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - IPW_SIO_PURGE, USB_TYPE_VENDOR | - USB_RECIP_INTERFACE | USB_DIR_OUT, - 0x03, - 0, - NULL, - 0, - 200000); - if (result < 0) - dev_err(&port->dev, "purge failed (error = %d)\n", result); - - - /* send RXBULK_off (tell modem to stop transmitting bulk data on - rx chan) */ - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - IPW_SIO_RXCTL, - USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, - IPW_RXBULK_OFF, - 0, /* index */ - NULL, - 0, - 100000); - - if (result < 0) - dev_err(&port->dev, - "Disabling bulk RxRead failed (error = %d)\n", result); - - usb_wwan_close(port); -} - -static struct usb_serial_driver ipw_device = { - .driver = { - .owner = THIS_MODULE, - .name = "ipw", - }, - .description = "IPWireless converter", - .id_table = usb_ipw_ids, - .num_ports = 1, - .disconnect = usb_wwan_disconnect, - .open = ipw_open, - .close = ipw_close, - .probe = ipw_probe, - .attach = usb_wwan_startup, - .release = ipw_release, - .dtr_rts = ipw_dtr_rts, - .write = usb_wwan_write, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &ipw_device, NULL -}; - -module_usb_serial_driver(usb_ipw_driver, serial_drivers); - -/* Module information */ -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/ir-usb.c b/ANDROID_3.4.5/drivers/usb/serial/ir-usb.c deleted file mode 100644 index 84965cd6..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/ir-usb.c +++ /dev/null @@ -1,476 +0,0 @@ -/* - * USB IR Dongle driver - * - * Copyright (C) 2001-2002 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2002 Gary Brubaker (xavyer@ix.netcom.com) - * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This driver allows a USB IrDA device to be used as a "dumb" serial device. - * This can be useful if you do not have access to a full IrDA stack on the - * other side of the connection. If you do have an IrDA stack on both devices, - * please use the usb-irda driver, as it contains the proper error checking and - * other goodness of a full IrDA stack. - * - * Portions of this driver were taken from drivers/net/irda/irda-usb.c, which - * was written by Roman Weissgaerber , Dag Brattli - * , and Jean Tourrilhes - * - * See Documentation/usb/usb-serial.txt for more information on using this - * driver - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Version Information - */ -#define DRIVER_VERSION "v0.5" -#define DRIVER_AUTHOR "Greg Kroah-Hartman , Johan Hovold " -#define DRIVER_DESC "USB IR Dongle driver" - -static bool debug; - -/* if overridden by the user, then use their value for the size of the read and - * write urbs */ -static int buffer_size; - -/* if overridden by the user, then use the specified number of XBOFs */ -static int xbof = -1; - -static int ir_startup (struct usb_serial *serial); -static int ir_open(struct tty_struct *tty, struct usb_serial_port *port); -static int ir_prepare_write_buffer(struct usb_serial_port *port, - void *dest, size_t size); -static void ir_process_read_urb(struct urb *urb); -static void ir_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios); - -/* Not that this lot means you can only have one per system */ -static u8 ir_baud; -static u8 ir_xbof; -static u8 ir_add_bof; - -static const struct usb_device_id ir_id_table[] = { - { USB_DEVICE(0x050f, 0x0180) }, /* KC Technology, KC-180 */ - { USB_DEVICE(0x08e9, 0x0100) }, /* XTNDAccess */ - { USB_DEVICE(0x09c4, 0x0011) }, /* ACTiSys ACT-IR2000U */ - { USB_INTERFACE_INFO(USB_CLASS_APP_SPEC, USB_SUBCLASS_IRDA, 0) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, ir_id_table); - -static struct usb_driver ir_driver = { - .name = "ir-usb", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = ir_id_table, -}; - -static struct usb_serial_driver ir_device = { - .driver = { - .owner = THIS_MODULE, - .name = "ir-usb", - }, - .description = "IR Dongle", - .id_table = ir_id_table, - .num_ports = 1, - .set_termios = ir_set_termios, - .attach = ir_startup, - .open = ir_open, - .prepare_write_buffer = ir_prepare_write_buffer, - .process_read_urb = ir_process_read_urb, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &ir_device, NULL -}; - -static inline void irda_usb_dump_class_desc(struct usb_irda_cs_descriptor *desc) -{ - dbg("bLength=%x", desc->bLength); - dbg("bDescriptorType=%x", desc->bDescriptorType); - dbg("bcdSpecRevision=%x", __le16_to_cpu(desc->bcdSpecRevision)); - dbg("bmDataSize=%x", desc->bmDataSize); - dbg("bmWindowSize=%x", desc->bmWindowSize); - dbg("bmMinTurnaroundTime=%d", desc->bmMinTurnaroundTime); - dbg("wBaudRate=%x", __le16_to_cpu(desc->wBaudRate)); - dbg("bmAdditionalBOFs=%x", desc->bmAdditionalBOFs); - dbg("bIrdaRateSniff=%x", desc->bIrdaRateSniff); - dbg("bMaxUnicastList=%x", desc->bMaxUnicastList); -} - -/*------------------------------------------------------------------*/ -/* - * Function irda_usb_find_class_desc(dev, ifnum) - * - * Returns instance of IrDA class descriptor, or NULL if not found - * - * The class descriptor is some extra info that IrDA USB devices will - * offer to us, describing their IrDA characteristics. We will use that in - * irda_usb_init_qos() - * - * Based on the same function in drivers/net/irda/irda-usb.c - */ -static struct usb_irda_cs_descriptor * -irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum) -{ - struct usb_irda_cs_descriptor *desc; - int ret; - - desc = kzalloc(sizeof(*desc), GFP_KERNEL); - if (!desc) - return NULL; - - ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_CS_IRDA_GET_CLASS_DESC, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, ifnum, desc, sizeof(*desc), 1000); - - dbg("%s - ret=%d", __func__, ret); - if (ret < sizeof(*desc)) { - dbg("%s - class descriptor read %s (%d)", - __func__, - (ret < 0) ? "failed" : "too short", - ret); - goto error; - } - if (desc->bDescriptorType != USB_DT_CS_IRDA) { - dbg("%s - bad class descriptor type", __func__); - goto error; - } - - irda_usb_dump_class_desc(desc); - return desc; - -error: - kfree(desc); - return NULL; -} - -static u8 ir_xbof_change(u8 xbof) -{ - u8 result; - - /* reference irda-usb.c */ - switch (xbof) { - case 48: - result = 0x10; - break; - case 28: - case 24: - result = 0x20; - break; - default: - case 12: - result = 0x30; - break; - case 5: - case 6: - result = 0x40; - break; - case 3: - result = 0x50; - break; - case 2: - result = 0x60; - break; - case 1: - result = 0x70; - break; - case 0: - result = 0x80; - break; - } - - return(result); -} - -static int ir_startup(struct usb_serial *serial) -{ - struct usb_irda_cs_descriptor *irda_desc; - - irda_desc = irda_usb_find_class_desc(serial->dev, 0); - if (!irda_desc) { - dev_err(&serial->dev->dev, - "IRDA class descriptor not found, device not bound\n"); - return -ENODEV; - } - - dbg("%s - Baud rates supported:%s%s%s%s%s%s%s%s%s", - __func__, - (irda_desc->wBaudRate & USB_IRDA_BR_2400) ? " 2400" : "", - (irda_desc->wBaudRate & USB_IRDA_BR_9600) ? " 9600" : "", - (irda_desc->wBaudRate & USB_IRDA_BR_19200) ? " 19200" : "", - (irda_desc->wBaudRate & USB_IRDA_BR_38400) ? " 38400" : "", - (irda_desc->wBaudRate & USB_IRDA_BR_57600) ? " 57600" : "", - (irda_desc->wBaudRate & USB_IRDA_BR_115200) ? " 115200" : "", - (irda_desc->wBaudRate & USB_IRDA_BR_576000) ? " 576000" : "", - (irda_desc->wBaudRate & USB_IRDA_BR_1152000) ? " 1152000" : "", - (irda_desc->wBaudRate & USB_IRDA_BR_4000000) ? " 4000000" : ""); - - switch (irda_desc->bmAdditionalBOFs) { - case USB_IRDA_AB_48: - ir_add_bof = 48; - break; - case USB_IRDA_AB_24: - ir_add_bof = 24; - break; - case USB_IRDA_AB_12: - ir_add_bof = 12; - break; - case USB_IRDA_AB_6: - ir_add_bof = 6; - break; - case USB_IRDA_AB_3: - ir_add_bof = 3; - break; - case USB_IRDA_AB_2: - ir_add_bof = 2; - break; - case USB_IRDA_AB_1: - ir_add_bof = 1; - break; - case USB_IRDA_AB_0: - ir_add_bof = 0; - break; - default: - break; - } - - kfree(irda_desc); - - return 0; -} - -static int ir_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - int i; - - dbg("%s - port %d", __func__, port->number); - - for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) - port->write_urbs[i]->transfer_flags = URB_ZERO_PACKET; - - /* Start reading from the device */ - return usb_serial_generic_open(tty, port); -} - -static int ir_prepare_write_buffer(struct usb_serial_port *port, - void *dest, size_t size) -{ - unsigned char *buf = dest; - int count; - - /* - * The first byte of the packet we send to the device contains an - * inbound header which indicates an additional number of BOFs and - * a baud rate change. - * - * See section 5.4.2.2 of the USB IrDA spec. - */ - *buf = ir_xbof | ir_baud; - - count = kfifo_out_locked(&port->write_fifo, buf + 1, size - 1, - &port->lock); - return count + 1; -} - -static void ir_process_read_urb(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - unsigned char *data = urb->transfer_buffer; - struct tty_struct *tty; - - if (!urb->actual_length) - return; - /* - * The first byte of the packet we get from the device - * contains a busy indicator and baud rate change. - * See section 5.4.1.2 of the USB IrDA spec. - */ - if (*data & 0x0f) - ir_baud = *data & 0x0f; - - if (urb->actual_length == 1) - return; - - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - tty_insert_flip_string(tty, data + 1, urb->actual_length - 1); - tty_flip_buffer_push(tty); - tty_kref_put(tty); -} - -static void ir_set_termios_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - - kfree(urb->transfer_buffer); - - if (status) - dbg("%s - non-zero urb status: %d", __func__, status); -} - -static void ir_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) -{ - struct urb *urb; - unsigned char *transfer_buffer; - int result; - speed_t baud; - int ir_baud; - - dbg("%s - port %d", __func__, port->number); - - baud = tty_get_baud_rate(tty); - - /* - * FIXME, we should compare the baud request against the - * capability stated in the IR header that we got in the - * startup function. - */ - - switch (baud) { - case 2400: - ir_baud = USB_IRDA_BR_2400; - break; - case 9600: - ir_baud = USB_IRDA_BR_9600; - break; - case 19200: - ir_baud = USB_IRDA_BR_19200; - break; - case 38400: - ir_baud = USB_IRDA_BR_38400; - break; - case 57600: - ir_baud = USB_IRDA_BR_57600; - break; - case 115200: - ir_baud = USB_IRDA_BR_115200; - break; - case 576000: - ir_baud = USB_IRDA_BR_576000; - break; - case 1152000: - ir_baud = USB_IRDA_BR_1152000; - break; - case 4000000: - ir_baud = USB_IRDA_BR_4000000; - break; - default: - ir_baud = USB_IRDA_BR_9600; - baud = 9600; - } - - if (xbof == -1) - ir_xbof = ir_xbof_change(ir_add_bof); - else - ir_xbof = ir_xbof_change(xbof) ; - - /* Only speed changes are supported */ - tty_termios_copy_hw(tty->termios, old_termios); - tty_encode_baud_rate(tty, baud, baud); - - /* - * send the baud change out on an "empty" data packet - */ - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - dev_err(&port->dev, "%s - no more urbs\n", __func__); - return; - } - transfer_buffer = kmalloc(1, GFP_KERNEL); - if (!transfer_buffer) { - dev_err(&port->dev, "%s - out of memory\n", __func__); - goto err_buf; - } - - *transfer_buffer = ir_xbof | ir_baud; - - usb_fill_bulk_urb( - urb, - port->serial->dev, - usb_sndbulkpipe(port->serial->dev, - port->bulk_out_endpointAddress), - transfer_buffer, - 1, - ir_set_termios_callback, - port); - - urb->transfer_flags = URB_ZERO_PACKET; - - result = usb_submit_urb(urb, GFP_KERNEL); - if (result) { - dev_err(&port->dev, "%s - failed to submit urb: %d\n", - __func__, result); - goto err_subm; - } - - usb_free_urb(urb); - - return; -err_subm: - kfree(transfer_buffer); -err_buf: - usb_free_urb(urb); -} - -static int __init ir_init(void) -{ - int retval; - - if (buffer_size) { - ir_device.bulk_in_size = buffer_size; - ir_device.bulk_out_size = buffer_size; - } - - retval = usb_serial_register_drivers(&ir_driver, serial_drivers); - if (retval == 0) - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return retval; -} - -static void __exit ir_exit(void) -{ - usb_serial_deregister_drivers(&ir_driver, serial_drivers); -} - - -module_init(ir_init); -module_exit(ir_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); -module_param(xbof, int, 0); -MODULE_PARM_DESC(xbof, "Force specific number of XBOFs"); -module_param(buffer_size, int, 0); -MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers"); - diff --git a/ANDROID_3.4.5/drivers/usb/serial/iuu_phoenix.c b/ANDROID_3.4.5/drivers/usb/serial/iuu_phoenix.c deleted file mode 100644 index f2192d52..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/iuu_phoenix.c +++ /dev/null @@ -1,1324 +0,0 @@ -/* - * Infinity Unlimited USB Phoenix driver - * - * Copyright (C) 2010 James Courtier-Dutton (James@superbug.co.uk) - - * Copyright (C) 2007 Alain Degreffe (eczema@ecze.com) - * - * Original code taken from iuutool (Copyright (C) 2006 Juan Carlos Borrás) - * - * 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. - * - * And tested with help of WB Electronics - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "iuu_phoenix.h" -#include - - -#ifdef CONFIG_USB_SERIAL_DEBUG -static bool debug = 1; -#else -static bool debug; -#endif - -/* - * Version Information - */ -#define DRIVER_VERSION "v0.12" -#define DRIVER_DESC "Infinity USB Unlimited Phoenix driver" - -static const struct usb_device_id id_table[] = { - {USB_DEVICE(IUU_USB_VENDOR_ID, IUU_USB_PRODUCT_ID)}, - {} /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver iuu_driver = { - .name = "iuu_phoenix", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - -/* turbo parameter */ -static int boost = 100; -static int clockmode = 1; -static int cdmode = 1; -static int iuu_cardin; -static int iuu_cardout; -static bool xmas; -static int vcc_default = 5; - -static void read_rxcmd_callback(struct urb *urb); - -struct iuu_private { - spinlock_t lock; /* store irq state */ - wait_queue_head_t delta_msr_wait; - u8 line_status; - int tiostatus; /* store IUART SIGNAL for tiocmget call */ - u8 reset; /* if 1 reset is needed */ - int poll; /* number of poll */ - u8 *writebuf; /* buffer for writing to device */ - int writelen; /* num of byte to write to device */ - u8 *buf; /* used for initialize speed */ - u8 *dbgbuf; /* debug buffer */ - u8 len; - int vcc; /* vcc (either 3 or 5 V) */ - u32 baud; - u32 boost; - u32 clk; -}; - - -static void iuu_free_buf(struct iuu_private *priv) -{ - kfree(priv->buf); - kfree(priv->dbgbuf); - kfree(priv->writebuf); -} - -static int iuu_alloc_buf(struct iuu_private *priv) -{ - priv->buf = kzalloc(256, GFP_KERNEL); - priv->dbgbuf = kzalloc(256, GFP_KERNEL); - priv->writebuf = kzalloc(256, GFP_KERNEL); - if (!priv->buf || !priv->dbgbuf || !priv->writebuf) { - iuu_free_buf(priv); - dbg("%s problem allocation buffer", __func__); - return -ENOMEM; - } - dbg("%s - Privates buffers allocation success", __func__); - return 0; -} - -static int iuu_startup(struct usb_serial *serial) -{ - struct iuu_private *priv; - priv = kzalloc(sizeof(struct iuu_private), GFP_KERNEL); - dbg("%s- priv allocation success", __func__); - if (!priv) - return -ENOMEM; - if (iuu_alloc_buf(priv)) { - kfree(priv); - return -ENOMEM; - } - priv->vcc = vcc_default; - spin_lock_init(&priv->lock); - init_waitqueue_head(&priv->delta_msr_wait); - usb_set_serial_port_data(serial->port[0], priv); - return 0; -} - -/* Release function */ -static void iuu_release(struct usb_serial *serial) -{ - struct usb_serial_port *port = serial->port[0]; - struct iuu_private *priv = usb_get_serial_port_data(port); - if (!port) - return; - - dbg("%s", __func__); - - if (priv) { - iuu_free_buf(priv); - dbg("%s - I will free all", __func__); - usb_set_serial_port_data(port, NULL); - - dbg("%s - priv is not anymore in port structure", __func__); - kfree(priv); - - dbg("%s priv is now kfree", __func__); - } -} - -static int iuu_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct iuu_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - - /* FIXME: locking on tiomstatus */ - dbg("%s (%d) msg : SET = 0x%04x, CLEAR = 0x%04x ", __func__, - port->number, set, clear); - - spin_lock_irqsave(&priv->lock, flags); - - if ((set & TIOCM_RTS) && !(priv->tiostatus == TIOCM_RTS)) { - dbg("%s TIOCMSET RESET called !!!", __func__); - priv->reset = 1; - } - if (set & TIOCM_RTS) - priv->tiostatus = TIOCM_RTS; - - spin_unlock_irqrestore(&priv->lock, flags); - return 0; -} - -/* This is used to provide a carrier detect mechanism - * When a card is present, the response is 0x00 - * When no card , the reader respond with TIOCM_CD - * This is known as CD autodetect mechanism - */ -static int iuu_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct iuu_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - int rc; - - spin_lock_irqsave(&priv->lock, flags); - rc = priv->tiostatus; - spin_unlock_irqrestore(&priv->lock, flags); - - return rc; -} - -static void iuu_rxcmd(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - int result; - int status = urb->status; - - dbg("%s - enter", __func__); - - if (status) { - dbg("%s - status = %d", __func__, status); - /* error stop all */ - return; - } - - - memset(port->write_urb->transfer_buffer, IUU_UART_RX, 1); - usb_fill_bulk_urb(port->write_urb, port->serial->dev, - usb_sndbulkpipe(port->serial->dev, - port->bulk_out_endpointAddress), - port->write_urb->transfer_buffer, 1, - read_rxcmd_callback, port); - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); -} - -static int iuu_reset(struct usb_serial_port *port, u8 wt) -{ - struct iuu_private *priv = usb_get_serial_port_data(port); - int result; - char *buf_ptr = port->write_urb->transfer_buffer; - dbg("%s - enter", __func__); - - /* Prepare the reset sequence */ - - *buf_ptr++ = IUU_RST_SET; - *buf_ptr++ = IUU_DELAY_MS; - *buf_ptr++ = wt; - *buf_ptr = IUU_RST_CLEAR; - - /* send the sequence */ - - usb_fill_bulk_urb(port->write_urb, - port->serial->dev, - usb_sndbulkpipe(port->serial->dev, - port->bulk_out_endpointAddress), - port->write_urb->transfer_buffer, 4, iuu_rxcmd, port); - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - priv->reset = 0; - return result; -} - -/* Status Function - * Return value is - * 0x00 = no card - * 0x01 = smartcard - * 0x02 = sim card - */ -static void iuu_update_status_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct iuu_private *priv = usb_get_serial_port_data(port); - u8 *st; - int status = urb->status; - - dbg("%s - enter", __func__); - - if (status) { - dbg("%s - status = %d", __func__, status); - /* error stop all */ - return; - } - - st = urb->transfer_buffer; - dbg("%s - enter", __func__); - if (urb->actual_length == 1) { - switch (st[0]) { - case 0x1: - priv->tiostatus = iuu_cardout; - break; - case 0x0: - priv->tiostatus = iuu_cardin; - break; - default: - priv->tiostatus = iuu_cardin; - } - } - iuu_rxcmd(urb); -} - -static void iuu_status_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - int result; - int status = urb->status; - - dbg("%s - status = %d", __func__, status); - usb_fill_bulk_urb(port->read_urb, port->serial->dev, - usb_rcvbulkpipe(port->serial->dev, - port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, 256, - iuu_update_status_callback, port); - result = usb_submit_urb(port->read_urb, GFP_ATOMIC); -} - -static int iuu_status(struct usb_serial_port *port) -{ - int result; - - dbg("%s - enter", __func__); - - memset(port->write_urb->transfer_buffer, IUU_GET_STATE_REGISTER, 1); - usb_fill_bulk_urb(port->write_urb, port->serial->dev, - usb_sndbulkpipe(port->serial->dev, - port->bulk_out_endpointAddress), - port->write_urb->transfer_buffer, 1, - iuu_status_callback, port); - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - return result; - -} - -static int bulk_immediate(struct usb_serial_port *port, u8 *buf, u8 count) -{ - int status; - struct usb_serial *serial = port->serial; - int actual = 0; - - dbg("%s - enter", __func__); - - /* send the data out the bulk port */ - - status = - usb_bulk_msg(serial->dev, - usb_sndbulkpipe(serial->dev, - port->bulk_out_endpointAddress), buf, - count, &actual, HZ * 1); - - if (status != IUU_OPERATION_OK) - dbg("%s - error = %2x", __func__, status); - else - dbg("%s - write OK !", __func__); - return status; -} - -static int read_immediate(struct usb_serial_port *port, u8 *buf, u8 count) -{ - int status; - struct usb_serial *serial = port->serial; - int actual = 0; - - dbg("%s - enter", __func__); - - /* send the data out the bulk port */ - - status = - usb_bulk_msg(serial->dev, - usb_rcvbulkpipe(serial->dev, - port->bulk_in_endpointAddress), buf, - count, &actual, HZ * 1); - - if (status != IUU_OPERATION_OK) - dbg("%s - error = %2x", __func__, status); - else - dbg("%s - read OK !", __func__); - return status; -} - -static int iuu_led(struct usb_serial_port *port, unsigned int R, - unsigned int G, unsigned int B, u8 f) -{ - int status; - u8 *buf; - buf = kmalloc(8, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - dbg("%s - enter", __func__); - - buf[0] = IUU_SET_LED; - buf[1] = R & 0xFF; - buf[2] = (R >> 8) & 0xFF; - buf[3] = G & 0xFF; - buf[4] = (G >> 8) & 0xFF; - buf[5] = B & 0xFF; - buf[6] = (B >> 8) & 0xFF; - buf[7] = f; - status = bulk_immediate(port, buf, 8); - kfree(buf); - if (status != IUU_OPERATION_OK) - dbg("%s - led error status = %2x", __func__, status); - else - dbg("%s - led OK !", __func__); - return IUU_OPERATION_OK; -} - -static void iuu_rgbf_fill_buffer(u8 *buf, u8 r1, u8 r2, u8 g1, u8 g2, u8 b1, - u8 b2, u8 freq) -{ - *buf++ = IUU_SET_LED; - *buf++ = r1; - *buf++ = r2; - *buf++ = g1; - *buf++ = g2; - *buf++ = b1; - *buf++ = b2; - *buf = freq; -} - -static void iuu_led_activity_on(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - int result; - char *buf_ptr = port->write_urb->transfer_buffer; - *buf_ptr++ = IUU_SET_LED; - if (xmas == 1) { - get_random_bytes(buf_ptr, 6); - *(buf_ptr+7) = 1; - } else { - iuu_rgbf_fill_buffer(buf_ptr, 255, 255, 0, 0, 0, 0, 255); - } - - usb_fill_bulk_urb(port->write_urb, port->serial->dev, - usb_sndbulkpipe(port->serial->dev, - port->bulk_out_endpointAddress), - port->write_urb->transfer_buffer, 8 , - iuu_rxcmd, port); - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); -} - -static void iuu_led_activity_off(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - int result; - char *buf_ptr = port->write_urb->transfer_buffer; - if (xmas == 1) { - iuu_rxcmd(urb); - return; - } else { - *buf_ptr++ = IUU_SET_LED; - iuu_rgbf_fill_buffer(buf_ptr, 0, 0, 255, 255, 0, 0, 255); - } - usb_fill_bulk_urb(port->write_urb, port->serial->dev, - usb_sndbulkpipe(port->serial->dev, - port->bulk_out_endpointAddress), - port->write_urb->transfer_buffer, 8 , - iuu_rxcmd, port); - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); -} - - - -static int iuu_clk(struct usb_serial_port *port, int dwFrq) -{ - int status; - struct iuu_private *priv = usb_get_serial_port_data(port); - int Count = 0; - u8 FrqGenAdr = 0x69; - u8 DIV = 0; /* 8bit */ - u8 XDRV = 0; /* 8bit */ - u8 PUMP = 0; /* 3bit */ - u8 PBmsb = 0; /* 2bit */ - u8 PBlsb = 0; /* 8bit */ - u8 PO = 0; /* 1bit */ - u8 Q = 0; /* 7bit */ - /* 24bit = 3bytes */ - unsigned int P = 0; - unsigned int P2 = 0; - int frq = (int)dwFrq; - - dbg("%s - enter", __func__); - - if (frq == 0) { - priv->buf[Count++] = IUU_UART_WRITE_I2C; - priv->buf[Count++] = FrqGenAdr << 1; - priv->buf[Count++] = 0x09; - priv->buf[Count++] = 0x00; - - status = bulk_immediate(port, (u8 *) priv->buf, Count); - if (status != 0) { - dbg("%s - write error ", __func__); - return status; - } - } else if (frq == 3579000) { - DIV = 100; - P = 1193; - Q = 40; - XDRV = 0; - } else if (frq == 3680000) { - DIV = 105; - P = 161; - Q = 5; - XDRV = 0; - } else if (frq == 6000000) { - DIV = 66; - P = 66; - Q = 2; - XDRV = 0x28; - } else { - unsigned int result = 0; - unsigned int tmp = 0; - unsigned int check; - unsigned int check2; - char found = 0x00; - unsigned int lQ = 2; - unsigned int lP = 2055; - unsigned int lDiv = 4; - - for (lQ = 2; lQ <= 47 && !found; lQ++) - for (lP = 2055; lP >= 8 && !found; lP--) - for (lDiv = 4; lDiv <= 127 && !found; lDiv++) { - tmp = (12000000 / lDiv) * (lP / lQ); - if (abs((int)(tmp - frq)) < - abs((int)(frq - result))) { - check2 = (12000000 / lQ); - if (check2 < 250000) - continue; - check = (12000000 / lQ) * lP; - if (check > 400000000) - continue; - if (check < 100000000) - continue; - if (lDiv < 4 || lDiv > 127) - continue; - result = tmp; - P = lP; - DIV = lDiv; - Q = lQ; - if (result == frq) - found = 0x01; - } - } - } - P2 = ((P - PO) / 2) - 4; - DIV = DIV; - PUMP = 0x04; - PBmsb = (P2 >> 8 & 0x03); - PBlsb = P2 & 0xFF; - PO = (P >> 10) & 0x01; - Q = Q - 2; - - priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ - priv->buf[Count++] = FrqGenAdr << 1; - priv->buf[Count++] = 0x09; - priv->buf[Count++] = 0x20; /* Adr = 0x09 */ - priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ - priv->buf[Count++] = FrqGenAdr << 1; - priv->buf[Count++] = 0x0C; - priv->buf[Count++] = DIV; /* Adr = 0x0C */ - priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ - priv->buf[Count++] = FrqGenAdr << 1; - priv->buf[Count++] = 0x12; - priv->buf[Count++] = XDRV; /* Adr = 0x12 */ - priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ - priv->buf[Count++] = FrqGenAdr << 1; - priv->buf[Count++] = 0x13; - priv->buf[Count++] = 0x6B; /* Adr = 0x13 */ - priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ - priv->buf[Count++] = FrqGenAdr << 1; - priv->buf[Count++] = 0x40; - priv->buf[Count++] = (0xC0 | ((PUMP & 0x07) << 2)) | - (PBmsb & 0x03); /* Adr = 0x40 */ - priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ - priv->buf[Count++] = FrqGenAdr << 1; - priv->buf[Count++] = 0x41; - priv->buf[Count++] = PBlsb; /* Adr = 0x41 */ - priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ - priv->buf[Count++] = FrqGenAdr << 1; - priv->buf[Count++] = 0x42; - priv->buf[Count++] = Q | (((PO & 0x01) << 7)); /* Adr = 0x42 */ - priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ - priv->buf[Count++] = FrqGenAdr << 1; - priv->buf[Count++] = 0x44; - priv->buf[Count++] = (char)0xFF; /* Adr = 0x44 */ - priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ - priv->buf[Count++] = FrqGenAdr << 1; - priv->buf[Count++] = 0x45; - priv->buf[Count++] = (char)0xFE; /* Adr = 0x45 */ - priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ - priv->buf[Count++] = FrqGenAdr << 1; - priv->buf[Count++] = 0x46; - priv->buf[Count++] = 0x7F; /* Adr = 0x46 */ - priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */ - priv->buf[Count++] = FrqGenAdr << 1; - priv->buf[Count++] = 0x47; - priv->buf[Count++] = (char)0x84; /* Adr = 0x47 */ - - status = bulk_immediate(port, (u8 *) priv->buf, Count); - if (status != IUU_OPERATION_OK) - dbg("%s - write error ", __func__); - return status; -} - -static int iuu_uart_flush(struct usb_serial_port *port) -{ - int i; - int status; - u8 rxcmd = IUU_UART_RX; - struct iuu_private *priv = usb_get_serial_port_data(port); - - dbg("%s - enter", __func__); - - if (iuu_led(port, 0xF000, 0, 0, 0xFF) < 0) - return -EIO; - - for (i = 0; i < 2; i++) { - status = bulk_immediate(port, &rxcmd, 1); - if (status != IUU_OPERATION_OK) { - dbg("%s - uart_flush_write error", __func__); - return status; - } - - status = read_immediate(port, &priv->len, 1); - if (status != IUU_OPERATION_OK) { - dbg("%s - uart_flush_read error", __func__); - return status; - } - - if (priv->len > 0) { - dbg("%s - uart_flush datalen is : %i ", __func__, - priv->len); - status = read_immediate(port, priv->buf, priv->len); - if (status != IUU_OPERATION_OK) { - dbg("%s - uart_flush_read error", __func__); - return status; - } - } - } - dbg("%s - uart_flush_read OK!", __func__); - iuu_led(port, 0, 0xF000, 0, 0xFF); - return status; -} - -static void read_buf_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - unsigned char *data = urb->transfer_buffer; - struct tty_struct *tty; - int status = urb->status; - - dbg("%s - status = %d", __func__, status); - - if (status) { - if (status == -EPROTO) { - /* reschedule needed */ - } - return; - } - - dbg("%s - %i chars to write", __func__, urb->actual_length); - tty = tty_port_tty_get(&port->port); - if (data == NULL) - dbg("%s - data is NULL !!!", __func__); - if (tty && urb->actual_length && data) { - tty_insert_flip_string(tty, data, urb->actual_length); - tty_flip_buffer_push(tty); - } - tty_kref_put(tty); - iuu_led_activity_on(urb); -} - -static int iuu_bulk_write(struct usb_serial_port *port) -{ - struct iuu_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - int result; - int i; - int buf_len; - char *buf_ptr = port->write_urb->transfer_buffer; - dbg("%s - enter", __func__); - - spin_lock_irqsave(&priv->lock, flags); - *buf_ptr++ = IUU_UART_ESC; - *buf_ptr++ = IUU_UART_TX; - *buf_ptr++ = priv->writelen; - - memcpy(buf_ptr, priv->writebuf, priv->writelen); - buf_len = priv->writelen; - priv->writelen = 0; - spin_unlock_irqrestore(&priv->lock, flags); - if (debug == 1) { - for (i = 0; i < buf_len; i++) - sprintf(priv->dbgbuf + i*2 , - "%02X", priv->writebuf[i]); - priv->dbgbuf[buf_len+i*2] = 0; - dbg("%s - writing %i chars : %s", __func__, - buf_len, priv->dbgbuf); - } - usb_fill_bulk_urb(port->write_urb, port->serial->dev, - usb_sndbulkpipe(port->serial->dev, - port->bulk_out_endpointAddress), - port->write_urb->transfer_buffer, buf_len + 3, - iuu_rxcmd, port); - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - usb_serial_port_softint(port); - return result; -} - -static int iuu_read_buf(struct usb_serial_port *port, int len) -{ - int result; - dbg("%s - enter", __func__); - - usb_fill_bulk_urb(port->read_urb, port->serial->dev, - usb_rcvbulkpipe(port->serial->dev, - port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, len, - read_buf_callback, port); - result = usb_submit_urb(port->read_urb, GFP_ATOMIC); - return result; -} - -static void iuu_uart_read_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct iuu_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - int status = urb->status; - int error = 0; - int len = 0; - unsigned char *data = urb->transfer_buffer; - priv->poll++; - - dbg("%s - enter", __func__); - - if (status) { - dbg("%s - status = %d", __func__, status); - /* error stop all */ - return; - } - if (data == NULL) - dbg("%s - data is NULL !!!", __func__); - - if (urb->actual_length == 1 && data != NULL) - len = (int) data[0]; - - if (urb->actual_length > 1) { - dbg("%s - urb->actual_length = %i", __func__, - urb->actual_length); - error = 1; - return; - } - /* if len > 0 call readbuf */ - - if (len > 0 && error == 0) { - dbg("%s - call read buf - len to read is %i ", - __func__, len); - status = iuu_read_buf(port, len); - return; - } - /* need to update status ? */ - if (priv->poll > 99) { - status = iuu_status(port); - priv->poll = 0; - return; - } - - /* reset waiting ? */ - - if (priv->reset == 1) { - status = iuu_reset(port, 0xC); - return; - } - /* Writebuf is waiting */ - spin_lock_irqsave(&priv->lock, flags); - if (priv->writelen > 0) { - spin_unlock_irqrestore(&priv->lock, flags); - status = iuu_bulk_write(port); - return; - } - spin_unlock_irqrestore(&priv->lock, flags); - /* if nothing to write call again rxcmd */ - dbg("%s - rxcmd recall", __func__); - iuu_led_activity_off(urb); -} - -static int iuu_uart_write(struct tty_struct *tty, struct usb_serial_port *port, - const u8 *buf, int count) -{ - struct iuu_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - dbg("%s - enter", __func__); - - if (count > 256) - return -ENOMEM; - - spin_lock_irqsave(&priv->lock, flags); - - /* fill the buffer */ - memcpy(priv->writebuf + priv->writelen, buf, count); - priv->writelen += count; - spin_unlock_irqrestore(&priv->lock, flags); - - return count; -} - -static void read_rxcmd_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - int result; - int status = urb->status; - - dbg("%s - status = %d", __func__, status); - - if (status) { - /* error stop all */ - return; - } - - usb_fill_bulk_urb(port->read_urb, port->serial->dev, - usb_rcvbulkpipe(port->serial->dev, - port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, 256, - iuu_uart_read_callback, port); - result = usb_submit_urb(port->read_urb, GFP_ATOMIC); - dbg("%s - submit result = %d", __func__, result); -} - -static int iuu_uart_on(struct usb_serial_port *port) -{ - int status; - u8 *buf; - - buf = kmalloc(sizeof(u8) * 4, GFP_KERNEL); - - if (!buf) - return -ENOMEM; - - buf[0] = IUU_UART_ENABLE; - buf[1] = (u8) ((IUU_BAUD_9600 >> 8) & 0x00FF); - buf[2] = (u8) (0x00FF & IUU_BAUD_9600); - buf[3] = (u8) (0x0F0 & IUU_ONE_STOP_BIT) | (0x07 & IUU_PARITY_EVEN); - - status = bulk_immediate(port, buf, 4); - if (status != IUU_OPERATION_OK) { - dbg("%s - uart_on error", __func__); - goto uart_enable_failed; - } - /* iuu_reset() the card after iuu_uart_on() */ - status = iuu_uart_flush(port); - if (status != IUU_OPERATION_OK) - dbg("%s - uart_flush error", __func__); -uart_enable_failed: - kfree(buf); - return status; -} - -/* Diables the IUU UART (a.k.a. the Phoenix voiderface) */ -static int iuu_uart_off(struct usb_serial_port *port) -{ - int status; - u8 *buf; - buf = kmalloc(1, GFP_KERNEL); - if (!buf) - return -ENOMEM; - buf[0] = IUU_UART_DISABLE; - - status = bulk_immediate(port, buf, 1); - if (status != IUU_OPERATION_OK) - dbg("%s - uart_off error", __func__); - - kfree(buf); - return status; -} - -static int iuu_uart_baud(struct usb_serial_port *port, u32 baud_base, - u32 *actual, u8 parity) -{ - int status; - u32 baud; - u8 *dataout; - u8 DataCount = 0; - u8 T1Frekvens = 0; - u8 T1reload = 0; - unsigned int T1FrekvensHZ = 0; - - dbg("%s - enter baud_base=%d", __func__, baud_base); - dataout = kmalloc(sizeof(u8) * 5, GFP_KERNEL); - - if (!dataout) - return -ENOMEM; - /*baud = (((priv->clk / 35) * baud_base) / 100000); */ - baud = baud_base; - - if (baud < 1200 || baud > 230400) { - kfree(dataout); - return IUU_INVALID_PARAMETER; - } - if (baud > 977) { - T1Frekvens = 3; - T1FrekvensHZ = 500000; - } - - if (baud > 3906) { - T1Frekvens = 2; - T1FrekvensHZ = 2000000; - } - - if (baud > 11718) { - T1Frekvens = 1; - T1FrekvensHZ = 6000000; - } - - if (baud > 46875) { - T1Frekvens = 0; - T1FrekvensHZ = 24000000; - } - - T1reload = 256 - (u8) (T1FrekvensHZ / (baud * 2)); - - /* magic number here: ENTER_FIRMWARE_UPDATE; */ - dataout[DataCount++] = IUU_UART_ESC; - /* magic number here: CHANGE_BAUD; */ - dataout[DataCount++] = IUU_UART_CHANGE; - dataout[DataCount++] = T1Frekvens; - dataout[DataCount++] = T1reload; - - *actual = (T1FrekvensHZ / (256 - T1reload)) / 2; - - switch (parity & 0x0F) { - case IUU_PARITY_NONE: - dataout[DataCount++] = 0x00; - break; - case IUU_PARITY_EVEN: - dataout[DataCount++] = 0x01; - break; - case IUU_PARITY_ODD: - dataout[DataCount++] = 0x02; - break; - case IUU_PARITY_MARK: - dataout[DataCount++] = 0x03; - break; - case IUU_PARITY_SPACE: - dataout[DataCount++] = 0x04; - break; - default: - kfree(dataout); - return IUU_INVALID_PARAMETER; - break; - } - - switch (parity & 0xF0) { - case IUU_ONE_STOP_BIT: - dataout[DataCount - 1] |= IUU_ONE_STOP_BIT; - break; - - case IUU_TWO_STOP_BITS: - dataout[DataCount - 1] |= IUU_TWO_STOP_BITS; - break; - default: - kfree(dataout); - return IUU_INVALID_PARAMETER; - break; - } - - status = bulk_immediate(port, dataout, DataCount); - if (status != IUU_OPERATION_OK) - dbg("%s - uart_off error", __func__); - kfree(dataout); - return status; -} - -static void iuu_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) -{ - const u32 supported_mask = CMSPAR|PARENB|PARODD; - struct iuu_private *priv = usb_get_serial_port_data(port); - unsigned int cflag = tty->termios->c_cflag; - int status; - u32 actual; - u32 parity; - int csize = CS7; - int baud; - u32 newval = cflag & supported_mask; - - /* Just use the ospeed. ispeed should be the same. */ - baud = tty->termios->c_ospeed; - - dbg("%s - enter c_ospeed or baud=%d", __func__, baud); - - /* compute the parity parameter */ - parity = 0; - if (cflag & CMSPAR) { /* Using mark space */ - if (cflag & PARODD) - parity |= IUU_PARITY_SPACE; - else - parity |= IUU_PARITY_MARK; - } else if (!(cflag & PARENB)) { - parity |= IUU_PARITY_NONE; - csize = CS8; - } else if (cflag & PARODD) - parity |= IUU_PARITY_ODD; - else - parity |= IUU_PARITY_EVEN; - - parity |= (cflag & CSTOPB ? IUU_TWO_STOP_BITS : IUU_ONE_STOP_BIT); - - /* set it */ - status = iuu_uart_baud(port, - baud * priv->boost / 100, - &actual, parity); - - /* set the termios value to the real one, so the user now what has - * changed. We support few fields so its easies to copy the old hw - * settings back over and then adjust them - */ - if (old_termios) - tty_termios_copy_hw(tty->termios, old_termios); - if (status != 0) /* Set failed - return old bits */ - return; - /* Re-encode speed, parity and csize */ - tty_encode_baud_rate(tty, baud, baud); - tty->termios->c_cflag &= ~(supported_mask|CSIZE); - tty->termios->c_cflag |= newval | csize; -} - -static void iuu_close(struct usb_serial_port *port) -{ - /* iuu_led (port,255,0,0,0); */ - struct usb_serial *serial; - - serial = port->serial; - if (!serial) - return; - - dbg("%s - port %d", __func__, port->number); - - iuu_uart_off(port); - if (serial->dev) { - /* free writebuf */ - /* shutdown our urbs */ - dbg("%s - shutting down urbs", __func__); - usb_kill_urb(port->write_urb); - usb_kill_urb(port->read_urb); - usb_kill_urb(port->interrupt_in_urb); - iuu_led(port, 0, 0, 0xF000, 0xFF); - } -} - -static void iuu_init_termios(struct tty_struct *tty) -{ - dbg("%s - enter", __func__); - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600 - | TIOCM_CTS | CSTOPB | PARENB; - tty->termios->c_ispeed = 9600; - tty->termios->c_ospeed = 9600; - tty->termios->c_lflag = 0; - tty->termios->c_oflag = 0; - tty->termios->c_iflag = 0; -} - -static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - u8 *buf; - int result; - int baud; - u32 actual; - struct iuu_private *priv = usb_get_serial_port_data(port); - - baud = tty->termios->c_ospeed; - tty->termios->c_ispeed = baud; - /* Re-encode speed */ - tty_encode_baud_rate(tty, baud, baud); - - dbg("%s - port %d, baud %d", __func__, port->number, baud); - usb_clear_halt(serial->dev, port->write_urb->pipe); - usb_clear_halt(serial->dev, port->read_urb->pipe); - - buf = kmalloc(10, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - priv->poll = 0; - - /* initialize writebuf */ -#define FISH(a, b, c, d) do { \ - result = usb_control_msg(port->serial->dev, \ - usb_rcvctrlpipe(port->serial->dev, 0), \ - b, a, c, d, buf, 1, 1000); \ - dbg("0x%x:0x%x:0x%x:0x%x %d - %x", a, b, c, d, result, \ - buf[0]); } while (0); - -#define SOUP(a, b, c, d) do { \ - result = usb_control_msg(port->serial->dev, \ - usb_sndctrlpipe(port->serial->dev, 0), \ - b, a, c, d, NULL, 0, 1000); \ - dbg("0x%x:0x%x:0x%x:0x%x %d", a, b, c, d, result); } while (0) - - /* This is not UART related but IUU USB driver related or something */ - /* like that. Basically no IUU will accept any commands from the USB */ - /* host unless it has received the following message */ - /* sprintf(buf ,"%c%c%c%c",0x03,0x02,0x02,0x0); */ - - SOUP(0x03, 0x02, 0x02, 0x0); - kfree(buf); - iuu_led(port, 0xF000, 0xF000, 0, 0xFF); - iuu_uart_on(port); - if (boost < 100) - boost = 100; - priv->boost = boost; - priv->baud = baud; - switch (clockmode) { - case 2: /* 3.680 Mhz */ - priv->clk = IUU_CLK_3680000; - iuu_clk(port, IUU_CLK_3680000 * boost / 100); - result = - iuu_uart_baud(port, baud * boost / 100, &actual, - IUU_PARITY_EVEN); - break; - case 3: /* 6.00 Mhz */ - iuu_clk(port, IUU_CLK_6000000 * boost / 100); - priv->clk = IUU_CLK_6000000; - /* Ratio of 6000000 to 3500000 for baud 9600 */ - result = - iuu_uart_baud(port, 16457 * boost / 100, &actual, - IUU_PARITY_EVEN); - break; - default: /* 3.579 Mhz */ - iuu_clk(port, IUU_CLK_3579000 * boost / 100); - priv->clk = IUU_CLK_3579000; - result = - iuu_uart_baud(port, baud * boost / 100, &actual, - IUU_PARITY_EVEN); - } - - /* set the cardin cardout signals */ - switch (cdmode) { - case 0: - iuu_cardin = 0; - iuu_cardout = 0; - break; - case 1: - iuu_cardin = TIOCM_CD; - iuu_cardout = 0; - break; - case 2: - iuu_cardin = 0; - iuu_cardout = TIOCM_CD; - break; - case 3: - iuu_cardin = TIOCM_DSR; - iuu_cardout = 0; - break; - case 4: - iuu_cardin = 0; - iuu_cardout = TIOCM_DSR; - break; - case 5: - iuu_cardin = TIOCM_CTS; - iuu_cardout = 0; - break; - case 6: - iuu_cardin = 0; - iuu_cardout = TIOCM_CTS; - break; - case 7: - iuu_cardin = TIOCM_RNG; - iuu_cardout = 0; - break; - case 8: - iuu_cardin = 0; - iuu_cardout = TIOCM_RNG; - } - - iuu_uart_flush(port); - - dbg("%s - initialization done", __func__); - - memset(port->write_urb->transfer_buffer, IUU_UART_RX, 1); - usb_fill_bulk_urb(port->write_urb, port->serial->dev, - usb_sndbulkpipe(port->serial->dev, - port->bulk_out_endpointAddress), - port->write_urb->transfer_buffer, 1, - read_rxcmd_callback, port); - result = usb_submit_urb(port->write_urb, GFP_KERNEL); - if (result) { - dev_err(&port->dev, "%s - failed submitting read urb," - " error %d\n", __func__, result); - iuu_close(port); - } else { - dbg("%s - rxcmd OK", __func__); - } - - return result; -} - -/* how to change VCC */ -static int iuu_vcc_set(struct usb_serial_port *port, unsigned int vcc) -{ - int status; - u8 *buf; - - buf = kmalloc(5, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - dbg("%s - enter", __func__); - - buf[0] = IUU_SET_VCC; - buf[1] = vcc & 0xFF; - buf[2] = (vcc >> 8) & 0xFF; - buf[3] = (vcc >> 16) & 0xFF; - buf[4] = (vcc >> 24) & 0xFF; - - status = bulk_immediate(port, buf, 5); - kfree(buf); - - if (status != IUU_OPERATION_OK) - dbg("%s - vcc error status = %2x", __func__, status); - else - dbg("%s - vcc OK !", __func__); - - return status; -} - -/* - * Sysfs Attributes - */ - -static ssize_t show_vcc_mode(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct usb_serial_port *port = to_usb_serial_port(dev); - struct iuu_private *priv = usb_get_serial_port_data(port); - - return sprintf(buf, "%d\n", priv->vcc); -} - -static ssize_t store_vcc_mode(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct usb_serial_port *port = to_usb_serial_port(dev); - struct iuu_private *priv = usb_get_serial_port_data(port); - unsigned long v; - - if (strict_strtoul(buf, 10, &v)) { - dev_err(dev, "%s - vcc_mode: %s is not a unsigned long\n", - __func__, buf); - goto fail_store_vcc_mode; - } - - dbg("%s: setting vcc_mode = %ld", __func__, v); - - if ((v != 3) && (v != 5)) { - dev_err(dev, "%s - vcc_mode %ld is invalid\n", __func__, v); - } else { - iuu_vcc_set(port, v); - priv->vcc = v; - } -fail_store_vcc_mode: - return count; -} - -static DEVICE_ATTR(vcc_mode, S_IRUSR | S_IWUSR, show_vcc_mode, - store_vcc_mode); - -static int iuu_create_sysfs_attrs(struct usb_serial_port *port) -{ - dbg("%s", __func__); - - return device_create_file(&port->dev, &dev_attr_vcc_mode); -} - -static int iuu_remove_sysfs_attrs(struct usb_serial_port *port) -{ - dbg("%s", __func__); - - device_remove_file(&port->dev, &dev_attr_vcc_mode); - return 0; -} - -/* - * End Sysfs Attributes - */ - -static struct usb_serial_driver iuu_device = { - .driver = { - .owner = THIS_MODULE, - .name = "iuu_phoenix", - }, - .id_table = id_table, - .num_ports = 1, - .bulk_in_size = 512, - .bulk_out_size = 512, - .port_probe = iuu_create_sysfs_attrs, - .port_remove = iuu_remove_sysfs_attrs, - .open = iuu_open, - .close = iuu_close, - .write = iuu_uart_write, - .read_bulk_callback = iuu_uart_read_callback, - .tiocmget = iuu_tiocmget, - .tiocmset = iuu_tiocmset, - .set_termios = iuu_set_termios, - .init_termios = iuu_init_termios, - .attach = iuu_startup, - .release = iuu_release, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &iuu_device, NULL -}; - -module_usb_serial_driver(iuu_driver, serial_drivers); - -MODULE_AUTHOR("Alain Degreffe eczema@ecze.com"); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -MODULE_VERSION(DRIVER_VERSION); -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - -module_param(xmas, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(xmas, "Xmas colors enabled or not"); - -module_param(boost, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(boost, "Card overclock boost (in percent 100-500)"); - -module_param(clockmode, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(clockmode, "Card clock mode (1=3.579 MHz, 2=3.680 MHz, " - "3=6 Mhz)"); - -module_param(cdmode, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(cdmode, "Card detect mode (0=none, 1=CD, 2=!CD, 3=DSR, " - "4=!DSR, 5=CTS, 6=!CTS, 7=RING, 8=!RING)"); - -module_param(vcc_default, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(vcc_default, "Set default VCC (either 3 for 3.3V or 5 " - "for 5V). Default to 5."); diff --git a/ANDROID_3.4.5/drivers/usb/serial/iuu_phoenix.h b/ANDROID_3.4.5/drivers/usb/serial/iuu_phoenix.h deleted file mode 100644 index b82630a3..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/iuu_phoenix.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Infinity Unlimited USB Phoenix driver - * - * Copyright (C) 2007 Alain Degreffe (eczema@ecze.com) - * - * - * Original code taken from iuutool ( Copyright (C) 2006 Juan Carlos Borrás ) - * - * 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. - * - * And tested with help of WB Electronics - * - */ - -#define IUU_USB_VENDOR_ID 0x104f -#define IUU_USB_PRODUCT_ID 0x0004 -#define IUU_USB_OP_TIMEOUT 0x0200 - -/* Programmer commands */ - -#define IUU_NO_OPERATION 0x00 -#define IUU_GET_FIRMWARE_VERSION 0x01 -#define IUU_GET_PRODUCT_NAME 0x02 -#define IUU_GET_STATE_REGISTER 0x03 -#define IUU_SET_LED 0x04 -#define IUU_WAIT_MUS 0x05 -#define IUU_WAIT_MS 0x06 -#define IUU_GET_LOADER_VERSION 0x50 -#define IUU_RST_SET 0x52 -#define IUU_RST_CLEAR 0x53 -#define IUU_SET_VCC 0x59 -#define IUU_UART_ENABLE 0x49 -#define IUU_UART_DISABLE 0x4A -#define IUU_UART_WRITE_I2C 0x4C -#define IUU_UART_ESC 0x5E -#define IUU_UART_TRAP 0x54 -#define IUU_UART_TRAP_BREAK 0x5B -#define IUU_UART_RX 0x56 -#define IUU_AVR_ON 0x21 -#define IUU_AVR_OFF 0x22 -#define IUU_AVR_1CLK 0x23 -#define IUU_AVR_RESET 0x24 -#define IUU_AVR_RESET_PC 0x25 -#define IUU_AVR_INC_PC 0x26 -#define IUU_AVR_INCN_PC 0x27 -#define IUU_AVR_PREAD 0x29 -#define IUU_AVR_PREADN 0x2A -#define IUU_AVR_PWRITE 0x28 -#define IUU_AVR_DREAD 0x2C -#define IUU_AVR_DREADN 0x2D -#define IUU_AVR_DWRITE 0x2B -#define IUU_AVR_PWRITEN 0x2E -#define IUU_EEPROM_ON 0x37 -#define IUU_EEPROM_OFF 0x38 -#define IUU_EEPROM_WRITE 0x39 -#define IUU_EEPROM_WRITEX 0x3A -#define IUU_EEPROM_WRITE8 0x3B -#define IUU_EEPROM_WRITE16 0x3C -#define IUU_EEPROM_WRITEX32 0x3D -#define IUU_EEPROM_WRITEX64 0x3E -#define IUU_EEPROM_READ 0x3F -#define IUU_EEPROM_READX 0x40 -#define IUU_EEPROM_BREAD 0x41 -#define IUU_EEPROM_BREADX 0x42 -#define IUU_PIC_CMD 0x0A -#define IUU_PIC_CMD_LOAD 0x0B -#define IUU_PIC_CMD_READ 0x0C -#define IUU_PIC_ON 0x0D -#define IUU_PIC_OFF 0x0E -#define IUU_PIC_RESET 0x16 -#define IUU_PIC_INC_PC 0x0F -#define IUU_PIC_INCN_PC 0x10 -#define IUU_PIC_PWRITE 0x11 -#define IUU_PIC_PREAD 0x12 -#define IUU_PIC_PREADN 0x13 -#define IUU_PIC_DWRITE 0x14 -#define IUU_PIC_DREAD 0x15 -#define IUU_UART_NOP 0x00 -#define IUU_UART_CHANGE 0x02 -#define IUU_UART_TX 0x04 -#define IUU_DELAY_MS 0x06 - -#define IUU_OPERATION_OK 0x00 -#define IUU_DEVICE_NOT_FOUND 0x01 -#define IUU_INVALID_HANDLE 0x02 -#define IUU_INVALID_PARAMETER 0x03 -#define IUU_INVALID_voidERFACE 0x04 -#define IUU_INVALID_REQUEST_LENGTH 0x05 -#define IUU_UART_NOT_ENABLED 0x06 -#define IUU_WRITE_ERROR 0x07 -#define IUU_READ_ERROR 0x08 -#define IUU_TX_ERROR 0x09 -#define IUU_RX_ERROR 0x0A - -#define IUU_PARITY_NONE 0x00 -#define IUU_PARITY_EVEN 0x01 -#define IUU_PARITY_ODD 0x02 -#define IUU_PARITY_MARK 0x03 -#define IUU_PARITY_SPACE 0x04 -#define IUU_SC_INSERTED 0x01 -#define IUU_VERIFY_ERROR 0x02 -#define IUU_SIM_INSERTED 0x04 -#define IUU_TWO_STOP_BITS 0x00 -#define IUU_ONE_STOP_BIT 0x20 -#define IUU_BAUD_2400 0x0398 -#define IUU_BAUD_9600 0x0298 -#define IUU_BAUD_19200 0x0164 -#define IUU_BAUD_28800 0x0198 -#define IUU_BAUD_38400 0x01B2 -#define IUU_BAUD_57600 0x0030 -#define IUU_BAUD_115200 0x0098 -#define IUU_CLK_3579000 3579000 -#define IUU_CLK_3680000 3680000 -#define IUU_CLK_6000000 6000000 -#define IUU_FULLCARD_IN 0x01 -#define IUU_DEV_ERROR 0x02 -#define IUU_MINICARD_IN 0x04 -#define IUU_VCC_5V 0x00 -#define IUU_VCC_3V 0x01 diff --git a/ANDROID_3.4.5/drivers/usb/serial/keyspan.c b/ANDROID_3.4.5/drivers/usb/serial/keyspan.c deleted file mode 100644 index a39ddd1b..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/keyspan.c +++ /dev/null @@ -1,2616 +0,0 @@ -/* - Keyspan USB to Serial Converter driver - - (C) Copyright (C) 2000-2001 Hugh Blemings - (C) Copyright (C) 2002 Greg Kroah-Hartman - - 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. - - See http://blemings.org/hugh/keyspan.html for more information. - - Code in this driver inspired by and in a number of places taken - from Brian Warner's original Keyspan-PDA driver. - - This driver has been put together with the support of Innosys, Inc. - and Keyspan, Inc the manufacturers of the Keyspan USB-serial products. - Thanks Guys :) - - Thanks to Paulus for miscellaneous tidy ups, some largish chunks - of much nicer and/or completely new code and (perhaps most uniquely) - having the patience to sit down and explain why and where he'd changed - stuff. - - Tip 'o the hat to IBM (and previously Linuxcare :) for supporting - staff in their work on open source projects. -*/ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "keyspan.h" - -static bool debug; - -/* - * Version Information - */ -#define DRIVER_VERSION "v1.1.5" -#define DRIVER_AUTHOR "Hugh Blemings driver_data; - struct keyspan_port_private *p_priv; - - dbg("%s", __func__); - - p_priv = usb_get_serial_port_data(port); - - if (break_state == -1) - p_priv->break_on = 1; - else - p_priv->break_on = 0; - - keyspan_send_setup(port, 0); -} - - -static void keyspan_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) -{ - int baud_rate, device_port; - struct keyspan_port_private *p_priv; - const struct keyspan_device_details *d_details; - unsigned int cflag; - - dbg("%s", __func__); - - p_priv = usb_get_serial_port_data(port); - d_details = p_priv->device_details; - cflag = tty->termios->c_cflag; - device_port = port->number - port->serial->minor; - - /* Baud rate calculation takes baud rate as an integer - so other rates can be generated if desired. */ - baud_rate = tty_get_baud_rate(tty); - /* If no match or invalid, don't change */ - if (d_details->calculate_baud_rate(baud_rate, d_details->baudclk, - NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) { - /* FIXME - more to do here to ensure rate changes cleanly */ - /* FIXME - calcuate exact rate from divisor ? */ - p_priv->baud = baud_rate; - } else - baud_rate = tty_termios_baud_rate(old_termios); - - tty_encode_baud_rate(tty, baud_rate, baud_rate); - /* set CTS/RTS handshake etc. */ - p_priv->cflag = cflag; - p_priv->flow_control = (cflag & CRTSCTS)? flow_cts: flow_none; - - /* Mark/Space not supported */ - tty->termios->c_cflag &= ~CMSPAR; - - keyspan_send_setup(port, 0); -} - -static int keyspan_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct keyspan_port_private *p_priv = usb_get_serial_port_data(port); - unsigned int value; - - value = ((p_priv->rts_state) ? TIOCM_RTS : 0) | - ((p_priv->dtr_state) ? TIOCM_DTR : 0) | - ((p_priv->cts_state) ? TIOCM_CTS : 0) | - ((p_priv->dsr_state) ? TIOCM_DSR : 0) | - ((p_priv->dcd_state) ? TIOCM_CAR : 0) | - ((p_priv->ri_state) ? TIOCM_RNG : 0); - - return value; -} - -static int keyspan_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct keyspan_port_private *p_priv = usb_get_serial_port_data(port); - - if (set & TIOCM_RTS) - p_priv->rts_state = 1; - if (set & TIOCM_DTR) - p_priv->dtr_state = 1; - if (clear & TIOCM_RTS) - p_priv->rts_state = 0; - if (clear & TIOCM_DTR) - p_priv->dtr_state = 0; - keyspan_send_setup(port, 0); - return 0; -} - -/* Write function is similar for the four protocols used - with only a minor change for usa90 (usa19hs) required */ -static int keyspan_write(struct tty_struct *tty, - struct usb_serial_port *port, const unsigned char *buf, int count) -{ - struct keyspan_port_private *p_priv; - const struct keyspan_device_details *d_details; - int flip; - int left, todo; - struct urb *this_urb; - int err, maxDataLen, dataOffset; - - p_priv = usb_get_serial_port_data(port); - d_details = p_priv->device_details; - - if (d_details->msg_format == msg_usa90) { - maxDataLen = 64; - dataOffset = 0; - } else { - maxDataLen = 63; - dataOffset = 1; - } - - dbg("%s - for port %d (%d chars), flip=%d", - __func__, port->number, count, p_priv->out_flip); - - for (left = count; left > 0; left -= todo) { - todo = left; - if (todo > maxDataLen) - todo = maxDataLen; - - flip = p_priv->out_flip; - - /* Check we have a valid urb/endpoint before we use it... */ - this_urb = p_priv->out_urbs[flip]; - if (this_urb == NULL) { - /* no bulk out, so return 0 bytes written */ - dbg("%s - no output urb :(", __func__); - return count; - } - - dbg("%s - endpoint %d flip %d", - __func__, usb_pipeendpoint(this_urb->pipe), flip); - - if (this_urb->status == -EINPROGRESS) { - if (time_before(jiffies, - p_priv->tx_start_time[flip] + 10 * HZ)) - break; - usb_unlink_urb(this_urb); - break; - } - - /* First byte in buffer is "last flag" (except for usa19hx) - - unused so for now so set to zero */ - ((char *)this_urb->transfer_buffer)[0] = 0; - - memcpy(this_urb->transfer_buffer + dataOffset, buf, todo); - buf += todo; - - /* send the data out the bulk port */ - this_urb->transfer_buffer_length = todo + dataOffset; - - err = usb_submit_urb(this_urb, GFP_ATOMIC); - if (err != 0) - dbg("usb_submit_urb(write bulk) failed (%d)", err); - p_priv->tx_start_time[flip] = jiffies; - - /* Flip for next time if usa26 or usa28 interface - (not used on usa49) */ - p_priv->out_flip = (flip + 1) & d_details->outdat_endp_flip; - } - - return count - left; -} - -static void usa26_indat_callback(struct urb *urb) -{ - int i, err; - int endpoint; - struct usb_serial_port *port; - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - int status = urb->status; - - dbg("%s", __func__); - - endpoint = usb_pipeendpoint(urb->pipe); - - if (status) { - dbg("%s - nonzero status: %x on endpoint %d.", - __func__, status, endpoint); - return; - } - - port = urb->context; - tty = tty_port_tty_get(&port->port); - if (tty && urb->actual_length) { - /* 0x80 bit is error flag */ - if ((data[0] & 0x80) == 0) { - /* no errors on individual bytes, only - possible overrun err */ - if (data[0] & RXERROR_OVERRUN) - err = TTY_OVERRUN; - else - err = 0; - for (i = 1; i < urb->actual_length ; ++i) - tty_insert_flip_char(tty, data[i], err); - } else { - /* some bytes had errors, every byte has status */ - dbg("%s - RX error!!!!", __func__); - for (i = 0; i + 1 < urb->actual_length; i += 2) { - int stat = data[i], flag = 0; - if (stat & RXERROR_OVERRUN) - flag |= TTY_OVERRUN; - if (stat & RXERROR_FRAMING) - flag |= TTY_FRAME; - if (stat & RXERROR_PARITY) - flag |= TTY_PARITY; - /* XXX should handle break (0x10) */ - tty_insert_flip_char(tty, data[i+1], flag); - } - } - tty_flip_buffer_push(tty); - } - tty_kref_put(tty); - - /* Resubmit urb so we continue receiving */ - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); -} - -/* Outdat handling is common for all devices */ -static void usa2x_outdat_callback(struct urb *urb) -{ - struct usb_serial_port *port; - struct keyspan_port_private *p_priv; - - port = urb->context; - p_priv = usb_get_serial_port_data(port); - dbg("%s - urb %d", __func__, urb == p_priv->out_urbs[1]); - - usb_serial_port_softint(port); -} - -static void usa26_inack_callback(struct urb *urb) -{ - dbg("%s", __func__); - -} - -static void usa26_outcont_callback(struct urb *urb) -{ - struct usb_serial_port *port; - struct keyspan_port_private *p_priv; - - port = urb->context; - p_priv = usb_get_serial_port_data(port); - - if (p_priv->resend_cont) { - dbg("%s - sending setup", __func__); - keyspan_usa26_send_setup(port->serial, port, - p_priv->resend_cont - 1); - } -} - -static void usa26_instat_callback(struct urb *urb) -{ - unsigned char *data = urb->transfer_buffer; - struct keyspan_usa26_portStatusMessage *msg; - struct usb_serial *serial; - struct usb_serial_port *port; - struct keyspan_port_private *p_priv; - struct tty_struct *tty; - int old_dcd_state, err; - int status = urb->status; - - serial = urb->context; - - if (status) { - dbg("%s - nonzero status: %x", __func__, status); - return; - } - if (urb->actual_length != 9) { - dbg("%s - %d byte report??", __func__, urb->actual_length); - goto exit; - } - - msg = (struct keyspan_usa26_portStatusMessage *)data; - -#if 0 - dbg("%s - port status: port %d cts %d dcd %d dsr %d ri %d toff %d txoff %d rxen %d cr %d", - __func__, msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr, msg->ri, msg->_txOff, - msg->_txXoff, msg->rxEnabled, msg->controlResponse); -#endif - - /* Now do something useful with the data */ - - - /* Check port number from message and retrieve private data */ - if (msg->port >= serial->num_ports) { - dbg("%s - Unexpected port number %d", __func__, msg->port); - goto exit; - } - port = serial->port[msg->port]; - p_priv = usb_get_serial_port_data(port); - - /* Update handshaking pin state information */ - old_dcd_state = p_priv->dcd_state; - p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0); - p_priv->dsr_state = ((msg->dsr) ? 1 : 0); - p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0); - p_priv->ri_state = ((msg->ri) ? 1 : 0); - - if (old_dcd_state != p_priv->dcd_state) { - tty = tty_port_tty_get(&port->port); - if (tty && !C_CLOCAL(tty)) - tty_hangup(tty); - tty_kref_put(tty); - } - - /* Resubmit urb so we continue receiving */ - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); -exit: ; -} - -static void usa26_glocont_callback(struct urb *urb) -{ - dbg("%s", __func__); -} - - -static void usa28_indat_callback(struct urb *urb) -{ - int err; - struct usb_serial_port *port; - struct tty_struct *tty; - unsigned char *data; - struct keyspan_port_private *p_priv; - int status = urb->status; - - dbg("%s", __func__); - - port = urb->context; - p_priv = usb_get_serial_port_data(port); - data = urb->transfer_buffer; - - if (urb != p_priv->in_urbs[p_priv->in_flip]) - return; - - do { - if (status) { - dbg("%s - nonzero status: %x on endpoint %d.", - __func__, status, usb_pipeendpoint(urb->pipe)); - return; - } - - port = urb->context; - p_priv = usb_get_serial_port_data(port); - data = urb->transfer_buffer; - - tty =tty_port_tty_get(&port->port); - if (tty && urb->actual_length) { - tty_insert_flip_string(tty, data, urb->actual_length); - tty_flip_buffer_push(tty); - } - tty_kref_put(tty); - - /* Resubmit urb so we continue receiving */ - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", - __func__, err); - p_priv->in_flip ^= 1; - - urb = p_priv->in_urbs[p_priv->in_flip]; - } while (urb->status != -EINPROGRESS); -} - -static void usa28_inack_callback(struct urb *urb) -{ - dbg("%s", __func__); -} - -static void usa28_outcont_callback(struct urb *urb) -{ - struct usb_serial_port *port; - struct keyspan_port_private *p_priv; - - port = urb->context; - p_priv = usb_get_serial_port_data(port); - - if (p_priv->resend_cont) { - dbg("%s - sending setup", __func__); - keyspan_usa28_send_setup(port->serial, port, - p_priv->resend_cont - 1); - } -} - -static void usa28_instat_callback(struct urb *urb) -{ - int err; - unsigned char *data = urb->transfer_buffer; - struct keyspan_usa28_portStatusMessage *msg; - struct usb_serial *serial; - struct usb_serial_port *port; - struct keyspan_port_private *p_priv; - struct tty_struct *tty; - int old_dcd_state; - int status = urb->status; - - serial = urb->context; - - if (status) { - dbg("%s - nonzero status: %x", __func__, status); - return; - } - - if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) { - dbg("%s - bad length %d", __func__, urb->actual_length); - goto exit; - } - - /*dbg("%s %x %x %x %x %x %x %x %x %x %x %x %x", __func__ - data[0], data[1], data[2], data[3], data[4], data[5], - data[6], data[7], data[8], data[9], data[10], data[11]);*/ - - /* Now do something useful with the data */ - msg = (struct keyspan_usa28_portStatusMessage *)data; - - /* Check port number from message and retrieve private data */ - if (msg->port >= serial->num_ports) { - dbg("%s - Unexpected port number %d", __func__, msg->port); - goto exit; - } - port = serial->port[msg->port]; - p_priv = usb_get_serial_port_data(port); - - /* Update handshaking pin state information */ - old_dcd_state = p_priv->dcd_state; - p_priv->cts_state = ((msg->cts) ? 1 : 0); - p_priv->dsr_state = ((msg->dsr) ? 1 : 0); - p_priv->dcd_state = ((msg->dcd) ? 1 : 0); - p_priv->ri_state = ((msg->ri) ? 1 : 0); - - if( old_dcd_state != p_priv->dcd_state && old_dcd_state) { - tty = tty_port_tty_get(&port->port); - if (tty && !C_CLOCAL(tty)) - tty_hangup(tty); - tty_kref_put(tty); - } - - /* Resubmit urb so we continue receiving */ - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); -exit: ; -} - -static void usa28_glocont_callback(struct urb *urb) -{ - dbg("%s", __func__); -} - - -static void usa49_glocont_callback(struct urb *urb) -{ - struct usb_serial *serial; - struct usb_serial_port *port; - struct keyspan_port_private *p_priv; - int i; - - dbg("%s", __func__); - - serial = urb->context; - for (i = 0; i < serial->num_ports; ++i) { - port = serial->port[i]; - p_priv = usb_get_serial_port_data(port); - - if (p_priv->resend_cont) { - dbg("%s - sending setup", __func__); - keyspan_usa49_send_setup(serial, port, - p_priv->resend_cont - 1); - break; - } - } -} - - /* This is actually called glostat in the Keyspan - doco */ -static void usa49_instat_callback(struct urb *urb) -{ - int err; - unsigned char *data = urb->transfer_buffer; - struct keyspan_usa49_portStatusMessage *msg; - struct usb_serial *serial; - struct usb_serial_port *port; - struct keyspan_port_private *p_priv; - int old_dcd_state; - int status = urb->status; - - dbg("%s", __func__); - - serial = urb->context; - - if (status) { - dbg("%s - nonzero status: %x", __func__, status); - return; - } - - if (urb->actual_length != - sizeof(struct keyspan_usa49_portStatusMessage)) { - dbg("%s - bad length %d", __func__, urb->actual_length); - goto exit; - } - - /*dbg(" %x %x %x %x %x %x %x %x %x %x %x", __func__, - data[0], data[1], data[2], data[3], data[4], data[5], - data[6], data[7], data[8], data[9], data[10]);*/ - - /* Now do something useful with the data */ - msg = (struct keyspan_usa49_portStatusMessage *)data; - - /* Check port number from message and retrieve private data */ - if (msg->portNumber >= serial->num_ports) { - dbg("%s - Unexpected port number %d", - __func__, msg->portNumber); - goto exit; - } - port = serial->port[msg->portNumber]; - p_priv = usb_get_serial_port_data(port); - - /* Update handshaking pin state information */ - old_dcd_state = p_priv->dcd_state; - p_priv->cts_state = ((msg->cts) ? 1 : 0); - p_priv->dsr_state = ((msg->dsr) ? 1 : 0); - p_priv->dcd_state = ((msg->dcd) ? 1 : 0); - p_priv->ri_state = ((msg->ri) ? 1 : 0); - - if (old_dcd_state != p_priv->dcd_state && old_dcd_state) { - struct tty_struct *tty = tty_port_tty_get(&port->port); - if (tty && !C_CLOCAL(tty)) - tty_hangup(tty); - tty_kref_put(tty); - } - - /* Resubmit urb so we continue receiving */ - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); -exit: ; -} - -static void usa49_inack_callback(struct urb *urb) -{ - dbg("%s", __func__); -} - -static void usa49_indat_callback(struct urb *urb) -{ - int i, err; - int endpoint; - struct usb_serial_port *port; - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - int status = urb->status; - - dbg("%s", __func__); - - endpoint = usb_pipeendpoint(urb->pipe); - - if (status) { - dbg("%s - nonzero status: %x on endpoint %d.", __func__, - status, endpoint); - return; - } - - port = urb->context; - tty = tty_port_tty_get(&port->port); - if (tty && urb->actual_length) { - /* 0x80 bit is error flag */ - if ((data[0] & 0x80) == 0) { - /* no error on any byte */ - tty_insert_flip_string(tty, data + 1, - urb->actual_length - 1); - } else { - /* some bytes had errors, every byte has status */ - for (i = 0; i + 1 < urb->actual_length; i += 2) { - int stat = data[i], flag = 0; - if (stat & RXERROR_OVERRUN) - flag |= TTY_OVERRUN; - if (stat & RXERROR_FRAMING) - flag |= TTY_FRAME; - if (stat & RXERROR_PARITY) - flag |= TTY_PARITY; - /* XXX should handle break (0x10) */ - tty_insert_flip_char(tty, data[i+1], flag); - } - } - tty_flip_buffer_push(tty); - } - tty_kref_put(tty); - - /* Resubmit urb so we continue receiving */ - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); -} - -static void usa49wg_indat_callback(struct urb *urb) -{ - int i, len, x, err; - struct usb_serial *serial; - struct usb_serial_port *port; - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - int status = urb->status; - - dbg("%s", __func__); - - serial = urb->context; - - if (status) { - dbg("%s - nonzero status: %x", __func__, status); - return; - } - - /* inbound data is in the form P#, len, status, data */ - i = 0; - len = 0; - - if (urb->actual_length) { - while (i < urb->actual_length) { - - /* Check port number from message*/ - if (data[i] >= serial->num_ports) { - dbg("%s - Unexpected port number %d", - __func__, data[i]); - return; - } - port = serial->port[data[i++]]; - tty = tty_port_tty_get(&port->port); - len = data[i++]; - - /* 0x80 bit is error flag */ - if ((data[i] & 0x80) == 0) { - /* no error on any byte */ - i++; - for (x = 1; x < len ; ++x) - tty_insert_flip_char(tty, data[i++], 0); - } else { - /* - * some bytes had errors, every byte has status - */ - for (x = 0; x + 1 < len; x += 2) { - int stat = data[i], flag = 0; - if (stat & RXERROR_OVERRUN) - flag |= TTY_OVERRUN; - if (stat & RXERROR_FRAMING) - flag |= TTY_FRAME; - if (stat & RXERROR_PARITY) - flag |= TTY_PARITY; - /* XXX should handle break (0x10) */ - tty_insert_flip_char(tty, - data[i+1], flag); - i += 2; - } - } - tty_flip_buffer_push(tty); - tty_kref_put(tty); - } - } - - /* Resubmit urb so we continue receiving */ - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); -} - -/* not used, usa-49 doesn't have per-port control endpoints */ -static void usa49_outcont_callback(struct urb *urb) -{ - dbg("%s", __func__); -} - -static void usa90_indat_callback(struct urb *urb) -{ - int i, err; - int endpoint; - struct usb_serial_port *port; - struct keyspan_port_private *p_priv; - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - int status = urb->status; - - dbg("%s", __func__); - - endpoint = usb_pipeendpoint(urb->pipe); - - if (status) { - dbg("%s - nonzero status: %x on endpoint %d.", - __func__, status, endpoint); - return; - } - - port = urb->context; - p_priv = usb_get_serial_port_data(port); - - if (urb->actual_length) { - tty = tty_port_tty_get(&port->port); - /* if current mode is DMA, looks like usa28 format - otherwise looks like usa26 data format */ - - if (p_priv->baud > 57600) - tty_insert_flip_string(tty, data, urb->actual_length); - else { - /* 0x80 bit is error flag */ - if ((data[0] & 0x80) == 0) { - /* no errors on individual bytes, only - possible overrun err*/ - if (data[0] & RXERROR_OVERRUN) - err = TTY_OVERRUN; - else - err = 0; - for (i = 1; i < urb->actual_length ; ++i) - tty_insert_flip_char(tty, data[i], - err); - } else { - /* some bytes had errors, every byte has status */ - dbg("%s - RX error!!!!", __func__); - for (i = 0; i + 1 < urb->actual_length; i += 2) { - int stat = data[i], flag = 0; - if (stat & RXERROR_OVERRUN) - flag |= TTY_OVERRUN; - if (stat & RXERROR_FRAMING) - flag |= TTY_FRAME; - if (stat & RXERROR_PARITY) - flag |= TTY_PARITY; - /* XXX should handle break (0x10) */ - tty_insert_flip_char(tty, data[i+1], - flag); - } - } - } - tty_flip_buffer_push(tty); - tty_kref_put(tty); - } - - /* Resubmit urb so we continue receiving */ - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); -} - - -static void usa90_instat_callback(struct urb *urb) -{ - unsigned char *data = urb->transfer_buffer; - struct keyspan_usa90_portStatusMessage *msg; - struct usb_serial *serial; - struct usb_serial_port *port; - struct keyspan_port_private *p_priv; - struct tty_struct *tty; - int old_dcd_state, err; - int status = urb->status; - - serial = urb->context; - - if (status) { - dbg("%s - nonzero status: %x", __func__, status); - return; - } - if (urb->actual_length < 14) { - dbg("%s - %d byte report??", __func__, urb->actual_length); - goto exit; - } - - msg = (struct keyspan_usa90_portStatusMessage *)data; - - /* Now do something useful with the data */ - - port = serial->port[0]; - p_priv = usb_get_serial_port_data(port); - - /* Update handshaking pin state information */ - old_dcd_state = p_priv->dcd_state; - p_priv->cts_state = ((msg->cts) ? 1 : 0); - p_priv->dsr_state = ((msg->dsr) ? 1 : 0); - p_priv->dcd_state = ((msg->dcd) ? 1 : 0); - p_priv->ri_state = ((msg->ri) ? 1 : 0); - - if (old_dcd_state != p_priv->dcd_state && old_dcd_state) { - tty = tty_port_tty_get(&port->port); - if (tty && !C_CLOCAL(tty)) - tty_hangup(tty); - tty_kref_put(tty); - } - - /* Resubmit urb so we continue receiving */ - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); -exit: - ; -} - -static void usa90_outcont_callback(struct urb *urb) -{ - struct usb_serial_port *port; - struct keyspan_port_private *p_priv; - - port = urb->context; - p_priv = usb_get_serial_port_data(port); - - if (p_priv->resend_cont) { - dbg("%s - sending setup", __func__); - keyspan_usa90_send_setup(port->serial, port, - p_priv->resend_cont - 1); - } -} - -/* Status messages from the 28xg */ -static void usa67_instat_callback(struct urb *urb) -{ - int err; - unsigned char *data = urb->transfer_buffer; - struct keyspan_usa67_portStatusMessage *msg; - struct usb_serial *serial; - struct usb_serial_port *port; - struct keyspan_port_private *p_priv; - int old_dcd_state; - int status = urb->status; - - dbg("%s", __func__); - - serial = urb->context; - - if (status) { - dbg("%s - nonzero status: %x", __func__, status); - return; - } - - if (urb->actual_length != - sizeof(struct keyspan_usa67_portStatusMessage)) { - dbg("%s - bad length %d", __func__, urb->actual_length); - return; - } - - - /* Now do something useful with the data */ - msg = (struct keyspan_usa67_portStatusMessage *)data; - - /* Check port number from message and retrieve private data */ - if (msg->port >= serial->num_ports) { - dbg("%s - Unexpected port number %d", __func__, msg->port); - return; - } - - port = serial->port[msg->port]; - p_priv = usb_get_serial_port_data(port); - - /* Update handshaking pin state information */ - old_dcd_state = p_priv->dcd_state; - p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0); - p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0); - - if (old_dcd_state != p_priv->dcd_state && old_dcd_state) { - struct tty_struct *tty = tty_port_tty_get(&port->port); - if (tty && !C_CLOCAL(tty)) - tty_hangup(tty); - tty_kref_put(tty); - } - - /* Resubmit urb so we continue receiving */ - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err != 0) - dbg("%s - resubmit read urb failed. (%d)", __func__, err); -} - -static void usa67_glocont_callback(struct urb *urb) -{ - struct usb_serial *serial; - struct usb_serial_port *port; - struct keyspan_port_private *p_priv; - int i; - - dbg("%s", __func__); - - serial = urb->context; - for (i = 0; i < serial->num_ports; ++i) { - port = serial->port[i]; - p_priv = usb_get_serial_port_data(port); - - if (p_priv->resend_cont) { - dbg("%s - sending setup", __func__); - keyspan_usa67_send_setup(serial, port, - p_priv->resend_cont - 1); - break; - } - } -} - -static int keyspan_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct keyspan_port_private *p_priv; - const struct keyspan_device_details *d_details; - int flip; - int data_len; - struct urb *this_urb; - - dbg("%s", __func__); - p_priv = usb_get_serial_port_data(port); - d_details = p_priv->device_details; - - /* FIXME: locking */ - if (d_details->msg_format == msg_usa90) - data_len = 64; - else - data_len = 63; - - flip = p_priv->out_flip; - - /* Check both endpoints to see if any are available. */ - this_urb = p_priv->out_urbs[flip]; - if (this_urb != NULL) { - if (this_urb->status != -EINPROGRESS) - return data_len; - flip = (flip + 1) & d_details->outdat_endp_flip; - this_urb = p_priv->out_urbs[flip]; - if (this_urb != NULL) { - if (this_urb->status != -EINPROGRESS) - return data_len; - } - } - return 0; -} - - -static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct keyspan_port_private *p_priv; - struct keyspan_serial_private *s_priv; - struct usb_serial *serial = port->serial; - const struct keyspan_device_details *d_details; - int i, err; - int baud_rate, device_port; - struct urb *urb; - unsigned int cflag = 0; - - s_priv = usb_get_serial_data(serial); - p_priv = usb_get_serial_port_data(port); - d_details = p_priv->device_details; - - dbg("%s - port%d.", __func__, port->number); - - /* Set some sane defaults */ - p_priv->rts_state = 1; - p_priv->dtr_state = 1; - p_priv->baud = 9600; - - /* force baud and lcr to be set on open */ - p_priv->old_baud = 0; - p_priv->old_cflag = 0; - - p_priv->out_flip = 0; - p_priv->in_flip = 0; - - /* Reset low level data toggle and start reading from endpoints */ - for (i = 0; i < 2; i++) { - urb = p_priv->in_urbs[i]; - if (urb == NULL) - continue; - - /* make sure endpoint data toggle is synchronized - with the device */ - usb_clear_halt(urb->dev, urb->pipe); - err = usb_submit_urb(urb, GFP_KERNEL); - if (err != 0) - dbg("%s - submit urb %d failed (%d)", - __func__, i, err); - } - - /* Reset low level data toggle on out endpoints */ - for (i = 0; i < 2; i++) { - urb = p_priv->out_urbs[i]; - if (urb == NULL) - continue; - /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), - usb_pipeout(urb->pipe), 0); */ - } - - /* get the terminal config for the setup message now so we don't - * need to send 2 of them */ - - device_port = port->number - port->serial->minor; - if (tty) { - cflag = tty->termios->c_cflag; - /* Baud rate calculation takes baud rate as an integer - so other rates can be generated if desired. */ - baud_rate = tty_get_baud_rate(tty); - /* If no match or invalid, leave as default */ - if (baud_rate >= 0 - && d_details->calculate_baud_rate(baud_rate, d_details->baudclk, - NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) { - p_priv->baud = baud_rate; - } - } - /* set CTS/RTS handshake etc. */ - p_priv->cflag = cflag; - p_priv->flow_control = (cflag & CRTSCTS)? flow_cts: flow_none; - - keyspan_send_setup(port, 1); - /* mdelay(100); */ - /* keyspan_set_termios(port, NULL); */ - - return 0; -} - -static inline void stop_urb(struct urb *urb) -{ - if (urb && urb->status == -EINPROGRESS) - usb_kill_urb(urb); -} - -static void keyspan_dtr_rts(struct usb_serial_port *port, int on) -{ - struct keyspan_port_private *p_priv = usb_get_serial_port_data(port); - - p_priv->rts_state = on; - p_priv->dtr_state = on; - keyspan_send_setup(port, 0); -} - -static void keyspan_close(struct usb_serial_port *port) -{ - int i; - struct usb_serial *serial = port->serial; - struct keyspan_serial_private *s_priv; - struct keyspan_port_private *p_priv; - - dbg("%s", __func__); - s_priv = usb_get_serial_data(serial); - p_priv = usb_get_serial_port_data(port); - - p_priv->rts_state = 0; - p_priv->dtr_state = 0; - - if (serial->dev) { - keyspan_send_setup(port, 2); - /* pilot-xfer seems to work best with this delay */ - mdelay(100); - /* keyspan_set_termios(port, NULL); */ - } - - /*while (p_priv->outcont_urb->status == -EINPROGRESS) { - dbg("%s - urb in progress", __func__); - }*/ - - p_priv->out_flip = 0; - p_priv->in_flip = 0; - - if (serial->dev) { - /* Stop reading/writing urbs */ - stop_urb(p_priv->inack_urb); - /* stop_urb(p_priv->outcont_urb); */ - for (i = 0; i < 2; i++) { - stop_urb(p_priv->in_urbs[i]); - stop_urb(p_priv->out_urbs[i]); - } - } -} - -/* download the firmware to a pre-renumeration device */ -static int keyspan_fake_startup(struct usb_serial *serial) -{ - int response; - const struct ihex_binrec *record; - char *fw_name; - const struct firmware *fw; - - dbg("Keyspan startup version %04x product %04x", - le16_to_cpu(serial->dev->descriptor.bcdDevice), - le16_to_cpu(serial->dev->descriptor.idProduct)); - - if ((le16_to_cpu(serial->dev->descriptor.bcdDevice) & 0x8000) - != 0x8000) { - dbg("Firmware already loaded. Quitting."); - return 1; - } - - /* Select firmware image on the basis of idProduct */ - switch (le16_to_cpu(serial->dev->descriptor.idProduct)) { - case keyspan_usa28_pre_product_id: - fw_name = "keyspan/usa28.fw"; - break; - - case keyspan_usa28x_pre_product_id: - fw_name = "keyspan/usa28x.fw"; - break; - - case keyspan_usa28xa_pre_product_id: - fw_name = "keyspan/usa28xa.fw"; - break; - - case keyspan_usa28xb_pre_product_id: - fw_name = "keyspan/usa28xb.fw"; - break; - - case keyspan_usa19_pre_product_id: - fw_name = "keyspan/usa19.fw"; - break; - - case keyspan_usa19qi_pre_product_id: - fw_name = "keyspan/usa19qi.fw"; - break; - - case keyspan_mpr_pre_product_id: - fw_name = "keyspan/mpr.fw"; - break; - - case keyspan_usa19qw_pre_product_id: - fw_name = "keyspan/usa19qw.fw"; - break; - - case keyspan_usa18x_pre_product_id: - fw_name = "keyspan/usa18x.fw"; - break; - - case keyspan_usa19w_pre_product_id: - fw_name = "keyspan/usa19w.fw"; - break; - - case keyspan_usa49w_pre_product_id: - fw_name = "keyspan/usa49w.fw"; - break; - - case keyspan_usa49wlc_pre_product_id: - fw_name = "keyspan/usa49wlc.fw"; - break; - - default: - dev_err(&serial->dev->dev, "Unknown product ID (%04x)\n", - le16_to_cpu(serial->dev->descriptor.idProduct)); - return 1; - } - - if (request_ihex_firmware(&fw, fw_name, &serial->dev->dev)) { - dev_err(&serial->dev->dev, "Required keyspan firmware image (%s) unavailable.\n", fw_name); - return(1); - } - - dbg("Uploading Keyspan %s firmware.", fw_name); - - /* download the firmware image */ - response = ezusb_set_reset(serial, 1); - - record = (const struct ihex_binrec *)fw->data; - - while (record) { - response = ezusb_writememory(serial, be32_to_cpu(record->addr), - (unsigned char *)record->data, - be16_to_cpu(record->len), 0xa0); - if (response < 0) { - dev_err(&serial->dev->dev, "ezusb_writememory failed for Keyspan firmware (%d %04X %p %d)\n", - response, be32_to_cpu(record->addr), - record->data, be16_to_cpu(record->len)); - break; - } - record = ihex_next_binrec(record); - } - release_firmware(fw); - /* bring device out of reset. Renumeration will occur in a - moment and the new device will bind to the real driver */ - response = ezusb_set_reset(serial, 0); - - /* we don't want this device to have a driver assigned to it. */ - return 1; -} - -/* Helper functions used by keyspan_setup_urbs */ -static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial, - int endpoint) -{ - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *ep; - int i; - - iface_desc = serial->interface->cur_altsetting; - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - ep = &iface_desc->endpoint[i].desc; - if (ep->bEndpointAddress == endpoint) - return ep; - } - dev_warn(&serial->interface->dev, "found no endpoint descriptor for " - "endpoint %x\n", endpoint); - return NULL; -} - -static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint, - int dir, void *ctx, char *buf, int len, - void (*callback)(struct urb *)) -{ - struct urb *urb; - struct usb_endpoint_descriptor const *ep_desc; - char const *ep_type_name; - - if (endpoint == -1) - return NULL; /* endpoint not needed */ - - dbg("%s - alloc for endpoint %d.", __func__, endpoint); - urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */ - if (urb == NULL) { - dbg("%s - alloc for endpoint %d failed.", __func__, endpoint); - return NULL; - } - - if (endpoint == 0) { - /* control EP filled in when used */ - return urb; - } - - ep_desc = find_ep(serial, endpoint); - if (!ep_desc) { - /* leak the urb, something's wrong and the callers don't care */ - return urb; - } - if (usb_endpoint_xfer_int(ep_desc)) { - ep_type_name = "INT"; - usb_fill_int_urb(urb, serial->dev, - usb_sndintpipe(serial->dev, endpoint) | dir, - buf, len, callback, ctx, - ep_desc->bInterval); - } else if (usb_endpoint_xfer_bulk(ep_desc)) { - ep_type_name = "BULK"; - usb_fill_bulk_urb(urb, serial->dev, - usb_sndbulkpipe(serial->dev, endpoint) | dir, - buf, len, callback, ctx); - } else { - dev_warn(&serial->interface->dev, - "unsupported endpoint type %x\n", - usb_endpoint_type(ep_desc)); - usb_free_urb(urb); - return NULL; - } - - dbg("%s - using urb %p for %s endpoint %x", - __func__, urb, ep_type_name, endpoint); - return urb; -} - -static struct callbacks { - void (*instat_callback)(struct urb *); - void (*glocont_callback)(struct urb *); - void (*indat_callback)(struct urb *); - void (*outdat_callback)(struct urb *); - void (*inack_callback)(struct urb *); - void (*outcont_callback)(struct urb *); -} keyspan_callbacks[] = { - { - /* msg_usa26 callbacks */ - .instat_callback = usa26_instat_callback, - .glocont_callback = usa26_glocont_callback, - .indat_callback = usa26_indat_callback, - .outdat_callback = usa2x_outdat_callback, - .inack_callback = usa26_inack_callback, - .outcont_callback = usa26_outcont_callback, - }, { - /* msg_usa28 callbacks */ - .instat_callback = usa28_instat_callback, - .glocont_callback = usa28_glocont_callback, - .indat_callback = usa28_indat_callback, - .outdat_callback = usa2x_outdat_callback, - .inack_callback = usa28_inack_callback, - .outcont_callback = usa28_outcont_callback, - }, { - /* msg_usa49 callbacks */ - .instat_callback = usa49_instat_callback, - .glocont_callback = usa49_glocont_callback, - .indat_callback = usa49_indat_callback, - .outdat_callback = usa2x_outdat_callback, - .inack_callback = usa49_inack_callback, - .outcont_callback = usa49_outcont_callback, - }, { - /* msg_usa90 callbacks */ - .instat_callback = usa90_instat_callback, - .glocont_callback = usa28_glocont_callback, - .indat_callback = usa90_indat_callback, - .outdat_callback = usa2x_outdat_callback, - .inack_callback = usa28_inack_callback, - .outcont_callback = usa90_outcont_callback, - }, { - /* msg_usa67 callbacks */ - .instat_callback = usa67_instat_callback, - .glocont_callback = usa67_glocont_callback, - .indat_callback = usa26_indat_callback, - .outdat_callback = usa2x_outdat_callback, - .inack_callback = usa26_inack_callback, - .outcont_callback = usa26_outcont_callback, - } -}; - - /* Generic setup urbs function that uses - data in device_details */ -static void keyspan_setup_urbs(struct usb_serial *serial) -{ - int i, j; - struct keyspan_serial_private *s_priv; - const struct keyspan_device_details *d_details; - struct usb_serial_port *port; - struct keyspan_port_private *p_priv; - struct callbacks *cback; - int endp; - - dbg("%s", __func__); - - s_priv = usb_get_serial_data(serial); - d_details = s_priv->device_details; - - /* Setup values for the various callback routines */ - cback = &keyspan_callbacks[d_details->msg_format]; - - /* Allocate and set up urbs for each one that is in use, - starting with instat endpoints */ - s_priv->instat_urb = keyspan_setup_urb - (serial, d_details->instat_endpoint, USB_DIR_IN, - serial, s_priv->instat_buf, INSTAT_BUFLEN, - cback->instat_callback); - - s_priv->indat_urb = keyspan_setup_urb - (serial, d_details->indat_endpoint, USB_DIR_IN, - serial, s_priv->indat_buf, INDAT49W_BUFLEN, - usa49wg_indat_callback); - - s_priv->glocont_urb = keyspan_setup_urb - (serial, d_details->glocont_endpoint, USB_DIR_OUT, - serial, s_priv->glocont_buf, GLOCONT_BUFLEN, - cback->glocont_callback); - - /* Setup endpoints for each port specific thing */ - for (i = 0; i < d_details->num_ports; i++) { - port = serial->port[i]; - p_priv = usb_get_serial_port_data(port); - - /* Do indat endpoints first, once for each flip */ - endp = d_details->indat_endpoints[i]; - for (j = 0; j <= d_details->indat_endp_flip; ++j, ++endp) { - p_priv->in_urbs[j] = keyspan_setup_urb - (serial, endp, USB_DIR_IN, port, - p_priv->in_buffer[j], 64, - cback->indat_callback); - } - for (; j < 2; ++j) - p_priv->in_urbs[j] = NULL; - - /* outdat endpoints also have flip */ - endp = d_details->outdat_endpoints[i]; - for (j = 0; j <= d_details->outdat_endp_flip; ++j, ++endp) { - p_priv->out_urbs[j] = keyspan_setup_urb - (serial, endp, USB_DIR_OUT, port, - p_priv->out_buffer[j], 64, - cback->outdat_callback); - } - for (; j < 2; ++j) - p_priv->out_urbs[j] = NULL; - - /* inack endpoint */ - p_priv->inack_urb = keyspan_setup_urb - (serial, d_details->inack_endpoints[i], USB_DIR_IN, - port, p_priv->inack_buffer, 1, cback->inack_callback); - - /* outcont endpoint */ - p_priv->outcont_urb = keyspan_setup_urb - (serial, d_details->outcont_endpoints[i], USB_DIR_OUT, - port, p_priv->outcont_buffer, 64, - cback->outcont_callback); - } -} - -/* usa19 function doesn't require prescaler */ -static int keyspan_usa19_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi, - u8 *rate_low, u8 *prescaler, int portnum) -{ - u32 b16, /* baud rate times 16 (actual rate used internally) */ - div, /* divisor */ - cnt; /* inverse of divisor (programmed into 8051) */ - - dbg("%s - %d.", __func__, baud_rate); - - /* prevent divide by zero... */ - b16 = baud_rate * 16L; - if (b16 == 0) - return KEYSPAN_INVALID_BAUD_RATE; - /* Any "standard" rate over 57k6 is marginal on the USA-19 - as we run out of divisor resolution. */ - if (baud_rate > 57600) - return KEYSPAN_INVALID_BAUD_RATE; - - /* calculate the divisor and the counter (its inverse) */ - div = baudclk / b16; - if (div == 0) - return KEYSPAN_INVALID_BAUD_RATE; - else - cnt = 0 - div; - - if (div > 0xffff) - return KEYSPAN_INVALID_BAUD_RATE; - - /* return the counter values if non-null */ - if (rate_low) - *rate_low = (u8) (cnt & 0xff); - if (rate_hi) - *rate_hi = (u8) ((cnt >> 8) & 0xff); - if (rate_low && rate_hi) - dbg("%s - %d %02x %02x.", - __func__, baud_rate, *rate_hi, *rate_low); - return KEYSPAN_BAUD_RATE_OK; -} - -/* usa19hs function doesn't require prescaler */ -static int keyspan_usa19hs_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi, - u8 *rate_low, u8 *prescaler, int portnum) -{ - u32 b16, /* baud rate times 16 (actual rate used internally) */ - div; /* divisor */ - - dbg("%s - %d.", __func__, baud_rate); - - /* prevent divide by zero... */ - b16 = baud_rate * 16L; - if (b16 == 0) - return KEYSPAN_INVALID_BAUD_RATE; - - /* calculate the divisor */ - div = baudclk / b16; - if (div == 0) - return KEYSPAN_INVALID_BAUD_RATE; - - if (div > 0xffff) - return KEYSPAN_INVALID_BAUD_RATE; - - /* return the counter values if non-null */ - if (rate_low) - *rate_low = (u8) (div & 0xff); - - if (rate_hi) - *rate_hi = (u8) ((div >> 8) & 0xff); - - if (rate_low && rate_hi) - dbg("%s - %d %02x %02x.", - __func__, baud_rate, *rate_hi, *rate_low); - - return KEYSPAN_BAUD_RATE_OK; -} - -static int keyspan_usa19w_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi, - u8 *rate_low, u8 *prescaler, int portnum) -{ - u32 b16, /* baud rate times 16 (actual rate used internally) */ - clk, /* clock with 13/8 prescaler */ - div, /* divisor using 13/8 prescaler */ - res, /* resulting baud rate using 13/8 prescaler */ - diff, /* error using 13/8 prescaler */ - smallest_diff; - u8 best_prescaler; - int i; - - dbg("%s - %d.", __func__, baud_rate); - - /* prevent divide by zero */ - b16 = baud_rate * 16L; - if (b16 == 0) - return KEYSPAN_INVALID_BAUD_RATE; - - /* Calculate prescaler by trying them all and looking - for best fit */ - - /* start with largest possible difference */ - smallest_diff = 0xffffffff; - - /* 0 is an invalid prescaler, used as a flag */ - best_prescaler = 0; - - for (i = 8; i <= 0xff; ++i) { - clk = (baudclk * 8) / (u32) i; - - div = clk / b16; - if (div == 0) - continue; - - res = clk / div; - diff = (res > b16) ? (res-b16) : (b16-res); - - if (diff < smallest_diff) { - best_prescaler = i; - smallest_diff = diff; - } - } - - if (best_prescaler == 0) - return KEYSPAN_INVALID_BAUD_RATE; - - clk = (baudclk * 8) / (u32) best_prescaler; - div = clk / b16; - - /* return the divisor and prescaler if non-null */ - if (rate_low) - *rate_low = (u8) (div & 0xff); - if (rate_hi) - *rate_hi = (u8) ((div >> 8) & 0xff); - if (prescaler) { - *prescaler = best_prescaler; - /* dbg("%s - %d %d", __func__, *prescaler, div); */ - } - return KEYSPAN_BAUD_RATE_OK; -} - - /* USA-28 supports different maximum baud rates on each port */ -static int keyspan_usa28_calc_baud(u32 baud_rate, u32 baudclk, u8 *rate_hi, - u8 *rate_low, u8 *prescaler, int portnum) -{ - u32 b16, /* baud rate times 16 (actual rate used internally) */ - div, /* divisor */ - cnt; /* inverse of divisor (programmed into 8051) */ - - dbg("%s - %d.", __func__, baud_rate); - - /* prevent divide by zero */ - b16 = baud_rate * 16L; - if (b16 == 0) - return KEYSPAN_INVALID_BAUD_RATE; - - /* calculate the divisor and the counter (its inverse) */ - div = KEYSPAN_USA28_BAUDCLK / b16; - if (div == 0) - return KEYSPAN_INVALID_BAUD_RATE; - else - cnt = 0 - div; - - /* check for out of range, based on portnum, - and return result */ - if (portnum == 0) { - if (div > 0xffff) - return KEYSPAN_INVALID_BAUD_RATE; - } else { - if (portnum == 1) { - if (div > 0xff) - return KEYSPAN_INVALID_BAUD_RATE; - } else - return KEYSPAN_INVALID_BAUD_RATE; - } - - /* return the counter values if not NULL - (port 1 will ignore retHi) */ - if (rate_low) - *rate_low = (u8) (cnt & 0xff); - if (rate_hi) - *rate_hi = (u8) ((cnt >> 8) & 0xff); - dbg("%s - %d OK.", __func__, baud_rate); - return KEYSPAN_BAUD_RATE_OK; -} - -static int keyspan_usa26_send_setup(struct usb_serial *serial, - struct usb_serial_port *port, - int reset_port) -{ - struct keyspan_usa26_portControlMessage msg; - struct keyspan_serial_private *s_priv; - struct keyspan_port_private *p_priv; - const struct keyspan_device_details *d_details; - int outcont_urb; - struct urb *this_urb; - int device_port, err; - - dbg("%s reset=%d", __func__, reset_port); - - s_priv = usb_get_serial_data(serial); - p_priv = usb_get_serial_port_data(port); - d_details = s_priv->device_details; - device_port = port->number - port->serial->minor; - - outcont_urb = d_details->outcont_endpoints[port->number]; - this_urb = p_priv->outcont_urb; - - dbg("%s - endpoint %d", __func__, usb_pipeendpoint(this_urb->pipe)); - - /* Make sure we have an urb then send the message */ - if (this_urb == NULL) { - dbg("%s - oops no urb.", __func__); - return -1; - } - - /* Save reset port val for resend. - Don't overwrite resend for open/close condition. */ - if ((reset_port + 1) > p_priv->resend_cont) - p_priv->resend_cont = reset_port + 1; - if (this_urb->status == -EINPROGRESS) { - /* dbg("%s - already writing", __func__); */ - mdelay(5); - return -1; - } - - memset(&msg, 0, sizeof(struct keyspan_usa26_portControlMessage)); - - /* Only set baud rate if it's changed */ - if (p_priv->old_baud != p_priv->baud) { - p_priv->old_baud = p_priv->baud; - msg.setClocking = 0xff; - if (d_details->calculate_baud_rate - (p_priv->baud, d_details->baudclk, &msg.baudHi, - &msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE) { - dbg("%s - Invalid baud rate %d requested, using 9600.", - __func__, p_priv->baud); - msg.baudLo = 0; - msg.baudHi = 125; /* Values for 9600 baud */ - msg.prescaler = 10; - } - msg.setPrescaler = 0xff; - } - - msg.lcr = (p_priv->cflag & CSTOPB)? STOPBITS_678_2: STOPBITS_5678_1; - switch (p_priv->cflag & CSIZE) { - case CS5: - msg.lcr |= USA_DATABITS_5; - break; - case CS6: - msg.lcr |= USA_DATABITS_6; - break; - case CS7: - msg.lcr |= USA_DATABITS_7; - break; - case CS8: - msg.lcr |= USA_DATABITS_8; - break; - } - if (p_priv->cflag & PARENB) { - /* note USA_PARITY_NONE == 0 */ - msg.lcr |= (p_priv->cflag & PARODD)? - USA_PARITY_ODD : USA_PARITY_EVEN; - } - msg.setLcr = 0xff; - - msg.ctsFlowControl = (p_priv->flow_control == flow_cts); - msg.xonFlowControl = 0; - msg.setFlowControl = 0xff; - msg.forwardingLength = 16; - msg.xonChar = 17; - msg.xoffChar = 19; - - /* Opening port */ - if (reset_port == 1) { - msg._txOn = 1; - msg._txOff = 0; - msg.txFlush = 0; - msg.txBreak = 0; - msg.rxOn = 1; - msg.rxOff = 0; - msg.rxFlush = 1; - msg.rxForward = 0; - msg.returnStatus = 0; - msg.resetDataToggle = 0xff; - } - - /* Closing port */ - else if (reset_port == 2) { - msg._txOn = 0; - msg._txOff = 1; - msg.txFlush = 0; - msg.txBreak = 0; - msg.rxOn = 0; - msg.rxOff = 1; - msg.rxFlush = 1; - msg.rxForward = 0; - msg.returnStatus = 0; - msg.resetDataToggle = 0; - } - - /* Sending intermediate configs */ - else { - msg._txOn = (!p_priv->break_on); - msg._txOff = 0; - msg.txFlush = 0; - msg.txBreak = (p_priv->break_on); - msg.rxOn = 0; - msg.rxOff = 0; - msg.rxFlush = 0; - msg.rxForward = 0; - msg.returnStatus = 0; - msg.resetDataToggle = 0x0; - } - - /* Do handshaking outputs */ - msg.setTxTriState_setRts = 0xff; - msg.txTriState_rts = p_priv->rts_state; - - msg.setHskoa_setDtr = 0xff; - msg.hskoa_dtr = p_priv->dtr_state; - - p_priv->resend_cont = 0; - memcpy(this_urb->transfer_buffer, &msg, sizeof(msg)); - - /* send the data out the device on control endpoint */ - this_urb->transfer_buffer_length = sizeof(msg); - - err = usb_submit_urb(this_urb, GFP_ATOMIC); - if (err != 0) - dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err); -#if 0 - else { - dbg("%s - usb_submit_urb(%d) OK %d bytes (end %d)", __func__ - outcont_urb, this_urb->transfer_buffer_length, - usb_pipeendpoint(this_urb->pipe)); - } -#endif - - return 0; -} - -static int keyspan_usa28_send_setup(struct usb_serial *serial, - struct usb_serial_port *port, - int reset_port) -{ - struct keyspan_usa28_portControlMessage msg; - struct keyspan_serial_private *s_priv; - struct keyspan_port_private *p_priv; - const struct keyspan_device_details *d_details; - struct urb *this_urb; - int device_port, err; - - dbg("%s", __func__); - - s_priv = usb_get_serial_data(serial); - p_priv = usb_get_serial_port_data(port); - d_details = s_priv->device_details; - device_port = port->number - port->serial->minor; - - /* only do something if we have a bulk out endpoint */ - this_urb = p_priv->outcont_urb; - if (this_urb == NULL) { - dbg("%s - oops no urb.", __func__); - return -1; - } - - /* Save reset port val for resend. - Don't overwrite resend for open/close condition. */ - if ((reset_port + 1) > p_priv->resend_cont) - p_priv->resend_cont = reset_port + 1; - if (this_urb->status == -EINPROGRESS) { - dbg("%s already writing", __func__); - mdelay(5); - return -1; - } - - memset(&msg, 0, sizeof(struct keyspan_usa28_portControlMessage)); - - msg.setBaudRate = 1; - if (d_details->calculate_baud_rate(p_priv->baud, d_details->baudclk, - &msg.baudHi, &msg.baudLo, NULL, device_port) == KEYSPAN_INVALID_BAUD_RATE) { - dbg("%s - Invalid baud rate requested %d.", - __func__, p_priv->baud); - msg.baudLo = 0xff; - msg.baudHi = 0xb2; /* Values for 9600 baud */ - } - - /* If parity is enabled, we must calculate it ourselves. */ - msg.parity = 0; /* XXX for now */ - - msg.ctsFlowControl = (p_priv->flow_control == flow_cts); - msg.xonFlowControl = 0; - - /* Do handshaking outputs, DTR is inverted relative to RTS */ - msg.rts = p_priv->rts_state; - msg.dtr = p_priv->dtr_state; - - msg.forwardingLength = 16; - msg.forwardMs = 10; - msg.breakThreshold = 45; - msg.xonChar = 17; - msg.xoffChar = 19; - - /*msg.returnStatus = 1; - msg.resetDataToggle = 0xff;*/ - /* Opening port */ - if (reset_port == 1) { - msg._txOn = 1; - msg._txOff = 0; - msg.txFlush = 0; - msg.txForceXoff = 0; - msg.txBreak = 0; - msg.rxOn = 1; - msg.rxOff = 0; - msg.rxFlush = 1; - msg.rxForward = 0; - msg.returnStatus = 0; - msg.resetDataToggle = 0xff; - } - /* Closing port */ - else if (reset_port == 2) { - msg._txOn = 0; - msg._txOff = 1; - msg.txFlush = 0; - msg.txForceXoff = 0; - msg.txBreak = 0; - msg.rxOn = 0; - msg.rxOff = 1; - msg.rxFlush = 1; - msg.rxForward = 0; - msg.returnStatus = 0; - msg.resetDataToggle = 0; - } - /* Sending intermediate configs */ - else { - msg._txOn = (!p_priv->break_on); - msg._txOff = 0; - msg.txFlush = 0; - msg.txForceXoff = 0; - msg.txBreak = (p_priv->break_on); - msg.rxOn = 0; - msg.rxOff = 0; - msg.rxFlush = 0; - msg.rxForward = 0; - msg.returnStatus = 0; - msg.resetDataToggle = 0x0; - } - - p_priv->resend_cont = 0; - memcpy(this_urb->transfer_buffer, &msg, sizeof(msg)); - - /* send the data out the device on control endpoint */ - this_urb->transfer_buffer_length = sizeof(msg); - - err = usb_submit_urb(this_urb, GFP_ATOMIC); - if (err != 0) - dbg("%s - usb_submit_urb(setup) failed", __func__); -#if 0 - else { - dbg("%s - usb_submit_urb(setup) OK %d bytes", __func__, - this_urb->transfer_buffer_length); - } -#endif - - return 0; -} - -static int keyspan_usa49_send_setup(struct usb_serial *serial, - struct usb_serial_port *port, - int reset_port) -{ - struct keyspan_usa49_portControlMessage msg; - struct usb_ctrlrequest *dr = NULL; - struct keyspan_serial_private *s_priv; - struct keyspan_port_private *p_priv; - const struct keyspan_device_details *d_details; - struct urb *this_urb; - int err, device_port; - - dbg("%s", __func__); - - s_priv = usb_get_serial_data(serial); - p_priv = usb_get_serial_port_data(port); - d_details = s_priv->device_details; - - this_urb = s_priv->glocont_urb; - - /* Work out which port within the device is being setup */ - device_port = port->number - port->serial->minor; - - /* Make sure we have an urb then send the message */ - if (this_urb == NULL) { - dbg("%s - oops no urb for port %d.", __func__, port->number); - return -1; - } - - dbg("%s - endpoint %d port %d (%d)", - __func__, usb_pipeendpoint(this_urb->pipe), - port->number, device_port); - - /* Save reset port val for resend. - Don't overwrite resend for open/close condition. */ - if ((reset_port + 1) > p_priv->resend_cont) - p_priv->resend_cont = reset_port + 1; - - if (this_urb->status == -EINPROGRESS) { - /* dbg("%s - already writing", __func__); */ - mdelay(5); - return -1; - } - - memset(&msg, 0, sizeof(struct keyspan_usa49_portControlMessage)); - - /*msg.portNumber = port->number;*/ - msg.portNumber = device_port; - - /* Only set baud rate if it's changed */ - if (p_priv->old_baud != p_priv->baud) { - p_priv->old_baud = p_priv->baud; - msg.setClocking = 0xff; - if (d_details->calculate_baud_rate - (p_priv->baud, d_details->baudclk, &msg.baudHi, - &msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE) { - dbg("%s - Invalid baud rate %d requested, using 9600.", - __func__, p_priv->baud); - msg.baudLo = 0; - msg.baudHi = 125; /* Values for 9600 baud */ - msg.prescaler = 10; - } - /* msg.setPrescaler = 0xff; */ - } - - msg.lcr = (p_priv->cflag & CSTOPB)? STOPBITS_678_2: STOPBITS_5678_1; - switch (p_priv->cflag & CSIZE) { - case CS5: - msg.lcr |= USA_DATABITS_5; - break; - case CS6: - msg.lcr |= USA_DATABITS_6; - break; - case CS7: - msg.lcr |= USA_DATABITS_7; - break; - case CS8: - msg.lcr |= USA_DATABITS_8; - break; - } - if (p_priv->cflag & PARENB) { - /* note USA_PARITY_NONE == 0 */ - msg.lcr |= (p_priv->cflag & PARODD)? - USA_PARITY_ODD : USA_PARITY_EVEN; - } - msg.setLcr = 0xff; - - msg.ctsFlowControl = (p_priv->flow_control == flow_cts); - msg.xonFlowControl = 0; - msg.setFlowControl = 0xff; - - msg.forwardingLength = 16; - msg.xonChar = 17; - msg.xoffChar = 19; - - /* Opening port */ - if (reset_port == 1) { - msg._txOn = 1; - msg._txOff = 0; - msg.txFlush = 0; - msg.txBreak = 0; - msg.rxOn = 1; - msg.rxOff = 0; - msg.rxFlush = 1; - msg.rxForward = 0; - msg.returnStatus = 0; - msg.resetDataToggle = 0xff; - msg.enablePort = 1; - msg.disablePort = 0; - } - /* Closing port */ - else if (reset_port == 2) { - msg._txOn = 0; - msg._txOff = 1; - msg.txFlush = 0; - msg.txBreak = 0; - msg.rxOn = 0; - msg.rxOff = 1; - msg.rxFlush = 1; - msg.rxForward = 0; - msg.returnStatus = 0; - msg.resetDataToggle = 0; - msg.enablePort = 0; - msg.disablePort = 1; - } - /* Sending intermediate configs */ - else { - msg._txOn = (!p_priv->break_on); - msg._txOff = 0; - msg.txFlush = 0; - msg.txBreak = (p_priv->break_on); - msg.rxOn = 0; - msg.rxOff = 0; - msg.rxFlush = 0; - msg.rxForward = 0; - msg.returnStatus = 0; - msg.resetDataToggle = 0x0; - msg.enablePort = 0; - msg.disablePort = 0; - } - - /* Do handshaking outputs */ - msg.setRts = 0xff; - msg.rts = p_priv->rts_state; - - msg.setDtr = 0xff; - msg.dtr = p_priv->dtr_state; - - p_priv->resend_cont = 0; - - /* if the device is a 49wg, we send control message on usb - control EP 0 */ - - if (d_details->product_id == keyspan_usa49wg_product_id) { - dr = (void *)(s_priv->ctrl_buf); - dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT; - dr->bRequest = 0xB0; /* 49wg control message */; - dr->wValue = 0; - dr->wIndex = 0; - dr->wLength = cpu_to_le16(sizeof(msg)); - - memcpy(s_priv->glocont_buf, &msg, sizeof(msg)); - - usb_fill_control_urb(this_urb, serial->dev, - usb_sndctrlpipe(serial->dev, 0), - (unsigned char *)dr, s_priv->glocont_buf, - sizeof(msg), usa49_glocont_callback, serial); - - } else { - memcpy(this_urb->transfer_buffer, &msg, sizeof(msg)); - - /* send the data out the device on control endpoint */ - this_urb->transfer_buffer_length = sizeof(msg); - } - err = usb_submit_urb(this_urb, GFP_ATOMIC); - if (err != 0) - dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err); -#if 0 - else { - dbg("%s - usb_submit_urb(%d) OK %d bytes (end %d)", __func__, - outcont_urb, this_urb->transfer_buffer_length, - usb_pipeendpoint(this_urb->pipe)); - } -#endif - - return 0; -} - -static int keyspan_usa90_send_setup(struct usb_serial *serial, - struct usb_serial_port *port, - int reset_port) -{ - struct keyspan_usa90_portControlMessage msg; - struct keyspan_serial_private *s_priv; - struct keyspan_port_private *p_priv; - const struct keyspan_device_details *d_details; - struct urb *this_urb; - int err; - u8 prescaler; - - dbg("%s", __func__); - - s_priv = usb_get_serial_data(serial); - p_priv = usb_get_serial_port_data(port); - d_details = s_priv->device_details; - - /* only do something if we have a bulk out endpoint */ - this_urb = p_priv->outcont_urb; - if (this_urb == NULL) { - dbg("%s - oops no urb.", __func__); - return -1; - } - - /* Save reset port val for resend. - Don't overwrite resend for open/close condition. */ - if ((reset_port + 1) > p_priv->resend_cont) - p_priv->resend_cont = reset_port + 1; - if (this_urb->status == -EINPROGRESS) { - dbg("%s already writing", __func__); - mdelay(5); - return -1; - } - - memset(&msg, 0, sizeof(struct keyspan_usa90_portControlMessage)); - - /* Only set baud rate if it's changed */ - if (p_priv->old_baud != p_priv->baud) { - p_priv->old_baud = p_priv->baud; - msg.setClocking = 0x01; - if (d_details->calculate_baud_rate - (p_priv->baud, d_details->baudclk, &msg.baudHi, - &msg.baudLo, &prescaler, 0) == KEYSPAN_INVALID_BAUD_RATE) { - dbg("%s - Invalid baud rate %d requested, using 9600.", - __func__, p_priv->baud); - p_priv->baud = 9600; - d_details->calculate_baud_rate(p_priv->baud, d_details->baudclk, - &msg.baudHi, &msg.baudLo, &prescaler, 0); - } - msg.setRxMode = 1; - msg.setTxMode = 1; - } - - /* modes must always be correctly specified */ - if (p_priv->baud > 57600) { - msg.rxMode = RXMODE_DMA; - msg.txMode = TXMODE_DMA; - } else { - msg.rxMode = RXMODE_BYHAND; - msg.txMode = TXMODE_BYHAND; - } - - msg.lcr = (p_priv->cflag & CSTOPB)? STOPBITS_678_2: STOPBITS_5678_1; - switch (p_priv->cflag & CSIZE) { - case CS5: - msg.lcr |= USA_DATABITS_5; - break; - case CS6: - msg.lcr |= USA_DATABITS_6; - break; - case CS7: - msg.lcr |= USA_DATABITS_7; - break; - case CS8: - msg.lcr |= USA_DATABITS_8; - break; - } - if (p_priv->cflag & PARENB) { - /* note USA_PARITY_NONE == 0 */ - msg.lcr |= (p_priv->cflag & PARODD)? - USA_PARITY_ODD : USA_PARITY_EVEN; - } - if (p_priv->old_cflag != p_priv->cflag) { - p_priv->old_cflag = p_priv->cflag; - msg.setLcr = 0x01; - } - - if (p_priv->flow_control == flow_cts) - msg.txFlowControl = TXFLOW_CTS; - msg.setTxFlowControl = 0x01; - msg.setRxFlowControl = 0x01; - - msg.rxForwardingLength = 16; - msg.rxForwardingTimeout = 16; - msg.txAckSetting = 0; - msg.xonChar = 17; - msg.xoffChar = 19; - - /* Opening port */ - if (reset_port == 1) { - msg.portEnabled = 1; - msg.rxFlush = 1; - msg.txBreak = (p_priv->break_on); - } - /* Closing port */ - else if (reset_port == 2) - msg.portEnabled = 0; - /* Sending intermediate configs */ - else { - msg.portEnabled = 1; - msg.txBreak = (p_priv->break_on); - } - - /* Do handshaking outputs */ - msg.setRts = 0x01; - msg.rts = p_priv->rts_state; - - msg.setDtr = 0x01; - msg.dtr = p_priv->dtr_state; - - p_priv->resend_cont = 0; - memcpy(this_urb->transfer_buffer, &msg, sizeof(msg)); - - /* send the data out the device on control endpoint */ - this_urb->transfer_buffer_length = sizeof(msg); - - err = usb_submit_urb(this_urb, GFP_ATOMIC); - if (err != 0) - dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err); - return 0; -} - -static int keyspan_usa67_send_setup(struct usb_serial *serial, - struct usb_serial_port *port, - int reset_port) -{ - struct keyspan_usa67_portControlMessage msg; - struct keyspan_serial_private *s_priv; - struct keyspan_port_private *p_priv; - const struct keyspan_device_details *d_details; - struct urb *this_urb; - int err, device_port; - - dbg("%s", __func__); - - s_priv = usb_get_serial_data(serial); - p_priv = usb_get_serial_port_data(port); - d_details = s_priv->device_details; - - this_urb = s_priv->glocont_urb; - - /* Work out which port within the device is being setup */ - device_port = port->number - port->serial->minor; - - /* Make sure we have an urb then send the message */ - if (this_urb == NULL) { - dbg("%s - oops no urb for port %d.", __func__, - port->number); - return -1; - } - - /* Save reset port val for resend. - Don't overwrite resend for open/close condition. */ - if ((reset_port + 1) > p_priv->resend_cont) - p_priv->resend_cont = reset_port + 1; - if (this_urb->status == -EINPROGRESS) { - /* dbg("%s - already writing", __func__); */ - mdelay(5); - return -1; - } - - memset(&msg, 0, sizeof(struct keyspan_usa67_portControlMessage)); - - msg.port = device_port; - - /* Only set baud rate if it's changed */ - if (p_priv->old_baud != p_priv->baud) { - p_priv->old_baud = p_priv->baud; - msg.setClocking = 0xff; - if (d_details->calculate_baud_rate - (p_priv->baud, d_details->baudclk, &msg.baudHi, - &msg.baudLo, &msg.prescaler, device_port) == KEYSPAN_INVALID_BAUD_RATE) { - dbg("%s - Invalid baud rate %d requested, using 9600.", - __func__, p_priv->baud); - msg.baudLo = 0; - msg.baudHi = 125; /* Values for 9600 baud */ - msg.prescaler = 10; - } - msg.setPrescaler = 0xff; - } - - msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1; - switch (p_priv->cflag & CSIZE) { - case CS5: - msg.lcr |= USA_DATABITS_5; - break; - case CS6: - msg.lcr |= USA_DATABITS_6; - break; - case CS7: - msg.lcr |= USA_DATABITS_7; - break; - case CS8: - msg.lcr |= USA_DATABITS_8; - break; - } - if (p_priv->cflag & PARENB) { - /* note USA_PARITY_NONE == 0 */ - msg.lcr |= (p_priv->cflag & PARODD)? - USA_PARITY_ODD : USA_PARITY_EVEN; - } - msg.setLcr = 0xff; - - msg.ctsFlowControl = (p_priv->flow_control == flow_cts); - msg.xonFlowControl = 0; - msg.setFlowControl = 0xff; - msg.forwardingLength = 16; - msg.xonChar = 17; - msg.xoffChar = 19; - - if (reset_port == 1) { - /* Opening port */ - msg._txOn = 1; - msg._txOff = 0; - msg.txFlush = 0; - msg.txBreak = 0; - msg.rxOn = 1; - msg.rxOff = 0; - msg.rxFlush = 1; - msg.rxForward = 0; - msg.returnStatus = 0; - msg.resetDataToggle = 0xff; - } else if (reset_port == 2) { - /* Closing port */ - msg._txOn = 0; - msg._txOff = 1; - msg.txFlush = 0; - msg.txBreak = 0; - msg.rxOn = 0; - msg.rxOff = 1; - msg.rxFlush = 1; - msg.rxForward = 0; - msg.returnStatus = 0; - msg.resetDataToggle = 0; - } else { - /* Sending intermediate configs */ - msg._txOn = (!p_priv->break_on); - msg._txOff = 0; - msg.txFlush = 0; - msg.txBreak = (p_priv->break_on); - msg.rxOn = 0; - msg.rxOff = 0; - msg.rxFlush = 0; - msg.rxForward = 0; - msg.returnStatus = 0; - msg.resetDataToggle = 0x0; - } - - /* Do handshaking outputs */ - msg.setTxTriState_setRts = 0xff; - msg.txTriState_rts = p_priv->rts_state; - - msg.setHskoa_setDtr = 0xff; - msg.hskoa_dtr = p_priv->dtr_state; - - p_priv->resend_cont = 0; - - memcpy(this_urb->transfer_buffer, &msg, sizeof(msg)); - - /* send the data out the device on control endpoint */ - this_urb->transfer_buffer_length = sizeof(msg); - - err = usb_submit_urb(this_urb, GFP_ATOMIC); - if (err != 0) - dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, - err); - return 0; -} - -static void keyspan_send_setup(struct usb_serial_port *port, int reset_port) -{ - struct usb_serial *serial = port->serial; - struct keyspan_serial_private *s_priv; - const struct keyspan_device_details *d_details; - - dbg("%s", __func__); - - s_priv = usb_get_serial_data(serial); - d_details = s_priv->device_details; - - switch (d_details->msg_format) { - case msg_usa26: - keyspan_usa26_send_setup(serial, port, reset_port); - break; - case msg_usa28: - keyspan_usa28_send_setup(serial, port, reset_port); - break; - case msg_usa49: - keyspan_usa49_send_setup(serial, port, reset_port); - break; - case msg_usa90: - keyspan_usa90_send_setup(serial, port, reset_port); - break; - case msg_usa67: - keyspan_usa67_send_setup(serial, port, reset_port); - break; - } -} - - -/* Gets called by the "real" driver (ie once firmware is loaded - and renumeration has taken place. */ -static int keyspan_startup(struct usb_serial *serial) -{ - int i, err; - struct usb_serial_port *port; - struct keyspan_serial_private *s_priv; - struct keyspan_port_private *p_priv; - const struct keyspan_device_details *d_details; - - dbg("%s", __func__); - - for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i) - if (d_details->product_id == - le16_to_cpu(serial->dev->descriptor.idProduct)) - break; - if (d_details == NULL) { - dev_err(&serial->dev->dev, "%s - unknown product id %x\n", - __func__, le16_to_cpu(serial->dev->descriptor.idProduct)); - return 1; - } - - /* Setup private data for serial driver */ - s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL); - if (!s_priv) { - dbg("%s - kmalloc for keyspan_serial_private failed.", - __func__); - return -ENOMEM; - } - - s_priv->device_details = d_details; - usb_set_serial_data(serial, s_priv); - - /* Now setup per port private data */ - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - p_priv = kzalloc(sizeof(struct keyspan_port_private), - GFP_KERNEL); - if (!p_priv) { - dbg("%s - kmalloc for keyspan_port_private (%d) failed!.", __func__, i); - return 1; - } - p_priv->device_details = d_details; - usb_set_serial_port_data(port, p_priv); - } - - keyspan_setup_urbs(serial); - - if (s_priv->instat_urb != NULL) { - err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL); - if (err != 0) - dbg("%s - submit instat urb failed %d", __func__, - err); - } - if (s_priv->indat_urb != NULL) { - err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL); - if (err != 0) - dbg("%s - submit indat urb failed %d", __func__, - err); - } - - return 0; -} - -static void keyspan_disconnect(struct usb_serial *serial) -{ - int i, j; - struct usb_serial_port *port; - struct keyspan_serial_private *s_priv; - struct keyspan_port_private *p_priv; - - dbg("%s", __func__); - - s_priv = usb_get_serial_data(serial); - - /* Stop reading/writing urbs */ - stop_urb(s_priv->instat_urb); - stop_urb(s_priv->glocont_urb); - stop_urb(s_priv->indat_urb); - for (i = 0; i < serial->num_ports; ++i) { - port = serial->port[i]; - p_priv = usb_get_serial_port_data(port); - stop_urb(p_priv->inack_urb); - stop_urb(p_priv->outcont_urb); - for (j = 0; j < 2; j++) { - stop_urb(p_priv->in_urbs[j]); - stop_urb(p_priv->out_urbs[j]); - } - } - - /* Now free them */ - usb_free_urb(s_priv->instat_urb); - usb_free_urb(s_priv->indat_urb); - usb_free_urb(s_priv->glocont_urb); - for (i = 0; i < serial->num_ports; ++i) { - port = serial->port[i]; - p_priv = usb_get_serial_port_data(port); - usb_free_urb(p_priv->inack_urb); - usb_free_urb(p_priv->outcont_urb); - for (j = 0; j < 2; j++) { - usb_free_urb(p_priv->in_urbs[j]); - usb_free_urb(p_priv->out_urbs[j]); - } - } -} - -static void keyspan_release(struct usb_serial *serial) -{ - int i; - struct usb_serial_port *port; - struct keyspan_serial_private *s_priv; - - dbg("%s", __func__); - - s_priv = usb_get_serial_data(serial); - - /* dbg("Freeing serial->private."); */ - kfree(s_priv); - - /* dbg("Freeing port->private."); */ - /* Now free per port private data */ - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - kfree(usb_get_serial_port_data(port)); - } -} - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -MODULE_FIRMWARE("keyspan/usa28.fw"); -MODULE_FIRMWARE("keyspan/usa28x.fw"); -MODULE_FIRMWARE("keyspan/usa28xa.fw"); -MODULE_FIRMWARE("keyspan/usa28xb.fw"); -MODULE_FIRMWARE("keyspan/usa19.fw"); -MODULE_FIRMWARE("keyspan/usa19qi.fw"); -MODULE_FIRMWARE("keyspan/mpr.fw"); -MODULE_FIRMWARE("keyspan/usa19qw.fw"); -MODULE_FIRMWARE("keyspan/usa18x.fw"); -MODULE_FIRMWARE("keyspan/usa19w.fw"); -MODULE_FIRMWARE("keyspan/usa49w.fw"); -MODULE_FIRMWARE("keyspan/usa49wlc.fw"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - diff --git a/ANDROID_3.4.5/drivers/usb/serial/keyspan.h b/ANDROID_3.4.5/drivers/usb/serial/keyspan.h deleted file mode 100644 index 622853c9..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/keyspan.h +++ /dev/null @@ -1,623 +0,0 @@ -/* - Keyspan USB to Serial Converter driver - - (C) Copyright (C) 2000-2001 - Hugh Blemings - - 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. - - See http://blemings.org/hugh/keyspan.html for more information. - - Code in this driver inspired by and in a number of places taken - from Brian Warner's original Keyspan-PDA driver. - - This driver has been put together with the support of Innosys, Inc. - and Keyspan, Inc the manufacturers of the Keyspan USB-serial products. - Thanks Guys :) - - Thanks to Paulus for miscellaneous tidy ups, some largish chunks - of much nicer and/or completely new code and (perhaps most uniquely) - having the patience to sit down and explain why and where he'd changed - stuff. - - Tip 'o the hat to IBM (and previously Linuxcare :) for supporting - staff in their work on open source projects. - - See keyspan.c for update history. - -*/ - -#ifndef __LINUX_USB_SERIAL_KEYSPAN_H -#define __LINUX_USB_SERIAL_KEYSPAN_H - - -/* Function prototypes for Keyspan serial converter */ -static int keyspan_open (struct tty_struct *tty, - struct usb_serial_port *port); -static void keyspan_close (struct usb_serial_port *port); -static void keyspan_dtr_rts (struct usb_serial_port *port, int on); -static int keyspan_startup (struct usb_serial *serial); -static void keyspan_disconnect (struct usb_serial *serial); -static void keyspan_release (struct usb_serial *serial); -static int keyspan_write_room (struct tty_struct *tty); - -static int keyspan_write (struct tty_struct *tty, - struct usb_serial_port *port, - const unsigned char *buf, - int count); - -static void keyspan_send_setup (struct usb_serial_port *port, - int reset_port); - - -static void keyspan_set_termios (struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old); -static void keyspan_break_ctl (struct tty_struct *tty, - int break_state); -static int keyspan_tiocmget (struct tty_struct *tty); -static int keyspan_tiocmset (struct tty_struct *tty, - unsigned int set, - unsigned int clear); -static int keyspan_fake_startup (struct usb_serial *serial); - -static int keyspan_usa19_calc_baud (u32 baud_rate, u32 baudclk, - u8 *rate_hi, u8 *rate_low, - u8 *prescaler, int portnum); - -static int keyspan_usa19w_calc_baud (u32 baud_rate, u32 baudclk, - u8 *rate_hi, u8 *rate_low, - u8 *prescaler, int portnum); - -static int keyspan_usa28_calc_baud (u32 baud_rate, u32 baudclk, - u8 *rate_hi, u8 *rate_low, - u8 *prescaler, int portnum); - -static int keyspan_usa19hs_calc_baud (u32 baud_rate, u32 baudclk, - u8 *rate_hi, u8 *rate_low, - u8 *prescaler, int portnum); - -static int keyspan_usa28_send_setup (struct usb_serial *serial, - struct usb_serial_port *port, - int reset_port); -static int keyspan_usa26_send_setup (struct usb_serial *serial, - struct usb_serial_port *port, - int reset_port); -static int keyspan_usa49_send_setup (struct usb_serial *serial, - struct usb_serial_port *port, - int reset_port); - -static int keyspan_usa90_send_setup (struct usb_serial *serial, - struct usb_serial_port *port, - int reset_port); - -static int keyspan_usa67_send_setup (struct usb_serial *serial, - struct usb_serial_port *port, - int reset_port); - -/* Values used for baud rate calculation - device specific */ -#define KEYSPAN_INVALID_BAUD_RATE (-1) -#define KEYSPAN_BAUD_RATE_OK (0) -#define KEYSPAN_USA18X_BAUDCLK (12000000L) /* a guess */ -#define KEYSPAN_USA19_BAUDCLK (12000000L) -#define KEYSPAN_USA19W_BAUDCLK (24000000L) -#define KEYSPAN_USA19HS_BAUDCLK (14769231L) -#define KEYSPAN_USA28_BAUDCLK (1843200L) -#define KEYSPAN_USA28X_BAUDCLK (12000000L) -#define KEYSPAN_USA49W_BAUDCLK (48000000L) - -/* Some constants used to characterise each device. */ -#define KEYSPAN_MAX_NUM_PORTS (4) -#define KEYSPAN_MAX_FLIPS (2) - -/* Device info for the Keyspan serial converter, used - by the overall usb-serial probe function */ -#define KEYSPAN_VENDOR_ID (0x06cd) - -/* Product IDs for the products supported, pre-renumeration */ -#define keyspan_usa18x_pre_product_id 0x0105 -#define keyspan_usa19_pre_product_id 0x0103 -#define keyspan_usa19qi_pre_product_id 0x010b -#define keyspan_mpr_pre_product_id 0x011b -#define keyspan_usa19qw_pre_product_id 0x0118 -#define keyspan_usa19w_pre_product_id 0x0106 -#define keyspan_usa28_pre_product_id 0x0101 -#define keyspan_usa28x_pre_product_id 0x0102 -#define keyspan_usa28xa_pre_product_id 0x0114 -#define keyspan_usa28xb_pre_product_id 0x0113 -#define keyspan_usa49w_pre_product_id 0x0109 -#define keyspan_usa49wlc_pre_product_id 0x011a - -/* Product IDs post-renumeration. Note that the 28x and 28xb - have the same id's post-renumeration but behave identically - so it's not an issue. As such, the 28xb is not listed in any - of the device tables. */ -#define keyspan_usa18x_product_id 0x0112 -#define keyspan_usa19_product_id 0x0107 -#define keyspan_usa19qi_product_id 0x010c -#define keyspan_usa19hs_product_id 0x0121 -#define keyspan_mpr_product_id 0x011c -#define keyspan_usa19qw_product_id 0x0119 -#define keyspan_usa19w_product_id 0x0108 -#define keyspan_usa28_product_id 0x010f -#define keyspan_usa28x_product_id 0x0110 -#define keyspan_usa28xa_product_id 0x0115 -#define keyspan_usa28xb_product_id 0x0110 -#define keyspan_usa28xg_product_id 0x0135 -#define keyspan_usa49w_product_id 0x010a -#define keyspan_usa49wlc_product_id 0x012a -#define keyspan_usa49wg_product_id 0x0131 - -struct keyspan_device_details { - /* product ID value */ - int product_id; - - enum {msg_usa26, msg_usa28, msg_usa49, msg_usa90, msg_usa67} msg_format; - - /* Number of physical ports */ - int num_ports; - - /* 1 if endpoint flipping used on input, 0 if not */ - int indat_endp_flip; - - /* 1 if endpoint flipping used on output, 0 if not */ - int outdat_endp_flip; - - /* Table mapping input data endpoint IDs to physical - port number and flip if used */ - int indat_endpoints[KEYSPAN_MAX_NUM_PORTS]; - - /* Same for output endpoints */ - int outdat_endpoints[KEYSPAN_MAX_NUM_PORTS]; - - /* Input acknowledge endpoints */ - int inack_endpoints[KEYSPAN_MAX_NUM_PORTS]; - - /* Output control endpoints */ - int outcont_endpoints[KEYSPAN_MAX_NUM_PORTS]; - - /* Endpoint used for input status */ - int instat_endpoint; - - /* Endpoint used for input data 49WG only */ - int indat_endpoint; - - /* Endpoint used for global control functions */ - int glocont_endpoint; - - int (*calculate_baud_rate) (u32 baud_rate, u32 baudclk, - u8 *rate_hi, u8 *rate_low, u8 *prescaler, int portnum); - u32 baudclk; -}; - -/* Now for each device type we setup the device detail - structure with the appropriate information (provided - in Keyspan's documentation) */ - -static const struct keyspan_device_details usa18x_device_details = { - .product_id = keyspan_usa18x_product_id, - .msg_format = msg_usa26, - .num_ports = 1, - .indat_endp_flip = 0, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81}, - .outdat_endpoints = {0x01}, - .inack_endpoints = {0x85}, - .outcont_endpoints = {0x05}, - .instat_endpoint = 0x87, - .indat_endpoint = -1, - .glocont_endpoint = 0x07, - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA18X_BAUDCLK, -}; - -static const struct keyspan_device_details usa19_device_details = { - .product_id = keyspan_usa19_product_id, - .msg_format = msg_usa28, - .num_ports = 1, - .indat_endp_flip = 1, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81}, - .outdat_endpoints = {0x01}, - .inack_endpoints = {0x83}, - .outcont_endpoints = {0x03}, - .instat_endpoint = 0x84, - .indat_endpoint = -1, - .glocont_endpoint = -1, - .calculate_baud_rate = keyspan_usa19_calc_baud, - .baudclk = KEYSPAN_USA19_BAUDCLK, -}; - -static const struct keyspan_device_details usa19qi_device_details = { - .product_id = keyspan_usa19qi_product_id, - .msg_format = msg_usa28, - .num_ports = 1, - .indat_endp_flip = 1, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81}, - .outdat_endpoints = {0x01}, - .inack_endpoints = {0x83}, - .outcont_endpoints = {0x03}, - .instat_endpoint = 0x84, - .indat_endpoint = -1, - .glocont_endpoint = -1, - .calculate_baud_rate = keyspan_usa28_calc_baud, - .baudclk = KEYSPAN_USA19_BAUDCLK, -}; - -static const struct keyspan_device_details mpr_device_details = { - .product_id = keyspan_mpr_product_id, - .msg_format = msg_usa28, - .num_ports = 1, - .indat_endp_flip = 1, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81}, - .outdat_endpoints = {0x01}, - .inack_endpoints = {0x83}, - .outcont_endpoints = {0x03}, - .instat_endpoint = 0x84, - .indat_endpoint = -1, - .glocont_endpoint = -1, - .calculate_baud_rate = keyspan_usa28_calc_baud, - .baudclk = KEYSPAN_USA19_BAUDCLK, -}; - -static const struct keyspan_device_details usa19qw_device_details = { - .product_id = keyspan_usa19qw_product_id, - .msg_format = msg_usa26, - .num_ports = 1, - .indat_endp_flip = 0, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81}, - .outdat_endpoints = {0x01}, - .inack_endpoints = {0x85}, - .outcont_endpoints = {0x05}, - .instat_endpoint = 0x87, - .indat_endpoint = -1, - .glocont_endpoint = 0x07, - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA19W_BAUDCLK, -}; - -static const struct keyspan_device_details usa19w_device_details = { - .product_id = keyspan_usa19w_product_id, - .msg_format = msg_usa26, - .num_ports = 1, - .indat_endp_flip = 0, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81}, - .outdat_endpoints = {0x01}, - .inack_endpoints = {0x85}, - .outcont_endpoints = {0x05}, - .instat_endpoint = 0x87, - .indat_endpoint = -1, - .glocont_endpoint = 0x07, - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA19W_BAUDCLK, -}; - -static const struct keyspan_device_details usa19hs_device_details = { - .product_id = keyspan_usa19hs_product_id, - .msg_format = msg_usa90, - .num_ports = 1, - .indat_endp_flip = 0, - .outdat_endp_flip = 0, - .indat_endpoints = {0x81}, - .outdat_endpoints = {0x01}, - .inack_endpoints = {-1}, - .outcont_endpoints = {0x02}, - .instat_endpoint = 0x82, - .indat_endpoint = -1, - .glocont_endpoint = -1, - .calculate_baud_rate = keyspan_usa19hs_calc_baud, - .baudclk = KEYSPAN_USA19HS_BAUDCLK, -}; - -static const struct keyspan_device_details usa28_device_details = { - .product_id = keyspan_usa28_product_id, - .msg_format = msg_usa28, - .num_ports = 2, - .indat_endp_flip = 1, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81, 0x83}, - .outdat_endpoints = {0x01, 0x03}, - .inack_endpoints = {0x85, 0x86}, - .outcont_endpoints = {0x05, 0x06}, - .instat_endpoint = 0x87, - .indat_endpoint = -1, - .glocont_endpoint = 0x07, - .calculate_baud_rate = keyspan_usa28_calc_baud, - .baudclk = KEYSPAN_USA28_BAUDCLK, -}; - -static const struct keyspan_device_details usa28x_device_details = { - .product_id = keyspan_usa28x_product_id, - .msg_format = msg_usa26, - .num_ports = 2, - .indat_endp_flip = 0, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81, 0x83}, - .outdat_endpoints = {0x01, 0x03}, - .inack_endpoints = {0x85, 0x86}, - .outcont_endpoints = {0x05, 0x06}, - .instat_endpoint = 0x87, - .indat_endpoint = -1, - .glocont_endpoint = 0x07, - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA28X_BAUDCLK, -}; - -static const struct keyspan_device_details usa28xa_device_details = { - .product_id = keyspan_usa28xa_product_id, - .msg_format = msg_usa26, - .num_ports = 2, - .indat_endp_flip = 0, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81, 0x83}, - .outdat_endpoints = {0x01, 0x03}, - .inack_endpoints = {0x85, 0x86}, - .outcont_endpoints = {0x05, 0x06}, - .instat_endpoint = 0x87, - .indat_endpoint = -1, - .glocont_endpoint = 0x07, - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA28X_BAUDCLK, -}; - -static const struct keyspan_device_details usa28xg_device_details = { - .product_id = keyspan_usa28xg_product_id, - .msg_format = msg_usa67, - .num_ports = 2, - .indat_endp_flip = 0, - .outdat_endp_flip = 0, - .indat_endpoints = {0x84, 0x88}, - .outdat_endpoints = {0x02, 0x06}, - .inack_endpoints = {-1, -1}, - .outcont_endpoints = {-1, -1}, - .instat_endpoint = 0x81, - .indat_endpoint = -1, - .glocont_endpoint = 0x01, - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA28X_BAUDCLK, -}; -/* We don't need a separate entry for the usa28xb as it appears as a 28x anyway */ - -static const struct keyspan_device_details usa49w_device_details = { - .product_id = keyspan_usa49w_product_id, - .msg_format = msg_usa49, - .num_ports = 4, - .indat_endp_flip = 0, - .outdat_endp_flip = 0, - .indat_endpoints = {0x81, 0x82, 0x83, 0x84}, - .outdat_endpoints = {0x01, 0x02, 0x03, 0x04}, - .inack_endpoints = {-1, -1, -1, -1}, - .outcont_endpoints = {-1, -1, -1, -1}, - .instat_endpoint = 0x87, - .indat_endpoint = -1, - .glocont_endpoint = 0x07, - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA49W_BAUDCLK, -}; - -static const struct keyspan_device_details usa49wlc_device_details = { - .product_id = keyspan_usa49wlc_product_id, - .msg_format = msg_usa49, - .num_ports = 4, - .indat_endp_flip = 0, - .outdat_endp_flip = 0, - .indat_endpoints = {0x81, 0x82, 0x83, 0x84}, - .outdat_endpoints = {0x01, 0x02, 0x03, 0x04}, - .inack_endpoints = {-1, -1, -1, -1}, - .outcont_endpoints = {-1, -1, -1, -1}, - .instat_endpoint = 0x87, - .indat_endpoint = -1, - .glocont_endpoint = 0x07, - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA19W_BAUDCLK, -}; - -static const struct keyspan_device_details usa49wg_device_details = { - .product_id = keyspan_usa49wg_product_id, - .msg_format = msg_usa49, - .num_ports = 4, - .indat_endp_flip = 0, - .outdat_endp_flip = 0, - .indat_endpoints = {-1, -1, -1, -1}, /* single 'global' data in EP */ - .outdat_endpoints = {0x01, 0x02, 0x04, 0x06}, - .inack_endpoints = {-1, -1, -1, -1}, - .outcont_endpoints = {-1, -1, -1, -1}, - .instat_endpoint = 0x81, - .indat_endpoint = 0x88, - .glocont_endpoint = 0x00, /* uses control EP */ - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA19W_BAUDCLK, -}; - -static const struct keyspan_device_details *keyspan_devices[] = { - &usa18x_device_details, - &usa19_device_details, - &usa19qi_device_details, - &mpr_device_details, - &usa19qw_device_details, - &usa19w_device_details, - &usa19hs_device_details, - &usa28_device_details, - &usa28x_device_details, - &usa28xa_device_details, - &usa28xg_device_details, - /* 28xb not required as it renumerates as a 28x */ - &usa49w_device_details, - &usa49wlc_device_details, - &usa49wg_device_details, - NULL, -}; - -static const struct usb_device_id keyspan_ids_combined[] = { - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19hs_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xg_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id)}, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)}, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wg_product_id)}, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, keyspan_ids_combined); - -static struct usb_driver keyspan_driver = { - .name = "keyspan", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = keyspan_ids_combined, -}; - -/* usb_device_id table for the pre-firmware download keyspan devices */ -static const struct usb_device_id keyspan_pre_ids[] = { - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_pre_product_id) }, - { } /* Terminating entry */ -}; - -static const struct usb_device_id keyspan_1port_ids[] = { - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19hs_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_product_id) }, - { } /* Terminating entry */ -}; - -static const struct usb_device_id keyspan_2port_ids[] = { - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xg_product_id) }, - { } /* Terminating entry */ -}; - -static const struct usb_device_id keyspan_4port_ids[] = { - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)}, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wg_product_id)}, - { } /* Terminating entry */ -}; - -/* Structs for the devices, pre and post renumeration. */ -static struct usb_serial_driver keyspan_pre_device = { - .driver = { - .owner = THIS_MODULE, - .name = "keyspan_no_firm", - }, - .description = "Keyspan - (without firmware)", - .id_table = keyspan_pre_ids, - .num_ports = 1, - .attach = keyspan_fake_startup, -}; - -static struct usb_serial_driver keyspan_1port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "keyspan_1", - }, - .description = "Keyspan 1 port adapter", - .id_table = keyspan_1port_ids, - .num_ports = 1, - .open = keyspan_open, - .close = keyspan_close, - .dtr_rts = keyspan_dtr_rts, - .write = keyspan_write, - .write_room = keyspan_write_room, - .set_termios = keyspan_set_termios, - .break_ctl = keyspan_break_ctl, - .tiocmget = keyspan_tiocmget, - .tiocmset = keyspan_tiocmset, - .attach = keyspan_startup, - .disconnect = keyspan_disconnect, - .release = keyspan_release, -}; - -static struct usb_serial_driver keyspan_2port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "keyspan_2", - }, - .description = "Keyspan 2 port adapter", - .id_table = keyspan_2port_ids, - .num_ports = 2, - .open = keyspan_open, - .close = keyspan_close, - .dtr_rts = keyspan_dtr_rts, - .write = keyspan_write, - .write_room = keyspan_write_room, - .set_termios = keyspan_set_termios, - .break_ctl = keyspan_break_ctl, - .tiocmget = keyspan_tiocmget, - .tiocmset = keyspan_tiocmset, - .attach = keyspan_startup, - .disconnect = keyspan_disconnect, - .release = keyspan_release, -}; - -static struct usb_serial_driver keyspan_4port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "keyspan_4", - }, - .description = "Keyspan 4 port adapter", - .id_table = keyspan_4port_ids, - .num_ports = 4, - .open = keyspan_open, - .close = keyspan_close, - .dtr_rts = keyspan_dtr_rts, - .write = keyspan_write, - .write_room = keyspan_write_room, - .set_termios = keyspan_set_termios, - .break_ctl = keyspan_break_ctl, - .tiocmget = keyspan_tiocmget, - .tiocmset = keyspan_tiocmset, - .attach = keyspan_startup, - .disconnect = keyspan_disconnect, - .release = keyspan_release, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &keyspan_pre_device, &keyspan_1port_device, - &keyspan_2port_device, &keyspan_4port_device, NULL -}; - -#endif diff --git a/ANDROID_3.4.5/drivers/usb/serial/keyspan_pda.c b/ANDROID_3.4.5/drivers/usb/serial/keyspan_pda.c deleted file mode 100644 index 693bcdfc..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/keyspan_pda.c +++ /dev/null @@ -1,844 +0,0 @@ -/* - * USB Keyspan PDA / Xircom / Entregra Converter driver - * - * Copyright (C) 1999 - 2001 Greg Kroah-Hartman - * Copyright (C) 1999, 2000 Brian Warner - * Copyright (C) 2000 Al Borchers - * - * 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. - * - * See Documentation/usb/usb-serial.txt for more information on using this - * driver - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static bool debug; - -/* make a simple define to handle if we are compiling keyspan_pda or xircom support */ -#if defined(CONFIG_USB_SERIAL_KEYSPAN_PDA) || defined(CONFIG_USB_SERIAL_KEYSPAN_PDA_MODULE) - #define KEYSPAN -#else - #undef KEYSPAN -#endif -#if defined(CONFIG_USB_SERIAL_XIRCOM) || defined(CONFIG_USB_SERIAL_XIRCOM_MODULE) - #define XIRCOM -#else - #undef XIRCOM -#endif - -/* - * Version Information - */ -#define DRIVER_VERSION "v1.1" -#define DRIVER_AUTHOR "Brian Warner " -#define DRIVER_DESC "USB Keyspan PDA Converter driver" - -struct keyspan_pda_private { - int tx_room; - int tx_throttled; - struct work_struct wakeup_work; - struct work_struct unthrottle_work; - struct usb_serial *serial; - struct usb_serial_port *port; -}; - - -#define KEYSPAN_VENDOR_ID 0x06cd -#define KEYSPAN_PDA_FAKE_ID 0x0103 -#define KEYSPAN_PDA_ID 0x0104 /* no clue */ - -/* For Xircom PGSDB9 and older Entregra version of the same device */ -#define XIRCOM_VENDOR_ID 0x085a -#define XIRCOM_FAKE_ID 0x8027 -#define ENTREGRA_VENDOR_ID 0x1645 -#define ENTREGRA_FAKE_ID 0x8093 - -static const struct usb_device_id id_table_combined[] = { -#ifdef KEYSPAN - { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_FAKE_ID) }, -#endif -#ifdef XIRCOM - { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) }, - { USB_DEVICE(ENTREGRA_VENDOR_ID, ENTREGRA_FAKE_ID) }, -#endif - { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, id_table_combined); - -static struct usb_driver keyspan_pda_driver = { - .name = "keyspan_pda", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; - -static const struct usb_device_id id_table_std[] = { - { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) }, - { } /* Terminating entry */ -}; - -#ifdef KEYSPAN -static const struct usb_device_id id_table_fake[] = { - { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_FAKE_ID) }, - { } /* Terminating entry */ -}; -#endif - -#ifdef XIRCOM -static const struct usb_device_id id_table_fake_xircom[] = { - { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) }, - { USB_DEVICE(ENTREGRA_VENDOR_ID, ENTREGRA_FAKE_ID) }, - { } -}; -#endif - -static void keyspan_pda_wakeup_write(struct work_struct *work) -{ - struct keyspan_pda_private *priv = - container_of(work, struct keyspan_pda_private, wakeup_work); - struct usb_serial_port *port = priv->port; - struct tty_struct *tty = tty_port_tty_get(&port->port); - if (tty) - tty_wakeup(tty); - tty_kref_put(tty); -} - -static void keyspan_pda_request_unthrottle(struct work_struct *work) -{ - struct keyspan_pda_private *priv = - container_of(work, struct keyspan_pda_private, unthrottle_work); - struct usb_serial *serial = priv->serial; - int result; - - dbg(" request_unthrottle"); - /* ask the device to tell us when the tx buffer becomes - sufficiently empty */ - result = usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - 7, /* request_unthrottle */ - USB_TYPE_VENDOR | USB_RECIP_INTERFACE - | USB_DIR_OUT, - 16, /* value: threshold */ - 0, /* index */ - NULL, - 0, - 2000); - if (result < 0) - dbg("%s - error %d from usb_control_msg", - __func__, result); -} - - -static void keyspan_pda_rx_interrupt(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - int retval; - int status = urb->status; - struct keyspan_pda_private *priv; - priv = usb_get_serial_port_data(port); - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); - return; - default: - dbg("%s - nonzero urb status received: %d", - __func__, status); - goto exit; - } - - /* see if the message is data or a status interrupt */ - switch (data[0]) { - case 0: - tty = tty_port_tty_get(&port->port); - /* rest of message is rx data */ - if (tty && urb->actual_length) { - tty_insert_flip_string(tty, data + 1, - urb->actual_length - 1); - tty_flip_buffer_push(tty); - } - tty_kref_put(tty); - break; - case 1: - /* status interrupt */ - dbg(" rx int, d1=%d, d2=%d", data[1], data[2]); - switch (data[1]) { - case 1: /* modemline change */ - break; - case 2: /* tx unthrottle interrupt */ - priv->tx_throttled = 0; - /* queue up a wakeup at scheduler time */ - schedule_work(&priv->wakeup_work); - break; - default: - break; - } - break; - default: - break; - } - -exit: - retval = usb_submit_urb(urb, GFP_ATOMIC); - if (retval) - dev_err(&port->dev, - "%s - usb_submit_urb failed with result %d", - __func__, retval); -} - - -static void keyspan_pda_rx_throttle(struct tty_struct *tty) -{ - /* stop receiving characters. We just turn off the URB request, and - let chars pile up in the device. If we're doing hardware - flowcontrol, the device will signal the other end when its buffer - fills up. If we're doing XON/XOFF, this would be a good time to - send an XOFF, although it might make sense to foist that off - upon the device too. */ - struct usb_serial_port *port = tty->driver_data; - dbg("keyspan_pda_rx_throttle port %d", port->number); - usb_kill_urb(port->interrupt_in_urb); -} - - -static void keyspan_pda_rx_unthrottle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - /* just restart the receive interrupt URB */ - dbg("keyspan_pda_rx_unthrottle port %d", port->number); - if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL)) - dbg(" usb_submit_urb(read urb) failed"); -} - - -static speed_t keyspan_pda_setbaud(struct usb_serial *serial, speed_t baud) -{ - int rc; - int bindex; - - switch (baud) { - case 110: - bindex = 0; - break; - case 300: - bindex = 1; - break; - case 1200: - bindex = 2; - break; - case 2400: - bindex = 3; - break; - case 4800: - bindex = 4; - break; - case 9600: - bindex = 5; - break; - case 19200: - bindex = 6; - break; - case 38400: - bindex = 7; - break; - case 57600: - bindex = 8; - break; - case 115200: - bindex = 9; - break; - default: - bindex = 5; /* Default to 9600 */ - baud = 9600; - } - - /* rather than figure out how to sleep while waiting for this - to complete, I just use the "legacy" API. */ - rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - 0, /* set baud */ - USB_TYPE_VENDOR - | USB_RECIP_INTERFACE - | USB_DIR_OUT, /* type */ - bindex, /* value */ - 0, /* index */ - NULL, /* &data */ - 0, /* size */ - 2000); /* timeout */ - if (rc < 0) - return 0; - return baud; -} - - -static void keyspan_pda_break_ctl(struct tty_struct *tty, int break_state) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; - int value; - int result; - - if (break_state == -1) - value = 1; /* start break */ - else - value = 0; /* clear break */ - result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - 4, /* set break */ - USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT, - value, 0, NULL, 0, 2000); - if (result < 0) - dbg("%s - error %d from usb_control_msg", - __func__, result); - /* there is something funky about this.. the TCSBRK that 'cu' performs - ought to translate into a break_ctl(-1),break_ctl(0) pair HZ/4 - seconds apart, but it feels like the break sent isn't as long as it - is on /dev/ttyS0 */ -} - - -static void keyspan_pda_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) -{ - struct usb_serial *serial = port->serial; - speed_t speed; - - /* cflag specifies lots of stuff: number of stop bits, parity, number - of data bits, baud. What can the device actually handle?: - CSTOPB (1 stop bit or 2) - PARENB (parity) - CSIZE (5bit .. 8bit) - There is minimal hw support for parity (a PSW bit seems to hold the - parity of whatever is in the accumulator). The UART either deals - with 10 bits (start, 8 data, stop) or 11 bits (start, 8 data, - 1 special, stop). So, with firmware changes, we could do: - 8N1: 10 bit - 8N2: 11 bit, extra bit always (mark?) - 8[EOMS]1: 11 bit, extra bit is parity - 7[EOMS]1: 10 bit, b0/b7 is parity - 7[EOMS]2: 11 bit, b0/b7 is parity, extra bit always (mark?) - - HW flow control is dictated by the tty->termios->c_cflags & CRTSCTS - bit. - - For now, just do baud. */ - - speed = tty_get_baud_rate(tty); - speed = keyspan_pda_setbaud(serial, speed); - - if (speed == 0) { - dbg("can't handle requested baud rate"); - /* It hasn't changed so.. */ - speed = tty_termios_baud_rate(old_termios); - } - /* Only speed can change so copy the old h/w parameters - then encode the new speed */ - tty_termios_copy_hw(tty->termios, old_termios); - tty_encode_baud_rate(tty, speed, speed); -} - - -/* modem control pins: DTR and RTS are outputs and can be controlled. - DCD, RI, DSR, CTS are inputs and can be read. All outputs can also be - read. The byte passed is: DTR(b7) DCD RI DSR CTS RTS(b2) unused unused */ - -static int keyspan_pda_get_modem_info(struct usb_serial *serial, - unsigned char *value) -{ - int rc; - u8 *data; - - data = kmalloc(1, GFP_KERNEL); - if (!data) - return -ENOMEM; - - rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - 3, /* get pins */ - USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_IN, - 0, 0, data, 1, 2000); - if (rc >= 0) - *value = *data; - - kfree(data); - return rc; -} - - -static int keyspan_pda_set_modem_info(struct usb_serial *serial, - unsigned char value) -{ - int rc; - rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - 3, /* set pins */ - USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_OUT, - value, 0, NULL, 0, 2000); - return rc; -} - -static int keyspan_pda_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; - int rc; - unsigned char status; - int value; - - rc = keyspan_pda_get_modem_info(serial, &status); - if (rc < 0) - return rc; - value = - ((status & (1<<7)) ? TIOCM_DTR : 0) | - ((status & (1<<6)) ? TIOCM_CAR : 0) | - ((status & (1<<5)) ? TIOCM_RNG : 0) | - ((status & (1<<4)) ? TIOCM_DSR : 0) | - ((status & (1<<3)) ? TIOCM_CTS : 0) | - ((status & (1<<2)) ? TIOCM_RTS : 0); - return value; -} - -static int keyspan_pda_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; - int rc; - unsigned char status; - - rc = keyspan_pda_get_modem_info(serial, &status); - if (rc < 0) - return rc; - - if (set & TIOCM_RTS) - status |= (1<<2); - if (set & TIOCM_DTR) - status |= (1<<7); - - if (clear & TIOCM_RTS) - status &= ~(1<<2); - if (clear & TIOCM_DTR) - status &= ~(1<<7); - rc = keyspan_pda_set_modem_info(serial, status); - return rc; -} - -static int keyspan_pda_write(struct tty_struct *tty, - struct usb_serial_port *port, const unsigned char *buf, int count) -{ - struct usb_serial *serial = port->serial; - int request_unthrottle = 0; - int rc = 0; - struct keyspan_pda_private *priv; - - priv = usb_get_serial_port_data(port); - /* guess how much room is left in the device's ring buffer, and if we - want to send more than that, check first, updating our notion of - what is left. If our write will result in no room left, ask the - device to give us an interrupt when the room available rises above - a threshold, and hold off all writers (eventually, those using - select() or poll() too) until we receive that unthrottle interrupt. - Block if we can't write anything at all, otherwise write as much as - we can. */ - dbg("keyspan_pda_write(%d)", count); - if (count == 0) { - dbg(" write request of 0 bytes"); - return 0; - } - - /* we might block because of: - the TX urb is in-flight (wait until it completes) - the device is full (wait until it says there is room) - */ - spin_lock_bh(&port->lock); - if (!test_bit(0, &port->write_urbs_free) || priv->tx_throttled) { - spin_unlock_bh(&port->lock); - return 0; - } - clear_bit(0, &port->write_urbs_free); - spin_unlock_bh(&port->lock); - - /* At this point the URB is in our control, nobody else can submit it - again (the only sudden transition was the one from EINPROGRESS to - finished). Also, the tx process is not throttled. So we are - ready to write. */ - - count = (count > port->bulk_out_size) ? port->bulk_out_size : count; - - /* Check if we might overrun the Tx buffer. If so, ask the - device how much room it really has. This is done only on - scheduler time, since usb_control_msg() sleeps. */ - if (count > priv->tx_room && !in_interrupt()) { - u8 *room; - - room = kmalloc(1, GFP_KERNEL); - if (!room) { - rc = -ENOMEM; - goto exit; - } - - rc = usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), - 6, /* write_room */ - USB_TYPE_VENDOR | USB_RECIP_INTERFACE - | USB_DIR_IN, - 0, /* value: 0 means "remaining room" */ - 0, /* index */ - room, - 1, - 2000); - if (rc > 0) { - dbg(" roomquery says %d", *room); - priv->tx_room = *room; - } - kfree(room); - if (rc < 0) { - dbg(" roomquery failed"); - goto exit; - } - if (rc == 0) { - dbg(" roomquery returned 0 bytes"); - rc = -EIO; /* device didn't return any data */ - goto exit; - } - } - if (count > priv->tx_room) { - /* we're about to completely fill the Tx buffer, so - we'll be throttled afterwards. */ - count = priv->tx_room; - request_unthrottle = 1; - } - - if (count) { - /* now transfer data */ - memcpy(port->write_urb->transfer_buffer, buf, count); - /* send the data out the bulk port */ - port->write_urb->transfer_buffer_length = count; - - priv->tx_room -= count; - - rc = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (rc) { - dbg(" usb_submit_urb(write bulk) failed"); - goto exit; - } - } else { - /* There wasn't any room left, so we are throttled until - the buffer empties a bit */ - request_unthrottle = 1; - } - - if (request_unthrottle) { - priv->tx_throttled = 1; /* block writers */ - schedule_work(&priv->unthrottle_work); - } - - rc = count; -exit: - if (rc < 0) - set_bit(0, &port->write_urbs_free); - return rc; -} - - -static void keyspan_pda_write_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct keyspan_pda_private *priv; - - set_bit(0, &port->write_urbs_free); - priv = usb_get_serial_port_data(port); - - /* queue up a wakeup at scheduler time */ - schedule_work(&priv->wakeup_work); -} - - -static int keyspan_pda_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct keyspan_pda_private *priv; - priv = usb_get_serial_port_data(port); - /* used by n_tty.c for processing of tabs and such. Giving it our - conservative guess is probably good enough, but needs testing by - running a console through the device. */ - return priv->tx_room; -} - - -static int keyspan_pda_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct keyspan_pda_private *priv; - unsigned long flags; - int ret = 0; - - priv = usb_get_serial_port_data(port); - - /* when throttled, return at least WAKEUP_CHARS to tell select() (via - n_tty.c:normal_poll() ) that we're not writeable. */ - - spin_lock_irqsave(&port->lock, flags); - if (!test_bit(0, &port->write_urbs_free) || priv->tx_throttled) - ret = 256; - spin_unlock_irqrestore(&port->lock, flags); - return ret; -} - - -static void keyspan_pda_dtr_rts(struct usb_serial_port *port, int on) -{ - struct usb_serial *serial = port->serial; - - if (serial->dev) { - if (on) - keyspan_pda_set_modem_info(serial, (1<<7) | (1<< 2)); - else - keyspan_pda_set_modem_info(serial, 0); - } -} - - -static int keyspan_pda_open(struct tty_struct *tty, - struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - u8 *room; - int rc = 0; - struct keyspan_pda_private *priv; - - /* find out how much room is in the Tx ring */ - room = kmalloc(1, GFP_KERNEL); - if (!room) - return -ENOMEM; - - rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - 6, /* write_room */ - USB_TYPE_VENDOR | USB_RECIP_INTERFACE - | USB_DIR_IN, - 0, /* value */ - 0, /* index */ - room, - 1, - 2000); - if (rc < 0) { - dbg("%s - roomquery failed", __func__); - goto error; - } - if (rc == 0) { - dbg("%s - roomquery returned 0 bytes", __func__); - rc = -EIO; - goto error; - } - priv = usb_get_serial_port_data(port); - priv->tx_room = *room; - priv->tx_throttled = *room ? 0 : 1; - - /*Start reading from the device*/ - rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - if (rc) { - dbg("%s - usb_submit_urb(read int) failed", __func__); - goto error; - } -error: - kfree(room); - return rc; -} -static void keyspan_pda_close(struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - - if (serial->dev) { - /* shutdown our bulk reads and writes */ - usb_kill_urb(port->write_urb); - usb_kill_urb(port->interrupt_in_urb); - } -} - - -/* download the firmware to a "fake" device (pre-renumeration) */ -static int keyspan_pda_fake_startup(struct usb_serial *serial) -{ - int response; - const char *fw_name; - const struct ihex_binrec *record; - const struct firmware *fw; - - /* download the firmware here ... */ - response = ezusb_set_reset(serial, 1); - - if (0) { ; } -#ifdef KEYSPAN - else if (le16_to_cpu(serial->dev->descriptor.idVendor) == KEYSPAN_VENDOR_ID) - fw_name = "keyspan_pda/keyspan_pda.fw"; -#endif -#ifdef XIRCOM - else if ((le16_to_cpu(serial->dev->descriptor.idVendor) == XIRCOM_VENDOR_ID) || - (le16_to_cpu(serial->dev->descriptor.idVendor) == ENTREGRA_VENDOR_ID)) - fw_name = "keyspan_pda/xircom_pgs.fw"; -#endif - else { - dev_err(&serial->dev->dev, "%s: unknown vendor, aborting.\n", - __func__); - return -ENODEV; - } - if (request_ihex_firmware(&fw, fw_name, &serial->dev->dev)) { - dev_err(&serial->dev->dev, "failed to load firmware \"%s\"\n", - fw_name); - return -ENOENT; - } - record = (const struct ihex_binrec *)fw->data; - - while (record) { - response = ezusb_writememory(serial, be32_to_cpu(record->addr), - (unsigned char *)record->data, - be16_to_cpu(record->len), 0xa0); - if (response < 0) { - dev_err(&serial->dev->dev, "ezusb_writememory failed " - "for Keyspan PDA firmware (%d %04X %p %d)\n", - response, be32_to_cpu(record->addr), - record->data, be16_to_cpu(record->len)); - break; - } - record = ihex_next_binrec(record); - } - release_firmware(fw); - /* bring device out of reset. Renumeration will occur in a moment - and the new device will bind to the real driver */ - response = ezusb_set_reset(serial, 0); - - /* we want this device to fail to have a driver assigned to it. */ - return 1; -} - -#ifdef KEYSPAN -MODULE_FIRMWARE("keyspan_pda/keyspan_pda.fw"); -#endif -#ifdef XIRCOM -MODULE_FIRMWARE("keyspan_pda/xircom_pgs.fw"); -#endif - -static int keyspan_pda_startup(struct usb_serial *serial) -{ - - struct keyspan_pda_private *priv; - - /* allocate the private data structures for all ports. Well, for all - one ports. */ - - priv = kmalloc(sizeof(struct keyspan_pda_private), GFP_KERNEL); - if (!priv) - return 1; /* error */ - usb_set_serial_port_data(serial->port[0], priv); - init_waitqueue_head(&serial->port[0]->write_wait); - INIT_WORK(&priv->wakeup_work, keyspan_pda_wakeup_write); - INIT_WORK(&priv->unthrottle_work, keyspan_pda_request_unthrottle); - priv->serial = serial; - priv->port = serial->port[0]; - return 0; -} - -static void keyspan_pda_release(struct usb_serial *serial) -{ - dbg("%s", __func__); - - kfree(usb_get_serial_port_data(serial->port[0])); -} - -#ifdef KEYSPAN -static struct usb_serial_driver keyspan_pda_fake_device = { - .driver = { - .owner = THIS_MODULE, - .name = "keyspan_pda_pre", - }, - .description = "Keyspan PDA - (prerenumeration)", - .id_table = id_table_fake, - .num_ports = 1, - .attach = keyspan_pda_fake_startup, -}; -#endif - -#ifdef XIRCOM -static struct usb_serial_driver xircom_pgs_fake_device = { - .driver = { - .owner = THIS_MODULE, - .name = "xircom_no_firm", - }, - .description = "Xircom / Entregra PGS - (prerenumeration)", - .id_table = id_table_fake_xircom, - .num_ports = 1, - .attach = keyspan_pda_fake_startup, -}; -#endif - -static struct usb_serial_driver keyspan_pda_device = { - .driver = { - .owner = THIS_MODULE, - .name = "keyspan_pda", - }, - .description = "Keyspan PDA", - .id_table = id_table_std, - .num_ports = 1, - .dtr_rts = keyspan_pda_dtr_rts, - .open = keyspan_pda_open, - .close = keyspan_pda_close, - .write = keyspan_pda_write, - .write_room = keyspan_pda_write_room, - .write_bulk_callback = keyspan_pda_write_bulk_callback, - .read_int_callback = keyspan_pda_rx_interrupt, - .chars_in_buffer = keyspan_pda_chars_in_buffer, - .throttle = keyspan_pda_rx_throttle, - .unthrottle = keyspan_pda_rx_unthrottle, - .set_termios = keyspan_pda_set_termios, - .break_ctl = keyspan_pda_break_ctl, - .tiocmget = keyspan_pda_tiocmget, - .tiocmset = keyspan_pda_tiocmset, - .attach = keyspan_pda_startup, - .release = keyspan_pda_release, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &keyspan_pda_device, -#ifdef KEYSPAN - &keyspan_pda_fake_device, -#endif -#ifdef XIRCOM - &xircom_pgs_fake_device, -#endif - NULL -}; - -module_usb_serial_driver(keyspan_pda_driver, serial_drivers); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/keyspan_usa26msg.h b/ANDROID_3.4.5/drivers/usb/serial/keyspan_usa26msg.h deleted file mode 100644 index 3808727d..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/keyspan_usa26msg.h +++ /dev/null @@ -1,260 +0,0 @@ -/* - usa26msg.h - - Copyright (C) 1998-2000 InnoSys Incorporated. All Rights Reserved - This file is available under a BSD-style copyright - - Keyspan USB Async Message Formats for the USA28X - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - 1. Redistributions of source code must retain this licence text - without modification, this list of conditions, and the following - disclaimer. The following copyright notice must appear immediately at - the beginning of all source files: - - Copyright (C) 1998-2000 InnoSys Incorporated. All Rights Reserved - - This file is available under a BSD-style copyright - - 2. The name of InnoSys Incorporated may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY INNOSYS CORP. ``AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - - Third revision: USA28X version (aka USA26) - - Buffer formats for RX/TX data messages are not defined by - a structure, but are described here: - - USB OUT (host -> USAxx, transmit) messages contain a - REQUEST_ACK indicator (set to 0xff to request an ACK at the - completion of transmit; 0x00 otherwise), followed by data: - - RQSTACK DAT DAT DAT ... - - with a total data length of 63. - - USB IN (USAxx -> host, receive) messages begin with a status - byte in which the 0x80 bit is either: - - (a) 0x80 bit clear - indicates that the bytes following it are all data - bytes: - - STAT DATA DATA DATA DATA DATA ... - - for a total of up to 63 DATA bytes, - - or: - - (b) 0x80 bit set - indiates that the bytes following alternate data and - status bytes: - - STAT DATA STAT DATA STAT DATA STAT DATA ... - - for a total of up to 32 DATA bytes. - - The valid bits in the STAT bytes are: - - OVERRUN 0x02 - PARITY 0x04 - FRAMING 0x08 - BREAK 0x10 - - Notes: - - (1) The OVERRUN bit can appear in either (a) or (b) format - messages, but the but the PARITY/FRAMING/BREAK bits - only appear in (b) format messages. - (2) For the host to determine the exact point at which the - overrun occurred (to identify the point in the data - stream at which the data was lost), it needs to count - 128 characters, starting at the first character of the - message in which OVERRUN was reported; the lost character(s) - would have been received between the 128th and 129th - characters. - (3) An RX data message in which the first byte has 0x80 clear - serves as a "break off" indicator. - - revision history: - - 1999feb10 add reportHskiaChanges to allow us to ignore them - 1999feb10 add txAckThreshold for fast+loose throughput enhancement - 1999mar30 beef up support for RX error reporting - 1999apr14 add resetDataToggle to control message - 2000jan04 merge with usa17msg.h - 2000jun01 add extended BSD-style copyright text - 2001jul05 change message format to improve OVERRUN case - - Note on shared names: - - In the case of fields which have been merged between the USA17 - and USA26 definitions, the USA26 definition is the first part - of the name and the USA17 definition is the second part of the - name; both meanings are described below. -*/ - -#ifndef __USA26MSG__ -#define __USA26MSG__ - - -struct keyspan_usa26_portControlMessage -{ - /* - there are three types of "commands" sent in the control message: - - 1. configuration changes which must be requested by setting - the corresponding "set" flag (and should only be requested - when necessary, to reduce overhead on the USA26): - */ - u8 setClocking, // BOTH: host requests baud rate be set - baudLo, // BOTH: host does baud divisor calculation - baudHi, // BOTH: baudHi is only used for first port (gives lower rates) - externalClock_txClocking, - // USA26: 0=internal, other=external - // USA17: 0=internal, other=external/RI - rxClocking, // USA17: 0=internal, 1=external/RI, other=external/DSR - - - setLcr, // BOTH: host requests lcr be set - lcr, // BOTH: use PARITY, STOPBITS, DATABITS below - - setFlowControl, // BOTH: host requests flow control be set - ctsFlowControl, // BOTH: 1=use CTS flow control, 0=don't - xonFlowControl, // BOTH: 1=use XON/XOFF flow control, 0=don't - xonChar, // BOTH: specified in current character format - xoffChar, // BOTH: specified in current character format - - setTxTriState_setRts, - // USA26: host requests TX tri-state be set - // USA17: host requests RTS output be set - txTriState_rts, // BOTH: 1=active (normal), 0=tristate (off) - - setHskoa_setDtr, - // USA26: host requests HSKOA output be set - // USA17: host requests DTR output be set - hskoa_dtr, // BOTH: 1=on, 0=off - - setPrescaler, // USA26: host requests prescalar be set (default: 13) - prescaler; // BOTH: specified as N/8; values 8-ff are valid - // must be set any time internal baud rate is set; - // must not be set when external clocking is used - // note: in USA17, prescaler is applied whenever - // setClocking is requested - - /* - 3. configuration data which is simply used as is (no overhead, - but must be specified correctly in every host message). - */ - u8 forwardingLength, // BOTH: forward when this number of chars available - reportHskiaChanges_dsrFlowControl, - // USA26: 1=normal; 0=ignore external clock - // USA17: 1=use DSR flow control, 0=don't - txAckThreshold, // BOTH: 0=not allowed, 1=normal, 2-255 deliver ACK faster - loopbackMode; // BOTH: 0=no loopback, 1=loopback enabled - - /* - 4. commands which are flags only; these are processed in order - (so that, e.g., if both _txOn and _txOff flags are set, the - port ends in a TX_OFF state); any non-zero value is respected - */ - u8 _txOn, // BOTH: enable transmitting (and continue if there's data) - _txOff, // BOTH: stop transmitting - txFlush, // BOTH: toss outbound data - txBreak, // BOTH: turn on break (cleared by _txOn) - rxOn, // BOTH: turn on receiver - rxOff, // BOTH: turn off receiver - rxFlush, // BOTH: toss inbound data - rxForward, // BOTH: forward all inbound data, NOW (as if fwdLen==1) - returnStatus, // BOTH: return current status (even if it hasn't changed) - resetDataToggle;// BOTH: reset data toggle state to DATA0 - -}; - -// defines for bits in lcr -#define USA_DATABITS_5 0x00 -#define USA_DATABITS_6 0x01 -#define USA_DATABITS_7 0x02 -#define USA_DATABITS_8 0x03 -#define STOPBITS_5678_1 0x00 // 1 stop bit for all byte sizes -#define STOPBITS_5_1p5 0x04 // 1.5 stop bits for 5-bit byte -#define STOPBITS_678_2 0x04 // 2 stop bits for 6/7/8-bit byte -#define USA_PARITY_NONE 0x00 -#define USA_PARITY_ODD 0x08 -#define USA_PARITY_EVEN 0x18 -#define PARITY_1 0x28 -#define PARITY_0 0x38 - -// all things called "StatusMessage" are sent on the status endpoint - -struct keyspan_usa26_portStatusMessage // one for each port -{ - u8 port, // BOTH: 0=first, 1=second, other=see below - hskia_cts, // USA26: reports HSKIA pin - // USA17: reports CTS pin - gpia_dcd, // USA26: reports GPIA pin - // USA17: reports DCD pin - dsr, // USA17: reports DSR pin - ri, // USA17: reports RI pin - _txOff, // port has been disabled (by host) - _txXoff, // port is in XOFF state (either host or RX XOFF) - rxEnabled, // as configured by rxOn/rxOff 1=on, 0=off - controlResponse;// 1=a control message has been processed -}; - -// bits in RX data message when STAT byte is included -#define RXERROR_OVERRUN 0x02 -#define RXERROR_PARITY 0x04 -#define RXERROR_FRAMING 0x08 -#define RXERROR_BREAK 0x10 - -struct keyspan_usa26_globalControlMessage -{ - u8 sendGlobalStatus, // 2=request for two status responses - resetStatusToggle, // 1=reset global status toggle - resetStatusCount; // a cycling value -}; - -struct keyspan_usa26_globalStatusMessage -{ - u8 port, // 3 - sendGlobalStatus, // from request, decremented - resetStatusCount; // as in request -}; - -struct keyspan_usa26_globalDebugMessage -{ - u8 port, // 2 - a, - b, - c, - d; -}; - -// ie: the maximum length of an EZUSB endpoint buffer -#define MAX_DATA_LEN 64 - -// update status approx. 60 times a second (16.6666 ms) -#define STATUS_UPDATE_INTERVAL 16 - -// status rationing tuning value (each port gets checked each n ms) -#define STATUS_RATION 10 - -#endif - - diff --git a/ANDROID_3.4.5/drivers/usb/serial/keyspan_usa28msg.h b/ANDROID_3.4.5/drivers/usb/serial/keyspan_usa28msg.h deleted file mode 100644 index dee454c4..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/keyspan_usa28msg.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - usa28msg.h - - Copyright (C) 1998-2000 InnoSys Incorporated. All Rights Reserved - This file is available under a BSD-style copyright - - Keyspan USB Async Message Formats for the USA26X - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - 1. Redistributions of source code must retain this licence text - without modification, this list of conditions, and the following - disclaimer. The following copyright notice must appear immediately at - the beginning of all source files: - - Copyright (C) 1998-2000 InnoSys Incorporated. All Rights Reserved - - This file is available under a BSD-style copyright - - 2. The name of InnoSys Incorporated may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY INNOSYS CORP. ``AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - - Note: these message formats are common to USA18, USA19, and USA28; - (for USA28X, see usa26msg.h) - - Buffer formats for RX/TX data messages are not defined by - a structure, but are described here: - - USB OUT (host -> USA28, transmit) messages contain a - REQUEST_ACK indicator (set to 0xff to request an ACK at the - completion of transmit; 0x00 otherwise), followed by data. - If the port is configured for parity, the data will be an - alternating string of parity and data bytes, so the message - format will be: - - RQSTACK PAR DAT PAR DAT ... - - so the maximum length is 63 bytes (1 + 62, or 31 data bytes); - always an odd number for the total message length. - - If there is no parity, the format is simply: - - RQSTACK DAT DAT DAT ... - - with a total data length of 63. - - USB IN (USA28 -> host, receive) messages contain data and parity - if parity is configred, thusly: - - DAT PAR DAT PAR DAT PAR ... - - for a total of 32 data bytes; - - If parity is not configured, the format is: - - DAT DAT DAT ... - - for a total of 64 data bytes. - - In the TX messages (USB OUT), the 0x01 bit of the PARity byte is - the parity bit. In the RX messages (USB IN), the PARity byte is - the content of the 8051's status register; the parity bit - (RX_PARITY_BIT) is the 0x04 bit. - - revision history: - - 1999may06 add resetDataToggle to control message - 2000mar21 add rs232invalid to status response message - 2000apr04 add 230.4Kb definition to setBaudRate - 2000apr13 add/remove loopbackMode switch - 2000apr13 change definition of setBaudRate to cover 115.2Kb, too - 2000jun01 add extended BSD-style copyright text -*/ - -#ifndef __USA28MSG__ -#define __USA28MSG__ - - -struct keyspan_usa28_portControlMessage -{ - /* - there are four types of "commands" sent in the control message: - - 1. configuration changes which must be requested by setting - the corresponding "set" flag (and should only be requested - when necessary, to reduce overhead on the USA28): - */ - u8 setBaudRate, // 0=don't set, 1=baudLo/Hi, 2=115.2K, 3=230.4K - baudLo, // host does baud divisor calculation - baudHi; // baudHi is only used for first port (gives lower rates) - - /* - 2. configuration changes which are done every time (because it's - hardly more trouble to do them than to check whether to do them): - */ - u8 parity, // 1=use parity, 0=don't - ctsFlowControl, // all except 19Q: 1=use CTS flow control, 0=don't - // 19Q: 0x08:CTSflowControl 0x10:DSRflowControl - xonFlowControl, // 1=use XON/XOFF flow control, 0=don't - rts, // 1=on, 0=off - dtr; // 1=on, 0=off - - /* - 3. configuration data which is simply used as is (no overhead, - but must be correct in every host message). - */ - u8 forwardingLength, // forward when this number of chars available - forwardMs, // forward this many ms after last rx data - breakThreshold, // specified in ms, 1-255 (see note below) - xonChar, // specified in current character format - xoffChar; // specified in current character format - - /* - 4. commands which are flags only; these are processed in order - (so that, e.g., if both _txOn and _txOff flags are set, the - port ends in a TX_OFF state); any non-zero value is respected - */ - u8 _txOn, // enable transmitting (and continue if there's data) - _txOff, // stop transmitting - txFlush, // toss outbound data - txForceXoff, // pretend we've received XOFF - txBreak, // turn on break (leave on until txOn clears it) - rxOn, // turn on receiver - rxOff, // turn off receiver - rxFlush, // toss inbound data - rxForward, // forward all inbound data, NOW - returnStatus, // return current status n times (1 or 2) - resetDataToggle;// reset data toggle state to DATA0 - -}; - -struct keyspan_usa28_portStatusMessage -{ - u8 port, // 0=first, 1=second, 2=global (see below) - cts, - dsr, // (not used in all products) - dcd, - - ri, // (not used in all products) - _txOff, // port has been disabled (by host) - _txXoff, // port is in XOFF state (either host or RX XOFF) - dataLost, // count of lost chars; wraps; not guaranteed exact - - rxEnabled, // as configured by rxOn/rxOff 1=on, 0=off - rxBreak, // 1=we're in break state - rs232invalid, // 1=no valid signals on rs-232 inputs - controlResponse;// 1=a control messages has been processed -}; - -// bit defines in txState -#define TX_OFF 0x01 // requested by host txOff command -#define TX_XOFF 0x02 // either real, or simulated by host - -struct keyspan_usa28_globalControlMessage -{ - u8 sendGlobalStatus, // 2=request for two status responses - resetStatusToggle, // 1=reset global status toggle - resetStatusCount; // a cycling value -}; - -struct keyspan_usa28_globalStatusMessage -{ - u8 port, // 3 - sendGlobalStatus, // from request, decremented - resetStatusCount; // as in request -}; - -struct keyspan_usa28_globalDebugMessage -{ - u8 port, // 2 - n, // typically a count/status byte - b; // typically a data byte -}; - -// ie: the maximum length of an EZUSB endpoint buffer -#define MAX_DATA_LEN 64 - -// the parity bytes have only one significant bit -#define RX_PARITY_BIT 0x04 -#define TX_PARITY_BIT 0x01 - -// update status approx. 60 times a second (16.6666 ms) -#define STATUS_UPDATE_INTERVAL 16 - -#endif - diff --git a/ANDROID_3.4.5/drivers/usb/serial/keyspan_usa49msg.h b/ANDROID_3.4.5/drivers/usb/serial/keyspan_usa49msg.h deleted file mode 100644 index 163b2dea..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/keyspan_usa49msg.h +++ /dev/null @@ -1,282 +0,0 @@ -/* - usa49msg.h - - Copyright (C) 1998-2000 InnoSys Incorporated. All Rights Reserved - This file is available under a BSD-style copyright - - Keyspan USB Async Message Formats for the USA49W - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - 1. Redistributions of source code must retain this licence text - without modification, this list of conditions, and the following - disclaimer. The following copyright notice must appear immediately at - the beginning of all source files: - - Copyright (C) 1998-2000 InnoSys Incorporated. All Rights Reserved - - This file is available under a BSD-style copyright - - 2. The name of InnoSys Incorporated may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY INNOSYS CORP. ``AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - - 4th revision: USA49W version - - Buffer formats for RX/TX data messages are not defined by - a structure, but are described here: - - USB OUT (host -> USAxx, transmit) messages contain a - REQUEST_ACK indicator (set to 0xff to request an ACK at the - completion of transmit; 0x00 otherwise), followed by data: - - RQSTACK DAT DAT DAT ... - - with a total data length of 63. - - USB IN (USAxx -> host, receive) messages begin with a status - byte in which the 0x80 bit is either: - - (a) 0x80 bit clear - indicates that the bytes following it are all data - bytes: - - STAT DATA DATA DATA DATA DATA ... - - for a total of up to 63 DATA bytes, - - or: - - (b) 0x80 bit set - indiates that the bytes following alternate data and - status bytes: - - STAT DATA STAT DATA STAT DATA STAT DATA ... - - for a total of up to 32 DATA bytes. - - The valid bits in the STAT bytes are: - - OVERRUN 0x02 - PARITY 0x04 - FRAMING 0x08 - BREAK 0x10 - - Notes: - - (1) The OVERRUN bit can appear in either (a) or (b) format - messages, but the but the PARITY/FRAMING/BREAK bits - only appear in (b) format messages. - (2) For the host to determine the exact point at which the - overrun occurred (to identify the point in the data - stream at which the data was lost), it needs to count - 128 characters, starting at the first character of the - message in which OVERRUN was reported; the lost character(s) - would have been received between the 128th and 129th - characters. - (3) An RX data message in which the first byte has 0x80 clear - serves as a "break off" indicator. - (4) a control message specifying disablePort will be answered - with a status message, but no further status will be sent - until a control messages with enablePort is sent - - revision history: - - 1999feb10 add reportHskiaChanges to allow us to ignore them - 1999feb10 add txAckThreshold for fast+loose throughput enhancement - 1999mar30 beef up support for RX error reporting - 1999apr14 add resetDataToggle to control message - 2000jan04 merge with usa17msg.h - 2000mar08 clone from usa26msg.h -> usa49msg.h - 2000mar09 change to support 4 ports - 2000may03 change external clocking to match USA-49W hardware - 2000jun01 add extended BSD-style copyright text - 2001jul05 change message format to improve OVERRUN case -*/ - -#ifndef __USA49MSG__ -#define __USA49MSG__ - - -/* - Host->device messages sent on the global control endpoint: - - portNumber message - ---------- -------------------- - 0,1,2,3 portControlMessage - 0x80 globalControlMessage -*/ - -struct keyspan_usa49_portControlMessage -{ - /* - 0. 0/1/2/3 port control message follows - 0x80 set non-port control message follows - */ - u8 portNumber, - - /* - there are three types of "commands" sent in the control message: - - 1. configuration changes which must be requested by setting - the corresponding "set" flag (and should only be requested - when necessary, to reduce overhead on the USA26): - */ - setClocking, // host requests baud rate be set - baudLo, // host does baud divisor calculation - baudHi, // baudHi is only used for first port (gives lower rates) - prescaler, // specified as N/8; values 8-ff are valid - // must be set any time internal baud rate is set; - txClocking, // 0=internal, 1=external/DSR - rxClocking, // 0=internal, 1=external/DSR - - setLcr, // host requests lcr be set - lcr, // use PARITY, STOPBITS, DATABITS below - - setFlowControl, // host requests flow control be set - ctsFlowControl, // 1=use CTS flow control, 0=don't - xonFlowControl, // 1=use XON/XOFF flow control, 0=don't - xonChar, // specified in current character format - xoffChar, // specified in current character format - - setRts, // host requests RTS output be set - rts, // 1=active, 0=inactive - - setDtr, // host requests DTR output be set - dtr; // 1=on, 0=off - - - /* - 3. configuration data which is simply used as is (no overhead, - but must be specified correctly in every host message). - */ - u8 forwardingLength, // forward when this number of chars available - dsrFlowControl, // 1=use DSR flow control, 0=don't - txAckThreshold, // 0=not allowed, 1=normal, 2-255 deliver ACK faster - loopbackMode; // 0=no loopback, 1=loopback enabled - - /* - 4. commands which are flags only; these are processed in order - (so that, e.g., if both _txOn and _txOff flags are set, the - port ends in a TX_OFF state); any non-zero value is respected - */ - u8 _txOn, // enable transmitting (and continue if there's data) - _txOff, // stop transmitting - txFlush, // toss outbound data - txBreak, // turn on break (cleared by _txOn) - rxOn, // turn on receiver - rxOff, // turn off receiver - rxFlush, // toss inbound data - rxForward, // forward all inbound data, NOW (as if fwdLen==1) - returnStatus, // return current status (even if it hasn't changed) - resetDataToggle,// reset data toggle state to DATA0 - enablePort, // start servicing port (move data, check status) - disablePort; // stop servicing port (does implicit tx/rx flush/off) - -}; - -// defines for bits in lcr -#define USA_DATABITS_5 0x00 -#define USA_DATABITS_6 0x01 -#define USA_DATABITS_7 0x02 -#define USA_DATABITS_8 0x03 -#define STOPBITS_5678_1 0x00 // 1 stop bit for all byte sizes -#define STOPBITS_5_1p5 0x04 // 1.5 stop bits for 5-bit byte -#define STOPBITS_678_2 0x04 // 2 stop bits for 6/7/8-bit byte -#define USA_PARITY_NONE 0x00 -#define USA_PARITY_ODD 0x08 -#define USA_PARITY_EVEN 0x18 -#define PARITY_1 0x28 -#define PARITY_0 0x38 - -/* - during normal operation, status messages are returned - to the host whenever the board detects changes. In some - circumstances (e.g. Windows), status messages from the - device cause problems; to shut them off, the host issues - a control message with the disableStatusMessages flags - set (to any non-zero value). The device will respond to - this message, and then suppress further status messages; - it will resume sending status messages any time the host - sends any control message (either global or port-specific). -*/ - -struct keyspan_usa49_globalControlMessage -{ - u8 portNumber, // 0x80 - sendGlobalStatus, // 1/2=number of status responses requested - resetStatusToggle, // 1=reset global status toggle - resetStatusCount, // a cycling value - remoteWakeupEnable, // 0x10=P1, 0x20=P2, 0x40=P3, 0x80=P4 - disableStatusMessages; // 1=send no status until host talks -}; - -/* - Device->host messages send on the global status endpoint - - portNumber message - ---------- -------------------- - 0x00,0x01,0x02,0x03 portStatusMessage - 0x80 globalStatusMessage - 0x81 globalDebugMessage -*/ - -struct keyspan_usa49_portStatusMessage // one for each port -{ - u8 portNumber, // 0,1,2,3 - cts, // reports CTS pin - dcd, // reports DCD pin - dsr, // reports DSR pin - ri, // reports RI pin - _txOff, // transmit has been disabled (by host) - _txXoff, // transmit is in XOFF state (either host or RX XOFF) - rxEnabled, // as configured by rxOn/rxOff 1=on, 0=off - controlResponse,// 1=a control message has been processed - txAck, // ACK (data TX complete) - rs232valid; // RS-232 signal valid -}; - -// bits in RX data message when STAT byte is included -#define RXERROR_OVERRUN 0x02 -#define RXERROR_PARITY 0x04 -#define RXERROR_FRAMING 0x08 -#define RXERROR_BREAK 0x10 - -struct keyspan_usa49_globalStatusMessage -{ - u8 portNumber, // 0x80=globalStatusMessage - sendGlobalStatus, // from request, decremented - resetStatusCount; // as in request -}; - -struct keyspan_usa49_globalDebugMessage -{ - u8 portNumber, // 0x81=globalDebugMessage - n, // typically a count/status byte - b; // typically a data byte -}; - -// ie: the maximum length of an EZUSB endpoint buffer -#define MAX_DATA_LEN 64 - -// update status approx. 60 times a second (16.6666 ms) -#define STATUS_UPDATE_INTERVAL 16 - -// status rationing tuning value (each port gets checked each n ms) -#define STATUS_RATION 10 - -#endif diff --git a/ANDROID_3.4.5/drivers/usb/serial/keyspan_usa67msg.h b/ANDROID_3.4.5/drivers/usb/serial/keyspan_usa67msg.h deleted file mode 100644 index 20fa3e2f..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/keyspan_usa67msg.h +++ /dev/null @@ -1,254 +0,0 @@ -/* - usa67msg.h - - Copyright (c) 1998-2007 InnoSys Incorporated. All Rights Reserved - This file is available under a BSD-style copyright - - Keyspan USB Async Firmware to run on Anchor FX1 - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - 1. Redistributions of source code must retain this licence text - without modification, this list of conditions, and the following - disclaimer. The following copyright notice must appear immediately at - the beginning of all source files: - - Copyright (c) 1998-2007 InnoSys Incorporated. All Rights Reserved - - This file is available under a BSD-style copyright - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - 3. The name of InnoSys Incorprated may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY INNOSYS CORP. ``AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - - Fourth revision: This message format supports the USA28XG - - Buffer formats for RX/TX data messages are not defined by - a structure, but are described here: - - USB OUT (host -> USAxx, transmit) messages contain a - REQUEST_ACK indicator (set to 0xff to request an ACK at the - completion of transmit; 0x00 otherwise), followed by data: - - RQSTACK DAT DAT DAT ... - - with a total data length of up to 63. - - USB IN (USAxx -> host, receive) messages begin with a status - byte in which the 0x80 bit is either: - - (a) 0x80 bit clear - indicates that the bytes following it are all data - bytes: - - STAT DATA DATA DATA DATA DATA ... - - for a total of up to 63 DATA bytes, - - or: - - (b) 0x80 bit set - indiates that the bytes following alternate data and - status bytes: - - STAT DATA STAT DATA STAT DATA STAT DATA ... - - for a total of up to 32 DATA bytes. - - The valid bits in the STAT bytes are: - - OVERRUN 0x02 - PARITY 0x04 - FRAMING 0x08 - BREAK 0x10 - - Notes: - - (1) The OVERRUN bit can appear in either (a) or (b) format - messages, but the but the PARITY/FRAMING/BREAK bits - only appear in (b) format messages. - (2) For the host to determine the exact point at which the - overrun occurred (to identify the point in the data - stream at which the data was lost), it needs to count - 128 characters, starting at the first character of the - message in which OVERRUN was reported; the lost character(s) - would have been received between the 128th and 129th - characters. - (3) An RX data message in which the first byte has 0x80 clear - serves as a "break off" indicator. - - revision history: - - 1999feb10 add reportHskiaChanges to allow us to ignore them - 1999feb10 add txAckThreshold for fast+loose throughput enhancement - 1999mar30 beef up support for RX error reporting - 1999apr14 add resetDataToggle to control message - 2000jan04 merge with usa17msg.h - 2000jun01 add extended BSD-style copyright text - 2001jul05 change message format to improve OVERRUN case - 2002jun05 update copyright date, improve comments - 2006feb06 modify for FX1 chip - -*/ - -#ifndef __USA67MSG__ -#define __USA67MSG__ - - -// all things called "ControlMessage" are sent on the 'control' endpoint - -typedef struct keyspan_usa67_portControlMessage -{ - u8 port; // 0 or 1 (selects port) - /* - there are three types of "commands" sent in the control message: - - 1. configuration changes which must be requested by setting - the corresponding "set" flag (and should only be requested - when necessary, to reduce overhead on the device): - */ - u8 setClocking, // host requests baud rate be set - baudLo, // host does baud divisor calculation - baudHi, // baudHi is only used for first port (gives lower rates) - externalClock_txClocking, - // 0=internal, other=external - - setLcr, // host requests lcr be set - lcr, // use PARITY, STOPBITS, DATABITS below - - setFlowControl, // host requests flow control be set - ctsFlowControl, // 1=use CTS flow control, 0=don't - xonFlowControl, // 1=use XON/XOFF flow control, 0=don't - xonChar, // specified in current character format - xoffChar, // specified in current character format - - setTxTriState_setRts, - // host requests TX tri-state be set - txTriState_rts, // 1=active (normal), 0=tristate (off) - - setHskoa_setDtr, - // host requests HSKOA output be set - hskoa_dtr, // 1=on, 0=off - - setPrescaler, // host requests prescalar be set (default: 13) - prescaler; // specified as N/8; values 8-ff are valid - // must be set any time internal baud rate is set; - // must not be set when external clocking is used - - /* - 3. configuration data which is simply used as is (no overhead, - but must be specified correctly in every host message). - */ - u8 forwardingLength, // forward when this number of chars available - reportHskiaChanges_dsrFlowControl, - // 1=normal; 0=ignore external clock - // 1=use DSR flow control, 0=don't - txAckThreshold, // 0=not allowed, 1=normal, 2-255 deliver ACK faster - loopbackMode; // 0=no loopback, 1=loopback enabled - - /* - 4. commands which are flags only; these are processed in order - (so that, e.g., if both _txOn and _txOff flags are set, the - port ends in a TX_OFF state); any non-zero value is respected - */ - u8 _txOn, // enable transmitting (and continue if there's data) - _txOff, // stop transmitting - txFlush, // toss outbound data - txBreak, // turn on break (cleared by _txOn) - rxOn, // turn on receiver - rxOff, // turn off receiver - rxFlush, // toss inbound data - rxForward, // forward all inbound data, NOW (as if fwdLen==1) - returnStatus, // return current status (even if it hasn't changed) - resetDataToggle;// reset data toggle state to DATA0 - -} keyspan_usa67_portControlMessage; - -// defines for bits in lcr -#define USA_DATABITS_5 0x00 -#define USA_DATABITS_6 0x01 -#define USA_DATABITS_7 0x02 -#define USA_DATABITS_8 0x03 -#define STOPBITS_5678_1 0x00 // 1 stop bit for all byte sizes -#define STOPBITS_5_1p5 0x04 // 1.5 stop bits for 5-bit byte -#define STOPBITS_678_2 0x04 // 2 stop bits for 6/7/8-bit byte -#define USA_PARITY_NONE 0x00 -#define USA_PARITY_ODD 0x08 -#define USA_PARITY_EVEN 0x18 -#define PARITY_1 0x28 -#define PARITY_0 0x38 - -// all things called "StatusMessage" are sent on the status endpoint - -typedef struct keyspan_usa67_portStatusMessage // one for each port -{ - u8 port, // 0=first, 1=second, other=see below - hskia_cts, // reports HSKIA pin - gpia_dcd, // reports GPIA pin - _txOff, // port has been disabled (by host) - _txXoff, // port is in XOFF state (either host or RX XOFF) - txAck, // indicates a TX message acknowledgement - rxEnabled, // as configured by rxOn/rxOff 1=on, 0=off - controlResponse;// 1=a control message has been processed -} keyspan_usa67_portStatusMessage; - -// bits in RX data message when STAT byte is included -#define RXERROR_OVERRUN 0x02 -#define RXERROR_PARITY 0x04 -#define RXERROR_FRAMING 0x08 -#define RXERROR_BREAK 0x10 - -typedef struct keyspan_usa67_globalControlMessage -{ - u8 port, // 3 - sendGlobalStatus, // 2=request for two status responses - resetStatusToggle, // 1=reset global status toggle - resetStatusCount; // a cycling value -} keyspan_usa67_globalControlMessage; - -typedef struct keyspan_usa67_globalStatusMessage -{ - u8 port, // 3 - sendGlobalStatus, // from request, decremented - resetStatusCount; // as in request -} keyspan_usa67_globalStatusMessage; - -typedef struct keyspan_usa67_globalDebugMessage -{ - u8 port, // 2 - a, - b, - c, - d; -} keyspan_usa67_globalDebugMessage; - -// ie: the maximum length of an FX1 endpoint buffer -#define MAX_DATA_LEN 64 - -// update status approx. 60 times a second (16.6666 ms) -#define STATUS_UPDATE_INTERVAL 16 - -// status rationing tuning value (each port gets checked each n ms) -#define STATUS_RATION 10 - -#endif - - diff --git a/ANDROID_3.4.5/drivers/usb/serial/keyspan_usa90msg.h b/ANDROID_3.4.5/drivers/usb/serial/keyspan_usa90msg.h deleted file mode 100644 index 86708ecd..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/keyspan_usa90msg.h +++ /dev/null @@ -1,198 +0,0 @@ -/* - usa90msg.h - - Copyright (c) 1998-2003 InnoSys Incorporated. All Rights Reserved - This file is available under a BSD-style copyright - - Keyspan USB Async Message Formats for the USA19HS - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - 1. Redistributions of source code must retain this licence text - without modification, this list of conditions, and the following - disclaimer. The following copyright notice must appear immediately at - the beginning of all source files: - - Copyright (c) 1998-2003 InnoSys Incorporated. All Rights Reserved - - This file is available under a BSD-style copyright - - 2. The name of InnoSys Incorporated may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY INNOSYS CORP. ``AS IS'' AND ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - - Revisions: - - 2003feb14 add setTxMode/txMode and cancelRxXoff to portControl - 2003mar21 change name of PARITY_0/1 to add MARK/SPACE -*/ - -#ifndef __USA90MSG__ -#define __USA90MSG__ - -struct keyspan_usa90_portControlMessage -{ - /* - there are three types of "commands" sent in the control message: - - 1. configuration changes which must be requested by setting - the corresponding "set" flag (and should only be requested - when necessary, to reduce overhead on the device): - */ - - u8 setClocking, // host requests baud rate be set - baudLo, // host does baud divisor calculation - baudHi, // host does baud divisor calculation - - setLcr, // host requests lcr be set - lcr, // use PARITY, STOPBITS, DATABITS below - - setRxMode, // set receive mode - rxMode, // RXMODE_DMA or RXMODE_BYHAND - - setTxMode, // set transmit mode - txMode, // TXMODE_DMA or TXMODE_BYHAND - - setTxFlowControl, // host requests tx flow control be set - txFlowControl , // use TX_FLOW... bits below - setRxFlowControl, // host requests rx flow control be set - rxFlowControl, // use RX_FLOW... bits below - sendXoff, // host requests XOFF transmitted immediately - sendXon, // host requests XON char transmitted - xonChar, // specified in current character format - xoffChar, // specified in current character format - - sendChar, // host requests char transmitted immediately - txChar, // character to send - - setRts, // host requests RTS output be set - rts, // 1=on, 0=off - setDtr, // host requests DTR output be set - dtr; // 1=on, 0=off - - - /* - 2. configuration data which is simply used as is - and must be specified correctly in every host message. - */ - - u8 rxForwardingLength, // forward when this number of chars available - rxForwardingTimeout, // (1-31 in ms) - txAckSetting; // 0=don't ack, 1=normal, 2-255 TBD... - /* - 3. Firmware states which cause actions if they change - and must be specified correctly in every host message. - */ - - u8 portEnabled, // 0=disabled, 1=enabled - txFlush, // 0=normal, 1=toss outbound data - txBreak, // 0=break off, 1=break on - loopbackMode; // 0=no loopback, 1=loopback enabled - - /* - 4. commands which are flags only; these are processed in order - (so that, e.g., if rxFlush and rxForward flags are set, the - port will have no data to forward); any non-zero value - is respected - */ - - u8 rxFlush, // toss inbound data - rxForward, // forward all inbound data, NOW (as if fwdLen==1) - cancelRxXoff, // cancel any receive XOFF state (_txXoff) - returnStatus; // return current status NOW -}; - -// defines for bits in lcr -#define USA_DATABITS_5 0x00 -#define USA_DATABITS_6 0x01 -#define USA_DATABITS_7 0x02 -#define USA_DATABITS_8 0x03 -#define STOPBITS_5678_1 0x00 // 1 stop bit for all byte sizes -#define STOPBITS_5_1p5 0x04 // 1.5 stop bits for 5-bit byte -#define STOPBITS_678_2 0x04 // 2 stop bits for 6-8 bit byte -#define USA_PARITY_NONE 0x00 -#define USA_PARITY_ODD 0x08 -#define USA_PARITY_EVEN 0x18 -#define PARITY_MARK_1 0x28 // force parity MARK -#define PARITY_SPACE_0 0x38 // force parity SPACE - -#define TXFLOW_CTS 0x04 -#define TXFLOW_DSR 0x08 -#define TXFLOW_XOFF 0x01 -#define TXFLOW_XOFF_ANY 0x02 -#define TXFLOW_XOFF_BITS (TXFLOW_XOFF | TXFLOW_XOFF_ANY) - -#define RXFLOW_XOFF 0x10 -#define RXFLOW_RTS 0x20 -#define RXFLOW_DTR 0x40 -#define RXFLOW_DSR_SENSITIVITY 0x80 - -#define RXMODE_BYHAND 0x00 -#define RXMODE_DMA 0x02 - -#define TXMODE_BYHAND 0x00 -#define TXMODE_DMA 0x02 - - -// all things called "StatusMessage" are sent on the status endpoint - -struct keyspan_usa90_portStatusMessage -{ - u8 msr, // reports the actual MSR register - cts, // reports CTS pin - dcd, // reports DCD pin - dsr, // reports DSR pin - ri, // reports RI pin - _txXoff, // port is in XOFF state (we received XOFF) - rxBreak, // reports break state - rxOverrun, // count of overrun errors (since last reported) - rxParity, // count of parity errors (since last reported) - rxFrame, // count of frame errors (since last reported) - portState, // PORTSTATE_xxx bits (useful for debugging) - messageAck, // message acknowledgement - charAck, // character acknowledgement - controlResponse; // (value = returnStatus) a control message has been processed -}; - -// bits in RX data message when STAT byte is included - -#define RXERROR_OVERRUN 0x02 -#define RXERROR_PARITY 0x04 -#define RXERROR_FRAMING 0x08 -#define RXERROR_BREAK 0x10 - -#define PORTSTATE_ENABLED 0x80 -#define PORTSTATE_TXFLUSH 0x01 -#define PORTSTATE_TXBREAK 0x02 -#define PORTSTATE_LOOPBACK 0x04 - -// MSR bits - -#define USA_MSR_dCTS 0x01 // CTS has changed since last report -#define USA_MSR_dDSR 0x02 -#define USA_MSR_dRI 0x04 -#define USA_MSR_dDCD 0x08 - -#define USA_MSR_CTS 0x10 // current state of CTS -#define USA_MSR_DSR 0x20 -#define USA_USA_MSR_RI 0x40 -#define MSR_DCD 0x80 - -// ie: the maximum length of an endpoint buffer -#define MAX_DATA_LEN 64 - -#endif diff --git a/ANDROID_3.4.5/drivers/usb/serial/kl5kusb105.c b/ANDROID_3.4.5/drivers/usb/serial/kl5kusb105.c deleted file mode 100644 index 10f05407..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/kl5kusb105.c +++ /dev/null @@ -1,702 +0,0 @@ -/* - * KLSI KL5KUSB105 chip RS232 converter driver - * - * Copyright (C) 2010 Johan Hovold - * Copyright (C) 2001 Utz-Uwe Haus - * - * 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. - * - * All information about the device was acquired using SniffUSB ans snoopUSB - * on Windows98. - * It was written out of frustration with the PalmConnect USB Serial adapter - * sold by Palm Inc. - * Neither Palm, nor their contractor (MCCI) or their supplier (KLSI) provided - * information that was not already available. - * - * It seems that KLSI bought some silicon-design information from ScanLogic, - * whose SL11R processor is at the core of the KL5KUSB chipset from KLSI. - * KLSI has firmware available for their devices; it is probable that the - * firmware differs from that used by KLSI in their products. If you have an - * original KLSI device and can provide some information on it, I would be - * most interested in adding support for it here. If you have any information - * on the protocol used (or find errors in my reverse-engineered stuff), please - * let me know. - * - * The code was only tested with a PalmConnect USB adapter; if you - * are adventurous, try it with any KLSI-based device and let me know how it - * breaks so that I can fix it! - */ - -/* TODO: - * check modem line signals - * implement handshaking or decide that we do not support it - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "kl5kusb105.h" - -static bool debug; - -/* - * Version Information - */ -#define DRIVER_VERSION "v0.4" -#define DRIVER_AUTHOR "Utz-Uwe Haus , Johan Hovold " -#define DRIVER_DESC "KLSI KL5KUSB105 chipset USB->Serial Converter driver" - - -/* - * Function prototypes - */ -static int klsi_105_startup(struct usb_serial *serial); -static void klsi_105_release(struct usb_serial *serial); -static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port); -static void klsi_105_close(struct usb_serial_port *port); -static void klsi_105_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old); -static int klsi_105_tiocmget(struct tty_struct *tty); -static int klsi_105_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear); -static void klsi_105_process_read_urb(struct urb *urb); -static int klsi_105_prepare_write_buffer(struct usb_serial_port *port, - void *dest, size_t size); - -/* - * All of the device info needed for the KLSI converters. - */ -static const struct usb_device_id id_table[] = { - { USB_DEVICE(PALMCONNECT_VID, PALMCONNECT_PID) }, - { USB_DEVICE(KLSI_VID, KLSI_KL5KUSB105D_PID) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver kl5kusb105d_driver = { - .name = "kl5kusb105d", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - -static struct usb_serial_driver kl5kusb105d_device = { - .driver = { - .owner = THIS_MODULE, - .name = "kl5kusb105d", - }, - .description = "KL5KUSB105D / PalmConnect", - .id_table = id_table, - .num_ports = 1, - .bulk_out_size = 64, - .open = klsi_105_open, - .close = klsi_105_close, - .set_termios = klsi_105_set_termios, - /*.break_ctl = klsi_105_break_ctl,*/ - .tiocmget = klsi_105_tiocmget, - .tiocmset = klsi_105_tiocmset, - .attach = klsi_105_startup, - .release = klsi_105_release, - .throttle = usb_serial_generic_throttle, - .unthrottle = usb_serial_generic_unthrottle, - .process_read_urb = klsi_105_process_read_urb, - .prepare_write_buffer = klsi_105_prepare_write_buffer, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &kl5kusb105d_device, NULL -}; - -struct klsi_105_port_settings { - __u8 pktlen; /* always 5, it seems */ - __u8 baudrate; - __u8 databits; - __u8 unknown1; - __u8 unknown2; -} __attribute__ ((packed)); - -struct klsi_105_private { - struct klsi_105_port_settings cfg; - struct ktermios termios; - unsigned long line_state; /* modem line settings */ - spinlock_t lock; -}; - - -/* - * Handle vendor specific USB requests - */ - - -#define KLSI_TIMEOUT 5000 /* default urb timeout */ - -static int klsi_105_chg_port_settings(struct usb_serial_port *port, - struct klsi_105_port_settings *settings) -{ - int rc; - - rc = usb_control_msg(port->serial->dev, - usb_sndctrlpipe(port->serial->dev, 0), - KL5KUSB105A_SIO_SET_DATA, - USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_INTERFACE, - 0, /* value */ - 0, /* index */ - settings, - sizeof(struct klsi_105_port_settings), - KLSI_TIMEOUT); - if (rc < 0) - dev_err(&port->dev, - "Change port settings failed (error = %d)\n", rc); - dev_info(&port->serial->dev->dev, - "%d byte block, baudrate %x, databits %d, u1 %d, u2 %d\n", - settings->pktlen, settings->baudrate, settings->databits, - settings->unknown1, settings->unknown2); - return rc; -} - -/* translate a 16-bit status value from the device to linux's TIO bits */ -static unsigned long klsi_105_status2linestate(const __u16 status) -{ - unsigned long res = 0; - - res = ((status & KL5KUSB105A_DSR) ? TIOCM_DSR : 0) - | ((status & KL5KUSB105A_CTS) ? TIOCM_CTS : 0) - ; - - return res; -} - -/* - * Read line control via vendor command and return result through - * *line_state_p - */ -/* It seems that the status buffer has always only 2 bytes length */ -#define KLSI_STATUSBUF_LEN 2 -static int klsi_105_get_line_state(struct usb_serial_port *port, - unsigned long *line_state_p) -{ - int rc; - u8 *status_buf; - __u16 status; - - dev_info(&port->serial->dev->dev, "sending SIO Poll request\n"); - - status_buf = kmalloc(KLSI_STATUSBUF_LEN, GFP_KERNEL); - if (!status_buf) { - dev_err(&port->dev, "%s - out of memory for status buffer.\n", - __func__); - return -ENOMEM; - } - status_buf[0] = 0xff; - status_buf[1] = 0xff; - rc = usb_control_msg(port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0), - KL5KUSB105A_SIO_POLL, - USB_TYPE_VENDOR | USB_DIR_IN, - 0, /* value */ - 0, /* index */ - status_buf, KLSI_STATUSBUF_LEN, - 10000 - ); - if (rc < 0) - dev_err(&port->dev, "Reading line status failed (error = %d)\n", - rc); - else { - status = get_unaligned_le16(status_buf); - - dev_info(&port->serial->dev->dev, "read status %x %x", - status_buf[0], status_buf[1]); - - *line_state_p = klsi_105_status2linestate(status); - } - - kfree(status_buf); - return rc; -} - - -/* - * Driver's tty interface functions - */ - -static int klsi_105_startup(struct usb_serial *serial) -{ - struct klsi_105_private *priv; - int i; - - /* check if we support the product id (see keyspan.c) - * FIXME - */ - - /* allocate the private data structure */ - for (i = 0; i < serial->num_ports; i++) { - priv = kmalloc(sizeof(struct klsi_105_private), - GFP_KERNEL); - if (!priv) { - dbg("%skmalloc for klsi_105_private failed.", __func__); - i--; - goto err_cleanup; - } - /* set initial values for control structures */ - priv->cfg.pktlen = 5; - priv->cfg.baudrate = kl5kusb105a_sio_b9600; - priv->cfg.databits = kl5kusb105a_dtb_8; - priv->cfg.unknown1 = 0; - priv->cfg.unknown2 = 1; - - priv->line_state = 0; - - usb_set_serial_port_data(serial->port[i], priv); - - spin_lock_init(&priv->lock); - - /* priv->termios is left uninitialized until port opening */ - init_waitqueue_head(&serial->port[i]->write_wait); - } - - return 0; - -err_cleanup: - for (; i >= 0; i--) { - priv = usb_get_serial_port_data(serial->port[i]); - kfree(priv); - usb_set_serial_port_data(serial->port[i], NULL); - } - return -ENOMEM; -} - -static void klsi_105_release(struct usb_serial *serial) -{ - int i; - - dbg("%s", __func__); - - for (i = 0; i < serial->num_ports; ++i) - kfree(usb_get_serial_port_data(serial->port[i])); -} - -static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct klsi_105_private *priv = usb_get_serial_port_data(port); - int retval = 0; - int rc; - int i; - unsigned long line_state; - struct klsi_105_port_settings *cfg; - unsigned long flags; - - dbg("%s port %d", __func__, port->number); - - /* Do a defined restart: - * Set up sane default baud rate and send the 'READ_ON' - * vendor command. - * FIXME: set modem line control (how?) - * Then read the modem line control and store values in - * priv->line_state. - */ - cfg = kmalloc(sizeof(*cfg), GFP_KERNEL); - if (!cfg) { - dev_err(&port->dev, "%s - out of memory for config buffer.\n", - __func__); - return -ENOMEM; - } - cfg->pktlen = 5; - cfg->baudrate = kl5kusb105a_sio_b9600; - cfg->databits = kl5kusb105a_dtb_8; - cfg->unknown1 = 0; - cfg->unknown2 = 1; - klsi_105_chg_port_settings(port, cfg); - - /* set up termios structure */ - spin_lock_irqsave(&priv->lock, flags); - priv->termios.c_iflag = tty->termios->c_iflag; - priv->termios.c_oflag = tty->termios->c_oflag; - priv->termios.c_cflag = tty->termios->c_cflag; - priv->termios.c_lflag = tty->termios->c_lflag; - for (i = 0; i < NCCS; i++) - priv->termios.c_cc[i] = tty->termios->c_cc[i]; - priv->cfg.pktlen = cfg->pktlen; - priv->cfg.baudrate = cfg->baudrate; - priv->cfg.databits = cfg->databits; - priv->cfg.unknown1 = cfg->unknown1; - priv->cfg.unknown2 = cfg->unknown2; - spin_unlock_irqrestore(&priv->lock, flags); - - /* READ_ON and urb submission */ - rc = usb_serial_generic_open(tty, port); - if (rc) { - retval = rc; - goto exit; - } - - rc = usb_control_msg(port->serial->dev, - usb_sndctrlpipe(port->serial->dev, 0), - KL5KUSB105A_SIO_CONFIGURE, - USB_TYPE_VENDOR|USB_DIR_OUT|USB_RECIP_INTERFACE, - KL5KUSB105A_SIO_CONFIGURE_READ_ON, - 0, /* index */ - NULL, - 0, - KLSI_TIMEOUT); - if (rc < 0) { - dev_err(&port->dev, "Enabling read failed (error = %d)\n", rc); - retval = rc; - } else - dbg("%s - enabled reading", __func__); - - rc = klsi_105_get_line_state(port, &line_state); - if (rc >= 0) { - spin_lock_irqsave(&priv->lock, flags); - priv->line_state = line_state; - spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - read line state 0x%lx", __func__, line_state); - retval = 0; - } else - retval = rc; - -exit: - kfree(cfg); - return retval; -} - -static void klsi_105_close(struct usb_serial_port *port) -{ - int rc; - - dbg("%s port %d", __func__, port->number); - - mutex_lock(&port->serial->disc_mutex); - if (!port->serial->disconnected) { - /* send READ_OFF */ - rc = usb_control_msg(port->serial->dev, - usb_sndctrlpipe(port->serial->dev, 0), - KL5KUSB105A_SIO_CONFIGURE, - USB_TYPE_VENDOR | USB_DIR_OUT, - KL5KUSB105A_SIO_CONFIGURE_READ_OFF, - 0, /* index */ - NULL, 0, - KLSI_TIMEOUT); - if (rc < 0) - dev_err(&port->dev, - "Disabling read failed (error = %d)\n", rc); - } - mutex_unlock(&port->serial->disc_mutex); - - /* shutdown our bulk reads and writes */ - usb_serial_generic_close(port); - - /* wgg - do I need this? I think so. */ - usb_kill_urb(port->interrupt_in_urb); -} - -/* We need to write a complete 64-byte data block and encode the - * number actually sent in the first double-byte, LSB-order. That - * leaves at most 62 bytes of payload. - */ -#define KLSI_HDR_LEN 2 -static int klsi_105_prepare_write_buffer(struct usb_serial_port *port, - void *dest, size_t size) -{ - unsigned char *buf = dest; - int count; - - count = kfifo_out_locked(&port->write_fifo, buf + KLSI_HDR_LEN, size, - &port->lock); - put_unaligned_le16(count, buf); - - return count + KLSI_HDR_LEN; -} - -/* The data received is preceded by a length double-byte in LSB-first order. - */ -static void klsi_105_process_read_urb(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - unsigned char *data = urb->transfer_buffer; - struct tty_struct *tty; - unsigned len; - - /* empty urbs seem to happen, we ignore them */ - if (!urb->actual_length) - return; - - if (urb->actual_length <= KLSI_HDR_LEN) { - dbg("%s - malformed packet", __func__); - return; - } - - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - - len = get_unaligned_le16(data); - if (len > urb->actual_length - KLSI_HDR_LEN) { - dbg("%s - packet length mismatch", __func__); - len = urb->actual_length - KLSI_HDR_LEN; - } - - tty_insert_flip_string(tty, data + KLSI_HDR_LEN, len); - tty_flip_buffer_push(tty); - tty_kref_put(tty); -} - -static void klsi_105_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old_termios) -{ - struct klsi_105_private *priv = usb_get_serial_port_data(port); - unsigned int iflag = tty->termios->c_iflag; - unsigned int old_iflag = old_termios->c_iflag; - unsigned int cflag = tty->termios->c_cflag; - unsigned int old_cflag = old_termios->c_cflag; - struct klsi_105_port_settings *cfg; - unsigned long flags; - speed_t baud; - - cfg = kmalloc(sizeof(*cfg), GFP_KERNEL); - if (!cfg) { - dev_err(&port->dev, "%s - out of memory for config buffer.\n", - __func__); - return; - } - - /* lock while we are modifying the settings */ - spin_lock_irqsave(&priv->lock, flags); - - /* - * Update baud rate - */ - baud = tty_get_baud_rate(tty); - - if ((cflag & CBAUD) != (old_cflag & CBAUD)) { - /* reassert DTR and (maybe) RTS on transition from B0 */ - if ((old_cflag & CBAUD) == B0) { - dbg("%s: baud was B0", __func__); -#if 0 - priv->control_state |= TIOCM_DTR; - /* don't set RTS if using hardware flow control */ - if (!(old_cflag & CRTSCTS)) - priv->control_state |= TIOCM_RTS; - mct_u232_set_modem_ctrl(serial, priv->control_state); -#endif - } - } - switch (baud) { - case 0: /* handled below */ - break; - case 1200: - priv->cfg.baudrate = kl5kusb105a_sio_b1200; - break; - case 2400: - priv->cfg.baudrate = kl5kusb105a_sio_b2400; - break; - case 4800: - priv->cfg.baudrate = kl5kusb105a_sio_b4800; - break; - case 9600: - priv->cfg.baudrate = kl5kusb105a_sio_b9600; - break; - case 19200: - priv->cfg.baudrate = kl5kusb105a_sio_b19200; - break; - case 38400: - priv->cfg.baudrate = kl5kusb105a_sio_b38400; - break; - case 57600: - priv->cfg.baudrate = kl5kusb105a_sio_b57600; - break; - case 115200: - priv->cfg.baudrate = kl5kusb105a_sio_b115200; - break; - default: - dbg("KLSI USB->Serial converter:" - " unsupported baudrate request, using default of 9600"); - priv->cfg.baudrate = kl5kusb105a_sio_b9600; - baud = 9600; - break; - } - if ((cflag & CBAUD) == B0) { - dbg("%s: baud is B0", __func__); - /* Drop RTS and DTR */ - /* maybe this should be simulated by sending read - * disable and read enable messages? - */ - ; -#if 0 - priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); - mct_u232_set_modem_ctrl(serial, priv->control_state); -#endif - } - tty_encode_baud_rate(tty, baud, baud); - - if ((cflag & CSIZE) != (old_cflag & CSIZE)) { - /* set the number of data bits */ - switch (cflag & CSIZE) { - case CS5: - dbg("%s - 5 bits/byte not supported", __func__); - spin_unlock_irqrestore(&priv->lock, flags); - goto err; - case CS6: - dbg("%s - 6 bits/byte not supported", __func__); - spin_unlock_irqrestore(&priv->lock, flags); - goto err; - case CS7: - priv->cfg.databits = kl5kusb105a_dtb_7; - break; - case CS8: - priv->cfg.databits = kl5kusb105a_dtb_8; - break; - default: - dev_err(&port->dev, - "CSIZE was not CS5-CS8, using default of 8\n"); - priv->cfg.databits = kl5kusb105a_dtb_8; - break; - } - } - - /* - * Update line control register (LCR) - */ - if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD)) - || (cflag & CSTOPB) != (old_cflag & CSTOPB)) { - /* Not currently supported */ - tty->termios->c_cflag &= ~(PARENB|PARODD|CSTOPB); -#if 0 - priv->last_lcr = 0; - - /* set the parity */ - if (cflag & PARENB) - priv->last_lcr |= (cflag & PARODD) ? - MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN; - else - priv->last_lcr |= MCT_U232_PARITY_NONE; - - /* set the number of stop bits */ - priv->last_lcr |= (cflag & CSTOPB) ? - MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1; - - mct_u232_set_line_ctrl(serial, priv->last_lcr); -#endif - ; - } - /* - * Set flow control: well, I do not really now how to handle DTR/RTS. - * Just do what we have seen with SniffUSB on Win98. - */ - if ((iflag & IXOFF) != (old_iflag & IXOFF) - || (iflag & IXON) != (old_iflag & IXON) - || (cflag & CRTSCTS) != (old_cflag & CRTSCTS)) { - /* Not currently supported */ - tty->termios->c_cflag &= ~CRTSCTS; - /* Drop DTR/RTS if no flow control otherwise assert */ -#if 0 - if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS)) - priv->control_state |= TIOCM_DTR | TIOCM_RTS; - else - priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); - mct_u232_set_modem_ctrl(serial, priv->control_state); -#endif - ; - } - memcpy(cfg, &priv->cfg, sizeof(*cfg)); - spin_unlock_irqrestore(&priv->lock, flags); - - /* now commit changes to device */ - klsi_105_chg_port_settings(port, cfg); -err: - kfree(cfg); -} - -#if 0 -static void mct_u232_break_ctl(struct tty_struct *tty, int break_state) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; - struct mct_u232_private *priv = - (struct mct_u232_private *)port->private; - unsigned char lcr = priv->last_lcr; - - dbg("%sstate=%d", __func__, break_state); - - /* LOCKING */ - if (break_state) - lcr |= MCT_U232_SET_BREAK; - - mct_u232_set_line_ctrl(serial, lcr); -} -#endif - -static int klsi_105_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct klsi_105_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - int rc; - unsigned long line_state; - dbg("%s - request, just guessing", __func__); - - rc = klsi_105_get_line_state(port, &line_state); - if (rc < 0) { - dev_err(&port->dev, - "Reading line control failed (error = %d)\n", rc); - /* better return value? EAGAIN? */ - return rc; - } - - spin_lock_irqsave(&priv->lock, flags); - priv->line_state = line_state; - spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - read line state 0x%lx", __func__, line_state); - return (int)line_state; -} - -static int klsi_105_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - int retval = -EINVAL; - - dbg("%s", __func__); - -/* if this ever gets implemented, it should be done something like this: - struct usb_serial *serial = port->serial; - struct klsi_105_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - int control; - - spin_lock_irqsave (&priv->lock, flags); - if (set & TIOCM_RTS) - priv->control_state |= TIOCM_RTS; - if (set & TIOCM_DTR) - priv->control_state |= TIOCM_DTR; - if (clear & TIOCM_RTS) - priv->control_state &= ~TIOCM_RTS; - if (clear & TIOCM_DTR) - priv->control_state &= ~TIOCM_DTR; - control = priv->control_state; - spin_unlock_irqrestore (&priv->lock, flags); - retval = mct_u232_set_modem_ctrl(serial, control); -*/ - return retval; -} - -module_usb_serial_driver(kl5kusb105d_driver, serial_drivers); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "enable extensive debugging messages"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/kl5kusb105.h b/ANDROID_3.4.5/drivers/usb/serial/kl5kusb105.h deleted file mode 100644 index 22a90bad..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/kl5kusb105.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Definitions for the KLSI KL5KUSB105 serial port adapter - */ - -/* vendor/product pairs that are known to contain this chipset */ -#define PALMCONNECT_VID 0x0830 -#define PALMCONNECT_PID 0x0080 - -#define KLSI_VID 0x05e9 -#define KLSI_KL5KUSB105D_PID 0x00c0 - -/* Vendor commands: */ - - -/* port table -- the chip supports up to 4 channels */ - -/* baud rates */ - -enum { - kl5kusb105a_sio_b115200 = 0, - kl5kusb105a_sio_b57600 = 1, - kl5kusb105a_sio_b38400 = 2, - kl5kusb105a_sio_b19200 = 4, - kl5kusb105a_sio_b14400 = 5, - kl5kusb105a_sio_b9600 = 6, - kl5kusb105a_sio_b4800 = 8, /* unchecked */ - kl5kusb105a_sio_b2400 = 9, /* unchecked */ - kl5kusb105a_sio_b1200 = 0xa, /* unchecked */ - kl5kusb105a_sio_b600 = 0xb /* unchecked */ -}; - -/* data bits */ -#define kl5kusb105a_dtb_7 7 -#define kl5kusb105a_dtb_8 8 - - - -/* requests: */ -#define KL5KUSB105A_SIO_SET_DATA 1 -#define KL5KUSB105A_SIO_POLL 2 -#define KL5KUSB105A_SIO_CONFIGURE 3 -/* values used for request KL5KUSB105A_SIO_CONFIGURE */ -#define KL5KUSB105A_SIO_CONFIGURE_READ_ON 3 -#define KL5KUSB105A_SIO_CONFIGURE_READ_OFF 2 - -/* Interpretation of modem status lines */ -/* These need sorting out by individually connecting pins and checking - * results. FIXME! - * When data is being sent we see 0x30 in the lower byte; this must - * contain DSR and CTS ... - */ -#define KL5KUSB105A_DSR ((1<<4) | (1<<5)) -#define KL5KUSB105A_CTS ((1<<5) | (1<<4)) - -#define KL5KUSB105A_WANTS_TO_SEND 0x30 -#if 0 -#define KL5KUSB105A_DTR /* Data Terminal Ready */ -#define KL5KUSB105A_CTS /* Clear To Send */ -#define KL5KUSB105A_CD /* Carrier Detect */ -#define KL5KUSB105A_DSR /* Data Set Ready */ -#define KL5KUSB105A_RxD /* Receive pin */ - -#define KL5KUSB105A_LE -#define KL5KUSB105A_RTS -#define KL5KUSB105A_ST -#define KL5KUSB105A_SR -#define KL5KUSB105A_RI /* Ring Indicator */ -#endif diff --git a/ANDROID_3.4.5/drivers/usb/serial/kobil_sct.c b/ANDROID_3.4.5/drivers/usb/serial/kobil_sct.c deleted file mode 100644 index 4a9a75eb..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/kobil_sct.c +++ /dev/null @@ -1,693 +0,0 @@ -/* - * KOBIL USB Smart Card Terminal Driver - * - * Copyright (C) 2002 KOBIL Systems GmbH - * Author: Thomas Wahrenbruch - * - * Contact: linuxusb@kobil.de - * - * This program is largely derived from work by the linux-usb group - * and associated source files. Please see the usb/serial files for - * individual credits and copyrights. - * - * 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. - * - * Thanks to Greg Kroah-Hartman (greg@kroah.com) for his help and - * patience. - * - * Supported readers: USB TWIN, KAAN Standard Plus and SecOVID Reader Plus - * (Adapter K), B1 Professional and KAAN Professional (Adapter B) - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "kobil_sct.h" - -static bool debug; - -/* Version Information */ -#define DRIVER_VERSION "21/05/2004" -#define DRIVER_AUTHOR "KOBIL Systems GmbH - http://www.kobil.com" -#define DRIVER_DESC "KOBIL USB Smart Card Terminal Driver (experimental)" - -#define KOBIL_VENDOR_ID 0x0D46 -#define KOBIL_ADAPTER_B_PRODUCT_ID 0x2011 -#define KOBIL_ADAPTER_K_PRODUCT_ID 0x2012 -#define KOBIL_USBTWIN_PRODUCT_ID 0x0078 -#define KOBIL_KAAN_SIM_PRODUCT_ID 0x0081 - -#define KOBIL_TIMEOUT 500 -#define KOBIL_BUF_LENGTH 300 - - -/* Function prototypes */ -static int kobil_startup(struct usb_serial *serial); -static void kobil_release(struct usb_serial *serial); -static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port); -static void kobil_close(struct usb_serial_port *port); -static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count); -static int kobil_write_room(struct tty_struct *tty); -static int kobil_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); -static int kobil_tiocmget(struct tty_struct *tty); -static int kobil_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear); -static void kobil_read_int_callback(struct urb *urb); -static void kobil_write_callback(struct urb *purb); -static void kobil_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old); -static void kobil_init_termios(struct tty_struct *tty); - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_B_PRODUCT_ID) }, - { USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_K_PRODUCT_ID) }, - { USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_USBTWIN_PRODUCT_ID) }, - { USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_KAAN_SIM_PRODUCT_ID) }, - { } /* Terminating entry */ -}; - - -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver kobil_driver = { - .name = "kobil", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - - -static struct usb_serial_driver kobil_device = { - .driver = { - .owner = THIS_MODULE, - .name = "kobil", - }, - .description = "KOBIL USB smart card terminal", - .id_table = id_table, - .num_ports = 1, - .attach = kobil_startup, - .release = kobil_release, - .ioctl = kobil_ioctl, - .set_termios = kobil_set_termios, - .init_termios = kobil_init_termios, - .tiocmget = kobil_tiocmget, - .tiocmset = kobil_tiocmset, - .open = kobil_open, - .close = kobil_close, - .write = kobil_write, - .write_room = kobil_write_room, - .read_int_callback = kobil_read_int_callback, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &kobil_device, NULL -}; - -struct kobil_private { - int write_int_endpoint_address; - int read_int_endpoint_address; - unsigned char buf[KOBIL_BUF_LENGTH]; /* buffer for the APDU to send */ - int filled; /* index of the last char in buf */ - int cur_pos; /* index of the next char to send in buf */ - __u16 device_type; -}; - - -static int kobil_startup(struct usb_serial *serial) -{ - int i; - struct kobil_private *priv; - struct usb_device *pdev; - struct usb_host_config *actconfig; - struct usb_interface *interface; - struct usb_host_interface *altsetting; - struct usb_host_endpoint *endpoint; - - priv = kmalloc(sizeof(struct kobil_private), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->filled = 0; - priv->cur_pos = 0; - priv->device_type = le16_to_cpu(serial->dev->descriptor.idProduct); - - switch (priv->device_type) { - case KOBIL_ADAPTER_B_PRODUCT_ID: - printk(KERN_DEBUG "KOBIL B1 PRO / KAAN PRO detected\n"); - break; - case KOBIL_ADAPTER_K_PRODUCT_ID: - printk(KERN_DEBUG - "KOBIL KAAN Standard Plus / SecOVID Reader Plus detected\n"); - break; - case KOBIL_USBTWIN_PRODUCT_ID: - printk(KERN_DEBUG "KOBIL USBTWIN detected\n"); - break; - case KOBIL_KAAN_SIM_PRODUCT_ID: - printk(KERN_DEBUG "KOBIL KAAN SIM detected\n"); - break; - } - usb_set_serial_port_data(serial->port[0], priv); - - /* search for the necessary endpoints */ - pdev = serial->dev; - actconfig = pdev->actconfig; - interface = actconfig->interface[0]; - altsetting = interface->cur_altsetting; - endpoint = altsetting->endpoint; - - for (i = 0; i < altsetting->desc.bNumEndpoints; i++) { - endpoint = &altsetting->endpoint[i]; - if (usb_endpoint_is_int_out(&endpoint->desc)) { - dbg("%s Found interrupt out endpoint. Address: %d", - __func__, endpoint->desc.bEndpointAddress); - priv->write_int_endpoint_address = - endpoint->desc.bEndpointAddress; - } - if (usb_endpoint_is_int_in(&endpoint->desc)) { - dbg("%s Found interrupt in endpoint. Address: %d", - __func__, endpoint->desc.bEndpointAddress); - priv->read_int_endpoint_address = - endpoint->desc.bEndpointAddress; - } - } - return 0; -} - - -static void kobil_release(struct usb_serial *serial) -{ - int i; - dbg("%s - port %d", __func__, serial->port[0]->number); - - for (i = 0; i < serial->num_ports; ++i) - kfree(usb_get_serial_port_data(serial->port[i])); -} - -static void kobil_init_termios(struct tty_struct *tty) -{ - /* Default to echo off and other sane device settings */ - tty->termios->c_lflag = 0; - tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE); - tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF; - /* do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) */ - tty->termios->c_oflag &= ~ONLCR; -} - -static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - int result = 0; - struct kobil_private *priv; - unsigned char *transfer_buffer; - int transfer_buffer_length = 8; - int write_urb_transfer_buffer_length = 8; - - dbg("%s - port %d", __func__, port->number); - priv = usb_get_serial_port_data(port); - - /* allocate memory for transfer buffer */ - transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL); - if (!transfer_buffer) - return -ENOMEM; - - /* allocate write_urb */ - if (!port->write_urb) { - dbg("%s - port %d Allocating port->write_urb", - __func__, port->number); - port->write_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!port->write_urb) { - dbg("%s - port %d usb_alloc_urb failed", - __func__, port->number); - kfree(transfer_buffer); - return -ENOMEM; - } - } - - /* allocate memory for write_urb transfer buffer */ - port->write_urb->transfer_buffer = - kmalloc(write_urb_transfer_buffer_length, GFP_KERNEL); - if (!port->write_urb->transfer_buffer) { - kfree(transfer_buffer); - usb_free_urb(port->write_urb); - port->write_urb = NULL; - return -ENOMEM; - } - - /* get hardware version */ - result = usb_control_msg(port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0), - SUSBCRequest_GetMisc, - USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN, - SUSBCR_MSC_GetHWVersion, - 0, - transfer_buffer, - transfer_buffer_length, - KOBIL_TIMEOUT - ); - dbg("%s - port %d Send get_HW_version URB returns: %i", - __func__, port->number, result); - dbg("Harware version: %i.%i.%i", - transfer_buffer[0], transfer_buffer[1], transfer_buffer[2]); - - /* get firmware version */ - result = usb_control_msg(port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0), - SUSBCRequest_GetMisc, - USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN, - SUSBCR_MSC_GetFWVersion, - 0, - transfer_buffer, - transfer_buffer_length, - KOBIL_TIMEOUT - ); - dbg("%s - port %d Send get_FW_version URB returns: %i", - __func__, port->number, result); - dbg("Firmware version: %i.%i.%i", - transfer_buffer[0], transfer_buffer[1], transfer_buffer[2]); - - if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID || - priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) { - /* Setting Baudrate, Parity and Stopbits */ - result = usb_control_msg(port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0), - SUSBCRequest_SetBaudRateParityAndStopBits, - USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, - SUSBCR_SBR_9600 | SUSBCR_SPASB_EvenParity | - SUSBCR_SPASB_1StopBit, - 0, - transfer_buffer, - 0, - KOBIL_TIMEOUT - ); - dbg("%s - port %d Send set_baudrate URB returns: %i", - __func__, port->number, result); - - /* reset all queues */ - result = usb_control_msg(port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0), - SUSBCRequest_Misc, - USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, - SUSBCR_MSC_ResetAllQueues, - 0, - transfer_buffer, - 0, - KOBIL_TIMEOUT - ); - dbg("%s - port %d Send reset_all_queues URB returns: %i", - __func__, port->number, result); - } - if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || - priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID || - priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) { - /* start reading (Adapter B 'cause PNP string) */ - result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); - dbg("%s - port %d Send read URB returns: %i", - __func__, port->number, result); - } - - kfree(transfer_buffer); - return 0; -} - - -static void kobil_close(struct usb_serial_port *port) -{ - dbg("%s - port %d", __func__, port->number); - - /* FIXME: Add rts/dtr methods */ - if (port->write_urb) { - usb_poison_urb(port->write_urb); - kfree(port->write_urb->transfer_buffer); - usb_free_urb(port->write_urb); - port->write_urb = NULL; - } - usb_kill_urb(port->interrupt_in_urb); -} - - -static void kobil_read_int_callback(struct urb *urb) -{ - int result; - struct usb_serial_port *port = urb->context; - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - int status = urb->status; -/* char *dbg_data; */ - - dbg("%s - port %d", __func__, port->number); - - if (status) { - dbg("%s - port %d Read int status not zero: %d", - __func__, port->number, status); - return; - } - - tty = tty_port_tty_get(&port->port); - if (tty && urb->actual_length) { - - /* BEGIN DEBUG */ - /* - dbg_data = kzalloc((3 * purb->actual_length + 10) - * sizeof(char), GFP_KERNEL); - if (! dbg_data) { - return; - } - for (i = 0; i < purb->actual_length; i++) { - sprintf(dbg_data +3*i, "%02X ", data[i]); - } - dbg(" <-- %s", dbg_data); - kfree(dbg_data); - */ - /* END DEBUG */ - - tty_insert_flip_string(tty, data, urb->actual_length); - tty_flip_buffer_push(tty); - } - tty_kref_put(tty); - - result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); - dbg("%s - port %d Send read URB returns: %i", - __func__, port->number, result); -} - - -static void kobil_write_callback(struct urb *purb) -{ -} - - -static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - int length = 0; - int result = 0; - int todo = 0; - struct kobil_private *priv; - - if (count == 0) { - dbg("%s - port %d write request of 0 bytes", - __func__, port->number); - return 0; - } - - priv = usb_get_serial_port_data(port); - - if (count > (KOBIL_BUF_LENGTH - priv->filled)) { - dbg("%s - port %d Error: write request bigger than buffer size", __func__, port->number); - return -ENOMEM; - } - - /* Copy data to buffer */ - memcpy(priv->buf + priv->filled, buf, count); - usb_serial_debug_data(debug, &port->dev, __func__, count, - priv->buf + priv->filled); - priv->filled = priv->filled + count; - - /* only send complete block. TWIN, KAAN SIM and adapter K - use the same protocol. */ - if (((priv->device_type != KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 2) && (priv->filled >= (priv->buf[1] + 3))) || - ((priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 3) && (priv->filled >= (priv->buf[2] + 4)))) { - /* stop reading (except TWIN and KAAN SIM) */ - if ((priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) - || (priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID)) - usb_kill_urb(port->interrupt_in_urb); - - todo = priv->filled - priv->cur_pos; - - while (todo > 0) { - /* max 8 byte in one urb (endpoint size) */ - length = (todo < 8) ? todo : 8; - /* copy data to transfer buffer */ - memcpy(port->write_urb->transfer_buffer, - priv->buf + priv->cur_pos, length); - usb_fill_int_urb(port->write_urb, - port->serial->dev, - usb_sndintpipe(port->serial->dev, - priv->write_int_endpoint_address), - port->write_urb->transfer_buffer, - length, - kobil_write_callback, - port, - 8 - ); - - priv->cur_pos = priv->cur_pos + length; - result = usb_submit_urb(port->write_urb, GFP_NOIO); - dbg("%s - port %d Send write URB returns: %i", - __func__, port->number, result); - todo = priv->filled - priv->cur_pos; - - if (todo > 0) - msleep(24); - } - - priv->filled = 0; - priv->cur_pos = 0; - - /* start reading (except TWIN and KAAN SIM) */ - if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID || - priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) { - result = usb_submit_urb(port->interrupt_in_urb, - GFP_NOIO); - dbg("%s - port %d Send read URB returns: %i", - __func__, port->number, result); - } - } - return count; -} - - -static int kobil_write_room(struct tty_struct *tty) -{ - /* dbg("%s - port %d", __func__, port->number); */ - /* FIXME */ - return 8; -} - - -static int kobil_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct kobil_private *priv; - int result; - unsigned char *transfer_buffer; - int transfer_buffer_length = 8; - - priv = usb_get_serial_port_data(port); - if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID - || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) { - /* This device doesn't support ioctl calls */ - return -EINVAL; - } - - /* allocate memory for transfer buffer */ - transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL); - if (!transfer_buffer) - return -ENOMEM; - - result = usb_control_msg(port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0), - SUSBCRequest_GetStatusLineState, - USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_IN, - 0, - 0, - transfer_buffer, - transfer_buffer_length, - KOBIL_TIMEOUT); - - dbg("%s - port %d Send get_status_line_state URB returns: %i. Statusline: %02x", - __func__, port->number, result, transfer_buffer[0]); - - result = 0; - if ((transfer_buffer[0] & SUSBCR_GSL_DSR) != 0) - result = TIOCM_DSR; - kfree(transfer_buffer); - return result; -} - -static int kobil_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct kobil_private *priv; - int result; - int dtr = 0; - int rts = 0; - unsigned char *transfer_buffer; - int transfer_buffer_length = 8; - - /* FIXME: locking ? */ - priv = usb_get_serial_port_data(port); - if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID - || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) { - /* This device doesn't support ioctl calls */ - return -EINVAL; - } - - /* allocate memory for transfer buffer */ - transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL); - if (!transfer_buffer) - return -ENOMEM; - - if (set & TIOCM_RTS) - rts = 1; - if (set & TIOCM_DTR) - dtr = 1; - if (clear & TIOCM_RTS) - rts = 0; - if (clear & TIOCM_DTR) - dtr = 0; - - if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) { - if (dtr != 0) - dbg("%s - port %d Setting DTR", - __func__, port->number); - else - dbg("%s - port %d Clearing DTR", - __func__, port->number); - result = usb_control_msg(port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0), - SUSBCRequest_SetStatusLinesOrQueues, - USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, - ((dtr != 0) ? SUSBCR_SSL_SETDTR : SUSBCR_SSL_CLRDTR), - 0, - transfer_buffer, - 0, - KOBIL_TIMEOUT); - } else { - if (rts != 0) - dbg("%s - port %d Setting RTS", - __func__, port->number); - else - dbg("%s - port %d Clearing RTS", - __func__, port->number); - result = usb_control_msg(port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0), - SUSBCRequest_SetStatusLinesOrQueues, - USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, - ((rts != 0) ? SUSBCR_SSL_SETRTS : SUSBCR_SSL_CLRRTS), - 0, - transfer_buffer, - 0, - KOBIL_TIMEOUT); - } - dbg("%s - port %d Send set_status_line URB returns: %i", - __func__, port->number, result); - kfree(transfer_buffer); - return (result < 0) ? result : 0; -} - -static void kobil_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old) -{ - struct kobil_private *priv; - int result; - unsigned short urb_val = 0; - int c_cflag = tty->termios->c_cflag; - speed_t speed; - - priv = usb_get_serial_port_data(port); - if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || - priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) { - /* This device doesn't support ioctl calls */ - *tty->termios = *old; - return; - } - - speed = tty_get_baud_rate(tty); - switch (speed) { - case 1200: - urb_val = SUSBCR_SBR_1200; - break; - default: - speed = 9600; - case 9600: - urb_val = SUSBCR_SBR_9600; - break; - } - urb_val |= (c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : - SUSBCR_SPASB_1StopBit; - if (c_cflag & PARENB) { - if (c_cflag & PARODD) - urb_val |= SUSBCR_SPASB_OddParity; - else - urb_val |= SUSBCR_SPASB_EvenParity; - } else - urb_val |= SUSBCR_SPASB_NoParity; - tty->termios->c_cflag &= ~CMSPAR; - tty_encode_baud_rate(tty, speed, speed); - - result = usb_control_msg(port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0), - SUSBCRequest_SetBaudRateParityAndStopBits, - USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, - urb_val, - 0, - NULL, - 0, - KOBIL_TIMEOUT - ); -} - -static int kobil_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - struct kobil_private *priv = usb_get_serial_port_data(port); - unsigned char *transfer_buffer; - int transfer_buffer_length = 8; - int result; - - if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || - priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) - /* This device doesn't support ioctl calls */ - return -ENOIOCTLCMD; - - switch (cmd) { - case TCFLSH: - transfer_buffer = kmalloc(transfer_buffer_length, GFP_KERNEL); - if (!transfer_buffer) - return -ENOBUFS; - - result = usb_control_msg(port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0), - SUSBCRequest_Misc, - USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, - SUSBCR_MSC_ResetAllQueues, - 0, - NULL, /* transfer_buffer, */ - 0, - KOBIL_TIMEOUT - ); - - dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __func__, port->number, result); - kfree(transfer_buffer); - return (result < 0) ? -EIO: 0; - default: - return -ENOIOCTLCMD; - } -} - -module_usb_serial_driver(kobil_driver, serial_drivers); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/kobil_sct.h b/ANDROID_3.4.5/drivers/usb/serial/kobil_sct.h deleted file mode 100644 index be207f71..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/kobil_sct.h +++ /dev/null @@ -1,77 +0,0 @@ -#define SUSBCRequest_SetBaudRateParityAndStopBits 1 -#define SUSBCR_SBR_MASK 0xFF00 -#define SUSBCR_SBR_1200 0x0100 -#define SUSBCR_SBR_9600 0x0200 -#define SUSBCR_SBR_19200 0x0400 -#define SUSBCR_SBR_28800 0x0800 -#define SUSBCR_SBR_38400 0x1000 -#define SUSBCR_SBR_57600 0x2000 -#define SUSBCR_SBR_115200 0x4000 - -#define SUSBCR_SPASB_MASK 0x0070 -#define SUSBCR_SPASB_NoParity 0x0010 -#define SUSBCR_SPASB_OddParity 0x0020 -#define SUSBCR_SPASB_EvenParity 0x0040 - -#define SUSBCR_SPASB_STPMASK 0x0003 -#define SUSBCR_SPASB_1StopBit 0x0001 -#define SUSBCR_SPASB_2StopBits 0x0002 - -#define SUSBCRequest_SetStatusLinesOrQueues 2 -#define SUSBCR_SSL_SETRTS 0x0001 -#define SUSBCR_SSL_CLRRTS 0x0002 -#define SUSBCR_SSL_SETDTR 0x0004 -#define SUSBCR_SSL_CLRDTR 0x0010 - -/* Kill the pending/current writes to the comm port. */ -#define SUSBCR_SSL_PURGE_TXABORT 0x0100 -/* Kill the pending/current reads to the comm port. */ -#define SUSBCR_SSL_PURGE_RXABORT 0x0200 -/* Kill the transmit queue if there. */ -#define SUSBCR_SSL_PURGE_TXCLEAR 0x0400 -/* Kill the typeahead buffer if there. */ -#define SUSBCR_SSL_PURGE_RXCLEAR 0x0800 - -#define SUSBCRequest_GetStatusLineState 4 -/* Any Character received */ -#define SUSBCR_GSL_RXCHAR 0x0001 -/* Transmitt Queue Empty */ -#define SUSBCR_GSL_TXEMPTY 0x0004 -/* CTS changed state */ -#define SUSBCR_GSL_CTS 0x0008 -/* DSR changed state */ -#define SUSBCR_GSL_DSR 0x0010 -/* RLSD changed state */ -#define SUSBCR_GSL_RLSD 0x0020 -/* BREAK received */ -#define SUSBCR_GSL_BREAK 0x0040 -/* Line status error occurred */ -#define SUSBCR_GSL_ERR 0x0080 -/* Ring signal detected */ -#define SUSBCR_GSL_RING 0x0100 - -#define SUSBCRequest_Misc 8 -/* use a predefined reset sequence */ -#define SUSBCR_MSC_ResetReader 0x0001 -/* use a predefined sequence to reset the internal queues */ -#define SUSBCR_MSC_ResetAllQueues 0x0002 - -#define SUSBCRequest_GetMisc 0x10 - -/* - * get the firmware version from device, coded like this 0xHHLLBBPP with - * HH = Firmware Version High Byte - * LL = Firmware Version Low Byte - * BB = Build Number - * PP = Further Attributes - */ -#define SUSBCR_MSC_GetFWVersion 0x0001 - -/* - * get the hardware version from device coded like this 0xHHLLPPRR with - * HH = Software Version High Byte - * LL = Software Version Low Byte - * PP = Further Attributes - * RR = Reserved for the hardware ID - */ -#define SUSBCR_MSC_GetHWVersion 0x0002 diff --git a/ANDROID_3.4.5/drivers/usb/serial/mct_u232.c b/ANDROID_3.4.5/drivers/usb/serial/mct_u232.c deleted file mode 100644 index ef4d7adf..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/mct_u232.c +++ /dev/null @@ -1,919 +0,0 @@ -/* - * MCT (Magic Control Technology Corp.) USB RS232 Converter Driver - * - * Copyright (C) 2000 Wolfgang Grandegger (wolfgang@ces.ch) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is largely derived from the Belkin USB Serial Adapter Driver - * (see belkin_sa.[ch]). All of the information about the device was acquired - * by using SniffUSB on Windows98. For technical details see mct_u232.h. - * - * William G. Greathouse and Greg Kroah-Hartman provided great help on how to - * do the reverse engineering and how to write a USB serial device driver. - * - * TO BE DONE, TO BE CHECKED: - * DTR/RTS signal handling may be incomplete or incorrect. I have mainly - * implemented what I have seen with SniffUSB or found in belkin_sa.c. - * For further TODOs check also belkin_sa.c. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "mct_u232.h" - -/* - * Version Information - */ -#define DRIVER_VERSION "z2.1" /* Linux in-kernel version */ -#define DRIVER_AUTHOR "Wolfgang Grandegger " -#define DRIVER_DESC "Magic Control Technology USB-RS232 converter driver" - -static bool debug; - -/* - * Function prototypes - */ -static int mct_u232_startup(struct usb_serial *serial); -static void mct_u232_release(struct usb_serial *serial); -static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port); -static void mct_u232_close(struct usb_serial_port *port); -static void mct_u232_dtr_rts(struct usb_serial_port *port, int on); -static void mct_u232_read_int_callback(struct urb *urb); -static void mct_u232_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old); -static void mct_u232_break_ctl(struct tty_struct *tty, int break_state); -static int mct_u232_tiocmget(struct tty_struct *tty); -static int mct_u232_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear); -static int mct_u232_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); -static int mct_u232_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount); -static void mct_u232_throttle(struct tty_struct *tty); -static void mct_u232_unthrottle(struct tty_struct *tty); - - -/* - * All of the device info needed for the MCT USB-RS232 converter. - */ -static const struct usb_device_id id_table_combined[] = { - { USB_DEVICE(MCT_U232_VID, MCT_U232_PID) }, - { USB_DEVICE(MCT_U232_VID, MCT_U232_SITECOM_PID) }, - { USB_DEVICE(MCT_U232_VID, MCT_U232_DU_H3SP_PID) }, - { USB_DEVICE(MCT_U232_BELKIN_F5U109_VID, MCT_U232_BELKIN_F5U109_PID) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, id_table_combined); - -static struct usb_driver mct_u232_driver = { - .name = "mct_u232", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; - -static struct usb_serial_driver mct_u232_device = { - .driver = { - .owner = THIS_MODULE, - .name = "mct_u232", - }, - .description = "MCT U232", - .id_table = id_table_combined, - .num_ports = 1, - .open = mct_u232_open, - .close = mct_u232_close, - .dtr_rts = mct_u232_dtr_rts, - .throttle = mct_u232_throttle, - .unthrottle = mct_u232_unthrottle, - .read_int_callback = mct_u232_read_int_callback, - .set_termios = mct_u232_set_termios, - .break_ctl = mct_u232_break_ctl, - .tiocmget = mct_u232_tiocmget, - .tiocmset = mct_u232_tiocmset, - .attach = mct_u232_startup, - .release = mct_u232_release, - .ioctl = mct_u232_ioctl, - .get_icount = mct_u232_get_icount, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &mct_u232_device, NULL -}; - -struct mct_u232_private { - spinlock_t lock; - unsigned int control_state; /* Modem Line Setting (TIOCM) */ - unsigned char last_lcr; /* Line Control Register */ - unsigned char last_lsr; /* Line Status Register */ - unsigned char last_msr; /* Modem Status Register */ - unsigned int rx_flags; /* Throttling flags */ - struct async_icount icount; - wait_queue_head_t msr_wait; /* for handling sleeping while waiting - for msr change to happen */ -}; - -#define THROTTLED 0x01 - -/* - * Handle vendor specific USB requests - */ - -#define WDR_TIMEOUT 5000 /* default urb timeout */ - -/* - * Later day 2.6.0-test kernels have new baud rates like B230400 which - * we do not know how to support. We ignore them for the moment. - */ -static int mct_u232_calculate_baud_rate(struct usb_serial *serial, - speed_t value, speed_t *result) -{ - *result = value; - - if (le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_SITECOM_PID - || le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_BELKIN_F5U109_PID) { - switch (value) { - case 300: - return 0x01; - case 600: - return 0x02; /* this one not tested */ - case 1200: - return 0x03; - case 2400: - return 0x04; - case 4800: - return 0x06; - case 9600: - return 0x08; - case 19200: - return 0x09; - case 38400: - return 0x0a; - case 57600: - return 0x0b; - case 115200: - return 0x0c; - default: - *result = 9600; - return 0x08; - } - } else { - /* FIXME: Can we use any divider - should we do - divider = 115200/value; - real baud = 115200/divider */ - switch (value) { - case 300: break; - case 600: break; - case 1200: break; - case 2400: break; - case 4800: break; - case 9600: break; - case 19200: break; - case 38400: break; - case 57600: break; - case 115200: break; - default: - value = 9600; - *result = 9600; - } - return 115200/value; - } -} - -static int mct_u232_set_baud_rate(struct tty_struct *tty, - struct usb_serial *serial, struct usb_serial_port *port, speed_t value) -{ - unsigned int divisor; - int rc; - unsigned char *buf; - unsigned char cts_enable_byte = 0; - speed_t speed; - - buf = kmalloc(MCT_U232_MAX_SIZE, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - divisor = mct_u232_calculate_baud_rate(serial, value, &speed); - put_unaligned_le32(cpu_to_le32(divisor), buf); - rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - MCT_U232_SET_BAUD_RATE_REQUEST, - MCT_U232_SET_REQUEST_TYPE, - 0, 0, buf, MCT_U232_SET_BAUD_RATE_SIZE, - WDR_TIMEOUT); - if (rc < 0) /*FIXME: What value speed results */ - dev_err(&port->dev, "Set BAUD RATE %d failed (error = %d)\n", - value, rc); - else - tty_encode_baud_rate(tty, speed, speed); - dbg("set_baud_rate: value: 0x%x, divisor: 0x%x", value, divisor); - - /* Mimic the MCT-supplied Windows driver (version 1.21P.0104), which - always sends two extra USB 'device request' messages after the - 'baud rate change' message. The actual functionality of the - request codes in these messages is not fully understood but these - particular codes are never seen in any operation besides a baud - rate change. Both of these messages send a single byte of data. - In the first message, the value of this byte is always zero. - - The second message has been determined experimentally to control - whether data will be transmitted to a device which is not asserting - the 'CTS' signal. If the second message's data byte is zero, data - will be transmitted even if 'CTS' is not asserted (i.e. no hardware - flow control). if the second message's data byte is nonzero (a - value of 1 is used by this driver), data will not be transmitted to - a device which is not asserting 'CTS'. - */ - - buf[0] = 0; - rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - MCT_U232_SET_UNKNOWN1_REQUEST, - MCT_U232_SET_REQUEST_TYPE, - 0, 0, buf, MCT_U232_SET_UNKNOWN1_SIZE, - WDR_TIMEOUT); - if (rc < 0) - dev_err(&port->dev, "Sending USB device request code %d " - "failed (error = %d)\n", MCT_U232_SET_UNKNOWN1_REQUEST, - rc); - - if (port && C_CRTSCTS(tty)) - cts_enable_byte = 1; - - dbg("set_baud_rate: send second control message, data = %02X", - cts_enable_byte); - buf[0] = cts_enable_byte; - rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - MCT_U232_SET_CTS_REQUEST, - MCT_U232_SET_REQUEST_TYPE, - 0, 0, buf, MCT_U232_SET_CTS_SIZE, - WDR_TIMEOUT); - if (rc < 0) - dev_err(&port->dev, "Sending USB device request code %d " - "failed (error = %d)\n", MCT_U232_SET_CTS_REQUEST, rc); - - kfree(buf); - return rc; -} /* mct_u232_set_baud_rate */ - -static int mct_u232_set_line_ctrl(struct usb_serial *serial, unsigned char lcr) -{ - int rc; - unsigned char *buf; - - buf = kmalloc(MCT_U232_MAX_SIZE, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - buf[0] = lcr; - rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - MCT_U232_SET_LINE_CTRL_REQUEST, - MCT_U232_SET_REQUEST_TYPE, - 0, 0, buf, MCT_U232_SET_LINE_CTRL_SIZE, - WDR_TIMEOUT); - if (rc < 0) - dev_err(&serial->dev->dev, - "Set LINE CTRL 0x%x failed (error = %d)\n", lcr, rc); - dbg("set_line_ctrl: 0x%x", lcr); - kfree(buf); - return rc; -} /* mct_u232_set_line_ctrl */ - -static int mct_u232_set_modem_ctrl(struct usb_serial *serial, - unsigned int control_state) -{ - int rc; - unsigned char mcr; - unsigned char *buf; - - buf = kmalloc(MCT_U232_MAX_SIZE, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - mcr = MCT_U232_MCR_NONE; - if (control_state & TIOCM_DTR) - mcr |= MCT_U232_MCR_DTR; - if (control_state & TIOCM_RTS) - mcr |= MCT_U232_MCR_RTS; - - buf[0] = mcr; - rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - MCT_U232_SET_MODEM_CTRL_REQUEST, - MCT_U232_SET_REQUEST_TYPE, - 0, 0, buf, MCT_U232_SET_MODEM_CTRL_SIZE, - WDR_TIMEOUT); - kfree(buf); - - dbg("set_modem_ctrl: state=0x%x ==> mcr=0x%x", control_state, mcr); - - if (rc < 0) { - dev_err(&serial->dev->dev, - "Set MODEM CTRL 0x%x failed (error = %d)\n", mcr, rc); - return rc; - } - return 0; -} /* mct_u232_set_modem_ctrl */ - -static int mct_u232_get_modem_stat(struct usb_serial *serial, - unsigned char *msr) -{ - int rc; - unsigned char *buf; - - buf = kmalloc(MCT_U232_MAX_SIZE, GFP_KERNEL); - if (buf == NULL) { - *msr = 0; - return -ENOMEM; - } - rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - MCT_U232_GET_MODEM_STAT_REQUEST, - MCT_U232_GET_REQUEST_TYPE, - 0, 0, buf, MCT_U232_GET_MODEM_STAT_SIZE, - WDR_TIMEOUT); - if (rc < 0) { - dev_err(&serial->dev->dev, - "Get MODEM STATus failed (error = %d)\n", rc); - *msr = 0; - } else { - *msr = buf[0]; - } - dbg("get_modem_stat: 0x%x", *msr); - kfree(buf); - return rc; -} /* mct_u232_get_modem_stat */ - -static void mct_u232_msr_to_icount(struct async_icount *icount, - unsigned char msr) -{ - /* Translate Control Line states */ - if (msr & MCT_U232_MSR_DDSR) - icount->dsr++; - if (msr & MCT_U232_MSR_DCTS) - icount->cts++; - if (msr & MCT_U232_MSR_DRI) - icount->rng++; - if (msr & MCT_U232_MSR_DCD) - icount->dcd++; -} /* mct_u232_msr_to_icount */ - -static void mct_u232_msr_to_state(unsigned int *control_state, - unsigned char msr) -{ - /* Translate Control Line states */ - if (msr & MCT_U232_MSR_DSR) - *control_state |= TIOCM_DSR; - else - *control_state &= ~TIOCM_DSR; - if (msr & MCT_U232_MSR_CTS) - *control_state |= TIOCM_CTS; - else - *control_state &= ~TIOCM_CTS; - if (msr & MCT_U232_MSR_RI) - *control_state |= TIOCM_RI; - else - *control_state &= ~TIOCM_RI; - if (msr & MCT_U232_MSR_CD) - *control_state |= TIOCM_CD; - else - *control_state &= ~TIOCM_CD; - dbg("msr_to_state: msr=0x%x ==> state=0x%x", msr, *control_state); -} /* mct_u232_msr_to_state */ - -/* - * Driver's tty interface functions - */ - -static int mct_u232_startup(struct usb_serial *serial) -{ - struct mct_u232_private *priv; - struct usb_serial_port *port, *rport; - - priv = kzalloc(sizeof(struct mct_u232_private), GFP_KERNEL); - if (!priv) - return -ENOMEM; - spin_lock_init(&priv->lock); - init_waitqueue_head(&priv->msr_wait); - usb_set_serial_port_data(serial->port[0], priv); - - init_waitqueue_head(&serial->port[0]->write_wait); - - /* Puh, that's dirty */ - port = serial->port[0]; - rport = serial->port[1]; - /* No unlinking, it wasn't submitted yet. */ - usb_free_urb(port->read_urb); - port->read_urb = rport->interrupt_in_urb; - rport->interrupt_in_urb = NULL; - port->read_urb->context = port; - - return 0; -} /* mct_u232_startup */ - - -static void mct_u232_release(struct usb_serial *serial) -{ - struct mct_u232_private *priv; - int i; - - dbg("%s", __func__); - - for (i = 0; i < serial->num_ports; ++i) { - /* My special items, the standard routines free my urbs */ - priv = usb_get_serial_port_data(serial->port[i]); - kfree(priv); - } -} /* mct_u232_release */ - -static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - struct mct_u232_private *priv = usb_get_serial_port_data(port); - int retval = 0; - unsigned int control_state; - unsigned long flags; - unsigned char last_lcr; - unsigned char last_msr; - - dbg("%s port %d", __func__, port->number); - - /* Compensate for a hardware bug: although the Sitecom U232-P25 - * device reports a maximum output packet size of 32 bytes, - * it seems to be able to accept only 16 bytes (and that's what - * SniffUSB says too...) - */ - if (le16_to_cpu(serial->dev->descriptor.idProduct) - == MCT_U232_SITECOM_PID) - port->bulk_out_size = 16; - - /* Do a defined restart: the normal serial device seems to - * always turn on DTR and RTS here, so do the same. I'm not - * sure if this is really necessary. But it should not harm - * either. - */ - spin_lock_irqsave(&priv->lock, flags); - if (tty && (tty->termios->c_cflag & CBAUD)) - priv->control_state = TIOCM_DTR | TIOCM_RTS; - else - priv->control_state = 0; - - priv->last_lcr = (MCT_U232_DATA_BITS_8 | - MCT_U232_PARITY_NONE | - MCT_U232_STOP_BITS_1); - control_state = priv->control_state; - last_lcr = priv->last_lcr; - spin_unlock_irqrestore(&priv->lock, flags); - mct_u232_set_modem_ctrl(serial, control_state); - mct_u232_set_line_ctrl(serial, last_lcr); - - /* Read modem status and update control state */ - mct_u232_get_modem_stat(serial, &last_msr); - spin_lock_irqsave(&priv->lock, flags); - priv->last_msr = last_msr; - mct_u232_msr_to_state(&priv->control_state, priv->last_msr); - spin_unlock_irqrestore(&priv->lock, flags); - - retval = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (retval) { - dev_err(&port->dev, - "usb_submit_urb(read bulk) failed pipe 0x%x err %d\n", - port->read_urb->pipe, retval); - goto error; - } - - retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - if (retval) { - usb_kill_urb(port->read_urb); - dev_err(&port->dev, - "usb_submit_urb(read int) failed pipe 0x%x err %d", - port->interrupt_in_urb->pipe, retval); - goto error; - } - return 0; - -error: - return retval; -} /* mct_u232_open */ - -static void mct_u232_dtr_rts(struct usb_serial_port *port, int on) -{ - unsigned int control_state; - struct mct_u232_private *priv = usb_get_serial_port_data(port); - - mutex_lock(&port->serial->disc_mutex); - if (!port->serial->disconnected) { - /* drop DTR and RTS */ - spin_lock_irq(&priv->lock); - if (on) - priv->control_state |= TIOCM_DTR | TIOCM_RTS; - else - priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); - control_state = priv->control_state; - spin_unlock_irq(&priv->lock); - mct_u232_set_modem_ctrl(port->serial, control_state); - } - mutex_unlock(&port->serial->disc_mutex); -} - -static void mct_u232_close(struct usb_serial_port *port) -{ - dbg("%s port %d", __func__, port->number); - - if (port->serial->dev) { - /* shutdown our urbs */ - usb_kill_urb(port->write_urb); - usb_kill_urb(port->read_urb); - usb_kill_urb(port->interrupt_in_urb); - } -} /* mct_u232_close */ - - -static void mct_u232_read_int_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct mct_u232_private *priv = usb_get_serial_port_data(port); - struct usb_serial *serial = port->serial; - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - int retval; - int status = urb->status; - unsigned long flags; - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); - return; - default: - dbg("%s - nonzero urb status received: %d", - __func__, status); - goto exit; - } - - if (!serial) { - dbg("%s - bad serial pointer, exiting", __func__); - return; - } - - dbg("%s - port %d", __func__, port->number); - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); - - /* - * Work-a-round: handle the 'usual' bulk-in pipe here - */ - if (urb->transfer_buffer_length > 2) { - if (urb->actual_length) { - tty = tty_port_tty_get(&port->port); - if (tty) { - tty_insert_flip_string(tty, data, - urb->actual_length); - tty_flip_buffer_push(tty); - } - tty_kref_put(tty); - } - goto exit; - } - - /* - * The interrupt-in pipe signals exceptional conditions (modem line - * signal changes and errors). data[0] holds MSR, data[1] holds LSR. - */ - spin_lock_irqsave(&priv->lock, flags); - priv->last_msr = data[MCT_U232_MSR_INDEX]; - - /* Record Control Line states */ - mct_u232_msr_to_state(&priv->control_state, priv->last_msr); - - mct_u232_msr_to_icount(&priv->icount, priv->last_msr); - -#if 0 - /* Not yet handled. See belkin_sa.c for further information */ - /* Now to report any errors */ - priv->last_lsr = data[MCT_U232_LSR_INDEX]; - /* - * fill in the flip buffer here, but I do not know the relation - * to the current/next receive buffer or characters. I need - * to look in to this before committing any code. - */ - if (priv->last_lsr & MCT_U232_LSR_ERR) { - tty = tty_port_tty_get(&port->port); - /* Overrun Error */ - if (priv->last_lsr & MCT_U232_LSR_OE) { - } - /* Parity Error */ - if (priv->last_lsr & MCT_U232_LSR_PE) { - } - /* Framing Error */ - if (priv->last_lsr & MCT_U232_LSR_FE) { - } - /* Break Indicator */ - if (priv->last_lsr & MCT_U232_LSR_BI) { - } - tty_kref_put(tty); - } -#endif - wake_up_interruptible(&priv->msr_wait); - spin_unlock_irqrestore(&priv->lock, flags); -exit: - retval = usb_submit_urb(urb, GFP_ATOMIC); - if (retval) - dev_err(&port->dev, - "%s - usb_submit_urb failed with result %d\n", - __func__, retval); -} /* mct_u232_read_int_callback */ - -static void mct_u232_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old_termios) -{ - struct usb_serial *serial = port->serial; - struct mct_u232_private *priv = usb_get_serial_port_data(port); - struct ktermios *termios = tty->termios; - unsigned int cflag = termios->c_cflag; - unsigned int old_cflag = old_termios->c_cflag; - unsigned long flags; - unsigned int control_state; - unsigned char last_lcr; - - /* get a local copy of the current port settings */ - spin_lock_irqsave(&priv->lock, flags); - control_state = priv->control_state; - spin_unlock_irqrestore(&priv->lock, flags); - last_lcr = 0; - - /* - * Update baud rate. - * Do not attempt to cache old rates and skip settings, - * disconnects screw such tricks up completely. - * Premature optimization is the root of all evil. - */ - - /* reassert DTR and RTS on transition from B0 */ - if ((old_cflag & CBAUD) == B0) { - dbg("%s: baud was B0", __func__); - control_state |= TIOCM_DTR | TIOCM_RTS; - mct_u232_set_modem_ctrl(serial, control_state); - } - - mct_u232_set_baud_rate(tty, serial, port, tty_get_baud_rate(tty)); - - if ((cflag & CBAUD) == B0) { - dbg("%s: baud is B0", __func__); - /* Drop RTS and DTR */ - control_state &= ~(TIOCM_DTR | TIOCM_RTS); - mct_u232_set_modem_ctrl(serial, control_state); - } - - /* - * Update line control register (LCR) - */ - - /* set the parity */ - if (cflag & PARENB) - last_lcr |= (cflag & PARODD) ? - MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN; - else - last_lcr |= MCT_U232_PARITY_NONE; - - /* set the number of data bits */ - switch (cflag & CSIZE) { - case CS5: - last_lcr |= MCT_U232_DATA_BITS_5; break; - case CS6: - last_lcr |= MCT_U232_DATA_BITS_6; break; - case CS7: - last_lcr |= MCT_U232_DATA_BITS_7; break; - case CS8: - last_lcr |= MCT_U232_DATA_BITS_8; break; - default: - dev_err(&port->dev, - "CSIZE was not CS5-CS8, using default of 8\n"); - last_lcr |= MCT_U232_DATA_BITS_8; - break; - } - - termios->c_cflag &= ~CMSPAR; - - /* set the number of stop bits */ - last_lcr |= (cflag & CSTOPB) ? - MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1; - - mct_u232_set_line_ctrl(serial, last_lcr); - - /* save off the modified port settings */ - spin_lock_irqsave(&priv->lock, flags); - priv->control_state = control_state; - priv->last_lcr = last_lcr; - spin_unlock_irqrestore(&priv->lock, flags); -} /* mct_u232_set_termios */ - -static void mct_u232_break_ctl(struct tty_struct *tty, int break_state) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; - struct mct_u232_private *priv = usb_get_serial_port_data(port); - unsigned char lcr; - unsigned long flags; - - dbg("%sstate=%d", __func__, break_state); - - spin_lock_irqsave(&priv->lock, flags); - lcr = priv->last_lcr; - - if (break_state) - lcr |= MCT_U232_SET_BREAK; - spin_unlock_irqrestore(&priv->lock, flags); - - mct_u232_set_line_ctrl(serial, lcr); -} /* mct_u232_break_ctl */ - - -static int mct_u232_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct mct_u232_private *priv = usb_get_serial_port_data(port); - unsigned int control_state; - unsigned long flags; - - dbg("%s", __func__); - - spin_lock_irqsave(&priv->lock, flags); - control_state = priv->control_state; - spin_unlock_irqrestore(&priv->lock, flags); - - return control_state; -} - -static int mct_u232_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; - struct mct_u232_private *priv = usb_get_serial_port_data(port); - unsigned int control_state; - unsigned long flags; - - dbg("%s", __func__); - - spin_lock_irqsave(&priv->lock, flags); - control_state = priv->control_state; - - if (set & TIOCM_RTS) - control_state |= TIOCM_RTS; - if (set & TIOCM_DTR) - control_state |= TIOCM_DTR; - if (clear & TIOCM_RTS) - control_state &= ~TIOCM_RTS; - if (clear & TIOCM_DTR) - control_state &= ~TIOCM_DTR; - - priv->control_state = control_state; - spin_unlock_irqrestore(&priv->lock, flags); - return mct_u232_set_modem_ctrl(serial, control_state); -} - -static void mct_u232_throttle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct mct_u232_private *priv = usb_get_serial_port_data(port); - unsigned int control_state; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irq(&priv->lock); - priv->rx_flags |= THROTTLED; - if (C_CRTSCTS(tty)) { - priv->control_state &= ~TIOCM_RTS; - control_state = priv->control_state; - spin_unlock_irq(&priv->lock); - (void) mct_u232_set_modem_ctrl(port->serial, control_state); - } else { - spin_unlock_irq(&priv->lock); - } -} - -static void mct_u232_unthrottle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct mct_u232_private *priv = usb_get_serial_port_data(port); - unsigned int control_state; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irq(&priv->lock); - if ((priv->rx_flags & THROTTLED) && C_CRTSCTS(tty)) { - priv->rx_flags &= ~THROTTLED; - priv->control_state |= TIOCM_RTS; - control_state = priv->control_state; - spin_unlock_irq(&priv->lock); - (void) mct_u232_set_modem_ctrl(port->serial, control_state); - } else { - spin_unlock_irq(&priv->lock); - } -} - -static int mct_u232_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - DEFINE_WAIT(wait); - struct usb_serial_port *port = tty->driver_data; - struct mct_u232_private *mct_u232_port = usb_get_serial_port_data(port); - struct async_icount cnow, cprev; - unsigned long flags; - - dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd); - - switch (cmd) { - - case TIOCMIWAIT: - - dbg("%s (%d) TIOCMIWAIT", __func__, port->number); - - spin_lock_irqsave(&mct_u232_port->lock, flags); - cprev = mct_u232_port->icount; - spin_unlock_irqrestore(&mct_u232_port->lock, flags); - for ( ; ; ) { - prepare_to_wait(&mct_u232_port->msr_wait, - &wait, TASK_INTERRUPTIBLE); - schedule(); - finish_wait(&mct_u232_port->msr_wait, &wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - spin_lock_irqsave(&mct_u232_port->lock, flags); - cnow = mct_u232_port->icount; - spin_unlock_irqrestore(&mct_u232_port->lock, flags); - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { - return 0; - } - cprev = cnow; - } - - } - return -ENOIOCTLCMD; -} - -static int mct_u232_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct mct_u232_private *mct_u232_port = usb_get_serial_port_data(port); - struct async_icount *ic = &mct_u232_port->icount; - unsigned long flags; - - spin_lock_irqsave(&mct_u232_port->lock, flags); - - icount->cts = ic->cts; - icount->dsr = ic->dsr; - icount->rng = ic->rng; - icount->dcd = ic->dcd; - icount->rx = ic->rx; - icount->tx = ic->tx; - icount->frame = ic->frame; - icount->overrun = ic->overrun; - icount->parity = ic->parity; - icount->brk = ic->brk; - icount->buf_overrun = ic->buf_overrun; - - spin_unlock_irqrestore(&mct_u232_port->lock, flags); - - dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", - __func__, port->number, icount->rx, icount->tx); - return 0; -} - -module_usb_serial_driver(mct_u232_driver, serial_drivers); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/mct_u232.h b/ANDROID_3.4.5/drivers/usb/serial/mct_u232.h deleted file mode 100644 index d325bb8c..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/mct_u232.h +++ /dev/null @@ -1,467 +0,0 @@ -/* - * Definitions for MCT (Magic Control Technology) USB-RS232 Converter Driver - * - * Copyright (C) 2000 Wolfgang Grandegger (wolfgang@ces.ch) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This driver is for the device MCT USB-RS232 Converter (25 pin, Model No. - * U232-P25) from Magic Control Technology Corp. (there is also a 9 pin - * Model No. U232-P9). See http://www.mct.com.tw/products/product_us232.html - * for further information. The properties of this device are listed at the end - * of this file. This device was used in the Dlink DSB-S25. - * - * All of the information about the device was acquired by using SniffUSB - * on Windows98. The technical details of the reverse engineering are - * summarized at the end of this file. - */ - -#ifndef __LINUX_USB_SERIAL_MCT_U232_H -#define __LINUX_USB_SERIAL_MCT_U232_H - -#define MCT_U232_VID 0x0711 /* Vendor Id */ -#define MCT_U232_PID 0x0210 /* Original MCT Product Id */ - -/* U232-P25, Sitecom */ -#define MCT_U232_SITECOM_PID 0x0230 /* Sitecom Product Id */ - -/* DU-H3SP USB BAY hub */ -#define MCT_U232_DU_H3SP_PID 0x0200 /* D-Link DU-H3SP USB BAY */ - -/* Belkin badge the MCT U232-P9 as the F5U109 */ -#define MCT_U232_BELKIN_F5U109_VID 0x050d /* Vendor Id */ -#define MCT_U232_BELKIN_F5U109_PID 0x0109 /* Product Id */ - -/* - * Vendor Request Interface - */ -#define MCT_U232_SET_REQUEST_TYPE 0x40 -#define MCT_U232_GET_REQUEST_TYPE 0xc0 - -/* Get Modem Status Register (MSR) */ -#define MCT_U232_GET_MODEM_STAT_REQUEST 2 -#define MCT_U232_GET_MODEM_STAT_SIZE 1 - -/* Get Line Control Register (LCR) */ -/* ... not used by this driver */ -#define MCT_U232_GET_LINE_CTRL_REQUEST 6 -#define MCT_U232_GET_LINE_CTRL_SIZE 1 - -/* Set Baud Rate Divisor */ -#define MCT_U232_SET_BAUD_RATE_REQUEST 5 -#define MCT_U232_SET_BAUD_RATE_SIZE 4 - -/* Set Line Control Register (LCR) */ -#define MCT_U232_SET_LINE_CTRL_REQUEST 7 -#define MCT_U232_SET_LINE_CTRL_SIZE 1 - -/* Set Modem Control Register (MCR) */ -#define MCT_U232_SET_MODEM_CTRL_REQUEST 10 -#define MCT_U232_SET_MODEM_CTRL_SIZE 1 - -/* - * This USB device request code is not well understood. It is transmitted by - * the MCT-supplied Windows driver whenever the baud rate changes. - */ -#define MCT_U232_SET_UNKNOWN1_REQUEST 11 /* Unknown functionality */ -#define MCT_U232_SET_UNKNOWN1_SIZE 1 - -/* - * This USB device request code appears to control whether CTS is required - * during transmission. - * - * Sending a zero byte allows data transmission to a device which is not - * asserting CTS. Sending a '1' byte will cause transmission to be deferred - * until the device asserts CTS. - */ -#define MCT_U232_SET_CTS_REQUEST 12 -#define MCT_U232_SET_CTS_SIZE 1 - -#define MCT_U232_MAX_SIZE 4 /* of MCT_XXX_SIZE */ - -/* - * Baud rate (divisor) - * Actually, there are two of them, MCT website calls them "Philips solution" - * and "Intel solution". They are the regular MCT and "Sitecom" for us. - * This is pointless to document in the header, see the code for the bits. - */ -static int mct_u232_calculate_baud_rate(struct usb_serial *serial, - speed_t value, speed_t *result); - -/* - * Line Control Register (LCR) - */ -#define MCT_U232_SET_BREAK 0x40 - -#define MCT_U232_PARITY_SPACE 0x38 -#define MCT_U232_PARITY_MARK 0x28 -#define MCT_U232_PARITY_EVEN 0x18 -#define MCT_U232_PARITY_ODD 0x08 -#define MCT_U232_PARITY_NONE 0x00 - -#define MCT_U232_DATA_BITS_5 0x00 -#define MCT_U232_DATA_BITS_6 0x01 -#define MCT_U232_DATA_BITS_7 0x02 -#define MCT_U232_DATA_BITS_8 0x03 - -#define MCT_U232_STOP_BITS_2 0x04 -#define MCT_U232_STOP_BITS_1 0x00 - -/* - * Modem Control Register (MCR) - */ -#define MCT_U232_MCR_NONE 0x8 /* Deactivate DTR and RTS */ -#define MCT_U232_MCR_RTS 0xa /* Activate RTS */ -#define MCT_U232_MCR_DTR 0x9 /* Activate DTR */ - -/* - * Modem Status Register (MSR) - */ -#define MCT_U232_MSR_INDEX 0x0 /* data[index] */ -#define MCT_U232_MSR_CD 0x80 /* Current CD */ -#define MCT_U232_MSR_RI 0x40 /* Current RI */ -#define MCT_U232_MSR_DSR 0x20 /* Current DSR */ -#define MCT_U232_MSR_CTS 0x10 /* Current CTS */ -#define MCT_U232_MSR_DCD 0x08 /* Delta CD */ -#define MCT_U232_MSR_DRI 0x04 /* Delta RI */ -#define MCT_U232_MSR_DDSR 0x02 /* Delta DSR */ -#define MCT_U232_MSR_DCTS 0x01 /* Delta CTS */ - -/* - * Line Status Register (LSR) - */ -#define MCT_U232_LSR_INDEX 1 /* data[index] */ -#define MCT_U232_LSR_ERR 0x80 /* OE | PE | FE | BI */ -#define MCT_U232_LSR_TEMT 0x40 /* transmit register empty */ -#define MCT_U232_LSR_THRE 0x20 /* transmit holding register empty */ -#define MCT_U232_LSR_BI 0x10 /* break indicator */ -#define MCT_U232_LSR_FE 0x08 /* framing error */ -#define MCT_U232_LSR_OE 0x02 /* overrun error */ -#define MCT_U232_LSR_PE 0x04 /* parity error */ -#define MCT_U232_LSR_OE 0x02 /* overrun error */ -#define MCT_U232_LSR_DR 0x01 /* receive data ready */ - - -/* ----------------------------------------------------------------------------- - * Technical Specification reverse engineered with SniffUSB on Windows98 - * ===================================================================== - * - * The technical details of the device have been acquired be using "SniffUSB" - * and the vendor-supplied device driver (version 2.3A) under Windows98. To - * identify the USB vendor-specific requests and to assign them to terminal - * settings (flow control, baud rate, etc.) the program "SerialSettings" from - * William G. Greathouse has been proven to be very useful. I also used the - * Win98 "HyperTerminal" and "usb-robot" on Linux for testing. The results and - * observations are summarized below: - * - * The USB requests seem to be directly mapped to the registers of a 8250, - * 16450 or 16550 UART. The FreeBSD handbook (appendix F.4 "Input/Output - * devices") contains a comprehensive description of UARTs and its registers. - * The bit descriptions are actually taken from there. - * - * - * Baud rate (divisor) - * ------------------- - * - * BmRequestType: 0x40 (0100 0000B) - * bRequest: 0x05 - * wValue: 0x0000 - * wIndex: 0x0000 - * wLength: 0x0004 - * Data: divisor = 115200 / baud_rate - * - * SniffUSB observations (Nov 2003): Contrary to the 'wLength' value of 4 - * shown above, observations with a Belkin F5U109 adapter, using the - * MCT-supplied Windows98 driver (U2SPORT.VXD, "File version: 1.21P.0104 for - * Win98/Me"), show this request has a length of 1 byte, presumably because - * of the fact that the Belkin adapter and the 'Sitecom U232-P25' adapter - * use a baud-rate code instead of a conventional RS-232 baud rate divisor. - * The current source code for this driver does not reflect this fact, but - * the driver works fine with this adapter/driver combination nonetheless. - * - * - * Line Control Register (LCR) - * --------------------------- - * - * BmRequestType: 0x40 (0100 0000B) 0xc0 (1100 0000B) - * bRequest: 0x07 0x06 - * wValue: 0x0000 - * wIndex: 0x0000 - * wLength: 0x0001 - * Data: LCR (see below) - * - * Bit 7: Divisor Latch Access Bit (DLAB). When set, access to the data - * transmit/receive register (THR/RBR) and the Interrupt Enable Register - * (IER) is disabled. Any access to these ports is now redirected to the - * Divisor Latch Registers. Setting this bit, loading the Divisor - * Registers, and clearing DLAB should be done with interrupts disabled. - * Bit 6: Set Break. When set to "1", the transmitter begins to transmit - * continuous Spacing until this bit is set to "0". This overrides any - * bits of characters that are being transmitted. - * Bit 5: Stick Parity. When parity is enabled, setting this bit causes parity - * to always be "1" or "0", based on the value of Bit 4. - * Bit 4: Even Parity Select (EPS). When parity is enabled and Bit 5 is "0", - * setting this bit causes even parity to be transmitted and expected. - * Otherwise, odd parity is used. - * Bit 3: Parity Enable (PEN). When set to "1", a parity bit is inserted - * between the last bit of the data and the Stop Bit. The UART will also - * expect parity to be present in the received data. - * Bit 2: Number of Stop Bits (STB). If set to "1" and using 5-bit data words, - * 1.5 Stop Bits are transmitted and expected in each data word. For - * 6, 7 and 8-bit data words, 2 Stop Bits are transmitted and expected. - * When this bit is set to "0", one Stop Bit is used on each data word. - * Bit 1: Word Length Select Bit #1 (WLSB1) - * Bit 0: Word Length Select Bit #0 (WLSB0) - * Together these bits specify the number of bits in each data word. - * 1 0 Word Length - * 0 0 5 Data Bits - * 0 1 6 Data Bits - * 1 0 7 Data Bits - * 1 1 8 Data Bits - * - * SniffUSB observations: Bit 7 seems not to be used. There seem to be two bugs - * in the Win98 driver: the break does not work (bit 6 is not asserted) and the - * stick parity bit is not cleared when set once. The LCR can also be read - * back with USB request 6 but this has never been observed with SniffUSB. - * - * - * Modem Control Register (MCR) - * ---------------------------- - * - * BmRequestType: 0x40 (0100 0000B) - * bRequest: 0x0a - * wValue: 0x0000 - * wIndex: 0x0000 - * wLength: 0x0001 - * Data: MCR (Bit 4..7, see below) - * - * Bit 7: Reserved, always 0. - * Bit 6: Reserved, always 0. - * Bit 5: Reserved, always 0. - * Bit 4: Loop-Back Enable. When set to "1", the UART transmitter and receiver - * are internally connected together to allow diagnostic operations. In - * addition, the UART modem control outputs are connected to the UART - * modem control inputs. CTS is connected to RTS, DTR is connected to - * DSR, OUT1 is connected to RI, and OUT 2 is connected to DCD. - * Bit 3: OUT 2. An auxiliary output that the host processor may set high or - * low. In the IBM PC serial adapter (and most clones), OUT 2 is used - * to tri-state (disable) the interrupt signal from the - * 8250/16450/16550 UART. - * Bit 2: OUT 1. An auxiliary output that the host processor may set high or - * low. This output is not used on the IBM PC serial adapter. - * Bit 1: Request to Send (RTS). When set to "1", the output of the UART -RTS - * line is Low (Active). - * Bit 0: Data Terminal Ready (DTR). When set to "1", the output of the UART - * -DTR line is Low (Active). - * - * SniffUSB observations: Bit 2 and 4 seem not to be used but bit 3 has been - * seen _always_ set. - * - * - * Modem Status Register (MSR) - * --------------------------- - * - * BmRequestType: 0xc0 (1100 0000B) - * bRequest: 0x02 - * wValue: 0x0000 - * wIndex: 0x0000 - * wLength: 0x0001 - * Data: MSR (see below) - * - * Bit 7: Data Carrier Detect (CD). Reflects the state of the DCD line on the - * UART. - * Bit 6: Ring Indicator (RI). Reflects the state of the RI line on the UART. - * Bit 5: Data Set Ready (DSR). Reflects the state of the DSR line on the UART. - * Bit 4: Clear To Send (CTS). Reflects the state of the CTS line on the UART. - * Bit 3: Delta Data Carrier Detect (DDCD). Set to "1" if the -DCD line has - * changed state one more more times since the last time the MSR was - * read by the host. - * Bit 2: Trailing Edge Ring Indicator (TERI). Set to "1" if the -RI line has - * had a low to high transition since the last time the MSR was read by - * the host. - * Bit 1: Delta Data Set Ready (DDSR). Set to "1" if the -DSR line has changed - * state one more more times since the last time the MSR was read by the - * host. - * Bit 0: Delta Clear To Send (DCTS). Set to "1" if the -CTS line has changed - * state one more times since the last time the MSR was read by the - * host. - * - * SniffUSB observations: the MSR is also returned as first byte on the - * interrupt-in endpoint 0x83 to signal changes of modem status lines. The USB - * request to read MSR cannot be applied during normal device operation. - * - * - * Line Status Register (LSR) - * -------------------------- - * - * Bit 7 Error in Receiver FIFO. On the 8250/16450 UART, this bit is zero. - * This bit is set to "1" when any of the bytes in the FIFO have one - * or more of the following error conditions: PE, FE, or BI. - * Bit 6 Transmitter Empty (TEMT). When set to "1", there are no words - * remaining in the transmit FIFO or the transmit shift register. The - * transmitter is completely idle. - * Bit 5 Transmitter Holding Register Empty (THRE). When set to "1", the - * FIFO (or holding register) now has room for at least one additional - * word to transmit. The transmitter may still be transmitting when - * this bit is set to "1". - * Bit 4 Break Interrupt (BI). The receiver has detected a Break signal. - * Bit 3 Framing Error (FE). A Start Bit was detected but the Stop Bit did - * not appear at the expected time. The received word is probably - * garbled. - * Bit 2 Parity Error (PE). The parity bit was incorrect for the word - * received. - * Bit 1 Overrun Error (OE). A new word was received and there was no room - * in the receive buffer. The newly-arrived word in the shift register - * is discarded. On 8250/16450 UARTs, the word in the holding register - * is discarded and the newly- arrived word is put in the holding - * register. - * Bit 0 Data Ready (DR). One or more words are in the receive FIFO that the - * host may read. A word must be completely received and moved from - * the shift register into the FIFO (or holding register for - * 8250/16450 designs) before this bit is set. - * - * SniffUSB observations: the LSR is returned as second byte on the - * interrupt-in endpoint 0x83 to signal error conditions. Such errors have - * been seen with minicom/zmodem transfers (CRC errors). - * - * - * Unknown #1 - * ------------------- - * - * BmRequestType: 0x40 (0100 0000B) - * bRequest: 0x0b - * wValue: 0x0000 - * wIndex: 0x0000 - * wLength: 0x0001 - * Data: 0x00 - * - * SniffUSB observations (Nov 2003): With the MCT-supplied Windows98 driver - * (U2SPORT.VXD, "File version: 1.21P.0104 for Win98/Me"), this request - * occurs immediately after a "Baud rate (divisor)" message. It was not - * observed at any other time. It is unclear what purpose this message - * serves. - * - * - * Unknown #2 - * ------------------- - * - * BmRequestType: 0x40 (0100 0000B) - * bRequest: 0x0c - * wValue: 0x0000 - * wIndex: 0x0000 - * wLength: 0x0001 - * Data: 0x00 - * - * SniffUSB observations (Nov 2003): With the MCT-supplied Windows98 driver - * (U2SPORT.VXD, "File version: 1.21P.0104 for Win98/Me"), this request - * occurs immediately after the 'Unknown #1' message (see above). It was - * not observed at any other time. It is unclear what other purpose (if - * any) this message might serve, but without it, the USB/RS-232 adapter - * will not write to RS-232 devices which do not assert the 'CTS' signal. - * - * - * Flow control - * ------------ - * - * SniffUSB observations: no flow control specific requests have been realized - * apart from DTR/RTS settings. Both signals are dropped for no flow control - * but asserted for hardware or software flow control. - * - * - * Endpoint usage - * -------------- - * - * SniffUSB observations: the bulk-out endpoint 0x1 and interrupt-in endpoint - * 0x81 is used to transmit and receive characters. The second interrupt-in - * endpoint 0x83 signals exceptional conditions like modem line changes and - * errors. The first byte returned is the MSR and the second byte the LSR. - * - * - * Other observations - * ------------------ - * - * Queued bulk transfers like used in visor.c did not work. - * - * - * Properties of the USB device used (as found in /var/log/messages) - * ----------------------------------------------------------------- - * - * Manufacturer: MCT Corporation. - * Product: USB-232 Interfact Controller - * SerialNumber: U2S22050 - * - * Length = 18 - * DescriptorType = 01 - * USB version = 1.00 - * Vendor:Product = 0711:0210 - * MaxPacketSize0 = 8 - * NumConfigurations = 1 - * Device version = 1.02 - * Device Class:SubClass:Protocol = 00:00:00 - * Per-interface classes - * Configuration: - * bLength = 9 - * bDescriptorType = 02 - * wTotalLength = 0027 - * bNumInterfaces = 01 - * bConfigurationValue = 01 - * iConfiguration = 00 - * bmAttributes = c0 - * MaxPower = 100mA - * - * Interface: 0 - * Alternate Setting: 0 - * bLength = 9 - * bDescriptorType = 04 - * bInterfaceNumber = 00 - * bAlternateSetting = 00 - * bNumEndpoints = 03 - * bInterface Class:SubClass:Protocol = 00:00:00 - * iInterface = 00 - * Endpoint: - * bLength = 7 - * bDescriptorType = 05 - * bEndpointAddress = 81 (in) - * bmAttributes = 03 (Interrupt) - * wMaxPacketSize = 0040 - * bInterval = 02 - * Endpoint: - * bLength = 7 - * bDescriptorType = 05 - * bEndpointAddress = 01 (out) - * bmAttributes = 02 (Bulk) - * wMaxPacketSize = 0040 - * bInterval = 00 - * Endpoint: - * bLength = 7 - * bDescriptorType = 05 - * bEndpointAddress = 83 (in) - * bmAttributes = 03 (Interrupt) - * wMaxPacketSize = 0002 - * bInterval = 02 - * - * - * Hardware details (added by Martin Hamilton, 2001/12/06) - * ----------------------------------------------------------------- - * - * This info was gleaned from opening a Belkin F5U109 DB9 USB serial - * adaptor, which turns out to simply be a re-badged U232-P9. We - * know this because there is a sticky label on the circuit board - * which says "U232-P9" ;-) - * - * The circuit board inside the adaptor contains a Philips PDIUSBD12 - * USB endpoint chip and a Philips P87C52UBAA microcontroller with - * embedded UART. Exhaustive documentation for these is available at: - * - * http://www.semiconductors.philips.com/pip/p87c52ubaa - * http://www.nxp.com/acrobat_download/various/PDIUSBD12_PROGRAMMING_GUIDE.pdf - * - * Thanks to Julian Highfield for the pointer to the Philips database. - * - */ - -#endif /* __LINUX_USB_SERIAL_MCT_U232_H */ - diff --git a/ANDROID_3.4.5/drivers/usb/serial/metro-usb.c b/ANDROID_3.4.5/drivers/usb/serial/metro-usb.c deleted file mode 100644 index 7c14671d..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/metro-usb.c +++ /dev/null @@ -1,394 +0,0 @@ -/* - Some of this code is credited to Linux USB open source files that are - distributed with Linux. - - Copyright: 2007 Metrologic Instruments. All rights reserved. - Copyright: 2011 Azimut Ltd. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Version Information */ -#define DRIVER_VERSION "v1.2.0.0" -#define DRIVER_DESC "Metrologic Instruments Inc. - USB-POS driver" - -/* Product information. */ -#define FOCUS_VENDOR_ID 0x0C2E -#define FOCUS_PRODUCT_ID_BI 0x0720 -#define FOCUS_PRODUCT_ID_UNI 0x0700 - -#define METROUSB_SET_REQUEST_TYPE 0x40 -#define METROUSB_SET_MODEM_CTRL_REQUEST 10 -#define METROUSB_SET_BREAK_REQUEST 0x40 -#define METROUSB_MCR_NONE 0x08 /* Deactivate DTR and RTS. */ -#define METROUSB_MCR_RTS 0x0a /* Activate RTS. */ -#define METROUSB_MCR_DTR 0x09 /* Activate DTR. */ -#define WDR_TIMEOUT 5000 /* default urb timeout. */ - -/* Private data structure. */ -struct metrousb_private { - spinlock_t lock; - int throttled; - unsigned long control_state; -}; - -/* Device table list. */ -static struct usb_device_id id_table[] = { - { USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_BI) }, - { USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_UNI) }, - { }, /* Terminating entry. */ -}; -MODULE_DEVICE_TABLE(usb, id_table); - -/* Input parameter constants. */ -static bool debug; - -static void metrousb_read_int_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct metrousb_private *metro_priv = usb_get_serial_port_data(port); - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - int throttled = 0; - int result = 0; - unsigned long flags = 0; - - dev_dbg(&port->dev, "%s\n", __func__); - - switch (urb->status) { - case 0: - /* Success status, read from the port. */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* urb has been terminated. */ - dev_dbg(&port->dev, - "%s - urb shutting down, error code=%d\n", - __func__, result); - return; - default: - dev_dbg(&port->dev, - "%s - non-zero urb received, error code=%d\n", - __func__, result); - goto exit; - } - - - /* Set the data read from the usb port into the serial port buffer. */ - tty = tty_port_tty_get(&port->port); - if (!tty) { - dev_dbg(&port->dev, "%s - bad tty pointer - exiting\n", - __func__); - return; - } - - if (tty && urb->actual_length) { - /* Loop through the data copying each byte to the tty layer. */ - tty_insert_flip_string(tty, data, urb->actual_length); - - /* Force the data to the tty layer. */ - tty_flip_buffer_push(tty); - } - tty_kref_put(tty); - - /* Set any port variables. */ - spin_lock_irqsave(&metro_priv->lock, flags); - throttled = metro_priv->throttled; - spin_unlock_irqrestore(&metro_priv->lock, flags); - - /* Continue trying to read if set. */ - if (!throttled) { - usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev, - usb_rcvintpipe(port->serial->dev, port->interrupt_in_endpointAddress), - port->interrupt_in_urb->transfer_buffer, - port->interrupt_in_urb->transfer_buffer_length, - metrousb_read_int_callback, port, 1); - - result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); - - if (result) - dev_dbg(&port->dev, - "%s - failed submitting interrupt in urb, error code=%d\n", - __func__, result); - } - return; - -exit: - /* Try to resubmit the urb. */ - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) - dev_dbg(&port->dev, - "%s - failed submitting interrupt in urb, error code=%d\n", - __func__, result); -} - -static void metrousb_cleanup(struct usb_serial_port *port) -{ - dev_dbg(&port->dev, "%s\n", __func__); - - if (port->serial->dev) { - /* Shutdown any interrupt in urbs. */ - if (port->interrupt_in_urb) { - usb_unlink_urb(port->interrupt_in_urb); - usb_kill_urb(port->interrupt_in_urb); - } - } -} - -static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - struct metrousb_private *metro_priv = usb_get_serial_port_data(port); - unsigned long flags = 0; - int result = 0; - - dev_dbg(&port->dev, "%s\n", __func__); - - /* Make sure the urb is initialized. */ - if (!port->interrupt_in_urb) { - dev_dbg(&port->dev, "%s - interrupt urb not initialized\n", - __func__); - return -ENODEV; - } - - /* Set the private data information for the port. */ - spin_lock_irqsave(&metro_priv->lock, flags); - metro_priv->control_state = 0; - metro_priv->throttled = 0; - spin_unlock_irqrestore(&metro_priv->lock, flags); - - /* Clear the urb pipe. */ - usb_clear_halt(serial->dev, port->interrupt_in_urb->pipe); - - /* Start reading from the device */ - usb_fill_int_urb(port->interrupt_in_urb, serial->dev, - usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress), - port->interrupt_in_urb->transfer_buffer, - port->interrupt_in_urb->transfer_buffer_length, - metrousb_read_int_callback, port, 1); - result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - - if (result) { - dev_dbg(&port->dev, - "%s - failed submitting interrupt in urb, error code=%d\n", - __func__, result); - goto exit; - } - - dev_dbg(&port->dev, "%s - port open\n", __func__); -exit: - return result; -} - -static int metrousb_set_modem_ctrl(struct usb_serial *serial, unsigned int control_state) -{ - int retval = 0; - unsigned char mcr = METROUSB_MCR_NONE; - - dev_dbg(&serial->dev->dev, "%s - control state = %d\n", - __func__, control_state); - - /* Set the modem control value. */ - if (control_state & TIOCM_DTR) - mcr |= METROUSB_MCR_DTR; - if (control_state & TIOCM_RTS) - mcr |= METROUSB_MCR_RTS; - - /* Send the command to the usb port. */ - retval = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - METROUSB_SET_REQUEST_TYPE, METROUSB_SET_MODEM_CTRL_REQUEST, - control_state, 0, NULL, 0, WDR_TIMEOUT); - if (retval < 0) - dev_dbg(&serial->dev->dev, - "%s - set modem ctrl=0x%x failed, error code=%d\n", - __func__, mcr, retval); - - return retval; -} - -static void metrousb_shutdown(struct usb_serial *serial) -{ - int i = 0; - - dev_dbg(&serial->dev->dev, "%s\n", __func__); - - /* Stop reading and writing on all ports. */ - for (i = 0; i < serial->num_ports; ++i) { - /* Close any open urbs. */ - metrousb_cleanup(serial->port[i]); - - /* Free memory. */ - kfree(usb_get_serial_port_data(serial->port[i])); - usb_set_serial_port_data(serial->port[i], NULL); - - dev_dbg(&serial->dev->dev, "%s - freed port number=%d\n", - __func__, serial->port[i]->number); - } -} - -static int metrousb_startup(struct usb_serial *serial) -{ - struct metrousb_private *metro_priv; - struct usb_serial_port *port; - int i = 0; - - dev_dbg(&serial->dev->dev, "%s\n", __func__); - - /* Loop through the serial ports setting up the private structures. - * Currently we only use one port. */ - for (i = 0; i < serial->num_ports; ++i) { - port = serial->port[i]; - - /* Declare memory. */ - metro_priv = kzalloc(sizeof(struct metrousb_private), GFP_KERNEL); - if (!metro_priv) - return -ENOMEM; - - /* Initialize memory. */ - spin_lock_init(&metro_priv->lock); - usb_set_serial_port_data(port, metro_priv); - - dev_dbg(&serial->dev->dev, "%s - port number=%d\n ", - __func__, port->number); - } - - return 0; -} - -static void metrousb_throttle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct metrousb_private *metro_priv = usb_get_serial_port_data(port); - unsigned long flags = 0; - - dev_dbg(tty->dev, "%s\n", __func__); - - /* Set the private information for the port to stop reading data. */ - spin_lock_irqsave(&metro_priv->lock, flags); - metro_priv->throttled = 1; - spin_unlock_irqrestore(&metro_priv->lock, flags); -} - -static int metrousb_tiocmget(struct tty_struct *tty) -{ - unsigned long control_state = 0; - struct usb_serial_port *port = tty->driver_data; - struct metrousb_private *metro_priv = usb_get_serial_port_data(port); - unsigned long flags = 0; - - dev_dbg(tty->dev, "%s\n", __func__); - - spin_lock_irqsave(&metro_priv->lock, flags); - control_state = metro_priv->control_state; - spin_unlock_irqrestore(&metro_priv->lock, flags); - - return control_state; -} - -static int metrousb_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; - struct metrousb_private *metro_priv = usb_get_serial_port_data(port); - unsigned long flags = 0; - unsigned long control_state = 0; - - dev_dbg(tty->dev, "%s - set=%d, clear=%d\n", __func__, set, clear); - - spin_lock_irqsave(&metro_priv->lock, flags); - control_state = metro_priv->control_state; - - /* Set the RTS and DTR values. */ - if (set & TIOCM_RTS) - control_state |= TIOCM_RTS; - if (set & TIOCM_DTR) - control_state |= TIOCM_DTR; - if (clear & TIOCM_RTS) - control_state &= ~TIOCM_RTS; - if (clear & TIOCM_DTR) - control_state &= ~TIOCM_DTR; - - metro_priv->control_state = control_state; - spin_unlock_irqrestore(&metro_priv->lock, flags); - return metrousb_set_modem_ctrl(serial, control_state); -} - -static void metrousb_unthrottle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct metrousb_private *metro_priv = usb_get_serial_port_data(port); - unsigned long flags = 0; - int result = 0; - - dev_dbg(tty->dev, "%s\n", __func__); - - /* Set the private information for the port to resume reading data. */ - spin_lock_irqsave(&metro_priv->lock, flags); - metro_priv->throttled = 0; - spin_unlock_irqrestore(&metro_priv->lock, flags); - - /* Submit the urb to read from the port. */ - port->interrupt_in_urb->dev = port->serial->dev; - result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); - if (result) - dev_dbg(tty->dev, - "failed submitting interrupt in urb error code=%d\n", - result); -} - -static struct usb_driver metrousb_driver = { - .name = "metro-usb", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table -}; - -static struct usb_serial_driver metrousb_device = { - .driver = { - .owner = THIS_MODULE, - .name = "metro-usb", - }, - .description = "Metrologic USB to serial converter.", - .id_table = id_table, - .num_ports = 1, - .open = metrousb_open, - .close = metrousb_cleanup, - .read_int_callback = metrousb_read_int_callback, - .attach = metrousb_startup, - .release = metrousb_shutdown, - .throttle = metrousb_throttle, - .unthrottle = metrousb_unthrottle, - .tiocmget = metrousb_tiocmget, - .tiocmset = metrousb_tiocmset, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &metrousb_device, - NULL, -}; - -module_usb_serial_driver(metrousb_driver, serial_drivers); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Philip Nicastro"); -MODULE_AUTHOR("Aleksey Babahin "); -MODULE_DESCRIPTION(DRIVER_DESC); - -/* Module input parameters */ -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Print debug info (bool 1=on, 0=off)"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/mos7720.c b/ANDROID_3.4.5/drivers/usb/serial/mos7720.c deleted file mode 100644 index bdce8203..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/mos7720.c +++ /dev/null @@ -1,2213 +0,0 @@ -/* - * mos7720.c - * Controls the Moschip 7720 usb to dual port serial convertor - * - * Copyright 2006 Moschip Semiconductor Tech. Ltd. - * - * 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, version 2 of the License. - * - * Developed by: - * Vijaya Kumar - * Ajay Kumar - * Gurudeva - * - * Cleaned up from the original by: - * Greg Kroah-Hartman - * - * Originally based on drivers/usb/serial/io_edgeport.c which is: - * Copyright (C) 2000 Inside Out Networks, All rights reserved. - * Copyright (C) 2001-2002 Greg Kroah-Hartman - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Version Information - */ -#define DRIVER_VERSION "2.1" -#define DRIVER_AUTHOR "Aspire Communications pvt Ltd." -#define DRIVER_DESC "Moschip USB Serial Driver" - -/* default urb timeout */ -#define MOS_WDR_TIMEOUT (HZ * 5) - -#define MOS_MAX_PORT 0x02 -#define MOS_WRITE 0x0E -#define MOS_READ 0x0D - -/* Interrupt Rotinue Defines */ -#define SERIAL_IIR_RLS 0x06 -#define SERIAL_IIR_RDA 0x04 -#define SERIAL_IIR_CTI 0x0c -#define SERIAL_IIR_THR 0x02 -#define SERIAL_IIR_MS 0x00 - -#define NUM_URBS 16 /* URB Count */ -#define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */ - -/* This structure holds all of the local serial port information */ -struct moschip_port { - __u8 shadowLCR; /* last LCR value received */ - __u8 shadowMCR; /* last MCR value received */ - __u8 shadowMSR; /* last MSR value received */ - char open; - struct async_icount icount; - struct usb_serial_port *port; /* loop back to the owner */ - struct urb *write_urb_pool[NUM_URBS]; -}; - -static bool debug; - -static struct usb_serial_driver moschip7720_2port_driver; - -#define USB_VENDOR_ID_MOSCHIP 0x9710 -#define MOSCHIP_DEVICE_ID_7720 0x7720 -#define MOSCHIP_DEVICE_ID_7715 0x7715 - -static const struct usb_device_id moschip_port_id_table[] = { - { USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7720) }, - { USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7715) }, - { } /* terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, moschip_port_id_table); - -#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT - -/* initial values for parport regs */ -#define DCR_INIT_VAL 0x0c /* SLCTIN, nINIT */ -#define ECR_INIT_VAL 0x00 /* SPP mode */ - -struct urbtracker { - struct mos7715_parport *mos_parport; - struct list_head urblist_entry; - struct kref ref_count; - struct urb *urb; -}; - -enum mos7715_pp_modes { - SPP = 0<<5, - PS2 = 1<<5, /* moschip calls this 'NIBBLE' mode */ - PPF = 2<<5, /* moschip calls this 'CB-FIFO mode */ -}; - -struct mos7715_parport { - struct parport *pp; /* back to containing struct */ - struct kref ref_count; /* to instance of this struct */ - struct list_head deferred_urbs; /* list deferred async urbs */ - struct list_head active_urbs; /* list async urbs in flight */ - spinlock_t listlock; /* protects list access */ - bool msg_pending; /* usb sync call pending */ - struct completion syncmsg_compl; /* usb sync call completed */ - struct tasklet_struct urb_tasklet; /* for sending deferred urbs */ - struct usb_serial *serial; /* back to containing struct */ - __u8 shadowECR; /* parallel port regs... */ - __u8 shadowDCR; - atomic_t shadowDSR; /* updated in int-in callback */ -}; - -/* lock guards against dereferencing NULL ptr in parport ops callbacks */ -static DEFINE_SPINLOCK(release_lock); - -#endif /* CONFIG_USB_SERIAL_MOS7715_PARPORT */ - -static const unsigned int dummy; /* for clarity in register access fns */ - -enum mos_regs { - THR, /* serial port regs */ - RHR, - IER, - FCR, - ISR, - LCR, - MCR, - LSR, - MSR, - SPR, - DLL, - DLM, - DPR, /* parallel port regs */ - DSR, - DCR, - ECR, - SP1_REG, /* device control regs */ - SP2_REG, /* serial port 2 (7720 only) */ - PP_REG, - SP_CONTROL_REG, -}; - -/* - * Return the correct value for the Windex field of the setup packet - * for a control endpoint message. See the 7715 datasheet. - */ -static inline __u16 get_reg_index(enum mos_regs reg) -{ - static const __u16 mos7715_index_lookup_table[] = { - 0x00, /* THR */ - 0x00, /* RHR */ - 0x01, /* IER */ - 0x02, /* FCR */ - 0x02, /* ISR */ - 0x03, /* LCR */ - 0x04, /* MCR */ - 0x05, /* LSR */ - 0x06, /* MSR */ - 0x07, /* SPR */ - 0x00, /* DLL */ - 0x01, /* DLM */ - 0x00, /* DPR */ - 0x01, /* DSR */ - 0x02, /* DCR */ - 0x0a, /* ECR */ - 0x01, /* SP1_REG */ - 0x02, /* SP2_REG (7720 only) */ - 0x04, /* PP_REG (7715 only) */ - 0x08, /* SP_CONTROL_REG */ - }; - return mos7715_index_lookup_table[reg]; -} - -/* - * Return the correct value for the upper byte of the Wvalue field of - * the setup packet for a control endpoint message. - */ -static inline __u16 get_reg_value(enum mos_regs reg, - unsigned int serial_portnum) -{ - if (reg >= SP1_REG) /* control reg */ - return 0x0000; - - else if (reg >= DPR) /* parallel port reg (7715 only) */ - return 0x0100; - - else /* serial port reg */ - return (serial_portnum + 2) << 8; -} - -/* - * Write data byte to the specified device register. The data is embedded in - * the value field of the setup packet. serial_portnum is ignored for registers - * not specific to a particular serial port. - */ -static int write_mos_reg(struct usb_serial *serial, unsigned int serial_portnum, - enum mos_regs reg, __u8 data) -{ - struct usb_device *usbdev = serial->dev; - unsigned int pipe = usb_sndctrlpipe(usbdev, 0); - __u8 request = (__u8)0x0e; - __u8 requesttype = (__u8)0x40; - __u16 index = get_reg_index(reg); - __u16 value = get_reg_value(reg, serial_portnum) + data; - int status = usb_control_msg(usbdev, pipe, request, requesttype, value, - index, NULL, 0, MOS_WDR_TIMEOUT); - if (status < 0) - dev_err(&usbdev->dev, - "mos7720: usb_control_msg() failed: %d", status); - return status; -} - -/* - * Read data byte from the specified device register. The data returned by the - * device is embedded in the value field of the setup packet. serial_portnum is - * ignored for registers that are not specific to a particular serial port. - */ -static int read_mos_reg(struct usb_serial *serial, unsigned int serial_portnum, - enum mos_regs reg, __u8 *data) -{ - struct usb_device *usbdev = serial->dev; - unsigned int pipe = usb_rcvctrlpipe(usbdev, 0); - __u8 request = (__u8)0x0d; - __u8 requesttype = (__u8)0xc0; - __u16 index = get_reg_index(reg); - __u16 value = get_reg_value(reg, serial_portnum); - int status = usb_control_msg(usbdev, pipe, request, requesttype, value, - index, data, 1, MOS_WDR_TIMEOUT); - if (status < 0) - dev_err(&usbdev->dev, - "mos7720: usb_control_msg() failed: %d", status); - return status; -} - -#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT - -static inline int mos7715_change_mode(struct mos7715_parport *mos_parport, - enum mos7715_pp_modes mode) -{ - mos_parport->shadowECR = mode; - write_mos_reg(mos_parport->serial, dummy, ECR, mos_parport->shadowECR); - return 0; -} - -static void destroy_mos_parport(struct kref *kref) -{ - struct mos7715_parport *mos_parport = - container_of(kref, struct mos7715_parport, ref_count); - - dbg("%s called", __func__); - kfree(mos_parport); -} - -static void destroy_urbtracker(struct kref *kref) -{ - struct urbtracker *urbtrack = - container_of(kref, struct urbtracker, ref_count); - struct mos7715_parport *mos_parport = urbtrack->mos_parport; - dbg("%s called", __func__); - usb_free_urb(urbtrack->urb); - kfree(urbtrack); - kref_put(&mos_parport->ref_count, destroy_mos_parport); -} - -/* - * This runs as a tasklet when sending an urb in a non-blocking parallel - * port callback had to be deferred because the disconnect mutex could not be - * obtained at the time. - */ -static void send_deferred_urbs(unsigned long _mos_parport) -{ - int ret_val; - unsigned long flags; - struct mos7715_parport *mos_parport = (void *)_mos_parport; - struct urbtracker *urbtrack; - struct list_head *cursor, *next; - - dbg("%s called", __func__); - - /* if release function ran, game over */ - if (unlikely(mos_parport->serial == NULL)) - return; - - /* try again to get the mutex */ - if (!mutex_trylock(&mos_parport->serial->disc_mutex)) { - dbg("%s: rescheduling tasklet", __func__); - tasklet_schedule(&mos_parport->urb_tasklet); - return; - } - - /* if device disconnected, game over */ - if (unlikely(mos_parport->serial->disconnected)) { - mutex_unlock(&mos_parport->serial->disc_mutex); - return; - } - - spin_lock_irqsave(&mos_parport->listlock, flags); - if (list_empty(&mos_parport->deferred_urbs)) { - spin_unlock_irqrestore(&mos_parport->listlock, flags); - mutex_unlock(&mos_parport->serial->disc_mutex); - dbg("%s: deferred_urbs list empty", __func__); - return; - } - - /* move contents of deferred_urbs list to active_urbs list and submit */ - list_for_each_safe(cursor, next, &mos_parport->deferred_urbs) - list_move_tail(cursor, &mos_parport->active_urbs); - list_for_each_entry(urbtrack, &mos_parport->active_urbs, - urblist_entry) { - ret_val = usb_submit_urb(urbtrack->urb, GFP_ATOMIC); - dbg("%s: urb submitted", __func__); - if (ret_val) { - dev_err(&mos_parport->serial->dev->dev, - "usb_submit_urb() failed: %d", ret_val); - list_del(&urbtrack->urblist_entry); - kref_put(&urbtrack->ref_count, destroy_urbtracker); - } - } - spin_unlock_irqrestore(&mos_parport->listlock, flags); - mutex_unlock(&mos_parport->serial->disc_mutex); -} - -/* callback for parallel port control urbs submitted asynchronously */ -static void async_complete(struct urb *urb) -{ - struct urbtracker *urbtrack = urb->context; - int status = urb->status; - dbg("%s called", __func__); - if (unlikely(status)) - dbg("%s - nonzero urb status received: %d", __func__, status); - - /* remove the urbtracker from the active_urbs list */ - spin_lock(&urbtrack->mos_parport->listlock); - list_del(&urbtrack->urblist_entry); - spin_unlock(&urbtrack->mos_parport->listlock); - kref_put(&urbtrack->ref_count, destroy_urbtracker); -} - -static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport, - enum mos_regs reg, __u8 data) -{ - struct urbtracker *urbtrack; - int ret_val; - unsigned long flags; - struct usb_ctrlrequest setup; - struct usb_serial *serial = mos_parport->serial; - struct usb_device *usbdev = serial->dev; - dbg("%s called", __func__); - - /* create and initialize the control urb and containing urbtracker */ - urbtrack = kmalloc(sizeof(struct urbtracker), GFP_ATOMIC); - if (urbtrack == NULL) { - dev_err(&usbdev->dev, "out of memory"); - return -ENOMEM; - } - kref_get(&mos_parport->ref_count); - urbtrack->mos_parport = mos_parport; - urbtrack->urb = usb_alloc_urb(0, GFP_ATOMIC); - if (urbtrack->urb == NULL) { - dev_err(&usbdev->dev, "out of urbs"); - kfree(urbtrack); - return -ENOMEM; - } - setup.bRequestType = (__u8)0x40; - setup.bRequest = (__u8)0x0e; - setup.wValue = get_reg_value(reg, dummy); - setup.wIndex = get_reg_index(reg); - setup.wLength = 0; - usb_fill_control_urb(urbtrack->urb, usbdev, - usb_sndctrlpipe(usbdev, 0), - (unsigned char *)&setup, - NULL, 0, async_complete, urbtrack); - kref_init(&urbtrack->ref_count); - INIT_LIST_HEAD(&urbtrack->urblist_entry); - - /* - * get the disconnect mutex, or add tracker to the deferred_urbs list - * and schedule a tasklet to try again later - */ - if (!mutex_trylock(&serial->disc_mutex)) { - spin_lock_irqsave(&mos_parport->listlock, flags); - list_add_tail(&urbtrack->urblist_entry, - &mos_parport->deferred_urbs); - spin_unlock_irqrestore(&mos_parport->listlock, flags); - tasklet_schedule(&mos_parport->urb_tasklet); - dbg("tasklet scheduled"); - return 0; - } - - /* bail if device disconnected */ - if (serial->disconnected) { - kref_put(&urbtrack->ref_count, destroy_urbtracker); - mutex_unlock(&serial->disc_mutex); - return -ENODEV; - } - - /* add the tracker to the active_urbs list and submit */ - spin_lock_irqsave(&mos_parport->listlock, flags); - list_add_tail(&urbtrack->urblist_entry, &mos_parport->active_urbs); - spin_unlock_irqrestore(&mos_parport->listlock, flags); - ret_val = usb_submit_urb(urbtrack->urb, GFP_ATOMIC); - mutex_unlock(&serial->disc_mutex); - if (ret_val) { - dev_err(&usbdev->dev, - "%s: submit_urb() failed: %d", __func__, ret_val); - spin_lock_irqsave(&mos_parport->listlock, flags); - list_del(&urbtrack->urblist_entry); - spin_unlock_irqrestore(&mos_parport->listlock, flags); - kref_put(&urbtrack->ref_count, destroy_urbtracker); - return ret_val; - } - return 0; -} - -/* - * This is the the common top part of all parallel port callback operations that - * send synchronous messages to the device. This implements convoluted locking - * that avoids two scenarios: (1) a port operation is called after usbserial - * has called our release function, at which point struct mos7715_parport has - * been destroyed, and (2) the device has been disconnected, but usbserial has - * not called the release function yet because someone has a serial port open. - * The shared release_lock prevents the first, and the mutex and disconnected - * flag maintained by usbserial covers the second. We also use the msg_pending - * flag to ensure that all synchronous usb messgage calls have completed before - * our release function can return. - */ -static int parport_prologue(struct parport *pp) -{ - struct mos7715_parport *mos_parport; - - spin_lock(&release_lock); - mos_parport = pp->private_data; - if (unlikely(mos_parport == NULL)) { - /* release fn called, port struct destroyed */ - spin_unlock(&release_lock); - return -1; - } - mos_parport->msg_pending = true; /* synch usb call pending */ - INIT_COMPLETION(mos_parport->syncmsg_compl); - spin_unlock(&release_lock); - - mutex_lock(&mos_parport->serial->disc_mutex); - if (mos_parport->serial->disconnected) { - /* device disconnected */ - mutex_unlock(&mos_parport->serial->disc_mutex); - mos_parport->msg_pending = false; - complete(&mos_parport->syncmsg_compl); - return -1; - } - - return 0; -} - -/* - * This is the the common bottom part of all parallel port functions that send - * synchronous messages to the device. - */ -static inline void parport_epilogue(struct parport *pp) -{ - struct mos7715_parport *mos_parport = pp->private_data; - mutex_unlock(&mos_parport->serial->disc_mutex); - mos_parport->msg_pending = false; - complete(&mos_parport->syncmsg_compl); -} - -static void parport_mos7715_write_data(struct parport *pp, unsigned char d) -{ - struct mos7715_parport *mos_parport = pp->private_data; - dbg("%s called: %2.2x", __func__, d); - if (parport_prologue(pp) < 0) - return; - mos7715_change_mode(mos_parport, SPP); - write_mos_reg(mos_parport->serial, dummy, DPR, (__u8)d); - parport_epilogue(pp); -} - -static unsigned char parport_mos7715_read_data(struct parport *pp) -{ - struct mos7715_parport *mos_parport = pp->private_data; - unsigned char d; - dbg("%s called", __func__); - if (parport_prologue(pp) < 0) - return 0; - read_mos_reg(mos_parport->serial, dummy, DPR, &d); - parport_epilogue(pp); - return d; -} - -static void parport_mos7715_write_control(struct parport *pp, unsigned char d) -{ - struct mos7715_parport *mos_parport = pp->private_data; - __u8 data; - dbg("%s called: %2.2x", __func__, d); - if (parport_prologue(pp) < 0) - return; - data = ((__u8)d & 0x0f) | (mos_parport->shadowDCR & 0xf0); - write_mos_reg(mos_parport->serial, dummy, DCR, data); - mos_parport->shadowDCR = data; - parport_epilogue(pp); -} - -static unsigned char parport_mos7715_read_control(struct parport *pp) -{ - struct mos7715_parport *mos_parport = pp->private_data; - __u8 dcr; - dbg("%s called", __func__); - spin_lock(&release_lock); - mos_parport = pp->private_data; - if (unlikely(mos_parport == NULL)) { - spin_unlock(&release_lock); - return 0; - } - dcr = mos_parport->shadowDCR & 0x0f; - spin_unlock(&release_lock); - return dcr; -} - -static unsigned char parport_mos7715_frob_control(struct parport *pp, - unsigned char mask, - unsigned char val) -{ - struct mos7715_parport *mos_parport = pp->private_data; - __u8 dcr; - dbg("%s called", __func__); - mask &= 0x0f; - val &= 0x0f; - if (parport_prologue(pp) < 0) - return 0; - mos_parport->shadowDCR = (mos_parport->shadowDCR & (~mask)) ^ val; - write_mos_reg(mos_parport->serial, dummy, DCR, mos_parport->shadowDCR); - dcr = mos_parport->shadowDCR & 0x0f; - parport_epilogue(pp); - return dcr; -} - -static unsigned char parport_mos7715_read_status(struct parport *pp) -{ - unsigned char status; - struct mos7715_parport *mos_parport = pp->private_data; - dbg("%s called", __func__); - spin_lock(&release_lock); - mos_parport = pp->private_data; - if (unlikely(mos_parport == NULL)) { /* release called */ - spin_unlock(&release_lock); - return 0; - } - status = atomic_read(&mos_parport->shadowDSR) & 0xf8; - spin_unlock(&release_lock); - return status; -} - -static void parport_mos7715_enable_irq(struct parport *pp) -{ - dbg("%s called", __func__); -} -static void parport_mos7715_disable_irq(struct parport *pp) -{ - dbg("%s called", __func__); -} - -static void parport_mos7715_data_forward(struct parport *pp) -{ - struct mos7715_parport *mos_parport = pp->private_data; - dbg("%s called", __func__); - if (parport_prologue(pp) < 0) - return; - mos7715_change_mode(mos_parport, PS2); - mos_parport->shadowDCR &= ~0x20; - write_mos_reg(mos_parport->serial, dummy, DCR, mos_parport->shadowDCR); - parport_epilogue(pp); -} - -static void parport_mos7715_data_reverse(struct parport *pp) -{ - struct mos7715_parport *mos_parport = pp->private_data; - dbg("%s called", __func__); - if (parport_prologue(pp) < 0) - return; - mos7715_change_mode(mos_parport, PS2); - mos_parport->shadowDCR |= 0x20; - write_mos_reg(mos_parport->serial, dummy, DCR, mos_parport->shadowDCR); - parport_epilogue(pp); -} - -static void parport_mos7715_init_state(struct pardevice *dev, - struct parport_state *s) -{ - dbg("%s called", __func__); - s->u.pc.ctr = DCR_INIT_VAL; - s->u.pc.ecr = ECR_INIT_VAL; -} - -/* N.B. Parport core code requires that this function not block */ -static void parport_mos7715_save_state(struct parport *pp, - struct parport_state *s) -{ - struct mos7715_parport *mos_parport; - dbg("%s called", __func__); - spin_lock(&release_lock); - mos_parport = pp->private_data; - if (unlikely(mos_parport == NULL)) { /* release called */ - spin_unlock(&release_lock); - return; - } - s->u.pc.ctr = mos_parport->shadowDCR; - s->u.pc.ecr = mos_parport->shadowECR; - spin_unlock(&release_lock); -} - -/* N.B. Parport core code requires that this function not block */ -static void parport_mos7715_restore_state(struct parport *pp, - struct parport_state *s) -{ - struct mos7715_parport *mos_parport; - dbg("%s called", __func__); - spin_lock(&release_lock); - mos_parport = pp->private_data; - if (unlikely(mos_parport == NULL)) { /* release called */ - spin_unlock(&release_lock); - return; - } - write_parport_reg_nonblock(mos_parport, DCR, mos_parport->shadowDCR); - write_parport_reg_nonblock(mos_parport, ECR, mos_parport->shadowECR); - spin_unlock(&release_lock); -} - -static size_t parport_mos7715_write_compat(struct parport *pp, - const void *buffer, - size_t len, int flags) -{ - int retval; - struct mos7715_parport *mos_parport = pp->private_data; - int actual_len; - dbg("%s called: %u chars", __func__, (unsigned int)len); - if (parport_prologue(pp) < 0) - return 0; - mos7715_change_mode(mos_parport, PPF); - retval = usb_bulk_msg(mos_parport->serial->dev, - usb_sndbulkpipe(mos_parport->serial->dev, 2), - (void *)buffer, len, &actual_len, - MOS_WDR_TIMEOUT); - parport_epilogue(pp); - if (retval) { - dev_err(&mos_parport->serial->dev->dev, - "mos7720: usb_bulk_msg() failed: %d", retval); - return 0; - } - return actual_len; -} - -static struct parport_operations parport_mos7715_ops = { - .owner = THIS_MODULE, - .write_data = parport_mos7715_write_data, - .read_data = parport_mos7715_read_data, - - .write_control = parport_mos7715_write_control, - .read_control = parport_mos7715_read_control, - .frob_control = parport_mos7715_frob_control, - - .read_status = parport_mos7715_read_status, - - .enable_irq = parport_mos7715_enable_irq, - .disable_irq = parport_mos7715_disable_irq, - - .data_forward = parport_mos7715_data_forward, - .data_reverse = parport_mos7715_data_reverse, - - .init_state = parport_mos7715_init_state, - .save_state = parport_mos7715_save_state, - .restore_state = parport_mos7715_restore_state, - - .compat_write_data = parport_mos7715_write_compat, - - .nibble_read_data = parport_ieee1284_read_nibble, - .byte_read_data = parport_ieee1284_read_byte, -}; - -/* - * Allocate and initialize parallel port control struct, initialize - * the parallel port hardware device, and register with the parport subsystem. - */ -static int mos7715_parport_init(struct usb_serial *serial) -{ - struct mos7715_parport *mos_parport; - - /* allocate and initialize parallel port control struct */ - mos_parport = kzalloc(sizeof(struct mos7715_parport), GFP_KERNEL); - if (mos_parport == NULL) { - dbg("mos7715_parport_init: kzalloc failed"); - return -ENOMEM; - } - mos_parport->msg_pending = false; - kref_init(&mos_parport->ref_count); - spin_lock_init(&mos_parport->listlock); - INIT_LIST_HEAD(&mos_parport->active_urbs); - INIT_LIST_HEAD(&mos_parport->deferred_urbs); - usb_set_serial_data(serial, mos_parport); /* hijack private pointer */ - mos_parport->serial = serial; - tasklet_init(&mos_parport->urb_tasklet, send_deferred_urbs, - (unsigned long) mos_parport); - init_completion(&mos_parport->syncmsg_compl); - - /* cycle parallel port reset bit */ - write_mos_reg(mos_parport->serial, dummy, PP_REG, (__u8)0x80); - write_mos_reg(mos_parport->serial, dummy, PP_REG, (__u8)0x00); - - /* initialize device registers */ - mos_parport->shadowDCR = DCR_INIT_VAL; - write_mos_reg(mos_parport->serial, dummy, DCR, mos_parport->shadowDCR); - mos_parport->shadowECR = ECR_INIT_VAL; - write_mos_reg(mos_parport->serial, dummy, ECR, mos_parport->shadowECR); - - /* register with parport core */ - mos_parport->pp = parport_register_port(0, PARPORT_IRQ_NONE, - PARPORT_DMA_NONE, - &parport_mos7715_ops); - if (mos_parport->pp == NULL) { - dev_err(&serial->interface->dev, - "Could not register parport\n"); - kref_put(&mos_parport->ref_count, destroy_mos_parport); - return -EIO; - } - mos_parport->pp->private_data = mos_parport; - mos_parport->pp->modes = PARPORT_MODE_COMPAT | PARPORT_MODE_PCSPP; - mos_parport->pp->dev = &serial->interface->dev; - parport_announce_port(mos_parport->pp); - - return 0; -} -#endif /* CONFIG_USB_SERIAL_MOS7715_PARPORT */ - -/* - * mos7720_interrupt_callback - * this is the callback function for when we have received data on the - * interrupt endpoint. - */ -static void mos7720_interrupt_callback(struct urb *urb) -{ - int result; - int length; - int status = urb->status; - __u8 *data; - __u8 sp1; - __u8 sp2; - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, - status); - return; - default: - dbg("%s - nonzero urb status received: %d", __func__, - status); - goto exit; - } - - length = urb->actual_length; - data = urb->transfer_buffer; - - /* Moschip get 4 bytes - * Byte 1 IIR Port 1 (port.number is 0) - * Byte 2 IIR Port 2 (port.number is 1) - * Byte 3 -------------- - * Byte 4 FIFO status for both */ - - /* the above description is inverted - * oneukum 2007-03-14 */ - - if (unlikely(length != 4)) { - dbg("Wrong data !!!"); - return; - } - - sp1 = data[3]; - sp2 = data[2]; - - if ((sp1 | sp2) & 0x01) { - /* No Interrupt Pending in both the ports */ - dbg("No Interrupt !!!"); - } else { - switch (sp1 & 0x0f) { - case SERIAL_IIR_RLS: - dbg("Serial Port 1: Receiver status error or address " - "bit detected in 9-bit mode\n"); - break; - case SERIAL_IIR_CTI: - dbg("Serial Port 1: Receiver time out"); - break; - case SERIAL_IIR_MS: - /* dbg("Serial Port 1: Modem status change"); */ - break; - } - - switch (sp2 & 0x0f) { - case SERIAL_IIR_RLS: - dbg("Serial Port 2: Receiver status error or address " - "bit detected in 9-bit mode"); - break; - case SERIAL_IIR_CTI: - dbg("Serial Port 2: Receiver time out"); - break; - case SERIAL_IIR_MS: - /* dbg("Serial Port 2: Modem status change"); */ - break; - } - } - -exit: - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) - dev_err(&urb->dev->dev, - "%s - Error %d submitting control urb\n", - __func__, result); -} - -/* - * mos7715_interrupt_callback - * this is the 7715's callback function for when we have received data on - * the interrupt endpoint. - */ -static void mos7715_interrupt_callback(struct urb *urb) -{ - int result; - int length; - int status = urb->status; - __u8 *data; - __u8 iir; - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - case -ENODEV: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, - status); - return; - default: - dbg("%s - nonzero urb status received: %d", __func__, - status); - goto exit; - } - - length = urb->actual_length; - data = urb->transfer_buffer; - - /* Structure of data from 7715 device: - * Byte 1: IIR serial Port - * Byte 2: unused - * Byte 2: DSR parallel port - * Byte 4: FIFO status for both */ - - if (unlikely(length != 4)) { - dbg("Wrong data !!!"); - return; - } - - iir = data[0]; - if (!(iir & 0x01)) { /* serial port interrupt pending */ - switch (iir & 0x0f) { - case SERIAL_IIR_RLS: - dbg("Serial Port: Receiver status error or address " - "bit detected in 9-bit mode\n"); - break; - case SERIAL_IIR_CTI: - dbg("Serial Port: Receiver time out"); - break; - case SERIAL_IIR_MS: - /* dbg("Serial Port: Modem status change"); */ - break; - } - } - -#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT - { /* update local copy of DSR reg */ - struct usb_serial_port *port = urb->context; - struct mos7715_parport *mos_parport = port->serial->private; - if (unlikely(mos_parport == NULL)) - return; - atomic_set(&mos_parport->shadowDSR, data[2]); - } -#endif - -exit: - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) - dev_err(&urb->dev->dev, - "%s - Error %d submitting control urb\n", - __func__, result); -} - -/* - * mos7720_bulk_in_callback - * this is the callback function for when we have received data on the - * bulk in endpoint. - */ -static void mos7720_bulk_in_callback(struct urb *urb) -{ - int retval; - unsigned char *data ; - struct usb_serial_port *port; - struct tty_struct *tty; - int status = urb->status; - - if (status) { - dbg("nonzero read bulk status received: %d", status); - return; - } - - port = urb->context; - - dbg("Entering...%s", __func__); - - data = urb->transfer_buffer; - - tty = tty_port_tty_get(&port->port); - if (tty && urb->actual_length) { - tty_insert_flip_string(tty, data, urb->actual_length); - tty_flip_buffer_push(tty); - } - tty_kref_put(tty); - - if (port->read_urb->status != -EINPROGRESS) { - retval = usb_submit_urb(port->read_urb, GFP_ATOMIC); - if (retval) - dbg("usb_submit_urb(read bulk) failed, retval = %d", - retval); - } -} - -/* - * mos7720_bulk_out_data_callback - * this is the callback function for when we have finished sending serial - * data on the bulk out endpoint. - */ -static void mos7720_bulk_out_data_callback(struct urb *urb) -{ - struct moschip_port *mos7720_port; - struct tty_struct *tty; - int status = urb->status; - - if (status) { - dbg("nonzero write bulk status received:%d", status); - return; - } - - mos7720_port = urb->context; - if (!mos7720_port) { - dbg("NULL mos7720_port pointer"); - return ; - } - - tty = tty_port_tty_get(&mos7720_port->port->port); - - if (tty && mos7720_port->open) - tty_wakeup(tty); - tty_kref_put(tty); -} - -/* - * mos77xx_probe - * this function installs the appropriate read interrupt endpoint callback - * depending on whether the device is a 7720 or 7715, thus avoiding costly - * run-time checks in the high-frequency callback routine itself. - */ -static int mos77xx_probe(struct usb_serial *serial, - const struct usb_device_id *id) -{ - if (id->idProduct == MOSCHIP_DEVICE_ID_7715) - moschip7720_2port_driver.read_int_callback = - mos7715_interrupt_callback; - else - moschip7720_2port_driver.read_int_callback = - mos7720_interrupt_callback; - - return 0; -} - -static int mos77xx_calc_num_ports(struct usb_serial *serial) -{ - u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); - if (product == MOSCHIP_DEVICE_ID_7715) - return 1; - - return 2; -} - -static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct usb_serial *serial; - struct urb *urb; - struct moschip_port *mos7720_port; - int response; - int port_number; - __u8 data; - int allocated_urbs = 0; - int j; - - serial = port->serial; - - mos7720_port = usb_get_serial_port_data(port); - if (mos7720_port == NULL) - return -ENODEV; - - usb_clear_halt(serial->dev, port->write_urb->pipe); - usb_clear_halt(serial->dev, port->read_urb->pipe); - - /* Initialising the write urb pool */ - for (j = 0; j < NUM_URBS; ++j) { - urb = usb_alloc_urb(0, GFP_KERNEL); - mos7720_port->write_urb_pool[j] = urb; - - if (urb == NULL) { - dev_err(&port->dev, "No more urbs???\n"); - continue; - } - - urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, - GFP_KERNEL); - if (!urb->transfer_buffer) { - dev_err(&port->dev, - "%s-out of memory for urb buffers.\n", - __func__); - usb_free_urb(mos7720_port->write_urb_pool[j]); - mos7720_port->write_urb_pool[j] = NULL; - continue; - } - allocated_urbs++; - } - - if (!allocated_urbs) - return -ENOMEM; - - /* Initialize MCS7720 -- Write Init values to corresponding Registers - * - * Register Index - * 0 : THR/RHR - * 1 : IER - * 2 : FCR - * 3 : LCR - * 4 : MCR - * 5 : LSR - * 6 : MSR - * 7 : SPR - * - * 0x08 : SP1/2 Control Reg - */ - port_number = port->number - port->serial->minor; - read_mos_reg(serial, port_number, LSR, &data); - - dbg("SS::%p LSR:%x", mos7720_port, data); - - dbg("Check:Sending Command .........."); - - write_mos_reg(serial, dummy, SP1_REG, 0x02); - write_mos_reg(serial, dummy, SP2_REG, 0x02); - - write_mos_reg(serial, port_number, IER, 0x00); - write_mos_reg(serial, port_number, FCR, 0x00); - - write_mos_reg(serial, port_number, FCR, 0xcf); - mos7720_port->shadowLCR = 0x03; - write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR); - mos7720_port->shadowMCR = 0x0b; - write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR); - - write_mos_reg(serial, port_number, SP_CONTROL_REG, 0x00); - read_mos_reg(serial, dummy, SP_CONTROL_REG, &data); - data = data | (port->number - port->serial->minor + 1); - write_mos_reg(serial, dummy, SP_CONTROL_REG, data); - mos7720_port->shadowLCR = 0x83; - write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR); - write_mos_reg(serial, port_number, THR, 0x0c); - write_mos_reg(serial, port_number, IER, 0x00); - mos7720_port->shadowLCR = 0x03; - write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR); - write_mos_reg(serial, port_number, IER, 0x0c); - - response = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (response) - dev_err(&port->dev, "%s - Error %d submitting read urb\n", - __func__, response); - - /* initialize our icount structure */ - memset(&(mos7720_port->icount), 0x00, sizeof(mos7720_port->icount)); - - /* initialize our port settings */ - mos7720_port->shadowMCR = UART_MCR_OUT2; /* Must set to enable ints! */ - - /* send a open port command */ - mos7720_port->open = 1; - - return 0; -} - -/* - * mos7720_chars_in_buffer - * this function is called by the tty driver when it wants to know how many - * bytes of data we currently have outstanding in the port (data that has - * been written, but hasn't made it out the port yet) - * If successful, we return the number of bytes left to be written in the - * system, - * Otherwise we return a negative error number. - */ -static int mos7720_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - int i; - int chars = 0; - struct moschip_port *mos7720_port; - - dbg("%s:entering ...........", __func__); - - mos7720_port = usb_get_serial_port_data(port); - if (mos7720_port == NULL) { - dbg("%s:leaving ...........", __func__); - return 0; - } - - for (i = 0; i < NUM_URBS; ++i) { - if (mos7720_port->write_urb_pool[i] && - mos7720_port->write_urb_pool[i]->status == -EINPROGRESS) - chars += URB_TRANSFER_BUFFER_SIZE; - } - dbg("%s - returns %d", __func__, chars); - return chars; -} - -static void mos7720_close(struct usb_serial_port *port) -{ - struct usb_serial *serial; - struct moschip_port *mos7720_port; - int j; - - dbg("mos7720_close:entering..."); - - serial = port->serial; - - mos7720_port = usb_get_serial_port_data(port); - if (mos7720_port == NULL) - return; - - for (j = 0; j < NUM_URBS; ++j) - usb_kill_urb(mos7720_port->write_urb_pool[j]); - - /* Freeing Write URBs */ - for (j = 0; j < NUM_URBS; ++j) { - if (mos7720_port->write_urb_pool[j]) { - kfree(mos7720_port->write_urb_pool[j]->transfer_buffer); - usb_free_urb(mos7720_port->write_urb_pool[j]); - } - } - - /* While closing port, shutdown all bulk read, write * - * and interrupt read if they exists, otherwise nop */ - dbg("Shutdown bulk write"); - usb_kill_urb(port->write_urb); - dbg("Shutdown bulk read"); - usb_kill_urb(port->read_urb); - - mutex_lock(&serial->disc_mutex); - /* these commands must not be issued if the device has - * been disconnected */ - if (!serial->disconnected) { - write_mos_reg(serial, port->number - port->serial->minor, - MCR, 0x00); - write_mos_reg(serial, port->number - port->serial->minor, - IER, 0x00); - } - mutex_unlock(&serial->disc_mutex); - mos7720_port->open = 0; - - dbg("Leaving %s", __func__); -} - -static void mos7720_break(struct tty_struct *tty, int break_state) -{ - struct usb_serial_port *port = tty->driver_data; - unsigned char data; - struct usb_serial *serial; - struct moschip_port *mos7720_port; - - dbg("Entering %s", __func__); - - serial = port->serial; - - mos7720_port = usb_get_serial_port_data(port); - if (mos7720_port == NULL) - return; - - if (break_state == -1) - data = mos7720_port->shadowLCR | UART_LCR_SBC; - else - data = mos7720_port->shadowLCR & ~UART_LCR_SBC; - - mos7720_port->shadowLCR = data; - write_mos_reg(serial, port->number - port->serial->minor, - LCR, mos7720_port->shadowLCR); -} - -/* - * mos7720_write_room - * this function is called by the tty driver when it wants to know how many - * bytes of data we can accept for a specific port. - * If successful, we return the amount of room that we have for this port - * Otherwise we return a negative error number. - */ -static int mos7720_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct moschip_port *mos7720_port; - int room = 0; - int i; - - dbg("%s:entering ...........", __func__); - - mos7720_port = usb_get_serial_port_data(port); - if (mos7720_port == NULL) { - dbg("%s:leaving ...........", __func__); - return -ENODEV; - } - - /* FIXME: Locking */ - for (i = 0; i < NUM_URBS; ++i) { - if (mos7720_port->write_urb_pool[i] && - mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) - room += URB_TRANSFER_BUFFER_SIZE; - } - - dbg("%s - returns %d", __func__, room); - return room; -} - -static int mos7720_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *data, int count) -{ - int status; - int i; - int bytes_sent = 0; - int transfer_size; - - struct moschip_port *mos7720_port; - struct usb_serial *serial; - struct urb *urb; - const unsigned char *current_position = data; - - dbg("%s:entering ...........", __func__); - - serial = port->serial; - - mos7720_port = usb_get_serial_port_data(port); - if (mos7720_port == NULL) { - dbg("mos7720_port is NULL"); - return -ENODEV; - } - - /* try to find a free urb in the list */ - urb = NULL; - - for (i = 0; i < NUM_URBS; ++i) { - if (mos7720_port->write_urb_pool[i] && - mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) { - urb = mos7720_port->write_urb_pool[i]; - dbg("URB:%d", i); - break; - } - } - - if (urb == NULL) { - dbg("%s - no more free urbs", __func__); - goto exit; - } - - if (urb->transfer_buffer == NULL) { - urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, - GFP_KERNEL); - if (urb->transfer_buffer == NULL) { - dev_err_console(port, "%s no more kernel memory...\n", - __func__); - goto exit; - } - } - transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE); - - memcpy(urb->transfer_buffer, current_position, transfer_size); - usb_serial_debug_data(debug, &port->dev, __func__, transfer_size, - urb->transfer_buffer); - - /* fill urb with data and submit */ - usb_fill_bulk_urb(urb, serial->dev, - usb_sndbulkpipe(serial->dev, - port->bulk_out_endpointAddress), - urb->transfer_buffer, transfer_size, - mos7720_bulk_out_data_callback, mos7720_port); - - /* send it down the pipe */ - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) { - dev_err_console(port, "%s - usb_submit_urb(write bulk) failed " - "with status = %d\n", __func__, status); - bytes_sent = status; - goto exit; - } - bytes_sent = transfer_size; - -exit: - return bytes_sent; -} - -static void mos7720_throttle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct moschip_port *mos7720_port; - int status; - - dbg("%s- port %d", __func__, port->number); - - mos7720_port = usb_get_serial_port_data(port); - - if (mos7720_port == NULL) - return; - - if (!mos7720_port->open) { - dbg("port not opened"); - return; - } - - dbg("%s: Entering ..........", __func__); - - /* if we are implementing XON/XOFF, send the stop character */ - if (I_IXOFF(tty)) { - unsigned char stop_char = STOP_CHAR(tty); - status = mos7720_write(tty, port, &stop_char, 1); - if (status <= 0) - return; - } - - /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { - mos7720_port->shadowMCR &= ~UART_MCR_RTS; - write_mos_reg(port->serial, port->number - port->serial->minor, - MCR, mos7720_port->shadowMCR); - if (status != 0) - return; - } -} - -static void mos7720_unthrottle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct moschip_port *mos7720_port = usb_get_serial_port_data(port); - int status; - - if (mos7720_port == NULL) - return; - - if (!mos7720_port->open) { - dbg("%s - port not opened", __func__); - return; - } - - dbg("%s: Entering ..........", __func__); - - /* if we are implementing XON/XOFF, send the start character */ - if (I_IXOFF(tty)) { - unsigned char start_char = START_CHAR(tty); - status = mos7720_write(tty, port, &start_char, 1); - if (status <= 0) - return; - } - - /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { - mos7720_port->shadowMCR |= UART_MCR_RTS; - write_mos_reg(port->serial, port->number - port->serial->minor, - MCR, mos7720_port->shadowMCR); - if (status != 0) - return; - } -} - -/* FIXME: this function does not work */ -static int set_higher_rates(struct moschip_port *mos7720_port, - unsigned int baud) -{ - struct usb_serial_port *port; - struct usb_serial *serial; - int port_number; - enum mos_regs sp_reg; - if (mos7720_port == NULL) - return -EINVAL; - - port = mos7720_port->port; - serial = port->serial; - - /*********************************************** - * Init Sequence for higher rates - ***********************************************/ - dbg("Sending Setting Commands .........."); - port_number = port->number - port->serial->minor; - - write_mos_reg(serial, port_number, IER, 0x00); - write_mos_reg(serial, port_number, FCR, 0x00); - write_mos_reg(serial, port_number, FCR, 0xcf); - mos7720_port->shadowMCR = 0x0b; - write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR); - write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x00); - - /*********************************************** - * Set for higher rates * - ***********************************************/ - /* writing baud rate verbatum into uart clock field clearly not right */ - if (port_number == 0) - sp_reg = SP1_REG; - else - sp_reg = SP2_REG; - write_mos_reg(serial, dummy, sp_reg, baud * 0x10); - write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x03); - mos7720_port->shadowMCR = 0x2b; - write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR); - - /*********************************************** - * Set DLL/DLM - ***********************************************/ - mos7720_port->shadowLCR = mos7720_port->shadowLCR | UART_LCR_DLAB; - write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR); - write_mos_reg(serial, port_number, DLL, 0x01); - write_mos_reg(serial, port_number, DLM, 0x00); - mos7720_port->shadowLCR = mos7720_port->shadowLCR & ~UART_LCR_DLAB; - write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR); - - return 0; -} - -/* baud rate information */ -struct divisor_table_entry { - __u32 baudrate; - __u16 divisor; -}; - -/* Define table of divisors for moschip 7720 hardware * - * These assume a 3.6864MHz crystal, the standard /16, and * - * MCR.7 = 0. */ -static struct divisor_table_entry divisor_table[] = { - { 50, 2304}, - { 110, 1047}, /* 2094.545455 => 230450 => .0217 % over */ - { 134, 857}, /* 1713.011152 => 230398.5 => .00065% under */ - { 150, 768}, - { 300, 384}, - { 600, 192}, - { 1200, 96}, - { 1800, 64}, - { 2400, 48}, - { 4800, 24}, - { 7200, 16}, - { 9600, 12}, - { 19200, 6}, - { 38400, 3}, - { 57600, 2}, - { 115200, 1}, -}; - -/***************************************************************************** - * calc_baud_rate_divisor - * this function calculates the proper baud rate divisor for the specified - * baud rate. - *****************************************************************************/ -static int calc_baud_rate_divisor(int baudrate, int *divisor) -{ - int i; - __u16 custom; - __u16 round1; - __u16 round; - - - dbg("%s - %d", __func__, baudrate); - - for (i = 0; i < ARRAY_SIZE(divisor_table); i++) { - if (divisor_table[i].baudrate == baudrate) { - *divisor = divisor_table[i].divisor; - return 0; - } - } - - /* After trying for all the standard baud rates * - * Try calculating the divisor for this baud rate */ - if (baudrate > 75 && baudrate < 230400) { - /* get the divisor */ - custom = (__u16)(230400L / baudrate); - - /* Check for round off */ - round1 = (__u16)(2304000L / baudrate); - round = (__u16)(round1 - (custom * 10)); - if (round > 4) - custom++; - *divisor = custom; - - dbg("Baud %d = %d", baudrate, custom); - return 0; - } - - dbg("Baud calculation Failed..."); - return -EINVAL; -} - -/* - * send_cmd_write_baud_rate - * this function sends the proper command to change the baud rate of the - * specified port. - */ -static int send_cmd_write_baud_rate(struct moschip_port *mos7720_port, - int baudrate) -{ - struct usb_serial_port *port; - struct usb_serial *serial; - int divisor; - int status; - unsigned char number; - - if (mos7720_port == NULL) - return -1; - - port = mos7720_port->port; - serial = port->serial; - - dbg("%s: Entering ..........", __func__); - - number = port->number - port->serial->minor; - dbg("%s - port = %d, baud = %d", __func__, port->number, baudrate); - - /* Calculate the Divisor */ - status = calc_baud_rate_divisor(baudrate, &divisor); - if (status) { - dev_err(&port->dev, "%s - bad baud rate\n", __func__); - return status; - } - - /* Enable access to divisor latch */ - mos7720_port->shadowLCR = mos7720_port->shadowLCR | UART_LCR_DLAB; - write_mos_reg(serial, number, LCR, mos7720_port->shadowLCR); - - /* Write the divisor */ - write_mos_reg(serial, number, DLL, (__u8)(divisor & 0xff)); - write_mos_reg(serial, number, DLM, (__u8)((divisor & 0xff00) >> 8)); - - /* Disable access to divisor latch */ - mos7720_port->shadowLCR = mos7720_port->shadowLCR & ~UART_LCR_DLAB; - write_mos_reg(serial, number, LCR, mos7720_port->shadowLCR); - - return status; -} - -/* - * change_port_settings - * This routine is called to set the UART on the device to match - * the specified new settings. - */ -static void change_port_settings(struct tty_struct *tty, - struct moschip_port *mos7720_port, - struct ktermios *old_termios) -{ - struct usb_serial_port *port; - struct usb_serial *serial; - int baud; - unsigned cflag; - unsigned iflag; - __u8 mask = 0xff; - __u8 lData; - __u8 lParity; - __u8 lStop; - int status; - int port_number; - - if (mos7720_port == NULL) - return ; - - port = mos7720_port->port; - serial = port->serial; - port_number = port->number - port->serial->minor; - - dbg("%s - port %d", __func__, port->number); - - if (!mos7720_port->open) { - dbg("%s - port not opened", __func__); - return; - } - - dbg("%s: Entering ..........", __func__); - - lData = UART_LCR_WLEN8; - lStop = 0x00; /* 1 stop bit */ - lParity = 0x00; /* No parity */ - - cflag = tty->termios->c_cflag; - iflag = tty->termios->c_iflag; - - /* Change the number of bits */ - switch (cflag & CSIZE) { - case CS5: - lData = UART_LCR_WLEN5; - mask = 0x1f; - break; - - case CS6: - lData = UART_LCR_WLEN6; - mask = 0x3f; - break; - - case CS7: - lData = UART_LCR_WLEN7; - mask = 0x7f; - break; - default: - case CS8: - lData = UART_LCR_WLEN8; - break; - } - - /* Change the Parity bit */ - if (cflag & PARENB) { - if (cflag & PARODD) { - lParity = UART_LCR_PARITY; - dbg("%s - parity = odd", __func__); - } else { - lParity = (UART_LCR_EPAR | UART_LCR_PARITY); - dbg("%s - parity = even", __func__); - } - - } else { - dbg("%s - parity = none", __func__); - } - - if (cflag & CMSPAR) - lParity = lParity | 0x20; - - /* Change the Stop bit */ - if (cflag & CSTOPB) { - lStop = UART_LCR_STOP; - dbg("%s - stop bits = 2", __func__); - } else { - lStop = 0x00; - dbg("%s - stop bits = 1", __func__); - } - -#define LCR_BITS_MASK 0x03 /* Mask for bits/char field */ -#define LCR_STOP_MASK 0x04 /* Mask for stop bits field */ -#define LCR_PAR_MASK 0x38 /* Mask for parity field */ - - /* Update the LCR with the correct value */ - mos7720_port->shadowLCR &= - ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK); - mos7720_port->shadowLCR |= (lData | lParity | lStop); - - - /* Disable Interrupts */ - write_mos_reg(serial, port_number, IER, 0x00); - write_mos_reg(serial, port_number, FCR, 0x00); - write_mos_reg(serial, port_number, FCR, 0xcf); - - /* Send the updated LCR value to the mos7720 */ - write_mos_reg(serial, port_number, LCR, mos7720_port->shadowLCR); - mos7720_port->shadowMCR = 0x0b; - write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR); - - /* set up the MCR register and send it to the mos7720 */ - mos7720_port->shadowMCR = UART_MCR_OUT2; - if (cflag & CBAUD) - mos7720_port->shadowMCR |= (UART_MCR_DTR | UART_MCR_RTS); - - if (cflag & CRTSCTS) { - mos7720_port->shadowMCR |= (UART_MCR_XONANY); - /* To set hardware flow control to the specified * - * serial port, in SP1/2_CONTROL_REG */ - if (port->number) - write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x01); - else - write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x02); - - } else - mos7720_port->shadowMCR &= ~(UART_MCR_XONANY); - - write_mos_reg(serial, port_number, MCR, mos7720_port->shadowMCR); - - /* Determine divisor based on baud rate */ - baud = tty_get_baud_rate(tty); - if (!baud) { - /* pick a default, any default... */ - dbg("Picked default baud..."); - baud = 9600; - } - - if (baud >= 230400) { - set_higher_rates(mos7720_port, baud); - /* Enable Interrupts */ - write_mos_reg(serial, port_number, IER, 0x0c); - return; - } - - dbg("%s - baud rate = %d", __func__, baud); - status = send_cmd_write_baud_rate(mos7720_port, baud); - /* FIXME: needs to write actual resulting baud back not just - blindly do so */ - if (cflag & CBAUD) - tty_encode_baud_rate(tty, baud, baud); - /* Enable Interrupts */ - write_mos_reg(serial, port_number, IER, 0x0c); - - if (port->read_urb->status != -EINPROGRESS) { - status = usb_submit_urb(port->read_urb, GFP_ATOMIC); - if (status) - dbg("usb_submit_urb(read bulk) failed, status = %d", - status); - } -} - -/* - * mos7720_set_termios - * this function is called by the tty driver when it wants to change the - * termios structure. - */ -static void mos7720_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) -{ - int status; - unsigned int cflag; - struct usb_serial *serial; - struct moschip_port *mos7720_port; - - serial = port->serial; - - mos7720_port = usb_get_serial_port_data(port); - - if (mos7720_port == NULL) - return; - - if (!mos7720_port->open) { - dbg("%s - port not opened", __func__); - return; - } - - dbg("%s\n", "setting termios - ASPIRE"); - - cflag = tty->termios->c_cflag; - - dbg("%s - cflag %08x iflag %08x", __func__, - tty->termios->c_cflag, - RELEVANT_IFLAG(tty->termios->c_iflag)); - - dbg("%s - old cflag %08x old iflag %08x", __func__, - old_termios->c_cflag, - RELEVANT_IFLAG(old_termios->c_iflag)); - - dbg("%s - port %d", __func__, port->number); - - /* change the port settings to the new ones specified */ - change_port_settings(tty, mos7720_port, old_termios); - - if (port->read_urb->status != -EINPROGRESS) { - status = usb_submit_urb(port->read_urb, GFP_ATOMIC); - if (status) - dbg("usb_submit_urb(read bulk) failed, status = %d", - status); - } -} - -/* - * get_lsr_info - get line status register info - * - * Purpose: Let user call ioctl() to get info when the UART physically - * is emptied. On bus types like RS485, the transmitter must - * release the bus after transmitting. This must be done when - * the transmit shift register is empty, not be done when the - * transmit holding register is empty. This functionality - * allows an RS485 driver to be written in user space. - */ -static int get_lsr_info(struct tty_struct *tty, - struct moschip_port *mos7720_port, unsigned int __user *value) -{ - struct usb_serial_port *port = tty->driver_data; - unsigned int result = 0; - unsigned char data = 0; - int port_number = port->number - port->serial->minor; - int count; - - count = mos7720_chars_in_buffer(tty); - if (count == 0) { - read_mos_reg(port->serial, port_number, LSR, &data); - if ((data & (UART_LSR_TEMT | UART_LSR_THRE)) - == (UART_LSR_TEMT | UART_LSR_THRE)) { - dbg("%s -- Empty", __func__); - result = TIOCSER_TEMT; - } - } - if (copy_to_user(value, &result, sizeof(int))) - return -EFAULT; - return 0; -} - -static int mos7720_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct moschip_port *mos7720_port = usb_get_serial_port_data(port); - unsigned int result = 0; - unsigned int mcr ; - unsigned int msr ; - - dbg("%s - port %d", __func__, port->number); - - mcr = mos7720_port->shadowMCR; - msr = mos7720_port->shadowMSR; - - result = ((mcr & UART_MCR_DTR) ? TIOCM_DTR : 0) /* 0x002 */ - | ((mcr & UART_MCR_RTS) ? TIOCM_RTS : 0) /* 0x004 */ - | ((msr & UART_MSR_CTS) ? TIOCM_CTS : 0) /* 0x020 */ - | ((msr & UART_MSR_DCD) ? TIOCM_CAR : 0) /* 0x040 */ - | ((msr & UART_MSR_RI) ? TIOCM_RI : 0) /* 0x080 */ - | ((msr & UART_MSR_DSR) ? TIOCM_DSR : 0); /* 0x100 */ - - dbg("%s -- %x", __func__, result); - - return result; -} - -static int mos7720_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct moschip_port *mos7720_port = usb_get_serial_port_data(port); - unsigned int mcr ; - dbg("%s - port %d", __func__, port->number); - dbg("he was at tiocmset"); - - mcr = mos7720_port->shadowMCR; - - if (set & TIOCM_RTS) - mcr |= UART_MCR_RTS; - if (set & TIOCM_DTR) - mcr |= UART_MCR_DTR; - if (set & TIOCM_LOOP) - mcr |= UART_MCR_LOOP; - - if (clear & TIOCM_RTS) - mcr &= ~UART_MCR_RTS; - if (clear & TIOCM_DTR) - mcr &= ~UART_MCR_DTR; - if (clear & TIOCM_LOOP) - mcr &= ~UART_MCR_LOOP; - - mos7720_port->shadowMCR = mcr; - write_mos_reg(port->serial, port->number - port->serial->minor, - MCR, mos7720_port->shadowMCR); - - return 0; -} - -static int mos7720_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct moschip_port *mos7720_port; - struct async_icount cnow; - - mos7720_port = usb_get_serial_port_data(port); - cnow = mos7720_port->icount; - - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - icount->rx = cnow.rx; - icount->tx = cnow.tx; - icount->frame = cnow.frame; - icount->overrun = cnow.overrun; - icount->parity = cnow.parity; - icount->brk = cnow.brk; - icount->buf_overrun = cnow.buf_overrun; - - dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __func__, - port->number, icount->rx, icount->tx); - return 0; -} - -static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd, - unsigned int __user *value) -{ - unsigned int mcr; - unsigned int arg; - - struct usb_serial_port *port; - - if (mos7720_port == NULL) - return -1; - - port = (struct usb_serial_port *)mos7720_port->port; - mcr = mos7720_port->shadowMCR; - - if (copy_from_user(&arg, value, sizeof(int))) - return -EFAULT; - - switch (cmd) { - case TIOCMBIS: - if (arg & TIOCM_RTS) - mcr |= UART_MCR_RTS; - if (arg & TIOCM_DTR) - mcr |= UART_MCR_RTS; - if (arg & TIOCM_LOOP) - mcr |= UART_MCR_LOOP; - break; - - case TIOCMBIC: - if (arg & TIOCM_RTS) - mcr &= ~UART_MCR_RTS; - if (arg & TIOCM_DTR) - mcr &= ~UART_MCR_RTS; - if (arg & TIOCM_LOOP) - mcr &= ~UART_MCR_LOOP; - break; - - } - - mos7720_port->shadowMCR = mcr; - write_mos_reg(port->serial, port->number - port->serial->minor, - MCR, mos7720_port->shadowMCR); - - return 0; -} - -static int get_serial_info(struct moschip_port *mos7720_port, - struct serial_struct __user *retinfo) -{ - struct serial_struct tmp; - - if (!retinfo) - return -EFAULT; - - memset(&tmp, 0, sizeof(tmp)); - - tmp.type = PORT_16550A; - tmp.line = mos7720_port->port->serial->minor; - tmp.port = mos7720_port->port->number; - tmp.irq = 0; - tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; - tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; - tmp.baud_base = 9600; - tmp.close_delay = 5*HZ; - tmp.closing_wait = 30*HZ; - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - return 0; -} - -static int mos7720_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - struct moschip_port *mos7720_port; - struct async_icount cnow; - struct async_icount cprev; - - mos7720_port = usb_get_serial_port_data(port); - if (mos7720_port == NULL) - return -ENODEV; - - dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd); - - switch (cmd) { - case TIOCSERGETLSR: - dbg("%s (%d) TIOCSERGETLSR", __func__, port->number); - return get_lsr_info(tty, mos7720_port, - (unsigned int __user *)arg); - - /* FIXME: These should be using the mode methods */ - case TIOCMBIS: - case TIOCMBIC: - dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", - __func__, port->number); - return set_modem_info(mos7720_port, cmd, - (unsigned int __user *)arg); - - case TIOCGSERIAL: - dbg("%s (%d) TIOCGSERIAL", __func__, port->number); - return get_serial_info(mos7720_port, - (struct serial_struct __user *)arg); - - case TIOCMIWAIT: - dbg("%s (%d) TIOCMIWAIT", __func__, port->number); - cprev = mos7720_port->icount; - while (1) { - if (signal_pending(current)) - return -ERESTARTSYS; - cnow = mos7720_port->icount; - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { - return 0; - } - cprev = cnow; - } - /* NOTREACHED */ - break; - } - - return -ENOIOCTLCMD; -} - -static int mos7720_startup(struct usb_serial *serial) -{ - struct moschip_port *mos7720_port; - struct usb_device *dev; - int i; - char data; - u16 product; - int ret_val; - - dbg("%s: Entering ..........", __func__); - - if (!serial) { - dbg("Invalid Handler"); - return -ENODEV; - } - - product = le16_to_cpu(serial->dev->descriptor.idProduct); - dev = serial->dev; - - /* - * The 7715 uses the first bulk in/out endpoint pair for the parallel - * port, and the second for the serial port. Because the usbserial core - * assumes both pairs are serial ports, we must engage in a bit of - * subterfuge and swap the pointers for ports 0 and 1 in order to make - * port 0 point to the serial port. However, both moschip devices use a - * single interrupt-in endpoint for both ports (as mentioned a little - * further down), and this endpoint was assigned to port 0. So after - * the swap, we must copy the interrupt endpoint elements from port 1 - * (as newly assigned) to port 0, and null out port 1 pointers. - */ - if (product == MOSCHIP_DEVICE_ID_7715) { - struct usb_serial_port *tmp = serial->port[0]; - serial->port[0] = serial->port[1]; - serial->port[1] = tmp; - serial->port[0]->interrupt_in_urb = tmp->interrupt_in_urb; - serial->port[0]->interrupt_in_buffer = tmp->interrupt_in_buffer; - serial->port[0]->interrupt_in_endpointAddress = - tmp->interrupt_in_endpointAddress; - serial->port[1]->interrupt_in_urb = NULL; - serial->port[1]->interrupt_in_buffer = NULL; - } - - - /* set up serial port private structures */ - for (i = 0; i < serial->num_ports; ++i) { - mos7720_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL); - if (mos7720_port == NULL) { - dev_err(&dev->dev, "%s - Out of memory\n", __func__); - return -ENOMEM; - } - - /* Initialize all port interrupt end point to port 0 int - * endpoint. Our device has only one interrupt endpoint - * common to all ports */ - serial->port[i]->interrupt_in_endpointAddress = - serial->port[0]->interrupt_in_endpointAddress; - - mos7720_port->port = serial->port[i]; - usb_set_serial_port_data(serial->port[i], mos7720_port); - - dbg("port number is %d", serial->port[i]->number); - dbg("serial number is %d", serial->minor); - } - - - /* setting configuration feature to one */ - usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - (__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5*HZ); - - /* start the interrupt urb */ - ret_val = usb_submit_urb(serial->port[0]->interrupt_in_urb, GFP_KERNEL); - if (ret_val) - dev_err(&dev->dev, - "%s - Error %d submitting control urb\n", - __func__, ret_val); - -#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT - if (product == MOSCHIP_DEVICE_ID_7715) { - ret_val = mos7715_parport_init(serial); - if (ret_val < 0) - return ret_val; - } -#endif - /* LSR For Port 1 */ - read_mos_reg(serial, 0, LSR, &data); - dbg("LSR:%x", data); - - return 0; -} - -static void mos7720_release(struct usb_serial *serial) -{ - int i; - -#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT - /* close the parallel port */ - - if (le16_to_cpu(serial->dev->descriptor.idProduct) - == MOSCHIP_DEVICE_ID_7715) { - struct urbtracker *urbtrack; - unsigned long flags; - struct mos7715_parport *mos_parport = - usb_get_serial_data(serial); - - /* prevent NULL ptr dereference in port callbacks */ - spin_lock(&release_lock); - mos_parport->pp->private_data = NULL; - spin_unlock(&release_lock); - - /* wait for synchronous usb calls to return */ - if (mos_parport->msg_pending) - wait_for_completion_timeout(&mos_parport->syncmsg_compl, - MOS_WDR_TIMEOUT); - - parport_remove_port(mos_parport->pp); - usb_set_serial_data(serial, NULL); - mos_parport->serial = NULL; - - /* if tasklet currently scheduled, wait for it to complete */ - tasklet_kill(&mos_parport->urb_tasklet); - - /* unlink any urbs sent by the tasklet */ - spin_lock_irqsave(&mos_parport->listlock, flags); - list_for_each_entry(urbtrack, - &mos_parport->active_urbs, - urblist_entry) - usb_unlink_urb(urbtrack->urb); - spin_unlock_irqrestore(&mos_parport->listlock, flags); - - kref_put(&mos_parport->ref_count, destroy_mos_parport); - } -#endif - /* free private structure allocated for serial port */ - for (i = 0; i < serial->num_ports; ++i) - kfree(usb_get_serial_port_data(serial->port[i])); -} - -static struct usb_driver usb_driver = { - .name = "moschip7720", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = moschip_port_id_table, -}; - -static struct usb_serial_driver moschip7720_2port_driver = { - .driver = { - .owner = THIS_MODULE, - .name = "moschip7720", - }, - .description = "Moschip 2 port adapter", - .id_table = moschip_port_id_table, - .calc_num_ports = mos77xx_calc_num_ports, - .open = mos7720_open, - .close = mos7720_close, - .throttle = mos7720_throttle, - .unthrottle = mos7720_unthrottle, - .probe = mos77xx_probe, - .attach = mos7720_startup, - .release = mos7720_release, - .ioctl = mos7720_ioctl, - .tiocmget = mos7720_tiocmget, - .tiocmset = mos7720_tiocmset, - .get_icount = mos7720_get_icount, - .set_termios = mos7720_set_termios, - .write = mos7720_write, - .write_room = mos7720_write_room, - .chars_in_buffer = mos7720_chars_in_buffer, - .break_ctl = mos7720_break, - .read_bulk_callback = mos7720_bulk_in_callback, - .read_int_callback = NULL /* dynamically assigned in probe() */ -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &moschip7720_2port_driver, NULL -}; - -module_usb_serial_driver(usb_driver, serial_drivers); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/mos7840.c b/ANDROID_3.4.5/drivers/usb/serial/mos7840.c deleted file mode 100644 index 62739ff5..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/mos7840.c +++ /dev/null @@ -1,2716 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Clean ups from Moschip version and a few ioctl implementations by: - * Paul B Schroeder - * - * Originally based on drivers/usb/serial/io_edgeport.c which is: - * Copyright (C) 2000 Inside Out Networks, All rights reserved. - * Copyright (C) 2001-2002 Greg Kroah-Hartman - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Version Information - */ -#define DRIVER_VERSION "1.3.2" -#define DRIVER_DESC "Moschip 7840/7820 USB Serial Driver" - -/* - * 16C50 UART register defines - */ - -#define LCR_BITS_5 0x00 /* 5 bits/char */ -#define LCR_BITS_6 0x01 /* 6 bits/char */ -#define LCR_BITS_7 0x02 /* 7 bits/char */ -#define LCR_BITS_8 0x03 /* 8 bits/char */ -#define LCR_BITS_MASK 0x03 /* Mask for bits/char field */ - -#define LCR_STOP_1 0x00 /* 1 stop bit */ -#define LCR_STOP_1_5 0x04 /* 1.5 stop bits (if 5 bits/char) */ -#define LCR_STOP_2 0x04 /* 2 stop bits (if 6-8 bits/char) */ -#define LCR_STOP_MASK 0x04 /* Mask for stop bits field */ - -#define LCR_PAR_NONE 0x00 /* No parity */ -#define LCR_PAR_ODD 0x08 /* Odd parity */ -#define LCR_PAR_EVEN 0x18 /* Even parity */ -#define LCR_PAR_MARK 0x28 /* Force parity bit to 1 */ -#define LCR_PAR_SPACE 0x38 /* Force parity bit to 0 */ -#define LCR_PAR_MASK 0x38 /* Mask for parity field */ - -#define LCR_SET_BREAK 0x40 /* Set Break condition */ -#define LCR_DL_ENABLE 0x80 /* Enable access to divisor latch */ - -#define MCR_DTR 0x01 /* Assert DTR */ -#define MCR_RTS 0x02 /* Assert RTS */ -#define MCR_OUT1 0x04 /* Loopback only: Sets state of RI */ -#define MCR_MASTER_IE 0x08 /* Enable interrupt outputs */ -#define MCR_LOOPBACK 0x10 /* Set internal (digital) loopback mode */ -#define MCR_XON_ANY 0x20 /* Enable any char to exit XOFF mode */ - -#define MOS7840_MSR_CTS 0x10 /* Current state of CTS */ -#define MOS7840_MSR_DSR 0x20 /* Current state of DSR */ -#define MOS7840_MSR_RI 0x40 /* Current state of RI */ -#define MOS7840_MSR_CD 0x80 /* Current state of CD */ - -/* - * Defines used for sending commands to port - */ - -#define WAIT_FOR_EVER (HZ * 0) /* timeout urb is wait for ever */ -#define MOS_WDR_TIMEOUT (HZ * 5) /* default urb timeout */ - -#define MOS_PORT1 0x0200 -#define MOS_PORT2 0x0300 -#define MOS_VENREG 0x0000 -#define MOS_MAX_PORT 0x02 -#define MOS_WRITE 0x0E -#define MOS_READ 0x0D - -/* Requests */ -#define MCS_RD_RTYPE 0xC0 -#define MCS_WR_RTYPE 0x40 -#define MCS_RDREQ 0x0D -#define MCS_WRREQ 0x0E -#define MCS_CTRL_TIMEOUT 500 -#define VENDOR_READ_LENGTH (0x01) - -#define MAX_NAME_LEN 64 - -#define ZLP_REG1 0x3A /* Zero_Flag_Reg1 58 */ -#define ZLP_REG5 0x3E /* Zero_Flag_Reg5 62 */ - -/* For higher baud Rates use TIOCEXBAUD */ -#define TIOCEXBAUD 0x5462 - -/* vendor id and device id defines */ - -/* The native mos7840/7820 component */ -#define USB_VENDOR_ID_MOSCHIP 0x9710 -#define MOSCHIP_DEVICE_ID_7840 0x7840 -#define MOSCHIP_DEVICE_ID_7820 0x7820 -/* The native component can have its vendor/device id's overridden - * in vendor-specific implementations. Such devices can be handled - * by making a change here, in moschip_port_id_table, and in - * moschip_id_table_combined - */ -#define USB_VENDOR_ID_BANDB 0x0856 -#define BANDB_DEVICE_ID_USO9ML2_2 0xAC22 -#define BANDB_DEVICE_ID_USO9ML2_2P 0xBC00 -#define BANDB_DEVICE_ID_USO9ML2_4 0xAC24 -#define BANDB_DEVICE_ID_USO9ML2_4P 0xBC01 -#define BANDB_DEVICE_ID_US9ML2_2 0xAC29 -#define BANDB_DEVICE_ID_US9ML2_4 0xAC30 -#define BANDB_DEVICE_ID_USPTL4_2 0xAC31 -#define BANDB_DEVICE_ID_USPTL4_4 0xAC32 -#define BANDB_DEVICE_ID_USOPTL4_2 0xAC42 -#define BANDB_DEVICE_ID_USOPTL4_2P 0xBC02 -#define BANDB_DEVICE_ID_USOPTL4_4 0xAC44 -#define BANDB_DEVICE_ID_USOPTL4_4P 0xBC03 -#define BANDB_DEVICE_ID_USOPTL2_4 0xAC24 - -/* This driver also supports - * ATEN UC2324 device using Moschip MCS7840 - * ATEN UC2322 device using Moschip MCS7820 - */ -#define USB_VENDOR_ID_ATENINTL 0x0557 -#define ATENINTL_DEVICE_ID_UC2324 0x2011 -#define ATENINTL_DEVICE_ID_UC2322 0x7820 - -/* Interrupt Routine Defines */ - -#define SERIAL_IIR_RLS 0x06 -#define SERIAL_IIR_MS 0x00 - -/* - * Emulation of the bit mask on the LINE STATUS REGISTER. - */ -#define SERIAL_LSR_DR 0x0001 -#define SERIAL_LSR_OE 0x0002 -#define SERIAL_LSR_PE 0x0004 -#define SERIAL_LSR_FE 0x0008 -#define SERIAL_LSR_BI 0x0010 - -#define MOS_MSR_DELTA_CTS 0x10 -#define MOS_MSR_DELTA_DSR 0x20 -#define MOS_MSR_DELTA_RI 0x40 -#define MOS_MSR_DELTA_CD 0x80 - -/* Serial Port register Address */ -#define INTERRUPT_ENABLE_REGISTER ((__u16)(0x01)) -#define FIFO_CONTROL_REGISTER ((__u16)(0x02)) -#define LINE_CONTROL_REGISTER ((__u16)(0x03)) -#define MODEM_CONTROL_REGISTER ((__u16)(0x04)) -#define LINE_STATUS_REGISTER ((__u16)(0x05)) -#define MODEM_STATUS_REGISTER ((__u16)(0x06)) -#define SCRATCH_PAD_REGISTER ((__u16)(0x07)) -#define DIVISOR_LATCH_LSB ((__u16)(0x00)) -#define DIVISOR_LATCH_MSB ((__u16)(0x01)) - -#define CLK_MULTI_REGISTER ((__u16)(0x02)) -#define CLK_START_VALUE_REGISTER ((__u16)(0x03)) -#define GPIO_REGISTER ((__u16)(0x07)) - -#define SERIAL_LCR_DLAB ((__u16)(0x0080)) - -/* - * URB POOL related defines - */ -#define NUM_URBS 16 /* URB Count */ -#define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */ - - -static const struct usb_device_id moschip_port_id_table[] = { - {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, - {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4P)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_2)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_2)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2P)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4P)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)}, - {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)}, - {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, - {} /* terminating entry */ -}; - -static const struct usb_device_id moschip_id_table_combined[] = { - {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, - {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4P)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_2)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_2)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2P)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4P)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)}, - {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)}, - {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, - {} /* terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, moschip_id_table_combined); - -/* This structure holds all of the local port information */ - -struct moschip_port { - int port_num; /*Actual port number in the device(1,2,etc) */ - struct urb *write_urb; /* write URB for this port */ - struct urb *read_urb; /* read URB for this port */ - struct urb *int_urb; - __u8 shadowLCR; /* last LCR value received */ - __u8 shadowMCR; /* last MCR value received */ - char open; - char open_ports; - char zombie; - wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */ - wait_queue_head_t delta_msr_wait; /* for handling sleeping while waiting for msr change to happen */ - int delta_msr_cond; - struct async_icount icount; - struct usb_serial_port *port; /* loop back to the owner of this object */ - - /* Offsets */ - __u8 SpRegOffset; - __u8 ControlRegOffset; - __u8 DcrRegOffset; - /* for processing control URBS in interrupt context */ - struct urb *control_urb; - struct usb_ctrlrequest *dr; - char *ctrl_buf; - int MsrLsr; - - spinlock_t pool_lock; - struct urb *write_urb_pool[NUM_URBS]; - char busy[NUM_URBS]; - bool read_urb_busy; -}; - - -static bool debug; - -/* - * mos7840_set_reg_sync - * To set the Control register by calling usb_fill_control_urb function - * by passing usb_sndctrlpipe function as parameter. - */ - -static int mos7840_set_reg_sync(struct usb_serial_port *port, __u16 reg, - __u16 val) -{ - struct usb_device *dev = port->serial->dev; - val = val & 0x00ff; - dbg("mos7840_set_reg_sync offset is %x, value %x", reg, val); - - return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ, - MCS_WR_RTYPE, val, reg, NULL, 0, - MOS_WDR_TIMEOUT); -} - -/* - * mos7840_get_reg_sync - * To set the Uart register by calling usb_fill_control_urb function by - * passing usb_rcvctrlpipe function as parameter. - */ - -static int mos7840_get_reg_sync(struct usb_serial_port *port, __u16 reg, - __u16 *val) -{ - struct usb_device *dev = port->serial->dev; - int ret = 0; - u8 *buf; - - buf = kmalloc(VENDOR_READ_LENGTH, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ, - MCS_RD_RTYPE, 0, reg, buf, VENDOR_READ_LENGTH, - MOS_WDR_TIMEOUT); - *val = buf[0]; - dbg("mos7840_get_reg_sync offset is %x, return val %x", reg, *val); - - kfree(buf); - return ret; -} - -/* - * mos7840_set_uart_reg - * To set the Uart register by calling usb_fill_control_urb function by - * passing usb_sndctrlpipe function as parameter. - */ - -static int mos7840_set_uart_reg(struct usb_serial_port *port, __u16 reg, - __u16 val) -{ - - struct usb_device *dev = port->serial->dev; - val = val & 0x00ff; - /* For the UART control registers, the application number need - to be Or'ed */ - if (port->serial->num_ports == 4) { - val |= (((__u16) port->number - - (__u16) (port->serial->minor)) + 1) << 8; - dbg("mos7840_set_uart_reg application number is %x", val); - } else { - if (((__u16) port->number - (__u16) (port->serial->minor)) == 0) { - val |= (((__u16) port->number - - (__u16) (port->serial->minor)) + 1) << 8; - dbg("mos7840_set_uart_reg application number is %x", - val); - } else { - val |= - (((__u16) port->number - - (__u16) (port->serial->minor)) + 2) << 8; - dbg("mos7840_set_uart_reg application number is %x", - val); - } - } - return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ, - MCS_WR_RTYPE, val, reg, NULL, 0, - MOS_WDR_TIMEOUT); - -} - -/* - * mos7840_get_uart_reg - * To set the Control register by calling usb_fill_control_urb function - * by passing usb_rcvctrlpipe function as parameter. - */ -static int mos7840_get_uart_reg(struct usb_serial_port *port, __u16 reg, - __u16 *val) -{ - struct usb_device *dev = port->serial->dev; - int ret = 0; - __u16 Wval; - u8 *buf; - - buf = kmalloc(VENDOR_READ_LENGTH, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - /* dbg("application number is %4x", - (((__u16)port->number - (__u16)(port->serial->minor))+1)<<8); */ - /* Wval is same as application number */ - if (port->serial->num_ports == 4) { - Wval = - (((__u16) port->number - (__u16) (port->serial->minor)) + - 1) << 8; - dbg("mos7840_get_uart_reg application number is %x", Wval); - } else { - if (((__u16) port->number - (__u16) (port->serial->minor)) == 0) { - Wval = (((__u16) port->number - - (__u16) (port->serial->minor)) + 1) << 8; - dbg("mos7840_get_uart_reg application number is %x", - Wval); - } else { - Wval = (((__u16) port->number - - (__u16) (port->serial->minor)) + 2) << 8; - dbg("mos7840_get_uart_reg application number is %x", - Wval); - } - } - ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ, - MCS_RD_RTYPE, Wval, reg, buf, VENDOR_READ_LENGTH, - MOS_WDR_TIMEOUT); - *val = buf[0]; - - kfree(buf); - return ret; -} - -static void mos7840_dump_serial_port(struct moschip_port *mos7840_port) -{ - - dbg("***************************************"); - dbg("SpRegOffset is %2x", mos7840_port->SpRegOffset); - dbg("ControlRegOffset is %2x", mos7840_port->ControlRegOffset); - dbg("DCRRegOffset is %2x", mos7840_port->DcrRegOffset); - dbg("***************************************"); - -} - -/************************************************************************/ -/************************************************************************/ -/* I N T E R F A C E F U N C T I O N S */ -/* I N T E R F A C E F U N C T I O N S */ -/************************************************************************/ -/************************************************************************/ - -static inline void mos7840_set_port_private(struct usb_serial_port *port, - struct moschip_port *data) -{ - usb_set_serial_port_data(port, (void *)data); -} - -static inline struct moschip_port *mos7840_get_port_private(struct - usb_serial_port - *port) -{ - return (struct moschip_port *)usb_get_serial_port_data(port); -} - -static void mos7840_handle_new_msr(struct moschip_port *port, __u8 new_msr) -{ - struct moschip_port *mos7840_port; - struct async_icount *icount; - mos7840_port = port; - icount = &mos7840_port->icount; - if (new_msr & - (MOS_MSR_DELTA_CTS | MOS_MSR_DELTA_DSR | MOS_MSR_DELTA_RI | - MOS_MSR_DELTA_CD)) { - icount = &mos7840_port->icount; - - /* update input line counters */ - if (new_msr & MOS_MSR_DELTA_CTS) { - icount->cts++; - smp_wmb(); - } - if (new_msr & MOS_MSR_DELTA_DSR) { - icount->dsr++; - smp_wmb(); - } - if (new_msr & MOS_MSR_DELTA_CD) { - icount->dcd++; - smp_wmb(); - } - if (new_msr & MOS_MSR_DELTA_RI) { - icount->rng++; - smp_wmb(); - } - } -} - -static void mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr) -{ - struct async_icount *icount; - - dbg("%s - %02x", __func__, new_lsr); - - if (new_lsr & SERIAL_LSR_BI) { - /* - * Parity and Framing errors only count if they - * occur exclusive of a break being - * received. - */ - new_lsr &= (__u8) (SERIAL_LSR_OE | SERIAL_LSR_BI); - } - - /* update input line counters */ - icount = &port->icount; - if (new_lsr & SERIAL_LSR_BI) { - icount->brk++; - smp_wmb(); - } - if (new_lsr & SERIAL_LSR_OE) { - icount->overrun++; - smp_wmb(); - } - if (new_lsr & SERIAL_LSR_PE) { - icount->parity++; - smp_wmb(); - } - if (new_lsr & SERIAL_LSR_FE) { - icount->frame++; - smp_wmb(); - } -} - -/************************************************************************/ -/************************************************************************/ -/* U S B C A L L B A C K F U N C T I O N S */ -/* U S B C A L L B A C K F U N C T I O N S */ -/************************************************************************/ -/************************************************************************/ - -static void mos7840_control_callback(struct urb *urb) -{ - unsigned char *data; - struct moschip_port *mos7840_port; - __u8 regval = 0x0; - int result = 0; - int status = urb->status; - - mos7840_port = urb->context; - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, - status); - return; - default: - dbg("%s - nonzero urb status received: %d", __func__, - status); - goto exit; - } - - dbg("%s urb buffer size is %d", __func__, urb->actual_length); - dbg("%s mos7840_port->MsrLsr is %d port %d", __func__, - mos7840_port->MsrLsr, mos7840_port->port_num); - data = urb->transfer_buffer; - regval = (__u8) data[0]; - dbg("%s data is %x", __func__, regval); - if (mos7840_port->MsrLsr == 0) - mos7840_handle_new_msr(mos7840_port, regval); - else if (mos7840_port->MsrLsr == 1) - mos7840_handle_new_lsr(mos7840_port, regval); - -exit: - spin_lock(&mos7840_port->pool_lock); - if (!mos7840_port->zombie) - result = usb_submit_urb(mos7840_port->int_urb, GFP_ATOMIC); - spin_unlock(&mos7840_port->pool_lock); - if (result) { - dev_err(&urb->dev->dev, - "%s - Error %d submitting interrupt urb\n", - __func__, result); - } -} - -static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, - __u16 *val) -{ - struct usb_device *dev = mcs->port->serial->dev; - struct usb_ctrlrequest *dr = mcs->dr; - unsigned char *buffer = mcs->ctrl_buf; - int ret; - - dr->bRequestType = MCS_RD_RTYPE; - dr->bRequest = MCS_RDREQ; - dr->wValue = cpu_to_le16(Wval); /* 0 */ - dr->wIndex = cpu_to_le16(reg); - dr->wLength = cpu_to_le16(2); - - usb_fill_control_urb(mcs->control_urb, dev, usb_rcvctrlpipe(dev, 0), - (unsigned char *)dr, buffer, 2, - mos7840_control_callback, mcs); - mcs->control_urb->transfer_buffer_length = 2; - ret = usb_submit_urb(mcs->control_urb, GFP_ATOMIC); - return ret; -} - -/***************************************************************************** - * mos7840_interrupt_callback - * this is the callback function for when we have received data on the - * interrupt endpoint. - *****************************************************************************/ - -static void mos7840_interrupt_callback(struct urb *urb) -{ - int result; - int length; - struct moschip_port *mos7840_port; - struct usb_serial *serial; - __u16 Data; - unsigned char *data; - __u8 sp[5], st; - int i, rv = 0; - __u16 wval, wreg = 0; - int status = urb->status; - - dbg("%s", " : Entering"); - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, - status); - return; - default: - dbg("%s - nonzero urb status received: %d", __func__, - status); - goto exit; - } - - length = urb->actual_length; - data = urb->transfer_buffer; - - serial = urb->context; - - /* Moschip get 5 bytes - * Byte 1 IIR Port 1 (port.number is 0) - * Byte 2 IIR Port 2 (port.number is 1) - * Byte 3 IIR Port 3 (port.number is 2) - * Byte 4 IIR Port 4 (port.number is 3) - * Byte 5 FIFO status for both */ - - if (length && length > 5) { - dbg("%s", "Wrong data !!!"); - return; - } - - sp[0] = (__u8) data[0]; - sp[1] = (__u8) data[1]; - sp[2] = (__u8) data[2]; - sp[3] = (__u8) data[3]; - st = (__u8) data[4]; - - for (i = 0; i < serial->num_ports; i++) { - mos7840_port = mos7840_get_port_private(serial->port[i]); - wval = - (((__u16) serial->port[i]->number - - (__u16) (serial->minor)) + 1) << 8; - if (mos7840_port->open) { - if (sp[i] & 0x01) { - dbg("SP%d No Interrupt !!!", i); - } else { - switch (sp[i] & 0x0f) { - case SERIAL_IIR_RLS: - dbg("Serial Port %d: Receiver status error or ", i); - dbg("address bit detected in 9-bit mode"); - mos7840_port->MsrLsr = 1; - wreg = LINE_STATUS_REGISTER; - break; - case SERIAL_IIR_MS: - dbg("Serial Port %d: Modem status change", i); - mos7840_port->MsrLsr = 0; - wreg = MODEM_STATUS_REGISTER; - break; - } - spin_lock(&mos7840_port->pool_lock); - if (!mos7840_port->zombie) { - rv = mos7840_get_reg(mos7840_port, wval, wreg, &Data); - } else { - spin_unlock(&mos7840_port->pool_lock); - return; - } - spin_unlock(&mos7840_port->pool_lock); - } - } - } - if (!(rv < 0)) - /* the completion handler for the control urb will resubmit */ - return; -exit: - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) { - dev_err(&urb->dev->dev, - "%s - Error %d submitting interrupt urb\n", - __func__, result); - } -} - -static int mos7840_port_paranoia_check(struct usb_serial_port *port, - const char *function) -{ - if (!port) { - dbg("%s - port == NULL", function); - return -1; - } - if (!port->serial) { - dbg("%s - port->serial == NULL", function); - return -1; - } - - return 0; -} - -/* Inline functions to check the sanity of a pointer that is passed to us */ -static int mos7840_serial_paranoia_check(struct usb_serial *serial, - const char *function) -{ - if (!serial) { - dbg("%s - serial == NULL", function); - return -1; - } - if (!serial->type) { - dbg("%s - serial->type == NULL!", function); - return -1; - } - - return 0; -} - -static struct usb_serial *mos7840_get_usb_serial(struct usb_serial_port *port, - const char *function) -{ - /* if no port was specified, or it fails a paranoia check */ - if (!port || - mos7840_port_paranoia_check(port, function) || - mos7840_serial_paranoia_check(port->serial, function)) { - /* then say that we don't have a valid usb_serial thing, - * which will end up genrating -ENODEV return values */ - return NULL; - } - - return port->serial; -} - -/***************************************************************************** - * mos7840_bulk_in_callback - * this is the callback function for when we have received data on the - * bulk in endpoint. - *****************************************************************************/ - -static void mos7840_bulk_in_callback(struct urb *urb) -{ - int retval; - unsigned char *data; - struct usb_serial *serial; - struct usb_serial_port *port; - struct moschip_port *mos7840_port; - struct tty_struct *tty; - int status = urb->status; - - mos7840_port = urb->context; - if (!mos7840_port) { - dbg("%s", "NULL mos7840_port pointer"); - return; - } - - if (status) { - dbg("nonzero read bulk status received: %d", status); - mos7840_port->read_urb_busy = false; - return; - } - - port = (struct usb_serial_port *)mos7840_port->port; - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Port Paranoia failed"); - mos7840_port->read_urb_busy = false; - return; - } - - serial = mos7840_get_usb_serial(port, __func__); - if (!serial) { - dbg("%s", "Bad serial pointer"); - mos7840_port->read_urb_busy = false; - return; - } - - dbg("%s", "Entering... "); - - data = urb->transfer_buffer; - - dbg("%s", "Entering ..........."); - - if (urb->actual_length) { - tty = tty_port_tty_get(&mos7840_port->port->port); - if (tty) { - tty_insert_flip_string(tty, data, urb->actual_length); - dbg(" %s ", data); - tty_flip_buffer_push(tty); - tty_kref_put(tty); - } - mos7840_port->icount.rx += urb->actual_length; - smp_wmb(); - dbg("mos7840_port->icount.rx is %d:", - mos7840_port->icount.rx); - } - - if (!mos7840_port->read_urb) { - dbg("%s", "URB KILLED !!!"); - mos7840_port->read_urb_busy = false; - return; - } - - - mos7840_port->read_urb_busy = true; - retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC); - - if (retval) { - dbg("usb_submit_urb(read bulk) failed, retval = %d", retval); - mos7840_port->read_urb_busy = false; - } -} - -/***************************************************************************** - * mos7840_bulk_out_data_callback - * this is the callback function for when we have finished sending - * serial data on the bulk out endpoint. - *****************************************************************************/ - -static void mos7840_bulk_out_data_callback(struct urb *urb) -{ - struct moschip_port *mos7840_port; - struct tty_struct *tty; - int status = urb->status; - int i; - - mos7840_port = urb->context; - spin_lock(&mos7840_port->pool_lock); - for (i = 0; i < NUM_URBS; i++) { - if (urb == mos7840_port->write_urb_pool[i]) { - mos7840_port->busy[i] = 0; - break; - } - } - spin_unlock(&mos7840_port->pool_lock); - - if (status) { - dbg("nonzero write bulk status received:%d", status); - return; - } - - if (mos7840_port_paranoia_check(mos7840_port->port, __func__)) { - dbg("%s", "Port Paranoia failed"); - return; - } - - dbg("%s", "Entering ........."); - - tty = tty_port_tty_get(&mos7840_port->port->port); - if (tty && mos7840_port->open) - tty_wakeup(tty); - tty_kref_put(tty); - -} - -/************************************************************************/ -/* D R I V E R T T Y I N T E R F A C E F U N C T I O N S */ -/************************************************************************/ -#ifdef MCSSerialProbe -static int mos7840_serial_probe(struct usb_serial *serial, - const struct usb_device_id *id) -{ - - /*need to implement the mode_reg reading and updating\ - structures usb_serial_ device_type\ - (i.e num_ports, num_bulkin,bulkout etc) */ - /* Also we can update the changes attach */ - return 1; -} -#endif - -/***************************************************************************** - * mos7840_open - * this function is called by the tty driver when a port is opened - * If successful, we return 0 - * Otherwise we return a negative error number. - *****************************************************************************/ - -static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - int response; - int j; - struct usb_serial *serial; - struct urb *urb; - __u16 Data; - int status; - struct moschip_port *mos7840_port; - struct moschip_port *port0; - - dbg ("%s enter", __func__); - - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Port Paranoia failed"); - return -ENODEV; - } - - serial = port->serial; - - if (mos7840_serial_paranoia_check(serial, __func__)) { - dbg("%s", "Serial Paranoia failed"); - return -ENODEV; - } - - mos7840_port = mos7840_get_port_private(port); - port0 = mos7840_get_port_private(serial->port[0]); - - if (mos7840_port == NULL || port0 == NULL) - return -ENODEV; - - usb_clear_halt(serial->dev, port->write_urb->pipe); - usb_clear_halt(serial->dev, port->read_urb->pipe); - port0->open_ports++; - - /* Initialising the write urb pool */ - for (j = 0; j < NUM_URBS; ++j) { - urb = usb_alloc_urb(0, GFP_KERNEL); - mos7840_port->write_urb_pool[j] = urb; - - if (urb == NULL) { - dev_err(&port->dev, "No more urbs???\n"); - continue; - } - - urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, - GFP_KERNEL); - if (!urb->transfer_buffer) { - usb_free_urb(urb); - mos7840_port->write_urb_pool[j] = NULL; - dev_err(&port->dev, - "%s-out of memory for urb buffers.\n", - __func__); - continue; - } - } - -/***************************************************************************** - * Initialize MCS7840 -- Write Init values to corresponding Registers - * - * Register Index - * 1 : IER - * 2 : FCR - * 3 : LCR - * 4 : MCR - * - * 0x08 : SP1/2 Control Reg - *****************************************************************************/ - - /* NEED to check the following Block */ - - Data = 0x0; - status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, &Data); - if (status < 0) { - dbg("Reading Spreg failed"); - return -1; - } - Data |= 0x80; - status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data); - if (status < 0) { - dbg("writing Spreg failed"); - return -1; - } - - Data &= ~0x80; - status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data); - if (status < 0) { - dbg("writing Spreg failed"); - return -1; - } - /* End of block to be checked */ - - Data = 0x0; - status = mos7840_get_reg_sync(port, mos7840_port->ControlRegOffset, - &Data); - if (status < 0) { - dbg("Reading Controlreg failed"); - return -1; - } - Data |= 0x08; /* Driver done bit */ - Data |= 0x20; /* rx_disable */ - status = mos7840_set_reg_sync(port, - mos7840_port->ControlRegOffset, Data); - if (status < 0) { - dbg("writing Controlreg failed"); - return -1; - } - /* do register settings here */ - /* Set all regs to the device default values. */ - /*********************************** - * First Disable all interrupts. - ***********************************/ - Data = 0x00; - status = mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data); - if (status < 0) { - dbg("disabling interrupts failed"); - return -1; - } - /* Set FIFO_CONTROL_REGISTER to the default value */ - Data = 0x00; - status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data); - if (status < 0) { - dbg("Writing FIFO_CONTROL_REGISTER failed"); - return -1; - } - - Data = 0xcf; - status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data); - if (status < 0) { - dbg("Writing FIFO_CONTROL_REGISTER failed"); - return -1; - } - - Data = 0x03; - status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data); - mos7840_port->shadowLCR = Data; - - Data = 0x0b; - status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data); - mos7840_port->shadowMCR = Data; - - Data = 0x00; - status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data); - mos7840_port->shadowLCR = Data; - - Data |= SERIAL_LCR_DLAB; /* data latch enable in LCR 0x80 */ - status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data); - - Data = 0x0c; - status = mos7840_set_uart_reg(port, DIVISOR_LATCH_LSB, Data); - - Data = 0x0; - status = mos7840_set_uart_reg(port, DIVISOR_LATCH_MSB, Data); - - Data = 0x00; - status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data); - - Data = Data & ~SERIAL_LCR_DLAB; - status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data); - mos7840_port->shadowLCR = Data; - - /* clearing Bulkin and Bulkout Fifo */ - Data = 0x0; - status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, &Data); - - Data = Data | 0x0c; - status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data); - - Data = Data & ~0x0c; - status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data); - /* Finally enable all interrupts */ - Data = 0x0c; - status = mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data); - - /* clearing rx_disable */ - Data = 0x0; - status = mos7840_get_reg_sync(port, mos7840_port->ControlRegOffset, - &Data); - Data = Data & ~0x20; - status = mos7840_set_reg_sync(port, mos7840_port->ControlRegOffset, - Data); - - /* rx_negate */ - Data = 0x0; - status = mos7840_get_reg_sync(port, mos7840_port->ControlRegOffset, - &Data); - Data = Data | 0x10; - status = mos7840_set_reg_sync(port, mos7840_port->ControlRegOffset, - Data); - - /* Check to see if we've set up our endpoint info yet * - * (can't set it up in mos7840_startup as the structures * - * were not set up at that time.) */ - if (port0->open_ports == 1) { - if (serial->port[0]->interrupt_in_buffer == NULL) { - /* set up interrupt urb */ - usb_fill_int_urb(serial->port[0]->interrupt_in_urb, - serial->dev, - usb_rcvintpipe(serial->dev, - serial->port[0]->interrupt_in_endpointAddress), - serial->port[0]->interrupt_in_buffer, - serial->port[0]->interrupt_in_urb-> - transfer_buffer_length, - mos7840_interrupt_callback, - serial, - serial->port[0]->interrupt_in_urb->interval); - - /* start interrupt read for mos7840 * - * will continue as long as mos7840 is connected */ - - response = - usb_submit_urb(serial->port[0]->interrupt_in_urb, - GFP_KERNEL); - if (response) { - dev_err(&port->dev, "%s - Error %d submitting " - "interrupt urb\n", __func__, response); - } - - } - - } - - /* see if we've set up our endpoint info yet * - * (can't set it up in mos7840_startup as the * - * structures were not set up at that time.) */ - - dbg("port number is %d", port->number); - dbg("serial number is %d", port->serial->minor); - dbg("Bulkin endpoint is %d", port->bulk_in_endpointAddress); - dbg("BulkOut endpoint is %d", port->bulk_out_endpointAddress); - dbg("Interrupt endpoint is %d", port->interrupt_in_endpointAddress); - dbg("port's number in the device is %d", mos7840_port->port_num); - mos7840_port->read_urb = port->read_urb; - - /* set up our bulk in urb */ - if ((serial->num_ports == 2) - && ((((__u16)port->number - - (__u16)(port->serial->minor)) % 2) != 0)) { - usb_fill_bulk_urb(mos7840_port->read_urb, - serial->dev, - usb_rcvbulkpipe(serial->dev, - (port->bulk_in_endpointAddress) + 2), - port->bulk_in_buffer, - mos7840_port->read_urb->transfer_buffer_length, - mos7840_bulk_in_callback, mos7840_port); - } else { - usb_fill_bulk_urb(mos7840_port->read_urb, - serial->dev, - usb_rcvbulkpipe(serial->dev, - port->bulk_in_endpointAddress), - port->bulk_in_buffer, - mos7840_port->read_urb->transfer_buffer_length, - mos7840_bulk_in_callback, mos7840_port); - } - - dbg("mos7840_open: bulkin endpoint is %d", - port->bulk_in_endpointAddress); - mos7840_port->read_urb_busy = true; - response = usb_submit_urb(mos7840_port->read_urb, GFP_KERNEL); - if (response) { - dev_err(&port->dev, "%s - Error %d submitting control urb\n", - __func__, response); - mos7840_port->read_urb_busy = false; - } - - /* initialize our wait queues */ - init_waitqueue_head(&mos7840_port->wait_chase); - init_waitqueue_head(&mos7840_port->delta_msr_wait); - - /* initialize our icount structure */ - memset(&(mos7840_port->icount), 0x00, sizeof(mos7840_port->icount)); - - /* initialize our port settings */ - /* Must set to enable ints! */ - mos7840_port->shadowMCR = MCR_MASTER_IE; - /* send a open port command */ - mos7840_port->open = 1; - /* mos7840_change_port_settings(mos7840_port,old_termios); */ - mos7840_port->icount.tx = 0; - mos7840_port->icount.rx = 0; - - dbg("usb_serial serial:%p mos7840_port:%p\n usb_serial_port port:%p", - serial, mos7840_port, port); - - dbg ("%s leave", __func__); - - return 0; - -} - -/***************************************************************************** - * mos7840_chars_in_buffer - * this function is called by the tty driver when it wants to know how many - * bytes of data we currently have outstanding in the port (data that has - * been written, but hasn't made it out the port yet) - * If successful, we return the number of bytes left to be written in the - * system, - * Otherwise we return zero. - *****************************************************************************/ - -static int mos7840_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - int i; - int chars = 0; - unsigned long flags; - struct moschip_port *mos7840_port; - - dbg("%s", " mos7840_chars_in_buffer:entering ..........."); - - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port"); - return 0; - } - - mos7840_port = mos7840_get_port_private(port); - if (mos7840_port == NULL) { - dbg("%s", "mos7840_break:leaving ..........."); - return 0; - } - - spin_lock_irqsave(&mos7840_port->pool_lock, flags); - for (i = 0; i < NUM_URBS; ++i) - if (mos7840_port->busy[i]) - chars += URB_TRANSFER_BUFFER_SIZE; - spin_unlock_irqrestore(&mos7840_port->pool_lock, flags); - dbg("%s - returns %d", __func__, chars); - return chars; - -} - -/***************************************************************************** - * mos7840_close - * this function is called by the tty driver when a port is closed - *****************************************************************************/ - -static void mos7840_close(struct usb_serial_port *port) -{ - struct usb_serial *serial; - struct moschip_port *mos7840_port; - struct moschip_port *port0; - int j; - __u16 Data; - - dbg("%s", "mos7840_close:entering..."); - - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Port Paranoia failed"); - return; - } - - serial = mos7840_get_usb_serial(port, __func__); - if (!serial) { - dbg("%s", "Serial Paranoia failed"); - return; - } - - mos7840_port = mos7840_get_port_private(port); - port0 = mos7840_get_port_private(serial->port[0]); - - if (mos7840_port == NULL || port0 == NULL) - return; - - for (j = 0; j < NUM_URBS; ++j) - usb_kill_urb(mos7840_port->write_urb_pool[j]); - - /* Freeing Write URBs */ - for (j = 0; j < NUM_URBS; ++j) { - if (mos7840_port->write_urb_pool[j]) { - if (mos7840_port->write_urb_pool[j]->transfer_buffer) - kfree(mos7840_port->write_urb_pool[j]-> - transfer_buffer); - - usb_free_urb(mos7840_port->write_urb_pool[j]); - } - } - - /* While closing port, shutdown all bulk read, write * - * and interrupt read if they exists */ - if (serial->dev) { - if (mos7840_port->write_urb) { - dbg("%s", "Shutdown bulk write"); - usb_kill_urb(mos7840_port->write_urb); - } - if (mos7840_port->read_urb) { - dbg("%s", "Shutdown bulk read"); - usb_kill_urb(mos7840_port->read_urb); - mos7840_port->read_urb_busy = false; - } - if ((&mos7840_port->control_urb)) { - dbg("%s", "Shutdown control read"); - /*/ usb_kill_urb (mos7840_port->control_urb); */ - } - } -/* if(mos7840_port->ctrl_buf != NULL) */ -/* kfree(mos7840_port->ctrl_buf); */ - port0->open_ports--; - dbg("mos7840_num_open_ports in close%d:in port%d", - port0->open_ports, port->number); - if (port0->open_ports == 0) { - if (serial->port[0]->interrupt_in_urb) { - dbg("%s", "Shutdown interrupt_in_urb"); - usb_kill_urb(serial->port[0]->interrupt_in_urb); - } - } - - if (mos7840_port->write_urb) { - /* if this urb had a transfer buffer already (old tx) free it */ - if (mos7840_port->write_urb->transfer_buffer != NULL) - kfree(mos7840_port->write_urb->transfer_buffer); - usb_free_urb(mos7840_port->write_urb); - } - - Data = 0x0; - mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data); - - Data = 0x00; - mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data); - - mos7840_port->open = 0; - - dbg("%s", "Leaving ............"); -} - -/************************************************************************ - * - * mos7840_block_until_chase_response - * - * This function will block the close until one of the following: - * 1. Response to our Chase comes from mos7840 - * 2. A timeout of 10 seconds without activity has expired - * (1K of mos7840 data @ 2400 baud ==> 4 sec to empty) - * - ************************************************************************/ - -static void mos7840_block_until_chase_response(struct tty_struct *tty, - struct moschip_port *mos7840_port) -{ - int timeout = 1 * HZ; - int wait = 10; - int count; - - while (1) { - count = mos7840_chars_in_buffer(tty); - - /* Check for Buffer status */ - if (count <= 0) - return; - - /* Block the thread for a while */ - interruptible_sleep_on_timeout(&mos7840_port->wait_chase, - timeout); - /* No activity.. count down section */ - wait--; - if (wait == 0) { - dbg("%s - TIMEOUT", __func__); - return; - } else { - /* Reset timeout value back to seconds */ - wait = 10; - } - } - -} - -/***************************************************************************** - * mos7840_break - * this function sends a break to the port - *****************************************************************************/ -static void mos7840_break(struct tty_struct *tty, int break_state) -{ - struct usb_serial_port *port = tty->driver_data; - unsigned char data; - struct usb_serial *serial; - struct moschip_port *mos7840_port; - - dbg("%s", "Entering ..........."); - dbg("mos7840_break: Start"); - - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Port Paranoia failed"); - return; - } - - serial = mos7840_get_usb_serial(port, __func__); - if (!serial) { - dbg("%s", "Serial Paranoia failed"); - return; - } - - mos7840_port = mos7840_get_port_private(port); - - if (mos7840_port == NULL) - return; - - if (serial->dev) - /* flush and block until tx is empty */ - mos7840_block_until_chase_response(tty, mos7840_port); - - if (break_state == -1) - data = mos7840_port->shadowLCR | LCR_SET_BREAK; - else - data = mos7840_port->shadowLCR & ~LCR_SET_BREAK; - - /* FIXME: no locking on shadowLCR anywhere in driver */ - mos7840_port->shadowLCR = data; - dbg("mcs7840_break mos7840_port->shadowLCR is %x", - mos7840_port->shadowLCR); - mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, - mos7840_port->shadowLCR); -} - -/***************************************************************************** - * mos7840_write_room - * this function is called by the tty driver when it wants to know how many - * bytes of data we can accept for a specific port. - * If successful, we return the amount of room that we have for this port - * Otherwise we return a negative error number. - *****************************************************************************/ - -static int mos7840_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - int i; - int room = 0; - unsigned long flags; - struct moschip_port *mos7840_port; - - dbg("%s", " mos7840_write_room:entering ..........."); - - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port"); - dbg("%s", " mos7840_write_room:leaving ..........."); - return -1; - } - - mos7840_port = mos7840_get_port_private(port); - if (mos7840_port == NULL) { - dbg("%s", "mos7840_break:leaving ..........."); - return -1; - } - - spin_lock_irqsave(&mos7840_port->pool_lock, flags); - for (i = 0; i < NUM_URBS; ++i) { - if (!mos7840_port->busy[i]) - room += URB_TRANSFER_BUFFER_SIZE; - } - spin_unlock_irqrestore(&mos7840_port->pool_lock, flags); - - room = (room == 0) ? 0 : room - URB_TRANSFER_BUFFER_SIZE + 1; - dbg("%s - returns %d", __func__, room); - return room; - -} - -/***************************************************************************** - * mos7840_write - * this function is called by the tty driver when data should be written to - * the port. - * If successful, we return the number of bytes written, otherwise we - * return a negative error number. - *****************************************************************************/ - -static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *data, int count) -{ - int status; - int i; - int bytes_sent = 0; - int transfer_size; - unsigned long flags; - - struct moschip_port *mos7840_port; - struct usb_serial *serial; - struct urb *urb; - /* __u16 Data; */ - const unsigned char *current_position = data; - unsigned char *data1; - dbg("%s", "entering ..........."); - /* dbg("mos7840_write: mos7840_port->shadowLCR is %x", - mos7840_port->shadowLCR); */ - -#ifdef NOTMOS7840 - Data = 0x00; - status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data); - mos7840_port->shadowLCR = Data; - dbg("mos7840_write: LINE_CONTROL_REGISTER is %x", Data); - dbg("mos7840_write: mos7840_port->shadowLCR is %x", - mos7840_port->shadowLCR); - - /* Data = 0x03; */ - /* status = mos7840_set_uart_reg(port,LINE_CONTROL_REGISTER,Data); */ - /* mos7840_port->shadowLCR=Data;//Need to add later */ - - Data |= SERIAL_LCR_DLAB; /* data latch enable in LCR 0x80 */ - status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data); - - /* Data = 0x0c; */ - /* status = mos7840_set_uart_reg(port,DIVISOR_LATCH_LSB,Data); */ - Data = 0x00; - status = mos7840_get_uart_reg(port, DIVISOR_LATCH_LSB, &Data); - dbg("mos7840_write:DLL value is %x", Data); - - Data = 0x0; - status = mos7840_get_uart_reg(port, DIVISOR_LATCH_MSB, &Data); - dbg("mos7840_write:DLM value is %x", Data); - - Data = Data & ~SERIAL_LCR_DLAB; - dbg("mos7840_write: mos7840_port->shadowLCR is %x", - mos7840_port->shadowLCR); - status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data); -#endif - - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Port Paranoia failed"); - return -1; - } - - serial = port->serial; - if (mos7840_serial_paranoia_check(serial, __func__)) { - dbg("%s", "Serial Paranoia failed"); - return -1; - } - - mos7840_port = mos7840_get_port_private(port); - if (mos7840_port == NULL) { - dbg("%s", "mos7840_port is NULL"); - return -1; - } - - /* try to find a free urb in the list */ - urb = NULL; - - spin_lock_irqsave(&mos7840_port->pool_lock, flags); - for (i = 0; i < NUM_URBS; ++i) { - if (!mos7840_port->busy[i]) { - mos7840_port->busy[i] = 1; - urb = mos7840_port->write_urb_pool[i]; - dbg("URB:%d", i); - break; - } - } - spin_unlock_irqrestore(&mos7840_port->pool_lock, flags); - - if (urb == NULL) { - dbg("%s - no more free urbs", __func__); - goto exit; - } - - if (urb->transfer_buffer == NULL) { - urb->transfer_buffer = - kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); - - if (urb->transfer_buffer == NULL) { - dev_err_console(port, "%s no more kernel memory...\n", - __func__); - goto exit; - } - } - transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE); - - memcpy(urb->transfer_buffer, current_position, transfer_size); - - /* fill urb with data and submit */ - if ((serial->num_ports == 2) - && ((((__u16)port->number - - (__u16)(port->serial->minor)) % 2) != 0)) { - usb_fill_bulk_urb(urb, - serial->dev, - usb_sndbulkpipe(serial->dev, - (port->bulk_out_endpointAddress) + 2), - urb->transfer_buffer, - transfer_size, - mos7840_bulk_out_data_callback, mos7840_port); - } else { - usb_fill_bulk_urb(urb, - serial->dev, - usb_sndbulkpipe(serial->dev, - port->bulk_out_endpointAddress), - urb->transfer_buffer, - transfer_size, - mos7840_bulk_out_data_callback, mos7840_port); - } - - data1 = urb->transfer_buffer; - dbg("bulkout endpoint is %d", port->bulk_out_endpointAddress); - - /* send it down the pipe */ - status = usb_submit_urb(urb, GFP_ATOMIC); - - if (status) { - mos7840_port->busy[i] = 0; - dev_err_console(port, "%s - usb_submit_urb(write bulk) failed " - "with status = %d\n", __func__, status); - bytes_sent = status; - goto exit; - } - bytes_sent = transfer_size; - mos7840_port->icount.tx += transfer_size; - smp_wmb(); - dbg("mos7840_port->icount.tx is %d:", mos7840_port->icount.tx); -exit: - return bytes_sent; - -} - -/***************************************************************************** - * mos7840_throttle - * this function is called by the tty driver when it wants to stop the data - * being read from the port. - *****************************************************************************/ - -static void mos7840_throttle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct moschip_port *mos7840_port; - int status; - - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port"); - return; - } - - dbg("- port %d", port->number); - - mos7840_port = mos7840_get_port_private(port); - - if (mos7840_port == NULL) - return; - - if (!mos7840_port->open) { - dbg("%s", "port not opened"); - return; - } - - dbg("%s", "Entering .........."); - - /* if we are implementing XON/XOFF, send the stop character */ - if (I_IXOFF(tty)) { - unsigned char stop_char = STOP_CHAR(tty); - status = mos7840_write(tty, port, &stop_char, 1); - if (status <= 0) - return; - } - /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { - mos7840_port->shadowMCR &= ~MCR_RTS; - status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, - mos7840_port->shadowMCR); - if (status < 0) - return; - } -} - -/***************************************************************************** - * mos7840_unthrottle - * this function is called by the tty driver when it wants to resume - * the data being read from the port (called after mos7840_throttle is - * called) - *****************************************************************************/ -static void mos7840_unthrottle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - int status; - struct moschip_port *mos7840_port = mos7840_get_port_private(port); - - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port"); - return; - } - - if (mos7840_port == NULL) - return; - - if (!mos7840_port->open) { - dbg("%s - port not opened", __func__); - return; - } - - dbg("%s", "Entering .........."); - - /* if we are implementing XON/XOFF, send the start character */ - if (I_IXOFF(tty)) { - unsigned char start_char = START_CHAR(tty); - status = mos7840_write(tty, port, &start_char, 1); - if (status <= 0) - return; - } - - /* if we are implementing RTS/CTS, toggle that line */ - if (tty->termios->c_cflag & CRTSCTS) { - mos7840_port->shadowMCR |= MCR_RTS; - status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, - mos7840_port->shadowMCR); - if (status < 0) - return; - } -} - -static int mos7840_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct moschip_port *mos7840_port; - unsigned int result; - __u16 msr; - __u16 mcr; - int status; - mos7840_port = mos7840_get_port_private(port); - - dbg("%s - port %d", __func__, port->number); - - if (mos7840_port == NULL) - return -ENODEV; - - status = mos7840_get_uart_reg(port, MODEM_STATUS_REGISTER, &msr); - status = mos7840_get_uart_reg(port, MODEM_CONTROL_REGISTER, &mcr); - result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0) - | ((mcr & MCR_RTS) ? TIOCM_RTS : 0) - | ((mcr & MCR_LOOPBACK) ? TIOCM_LOOP : 0) - | ((msr & MOS7840_MSR_CTS) ? TIOCM_CTS : 0) - | ((msr & MOS7840_MSR_CD) ? TIOCM_CAR : 0) - | ((msr & MOS7840_MSR_RI) ? TIOCM_RI : 0) - | ((msr & MOS7840_MSR_DSR) ? TIOCM_DSR : 0); - - dbg("%s - 0x%04X", __func__, result); - - return result; -} - -static int mos7840_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct moschip_port *mos7840_port; - unsigned int mcr; - int status; - - dbg("%s - port %d", __func__, port->number); - - mos7840_port = mos7840_get_port_private(port); - - if (mos7840_port == NULL) - return -ENODEV; - - /* FIXME: What locks the port registers ? */ - mcr = mos7840_port->shadowMCR; - if (clear & TIOCM_RTS) - mcr &= ~MCR_RTS; - if (clear & TIOCM_DTR) - mcr &= ~MCR_DTR; - if (clear & TIOCM_LOOP) - mcr &= ~MCR_LOOPBACK; - - if (set & TIOCM_RTS) - mcr |= MCR_RTS; - if (set & TIOCM_DTR) - mcr |= MCR_DTR; - if (set & TIOCM_LOOP) - mcr |= MCR_LOOPBACK; - - mos7840_port->shadowMCR = mcr; - - status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mcr); - if (status < 0) { - dbg("setting MODEM_CONTROL_REGISTER Failed"); - return status; - } - - return 0; -} - -/***************************************************************************** - * mos7840_calc_baud_rate_divisor - * this function calculates the proper baud rate divisor for the specified - * baud rate. - *****************************************************************************/ -static int mos7840_calc_baud_rate_divisor(int baudRate, int *divisor, - __u16 *clk_sel_val) -{ - - dbg("%s - %d", __func__, baudRate); - - if (baudRate <= 115200) { - *divisor = 115200 / baudRate; - *clk_sel_val = 0x0; - } - if ((baudRate > 115200) && (baudRate <= 230400)) { - *divisor = 230400 / baudRate; - *clk_sel_val = 0x10; - } else if ((baudRate > 230400) && (baudRate <= 403200)) { - *divisor = 403200 / baudRate; - *clk_sel_val = 0x20; - } else if ((baudRate > 403200) && (baudRate <= 460800)) { - *divisor = 460800 / baudRate; - *clk_sel_val = 0x30; - } else if ((baudRate > 460800) && (baudRate <= 806400)) { - *divisor = 806400 / baudRate; - *clk_sel_val = 0x40; - } else if ((baudRate > 806400) && (baudRate <= 921600)) { - *divisor = 921600 / baudRate; - *clk_sel_val = 0x50; - } else if ((baudRate > 921600) && (baudRate <= 1572864)) { - *divisor = 1572864 / baudRate; - *clk_sel_val = 0x60; - } else if ((baudRate > 1572864) && (baudRate <= 3145728)) { - *divisor = 3145728 / baudRate; - *clk_sel_val = 0x70; - } - return 0; - -#ifdef NOTMCS7840 - - for (i = 0; i < ARRAY_SIZE(mos7840_divisor_table); i++) { - if (mos7840_divisor_table[i].BaudRate == baudrate) { - *divisor = mos7840_divisor_table[i].Divisor; - return 0; - } - } - - /* After trying for all the standard baud rates * - * Try calculating the divisor for this baud rate */ - - if (baudrate > 75 && baudrate < 230400) { - /* get the divisor */ - custom = (__u16) (230400L / baudrate); - - /* Check for round off */ - round1 = (__u16) (2304000L / baudrate); - round = (__u16) (round1 - (custom * 10)); - if (round > 4) - custom++; - *divisor = custom; - - dbg(" Baud %d = %d", baudrate, custom); - return 0; - } - - dbg("%s", " Baud calculation Failed..."); - return -1; -#endif -} - -/***************************************************************************** - * mos7840_send_cmd_write_baud_rate - * this function sends the proper command to change the baud rate of the - * specified port. - *****************************************************************************/ - -static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, - int baudRate) -{ - int divisor = 0; - int status; - __u16 Data; - unsigned char number; - __u16 clk_sel_val; - struct usb_serial_port *port; - - if (mos7840_port == NULL) - return -1; - - port = (struct usb_serial_port *)mos7840_port->port; - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port"); - return -1; - } - - if (mos7840_serial_paranoia_check(port->serial, __func__)) { - dbg("%s", "Invalid Serial"); - return -1; - } - - dbg("%s", "Entering .........."); - - number = mos7840_port->port->number - mos7840_port->port->serial->minor; - - dbg("%s - port = %d, baud = %d", __func__, - mos7840_port->port->number, baudRate); - /* reset clk_uart_sel in spregOffset */ - if (baudRate > 115200) { -#ifdef HW_flow_control - /* NOTE: need to see the pther register to modify */ - /* setting h/w flow control bit to 1 */ - Data = 0x2b; - mos7840_port->shadowMCR = Data; - status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, - Data); - if (status < 0) { - dbg("Writing spreg failed in set_serial_baud"); - return -1; - } -#endif - - } else { -#ifdef HW_flow_control - /* setting h/w flow control bit to 0 */ - Data = 0xb; - mos7840_port->shadowMCR = Data; - status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, - Data); - if (status < 0) { - dbg("Writing spreg failed in set_serial_baud"); - return -1; - } -#endif - - } - - if (1) { /* baudRate <= 115200) */ - clk_sel_val = 0x0; - Data = 0x0; - status = mos7840_calc_baud_rate_divisor(baudRate, &divisor, - &clk_sel_val); - status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, - &Data); - if (status < 0) { - dbg("reading spreg failed in set_serial_baud"); - return -1; - } - Data = (Data & 0x8f) | clk_sel_val; - status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, - Data); - if (status < 0) { - dbg("Writing spreg failed in set_serial_baud"); - return -1; - } - /* Calculate the Divisor */ - - if (status) { - dev_err(&port->dev, "%s - bad baud rate\n", __func__); - return status; - } - /* Enable access to divisor latch */ - Data = mos7840_port->shadowLCR | SERIAL_LCR_DLAB; - mos7840_port->shadowLCR = Data; - mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data); - - /* Write the divisor */ - Data = (unsigned char)(divisor & 0xff); - dbg("set_serial_baud Value to write DLL is %x", Data); - mos7840_set_uart_reg(port, DIVISOR_LATCH_LSB, Data); - - Data = (unsigned char)((divisor & 0xff00) >> 8); - dbg("set_serial_baud Value to write DLM is %x", Data); - mos7840_set_uart_reg(port, DIVISOR_LATCH_MSB, Data); - - /* Disable access to divisor latch */ - Data = mos7840_port->shadowLCR & ~SERIAL_LCR_DLAB; - mos7840_port->shadowLCR = Data; - mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data); - - } - return status; -} - -/***************************************************************************** - * mos7840_change_port_settings - * This routine is called to set the UART on the device to match - * the specified new settings. - *****************************************************************************/ - -static void mos7840_change_port_settings(struct tty_struct *tty, - struct moschip_port *mos7840_port, struct ktermios *old_termios) -{ - int baud; - unsigned cflag; - unsigned iflag; - __u8 lData; - __u8 lParity; - __u8 lStop; - int status; - __u16 Data; - struct usb_serial_port *port; - struct usb_serial *serial; - - if (mos7840_port == NULL) - return; - - port = (struct usb_serial_port *)mos7840_port->port; - - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port"); - return; - } - - if (mos7840_serial_paranoia_check(port->serial, __func__)) { - dbg("%s", "Invalid Serial"); - return; - } - - serial = port->serial; - - dbg("%s - port %d", __func__, mos7840_port->port->number); - - if (!mos7840_port->open) { - dbg("%s - port not opened", __func__); - return; - } - - dbg("%s", "Entering .........."); - - lData = LCR_BITS_8; - lStop = LCR_STOP_1; - lParity = LCR_PAR_NONE; - - cflag = tty->termios->c_cflag; - iflag = tty->termios->c_iflag; - - /* Change the number of bits */ - if (cflag & CSIZE) { - switch (cflag & CSIZE) { - case CS5: - lData = LCR_BITS_5; - break; - - case CS6: - lData = LCR_BITS_6; - break; - - case CS7: - lData = LCR_BITS_7; - break; - default: - case CS8: - lData = LCR_BITS_8; - break; - } - } - /* Change the Parity bit */ - if (cflag & PARENB) { - if (cflag & PARODD) { - lParity = LCR_PAR_ODD; - dbg("%s - parity = odd", __func__); - } else { - lParity = LCR_PAR_EVEN; - dbg("%s - parity = even", __func__); - } - - } else { - dbg("%s - parity = none", __func__); - } - - if (cflag & CMSPAR) - lParity = lParity | 0x20; - - /* Change the Stop bit */ - if (cflag & CSTOPB) { - lStop = LCR_STOP_2; - dbg("%s - stop bits = 2", __func__); - } else { - lStop = LCR_STOP_1; - dbg("%s - stop bits = 1", __func__); - } - - /* Update the LCR with the correct value */ - mos7840_port->shadowLCR &= - ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK); - mos7840_port->shadowLCR |= (lData | lParity | lStop); - - dbg("mos7840_change_port_settings mos7840_port->shadowLCR is %x", - mos7840_port->shadowLCR); - /* Disable Interrupts */ - Data = 0x00; - mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data); - - Data = 0x00; - mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data); - - Data = 0xcf; - mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data); - - /* Send the updated LCR value to the mos7840 */ - Data = mos7840_port->shadowLCR; - - mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data); - - Data = 0x00b; - mos7840_port->shadowMCR = Data; - mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data); - Data = 0x00b; - mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data); - - /* set up the MCR register and send it to the mos7840 */ - - mos7840_port->shadowMCR = MCR_MASTER_IE; - if (cflag & CBAUD) - mos7840_port->shadowMCR |= (MCR_DTR | MCR_RTS); - - if (cflag & CRTSCTS) - mos7840_port->shadowMCR |= (MCR_XON_ANY); - else - mos7840_port->shadowMCR &= ~(MCR_XON_ANY); - - Data = mos7840_port->shadowMCR; - mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data); - - /* Determine divisor based on baud rate */ - baud = tty_get_baud_rate(tty); - - if (!baud) { - /* pick a default, any default... */ - dbg("%s", "Picked default baud..."); - baud = 9600; - } - - dbg("%s - baud rate = %d", __func__, baud); - status = mos7840_send_cmd_write_baud_rate(mos7840_port, baud); - - /* Enable Interrupts */ - Data = 0x0c; - mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data); - - if (mos7840_port->read_urb_busy == false) { - mos7840_port->read_urb_busy = true; - status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC); - if (status) { - dbg("usb_submit_urb(read bulk) failed, status = %d", - status); - mos7840_port->read_urb_busy = false; - } - } - wake_up(&mos7840_port->delta_msr_wait); - mos7840_port->delta_msr_cond = 1; - dbg("mos7840_change_port_settings mos7840_port->shadowLCR is End %x", - mos7840_port->shadowLCR); -} - -/***************************************************************************** - * mos7840_set_termios - * this function is called by the tty driver when it wants to change - * the termios structure - *****************************************************************************/ - -static void mos7840_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old_termios) -{ - int status; - unsigned int cflag; - struct usb_serial *serial; - struct moschip_port *mos7840_port; - dbg("mos7840_set_termios: START"); - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port"); - return; - } - - serial = port->serial; - - if (mos7840_serial_paranoia_check(serial, __func__)) { - dbg("%s", "Invalid Serial"); - return; - } - - mos7840_port = mos7840_get_port_private(port); - - if (mos7840_port == NULL) - return; - - if (!mos7840_port->open) { - dbg("%s - port not opened", __func__); - return; - } - - dbg("%s", "setting termios - "); - - cflag = tty->termios->c_cflag; - - dbg("%s - clfag %08x iflag %08x", __func__, - tty->termios->c_cflag, RELEVANT_IFLAG(tty->termios->c_iflag)); - dbg("%s - old clfag %08x old iflag %08x", __func__, - old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag)); - dbg("%s - port %d", __func__, port->number); - - /* change the port settings to the new ones specified */ - - mos7840_change_port_settings(tty, mos7840_port, old_termios); - - if (!mos7840_port->read_urb) { - dbg("%s", "URB KILLED !!!!!"); - return; - } - - if (mos7840_port->read_urb_busy == false) { - mos7840_port->read_urb_busy = true; - status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC); - if (status) { - dbg("usb_submit_urb(read bulk) failed, status = %d", - status); - mos7840_port->read_urb_busy = false; - } - } -} - -/***************************************************************************** - * mos7840_get_lsr_info - get line status register info - * - * Purpose: Let user call ioctl() to get info when the UART physically - * is emptied. On bus types like RS485, the transmitter must - * release the bus after transmitting. This must be done when - * the transmit shift register is empty, not be done when the - * transmit holding register is empty. This functionality - * allows an RS485 driver to be written in user space. - *****************************************************************************/ - -static int mos7840_get_lsr_info(struct tty_struct *tty, - unsigned int __user *value) -{ - int count; - unsigned int result = 0; - - count = mos7840_chars_in_buffer(tty); - if (count == 0) { - dbg("%s -- Empty", __func__); - result = TIOCSER_TEMT; - } - - if (copy_to_user(value, &result, sizeof(int))) - return -EFAULT; - return 0; -} - -/***************************************************************************** - * mos7840_get_serial_info - * function to get information about serial port - *****************************************************************************/ - -static int mos7840_get_serial_info(struct moschip_port *mos7840_port, - struct serial_struct __user *retinfo) -{ - struct serial_struct tmp; - - if (mos7840_port == NULL) - return -1; - - if (!retinfo) - return -EFAULT; - - memset(&tmp, 0, sizeof(tmp)); - - tmp.type = PORT_16550A; - tmp.line = mos7840_port->port->serial->minor; - tmp.port = mos7840_port->port->number; - tmp.irq = 0; - tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; - tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; - tmp.baud_base = 9600; - tmp.close_delay = 5 * HZ; - tmp.closing_wait = 30 * HZ; - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - return 0; -} - -static int mos7840_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct moschip_port *mos7840_port; - struct async_icount cnow; - - mos7840_port = mos7840_get_port_private(port); - cnow = mos7840_port->icount; - - smp_rmb(); - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - icount->rx = cnow.rx; - icount->tx = cnow.tx; - icount->frame = cnow.frame; - icount->overrun = cnow.overrun; - icount->parity = cnow.parity; - icount->brk = cnow.brk; - icount->buf_overrun = cnow.buf_overrun; - - dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __func__, - port->number, icount->rx, icount->tx); - return 0; -} - -/***************************************************************************** - * SerialIoctl - * this function handles any ioctl calls to the driver - *****************************************************************************/ - -static int mos7840_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - void __user *argp = (void __user *)arg; - struct moschip_port *mos7840_port; - - struct async_icount cnow; - struct async_icount cprev; - - if (mos7840_port_paranoia_check(port, __func__)) { - dbg("%s", "Invalid port"); - return -1; - } - - mos7840_port = mos7840_get_port_private(port); - - if (mos7840_port == NULL) - return -1; - - dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd); - - switch (cmd) { - /* return number of bytes available */ - - case TIOCSERGETLSR: - dbg("%s (%d) TIOCSERGETLSR", __func__, port->number); - return mos7840_get_lsr_info(tty, argp); - - case TIOCGSERIAL: - dbg("%s (%d) TIOCGSERIAL", __func__, port->number); - return mos7840_get_serial_info(mos7840_port, argp); - - case TIOCSSERIAL: - dbg("%s (%d) TIOCSSERIAL", __func__, port->number); - break; - - case TIOCMIWAIT: - dbg("%s (%d) TIOCMIWAIT", __func__, port->number); - cprev = mos7840_port->icount; - while (1) { - /* interruptible_sleep_on(&mos7840_port->delta_msr_wait); */ - mos7840_port->delta_msr_cond = 0; - wait_event_interruptible(mos7840_port->delta_msr_wait, - (mos7840_port-> - delta_msr_cond == 1)); - - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - cnow = mos7840_port->icount; - smp_rmb(); - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { - return 0; - } - cprev = cnow; - } - /* NOTREACHED */ - break; - - default: - break; - } - return -ENOIOCTLCMD; -} - -static int mos7840_calc_num_ports(struct usb_serial *serial) -{ - __u16 Data = 0x00; - int ret = 0; - int mos7840_num_ports; - - ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &Data, - VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); - - if ((Data & 0x01) == 0) { - mos7840_num_ports = 2; - serial->num_bulk_in = 2; - serial->num_bulk_out = 2; - serial->num_ports = 2; - } else { - mos7840_num_ports = 4; - serial->num_bulk_in = 4; - serial->num_bulk_out = 4; - serial->num_ports = 4; - } - - return mos7840_num_ports; -} - -/**************************************************************************** - * mos7840_startup - ****************************************************************************/ - -static int mos7840_startup(struct usb_serial *serial) -{ - struct moschip_port *mos7840_port; - struct usb_device *dev; - int i, status; - - __u16 Data; - dbg("%s", "mos7840_startup :Entering.........."); - - if (!serial) { - dbg("%s", "Invalid Handler"); - return -1; - } - - dev = serial->dev; - - dbg("%s", "Entering..."); - dbg ("mos7840_startup: serial = %p", serial); - - /* we set up the pointers to the endpoints in the mos7840_open * - * function, as the structures aren't created yet. */ - - /* set up port private structures */ - for (i = 0; i < serial->num_ports; ++i) { - dbg ("mos7840_startup: configuring port %d............", i); - mos7840_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL); - if (mos7840_port == NULL) { - dev_err(&dev->dev, "%s - Out of memory\n", __func__); - status = -ENOMEM; - i--; /* don't follow NULL pointer cleaning up */ - goto error; - } - - /* Initialize all port interrupt end point to port 0 int - * endpoint. Our device has only one interrupt end point - * common to all port */ - - mos7840_port->port = serial->port[i]; - mos7840_set_port_private(serial->port[i], mos7840_port); - spin_lock_init(&mos7840_port->pool_lock); - - /* minor is not initialised until later by - * usb-serial.c:get_free_serial() and cannot therefore be used - * to index device instances */ - mos7840_port->port_num = i + 1; - dbg ("serial->port[i]->number = %d", serial->port[i]->number); - dbg ("serial->port[i]->serial->minor = %d", serial->port[i]->serial->minor); - dbg ("mos7840_port->port_num = %d", mos7840_port->port_num); - dbg ("serial->minor = %d", serial->minor); - - if (mos7840_port->port_num == 1) { - mos7840_port->SpRegOffset = 0x0; - mos7840_port->ControlRegOffset = 0x1; - mos7840_port->DcrRegOffset = 0x4; - } else if ((mos7840_port->port_num == 2) - && (serial->num_ports == 4)) { - mos7840_port->SpRegOffset = 0x8; - mos7840_port->ControlRegOffset = 0x9; - mos7840_port->DcrRegOffset = 0x16; - } else if ((mos7840_port->port_num == 2) - && (serial->num_ports == 2)) { - mos7840_port->SpRegOffset = 0xa; - mos7840_port->ControlRegOffset = 0xb; - mos7840_port->DcrRegOffset = 0x19; - } else if ((mos7840_port->port_num == 3) - && (serial->num_ports == 4)) { - mos7840_port->SpRegOffset = 0xa; - mos7840_port->ControlRegOffset = 0xb; - mos7840_port->DcrRegOffset = 0x19; - } else if ((mos7840_port->port_num == 4) - && (serial->num_ports == 4)) { - mos7840_port->SpRegOffset = 0xc; - mos7840_port->ControlRegOffset = 0xd; - mos7840_port->DcrRegOffset = 0x1c; - } - mos7840_dump_serial_port(mos7840_port); - mos7840_set_port_private(serial->port[i], mos7840_port); - - /* enable rx_disable bit in control register */ - status = mos7840_get_reg_sync(serial->port[i], - mos7840_port->ControlRegOffset, &Data); - if (status < 0) { - dbg("Reading ControlReg failed status-0x%x", status); - break; - } else - dbg("ControlReg Reading success val is %x, status%d", - Data, status); - Data |= 0x08; /* setting driver done bit */ - Data |= 0x04; /* sp1_bit to have cts change reflect in - modem status reg */ - - /* Data |= 0x20; //rx_disable bit */ - status = mos7840_set_reg_sync(serial->port[i], - mos7840_port->ControlRegOffset, Data); - if (status < 0) { - dbg("Writing ControlReg failed(rx_disable) status-0x%x", status); - break; - } else - dbg("ControlReg Writing success(rx_disable) status%d", - status); - - /* Write default values in DCR (i.e 0x01 in DCR0, 0x05 in DCR2 - and 0x24 in DCR3 */ - Data = 0x01; - status = mos7840_set_reg_sync(serial->port[i], - (__u16) (mos7840_port->DcrRegOffset + 0), Data); - if (status < 0) { - dbg("Writing DCR0 failed status-0x%x", status); - break; - } else - dbg("DCR0 Writing success status%d", status); - - Data = 0x05; - status = mos7840_set_reg_sync(serial->port[i], - (__u16) (mos7840_port->DcrRegOffset + 1), Data); - if (status < 0) { - dbg("Writing DCR1 failed status-0x%x", status); - break; - } else - dbg("DCR1 Writing success status%d", status); - - Data = 0x24; - status = mos7840_set_reg_sync(serial->port[i], - (__u16) (mos7840_port->DcrRegOffset + 2), Data); - if (status < 0) { - dbg("Writing DCR2 failed status-0x%x", status); - break; - } else - dbg("DCR2 Writing success status%d", status); - - /* write values in clkstart0x0 and clkmulti 0x20 */ - Data = 0x0; - status = mos7840_set_reg_sync(serial->port[i], - CLK_START_VALUE_REGISTER, Data); - if (status < 0) { - dbg("Writing CLK_START_VALUE_REGISTER failed status-0x%x", status); - break; - } else - dbg("CLK_START_VALUE_REGISTER Writing success status%d", status); - - Data = 0x20; - status = mos7840_set_reg_sync(serial->port[i], - CLK_MULTI_REGISTER, Data); - if (status < 0) { - dbg("Writing CLK_MULTI_REGISTER failed status-0x%x", - status); - goto error; - } else - dbg("CLK_MULTI_REGISTER Writing success status%d", - status); - - /* write value 0x0 to scratchpad register */ - Data = 0x00; - status = mos7840_set_uart_reg(serial->port[i], - SCRATCH_PAD_REGISTER, Data); - if (status < 0) { - dbg("Writing SCRATCH_PAD_REGISTER failed status-0x%x", - status); - break; - } else - dbg("SCRATCH_PAD_REGISTER Writing success status%d", - status); - - /* Zero Length flag register */ - if ((mos7840_port->port_num != 1) - && (serial->num_ports == 2)) { - - Data = 0xff; - status = mos7840_set_reg_sync(serial->port[i], - (__u16) (ZLP_REG1 + - ((__u16)mos7840_port->port_num)), Data); - dbg("ZLIP offset %x", - (__u16) (ZLP_REG1 + - ((__u16) mos7840_port->port_num))); - if (status < 0) { - dbg("Writing ZLP_REG%d failed status-0x%x", - i + 2, status); - break; - } else - dbg("ZLP_REG%d Writing success status%d", - i + 2, status); - } else { - Data = 0xff; - status = mos7840_set_reg_sync(serial->port[i], - (__u16) (ZLP_REG1 + - ((__u16)mos7840_port->port_num) - 0x1), Data); - dbg("ZLIP offset %x", - (__u16) (ZLP_REG1 + - ((__u16) mos7840_port->port_num) - 0x1)); - if (status < 0) { - dbg("Writing ZLP_REG%d failed status-0x%x", - i + 1, status); - break; - } else - dbg("ZLP_REG%d Writing success status%d", - i + 1, status); - - } - mos7840_port->control_urb = usb_alloc_urb(0, GFP_KERNEL); - mos7840_port->ctrl_buf = kmalloc(16, GFP_KERNEL); - mos7840_port->dr = kmalloc(sizeof(struct usb_ctrlrequest), - GFP_KERNEL); - if (!mos7840_port->control_urb || !mos7840_port->ctrl_buf || - !mos7840_port->dr) { - status = -ENOMEM; - goto error; - } - } - dbg ("mos7840_startup: all ports configured..........."); - - /* Zero Length flag enable */ - Data = 0x0f; - status = mos7840_set_reg_sync(serial->port[0], ZLP_REG5, Data); - if (status < 0) { - dbg("Writing ZLP_REG5 failed status-0x%x", status); - goto error; - } else - dbg("ZLP_REG5 Writing success status%d", status); - - /* setting configuration feature to one */ - usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - (__u8) 0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5 * HZ); - return 0; -error: - for (/* nothing */; i >= 0; i--) { - mos7840_port = mos7840_get_port_private(serial->port[i]); - - kfree(mos7840_port->dr); - kfree(mos7840_port->ctrl_buf); - usb_free_urb(mos7840_port->control_urb); - kfree(mos7840_port); - serial->port[i] = NULL; - } - return status; -} - -/**************************************************************************** - * mos7840_disconnect - * This function is called whenever the device is removed from the usb bus. - ****************************************************************************/ - -static void mos7840_disconnect(struct usb_serial *serial) -{ - int i; - unsigned long flags; - struct moschip_port *mos7840_port; - dbg("%s", " disconnect :entering.........."); - - if (!serial) { - dbg("%s", "Invalid Handler"); - return; - } - - /* check for the ports to be closed,close the ports and disconnect */ - - /* free private structure allocated for serial port * - * stop reads and writes on all ports */ - - for (i = 0; i < serial->num_ports; ++i) { - mos7840_port = mos7840_get_port_private(serial->port[i]); - dbg ("mos7840_port %d = %p", i, mos7840_port); - if (mos7840_port) { - spin_lock_irqsave(&mos7840_port->pool_lock, flags); - mos7840_port->zombie = 1; - spin_unlock_irqrestore(&mos7840_port->pool_lock, flags); - usb_kill_urb(mos7840_port->control_urb); - } - } - - dbg("%s", "Thank u :: "); - -} - -/**************************************************************************** - * mos7840_release - * This function is called when the usb_serial structure is freed. - ****************************************************************************/ - -static void mos7840_release(struct usb_serial *serial) -{ - int i; - struct moschip_port *mos7840_port; - dbg("%s", " release :entering.........."); - - if (!serial) { - dbg("%s", "Invalid Handler"); - return; - } - - /* check for the ports to be closed,close the ports and disconnect */ - - /* free private structure allocated for serial port * - * stop reads and writes on all ports */ - - for (i = 0; i < serial->num_ports; ++i) { - mos7840_port = mos7840_get_port_private(serial->port[i]); - dbg("mos7840_port %d = %p", i, mos7840_port); - if (mos7840_port) { - kfree(mos7840_port->ctrl_buf); - kfree(mos7840_port->dr); - kfree(mos7840_port); - } - } - - dbg("%s", "Thank u :: "); - -} - -static struct usb_driver io_driver = { - .name = "mos7840", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = moschip_id_table_combined, -}; - -static struct usb_serial_driver moschip7840_4port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "mos7840", - }, - .description = DRIVER_DESC, - .id_table = moschip_port_id_table, - .num_ports = 4, - .open = mos7840_open, - .close = mos7840_close, - .write = mos7840_write, - .write_room = mos7840_write_room, - .chars_in_buffer = mos7840_chars_in_buffer, - .throttle = mos7840_throttle, - .unthrottle = mos7840_unthrottle, - .calc_num_ports = mos7840_calc_num_ports, -#ifdef MCSSerialProbe - .probe = mos7840_serial_probe, -#endif - .ioctl = mos7840_ioctl, - .set_termios = mos7840_set_termios, - .break_ctl = mos7840_break, - .tiocmget = mos7840_tiocmget, - .tiocmset = mos7840_tiocmset, - .get_icount = mos7840_get_icount, - .attach = mos7840_startup, - .disconnect = mos7840_disconnect, - .release = mos7840_release, - .read_bulk_callback = mos7840_bulk_in_callback, - .read_int_callback = mos7840_interrupt_callback, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &moschip7840_4port_device, NULL -}; - -module_usb_serial_driver(io_driver, serial_drivers); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/moto_modem.c b/ANDROID_3.4.5/drivers/usb/serial/moto_modem.c deleted file mode 100644 index 3ab6214b..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/moto_modem.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Motorola USB Phone driver - * - * Copyright (C) 2008 Greg Kroah-Hartman - * - * 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. - * - * {sigh} - * Motorola should be using the CDC ACM USB spec, but instead - * they try to just "do their own thing"... This driver should handle a - * few phones in which a basic "dumb serial connection" is needed to be - * able to get a connection through to them. - */ - -#include -#include -#include -#include -#include -#include - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(0x05c6, 0x3197) }, /* unknown Motorola phone */ - { USB_DEVICE(0x0c44, 0x0022) }, /* unknown Mororola phone */ - { USB_DEVICE(0x22b8, 0x2a64) }, /* Motorola KRZR K1m */ - { USB_DEVICE(0x22b8, 0x2c84) }, /* Motorola VE240 phone */ - { USB_DEVICE(0x22b8, 0x2c64) }, /* Motorola V950 phone */ - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver moto_driver = { - .name = "moto-modem", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - -static struct usb_serial_driver moto_device = { - .driver = { - .owner = THIS_MODULE, - .name = "moto-modem", - }, - .id_table = id_table, - .num_ports = 1, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &moto_device, NULL -}; - -module_usb_serial_driver(moto_driver, serial_drivers); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/navman.c b/ANDROID_3.4.5/drivers/usb/serial/navman.c deleted file mode 100644 index 29ab6eb5..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/navman.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Navman Serial USB driver - * - * Copyright (C) 2006 Greg Kroah-Hartman - * - * 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. - * - * TODO: - * Add termios method that uses copy_hw but also kills all echo - * flags as the navman is rx only so cannot echo. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static bool debug; - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(0x0a99, 0x0001) }, /* Talon Technology device */ - { USB_DEVICE(0x0df7, 0x0900) }, /* Mobile Action i-gotU */ - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver navman_driver = { - .name = "navman", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - -static void navman_read_int_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - unsigned char *data = urb->transfer_buffer; - struct tty_struct *tty; - int status = urb->status; - int result; - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); - return; - default: - dbg("%s - nonzero urb status received: %d", - __func__, status); - goto exit; - } - - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, data); - - tty = tty_port_tty_get(&port->port); - if (tty && urb->actual_length) { - tty_insert_flip_string(tty, data, urb->actual_length); - tty_flip_buffer_push(tty); - } - tty_kref_put(tty); - -exit: - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) - dev_err(&urb->dev->dev, - "%s - Error %d submitting interrupt urb\n", - __func__, result); -} - -static int navman_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - int result = 0; - - dbg("%s - port %d", __func__, port->number); - - if (port->interrupt_in_urb) { - dbg("%s - adding interrupt input for treo", __func__); - result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - if (result) - dev_err(&port->dev, - "%s - failed submitting interrupt urb, error %d\n", - __func__, result); - } - return result; -} - -static void navman_close(struct usb_serial_port *port) -{ - dbg("%s - port %d", __func__, port->number); - - usb_kill_urb(port->interrupt_in_urb); -} - -static int navman_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - dbg("%s - port %d", __func__, port->number); - - /* - * This device can't write any data, only read from the device - */ - return -EOPNOTSUPP; -} - -static struct usb_serial_driver navman_device = { - .driver = { - .owner = THIS_MODULE, - .name = "navman", - }, - .id_table = id_table, - .num_ports = 1, - .open = navman_open, - .close = navman_close, - .write = navman_write, - .read_int_callback = navman_read_int_callback, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &navman_device, NULL -}; - -module_usb_serial_driver(navman_driver, serial_drivers); - -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/omninet.c b/ANDROID_3.4.5/drivers/usb/serial/omninet.c deleted file mode 100644 index 88dc785b..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/omninet.c +++ /dev/null @@ -1,331 +0,0 @@ -/* - * USB ZyXEL omni.net LCD PLUS 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. - * - * See Documentation/usb/usb-serial.txt for more information on using this - * driver - * - * Please report both successes and troubles to the author at omninet@kroah.com - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static bool debug; - -/* - * Version Information - */ -#define DRIVER_VERSION "v1.1" -#define DRIVER_AUTHOR "Alessandro Zummo" -#define DRIVER_DESC "USB ZyXEL omni.net LCD PLUS Driver" - -#define ZYXEL_VENDOR_ID 0x0586 -#define ZYXEL_OMNINET_ID 0x1000 -/* This one seems to be a re-branded ZyXEL device */ -#define BT_IGNITIONPRO_ID 0x2000 - -/* function prototypes */ -static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port); -static void omninet_close(struct usb_serial_port *port); -static void omninet_read_bulk_callback(struct urb *urb); -static void omninet_write_bulk_callback(struct urb *urb); -static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count); -static int omninet_write_room(struct tty_struct *tty); -static void omninet_disconnect(struct usb_serial *serial); -static void omninet_release(struct usb_serial *serial); -static int omninet_attach(struct usb_serial *serial); - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNINET_ID) }, - { USB_DEVICE(ZYXEL_VENDOR_ID, BT_IGNITIONPRO_ID) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver omninet_driver = { - .name = "omninet", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - - -static struct usb_serial_driver zyxel_omninet_device = { - .driver = { - .owner = THIS_MODULE, - .name = "omninet", - }, - .description = "ZyXEL - omni.net lcd plus usb", - .id_table = id_table, - .num_ports = 1, - .attach = omninet_attach, - .open = omninet_open, - .close = omninet_close, - .write = omninet_write, - .write_room = omninet_write_room, - .read_bulk_callback = omninet_read_bulk_callback, - .write_bulk_callback = omninet_write_bulk_callback, - .disconnect = omninet_disconnect, - .release = omninet_release, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &zyxel_omninet_device, NULL -}; - - -/* The protocol. - * - * The omni.net always exchange 64 bytes of data with the host. The first - * four bytes are the control header, you can see it in the above structure. - * - * oh_seq is a sequence number. Don't know if/how it's used. - * oh_len is the length of the data bytes in the packet. - * oh_xxx Bit-mapped, related to handshaking and status info. - * I normally set it to 0x03 in trasmitted frames. - * 7: Active when the TA is in a CONNECTed state. - * 6: unknown - * 5: handshaking, unknown - * 4: handshaking, unknown - * 3: unknown, usually 0 - * 2: unknown, usually 0 - * 1: handshaking, unknown, usually set to 1 in trasmitted frames - * 0: handshaking, unknown, usually set to 1 in trasmitted frames - * oh_pad Probably a pad byte. - * - * After the header you will find data bytes if oh_len was greater than zero. - * - */ - -struct omninet_header { - __u8 oh_seq; - __u8 oh_len; - __u8 oh_xxx; - __u8 oh_pad; -}; - -struct omninet_data { - __u8 od_outseq; /* Sequence number for bulk_out URBs */ -}; - -static int omninet_attach(struct usb_serial *serial) -{ - struct omninet_data *od; - struct usb_serial_port *port = serial->port[0]; - - od = kmalloc(sizeof(struct omninet_data), GFP_KERNEL); - if (!od) { - dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", - __func__, sizeof(struct omninet_data)); - return -ENOMEM; - } - usb_set_serial_port_data(port, od); - return 0; -} - -static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - struct usb_serial_port *wport; - int result = 0; - - dbg("%s - port %d", __func__, port->number); - - wport = serial->port[1]; - tty_port_tty_set(&wport->port, tty); - - /* Start reading from the device */ - result = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (result) - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", - __func__, result); - return result; -} - -static void omninet_close(struct usb_serial_port *port) -{ - dbg("%s - port %d", __func__, port->number); - usb_kill_urb(port->read_urb); -} - - -#define OMNINET_DATAOFFSET 0x04 -#define OMNINET_HEADERLEN sizeof(struct omninet_header) -#define OMNINET_BULKOUTSIZE (64 - OMNINET_HEADERLEN) - -static void omninet_read_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - unsigned char *data = urb->transfer_buffer; - struct omninet_header *header = (struct omninet_header *) &data[0]; - int status = urb->status; - int result; - int i; - - dbg("%s - port %d", __func__, port->number); - - if (status) { - dbg("%s - nonzero read bulk status received: %d", - __func__, status); - return; - } - - if (debug && header->oh_xxx != 0x30) { - if (urb->actual_length) { - printk(KERN_DEBUG "%s: omninet_read %d: ", - __FILE__, header->oh_len); - for (i = 0; i < (header->oh_len + - OMNINET_HEADERLEN); i++) - printk("%.2x ", data[i]); - printk("\n"); - } - } - - if (urb->actual_length && header->oh_len) { - struct tty_struct *tty = tty_port_tty_get(&port->port); - tty_insert_flip_string(tty, data + OMNINET_DATAOFFSET, - header->oh_len); - tty_flip_buffer_push(tty); - tty_kref_put(tty); - } - - /* Continue trying to always read */ - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) - dev_err(&port->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, result); -} - -static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - struct usb_serial *serial = port->serial; - struct usb_serial_port *wport = serial->port[1]; - - struct omninet_data *od = usb_get_serial_port_data(port); - struct omninet_header *header = (struct omninet_header *) - wport->write_urb->transfer_buffer; - - int result; - - dbg("%s - port %d", __func__, port->number); - - if (count == 0) { - dbg("%s - write request of 0 bytes", __func__); - return 0; - } - - if (!test_and_clear_bit(0, &port->write_urbs_free)) { - dbg("%s - already writing", __func__); - return 0; - } - - count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count; - - memcpy(wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, - buf, count); - - usb_serial_debug_data(debug, &port->dev, __func__, count, - wport->write_urb->transfer_buffer); - - header->oh_seq = od->od_outseq++; - header->oh_len = count; - header->oh_xxx = 0x03; - header->oh_pad = 0x00; - - /* send the data out the bulk port, always 64 bytes */ - wport->write_urb->transfer_buffer_length = 64; - - result = usb_submit_urb(wport->write_urb, GFP_ATOMIC); - if (result) { - set_bit(0, &wport->write_urbs_free); - dev_err_console(port, - "%s - failed submitting write urb, error %d\n", - __func__, result); - } else - result = count; - - return result; -} - - -static int omninet_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; - struct usb_serial_port *wport = serial->port[1]; - - int room = 0; /* Default: no room */ - - if (test_bit(0, &wport->write_urbs_free)) - room = wport->bulk_out_size - OMNINET_HEADERLEN; - - dbg("%s - returns %d", __func__, room); - - return room; -} - -static void omninet_write_bulk_callback(struct urb *urb) -{ -/* struct omninet_header *header = (struct omninet_header *) - urb->transfer_buffer; */ - struct usb_serial_port *port = urb->context; - int status = urb->status; - - dbg("%s - port %0x", __func__, port->number); - - set_bit(0, &port->write_urbs_free); - if (status) { - dbg("%s - nonzero write bulk status received: %d", - __func__, status); - return; - } - - usb_serial_port_softint(port); -} - - -static void omninet_disconnect(struct usb_serial *serial) -{ - struct usb_serial_port *wport = serial->port[1]; - - dbg("%s", __func__); - - usb_kill_urb(wport->write_urb); -} - - -static void omninet_release(struct usb_serial *serial) -{ - struct usb_serial_port *port = serial->port[0]; - - dbg("%s", __func__); - - kfree(usb_get_serial_port_data(port)); -} - -module_usb_serial_driver(omninet_driver, serial_drivers); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/opticon.c b/ANDROID_3.4.5/drivers/usb/serial/opticon.c deleted file mode 100644 index 82cc9d20..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/opticon.c +++ /dev/null @@ -1,640 +0,0 @@ -/* - * Opticon USB barcode to serial driver - * - * Copyright (C) 2011 Martin Jansen - * Copyright (C) 2008 - 2009 Greg Kroah-Hartman - * Copyright (C) 2008 - 2009 Novell Inc. - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define CONTROL_RTS 0x02 -#define RESEND_CTS_STATE 0x03 - -/* max number of write urbs in flight */ -#define URB_UPPER_LIMIT 8 - -/* This driver works for the Opticon 1D barcode reader - * an examples of 1D barcode types are EAN, UPC, Code39, IATA etc.. */ -#define DRIVER_DESC "Opticon USB barcode to serial driver (1D)" - -static bool debug; - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(0x065a, 0x0009) }, - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -/* This structure holds all of the individual device information */ -struct opticon_private { - struct usb_device *udev; - struct usb_serial *serial; - struct usb_serial_port *port; - unsigned char *bulk_in_buffer; - struct urb *bulk_read_urb; - int buffer_size; - u8 bulk_address; - spinlock_t lock; /* protects the following flags */ - bool throttled; - bool actually_throttled; - bool rts; - bool cts; - int outstanding_urbs; -}; - - - -static void opticon_read_bulk_callback(struct urb *urb) -{ - struct opticon_private *priv = urb->context; - unsigned char *data = urb->transfer_buffer; - struct usb_serial_port *port = priv->port; - int status = urb->status; - struct tty_struct *tty; - int result; - int data_length; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); - return; - default: - dbg("%s - nonzero urb status received: %d", - __func__, status); - goto exit; - } - - usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, - data); - - if (urb->actual_length > 2) { - data_length = urb->actual_length - 2; - - /* - * Data from the device comes with a 2 byte header: - * - * <0x00><0x00>data... - * This is real data to be sent to the tty layer - * <0x00><0x01)level - * This is a CTS level change, the third byte is the CTS - * value (0 for low, 1 for high). - */ - if ((data[0] == 0x00) && (data[1] == 0x00)) { - /* real data, send it to the tty layer */ - tty = tty_port_tty_get(&port->port); - if (tty) { - tty_insert_flip_string(tty, data + 2, - data_length); - tty_flip_buffer_push(tty); - tty_kref_put(tty); - } - } else { - if ((data[0] == 0x00) && (data[1] == 0x01)) { - spin_lock_irqsave(&priv->lock, flags); - /* CTS status information package */ - if (data[2] == 0x00) - priv->cts = false; - else - priv->cts = true; - spin_unlock_irqrestore(&priv->lock, flags); - } else { - dev_dbg(&priv->udev->dev, - "Unknown data packet received from the device:" - " %2x %2x\n", - data[0], data[1]); - } - } - } else { - dev_dbg(&priv->udev->dev, - "Improper amount of data received from the device, " - "%d bytes", urb->actual_length); - } - -exit: - spin_lock(&priv->lock); - - /* Continue trying to always read if we should */ - if (!priv->throttled) { - usb_fill_bulk_urb(priv->bulk_read_urb, priv->udev, - usb_rcvbulkpipe(priv->udev, - priv->bulk_address), - priv->bulk_in_buffer, priv->buffer_size, - opticon_read_bulk_callback, priv); - result = usb_submit_urb(priv->bulk_read_urb, GFP_ATOMIC); - if (result) - dev_err(&port->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, result); - } else - priv->actually_throttled = true; - spin_unlock(&priv->lock); -} - -static int send_control_msg(struct usb_serial_port *port, u8 requesttype, - u8 val) -{ - struct usb_serial *serial = port->serial; - int retval; - u8 buffer[2]; - - buffer[0] = val; - /* Send the message to the vendor control endpoint - * of the connected device */ - retval = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - requesttype, - USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, - 0, 0, buffer, 1, 0); - - return retval; -} - -static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct opticon_private *priv = usb_get_serial_data(port->serial); - unsigned long flags; - int result = 0; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&priv->lock, flags); - priv->throttled = false; - priv->actually_throttled = false; - priv->port = port; - priv->rts = false; - spin_unlock_irqrestore(&priv->lock, flags); - - /* Clear RTS line */ - send_control_msg(port, CONTROL_RTS, 0); - - /* Setup the read URB and start reading from the device */ - usb_fill_bulk_urb(priv->bulk_read_urb, priv->udev, - usb_rcvbulkpipe(priv->udev, - priv->bulk_address), - priv->bulk_in_buffer, priv->buffer_size, - opticon_read_bulk_callback, priv); - - /* clear the halt status of the enpoint */ - usb_clear_halt(priv->udev, priv->bulk_read_urb->pipe); - - result = usb_submit_urb(priv->bulk_read_urb, GFP_KERNEL); - if (result) - dev_err(&port->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, result); - /* Request CTS line state, sometimes during opening the current - * CTS state can be missed. */ - send_control_msg(port, RESEND_CTS_STATE, 1); - return result; -} - -static void opticon_close(struct usb_serial_port *port) -{ - struct opticon_private *priv = usb_get_serial_data(port->serial); - - dbg("%s - port %d", __func__, port->number); - - /* shutdown our urbs */ - usb_kill_urb(priv->bulk_read_urb); -} - -static void opticon_write_control_callback(struct urb *urb) -{ - struct opticon_private *priv = urb->context; - int status = urb->status; - unsigned long flags; - - /* free up the transfer buffer, as usb_free_urb() does not do this */ - kfree(urb->transfer_buffer); - - /* setup packet may be set if we're using it for writing */ - kfree(urb->setup_packet); - - if (status) - dbg("%s - nonzero write bulk status received: %d", - __func__, status); - - spin_lock_irqsave(&priv->lock, flags); - --priv->outstanding_urbs; - spin_unlock_irqrestore(&priv->lock, flags); - - usb_serial_port_softint(priv->port); -} - -static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - struct opticon_private *priv = usb_get_serial_data(port->serial); - struct usb_serial *serial = port->serial; - struct urb *urb; - unsigned char *buffer; - unsigned long flags; - int status; - struct usb_ctrlrequest *dr; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&priv->lock, flags); - if (priv->outstanding_urbs > URB_UPPER_LIMIT) { - spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - write limit hit", __func__); - return 0; - } - priv->outstanding_urbs++; - spin_unlock_irqrestore(&priv->lock, flags); - - buffer = kmalloc(count, GFP_ATOMIC); - if (!buffer) { - dev_err(&port->dev, "out of memory\n"); - count = -ENOMEM; - - goto error_no_buffer; - } - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - dev_err(&port->dev, "no more free urbs\n"); - count = -ENOMEM; - goto error_no_urb; - } - - memcpy(buffer, buf, count); - - usb_serial_debug_data(debug, &port->dev, __func__, count, buffer); - - /* The conncected devices do not have a bulk write endpoint, - * to transmit data to de barcode device the control endpoint is used */ - dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO); - if (!dr) { - dev_err(&port->dev, "out of memory\n"); - count = -ENOMEM; - goto error; - } - - dr->bRequestType = USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT; - dr->bRequest = 0x01; - dr->wValue = 0; - dr->wIndex = 0; - dr->wLength = cpu_to_le16(count); - - usb_fill_control_urb(urb, serial->dev, - usb_sndctrlpipe(serial->dev, 0), - (unsigned char *)dr, buffer, count, - opticon_write_control_callback, priv); - - /* send it down the pipe */ - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) { - dev_err(&port->dev, - "%s - usb_submit_urb(write endpoint) failed status = %d\n", - __func__, status); - count = status; - goto error; - } - - /* we are done with this urb, so let the host driver - * really free it when it is finished with it */ - usb_free_urb(urb); - - return count; -error: - usb_free_urb(urb); -error_no_urb: - kfree(buffer); -error_no_buffer: - spin_lock_irqsave(&priv->lock, flags); - --priv->outstanding_urbs; - spin_unlock_irqrestore(&priv->lock, flags); - return count; -} - -static int opticon_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct opticon_private *priv = usb_get_serial_data(port->serial); - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - /* - * We really can take almost anything the user throws at us - * but let's pick a nice big number to tell the tty - * layer that we have lots of free space, unless we don't. - */ - spin_lock_irqsave(&priv->lock, flags); - if (priv->outstanding_urbs > URB_UPPER_LIMIT * 2 / 3) { - spin_unlock_irqrestore(&priv->lock, flags); - dbg("%s - write limit hit", __func__); - return 0; - } - spin_unlock_irqrestore(&priv->lock, flags); - - return 2048; -} - -static void opticon_throttle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct opticon_private *priv = usb_get_serial_data(port->serial); - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); - priv->throttled = true; - spin_unlock_irqrestore(&priv->lock, flags); -} - - -static void opticon_unthrottle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct opticon_private *priv = usb_get_serial_data(port->serial); - unsigned long flags; - int result, was_throttled; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&priv->lock, flags); - priv->throttled = false; - was_throttled = priv->actually_throttled; - priv->actually_throttled = false; - spin_unlock_irqrestore(&priv->lock, flags); - - if (was_throttled) { - result = usb_submit_urb(priv->bulk_read_urb, GFP_ATOMIC); - if (result) - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", - __func__, result); - } -} - -static int opticon_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct opticon_private *priv = usb_get_serial_data(port->serial); - unsigned long flags; - int result = 0; - - dbg("%s - port %d", __func__, port->number); - if (!usb_get_intfdata(port->serial->interface)) - return -ENODEV; - - spin_lock_irqsave(&priv->lock, flags); - if (priv->rts) - result |= TIOCM_RTS; - if (priv->cts) - result |= TIOCM_CTS; - spin_unlock_irqrestore(&priv->lock, flags); - - dbg("%s - %x", __func__, result); - return result; -} - -static int opticon_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct opticon_private *priv = usb_get_serial_data(port->serial); - unsigned long flags; - bool rts; - bool changed = false; - - if (!usb_get_intfdata(port->serial->interface)) - return -ENODEV; - /* We only support RTS so we only handle that */ - spin_lock_irqsave(&priv->lock, flags); - - rts = priv->rts; - if (set & TIOCM_RTS) - priv->rts = true; - if (clear & TIOCM_RTS) - priv->rts = false; - changed = rts ^ priv->rts; - spin_unlock_irqrestore(&priv->lock, flags); - - if (!changed) - return 0; - - /* Send the new RTS state to the connected device */ - return send_control_msg(port, CONTROL_RTS, !rts); -} - -static int get_serial_info(struct opticon_private *priv, - struct serial_struct __user *serial) -{ - struct serial_struct tmp; - - if (!serial) - return -EFAULT; - - memset(&tmp, 0x00, sizeof(tmp)); - - /* fake emulate a 16550 uart to make userspace code happy */ - tmp.type = PORT_16550A; - tmp.line = priv->serial->minor; - tmp.port = 0; - tmp.irq = 0; - tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; - tmp.xmit_fifo_size = 1024; - tmp.baud_base = 9600; - tmp.close_delay = 5*HZ; - tmp.closing_wait = 30*HZ; - - if (copy_to_user(serial, &tmp, sizeof(*serial))) - return -EFAULT; - return 0; -} - -static int opticon_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - struct opticon_private *priv = usb_get_serial_data(port->serial); - - dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd); - - switch (cmd) { - case TIOCGSERIAL: - return get_serial_info(priv, - (struct serial_struct __user *)arg); - } - - return -ENOIOCTLCMD; -} - -static int opticon_startup(struct usb_serial *serial) -{ - struct opticon_private *priv; - struct usb_host_interface *intf; - int i; - int retval = -ENOMEM; - bool bulk_in_found = false; - - /* create our private serial structure */ - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (priv == NULL) { - dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__); - return -ENOMEM; - } - spin_lock_init(&priv->lock); - priv->serial = serial; - priv->port = serial->port[0]; - priv->udev = serial->dev; - priv->outstanding_urbs = 0; /* Init the outstanding urbs */ - - /* find our bulk endpoint */ - intf = serial->interface->altsetting; - for (i = 0; i < intf->desc.bNumEndpoints; ++i) { - struct usb_endpoint_descriptor *endpoint; - - endpoint = &intf->endpoint[i].desc; - if (!usb_endpoint_is_bulk_in(endpoint)) - continue; - - priv->bulk_read_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!priv->bulk_read_urb) { - dev_err(&priv->udev->dev, "out of memory\n"); - goto error; - } - - priv->buffer_size = usb_endpoint_maxp(endpoint) * 2; - priv->bulk_in_buffer = kmalloc(priv->buffer_size, GFP_KERNEL); - if (!priv->bulk_in_buffer) { - dev_err(&priv->udev->dev, "out of memory\n"); - goto error; - } - - priv->bulk_address = endpoint->bEndpointAddress; - - bulk_in_found = true; - break; - } - - if (!bulk_in_found) { - dev_err(&priv->udev->dev, - "Error - the proper endpoints were not found!\n"); - goto error; - } - - usb_set_serial_data(serial, priv); - return 0; - -error: - usb_free_urb(priv->bulk_read_urb); - kfree(priv->bulk_in_buffer); - kfree(priv); - return retval; -} - -static void opticon_disconnect(struct usb_serial *serial) -{ - struct opticon_private *priv = usb_get_serial_data(serial); - - dbg("%s", __func__); - - usb_kill_urb(priv->bulk_read_urb); - usb_free_urb(priv->bulk_read_urb); -} - -static void opticon_release(struct usb_serial *serial) -{ - struct opticon_private *priv = usb_get_serial_data(serial); - - dbg("%s", __func__); - - kfree(priv->bulk_in_buffer); - kfree(priv); -} - -static int opticon_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct usb_serial *serial = usb_get_intfdata(intf); - struct opticon_private *priv = usb_get_serial_data(serial); - - usb_kill_urb(priv->bulk_read_urb); - return 0; -} - -static int opticon_resume(struct usb_interface *intf) -{ - struct usb_serial *serial = usb_get_intfdata(intf); - struct opticon_private *priv = usb_get_serial_data(serial); - struct usb_serial_port *port = serial->port[0]; - int result; - - mutex_lock(&port->port.mutex); - /* This is protected by the port mutex against close/open */ - if (test_bit(ASYNCB_INITIALIZED, &port->port.flags)) - result = usb_submit_urb(priv->bulk_read_urb, GFP_NOIO); - else - result = 0; - mutex_unlock(&port->port.mutex); - return result; -} - -static struct usb_driver opticon_driver = { - .name = "opticon", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .suspend = opticon_suspend, - .resume = opticon_resume, - .id_table = id_table, -}; - -static struct usb_serial_driver opticon_device = { - .driver = { - .owner = THIS_MODULE, - .name = "opticon", - }, - .id_table = id_table, - .num_ports = 1, - .attach = opticon_startup, - .open = opticon_open, - .close = opticon_close, - .write = opticon_write, - .write_room = opticon_write_room, - .disconnect = opticon_disconnect, - .release = opticon_release, - .throttle = opticon_throttle, - .unthrottle = opticon_unthrottle, - .ioctl = opticon_ioctl, - .tiocmget = opticon_tiocmget, - .tiocmset = opticon_tiocmset, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &opticon_device, NULL -}; - -module_usb_serial_driver(opticon_driver, serial_drivers); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/option.c b/ANDROID_3.4.5/drivers/usb/serial/option.c deleted file mode 100644 index 82d5ecf9..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/option.c +++ /dev/null @@ -1,1556 +0,0 @@ -/* - USB Driver for GSM modems - - Copyright (C) 2005 Matthias Urlichs - - This driver is free software; you can redistribute it and/or modify - it under the terms of Version 2 of the GNU General Public License as - published by the Free Software Foundation. - - Portions copied from the Keyspan driver by Hugh Blemings - - History: see the git log. - - Work sponsored by: Sigos GmbH, Germany - - This driver exists because the "normal" serial driver doesn't work too well - with GSM modems. Issues: - - data loss -- one single Receive URB is not nearly enough - - nonstandard flow (Option devices) control - - controlling the baud rate doesn't make sense - - This driver is named "option" because the most common device it's - used for is a PC-Card (with an internal OHCI-USB interface, behind - which the GSM interface sits), made by Option Inc. - - Some of the "one port" devices actually exhibit multiple USB instances - on the USB bus. This is not a bug, these ports are used for different - device features. -*/ - -#define DRIVER_VERSION "v0.7.2" -#define DRIVER_AUTHOR "Matthias Urlichs " -#define DRIVER_DESC "USB Driver for GSM modems" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "usb-wwan.h" - -/* Function prototypes */ -static int option_probe(struct usb_serial *serial, - const struct usb_device_id *id); -static void option_release(struct usb_serial *serial); -static int option_send_setup(struct usb_serial_port *port); -static void option_instat_callback(struct urb *urb); -/* VIA-Telecom CBP(Non-CDC version) IDs */ -#define VIATELECOM_VENDOR_ID 0x15EB -#define VIATELECOM_PRODUCT_ID 0x0001 -#define BORA9380_VENDOR_ID 0x16d8 -#define BORA9380_PRODUCT_ID 0x4000 - -/* Vendor and product IDs */ -#define OPTION_VENDOR_ID 0x0AF0 -#define OPTION_PRODUCT_COLT 0x5000 -#define OPTION_PRODUCT_RICOLA 0x6000 -#define OPTION_PRODUCT_RICOLA_LIGHT 0x6100 -#define OPTION_PRODUCT_RICOLA_QUAD 0x6200 -#define OPTION_PRODUCT_RICOLA_QUAD_LIGHT 0x6300 -#define OPTION_PRODUCT_RICOLA_NDIS 0x6050 -#define OPTION_PRODUCT_RICOLA_NDIS_LIGHT 0x6150 -#define OPTION_PRODUCT_RICOLA_NDIS_QUAD 0x6250 -#define OPTION_PRODUCT_RICOLA_NDIS_QUAD_LIGHT 0x6350 -#define OPTION_PRODUCT_COBRA 0x6500 -#define OPTION_PRODUCT_COBRA_BUS 0x6501 -#define OPTION_PRODUCT_VIPER 0x6600 -#define OPTION_PRODUCT_VIPER_BUS 0x6601 -#define OPTION_PRODUCT_GT_MAX_READY 0x6701 -#define OPTION_PRODUCT_FUJI_MODEM_LIGHT 0x6721 -#define OPTION_PRODUCT_FUJI_MODEM_GT 0x6741 -#define OPTION_PRODUCT_FUJI_MODEM_EX 0x6761 -#define OPTION_PRODUCT_KOI_MODEM 0x6800 -#define OPTION_PRODUCT_SCORPION_MODEM 0x6901 -#define OPTION_PRODUCT_ETNA_MODEM 0x7001 -#define OPTION_PRODUCT_ETNA_MODEM_LITE 0x7021 -#define OPTION_PRODUCT_ETNA_MODEM_GT 0x7041 -#define OPTION_PRODUCT_ETNA_MODEM_EX 0x7061 -#define OPTION_PRODUCT_ETNA_KOI_MODEM 0x7100 -#define OPTION_PRODUCT_GTM380_MODEM 0x7201 - -#define HUAWEI_VENDOR_ID 0x12D1 -#define HUAWEI_PRODUCT_E600 0x1001 -#define HUAWEI_PRODUCT_E220 0x1003 -#define HUAWEI_PRODUCT_E220BIS 0x1004 -#define HUAWEI_PRODUCT_E1401 0x1401 -#define HUAWEI_PRODUCT_E1402 0x1402 -#define HUAWEI_PRODUCT_E1403 0x1403 -#define HUAWEI_PRODUCT_E1404 0x1404 -#define HUAWEI_PRODUCT_E1405 0x1405 -#define HUAWEI_PRODUCT_E1406 0x1406 -#define HUAWEI_PRODUCT_E1407 0x1407 -#define HUAWEI_PRODUCT_E1408 0x1408 -#define HUAWEI_PRODUCT_E1409 0x1409 -#define HUAWEI_PRODUCT_E140A 0x140A -#define HUAWEI_PRODUCT_E140B 0x140B -#define HUAWEI_PRODUCT_E140C 0x140C -#define HUAWEI_PRODUCT_E140D 0x140D -#define HUAWEI_PRODUCT_E140E 0x140E -#define HUAWEI_PRODUCT_E140F 0x140F -#define HUAWEI_PRODUCT_E1410 0x1410 -#define HUAWEI_PRODUCT_E1411 0x1411 -#define HUAWEI_PRODUCT_E1412 0x1412 -#define HUAWEI_PRODUCT_E1413 0x1413 -#define HUAWEI_PRODUCT_E1414 0x1414 -#define HUAWEI_PRODUCT_E1415 0x1415 -#define HUAWEI_PRODUCT_E1416 0x1416 -#define HUAWEI_PRODUCT_E1417 0x1417 -#define HUAWEI_PRODUCT_E1418 0x1418 -#define HUAWEI_PRODUCT_E1419 0x1419 -#define HUAWEI_PRODUCT_E141A 0x141A -#define HUAWEI_PRODUCT_E141B 0x141B -#define HUAWEI_PRODUCT_E141C 0x141C -#define HUAWEI_PRODUCT_E141D 0x141D -#define HUAWEI_PRODUCT_E141E 0x141E -#define HUAWEI_PRODUCT_E141F 0x141F -#define HUAWEI_PRODUCT_E1420 0x1420 -#define HUAWEI_PRODUCT_E1421 0x1421 -#define HUAWEI_PRODUCT_E1422 0x1422 -#define HUAWEI_PRODUCT_E1423 0x1423 -#define HUAWEI_PRODUCT_E1424 0x1424 -#define HUAWEI_PRODUCT_E1425 0x1425 -#define HUAWEI_PRODUCT_E1426 0x1426 -#define HUAWEI_PRODUCT_E1427 0x1427 -#define HUAWEI_PRODUCT_E1428 0x1428 -#define HUAWEI_PRODUCT_E1429 0x1429 -#define HUAWEI_PRODUCT_E142A 0x142A -#define HUAWEI_PRODUCT_E142B 0x142B -#define HUAWEI_PRODUCT_E142C 0x142C -#define HUAWEI_PRODUCT_E142D 0x142D -#define HUAWEI_PRODUCT_E142E 0x142E -#define HUAWEI_PRODUCT_E142F 0x142F -#define HUAWEI_PRODUCT_E1430 0x1430 -#define HUAWEI_PRODUCT_E1431 0x1431 -#define HUAWEI_PRODUCT_E1432 0x1432 -#define HUAWEI_PRODUCT_E1433 0x1433 -#define HUAWEI_PRODUCT_E1434 0x1434 -#define HUAWEI_PRODUCT_E1435 0x1435 -#define HUAWEI_PRODUCT_E1436 0x1436 -#define HUAWEI_PRODUCT_E1437 0x1437 -#define HUAWEI_PRODUCT_E1438 0x1438 -#define HUAWEI_PRODUCT_E1439 0x1439 -#define HUAWEI_PRODUCT_E143A 0x143A -#define HUAWEI_PRODUCT_E143B 0x143B -#define HUAWEI_PRODUCT_E143C 0x143C -#define HUAWEI_PRODUCT_E143D 0x143D -#define HUAWEI_PRODUCT_E143E 0x143E -#define HUAWEI_PRODUCT_E143F 0x143F -#define HUAWEI_PRODUCT_K4505 0x1464 -#define HUAWEI_PRODUCT_K3765 0x1465 -#define HUAWEI_PRODUCT_E14AC 0x14AC -#define HUAWEI_PRODUCT_K3806 0x14AE -#define HUAWEI_PRODUCT_K4605 0x14C6 -#define HUAWEI_PRODUCT_K5005 0x14C8 -#define HUAWEI_PRODUCT_K3770 0x14C9 -#define HUAWEI_PRODUCT_K3771 0x14CA -#define HUAWEI_PRODUCT_K4510 0x14CB -#define HUAWEI_PRODUCT_K4511 0x14CC -#define HUAWEI_PRODUCT_ETS1220 0x1803 -#define HUAWEI_PRODUCT_E353 0x1506 -//aron add-------- -#define HUAWEI_PRODUCT_E153 0x1446 -#define HUAWEI_PRODUCT_E173 0x1C05 -//---------- -#define QUANTA_VENDOR_ID 0x0408 -#define QUANTA_PRODUCT_Q101 0xEA02 -#define QUANTA_PRODUCT_Q111 0xEA03 -#define QUANTA_PRODUCT_GLX 0xEA04 -#define QUANTA_PRODUCT_GKE 0xEA05 -#define QUANTA_PRODUCT_GLE 0xEA06 - -#define NOVATELWIRELESS_VENDOR_ID 0x1410 - -/* YISO PRODUCTS */ - -#define YISO_VENDOR_ID 0x0EAB -#define YISO_PRODUCT_U893 0xC893 - -/* - * NOVATEL WIRELESS PRODUCTS - * - * Note from Novatel Wireless: - * If your Novatel modem does not work on linux, don't - * change the option module, but check our website. If - * that does not help, contact ddeschepper@nvtl.com -*/ -/* MERLIN EVDO PRODUCTS */ -#define NOVATELWIRELESS_PRODUCT_V640 0x1100 -#define NOVATELWIRELESS_PRODUCT_V620 0x1110 -#define NOVATELWIRELESS_PRODUCT_V740 0x1120 -#define NOVATELWIRELESS_PRODUCT_V720 0x1130 - -/* MERLIN HSDPA/HSPA PRODUCTS */ -#define NOVATELWIRELESS_PRODUCT_U730 0x1400 -#define NOVATELWIRELESS_PRODUCT_U740 0x1410 -#define NOVATELWIRELESS_PRODUCT_U870 0x1420 -#define NOVATELWIRELESS_PRODUCT_XU870 0x1430 -#define NOVATELWIRELESS_PRODUCT_X950D 0x1450 - -/* EXPEDITE PRODUCTS */ -#define NOVATELWIRELESS_PRODUCT_EV620 0x2100 -#define NOVATELWIRELESS_PRODUCT_ES720 0x2110 -#define NOVATELWIRELESS_PRODUCT_E725 0x2120 -#define NOVATELWIRELESS_PRODUCT_ES620 0x2130 -#define NOVATELWIRELESS_PRODUCT_EU730 0x2400 -#define NOVATELWIRELESS_PRODUCT_EU740 0x2410 -#define NOVATELWIRELESS_PRODUCT_EU870D 0x2420 -/* OVATION PRODUCTS */ -#define NOVATELWIRELESS_PRODUCT_MC727 0x4100 -#define NOVATELWIRELESS_PRODUCT_MC950D 0x4400 -/* - * Note from Novatel Wireless: - * All PID in the 5xxx range are currently reserved for - * auto-install CDROMs, and should not be added to this - * module. - * - * #define NOVATELWIRELESS_PRODUCT_U727 0x5010 - * #define NOVATELWIRELESS_PRODUCT_MC727_NEW 0x5100 -*/ -#define NOVATELWIRELESS_PRODUCT_OVMC760 0x6002 -#define NOVATELWIRELESS_PRODUCT_MC780 0x6010 -#define NOVATELWIRELESS_PRODUCT_EVDO_FULLSPEED 0x6000 -#define NOVATELWIRELESS_PRODUCT_EVDO_HIGHSPEED 0x6001 -#define NOVATELWIRELESS_PRODUCT_HSPA_FULLSPEED 0x7000 -#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED 0x7001 -#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED3 0x7003 -#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED4 0x7004 -#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED5 0x7005 -#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED6 0x7006 -#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED7 0x7007 -#define NOVATELWIRELESS_PRODUCT_MC996D 0x7030 -#define NOVATELWIRELESS_PRODUCT_MF3470 0x7041 -#define NOVATELWIRELESS_PRODUCT_MC547 0x7042 -#define NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_FULLSPEED 0x8000 -#define NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_HIGHSPEED 0x8001 -#define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED 0x9000 -#define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED 0x9001 -#define NOVATELWIRELESS_PRODUCT_G1 0xA001 -#define NOVATELWIRELESS_PRODUCT_G1_M 0xA002 -#define NOVATELWIRELESS_PRODUCT_G2 0xA010 -#define NOVATELWIRELESS_PRODUCT_MC551 0xB001 - -/* AMOI PRODUCTS */ -#define AMOI_VENDOR_ID 0x1614 -#define AMOI_PRODUCT_H01 0x0800 -#define AMOI_PRODUCT_H01A 0x7002 -#define AMOI_PRODUCT_H02 0x0802 -#define AMOI_PRODUCT_SKYPEPHONE_S2 0x0407 - -#define DELL_VENDOR_ID 0x413C - -/* Dell modems */ -#define DELL_PRODUCT_5700_MINICARD 0x8114 -#define DELL_PRODUCT_5500_MINICARD 0x8115 -#define DELL_PRODUCT_5505_MINICARD 0x8116 -#define DELL_PRODUCT_5700_EXPRESSCARD 0x8117 -#define DELL_PRODUCT_5510_EXPRESSCARD 0x8118 - -#define DELL_PRODUCT_5700_MINICARD_SPRINT 0x8128 -#define DELL_PRODUCT_5700_MINICARD_TELUS 0x8129 - -#define DELL_PRODUCT_5720_MINICARD_VZW 0x8133 -#define DELL_PRODUCT_5720_MINICARD_SPRINT 0x8134 -#define DELL_PRODUCT_5720_MINICARD_TELUS 0x8135 -#define DELL_PRODUCT_5520_MINICARD_CINGULAR 0x8136 -#define DELL_PRODUCT_5520_MINICARD_GENERIC_L 0x8137 -#define DELL_PRODUCT_5520_MINICARD_GENERIC_I 0x8138 - -#define DELL_PRODUCT_5730_MINICARD_SPRINT 0x8180 -#define DELL_PRODUCT_5730_MINICARD_TELUS 0x8181 -#define DELL_PRODUCT_5730_MINICARD_VZW 0x8182 - -#define KYOCERA_VENDOR_ID 0x0c88 -#define KYOCERA_PRODUCT_KPC650 0x17da -#define KYOCERA_PRODUCT_KPC680 0x180a - -#define ANYDATA_VENDOR_ID 0x16d5 -#define ANYDATA_PRODUCT_ADU_620UW 0x6202 -#define ANYDATA_PRODUCT_ADU_E100A 0x6501 -#define ANYDATA_PRODUCT_ADU_500A 0x6502 - -#define AXESSTEL_VENDOR_ID 0x1726 -#define AXESSTEL_PRODUCT_MV110H 0x1000 - -#define BANDRICH_VENDOR_ID 0x1A8D -#define BANDRICH_PRODUCT_C100_1 0x1002 -#define BANDRICH_PRODUCT_C100_2 0x1003 -#define BANDRICH_PRODUCT_1004 0x1004 -#define BANDRICH_PRODUCT_1005 0x1005 -#define BANDRICH_PRODUCT_1006 0x1006 -#define BANDRICH_PRODUCT_1007 0x1007 -#define BANDRICH_PRODUCT_1008 0x1008 -#define BANDRICH_PRODUCT_1009 0x1009 -#define BANDRICH_PRODUCT_100A 0x100a - -#define BANDRICH_PRODUCT_100B 0x100b -#define BANDRICH_PRODUCT_100C 0x100c -#define BANDRICH_PRODUCT_100D 0x100d -#define BANDRICH_PRODUCT_100E 0x100e - -#define BANDRICH_PRODUCT_100F 0x100f -#define BANDRICH_PRODUCT_1010 0x1010 -#define BANDRICH_PRODUCT_1011 0x1011 -#define BANDRICH_PRODUCT_1012 0x1012 - -#define QUALCOMM_VENDOR_ID 0x05C6 - -#define CMOTECH_VENDOR_ID 0x16d8 -#define CMOTECH_PRODUCT_6008 0x6008 -#define CMOTECH_PRODUCT_6280 0x6280 - -#define TELIT_VENDOR_ID 0x1bc7 -#define TELIT_PRODUCT_UC864E 0x1003 -#define TELIT_PRODUCT_UC864G 0x1004 -#define TELIT_PRODUCT_CC864_DUAL 0x1005 -#define TELIT_PRODUCT_CC864_SINGLE 0x1006 -#define TELIT_PRODUCT_DE910_DUAL 0x1010 - -/* ZTE PRODUCTS */ -#define ZTE_VENDOR_ID 0x19d2 -#define ZTE_PRODUCT_MF622 0x0001 -#define ZTE_PRODUCT_MF628 0x0015 -#define ZTE_PRODUCT_MF626 0x0031 -#define ZTE_PRODUCT_CDMA_TECH 0xfffe -#define ZTE_PRODUCT_AC8710 0xfff1 -#define ZTE_PRODUCT_AC2726 0xfff5 -#define ZTE_PRODUCT_AC8710T 0xffff -#define ZTE_PRODUCT_MC2718 0xffe8 -#define ZTE_PRODUCT_AD3812 0xffeb -#define ZTE_PRODUCT_MC2716 0xffed - -#define BENQ_VENDOR_ID 0x04a5 -#define BENQ_PRODUCT_H10 0x4068 - -#define DLINK_VENDOR_ID 0x1186 -#define DLINK_PRODUCT_DWM_652 0x3e04 -#define DLINK_PRODUCT_DWM_652_U5 0xce16 -#define DLINK_PRODUCT_DWM_652_U5A 0xce1e - -#define QISDA_VENDOR_ID 0x1da5 -#define QISDA_PRODUCT_H21_4512 0x4512 -#define QISDA_PRODUCT_H21_4523 0x4523 -#define QISDA_PRODUCT_H20_4515 0x4515 -#define QISDA_PRODUCT_H20_4518 0x4518 -#define QISDA_PRODUCT_H20_4519 0x4519 - -/* TLAYTECH PRODUCTS */ -#define TLAYTECH_VENDOR_ID 0x20B9 -#define TLAYTECH_PRODUCT_TEU800 0x1682 - -/* TOSHIBA PRODUCTS */ -#define TOSHIBA_VENDOR_ID 0x0930 -#define TOSHIBA_PRODUCT_HSDPA_MINICARD 0x1302 -#define TOSHIBA_PRODUCT_G450 0x0d45 - -#define ALINK_VENDOR_ID 0x1e0e -#define ALINK_PRODUCT_PH300 0x9100 -#define ALINK_PRODUCT_3GU 0x9200 - -/* ALCATEL PRODUCTS */ -#define ALCATEL_VENDOR_ID 0x1bbb -#define ALCATEL_PRODUCT_X060S_X200 0x0000 - -#define PIRELLI_VENDOR_ID 0x1266 -#define PIRELLI_PRODUCT_C100_1 0x1002 -#define PIRELLI_PRODUCT_C100_2 0x1003 -#define PIRELLI_PRODUCT_1004 0x1004 -#define PIRELLI_PRODUCT_1005 0x1005 -#define PIRELLI_PRODUCT_1006 0x1006 -#define PIRELLI_PRODUCT_1007 0x1007 -#define PIRELLI_PRODUCT_1008 0x1008 -#define PIRELLI_PRODUCT_1009 0x1009 -#define PIRELLI_PRODUCT_100A 0x100a -#define PIRELLI_PRODUCT_100B 0x100b -#define PIRELLI_PRODUCT_100C 0x100c -#define PIRELLI_PRODUCT_100D 0x100d -#define PIRELLI_PRODUCT_100E 0x100e -#define PIRELLI_PRODUCT_100F 0x100f -#define PIRELLI_PRODUCT_1011 0x1011 -#define PIRELLI_PRODUCT_1012 0x1012 - -/* Airplus products */ -#define AIRPLUS_VENDOR_ID 0x1011 -#define AIRPLUS_PRODUCT_MCD650 0x3198 - -/* Longcheer/Longsung vendor ID; makes whitelabel devices that - * many other vendors like 4G Systems, Alcatel, ChinaBird, - * Mobidata, etc sell under their own brand names. - */ -#define LONGCHEER_VENDOR_ID 0x1c9e - -/* 4G Systems products */ -/* This is the 4G XS Stick W14 a.k.a. Mobilcom Debitel Surf-Stick * - * It seems to contain a Qualcomm QSC6240/6290 chipset */ -#define FOUR_G_SYSTEMS_PRODUCT_W14 0x9603 - -/* Zoom */ -#define ZOOM_PRODUCT_4597 0x9607 - -/* Haier products */ -#define HAIER_VENDOR_ID 0x201e -#define HAIER_PRODUCT_CE100 0x2009 - -/* Cinterion (formerly Siemens) products */ -#define SIEMENS_VENDOR_ID 0x0681 -#define CINTERION_VENDOR_ID 0x1e2d -#define CINTERION_PRODUCT_HC25_MDM 0x0047 -#define CINTERION_PRODUCT_HC25_MDMNET 0x0040 -#define CINTERION_PRODUCT_HC28_MDM 0x004C -#define CINTERION_PRODUCT_HC28_MDMNET 0x004A /* same for HC28J */ -#define CINTERION_PRODUCT_EU3_E 0x0051 -#define CINTERION_PRODUCT_EU3_P 0x0052 -#define CINTERION_PRODUCT_PH8 0x0053 - -/* Olivetti products */ -#define OLIVETTI_VENDOR_ID 0x0b3c -#define OLIVETTI_PRODUCT_OLICARD100 0xc000 - -/* Celot products */ -#define CELOT_VENDOR_ID 0x211f -#define CELOT_PRODUCT_CT680M 0x6801 - -/* ONDA Communication vendor id */ -#define ONDA_VENDOR_ID 0x1ee8 - -/* ONDA MT825UP HSDPA 14.2 modem */ -#define ONDA_MT825UP 0x000b - -/* Samsung products */ -#define SAMSUNG_VENDOR_ID 0x04e8 -#define SAMSUNG_PRODUCT_GT_B3730 0x6889 - -/* YUGA products www.yuga-info.com gavin.kx@qq.com */ -#define YUGA_VENDOR_ID 0x257A -#define YUGA_PRODUCT_CEM600 0x1601 -#define YUGA_PRODUCT_CEM610 0x1602 -#define YUGA_PRODUCT_CEM500 0x1603 -#define YUGA_PRODUCT_CEM510 0x1604 -#define YUGA_PRODUCT_CEM800 0x1605 -#define YUGA_PRODUCT_CEM900 0x1606 - -#define YUGA_PRODUCT_CEU818 0x1607 -#define YUGA_PRODUCT_CEU816 0x1608 -#define YUGA_PRODUCT_CEU828 0x1609 -#define YUGA_PRODUCT_CEU826 0x160A -#define YUGA_PRODUCT_CEU518 0x160B -#define YUGA_PRODUCT_CEU516 0x160C -#define YUGA_PRODUCT_CEU528 0x160D -#define YUGA_PRODUCT_CEU526 0x160F -#define YUGA_PRODUCT_CEU881 0x161F -#define YUGA_PRODUCT_CEU882 0x162F - -#define YUGA_PRODUCT_CWM600 0x2601 -#define YUGA_PRODUCT_CWM610 0x2602 -#define YUGA_PRODUCT_CWM500 0x2603 -#define YUGA_PRODUCT_CWM510 0x2604 -#define YUGA_PRODUCT_CWM800 0x2605 -#define YUGA_PRODUCT_CWM900 0x2606 - -#define YUGA_PRODUCT_CWU718 0x2607 -#define YUGA_PRODUCT_CWU716 0x2608 -#define YUGA_PRODUCT_CWU728 0x2609 -#define YUGA_PRODUCT_CWU726 0x260A -#define YUGA_PRODUCT_CWU518 0x260B -#define YUGA_PRODUCT_CWU516 0x260C -#define YUGA_PRODUCT_CWU528 0x260D -#define YUGA_PRODUCT_CWU581 0x260E -#define YUGA_PRODUCT_CWU526 0x260F -#define YUGA_PRODUCT_CWU582 0x261F -#define YUGA_PRODUCT_CWU583 0x262F - -#define YUGA_PRODUCT_CLM600 0x3601 -#define YUGA_PRODUCT_CLM610 0x3602 -#define YUGA_PRODUCT_CLM500 0x3603 -#define YUGA_PRODUCT_CLM510 0x3604 -#define YUGA_PRODUCT_CLM800 0x3605 -#define YUGA_PRODUCT_CLM900 0x3606 - -#define YUGA_PRODUCT_CLU718 0x3607 -#define YUGA_PRODUCT_CLU716 0x3608 -#define YUGA_PRODUCT_CLU728 0x3609 -#define YUGA_PRODUCT_CLU726 0x360A -#define YUGA_PRODUCT_CLU518 0x360B -#define YUGA_PRODUCT_CLU516 0x360C -#define YUGA_PRODUCT_CLU528 0x360D -#define YUGA_PRODUCT_CLU526 0x360F - -/* Viettel products */ -#define VIETTEL_VENDOR_ID 0x2262 -#define VIETTEL_PRODUCT_VT1000 0x0002 - -/* ZD Incorporated */ -#define ZD_VENDOR_ID 0x0685 -#define ZD_PRODUCT_7000 0x7000 - -/* LG products */ -#define LG_VENDOR_ID 0x1004 -#define LG_PRODUCT_L02C 0x618f - -/* MediaTek products */ -#define MEDIATEK_VENDOR_ID 0x0e8d -#define MEDIATEK_PRODUCT_DC_1COM 0x00a0 -#define MEDIATEK_PRODUCT_DC_4COM 0x00a5 -#define MEDIATEK_PRODUCT_DC_5COM 0x00a4 -#define MEDIATEK_PRODUCT_7208_1COM 0x7101 -#define MEDIATEK_PRODUCT_7208_2COM 0x7102 -#define MEDIATEK_PRODUCT_FP_1COM 0x0003 -#define MEDIATEK_PRODUCT_FP_2COM 0x0023 -#define MEDIATEK_PRODUCT_FPDC_1COM 0x0043 -#define MEDIATEK_PRODUCT_FPDC_2COM 0x0033 - -/* Cellient products */ -#define CELLIENT_VENDOR_ID 0x2692 -#define CELLIENT_PRODUCT_MEN200 0x9005 - -/* some devices interfaces need special handling due to a number of reasons */ -enum option_blacklist_reason { - OPTION_BLACKLIST_NONE = 0, - OPTION_BLACKLIST_SENDSETUP = 1, - OPTION_BLACKLIST_RESERVED_IF = 2 -}; - -#define MAX_BL_NUM 8 -struct option_blacklist_info { - /* bitfield of interface numbers for OPTION_BLACKLIST_SENDSETUP */ - const unsigned long sendsetup; - /* bitfield of interface numbers for OPTION_BLACKLIST_RESERVED_IF */ - const unsigned long reserved; -}; - -static const struct option_blacklist_info four_g_w14_blacklist = { - .sendsetup = BIT(0) | BIT(1), -}; - -static const struct option_blacklist_info alcatel_x200_blacklist = { - .sendsetup = BIT(0) | BIT(1), -}; - -static const struct option_blacklist_info zte_0037_blacklist = { - .sendsetup = BIT(0) | BIT(1), -}; - -static const struct option_blacklist_info zte_k3765_z_blacklist = { - .sendsetup = BIT(0) | BIT(1) | BIT(2), - .reserved = BIT(4), -}; - -static const struct option_blacklist_info zte_ad3812_z_blacklist = { - .sendsetup = BIT(0) | BIT(1) | BIT(2), -}; - -static const struct option_blacklist_info zte_mc2718_z_blacklist = { - .sendsetup = BIT(1) | BIT(2) | BIT(3) | BIT(4), -}; - -static const struct option_blacklist_info zte_mc2716_z_blacklist = { - .sendsetup = BIT(1) | BIT(2) | BIT(3), -}; - -static const struct option_blacklist_info huawei_cdc12_blacklist = { - .reserved = BIT(1) | BIT(2), -}; - -static const struct option_blacklist_info net_intf1_blacklist = { - .reserved = BIT(1), -}; - -static const struct option_blacklist_info net_intf2_blacklist = { - .reserved = BIT(2), -}; - -static const struct option_blacklist_info net_intf3_blacklist = { - .reserved = BIT(3), -}; - -static const struct option_blacklist_info net_intf4_blacklist = { - .reserved = BIT(4), -}; - -static const struct option_blacklist_info net_intf5_blacklist = { - .reserved = BIT(5), -}; - -static const struct option_blacklist_info zte_mf626_blacklist = { - .sendsetup = BIT(0) | BIT(1), - .reserved = BIT(4), -}; - -static const struct usb_device_id option_ids[] = { - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_LIGHT) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_QUAD) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_QUAD_LIGHT) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_LIGHT) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_QUAD) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_QUAD_LIGHT) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA_BUS) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_VIPER) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_VIPER_BUS) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GT_MAX_READY) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_LIGHT) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_GT) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_EX) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_KOI_MODEM) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_SCORPION_MODEM) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_LITE) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_GT) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_EX) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_MODEM) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GTM380_MODEM) }, - { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_Q101) }, - { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_Q111) }, - { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLX) }, - { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GKE) }, - { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLE) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220BIS, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1401, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1402, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1403, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1404, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1405, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1406, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1407, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1408, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1409, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140A, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140B, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140C, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140D, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140E, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140F, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1410, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1411, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1412, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1413, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1414, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1415, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1416, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1417, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1418, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1419, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141A, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141B, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141C, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141D, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141E, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141F, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1420, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1421, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1422, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1423, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1424, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1425, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1426, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1427, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1428, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1429, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142A, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142B, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142C, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142D, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142E, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142F, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1430, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1431, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1432, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1433, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1434, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1435, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1436, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1437, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1438, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1439, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143A, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143B, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143C, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143D, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143E, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143F, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ETS1220, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3806, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0x01, 0x31) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0x01, 0x32) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K5005, 0xff, 0x01, 0x31) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K5005, 0xff, 0x01, 0x32) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K5005, 0xff, 0x01, 0x33) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x31) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x32) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3771, 0xff, 0x02, 0x31) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3771, 0xff, 0x02, 0x32) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4510, 0xff, 0x01, 0x31) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4510, 0xff, 0x01, 0x32) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x31) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x32) }, - { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E153) }, //aaron add - { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173) },//aron add - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x01) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x02) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x03) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x10) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x12) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x13) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x01) }, /* E398 3G Modem */ - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x02) }, /* E398 3G PC UI Interface */ - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x03) }, /* E398 3G Application Interface */ - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V740) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V720) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U730) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U740) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U870) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_XU870) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_X950D) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EV620) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_ES720) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E725) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_ES620) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EU730) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EU740) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EU870D) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC950D) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC727) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_OVMC760) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC780) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_FULLSPEED) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_FULLSPEED) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_FULLSPEED) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_HIGHSPEED) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED3) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED4) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED5) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED6) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED7) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC996D) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MF3470) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC547) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_HIGHSPEED) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G1) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G1_M) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G2) }, - /* Novatel Ovation MC551 a.k.a. Verizon USB551L */ - { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC551, 0xff, 0xff, 0xff) }, - - { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01) }, - { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01A) }, - { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H02) }, - { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_SKYPEPHONE_S2) }, - - { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5700_MINICARD) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO Mini-Card == Novatel Expedite EV620 CDMA/EV-DO */ - { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5500_MINICARD) }, /* Dell Wireless 5500 Mobile Broadband HSDPA Mini-Card == Novatel Expedite EU740 HSDPA/3G */ - { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5505_MINICARD) }, /* Dell Wireless 5505 Mobile Broadband HSDPA Mini-Card == Novatel Expedite EU740 HSDPA/3G */ - { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5700_EXPRESSCARD) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO ExpressCard == Novatel Merlin XV620 CDMA/EV-DO */ - { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5510_EXPRESSCARD) }, /* Dell Wireless 5510 Mobile Broadband HSDPA ExpressCard == Novatel Merlin XU870 HSDPA/3G */ - { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5700_MINICARD_SPRINT) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO Mini-Card == Novatel Expedite E720 CDMA/EV-DO */ - { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5700_MINICARD_TELUS) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO Mini-Card == Novatel Expedite ET620 CDMA/EV-DO */ - { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5720_MINICARD_VZW) }, /* Dell Wireless 5720 == Novatel EV620 CDMA/EV-DO */ - { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5720_MINICARD_SPRINT) }, /* Dell Wireless 5720 == Novatel EV620 CDMA/EV-DO */ - { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5720_MINICARD_TELUS) }, /* Dell Wireless 5720 == Novatel EV620 CDMA/EV-DO */ - { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5520_MINICARD_CINGULAR) }, /* Dell Wireless HSDPA 5520 == Novatel Expedite EU860D */ - { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5520_MINICARD_GENERIC_L) }, /* Dell Wireless HSDPA 5520 */ - { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5520_MINICARD_GENERIC_I) }, /* Dell Wireless 5520 Voda I Mobile Broadband (3G HSDPA) Minicard */ - { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5730_MINICARD_SPRINT) }, /* Dell Wireless 5730 Mobile Broadband EVDO/HSPA Mini-Card */ - { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5730_MINICARD_TELUS) }, /* Dell Wireless 5730 Mobile Broadband EVDO/HSPA Mini-Card */ - { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5730_MINICARD_VZW) }, /* Dell Wireless 5730 Mobile Broadband EVDO/HSPA Mini-Card */ - { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, /* ADU-E100, ADU-310 */ - { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) }, - { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) }, - { USB_DEVICE(AXESSTEL_VENDOR_ID, AXESSTEL_PRODUCT_MV110H) }, - { USB_DEVICE(YISO_VENDOR_ID, YISO_PRODUCT_U893) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1004) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1005) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1006) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1007) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1008) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1009) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100A) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100B) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100C) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100D) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100E) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_100F) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1010) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1011) }, - { USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1012) }, - { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC650) }, - { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) }, - { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6000)}, /* ZTE AC8700 */ - { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */ - { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */ - { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6280) }, /* BP3-USB & BP3-EXT HSDPA */ - { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6008) }, - { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) }, - { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864G) }, - { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_DUAL) }, - { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) }, - { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */ - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0003, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0004, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0005, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0006, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0008, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0009, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000a, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000b, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000c, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000d, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000e, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000f, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0010, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0011, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0012, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0013, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0016, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0017, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0018, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0019, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0020, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0021, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0022, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0023, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0024, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0025, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0028, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0029, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0030, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626, 0xff, - 0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_mf626_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0032, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0033, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0034, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0037, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&zte_0037_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0038, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0039, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0040, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0042, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0043, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0044, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0048, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0049, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0050, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0051, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0052, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0054, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0055, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0056, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0057, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0058, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0061, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0062, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0063, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0064, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0065, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0066, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0067, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0069, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0076, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0077, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0078, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0079, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0082, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0083, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0086, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0087, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0088, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0089, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0090, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0091, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0092, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0093, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0094, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0095, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0096, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0097, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0104, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0105, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0106, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0108, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0113, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0117, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0118, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0121, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0122, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0123, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0124, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0125, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0126, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0128, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0142, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0143, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0144, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0145, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0148, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0151, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0153, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0155, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0156, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0157, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0158, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0159, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0161, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0162, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0164, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0165, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0167, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1057, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1058, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1059, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1060, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1061, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1062, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1063, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1064, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1065, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1066, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1067, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1068, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1069, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1070, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1071, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1072, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1073, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1074, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1075, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1076, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1077, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1078, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1079, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1080, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1081, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1082, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1083, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1084, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1085, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1086, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1087, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1088, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1089, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1090, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1091, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1092, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1093, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1094, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1095, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1096, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1097, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1098, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1099, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1100, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1101, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1102, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1103, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1104, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1105, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1106, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1107, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1108, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1109, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1110, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1111, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1112, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1113, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1114, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1115, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1116, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1117, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1118, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1119, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1120, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1121, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1122, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1123, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1124, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1125, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1126, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1127, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1128, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1129, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1130, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1131, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1132, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1133, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1134, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1135, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1136, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1137, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1138, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1139, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1140, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1141, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1142, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1143, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1144, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1145, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1146, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1147, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1148, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1149, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1150, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1151, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1152, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1153, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1154, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1155, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1156, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1157, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1158, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1159, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1160, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1161, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1162, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1163, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1164, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1165, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1166, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1167, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1168, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1169, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1170, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1244, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1245, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1246, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1247, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1248, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1249, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1250, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1251, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1252, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1253, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1254, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1255, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1256, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1257, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1258, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1259, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1260, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1261, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1262, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1263, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1264, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1265, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1266, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1267, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1268, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1269, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1270, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1271, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1272, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1273, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1274, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1275, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1276, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1277, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1278, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1279, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1280, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1281, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1282, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1283, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1284, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1285, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1286, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1287, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1288, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1289, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1290, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1291, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1292, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1293, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1294, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1295, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1296, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1297, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1298, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1299, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1300, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1402, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&net_intf2_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff, - 0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_k3765_z_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) }, - - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0014, 0xff, 0xff, 0xff) }, /* ZTE CDMA products */ - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0027, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0059, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0060, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0070, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0073, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0094, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0130, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0133, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0141, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2000, 0xff, 0xff, 0xff) }, //aron add. - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0152, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0168, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0170, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0176, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0178, 0xff, 0xff, 0xff) }, - - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710T, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2718, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&zte_mc2718_z_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AD3812, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&zte_ad3812_z_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2716, 0xff, 0xff, 0xff), - .driver_info = (kernel_ulong_t)&zte_mc2716_z_blacklist }, - { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) }, - { USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) }, - { USB_DEVICE(ALINK_VENDOR_ID, DLINK_PRODUCT_DWM_652_U5) }, /* Yes, ALINK_VENDOR_ID */ - { USB_DEVICE(ALINK_VENDOR_ID, DLINK_PRODUCT_DWM_652_U5A) }, - { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4512) }, - { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4523) }, - { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4515) }, - { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4518) }, - { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4519) }, - { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_G450) }, - { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_HSDPA_MINICARD ) }, /* Toshiba 3G HSDPA == Novatel Expedite EU870D MiniCard */ - { USB_DEVICE(ALINK_VENDOR_ID, 0x9000) }, - { USB_DEVICE(ALINK_VENDOR_ID, ALINK_PRODUCT_PH300) }, - { USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) }, - { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S_X200), - .driver_info = (kernel_ulong_t)&alcatel_x200_blacklist - }, - { USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) }, - { USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) }, - { USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14), - .driver_info = (kernel_ulong_t)&four_g_w14_blacklist - }, - { USB_DEVICE(LONGCHEER_VENDOR_ID, ZOOM_PRODUCT_4597) }, - { USB_DEVICE(HAIER_VENDOR_ID, HAIER_PRODUCT_CE100) }, - /* Pirelli */ - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_C100_1)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_C100_2)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1004)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1005)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1006)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1007)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1008)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1009)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100A)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100B) }, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100C) }, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100D) }, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100E) }, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_100F) }, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1011)}, - { USB_DEVICE(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_1012)}, - /* Cinterion */ - { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_E) }, - { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_P) }, - { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8) }, - { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, - { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) }, - { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDM) }, - { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDMNET) }, - { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, /* HC28 enumerates with Siemens or Cinterion VID depending on FW revision */ - { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) }, - - { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) }, - { USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */ - { USB_DEVICE(ONDA_VENDOR_ID, ONDA_MT825UP) }, /* ONDA MT825UP modem */ - { USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_GT_B3730, USB_CLASS_CDC_DATA, 0x00, 0x00) }, /* Samsung GT-B3730 LTE USB modem.*/ - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM600) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM610) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM500) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM510) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM800) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM900) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU818) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU816) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU828) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU826) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU518) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU516) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU528) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU526) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM600) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM610) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM500) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM510) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM800) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM900) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU718) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU716) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU728) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU726) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU518) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU516) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU528) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU526) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM600) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM610) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM500) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM510) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM800) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM900) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU718) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU716) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU728) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU726) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU518) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU516) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU528) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU526) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU881) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU882) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU581) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU582) }, - { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU583) }, - { USB_DEVICE_AND_INTERFACE_INFO(VIETTEL_VENDOR_ID, VIETTEL_PRODUCT_VT1000, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZD_VENDOR_ID, ZD_PRODUCT_7000, 0xff, 0xff, 0xff) }, - { USB_DEVICE(LG_VENDOR_ID, LG_PRODUCT_L02C) }, /* docomo L-02C modem */ - { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a1, 0xff, 0x00, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a1, 0xff, 0x02, 0x01) }, - { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x00, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x02, 0x01) }, /* MediaTek MT6276M modem & app port */ - { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_1COM, 0x0a, 0x00, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_5COM, 0xff, 0x02, 0x01) }, - { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_5COM, 0xff, 0x00, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM, 0xff, 0x02, 0x01) }, - { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_DC_4COM, 0xff, 0x00, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7208_1COM, 0x02, 0x00, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_7208_2COM, 0x02, 0x02, 0x01) }, - { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_1COM, 0x0a, 0x00, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FP_2COM, 0x0a, 0x00, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_1COM, 0x0a, 0x00, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, MEDIATEK_PRODUCT_FPDC_2COM, 0x0a, 0x00, 0x00) }, - { USB_DEVICE(CELLIENT_VENDOR_ID, CELLIENT_PRODUCT_MEN200) }, - { USB_DEVICE(VIATELECOM_VENDOR_ID, VIATELECOM_PRODUCT_ID) },/* VIA-Telecom CBP CDC Version*/ - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c05, 0xff, 0xff, 0xff) }, /*huawei E173*/ - { USB_DEVICE_AND_INTERFACE_INFO(0x05c6, 0x1000, 0xff, 0xff, 0xff) }, /*´´¾°SCV SEV759 */ - { USB_DEVICE_AND_INTERFACE_INFO(0x05c6, 0x6000, 0xff, 0xff, 0xff) }, /*´´¾°SCV SEV759 */ - { USB_DEVICE_AND_INTERFACE_INFO(0x20a6, 0xf00e, 0xff, 0xff, 0xff) }, /*´´¾°SCV SEW868 */ - { USB_DEVICE_AND_INTERFACE_INFO(0x20a6, 0x1105, 0xff, 0xff, 0xff) }, /*´´¾°SCV SEW868 */ - { USB_DEVICE(0x19f5, 0x9909) }, /*UW100 */ - { USB_DEVICE(0x19f5, 0x9013) }, /*UW100 */ - { USB_DEVICE_AND_INTERFACE_INFO(0x05c6, 0x0015, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1176, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff) }, - { USB_DEVICE(BORA9380_VENDOR_ID, BORA9380_PRODUCT_ID) },/* ²¨ÀÖ9380*/ - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x14a8, 0xff, 0xff, 0xff) }, - - { USB_DEVICE(0x1c9e, 0x9605) }, /*a dongle without brand */ - { USB_DEVICE(0x231e, 0x0036) }, /*CYIT TD/GSM modem*/ - { USB_DEVICE(ZTE_VENDOR_ID, 0x1176) }, /*vodafone k3770-z*/ - { USB_DEVICE(HUAWEI_VENDOR_ID, 0x1506) }, /*hw e1731*/ - { USB_DEVICE(HUAWEI_VENDOR_ID, 0x1573) }, /*hw mu609*/ - { USB_DEVICE(0x1782, 0x0002) }, /*spectrum G3 3g modem*/ - { USB_DEVICE(HUAWEI_VENDOR_ID, 0x1c25) }, /*hw mu709*/ - { USB_DEVICE(0x2001, 0x7d01) }, /*dlink dwm156*/ - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, option_ids); - -static struct usb_driver option_driver = { - .name = "option", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, -#ifdef CONFIG_PM - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .supports_autosuspend = 1, -#endif - .id_table = option_ids, -}; - -/* The card has three separate interfaces, which the serial driver - * recognizes separately, thus num_port=1. - */ - -static struct usb_serial_driver option_1port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "option1", - }, - .description = "GSM modem (1-port)", - .id_table = option_ids, - .num_ports = 1, - .probe = option_probe, - .open = usb_wwan_open, - .close = usb_wwan_close, - .dtr_rts = usb_wwan_dtr_rts, - .write = usb_wwan_write, - .write_room = usb_wwan_write_room, - .chars_in_buffer = usb_wwan_chars_in_buffer, - .set_termios = usb_wwan_set_termios, - .tiocmget = usb_wwan_tiocmget, - .tiocmset = usb_wwan_tiocmset, - .ioctl = usb_wwan_ioctl, - .attach = usb_wwan_startup, - .disconnect = usb_wwan_disconnect, - .release = option_release, - .read_int_callback = option_instat_callback, -#ifdef CONFIG_PM - .suspend = usb_wwan_suspend, - .resume = usb_wwan_resume, -#endif -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &option_1port_device, NULL -}; - -static bool debug; - -module_usb_serial_driver(option_driver, serial_drivers); - -static bool is_blacklisted(const u8 ifnum, enum option_blacklist_reason reason, - const struct option_blacklist_info *blacklist) -{ - unsigned long num; - const unsigned long *intf_list; - - if (blacklist) { - if (reason == OPTION_BLACKLIST_SENDSETUP) - intf_list = &blacklist->sendsetup; - else if (reason == OPTION_BLACKLIST_RESERVED_IF) - intf_list = &blacklist->reserved; - else { - BUG_ON(reason); - return false; - } - - for_each_set_bit(num, intf_list, MAX_BL_NUM + 1) { - if (num == ifnum) - return true; - } - } - return false; -} -static int viatelecom_send_setup(struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - struct usb_wwan_port_private *portdata = usb_get_serial_port_data(port); - int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber; - - /* VIA-Telecom CBP DTR format */ - return usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - 0x01, 0x40, portdata->dtr_state? 1: 0, ifNum, - NULL, 0, USB_CTRL_SET_TIMEOUT); - - -} - - -static int option_probe(struct usb_serial *serial, - const struct usb_device_id *id) -{ - struct usb_wwan_intf_private *data; - - /* D-Link DWM 652 still exposes CD-Rom emulation interface in modem mode */ - if (serial->dev->descriptor.idVendor == DLINK_VENDOR_ID && - serial->dev->descriptor.idProduct == DLINK_PRODUCT_DWM_652 && - serial->interface->cur_altsetting->desc.bInterfaceClass == 0x8) - return -ENODEV; - - /* Bandrich modem and AT command interface is 0xff */ - if ((serial->dev->descriptor.idVendor == BANDRICH_VENDOR_ID || - serial->dev->descriptor.idVendor == PIRELLI_VENDOR_ID) && - serial->interface->cur_altsetting->desc.bInterfaceClass != 0xff) - return -ENODEV; - - /* Don't bind reserved interfaces (like network ones) which often have - * the same class/subclass/protocol as the serial interfaces. Look at - * the Windows driver .INF files for reserved interface numbers. - */ - if (is_blacklisted( - serial->interface->cur_altsetting->desc.bInterfaceNumber, - OPTION_BLACKLIST_RESERVED_IF, - (const struct option_blacklist_info *) id->driver_info)) - return -ENODEV; - - /* Don't bind network interface on Samsung GT-B3730, it is handled by a separate module */ - if (serial->dev->descriptor.idVendor == SAMSUNG_VENDOR_ID && - serial->dev->descriptor.idProduct == SAMSUNG_PRODUCT_GT_B3730 && - serial->interface->cur_altsetting->desc.bInterfaceClass != USB_CLASS_CDC_DATA) - return -ENODEV; - - - if(serial->dev->descriptor.idVendor == HUAWEI_VENDOR_ID){ - if(0!=(serial->dev->config->desc.bmAttributes&0x20)){ - usb_enable_autosuspend(serial->dev); - } - } - - data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL); - if (!data) - return -ENOMEM; - - if ((serial->dev->descriptor.idVendor == BORA9380_VENDOR_ID && - serial->dev->descriptor.idProduct == BORA9380_PRODUCT_ID)) { - data->send_setup = viatelecom_send_setup; - } else - data->send_setup = option_send_setup; - spin_lock_init(&data->susp_lock); - data->private = (void *)id->driver_info; - return 0; -} - -static void option_release(struct usb_serial *serial) -{ - struct usb_wwan_intf_private *priv = usb_get_serial_data(serial); - - usb_wwan_release(serial); - - kfree(priv); -} - -static void option_instat_callback(struct urb *urb) -{ - int err; - int status = urb->status; - struct usb_serial_port *port = urb->context; - struct usb_wwan_port_private *portdata = - usb_get_serial_port_data(port); - - dbg("%s", __func__); - dbg("%s: urb %p port %p has data %p", __func__, urb, port, portdata); - - if (status == 0) { - struct usb_ctrlrequest *req_pkt = - (struct usb_ctrlrequest *)urb->transfer_buffer; - - if (!req_pkt) { - dbg("%s: NULL req_pkt", __func__); - return; - } - if ((req_pkt->bRequestType == 0xA1) && - (req_pkt->bRequest == 0x20)) { - int old_dcd_state; - unsigned char signals = *((unsigned char *) - urb->transfer_buffer + - sizeof(struct usb_ctrlrequest)); - - dbg("%s: signal x%x", __func__, signals); - - old_dcd_state = portdata->dcd_state; - portdata->cts_state = 1; - portdata->dcd_state = ((signals & 0x01) ? 1 : 0); - portdata->dsr_state = ((signals & 0x02) ? 1 : 0); - portdata->ri_state = ((signals & 0x08) ? 1 : 0); - - if (old_dcd_state && !portdata->dcd_state) { - struct tty_struct *tty = - tty_port_tty_get(&port->port); - if (tty && !C_CLOCAL(tty)) - tty_hangup(tty); - tty_kref_put(tty); - } - } else { - dbg("%s: type %x req %x", __func__, - req_pkt->bRequestType, req_pkt->bRequest); - } - } else - err("%s: error %d", __func__, status); - - /* Resubmit urb so we continue receiving IRQ data */ - if (status != -ESHUTDOWN && status != -ENOENT) { - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) - dbg("%s: resubmit intr urb failed. (%d)", - __func__, err); - } -} - -/** send RTS/DTR state to the port. - * - * This is exactly the same as SET_CONTROL_LINE_STATE from the PSTN - * CDC. -*/ -static int option_send_setup(struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - struct usb_wwan_intf_private *intfdata = - (struct usb_wwan_intf_private *) serial->private; - struct usb_wwan_port_private *portdata; - int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber; - int val = 0; - dbg("%s", __func__); - - if (is_blacklisted(ifNum, OPTION_BLACKLIST_SENDSETUP, - (struct option_blacklist_info *) intfdata->private)) { - dbg("No send_setup on blacklisted interface #%d\n", ifNum); - return -EIO; - } - - portdata = usb_get_serial_port_data(port); - - if (portdata->dtr_state) - val |= 0x01; - if (portdata->rts_state) - val |= 0x02; - - return usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), - 0x22, 0x21, val, ifNum, NULL, 0, USB_CTRL_SET_TIMEOUT); -} - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug messages"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/oti6858.c b/ANDROID_3.4.5/drivers/usb/serial/oti6858.c deleted file mode 100644 index 5fdc33c6..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/oti6858.c +++ /dev/null @@ -1,970 +0,0 @@ -/* - * Ours Technology Inc. OTi-6858 USB to serial adapter driver. - * - * Copyleft (C) 2007 Kees Lemmens (adapted for kernel 2.6.20) - * Copyright (C) 2006 Tomasz Michal Lukaszewski (FIXME: add e-mail) - * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2003 IBM Corp. - * - * Many thanks to the authors of pl2303 driver: all functions in this file - * are heavily based on pl2303 code, buffering code is a 1-to-1 copy. - * - * Warning! You use this driver on your own risk! The only official - * description of this device I have is datasheet from manufacturer, - * and it doesn't contain almost any information needed to write a driver. - * Almost all knowlegde used while writing this driver was gathered by: - * - analyzing traffic between device and the M$ Windows 2000 driver, - * - trying different bit combinations and checking pin states - * with a voltmeter, - * - receiving malformed frames and producing buffer overflows - * to learn how errors are reported, - * So, THIS CODE CAN DESTROY OTi-6858 AND ANY OTHER DEVICES, THAT ARE - * CONNECTED TO IT! - * - * 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. - * - * See Documentation/usb/usb-serial.txt for more information on using this - * driver - * - * TODO: - * - implement correct flushing for ioctls and oti6858_close() - * - check how errors (rx overflow, parity error, framing error) are reported - * - implement oti6858_break_ctl() - * - implement more ioctls - * - test/implement flow control - * - allow setting custom baud rates - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "oti6858.h" - -#define OTI6858_DESCRIPTION \ - "Ours Technology Inc. OTi-6858 USB to serial adapter driver" -#define OTI6858_AUTHOR "Tomasz Michal Lukaszewski " -#define OTI6858_VERSION "0.2" - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(OTI6858_VENDOR_ID, OTI6858_PRODUCT_ID) }, - { } -}; - -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver oti6858_driver = { - .name = "oti6858", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - -static bool debug; - -/* requests */ -#define OTI6858_REQ_GET_STATUS (USB_DIR_IN | USB_TYPE_VENDOR | 0x00) -#define OTI6858_REQ_T_GET_STATUS 0x01 - -#define OTI6858_REQ_SET_LINE (USB_DIR_OUT | USB_TYPE_VENDOR | 0x00) -#define OTI6858_REQ_T_SET_LINE 0x00 - -#define OTI6858_REQ_CHECK_TXBUFF (USB_DIR_IN | USB_TYPE_VENDOR | 0x01) -#define OTI6858_REQ_T_CHECK_TXBUFF 0x00 - -/* format of the control packet */ -struct oti6858_control_pkt { - __le16 divisor; /* baud rate = 96000000 / (16 * divisor), LE */ -#define OTI6858_MAX_BAUD_RATE 3000000 - u8 frame_fmt; -#define FMT_STOP_BITS_MASK 0xc0 -#define FMT_STOP_BITS_1 0x00 -#define FMT_STOP_BITS_2 0x40 /* 1.5 stop bits if FMT_DATA_BITS_5 */ -#define FMT_PARITY_MASK 0x38 -#define FMT_PARITY_NONE 0x00 -#define FMT_PARITY_ODD 0x08 -#define FMT_PARITY_EVEN 0x18 -#define FMT_PARITY_MARK 0x28 -#define FMT_PARITY_SPACE 0x38 -#define FMT_DATA_BITS_MASK 0x03 -#define FMT_DATA_BITS_5 0x00 -#define FMT_DATA_BITS_6 0x01 -#define FMT_DATA_BITS_7 0x02 -#define FMT_DATA_BITS_8 0x03 - u8 something; /* always equals 0x43 */ - u8 control; /* settings of flow control lines */ -#define CONTROL_MASK 0x0c -#define CONTROL_DTR_HIGH 0x08 -#define CONTROL_RTS_HIGH 0x04 - u8 tx_status; -#define TX_BUFFER_EMPTIED 0x09 - u8 pin_state; -#define PIN_MASK 0x3f -#define PIN_RTS 0x20 /* output pin */ -#define PIN_CTS 0x10 /* input pin, active low */ -#define PIN_DSR 0x08 /* input pin, active low */ -#define PIN_DTR 0x04 /* output pin */ -#define PIN_RI 0x02 /* input pin, active low */ -#define PIN_DCD 0x01 /* input pin, active low */ - u8 rx_bytes_avail; /* number of bytes in rx buffer */; -}; - -#define OTI6858_CTRL_PKT_SIZE sizeof(struct oti6858_control_pkt) -#define OTI6858_CTRL_EQUALS_PENDING(a, priv) \ - (((a)->divisor == (priv)->pending_setup.divisor) \ - && ((a)->control == (priv)->pending_setup.control) \ - && ((a)->frame_fmt == (priv)->pending_setup.frame_fmt)) - -/* function prototypes */ -static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port); -static void oti6858_close(struct usb_serial_port *port); -static void oti6858_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old); -static void oti6858_init_termios(struct tty_struct *tty); -static int oti6858_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); -static void oti6858_read_int_callback(struct urb *urb); -static void oti6858_read_bulk_callback(struct urb *urb); -static void oti6858_write_bulk_callback(struct urb *urb); -static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count); -static int oti6858_write_room(struct tty_struct *tty); -static int oti6858_chars_in_buffer(struct tty_struct *tty); -static int oti6858_tiocmget(struct tty_struct *tty); -static int oti6858_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear); -static int oti6858_startup(struct usb_serial *serial); -static void oti6858_release(struct usb_serial *serial); - -/* device info */ -static struct usb_serial_driver oti6858_device = { - .driver = { - .owner = THIS_MODULE, - .name = "oti6858", - }, - .id_table = id_table, - .num_ports = 1, - .open = oti6858_open, - .close = oti6858_close, - .write = oti6858_write, - .ioctl = oti6858_ioctl, - .set_termios = oti6858_set_termios, - .init_termios = oti6858_init_termios, - .tiocmget = oti6858_tiocmget, - .tiocmset = oti6858_tiocmset, - .read_bulk_callback = oti6858_read_bulk_callback, - .read_int_callback = oti6858_read_int_callback, - .write_bulk_callback = oti6858_write_bulk_callback, - .write_room = oti6858_write_room, - .chars_in_buffer = oti6858_chars_in_buffer, - .attach = oti6858_startup, - .release = oti6858_release, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &oti6858_device, NULL -}; - -struct oti6858_private { - spinlock_t lock; - - struct oti6858_control_pkt status; - - struct { - u8 read_urb_in_use; - u8 write_urb_in_use; - } flags; - struct delayed_work delayed_write_work; - - struct { - __le16 divisor; - u8 frame_fmt; - u8 control; - } pending_setup; - u8 transient; - u8 setup_done; - struct delayed_work delayed_setup_work; - - wait_queue_head_t intr_wait; - struct usb_serial_port *port; /* USB port with which associated */ -}; - -static void setup_line(struct work_struct *work) -{ - struct oti6858_private *priv = container_of(work, - struct oti6858_private, delayed_setup_work.work); - struct usb_serial_port *port = priv->port; - struct oti6858_control_pkt *new_setup; - unsigned long flags; - int result; - - dbg("%s(port = %d)", __func__, port->number); - - new_setup = kmalloc(OTI6858_CTRL_PKT_SIZE, GFP_KERNEL); - if (new_setup == NULL) { - dev_err(&port->dev, "%s(): out of memory!\n", __func__); - /* we will try again */ - schedule_delayed_work(&priv->delayed_setup_work, - msecs_to_jiffies(2)); - return; - } - - result = usb_control_msg(port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0), - OTI6858_REQ_T_GET_STATUS, - OTI6858_REQ_GET_STATUS, - 0, 0, - new_setup, OTI6858_CTRL_PKT_SIZE, - 100); - - if (result != OTI6858_CTRL_PKT_SIZE) { - dev_err(&port->dev, "%s(): error reading status\n", __func__); - kfree(new_setup); - /* we will try again */ - schedule_delayed_work(&priv->delayed_setup_work, - msecs_to_jiffies(2)); - return; - } - - spin_lock_irqsave(&priv->lock, flags); - if (!OTI6858_CTRL_EQUALS_PENDING(new_setup, priv)) { - new_setup->divisor = priv->pending_setup.divisor; - new_setup->control = priv->pending_setup.control; - new_setup->frame_fmt = priv->pending_setup.frame_fmt; - - spin_unlock_irqrestore(&priv->lock, flags); - result = usb_control_msg(port->serial->dev, - usb_sndctrlpipe(port->serial->dev, 0), - OTI6858_REQ_T_SET_LINE, - OTI6858_REQ_SET_LINE, - 0, 0, - new_setup, OTI6858_CTRL_PKT_SIZE, - 100); - } else { - spin_unlock_irqrestore(&priv->lock, flags); - result = 0; - } - kfree(new_setup); - - spin_lock_irqsave(&priv->lock, flags); - if (result != OTI6858_CTRL_PKT_SIZE) - priv->transient = 0; - priv->setup_done = 1; - spin_unlock_irqrestore(&priv->lock, flags); - - dbg("%s(): submitting interrupt urb", __func__); - result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - if (result != 0) { - dev_err(&port->dev, "%s(): usb_submit_urb() failed" - " with error %d\n", __func__, result); - } -} - -static void send_data(struct work_struct *work) -{ - struct oti6858_private *priv = container_of(work, - struct oti6858_private, delayed_write_work.work); - struct usb_serial_port *port = priv->port; - int count = 0, result; - unsigned long flags; - u8 *allow; - - dbg("%s(port = %d)", __func__, port->number); - - spin_lock_irqsave(&priv->lock, flags); - if (priv->flags.write_urb_in_use) { - spin_unlock_irqrestore(&priv->lock, flags); - schedule_delayed_work(&priv->delayed_write_work, - msecs_to_jiffies(2)); - return; - } - priv->flags.write_urb_in_use = 1; - spin_unlock_irqrestore(&priv->lock, flags); - - spin_lock_irqsave(&port->lock, flags); - count = kfifo_len(&port->write_fifo); - spin_unlock_irqrestore(&port->lock, flags); - - if (count > port->bulk_out_size) - count = port->bulk_out_size; - - if (count != 0) { - allow = kmalloc(1, GFP_KERNEL); - if (!allow) { - dev_err_console(port, "%s(): kmalloc failed\n", - __func__); - return; - } - result = usb_control_msg(port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0), - OTI6858_REQ_T_CHECK_TXBUFF, - OTI6858_REQ_CHECK_TXBUFF, - count, 0, allow, 1, 100); - if (result != 1 || *allow != 0) - count = 0; - kfree(allow); - } - - if (count == 0) { - priv->flags.write_urb_in_use = 0; - - dbg("%s(): submitting interrupt urb", __func__); - result = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO); - if (result != 0) { - dev_err(&port->dev, "%s(): usb_submit_urb() failed" - " with error %d\n", __func__, result); - } - return; - } - - count = kfifo_out_locked(&port->write_fifo, - port->write_urb->transfer_buffer, - count, &port->lock); - port->write_urb->transfer_buffer_length = count; - result = usb_submit_urb(port->write_urb, GFP_NOIO); - if (result != 0) { - dev_err_console(port, "%s(): usb_submit_urb() failed" - " with error %d\n", __func__, result); - priv->flags.write_urb_in_use = 0; - } - - usb_serial_port_softint(port); -} - -static int oti6858_startup(struct usb_serial *serial) -{ - struct usb_serial_port *port = serial->port[0]; - struct oti6858_private *priv; - int i; - - for (i = 0; i < serial->num_ports; ++i) { - priv = kzalloc(sizeof(struct oti6858_private), GFP_KERNEL); - if (!priv) - break; - - spin_lock_init(&priv->lock); - init_waitqueue_head(&priv->intr_wait); -/* INIT_WORK(&priv->setup_work, setup_line, serial->port[i]); */ -/* INIT_WORK(&priv->write_work, send_data, serial->port[i]); */ - priv->port = port; - INIT_DELAYED_WORK(&priv->delayed_setup_work, setup_line); - INIT_DELAYED_WORK(&priv->delayed_write_work, send_data); - - usb_set_serial_port_data(serial->port[i], priv); - } - if (i == serial->num_ports) - return 0; - - for (--i; i >= 0; --i) { - priv = usb_get_serial_port_data(serial->port[i]); - kfree(priv); - usb_set_serial_port_data(serial->port[i], NULL); - } - return -ENOMEM; -} - -static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - dbg("%s(port = %d, count = %d)", __func__, port->number, count); - - if (!count) - return count; - - count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock); - - return count; -} - -static int oti6858_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - int room = 0; - unsigned long flags; - - dbg("%s(port = %d)", __func__, port->number); - - spin_lock_irqsave(&port->lock, flags); - room = kfifo_avail(&port->write_fifo); - spin_unlock_irqrestore(&port->lock, flags); - - return room; -} - -static int oti6858_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - int chars = 0; - unsigned long flags; - - dbg("%s(port = %d)", __func__, port->number); - - spin_lock_irqsave(&port->lock, flags); - chars = kfifo_len(&port->write_fifo); - spin_unlock_irqrestore(&port->lock, flags); - - return chars; -} - -static void oti6858_init_termios(struct tty_struct *tty) -{ - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL; - tty->termios->c_ispeed = 38400; - tty->termios->c_ospeed = 38400; -} - -static void oti6858_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) -{ - struct oti6858_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - unsigned int cflag; - u8 frame_fmt, control; - __le16 divisor; - int br; - - dbg("%s(port = %d)", __func__, port->number); - - if (!tty) { - dbg("%s(): no tty structures", __func__); - return; - } - - cflag = tty->termios->c_cflag; - - spin_lock_irqsave(&priv->lock, flags); - divisor = priv->pending_setup.divisor; - frame_fmt = priv->pending_setup.frame_fmt; - control = priv->pending_setup.control; - spin_unlock_irqrestore(&priv->lock, flags); - - frame_fmt &= ~FMT_DATA_BITS_MASK; - switch (cflag & CSIZE) { - case CS5: - frame_fmt |= FMT_DATA_BITS_5; - break; - case CS6: - frame_fmt |= FMT_DATA_BITS_6; - break; - case CS7: - frame_fmt |= FMT_DATA_BITS_7; - break; - default: - case CS8: - frame_fmt |= FMT_DATA_BITS_8; - break; - } - - /* manufacturer claims that this device can work with baud rates - * up to 3 Mbps; I've tested it only on 115200 bps, so I can't - * guarantee that any other baud rate will work (especially - * the higher ones) - */ - br = tty_get_baud_rate(tty); - if (br == 0) { - divisor = 0; - } else { - int real_br; - int new_divisor; - br = min(br, OTI6858_MAX_BAUD_RATE); - - new_divisor = (96000000 + 8 * br) / (16 * br); - real_br = 96000000 / (16 * new_divisor); - divisor = cpu_to_le16(new_divisor); - tty_encode_baud_rate(tty, real_br, real_br); - } - - frame_fmt &= ~FMT_STOP_BITS_MASK; - if ((cflag & CSTOPB) != 0) - frame_fmt |= FMT_STOP_BITS_2; - else - frame_fmt |= FMT_STOP_BITS_1; - - frame_fmt &= ~FMT_PARITY_MASK; - if ((cflag & PARENB) != 0) { - if ((cflag & PARODD) != 0) - frame_fmt |= FMT_PARITY_ODD; - else - frame_fmt |= FMT_PARITY_EVEN; - } else { - frame_fmt |= FMT_PARITY_NONE; - } - - control &= ~CONTROL_MASK; - if ((cflag & CRTSCTS) != 0) - control |= (CONTROL_DTR_HIGH | CONTROL_RTS_HIGH); - - /* change control lines if we are switching to or from B0 */ - /* FIXME: - spin_lock_irqsave(&priv->lock, flags); - control = priv->line_control; - if ((cflag & CBAUD) == B0) - priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); - else - priv->line_control |= (CONTROL_DTR | CONTROL_RTS); - if (control != priv->line_control) { - control = priv->line_control; - spin_unlock_irqrestore(&priv->lock, flags); - set_control_lines(serial->dev, control); - } else { - spin_unlock_irqrestore(&priv->lock, flags); - } - */ - - spin_lock_irqsave(&priv->lock, flags); - if (divisor != priv->pending_setup.divisor - || control != priv->pending_setup.control - || frame_fmt != priv->pending_setup.frame_fmt) { - priv->pending_setup.divisor = divisor; - priv->pending_setup.control = control; - priv->pending_setup.frame_fmt = frame_fmt; - } - spin_unlock_irqrestore(&priv->lock, flags); -} - -static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct oti6858_private *priv = usb_get_serial_port_data(port); - struct ktermios tmp_termios; - struct usb_serial *serial = port->serial; - struct oti6858_control_pkt *buf; - unsigned long flags; - int result; - - dbg("%s(port = %d)", __func__, port->number); - - usb_clear_halt(serial->dev, port->write_urb->pipe); - usb_clear_halt(serial->dev, port->read_urb->pipe); - - buf = kmalloc(OTI6858_CTRL_PKT_SIZE, GFP_KERNEL); - if (buf == NULL) { - dev_err(&port->dev, "%s(): out of memory!\n", __func__); - return -ENOMEM; - } - - result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - OTI6858_REQ_T_GET_STATUS, - OTI6858_REQ_GET_STATUS, - 0, 0, - buf, OTI6858_CTRL_PKT_SIZE, - 100); - if (result != OTI6858_CTRL_PKT_SIZE) { - /* assume default (after power-on reset) values */ - buf->divisor = cpu_to_le16(0x009c); /* 38400 bps */ - buf->frame_fmt = 0x03; /* 8N1 */ - buf->something = 0x43; - buf->control = 0x4c; /* DTR, RTS */ - buf->tx_status = 0x00; - buf->pin_state = 0x5b; /* RTS, CTS, DSR, DTR, RI, DCD */ - buf->rx_bytes_avail = 0x00; - } - - spin_lock_irqsave(&priv->lock, flags); - memcpy(&priv->status, buf, OTI6858_CTRL_PKT_SIZE); - priv->pending_setup.divisor = buf->divisor; - priv->pending_setup.frame_fmt = buf->frame_fmt; - priv->pending_setup.control = buf->control; - spin_unlock_irqrestore(&priv->lock, flags); - kfree(buf); - - dbg("%s(): submitting interrupt urb", __func__); - result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - if (result != 0) { - dev_err(&port->dev, "%s(): usb_submit_urb() failed" - " with error %d\n", __func__, result); - oti6858_close(port); - return result; - } - - /* setup termios */ - if (tty) - oti6858_set_termios(tty, port, &tmp_termios); - port->port.drain_delay = 256; /* FIXME: check the FIFO length */ - return 0; -} - -static void oti6858_close(struct usb_serial_port *port) -{ - struct oti6858_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - - dbg("%s(port = %d)", __func__, port->number); - - spin_lock_irqsave(&port->lock, flags); - /* clear out any remaining data in the buffer */ - kfifo_reset_out(&port->write_fifo); - spin_unlock_irqrestore(&port->lock, flags); - - dbg("%s(): after buf_clear()", __func__); - - /* cancel scheduled setup */ - cancel_delayed_work_sync(&priv->delayed_setup_work); - cancel_delayed_work_sync(&priv->delayed_write_work); - - /* shutdown our urbs */ - dbg("%s(): shutting down urbs", __func__); - usb_kill_urb(port->write_urb); - usb_kill_urb(port->read_urb); - usb_kill_urb(port->interrupt_in_urb); -} - -static int oti6858_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct oti6858_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - u8 control; - - dbg("%s(port = %d, set = 0x%08x, clear = 0x%08x)", - __func__, port->number, set, clear); - - if (!usb_get_intfdata(port->serial->interface)) - return -ENODEV; - - /* FIXME: check if this is correct (active high/low) */ - spin_lock_irqsave(&priv->lock, flags); - control = priv->pending_setup.control; - if ((set & TIOCM_RTS) != 0) - control |= CONTROL_RTS_HIGH; - if ((set & TIOCM_DTR) != 0) - control |= CONTROL_DTR_HIGH; - if ((clear & TIOCM_RTS) != 0) - control &= ~CONTROL_RTS_HIGH; - if ((clear & TIOCM_DTR) != 0) - control &= ~CONTROL_DTR_HIGH; - - if (control != priv->pending_setup.control) - priv->pending_setup.control = control; - - spin_unlock_irqrestore(&priv->lock, flags); - return 0; -} - -static int oti6858_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct oti6858_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - unsigned pin_state; - unsigned result = 0; - - dbg("%s(port = %d)", __func__, port->number); - - if (!usb_get_intfdata(port->serial->interface)) - return -ENODEV; - - spin_lock_irqsave(&priv->lock, flags); - pin_state = priv->status.pin_state & PIN_MASK; - spin_unlock_irqrestore(&priv->lock, flags); - - /* FIXME: check if this is correct (active high/low) */ - if ((pin_state & PIN_RTS) != 0) - result |= TIOCM_RTS; - if ((pin_state & PIN_CTS) != 0) - result |= TIOCM_CTS; - if ((pin_state & PIN_DSR) != 0) - result |= TIOCM_DSR; - if ((pin_state & PIN_DTR) != 0) - result |= TIOCM_DTR; - if ((pin_state & PIN_RI) != 0) - result |= TIOCM_RI; - if ((pin_state & PIN_DCD) != 0) - result |= TIOCM_CD; - - dbg("%s() = 0x%08x", __func__, result); - - return result; -} - -static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) -{ - struct oti6858_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - unsigned int prev, status; - unsigned int changed; - - spin_lock_irqsave(&priv->lock, flags); - prev = priv->status.pin_state; - spin_unlock_irqrestore(&priv->lock, flags); - - while (1) { - wait_event_interruptible(priv->intr_wait, - priv->status.pin_state != prev); - if (signal_pending(current)) - return -ERESTARTSYS; - - spin_lock_irqsave(&priv->lock, flags); - status = priv->status.pin_state & PIN_MASK; - spin_unlock_irqrestore(&priv->lock, flags); - - changed = prev ^ status; - /* FIXME: check if this is correct (active high/low) */ - if (((arg & TIOCM_RNG) && (changed & PIN_RI)) || - ((arg & TIOCM_DSR) && (changed & PIN_DSR)) || - ((arg & TIOCM_CD) && (changed & PIN_DCD)) || - ((arg & TIOCM_CTS) && (changed & PIN_CTS))) - return 0; - prev = status; - } - - /* NOTREACHED */ - return 0; -} - -static int oti6858_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - - dbg("%s(port = %d, cmd = 0x%04x, arg = 0x%08lx)", - __func__, port->number, cmd, arg); - - switch (cmd) { - case TIOCMIWAIT: - dbg("%s(): TIOCMIWAIT", __func__); - return wait_modem_info(port, arg); - default: - dbg("%s(): 0x%04x not supported", __func__, cmd); - break; - } - return -ENOIOCTLCMD; -} - - -static void oti6858_release(struct usb_serial *serial) -{ - int i; - - dbg("%s()", __func__); - - for (i = 0; i < serial->num_ports; ++i) - kfree(usb_get_serial_port_data(serial->port[i])); -} - -static void oti6858_read_int_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct oti6858_private *priv = usb_get_serial_port_data(port); - int transient = 0, can_recv = 0, resubmit = 1; - int status = urb->status; - - dbg("%s(port = %d, status = %d)", - __func__, port->number, status); - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s(): urb shutting down with status: %d", - __func__, status); - return; - default: - dbg("%s(): nonzero urb status received: %d", - __func__, status); - break; - } - - if (status == 0 && urb->actual_length == OTI6858_CTRL_PKT_SIZE) { - struct oti6858_control_pkt *xs = urb->transfer_buffer; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - - if (!priv->transient) { - if (!OTI6858_CTRL_EQUALS_PENDING(xs, priv)) { - if (xs->rx_bytes_avail == 0) { - priv->transient = 4; - priv->setup_done = 0; - resubmit = 0; - dbg("%s(): scheduling setup_line()", - __func__); - schedule_delayed_work(&priv->delayed_setup_work, 0); - } - } - } else { - if (OTI6858_CTRL_EQUALS_PENDING(xs, priv)) { - priv->transient = 0; - } else if (!priv->setup_done) { - resubmit = 0; - } else if (--priv->transient == 0) { - if (xs->rx_bytes_avail == 0) { - priv->transient = 4; - priv->setup_done = 0; - resubmit = 0; - dbg("%s(): scheduling setup_line()", - __func__); - schedule_delayed_work(&priv->delayed_setup_work, 0); - } - } - } - - if (!priv->transient) { - if (xs->pin_state != priv->status.pin_state) - wake_up_interruptible(&priv->intr_wait); - memcpy(&priv->status, xs, OTI6858_CTRL_PKT_SIZE); - } - - if (!priv->transient && xs->rx_bytes_avail != 0) { - can_recv = xs->rx_bytes_avail; - priv->flags.read_urb_in_use = 1; - } - - transient = priv->transient; - spin_unlock_irqrestore(&priv->lock, flags); - } - - if (can_recv) { - int result; - - result = usb_submit_urb(port->read_urb, GFP_ATOMIC); - if (result != 0) { - priv->flags.read_urb_in_use = 0; - dev_err(&port->dev, "%s(): usb_submit_urb() failed," - " error %d\n", __func__, result); - } else { - resubmit = 0; - } - } else if (!transient) { - unsigned long flags; - int count; - - spin_lock_irqsave(&port->lock, flags); - count = kfifo_len(&port->write_fifo); - spin_unlock_irqrestore(&port->lock, flags); - - spin_lock_irqsave(&priv->lock, flags); - if (priv->flags.write_urb_in_use == 0 && count != 0) { - schedule_delayed_work(&priv->delayed_write_work, 0); - resubmit = 0; - } - spin_unlock_irqrestore(&priv->lock, flags); - } - - if (resubmit) { - int result; - -/* dbg("%s(): submitting interrupt urb", __func__); */ - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result != 0) { - dev_err(&urb->dev->dev, - "%s(): usb_submit_urb() failed with" - " error %d\n", __func__, result); - } - } -} - -static void oti6858_read_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct oti6858_private *priv = usb_get_serial_port_data(port); - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - unsigned long flags; - int status = urb->status; - int result; - - dbg("%s(port = %d, status = %d)", - __func__, port->number, status); - - spin_lock_irqsave(&priv->lock, flags); - priv->flags.read_urb_in_use = 0; - spin_unlock_irqrestore(&priv->lock, flags); - - if (status != 0) { - dbg("%s(): unable to handle the error, exiting", __func__); - return; - } - - tty = tty_port_tty_get(&port->port); - if (tty != NULL && urb->actual_length > 0) { - tty_insert_flip_string(tty, data, urb->actual_length); - tty_flip_buffer_push(tty); - } - tty_kref_put(tty); - - /* schedule the interrupt urb */ - result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); - if (result != 0 && result != -EPERM) { - dev_err(&port->dev, "%s(): usb_submit_urb() failed," - " error %d\n", __func__, result); - } -} - -static void oti6858_write_bulk_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct oti6858_private *priv = usb_get_serial_port_data(port); - int status = urb->status; - int result; - - dbg("%s(port = %d, status = %d)", - __func__, port->number, status); - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s(): urb shutting down with status: %d", - __func__, status); - priv->flags.write_urb_in_use = 0; - return; - default: - /* error in the urb, so we have to resubmit it */ - dbg("%s(): nonzero write bulk status received: %d", - __func__, status); - dbg("%s(): overflow in write", __func__); - - port->write_urb->transfer_buffer_length = 1; - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (result) { - dev_err_console(port, "%s(): usb_submit_urb() failed," - " error %d\n", __func__, result); - } else { - return; - } - } - - priv->flags.write_urb_in_use = 0; - - /* schedule the interrupt urb if we are still open */ - dbg("%s(): submitting interrupt urb", __func__); - result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); - if (result != 0) { - dev_err(&port->dev, "%s(): failed submitting int urb," - " error %d\n", __func__, result); - } -} - -module_usb_serial_driver(oti6858_driver, serial_drivers); - -MODULE_DESCRIPTION(OTI6858_DESCRIPTION); -MODULE_AUTHOR(OTI6858_AUTHOR); -MODULE_VERSION(OTI6858_VERSION); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "enable debug output"); - diff --git a/ANDROID_3.4.5/drivers/usb/serial/oti6858.h b/ANDROID_3.4.5/drivers/usb/serial/oti6858.h deleted file mode 100644 index 704ac3a5..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/oti6858.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Ours Technology Inc. OTi-6858 USB to serial adapter driver. - * - * 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. - */ -#ifndef __LINUX_USB_SERIAL_OTI6858_H -#define __LINUX_USB_SERIAL_OTI6858_H - -#define OTI6858_VENDOR_ID 0x0ea0 -#define OTI6858_PRODUCT_ID 0x6858 - -#endif diff --git a/ANDROID_3.4.5/drivers/usb/serial/pl2303.c b/ANDROID_3.4.5/drivers/usb/serial/pl2303.c deleted file mode 100644 index a1a90629..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/pl2303.c +++ /dev/null @@ -1,865 +0,0 @@ -/* - * Prolific PL2303 USB to serial adaptor driver - * - * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2003 IBM Corp. - * - * Original driver for 2.2.x by anonymous - * - * 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. - * - * See Documentation/usb/usb-serial.txt for more information on using this - * driver - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "pl2303.h" - -/* - * Version Information - */ -#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver" - -static bool debug; - -#define PL2303_CLOSING_WAIT (30*HZ) - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) }, - { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) }, - { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) }, - { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) }, - { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) }, - { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) }, - { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) }, - { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) }, - { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) }, - { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) }, - { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, - { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) }, - { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) }, - { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) }, - { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) }, - { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) }, - { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) }, - { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) }, - { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) }, - { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) }, - { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) }, - { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) }, - { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) }, - { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) }, - { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) }, - { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) }, - { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) }, - { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) }, - { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) }, - { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) }, - { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */ - { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) }, - { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) }, - { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) }, - { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) }, - { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) }, - { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) }, - { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) }, - { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) }, - { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) }, - { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) }, - { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) }, - { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) }, - { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) }, - { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) }, - { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) }, - { USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) }, - { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) }, - { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) }, - { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) }, - { USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver pl2303_driver = { - .name = "pl2303", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .supports_autosuspend = 1, -}; - -#define SET_LINE_REQUEST_TYPE 0x21 -#define SET_LINE_REQUEST 0x20 - -#define SET_CONTROL_REQUEST_TYPE 0x21 -#define SET_CONTROL_REQUEST 0x22 -#define CONTROL_DTR 0x01 -#define CONTROL_RTS 0x02 - -#define BREAK_REQUEST_TYPE 0x21 -#define BREAK_REQUEST 0x23 -#define BREAK_ON 0xffff -#define BREAK_OFF 0x0000 - -#define GET_LINE_REQUEST_TYPE 0xa1 -#define GET_LINE_REQUEST 0x21 - -#define VENDOR_WRITE_REQUEST_TYPE 0x40 -#define VENDOR_WRITE_REQUEST 0x01 - -#define VENDOR_READ_REQUEST_TYPE 0xc0 -#define VENDOR_READ_REQUEST 0x01 - -#define UART_STATE 0x08 -#define UART_STATE_TRANSIENT_MASK 0x74 -#define UART_DCD 0x01 -#define UART_DSR 0x02 -#define UART_BREAK_ERROR 0x04 -#define UART_RING 0x08 -#define UART_FRAME_ERROR 0x10 -#define UART_PARITY_ERROR 0x20 -#define UART_OVERRUN_ERROR 0x40 -#define UART_CTS 0x80 - - -enum pl2303_type { - type_0, /* don't know the difference between type 0 and */ - type_1, /* type 1, until someone from prolific tells us... */ - HX, /* HX version of the pl2303 chip */ -}; - -struct pl2303_private { - spinlock_t lock; - wait_queue_head_t delta_msr_wait; - u8 line_control; - u8 line_status; - enum pl2303_type type; -}; - -static int pl2303_vendor_read(__u16 value, __u16 index, - struct usb_serial *serial, unsigned char *buf) -{ - int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE, - value, index, buf, 1, 100); - dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE, - VENDOR_READ_REQUEST, value, index, res, buf[0]); - return res; -} - -static int pl2303_vendor_write(__u16 value, __u16 index, - struct usb_serial *serial) -{ - int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE, - value, index, NULL, 0, 100); - dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE, - VENDOR_WRITE_REQUEST, value, index, res); - return res; -} - -static int pl2303_startup(struct usb_serial *serial) -{ - struct pl2303_private *priv; - enum pl2303_type type = type_0; - unsigned char *buf; - int i; - - buf = kmalloc(10, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - if (serial->dev->descriptor.bDeviceClass == 0x02) - type = type_0; - else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40) - type = HX; - else if (serial->dev->descriptor.bDeviceClass == 0x00) - type = type_1; - else if (serial->dev->descriptor.bDeviceClass == 0xFF) - type = type_1; - dbg("device type: %d", type); - - for (i = 0; i < serial->num_ports; ++i) { - priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL); - if (!priv) - goto cleanup; - spin_lock_init(&priv->lock); - init_waitqueue_head(&priv->delta_msr_wait); - priv->type = type; - usb_set_serial_port_data(serial->port[i], priv); - } - - pl2303_vendor_read(0x8484, 0, serial, buf); - pl2303_vendor_write(0x0404, 0, serial); - pl2303_vendor_read(0x8484, 0, serial, buf); - pl2303_vendor_read(0x8383, 0, serial, buf); - pl2303_vendor_read(0x8484, 0, serial, buf); - pl2303_vendor_write(0x0404, 1, serial); - pl2303_vendor_read(0x8484, 0, serial, buf); - pl2303_vendor_read(0x8383, 0, serial, buf); - pl2303_vendor_write(0, 1, serial); - pl2303_vendor_write(1, 0, serial); - if (type == HX) - pl2303_vendor_write(2, 0x44, serial); - else - pl2303_vendor_write(2, 0x24, serial); - - kfree(buf); - return 0; - -cleanup: - kfree(buf); - for (--i; i >= 0; --i) { - priv = usb_get_serial_port_data(serial->port[i]); - kfree(priv); - usb_set_serial_port_data(serial->port[i], NULL); - } - return -ENOMEM; -} - -static int set_control_lines(struct usb_device *dev, u8 value) -{ - int retval; - - retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE, - value, 0, NULL, 0, 100); - dbg("%s - value = %d, retval = %d", __func__, value, retval); - return retval; -} - -static void pl2303_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) -{ - struct usb_serial *serial = port->serial; - struct pl2303_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - unsigned int cflag; - unsigned char *buf; - int baud; - int i; - u8 control; - const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600, - 4800, 7200, 9600, 14400, 19200, 28800, 38400, - 57600, 115200, 230400, 460800, 614400, - 921600, 1228800, 2457600, 3000000, 6000000 }; - int baud_floor, baud_ceil; - int k; - - dbg("%s - port %d", __func__, port->number); - - /* The PL2303 is reported to lose bytes if you change - serial settings even to the same values as before. Thus - we actually need to filter in this specific case */ - - if (!tty_termios_hw_change(tty->termios, old_termios)) - return; - - cflag = tty->termios->c_cflag; - - buf = kzalloc(7, GFP_KERNEL); - if (!buf) { - dev_err(&port->dev, "%s - out of memory.\n", __func__); - /* Report back no change occurred */ - *tty->termios = *old_termios; - return; - } - - i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, - 0, 0, buf, 7, 100); - dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i, - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); - - if (cflag & CSIZE) { - switch (cflag & CSIZE) { - case CS5: - buf[6] = 5; - break; - case CS6: - buf[6] = 6; - break; - case CS7: - buf[6] = 7; - break; - default: - case CS8: - buf[6] = 8; - break; - } - dbg("%s - data bits = %d", __func__, buf[6]); - } - - /* For reference buf[0]:buf[3] baud rate value */ - /* NOTE: Only the values defined in baud_sup are supported ! - * => if unsupported values are set, the PL2303 seems to use - * 9600 baud (at least my PL2303X always does) - */ - baud = tty_get_baud_rate(tty); - dbg("%s - baud requested = %d", __func__, baud); - if (baud) { - /* Set baudrate to nearest supported value */ - for (k=0; k (baud % baud_floor)) - baud = baud_floor; - else - baud = baud_ceil; - } - break; - } - } - if (baud > 1228800) { - /* type_0, type_1 only support up to 1228800 baud */ - if (priv->type != HX) - baud = 1228800; - else if (baud > 6000000) - baud = 6000000; - } - dbg("%s - baud set = %d", __func__, baud); - if (baud <= 115200) { - buf[0] = baud & 0xff; - buf[1] = (baud >> 8) & 0xff; - buf[2] = (baud >> 16) & 0xff; - buf[3] = (baud >> 24) & 0xff; - } else { - /* apparently the formula for higher speeds is: - * baudrate = 12M * 32 / (2^buf[1]) / buf[0] - */ - unsigned tmp = 12*1000*1000*32 / baud; - buf[3] = 0x80; - buf[2] = 0; - buf[1] = (tmp >= 256); - while (tmp >= 256) { - tmp >>= 2; - buf[1] <<= 1; - } - buf[0] = tmp; - } - } - - /* For reference buf[4]=0 is 1 stop bits */ - /* For reference buf[4]=1 is 1.5 stop bits */ - /* For reference buf[4]=2 is 2 stop bits */ - if (cflag & CSTOPB) { - /* NOTE: Comply with "real" UARTs / RS232: - * use 1.5 instead of 2 stop bits with 5 data bits - */ - if ((cflag & CSIZE) == CS5) { - buf[4] = 1; - dbg("%s - stop bits = 1.5", __func__); - } else { - buf[4] = 2; - dbg("%s - stop bits = 2", __func__); - } - } else { - buf[4] = 0; - dbg("%s - stop bits = 1", __func__); - } - - if (cflag & PARENB) { - /* For reference buf[5]=0 is none parity */ - /* For reference buf[5]=1 is odd parity */ - /* For reference buf[5]=2 is even parity */ - /* For reference buf[5]=3 is mark parity */ - /* For reference buf[5]=4 is space parity */ - if (cflag & PARODD) { - if (cflag & CMSPAR) { - buf[5] = 3; - dbg("%s - parity = mark", __func__); - } else { - buf[5] = 1; - dbg("%s - parity = odd", __func__); - } - } else { - if (cflag & CMSPAR) { - buf[5] = 4; - dbg("%s - parity = space", __func__); - } else { - buf[5] = 2; - dbg("%s - parity = even", __func__); - } - } - } else { - buf[5] = 0; - dbg("%s - parity = none", __func__); - } - - i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, - 0, 0, buf, 7, 100); - dbg("0x21:0x20:0:0 %d", i); - - /* change control lines if we are switching to or from B0 */ - spin_lock_irqsave(&priv->lock, flags); - control = priv->line_control; - if ((cflag & CBAUD) == B0) - priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); - else if ((old_termios->c_cflag & CBAUD) == B0) - priv->line_control |= (CONTROL_DTR | CONTROL_RTS); - if (control != priv->line_control) { - control = priv->line_control; - spin_unlock_irqrestore(&priv->lock, flags); - set_control_lines(serial->dev, control); - } else { - spin_unlock_irqrestore(&priv->lock, flags); - } - - buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0; - - i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, - 0, 0, buf, 7, 100); - dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i, - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); - - if (cflag & CRTSCTS) { - if (priv->type == HX) - pl2303_vendor_write(0x0, 0x61, serial); - else - pl2303_vendor_write(0x0, 0x41, serial); - } else { - pl2303_vendor_write(0x0, 0x0, serial); - } - - /* Save resulting baud rate */ - if (baud) - tty_encode_baud_rate(tty, baud, baud); - - kfree(buf); -} - -static void pl2303_dtr_rts(struct usb_serial_port *port, int on) -{ - struct pl2303_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - u8 control; - - spin_lock_irqsave(&priv->lock, flags); - /* Change DTR and RTS */ - if (on) - priv->line_control |= (CONTROL_DTR | CONTROL_RTS); - else - priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); - control = priv->line_control; - spin_unlock_irqrestore(&priv->lock, flags); - set_control_lines(port->serial->dev, control); -} - -static void pl2303_close(struct usb_serial_port *port) -{ - dbg("%s - port %d", __func__, port->number); - - usb_serial_generic_close(port); - usb_kill_urb(port->interrupt_in_urb); -} - -static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct ktermios tmp_termios; - struct usb_serial *serial = port->serial; - struct pl2303_private *priv = usb_get_serial_port_data(port); - int result; - - dbg("%s - port %d", __func__, port->number); - - if (priv->type != HX) { - usb_clear_halt(serial->dev, port->write_urb->pipe); - usb_clear_halt(serial->dev, port->read_urb->pipe); - } else { - /* reset upstream data pipes */ - pl2303_vendor_write(8, 0, serial); - pl2303_vendor_write(9, 0, serial); - } - - /* Setup termios */ - if (tty) - pl2303_set_termios(tty, port, &tmp_termios); - - dbg("%s - submitting interrupt urb", __func__); - result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - if (result) { - dev_err(&port->dev, "%s - failed submitting interrupt urb," - " error %d\n", __func__, result); - return result; - } - - result = usb_serial_generic_open(tty, port); - if (result) { - usb_kill_urb(port->interrupt_in_urb); - return result; - } - - port->port.drain_delay = 256; - return 0; -} - -static int pl2303_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct pl2303_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - u8 control; - - if (!usb_get_intfdata(port->serial->interface)) - return -ENODEV; - - spin_lock_irqsave(&priv->lock, flags); - if (set & TIOCM_RTS) - priv->line_control |= CONTROL_RTS; - if (set & TIOCM_DTR) - priv->line_control |= CONTROL_DTR; - if (clear & TIOCM_RTS) - priv->line_control &= ~CONTROL_RTS; - if (clear & TIOCM_DTR) - priv->line_control &= ~CONTROL_DTR; - control = priv->line_control; - spin_unlock_irqrestore(&priv->lock, flags); - - return set_control_lines(port->serial->dev, control); -} - -static int pl2303_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct pl2303_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - unsigned int mcr; - unsigned int status; - unsigned int result; - - dbg("%s (%d)", __func__, port->number); - - if (!usb_get_intfdata(port->serial->interface)) - return -ENODEV; - - spin_lock_irqsave(&priv->lock, flags); - mcr = priv->line_control; - status = priv->line_status; - spin_unlock_irqrestore(&priv->lock, flags); - - result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0) - | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0) - | ((status & UART_CTS) ? TIOCM_CTS : 0) - | ((status & UART_DSR) ? TIOCM_DSR : 0) - | ((status & UART_RING) ? TIOCM_RI : 0) - | ((status & UART_DCD) ? TIOCM_CD : 0); - - dbg("%s - result = %x", __func__, result); - - return result; -} - -static int pl2303_carrier_raised(struct usb_serial_port *port) -{ - struct pl2303_private *priv = usb_get_serial_port_data(port); - if (priv->line_status & UART_DCD) - return 1; - return 0; -} - -static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) -{ - struct pl2303_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - unsigned int prevstatus; - unsigned int status; - unsigned int changed; - - spin_lock_irqsave(&priv->lock, flags); - prevstatus = priv->line_status; - spin_unlock_irqrestore(&priv->lock, flags); - - while (1) { - interruptible_sleep_on(&priv->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - - spin_lock_irqsave(&priv->lock, flags); - status = priv->line_status; - spin_unlock_irqrestore(&priv->lock, flags); - - changed = prevstatus ^ status; - - if (((arg & TIOCM_RNG) && (changed & UART_RING)) || - ((arg & TIOCM_DSR) && (changed & UART_DSR)) || - ((arg & TIOCM_CD) && (changed & UART_DCD)) || - ((arg & TIOCM_CTS) && (changed & UART_CTS))) { - return 0; - } - prevstatus = status; - } - /* NOTREACHED */ - return 0; -} - -static int pl2303_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct serial_struct ser; - struct usb_serial_port *port = tty->driver_data; - dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd); - - switch (cmd) { - case TIOCGSERIAL: - memset(&ser, 0, sizeof ser); - ser.type = PORT_16654; - ser.line = port->serial->minor; - ser.port = port->number; - ser.baud_base = 460800; - - if (copy_to_user((void __user *)arg, &ser, sizeof ser)) - return -EFAULT; - - return 0; - - case TIOCMIWAIT: - dbg("%s (%d) TIOCMIWAIT", __func__, port->number); - return wait_modem_info(port, arg); - default: - dbg("%s not supported = 0x%04x", __func__, cmd); - break; - } - return -ENOIOCTLCMD; -} - -static void pl2303_break_ctl(struct tty_struct *tty, int break_state) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; - u16 state; - int result; - - dbg("%s - port %d", __func__, port->number); - - if (break_state == 0) - state = BREAK_OFF; - else - state = BREAK_ON; - dbg("%s - turning break %s", __func__, - state == BREAK_OFF ? "off" : "on"); - - result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - BREAK_REQUEST, BREAK_REQUEST_TYPE, state, - 0, NULL, 0, 100); - if (result) - dbg("%s - error sending break = %d", __func__, result); -} - -static void pl2303_release(struct usb_serial *serial) -{ - int i; - struct pl2303_private *priv; - - dbg("%s", __func__); - - for (i = 0; i < serial->num_ports; ++i) { - priv = usb_get_serial_port_data(serial->port[i]); - kfree(priv); - } -} - -static void pl2303_update_line_status(struct usb_serial_port *port, - unsigned char *data, - unsigned int actual_length) -{ - - struct pl2303_private *priv = usb_get_serial_port_data(port); - struct tty_struct *tty; - unsigned long flags; - u8 status_idx = UART_STATE; - u8 length = UART_STATE + 1; - u8 prev_line_status; - u16 idv, idp; - - idv = le16_to_cpu(port->serial->dev->descriptor.idVendor); - idp = le16_to_cpu(port->serial->dev->descriptor.idProduct); - - - if (idv == SIEMENS_VENDOR_ID) { - if (idp == SIEMENS_PRODUCT_ID_X65 || - idp == SIEMENS_PRODUCT_ID_SX1 || - idp == SIEMENS_PRODUCT_ID_X75) { - - length = 1; - status_idx = 0; - } - } - - if (actual_length < length) - return; - - /* Save off the uart status for others to look at */ - spin_lock_irqsave(&priv->lock, flags); - prev_line_status = priv->line_status; - priv->line_status = data[status_idx]; - spin_unlock_irqrestore(&priv->lock, flags); - if (priv->line_status & UART_BREAK_ERROR) - usb_serial_handle_break(port); - wake_up_interruptible(&priv->delta_msr_wait); - - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - if ((priv->line_status ^ prev_line_status) & UART_DCD) - usb_serial_handle_dcd_change(port, tty, - priv->line_status & UART_DCD); - tty_kref_put(tty); -} - -static void pl2303_read_int_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - unsigned char *data = urb->transfer_buffer; - unsigned int actual_length = urb->actual_length; - int status = urb->status; - int retval; - - dbg("%s (%d)", __func__, port->number); - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, - status); - return; - default: - dbg("%s - nonzero urb status received: %d", __func__, - status); - goto exit; - } - - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, urb->transfer_buffer); - - pl2303_update_line_status(port, data, actual_length); - -exit: - retval = usb_submit_urb(urb, GFP_ATOMIC); - if (retval) - dev_err(&urb->dev->dev, - "%s - usb_submit_urb failed with result %d\n", - __func__, retval); -} - -static void pl2303_process_read_urb(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct pl2303_private *priv = usb_get_serial_port_data(port); - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - char tty_flag = TTY_NORMAL; - unsigned long flags; - u8 line_status; - int i; - - /* update line status */ - spin_lock_irqsave(&priv->lock, flags); - line_status = priv->line_status; - priv->line_status &= ~UART_STATE_TRANSIENT_MASK; - spin_unlock_irqrestore(&priv->lock, flags); - wake_up_interruptible(&priv->delta_msr_wait); - - if (!urb->actual_length) - return; - - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - - /* break takes precedence over parity, */ - /* which takes precedence over framing errors */ - if (line_status & UART_BREAK_ERROR) - tty_flag = TTY_BREAK; - else if (line_status & UART_PARITY_ERROR) - tty_flag = TTY_PARITY; - else if (line_status & UART_FRAME_ERROR) - tty_flag = TTY_FRAME; - dbg("%s - tty_flag = %d", __func__, tty_flag); - - /* overrun is special, not associated with a char */ - if (line_status & UART_OVERRUN_ERROR) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - - if (port->port.console && port->sysrq) { - for (i = 0; i < urb->actual_length; ++i) - if (!usb_serial_handle_sysrq_char(port, data[i])) - tty_insert_flip_char(tty, data[i], tty_flag); - } else { - tty_insert_flip_string_fixed_flag(tty, data, tty_flag, - urb->actual_length); - } - - tty_flip_buffer_push(tty); - tty_kref_put(tty); -} - -/* All of the device info needed for the PL2303 SIO serial converter */ -static struct usb_serial_driver pl2303_device = { - .driver = { - .owner = THIS_MODULE, - .name = "pl2303", - }, - .id_table = id_table, - .num_ports = 1, - .bulk_in_size = 256, - .bulk_out_size = 256, - .open = pl2303_open, - .close = pl2303_close, - .dtr_rts = pl2303_dtr_rts, - .carrier_raised = pl2303_carrier_raised, - .ioctl = pl2303_ioctl, - .break_ctl = pl2303_break_ctl, - .set_termios = pl2303_set_termios, - .tiocmget = pl2303_tiocmget, - .tiocmset = pl2303_tiocmset, - .process_read_urb = pl2303_process_read_urb, - .read_int_callback = pl2303_read_int_callback, - .attach = pl2303_startup, - .release = pl2303_release, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &pl2303_device, NULL -}; - -module_usb_serial_driver(pl2303_driver, serial_drivers); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - diff --git a/ANDROID_3.4.5/drivers/usb/serial/pl2303.h b/ANDROID_3.4.5/drivers/usb/serial/pl2303.h deleted file mode 100644 index c38b8c00..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/pl2303.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Prolific PL2303 USB to serial adaptor driver header file - * - * 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. - * - */ - -#define BENQ_VENDOR_ID 0x04a5 -#define BENQ_PRODUCT_ID_S81 0x4027 - -#define PL2303_VENDOR_ID 0x067b -#define PL2303_PRODUCT_ID 0x2303 -#define PL2303_PRODUCT_ID_RSAQ2 0x04bb -#define PL2303_PRODUCT_ID_DCU11 0x1234 -#define PL2303_PRODUCT_ID_PHAROS 0xaaa0 -#define PL2303_PRODUCT_ID_RSAQ3 0xaaa2 -#define PL2303_PRODUCT_ID_ALDIGA 0x0611 -#define PL2303_PRODUCT_ID_MMX 0x0612 -#define PL2303_PRODUCT_ID_GPRS 0x0609 -#define PL2303_PRODUCT_ID_HCR331 0x331a -#define PL2303_PRODUCT_ID_MOTOROLA 0x0307 - -#define ATEN_VENDOR_ID 0x0557 -#define ATEN_VENDOR_ID2 0x0547 -#define ATEN_PRODUCT_ID 0x2008 - -#define IODATA_VENDOR_ID 0x04bb -#define IODATA_PRODUCT_ID 0x0a03 -#define IODATA_PRODUCT_ID_RSAQ5 0x0a0e - -#define ELCOM_VENDOR_ID 0x056e -#define ELCOM_PRODUCT_ID 0x5003 -#define ELCOM_PRODUCT_ID_UCSGT 0x5004 - -#define ITEGNO_VENDOR_ID 0x0eba -#define ITEGNO_PRODUCT_ID 0x1080 -#define ITEGNO_PRODUCT_ID_2080 0x2080 - -#define MA620_VENDOR_ID 0x0df7 -#define MA620_PRODUCT_ID 0x0620 - -#define RATOC_VENDOR_ID 0x0584 -#define RATOC_PRODUCT_ID 0xb000 - -#define TRIPP_VENDOR_ID 0x2478 -#define TRIPP_PRODUCT_ID 0x2008 - -#define RADIOSHACK_VENDOR_ID 0x1453 -#define RADIOSHACK_PRODUCT_ID 0x4026 - -#define DCU10_VENDOR_ID 0x0731 -#define DCU10_PRODUCT_ID 0x0528 - -#define SITECOM_VENDOR_ID 0x6189 -#define SITECOM_PRODUCT_ID 0x2068 - -/* Alcatel OT535/735 USB cable */ -#define ALCATEL_VENDOR_ID 0x11f7 -#define ALCATEL_PRODUCT_ID 0x02df - -/* Samsung I330 phone cradle */ -#define SAMSUNG_VENDOR_ID 0x04e8 -#define SAMSUNG_PRODUCT_ID 0x8001 - -#define SIEMENS_VENDOR_ID 0x11f5 -#define SIEMENS_PRODUCT_ID_SX1 0x0001 -#define SIEMENS_PRODUCT_ID_X65 0x0003 -#define SIEMENS_PRODUCT_ID_X75 0x0004 -#define SIEMENS_PRODUCT_ID_EF81 0x0005 - -#define SYNTECH_VENDOR_ID 0x0745 -#define SYNTECH_PRODUCT_ID 0x0001 - -/* Nokia CA-42 Cable */ -#define NOKIA_CA42_VENDOR_ID 0x078b -#define NOKIA_CA42_PRODUCT_ID 0x1234 - -/* CA-42 CLONE Cable www.ca-42.com chipset: Prolific Technology Inc */ -#define CA_42_CA42_VENDOR_ID 0x10b5 -#define CA_42_CA42_PRODUCT_ID 0xac70 - -#define SAGEM_VENDOR_ID 0x079b -#define SAGEM_PRODUCT_ID 0x0027 - -/* Leadtek GPS 9531 (ID 0413:2101) */ -#define LEADTEK_VENDOR_ID 0x0413 -#define LEADTEK_9531_PRODUCT_ID 0x2101 - -/* USB GSM cable from Speed Dragon Multimedia, Ltd */ -#define SPEEDDRAGON_VENDOR_ID 0x0e55 -#define SPEEDDRAGON_PRODUCT_ID 0x110b - -/* DATAPILOT Universal-2 Phone Cable */ -#define DATAPILOT_U2_VENDOR_ID 0x0731 -#define DATAPILOT_U2_PRODUCT_ID 0x2003 - -/* Belkin "F5U257" Serial Adapter */ -#define BELKIN_VENDOR_ID 0x050d -#define BELKIN_PRODUCT_ID 0x0257 - -/* Alcor Micro Corp. USB 2.0 TO RS-232 */ -#define ALCOR_VENDOR_ID 0x058F -#define ALCOR_PRODUCT_ID 0x9720 - -/* Willcom WS002IN Data Driver (by NetIndex Inc.) */ -#define WS002IN_VENDOR_ID 0x11f6 -#define WS002IN_PRODUCT_ID 0x2001 - -/* Corega CG-USBRS232R Serial Adapter */ -#define COREGA_VENDOR_ID 0x07aa -#define COREGA_PRODUCT_ID 0x002a - -/* Y.C. Cable U.S.A., Inc - USB to RS-232 */ -#define YCCABLE_VENDOR_ID 0x05ad -#define YCCABLE_PRODUCT_ID 0x0fba - -/* "Superial" USB - Serial */ -#define SUPERIAL_VENDOR_ID 0x5372 -#define SUPERIAL_PRODUCT_ID 0x2303 - -/* Hewlett-Packard LD220-HP POS Pole Display */ -#define HP_VENDOR_ID 0x03f0 -#define HP_LD220_PRODUCT_ID 0x3524 - -/* Cressi Edy (diving computer) PC interface */ -#define CRESSI_VENDOR_ID 0x04b8 -#define CRESSI_EDY_PRODUCT_ID 0x0521 - -/* Zeagle dive computer interface */ -#define ZEAGLE_VENDOR_ID 0x04b8 -#define ZEAGLE_N2ITION3_PRODUCT_ID 0x0522 - -/* Sony, USB data cable for CMD-Jxx mobile phones */ -#define SONY_VENDOR_ID 0x054c -#define SONY_QN3USB_PRODUCT_ID 0x0437 - -/* Sanwa KB-USB2 multimeter cable (ID: 11ad:0001) */ -#define SANWA_VENDOR_ID 0x11ad -#define SANWA_PRODUCT_ID 0x0001 - -/* ADLINK ND-6530 RS232,RS485 and RS422 adapter */ -#define ADLINK_VENDOR_ID 0x0b63 -#define ADLINK_ND6530_PRODUCT_ID 0x6530 - -/* SMART USB Serial Adapter */ -#define SMART_VENDOR_ID 0x0b8c -#define SMART_PRODUCT_ID 0x2303 - diff --git a/ANDROID_3.4.5/drivers/usb/serial/qcaux.c b/ANDROID_3.4.5/drivers/usb/serial/qcaux.c deleted file mode 100644 index 96624568..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/qcaux.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Qualcomm USB Auxiliary Serial Port driver - * - * Copyright (C) 2008 Greg Kroah-Hartman - * Copyright (C) 2010 Dan Williams - * - * 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. - * - * Devices listed here usually provide a CDC ACM port on which normal modem - * AT commands and PPP can be used. But when that port is in-use by PPP it - * cannot be used simultaneously for status or signal strength. Instead, the - * ports here can be queried for that information using the Qualcomm DM - * protocol. - */ - -#include -#include -#include -#include -#include -#include - -/* NOTE: for now, only use this driver for devices that provide a CDC-ACM port - * for normal AT commands, but also provide secondary USB interfaces for the - * QCDM-capable ports. Devices that do not provide a CDC-ACM port should - * probably be driven by option.ko. - */ - -/* UTStarcom/Pantech/Curitel devices */ -#define UTSTARCOM_VENDOR_ID 0x106c -#define UTSTARCOM_PRODUCT_PC5740 0x3701 -#define UTSTARCOM_PRODUCT_PC5750 0x3702 /* aka Pantech PX-500 */ -#define UTSTARCOM_PRODUCT_UM150 0x3711 -#define UTSTARCOM_PRODUCT_UM175_V1 0x3712 -#define UTSTARCOM_PRODUCT_UM175_V2 0x3714 -#define UTSTARCOM_PRODUCT_UM175_ALLTEL 0x3715 -#define PANTECH_PRODUCT_UML190_VZW 0x3716 -#define PANTECH_PRODUCT_UML290_VZW 0x3718 - -/* CMOTECH devices */ -#define CMOTECH_VENDOR_ID 0x16d8 -#define CMOTECH_PRODUCT_CDU550 0x5553 -#define CMOTECH_PRODUCT_CDX650 0x6512 - -/* LG devices */ -#define LG_VENDOR_ID 0x1004 -#define LG_PRODUCT_VX4400_6000 0x6000 /* VX4400/VX6000/Rumor */ - -/* Sanyo devices */ -#define SANYO_VENDOR_ID 0x0474 -#define SANYO_PRODUCT_KATANA_LX 0x0754 /* SCP-3800 (Katana LX) */ - -/* Samsung devices */ -#define SAMSUNG_VENDOR_ID 0x04e8 -#define SAMSUNG_PRODUCT_U520 0x6640 /* SCH-U520 */ - -static struct usb_device_id id_table[] = { - { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_PC5740, 0xff, 0x00, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_PC5750, 0xff, 0x00, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_UM150, 0xff, 0x00, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_UM175_V1, 0xff, 0x00, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_UM175_V2, 0xff, 0x00, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_UM175_ALLTEL, 0xff, 0x00, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDU550, 0xff, 0xff, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDX650, 0xff, 0xff, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(LG_VENDOR_ID, LG_PRODUCT_VX4400_6000, 0xff, 0xff, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(SANYO_VENDOR_ID, SANYO_PRODUCT_KATANA_LX, 0xff, 0xff, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_U520, 0xff, 0x00, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML190_VZW, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML190_VZW, 0xff, 0xfe, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xfd, 0xff) }, /* NMEA */ - { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xfe, 0xff) }, /* WMC */ - { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xff, 0xff) }, /* DIAG */ - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver qcaux_driver = { - .name = "qcaux", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - -static struct usb_serial_driver qcaux_device = { - .driver = { - .owner = THIS_MODULE, - .name = "qcaux", - }, - .id_table = id_table, - .num_ports = 1, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &qcaux_device, NULL -}; - -module_usb_serial_driver(qcaux_driver, serial_drivers); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/qcserial.c b/ANDROID_3.4.5/drivers/usb/serial/qcserial.c deleted file mode 100644 index 50b53717..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/qcserial.c +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Qualcomm Serial USB driver - * - * Copyright (c) 2008 QUALCOMM Incorporated. - * Copyright (c) 2009 Greg Kroah-Hartman - * Copyright (c) 2009 Novell Inc. - * - * 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include "usb-wwan.h" - -#define DRIVER_AUTHOR "Qualcomm Inc" -#define DRIVER_DESC "Qualcomm USB Serial driver" - -static bool debug; - -#define DEVICE_G1K(v, p) \ - USB_DEVICE(v, p), .driver_info = 1 - -static const struct usb_device_id id_table[] = { - /* Gobi 1000 devices */ - {DEVICE_G1K(0x05c6, 0x9211)}, /* Acer Gobi QDL device */ - {DEVICE_G1K(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ - {DEVICE_G1K(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */ - {DEVICE_G1K(0x03f0, 0x201d)}, /* HP un2400 Gobi QDL Device */ - {DEVICE_G1K(0x04da, 0x250d)}, /* Panasonic Gobi Modem device */ - {DEVICE_G1K(0x04da, 0x250c)}, /* Panasonic Gobi QDL device */ - {DEVICE_G1K(0x413c, 0x8172)}, /* Dell Gobi Modem device */ - {DEVICE_G1K(0x413c, 0x8171)}, /* Dell Gobi QDL device */ - {DEVICE_G1K(0x1410, 0xa001)}, /* Novatel Gobi Modem device */ - {DEVICE_G1K(0x1410, 0xa008)}, /* Novatel Gobi QDL device */ - {DEVICE_G1K(0x0b05, 0x1776)}, /* Asus Gobi Modem device */ - {DEVICE_G1K(0x0b05, 0x1774)}, /* Asus Gobi QDL device */ - {DEVICE_G1K(0x19d2, 0xfff3)}, /* ONDA Gobi Modem device */ - {DEVICE_G1K(0x19d2, 0xfff2)}, /* ONDA Gobi QDL device */ - {DEVICE_G1K(0x1557, 0x0a80)}, /* OQO Gobi QDL device */ - {DEVICE_G1K(0x05c6, 0x9001)}, /* Generic Gobi Modem device */ - {DEVICE_G1K(0x05c6, 0x9002)}, /* Generic Gobi Modem device */ - {DEVICE_G1K(0x05c6, 0x9202)}, /* Generic Gobi Modem device */ - {DEVICE_G1K(0x05c6, 0x9203)}, /* Generic Gobi Modem device */ - {DEVICE_G1K(0x05c6, 0x9222)}, /* Generic Gobi Modem device */ - {DEVICE_G1K(0x05c6, 0x9008)}, /* Generic Gobi QDL device */ - {DEVICE_G1K(0x05c6, 0x9009)}, /* Generic Gobi Modem device */ - {DEVICE_G1K(0x05c6, 0x9201)}, /* Generic Gobi QDL device */ - {DEVICE_G1K(0x05c6, 0x9221)}, /* Generic Gobi QDL device */ - {DEVICE_G1K(0x05c6, 0x9231)}, /* Generic Gobi QDL device */ - {DEVICE_G1K(0x1f45, 0x0001)}, /* Unknown Gobi QDL device */ - - /* Gobi 2000 devices */ - {USB_DEVICE(0x1410, 0xa010)}, /* Novatel Gobi 2000 QDL device */ - {USB_DEVICE(0x1410, 0xa011)}, /* Novatel Gobi 2000 QDL device */ - {USB_DEVICE(0x1410, 0xa012)}, /* Novatel Gobi 2000 QDL device */ - {USB_DEVICE(0x1410, 0xa013)}, /* Novatel Gobi 2000 QDL device */ - {USB_DEVICE(0x1410, 0xa014)}, /* Novatel Gobi 2000 QDL device */ - {USB_DEVICE(0x413c, 0x8185)}, /* Dell Gobi 2000 QDL device (N0218, VU936) */ - {USB_DEVICE(0x413c, 0x8186)}, /* Dell Gobi 2000 Modem device (N0218, VU936) */ - {USB_DEVICE(0x05c6, 0x9208)}, /* Generic Gobi 2000 QDL device */ - {USB_DEVICE(0x05c6, 0x920b)}, /* Generic Gobi 2000 Modem device */ - {USB_DEVICE(0x05c6, 0x9224)}, /* Sony Gobi 2000 QDL device (N0279, VU730) */ - {USB_DEVICE(0x05c6, 0x9225)}, /* Sony Gobi 2000 Modem device (N0279, VU730) */ - {USB_DEVICE(0x05c6, 0x9244)}, /* Samsung Gobi 2000 QDL device (VL176) */ - {USB_DEVICE(0x05c6, 0x9245)}, /* Samsung Gobi 2000 Modem device (VL176) */ - {USB_DEVICE(0x03f0, 0x241d)}, /* HP Gobi 2000 QDL device (VP412) */ - {USB_DEVICE(0x03f0, 0x251d)}, /* HP Gobi 2000 Modem device (VP412) */ - {USB_DEVICE(0x05c6, 0x9214)}, /* Acer Gobi 2000 QDL device (VP413) */ - {USB_DEVICE(0x05c6, 0x9215)}, /* Acer Gobi 2000 Modem device (VP413) */ - {USB_DEVICE(0x05c6, 0x9264)}, /* Asus Gobi 2000 QDL device (VR305) */ - {USB_DEVICE(0x05c6, 0x9265)}, /* Asus Gobi 2000 Modem device (VR305) */ - {USB_DEVICE(0x05c6, 0x9234)}, /* Top Global Gobi 2000 QDL device (VR306) */ - {USB_DEVICE(0x05c6, 0x9235)}, /* Top Global Gobi 2000 Modem device (VR306) */ - {USB_DEVICE(0x05c6, 0x9274)}, /* iRex Technologies Gobi 2000 QDL device (VR307) */ - {USB_DEVICE(0x05c6, 0x9275)}, /* iRex Technologies Gobi 2000 Modem device (VR307) */ - {USB_DEVICE(0x1199, 0x9000)}, /* Sierra Wireless Gobi 2000 QDL device (VT773) */ - {USB_DEVICE(0x1199, 0x9001)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ - {USB_DEVICE(0x1199, 0x9002)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ - {USB_DEVICE(0x1199, 0x9003)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ - {USB_DEVICE(0x1199, 0x9004)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ - {USB_DEVICE(0x1199, 0x9005)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ - {USB_DEVICE(0x1199, 0x9006)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ - {USB_DEVICE(0x1199, 0x9007)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ - {USB_DEVICE(0x1199, 0x9008)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ - {USB_DEVICE(0x1199, 0x9009)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ - {USB_DEVICE(0x1199, 0x900a)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ - {USB_DEVICE(0x1199, 0x9011)}, /* Sierra Wireless Gobi 2000 Modem device (MC8305) */ - {USB_DEVICE(0x16d8, 0x8001)}, /* CMDTech Gobi 2000 QDL device (VU922) */ - {USB_DEVICE(0x16d8, 0x8002)}, /* CMDTech Gobi 2000 Modem device (VU922) */ - {USB_DEVICE(0x05c6, 0x9204)}, /* Gobi 2000 QDL device */ - {USB_DEVICE(0x05c6, 0x9205)}, /* Gobi 2000 Modem device */ - - /* Gobi 3000 devices */ - {USB_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Gobi 3000 QDL */ - {USB_DEVICE(0x05c6, 0x920c)}, /* Gobi 3000 QDL */ - {USB_DEVICE(0x05c6, 0x920d)}, /* Gobi 3000 Composite */ - {USB_DEVICE(0x1410, 0xa020)}, /* Novatel Gobi 3000 QDL */ - {USB_DEVICE(0x1410, 0xa021)}, /* Novatel Gobi 3000 Composite */ - {USB_DEVICE(0x413c, 0x8193)}, /* Dell Gobi 3000 QDL */ - {USB_DEVICE(0x413c, 0x8194)}, /* Dell Gobi 3000 Composite */ - {USB_DEVICE(0x1199, 0x9010)}, /* Sierra Wireless Gobi 3000 QDL */ - {USB_DEVICE(0x1199, 0x9012)}, /* Sierra Wireless Gobi 3000 QDL */ - {USB_DEVICE(0x1199, 0x9013)}, /* Sierra Wireless Gobi 3000 Modem device (MC8355) */ - {USB_DEVICE(0x1199, 0x9014)}, /* Sierra Wireless Gobi 3000 QDL */ - {USB_DEVICE(0x1199, 0x9015)}, /* Sierra Wireless Gobi 3000 Modem device */ - {USB_DEVICE(0x1199, 0x9018)}, /* Sierra Wireless Gobi 3000 QDL */ - {USB_DEVICE(0x1199, 0x9019)}, /* Sierra Wireless Gobi 3000 Modem device */ - {USB_DEVICE(0x12D1, 0x14F0)}, /* Sony Gobi 3000 QDL */ - {USB_DEVICE(0x12D1, 0x14F1)}, /* Sony Gobi 3000 Composite */ - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver qcdriver = { - .name = "qcserial", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .supports_autosuspend = true, -}; - -static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) -{ - struct usb_wwan_intf_private *data; - struct usb_host_interface *intf = serial->interface->cur_altsetting; - int retval = -ENODEV; - __u8 nintf; - __u8 ifnum; - bool is_gobi1k = id->driver_info ? true : false; - - dbg("%s", __func__); - dbg("Is Gobi 1000 = %d", is_gobi1k); - - nintf = serial->dev->actconfig->desc.bNumInterfaces; - dbg("Num Interfaces = %d", nintf); - ifnum = intf->desc.bInterfaceNumber; - dbg("This Interface = %d", ifnum); - - data = kzalloc(sizeof(struct usb_wwan_intf_private), - GFP_KERNEL); - if (!data) - return -ENOMEM; - - spin_lock_init(&data->susp_lock); - - switch (nintf) { - case 1: - /* QDL mode */ - /* Gobi 2000 has a single altsetting, older ones have two */ - if (serial->interface->num_altsetting == 2) - intf = &serial->interface->altsetting[1]; - else if (serial->interface->num_altsetting > 2) - break; - - if (intf->desc.bNumEndpoints == 2 && - usb_endpoint_is_bulk_in(&intf->endpoint[0].desc) && - usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) { - dbg("QDL port found"); - - if (serial->interface->num_altsetting == 1) { - retval = 0; /* Success */ - break; - } - - retval = usb_set_interface(serial->dev, ifnum, 1); - if (retval < 0) { - dev_err(&serial->dev->dev, - "Could not set interface, error %d\n", - retval); - retval = -ENODEV; - kfree(data); - } - } - break; - - case 3: - case 4: - /* Composite mode; don't bind to the QMI/net interface as that - * gets handled by other drivers. - */ - - /* Gobi 1K USB layout: - * 0: serial port (doesn't respond) - * 1: serial port (doesn't respond) - * 2: AT-capable modem port - * 3: QMI/net - * - * Gobi 2K+ USB layout: - * 0: QMI/net - * 1: DM/DIAG (use libqcdm from ModemManager for communication) - * 2: AT-capable modem port - * 3: NMEA - */ - - if (ifnum == 1 && !is_gobi1k) { - dbg("Gobi 2K+ DM/DIAG interface found"); - retval = usb_set_interface(serial->dev, ifnum, 0); - if (retval < 0) { - dev_err(&serial->dev->dev, - "Could not set interface, error %d\n", - retval); - retval = -ENODEV; - kfree(data); - } - } else if (ifnum == 2) { - dbg("Modem port found"); - retval = usb_set_interface(serial->dev, ifnum, 0); - if (retval < 0) { - dev_err(&serial->dev->dev, - "Could not set interface, error %d\n", - retval); - retval = -ENODEV; - kfree(data); - } - } else if (ifnum==3 && !is_gobi1k) { - /* - * NMEA (serial line 9600 8N1) - * # echo "\$GPS_START" > /dev/ttyUSBx - * # echo "\$GPS_STOP" > /dev/ttyUSBx - */ - dbg("Gobi 2K+ NMEA GPS interface found"); - retval = usb_set_interface(serial->dev, ifnum, 0); - if (retval < 0) { - dev_err(&serial->dev->dev, - "Could not set interface, error %d\n", - retval); - retval = -ENODEV; - kfree(data); - } - } - break; - - default: - dev_err(&serial->dev->dev, - "unknown number of interfaces: %d\n", nintf); - kfree(data); - retval = -ENODEV; - } - - /* Set serial->private if not returning -ENODEV */ - if (retval != -ENODEV) - usb_set_serial_data(serial, data); - return retval; -} - -static void qc_release(struct usb_serial *serial) -{ - struct usb_wwan_intf_private *priv = usb_get_serial_data(serial); - - dbg("%s", __func__); - - /* Call usb_wwan release & free the private data allocated in qcprobe */ - usb_wwan_release(serial); - usb_set_serial_data(serial, NULL); - kfree(priv); -} - -static struct usb_serial_driver qcdevice = { - .driver = { - .owner = THIS_MODULE, - .name = "qcserial", - }, - .description = "Qualcomm USB modem", - .id_table = id_table, - .num_ports = 1, - .probe = qcprobe, - .open = usb_wwan_open, - .close = usb_wwan_close, - .write = usb_wwan_write, - .write_room = usb_wwan_write_room, - .chars_in_buffer = usb_wwan_chars_in_buffer, - .attach = usb_wwan_startup, - .disconnect = usb_wwan_disconnect, - .release = qc_release, -#ifdef CONFIG_PM - .suspend = usb_wwan_suspend, - .resume = usb_wwan_resume, -#endif -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &qcdevice, NULL -}; - -module_usb_serial_driver(qcdriver, serial_drivers); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL v2"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/safe_serial.c b/ANDROID_3.4.5/drivers/usb/serial/safe_serial.c deleted file mode 100644 index ae4ee30c..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/safe_serial.c +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Safe Encapsulated USB Serial Driver - * - * Copyright (C) 2010 Johan Hovold - * Copyright (C) 2001 Lineo - * Copyright (C) 2001 Hewlett-Packard - * - * 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. - * - * By: - * Stuart Lynne , Tom Rushworth - */ - -/* - * The encapsultaion is designed to overcome difficulties with some USB - * hardware. - * - * While the USB protocol has a CRC over the data while in transit, i.e. while - * being carried over the bus, there is no end to end protection. If the - * hardware has any problems getting the data into or out of the USB transmit - * and receive FIFO's then data can be lost. - * - * This protocol adds a two byte trailer to each USB packet to specify the - * number of bytes of valid data and a 10 bit CRC that will allow the receiver - * to verify that the entire USB packet was received without error. - * - * Because in this case the sender and receiver are the class and function - * drivers there is now end to end protection. - * - * There is an additional option that can be used to force all transmitted - * packets to be padded to the maximum packet size. This provides a work - * around for some devices which have problems with small USB packets. - * - * Assuming a packetsize of N: - * - * 0..N-2 data and optional padding - * - * N-2 bits 7-2 - number of bytes of valid data - * bits 1-0 top two bits of 10 bit CRC - * N-1 bottom 8 bits of 10 bit CRC - * - * - * | Data Length | 10 bit CRC | - * + 7 . 6 . 5 . 4 . 3 . 2 . 1 . 0 | 7 . 6 . 5 . 4 . 3 . 2 . 1 . 0 + - * - * The 10 bit CRC is computed across the sent data, followed by the trailer - * with the length set and the CRC set to zero. The CRC is then OR'd into - * the trailer. - * - * When received a 10 bit CRC is computed over the entire frame including - * the trailer and should be equal to zero. - * - * Two module parameters are used to control the encapsulation, if both are - * turned of the module works as a simple serial device with NO - * encapsulation. - * - * See linux/drivers/usbd/serial_fd for a device function driver - * implementation of this. - * - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#ifndef CONFIG_USB_SERIAL_SAFE_PADDED -#define CONFIG_USB_SERIAL_SAFE_PADDED 0 -#endif - -static bool debug; -static bool safe = 1; -static bool padded = CONFIG_USB_SERIAL_SAFE_PADDED; - -#define DRIVER_VERSION "v0.1" -#define DRIVER_AUTHOR "sl@lineo.com, tbr@lineo.com, Johan Hovold " -#define DRIVER_DESC "USB Safe Encapsulated Serial" - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -static __u16 vendor; /* no default */ -static __u16 product; /* no default */ -module_param(vendor, ushort, 0); -MODULE_PARM_DESC(vendor, "User specified USB idVendor (required)"); -module_param(product, ushort, 0); -MODULE_PARM_DESC(product, "User specified USB idProduct (required)"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - -module_param(safe, bool, 0); -MODULE_PARM_DESC(safe, "Turn Safe Encapsulation On/Off"); - -module_param(padded, bool, 0); -MODULE_PARM_DESC(padded, "Pad to full wMaxPacketSize On/Off"); - -#define CDC_DEVICE_CLASS 0x02 - -#define CDC_INTERFACE_CLASS 0x02 -#define CDC_INTERFACE_SUBCLASS 0x06 - -#define LINEO_INTERFACE_CLASS 0xff - -#define LINEO_INTERFACE_SUBCLASS_SAFENET 0x01 -#define LINEO_SAFENET_CRC 0x01 -#define LINEO_SAFENET_CRC_PADDED 0x02 - -#define LINEO_INTERFACE_SUBCLASS_SAFESERIAL 0x02 -#define LINEO_SAFESERIAL_CRC 0x01 -#define LINEO_SAFESERIAL_CRC_PADDED 0x02 - - -#define MY_USB_DEVICE(vend, prod, dc, ic, isc) \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ - USB_DEVICE_ID_MATCH_DEV_CLASS | \ - USB_DEVICE_ID_MATCH_INT_CLASS | \ - USB_DEVICE_ID_MATCH_INT_SUBCLASS, \ - .idVendor = (vend), \ - .idProduct = (prod),\ - .bDeviceClass = (dc),\ - .bInterfaceClass = (ic), \ - .bInterfaceSubClass = (isc), - -static struct usb_device_id id_table[] = { - {MY_USB_DEVICE(0x49f, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, /* Itsy */ - {MY_USB_DEVICE(0x3f0, 0x2101, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, /* Calypso */ - {MY_USB_DEVICE(0x4dd, 0x8001, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, /* Iris */ - {MY_USB_DEVICE(0x4dd, 0x8002, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, /* Collie */ - {MY_USB_DEVICE(0x4dd, 0x8003, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, /* Collie */ - {MY_USB_DEVICE(0x4dd, 0x8004, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, /* Collie */ - {MY_USB_DEVICE(0x5f9, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, /* Sharp tmp */ - /* extra null entry for module vendor/produc parameters */ - {MY_USB_DEVICE(0, 0, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)}, - {} /* terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver safe_driver = { - .name = "safe_serial", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - -static const __u16 crc10_table[256] = { - 0x000, 0x233, 0x255, 0x066, 0x299, 0x0aa, 0x0cc, 0x2ff, - 0x301, 0x132, 0x154, 0x367, 0x198, 0x3ab, 0x3cd, 0x1fe, - 0x031, 0x202, 0x264, 0x057, 0x2a8, 0x09b, 0x0fd, 0x2ce, - 0x330, 0x103, 0x165, 0x356, 0x1a9, 0x39a, 0x3fc, 0x1cf, - 0x062, 0x251, 0x237, 0x004, 0x2fb, 0x0c8, 0x0ae, 0x29d, - 0x363, 0x150, 0x136, 0x305, 0x1fa, 0x3c9, 0x3af, 0x19c, - 0x053, 0x260, 0x206, 0x035, 0x2ca, 0x0f9, 0x09f, 0x2ac, - 0x352, 0x161, 0x107, 0x334, 0x1cb, 0x3f8, 0x39e, 0x1ad, - 0x0c4, 0x2f7, 0x291, 0x0a2, 0x25d, 0x06e, 0x008, 0x23b, - 0x3c5, 0x1f6, 0x190, 0x3a3, 0x15c, 0x36f, 0x309, 0x13a, - 0x0f5, 0x2c6, 0x2a0, 0x093, 0x26c, 0x05f, 0x039, 0x20a, - 0x3f4, 0x1c7, 0x1a1, 0x392, 0x16d, 0x35e, 0x338, 0x10b, - 0x0a6, 0x295, 0x2f3, 0x0c0, 0x23f, 0x00c, 0x06a, 0x259, - 0x3a7, 0x194, 0x1f2, 0x3c1, 0x13e, 0x30d, 0x36b, 0x158, - 0x097, 0x2a4, 0x2c2, 0x0f1, 0x20e, 0x03d, 0x05b, 0x268, - 0x396, 0x1a5, 0x1c3, 0x3f0, 0x10f, 0x33c, 0x35a, 0x169, - 0x188, 0x3bb, 0x3dd, 0x1ee, 0x311, 0x122, 0x144, 0x377, - 0x289, 0x0ba, 0x0dc, 0x2ef, 0x010, 0x223, 0x245, 0x076, - 0x1b9, 0x38a, 0x3ec, 0x1df, 0x320, 0x113, 0x175, 0x346, - 0x2b8, 0x08b, 0x0ed, 0x2de, 0x021, 0x212, 0x274, 0x047, - 0x1ea, 0x3d9, 0x3bf, 0x18c, 0x373, 0x140, 0x126, 0x315, - 0x2eb, 0x0d8, 0x0be, 0x28d, 0x072, 0x241, 0x227, 0x014, - 0x1db, 0x3e8, 0x38e, 0x1bd, 0x342, 0x171, 0x117, 0x324, - 0x2da, 0x0e9, 0x08f, 0x2bc, 0x043, 0x270, 0x216, 0x025, - 0x14c, 0x37f, 0x319, 0x12a, 0x3d5, 0x1e6, 0x180, 0x3b3, - 0x24d, 0x07e, 0x018, 0x22b, 0x0d4, 0x2e7, 0x281, 0x0b2, - 0x17d, 0x34e, 0x328, 0x11b, 0x3e4, 0x1d7, 0x1b1, 0x382, - 0x27c, 0x04f, 0x029, 0x21a, 0x0e5, 0x2d6, 0x2b0, 0x083, - 0x12e, 0x31d, 0x37b, 0x148, 0x3b7, 0x184, 0x1e2, 0x3d1, - 0x22f, 0x01c, 0x07a, 0x249, 0x0b6, 0x285, 0x2e3, 0x0d0, - 0x11f, 0x32c, 0x34a, 0x179, 0x386, 0x1b5, 0x1d3, 0x3e0, - 0x21e, 0x02d, 0x04b, 0x278, 0x087, 0x2b4, 0x2d2, 0x0e1, -}; - -#define CRC10_INITFCS 0x000 /* Initial FCS value */ -#define CRC10_GOODFCS 0x000 /* Good final FCS value */ -#define CRC10_FCS(fcs, c) ((((fcs) << 8) & 0x3ff) ^ crc10_table[((fcs) >> 2) & 0xff] ^ (c)) - -/** - * fcs_compute10 - memcpy and calculate 10 bit CRC across buffer - * @sp: pointer to buffer - * @len: number of bytes - * @fcs: starting FCS - * - * Perform a memcpy and calculate fcs using ppp 10bit CRC algorithm. Return - * new 10 bit FCS. - */ -static __u16 __inline__ fcs_compute10(unsigned char *sp, int len, __u16 fcs) -{ - for (; len-- > 0; fcs = CRC10_FCS(fcs, *sp++)); - return fcs; -} - -static void safe_process_read_urb(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - unsigned char *data = urb->transfer_buffer; - unsigned char length = urb->actual_length; - int actual_length; - struct tty_struct *tty; - __u16 fcs; - - if (!length) - return; - - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - - if (!safe) - goto out; - - fcs = fcs_compute10(data, length, CRC10_INITFCS); - if (fcs) { - dev_err(&port->dev, "%s - bad CRC %x\n", __func__, fcs); - goto err; - } - - actual_length = data[length - 2] >> 2; - if (actual_length > (length - 2)) { - dev_err(&port->dev, "%s - inconsistent lengths %d:%d\n", - __func__, actual_length, length); - goto err; - } - dev_info(&urb->dev->dev, "%s - actual: %d\n", __func__, actual_length); - length = actual_length; -out: - tty_insert_flip_string(tty, data, length); - tty_flip_buffer_push(tty); -err: - tty_kref_put(tty); -} - -static int safe_prepare_write_buffer(struct usb_serial_port *port, - void *dest, size_t size) -{ - unsigned char *buf = dest; - int count; - int trailer_len; - int pkt_len; - __u16 fcs; - - trailer_len = safe ? 2 : 0; - - count = kfifo_out_locked(&port->write_fifo, buf, size - trailer_len, - &port->lock); - if (!safe) - return count; - - /* pad if necessary */ - if (padded) { - pkt_len = size; - memset(buf + count, '0', pkt_len - count - trailer_len); - } else { - pkt_len = count + trailer_len; - } - - /* set count */ - buf[pkt_len - 2] = count << 2; - buf[pkt_len - 1] = 0; - - /* compute fcs and insert into trailer */ - fcs = fcs_compute10(buf, pkt_len, CRC10_INITFCS); - buf[pkt_len - 2] |= fcs >> 8; - buf[pkt_len - 1] |= fcs & 0xff; - - return pkt_len; -} - -static int safe_startup(struct usb_serial *serial) -{ - switch (serial->interface->cur_altsetting->desc.bInterfaceProtocol) { - case LINEO_SAFESERIAL_CRC: - break; - case LINEO_SAFESERIAL_CRC_PADDED: - padded = 1; - break; - default: - return -EINVAL; - } - return 0; -} - -static struct usb_serial_driver safe_device = { - .driver = { - .owner = THIS_MODULE, - .name = "safe_serial", - }, - .id_table = id_table, - .num_ports = 1, - .process_read_urb = safe_process_read_urb, - .prepare_write_buffer = safe_prepare_write_buffer, - .attach = safe_startup, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &safe_device, NULL -}; - -static int __init safe_init(void) -{ - int i; - - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - - /* if we have vendor / product parameters patch them into id list */ - if (vendor || product) { - printk(KERN_INFO KBUILD_MODNAME ": vendor: %x product: %x\n", - vendor, product); - - for (i = 0; i < ARRAY_SIZE(id_table); i++) { - if (!id_table[i].idVendor && !id_table[i].idProduct) { - id_table[i].idVendor = vendor; - id_table[i].idProduct = product; - break; - } - } - } - - return usb_serial_register_drivers(&safe_driver, serial_drivers); -} - -static void __exit safe_exit(void) -{ - usb_serial_deregister_drivers(&safe_driver, serial_drivers); -} - -module_init(safe_init); -module_exit(safe_exit); diff --git a/ANDROID_3.4.5/drivers/usb/serial/siemens_mpi.c b/ANDROID_3.4.5/drivers/usb/serial/siemens_mpi.c deleted file mode 100644 index 46c0430f..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/siemens_mpi.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Siemens USB-MPI Serial USB driver - * - * Copyright (C) 2005 Thomas Hergenhahn - * Copyright (C) 2005,2008 Greg Kroah-Hartman - * - * 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. - */ - -#include -#include -#include -#include -#include -#include - -/* Version Information */ -#define DRIVER_VERSION "Version 0.1 09/26/2005" -#define DRIVER_AUTHOR "Thomas Hergenhahn@web.de http://libnodave.sf.net" -#define DRIVER_DESC "Driver for Siemens USB/MPI adapter" - - -static const struct usb_device_id id_table[] = { - /* Vendor and product id for 6ES7-972-0CB20-0XA0 */ - { USB_DEVICE(0x908, 0x0004) }, - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver siemens_usb_mpi_driver = { - .name = "siemens_mpi", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - -static struct usb_serial_driver siemens_usb_mpi_device = { - .driver = { - .owner = THIS_MODULE, - .name = "siemens_mpi", - }, - .id_table = id_table, - .num_ports = 1, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &siemens_usb_mpi_device, NULL -}; - -module_usb_serial_driver(siemens_usb_mpi_driver, serial_drivers); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/sierra.c b/ANDROID_3.4.5/drivers/usb/serial/sierra.c deleted file mode 100644 index 449bf6d3..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/sierra.c +++ /dev/null @@ -1,1136 +0,0 @@ -/* - USB Driver for Sierra Wireless - - Copyright (C) 2006, 2007, 2008 Kevin Lloyd , - - Copyright (C) 2008, 2009 Elina Pasheva, Matthew Safar, Rory Filer - - - IMPORTANT DISCLAIMER: This driver is not commercially supported by - Sierra Wireless. Use at your own risk. - - This driver is free software; you can redistribute it and/or modify - it under the terms of Version 2 of the GNU General Public License as - published by the Free Software Foundation. - - Portions based on the option driver by Matthias Urlichs - Whom based his on the Keyspan driver by Hugh Blemings -*/ -/* Uncomment to log function calls */ -/* #define DEBUG */ -#define DRIVER_VERSION "v.1.7.16" -#define DRIVER_AUTHOR "Kevin Lloyd, Elina Pasheva, Matthew Safar, Rory Filer" -#define DRIVER_DESC "USB Driver for Sierra Wireless USB modems" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SWIMS_USB_REQUEST_SetPower 0x00 -#define SWIMS_USB_REQUEST_SetNmea 0x07 - -#define N_IN_URB_HM 8 -#define N_OUT_URB_HM 64 -#define N_IN_URB 4 -#define N_OUT_URB 4 -#define IN_BUFLEN 4096 - -#define MAX_TRANSFER (PAGE_SIZE - 512) -/* MAX_TRANSFER is chosen so that the VM is not stressed by - allocations > PAGE_SIZE and the number of packets in a page - is an integer 512 is the largest possible packet on EHCI */ - -static bool debug; -static bool nmea; - -/* Used in interface blacklisting */ -struct sierra_iface_info { - const u32 infolen; /* number of interface numbers on blacklist */ - const u8 *ifaceinfo; /* pointer to the array holding the numbers */ -}; - -struct sierra_intf_private { - spinlock_t susp_lock; - unsigned int suspended:1; - int in_flight; -}; - -static int sierra_set_power_state(struct usb_device *udev, __u16 swiState) -{ - int result; - dev_dbg(&udev->dev, "%s\n", __func__); - result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - SWIMS_USB_REQUEST_SetPower, /* __u8 request */ - USB_TYPE_VENDOR, /* __u8 request type */ - swiState, /* __u16 value */ - 0, /* __u16 index */ - NULL, /* void *data */ - 0, /* __u16 size */ - USB_CTRL_SET_TIMEOUT); /* int timeout */ - return result; -} - -static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable) -{ - int result; - dev_dbg(&udev->dev, "%s\n", __func__); - result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - SWIMS_USB_REQUEST_SetNmea, /* __u8 request */ - USB_TYPE_VENDOR, /* __u8 request type */ - enable, /* __u16 value */ - 0x0000, /* __u16 index */ - NULL, /* void *data */ - 0, /* __u16 size */ - USB_CTRL_SET_TIMEOUT); /* int timeout */ - return result; -} - -static int sierra_calc_num_ports(struct usb_serial *serial) -{ - int num_ports = 0; - u8 ifnum, numendpoints; - - dev_dbg(&serial->dev->dev, "%s\n", __func__); - - ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber; - numendpoints = serial->interface->cur_altsetting->desc.bNumEndpoints; - - /* Dummy interface present on some SKUs should be ignored */ - if (ifnum == 0x99) - num_ports = 0; - else if (numendpoints <= 3) - num_ports = 1; - else - num_ports = (numendpoints-1)/2; - return num_ports; -} - -static int is_blacklisted(const u8 ifnum, - const struct sierra_iface_info *blacklist) -{ - const u8 *info; - int i; - - if (blacklist) { - info = blacklist->ifaceinfo; - - for (i = 0; i < blacklist->infolen; i++) { - if (info[i] == ifnum) - return 1; - } - } - return 0; -} - -static int is_himemory(const u8 ifnum, - const struct sierra_iface_info *himemorylist) -{ - const u8 *info; - int i; - - if (himemorylist) { - info = himemorylist->ifaceinfo; - - for (i=0; i < himemorylist->infolen; i++) { - if (info[i] == ifnum) - return 1; - } - } - return 0; -} - -static int sierra_calc_interface(struct usb_serial *serial) -{ - int interface; - struct usb_interface *p_interface; - struct usb_host_interface *p_host_interface; - dev_dbg(&serial->dev->dev, "%s\n", __func__); - - /* Get the interface structure pointer from the serial struct */ - p_interface = serial->interface; - - /* Get a pointer to the host interface structure */ - p_host_interface = p_interface->cur_altsetting; - - /* read the interface descriptor for this active altsetting - * to find out the interface number we are on - */ - interface = p_host_interface->desc.bInterfaceNumber; - - return interface; -} - -static int sierra_probe(struct usb_serial *serial, - const struct usb_device_id *id) -{ - int result = 0; - struct usb_device *udev; - struct sierra_intf_private *data; - u8 ifnum; - - udev = serial->dev; - dev_dbg(&udev->dev, "%s\n", __func__); - - ifnum = sierra_calc_interface(serial); - /* - * If this interface supports more than 1 alternate - * select the 2nd one - */ - if (serial->interface->num_altsetting == 2) { - dev_dbg(&udev->dev, "Selecting alt setting for interface %d\n", - ifnum); - /* We know the alternate setting is 1 for the MC8785 */ - usb_set_interface(udev, ifnum, 1); - } - - /* ifnum could have changed - by calling usb_set_interface */ - ifnum = sierra_calc_interface(serial); - - if (is_blacklisted(ifnum, - (struct sierra_iface_info *)id->driver_info)) { - dev_dbg(&serial->dev->dev, - "Ignoring blacklisted interface #%d\n", ifnum); - return -ENODEV; - } - - data = serial->private = kzalloc(sizeof(struct sierra_intf_private), GFP_KERNEL); - if (!data) - return -ENOMEM; - spin_lock_init(&data->susp_lock); - - return result; -} - -/* interfaces with higher memory requirements */ -static const u8 hi_memory_typeA_ifaces[] = { 0, 2 }; -static const struct sierra_iface_info typeA_interface_list = { - .infolen = ARRAY_SIZE(hi_memory_typeA_ifaces), - .ifaceinfo = hi_memory_typeA_ifaces, -}; - -static const u8 hi_memory_typeB_ifaces[] = { 3, 4, 5, 6 }; -static const struct sierra_iface_info typeB_interface_list = { - .infolen = ARRAY_SIZE(hi_memory_typeB_ifaces), - .ifaceinfo = hi_memory_typeB_ifaces, -}; - -/* 'blacklist' of interfaces not served by this driver */ -static const u8 direct_ip_non_serial_ifaces[] = { 7, 8, 9, 10, 11, 19, 20 }; -static const struct sierra_iface_info direct_ip_interface_blacklist = { - .infolen = ARRAY_SIZE(direct_ip_non_serial_ifaces), - .ifaceinfo = direct_ip_non_serial_ifaces, -}; - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(0x0F3D, 0x0112) }, /* Airprime/Sierra PC 5220 */ - { USB_DEVICE(0x03F0, 0x1B1D) }, /* HP ev2200 a.k.a MC5720 */ - { USB_DEVICE(0x03F0, 0x211D) }, /* HP ev2210 a.k.a MC5725 */ - { USB_DEVICE(0x03F0, 0x1E1D) }, /* HP hs2300 a.k.a MC8775 */ - - { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ - { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ - { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ - { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ - { USB_DEVICE(0x1199, 0x0220) }, /* Sierra Wireless MC5725 */ - { USB_DEVICE(0x1199, 0x0022) }, /* Sierra Wireless EM5725 */ - { USB_DEVICE(0x1199, 0x0024) }, /* Sierra Wireless MC5727 */ - { USB_DEVICE(0x1199, 0x0224) }, /* Sierra Wireless MC5727 */ - { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ - { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */ - { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */ - { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U */ - { USB_DEVICE(0x1199, 0x0301) }, /* Sierra Wireless USB Dongle 250U */ - /* Sierra Wireless C597 */ - { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x0023, 0xFF, 0xFF, 0xFF) }, - /* Sierra Wireless T598 */ - { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x0025, 0xFF, 0xFF, 0xFF) }, - { USB_DEVICE(0x1199, 0x0026) }, /* Sierra Wireless T11 */ - { USB_DEVICE(0x1199, 0x0027) }, /* Sierra Wireless AC402 */ - { USB_DEVICE(0x1199, 0x0028) }, /* Sierra Wireless MC5728 */ - { USB_DEVICE(0x1199, 0x0029) }, /* Sierra Wireless Device */ - - { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ - { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ - { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */ - { USB_DEVICE(0x1199, 0x6805) }, /* Sierra Wireless MC8765 */ - { USB_DEVICE(0x1199, 0x6808) }, /* Sierra Wireless MC8755 */ - { USB_DEVICE(0x1199, 0x6809) }, /* Sierra Wireless MC8765 */ - { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */ - { USB_DEVICE(0x1199, 0x6813) }, /* Sierra Wireless MC8775 */ - { USB_DEVICE(0x1199, 0x6815) }, /* Sierra Wireless MC8775 */ - { USB_DEVICE(0x1199, 0x6816) }, /* Sierra Wireless MC8775 */ - { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ - { USB_DEVICE(0x1199, 0x6821) }, /* Sierra Wireless AirCard 875U */ - { USB_DEVICE(0x1199, 0x6822) }, /* Sierra Wireless AirCard 875E */ - { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780 */ - { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781 */ - { USB_DEVICE(0x1199, 0x6834) }, /* Sierra Wireless MC8780 */ - { USB_DEVICE(0x1199, 0x6835) }, /* Sierra Wireless MC8781 */ - { USB_DEVICE(0x1199, 0x6838) }, /* Sierra Wireless MC8780 */ - { USB_DEVICE(0x1199, 0x6839) }, /* Sierra Wireless MC8781 */ - { USB_DEVICE(0x1199, 0x683A) }, /* Sierra Wireless MC8785 */ - { USB_DEVICE(0x1199, 0x683B) }, /* Sierra Wireless MC8785 Composite */ - /* Sierra Wireless MC8790, MC8791, MC8792 Composite */ - { USB_DEVICE(0x1199, 0x683C) }, - { USB_DEVICE(0x1199, 0x683D) }, /* Sierra Wireless MC8791 Composite */ - /* Sierra Wireless MC8790, MC8791, MC8792 */ - { USB_DEVICE(0x1199, 0x683E) }, - { USB_DEVICE(0x1199, 0x6850) }, /* Sierra Wireless AirCard 880 */ - { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */ - { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880 E */ - { USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881 E */ - { USB_DEVICE(0x1199, 0x6855) }, /* Sierra Wireless AirCard 880 U */ - { USB_DEVICE(0x1199, 0x6856) }, /* Sierra Wireless AirCard 881 U */ - { USB_DEVICE(0x1199, 0x6859) }, /* Sierra Wireless AirCard 885 E */ - { USB_DEVICE(0x1199, 0x685A) }, /* Sierra Wireless AirCard 885 E */ - /* Sierra Wireless C885 */ - { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6880, 0xFF, 0xFF, 0xFF)}, - /* Sierra Wireless C888, Air Card 501, USB 303, USB 304 */ - { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6890, 0xFF, 0xFF, 0xFF)}, - /* Sierra Wireless C22/C33 */ - { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6891, 0xFF, 0xFF, 0xFF)}, - /* Sierra Wireless HSPA Non-Composite Device */ - { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6892, 0xFF, 0xFF, 0xFF)}, - { USB_DEVICE(0x1199, 0x6893) }, /* Sierra Wireless Device */ - { USB_DEVICE(0x1199, 0x68A2), /* Sierra Wireless MC77xx in QMI mode */ - .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist - }, - { USB_DEVICE(0x1199, 0x68A3), /* Sierra Wireless Direct IP modems */ - .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist - }, - /* AT&T Direct IP LTE modems */ - { USB_DEVICE_AND_INTERFACE_INFO(0x0F3D, 0x68AA, 0xFF, 0xFF, 0xFF), - .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist - }, - { USB_DEVICE(0x0f3d, 0x68A3), /* Airprime/Sierra Wireless Direct IP modems */ - .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist - }, - { USB_DEVICE(0x413C, 0x08133) }, /* Dell Computer Corp. Wireless 5720 VZW Mobile Broadband (EVDO Rev-A) Minicard GPS Port */ - - { } -}; -MODULE_DEVICE_TABLE(usb, id_table); - - -struct sierra_port_private { - spinlock_t lock; /* lock the structure */ - int outstanding_urbs; /* number of out urbs in flight */ - struct usb_anchor active; - struct usb_anchor delayed; - - int num_out_urbs; - int num_in_urbs; - /* Input endpoints and buffers for this port */ - struct urb *in_urbs[N_IN_URB_HM]; - - /* Settings for the port */ - int rts_state; /* Handshaking pins (outputs) */ - int dtr_state; - int cts_state; /* Handshaking pins (inputs) */ - int dsr_state; - int dcd_state; - int ri_state; - unsigned int opened:1; -}; - -static int sierra_send_setup(struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - struct sierra_port_private *portdata; - __u16 interface = 0; - int val = 0; - int do_send = 0; - int retval; - - dev_dbg(&port->dev, "%s\n", __func__); - - portdata = usb_get_serial_port_data(port); - - if (portdata->dtr_state) - val |= 0x01; - if (portdata->rts_state) - val |= 0x02; - - /* If composite device then properly report interface */ - if (serial->num_ports == 1) { - interface = sierra_calc_interface(serial); - /* Control message is sent only to interfaces with - * interrupt_in endpoints - */ - if (port->interrupt_in_urb) { - /* send control message */ - do_send = 1; - } - } - - /* Otherwise the need to do non-composite mapping */ - else { - if (port->bulk_out_endpointAddress == 2) - interface = 0; - else if (port->bulk_out_endpointAddress == 4) - interface = 1; - else if (port->bulk_out_endpointAddress == 5) - interface = 2; - - do_send = 1; - } - if (!do_send) - return 0; - - retval = usb_autopm_get_interface(serial->interface); - if (retval < 0) - return retval; - - retval = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - 0x22, 0x21, val, interface, NULL, 0, USB_CTRL_SET_TIMEOUT); - usb_autopm_put_interface(serial->interface); - - return retval; -} - -static void sierra_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) -{ - dev_dbg(&port->dev, "%s\n", __func__); - tty_termios_copy_hw(tty->termios, old_termios); - sierra_send_setup(port); -} - -static int sierra_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - unsigned int value; - struct sierra_port_private *portdata; - - dev_dbg(&port->dev, "%s\n", __func__); - portdata = usb_get_serial_port_data(port); - - value = ((portdata->rts_state) ? TIOCM_RTS : 0) | - ((portdata->dtr_state) ? TIOCM_DTR : 0) | - ((portdata->cts_state) ? TIOCM_CTS : 0) | - ((portdata->dsr_state) ? TIOCM_DSR : 0) | - ((portdata->dcd_state) ? TIOCM_CAR : 0) | - ((portdata->ri_state) ? TIOCM_RNG : 0); - - return value; -} - -static int sierra_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct sierra_port_private *portdata; - - portdata = usb_get_serial_port_data(port); - - if (set & TIOCM_RTS) - portdata->rts_state = 1; - if (set & TIOCM_DTR) - portdata->dtr_state = 1; - - if (clear & TIOCM_RTS) - portdata->rts_state = 0; - if (clear & TIOCM_DTR) - portdata->dtr_state = 0; - return sierra_send_setup(port); -} - -static void sierra_release_urb(struct urb *urb) -{ - struct usb_serial_port *port; - if (urb) { - port = urb->context; - dev_dbg(&port->dev, "%s: %p\n", __func__, urb); - kfree(urb->transfer_buffer); - usb_free_urb(urb); - } -} - -static void sierra_outdat_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct sierra_port_private *portdata = usb_get_serial_port_data(port); - struct sierra_intf_private *intfdata; - int status = urb->status; - - dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number); - intfdata = port->serial->private; - - /* free up the transfer buffer, as usb_free_urb() does not do this */ - kfree(urb->transfer_buffer); - usb_autopm_put_interface_async(port->serial->interface); - if (status) - dev_dbg(&port->dev, "%s - nonzero write bulk status " - "received: %d\n", __func__, status); - - spin_lock(&portdata->lock); - --portdata->outstanding_urbs; - spin_unlock(&portdata->lock); - spin_lock(&intfdata->susp_lock); - --intfdata->in_flight; - spin_unlock(&intfdata->susp_lock); - - usb_serial_port_softint(port); -} - -/* Write */ -static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - struct sierra_port_private *portdata; - struct sierra_intf_private *intfdata; - struct usb_serial *serial = port->serial; - unsigned long flags; - unsigned char *buffer; - struct urb *urb; - size_t writesize = min((size_t)count, (size_t)MAX_TRANSFER); - int retval = 0; - - /* verify that we actually have some data to write */ - if (count == 0) - return 0; - - portdata = usb_get_serial_port_data(port); - intfdata = serial->private; - - dev_dbg(&port->dev, "%s: write (%zd bytes)\n", __func__, writesize); - spin_lock_irqsave(&portdata->lock, flags); - dev_dbg(&port->dev, "%s - outstanding_urbs: %d\n", __func__, - portdata->outstanding_urbs); - if (portdata->outstanding_urbs > portdata->num_out_urbs) { - spin_unlock_irqrestore(&portdata->lock, flags); - dev_dbg(&port->dev, "%s - write limit hit\n", __func__); - return 0; - } - portdata->outstanding_urbs++; - dev_dbg(&port->dev, "%s - 1, outstanding_urbs: %d\n", __func__, - portdata->outstanding_urbs); - spin_unlock_irqrestore(&portdata->lock, flags); - - retval = usb_autopm_get_interface_async(serial->interface); - if (retval < 0) { - spin_lock_irqsave(&portdata->lock, flags); - portdata->outstanding_urbs--; - spin_unlock_irqrestore(&portdata->lock, flags); - goto error_simple; - } - - buffer = kmalloc(writesize, GFP_ATOMIC); - if (!buffer) { - dev_err(&port->dev, "out of memory\n"); - retval = -ENOMEM; - goto error_no_buffer; - } - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - dev_err(&port->dev, "no more free urbs\n"); - retval = -ENOMEM; - goto error_no_urb; - } - - memcpy(buffer, buf, writesize); - - usb_serial_debug_data(debug, &port->dev, __func__, writesize, buffer); - - usb_fill_bulk_urb(urb, serial->dev, - usb_sndbulkpipe(serial->dev, - port->bulk_out_endpointAddress), - buffer, writesize, sierra_outdat_callback, port); - - /* Handle the need to send a zero length packet */ - urb->transfer_flags |= URB_ZERO_PACKET; - - spin_lock_irqsave(&intfdata->susp_lock, flags); - - if (intfdata->suspended) { - usb_anchor_urb(urb, &portdata->delayed); - spin_unlock_irqrestore(&intfdata->susp_lock, flags); - goto skip_power; - } else { - usb_anchor_urb(urb, &portdata->active); - } - /* send it down the pipe */ - retval = usb_submit_urb(urb, GFP_ATOMIC); - if (retval) { - usb_unanchor_urb(urb); - spin_unlock_irqrestore(&intfdata->susp_lock, flags); - dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed " - "with status = %d\n", __func__, retval); - goto error; - } else { - intfdata->in_flight++; - spin_unlock_irqrestore(&intfdata->susp_lock, flags); - } - -skip_power: - /* we are done with this urb, so let the host driver - * really free it when it is finished with it */ - usb_free_urb(urb); - - return writesize; -error: - usb_free_urb(urb); -error_no_urb: - kfree(buffer); -error_no_buffer: - spin_lock_irqsave(&portdata->lock, flags); - --portdata->outstanding_urbs; - dev_dbg(&port->dev, "%s - 2. outstanding_urbs: %d\n", __func__, - portdata->outstanding_urbs); - spin_unlock_irqrestore(&portdata->lock, flags); - usb_autopm_put_interface_async(serial->interface); -error_simple: - return retval; -} - -static void sierra_indat_callback(struct urb *urb) -{ - int err; - int endpoint; - struct usb_serial_port *port; - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - int status = urb->status; - - endpoint = usb_pipeendpoint(urb->pipe); - port = urb->context; - - dev_dbg(&port->dev, "%s: %p\n", __func__, urb); - - if (status) { - dev_dbg(&port->dev, "%s: nonzero status: %d on" - " endpoint %02x\n", __func__, status, endpoint); - } else { - if (urb->actual_length) { - tty = tty_port_tty_get(&port->port); - if (tty) { - tty_insert_flip_string(tty, data, - urb->actual_length); - tty_flip_buffer_push(tty); - - tty_kref_put(tty); - usb_serial_debug_data(debug, &port->dev, - __func__, urb->actual_length, data); - } - } else { - dev_dbg(&port->dev, "%s: empty read urb" - " received\n", __func__); - } - } - - /* Resubmit urb so we continue receiving */ - if (status != -ESHUTDOWN && status != -EPERM) { - usb_mark_last_busy(port->serial->dev); - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err && err != -EPERM) - dev_err(&port->dev, "resubmit read urb failed." - "(%d)\n", err); - } -} - -static void sierra_instat_callback(struct urb *urb) -{ - int err; - int status = urb->status; - struct usb_serial_port *port = urb->context; - struct sierra_port_private *portdata = usb_get_serial_port_data(port); - struct usb_serial *serial = port->serial; - - dev_dbg(&port->dev, "%s: urb %p port %p has data %p\n", __func__, - urb, port, portdata); - - if (status == 0) { - struct usb_ctrlrequest *req_pkt = - (struct usb_ctrlrequest *)urb->transfer_buffer; - - if (!req_pkt) { - dev_dbg(&port->dev, "%s: NULL req_pkt\n", - __func__); - return; - } - if ((req_pkt->bRequestType == 0xA1) && - (req_pkt->bRequest == 0x20)) { - int old_dcd_state; - unsigned char signals = *((unsigned char *) - urb->transfer_buffer + - sizeof(struct usb_ctrlrequest)); - struct tty_struct *tty; - - dev_dbg(&port->dev, "%s: signal x%x\n", __func__, - signals); - - old_dcd_state = portdata->dcd_state; - portdata->cts_state = 1; - portdata->dcd_state = ((signals & 0x01) ? 1 : 0); - portdata->dsr_state = ((signals & 0x02) ? 1 : 0); - portdata->ri_state = ((signals & 0x08) ? 1 : 0); - - tty = tty_port_tty_get(&port->port); - if (tty && !C_CLOCAL(tty) && - old_dcd_state && !portdata->dcd_state) - tty_hangup(tty); - tty_kref_put(tty); - } else { - dev_dbg(&port->dev, "%s: type %x req %x\n", - __func__, req_pkt->bRequestType, - req_pkt->bRequest); - } - } else - dev_dbg(&port->dev, "%s: error %d\n", __func__, status); - - /* Resubmit urb so we continue receiving IRQ data */ - if (status != -ESHUTDOWN && status != -ENOENT) { - usb_mark_last_busy(serial->dev); - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err && err != -EPERM) - dev_err(&port->dev, "%s: resubmit intr urb " - "failed. (%d)\n", __func__, err); - } -} - -static int sierra_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct sierra_port_private *portdata = usb_get_serial_port_data(port); - unsigned long flags; - - dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number); - - /* try to give a good number back based on if we have any free urbs at - * this point in time */ - spin_lock_irqsave(&portdata->lock, flags); - if (portdata->outstanding_urbs > (portdata->num_out_urbs * 2) / 3) { - spin_unlock_irqrestore(&portdata->lock, flags); - dev_dbg(&port->dev, "%s - write limit hit\n", __func__); - return 0; - } - spin_unlock_irqrestore(&portdata->lock, flags); - - return 2048; -} - -static void sierra_stop_rx_urbs(struct usb_serial_port *port) -{ - int i; - struct sierra_port_private *portdata = usb_get_serial_port_data(port); - - for (i = 0; i < portdata->num_in_urbs; i++) - usb_kill_urb(portdata->in_urbs[i]); - - usb_kill_urb(port->interrupt_in_urb); -} - -static int sierra_submit_rx_urbs(struct usb_serial_port *port, gfp_t mem_flags) -{ - int ok_cnt; - int err = -EINVAL; - int i; - struct urb *urb; - struct sierra_port_private *portdata = usb_get_serial_port_data(port); - - ok_cnt = 0; - for (i = 0; i < portdata->num_in_urbs; i++) { - urb = portdata->in_urbs[i]; - if (!urb) - continue; - err = usb_submit_urb(urb, mem_flags); - if (err) { - dev_err(&port->dev, "%s: submit urb failed: %d\n", - __func__, err); - } else { - ok_cnt++; - } - } - - if (ok_cnt && port->interrupt_in_urb) { - err = usb_submit_urb(port->interrupt_in_urb, mem_flags); - if (err) { - dev_err(&port->dev, "%s: submit intr urb failed: %d\n", - __func__, err); - } - } - - if (ok_cnt > 0) /* at least one rx urb submitted */ - return 0; - else - return err; -} - -static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint, - int dir, void *ctx, int len, - gfp_t mem_flags, - usb_complete_t callback) -{ - struct urb *urb; - u8 *buf; - - if (endpoint == -1) - return NULL; - - urb = usb_alloc_urb(0, mem_flags); - if (urb == NULL) { - dev_dbg(&serial->dev->dev, "%s: alloc for endpoint %d failed\n", - __func__, endpoint); - return NULL; - } - - buf = kmalloc(len, mem_flags); - if (buf) { - /* Fill URB using supplied data */ - usb_fill_bulk_urb(urb, serial->dev, - usb_sndbulkpipe(serial->dev, endpoint) | dir, - buf, len, callback, ctx); - - /* debug */ - dev_dbg(&serial->dev->dev, "%s %c u : %p d:%p\n", __func__, - dir == USB_DIR_IN ? 'i' : 'o', urb, buf); - } else { - dev_dbg(&serial->dev->dev, "%s %c u:%p d:%p\n", __func__, - dir == USB_DIR_IN ? 'i' : 'o', urb, buf); - - sierra_release_urb(urb); - urb = NULL; - } - - return urb; -} - -static void sierra_close(struct usb_serial_port *port) -{ - int i; - struct usb_serial *serial = port->serial; - struct sierra_port_private *portdata; - struct sierra_intf_private *intfdata = port->serial->private; - - - dev_dbg(&port->dev, "%s\n", __func__); - portdata = usb_get_serial_port_data(port); - - portdata->rts_state = 0; - portdata->dtr_state = 0; - - if (serial->dev) { - mutex_lock(&serial->disc_mutex); - if (!serial->disconnected) { - serial->interface->needs_remote_wakeup = 0; - /* odd error handling due to pm counters */ - if (!usb_autopm_get_interface(serial->interface)) - sierra_send_setup(port); - else - usb_autopm_get_interface_no_resume(serial->interface); - - } - mutex_unlock(&serial->disc_mutex); - spin_lock_irq(&intfdata->susp_lock); - portdata->opened = 0; - spin_unlock_irq(&intfdata->susp_lock); - - - /* Stop reading urbs */ - sierra_stop_rx_urbs(port); - /* .. and release them */ - for (i = 0; i < portdata->num_in_urbs; i++) { - sierra_release_urb(portdata->in_urbs[i]); - portdata->in_urbs[i] = NULL; - } - } -} - -static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct sierra_port_private *portdata; - struct usb_serial *serial = port->serial; - struct sierra_intf_private *intfdata = serial->private; - int i; - int err; - int endpoint; - struct urb *urb; - - portdata = usb_get_serial_port_data(port); - - dev_dbg(&port->dev, "%s\n", __func__); - - /* Set some sane defaults */ - portdata->rts_state = 1; - portdata->dtr_state = 1; - - - endpoint = port->bulk_in_endpointAddress; - for (i = 0; i < portdata->num_in_urbs; i++) { - urb = sierra_setup_urb(serial, endpoint, USB_DIR_IN, port, - IN_BUFLEN, GFP_KERNEL, - sierra_indat_callback); - portdata->in_urbs[i] = urb; - } - /* clear halt condition */ - usb_clear_halt(serial->dev, - usb_sndbulkpipe(serial->dev, endpoint) | USB_DIR_IN); - - err = sierra_submit_rx_urbs(port, GFP_KERNEL); - if (err) { - /* get rid of everything as in close */ - sierra_close(port); - /* restore balance for autopm */ - if (!serial->disconnected) - usb_autopm_put_interface(serial->interface); - return err; - } - sierra_send_setup(port); - - serial->interface->needs_remote_wakeup = 1; - spin_lock_irq(&intfdata->susp_lock); - portdata->opened = 1; - spin_unlock_irq(&intfdata->susp_lock); - usb_autopm_put_interface(serial->interface); - - return 0; -} - - -static void sierra_dtr_rts(struct usb_serial_port *port, int on) -{ - struct usb_serial *serial = port->serial; - struct sierra_port_private *portdata; - - portdata = usb_get_serial_port_data(port); - portdata->rts_state = on; - portdata->dtr_state = on; - - if (serial->dev) { - mutex_lock(&serial->disc_mutex); - if (!serial->disconnected) - sierra_send_setup(port); - mutex_unlock(&serial->disc_mutex); - } -} - -static int sierra_startup(struct usb_serial *serial) -{ - struct usb_serial_port *port; - struct sierra_port_private *portdata; - struct sierra_iface_info *himemoryp = NULL; - int i; - u8 ifnum; - - dev_dbg(&serial->dev->dev, "%s\n", __func__); - - /* Set Device mode to D0 */ - sierra_set_power_state(serial->dev, 0x0000); - - /* Check NMEA and set */ - if (nmea) - sierra_vsc_set_nmea(serial->dev, 1); - - /* Now setup per port private data */ - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); - if (!portdata) { - dev_dbg(&port->dev, "%s: kmalloc for " - "sierra_port_private (%d) failed!\n", - __func__, i); - return -ENOMEM; - } - spin_lock_init(&portdata->lock); - init_usb_anchor(&portdata->active); - init_usb_anchor(&portdata->delayed); - ifnum = i; - /* Assume low memory requirements */ - portdata->num_out_urbs = N_OUT_URB; - portdata->num_in_urbs = N_IN_URB; - - /* Determine actual memory requirements */ - if (serial->num_ports == 1) { - /* Get interface number for composite device */ - ifnum = sierra_calc_interface(serial); - himemoryp = - (struct sierra_iface_info *)&typeB_interface_list; - if (is_himemory(ifnum, himemoryp)) { - portdata->num_out_urbs = N_OUT_URB_HM; - portdata->num_in_urbs = N_IN_URB_HM; - } - } - else { - himemoryp = - (struct sierra_iface_info *)&typeA_interface_list; - if (is_himemory(i, himemoryp)) { - portdata->num_out_urbs = N_OUT_URB_HM; - portdata->num_in_urbs = N_IN_URB_HM; - } - } - dev_dbg(&serial->dev->dev, - "Memory usage (urbs) interface #%d, in=%d, out=%d\n", - ifnum,portdata->num_in_urbs, portdata->num_out_urbs ); - /* Set the port private data pointer */ - usb_set_serial_port_data(port, portdata); - } - - return 0; -} - -static void sierra_release(struct usb_serial *serial) -{ - int i; - struct usb_serial_port *port; - struct sierra_port_private *portdata; - - dev_dbg(&serial->dev->dev, "%s\n", __func__); - - for (i = 0; i < serial->num_ports; ++i) { - port = serial->port[i]; - if (!port) - continue; - portdata = usb_get_serial_port_data(port); - if (!portdata) - continue; - kfree(portdata); - } -} - -#ifdef CONFIG_PM -static void stop_read_write_urbs(struct usb_serial *serial) -{ - int i; - struct usb_serial_port *port; - struct sierra_port_private *portdata; - - /* Stop reading/writing urbs */ - for (i = 0; i < serial->num_ports; ++i) { - port = serial->port[i]; - portdata = usb_get_serial_port_data(port); - sierra_stop_rx_urbs(port); - usb_kill_anchored_urbs(&portdata->active); - } -} - -static int sierra_suspend(struct usb_serial *serial, pm_message_t message) -{ - struct sierra_intf_private *intfdata; - int b; - - if (PMSG_IS_AUTO(message)) { - intfdata = serial->private; - spin_lock_irq(&intfdata->susp_lock); - b = intfdata->in_flight; - - if (b) { - spin_unlock_irq(&intfdata->susp_lock); - return -EBUSY; - } else { - intfdata->suspended = 1; - spin_unlock_irq(&intfdata->susp_lock); - } - } - stop_read_write_urbs(serial); - - return 0; -} - -static int sierra_resume(struct usb_serial *serial) -{ - struct usb_serial_port *port; - struct sierra_intf_private *intfdata = serial->private; - struct sierra_port_private *portdata; - struct urb *urb; - int ec = 0; - int i, err; - - spin_lock_irq(&intfdata->susp_lock); - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - portdata = usb_get_serial_port_data(port); - - while ((urb = usb_get_from_anchor(&portdata->delayed))) { - usb_anchor_urb(urb, &portdata->active); - intfdata->in_flight++; - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err < 0) { - intfdata->in_flight--; - usb_unanchor_urb(urb); - usb_scuttle_anchored_urbs(&portdata->delayed); - break; - } - } - - if (portdata->opened) { - err = sierra_submit_rx_urbs(port, GFP_ATOMIC); - if (err) - ec++; - } - } - intfdata->suspended = 0; - spin_unlock_irq(&intfdata->susp_lock); - - return ec ? -EIO : 0; -} - -static int sierra_reset_resume(struct usb_interface *intf) -{ - struct usb_serial *serial = usb_get_intfdata(intf); - dev_err(&serial->dev->dev, "%s\n", __func__); - return usb_serial_resume(intf); -} -#else -#define sierra_suspend NULL -#define sierra_resume NULL -#define sierra_reset_resume NULL -#endif - -static struct usb_driver sierra_driver = { - .name = "sierra", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .reset_resume = sierra_reset_resume, - .id_table = id_table, - .supports_autosuspend = 1, -}; - -static struct usb_serial_driver sierra_device = { - .driver = { - .owner = THIS_MODULE, - .name = "sierra", - }, - .description = "Sierra USB modem", - .id_table = id_table, - .calc_num_ports = sierra_calc_num_ports, - .probe = sierra_probe, - .open = sierra_open, - .close = sierra_close, - .dtr_rts = sierra_dtr_rts, - .write = sierra_write, - .write_room = sierra_write_room, - .set_termios = sierra_set_termios, - .tiocmget = sierra_tiocmget, - .tiocmset = sierra_tiocmset, - .attach = sierra_startup, - .release = sierra_release, - .suspend = sierra_suspend, - .resume = sierra_resume, - .read_int_callback = sierra_instat_callback, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &sierra_device, NULL -}; - -module_usb_serial_driver(sierra_driver, serial_drivers); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); - -module_param(nmea, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(nmea, "NMEA streaming"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug messages"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/spcp8x5.c b/ANDROID_3.4.5/drivers/usb/serial/spcp8x5.c deleted file mode 100644 index f06c9a8f..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/spcp8x5.c +++ /dev/null @@ -1,676 +0,0 @@ -/* - * spcp8x5 USB to serial adaptor driver - * - * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com) - * Copyright (C) 2006 Linxb (xubin.lin@worldplus.com.cn) - * Copyright (C) 2006 S1 Corp. - * - * Original driver for 2.6.10 pl2303 driver by - * Greg Kroah-Hartman (greg@kroah.com) - * Changes for 2.6.20 by Harald Klein - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* Version Information */ -#define DRIVER_VERSION "v0.10" -#define DRIVER_DESC "SPCP8x5 USB to serial adaptor driver" - -static bool debug; - -#define SPCP8x5_007_VID 0x04FC -#define SPCP8x5_007_PID 0x0201 -#define SPCP8x5_008_VID 0x04fc -#define SPCP8x5_008_PID 0x0235 -#define SPCP8x5_PHILIPS_VID 0x0471 -#define SPCP8x5_PHILIPS_PID 0x081e -#define SPCP8x5_INTERMATIC_VID 0x04FC -#define SPCP8x5_INTERMATIC_PID 0x0204 -#define SPCP8x5_835_VID 0x04fc -#define SPCP8x5_835_PID 0x0231 - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(SPCP8x5_PHILIPS_VID , SPCP8x5_PHILIPS_PID)}, - { USB_DEVICE(SPCP8x5_INTERMATIC_VID, SPCP8x5_INTERMATIC_PID)}, - { USB_DEVICE(SPCP8x5_835_VID, SPCP8x5_835_PID)}, - { USB_DEVICE(SPCP8x5_008_VID, SPCP8x5_008_PID)}, - { USB_DEVICE(SPCP8x5_007_VID, SPCP8x5_007_PID)}, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, id_table); - -struct spcp8x5_usb_ctrl_arg { - u8 type; - u8 cmd; - u8 cmd_type; - u16 value; - u16 index; - u16 length; -}; - - -/* spcp8x5 spec register define */ -#define MCR_CONTROL_LINE_RTS 0x02 -#define MCR_CONTROL_LINE_DTR 0x01 -#define MCR_DTR 0x01 -#define MCR_RTS 0x02 - -#define MSR_STATUS_LINE_DCD 0x80 -#define MSR_STATUS_LINE_RI 0x40 -#define MSR_STATUS_LINE_DSR 0x20 -#define MSR_STATUS_LINE_CTS 0x10 - -/* verdor command here , we should define myself */ -#define SET_DEFAULT 0x40 -#define SET_DEFAULT_TYPE 0x20 - -#define SET_UART_FORMAT 0x40 -#define SET_UART_FORMAT_TYPE 0x21 -#define SET_UART_FORMAT_SIZE_5 0x00 -#define SET_UART_FORMAT_SIZE_6 0x01 -#define SET_UART_FORMAT_SIZE_7 0x02 -#define SET_UART_FORMAT_SIZE_8 0x03 -#define SET_UART_FORMAT_STOP_1 0x00 -#define SET_UART_FORMAT_STOP_2 0x04 -#define SET_UART_FORMAT_PAR_NONE 0x00 -#define SET_UART_FORMAT_PAR_ODD 0x10 -#define SET_UART_FORMAT_PAR_EVEN 0x30 -#define SET_UART_FORMAT_PAR_MASK 0xD0 -#define SET_UART_FORMAT_PAR_SPACE 0x90 - -#define GET_UART_STATUS_TYPE 0xc0 -#define GET_UART_STATUS 0x22 -#define GET_UART_STATUS_MSR 0x06 - -#define SET_UART_STATUS 0x40 -#define SET_UART_STATUS_TYPE 0x23 -#define SET_UART_STATUS_MCR 0x0004 -#define SET_UART_STATUS_MCR_DTR 0x01 -#define SET_UART_STATUS_MCR_RTS 0x02 -#define SET_UART_STATUS_MCR_LOOP 0x10 - -#define SET_WORKING_MODE 0x40 -#define SET_WORKING_MODE_TYPE 0x24 -#define SET_WORKING_MODE_U2C 0x00 -#define SET_WORKING_MODE_RS485 0x01 -#define SET_WORKING_MODE_PDMA 0x02 -#define SET_WORKING_MODE_SPP 0x03 - -#define SET_FLOWCTL_CHAR 0x40 -#define SET_FLOWCTL_CHAR_TYPE 0x25 - -#define GET_VERSION 0xc0 -#define GET_VERSION_TYPE 0x26 - -#define SET_REGISTER 0x40 -#define SET_REGISTER_TYPE 0x27 - -#define GET_REGISTER 0xc0 -#define GET_REGISTER_TYPE 0x28 - -#define SET_RAM 0x40 -#define SET_RAM_TYPE 0x31 - -#define GET_RAM 0xc0 -#define GET_RAM_TYPE 0x32 - -/* how come ??? */ -#define UART_STATE 0x08 -#define UART_STATE_TRANSIENT_MASK 0x75 -#define UART_DCD 0x01 -#define UART_DSR 0x02 -#define UART_BREAK_ERROR 0x04 -#define UART_RING 0x08 -#define UART_FRAME_ERROR 0x10 -#define UART_PARITY_ERROR 0x20 -#define UART_OVERRUN_ERROR 0x40 -#define UART_CTS 0x80 - -enum spcp8x5_type { - SPCP825_007_TYPE, - SPCP825_008_TYPE, - SPCP825_PHILIP_TYPE, - SPCP825_INTERMATIC_TYPE, - SPCP835_TYPE, -}; - -static struct usb_driver spcp8x5_driver = { - .name = "spcp8x5", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - - -struct spcp8x5_private { - spinlock_t lock; - enum spcp8x5_type type; - wait_queue_head_t delta_msr_wait; - u8 line_control; - u8 line_status; -}; - -/* desc : when device plug in,this function would be called. - * thanks to usb_serial subsystem,then do almost every things for us. And what - * we should do just alloc the buffer */ -static int spcp8x5_startup(struct usb_serial *serial) -{ - struct spcp8x5_private *priv; - int i; - enum spcp8x5_type type = SPCP825_007_TYPE; - u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); - - if (product == 0x0201) - type = SPCP825_007_TYPE; - else if (product == 0x0231) - type = SPCP835_TYPE; - else if (product == 0x0235) - type = SPCP825_008_TYPE; - else if (product == 0x0204) - type = SPCP825_INTERMATIC_TYPE; - else if (product == 0x0471 && - serial->dev->descriptor.idVendor == cpu_to_le16(0x081e)) - type = SPCP825_PHILIP_TYPE; - dev_dbg(&serial->dev->dev, "device type = %d\n", (int)type); - - for (i = 0; i < serial->num_ports; ++i) { - priv = kzalloc(sizeof(struct spcp8x5_private), GFP_KERNEL); - if (!priv) - goto cleanup; - - spin_lock_init(&priv->lock); - init_waitqueue_head(&priv->delta_msr_wait); - priv->type = type; - usb_set_serial_port_data(serial->port[i] , priv); - } - - return 0; -cleanup: - for (--i; i >= 0; --i) { - priv = usb_get_serial_port_data(serial->port[i]); - kfree(priv); - usb_set_serial_port_data(serial->port[i] , NULL); - } - return -ENOMEM; -} - -/* call when the device plug out. free all the memory alloced by probe */ -static void spcp8x5_release(struct usb_serial *serial) -{ - int i; - - for (i = 0; i < serial->num_ports; i++) - kfree(usb_get_serial_port_data(serial->port[i])); -} - -/* set the modem control line of the device. - * NOTE spcp825-007 not supported this */ -static int spcp8x5_set_ctrlLine(struct usb_device *dev, u8 value, - enum spcp8x5_type type) -{ - int retval; - u8 mcr = 0 ; - - if (type == SPCP825_007_TYPE) - return -EPERM; - - mcr = (unsigned short)value; - retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - SET_UART_STATUS_TYPE, SET_UART_STATUS, - mcr, 0x04, NULL, 0, 100); - if (retval != 0) - dev_dbg(&dev->dev, "usb_control_msg return %#x\n", retval); - return retval; -} - -/* get the modem status register of the device - * NOTE spcp825-007 not supported this */ -static int spcp8x5_get_msr(struct usb_device *dev, u8 *status, - enum spcp8x5_type type) -{ - u8 *status_buffer; - int ret; - - /* I return Permited not support here but seem inval device - * is more fix */ - if (type == SPCP825_007_TYPE) - return -EPERM; - if (status == NULL) - return -EINVAL; - - status_buffer = kmalloc(1, GFP_KERNEL); - if (!status_buffer) - return -ENOMEM; - status_buffer[0] = status[0]; - - ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - GET_UART_STATUS, GET_UART_STATUS_TYPE, - 0, GET_UART_STATUS_MSR, status_buffer, 1, 100); - if (ret < 0) - dev_dbg(&dev->dev, "Get MSR = 0x%p failed (error = %d)", - status_buffer, ret); - - dev_dbg(&dev->dev, "0xc0:0x22:0:6 %d - 0x%p ", ret, status_buffer); - status[0] = status_buffer[0]; - kfree(status_buffer); - - return ret; -} - -/* select the work mode. - * NOTE this function not supported by spcp825-007 */ -static void spcp8x5_set_workMode(struct usb_device *dev, u16 value, - u16 index, enum spcp8x5_type type) -{ - int ret; - - /* I return Permited not support here but seem inval device - * is more fix */ - if (type == SPCP825_007_TYPE) - return; - - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - SET_WORKING_MODE_TYPE, SET_WORKING_MODE, - value, index, NULL, 0, 100); - dev_dbg(&dev->dev, "value = %#x , index = %#x\n", value, index); - if (ret < 0) - dev_dbg(&dev->dev, - "RTSCTS usb_control_msg(enable flowctrl) = %d\n", ret); -} - -static int spcp8x5_carrier_raised(struct usb_serial_port *port) -{ - struct spcp8x5_private *priv = usb_get_serial_port_data(port); - if (priv->line_status & MSR_STATUS_LINE_DCD) - return 1; - return 0; -} - -static void spcp8x5_dtr_rts(struct usb_serial_port *port, int on) -{ - struct spcp8x5_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - u8 control; - - spin_lock_irqsave(&priv->lock, flags); - if (on) - priv->line_control = MCR_CONTROL_LINE_DTR - | MCR_CONTROL_LINE_RTS; - else - priv->line_control &= ~ (MCR_CONTROL_LINE_DTR - | MCR_CONTROL_LINE_RTS); - control = priv->line_control; - spin_unlock_irqrestore(&priv->lock, flags); - spcp8x5_set_ctrlLine(port->serial->dev, control , priv->type); -} - -static void spcp8x5_init_termios(struct tty_struct *tty) -{ - /* for the 1st time call this function */ - *(tty->termios) = tty_std_termios; - tty->termios->c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; - tty->termios->c_ispeed = 115200; - tty->termios->c_ospeed = 115200; -} - -/* set the serial param for transfer. we should check if we really need to - * transfer. if we set flow control we should do this too. */ -static void spcp8x5_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) -{ - struct usb_serial *serial = port->serial; - struct spcp8x5_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - unsigned int cflag = tty->termios->c_cflag; - unsigned int old_cflag = old_termios->c_cflag; - unsigned short uartdata; - unsigned char buf[2] = {0, 0}; - int baud; - int i; - u8 control; - - - /* check that they really want us to change something */ - if (!tty_termios_hw_change(tty->termios, old_termios)) - return; - - /* set DTR/RTS active */ - spin_lock_irqsave(&priv->lock, flags); - control = priv->line_control; - if ((old_cflag & CBAUD) == B0) { - priv->line_control |= MCR_DTR; - if (!(old_cflag & CRTSCTS)) - priv->line_control |= MCR_RTS; - } - if (control != priv->line_control) { - control = priv->line_control; - spin_unlock_irqrestore(&priv->lock, flags); - spcp8x5_set_ctrlLine(serial->dev, control , priv->type); - } else { - spin_unlock_irqrestore(&priv->lock, flags); - } - - /* Set Baud Rate */ - baud = tty_get_baud_rate(tty); - switch (baud) { - case 300: buf[0] = 0x00; break; - case 600: buf[0] = 0x01; break; - case 1200: buf[0] = 0x02; break; - case 2400: buf[0] = 0x03; break; - case 4800: buf[0] = 0x04; break; - case 9600: buf[0] = 0x05; break; - case 19200: buf[0] = 0x07; break; - case 38400: buf[0] = 0x09; break; - case 57600: buf[0] = 0x0a; break; - case 115200: buf[0] = 0x0b; break; - case 230400: buf[0] = 0x0c; break; - case 460800: buf[0] = 0x0d; break; - case 921600: buf[0] = 0x0e; break; -/* case 1200000: buf[0] = 0x0f; break; */ -/* case 2400000: buf[0] = 0x10; break; */ - case 3000000: buf[0] = 0x11; break; -/* case 6000000: buf[0] = 0x12; break; */ - case 0: - case 1000000: - buf[0] = 0x0b; break; - default: - dev_err(&port->dev, "spcp825 driver does not support the " - "baudrate requested, using default of 9600.\n"); - } - - /* Set Data Length : 00:5bit, 01:6bit, 10:7bit, 11:8bit */ - if (cflag & CSIZE) { - switch (cflag & CSIZE) { - case CS5: - buf[1] |= SET_UART_FORMAT_SIZE_5; - break; - case CS6: - buf[1] |= SET_UART_FORMAT_SIZE_6; - break; - case CS7: - buf[1] |= SET_UART_FORMAT_SIZE_7; - break; - default: - case CS8: - buf[1] |= SET_UART_FORMAT_SIZE_8; - break; - } - } - - /* Set Stop bit2 : 0:1bit 1:2bit */ - buf[1] |= (cflag & CSTOPB) ? SET_UART_FORMAT_STOP_2 : - SET_UART_FORMAT_STOP_1; - - /* Set Parity bit3-4 01:Odd 11:Even */ - if (cflag & PARENB) { - buf[1] |= (cflag & PARODD) ? - SET_UART_FORMAT_PAR_ODD : SET_UART_FORMAT_PAR_EVEN ; - } else - buf[1] |= SET_UART_FORMAT_PAR_NONE; - - uartdata = buf[0] | buf[1]<<8; - - i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - SET_UART_FORMAT_TYPE, SET_UART_FORMAT, - uartdata, 0, NULL, 0, 100); - if (i < 0) - dev_err(&port->dev, "Set UART format %#x failed (error = %d)\n", - uartdata, i); - dbg("0x21:0x40:0:0 %d", i); - - if (cflag & CRTSCTS) { - /* enable hardware flow control */ - spcp8x5_set_workMode(serial->dev, 0x000a, - SET_WORKING_MODE_U2C, priv->type); - } -} - -/* open the serial port. do some usb system call. set termios and get the line - * status of the device. */ -static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct ktermios tmp_termios; - struct usb_serial *serial = port->serial; - struct spcp8x5_private *priv = usb_get_serial_port_data(port); - int ret; - unsigned long flags; - u8 status = 0x30; - /* status 0x30 means DSR and CTS = 1 other CDC RI and delta = 0 */ - - dbg("%s - port %d", __func__, port->number); - - usb_clear_halt(serial->dev, port->write_urb->pipe); - usb_clear_halt(serial->dev, port->read_urb->pipe); - - ret = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - 0x09, 0x00, - 0x01, 0x00, NULL, 0x00, 100); - if (ret) - return ret; - - spcp8x5_set_ctrlLine(serial->dev, priv->line_control , priv->type); - - /* Setup termios */ - if (tty) - spcp8x5_set_termios(tty, port, &tmp_termios); - - spcp8x5_get_msr(serial->dev, &status, priv->type); - - /* may be we should update uart status here but now we did not do */ - spin_lock_irqsave(&priv->lock, flags); - priv->line_status = status & 0xf0 ; - spin_unlock_irqrestore(&priv->lock, flags); - - port->port.drain_delay = 256; - - return usb_serial_generic_open(tty, port); -} - -static void spcp8x5_process_read_urb(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct spcp8x5_private *priv = usb_get_serial_port_data(port); - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - unsigned long flags; - u8 status; - char tty_flag; - - /* get tty_flag from status */ - tty_flag = TTY_NORMAL; - - spin_lock_irqsave(&priv->lock, flags); - status = priv->line_status; - priv->line_status &= ~UART_STATE_TRANSIENT_MASK; - spin_unlock_irqrestore(&priv->lock, flags); - /* wake up the wait for termios */ - wake_up_interruptible(&priv->delta_msr_wait); - - if (!urb->actual_length) - return; - - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - - if (status & UART_STATE_TRANSIENT_MASK) { - /* break takes precedence over parity, which takes precedence - * over framing errors */ - if (status & UART_BREAK_ERROR) - tty_flag = TTY_BREAK; - else if (status & UART_PARITY_ERROR) - tty_flag = TTY_PARITY; - else if (status & UART_FRAME_ERROR) - tty_flag = TTY_FRAME; - dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag); - - /* overrun is special, not associated with a char */ - if (status & UART_OVERRUN_ERROR) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - - if (status & UART_DCD) - usb_serial_handle_dcd_change(port, tty, - priv->line_status & MSR_STATUS_LINE_DCD); - } - - tty_insert_flip_string_fixed_flag(tty, data, tty_flag, - urb->actual_length); - tty_flip_buffer_push(tty); - tty_kref_put(tty); -} - -static int spcp8x5_wait_modem_info(struct usb_serial_port *port, - unsigned int arg) -{ - struct spcp8x5_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - unsigned int prevstatus; - unsigned int status; - unsigned int changed; - - spin_lock_irqsave(&priv->lock, flags); - prevstatus = priv->line_status; - spin_unlock_irqrestore(&priv->lock, flags); - - while (1) { - /* wake up in bulk read */ - interruptible_sleep_on(&priv->delta_msr_wait); - - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - - spin_lock_irqsave(&priv->lock, flags); - status = priv->line_status; - spin_unlock_irqrestore(&priv->lock, flags); - - changed = prevstatus^status; - - if (((arg & TIOCM_RNG) && (changed & MSR_STATUS_LINE_RI)) || - ((arg & TIOCM_DSR) && (changed & MSR_STATUS_LINE_DSR)) || - ((arg & TIOCM_CD) && (changed & MSR_STATUS_LINE_DCD)) || - ((arg & TIOCM_CTS) && (changed & MSR_STATUS_LINE_CTS))) - return 0; - - prevstatus = status; - } - /* NOTREACHED */ - return 0; -} - -static int spcp8x5_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd); - - switch (cmd) { - case TIOCMIWAIT: - dbg("%s (%d) TIOCMIWAIT", __func__, port->number); - return spcp8x5_wait_modem_info(port, arg); - - default: - dbg("%s not supported = 0x%04x", __func__, cmd); - break; - } - - return -ENOIOCTLCMD; -} - -static int spcp8x5_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct spcp8x5_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - u8 control; - - spin_lock_irqsave(&priv->lock, flags); - if (set & TIOCM_RTS) - priv->line_control |= MCR_RTS; - if (set & TIOCM_DTR) - priv->line_control |= MCR_DTR; - if (clear & TIOCM_RTS) - priv->line_control &= ~MCR_RTS; - if (clear & TIOCM_DTR) - priv->line_control &= ~MCR_DTR; - control = priv->line_control; - spin_unlock_irqrestore(&priv->lock, flags); - - return spcp8x5_set_ctrlLine(port->serial->dev, control , priv->type); -} - -static int spcp8x5_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct spcp8x5_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - unsigned int mcr; - unsigned int status; - unsigned int result; - - spin_lock_irqsave(&priv->lock, flags); - mcr = priv->line_control; - status = priv->line_status; - spin_unlock_irqrestore(&priv->lock, flags); - - result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0) - | ((mcr & MCR_RTS) ? TIOCM_RTS : 0) - | ((status & MSR_STATUS_LINE_CTS) ? TIOCM_CTS : 0) - | ((status & MSR_STATUS_LINE_DSR) ? TIOCM_DSR : 0) - | ((status & MSR_STATUS_LINE_RI) ? TIOCM_RI : 0) - | ((status & MSR_STATUS_LINE_DCD) ? TIOCM_CD : 0); - - return result; -} - -/* All of the device info needed for the spcp8x5 SIO serial converter */ -static struct usb_serial_driver spcp8x5_device = { - .driver = { - .owner = THIS_MODULE, - .name = "SPCP8x5", - }, - .id_table = id_table, - .num_ports = 1, - .open = spcp8x5_open, - .dtr_rts = spcp8x5_dtr_rts, - .carrier_raised = spcp8x5_carrier_raised, - .set_termios = spcp8x5_set_termios, - .init_termios = spcp8x5_init_termios, - .ioctl = spcp8x5_ioctl, - .tiocmget = spcp8x5_tiocmget, - .tiocmset = spcp8x5_tiocmset, - .attach = spcp8x5_startup, - .release = spcp8x5_release, - .process_read_urb = spcp8x5_process_read_urb, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &spcp8x5_device, NULL -}; - -module_usb_serial_driver(spcp8x5_driver, serial_drivers); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/ssu100.c b/ANDROID_3.4.5/drivers/usb/serial/ssu100.c deleted file mode 100644 index 3cdc8a52..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/ssu100.c +++ /dev/null @@ -1,704 +0,0 @@ -/* - * usb-serial driver for Quatech SSU-100 - * - * based on ftdi_sio.c and the original serqt_usb.c from Quatech - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define QT_OPEN_CLOSE_CHANNEL 0xca -#define QT_SET_GET_DEVICE 0xc2 -#define QT_SET_GET_REGISTER 0xc0 -#define QT_GET_SET_PREBUF_TRIG_LVL 0xcc -#define QT_SET_ATF 0xcd -#define QT_GET_SET_UART 0xc1 -#define QT_TRANSFER_IN 0xc0 -#define QT_HW_FLOW_CONTROL_MASK 0xc5 -#define QT_SW_FLOW_CONTROL_MASK 0xc6 - -#define SERIAL_MSR_MASK 0xf0 - -#define SERIAL_CRTSCTS ((UART_MCR_RTS << 8) | UART_MSR_CTS) - -#define SERIAL_EVEN_PARITY (UART_LCR_PARITY | UART_LCR_EPAR) - -#define MAX_BAUD_RATE 460800 - -#define ATC_DISABLED 0x00 -#define DUPMODE_BITS 0xc0 -#define RR_BITS 0x03 -#define LOOPMODE_BITS 0x41 -#define RS232_MODE 0x00 -#define RTSCTS_TO_CONNECTOR 0x40 -#define CLKS_X4 0x02 -#define FULLPWRBIT 0x00000080 -#define NEXT_BOARD_POWER_BIT 0x00000004 - -static bool debug; - -/* Version Information */ -#define DRIVER_VERSION "v0.1" -#define DRIVER_DESC "Quatech SSU-100 USB to Serial Driver" - -#define USB_VENDOR_ID_QUATECH 0x061d /* Quatech VID */ -#define QUATECH_SSU100 0xC020 /* SSU100 */ - -static const struct usb_device_id id_table[] = { - {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU100)}, - {} /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, id_table); - - -static struct usb_driver ssu100_driver = { - .name = "ssu100", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .supports_autosuspend = 1, -}; - -struct ssu100_port_private { - spinlock_t status_lock; - u8 shadowLSR; - u8 shadowMSR; - wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ - struct async_icount icount; -}; - -static void ssu100_release(struct usb_serial *serial) -{ - struct ssu100_port_private *priv = usb_get_serial_port_data(*serial->port); - - dbg("%s", __func__); - kfree(priv); -} - -static inline int ssu100_control_msg(struct usb_device *dev, - u8 request, u16 data, u16 index) -{ - return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - request, 0x40, data, index, - NULL, 0, 300); -} - -static inline int ssu100_setdevice(struct usb_device *dev, u8 *data) -{ - u16 x = ((u16)(data[1] << 8) | (u16)(data[0])); - - return ssu100_control_msg(dev, QT_SET_GET_DEVICE, x, 0); -} - - -static inline int ssu100_getdevice(struct usb_device *dev, u8 *data) -{ - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - QT_SET_GET_DEVICE, 0xc0, 0, 0, - data, 3, 300); -} - -static inline int ssu100_getregister(struct usb_device *dev, - unsigned short uart, - unsigned short reg, - u8 *data) -{ - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - QT_SET_GET_REGISTER, 0xc0, reg, - uart, data, sizeof(*data), 300); - -} - - -static inline int ssu100_setregister(struct usb_device *dev, - unsigned short uart, - unsigned short reg, - u16 data) -{ - u16 value = (data << 8) | reg; - - return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - QT_SET_GET_REGISTER, 0x40, value, uart, - NULL, 0, 300); - -} - -#define set_mctrl(dev, set) update_mctrl((dev), (set), 0) -#define clear_mctrl(dev, clear) update_mctrl((dev), 0, (clear)) - -/* these do not deal with device that have more than 1 port */ -static inline int update_mctrl(struct usb_device *dev, unsigned int set, - unsigned int clear) -{ - unsigned urb_value; - int result; - - if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) { - dbg("%s - DTR|RTS not being set|cleared", __func__); - return 0; /* no change */ - } - - clear &= ~set; /* 'set' takes precedence over 'clear' */ - urb_value = 0; - if (set & TIOCM_DTR) - urb_value |= UART_MCR_DTR; - if (set & TIOCM_RTS) - urb_value |= UART_MCR_RTS; - - result = ssu100_setregister(dev, 0, UART_MCR, urb_value); - if (result < 0) - dbg("%s Error from MODEM_CTRL urb", __func__); - - return result; -} - -static int ssu100_initdevice(struct usb_device *dev) -{ - u8 *data; - int result = 0; - - dbg("%s", __func__); - - data = kzalloc(3, GFP_KERNEL); - if (!data) - return -ENOMEM; - - result = ssu100_getdevice(dev, data); - if (result < 0) { - dbg("%s - get_device failed %i", __func__, result); - goto out; - } - - data[1] &= ~FULLPWRBIT; - - result = ssu100_setdevice(dev, data); - if (result < 0) { - dbg("%s - setdevice failed %i", __func__, result); - goto out; - } - - result = ssu100_control_msg(dev, QT_GET_SET_PREBUF_TRIG_LVL, 128, 0); - if (result < 0) { - dbg("%s - set prebuffer level failed %i", __func__, result); - goto out; - } - - result = ssu100_control_msg(dev, QT_SET_ATF, ATC_DISABLED, 0); - if (result < 0) { - dbg("%s - set ATFprebuffer level failed %i", __func__, result); - goto out; - } - - result = ssu100_getdevice(dev, data); - if (result < 0) { - dbg("%s - get_device failed %i", __func__, result); - goto out; - } - - data[0] &= ~(RR_BITS | DUPMODE_BITS); - data[0] |= CLKS_X4; - data[1] &= ~(LOOPMODE_BITS); - data[1] |= RS232_MODE; - - result = ssu100_setdevice(dev, data); - if (result < 0) { - dbg("%s - setdevice failed %i", __func__, result); - goto out; - } - -out: kfree(data); - return result; - -} - - -static void ssu100_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old_termios) -{ - struct usb_device *dev = port->serial->dev; - struct ktermios *termios = tty->termios; - u16 baud, divisor, remainder; - unsigned int cflag = termios->c_cflag; - u16 urb_value = 0; /* will hold the new flags */ - int result; - - dbg("%s", __func__); - - if (cflag & PARENB) { - if (cflag & PARODD) - urb_value |= UART_LCR_PARITY; - else - urb_value |= SERIAL_EVEN_PARITY; - } - - switch (cflag & CSIZE) { - case CS5: - urb_value |= UART_LCR_WLEN5; - break; - case CS6: - urb_value |= UART_LCR_WLEN6; - break; - case CS7: - urb_value |= UART_LCR_WLEN7; - break; - default: - case CS8: - urb_value |= UART_LCR_WLEN8; - break; - } - - baud = tty_get_baud_rate(tty); - if (!baud) - baud = 9600; - - dbg("%s - got baud = %d\n", __func__, baud); - - - divisor = MAX_BAUD_RATE / baud; - remainder = MAX_BAUD_RATE % baud; - if (((remainder * 2) >= baud) && (baud != 110)) - divisor++; - - urb_value = urb_value << 8; - - result = ssu100_control_msg(dev, QT_GET_SET_UART, divisor, urb_value); - if (result < 0) - dbg("%s - set uart failed", __func__); - - if (cflag & CRTSCTS) - result = ssu100_control_msg(dev, QT_HW_FLOW_CONTROL_MASK, - SERIAL_CRTSCTS, 0); - else - result = ssu100_control_msg(dev, QT_HW_FLOW_CONTROL_MASK, - 0, 0); - if (result < 0) - dbg("%s - set HW flow control failed", __func__); - - if (I_IXOFF(tty) || I_IXON(tty)) { - u16 x = ((u16)(START_CHAR(tty) << 8) | (u16)(STOP_CHAR(tty))); - - result = ssu100_control_msg(dev, QT_SW_FLOW_CONTROL_MASK, - x, 0); - } else - result = ssu100_control_msg(dev, QT_SW_FLOW_CONTROL_MASK, - 0, 0); - - if (result < 0) - dbg("%s - set SW flow control failed", __func__); - -} - - -static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct usb_device *dev = port->serial->dev; - struct ssu100_port_private *priv = usb_get_serial_port_data(port); - u8 *data; - int result; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - data = kzalloc(2, GFP_KERNEL); - if (!data) - return -ENOMEM; - - result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - QT_OPEN_CLOSE_CHANNEL, - QT_TRANSFER_IN, 0x01, - 0, data, 2, 300); - if (result < 0) { - dbg("%s - open failed %i", __func__, result); - kfree(data); - return result; - } - - spin_lock_irqsave(&priv->status_lock, flags); - priv->shadowLSR = data[0]; - priv->shadowMSR = data[1]; - spin_unlock_irqrestore(&priv->status_lock, flags); - - kfree(data); - -/* set to 9600 */ - result = ssu100_control_msg(dev, QT_GET_SET_UART, 0x30, 0x0300); - if (result < 0) - dbg("%s - set uart failed", __func__); - - if (tty) - ssu100_set_termios(tty, port, tty->termios); - - return usb_serial_generic_open(tty, port); -} - -static void ssu100_close(struct usb_serial_port *port) -{ - dbg("%s", __func__); - usb_serial_generic_close(port); -} - -static int get_serial_info(struct usb_serial_port *port, - struct serial_struct __user *retinfo) -{ - struct serial_struct tmp; - - if (!retinfo) - return -EFAULT; - - memset(&tmp, 0, sizeof(tmp)); - tmp.line = port->serial->minor; - tmp.port = 0; - tmp.irq = 0; - tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; - tmp.xmit_fifo_size = port->bulk_out_size; - tmp.baud_base = 9600; - tmp.close_delay = 5*HZ; - tmp.closing_wait = 30*HZ; - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - return 0; -} - -static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) -{ - struct ssu100_port_private *priv = usb_get_serial_port_data(port); - struct async_icount prev, cur; - unsigned long flags; - - spin_lock_irqsave(&priv->status_lock, flags); - prev = priv->icount; - spin_unlock_irqrestore(&priv->status_lock, flags); - - while (1) { - wait_event_interruptible(priv->delta_msr_wait, - ((priv->icount.rng != prev.rng) || - (priv->icount.dsr != prev.dsr) || - (priv->icount.dcd != prev.dcd) || - (priv->icount.cts != prev.cts))); - - if (signal_pending(current)) - return -ERESTARTSYS; - - spin_lock_irqsave(&priv->status_lock, flags); - cur = priv->icount; - spin_unlock_irqrestore(&priv->status_lock, flags); - - if ((prev.rng == cur.rng) && - (prev.dsr == cur.dsr) && - (prev.dcd == cur.dcd) && - (prev.cts == cur.cts)) - return -EIO; - - if ((arg & TIOCM_RNG && (prev.rng != cur.rng)) || - (arg & TIOCM_DSR && (prev.dsr != cur.dsr)) || - (arg & TIOCM_CD && (prev.dcd != cur.dcd)) || - (arg & TIOCM_CTS && (prev.cts != cur.cts))) - return 0; - } - return 0; -} - -static int ssu100_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct ssu100_port_private *priv = usb_get_serial_port_data(port); - struct async_icount cnow = priv->icount; - - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - icount->rx = cnow.rx; - icount->tx = cnow.tx; - icount->frame = cnow.frame; - icount->overrun = cnow.overrun; - icount->parity = cnow.parity; - icount->brk = cnow.brk; - icount->buf_overrun = cnow.buf_overrun; - - return 0; -} - - - -static int ssu100_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - - dbg("%s cmd 0x%04x", __func__, cmd); - - switch (cmd) { - case TIOCGSERIAL: - return get_serial_info(port, - (struct serial_struct __user *) arg); - - case TIOCMIWAIT: - return wait_modem_info(port, arg); - - default: - break; - } - - dbg("%s arg not supported", __func__); - - return -ENOIOCTLCMD; -} - -static int ssu100_attach(struct usb_serial *serial) -{ - struct ssu100_port_private *priv; - struct usb_serial_port *port = *serial->port; - - dbg("%s", __func__); - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", __func__, - sizeof(*priv)); - return -ENOMEM; - } - - spin_lock_init(&priv->status_lock); - init_waitqueue_head(&priv->delta_msr_wait); - usb_set_serial_port_data(port, priv); - - return ssu100_initdevice(serial->dev); -} - -static int ssu100_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_device *dev = port->serial->dev; - u8 *d; - int r; - - dbg("%s\n", __func__); - - d = kzalloc(2, GFP_KERNEL); - if (!d) - return -ENOMEM; - - r = ssu100_getregister(dev, 0, UART_MCR, d); - if (r < 0) - goto mget_out; - - r = ssu100_getregister(dev, 0, UART_MSR, d+1); - if (r < 0) - goto mget_out; - - r = (d[0] & UART_MCR_DTR ? TIOCM_DTR : 0) | - (d[0] & UART_MCR_RTS ? TIOCM_RTS : 0) | - (d[1] & UART_MSR_CTS ? TIOCM_CTS : 0) | - (d[1] & UART_MSR_DCD ? TIOCM_CAR : 0) | - (d[1] & UART_MSR_RI ? TIOCM_RI : 0) | - (d[1] & UART_MSR_DSR ? TIOCM_DSR : 0); - -mget_out: - kfree(d); - return r; -} - -static int ssu100_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_device *dev = port->serial->dev; - - dbg("%s\n", __func__); - return update_mctrl(dev, set, clear); -} - -static void ssu100_dtr_rts(struct usb_serial_port *port, int on) -{ - struct usb_device *dev = port->serial->dev; - - dbg("%s\n", __func__); - - mutex_lock(&port->serial->disc_mutex); - if (!port->serial->disconnected) { - /* Disable flow control */ - if (!on && - ssu100_setregister(dev, 0, UART_MCR, 0) < 0) - dev_err(&port->dev, "error from flowcontrol urb\n"); - /* drop RTS and DTR */ - if (on) - set_mctrl(dev, TIOCM_DTR | TIOCM_RTS); - else - clear_mctrl(dev, TIOCM_DTR | TIOCM_RTS); - } - mutex_unlock(&port->serial->disc_mutex); -} - -static void ssu100_update_msr(struct usb_serial_port *port, u8 msr) -{ - struct ssu100_port_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - - spin_lock_irqsave(&priv->status_lock, flags); - priv->shadowMSR = msr; - spin_unlock_irqrestore(&priv->status_lock, flags); - - if (msr & UART_MSR_ANY_DELTA) { - /* update input line counters */ - if (msr & UART_MSR_DCTS) - priv->icount.cts++; - if (msr & UART_MSR_DDSR) - priv->icount.dsr++; - if (msr & UART_MSR_DDCD) - priv->icount.dcd++; - if (msr & UART_MSR_TERI) - priv->icount.rng++; - wake_up_interruptible(&priv->delta_msr_wait); - } -} - -static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr, - char *tty_flag) -{ - struct ssu100_port_private *priv = usb_get_serial_port_data(port); - unsigned long flags; - - spin_lock_irqsave(&priv->status_lock, flags); - priv->shadowLSR = lsr; - spin_unlock_irqrestore(&priv->status_lock, flags); - - *tty_flag = TTY_NORMAL; - if (lsr & UART_LSR_BRK_ERROR_BITS) { - /* we always want to update icount, but we only want to - * update tty_flag for one case */ - if (lsr & UART_LSR_BI) { - priv->icount.brk++; - *tty_flag = TTY_BREAK; - usb_serial_handle_break(port); - } - if (lsr & UART_LSR_PE) { - priv->icount.parity++; - if (*tty_flag == TTY_NORMAL) - *tty_flag = TTY_PARITY; - } - if (lsr & UART_LSR_FE) { - priv->icount.frame++; - if (*tty_flag == TTY_NORMAL) - *tty_flag = TTY_FRAME; - } - if (lsr & UART_LSR_OE){ - priv->icount.overrun++; - if (*tty_flag == TTY_NORMAL) - *tty_flag = TTY_OVERRUN; - } - } - -} - -static int ssu100_process_packet(struct urb *urb, - struct tty_struct *tty) -{ - struct usb_serial_port *port = urb->context; - char *packet = (char *)urb->transfer_buffer; - char flag = TTY_NORMAL; - u32 len = urb->actual_length; - int i; - char *ch; - - dbg("%s - port %d", __func__, port->number); - - if ((len >= 4) && - (packet[0] == 0x1b) && (packet[1] == 0x1b) && - ((packet[2] == 0x00) || (packet[2] == 0x01))) { - if (packet[2] == 0x00) { - ssu100_update_lsr(port, packet[3], &flag); - if (flag == TTY_OVERRUN) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } - if (packet[2] == 0x01) - ssu100_update_msr(port, packet[3]); - - len -= 4; - ch = packet + 4; - } else - ch = packet; - - if (!len) - return 0; /* status only */ - - if (port->port.console && port->sysrq) { - for (i = 0; i < len; i++, ch++) { - if (!usb_serial_handle_sysrq_char(port, *ch)) - tty_insert_flip_char(tty, *ch, flag); - } - } else - tty_insert_flip_string_fixed_flag(tty, ch, flag, len); - - return len; -} - -static void ssu100_process_read_urb(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct tty_struct *tty; - int count; - - dbg("%s", __func__); - - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - - count = ssu100_process_packet(urb, tty); - - if (count) - tty_flip_buffer_push(tty); - tty_kref_put(tty); -} - -static struct usb_serial_driver ssu100_device = { - .driver = { - .owner = THIS_MODULE, - .name = "ssu100", - }, - .description = DRIVER_DESC, - .id_table = id_table, - .num_ports = 1, - .open = ssu100_open, - .close = ssu100_close, - .attach = ssu100_attach, - .release = ssu100_release, - .dtr_rts = ssu100_dtr_rts, - .process_read_urb = ssu100_process_read_urb, - .tiocmget = ssu100_tiocmget, - .tiocmset = ssu100_tiocmset, - .get_icount = ssu100_get_icount, - .ioctl = ssu100_ioctl, - .set_termios = ssu100_set_termios, - .disconnect = usb_serial_generic_disconnect, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &ssu100_device, NULL -}; - -module_usb_serial_driver(ssu100_driver, serial_drivers); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/symbolserial.c b/ANDROID_3.4.5/drivers/usb/serial/symbolserial.c deleted file mode 100644 index 1a5be136..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/symbolserial.c +++ /dev/null @@ -1,317 +0,0 @@ -/* - * Symbol USB barcode to serial driver - * - * Copyright (C) 2009 Greg Kroah-Hartman - * Copyright (C) 2009 Novell Inc. - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static bool debug; - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(0x05e0, 0x0600) }, - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -/* This structure holds all of the individual device information */ -struct symbol_private { - struct usb_device *udev; - struct usb_serial *serial; - struct usb_serial_port *port; - unsigned char *int_buffer; - struct urb *int_urb; - int buffer_size; - u8 bInterval; - u8 int_address; - spinlock_t lock; /* protects the following flags */ - bool throttled; - bool actually_throttled; - bool rts; -}; - -static void symbol_int_callback(struct urb *urb) -{ - struct symbol_private *priv = urb->context; - unsigned char *data = urb->transfer_buffer; - struct usb_serial_port *port = priv->port; - int status = urb->status; - struct tty_struct *tty; - int result; - int data_length; - - dbg("%s - port %d", __func__, port->number); - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); - return; - default: - dbg("%s - nonzero urb status received: %d", - __func__, status); - goto exit; - } - - usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, - data); - - if (urb->actual_length > 1) { - data_length = urb->actual_length - 1; - - /* - * Data from the device comes with a 1 byte header: - * - * data... - * This is real data to be sent to the tty layer - * we pretty much just ignore the size and send everything - * else to the tty layer. - */ - tty = tty_port_tty_get(&port->port); - if (tty) { - tty_insert_flip_string(tty, &data[1], data_length); - tty_flip_buffer_push(tty); - tty_kref_put(tty); - } - } else { - dev_dbg(&priv->udev->dev, - "Improper amount of data received from the device, " - "%d bytes", urb->actual_length); - } - -exit: - spin_lock(&priv->lock); - - /* Continue trying to always read if we should */ - if (!priv->throttled) { - usb_fill_int_urb(priv->int_urb, priv->udev, - usb_rcvintpipe(priv->udev, - priv->int_address), - priv->int_buffer, priv->buffer_size, - symbol_int_callback, priv, priv->bInterval); - result = usb_submit_urb(priv->int_urb, GFP_ATOMIC); - if (result) - dev_err(&port->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, result); - } else - priv->actually_throttled = true; - spin_unlock(&priv->lock); -} - -static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct symbol_private *priv = usb_get_serial_data(port->serial); - unsigned long flags; - int result = 0; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&priv->lock, flags); - priv->throttled = false; - priv->actually_throttled = false; - priv->port = port; - spin_unlock_irqrestore(&priv->lock, flags); - - /* Start reading from the device */ - usb_fill_int_urb(priv->int_urb, priv->udev, - usb_rcvintpipe(priv->udev, priv->int_address), - priv->int_buffer, priv->buffer_size, - symbol_int_callback, priv, priv->bInterval); - result = usb_submit_urb(priv->int_urb, GFP_KERNEL); - if (result) - dev_err(&port->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, result); - return result; -} - -static void symbol_close(struct usb_serial_port *port) -{ - struct symbol_private *priv = usb_get_serial_data(port->serial); - - dbg("%s - port %d", __func__, port->number); - - /* shutdown our urbs */ - usb_kill_urb(priv->int_urb); -} - -static void symbol_throttle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct symbol_private *priv = usb_get_serial_data(port->serial); - - dbg("%s - port %d", __func__, port->number); - spin_lock_irq(&priv->lock); - priv->throttled = true; - spin_unlock_irq(&priv->lock); -} - -static void symbol_unthrottle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct symbol_private *priv = usb_get_serial_data(port->serial); - int result; - bool was_throttled; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irq(&priv->lock); - priv->throttled = false; - was_throttled = priv->actually_throttled; - priv->actually_throttled = false; - spin_unlock_irq(&priv->lock); - - if (was_throttled) { - result = usb_submit_urb(priv->int_urb, GFP_KERNEL); - if (result) - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", - __func__, result); - } -} - -static int symbol_startup(struct usb_serial *serial) -{ - struct symbol_private *priv; - struct usb_host_interface *intf; - int i; - int retval = -ENOMEM; - bool int_in_found = false; - - /* create our private serial structure */ - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (priv == NULL) { - dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__); - return -ENOMEM; - } - spin_lock_init(&priv->lock); - priv->serial = serial; - priv->port = serial->port[0]; - priv->udev = serial->dev; - - /* find our interrupt endpoint */ - intf = serial->interface->altsetting; - for (i = 0; i < intf->desc.bNumEndpoints; ++i) { - struct usb_endpoint_descriptor *endpoint; - - endpoint = &intf->endpoint[i].desc; - if (!usb_endpoint_is_int_in(endpoint)) - continue; - - priv->int_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!priv->int_urb) { - dev_err(&priv->udev->dev, "out of memory\n"); - goto error; - } - - priv->buffer_size = usb_endpoint_maxp(endpoint) * 2; - priv->int_buffer = kmalloc(priv->buffer_size, GFP_KERNEL); - if (!priv->int_buffer) { - dev_err(&priv->udev->dev, "out of memory\n"); - goto error; - } - - priv->int_address = endpoint->bEndpointAddress; - priv->bInterval = endpoint->bInterval; - - /* set up our int urb */ - usb_fill_int_urb(priv->int_urb, priv->udev, - usb_rcvintpipe(priv->udev, - endpoint->bEndpointAddress), - priv->int_buffer, priv->buffer_size, - symbol_int_callback, priv, priv->bInterval); - - int_in_found = true; - break; - } - - if (!int_in_found) { - dev_err(&priv->udev->dev, - "Error - the proper endpoints were not found!\n"); - goto error; - } - - usb_set_serial_data(serial, priv); - return 0; - -error: - usb_free_urb(priv->int_urb); - kfree(priv->int_buffer); - kfree(priv); - return retval; -} - -static void symbol_disconnect(struct usb_serial *serial) -{ - struct symbol_private *priv = usb_get_serial_data(serial); - - dbg("%s", __func__); - - usb_kill_urb(priv->int_urb); - usb_free_urb(priv->int_urb); -} - -static void symbol_release(struct usb_serial *serial) -{ - struct symbol_private *priv = usb_get_serial_data(serial); - - dbg("%s", __func__); - - kfree(priv->int_buffer); - kfree(priv); -} - -static struct usb_driver symbol_driver = { - .name = "symbol", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - -static struct usb_serial_driver symbol_device = { - .driver = { - .owner = THIS_MODULE, - .name = "symbol", - }, - .id_table = id_table, - .num_ports = 1, - .attach = symbol_startup, - .open = symbol_open, - .close = symbol_close, - .disconnect = symbol_disconnect, - .release = symbol_release, - .throttle = symbol_throttle, - .unthrottle = symbol_unthrottle, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &symbol_device, NULL -}; - -module_usb_serial_driver(symbol_driver, serial_drivers); - -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/ti_usb_3410_5052.c b/ANDROID_3.4.5/drivers/usb/serial/ti_usb_3410_5052.c deleted file mode 100644 index 33774375..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/ti_usb_3410_5052.c +++ /dev/null @@ -1,1750 +0,0 @@ -/* vi: ts=8 sw=8 - * - * TI 3410/5052 USB Serial Driver - * - * Copyright (C) 2004 Texas Instruments - * - * This driver is based on the Linux io_ti driver, which is - * Copyright (C) 2000-2002 Inside Out Networks - * Copyright (C) 2001-2002 Greg Kroah-Hartman - * - * 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. - * - * For questions or problems with this driver, contact Texas Instruments - * technical support, or Al Borchers , or - * Peter Berger . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ti_usb_3410_5052.h" - -/* Defines */ - -#define TI_DRIVER_VERSION "v0.10" -#define TI_DRIVER_AUTHOR "Al Borchers " -#define TI_DRIVER_DESC "TI USB 3410/5052 Serial Driver" - -#define TI_FIRMWARE_BUF_SIZE 16284 - -#define TI_WRITE_BUF_SIZE 1024 - -#define TI_TRANSFER_TIMEOUT 2 - -#define TI_DEFAULT_CLOSING_WAIT 4000 /* in .01 secs */ - -/* supported setserial flags */ -#define TI_SET_SERIAL_FLAGS 0 - -/* read urb states */ -#define TI_READ_URB_RUNNING 0 -#define TI_READ_URB_STOPPING 1 -#define TI_READ_URB_STOPPED 2 - -#define TI_EXTRA_VID_PID_COUNT 5 - - -/* Structures */ - -struct ti_port { - int tp_is_open; - __u8 tp_msr; - __u8 tp_lsr; - __u8 tp_shadow_mcr; - __u8 tp_uart_mode; /* 232 or 485 modes */ - unsigned int tp_uart_base_addr; - int tp_flags; - int tp_closing_wait;/* in .01 secs */ - struct async_icount tp_icount; - wait_queue_head_t tp_msr_wait; /* wait for msr change */ - wait_queue_head_t tp_write_wait; - struct ti_device *tp_tdev; - struct usb_serial_port *tp_port; - spinlock_t tp_lock; - int tp_read_urb_state; - int tp_write_urb_in_use; - struct kfifo write_fifo; -}; - -struct ti_device { - struct mutex td_open_close_lock; - int td_open_port_count; - struct usb_serial *td_serial; - int td_is_3410; - int td_urb_error; -}; - - -/* Function Declarations */ - -static int ti_startup(struct usb_serial *serial); -static void ti_release(struct usb_serial *serial); -static int ti_open(struct tty_struct *tty, struct usb_serial_port *port); -static void ti_close(struct usb_serial_port *port); -static int ti_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *data, int count); -static int ti_write_room(struct tty_struct *tty); -static int ti_chars_in_buffer(struct tty_struct *tty); -static void ti_throttle(struct tty_struct *tty); -static void ti_unthrottle(struct tty_struct *tty); -static int ti_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); -static int ti_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount); -static void ti_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios); -static int ti_tiocmget(struct tty_struct *tty); -static int ti_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear); -static void ti_break(struct tty_struct *tty, int break_state); -static void ti_interrupt_callback(struct urb *urb); -static void ti_bulk_in_callback(struct urb *urb); -static void ti_bulk_out_callback(struct urb *urb); - -static void ti_recv(struct device *dev, struct tty_struct *tty, - unsigned char *data, int length); -static void ti_send(struct ti_port *tport); -static int ti_set_mcr(struct ti_port *tport, unsigned int mcr); -static int ti_get_lsr(struct ti_port *tport); -static int ti_get_serial_info(struct ti_port *tport, - struct serial_struct __user *ret_arg); -static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport, - struct serial_struct __user *new_arg); -static void ti_handle_new_msr(struct ti_port *tport, __u8 msr); - -static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush); - -static void ti_stop_read(struct ti_port *tport, struct tty_struct *tty); -static int ti_restart_read(struct ti_port *tport, struct tty_struct *tty); - -static int ti_command_out_sync(struct ti_device *tdev, __u8 command, - __u16 moduleid, __u16 value, __u8 *data, int size); -static int ti_command_in_sync(struct ti_device *tdev, __u8 command, - __u16 moduleid, __u16 value, __u8 *data, int size); - -static int ti_write_byte(struct ti_device *tdev, unsigned long addr, - __u8 mask, __u8 byte); - -static int ti_download_firmware(struct ti_device *tdev); - - -/* Data */ - -/* module parameters */ -static bool debug; -static int closing_wait = TI_DEFAULT_CLOSING_WAIT; -static ushort vendor_3410[TI_EXTRA_VID_PID_COUNT]; -static unsigned int vendor_3410_count; -static ushort product_3410[TI_EXTRA_VID_PID_COUNT]; -static unsigned int product_3410_count; -static ushort vendor_5052[TI_EXTRA_VID_PID_COUNT]; -static unsigned int vendor_5052_count; -static ushort product_5052[TI_EXTRA_VID_PID_COUNT]; -static unsigned int product_5052_count; - -/* supported devices */ -/* the array dimension is the number of default entries plus */ -/* TI_EXTRA_VID_PID_COUNT user defined entries plus 1 terminating */ -/* null entry */ -static struct usb_device_id ti_id_table_3410[15+TI_EXTRA_VID_PID_COUNT+1] = { - { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, - { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, - { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, - { USB_DEVICE(MTS_VENDOR_ID, MTS_CDMA_NO_FW_PRODUCT_ID) }, - { USB_DEVICE(MTS_VENDOR_ID, MTS_CDMA_PRODUCT_ID) }, - { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_PRODUCT_ID) }, - { USB_DEVICE(MTS_VENDOR_ID, MTS_EDGE_PRODUCT_ID) }, - { USB_DEVICE(MTS_VENDOR_ID, MTS_MT9234MU_PRODUCT_ID) }, - { USB_DEVICE(MTS_VENDOR_ID, MTS_MT9234ZBA_PRODUCT_ID) }, - { USB_DEVICE(MTS_VENDOR_ID, MTS_MT9234ZBAOLD_PRODUCT_ID) }, - { USB_DEVICE(IBM_VENDOR_ID, IBM_4543_PRODUCT_ID) }, - { USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) }, - { USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) }, - { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) }, - { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) }, -}; - -static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = { - { USB_DEVICE(TI_VENDOR_ID, TI_5052_BOOT_PRODUCT_ID) }, - { USB_DEVICE(TI_VENDOR_ID, TI_5152_BOOT_PRODUCT_ID) }, - { USB_DEVICE(TI_VENDOR_ID, TI_5052_EEPROM_PRODUCT_ID) }, - { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) }, -}; - -static struct usb_device_id ti_id_table_combined[19+2*TI_EXTRA_VID_PID_COUNT+1] = { - { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, - { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, - { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, - { USB_DEVICE(MTS_VENDOR_ID, MTS_CDMA_NO_FW_PRODUCT_ID) }, - { USB_DEVICE(MTS_VENDOR_ID, MTS_CDMA_PRODUCT_ID) }, - { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_PRODUCT_ID) }, - { USB_DEVICE(MTS_VENDOR_ID, MTS_EDGE_PRODUCT_ID) }, - { USB_DEVICE(MTS_VENDOR_ID, MTS_MT9234MU_PRODUCT_ID) }, - { USB_DEVICE(MTS_VENDOR_ID, MTS_MT9234ZBA_PRODUCT_ID) }, - { USB_DEVICE(MTS_VENDOR_ID, MTS_MT9234ZBAOLD_PRODUCT_ID) }, - { USB_DEVICE(TI_VENDOR_ID, TI_5052_BOOT_PRODUCT_ID) }, - { USB_DEVICE(TI_VENDOR_ID, TI_5152_BOOT_PRODUCT_ID) }, - { USB_DEVICE(TI_VENDOR_ID, TI_5052_EEPROM_PRODUCT_ID) }, - { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) }, - { USB_DEVICE(IBM_VENDOR_ID, IBM_4543_PRODUCT_ID) }, - { USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) }, - { USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) }, - { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) }, - { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) }, - { } -}; - -static struct usb_driver ti_usb_driver = { - .name = "ti_usb_3410_5052", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = ti_id_table_combined, -}; - -static struct usb_serial_driver ti_1port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "ti_usb_3410_5052_1", - }, - .description = "TI USB 3410 1 port adapter", - .id_table = ti_id_table_3410, - .num_ports = 1, - .attach = ti_startup, - .release = ti_release, - .open = ti_open, - .close = ti_close, - .write = ti_write, - .write_room = ti_write_room, - .chars_in_buffer = ti_chars_in_buffer, - .throttle = ti_throttle, - .unthrottle = ti_unthrottle, - .ioctl = ti_ioctl, - .set_termios = ti_set_termios, - .tiocmget = ti_tiocmget, - .tiocmset = ti_tiocmset, - .get_icount = ti_get_icount, - .break_ctl = ti_break, - .read_int_callback = ti_interrupt_callback, - .read_bulk_callback = ti_bulk_in_callback, - .write_bulk_callback = ti_bulk_out_callback, -}; - -static struct usb_serial_driver ti_2port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "ti_usb_3410_5052_2", - }, - .description = "TI USB 5052 2 port adapter", - .id_table = ti_id_table_5052, - .num_ports = 2, - .attach = ti_startup, - .release = ti_release, - .open = ti_open, - .close = ti_close, - .write = ti_write, - .write_room = ti_write_room, - .chars_in_buffer = ti_chars_in_buffer, - .throttle = ti_throttle, - .unthrottle = ti_unthrottle, - .ioctl = ti_ioctl, - .set_termios = ti_set_termios, - .tiocmget = ti_tiocmget, - .tiocmset = ti_tiocmset, - .get_icount = ti_get_icount, - .break_ctl = ti_break, - .read_int_callback = ti_interrupt_callback, - .read_bulk_callback = ti_bulk_in_callback, - .write_bulk_callback = ti_bulk_out_callback, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &ti_1port_device, &ti_2port_device, NULL -}; - -/* Module */ - -MODULE_AUTHOR(TI_DRIVER_AUTHOR); -MODULE_DESCRIPTION(TI_DRIVER_DESC); -MODULE_VERSION(TI_DRIVER_VERSION); -MODULE_LICENSE("GPL"); - -MODULE_FIRMWARE("ti_3410.fw"); -MODULE_FIRMWARE("ti_5052.fw"); -MODULE_FIRMWARE("mts_cdma.fw"); -MODULE_FIRMWARE("mts_gsm.fw"); -MODULE_FIRMWARE("mts_edge.fw"); -MODULE_FIRMWARE("mts_mt9234mu.fw"); -MODULE_FIRMWARE("mts_mt9234zba.fw"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable debugging, 0=no, 1=yes"); - -module_param(closing_wait, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(closing_wait, - "Maximum wait for data to drain in close, in .01 secs, default is 4000"); - -module_param_array(vendor_3410, ushort, &vendor_3410_count, S_IRUGO); -MODULE_PARM_DESC(vendor_3410, - "Vendor ids for 3410 based devices, 1-5 short integers"); -module_param_array(product_3410, ushort, &product_3410_count, S_IRUGO); -MODULE_PARM_DESC(product_3410, - "Product ids for 3410 based devices, 1-5 short integers"); -module_param_array(vendor_5052, ushort, &vendor_5052_count, S_IRUGO); -MODULE_PARM_DESC(vendor_5052, - "Vendor ids for 5052 based devices, 1-5 short integers"); -module_param_array(product_5052, ushort, &product_5052_count, S_IRUGO); -MODULE_PARM_DESC(product_5052, - "Product ids for 5052 based devices, 1-5 short integers"); - -MODULE_DEVICE_TABLE(usb, ti_id_table_combined); - - -/* Functions */ - -static int __init ti_init(void) -{ - int i, j, c; - int ret; - - /* insert extra vendor and product ids */ - c = ARRAY_SIZE(ti_id_table_combined) - 2 * TI_EXTRA_VID_PID_COUNT - 1; - j = ARRAY_SIZE(ti_id_table_3410) - TI_EXTRA_VID_PID_COUNT - 1; - for (i = 0; i < min(vendor_3410_count, product_3410_count); i++, j++, c++) { - ti_id_table_3410[j].idVendor = vendor_3410[i]; - ti_id_table_3410[j].idProduct = product_3410[i]; - ti_id_table_3410[j].match_flags = USB_DEVICE_ID_MATCH_DEVICE; - ti_id_table_combined[c].idVendor = vendor_3410[i]; - ti_id_table_combined[c].idProduct = product_3410[i]; - ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE; - } - j = ARRAY_SIZE(ti_id_table_5052) - TI_EXTRA_VID_PID_COUNT - 1; - for (i = 0; i < min(vendor_5052_count, product_5052_count); i++, j++, c++) { - ti_id_table_5052[j].idVendor = vendor_5052[i]; - ti_id_table_5052[j].idProduct = product_5052[i]; - ti_id_table_5052[j].match_flags = USB_DEVICE_ID_MATCH_DEVICE; - ti_id_table_combined[c].idVendor = vendor_5052[i]; - ti_id_table_combined[c].idProduct = product_5052[i]; - ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE; - } - - ret = usb_serial_register_drivers(&ti_usb_driver, serial_drivers); - if (ret == 0) - printk(KERN_INFO KBUILD_MODNAME ": " TI_DRIVER_VERSION ":" - TI_DRIVER_DESC "\n"); - return ret; -} - - -static void __exit ti_exit(void) -{ - usb_serial_deregister_drivers(&ti_usb_driver, serial_drivers); -} - - -module_init(ti_init); -module_exit(ti_exit); - - -static int ti_startup(struct usb_serial *serial) -{ - struct ti_device *tdev; - struct ti_port *tport; - struct usb_device *dev = serial->dev; - int status; - int i; - - - dbg("%s - product 0x%4X, num configurations %d, configuration value %d", - __func__, le16_to_cpu(dev->descriptor.idProduct), - dev->descriptor.bNumConfigurations, - dev->actconfig->desc.bConfigurationValue); - - /* create device structure */ - tdev = kzalloc(sizeof(struct ti_device), GFP_KERNEL); - if (tdev == NULL) { - dev_err(&dev->dev, "%s - out of memory\n", __func__); - return -ENOMEM; - } - mutex_init(&tdev->td_open_close_lock); - tdev->td_serial = serial; - usb_set_serial_data(serial, tdev); - - /* determine device type */ - if (usb_match_id(serial->interface, ti_id_table_3410)) - tdev->td_is_3410 = 1; - dbg("%s - device type is %s", __func__, - tdev->td_is_3410 ? "3410" : "5052"); - - /* if we have only 1 configuration, download firmware */ - if (dev->descriptor.bNumConfigurations == 1) { - if ((status = ti_download_firmware(tdev)) != 0) - goto free_tdev; - - /* 3410 must be reset, 5052 resets itself */ - if (tdev->td_is_3410) { - msleep_interruptible(100); - usb_reset_device(dev); - } - - status = -ENODEV; - goto free_tdev; - } - - /* the second configuration must be set */ - if (dev->actconfig->desc.bConfigurationValue == TI_BOOT_CONFIG) { - status = usb_driver_set_configuration(dev, TI_ACTIVE_CONFIG); - status = status ? status : -ENODEV; - goto free_tdev; - } - - /* set up port structures */ - for (i = 0; i < serial->num_ports; ++i) { - tport = kzalloc(sizeof(struct ti_port), GFP_KERNEL); - if (tport == NULL) { - dev_err(&dev->dev, "%s - out of memory\n", __func__); - status = -ENOMEM; - goto free_tports; - } - spin_lock_init(&tport->tp_lock); - tport->tp_uart_base_addr = (i == 0 ? - TI_UART1_BASE_ADDR : TI_UART2_BASE_ADDR); - tport->tp_closing_wait = closing_wait; - init_waitqueue_head(&tport->tp_msr_wait); - init_waitqueue_head(&tport->tp_write_wait); - if (kfifo_alloc(&tport->write_fifo, TI_WRITE_BUF_SIZE, - GFP_KERNEL)) { - dev_err(&dev->dev, "%s - out of memory\n", __func__); - kfree(tport); - status = -ENOMEM; - goto free_tports; - } - tport->tp_port = serial->port[i]; - tport->tp_tdev = tdev; - usb_set_serial_port_data(serial->port[i], tport); - tport->tp_uart_mode = 0; /* default is RS232 */ - } - - return 0; - -free_tports: - for (--i; i >= 0; --i) { - tport = usb_get_serial_port_data(serial->port[i]); - kfifo_free(&tport->write_fifo); - kfree(tport); - usb_set_serial_port_data(serial->port[i], NULL); - } -free_tdev: - kfree(tdev); - usb_set_serial_data(serial, NULL); - return status; -} - - -static void ti_release(struct usb_serial *serial) -{ - int i; - struct ti_device *tdev = usb_get_serial_data(serial); - struct ti_port *tport; - - dbg("%s", __func__); - - for (i = 0; i < serial->num_ports; ++i) { - tport = usb_get_serial_port_data(serial->port[i]); - if (tport) { - kfifo_free(&tport->write_fifo); - kfree(tport); - } - } - - kfree(tdev); -} - - -static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct ti_port *tport = usb_get_serial_port_data(port); - struct ti_device *tdev; - struct usb_device *dev; - struct urb *urb; - int port_number; - int status; - __u16 open_settings = (__u8)(TI_PIPE_MODE_CONTINOUS | - TI_PIPE_TIMEOUT_ENABLE | - (TI_TRANSFER_TIMEOUT << 2)); - - dbg("%s - port %d", __func__, port->number); - - if (tport == NULL) - return -ENODEV; - - dev = port->serial->dev; - tdev = tport->tp_tdev; - - /* only one open on any port on a device at a time */ - if (mutex_lock_interruptible(&tdev->td_open_close_lock)) - return -ERESTARTSYS; - - port_number = port->number - port->serial->minor; - - memset(&(tport->tp_icount), 0x00, sizeof(tport->tp_icount)); - - tport->tp_msr = 0; - tport->tp_shadow_mcr |= (TI_MCR_RTS | TI_MCR_DTR); - - /* start interrupt urb the first time a port is opened on this device */ - if (tdev->td_open_port_count == 0) { - dbg("%s - start interrupt in urb", __func__); - urb = tdev->td_serial->port[0]->interrupt_in_urb; - if (!urb) { - dev_err(&port->dev, "%s - no interrupt urb\n", - __func__); - status = -EINVAL; - goto release_lock; - } - urb->context = tdev; - status = usb_submit_urb(urb, GFP_KERNEL); - if (status) { - dev_err(&port->dev, - "%s - submit interrupt urb failed, %d\n", - __func__, status); - goto release_lock; - } - } - - if (tty) - ti_set_termios(tty, port, tty->termios); - - dbg("%s - sending TI_OPEN_PORT", __func__); - status = ti_command_out_sync(tdev, TI_OPEN_PORT, - (__u8)(TI_UART1_PORT + port_number), open_settings, NULL, 0); - if (status) { - dev_err(&port->dev, "%s - cannot send open command, %d\n", - __func__, status); - goto unlink_int_urb; - } - - dbg("%s - sending TI_START_PORT", __func__); - status = ti_command_out_sync(tdev, TI_START_PORT, - (__u8)(TI_UART1_PORT + port_number), 0, NULL, 0); - if (status) { - dev_err(&port->dev, "%s - cannot send start command, %d\n", - __func__, status); - goto unlink_int_urb; - } - - dbg("%s - sending TI_PURGE_PORT", __func__); - status = ti_command_out_sync(tdev, TI_PURGE_PORT, - (__u8)(TI_UART1_PORT + port_number), TI_PURGE_INPUT, NULL, 0); - if (status) { - dev_err(&port->dev, "%s - cannot clear input buffers, %d\n", - __func__, status); - goto unlink_int_urb; - } - status = ti_command_out_sync(tdev, TI_PURGE_PORT, - (__u8)(TI_UART1_PORT + port_number), TI_PURGE_OUTPUT, NULL, 0); - if (status) { - dev_err(&port->dev, "%s - cannot clear output buffers, %d\n", - __func__, status); - goto unlink_int_urb; - } - - /* reset the data toggle on the bulk endpoints to work around bug in - * host controllers where things get out of sync some times */ - usb_clear_halt(dev, port->write_urb->pipe); - usb_clear_halt(dev, port->read_urb->pipe); - - if (tty) - ti_set_termios(tty, port, tty->termios); - - dbg("%s - sending TI_OPEN_PORT (2)", __func__); - status = ti_command_out_sync(tdev, TI_OPEN_PORT, - (__u8)(TI_UART1_PORT + port_number), open_settings, NULL, 0); - if (status) { - dev_err(&port->dev, "%s - cannot send open command (2), %d\n", - __func__, status); - goto unlink_int_urb; - } - - dbg("%s - sending TI_START_PORT (2)", __func__); - status = ti_command_out_sync(tdev, TI_START_PORT, - (__u8)(TI_UART1_PORT + port_number), 0, NULL, 0); - if (status) { - dev_err(&port->dev, "%s - cannot send start command (2), %d\n", - __func__, status); - goto unlink_int_urb; - } - - /* start read urb */ - dbg("%s - start read urb", __func__); - urb = port->read_urb; - if (!urb) { - dev_err(&port->dev, "%s - no read urb\n", __func__); - status = -EINVAL; - goto unlink_int_urb; - } - tport->tp_read_urb_state = TI_READ_URB_RUNNING; - urb->context = tport; - status = usb_submit_urb(urb, GFP_KERNEL); - if (status) { - dev_err(&port->dev, "%s - submit read urb failed, %d\n", - __func__, status); - goto unlink_int_urb; - } - - tport->tp_is_open = 1; - ++tdev->td_open_port_count; - - goto release_lock; - -unlink_int_urb: - if (tdev->td_open_port_count == 0) - usb_kill_urb(port->serial->port[0]->interrupt_in_urb); -release_lock: - mutex_unlock(&tdev->td_open_close_lock); - dbg("%s - exit %d", __func__, status); - return status; -} - - -static void ti_close(struct usb_serial_port *port) -{ - struct ti_device *tdev; - struct ti_port *tport; - int port_number; - int status; - int do_unlock; - - dbg("%s - port %d", __func__, port->number); - - tdev = usb_get_serial_data(port->serial); - tport = usb_get_serial_port_data(port); - if (tdev == NULL || tport == NULL) - return; - - tport->tp_is_open = 0; - - ti_drain(tport, (tport->tp_closing_wait*HZ)/100, 1); - - usb_kill_urb(port->read_urb); - usb_kill_urb(port->write_urb); - tport->tp_write_urb_in_use = 0; - - port_number = port->number - port->serial->minor; - - dbg("%s - sending TI_CLOSE_PORT", __func__); - status = ti_command_out_sync(tdev, TI_CLOSE_PORT, - (__u8)(TI_UART1_PORT + port_number), 0, NULL, 0); - if (status) - dev_err(&port->dev, - "%s - cannot send close port command, %d\n" - , __func__, status); - - /* if mutex_lock is interrupted, continue anyway */ - do_unlock = !mutex_lock_interruptible(&tdev->td_open_close_lock); - --tport->tp_tdev->td_open_port_count; - if (tport->tp_tdev->td_open_port_count <= 0) { - /* last port is closed, shut down interrupt urb */ - usb_kill_urb(port->serial->port[0]->interrupt_in_urb); - tport->tp_tdev->td_open_port_count = 0; - } - if (do_unlock) - mutex_unlock(&tdev->td_open_close_lock); - - dbg("%s - exit", __func__); -} - - -static int ti_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *data, int count) -{ - struct ti_port *tport = usb_get_serial_port_data(port); - - dbg("%s - port %d", __func__, port->number); - - if (count == 0) { - dbg("%s - write request of 0 bytes", __func__); - return 0; - } - - if (tport == NULL || !tport->tp_is_open) - return -ENODEV; - - count = kfifo_in_locked(&tport->write_fifo, data, count, - &tport->tp_lock); - ti_send(tport); - - return count; -} - - -static int ti_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct ti_port *tport = usb_get_serial_port_data(port); - int room = 0; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - if (tport == NULL) - return 0; - - spin_lock_irqsave(&tport->tp_lock, flags); - room = kfifo_avail(&tport->write_fifo); - spin_unlock_irqrestore(&tport->tp_lock, flags); - - dbg("%s - returns %d", __func__, room); - return room; -} - - -static int ti_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct ti_port *tport = usb_get_serial_port_data(port); - int chars = 0; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - if (tport == NULL) - return 0; - - spin_lock_irqsave(&tport->tp_lock, flags); - chars = kfifo_len(&tport->write_fifo); - spin_unlock_irqrestore(&tport->tp_lock, flags); - - dbg("%s - returns %d", __func__, chars); - return chars; -} - - -static void ti_throttle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct ti_port *tport = usb_get_serial_port_data(port); - - dbg("%s - port %d", __func__, port->number); - - if (tport == NULL) - return; - - if (I_IXOFF(tty) || C_CRTSCTS(tty)) - ti_stop_read(tport, tty); - -} - - -static void ti_unthrottle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct ti_port *tport = usb_get_serial_port_data(port); - int status; - - dbg("%s - port %d", __func__, port->number); - - if (tport == NULL) - return; - - if (I_IXOFF(tty) || C_CRTSCTS(tty)) { - status = ti_restart_read(tport, tty); - if (status) - dev_err(&port->dev, "%s - cannot restart read, %d\n", - __func__, status); - } -} - -static int ti_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - struct ti_port *tport = usb_get_serial_port_data(port); - struct async_icount cnow = tport->tp_icount; - - dbg("%s - (%d) TIOCGICOUNT RX=%d, TX=%d", - __func__, port->number, - cnow.rx, cnow.tx); - - icount->cts = cnow.cts; - icount->dsr = cnow.dsr; - icount->rng = cnow.rng; - icount->dcd = cnow.dcd; - icount->rx = cnow.rx; - icount->tx = cnow.tx; - icount->frame = cnow.frame; - icount->overrun = cnow.overrun; - icount->parity = cnow.parity; - icount->brk = cnow.brk; - icount->buf_overrun = cnow.buf_overrun; - - return 0; -} - -static int ti_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - struct ti_port *tport = usb_get_serial_port_data(port); - struct async_icount cnow; - struct async_icount cprev; - - dbg("%s - port %d, cmd = 0x%04X", __func__, port->number, cmd); - - if (tport == NULL) - return -ENODEV; - - switch (cmd) { - case TIOCGSERIAL: - dbg("%s - (%d) TIOCGSERIAL", __func__, port->number); - return ti_get_serial_info(tport, - (struct serial_struct __user *)arg); - case TIOCSSERIAL: - dbg("%s - (%d) TIOCSSERIAL", __func__, port->number); - return ti_set_serial_info(tty, tport, - (struct serial_struct __user *)arg); - case TIOCMIWAIT: - dbg("%s - (%d) TIOCMIWAIT", __func__, port->number); - cprev = tport->tp_icount; - while (1) { - interruptible_sleep_on(&tport->tp_msr_wait); - if (signal_pending(current)) - return -ERESTARTSYS; - cnow = tport->tp_icount; - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) - return 0; - cprev = cnow; - } - break; - } - return -ENOIOCTLCMD; -} - - -static void ti_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) -{ - struct ti_port *tport = usb_get_serial_port_data(port); - struct ti_uart_config *config; - tcflag_t cflag, iflag; - int baud; - int status; - int port_number = port->number - port->serial->minor; - unsigned int mcr; - - dbg("%s - port %d", __func__, port->number); - - cflag = tty->termios->c_cflag; - iflag = tty->termios->c_iflag; - - dbg("%s - cflag %08x, iflag %08x", __func__, cflag, iflag); - dbg("%s - old clfag %08x, old iflag %08x", __func__, - old_termios->c_cflag, old_termios->c_iflag); - - if (tport == NULL) - return; - - config = kmalloc(sizeof(*config), GFP_KERNEL); - if (!config) { - dev_err(&port->dev, "%s - out of memory\n", __func__); - return; - } - - config->wFlags = 0; - - /* these flags must be set */ - config->wFlags |= TI_UART_ENABLE_MS_INTS; - config->wFlags |= TI_UART_ENABLE_AUTO_START_DMA; - config->bUartMode = (__u8)(tport->tp_uart_mode); - - switch (cflag & CSIZE) { - case CS5: - config->bDataBits = TI_UART_5_DATA_BITS; - break; - case CS6: - config->bDataBits = TI_UART_6_DATA_BITS; - break; - case CS7: - config->bDataBits = TI_UART_7_DATA_BITS; - break; - default: - case CS8: - config->bDataBits = TI_UART_8_DATA_BITS; - break; - } - - /* CMSPAR isn't supported by this driver */ - tty->termios->c_cflag &= ~CMSPAR; - - if (cflag & PARENB) { - if (cflag & PARODD) { - config->wFlags |= TI_UART_ENABLE_PARITY_CHECKING; - config->bParity = TI_UART_ODD_PARITY; - } else { - config->wFlags |= TI_UART_ENABLE_PARITY_CHECKING; - config->bParity = TI_UART_EVEN_PARITY; - } - } else { - config->wFlags &= ~TI_UART_ENABLE_PARITY_CHECKING; - config->bParity = TI_UART_NO_PARITY; - } - - if (cflag & CSTOPB) - config->bStopBits = TI_UART_2_STOP_BITS; - else - config->bStopBits = TI_UART_1_STOP_BITS; - - if (cflag & CRTSCTS) { - /* RTS flow control must be off to drop RTS for baud rate B0 */ - if ((cflag & CBAUD) != B0) - config->wFlags |= TI_UART_ENABLE_RTS_IN; - config->wFlags |= TI_UART_ENABLE_CTS_OUT; - } else { - tty->hw_stopped = 0; - ti_restart_read(tport, tty); - } - - if (I_IXOFF(tty) || I_IXON(tty)) { - config->cXon = START_CHAR(tty); - config->cXoff = STOP_CHAR(tty); - - if (I_IXOFF(tty)) - config->wFlags |= TI_UART_ENABLE_X_IN; - else - ti_restart_read(tport, tty); - - if (I_IXON(tty)) - config->wFlags |= TI_UART_ENABLE_X_OUT; - } - - baud = tty_get_baud_rate(tty); - if (!baud) - baud = 9600; - if (tport->tp_tdev->td_is_3410) - config->wBaudRate = (__u16)((923077 + baud/2) / baud); - else - config->wBaudRate = (__u16)((461538 + baud/2) / baud); - - /* FIXME: Should calculate resulting baud here and report it back */ - if ((cflag & CBAUD) != B0) - tty_encode_baud_rate(tty, baud, baud); - - dbg("%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d", - __func__, baud, config->wBaudRate, config->wFlags, config->bDataBits, config->bParity, config->bStopBits, config->cXon, config->cXoff, config->bUartMode); - - cpu_to_be16s(&config->wBaudRate); - cpu_to_be16s(&config->wFlags); - - status = ti_command_out_sync(tport->tp_tdev, TI_SET_CONFIG, - (__u8)(TI_UART1_PORT + port_number), 0, (__u8 *)config, - sizeof(*config)); - if (status) - dev_err(&port->dev, "%s - cannot set config on port %d, %d\n", - __func__, port_number, status); - - /* SET_CONFIG asserts RTS and DTR, reset them correctly */ - mcr = tport->tp_shadow_mcr; - /* if baud rate is B0, clear RTS and DTR */ - if ((cflag & CBAUD) == B0) - mcr &= ~(TI_MCR_DTR | TI_MCR_RTS); - status = ti_set_mcr(tport, mcr); - if (status) - dev_err(&port->dev, - "%s - cannot set modem control on port %d, %d\n", - __func__, port_number, status); - - kfree(config); -} - - -static int ti_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct ti_port *tport = usb_get_serial_port_data(port); - unsigned int result; - unsigned int msr; - unsigned int mcr; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - if (tport == NULL) - return -ENODEV; - - spin_lock_irqsave(&tport->tp_lock, flags); - msr = tport->tp_msr; - mcr = tport->tp_shadow_mcr; - spin_unlock_irqrestore(&tport->tp_lock, flags); - - result = ((mcr & TI_MCR_DTR) ? TIOCM_DTR : 0) - | ((mcr & TI_MCR_RTS) ? TIOCM_RTS : 0) - | ((mcr & TI_MCR_LOOP) ? TIOCM_LOOP : 0) - | ((msr & TI_MSR_CTS) ? TIOCM_CTS : 0) - | ((msr & TI_MSR_CD) ? TIOCM_CAR : 0) - | ((msr & TI_MSR_RI) ? TIOCM_RI : 0) - | ((msr & TI_MSR_DSR) ? TIOCM_DSR : 0); - - dbg("%s - 0x%04X", __func__, result); - - return result; -} - - -static int ti_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct ti_port *tport = usb_get_serial_port_data(port); - unsigned int mcr; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - if (tport == NULL) - return -ENODEV; - - spin_lock_irqsave(&tport->tp_lock, flags); - mcr = tport->tp_shadow_mcr; - - if (set & TIOCM_RTS) - mcr |= TI_MCR_RTS; - if (set & TIOCM_DTR) - mcr |= TI_MCR_DTR; - if (set & TIOCM_LOOP) - mcr |= TI_MCR_LOOP; - - if (clear & TIOCM_RTS) - mcr &= ~TI_MCR_RTS; - if (clear & TIOCM_DTR) - mcr &= ~TI_MCR_DTR; - if (clear & TIOCM_LOOP) - mcr &= ~TI_MCR_LOOP; - spin_unlock_irqrestore(&tport->tp_lock, flags); - - return ti_set_mcr(tport, mcr); -} - - -static void ti_break(struct tty_struct *tty, int break_state) -{ - struct usb_serial_port *port = tty->driver_data; - struct ti_port *tport = usb_get_serial_port_data(port); - int status; - - dbg("%s - state = %d", __func__, break_state); - - if (tport == NULL) - return; - - ti_drain(tport, (tport->tp_closing_wait*HZ)/100, 0); - - status = ti_write_byte(tport->tp_tdev, - tport->tp_uart_base_addr + TI_UART_OFFSET_LCR, - TI_LCR_BREAK, break_state == -1 ? TI_LCR_BREAK : 0); - - if (status) - dbg("%s - error setting break, %d", __func__, status); -} - - -static void ti_interrupt_callback(struct urb *urb) -{ - struct ti_device *tdev = urb->context; - struct usb_serial_port *port; - struct usb_serial *serial = tdev->td_serial; - struct ti_port *tport; - struct device *dev = &urb->dev->dev; - unsigned char *data = urb->transfer_buffer; - int length = urb->actual_length; - int port_number; - int function; - int status = urb->status; - int retval; - __u8 msr; - - dbg("%s", __func__); - - switch (status) { - case 0: - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - dbg("%s - urb shutting down, %d", __func__, status); - tdev->td_urb_error = 1; - return; - default: - dev_err(dev, "%s - nonzero urb status, %d\n", - __func__, status); - tdev->td_urb_error = 1; - goto exit; - } - - if (length != 2) { - dbg("%s - bad packet size, %d", __func__, length); - goto exit; - } - - if (data[0] == TI_CODE_HARDWARE_ERROR) { - dev_err(dev, "%s - hardware error, %d\n", __func__, data[1]); - goto exit; - } - - port_number = TI_GET_PORT_FROM_CODE(data[0]); - function = TI_GET_FUNC_FROM_CODE(data[0]); - - dbg("%s - port_number %d, function %d, data 0x%02X", - __func__, port_number, function, data[1]); - - if (port_number >= serial->num_ports) { - dev_err(dev, "%s - bad port number, %d\n", - __func__, port_number); - goto exit; - } - - port = serial->port[port_number]; - - tport = usb_get_serial_port_data(port); - if (!tport) - goto exit; - - switch (function) { - case TI_CODE_DATA_ERROR: - dev_err(dev, "%s - DATA ERROR, port %d, data 0x%02X\n", - __func__, port_number, data[1]); - break; - - case TI_CODE_MODEM_STATUS: - msr = data[1]; - dbg("%s - port %d, msr 0x%02X", __func__, port_number, msr); - ti_handle_new_msr(tport, msr); - break; - - default: - dev_err(dev, "%s - unknown interrupt code, 0x%02X\n", - __func__, data[1]); - break; - } - -exit: - retval = usb_submit_urb(urb, GFP_ATOMIC); - if (retval) - dev_err(dev, "%s - resubmit interrupt urb failed, %d\n", - __func__, retval); -} - - -static void ti_bulk_in_callback(struct urb *urb) -{ - struct ti_port *tport = urb->context; - struct usb_serial_port *port = tport->tp_port; - struct device *dev = &urb->dev->dev; - int status = urb->status; - int retval = 0; - struct tty_struct *tty; - - dbg("%s", __func__); - - switch (status) { - case 0: - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - dbg("%s - urb shutting down, %d", __func__, status); - tport->tp_tdev->td_urb_error = 1; - wake_up_interruptible(&tport->tp_write_wait); - return; - default: - dev_err(dev, "%s - nonzero urb status, %d\n", - __func__, status); - tport->tp_tdev->td_urb_error = 1; - wake_up_interruptible(&tport->tp_write_wait); - } - - if (status == -EPIPE) - goto exit; - - if (status) { - dev_err(dev, "%s - stopping read!\n", __func__); - return; - } - - tty = tty_port_tty_get(&port->port); - if (tty) { - if (urb->actual_length) { - usb_serial_debug_data(debug, dev, __func__, - urb->actual_length, urb->transfer_buffer); - - if (!tport->tp_is_open) - dbg("%s - port closed, dropping data", - __func__); - else - ti_recv(&urb->dev->dev, tty, - urb->transfer_buffer, - urb->actual_length); - spin_lock(&tport->tp_lock); - tport->tp_icount.rx += urb->actual_length; - spin_unlock(&tport->tp_lock); - } - tty_kref_put(tty); - } - -exit: - /* continue to read unless stopping */ - spin_lock(&tport->tp_lock); - if (tport->tp_read_urb_state == TI_READ_URB_RUNNING) - retval = usb_submit_urb(urb, GFP_ATOMIC); - else if (tport->tp_read_urb_state == TI_READ_URB_STOPPING) - tport->tp_read_urb_state = TI_READ_URB_STOPPED; - - spin_unlock(&tport->tp_lock); - if (retval) - dev_err(dev, "%s - resubmit read urb failed, %d\n", - __func__, retval); -} - - -static void ti_bulk_out_callback(struct urb *urb) -{ - struct ti_port *tport = urb->context; - struct usb_serial_port *port = tport->tp_port; - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - - tport->tp_write_urb_in_use = 0; - - switch (status) { - case 0: - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - dbg("%s - urb shutting down, %d", __func__, status); - tport->tp_tdev->td_urb_error = 1; - wake_up_interruptible(&tport->tp_write_wait); - return; - default: - dev_err_console(port, "%s - nonzero urb status, %d\n", - __func__, status); - tport->tp_tdev->td_urb_error = 1; - wake_up_interruptible(&tport->tp_write_wait); - } - - /* send any buffered data */ - ti_send(tport); -} - - -static void ti_recv(struct device *dev, struct tty_struct *tty, - unsigned char *data, int length) -{ - int cnt; - - do { - cnt = tty_insert_flip_string(tty, data, length); - if (cnt < length) { - dev_err(dev, "%s - dropping data, %d bytes lost\n", - __func__, length - cnt); - if (cnt == 0) - break; - } - tty_flip_buffer_push(tty); - data += cnt; - length -= cnt; - } while (length > 0); - -} - - -static void ti_send(struct ti_port *tport) -{ - int count, result; - struct usb_serial_port *port = tport->tp_port; - struct tty_struct *tty = tty_port_tty_get(&port->port); /* FIXME */ - unsigned long flags; - - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&tport->tp_lock, flags); - - if (tport->tp_write_urb_in_use) - goto unlock; - - count = kfifo_out(&tport->write_fifo, - port->write_urb->transfer_buffer, - port->bulk_out_size); - - if (count == 0) - goto unlock; - - tport->tp_write_urb_in_use = 1; - - spin_unlock_irqrestore(&tport->tp_lock, flags); - - usb_serial_debug_data(debug, &port->dev, __func__, count, - port->write_urb->transfer_buffer); - - usb_fill_bulk_urb(port->write_urb, port->serial->dev, - usb_sndbulkpipe(port->serial->dev, - port->bulk_out_endpointAddress), - port->write_urb->transfer_buffer, count, - ti_bulk_out_callback, tport); - - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (result) { - dev_err_console(port, "%s - submit write urb failed, %d\n", - __func__, result); - tport->tp_write_urb_in_use = 0; - /* TODO: reschedule ti_send */ - } else { - spin_lock_irqsave(&tport->tp_lock, flags); - tport->tp_icount.tx += count; - spin_unlock_irqrestore(&tport->tp_lock, flags); - } - - /* more room in the buffer for new writes, wakeup */ - if (tty) - tty_wakeup(tty); - tty_kref_put(tty); - wake_up_interruptible(&tport->tp_write_wait); - return; -unlock: - spin_unlock_irqrestore(&tport->tp_lock, flags); - tty_kref_put(tty); - return; -} - - -static int ti_set_mcr(struct ti_port *tport, unsigned int mcr) -{ - unsigned long flags; - int status; - - status = ti_write_byte(tport->tp_tdev, - tport->tp_uart_base_addr + TI_UART_OFFSET_MCR, - TI_MCR_RTS | TI_MCR_DTR | TI_MCR_LOOP, mcr); - - spin_lock_irqsave(&tport->tp_lock, flags); - if (!status) - tport->tp_shadow_mcr = mcr; - spin_unlock_irqrestore(&tport->tp_lock, flags); - - return status; -} - - -static int ti_get_lsr(struct ti_port *tport) -{ - int size, status; - struct ti_device *tdev = tport->tp_tdev; - struct usb_serial_port *port = tport->tp_port; - int port_number = port->number - port->serial->minor; - struct ti_port_status *data; - - dbg("%s - port %d", __func__, port->number); - - size = sizeof(struct ti_port_status); - data = kmalloc(size, GFP_KERNEL); - if (!data) { - dev_err(&port->dev, "%s - out of memory\n", __func__); - return -ENOMEM; - } - - status = ti_command_in_sync(tdev, TI_GET_PORT_STATUS, - (__u8)(TI_UART1_PORT+port_number), 0, (__u8 *)data, size); - if (status) { - dev_err(&port->dev, - "%s - get port status command failed, %d\n", - __func__, status); - goto free_data; - } - - dbg("%s - lsr 0x%02X", __func__, data->bLSR); - - tport->tp_lsr = data->bLSR; - -free_data: - kfree(data); - return status; -} - - -static int ti_get_serial_info(struct ti_port *tport, - struct serial_struct __user *ret_arg) -{ - struct usb_serial_port *port = tport->tp_port; - struct serial_struct ret_serial; - - if (!ret_arg) - return -EFAULT; - - memset(&ret_serial, 0, sizeof(ret_serial)); - - ret_serial.type = PORT_16550A; - ret_serial.line = port->serial->minor; - ret_serial.port = port->number - port->serial->minor; - ret_serial.flags = tport->tp_flags; - ret_serial.xmit_fifo_size = TI_WRITE_BUF_SIZE; - ret_serial.baud_base = tport->tp_tdev->td_is_3410 ? 921600 : 460800; - ret_serial.closing_wait = tport->tp_closing_wait; - - if (copy_to_user(ret_arg, &ret_serial, sizeof(*ret_arg))) - return -EFAULT; - - return 0; -} - - -static int ti_set_serial_info(struct tty_struct *tty, struct ti_port *tport, - struct serial_struct __user *new_arg) -{ - struct serial_struct new_serial; - - if (copy_from_user(&new_serial, new_arg, sizeof(new_serial))) - return -EFAULT; - - tport->tp_flags = new_serial.flags & TI_SET_SERIAL_FLAGS; - tport->tp_closing_wait = new_serial.closing_wait; - - return 0; -} - - -static void ti_handle_new_msr(struct ti_port *tport, __u8 msr) -{ - struct async_icount *icount; - struct tty_struct *tty; - unsigned long flags; - - dbg("%s - msr 0x%02X", __func__, msr); - - if (msr & TI_MSR_DELTA_MASK) { - spin_lock_irqsave(&tport->tp_lock, flags); - icount = &tport->tp_icount; - if (msr & TI_MSR_DELTA_CTS) - icount->cts++; - if (msr & TI_MSR_DELTA_DSR) - icount->dsr++; - if (msr & TI_MSR_DELTA_CD) - icount->dcd++; - if (msr & TI_MSR_DELTA_RI) - icount->rng++; - wake_up_interruptible(&tport->tp_msr_wait); - spin_unlock_irqrestore(&tport->tp_lock, flags); - } - - tport->tp_msr = msr & TI_MSR_MASK; - - /* handle CTS flow control */ - tty = tty_port_tty_get(&tport->tp_port->port); - if (tty && C_CRTSCTS(tty)) { - if (msr & TI_MSR_CTS) { - tty->hw_stopped = 0; - tty_wakeup(tty); - } else { - tty->hw_stopped = 1; - } - } - tty_kref_put(tty); -} - - -static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush) -{ - struct ti_device *tdev = tport->tp_tdev; - struct usb_serial_port *port = tport->tp_port; - wait_queue_t wait; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irq(&tport->tp_lock); - - /* wait for data to drain from the buffer */ - tdev->td_urb_error = 0; - init_waitqueue_entry(&wait, current); - add_wait_queue(&tport->tp_write_wait, &wait); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (kfifo_len(&tport->write_fifo) == 0 - || timeout == 0 || signal_pending(current) - || tdev->td_urb_error - || port->serial->disconnected) /* disconnect */ - break; - spin_unlock_irq(&tport->tp_lock); - timeout = schedule_timeout(timeout); - spin_lock_irq(&tport->tp_lock); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&tport->tp_write_wait, &wait); - - /* flush any remaining data in the buffer */ - if (flush) - kfifo_reset_out(&tport->write_fifo); - - spin_unlock_irq(&tport->tp_lock); - - mutex_lock(&port->serial->disc_mutex); - /* wait for data to drain from the device */ - /* wait for empty tx register, plus 20 ms */ - timeout += jiffies; - tport->tp_lsr &= ~TI_LSR_TX_EMPTY; - while ((long)(jiffies - timeout) < 0 && !signal_pending(current) - && !(tport->tp_lsr&TI_LSR_TX_EMPTY) && !tdev->td_urb_error - && !port->serial->disconnected) { - if (ti_get_lsr(tport)) - break; - mutex_unlock(&port->serial->disc_mutex); - msleep_interruptible(20); - mutex_lock(&port->serial->disc_mutex); - } - mutex_unlock(&port->serial->disc_mutex); -} - - -static void ti_stop_read(struct ti_port *tport, struct tty_struct *tty) -{ - unsigned long flags; - - spin_lock_irqsave(&tport->tp_lock, flags); - - if (tport->tp_read_urb_state == TI_READ_URB_RUNNING) - tport->tp_read_urb_state = TI_READ_URB_STOPPING; - - spin_unlock_irqrestore(&tport->tp_lock, flags); -} - - -static int ti_restart_read(struct ti_port *tport, struct tty_struct *tty) -{ - struct urb *urb; - int status = 0; - unsigned long flags; - - spin_lock_irqsave(&tport->tp_lock, flags); - - if (tport->tp_read_urb_state == TI_READ_URB_STOPPED) { - tport->tp_read_urb_state = TI_READ_URB_RUNNING; - urb = tport->tp_port->read_urb; - spin_unlock_irqrestore(&tport->tp_lock, flags); - urb->context = tport; - status = usb_submit_urb(urb, GFP_KERNEL); - } else { - tport->tp_read_urb_state = TI_READ_URB_RUNNING; - spin_unlock_irqrestore(&tport->tp_lock, flags); - } - - return status; -} - - -static int ti_command_out_sync(struct ti_device *tdev, __u8 command, - __u16 moduleid, __u16 value, __u8 *data, int size) -{ - int status; - - status = usb_control_msg(tdev->td_serial->dev, - usb_sndctrlpipe(tdev->td_serial->dev, 0), command, - (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT), - value, moduleid, data, size, 1000); - - if (status == size) - status = 0; - - if (status > 0) - status = -ECOMM; - - return status; -} - - -static int ti_command_in_sync(struct ti_device *tdev, __u8 command, - __u16 moduleid, __u16 value, __u8 *data, int size) -{ - int status; - - status = usb_control_msg(tdev->td_serial->dev, - usb_rcvctrlpipe(tdev->td_serial->dev, 0), command, - (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN), - value, moduleid, data, size, 1000); - - if (status == size) - status = 0; - - if (status > 0) - status = -ECOMM; - - return status; -} - - -static int ti_write_byte(struct ti_device *tdev, unsigned long addr, - __u8 mask, __u8 byte) -{ - int status; - unsigned int size; - struct ti_write_data_bytes *data; - struct device *dev = &tdev->td_serial->dev->dev; - - dbg("%s - addr 0x%08lX, mask 0x%02X, byte 0x%02X", - __func__, addr, mask, byte); - - size = sizeof(struct ti_write_data_bytes) + 2; - data = kmalloc(size, GFP_KERNEL); - if (!data) { - dev_err(dev, "%s - out of memory\n", __func__); - return -ENOMEM; - } - - data->bAddrType = TI_RW_DATA_ADDR_XDATA; - data->bDataType = TI_RW_DATA_BYTE; - data->bDataCounter = 1; - data->wBaseAddrHi = cpu_to_be16(addr>>16); - data->wBaseAddrLo = cpu_to_be16(addr); - data->bData[0] = mask; - data->bData[1] = byte; - - status = ti_command_out_sync(tdev, TI_WRITE_DATA, TI_RAM_PORT, 0, - (__u8 *)data, size); - - if (status < 0) - dev_err(dev, "%s - failed, %d\n", __func__, status); - - kfree(data); - - return status; -} - -static int ti_do_download(struct usb_device *dev, int pipe, - u8 *buffer, int size) -{ - int pos; - u8 cs = 0; - int done; - struct ti_firmware_header *header; - int status = 0; - int len; - - for (pos = sizeof(struct ti_firmware_header); pos < size; pos++) - cs = (__u8)(cs + buffer[pos]); - - header = (struct ti_firmware_header *)buffer; - header->wLength = cpu_to_le16((__u16)(size - - sizeof(struct ti_firmware_header))); - header->bCheckSum = cs; - - dbg("%s - downloading firmware", __func__); - for (pos = 0; pos < size; pos += done) { - len = min(size - pos, TI_DOWNLOAD_MAX_PACKET_SIZE); - status = usb_bulk_msg(dev, pipe, buffer + pos, len, - &done, 1000); - if (status) - break; - } - return status; -} - -static int ti_download_firmware(struct ti_device *tdev) -{ - int status; - int buffer_size; - __u8 *buffer; - struct usb_device *dev = tdev->td_serial->dev; - unsigned int pipe = usb_sndbulkpipe(dev, - tdev->td_serial->port[0]->bulk_out_endpointAddress); - const struct firmware *fw_p; - char buf[32]; - - dbg("%s\n", __func__); - /* try ID specific firmware first, then try generic firmware */ - sprintf(buf, "ti_usb-v%04x-p%04x.fw", dev->descriptor.idVendor, - dev->descriptor.idProduct); - if ((status = request_firmware(&fw_p, buf, &dev->dev)) != 0) { - buf[0] = '\0'; - if (dev->descriptor.idVendor == MTS_VENDOR_ID) { - switch (dev->descriptor.idProduct) { - case MTS_CDMA_PRODUCT_ID: - strcpy(buf, "mts_cdma.fw"); - break; - case MTS_GSM_PRODUCT_ID: - strcpy(buf, "mts_gsm.fw"); - break; - case MTS_EDGE_PRODUCT_ID: - strcpy(buf, "mts_edge.fw"); - break; - case MTS_MT9234MU_PRODUCT_ID: - strcpy(buf, "mts_mt9234mu.fw"); - break; - case MTS_MT9234ZBA_PRODUCT_ID: - strcpy(buf, "mts_mt9234zba.fw"); - break; - case MTS_MT9234ZBAOLD_PRODUCT_ID: - strcpy(buf, "mts_mt9234zba.fw"); - break; } - } - if (buf[0] == '\0') { - if (tdev->td_is_3410) - strcpy(buf, "ti_3410.fw"); - else - strcpy(buf, "ti_5052.fw"); - } - status = request_firmware(&fw_p, buf, &dev->dev); - } - if (status) { - dev_err(&dev->dev, "%s - firmware not found\n", __func__); - return -ENOENT; - } - if (fw_p->size > TI_FIRMWARE_BUF_SIZE) { - dev_err(&dev->dev, "%s - firmware too large %zu\n", __func__, fw_p->size); - release_firmware(fw_p); - return -ENOENT; - } - - buffer_size = TI_FIRMWARE_BUF_SIZE + sizeof(struct ti_firmware_header); - buffer = kmalloc(buffer_size, GFP_KERNEL); - if (buffer) { - memcpy(buffer, fw_p->data, fw_p->size); - memset(buffer + fw_p->size, 0xff, buffer_size - fw_p->size); - status = ti_do_download(dev, pipe, buffer, fw_p->size); - kfree(buffer); - } else { - dbg("%s ENOMEM\n", __func__); - status = -ENOMEM; - } - release_firmware(fw_p); - if (status) { - dev_err(&dev->dev, "%s - error downloading firmware, %d\n", - __func__, status); - return status; - } - - dbg("%s - download successful", __func__); - - return 0; -} diff --git a/ANDROID_3.4.5/drivers/usb/serial/ti_usb_3410_5052.h b/ANDROID_3.4.5/drivers/usb/serial/ti_usb_3410_5052.h deleted file mode 100644 index b353e7e3..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/ti_usb_3410_5052.h +++ /dev/null @@ -1,245 +0,0 @@ -/* vi: ts=8 sw=8 - * - * TI 3410/5052 USB Serial Driver Header - * - * Copyright (C) 2004 Texas Instruments - * - * This driver is based on the Linux io_ti driver, which is - * Copyright (C) 2000-2002 Inside Out Networks - * Copyright (C) 2001-2002 Greg Kroah-Hartman - * - * 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. - * - * For questions or problems with this driver, contact Texas Instruments - * technical support, or Al Borchers , or - * Peter Berger . - */ - -#ifndef _TI_3410_5052_H_ -#define _TI_3410_5052_H_ - -/* Configuration ids */ -#define TI_BOOT_CONFIG 1 -#define TI_ACTIVE_CONFIG 2 - -/* Vendor and product ids */ -#define TI_VENDOR_ID 0x0451 -#define IBM_VENDOR_ID 0x04b3 -#define TI_3410_PRODUCT_ID 0x3410 -#define IBM_4543_PRODUCT_ID 0x4543 -#define IBM_454B_PRODUCT_ID 0x454b -#define IBM_454C_PRODUCT_ID 0x454c -#define TI_3410_EZ430_ID 0xF430 /* TI ez430 development tool */ -#define TI_5052_BOOT_PRODUCT_ID 0x5052 /* no EEPROM, no firmware */ -#define TI_5152_BOOT_PRODUCT_ID 0x5152 /* no EEPROM, no firmware */ -#define TI_5052_EEPROM_PRODUCT_ID 0x505A /* EEPROM, no firmware */ -#define TI_5052_FIRMWARE_PRODUCT_ID 0x505F /* firmware is running */ -#define FRI2_PRODUCT_ID 0x5053 /* Fish River Island II */ - -/* Multi-Tech vendor and product ids */ -#define MTS_VENDOR_ID 0x06E0 -#define MTS_GSM_NO_FW_PRODUCT_ID 0xF108 -#define MTS_CDMA_NO_FW_PRODUCT_ID 0xF109 -#define MTS_CDMA_PRODUCT_ID 0xF110 -#define MTS_GSM_PRODUCT_ID 0xF111 -#define MTS_EDGE_PRODUCT_ID 0xF112 -#define MTS_MT9234MU_PRODUCT_ID 0xF114 -#define MTS_MT9234ZBA_PRODUCT_ID 0xF115 -#define MTS_MT9234ZBAOLD_PRODUCT_ID 0x0319 - -/* Abbott Diabetics vendor and product ids */ -#define ABBOTT_VENDOR_ID 0x1a61 -#define ABBOTT_PRODUCT_ID 0x3410 - -/* Commands */ -#define TI_GET_VERSION 0x01 -#define TI_GET_PORT_STATUS 0x02 -#define TI_GET_PORT_DEV_INFO 0x03 -#define TI_GET_CONFIG 0x04 -#define TI_SET_CONFIG 0x05 -#define TI_OPEN_PORT 0x06 -#define TI_CLOSE_PORT 0x07 -#define TI_START_PORT 0x08 -#define TI_STOP_PORT 0x09 -#define TI_TEST_PORT 0x0A -#define TI_PURGE_PORT 0x0B -#define TI_RESET_EXT_DEVICE 0x0C -#define TI_WRITE_DATA 0x80 -#define TI_READ_DATA 0x81 -#define TI_REQ_TYPE_CLASS 0x82 - -/* Module identifiers */ -#define TI_I2C_PORT 0x01 -#define TI_IEEE1284_PORT 0x02 -#define TI_UART1_PORT 0x03 -#define TI_UART2_PORT 0x04 -#define TI_RAM_PORT 0x05 - -/* Modem status */ -#define TI_MSR_DELTA_CTS 0x01 -#define TI_MSR_DELTA_DSR 0x02 -#define TI_MSR_DELTA_RI 0x04 -#define TI_MSR_DELTA_CD 0x08 -#define TI_MSR_CTS 0x10 -#define TI_MSR_DSR 0x20 -#define TI_MSR_RI 0x40 -#define TI_MSR_CD 0x80 -#define TI_MSR_DELTA_MASK 0x0F -#define TI_MSR_MASK 0xF0 - -/* Line status */ -#define TI_LSR_OVERRUN_ERROR 0x01 -#define TI_LSR_PARITY_ERROR 0x02 -#define TI_LSR_FRAMING_ERROR 0x04 -#define TI_LSR_BREAK 0x08 -#define TI_LSR_ERROR 0x0F -#define TI_LSR_RX_FULL 0x10 -#define TI_LSR_TX_EMPTY 0x20 - -/* Line control */ -#define TI_LCR_BREAK 0x40 - -/* Modem control */ -#define TI_MCR_LOOP 0x04 -#define TI_MCR_DTR 0x10 -#define TI_MCR_RTS 0x20 - -/* Mask settings */ -#define TI_UART_ENABLE_RTS_IN 0x0001 -#define TI_UART_DISABLE_RTS 0x0002 -#define TI_UART_ENABLE_PARITY_CHECKING 0x0008 -#define TI_UART_ENABLE_DSR_OUT 0x0010 -#define TI_UART_ENABLE_CTS_OUT 0x0020 -#define TI_UART_ENABLE_X_OUT 0x0040 -#define TI_UART_ENABLE_XA_OUT 0x0080 -#define TI_UART_ENABLE_X_IN 0x0100 -#define TI_UART_ENABLE_DTR_IN 0x0800 -#define TI_UART_DISABLE_DTR 0x1000 -#define TI_UART_ENABLE_MS_INTS 0x2000 -#define TI_UART_ENABLE_AUTO_START_DMA 0x4000 - -/* Parity */ -#define TI_UART_NO_PARITY 0x00 -#define TI_UART_ODD_PARITY 0x01 -#define TI_UART_EVEN_PARITY 0x02 -#define TI_UART_MARK_PARITY 0x03 -#define TI_UART_SPACE_PARITY 0x04 - -/* Stop bits */ -#define TI_UART_1_STOP_BITS 0x00 -#define TI_UART_1_5_STOP_BITS 0x01 -#define TI_UART_2_STOP_BITS 0x02 - -/* Bits per character */ -#define TI_UART_5_DATA_BITS 0x00 -#define TI_UART_6_DATA_BITS 0x01 -#define TI_UART_7_DATA_BITS 0x02 -#define TI_UART_8_DATA_BITS 0x03 - -/* 232/485 modes */ -#define TI_UART_232 0x00 -#define TI_UART_485_RECEIVER_DISABLED 0x01 -#define TI_UART_485_RECEIVER_ENABLED 0x02 - -/* Pipe transfer mode and timeout */ -#define TI_PIPE_MODE_CONTINOUS 0x01 -#define TI_PIPE_MODE_MASK 0x03 -#define TI_PIPE_TIMEOUT_MASK 0x7C -#define TI_PIPE_TIMEOUT_ENABLE 0x80 - -/* Config struct */ -struct ti_uart_config { - __u16 wBaudRate; - __u16 wFlags; - __u8 bDataBits; - __u8 bParity; - __u8 bStopBits; - char cXon; - char cXoff; - __u8 bUartMode; -} __attribute__((packed)); - -/* Get port status */ -struct ti_port_status { - __u8 bCmdCode; - __u8 bModuleId; - __u8 bErrorCode; - __u8 bMSR; - __u8 bLSR; -} __attribute__((packed)); - -/* Purge modes */ -#define TI_PURGE_OUTPUT 0x00 -#define TI_PURGE_INPUT 0x80 - -/* Read/Write data */ -#define TI_RW_DATA_ADDR_SFR 0x10 -#define TI_RW_DATA_ADDR_IDATA 0x20 -#define TI_RW_DATA_ADDR_XDATA 0x30 -#define TI_RW_DATA_ADDR_CODE 0x40 -#define TI_RW_DATA_ADDR_GPIO 0x50 -#define TI_RW_DATA_ADDR_I2C 0x60 -#define TI_RW_DATA_ADDR_FLASH 0x70 -#define TI_RW_DATA_ADDR_DSP 0x80 - -#define TI_RW_DATA_UNSPECIFIED 0x00 -#define TI_RW_DATA_BYTE 0x01 -#define TI_RW_DATA_WORD 0x02 -#define TI_RW_DATA_DOUBLE_WORD 0x04 - -struct ti_write_data_bytes { - __u8 bAddrType; - __u8 bDataType; - __u8 bDataCounter; - __be16 wBaseAddrHi; - __be16 wBaseAddrLo; - __u8 bData[0]; -} __attribute__((packed)); - -struct ti_read_data_request { - __u8 bAddrType; - __u8 bDataType; - __u8 bDataCounter; - __be16 wBaseAddrHi; - __be16 wBaseAddrLo; -} __attribute__((packed)); - -struct ti_read_data_bytes { - __u8 bCmdCode; - __u8 bModuleId; - __u8 bErrorCode; - __u8 bData[0]; -} __attribute__((packed)); - -/* Interrupt struct */ -struct ti_interrupt { - __u8 bICode; - __u8 bIInfo; -} __attribute__((packed)); - -/* Interrupt codes */ -#define TI_GET_PORT_FROM_CODE(c) (((c) >> 4) - 3) -#define TI_GET_FUNC_FROM_CODE(c) ((c) & 0x0f) -#define TI_CODE_HARDWARE_ERROR 0xFF -#define TI_CODE_DATA_ERROR 0x03 -#define TI_CODE_MODEM_STATUS 0x04 - -/* Download firmware max packet size */ -#define TI_DOWNLOAD_MAX_PACKET_SIZE 64 - -/* Firmware image header */ -struct ti_firmware_header { - __le16 wLength; - __u8 bCheckSum; -} __attribute__((packed)); - -/* UART addresses */ -#define TI_UART1_BASE_ADDR 0xFFA0 /* UART 1 base address */ -#define TI_UART2_BASE_ADDR 0xFFB0 /* UART 2 base address */ -#define TI_UART_OFFSET_LCR 0x0002 /* UART MCR register offset */ -#define TI_UART_OFFSET_MCR 0x0004 /* UART MCR register offset */ - -#endif /* _TI_3410_5052_H_ */ diff --git a/ANDROID_3.4.5/drivers/usb/serial/usb-serial.c b/ANDROID_3.4.5/drivers/usb/serial/usb-serial.c deleted file mode 100644 index 03c117c9..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/usb-serial.c +++ /dev/null @@ -1,1455 +0,0 @@ -/* - * USB Serial Converter driver - * - * Copyright (C) 1999 - 2005 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2000 Peter Berger (pberger@brimson.com) - * Copyright (C) 2000 Al Borchers (borchers@steinerpoint.com) - * - * 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 driver was originally based on the ACM driver by Armin Fuerst (which was - * based on a driver by Brad Keryan) - * - * See Documentation/usb/usb-serial.txt for more information on using this - * driver - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "pl2303.h" - -/* - * Version Information - */ -#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/" -#define DRIVER_DESC "USB Serial Driver core" - -/* Driver structure we register with the USB core */ -static struct usb_driver usb_serial_driver = { - .name = "usbserial", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .no_dynamic_id = 1, - .supports_autosuspend = 1, -}; - -/* There is no MODULE_DEVICE_TABLE for usbserial.c. Instead - the MODULE_DEVICE_TABLE declarations in each serial driver - cause the "hotplug" program to pull in whatever module is necessary - via modprobe, and modprobe will load usbserial because the serial - drivers depend on it. -*/ - -static bool debug; -/* initially all NULL */ -static struct usb_serial *serial_table[SERIAL_TTY_MINORS]; -static DEFINE_MUTEX(table_lock); -static LIST_HEAD(usb_serial_driver_list); - -/* - * Look up the serial structure. If it is found and it hasn't been - * disconnected, return with its disc_mutex held and its refcount - * incremented. Otherwise return NULL. - */ -struct usb_serial *usb_serial_get_by_index(unsigned index) -{ - struct usb_serial *serial; - - mutex_lock(&table_lock); - serial = serial_table[index]; - - if (serial) { - mutex_lock(&serial->disc_mutex); - if (serial->disconnected) { - mutex_unlock(&serial->disc_mutex); - serial = NULL; - } else { - kref_get(&serial->kref); - } - } - mutex_unlock(&table_lock); - return serial; -} - -static struct usb_serial *get_free_serial(struct usb_serial *serial, - int num_ports, unsigned int *minor,int startIndex) -{ - unsigned int i, j; - int good_spot; - - dbg("%s %d", __func__, num_ports); - *minor = startIndex; - - mutex_lock(&table_lock); - for (i = startIndex; i < SERIAL_TTY_MINORS; ++i) { - if (serial_table[i]) - continue; - - good_spot = 1; - for (j = 1; j <= num_ports-1; ++j) - if ((i+j >= SERIAL_TTY_MINORS) || (serial_table[i+j])) { - good_spot = 0; - i += j; - break; - } - if (good_spot == 0) - continue; - - *minor = i; - j = 0; - dbg("%s - minor base = %d", __func__, *minor); - for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i) { - serial_table[i] = serial; - serial->port[j++]->number = i; - } - mutex_unlock(&table_lock); - return serial; - } - mutex_unlock(&table_lock); - return NULL; -} - -static void return_serial(struct usb_serial *serial) -{ - int i; - - dbg("%s", __func__); - - mutex_lock(&table_lock); - for (i = 0; i < serial->num_ports; ++i) - serial_table[serial->minor + i] = NULL; - mutex_unlock(&table_lock); -} - -static void destroy_serial(struct kref *kref) -{ - struct usb_serial *serial; - struct usb_serial_port *port; - int i; - - serial = to_usb_serial(kref); - - dbg("%s - %s", __func__, serial->type->description); - - /* return the minor range that this device had */ - if (serial->minor != SERIAL_TTY_NO_MINOR) - return_serial(serial); - - if (serial->attached) - serial->type->release(serial); - - /* Now that nothing is using the ports, they can be freed */ - for (i = 0; i < serial->num_port_pointers; ++i) { - port = serial->port[i]; - if (port) { - port->serial = NULL; - put_device(&port->dev); - } - } - - usb_put_dev(serial->dev); - kfree(serial); -} - -void usb_serial_put(struct usb_serial *serial) -{ - kref_put(&serial->kref, destroy_serial); -} - -/***************************************************************************** - * Driver tty interface functions - *****************************************************************************/ - -/** - * serial_install - install tty - * @driver: the driver (USB in our case) - * @tty: the tty being created - * - * Create the termios objects for this tty. We use the default - * USB serial settings but permit them to be overridden by - * serial->type->init_termios. - * - * This is the first place a new tty gets used. Hence this is where we - * acquire references to the usb_serial structure and the driver module, - * where we store a pointer to the port, and where we do an autoresume. - * All these actions are reversed in serial_cleanup(). - */ -static int serial_install(struct tty_driver *driver, struct tty_struct *tty) -{ - int idx = tty->index; - struct usb_serial *serial; - struct usb_serial_port *port; - int retval = -ENODEV; - - dbg("%s", __func__); - - serial = usb_serial_get_by_index(idx); - if (!serial) - return retval; - - port = serial->port[idx - serial->minor]; - if (!port) - goto error_no_port; - if (!try_module_get(serial->type->driver.owner)) - goto error_module_get; - - retval = usb_autopm_get_interface(serial->interface); - if (retval) - goto error_get_interface; - - retval = tty_standard_install(driver, tty); - if (retval) - goto error_init_termios; - - mutex_unlock(&serial->disc_mutex); - - /* allow the driver to update the settings */ - if (serial->type->init_termios) - serial->type->init_termios(tty); - - tty->driver_data = port; - - return retval; - - error_init_termios: - usb_autopm_put_interface(serial->interface); - error_get_interface: - module_put(serial->type->driver.owner); - error_module_get: - error_no_port: - usb_serial_put(serial); - mutex_unlock(&serial->disc_mutex); - return retval; -} - -static int serial_activate(struct tty_port *tport, struct tty_struct *tty) -{ - struct usb_serial_port *port = - container_of(tport, struct usb_serial_port, port); - struct usb_serial *serial = port->serial; - int retval; - - mutex_lock(&serial->disc_mutex); - if (serial->disconnected) - retval = -ENODEV; - else - retval = port->serial->type->open(tty, port); - mutex_unlock(&serial->disc_mutex); - - if (retval < 0) - retval = usb_translate_errors(retval); - - return retval; -} - -static int serial_open(struct tty_struct *tty, struct file *filp) -{ - struct usb_serial_port *port = tty->driver_data; - - dbg("%s - port %d", __func__, port->number); - return tty_port_open(&port->port, tty, filp); -} - -/** - * serial_down - shut down hardware - * @tport: tty port to shut down - * - * Shut down a USB serial port unless it is the console. We never - * shut down the console hardware as it will always be in use. Serialized - * against activate by the tport mutex and kept to matching open/close pairs - * of calls by the ASYNCB_INITIALIZED flag. - */ -static void serial_down(struct tty_port *tport) -{ - struct usb_serial_port *port = - container_of(tport, struct usb_serial_port, port); - struct usb_serial_driver *drv = port->serial->type; - /* - * The console is magical. Do not hang up the console hardware - * or there will be tears. - */ - if (port->port.console) - return; - if (drv->close) - drv->close(port); -} - -static void serial_hangup(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); - tty_port_hangup(&port->port); -} - -static void serial_close(struct tty_struct *tty, struct file *filp) -{ - struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); - tty_port_close(&port->port, tty, filp); -} - -/** - * serial_cleanup - free resources post close/hangup - * @port: port to free up - * - * Do the resource freeing and refcount dropping for the port. - * Avoid freeing the console. - * - * Called asynchronously after the last tty kref is dropped, - * and the tty layer has already done the tty_shutdown(tty); - */ -static void serial_cleanup(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial; - struct module *owner; - - /* The console is magical. Do not hang up the console hardware - * or there will be tears. - */ - if (port->port.console) - return; - - dbg("%s - port %d", __func__, port->number); - - tty->driver_data = NULL; - - serial = port->serial; - owner = serial->type->driver.owner; - - mutex_lock(&serial->disc_mutex); - if (!serial->disconnected) - usb_autopm_put_interface(serial->interface); - mutex_unlock(&serial->disc_mutex); - - usb_serial_put(serial); - module_put(owner); -} - -static int serial_write(struct tty_struct *tty, const unsigned char *buf, - int count) -{ - struct usb_serial_port *port = tty->driver_data; - int retval = -ENODEV; - - if (port->serial->dev->state == USB_STATE_NOTATTACHED) - goto exit; - - dbg("%s - port %d, %d byte(s)", __func__, port->number, count); - - /* pass on to the driver specific version of this function */ - retval = port->serial->type->write(tty, port, buf, count); - if (retval < 0) - retval = usb_translate_errors(retval); -exit: - return retval; -} - -static int serial_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); - /* pass on to the driver specific version of this function */ - return port->serial->type->write_room(tty); -} - -static int serial_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); - - /* if the device was unplugged then any remaining characters - fell out of the connector ;) */ - if (port->serial->disconnected) - return 0; - /* pass on to the driver specific version of this function */ - return port->serial->type->chars_in_buffer(tty); -} - -static void serial_throttle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); - - /* pass on to the driver specific version of this function */ - if (port->serial->type->throttle) - port->serial->type->throttle(tty); -} - -static void serial_unthrottle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); - - /* pass on to the driver specific version of this function */ - if (port->serial->type->unthrottle) - port->serial->type->unthrottle(tty); -} - -static int serial_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - int retval = -ENODEV; - - dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd); - - /* pass on to the driver specific version of this function - if it is available */ - if (port->serial->type->ioctl) { - retval = port->serial->type->ioctl(tty, cmd, arg); - } else - retval = -ENOIOCTLCMD; - return retval; -} - -static void serial_set_termios(struct tty_struct *tty, struct ktermios *old) -{ - struct usb_serial_port *port = tty->driver_data; - dbg("%s - port %d", __func__, port->number); - - /* pass on to the driver specific version of this function - if it is available */ - if (port->serial->type->set_termios) - port->serial->type->set_termios(tty, port, old); - else - tty_termios_copy_hw(tty->termios, old); -} - -static int serial_break(struct tty_struct *tty, int break_state) -{ - struct usb_serial_port *port = tty->driver_data; - - dbg("%s - port %d", __func__, port->number); - - /* pass on to the driver specific version of this function - if it is available */ - if (port->serial->type->break_ctl) - port->serial->type->break_ctl(tty, break_state); - return 0; -} - -static int serial_proc_show(struct seq_file *m, void *v) -{ - struct usb_serial *serial; - int i; - char tmp[40]; - - dbg("%s", __func__); - seq_puts(m, "usbserinfo:1.0 driver:2.0\n"); - for (i = 0; i < SERIAL_TTY_MINORS; ++i) { - serial = usb_serial_get_by_index(i); - if (serial == NULL) - continue; - - seq_printf(m, "%d:", i); - if (serial->type->driver.owner) - seq_printf(m, " module:%s", - module_name(serial->type->driver.owner)); - seq_printf(m, " name:\"%s\"", - serial->type->description); - seq_printf(m, " vendor:%04x product:%04x", - le16_to_cpu(serial->dev->descriptor.idVendor), - le16_to_cpu(serial->dev->descriptor.idProduct)); - seq_printf(m, " num_ports:%d", serial->num_ports); - seq_printf(m, " port:%d", i - serial->minor + 1); - usb_make_path(serial->dev, tmp, sizeof(tmp)); - seq_printf(m, " path:%s", tmp); - - seq_putc(m, '\n'); - usb_serial_put(serial); - mutex_unlock(&serial->disc_mutex); - } - return 0; -} - -static int serial_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, serial_proc_show, NULL); -} - -static const struct file_operations serial_proc_fops = { - .owner = THIS_MODULE, - .open = serial_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int serial_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - - dbg("%s - port %d", __func__, port->number); - - if (port->serial->type->tiocmget) - return port->serial->type->tiocmget(tty); - return -EINVAL; -} - -static int serial_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - - dbg("%s - port %d", __func__, port->number); - - if (port->serial->type->tiocmset) - return port->serial->type->tiocmset(tty, set, clear); - return -EINVAL; -} - -static int serial_get_icount(struct tty_struct *tty, - struct serial_icounter_struct *icount) -{ - struct usb_serial_port *port = tty->driver_data; - - dbg("%s - port %d", __func__, port->number); - - if (port->serial->type->get_icount) - return port->serial->type->get_icount(tty, icount); - return -EINVAL; -} - -/* - * We would be calling tty_wakeup here, but unfortunately some line - * disciplines have an annoying habit of calling tty->write from - * the write wakeup callback (e.g. n_hdlc.c). - */ -void usb_serial_port_softint(struct usb_serial_port *port) -{ - schedule_work(&port->work); -} -EXPORT_SYMBOL_GPL(usb_serial_port_softint); - -static void usb_serial_port_work(struct work_struct *work) -{ - struct usb_serial_port *port = - container_of(work, struct usb_serial_port, work); - struct tty_struct *tty; - - dbg("%s - port %d", __func__, port->number); - - tty = tty_port_tty_get(&port->port); - if (!tty) - return; - - tty_wakeup(tty); - tty_kref_put(tty); -} - -static void kill_traffic(struct usb_serial_port *port) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) - usb_kill_urb(port->read_urbs[i]); - for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) - usb_kill_urb(port->write_urbs[i]); - /* - * This is tricky. - * Some drivers submit the read_urb in the - * handler for the write_urb or vice versa - * this order determines the order in which - * usb_kill_urb() must be used to reliably - * kill the URBs. As it is unknown here, - * both orders must be used in turn. - * The call below is not redundant. - */ - usb_kill_urb(port->read_urb); - usb_kill_urb(port->interrupt_in_urb); - usb_kill_urb(port->interrupt_out_urb); -} - -static void port_release(struct device *dev) -{ - struct usb_serial_port *port = to_usb_serial_port(dev); - int i; - - dbg ("%s - %s", __func__, dev_name(dev)); - - /* - * Stop all the traffic before cancelling the work, so that - * nobody will restart it by calling usb_serial_port_softint. - */ - kill_traffic(port); - cancel_work_sync(&port->work); - - usb_free_urb(port->interrupt_in_urb); - usb_free_urb(port->interrupt_out_urb); - for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) { - usb_free_urb(port->read_urbs[i]); - kfree(port->bulk_in_buffers[i]); - } - for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) { - usb_free_urb(port->write_urbs[i]); - kfree(port->bulk_out_buffers[i]); - } - kfifo_free(&port->write_fifo); - kfree(port->interrupt_in_buffer); - kfree(port->interrupt_out_buffer); - kfree(port); -} - -static struct usb_serial *create_serial(struct usb_device *dev, - struct usb_interface *interface, - struct usb_serial_driver *driver) -{ - struct usb_serial *serial; - - serial = kzalloc(sizeof(*serial), GFP_KERNEL); - if (!serial) { - dev_err(&dev->dev, "%s - out of memory\n", __func__); - return NULL; - } - serial->dev = usb_get_dev(dev); - serial->type = driver; - serial->interface = interface; - kref_init(&serial->kref); - mutex_init(&serial->disc_mutex); - serial->minor = SERIAL_TTY_NO_MINOR; - - return serial; -} - -static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf, - struct usb_serial_driver *drv) -{ - struct usb_dynid *dynid; - - spin_lock(&drv->dynids.lock); - list_for_each_entry(dynid, &drv->dynids.list, node) { - if (usb_match_one_id(intf, &dynid->id)) { - spin_unlock(&drv->dynids.lock); - return &dynid->id; - } - } - spin_unlock(&drv->dynids.lock); - return NULL; -} - -static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv, - struct usb_interface *intf) -{ - const struct usb_device_id *id; - - id = usb_match_id(intf, drv->id_table); - if (id) { - dbg("static descriptor matches"); - goto exit; - } - id = match_dynamic_id(intf, drv); - if (id) - dbg("dynamic descriptor matches"); -exit: - return id; -} - -/* Caller must hold table_lock */ -static struct usb_serial_driver *search_serial_device( - struct usb_interface *iface) -{ - const struct usb_device_id *id = NULL; - struct usb_serial_driver *drv; - struct usb_driver *driver = to_usb_driver(iface->dev.driver); - - /* Check if the usb id matches a known device */ - list_for_each_entry(drv, &usb_serial_driver_list, driver_list) { - if (drv->usb_driver == driver) - id = get_iface_id(drv, iface); - if (id) - return drv; - } - - return NULL; -} - -static int serial_carrier_raised(struct tty_port *port) -{ - struct usb_serial_port *p = container_of(port, struct usb_serial_port, port); - struct usb_serial_driver *drv = p->serial->type; - - if (drv->carrier_raised) - return drv->carrier_raised(p); - /* No carrier control - don't block */ - return 1; -} - -static void serial_dtr_rts(struct tty_port *port, int on) -{ - struct usb_serial_port *p = container_of(port, struct usb_serial_port, port); - struct usb_serial_driver *drv = p->serial->type; - - if (drv->dtr_rts) - drv->dtr_rts(p, on); -} - -static const struct tty_port_operations serial_port_ops = { - .carrier_raised = serial_carrier_raised, - .dtr_rts = serial_dtr_rts, - .activate = serial_activate, - .shutdown = serial_down, -}; - -int usb_serial_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(interface); - struct usb_serial *serial = NULL; - struct usb_serial_port *port; - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS]; - struct usb_endpoint_descriptor *interrupt_out_endpoint[MAX_NUM_PORTS]; - struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS]; - struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS]; - struct usb_serial_driver *type = NULL; - int retval; - unsigned int minor; - int buffer_size; - int i; - int j; - int num_interrupt_in = 0; - int num_interrupt_out = 0; - int num_bulk_in = 0; - int num_bulk_out = 0; - int num_ports = 0; - int max_endpoints; - int startIndex = 0; - mutex_lock(&table_lock); - type = search_serial_device(interface); - if (!type) { - mutex_unlock(&table_lock); - dbg("none matched"); - return -ENODEV; - } - - if (!try_module_get(type->driver.owner)) { - mutex_unlock(&table_lock); - dev_err(&interface->dev, "module get failed, exiting\n"); - return -EIO; - } - mutex_unlock(&table_lock); - - serial = create_serial(dev, interface, type); - if (!serial) { - module_put(type->driver.owner); - dev_err(&interface->dev, "%s - out of memory\n", __func__); - return -ENOMEM; - } - - /* if this device type has a probe function, call it */ - if (type->probe) { - const struct usb_device_id *id; - - id = get_iface_id(type, interface); - retval = type->probe(serial, id); - - if (retval) { - dbg("sub driver rejected device"); - kfree(serial); - module_put(type->driver.owner); - return retval; - } - } - - /* descriptor matches, let's find the endpoints needed */ - /* check out the endpoints */ - iface_desc = interface->cur_altsetting; - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - - if (usb_endpoint_is_bulk_in(endpoint)) { - /* we found a bulk in endpoint */ - dbg("found bulk in on endpoint %d", i); - bulk_in_endpoint[num_bulk_in] = endpoint; - ++num_bulk_in; - } - - if (usb_endpoint_is_bulk_out(endpoint)) { - /* we found a bulk out endpoint */ - dbg("found bulk out on endpoint %d", i); - bulk_out_endpoint[num_bulk_out] = endpoint; - ++num_bulk_out; - } - - if (usb_endpoint_is_int_in(endpoint)) { - /* we found a interrupt in endpoint */ - dbg("found interrupt in on endpoint %d", i); - interrupt_in_endpoint[num_interrupt_in] = endpoint; - ++num_interrupt_in; - } - - if (usb_endpoint_is_int_out(endpoint)) { - /* we found an interrupt out endpoint */ - dbg("found interrupt out on endpoint %d", i); - interrupt_out_endpoint[num_interrupt_out] = endpoint; - ++num_interrupt_out; - } - } - -#if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE) - /* BEGIN HORRIBLE HACK FOR PL2303 */ - /* this is needed due to the looney way its endpoints are set up */ - if (((le16_to_cpu(dev->descriptor.idVendor) == PL2303_VENDOR_ID) && - (le16_to_cpu(dev->descriptor.idProduct) == PL2303_PRODUCT_ID)) || - ((le16_to_cpu(dev->descriptor.idVendor) == ATEN_VENDOR_ID) && - (le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID)) || - ((le16_to_cpu(dev->descriptor.idVendor) == ALCOR_VENDOR_ID) && - (le16_to_cpu(dev->descriptor.idProduct) == ALCOR_PRODUCT_ID)) || - ((le16_to_cpu(dev->descriptor.idVendor) == SIEMENS_VENDOR_ID) && - (le16_to_cpu(dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_EF81))) { - if (interface != dev->actconfig->interface[0]) { - /* check out the endpoints of the other interface*/ - iface_desc = dev->actconfig->interface[0]->cur_altsetting; - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - if (usb_endpoint_is_int_in(endpoint)) { - /* we found a interrupt in endpoint */ - dbg("found interrupt in for Prolific device on separate interface"); - interrupt_in_endpoint[num_interrupt_in] = endpoint; - ++num_interrupt_in; - } - } - } - - /* Now make sure the PL-2303 is configured correctly. - * If not, give up now and hope this hack will work - * properly during a later invocation of usb_serial_probe - */ - if (num_bulk_in == 0 || num_bulk_out == 0) { - dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n"); - kfree(serial); - module_put(type->driver.owner); - return -ENODEV; - } - } - /* END HORRIBLE HACK FOR PL2303 */ -#endif - -#ifdef CONFIG_USB_SERIAL_GENERIC - if (type == &usb_serial_generic_device) { - num_ports = num_bulk_out; - if (num_ports == 0) { - dev_err(&interface->dev, - "Generic device with no bulk out, not allowed.\n"); - kfree(serial); - module_put(type->driver.owner); - return -EIO; - } - } -#endif - if (!num_ports) { - /* if this device type has a calc_num_ports function, call it */ - if (type->calc_num_ports) - num_ports = type->calc_num_ports(serial); - if (!num_ports) - num_ports = type->num_ports; - } - - serial->num_ports = num_ports; - serial->num_bulk_in = num_bulk_in; - serial->num_bulk_out = num_bulk_out; - serial->num_interrupt_in = num_interrupt_in; - serial->num_interrupt_out = num_interrupt_out; - - /* found all that we need */ - dev_info(&interface->dev, "%s converter detected\n", - type->description); - - /* create our ports, we need as many as the max endpoints */ - /* we don't use num_ports here because some devices have more - endpoint pairs than ports */ - max_endpoints = max(num_bulk_in, num_bulk_out); - max_endpoints = max(max_endpoints, num_interrupt_in); - max_endpoints = max(max_endpoints, num_interrupt_out); - max_endpoints = max(max_endpoints, (int)serial->num_ports); - serial->num_port_pointers = max_endpoints; - - dbg("%s - setting up %d port structures for this device", - __func__, max_endpoints); - for (i = 0; i < max_endpoints; ++i) { - port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL); - if (!port) - goto probe_error; - tty_port_init(&port->port); - port->port.ops = &serial_port_ops; - port->serial = serial; - spin_lock_init(&port->lock); - /* Keep this for private driver use for the moment but - should probably go away */ - INIT_WORK(&port->work, usb_serial_port_work); - serial->port[i] = port; - port->dev.parent = &interface->dev; - port->dev.driver = NULL; - port->dev.bus = &usb_serial_bus_type; - port->dev.release = &port_release; - device_initialize(&port->dev); - } - - /* set up the endpoint information */ - for (i = 0; i < num_bulk_in; ++i) { - endpoint = bulk_in_endpoint[i]; - port = serial->port[i]; - buffer_size = max_t(int, serial->type->bulk_in_size, - usb_endpoint_maxp(endpoint)); - port->bulk_in_size = buffer_size; - port->bulk_in_endpointAddress = endpoint->bEndpointAddress; - - for (j = 0; j < ARRAY_SIZE(port->read_urbs); ++j) { - set_bit(j, &port->read_urbs_free); - port->read_urbs[j] = usb_alloc_urb(0, GFP_KERNEL); - if (!port->read_urbs[j]) { - dev_err(&interface->dev, - "No free urbs available\n"); - goto probe_error; - } - port->bulk_in_buffers[j] = kmalloc(buffer_size, - GFP_KERNEL); - if (!port->bulk_in_buffers[j]) { - dev_err(&interface->dev, - "Couldn't allocate bulk_in_buffer\n"); - goto probe_error; - } - usb_fill_bulk_urb(port->read_urbs[j], dev, - usb_rcvbulkpipe(dev, - endpoint->bEndpointAddress), - port->bulk_in_buffers[j], buffer_size, - serial->type->read_bulk_callback, - port); - } - - port->read_urb = port->read_urbs[0]; - port->bulk_in_buffer = port->bulk_in_buffers[0]; - } - - for (i = 0; i < num_bulk_out; ++i) { - endpoint = bulk_out_endpoint[i]; - port = serial->port[i]; - if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL)) - goto probe_error; - buffer_size = serial->type->bulk_out_size; - if (!buffer_size) - buffer_size = usb_endpoint_maxp(endpoint); - port->bulk_out_size = buffer_size; - port->bulk_out_endpointAddress = endpoint->bEndpointAddress; - - for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) { - set_bit(j, &port->write_urbs_free); - port->write_urbs[j] = usb_alloc_urb(0, GFP_KERNEL); - if (!port->write_urbs[j]) { - dev_err(&interface->dev, - "No free urbs available\n"); - goto probe_error; - } - port->bulk_out_buffers[j] = kmalloc(buffer_size, - GFP_KERNEL); - if (!port->bulk_out_buffers[j]) { - dev_err(&interface->dev, - "Couldn't allocate bulk_out_buffer\n"); - goto probe_error; - } - usb_fill_bulk_urb(port->write_urbs[j], dev, - usb_sndbulkpipe(dev, - endpoint->bEndpointAddress), - port->bulk_out_buffers[j], buffer_size, - serial->type->write_bulk_callback, - port); - } - - port->write_urb = port->write_urbs[0]; - port->bulk_out_buffer = port->bulk_out_buffers[0]; - } - - if (serial->type->read_int_callback) { - for (i = 0; i < num_interrupt_in; ++i) { - endpoint = interrupt_in_endpoint[i]; - port = serial->port[i]; - port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!port->interrupt_in_urb) { - dev_err(&interface->dev, - "No free urbs available\n"); - goto probe_error; - } - buffer_size = usb_endpoint_maxp(endpoint); - port->interrupt_in_endpointAddress = - endpoint->bEndpointAddress; - port->interrupt_in_buffer = kmalloc(buffer_size, - GFP_KERNEL); - if (!port->interrupt_in_buffer) { - dev_err(&interface->dev, - "Couldn't allocate interrupt_in_buffer\n"); - goto probe_error; - } - usb_fill_int_urb(port->interrupt_in_urb, dev, - usb_rcvintpipe(dev, - endpoint->bEndpointAddress), - port->interrupt_in_buffer, buffer_size, - serial->type->read_int_callback, port, - endpoint->bInterval); - } - } else if (num_interrupt_in) { - dbg("the device claims to support interrupt in transfers, but read_int_callback is not defined"); - } - - if (serial->type->write_int_callback) { - for (i = 0; i < num_interrupt_out; ++i) { - endpoint = interrupt_out_endpoint[i]; - port = serial->port[i]; - port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!port->interrupt_out_urb) { - dev_err(&interface->dev, - "No free urbs available\n"); - goto probe_error; - } - buffer_size = usb_endpoint_maxp(endpoint); - port->interrupt_out_size = buffer_size; - port->interrupt_out_endpointAddress = - endpoint->bEndpointAddress; - port->interrupt_out_buffer = kmalloc(buffer_size, - GFP_KERNEL); - if (!port->interrupt_out_buffer) { - dev_err(&interface->dev, - "Couldn't allocate interrupt_out_buffer\n"); - goto probe_error; - } - usb_fill_int_urb(port->interrupt_out_urb, dev, - usb_sndintpipe(dev, - endpoint->bEndpointAddress), - port->interrupt_out_buffer, buffer_size, - serial->type->write_int_callback, port, - endpoint->bInterval); - } - } else if (num_interrupt_out) { - dbg("the device claims to support interrupt out transfers, but write_int_callback is not defined"); - } - - /* if this device type has an attach function, call it */ - if (type->attach) { - retval = type->attach(serial); - if (retval < 0) - goto probe_error; - serial->attached = 1; - if (retval > 0) { - /* quietly accept this device, but don't bind to a - serial port as it's about to disappear */ - serial->num_ports = 0; - goto exit; - } - } else { - serial->attached = 1; - } - - /* Avoid race with tty_open and serial_install by setting the - * disconnected flag and not clearing it until all ports have been - * registered. - */ - serial->disconnected = 1; - if(!strcmp(type->driver.name,"pl2303")||!strcmp(type->driver.name,"ftdi_sio")||!strcmp(type->driver.name,"cp210x")) - startIndex = 5; - - if (get_free_serial(serial, num_ports, &minor, startIndex) == NULL) { - dev_err(&interface->dev, "No more free serial devices\n"); - goto probe_error; - } - serial->minor = minor; - - /* register all of the individual ports with the driver core */ - for (i = 0; i < num_ports; ++i) { - port = serial->port[i]; - dev_set_name(&port->dev, "ttyUSB%d", port->number); - dbg ("%s - registering %s", __func__, dev_name(&port->dev)); - device_enable_async_suspend(&port->dev); - - retval = device_add(&port->dev); - if (retval) - dev_err(&port->dev, "Error registering port device, " - "continuing\n"); - } - - serial->disconnected = 0; - - usb_serial_console_init(debug, minor); - -exit: - /* success */ - usb_set_intfdata(interface, serial); - module_put(type->driver.owner); - return 0; - -probe_error: - usb_serial_put(serial); - module_put(type->driver.owner); - return -EIO; -} -EXPORT_SYMBOL_GPL(usb_serial_probe); - -void usb_serial_disconnect(struct usb_interface *interface) -{ - int i; - struct usb_serial *serial = usb_get_intfdata(interface); - struct device *dev = &interface->dev; - struct usb_serial_port *port; - - usb_serial_console_disconnect(serial); - dbg("%s", __func__); - - mutex_lock(&serial->disc_mutex); - usb_set_intfdata(interface, NULL); - /* must set a flag, to signal subdrivers */ - serial->disconnected = 1; - mutex_unlock(&serial->disc_mutex); - - for (i = 0; i < serial->num_ports; ++i) { - port = serial->port[i]; - if (port) { - struct tty_struct *tty = tty_port_tty_get(&port->port); - if (tty) { - tty_vhangup(tty); - tty_kref_put(tty); - } - kill_traffic(port); - cancel_work_sync(&port->work); - if (device_is_registered(&port->dev)) - device_del(&port->dev); - } - } - serial->type->disconnect(serial); - - /* let the last holder of this object cause it to be cleaned up */ - usb_serial_put(serial); - dev_info(dev, "device disconnected\n"); -} -EXPORT_SYMBOL_GPL(usb_serial_disconnect); - -int usb_serial_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct usb_serial *serial = usb_get_intfdata(intf); - struct usb_serial_port *port; - int i, r = 0; - - serial->suspending = 1; - - if (serial->type->suspend) { - r = serial->type->suspend(serial, message); - if (r < 0) { - serial->suspending = 0; - goto err_out; - } - } - - for (i = 0; i < serial->num_ports; ++i) { - port = serial->port[i]; - if (port) - kill_traffic(port); - } - -err_out: - return r; -} -EXPORT_SYMBOL(usb_serial_suspend); - -int usb_serial_resume(struct usb_interface *intf) -{ - struct usb_serial *serial = usb_get_intfdata(intf); - int rv; - - serial->suspending = 0; - if (serial->type->resume) - rv = serial->type->resume(serial); - else - rv = usb_serial_generic_resume(serial); - - return rv; -} -EXPORT_SYMBOL(usb_serial_resume); - -static const struct tty_operations serial_ops = { - .open = serial_open, - .close = serial_close, - .write = serial_write, - .hangup = serial_hangup, - .write_room = serial_write_room, - .ioctl = serial_ioctl, - .set_termios = serial_set_termios, - .throttle = serial_throttle, - .unthrottle = serial_unthrottle, - .break_ctl = serial_break, - .chars_in_buffer = serial_chars_in_buffer, - .tiocmget = serial_tiocmget, - .tiocmset = serial_tiocmset, - .get_icount = serial_get_icount, - .cleanup = serial_cleanup, - .install = serial_install, - .proc_fops = &serial_proc_fops, -}; - - -struct tty_driver *usb_serial_tty_driver; - -static int __init usb_serial_init(void) -{ - int i; - int result; - - usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS); - if (!usb_serial_tty_driver) - return -ENOMEM; - - /* Initialize our global data */ - for (i = 0; i < SERIAL_TTY_MINORS; ++i) - serial_table[i] = NULL; - - result = bus_register(&usb_serial_bus_type); - if (result) { - printk(KERN_ERR "usb-serial: %s - registering bus driver " - "failed\n", __func__); - goto exit_bus; - } - - usb_serial_tty_driver->driver_name = "usbserial"; - usb_serial_tty_driver->name = "ttyUSB"; - usb_serial_tty_driver->major = SERIAL_TTY_MAJOR; - usb_serial_tty_driver->minor_start = 0; - usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; - usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL; - usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_DEV; - usb_serial_tty_driver->init_termios = tty_std_termios; - usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD - | HUPCL | CLOCAL; - usb_serial_tty_driver->init_termios.c_ispeed = 9600; - usb_serial_tty_driver->init_termios.c_ospeed = 9600; - tty_set_operations(usb_serial_tty_driver, &serial_ops); - result = tty_register_driver(usb_serial_tty_driver); - if (result) { - printk(KERN_ERR "usb-serial: %s - tty_register_driver failed\n", - __func__); - goto exit_reg_driver; - } - - /* register the USB driver */ - result = usb_register(&usb_serial_driver); - if (result < 0) { - printk(KERN_ERR "usb-serial: %s - usb_register failed\n", - __func__); - goto exit_tty; - } - - /* register the generic driver, if we should */ - result = usb_serial_generic_register(debug); - if (result < 0) { - printk(KERN_ERR "usb-serial: %s - registering generic " - "driver failed\n", __func__); - goto exit_generic; - } - - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n"); - - return result; - -exit_generic: - usb_deregister(&usb_serial_driver); - -exit_tty: - tty_unregister_driver(usb_serial_tty_driver); - -exit_reg_driver: - bus_unregister(&usb_serial_bus_type); - -exit_bus: - printk(KERN_ERR "usb-serial: %s - returning with error %d\n", - __func__, result); - put_tty_driver(usb_serial_tty_driver); - return result; -} - - -static void __exit usb_serial_exit(void) -{ - usb_serial_console_exit(); - - usb_serial_generic_deregister(); - - usb_deregister(&usb_serial_driver); - tty_unregister_driver(usb_serial_tty_driver); - put_tty_driver(usb_serial_tty_driver); - bus_unregister(&usb_serial_bus_type); -} - - -module_init(usb_serial_init); -module_exit(usb_serial_exit); - -#define set_to_generic_if_null(type, function) \ - do { \ - if (!type->function) { \ - type->function = usb_serial_generic_##function; \ - dbg("Had to override the " #function \ - " usb serial operation with the generic one.");\ - } \ - } while (0) - -static void fixup_generic(struct usb_serial_driver *device) -{ - set_to_generic_if_null(device, open); - set_to_generic_if_null(device, write); - set_to_generic_if_null(device, close); - set_to_generic_if_null(device, write_room); - set_to_generic_if_null(device, chars_in_buffer); - set_to_generic_if_null(device, read_bulk_callback); - set_to_generic_if_null(device, write_bulk_callback); - set_to_generic_if_null(device, disconnect); - set_to_generic_if_null(device, release); - set_to_generic_if_null(device, process_read_urb); - set_to_generic_if_null(device, prepare_write_buffer); -} - -static int usb_serial_register(struct usb_serial_driver *driver) -{ - int retval; - - if (usb_disabled()) - return -ENODEV; - - fixup_generic(driver); - - if (!driver->description) - driver->description = driver->driver.name; - if (!driver->usb_driver) { - WARN(1, "Serial driver %s has no usb_driver\n", - driver->description); - return -EINVAL; - } - - /* Add this device to our list of devices */ - mutex_lock(&table_lock); - list_add(&driver->driver_list, &usb_serial_driver_list); - - retval = usb_serial_bus_register(driver); - if (retval) { - printk(KERN_ERR "usb-serial: problem %d when registering " - "driver %s\n", retval, driver->description); - list_del(&driver->driver_list); - } else - printk(KERN_INFO "USB Serial support registered for %s\n", - driver->description); - - mutex_unlock(&table_lock); - return retval; -} - -static void usb_serial_deregister(struct usb_serial_driver *device) -{ - printk(KERN_INFO "USB Serial deregistering driver %s\n", - device->description); - mutex_lock(&table_lock); - list_del(&device->driver_list); - usb_serial_bus_deregister(device); - mutex_unlock(&table_lock); -} - -/** - * usb_serial_register_drivers - register drivers for a usb-serial module - * @udriver: usb_driver used for matching devices/interfaces - * @serial_drivers: NULL-terminated array of pointers to drivers to be registered - * - * Registers @udriver and all the drivers in the @serial_drivers array. - * Automatically fills in the .no_dynamic_id and PM fields in @udriver and - * the .usb_driver field in each serial driver. - */ -int usb_serial_register_drivers(struct usb_driver *udriver, - struct usb_serial_driver * const serial_drivers[]) -{ - int rc; - const struct usb_device_id *saved_id_table; - struct usb_serial_driver * const *sd; - - /* - * udriver must be registered before any of the serial drivers, - * because the store_new_id() routine for the serial drivers (in - * bus.c) probes udriver. - * - * Performance hack: We don't want udriver to be probed until - * the serial drivers are registered, because the probe would - * simply fail for lack of a matching serial driver. - * Therefore save off udriver's id_table until we are all set. - * - * Suspend/resume support is implemented in the usb-serial core, - * so fill in the PM-related fields in udriver. - */ - saved_id_table = udriver->id_table; - udriver->id_table = NULL; - - udriver->no_dynamic_id = 1; - udriver->supports_autosuspend = 1; - udriver->suspend = usb_serial_suspend; - udriver->resume = usb_serial_resume; - rc = usb_register(udriver); - if (rc) - return rc; - - for (sd = serial_drivers; *sd; ++sd) { - (*sd)->usb_driver = udriver; - rc = usb_serial_register(*sd); - if (rc) - goto failed; - } - - /* Now restore udriver's id_table and look for matches */ - udriver->id_table = saved_id_table; - rc = driver_attach(&udriver->drvwrap.driver); - return 0; - - failed: - while (sd-- > serial_drivers) - usb_serial_deregister(*sd); - usb_deregister(udriver); - return rc; -} -EXPORT_SYMBOL_GPL(usb_serial_register_drivers); - -/** - * usb_serial_deregister_drivers - deregister drivers for a usb-serial module - * @udriver: usb_driver to unregister - * @serial_drivers: NULL-terminated array of pointers to drivers to be deregistered - * - * Deregisters @udriver and all the drivers in the @serial_drivers array. - */ -void usb_serial_deregister_drivers(struct usb_driver *udriver, - struct usb_serial_driver * const serial_drivers[]) -{ - for (; *serial_drivers; ++serial_drivers) - usb_serial_deregister(*serial_drivers); - usb_deregister(udriver); -} -EXPORT_SYMBOL_GPL(usb_serial_deregister_drivers); - -/* Module information */ -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/usb-wwan.h b/ANDROID_3.4.5/drivers/usb/serial/usb-wwan.h deleted file mode 100644 index c47b6ec0..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/usb-wwan.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Definitions for USB serial mobile broadband cards - */ - -#ifndef __LINUX_USB_USB_WWAN -#define __LINUX_USB_USB_WWAN - -extern void usb_wwan_dtr_rts(struct usb_serial_port *port, int on); -extern int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port); -extern void usb_wwan_close(struct usb_serial_port *port); -extern int usb_wwan_startup(struct usb_serial *serial); -extern void usb_wwan_disconnect(struct usb_serial *serial); -extern void usb_wwan_release(struct usb_serial *serial); -extern int usb_wwan_write_room(struct tty_struct *tty); -extern void usb_wwan_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old); -extern int usb_wwan_tiocmget(struct tty_struct *tty); -extern int usb_wwan_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear); -extern int usb_wwan_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); -extern int usb_wwan_send_setup(struct usb_serial_port *port); -extern int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count); -extern int usb_wwan_chars_in_buffer(struct tty_struct *tty); -#ifdef CONFIG_PM -extern int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message); -extern int usb_wwan_resume(struct usb_serial *serial); -#endif - -/* per port private data */ - -#define N_IN_URB 4 -#define N_OUT_URB 4 -#define IN_BUFLEN 4096 -#define OUT_BUFLEN 4096 - -struct usb_wwan_intf_private { - spinlock_t susp_lock; - unsigned int suspended:1; - int in_flight; - int (*send_setup) (struct usb_serial_port *port); - void *private; -}; - -struct usb_wwan_port_private { - /* Input endpoints and buffer for this port */ - struct urb *in_urbs[N_IN_URB]; - u8 *in_buffer[N_IN_URB]; - /* Output endpoints and buffer for this port */ - struct urb *out_urbs[N_OUT_URB]; - u8 *out_buffer[N_OUT_URB]; - unsigned long out_busy; /* Bit vector of URBs in use */ - int opened; - struct usb_anchor delayed; - - /* Settings for the port */ - int rts_state; /* Handshaking pins (outputs) */ - int dtr_state; - int cts_state; /* Handshaking pins (inputs) */ - int dsr_state; - int dcd_state; - int ri_state; - - unsigned long tx_start_time[N_OUT_URB]; -}; - -#endif /* __LINUX_USB_USB_WWAN */ diff --git a/ANDROID_3.4.5/drivers/usb/serial/usb_debug.c b/ANDROID_3.4.5/drivers/usb/serial/usb_debug.c deleted file mode 100644 index e3e8995a..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/usb_debug.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * USB Debug cable driver - * - * Copyright (C) 2006 Greg Kroah-Hartman - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include - -#define USB_DEBUG_MAX_PACKET_SIZE 8 -#define USB_DEBUG_BRK_SIZE 8 -static char USB_DEBUG_BRK[USB_DEBUG_BRK_SIZE] = { - 0x00, - 0xff, - 0x01, - 0xfe, - 0x00, - 0xfe, - 0x01, - 0xff, -}; - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(0x0525, 0x127a) }, - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver debug_driver = { - .name = "debug", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - -/* This HW really does not support a serial break, so one will be - * emulated when ever the break state is set to true. - */ -static void usb_debug_break_ctl(struct tty_struct *tty, int break_state) -{ - struct usb_serial_port *port = tty->driver_data; - if (!break_state) - return; - usb_serial_generic_write(tty, port, USB_DEBUG_BRK, USB_DEBUG_BRK_SIZE); -} - -static void usb_debug_process_read_urb(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - - if (urb->actual_length == USB_DEBUG_BRK_SIZE && - memcmp(urb->transfer_buffer, USB_DEBUG_BRK, - USB_DEBUG_BRK_SIZE) == 0) { - usb_serial_handle_break(port); - return; - } - - usb_serial_generic_process_read_urb(urb); -} - -static struct usb_serial_driver debug_device = { - .driver = { - .owner = THIS_MODULE, - .name = "debug", - }, - .id_table = id_table, - .num_ports = 1, - .bulk_out_size = USB_DEBUG_MAX_PACKET_SIZE, - .break_ctl = usb_debug_break_ctl, - .process_read_urb = usb_debug_process_read_urb, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &debug_device, NULL -}; - -module_usb_serial_driver(debug_driver, serial_drivers); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/usb_wwan.c b/ANDROID_3.4.5/drivers/usb/serial/usb_wwan.c deleted file mode 100644 index c88657dd..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/usb_wwan.c +++ /dev/null @@ -1,774 +0,0 @@ -/* - USB Driver layer for GSM modems - - Copyright (C) 2005 Matthias Urlichs - - This driver is free software; you can redistribute it and/or modify - it under the terms of Version 2 of the GNU General Public License as - published by the Free Software Foundation. - - Portions copied from the Keyspan driver by Hugh Blemings - - History: see the git log. - - Work sponsored by: Sigos GmbH, Germany - - This driver exists because the "normal" serial driver doesn't work too well - with GSM modems. Issues: - - data loss -- one single Receive URB is not nearly enough - - controlling the baud rate doesn't make sense -*/ - -#define DRIVER_VERSION "v0.7.2" -#define DRIVER_AUTHOR "Matthias Urlichs " -#define DRIVER_DESC "USB Driver for GSM modems" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "usb-wwan.h" - -static bool debug; - -void usb_wwan_dtr_rts(struct usb_serial_port *port, int on) -{ - struct usb_serial *serial = port->serial; - struct usb_wwan_port_private *portdata; - - struct usb_wwan_intf_private *intfdata; - - dbg("%s", __func__); - - intfdata = port->serial->private; - - if (!intfdata->send_setup) - return; - - portdata = usb_get_serial_port_data(port); - mutex_lock(&serial->disc_mutex); - portdata->rts_state = on; - portdata->dtr_state = on; - if (serial->dev) - intfdata->send_setup(port); - mutex_unlock(&serial->disc_mutex); -} -EXPORT_SYMBOL(usb_wwan_dtr_rts); - -void usb_wwan_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old_termios) -{ - struct usb_wwan_intf_private *intfdata = port->serial->private; - - dbg("%s", __func__); - - /* Doesn't support option setting */ - tty_termios_copy_hw(tty->termios, old_termios); - - if (intfdata->send_setup) - intfdata->send_setup(port); -} -EXPORT_SYMBOL(usb_wwan_set_termios); - -int usb_wwan_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - unsigned int value; - struct usb_wwan_port_private *portdata; - - portdata = usb_get_serial_port_data(port); - - value = ((portdata->rts_state) ? TIOCM_RTS : 0) | - ((portdata->dtr_state) ? TIOCM_DTR : 0) | - ((portdata->cts_state) ? TIOCM_CTS : 0) | - ((portdata->dsr_state) ? TIOCM_DSR : 0) | - ((portdata->dcd_state) ? TIOCM_CAR : 0) | - ((portdata->ri_state) ? TIOCM_RNG : 0); - - return value; -} -EXPORT_SYMBOL(usb_wwan_tiocmget); - -int usb_wwan_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_wwan_port_private *portdata; - struct usb_wwan_intf_private *intfdata; - - portdata = usb_get_serial_port_data(port); - intfdata = port->serial->private; - - if (!intfdata->send_setup) - return -EINVAL; - - /* FIXME: what locks portdata fields ? */ - if (set & TIOCM_RTS) - portdata->rts_state = 1; - if (set & TIOCM_DTR) - portdata->dtr_state = 1; - - if (clear & TIOCM_RTS) - portdata->rts_state = 0; - if (clear & TIOCM_DTR) - portdata->dtr_state = 0; - return intfdata->send_setup(port); -} -EXPORT_SYMBOL(usb_wwan_tiocmset); - -static int get_serial_info(struct usb_serial_port *port, - struct serial_struct __user *retinfo) -{ - struct serial_struct tmp; - - if (!retinfo) - return -EFAULT; - - memset(&tmp, 0, sizeof(tmp)); - tmp.line = port->serial->minor; - tmp.port = port->number; - tmp.baud_base = tty_get_baud_rate(port->port.tty); - tmp.close_delay = port->port.close_delay / 10; - tmp.closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? - ASYNC_CLOSING_WAIT_NONE : - port->port.closing_wait / 10; - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - return 0; -} - -static int set_serial_info(struct usb_serial_port *port, - struct serial_struct __user *newinfo) -{ - struct serial_struct new_serial; - unsigned int closing_wait, close_delay; - int retval = 0; - - if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) - return -EFAULT; - - close_delay = new_serial.close_delay * 10; - closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? - ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; - - mutex_lock(&port->port.mutex); - - if (!capable(CAP_SYS_ADMIN)) { - if ((close_delay != port->port.close_delay) || - (closing_wait != port->port.closing_wait)) - retval = -EPERM; - else - retval = -EOPNOTSUPP; - } else { - port->port.close_delay = close_delay; - port->port.closing_wait = closing_wait; - } - - mutex_unlock(&port->port.mutex); - return retval; -} - -int usb_wwan_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - - dbg("%s cmd 0x%04x", __func__, cmd); - - switch (cmd) { - case TIOCGSERIAL: - return get_serial_info(port, - (struct serial_struct __user *) arg); - case TIOCSSERIAL: - return set_serial_info(port, - (struct serial_struct __user *) arg); - default: - break; - } - - dbg("%s arg not supported", __func__); - - return -ENOIOCTLCMD; -} -EXPORT_SYMBOL(usb_wwan_ioctl); - -/* Write */ -int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - struct usb_wwan_port_private *portdata; - struct usb_wwan_intf_private *intfdata; - int i; - int left, todo; - struct urb *this_urb = NULL; /* spurious */ - int err; - unsigned long flags; - - portdata = usb_get_serial_port_data(port); - intfdata = port->serial->private; - - dbg("%s: write (%d chars)", __func__, count); - - i = 0; - left = count; - for (i = 0; left > 0 && i < N_OUT_URB; i++) { - todo = left; - if (todo > OUT_BUFLEN) - todo = OUT_BUFLEN; - - this_urb = portdata->out_urbs[i]; - if (test_and_set_bit(i, &portdata->out_busy)) { - if (time_before(jiffies, - portdata->tx_start_time[i] + 10 * HZ)) - continue; - usb_unlink_urb(this_urb); - continue; - } - dbg("%s: endpoint %d buf %d", __func__, - usb_pipeendpoint(this_urb->pipe), i); - - err = usb_autopm_get_interface_async(port->serial->interface); - if (err < 0) - break; - - /* send the data */ - memcpy(this_urb->transfer_buffer, buf, todo); - this_urb->transfer_buffer_length = todo; - - spin_lock_irqsave(&intfdata->susp_lock, flags); - if (intfdata->suspended) { - usb_anchor_urb(this_urb, &portdata->delayed); - spin_unlock_irqrestore(&intfdata->susp_lock, flags); - } else { - intfdata->in_flight++; - spin_unlock_irqrestore(&intfdata->susp_lock, flags); - err = usb_submit_urb(this_urb, GFP_ATOMIC); - if (err) { - dbg("usb_submit_urb %p (write bulk) failed " - "(%d)", this_urb, err); - clear_bit(i, &portdata->out_busy); - spin_lock_irqsave(&intfdata->susp_lock, flags); - intfdata->in_flight--; - spin_unlock_irqrestore(&intfdata->susp_lock, - flags); - usb_autopm_put_interface_async(port->serial->interface); - break; - } - } - - portdata->tx_start_time[i] = jiffies; - buf += todo; - left -= todo; - } - - count -= left; - dbg("%s: wrote (did %d)", __func__, count); - return count; -} -EXPORT_SYMBOL(usb_wwan_write); - -static void usb_wwan_indat_callback(struct urb *urb) -{ - int err; - int endpoint; - struct usb_serial_port *port; - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - int status = urb->status; - - dbg("%s: %p", __func__, urb); - - endpoint = usb_pipeendpoint(urb->pipe); - port = urb->context; - - if (status) { - dbg("%s: nonzero status: %d on endpoint %02x.", - __func__, status, endpoint); - } else { - tty = tty_port_tty_get(&port->port); - if (tty) { - if (urb->actual_length) { - tty_insert_flip_string(tty, data, - urb->actual_length); - tty_flip_buffer_push(tty); - } else - dbg("%s: empty read urb received", __func__); - tty_kref_put(tty); - } - - /* Resubmit urb so we continue receiving */ - if (status != -ESHUTDOWN) { - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) { - if (err != -EPERM) { - printk(KERN_ERR "%s: resubmit read urb failed. " - "(%d)", __func__, err); - /* busy also in error unless we are killed */ - usb_mark_last_busy(port->serial->dev); - } - } else { - usb_mark_last_busy(port->serial->dev); - } - } - - } -} - -static void usb_wwan_outdat_callback(struct urb *urb) -{ - struct usb_serial_port *port; - struct usb_wwan_port_private *portdata; - struct usb_wwan_intf_private *intfdata; - int i; - - dbg("%s", __func__); - - port = urb->context; - intfdata = port->serial->private; - - usb_serial_port_softint(port); - usb_autopm_put_interface_async(port->serial->interface); - portdata = usb_get_serial_port_data(port); - spin_lock(&intfdata->susp_lock); - intfdata->in_flight--; - spin_unlock(&intfdata->susp_lock); - - for (i = 0; i < N_OUT_URB; ++i) { - if (portdata->out_urbs[i] == urb) { - smp_mb__before_clear_bit(); - clear_bit(i, &portdata->out_busy); - break; - } - } -} - -int usb_wwan_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_wwan_port_private *portdata; - int i; - int data_len = 0; - struct urb *this_urb; - - portdata = usb_get_serial_port_data(port); - - for (i = 0; i < N_OUT_URB; i++) { - this_urb = portdata->out_urbs[i]; - if (this_urb && !test_bit(i, &portdata->out_busy)) - data_len += OUT_BUFLEN; - } - - dbg("%s: %d", __func__, data_len); - return data_len; -} -EXPORT_SYMBOL(usb_wwan_write_room); - -int usb_wwan_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_wwan_port_private *portdata; - int i; - int data_len = 0; - struct urb *this_urb; - - portdata = usb_get_serial_port_data(port); - - for (i = 0; i < N_OUT_URB; i++) { - this_urb = portdata->out_urbs[i]; - /* FIXME: This locking is insufficient as this_urb may - go unused during the test */ - if (this_urb && test_bit(i, &portdata->out_busy)) - data_len += this_urb->transfer_buffer_length; - } - dbg("%s: %d", __func__, data_len); - return data_len; -} -EXPORT_SYMBOL(usb_wwan_chars_in_buffer); - -int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct usb_wwan_port_private *portdata; - struct usb_wwan_intf_private *intfdata; - struct usb_serial *serial = port->serial; - int i, err; - struct urb *urb; - - portdata = usb_get_serial_port_data(port); - intfdata = serial->private; - - dbg("%s", __func__); - - /* Start reading from the IN endpoint */ - for (i = 0; i < N_IN_URB; i++) { - urb = portdata->in_urbs[i]; - if (!urb) - continue; - err = usb_submit_urb(urb, GFP_KERNEL); - if (err) { - dbg("%s: submit urb %d failed (%d) %d", - __func__, i, err, urb->transfer_buffer_length); - } - } - - if (intfdata->send_setup) - intfdata->send_setup(port); - - serial->interface->needs_remote_wakeup = 1; - spin_lock_irq(&intfdata->susp_lock); - portdata->opened = 1; - spin_unlock_irq(&intfdata->susp_lock); - /* this balances a get in the generic USB serial code */ - usb_autopm_put_interface(serial->interface); - - return 0; -} -EXPORT_SYMBOL(usb_wwan_open); - -void usb_wwan_close(struct usb_serial_port *port) -{ - int i; - struct usb_serial *serial = port->serial; - struct usb_wwan_port_private *portdata; - struct usb_wwan_intf_private *intfdata = port->serial->private; - - dbg("%s", __func__); - portdata = usb_get_serial_port_data(port); - - if (serial->dev) { - /* Stop reading/writing urbs */ - spin_lock_irq(&intfdata->susp_lock); - portdata->opened = 0; - spin_unlock_irq(&intfdata->susp_lock); - - for (i = 0; i < N_IN_URB; i++) - usb_kill_urb(portdata->in_urbs[i]); - for (i = 0; i < N_OUT_URB; i++) - usb_kill_urb(portdata->out_urbs[i]); - /* balancing - important as an error cannot be handled*/ - usb_autopm_get_interface_no_resume(serial->interface); - serial->interface->needs_remote_wakeup = 0; - } -} -EXPORT_SYMBOL(usb_wwan_close); - -/* Helper functions used by usb_wwan_setup_urbs */ -static struct urb *usb_wwan_setup_urb(struct usb_serial *serial, int endpoint, - int dir, void *ctx, char *buf, int len, - void (*callback) (struct urb *)) -{ - struct urb *urb; - - if (endpoint == -1) - return NULL; /* endpoint not needed */ - - urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */ - if (urb == NULL) { - dbg("%s: alloc for endpoint %d failed.", __func__, endpoint); - return NULL; - } - - /* Fill URB using supplied data. */ - usb_fill_bulk_urb(urb, serial->dev, - usb_sndbulkpipe(serial->dev, endpoint) | dir, - buf, len, callback, ctx); - - return urb; -} - -/* Setup urbs */ -static void usb_wwan_setup_urbs(struct usb_serial *serial) -{ - int i, j; - struct usb_serial_port *port; - struct usb_wwan_port_private *portdata; - - dbg("%s", __func__); - - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - portdata = usb_get_serial_port_data(port); - - /* Do indat endpoints first */ - for (j = 0; j < N_IN_URB; ++j) { - portdata->in_urbs[j] = usb_wwan_setup_urb(serial, - port-> - bulk_in_endpointAddress, - USB_DIR_IN, - port, - portdata-> - in_buffer[j], - IN_BUFLEN, - usb_wwan_indat_callback); - } - - /* outdat endpoints */ - for (j = 0; j < N_OUT_URB; ++j) { - portdata->out_urbs[j] = usb_wwan_setup_urb(serial, - port-> - bulk_out_endpointAddress, - USB_DIR_OUT, - port, - portdata-> - out_buffer - [j], - OUT_BUFLEN, - usb_wwan_outdat_callback); - } - } -} - -int usb_wwan_startup(struct usb_serial *serial) -{ - int i, j, err; - struct usb_serial_port *port; - struct usb_wwan_port_private *portdata; - u8 *buffer; - - dbg("%s", __func__); - - /* Now setup per port private data */ - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); - if (!portdata) { - dbg("%s: kmalloc for usb_wwan_port_private (%d) failed!.", - __func__, i); - return 1; - } - init_usb_anchor(&portdata->delayed); - - for (j = 0; j < N_IN_URB; j++) { - buffer = (u8 *) __get_free_page(GFP_KERNEL); - if (!buffer) - goto bail_out_error; - portdata->in_buffer[j] = buffer; - } - - for (j = 0; j < N_OUT_URB; j++) { - buffer = kmalloc(OUT_BUFLEN, GFP_KERNEL); - if (!buffer) - goto bail_out_error2; - portdata->out_buffer[j] = buffer; - } - - usb_set_serial_port_data(port, portdata); - - if (!port->interrupt_in_urb) - continue; - err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - if (err) - dbg("%s: submit irq_in urb failed %d", __func__, err); - } - usb_wwan_setup_urbs(serial); - return 0; - -bail_out_error2: - for (j = 0; j < N_OUT_URB; j++) - kfree(portdata->out_buffer[j]); -bail_out_error: - for (j = 0; j < N_IN_URB; j++) - if (portdata->in_buffer[j]) - free_page((unsigned long)portdata->in_buffer[j]); - kfree(portdata); - return 1; -} -EXPORT_SYMBOL(usb_wwan_startup); - -static void stop_read_write_urbs(struct usb_serial *serial) -{ - int i, j; - struct usb_serial_port *port; - struct usb_wwan_port_private *portdata; - - /* Stop reading/writing urbs */ - for (i = 0; i < serial->num_ports; ++i) { - port = serial->port[i]; - portdata = usb_get_serial_port_data(port); - for (j = 0; j < N_IN_URB; j++) - usb_kill_urb(portdata->in_urbs[j]); - for (j = 0; j < N_OUT_URB; j++) - usb_kill_urb(portdata->out_urbs[j]); - } -} - -void usb_wwan_disconnect(struct usb_serial *serial) -{ - dbg("%s", __func__); - - stop_read_write_urbs(serial); -} -EXPORT_SYMBOL(usb_wwan_disconnect); - -void usb_wwan_release(struct usb_serial *serial) -{ - int i, j; - struct usb_serial_port *port; - struct usb_wwan_port_private *portdata; - - dbg("%s", __func__); - - /* Now free them */ - for (i = 0; i < serial->num_ports; ++i) { - port = serial->port[i]; - portdata = usb_get_serial_port_data(port); - - for (j = 0; j < N_IN_URB; j++) { - usb_free_urb(portdata->in_urbs[j]); - free_page((unsigned long) - portdata->in_buffer[j]); - portdata->in_urbs[j] = NULL; - } - for (j = 0; j < N_OUT_URB; j++) { - usb_free_urb(portdata->out_urbs[j]); - kfree(portdata->out_buffer[j]); - portdata->out_urbs[j] = NULL; - } - } - - /* Now free per port private data */ - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - kfree(usb_get_serial_port_data(port)); - } -} -EXPORT_SYMBOL(usb_wwan_release); - -#ifdef CONFIG_PM -int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message) -{ - struct usb_wwan_intf_private *intfdata = serial->private; - int b; - - dbg("%s entered", __func__); - - if (PMSG_IS_AUTO(message)) { - spin_lock_irq(&intfdata->susp_lock); - b = intfdata->in_flight; - spin_unlock_irq(&intfdata->susp_lock); - - if (b) - return -EBUSY; - } - - spin_lock_irq(&intfdata->susp_lock); - intfdata->suspended = 1; - spin_unlock_irq(&intfdata->susp_lock); - stop_read_write_urbs(serial); - - return 0; -} -EXPORT_SYMBOL(usb_wwan_suspend); - -static void unbusy_queued_urb(struct urb *urb, struct usb_wwan_port_private *portdata) -{ - int i; - - for (i = 0; i < N_OUT_URB; i++) { - if (urb == portdata->out_urbs[i]) { - clear_bit(i, &portdata->out_busy); - break; - } - } -} - -static void play_delayed(struct usb_serial_port *port) -{ - struct usb_wwan_intf_private *data; - struct usb_wwan_port_private *portdata; - struct urb *urb; - int err; - - portdata = usb_get_serial_port_data(port); - data = port->serial->private; - while ((urb = usb_get_from_anchor(&portdata->delayed))) { - err = usb_submit_urb(urb, GFP_ATOMIC); - if (!err) { - data->in_flight++; - } else { - /* we have to throw away the rest */ - do { - unbusy_queued_urb(urb, portdata); - usb_autopm_put_interface_no_suspend(port->serial->interface); - } while ((urb = usb_get_from_anchor(&portdata->delayed))); - break; - } - } -} - -int usb_wwan_resume(struct usb_serial *serial) -{ - int i, j; - struct usb_serial_port *port; - struct usb_wwan_intf_private *intfdata = serial->private; - struct usb_wwan_port_private *portdata; - struct urb *urb; - int err = 0; - - dbg("%s entered", __func__); - /* get the interrupt URBs resubmitted unconditionally */ - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - if (!port->interrupt_in_urb) { - dbg("%s: No interrupt URB for port %d", __func__, i); - continue; - } - err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO); - dbg("Submitted interrupt URB for port %d (result %d)", i, err); - if (err < 0) { - err("%s: Error %d for interrupt URB of port%d", - __func__, err, i); - goto err_out; - } - } - - for (i = 0; i < serial->num_ports; i++) { - /* walk all ports */ - port = serial->port[i]; - portdata = usb_get_serial_port_data(port); - - /* skip closed ports */ - spin_lock_irq(&intfdata->susp_lock); - if (!portdata->opened) { - spin_unlock_irq(&intfdata->susp_lock); - continue; - } - - for (j = 0; j < N_IN_URB; j++) { - urb = portdata->in_urbs[j]; - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err < 0) { - err("%s: Error %d for bulk URB %d", - __func__, err, i); - spin_unlock_irq(&intfdata->susp_lock); - goto err_out; - } - } - play_delayed(port); - spin_unlock_irq(&intfdata->susp_lock); - } - spin_lock_irq(&intfdata->susp_lock); - intfdata->suspended = 0; - spin_unlock_irq(&intfdata->susp_lock); -err_out: - return err; -} -EXPORT_SYMBOL(usb_wwan_resume); -#endif - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug messages"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/via_option.c b/ANDROID_3.4.5/drivers/usb/serial/via_option.c deleted file mode 100755 index 2c8a84f3..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/via_option.c +++ /dev/null @@ -1,1218 +0,0 @@ -/* - USB Driver for GSM modems - - Copyright (C) 2005 Matthias Urlichs - - This driver is free software; you can redistribute it and/or modify - it under the terms of Version 2 of the GNU General Public License as - published by the Free Software Foundation. - - Portions copied from the Keyspan driver by Hugh Blemings - - History: see the git log. - - Work sponsored by: Sigos GmbH, Germany - - This driver exists because the "normal" serial driver doesn't work too well - with GSM modems. Issues: - - data loss -- one single Receive URB is not nearly enough - - nonstandard flow (Option devices) control - - controlling the baud rate doesn't make sense - - This driver is named "option" because the most common device it's - used for is a PC-Card (with an internal OHCI-USB interface, behind - which the GSM interface sits), made by Option Inc. - - Some of the "one port" devices actually exhibit multiple USB instances - on the USB bus. This is not a bug, these ports are used for different - device features. -*/ - -#define DRIVER_VERSION "v0.7.2" -#define DRIVER_AUTHOR "Matthias Urlichs " -#define DRIVER_DESC "USB Driver for GSM modems" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "via_usb-wwan.h" -#include "via_usb_wwan.c" - -#if defined(CONFIG_VIATELECOM_SYNC_CBP) -#include -//#include "../drivers/usb/core/usb.h" -#endif - -/* Function prototypes */ -static int option_probe(struct usb_serial *serial, - const struct usb_device_id *id); -static void option_release(struct usb_serial *serial); -static int option_send_setup(struct usb_serial_port *port); -static void option_instat_callback(struct urb *urb); -/* VIA-Telecom CBP(Non-CDC version) IDs */ -struct wake_lock ets_wake_lock; -int ets_wake_lock_init = 0; -#define VIATELECOM_VENDOR_ID 0x15EB -#define VIATELECOM_PRODUCT_ID 0x0001 -#define BORA9380_VENDOR_ID 0x16d8 -#define BORA9380_PRODUCT_ID 0x4000 - -/* Vendor and product IDs */ -#define OPTION_VENDOR_ID 0x0AF0 -#define OPTION_PRODUCT_COLT 0x5000 -#define OPTION_PRODUCT_RICOLA 0x6000 -#define OPTION_PRODUCT_RICOLA_LIGHT 0x6100 -#define OPTION_PRODUCT_RICOLA_QUAD 0x6200 -#define OPTION_PRODUCT_RICOLA_QUAD_LIGHT 0x6300 -#define OPTION_PRODUCT_RICOLA_NDIS 0x6050 -#define OPTION_PRODUCT_RICOLA_NDIS_LIGHT 0x6150 -#define OPTION_PRODUCT_RICOLA_NDIS_QUAD 0x6250 -#define OPTION_PRODUCT_RICOLA_NDIS_QUAD_LIGHT 0x6350 -#define OPTION_PRODUCT_COBRA 0x6500 -#define OPTION_PRODUCT_COBRA_BUS 0x6501 -#define OPTION_PRODUCT_VIPER 0x6600 -#define OPTION_PRODUCT_VIPER_BUS 0x6601 -#define OPTION_PRODUCT_GT_MAX_READY 0x6701 -#define OPTION_PRODUCT_FUJI_MODEM_LIGHT 0x6721 -#define OPTION_PRODUCT_FUJI_MODEM_GT 0x6741 -#define OPTION_PRODUCT_FUJI_MODEM_EX 0x6761 -#define OPTION_PRODUCT_KOI_MODEM 0x6800 -#define OPTION_PRODUCT_SCORPION_MODEM 0x6901 -#define OPTION_PRODUCT_ETNA_MODEM 0x7001 -#define OPTION_PRODUCT_ETNA_MODEM_LITE 0x7021 -#define OPTION_PRODUCT_ETNA_MODEM_GT 0x7041 -#define OPTION_PRODUCT_ETNA_MODEM_EX 0x7061 -#define OPTION_PRODUCT_ETNA_KOI_MODEM 0x7100 -#define OPTION_PRODUCT_GTM380_MODEM 0x7201 - -#define HUAWEI_VENDOR_ID 0x12D1 -#define HUAWEI_PRODUCT_E600 0x1001 -#define HUAWEI_PRODUCT_E220 0x1003 -#define HUAWEI_PRODUCT_E220BIS 0x1004 -#define HUAWEI_PRODUCT_E1401 0x1401 -#define HUAWEI_PRODUCT_E1402 0x1402 -#define HUAWEI_PRODUCT_E1403 0x1403 -#define HUAWEI_PRODUCT_E1404 0x1404 -#define HUAWEI_PRODUCT_E1405 0x1405 -#define HUAWEI_PRODUCT_E1406 0x1406 -#define HUAWEI_PRODUCT_E1407 0x1407 -#define HUAWEI_PRODUCT_E1408 0x1408 -#define HUAWEI_PRODUCT_E1409 0x1409 -#define HUAWEI_PRODUCT_E140A 0x140A -#define HUAWEI_PRODUCT_E140B 0x140B -#define HUAWEI_PRODUCT_E140C 0x140C -#define HUAWEI_PRODUCT_E140D 0x140D -#define HUAWEI_PRODUCT_E140E 0x140E -#define HUAWEI_PRODUCT_E140F 0x140F -#define HUAWEI_PRODUCT_E1410 0x1410 -#define HUAWEI_PRODUCT_E1411 0x1411 -#define HUAWEI_PRODUCT_E1412 0x1412 -#define HUAWEI_PRODUCT_E1413 0x1413 -#define HUAWEI_PRODUCT_E1414 0x1414 -#define HUAWEI_PRODUCT_E1415 0x1415 -#define HUAWEI_PRODUCT_E1416 0x1416 -#define HUAWEI_PRODUCT_E1417 0x1417 -#define HUAWEI_PRODUCT_E1418 0x1418 -#define HUAWEI_PRODUCT_E1419 0x1419 -#define HUAWEI_PRODUCT_E141A 0x141A -#define HUAWEI_PRODUCT_E141B 0x141B -#define HUAWEI_PRODUCT_E141C 0x141C -#define HUAWEI_PRODUCT_E141D 0x141D -#define HUAWEI_PRODUCT_E141E 0x141E -#define HUAWEI_PRODUCT_E141F 0x141F -#define HUAWEI_PRODUCT_E1420 0x1420 -#define HUAWEI_PRODUCT_E1421 0x1421 -#define HUAWEI_PRODUCT_E1422 0x1422 -#define HUAWEI_PRODUCT_E1423 0x1423 -#define HUAWEI_PRODUCT_E1424 0x1424 -#define HUAWEI_PRODUCT_E1425 0x1425 -#define HUAWEI_PRODUCT_E1426 0x1426 -#define HUAWEI_PRODUCT_E1427 0x1427 -#define HUAWEI_PRODUCT_E1428 0x1428 -#define HUAWEI_PRODUCT_E1429 0x1429 -#define HUAWEI_PRODUCT_E142A 0x142A -#define HUAWEI_PRODUCT_E142B 0x142B -#define HUAWEI_PRODUCT_E142C 0x142C -#define HUAWEI_PRODUCT_E142D 0x142D -#define HUAWEI_PRODUCT_E142E 0x142E -#define HUAWEI_PRODUCT_E142F 0x142F -#define HUAWEI_PRODUCT_E1430 0x1430 -#define HUAWEI_PRODUCT_E1431 0x1431 -#define HUAWEI_PRODUCT_E1432 0x1432 -#define HUAWEI_PRODUCT_E1433 0x1433 -#define HUAWEI_PRODUCT_E1434 0x1434 -#define HUAWEI_PRODUCT_E1435 0x1435 -#define HUAWEI_PRODUCT_E1436 0x1436 -#define HUAWEI_PRODUCT_E1437 0x1437 -#define HUAWEI_PRODUCT_E1438 0x1438 -#define HUAWEI_PRODUCT_E1439 0x1439 -#define HUAWEI_PRODUCT_E143A 0x143A -#define HUAWEI_PRODUCT_E143B 0x143B -#define HUAWEI_PRODUCT_E143C 0x143C -#define HUAWEI_PRODUCT_E143D 0x143D -#define HUAWEI_PRODUCT_E143E 0x143E -#define HUAWEI_PRODUCT_E143F 0x143F -#define HUAWEI_PRODUCT_K4505 0x1464 -#define HUAWEI_PRODUCT_K3765 0x1465 -#define HUAWEI_PRODUCT_E14AC 0x14AC -#define HUAWEI_PRODUCT_K3806 0x14AE -#define HUAWEI_PRODUCT_K4605 0x14C6 -#define HUAWEI_PRODUCT_K5005 0x14C8 -#define HUAWEI_PRODUCT_K3770 0x14C9 -#define HUAWEI_PRODUCT_K3771 0x14CA -#define HUAWEI_PRODUCT_K4510 0x14CB -#define HUAWEI_PRODUCT_K4511 0x14CC -#define HUAWEI_PRODUCT_ETS1220 0x1803 -#define HUAWEI_PRODUCT_E353 0x1506 -//aron add-------- -#define HUAWEI_PRODUCT_E153 0x1446 -#define HUAWEI_PRODUCT_E173 0x1C05 -//---------- -#define QUANTA_VENDOR_ID 0x0408 -#define QUANTA_PRODUCT_Q101 0xEA02 -#define QUANTA_PRODUCT_Q111 0xEA03 -#define QUANTA_PRODUCT_GLX 0xEA04 -#define QUANTA_PRODUCT_GKE 0xEA05 -#define QUANTA_PRODUCT_GLE 0xEA06 - -#define NOVATELWIRELESS_VENDOR_ID 0x1410 - -/* YISO PRODUCTS */ - -#define YISO_VENDOR_ID 0x0EAB -#define YISO_PRODUCT_U893 0xC893 - -/* - * NOVATEL WIRELESS PRODUCTS - * - * Note from Novatel Wireless: - * If your Novatel modem does not work on linux, don't - * change the option module, but check our website. If - * that does not help, contact ddeschepper@nvtl.com -*/ -/* MERLIN EVDO PRODUCTS */ -#define NOVATELWIRELESS_PRODUCT_V640 0x1100 -#define NOVATELWIRELESS_PRODUCT_V620 0x1110 -#define NOVATELWIRELESS_PRODUCT_V740 0x1120 -#define NOVATELWIRELESS_PRODUCT_V720 0x1130 - -/* MERLIN HSDPA/HSPA PRODUCTS */ -#define NOVATELWIRELESS_PRODUCT_U730 0x1400 -#define NOVATELWIRELESS_PRODUCT_U740 0x1410 -#define NOVATELWIRELESS_PRODUCT_U870 0x1420 -#define NOVATELWIRELESS_PRODUCT_XU870 0x1430 -#define NOVATELWIRELESS_PRODUCT_X950D 0x1450 - -/* EXPEDITE PRODUCTS */ -#define NOVATELWIRELESS_PRODUCT_EV620 0x2100 -#define NOVATELWIRELESS_PRODUCT_ES720 0x2110 -#define NOVATELWIRELESS_PRODUCT_E725 0x2120 -#define NOVATELWIRELESS_PRODUCT_ES620 0x2130 -#define NOVATELWIRELESS_PRODUCT_EU730 0x2400 -#define NOVATELWIRELESS_PRODUCT_EU740 0x2410 -#define NOVATELWIRELESS_PRODUCT_EU870D 0x2420 -/* OVATION PRODUCTS */ -#define NOVATELWIRELESS_PRODUCT_MC727 0x4100 -#define NOVATELWIRELESS_PRODUCT_MC950D 0x4400 -/* - * Note from Novatel Wireless: - * All PID in the 5xxx range are currently reserved for - * auto-install CDROMs, and should not be added to this - * module. - * - * #define NOVATELWIRELESS_PRODUCT_U727 0x5010 - * #define NOVATELWIRELESS_PRODUCT_MC727_NEW 0x5100 -*/ -#define NOVATELWIRELESS_PRODUCT_OVMC760 0x6002 -#define NOVATELWIRELESS_PRODUCT_MC780 0x6010 -#define NOVATELWIRELESS_PRODUCT_EVDO_FULLSPEED 0x6000 -#define NOVATELWIRELESS_PRODUCT_EVDO_HIGHSPEED 0x6001 -#define NOVATELWIRELESS_PRODUCT_HSPA_FULLSPEED 0x7000 -#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED 0x7001 -#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED3 0x7003 -#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED4 0x7004 -#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED5 0x7005 -#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED6 0x7006 -#define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED7 0x7007 -#define NOVATELWIRELESS_PRODUCT_MC996D 0x7030 -#define NOVATELWIRELESS_PRODUCT_MF3470 0x7041 -#define NOVATELWIRELESS_PRODUCT_MC547 0x7042 -#define NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_FULLSPEED 0x8000 -#define NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_HIGHSPEED 0x8001 -#define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED 0x9000 -#define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED 0x9001 -#define NOVATELWIRELESS_PRODUCT_G1 0xA001 -#define NOVATELWIRELESS_PRODUCT_G1_M 0xA002 -#define NOVATELWIRELESS_PRODUCT_G2 0xA010 -#define NOVATELWIRELESS_PRODUCT_MC551 0xB001 - -/* AMOI PRODUCTS */ -#define AMOI_VENDOR_ID 0x1614 -#define AMOI_PRODUCT_H01 0x0800 -#define AMOI_PRODUCT_H01A 0x7002 -#define AMOI_PRODUCT_H02 0x0802 -#define AMOI_PRODUCT_SKYPEPHONE_S2 0x0407 - -#define DELL_VENDOR_ID 0x413C - -/* Dell modems */ -#define DELL_PRODUCT_5700_MINICARD 0x8114 -#define DELL_PRODUCT_5500_MINICARD 0x8115 -#define DELL_PRODUCT_5505_MINICARD 0x8116 -#define DELL_PRODUCT_5700_EXPRESSCARD 0x8117 -#define DELL_PRODUCT_5510_EXPRESSCARD 0x8118 - -#define DELL_PRODUCT_5700_MINICARD_SPRINT 0x8128 -#define DELL_PRODUCT_5700_MINICARD_TELUS 0x8129 - -#define DELL_PRODUCT_5720_MINICARD_VZW 0x8133 -#define DELL_PRODUCT_5720_MINICARD_SPRINT 0x8134 -#define DELL_PRODUCT_5720_MINICARD_TELUS 0x8135 -#define DELL_PRODUCT_5520_MINICARD_CINGULAR 0x8136 -#define DELL_PRODUCT_5520_MINICARD_GENERIC_L 0x8137 -#define DELL_PRODUCT_5520_MINICARD_GENERIC_I 0x8138 - -#define DELL_PRODUCT_5730_MINICARD_SPRINT 0x8180 -#define DELL_PRODUCT_5730_MINICARD_TELUS 0x8181 -#define DELL_PRODUCT_5730_MINICARD_VZW 0x8182 - -#define KYOCERA_VENDOR_ID 0x0c88 -#define KYOCERA_PRODUCT_KPC650 0x17da -#define KYOCERA_PRODUCT_KPC680 0x180a - -#define ANYDATA_VENDOR_ID 0x16d5 -#define ANYDATA_PRODUCT_ADU_620UW 0x6202 -#define ANYDATA_PRODUCT_ADU_E100A 0x6501 -#define ANYDATA_PRODUCT_ADU_500A 0x6502 - -#define AXESSTEL_VENDOR_ID 0x1726 -#define AXESSTEL_PRODUCT_MV110H 0x1000 - -#define BANDRICH_VENDOR_ID 0x1A8D -#define BANDRICH_PRODUCT_C100_1 0x1002 -#define BANDRICH_PRODUCT_C100_2 0x1003 -#define BANDRICH_PRODUCT_1004 0x1004 -#define BANDRICH_PRODUCT_1005 0x1005 -#define BANDRICH_PRODUCT_1006 0x1006 -#define BANDRICH_PRODUCT_1007 0x1007 -#define BANDRICH_PRODUCT_1008 0x1008 -#define BANDRICH_PRODUCT_1009 0x1009 -#define BANDRICH_PRODUCT_100A 0x100a - -#define BANDRICH_PRODUCT_100B 0x100b -#define BANDRICH_PRODUCT_100C 0x100c -#define BANDRICH_PRODUCT_100D 0x100d -#define BANDRICH_PRODUCT_100E 0x100e - -#define BANDRICH_PRODUCT_100F 0x100f -#define BANDRICH_PRODUCT_1010 0x1010 -#define BANDRICH_PRODUCT_1011 0x1011 -#define BANDRICH_PRODUCT_1012 0x1012 - -#define QUALCOMM_VENDOR_ID 0x05C6 - -#define CMOTECH_VENDOR_ID 0x16d8 -#define CMOTECH_PRODUCT_6008 0x6008 -#define CMOTECH_PRODUCT_6280 0x6280 - -#define TELIT_VENDOR_ID 0x1bc7 -#define TELIT_PRODUCT_UC864E 0x1003 -#define TELIT_PRODUCT_UC864G 0x1004 -#define TELIT_PRODUCT_CC864_DUAL 0x1005 -#define TELIT_PRODUCT_CC864_SINGLE 0x1006 -#define TELIT_PRODUCT_DE910_DUAL 0x1010 - -/* ZTE PRODUCTS */ -#define ZTE_VENDOR_ID 0x19d2 -#define ZTE_PRODUCT_MF622 0x0001 -#define ZTE_PRODUCT_MF628 0x0015 -#define ZTE_PRODUCT_MF626 0x0031 -#define ZTE_PRODUCT_CDMA_TECH 0xfffe -#define ZTE_PRODUCT_AC8710 0xfff1 -#define ZTE_PRODUCT_AC2726 0xfff5 -#define ZTE_PRODUCT_AC8710T 0xffff -#define ZTE_PRODUCT_MC2718 0xffe8 -#define ZTE_PRODUCT_AD3812 0xffeb -#define ZTE_PRODUCT_MC2716 0xffed - -#define BENQ_VENDOR_ID 0x04a5 -#define BENQ_PRODUCT_H10 0x4068 - -#define DLINK_VENDOR_ID 0x1186 -#define DLINK_PRODUCT_DWM_652 0x3e04 -#define DLINK_PRODUCT_DWM_652_U5 0xce16 -#define DLINK_PRODUCT_DWM_652_U5A 0xce1e - -#define QISDA_VENDOR_ID 0x1da5 -#define QISDA_PRODUCT_H21_4512 0x4512 -#define QISDA_PRODUCT_H21_4523 0x4523 -#define QISDA_PRODUCT_H20_4515 0x4515 -#define QISDA_PRODUCT_H20_4518 0x4518 -#define QISDA_PRODUCT_H20_4519 0x4519 - -/* TLAYTECH PRODUCTS */ -#define TLAYTECH_VENDOR_ID 0x20B9 -#define TLAYTECH_PRODUCT_TEU800 0x1682 - -/* TOSHIBA PRODUCTS */ -#define TOSHIBA_VENDOR_ID 0x0930 -#define TOSHIBA_PRODUCT_HSDPA_MINICARD 0x1302 -#define TOSHIBA_PRODUCT_G450 0x0d45 - -#define ALINK_VENDOR_ID 0x1e0e -#define ALINK_PRODUCT_PH300 0x9100 -#define ALINK_PRODUCT_3GU 0x9200 - -/* ALCATEL PRODUCTS */ -#define ALCATEL_VENDOR_ID 0x1bbb -#define ALCATEL_PRODUCT_X060S_X200 0x0000 - -#define PIRELLI_VENDOR_ID 0x1266 -#define PIRELLI_PRODUCT_C100_1 0x1002 -#define PIRELLI_PRODUCT_C100_2 0x1003 -#define PIRELLI_PRODUCT_1004 0x1004 -#define PIRELLI_PRODUCT_1005 0x1005 -#define PIRELLI_PRODUCT_1006 0x1006 -#define PIRELLI_PRODUCT_1007 0x1007 -#define PIRELLI_PRODUCT_1008 0x1008 -#define PIRELLI_PRODUCT_1009 0x1009 -#define PIRELLI_PRODUCT_100A 0x100a -#define PIRELLI_PRODUCT_100B 0x100b -#define PIRELLI_PRODUCT_100C 0x100c -#define PIRELLI_PRODUCT_100D 0x100d -#define PIRELLI_PRODUCT_100E 0x100e -#define PIRELLI_PRODUCT_100F 0x100f -#define PIRELLI_PRODUCT_1011 0x1011 -#define PIRELLI_PRODUCT_1012 0x1012 - -/* Airplus products */ -#define AIRPLUS_VENDOR_ID 0x1011 -#define AIRPLUS_PRODUCT_MCD650 0x3198 - -/* Longcheer/Longsung vendor ID; makes whitelabel devices that - * many other vendors like 4G Systems, Alcatel, ChinaBird, - * Mobidata, etc sell under their own brand names. - */ -#define LONGCHEER_VENDOR_ID 0x1c9e - -/* 4G Systems products */ -/* This is the 4G XS Stick W14 a.k.a. Mobilcom Debitel Surf-Stick * - * It seems to contain a Qualcomm QSC6240/6290 chipset */ -#define FOUR_G_SYSTEMS_PRODUCT_W14 0x9603 - -/* Zoom */ -#define ZOOM_PRODUCT_4597 0x9607 - -/* Haier products */ -#define HAIER_VENDOR_ID 0x201e -#define HAIER_PRODUCT_CE100 0x2009 - -/* Cinterion (formerly Siemens) products */ -#define SIEMENS_VENDOR_ID 0x0681 -#define CINTERION_VENDOR_ID 0x1e2d -#define CINTERION_PRODUCT_HC25_MDM 0x0047 -#define CINTERION_PRODUCT_HC25_MDMNET 0x0040 -#define CINTERION_PRODUCT_HC28_MDM 0x004C -#define CINTERION_PRODUCT_HC28_MDMNET 0x004A /* same for HC28J */ -#define CINTERION_PRODUCT_EU3_E 0x0051 -#define CINTERION_PRODUCT_EU3_P 0x0052 -#define CINTERION_PRODUCT_PH8 0x0053 - -/* Olivetti products */ -#define OLIVETTI_VENDOR_ID 0x0b3c -#define OLIVETTI_PRODUCT_OLICARD100 0xc000 - -/* Celot products */ -#define CELOT_VENDOR_ID 0x211f -#define CELOT_PRODUCT_CT680M 0x6801 - -/* ONDA Communication vendor id */ -#define ONDA_VENDOR_ID 0x1ee8 - -/* ONDA MT825UP HSDPA 14.2 modem */ -#define ONDA_MT825UP 0x000b - -/* Samsung products */ -#define SAMSUNG_VENDOR_ID 0x04e8 -#define SAMSUNG_PRODUCT_GT_B3730 0x6889 - -/* YUGA products www.yuga-info.com gavin.kx@qq.com */ -#define YUGA_VENDOR_ID 0x257A -#define YUGA_PRODUCT_CEM600 0x1601 -#define YUGA_PRODUCT_CEM610 0x1602 -#define YUGA_PRODUCT_CEM500 0x1603 -#define YUGA_PRODUCT_CEM510 0x1604 -#define YUGA_PRODUCT_CEM800 0x1605 -#define YUGA_PRODUCT_CEM900 0x1606 - -#define YUGA_PRODUCT_CEU818 0x1607 -#define YUGA_PRODUCT_CEU816 0x1608 -#define YUGA_PRODUCT_CEU828 0x1609 -#define YUGA_PRODUCT_CEU826 0x160A -#define YUGA_PRODUCT_CEU518 0x160B -#define YUGA_PRODUCT_CEU516 0x160C -#define YUGA_PRODUCT_CEU528 0x160D -#define YUGA_PRODUCT_CEU526 0x160F -#define YUGA_PRODUCT_CEU881 0x161F -#define YUGA_PRODUCT_CEU882 0x162F - -#define YUGA_PRODUCT_CWM600 0x2601 -#define YUGA_PRODUCT_CWM610 0x2602 -#define YUGA_PRODUCT_CWM500 0x2603 -#define YUGA_PRODUCT_CWM510 0x2604 -#define YUGA_PRODUCT_CWM800 0x2605 -#define YUGA_PRODUCT_CWM900 0x2606 - -#define YUGA_PRODUCT_CWU718 0x2607 -#define YUGA_PRODUCT_CWU716 0x2608 -#define YUGA_PRODUCT_CWU728 0x2609 -#define YUGA_PRODUCT_CWU726 0x260A -#define YUGA_PRODUCT_CWU518 0x260B -#define YUGA_PRODUCT_CWU516 0x260C -#define YUGA_PRODUCT_CWU528 0x260D -#define YUGA_PRODUCT_CWU581 0x260E -#define YUGA_PRODUCT_CWU526 0x260F -#define YUGA_PRODUCT_CWU582 0x261F -#define YUGA_PRODUCT_CWU583 0x262F - -#define YUGA_PRODUCT_CLM600 0x3601 -#define YUGA_PRODUCT_CLM610 0x3602 -#define YUGA_PRODUCT_CLM500 0x3603 -#define YUGA_PRODUCT_CLM510 0x3604 -#define YUGA_PRODUCT_CLM800 0x3605 -#define YUGA_PRODUCT_CLM900 0x3606 - -#define YUGA_PRODUCT_CLU718 0x3607 -#define YUGA_PRODUCT_CLU716 0x3608 -#define YUGA_PRODUCT_CLU728 0x3609 -#define YUGA_PRODUCT_CLU726 0x360A -#define YUGA_PRODUCT_CLU518 0x360B -#define YUGA_PRODUCT_CLU516 0x360C -#define YUGA_PRODUCT_CLU528 0x360D -#define YUGA_PRODUCT_CLU526 0x360F - -/* Viettel products */ -#define VIETTEL_VENDOR_ID 0x2262 -#define VIETTEL_PRODUCT_VT1000 0x0002 - -/* ZD Incorporated */ -#define ZD_VENDOR_ID 0x0685 -#define ZD_PRODUCT_7000 0x7000 - -/* LG products */ -#define LG_VENDOR_ID 0x1004 -#define LG_PRODUCT_L02C 0x618f - -/* MediaTek products */ -#define MEDIATEK_VENDOR_ID 0x0e8d -#define MEDIATEK_PRODUCT_DC_1COM 0x00a0 -#define MEDIATEK_PRODUCT_DC_4COM 0x00a5 -#define MEDIATEK_PRODUCT_DC_5COM 0x00a4 -#define MEDIATEK_PRODUCT_7208_1COM 0x7101 -#define MEDIATEK_PRODUCT_7208_2COM 0x7102 -#define MEDIATEK_PRODUCT_FP_1COM 0x0003 -#define MEDIATEK_PRODUCT_FP_2COM 0x0023 -#define MEDIATEK_PRODUCT_FPDC_1COM 0x0043 -#define MEDIATEK_PRODUCT_FPDC_2COM 0x0033 - -/* Cellient products */ -#define CELLIENT_VENDOR_ID 0x2692 -#define CELLIENT_PRODUCT_MEN200 0x9005 - -/* some devices interfaces need special handling due to a number of reasons */ -enum option_blacklist_reason { - OPTION_BLACKLIST_NONE = 0, - OPTION_BLACKLIST_SENDSETUP = 1, - OPTION_BLACKLIST_RESERVED_IF = 2 -}; - -#define MAX_BL_NUM 8 -struct option_blacklist_info { - /* bitfield of interface numbers for OPTION_BLACKLIST_SENDSETUP */ - const unsigned long sendsetup; - /* bitfield of interface numbers for OPTION_BLACKLIST_RESERVED_IF */ - const unsigned long reserved; -}; - -static const struct option_blacklist_info four_g_w14_blacklist = { - .sendsetup = BIT(0) | BIT(1), -}; - -static const struct option_blacklist_info alcatel_x200_blacklist = { - .sendsetup = BIT(0) | BIT(1), -}; - -static const struct option_blacklist_info zte_0037_blacklist = { - .sendsetup = BIT(0) | BIT(1), -}; - -static const struct option_blacklist_info zte_k3765_z_blacklist = { - .sendsetup = BIT(0) | BIT(1) | BIT(2), - .reserved = BIT(4), -}; - -static const struct option_blacklist_info zte_ad3812_z_blacklist = { - .sendsetup = BIT(0) | BIT(1) | BIT(2), -}; - -static const struct option_blacklist_info zte_mc2718_z_blacklist = { - .sendsetup = BIT(1) | BIT(2) | BIT(3) | BIT(4), -}; - -static const struct option_blacklist_info zte_mc2716_z_blacklist = { - .sendsetup = BIT(1) | BIT(2) | BIT(3), -}; - -static const struct option_blacklist_info huawei_cdc12_blacklist = { - .reserved = BIT(1) | BIT(2), -}; - -static const struct option_blacklist_info net_intf1_blacklist = { - .reserved = BIT(1), -}; - -static const struct option_blacklist_info net_intf2_blacklist = { - .reserved = BIT(2), -}; - -static const struct option_blacklist_info net_intf3_blacklist = { - .reserved = BIT(3), -}; - -static const struct option_blacklist_info net_intf4_blacklist = { - .reserved = BIT(4), -}; - -static const struct option_blacklist_info net_intf5_blacklist = { - .reserved = BIT(5), -}; - -static const struct option_blacklist_info zte_mf626_blacklist = { - .sendsetup = BIT(0) | BIT(1), - .reserved = BIT(4), -}; - -static const struct usb_device_id option_ids[] = { - { USB_DEVICE(VIATELECOM_VENDOR_ID, VIATELECOM_PRODUCT_ID) }, - { USB_DEVICE(0x201e, 0x1022) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, option_ids); - - -/* add rawbulk suspend support */ -static int usb_serial_option_suspend(struct usb_interface *intf, pm_message_t message) -{ - int rc = 0; - - rc = usb_serial_suspend(intf, message); - if(rc < 0) - { - err("usb_serial_suspend return error, errno=%d\n", rc); - return rc; - } -#ifdef CONFIG_USB_ANDROID_RAWBULK - return rawbulk_suspend_host_interface(intf->cur_altsetting->desc.bInterfaceNumber, message); -#else - return rc; -#endif -} - -static int usb_serial_option_resume(struct usb_interface *intf) -{ - int rc = 0; - - rc = usb_serial_resume(intf); - if(rc < 0) - { - err("usb_serial_resume return error, errno=%d\n", rc); - return rc; - } - -#ifdef CONFIG_USB_ANDROID_RAWBULK - return rawbulk_resume_host_interface(intf->cur_altsetting->desc.bInterfaceNumber); -#else - return rc; -#endif -} -/* End of temp added */ - -static int usb_serial_option_probe(struct usb_interface *interface, - const struct usb_device_id *id); -static void usb_serial_option_disconnect(struct usb_interface *interface); -static struct usb_driver option_driver = { - .name = "via_option", - .probe = usb_serial_option_probe, - .disconnect = usb_serial_option_disconnect, -#ifdef CONFIG_PM - .suspend = usb_serial_option_suspend, - .resume = usb_serial_option_resume, - .supports_autosuspend = 1, -#endif - .id_table = option_ids, -}; - -static int usb_wwan_option_write(struct tty_struct *tty, struct usb_serial_port - *port, const unsigned char *buf, int count); - - -/* The card has three separate interfaces, which the serial driver - * recognizes separately, thus num_port=1. - */ - -static struct usb_serial_driver option_1port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "via_option1", - }, - .description = "GSM modem (1-port)", - .id_table = option_ids, - .num_ports = 1, - .probe = option_probe, - .open = usb_wwan_open, - .close = usb_wwan_close, - .dtr_rts = usb_wwan_dtr_rts, - .write = usb_wwan_option_write, - .write_room = usb_wwan_write_room, - .chars_in_buffer = usb_wwan_chars_in_buffer, - .set_termios = usb_wwan_set_termios, - .tiocmget = usb_wwan_tiocmget, - .tiocmset = usb_wwan_tiocmset, - .ioctl = usb_wwan_ioctl, - .attach = usb_wwan_startup, - .disconnect = usb_wwan_disconnect, - .release = usb_wwan_release, - .read_int_callback = option_instat_callback, -#ifdef CONFIG_PM - .suspend = usb_wwan_suspend, - .resume = usb_wwan_resume, -#endif -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &option_1port_device, NULL -}; - -//static bool debug; - -//module_usb_serial_driver(option_driver, serial_drivers); - -static bool is_blacklisted(const u8 ifnum, enum option_blacklist_reason reason, - const struct option_blacklist_info *blacklist) -{ - unsigned long num; - const unsigned long *intf_list; - - if (blacklist) { - if (reason == OPTION_BLACKLIST_SENDSETUP) - intf_list = &blacklist->sendsetup; - else if (reason == OPTION_BLACKLIST_RESERVED_IF) - intf_list = &blacklist->reserved; - else { - BUG_ON(reason); - return false; - } - - for_each_set_bit(num, intf_list, MAX_BL_NUM + 1) { - if (num == ifnum) - return true; - } - } - return false; -} - - -static int usb_wwan_option_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ -#ifdef CONFIG_USB_ANDROID_RAWBULK - int inception; - struct usb_wwan_port_private *portdata = usb_get_serial_port_data(port); - spin_lock_irq(&portdata->incept_lock); - inception = portdata->inception; - spin_unlock_irq(&portdata->incept_lock); - - if (inception) - return 0; -#endif - - return usb_wwan_write(tty, port, buf, count); -} - -#ifdef CONFIG_USB_ANDROID_RAWBULK -#if defined(CONFIG_USB_SUSPEND) && defined(CONFIG_AP2MODEM_VIATELECOM) -extern void ap_wake_modem(void); -extern void ap_sleep_modem(void); -#endif - -#ifdef CONFIG_VIATELECOM_SYNC_CBP -static int option_rawbulk_asc_notifier(int msg, void *data) { - int opened; - struct usb_serial *serial = data; - struct usb_serial_port *port = serial->port[0]; - struct usb_wwan_port_private *portdata = usb_get_serial_port_data(port); - struct usb_wwan_intf_private *intfdata = serial->private; - - spin_lock_irq(&intfdata->susp_lock); - opened = portdata->opened; - spin_unlock_irq(&intfdata->susp_lock); - - if (!opened && msg == ASC_NTF_RX_PREPARE) - asc_rx_confirm_ready(USB_RX_HD_NAME, 1); - return 0; -} -#endif - -static int option_rawbulk_intercept(struct usb_interface *interface, unsigned int flags) { - int rc = 0; - struct usb_serial *serial = usb_get_intfdata(interface); - struct usb_serial_port *port = serial->port[0]; - struct usb_wwan_port_private *portdata = usb_get_serial_port_data(port); - struct usb_wwan_intf_private *intfdata = serial->private; - int nif = interface->cur_altsetting->desc.bInterfaceNumber; - int enable = flags & RAWBULK_INCEPT_FLAG_ENABLE; - int opened; - int n; - - spin_lock_irq(&portdata->incept_lock); - if (portdata->inception == !!enable) { - spin_unlock_irq(&portdata->incept_lock); - return -ENOENT; - } - spin_unlock_irq(&portdata->incept_lock); - - spin_lock_irq(&intfdata->susp_lock); - opened = portdata->opened; - spin_unlock_irq(&intfdata->susp_lock); - - printk(KERN_DEBUG "rawbulk do %s on port %d (%s)\n", enable? "incept": - "unincept", port->number, opened? "opened": "not-in-use"); - - if (enable) { -#if defined(CONFIG_VIATELECOM_SYNC_CBP) - struct asc_infor user = { - .notifier = option_rawbulk_asc_notifier, - .data = serial, - }; - snprintf(user.name, ASC_NAME_LEN, "%s%d", RAWBULK_RX_USER_NAME, nif); - asc_rx_add_user(USB_RX_HD_NAME, &user); - asc_tx_auto_ready(USB_TX_HD_NAME, 0); -#endif - -#ifdef CONFIG_PM - rc = usb_autopm_get_interface(interface); - if (rc < 0) - printk(KERN_ERR "incept failed while geting interface#%d\n", nif); -#endif - /* Stop reading/writing urbs */ - if (opened) { - if (!(flags & RAWBULK_INCEPT_FLAG_PUSH_WAY)) - for (n = 0; n < portdata->n_in_urb; n++) - usb_kill_urb(portdata->in_urbs[n]); - for (n = 0; n < portdata->n_out_urb; n++) - usb_kill_urb(portdata->out_urbs[n]); - } - /* Start urb for push-way */ - if (flags & RAWBULK_INCEPT_FLAG_PUSH_WAY) { - for (n = 0; n < portdata->n_in_urb; n ++) { - struct urb *urb = portdata->in_urbs[n]; - if (!urb || !urb->dev) - continue; - /* reset urb */ - usb_kill_urb(urb); - usb_clear_halt(urb->dev, urb->pipe); - rc = usb_submit_urb(urb, GFP_KERNEL); - if (rc < 0) - break; - } - if (rc < 0) - printk(KERN_ERR "incept %d while re-submitting " \ - "pushable urbs %d\n", nif, rc); - } - } else { -#if defined(CONFIG_VIATELECOM_SYNC_CBP) - char asc_user[ASC_NAME_LEN]; -#endif - rc = usb_autopm_get_interface(interface); - if (rc < 0) - printk(KERN_ERR "unincept while get interface#%d\n", nif); - if (!intfdata->suspended && opened) { - for (n = 0; n < portdata->n_in_urb; n ++) { - struct urb *urb = portdata->in_urbs[n]; - if (!urb || !urb->dev) - continue; - /* reset urb */ - usb_kill_urb(urb); - usb_clear_halt(urb->dev, urb->pipe); - rc = usb_submit_urb(urb, GFP_KERNEL); - if (rc < 0) - break; - } - if (rc < 0) - printk(KERN_ERR "unincept %d while reseting " \ - "bulk IN urbs %d\n", nif, rc); - } -#ifdef CONFIG_PM - usb_autopm_put_interface(interface); -#endif -#if defined(CONFIG_VIATELECOM_SYNC_CBP) - snprintf(asc_user, ASC_NAME_LEN, "%s%d", ASC_PATH(USB_RX_HD_NAME, RAWBULK_RX_USER_NAME), nif); - asc_rx_del_user(asc_user); -#endif - } - - if (!rc) { - spin_lock_irq(&portdata->incept_lock); - portdata->inception = !!enable; - spin_unlock_irq(&portdata->incept_lock); - } else - printk(KERN_ERR "failed(%d) to %s inception on interface#%d\n", - rc, enable? "enable": "disable", nif); - - return rc; -} - -#endif - -int serial_ntcall(struct notifier_block *nb, unsigned long val, void *nodata) -{ - struct usb_wwan_intf_private *data = container_of(nb,struct usb_wwan_intf_private,pm_nb); - - switch (val) { - case PM_SUSPEND_PREPARE: - usb_disable_autosuspend(data->udev); - return NOTIFY_DONE; - case PM_POST_SUSPEND: - usb_enable_autosuspend(data->udev); - return NOTIFY_DONE; - } - return NOTIFY_DONE; -} - -static int viatelecom_send_setup(struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - struct usb_wwan_port_private *portdata = usb_get_serial_port_data(port); - int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber; - - /* VIA-Telecom CBP DTR format */ - return usb_control_msg(serial->dev, - usb_sndctrlpipe(serial->dev, 0), - 0x01, 0x40, portdata->dtr_state? 1: 0, ifNum, - NULL, 0, USB_CTRL_SET_TIMEOUT); - - -} -static int option_probe(struct usb_serial *serial, - const struct usb_device_id *id) -{ - struct usb_wwan_intf_private *data; - - /* D-Link DWM 652 still exposes CD-Rom emulation interface in modem mode */ - if (serial->dev->descriptor.idVendor == DLINK_VENDOR_ID && - serial->dev->descriptor.idProduct == DLINK_PRODUCT_DWM_652 && - serial->interface->cur_altsetting->desc.bInterfaceClass == 0x8) - return -ENODEV; - - /* Bandrich modem and AT command interface is 0xff */ - if ((serial->dev->descriptor.idVendor == BANDRICH_VENDOR_ID || - serial->dev->descriptor.idVendor == PIRELLI_VENDOR_ID) && - serial->interface->cur_altsetting->desc.bInterfaceClass != 0xff) - return -ENODEV; - - /* Don't bind reserved interfaces (like network ones) which often have - * the same class/subclass/protocol as the serial interfaces. Look at - * the Windows driver .INF files for reserved interface numbers. - */ - if (is_blacklisted( - serial->interface->cur_altsetting->desc.bInterfaceNumber, - OPTION_BLACKLIST_RESERVED_IF, - (const struct option_blacklist_info *) id->driver_info)) - return -ENODEV; - - /* Don't bind network interface on Samsung GT-B3730, it is handled by a separate module */ - if (serial->dev->descriptor.idVendor == SAMSUNG_VENDOR_ID && - serial->dev->descriptor.idProduct == SAMSUNG_PRODUCT_GT_B3730 && - serial->interface->cur_altsetting->desc.bInterfaceClass != USB_CLASS_CDC_DATA) - return -ENODEV; - - data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL); - if (!data) - return -ENOMEM; - - - //kevin modify for viatel modem - data->send_setup = viatelecom_send_setup; - //data->send_setup = option_send_setup; - - spin_lock_init(&data->susp_lock); - data->private = (void *)id->driver_info; - return 0; -} - -static void option_release(struct usb_serial *serial) -{ - struct usb_wwan_intf_private *priv = usb_get_serial_data(serial); - - usb_wwan_release(serial); - - kfree(priv); -} - -#define USB_CBP_TESTMODE_ENABLE 0x1 -#define USB_CBP_TESTMODE_QUERY 0x2 -#define USB_CBP_TESTMODE_UNSOLICTED 0x3 -static ssize_t option_port_testmode_show(struct device *dev, struct device_attribute - *attr, char *buf) -{ - int rc; - struct usb_serial_port *port0 = container_of(dev, struct usb_serial_port, dev); - struct usb_device *udev = port0->serial->dev; - struct usb_interface *interface = port0->serial->interface; - int ifnum = interface->cur_altsetting->desc.bInterfaceNumber; - int feedback = -1; - rc = usb_autopm_get_interface(interface); - if (rc < 0) { - printk(KERN_ERR "failed to awake cp-usb when query testmode. %d\n", rc); - return -ENODEV; - } - rc = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), USB_CBP_TESTMODE_QUERY, - USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, - 0, ifnum, &feedback, 2, USB_CTRL_GET_TIMEOUT * 5); - usb_autopm_put_interface(interface); - if ((feedback & 0xff) == 0x1) - return sprintf(buf, "%s", "enabled"); - if ((feedback & 0xff) == 0x0) - return sprintf(buf, "%s", "disabled"); - printk(KERN_ERR "connot query cp testmode %d, feedback %04x\n", rc, feedback & 0xffff); - return -EOPNOTSUPP; -} - -static ssize_t option_port_testmode_store(struct device *dev, struct device_attribute - *attr, const char *buf, size_t count) -{ - int rc = 0; - int enable = -1; - struct usb_serial_port *port0 = container_of(dev, struct usb_serial_port, dev); - struct usb_device *udev = port0->serial->dev; - struct usb_interface *interface = port0->serial->interface; - int ifnum = interface->cur_altsetting->desc.bInterfaceNumber; - - if (!strncmp(buf, "enable", 6)) - enable = 1; - else if (!strncmp(buf, "disable", 7)) - enable = 0; - if (enable >= 0) { - rc = usb_autopm_get_interface(interface); - if (rc < 0) { - printk(KERN_ERR "failed to awake cp-usb when set testmode. %d\n", rc); - return -ENODEV; - } - rc = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - USB_CBP_TESTMODE_ENABLE, - USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, - enable, ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT); - usb_autopm_put_interface(interface); - if (rc < 0) { - printk(KERN_DEBUG "failed to sent testmode contorl msg %d\n", rc); - return rc; - } - } else if (!strncmp(buf, "unsolited", 9)) { - /* rc = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - USB_CBP_TESTMODE_UNSOLICTED, - USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, - 0, ifnum, ¶m, sizeof(param), USB_CTRL_SET_TIMEOUT); */ - printk(KERN_DEBUG "unsolited test mode for cp does not supported yet.\n"); - } - - return count; -} - -static DEVICE_ATTR(testmode, S_IRUGO | S_IWUSR, - option_port_testmode_show, - option_port_testmode_store); - -static int usb_serial_option_probe(struct usb_interface *interface, - const struct usb_device_id *id) { - struct usb_serial *serial; - int ret = usb_serial_probe(interface, id); - if (ret < 0) - return ret; - -#ifdef CONFIG_USB_ANDROID_RAWBULK - ret = rawbulk_bind_host_interface(interface, option_rawbulk_intercept); - if (ret < 0) - return ret; -#endif - - - - - serial = usb_get_intfdata(interface); - return sysfs_create_file(&serial->port[0]->dev.kobj, - &dev_attr_testmode.attr); -} - -static void usb_serial_option_disconnect(struct usb_interface *interface) { - struct usb_serial *serial = usb_get_intfdata(interface); - struct usb_wwan_intf_private *data = serial->private; - - - - unregister_pm_notifier(&data->pm_nb); - - sysfs_remove_file(&serial->port[0]->dev.kobj, &dev_attr_testmode.attr); -#ifdef CONFIG_USB_ANDROID_RAWBULK - rawbulk_unbind_host_interface(interface); -#endif - - usb_serial_disconnect(interface); -} - - -static void option_instat_callback(struct urb *urb) -{ - int err; - int status = urb->status; - struct usb_serial_port *port = urb->context; - struct usb_wwan_port_private *portdata = - usb_get_serial_port_data(port); - - dbg("%s", __func__); - dbg("%s: urb %p port %p has data %p", __func__, urb, port, portdata); - - if (status == 0) { - struct usb_ctrlrequest *req_pkt = - (struct usb_ctrlrequest *)urb->transfer_buffer; - - if (!req_pkt) { - dbg("%s: NULL req_pkt", __func__); - return; - } - if ((req_pkt->bRequestType == 0xA1) && - (req_pkt->bRequest == 0x20)) { - int old_dcd_state; - unsigned char signals = *((unsigned char *) - urb->transfer_buffer + - sizeof(struct usb_ctrlrequest)); - - dbg("%s: signal x%x", __func__, signals); - - old_dcd_state = portdata->dcd_state; - portdata->cts_state = 1; - portdata->dcd_state = ((signals & 0x01) ? 1 : 0); - portdata->dsr_state = ((signals & 0x02) ? 1 : 0); - portdata->ri_state = ((signals & 0x08) ? 1 : 0); - - if (old_dcd_state && !portdata->dcd_state) { - struct tty_struct *tty = - tty_port_tty_get(&port->port); - if (tty && !C_CLOCAL(tty)) - tty_hangup(tty); - tty_kref_put(tty); - } - } else { - dbg("%s: type %x req %x", __func__, - req_pkt->bRequestType, req_pkt->bRequest); - } - } else - err("%s: error %d", __func__, status); - - /* Resubmit urb so we continue receiving IRQ data */ - if (status != -ESHUTDOWN && status != -ENOENT) { - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) - dbg("%s: resubmit intr urb failed. (%d)", - __func__, err); - } -} - -/** send RTS/DTR state to the port. - * - * This is exactly the same as SET_CONTROL_LINE_STATE from the PSTN - * CDC. -*/ -static int option_send_setup(struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - struct usb_wwan_intf_private *intfdata = - (struct usb_wwan_intf_private *) serial->private; - struct usb_wwan_port_private *portdata; - int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber; - int val = 0; - dbg("%s", __func__); - - if (is_blacklisted(ifNum, OPTION_BLACKLIST_SENDSETUP, - (struct option_blacklist_info *) intfdata->private)) { - dbg("No send_setup on blacklisted interface #%d\n", ifNum); - return -EIO; - } - - portdata = usb_get_serial_port_data(port); - - if (portdata->dtr_state) - val |= 0x01; - if (portdata->rts_state) - val |= 0x02; - - return usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), - 0x22, 0x21, val, ifNum, NULL, 0, USB_CTRL_SET_TIMEOUT); -} - - - - -static int __init via_option_init(void) -{ - int retval; - - - retval = usb_serial_register_drivers(&option_driver, serial_drivers); - if (retval) - goto failed_driver_register; - - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n"); - - - - wake_lock_init(&ets_wake_lock, WAKE_LOCK_SUSPEND, "ETS_Prevent_Suspend"); - usb_ap_sync_cbp_init(); - return 0; - -failed_driver_register: - - - return retval; -} - - -static void __exit via_option_exit (void) -{ - - wake_lock_destroy(&ets_wake_lock); - - usb_serial_deregister_drivers(&option_driver, serial_drivers); -} - - -module_init(via_option_init); -module_exit(via_option_exit); - - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); - -//module_param(debug, bool, S_IRUGO | S_IWUSR); -//MODULE_PARM_DESC(debug, "Debug messages"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/via_usb-wwan.h b/ANDROID_3.4.5/drivers/usb/serial/via_usb-wwan.h deleted file mode 100755 index 415b74c6..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/via_usb-wwan.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Definitions for USB serial mobile broadband cards - */ - -#ifndef __LINUX_USB_USB_WWAN -#define __LINUX_USB_USB_WWAN - -#define CONFIG_VIATELECOM_SYNC_CBP 1 -#define CONFIG_USB_ANDROID_RAWBULK 1 - - - -extern void usb_wwan_dtr_rts(struct usb_serial_port *port, int on); -extern int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port); -extern void usb_wwan_close(struct usb_serial_port *port); -extern int usb_wwan_startup(struct usb_serial *serial); -extern void usb_wwan_disconnect(struct usb_serial *serial); -extern void usb_wwan_release(struct usb_serial *serial); -extern int usb_wwan_write_room(struct tty_struct *tty); -extern void usb_wwan_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old); -extern int usb_wwan_tiocmget(struct tty_struct *tty); -extern int usb_wwan_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear); -extern int usb_wwan_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); -extern int usb_wwan_send_setup(struct usb_serial_port *port); -extern int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count); -extern int usb_wwan_chars_in_buffer(struct tty_struct *tty); -#ifdef CONFIG_PM -extern int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message); -extern int usb_wwan_resume(struct usb_serial *serial); -#endif - -/* per port private data */ - -#define N_IN_URB 8 -#define N_OUT_URB 16 -#define IN_BUFLEN 4096 -#define OUT_BUFLEN 4096 - -#define MAX_IN_URBS 16 -#define MAX_OUT_URBS 16 - -struct usb_wwan_intf_private { - spinlock_t susp_lock; - struct usb_device *udev; - struct notifier_block pm_nb; - unsigned int suspended:1; - int in_flight; - int (*send_setup) (struct usb_serial_port *port); - void *private; -}; - -struct usb_wwan_port_private { - /* Input endpoints and buffer for this port */ - unsigned int n_in_urb; - unsigned int in_buflen; - struct urb *in_urbs[MAX_IN_URBS]; - u8 *in_buffer[MAX_IN_URBS]; - /* Output endpoints and buffer for this port */ - unsigned int n_out_urb; - unsigned int out_buflen; - struct urb *out_urbs[MAX_OUT_URBS]; - u8 *out_buffer[MAX_OUT_URBS]; - unsigned long out_busy; /* Bit vector of URBs in use */ - int opened; - struct usb_anchor delayed; - - /* Settings for the port */ - int rts_state; /* Handshaking pins (outputs) */ - int dtr_state; - int cts_state; /* Handshaking pins (inputs) */ - int dsr_state; - int dcd_state; - int ri_state; - - unsigned long tx_start_time[MAX_OUT_URBS]; - -#ifdef CONFIG_USB_ANDROID_RAWBULK - spinlock_t incept_lock; - unsigned int inception:1; -#endif -}; - -#endif /* __LINUX_USB_USB_WWAN */ diff --git a/ANDROID_3.4.5/drivers/usb/serial/via_usb_wwan.c b/ANDROID_3.4.5/drivers/usb/serial/via_usb_wwan.c deleted file mode 100755 index 56c11455..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/via_usb_wwan.c +++ /dev/null @@ -1,1013 +0,0 @@ -/* - USB Driver layer for GSM modems - - Copyright (C) 2005 Matthias Urlichs - - This driver is free software; you can redistribute it and/or modify - it under the terms of Version 2 of the GNU General Public License as - published by the Free Software Foundation. - - Portions copied from the Keyspan driver by Hugh Blemings - - History: see the git log. - - Work sponsored by: Sigos GmbH, Germany - - This driver exists because the "normal" serial driver doesn't work too well - with GSM modems. Issues: - - data loss -- one single Receive URB is not nearly enough - - controlling the baud rate doesn't make sense -*/ - -#define DRIVER_VERSION "v0.7.2" -#define DRIVER_AUTHOR "Matthias Urlichs " -#define DRIVER_DESC "USB Driver for GSM modems" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "via_usb-wwan.h" - -#ifdef CONFIG_USB_ANDROID_RAWBULK -#include -#endif - -#ifdef CONFIG_VIATELECOM_SYNC_CBP -#include -#define ASC_INTF_NUM (10) -atomic_t intf_pm_count[ASC_INTF_NUM]; - -#define EXPORT_SYMBOL(x) - - -static struct asc_config usb_tx_handle = { - .name = USB_TX_HD_NAME, - .gpio_wake = GPIO_VIATEL_USB_AP_WAKE_MDM, - .gpio_ready = GPIO_VIATEL_USB_MDM_RDY, - .polar = 1, -}; - -struct asc_config usb_rx_handle = { - .name = USB_RX_HD_NAME, - .gpio_wake = GPIO_VIATEL_USB_MDM_WAKE_AP, - .gpio_ready = GPIO_VIATEL_USB_AP_RDY, - .polar = 1, -}; - -static int usb_ap_sync_cbp_init(void) -{ - int i, ret = 0; - for(i = 0; i < ASC_INTF_NUM; i++){ - atomic_set(&intf_pm_count[i], 0); - } - asc_tx_register_handle(&usb_tx_handle); - asc_rx_register_handle(&usb_rx_handle); - return ret; -} - -//late_initcall(usb_ap_sync_cbp_init); - -static int cbp_usb_interface_notifier(int msg, void *data) - { - int index, ret = 0; - struct usb_interface * intf = (struct usb_interface *)data; - - if(!intf) { - printk(KERN_ERR "%s - usb find device interface error\n", __func__); - return -ENODEV; - } - - index = (int)intf->cur_altsetting->desc.bInterfaceNumber; - if(index < 0 || index > ASC_INTF_NUM){ - printk(KERN_ERR "%s - error interface index %d.\n", __func__, index); - return -ENODEV; - } - switch(msg){ - case ASC_NTF_RX_PREPARE: - //printk("%s:inft%d get cnt=%d", __FUNCTION__, index, atomic_read(&intf_pm_count[index])); - if(!atomic_read(&intf_pm_count[index])){ - if(!usb_autopm_get_interface(intf)){ - atomic_set(&intf_pm_count[index], 1); - } - } - asc_rx_confirm_ready(USB_RX_HD_NAME, !ret); - break; - - case ASC_NTF_RX_POST: - //printk("%s:inft%d put cnt=%d", __FUNCTION__, index, atomic_read(&intf_pm_count[index])); - if(atomic_read(&intf_pm_count[index])){ - usb_autopm_put_interface(intf); - atomic_set(&intf_pm_count[index], 0); - } - break; - default: - printk("%s unknow message %d\n", __FUNCTION__, msg); - } - - return ret; -} -static int cbp_usb_interface_add_user(struct usb_interface * intf) -{ - int index; - struct asc_infor user; - - if(!intf){ - return -EINVAL; - } - - index = (int)intf->cur_altsetting->desc.bInterfaceNumber; - memset(&user, 0, sizeof(user)); - user.notifier = cbp_usb_interface_notifier; - user.data = intf; - snprintf(user.name, ASC_NAME_LEN, "%s%d", USB_RX_USER_NAME, index); - return asc_rx_add_user(USB_RX_HD_NAME, &user); -} - -static void cbp_usb_interface_del_user(struct usb_interface * intf) -{ - int index; - char path[ASC_NAME_LEN]; - - if(!intf){ - return ; - } - - index = (int)intf->cur_altsetting->desc.bInterfaceNumber; - if(atomic_read(&intf_pm_count[index])){ - usb_autopm_put_interface_no_suspend(intf); - atomic_set(&intf_pm_count[index], 0); - } - memset(path, 0, ASC_NAME_LEN); - snprintf(path, ASC_NAME_LEN, "%s%d", ASC_PATH(USB_RX_HD_NAME, USB_RX_USER_NAME), index); - return asc_rx_del_user(path); -} -#endif - -static int debug; -extern struct wake_lock ets_wake_lock; - -static unsigned int dump_mask = 0; -module_param(dump_mask, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(dump_mask, "Set data dump mask for each interface"); - -static void usb_wwan_dump_data(struct usb_interface *interface, - const char *str, const unsigned char *data, int size) { - int i; - int no_chars = 0; - int n = interface->cur_altsetting->desc.bInterfaceNumber; - - if (!(dump_mask & (1 << n))) - return; - - printk(KERN_DEBUG "usb_wwan: dump on interface#%d, %s: len = %d, chars = \"", - n, str, size); - for (i = 0; i < size; ++i) { - char c = data[i]; - if (c > 0x20 && c < 0x7e) { - printk("%c", c); - } else { - printk("."); - no_chars ++; - } - } - printk("\", data = "); - for (i = 0; i < size; ++i) { - printk("%.2x ", data[i]); - if (i > 7) - break; - } - if (size < 8) { - printk("\n"); - return; - } else if (i < size - 8) { - printk("... "); - i = size - 8; - } - for (; i < size; ++i) - printk("%.2x ", data[i]); - printk("\n"); -} - -void usb_wwan_dtr_rts(struct usb_serial_port *port, int on) -{ - struct usb_serial *serial = port->serial; - struct usb_wwan_port_private *portdata; - - struct usb_wwan_intf_private *intfdata; - - dbg("%s", __func__); - - intfdata = port->serial->private; - - if (!intfdata->send_setup) - return; - - portdata = usb_get_serial_port_data(port); - mutex_lock(&serial->disc_mutex); - portdata->rts_state = on; - portdata->dtr_state = on; - if (serial->dev) - intfdata->send_setup(port); - mutex_unlock(&serial->disc_mutex); -} -EXPORT_SYMBOL(usb_wwan_dtr_rts); - -void usb_wwan_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old_termios) -{ - struct usb_wwan_intf_private *intfdata = port->serial->private; - - dbg("%s", __func__); - - /* Doesn't support option setting */ - tty_termios_copy_hw(tty->termios, old_termios); - - if (intfdata->send_setup) - intfdata->send_setup(port); -} -EXPORT_SYMBOL(usb_wwan_set_termios); - -int usb_wwan_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - unsigned int value; - struct usb_wwan_port_private *portdata; - - portdata = usb_get_serial_port_data(port); - - value = ((portdata->rts_state) ? TIOCM_RTS : 0) | - ((portdata->dtr_state) ? TIOCM_DTR : 0) | - ((portdata->cts_state) ? TIOCM_CTS : 0) | - ((portdata->dsr_state) ? TIOCM_DSR : 0) | - ((portdata->dcd_state) ? TIOCM_CAR : 0) | - ((portdata->ri_state) ? TIOCM_RNG : 0); - - return value; -} -EXPORT_SYMBOL(usb_wwan_tiocmget); - -int usb_wwan_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_wwan_port_private *portdata; - struct usb_wwan_intf_private *intfdata; - - portdata = usb_get_serial_port_data(port); - intfdata = port->serial->private; - - if (!intfdata->send_setup) - return -EINVAL; - - /* FIXME: what locks portdata fields ? */ - if (set & TIOCM_RTS) - portdata->rts_state = 1; - if (set & TIOCM_DTR) - portdata->dtr_state = 1; - - if (clear & TIOCM_RTS) - portdata->rts_state = 0; - if (clear & TIOCM_DTR) - portdata->dtr_state = 0; - return intfdata->send_setup(port); -} -EXPORT_SYMBOL(usb_wwan_tiocmset); - -static int get_serial_info(struct usb_serial_port *port, - struct serial_struct __user *retinfo) -{ - struct serial_struct tmp; - - if (!retinfo) - return -EFAULT; - - memset(&tmp, 0, sizeof(tmp)); - tmp.line = port->serial->minor; - tmp.port = port->number; - tmp.baud_base = tty_get_baud_rate(port->port.tty); - tmp.close_delay = port->port.close_delay / 10; - tmp.closing_wait = port->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ? - ASYNC_CLOSING_WAIT_NONE : - port->port.closing_wait / 10; - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - return 0; -} - -static int set_serial_info(struct usb_serial_port *port, - struct serial_struct __user *newinfo) -{ - struct serial_struct new_serial; - unsigned int closing_wait, close_delay; - int retval = 0; - - if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) - return -EFAULT; - - close_delay = new_serial.close_delay * 10; - closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? - ASYNC_CLOSING_WAIT_NONE : new_serial.closing_wait * 10; - - mutex_lock(&port->port.mutex); - - if (!capable(CAP_SYS_ADMIN)) { - if ((close_delay != port->port.close_delay) || - (closing_wait != port->port.closing_wait)) - retval = -EPERM; - else - retval = -EOPNOTSUPP; - } else { - port->port.close_delay = close_delay; - port->port.closing_wait = closing_wait; - } - - mutex_unlock(&port->port.mutex); - return retval; -} - -int usb_wwan_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - - dbg("%s cmd 0x%04x", __func__, cmd); - - switch (cmd) { - case TIOCGSERIAL: - return get_serial_info(port, - (struct serial_struct __user *) arg); - case TIOCSSERIAL: - return set_serial_info(port, - (struct serial_struct __user *) arg); - default: - break; - } - - dbg("%s arg not supported", __func__); - - return -ENOIOCTLCMD; -} -EXPORT_SYMBOL(usb_wwan_ioctl); - -/* Write */ -int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, - const unsigned char *buf, int count) -{ - struct usb_wwan_port_private *portdata; - struct usb_wwan_intf_private *intfdata; - int i; - int left, todo; - struct urb *this_urb = NULL; /* spurious */ - int err; - unsigned long flags; - - portdata = usb_get_serial_port_data(port); - intfdata = port->serial->private; - - dbg("%s: write (%d chars)", __func__, count); - -#ifdef CONFIG_VIATELECOM_SYNC_CBP - asc_tx_auto_ready(USB_TX_HD_NAME, 0); -#endif - - i = 0; - left = count; - for (i = 0; left > 0 && i < portdata->n_out_urb; i++) { - todo = left; - if (todo > portdata->out_buflen) - todo = portdata->out_buflen; - - this_urb = portdata->out_urbs[i]; - if (test_and_set_bit(i, &portdata->out_busy)) { - if (time_before(jiffies, - portdata->tx_start_time[i] + 10 * HZ)) - continue; - usb_unlink_urb(this_urb); - continue; - } - dbg("%s: endpoint %d buf %d", __func__, - usb_pipeendpoint(this_urb->pipe), i); - - err = usb_autopm_get_interface_async(port->serial->interface); - if (err < 0) - break; - - /* send the data */ - memcpy(this_urb->transfer_buffer, buf, todo); - this_urb->transfer_buffer_length = todo; - - spin_lock_irqsave(&intfdata->susp_lock, flags); - if (intfdata->suspended) { - usb_anchor_urb(this_urb, &portdata->delayed); - spin_unlock_irqrestore(&intfdata->susp_lock, flags); - } else { - intfdata->in_flight++; - spin_unlock_irqrestore(&intfdata->susp_lock, flags); - err = usb_submit_urb(this_urb, GFP_ATOMIC); - if (err) { - dbg("usb_submit_urb %p (write bulk) failed " - "(%d)", this_urb, err); - clear_bit(i, &portdata->out_busy); - spin_lock_irqsave(&intfdata->susp_lock, flags); - intfdata->in_flight--; - spin_unlock_irqrestore(&intfdata->susp_lock, - flags); - usb_autopm_put_interface_async(port->serial->interface); - break; - } - } - - portdata->tx_start_time[i] = jiffies; - buf += todo; - left -= todo; - } - - count -= left; - dbg("%s: wrote (did %d)", __func__, count); - return count; -} -EXPORT_SYMBOL(usb_wwan_write); - -static void usb_wwan_indat_callback(struct urb *urb) -{ - int err; - int endpoint; - struct usb_serial_port *port; - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - int status = urb->status; - - dbg("%s: %p", __func__, urb); - - endpoint = usb_pipeendpoint(urb->pipe); - port = urb->context; - - if (status) { - dbg("%s: nonzero status: %d on endpoint %02x.", - __func__, status, endpoint); - } else { - int inception = 0; - struct usb_wwan_port_private *portdata = usb_get_serial_port_data(port); -#ifdef CONFIG_USB_ANDROID_RAWBULK - spin_lock(&portdata->incept_lock); - inception = portdata->inception; - spin_unlock(&portdata->incept_lock); -#endif - if (inception) { -#ifdef CONFIG_USB_ANDROID_RAWBULK - struct usb_interface *interface = port->serial->interface; - int tid = interface->cur_altsetting->desc.bInterfaceNumber; - err = rawbulk_push_upstream_buffer(tid, data, urb->actual_length); - if (err < 0) - printk(KERN_DEBUG "failed to push data to rawbulk(%d) %d\n", tid, err); -#endif - } else { - usb_wwan_dump_data(port->serial->interface, "from device", data, - urb->actual_length); - tty = tty_port_tty_get(&port->port); - if (tty) { - if (urb->actual_length) { - tty_insert_flip_string(tty, data, - urb->actual_length); - tty_flip_buffer_push(tty); - } else - dbg("%s: empty read urb received", __func__); - tty_kref_put(tty); - } - } - - /* Resubmit urb so we continue receiving */ - if (status != -ESHUTDOWN) { - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) { - if (err != -EPERM) { - printk(KERN_ERR "%s: resubmit read urb failed. " - "(%d)", __func__, err); - /* busy also in error unless we are killed */ - usb_mark_last_busy(port->serial->dev); - } - } else { - usb_mark_last_busy(port->serial->dev); - } - } - - } -} - -static void usb_wwan_outdat_callback(struct urb *urb) -{ - struct usb_serial_port *port; - struct usb_wwan_port_private *portdata; - struct usb_wwan_intf_private *intfdata; - int i; - - dbg("%s", __func__); - - port = urb->context; - intfdata = port->serial->private; - usb_wwan_dump_data(port->serial->interface, urb->status < 0? - "failed sent to device": "to device", - urb->transfer_buffer, urb->transfer_buffer_length); - usb_serial_port_softint(port); - usb_autopm_put_interface_async(port->serial->interface); - portdata = usb_get_serial_port_data(port); - spin_lock(&intfdata->susp_lock); - intfdata->in_flight--; - spin_unlock(&intfdata->susp_lock); - - for (i = 0; i < portdata->n_out_urb; ++i) { - if (portdata->out_urbs[i] == urb) { - smp_mb__before_clear_bit(); - clear_bit(i, &portdata->out_busy); - break; - } - } -} - -int usb_wwan_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_wwan_port_private *portdata; - int i; - int data_len = 0; - struct urb *this_urb; - - portdata = usb_get_serial_port_data(port); - - for (i = 0; i < portdata->n_out_urb; i++) { - this_urb = portdata->out_urbs[i]; - if (this_urb && !test_bit(i, &portdata->out_busy)) - data_len += portdata->out_buflen; - } - - dbg("%s: %d", __func__, data_len); - return data_len; -} -EXPORT_SYMBOL(usb_wwan_write_room); - -int usb_wwan_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_wwan_port_private *portdata; - int i; - int data_len = 0; - struct urb *this_urb; - - portdata = usb_get_serial_port_data(port); - - for (i = 0; i < portdata->n_out_urb; i++) { - this_urb = portdata->out_urbs[i]; - /* FIXME: This locking is insufficient as this_urb may - go unused during the test */ - if (this_urb && test_bit(i, &portdata->out_busy)) - data_len += this_urb->transfer_buffer_length; - } - dbg("%s: %d", __func__, data_len); - return data_len; -} -EXPORT_SYMBOL(usb_wwan_chars_in_buffer); - -static int port_to_infnum(struct usb_serial_port *port) -{ - struct usb_interface *interface = port->serial->interface; - int tid = interface->cur_altsetting->desc.bInterfaceNumber; - return tid; -} - -int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - struct usb_wwan_port_private *portdata; - struct usb_wwan_intf_private *intfdata; - struct usb_serial *serial = port->serial; - int i, err; - struct urb *urb; - - portdata = usb_get_serial_port_data(port); - intfdata = serial->private; - - dbg("%s", __func__); - -#if defined(CONFIG_VIATELECOM_SYNC_CBP) - cbp_usb_interface_add_user(serial->interface); -#endif - - /* Start reading from the IN endpoint */ - for (i = 0; i < portdata->n_in_urb; i++) { - urb = portdata->in_urbs[i]; - if (!urb) - continue; - err = usb_submit_urb(urb, GFP_KERNEL); - if (err) { - dbg("%s: submit urb %d failed (%d) %d", - __func__, i, err, urb->transfer_buffer_length); - } - } - - if (intfdata->send_setup) - intfdata->send_setup(port); - - serial->interface->needs_remote_wakeup = 0; - spin_lock_irq(&intfdata->susp_lock); - portdata->opened = 1; - spin_unlock_irq(&intfdata->susp_lock); - /* this balances a get in the generic USB serial code */ - if(port_to_infnum(port) == 1) - { - usb_autopm_get_interface(serial->interface); - wake_lock(&ets_wake_lock); - } - else - usb_autopm_put_interface(serial->interface); - - return 0; -} -EXPORT_SYMBOL(usb_wwan_open); - -void usb_wwan_close(struct usb_serial_port *port) -{ - int i; - struct usb_serial *serial = port->serial; - struct usb_wwan_port_private *portdata; - struct usb_wwan_intf_private *intfdata = port->serial->private; - - dbg("%s", __func__); - portdata = usb_get_serial_port_data(port); - - if (serial->dev) { -#if defined(CONFIG_VIATELECOM_SYNC_CBP) - cbp_usb_interface_del_user(serial->interface); -#endif - /* Stop reading/writing urbs */ - spin_lock_irq(&intfdata->susp_lock); - portdata->opened = 0; - spin_unlock_irq(&intfdata->susp_lock); - - for (i = 0; i < portdata->n_in_urb; i++) - usb_kill_urb(portdata->in_urbs[i]); - for (i = 0; i < portdata->n_out_urb; i++) - usb_kill_urb(portdata->out_urbs[i]); - /* balancing - important as an error cannot be handled*/ - if(port_to_infnum(port) == 1) - { - usb_autopm_put_interface(serial->interface); - wake_unlock(&ets_wake_lock); - } - else - usb_autopm_get_interface_no_resume(serial->interface); - serial->interface->needs_remote_wakeup = 0; - } -} -EXPORT_SYMBOL(usb_wwan_close); - -/* Helper functions used by usb_wwan_setup_urbs */ -static struct urb *usb_wwan_setup_urb(struct usb_serial *serial, int endpoint, - int dir, void *ctx, char *buf, int len, - void (*callback) (struct urb *)) -{ - struct urb *urb; - - if (endpoint == -1) - return NULL; /* endpoint not needed */ - - urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */ - if (urb == NULL) { - dbg("%s: alloc for endpoint %d failed.", __func__, endpoint); - return NULL; - } - - /* Fill URB using supplied data. */ - usb_fill_bulk_urb(urb, serial->dev, - usb_sndbulkpipe(serial->dev, endpoint) | dir, - buf, len, callback, ctx); - - return urb; -} - -/* Setup urbs */ -static void usb_wwan_setup_urbs(struct usb_serial *serial) -{ - int i, j; - struct usb_serial_port *port; - struct usb_wwan_port_private *portdata; - - dbg("%s", __func__); - - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - portdata = usb_get_serial_port_data(port); - - /* Do indat endpoints first */ - for (j = 0; j < portdata->n_in_urb; ++j) { - portdata->in_urbs[j] = usb_wwan_setup_urb(serial, - port-> - bulk_in_endpointAddress, - USB_DIR_IN, - port, - portdata->in_buffer[j], - portdata->in_buflen, - usb_wwan_indat_callback); - } - - /* outdat endpoints */ - for (j = 0; j < portdata->n_out_urb; ++j) { - portdata->out_urbs[j] = usb_wwan_setup_urb(serial, - port-> - bulk_out_endpointAddress, - USB_DIR_OUT, - port, - portdata->out_buffer[j], - portdata->out_buflen, - usb_wwan_outdat_callback); - } - } -} - -static struct _via_cbp_port_init_params { - unsigned int n_in_urb; - unsigned int n_out_urb; - unsigned int in_buflen; - unsigned int out_buflen; -} _cbp_init_params[] = { - { 16, 16, 4096, 4096 }, /* Data Port */ - { 4, 4, 4096, 4096 }, /* ETS */ - { 1, 1, 4096, 4096 }, /* AT Channel */ - { 1, 1, 4096, 4096 }, /* PCV */ - { 1, 1, 4096, 4096 }, /* GPS */ - { }, -}; - -int usb_wwan_startup(struct usb_serial *serial) -{ - int i, j, err; - struct usb_serial_port *port; - struct usb_wwan_port_private *portdata; - u8 *buffer; - - dbg("%s", __func__); - - /* Now setup per port private data */ - for (i = 0; i < serial->num_ports; i++) { - int nr; - port = serial->port[i]; - portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); - if (!portdata) { - dbg("%s: kmalloc for usb_wwan_port_private (%d) failed!.", - __func__, i); - return 1; - } - init_usb_anchor(&portdata->delayed); - - //if (__le16_to_cpu(serial->dev->descriptor.idVendor) == 0x15eb && - // __le16_to_cpu(serial->dev->descriptor.idProduct) == 0x0001) { - nr = serial->interface->cur_altsetting->desc.bInterfaceNumber; - portdata->n_in_urb = min((int)_cbp_init_params[nr].n_in_urb, MAX_IN_URBS); - portdata->n_out_urb = min((int)_cbp_init_params[nr].n_out_urb, MAX_OUT_URBS); - portdata->in_buflen = _cbp_init_params[nr].in_buflen; - portdata->out_buflen = _cbp_init_params[nr].out_buflen; - //} else { - // portdata->n_in_urb = N_IN_URB; - // portdata->n_out_urb = N_OUT_URB; - // portdata->in_buflen = IN_BUFLEN; - // portdata->out_buflen = OUT_BUFLEN; - //} - - for (j = 0; j < portdata->n_in_urb; j++) { - buffer = (u8 *) __get_free_page(GFP_KERNEL); - if (!buffer) - goto bail_out_error; - portdata->in_buffer[j] = buffer; - portdata->in_buflen = PAGE_SIZE; - } - - for (j = 0; j < portdata->n_out_urb; j++) { - buffer = kmalloc(portdata->out_buflen, GFP_KERNEL); - if (!buffer) - goto bail_out_error2; - portdata->out_buffer[j] = buffer; - } - - usb_set_serial_port_data(port, portdata); - - if (!port->interrupt_in_urb) - continue; - err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - if (err) - dbg("%s: submit irq_in urb failed %d", __func__, err); - } - usb_wwan_setup_urbs(serial); - return 0; - -bail_out_error2: - for (j = 0; j < portdata->n_out_urb; j++) - kfree(portdata->out_buffer[j]); -bail_out_error: - for (j = 0; j < portdata->n_in_urb; j++) - if (portdata->in_buffer[j]) - free_page((unsigned long)portdata->in_buffer[j]); - kfree(portdata); - return 1; -} -EXPORT_SYMBOL(usb_wwan_startup); - -static void stop_read_write_urbs(struct usb_serial *serial) -{ - int i, j; - struct usb_serial_port *port; - struct usb_wwan_port_private *portdata; - - /* Stop reading/writing urbs */ - for (i = 0; i < serial->num_ports; ++i) { - port = serial->port[i]; - portdata = usb_get_serial_port_data(port); - for (j = 0; j < portdata->n_in_urb; j++) - usb_kill_urb(portdata->in_urbs[j]); - for (j = 0; j < portdata->n_out_urb; j++) - usb_kill_urb(portdata->out_urbs[j]); - } -} - -void usb_wwan_disconnect(struct usb_serial *serial) -{ - dbg("%s", __func__); - stop_read_write_urbs(serial); -#if defined(CONFIG_VIATELECOM_SYNC_CBP) - cbp_usb_interface_del_user(serial->interface); -#endif -} -EXPORT_SYMBOL(usb_wwan_disconnect); - -void usb_wwan_release(struct usb_serial *serial) -{ - int i, j; - struct usb_serial_port *port; - struct usb_wwan_port_private *portdata; - - dbg("%s", __func__); - - /* Now free them */ - for (i = 0; i < serial->num_ports; ++i) { - port = serial->port[i]; - portdata = usb_get_serial_port_data(port); - - for (j = 0; j < portdata->n_in_urb; j++) { - usb_free_urb(portdata->in_urbs[j]); - free_page((unsigned long) - portdata->in_buffer[j]); - portdata->in_urbs[j] = NULL; - } - for (j = 0; j < portdata->n_out_urb; j++) { - usb_free_urb(portdata->out_urbs[j]); - kfree(portdata->out_buffer[j]); - portdata->out_urbs[j] = NULL; - } - } - - /* Now free per port private data */ - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - kfree(usb_get_serial_port_data(port)); - } -} -EXPORT_SYMBOL(usb_wwan_release); - -#ifdef CONFIG_PM -int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message) -{ - struct usb_wwan_intf_private *intfdata = serial->private; - int b; - - dbg("%s entered", __func__); - - if (PMSG_IS_AUTO(message)) { - spin_lock_irq(&intfdata->susp_lock); - b = intfdata->in_flight; - spin_unlock_irq(&intfdata->susp_lock); - - if (b) - return -EBUSY; - } - - spin_lock_irq(&intfdata->susp_lock); - intfdata->suspended = 1; - spin_unlock_irq(&intfdata->susp_lock); - stop_read_write_urbs(serial); - - return 0; -} -EXPORT_SYMBOL(usb_wwan_suspend); - -static void unbusy_queued_urb(struct urb *urb, struct usb_wwan_port_private *portdata) -{ - int i; - - for (i = 0; i < portdata->n_out_urb; i++) { - if (urb == portdata->out_urbs[i]) { - clear_bit(i, &portdata->out_busy); - break; - } - } -} - -static void play_delayed(struct usb_serial_port *port) -{ - struct usb_wwan_intf_private *data; - struct usb_wwan_port_private *portdata; - struct urb *urb; - int err; - - portdata = usb_get_serial_port_data(port); - data = port->serial->private; - while ((urb = usb_get_from_anchor(&portdata->delayed))) { - err = usb_submit_urb(urb, GFP_ATOMIC); - if (!err) { - data->in_flight++; - } else { - /* we have to throw away the rest */ - do { - unbusy_queued_urb(urb, portdata); - usb_autopm_put_interface_no_suspend(port->serial->interface); - } while ((urb = usb_get_from_anchor(&portdata->delayed))); - break; - } - } -} - -int usb_wwan_resume(struct usb_serial *serial) -{ - int i, j; - struct usb_serial_port *port; - struct usb_wwan_intf_private *intfdata = serial->private; - struct usb_wwan_port_private *portdata; - struct urb *urb; - int err = 0; - - dbg("%s entered", __func__); - /* get the interrupt URBs resubmitted unconditionally */ - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - if (!port->interrupt_in_urb) { - dbg("%s: No interrupt URB for port %d", __func__, i); - continue; - } - err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO); - dbg("Submitted interrupt URB for port %d (result %d)", i, err); - if (err < 0) { - err("%s: Error %d for interrupt URB of port%d", - __func__, err, i); - goto err_out; - } - } - - for (i = 0; i < serial->num_ports; i++) { - /* walk all ports */ - port = serial->port[i]; - portdata = usb_get_serial_port_data(port); - - /* skip closed ports */ - spin_lock_irq(&intfdata->susp_lock); - if (!portdata->opened) { - spin_unlock_irq(&intfdata->susp_lock); - continue; - } - - for (j = 0; j < portdata->n_in_urb; j++) { - urb = portdata->in_urbs[j]; - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err < 0) { - err("%s: Error %d for bulk URB %d", - __func__, err, i); - spin_unlock_irq(&intfdata->susp_lock); - goto err_out; - } - } - play_delayed(port); - spin_unlock_irq(&intfdata->susp_lock); - } - spin_lock_irq(&intfdata->susp_lock); - intfdata->suspended = 0; - spin_unlock_irq(&intfdata->susp_lock); -err_out: - return err; -} -EXPORT_SYMBOL(usb_wwan_resume); -#endif - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug messages"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/visor.c b/ANDROID_3.4.5/drivers/usb/serial/visor.c deleted file mode 100644 index 71d69647..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/visor.c +++ /dev/null @@ -1,716 +0,0 @@ -/* - * USB HandSpring Visor, Palm m50x, and Sony Clie driver - * (supports all of the Palm OS USB devices) - * - * Copyright (C) 1999 - 2004 - * Greg Kroah-Hartman (greg@kroah.com) - * - * 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. - * - * See Documentation/usb/usb-serial.txt for more information on using this - * driver - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "visor.h" - -/* - * Version Information - */ -#define DRIVER_AUTHOR "Greg Kroah-Hartman " -#define DRIVER_DESC "USB HandSpring Visor / Palm OS driver" - -/* function prototypes for a handspring visor */ -static int visor_open(struct tty_struct *tty, struct usb_serial_port *port); -static void visor_close(struct usb_serial_port *port); -static int visor_probe(struct usb_serial *serial, - const struct usb_device_id *id); -static int visor_calc_num_ports(struct usb_serial *serial); -static void visor_read_int_callback(struct urb *urb); -static int clie_3_5_startup(struct usb_serial *serial); -static int treo_attach(struct usb_serial *serial); -static int clie_5_attach(struct usb_serial *serial); -static int palm_os_3_probe(struct usb_serial *serial, - const struct usb_device_id *id); -static int palm_os_4_probe(struct usb_serial *serial, - const struct usb_device_id *id); - -/* Parameters that may be passed into the module. */ -static bool debug; -static __u16 vendor; -static __u16 product; - -static struct usb_device_id id_table [] = { - { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID), - .driver_info = (kernel_ulong_t)&palm_os_3_probe }, - { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO600_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(GSPDA_VENDOR_ID, GSPDA_XPLORE_M68_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_M100_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_TREO_650), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NZ90V_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_TJ25_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(ACER_VENDOR_ID, ACER_S10_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(TAPWAVE_VENDOR_ID, TAPWAVE_ZODIAC_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_7135_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { USB_DEVICE(FOSSIL_VENDOR_ID, FOSSIL_ABACUS_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { }, /* optional parameter entry */ - { } /* Terminating entry */ -}; - -static struct usb_device_id clie_id_5_table [] = { - { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_UX50_ID), - .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { }, /* optional parameter entry */ - { } /* Terminating entry */ -}; - -static struct usb_device_id clie_id_3_5_table [] = { - { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) }, - { } /* Terminating entry */ -}; - -static struct usb_device_id id_table_combined [] = { - { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) }, - { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO_ID) }, - { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO600_ID) }, - { USB_DEVICE(GSPDA_VENDOR_ID, GSPDA_XPLORE_M68_ID) }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID) }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_M100_ID) }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_TREO_650) }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) }, - { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) }, - { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) }, - { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) }, - { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) }, - { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_1_ID) }, - { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NX60_ID) }, - { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_NZ90V_ID) }, - { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_UX50_ID) }, - { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_TJ25_ID) }, - { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID) }, - { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID) }, - { USB_DEVICE(TAPWAVE_VENDOR_ID, TAPWAVE_ZODIAC_ID) }, - { USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID) }, - { USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID) }, - { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_7135_ID) }, - { USB_DEVICE(FOSSIL_VENDOR_ID, FOSSIL_ABACUS_ID) }, - { }, /* optional parameter entry */ - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, id_table_combined); - -static struct usb_driver visor_driver = { - .name = "visor", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; - -/* All of the device info needed for the Handspring Visor, - and Palm 4.0 devices */ -static struct usb_serial_driver handspring_device = { - .driver = { - .owner = THIS_MODULE, - .name = "visor", - }, - .description = "Handspring Visor / Palm OS", - .id_table = id_table, - .num_ports = 2, - .bulk_out_size = 256, - .open = visor_open, - .close = visor_close, - .throttle = usb_serial_generic_throttle, - .unthrottle = usb_serial_generic_unthrottle, - .attach = treo_attach, - .probe = visor_probe, - .calc_num_ports = visor_calc_num_ports, - .read_int_callback = visor_read_int_callback, -}; - -/* All of the device info needed for the Clie UX50, TH55 Palm 5.0 devices */ -static struct usb_serial_driver clie_5_device = { - .driver = { - .owner = THIS_MODULE, - .name = "clie_5", - }, - .description = "Sony Clie 5.0", - .id_table = clie_id_5_table, - .num_ports = 2, - .bulk_out_size = 256, - .open = visor_open, - .close = visor_close, - .throttle = usb_serial_generic_throttle, - .unthrottle = usb_serial_generic_unthrottle, - .attach = clie_5_attach, - .probe = visor_probe, - .calc_num_ports = visor_calc_num_ports, - .read_int_callback = visor_read_int_callback, -}; - -/* device info for the Sony Clie OS version 3.5 */ -static struct usb_serial_driver clie_3_5_device = { - .driver = { - .owner = THIS_MODULE, - .name = "clie_3.5", - }, - .description = "Sony Clie 3.5", - .id_table = clie_id_3_5_table, - .num_ports = 1, - .bulk_out_size = 256, - .open = visor_open, - .close = visor_close, - .throttle = usb_serial_generic_throttle, - .unthrottle = usb_serial_generic_unthrottle, - .attach = clie_3_5_startup, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &handspring_device, &clie_5_device, &clie_3_5_device, NULL -}; - -/****************************************************************************** - * Handspring Visor specific driver functions - ******************************************************************************/ -static int visor_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - int result = 0; - - dbg("%s - port %d", __func__, port->number); - - if (!port->read_urb) { - /* this is needed for some brain dead Sony devices */ - dev_err(&port->dev, "Device lied about number of ports, please use a lower one.\n"); - return -ENODEV; - } - - /* Start reading from the device */ - result = usb_serial_generic_open(tty, port); - if (result) - goto exit; - - if (port->interrupt_in_urb) { - dbg("%s - adding interrupt input for treo", __func__); - result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); - if (result) - dev_err(&port->dev, - "%s - failed submitting interrupt urb, error %d\n", - __func__, result); - } -exit: - return result; -} - - -static void visor_close(struct usb_serial_port *port) -{ - unsigned char *transfer_buffer; - - dbg("%s - port %d", __func__, port->number); - - /* shutdown our urbs */ - usb_serial_generic_close(port); - usb_kill_urb(port->interrupt_in_urb); - - mutex_lock(&port->serial->disc_mutex); - if (!port->serial->disconnected) { - /* Try to send shutdown message, unless the device is gone */ - transfer_buffer = kmalloc(0x12, GFP_KERNEL); - if (transfer_buffer) { - usb_control_msg(port->serial->dev, - usb_rcvctrlpipe(port->serial->dev, 0), - VISOR_CLOSE_NOTIFICATION, 0xc2, - 0x0000, 0x0000, - transfer_buffer, 0x12, 300); - kfree(transfer_buffer); - } - } - mutex_unlock(&port->serial->disc_mutex); -} - -static void visor_read_int_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - int status = urb->status; - int result; - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); - return; - default: - dbg("%s - nonzero urb status received: %d", - __func__, status); - goto exit; - } - - /* - * This information is still unknown what it can be used for. - * If anyone has an idea, please let the author know... - * - * Rumor has it this endpoint is used to notify when data - * is ready to be read from the bulk ones. - */ - usb_serial_debug_data(debug, &port->dev, __func__, - urb->actual_length, urb->transfer_buffer); - -exit: - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) - dev_err(&urb->dev->dev, - "%s - Error %d submitting interrupt urb\n", - __func__, result); -} - -static int palm_os_3_probe(struct usb_serial *serial, - const struct usb_device_id *id) -{ - struct device *dev = &serial->dev->dev; - struct visor_connection_info *connection_info; - unsigned char *transfer_buffer; - char *string; - int retval = 0; - int i; - int num_ports = 0; - - dbg("%s", __func__); - - transfer_buffer = kmalloc(sizeof(*connection_info), GFP_KERNEL); - if (!transfer_buffer) { - dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __func__, - sizeof(*connection_info)); - return -ENOMEM; - } - - /* send a get connection info request */ - retval = usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), - VISOR_GET_CONNECTION_INFORMATION, - 0xc2, 0x0000, 0x0000, transfer_buffer, - sizeof(*connection_info), 300); - if (retval < 0) { - dev_err(dev, "%s - error %d getting connection information\n", - __func__, retval); - goto exit; - } - - if (retval == sizeof(*connection_info)) { - connection_info = (struct visor_connection_info *) - transfer_buffer; - - num_ports = le16_to_cpu(connection_info->num_ports); - for (i = 0; i < num_ports; ++i) { - switch ( - connection_info->connections[i].port_function_id) { - case VISOR_FUNCTION_GENERIC: - string = "Generic"; - break; - case VISOR_FUNCTION_DEBUGGER: - string = "Debugger"; - break; - case VISOR_FUNCTION_HOTSYNC: - string = "HotSync"; - break; - case VISOR_FUNCTION_CONSOLE: - string = "Console"; - break; - case VISOR_FUNCTION_REMOTE_FILE_SYS: - string = "Remote File System"; - break; - default: - string = "unknown"; - break; - } - dev_info(dev, "%s: port %d, is for %s use\n", - serial->type->description, - connection_info->connections[i].port, string); - } - } - /* - * Handle devices that report invalid stuff here. - */ - if (num_ports == 0 || num_ports > 2) { - dev_warn(dev, "%s: No valid connect info available\n", - serial->type->description); - num_ports = 2; - } - - dev_info(dev, "%s: Number of ports: %d\n", serial->type->description, - num_ports); - - /* - * save off our num_ports info so that we can use it in the - * calc_num_ports callback - */ - usb_set_serial_data(serial, (void *)(long)num_ports); - - /* ask for the number of bytes available, but ignore the - response as it is broken */ - retval = usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), - VISOR_REQUEST_BYTES_AVAILABLE, - 0xc2, 0x0000, 0x0005, transfer_buffer, - 0x02, 300); - if (retval < 0) - dev_err(dev, "%s - error %d getting bytes available request\n", - __func__, retval); - retval = 0; - -exit: - kfree(transfer_buffer); - - return retval; -} - -static int palm_os_4_probe(struct usb_serial *serial, - const struct usb_device_id *id) -{ - struct device *dev = &serial->dev->dev; - struct palm_ext_connection_info *connection_info; - unsigned char *transfer_buffer; - int retval; - - dbg("%s", __func__); - - transfer_buffer = kmalloc(sizeof(*connection_info), GFP_KERNEL); - if (!transfer_buffer) { - dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __func__, - sizeof(*connection_info)); - return -ENOMEM; - } - - retval = usb_control_msg(serial->dev, - usb_rcvctrlpipe(serial->dev, 0), - PALM_GET_EXT_CONNECTION_INFORMATION, - 0xc2, 0x0000, 0x0000, transfer_buffer, - sizeof(*connection_info), 300); - if (retval < 0) - dev_err(dev, "%s - error %d getting connection info\n", - __func__, retval); - else - usb_serial_debug_data(debug, &serial->dev->dev, __func__, - retval, transfer_buffer); - - kfree(transfer_buffer); - return 0; -} - - -static int visor_probe(struct usb_serial *serial, - const struct usb_device_id *id) -{ - int retval = 0; - int (*startup)(struct usb_serial *serial, - const struct usb_device_id *id); - - dbg("%s", __func__); - - /* - * some Samsung Android phones in modem mode have the same ID - * as SPH-I500, but they are ACM devices, so dont bind to them - */ - if (id->idVendor == SAMSUNG_VENDOR_ID && - id->idProduct == SAMSUNG_SPH_I500_ID && - serial->dev->descriptor.bDeviceClass == USB_CLASS_COMM && - serial->dev->descriptor.bDeviceSubClass == - USB_CDC_SUBCLASS_ACM) - return -ENODEV; - - if (serial->dev->actconfig->desc.bConfigurationValue != 1) { - dev_err(&serial->dev->dev, "active config #%d != 1 ??\n", - serial->dev->actconfig->desc.bConfigurationValue); - return -ENODEV; - } - - if (id->driver_info) { - startup = (void *)id->driver_info; - retval = startup(serial, id); - } - - return retval; -} - -static int visor_calc_num_ports(struct usb_serial *serial) -{ - int num_ports = (int)(long)(usb_get_serial_data(serial)); - - if (num_ports) - usb_set_serial_data(serial, NULL); - - return num_ports; -} - -static int clie_3_5_startup(struct usb_serial *serial) -{ - struct device *dev = &serial->dev->dev; - int result; - u8 *data; - - dbg("%s", __func__); - - data = kmalloc(1, GFP_KERNEL); - if (!data) - return -ENOMEM; - - /* - * Note that PEG-300 series devices expect the following two calls. - */ - - /* get the config number */ - result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - USB_REQ_GET_CONFIGURATION, USB_DIR_IN, - 0, 0, data, 1, 3000); - if (result < 0) { - dev_err(dev, "%s: get config number failed: %d\n", - __func__, result); - goto out; - } - if (result != 1) { - dev_err(dev, "%s: get config number bad return length: %d\n", - __func__, result); - result = -EIO; - goto out; - } - - /* get the interface number */ - result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - USB_REQ_GET_INTERFACE, - USB_DIR_IN | USB_RECIP_INTERFACE, - 0, 0, data, 1, 3000); - if (result < 0) { - dev_err(dev, "%s: get interface number failed: %d\n", - __func__, result); - goto out; - } - if (result != 1) { - dev_err(dev, - "%s: get interface number bad return length: %d\n", - __func__, result); - result = -EIO; - goto out; - } - - result = 0; -out: - kfree(data); - - return result; -} - -static int treo_attach(struct usb_serial *serial) -{ - struct usb_serial_port *swap_port; - - /* Only do this endpoint hack for the Handspring devices with - * interrupt in endpoints, which for now are the Treo devices. */ - if (!((le16_to_cpu(serial->dev->descriptor.idVendor) - == HANDSPRING_VENDOR_ID) || - (le16_to_cpu(serial->dev->descriptor.idVendor) - == KYOCERA_VENDOR_ID)) || - (serial->num_interrupt_in == 0)) - return 0; - - dbg("%s", __func__); - - /* - * It appears that Treos and Kyoceras want to use the - * 1st bulk in endpoint to communicate with the 2nd bulk out endpoint, - * so let's swap the 1st and 2nd bulk in and interrupt endpoints. - * Note that swapping the bulk out endpoints would break lots of - * apps that want to communicate on the second port. - */ -#define COPY_PORT(dest, src) \ - do { \ - dest->read_urb = src->read_urb; \ - dest->bulk_in_endpointAddress = src->bulk_in_endpointAddress;\ - dest->bulk_in_buffer = src->bulk_in_buffer; \ - dest->interrupt_in_urb = src->interrupt_in_urb; \ - dest->interrupt_in_endpointAddress = \ - src->interrupt_in_endpointAddress;\ - dest->interrupt_in_buffer = src->interrupt_in_buffer; \ - } while (0); - - swap_port = kmalloc(sizeof(*swap_port), GFP_KERNEL); - if (!swap_port) - return -ENOMEM; - COPY_PORT(swap_port, serial->port[0]); - COPY_PORT(serial->port[0], serial->port[1]); - COPY_PORT(serial->port[1], swap_port); - kfree(swap_port); - - return 0; -} - -static int clie_5_attach(struct usb_serial *serial) -{ - struct usb_serial_port *port; - unsigned int pipe; - int j; - - dbg("%s", __func__); - - /* TH55 registers 2 ports. - Communication in from the UX50/TH55 uses bulk_in_endpointAddress - from port 0. Communication out to the UX50/TH55 uses - bulk_out_endpointAddress from port 1 - - Lets do a quick and dirty mapping - */ - - /* some sanity check */ - if (serial->num_ports < 2) - return -1; - - /* port 0 now uses the modified endpoint Address */ - port = serial->port[0]; - port->bulk_out_endpointAddress = - serial->port[1]->bulk_out_endpointAddress; - - pipe = usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress); - for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) - port->write_urbs[j]->pipe = pipe; - - return 0; -} - -static int __init visor_init(void) -{ - int i, retval; - /* Only if parameters were passed to us */ - if (vendor > 0 && product > 0) { - struct usb_device_id usb_dev_temp[] = { - { - USB_DEVICE(vendor, product), - .driver_info = - (kernel_ulong_t) &palm_os_4_probe - } - }; - - /* Find the last entry in id_table */ - for (i = 0;; i++) { - if (id_table[i].idVendor == 0) { - id_table[i] = usb_dev_temp[0]; - break; - } - } - /* Find the last entry in id_table_combined */ - for (i = 0;; i++) { - if (id_table_combined[i].idVendor == 0) { - id_table_combined[i] = usb_dev_temp[0]; - break; - } - } - printk(KERN_INFO KBUILD_MODNAME - ": Untested USB device specified at time of module insertion\n"); - printk(KERN_INFO KBUILD_MODNAME - ": Warning: This is not guaranteed to work\n"); - printk(KERN_INFO KBUILD_MODNAME - ": Using a newer kernel is preferred to this method\n"); - printk(KERN_INFO KBUILD_MODNAME - ": Adding Palm OS protocol 4.x support for unknown device: 0x%x/0x%x\n", - vendor, product); - } - - retval = usb_serial_register_drivers(&visor_driver, serial_drivers); - if (retval == 0) - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n"); - return retval; -} - - -static void __exit visor_exit (void) -{ - usb_serial_deregister_drivers(&visor_driver, serial_drivers); -} - - -module_init(visor_init); -module_exit(visor_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - -module_param(vendor, ushort, 0); -MODULE_PARM_DESC(vendor, "User specified vendor ID"); -module_param(product, ushort, 0); -MODULE_PARM_DESC(product, "User specified product ID"); - diff --git a/ANDROID_3.4.5/drivers/usb/serial/visor.h b/ANDROID_3.4.5/drivers/usb/serial/visor.h deleted file mode 100644 index 88db4d06..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/visor.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * USB HandSpring Visor driver - * - * Copyright (C) 1999 - 2003 - * Greg Kroah-Hartman (greg@kroah.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * See Documentation/usb/usb-serial.txt for more information on using this - * driver. - * - */ - -#ifndef __LINUX_USB_SERIAL_VISOR_H -#define __LINUX_USB_SERIAL_VISOR_H - - -#define HANDSPRING_VENDOR_ID 0x082d -#define HANDSPRING_VISOR_ID 0x0100 -#define HANDSPRING_TREO_ID 0x0200 -#define HANDSPRING_TREO600_ID 0x0300 - -#define PALM_VENDOR_ID 0x0830 -#define PALM_M500_ID 0x0001 -#define PALM_M505_ID 0x0002 -#define PALM_M515_ID 0x0003 -#define PALM_I705_ID 0x0020 -#define PALM_M125_ID 0x0040 -#define PALM_M130_ID 0x0050 -#define PALM_TUNGSTEN_T_ID 0x0060 -#define PALM_TREO_650 0x0061 -#define PALM_TUNGSTEN_Z_ID 0x0031 -#define PALM_ZIRE_ID 0x0070 -#define PALM_M100_ID 0x0080 - -#define GSPDA_VENDOR_ID 0x115e -#define GSPDA_XPLORE_M68_ID 0xf100 - -#define SONY_VENDOR_ID 0x054C -#define SONY_CLIE_3_5_ID 0x0038 -#define SONY_CLIE_4_0_ID 0x0066 -#define SONY_CLIE_S360_ID 0x0095 -#define SONY_CLIE_4_1_ID 0x009A -#define SONY_CLIE_NX60_ID 0x00DA -#define SONY_CLIE_NZ90V_ID 0x00E9 -#define SONY_CLIE_UX50_ID 0x0144 -#define SONY_CLIE_TJ25_ID 0x0169 - -#define ACER_VENDOR_ID 0x0502 -#define ACER_S10_ID 0x0001 - -#define SAMSUNG_VENDOR_ID 0x04E8 -#define SAMSUNG_SCH_I330_ID 0x8001 -#define SAMSUNG_SPH_I500_ID 0x6601 - -#define TAPWAVE_VENDOR_ID 0x12EF -#define TAPWAVE_ZODIAC_ID 0x0100 - -#define GARMIN_VENDOR_ID 0x091E -#define GARMIN_IQUE_3600_ID 0x0004 - -#define ACEECA_VENDOR_ID 0x4766 -#define ACEECA_MEZ1000_ID 0x0001 - -#define KYOCERA_VENDOR_ID 0x0C88 -#define KYOCERA_7135_ID 0x0021 - -#define FOSSIL_VENDOR_ID 0x0E67 -#define FOSSIL_ABACUS_ID 0x0002 - -/**************************************************************************** - * Handspring Visor Vendor specific request codes (bRequest values) - * A big thank you to Handspring for providing the following information. - * If anyone wants the original file where these values and structures came - * from, send email to . - ****************************************************************************/ - -/**************************************************************************** - * VISOR_REQUEST_BYTES_AVAILABLE asks the visor for the number of bytes that - * are available to be transferred to the host for the specified endpoint. - * Currently this is not used, and always returns 0x0001 - ****************************************************************************/ -#define VISOR_REQUEST_BYTES_AVAILABLE 0x01 - -/**************************************************************************** - * VISOR_CLOSE_NOTIFICATION is set to the device to notify it that the host - * is now closing the pipe. An empty packet is sent in response. - ****************************************************************************/ -#define VISOR_CLOSE_NOTIFICATION 0x02 - -/**************************************************************************** - * VISOR_GET_CONNECTION_INFORMATION is sent by the host during enumeration to - * get the endpoints used by the connection. - ****************************************************************************/ -#define VISOR_GET_CONNECTION_INFORMATION 0x03 - - -/**************************************************************************** - * VISOR_GET_CONNECTION_INFORMATION returns data in the following format - ****************************************************************************/ -struct visor_connection_info { - __le16 num_ports; - struct { - __u8 port_function_id; - __u8 port; - } connections[2]; -}; - - -/* struct visor_connection_info.connection[x].port defines: */ -#define VISOR_ENDPOINT_1 0x01 -#define VISOR_ENDPOINT_2 0x02 - -/* struct visor_connection_info.connection[x].port_function_id defines: */ -#define VISOR_FUNCTION_GENERIC 0x00 -#define VISOR_FUNCTION_DEBUGGER 0x01 -#define VISOR_FUNCTION_HOTSYNC 0x02 -#define VISOR_FUNCTION_CONSOLE 0x03 -#define VISOR_FUNCTION_REMOTE_FILE_SYS 0x04 - - -/**************************************************************************** - * PALM_GET_SOME_UNKNOWN_INFORMATION is sent by the host during enumeration to - * get some information from the M series devices, that is currently unknown. - ****************************************************************************/ -#define PALM_GET_EXT_CONNECTION_INFORMATION 0x04 - -/** - * struct palm_ext_connection_info - return data from a PALM_GET_EXT_CONNECTION_INFORMATION request - * @num_ports: maximum number of functions/connections in use - * @endpoint_numbers_different: will be 1 if in and out endpoints numbers are - * different, otherwise it is 0. If value is 1, then - * connections.end_point_info is non-zero. If value is 0, then - * connections.port contains the endpoint number, which is the same for in - * and out. - * @port_function_id: contains the creator id of the applicaton that opened - * this connection. - * @port: contains the in/out endpoint number. Is 0 if in and out endpoint - * numbers are different. - * @end_point_info: high nubbe is in endpoint and low nibble will indicate out - * endpoint. Is 0 if in and out endpoints are the same. - * - * The maximum number of connections currently supported is 2 - */ -struct palm_ext_connection_info { - __u8 num_ports; - __u8 endpoint_numbers_different; - __le16 reserved1; - struct { - __u32 port_function_id; - __u8 port; - __u8 end_point_info; - __le16 reserved; - } connections[2]; -}; - -#endif - diff --git a/ANDROID_3.4.5/drivers/usb/serial/vivopay-serial.c b/ANDROID_3.4.5/drivers/usb/serial/vivopay-serial.c deleted file mode 100644 index 078f338b..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/vivopay-serial.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2001-2005 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (C) 2009 Outpost Embedded, LLC - */ - -#include -#include -#include -#include -#include -#include - - -#define DRIVER_VERSION "v1.0" -#define DRIVER_DESC "ViVOpay USB Serial Driver" - -#define VIVOPAY_VENDOR_ID 0x1d5f - - -static struct usb_device_id id_table [] = { - /* ViVOpay 8800 */ - { USB_DEVICE(VIVOPAY_VENDOR_ID, 0x1004) }, - { }, -}; - -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver vivopay_serial_driver = { - .name = "vivopay-serial", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - -static struct usb_serial_driver vivopay_serial_device = { - .driver = { - .owner = THIS_MODULE, - .name = "vivopay-serial", - }, - .id_table = id_table, - .num_ports = 1, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &vivopay_serial_device, NULL -}; - -module_usb_serial_driver(vivopay_serial_driver, serial_drivers); - -MODULE_AUTHOR("Forest Bond "); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/whiteheat.c b/ANDROID_3.4.5/drivers/usb/serial/whiteheat.c deleted file mode 100644 index 407e23c8..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/whiteheat.c +++ /dev/null @@ -1,1470 +0,0 @@ -/* - * USB ConnectTech WhiteHEAT driver - * - * Copyright (C) 2002 - * Connect Tech Inc. - * - * Copyright (C) 1999 - 2001 - * Greg Kroah-Hartman (greg@kroah.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * See Documentation/usb/usb-serial.txt for more information on using this - * driver - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "whiteheat.h" /* WhiteHEAT specific commands */ - -static bool debug; - -#ifndef CMSPAR -#define CMSPAR 0 -#endif - -/* - * Version Information - */ -#define DRIVER_VERSION "v2.0" -#define DRIVER_AUTHOR "Greg Kroah-Hartman , Stuart MacDonald " -#define DRIVER_DESC "USB ConnectTech WhiteHEAT driver" - -#define CONNECT_TECH_VENDOR_ID 0x0710 -#define CONNECT_TECH_FAKE_WHITE_HEAT_ID 0x0001 -#define CONNECT_TECH_WHITE_HEAT_ID 0x8001 - -/* - ID tables for whiteheat are unusual, because we want to different - things for different versions of the device. Eventually, this - will be doable from a single table. But, for now, we define two - separate ID tables, and then a third table that combines them - just for the purpose of exporting the autoloading information. -*/ -static const struct usb_device_id id_table_std[] = { - { USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_WHITE_HEAT_ID) }, - { } /* Terminating entry */ -}; - -static const struct usb_device_id id_table_prerenumeration[] = { - { USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_FAKE_WHITE_HEAT_ID) }, - { } /* Terminating entry */ -}; - -static const struct usb_device_id id_table_combined[] = { - { USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_WHITE_HEAT_ID) }, - { USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_FAKE_WHITE_HEAT_ID) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, id_table_combined); - -static struct usb_driver whiteheat_driver = { - .name = "whiteheat", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; - -/* function prototypes for the Connect Tech WhiteHEAT prerenumeration device */ -static int whiteheat_firmware_download(struct usb_serial *serial, - const struct usb_device_id *id); -static int whiteheat_firmware_attach(struct usb_serial *serial); - -/* function prototypes for the Connect Tech WhiteHEAT serial converter */ -static int whiteheat_attach(struct usb_serial *serial); -static void whiteheat_release(struct usb_serial *serial); -static int whiteheat_open(struct tty_struct *tty, - struct usb_serial_port *port); -static void whiteheat_close(struct usb_serial_port *port); -static int whiteheat_write(struct tty_struct *tty, - struct usb_serial_port *port, - const unsigned char *buf, int count); -static int whiteheat_write_room(struct tty_struct *tty); -static int whiteheat_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); -static void whiteheat_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old); -static int whiteheat_tiocmget(struct tty_struct *tty); -static int whiteheat_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear); -static void whiteheat_break_ctl(struct tty_struct *tty, int break_state); -static int whiteheat_chars_in_buffer(struct tty_struct *tty); -static void whiteheat_throttle(struct tty_struct *tty); -static void whiteheat_unthrottle(struct tty_struct *tty); -static void whiteheat_read_callback(struct urb *urb); -static void whiteheat_write_callback(struct urb *urb); - -static struct usb_serial_driver whiteheat_fake_device = { - .driver = { - .owner = THIS_MODULE, - .name = "whiteheatnofirm", - }, - .description = "Connect Tech - WhiteHEAT - (prerenumeration)", - .id_table = id_table_prerenumeration, - .num_ports = 1, - .probe = whiteheat_firmware_download, - .attach = whiteheat_firmware_attach, -}; - -static struct usb_serial_driver whiteheat_device = { - .driver = { - .owner = THIS_MODULE, - .name = "whiteheat", - }, - .description = "Connect Tech - WhiteHEAT", - .id_table = id_table_std, - .num_ports = 4, - .attach = whiteheat_attach, - .release = whiteheat_release, - .open = whiteheat_open, - .close = whiteheat_close, - .write = whiteheat_write, - .write_room = whiteheat_write_room, - .ioctl = whiteheat_ioctl, - .set_termios = whiteheat_set_termios, - .break_ctl = whiteheat_break_ctl, - .tiocmget = whiteheat_tiocmget, - .tiocmset = whiteheat_tiocmset, - .chars_in_buffer = whiteheat_chars_in_buffer, - .throttle = whiteheat_throttle, - .unthrottle = whiteheat_unthrottle, - .read_bulk_callback = whiteheat_read_callback, - .write_bulk_callback = whiteheat_write_callback, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &whiteheat_fake_device, &whiteheat_device, NULL -}; - -struct whiteheat_command_private { - struct mutex mutex; - __u8 port_running; - __u8 command_finished; - wait_queue_head_t wait_command; /* for handling sleeping whilst - waiting for a command to - finish */ - __u8 result_buffer[64]; -}; - - -#define THROTTLED 0x01 -#define ACTUALLY_THROTTLED 0x02 - -static int urb_pool_size = 8; - -struct whiteheat_urb_wrap { - struct list_head list; - struct urb *urb; -}; - -struct whiteheat_private { - spinlock_t lock; - __u8 flags; - __u8 mcr; /* FIXME: no locking on mcr */ - struct list_head rx_urbs_free; - struct list_head rx_urbs_submitted; - struct list_head rx_urb_q; - struct work_struct rx_work; - struct usb_serial_port *port; - struct list_head tx_urbs_free; - struct list_head tx_urbs_submitted; - struct mutex deathwarrant; -}; - - -/* local function prototypes */ -static int start_command_port(struct usb_serial *serial); -static void stop_command_port(struct usb_serial *serial); -static void command_port_write_callback(struct urb *urb); -static void command_port_read_callback(struct urb *urb); - -static int start_port_read(struct usb_serial_port *port); -static struct whiteheat_urb_wrap *urb_to_wrap(struct urb *urb, - struct list_head *head); -static struct list_head *list_first(struct list_head *head); -static void rx_data_softint(struct work_struct *work); - -static int firm_send_command(struct usb_serial_port *port, __u8 command, - __u8 *data, __u8 datasize); -static int firm_open(struct usb_serial_port *port); -static int firm_close(struct usb_serial_port *port); -static void firm_setup_port(struct tty_struct *tty); -static int firm_set_rts(struct usb_serial_port *port, __u8 onoff); -static int firm_set_dtr(struct usb_serial_port *port, __u8 onoff); -static int firm_set_break(struct usb_serial_port *port, __u8 onoff); -static int firm_purge(struct usb_serial_port *port, __u8 rxtx); -static int firm_get_dtr_rts(struct usb_serial_port *port); -static int firm_report_tx_done(struct usb_serial_port *port); - - -#define COMMAND_PORT 4 -#define COMMAND_TIMEOUT (2*HZ) /* 2 second timeout for a command */ -#define COMMAND_TIMEOUT_MS 2000 -#define CLOSING_DELAY (30 * HZ) - - -/***************************************************************************** - * Connect Tech's White Heat prerenumeration driver functions - *****************************************************************************/ - -/* steps to download the firmware to the WhiteHEAT device: - - hold the reset (by writing to the reset bit of the CPUCS register) - - download the VEND_AX.HEX file to the chip using VENDOR_REQUEST-ANCHOR_LOAD - - release the reset (by writing to the CPUCS register) - - download the WH.HEX file for all addresses greater than 0x1b3f using - VENDOR_REQUEST-ANCHOR_EXTERNAL_RAM_LOAD - - hold the reset - - download the WH.HEX file for all addresses less than 0x1b40 using - VENDOR_REQUEST_ANCHOR_LOAD - - release the reset - - device renumerated itself and comes up as new device id with all - firmware download completed. -*/ -static int whiteheat_firmware_download(struct usb_serial *serial, - const struct usb_device_id *id) -{ - int response, ret = -ENOENT; - const struct firmware *loader_fw = NULL, *firmware_fw = NULL; - const struct ihex_binrec *record; - - dbg("%s", __func__); - - if (request_ihex_firmware(&firmware_fw, "whiteheat.fw", - &serial->dev->dev)) { - dev_err(&serial->dev->dev, - "%s - request \"whiteheat.fw\" failed\n", __func__); - goto out; - } - if (request_ihex_firmware(&loader_fw, "whiteheat_loader.fw", - &serial->dev->dev)) { - dev_err(&serial->dev->dev, - "%s - request \"whiteheat_loader.fw\" failed\n", - __func__); - goto out; - } - ret = 0; - response = ezusb_set_reset (serial, 1); - - record = (const struct ihex_binrec *)loader_fw->data; - while (record) { - response = ezusb_writememory (serial, be32_to_cpu(record->addr), - (unsigned char *)record->data, - be16_to_cpu(record->len), 0xa0); - if (response < 0) { - dev_err(&serial->dev->dev, "%s - ezusb_writememory " - "failed for loader (%d %04X %p %d)\n", - __func__, response, be32_to_cpu(record->addr), - record->data, be16_to_cpu(record->len)); - break; - } - record = ihex_next_binrec(record); - } - - response = ezusb_set_reset(serial, 0); - - record = (const struct ihex_binrec *)firmware_fw->data; - while (record && be32_to_cpu(record->addr) < 0x1b40) - record = ihex_next_binrec(record); - while (record) { - response = ezusb_writememory (serial, be32_to_cpu(record->addr), - (unsigned char *)record->data, - be16_to_cpu(record->len), 0xa3); - if (response < 0) { - dev_err(&serial->dev->dev, "%s - ezusb_writememory " - "failed for first firmware step " - "(%d %04X %p %d)\n", __func__, response, - be32_to_cpu(record->addr), record->data, - be16_to_cpu(record->len)); - break; - } - ++record; - } - - response = ezusb_set_reset(serial, 1); - - record = (const struct ihex_binrec *)firmware_fw->data; - while (record && be32_to_cpu(record->addr) < 0x1b40) { - response = ezusb_writememory (serial, be32_to_cpu(record->addr), - (unsigned char *)record->data, - be16_to_cpu(record->len), 0xa0); - if (response < 0) { - dev_err(&serial->dev->dev, "%s - ezusb_writememory " - "failed for second firmware step " - "(%d %04X %p %d)\n", __func__, response, - be32_to_cpu(record->addr), record->data, - be16_to_cpu(record->len)); - break; - } - ++record; - } - ret = 0; - response = ezusb_set_reset (serial, 0); - out: - release_firmware(loader_fw); - release_firmware(firmware_fw); - return ret; -} - - -static int whiteheat_firmware_attach(struct usb_serial *serial) -{ - /* We want this device to fail to have a driver assigned to it */ - return 1; -} - - -/***************************************************************************** - * Connect Tech's White Heat serial driver functions - *****************************************************************************/ -static int whiteheat_attach(struct usb_serial *serial) -{ - struct usb_serial_port *command_port; - struct whiteheat_command_private *command_info; - struct usb_serial_port *port; - struct whiteheat_private *info; - struct whiteheat_hw_info *hw_info; - int pipe; - int ret; - int alen; - __u8 *command; - __u8 *result; - int i; - int j; - struct urb *urb; - int buf_size; - struct whiteheat_urb_wrap *wrap; - struct list_head *tmp; - - command_port = serial->port[COMMAND_PORT]; - - pipe = usb_sndbulkpipe(serial->dev, - command_port->bulk_out_endpointAddress); - command = kmalloc(2, GFP_KERNEL); - if (!command) - goto no_command_buffer; - command[0] = WHITEHEAT_GET_HW_INFO; - command[1] = 0; - - result = kmalloc(sizeof(*hw_info) + 1, GFP_KERNEL); - if (!result) - goto no_result_buffer; - /* - * When the module is reloaded the firmware is still there and - * the endpoints are still in the usb core unchanged. This is the - * unlinking bug in disguise. Same for the call below. - */ - usb_clear_halt(serial->dev, pipe); - ret = usb_bulk_msg(serial->dev, pipe, command, 2, - &alen, COMMAND_TIMEOUT_MS); - if (ret) { - dev_err(&serial->dev->dev, "%s: Couldn't send command [%d]\n", - serial->type->description, ret); - goto no_firmware; - } else if (alen != 2) { - dev_err(&serial->dev->dev, "%s: Send command incomplete [%d]\n", - serial->type->description, alen); - goto no_firmware; - } - - pipe = usb_rcvbulkpipe(serial->dev, - command_port->bulk_in_endpointAddress); - /* See the comment on the usb_clear_halt() above */ - usb_clear_halt(serial->dev, pipe); - ret = usb_bulk_msg(serial->dev, pipe, result, - sizeof(*hw_info) + 1, &alen, COMMAND_TIMEOUT_MS); - if (ret) { - dev_err(&serial->dev->dev, "%s: Couldn't get results [%d]\n", - serial->type->description, ret); - goto no_firmware; - } else if (alen != sizeof(*hw_info) + 1) { - dev_err(&serial->dev->dev, "%s: Get results incomplete [%d]\n", - serial->type->description, alen); - goto no_firmware; - } else if (result[0] != command[0]) { - dev_err(&serial->dev->dev, "%s: Command failed [%d]\n", - serial->type->description, result[0]); - goto no_firmware; - } - - hw_info = (struct whiteheat_hw_info *)&result[1]; - - dev_info(&serial->dev->dev, "%s: Driver %s: Firmware v%d.%02d\n", - serial->type->description, DRIVER_VERSION, - hw_info->sw_major_rev, hw_info->sw_minor_rev); - - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - - info = kmalloc(sizeof(struct whiteheat_private), GFP_KERNEL); - if (info == NULL) { - dev_err(&port->dev, - "%s: Out of memory for port structures\n", - serial->type->description); - goto no_private; - } - - spin_lock_init(&info->lock); - mutex_init(&info->deathwarrant); - info->flags = 0; - info->mcr = 0; - INIT_WORK(&info->rx_work, rx_data_softint); - info->port = port; - - INIT_LIST_HEAD(&info->rx_urbs_free); - INIT_LIST_HEAD(&info->rx_urbs_submitted); - INIT_LIST_HEAD(&info->rx_urb_q); - INIT_LIST_HEAD(&info->tx_urbs_free); - INIT_LIST_HEAD(&info->tx_urbs_submitted); - - for (j = 0; j < urb_pool_size; j++) { - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - dev_err(&port->dev, "No free urbs available\n"); - goto no_rx_urb; - } - buf_size = port->read_urb->transfer_buffer_length; - urb->transfer_buffer = kmalloc(buf_size, GFP_KERNEL); - if (!urb->transfer_buffer) { - dev_err(&port->dev, - "Couldn't allocate urb buffer\n"); - goto no_rx_buf; - } - wrap = kmalloc(sizeof(*wrap), GFP_KERNEL); - if (!wrap) { - dev_err(&port->dev, - "Couldn't allocate urb wrapper\n"); - goto no_rx_wrap; - } - usb_fill_bulk_urb(urb, serial->dev, - usb_rcvbulkpipe(serial->dev, - port->bulk_in_endpointAddress), - urb->transfer_buffer, buf_size, - whiteheat_read_callback, port); - wrap->urb = urb; - list_add(&wrap->list, &info->rx_urbs_free); - - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - dev_err(&port->dev, "No free urbs available\n"); - goto no_tx_urb; - } - buf_size = port->write_urb->transfer_buffer_length; - urb->transfer_buffer = kmalloc(buf_size, GFP_KERNEL); - if (!urb->transfer_buffer) { - dev_err(&port->dev, - "Couldn't allocate urb buffer\n"); - goto no_tx_buf; - } - wrap = kmalloc(sizeof(*wrap), GFP_KERNEL); - if (!wrap) { - dev_err(&port->dev, - "Couldn't allocate urb wrapper\n"); - goto no_tx_wrap; - } - usb_fill_bulk_urb(urb, serial->dev, - usb_sndbulkpipe(serial->dev, - port->bulk_out_endpointAddress), - urb->transfer_buffer, buf_size, - whiteheat_write_callback, port); - wrap->urb = urb; - list_add(&wrap->list, &info->tx_urbs_free); - } - - usb_set_serial_port_data(port, info); - } - - command_info = kmalloc(sizeof(struct whiteheat_command_private), - GFP_KERNEL); - if (command_info == NULL) { - dev_err(&serial->dev->dev, - "%s: Out of memory for port structures\n", - serial->type->description); - goto no_command_private; - } - - mutex_init(&command_info->mutex); - command_info->port_running = 0; - init_waitqueue_head(&command_info->wait_command); - usb_set_serial_port_data(command_port, command_info); - command_port->write_urb->complete = command_port_write_callback; - command_port->read_urb->complete = command_port_read_callback; - kfree(result); - kfree(command); - - return 0; - -no_firmware: - /* Firmware likely not running */ - dev_err(&serial->dev->dev, - "%s: Unable to retrieve firmware version, try replugging\n", - serial->type->description); - dev_err(&serial->dev->dev, - "%s: If the firmware is not running (status led not blinking)\n", - serial->type->description); - dev_err(&serial->dev->dev, - "%s: please contact support@connecttech.com\n", - serial->type->description); - kfree(result); - return -ENODEV; - -no_command_private: - for (i = serial->num_ports - 1; i >= 0; i--) { - port = serial->port[i]; - info = usb_get_serial_port_data(port); - for (j = urb_pool_size - 1; j >= 0; j--) { - tmp = list_first(&info->tx_urbs_free); - list_del(tmp); - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - kfree(wrap); -no_tx_wrap: - kfree(urb->transfer_buffer); -no_tx_buf: - usb_free_urb(urb); -no_tx_urb: - tmp = list_first(&info->rx_urbs_free); - list_del(tmp); - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - kfree(wrap); -no_rx_wrap: - kfree(urb->transfer_buffer); -no_rx_buf: - usb_free_urb(urb); -no_rx_urb: - ; - } - kfree(info); -no_private: - ; - } - kfree(result); -no_result_buffer: - kfree(command); -no_command_buffer: - return -ENOMEM; -} - - -static void whiteheat_release(struct usb_serial *serial) -{ - struct usb_serial_port *command_port; - struct usb_serial_port *port; - struct whiteheat_private *info; - struct whiteheat_urb_wrap *wrap; - struct urb *urb; - struct list_head *tmp; - struct list_head *tmp2; - int i; - - dbg("%s", __func__); - - /* free up our private data for our command port */ - command_port = serial->port[COMMAND_PORT]; - kfree(usb_get_serial_port_data(command_port)); - - for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - info = usb_get_serial_port_data(port); - list_for_each_safe(tmp, tmp2, &info->rx_urbs_free) { - list_del(tmp); - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - kfree(wrap); - kfree(urb->transfer_buffer); - usb_free_urb(urb); - } - list_for_each_safe(tmp, tmp2, &info->tx_urbs_free) { - list_del(tmp); - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - kfree(wrap); - kfree(urb->transfer_buffer); - usb_free_urb(urb); - } - kfree(info); - } -} - -static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port) -{ - int retval = 0; - - dbg("%s - port %d", __func__, port->number); - - retval = start_command_port(port->serial); - if (retval) - goto exit; - - if (tty) - tty->low_latency = 1; - - /* send an open port command */ - retval = firm_open(port); - if (retval) { - stop_command_port(port->serial); - goto exit; - } - - retval = firm_purge(port, WHITEHEAT_PURGE_RX | WHITEHEAT_PURGE_TX); - if (retval) { - firm_close(port); - stop_command_port(port->serial); - goto exit; - } - - if (tty) - firm_setup_port(tty); - - /* Work around HCD bugs */ - usb_clear_halt(port->serial->dev, port->read_urb->pipe); - usb_clear_halt(port->serial->dev, port->write_urb->pipe); - - /* Start reading from the device */ - retval = start_port_read(port); - if (retval) { - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", - __func__, retval); - firm_close(port); - stop_command_port(port->serial); - goto exit; - } - -exit: - dbg("%s - exit, retval = %d", __func__, retval); - return retval; -} - - -static void whiteheat_close(struct usb_serial_port *port) -{ - struct whiteheat_private *info = usb_get_serial_port_data(port); - struct whiteheat_urb_wrap *wrap; - struct urb *urb; - struct list_head *tmp; - struct list_head *tmp2; - - dbg("%s - port %d", __func__, port->number); - - firm_report_tx_done(port); - firm_close(port); - - /* shutdown our bulk reads and writes */ - mutex_lock(&info->deathwarrant); - spin_lock_irq(&info->lock); - list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) { - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - list_del(tmp); - spin_unlock_irq(&info->lock); - usb_kill_urb(urb); - spin_lock_irq(&info->lock); - list_add(tmp, &info->rx_urbs_free); - } - list_for_each_safe(tmp, tmp2, &info->rx_urb_q) - list_move(tmp, &info->rx_urbs_free); - list_for_each_safe(tmp, tmp2, &info->tx_urbs_submitted) { - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - list_del(tmp); - spin_unlock_irq(&info->lock); - usb_kill_urb(urb); - spin_lock_irq(&info->lock); - list_add(tmp, &info->tx_urbs_free); - } - spin_unlock_irq(&info->lock); - mutex_unlock(&info->deathwarrant); - stop_command_port(port->serial); -} - - -static int whiteheat_write(struct tty_struct *tty, - struct usb_serial_port *port, const unsigned char *buf, int count) -{ - struct whiteheat_private *info = usb_get_serial_port_data(port); - struct whiteheat_urb_wrap *wrap; - struct urb *urb; - int result; - int bytes; - int sent = 0; - unsigned long flags; - struct list_head *tmp; - - dbg("%s - port %d", __func__, port->number); - - if (count == 0) { - dbg("%s - write request of 0 bytes", __func__); - return (0); - } - - while (count) { - spin_lock_irqsave(&info->lock, flags); - if (list_empty(&info->tx_urbs_free)) { - spin_unlock_irqrestore(&info->lock, flags); - break; - } - tmp = list_first(&info->tx_urbs_free); - list_del(tmp); - spin_unlock_irqrestore(&info->lock, flags); - - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - bytes = (count > port->bulk_out_size) ? - port->bulk_out_size : count; - memcpy(urb->transfer_buffer, buf + sent, bytes); - - usb_serial_debug_data(debug, &port->dev, - __func__, bytes, urb->transfer_buffer); - - urb->transfer_buffer_length = bytes; - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) { - dev_err_console(port, - "%s - failed submitting write urb, error %d\n", - __func__, result); - sent = result; - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->tx_urbs_free); - spin_unlock_irqrestore(&info->lock, flags); - break; - } else { - sent += bytes; - count -= bytes; - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->tx_urbs_submitted); - spin_unlock_irqrestore(&info->lock, flags); - } - } - - return sent; -} - -static int whiteheat_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct whiteheat_private *info = usb_get_serial_port_data(port); - struct list_head *tmp; - int room = 0; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&info->lock, flags); - list_for_each(tmp, &info->tx_urbs_free) - room++; - spin_unlock_irqrestore(&info->lock, flags); - room *= port->bulk_out_size; - - dbg("%s - returns %d", __func__, room); - return (room); -} - -static int whiteheat_tiocmget(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct whiteheat_private *info = usb_get_serial_port_data(port); - unsigned int modem_signals = 0; - - dbg("%s - port %d", __func__, port->number); - - firm_get_dtr_rts(port); - if (info->mcr & UART_MCR_DTR) - modem_signals |= TIOCM_DTR; - if (info->mcr & UART_MCR_RTS) - modem_signals |= TIOCM_RTS; - - return modem_signals; -} - -static int whiteheat_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct usb_serial_port *port = tty->driver_data; - struct whiteheat_private *info = usb_get_serial_port_data(port); - - dbg("%s - port %d", __func__, port->number); - - if (set & TIOCM_RTS) - info->mcr |= UART_MCR_RTS; - if (set & TIOCM_DTR) - info->mcr |= UART_MCR_DTR; - - if (clear & TIOCM_RTS) - info->mcr &= ~UART_MCR_RTS; - if (clear & TIOCM_DTR) - info->mcr &= ~UART_MCR_DTR; - - firm_set_dtr(port, info->mcr & UART_MCR_DTR); - firm_set_rts(port, info->mcr & UART_MCR_RTS); - return 0; -} - - -static int whiteheat_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct usb_serial_port *port = tty->driver_data; - struct serial_struct serstruct; - void __user *user_arg = (void __user *)arg; - - dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd); - - switch (cmd) { - case TIOCGSERIAL: - memset(&serstruct, 0, sizeof(serstruct)); - serstruct.type = PORT_16654; - serstruct.line = port->serial->minor; - serstruct.port = port->number; - serstruct.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; - serstruct.xmit_fifo_size = port->bulk_out_size; - serstruct.custom_divisor = 0; - serstruct.baud_base = 460800; - serstruct.close_delay = CLOSING_DELAY; - serstruct.closing_wait = CLOSING_DELAY; - - if (copy_to_user(user_arg, &serstruct, sizeof(serstruct))) - return -EFAULT; - break; - default: - break; - } - - return -ENOIOCTLCMD; -} - - -static void whiteheat_set_termios(struct tty_struct *tty, - struct usb_serial_port *port, struct ktermios *old_termios) -{ - firm_setup_port(tty); -} - -static void whiteheat_break_ctl(struct tty_struct *tty, int break_state) -{ - struct usb_serial_port *port = tty->driver_data; - firm_set_break(port, break_state); -} - - -static int whiteheat_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct whiteheat_private *info = usb_get_serial_port_data(port); - struct list_head *tmp; - struct whiteheat_urb_wrap *wrap; - int chars = 0; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&info->lock, flags); - list_for_each(tmp, &info->tx_urbs_submitted) { - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - chars += wrap->urb->transfer_buffer_length; - } - spin_unlock_irqrestore(&info->lock, flags); - - dbg("%s - returns %d", __func__, chars); - return chars; -} - - -static void whiteheat_throttle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct whiteheat_private *info = usb_get_serial_port_data(port); - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irq(&info->lock); - info->flags |= THROTTLED; - spin_unlock_irq(&info->lock); -} - - -static void whiteheat_unthrottle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct whiteheat_private *info = usb_get_serial_port_data(port); - int actually_throttled; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irq(&info->lock); - actually_throttled = info->flags & ACTUALLY_THROTTLED; - info->flags &= ~(THROTTLED | ACTUALLY_THROTTLED); - spin_unlock_irq(&info->lock); - - if (actually_throttled) - rx_data_softint(&info->rx_work); -} - - -/***************************************************************************** - * Connect Tech's White Heat callback routines - *****************************************************************************/ -static void command_port_write_callback(struct urb *urb) -{ - int status = urb->status; - - dbg("%s", __func__); - - if (status) { - dbg("nonzero urb status: %d", status); - return; - } -} - - -static void command_port_read_callback(struct urb *urb) -{ - struct usb_serial_port *command_port = urb->context; - struct whiteheat_command_private *command_info; - int status = urb->status; - unsigned char *data = urb->transfer_buffer; - int result; - - dbg("%s", __func__); - - command_info = usb_get_serial_port_data(command_port); - if (!command_info) { - dbg("%s - command_info is NULL, exiting.", __func__); - return; - } - if (status) { - dbg("%s - nonzero urb status: %d", __func__, status); - if (status != -ENOENT) - command_info->command_finished = WHITEHEAT_CMD_FAILURE; - wake_up(&command_info->wait_command); - return; - } - - usb_serial_debug_data(debug, &command_port->dev, - __func__, urb->actual_length, data); - - if (data[0] == WHITEHEAT_CMD_COMPLETE) { - command_info->command_finished = WHITEHEAT_CMD_COMPLETE; - wake_up(&command_info->wait_command); - } else if (data[0] == WHITEHEAT_CMD_FAILURE) { - command_info->command_finished = WHITEHEAT_CMD_FAILURE; - wake_up(&command_info->wait_command); - } else if (data[0] == WHITEHEAT_EVENT) { - /* These are unsolicited reports from the firmware, hence no - waiting command to wakeup */ - dbg("%s - event received", __func__); - } else if (data[0] == WHITEHEAT_GET_DTR_RTS) { - memcpy(command_info->result_buffer, &data[1], - urb->actual_length - 1); - command_info->command_finished = WHITEHEAT_CMD_COMPLETE; - wake_up(&command_info->wait_command); - } else - dbg("%s - bad reply from firmware", __func__); - - /* Continue trying to always read */ - result = usb_submit_urb(command_port->read_urb, GFP_ATOMIC); - if (result) - dbg("%s - failed resubmitting read urb, error %d", - __func__, result); -} - - -static void whiteheat_read_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct whiteheat_urb_wrap *wrap; - unsigned char *data = urb->transfer_buffer; - struct whiteheat_private *info = usb_get_serial_port_data(port); - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - - spin_lock(&info->lock); - wrap = urb_to_wrap(urb, &info->rx_urbs_submitted); - if (!wrap) { - spin_unlock(&info->lock); - dev_err(&port->dev, "%s - Not my urb!\n", __func__); - return; - } - list_del(&wrap->list); - spin_unlock(&info->lock); - - if (status) { - dbg("%s - nonzero read bulk status received: %d", - __func__, status); - spin_lock(&info->lock); - list_add(&wrap->list, &info->rx_urbs_free); - spin_unlock(&info->lock); - return; - } - - usb_serial_debug_data(debug, &port->dev, - __func__, urb->actual_length, data); - - spin_lock(&info->lock); - list_add_tail(&wrap->list, &info->rx_urb_q); - if (info->flags & THROTTLED) { - info->flags |= ACTUALLY_THROTTLED; - spin_unlock(&info->lock); - return; - } - spin_unlock(&info->lock); - - schedule_work(&info->rx_work); -} - - -static void whiteheat_write_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct whiteheat_private *info = usb_get_serial_port_data(port); - struct whiteheat_urb_wrap *wrap; - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - - spin_lock(&info->lock); - wrap = urb_to_wrap(urb, &info->tx_urbs_submitted); - if (!wrap) { - spin_unlock(&info->lock); - dev_err(&port->dev, "%s - Not my urb!\n", __func__); - return; - } - list_move(&wrap->list, &info->tx_urbs_free); - spin_unlock(&info->lock); - - if (status) { - dbg("%s - nonzero write bulk status received: %d", - __func__, status); - return; - } - - usb_serial_port_softint(port); -} - - -/***************************************************************************** - * Connect Tech's White Heat firmware interface - *****************************************************************************/ -static int firm_send_command(struct usb_serial_port *port, __u8 command, - __u8 *data, __u8 datasize) -{ - struct usb_serial_port *command_port; - struct whiteheat_command_private *command_info; - struct whiteheat_private *info; - __u8 *transfer_buffer; - int retval = 0; - int t; - - dbg("%s - command %d", __func__, command); - - command_port = port->serial->port[COMMAND_PORT]; - command_info = usb_get_serial_port_data(command_port); - mutex_lock(&command_info->mutex); - command_info->command_finished = false; - - transfer_buffer = (__u8 *)command_port->write_urb->transfer_buffer; - transfer_buffer[0] = command; - memcpy(&transfer_buffer[1], data, datasize); - command_port->write_urb->transfer_buffer_length = datasize + 1; - retval = usb_submit_urb(command_port->write_urb, GFP_NOIO); - if (retval) { - dbg("%s - submit urb failed", __func__); - goto exit; - } - - /* wait for the command to complete */ - t = wait_event_timeout(command_info->wait_command, - (bool)command_info->command_finished, COMMAND_TIMEOUT); - if (!t) - usb_kill_urb(command_port->write_urb); - - if (command_info->command_finished == false) { - dbg("%s - command timed out.", __func__); - retval = -ETIMEDOUT; - goto exit; - } - - if (command_info->command_finished == WHITEHEAT_CMD_FAILURE) { - dbg("%s - command failed.", __func__); - retval = -EIO; - goto exit; - } - - if (command_info->command_finished == WHITEHEAT_CMD_COMPLETE) { - dbg("%s - command completed.", __func__); - switch (command) { - case WHITEHEAT_GET_DTR_RTS: - info = usb_get_serial_port_data(port); - memcpy(&info->mcr, command_info->result_buffer, - sizeof(struct whiteheat_dr_info)); - break; - } - } -exit: - mutex_unlock(&command_info->mutex); - return retval; -} - - -static int firm_open(struct usb_serial_port *port) -{ - struct whiteheat_simple open_command; - - open_command.port = port->number - port->serial->minor + 1; - return firm_send_command(port, WHITEHEAT_OPEN, - (__u8 *)&open_command, sizeof(open_command)); -} - - -static int firm_close(struct usb_serial_port *port) -{ - struct whiteheat_simple close_command; - - close_command.port = port->number - port->serial->minor + 1; - return firm_send_command(port, WHITEHEAT_CLOSE, - (__u8 *)&close_command, sizeof(close_command)); -} - - -static void firm_setup_port(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct whiteheat_port_settings port_settings; - unsigned int cflag = tty->termios->c_cflag; - - port_settings.port = port->number + 1; - - /* get the byte size */ - switch (cflag & CSIZE) { - case CS5: port_settings.bits = 5; break; - case CS6: port_settings.bits = 6; break; - case CS7: port_settings.bits = 7; break; - default: - case CS8: port_settings.bits = 8; break; - } - dbg("%s - data bits = %d", __func__, port_settings.bits); - - /* determine the parity */ - if (cflag & PARENB) - if (cflag & CMSPAR) - if (cflag & PARODD) - port_settings.parity = WHITEHEAT_PAR_MARK; - else - port_settings.parity = WHITEHEAT_PAR_SPACE; - else - if (cflag & PARODD) - port_settings.parity = WHITEHEAT_PAR_ODD; - else - port_settings.parity = WHITEHEAT_PAR_EVEN; - else - port_settings.parity = WHITEHEAT_PAR_NONE; - dbg("%s - parity = %c", __func__, port_settings.parity); - - /* figure out the stop bits requested */ - if (cflag & CSTOPB) - port_settings.stop = 2; - else - port_settings.stop = 1; - dbg("%s - stop bits = %d", __func__, port_settings.stop); - - /* figure out the flow control settings */ - if (cflag & CRTSCTS) - port_settings.hflow = (WHITEHEAT_HFLOW_CTS | - WHITEHEAT_HFLOW_RTS); - else - port_settings.hflow = WHITEHEAT_HFLOW_NONE; - dbg("%s - hardware flow control = %s %s %s %s", __func__, - (port_settings.hflow & WHITEHEAT_HFLOW_CTS) ? "CTS" : "", - (port_settings.hflow & WHITEHEAT_HFLOW_RTS) ? "RTS" : "", - (port_settings.hflow & WHITEHEAT_HFLOW_DSR) ? "DSR" : "", - (port_settings.hflow & WHITEHEAT_HFLOW_DTR) ? "DTR" : ""); - - /* determine software flow control */ - if (I_IXOFF(tty)) - port_settings.sflow = WHITEHEAT_SFLOW_RXTX; - else - port_settings.sflow = WHITEHEAT_SFLOW_NONE; - dbg("%s - software flow control = %c", __func__, port_settings.sflow); - - port_settings.xon = START_CHAR(tty); - port_settings.xoff = STOP_CHAR(tty); - dbg("%s - XON = %2x, XOFF = %2x", - __func__, port_settings.xon, port_settings.xoff); - - /* get the baud rate wanted */ - port_settings.baud = tty_get_baud_rate(tty); - dbg("%s - baud rate = %d", __func__, port_settings.baud); - - /* fixme: should set validated settings */ - tty_encode_baud_rate(tty, port_settings.baud, port_settings.baud); - /* handle any settings that aren't specified in the tty structure */ - port_settings.lloop = 0; - - /* now send the message to the device */ - firm_send_command(port, WHITEHEAT_SETUP_PORT, - (__u8 *)&port_settings, sizeof(port_settings)); -} - - -static int firm_set_rts(struct usb_serial_port *port, __u8 onoff) -{ - struct whiteheat_set_rdb rts_command; - - rts_command.port = port->number - port->serial->minor + 1; - rts_command.state = onoff; - return firm_send_command(port, WHITEHEAT_SET_RTS, - (__u8 *)&rts_command, sizeof(rts_command)); -} - - -static int firm_set_dtr(struct usb_serial_port *port, __u8 onoff) -{ - struct whiteheat_set_rdb dtr_command; - - dtr_command.port = port->number - port->serial->minor + 1; - dtr_command.state = onoff; - return firm_send_command(port, WHITEHEAT_SET_DTR, - (__u8 *)&dtr_command, sizeof(dtr_command)); -} - - -static int firm_set_break(struct usb_serial_port *port, __u8 onoff) -{ - struct whiteheat_set_rdb break_command; - - break_command.port = port->number - port->serial->minor + 1; - break_command.state = onoff; - return firm_send_command(port, WHITEHEAT_SET_BREAK, - (__u8 *)&break_command, sizeof(break_command)); -} - - -static int firm_purge(struct usb_serial_port *port, __u8 rxtx) -{ - struct whiteheat_purge purge_command; - - purge_command.port = port->number - port->serial->minor + 1; - purge_command.what = rxtx; - return firm_send_command(port, WHITEHEAT_PURGE, - (__u8 *)&purge_command, sizeof(purge_command)); -} - - -static int firm_get_dtr_rts(struct usb_serial_port *port) -{ - struct whiteheat_simple get_dr_command; - - get_dr_command.port = port->number - port->serial->minor + 1; - return firm_send_command(port, WHITEHEAT_GET_DTR_RTS, - (__u8 *)&get_dr_command, sizeof(get_dr_command)); -} - - -static int firm_report_tx_done(struct usb_serial_port *port) -{ - struct whiteheat_simple close_command; - - close_command.port = port->number - port->serial->minor + 1; - return firm_send_command(port, WHITEHEAT_REPORT_TX_DONE, - (__u8 *)&close_command, sizeof(close_command)); -} - - -/***************************************************************************** - * Connect Tech's White Heat utility functions - *****************************************************************************/ -static int start_command_port(struct usb_serial *serial) -{ - struct usb_serial_port *command_port; - struct whiteheat_command_private *command_info; - int retval = 0; - - command_port = serial->port[COMMAND_PORT]; - command_info = usb_get_serial_port_data(command_port); - mutex_lock(&command_info->mutex); - if (!command_info->port_running) { - /* Work around HCD bugs */ - usb_clear_halt(serial->dev, command_port->read_urb->pipe); - - retval = usb_submit_urb(command_port->read_urb, GFP_KERNEL); - if (retval) { - dev_err(&serial->dev->dev, - "%s - failed submitting read urb, error %d\n", - __func__, retval); - goto exit; - } - } - command_info->port_running++; - -exit: - mutex_unlock(&command_info->mutex); - return retval; -} - - -static void stop_command_port(struct usb_serial *serial) -{ - struct usb_serial_port *command_port; - struct whiteheat_command_private *command_info; - - command_port = serial->port[COMMAND_PORT]; - command_info = usb_get_serial_port_data(command_port); - mutex_lock(&command_info->mutex); - command_info->port_running--; - if (!command_info->port_running) - usb_kill_urb(command_port->read_urb); - mutex_unlock(&command_info->mutex); -} - - -static int start_port_read(struct usb_serial_port *port) -{ - struct whiteheat_private *info = usb_get_serial_port_data(port); - struct whiteheat_urb_wrap *wrap; - struct urb *urb; - int retval = 0; - unsigned long flags; - struct list_head *tmp; - struct list_head *tmp2; - - spin_lock_irqsave(&info->lock, flags); - - list_for_each_safe(tmp, tmp2, &info->rx_urbs_free) { - list_del(tmp); - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - spin_unlock_irqrestore(&info->lock, flags); - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->rx_urbs_free); - list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) { - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - list_del(tmp); - spin_unlock_irqrestore(&info->lock, flags); - usb_kill_urb(urb); - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->rx_urbs_free); - } - break; - } - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->rx_urbs_submitted); - } - - spin_unlock_irqrestore(&info->lock, flags); - - return retval; -} - - -static struct whiteheat_urb_wrap *urb_to_wrap(struct urb *urb, - struct list_head *head) -{ - struct whiteheat_urb_wrap *wrap; - struct list_head *tmp; - - list_for_each(tmp, head) { - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - if (wrap->urb == urb) - return wrap; - } - - return NULL; -} - - -static struct list_head *list_first(struct list_head *head) -{ - return head->next; -} - - -static void rx_data_softint(struct work_struct *work) -{ - struct whiteheat_private *info = - container_of(work, struct whiteheat_private, rx_work); - struct usb_serial_port *port = info->port; - struct tty_struct *tty = tty_port_tty_get(&port->port); - struct whiteheat_urb_wrap *wrap; - struct urb *urb; - unsigned long flags; - struct list_head *tmp; - struct list_head *tmp2; - int result; - int sent = 0; - - spin_lock_irqsave(&info->lock, flags); - if (info->flags & THROTTLED) { - spin_unlock_irqrestore(&info->lock, flags); - goto out; - } - - list_for_each_safe(tmp, tmp2, &info->rx_urb_q) { - list_del(tmp); - spin_unlock_irqrestore(&info->lock, flags); - - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - - if (tty && urb->actual_length) - sent += tty_insert_flip_string(tty, - urb->transfer_buffer, urb->actual_length); - - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) { - dev_err(&port->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, result); - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->rx_urbs_free); - continue; - } - - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->rx_urbs_submitted); - } - spin_unlock_irqrestore(&info->lock, flags); - - if (sent) - tty_flip_buffer_push(tty); -out: - tty_kref_put(tty); -} - -module_usb_serial_driver(whiteheat_driver, serial_drivers); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -MODULE_FIRMWARE("whiteheat.fw"); -MODULE_FIRMWARE("whiteheat_loader.fw"); - -module_param(urb_pool_size, int, 0); -MODULE_PARM_DESC(urb_pool_size, "Number of urbs to use for buffering"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/ANDROID_3.4.5/drivers/usb/serial/whiteheat.h b/ANDROID_3.4.5/drivers/usb/serial/whiteheat.h deleted file mode 100644 index 38065df4..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/whiteheat.h +++ /dev/null @@ -1,302 +0,0 @@ -/* - * USB ConnectTech WhiteHEAT driver - * - * Copyright (C) 2002 - * Connect Tech Inc. - * - * Copyright (C) 1999, 2000 - * Greg Kroah-Hartman (greg@kroah.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * See Documentation/usb/usb-serial.txt for more information on using this - * driver - * - */ - -#ifndef __LINUX_USB_SERIAL_WHITEHEAT_H -#define __LINUX_USB_SERIAL_WHITEHEAT_H - - -/* WhiteHEAT commands */ -#define WHITEHEAT_OPEN 1 /* open the port */ -#define WHITEHEAT_CLOSE 2 /* close the port */ -#define WHITEHEAT_SETUP_PORT 3 /* change port settings */ -#define WHITEHEAT_SET_RTS 4 /* turn RTS on or off */ -#define WHITEHEAT_SET_DTR 5 /* turn DTR on or off */ -#define WHITEHEAT_SET_BREAK 6 /* turn BREAK on or off */ -#define WHITEHEAT_DUMP 7 /* dump memory */ -#define WHITEHEAT_STATUS 8 /* get status */ -#define WHITEHEAT_PURGE 9 /* clear the UART fifos */ -#define WHITEHEAT_GET_DTR_RTS 10 /* get the state of DTR and RTS - for a port */ -#define WHITEHEAT_GET_HW_INFO 11 /* get EEPROM info and - hardware ID */ -#define WHITEHEAT_REPORT_TX_DONE 12 /* get the next TX done */ -#define WHITEHEAT_EVENT 13 /* unsolicited status events */ -#define WHITEHEAT_ECHO 14 /* send data to the indicated - IN endpoint */ -#define WHITEHEAT_DO_TEST 15 /* perform specified test */ -#define WHITEHEAT_CMD_COMPLETE 16 /* reply for some commands */ -#define WHITEHEAT_CMD_FAILURE 17 /* reply for failed commands */ - - -/* - * Commands to the firmware - */ - - -/* - * WHITEHEAT_OPEN - * WHITEHEAT_CLOSE - * WHITEHEAT_STATUS - * WHITEHEAT_GET_DTR_RTS - * WHITEHEAT_REPORT_TX_DONE -*/ -struct whiteheat_simple { - __u8 port; /* port number (1 to N) */ -}; - - -/* - * WHITEHEAT_SETUP_PORT - */ -#define WHITEHEAT_PAR_NONE 'n' /* no parity */ -#define WHITEHEAT_PAR_EVEN 'e' /* even parity */ -#define WHITEHEAT_PAR_ODD 'o' /* odd parity */ -#define WHITEHEAT_PAR_SPACE '0' /* space (force 0) parity */ -#define WHITEHEAT_PAR_MARK '1' /* mark (force 1) parity */ - -#define WHITEHEAT_SFLOW_NONE 'n' /* no software flow control */ -#define WHITEHEAT_SFLOW_RX 'r' /* XOFF/ON is sent when RX - fills/empties */ -#define WHITEHEAT_SFLOW_TX 't' /* when received XOFF/ON will - stop/start TX */ -#define WHITEHEAT_SFLOW_RXTX 'b' /* both SFLOW_RX and SFLOW_TX */ - -#define WHITEHEAT_HFLOW_NONE 0x00 /* no hardware flow control */ -#define WHITEHEAT_HFLOW_RTS_TOGGLE 0x01 /* RTS is on during transmit, - off otherwise */ -#define WHITEHEAT_HFLOW_DTR 0x02 /* DTR is off/on when RX - fills/empties */ -#define WHITEHEAT_HFLOW_CTS 0x08 /* when received CTS off/on - will stop/start TX */ -#define WHITEHEAT_HFLOW_DSR 0x10 /* when received DSR off/on - will stop/start TX */ -#define WHITEHEAT_HFLOW_RTS 0x80 /* RTS is off/on when RX - fills/empties */ - -struct whiteheat_port_settings { - __u8 port; /* port number (1 to N) */ - __u32 baud; /* any value 7 - 460800, firmware calculates - best fit; arrives little endian */ - __u8 bits; /* 5, 6, 7, or 8 */ - __u8 stop; /* 1 or 2, default 1 (2 = 1.5 if bits = 5) */ - __u8 parity; /* see WHITEHEAT_PAR_* above */ - __u8 sflow; /* see WHITEHEAT_SFLOW_* above */ - __u8 xoff; /* XOFF byte value */ - __u8 xon; /* XON byte value */ - __u8 hflow; /* see WHITEHEAT_HFLOW_* above */ - __u8 lloop; /* 0/1 turns local loopback mode off/on */ -} __attribute__ ((packed)); - - -/* - * WHITEHEAT_SET_RTS - * WHITEHEAT_SET_DTR - * WHITEHEAT_SET_BREAK - */ -#define WHITEHEAT_RTS_OFF 0x00 -#define WHITEHEAT_RTS_ON 0x01 -#define WHITEHEAT_DTR_OFF 0x00 -#define WHITEHEAT_DTR_ON 0x01 -#define WHITEHEAT_BREAK_OFF 0x00 -#define WHITEHEAT_BREAK_ON 0x01 - -struct whiteheat_set_rdb { - __u8 port; /* port number (1 to N) */ - __u8 state; /* 0/1 turns signal off/on */ -}; - - -/* - * WHITEHEAT_DUMP - */ -#define WHITEHEAT_DUMP_MEM_DATA 'd' /* data */ -#define WHITEHEAT_DUMP_MEM_IDATA 'i' /* idata */ -#define WHITEHEAT_DUMP_MEM_BDATA 'b' /* bdata */ -#define WHITEHEAT_DUMP_MEM_XDATA 'x' /* xdata */ - -/* - * Allowable address ranges (firmware checks address): - * Type DATA: 0x00 - 0xff - * Type IDATA: 0x80 - 0xff - * Type BDATA: 0x20 - 0x2f - * Type XDATA: 0x0000 - 0xffff - * - * B/I/DATA all read the local memory space - * XDATA reads the external memory space - * BDATA returns bits as bytes - * - * NOTE: 0x80 - 0xff (local space) are the Special Function Registers - * of the 8051, and some have on-read side-effects. - */ - -struct whiteheat_dump { - __u8 mem_type; /* see WHITEHEAT_DUMP_* above */ - __u16 addr; /* address, see restrictions above */ - __u16 length; /* number of bytes to dump, max 63 bytes */ -}; - - -/* - * WHITEHEAT_PURGE - */ -#define WHITEHEAT_PURGE_RX 0x01 /* purge rx fifos */ -#define WHITEHEAT_PURGE_TX 0x02 /* purge tx fifos */ - -struct whiteheat_purge { - __u8 port; /* port number (1 to N) */ - __u8 what; /* bit pattern of what to purge */ -}; - - -/* - * WHITEHEAT_ECHO - */ -struct whiteheat_echo { - __u8 port; /* port number (1 to N) */ - __u8 length; /* length of message to echo, max 61 bytes */ - __u8 echo_data[61]; /* data to echo */ -}; - - -/* - * WHITEHEAT_DO_TEST - */ -#define WHITEHEAT_TEST_UART_RW 0x01 /* read/write uart registers */ -#define WHITEHEAT_TEST_UART_INTR 0x02 /* uart interrupt */ -#define WHITEHEAT_TEST_SETUP_CONT 0x03 /* setup for - PORT_CONT/PORT_DISCONT */ -#define WHITEHEAT_TEST_PORT_CONT 0x04 /* port connect */ -#define WHITEHEAT_TEST_PORT_DISCONT 0x05 /* port disconnect */ -#define WHITEHEAT_TEST_UART_CLK_START 0x06 /* uart clock test start */ -#define WHITEHEAT_TEST_UART_CLK_STOP 0x07 /* uart clock test stop */ -#define WHITEHEAT_TEST_MODEM_FT 0x08 /* modem signals, requires a - loopback cable/connector */ -#define WHITEHEAT_TEST_ERASE_EEPROM 0x09 /* erase eeprom */ -#define WHITEHEAT_TEST_READ_EEPROM 0x0a /* read eeprom */ -#define WHITEHEAT_TEST_PROGRAM_EEPROM 0x0b /* program eeprom */ - -struct whiteheat_test { - __u8 port; /* port number (1 to n) */ - __u8 test; /* see WHITEHEAT_TEST_* above*/ - __u8 info[32]; /* additional info */ -}; - - -/* - * Replies from the firmware - */ - - -/* - * WHITEHEAT_STATUS - */ -#define WHITEHEAT_EVENT_MODEM 0x01 /* modem field is valid */ -#define WHITEHEAT_EVENT_ERROR 0x02 /* error field is valid */ -#define WHITEHEAT_EVENT_FLOW 0x04 /* flow field is valid */ -#define WHITEHEAT_EVENT_CONNECT 0x08 /* connect field is valid */ - -#define WHITEHEAT_FLOW_NONE 0x00 /* no flow control active */ -#define WHITEHEAT_FLOW_HARD_OUT 0x01 /* TX is stopped by CTS - (waiting for CTS to go on) */ -#define WHITEHEAT_FLOW_HARD_IN 0x02 /* remote TX is stopped - by RTS */ -#define WHITEHEAT_FLOW_SOFT_OUT 0x04 /* TX is stopped by XOFF - received (waiting for XON) */ -#define WHITEHEAT_FLOW_SOFT_IN 0x08 /* remote TX is stopped by XOFF - transmitted */ -#define WHITEHEAT_FLOW_TX_DONE 0x80 /* TX has completed */ - -struct whiteheat_status_info { - __u8 port; /* port number (1 to N) */ - __u8 event; /* indicates what the current event is, - see WHITEHEAT_EVENT_* above */ - __u8 modem; /* modem signal status (copy of uart's - MSR register) */ - __u8 error; /* line status (copy of uart's LSR register) */ - __u8 flow; /* flow control state, see WHITEHEAT_FLOW_* - above */ - __u8 connect; /* 0 means not connected, non-zero means - connected */ -}; - - -/* - * WHITEHEAT_GET_DTR_RTS - */ -struct whiteheat_dr_info { - __u8 mcr; /* copy of uart's MCR register */ -}; - - -/* - * WHITEHEAT_GET_HW_INFO - */ -struct whiteheat_hw_info { - __u8 hw_id; /* hardware id number, WhiteHEAT = 0 */ - __u8 sw_major_rev; /* major version number */ - __u8 sw_minor_rev; /* minor version number */ - struct whiteheat_hw_eeprom_info { - __u8 b0; /* B0 */ - __u8 vendor_id_low; /* vendor id (low byte) */ - __u8 vendor_id_high; /* vendor id (high byte) */ - __u8 product_id_low; /* product id (low byte) */ - __u8 product_id_high; /* product id (high byte) */ - __u8 device_id_low; /* device id (low byte) */ - __u8 device_id_high; /* device id (high byte) */ - __u8 not_used_1; - __u8 serial_number_0; /* serial number (low byte) */ - __u8 serial_number_1; /* serial number */ - __u8 serial_number_2; /* serial number */ - __u8 serial_number_3; /* serial number (high byte) */ - __u8 not_used_2; - __u8 not_used_3; - __u8 checksum_low; /* checksum (low byte) */ - __u8 checksum_high; /* checksum (high byte */ - } hw_eeprom_info; /* EEPROM contents */ -}; - - -/* - * WHITEHEAT_EVENT - */ -struct whiteheat_event_info { - __u8 port; /* port number (1 to N) */ - __u8 event; /* see whiteheat_status_info.event */ - __u8 info; /* see whiteheat_status_info.modem, .error, - .flow, .connect */ -}; - - -/* - * WHITEHEAT_DO_TEST - */ -#define WHITEHEAT_TEST_FAIL 0x00 /* test failed */ -#define WHITEHEAT_TEST_UNKNOWN 0x01 /* unknown test requested */ -#define WHITEHEAT_TEST_PASS 0xff /* test passed */ - -struct whiteheat_test_info { - __u8 port; /* port number (1 to N) */ - __u8 test; /* indicates which test this is a response for, - see WHITEHEAT_DO_TEST above */ - __u8 status; /* see WHITEHEAT_TEST_* above */ - __u8 results[32]; /* test-dependent results */ -}; - - -#endif diff --git a/ANDROID_3.4.5/drivers/usb/serial/zio.c b/ANDROID_3.4.5/drivers/usb/serial/zio.c deleted file mode 100644 index 9d0bb375..00000000 --- a/ANDROID_3.4.5/drivers/usb/serial/zio.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * ZIO Motherboard USB driver - * - * Copyright (C) 2010 Zilogic Systems - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include - -static const struct usb_device_id id_table[] = { - { USB_DEVICE(0x1CBE, 0x0103) }, - { }, -}; -MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver zio_driver = { - .name = "zio", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - -static struct usb_serial_driver zio_device = { - .driver = { - .owner = THIS_MODULE, - .name = "zio", - }, - .id_table = id_table, - .num_ports = 1, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &zio_device, NULL -}; - -module_usb_serial_driver(zio_driver, serial_drivers); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/storage/Kconfig b/ANDROID_3.4.5/drivers/usb/storage/Kconfig deleted file mode 100644 index 7691c866..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/Kconfig +++ /dev/null @@ -1,229 +0,0 @@ -# -# USB Storage driver configuration -# - -comment "NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may" -comment "also be needed; see USB_STORAGE Help for more info" - depends on USB - -config USB_STORAGE - tristate "USB Mass Storage support" - depends on USB && SCSI - ---help--- - Say Y here if you want to connect USB mass storage devices to your - computer's USB port. This is the driver you need for USB - floppy drives, USB hard disks, USB tape drives, USB CD-ROMs, - USB flash devices, and memory sticks, along with - similar devices. This driver may also be used for some cameras - and card readers. - - This option depends on 'SCSI' support being enabled, but you - probably also need 'SCSI device support: SCSI disk support' - (BLK_DEV_SD) for most USB storage devices. - - To compile this driver as a module, choose M here: the - module will be called usb-storage. - -config USB_STORAGE_DEBUG - bool "USB Mass Storage verbose debug" - depends on USB_STORAGE - help - Say Y here in order to have the USB Mass Storage code generate - verbose debugging messages. - -config USB_STORAGE_REALTEK - tristate "Realtek Card Reader support" - depends on USB_STORAGE - help - Say Y here to include additional code to support the power-saving function - for Realtek RTS51xx USB card readers. - - If this driver is compiled as a module, it will be named ums-realtek. - -config REALTEK_AUTOPM - bool "Realtek Card Reader autosuspend support" - depends on USB_STORAGE_REALTEK && PM_RUNTIME - default y - -config USB_STORAGE_DATAFAB - tristate "Datafab Compact Flash Reader support" - depends on USB_STORAGE - help - Support for certain Datafab CompactFlash readers. - Datafab has a web page at . - - If this driver is compiled as a module, it will be named ums-datafab. - -config USB_STORAGE_FREECOM - tristate "Freecom USB/ATAPI Bridge support" - depends on USB_STORAGE - help - Support for the Freecom USB to IDE/ATAPI adaptor. - Freecom has a web page at . - - If this driver is compiled as a module, it will be named ums-freecom. - -config USB_STORAGE_ISD200 - tristate "ISD-200 USB/ATA Bridge support" - depends on USB_STORAGE - ---help--- - Say Y here if you want to use USB Mass Store devices based - on the In-Systems Design ISD-200 USB/ATA bridge. - - Some of the products that use this chip are: - - - Archos Jukebox 6000 - - ISD SmartCable for Storage - - Taiwan Skymaster CD530U/DEL-0241 IDE bridge - - Sony CRX10U CD-R/RW drive - - CyQ've CQ8060A CDRW drive - - Planex eXtreme Drive RX-25HU USB-IDE cable (not model RX-25U) - - If this driver is compiled as a module, it will be named ums-isd200. - -config USB_STORAGE_USBAT - tristate "USBAT/USBAT02-based storage support" - depends on USB_STORAGE - help - Say Y here to include additional code to support storage devices - based on the SCM/Shuttle USBAT/USBAT02 processors. - - Devices reported to work with this driver include: - - CompactFlash reader included with Kodak DC3800 camera - - Dane-Elec Zmate CompactFlash reader - - Delkin Efilm reader2 - - HP 8200e/8210e/8230e CD-Writer Plus drives - - I-JAM JS-50U - - Jessops CompactFlash JESDCFRU BLACK - - Kingston Technology PCREAD-USB/CF - - Maxell UA4 CompactFlash reader - - Memorex UCF-100 - - Microtech ZiO! ICS-45 CF2 - - RCA LYRA MP3 portable - - Sandisk ImageMate SDDR-05b - - If this driver is compiled as a module, it will be named ums-usbat. - -config USB_STORAGE_SDDR09 - tristate "SanDisk SDDR-09 (and other SmartMedia, including DPCM) support" - depends on USB_STORAGE - help - Say Y here to include additional code to support the Sandisk SDDR-09 - SmartMedia reader in the USB Mass Storage driver. - Also works for the Microtech Zio! CompactFlash/SmartMedia reader. - - If this driver is compiled as a module, it will be named ums-sddr09. - -config USB_STORAGE_SDDR55 - tristate "SanDisk SDDR-55 SmartMedia support" - depends on USB_STORAGE - help - Say Y here to include additional code to support the Sandisk SDDR-55 - SmartMedia reader in the USB Mass Storage driver. - - If this driver is compiled as a module, it will be named ums-sddr55. - -config USB_STORAGE_JUMPSHOT - tristate "Lexar Jumpshot Compact Flash Reader" - depends on USB_STORAGE - help - Say Y here to include additional code to support the Lexar Jumpshot - USB CompactFlash reader. - - If this driver is compiled as a module, it will be named ums-jumpshot. - -config USB_STORAGE_ALAUDA - tristate "Olympus MAUSB-10/Fuji DPC-R1 support" - depends on USB_STORAGE - help - Say Y here to include additional code to support the Olympus MAUSB-10 - and Fujifilm DPC-R1 USB Card reader/writer devices. - - These devices are based on the Alauda chip and support both - XD and SmartMedia cards. - - If this driver is compiled as a module, it will be named ums-alauda. - -config USB_STORAGE_ONETOUCH - tristate "Support OneTouch Button on Maxtor Hard Drives" - depends on USB_STORAGE - depends on INPUT=y || INPUT=USB_STORAGE - help - Say Y here to include additional code to support the Maxtor OneTouch - USB hard drive's onetouch button. - - This code registers the button on the front of Maxtor OneTouch USB - hard drive's as an input device. An action can be associated with - this input in any keybinding software. (e.g. gnome's keyboard short- - cuts) - - If this driver is compiled as a module, it will be named ums-onetouch. - -config USB_STORAGE_KARMA - tristate "Support for Rio Karma music player" - depends on USB_STORAGE - help - Say Y here to include additional code to support the Rio Karma - USB interface. - - This code places the Rio Karma into mass storage mode, enabling - it to be mounted as an ordinary filesystem. Performing an eject - on the resulting scsi device node returns the Karma to normal - operation. - - If this driver is compiled as a module, it will be named ums-karma. - -config USB_STORAGE_CYPRESS_ATACB - tristate "SAT emulation on Cypress USB/ATA Bridge with ATACB" - depends on USB_STORAGE - ---help--- - Say Y here if you want to use SAT (ata pass through) on devices based - on the Cypress USB/ATA bridge supporting ATACB. This will allow you - to use tools to tune and monitor your drive (like hdparm or smartctl). - - If you say no here your device will still work with the standard usb - mass storage class. - - If this driver is compiled as a module, it will be named ums-cypress. - -config USB_STORAGE_ENE_UB6250 - tristate "USB ENE card reader support" - depends on USB && SCSI - depends on USB_STORAGE - ---help--- - Say Y here if you wish to control a ENE SD/MS Card reader. - To use SM card, please build driver/staging/keucr/keucr.ko - - This option depends on 'SCSI' support being enabled, but you - probably also need 'SCSI device support: SCSI disk support' - (BLK_DEV_SD) for most USB storage devices. - - To compile this driver as a module, choose M here: the - module will be called ums-eneub6250. - -config USB_UAS - tristate "USB Attached SCSI" - depends on USB && SCSI - help - The USB Attached SCSI protocol is supported by some USB - storage devices. It permits higher performance by supporting - multiple outstanding commands. - - If you don't know whether you have a UAS device, it is safe to - say 'Y' or 'M' here and the kernel will use the right driver. - - If you compile this driver as a module, it will be named uas. - -config USB_LIBUSUAL - bool "The shared table of common (or usual) storage devices" - depends on USB - help - This module contains a table of common (or usual) devices - for usb-storage and ub drivers, and allows to switch binding - of these devices without rebuilding modules. - - Typical syntax of /etc/modprobe.d/*conf is: - - options libusual bias="ub" - - If unsure, say N. diff --git a/ANDROID_3.4.5/drivers/usb/storage/Makefile b/ANDROID_3.4.5/drivers/usb/storage/Makefile deleted file mode 100644 index 82e6416a..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/Makefile +++ /dev/null @@ -1,51 +0,0 @@ -# -# Makefile for the USB Mass Storage device drivers. -# -# 15 Aug 2000, Christoph Hellwig -# Rewritten to use lists instead of if-statements. -# - -ccflags-y := -Idrivers/scsi - -obj-$(CONFIG_USB_UAS) += uas.o -obj-$(CONFIG_USB_STORAGE) += usb-storage.o - -usb-storage-y := scsiglue.o protocol.o transport.o usb.o -usb-storage-y += initializers.o sierra_ms.o option_ms.o - -usb-storage-$(CONFIG_USB_STORAGE_DEBUG) += debug.o - -ifeq ($(CONFIG_USB_LIBUSUAL),) - usb-storage-y += usual-tables.o -else - obj-$(CONFIG_USB) += usb-libusual.o - usb-libusual-y := libusual.o usual-tables.o -endif - -obj-$(CONFIG_USB_STORAGE_ALAUDA) += ums-alauda.o -obj-$(CONFIG_USB_STORAGE_CYPRESS_ATACB) += ums-cypress.o -obj-$(CONFIG_USB_STORAGE_DATAFAB) += ums-datafab.o -obj-$(CONFIG_USB_STORAGE_ENE_UB6250) += ums-eneub6250.o -obj-$(CONFIG_USB_STORAGE_FREECOM) += ums-freecom.o -obj-$(CONFIG_USB_STORAGE_ISD200) += ums-isd200.o -obj-$(CONFIG_USB_STORAGE_JUMPSHOT) += ums-jumpshot.o -obj-$(CONFIG_USB_STORAGE_KARMA) += ums-karma.o -obj-$(CONFIG_USB_STORAGE_ONETOUCH) += ums-onetouch.o -obj-$(CONFIG_USB_STORAGE_REALTEK) += ums-realtek.o -obj-$(CONFIG_USB_STORAGE_SDDR09) += ums-sddr09.o -obj-$(CONFIG_USB_STORAGE_SDDR55) += ums-sddr55.o -obj-$(CONFIG_USB_STORAGE_USBAT) += ums-usbat.o - -ums-alauda-y := alauda.o -ums-cypress-y := cypress_atacb.o -ums-datafab-y := datafab.o -ums-eneub6250-y := ene_ub6250.o -ums-freecom-y := freecom.o -ums-isd200-y := isd200.o -ums-jumpshot-y := jumpshot.o -ums-karma-y := karma.o -ums-onetouch-y := onetouch.o -ums-realtek-y := realtek_cr.o -ums-sddr09-y := sddr09.o -ums-sddr55-y := sddr55.o -ums-usbat-y := shuttle_usbat.o diff --git a/ANDROID_3.4.5/drivers/usb/storage/alauda.c b/ANDROID_3.4.5/drivers/usb/storage/alauda.c deleted file mode 100644 index bab8c8fe..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/alauda.c +++ /dev/null @@ -1,1282 +0,0 @@ -/* - * Driver for Alauda-based card readers - * - * Current development and maintenance by: - * (c) 2005 Daniel Drake - * - * The 'Alauda' is a chip manufacturered by RATOC for OEM use. - * - * Alauda implements a vendor-specific command set to access two media reader - * ports (XD, SmartMedia). This driver converts SCSI commands to the commands - * which are accepted by these devices. - * - * The driver was developed through reverse-engineering, with the help of the - * sddr09 driver which has many similarities, and with some help from the - * (very old) vendor-supplied GPL sma03 driver. - * - * For protocol info, see http://alauda.sourceforge.net - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include - -#include -#include -#include - -#include "usb.h" -#include "transport.h" -#include "protocol.h" -#include "debug.h" - -MODULE_DESCRIPTION("Driver for Alauda-based card readers"); -MODULE_AUTHOR("Daniel Drake "); -MODULE_LICENSE("GPL"); - -/* - * Status bytes - */ -#define ALAUDA_STATUS_ERROR 0x01 -#define ALAUDA_STATUS_READY 0x40 - -/* - * Control opcodes (for request field) - */ -#define ALAUDA_GET_XD_MEDIA_STATUS 0x08 -#define ALAUDA_GET_SM_MEDIA_STATUS 0x98 -#define ALAUDA_ACK_XD_MEDIA_CHANGE 0x0a -#define ALAUDA_ACK_SM_MEDIA_CHANGE 0x9a -#define ALAUDA_GET_XD_MEDIA_SIG 0x86 -#define ALAUDA_GET_SM_MEDIA_SIG 0x96 - -/* - * Bulk command identity (byte 0) - */ -#define ALAUDA_BULK_CMD 0x40 - -/* - * Bulk opcodes (byte 1) - */ -#define ALAUDA_BULK_GET_REDU_DATA 0x85 -#define ALAUDA_BULK_READ_BLOCK 0x94 -#define ALAUDA_BULK_ERASE_BLOCK 0xa3 -#define ALAUDA_BULK_WRITE_BLOCK 0xb4 -#define ALAUDA_BULK_GET_STATUS2 0xb7 -#define ALAUDA_BULK_RESET_MEDIA 0xe0 - -/* - * Port to operate on (byte 8) - */ -#define ALAUDA_PORT_XD 0x00 -#define ALAUDA_PORT_SM 0x01 - -/* - * LBA and PBA are unsigned ints. Special values. - */ -#define UNDEF 0xffff -#define SPARE 0xfffe -#define UNUSABLE 0xfffd - -struct alauda_media_info { - unsigned long capacity; /* total media size in bytes */ - unsigned int pagesize; /* page size in bytes */ - unsigned int blocksize; /* number of pages per block */ - unsigned int uzonesize; /* number of usable blocks per zone */ - unsigned int zonesize; /* number of blocks per zone */ - unsigned int blockmask; /* mask to get page from address */ - - unsigned char pageshift; - unsigned char blockshift; - unsigned char zoneshift; - - u16 **lba_to_pba; /* logical to physical block map */ - u16 **pba_to_lba; /* physical to logical block map */ -}; - -struct alauda_info { - struct alauda_media_info port[2]; - int wr_ep; /* endpoint to write data out of */ - - unsigned char sense_key; - unsigned long sense_asc; /* additional sense code */ - unsigned long sense_ascq; /* additional sense code qualifier */ -}; - -#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) ) -#define LSB_of(s) ((s)&0xFF) -#define MSB_of(s) ((s)>>8) - -#define MEDIA_PORT(us) us->srb->device->lun -#define MEDIA_INFO(us) ((struct alauda_info *)us->extra)->port[MEDIA_PORT(us)] - -#define PBA_LO(pba) ((pba & 0xF) << 5) -#define PBA_HI(pba) (pba >> 3) -#define PBA_ZONE(pba) (pba >> 11) - -static int init_alauda(struct us_data *us); - - -/* - * The table of devices - */ -#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ - vendorName, productName, useProtocol, useTransport, \ - initFunction, flags) \ -{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } - -static struct usb_device_id alauda_usb_ids[] = { -# include "unusual_alauda.h" - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, alauda_usb_ids); - -#undef UNUSUAL_DEV - -/* - * The flags table - */ -#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ - vendor_name, product_name, use_protocol, use_transport, \ - init_function, Flags) \ -{ \ - .vendorName = vendor_name, \ - .productName = product_name, \ - .useProtocol = use_protocol, \ - .useTransport = use_transport, \ - .initFunction = init_function, \ -} - -static struct us_unusual_dev alauda_unusual_dev_list[] = { -# include "unusual_alauda.h" - { } /* Terminating entry */ -}; - -#undef UNUSUAL_DEV - - -/* - * Media handling - */ - -struct alauda_card_info { - unsigned char id; /* id byte */ - unsigned char chipshift; /* 1< LBA mappings for a particular port - */ -static void alauda_free_maps (struct alauda_media_info *media_info) -{ - unsigned int shift = media_info->zoneshift - + media_info->blockshift + media_info->pageshift; - unsigned int num_zones = media_info->capacity >> shift; - unsigned int i; - - if (media_info->lba_to_pba != NULL) - for (i = 0; i < num_zones; i++) { - kfree(media_info->lba_to_pba[i]); - media_info->lba_to_pba[i] = NULL; - } - - if (media_info->pba_to_lba != NULL) - for (i = 0; i < num_zones; i++) { - kfree(media_info->pba_to_lba[i]); - media_info->pba_to_lba[i] = NULL; - } -} - -/* - * Returns 2 bytes of status data - * The first byte describes media status, and second byte describes door status - */ -static int alauda_get_media_status(struct us_data *us, unsigned char *data) -{ - int rc; - unsigned char command; - - if (MEDIA_PORT(us) == ALAUDA_PORT_XD) - command = ALAUDA_GET_XD_MEDIA_STATUS; - else - command = ALAUDA_GET_SM_MEDIA_STATUS; - - rc = usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe, - command, 0xc0, 0, 1, data, 2); - - US_DEBUGP("alauda_get_media_status: Media status %02X %02X\n", - data[0], data[1]); - - return rc; -} - -/* - * Clears the "media was changed" bit so that we know when it changes again - * in the future. - */ -static int alauda_ack_media(struct us_data *us) -{ - unsigned char command; - - if (MEDIA_PORT(us) == ALAUDA_PORT_XD) - command = ALAUDA_ACK_XD_MEDIA_CHANGE; - else - command = ALAUDA_ACK_SM_MEDIA_CHANGE; - - return usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, - command, 0x40, 0, 1, NULL, 0); -} - -/* - * Retrieves a 4-byte media signature, which indicates manufacturer, capacity, - * and some other details. - */ -static int alauda_get_media_signature(struct us_data *us, unsigned char *data) -{ - unsigned char command; - - if (MEDIA_PORT(us) == ALAUDA_PORT_XD) - command = ALAUDA_GET_XD_MEDIA_SIG; - else - command = ALAUDA_GET_SM_MEDIA_SIG; - - return usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe, - command, 0xc0, 0, 0, data, 4); -} - -/* - * Resets the media status (but not the whole device?) - */ -static int alauda_reset_media(struct us_data *us) -{ - unsigned char *command = us->iobuf; - - memset(command, 0, 9); - command[0] = ALAUDA_BULK_CMD; - command[1] = ALAUDA_BULK_RESET_MEDIA; - command[8] = MEDIA_PORT(us); - - return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, - command, 9, NULL); -} - -/* - * Examines the media and deduces capacity, etc. - */ -static int alauda_init_media(struct us_data *us) -{ - unsigned char *data = us->iobuf; - int ready = 0; - struct alauda_card_info *media_info; - unsigned int num_zones; - - while (ready == 0) { - msleep(20); - - if (alauda_get_media_status(us, data) != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - if (data[0] & 0x10) - ready = 1; - } - - US_DEBUGP("alauda_init_media: We are ready for action!\n"); - - if (alauda_ack_media(us) != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - msleep(10); - - if (alauda_get_media_status(us, data) != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - if (data[0] != 0x14) { - US_DEBUGP("alauda_init_media: Media not ready after ack\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - if (alauda_get_media_signature(us, data) != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - US_DEBUGP("alauda_init_media: Media signature: %02X %02X %02X %02X\n", - data[0], data[1], data[2], data[3]); - media_info = alauda_card_find_id(data[1]); - if (media_info == NULL) { - printk(KERN_WARNING - "alauda_init_media: Unrecognised media signature: " - "%02X %02X %02X %02X\n", - data[0], data[1], data[2], data[3]); - return USB_STOR_TRANSPORT_ERROR; - } - - MEDIA_INFO(us).capacity = 1 << media_info->chipshift; - US_DEBUGP("Found media with capacity: %ldMB\n", - MEDIA_INFO(us).capacity >> 20); - - MEDIA_INFO(us).pageshift = media_info->pageshift; - MEDIA_INFO(us).blockshift = media_info->blockshift; - MEDIA_INFO(us).zoneshift = media_info->zoneshift; - - MEDIA_INFO(us).pagesize = 1 << media_info->pageshift; - MEDIA_INFO(us).blocksize = 1 << media_info->blockshift; - MEDIA_INFO(us).zonesize = 1 << media_info->zoneshift; - - MEDIA_INFO(us).uzonesize = ((1 << media_info->zoneshift) / 128) * 125; - MEDIA_INFO(us).blockmask = MEDIA_INFO(us).blocksize - 1; - - num_zones = MEDIA_INFO(us).capacity >> (MEDIA_INFO(us).zoneshift - + MEDIA_INFO(us).blockshift + MEDIA_INFO(us).pageshift); - MEDIA_INFO(us).pba_to_lba = kcalloc(num_zones, sizeof(u16*), GFP_NOIO); - MEDIA_INFO(us).lba_to_pba = kcalloc(num_zones, sizeof(u16*), GFP_NOIO); - - if (alauda_reset_media(us) != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - return USB_STOR_TRANSPORT_GOOD; -} - -/* - * Examines the media status and does the right thing when the media has gone, - * appeared, or changed. - */ -static int alauda_check_media(struct us_data *us) -{ - struct alauda_info *info = (struct alauda_info *) us->extra; - unsigned char status[2]; - int rc; - - rc = alauda_get_media_status(us, status); - - /* Check for no media or door open */ - if ((status[0] & 0x80) || ((status[0] & 0x1F) == 0x10) - || ((status[1] & 0x01) == 0)) { - US_DEBUGP("alauda_check_media: No media, or door open\n"); - alauda_free_maps(&MEDIA_INFO(us)); - info->sense_key = 0x02; - info->sense_asc = 0x3A; - info->sense_ascq = 0x00; - return USB_STOR_TRANSPORT_FAILED; - } - - /* Check for media change */ - if (status[0] & 0x08) { - US_DEBUGP("alauda_check_media: Media change detected\n"); - alauda_free_maps(&MEDIA_INFO(us)); - alauda_init_media(us); - - info->sense_key = UNIT_ATTENTION; - info->sense_asc = 0x28; - info->sense_ascq = 0x00; - return USB_STOR_TRANSPORT_FAILED; - } - - return USB_STOR_TRANSPORT_GOOD; -} - -/* - * Checks the status from the 2nd status register - * Returns 3 bytes of status data, only the first is known - */ -static int alauda_check_status2(struct us_data *us) -{ - int rc; - unsigned char command[] = { - ALAUDA_BULK_CMD, ALAUDA_BULK_GET_STATUS2, - 0, 0, 0, 0, 3, 0, MEDIA_PORT(us) - }; - unsigned char data[3]; - - rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, - command, 9, NULL); - if (rc != USB_STOR_XFER_GOOD) - return rc; - - rc = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, - data, 3, NULL); - if (rc != USB_STOR_XFER_GOOD) - return rc; - - US_DEBUGP("alauda_check_status2: %02X %02X %02X\n", data[0], data[1], data[2]); - if (data[0] & ALAUDA_STATUS_ERROR) - return USB_STOR_XFER_ERROR; - - return USB_STOR_XFER_GOOD; -} - -/* - * Gets the redundancy data for the first page of a PBA - * Returns 16 bytes. - */ -static int alauda_get_redu_data(struct us_data *us, u16 pba, unsigned char *data) -{ - int rc; - unsigned char command[] = { - ALAUDA_BULK_CMD, ALAUDA_BULK_GET_REDU_DATA, - PBA_HI(pba), PBA_ZONE(pba), 0, PBA_LO(pba), 0, 0, MEDIA_PORT(us) - }; - - rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, - command, 9, NULL); - if (rc != USB_STOR_XFER_GOOD) - return rc; - - return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, - data, 16, NULL); -} - -/* - * Finds the first unused PBA in a zone - * Returns the absolute PBA of an unused PBA, or 0 if none found. - */ -static u16 alauda_find_unused_pba(struct alauda_media_info *info, - unsigned int zone) -{ - u16 *pba_to_lba = info->pba_to_lba[zone]; - unsigned int i; - - for (i = 0; i < info->zonesize; i++) - if (pba_to_lba[i] == UNDEF) - return (zone << info->zoneshift) + i; - - return 0; -} - -/* - * Reads the redundancy data for all PBA's in a zone - * Produces lba <--> pba mappings - */ -static int alauda_read_map(struct us_data *us, unsigned int zone) -{ - unsigned char *data = us->iobuf; - int result; - int i, j; - unsigned int zonesize = MEDIA_INFO(us).zonesize; - unsigned int uzonesize = MEDIA_INFO(us).uzonesize; - unsigned int lba_offset, lba_real, blocknum; - unsigned int zone_base_lba = zone * uzonesize; - unsigned int zone_base_pba = zone * zonesize; - u16 *lba_to_pba = kcalloc(zonesize, sizeof(u16), GFP_NOIO); - u16 *pba_to_lba = kcalloc(zonesize, sizeof(u16), GFP_NOIO); - if (lba_to_pba == NULL || pba_to_lba == NULL) { - result = USB_STOR_TRANSPORT_ERROR; - goto error; - } - - US_DEBUGP("alauda_read_map: Mapping blocks for zone %d\n", zone); - - /* 1024 PBA's per zone */ - for (i = 0; i < zonesize; i++) - lba_to_pba[i] = pba_to_lba[i] = UNDEF; - - for (i = 0; i < zonesize; i++) { - blocknum = zone_base_pba + i; - - result = alauda_get_redu_data(us, blocknum, data); - if (result != USB_STOR_XFER_GOOD) { - result = USB_STOR_TRANSPORT_ERROR; - goto error; - } - - /* special PBAs have control field 0^16 */ - for (j = 0; j < 16; j++) - if (data[j] != 0) - goto nonz; - pba_to_lba[i] = UNUSABLE; - US_DEBUGP("alauda_read_map: PBA %d has no logical mapping\n", blocknum); - continue; - - nonz: - /* unwritten PBAs have control field FF^16 */ - for (j = 0; j < 16; j++) - if (data[j] != 0xff) - goto nonff; - continue; - - nonff: - /* normal PBAs start with six FFs */ - if (j < 6) { - US_DEBUGP("alauda_read_map: PBA %d has no logical mapping: " - "reserved area = %02X%02X%02X%02X " - "data status %02X block status %02X\n", - blocknum, data[0], data[1], data[2], data[3], - data[4], data[5]); - pba_to_lba[i] = UNUSABLE; - continue; - } - - if ((data[6] >> 4) != 0x01) { - US_DEBUGP("alauda_read_map: PBA %d has invalid address " - "field %02X%02X/%02X%02X\n", - blocknum, data[6], data[7], data[11], data[12]); - pba_to_lba[i] = UNUSABLE; - continue; - } - - /* check even parity */ - if (parity[data[6] ^ data[7]]) { - printk(KERN_WARNING - "alauda_read_map: Bad parity in LBA for block %d" - " (%02X %02X)\n", i, data[6], data[7]); - pba_to_lba[i] = UNUSABLE; - continue; - } - - lba_offset = short_pack(data[7], data[6]); - lba_offset = (lba_offset & 0x07FF) >> 1; - lba_real = lba_offset + zone_base_lba; - - /* - * Every 1024 physical blocks ("zone"), the LBA numbers - * go back to zero, but are within a higher block of LBA's. - * Also, there is a maximum of 1000 LBA's per zone. - * In other words, in PBA 1024-2047 you will find LBA 0-999 - * which are really LBA 1000-1999. This allows for 24 bad - * or special physical blocks per zone. - */ - - if (lba_offset >= uzonesize) { - printk(KERN_WARNING - "alauda_read_map: Bad low LBA %d for block %d\n", - lba_real, blocknum); - continue; - } - - if (lba_to_pba[lba_offset] != UNDEF) { - printk(KERN_WARNING - "alauda_read_map: " - "LBA %d seen for PBA %d and %d\n", - lba_real, lba_to_pba[lba_offset], blocknum); - continue; - } - - pba_to_lba[i] = lba_real; - lba_to_pba[lba_offset] = blocknum; - continue; - } - - MEDIA_INFO(us).lba_to_pba[zone] = lba_to_pba; - MEDIA_INFO(us).pba_to_lba[zone] = pba_to_lba; - result = 0; - goto out; - -error: - kfree(lba_to_pba); - kfree(pba_to_lba); -out: - return result; -} - -/* - * Checks to see whether we have already mapped a certain zone - * If we haven't, the map is generated - */ -static void alauda_ensure_map_for_zone(struct us_data *us, unsigned int zone) -{ - if (MEDIA_INFO(us).lba_to_pba[zone] == NULL - || MEDIA_INFO(us).pba_to_lba[zone] == NULL) - alauda_read_map(us, zone); -} - -/* - * Erases an entire block - */ -static int alauda_erase_block(struct us_data *us, u16 pba) -{ - int rc; - unsigned char command[] = { - ALAUDA_BULK_CMD, ALAUDA_BULK_ERASE_BLOCK, PBA_HI(pba), - PBA_ZONE(pba), 0, PBA_LO(pba), 0x02, 0, MEDIA_PORT(us) - }; - unsigned char buf[2]; - - US_DEBUGP("alauda_erase_block: Erasing PBA %d\n", pba); - - rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, - command, 9, NULL); - if (rc != USB_STOR_XFER_GOOD) - return rc; - - rc = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, - buf, 2, NULL); - if (rc != USB_STOR_XFER_GOOD) - return rc; - - US_DEBUGP("alauda_erase_block: Erase result: %02X %02X\n", - buf[0], buf[1]); - return rc; -} - -/* - * Reads data from a certain offset page inside a PBA, including interleaved - * redundancy data. Returns (pagesize+64)*pages bytes in data. - */ -static int alauda_read_block_raw(struct us_data *us, u16 pba, - unsigned int page, unsigned int pages, unsigned char *data) -{ - int rc; - unsigned char command[] = { - ALAUDA_BULK_CMD, ALAUDA_BULK_READ_BLOCK, PBA_HI(pba), - PBA_ZONE(pba), 0, PBA_LO(pba) + page, pages, 0, MEDIA_PORT(us) - }; - - US_DEBUGP("alauda_read_block: pba %d page %d count %d\n", - pba, page, pages); - - rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, - command, 9, NULL); - if (rc != USB_STOR_XFER_GOOD) - return rc; - - return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, - data, (MEDIA_INFO(us).pagesize + 64) * pages, NULL); -} - -/* - * Reads data from a certain offset page inside a PBA, excluding redundancy - * data. Returns pagesize*pages bytes in data. Note that data must be big enough - * to hold (pagesize+64)*pages bytes of data, but you can ignore those 'extra' - * trailing bytes outside this function. - */ -static int alauda_read_block(struct us_data *us, u16 pba, - unsigned int page, unsigned int pages, unsigned char *data) -{ - int i, rc; - unsigned int pagesize = MEDIA_INFO(us).pagesize; - - rc = alauda_read_block_raw(us, pba, page, pages, data); - if (rc != USB_STOR_XFER_GOOD) - return rc; - - /* Cut out the redundancy data */ - for (i = 0; i < pages; i++) { - int dest_offset = i * pagesize; - int src_offset = i * (pagesize + 64); - memmove(data + dest_offset, data + src_offset, pagesize); - } - - return rc; -} - -/* - * Writes an entire block of data and checks status after write. - * Redundancy data must be already included in data. Data should be - * (pagesize+64)*blocksize bytes in length. - */ -static int alauda_write_block(struct us_data *us, u16 pba, unsigned char *data) -{ - int rc; - struct alauda_info *info = (struct alauda_info *) us->extra; - unsigned char command[] = { - ALAUDA_BULK_CMD, ALAUDA_BULK_WRITE_BLOCK, PBA_HI(pba), - PBA_ZONE(pba), 0, PBA_LO(pba), 32, 0, MEDIA_PORT(us) - }; - - US_DEBUGP("alauda_write_block: pba %d\n", pba); - - rc = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, - command, 9, NULL); - if (rc != USB_STOR_XFER_GOOD) - return rc; - - rc = usb_stor_bulk_transfer_buf(us, info->wr_ep, data, - (MEDIA_INFO(us).pagesize + 64) * MEDIA_INFO(us).blocksize, - NULL); - if (rc != USB_STOR_XFER_GOOD) - return rc; - - return alauda_check_status2(us); -} - -/* - * Write some data to a specific LBA. - */ -static int alauda_write_lba(struct us_data *us, u16 lba, - unsigned int page, unsigned int pages, - unsigned char *ptr, unsigned char *blockbuffer) -{ - u16 pba, lbap, new_pba; - unsigned char *bptr, *cptr, *xptr; - unsigned char ecc[3]; - int i, result; - unsigned int uzonesize = MEDIA_INFO(us).uzonesize; - unsigned int zonesize = MEDIA_INFO(us).zonesize; - unsigned int pagesize = MEDIA_INFO(us).pagesize; - unsigned int blocksize = MEDIA_INFO(us).blocksize; - unsigned int lba_offset = lba % uzonesize; - unsigned int new_pba_offset; - unsigned int zone = lba / uzonesize; - - alauda_ensure_map_for_zone(us, zone); - - pba = MEDIA_INFO(us).lba_to_pba[zone][lba_offset]; - if (pba == 1) { - /* Maybe it is impossible to write to PBA 1. - Fake success, but don't do anything. */ - printk(KERN_WARNING - "alauda_write_lba: avoid writing to pba 1\n"); - return USB_STOR_TRANSPORT_GOOD; - } - - new_pba = alauda_find_unused_pba(&MEDIA_INFO(us), zone); - if (!new_pba) { - printk(KERN_WARNING - "alauda_write_lba: Out of unused blocks\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - /* read old contents */ - if (pba != UNDEF) { - result = alauda_read_block_raw(us, pba, 0, - blocksize, blockbuffer); - if (result != USB_STOR_XFER_GOOD) - return result; - } else { - memset(blockbuffer, 0, blocksize * (pagesize + 64)); - } - - lbap = (lba_offset << 1) | 0x1000; - if (parity[MSB_of(lbap) ^ LSB_of(lbap)]) - lbap ^= 1; - - /* check old contents and fill lba */ - for (i = 0; i < blocksize; i++) { - bptr = blockbuffer + (i * (pagesize + 64)); - cptr = bptr + pagesize; - nand_compute_ecc(bptr, ecc); - if (!nand_compare_ecc(cptr+13, ecc)) { - US_DEBUGP("Warning: bad ecc in page %d- of pba %d\n", - i, pba); - nand_store_ecc(cptr+13, ecc); - } - nand_compute_ecc(bptr + (pagesize / 2), ecc); - if (!nand_compare_ecc(cptr+8, ecc)) { - US_DEBUGP("Warning: bad ecc in page %d+ of pba %d\n", - i, pba); - nand_store_ecc(cptr+8, ecc); - } - cptr[6] = cptr[11] = MSB_of(lbap); - cptr[7] = cptr[12] = LSB_of(lbap); - } - - /* copy in new stuff and compute ECC */ - xptr = ptr; - for (i = page; i < page+pages; i++) { - bptr = blockbuffer + (i * (pagesize + 64)); - cptr = bptr + pagesize; - memcpy(bptr, xptr, pagesize); - xptr += pagesize; - nand_compute_ecc(bptr, ecc); - nand_store_ecc(cptr+13, ecc); - nand_compute_ecc(bptr + (pagesize / 2), ecc); - nand_store_ecc(cptr+8, ecc); - } - - result = alauda_write_block(us, new_pba, blockbuffer); - if (result != USB_STOR_XFER_GOOD) - return result; - - new_pba_offset = new_pba - (zone * zonesize); - MEDIA_INFO(us).pba_to_lba[zone][new_pba_offset] = lba; - MEDIA_INFO(us).lba_to_pba[zone][lba_offset] = new_pba; - US_DEBUGP("alauda_write_lba: Remapped LBA %d to PBA %d\n", - lba, new_pba); - - if (pba != UNDEF) { - unsigned int pba_offset = pba - (zone * zonesize); - result = alauda_erase_block(us, pba); - if (result != USB_STOR_XFER_GOOD) - return result; - MEDIA_INFO(us).pba_to_lba[zone][pba_offset] = UNDEF; - } - - return USB_STOR_TRANSPORT_GOOD; -} - -/* - * Read data from a specific sector address - */ -static int alauda_read_data(struct us_data *us, unsigned long address, - unsigned int sectors) -{ - unsigned char *buffer; - u16 lba, max_lba; - unsigned int page, len, offset; - unsigned int blockshift = MEDIA_INFO(us).blockshift; - unsigned int pageshift = MEDIA_INFO(us).pageshift; - unsigned int blocksize = MEDIA_INFO(us).blocksize; - unsigned int pagesize = MEDIA_INFO(us).pagesize; - unsigned int uzonesize = MEDIA_INFO(us).uzonesize; - struct scatterlist *sg; - int result; - - /* - * Since we only read in one block at a time, we have to create - * a bounce buffer and move the data a piece at a time between the - * bounce buffer and the actual transfer buffer. - * We make this buffer big enough to hold temporary redundancy data, - * which we use when reading the data blocks. - */ - - len = min(sectors, blocksize) * (pagesize + 64); - buffer = kmalloc(len, GFP_NOIO); - if (buffer == NULL) { - printk(KERN_WARNING "alauda_read_data: Out of memory\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - /* Figure out the initial LBA and page */ - lba = address >> blockshift; - page = (address & MEDIA_INFO(us).blockmask); - max_lba = MEDIA_INFO(us).capacity >> (blockshift + pageshift); - - result = USB_STOR_TRANSPORT_GOOD; - offset = 0; - sg = NULL; - - while (sectors > 0) { - unsigned int zone = lba / uzonesize; /* integer division */ - unsigned int lba_offset = lba - (zone * uzonesize); - unsigned int pages; - u16 pba; - alauda_ensure_map_for_zone(us, zone); - - /* Not overflowing capacity? */ - if (lba >= max_lba) { - US_DEBUGP("Error: Requested lba %u exceeds " - "maximum %u\n", lba, max_lba); - result = USB_STOR_TRANSPORT_ERROR; - break; - } - - /* Find number of pages we can read in this block */ - pages = min(sectors, blocksize - page); - len = pages << pageshift; - - /* Find where this lba lives on disk */ - pba = MEDIA_INFO(us).lba_to_pba[zone][lba_offset]; - - if (pba == UNDEF) { /* this lba was never written */ - US_DEBUGP("Read %d zero pages (LBA %d) page %d\n", - pages, lba, page); - - /* This is not really an error. It just means - that the block has never been written. - Instead of returning USB_STOR_TRANSPORT_ERROR - it is better to return all zero data. */ - - memset(buffer, 0, len); - } else { - US_DEBUGP("Read %d pages, from PBA %d" - " (LBA %d) page %d\n", - pages, pba, lba, page); - - result = alauda_read_block(us, pba, page, pages, buffer); - if (result != USB_STOR_TRANSPORT_GOOD) - break; - } - - /* Store the data in the transfer buffer */ - usb_stor_access_xfer_buf(buffer, len, us->srb, - &sg, &offset, TO_XFER_BUF); - - page = 0; - lba++; - sectors -= pages; - } - - kfree(buffer); - return result; -} - -/* - * Write data to a specific sector address - */ -static int alauda_write_data(struct us_data *us, unsigned long address, - unsigned int sectors) -{ - unsigned char *buffer, *blockbuffer; - unsigned int page, len, offset; - unsigned int blockshift = MEDIA_INFO(us).blockshift; - unsigned int pageshift = MEDIA_INFO(us).pageshift; - unsigned int blocksize = MEDIA_INFO(us).blocksize; - unsigned int pagesize = MEDIA_INFO(us).pagesize; - struct scatterlist *sg; - u16 lba, max_lba; - int result; - - /* - * Since we don't write the user data directly to the device, - * we have to create a bounce buffer and move the data a piece - * at a time between the bounce buffer and the actual transfer buffer. - */ - - len = min(sectors, blocksize) * pagesize; - buffer = kmalloc(len, GFP_NOIO); - if (buffer == NULL) { - printk(KERN_WARNING "alauda_write_data: Out of memory\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - /* - * We also need a temporary block buffer, where we read in the old data, - * overwrite parts with the new data, and manipulate the redundancy data - */ - blockbuffer = kmalloc((pagesize + 64) * blocksize, GFP_NOIO); - if (blockbuffer == NULL) { - printk(KERN_WARNING "alauda_write_data: Out of memory\n"); - kfree(buffer); - return USB_STOR_TRANSPORT_ERROR; - } - - /* Figure out the initial LBA and page */ - lba = address >> blockshift; - page = (address & MEDIA_INFO(us).blockmask); - max_lba = MEDIA_INFO(us).capacity >> (pageshift + blockshift); - - result = USB_STOR_TRANSPORT_GOOD; - offset = 0; - sg = NULL; - - while (sectors > 0) { - /* Write as many sectors as possible in this block */ - unsigned int pages = min(sectors, blocksize - page); - len = pages << pageshift; - - /* Not overflowing capacity? */ - if (lba >= max_lba) { - US_DEBUGP("alauda_write_data: Requested lba %u exceeds " - "maximum %u\n", lba, max_lba); - result = USB_STOR_TRANSPORT_ERROR; - break; - } - - /* Get the data from the transfer buffer */ - usb_stor_access_xfer_buf(buffer, len, us->srb, - &sg, &offset, FROM_XFER_BUF); - - result = alauda_write_lba(us, lba, page, pages, buffer, - blockbuffer); - if (result != USB_STOR_TRANSPORT_GOOD) - break; - - page = 0; - lba++; - sectors -= pages; - } - - kfree(buffer); - kfree(blockbuffer); - return result; -} - -/* - * Our interface with the rest of the world - */ - -static void alauda_info_destructor(void *extra) -{ - struct alauda_info *info = (struct alauda_info *) extra; - int port; - - if (!info) - return; - - for (port = 0; port < 2; port++) { - struct alauda_media_info *media_info = &info->port[port]; - - alauda_free_maps(media_info); - kfree(media_info->lba_to_pba); - kfree(media_info->pba_to_lba); - } -} - -/* - * Initialize alauda_info struct and find the data-write endpoint - */ -static int init_alauda(struct us_data *us) -{ - struct alauda_info *info; - struct usb_host_interface *altsetting = us->pusb_intf->cur_altsetting; - nand_init_ecc(); - - us->extra = kzalloc(sizeof(struct alauda_info), GFP_NOIO); - if (!us->extra) { - US_DEBUGP("init_alauda: Gah! Can't allocate storage for" - "alauda info struct!\n"); - return USB_STOR_TRANSPORT_ERROR; - } - info = (struct alauda_info *) us->extra; - us->extra_destructor = alauda_info_destructor; - - info->wr_ep = usb_sndbulkpipe(us->pusb_dev, - altsetting->endpoint[0].desc.bEndpointAddress - & USB_ENDPOINT_NUMBER_MASK); - - return USB_STOR_TRANSPORT_GOOD; -} - -static int alauda_transport(struct scsi_cmnd *srb, struct us_data *us) -{ - int rc; - struct alauda_info *info = (struct alauda_info *) us->extra; - unsigned char *ptr = us->iobuf; - static unsigned char inquiry_response[36] = { - 0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00 - }; - - if (srb->cmnd[0] == INQUIRY) { - US_DEBUGP("alauda_transport: INQUIRY. " - "Returning bogus response.\n"); - memcpy(ptr, inquiry_response, sizeof(inquiry_response)); - fill_inquiry_response(us, ptr, 36); - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == TEST_UNIT_READY) { - US_DEBUGP("alauda_transport: TEST_UNIT_READY.\n"); - return alauda_check_media(us); - } - - if (srb->cmnd[0] == READ_CAPACITY) { - unsigned int num_zones; - unsigned long capacity; - - rc = alauda_check_media(us); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - - num_zones = MEDIA_INFO(us).capacity >> (MEDIA_INFO(us).zoneshift - + MEDIA_INFO(us).blockshift + MEDIA_INFO(us).pageshift); - - capacity = num_zones * MEDIA_INFO(us).uzonesize - * MEDIA_INFO(us).blocksize; - - /* Report capacity and page size */ - ((__be32 *) ptr)[0] = cpu_to_be32(capacity - 1); - ((__be32 *) ptr)[1] = cpu_to_be32(512); - - usb_stor_set_xfer_buf(ptr, 8, srb); - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == READ_10) { - unsigned int page, pages; - - rc = alauda_check_media(us); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - - page = short_pack(srb->cmnd[3], srb->cmnd[2]); - page <<= 16; - page |= short_pack(srb->cmnd[5], srb->cmnd[4]); - pages = short_pack(srb->cmnd[8], srb->cmnd[7]); - - US_DEBUGP("alauda_transport: READ_10: page %d pagect %d\n", - page, pages); - - return alauda_read_data(us, page, pages); - } - - if (srb->cmnd[0] == WRITE_10) { - unsigned int page, pages; - - rc = alauda_check_media(us); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - - page = short_pack(srb->cmnd[3], srb->cmnd[2]); - page <<= 16; - page |= short_pack(srb->cmnd[5], srb->cmnd[4]); - pages = short_pack(srb->cmnd[8], srb->cmnd[7]); - - US_DEBUGP("alauda_transport: WRITE_10: page %d pagect %d\n", - page, pages); - - return alauda_write_data(us, page, pages); - } - - if (srb->cmnd[0] == REQUEST_SENSE) { - US_DEBUGP("alauda_transport: REQUEST_SENSE.\n"); - - memset(ptr, 0, 18); - ptr[0] = 0xF0; - ptr[2] = info->sense_key; - ptr[7] = 11; - ptr[12] = info->sense_asc; - ptr[13] = info->sense_ascq; - usb_stor_set_xfer_buf(ptr, 18, srb); - - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { - /* sure. whatever. not like we can stop the user from popping - the media out of the device (no locking doors, etc) */ - return USB_STOR_TRANSPORT_GOOD; - } - - US_DEBUGP("alauda_transport: Gah! Unknown command: %d (0x%x)\n", - srb->cmnd[0], srb->cmnd[0]); - info->sense_key = 0x05; - info->sense_asc = 0x20; - info->sense_ascq = 0x00; - return USB_STOR_TRANSPORT_FAILED; -} - -static int alauda_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct us_data *us; - int result; - - result = usb_stor_probe1(&us, intf, id, - (id - alauda_usb_ids) + alauda_unusual_dev_list); - if (result) - return result; - - us->transport_name = "Alauda Control/Bulk"; - us->transport = alauda_transport; - us->transport_reset = usb_stor_Bulk_reset; - us->max_lun = 1; - - result = usb_stor_probe2(us); - return result; -} - -static struct usb_driver alauda_driver = { - .name = "ums-alauda", - .probe = alauda_probe, - .disconnect = usb_stor_disconnect, - .suspend = usb_stor_suspend, - .resume = usb_stor_resume, - .reset_resume = usb_stor_reset_resume, - .pre_reset = usb_stor_pre_reset, - .post_reset = usb_stor_post_reset, - .id_table = alauda_usb_ids, - .soft_unbind = 1, - .no_dynamic_id = 1, -}; - -module_usb_driver(alauda_driver); diff --git a/ANDROID_3.4.5/drivers/usb/storage/cypress_atacb.c b/ANDROID_3.4.5/drivers/usb/storage/cypress_atacb.c deleted file mode 100644 index 5fe451d1..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/cypress_atacb.c +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Support for emulating SAT (ata pass through) on devices based - * on the Cypress USB/ATA bridge supporting ATACB. - * - * Copyright (c) 2008 Matthieu Castet (castet.matthieu@free.fr) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include - -#include "usb.h" -#include "protocol.h" -#include "scsiglue.h" -#include "debug.h" - -MODULE_DESCRIPTION("SAT support for Cypress USB/ATA bridges with ATACB"); -MODULE_AUTHOR("Matthieu Castet "); -MODULE_LICENSE("GPL"); - -/* - * The table of devices - */ -#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ - vendorName, productName, useProtocol, useTransport, \ - initFunction, flags) \ -{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } - -static struct usb_device_id cypress_usb_ids[] = { -# include "unusual_cypress.h" - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, cypress_usb_ids); - -#undef UNUSUAL_DEV - -/* - * The flags table - */ -#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ - vendor_name, product_name, use_protocol, use_transport, \ - init_function, Flags) \ -{ \ - .vendorName = vendor_name, \ - .productName = product_name, \ - .useProtocol = use_protocol, \ - .useTransport = use_transport, \ - .initFunction = init_function, \ -} - -static struct us_unusual_dev cypress_unusual_dev_list[] = { -# include "unusual_cypress.h" - { } /* Terminating entry */ -}; - -#undef UNUSUAL_DEV - - -/* - * ATACB is a protocol used on cypress usb<->ata bridge to - * send raw ATA command over mass storage - * There is a ATACB2 protocol that support LBA48 on newer chip. - * More info that be found on cy7c68310_8.pdf and cy7c68300c_8.pdf - * datasheet from cypress.com. - */ -static void cypress_atacb_passthrough(struct scsi_cmnd *srb, struct us_data *us) -{ - unsigned char save_cmnd[MAX_COMMAND_SIZE]; - - if (likely(srb->cmnd[0] != ATA_16 && srb->cmnd[0] != ATA_12)) { - usb_stor_transparent_scsi_command(srb, us); - return; - } - - memcpy(save_cmnd, srb->cmnd, sizeof(save_cmnd)); - memset(srb->cmnd, 0, MAX_COMMAND_SIZE); - - /* check if we support the command */ - if (save_cmnd[1] >> 5) /* MULTIPLE_COUNT */ - goto invalid_fld; - /* check protocol */ - switch((save_cmnd[1] >> 1) & 0xf) { - case 3: /*no DATA */ - case 4: /* PIO in */ - case 5: /* PIO out */ - break; - default: - goto invalid_fld; - } - - /* first build the ATACB command */ - srb->cmd_len = 16; - - srb->cmnd[0] = 0x24; /* bVSCBSignature : vendor-specific command - this value can change, but most(all ?) manufacturers - keep the cypress default : 0x24 */ - srb->cmnd[1] = 0x24; /* bVSCBSubCommand : 0x24 for ATACB */ - - srb->cmnd[3] = 0xff - 1; /* features, sector count, lba low, lba med - lba high, device, command are valid */ - srb->cmnd[4] = 1; /* TransferBlockCount : 512 */ - - if (save_cmnd[0] == ATA_16) { - srb->cmnd[ 6] = save_cmnd[ 4]; /* features */ - srb->cmnd[ 7] = save_cmnd[ 6]; /* sector count */ - srb->cmnd[ 8] = save_cmnd[ 8]; /* lba low */ - srb->cmnd[ 9] = save_cmnd[10]; /* lba med */ - srb->cmnd[10] = save_cmnd[12]; /* lba high */ - srb->cmnd[11] = save_cmnd[13]; /* device */ - srb->cmnd[12] = save_cmnd[14]; /* command */ - - if (save_cmnd[1] & 0x01) {/* extended bit set for LBA48 */ - /* this could be supported by atacb2 */ - if (save_cmnd[3] || save_cmnd[5] || save_cmnd[7] || save_cmnd[9] - || save_cmnd[11]) - goto invalid_fld; - } - } - else { /* ATA12 */ - srb->cmnd[ 6] = save_cmnd[3]; /* features */ - srb->cmnd[ 7] = save_cmnd[4]; /* sector count */ - srb->cmnd[ 8] = save_cmnd[5]; /* lba low */ - srb->cmnd[ 9] = save_cmnd[6]; /* lba med */ - srb->cmnd[10] = save_cmnd[7]; /* lba high */ - srb->cmnd[11] = save_cmnd[8]; /* device */ - srb->cmnd[12] = save_cmnd[9]; /* command */ - - } - /* Filter SET_FEATURES - XFER MODE command */ - if ((srb->cmnd[12] == ATA_CMD_SET_FEATURES) - && (srb->cmnd[6] == SETFEATURES_XFER)) - goto invalid_fld; - - if (srb->cmnd[12] == ATA_CMD_ID_ATA || srb->cmnd[12] == ATA_CMD_ID_ATAPI) - srb->cmnd[2] |= (1<<7); /* set IdentifyPacketDevice for these cmds */ - - - usb_stor_transparent_scsi_command(srb, us); - - /* if the device doesn't support ATACB - */ - if (srb->result == SAM_STAT_CHECK_CONDITION && - memcmp(srb->sense_buffer, usb_stor_sense_invalidCDB, - sizeof(usb_stor_sense_invalidCDB)) == 0) { - US_DEBUGP("cypress atacb not supported ???\n"); - goto end; - } - - /* if ck_cond flags is set, and there wasn't critical error, - * build the special sense - */ - if ((srb->result != (DID_ERROR << 16) && - srb->result != (DID_ABORT << 16)) && - save_cmnd[2] & 0x20) { - struct scsi_eh_save ses; - unsigned char regs[8]; - unsigned char *sb = srb->sense_buffer; - unsigned char *desc = sb + 8; - int tmp_result; - - /* build the command for - * reading the ATA registers */ - scsi_eh_prep_cmnd(srb, &ses, NULL, 0, sizeof(regs)); - - /* we use the same command as before, but we set - * the read taskfile bit, for not executing atacb command, - * but reading register selected in srb->cmnd[4] - */ - srb->cmd_len = 16; - srb->cmnd = ses.cmnd; - srb->cmnd[2] = 1; - - usb_stor_transparent_scsi_command(srb, us); - memcpy(regs, srb->sense_buffer, sizeof(regs)); - tmp_result = srb->result; - scsi_eh_restore_cmnd(srb, &ses); - /* we fail to get registers, report invalid command */ - if (tmp_result != SAM_STAT_GOOD) - goto invalid_fld; - - /* build the sense */ - memset(sb, 0, SCSI_SENSE_BUFFERSIZE); - - /* set sk, asc for a good command */ - sb[1] = RECOVERED_ERROR; - sb[2] = 0; /* ATA PASS THROUGH INFORMATION AVAILABLE */ - sb[3] = 0x1D; - - /* XXX we should generate sk, asc, ascq from status and error - * regs - * (see 11.1 Error translation ATA device error to SCSI error - * map, and ata_to_sense_error from libata.) - */ - - /* Sense data is current and format is descriptor. */ - sb[0] = 0x72; - desc[0] = 0x09; /* ATA_RETURN_DESCRIPTOR */ - - /* set length of additional sense data */ - sb[7] = 14; - desc[1] = 12; - - /* Copy registers into sense buffer. */ - desc[ 2] = 0x00; - desc[ 3] = regs[1]; /* features */ - desc[ 5] = regs[2]; /* sector count */ - desc[ 7] = regs[3]; /* lba low */ - desc[ 9] = regs[4]; /* lba med */ - desc[11] = regs[5]; /* lba high */ - desc[12] = regs[6]; /* device */ - desc[13] = regs[7]; /* command */ - - srb->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; - } - goto end; -invalid_fld: - srb->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; - - memcpy(srb->sense_buffer, - usb_stor_sense_invalidCDB, - sizeof(usb_stor_sense_invalidCDB)); -end: - memcpy(srb->cmnd, save_cmnd, sizeof(save_cmnd)); - if (srb->cmnd[0] == ATA_12) - srb->cmd_len = 12; -} - - -static int cypress_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct us_data *us; - int result; - - result = usb_stor_probe1(&us, intf, id, - (id - cypress_usb_ids) + cypress_unusual_dev_list); - if (result) - return result; - - us->protocol_name = "Transparent SCSI with Cypress ATACB"; - us->proto_handler = cypress_atacb_passthrough; - - result = usb_stor_probe2(us); - return result; -} - -static struct usb_driver cypress_driver = { - .name = "ums-cypress", - .probe = cypress_probe, - .disconnect = usb_stor_disconnect, - .suspend = usb_stor_suspend, - .resume = usb_stor_resume, - .reset_resume = usb_stor_reset_resume, - .pre_reset = usb_stor_pre_reset, - .post_reset = usb_stor_post_reset, - .id_table = cypress_usb_ids, - .soft_unbind = 1, - .no_dynamic_id = 1, -}; - -module_usb_driver(cypress_driver); diff --git a/ANDROID_3.4.5/drivers/usb/storage/datafab.c b/ANDROID_3.4.5/drivers/usb/storage/datafab.c deleted file mode 100644 index 35e9c51e..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/datafab.c +++ /dev/null @@ -1,757 +0,0 @@ -/* Driver for Datafab USB Compact Flash reader - * - * datafab driver v0.1: - * - * First release - * - * Current development and maintenance by: - * (c) 2000 Jimmie Mayfield (mayfield+datafab@sackheads.org) - * - * Many thanks to Robert Baruch for the SanDisk SmartMedia reader driver - * which I used as a template for this driver. - * - * Some bugfixes and scatter-gather code by Gregory P. Smith - * (greg-usb@electricrain.com) - * - * Fix for media change by Joerg Schneider (js@joergschneider.com) - * - * Other contributors: - * (c) 2002 Alan Stern - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* - * This driver attempts to support USB CompactFlash reader/writer devices - * based on Datafab USB-to-ATA chips. It was specifically developed for the - * Datafab MDCFE-B USB CompactFlash reader but has since been found to work - * with a variety of Datafab-based devices from a number of manufacturers. - * I've received a report of this driver working with a Datafab-based - * SmartMedia device though please be aware that I'm personally unable to - * test SmartMedia support. - * - * This driver supports reading and writing. If you're truly paranoid, - * however, you can force the driver into a write-protected state by setting - * the WP enable bits in datafab_handle_mode_sense(). See the comments - * in that routine. - */ - -#include -#include -#include - -#include -#include - -#include "usb.h" -#include "transport.h" -#include "protocol.h" -#include "debug.h" - -MODULE_DESCRIPTION("Driver for Datafab USB Compact Flash reader"); -MODULE_AUTHOR("Jimmie Mayfield "); -MODULE_LICENSE("GPL"); - -struct datafab_info { - unsigned long sectors; /* total sector count */ - unsigned long ssize; /* sector size in bytes */ - signed char lun; /* used for dual-slot readers */ - - /* the following aren't used yet */ - unsigned char sense_key; - unsigned long sense_asc; /* additional sense code */ - unsigned long sense_ascq; /* additional sense code qualifier */ -}; - -static int datafab_determine_lun(struct us_data *us, - struct datafab_info *info); - - -/* - * The table of devices - */ -#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ - vendorName, productName, useProtocol, useTransport, \ - initFunction, flags) \ -{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } - -static struct usb_device_id datafab_usb_ids[] = { -# include "unusual_datafab.h" - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, datafab_usb_ids); - -#undef UNUSUAL_DEV - -/* - * The flags table - */ -#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ - vendor_name, product_name, use_protocol, use_transport, \ - init_function, Flags) \ -{ \ - .vendorName = vendor_name, \ - .productName = product_name, \ - .useProtocol = use_protocol, \ - .useTransport = use_transport, \ - .initFunction = init_function, \ -} - -static struct us_unusual_dev datafab_unusual_dev_list[] = { -# include "unusual_datafab.h" - { } /* Terminating entry */ -}; - -#undef UNUSUAL_DEV - - -static inline int -datafab_bulk_read(struct us_data *us, unsigned char *data, unsigned int len) { - if (len == 0) - return USB_STOR_XFER_GOOD; - - US_DEBUGP("datafab_bulk_read: len = %d\n", len); - return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, - data, len, NULL); -} - - -static inline int -datafab_bulk_write(struct us_data *us, unsigned char *data, unsigned int len) { - if (len == 0) - return USB_STOR_XFER_GOOD; - - US_DEBUGP("datafab_bulk_write: len = %d\n", len); - return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, - data, len, NULL); -} - - -static int datafab_read_data(struct us_data *us, - struct datafab_info *info, - u32 sector, - u32 sectors) -{ - unsigned char *command = us->iobuf; - unsigned char *buffer; - unsigned char thistime; - unsigned int totallen, alloclen; - int len, result; - unsigned int sg_offset = 0; - struct scatterlist *sg = NULL; - - // we're working in LBA mode. according to the ATA spec, - // we can support up to 28-bit addressing. I don't know if Datafab - // supports beyond 24-bit addressing. It's kind of hard to test - // since it requires > 8GB CF card. - // - if (sectors > 0x0FFFFFFF) - return USB_STOR_TRANSPORT_ERROR; - - if (info->lun == -1) { - result = datafab_determine_lun(us, info); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - } - - totallen = sectors * info->ssize; - - // Since we don't read more than 64 KB at a time, we have to create - // a bounce buffer and move the data a piece at a time between the - // bounce buffer and the actual transfer buffer. - - alloclen = min(totallen, 65536u); - buffer = kmalloc(alloclen, GFP_NOIO); - if (buffer == NULL) - return USB_STOR_TRANSPORT_ERROR; - - do { - // loop, never allocate or transfer more than 64k at once - // (min(128k, 255*info->ssize) is the real limit) - - len = min(totallen, alloclen); - thistime = (len / info->ssize) & 0xff; - - command[0] = 0; - command[1] = thistime; - command[2] = sector & 0xFF; - command[3] = (sector >> 8) & 0xFF; - command[4] = (sector >> 16) & 0xFF; - - command[5] = 0xE0 + (info->lun << 4); - command[5] |= (sector >> 24) & 0x0F; - command[6] = 0x20; - command[7] = 0x01; - - // send the read command - result = datafab_bulk_write(us, command, 8); - if (result != USB_STOR_XFER_GOOD) - goto leave; - - // read the result - result = datafab_bulk_read(us, buffer, len); - if (result != USB_STOR_XFER_GOOD) - goto leave; - - // Store the data in the transfer buffer - usb_stor_access_xfer_buf(buffer, len, us->srb, - &sg, &sg_offset, TO_XFER_BUF); - - sector += thistime; - totallen -= len; - } while (totallen > 0); - - kfree(buffer); - return USB_STOR_TRANSPORT_GOOD; - - leave: - kfree(buffer); - return USB_STOR_TRANSPORT_ERROR; -} - - -static int datafab_write_data(struct us_data *us, - struct datafab_info *info, - u32 sector, - u32 sectors) -{ - unsigned char *command = us->iobuf; - unsigned char *reply = us->iobuf; - unsigned char *buffer; - unsigned char thistime; - unsigned int totallen, alloclen; - int len, result; - unsigned int sg_offset = 0; - struct scatterlist *sg = NULL; - - // we're working in LBA mode. according to the ATA spec, - // we can support up to 28-bit addressing. I don't know if Datafab - // supports beyond 24-bit addressing. It's kind of hard to test - // since it requires > 8GB CF card. - // - if (sectors > 0x0FFFFFFF) - return USB_STOR_TRANSPORT_ERROR; - - if (info->lun == -1) { - result = datafab_determine_lun(us, info); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - } - - totallen = sectors * info->ssize; - - // Since we don't write more than 64 KB at a time, we have to create - // a bounce buffer and move the data a piece at a time between the - // bounce buffer and the actual transfer buffer. - - alloclen = min(totallen, 65536u); - buffer = kmalloc(alloclen, GFP_NOIO); - if (buffer == NULL) - return USB_STOR_TRANSPORT_ERROR; - - do { - // loop, never allocate or transfer more than 64k at once - // (min(128k, 255*info->ssize) is the real limit) - - len = min(totallen, alloclen); - thistime = (len / info->ssize) & 0xff; - - // Get the data from the transfer buffer - usb_stor_access_xfer_buf(buffer, len, us->srb, - &sg, &sg_offset, FROM_XFER_BUF); - - command[0] = 0; - command[1] = thistime; - command[2] = sector & 0xFF; - command[3] = (sector >> 8) & 0xFF; - command[4] = (sector >> 16) & 0xFF; - - command[5] = 0xE0 + (info->lun << 4); - command[5] |= (sector >> 24) & 0x0F; - command[6] = 0x30; - command[7] = 0x02; - - // send the command - result = datafab_bulk_write(us, command, 8); - if (result != USB_STOR_XFER_GOOD) - goto leave; - - // send the data - result = datafab_bulk_write(us, buffer, len); - if (result != USB_STOR_XFER_GOOD) - goto leave; - - // read the result - result = datafab_bulk_read(us, reply, 2); - if (result != USB_STOR_XFER_GOOD) - goto leave; - - if (reply[0] != 0x50 && reply[1] != 0) { - US_DEBUGP("datafab_write_data: Gah! " - "write return code: %02x %02x\n", - reply[0], reply[1]); - result = USB_STOR_TRANSPORT_ERROR; - goto leave; - } - - sector += thistime; - totallen -= len; - } while (totallen > 0); - - kfree(buffer); - return USB_STOR_TRANSPORT_GOOD; - - leave: - kfree(buffer); - return USB_STOR_TRANSPORT_ERROR; -} - - -static int datafab_determine_lun(struct us_data *us, - struct datafab_info *info) -{ - // Dual-slot readers can be thought of as dual-LUN devices. - // We need to determine which card slot is being used. - // We'll send an IDENTIFY DEVICE command and see which LUN responds... - // - // There might be a better way of doing this? - - static unsigned char scommand[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 }; - unsigned char *command = us->iobuf; - unsigned char *buf; - int count = 0, rc; - - if (!info) - return USB_STOR_TRANSPORT_ERROR; - - memcpy(command, scommand, 8); - buf = kmalloc(512, GFP_NOIO); - if (!buf) - return USB_STOR_TRANSPORT_ERROR; - - US_DEBUGP("datafab_determine_lun: locating...\n"); - - // we'll try 3 times before giving up... - // - while (count++ < 3) { - command[5] = 0xa0; - - rc = datafab_bulk_write(us, command, 8); - if (rc != USB_STOR_XFER_GOOD) { - rc = USB_STOR_TRANSPORT_ERROR; - goto leave; - } - - rc = datafab_bulk_read(us, buf, 512); - if (rc == USB_STOR_XFER_GOOD) { - info->lun = 0; - rc = USB_STOR_TRANSPORT_GOOD; - goto leave; - } - - command[5] = 0xb0; - - rc = datafab_bulk_write(us, command, 8); - if (rc != USB_STOR_XFER_GOOD) { - rc = USB_STOR_TRANSPORT_ERROR; - goto leave; - } - - rc = datafab_bulk_read(us, buf, 512); - if (rc == USB_STOR_XFER_GOOD) { - info->lun = 1; - rc = USB_STOR_TRANSPORT_GOOD; - goto leave; - } - - msleep(20); - } - - rc = USB_STOR_TRANSPORT_ERROR; - - leave: - kfree(buf); - return rc; -} - -static int datafab_id_device(struct us_data *us, - struct datafab_info *info) -{ - // this is a variation of the ATA "IDENTIFY DEVICE" command...according - // to the ATA spec, 'Sector Count' isn't used but the Windows driver - // sets this bit so we do too... - // - static unsigned char scommand[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 }; - unsigned char *command = us->iobuf; - unsigned char *reply; - int rc; - - if (!info) - return USB_STOR_TRANSPORT_ERROR; - - if (info->lun == -1) { - rc = datafab_determine_lun(us, info); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - } - - memcpy(command, scommand, 8); - reply = kmalloc(512, GFP_NOIO); - if (!reply) - return USB_STOR_TRANSPORT_ERROR; - - command[5] += (info->lun << 4); - - rc = datafab_bulk_write(us, command, 8); - if (rc != USB_STOR_XFER_GOOD) { - rc = USB_STOR_TRANSPORT_ERROR; - goto leave; - } - - // we'll go ahead and extract the media capacity while we're here... - // - rc = datafab_bulk_read(us, reply, 512); - if (rc == USB_STOR_XFER_GOOD) { - // capacity is at word offset 57-58 - // - info->sectors = ((u32)(reply[117]) << 24) | - ((u32)(reply[116]) << 16) | - ((u32)(reply[115]) << 8) | - ((u32)(reply[114]) ); - rc = USB_STOR_TRANSPORT_GOOD; - goto leave; - } - - rc = USB_STOR_TRANSPORT_ERROR; - - leave: - kfree(reply); - return rc; -} - - -static int datafab_handle_mode_sense(struct us_data *us, - struct scsi_cmnd * srb, - int sense_6) -{ - static unsigned char rw_err_page[12] = { - 0x1, 0xA, 0x21, 1, 0, 0, 0, 0, 1, 0, 0, 0 - }; - static unsigned char cache_page[12] = { - 0x8, 0xA, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - static unsigned char rbac_page[12] = { - 0x1B, 0xA, 0, 0x81, 0, 0, 0, 0, 0, 0, 0, 0 - }; - static unsigned char timer_page[8] = { - 0x1C, 0x6, 0, 0, 0, 0 - }; - unsigned char pc, page_code; - unsigned int i = 0; - struct datafab_info *info = (struct datafab_info *) (us->extra); - unsigned char *ptr = us->iobuf; - - // most of this stuff is just a hack to get things working. the - // datafab reader doesn't present a SCSI interface so we - // fudge the SCSI commands... - // - - pc = srb->cmnd[2] >> 6; - page_code = srb->cmnd[2] & 0x3F; - - switch (pc) { - case 0x0: - US_DEBUGP("datafab_handle_mode_sense: Current values\n"); - break; - case 0x1: - US_DEBUGP("datafab_handle_mode_sense: Changeable values\n"); - break; - case 0x2: - US_DEBUGP("datafab_handle_mode_sense: Default values\n"); - break; - case 0x3: - US_DEBUGP("datafab_handle_mode_sense: Saves values\n"); - break; - } - - memset(ptr, 0, 8); - if (sense_6) { - ptr[2] = 0x00; // WP enable: 0x80 - i = 4; - } else { - ptr[3] = 0x00; // WP enable: 0x80 - i = 8; - } - - switch (page_code) { - default: - // vendor-specific mode - info->sense_key = 0x05; - info->sense_asc = 0x24; - info->sense_ascq = 0x00; - return USB_STOR_TRANSPORT_FAILED; - - case 0x1: - memcpy(ptr + i, rw_err_page, sizeof(rw_err_page)); - i += sizeof(rw_err_page); - break; - - case 0x8: - memcpy(ptr + i, cache_page, sizeof(cache_page)); - i += sizeof(cache_page); - break; - - case 0x1B: - memcpy(ptr + i, rbac_page, sizeof(rbac_page)); - i += sizeof(rbac_page); - break; - - case 0x1C: - memcpy(ptr + i, timer_page, sizeof(timer_page)); - i += sizeof(timer_page); - break; - - case 0x3F: // retrieve all pages - memcpy(ptr + i, timer_page, sizeof(timer_page)); - i += sizeof(timer_page); - memcpy(ptr + i, rbac_page, sizeof(rbac_page)); - i += sizeof(rbac_page); - memcpy(ptr + i, cache_page, sizeof(cache_page)); - i += sizeof(cache_page); - memcpy(ptr + i, rw_err_page, sizeof(rw_err_page)); - i += sizeof(rw_err_page); - break; - } - - if (sense_6) - ptr[0] = i - 1; - else - ((__be16 *) ptr)[0] = cpu_to_be16(i - 2); - usb_stor_set_xfer_buf(ptr, i, srb); - - return USB_STOR_TRANSPORT_GOOD; -} - -static void datafab_info_destructor(void *extra) -{ - // this routine is a placeholder... - // currently, we don't allocate any extra memory so we're okay -} - - -// Transport for the Datafab MDCFE-B -// -static int datafab_transport(struct scsi_cmnd *srb, struct us_data *us) -{ - struct datafab_info *info; - int rc; - unsigned long block, blocks; - unsigned char *ptr = us->iobuf; - static unsigned char inquiry_reply[8] = { - 0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00 - }; - - if (!us->extra) { - us->extra = kzalloc(sizeof(struct datafab_info), GFP_NOIO); - if (!us->extra) { - US_DEBUGP("datafab_transport: Gah! " - "Can't allocate storage for Datafab info struct!\n"); - return USB_STOR_TRANSPORT_ERROR; - } - us->extra_destructor = datafab_info_destructor; - ((struct datafab_info *)us->extra)->lun = -1; - } - - info = (struct datafab_info *) (us->extra); - - if (srb->cmnd[0] == INQUIRY) { - US_DEBUGP("datafab_transport: INQUIRY. Returning bogus response"); - memcpy(ptr, inquiry_reply, sizeof(inquiry_reply)); - fill_inquiry_response(us, ptr, 36); - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == READ_CAPACITY) { - info->ssize = 0x200; // hard coded 512 byte sectors as per ATA spec - rc = datafab_id_device(us, info); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - - US_DEBUGP("datafab_transport: READ_CAPACITY: %ld sectors, %ld bytes per sector\n", - info->sectors, info->ssize); - - // build the reply - // we need the last sector, not the number of sectors - ((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1); - ((__be32 *) ptr)[1] = cpu_to_be32(info->ssize); - usb_stor_set_xfer_buf(ptr, 8, srb); - - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == MODE_SELECT_10) { - US_DEBUGP("datafab_transport: Gah! MODE_SELECT_10.\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - // don't bother implementing READ_6 or WRITE_6. - // - if (srb->cmnd[0] == READ_10) { - block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | - ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); - - blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); - - US_DEBUGP("datafab_transport: READ_10: read block 0x%04lx count %ld\n", block, blocks); - return datafab_read_data(us, info, block, blocks); - } - - if (srb->cmnd[0] == READ_12) { - // we'll probably never see a READ_12 but we'll do it anyway... - // - block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | - ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); - - blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | - ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9])); - - US_DEBUGP("datafab_transport: READ_12: read block 0x%04lx count %ld\n", block, blocks); - return datafab_read_data(us, info, block, blocks); - } - - if (srb->cmnd[0] == WRITE_10) { - block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | - ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); - - blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); - - US_DEBUGP("datafab_transport: WRITE_10: write block 0x%04lx count %ld\n", block, blocks); - return datafab_write_data(us, info, block, blocks); - } - - if (srb->cmnd[0] == WRITE_12) { - // we'll probably never see a WRITE_12 but we'll do it anyway... - // - block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | - ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); - - blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | - ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9])); - - US_DEBUGP("datafab_transport: WRITE_12: write block 0x%04lx count %ld\n", block, blocks); - return datafab_write_data(us, info, block, blocks); - } - - if (srb->cmnd[0] == TEST_UNIT_READY) { - US_DEBUGP("datafab_transport: TEST_UNIT_READY.\n"); - return datafab_id_device(us, info); - } - - if (srb->cmnd[0] == REQUEST_SENSE) { - US_DEBUGP("datafab_transport: REQUEST_SENSE. Returning faked response\n"); - - // this response is pretty bogus right now. eventually if necessary - // we can set the correct sense data. so far though it hasn't been - // necessary - // - memset(ptr, 0, 18); - ptr[0] = 0xF0; - ptr[2] = info->sense_key; - ptr[7] = 11; - ptr[12] = info->sense_asc; - ptr[13] = info->sense_ascq; - usb_stor_set_xfer_buf(ptr, 18, srb); - - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == MODE_SENSE) { - US_DEBUGP("datafab_transport: MODE_SENSE_6 detected\n"); - return datafab_handle_mode_sense(us, srb, 1); - } - - if (srb->cmnd[0] == MODE_SENSE_10) { - US_DEBUGP("datafab_transport: MODE_SENSE_10 detected\n"); - return datafab_handle_mode_sense(us, srb, 0); - } - - if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { - // sure. whatever. not like we can stop the user from - // popping the media out of the device (no locking doors, etc) - // - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == START_STOP) { - /* this is used by sd.c'check_scsidisk_media_change to detect - media change */ - US_DEBUGP("datafab_transport: START_STOP.\n"); - /* the first datafab_id_device after a media change returns - an error (determined experimentally) */ - rc = datafab_id_device(us, info); - if (rc == USB_STOR_TRANSPORT_GOOD) { - info->sense_key = NO_SENSE; - srb->result = SUCCESS; - } else { - info->sense_key = UNIT_ATTENTION; - srb->result = SAM_STAT_CHECK_CONDITION; - } - return rc; - } - - US_DEBUGP("datafab_transport: Gah! Unknown command: %d (0x%x)\n", - srb->cmnd[0], srb->cmnd[0]); - info->sense_key = 0x05; - info->sense_asc = 0x20; - info->sense_ascq = 0x00; - return USB_STOR_TRANSPORT_FAILED; -} - -static int datafab_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct us_data *us; - int result; - - result = usb_stor_probe1(&us, intf, id, - (id - datafab_usb_ids) + datafab_unusual_dev_list); - if (result) - return result; - - us->transport_name = "Datafab Bulk-Only"; - us->transport = datafab_transport; - us->transport_reset = usb_stor_Bulk_reset; - us->max_lun = 1; - - result = usb_stor_probe2(us); - return result; -} - -static struct usb_driver datafab_driver = { - .name = "ums-datafab", - .probe = datafab_probe, - .disconnect = usb_stor_disconnect, - .suspend = usb_stor_suspend, - .resume = usb_stor_resume, - .reset_resume = usb_stor_reset_resume, - .pre_reset = usb_stor_pre_reset, - .post_reset = usb_stor_post_reset, - .id_table = datafab_usb_ids, - .soft_unbind = 1, - .no_dynamic_id = 1, -}; - -module_usb_driver(datafab_driver); diff --git a/ANDROID_3.4.5/drivers/usb/storage/debug.c b/ANDROID_3.4.5/drivers/usb/storage/debug.c deleted file mode 100644 index a2b5526c..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/debug.c +++ /dev/null @@ -1,177 +0,0 @@ -/* Driver for USB Mass Storage compliant devices - * Debugging Functions Source Code File - * - * Current development and maintenance by: - * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * Developed with the assistance of: - * (c) 2002 Alan Stern - * - * Initial work by: - * (c) 1999 Michael Gee (michael@linuxspecific.com) - * - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI and ATAPI commands in - * mind when they created this document. The commands are all very - * similar to commands in the SCSI-II and ATAPI specifications. - * - * It is important to note that in a number of cases this class - * exhibits class-specific exemptions from the USB specification. - * Notably the usage of NAK, STALL and ACK differs from the norm, in - * that they are used to communicate wait, failed and OK on commands. - * - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -#include "debug.h" -#include "scsi.h" - - -void usb_stor_show_command(struct scsi_cmnd *srb) -{ - char *what = NULL; - int i; - - switch (srb->cmnd[0]) { - case TEST_UNIT_READY: what = "TEST_UNIT_READY"; break; - case REZERO_UNIT: what = "REZERO_UNIT"; break; - case REQUEST_SENSE: what = "REQUEST_SENSE"; break; - case FORMAT_UNIT: what = "FORMAT_UNIT"; break; - case READ_BLOCK_LIMITS: what = "READ_BLOCK_LIMITS"; break; - case REASSIGN_BLOCKS: what = "REASSIGN_BLOCKS"; break; - case READ_6: what = "READ_6"; break; - case WRITE_6: what = "WRITE_6"; break; - case SEEK_6: what = "SEEK_6"; break; - case READ_REVERSE: what = "READ_REVERSE"; break; - case WRITE_FILEMARKS: what = "WRITE_FILEMARKS"; break; - case SPACE: what = "SPACE"; break; - case INQUIRY: what = "INQUIRY"; break; - case RECOVER_BUFFERED_DATA: what = "RECOVER_BUFFERED_DATA"; break; - case MODE_SELECT: what = "MODE_SELECT"; break; - case RESERVE: what = "RESERVE"; break; - case RELEASE: what = "RELEASE"; break; - case COPY: what = "COPY"; break; - case ERASE: what = "ERASE"; break; - case MODE_SENSE: what = "MODE_SENSE"; break; - case START_STOP: what = "START_STOP"; break; - case RECEIVE_DIAGNOSTIC: what = "RECEIVE_DIAGNOSTIC"; break; - case SEND_DIAGNOSTIC: what = "SEND_DIAGNOSTIC"; break; - case ALLOW_MEDIUM_REMOVAL: what = "ALLOW_MEDIUM_REMOVAL"; break; - case SET_WINDOW: what = "SET_WINDOW"; break; - case READ_CAPACITY: what = "READ_CAPACITY"; break; - case READ_10: what = "READ_10"; break; - case WRITE_10: what = "WRITE_10"; break; - case SEEK_10: what = "SEEK_10"; break; - case WRITE_VERIFY: what = "WRITE_VERIFY"; break; - case VERIFY: what = "VERIFY"; break; - case SEARCH_HIGH: what = "SEARCH_HIGH"; break; - case SEARCH_EQUAL: what = "SEARCH_EQUAL"; break; - case SEARCH_LOW: what = "SEARCH_LOW"; break; - case SET_LIMITS: what = "SET_LIMITS"; break; - case READ_POSITION: what = "READ_POSITION"; break; - case SYNCHRONIZE_CACHE: what = "SYNCHRONIZE_CACHE"; break; - case LOCK_UNLOCK_CACHE: what = "LOCK_UNLOCK_CACHE"; break; - case READ_DEFECT_DATA: what = "READ_DEFECT_DATA"; break; - case MEDIUM_SCAN: what = "MEDIUM_SCAN"; break; - case COMPARE: what = "COMPARE"; break; - case COPY_VERIFY: what = "COPY_VERIFY"; break; - case WRITE_BUFFER: what = "WRITE_BUFFER"; break; - case READ_BUFFER: what = "READ_BUFFER"; break; - case UPDATE_BLOCK: what = "UPDATE_BLOCK"; break; - case READ_LONG: what = "READ_LONG"; break; - case WRITE_LONG: what = "WRITE_LONG"; break; - case CHANGE_DEFINITION: what = "CHANGE_DEFINITION"; break; - case WRITE_SAME: what = "WRITE_SAME"; break; - case GPCMD_READ_SUBCHANNEL: what = "READ SUBCHANNEL"; break; - case READ_TOC: what = "READ_TOC"; break; - case GPCMD_READ_HEADER: what = "READ HEADER"; break; - case GPCMD_PLAY_AUDIO_10: what = "PLAY AUDIO (10)"; break; - case GPCMD_PLAY_AUDIO_MSF: what = "PLAY AUDIO MSF"; break; - case GPCMD_GET_EVENT_STATUS_NOTIFICATION: - what = "GET EVENT/STATUS NOTIFICATION"; break; - case GPCMD_PAUSE_RESUME: what = "PAUSE/RESUME"; break; - case LOG_SELECT: what = "LOG_SELECT"; break; - case LOG_SENSE: what = "LOG_SENSE"; break; - case GPCMD_STOP_PLAY_SCAN: what = "STOP PLAY/SCAN"; break; - case GPCMD_READ_DISC_INFO: what = "READ DISC INFORMATION"; break; - case GPCMD_READ_TRACK_RZONE_INFO: - what = "READ TRACK INFORMATION"; break; - case GPCMD_RESERVE_RZONE_TRACK: what = "RESERVE TRACK"; break; - case GPCMD_SEND_OPC: what = "SEND OPC"; break; - case MODE_SELECT_10: what = "MODE_SELECT_10"; break; - case GPCMD_REPAIR_RZONE_TRACK: what = "REPAIR TRACK"; break; - case 0x59: what = "READ MASTER CUE"; break; - case MODE_SENSE_10: what = "MODE_SENSE_10"; break; - case GPCMD_CLOSE_TRACK: what = "CLOSE TRACK/SESSION"; break; - case 0x5C: what = "READ BUFFER CAPACITY"; break; - case 0x5D: what = "SEND CUE SHEET"; break; - case GPCMD_BLANK: what = "BLANK"; break; - case REPORT_LUNS: what = "REPORT LUNS"; break; - case MOVE_MEDIUM: what = "MOVE_MEDIUM or PLAY AUDIO (12)"; break; - case READ_12: what = "READ_12"; break; - case WRITE_12: what = "WRITE_12"; break; - case WRITE_VERIFY_12: what = "WRITE_VERIFY_12"; break; - case SEARCH_HIGH_12: what = "SEARCH_HIGH_12"; break; - case SEARCH_EQUAL_12: what = "SEARCH_EQUAL_12"; break; - case SEARCH_LOW_12: what = "SEARCH_LOW_12"; break; - case SEND_VOLUME_TAG: what = "SEND_VOLUME_TAG"; break; - case READ_ELEMENT_STATUS: what = "READ_ELEMENT_STATUS"; break; - case GPCMD_READ_CD_MSF: what = "READ CD MSF"; break; - case GPCMD_SCAN: what = "SCAN"; break; - case GPCMD_SET_SPEED: what = "SET CD SPEED"; break; - case GPCMD_MECHANISM_STATUS: what = "MECHANISM STATUS"; break; - case GPCMD_READ_CD: what = "READ CD"; break; - case 0xE1: what = "WRITE CONTINUE"; break; - case WRITE_LONG_2: what = "WRITE_LONG_2"; break; - default: what = "(unknown command)"; break; - } - US_DEBUGP("Command %s (%d bytes)\n", what, srb->cmd_len); - US_DEBUGP(""); - for (i = 0; i < srb->cmd_len && i < 16; i++) - US_DEBUGPX(" %02x", srb->cmnd[i]); - US_DEBUGPX("\n"); -} - -void usb_stor_show_sense( - unsigned char key, - unsigned char asc, - unsigned char ascq) { - - const char *what, *keystr; - - keystr = scsi_sense_key_string(key); - what = scsi_extd_sense_format(asc, ascq); - - if (keystr == NULL) - keystr = "(Unknown Key)"; - if (what == NULL) - what = "(unknown ASC/ASCQ)"; - - US_DEBUGP("%s: ", keystr); - US_DEBUGPX(what, ascq); - US_DEBUGPX("\n"); -} diff --git a/ANDROID_3.4.5/drivers/usb/storage/debug.h b/ANDROID_3.4.5/drivers/usb/storage/debug.h deleted file mode 100644 index dbb985d5..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/debug.h +++ /dev/null @@ -1,62 +0,0 @@ -/* Driver for USB Mass Storage compliant devices - * Debugging Functions Header File - * - * Current development and maintenance by: - * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * Initial work by: - * (c) 1999 Michael Gee (michael@linuxspecific.com) - * - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI and ATAPI commands in - * mind when they created this document. The commands are all very - * similar to commands in the SCSI-II and ATAPI specifications. - * - * It is important to note that in a number of cases this class - * exhibits class-specific exemptions from the USB specification. - * Notably the usage of NAK, STALL and ACK differs from the norm, in - * that they are used to communicate wait, failed and OK on commands. - * - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _DEBUG_H_ -#define _DEBUG_H_ - -#include - -#define USB_STORAGE "usb-storage: " - -#ifdef CONFIG_USB_STORAGE_DEBUG -void usb_stor_show_command(struct scsi_cmnd *srb); -void usb_stor_show_sense( unsigned char key, - unsigned char asc, unsigned char ascq ); -#define US_DEBUGP(x...) printk( KERN_DEBUG USB_STORAGE x ) -#define US_DEBUGPX(x...) printk( x ) -#define US_DEBUG(x) x -#else -#define US_DEBUGP(x...) -#define US_DEBUGPX(x...) -#define US_DEBUG(x) -#endif - -#endif diff --git a/ANDROID_3.4.5/drivers/usb/storage/ene_ub6250.c b/ANDROID_3.4.5/drivers/usb/storage/ene_ub6250.c deleted file mode 100644 index e7e67810..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/ene_ub6250.c +++ /dev/null @@ -1,2413 +0,0 @@ -/* - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include -#include -#include -#include - -#include -#include - -#include - -#include "usb.h" -#include "transport.h" -#include "protocol.h" -#include "debug.h" - -MODULE_DESCRIPTION("Driver for ENE UB6250 reader"); -MODULE_LICENSE("GPL"); - - -/* - * The table of devices - */ -#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ - vendorName, productName, useProtocol, useTransport, \ - initFunction, flags) \ -{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } - -static struct usb_device_id ene_ub6250_usb_ids[] = { -# include "unusual_ene_ub6250.h" - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, ene_ub6250_usb_ids); - -#undef UNUSUAL_DEV - -/* - * The flags table - */ -#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ - vendor_name, product_name, use_protocol, use_transport, \ - init_function, Flags) \ -{ \ - .vendorName = vendor_name, \ - .productName = product_name, \ - .useProtocol = use_protocol, \ - .useTransport = use_transport, \ - .initFunction = init_function, \ -} - -static struct us_unusual_dev ene_ub6250_unusual_dev_list[] = { -# include "unusual_ene_ub6250.h" - { } /* Terminating entry */ -}; - -#undef UNUSUAL_DEV - - - -/* ENE bin code len */ -#define ENE_BIN_CODE_LEN 0x800 -/* EnE HW Register */ -#define REG_CARD_STATUS 0xFF83 -#define REG_HW_TRAP1 0xFF89 - -/* SRB Status */ -#define SS_SUCCESS 0x00 /* No Sense */ -#define SS_NOT_READY 0x02 -#define SS_MEDIUM_ERR 0x03 -#define SS_HW_ERR 0x04 -#define SS_ILLEGAL_REQUEST 0x05 -#define SS_UNIT_ATTENTION 0x06 - -/* ENE Load FW Pattern */ -#define SD_INIT1_PATTERN 1 -#define SD_INIT2_PATTERN 2 -#define SD_RW_PATTERN 3 -#define MS_INIT_PATTERN 4 -#define MSP_RW_PATTERN 5 -#define MS_RW_PATTERN 6 -#define SM_INIT_PATTERN 7 -#define SM_RW_PATTERN 8 - -#define FDIR_WRITE 0 -#define FDIR_READ 1 - -/* For MS Card */ - -/* Status Register 1 */ -#define MS_REG_ST1_MB 0x80 /* media busy */ -#define MS_REG_ST1_FB1 0x40 /* flush busy 1 */ -#define MS_REG_ST1_DTER 0x20 /* error on data(corrected) */ -#define MS_REG_ST1_UCDT 0x10 /* unable to correct data */ -#define MS_REG_ST1_EXER 0x08 /* error on extra(corrected) */ -#define MS_REG_ST1_UCEX 0x04 /* unable to correct extra */ -#define MS_REG_ST1_FGER 0x02 /* error on overwrite flag(corrected) */ -#define MS_REG_ST1_UCFG 0x01 /* unable to correct overwrite flag */ -#define MS_REG_ST1_DEFAULT (MS_REG_ST1_MB | MS_REG_ST1_FB1 | MS_REG_ST1_DTER | MS_REG_ST1_UCDT | MS_REG_ST1_EXER | MS_REG_ST1_UCEX | MS_REG_ST1_FGER | MS_REG_ST1_UCFG) - -/* Overwrite Area */ -#define MS_REG_OVR_BKST 0x80 /* block status */ -#define MS_REG_OVR_BKST_OK MS_REG_OVR_BKST /* OK */ -#define MS_REG_OVR_BKST_NG 0x00 /* NG */ -#define MS_REG_OVR_PGST0 0x40 /* page status */ -#define MS_REG_OVR_PGST1 0x20 -#define MS_REG_OVR_PGST_MASK (MS_REG_OVR_PGST0 | MS_REG_OVR_PGST1) -#define MS_REG_OVR_PGST_OK (MS_REG_OVR_PGST0 | MS_REG_OVR_PGST1) /* OK */ -#define MS_REG_OVR_PGST_NG MS_REG_OVR_PGST1 /* NG */ -#define MS_REG_OVR_PGST_DATA_ERROR 0x00 /* data error */ -#define MS_REG_OVR_UDST 0x10 /* update status */ -#define MS_REG_OVR_UDST_UPDATING 0x00 /* updating */ -#define MS_REG_OVR_UDST_NO_UPDATE MS_REG_OVR_UDST -#define MS_REG_OVR_RESERVED 0x08 -#define MS_REG_OVR_DEFAULT (MS_REG_OVR_BKST_OK | MS_REG_OVR_PGST_OK | MS_REG_OVR_UDST_NO_UPDATE | MS_REG_OVR_RESERVED) - -/* Management Flag */ -#define MS_REG_MNG_SCMS0 0x20 /* serial copy management system */ -#define MS_REG_MNG_SCMS1 0x10 -#define MS_REG_MNG_SCMS_MASK (MS_REG_MNG_SCMS0 | MS_REG_MNG_SCMS1) -#define MS_REG_MNG_SCMS_COPY_OK (MS_REG_MNG_SCMS0 | MS_REG_MNG_SCMS1) -#define MS_REG_MNG_SCMS_ONE_COPY MS_REG_MNG_SCMS1 -#define MS_REG_MNG_SCMS_NO_COPY 0x00 -#define MS_REG_MNG_ATFLG 0x08 /* address transfer table flag */ -#define MS_REG_MNG_ATFLG_OTHER MS_REG_MNG_ATFLG /* other */ -#define MS_REG_MNG_ATFLG_ATTBL 0x00 /* address transfer table */ -#define MS_REG_MNG_SYSFLG 0x04 /* system flag */ -#define MS_REG_MNG_SYSFLG_USER MS_REG_MNG_SYSFLG /* user block */ -#define MS_REG_MNG_SYSFLG_BOOT 0x00 /* system block */ -#define MS_REG_MNG_RESERVED 0xc3 -#define MS_REG_MNG_DEFAULT (MS_REG_MNG_SCMS_COPY_OK | MS_REG_MNG_ATFLG_OTHER | MS_REG_MNG_SYSFLG_USER | MS_REG_MNG_RESERVED) - - -#define MS_MAX_PAGES_PER_BLOCK 32 -#define MS_MAX_INITIAL_ERROR_BLOCKS 10 -#define MS_LIB_BITS_PER_BYTE 8 - -#define MS_SYSINF_FORMAT_FAT 1 -#define MS_SYSINF_USAGE_GENERAL 0 - -#define MS_SYSINF_MSCLASS_TYPE_1 1 -#define MS_SYSINF_PAGE_SIZE MS_BYTES_PER_PAGE /* fixed */ - -#define MS_SYSINF_CARDTYPE_RDONLY 1 -#define MS_SYSINF_CARDTYPE_RDWR 2 -#define MS_SYSINF_CARDTYPE_HYBRID 3 -#define MS_SYSINF_SECURITY 0x01 -#define MS_SYSINF_SECURITY_NO_SUPPORT MS_SYSINF_SECURITY -#define MS_SYSINF_SECURITY_SUPPORT 0 - -#define MS_SYSINF_RESERVED1 1 -#define MS_SYSINF_RESERVED2 1 - -#define MS_SYSENT_TYPE_INVALID_BLOCK 0x01 -#define MS_SYSENT_TYPE_CIS_IDI 0x0a /* CIS/IDI */ - -#define SIZE_OF_KIRO 1024 -#define BYTE_MASK 0xff - -/* ms error code */ -#define MS_STATUS_WRITE_PROTECT 0x0106 -#define MS_STATUS_SUCCESS 0x0000 -#define MS_ERROR_FLASH_READ 0x8003 -#define MS_ERROR_FLASH_ERASE 0x8005 -#define MS_LB_ERROR 0xfff0 -#define MS_LB_BOOT_BLOCK 0xfff1 -#define MS_LB_INITIAL_ERROR 0xfff2 -#define MS_STATUS_SUCCESS_WITH_ECC 0xfff3 -#define MS_LB_ACQUIRED_ERROR 0xfff4 -#define MS_LB_NOT_USED_ERASED 0xfff5 -#define MS_NOCARD_ERROR 0xfff8 -#define MS_NO_MEMORY_ERROR 0xfff9 -#define MS_STATUS_INT_ERROR 0xfffa -#define MS_STATUS_ERROR 0xfffe -#define MS_LB_NOT_USED 0xffff - -#define MS_REG_MNG_SYSFLG 0x04 /* system flag */ -#define MS_REG_MNG_SYSFLG_USER MS_REG_MNG_SYSFLG /* user block */ - -#define MS_BOOT_BLOCK_ID 0x0001 -#define MS_BOOT_BLOCK_FORMAT_VERSION 0x0100 -#define MS_BOOT_BLOCK_DATA_ENTRIES 2 - -#define MS_NUMBER_OF_SYSTEM_ENTRY 4 -#define MS_NUMBER_OF_BOOT_BLOCK 2 -#define MS_BYTES_PER_PAGE 512 -#define MS_LOGICAL_BLOCKS_PER_SEGMENT 496 -#define MS_LOGICAL_BLOCKS_IN_1ST_SEGMENT 494 - -#define MS_PHYSICAL_BLOCKS_PER_SEGMENT 0x200 /* 512 */ -#define MS_PHYSICAL_BLOCKS_PER_SEGMENT_MASK 0x1ff - -/* overwrite area */ -#define MS_REG_OVR_BKST 0x80 /* block status */ -#define MS_REG_OVR_BKST_OK MS_REG_OVR_BKST /* OK */ -#define MS_REG_OVR_BKST_NG 0x00 /* NG */ - -/* Status Register 1 */ -#define MS_REG_ST1_DTER 0x20 /* error on data(corrected) */ -#define MS_REG_ST1_EXER 0x08 /* error on extra(corrected) */ -#define MS_REG_ST1_FGER 0x02 /* error on overwrite flag(corrected) */ - -/* MemoryStick Register */ -/* Status Register 0 */ -#define MS_REG_ST0_WP 0x01 /* write protected */ -#define MS_REG_ST0_WP_ON MS_REG_ST0_WP - -#define MS_LIB_CTRL_RDONLY 0 -#define MS_LIB_CTRL_WRPROTECT 1 - -/*dphy->log table */ -#define ms_libconv_to_logical(pdx, PhyBlock) (((PhyBlock) >= (pdx)->MS_Lib.NumberOfPhyBlock) ? MS_STATUS_ERROR : (pdx)->MS_Lib.Phy2LogMap[PhyBlock]) -#define ms_libconv_to_physical(pdx, LogBlock) (((LogBlock) >= (pdx)->MS_Lib.NumberOfLogBlock) ? MS_STATUS_ERROR : (pdx)->MS_Lib.Log2PhyMap[LogBlock]) - -#define ms_lib_ctrl_set(pdx, Flag) ((pdx)->MS_Lib.flags |= (1 << (Flag))) -#define ms_lib_ctrl_reset(pdx, Flag) ((pdx)->MS_Lib.flags &= ~(1 << (Flag))) -#define ms_lib_ctrl_check(pdx, Flag) ((pdx)->MS_Lib.flags & (1 << (Flag))) - -#define ms_lib_iswritable(pdx) ((ms_lib_ctrl_check((pdx), MS_LIB_CTRL_RDONLY) == 0) && (ms_lib_ctrl_check(pdx, MS_LIB_CTRL_WRPROTECT) == 0)) -#define ms_lib_clear_pagemap(pdx) memset((pdx)->MS_Lib.pagemap, 0, sizeof((pdx)->MS_Lib.pagemap)) -#define memstick_logaddr(logadr1, logadr0) ((((u16)(logadr1)) << 8) | (logadr0)) - - -struct SD_STATUS { - u8 Insert:1; - u8 Ready:1; - u8 MediaChange:1; - u8 IsMMC:1; - u8 HiCapacity:1; - u8 HiSpeed:1; - u8 WtP:1; - u8 Reserved:1; -}; - -struct MS_STATUS { - u8 Insert:1; - u8 Ready:1; - u8 MediaChange:1; - u8 IsMSPro:1; - u8 IsMSPHG:1; - u8 Reserved1:1; - u8 WtP:1; - u8 Reserved2:1; -}; - -struct SM_STATUS { - u8 Insert:1; - u8 Ready:1; - u8 MediaChange:1; - u8 Reserved:3; - u8 WtP:1; - u8 IsMS:1; -}; - -struct ms_bootblock_cis { - u8 bCistplDEVICE[6]; /* 0 */ - u8 bCistplDEVICE0C[6]; /* 6 */ - u8 bCistplJEDECC[4]; /* 12 */ - u8 bCistplMANFID[6]; /* 16 */ - u8 bCistplVER1[32]; /* 22 */ - u8 bCistplFUNCID[4]; /* 54 */ - u8 bCistplFUNCE0[4]; /* 58 */ - u8 bCistplFUNCE1[5]; /* 62 */ - u8 bCistplCONF[7]; /* 67 */ - u8 bCistplCFTBLENT0[10];/* 74 */ - u8 bCistplCFTBLENT1[8]; /* 84 */ - u8 bCistplCFTBLENT2[12];/* 92 */ - u8 bCistplCFTBLENT3[8]; /* 104 */ - u8 bCistplCFTBLENT4[17];/* 112 */ - u8 bCistplCFTBLENT5[8]; /* 129 */ - u8 bCistplCFTBLENT6[17];/* 137 */ - u8 bCistplCFTBLENT7[8]; /* 154 */ - u8 bCistplNOLINK[3]; /* 162 */ -} ; - -struct ms_bootblock_idi { -#define MS_IDI_GENERAL_CONF 0x848A - u16 wIDIgeneralConfiguration; /* 0 */ - u16 wIDInumberOfCylinder; /* 1 */ - u16 wIDIreserved0; /* 2 */ - u16 wIDInumberOfHead; /* 3 */ - u16 wIDIbytesPerTrack; /* 4 */ - u16 wIDIbytesPerSector; /* 5 */ - u16 wIDIsectorsPerTrack; /* 6 */ - u16 wIDItotalSectors[2]; /* 7-8 high,low */ - u16 wIDIreserved1[11]; /* 9-19 */ - u16 wIDIbufferType; /* 20 */ - u16 wIDIbufferSize; /* 21 */ - u16 wIDIlongCmdECC; /* 22 */ - u16 wIDIfirmVersion[4]; /* 23-26 */ - u16 wIDImodelName[20]; /* 27-46 */ - u16 wIDIreserved2; /* 47 */ - u16 wIDIlongWordSupported; /* 48 */ - u16 wIDIdmaSupported; /* 49 */ - u16 wIDIreserved3; /* 50 */ - u16 wIDIpioTiming; /* 51 */ - u16 wIDIdmaTiming; /* 52 */ - u16 wIDItransferParameter; /* 53 */ - u16 wIDIformattedCylinder; /* 54 */ - u16 wIDIformattedHead; /* 55 */ - u16 wIDIformattedSectorsPerTrack;/* 56 */ - u16 wIDIformattedTotalSectors[2];/* 57-58 */ - u16 wIDImultiSector; /* 59 */ - u16 wIDIlbaSectors[2]; /* 60-61 */ - u16 wIDIsingleWordDMA; /* 62 */ - u16 wIDImultiWordDMA; /* 63 */ - u16 wIDIreserved4[192]; /* 64-255 */ -}; - -struct ms_bootblock_sysent_rec { - u32 dwStart; - u32 dwSize; - u8 bType; - u8 bReserved[3]; -}; - -struct ms_bootblock_sysent { - struct ms_bootblock_sysent_rec entry[MS_NUMBER_OF_SYSTEM_ENTRY]; -}; - -struct ms_bootblock_sysinf { - u8 bMsClass; /* must be 1 */ - u8 bCardType; /* see below */ - u16 wBlockSize; /* n KB */ - u16 wBlockNumber; /* number of physical block */ - u16 wTotalBlockNumber; /* number of logical block */ - u16 wPageSize; /* must be 0x200 */ - u8 bExtraSize; /* 0x10 */ - u8 bSecuritySupport; - u8 bAssemblyDate[8]; - u8 bFactoryArea[4]; - u8 bAssemblyMakerCode; - u8 bAssemblyMachineCode[3]; - u16 wMemoryMakerCode; - u16 wMemoryDeviceCode; - u16 wMemorySize; - u8 bReserved1; - u8 bReserved2; - u8 bVCC; - u8 bVPP; - u16 wControllerChipNumber; - u16 wControllerFunction; /* New MS */ - u8 bReserved3[9]; /* New MS */ - u8 bParallelSupport; /* New MS */ - u16 wFormatValue; /* New MS */ - u8 bFormatType; - u8 bUsage; - u8 bDeviceType; - u8 bReserved4[22]; - u8 bFUValue3; - u8 bFUValue4; - u8 bReserved5[15]; -}; - -struct ms_bootblock_header { - u16 wBlockID; - u16 wFormatVersion; - u8 bReserved1[184]; - u8 bNumberOfDataEntry; - u8 bReserved2[179]; -}; - -struct ms_bootblock_page0 { - struct ms_bootblock_header header; - struct ms_bootblock_sysent sysent; - struct ms_bootblock_sysinf sysinf; -}; - -struct ms_bootblock_cis_idi { - union { - struct ms_bootblock_cis cis; - u8 dmy[256]; - } cis; - - union { - struct ms_bootblock_idi idi; - u8 dmy[256]; - } idi; - -}; - -/* ENE MS Lib struct */ -struct ms_lib_type_extdat { - u8 reserved; - u8 intr; - u8 status0; - u8 status1; - u8 ovrflg; - u8 mngflg; - u16 logadr; -}; - -struct ms_lib_ctrl { - u32 flags; - u32 BytesPerSector; - u32 NumberOfCylinder; - u32 SectorsPerCylinder; - u16 cardType; /* R/W, RO, Hybrid */ - u16 blockSize; - u16 PagesPerBlock; - u16 NumberOfPhyBlock; - u16 NumberOfLogBlock; - u16 NumberOfSegment; - u16 *Phy2LogMap; /* phy2log table */ - u16 *Log2PhyMap; /* log2phy table */ - u16 wrtblk; - unsigned char *pagemap[(MS_MAX_PAGES_PER_BLOCK + (MS_LIB_BITS_PER_BYTE-1)) / MS_LIB_BITS_PER_BYTE]; - unsigned char *blkpag; - struct ms_lib_type_extdat *blkext; - unsigned char copybuf[512]; -}; - - -/* SD Block Length */ -/* 2^9 = 512 Bytes, The HW maximum read/write data length */ -#define SD_BLOCK_LEN 9 - -struct ene_ub6250_info { - /* for 6250 code */ - struct SD_STATUS SD_Status; - struct MS_STATUS MS_Status; - struct SM_STATUS SM_Status; - - /* ----- SD Control Data ---------------- */ - /*SD_REGISTER SD_Regs; */ - u16 SD_Block_Mult; - u8 SD_READ_BL_LEN; - u16 SD_C_SIZE; - u8 SD_C_SIZE_MULT; - - /* SD/MMC New spec. */ - u8 SD_SPEC_VER; - u8 SD_CSD_VER; - u8 SD20_HIGH_CAPACITY; - u32 HC_C_SIZE; - u8 MMC_SPEC_VER; - u8 MMC_BusWidth; - u8 MMC_HIGH_CAPACITY; - - /*----- MS Control Data ---------------- */ - bool MS_SWWP; - u32 MSP_TotalBlock; - struct ms_lib_ctrl MS_Lib; - bool MS_IsRWPage; - u16 MS_Model; - - /*----- SM Control Data ---------------- */ - u8 SM_DeviceID; - u8 SM_CardID; - - unsigned char *testbuf; - u8 BIN_FLAG; - u32 bl_num; - int SrbStatus; - - /*------Power Managerment ---------------*/ - bool Power_IsResum; -}; - -static int ene_sd_init(struct us_data *us); -static int ene_ms_init(struct us_data *us); -static int ene_load_bincode(struct us_data *us, unsigned char flag); - -static void ene_ub6250_info_destructor(void *extra) -{ - if (!extra) - return; -} - -static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg) -{ - struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; - struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf; - - int result; - unsigned int residue; - unsigned int cswlen = 0, partial = 0; - unsigned int transfer_length = bcb->DataTransferLength; - - /* US_DEBUGP("transport --- ene_send_scsi_cmd\n"); */ - /* send cmd to out endpoint */ - result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, - bcb, US_BULK_CB_WRAP_LEN, NULL); - if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("send cmd to out endpoint fail ---\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - if (buf) { - unsigned int pipe = fDir; - - if (fDir == FDIR_READ) - pipe = us->recv_bulk_pipe; - else - pipe = us->send_bulk_pipe; - - /* Bulk */ - if (use_sg) { - result = usb_stor_bulk_srb(us, pipe, us->srb); - } else { - result = usb_stor_bulk_transfer_sg(us, pipe, buf, - transfer_length, 0, &partial); - } - if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("data transfer fail ---\n"); - return USB_STOR_TRANSPORT_ERROR; - } - } - - /* Get CSW for device status */ - result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, - US_BULK_CS_WRAP_LEN, &cswlen); - - if (result == USB_STOR_XFER_SHORT && cswlen == 0) { - US_DEBUGP("Received 0-length CSW; retrying...\n"); - result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, - bcs, US_BULK_CS_WRAP_LEN, &cswlen); - } - - if (result == USB_STOR_XFER_STALLED) { - /* get the status again */ - US_DEBUGP("Attempting to get CSW (2nd try)...\n"); - result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, - bcs, US_BULK_CS_WRAP_LEN, NULL); - } - - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - /* check bulk status */ - residue = le32_to_cpu(bcs->Residue); - - /* try to compute the actual residue, based on how much data - * was really transferred and what the device tells us */ - if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE)) { - residue = min(residue, transfer_length); - if (us->srb != NULL) - scsi_set_resid(us->srb, max(scsi_get_resid(us->srb), - (int)residue)); - } - - if (bcs->Status != US_BULK_STAT_OK) - return USB_STOR_TRANSPORT_ERROR; - - return USB_STOR_TRANSPORT_GOOD; -} - -static int sd_scsi_test_unit_ready(struct us_data *us, struct scsi_cmnd *srb) -{ - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - if (info->SD_Status.Insert && info->SD_Status.Ready) - return USB_STOR_TRANSPORT_GOOD; - else { - ene_sd_init(us); - return USB_STOR_TRANSPORT_GOOD; - } - - return USB_STOR_TRANSPORT_GOOD; -} - -static int sd_scsi_inquiry(struct us_data *us, struct scsi_cmnd *srb) -{ - unsigned char data_ptr[36] = { - 0x00, 0x80, 0x02, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x55, - 0x53, 0x42, 0x32, 0x2E, 0x30, 0x20, 0x20, 0x43, 0x61, - 0x72, 0x64, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x31, 0x30, 0x30 }; - - usb_stor_set_xfer_buf(data_ptr, 36, srb); - return USB_STOR_TRANSPORT_GOOD; -} - -static int sd_scsi_mode_sense(struct us_data *us, struct scsi_cmnd *srb) -{ - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - unsigned char mediaNoWP[12] = { - 0x0b, 0x00, 0x00, 0x08, 0x00, 0x00, - 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 }; - unsigned char mediaWP[12] = { - 0x0b, 0x00, 0x80, 0x08, 0x00, 0x00, - 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 }; - - if (info->SD_Status.WtP) - usb_stor_set_xfer_buf(mediaWP, 12, srb); - else - usb_stor_set_xfer_buf(mediaNoWP, 12, srb); - - - return USB_STOR_TRANSPORT_GOOD; -} - -static int sd_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb) -{ - u32 bl_num; - u32 bl_len; - unsigned int offset = 0; - unsigned char buf[8]; - struct scatterlist *sg = NULL; - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - US_DEBUGP("sd_scsi_read_capacity\n"); - if (info->SD_Status.HiCapacity) { - bl_len = 0x200; - if (info->SD_Status.IsMMC) - bl_num = info->HC_C_SIZE-1; - else - bl_num = (info->HC_C_SIZE + 1) * 1024 - 1; - } else { - bl_len = 1 << (info->SD_READ_BL_LEN); - bl_num = info->SD_Block_Mult * (info->SD_C_SIZE + 1) - * (1 << (info->SD_C_SIZE_MULT + 2)) - 1; - } - info->bl_num = bl_num; - US_DEBUGP("bl_len = %x\n", bl_len); - US_DEBUGP("bl_num = %x\n", bl_num); - - /*srb->request_bufflen = 8; */ - buf[0] = (bl_num >> 24) & 0xff; - buf[1] = (bl_num >> 16) & 0xff; - buf[2] = (bl_num >> 8) & 0xff; - buf[3] = (bl_num >> 0) & 0xff; - buf[4] = (bl_len >> 24) & 0xff; - buf[5] = (bl_len >> 16) & 0xff; - buf[6] = (bl_len >> 8) & 0xff; - buf[7] = (bl_len >> 0) & 0xff; - - usb_stor_access_xfer_buf(buf, 8, srb, &sg, &offset, TO_XFER_BUF); - - return USB_STOR_TRANSPORT_GOOD; -} - -static int sd_scsi_read(struct us_data *us, struct scsi_cmnd *srb) -{ - int result; - unsigned char *cdb = srb->cmnd; - struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - u32 bn = ((cdb[2] << 24) & 0xff000000) | ((cdb[3] << 16) & 0x00ff0000) | - ((cdb[4] << 8) & 0x0000ff00) | ((cdb[5] << 0) & 0x000000ff); - u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff); - u32 bnByte = bn * 0x200; - u32 blenByte = blen * 0x200; - - if (bn > info->bl_num) - return USB_STOR_TRANSPORT_ERROR; - - result = ene_load_bincode(us, SD_RW_PATTERN); - if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Load SD RW pattern Fail !!\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - if (info->SD_Status.HiCapacity) - bnByte = bn; - - /* set up the command wrapper */ - memset(bcb, 0, sizeof(struct bulk_cb_wrap)); - bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb->DataTransferLength = blenByte; - bcb->Flags = US_BULK_FLAG_IN; - bcb->CDB[0] = 0xF1; - bcb->CDB[5] = (unsigned char)(bnByte); - bcb->CDB[4] = (unsigned char)(bnByte>>8); - bcb->CDB[3] = (unsigned char)(bnByte>>16); - bcb->CDB[2] = (unsigned char)(bnByte>>24); - - result = ene_send_scsi_cmd(us, FDIR_READ, scsi_sglist(srb), 1); - return result; -} - -static int sd_scsi_write(struct us_data *us, struct scsi_cmnd *srb) -{ - int result; - unsigned char *cdb = srb->cmnd; - struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - u32 bn = ((cdb[2] << 24) & 0xff000000) | ((cdb[3] << 16) & 0x00ff0000) | - ((cdb[4] << 8) & 0x0000ff00) | ((cdb[5] << 0) & 0x000000ff); - u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff); - u32 bnByte = bn * 0x200; - u32 blenByte = blen * 0x200; - - if (bn > info->bl_num) - return USB_STOR_TRANSPORT_ERROR; - - result = ene_load_bincode(us, SD_RW_PATTERN); - if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Load SD RW pattern Fail !!\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - if (info->SD_Status.HiCapacity) - bnByte = bn; - - /* set up the command wrapper */ - memset(bcb, 0, sizeof(struct bulk_cb_wrap)); - bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb->DataTransferLength = blenByte; - bcb->Flags = 0x00; - bcb->CDB[0] = 0xF0; - bcb->CDB[5] = (unsigned char)(bnByte); - bcb->CDB[4] = (unsigned char)(bnByte>>8); - bcb->CDB[3] = (unsigned char)(bnByte>>16); - bcb->CDB[2] = (unsigned char)(bnByte>>24); - - result = ene_send_scsi_cmd(us, FDIR_WRITE, scsi_sglist(srb), 1); - return result; -} - -/* - * ENE MS Card - */ - -static int ms_lib_set_logicalpair(struct us_data *us, u16 logblk, u16 phyblk) -{ - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - if ((logblk >= info->MS_Lib.NumberOfLogBlock) || (phyblk >= info->MS_Lib.NumberOfPhyBlock)) - return (u32)-1; - - info->MS_Lib.Phy2LogMap[phyblk] = logblk; - info->MS_Lib.Log2PhyMap[logblk] = phyblk; - - return 0; -} - -static int ms_lib_set_logicalblockmark(struct us_data *us, u16 phyblk, u16 mark) -{ - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - if (phyblk >= info->MS_Lib.NumberOfPhyBlock) - return (u32)-1; - - info->MS_Lib.Phy2LogMap[phyblk] = mark; - - return 0; -} - -static int ms_lib_set_initialerrorblock(struct us_data *us, u16 phyblk) -{ - return ms_lib_set_logicalblockmark(us, phyblk, MS_LB_INITIAL_ERROR); -} - -static int ms_lib_set_bootblockmark(struct us_data *us, u16 phyblk) -{ - return ms_lib_set_logicalblockmark(us, phyblk, MS_LB_BOOT_BLOCK); -} - -static int ms_lib_free_logicalmap(struct us_data *us) -{ - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - kfree(info->MS_Lib.Phy2LogMap); - info->MS_Lib.Phy2LogMap = NULL; - - kfree(info->MS_Lib.Log2PhyMap); - info->MS_Lib.Log2PhyMap = NULL; - - return 0; -} - -static int ms_lib_alloc_logicalmap(struct us_data *us) -{ - u32 i; - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - info->MS_Lib.Phy2LogMap = kmalloc(info->MS_Lib.NumberOfPhyBlock * sizeof(u16), GFP_KERNEL); - info->MS_Lib.Log2PhyMap = kmalloc(info->MS_Lib.NumberOfLogBlock * sizeof(u16), GFP_KERNEL); - - if ((info->MS_Lib.Phy2LogMap == NULL) || (info->MS_Lib.Log2PhyMap == NULL)) { - ms_lib_free_logicalmap(us); - return (u32)-1; - } - - for (i = 0; i < info->MS_Lib.NumberOfPhyBlock; i++) - info->MS_Lib.Phy2LogMap[i] = MS_LB_NOT_USED; - - for (i = 0; i < info->MS_Lib.NumberOfLogBlock; i++) - info->MS_Lib.Log2PhyMap[i] = MS_LB_NOT_USED; - - return 0; -} - -static void ms_lib_clear_writebuf(struct us_data *us) -{ - int i; - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - info->MS_Lib.wrtblk = (u16)-1; - ms_lib_clear_pagemap(info); - - if (info->MS_Lib.blkpag) - memset(info->MS_Lib.blkpag, 0xff, info->MS_Lib.PagesPerBlock * info->MS_Lib.BytesPerSector); - - if (info->MS_Lib.blkext) { - for (i = 0; i < info->MS_Lib.PagesPerBlock; i++) { - info->MS_Lib.blkext[i].status1 = MS_REG_ST1_DEFAULT; - info->MS_Lib.blkext[i].ovrflg = MS_REG_OVR_DEFAULT; - info->MS_Lib.blkext[i].mngflg = MS_REG_MNG_DEFAULT; - info->MS_Lib.blkext[i].logadr = MS_LB_NOT_USED; - } - } -} - -static int ms_count_freeblock(struct us_data *us, u16 PhyBlock) -{ - u32 Ende, Count; - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - Ende = PhyBlock + MS_PHYSICAL_BLOCKS_PER_SEGMENT; - for (Count = 0; PhyBlock < Ende; PhyBlock++) { - switch (info->MS_Lib.Phy2LogMap[PhyBlock]) { - case MS_LB_NOT_USED: - case MS_LB_NOT_USED_ERASED: - Count++; - default: - break; - } - } - - return Count; -} - -static int ms_read_readpage(struct us_data *us, u32 PhyBlockAddr, - u8 PageNum, u32 *PageBuf, struct ms_lib_type_extdat *ExtraDat) -{ - struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; - int result; - u8 ExtBuf[4]; - u32 bn = PhyBlockAddr * 0x20 + PageNum; - - /* printk(KERN_INFO "MS --- MS_ReaderReadPage, - PhyBlockAddr = %x, PageNum = %x\n", PhyBlockAddr, PageNum); */ - - result = ene_load_bincode(us, MS_RW_PATTERN); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - /* Read Page Data */ - memset(bcb, 0, sizeof(struct bulk_cb_wrap)); - bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb->DataTransferLength = 0x200; - bcb->Flags = US_BULK_FLAG_IN; - bcb->CDB[0] = 0xF1; - - bcb->CDB[1] = 0x02; /* in init.c ENE_MSInit() is 0x01 */ - - bcb->CDB[5] = (unsigned char)(bn); - bcb->CDB[4] = (unsigned char)(bn>>8); - bcb->CDB[3] = (unsigned char)(bn>>16); - bcb->CDB[2] = (unsigned char)(bn>>24); - - result = ene_send_scsi_cmd(us, FDIR_READ, PageBuf, 0); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - - /* Read Extra Data */ - memset(bcb, 0, sizeof(struct bulk_cb_wrap)); - bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb->DataTransferLength = 0x4; - bcb->Flags = US_BULK_FLAG_IN; - bcb->CDB[0] = 0xF1; - bcb->CDB[1] = 0x03; - - bcb->CDB[5] = (unsigned char)(PageNum); - bcb->CDB[4] = (unsigned char)(PhyBlockAddr); - bcb->CDB[3] = (unsigned char)(PhyBlockAddr>>8); - bcb->CDB[2] = (unsigned char)(PhyBlockAddr>>16); - bcb->CDB[6] = 0x01; - - result = ene_send_scsi_cmd(us, FDIR_READ, &ExtBuf, 0); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - ExtraDat->reserved = 0; - ExtraDat->intr = 0x80; /* Not yet,fireware support */ - ExtraDat->status0 = 0x10; /* Not yet,fireware support */ - - ExtraDat->status1 = 0x00; /* Not yet,fireware support */ - ExtraDat->ovrflg = ExtBuf[0]; - ExtraDat->mngflg = ExtBuf[1]; - ExtraDat->logadr = memstick_logaddr(ExtBuf[2], ExtBuf[3]); - - return USB_STOR_TRANSPORT_GOOD; -} - -static int ms_lib_process_bootblock(struct us_data *us, u16 PhyBlock, u8 *PageData) -{ - struct ms_bootblock_sysent *SysEntry; - struct ms_bootblock_sysinf *SysInfo; - u32 i, result; - u8 PageNumber; - u8 *PageBuffer; - struct ms_lib_type_extdat ExtraData; - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - PageBuffer = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL); - if (PageBuffer == NULL) - return (u32)-1; - - result = (u32)-1; - - SysInfo = &(((struct ms_bootblock_page0 *)PageData)->sysinf); - - if ((SysInfo->bMsClass != MS_SYSINF_MSCLASS_TYPE_1) || - (be16_to_cpu(SysInfo->wPageSize) != MS_SYSINF_PAGE_SIZE) || - ((SysInfo->bSecuritySupport & MS_SYSINF_SECURITY) == MS_SYSINF_SECURITY_SUPPORT) || - (SysInfo->bReserved1 != MS_SYSINF_RESERVED1) || - (SysInfo->bReserved2 != MS_SYSINF_RESERVED2) || - (SysInfo->bFormatType != MS_SYSINF_FORMAT_FAT) || - (SysInfo->bUsage != MS_SYSINF_USAGE_GENERAL)) - goto exit; - /* */ - switch (info->MS_Lib.cardType = SysInfo->bCardType) { - case MS_SYSINF_CARDTYPE_RDONLY: - ms_lib_ctrl_set(info, MS_LIB_CTRL_RDONLY); - break; - case MS_SYSINF_CARDTYPE_RDWR: - ms_lib_ctrl_reset(info, MS_LIB_CTRL_RDONLY); - break; - case MS_SYSINF_CARDTYPE_HYBRID: - default: - goto exit; - } - - info->MS_Lib.blockSize = be16_to_cpu(SysInfo->wBlockSize); - info->MS_Lib.NumberOfPhyBlock = be16_to_cpu(SysInfo->wBlockNumber); - info->MS_Lib.NumberOfLogBlock = be16_to_cpu(SysInfo->wTotalBlockNumber)-2; - info->MS_Lib.PagesPerBlock = info->MS_Lib.blockSize * SIZE_OF_KIRO / MS_BYTES_PER_PAGE; - info->MS_Lib.NumberOfSegment = info->MS_Lib.NumberOfPhyBlock / MS_PHYSICAL_BLOCKS_PER_SEGMENT; - info->MS_Model = be16_to_cpu(SysInfo->wMemorySize); - - /*Allocate to all number of logicalblock and physicalblock */ - if (ms_lib_alloc_logicalmap(us)) - goto exit; - - /* Mark the book block */ - ms_lib_set_bootblockmark(us, PhyBlock); - - SysEntry = &(((struct ms_bootblock_page0 *)PageData)->sysent); - - for (i = 0; i < MS_NUMBER_OF_SYSTEM_ENTRY; i++) { - u32 EntryOffset, EntrySize; - - EntryOffset = be32_to_cpu(SysEntry->entry[i].dwStart); - - if (EntryOffset == 0xffffff) - continue; - EntrySize = be32_to_cpu(SysEntry->entry[i].dwSize); - - if (EntrySize == 0) - continue; - - if (EntryOffset + MS_BYTES_PER_PAGE + EntrySize > info->MS_Lib.blockSize * (u32)SIZE_OF_KIRO) - continue; - - if (i == 0) { - u8 PrevPageNumber = 0; - u16 phyblk; - - if (SysEntry->entry[i].bType != MS_SYSENT_TYPE_INVALID_BLOCK) - goto exit; - - while (EntrySize > 0) { - - PageNumber = (u8)(EntryOffset / MS_BYTES_PER_PAGE + 1); - if (PageNumber != PrevPageNumber) { - switch (ms_read_readpage(us, PhyBlock, PageNumber, (u32 *)PageBuffer, &ExtraData)) { - case MS_STATUS_SUCCESS: - break; - case MS_STATUS_WRITE_PROTECT: - case MS_ERROR_FLASH_READ: - case MS_STATUS_ERROR: - default: - goto exit; - } - - PrevPageNumber = PageNumber; - } - - phyblk = be16_to_cpu(*(u16 *)(PageBuffer + (EntryOffset % MS_BYTES_PER_PAGE))); - if (phyblk < 0x0fff) - ms_lib_set_initialerrorblock(us, phyblk); - - EntryOffset += 2; - EntrySize -= 2; - } - } else if (i == 1) { /* CIS/IDI */ - struct ms_bootblock_idi *idi; - - if (SysEntry->entry[i].bType != MS_SYSENT_TYPE_CIS_IDI) - goto exit; - - switch (ms_read_readpage(us, PhyBlock, (u8)(EntryOffset / MS_BYTES_PER_PAGE + 1), (u32 *)PageBuffer, &ExtraData)) { - case MS_STATUS_SUCCESS: - break; - case MS_STATUS_WRITE_PROTECT: - case MS_ERROR_FLASH_READ: - case MS_STATUS_ERROR: - default: - goto exit; - } - - idi = &((struct ms_bootblock_cis_idi *)(PageBuffer + (EntryOffset % MS_BYTES_PER_PAGE)))->idi.idi; - if (le16_to_cpu(idi->wIDIgeneralConfiguration) != MS_IDI_GENERAL_CONF) - goto exit; - - info->MS_Lib.BytesPerSector = le16_to_cpu(idi->wIDIbytesPerSector); - if (info->MS_Lib.BytesPerSector != MS_BYTES_PER_PAGE) - goto exit; - } - } /* End for .. */ - - result = 0; - -exit: - if (result) - ms_lib_free_logicalmap(us); - - kfree(PageBuffer); - - result = 0; - return result; -} - -static void ms_lib_free_writebuf(struct us_data *us) -{ - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - info->MS_Lib.wrtblk = (u16)-1; /* set to -1 */ - - /* memset((fdoExt)->MS_Lib.pagemap, 0, sizeof((fdoExt)->MS_Lib.pagemap)) */ - - ms_lib_clear_pagemap(info); /* (pdx)->MS_Lib.pagemap memset 0 in ms.h */ - - if (info->MS_Lib.blkpag) { - kfree((u8 *)(info->MS_Lib.blkpag)); /* Arnold test ... */ - info->MS_Lib.blkpag = NULL; - } - - if (info->MS_Lib.blkext) { - kfree((u8 *)(info->MS_Lib.blkext)); /* Arnold test ... */ - info->MS_Lib.blkext = NULL; - } -} - - -static void ms_lib_free_allocatedarea(struct us_data *us) -{ - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - ms_lib_free_writebuf(us); /* Free MS_Lib.pagemap */ - ms_lib_free_logicalmap(us); /* kfree MS_Lib.Phy2LogMap and MS_Lib.Log2PhyMap */ - - /* set struct us point flag to 0 */ - info->MS_Lib.flags = 0; - info->MS_Lib.BytesPerSector = 0; - info->MS_Lib.SectorsPerCylinder = 0; - - info->MS_Lib.cardType = 0; - info->MS_Lib.blockSize = 0; - info->MS_Lib.PagesPerBlock = 0; - - info->MS_Lib.NumberOfPhyBlock = 0; - info->MS_Lib.NumberOfLogBlock = 0; -} - - -static int ms_lib_alloc_writebuf(struct us_data *us) -{ - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - info->MS_Lib.wrtblk = (u16)-1; - - info->MS_Lib.blkpag = kmalloc(info->MS_Lib.PagesPerBlock * info->MS_Lib.BytesPerSector, GFP_KERNEL); - info->MS_Lib.blkext = kmalloc(info->MS_Lib.PagesPerBlock * sizeof(struct ms_lib_type_extdat), GFP_KERNEL); - - if ((info->MS_Lib.blkpag == NULL) || (info->MS_Lib.blkext == NULL)) { - ms_lib_free_writebuf(us); - return (u32)-1; - } - - ms_lib_clear_writebuf(us); - -return 0; -} - -static int ms_lib_force_setlogical_pair(struct us_data *us, u16 logblk, u16 phyblk) -{ - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - if (logblk == MS_LB_NOT_USED) - return 0; - - if ((logblk >= info->MS_Lib.NumberOfLogBlock) || - (phyblk >= info->MS_Lib.NumberOfPhyBlock)) - return (u32)-1; - - info->MS_Lib.Phy2LogMap[phyblk] = logblk; - info->MS_Lib.Log2PhyMap[logblk] = phyblk; - - return 0; -} - -static int ms_read_copyblock(struct us_data *us, u16 oldphy, u16 newphy, - u16 PhyBlockAddr, u8 PageNum, unsigned char *buf, u16 len) -{ - struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; - int result; - - /* printk(KERN_INFO "MS_ReaderCopyBlock --- PhyBlockAddr = %x, - PageNum = %x\n", PhyBlockAddr, PageNum); */ - result = ene_load_bincode(us, MS_RW_PATTERN); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - memset(bcb, 0, sizeof(struct bulk_cb_wrap)); - bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb->DataTransferLength = 0x200*len; - bcb->Flags = 0x00; - bcb->CDB[0] = 0xF0; - bcb->CDB[1] = 0x08; - bcb->CDB[4] = (unsigned char)(oldphy); - bcb->CDB[3] = (unsigned char)(oldphy>>8); - bcb->CDB[2] = 0; /* (BYTE)(oldphy>>16) */ - bcb->CDB[7] = (unsigned char)(newphy); - bcb->CDB[6] = (unsigned char)(newphy>>8); - bcb->CDB[5] = 0; /* (BYTE)(newphy>>16) */ - bcb->CDB[9] = (unsigned char)(PhyBlockAddr); - bcb->CDB[8] = (unsigned char)(PhyBlockAddr>>8); - bcb->CDB[10] = PageNum; - - result = ene_send_scsi_cmd(us, FDIR_WRITE, buf, 0); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - return USB_STOR_TRANSPORT_GOOD; -} - -static int ms_read_eraseblock(struct us_data *us, u32 PhyBlockAddr) -{ - struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; - int result; - u32 bn = PhyBlockAddr; - - /* printk(KERN_INFO "MS --- ms_read_eraseblock, - PhyBlockAddr = %x\n", PhyBlockAddr); */ - result = ene_load_bincode(us, MS_RW_PATTERN); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - memset(bcb, 0, sizeof(struct bulk_cb_wrap)); - bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb->DataTransferLength = 0x200; - bcb->Flags = US_BULK_FLAG_IN; - bcb->CDB[0] = 0xF2; - bcb->CDB[1] = 0x06; - bcb->CDB[4] = (unsigned char)(bn); - bcb->CDB[3] = (unsigned char)(bn>>8); - bcb->CDB[2] = (unsigned char)(bn>>16); - - result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - return USB_STOR_TRANSPORT_GOOD; -} - -static int ms_lib_check_disableblock(struct us_data *us, u16 PhyBlock) -{ - unsigned char *PageBuf = NULL; - u16 result = MS_STATUS_SUCCESS; - u16 blk, index = 0; - struct ms_lib_type_extdat extdat; - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - PageBuf = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL); - if (PageBuf == NULL) { - result = MS_NO_MEMORY_ERROR; - goto exit; - } - - ms_read_readpage(us, PhyBlock, 1, (u32 *)PageBuf, &extdat); - do { - blk = be16_to_cpu(PageBuf[index]); - if (blk == MS_LB_NOT_USED) - break; - if (blk == info->MS_Lib.Log2PhyMap[0]) { - result = MS_ERROR_FLASH_READ; - break; - } - index++; - } while (1); - -exit: - kfree(PageBuf); - return result; -} - -static int ms_lib_setacquired_errorblock(struct us_data *us, u16 phyblk) -{ - u16 log; - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - if (phyblk >= info->MS_Lib.NumberOfPhyBlock) - return (u32)-1; - - log = info->MS_Lib.Phy2LogMap[phyblk]; - - if (log < info->MS_Lib.NumberOfLogBlock) - info->MS_Lib.Log2PhyMap[log] = MS_LB_NOT_USED; - - if (info->MS_Lib.Phy2LogMap[phyblk] != MS_LB_INITIAL_ERROR) - info->MS_Lib.Phy2LogMap[phyblk] = MS_LB_ACQUIRED_ERROR; - - return 0; -} - -static int ms_lib_overwrite_extra(struct us_data *us, u32 PhyBlockAddr, - u8 PageNum, u8 OverwriteFlag) -{ - struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; - int result; - - /* printk("MS --- MS_LibOverwriteExtra, - PhyBlockAddr = %x, PageNum = %x\n", PhyBlockAddr, PageNum); */ - result = ene_load_bincode(us, MS_RW_PATTERN); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - memset(bcb, 0, sizeof(struct bulk_cb_wrap)); - bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb->DataTransferLength = 0x4; - bcb->Flags = US_BULK_FLAG_IN; - bcb->CDB[0] = 0xF2; - bcb->CDB[1] = 0x05; - bcb->CDB[5] = (unsigned char)(PageNum); - bcb->CDB[4] = (unsigned char)(PhyBlockAddr); - bcb->CDB[3] = (unsigned char)(PhyBlockAddr>>8); - bcb->CDB[2] = (unsigned char)(PhyBlockAddr>>16); - bcb->CDB[6] = OverwriteFlag; - bcb->CDB[7] = 0xFF; - bcb->CDB[8] = 0xFF; - bcb->CDB[9] = 0xFF; - - result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - return USB_STOR_TRANSPORT_GOOD; -} - -static int ms_lib_error_phyblock(struct us_data *us, u16 phyblk) -{ - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - if (phyblk >= info->MS_Lib.NumberOfPhyBlock) - return MS_STATUS_ERROR; - - ms_lib_setacquired_errorblock(us, phyblk); - - if (ms_lib_iswritable(info)) - return ms_lib_overwrite_extra(us, phyblk, 0, (u8)(~MS_REG_OVR_BKST & BYTE_MASK)); - - return MS_STATUS_SUCCESS; -} - -static int ms_lib_erase_phyblock(struct us_data *us, u16 phyblk) -{ - u16 log; - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - if (phyblk >= info->MS_Lib.NumberOfPhyBlock) - return MS_STATUS_ERROR; - - log = info->MS_Lib.Phy2LogMap[phyblk]; - - if (log < info->MS_Lib.NumberOfLogBlock) - info->MS_Lib.Log2PhyMap[log] = MS_LB_NOT_USED; - - info->MS_Lib.Phy2LogMap[phyblk] = MS_LB_NOT_USED; - - if (ms_lib_iswritable(info)) { - switch (ms_read_eraseblock(us, phyblk)) { - case MS_STATUS_SUCCESS: - info->MS_Lib.Phy2LogMap[phyblk] = MS_LB_NOT_USED_ERASED; - return MS_STATUS_SUCCESS; - case MS_ERROR_FLASH_ERASE: - case MS_STATUS_INT_ERROR: - ms_lib_error_phyblock(us, phyblk); - return MS_ERROR_FLASH_ERASE; - case MS_STATUS_ERROR: - default: - ms_lib_ctrl_set(info, MS_LIB_CTRL_RDONLY); /* MS_LibCtrlSet will used by ENE_MSInit ,need check, and why us to info*/ - ms_lib_setacquired_errorblock(us, phyblk); - return MS_STATUS_ERROR; - } - } - - ms_lib_setacquired_errorblock(us, phyblk); - - return MS_STATUS_SUCCESS; -} - -static int ms_lib_read_extra(struct us_data *us, u32 PhyBlock, - u8 PageNum, struct ms_lib_type_extdat *ExtraDat) -{ - struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; - int result; - u8 ExtBuf[4]; - - /* printk("MS_LibReadExtra --- PhyBlock = %x, PageNum = %x\n", PhyBlock, PageNum); */ - memset(bcb, 0, sizeof(struct bulk_cb_wrap)); - bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb->DataTransferLength = 0x4; - bcb->Flags = US_BULK_FLAG_IN; - bcb->CDB[0] = 0xF1; - bcb->CDB[1] = 0x03; - bcb->CDB[5] = (unsigned char)(PageNum); - bcb->CDB[4] = (unsigned char)(PhyBlock); - bcb->CDB[3] = (unsigned char)(PhyBlock>>8); - bcb->CDB[2] = (unsigned char)(PhyBlock>>16); - bcb->CDB[6] = 0x01; - - result = ene_send_scsi_cmd(us, FDIR_READ, &ExtBuf, 0); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - ExtraDat->reserved = 0; - ExtraDat->intr = 0x80; /* Not yet, waiting for fireware support */ - ExtraDat->status0 = 0x10; /* Not yet, waiting for fireware support */ - ExtraDat->status1 = 0x00; /* Not yet, waiting for fireware support */ - ExtraDat->ovrflg = ExtBuf[0]; - ExtraDat->mngflg = ExtBuf[1]; - ExtraDat->logadr = memstick_logaddr(ExtBuf[2], ExtBuf[3]); - - return USB_STOR_TRANSPORT_GOOD; -} - -static int ms_libsearch_block_from_physical(struct us_data *us, u16 phyblk) -{ - u16 Newblk; - u16 blk; - struct ms_lib_type_extdat extdat; /* need check */ - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - - if (phyblk >= info->MS_Lib.NumberOfPhyBlock) - return MS_LB_ERROR; - - for (blk = phyblk + 1; blk != phyblk; blk++) { - if ((blk & MS_PHYSICAL_BLOCKS_PER_SEGMENT_MASK) == 0) - blk -= MS_PHYSICAL_BLOCKS_PER_SEGMENT; - - Newblk = info->MS_Lib.Phy2LogMap[blk]; - if (info->MS_Lib.Phy2LogMap[blk] == MS_LB_NOT_USED_ERASED) { - return blk; - } else if (info->MS_Lib.Phy2LogMap[blk] == MS_LB_NOT_USED) { - switch (ms_lib_read_extra(us, blk, 0, &extdat)) { - case MS_STATUS_SUCCESS: - case MS_STATUS_SUCCESS_WITH_ECC: - break; - case MS_NOCARD_ERROR: - return MS_NOCARD_ERROR; - case MS_STATUS_INT_ERROR: - return MS_LB_ERROR; - case MS_ERROR_FLASH_READ: - default: - ms_lib_setacquired_errorblock(us, blk); - continue; - } /* End switch */ - - if ((extdat.ovrflg & MS_REG_OVR_BKST) != MS_REG_OVR_BKST_OK) { - ms_lib_setacquired_errorblock(us, blk); - continue; - } - - switch (ms_lib_erase_phyblock(us, blk)) { - case MS_STATUS_SUCCESS: - return blk; - case MS_STATUS_ERROR: - return MS_LB_ERROR; - case MS_ERROR_FLASH_ERASE: - default: - ms_lib_error_phyblock(us, blk); - break; - } - } - } /* End for */ - - return MS_LB_ERROR; -} -static int ms_libsearch_block_from_logical(struct us_data *us, u16 logblk) -{ - u16 phyblk; - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - phyblk = ms_libconv_to_physical(info, logblk); - if (phyblk >= MS_LB_ERROR) { - if (logblk >= info->MS_Lib.NumberOfLogBlock) - return MS_LB_ERROR; - - phyblk = (logblk + MS_NUMBER_OF_BOOT_BLOCK) / MS_LOGICAL_BLOCKS_PER_SEGMENT; - phyblk *= MS_PHYSICAL_BLOCKS_PER_SEGMENT; - phyblk += MS_PHYSICAL_BLOCKS_PER_SEGMENT - 1; - } - - return ms_libsearch_block_from_physical(us, phyblk); -} - -static int ms_scsi_test_unit_ready(struct us_data *us, struct scsi_cmnd *srb) -{ - struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra); - - /* pr_info("MS_SCSI_Test_Unit_Ready\n"); */ - if (info->MS_Status.Insert && info->MS_Status.Ready) { - return USB_STOR_TRANSPORT_GOOD; - } else { - ene_ms_init(us); - return USB_STOR_TRANSPORT_GOOD; - } - - return USB_STOR_TRANSPORT_GOOD; -} - -static int ms_scsi_inquiry(struct us_data *us, struct scsi_cmnd *srb) -{ - /* pr_info("MS_SCSI_Inquiry\n"); */ - unsigned char data_ptr[36] = { - 0x00, 0x80, 0x02, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x55, - 0x53, 0x42, 0x32, 0x2E, 0x30, 0x20, 0x20, 0x43, 0x61, - 0x72, 0x64, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x31, 0x30, 0x30}; - - usb_stor_set_xfer_buf(data_ptr, 36, srb); - return USB_STOR_TRANSPORT_GOOD; -} - -static int ms_scsi_mode_sense(struct us_data *us, struct scsi_cmnd *srb) -{ - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - unsigned char mediaNoWP[12] = { - 0x0b, 0x00, 0x00, 0x08, 0x00, 0x00, - 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 }; - unsigned char mediaWP[12] = { - 0x0b, 0x00, 0x80, 0x08, 0x00, 0x00, - 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 }; - - if (info->MS_Status.WtP) - usb_stor_set_xfer_buf(mediaWP, 12, srb); - else - usb_stor_set_xfer_buf(mediaNoWP, 12, srb); - - return USB_STOR_TRANSPORT_GOOD; -} - -static int ms_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb) -{ - u32 bl_num; - u16 bl_len; - unsigned int offset = 0; - unsigned char buf[8]; - struct scatterlist *sg = NULL; - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - US_DEBUGP("ms_scsi_read_capacity\n"); - bl_len = 0x200; - if (info->MS_Status.IsMSPro) - bl_num = info->MSP_TotalBlock - 1; - else - bl_num = info->MS_Lib.NumberOfLogBlock * info->MS_Lib.blockSize * 2 - 1; - - info->bl_num = bl_num; - US_DEBUGP("bl_len = %x\n", bl_len); - US_DEBUGP("bl_num = %x\n", bl_num); - - /*srb->request_bufflen = 8; */ - buf[0] = (bl_num >> 24) & 0xff; - buf[1] = (bl_num >> 16) & 0xff; - buf[2] = (bl_num >> 8) & 0xff; - buf[3] = (bl_num >> 0) & 0xff; - buf[4] = (bl_len >> 24) & 0xff; - buf[5] = (bl_len >> 16) & 0xff; - buf[6] = (bl_len >> 8) & 0xff; - buf[7] = (bl_len >> 0) & 0xff; - - usb_stor_access_xfer_buf(buf, 8, srb, &sg, &offset, TO_XFER_BUF); - - return USB_STOR_TRANSPORT_GOOD; -} - -static void ms_lib_phy_to_log_range(u16 PhyBlock, u16 *LogStart, u16 *LogEnde) -{ - PhyBlock /= MS_PHYSICAL_BLOCKS_PER_SEGMENT; - - if (PhyBlock) { - *LogStart = MS_LOGICAL_BLOCKS_IN_1ST_SEGMENT + (PhyBlock - 1) * MS_LOGICAL_BLOCKS_PER_SEGMENT;/*496*/ - *LogEnde = *LogStart + MS_LOGICAL_BLOCKS_PER_SEGMENT;/*496*/ - } else { - *LogStart = 0; - *LogEnde = MS_LOGICAL_BLOCKS_IN_1ST_SEGMENT;/*494*/ - } -} - -static int ms_lib_read_extrablock(struct us_data *us, u32 PhyBlock, - u8 PageNum, u8 blen, void *buf) -{ - struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; - int result; - - /* printk("MS_LibReadExtraBlock --- PhyBlock = %x, - PageNum = %x, blen = %x\n", PhyBlock, PageNum, blen); */ - - /* Read Extra Data */ - memset(bcb, 0, sizeof(struct bulk_cb_wrap)); - bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb->DataTransferLength = 0x4 * blen; - bcb->Flags = US_BULK_FLAG_IN; - bcb->CDB[0] = 0xF1; - bcb->CDB[1] = 0x03; - bcb->CDB[5] = (unsigned char)(PageNum); - bcb->CDB[4] = (unsigned char)(PhyBlock); - bcb->CDB[3] = (unsigned char)(PhyBlock>>8); - bcb->CDB[2] = (unsigned char)(PhyBlock>>16); - bcb->CDB[6] = blen; - - result = ene_send_scsi_cmd(us, FDIR_READ, buf, 0); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - return USB_STOR_TRANSPORT_GOOD; -} - -static int ms_lib_scan_logicalblocknumber(struct us_data *us, u16 btBlk1st) -{ - u16 PhyBlock, newblk, i; - u16 LogStart, LogEnde; - struct ms_lib_type_extdat extdat; - u8 buf[0x200]; - u32 count = 0, index = 0; - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - for (PhyBlock = 0; PhyBlock < info->MS_Lib.NumberOfPhyBlock;) { - ms_lib_phy_to_log_range(PhyBlock, &LogStart, &LogEnde); - - for (i = 0; i < MS_PHYSICAL_BLOCKS_PER_SEGMENT; i++, PhyBlock++) { - switch (ms_libconv_to_logical(info, PhyBlock)) { - case MS_STATUS_ERROR: - continue; - default: - break; - } - - if (count == PhyBlock) { - ms_lib_read_extrablock(us, PhyBlock, 0, 0x80, &buf); - count += 0x80; - } - index = (PhyBlock % 0x80) * 4; - - extdat.ovrflg = buf[index]; - extdat.mngflg = buf[index+1]; - extdat.logadr = memstick_logaddr(buf[index+2], buf[index+3]); - - if ((extdat.ovrflg & MS_REG_OVR_BKST) != MS_REG_OVR_BKST_OK) { - ms_lib_setacquired_errorblock(us, PhyBlock); - continue; - } - - if ((extdat.mngflg & MS_REG_MNG_ATFLG) == MS_REG_MNG_ATFLG_ATTBL) { - ms_lib_erase_phyblock(us, PhyBlock); - continue; - } - - if (extdat.logadr != MS_LB_NOT_USED) { - if ((extdat.logadr < LogStart) || (LogEnde <= extdat.logadr)) { - ms_lib_erase_phyblock(us, PhyBlock); - continue; - } - - newblk = ms_libconv_to_physical(info, extdat.logadr); - - if (newblk != MS_LB_NOT_USED) { - if (extdat.logadr == 0) { - ms_lib_set_logicalpair(us, extdat.logadr, PhyBlock); - if (ms_lib_check_disableblock(us, btBlk1st)) { - ms_lib_set_logicalpair(us, extdat.logadr, newblk); - continue; - } - } - - ms_lib_read_extra(us, newblk, 0, &extdat); - if ((extdat.ovrflg & MS_REG_OVR_UDST) == MS_REG_OVR_UDST_UPDATING) { - ms_lib_erase_phyblock(us, PhyBlock); - continue; - } else { - ms_lib_erase_phyblock(us, newblk); - } - } - - ms_lib_set_logicalpair(us, extdat.logadr, PhyBlock); - } - } - } /* End for ... */ - - return MS_STATUS_SUCCESS; -} - - -static int ms_scsi_read(struct us_data *us, struct scsi_cmnd *srb) -{ - int result; - unsigned char *cdb = srb->cmnd; - struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - u32 bn = ((cdb[2] << 24) & 0xff000000) | ((cdb[3] << 16) & 0x00ff0000) | - ((cdb[4] << 8) & 0x0000ff00) | ((cdb[5] << 0) & 0x000000ff); - u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff); - u32 blenByte = blen * 0x200; - - if (bn > info->bl_num) - return USB_STOR_TRANSPORT_ERROR; - - if (info->MS_Status.IsMSPro) { - result = ene_load_bincode(us, MSP_RW_PATTERN); - if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Load MPS RW pattern Fail !!\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - /* set up the command wrapper */ - memset(bcb, 0, sizeof(struct bulk_cb_wrap)); - bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb->DataTransferLength = blenByte; - bcb->Flags = US_BULK_FLAG_IN; - bcb->CDB[0] = 0xF1; - bcb->CDB[1] = 0x02; - bcb->CDB[5] = (unsigned char)(bn); - bcb->CDB[4] = (unsigned char)(bn>>8); - bcb->CDB[3] = (unsigned char)(bn>>16); - bcb->CDB[2] = (unsigned char)(bn>>24); - - result = ene_send_scsi_cmd(us, FDIR_READ, scsi_sglist(srb), 1); - } else { - void *buf; - int offset = 0; - u16 phyblk, logblk; - u8 PageNum; - u16 len; - u32 blkno; - - buf = kmalloc(blenByte, GFP_KERNEL); - if (buf == NULL) - return USB_STOR_TRANSPORT_ERROR; - - result = ene_load_bincode(us, MS_RW_PATTERN); - if (result != USB_STOR_XFER_GOOD) { - pr_info("Load MS RW pattern Fail !!\n"); - result = USB_STOR_TRANSPORT_ERROR; - goto exit; - } - - logblk = (u16)(bn / info->MS_Lib.PagesPerBlock); - PageNum = (u8)(bn % info->MS_Lib.PagesPerBlock); - - while (1) { - if (blen > (info->MS_Lib.PagesPerBlock-PageNum)) - len = info->MS_Lib.PagesPerBlock-PageNum; - else - len = blen; - - phyblk = ms_libconv_to_physical(info, logblk); - blkno = phyblk * 0x20 + PageNum; - - /* set up the command wrapper */ - memset(bcb, 0, sizeof(struct bulk_cb_wrap)); - bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb->DataTransferLength = 0x200 * len; - bcb->Flags = US_BULK_FLAG_IN; - bcb->CDB[0] = 0xF1; - bcb->CDB[1] = 0x02; - bcb->CDB[5] = (unsigned char)(blkno); - bcb->CDB[4] = (unsigned char)(blkno>>8); - bcb->CDB[3] = (unsigned char)(blkno>>16); - bcb->CDB[2] = (unsigned char)(blkno>>24); - - result = ene_send_scsi_cmd(us, FDIR_READ, buf+offset, 0); - if (result != USB_STOR_XFER_GOOD) { - pr_info("MS_SCSI_Read --- result = %x\n", result); - result = USB_STOR_TRANSPORT_ERROR; - goto exit; - } - - blen -= len; - if (blen <= 0) - break; - logblk++; - PageNum = 0; - offset += MS_BYTES_PER_PAGE*len; - } - usb_stor_set_xfer_buf(buf, blenByte, srb); -exit: - kfree(buf); - } - return result; -} - -static int ms_scsi_write(struct us_data *us, struct scsi_cmnd *srb) -{ - int result; - struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; - unsigned char *cdb = srb->cmnd; - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - u32 bn = ((cdb[2] << 24) & 0xff000000) | - ((cdb[3] << 16) & 0x00ff0000) | - ((cdb[4] << 8) & 0x0000ff00) | - ((cdb[5] << 0) & 0x000000ff); - u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff); - u32 blenByte = blen * 0x200; - - if (bn > info->bl_num) - return USB_STOR_TRANSPORT_ERROR; - - if (info->MS_Status.IsMSPro) { - result = ene_load_bincode(us, MSP_RW_PATTERN); - if (result != USB_STOR_XFER_GOOD) { - pr_info("Load MSP RW pattern Fail !!\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - /* set up the command wrapper */ - memset(bcb, 0, sizeof(struct bulk_cb_wrap)); - bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb->DataTransferLength = blenByte; - bcb->Flags = 0x00; - bcb->CDB[0] = 0xF0; - bcb->CDB[1] = 0x04; - bcb->CDB[5] = (unsigned char)(bn); - bcb->CDB[4] = (unsigned char)(bn>>8); - bcb->CDB[3] = (unsigned char)(bn>>16); - bcb->CDB[2] = (unsigned char)(bn>>24); - - result = ene_send_scsi_cmd(us, FDIR_WRITE, scsi_sglist(srb), 1); - } else { - void *buf; - int offset = 0; - u16 PhyBlockAddr; - u8 PageNum; - u16 len, oldphy, newphy; - - buf = kmalloc(blenByte, GFP_KERNEL); - if (buf == NULL) - return USB_STOR_TRANSPORT_ERROR; - usb_stor_set_xfer_buf(buf, blenByte, srb); - - result = ene_load_bincode(us, MS_RW_PATTERN); - if (result != USB_STOR_XFER_GOOD) { - pr_info("Load MS RW pattern Fail !!\n"); - result = USB_STOR_TRANSPORT_ERROR; - goto exit; - } - - PhyBlockAddr = (u16)(bn / info->MS_Lib.PagesPerBlock); - PageNum = (u8)(bn % info->MS_Lib.PagesPerBlock); - - while (1) { - if (blen > (info->MS_Lib.PagesPerBlock-PageNum)) - len = info->MS_Lib.PagesPerBlock-PageNum; - else - len = blen; - - oldphy = ms_libconv_to_physical(info, PhyBlockAddr); /* need check us <-> info */ - newphy = ms_libsearch_block_from_logical(us, PhyBlockAddr); - - result = ms_read_copyblock(us, oldphy, newphy, PhyBlockAddr, PageNum, buf+offset, len); - - if (result != USB_STOR_XFER_GOOD) { - pr_info("MS_SCSI_Write --- result = %x\n", result); - result = USB_STOR_TRANSPORT_ERROR; - goto exit; - } - - info->MS_Lib.Phy2LogMap[oldphy] = MS_LB_NOT_USED_ERASED; - ms_lib_force_setlogical_pair(us, PhyBlockAddr, newphy); - - blen -= len; - if (blen <= 0) - break; - PhyBlockAddr++; - PageNum = 0; - offset += MS_BYTES_PER_PAGE*len; - } -exit: - kfree(buf); - } - return result; -} - -/* - * ENE MS Card - */ - -static int ene_get_card_type(struct us_data *us, u16 index, void *buf) -{ - struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; - int result; - - memset(bcb, 0, sizeof(struct bulk_cb_wrap)); - bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb->DataTransferLength = 0x01; - bcb->Flags = US_BULK_FLAG_IN; - bcb->CDB[0] = 0xED; - bcb->CDB[2] = (unsigned char)(index>>8); - bcb->CDB[3] = (unsigned char)index; - - result = ene_send_scsi_cmd(us, FDIR_READ, buf, 0); - return result; -} - -static int ene_get_card_status(struct us_data *us, u8 *buf) -{ - u16 tmpreg; - u32 reg4b; - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - /*US_DEBUGP("transport --- ENE_ReadSDReg\n");*/ - reg4b = *(u32 *)&buf[0x18]; - info->SD_READ_BL_LEN = (u8)((reg4b >> 8) & 0x0f); - - tmpreg = (u16) reg4b; - reg4b = *(u32 *)(&buf[0x14]); - if (info->SD_Status.HiCapacity && !info->SD_Status.IsMMC) - info->HC_C_SIZE = (reg4b >> 8) & 0x3fffff; - - info->SD_C_SIZE = ((tmpreg & 0x03) << 10) | (u16)(reg4b >> 22); - info->SD_C_SIZE_MULT = (u8)(reg4b >> 7) & 0x07; - if (info->SD_Status.HiCapacity && info->SD_Status.IsMMC) - info->HC_C_SIZE = *(u32 *)(&buf[0x100]); - - if (info->SD_READ_BL_LEN > SD_BLOCK_LEN) { - info->SD_Block_Mult = 1 << (info->SD_READ_BL_LEN-SD_BLOCK_LEN); - info->SD_READ_BL_LEN = SD_BLOCK_LEN; - } else { - info->SD_Block_Mult = 1; - } - - return USB_STOR_TRANSPORT_GOOD; -} - -static int ene_load_bincode(struct us_data *us, unsigned char flag) -{ - int err; - char *fw_name = NULL; - unsigned char *buf = NULL; - const struct firmware *sd_fw = NULL; - int result = USB_STOR_TRANSPORT_ERROR; - struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - if (info->BIN_FLAG == flag) - return USB_STOR_TRANSPORT_GOOD; - - switch (flag) { - /* For SD */ - case SD_INIT1_PATTERN: - US_DEBUGP("SD_INIT1_PATTERN\n"); - fw_name = "ene-ub6250/sd_init1.bin"; - break; - case SD_INIT2_PATTERN: - US_DEBUGP("SD_INIT2_PATTERN\n"); - fw_name = "ene-ub6250/sd_init2.bin"; - break; - case SD_RW_PATTERN: - US_DEBUGP("SD_RDWR_PATTERN\n"); - fw_name = "ene-ub6250/sd_rdwr.bin"; - break; - /* For MS */ - case MS_INIT_PATTERN: - US_DEBUGP("MS_INIT_PATTERN\n"); - fw_name = "ene-ub6250/ms_init.bin"; - break; - case MSP_RW_PATTERN: - US_DEBUGP("MSP_RW_PATTERN\n"); - fw_name = "ene-ub6250/msp_rdwr.bin"; - break; - case MS_RW_PATTERN: - US_DEBUGP("MS_RW_PATTERN\n"); - fw_name = "ene-ub6250/ms_rdwr.bin"; - break; - default: - US_DEBUGP("----------- Unknown PATTERN ----------\n"); - goto nofw; - } - - err = request_firmware(&sd_fw, fw_name, &us->pusb_dev->dev); - if (err) { - US_DEBUGP("load firmware %s failed\n", fw_name); - goto nofw; - } - buf = kmalloc(sd_fw->size, GFP_KERNEL); - if (buf == NULL) { - US_DEBUGP("Malloc memory for fireware failed!\n"); - goto nofw; - } - memcpy(buf, sd_fw->data, sd_fw->size); - memset(bcb, 0, sizeof(struct bulk_cb_wrap)); - bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb->DataTransferLength = sd_fw->size; - bcb->Flags = 0x00; - bcb->CDB[0] = 0xEF; - - result = ene_send_scsi_cmd(us, FDIR_WRITE, buf, 0); - info->BIN_FLAG = flag; - kfree(buf); - -nofw: - if (sd_fw != NULL) { - release_firmware(sd_fw); - sd_fw = NULL; - } - - return result; -} - -static int ms_card_init(struct us_data *us) -{ - u32 result; - u16 TmpBlock; - unsigned char *PageBuffer0 = NULL, *PageBuffer1 = NULL; - struct ms_lib_type_extdat extdat; - u16 btBlk1st, btBlk2nd; - u32 btBlk1stErred; - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - printk(KERN_INFO "MS_CardInit start\n"); - - ms_lib_free_allocatedarea(us); /* Clean buffer and set struct us_data flag to 0 */ - - /* get two PageBuffer */ - PageBuffer0 = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL); - PageBuffer1 = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL); - if ((PageBuffer0 == NULL) || (PageBuffer1 == NULL)) { - result = MS_NO_MEMORY_ERROR; - goto exit; - } - - btBlk1st = btBlk2nd = MS_LB_NOT_USED; - btBlk1stErred = 0; - - for (TmpBlock = 0; TmpBlock < MS_MAX_INITIAL_ERROR_BLOCKS+2; TmpBlock++) { - - switch (ms_read_readpage(us, TmpBlock, 0, (u32 *)PageBuffer0, &extdat)) { - case MS_STATUS_SUCCESS: - break; - case MS_STATUS_INT_ERROR: - break; - case MS_STATUS_ERROR: - default: - continue; - } - - if ((extdat.ovrflg & MS_REG_OVR_BKST) == MS_REG_OVR_BKST_NG) - continue; - - if (((extdat.mngflg & MS_REG_MNG_SYSFLG) == MS_REG_MNG_SYSFLG_USER) || - (be16_to_cpu(((struct ms_bootblock_page0 *)PageBuffer0)->header.wBlockID) != MS_BOOT_BLOCK_ID) || - (be16_to_cpu(((struct ms_bootblock_page0 *)PageBuffer0)->header.wFormatVersion) != MS_BOOT_BLOCK_FORMAT_VERSION) || - (((struct ms_bootblock_page0 *)PageBuffer0)->header.bNumberOfDataEntry != MS_BOOT_BLOCK_DATA_ENTRIES)) - continue; - - if (btBlk1st != MS_LB_NOT_USED) { - btBlk2nd = TmpBlock; - break; - } - - btBlk1st = TmpBlock; - memcpy(PageBuffer1, PageBuffer0, MS_BYTES_PER_PAGE); - if (extdat.status1 & (MS_REG_ST1_DTER | MS_REG_ST1_EXER | MS_REG_ST1_FGER)) - btBlk1stErred = 1; - } - - if (btBlk1st == MS_LB_NOT_USED) { - result = MS_STATUS_ERROR; - goto exit; - } - - /* write protect */ - if ((extdat.status0 & MS_REG_ST0_WP) == MS_REG_ST0_WP_ON) - ms_lib_ctrl_set(info, MS_LIB_CTRL_WRPROTECT); - - result = MS_STATUS_ERROR; - /* 1st Boot Block */ - if (btBlk1stErred == 0) - result = ms_lib_process_bootblock(us, btBlk1st, PageBuffer1); - /* 1st */ - /* 2nd Boot Block */ - if (result && (btBlk2nd != MS_LB_NOT_USED)) - result = ms_lib_process_bootblock(us, btBlk2nd, PageBuffer0); - - if (result) { - result = MS_STATUS_ERROR; - goto exit; - } - - for (TmpBlock = 0; TmpBlock < btBlk1st; TmpBlock++) - info->MS_Lib.Phy2LogMap[TmpBlock] = MS_LB_INITIAL_ERROR; - - info->MS_Lib.Phy2LogMap[btBlk1st] = MS_LB_BOOT_BLOCK; - - if (btBlk2nd != MS_LB_NOT_USED) { - for (TmpBlock = btBlk1st + 1; TmpBlock < btBlk2nd; TmpBlock++) - info->MS_Lib.Phy2LogMap[TmpBlock] = MS_LB_INITIAL_ERROR; - - info->MS_Lib.Phy2LogMap[btBlk2nd] = MS_LB_BOOT_BLOCK; - } - - result = ms_lib_scan_logicalblocknumber(us, btBlk1st); - if (result) - goto exit; - - for (TmpBlock = MS_PHYSICAL_BLOCKS_PER_SEGMENT; - TmpBlock < info->MS_Lib.NumberOfPhyBlock; - TmpBlock += MS_PHYSICAL_BLOCKS_PER_SEGMENT) { - if (ms_count_freeblock(us, TmpBlock) == 0) { - ms_lib_ctrl_set(info, MS_LIB_CTRL_WRPROTECT); - break; - } - } - - /* write */ - if (ms_lib_alloc_writebuf(us)) { - result = MS_NO_MEMORY_ERROR; - goto exit; - } - - result = MS_STATUS_SUCCESS; - -exit: - kfree(PageBuffer1); - kfree(PageBuffer0); - - printk(KERN_INFO "MS_CardInit end\n"); - return result; -} - -static int ene_ms_init(struct us_data *us) -{ - struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; - int result; - u8 buf[0x200]; - u16 MSP_BlockSize, MSP_UserAreaBlocks; - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - printk(KERN_INFO "transport --- ENE_MSInit\n"); - - /* the same part to test ENE */ - - result = ene_load_bincode(us, MS_INIT_PATTERN); - if (result != USB_STOR_XFER_GOOD) { - printk(KERN_ERR "Load MS Init Code Fail !!\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - memset(bcb, 0, sizeof(struct bulk_cb_wrap)); - bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb->DataTransferLength = 0x200; - bcb->Flags = US_BULK_FLAG_IN; - bcb->CDB[0] = 0xF1; - bcb->CDB[1] = 0x01; - - result = ene_send_scsi_cmd(us, FDIR_READ, &buf, 0); - if (result != USB_STOR_XFER_GOOD) { - printk(KERN_ERR "Execution MS Init Code Fail !!\n"); - return USB_STOR_TRANSPORT_ERROR; - } - /* the same part to test ENE */ - info->MS_Status = *(struct MS_STATUS *)&buf[0]; - - if (info->MS_Status.Insert && info->MS_Status.Ready) { - printk(KERN_INFO "Insert = %x\n", info->MS_Status.Insert); - printk(KERN_INFO "Ready = %x\n", info->MS_Status.Ready); - printk(KERN_INFO "IsMSPro = %x\n", info->MS_Status.IsMSPro); - printk(KERN_INFO "IsMSPHG = %x\n", info->MS_Status.IsMSPHG); - printk(KERN_INFO "WtP= %x\n", info->MS_Status.WtP); - if (info->MS_Status.IsMSPro) { - MSP_BlockSize = (buf[6] << 8) | buf[7]; - MSP_UserAreaBlocks = (buf[10] << 8) | buf[11]; - info->MSP_TotalBlock = MSP_BlockSize * MSP_UserAreaBlocks; - } else { - ms_card_init(us); /* Card is MS (to ms.c)*/ - } - US_DEBUGP("MS Init Code OK !!\n"); - } else { - US_DEBUGP("MS Card Not Ready --- %x\n", buf[0]); - return USB_STOR_TRANSPORT_ERROR; - } - - return USB_STOR_TRANSPORT_GOOD; -} - -static int ene_sd_init(struct us_data *us) -{ - int result; - u8 buf[0x200]; - struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; - struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; - - US_DEBUGP("transport --- ENE_SDInit\n"); - /* SD Init Part-1 */ - result = ene_load_bincode(us, SD_INIT1_PATTERN); - if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Load SD Init Code Part-1 Fail !!\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - memset(bcb, 0, sizeof(struct bulk_cb_wrap)); - bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb->Flags = US_BULK_FLAG_IN; - bcb->CDB[0] = 0xF2; - - result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0); - if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Execution SD Init Code Fail !!\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - /* SD Init Part-2 */ - result = ene_load_bincode(us, SD_INIT2_PATTERN); - if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Load SD Init Code Part-2 Fail !!\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - memset(bcb, 0, sizeof(struct bulk_cb_wrap)); - bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb->DataTransferLength = 0x200; - bcb->Flags = US_BULK_FLAG_IN; - bcb->CDB[0] = 0xF1; - - result = ene_send_scsi_cmd(us, FDIR_READ, &buf, 0); - if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Execution SD Init Code Fail !!\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - info->SD_Status = *(struct SD_STATUS *)&buf[0]; - if (info->SD_Status.Insert && info->SD_Status.Ready) { - ene_get_card_status(us, (unsigned char *)&buf); - US_DEBUGP("Insert = %x\n", info->SD_Status.Insert); - US_DEBUGP("Ready = %x\n", info->SD_Status.Ready); - US_DEBUGP("IsMMC = %x\n", info->SD_Status.IsMMC); - US_DEBUGP("HiCapacity = %x\n", info->SD_Status.HiCapacity); - US_DEBUGP("HiSpeed = %x\n", info->SD_Status.HiSpeed); - US_DEBUGP("WtP = %x\n", info->SD_Status.WtP); - } else { - US_DEBUGP("SD Card Not Ready --- %x\n", buf[0]); - return USB_STOR_TRANSPORT_ERROR; - } - return USB_STOR_TRANSPORT_GOOD; -} - - -static int ene_init(struct us_data *us) -{ - int result; - u8 misc_reg03 = 0; - struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra); - - result = ene_get_card_type(us, REG_CARD_STATUS, &misc_reg03); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - if (misc_reg03 & 0x01) { - if (!info->SD_Status.Ready) { - result = ene_sd_init(us); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - } - } - if (misc_reg03 & 0x02) { - if (!info->MS_Status.Ready) { - result = ene_ms_init(us); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - } - } - return result; -} - -/*----- sd_scsi_irp() ---------*/ -static int sd_scsi_irp(struct us_data *us, struct scsi_cmnd *srb) -{ - int result; - struct ene_ub6250_info *info = (struct ene_ub6250_info *)us->extra; - - info->SrbStatus = SS_SUCCESS; - switch (srb->cmnd[0]) { - case TEST_UNIT_READY: - result = sd_scsi_test_unit_ready(us, srb); - break; /* 0x00 */ - case INQUIRY: - result = sd_scsi_inquiry(us, srb); - break; /* 0x12 */ - case MODE_SENSE: - result = sd_scsi_mode_sense(us, srb); - break; /* 0x1A */ - /* - case START_STOP: - result = SD_SCSI_Start_Stop(us, srb); - break; //0x1B - */ - case READ_CAPACITY: - result = sd_scsi_read_capacity(us, srb); - break; /* 0x25 */ - case READ_10: - result = sd_scsi_read(us, srb); - break; /* 0x28 */ - case WRITE_10: - result = sd_scsi_write(us, srb); - break; /* 0x2A */ - default: - info->SrbStatus = SS_ILLEGAL_REQUEST; - result = USB_STOR_TRANSPORT_FAILED; - break; - } - return result; -} - -/* - * ms_scsi_irp() - */ -static int ms_scsi_irp(struct us_data *us, struct scsi_cmnd *srb) -{ - int result; - struct ene_ub6250_info *info = (struct ene_ub6250_info *)us->extra; - info->SrbStatus = SS_SUCCESS; - switch (srb->cmnd[0]) { - case TEST_UNIT_READY: - result = ms_scsi_test_unit_ready(us, srb); - break; /* 0x00 */ - case INQUIRY: - result = ms_scsi_inquiry(us, srb); - break; /* 0x12 */ - case MODE_SENSE: - result = ms_scsi_mode_sense(us, srb); - break; /* 0x1A */ - case READ_CAPACITY: - result = ms_scsi_read_capacity(us, srb); - break; /* 0x25 */ - case READ_10: - result = ms_scsi_read(us, srb); - break; /* 0x28 */ - case WRITE_10: - result = ms_scsi_write(us, srb); - break; /* 0x2A */ - default: - info->SrbStatus = SS_ILLEGAL_REQUEST; - result = USB_STOR_TRANSPORT_FAILED; - break; - } - return result; -} - -static int ene_transport(struct scsi_cmnd *srb, struct us_data *us) -{ - int result = 0; - struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra); - - /*US_DEBUG(usb_stor_show_command(srb)); */ - scsi_set_resid(srb, 0); - if (unlikely(!(info->SD_Status.Ready || info->MS_Status.Ready))) { - result = ene_init(us); - } else { - if (info->SD_Status.Ready) - result = sd_scsi_irp(us, srb); - - if (info->MS_Status.Ready) - result = ms_scsi_irp(us, srb); - } - return 0; -} - - -static int ene_ub6250_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - int result; - u8 misc_reg03 = 0; - struct us_data *us; - - result = usb_stor_probe1(&us, intf, id, - (id - ene_ub6250_usb_ids) + ene_ub6250_unusual_dev_list); - if (result) - return result; - - /* FIXME: where should the code alloc extra buf ? */ - if (!us->extra) { - us->extra = kzalloc(sizeof(struct ene_ub6250_info), GFP_KERNEL); - if (!us->extra) - return -ENOMEM; - us->extra_destructor = ene_ub6250_info_destructor; - } - - us->transport_name = "ene_ub6250"; - us->transport = ene_transport; - us->max_lun = 0; - - result = usb_stor_probe2(us); - if (result) - return result; - - /* probe card type */ - result = ene_get_card_type(us, REG_CARD_STATUS, &misc_reg03); - if (result != USB_STOR_XFER_GOOD) { - usb_stor_disconnect(intf); - return USB_STOR_TRANSPORT_ERROR; - } - - if (!(misc_reg03 & 0x01)) { - pr_info("ums_eneub6250: The driver only supports SD/MS card. " - "To use SM card, please build driver/staging/keucr\n"); - } - - return result; -} - - -#ifdef CONFIG_PM - -static int ene_ub6250_resume(struct usb_interface *iface) -{ - u8 tmp = 0; - struct us_data *us = usb_get_intfdata(iface); - struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra); - - mutex_lock(&us->dev_mutex); - - US_DEBUGP("%s\n", __func__); - if (us->suspend_resume_hook) - (us->suspend_resume_hook)(us, US_RESUME); - - mutex_unlock(&us->dev_mutex); - - info->Power_IsResum = true; - /*info->SD_Status.Ready = 0; */ - info->SD_Status = *(struct SD_STATUS *)&tmp; - info->MS_Status = *(struct MS_STATUS *)&tmp; - info->SM_Status = *(struct SM_STATUS *)&tmp; - - return 0; -} - -static int ene_ub6250_reset_resume(struct usb_interface *iface) -{ - u8 tmp = 0; - struct us_data *us = usb_get_intfdata(iface); - struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra); - US_DEBUGP("%s\n", __func__); - /* Report the reset to the SCSI core */ - usb_stor_reset_resume(iface); - - /* FIXME: Notify the subdrivers that they need to reinitialize - * the device */ - info->Power_IsResum = true; - /*info->SD_Status.Ready = 0; */ - info->SD_Status = *(struct SD_STATUS *)&tmp; - info->MS_Status = *(struct MS_STATUS *)&tmp; - info->SM_Status = *(struct SM_STATUS *)&tmp; - - return 0; -} - -#else - -#define ene_ub6250_resume NULL -#define ene_ub6250_reset_resume NULL - -#endif - -static struct usb_driver ene_ub6250_driver = { - .name = "ums_eneub6250", - .probe = ene_ub6250_probe, - .disconnect = usb_stor_disconnect, - .suspend = usb_stor_suspend, - .resume = ene_ub6250_resume, - .reset_resume = ene_ub6250_reset_resume, - .pre_reset = usb_stor_pre_reset, - .post_reset = usb_stor_post_reset, - .id_table = ene_ub6250_usb_ids, - .soft_unbind = 1, - .no_dynamic_id = 1, -}; - -module_usb_driver(ene_ub6250_driver); diff --git a/ANDROID_3.4.5/drivers/usb/storage/freecom.c b/ANDROID_3.4.5/drivers/usb/storage/freecom.c deleted file mode 100644 index 042cf9ef..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/freecom.c +++ /dev/null @@ -1,559 +0,0 @@ -/* Driver for Freecom USB/IDE adaptor - * - * Freecom v0.1: - * - * First release - * - * Current development and maintenance by: - * (C) 2000 David Brown - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - * This driver was developed with information provided in FREECOM's USB - * Programmers Reference Guide. For further information contact Freecom - * (http://www.freecom.de/) - */ - -#include -#include -#include - -#include "usb.h" -#include "transport.h" -#include "protocol.h" -#include "debug.h" - -MODULE_DESCRIPTION("Driver for Freecom USB/IDE adaptor"); -MODULE_AUTHOR("David Brown "); -MODULE_LICENSE("GPL"); - -#ifdef CONFIG_USB_STORAGE_DEBUG -static void pdump (void *, int); -#endif - -/* Bits of HD_STATUS */ -#define ERR_STAT 0x01 -#define DRQ_STAT 0x08 - -/* All of the outgoing packets are 64 bytes long. */ -struct freecom_cb_wrap { - u8 Type; /* Command type. */ - u8 Timeout; /* Timeout in seconds. */ - u8 Atapi[12]; /* An ATAPI packet. */ - u8 Filler[50]; /* Padding Data. */ -}; - -struct freecom_xfer_wrap { - u8 Type; /* Command type. */ - u8 Timeout; /* Timeout in seconds. */ - __le32 Count; /* Number of bytes to transfer. */ - u8 Pad[58]; -} __attribute__ ((packed)); - -struct freecom_ide_out { - u8 Type; /* Type + IDE register. */ - u8 Pad; - __le16 Value; /* Value to write. */ - u8 Pad2[60]; -}; - -struct freecom_ide_in { - u8 Type; /* Type | IDE register. */ - u8 Pad[63]; -}; - -struct freecom_status { - u8 Status; - u8 Reason; - __le16 Count; - u8 Pad[60]; -}; - -/* Freecom stuffs the interrupt status in the INDEX_STAT bit of the ide - * register. */ -#define FCM_INT_STATUS 0x02 /* INDEX_STAT */ -#define FCM_STATUS_BUSY 0x80 - -/* These are the packet types. The low bit indicates that this command - * should wait for an interrupt. */ -#define FCM_PACKET_ATAPI 0x21 -#define FCM_PACKET_STATUS 0x20 - -/* Receive data from the IDE interface. The ATAPI packet has already - * waited, so the data should be immediately available. */ -#define FCM_PACKET_INPUT 0x81 - -/* Send data to the IDE interface. */ -#define FCM_PACKET_OUTPUT 0x01 - -/* Write a value to an ide register. Or the ide register to write after - * munging the address a bit. */ -#define FCM_PACKET_IDE_WRITE 0x40 -#define FCM_PACKET_IDE_READ 0xC0 - -/* All packets (except for status) are 64 bytes long. */ -#define FCM_PACKET_LENGTH 64 -#define FCM_STATUS_PACKET_LENGTH 4 - -static int init_freecom(struct us_data *us); - - -/* - * The table of devices - */ -#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ - vendorName, productName, useProtocol, useTransport, \ - initFunction, flags) \ -{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } - -static struct usb_device_id freecom_usb_ids[] = { -# include "unusual_freecom.h" - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, freecom_usb_ids); - -#undef UNUSUAL_DEV - -/* - * The flags table - */ -#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ - vendor_name, product_name, use_protocol, use_transport, \ - init_function, Flags) \ -{ \ - .vendorName = vendor_name, \ - .productName = product_name, \ - .useProtocol = use_protocol, \ - .useTransport = use_transport, \ - .initFunction = init_function, \ -} - -static struct us_unusual_dev freecom_unusual_dev_list[] = { -# include "unusual_freecom.h" - { } /* Terminating entry */ -}; - -#undef UNUSUAL_DEV - -static int -freecom_readdata (struct scsi_cmnd *srb, struct us_data *us, - unsigned int ipipe, unsigned int opipe, int count) -{ - struct freecom_xfer_wrap *fxfr = - (struct freecom_xfer_wrap *) us->iobuf; - int result; - - fxfr->Type = FCM_PACKET_INPUT | 0x00; - fxfr->Timeout = 0; /* Short timeout for debugging. */ - fxfr->Count = cpu_to_le32 (count); - memset (fxfr->Pad, 0, sizeof (fxfr->Pad)); - - US_DEBUGP("Read data Freecom! (c=%d)\n", count); - - /* Issue the transfer command. */ - result = usb_stor_bulk_transfer_buf (us, opipe, fxfr, - FCM_PACKET_LENGTH, NULL); - if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP ("Freecom readdata transport error\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - /* Now transfer all of our blocks. */ - US_DEBUGP("Start of read\n"); - result = usb_stor_bulk_srb(us, ipipe, srb); - US_DEBUGP("freecom_readdata done!\n"); - - if (result > USB_STOR_XFER_SHORT) - return USB_STOR_TRANSPORT_ERROR; - return USB_STOR_TRANSPORT_GOOD; -} - -static int -freecom_writedata (struct scsi_cmnd *srb, struct us_data *us, - int unsigned ipipe, unsigned int opipe, int count) -{ - struct freecom_xfer_wrap *fxfr = - (struct freecom_xfer_wrap *) us->iobuf; - int result; - - fxfr->Type = FCM_PACKET_OUTPUT | 0x00; - fxfr->Timeout = 0; /* Short timeout for debugging. */ - fxfr->Count = cpu_to_le32 (count); - memset (fxfr->Pad, 0, sizeof (fxfr->Pad)); - - US_DEBUGP("Write data Freecom! (c=%d)\n", count); - - /* Issue the transfer command. */ - result = usb_stor_bulk_transfer_buf (us, opipe, fxfr, - FCM_PACKET_LENGTH, NULL); - if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP ("Freecom writedata transport error\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - /* Now transfer all of our blocks. */ - US_DEBUGP("Start of write\n"); - result = usb_stor_bulk_srb(us, opipe, srb); - - US_DEBUGP("freecom_writedata done!\n"); - if (result > USB_STOR_XFER_SHORT) - return USB_STOR_TRANSPORT_ERROR; - return USB_STOR_TRANSPORT_GOOD; -} - -/* - * Transport for the Freecom USB/IDE adaptor. - * - */ -static int freecom_transport(struct scsi_cmnd *srb, struct us_data *us) -{ - struct freecom_cb_wrap *fcb; - struct freecom_status *fst; - unsigned int ipipe, opipe; /* We need both pipes. */ - int result; - unsigned int partial; - int length; - - fcb = (struct freecom_cb_wrap *) us->iobuf; - fst = (struct freecom_status *) us->iobuf; - - US_DEBUGP("Freecom TRANSPORT STARTED\n"); - - /* Get handles for both transports. */ - opipe = us->send_bulk_pipe; - ipipe = us->recv_bulk_pipe; - - /* The ATAPI Command always goes out first. */ - fcb->Type = FCM_PACKET_ATAPI | 0x00; - fcb->Timeout = 0; - memcpy (fcb->Atapi, srb->cmnd, 12); - memset (fcb->Filler, 0, sizeof (fcb->Filler)); - - US_DEBUG(pdump (srb->cmnd, 12)); - - /* Send it out. */ - result = usb_stor_bulk_transfer_buf (us, opipe, fcb, - FCM_PACKET_LENGTH, NULL); - - /* The Freecom device will only fail if there is something wrong in - * USB land. It returns the status in its own registers, which - * come back in the bulk pipe. */ - if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP ("freecom transport error\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - /* There are times we can optimize out this status read, but it - * doesn't hurt us to always do it now. */ - result = usb_stor_bulk_transfer_buf (us, ipipe, fst, - FCM_STATUS_PACKET_LENGTH, &partial); - US_DEBUGP("foo Status result %d %u\n", result, partial); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - US_DEBUG(pdump ((void *) fst, partial)); - - /* The firmware will time-out commands after 20 seconds. Some commands - * can legitimately take longer than this, so we use a different - * command that only waits for the interrupt and then sends status, - * without having to send a new ATAPI command to the device. - * - * NOTE: There is some indication that a data transfer after a timeout - * may not work, but that is a condition that should never happen. - */ - while (fst->Status & FCM_STATUS_BUSY) { - US_DEBUGP("20 second USB/ATAPI bridge TIMEOUT occurred!\n"); - US_DEBUGP("fst->Status is %x\n", fst->Status); - - /* Get the status again */ - fcb->Type = FCM_PACKET_STATUS; - fcb->Timeout = 0; - memset (fcb->Atapi, 0, sizeof(fcb->Atapi)); - memset (fcb->Filler, 0, sizeof (fcb->Filler)); - - /* Send it out. */ - result = usb_stor_bulk_transfer_buf (us, opipe, fcb, - FCM_PACKET_LENGTH, NULL); - - /* The Freecom device will only fail if there is something - * wrong in USB land. It returns the status in its own - * registers, which come back in the bulk pipe. - */ - if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP ("freecom transport error\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - /* get the data */ - result = usb_stor_bulk_transfer_buf (us, ipipe, fst, - FCM_STATUS_PACKET_LENGTH, &partial); - - US_DEBUGP("bar Status result %d %u\n", result, partial); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - US_DEBUG(pdump ((void *) fst, partial)); - } - - if (partial != 4) - return USB_STOR_TRANSPORT_ERROR; - if ((fst->Status & 1) != 0) { - US_DEBUGP("operation failed\n"); - return USB_STOR_TRANSPORT_FAILED; - } - - /* The device might not have as much data available as we - * requested. If you ask for more than the device has, this reads - * and such will hang. */ - US_DEBUGP("Device indicates that it has %d bytes available\n", - le16_to_cpu (fst->Count)); - US_DEBUGP("SCSI requested %d\n", scsi_bufflen(srb)); - - /* Find the length we desire to read. */ - switch (srb->cmnd[0]) { - case INQUIRY: - case REQUEST_SENSE: /* 16 or 18 bytes? spec says 18, lots of devices only have 16 */ - case MODE_SENSE: - case MODE_SENSE_10: - length = le16_to_cpu(fst->Count); - break; - default: - length = scsi_bufflen(srb); - } - - /* verify that this amount is legal */ - if (length > scsi_bufflen(srb)) { - length = scsi_bufflen(srb); - US_DEBUGP("Truncating request to match buffer length: %d\n", length); - } - - /* What we do now depends on what direction the data is supposed to - * move in. */ - - switch (us->srb->sc_data_direction) { - case DMA_FROM_DEVICE: - /* catch bogus "read 0 length" case */ - if (!length) - break; - /* Make sure that the status indicates that the device - * wants data as well. */ - if ((fst->Status & DRQ_STAT) == 0 || (fst->Reason & 3) != 2) { - US_DEBUGP("SCSI wants data, drive doesn't have any\n"); - return USB_STOR_TRANSPORT_FAILED; - } - result = freecom_readdata (srb, us, ipipe, opipe, length); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - - US_DEBUGP("FCM: Waiting for status\n"); - result = usb_stor_bulk_transfer_buf (us, ipipe, fst, - FCM_PACKET_LENGTH, &partial); - US_DEBUG(pdump ((void *) fst, partial)); - - if (partial != 4 || result > USB_STOR_XFER_SHORT) - return USB_STOR_TRANSPORT_ERROR; - if ((fst->Status & ERR_STAT) != 0) { - US_DEBUGP("operation failed\n"); - return USB_STOR_TRANSPORT_FAILED; - } - if ((fst->Reason & 3) != 3) { - US_DEBUGP("Drive seems still hungry\n"); - return USB_STOR_TRANSPORT_FAILED; - } - US_DEBUGP("Transfer happy\n"); - break; - - case DMA_TO_DEVICE: - /* catch bogus "write 0 length" case */ - if (!length) - break; - /* Make sure the status indicates that the device wants to - * send us data. */ - /* !!IMPLEMENT!! */ - result = freecom_writedata (srb, us, ipipe, opipe, length); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - - US_DEBUGP("FCM: Waiting for status\n"); - result = usb_stor_bulk_transfer_buf (us, ipipe, fst, - FCM_PACKET_LENGTH, &partial); - - if (partial != 4 || result > USB_STOR_XFER_SHORT) - return USB_STOR_TRANSPORT_ERROR; - if ((fst->Status & ERR_STAT) != 0) { - US_DEBUGP("operation failed\n"); - return USB_STOR_TRANSPORT_FAILED; - } - if ((fst->Reason & 3) != 3) { - US_DEBUGP("Drive seems still hungry\n"); - return USB_STOR_TRANSPORT_FAILED; - } - - US_DEBUGP("Transfer happy\n"); - break; - - - case DMA_NONE: - /* Easy, do nothing. */ - break; - - default: - /* should never hit here -- filtered in usb.c */ - US_DEBUGP ("freecom unimplemented direction: %d\n", - us->srb->sc_data_direction); - /* Return fail, SCSI seems to handle this better. */ - return USB_STOR_TRANSPORT_FAILED; - break; - } - - return USB_STOR_TRANSPORT_GOOD; -} - -static int init_freecom(struct us_data *us) -{ - int result; - char *buffer = us->iobuf; - - /* The DMA-mapped I/O buffer is 64 bytes long, just right for - * all our packets. No need to allocate any extra buffer space. - */ - - result = usb_stor_control_msg(us, us->recv_ctrl_pipe, - 0x4c, 0xc0, 0x4346, 0x0, buffer, 0x20, 3*HZ); - buffer[32] = '\0'; - US_DEBUGP("String returned from FC init is: %s\n", buffer); - - /* Special thanks to the people at Freecom for providing me with - * this "magic sequence", which they use in their Windows and MacOS - * drivers to make sure that all the attached perhiperals are - * properly reset. - */ - - /* send reset */ - result = usb_stor_control_msg(us, us->send_ctrl_pipe, - 0x4d, 0x40, 0x24d8, 0x0, NULL, 0x0, 3*HZ); - US_DEBUGP("result from activate reset is %d\n", result); - - /* wait 250ms */ - mdelay(250); - - /* clear reset */ - result = usb_stor_control_msg(us, us->send_ctrl_pipe, - 0x4d, 0x40, 0x24f8, 0x0, NULL, 0x0, 3*HZ); - US_DEBUGP("result from clear reset is %d\n", result); - - /* wait 3 seconds */ - mdelay(3 * 1000); - - return USB_STOR_TRANSPORT_GOOD; -} - -static int usb_stor_freecom_reset(struct us_data *us) -{ - printk (KERN_CRIT "freecom reset called\n"); - - /* We don't really have this feature. */ - return FAILED; -} - -#ifdef CONFIG_USB_STORAGE_DEBUG -static void pdump (void *ibuffer, int length) -{ - static char line[80]; - int offset = 0; - unsigned char *buffer = (unsigned char *) ibuffer; - int i, j; - int from, base; - - offset = 0; - for (i = 0; i < length; i++) { - if ((i & 15) == 0) { - if (i > 0) { - offset += sprintf (line+offset, " - "); - for (j = i - 16; j < i; j++) { - if (buffer[j] >= 32 && buffer[j] <= 126) - line[offset++] = buffer[j]; - else - line[offset++] = '.'; - } - line[offset] = 0; - US_DEBUGP("%s\n", line); - offset = 0; - } - offset += sprintf (line+offset, "%08x:", i); - } else if ((i & 7) == 0) { - offset += sprintf (line+offset, " -"); - } - offset += sprintf (line+offset, " %02x", buffer[i] & 0xff); - } - - /* Add the last "chunk" of data. */ - from = (length - 1) % 16; - base = ((length - 1) / 16) * 16; - - for (i = from + 1; i < 16; i++) - offset += sprintf (line+offset, " "); - if (from < 8) - offset += sprintf (line+offset, " "); - offset += sprintf (line+offset, " - "); - - for (i = 0; i <= from; i++) { - if (buffer[base+i] >= 32 && buffer[base+i] <= 126) - line[offset++] = buffer[base+i]; - else - line[offset++] = '.'; - } - line[offset] = 0; - US_DEBUGP("%s\n", line); - offset = 0; -} -#endif - -static int freecom_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct us_data *us; - int result; - - result = usb_stor_probe1(&us, intf, id, - (id - freecom_usb_ids) + freecom_unusual_dev_list); - if (result) - return result; - - us->transport_name = "Freecom"; - us->transport = freecom_transport; - us->transport_reset = usb_stor_freecom_reset; - us->max_lun = 0; - - result = usb_stor_probe2(us); - return result; -} - -static struct usb_driver freecom_driver = { - .name = "ums-freecom", - .probe = freecom_probe, - .disconnect = usb_stor_disconnect, - .suspend = usb_stor_suspend, - .resume = usb_stor_resume, - .reset_resume = usb_stor_reset_resume, - .pre_reset = usb_stor_pre_reset, - .post_reset = usb_stor_post_reset, - .id_table = freecom_usb_ids, - .soft_unbind = 1, - .no_dynamic_id = 1, -}; - -module_usb_driver(freecom_driver); diff --git a/ANDROID_3.4.5/drivers/usb/storage/initializers.c b/ANDROID_3.4.5/drivers/usb/storage/initializers.c deleted file mode 100644 index 105d9001..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/initializers.c +++ /dev/null @@ -1,106 +0,0 @@ -/* Special Initializers for certain USB Mass Storage devices - * - * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI and ATAPI commands in - * mind when they created this document. The commands are all very - * similar to commands in the SCSI-II and ATAPI specifications. - * - * It is important to note that in a number of cases this class - * exhibits class-specific exemptions from the USB specification. - * Notably the usage of NAK, STALL and ACK differs from the norm, in - * that they are used to communicate wait, failed and OK on commands. - * - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include - -#include "usb.h" -#include "initializers.h" -#include "debug.h" -#include "transport.h" - -/* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target - * mode */ -int usb_stor_euscsi_init(struct us_data *us) -{ - int result; - - US_DEBUGP("Attempting to init eUSCSI bridge...\n"); - us->iobuf[0] = 0x1; - result = usb_stor_control_msg(us, us->send_ctrl_pipe, - 0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR, - 0x01, 0x0, us->iobuf, 0x1, 5000); - US_DEBUGP("-- result is %d\n", result); - - return 0; -} - -/* This function is required to activate all four slots on the UCR-61S2B - * flash reader */ -int usb_stor_ucr61s2b_init(struct us_data *us) -{ - struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap*) us->iobuf; - struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap*) us->iobuf; - int res; - unsigned int partial; - static char init_string[] = "\xec\x0a\x06\x00$PCCHIPS"; - - US_DEBUGP("Sending UCR-61S2B initialization packet...\n"); - - bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb->Tag = 0; - bcb->DataTransferLength = cpu_to_le32(0); - bcb->Flags = bcb->Lun = 0; - bcb->Length = sizeof(init_string) - 1; - memset(bcb->CDB, 0, sizeof(bcb->CDB)); - memcpy(bcb->CDB, init_string, sizeof(init_string) - 1); - - res = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb, - US_BULK_CB_WRAP_LEN, &partial); - if (res) - return -EIO; - - US_DEBUGP("Getting status packet...\n"); - res = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, - US_BULK_CS_WRAP_LEN, &partial); - if (res) - return -EIO; - - return 0; -} - -/* This places the HUAWEI E220 devices in multi-port mode */ -int usb_stor_huawei_e220_init(struct us_data *us) -{ - int result; - - result = usb_stor_control_msg(us, us->send_ctrl_pipe, - USB_REQ_SET_FEATURE, - USB_TYPE_STANDARD | USB_RECIP_DEVICE, - 0x01, 0x0, NULL, 0x0, 1000); - US_DEBUGP("Huawei mode set result is %d\n", result); - return 0; -} diff --git a/ANDROID_3.4.5/drivers/usb/storage/initializers.h b/ANDROID_3.4.5/drivers/usb/storage/initializers.h deleted file mode 100644 index 529327fb..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/initializers.h +++ /dev/null @@ -1,50 +0,0 @@ -/* Header file for Special Initializers for certain USB Mass Storage devices - * - * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI and ATAPI commands in - * mind when they created this document. The commands are all very - * similar to commands in the SCSI-II and ATAPI specifications. - * - * It is important to note that in a number of cases this class - * exhibits class-specific exemptions from the USB specification. - * Notably the usage of NAK, STALL and ACK differs from the norm, in - * that they are used to communicate wait, failed and OK on commands. - * - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "usb.h" -#include "transport.h" - -/* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target - * mode */ -int usb_stor_euscsi_init(struct us_data *us); - -/* This function is required to activate all four slots on the UCR-61S2B - * flash reader */ -int usb_stor_ucr61s2b_init(struct us_data *us); - -/* This places the HUAWEI E220 devices in multi-port mode */ -int usb_stor_huawei_e220_init(struct us_data *us); diff --git a/ANDROID_3.4.5/drivers/usb/storage/isd200.c b/ANDROID_3.4.5/drivers/usb/storage/isd200.c deleted file mode 100644 index 31fa24e7..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/isd200.c +++ /dev/null @@ -1,1572 +0,0 @@ -/* Transport & Protocol Driver for In-System Design, Inc. ISD200 ASIC - * - * Current development and maintenance: - * (C) 2001-2002 Björn Stenberg (bjorn@haxx.se) - * - * Developed with the assistance of: - * (C) 2002 Alan Stern - * - * Initial work: - * (C) 2000 In-System Design, Inc. (support@in-system.com) - * - * The ISD200 ASIC does not natively support ATA devices. The chip - * does implement an interface, the ATA Command Block (ATACB) which provides - * a means of passing ATA commands and ATA register accesses to a device. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - * - * History: - * - * 2002-10-19: Removed the specialized transfer routines. - * (Alan Stern ) - * 2001-02-24: Removed lots of duplicate code and simplified the structure. - * (bjorn@haxx.se) - * 2002-01-16: Fixed endianness bug so it works on the ppc arch. - * (Luc Saillard ) - * 2002-01-17: All bitfields removed. - * (bjorn@haxx.se) - */ - - -/* Include files */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "usb.h" -#include "transport.h" -#include "protocol.h" -#include "debug.h" -#include "scsiglue.h" - -MODULE_DESCRIPTION("Driver for In-System Design, Inc. ISD200 ASIC"); -MODULE_AUTHOR("Björn Stenberg "); -MODULE_LICENSE("GPL"); - -static int isd200_Initialization(struct us_data *us); - - -/* - * The table of devices - */ -#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ - vendorName, productName, useProtocol, useTransport, \ - initFunction, flags) \ -{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } - -static struct usb_device_id isd200_usb_ids[] = { -# include "unusual_isd200.h" - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, isd200_usb_ids); - -#undef UNUSUAL_DEV -#undef USUAL_DEV - -/* - * The flags table - */ -#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ - vendor_name, product_name, use_protocol, use_transport, \ - init_function, Flags) \ -{ \ - .vendorName = vendor_name, \ - .productName = product_name, \ - .useProtocol = use_protocol, \ - .useTransport = use_transport, \ - .initFunction = init_function, \ -} - -static struct us_unusual_dev isd200_unusual_dev_list[] = { -# include "unusual_isd200.h" - { } /* Terminating entry */ -}; - -#undef UNUSUAL_DEV -#undef USUAL_DEV - - -/* Timeout defines (in Seconds) */ - -#define ISD200_ENUM_BSY_TIMEOUT 35 -#define ISD200_ENUM_DETECT_TIMEOUT 30 -#define ISD200_DEFAULT_TIMEOUT 30 - -/* device flags */ -#define DF_ATA_DEVICE 0x0001 -#define DF_MEDIA_STATUS_ENABLED 0x0002 -#define DF_REMOVABLE_MEDIA 0x0004 - -/* capability bit definitions */ -#define CAPABILITY_DMA 0x01 -#define CAPABILITY_LBA 0x02 - -/* command_setX bit definitions */ -#define COMMANDSET_REMOVABLE 0x02 -#define COMMANDSET_MEDIA_STATUS 0x10 - -/* ATA Vendor Specific defines */ -#define ATA_ADDRESS_DEVHEAD_STD 0xa0 -#define ATA_ADDRESS_DEVHEAD_LBA_MODE 0x40 -#define ATA_ADDRESS_DEVHEAD_SLAVE 0x10 - -/* Action Select bits */ -#define ACTION_SELECT_0 0x01 -#define ACTION_SELECT_1 0x02 -#define ACTION_SELECT_2 0x04 -#define ACTION_SELECT_3 0x08 -#define ACTION_SELECT_4 0x10 -#define ACTION_SELECT_5 0x20 -#define ACTION_SELECT_6 0x40 -#define ACTION_SELECT_7 0x80 - -/* Register Select bits */ -#define REG_ALTERNATE_STATUS 0x01 -#define REG_DEVICE_CONTROL 0x01 -#define REG_ERROR 0x02 -#define REG_FEATURES 0x02 -#define REG_SECTOR_COUNT 0x04 -#define REG_SECTOR_NUMBER 0x08 -#define REG_CYLINDER_LOW 0x10 -#define REG_CYLINDER_HIGH 0x20 -#define REG_DEVICE_HEAD 0x40 -#define REG_STATUS 0x80 -#define REG_COMMAND 0x80 - -/* ATA registers offset definitions */ -#define ATA_REG_ERROR_OFFSET 1 -#define ATA_REG_LCYL_OFFSET 4 -#define ATA_REG_HCYL_OFFSET 5 -#define ATA_REG_STATUS_OFFSET 7 - -/* ATA error definitions not in */ -#define ATA_ERROR_MEDIA_CHANGE 0x20 - -/* ATA command definitions not in */ -#define ATA_COMMAND_GET_MEDIA_STATUS 0xDA -#define ATA_COMMAND_MEDIA_EJECT 0xED - -/* ATA drive control definitions */ -#define ATA_DC_DISABLE_INTERRUPTS 0x02 -#define ATA_DC_RESET_CONTROLLER 0x04 -#define ATA_DC_REENABLE_CONTROLLER 0x00 - -/* - * General purpose return codes - */ - -#define ISD200_ERROR -1 -#define ISD200_GOOD 0 - -/* - * Transport return codes - */ - -#define ISD200_TRANSPORT_GOOD 0 /* Transport good, command good */ -#define ISD200_TRANSPORT_FAILED 1 /* Transport good, command failed */ -#define ISD200_TRANSPORT_ERROR 2 /* Transport bad (i.e. device dead) */ - -/* driver action codes */ -#define ACTION_READ_STATUS 0 -#define ACTION_RESET 1 -#define ACTION_REENABLE 2 -#define ACTION_SOFT_RESET 3 -#define ACTION_ENUM 4 -#define ACTION_IDENTIFY 5 - - -/* - * ata_cdb struct - */ - - -union ata_cdb { - struct { - unsigned char SignatureByte0; - unsigned char SignatureByte1; - unsigned char ActionSelect; - unsigned char RegisterSelect; - unsigned char TransferBlockSize; - unsigned char WriteData3F6; - unsigned char WriteData1F1; - unsigned char WriteData1F2; - unsigned char WriteData1F3; - unsigned char WriteData1F4; - unsigned char WriteData1F5; - unsigned char WriteData1F6; - unsigned char WriteData1F7; - unsigned char Reserved[3]; - } generic; - - struct { - unsigned char SignatureByte0; - unsigned char SignatureByte1; - unsigned char ActionSelect; - unsigned char RegisterSelect; - unsigned char TransferBlockSize; - unsigned char AlternateStatusByte; - unsigned char ErrorByte; - unsigned char SectorCountByte; - unsigned char SectorNumberByte; - unsigned char CylinderLowByte; - unsigned char CylinderHighByte; - unsigned char DeviceHeadByte; - unsigned char StatusByte; - unsigned char Reserved[3]; - } read; - - struct { - unsigned char SignatureByte0; - unsigned char SignatureByte1; - unsigned char ActionSelect; - unsigned char RegisterSelect; - unsigned char TransferBlockSize; - unsigned char DeviceControlByte; - unsigned char FeaturesByte; - unsigned char SectorCountByte; - unsigned char SectorNumberByte; - unsigned char CylinderLowByte; - unsigned char CylinderHighByte; - unsigned char DeviceHeadByte; - unsigned char CommandByte; - unsigned char Reserved[3]; - } write; -}; - - -/* - * Inquiry data structure. This is the data returned from the target - * after it receives an inquiry. - * - * This structure may be extended by the number of bytes specified - * in the field AdditionalLength. The defined size constant only - * includes fields through ProductRevisionLevel. - */ - -/* - * DeviceType field - */ -#define DIRECT_ACCESS_DEVICE 0x00 /* disks */ -#define DEVICE_REMOVABLE 0x80 - -struct inquiry_data { - unsigned char DeviceType; - unsigned char DeviceTypeModifier; - unsigned char Versions; - unsigned char Format; - unsigned char AdditionalLength; - unsigned char Reserved[2]; - unsigned char Capability; - unsigned char VendorId[8]; - unsigned char ProductId[16]; - unsigned char ProductRevisionLevel[4]; - unsigned char VendorSpecific[20]; - unsigned char Reserved3[40]; -} __attribute__ ((packed)); - -/* - * INQUIRY data buffer size - */ - -#define INQUIRYDATABUFFERSIZE 36 - - -/* - * ISD200 CONFIG data struct - */ - -#define ATACFG_TIMING 0x0f -#define ATACFG_ATAPI_RESET 0x10 -#define ATACFG_MASTER 0x20 -#define ATACFG_BLOCKSIZE 0xa0 - -#define ATACFGE_LAST_LUN 0x07 -#define ATACFGE_DESC_OVERRIDE 0x08 -#define ATACFGE_STATE_SUSPEND 0x10 -#define ATACFGE_SKIP_BOOT 0x20 -#define ATACFGE_CONF_DESC2 0x40 -#define ATACFGE_INIT_STATUS 0x80 - -#define CFG_CAPABILITY_SRST 0x01 - -struct isd200_config { - unsigned char EventNotification; - unsigned char ExternalClock; - unsigned char ATAInitTimeout; - unsigned char ATAConfig; - unsigned char ATAMajorCommand; - unsigned char ATAMinorCommand; - unsigned char ATAExtraConfig; - unsigned char Capability; -}__attribute__ ((packed)); - - -/* - * ISD200 driver information struct - */ - -struct isd200_info { - struct inquiry_data InquiryData; - u16 *id; - struct isd200_config ConfigData; - unsigned char *RegsBuf; - unsigned char ATARegs[8]; - unsigned char DeviceHead; - unsigned char DeviceFlags; - - /* maximum number of LUNs supported */ - unsigned char MaxLUNs; - unsigned char cmnd[BLK_MAX_CDB]; - struct scsi_cmnd srb; - struct scatterlist sg; -}; - - -/* - * Read Capacity Data - returned in Big Endian format - */ - -struct read_capacity_data { - __be32 LogicalBlockAddress; - __be32 BytesPerBlock; -}; - -/* - * Read Block Limits Data - returned in Big Endian format - * This structure returns the maximum and minimum block - * size for a TAPE device. - */ - -struct read_block_limits { - unsigned char Reserved; - unsigned char BlockMaximumSize[3]; - unsigned char BlockMinimumSize[2]; -}; - - -/* - * Sense Data Format - */ - -#define SENSE_ERRCODE 0x7f -#define SENSE_ERRCODE_VALID 0x80 -#define SENSE_FLAG_SENSE_KEY 0x0f -#define SENSE_FLAG_BAD_LENGTH 0x20 -#define SENSE_FLAG_END_OF_MEDIA 0x40 -#define SENSE_FLAG_FILE_MARK 0x80 -struct sense_data { - unsigned char ErrorCode; - unsigned char SegmentNumber; - unsigned char Flags; - unsigned char Information[4]; - unsigned char AdditionalSenseLength; - unsigned char CommandSpecificInformation[4]; - unsigned char AdditionalSenseCode; - unsigned char AdditionalSenseCodeQualifier; - unsigned char FieldReplaceableUnitCode; - unsigned char SenseKeySpecific[3]; -} __attribute__ ((packed)); - -/* - * Default request sense buffer size - */ - -#define SENSE_BUFFER_SIZE 18 - -/*********************************************************************** - * Helper routines - ***********************************************************************/ - -/************************************************************************** - * isd200_build_sense - * - * Builds an artificial sense buffer to report the results of a - * failed command. - * - * RETURNS: - * void - */ -static void isd200_build_sense(struct us_data *us, struct scsi_cmnd *srb) -{ - struct isd200_info *info = (struct isd200_info *)us->extra; - struct sense_data *buf = (struct sense_data *) &srb->sense_buffer[0]; - unsigned char error = info->ATARegs[ATA_REG_ERROR_OFFSET]; - - if(error & ATA_ERROR_MEDIA_CHANGE) { - buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; - buf->AdditionalSenseLength = 0xb; - buf->Flags = UNIT_ATTENTION; - buf->AdditionalSenseCode = 0; - buf->AdditionalSenseCodeQualifier = 0; - } else if (error & ATA_MCR) { - buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; - buf->AdditionalSenseLength = 0xb; - buf->Flags = UNIT_ATTENTION; - buf->AdditionalSenseCode = 0; - buf->AdditionalSenseCodeQualifier = 0; - } else if (error & ATA_TRK0NF) { - buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; - buf->AdditionalSenseLength = 0xb; - buf->Flags = NOT_READY; - buf->AdditionalSenseCode = 0; - buf->AdditionalSenseCodeQualifier = 0; - } else if (error & ATA_UNC) { - buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID; - buf->AdditionalSenseLength = 0xb; - buf->Flags = DATA_PROTECT; - buf->AdditionalSenseCode = 0; - buf->AdditionalSenseCodeQualifier = 0; - } else { - buf->ErrorCode = 0; - buf->AdditionalSenseLength = 0; - buf->Flags = 0; - buf->AdditionalSenseCode = 0; - buf->AdditionalSenseCodeQualifier = 0; - } -} - - -/*********************************************************************** - * Transport routines - ***********************************************************************/ - -/************************************************************************** - * isd200_set_srb(), isd200_srb_set_bufflen() - * - * Two helpers to facilitate in initialization of scsi_cmnd structure - * Will need to change when struct scsi_cmnd changes - */ -static void isd200_set_srb(struct isd200_info *info, - enum dma_data_direction dir, void* buff, unsigned bufflen) -{ - struct scsi_cmnd *srb = &info->srb; - - if (buff) - sg_init_one(&info->sg, buff, bufflen); - - srb->sc_data_direction = dir; - srb->sdb.table.sgl = buff ? &info->sg : NULL; - srb->sdb.length = bufflen; - srb->sdb.table.nents = buff ? 1 : 0; -} - -static void isd200_srb_set_bufflen(struct scsi_cmnd *srb, unsigned bufflen) -{ - srb->sdb.length = bufflen; -} - - -/************************************************************************** - * isd200_action - * - * Routine for sending commands to the isd200 - * - * RETURNS: - * ISD status code - */ -static int isd200_action( struct us_data *us, int action, - void* pointer, int value ) -{ - union ata_cdb ata; - /* static to prevent this large struct being placed on the valuable stack */ - static struct scsi_device srb_dev; - struct isd200_info *info = (struct isd200_info *)us->extra; - struct scsi_cmnd *srb = &info->srb; - int status; - - memset(&ata, 0, sizeof(ata)); - srb->cmnd = info->cmnd; - srb->device = &srb_dev; - - ata.generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; - ata.generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; - ata.generic.TransferBlockSize = 1; - - switch ( action ) { - case ACTION_READ_STATUS: - US_DEBUGP(" isd200_action(READ_STATUS)\n"); - ata.generic.ActionSelect = ACTION_SELECT_0|ACTION_SELECT_2; - ata.generic.RegisterSelect = - REG_CYLINDER_LOW | REG_CYLINDER_HIGH | - REG_STATUS | REG_ERROR; - isd200_set_srb(info, DMA_FROM_DEVICE, pointer, value); - break; - - case ACTION_ENUM: - US_DEBUGP(" isd200_action(ENUM,0x%02x)\n",value); - ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| - ACTION_SELECT_3|ACTION_SELECT_4| - ACTION_SELECT_5; - ata.generic.RegisterSelect = REG_DEVICE_HEAD; - ata.write.DeviceHeadByte = value; - isd200_set_srb(info, DMA_NONE, NULL, 0); - break; - - case ACTION_RESET: - US_DEBUGP(" isd200_action(RESET)\n"); - ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| - ACTION_SELECT_3|ACTION_SELECT_4; - ata.generic.RegisterSelect = REG_DEVICE_CONTROL; - ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER; - isd200_set_srb(info, DMA_NONE, NULL, 0); - break; - - case ACTION_REENABLE: - US_DEBUGP(" isd200_action(REENABLE)\n"); - ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2| - ACTION_SELECT_3|ACTION_SELECT_4; - ata.generic.RegisterSelect = REG_DEVICE_CONTROL; - ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER; - isd200_set_srb(info, DMA_NONE, NULL, 0); - break; - - case ACTION_SOFT_RESET: - US_DEBUGP(" isd200_action(SOFT_RESET)\n"); - ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_5; - ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND; - ata.write.DeviceHeadByte = info->DeviceHead; - ata.write.CommandByte = ATA_CMD_DEV_RESET; - isd200_set_srb(info, DMA_NONE, NULL, 0); - break; - - case ACTION_IDENTIFY: - US_DEBUGP(" isd200_action(IDENTIFY)\n"); - ata.generic.RegisterSelect = REG_COMMAND; - ata.write.CommandByte = ATA_CMD_ID_ATA; - isd200_set_srb(info, DMA_FROM_DEVICE, info->id, - ATA_ID_WORDS * 2); - break; - - default: - US_DEBUGP("Error: Undefined action %d\n",action); - return ISD200_ERROR; - } - - memcpy(srb->cmnd, &ata, sizeof(ata.generic)); - srb->cmd_len = sizeof(ata.generic); - status = usb_stor_Bulk_transport(srb, us); - if (status == USB_STOR_TRANSPORT_GOOD) - status = ISD200_GOOD; - else { - US_DEBUGP(" isd200_action(0x%02x) error: %d\n",action,status); - status = ISD200_ERROR; - /* need to reset device here */ - } - - return status; -} - -/************************************************************************** - * isd200_read_regs - * - * Read ATA Registers - * - * RETURNS: - * ISD status code - */ -static int isd200_read_regs( struct us_data *us ) -{ - struct isd200_info *info = (struct isd200_info *)us->extra; - int retStatus = ISD200_GOOD; - int transferStatus; - - US_DEBUGP("Entering isd200_IssueATAReadRegs\n"); - - transferStatus = isd200_action( us, ACTION_READ_STATUS, - info->RegsBuf, sizeof(info->ATARegs) ); - if (transferStatus != ISD200_TRANSPORT_GOOD) { - US_DEBUGP(" Error reading ATA registers\n"); - retStatus = ISD200_ERROR; - } else { - memcpy(info->ATARegs, info->RegsBuf, sizeof(info->ATARegs)); - US_DEBUGP(" Got ATA Register[ATA_REG_ERROR_OFFSET] = 0x%x\n", - info->ATARegs[ATA_REG_ERROR_OFFSET]); - } - - return retStatus; -} - - -/************************************************************************** - * Invoke the transport and basic error-handling/recovery methods - * - * This is used by the protocol layers to actually send the message to - * the device and receive the response. - */ -static void isd200_invoke_transport( struct us_data *us, - struct scsi_cmnd *srb, - union ata_cdb *ataCdb ) -{ - int need_auto_sense = 0; - int transferStatus; - int result; - - /* send the command to the transport layer */ - memcpy(srb->cmnd, ataCdb, sizeof(ataCdb->generic)); - srb->cmd_len = sizeof(ataCdb->generic); - transferStatus = usb_stor_Bulk_transport(srb, us); - - /* if the command gets aborted by the higher layers, we need to - * short-circuit all other processing - */ - if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { - US_DEBUGP("-- command was aborted\n"); - goto Handle_Abort; - } - - switch (transferStatus) { - - case USB_STOR_TRANSPORT_GOOD: - /* Indicate a good result */ - srb->result = SAM_STAT_GOOD; - break; - - case USB_STOR_TRANSPORT_NO_SENSE: - US_DEBUGP("-- transport indicates protocol failure\n"); - srb->result = SAM_STAT_CHECK_CONDITION; - return; - - case USB_STOR_TRANSPORT_FAILED: - US_DEBUGP("-- transport indicates command failure\n"); - need_auto_sense = 1; - break; - - case USB_STOR_TRANSPORT_ERROR: - US_DEBUGP("-- transport indicates transport error\n"); - srb->result = DID_ERROR << 16; - /* Need reset here */ - return; - - default: - US_DEBUGP("-- transport indicates unknown error\n"); - srb->result = DID_ERROR << 16; - /* Need reset here */ - return; - } - - if ((scsi_get_resid(srb) > 0) && - !((srb->cmnd[0] == REQUEST_SENSE) || - (srb->cmnd[0] == INQUIRY) || - (srb->cmnd[0] == MODE_SENSE) || - (srb->cmnd[0] == LOG_SENSE) || - (srb->cmnd[0] == MODE_SENSE_10))) { - US_DEBUGP("-- unexpectedly short transfer\n"); - need_auto_sense = 1; - } - - if (need_auto_sense) { - result = isd200_read_regs(us); - if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { - US_DEBUGP("-- auto-sense aborted\n"); - goto Handle_Abort; - } - if (result == ISD200_GOOD) { - isd200_build_sense(us, srb); - srb->result = SAM_STAT_CHECK_CONDITION; - - /* If things are really okay, then let's show that */ - if ((srb->sense_buffer[2] & 0xf) == 0x0) - srb->result = SAM_STAT_GOOD; - } else { - srb->result = DID_ERROR << 16; - /* Need reset here */ - } - } - - /* Regardless of auto-sense, if we _know_ we have an error - * condition, show that in the result code - */ - if (transferStatus == USB_STOR_TRANSPORT_FAILED) - srb->result = SAM_STAT_CHECK_CONDITION; - return; - - /* abort processing: the bulk-only transport requires a reset - * following an abort */ - Handle_Abort: - srb->result = DID_ABORT << 16; - - /* permit the reset transfer to take place */ - clear_bit(US_FLIDX_ABORTING, &us->dflags); - /* Need reset here */ -} - -#ifdef CONFIG_USB_STORAGE_DEBUG -static void isd200_log_config( struct isd200_info* info ) -{ - US_DEBUGP(" Event Notification: 0x%x\n", - info->ConfigData.EventNotification); - US_DEBUGP(" External Clock: 0x%x\n", - info->ConfigData.ExternalClock); - US_DEBUGP(" ATA Init Timeout: 0x%x\n", - info->ConfigData.ATAInitTimeout); - US_DEBUGP(" ATAPI Command Block Size: 0x%x\n", - (info->ConfigData.ATAConfig & ATACFG_BLOCKSIZE) >> 6); - US_DEBUGP(" Master/Slave Selection: 0x%x\n", - info->ConfigData.ATAConfig & ATACFG_MASTER); - US_DEBUGP(" ATAPI Reset: 0x%x\n", - info->ConfigData.ATAConfig & ATACFG_ATAPI_RESET); - US_DEBUGP(" ATA Timing: 0x%x\n", - info->ConfigData.ATAConfig & ATACFG_TIMING); - US_DEBUGP(" ATA Major Command: 0x%x\n", - info->ConfigData.ATAMajorCommand); - US_DEBUGP(" ATA Minor Command: 0x%x\n", - info->ConfigData.ATAMinorCommand); - US_DEBUGP(" Init Status: 0x%x\n", - info->ConfigData.ATAExtraConfig & ATACFGE_INIT_STATUS); - US_DEBUGP(" Config Descriptor 2: 0x%x\n", - info->ConfigData.ATAExtraConfig & ATACFGE_CONF_DESC2); - US_DEBUGP(" Skip Device Boot: 0x%x\n", - info->ConfigData.ATAExtraConfig & ATACFGE_SKIP_BOOT); - US_DEBUGP(" ATA 3 State Supsend: 0x%x\n", - info->ConfigData.ATAExtraConfig & ATACFGE_STATE_SUSPEND); - US_DEBUGP(" Descriptor Override: 0x%x\n", - info->ConfigData.ATAExtraConfig & ATACFGE_DESC_OVERRIDE); - US_DEBUGP(" Last LUN Identifier: 0x%x\n", - info->ConfigData.ATAExtraConfig & ATACFGE_LAST_LUN); - US_DEBUGP(" SRST Enable: 0x%x\n", - info->ConfigData.ATAExtraConfig & CFG_CAPABILITY_SRST); -} -#endif - -/************************************************************************** - * isd200_write_config - * - * Write the ISD200 Configuration data - * - * RETURNS: - * ISD status code - */ -static int isd200_write_config( struct us_data *us ) -{ - struct isd200_info *info = (struct isd200_info *)us->extra; - int retStatus = ISD200_GOOD; - int result; - -#ifdef CONFIG_USB_STORAGE_DEBUG - US_DEBUGP("Entering isd200_write_config\n"); - US_DEBUGP(" Writing the following ISD200 Config Data:\n"); - isd200_log_config(info); -#endif - - /* let's send the command via the control pipe */ - result = usb_stor_ctrl_transfer( - us, - us->send_ctrl_pipe, - 0x01, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, - 0x0000, - 0x0002, - (void *) &info->ConfigData, - sizeof(info->ConfigData)); - - if (result >= 0) { - US_DEBUGP(" ISD200 Config Data was written successfully\n"); - } else { - US_DEBUGP(" Request to write ISD200 Config Data failed!\n"); - retStatus = ISD200_ERROR; - } - - US_DEBUGP("Leaving isd200_write_config %08X\n", retStatus); - return retStatus; -} - - -/************************************************************************** - * isd200_read_config - * - * Reads the ISD200 Configuration data - * - * RETURNS: - * ISD status code - */ -static int isd200_read_config( struct us_data *us ) -{ - struct isd200_info *info = (struct isd200_info *)us->extra; - int retStatus = ISD200_GOOD; - int result; - - US_DEBUGP("Entering isd200_read_config\n"); - - /* read the configuration information from ISD200. Use this to */ - /* determine what the special ATA CDB bytes are. */ - - result = usb_stor_ctrl_transfer( - us, - us->recv_ctrl_pipe, - 0x02, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0x0000, - 0x0002, - (void *) &info->ConfigData, - sizeof(info->ConfigData)); - - - if (result >= 0) { - US_DEBUGP(" Retrieved the following ISD200 Config Data:\n"); -#ifdef CONFIG_USB_STORAGE_DEBUG - isd200_log_config(info); -#endif - } else { - US_DEBUGP(" Request to get ISD200 Config Data failed!\n"); - retStatus = ISD200_ERROR; - } - - US_DEBUGP("Leaving isd200_read_config %08X\n", retStatus); - return retStatus; -} - - -/************************************************************************** - * isd200_atapi_soft_reset - * - * Perform an Atapi Soft Reset on the device - * - * RETURNS: - * NT status code - */ -static int isd200_atapi_soft_reset( struct us_data *us ) -{ - int retStatus = ISD200_GOOD; - int transferStatus; - - US_DEBUGP("Entering isd200_atapi_soft_reset\n"); - - transferStatus = isd200_action( us, ACTION_SOFT_RESET, NULL, 0 ); - if (transferStatus != ISD200_TRANSPORT_GOOD) { - US_DEBUGP(" Error issuing Atapi Soft Reset\n"); - retStatus = ISD200_ERROR; - } - - US_DEBUGP("Leaving isd200_atapi_soft_reset %08X\n", retStatus); - return retStatus; -} - - -/************************************************************************** - * isd200_srst - * - * Perform an SRST on the device - * - * RETURNS: - * ISD status code - */ -static int isd200_srst( struct us_data *us ) -{ - int retStatus = ISD200_GOOD; - int transferStatus; - - US_DEBUGP("Entering isd200_SRST\n"); - - transferStatus = isd200_action( us, ACTION_RESET, NULL, 0 ); - - /* check to see if this request failed */ - if (transferStatus != ISD200_TRANSPORT_GOOD) { - US_DEBUGP(" Error issuing SRST\n"); - retStatus = ISD200_ERROR; - } else { - /* delay 10ms to give the drive a chance to see it */ - msleep(10); - - transferStatus = isd200_action( us, ACTION_REENABLE, NULL, 0 ); - if (transferStatus != ISD200_TRANSPORT_GOOD) { - US_DEBUGP(" Error taking drive out of reset\n"); - retStatus = ISD200_ERROR; - } else { - /* delay 50ms to give the drive a chance to recover after SRST */ - msleep(50); - } - } - - US_DEBUGP("Leaving isd200_srst %08X\n", retStatus); - return retStatus; -} - - -/************************************************************************** - * isd200_try_enum - * - * Helper function for isd200_manual_enum(). Does ENUM and READ_STATUS - * and tries to analyze the status registers - * - * RETURNS: - * ISD status code - */ -static int isd200_try_enum(struct us_data *us, unsigned char master_slave, - int detect ) -{ - int status = ISD200_GOOD; - unsigned long endTime; - struct isd200_info *info = (struct isd200_info *)us->extra; - unsigned char *regs = info->RegsBuf; - int recheckAsMaster = 0; - - if ( detect ) - endTime = jiffies + ISD200_ENUM_DETECT_TIMEOUT * HZ; - else - endTime = jiffies + ISD200_ENUM_BSY_TIMEOUT * HZ; - - /* loop until we detect !BSY or timeout */ - while(1) { -#ifdef CONFIG_USB_STORAGE_DEBUG - char* mstr = master_slave == ATA_ADDRESS_DEVHEAD_STD ? - "Master" : "Slave"; -#endif - - status = isd200_action( us, ACTION_ENUM, NULL, master_slave ); - if ( status != ISD200_GOOD ) - break; - - status = isd200_action( us, ACTION_READ_STATUS, - regs, 8 ); - if ( status != ISD200_GOOD ) - break; - - if (!detect) { - if (regs[ATA_REG_STATUS_OFFSET] & ATA_BUSY) { - US_DEBUGP(" %s status is still BSY, try again...\n",mstr); - } else { - US_DEBUGP(" %s status !BSY, continue with next operation\n",mstr); - break; - } - } - /* check for ATA_BUSY and */ - /* ATA_DF (workaround ATA Zip drive) and */ - /* ATA_ERR (workaround for Archos CD-ROM) */ - else if (regs[ATA_REG_STATUS_OFFSET] & - (ATA_BUSY | ATA_DF | ATA_ERR)) { - US_DEBUGP(" Status indicates it is not ready, try again...\n"); - } - /* check for DRDY, ATA devices set DRDY after SRST */ - else if (regs[ATA_REG_STATUS_OFFSET] & ATA_DRDY) { - US_DEBUGP(" Identified ATA device\n"); - info->DeviceFlags |= DF_ATA_DEVICE; - info->DeviceHead = master_slave; - break; - } - /* check Cylinder High/Low to - determine if it is an ATAPI device - */ - else if (regs[ATA_REG_HCYL_OFFSET] == 0xEB && - regs[ATA_REG_LCYL_OFFSET] == 0x14) { - /* It seems that the RICOH - MP6200A CD/RW drive will - report itself okay as a - slave when it is really a - master. So this check again - as a master device just to - make sure it doesn't report - itself okay as a master also - */ - if ((master_slave & ATA_ADDRESS_DEVHEAD_SLAVE) && - !recheckAsMaster) { - US_DEBUGP(" Identified ATAPI device as slave. Rechecking again as master\n"); - recheckAsMaster = 1; - master_slave = ATA_ADDRESS_DEVHEAD_STD; - } else { - US_DEBUGP(" Identified ATAPI device\n"); - info->DeviceHead = master_slave; - - status = isd200_atapi_soft_reset(us); - break; - } - } else { - US_DEBUGP(" Not ATA, not ATAPI. Weird.\n"); - break; - } - - /* check for timeout on this request */ - if (time_after_eq(jiffies, endTime)) { - if (!detect) - US_DEBUGP(" BSY check timeout, just continue with next operation...\n"); - else - US_DEBUGP(" Device detect timeout!\n"); - break; - } - } - - return status; -} - -/************************************************************************** - * isd200_manual_enum - * - * Determines if the drive attached is an ATA or ATAPI and if it is a - * master or slave. - * - * RETURNS: - * ISD status code - */ -static int isd200_manual_enum(struct us_data *us) -{ - struct isd200_info *info = (struct isd200_info *)us->extra; - int retStatus = ISD200_GOOD; - - US_DEBUGP("Entering isd200_manual_enum\n"); - - retStatus = isd200_read_config(us); - if (retStatus == ISD200_GOOD) { - int isslave; - /* master or slave? */ - retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, 0); - if (retStatus == ISD200_GOOD) - retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_SLAVE, 0); - - if (retStatus == ISD200_GOOD) { - retStatus = isd200_srst(us); - if (retStatus == ISD200_GOOD) - /* ata or atapi? */ - retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, 1); - } - - isslave = (info->DeviceHead & ATA_ADDRESS_DEVHEAD_SLAVE) ? 1 : 0; - if (!(info->ConfigData.ATAConfig & ATACFG_MASTER)) { - US_DEBUGP(" Setting Master/Slave selection to %d\n", isslave); - info->ConfigData.ATAConfig &= 0x3f; - info->ConfigData.ATAConfig |= (isslave<<6); - retStatus = isd200_write_config(us); - } - } - - US_DEBUGP("Leaving isd200_manual_enum %08X\n", retStatus); - return(retStatus); -} - -static void isd200_fix_driveid(u16 *id) -{ -#ifndef __LITTLE_ENDIAN -# ifdef __BIG_ENDIAN - int i; - - for (i = 0; i < ATA_ID_WORDS; i++) - id[i] = __le16_to_cpu(id[i]); -# else -# error "Please fix " -# endif -#endif -} - -static void isd200_dump_driveid(u16 *id) -{ - US_DEBUGP(" Identify Data Structure:\n"); - US_DEBUGP(" config = 0x%x\n", id[ATA_ID_CONFIG]); - US_DEBUGP(" cyls = 0x%x\n", id[ATA_ID_CYLS]); - US_DEBUGP(" heads = 0x%x\n", id[ATA_ID_HEADS]); - US_DEBUGP(" track_bytes = 0x%x\n", id[4]); - US_DEBUGP(" sector_bytes = 0x%x\n", id[5]); - US_DEBUGP(" sectors = 0x%x\n", id[ATA_ID_SECTORS]); - US_DEBUGP(" serial_no[0] = 0x%x\n", *(char *)&id[ATA_ID_SERNO]); - US_DEBUGP(" buf_type = 0x%x\n", id[20]); - US_DEBUGP(" buf_size = 0x%x\n", id[ATA_ID_BUF_SIZE]); - US_DEBUGP(" ecc_bytes = 0x%x\n", id[22]); - US_DEBUGP(" fw_rev[0] = 0x%x\n", *(char *)&id[ATA_ID_FW_REV]); - US_DEBUGP(" model[0] = 0x%x\n", *(char *)&id[ATA_ID_PROD]); - US_DEBUGP(" max_multsect = 0x%x\n", id[ATA_ID_MAX_MULTSECT] & 0xff); - US_DEBUGP(" dword_io = 0x%x\n", id[ATA_ID_DWORD_IO]); - US_DEBUGP(" capability = 0x%x\n", id[ATA_ID_CAPABILITY] >> 8); - US_DEBUGP(" tPIO = 0x%x\n", id[ATA_ID_OLD_PIO_MODES] >> 8); - US_DEBUGP(" tDMA = 0x%x\n", id[ATA_ID_OLD_DMA_MODES] >> 8); - US_DEBUGP(" field_valid = 0x%x\n", id[ATA_ID_FIELD_VALID]); - US_DEBUGP(" cur_cyls = 0x%x\n", id[ATA_ID_CUR_CYLS]); - US_DEBUGP(" cur_heads = 0x%x\n", id[ATA_ID_CUR_HEADS]); - US_DEBUGP(" cur_sectors = 0x%x\n", id[ATA_ID_CUR_SECTORS]); - US_DEBUGP(" cur_capacity = 0x%x\n", ata_id_u32(id, 57)); - US_DEBUGP(" multsect = 0x%x\n", id[ATA_ID_MULTSECT] & 0xff); - US_DEBUGP(" lba_capacity = 0x%x\n", ata_id_u32(id, ATA_ID_LBA_CAPACITY)); - US_DEBUGP(" command_set_1 = 0x%x\n", id[ATA_ID_COMMAND_SET_1]); - US_DEBUGP(" command_set_2 = 0x%x\n", id[ATA_ID_COMMAND_SET_2]); -} - -/************************************************************************** - * isd200_get_inquiry_data - * - * Get inquiry data - * - * RETURNS: - * ISD status code - */ -static int isd200_get_inquiry_data( struct us_data *us ) -{ - struct isd200_info *info = (struct isd200_info *)us->extra; - int retStatus = ISD200_GOOD; - u16 *id = info->id; - - US_DEBUGP("Entering isd200_get_inquiry_data\n"); - - /* set default to Master */ - info->DeviceHead = ATA_ADDRESS_DEVHEAD_STD; - - /* attempt to manually enumerate this device */ - retStatus = isd200_manual_enum(us); - if (retStatus == ISD200_GOOD) { - int transferStatus; - - /* check for an ATA device */ - if (info->DeviceFlags & DF_ATA_DEVICE) { - /* this must be an ATA device */ - /* perform an ATA Command Identify */ - transferStatus = isd200_action( us, ACTION_IDENTIFY, - id, ATA_ID_WORDS * 2); - if (transferStatus != ISD200_TRANSPORT_GOOD) { - /* Error issuing ATA Command Identify */ - US_DEBUGP(" Error issuing ATA Command Identify\n"); - retStatus = ISD200_ERROR; - } else { - /* ATA Command Identify successful */ - int i; - __be16 *src; - __u16 *dest; - - isd200_fix_driveid(id); - isd200_dump_driveid(id); - - memset(&info->InquiryData, 0, sizeof(info->InquiryData)); - - /* Standard IDE interface only supports disks */ - info->InquiryData.DeviceType = DIRECT_ACCESS_DEVICE; - - /* The length must be at least 36 (5 + 31) */ - info->InquiryData.AdditionalLength = 0x1F; - - if (id[ATA_ID_COMMAND_SET_1] & COMMANDSET_MEDIA_STATUS) { - /* set the removable bit */ - info->InquiryData.DeviceTypeModifier = DEVICE_REMOVABLE; - info->DeviceFlags |= DF_REMOVABLE_MEDIA; - } - - /* Fill in vendor identification fields */ - src = (__be16 *)&id[ATA_ID_PROD]; - dest = (__u16*)info->InquiryData.VendorId; - for (i=0;i<4;i++) - dest[i] = be16_to_cpu(src[i]); - - src = (__be16 *)&id[ATA_ID_PROD + 8/2]; - dest = (__u16*)info->InquiryData.ProductId; - for (i=0;i<8;i++) - dest[i] = be16_to_cpu(src[i]); - - src = (__be16 *)&id[ATA_ID_FW_REV]; - dest = (__u16*)info->InquiryData.ProductRevisionLevel; - for (i=0;i<2;i++) - dest[i] = be16_to_cpu(src[i]); - - /* determine if it supports Media Status Notification */ - if (id[ATA_ID_COMMAND_SET_2] & COMMANDSET_MEDIA_STATUS) { - US_DEBUGP(" Device supports Media Status Notification\n"); - - /* Indicate that it is enabled, even though it is not - * This allows the lock/unlock of the media to work - * correctly. - */ - info->DeviceFlags |= DF_MEDIA_STATUS_ENABLED; - } - else - info->DeviceFlags &= ~DF_MEDIA_STATUS_ENABLED; - - } - } else { - /* - * this must be an ATAPI device - * use an ATAPI protocol (Transparent SCSI) - */ - us->protocol_name = "Transparent SCSI"; - us->proto_handler = usb_stor_transparent_scsi_command; - - US_DEBUGP("Protocol changed to: %s\n", us->protocol_name); - - /* Free driver structure */ - us->extra_destructor(info); - kfree(info); - us->extra = NULL; - us->extra_destructor = NULL; - } - } - - US_DEBUGP("Leaving isd200_get_inquiry_data %08X\n", retStatus); - - return(retStatus); -} - -/************************************************************************** - * isd200_scsi_to_ata - * - * Translate SCSI commands to ATA commands. - * - * RETURNS: - * 1 if the command needs to be sent to the transport layer - * 0 otherwise - */ -static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, - union ata_cdb * ataCdb) -{ - struct isd200_info *info = (struct isd200_info *)us->extra; - u16 *id = info->id; - int sendToTransport = 1; - unsigned char sectnum, head; - unsigned short cylinder; - unsigned long lba; - unsigned long blockCount; - unsigned char senseData[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - - memset(ataCdb, 0, sizeof(union ata_cdb)); - - /* SCSI Command */ - switch (srb->cmnd[0]) { - case INQUIRY: - US_DEBUGP(" ATA OUT - INQUIRY\n"); - - /* copy InquiryData */ - usb_stor_set_xfer_buf((unsigned char *) &info->InquiryData, - sizeof(info->InquiryData), srb); - srb->result = SAM_STAT_GOOD; - sendToTransport = 0; - break; - - case MODE_SENSE: - US_DEBUGP(" ATA OUT - SCSIOP_MODE_SENSE\n"); - - /* Initialize the return buffer */ - usb_stor_set_xfer_buf(senseData, sizeof(senseData), srb); - - if (info->DeviceFlags & DF_MEDIA_STATUS_ENABLED) - { - ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; - ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; - ataCdb->generic.TransferBlockSize = 1; - ataCdb->generic.RegisterSelect = REG_COMMAND; - ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; - isd200_srb_set_bufflen(srb, 0); - } else { - US_DEBUGP(" Media Status not supported, just report okay\n"); - srb->result = SAM_STAT_GOOD; - sendToTransport = 0; - } - break; - - case TEST_UNIT_READY: - US_DEBUGP(" ATA OUT - SCSIOP_TEST_UNIT_READY\n"); - - if (info->DeviceFlags & DF_MEDIA_STATUS_ENABLED) - { - ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; - ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; - ataCdb->generic.TransferBlockSize = 1; - ataCdb->generic.RegisterSelect = REG_COMMAND; - ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; - isd200_srb_set_bufflen(srb, 0); - } else { - US_DEBUGP(" Media Status not supported, just report okay\n"); - srb->result = SAM_STAT_GOOD; - sendToTransport = 0; - } - break; - - case READ_CAPACITY: - { - unsigned long capacity; - struct read_capacity_data readCapacityData; - - US_DEBUGP(" ATA OUT - SCSIOP_READ_CAPACITY\n"); - - if (ata_id_has_lba(id)) - capacity = ata_id_u32(id, ATA_ID_LBA_CAPACITY) - 1; - else - capacity = (id[ATA_ID_HEADS] * id[ATA_ID_CYLS] * - id[ATA_ID_SECTORS]) - 1; - - readCapacityData.LogicalBlockAddress = cpu_to_be32(capacity); - readCapacityData.BytesPerBlock = cpu_to_be32(0x200); - - usb_stor_set_xfer_buf((unsigned char *) &readCapacityData, - sizeof(readCapacityData), srb); - srb->result = SAM_STAT_GOOD; - sendToTransport = 0; - } - break; - - case READ_10: - US_DEBUGP(" ATA OUT - SCSIOP_READ\n"); - - lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]); - blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8]; - - if (ata_id_has_lba(id)) { - sectnum = (unsigned char)(lba); - cylinder = (unsigned short)(lba>>8); - head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F); - } else { - sectnum = (u8)((lba % id[ATA_ID_SECTORS]) + 1); - cylinder = (u16)(lba / (id[ATA_ID_SECTORS] * - id[ATA_ID_HEADS])); - head = (u8)((lba / id[ATA_ID_SECTORS]) % - id[ATA_ID_HEADS]); - } - ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; - ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; - ataCdb->generic.TransferBlockSize = 1; - ataCdb->generic.RegisterSelect = - REG_SECTOR_COUNT | REG_SECTOR_NUMBER | - REG_CYLINDER_LOW | REG_CYLINDER_HIGH | - REG_DEVICE_HEAD | REG_COMMAND; - ataCdb->write.SectorCountByte = (unsigned char)blockCount; - ataCdb->write.SectorNumberByte = sectnum; - ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8); - ataCdb->write.CylinderLowByte = (unsigned char)cylinder; - ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD); - ataCdb->write.CommandByte = ATA_CMD_PIO_READ; - break; - - case WRITE_10: - US_DEBUGP(" ATA OUT - SCSIOP_WRITE\n"); - - lba = be32_to_cpu(*(__be32 *)&srb->cmnd[2]); - blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8]; - - if (ata_id_has_lba(id)) { - sectnum = (unsigned char)(lba); - cylinder = (unsigned short)(lba>>8); - head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F); - } else { - sectnum = (u8)((lba % id[ATA_ID_SECTORS]) + 1); - cylinder = (u16)(lba / (id[ATA_ID_SECTORS] * - id[ATA_ID_HEADS])); - head = (u8)((lba / id[ATA_ID_SECTORS]) % - id[ATA_ID_HEADS]); - } - ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; - ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; - ataCdb->generic.TransferBlockSize = 1; - ataCdb->generic.RegisterSelect = - REG_SECTOR_COUNT | REG_SECTOR_NUMBER | - REG_CYLINDER_LOW | REG_CYLINDER_HIGH | - REG_DEVICE_HEAD | REG_COMMAND; - ataCdb->write.SectorCountByte = (unsigned char)blockCount; - ataCdb->write.SectorNumberByte = sectnum; - ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8); - ataCdb->write.CylinderLowByte = (unsigned char)cylinder; - ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD); - ataCdb->write.CommandByte = ATA_CMD_PIO_WRITE; - break; - - case ALLOW_MEDIUM_REMOVAL: - US_DEBUGP(" ATA OUT - SCSIOP_MEDIUM_REMOVAL\n"); - - if (info->DeviceFlags & DF_REMOVABLE_MEDIA) { - US_DEBUGP(" srb->cmnd[4] = 0x%X\n", srb->cmnd[4]); - - ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; - ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; - ataCdb->generic.TransferBlockSize = 1; - ataCdb->generic.RegisterSelect = REG_COMMAND; - ataCdb->write.CommandByte = (srb->cmnd[4] & 0x1) ? - ATA_CMD_MEDIA_LOCK : ATA_CMD_MEDIA_UNLOCK; - isd200_srb_set_bufflen(srb, 0); - } else { - US_DEBUGP(" Not removeable media, just report okay\n"); - srb->result = SAM_STAT_GOOD; - sendToTransport = 0; - } - break; - - case START_STOP: - US_DEBUGP(" ATA OUT - SCSIOP_START_STOP_UNIT\n"); - US_DEBUGP(" srb->cmnd[4] = 0x%X\n", srb->cmnd[4]); - - if ((srb->cmnd[4] & 0x3) == 0x2) { - US_DEBUGP(" Media Eject\n"); - ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; - ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; - ataCdb->generic.TransferBlockSize = 0; - ataCdb->generic.RegisterSelect = REG_COMMAND; - ataCdb->write.CommandByte = ATA_COMMAND_MEDIA_EJECT; - } else if ((srb->cmnd[4] & 0x3) == 0x1) { - US_DEBUGP(" Get Media Status\n"); - ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; - ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; - ataCdb->generic.TransferBlockSize = 1; - ataCdb->generic.RegisterSelect = REG_COMMAND; - ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; - isd200_srb_set_bufflen(srb, 0); - } else { - US_DEBUGP(" Nothing to do, just report okay\n"); - srb->result = SAM_STAT_GOOD; - sendToTransport = 0; - } - break; - - default: - US_DEBUGP("Unsupported SCSI command - 0x%X\n", srb->cmnd[0]); - srb->result = DID_ERROR << 16; - sendToTransport = 0; - break; - } - - return(sendToTransport); -} - - -/************************************************************************** - * isd200_free_info - * - * Frees the driver structure. - */ -static void isd200_free_info_ptrs(void *info_) -{ - struct isd200_info *info = (struct isd200_info *) info_; - - if (info) { - kfree(info->id); - kfree(info->RegsBuf); - kfree(info->srb.sense_buffer); - } -} - -/************************************************************************** - * isd200_init_info - * - * Allocates (if necessary) and initializes the driver structure. - * - * RETURNS: - * ISD status code - */ -static int isd200_init_info(struct us_data *us) -{ - int retStatus = ISD200_GOOD; - struct isd200_info *info; - - info = kzalloc(sizeof(struct isd200_info), GFP_KERNEL); - if (!info) - retStatus = ISD200_ERROR; - else { - info->id = kzalloc(ATA_ID_WORDS * 2, GFP_KERNEL); - info->RegsBuf = (unsigned char *) - kmalloc(sizeof(info->ATARegs), GFP_KERNEL); - info->srb.sense_buffer = - kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); - if (!info->id || !info->RegsBuf || !info->srb.sense_buffer) { - isd200_free_info_ptrs(info); - kfree(info); - retStatus = ISD200_ERROR; - } - } - - if (retStatus == ISD200_GOOD) { - us->extra = info; - us->extra_destructor = isd200_free_info_ptrs; - } else - US_DEBUGP("ERROR - kmalloc failure\n"); - - return retStatus; -} - -/************************************************************************** - * Initialization for the ISD200 - */ - -static int isd200_Initialization(struct us_data *us) -{ - US_DEBUGP("ISD200 Initialization...\n"); - - /* Initialize ISD200 info struct */ - - if (isd200_init_info(us) == ISD200_ERROR) { - US_DEBUGP("ERROR Initializing ISD200 Info struct\n"); - } else { - /* Get device specific data */ - - if (isd200_get_inquiry_data(us) != ISD200_GOOD) - US_DEBUGP("ISD200 Initialization Failure\n"); - else - US_DEBUGP("ISD200 Initialization complete\n"); - } - - return 0; -} - - -/************************************************************************** - * Protocol and Transport for the ISD200 ASIC - * - * This protocol and transport are for ATA devices connected to an ISD200 - * ASIC. An ATAPI device that is connected as a slave device will be - * detected in the driver initialization function and the protocol will - * be changed to an ATAPI protocol (Transparent SCSI). - * - */ - -static void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us) -{ - int sendToTransport = 1, orig_bufflen; - union ata_cdb ataCdb; - - /* Make sure driver was initialized */ - - if (us->extra == NULL) - US_DEBUGP("ERROR Driver not initialized\n"); - - scsi_set_resid(srb, 0); - /* scsi_bufflen might change in protocol translation to ata */ - orig_bufflen = scsi_bufflen(srb); - sendToTransport = isd200_scsi_to_ata(srb, us, &ataCdb); - - /* send the command to the transport layer */ - if (sendToTransport) - isd200_invoke_transport(us, srb, &ataCdb); - - isd200_srb_set_bufflen(srb, orig_bufflen); -} - -static int isd200_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct us_data *us; - int result; - - result = usb_stor_probe1(&us, intf, id, - (id - isd200_usb_ids) + isd200_unusual_dev_list); - if (result) - return result; - - us->protocol_name = "ISD200 ATA/ATAPI"; - us->proto_handler = isd200_ata_command; - - result = usb_stor_probe2(us); - return result; -} - -static struct usb_driver isd200_driver = { - .name = "ums-isd200", - .probe = isd200_probe, - .disconnect = usb_stor_disconnect, - .suspend = usb_stor_suspend, - .resume = usb_stor_resume, - .reset_resume = usb_stor_reset_resume, - .pre_reset = usb_stor_pre_reset, - .post_reset = usb_stor_post_reset, - .id_table = isd200_usb_ids, - .soft_unbind = 1, - .no_dynamic_id = 1, -}; - -module_usb_driver(isd200_driver); diff --git a/ANDROID_3.4.5/drivers/usb/storage/jumpshot.c b/ANDROID_3.4.5/drivers/usb/storage/jumpshot.c deleted file mode 100644 index e3b97383..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/jumpshot.c +++ /dev/null @@ -1,683 +0,0 @@ -/* Driver for Lexar "Jumpshot" Compact Flash reader - * - * jumpshot driver v0.1: - * - * First release - * - * Current development and maintenance by: - * (c) 2000 Jimmie Mayfield (mayfield+usb@sackheads.org) - * - * Many thanks to Robert Baruch for the SanDisk SmartMedia reader driver - * which I used as a template for this driver. - * - * Some bugfixes and scatter-gather code by Gregory P. Smith - * (greg-usb@electricrain.com) - * - * Fix for media change by Joerg Schneider (js@joergschneider.com) - * - * Developed with the assistance of: - * - * (C) 2002 Alan Stern - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - /* - * This driver attempts to support the Lexar Jumpshot USB CompactFlash - * reader. Like many other USB CompactFlash readers, the Jumpshot contains - * a USB-to-ATA chip. - * - * This driver supports reading and writing. If you're truly paranoid, - * however, you can force the driver into a write-protected state by setting - * the WP enable bits in jumpshot_handle_mode_sense. See the comments - * in that routine. - */ - -#include -#include -#include - -#include -#include - -#include "usb.h" -#include "transport.h" -#include "protocol.h" -#include "debug.h" - - -MODULE_DESCRIPTION("Driver for Lexar \"Jumpshot\" Compact Flash reader"); -MODULE_AUTHOR("Jimmie Mayfield "); -MODULE_LICENSE("GPL"); - -/* - * The table of devices - */ -#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ - vendorName, productName, useProtocol, useTransport, \ - initFunction, flags) \ -{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } - -static struct usb_device_id jumpshot_usb_ids[] = { -# include "unusual_jumpshot.h" - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, jumpshot_usb_ids); - -#undef UNUSUAL_DEV - -/* - * The flags table - */ -#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ - vendor_name, product_name, use_protocol, use_transport, \ - init_function, Flags) \ -{ \ - .vendorName = vendor_name, \ - .productName = product_name, \ - .useProtocol = use_protocol, \ - .useTransport = use_transport, \ - .initFunction = init_function, \ -} - -static struct us_unusual_dev jumpshot_unusual_dev_list[] = { -# include "unusual_jumpshot.h" - { } /* Terminating entry */ -}; - -#undef UNUSUAL_DEV - - -struct jumpshot_info { - unsigned long sectors; /* total sector count */ - unsigned long ssize; /* sector size in bytes */ - - /* the following aren't used yet */ - unsigned char sense_key; - unsigned long sense_asc; /* additional sense code */ - unsigned long sense_ascq; /* additional sense code qualifier */ -}; - -static inline int jumpshot_bulk_read(struct us_data *us, - unsigned char *data, - unsigned int len) -{ - if (len == 0) - return USB_STOR_XFER_GOOD; - - US_DEBUGP("jumpshot_bulk_read: len = %d\n", len); - return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, - data, len, NULL); -} - - -static inline int jumpshot_bulk_write(struct us_data *us, - unsigned char *data, - unsigned int len) -{ - if (len == 0) - return USB_STOR_XFER_GOOD; - - US_DEBUGP("jumpshot_bulk_write: len = %d\n", len); - return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, - data, len, NULL); -} - - -static int jumpshot_get_status(struct us_data *us) -{ - int rc; - - if (!us) - return USB_STOR_TRANSPORT_ERROR; - - // send the setup - rc = usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe, - 0, 0xA0, 0, 7, us->iobuf, 1); - - if (rc != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - if (us->iobuf[0] != 0x50) { - US_DEBUGP("jumpshot_get_status: 0x%2x\n", - us->iobuf[0]); - return USB_STOR_TRANSPORT_ERROR; - } - - return USB_STOR_TRANSPORT_GOOD; -} - -static int jumpshot_read_data(struct us_data *us, - struct jumpshot_info *info, - u32 sector, - u32 sectors) -{ - unsigned char *command = us->iobuf; - unsigned char *buffer; - unsigned char thistime; - unsigned int totallen, alloclen; - int len, result; - unsigned int sg_offset = 0; - struct scatterlist *sg = NULL; - - // we're working in LBA mode. according to the ATA spec, - // we can support up to 28-bit addressing. I don't know if Jumpshot - // supports beyond 24-bit addressing. It's kind of hard to test - // since it requires > 8GB CF card. - - if (sector > 0x0FFFFFFF) - return USB_STOR_TRANSPORT_ERROR; - - totallen = sectors * info->ssize; - - // Since we don't read more than 64 KB at a time, we have to create - // a bounce buffer and move the data a piece at a time between the - // bounce buffer and the actual transfer buffer. - - alloclen = min(totallen, 65536u); - buffer = kmalloc(alloclen, GFP_NOIO); - if (buffer == NULL) - return USB_STOR_TRANSPORT_ERROR; - - do { - // loop, never allocate or transfer more than 64k at once - // (min(128k, 255*info->ssize) is the real limit) - len = min(totallen, alloclen); - thistime = (len / info->ssize) & 0xff; - - command[0] = 0; - command[1] = thistime; - command[2] = sector & 0xFF; - command[3] = (sector >> 8) & 0xFF; - command[4] = (sector >> 16) & 0xFF; - - command[5] = 0xE0 | ((sector >> 24) & 0x0F); - command[6] = 0x20; - - // send the setup + command - result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, - 0, 0x20, 0, 1, command, 7); - if (result != USB_STOR_XFER_GOOD) - goto leave; - - // read the result - result = jumpshot_bulk_read(us, buffer, len); - if (result != USB_STOR_XFER_GOOD) - goto leave; - - US_DEBUGP("jumpshot_read_data: %d bytes\n", len); - - // Store the data in the transfer buffer - usb_stor_access_xfer_buf(buffer, len, us->srb, - &sg, &sg_offset, TO_XFER_BUF); - - sector += thistime; - totallen -= len; - } while (totallen > 0); - - kfree(buffer); - return USB_STOR_TRANSPORT_GOOD; - - leave: - kfree(buffer); - return USB_STOR_TRANSPORT_ERROR; -} - - -static int jumpshot_write_data(struct us_data *us, - struct jumpshot_info *info, - u32 sector, - u32 sectors) -{ - unsigned char *command = us->iobuf; - unsigned char *buffer; - unsigned char thistime; - unsigned int totallen, alloclen; - int len, result, waitcount; - unsigned int sg_offset = 0; - struct scatterlist *sg = NULL; - - // we're working in LBA mode. according to the ATA spec, - // we can support up to 28-bit addressing. I don't know if Jumpshot - // supports beyond 24-bit addressing. It's kind of hard to test - // since it requires > 8GB CF card. - // - if (sector > 0x0FFFFFFF) - return USB_STOR_TRANSPORT_ERROR; - - totallen = sectors * info->ssize; - - // Since we don't write more than 64 KB at a time, we have to create - // a bounce buffer and move the data a piece at a time between the - // bounce buffer and the actual transfer buffer. - - alloclen = min(totallen, 65536u); - buffer = kmalloc(alloclen, GFP_NOIO); - if (buffer == NULL) - return USB_STOR_TRANSPORT_ERROR; - - do { - // loop, never allocate or transfer more than 64k at once - // (min(128k, 255*info->ssize) is the real limit) - - len = min(totallen, alloclen); - thistime = (len / info->ssize) & 0xff; - - // Get the data from the transfer buffer - usb_stor_access_xfer_buf(buffer, len, us->srb, - &sg, &sg_offset, FROM_XFER_BUF); - - command[0] = 0; - command[1] = thistime; - command[2] = sector & 0xFF; - command[3] = (sector >> 8) & 0xFF; - command[4] = (sector >> 16) & 0xFF; - - command[5] = 0xE0 | ((sector >> 24) & 0x0F); - command[6] = 0x30; - - // send the setup + command - result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, - 0, 0x20, 0, 1, command, 7); - if (result != USB_STOR_XFER_GOOD) - goto leave; - - // send the data - result = jumpshot_bulk_write(us, buffer, len); - if (result != USB_STOR_XFER_GOOD) - goto leave; - - // read the result. apparently the bulk write can complete - // before the jumpshot drive is finished writing. so we loop - // here until we get a good return code - waitcount = 0; - do { - result = jumpshot_get_status(us); - if (result != USB_STOR_TRANSPORT_GOOD) { - // I have not experimented to find the smallest value. - // - msleep(50); - } - } while ((result != USB_STOR_TRANSPORT_GOOD) && (waitcount < 10)); - - if (result != USB_STOR_TRANSPORT_GOOD) - US_DEBUGP("jumpshot_write_data: Gah! Waitcount = 10. Bad write!?\n"); - - sector += thistime; - totallen -= len; - } while (totallen > 0); - - kfree(buffer); - return result; - - leave: - kfree(buffer); - return USB_STOR_TRANSPORT_ERROR; -} - -static int jumpshot_id_device(struct us_data *us, - struct jumpshot_info *info) -{ - unsigned char *command = us->iobuf; - unsigned char *reply; - int rc; - - if (!info) - return USB_STOR_TRANSPORT_ERROR; - - command[0] = 0xE0; - command[1] = 0xEC; - reply = kmalloc(512, GFP_NOIO); - if (!reply) - return USB_STOR_TRANSPORT_ERROR; - - // send the setup - rc = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, - 0, 0x20, 0, 6, command, 2); - - if (rc != USB_STOR_XFER_GOOD) { - US_DEBUGP("jumpshot_id_device: Gah! " - "send_control for read_capacity failed\n"); - rc = USB_STOR_TRANSPORT_ERROR; - goto leave; - } - - // read the reply - rc = jumpshot_bulk_read(us, reply, 512); - if (rc != USB_STOR_XFER_GOOD) { - rc = USB_STOR_TRANSPORT_ERROR; - goto leave; - } - - info->sectors = ((u32)(reply[117]) << 24) | - ((u32)(reply[116]) << 16) | - ((u32)(reply[115]) << 8) | - ((u32)(reply[114]) ); - - rc = USB_STOR_TRANSPORT_GOOD; - - leave: - kfree(reply); - return rc; -} - -static int jumpshot_handle_mode_sense(struct us_data *us, - struct scsi_cmnd * srb, - int sense_6) -{ - static unsigned char rw_err_page[12] = { - 0x1, 0xA, 0x21, 1, 0, 0, 0, 0, 1, 0, 0, 0 - }; - static unsigned char cache_page[12] = { - 0x8, 0xA, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - static unsigned char rbac_page[12] = { - 0x1B, 0xA, 0, 0x81, 0, 0, 0, 0, 0, 0, 0, 0 - }; - static unsigned char timer_page[8] = { - 0x1C, 0x6, 0, 0, 0, 0 - }; - unsigned char pc, page_code; - unsigned int i = 0; - struct jumpshot_info *info = (struct jumpshot_info *) (us->extra); - unsigned char *ptr = us->iobuf; - - pc = srb->cmnd[2] >> 6; - page_code = srb->cmnd[2] & 0x3F; - - switch (pc) { - case 0x0: - US_DEBUGP("jumpshot_handle_mode_sense: Current values\n"); - break; - case 0x1: - US_DEBUGP("jumpshot_handle_mode_sense: Changeable values\n"); - break; - case 0x2: - US_DEBUGP("jumpshot_handle_mode_sense: Default values\n"); - break; - case 0x3: - US_DEBUGP("jumpshot_handle_mode_sense: Saves values\n"); - break; - } - - memset(ptr, 0, 8); - if (sense_6) { - ptr[2] = 0x00; // WP enable: 0x80 - i = 4; - } else { - ptr[3] = 0x00; // WP enable: 0x80 - i = 8; - } - - switch (page_code) { - case 0x0: - // vendor-specific mode - info->sense_key = 0x05; - info->sense_asc = 0x24; - info->sense_ascq = 0x00; - return USB_STOR_TRANSPORT_FAILED; - - case 0x1: - memcpy(ptr + i, rw_err_page, sizeof(rw_err_page)); - i += sizeof(rw_err_page); - break; - - case 0x8: - memcpy(ptr + i, cache_page, sizeof(cache_page)); - i += sizeof(cache_page); - break; - - case 0x1B: - memcpy(ptr + i, rbac_page, sizeof(rbac_page)); - i += sizeof(rbac_page); - break; - - case 0x1C: - memcpy(ptr + i, timer_page, sizeof(timer_page)); - i += sizeof(timer_page); - break; - - case 0x3F: - memcpy(ptr + i, timer_page, sizeof(timer_page)); - i += sizeof(timer_page); - memcpy(ptr + i, rbac_page, sizeof(rbac_page)); - i += sizeof(rbac_page); - memcpy(ptr + i, cache_page, sizeof(cache_page)); - i += sizeof(cache_page); - memcpy(ptr + i, rw_err_page, sizeof(rw_err_page)); - i += sizeof(rw_err_page); - break; - } - - if (sense_6) - ptr[0] = i - 1; - else - ((__be16 *) ptr)[0] = cpu_to_be16(i - 2); - usb_stor_set_xfer_buf(ptr, i, srb); - - return USB_STOR_TRANSPORT_GOOD; -} - - -static void jumpshot_info_destructor(void *extra) -{ - // this routine is a placeholder... - // currently, we don't allocate any extra blocks so we're okay -} - - - -// Transport for the Lexar 'Jumpshot' -// -static int jumpshot_transport(struct scsi_cmnd *srb, struct us_data *us) -{ - struct jumpshot_info *info; - int rc; - unsigned long block, blocks; - unsigned char *ptr = us->iobuf; - static unsigned char inquiry_response[8] = { - 0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00 - }; - - if (!us->extra) { - us->extra = kzalloc(sizeof(struct jumpshot_info), GFP_NOIO); - if (!us->extra) { - US_DEBUGP("jumpshot_transport: Gah! Can't allocate storage for jumpshot info struct!\n"); - return USB_STOR_TRANSPORT_ERROR; - } - us->extra_destructor = jumpshot_info_destructor; - } - - info = (struct jumpshot_info *) (us->extra); - - if (srb->cmnd[0] == INQUIRY) { - US_DEBUGP("jumpshot_transport: INQUIRY. Returning bogus response.\n"); - memcpy(ptr, inquiry_response, sizeof(inquiry_response)); - fill_inquiry_response(us, ptr, 36); - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == READ_CAPACITY) { - info->ssize = 0x200; // hard coded 512 byte sectors as per ATA spec - - rc = jumpshot_get_status(us); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - - rc = jumpshot_id_device(us, info); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - - US_DEBUGP("jumpshot_transport: READ_CAPACITY: %ld sectors, %ld bytes per sector\n", - info->sectors, info->ssize); - - // build the reply - // - ((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1); - ((__be32 *) ptr)[1] = cpu_to_be32(info->ssize); - usb_stor_set_xfer_buf(ptr, 8, srb); - - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == MODE_SELECT_10) { - US_DEBUGP("jumpshot_transport: Gah! MODE_SELECT_10.\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - if (srb->cmnd[0] == READ_10) { - block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | - ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); - - blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); - - US_DEBUGP("jumpshot_transport: READ_10: read block 0x%04lx count %ld\n", block, blocks); - return jumpshot_read_data(us, info, block, blocks); - } - - if (srb->cmnd[0] == READ_12) { - // I don't think we'll ever see a READ_12 but support it anyway... - // - block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | - ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); - - blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | - ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9])); - - US_DEBUGP("jumpshot_transport: READ_12: read block 0x%04lx count %ld\n", block, blocks); - return jumpshot_read_data(us, info, block, blocks); - } - - if (srb->cmnd[0] == WRITE_10) { - block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | - ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); - - blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); - - US_DEBUGP("jumpshot_transport: WRITE_10: write block 0x%04lx count %ld\n", block, blocks); - return jumpshot_write_data(us, info, block, blocks); - } - - if (srb->cmnd[0] == WRITE_12) { - // I don't think we'll ever see a WRITE_12 but support it anyway... - // - block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | - ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); - - blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | - ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9])); - - US_DEBUGP("jumpshot_transport: WRITE_12: write block 0x%04lx count %ld\n", block, blocks); - return jumpshot_write_data(us, info, block, blocks); - } - - - if (srb->cmnd[0] == TEST_UNIT_READY) { - US_DEBUGP("jumpshot_transport: TEST_UNIT_READY.\n"); - return jumpshot_get_status(us); - } - - if (srb->cmnd[0] == REQUEST_SENSE) { - US_DEBUGP("jumpshot_transport: REQUEST_SENSE.\n"); - - memset(ptr, 0, 18); - ptr[0] = 0xF0; - ptr[2] = info->sense_key; - ptr[7] = 11; - ptr[12] = info->sense_asc; - ptr[13] = info->sense_ascq; - usb_stor_set_xfer_buf(ptr, 18, srb); - - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == MODE_SENSE) { - US_DEBUGP("jumpshot_transport: MODE_SENSE_6 detected\n"); - return jumpshot_handle_mode_sense(us, srb, 1); - } - - if (srb->cmnd[0] == MODE_SENSE_10) { - US_DEBUGP("jumpshot_transport: MODE_SENSE_10 detected\n"); - return jumpshot_handle_mode_sense(us, srb, 0); - } - - if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { - // sure. whatever. not like we can stop the user from popping - // the media out of the device (no locking doors, etc) - // - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == START_STOP) { - /* this is used by sd.c'check_scsidisk_media_change to detect - media change */ - US_DEBUGP("jumpshot_transport: START_STOP.\n"); - /* the first jumpshot_id_device after a media change returns - an error (determined experimentally) */ - rc = jumpshot_id_device(us, info); - if (rc == USB_STOR_TRANSPORT_GOOD) { - info->sense_key = NO_SENSE; - srb->result = SUCCESS; - } else { - info->sense_key = UNIT_ATTENTION; - srb->result = SAM_STAT_CHECK_CONDITION; - } - return rc; - } - - US_DEBUGP("jumpshot_transport: Gah! Unknown command: %d (0x%x)\n", - srb->cmnd[0], srb->cmnd[0]); - info->sense_key = 0x05; - info->sense_asc = 0x20; - info->sense_ascq = 0x00; - return USB_STOR_TRANSPORT_FAILED; -} - -static int jumpshot_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct us_data *us; - int result; - - result = usb_stor_probe1(&us, intf, id, - (id - jumpshot_usb_ids) + jumpshot_unusual_dev_list); - if (result) - return result; - - us->transport_name = "Lexar Jumpshot Control/Bulk"; - us->transport = jumpshot_transport; - us->transport_reset = usb_stor_Bulk_reset; - us->max_lun = 1; - - result = usb_stor_probe2(us); - return result; -} - -static struct usb_driver jumpshot_driver = { - .name = "ums-jumpshot", - .probe = jumpshot_probe, - .disconnect = usb_stor_disconnect, - .suspend = usb_stor_suspend, - .resume = usb_stor_resume, - .reset_resume = usb_stor_reset_resume, - .pre_reset = usb_stor_pre_reset, - .post_reset = usb_stor_post_reset, - .id_table = jumpshot_usb_ids, - .soft_unbind = 1, - .no_dynamic_id = 1, -}; - -module_usb_driver(jumpshot_driver); diff --git a/ANDROID_3.4.5/drivers/usb/storage/karma.c b/ANDROID_3.4.5/drivers/usb/storage/karma.c deleted file mode 100644 index a8708eae..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/karma.c +++ /dev/null @@ -1,236 +0,0 @@ -/* Driver for Rio Karma - * - * (c) 2006 Bob Copeland - * (c) 2006 Keith Bennett - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include - -#include -#include -#include - -#include "usb.h" -#include "transport.h" -#include "debug.h" - -MODULE_DESCRIPTION("Driver for Rio Karma"); -MODULE_AUTHOR("Bob Copeland , Keith Bennett "); -MODULE_LICENSE("GPL"); - -#define RIO_PREFIX "RIOP\x00" -#define RIO_PREFIX_LEN 5 -#define RIO_SEND_LEN 40 -#define RIO_RECV_LEN 0x200 - -#define RIO_ENTER_STORAGE 0x1 -#define RIO_LEAVE_STORAGE 0x2 -#define RIO_RESET 0xC - -struct karma_data { - int in_storage; - char *recv; -}; - -static int rio_karma_init(struct us_data *us); - - -/* - * The table of devices - */ -#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ - vendorName, productName, useProtocol, useTransport, \ - initFunction, flags) \ -{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } - -static struct usb_device_id karma_usb_ids[] = { -# include "unusual_karma.h" - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, karma_usb_ids); - -#undef UNUSUAL_DEV - -/* - * The flags table - */ -#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ - vendor_name, product_name, use_protocol, use_transport, \ - init_function, Flags) \ -{ \ - .vendorName = vendor_name, \ - .productName = product_name, \ - .useProtocol = use_protocol, \ - .useTransport = use_transport, \ - .initFunction = init_function, \ -} - -static struct us_unusual_dev karma_unusual_dev_list[] = { -# include "unusual_karma.h" - { } /* Terminating entry */ -}; - -#undef UNUSUAL_DEV - - -/* - * Send commands to Rio Karma. - * - * For each command we send 40 bytes starting 'RIOP\0' followed by - * the command number and a sequence number, which the device will ack - * with a 512-byte packet with the high four bits set and everything - * else null. Then we send 'RIOP\x80' followed by a zero and the - * sequence number, until byte 5 in the response repeats the sequence - * number. - */ -static int rio_karma_send_command(char cmd, struct us_data *us) -{ - int result, partial; - unsigned long timeout; - static unsigned char seq = 1; - struct karma_data *data = (struct karma_data *) us->extra; - - US_DEBUGP("karma: sending command %04x\n", cmd); - memset(us->iobuf, 0, RIO_SEND_LEN); - memcpy(us->iobuf, RIO_PREFIX, RIO_PREFIX_LEN); - us->iobuf[5] = cmd; - us->iobuf[6] = seq; - - timeout = jiffies + msecs_to_jiffies(6000); - for (;;) { - result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, - us->iobuf, RIO_SEND_LEN, &partial); - if (result != USB_STOR_XFER_GOOD) - goto err; - - result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, - data->recv, RIO_RECV_LEN, &partial); - if (result != USB_STOR_XFER_GOOD) - goto err; - - if (data->recv[5] == seq) - break; - - if (time_after(jiffies, timeout)) - goto err; - - us->iobuf[4] = 0x80; - us->iobuf[5] = 0; - msleep(50); - } - - seq++; - if (seq == 0) - seq = 1; - - US_DEBUGP("karma: sent command %04x\n", cmd); - return 0; -err: - US_DEBUGP("karma: command %04x failed\n", cmd); - return USB_STOR_TRANSPORT_FAILED; -} - -/* - * Trap START_STOP and READ_10 to leave/re-enter storage mode. - * Everything else is propagated to the normal bulk layer. - */ -static int rio_karma_transport(struct scsi_cmnd *srb, struct us_data *us) -{ - int ret; - struct karma_data *data = (struct karma_data *) us->extra; - - if (srb->cmnd[0] == READ_10 && !data->in_storage) { - ret = rio_karma_send_command(RIO_ENTER_STORAGE, us); - if (ret) - return ret; - - data->in_storage = 1; - return usb_stor_Bulk_transport(srb, us); - } else if (srb->cmnd[0] == START_STOP) { - ret = rio_karma_send_command(RIO_LEAVE_STORAGE, us); - if (ret) - return ret; - - data->in_storage = 0; - return rio_karma_send_command(RIO_RESET, us); - } - return usb_stor_Bulk_transport(srb, us); -} - -static void rio_karma_destructor(void *extra) -{ - struct karma_data *data = (struct karma_data *) extra; - kfree(data->recv); -} - -static int rio_karma_init(struct us_data *us) -{ - int ret = 0; - struct karma_data *data = kzalloc(sizeof(struct karma_data), GFP_NOIO); - if (!data) - goto out; - - data->recv = kmalloc(RIO_RECV_LEN, GFP_NOIO); - if (!data->recv) { - kfree(data); - goto out; - } - - us->extra = data; - us->extra_destructor = rio_karma_destructor; - ret = rio_karma_send_command(RIO_ENTER_STORAGE, us); - data->in_storage = (ret == 0); -out: - return ret; -} - -static int karma_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct us_data *us; - int result; - - result = usb_stor_probe1(&us, intf, id, - (id - karma_usb_ids) + karma_unusual_dev_list); - if (result) - return result; - - us->transport_name = "Rio Karma/Bulk"; - us->transport = rio_karma_transport; - us->transport_reset = usb_stor_Bulk_reset; - - result = usb_stor_probe2(us); - return result; -} - -static struct usb_driver karma_driver = { - .name = "ums-karma", - .probe = karma_probe, - .disconnect = usb_stor_disconnect, - .suspend = usb_stor_suspend, - .resume = usb_stor_resume, - .reset_resume = usb_stor_reset_resume, - .pre_reset = usb_stor_pre_reset, - .post_reset = usb_stor_post_reset, - .id_table = karma_usb_ids, - .soft_unbind = 1, - .no_dynamic_id = 1, -}; - -module_usb_driver(karma_driver); diff --git a/ANDROID_3.4.5/drivers/usb/storage/libusual.c b/ANDROID_3.4.5/drivers/usb/storage/libusual.c deleted file mode 100644 index fe3ffe14..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/libusual.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * libusual - * - * The libusual contains the table of devices common for ub and usb-storage. - */ -#include -#include -#include -#include -#include -#include -#include - -/* - */ -#define USU_MOD_FL_THREAD 1 /* Thread is running */ -#define USU_MOD_FL_PRESENT 2 /* The module is loaded */ - -struct mod_status { - unsigned long fls; -}; - -static struct mod_status stat[3]; -static DEFINE_SPINLOCK(usu_lock); - -/* - */ -#define USB_US_DEFAULT_BIAS USB_US_TYPE_STOR -static atomic_t usu_bias = ATOMIC_INIT(USB_US_DEFAULT_BIAS); - -#define BIAS_NAME_SIZE (sizeof("usb-storage")) -static const char *bias_names[3] = { "none", "usb-storage", "ub" }; - -static DEFINE_MUTEX(usu_probe_mutex); -static DECLARE_COMPLETION(usu_end_notify); -static atomic_t total_threads = ATOMIC_INIT(0); - -static int usu_probe_thread(void *arg); - -/* - * @type: the module type as an integer - */ -void usb_usual_set_present(int type) -{ - struct mod_status *st; - unsigned long flags; - - if (type <= 0 || type >= 3) - return; - st = &stat[type]; - spin_lock_irqsave(&usu_lock, flags); - st->fls |= USU_MOD_FL_PRESENT; - spin_unlock_irqrestore(&usu_lock, flags); -} -EXPORT_SYMBOL_GPL(usb_usual_set_present); - -void usb_usual_clear_present(int type) -{ - struct mod_status *st; - unsigned long flags; - - if (type <= 0 || type >= 3) - return; - st = &stat[type]; - spin_lock_irqsave(&usu_lock, flags); - st->fls &= ~USU_MOD_FL_PRESENT; - spin_unlock_irqrestore(&usu_lock, flags); -} -EXPORT_SYMBOL_GPL(usb_usual_clear_present); - -/* - * Match the calling driver type against the table. - * Returns: 0 if the device matches. - */ -int usb_usual_check_type(const struct usb_device_id *id, int caller_type) -{ - int id_type = USB_US_TYPE(id->driver_info); - - if (caller_type <= 0 || caller_type >= 3) - return -EINVAL; - - /* Drivers grab fixed assignment devices */ - if (id_type == caller_type) - return 0; - /* Drivers grab devices biased to them */ - if (id_type == USB_US_TYPE_NONE && caller_type == atomic_read(&usu_bias)) - return 0; - return -ENODEV; -} -EXPORT_SYMBOL_GPL(usb_usual_check_type); - -/* - */ -static int usu_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - int rc; - unsigned long type; - struct task_struct* task; - unsigned long flags; - - type = USB_US_TYPE(id->driver_info); - if (type == 0) - type = atomic_read(&usu_bias); - - spin_lock_irqsave(&usu_lock, flags); - if ((stat[type].fls & (USU_MOD_FL_THREAD|USU_MOD_FL_PRESENT)) != 0) { - spin_unlock_irqrestore(&usu_lock, flags); - return -ENXIO; - } - stat[type].fls |= USU_MOD_FL_THREAD; - spin_unlock_irqrestore(&usu_lock, flags); - - task = kthread_run(usu_probe_thread, (void*)type, "libusual_%ld", type); - if (IS_ERR(task)) { - rc = PTR_ERR(task); - printk(KERN_WARNING "libusual: " - "Unable to start the thread for %s: %d\n", - bias_names[type], rc); - spin_lock_irqsave(&usu_lock, flags); - stat[type].fls &= ~USU_MOD_FL_THREAD; - spin_unlock_irqrestore(&usu_lock, flags); - return rc; /* Not being -ENXIO causes a message printed */ - } - atomic_inc(&total_threads); - - return -ENXIO; -} - -static void usu_disconnect(struct usb_interface *intf) -{ - ; /* We should not be here. */ -} - -static struct usb_driver usu_driver = { - .name = "libusual", - .probe = usu_probe, - .disconnect = usu_disconnect, - .id_table = usb_storage_usb_ids, -}; - -/* - * A whole new thread for a purpose of request_module seems quite stupid. - * The request_module forks once inside again. However, if we attempt - * to load a storage module from our own modprobe thread, that module - * references our symbols, which cannot be resolved until our module is - * initialized. I wish there was a way to wait for the end of initialization. - * The module notifier reports MODULE_STATE_COMING only. - * So, we wait until module->init ends as the next best thing. - */ -static int usu_probe_thread(void *arg) -{ - int type = (unsigned long) arg; - struct mod_status *st = &stat[type]; - int rc; - unsigned long flags; - - mutex_lock(&usu_probe_mutex); - rc = request_module(bias_names[type]); - spin_lock_irqsave(&usu_lock, flags); - if (rc == 0 && (st->fls & USU_MOD_FL_PRESENT) == 0) { - /* - * This should not happen, but let us keep tabs on it. - */ - printk(KERN_NOTICE "libusual: " - "modprobe for %s succeeded, but module is not present\n", - bias_names[type]); - } - st->fls &= ~USU_MOD_FL_THREAD; - spin_unlock_irqrestore(&usu_lock, flags); - mutex_unlock(&usu_probe_mutex); - - complete_and_exit(&usu_end_notify, 0); -} - -/* - */ -static int __init usb_usual_init(void) -{ - int rc; - - mutex_lock(&usu_probe_mutex); - rc = usb_register(&usu_driver); - mutex_unlock(&usu_probe_mutex); - return rc; -} - -static void __exit usb_usual_exit(void) -{ - /* - * We do not check for any drivers present, because - * they keep us pinned with symbol references. - */ - - usb_deregister(&usu_driver); - - while (atomic_read(&total_threads) > 0) { - wait_for_completion(&usu_end_notify); - atomic_dec(&total_threads); - } -} - -/* - * Validate and accept the bias parameter. - */ -static int usu_set_bias(const char *bias_s, struct kernel_param *kp) -{ - int i; - int len; - int bias_n = 0; - - len = strlen(bias_s); - if (len == 0) - return -EDOM; - if (bias_s[len-1] == '\n') - --len; - - for (i = 1; i < 3; i++) { - if (strncmp(bias_s, bias_names[i], len) == 0) { - bias_n = i; - break; - } - } - if (bias_n == 0) - return -EINVAL; - - atomic_set(&usu_bias, bias_n); - return 0; -} - -static int usu_get_bias(char *buffer, struct kernel_param *kp) -{ - return strlen(strcpy(buffer, bias_names[atomic_read(&usu_bias)])); -} - -module_init(usb_usual_init); -module_exit(usb_usual_exit); - -module_param_call(bias, usu_set_bias, usu_get_bias, NULL, S_IRUGO|S_IWUSR); -__MODULE_PARM_TYPE(bias, "string"); -MODULE_PARM_DESC(bias, "Bias to usb-storage or ub"); - -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/storage/onetouch.c b/ANDROID_3.4.5/drivers/usb/storage/onetouch.c deleted file mode 100644 index 886567a3..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/onetouch.c +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Support for the Maxtor OneTouch USB hard drive's button - * - * Current development and maintenance by: - * Copyright (c) 2005 Nick Sillik - * - * Initial work by: - * Copyright (c) 2003 Erik Thyren - * - * Based on usbmouse.c (Vojtech Pavlik) and xpad.c (Marko Friedemann) - * - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include "usb.h" -#include "debug.h" - -MODULE_DESCRIPTION("Maxtor USB OneTouch hard drive button driver"); -MODULE_AUTHOR("Nick Sillik "); -MODULE_LICENSE("GPL"); - -#define ONETOUCH_PKT_LEN 0x02 -#define ONETOUCH_BUTTON KEY_PROG1 - -static int onetouch_connect_input(struct us_data *ss); -static void onetouch_release_input(void *onetouch_); - -struct usb_onetouch { - char name[128]; - char phys[64]; - struct input_dev *dev; /* input device interface */ - struct usb_device *udev; /* usb device */ - - struct urb *irq; /* urb for interrupt in report */ - unsigned char *data; /* input data */ - dma_addr_t data_dma; - unsigned int is_open:1; -}; - - -/* - * The table of devices - */ -#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ - vendorName, productName, useProtocol, useTransport, \ - initFunction, flags) \ -{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } - -static struct usb_device_id onetouch_usb_ids[] = { -# include "unusual_onetouch.h" - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, onetouch_usb_ids); - -#undef UNUSUAL_DEV - -/* - * The flags table - */ -#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ - vendor_name, product_name, use_protocol, use_transport, \ - init_function, Flags) \ -{ \ - .vendorName = vendor_name, \ - .productName = product_name, \ - .useProtocol = use_protocol, \ - .useTransport = use_transport, \ - .initFunction = init_function, \ -} - -static struct us_unusual_dev onetouch_unusual_dev_list[] = { -# include "unusual_onetouch.h" - { } /* Terminating entry */ -}; - -#undef UNUSUAL_DEV - - -static void usb_onetouch_irq(struct urb *urb) -{ - struct usb_onetouch *onetouch = urb->context; - signed char *data = onetouch->data; - struct input_dev *dev = onetouch->dev; - int status = urb->status; - int retval; - - switch (status) { - case 0: /* success */ - break; - case -ECONNRESET: /* unlink */ - case -ENOENT: - case -ESHUTDOWN: - return; - /* -EPIPE: should clear the halt */ - default: /* error */ - goto resubmit; - } - - input_report_key(dev, ONETOUCH_BUTTON, data[0] & 0x02); - input_sync(dev); - -resubmit: - retval = usb_submit_urb (urb, GFP_ATOMIC); - if (retval) - dev_err(&dev->dev, "can't resubmit intr, %s-%s/input0, " - "retval %d\n", onetouch->udev->bus->bus_name, - onetouch->udev->devpath, retval); -} - -static int usb_onetouch_open(struct input_dev *dev) -{ - struct usb_onetouch *onetouch = input_get_drvdata(dev); - - onetouch->is_open = 1; - onetouch->irq->dev = onetouch->udev; - if (usb_submit_urb(onetouch->irq, GFP_KERNEL)) { - dev_err(&dev->dev, "usb_submit_urb failed\n"); - return -EIO; - } - - return 0; -} - -static void usb_onetouch_close(struct input_dev *dev) -{ - struct usb_onetouch *onetouch = input_get_drvdata(dev); - - usb_kill_urb(onetouch->irq); - onetouch->is_open = 0; -} - -#ifdef CONFIG_PM -static void usb_onetouch_pm_hook(struct us_data *us, int action) -{ - struct usb_onetouch *onetouch = (struct usb_onetouch *) us->extra; - - if (onetouch->is_open) { - switch (action) { - case US_SUSPEND: - usb_kill_urb(onetouch->irq); - break; - case US_RESUME: - if (usb_submit_urb(onetouch->irq, GFP_NOIO) != 0) - dev_err(&onetouch->irq->dev->dev, - "usb_submit_urb failed\n"); - break; - default: - break; - } - } -} -#endif /* CONFIG_PM */ - -static int onetouch_connect_input(struct us_data *ss) -{ - struct usb_device *udev = ss->pusb_dev; - struct usb_host_interface *interface; - struct usb_endpoint_descriptor *endpoint; - struct usb_onetouch *onetouch; - struct input_dev *input_dev; - int pipe, maxp; - int error = -ENOMEM; - - interface = ss->pusb_intf->cur_altsetting; - - if (interface->desc.bNumEndpoints != 3) - return -ENODEV; - - endpoint = &interface->endpoint[2].desc; - if (!usb_endpoint_is_int_in(endpoint)) - return -ENODEV; - - pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress); - maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); - - onetouch = kzalloc(sizeof(struct usb_onetouch), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!onetouch || !input_dev) - goto fail1; - - onetouch->data = usb_alloc_coherent(udev, ONETOUCH_PKT_LEN, - GFP_KERNEL, &onetouch->data_dma); - if (!onetouch->data) - goto fail1; - - onetouch->irq = usb_alloc_urb(0, GFP_KERNEL); - if (!onetouch->irq) - goto fail2; - - onetouch->udev = udev; - onetouch->dev = input_dev; - - if (udev->manufacturer) - strlcpy(onetouch->name, udev->manufacturer, - sizeof(onetouch->name)); - if (udev->product) { - if (udev->manufacturer) - strlcat(onetouch->name, " ", sizeof(onetouch->name)); - strlcat(onetouch->name, udev->product, sizeof(onetouch->name)); - } - - if (!strlen(onetouch->name)) - snprintf(onetouch->name, sizeof(onetouch->name), - "Maxtor Onetouch %04x:%04x", - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct)); - - usb_make_path(udev, onetouch->phys, sizeof(onetouch->phys)); - strlcat(onetouch->phys, "/input0", sizeof(onetouch->phys)); - - input_dev->name = onetouch->name; - input_dev->phys = onetouch->phys; - usb_to_input_id(udev, &input_dev->id); - input_dev->dev.parent = &udev->dev; - - set_bit(EV_KEY, input_dev->evbit); - set_bit(ONETOUCH_BUTTON, input_dev->keybit); - clear_bit(0, input_dev->keybit); - - input_set_drvdata(input_dev, onetouch); - - input_dev->open = usb_onetouch_open; - input_dev->close = usb_onetouch_close; - - usb_fill_int_urb(onetouch->irq, udev, pipe, onetouch->data, - (maxp > 8 ? 8 : maxp), - usb_onetouch_irq, onetouch, endpoint->bInterval); - onetouch->irq->transfer_dma = onetouch->data_dma; - onetouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - - ss->extra_destructor = onetouch_release_input; - ss->extra = onetouch; -#ifdef CONFIG_PM - ss->suspend_resume_hook = usb_onetouch_pm_hook; -#endif - - error = input_register_device(onetouch->dev); - if (error) - goto fail3; - - return 0; - - fail3: usb_free_urb(onetouch->irq); - fail2: usb_free_coherent(udev, ONETOUCH_PKT_LEN, - onetouch->data, onetouch->data_dma); - fail1: kfree(onetouch); - input_free_device(input_dev); - return error; -} - -static void onetouch_release_input(void *onetouch_) -{ - struct usb_onetouch *onetouch = (struct usb_onetouch *) onetouch_; - - if (onetouch) { - usb_kill_urb(onetouch->irq); - input_unregister_device(onetouch->dev); - usb_free_urb(onetouch->irq); - usb_free_coherent(onetouch->udev, ONETOUCH_PKT_LEN, - onetouch->data, onetouch->data_dma); - } -} - -static int onetouch_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct us_data *us; - int result; - - result = usb_stor_probe1(&us, intf, id, - (id - onetouch_usb_ids) + onetouch_unusual_dev_list); - if (result) - return result; - - /* Use default transport and protocol */ - - result = usb_stor_probe2(us); - return result; -} - -static struct usb_driver onetouch_driver = { - .name = "ums-onetouch", - .probe = onetouch_probe, - .disconnect = usb_stor_disconnect, - .suspend = usb_stor_suspend, - .resume = usb_stor_resume, - .reset_resume = usb_stor_reset_resume, - .pre_reset = usb_stor_pre_reset, - .post_reset = usb_stor_post_reset, - .id_table = onetouch_usb_ids, - .soft_unbind = 1, - .no_dynamic_id = 1, -}; - -module_usb_driver(onetouch_driver); diff --git a/ANDROID_3.4.5/drivers/usb/storage/option_ms.c b/ANDROID_3.4.5/drivers/usb/storage/option_ms.c deleted file mode 100644 index e0f76bb0..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/option_ms.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Driver for Option High Speed Mobile Devices. - * - * (c) 2008 Dan Williams - * - * Inspiration taken from sierra_ms.c by Kevin Lloyd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include - -#include "usb.h" -#include "transport.h" -#include "option_ms.h" -#include "debug.h" - -#define ZCD_FORCE_MODEM 0x01 -#define ZCD_ALLOW_MS 0x02 - -static unsigned int option_zero_cd = ZCD_FORCE_MODEM; -module_param(option_zero_cd, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(option_zero_cd, "ZeroCD mode (1=Force Modem (default)," - " 2=Allow CD-Rom"); - -#define RESPONSE_LEN 1024 - -static int option_rezero(struct us_data *us) -{ - const unsigned char rezero_msg[] = { - 0x55, 0x53, 0x42, 0x43, 0x78, 0x56, 0x34, 0x12, - 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - char *buffer; - int result; - - US_DEBUGP("Option MS: %s", "DEVICE MODE SWITCH\n"); - - buffer = kzalloc(RESPONSE_LEN, GFP_KERNEL); - if (buffer == NULL) - return USB_STOR_TRANSPORT_ERROR; - - memcpy(buffer, rezero_msg, sizeof(rezero_msg)); - result = usb_stor_bulk_transfer_buf(us, - us->send_bulk_pipe, - buffer, sizeof(rezero_msg), NULL); - if (result != USB_STOR_XFER_GOOD) { - result = USB_STOR_XFER_ERROR; - goto out; - } - - /* Some of the devices need to be asked for a response, but we don't - * care what that response is. - */ - usb_stor_bulk_transfer_buf(us, - us->recv_bulk_pipe, - buffer, RESPONSE_LEN, NULL); - - /* Read the CSW */ - usb_stor_bulk_transfer_buf(us, - us->recv_bulk_pipe, - buffer, 13, NULL); - - result = USB_STOR_XFER_GOOD; - -out: - kfree(buffer); - return result; -} - -static int option_inquiry(struct us_data *us) -{ - const unsigned char inquiry_msg[] = { - 0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78, - 0x24, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x12, - 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - char *buffer; - int result; - - US_DEBUGP("Option MS: %s", "device inquiry for vendor name\n"); - - buffer = kzalloc(0x24, GFP_KERNEL); - if (buffer == NULL) - return USB_STOR_TRANSPORT_ERROR; - - memcpy(buffer, inquiry_msg, sizeof(inquiry_msg)); - result = usb_stor_bulk_transfer_buf(us, - us->send_bulk_pipe, - buffer, sizeof(inquiry_msg), NULL); - if (result != USB_STOR_XFER_GOOD) { - result = USB_STOR_XFER_ERROR; - goto out; - } - - result = usb_stor_bulk_transfer_buf(us, - us->recv_bulk_pipe, - buffer, 0x24, NULL); - if (result != USB_STOR_XFER_GOOD) { - result = USB_STOR_XFER_ERROR; - goto out; - } - - result = memcmp(buffer+8, "Option", 6); - - if (result != 0) - result = memcmp(buffer+8, "ZCOPTION", 8); - - /* Read the CSW */ - usb_stor_bulk_transfer_buf(us, - us->recv_bulk_pipe, - buffer, 13, NULL); - -out: - kfree(buffer); - return result; -} - - -int option_ms_init(struct us_data *us) -{ - int result; - - US_DEBUGP("Option MS: option_ms_init called\n"); - - /* Additional test for vendor information via INQUIRY, - * because some vendor/product IDs are ambiguous - */ - result = option_inquiry(us); - if (result != 0) { - US_DEBUGP("Option MS: vendor is not Option or not determinable," - " no action taken\n"); - return 0; - } else - US_DEBUGP("Option MS: this is a genuine Option device," - " proceeding\n"); - - /* Force Modem mode */ - if (option_zero_cd == ZCD_FORCE_MODEM) { - US_DEBUGP("Option MS: %s", "Forcing Modem Mode\n"); - result = option_rezero(us); - if (result != USB_STOR_XFER_GOOD) - US_DEBUGP("Option MS: Failed to switch to modem mode.\n"); - return -EIO; - } else if (option_zero_cd == ZCD_ALLOW_MS) { - /* Allow Mass Storage mode (keep CD-Rom) */ - US_DEBUGP("Option MS: %s", "Allowing Mass Storage Mode if device" - " requests it\n"); - } - - return 0; -} - diff --git a/ANDROID_3.4.5/drivers/usb/storage/option_ms.h b/ANDROID_3.4.5/drivers/usb/storage/option_ms.h deleted file mode 100644 index b6e448ca..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/option_ms.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef _OPTION_MS_H_ -#define _OPTION_MS_H_ -extern int option_ms_init(struct us_data *us); -#endif diff --git a/ANDROID_3.4.5/drivers/usb/storage/protocol.c b/ANDROID_3.4.5/drivers/usb/storage/protocol.c deleted file mode 100644 index 82dd8347..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/protocol.c +++ /dev/null @@ -1,220 +0,0 @@ -/* Driver for USB Mass Storage compliant devices - * - * Current development and maintenance by: - * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * Developed with the assistance of: - * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) - * (c) 2002 Alan Stern (stern@rowland.org) - * - * Initial work by: - * (c) 1999 Michael Gee (michael@linuxspecific.com) - * - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI and ATAPI commands in - * mind when they created this document. The commands are all very - * similar to commands in the SCSI-II and ATAPI specifications. - * - * It is important to note that in a number of cases this class - * exhibits class-specific exemptions from the USB specification. - * Notably the usage of NAK, STALL and ACK differs from the norm, in - * that they are used to communicate wait, failed and OK on commands. - * - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -#include "usb.h" -#include "protocol.h" -#include "debug.h" -#include "scsiglue.h" -#include "transport.h" - -/*********************************************************************** - * Protocol routines - ***********************************************************************/ - -void usb_stor_pad12_command(struct scsi_cmnd *srb, struct us_data *us) -{ - /* - * Pad the SCSI command with zeros out to 12 bytes. If the - * command already is 12 bytes or longer, leave it alone. - * - * NOTE: This only works because a scsi_cmnd struct field contains - * a unsigned char cmnd[16], so we know we have storage available - */ - for (; srb->cmd_len<12; srb->cmd_len++) - srb->cmnd[srb->cmd_len] = 0; - - /* send the command to the transport layer */ - usb_stor_invoke_transport(srb, us); -} - -void usb_stor_ufi_command(struct scsi_cmnd *srb, struct us_data *us) -{ - /* fix some commands -- this is a form of mode translation - * UFI devices only accept 12 byte long commands - * - * NOTE: This only works because a scsi_cmnd struct field contains - * a unsigned char cmnd[16], so we know we have storage available - */ - - /* Pad the ATAPI command with zeros */ - for (; srb->cmd_len<12; srb->cmd_len++) - srb->cmnd[srb->cmd_len] = 0; - - /* set command length to 12 bytes (this affects the transport layer) */ - srb->cmd_len = 12; - - /* XXX We should be constantly re-evaluating the need for these */ - - /* determine the correct data length for these commands */ - switch (srb->cmnd[0]) { - - /* for INQUIRY, UFI devices only ever return 36 bytes */ - case INQUIRY: - srb->cmnd[4] = 36; - break; - - /* again, for MODE_SENSE_10, we get the minimum (8) */ - case MODE_SENSE_10: - srb->cmnd[7] = 0; - srb->cmnd[8] = 8; - break; - - /* for REQUEST_SENSE, UFI devices only ever return 18 bytes */ - case REQUEST_SENSE: - srb->cmnd[4] = 18; - break; - } /* end switch on cmnd[0] */ - - /* send the command to the transport layer */ - usb_stor_invoke_transport(srb, us); -} - -void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb, - struct us_data *us) -{ - /* send the command to the transport layer */ - usb_stor_invoke_transport(srb, us); -} -EXPORT_SYMBOL_GPL(usb_stor_transparent_scsi_command); - -/*********************************************************************** - * Scatter-gather transfer buffer access routines - ***********************************************************************/ - -/* Copy a buffer of length buflen to/from the srb's transfer buffer. - * Update the **sgptr and *offset variables so that the next copy will - * pick up from where this one left off. - */ -unsigned int usb_stor_access_xfer_buf(unsigned char *buffer, - unsigned int buflen, struct scsi_cmnd *srb, struct scatterlist **sgptr, - unsigned int *offset, enum xfer_buf_dir dir) -{ - unsigned int cnt; - struct scatterlist *sg = *sgptr; - - /* We have to go through the list one entry - * at a time. Each s-g entry contains some number of pages, and - * each page has to be kmap()'ed separately. If the page is already - * in kernel-addressable memory then kmap() will return its address. - * If the page is not directly accessible -- such as a user buffer - * located in high memory -- then kmap() will map it to a temporary - * position in the kernel's virtual address space. - */ - - if (!sg) - sg = scsi_sglist(srb); - - /* This loop handles a single s-g list entry, which may - * include multiple pages. Find the initial page structure - * and the starting offset within the page, and update - * the *offset and **sgptr values for the next loop. - */ - cnt = 0; - while (cnt < buflen && sg) { - struct page *page = sg_page(sg) + - ((sg->offset + *offset) >> PAGE_SHIFT); - unsigned int poff = (sg->offset + *offset) & (PAGE_SIZE-1); - unsigned int sglen = sg->length - *offset; - - if (sglen > buflen - cnt) { - - /* Transfer ends within this s-g entry */ - sglen = buflen - cnt; - *offset += sglen; - } else { - - /* Transfer continues to next s-g entry */ - *offset = 0; - sg = sg_next(sg); - } - - /* Transfer the data for all the pages in this - * s-g entry. For each page: call kmap(), do the - * transfer, and call kunmap() immediately after. */ - while (sglen > 0) { - unsigned int plen = min(sglen, (unsigned int) - PAGE_SIZE - poff); - unsigned char *ptr = kmap(page); - - if (dir == TO_XFER_BUF) - memcpy(ptr + poff, buffer + cnt, plen); - else - memcpy(buffer + cnt, ptr + poff, plen); - kunmap(page); - - /* Start at the beginning of the next page */ - poff = 0; - ++page; - cnt += plen; - sglen -= plen; - } - } - *sgptr = sg; - - /* Return the amount actually transferred */ - return cnt; -} -EXPORT_SYMBOL_GPL(usb_stor_access_xfer_buf); - -/* Store the contents of buffer into srb's transfer buffer and set the - * SCSI residue. - */ -void usb_stor_set_xfer_buf(unsigned char *buffer, - unsigned int buflen, struct scsi_cmnd *srb) -{ - unsigned int offset = 0; - struct scatterlist *sg = NULL; - - buflen = min(buflen, scsi_bufflen(srb)); - buflen = usb_stor_access_xfer_buf(buffer, buflen, srb, &sg, &offset, - TO_XFER_BUF); - if (buflen < scsi_bufflen(srb)) - scsi_set_resid(srb, scsi_bufflen(srb) - buflen); -} -EXPORT_SYMBOL_GPL(usb_stor_set_xfer_buf); diff --git a/ANDROID_3.4.5/drivers/usb/storage/protocol.h b/ANDROID_3.4.5/drivers/usb/storage/protocol.h deleted file mode 100644 index ffc3e2af..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/protocol.h +++ /dev/null @@ -1,57 +0,0 @@ -/* Driver for USB Mass Storage compliant devices - * Protocol Functions Header File - * - * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI and ATAPI commands in - * mind when they created this document. The commands are all very - * similar to commands in the SCSI-II and ATAPI specifications. - * - * It is important to note that in a number of cases this class - * exhibits class-specific exemptions from the USB specification. - * Notably the usage of NAK, STALL and ACK differs from the norm, in - * that they are used to communicate wait, failed and OK on commands. - * - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _PROTOCOL_H_ -#define _PROTOCOL_H_ - -/* Protocol handling routines */ -extern void usb_stor_pad12_command(struct scsi_cmnd*, struct us_data*); -extern void usb_stor_ufi_command(struct scsi_cmnd*, struct us_data*); -extern void usb_stor_transparent_scsi_command(struct scsi_cmnd*, - struct us_data*); - -/* struct scsi_cmnd transfer buffer access utilities */ -enum xfer_buf_dir {TO_XFER_BUF, FROM_XFER_BUF}; - -extern unsigned int usb_stor_access_xfer_buf(unsigned char *buffer, - unsigned int buflen, struct scsi_cmnd *srb, struct scatterlist **, - unsigned int *offset, enum xfer_buf_dir dir); - -extern void usb_stor_set_xfer_buf(unsigned char *buffer, - unsigned int buflen, struct scsi_cmnd *srb); -#endif diff --git a/ANDROID_3.4.5/drivers/usb/storage/realtek_cr.c b/ANDROID_3.4.5/drivers/usb/storage/realtek_cr.c deleted file mode 100644 index 63cf2822..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/realtek_cr.c +++ /dev/null @@ -1,1112 +0,0 @@ -/* Driver for Realtek RTS51xx USB card reader - * - * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - * - * Author: - * wwang (wei_wang@realsil.com.cn) - * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include "usb.h" -#include "transport.h" -#include "protocol.h" -#include "debug.h" - -MODULE_DESCRIPTION("Driver for Realtek USB Card Reader"); -MODULE_AUTHOR("wwang "); -MODULE_LICENSE("GPL"); -MODULE_VERSION("1.03"); - -static int auto_delink_en = 1; -module_param(auto_delink_en, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(auto_delink_en, "enable auto delink"); - -#ifdef CONFIG_REALTEK_AUTOPM -static int ss_en = 1; -module_param(ss_en, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(ss_en, "enable selective suspend"); - -static int ss_delay = 50; -module_param(ss_delay, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(ss_delay, - "seconds to delay before entering selective suspend"); - -enum RTS51X_STAT { - RTS51X_STAT_INIT, - RTS51X_STAT_IDLE, - RTS51X_STAT_RUN, - RTS51X_STAT_SS -}; - -#define POLLING_INTERVAL 50 - -#define rts51x_set_stat(chip, stat) \ - ((chip)->state = (enum RTS51X_STAT)(stat)) -#define rts51x_get_stat(chip) ((chip)->state) - -#define SET_LUN_READY(chip, lun) ((chip)->lun_ready |= ((u8)1 << (lun))) -#define CLR_LUN_READY(chip, lun) ((chip)->lun_ready &= ~((u8)1 << (lun))) -#define TST_LUN_READY(chip, lun) ((chip)->lun_ready & ((u8)1 << (lun))) - -#endif - -struct rts51x_status { - u16 vid; - u16 pid; - u8 cur_lun; - u8 card_type; - u8 total_lun; - u16 fw_ver; - u8 phy_exist; - u8 multi_flag; - u8 multi_card; - u8 log_exist; - union { - u8 detailed_type1; - u8 detailed_type2; - } detailed_type; - u8 function[2]; -}; - -struct rts51x_chip { - u16 vendor_id; - u16 product_id; - char max_lun; - - struct rts51x_status *status; - int status_len; - - u32 flag; -#ifdef CONFIG_REALTEK_AUTOPM - struct us_data *us; - struct timer_list rts51x_suspend_timer; - unsigned long timer_expires; - int pwr_state; - u8 lun_ready; - enum RTS51X_STAT state; - int support_auto_delink; -#endif - /* used to back up the protocal choosen in probe1 phase */ - proto_cmnd proto_handler_backup; -}; - -/* flag definition */ -#define FLIDX_AUTO_DELINK 0x01 - -#define SCSI_LUN(srb) ((srb)->device->lun) - -/* Bit Operation */ -#define SET_BIT(data, idx) ((data) |= 1 << (idx)) -#define CLR_BIT(data, idx) ((data) &= ~(1 << (idx))) -#define CHK_BIT(data, idx) ((data) & (1 << (idx))) - -#define SET_AUTO_DELINK(chip) ((chip)->flag |= FLIDX_AUTO_DELINK) -#define CLR_AUTO_DELINK(chip) ((chip)->flag &= ~FLIDX_AUTO_DELINK) -#define CHK_AUTO_DELINK(chip) ((chip)->flag & FLIDX_AUTO_DELINK) - -#define RTS51X_GET_VID(chip) ((chip)->vendor_id) -#define RTS51X_GET_PID(chip) ((chip)->product_id) - -#define VENDOR_ID(chip) ((chip)->status[0].vid) -#define PRODUCT_ID(chip) ((chip)->status[0].pid) -#define FW_VERSION(chip) ((chip)->status[0].fw_ver) -#define STATUS_LEN(chip) ((chip)->status_len) - -#define STATUS_SUCCESS 0 -#define STATUS_FAIL 1 - -/* Check card reader function */ -#define SUPPORT_DETAILED_TYPE1(chip) \ - CHK_BIT((chip)->status[0].function[0], 1) -#define SUPPORT_OT(chip) \ - CHK_BIT((chip)->status[0].function[0], 2) -#define SUPPORT_OC(chip) \ - CHK_BIT((chip)->status[0].function[0], 3) -#define SUPPORT_AUTO_DELINK(chip) \ - CHK_BIT((chip)->status[0].function[0], 4) -#define SUPPORT_SDIO(chip) \ - CHK_BIT((chip)->status[0].function[1], 0) -#define SUPPORT_DETAILED_TYPE2(chip) \ - CHK_BIT((chip)->status[0].function[1], 1) - -#define CHECK_PID(chip, pid) (RTS51X_GET_PID(chip) == (pid)) -#define CHECK_FW_VER(chip, fw_ver) (FW_VERSION(chip) == (fw_ver)) -#define CHECK_ID(chip, pid, fw_ver) \ - (CHECK_PID((chip), (pid)) && CHECK_FW_VER((chip), (fw_ver))) - -static int init_realtek_cr(struct us_data *us); - -/* - * The table of devices - */ -#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ - vendorName, productName, useProtocol, useTransport, \ - initFunction, flags) \ -{\ - USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24)\ -} - -static const struct usb_device_id realtek_cr_ids[] = { -# include "unusual_realtek.h" - {} /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, realtek_cr_ids); - -#undef UNUSUAL_DEV - -/* - * The flags table - */ -#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ - vendor_name, product_name, use_protocol, use_transport, \ - init_function, Flags) \ -{ \ - .vendorName = vendor_name, \ - .productName = product_name, \ - .useProtocol = use_protocol, \ - .useTransport = use_transport, \ - .initFunction = init_function, \ -} - -static struct us_unusual_dev realtek_cr_unusual_dev_list[] = { -# include "unusual_realtek.h" - {} /* Terminating entry */ -}; - -#undef UNUSUAL_DEV - -static int rts51x_bulk_transport(struct us_data *us, u8 lun, - u8 *cmd, int cmd_len, u8 *buf, int buf_len, - enum dma_data_direction dir, int *act_len) -{ - struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *)us->iobuf; - struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *)us->iobuf; - int result; - unsigned int residue; - unsigned int cswlen; - unsigned int cbwlen = US_BULK_CB_WRAP_LEN; - - /* set up the command wrapper */ - bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb->DataTransferLength = cpu_to_le32(buf_len); - bcb->Flags = (dir == DMA_FROM_DEVICE) ? US_BULK_FLAG_IN : 0; - bcb->Tag = ++us->tag; - bcb->Lun = lun; - bcb->Length = cmd_len; - - /* copy the command payload */ - memset(bcb->CDB, 0, sizeof(bcb->CDB)); - memcpy(bcb->CDB, cmd, bcb->Length); - - /* send it to out endpoint */ - result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, - bcb, cbwlen, NULL); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - /* DATA STAGE */ - /* send/receive data payload, if there is any */ - - if (buf && buf_len) { - unsigned int pipe = (dir == DMA_FROM_DEVICE) ? - us->recv_bulk_pipe : us->send_bulk_pipe; - result = usb_stor_bulk_transfer_buf(us, pipe, - buf, buf_len, NULL); - if (result == USB_STOR_XFER_ERROR) - return USB_STOR_TRANSPORT_ERROR; - } - - /* get CSW for device status */ - result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, - bcs, US_BULK_CS_WRAP_LEN, &cswlen); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - /* check bulk status */ - if (bcs->Signature != cpu_to_le32(US_BULK_CS_SIGN)) { - US_DEBUGP("Signature mismatch: got %08X, expecting %08X\n", - le32_to_cpu(bcs->Signature), US_BULK_CS_SIGN); - return USB_STOR_TRANSPORT_ERROR; - } - - residue = bcs->Residue; - if (bcs->Tag != us->tag) - return USB_STOR_TRANSPORT_ERROR; - - /* try to compute the actual residue, based on how much data - * was really transferred and what the device tells us */ - if (residue) - residue = residue < buf_len ? residue : buf_len; - - if (act_len) - *act_len = buf_len - residue; - - /* based on the status code, we report good or bad */ - switch (bcs->Status) { - case US_BULK_STAT_OK: - /* command good -- note that data could be short */ - return USB_STOR_TRANSPORT_GOOD; - - case US_BULK_STAT_FAIL: - /* command failed */ - return USB_STOR_TRANSPORT_FAILED; - - case US_BULK_STAT_PHASE: - /* phase error -- note that a transport reset will be - * invoked by the invoke_transport() function - */ - return USB_STOR_TRANSPORT_ERROR; - } - - /* we should never get here, but if we do, we're in trouble */ - return USB_STOR_TRANSPORT_ERROR; -} - -static int rts51x_bulk_transport_special(struct us_data *us, u8 lun, - u8 *cmd, int cmd_len, u8 *buf, int buf_len, - enum dma_data_direction dir, int *act_len) -{ - struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; - struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf; - int result; - unsigned int cswlen; - unsigned int cbwlen = US_BULK_CB_WRAP_LEN; - - /* set up the command wrapper */ - bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb->DataTransferLength = cpu_to_le32(buf_len); - bcb->Flags = (dir == DMA_FROM_DEVICE) ? US_BULK_FLAG_IN : 0; - bcb->Tag = ++us->tag; - bcb->Lun = lun; - bcb->Length = cmd_len; - - /* copy the command payload */ - memset(bcb->CDB, 0, sizeof(bcb->CDB)); - memcpy(bcb->CDB, cmd, bcb->Length); - - /* send it to out endpoint */ - result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, - bcb, cbwlen, NULL); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - /* DATA STAGE */ - /* send/receive data payload, if there is any */ - - if (buf && buf_len) { - unsigned int pipe = (dir == DMA_FROM_DEVICE) ? - us->recv_bulk_pipe : us->send_bulk_pipe; - result = usb_stor_bulk_transfer_buf(us, pipe, - buf, buf_len, NULL); - if (result == USB_STOR_XFER_ERROR) - return USB_STOR_TRANSPORT_ERROR; - } - - /* get CSW for device status */ - result = usb_bulk_msg(us->pusb_dev, us->recv_bulk_pipe, bcs, - US_BULK_CS_WRAP_LEN, &cswlen, 250); - return result; -} - -/* Determine what the maximum LUN supported is */ -static int rts51x_get_max_lun(struct us_data *us) -{ - int result; - - /* issue the command */ - us->iobuf[0] = 0; - result = usb_stor_control_msg(us, us->recv_ctrl_pipe, - US_BULK_GET_MAX_LUN, - USB_DIR_IN | USB_TYPE_CLASS | - USB_RECIP_INTERFACE, - 0, us->ifnum, us->iobuf, 1, 10 * HZ); - - US_DEBUGP("GetMaxLUN command result is %d, data is %d\n", - result, us->iobuf[0]); - - /* if we have a successful request, return the result */ - if (result > 0) - return us->iobuf[0]; - - return 0; -} - -static int rts51x_read_mem(struct us_data *us, u16 addr, u8 *data, u16 len) -{ - int retval; - u8 cmnd[12] = { 0 }; - u8 *buf; - - buf = kmalloc(len, GFP_NOIO); - if (buf == NULL) - return USB_STOR_TRANSPORT_ERROR; - - US_DEBUGP("%s, addr = 0x%x, len = %d\n", __func__, addr, len); - - cmnd[0] = 0xF0; - cmnd[1] = 0x0D; - cmnd[2] = (u8) (addr >> 8); - cmnd[3] = (u8) addr; - cmnd[4] = (u8) (len >> 8); - cmnd[5] = (u8) len; - - retval = rts51x_bulk_transport(us, 0, cmnd, 12, - buf, len, DMA_FROM_DEVICE, NULL); - if (retval != USB_STOR_TRANSPORT_GOOD) { - kfree(buf); - return -EIO; - } - - memcpy(data, buf, len); - kfree(buf); - return 0; -} - -static int rts51x_write_mem(struct us_data *us, u16 addr, u8 *data, u16 len) -{ - int retval; - u8 cmnd[12] = { 0 }; - u8 *buf; - - buf = kmemdup(data, len, GFP_NOIO); - if (buf == NULL) - return USB_STOR_TRANSPORT_ERROR; - - US_DEBUGP("%s, addr = 0x%x, len = %d\n", __func__, addr, len); - - cmnd[0] = 0xF0; - cmnd[1] = 0x0E; - cmnd[2] = (u8) (addr >> 8); - cmnd[3] = (u8) addr; - cmnd[4] = (u8) (len >> 8); - cmnd[5] = (u8) len; - - retval = rts51x_bulk_transport(us, 0, cmnd, 12, - buf, len, DMA_TO_DEVICE, NULL); - kfree(buf); - if (retval != USB_STOR_TRANSPORT_GOOD) - return -EIO; - - return 0; -} - -static int rts51x_read_status(struct us_data *us, - u8 lun, u8 *status, int len, int *actlen) -{ - int retval; - u8 cmnd[12] = { 0 }; - u8 *buf; - - buf = kmalloc(len, GFP_NOIO); - if (buf == NULL) - return USB_STOR_TRANSPORT_ERROR; - - US_DEBUGP("%s, lun = %d\n", __func__, lun); - - cmnd[0] = 0xF0; - cmnd[1] = 0x09; - - retval = rts51x_bulk_transport(us, lun, cmnd, 12, - buf, len, DMA_FROM_DEVICE, actlen); - if (retval != USB_STOR_TRANSPORT_GOOD) { - kfree(buf); - return -EIO; - } - - memcpy(status, buf, len); - kfree(buf); - return 0; -} - -static int rts51x_check_status(struct us_data *us, u8 lun) -{ - struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra); - int retval; - u8 buf[16]; - - retval = rts51x_read_status(us, lun, buf, 16, &(chip->status_len)); - if (retval < 0) - return -EIO; - - US_DEBUGP("chip->status_len = %d\n", chip->status_len); - - chip->status[lun].vid = ((u16) buf[0] << 8) | buf[1]; - chip->status[lun].pid = ((u16) buf[2] << 8) | buf[3]; - chip->status[lun].cur_lun = buf[4]; - chip->status[lun].card_type = buf[5]; - chip->status[lun].total_lun = buf[6]; - chip->status[lun].fw_ver = ((u16) buf[7] << 8) | buf[8]; - chip->status[lun].phy_exist = buf[9]; - chip->status[lun].multi_flag = buf[10]; - chip->status[lun].multi_card = buf[11]; - chip->status[lun].log_exist = buf[12]; - if (chip->status_len == 16) { - chip->status[lun].detailed_type.detailed_type1 = buf[13]; - chip->status[lun].function[0] = buf[14]; - chip->status[lun].function[1] = buf[15]; - } - - return 0; -} - -static int enable_oscillator(struct us_data *us) -{ - int retval; - u8 value; - - retval = rts51x_read_mem(us, 0xFE77, &value, 1); - if (retval < 0) - return -EIO; - - value |= 0x04; - retval = rts51x_write_mem(us, 0xFE77, &value, 1); - if (retval < 0) - return -EIO; - - retval = rts51x_read_mem(us, 0xFE77, &value, 1); - if (retval < 0) - return -EIO; - - if (!(value & 0x04)) - return -EIO; - - return 0; -} - -static int __do_config_autodelink(struct us_data *us, u8 *data, u16 len) -{ - int retval; - u8 cmnd[12] = {0}; - u8 *buf; - - US_DEBUGP("%s, addr = 0xfe47, len = %d\n", __FUNCTION__, len); - - buf = kmemdup(data, len, GFP_NOIO); - if (!buf) - return USB_STOR_TRANSPORT_ERROR; - - cmnd[0] = 0xF0; - cmnd[1] = 0x0E; - cmnd[2] = 0xfe; - cmnd[3] = 0x47; - cmnd[4] = (u8)(len >> 8); - cmnd[5] = (u8)len; - - retval = rts51x_bulk_transport_special(us, 0, cmnd, 12, buf, len, DMA_TO_DEVICE, NULL); - kfree(buf); - if (retval != USB_STOR_TRANSPORT_GOOD) { - return -EIO; - } - - return 0; -} - -static int do_config_autodelink(struct us_data *us, int enable, int force) -{ - int retval; - u8 value; - - retval = rts51x_read_mem(us, 0xFE47, &value, 1); - if (retval < 0) - return -EIO; - - if (enable) { - if (force) - value |= 0x03; - else - value |= 0x01; - } else { - value &= ~0x03; - } - - US_DEBUGP("In %s,set 0xfe47 to 0x%x\n", __func__, value); - - /* retval = rts51x_write_mem(us, 0xFE47, &value, 1); */ - retval = __do_config_autodelink(us, &value, 1); - if (retval < 0) - return -EIO; - - return 0; -} - -static int config_autodelink_after_power_on(struct us_data *us) -{ - struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra); - int retval; - u8 value; - - US_DEBUGP("%s: <---\n", __func__); - - if (!CHK_AUTO_DELINK(chip)) - return 0; - - retval = rts51x_read_mem(us, 0xFE47, &value, 1); - if (retval < 0) - return -EIO; - - if (auto_delink_en) { - CLR_BIT(value, 0); - CLR_BIT(value, 1); - SET_BIT(value, 2); - - if (CHECK_ID(chip, 0x0138, 0x3882)) - CLR_BIT(value, 2); - - SET_BIT(value, 7); - - /* retval = rts51x_write_mem(us, 0xFE47, &value, 1); */ - retval = __do_config_autodelink(us, &value, 1); - if (retval < 0) - return -EIO; - - retval = enable_oscillator(us); - if (retval == 0) - (void)do_config_autodelink(us, 1, 0); - } else { - /* Autodelink controlled by firmware */ - - SET_BIT(value, 2); - - if (CHECK_ID(chip, 0x0138, 0x3882)) - CLR_BIT(value, 2); - - if (CHECK_ID(chip, 0x0159, 0x5889) || - CHECK_ID(chip, 0x0138, 0x3880)) { - CLR_BIT(value, 0); - CLR_BIT(value, 7); - } - - /* retval = rts51x_write_mem(us, 0xFE47, &value, 1); */ - retval = __do_config_autodelink(us, &value, 1); - if (retval < 0) - return -EIO; - - if (CHECK_ID(chip, 0x0159, 0x5888)) { - value = 0xFF; - retval = rts51x_write_mem(us, 0xFE79, &value, 1); - if (retval < 0) - return -EIO; - - value = 0x01; - retval = rts51x_write_mem(us, 0x48, &value, 1); - if (retval < 0) - return -EIO; - } - } - - US_DEBUGP("%s: --->\n", __func__); - - return 0; -} - -static int config_autodelink_before_power_down(struct us_data *us) -{ - struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra); - int retval; - u8 value; - - US_DEBUGP("%s: <---\n", __func__); - - if (!CHK_AUTO_DELINK(chip)) - return 0; - - if (auto_delink_en) { - retval = rts51x_read_mem(us, 0xFE77, &value, 1); - if (retval < 0) - return -EIO; - - SET_BIT(value, 2); - retval = rts51x_write_mem(us, 0xFE77, &value, 1); - if (retval < 0) - return -EIO; - - if (CHECK_ID(chip, 0x0159, 0x5888)) { - value = 0x01; - retval = rts51x_write_mem(us, 0x48, &value, 1); - if (retval < 0) - return -EIO; - } - - retval = rts51x_read_mem(us, 0xFE47, &value, 1); - if (retval < 0) - return -EIO; - - SET_BIT(value, 0); - if (CHECK_ID(chip, 0x0138, 0x3882)) - SET_BIT(value, 2); - retval = rts51x_write_mem(us, 0xFE77, &value, 1); - if (retval < 0) - return -EIO; - } else { - if (CHECK_ID(chip, 0x0159, 0x5889) || - CHECK_ID(chip, 0x0138, 0x3880) || - CHECK_ID(chip, 0x0138, 0x3882)) { - retval = rts51x_read_mem(us, 0xFE47, &value, 1); - if (retval < 0) - return -EIO; - - if (CHECK_ID(chip, 0x0159, 0x5889) || - CHECK_ID(chip, 0x0138, 0x3880)) { - SET_BIT(value, 0); - SET_BIT(value, 7); - } - - if (CHECK_ID(chip, 0x0138, 0x3882)) - SET_BIT(value, 2); - - /* retval = rts51x_write_mem(us, 0xFE47, &value, 1); */ - retval = __do_config_autodelink(us, &value, 1); - if (retval < 0) - return -EIO; - } - - if (CHECK_ID(chip, 0x0159, 0x5888)) { - value = 0x01; - retval = rts51x_write_mem(us, 0x48, &value, 1); - if (retval < 0) - return -EIO; - } - } - - US_DEBUGP("%s: --->\n", __func__); - - return 0; -} - -static void fw5895_init(struct us_data *us) -{ - struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra); - int retval; - u8 val; - - US_DEBUGP("%s: <---\n", __func__); - - if ((PRODUCT_ID(chip) != 0x0158) || (FW_VERSION(chip) != 0x5895)) { - US_DEBUGP("Not the specified device, return immediately!\n"); - } else { - retval = rts51x_read_mem(us, 0xFD6F, &val, 1); - if (retval == STATUS_SUCCESS && (val & 0x1F) == 0) { - val = 0x1F; - retval = rts51x_write_mem(us, 0xFD70, &val, 1); - if (retval != STATUS_SUCCESS) - US_DEBUGP("Write memory fail\n"); - } else { - US_DEBUGP("Read memory fail, OR (val & 0x1F) != 0\n"); - } - } - - US_DEBUGP("%s: --->\n", __func__); -} - -#ifdef CONFIG_REALTEK_AUTOPM -static void fw5895_set_mmc_wp(struct us_data *us) -{ - struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra); - int retval; - u8 buf[13]; - - US_DEBUGP("%s: <---\n", __func__); - - if ((PRODUCT_ID(chip) != 0x0158) || (FW_VERSION(chip) != 0x5895)) { - US_DEBUGP("Not the specified device, return immediately!\n"); - } else { - retval = rts51x_read_mem(us, 0xFD6F, buf, 1); - if (retval == STATUS_SUCCESS && (buf[0] & 0x24) == 0x24) { - /* SD Exist and SD WP */ - retval = rts51x_read_mem(us, 0xD04E, buf, 1); - if (retval == STATUS_SUCCESS) { - buf[0] |= 0x04; - retval = rts51x_write_mem(us, 0xFD70, buf, 1); - if (retval != STATUS_SUCCESS) - US_DEBUGP("Write memory fail\n"); - } else { - US_DEBUGP("Read memory fail\n"); - } - } else { - US_DEBUGP("Read memory fail, OR (buf[0]&0x24)!=0x24\n"); - } - } - - US_DEBUGP("%s: --->\n", __func__); -} - -static void rts51x_modi_suspend_timer(struct rts51x_chip *chip) -{ - US_DEBUGP("%s: <---, state:%d\n", __func__, rts51x_get_stat(chip)); - - chip->timer_expires = jiffies + msecs_to_jiffies(1000*ss_delay); - mod_timer(&chip->rts51x_suspend_timer, chip->timer_expires); - - US_DEBUGP("%s: --->\n", __func__); -} - -static void rts51x_suspend_timer_fn(unsigned long data) -{ - struct rts51x_chip *chip = (struct rts51x_chip *)data; - struct us_data *us = chip->us; - - US_DEBUGP("%s: <---\n", __func__); - - switch (rts51x_get_stat(chip)) { - case RTS51X_STAT_INIT: - case RTS51X_STAT_RUN: - rts51x_modi_suspend_timer(chip); - break; - case RTS51X_STAT_IDLE: - case RTS51X_STAT_SS: - US_DEBUGP("%s: RTS51X_STAT_SS, intf->pm_usage_cnt:%d," - "power.usage:%d\n", __func__, - atomic_read(&us->pusb_intf->pm_usage_cnt), - atomic_read(&us->pusb_intf->dev.power.usage_count)); - - if (atomic_read(&us->pusb_intf->pm_usage_cnt) > 0) { - US_DEBUGP("%s: Ready to enter SS state.\n", - __func__); - rts51x_set_stat(chip, RTS51X_STAT_SS); - /* ignore mass storage interface's children */ - pm_suspend_ignore_children(&us->pusb_intf->dev, true); - usb_autopm_put_interface_async(us->pusb_intf); - US_DEBUGP("%s: RTS51X_STAT_SS 01," - "intf->pm_usage_cnt:%d, power.usage:%d\n", - __func__, - atomic_read(&us->pusb_intf->pm_usage_cnt), - atomic_read( - &us->pusb_intf->dev.power.usage_count)); - } - break; - default: - US_DEBUGP("%s: Unknonwn state !!!\n", __func__); - break; - } - - US_DEBUGP("%s: --->\n", __func__); -} - -static inline int working_scsi(struct scsi_cmnd *srb) -{ - if ((srb->cmnd[0] == TEST_UNIT_READY) || - (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL)) { - return 0; - } - - return 1; -} - -static void rts51x_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) -{ - struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra); - static int card_first_show = 1; - static u8 media_not_present[] = { 0x70, 0, 0x02, 0, 0, 0, 0, - 10, 0, 0, 0, 0, 0x3A, 0, 0, 0, 0, 0 - }; - static u8 invalid_cmd_field[] = { 0x70, 0, 0x05, 0, 0, 0, 0, - 10, 0, 0, 0, 0, 0x24, 0, 0, 0, 0, 0 - }; - int ret; - - US_DEBUGP("%s: <---\n", __func__); - - if (working_scsi(srb)) { - US_DEBUGP("%s: working scsi, intf->pm_usage_cnt:%d," - "power.usage:%d\n", __func__, - atomic_read(&us->pusb_intf->pm_usage_cnt), - atomic_read(&us->pusb_intf->dev.power.usage_count)); - - if (atomic_read(&us->pusb_intf->pm_usage_cnt) <= 0) { - ret = usb_autopm_get_interface(us->pusb_intf); - US_DEBUGP("%s: working scsi, ret=%d\n", __func__, ret); - } - if (rts51x_get_stat(chip) != RTS51X_STAT_RUN) - rts51x_set_stat(chip, RTS51X_STAT_RUN); - chip->proto_handler_backup(srb, us); - } else { - if (rts51x_get_stat(chip) == RTS51X_STAT_SS) { - US_DEBUGP("%s: NOT working scsi\n", __func__); - if ((srb->cmnd[0] == TEST_UNIT_READY) && - (chip->pwr_state == US_SUSPEND)) { - if (TST_LUN_READY(chip, srb->device->lun)) { - srb->result = SAM_STAT_GOOD; - } else { - srb->result = SAM_STAT_CHECK_CONDITION; - memcpy(srb->sense_buffer, - media_not_present, - US_SENSE_SIZE); - } - US_DEBUGP("%s: TEST_UNIT_READY--->\n", - __func__); - goto out; - } - if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { - int prevent = srb->cmnd[4] & 0x1; - if (prevent) { - srb->result = SAM_STAT_CHECK_CONDITION; - memcpy(srb->sense_buffer, - invalid_cmd_field, - US_SENSE_SIZE); - } else { - srb->result = SAM_STAT_GOOD; - } - US_DEBUGP("%s: ALLOW_MEDIUM_REMOVAL--->\n", - __func__); - goto out; - } - } else { - US_DEBUGP("%s: NOT working scsi, not SS\n", __func__); - chip->proto_handler_backup(srb, us); - /* Check wether card is plugged in */ - if (srb->cmnd[0] == TEST_UNIT_READY) { - if (srb->result == SAM_STAT_GOOD) { - SET_LUN_READY(chip, srb->device->lun); - if (card_first_show) { - card_first_show = 0; - fw5895_set_mmc_wp(us); - } - } else { - CLR_LUN_READY(chip, srb->device->lun); - card_first_show = 1; - } - } - if (rts51x_get_stat(chip) != RTS51X_STAT_IDLE) - rts51x_set_stat(chip, RTS51X_STAT_IDLE); - } - } -out: - US_DEBUGP("%s: state:%d\n", __func__, rts51x_get_stat(chip)); - if (rts51x_get_stat(chip) == RTS51X_STAT_RUN) - rts51x_modi_suspend_timer(chip); - - US_DEBUGP("%s: --->\n", __func__); -} - -static int realtek_cr_autosuspend_setup(struct us_data *us) -{ - struct rts51x_chip *chip; - struct rts51x_status *status = NULL; - u8 buf[16]; - int retval; - - chip = (struct rts51x_chip *)us->extra; - chip->support_auto_delink = 0; - chip->pwr_state = US_RESUME; - chip->lun_ready = 0; - rts51x_set_stat(chip, RTS51X_STAT_INIT); - - retval = rts51x_read_status(us, 0, buf, 16, &(chip->status_len)); - if (retval != STATUS_SUCCESS) { - US_DEBUGP("Read status fail\n"); - return -EIO; - } - status = chip->status; - status->vid = ((u16) buf[0] << 8) | buf[1]; - status->pid = ((u16) buf[2] << 8) | buf[3]; - status->cur_lun = buf[4]; - status->card_type = buf[5]; - status->total_lun = buf[6]; - status->fw_ver = ((u16) buf[7] << 8) | buf[8]; - status->phy_exist = buf[9]; - status->multi_flag = buf[10]; - status->multi_card = buf[11]; - status->log_exist = buf[12]; - if (chip->status_len == 16) { - status->detailed_type.detailed_type1 = buf[13]; - status->function[0] = buf[14]; - status->function[1] = buf[15]; - } - - /* back up the proto_handler in us->extra */ - chip = (struct rts51x_chip *)(us->extra); - chip->proto_handler_backup = us->proto_handler; - /* Set the autosuspend_delay to 0 */ - pm_runtime_set_autosuspend_delay(&us->pusb_dev->dev, 0); - /* override us->proto_handler setted in get_protocol() */ - us->proto_handler = rts51x_invoke_transport; - - chip->timer_expires = 0; - setup_timer(&chip->rts51x_suspend_timer, rts51x_suspend_timer_fn, - (unsigned long)chip); - fw5895_init(us); - - /* enable autosuspend funciton of the usb device */ - usb_enable_autosuspend(us->pusb_dev); - - return 0; -} -#endif - -static void realtek_cr_destructor(void *extra) -{ - struct rts51x_chip *chip = (struct rts51x_chip *)extra; - - US_DEBUGP("%s: <---\n", __func__); - - if (!chip) - return; -#ifdef CONFIG_REALTEK_AUTOPM - if (ss_en) { - del_timer(&chip->rts51x_suspend_timer); - chip->timer_expires = 0; - } -#endif - kfree(chip->status); -} - -#ifdef CONFIG_PM -static int realtek_cr_suspend(struct usb_interface *iface, pm_message_t message) -{ - struct us_data *us = usb_get_intfdata(iface); - - US_DEBUGP("%s: <---\n", __func__); - - /* wait until no command is running */ - mutex_lock(&us->dev_mutex); - - config_autodelink_before_power_down(us); - - mutex_unlock(&us->dev_mutex); - - US_DEBUGP("%s: --->\n", __func__); - - return 0; -} - -static int realtek_cr_resume(struct usb_interface *iface) -{ - struct us_data *us = usb_get_intfdata(iface); - - US_DEBUGP("%s: <---\n", __func__); - - fw5895_init(us); - config_autodelink_after_power_on(us); - - US_DEBUGP("%s: --->\n", __func__); - - return 0; -} -#else -#define realtek_cr_suspend NULL -#define realtek_cr_resume NULL -#endif - -static int init_realtek_cr(struct us_data *us) -{ - struct rts51x_chip *chip; - int size, i, retval; - - chip = kzalloc(sizeof(struct rts51x_chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - us->extra = chip; - us->extra_destructor = realtek_cr_destructor; - us->max_lun = chip->max_lun = rts51x_get_max_lun(us); - - US_DEBUGP("chip->max_lun = %d\n", chip->max_lun); - - size = (chip->max_lun + 1) * sizeof(struct rts51x_status); - chip->status = kzalloc(size, GFP_KERNEL); - if (!chip->status) - goto INIT_FAIL; - - for (i = 0; i <= (int)(chip->max_lun); i++) { - retval = rts51x_check_status(us, (u8) i); - if (retval < 0) - goto INIT_FAIL; - } - - if (CHECK_FW_VER(chip, 0x5888) || CHECK_FW_VER(chip, 0x5889) || - CHECK_FW_VER(chip, 0x5901)) - SET_AUTO_DELINK(chip); - if (STATUS_LEN(chip) == 16) { - if (SUPPORT_AUTO_DELINK(chip)) - SET_AUTO_DELINK(chip); - } -#ifdef CONFIG_REALTEK_AUTOPM - if (ss_en) { - chip->us = us; - realtek_cr_autosuspend_setup(us); - } -#endif - - US_DEBUGP("chip->flag = 0x%x\n", chip->flag); - - (void)config_autodelink_after_power_on(us); - - return 0; - -INIT_FAIL: - if (us->extra) { - kfree(chip->status); - kfree(us->extra); - us->extra = NULL; - } - - return -EIO; -} - -static int realtek_cr_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct us_data *us; - int result; - - US_DEBUGP("Probe Realtek Card Reader!\n"); - - result = usb_stor_probe1(&us, intf, id, - (id - realtek_cr_ids) + - realtek_cr_unusual_dev_list); - if (result) - return result; - - result = usb_stor_probe2(us); - - return result; -} - -static struct usb_driver realtek_cr_driver = { - .name = "ums-realtek", - .probe = realtek_cr_probe, - .disconnect = usb_stor_disconnect, - /* .suspend = usb_stor_suspend, */ - /* .resume = usb_stor_resume, */ - .reset_resume = usb_stor_reset_resume, - .suspend = realtek_cr_suspend, - .resume = realtek_cr_resume, - .pre_reset = usb_stor_pre_reset, - .post_reset = usb_stor_post_reset, - .id_table = realtek_cr_ids, - .soft_unbind = 1, - .supports_autosuspend = 1, - .no_dynamic_id = 1, -}; - -module_usb_driver(realtek_cr_driver); diff --git a/ANDROID_3.4.5/drivers/usb/storage/scsiglue.c b/ANDROID_3.4.5/drivers/usb/storage/scsiglue.c deleted file mode 100644 index 11418da9..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/scsiglue.c +++ /dev/null @@ -1,595 +0,0 @@ -/* Driver for USB Mass Storage compliant devices - * SCSI layer glue code - * - * Current development and maintenance by: - * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * Developed with the assistance of: - * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) - * (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov) - * - * Initial work by: - * (c) 1999 Michael Gee (michael@linuxspecific.com) - * - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI and ATAPI commands in - * mind when they created this document. The commands are all very - * similar to commands in the SCSI-II and ATAPI specifications. - * - * It is important to note that in a number of cases this class - * exhibits class-specific exemptions from the USB specification. - * Notably the usage of NAK, STALL and ACK differs from the norm, in - * that they are used to communicate wait, failed and OK on commands. - * - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include - -#include -#include -#include -#include -#include - -#include "usb.h" -#include "scsiglue.h" -#include "debug.h" -#include "transport.h" -#include "protocol.h" - -/* Vendor IDs for companies that seem to include the READ CAPACITY bug - * in all their devices - */ -#define VENDOR_ID_NOKIA 0x0421 -#define VENDOR_ID_NIKON 0x04b0 -#define VENDOR_ID_PENTAX 0x0a17 -#define VENDOR_ID_MOTOROLA 0x22b8 - -/*********************************************************************** - * Host functions - ***********************************************************************/ - -static const char* host_info(struct Scsi_Host *host) -{ - struct us_data *us = host_to_us(host); - return us->scsi_name; -} - -static int slave_alloc (struct scsi_device *sdev) -{ - /* - * Set the INQUIRY transfer length to 36. We don't use any of - * the extra data and many devices choke if asked for more or - * less than 36 bytes. - */ - sdev->inquiry_len = 36; - - /* USB has unusual DMA-alignment requirements: Although the - * starting address of each scatter-gather element doesn't matter, - * the length of each element except the last must be divisible - * by the Bulk maxpacket value. There's currently no way to - * express this by block-layer constraints, so we'll cop out - * and simply require addresses to be aligned at 512-byte - * boundaries. This is okay since most block I/O involves - * hardware sectors that are multiples of 512 bytes in length, - * and since host controllers up through USB 2.0 have maxpacket - * values no larger than 512. - * - * But it doesn't suffice for Wireless USB, where Bulk maxpacket - * values can be as large as 2048. To make that work properly - * will require changes to the block layer. - */ - blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1)); - - return 0; -} - -static int slave_configure(struct scsi_device *sdev) -{ - struct us_data *us = host_to_us(sdev->host); - - /* Many devices have trouble transferring more than 32KB at a time, - * while others have trouble with more than 64K. At this time we - * are limiting both to 32K (64 sectores). - */ - if (us->fflags & (US_FL_MAX_SECTORS_64 | US_FL_MAX_SECTORS_MIN)) { - unsigned int max_sectors = 64; - - if (us->fflags & US_FL_MAX_SECTORS_MIN) - max_sectors = PAGE_CACHE_SIZE >> 9; - if (queue_max_hw_sectors(sdev->request_queue) > max_sectors) - blk_queue_max_hw_sectors(sdev->request_queue, - max_sectors); - } else if (sdev->type == TYPE_TAPE) { - /* Tapes need much higher max_sector limits, so just - * raise it to the maximum possible (4 GB / 512) and - * let the queue segment size sort out the real limit. - */ - blk_queue_max_hw_sectors(sdev->request_queue, 0x7FFFFF); - } - - /* Some USB host controllers can't do DMA; they have to use PIO. - * They indicate this by setting their dma_mask to NULL. For - * such controllers we need to make sure the block layer sets - * up bounce buffers in addressable memory. - */ - if (!us->pusb_dev->bus->controller->dma_mask) - blk_queue_bounce_limit(sdev->request_queue, BLK_BOUNCE_HIGH); - - /* We can't put these settings in slave_alloc() because that gets - * called before the device type is known. Consequently these - * settings can't be overridden via the scsi devinfo mechanism. */ - if (sdev->type == TYPE_DISK) { - - /* Some vendors seem to put the READ CAPACITY bug into - * all their devices -- primarily makers of cell phones - * and digital cameras. Since these devices always use - * flash media and can be expected to have an even number - * of sectors, we will always enable the CAPACITY_HEURISTICS - * flag unless told otherwise. */ - switch (le16_to_cpu(us->pusb_dev->descriptor.idVendor)) { - case VENDOR_ID_NOKIA: - case VENDOR_ID_NIKON: - case VENDOR_ID_PENTAX: - case VENDOR_ID_MOTOROLA: - if (!(us->fflags & (US_FL_FIX_CAPACITY | - US_FL_CAPACITY_OK))) - us->fflags |= US_FL_CAPACITY_HEURISTICS; - break; - } - - /* Disk-type devices use MODE SENSE(6) if the protocol - * (SubClass) is Transparent SCSI, otherwise they use - * MODE SENSE(10). */ - if (us->subclass != USB_SC_SCSI && us->subclass != USB_SC_CYP_ATACB) - sdev->use_10_for_ms = 1; - - /* Many disks only accept MODE SENSE transfer lengths of - * 192 bytes (that's what Windows uses). */ - sdev->use_192_bytes_for_3f = 1; - - /* Some devices don't like MODE SENSE with page=0x3f, - * which is the command used for checking if a device - * is write-protected. Now that we tell the sd driver - * to do a 192-byte transfer with this command the - * majority of devices work fine, but a few still can't - * handle it. The sd driver will simply assume those - * devices are write-enabled. */ - if (us->fflags & US_FL_NO_WP_DETECT) - sdev->skip_ms_page_3f = 1; - - /* A number of devices have problems with MODE SENSE for - * page x08, so we will skip it. */ - sdev->skip_ms_page_8 = 1; - - /* Some devices don't handle VPD pages correctly */ - sdev->skip_vpd_pages = 1; - - /* Some disks return the total number of blocks in response - * to READ CAPACITY rather than the highest block number. - * If this device makes that mistake, tell the sd driver. */ - if (us->fflags & US_FL_FIX_CAPACITY) - sdev->fix_capacity = 1; - - /* A few disks have two indistinguishable version, one of - * which reports the correct capacity and the other does not. - * The sd driver has to guess which is the case. */ - if (us->fflags & US_FL_CAPACITY_HEURISTICS) - sdev->guess_capacity = 1; - - /* Some devices cannot handle READ_CAPACITY_16 */ - if (us->fflags & US_FL_NO_READ_CAPACITY_16) - sdev->no_read_capacity_16 = 1; - - /* - * Many devices do not respond properly to READ_CAPACITY_16. - * Tell the SCSI layer to try READ_CAPACITY_10 first. - */ - sdev->try_rc_10_first = 1; - - /* assume SPC3 or latter devices support sense size > 18 */ - if (sdev->scsi_level > SCSI_SPC_2) - us->fflags |= US_FL_SANE_SENSE; - - /* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable - * Hardware Error) when any low-level error occurs, - * recoverable or not. Setting this flag tells the SCSI - * midlayer to retry such commands, which frequently will - * succeed and fix the error. The worst this can lead to - * is an occasional series of retries that will all fail. */ - sdev->retry_hwerror = 1; - - /* USB disks should allow restart. Some drives spin down - * automatically, requiring a START-STOP UNIT command. */ - sdev->allow_restart = 1; - - /* Some USB cardreaders have trouble reading an sdcard's last - * sector in a larger then 1 sector read, since the performance - * impact is negible we set this flag for all USB disks */ - sdev->last_sector_bug = 1; - - /* Enable last-sector hacks for single-target devices using - * the Bulk-only transport, unless we already know the - * capacity will be decremented or is correct. */ - if (!(us->fflags & (US_FL_FIX_CAPACITY | US_FL_CAPACITY_OK | - US_FL_SCM_MULT_TARG)) && - us->protocol == USB_PR_BULK) - us->use_last_sector_hacks = 1; - } else { - - /* Non-disk-type devices don't need to blacklist any pages - * or to force 192-byte transfer lengths for MODE SENSE. - * But they do need to use MODE SENSE(10). */ - sdev->use_10_for_ms = 1; - - /* Some (fake) usb cdrom devices don't like READ_DISC_INFO */ - if (us->fflags & US_FL_NO_READ_DISC_INFO) - sdev->no_read_disc_info = 1; - } - - /* The CB and CBI transports have no way to pass LUN values - * other than the bits in the second byte of a CDB. But those - * bits don't get set to the LUN value if the device reports - * scsi_level == 0 (UNKNOWN). Hence such devices must necessarily - * be single-LUN. - */ - if ((us->protocol == USB_PR_CB || us->protocol == USB_PR_CBI) && - sdev->scsi_level == SCSI_UNKNOWN) - us->max_lun = 0; - - /* Some devices choke when they receive a PREVENT-ALLOW MEDIUM - * REMOVAL command, so suppress those commands. */ - if (us->fflags & US_FL_NOT_LOCKABLE) - sdev->lockable = 0; - - /* this is to satisfy the compiler, tho I don't think the - * return code is ever checked anywhere. */ - return 0; -} - -static int target_alloc(struct scsi_target *starget) -{ - struct us_data *us = host_to_us(dev_to_shost(starget->dev.parent)); - - /* - * Some USB drives don't support REPORT LUNS, even though they - * report a SCSI revision level above 2. Tell the SCSI layer - * not to issue that command; it will perform a normal sequential - * scan instead. - */ - starget->no_report_luns = 1; - - /* - * The UFI spec treats the Peripheral Qualifier bits in an - * INQUIRY result as reserved and requires devices to set them - * to 0. However the SCSI spec requires these bits to be set - * to 3 to indicate when a LUN is not present. - * - * Let the scanning code know if this target merely sets - * Peripheral Device Type to 0x1f to indicate no LUN. - */ - if (us->subclass == USB_SC_UFI) - starget->pdt_1f_for_no_lun = 1; - - return 0; -} - -/* queue a command */ -/* This is always called with scsi_lock(host) held */ -static int queuecommand_lck(struct scsi_cmnd *srb, - void (*done)(struct scsi_cmnd *)) -{ - struct us_data *us = host_to_us(srb->device->host); - - US_DEBUGP("%s called\n", __func__); - - /* check for state-transition errors */ - if (us->srb != NULL) { - printk(KERN_ERR USB_STORAGE "Error in %s: us->srb = %p\n", - __func__, us->srb); - return SCSI_MLQUEUE_HOST_BUSY; - } - - /* fail the command if we are disconnecting */ - if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) { - US_DEBUGP("Fail command during disconnect\n"); - srb->result = DID_NO_CONNECT << 16; - done(srb); - return 0; - } - - /* enqueue the command and wake up the control thread */ - srb->scsi_done = done; - us->srb = srb; - complete(&us->cmnd_ready); - - return 0; -} - -static DEF_SCSI_QCMD(queuecommand) - -/*********************************************************************** - * Error handling functions - ***********************************************************************/ - -/* Command timeout and abort */ -static int command_abort(struct scsi_cmnd *srb) -{ - struct us_data *us = host_to_us(srb->device->host); - - US_DEBUGP("%s called\n", __func__); - - /* us->srb together with the TIMED_OUT, RESETTING, and ABORTING - * bits are protected by the host lock. */ - scsi_lock(us_to_host(us)); - - /* Is this command still active? */ - if (us->srb != srb) { - scsi_unlock(us_to_host(us)); - US_DEBUGP ("-- nothing to abort\n"); - return FAILED; - } - - /* Set the TIMED_OUT bit. Also set the ABORTING bit, but only if - * a device reset isn't already in progress (to avoid interfering - * with the reset). Note that we must retain the host lock while - * calling usb_stor_stop_transport(); otherwise it might interfere - * with an auto-reset that begins as soon as we release the lock. */ - set_bit(US_FLIDX_TIMED_OUT, &us->dflags); - if (!test_bit(US_FLIDX_RESETTING, &us->dflags)) { - set_bit(US_FLIDX_ABORTING, &us->dflags); - usb_stor_stop_transport(us); - } - scsi_unlock(us_to_host(us)); - - /* Wait for the aborted command to finish */ - wait_for_completion(&us->notify); - return SUCCESS; -} - -/* This invokes the transport reset mechanism to reset the state of the - * device */ -static int device_reset(struct scsi_cmnd *srb) -{ - struct us_data *us = host_to_us(srb->device->host); - int result; - - US_DEBUGP("%s called\n", __func__); - - /* lock the device pointers and do the reset */ - mutex_lock(&(us->dev_mutex)); - result = us->transport_reset(us); - mutex_unlock(&us->dev_mutex); - - return result < 0 ? FAILED : SUCCESS; -} - -/* Simulate a SCSI bus reset by resetting the device's USB port. */ -static int bus_reset(struct scsi_cmnd *srb) -{ - struct us_data *us = host_to_us(srb->device->host); - int result; - - US_DEBUGP("%s called\n", __func__); - result = usb_stor_port_reset(us); - return result < 0 ? FAILED : SUCCESS; -} - -/* Report a driver-initiated device reset to the SCSI layer. - * Calling this for a SCSI-initiated reset is unnecessary but harmless. - * The caller must own the SCSI host lock. */ -void usb_stor_report_device_reset(struct us_data *us) -{ - int i; - struct Scsi_Host *host = us_to_host(us); - - scsi_report_device_reset(host, 0, 0); - if (us->fflags & US_FL_SCM_MULT_TARG) { - for (i = 1; i < host->max_id; ++i) - scsi_report_device_reset(host, 0, i); - } -} - -/* Report a driver-initiated bus reset to the SCSI layer. - * Calling this for a SCSI-initiated reset is unnecessary but harmless. - * The caller must not own the SCSI host lock. */ -void usb_stor_report_bus_reset(struct us_data *us) -{ - struct Scsi_Host *host = us_to_host(us); - - scsi_lock(host); - scsi_report_bus_reset(host, 0); - scsi_unlock(host); -} - -/*********************************************************************** - * /proc/scsi/ functions - ***********************************************************************/ - -/* we use this macro to help us write into the buffer */ -#undef SPRINTF -#define SPRINTF(args...) \ - do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0) - -static int proc_info (struct Scsi_Host *host, char *buffer, - char **start, off_t offset, int length, int inout) -{ - struct us_data *us = host_to_us(host); - char *pos = buffer; - const char *string; - - /* if someone is sending us data, just throw it away */ - if (inout) - return length; - - /* print the controller name */ - SPRINTF(" Host scsi%d: usb-storage\n", host->host_no); - - /* print product, vendor, and serial number strings */ - if (us->pusb_dev->manufacturer) - string = us->pusb_dev->manufacturer; - else if (us->unusual_dev->vendorName) - string = us->unusual_dev->vendorName; - else - string = "Unknown"; - SPRINTF(" Vendor: %s\n", string); - if (us->pusb_dev->product) - string = us->pusb_dev->product; - else if (us->unusual_dev->productName) - string = us->unusual_dev->productName; - else - string = "Unknown"; - SPRINTF(" Product: %s\n", string); - if (us->pusb_dev->serial) - string = us->pusb_dev->serial; - else - string = "None"; - SPRINTF("Serial Number: %s\n", string); - - /* show the protocol and transport */ - SPRINTF(" Protocol: %s\n", us->protocol_name); - SPRINTF(" Transport: %s\n", us->transport_name); - - /* show the device flags */ - if (pos < buffer + length) { - pos += sprintf(pos, " Quirks:"); - -#define US_FLAG(name, value) \ - if (us->fflags & value) pos += sprintf(pos, " " #name); -US_DO_ALL_FLAGS -#undef US_FLAG - - *(pos++) = '\n'; - } - - /* - * Calculate start of next buffer, and return value. - */ - *start = buffer + offset; - - if ((pos - buffer) < offset) - return (0); - else if ((pos - buffer - offset) < length) - return (pos - buffer - offset); - else - return (length); -} - -/*********************************************************************** - * Sysfs interface - ***********************************************************************/ - -/* Output routine for the sysfs max_sectors file */ -static ssize_t show_max_sectors(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct scsi_device *sdev = to_scsi_device(dev); - - return sprintf(buf, "%u\n", queue_max_hw_sectors(sdev->request_queue)); -} - -/* Input routine for the sysfs max_sectors file */ -static ssize_t store_max_sectors(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) -{ - struct scsi_device *sdev = to_scsi_device(dev); - unsigned short ms; - - if (sscanf(buf, "%hu", &ms) > 0) { - blk_queue_max_hw_sectors(sdev->request_queue, ms); - return count; - } - return -EINVAL; -} - -static DEVICE_ATTR(max_sectors, S_IRUGO | S_IWUSR, show_max_sectors, - store_max_sectors); - -static struct device_attribute *sysfs_device_attr_list[] = { - &dev_attr_max_sectors, - NULL, - }; - -/* - * this defines our host template, with which we'll allocate hosts - */ - -struct scsi_host_template usb_stor_host_template = { - /* basic userland interface stuff */ - .name = "usb-storage", - .proc_name = "usb-storage", - .proc_info = proc_info, - .info = host_info, - - /* command interface -- queued only */ - .queuecommand = queuecommand, - - /* error and abort handlers */ - .eh_abort_handler = command_abort, - .eh_device_reset_handler = device_reset, - .eh_bus_reset_handler = bus_reset, - - /* queue commands only, only one command per LUN */ - .can_queue = 1, - .cmd_per_lun = 1, - - /* unknown initiator id */ - .this_id = -1, - - .slave_alloc = slave_alloc, - .slave_configure = slave_configure, - .target_alloc = target_alloc, - - /* lots of sg segments can be handled */ - .sg_tablesize = SCSI_MAX_SG_CHAIN_SEGMENTS, - - /* limit the total size of a transfer to 120 KB */ - .max_sectors = 240, - - /* merge commands... this seems to help performance, but - * periodically someone should test to see which setting is more - * optimal. - */ - .use_clustering = 1, - - /* emulated HBA */ - .emulated = 1, - - /* we do our own delay after a device or bus reset */ - .skip_settle_delay = 1, - - /* sysfs device attributes */ - .sdev_attrs = sysfs_device_attr_list, - - /* module management */ - .module = THIS_MODULE -}; - -/* To Report "Illegal Request: Invalid Field in CDB */ -unsigned char usb_stor_sense_invalidCDB[18] = { - [0] = 0x70, /* current error */ - [2] = ILLEGAL_REQUEST, /* Illegal Request = 0x05 */ - [7] = 0x0a, /* additional length */ - [12] = 0x24 /* Invalid Field in CDB */ -}; -EXPORT_SYMBOL_GPL(usb_stor_sense_invalidCDB); diff --git a/ANDROID_3.4.5/drivers/usb/storage/scsiglue.h b/ANDROID_3.4.5/drivers/usb/storage/scsiglue.h deleted file mode 100644 index ffa1cca9..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/scsiglue.h +++ /dev/null @@ -1,48 +0,0 @@ -/* Driver for USB Mass Storage compliant devices - * SCSI Connecting Glue Header File - * - * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI and ATAPI commands in - * mind when they created this document. The commands are all very - * similar to commands in the SCSI-II and ATAPI specifications. - * - * It is important to note that in a number of cases this class - * exhibits class-specific exemptions from the USB specification. - * Notably the usage of NAK, STALL and ACK differs from the norm, in - * that they are used to communicate wait, failed and OK on commands. - * - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _SCSIGLUE_H_ -#define _SCSIGLUE_H_ - -extern void usb_stor_report_device_reset(struct us_data *us); -extern void usb_stor_report_bus_reset(struct us_data *us); - -extern unsigned char usb_stor_sense_invalidCDB[18]; -extern struct scsi_host_template usb_stor_host_template; - -#endif diff --git a/ANDROID_3.4.5/drivers/usb/storage/sddr09.c b/ANDROID_3.4.5/drivers/usb/storage/sddr09.c deleted file mode 100644 index 3252a62b..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/sddr09.c +++ /dev/null @@ -1,1793 +0,0 @@ -/* Driver for SanDisk SDDR-09 SmartMedia reader - * - * (c) 2000, 2001 Robert Baruch (autophile@starband.net) - * (c) 2002 Andries Brouwer (aeb@cwi.nl) - * Developed with the assistance of: - * (c) 2002 Alan Stern - * - * The SanDisk SDDR-09 SmartMedia reader uses the Shuttle EUSB-01 chip. - * This chip is a programmable USB controller. In the SDDR-09, it has - * been programmed to obey a certain limited set of SCSI commands. - * This driver translates the "real" SCSI commands to the SDDR-09 SCSI - * commands. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* - * Known vendor commands: 12 bytes, first byte is opcode - * - * E7: read scatter gather - * E8: read - * E9: write - * EA: erase - * EB: reset - * EC: read status - * ED: read ID - * EE: write CIS (?) - * EF: compute checksum (?) - */ - -#include -#include -#include - -#include -#include -#include - -#include "usb.h" -#include "transport.h" -#include "protocol.h" -#include "debug.h" - -MODULE_DESCRIPTION("Driver for SanDisk SDDR-09 SmartMedia reader"); -MODULE_AUTHOR("Andries Brouwer , Robert Baruch "); -MODULE_LICENSE("GPL"); - -static int usb_stor_sddr09_dpcm_init(struct us_data *us); -static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us); -static int usb_stor_sddr09_init(struct us_data *us); - - -/* - * The table of devices - */ -#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ - vendorName, productName, useProtocol, useTransport, \ - initFunction, flags) \ -{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } - -static struct usb_device_id sddr09_usb_ids[] = { -# include "unusual_sddr09.h" - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, sddr09_usb_ids); - -#undef UNUSUAL_DEV - -/* - * The flags table - */ -#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ - vendor_name, product_name, use_protocol, use_transport, \ - init_function, Flags) \ -{ \ - .vendorName = vendor_name, \ - .productName = product_name, \ - .useProtocol = use_protocol, \ - .useTransport = use_transport, \ - .initFunction = init_function, \ -} - -static struct us_unusual_dev sddr09_unusual_dev_list[] = { -# include "unusual_sddr09.h" - { } /* Terminating entry */ -}; - -#undef UNUSUAL_DEV - - -#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) ) -#define LSB_of(s) ((s)&0xFF) -#define MSB_of(s) ((s)>>8) - -/* #define US_DEBUGP printk */ - -/* - * First some stuff that does not belong here: - * data on SmartMedia and other cards, completely - * unrelated to this driver. - * Similar stuff occurs in . - */ - -struct nand_flash_dev { - int model_id; - int chipshift; /* 1<recv_ctrl_pipe; - else - pipe = us->send_ctrl_pipe; - - rc = usb_stor_ctrl_transfer(us, pipe, request, requesttype, - 0, 0, xfer_data, xfer_len); - switch (rc) { - case USB_STOR_XFER_GOOD: return 0; - case USB_STOR_XFER_STALLED: return -EPIPE; - default: return -EIO; - } -} - -static int -sddr09_send_scsi_command(struct us_data *us, - unsigned char *command, - unsigned int command_len) { - return sddr09_send_command(us, 0, USB_DIR_OUT, command, command_len); -} - -#if 0 -/* - * Test Unit Ready Command: 12 bytes. - * byte 0: opcode: 00 - */ -static int -sddr09_test_unit_ready(struct us_data *us) { - unsigned char *command = us->iobuf; - int result; - - memset(command, 0, 6); - command[1] = LUNBITS; - - result = sddr09_send_scsi_command(us, command, 6); - - US_DEBUGP("sddr09_test_unit_ready returns %d\n", result); - - return result; -} -#endif - -/* - * Request Sense Command: 12 bytes. - * byte 0: opcode: 03 - * byte 4: data length - */ -static int -sddr09_request_sense(struct us_data *us, unsigned char *sensebuf, int buflen) { - unsigned char *command = us->iobuf; - int result; - - memset(command, 0, 12); - command[0] = 0x03; - command[1] = LUNBITS; - command[4] = buflen; - - result = sddr09_send_scsi_command(us, command, 12); - if (result) - return result; - - result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, - sensebuf, buflen, NULL); - return (result == USB_STOR_XFER_GOOD ? 0 : -EIO); -} - -/* - * Read Command: 12 bytes. - * byte 0: opcode: E8 - * byte 1: last two bits: 00: read data, 01: read blockwise control, - * 10: read both, 11: read pagewise control. - * It turns out we need values 20, 21, 22, 23 here (LUN 1). - * bytes 2-5: address (interpretation depends on byte 1, see below) - * bytes 10-11: count (idem) - * - * A page has 512 data bytes and 64 control bytes (16 control and 48 junk). - * A read data command gets data in 512-byte pages. - * A read control command gets control in 64-byte chunks. - * A read both command gets data+control in 576-byte chunks. - * - * Blocks are groups of 32 pages, and read blockwise control jumps to the - * next block, while read pagewise control jumps to the next page after - * reading a group of 64 control bytes. - * [Here 512 = 1<iobuf; - int result; - - command[0] = 0xE8; - command[1] = LUNBITS | x; - command[2] = MSB_of(fromaddress>>16); - command[3] = LSB_of(fromaddress>>16); - command[4] = MSB_of(fromaddress & 0xFFFF); - command[5] = LSB_of(fromaddress & 0xFFFF); - command[6] = 0; - command[7] = 0; - command[8] = 0; - command[9] = 0; - command[10] = MSB_of(nr_of_pages); - command[11] = LSB_of(nr_of_pages); - - result = sddr09_send_scsi_command(us, command, 12); - - if (result) { - US_DEBUGP("Result for send_control in sddr09_read2%d %d\n", - x, result); - return result; - } - - result = usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, - buf, bulklen, use_sg, NULL); - - if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Result for bulk_transfer in sddr09_read2%d %d\n", - x, result); - return -EIO; - } - return 0; -} - -/* - * Read Data - * - * fromaddress counts data shorts: - * increasing it by 256 shifts the bytestream by 512 bytes; - * the last 8 bits are ignored. - * - * nr_of_pages counts pages of size (1 << pageshift). - */ -static int -sddr09_read20(struct us_data *us, unsigned long fromaddress, - int nr_of_pages, int pageshift, unsigned char *buf, int use_sg) { - int bulklen = nr_of_pages << pageshift; - - /* The last 8 bits of fromaddress are ignored. */ - return sddr09_readX(us, 0, fromaddress, nr_of_pages, bulklen, - buf, use_sg); -} - -/* - * Read Blockwise Control - * - * fromaddress gives the starting position (as in read data; - * the last 8 bits are ignored); increasing it by 32*256 shifts - * the output stream by 64 bytes. - * - * count counts control groups of size (1 << controlshift). - * For me, controlshift = 6. Is this constant? - * - * After getting one control group, jump to the next block - * (fromaddress += 8192). - */ -static int -sddr09_read21(struct us_data *us, unsigned long fromaddress, - int count, int controlshift, unsigned char *buf, int use_sg) { - - int bulklen = (count << controlshift); - return sddr09_readX(us, 1, fromaddress, count, bulklen, - buf, use_sg); -} - -/* - * Read both Data and Control - * - * fromaddress counts data shorts, ignoring control: - * increasing it by 256 shifts the bytestream by 576 = 512+64 bytes; - * the last 8 bits are ignored. - * - * nr_of_pages counts pages of size (1 << pageshift) + (1 << controlshift). - */ -static int -sddr09_read22(struct us_data *us, unsigned long fromaddress, - int nr_of_pages, int pageshift, unsigned char *buf, int use_sg) { - - int bulklen = (nr_of_pages << pageshift) + (nr_of_pages << CONTROL_SHIFT); - US_DEBUGP("sddr09_read22: reading %d pages, %d bytes\n", - nr_of_pages, bulklen); - return sddr09_readX(us, 2, fromaddress, nr_of_pages, bulklen, - buf, use_sg); -} - -#if 0 -/* - * Read Pagewise Control - * - * fromaddress gives the starting position (as in read data; - * the last 8 bits are ignored); increasing it by 256 shifts - * the output stream by 64 bytes. - * - * count counts control groups of size (1 << controlshift). - * For me, controlshift = 6. Is this constant? - * - * After getting one control group, jump to the next page - * (fromaddress += 256). - */ -static int -sddr09_read23(struct us_data *us, unsigned long fromaddress, - int count, int controlshift, unsigned char *buf, int use_sg) { - - int bulklen = (count << controlshift); - return sddr09_readX(us, 3, fromaddress, count, bulklen, - buf, use_sg); -} -#endif - -/* - * Erase Command: 12 bytes. - * byte 0: opcode: EA - * bytes 6-9: erase address (big-endian, counting shorts, sector aligned). - * - * Always precisely one block is erased; bytes 2-5 and 10-11 are ignored. - * The byte address being erased is 2*Eaddress. - * The CIS cannot be erased. - */ -static int -sddr09_erase(struct us_data *us, unsigned long Eaddress) { - unsigned char *command = us->iobuf; - int result; - - US_DEBUGP("sddr09_erase: erase address %lu\n", Eaddress); - - memset(command, 0, 12); - command[0] = 0xEA; - command[1] = LUNBITS; - command[6] = MSB_of(Eaddress>>16); - command[7] = LSB_of(Eaddress>>16); - command[8] = MSB_of(Eaddress & 0xFFFF); - command[9] = LSB_of(Eaddress & 0xFFFF); - - result = sddr09_send_scsi_command(us, command, 12); - - if (result) - US_DEBUGP("Result for send_control in sddr09_erase %d\n", - result); - - return result; -} - -/* - * Write CIS Command: 12 bytes. - * byte 0: opcode: EE - * bytes 2-5: write address in shorts - * bytes 10-11: sector count - * - * This writes at the indicated address. Don't know how it differs - * from E9. Maybe it does not erase? However, it will also write to - * the CIS. - * - * When two such commands on the same page follow each other directly, - * the second one is not done. - */ - -/* - * Write Command: 12 bytes. - * byte 0: opcode: E9 - * bytes 2-5: write address (big-endian, counting shorts, sector aligned). - * bytes 6-9: erase address (big-endian, counting shorts, sector aligned). - * bytes 10-11: sector count (big-endian, in 512-byte sectors). - * - * If write address equals erase address, the erase is done first, - * otherwise the write is done first. When erase address equals zero - * no erase is done? - */ -static int -sddr09_writeX(struct us_data *us, - unsigned long Waddress, unsigned long Eaddress, - int nr_of_pages, int bulklen, unsigned char *buf, int use_sg) { - - unsigned char *command = us->iobuf; - int result; - - command[0] = 0xE9; - command[1] = LUNBITS; - - command[2] = MSB_of(Waddress>>16); - command[3] = LSB_of(Waddress>>16); - command[4] = MSB_of(Waddress & 0xFFFF); - command[5] = LSB_of(Waddress & 0xFFFF); - - command[6] = MSB_of(Eaddress>>16); - command[7] = LSB_of(Eaddress>>16); - command[8] = MSB_of(Eaddress & 0xFFFF); - command[9] = LSB_of(Eaddress & 0xFFFF); - - command[10] = MSB_of(nr_of_pages); - command[11] = LSB_of(nr_of_pages); - - result = sddr09_send_scsi_command(us, command, 12); - - if (result) { - US_DEBUGP("Result for send_control in sddr09_writeX %d\n", - result); - return result; - } - - result = usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, - buf, bulklen, use_sg, NULL); - - if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Result for bulk_transfer in sddr09_writeX %d\n", - result); - return -EIO; - } - return 0; -} - -/* erase address, write same address */ -static int -sddr09_write_inplace(struct us_data *us, unsigned long address, - int nr_of_pages, int pageshift, unsigned char *buf, - int use_sg) { - int bulklen = (nr_of_pages << pageshift) + (nr_of_pages << CONTROL_SHIFT); - return sddr09_writeX(us, address, address, nr_of_pages, bulklen, - buf, use_sg); -} - -#if 0 -/* - * Read Scatter Gather Command: 3+4n bytes. - * byte 0: opcode E7 - * byte 2: n - * bytes 4i-1,4i,4i+1: page address - * byte 4i+2: page count - * (i=1..n) - * - * This reads several pages from the card to a single memory buffer. - * The last two bits of byte 1 have the same meaning as for E8. - */ -static int -sddr09_read_sg_test_only(struct us_data *us) { - unsigned char *command = us->iobuf; - int result, bulklen, nsg, ct; - unsigned char *buf; - unsigned long address; - - nsg = bulklen = 0; - command[0] = 0xE7; - command[1] = LUNBITS; - command[2] = 0; - address = 040000; ct = 1; - nsg++; - bulklen += (ct << 9); - command[4*nsg+2] = ct; - command[4*nsg+1] = ((address >> 9) & 0xFF); - command[4*nsg+0] = ((address >> 17) & 0xFF); - command[4*nsg-1] = ((address >> 25) & 0xFF); - - address = 0340000; ct = 1; - nsg++; - bulklen += (ct << 9); - command[4*nsg+2] = ct; - command[4*nsg+1] = ((address >> 9) & 0xFF); - command[4*nsg+0] = ((address >> 17) & 0xFF); - command[4*nsg-1] = ((address >> 25) & 0xFF); - - address = 01000000; ct = 2; - nsg++; - bulklen += (ct << 9); - command[4*nsg+2] = ct; - command[4*nsg+1] = ((address >> 9) & 0xFF); - command[4*nsg+0] = ((address >> 17) & 0xFF); - command[4*nsg-1] = ((address >> 25) & 0xFF); - - command[2] = nsg; - - result = sddr09_send_scsi_command(us, command, 4*nsg+3); - - if (result) { - US_DEBUGP("Result for send_control in sddr09_read_sg %d\n", - result); - return result; - } - - buf = kmalloc(bulklen, GFP_NOIO); - if (!buf) - return -ENOMEM; - - result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, - buf, bulklen, NULL); - kfree(buf); - if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Result for bulk_transfer in sddr09_read_sg %d\n", - result); - return -EIO; - } - - return 0; -} -#endif - -/* - * Read Status Command: 12 bytes. - * byte 0: opcode: EC - * - * Returns 64 bytes, all zero except for the first. - * bit 0: 1: Error - * bit 5: 1: Suspended - * bit 6: 1: Ready - * bit 7: 1: Not write-protected - */ - -static int -sddr09_read_status(struct us_data *us, unsigned char *status) { - - unsigned char *command = us->iobuf; - unsigned char *data = us->iobuf; - int result; - - US_DEBUGP("Reading status...\n"); - - memset(command, 0, 12); - command[0] = 0xEC; - command[1] = LUNBITS; - - result = sddr09_send_scsi_command(us, command, 12); - if (result) - return result; - - result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, - data, 64, NULL); - *status = data[0]; - return (result == USB_STOR_XFER_GOOD ? 0 : -EIO); -} - -static int -sddr09_read_data(struct us_data *us, - unsigned long address, - unsigned int sectors) { - - struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra; - unsigned char *buffer; - unsigned int lba, maxlba, pba; - unsigned int page, pages; - unsigned int len, offset; - struct scatterlist *sg; - int result; - - // Figure out the initial LBA and page - lba = address >> info->blockshift; - page = (address & info->blockmask); - maxlba = info->capacity >> (info->pageshift + info->blockshift); - if (lba >= maxlba) - return -EIO; - - // Since we only read in one block at a time, we have to create - // a bounce buffer and move the data a piece at a time between the - // bounce buffer and the actual transfer buffer. - - len = min(sectors, (unsigned int) info->blocksize) * info->pagesize; - buffer = kmalloc(len, GFP_NOIO); - if (buffer == NULL) { - printk(KERN_WARNING "sddr09_read_data: Out of memory\n"); - return -ENOMEM; - } - - // This could be made much more efficient by checking for - // contiguous LBA's. Another exercise left to the student. - - result = 0; - offset = 0; - sg = NULL; - - while (sectors > 0) { - - /* Find number of pages we can read in this block */ - pages = min(sectors, info->blocksize - page); - len = pages << info->pageshift; - - /* Not overflowing capacity? */ - if (lba >= maxlba) { - US_DEBUGP("Error: Requested lba %u exceeds " - "maximum %u\n", lba, maxlba); - result = -EIO; - break; - } - - /* Find where this lba lives on disk */ - pba = info->lba_to_pba[lba]; - - if (pba == UNDEF) { /* this lba was never written */ - - US_DEBUGP("Read %d zero pages (LBA %d) page %d\n", - pages, lba, page); - - /* This is not really an error. It just means - that the block has never been written. - Instead of returning an error - it is better to return all zero data. */ - - memset(buffer, 0, len); - - } else { - US_DEBUGP("Read %d pages, from PBA %d" - " (LBA %d) page %d\n", - pages, pba, lba, page); - - address = ((pba << info->blockshift) + page) << - info->pageshift; - - result = sddr09_read20(us, address>>1, - pages, info->pageshift, buffer, 0); - if (result) - break; - } - - // Store the data in the transfer buffer - usb_stor_access_xfer_buf(buffer, len, us->srb, - &sg, &offset, TO_XFER_BUF); - - page = 0; - lba++; - sectors -= pages; - } - - kfree(buffer); - return result; -} - -static unsigned int -sddr09_find_unused_pba(struct sddr09_card_info *info, unsigned int lba) { - static unsigned int lastpba = 1; - int zonestart, end, i; - - zonestart = (lba/1000) << 10; - end = info->capacity >> (info->blockshift + info->pageshift); - end -= zonestart; - if (end > 1024) - end = 1024; - - for (i = lastpba+1; i < end; i++) { - if (info->pba_to_lba[zonestart+i] == UNDEF) { - lastpba = i; - return zonestart+i; - } - } - for (i = 0; i <= lastpba; i++) { - if (info->pba_to_lba[zonestart+i] == UNDEF) { - lastpba = i; - return zonestart+i; - } - } - return 0; -} - -static int -sddr09_write_lba(struct us_data *us, unsigned int lba, - unsigned int page, unsigned int pages, - unsigned char *ptr, unsigned char *blockbuffer) { - - struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra; - unsigned long address; - unsigned int pba, lbap; - unsigned int pagelen; - unsigned char *bptr, *cptr, *xptr; - unsigned char ecc[3]; - int i, result, isnew; - - lbap = ((lba % 1000) << 1) | 0x1000; - if (parity[MSB_of(lbap) ^ LSB_of(lbap)]) - lbap ^= 1; - pba = info->lba_to_pba[lba]; - isnew = 0; - - if (pba == UNDEF) { - pba = sddr09_find_unused_pba(info, lba); - if (!pba) { - printk(KERN_WARNING - "sddr09_write_lba: Out of unused blocks\n"); - return -ENOSPC; - } - info->pba_to_lba[pba] = lba; - info->lba_to_pba[lba] = pba; - isnew = 1; - } - - if (pba == 1) { - /* Maybe it is impossible to write to PBA 1. - Fake success, but don't do anything. */ - printk(KERN_WARNING "sddr09: avoid writing to pba 1\n"); - return 0; - } - - pagelen = (1 << info->pageshift) + (1 << CONTROL_SHIFT); - - /* read old contents */ - address = (pba << (info->pageshift + info->blockshift)); - result = sddr09_read22(us, address>>1, info->blocksize, - info->pageshift, blockbuffer, 0); - if (result) - return result; - - /* check old contents and fill lba */ - for (i = 0; i < info->blocksize; i++) { - bptr = blockbuffer + i*pagelen; - cptr = bptr + info->pagesize; - nand_compute_ecc(bptr, ecc); - if (!nand_compare_ecc(cptr+13, ecc)) { - US_DEBUGP("Warning: bad ecc in page %d- of pba %d\n", - i, pba); - nand_store_ecc(cptr+13, ecc); - } - nand_compute_ecc(bptr+(info->pagesize / 2), ecc); - if (!nand_compare_ecc(cptr+8, ecc)) { - US_DEBUGP("Warning: bad ecc in page %d+ of pba %d\n", - i, pba); - nand_store_ecc(cptr+8, ecc); - } - cptr[6] = cptr[11] = MSB_of(lbap); - cptr[7] = cptr[12] = LSB_of(lbap); - } - - /* copy in new stuff and compute ECC */ - xptr = ptr; - for (i = page; i < page+pages; i++) { - bptr = blockbuffer + i*pagelen; - cptr = bptr + info->pagesize; - memcpy(bptr, xptr, info->pagesize); - xptr += info->pagesize; - nand_compute_ecc(bptr, ecc); - nand_store_ecc(cptr+13, ecc); - nand_compute_ecc(bptr+(info->pagesize / 2), ecc); - nand_store_ecc(cptr+8, ecc); - } - - US_DEBUGP("Rewrite PBA %d (LBA %d)\n", pba, lba); - - result = sddr09_write_inplace(us, address>>1, info->blocksize, - info->pageshift, blockbuffer, 0); - - US_DEBUGP("sddr09_write_inplace returns %d\n", result); - -#if 0 - { - unsigned char status = 0; - int result2 = sddr09_read_status(us, &status); - if (result2) - US_DEBUGP("sddr09_write_inplace: cannot read status\n"); - else if (status != 0xc0) - US_DEBUGP("sddr09_write_inplace: status after write: 0x%x\n", - status); - } -#endif - -#if 0 - { - int result2 = sddr09_test_unit_ready(us); - } -#endif - - return result; -} - -static int -sddr09_write_data(struct us_data *us, - unsigned long address, - unsigned int sectors) { - - struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra; - unsigned int lba, maxlba, page, pages; - unsigned int pagelen, blocklen; - unsigned char *blockbuffer; - unsigned char *buffer; - unsigned int len, offset; - struct scatterlist *sg; - int result; - - // Figure out the initial LBA and page - lba = address >> info->blockshift; - page = (address & info->blockmask); - maxlba = info->capacity >> (info->pageshift + info->blockshift); - if (lba >= maxlba) - return -EIO; - - // blockbuffer is used for reading in the old data, overwriting - // with the new data, and performing ECC calculations - - /* TODO: instead of doing kmalloc/kfree for each write, - add a bufferpointer to the info structure */ - - pagelen = (1 << info->pageshift) + (1 << CONTROL_SHIFT); - blocklen = (pagelen << info->blockshift); - blockbuffer = kmalloc(blocklen, GFP_NOIO); - if (!blockbuffer) { - printk(KERN_WARNING "sddr09_write_data: Out of memory\n"); - return -ENOMEM; - } - - // Since we don't write the user data directly to the device, - // we have to create a bounce buffer and move the data a piece - // at a time between the bounce buffer and the actual transfer buffer. - - len = min(sectors, (unsigned int) info->blocksize) * info->pagesize; - buffer = kmalloc(len, GFP_NOIO); - if (buffer == NULL) { - printk(KERN_WARNING "sddr09_write_data: Out of memory\n"); - kfree(blockbuffer); - return -ENOMEM; - } - - result = 0; - offset = 0; - sg = NULL; - - while (sectors > 0) { - - // Write as many sectors as possible in this block - - pages = min(sectors, info->blocksize - page); - len = (pages << info->pageshift); - - /* Not overflowing capacity? */ - if (lba >= maxlba) { - US_DEBUGP("Error: Requested lba %u exceeds " - "maximum %u\n", lba, maxlba); - result = -EIO; - break; - } - - // Get the data from the transfer buffer - usb_stor_access_xfer_buf(buffer, len, us->srb, - &sg, &offset, FROM_XFER_BUF); - - result = sddr09_write_lba(us, lba, page, pages, - buffer, blockbuffer); - if (result) - break; - - page = 0; - lba++; - sectors -= pages; - } - - kfree(buffer); - kfree(blockbuffer); - - return result; -} - -static int -sddr09_read_control(struct us_data *us, - unsigned long address, - unsigned int blocks, - unsigned char *content, - int use_sg) { - - US_DEBUGP("Read control address %lu, blocks %d\n", - address, blocks); - - return sddr09_read21(us, address, blocks, - CONTROL_SHIFT, content, use_sg); -} - -/* - * Read Device ID Command: 12 bytes. - * byte 0: opcode: ED - * - * Returns 2 bytes: Manufacturer ID and Device ID. - * On more recent cards 3 bytes: the third byte is an option code A5 - * signifying that the secret command to read an 128-bit ID is available. - * On still more recent cards 4 bytes: the fourth byte C0 means that - * a second read ID cmd is available. - */ -static int -sddr09_read_deviceID(struct us_data *us, unsigned char *deviceID) { - unsigned char *command = us->iobuf; - unsigned char *content = us->iobuf; - int result, i; - - memset(command, 0, 12); - command[0] = 0xED; - command[1] = LUNBITS; - - result = sddr09_send_scsi_command(us, command, 12); - if (result) - return result; - - result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, - content, 64, NULL); - - for (i = 0; i < 4; i++) - deviceID[i] = content[i]; - - return (result == USB_STOR_XFER_GOOD ? 0 : -EIO); -} - -static int -sddr09_get_wp(struct us_data *us, struct sddr09_card_info *info) { - int result; - unsigned char status; - - result = sddr09_read_status(us, &status); - if (result) { - US_DEBUGP("sddr09_get_wp: read_status fails\n"); - return result; - } - US_DEBUGP("sddr09_get_wp: status 0x%02X", status); - if ((status & 0x80) == 0) { - info->flags |= SDDR09_WP; /* write protected */ - US_DEBUGP(" WP"); - } - if (status & 0x40) - US_DEBUGP(" Ready"); - if (status & LUNBITS) - US_DEBUGP(" Suspended"); - if (status & 0x1) - US_DEBUGP(" Error"); - US_DEBUGP("\n"); - return 0; -} - -#if 0 -/* - * Reset Command: 12 bytes. - * byte 0: opcode: EB - */ -static int -sddr09_reset(struct us_data *us) { - - unsigned char *command = us->iobuf; - - memset(command, 0, 12); - command[0] = 0xEB; - command[1] = LUNBITS; - - return sddr09_send_scsi_command(us, command, 12); -} -#endif - -static struct nand_flash_dev * -sddr09_get_cardinfo(struct us_data *us, unsigned char flags) { - struct nand_flash_dev *cardinfo; - unsigned char deviceID[4]; - char blurbtxt[256]; - int result; - - US_DEBUGP("Reading capacity...\n"); - - result = sddr09_read_deviceID(us, deviceID); - - if (result) { - US_DEBUGP("Result of read_deviceID is %d\n", result); - printk(KERN_WARNING "sddr09: could not read card info\n"); - return NULL; - } - - sprintf(blurbtxt, "sddr09: Found Flash card, ID = %02X %02X %02X %02X", - deviceID[0], deviceID[1], deviceID[2], deviceID[3]); - - /* Byte 0 is the manufacturer */ - sprintf(blurbtxt + strlen(blurbtxt), - ": Manuf. %s", - nand_flash_manufacturer(deviceID[0])); - - /* Byte 1 is the device type */ - cardinfo = nand_find_id(deviceID[1]); - if (cardinfo) { - /* MB or MiB? It is neither. A 16 MB card has - 17301504 raw bytes, of which 16384000 are - usable for user data. */ - sprintf(blurbtxt + strlen(blurbtxt), - ", %d MB", 1<<(cardinfo->chipshift - 20)); - } else { - sprintf(blurbtxt + strlen(blurbtxt), - ", type unrecognized"); - } - - /* Byte 2 is code to signal availability of 128-bit ID */ - if (deviceID[2] == 0xa5) { - sprintf(blurbtxt + strlen(blurbtxt), - ", 128-bit ID"); - } - - /* Byte 3 announces the availability of another read ID command */ - if (deviceID[3] == 0xc0) { - sprintf(blurbtxt + strlen(blurbtxt), - ", extra cmd"); - } - - if (flags & SDDR09_WP) - sprintf(blurbtxt + strlen(blurbtxt), - ", WP"); - - printk(KERN_WARNING "%s\n", blurbtxt); - - return cardinfo; -} - -static int -sddr09_read_map(struct us_data *us) { - - struct sddr09_card_info *info = (struct sddr09_card_info *) us->extra; - int numblocks, alloc_len, alloc_blocks; - int i, j, result; - unsigned char *buffer, *buffer_end, *ptr; - unsigned int lba, lbact; - - if (!info->capacity) - return -1; - - // size of a block is 1 << (blockshift + pageshift) bytes - // divide into the total capacity to get the number of blocks - - numblocks = info->capacity >> (info->blockshift + info->pageshift); - - // read 64 bytes for every block (actually 1 << CONTROL_SHIFT) - // but only use a 64 KB buffer - // buffer size used must be a multiple of (1 << CONTROL_SHIFT) -#define SDDR09_READ_MAP_BUFSZ 65536 - - alloc_blocks = min(numblocks, SDDR09_READ_MAP_BUFSZ >> CONTROL_SHIFT); - alloc_len = (alloc_blocks << CONTROL_SHIFT); - buffer = kmalloc(alloc_len, GFP_NOIO); - if (buffer == NULL) { - printk(KERN_WARNING "sddr09_read_map: out of memory\n"); - result = -1; - goto done; - } - buffer_end = buffer + alloc_len; - -#undef SDDR09_READ_MAP_BUFSZ - - kfree(info->lba_to_pba); - kfree(info->pba_to_lba); - info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_NOIO); - info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_NOIO); - - if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) { - printk(KERN_WARNING "sddr09_read_map: out of memory\n"); - result = -1; - goto done; - } - - for (i = 0; i < numblocks; i++) - info->lba_to_pba[i] = info->pba_to_lba[i] = UNDEF; - - /* - * Define lba-pba translation table - */ - - ptr = buffer_end; - for (i = 0; i < numblocks; i++) { - ptr += (1 << CONTROL_SHIFT); - if (ptr >= buffer_end) { - unsigned long address; - - address = i << (info->pageshift + info->blockshift); - result = sddr09_read_control( - us, address>>1, - min(alloc_blocks, numblocks - i), - buffer, 0); - if (result) { - result = -1; - goto done; - } - ptr = buffer; - } - - if (i == 0 || i == 1) { - info->pba_to_lba[i] = UNUSABLE; - continue; - } - - /* special PBAs have control field 0^16 */ - for (j = 0; j < 16; j++) - if (ptr[j] != 0) - goto nonz; - info->pba_to_lba[i] = UNUSABLE; - printk(KERN_WARNING "sddr09: PBA %d has no logical mapping\n", - i); - continue; - - nonz: - /* unwritten PBAs have control field FF^16 */ - for (j = 0; j < 16; j++) - if (ptr[j] != 0xff) - goto nonff; - continue; - - nonff: - /* normal PBAs start with six FFs */ - if (j < 6) { - printk(KERN_WARNING - "sddr09: PBA %d has no logical mapping: " - "reserved area = %02X%02X%02X%02X " - "data status %02X block status %02X\n", - i, ptr[0], ptr[1], ptr[2], ptr[3], - ptr[4], ptr[5]); - info->pba_to_lba[i] = UNUSABLE; - continue; - } - - if ((ptr[6] >> 4) != 0x01) { - printk(KERN_WARNING - "sddr09: PBA %d has invalid address field " - "%02X%02X/%02X%02X\n", - i, ptr[6], ptr[7], ptr[11], ptr[12]); - info->pba_to_lba[i] = UNUSABLE; - continue; - } - - /* check even parity */ - if (parity[ptr[6] ^ ptr[7]]) { - printk(KERN_WARNING - "sddr09: Bad parity in LBA for block %d" - " (%02X %02X)\n", i, ptr[6], ptr[7]); - info->pba_to_lba[i] = UNUSABLE; - continue; - } - - lba = short_pack(ptr[7], ptr[6]); - lba = (lba & 0x07FF) >> 1; - - /* - * Every 1024 physical blocks ("zone"), the LBA numbers - * go back to zero, but are within a higher block of LBA's. - * Also, there is a maximum of 1000 LBA's per zone. - * In other words, in PBA 1024-2047 you will find LBA 0-999 - * which are really LBA 1000-1999. This allows for 24 bad - * or special physical blocks per zone. - */ - - if (lba >= 1000) { - printk(KERN_WARNING - "sddr09: Bad low LBA %d for block %d\n", - lba, i); - goto possibly_erase; - } - - lba += 1000*(i/0x400); - - if (info->lba_to_pba[lba] != UNDEF) { - printk(KERN_WARNING - "sddr09: LBA %d seen for PBA %d and %d\n", - lba, info->lba_to_pba[lba], i); - goto possibly_erase; - } - - info->pba_to_lba[i] = lba; - info->lba_to_pba[lba] = i; - continue; - - possibly_erase: - if (erase_bad_lba_entries) { - unsigned long address; - - address = (i << (info->pageshift + info->blockshift)); - sddr09_erase(us, address>>1); - info->pba_to_lba[i] = UNDEF; - } else - info->pba_to_lba[i] = UNUSABLE; - } - - /* - * Approximate capacity. This is not entirely correct yet, - * since a zone with less than 1000 usable pages leads to - * missing LBAs. Especially if it is the last zone, some - * LBAs can be past capacity. - */ - lbact = 0; - for (i = 0; i < numblocks; i += 1024) { - int ct = 0; - - for (j = 0; j < 1024 && i+j < numblocks; j++) { - if (info->pba_to_lba[i+j] != UNUSABLE) { - if (ct >= 1000) - info->pba_to_lba[i+j] = SPARE; - else - ct++; - } - } - lbact += ct; - } - info->lbact = lbact; - US_DEBUGP("Found %d LBA's\n", lbact); - result = 0; - - done: - if (result != 0) { - kfree(info->lba_to_pba); - kfree(info->pba_to_lba); - info->lba_to_pba = NULL; - info->pba_to_lba = NULL; - } - kfree(buffer); - return result; -} - -static void -sddr09_card_info_destructor(void *extra) { - struct sddr09_card_info *info = (struct sddr09_card_info *)extra; - - if (!info) - return; - - kfree(info->lba_to_pba); - kfree(info->pba_to_lba); -} - -static int -sddr09_common_init(struct us_data *us) { - int result; - - /* set the configuration -- STALL is an acceptable response here */ - if (us->pusb_dev->actconfig->desc.bConfigurationValue != 1) { - US_DEBUGP("active config #%d != 1 ??\n", us->pusb_dev - ->actconfig->desc.bConfigurationValue); - return -EINVAL; - } - - result = usb_reset_configuration(us->pusb_dev); - US_DEBUGP("Result of usb_reset_configuration is %d\n", result); - if (result == -EPIPE) { - US_DEBUGP("-- stall on control interface\n"); - } else if (result != 0) { - /* it's not a stall, but another error -- time to bail */ - US_DEBUGP("-- Unknown error. Rejecting device\n"); - return -EINVAL; - } - - us->extra = kzalloc(sizeof(struct sddr09_card_info), GFP_NOIO); - if (!us->extra) - return -ENOMEM; - us->extra_destructor = sddr09_card_info_destructor; - - nand_init_ecc(); - return 0; -} - - -/* - * This is needed at a very early stage. If this is not listed in the - * unusual devices list but called from here then LUN 0 of the combo reader - * is not recognized. But I do not know what precisely these calls do. - */ -static int -usb_stor_sddr09_dpcm_init(struct us_data *us) { - int result; - unsigned char *data = us->iobuf; - - result = sddr09_common_init(us); - if (result) - return result; - - result = sddr09_send_command(us, 0x01, USB_DIR_IN, data, 2); - if (result) { - US_DEBUGP("sddr09_init: send_command fails\n"); - return result; - } - - US_DEBUGP("SDDR09init: %02X %02X\n", data[0], data[1]); - // get 07 02 - - result = sddr09_send_command(us, 0x08, USB_DIR_IN, data, 2); - if (result) { - US_DEBUGP("sddr09_init: 2nd send_command fails\n"); - return result; - } - - US_DEBUGP("SDDR09init: %02X %02X\n", data[0], data[1]); - // get 07 00 - - result = sddr09_request_sense(us, data, 18); - if (result == 0 && data[2] != 0) { - int j; - for (j=0; j<18; j++) - printk(" %02X", data[j]); - printk("\n"); - // get 70 00 00 00 00 00 00 * 00 00 00 00 00 00 - // 70: current command - // sense key 0, sense code 0, extd sense code 0 - // additional transfer length * = sizeof(data) - 7 - // Or: 70 00 06 00 00 00 00 0b 00 00 00 00 28 00 00 00 00 00 - // sense key 06, sense code 28: unit attention, - // not ready to ready transition - } - - // test unit ready - - return 0; /* not result */ -} - -/* - * Transport for the Microtech DPCM-USB - */ -static int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us) -{ - int ret; - - US_DEBUGP("dpcm_transport: LUN=%d\n", srb->device->lun); - - switch (srb->device->lun) { - case 0: - - /* - * LUN 0 corresponds to the CompactFlash card reader. - */ - ret = usb_stor_CB_transport(srb, us); - break; - - case 1: - - /* - * LUN 1 corresponds to the SmartMedia card reader. - */ - - /* - * Set the LUN to 0 (just in case). - */ - srb->device->lun = 0; - ret = sddr09_transport(srb, us); - srb->device->lun = 1; - break; - - default: - US_DEBUGP("dpcm_transport: Invalid LUN %d\n", - srb->device->lun); - ret = USB_STOR_TRANSPORT_ERROR; - break; - } - return ret; -} - - -/* - * Transport for the Sandisk SDDR-09 - */ -static int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us) -{ - static unsigned char sensekey = 0, sensecode = 0; - static unsigned char havefakesense = 0; - int result, i; - unsigned char *ptr = us->iobuf; - unsigned long capacity; - unsigned int page, pages; - - struct sddr09_card_info *info; - - static unsigned char inquiry_response[8] = { - 0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00 - }; - - /* note: no block descriptor support */ - static unsigned char mode_page_01[19] = { - 0x00, 0x0F, 0x00, 0x0, 0x0, 0x0, 0x00, - 0x01, 0x0A, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - - info = (struct sddr09_card_info *)us->extra; - - if (srb->cmnd[0] == REQUEST_SENSE && havefakesense) { - /* for a faked command, we have to follow with a faked sense */ - memset(ptr, 0, 18); - ptr[0] = 0x70; - ptr[2] = sensekey; - ptr[7] = 11; - ptr[12] = sensecode; - usb_stor_set_xfer_buf(ptr, 18, srb); - sensekey = sensecode = havefakesense = 0; - return USB_STOR_TRANSPORT_GOOD; - } - - havefakesense = 1; - - /* Dummy up a response for INQUIRY since SDDR09 doesn't - respond to INQUIRY commands */ - - if (srb->cmnd[0] == INQUIRY) { - memcpy(ptr, inquiry_response, 8); - fill_inquiry_response(us, ptr, 36); - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == READ_CAPACITY) { - struct nand_flash_dev *cardinfo; - - sddr09_get_wp(us, info); /* read WP bit */ - - cardinfo = sddr09_get_cardinfo(us, info->flags); - if (!cardinfo) { - /* probably no media */ - init_error: - sensekey = 0x02; /* not ready */ - sensecode = 0x3a; /* medium not present */ - return USB_STOR_TRANSPORT_FAILED; - } - - info->capacity = (1 << cardinfo->chipshift); - info->pageshift = cardinfo->pageshift; - info->pagesize = (1 << info->pageshift); - info->blockshift = cardinfo->blockshift; - info->blocksize = (1 << info->blockshift); - info->blockmask = info->blocksize - 1; - - // map initialization, must follow get_cardinfo() - if (sddr09_read_map(us)) { - /* probably out of memory */ - goto init_error; - } - - // Report capacity - - capacity = (info->lbact << info->blockshift) - 1; - - ((__be32 *) ptr)[0] = cpu_to_be32(capacity); - - // Report page size - - ((__be32 *) ptr)[1] = cpu_to_be32(info->pagesize); - usb_stor_set_xfer_buf(ptr, 8, srb); - - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == MODE_SENSE_10) { - int modepage = (srb->cmnd[2] & 0x3F); - - /* They ask for the Read/Write error recovery page, - or for all pages. */ - /* %% We should check DBD %% */ - if (modepage == 0x01 || modepage == 0x3F) { - US_DEBUGP("SDDR09: Dummy up request for " - "mode page 0x%x\n", modepage); - - memcpy(ptr, mode_page_01, sizeof(mode_page_01)); - ((__be16*)ptr)[0] = cpu_to_be16(sizeof(mode_page_01) - 2); - ptr[3] = (info->flags & SDDR09_WP) ? 0x80 : 0; - usb_stor_set_xfer_buf(ptr, sizeof(mode_page_01), srb); - return USB_STOR_TRANSPORT_GOOD; - } - - sensekey = 0x05; /* illegal request */ - sensecode = 0x24; /* invalid field in CDB */ - return USB_STOR_TRANSPORT_FAILED; - } - - if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) - return USB_STOR_TRANSPORT_GOOD; - - havefakesense = 0; - - if (srb->cmnd[0] == READ_10) { - - page = short_pack(srb->cmnd[3], srb->cmnd[2]); - page <<= 16; - page |= short_pack(srb->cmnd[5], srb->cmnd[4]); - pages = short_pack(srb->cmnd[8], srb->cmnd[7]); - - US_DEBUGP("READ_10: read page %d pagect %d\n", - page, pages); - - result = sddr09_read_data(us, page, pages); - return (result == 0 ? USB_STOR_TRANSPORT_GOOD : - USB_STOR_TRANSPORT_ERROR); - } - - if (srb->cmnd[0] == WRITE_10) { - - page = short_pack(srb->cmnd[3], srb->cmnd[2]); - page <<= 16; - page |= short_pack(srb->cmnd[5], srb->cmnd[4]); - pages = short_pack(srb->cmnd[8], srb->cmnd[7]); - - US_DEBUGP("WRITE_10: write page %d pagect %d\n", - page, pages); - - result = sddr09_write_data(us, page, pages); - return (result == 0 ? USB_STOR_TRANSPORT_GOOD : - USB_STOR_TRANSPORT_ERROR); - } - - /* catch-all for all other commands, except - * pass TEST_UNIT_READY and REQUEST_SENSE through - */ - if (srb->cmnd[0] != TEST_UNIT_READY && - srb->cmnd[0] != REQUEST_SENSE) { - sensekey = 0x05; /* illegal request */ - sensecode = 0x20; /* invalid command */ - havefakesense = 1; - return USB_STOR_TRANSPORT_FAILED; - } - - for (; srb->cmd_len<12; srb->cmd_len++) - srb->cmnd[srb->cmd_len] = 0; - - srb->cmnd[1] = LUNBITS; - - ptr[0] = 0; - for (i=0; i<12; i++) - sprintf(ptr+strlen(ptr), "%02X ", srb->cmnd[i]); - - US_DEBUGP("SDDR09: Send control for command %s\n", ptr); - - result = sddr09_send_scsi_command(us, srb->cmnd, 12); - if (result) { - US_DEBUGP("sddr09_transport: sddr09_send_scsi_command " - "returns %d\n", result); - return USB_STOR_TRANSPORT_ERROR; - } - - if (scsi_bufflen(srb) == 0) - return USB_STOR_TRANSPORT_GOOD; - - if (srb->sc_data_direction == DMA_TO_DEVICE || - srb->sc_data_direction == DMA_FROM_DEVICE) { - unsigned int pipe = (srb->sc_data_direction == DMA_TO_DEVICE) - ? us->send_bulk_pipe : us->recv_bulk_pipe; - - US_DEBUGP("SDDR09: %s %d bytes\n", - (srb->sc_data_direction == DMA_TO_DEVICE) ? - "sending" : "receiving", - scsi_bufflen(srb)); - - result = usb_stor_bulk_srb(us, pipe, srb); - - return (result == USB_STOR_XFER_GOOD ? - USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); - } - - return USB_STOR_TRANSPORT_GOOD; -} - -/* - * Initialization routine for the sddr09 subdriver - */ -static int -usb_stor_sddr09_init(struct us_data *us) { - return sddr09_common_init(us); -} - -static int sddr09_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct us_data *us; - int result; - - result = usb_stor_probe1(&us, intf, id, - (id - sddr09_usb_ids) + sddr09_unusual_dev_list); - if (result) - return result; - - if (us->protocol == USB_PR_DPCM_USB) { - us->transport_name = "Control/Bulk-EUSB/SDDR09"; - us->transport = dpcm_transport; - us->transport_reset = usb_stor_CB_reset; - us->max_lun = 1; - } else { - us->transport_name = "EUSB/SDDR09"; - us->transport = sddr09_transport; - us->transport_reset = usb_stor_CB_reset; - us->max_lun = 0; - } - - result = usb_stor_probe2(us); - return result; -} - -static struct usb_driver sddr09_driver = { - .name = "ums-sddr09", - .probe = sddr09_probe, - .disconnect = usb_stor_disconnect, - .suspend = usb_stor_suspend, - .resume = usb_stor_resume, - .reset_resume = usb_stor_reset_resume, - .pre_reset = usb_stor_pre_reset, - .post_reset = usb_stor_post_reset, - .id_table = sddr09_usb_ids, - .soft_unbind = 1, - .no_dynamic_id = 1, -}; - -module_usb_driver(sddr09_driver); diff --git a/ANDROID_3.4.5/drivers/usb/storage/sddr55.c b/ANDROID_3.4.5/drivers/usb/storage/sddr55.c deleted file mode 100644 index c1440780..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/sddr55.c +++ /dev/null @@ -1,1012 +0,0 @@ -/* Driver for SanDisk SDDR-55 SmartMedia reader - * - * SDDR55 driver v0.1: - * - * First release - * - * Current development and maintenance by: - * (c) 2002 Simon Munton - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -#include -#include - -#include "usb.h" -#include "transport.h" -#include "protocol.h" -#include "debug.h" - -MODULE_DESCRIPTION("Driver for SanDisk SDDR-55 SmartMedia reader"); -MODULE_AUTHOR("Simon Munton"); -MODULE_LICENSE("GPL"); - -/* - * The table of devices - */ -#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ - vendorName, productName, useProtocol, useTransport, \ - initFunction, flags) \ -{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } - -static struct usb_device_id sddr55_usb_ids[] = { -# include "unusual_sddr55.h" - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, sddr55_usb_ids); - -#undef UNUSUAL_DEV - -/* - * The flags table - */ -#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ - vendor_name, product_name, use_protocol, use_transport, \ - init_function, Flags) \ -{ \ - .vendorName = vendor_name, \ - .productName = product_name, \ - .useProtocol = use_protocol, \ - .useTransport = use_transport, \ - .initFunction = init_function, \ -} - -static struct us_unusual_dev sddr55_unusual_dev_list[] = { -# include "unusual_sddr55.h" - { } /* Terminating entry */ -}; - -#undef UNUSUAL_DEV - - -#define short_pack(lsb,msb) ( ((u16)(lsb)) | ( ((u16)(msb))<<8 ) ) -#define LSB_of(s) ((s)&0xFF) -#define MSB_of(s) ((s)>>8) -#define PAGESIZE 512 - -#define set_sense_info(sk, asc, ascq) \ - do { \ - info->sense_data[2] = sk; \ - info->sense_data[12] = asc; \ - info->sense_data[13] = ascq; \ - } while (0) - - -struct sddr55_card_info { - unsigned long capacity; /* Size of card in bytes */ - int max_log_blks; /* maximum number of logical blocks */ - int pageshift; /* log2 of pagesize */ - int smallpageshift; /* 1 if pagesize == 256 */ - int blocksize; /* Size of block in pages */ - int blockshift; /* log2 of blocksize */ - int blockmask; /* 2^blockshift - 1 */ - int read_only; /* non zero if card is write protected */ - int force_read_only; /* non zero if we find a map error*/ - int *lba_to_pba; /* logical to physical map */ - int *pba_to_lba; /* physical to logical map */ - int fatal_error; /* set if we detect something nasty */ - unsigned long last_access; /* number of jiffies since we last talked to device */ - unsigned char sense_data[18]; -}; - - -#define NOT_ALLOCATED 0xffffffff -#define BAD_BLOCK 0xffff -#define CIS_BLOCK 0x400 -#define UNUSED_BLOCK 0x3ff - -static int -sddr55_bulk_transport(struct us_data *us, int direction, - unsigned char *data, unsigned int len) { - struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra; - unsigned int pipe = (direction == DMA_FROM_DEVICE) ? - us->recv_bulk_pipe : us->send_bulk_pipe; - - if (!len) - return USB_STOR_XFER_GOOD; - info->last_access = jiffies; - return usb_stor_bulk_transfer_buf(us, pipe, data, len, NULL); -} - -/* check if card inserted, if there is, update read_only status - * return non zero if no card - */ - -static int sddr55_status(struct us_data *us) -{ - int result; - unsigned char *command = us->iobuf; - unsigned char *status = us->iobuf; - struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra; - - /* send command */ - memset(command, 0, 8); - command[5] = 0xB0; - command[7] = 0x80; - result = sddr55_bulk_transport(us, - DMA_TO_DEVICE, command, 8); - - US_DEBUGP("Result for send_command in status %d\n", - result); - - if (result != USB_STOR_XFER_GOOD) { - set_sense_info (4, 0, 0); /* hardware error */ - return USB_STOR_TRANSPORT_ERROR; - } - - result = sddr55_bulk_transport(us, - DMA_FROM_DEVICE, status, 4); - - /* expect to get short transfer if no card fitted */ - if (result == USB_STOR_XFER_SHORT || result == USB_STOR_XFER_STALLED) { - /* had a short transfer, no card inserted, free map memory */ - kfree(info->lba_to_pba); - kfree(info->pba_to_lba); - info->lba_to_pba = NULL; - info->pba_to_lba = NULL; - - info->fatal_error = 0; - info->force_read_only = 0; - - set_sense_info (2, 0x3a, 0); /* not ready, medium not present */ - return USB_STOR_TRANSPORT_FAILED; - } - - if (result != USB_STOR_XFER_GOOD) { - set_sense_info (4, 0, 0); /* hardware error */ - return USB_STOR_TRANSPORT_FAILED; - } - - /* check write protect status */ - info->read_only = (status[0] & 0x20); - - /* now read status */ - result = sddr55_bulk_transport(us, - DMA_FROM_DEVICE, status, 2); - - if (result != USB_STOR_XFER_GOOD) { - set_sense_info (4, 0, 0); /* hardware error */ - } - - return (result == USB_STOR_XFER_GOOD ? - USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_FAILED); -} - - -static int sddr55_read_data(struct us_data *us, - unsigned int lba, - unsigned int page, - unsigned short sectors) { - - int result = USB_STOR_TRANSPORT_GOOD; - unsigned char *command = us->iobuf; - unsigned char *status = us->iobuf; - struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra; - unsigned char *buffer; - - unsigned int pba; - unsigned long address; - - unsigned short pages; - unsigned int len, offset; - struct scatterlist *sg; - - // Since we only read in one block at a time, we have to create - // a bounce buffer and move the data a piece at a time between the - // bounce buffer and the actual transfer buffer. - - len = min((unsigned int) sectors, (unsigned int) info->blocksize >> - info->smallpageshift) * PAGESIZE; - buffer = kmalloc(len, GFP_NOIO); - if (buffer == NULL) - return USB_STOR_TRANSPORT_ERROR; /* out of memory */ - offset = 0; - sg = NULL; - - while (sectors>0) { - - /* have we got to end? */ - if (lba >= info->max_log_blks) - break; - - pba = info->lba_to_pba[lba]; - - // Read as many sectors as possible in this block - - pages = min((unsigned int) sectors << info->smallpageshift, - info->blocksize - page); - len = pages << info->pageshift; - - US_DEBUGP("Read %02X pages, from PBA %04X" - " (LBA %04X) page %02X\n", - pages, pba, lba, page); - - if (pba == NOT_ALLOCATED) { - /* no pba for this lba, fill with zeroes */ - memset (buffer, 0, len); - } else { - - address = (pba << info->blockshift) + page; - - command[0] = 0; - command[1] = LSB_of(address>>16); - command[2] = LSB_of(address>>8); - command[3] = LSB_of(address); - - command[4] = 0; - command[5] = 0xB0; - command[6] = LSB_of(pages << (1 - info->smallpageshift)); - command[7] = 0x85; - - /* send command */ - result = sddr55_bulk_transport(us, - DMA_TO_DEVICE, command, 8); - - US_DEBUGP("Result for send_command in read_data %d\n", - result); - - if (result != USB_STOR_XFER_GOOD) { - result = USB_STOR_TRANSPORT_ERROR; - goto leave; - } - - /* read data */ - result = sddr55_bulk_transport(us, - DMA_FROM_DEVICE, buffer, len); - - if (result != USB_STOR_XFER_GOOD) { - result = USB_STOR_TRANSPORT_ERROR; - goto leave; - } - - /* now read status */ - result = sddr55_bulk_transport(us, - DMA_FROM_DEVICE, status, 2); - - if (result != USB_STOR_XFER_GOOD) { - result = USB_STOR_TRANSPORT_ERROR; - goto leave; - } - - /* check status for error */ - if (status[0] == 0xff && status[1] == 0x4) { - set_sense_info (3, 0x11, 0); - result = USB_STOR_TRANSPORT_FAILED; - goto leave; - } - } - - // Store the data in the transfer buffer - usb_stor_access_xfer_buf(buffer, len, us->srb, - &sg, &offset, TO_XFER_BUF); - - page = 0; - lba++; - sectors -= pages >> info->smallpageshift; - } - - result = USB_STOR_TRANSPORT_GOOD; - -leave: - kfree(buffer); - - return result; -} - -static int sddr55_write_data(struct us_data *us, - unsigned int lba, - unsigned int page, - unsigned short sectors) { - - int result = USB_STOR_TRANSPORT_GOOD; - unsigned char *command = us->iobuf; - unsigned char *status = us->iobuf; - struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra; - unsigned char *buffer; - - unsigned int pba; - unsigned int new_pba; - unsigned long address; - - unsigned short pages; - int i; - unsigned int len, offset; - struct scatterlist *sg; - - /* check if we are allowed to write */ - if (info->read_only || info->force_read_only) { - set_sense_info (7, 0x27, 0); /* read only */ - return USB_STOR_TRANSPORT_FAILED; - } - - // Since we only write one block at a time, we have to create - // a bounce buffer and move the data a piece at a time between the - // bounce buffer and the actual transfer buffer. - - len = min((unsigned int) sectors, (unsigned int) info->blocksize >> - info->smallpageshift) * PAGESIZE; - buffer = kmalloc(len, GFP_NOIO); - if (buffer == NULL) - return USB_STOR_TRANSPORT_ERROR; - offset = 0; - sg = NULL; - - while (sectors > 0) { - - /* have we got to end? */ - if (lba >= info->max_log_blks) - break; - - pba = info->lba_to_pba[lba]; - - // Write as many sectors as possible in this block - - pages = min((unsigned int) sectors << info->smallpageshift, - info->blocksize - page); - len = pages << info->pageshift; - - // Get the data from the transfer buffer - usb_stor_access_xfer_buf(buffer, len, us->srb, - &sg, &offset, FROM_XFER_BUF); - - US_DEBUGP("Write %02X pages, to PBA %04X" - " (LBA %04X) page %02X\n", - pages, pba, lba, page); - - command[4] = 0; - - if (pba == NOT_ALLOCATED) { - /* no pba allocated for this lba, find a free pba to use */ - - int max_pba = (info->max_log_blks / 250 ) * 256; - int found_count = 0; - int found_pba = -1; - - /* set pba to first block in zone lba is in */ - pba = (lba / 1000) * 1024; - - US_DEBUGP("No PBA for LBA %04X\n",lba); - - if (max_pba > 1024) - max_pba = 1024; - - /* - * Scan through the map looking for an unused block - * leave 16 unused blocks at start (or as many as - * possible) since the sddr55 seems to reuse a used - * block when it shouldn't if we don't leave space. - */ - for (i = 0; i < max_pba; i++, pba++) { - if (info->pba_to_lba[pba] == UNUSED_BLOCK) { - found_pba = pba; - if (found_count++ > 16) - break; - } - } - - pba = found_pba; - - if (pba == -1) { - /* oh dear */ - US_DEBUGP("Couldn't find unallocated block\n"); - - set_sense_info (3, 0x31, 0); /* medium error */ - result = USB_STOR_TRANSPORT_FAILED; - goto leave; - } - - US_DEBUGP("Allocating PBA %04X for LBA %04X\n", pba, lba); - - /* set writing to unallocated block flag */ - command[4] = 0x40; - } - - address = (pba << info->blockshift) + page; - - command[1] = LSB_of(address>>16); - command[2] = LSB_of(address>>8); - command[3] = LSB_of(address); - - /* set the lba into the command, modulo 1000 */ - command[0] = LSB_of(lba % 1000); - command[6] = MSB_of(lba % 1000); - - command[4] |= LSB_of(pages >> info->smallpageshift); - command[5] = 0xB0; - command[7] = 0x86; - - /* send command */ - result = sddr55_bulk_transport(us, - DMA_TO_DEVICE, command, 8); - - if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Result for send_command in write_data %d\n", - result); - - /* set_sense_info is superfluous here? */ - set_sense_info (3, 0x3, 0);/* peripheral write error */ - result = USB_STOR_TRANSPORT_FAILED; - goto leave; - } - - /* send the data */ - result = sddr55_bulk_transport(us, - DMA_TO_DEVICE, buffer, len); - - if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Result for send_data in write_data %d\n", - result); - - /* set_sense_info is superfluous here? */ - set_sense_info (3, 0x3, 0);/* peripheral write error */ - result = USB_STOR_TRANSPORT_FAILED; - goto leave; - } - - /* now read status */ - result = sddr55_bulk_transport(us, DMA_FROM_DEVICE, status, 6); - - if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Result for get_status in write_data %d\n", - result); - - /* set_sense_info is superfluous here? */ - set_sense_info (3, 0x3, 0);/* peripheral write error */ - result = USB_STOR_TRANSPORT_FAILED; - goto leave; - } - - new_pba = (status[3] + (status[4] << 8) + (status[5] << 16)) - >> info->blockshift; - - /* check status for error */ - if (status[0] == 0xff && status[1] == 0x4) { - info->pba_to_lba[new_pba] = BAD_BLOCK; - - set_sense_info (3, 0x0c, 0); - result = USB_STOR_TRANSPORT_FAILED; - goto leave; - } - - US_DEBUGP("Updating maps for LBA %04X: old PBA %04X, new PBA %04X\n", - lba, pba, new_pba); - - /* update the lba<->pba maps, note new_pba might be the same as pba */ - info->lba_to_pba[lba] = new_pba; - info->pba_to_lba[pba] = UNUSED_BLOCK; - - /* check that new_pba wasn't already being used */ - if (info->pba_to_lba[new_pba] != UNUSED_BLOCK) { - printk(KERN_ERR "sddr55 error: new PBA %04X already in use for LBA %04X\n", - new_pba, info->pba_to_lba[new_pba]); - info->fatal_error = 1; - set_sense_info (3, 0x31, 0); - result = USB_STOR_TRANSPORT_FAILED; - goto leave; - } - - /* update the pba<->lba maps for new_pba */ - info->pba_to_lba[new_pba] = lba % 1000; - - page = 0; - lba++; - sectors -= pages >> info->smallpageshift; - } - result = USB_STOR_TRANSPORT_GOOD; - - leave: - kfree(buffer); - return result; -} - -static int sddr55_read_deviceID(struct us_data *us, - unsigned char *manufacturerID, - unsigned char *deviceID) { - - int result; - unsigned char *command = us->iobuf; - unsigned char *content = us->iobuf; - - memset(command, 0, 8); - command[5] = 0xB0; - command[7] = 0x84; - result = sddr55_bulk_transport(us, DMA_TO_DEVICE, command, 8); - - US_DEBUGP("Result of send_control for device ID is %d\n", - result); - - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - result = sddr55_bulk_transport(us, - DMA_FROM_DEVICE, content, 4); - - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - *manufacturerID = content[0]; - *deviceID = content[1]; - - if (content[0] != 0xff) { - result = sddr55_bulk_transport(us, - DMA_FROM_DEVICE, content, 2); - } - - return USB_STOR_TRANSPORT_GOOD; -} - - -static int sddr55_reset(struct us_data *us) -{ - return 0; -} - - -static unsigned long sddr55_get_capacity(struct us_data *us) { - - unsigned char uninitialized_var(manufacturerID); - unsigned char uninitialized_var(deviceID); - int result; - struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra; - - US_DEBUGP("Reading capacity...\n"); - - result = sddr55_read_deviceID(us, - &manufacturerID, - &deviceID); - - US_DEBUGP("Result of read_deviceID is %d\n", - result); - - if (result != USB_STOR_XFER_GOOD) - return 0; - - US_DEBUGP("Device ID = %02X\n", deviceID); - US_DEBUGP("Manuf ID = %02X\n", manufacturerID); - - info->pageshift = 9; - info->smallpageshift = 0; - info->blocksize = 16; - info->blockshift = 4; - info->blockmask = 15; - - switch (deviceID) { - - case 0x6e: // 1MB - case 0xe8: - case 0xec: - info->pageshift = 8; - info->smallpageshift = 1; - return 0x00100000; - - case 0xea: // 2MB - case 0x64: - info->pageshift = 8; - info->smallpageshift = 1; - case 0x5d: // 5d is a ROM card with pagesize 512. - return 0x00200000; - - case 0xe3: // 4MB - case 0xe5: - case 0x6b: - case 0xd5: - return 0x00400000; - - case 0xe6: // 8MB - case 0xd6: - return 0x00800000; - - case 0x73: // 16MB - info->blocksize = 32; - info->blockshift = 5; - info->blockmask = 31; - return 0x01000000; - - case 0x75: // 32MB - info->blocksize = 32; - info->blockshift = 5; - info->blockmask = 31; - return 0x02000000; - - case 0x76: // 64MB - info->blocksize = 32; - info->blockshift = 5; - info->blockmask = 31; - return 0x04000000; - - case 0x79: // 128MB - info->blocksize = 32; - info->blockshift = 5; - info->blockmask = 31; - return 0x08000000; - - default: // unknown - return 0; - - } -} - -static int sddr55_read_map(struct us_data *us) { - - struct sddr55_card_info *info = (struct sddr55_card_info *)(us->extra); - int numblocks; - unsigned char *buffer; - unsigned char *command = us->iobuf; - int i; - unsigned short lba; - unsigned short max_lba; - int result; - - if (!info->capacity) - return -1; - - numblocks = info->capacity >> (info->blockshift + info->pageshift); - - buffer = kmalloc( numblocks * 2, GFP_NOIO ); - - if (!buffer) - return -1; - - memset(command, 0, 8); - command[5] = 0xB0; - command[6] = numblocks * 2 / 256; - command[7] = 0x8A; - - result = sddr55_bulk_transport(us, DMA_TO_DEVICE, command, 8); - - if ( result != USB_STOR_XFER_GOOD) { - kfree (buffer); - return -1; - } - - result = sddr55_bulk_transport(us, DMA_FROM_DEVICE, buffer, numblocks * 2); - - if ( result != USB_STOR_XFER_GOOD) { - kfree (buffer); - return -1; - } - - result = sddr55_bulk_transport(us, DMA_FROM_DEVICE, command, 2); - - if ( result != USB_STOR_XFER_GOOD) { - kfree (buffer); - return -1; - } - - kfree(info->lba_to_pba); - kfree(info->pba_to_lba); - info->lba_to_pba = kmalloc(numblocks*sizeof(int), GFP_NOIO); - info->pba_to_lba = kmalloc(numblocks*sizeof(int), GFP_NOIO); - - if (info->lba_to_pba == NULL || info->pba_to_lba == NULL) { - kfree(info->lba_to_pba); - kfree(info->pba_to_lba); - info->lba_to_pba = NULL; - info->pba_to_lba = NULL; - kfree(buffer); - return -1; - } - - memset(info->lba_to_pba, 0xff, numblocks*sizeof(int)); - memset(info->pba_to_lba, 0xff, numblocks*sizeof(int)); - - /* set maximum lba */ - max_lba = info->max_log_blks; - if (max_lba > 1000) - max_lba = 1000; - - // Each block is 64 bytes of control data, so block i is located in - // scatterlist block i*64/128k = i*(2^6)*(2^-17) = i*(2^-11) - - for (i=0; ipba_to_lba[i] = lba; - - if (lba >= max_lba) { - continue; - } - - if (info->lba_to_pba[lba + zone * 1000] != NOT_ALLOCATED && - !info->force_read_only) { - printk(KERN_WARNING - "sddr55: map inconsistency at LBA %04X\n", - lba + zone * 1000); - info->force_read_only = 1; - } - - if (lba<0x10 || (lba>=0x3E0 && lba<0x3EF)) - US_DEBUGP("LBA %04X <-> PBA %04X\n", lba, i); - - info->lba_to_pba[lba + zone * 1000] = i; - } - - kfree(buffer); - return 0; -} - - -static void sddr55_card_info_destructor(void *extra) { - struct sddr55_card_info *info = (struct sddr55_card_info *)extra; - - if (!extra) - return; - - kfree(info->lba_to_pba); - kfree(info->pba_to_lba); -} - - -/* - * Transport for the Sandisk SDDR-55 - */ -static int sddr55_transport(struct scsi_cmnd *srb, struct us_data *us) -{ - int result; - static unsigned char inquiry_response[8] = { - 0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00 - }; - // write-protected for now, no block descriptor support - static unsigned char mode_page_01[20] = { - 0x0, 0x12, 0x00, 0x80, 0x0, 0x0, 0x0, 0x0, - 0x01, 0x0A, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - unsigned char *ptr = us->iobuf; - unsigned long capacity; - unsigned int lba; - unsigned int pba; - unsigned int page; - unsigned short pages; - struct sddr55_card_info *info; - - if (!us->extra) { - us->extra = kzalloc( - sizeof(struct sddr55_card_info), GFP_NOIO); - if (!us->extra) - return USB_STOR_TRANSPORT_ERROR; - us->extra_destructor = sddr55_card_info_destructor; - } - - info = (struct sddr55_card_info *)(us->extra); - - if (srb->cmnd[0] == REQUEST_SENSE) { - US_DEBUGP("SDDR55: request sense %02x/%02x/%02x\n", info->sense_data[2], info->sense_data[12], info->sense_data[13]); - - memcpy (ptr, info->sense_data, sizeof info->sense_data); - ptr[0] = 0x70; - ptr[7] = 11; - usb_stor_set_xfer_buf (ptr, sizeof info->sense_data, srb); - memset (info->sense_data, 0, sizeof info->sense_data); - - return USB_STOR_TRANSPORT_GOOD; - } - - memset (info->sense_data, 0, sizeof info->sense_data); - - /* Dummy up a response for INQUIRY since SDDR55 doesn't - respond to INQUIRY commands */ - - if (srb->cmnd[0] == INQUIRY) { - memcpy(ptr, inquiry_response, 8); - fill_inquiry_response(us, ptr, 36); - return USB_STOR_TRANSPORT_GOOD; - } - - /* only check card status if the map isn't allocated, ie no card seen yet - * or if it's been over half a second since we last accessed it - */ - if (info->lba_to_pba == NULL || time_after(jiffies, info->last_access + HZ/2)) { - - /* check to see if a card is fitted */ - result = sddr55_status (us); - if (result) { - result = sddr55_status (us); - if (!result) { - set_sense_info (6, 0x28, 0); /* new media, set unit attention, not ready to ready */ - } - return USB_STOR_TRANSPORT_FAILED; - } - } - - /* if we detected a problem with the map when writing, - don't allow any more access */ - if (info->fatal_error) { - - set_sense_info (3, 0x31, 0); - return USB_STOR_TRANSPORT_FAILED; - } - - if (srb->cmnd[0] == READ_CAPACITY) { - - capacity = sddr55_get_capacity(us); - - if (!capacity) { - set_sense_info (3, 0x30, 0); /* incompatible medium */ - return USB_STOR_TRANSPORT_FAILED; - } - - info->capacity = capacity; - - /* figure out the maximum logical block number, allowing for - * the fact that only 250 out of every 256 are used */ - info->max_log_blks = ((info->capacity >> (info->pageshift + info->blockshift)) / 256) * 250; - - /* Last page in the card, adjust as we only use 250 out of - * every 256 pages */ - capacity = (capacity / 256) * 250; - - capacity /= PAGESIZE; - capacity--; - - ((__be32 *) ptr)[0] = cpu_to_be32(capacity); - ((__be32 *) ptr)[1] = cpu_to_be32(PAGESIZE); - usb_stor_set_xfer_buf(ptr, 8, srb); - - sddr55_read_map(us); - - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == MODE_SENSE_10) { - - memcpy(ptr, mode_page_01, sizeof mode_page_01); - ptr[3] = (info->read_only || info->force_read_only) ? 0x80 : 0; - usb_stor_set_xfer_buf(ptr, sizeof(mode_page_01), srb); - - if ( (srb->cmnd[2] & 0x3F) == 0x01 ) { - US_DEBUGP( - "SDDR55: Dummy up request for mode page 1\n"); - return USB_STOR_TRANSPORT_GOOD; - - } else if ( (srb->cmnd[2] & 0x3F) == 0x3F ) { - US_DEBUGP( - "SDDR55: Dummy up request for all mode pages\n"); - return USB_STOR_TRANSPORT_GOOD; - } - - set_sense_info (5, 0x24, 0); /* invalid field in command */ - return USB_STOR_TRANSPORT_FAILED; - } - - if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { - - US_DEBUGP( - "SDDR55: %s medium removal. Not that I can do" - " anything about it...\n", - (srb->cmnd[4]&0x03) ? "Prevent" : "Allow"); - - return USB_STOR_TRANSPORT_GOOD; - - } - - if (srb->cmnd[0] == READ_10 || srb->cmnd[0] == WRITE_10) { - - page = short_pack(srb->cmnd[3], srb->cmnd[2]); - page <<= 16; - page |= short_pack(srb->cmnd[5], srb->cmnd[4]); - pages = short_pack(srb->cmnd[8], srb->cmnd[7]); - - page <<= info->smallpageshift; - - // convert page to block and page-within-block - - lba = page >> info->blockshift; - page = page & info->blockmask; - - // locate physical block corresponding to logical block - - if (lba >= info->max_log_blks) { - - US_DEBUGP("Error: Requested LBA %04X exceeds maximum " - "block %04X\n", lba, info->max_log_blks-1); - - set_sense_info (5, 0x24, 0); /* invalid field in command */ - - return USB_STOR_TRANSPORT_FAILED; - } - - pba = info->lba_to_pba[lba]; - - if (srb->cmnd[0] == WRITE_10) { - US_DEBUGP("WRITE_10: write block %04X (LBA %04X) page %01X" - " pages %d\n", - pba, lba, page, pages); - - return sddr55_write_data(us, lba, page, pages); - } else { - US_DEBUGP("READ_10: read block %04X (LBA %04X) page %01X" - " pages %d\n", - pba, lba, page, pages); - - return sddr55_read_data(us, lba, page, pages); - } - } - - - if (srb->cmnd[0] == TEST_UNIT_READY) { - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == START_STOP) { - return USB_STOR_TRANSPORT_GOOD; - } - - set_sense_info (5, 0x20, 0); /* illegal command */ - - return USB_STOR_TRANSPORT_FAILED; // FIXME: sense buffer? -} - - -static int sddr55_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct us_data *us; - int result; - - result = usb_stor_probe1(&us, intf, id, - (id - sddr55_usb_ids) + sddr55_unusual_dev_list); - if (result) - return result; - - us->transport_name = "SDDR55"; - us->transport = sddr55_transport; - us->transport_reset = sddr55_reset; - us->max_lun = 0; - - result = usb_stor_probe2(us); - return result; -} - -static struct usb_driver sddr55_driver = { - .name = "ums-sddr55", - .probe = sddr55_probe, - .disconnect = usb_stor_disconnect, - .suspend = usb_stor_suspend, - .resume = usb_stor_resume, - .reset_resume = usb_stor_reset_resume, - .pre_reset = usb_stor_pre_reset, - .post_reset = usb_stor_post_reset, - .id_table = sddr55_usb_ids, - .soft_unbind = 1, - .no_dynamic_id = 1, -}; - -module_usb_driver(sddr55_driver); diff --git a/ANDROID_3.4.5/drivers/usb/storage/shuttle_usbat.c b/ANDROID_3.4.5/drivers/usb/storage/shuttle_usbat.c deleted file mode 100644 index fa1ceebc..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/shuttle_usbat.c +++ /dev/null @@ -1,1869 +0,0 @@ -/* Driver for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable - * - * Current development and maintenance by: - * (c) 2000, 2001 Robert Baruch (autophile@starband.net) - * (c) 2004, 2005 Daniel Drake - * - * Developed with the assistance of: - * (c) 2002 Alan Stern - * - * Flash support based on earlier work by: - * (c) 2002 Thomas Kreiling - * - * Many originally ATAPI devices were slightly modified to meet the USB - * market by using some kind of translation from ATAPI to USB on the host, - * and the peripheral would translate from USB back to ATAPI. - * - * SCM Microsystems (www.scmmicro.com) makes a device, sold to OEM's only, - * which does the USB-to-ATAPI conversion. By obtaining the data sheet on - * their device under nondisclosure agreement, I have been able to write - * this driver for Linux. - * - * The chip used in the device can also be used for EPP and ISA translation - * as well. This driver is only guaranteed to work with the ATAPI - * translation. - * - * See the Kconfig help text for a list of devices known to be supported by - * this driver. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -#include -#include - -#include "usb.h" -#include "transport.h" -#include "protocol.h" -#include "debug.h" - -MODULE_DESCRIPTION("Driver for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable"); -MODULE_AUTHOR("Daniel Drake , Robert Baruch "); -MODULE_LICENSE("GPL"); - -/* Supported device types */ -#define USBAT_DEV_HP8200 0x01 -#define USBAT_DEV_FLASH 0x02 - -#define USBAT_EPP_PORT 0x10 -#define USBAT_EPP_REGISTER 0x30 -#define USBAT_ATA 0x40 -#define USBAT_ISA 0x50 - -/* Commands (need to be logically OR'd with an access type */ -#define USBAT_CMD_READ_REG 0x00 -#define USBAT_CMD_WRITE_REG 0x01 -#define USBAT_CMD_READ_BLOCK 0x02 -#define USBAT_CMD_WRITE_BLOCK 0x03 -#define USBAT_CMD_COND_READ_BLOCK 0x04 -#define USBAT_CMD_COND_WRITE_BLOCK 0x05 -#define USBAT_CMD_WRITE_REGS 0x07 - -/* Commands (these don't need an access type) */ -#define USBAT_CMD_EXEC_CMD 0x80 -#define USBAT_CMD_SET_FEAT 0x81 -#define USBAT_CMD_UIO 0x82 - -/* Methods of accessing UIO register */ -#define USBAT_UIO_READ 1 -#define USBAT_UIO_WRITE 0 - -/* Qualifier bits */ -#define USBAT_QUAL_FCQ 0x20 /* full compare */ -#define USBAT_QUAL_ALQ 0x10 /* auto load subcount */ - -/* USBAT Flash Media status types */ -#define USBAT_FLASH_MEDIA_NONE 0 -#define USBAT_FLASH_MEDIA_CF 1 - -/* USBAT Flash Media change types */ -#define USBAT_FLASH_MEDIA_SAME 0 -#define USBAT_FLASH_MEDIA_CHANGED 1 - -/* USBAT ATA registers */ -#define USBAT_ATA_DATA 0x10 /* read/write data (R/W) */ -#define USBAT_ATA_FEATURES 0x11 /* set features (W) */ -#define USBAT_ATA_ERROR 0x11 /* error (R) */ -#define USBAT_ATA_SECCNT 0x12 /* sector count (R/W) */ -#define USBAT_ATA_SECNUM 0x13 /* sector number (R/W) */ -#define USBAT_ATA_LBA_ME 0x14 /* cylinder low (R/W) */ -#define USBAT_ATA_LBA_HI 0x15 /* cylinder high (R/W) */ -#define USBAT_ATA_DEVICE 0x16 /* head/device selection (R/W) */ -#define USBAT_ATA_STATUS 0x17 /* device status (R) */ -#define USBAT_ATA_CMD 0x17 /* device command (W) */ -#define USBAT_ATA_ALTSTATUS 0x0E /* status (no clear IRQ) (R) */ - -/* USBAT User I/O Data registers */ -#define USBAT_UIO_EPAD 0x80 /* Enable Peripheral Control Signals */ -#define USBAT_UIO_CDT 0x40 /* Card Detect (Read Only) */ - /* CDT = ACKD & !UI1 & !UI0 */ -#define USBAT_UIO_1 0x20 /* I/O 1 */ -#define USBAT_UIO_0 0x10 /* I/O 0 */ -#define USBAT_UIO_EPP_ATA 0x08 /* 1=EPP mode, 0=ATA mode */ -#define USBAT_UIO_UI1 0x04 /* Input 1 */ -#define USBAT_UIO_UI0 0x02 /* Input 0 */ -#define USBAT_UIO_INTR_ACK 0x01 /* Interrupt (ATA/ISA)/Acknowledge (EPP) */ - -/* USBAT User I/O Enable registers */ -#define USBAT_UIO_DRVRST 0x80 /* Reset Peripheral */ -#define USBAT_UIO_ACKD 0x40 /* Enable Card Detect */ -#define USBAT_UIO_OE1 0x20 /* I/O 1 set=output/clr=input */ - /* If ACKD=1, set OE1 to 1 also. */ -#define USBAT_UIO_OE0 0x10 /* I/O 0 set=output/clr=input */ -#define USBAT_UIO_ADPRST 0x01 /* Reset SCM chip */ - -/* USBAT Features */ -#define USBAT_FEAT_ETEN 0x80 /* External trigger enable */ -#define USBAT_FEAT_U1 0x08 -#define USBAT_FEAT_U0 0x04 -#define USBAT_FEAT_ET1 0x02 -#define USBAT_FEAT_ET2 0x01 - -struct usbat_info { - int devicetype; - - /* Used for Flash readers only */ - unsigned long sectors; /* total sector count */ - unsigned long ssize; /* sector size in bytes */ - - unsigned char sense_key; - unsigned long sense_asc; /* additional sense code */ - unsigned long sense_ascq; /* additional sense code qualifier */ -}; - -#define short_pack(LSB,MSB) ( ((u16)(LSB)) | ( ((u16)(MSB))<<8 ) ) -#define LSB_of(s) ((s)&0xFF) -#define MSB_of(s) ((s)>>8) - -static int transferred = 0; - -static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us); -static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us); - -static int init_usbat_cd(struct us_data *us); -static int init_usbat_flash(struct us_data *us); - - -/* - * The table of devices - */ -#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ - vendorName, productName, useProtocol, useTransport, \ - initFunction, flags) \ -{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } - -static struct usb_device_id usbat_usb_ids[] = { -# include "unusual_usbat.h" - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, usbat_usb_ids); - -#undef UNUSUAL_DEV - -/* - * The flags table - */ -#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ - vendor_name, product_name, use_protocol, use_transport, \ - init_function, Flags) \ -{ \ - .vendorName = vendor_name, \ - .productName = product_name, \ - .useProtocol = use_protocol, \ - .useTransport = use_transport, \ - .initFunction = init_function, \ -} - -static struct us_unusual_dev usbat_unusual_dev_list[] = { -# include "unusual_usbat.h" - { } /* Terminating entry */ -}; - -#undef UNUSUAL_DEV - -/* - * Convenience function to produce an ATA read/write sectors command - * Use cmd=0x20 for read, cmd=0x30 for write - */ -static void usbat_pack_ata_sector_cmd(unsigned char *buf, - unsigned char thistime, - u32 sector, unsigned char cmd) -{ - buf[0] = 0; - buf[1] = thistime; - buf[2] = sector & 0xFF; - buf[3] = (sector >> 8) & 0xFF; - buf[4] = (sector >> 16) & 0xFF; - buf[5] = 0xE0 | ((sector >> 24) & 0x0F); - buf[6] = cmd; -} - -/* - * Convenience function to get the device type (flash or hp8200) - */ -static int usbat_get_device_type(struct us_data *us) -{ - return ((struct usbat_info*)us->extra)->devicetype; -} - -/* - * Read a register from the device - */ -static int usbat_read(struct us_data *us, - unsigned char access, - unsigned char reg, - unsigned char *content) -{ - return usb_stor_ctrl_transfer(us, - us->recv_ctrl_pipe, - access | USBAT_CMD_READ_REG, - 0xC0, - (u16)reg, - 0, - content, - 1); -} - -/* - * Write to a register on the device - */ -static int usbat_write(struct us_data *us, - unsigned char access, - unsigned char reg, - unsigned char content) -{ - return usb_stor_ctrl_transfer(us, - us->send_ctrl_pipe, - access | USBAT_CMD_WRITE_REG, - 0x40, - short_pack(reg, content), - 0, - NULL, - 0); -} - -/* - * Convenience function to perform a bulk read - */ -static int usbat_bulk_read(struct us_data *us, - void* buf, - unsigned int len, - int use_sg) -{ - if (len == 0) - return USB_STOR_XFER_GOOD; - - US_DEBUGP("usbat_bulk_read: len = %d\n", len); - return usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, buf, len, use_sg, NULL); -} - -/* - * Convenience function to perform a bulk write - */ -static int usbat_bulk_write(struct us_data *us, - void* buf, - unsigned int len, - int use_sg) -{ - if (len == 0) - return USB_STOR_XFER_GOOD; - - US_DEBUGP("usbat_bulk_write: len = %d\n", len); - return usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, buf, len, use_sg, NULL); -} - -/* - * Some USBAT-specific commands can only be executed over a command transport - * This transport allows one (len=8) or two (len=16) vendor-specific commands - * to be executed. - */ -static int usbat_execute_command(struct us_data *us, - unsigned char *commands, - unsigned int len) -{ - return usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, - USBAT_CMD_EXEC_CMD, 0x40, 0, 0, - commands, len); -} - -/* - * Read the status register - */ -static int usbat_get_status(struct us_data *us, unsigned char *status) -{ - int rc; - rc = usbat_read(us, USBAT_ATA, USBAT_ATA_STATUS, status); - - US_DEBUGP("usbat_get_status: 0x%02X\n", (unsigned short) (*status)); - return rc; -} - -/* - * Check the device status - */ -static int usbat_check_status(struct us_data *us) -{ - unsigned char *reply = us->iobuf; - int rc; - - rc = usbat_get_status(us, reply); - if (rc != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_FAILED; - - /* error/check condition (0x51 is ok) */ - if (*reply & 0x01 && *reply != 0x51) - return USB_STOR_TRANSPORT_FAILED; - - /* device fault */ - if (*reply & 0x20) - return USB_STOR_TRANSPORT_FAILED; - - return USB_STOR_TRANSPORT_GOOD; -} - -/* - * Stores critical information in internal registers in preparation for the execution - * of a conditional usbat_read_blocks or usbat_write_blocks call. - */ -static int usbat_set_shuttle_features(struct us_data *us, - unsigned char external_trigger, - unsigned char epp_control, - unsigned char mask_byte, - unsigned char test_pattern, - unsigned char subcountH, - unsigned char subcountL) -{ - unsigned char *command = us->iobuf; - - command[0] = 0x40; - command[1] = USBAT_CMD_SET_FEAT; - - /* - * The only bit relevant to ATA access is bit 6 - * which defines 8 bit data access (set) or 16 bit (unset) - */ - command[2] = epp_control; - - /* - * If FCQ is set in the qualifier (defined in R/W cmd), then bits U0, U1, - * ET1 and ET2 define an external event to be checked for on event of a - * _read_blocks or _write_blocks operation. The read/write will not take - * place unless the defined trigger signal is active. - */ - command[3] = external_trigger; - - /* - * The resultant byte of the mask operation (see mask_byte) is compared for - * equivalence with this test pattern. If equal, the read/write will take - * place. - */ - command[4] = test_pattern; - - /* - * This value is logically ANDed with the status register field specified - * in the read/write command. - */ - command[5] = mask_byte; - - /* - * If ALQ is set in the qualifier, this field contains the address of the - * registers where the byte count should be read for transferring the data. - * If ALQ is not set, then this field contains the number of bytes to be - * transferred. - */ - command[6] = subcountL; - command[7] = subcountH; - - return usbat_execute_command(us, command, 8); -} - -/* - * Block, waiting for an ATA device to become not busy or to report - * an error condition. - */ -static int usbat_wait_not_busy(struct us_data *us, int minutes) -{ - int i; - int result; - unsigned char *status = us->iobuf; - - /* Synchronizing cache on a CDR could take a heck of a long time, - * but probably not more than 10 minutes or so. On the other hand, - * doing a full blank on a CDRW at speed 1 will take about 75 - * minutes! - */ - - for (i=0; i<1200+minutes*60; i++) { - - result = usbat_get_status(us, status); - - if (result!=USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - if (*status & 0x01) { /* check condition */ - result = usbat_read(us, USBAT_ATA, 0x10, status); - return USB_STOR_TRANSPORT_FAILED; - } - if (*status & 0x20) /* device fault */ - return USB_STOR_TRANSPORT_FAILED; - - if ((*status & 0x80)==0x00) { /* not busy */ - US_DEBUGP("Waited not busy for %d steps\n", i); - return USB_STOR_TRANSPORT_GOOD; - } - - if (i<500) - msleep(10); /* 5 seconds */ - else if (i<700) - msleep(50); /* 10 seconds */ - else if (i<1200) - msleep(100); /* 50 seconds */ - else - msleep(1000); /* X minutes */ - } - - US_DEBUGP("Waited not busy for %d minutes, timing out.\n", - minutes); - return USB_STOR_TRANSPORT_FAILED; -} - -/* - * Read block data from the data register - */ -static int usbat_read_block(struct us_data *us, - void* buf, - unsigned short len, - int use_sg) -{ - int result; - unsigned char *command = us->iobuf; - - if (!len) - return USB_STOR_TRANSPORT_GOOD; - - command[0] = 0xC0; - command[1] = USBAT_ATA | USBAT_CMD_READ_BLOCK; - command[2] = USBAT_ATA_DATA; - command[3] = 0; - command[4] = 0; - command[5] = 0; - command[6] = LSB_of(len); - command[7] = MSB_of(len); - - result = usbat_execute_command(us, command, 8); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - result = usbat_bulk_read(us, buf, len, use_sg); - return (result == USB_STOR_XFER_GOOD ? - USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); -} - -/* - * Write block data via the data register - */ -static int usbat_write_block(struct us_data *us, - unsigned char access, - void* buf, - unsigned short len, - int minutes, - int use_sg) -{ - int result; - unsigned char *command = us->iobuf; - - if (!len) - return USB_STOR_TRANSPORT_GOOD; - - command[0] = 0x40; - command[1] = access | USBAT_CMD_WRITE_BLOCK; - command[2] = USBAT_ATA_DATA; - command[3] = 0; - command[4] = 0; - command[5] = 0; - command[6] = LSB_of(len); - command[7] = MSB_of(len); - - result = usbat_execute_command(us, command, 8); - - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - result = usbat_bulk_write(us, buf, len, use_sg); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - return usbat_wait_not_busy(us, minutes); -} - -/* - * Process read and write requests - */ -static int usbat_hp8200e_rw_block_test(struct us_data *us, - unsigned char access, - unsigned char *registers, - unsigned char *data_out, - unsigned short num_registers, - unsigned char data_reg, - unsigned char status_reg, - unsigned char timeout, - unsigned char qualifier, - int direction, - void *buf, - unsigned short len, - int use_sg, - int minutes) -{ - int result; - unsigned int pipe = (direction == DMA_FROM_DEVICE) ? - us->recv_bulk_pipe : us->send_bulk_pipe; - - unsigned char *command = us->iobuf; - int i, j; - int cmdlen; - unsigned char *data = us->iobuf; - unsigned char *status = us->iobuf; - - BUG_ON(num_registers > US_IOBUF_SIZE/2); - - for (i=0; i<20; i++) { - - /* - * The first time we send the full command, which consists - * of downloading the SCSI command followed by downloading - * the data via a write-and-test. Any other time we only - * send the command to download the data -- the SCSI command - * is still 'active' in some sense in the device. - * - * We're only going to try sending the data 10 times. After - * that, we just return a failure. - */ - - if (i==0) { - cmdlen = 16; - /* - * Write to multiple registers - * Not really sure the 0x07, 0x17, 0xfc, 0xe7 is - * necessary here, but that's what came out of the - * trace every single time. - */ - command[0] = 0x40; - command[1] = access | USBAT_CMD_WRITE_REGS; - command[2] = 0x07; - command[3] = 0x17; - command[4] = 0xFC; - command[5] = 0xE7; - command[6] = LSB_of(num_registers*2); - command[7] = MSB_of(num_registers*2); - } else - cmdlen = 8; - - /* Conditionally read or write blocks */ - command[cmdlen-8] = (direction==DMA_TO_DEVICE ? 0x40 : 0xC0); - command[cmdlen-7] = access | - (direction==DMA_TO_DEVICE ? - USBAT_CMD_COND_WRITE_BLOCK : USBAT_CMD_COND_READ_BLOCK); - command[cmdlen-6] = data_reg; - command[cmdlen-5] = status_reg; - command[cmdlen-4] = timeout; - command[cmdlen-3] = qualifier; - command[cmdlen-2] = LSB_of(len); - command[cmdlen-1] = MSB_of(len); - - result = usbat_execute_command(us, command, cmdlen); - - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - if (i==0) { - - for (j=0; jsend_bulk_pipe) < 0) - return USB_STOR_TRANSPORT_ERROR; - } - - /* - * Read status: is the device angry, or just busy? - */ - - result = usbat_read(us, USBAT_ATA, - direction==DMA_TO_DEVICE ? - USBAT_ATA_STATUS : USBAT_ATA_ALTSTATUS, - status); - - if (result!=USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - if (*status & 0x01) /* check condition */ - return USB_STOR_TRANSPORT_FAILED; - if (*status & 0x20) /* device fault */ - return USB_STOR_TRANSPORT_FAILED; - - US_DEBUGP("Redoing %s\n", - direction==DMA_TO_DEVICE ? "write" : "read"); - - } else if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - else - return usbat_wait_not_busy(us, minutes); - - } - - US_DEBUGP("Bummer! %s bulk data 20 times failed.\n", - direction==DMA_TO_DEVICE ? "Writing" : "Reading"); - - return USB_STOR_TRANSPORT_FAILED; -} - -/* - * Write to multiple registers: - * Allows us to write specific data to any registers. The data to be written - * gets packed in this sequence: reg0, data0, reg1, data1, ..., regN, dataN - * which gets sent through bulk out. - * Not designed for large transfers of data! - */ -static int usbat_multiple_write(struct us_data *us, - unsigned char *registers, - unsigned char *data_out, - unsigned short num_registers) -{ - int i, result; - unsigned char *data = us->iobuf; - unsigned char *command = us->iobuf; - - BUG_ON(num_registers > US_IOBUF_SIZE/2); - - /* Write to multiple registers, ATA access */ - command[0] = 0x40; - command[1] = USBAT_ATA | USBAT_CMD_WRITE_REGS; - - /* No relevance */ - command[2] = 0; - command[3] = 0; - command[4] = 0; - command[5] = 0; - - /* Number of bytes to be transferred (incl. addresses and data) */ - command[6] = LSB_of(num_registers*2); - command[7] = MSB_of(num_registers*2); - - /* The setup command */ - result = usbat_execute_command(us, command, 8); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - /* Create the reg/data, reg/data sequence */ - for (i=0; iiobuf; - - command[0] = 0xC0; - command[1] = USBAT_ATA | USBAT_CMD_COND_READ_BLOCK; - command[2] = USBAT_ATA_DATA; - command[3] = USBAT_ATA_STATUS; - command[4] = 0xFD; /* Timeout (ms); */ - command[5] = USBAT_QUAL_FCQ; - command[6] = LSB_of(len); - command[7] = MSB_of(len); - - /* Multiple block read setup command */ - result = usbat_execute_command(us, command, 8); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_FAILED; - - /* Read the blocks we just asked for */ - result = usbat_bulk_read(us, buffer, len, use_sg); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_FAILED; - - return USB_STOR_TRANSPORT_GOOD; -} - -/* - * Conditionally write blocks to device: - * Allows us to write blocks to a specific data register, based upon the - * condition that a status register can be successfully masked with a status - * qualifier. If this condition is not initially met, the write will wait - * up until a maximum amount of time has elapsed, as specified by timeout. - * The read will start when the condition is met, otherwise the command aborts. - * - * The qualifier defined here is not the value that is masked, it defines - * conditions for the write to take place. The actual masked qualifier (and - * other related details) are defined beforehand with _set_shuttle_features(). - */ -static int usbat_write_blocks(struct us_data *us, - void* buffer, - int len, - int use_sg) -{ - int result; - unsigned char *command = us->iobuf; - - command[0] = 0x40; - command[1] = USBAT_ATA | USBAT_CMD_COND_WRITE_BLOCK; - command[2] = USBAT_ATA_DATA; - command[3] = USBAT_ATA_STATUS; - command[4] = 0xFD; /* Timeout (ms) */ - command[5] = USBAT_QUAL_FCQ; - command[6] = LSB_of(len); - command[7] = MSB_of(len); - - /* Multiple block write setup command */ - result = usbat_execute_command(us, command, 8); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_FAILED; - - /* Write the data */ - result = usbat_bulk_write(us, buffer, len, use_sg); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_FAILED; - - return USB_STOR_TRANSPORT_GOOD; -} - -/* - * Read the User IO register - */ -static int usbat_read_user_io(struct us_data *us, unsigned char *data_flags) -{ - int result; - - result = usb_stor_ctrl_transfer(us, - us->recv_ctrl_pipe, - USBAT_CMD_UIO, - 0xC0, - 0, - 0, - data_flags, - USBAT_UIO_READ); - - US_DEBUGP("usbat_read_user_io: UIO register reads %02X\n", (unsigned short) (*data_flags)); - - return result; -} - -/* - * Write to the User IO register - */ -static int usbat_write_user_io(struct us_data *us, - unsigned char enable_flags, - unsigned char data_flags) -{ - return usb_stor_ctrl_transfer(us, - us->send_ctrl_pipe, - USBAT_CMD_UIO, - 0x40, - short_pack(enable_flags, data_flags), - 0, - NULL, - USBAT_UIO_WRITE); -} - -/* - * Reset the device - * Often needed on media change. - */ -static int usbat_device_reset(struct us_data *us) -{ - int rc; - - /* - * Reset peripheral, enable peripheral control signals - * (bring reset signal up) - */ - rc = usbat_write_user_io(us, - USBAT_UIO_DRVRST | USBAT_UIO_OE1 | USBAT_UIO_OE0, - USBAT_UIO_EPAD | USBAT_UIO_1); - if (rc != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - /* - * Enable peripheral control signals - * (bring reset signal down) - */ - rc = usbat_write_user_io(us, - USBAT_UIO_OE1 | USBAT_UIO_OE0, - USBAT_UIO_EPAD | USBAT_UIO_1); - if (rc != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - return USB_STOR_TRANSPORT_GOOD; -} - -/* - * Enable card detect - */ -static int usbat_device_enable_cdt(struct us_data *us) -{ - int rc; - - /* Enable peripheral control signals and card detect */ - rc = usbat_write_user_io(us, - USBAT_UIO_ACKD | USBAT_UIO_OE1 | USBAT_UIO_OE0, - USBAT_UIO_EPAD | USBAT_UIO_1); - if (rc != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - return USB_STOR_TRANSPORT_GOOD; -} - -/* - * Determine if media is present. - */ -static int usbat_flash_check_media_present(unsigned char *uio) -{ - if (*uio & USBAT_UIO_UI0) { - US_DEBUGP("usbat_flash_check_media_present: no media detected\n"); - return USBAT_FLASH_MEDIA_NONE; - } - - return USBAT_FLASH_MEDIA_CF; -} - -/* - * Determine if media has changed since last operation - */ -static int usbat_flash_check_media_changed(unsigned char *uio) -{ - if (*uio & USBAT_UIO_0) { - US_DEBUGP("usbat_flash_check_media_changed: media change detected\n"); - return USBAT_FLASH_MEDIA_CHANGED; - } - - return USBAT_FLASH_MEDIA_SAME; -} - -/* - * Check for media change / no media and handle the situation appropriately - */ -static int usbat_flash_check_media(struct us_data *us, - struct usbat_info *info) -{ - int rc; - unsigned char *uio = us->iobuf; - - rc = usbat_read_user_io(us, uio); - if (rc != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - /* Check for media existence */ - rc = usbat_flash_check_media_present(uio); - if (rc == USBAT_FLASH_MEDIA_NONE) { - info->sense_key = 0x02; - info->sense_asc = 0x3A; - info->sense_ascq = 0x00; - return USB_STOR_TRANSPORT_FAILED; - } - - /* Check for media change */ - rc = usbat_flash_check_media_changed(uio); - if (rc == USBAT_FLASH_MEDIA_CHANGED) { - - /* Reset and re-enable card detect */ - rc = usbat_device_reset(us); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - rc = usbat_device_enable_cdt(us); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - - msleep(50); - - rc = usbat_read_user_io(us, uio); - if (rc != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - info->sense_key = UNIT_ATTENTION; - info->sense_asc = 0x28; - info->sense_ascq = 0x00; - return USB_STOR_TRANSPORT_FAILED; - } - - return USB_STOR_TRANSPORT_GOOD; -} - -/* - * Determine whether we are controlling a flash-based reader/writer, - * or a HP8200-based CD drive. - * Sets transport functions as appropriate. - */ -static int usbat_identify_device(struct us_data *us, - struct usbat_info *info) -{ - int rc; - unsigned char status; - - if (!us || !info) - return USB_STOR_TRANSPORT_ERROR; - - rc = usbat_device_reset(us); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - msleep(500); - - /* - * In attempt to distinguish between HP CDRW's and Flash readers, we now - * execute the IDENTIFY PACKET DEVICE command. On ATA devices (i.e. flash - * readers), this command should fail with error. On ATAPI devices (i.e. - * CDROM drives), it should succeed. - */ - rc = usbat_write(us, USBAT_ATA, USBAT_ATA_CMD, 0xA1); - if (rc != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - rc = usbat_get_status(us, &status); - if (rc != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - /* Check for error bit, or if the command 'fell through' */ - if (status == 0xA1 || !(status & 0x01)) { - /* Device is HP 8200 */ - US_DEBUGP("usbat_identify_device: Detected HP8200 CDRW\n"); - info->devicetype = USBAT_DEV_HP8200; - } else { - /* Device is a CompactFlash reader/writer */ - US_DEBUGP("usbat_identify_device: Detected Flash reader/writer\n"); - info->devicetype = USBAT_DEV_FLASH; - } - - return USB_STOR_TRANSPORT_GOOD; -} - -/* - * Set the transport function based on the device type - */ -static int usbat_set_transport(struct us_data *us, - struct usbat_info *info, - int devicetype) -{ - - if (!info->devicetype) - info->devicetype = devicetype; - - if (!info->devicetype) - usbat_identify_device(us, info); - - switch (info->devicetype) { - default: - return USB_STOR_TRANSPORT_ERROR; - - case USBAT_DEV_HP8200: - us->transport = usbat_hp8200e_transport; - break; - - case USBAT_DEV_FLASH: - us->transport = usbat_flash_transport; - break; - } - - return 0; -} - -/* - * Read the media capacity - */ -static int usbat_flash_get_sector_count(struct us_data *us, - struct usbat_info *info) -{ - unsigned char registers[3] = { - USBAT_ATA_SECCNT, - USBAT_ATA_DEVICE, - USBAT_ATA_CMD, - }; - unsigned char command[3] = { 0x01, 0xA0, 0xEC }; - unsigned char *reply; - unsigned char status; - int rc; - - if (!us || !info) - return USB_STOR_TRANSPORT_ERROR; - - reply = kmalloc(512, GFP_NOIO); - if (!reply) - return USB_STOR_TRANSPORT_ERROR; - - /* ATA command : IDENTIFY DEVICE */ - rc = usbat_multiple_write(us, registers, command, 3); - if (rc != USB_STOR_XFER_GOOD) { - US_DEBUGP("usbat_flash_get_sector_count: Gah! identify_device failed\n"); - rc = USB_STOR_TRANSPORT_ERROR; - goto leave; - } - - /* Read device status */ - if (usbat_get_status(us, &status) != USB_STOR_XFER_GOOD) { - rc = USB_STOR_TRANSPORT_ERROR; - goto leave; - } - - msleep(100); - - /* Read the device identification data */ - rc = usbat_read_block(us, reply, 512, 0); - if (rc != USB_STOR_TRANSPORT_GOOD) - goto leave; - - info->sectors = ((u32)(reply[117]) << 24) | - ((u32)(reply[116]) << 16) | - ((u32)(reply[115]) << 8) | - ((u32)(reply[114]) ); - - rc = USB_STOR_TRANSPORT_GOOD; - - leave: - kfree(reply); - return rc; -} - -/* - * Read data from device - */ -static int usbat_flash_read_data(struct us_data *us, - struct usbat_info *info, - u32 sector, - u32 sectors) -{ - unsigned char registers[7] = { - USBAT_ATA_FEATURES, - USBAT_ATA_SECCNT, - USBAT_ATA_SECNUM, - USBAT_ATA_LBA_ME, - USBAT_ATA_LBA_HI, - USBAT_ATA_DEVICE, - USBAT_ATA_STATUS, - }; - unsigned char command[7]; - unsigned char *buffer; - unsigned char thistime; - unsigned int totallen, alloclen; - int len, result; - unsigned int sg_offset = 0; - struct scatterlist *sg = NULL; - - result = usbat_flash_check_media(us, info); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - - /* - * we're working in LBA mode. according to the ATA spec, - * we can support up to 28-bit addressing. I don't know if Jumpshot - * supports beyond 24-bit addressing. It's kind of hard to test - * since it requires > 8GB CF card. - */ - - if (sector > 0x0FFFFFFF) - return USB_STOR_TRANSPORT_ERROR; - - totallen = sectors * info->ssize; - - /* - * Since we don't read more than 64 KB at a time, we have to create - * a bounce buffer and move the data a piece at a time between the - * bounce buffer and the actual transfer buffer. - */ - - alloclen = min(totallen, 65536u); - buffer = kmalloc(alloclen, GFP_NOIO); - if (buffer == NULL) - return USB_STOR_TRANSPORT_ERROR; - - do { - /* - * loop, never allocate or transfer more than 64k at once - * (min(128k, 255*info->ssize) is the real limit) - */ - len = min(totallen, alloclen); - thistime = (len / info->ssize) & 0xff; - - /* ATA command 0x20 (READ SECTORS) */ - usbat_pack_ata_sector_cmd(command, thistime, sector, 0x20); - - /* Write/execute ATA read command */ - result = usbat_multiple_write(us, registers, command, 7); - if (result != USB_STOR_TRANSPORT_GOOD) - goto leave; - - /* Read the data we just requested */ - result = usbat_read_blocks(us, buffer, len, 0); - if (result != USB_STOR_TRANSPORT_GOOD) - goto leave; - - US_DEBUGP("usbat_flash_read_data: %d bytes\n", len); - - /* Store the data in the transfer buffer */ - usb_stor_access_xfer_buf(buffer, len, us->srb, - &sg, &sg_offset, TO_XFER_BUF); - - sector += thistime; - totallen -= len; - } while (totallen > 0); - - kfree(buffer); - return USB_STOR_TRANSPORT_GOOD; - -leave: - kfree(buffer); - return USB_STOR_TRANSPORT_ERROR; -} - -/* - * Write data to device - */ -static int usbat_flash_write_data(struct us_data *us, - struct usbat_info *info, - u32 sector, - u32 sectors) -{ - unsigned char registers[7] = { - USBAT_ATA_FEATURES, - USBAT_ATA_SECCNT, - USBAT_ATA_SECNUM, - USBAT_ATA_LBA_ME, - USBAT_ATA_LBA_HI, - USBAT_ATA_DEVICE, - USBAT_ATA_STATUS, - }; - unsigned char command[7]; - unsigned char *buffer; - unsigned char thistime; - unsigned int totallen, alloclen; - int len, result; - unsigned int sg_offset = 0; - struct scatterlist *sg = NULL; - - result = usbat_flash_check_media(us, info); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - - /* - * we're working in LBA mode. according to the ATA spec, - * we can support up to 28-bit addressing. I don't know if the device - * supports beyond 24-bit addressing. It's kind of hard to test - * since it requires > 8GB media. - */ - - if (sector > 0x0FFFFFFF) - return USB_STOR_TRANSPORT_ERROR; - - totallen = sectors * info->ssize; - - /* - * Since we don't write more than 64 KB at a time, we have to create - * a bounce buffer and move the data a piece at a time between the - * bounce buffer and the actual transfer buffer. - */ - - alloclen = min(totallen, 65536u); - buffer = kmalloc(alloclen, GFP_NOIO); - if (buffer == NULL) - return USB_STOR_TRANSPORT_ERROR; - - do { - /* - * loop, never allocate or transfer more than 64k at once - * (min(128k, 255*info->ssize) is the real limit) - */ - len = min(totallen, alloclen); - thistime = (len / info->ssize) & 0xff; - - /* Get the data from the transfer buffer */ - usb_stor_access_xfer_buf(buffer, len, us->srb, - &sg, &sg_offset, FROM_XFER_BUF); - - /* ATA command 0x30 (WRITE SECTORS) */ - usbat_pack_ata_sector_cmd(command, thistime, sector, 0x30); - - /* Write/execute ATA write command */ - result = usbat_multiple_write(us, registers, command, 7); - if (result != USB_STOR_TRANSPORT_GOOD) - goto leave; - - /* Write the data */ - result = usbat_write_blocks(us, buffer, len, 0); - if (result != USB_STOR_TRANSPORT_GOOD) - goto leave; - - sector += thistime; - totallen -= len; - } while (totallen > 0); - - kfree(buffer); - return result; - -leave: - kfree(buffer); - return USB_STOR_TRANSPORT_ERROR; -} - -/* - * Squeeze a potentially huge (> 65535 byte) read10 command into - * a little ( <= 65535 byte) ATAPI pipe - */ -static int usbat_hp8200e_handle_read10(struct us_data *us, - unsigned char *registers, - unsigned char *data, - struct scsi_cmnd *srb) -{ - int result = USB_STOR_TRANSPORT_GOOD; - unsigned char *buffer; - unsigned int len; - unsigned int sector; - unsigned int sg_offset = 0; - struct scatterlist *sg = NULL; - - US_DEBUGP("handle_read10: transfersize %d\n", - srb->transfersize); - - if (scsi_bufflen(srb) < 0x10000) { - - result = usbat_hp8200e_rw_block_test(us, USBAT_ATA, - registers, data, 19, - USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD, - (USBAT_QUAL_FCQ | USBAT_QUAL_ALQ), - DMA_FROM_DEVICE, - scsi_sglist(srb), - scsi_bufflen(srb), scsi_sg_count(srb), 1); - - return result; - } - - /* - * Since we're requesting more data than we can handle in - * a single read command (max is 64k-1), we will perform - * multiple reads, but each read must be in multiples of - * a sector. Luckily the sector size is in srb->transfersize - * (see linux/drivers/scsi/sr.c). - */ - - if (data[7+0] == GPCMD_READ_CD) { - len = short_pack(data[7+9], data[7+8]); - len <<= 16; - len |= data[7+7]; - US_DEBUGP("handle_read10: GPCMD_READ_CD: len %d\n", len); - srb->transfersize = scsi_bufflen(srb)/len; - } - - if (!srb->transfersize) { - srb->transfersize = 2048; /* A guess */ - US_DEBUGP("handle_read10: transfersize 0, forcing %d\n", - srb->transfersize); - } - - /* - * Since we only read in one block at a time, we have to create - * a bounce buffer and move the data a piece at a time between the - * bounce buffer and the actual transfer buffer. - */ - - len = (65535/srb->transfersize) * srb->transfersize; - US_DEBUGP("Max read is %d bytes\n", len); - len = min(len, scsi_bufflen(srb)); - buffer = kmalloc(len, GFP_NOIO); - if (buffer == NULL) /* bloody hell! */ - return USB_STOR_TRANSPORT_FAILED; - sector = short_pack(data[7+3], data[7+2]); - sector <<= 16; - sector |= short_pack(data[7+5], data[7+4]); - transferred = 0; - - while (transferred != scsi_bufflen(srb)) { - - if (len > scsi_bufflen(srb) - transferred) - len = scsi_bufflen(srb) - transferred; - - data[3] = len&0xFF; /* (cylL) = expected length (L) */ - data[4] = (len>>8)&0xFF; /* (cylH) = expected length (H) */ - - /* Fix up the SCSI command sector and num sectors */ - - data[7+2] = MSB_of(sector>>16); /* SCSI command sector */ - data[7+3] = LSB_of(sector>>16); - data[7+4] = MSB_of(sector&0xFFFF); - data[7+5] = LSB_of(sector&0xFFFF); - if (data[7+0] == GPCMD_READ_CD) - data[7+6] = 0; - data[7+7] = MSB_of(len / srb->transfersize); /* SCSI command */ - data[7+8] = LSB_of(len / srb->transfersize); /* num sectors */ - - result = usbat_hp8200e_rw_block_test(us, USBAT_ATA, - registers, data, 19, - USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD, - (USBAT_QUAL_FCQ | USBAT_QUAL_ALQ), - DMA_FROM_DEVICE, - buffer, - len, 0, 1); - - if (result != USB_STOR_TRANSPORT_GOOD) - break; - - /* Store the data in the transfer buffer */ - usb_stor_access_xfer_buf(buffer, len, srb, - &sg, &sg_offset, TO_XFER_BUF); - - /* Update the amount transferred and the sector number */ - - transferred += len; - sector += len / srb->transfersize; - - } /* while transferred != scsi_bufflen(srb) */ - - kfree(buffer); - return result; -} - -static int usbat_select_and_test_registers(struct us_data *us) -{ - int selector; - unsigned char *status = us->iobuf; - - /* try device = master, then device = slave. */ - for (selector = 0xA0; selector <= 0xB0; selector += 0x10) { - if (usbat_write(us, USBAT_ATA, USBAT_ATA_DEVICE, selector) != - USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - if (usbat_read(us, USBAT_ATA, USBAT_ATA_STATUS, status) != - USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - if (usbat_read(us, USBAT_ATA, USBAT_ATA_DEVICE, status) != - USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) != - USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_HI, status) != - USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - if (usbat_write(us, USBAT_ATA, USBAT_ATA_LBA_ME, 0x55) != - USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - if (usbat_write(us, USBAT_ATA, USBAT_ATA_LBA_HI, 0xAA) != - USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) != - USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) != - USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - } - - return USB_STOR_TRANSPORT_GOOD; -} - -/* - * Initialize the USBAT processor and the storage device - */ -static int init_usbat(struct us_data *us, int devicetype) -{ - int rc; - struct usbat_info *info; - unsigned char subcountH = USBAT_ATA_LBA_HI; - unsigned char subcountL = USBAT_ATA_LBA_ME; - unsigned char *status = us->iobuf; - - us->extra = kzalloc(sizeof(struct usbat_info), GFP_NOIO); - if (!us->extra) { - US_DEBUGP("init_usbat: Gah! Can't allocate storage for usbat info struct!\n"); - return 1; - } - info = (struct usbat_info *) (us->extra); - - /* Enable peripheral control signals */ - rc = usbat_write_user_io(us, - USBAT_UIO_OE1 | USBAT_UIO_OE0, - USBAT_UIO_EPAD | USBAT_UIO_1); - if (rc != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - US_DEBUGP("INIT 1\n"); - - msleep(2000); - - rc = usbat_read_user_io(us, status); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - - US_DEBUGP("INIT 2\n"); - - rc = usbat_read_user_io(us, status); - if (rc != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - rc = usbat_read_user_io(us, status); - if (rc != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - US_DEBUGP("INIT 3\n"); - - rc = usbat_select_and_test_registers(us); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - - US_DEBUGP("INIT 4\n"); - - rc = usbat_read_user_io(us, status); - if (rc != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - US_DEBUGP("INIT 5\n"); - - /* Enable peripheral control signals and card detect */ - rc = usbat_device_enable_cdt(us); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - - US_DEBUGP("INIT 6\n"); - - rc = usbat_read_user_io(us, status); - if (rc != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - US_DEBUGP("INIT 7\n"); - - msleep(1400); - - rc = usbat_read_user_io(us, status); - if (rc != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - US_DEBUGP("INIT 8\n"); - - rc = usbat_select_and_test_registers(us); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - - US_DEBUGP("INIT 9\n"); - - /* At this point, we need to detect which device we are using */ - if (usbat_set_transport(us, info, devicetype)) - return USB_STOR_TRANSPORT_ERROR; - - US_DEBUGP("INIT 10\n"); - - if (usbat_get_device_type(us) == USBAT_DEV_FLASH) { - subcountH = 0x02; - subcountL = 0x00; - } - rc = usbat_set_shuttle_features(us, (USBAT_FEAT_ETEN | USBAT_FEAT_ET2 | USBAT_FEAT_ET1), - 0x00, 0x88, 0x08, subcountH, subcountL); - if (rc != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - US_DEBUGP("INIT 11\n"); - - return USB_STOR_TRANSPORT_GOOD; -} - -/* - * Transport for the HP 8200e - */ -static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us) -{ - int result; - unsigned char *status = us->iobuf; - unsigned char registers[32]; - unsigned char data[32]; - unsigned int len; - int i; - - len = scsi_bufflen(srb); - - /* Send A0 (ATA PACKET COMMAND). - Note: I guess we're never going to get any of the ATA - commands... just ATA Packet Commands. - */ - - registers[0] = USBAT_ATA_FEATURES; - registers[1] = USBAT_ATA_SECCNT; - registers[2] = USBAT_ATA_SECNUM; - registers[3] = USBAT_ATA_LBA_ME; - registers[4] = USBAT_ATA_LBA_HI; - registers[5] = USBAT_ATA_DEVICE; - registers[6] = USBAT_ATA_CMD; - data[0] = 0x00; - data[1] = 0x00; - data[2] = 0x00; - data[3] = len&0xFF; /* (cylL) = expected length (L) */ - data[4] = (len>>8)&0xFF; /* (cylH) = expected length (H) */ - data[5] = 0xB0; /* (device sel) = slave */ - data[6] = 0xA0; /* (command) = ATA PACKET COMMAND */ - - for (i=7; i<19; i++) { - registers[i] = 0x10; - data[i] = (i-7 >= srb->cmd_len) ? 0 : srb->cmnd[i-7]; - } - - result = usbat_get_status(us, status); - US_DEBUGP("Status = %02X\n", *status); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - if (srb->cmnd[0] == TEST_UNIT_READY) - transferred = 0; - - if (srb->sc_data_direction == DMA_TO_DEVICE) { - - result = usbat_hp8200e_rw_block_test(us, USBAT_ATA, - registers, data, 19, - USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD, - (USBAT_QUAL_FCQ | USBAT_QUAL_ALQ), - DMA_TO_DEVICE, - scsi_sglist(srb), - len, scsi_sg_count(srb), 10); - - if (result == USB_STOR_TRANSPORT_GOOD) { - transferred += len; - US_DEBUGP("Wrote %08X bytes\n", transferred); - } - - return result; - - } else if (srb->cmnd[0] == READ_10 || - srb->cmnd[0] == GPCMD_READ_CD) { - - return usbat_hp8200e_handle_read10(us, registers, data, srb); - - } - - if (len > 0xFFFF) { - US_DEBUGP("Error: len = %08X... what do I do now?\n", - len); - return USB_STOR_TRANSPORT_ERROR; - } - - result = usbat_multiple_write(us, registers, data, 7); - - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - - /* - * Write the 12-byte command header. - * - * If the command is BLANK then set the timer for 75 minutes. - * Otherwise set it for 10 minutes. - * - * NOTE: THE 8200 DOCUMENTATION STATES THAT BLANKING A CDRW - * AT SPEED 4 IS UNRELIABLE!!! - */ - - result = usbat_write_block(us, USBAT_ATA, srb->cmnd, 12, - srb->cmnd[0] == GPCMD_BLANK ? 75 : 10, 0); - - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - - /* If there is response data to be read in then do it here. */ - - if (len != 0 && (srb->sc_data_direction == DMA_FROM_DEVICE)) { - - /* How many bytes to read in? Check cylL register */ - - if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) != - USB_STOR_XFER_GOOD) { - return USB_STOR_TRANSPORT_ERROR; - } - - if (len > 0xFF) { /* need to read cylH also */ - len = *status; - if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_HI, status) != - USB_STOR_XFER_GOOD) { - return USB_STOR_TRANSPORT_ERROR; - } - len += ((unsigned int) *status)<<8; - } - else - len = *status; - - - result = usbat_read_block(us, scsi_sglist(srb), len, - scsi_sg_count(srb)); - } - - return result; -} - -/* - * Transport for USBAT02-based CompactFlash and similar storage devices - */ -static int usbat_flash_transport(struct scsi_cmnd * srb, struct us_data *us) -{ - int rc; - struct usbat_info *info = (struct usbat_info *) (us->extra); - unsigned long block, blocks; - unsigned char *ptr = us->iobuf; - static unsigned char inquiry_response[36] = { - 0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00 - }; - - if (srb->cmnd[0] == INQUIRY) { - US_DEBUGP("usbat_flash_transport: INQUIRY. Returning bogus response.\n"); - memcpy(ptr, inquiry_response, sizeof(inquiry_response)); - fill_inquiry_response(us, ptr, 36); - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == READ_CAPACITY) { - rc = usbat_flash_check_media(us, info); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - - rc = usbat_flash_get_sector_count(us, info); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - - /* hard coded 512 byte sectors as per ATA spec */ - info->ssize = 0x200; - US_DEBUGP("usbat_flash_transport: READ_CAPACITY: %ld sectors, %ld bytes per sector\n", - info->sectors, info->ssize); - - /* - * build the reply - * note: must return the sector number of the last sector, - * *not* the total number of sectors - */ - ((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1); - ((__be32 *) ptr)[1] = cpu_to_be32(info->ssize); - usb_stor_set_xfer_buf(ptr, 8, srb); - - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == MODE_SELECT_10) { - US_DEBUGP("usbat_flash_transport: Gah! MODE_SELECT_10.\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - if (srb->cmnd[0] == READ_10) { - block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | - ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); - - blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); - - US_DEBUGP("usbat_flash_transport: READ_10: read block 0x%04lx count %ld\n", block, blocks); - return usbat_flash_read_data(us, info, block, blocks); - } - - if (srb->cmnd[0] == READ_12) { - /* - * I don't think we'll ever see a READ_12 but support it anyway - */ - block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | - ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); - - blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | - ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9])); - - US_DEBUGP("usbat_flash_transport: READ_12: read block 0x%04lx count %ld\n", block, blocks); - return usbat_flash_read_data(us, info, block, blocks); - } - - if (srb->cmnd[0] == WRITE_10) { - block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | - ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); - - blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8])); - - US_DEBUGP("usbat_flash_transport: WRITE_10: write block 0x%04lx count %ld\n", block, blocks); - return usbat_flash_write_data(us, info, block, blocks); - } - - if (srb->cmnd[0] == WRITE_12) { - /* - * I don't think we'll ever see a WRITE_12 but support it anyway - */ - block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) | - ((u32)(srb->cmnd[4]) << 8) | ((u32)(srb->cmnd[5])); - - blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) | - ((u32)(srb->cmnd[8]) << 8) | ((u32)(srb->cmnd[9])); - - US_DEBUGP("usbat_flash_transport: WRITE_12: write block 0x%04lx count %ld\n", block, blocks); - return usbat_flash_write_data(us, info, block, blocks); - } - - - if (srb->cmnd[0] == TEST_UNIT_READY) { - US_DEBUGP("usbat_flash_transport: TEST_UNIT_READY.\n"); - - rc = usbat_flash_check_media(us, info); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; - - return usbat_check_status(us); - } - - if (srb->cmnd[0] == REQUEST_SENSE) { - US_DEBUGP("usbat_flash_transport: REQUEST_SENSE.\n"); - - memset(ptr, 0, 18); - ptr[0] = 0xF0; - ptr[2] = info->sense_key; - ptr[7] = 11; - ptr[12] = info->sense_asc; - ptr[13] = info->sense_ascq; - usb_stor_set_xfer_buf(ptr, 18, srb); - - return USB_STOR_TRANSPORT_GOOD; - } - - if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { - /* - * sure. whatever. not like we can stop the user from popping - * the media out of the device (no locking doors, etc) - */ - return USB_STOR_TRANSPORT_GOOD; - } - - US_DEBUGP("usbat_flash_transport: Gah! Unknown command: %d (0x%x)\n", - srb->cmnd[0], srb->cmnd[0]); - info->sense_key = 0x05; - info->sense_asc = 0x20; - info->sense_ascq = 0x00; - return USB_STOR_TRANSPORT_FAILED; -} - -static int init_usbat_cd(struct us_data *us) -{ - return init_usbat(us, USBAT_DEV_HP8200); -} - -static int init_usbat_flash(struct us_data *us) -{ - return init_usbat(us, USBAT_DEV_FLASH); -} - -static int usbat_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct us_data *us; - int result; - - result = usb_stor_probe1(&us, intf, id, - (id - usbat_usb_ids) + usbat_unusual_dev_list); - if (result) - return result; - - /* The actual transport will be determined later by the - * initialization routine; this is just a placeholder. - */ - us->transport_name = "Shuttle USBAT"; - us->transport = usbat_flash_transport; - us->transport_reset = usb_stor_CB_reset; - us->max_lun = 1; - - result = usb_stor_probe2(us); - return result; -} - -static struct usb_driver usbat_driver = { - .name = "ums-usbat", - .probe = usbat_probe, - .disconnect = usb_stor_disconnect, - .suspend = usb_stor_suspend, - .resume = usb_stor_resume, - .reset_resume = usb_stor_reset_resume, - .pre_reset = usb_stor_pre_reset, - .post_reset = usb_stor_post_reset, - .id_table = usbat_usb_ids, - .soft_unbind = 1, - .no_dynamic_id = 1, -}; - -module_usb_driver(usbat_driver); diff --git a/ANDROID_3.4.5/drivers/usb/storage/sierra_ms.c b/ANDROID_3.4.5/drivers/usb/storage/sierra_ms.c deleted file mode 100644 index 37539c89..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/sierra_ms.c +++ /dev/null @@ -1,207 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "usb.h" -#include "transport.h" -#include "protocol.h" -#include "scsiglue.h" -#include "sierra_ms.h" -#include "debug.h" - -#define SWIMS_USB_REQUEST_SetSwocMode 0x0B -#define SWIMS_USB_REQUEST_GetSwocInfo 0x0A -#define SWIMS_USB_INDEX_SetMode 0x0000 -#define SWIMS_SET_MODE_Modem 0x0001 - -#define TRU_NORMAL 0x01 -#define TRU_FORCE_MS 0x02 -#define TRU_FORCE_MODEM 0x03 - -static unsigned int swi_tru_install = 1; -module_param(swi_tru_install, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(swi_tru_install, "TRU-Install mode (1=Full Logic (def)," - " 2=Force CD-Rom, 3=Force Modem)"); - -struct swoc_info { - __u8 rev; - __u8 reserved[8]; - __u16 LinuxSKU; - __u16 LinuxVer; - __u8 reserved2[47]; -} __attribute__((__packed__)); - -static bool containsFullLinuxPackage(struct swoc_info *swocInfo) -{ - if ((swocInfo->LinuxSKU >= 0x2100 && swocInfo->LinuxSKU <= 0x2FFF) || - (swocInfo->LinuxSKU >= 0x7100 && swocInfo->LinuxSKU <= 0x7FFF)) - return true; - else - return false; -} - -static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSWocMode) -{ - int result; - US_DEBUGP("SWIMS: %s", "DEVICE MODE SWITCH\n"); - result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - SWIMS_USB_REQUEST_SetSwocMode, /* __u8 request */ - USB_TYPE_VENDOR | USB_DIR_OUT, /* __u8 request type */ - eSWocMode, /* __u16 value */ - 0x0000, /* __u16 index */ - NULL, /* void *data */ - 0, /* __u16 size */ - USB_CTRL_SET_TIMEOUT); /* int timeout */ - return result; -} - - -static int sierra_get_swoc_info(struct usb_device *udev, - struct swoc_info *swocInfo) -{ - int result; - - US_DEBUGP("SWIMS: Attempting to get TRU-Install info.\n"); - - result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - SWIMS_USB_REQUEST_GetSwocInfo, /* __u8 request */ - USB_TYPE_VENDOR | USB_DIR_IN, /* __u8 request type */ - 0, /* __u16 value */ - 0, /* __u16 index */ - (void *) swocInfo, /* void *data */ - sizeof(struct swoc_info), /* __u16 size */ - USB_CTRL_SET_TIMEOUT); /* int timeout */ - - swocInfo->LinuxSKU = le16_to_cpu(swocInfo->LinuxSKU); - swocInfo->LinuxVer = le16_to_cpu(swocInfo->LinuxVer); - return result; -} - -static void debug_swoc(struct swoc_info *swocInfo) -{ - US_DEBUGP("SWIMS: SWoC Rev: %02d \n", swocInfo->rev); - US_DEBUGP("SWIMS: Linux SKU: %04X \n", swocInfo->LinuxSKU); - US_DEBUGP("SWIMS: Linux Version: %04X \n", swocInfo->LinuxVer); -} - - -static ssize_t show_truinst(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct swoc_info *swocInfo; - struct usb_interface *intf = to_usb_interface(dev); - struct usb_device *udev = interface_to_usbdev(intf); - int result; - if (swi_tru_install == TRU_FORCE_MS) { - result = snprintf(buf, PAGE_SIZE, "Forced Mass Storage\n"); - } else { - swocInfo = kmalloc(sizeof(struct swoc_info), GFP_KERNEL); - if (!swocInfo) { - US_DEBUGP("SWIMS: Allocation failure\n"); - snprintf(buf, PAGE_SIZE, "Error\n"); - return -ENOMEM; - } - result = sierra_get_swoc_info(udev, swocInfo); - if (result < 0) { - US_DEBUGP("SWIMS: failed SWoC query\n"); - kfree(swocInfo); - snprintf(buf, PAGE_SIZE, "Error\n"); - return -EIO; - } - debug_swoc(swocInfo); - result = snprintf(buf, PAGE_SIZE, - "REV=%02d SKU=%04X VER=%04X\n", - swocInfo->rev, - swocInfo->LinuxSKU, - swocInfo->LinuxVer); - kfree(swocInfo); - } - return result; -} -static DEVICE_ATTR(truinst, S_IRUGO, show_truinst, NULL); - -int sierra_ms_init(struct us_data *us) -{ - int result, retries; - struct swoc_info *swocInfo; - struct usb_device *udev; - struct Scsi_Host *sh; - struct scsi_device *sd; - - retries = 3; - result = 0; - udev = us->pusb_dev; - - sh = us_to_host(us); - sd = scsi_get_host_dev(sh); - - US_DEBUGP("SWIMS: sierra_ms_init called\n"); - - /* Force Modem mode */ - if (swi_tru_install == TRU_FORCE_MODEM) { - US_DEBUGP("SWIMS: %s", "Forcing Modem Mode\n"); - result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem); - if (result < 0) - US_DEBUGP("SWIMS: Failed to switch to modem mode.\n"); - return -EIO; - } - /* Force Mass Storage mode (keep CD-Rom) */ - else if (swi_tru_install == TRU_FORCE_MS) { - US_DEBUGP("SWIMS: %s", "Forcing Mass Storage Mode\n"); - goto complete; - } - /* Normal TRU-Install Logic */ - else { - US_DEBUGP("SWIMS: %s", "Normal SWoC Logic\n"); - - swocInfo = kmalloc(sizeof(struct swoc_info), - GFP_KERNEL); - if (!swocInfo) { - US_DEBUGP("SWIMS: %s", "Allocation failure\n"); - return -ENOMEM; - } - - retries = 3; - do { - retries--; - result = sierra_get_swoc_info(udev, swocInfo); - if (result < 0) { - US_DEBUGP("SWIMS: %s", "Failed SWoC query\n"); - schedule_timeout_uninterruptible(2*HZ); - } - } while (retries && result < 0); - - if (result < 0) { - US_DEBUGP("SWIMS: %s", - "Completely failed SWoC query\n"); - kfree(swocInfo); - return -EIO; - } - - debug_swoc(swocInfo); - - /* If there is not Linux software on the TRU-Install device - * then switch to modem mode - */ - if (!containsFullLinuxPackage(swocInfo)) { - US_DEBUGP("SWIMS: %s", - "Switching to Modem Mode\n"); - result = sierra_set_ms_mode(udev, - SWIMS_SET_MODE_Modem); - if (result < 0) - US_DEBUGP("SWIMS: Failed to switch modem\n"); - kfree(swocInfo); - return -EIO; - } - kfree(swocInfo); - } -complete: - result = device_create_file(&us->pusb_intf->dev, &dev_attr_truinst); - - return 0; -} - diff --git a/ANDROID_3.4.5/drivers/usb/storage/sierra_ms.h b/ANDROID_3.4.5/drivers/usb/storage/sierra_ms.h deleted file mode 100644 index bb48634a..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/sierra_ms.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef _SIERRA_MS_H_ -#define _SIERRA_MS_H_ -extern int sierra_ms_init(struct us_data *us); -#endif diff --git a/ANDROID_3.4.5/drivers/usb/storage/transport.c b/ANDROID_3.4.5/drivers/usb/storage/transport.c deleted file mode 100644 index c70109e5..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/transport.c +++ /dev/null @@ -1,1353 +0,0 @@ -/* Driver for USB Mass Storage compliant devices - * - * Current development and maintenance by: - * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * Developed with the assistance of: - * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) - * (c) 2000 Stephen J. Gowdy (SGowdy@lbl.gov) - * (c) 2002 Alan Stern - * - * Initial work by: - * (c) 1999 Michael Gee (michael@linuxspecific.com) - * - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI and ATAPI commands in - * mind when they created this document. The commands are all very - * similar to commands in the SCSI-II and ATAPI specifications. - * - * It is important to note that in a number of cases this class - * exhibits class-specific exemptions from the USB specification. - * Notably the usage of NAK, STALL and ACK differs from the norm, in - * that they are used to communicate wait, failed and OK on commands. - * - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include "usb.h" -#include "transport.h" -#include "protocol.h" -#include "scsiglue.h" -#include "debug.h" - -#include -#include "../../scsi/sd.h" - - -/*********************************************************************** - * Data transfer routines - ***********************************************************************/ - -/* - * This is subtle, so pay attention: - * --------------------------------- - * We're very concerned about races with a command abort. Hanging this code - * is a sure fire way to hang the kernel. (Note that this discussion applies - * only to transactions resulting from a scsi queued-command, since only - * these transactions are subject to a scsi abort. Other transactions, such - * as those occurring during device-specific initialization, must be handled - * by a separate code path.) - * - * The abort function (usb_storage_command_abort() in scsiglue.c) first - * sets the machine state and the ABORTING bit in us->dflags to prevent - * new URBs from being submitted. It then calls usb_stor_stop_transport() - * below, which atomically tests-and-clears the URB_ACTIVE bit in us->dflags - * to see if the current_urb needs to be stopped. Likewise, the SG_ACTIVE - * bit is tested to see if the current_sg scatter-gather request needs to be - * stopped. The timeout callback routine does much the same thing. - * - * When a disconnect occurs, the DISCONNECTING bit in us->dflags is set to - * prevent new URBs from being submitted, and usb_stor_stop_transport() is - * called to stop any ongoing requests. - * - * The submit function first verifies that the submitting is allowed - * (neither ABORTING nor DISCONNECTING bits are set) and that the submit - * completes without errors, and only then sets the URB_ACTIVE bit. This - * prevents the stop_transport() function from trying to cancel the URB - * while the submit call is underway. Next, the submit function must test - * the flags to see if an abort or disconnect occurred during the submission - * or before the URB_ACTIVE bit was set. If so, it's essential to cancel - * the URB if it hasn't been cancelled already (i.e., if the URB_ACTIVE bit - * is still set). Either way, the function must then wait for the URB to - * finish. Note that the URB can still be in progress even after a call to - * usb_unlink_urb() returns. - * - * The idea is that (1) once the ABORTING or DISCONNECTING bit is set, - * either the stop_transport() function or the submitting function - * is guaranteed to call usb_unlink_urb() for an active URB, - * and (2) test_and_clear_bit() prevents usb_unlink_urb() from being - * called more than once or from being called during usb_submit_urb(). - */ - -/* This is the completion handler which will wake us up when an URB - * completes. - */ -static void usb_stor_blocking_completion(struct urb *urb) -{ - struct completion *urb_done_ptr = urb->context; - - complete(urb_done_ptr); -} - -/* This is the common part of the URB message submission code - * - * All URBs from the usb-storage driver involved in handling a queued scsi - * command _must_ pass through this function (or something like it) for the - * abort mechanisms to work properly. - */ -static int usb_stor_msg_common(struct us_data *us, int timeout) -{ - struct completion urb_done; - long timeleft; - int status; - - /* don't submit URBs during abort processing */ - if (test_bit(US_FLIDX_ABORTING, &us->dflags)) - return -EIO; - - /* set up data structures for the wakeup system */ - init_completion(&urb_done); - - /* fill the common fields in the URB */ - us->current_urb->context = &urb_done; - us->current_urb->transfer_flags = 0; - - /* we assume that if transfer_buffer isn't us->iobuf then it - * hasn't been mapped for DMA. Yes, this is clunky, but it's - * easier than always having the caller tell us whether the - * transfer buffer has already been mapped. */ - if (us->current_urb->transfer_buffer == us->iobuf) - us->current_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - us->current_urb->transfer_dma = us->iobuf_dma; - - /* submit the URB */ - status = usb_submit_urb(us->current_urb, GFP_NOIO); - if (status) { - /* something went wrong */ - return status; - } - - /* since the URB has been submitted successfully, it's now okay - * to cancel it */ - set_bit(US_FLIDX_URB_ACTIVE, &us->dflags); - - /* did an abort occur during the submission? */ - if (test_bit(US_FLIDX_ABORTING, &us->dflags)) { - - /* cancel the URB, if it hasn't been cancelled already */ - if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags)) { - US_DEBUGP("-- cancelling URB\n"); - usb_unlink_urb(us->current_urb); - } - } - - /* wait for the completion of the URB */ - timeleft = wait_for_completion_interruptible_timeout( - &urb_done, timeout ? : MAX_SCHEDULE_TIMEOUT); - - clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags); - - if (timeleft <= 0) { - US_DEBUGP("%s -- cancelling URB\n", - timeleft == 0 ? "Timeout" : "Signal"); - usb_kill_urb(us->current_urb); - } - - /* return the URB status */ - return us->current_urb->status; -} - -/* - * Transfer one control message, with timeouts, and allowing early - * termination. Return codes are usual -Exxx, *not* USB_STOR_XFER_xxx. - */ -int usb_stor_control_msg(struct us_data *us, unsigned int pipe, - u8 request, u8 requesttype, u16 value, u16 index, - void *data, u16 size, int timeout) -{ - int status; - - US_DEBUGP("%s: rq=%02x rqtype=%02x value=%04x index=%02x len=%u\n", - __func__, request, requesttype, - value, index, size); - - /* fill in the devrequest structure */ - us->cr->bRequestType = requesttype; - us->cr->bRequest = request; - us->cr->wValue = cpu_to_le16(value); - us->cr->wIndex = cpu_to_le16(index); - us->cr->wLength = cpu_to_le16(size); - - /* fill and submit the URB */ - usb_fill_control_urb(us->current_urb, us->pusb_dev, pipe, - (unsigned char*) us->cr, data, size, - usb_stor_blocking_completion, NULL); - status = usb_stor_msg_common(us, timeout); - - /* return the actual length of the data transferred if no error */ - if (status == 0) - status = us->current_urb->actual_length; - return status; -} -EXPORT_SYMBOL_GPL(usb_stor_control_msg); - -/* This is a version of usb_clear_halt() that allows early termination and - * doesn't read the status from the device -- this is because some devices - * crash their internal firmware when the status is requested after a halt. - * - * A definitive list of these 'bad' devices is too difficult to maintain or - * make complete enough to be useful. This problem was first observed on the - * Hagiwara FlashGate DUAL unit. However, bus traces reveal that neither - * MacOS nor Windows checks the status after clearing a halt. - * - * Since many vendors in this space limit their testing to interoperability - * with these two OSes, specification violations like this one are common. - */ -int usb_stor_clear_halt(struct us_data *us, unsigned int pipe) -{ - int result; - int endp = usb_pipeendpoint(pipe); - - if (usb_pipein (pipe)) - endp |= USB_DIR_IN; - - result = usb_stor_control_msg(us, us->send_ctrl_pipe, - USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, - USB_ENDPOINT_HALT, endp, - NULL, 0, 3*HZ); - - if (result >= 0) - usb_reset_endpoint(us->pusb_dev, endp); - - US_DEBUGP("%s: result = %d\n", __func__, result); - return result; -} -EXPORT_SYMBOL_GPL(usb_stor_clear_halt); - - -/* - * Interpret the results of a URB transfer - * - * This function prints appropriate debugging messages, clears halts on - * non-control endpoints, and translates the status to the corresponding - * USB_STOR_XFER_xxx return code. - */ -static int interpret_urb_result(struct us_data *us, unsigned int pipe, - unsigned int length, int result, unsigned int partial) -{ - US_DEBUGP("Status code %d; transferred %u/%u\n", - result, partial, length); - switch (result) { - - /* no error code; did we send all the data? */ - case 0: - if (partial != length) { - US_DEBUGP("-- short transfer\n"); - return USB_STOR_XFER_SHORT; - } - - US_DEBUGP("-- transfer complete\n"); - return USB_STOR_XFER_GOOD; - - /* stalled */ - case -EPIPE: - /* for control endpoints, (used by CB[I]) a stall indicates - * a failed command */ - if (usb_pipecontrol(pipe)) { - US_DEBUGP("-- stall on control pipe\n"); - return USB_STOR_XFER_STALLED; - } - - /* for other sorts of endpoint, clear the stall */ - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - if (usb_stor_clear_halt(us, pipe) < 0) - return USB_STOR_XFER_ERROR; - return USB_STOR_XFER_STALLED; - - /* babble - the device tried to send more than we wanted to read */ - case -EOVERFLOW: - US_DEBUGP("-- babble\n"); - return USB_STOR_XFER_LONG; - - /* the transfer was cancelled by abort, disconnect, or timeout */ - case -ECONNRESET: - US_DEBUGP("-- transfer cancelled\n"); - return USB_STOR_XFER_ERROR; - - /* short scatter-gather read transfer */ - case -EREMOTEIO: - US_DEBUGP("-- short read transfer\n"); - return USB_STOR_XFER_SHORT; - - /* abort or disconnect in progress */ - case -EIO: - US_DEBUGP("-- abort or disconnect in progress\n"); - return USB_STOR_XFER_ERROR; - - /* the catch-all error case */ - default: - US_DEBUGP("-- unknown error\n"); - return USB_STOR_XFER_ERROR; - } -} - -/* - * Transfer one control message, without timeouts, but allowing early - * termination. Return codes are USB_STOR_XFER_xxx. - */ -int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe, - u8 request, u8 requesttype, u16 value, u16 index, - void *data, u16 size) -{ - int result; - - US_DEBUGP("%s: rq=%02x rqtype=%02x value=%04x index=%02x len=%u\n", - __func__, request, requesttype, - value, index, size); - - /* fill in the devrequest structure */ - us->cr->bRequestType = requesttype; - us->cr->bRequest = request; - us->cr->wValue = cpu_to_le16(value); - us->cr->wIndex = cpu_to_le16(index); - us->cr->wLength = cpu_to_le16(size); - - /* fill and submit the URB */ - usb_fill_control_urb(us->current_urb, us->pusb_dev, pipe, - (unsigned char*) us->cr, data, size, - usb_stor_blocking_completion, NULL); - result = usb_stor_msg_common(us, 0); - - return interpret_urb_result(us, pipe, size, result, - us->current_urb->actual_length); -} -EXPORT_SYMBOL_GPL(usb_stor_ctrl_transfer); - -/* - * Receive one interrupt buffer, without timeouts, but allowing early - * termination. Return codes are USB_STOR_XFER_xxx. - * - * This routine always uses us->recv_intr_pipe as the pipe and - * us->ep_bInterval as the interrupt interval. - */ -static int usb_stor_intr_transfer(struct us_data *us, void *buf, - unsigned int length) -{ - int result; - unsigned int pipe = us->recv_intr_pipe; - unsigned int maxp; - - US_DEBUGP("%s: xfer %u bytes\n", __func__, length); - - /* calculate the max packet size */ - maxp = usb_maxpacket(us->pusb_dev, pipe, usb_pipeout(pipe)); - if (maxp > length) - maxp = length; - - /* fill and submit the URB */ - usb_fill_int_urb(us->current_urb, us->pusb_dev, pipe, buf, - maxp, usb_stor_blocking_completion, NULL, - us->ep_bInterval); - result = usb_stor_msg_common(us, 0); - - return interpret_urb_result(us, pipe, length, result, - us->current_urb->actual_length); -} - -/* - * Transfer one buffer via bulk pipe, without timeouts, but allowing early - * termination. Return codes are USB_STOR_XFER_xxx. If the bulk pipe - * stalls during the transfer, the halt is automatically cleared. - */ -int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, - void *buf, unsigned int length, unsigned int *act_len) -{ - int result; - - US_DEBUGP("%s: xfer %u bytes\n", __func__, length); - - /* fill and submit the URB */ - usb_fill_bulk_urb(us->current_urb, us->pusb_dev, pipe, buf, length, - usb_stor_blocking_completion, NULL); - result = usb_stor_msg_common(us, 0); - - /* store the actual length of the data transferred */ - if (act_len) - *act_len = us->current_urb->actual_length; - return interpret_urb_result(us, pipe, length, result, - us->current_urb->actual_length); -} -EXPORT_SYMBOL_GPL(usb_stor_bulk_transfer_buf); - -/* - * Transfer a scatter-gather list via bulk transfer - * - * This function does basically the same thing as usb_stor_bulk_transfer_buf() - * above, but it uses the usbcore scatter-gather library. - */ -static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe, - struct scatterlist *sg, int num_sg, unsigned int length, - unsigned int *act_len) -{ - int result; - - /* don't submit s-g requests during abort processing */ - if (test_bit(US_FLIDX_ABORTING, &us->dflags)) - return USB_STOR_XFER_ERROR; - - /* initialize the scatter-gather request block */ - US_DEBUGP("%s: xfer %u bytes, %d entries\n", __func__, - length, num_sg); - result = usb_sg_init(&us->current_sg, us->pusb_dev, pipe, 0, - sg, num_sg, length, GFP_NOIO); - if (result) { - US_DEBUGP("usb_sg_init returned %d\n", result); - return USB_STOR_XFER_ERROR; - } - - /* since the block has been initialized successfully, it's now - * okay to cancel it */ - set_bit(US_FLIDX_SG_ACTIVE, &us->dflags); - - /* did an abort occur during the submission? */ - if (test_bit(US_FLIDX_ABORTING, &us->dflags)) { - - /* cancel the request, if it hasn't been cancelled already */ - if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags)) { - US_DEBUGP("-- cancelling sg request\n"); - usb_sg_cancel(&us->current_sg); - } - } - - /* wait for the completion of the transfer */ - usb_sg_wait(&us->current_sg); - clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags); - - result = us->current_sg.status; - if (act_len) - *act_len = us->current_sg.bytes; - return interpret_urb_result(us, pipe, length, result, - us->current_sg.bytes); -} - -/* - * Common used function. Transfer a complete command - * via usb_stor_bulk_transfer_sglist() above. Set cmnd resid - */ -int usb_stor_bulk_srb(struct us_data* us, unsigned int pipe, - struct scsi_cmnd* srb) -{ - unsigned int partial; - int result = usb_stor_bulk_transfer_sglist(us, pipe, scsi_sglist(srb), - scsi_sg_count(srb), scsi_bufflen(srb), - &partial); - - scsi_set_resid(srb, scsi_bufflen(srb) - partial); - return result; -} -EXPORT_SYMBOL_GPL(usb_stor_bulk_srb); - -/* - * Transfer an entire SCSI command's worth of data payload over the bulk - * pipe. - * - * Note that this uses usb_stor_bulk_transfer_buf() and - * usb_stor_bulk_transfer_sglist() to achieve its goals -- - * this function simply determines whether we're going to use - * scatter-gather or not, and acts appropriately. - */ -int usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe, - void *buf, unsigned int length_left, int use_sg, int *residual) -{ - int result; - unsigned int partial; - - /* are we scatter-gathering? */ - if (use_sg) { - /* use the usb core scatter-gather primitives */ - result = usb_stor_bulk_transfer_sglist(us, pipe, - (struct scatterlist *) buf, use_sg, - length_left, &partial); - length_left -= partial; - } else { - /* no scatter-gather, just make the request */ - result = usb_stor_bulk_transfer_buf(us, pipe, buf, - length_left, &partial); - length_left -= partial; - } - - /* store the residual and return the error code */ - if (residual) - *residual = length_left; - return result; -} -EXPORT_SYMBOL_GPL(usb_stor_bulk_transfer_sg); - -/*********************************************************************** - * Transport routines - ***********************************************************************/ - -/* There are so many devices that report the capacity incorrectly, - * this routine was written to counteract some of the resulting - * problems. - */ -static void last_sector_hacks(struct us_data *us, struct scsi_cmnd *srb) -{ - struct gendisk *disk; - struct scsi_disk *sdkp; - u32 sector; - - /* To Report "Medium Error: Record Not Found */ - static unsigned char record_not_found[18] = { - [0] = 0x70, /* current error */ - [2] = MEDIUM_ERROR, /* = 0x03 */ - [7] = 0x0a, /* additional length */ - [12] = 0x14 /* Record Not Found */ - }; - - /* If last-sector problems can't occur, whether because the - * capacity was already decremented or because the device is - * known to report the correct capacity, then we don't need - * to do anything. - */ - if (!us->use_last_sector_hacks) - return; - - /* Was this command a READ(10) or a WRITE(10)? */ - if (srb->cmnd[0] != READ_10 && srb->cmnd[0] != WRITE_10) - goto done; - - /* Did this command access the last sector? */ - sector = (srb->cmnd[2] << 24) | (srb->cmnd[3] << 16) | - (srb->cmnd[4] << 8) | (srb->cmnd[5]); - disk = srb->request->rq_disk; - if (!disk) - goto done; - sdkp = scsi_disk(disk); - if (!sdkp) - goto done; - if (sector + 1 != sdkp->capacity) - goto done; - - if (srb->result == SAM_STAT_GOOD && scsi_get_resid(srb) == 0) { - - /* The command succeeded. We know this device doesn't - * have the last-sector bug, so stop checking it. - */ - us->use_last_sector_hacks = 0; - - } else { - /* The command failed. Allow up to 3 retries in case this - * is some normal sort of failure. After that, assume the - * capacity is wrong and we're trying to access the sector - * beyond the end. Replace the result code and sense data - * with values that will cause the SCSI core to fail the - * command immediately, instead of going into an infinite - * (or even just a very long) retry loop. - */ - if (++us->last_sector_retries < 3) - return; - srb->result = SAM_STAT_CHECK_CONDITION; - memcpy(srb->sense_buffer, record_not_found, - sizeof(record_not_found)); - } - - done: - /* Don't reset the retry counter for TEST UNIT READY commands, - * because they get issued after device resets which might be - * caused by a failed last-sector access. - */ - if (srb->cmnd[0] != TEST_UNIT_READY) - us->last_sector_retries = 0; -} - -/* Invoke the transport and basic error-handling/recovery methods - * - * This is used by the protocol layers to actually send the message to - * the device and receive the response. - */ -void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) -{ - int need_auto_sense; - int result; - - /* send the command to the transport layer */ - scsi_set_resid(srb, 0); - result = us->transport(srb, us); - - /* if the command gets aborted by the higher layers, we need to - * short-circuit all other processing - */ - if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { - US_DEBUGP("-- command was aborted\n"); - srb->result = DID_ABORT << 16; - goto Handle_Errors; - } - - /* if there is a transport error, reset and don't auto-sense */ - if (result == USB_STOR_TRANSPORT_ERROR) { - US_DEBUGP("-- transport indicates error, resetting\n"); - srb->result = DID_ERROR << 16; - goto Handle_Errors; - } - - /* if the transport provided its own sense data, don't auto-sense */ - if (result == USB_STOR_TRANSPORT_NO_SENSE) { - srb->result = SAM_STAT_CHECK_CONDITION; - last_sector_hacks(us, srb); - return; - } - - srb->result = SAM_STAT_GOOD; - - /* Determine if we need to auto-sense - * - * I normally don't use a flag like this, but it's almost impossible - * to understand what's going on here if I don't. - */ - need_auto_sense = 0; - - /* - * If we're running the CB transport, which is incapable - * of determining status on its own, we will auto-sense - * unless the operation involved a data-in transfer. Devices - * can signal most data-in errors by stalling the bulk-in pipe. - */ - if ((us->protocol == USB_PR_CB || us->protocol == USB_PR_DPCM_USB) && - srb->sc_data_direction != DMA_FROM_DEVICE) { - US_DEBUGP("-- CB transport device requiring auto-sense\n"); - need_auto_sense = 1; - } - - /* - * If we have a failure, we're going to do a REQUEST_SENSE - * automatically. Note that we differentiate between a command - * "failure" and an "error" in the transport mechanism. - */ - if (result == USB_STOR_TRANSPORT_FAILED) { - US_DEBUGP("-- transport indicates command failure\n"); - need_auto_sense = 1; - } - - /* - * Determine if this device is SAT by seeing if the - * command executed successfully. Otherwise we'll have - * to wait for at least one CHECK_CONDITION to determine - * SANE_SENSE support - */ - if (unlikely((srb->cmnd[0] == ATA_16 || srb->cmnd[0] == ATA_12) && - result == USB_STOR_TRANSPORT_GOOD && - !(us->fflags & US_FL_SANE_SENSE) && - !(us->fflags & US_FL_BAD_SENSE) && - !(srb->cmnd[2] & 0x20))) { - US_DEBUGP("-- SAT supported, increasing auto-sense\n"); - us->fflags |= US_FL_SANE_SENSE; - } - - /* - * A short transfer on a command where we don't expect it - * is unusual, but it doesn't mean we need to auto-sense. - */ - if ((scsi_get_resid(srb) > 0) && - !((srb->cmnd[0] == REQUEST_SENSE) || - (srb->cmnd[0] == INQUIRY) || - (srb->cmnd[0] == MODE_SENSE) || - (srb->cmnd[0] == LOG_SENSE) || - (srb->cmnd[0] == MODE_SENSE_10))) { - US_DEBUGP("-- unexpectedly short transfer\n"); - } - - /* Now, if we need to do the auto-sense, let's do it */ - if (need_auto_sense) { - int temp_result; - struct scsi_eh_save ses; - int sense_size = US_SENSE_SIZE; - struct scsi_sense_hdr sshdr; - const u8 *scdd; - u8 fm_ili; - - /* device supports and needs bigger sense buffer */ - if (us->fflags & US_FL_SANE_SENSE) - sense_size = ~0; -Retry_Sense: - US_DEBUGP("Issuing auto-REQUEST_SENSE\n"); - - scsi_eh_prep_cmnd(srb, &ses, NULL, 0, sense_size); - - /* FIXME: we must do the protocol translation here */ - if (us->subclass == USB_SC_RBC || us->subclass == USB_SC_SCSI || - us->subclass == USB_SC_CYP_ATACB) - srb->cmd_len = 6; - else - srb->cmd_len = 12; - - /* issue the auto-sense command */ - scsi_set_resid(srb, 0); - temp_result = us->transport(us->srb, us); - - /* let's clean up right away */ - scsi_eh_restore_cmnd(srb, &ses); - - if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { - US_DEBUGP("-- auto-sense aborted\n"); - srb->result = DID_ABORT << 16; - - /* If SANE_SENSE caused this problem, disable it */ - if (sense_size != US_SENSE_SIZE) { - us->fflags &= ~US_FL_SANE_SENSE; - us->fflags |= US_FL_BAD_SENSE; - } - goto Handle_Errors; - } - - /* Some devices claim to support larger sense but fail when - * trying to request it. When a transport failure happens - * using US_FS_SANE_SENSE, we always retry with a standard - * (small) sense request. This fixes some USB GSM modems - */ - if (temp_result == USB_STOR_TRANSPORT_FAILED && - sense_size != US_SENSE_SIZE) { - US_DEBUGP("-- auto-sense failure, retry small sense\n"); - sense_size = US_SENSE_SIZE; - us->fflags &= ~US_FL_SANE_SENSE; - us->fflags |= US_FL_BAD_SENSE; - goto Retry_Sense; - } - - /* Other failures */ - if (temp_result != USB_STOR_TRANSPORT_GOOD) { - US_DEBUGP("-- auto-sense failure\n"); - - /* we skip the reset if this happens to be a - * multi-target device, since failure of an - * auto-sense is perfectly valid - */ - srb->result = DID_ERROR << 16; - if (!(us->fflags & US_FL_SCM_MULT_TARG)) - goto Handle_Errors; - return; - } - - /* If the sense data returned is larger than 18-bytes then we - * assume this device supports requesting more in the future. - * The response code must be 70h through 73h inclusive. - */ - if (srb->sense_buffer[7] > (US_SENSE_SIZE - 8) && - !(us->fflags & US_FL_SANE_SENSE) && - !(us->fflags & US_FL_BAD_SENSE) && - (srb->sense_buffer[0] & 0x7C) == 0x70) { - US_DEBUGP("-- SANE_SENSE support enabled\n"); - us->fflags |= US_FL_SANE_SENSE; - - /* Indicate to the user that we truncated their sense - * because we didn't know it supported larger sense. - */ - US_DEBUGP("-- Sense data truncated to %i from %i\n", - US_SENSE_SIZE, - srb->sense_buffer[7] + 8); - srb->sense_buffer[7] = (US_SENSE_SIZE - 8); - } - - scsi_normalize_sense(srb->sense_buffer, SCSI_SENSE_BUFFERSIZE, - &sshdr); - - US_DEBUGP("-- Result from auto-sense is %d\n", temp_result); - US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n", - sshdr.response_code, sshdr.sense_key, - sshdr.asc, sshdr.ascq); -#ifdef CONFIG_USB_STORAGE_DEBUG - usb_stor_show_sense(sshdr.sense_key, sshdr.asc, sshdr.ascq); -#endif - - /* set the result so the higher layers expect this data */ - srb->result = SAM_STAT_CHECK_CONDITION; - - scdd = scsi_sense_desc_find(srb->sense_buffer, - SCSI_SENSE_BUFFERSIZE, 4); - fm_ili = (scdd ? scdd[3] : srb->sense_buffer[2]) & 0xA0; - - /* We often get empty sense data. This could indicate that - * everything worked or that there was an unspecified - * problem. We have to decide which. - */ - if (sshdr.sense_key == 0 && sshdr.asc == 0 && sshdr.ascq == 0 && - fm_ili == 0) { - /* If things are really okay, then let's show that. - * Zero out the sense buffer so the higher layers - * won't realize we did an unsolicited auto-sense. - */ - if (result == USB_STOR_TRANSPORT_GOOD) { - srb->result = SAM_STAT_GOOD; - srb->sense_buffer[0] = 0x0; - - /* If there was a problem, report an unspecified - * hardware error to prevent the higher layers from - * entering an infinite retry loop. - */ - } else { - srb->result = DID_ERROR << 16; - if ((sshdr.response_code & 0x72) == 0x72) - srb->sense_buffer[1] = HARDWARE_ERROR; - else - srb->sense_buffer[2] = HARDWARE_ERROR; - } - } - } - - /* - * Some devices don't work or return incorrect data the first - * time they get a READ(10) command, or for the first READ(10) - * after a media change. If the INITIAL_READ10 flag is set, - * keep track of whether READ(10) commands succeed. If the - * previous one succeeded and this one failed, set the REDO_READ10 - * flag to force a retry. - */ - if (unlikely((us->fflags & US_FL_INITIAL_READ10) && - srb->cmnd[0] == READ_10)) { - if (srb->result == SAM_STAT_GOOD) { - set_bit(US_FLIDX_READ10_WORKED, &us->dflags); - } else if (test_bit(US_FLIDX_READ10_WORKED, &us->dflags)) { - clear_bit(US_FLIDX_READ10_WORKED, &us->dflags); - set_bit(US_FLIDX_REDO_READ10, &us->dflags); - } - - /* - * Next, if the REDO_READ10 flag is set, return a result - * code that will cause the SCSI core to retry the READ(10) - * command immediately. - */ - if (test_bit(US_FLIDX_REDO_READ10, &us->dflags)) { - clear_bit(US_FLIDX_REDO_READ10, &us->dflags); - srb->result = DID_IMM_RETRY << 16; - srb->sense_buffer[0] = 0; - } - } - - /* Did we transfer less than the minimum amount required? */ - if ((srb->result == SAM_STAT_GOOD || srb->sense_buffer[2] == 0) && - scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow) - srb->result = DID_ERROR << 16; - - last_sector_hacks(us, srb); - return; - - /* Error and abort processing: try to resynchronize with the device - * by issuing a port reset. If that fails, try a class-specific - * device reset. */ - Handle_Errors: - - /* Set the RESETTING bit, and clear the ABORTING bit so that - * the reset may proceed. */ - scsi_lock(us_to_host(us)); - set_bit(US_FLIDX_RESETTING, &us->dflags); - clear_bit(US_FLIDX_ABORTING, &us->dflags); - scsi_unlock(us_to_host(us)); - - /* We must release the device lock because the pre_reset routine - * will want to acquire it. */ - mutex_unlock(&us->dev_mutex); - result = usb_stor_port_reset(us); - mutex_lock(&us->dev_mutex); - - if (result < 0) { - scsi_lock(us_to_host(us)); - usb_stor_report_device_reset(us); - scsi_unlock(us_to_host(us)); - us->transport_reset(us); - } - clear_bit(US_FLIDX_RESETTING, &us->dflags); - last_sector_hacks(us, srb); -} - -/* Stop the current URB transfer */ -void usb_stor_stop_transport(struct us_data *us) -{ - US_DEBUGP("%s called\n", __func__); - - /* If the state machine is blocked waiting for an URB, - * let's wake it up. The test_and_clear_bit() call - * guarantees that if a URB has just been submitted, - * it won't be cancelled more than once. */ - if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags)) { - US_DEBUGP("-- cancelling URB\n"); - usb_unlink_urb(us->current_urb); - } - - /* If we are waiting for a scatter-gather operation, cancel it. */ - if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags)) { - US_DEBUGP("-- cancelling sg request\n"); - usb_sg_cancel(&us->current_sg); - } -} - -/* - * Control/Bulk and Control/Bulk/Interrupt transport - */ - -int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us) -{ - unsigned int transfer_length = scsi_bufflen(srb); - unsigned int pipe = 0; - int result; - - /* COMMAND STAGE */ - /* let's send the command via the control pipe */ - result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, - US_CBI_ADSC, - USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, - us->ifnum, srb->cmnd, srb->cmd_len); - - /* check the return code for the command */ - US_DEBUGP("Call to usb_stor_ctrl_transfer() returned %d\n", result); - - /* if we stalled the command, it means command failed */ - if (result == USB_STOR_XFER_STALLED) { - return USB_STOR_TRANSPORT_FAILED; - } - - /* Uh oh... serious problem here */ - if (result != USB_STOR_XFER_GOOD) { - return USB_STOR_TRANSPORT_ERROR; - } - - /* DATA STAGE */ - /* transfer the data payload for this command, if one exists*/ - if (transfer_length) { - pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? - us->recv_bulk_pipe : us->send_bulk_pipe; - result = usb_stor_bulk_srb(us, pipe, srb); - US_DEBUGP("CBI data stage result is 0x%x\n", result); - - /* if we stalled the data transfer it means command failed */ - if (result == USB_STOR_XFER_STALLED) - return USB_STOR_TRANSPORT_FAILED; - if (result > USB_STOR_XFER_STALLED) - return USB_STOR_TRANSPORT_ERROR; - } - - /* STATUS STAGE */ - - /* NOTE: CB does not have a status stage. Silly, I know. So - * we have to catch this at a higher level. - */ - if (us->protocol != USB_PR_CBI) - return USB_STOR_TRANSPORT_GOOD; - - result = usb_stor_intr_transfer(us, us->iobuf, 2); - US_DEBUGP("Got interrupt data (0x%x, 0x%x)\n", - us->iobuf[0], us->iobuf[1]); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - /* UFI gives us ASC and ASCQ, like a request sense - * - * REQUEST_SENSE and INQUIRY don't affect the sense data on UFI - * devices, so we ignore the information for those commands. Note - * that this means we could be ignoring a real error on these - * commands, but that can't be helped. - */ - if (us->subclass == USB_SC_UFI) { - if (srb->cmnd[0] == REQUEST_SENSE || - srb->cmnd[0] == INQUIRY) - return USB_STOR_TRANSPORT_GOOD; - if (us->iobuf[0]) - goto Failed; - return USB_STOR_TRANSPORT_GOOD; - } - - /* If not UFI, we interpret the data as a result code - * The first byte should always be a 0x0. - * - * Some bogus devices don't follow that rule. They stuff the ASC - * into the first byte -- so if it's non-zero, call it a failure. - */ - if (us->iobuf[0]) { - US_DEBUGP("CBI IRQ data showed reserved bType 0x%x\n", - us->iobuf[0]); - goto Failed; - - } - - /* The second byte & 0x0F should be 0x0 for good, otherwise error */ - switch (us->iobuf[1] & 0x0F) { - case 0x00: - return USB_STOR_TRANSPORT_GOOD; - case 0x01: - goto Failed; - } - return USB_STOR_TRANSPORT_ERROR; - - /* the CBI spec requires that the bulk pipe must be cleared - * following any data-in/out command failure (section 2.4.3.1.3) - */ - Failed: - if (pipe) - usb_stor_clear_halt(us, pipe); - return USB_STOR_TRANSPORT_FAILED; -} -EXPORT_SYMBOL_GPL(usb_stor_CB_transport); - -/* - * Bulk only transport - */ - -/* Determine what the maximum LUN supported is */ -int usb_stor_Bulk_max_lun(struct us_data *us) -{ - int result; - - /* issue the command */ - us->iobuf[0] = 0; - result = usb_stor_control_msg(us, us->recv_ctrl_pipe, - US_BULK_GET_MAX_LUN, - USB_DIR_IN | USB_TYPE_CLASS | - USB_RECIP_INTERFACE, - 0, us->ifnum, us->iobuf, 1, 10*HZ); - - US_DEBUGP("GetMaxLUN command result is %d, data is %d\n", - result, us->iobuf[0]); - - /* if we have a successful request, return the result */ - if (result > 0) - return us->iobuf[0]; - - /* - * Some devices don't like GetMaxLUN. They may STALL the control - * pipe, they may return a zero-length result, they may do nothing at - * all and timeout, or they may fail in even more bizarrely creative - * ways. In these cases the best approach is to use the default - * value: only one LUN. - */ - return 0; -} - -int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) -{ - struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; - struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf; - unsigned int transfer_length = scsi_bufflen(srb); - unsigned int residue; - int result; - int fake_sense = 0; - unsigned int cswlen; - unsigned int cbwlen = US_BULK_CB_WRAP_LEN; - - /* Take care of BULK32 devices; set extra byte to 0 */ - if (unlikely(us->fflags & US_FL_BULK32)) { - cbwlen = 32; - us->iobuf[31] = 0; - } - - /* set up the command wrapper */ - bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb->DataTransferLength = cpu_to_le32(transfer_length); - bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ? - US_BULK_FLAG_IN : 0; - bcb->Tag = ++us->tag; - bcb->Lun = srb->device->lun; - if (us->fflags & US_FL_SCM_MULT_TARG) - bcb->Lun |= srb->device->id << 4; - bcb->Length = srb->cmd_len; - - /* copy the command payload */ - memset(bcb->CDB, 0, sizeof(bcb->CDB)); - memcpy(bcb->CDB, srb->cmnd, bcb->Length); - - /* send it to out endpoint */ - US_DEBUGP("Bulk Command S 0x%x T 0x%x L %d F %d Trg %d LUN %d CL %d\n", - le32_to_cpu(bcb->Signature), bcb->Tag, - le32_to_cpu(bcb->DataTransferLength), bcb->Flags, - (bcb->Lun >> 4), (bcb->Lun & 0x0F), - bcb->Length); - result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, - bcb, cbwlen, NULL); - US_DEBUGP("Bulk command transfer result=%d\n", result); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - /* DATA STAGE */ - /* send/receive data payload, if there is any */ - - /* Some USB-IDE converter chips need a 100us delay between the - * command phase and the data phase. Some devices need a little - * more than that, probably because of clock rate inaccuracies. */ - if (unlikely(us->fflags & US_FL_GO_SLOW)) - udelay(125); - - if (transfer_length) { - unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? - us->recv_bulk_pipe : us->send_bulk_pipe; - result = usb_stor_bulk_srb(us, pipe, srb); - US_DEBUGP("Bulk data transfer result 0x%x\n", result); - if (result == USB_STOR_XFER_ERROR) - return USB_STOR_TRANSPORT_ERROR; - - /* If the device tried to send back more data than the - * amount requested, the spec requires us to transfer - * the CSW anyway. Since there's no point retrying the - * the command, we'll return fake sense data indicating - * Illegal Request, Invalid Field in CDB. - */ - if (result == USB_STOR_XFER_LONG) - fake_sense = 1; - } - - /* See flow chart on pg 15 of the Bulk Only Transport spec for - * an explanation of how this code works. - */ - - /* get CSW for device status */ - US_DEBUGP("Attempting to get CSW...\n"); - result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, - bcs, US_BULK_CS_WRAP_LEN, &cswlen); - - /* Some broken devices add unnecessary zero-length packets to the - * end of their data transfers. Such packets show up as 0-length - * CSWs. If we encounter such a thing, try to read the CSW again. - */ - if (result == USB_STOR_XFER_SHORT && cswlen == 0) { - US_DEBUGP("Received 0-length CSW; retrying...\n"); - result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, - bcs, US_BULK_CS_WRAP_LEN, &cswlen); - } - - /* did the attempt to read the CSW fail? */ - if (result == USB_STOR_XFER_STALLED) { - - /* get the status again */ - US_DEBUGP("Attempting to get CSW (2nd try)...\n"); - result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, - bcs, US_BULK_CS_WRAP_LEN, NULL); - } - - /* if we still have a failure at this point, we're in trouble */ - US_DEBUGP("Bulk status result = %d\n", result); - if (result != USB_STOR_XFER_GOOD) - return USB_STOR_TRANSPORT_ERROR; - - /* check bulk status */ - residue = le32_to_cpu(bcs->Residue); - US_DEBUGP("Bulk Status S 0x%x T 0x%x R %u Stat 0x%x\n", - le32_to_cpu(bcs->Signature), bcs->Tag, - residue, bcs->Status); - if (!(bcs->Tag == us->tag || (us->fflags & US_FL_BULK_IGNORE_TAG)) || - bcs->Status > US_BULK_STAT_PHASE) { - US_DEBUGP("Bulk logical error\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - /* Some broken devices report odd signatures, so we do not check them - * for validity against the spec. We store the first one we see, - * and check subsequent transfers for validity against this signature. - */ - if (!us->bcs_signature) { - us->bcs_signature = bcs->Signature; - if (us->bcs_signature != cpu_to_le32(US_BULK_CS_SIGN)) - US_DEBUGP("Learnt BCS signature 0x%08X\n", - le32_to_cpu(us->bcs_signature)); - } else if (bcs->Signature != us->bcs_signature) { - US_DEBUGP("Signature mismatch: got %08X, expecting %08X\n", - le32_to_cpu(bcs->Signature), - le32_to_cpu(us->bcs_signature)); - return USB_STOR_TRANSPORT_ERROR; - } - - /* try to compute the actual residue, based on how much data - * was really transferred and what the device tells us */ - if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE)) { - - /* Heuristically detect devices that generate bogus residues - * by seeing what happens with INQUIRY and READ CAPACITY - * commands. - */ - if (bcs->Status == US_BULK_STAT_OK && - scsi_get_resid(srb) == 0 && - ((srb->cmnd[0] == INQUIRY && - transfer_length == 36) || - (srb->cmnd[0] == READ_CAPACITY && - transfer_length == 8))) { - us->fflags |= US_FL_IGNORE_RESIDUE; - - } else { - residue = min(residue, transfer_length); - scsi_set_resid(srb, max(scsi_get_resid(srb), - (int) residue)); - } - } - - /* based on the status code, we report good or bad */ - switch (bcs->Status) { - case US_BULK_STAT_OK: - /* device babbled -- return fake sense data */ - if (fake_sense) { - memcpy(srb->sense_buffer, - usb_stor_sense_invalidCDB, - sizeof(usb_stor_sense_invalidCDB)); - return USB_STOR_TRANSPORT_NO_SENSE; - } - - /* command good -- note that data could be short */ - return USB_STOR_TRANSPORT_GOOD; - - case US_BULK_STAT_FAIL: - /* command failed */ - return USB_STOR_TRANSPORT_FAILED; - - case US_BULK_STAT_PHASE: - /* phase error -- note that a transport reset will be - * invoked by the invoke_transport() function - */ - return USB_STOR_TRANSPORT_ERROR; - } - - /* we should never get here, but if we do, we're in trouble */ - return USB_STOR_TRANSPORT_ERROR; -} -EXPORT_SYMBOL_GPL(usb_stor_Bulk_transport); - -/*********************************************************************** - * Reset routines - ***********************************************************************/ - -/* This is the common part of the device reset code. - * - * It's handy that every transport mechanism uses the control endpoint for - * resets. - * - * Basically, we send a reset with a 5-second timeout, so we don't get - * jammed attempting to do the reset. - */ -static int usb_stor_reset_common(struct us_data *us, - u8 request, u8 requesttype, - u16 value, u16 index, void *data, u16 size) -{ - int result; - int result2; - - if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) { - US_DEBUGP("No reset during disconnect\n"); - return -EIO; - } - - result = usb_stor_control_msg(us, us->send_ctrl_pipe, - request, requesttype, value, index, data, size, - 5*HZ); - if (result < 0) { - US_DEBUGP("Soft reset failed: %d\n", result); - return result; - } - - /* Give the device some time to recover from the reset, - * but don't delay disconnect processing. */ - wait_event_interruptible_timeout(us->delay_wait, - test_bit(US_FLIDX_DISCONNECTING, &us->dflags), - HZ*6); - if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) { - US_DEBUGP("Reset interrupted by disconnect\n"); - return -EIO; - } - - US_DEBUGP("Soft reset: clearing bulk-in endpoint halt\n"); - result = usb_stor_clear_halt(us, us->recv_bulk_pipe); - - US_DEBUGP("Soft reset: clearing bulk-out endpoint halt\n"); - result2 = usb_stor_clear_halt(us, us->send_bulk_pipe); - - /* return a result code based on the result of the clear-halts */ - if (result >= 0) - result = result2; - if (result < 0) - US_DEBUGP("Soft reset failed\n"); - else - US_DEBUGP("Soft reset done\n"); - return result; -} - -/* This issues a CB[I] Reset to the device in question - */ -#define CB_RESET_CMD_SIZE 12 - -int usb_stor_CB_reset(struct us_data *us) -{ - US_DEBUGP("%s called\n", __func__); - - memset(us->iobuf, 0xFF, CB_RESET_CMD_SIZE); - us->iobuf[0] = SEND_DIAGNOSTIC; - us->iobuf[1] = 4; - return usb_stor_reset_common(us, US_CBI_ADSC, - USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, us->ifnum, us->iobuf, CB_RESET_CMD_SIZE); -} -EXPORT_SYMBOL_GPL(usb_stor_CB_reset); - -/* This issues a Bulk-only Reset to the device in question, including - * clearing the subsequent endpoint halts that may occur. - */ -int usb_stor_Bulk_reset(struct us_data *us) -{ - US_DEBUGP("%s called\n", __func__); - - return usb_stor_reset_common(us, US_BULK_RESET_REQUEST, - USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, us->ifnum, NULL, 0); -} -EXPORT_SYMBOL_GPL(usb_stor_Bulk_reset); - -/* Issue a USB port reset to the device. The caller must not hold - * us->dev_mutex. - */ -int usb_stor_port_reset(struct us_data *us) -{ - int result; - - /*for these devices we must use the class specific method */ - if (us->pusb_dev->quirks & USB_QUIRK_RESET_MORPHS) - return -EPERM; - - result = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf); - if (result < 0) - US_DEBUGP("unable to lock device for reset: %d\n", result); - else { - /* Were we disconnected while waiting for the lock? */ - if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) { - result = -EIO; - US_DEBUGP("No reset during disconnect\n"); - } else { - result = usb_reset_device(us->pusb_dev); - US_DEBUGP("usb_reset_device returns %d\n", - result); - } - usb_unlock_device(us->pusb_dev); - } - return result; -} diff --git a/ANDROID_3.4.5/drivers/usb/storage/transport.h b/ANDROID_3.4.5/drivers/usb/storage/transport.h deleted file mode 100644 index 9369d752..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/transport.h +++ /dev/null @@ -1,103 +0,0 @@ -/* Driver for USB Mass Storage compliant devices - * Transport Functions Header File - * - * Current development and maintenance by: - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI and ATAPI commands in - * mind when they created this document. The commands are all very - * similar to commands in the SCSI-II and ATAPI specifications. - * - * It is important to note that in a number of cases this class - * exhibits class-specific exemptions from the USB specification. - * Notably the usage of NAK, STALL and ACK differs from the norm, in - * that they are used to communicate wait, failed and OK on commands. - * - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _TRANSPORT_H_ -#define _TRANSPORT_H_ - -#include - -/* - * usb_stor_bulk_transfer_xxx() return codes, in order of severity - */ - -#define USB_STOR_XFER_GOOD 0 /* good transfer */ -#define USB_STOR_XFER_SHORT 1 /* transferred less than expected */ -#define USB_STOR_XFER_STALLED 2 /* endpoint stalled */ -#define USB_STOR_XFER_LONG 3 /* device tried to send too much */ -#define USB_STOR_XFER_ERROR 4 /* transfer died in the middle */ - -/* - * Transport return codes - */ - -#define USB_STOR_TRANSPORT_GOOD 0 /* Transport good, command good */ -#define USB_STOR_TRANSPORT_FAILED 1 /* Transport good, command failed */ -#define USB_STOR_TRANSPORT_NO_SENSE 2 /* Command failed, no auto-sense */ -#define USB_STOR_TRANSPORT_ERROR 3 /* Transport bad (i.e. device dead) */ - -/* - * We used to have USB_STOR_XFER_ABORTED and USB_STOR_TRANSPORT_ABORTED - * return codes. But now the transport and low-level transfer routines - * treat an abort as just another error (-ENOENT for a cancelled URB). - * It is up to the invoke_transport() function to test for aborts and - * distinguish them from genuine communication errors. - */ - -/* - * CBI accept device specific command - */ - -#define US_CBI_ADSC 0 - -extern int usb_stor_CB_transport(struct scsi_cmnd *, struct us_data*); -extern int usb_stor_CB_reset(struct us_data*); - -extern int usb_stor_Bulk_transport(struct scsi_cmnd *, struct us_data*); -extern int usb_stor_Bulk_max_lun(struct us_data*); -extern int usb_stor_Bulk_reset(struct us_data*); - -extern void usb_stor_invoke_transport(struct scsi_cmnd *, struct us_data*); -extern void usb_stor_stop_transport(struct us_data*); - -extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe, - u8 request, u8 requesttype, u16 value, u16 index, - void *data, u16 size, int timeout); -extern int usb_stor_clear_halt(struct us_data *us, unsigned int pipe); - -extern int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe, - u8 request, u8 requesttype, u16 value, u16 index, - void *data, u16 size); -extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, - void *buf, unsigned int length, unsigned int *act_len); -extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe, - void *buf, unsigned int length, int use_sg, int *residual); -extern int usb_stor_bulk_srb(struct us_data* us, unsigned int pipe, - struct scsi_cmnd* srb); - -extern int usb_stor_port_reset(struct us_data *us); -#endif diff --git a/ANDROID_3.4.5/drivers/usb/storage/uas.c b/ANDROID_3.4.5/drivers/usb/storage/uas.c deleted file mode 100644 index 8ec8a6e6..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/uas.c +++ /dev/null @@ -1,862 +0,0 @@ -/* - * USB Attached SCSI - * Note that this is not the same as the USB Mass Storage driver - * - * Copyright Matthew Wilcox for Intel Corp, 2010 - * Copyright Sarah Sharp for Intel Corp, 2010 - * - * Distributed under the terms of the GNU GPL, version two. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -/* - * The r00-r01c specs define this version of the SENSE IU data structure. - * It's still in use by several different firmware releases. - */ -struct sense_iu_old { - __u8 iu_id; - __u8 rsvd1; - __be16 tag; - __be16 len; - __u8 status; - __u8 service_response; - __u8 sense[SCSI_SENSE_BUFFERSIZE]; -}; - -struct uas_dev_info { - struct usb_interface *intf; - struct usb_device *udev; - int qdepth; - unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe; - unsigned use_streams:1; - unsigned uas_sense_old:1; - struct scsi_cmnd *cmnd; - struct urb *status_urb; /* used only if stream support is available */ -}; - -enum { - ALLOC_STATUS_URB = (1 << 0), - SUBMIT_STATUS_URB = (1 << 1), - ALLOC_DATA_IN_URB = (1 << 2), - SUBMIT_DATA_IN_URB = (1 << 3), - ALLOC_DATA_OUT_URB = (1 << 4), - SUBMIT_DATA_OUT_URB = (1 << 5), - ALLOC_CMD_URB = (1 << 6), - SUBMIT_CMD_URB = (1 << 7), - COMPLETED_DATA_IN = (1 << 8), - COMPLETED_DATA_OUT = (1 << 9), - DATA_COMPLETES_CMD = (1 << 10), -}; - -/* Overrides scsi_pointer */ -struct uas_cmd_info { - unsigned int state; - unsigned int stream; - struct urb *cmd_urb; - /* status_urb is used only if stream support isn't available */ - struct urb *status_urb; - struct urb *data_in_urb; - struct urb *data_out_urb; - struct list_head list; -}; - -/* I hate forward declarations, but I actually have a loop */ -static int uas_submit_urbs(struct scsi_cmnd *cmnd, - struct uas_dev_info *devinfo, gfp_t gfp); -static void uas_do_work(struct work_struct *work); - -static DECLARE_WORK(uas_work, uas_do_work); -static DEFINE_SPINLOCK(uas_work_lock); -static LIST_HEAD(uas_work_list); - -static void uas_do_work(struct work_struct *work) -{ - struct uas_cmd_info *cmdinfo; - struct uas_cmd_info *temp; - struct list_head list; - int err; - - spin_lock_irq(&uas_work_lock); - list_replace_init(&uas_work_list, &list); - spin_unlock_irq(&uas_work_lock); - - list_for_each_entry_safe(cmdinfo, temp, &list, list) { - struct scsi_pointer *scp = (void *)cmdinfo; - struct scsi_cmnd *cmnd = container_of(scp, - struct scsi_cmnd, SCp); - err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO); - if (err) { - list_del(&cmdinfo->list); - spin_lock_irq(&uas_work_lock); - list_add_tail(&cmdinfo->list, &uas_work_list); - spin_unlock_irq(&uas_work_lock); - schedule_work(&uas_work); - } - } -} - -static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd) -{ - struct sense_iu *sense_iu = urb->transfer_buffer; - struct scsi_device *sdev = cmnd->device; - struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; - - if (urb->actual_length > 16) { - unsigned len = be16_to_cpup(&sense_iu->len); - if (len + 16 != urb->actual_length) { - int newlen = min(len + 16, urb->actual_length) - 16; - if (newlen < 0) - newlen = 0; - sdev_printk(KERN_INFO, sdev, "%s: urb length %d " - "disagrees with IU sense data length %d, " - "using %d bytes of sense data\n", __func__, - urb->actual_length, len, newlen); - len = newlen; - } - memcpy(cmnd->sense_buffer, sense_iu->sense, len); - } - - cmnd->result = sense_iu->status; - if (!(cmdinfo->state & DATA_COMPLETES_CMD)) - cmnd->scsi_done(cmnd); -} - -static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd) -{ - struct sense_iu_old *sense_iu = urb->transfer_buffer; - struct scsi_device *sdev = cmnd->device; - struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; - - if (urb->actual_length > 8) { - unsigned len = be16_to_cpup(&sense_iu->len) - 2; - if (len + 8 != urb->actual_length) { - int newlen = min(len + 8, urb->actual_length) - 8; - if (newlen < 0) - newlen = 0; - sdev_printk(KERN_INFO, sdev, "%s: urb length %d " - "disagrees with IU sense data length %d, " - "using %d bytes of sense data\n", __func__, - urb->actual_length, len, newlen); - len = newlen; - } - memcpy(cmnd->sense_buffer, sense_iu->sense, len); - } - - cmnd->result = sense_iu->status; - if (!(cmdinfo->state & DATA_COMPLETES_CMD)) - cmnd->scsi_done(cmnd); -} - -static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd, - unsigned direction) -{ - struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; - int err; - - cmdinfo->state = direction; - err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC); - if (err) { - spin_lock(&uas_work_lock); - list_add_tail(&cmdinfo->list, &uas_work_list); - spin_unlock(&uas_work_lock); - schedule_work(&uas_work); - } -} - -static void uas_stat_cmplt(struct urb *urb) -{ - struct iu *iu = urb->transfer_buffer; - struct Scsi_Host *shost = urb->context; - struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; - struct scsi_cmnd *cmnd; - struct uas_cmd_info *cmdinfo; - u16 tag; - int ret; - - if (urb->status) { - dev_err(&urb->dev->dev, "URB BAD STATUS %d\n", urb->status); - if (devinfo->use_streams) - usb_free_urb(urb); - return; - } - - tag = be16_to_cpup(&iu->tag) - 1; - if (tag == 0) - cmnd = devinfo->cmnd; - else - cmnd = scsi_host_find_tag(shost, tag - 1); - if (!cmnd) { - if (devinfo->use_streams) { - usb_free_urb(urb); - return; - } - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) - dev_err(&urb->dev->dev, "failed submit status urb\n"); - return; - } - cmdinfo = (void *)&cmnd->SCp; - - switch (iu->iu_id) { - case IU_ID_STATUS: - if (devinfo->cmnd == cmnd) - devinfo->cmnd = NULL; - - if (!(cmdinfo->state & COMPLETED_DATA_IN) && - cmdinfo->data_in_urb) { - if (devinfo->use_streams) { - cmdinfo->state |= DATA_COMPLETES_CMD; - usb_unlink_urb(cmdinfo->data_in_urb); - } else { - usb_free_urb(cmdinfo->data_in_urb); - } - } - if (!(cmdinfo->state & COMPLETED_DATA_OUT) && - cmdinfo->data_out_urb) { - if (devinfo->use_streams) { - cmdinfo->state |= DATA_COMPLETES_CMD; - usb_unlink_urb(cmdinfo->data_in_urb); - } else { - usb_free_urb(cmdinfo->data_out_urb); - } - } - - if (urb->actual_length < 16) - devinfo->uas_sense_old = 1; - if (devinfo->uas_sense_old) - uas_sense_old(urb, cmnd); - else - uas_sense(urb, cmnd); - break; - case IU_ID_READ_READY: - uas_xfer_data(urb, cmnd, SUBMIT_DATA_IN_URB); - break; - case IU_ID_WRITE_READY: - uas_xfer_data(urb, cmnd, SUBMIT_DATA_OUT_URB); - break; - default: - scmd_printk(KERN_ERR, cmnd, - "Bogus IU (%d) received on status pipe\n", iu->iu_id); - } - - if (devinfo->use_streams) { - usb_free_urb(urb); - return; - } - - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) - dev_err(&urb->dev->dev, "failed submit status urb\n"); -} - -static void uas_data_out_cmplt(struct urb *urb) -{ - struct scsi_cmnd *cmnd = urb->context; - struct scsi_data_buffer *sdb = scsi_out(cmnd); - struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; - - cmdinfo->state |= COMPLETED_DATA_OUT; - - sdb->resid = sdb->length - urb->actual_length; - usb_free_urb(urb); - - if (cmdinfo->state & DATA_COMPLETES_CMD) - cmnd->scsi_done(cmnd); -} - -static void uas_data_in_cmplt(struct urb *urb) -{ - struct scsi_cmnd *cmnd = urb->context; - struct scsi_data_buffer *sdb = scsi_in(cmnd); - struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; - - cmdinfo->state |= COMPLETED_DATA_IN; - - sdb->resid = sdb->length - urb->actual_length; - usb_free_urb(urb); - - if (cmdinfo->state & DATA_COMPLETES_CMD) - cmnd->scsi_done(cmnd); -} - -static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp, - unsigned int pipe, struct scsi_cmnd *cmnd, - enum dma_data_direction dir) -{ - struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; - struct usb_device *udev = devinfo->udev; - struct urb *urb = usb_alloc_urb(0, gfp); - struct scsi_data_buffer *sdb; - usb_complete_t complete_fn; - u16 stream_id = cmdinfo->stream; - - if (!urb) - goto out; - if (dir == DMA_FROM_DEVICE) { - sdb = scsi_in(cmnd); - complete_fn = uas_data_in_cmplt; - } else { - sdb = scsi_out(cmnd); - complete_fn = uas_data_out_cmplt; - } - usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length, - complete_fn, cmnd); - urb->stream_id = stream_id; - urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0; - urb->sg = sdb->table.sgl; - out: - return urb; -} - -static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp, - struct Scsi_Host *shost, u16 stream_id) -{ - struct usb_device *udev = devinfo->udev; - struct urb *urb = usb_alloc_urb(0, gfp); - struct sense_iu *iu; - - if (!urb) - goto out; - - iu = kzalloc(sizeof(*iu), gfp); - if (!iu) - goto free; - - usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu), - uas_stat_cmplt, shost); - urb->stream_id = stream_id; - urb->transfer_flags |= URB_FREE_BUFFER; - out: - return urb; - free: - usb_free_urb(urb); - return NULL; -} - -static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp, - struct scsi_cmnd *cmnd, u16 stream_id) -{ - struct usb_device *udev = devinfo->udev; - struct scsi_device *sdev = cmnd->device; - struct urb *urb = usb_alloc_urb(0, gfp); - struct command_iu *iu; - int len; - - if (!urb) - goto out; - - len = cmnd->cmd_len - 16; - if (len < 0) - len = 0; - len = ALIGN(len, 4); - iu = kzalloc(sizeof(*iu) + len, gfp); - if (!iu) - goto free; - - iu->iu_id = IU_ID_COMMAND; - if (blk_rq_tagged(cmnd->request)) - iu->tag = cpu_to_be16(cmnd->request->tag + 2); - else - iu->tag = cpu_to_be16(1); - iu->prio_attr = UAS_SIMPLE_TAG; - iu->len = len; - int_to_scsilun(sdev->lun, &iu->lun); - memcpy(iu->cdb, cmnd->cmnd, cmnd->cmd_len); - - usb_fill_bulk_urb(urb, udev, devinfo->cmd_pipe, iu, sizeof(*iu) + len, - usb_free_urb, NULL); - urb->transfer_flags |= URB_FREE_BUFFER; - out: - return urb; - free: - usb_free_urb(urb); - return NULL; -} - -/* - * Why should I request the Status IU before sending the Command IU? Spec - * says to, but also says the device may receive them in any order. Seems - * daft to me. - */ - -static int uas_submit_urbs(struct scsi_cmnd *cmnd, - struct uas_dev_info *devinfo, gfp_t gfp) -{ - struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; - - if (cmdinfo->state & ALLOC_STATUS_URB) { - cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp, - cmnd->device->host, cmdinfo->stream); - if (!cmdinfo->status_urb) - return SCSI_MLQUEUE_DEVICE_BUSY; - cmdinfo->state &= ~ALLOC_STATUS_URB; - } - - if (cmdinfo->state & SUBMIT_STATUS_URB) { - if (usb_submit_urb(cmdinfo->status_urb, gfp)) { - scmd_printk(KERN_INFO, cmnd, - "sense urb submission failure\n"); - return SCSI_MLQUEUE_DEVICE_BUSY; - } - cmdinfo->state &= ~SUBMIT_STATUS_URB; - } - - if (cmdinfo->state & ALLOC_DATA_IN_URB) { - cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, gfp, - devinfo->data_in_pipe, cmnd, - DMA_FROM_DEVICE); - if (!cmdinfo->data_in_urb) - return SCSI_MLQUEUE_DEVICE_BUSY; - cmdinfo->state &= ~ALLOC_DATA_IN_URB; - } - - if (cmdinfo->state & SUBMIT_DATA_IN_URB) { - if (usb_submit_urb(cmdinfo->data_in_urb, gfp)) { - scmd_printk(KERN_INFO, cmnd, - "data in urb submission failure\n"); - return SCSI_MLQUEUE_DEVICE_BUSY; - } - cmdinfo->state &= ~SUBMIT_DATA_IN_URB; - } - - if (cmdinfo->state & ALLOC_DATA_OUT_URB) { - cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, gfp, - devinfo->data_out_pipe, cmnd, - DMA_TO_DEVICE); - if (!cmdinfo->data_out_urb) - return SCSI_MLQUEUE_DEVICE_BUSY; - cmdinfo->state &= ~ALLOC_DATA_OUT_URB; - } - - if (cmdinfo->state & SUBMIT_DATA_OUT_URB) { - if (usb_submit_urb(cmdinfo->data_out_urb, gfp)) { - scmd_printk(KERN_INFO, cmnd, - "data out urb submission failure\n"); - return SCSI_MLQUEUE_DEVICE_BUSY; - } - cmdinfo->state &= ~SUBMIT_DATA_OUT_URB; - } - - if (cmdinfo->state & ALLOC_CMD_URB) { - cmdinfo->cmd_urb = uas_alloc_cmd_urb(devinfo, gfp, cmnd, - cmdinfo->stream); - if (!cmdinfo->cmd_urb) - return SCSI_MLQUEUE_DEVICE_BUSY; - cmdinfo->state &= ~ALLOC_CMD_URB; - } - - if (cmdinfo->state & SUBMIT_CMD_URB) { - if (usb_submit_urb(cmdinfo->cmd_urb, gfp)) { - scmd_printk(KERN_INFO, cmnd, - "cmd urb submission failure\n"); - return SCSI_MLQUEUE_DEVICE_BUSY; - } - cmdinfo->state &= ~SUBMIT_CMD_URB; - } - - return 0; -} - -static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, - void (*done)(struct scsi_cmnd *)) -{ - struct scsi_device *sdev = cmnd->device; - struct uas_dev_info *devinfo = sdev->hostdata; - struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; - int err; - - BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer)); - - if (devinfo->cmnd) - return SCSI_MLQUEUE_DEVICE_BUSY; - - if (blk_rq_tagged(cmnd->request)) { - cmdinfo->stream = cmnd->request->tag + 2; - } else { - devinfo->cmnd = cmnd; - cmdinfo->stream = 1; - } - - cmnd->scsi_done = done; - - cmdinfo->state = ALLOC_STATUS_URB | SUBMIT_STATUS_URB | - ALLOC_CMD_URB | SUBMIT_CMD_URB; - - switch (cmnd->sc_data_direction) { - case DMA_FROM_DEVICE: - cmdinfo->state |= ALLOC_DATA_IN_URB | SUBMIT_DATA_IN_URB; - break; - case DMA_BIDIRECTIONAL: - cmdinfo->state |= ALLOC_DATA_IN_URB | SUBMIT_DATA_IN_URB; - case DMA_TO_DEVICE: - cmdinfo->state |= ALLOC_DATA_OUT_URB | SUBMIT_DATA_OUT_URB; - case DMA_NONE: - break; - } - - if (!devinfo->use_streams) { - cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB | - ALLOC_STATUS_URB | SUBMIT_STATUS_URB); - cmdinfo->stream = 0; - } - - err = uas_submit_urbs(cmnd, devinfo, GFP_ATOMIC); - if (err) { - /* If we did nothing, give up now */ - if (cmdinfo->state & SUBMIT_STATUS_URB) { - usb_free_urb(cmdinfo->status_urb); - return SCSI_MLQUEUE_DEVICE_BUSY; - } - spin_lock(&uas_work_lock); - list_add_tail(&cmdinfo->list, &uas_work_list); - spin_unlock(&uas_work_lock); - schedule_work(&uas_work); - } - - return 0; -} - -static DEF_SCSI_QCMD(uas_queuecommand) - -static int uas_eh_abort_handler(struct scsi_cmnd *cmnd) -{ - struct scsi_device *sdev = cmnd->device; - sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__, - cmnd->request->tag); - -/* XXX: Send ABORT TASK Task Management command */ - return FAILED; -} - -static int uas_eh_device_reset_handler(struct scsi_cmnd *cmnd) -{ - struct scsi_device *sdev = cmnd->device; - sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__, - cmnd->request->tag); - -/* XXX: Send LOGICAL UNIT RESET Task Management command */ - return FAILED; -} - -static int uas_eh_target_reset_handler(struct scsi_cmnd *cmnd) -{ - struct scsi_device *sdev = cmnd->device; - sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__, - cmnd->request->tag); - -/* XXX: Can we reset just the one USB interface? - * Would calling usb_set_interface() have the right effect? - */ - return FAILED; -} - -static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd) -{ - struct scsi_device *sdev = cmnd->device; - struct uas_dev_info *devinfo = sdev->hostdata; - struct usb_device *udev = devinfo->udev; - - sdev_printk(KERN_INFO, sdev, "%s tag %d\n", __func__, - cmnd->request->tag); - - if (usb_reset_device(udev)) - return SUCCESS; - - return FAILED; -} - -static int uas_slave_alloc(struct scsi_device *sdev) -{ - sdev->hostdata = (void *)sdev->host->hostdata[0]; - return 0; -} - -static int uas_slave_configure(struct scsi_device *sdev) -{ - struct uas_dev_info *devinfo = sdev->hostdata; - scsi_set_tag_type(sdev, MSG_ORDERED_TAG); - scsi_activate_tcq(sdev, devinfo->qdepth - 2); - return 0; -} - -static struct scsi_host_template uas_host_template = { - .module = THIS_MODULE, - .name = "uas", - .queuecommand = uas_queuecommand, - .slave_alloc = uas_slave_alloc, - .slave_configure = uas_slave_configure, - .eh_abort_handler = uas_eh_abort_handler, - .eh_device_reset_handler = uas_eh_device_reset_handler, - .eh_target_reset_handler = uas_eh_target_reset_handler, - .eh_bus_reset_handler = uas_eh_bus_reset_handler, - .can_queue = 65536, /* Is there a limit on the _host_ ? */ - .this_id = -1, - .sg_tablesize = SG_NONE, - .cmd_per_lun = 1, /* until we override it */ - .skip_settle_delay = 1, - .ordered_tag = 1, -}; - -static struct usb_device_id uas_usb_ids[] = { - { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_BULK) }, - { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_UAS) }, - /* 0xaa is a prototype device I happen to have access to */ - { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, 0xaa) }, - { } -}; -MODULE_DEVICE_TABLE(usb, uas_usb_ids); - -static int uas_is_interface(struct usb_host_interface *intf) -{ - return (intf->desc.bInterfaceClass == USB_CLASS_MASS_STORAGE && - intf->desc.bInterfaceSubClass == USB_SC_SCSI && - intf->desc.bInterfaceProtocol == USB_PR_UAS); -} - -static int uas_isnt_supported(struct usb_device *udev) -{ - struct usb_hcd *hcd = bus_to_hcd(udev->bus); - - dev_warn(&udev->dev, "The driver for the USB controller %s does not " - "support scatter-gather which is\n", - hcd->driver->description); - dev_warn(&udev->dev, "required by the UAS driver. Please try an" - "alternative USB controller if you wish to use UAS.\n"); - return -ENODEV; -} - -static int uas_switch_interface(struct usb_device *udev, - struct usb_interface *intf) -{ - int i; - int sg_supported = udev->bus->sg_tablesize != 0; - - for (i = 0; i < intf->num_altsetting; i++) { - struct usb_host_interface *alt = &intf->altsetting[i]; - - if (uas_is_interface(alt)) { - if (!sg_supported) - return uas_isnt_supported(udev); - return usb_set_interface(udev, - alt->desc.bInterfaceNumber, - alt->desc.bAlternateSetting); - } - } - - return -ENODEV; -} - -static void uas_configure_endpoints(struct uas_dev_info *devinfo) -{ - struct usb_host_endpoint *eps[4] = { }; - struct usb_interface *intf = devinfo->intf; - struct usb_device *udev = devinfo->udev; - struct usb_host_endpoint *endpoint = intf->cur_altsetting->endpoint; - unsigned i, n_endpoints = intf->cur_altsetting->desc.bNumEndpoints; - - devinfo->uas_sense_old = 0; - devinfo->cmnd = NULL; - - for (i = 0; i < n_endpoints; i++) { - unsigned char *extra = endpoint[i].extra; - int len = endpoint[i].extralen; - while (len > 1) { - if (extra[1] == USB_DT_PIPE_USAGE) { - unsigned pipe_id = extra[2]; - if (pipe_id > 0 && pipe_id < 5) - eps[pipe_id - 1] = &endpoint[i]; - break; - } - len -= extra[0]; - extra += extra[0]; - } - } - - /* - * Assume that if we didn't find a control pipe descriptor, we're - * using a device with old firmware that happens to be set up like - * this. - */ - if (!eps[0]) { - devinfo->cmd_pipe = usb_sndbulkpipe(udev, 1); - devinfo->status_pipe = usb_rcvbulkpipe(udev, 1); - devinfo->data_in_pipe = usb_rcvbulkpipe(udev, 2); - devinfo->data_out_pipe = usb_sndbulkpipe(udev, 2); - - eps[1] = usb_pipe_endpoint(udev, devinfo->status_pipe); - eps[2] = usb_pipe_endpoint(udev, devinfo->data_in_pipe); - eps[3] = usb_pipe_endpoint(udev, devinfo->data_out_pipe); - } else { - devinfo->cmd_pipe = usb_sndbulkpipe(udev, - eps[0]->desc.bEndpointAddress); - devinfo->status_pipe = usb_rcvbulkpipe(udev, - eps[1]->desc.bEndpointAddress); - devinfo->data_in_pipe = usb_rcvbulkpipe(udev, - eps[2]->desc.bEndpointAddress); - devinfo->data_out_pipe = usb_sndbulkpipe(udev, - eps[3]->desc.bEndpointAddress); - } - - devinfo->qdepth = usb_alloc_streams(devinfo->intf, eps + 1, 3, 256, - GFP_KERNEL); - if (devinfo->qdepth < 0) { - devinfo->qdepth = 256; - devinfo->use_streams = 0; - } else { - devinfo->use_streams = 1; - } -} - -static int uas_alloc_status_urb(struct uas_dev_info *devinfo, - struct Scsi_Host *shost) -{ - if (devinfo->use_streams) { - devinfo->status_urb = NULL; - return 0; - } - - devinfo->status_urb = uas_alloc_sense_urb(devinfo, GFP_KERNEL, - shost, 0); - if (!devinfo->status_urb) - goto err_s_urb; - - if (usb_submit_urb(devinfo->status_urb, GFP_KERNEL)) - goto err_submit_urb; - - return 0; -err_submit_urb: - usb_free_urb(devinfo->status_urb); -err_s_urb: - return -ENOMEM; -} - -static void uas_free_streams(struct uas_dev_info *devinfo) -{ - struct usb_device *udev = devinfo->udev; - struct usb_host_endpoint *eps[3]; - - eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe); - eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe); - eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe); - usb_free_streams(devinfo->intf, eps, 3, GFP_KERNEL); -} - -/* - * XXX: What I'd like to do here is register a SCSI host for each USB host in - * the system. Follow usb-storage's design of registering a SCSI host for - * each USB device for the moment. Can implement this by walking up the - * USB hierarchy until we find a USB host. - */ -static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - int result; - struct Scsi_Host *shost; - struct uas_dev_info *devinfo; - struct usb_device *udev = interface_to_usbdev(intf); - - if (uas_switch_interface(udev, intf)) - return -ENODEV; - - devinfo = kmalloc(sizeof(struct uas_dev_info), GFP_KERNEL); - if (!devinfo) - return -ENOMEM; - - result = -ENOMEM; - shost = scsi_host_alloc(&uas_host_template, sizeof(void *)); - if (!shost) - goto free; - - shost->max_cmd_len = 16 + 252; - shost->max_id = 1; - shost->sg_tablesize = udev->bus->sg_tablesize; - - devinfo->intf = intf; - devinfo->udev = udev; - uas_configure_endpoints(devinfo); - - result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 2); - if (result) - goto free; - - result = scsi_add_host(shost, &intf->dev); - if (result) - goto deconfig_eps; - - shost->hostdata[0] = (unsigned long)devinfo; - - result = uas_alloc_status_urb(devinfo, shost); - if (result) - goto err_alloc_status; - - scsi_scan_host(shost); - usb_set_intfdata(intf, shost); - return result; - -err_alloc_status: - scsi_remove_host(shost); - shost = NULL; -deconfig_eps: - uas_free_streams(devinfo); - free: - kfree(devinfo); - if (shost) - scsi_host_put(shost); - return result; -} - -static int uas_pre_reset(struct usb_interface *intf) -{ -/* XXX: Need to return 1 if it's not our device in error handling */ - return 0; -} - -static int uas_post_reset(struct usb_interface *intf) -{ -/* XXX: Need to return 1 if it's not our device in error handling */ - return 0; -} - -static void uas_disconnect(struct usb_interface *intf) -{ - struct Scsi_Host *shost = usb_get_intfdata(intf); - struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; - - scsi_remove_host(shost); - usb_kill_urb(devinfo->status_urb); - usb_free_urb(devinfo->status_urb); - uas_free_streams(devinfo); - kfree(devinfo); -} - -/* - * XXX: Should this plug into libusual so we can auto-upgrade devices from - * Bulk-Only to UAS? - */ -static struct usb_driver uas_driver = { - .name = "uas", - .probe = uas_probe, - .disconnect = uas_disconnect, - .pre_reset = uas_pre_reset, - .post_reset = uas_post_reset, - .id_table = uas_usb_ids, -}; - -module_usb_driver(uas_driver); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Matthew Wilcox and Sarah Sharp"); diff --git a/ANDROID_3.4.5/drivers/usb/storage/unusual_alauda.h b/ANDROID_3.4.5/drivers/usb/storage/unusual_alauda.h deleted file mode 100644 index fa3e9eda..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/unusual_alauda.h +++ /dev/null @@ -1,31 +0,0 @@ -/* Unusual Devices File for the Alauda-based card readers - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#if defined(CONFIG_USB_STORAGE_ALAUDA) || \ - defined(CONFIG_USB_STORAGE_ALAUDA_MODULE) - -UNUSUAL_DEV( 0x0584, 0x0008, 0x0102, 0x0102, - "Fujifilm", - "DPC-R1 (Alauda)", - USB_SC_SCSI, USB_PR_ALAUDA, init_alauda, 0), - -UNUSUAL_DEV( 0x07b4, 0x010a, 0x0102, 0x0102, - "Olympus", - "MAUSB-10 (Alauda)", - USB_SC_SCSI, USB_PR_ALAUDA, init_alauda, 0), - -#endif /* defined(CONFIG_USB_STORAGE_ALAUDA) || ... */ diff --git a/ANDROID_3.4.5/drivers/usb/storage/unusual_cypress.h b/ANDROID_3.4.5/drivers/usb/storage/unusual_cypress.h deleted file mode 100644 index 2c855302..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/unusual_cypress.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Unusual Devices File for devices based on the Cypress USB/ATA bridge - * with support for ATACB - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#if defined(CONFIG_USB_STORAGE_CYPRESS_ATACB) || \ - defined(CONFIG_USB_STORAGE_CYPRESS_ATACB_MODULE) - -/* CY7C68300 : support atacb */ -UNUSUAL_DEV( 0x04b4, 0x6830, 0x0000, 0x9999, - "Cypress", - "Cypress AT2LP", - USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0), - -/* CY7C68310 : support atacb and atacb2 */ -UNUSUAL_DEV( 0x04b4, 0x6831, 0x0000, 0x9999, - "Cypress", - "Cypress ISD-300LP", - USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0), - -UNUSUAL_DEV( 0x14cd, 0x6116, 0x0000, 0x9999, - "Super Top", - "USB 2.0 SATA BRIDGE", - USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0), - -#endif /* defined(CONFIG_USB_STORAGE_CYPRESS_ATACB) || ... */ diff --git a/ANDROID_3.4.5/drivers/usb/storage/unusual_datafab.h b/ANDROID_3.4.5/drivers/usb/storage/unusual_datafab.h deleted file mode 100644 index 582a603c..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/unusual_datafab.h +++ /dev/null @@ -1,98 +0,0 @@ -/* Unusual Devices File for the Datafab USB Compact Flash reader - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#if defined(CONFIG_USB_STORAGE_DATAFAB) || \ - defined(CONFIG_USB_STORAGE_DATAFAB_MODULE) - -UNUSUAL_DEV( 0x07c4, 0xa000, 0x0000, 0x0015, - "Datafab", - "MDCFE-B USB CF Reader", - USB_SC_SCSI, USB_PR_DATAFAB, NULL, - 0), - -/* - * The following Datafab-based devices may or may not work - * using the current driver...the 0xffff is arbitrary since I - * don't know what device versions exist for these guys. - * - * The 0xa003 and 0xa004 devices in particular I'm curious about. - * I'm told they exist but so far nobody has come forward to say that - * they work with this driver. Given the success we've had getting - * other Datafab-based cards operational with this driver, I've decided - * to leave these two devices in the list. - */ -UNUSUAL_DEV( 0x07c4, 0xa001, 0x0000, 0xffff, - "SIIG/Datafab", - "SIIG/Datafab Memory Stick+CF Reader/Writer", - USB_SC_SCSI, USB_PR_DATAFAB, NULL, - 0), - -/* Reported by Josef Reisinger */ -UNUSUAL_DEV( 0x07c4, 0xa002, 0x0000, 0xffff, - "Datafab/Unknown", - "MD2/MD3 Disk enclosure", - USB_SC_SCSI, USB_PR_DATAFAB, NULL, - US_FL_SINGLE_LUN), - -UNUSUAL_DEV( 0x07c4, 0xa003, 0x0000, 0xffff, - "Datafab/Unknown", - "Datafab-based Reader", - USB_SC_SCSI, USB_PR_DATAFAB, NULL, - 0), - -UNUSUAL_DEV( 0x07c4, 0xa004, 0x0000, 0xffff, - "Datafab/Unknown", - "Datafab-based Reader", - USB_SC_SCSI, USB_PR_DATAFAB, NULL, - 0), - -UNUSUAL_DEV( 0x07c4, 0xa005, 0x0000, 0xffff, - "PNY/Datafab", - "PNY/Datafab CF+SM Reader", - USB_SC_SCSI, USB_PR_DATAFAB, NULL, - 0), - -UNUSUAL_DEV( 0x07c4, 0xa006, 0x0000, 0xffff, - "Simple Tech/Datafab", - "Simple Tech/Datafab CF+SM Reader", - USB_SC_SCSI, USB_PR_DATAFAB, NULL, - 0), - -/* Submitted by Olaf Hering */ -UNUSUAL_DEV( 0x07c4, 0xa109, 0x0000, 0xffff, - "Datafab Systems, Inc.", - "USB to CF + SM Combo (LC1)", - USB_SC_SCSI, USB_PR_DATAFAB, NULL, - 0), - -/* Reported by Felix Moeller - * in Germany this is sold by Hama with the productnumber 46952 - * as "DualSlot CompactFlash(TM) & MStick Drive USB" - */ -UNUSUAL_DEV( 0x07c4, 0xa10b, 0x0000, 0xffff, - "DataFab Systems Inc.", - "USB CF+MS", - USB_SC_SCSI, USB_PR_DATAFAB, NULL, - 0), - -UNUSUAL_DEV( 0x0c0b, 0xa109, 0x0000, 0xffff, - "Acomdata", - "CF", - USB_SC_SCSI, USB_PR_DATAFAB, NULL, - US_FL_SINGLE_LUN), - -#endif /* defined(CONFIG_USB_STORAGE_DATAFAB) || ... */ diff --git a/ANDROID_3.4.5/drivers/usb/storage/unusual_devs.h b/ANDROID_3.4.5/drivers/usb/storage/unusual_devs.h deleted file mode 100644 index 8f3cbb8d..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/unusual_devs.h +++ /dev/null @@ -1,2050 +0,0 @@ -/* Driver for USB Mass Storage compliant devices - * Unusual Devices File - * - * Current development and maintenance by: - * (c) 2000-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * Initial work by: - * (c) 2000 Adam J. Richter (adam@yggdrasil.com), Yggdrasil Computing, Inc. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* IMPORTANT NOTE: This file must be included in another file which does - * the following thing for it to work: - * The UNUSUAL_DEV, COMPLIANT_DEV, and USUAL_DEV macros must be defined - * before this file is included. - */ - -/* If you edit this file, please try to keep it sorted first by VendorID, - * then by ProductID. - * - * If you want to add an entry for this file, be sure to include the - * following information: - * - a patch that adds the entry for your device, including your - * email address right above the entry (plus maybe a brief - * explanation of the reason for the entry), - * - a copy of /proc/bus/usb/devices with your device plugged in - * running with this patch. - * Send your submission to either Phil Dibowitz or - * Alan Stern , and don't forget to CC: the - * USB development list and the USB storage list - * - */ - -/* Note: If you add an entry only in order to set the CAPACITY_OK flag, - * use the COMPLIANT_DEV macro instead of UNUSUAL_DEV. This is - * because such entries mark devices which actually work correctly, - * as opposed to devices that do something strangely or wrongly. - */ - -#if !defined(CONFIG_USB_STORAGE_SDDR09) && \ - !defined(CONFIG_USB_STORAGE_SDDR09_MODULE) -#define NO_SDDR09 -#endif - -/* patch submitted by Vivian Bregier - */ -UNUSUAL_DEV( 0x03eb, 0x2002, 0x0100, 0x0100, - "ATMEL", - "SND1 Storage", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE), - -/* Reported by Rodolfo Quesada */ -UNUSUAL_DEV( 0x03ee, 0x6906, 0x0003, 0x0003, - "VIA Technologies Inc.", - "Mitsumi multi cardreader", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), - -UNUSUAL_DEV( 0x03f0, 0x0107, 0x0200, 0x0200, - "HP", - "CD-Writer+", - USB_SC_8070, USB_PR_CB, NULL, 0), - -/* Reported by Ben Efros */ -UNUSUAL_DEV( 0x03f0, 0x070c, 0x0000, 0x0000, - "HP", - "Personal Media Drive", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_SANE_SENSE ), - -/* Reported by Grant Grundler - * HP r707 camera in "Disk" mode with 2.00.23 or 2.00.24 firmware. - */ -UNUSUAL_DEV( 0x03f0, 0x4002, 0x0001, 0x0001, - "HP", - "PhotoSmart R707", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_CAPACITY), - -/* Reported by Sebastian Kapfer - * and Olaf Hering (different bcd's, same vendor/product) - * for USB floppies that need the SINGLE_LUN enforcement. - */ -UNUSUAL_DEV( 0x0409, 0x0040, 0x0000, 0x9999, - "NEC", - "NEC USB UF000x", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_SINGLE_LUN ), - -/* Patch submitted by Mihnea-Costin Grigore */ -UNUSUAL_DEV( 0x040d, 0x6205, 0x0003, 0x0003, - "VIA Technologies Inc.", - "USB 2.0 Card Reader", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), - -/* Deduced by Jonathan Woithe - * Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message - * always fails and confuses drive. - */ -UNUSUAL_DEV( 0x0411, 0x001c, 0x0113, 0x0113, - "Buffalo", - "DUB-P40G HDD", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_INQUIRY ), - -/* Submitted by Ernestas Vaiciukevicius */ -UNUSUAL_DEV( 0x0419, 0x0100, 0x0100, 0x0100, - "Samsung Info. Systems America, Inc.", - "MP3 Player", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), - -/* Reported by Orgad Shaneh */ -UNUSUAL_DEV( 0x0419, 0xaace, 0x0100, 0x0100, - "Samsung", "MP3 Player", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), - -/* Reported by Christian Leber */ -UNUSUAL_DEV( 0x0419, 0xaaf5, 0x0100, 0x0100, - "TrekStor", - "i.Beat 115 2.0", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE | US_FL_NOT_LOCKABLE ), - -/* Reported by Stefan Werner */ -UNUSUAL_DEV( 0x0419, 0xaaf6, 0x0100, 0x0100, - "TrekStor", - "i.Beat Joy 2.0", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), - -/* Reported by Pete Zaitcev , bz#176584 */ -UNUSUAL_DEV( 0x0420, 0x0001, 0x0100, 0x0100, - "GENERIC", "MP3 PLAYER", /* MyMusix PD-205 on the outside. */ - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), - -/* Reported by Andrew Nayenko - * Updated for new firmware by Phillip Potter */ -UNUSUAL_DEV( 0x0421, 0x0019, 0x0592, 0x0610, - "Nokia", - "Nokia 6288", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_MAX_SECTORS_64 ), - -/* Reported by Mario Rettig */ -UNUSUAL_DEV( 0x0421, 0x042e, 0x0100, 0x0100, - "Nokia", - "Nokia 3250", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), - -/* Reported by */ -UNUSUAL_DEV( 0x0421, 0x0433, 0x0100, 0x0100, - "Nokia", - "E70", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), - -/* Reported by Jon Hart */ -UNUSUAL_DEV( 0x0421, 0x0434, 0x0100, 0x0100, - "Nokia", - "E60", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ), - -/* Reported by Sumedha Swamy and - * Einar Th. Einarsson */ -UNUSUAL_DEV( 0x0421, 0x0444, 0x0100, 0x0100, - "Nokia", - "N91", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), - -/* Reported by Jiri Slaby and - * Rene C. Castberg */ -UNUSUAL_DEV( 0x0421, 0x0446, 0x0100, 0x0100, - "Nokia", - "N80", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), - -/* Reported by Matthew Bloch */ -UNUSUAL_DEV( 0x0421, 0x044e, 0x0100, 0x0100, - "Nokia", - "E61", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), - -/* Reported by Bardur Arantsson */ -UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0610, - "Nokia", - "6131", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_MAX_SECTORS_64 ), - -/* Reported by Manuel Osdoba */ -UNUSUAL_DEV( 0x0421, 0x0492, 0x0452, 0x9999, - "Nokia", - "Nokia 6233", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_MAX_SECTORS_64 ), - -/* Reported by Alex Corcoles */ -UNUSUAL_DEV( 0x0421, 0x0495, 0x0370, 0x0370, - "Nokia", - "6234", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_MAX_SECTORS_64 ), - -#ifdef NO_SDDR09 -UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100, - "Microtech", - "CameraMate", - USB_SC_SCSI, USB_PR_CB, NULL, - US_FL_SINGLE_LUN ), -#endif - -/* Patch submitted by Daniel Drake - * Device reports nonsense bInterfaceProtocol 6 when connected over USB2 */ -UNUSUAL_DEV( 0x0451, 0x5416, 0x0100, 0x0100, - "Neuros Audio", - "USB 2.0 HD 2.5", - USB_SC_DEVICE, USB_PR_BULK, NULL, - US_FL_NEED_OVERRIDE ), - -/* - * Pete Zaitcev , from Patrick C. F. Ernzer, bz#162559. - * The key does not actually break, but it returns zero sense which - * makes our SCSI stack to print confusing messages. - */ -UNUSUAL_DEV( 0x0457, 0x0150, 0x0100, 0x0100, - "USBest Technology", /* sold by Transcend */ - "USB Mass Storage Device", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ), - -/* -* Bohdan Linda -* 1GB USB sticks MyFlash High Speed. I have restricted -* the revision to my model only -*/ -UNUSUAL_DEV( 0x0457, 0x0151, 0x0100, 0x0100, - "USB 2.0", - "Flash Disk", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_NOT_LOCKABLE ), - -/* Reported by Tamas Kerecsen - * Obviously the PROM has not been customized by the VAR; - * the Vendor and Product string descriptors are: - * Generic Mass Storage (PROTOTYPE--Remember to change idVendor) - * Generic Manufacturer (PROTOTYPE--Remember to change idVendor) - */ -UNUSUAL_DEV( 0x045e, 0xffff, 0x0000, 0x0000, - "Mitac", - "GPS", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_MAX_SECTORS_64 ), - -/* - * This virtual floppy is found in Sun equipment (x4600, x4200m2, etc.) - * Reported by Pete Zaitcev - * This device chokes on both version of MODE SENSE which we have, so - * use_10_for_ms is not effective, and we use US_FL_NO_WP_DETECT. - */ -UNUSUAL_DEV( 0x046b, 0xff40, 0x0100, 0x0100, - "AMI", - "Virtual Floppy", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_NO_WP_DETECT), - -/* Patch submitted by Philipp Friedrich */ -UNUSUAL_DEV( 0x0482, 0x0100, 0x0100, 0x0100, - "Kyocera", - "Finecam S3x", - USB_SC_8070, USB_PR_CB, NULL, US_FL_FIX_INQUIRY), - -/* Patch submitted by Philipp Friedrich */ -UNUSUAL_DEV( 0x0482, 0x0101, 0x0100, 0x0100, - "Kyocera", - "Finecam S4", - USB_SC_8070, USB_PR_CB, NULL, US_FL_FIX_INQUIRY), - -/* Patch submitted by Stephane Galles */ -UNUSUAL_DEV( 0x0482, 0x0103, 0x0100, 0x0100, - "Kyocera", - "Finecam S5", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_INQUIRY), - -/* Patch submitted by Jens Taprogge */ -UNUSUAL_DEV( 0x0482, 0x0107, 0x0100, 0x0100, - "Kyocera", - "CONTAX SL300R T*", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE), - -/* Reported by Paul Stewart - * This entry is needed because the device reports Sub=ff */ -UNUSUAL_DEV( 0x04a4, 0x0004, 0x0001, 0x0001, - "Hitachi", - "DVD-CAM DZ-MV100A Camcorder", - USB_SC_SCSI, USB_PR_CB, NULL, US_FL_SINGLE_LUN), - -/* BENQ DC5330 - * Reported by Manuel Fombuena and - * Frank Copeland */ -UNUSUAL_DEV( 0x04a5, 0x3010, 0x0100, 0x0100, - "Tekom Technologies, Inc", - "300_CAMERA", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), - -/* Patch for Nikon coolpix 2000 - * Submitted by Fabien Cosse */ -UNUSUAL_DEV( 0x04b0, 0x0301, 0x0010, 0x0010, - "NIKON", - "NIKON DSC E2000", - USB_SC_DEVICE, USB_PR_DEVICE,NULL, - US_FL_NOT_LOCKABLE ), - -/* Reported by Doug Maxey (dwm@austin.ibm.com) */ -UNUSUAL_DEV( 0x04b3, 0x4001, 0x0110, 0x0110, - "IBM", - "IBM RSA2", - USB_SC_DEVICE, USB_PR_CB, NULL, - US_FL_MAX_SECTORS_MIN), - -/* Reported by Simon Levitt - * This entry needs Sub and Proto fields */ -UNUSUAL_DEV( 0x04b8, 0x0601, 0x0100, 0x0100, - "Epson", - "875DC Storage", - USB_SC_SCSI, USB_PR_CB, NULL, US_FL_FIX_INQUIRY), - -/* Reported by Khalid Aziz - * This entry is needed because the device reports Sub=ff */ -UNUSUAL_DEV( 0x04b8, 0x0602, 0x0110, 0x0110, - "Epson", - "785EPX Storage", - USB_SC_SCSI, USB_PR_BULK, NULL, US_FL_SINGLE_LUN), - -/* Not sure who reported this originally but - * Pavel Machek reported that the extra US_FL_SINGLE_LUN - * flag be added */ -UNUSUAL_DEV( 0x04cb, 0x0100, 0x0000, 0x2210, - "Fujifilm", - "FinePix 1400Zoom", - USB_SC_UFI, USB_PR_DEVICE, NULL, US_FL_FIX_INQUIRY | US_FL_SINGLE_LUN), - -/* Reported by Ondrej Zary - * The device reports one sector more and breaks when that sector is accessed - */ -UNUSUAL_DEV( 0x04ce, 0x0002, 0x026c, 0x026c, - "ScanLogic", - "SL11R-IDE", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY), - -/* Reported by Kriston Fincher - * Patch submitted by Sean Millichamp - * This is to support the Panasonic PalmCam PV-SD4090 - * This entry is needed because the device reports Sub=ff - */ -UNUSUAL_DEV( 0x04da, 0x0901, 0x0100, 0x0200, - "Panasonic", - "LS-120 Camera", - USB_SC_UFI, USB_PR_DEVICE, NULL, 0), - -/* From Yukihiro Nakai, via zaitcev@yahoo.com. - * This is needed for CB instead of CBI */ -UNUSUAL_DEV( 0x04da, 0x0d05, 0x0000, 0x0000, - "Sharp CE-CW05", - "CD-R/RW Drive", - USB_SC_8070, USB_PR_CB, NULL, 0), - -/* Reported by Adriaan Penning */ -UNUSUAL_DEV( 0x04da, 0x2372, 0x0000, 0x9999, - "Panasonic", - "DMC-LCx Camera", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE ), - -/* Reported by Simeon Simeonov */ -UNUSUAL_DEV( 0x04da, 0x2373, 0x0000, 0x9999, - "LEICA", - "D-LUX Camera", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE ), - -/* Most of the following entries were developed with the help of - * Shuttle/SCM directly. - */ -UNUSUAL_DEV( 0x04e6, 0x0001, 0x0200, 0x0200, - "Matshita", - "LS-120", - USB_SC_8020, USB_PR_CB, NULL, 0), - -UNUSUAL_DEV( 0x04e6, 0x0002, 0x0100, 0x0100, - "Shuttle", - "eUSCSI Bridge", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init, - US_FL_SCM_MULT_TARG ), - -#ifdef NO_SDDR09 -UNUSUAL_DEV( 0x04e6, 0x0005, 0x0100, 0x0208, - "SCM Microsystems", - "eUSB CompactFlash Adapter", - USB_SC_SCSI, USB_PR_CB, NULL, - US_FL_SINGLE_LUN), -#endif - -/* Reported by Markus Demleitner */ -UNUSUAL_DEV( 0x04e6, 0x0006, 0x0100, 0x0100, - "SCM Microsystems Inc.", - "eUSB MMC Adapter", - USB_SC_SCSI, USB_PR_CB, NULL, - US_FL_SINGLE_LUN), - -/* Reported by Daniel Nouri */ -UNUSUAL_DEV( 0x04e6, 0x0006, 0x0205, 0x0205, - "Shuttle", - "eUSB MMC Adapter", - USB_SC_SCSI, USB_PR_DEVICE, NULL, - US_FL_SINGLE_LUN), - -UNUSUAL_DEV( 0x04e6, 0x0007, 0x0100, 0x0200, - "Sony", - "Hifd", - USB_SC_SCSI, USB_PR_CB, NULL, - US_FL_SINGLE_LUN), - -UNUSUAL_DEV( 0x04e6, 0x0009, 0x0200, 0x0200, - "Shuttle", - "eUSB ATA/ATAPI Adapter", - USB_SC_8020, USB_PR_CB, NULL, 0), - -UNUSUAL_DEV( 0x04e6, 0x000a, 0x0200, 0x0200, - "Shuttle", - "eUSB CompactFlash Adapter", - USB_SC_8020, USB_PR_CB, NULL, 0), - -UNUSUAL_DEV( 0x04e6, 0x000B, 0x0100, 0x0100, - "Shuttle", - "eUSCSI Bridge", - USB_SC_SCSI, USB_PR_BULK, usb_stor_euscsi_init, - US_FL_SCM_MULT_TARG ), - -UNUSUAL_DEV( 0x04e6, 0x000C, 0x0100, 0x0100, - "Shuttle", - "eUSCSI Bridge", - USB_SC_SCSI, USB_PR_BULK, usb_stor_euscsi_init, - US_FL_SCM_MULT_TARG ), - -UNUSUAL_DEV( 0x04e6, 0x0101, 0x0200, 0x0200, - "Shuttle", - "CD-RW Device", - USB_SC_8020, USB_PR_CB, NULL, 0), - -/* Reported by Dmitry Khlystov */ -UNUSUAL_DEV( 0x04e8, 0x507c, 0x0220, 0x0220, - "Samsung", - "YP-U3", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_MAX_SECTORS_64), - -/* Reported by Vitaly Kuznetsov */ -UNUSUAL_DEV( 0x04e8, 0x5122, 0x0000, 0x9999, - "Samsung", - "YP-CP3", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_MAX_SECTORS_64 | US_FL_BULK_IGNORE_TAG), - -/* Entry and supporting patch by Theodore Kilgore . - * Device uses standards-violating 32-byte Bulk Command Block Wrappers and - * reports itself as "Proprietary SCSI Bulk." Cf. device entry 0x084d:0x0011. - */ -UNUSUAL_DEV( 0x04fc, 0x80c2, 0x0100, 0x0100, - "Kobian Mercury", - "Binocam DCB-132", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_BULK32), - -/* Reported by Bob Sass -- only rev 1.33 tested */ -UNUSUAL_DEV( 0x050d, 0x0115, 0x0133, 0x0133, - "Belkin", - "USB SCSI Adaptor", - USB_SC_SCSI, USB_PR_BULK, usb_stor_euscsi_init, - US_FL_SCM_MULT_TARG ), - -/* Iomega Clik! Drive - * Reported by David Chatenay - * The reason this is needed is not fully known. - */ -UNUSUAL_DEV( 0x0525, 0xa140, 0x0100, 0x0100, - "Iomega", - "USB Clik! 40", - USB_SC_8070, USB_PR_DEVICE, NULL, - US_FL_FIX_INQUIRY ), - -/* Added by Alan Stern */ -COMPLIANT_DEV(0x0525, 0xa4a5, 0x0000, 0x9999, - "Linux", - "File-backed Storage Gadget", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_CAPACITY_OK ), - -/* Yakumo Mega Image 37 - * Submitted by Stephan Fuhrmann */ -UNUSUAL_DEV( 0x052b, 0x1801, 0x0100, 0x0100, - "Tekom Technologies, Inc", - "300_CAMERA", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), - -/* Another Yakumo camera. - * Reported by Michele Alzetta */ -UNUSUAL_DEV( 0x052b, 0x1804, 0x0100, 0x0100, - "Tekom Technologies, Inc", - "300_CAMERA", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), - -/* Reported by Iacopo Spalletti */ -UNUSUAL_DEV( 0x052b, 0x1807, 0x0100, 0x0100, - "Tekom Technologies, Inc", - "300_CAMERA", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), - -/* Yakumo Mega Image 47 - * Reported by Bjoern Paetzel */ -UNUSUAL_DEV( 0x052b, 0x1905, 0x0100, 0x0100, - "Tekom Technologies, Inc", - "400_CAMERA", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), - -/* Reported by Paul Ortyl - * Note that it's similar to the device above, only different prodID */ -UNUSUAL_DEV( 0x052b, 0x1911, 0x0100, 0x0100, - "Tekom Technologies, Inc", - "400_CAMERA", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), - -UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0450, - "Sony", - "DSC-S30/S70/S75/505V/F505/F707/F717/P8", - USB_SC_SCSI, USB_PR_DEVICE, NULL, - US_FL_SINGLE_LUN | US_FL_NOT_LOCKABLE | US_FL_NO_WP_DETECT ), - -/* Submitted by Lars Jacob - * This entry is needed because the device reports Sub=ff */ -UNUSUAL_DEV( 0x054c, 0x0010, 0x0500, 0x0610, - "Sony", - "DSC-T1/T5/H5", - USB_SC_8070, USB_PR_DEVICE, NULL, - US_FL_SINGLE_LUN ), - - -/* Reported by wim@geeks.nl */ -UNUSUAL_DEV( 0x054c, 0x0025, 0x0100, 0x0100, - "Sony", - "Memorystick NW-MS7", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_SINGLE_LUN ), - -/* Submitted by Olaf Hering, SuSE Bugzilla #49049 */ -UNUSUAL_DEV( 0x054c, 0x002c, 0x0501, 0x2000, - "Sony", - "USB Floppy Drive", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_SINGLE_LUN ), - -UNUSUAL_DEV( 0x054c, 0x002d, 0x0100, 0x0100, - "Sony", - "Memorystick MSAC-US1", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_SINGLE_LUN ), - -/* Submitted by Klaus Mueller */ -UNUSUAL_DEV( 0x054c, 0x002e, 0x0106, 0x0310, - "Sony", - "Handycam", - USB_SC_SCSI, USB_PR_DEVICE, NULL, - US_FL_SINGLE_LUN ), - -/* Submitted by Rajesh Kumble Nayak */ -UNUSUAL_DEV( 0x054c, 0x002e, 0x0500, 0x0500, - "Sony", - "Handycam HC-85", - USB_SC_UFI, USB_PR_DEVICE, NULL, - US_FL_SINGLE_LUN ), - -UNUSUAL_DEV( 0x054c, 0x0032, 0x0000, 0x9999, - "Sony", - "Memorystick MSC-U01N", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_SINGLE_LUN ), - -/* Submitted by Michal Mlotek */ -UNUSUAL_DEV( 0x054c, 0x0058, 0x0000, 0x9999, - "Sony", - "PEG N760c Memorystick", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_INQUIRY ), - -UNUSUAL_DEV( 0x054c, 0x0069, 0x0000, 0x9999, - "Sony", - "Memorystick MSC-U03", - USB_SC_UFI, USB_PR_CB, NULL, - US_FL_SINGLE_LUN ), - -/* Submitted by Nathan Babb */ -UNUSUAL_DEV( 0x054c, 0x006d, 0x0000, 0x9999, - "Sony", - "PEG Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_INQUIRY ), - -/* Submitted by Frank Engel */ -UNUSUAL_DEV( 0x054c, 0x0099, 0x0000, 0x9999, - "Sony", - "PEG Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_INQUIRY ), - -/* Submitted by Mike Alborn */ -UNUSUAL_DEV( 0x054c, 0x016a, 0x0000, 0x9999, - "Sony", - "PEG Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_INQUIRY ), - -/* floppy reports multiple luns */ -UNUSUAL_DEV( 0x055d, 0x2020, 0x0000, 0x0210, - "SAMSUNG", - "SFD-321U [FW 0C]", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_SINGLE_LUN ), - -/* We keep this entry to force the transport; firmware 3.00 and later is ok. */ -UNUSUAL_DEV( 0x057b, 0x0000, 0x0000, 0x0299, - "Y-E Data", - "Flashbuster-U", - USB_SC_DEVICE, USB_PR_CB, NULL, - US_FL_SINGLE_LUN), - -/* Reported by Johann Cardon - * This entry is needed only because the device reports - * bInterfaceClass = 0xff (vendor-specific) - */ -UNUSUAL_DEV( 0x057b, 0x0022, 0x0000, 0x9999, - "Y-E Data", - "Silicon Media R/W", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, 0), - -/* Reported by RTE */ -UNUSUAL_DEV( 0x058f, 0x6387, 0x0141, 0x0141, - "JetFlash", - "TS1GJF2A/120", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_MAX_SECTORS_64 ), - -/* Fabrizio Fellini */ -UNUSUAL_DEV( 0x0595, 0x4343, 0x0000, 0x2210, - "Fujifilm", - "Digital Camera EX-20 DSC", - USB_SC_8070, USB_PR_DEVICE, NULL, 0 ), - -/* Reported by Andre Welter - * This antique device predates the release of the Bulk-only Transport - * spec, and if it gets a Get-Max-LUN then it requires the host to do a - * Clear-Halt on the bulk endpoints. The SINGLE_LUN flag will prevent - * us from sending the request. - */ -UNUSUAL_DEV( 0x059b, 0x0001, 0x0100, 0x0100, - "Iomega", - "ZIP 100", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_SINGLE_LUN ), - -/* Reported by */ -UNUSUAL_DEV( 0x059f, 0x0643, 0x0000, 0x0000, - "LaCie", - "DVD+-RW", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_GO_SLOW ), - -/* Submitted by Joel Bourquard - * Some versions of this device need the SubClass and Protocol overrides - * while others don't. - */ -UNUSUAL_DEV( 0x05ab, 0x0060, 0x1104, 0x1110, - "In-System", - "PyroGate External CD-ROM Enclosure (FCD-523)", - USB_SC_SCSI, USB_PR_BULK, NULL, - US_FL_NEED_OVERRIDE ), - -/* Submitted by Sven Anderson - * There are at least four ProductIDs used for iPods, so I added 0x1202 and - * 0x1204. They just need the US_FL_FIX_CAPACITY. As the bcdDevice appears - * to change with firmware updates, I changed the range to maximum for all - * iPod entries. - */ -UNUSUAL_DEV( 0x05ac, 0x1202, 0x0000, 0x9999, - "Apple", - "iPod", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY ), - -/* Reported by Avi Kivity */ -UNUSUAL_DEV( 0x05ac, 0x1203, 0x0000, 0x9999, - "Apple", - "iPod", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY ), - -UNUSUAL_DEV( 0x05ac, 0x1204, 0x0000, 0x9999, - "Apple", - "iPod", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE ), - -UNUSUAL_DEV( 0x05ac, 0x1205, 0x0000, 0x9999, - "Apple", - "iPod", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY ), - -/* - * Reported by Tyson Vinson - * This particular productId is the iPod Nano - */ -UNUSUAL_DEV( 0x05ac, 0x120a, 0x0000, 0x9999, - "Apple", - "iPod", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY ), - -/* Reported by Dan Williams - * Option N.V. mobile broadband modems - * Ignore driver CD mode and force into modem mode by default. - */ - -/* Globetrotter HSDPA; mass storage shows up as Qualcomm for vendor */ -UNUSUAL_DEV( 0x05c6, 0x1000, 0x0000, 0x9999, - "Option N.V.", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, option_ms_init, - 0), - -/* Reported by Blake Matheny */ -UNUSUAL_DEV( 0x05dc, 0xb002, 0x0000, 0x0113, - "Lexar", - "USB CF Reader", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_INQUIRY ), - -/* The following two entries are for a Genesys USB to IDE - * converter chip, but it changes its ProductId depending - * on whether or not a disk or an optical device is enclosed - * They were originally reported by Alexander Oltu - * and Peter Marks - * respectively. - * - * US_FL_GO_SLOW and US_FL_MAX_SECTORS_64 added by Phil Dibowitz - * as these flags were made and hard-coded - * special-cases were pulled from scsiglue.c. - */ -UNUSUAL_DEV( 0x05e3, 0x0701, 0x0000, 0xffff, - "Genesys Logic", - "USB to IDE Optical", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 | US_FL_IGNORE_RESIDUE ), - -UNUSUAL_DEV( 0x05e3, 0x0702, 0x0000, 0xffff, - "Genesys Logic", - "USB to IDE Disk", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 | US_FL_IGNORE_RESIDUE ), - -/* Reported by Ben Efros */ -UNUSUAL_DEV( 0x05e3, 0x0723, 0x9451, 0x9451, - "Genesys Logic", - "USB to SATA", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_SANE_SENSE ), - -/* Reported by Hanno Boeck - * Taken from the Lycoris Kernel */ -UNUSUAL_DEV( 0x0636, 0x0003, 0x0000, 0x9999, - "Vivitar", - "Vivicam 35Xx", - USB_SC_SCSI, USB_PR_BULK, NULL, - US_FL_FIX_INQUIRY ), - -UNUSUAL_DEV( 0x0644, 0x0000, 0x0100, 0x0100, - "TEAC", - "Floppy Drive", - USB_SC_UFI, USB_PR_CB, NULL, 0 ), - -/* Reported by Darsen Lu */ -UNUSUAL_DEV( 0x066f, 0x8000, 0x0001, 0x0001, - "SigmaTel", - "USBMSC Audio Player", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY ), - -/* Reported by Daniel Kukula */ -UNUSUAL_DEV( 0x067b, 0x1063, 0x0100, 0x0100, - "Prolific Technology, Inc.", - "Prolific Storage Gadget", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_BAD_SENSE ), - -/* Reported by Rogerio Brito */ -UNUSUAL_DEV( 0x067b, 0x2317, 0x0001, 0x001, - "Prolific Technology, Inc.", - "Mass Storage Device", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_NOT_LOCKABLE ), - -/* Reported by Richard -=[]=- */ -/* Change to bcdDeviceMin (0x0100 to 0x0001) reported by - * Thomas Bartosik */ -UNUSUAL_DEV( 0x067b, 0x2507, 0x0001, 0x0100, - "Prolific Technology Inc.", - "Mass Storage Device", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY | US_FL_GO_SLOW ), - -/* Reported by Alex Butcher */ -UNUSUAL_DEV( 0x067b, 0x3507, 0x0001, 0x0101, - "Prolific Technology Inc.", - "ATAPI-6 Bridge Controller", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY | US_FL_GO_SLOW ), - -/* Submitted by Benny Sjostrand */ -UNUSUAL_DEV( 0x0686, 0x4011, 0x0001, 0x0001, - "Minolta", - "Dimage F300", - USB_SC_SCSI, USB_PR_BULK, NULL, 0 ), - -/* Reported by Miguel A. Fosas */ -UNUSUAL_DEV( 0x0686, 0x4017, 0x0001, 0x0001, - "Minolta", - "DIMAGE E223", - USB_SC_SCSI, USB_PR_DEVICE, NULL, 0 ), - -UNUSUAL_DEV( 0x0693, 0x0005, 0x0100, 0x0100, - "Hagiwara", - "Flashgate", - USB_SC_SCSI, USB_PR_BULK, NULL, 0 ), - -/* Reported by David Hamilton */ -UNUSUAL_DEV( 0x069b, 0x3004, 0x0001, 0x0001, - "Thomson Multimedia Inc.", - "RCA RD1080 MP3 Player", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY ), - -/* Reported by Adrian Pilchowiec */ -UNUSUAL_DEV( 0x071b, 0x3203, 0x0000, 0x0000, - "RockChip", - "MP3", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_NO_WP_DETECT | US_FL_MAX_SECTORS_64 | - US_FL_NO_READ_CAPACITY_16), - -/* Reported by Jean-Baptiste Onofre - * Support the following product : - * "Dane-Elec MediaTouch" - */ -UNUSUAL_DEV( 0x071b, 0x32bb, 0x0000, 0x0000, - "RockChip", - "MTP", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_NO_WP_DETECT | US_FL_MAX_SECTORS_64), - -/* Reported by Massimiliano Ghilardi - * This USB MP3/AVI player device fails and disconnects if more than 128 - * sectors (64kB) are read/written in a single command, and may be present - * at least in the following products: - * "Magnex Digital Video Panel DVP 1800" - * "MP4 AIGO 4GB SLOT SD" - * "Teclast TL-C260 MP3" - * "i.Meizu PMP MP3/MP4" - * "Speed MV8 MP4 Audio Player" - */ -UNUSUAL_DEV( 0x071b, 0x3203, 0x0100, 0x0100, - "RockChip", - "ROCK MP3", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_MAX_SECTORS_64), - -/* Reported by Olivier Blondeau */ -UNUSUAL_DEV( 0x0727, 0x0306, 0x0100, 0x0100, - "ATMEL", - "SND1 Storage", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE), - -/* Submitted by Roman Hodek */ -UNUSUAL_DEV( 0x0781, 0x0001, 0x0200, 0x0200, - "Sandisk", - "ImageMate SDDR-05a", - USB_SC_SCSI, USB_PR_CB, NULL, - US_FL_SINGLE_LUN ), - -UNUSUAL_DEV( 0x0781, 0x0002, 0x0009, 0x0009, - "SanDisk Corporation", - "ImageMate CompactFlash USB", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY ), - -UNUSUAL_DEV( 0x0781, 0x0100, 0x0100, 0x0100, - "Sandisk", - "ImageMate SDDR-12", - USB_SC_SCSI, USB_PR_CB, NULL, - US_FL_SINGLE_LUN ), - -/* Reported by Eero Volotinen */ -UNUSUAL_DEV( 0x07ab, 0xfccd, 0x0000, 0x9999, - "Freecom Technologies", - "FHD-Classic", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY), - -UNUSUAL_DEV( 0x07af, 0x0004, 0x0100, 0x0133, - "Microtech", - "USB-SCSI-DB25", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init, - US_FL_SCM_MULT_TARG ), - -UNUSUAL_DEV( 0x07af, 0x0005, 0x0100, 0x0100, - "Microtech", - "USB-SCSI-HD50", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init, - US_FL_SCM_MULT_TARG ), - -#ifdef NO_SDDR09 -UNUSUAL_DEV( 0x07af, 0x0006, 0x0100, 0x0100, - "Microtech", - "CameraMate", - USB_SC_SCSI, USB_PR_CB, NULL, - US_FL_SINGLE_LUN ), -#endif - -/* Datafab KECF-USB / Sagatek DCS-CF / Simpletech Flashlink UCF-100 - * Only revision 1.13 tested (same for all of the above devices, - * based on the Datafab DF-UG-07 chip). Needed for US_FL_FIX_INQUIRY. - * Submitted by Marek Michalkiewicz . - * See also http://martin.wilck.bei.t-online.de/#kecf . - */ -UNUSUAL_DEV( 0x07c4, 0xa400, 0x0000, 0xffff, - "Datafab", - "KECF-USB", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_INQUIRY | US_FL_FIX_CAPACITY ), - -/* Reported by Rauch Wolke - * and augmented by binbin (Bugzilla #12882) - */ -UNUSUAL_DEV( 0x07c4, 0xa4a5, 0x0000, 0xffff, - "Simple Tech/Datafab", - "CF+SM Reader", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE | US_FL_MAX_SECTORS_64 ), - -/* Casio QV 2x00/3x00/4000/8000 digital still cameras are not conformant - * to the USB storage specification in two ways: - * - They tell us they are using transport protocol CBI. In reality they - * are using transport protocol CB. - * - They don't like the INQUIRY command. So we must handle this command - * of the SCSI layer ourselves. - * - Some cameras with idProduct=0x1001 and bcdDevice=0x1000 have - * bInterfaceProtocol=0x00 (USB_PR_CBI) while others have 0x01 (USB_PR_CB). - * So don't remove the USB_PR_CB override! - * - Cameras with bcdDevice=0x9009 require the USB_SC_8070 override. - */ -UNUSUAL_DEV( 0x07cf, 0x1001, 0x1000, 0x9999, - "Casio", - "QV DigitalCamera", - USB_SC_8070, USB_PR_CB, NULL, - US_FL_NEED_OVERRIDE | US_FL_FIX_INQUIRY ), - -/* Submitted by Hartmut Wahl */ -UNUSUAL_DEV( 0x0839, 0x000a, 0x0001, 0x0001, - "Samsung", - "Digimax 410", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_INQUIRY), - -/* Reported by Luciano Rocha */ -UNUSUAL_DEV( 0x0840, 0x0082, 0x0001, 0x0001, - "Argosy", - "Storage", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY), - -/* Reported and patched by Nguyen Anh Quynh */ -UNUSUAL_DEV( 0x0840, 0x0084, 0x0001, 0x0001, - "Argosy", - "Storage", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY), - -/* Reported by Martijn Hijdra */ -UNUSUAL_DEV( 0x0840, 0x0085, 0x0001, 0x0001, - "Argosy", - "Storage", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY), - -/* Entry and supporting patch by Theodore Kilgore . - * Flag will support Bulk devices which use a standards-violating 32-byte - * Command Block Wrapper. Here, the "DC2MEGA" cameras (several brands) with - * Grandtech GT892x chip, which request "Proprietary SCSI Bulk" support. - */ - -UNUSUAL_DEV( 0x084d, 0x0011, 0x0110, 0x0110, - "Grandtech", - "DC2MEGA", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_BULK32), - -/* Reported by - * The device reports a vendor-specific device class, requiring an - * explicit vendor/product match. - */ -UNUSUAL_DEV( 0x0851, 0x1542, 0x0002, 0x0002, - "MagicPixel", - "FW_Omega2", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, 0), - -/* Andrew Lunn - * PanDigital Digital Picture Frame. Does not like ALLOW_MEDIUM_REMOVAL - * on LUN 4. - * Note: Vend:Prod clash with "Ltd Maxell WS30 Slim Digital Camera" -*/ -UNUSUAL_DEV( 0x0851, 0x1543, 0x0200, 0x0200, - "PanDigital", - "Photo Frame", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_NOT_LOCKABLE), - -/* Submitted by Jan De Luyck */ -UNUSUAL_DEV( 0x08bd, 0x1100, 0x0000, 0x0000, - "CITIZEN", - "X1DE-USB", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_SINGLE_LUN), - -/* Submitted by Dylan Taft - * US_FL_IGNORE_RESIDUE Needed - */ -UNUSUAL_DEV( 0x08ca, 0x3103, 0x0100, 0x0100, - "AIPTEK", - "Aiptek USB Keychain MP3 Player", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE), - -/* Entry needed for flags. Moreover, all devices with this ID use - * bulk-only transport, but _some_ falsely report Control/Bulk instead. - * One example is "Trumpion Digital Research MYMP3". - * Submitted by Bjoern Brill - */ -UNUSUAL_DEV( 0x090a, 0x1001, 0x0100, 0x0100, - "Trumpion", - "t33520 USB Flash Card Controller", - USB_SC_DEVICE, USB_PR_BULK, NULL, - US_FL_NEED_OVERRIDE ), - -/* Reported by Filippo Bardelli - * The device reports a subclass of RBC, which is wrong. - */ -UNUSUAL_DEV( 0x090a, 0x1050, 0x0100, 0x0100, - "Trumpion Microelectronics, Inc.", - "33520 USB Digital Voice Recorder", - USB_SC_UFI, USB_PR_DEVICE, NULL, - 0), - -/* Trumpion Microelectronics MP3 player (felipe_alfaro@linuxmail.org) */ -UNUSUAL_DEV( 0x090a, 0x1200, 0x0000, 0x9999, - "Trumpion", - "MP3 player", - USB_SC_RBC, USB_PR_BULK, NULL, - 0 ), - -/* aeb */ -UNUSUAL_DEV( 0x090c, 0x1132, 0x0000, 0xffff, - "Feiya", - "5-in-1 Card Reader", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY ), - -/* Reported by Paul Hartman - * This card reader returns "Illegal Request, Logical Block Address - * Out of Range" for the first READ(10) after a new card is inserted. - */ -UNUSUAL_DEV( 0x090c, 0x6000, 0x0100, 0x0100, - "Feiya", - "SD/SDHC Card Reader", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_INITIAL_READ10 ), - -/* This Pentax still camera is not conformant - * to the USB storage specification: - - * - It does not like the INQUIRY command. So we must handle this command - * of the SCSI layer ourselves. - * Tested on Rev. 10.00 (0x1000) - * Submitted by James Courtier-Dutton - */ -UNUSUAL_DEV( 0x0a17, 0x0004, 0x1000, 0x1000, - "Pentax", - "Optio 2/3/400", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_INQUIRY ), - -/* These are virtual windows driver CDs, which the zd1211rw driver - * automatically converts into WLAN devices. */ -UNUSUAL_DEV( 0x0ace, 0x2011, 0x0101, 0x0101, - "ZyXEL", - "G-220F USB-WLAN Install", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_DEVICE ), - -UNUSUAL_DEV( 0x0ace, 0x20ff, 0x0101, 0x0101, - "SiteCom", - "WL-117 USB-WLAN Install", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_DEVICE ), - -/* Reported by Dan Williams - * Option N.V. mobile broadband modems - * Ignore driver CD mode and force into modem mode by default. - */ - -/* iCON 225 */ -UNUSUAL_DEV( 0x0af0, 0x6971, 0x0000, 0x9999, - "Option N.V.", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, option_ms_init, - 0), - -/* Reported by F. Aben - * This device (wrongly) has a vendor-specific device descriptor. - * The entry is needed so usb-storage can bind to it's mass-storage - * interface as an interface driver */ -UNUSUAL_DEV( 0x0af0, 0x7401, 0x0000, 0x0000, - "Option", - "GI 0401 SD-Card", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - 0 ), - -/* Reported by Jan Dumon - * These devices (wrongly) have a vendor-specific device descriptor. - * These entries are needed so usb-storage can bind to their mass-storage - * interface as an interface driver */ -UNUSUAL_DEV( 0x0af0, 0x7501, 0x0000, 0x0000, - "Option", - "GI 0431 SD-Card", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - 0 ), - -UNUSUAL_DEV( 0x0af0, 0x7701, 0x0000, 0x0000, - "Option", - "GI 0451 SD-Card", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - 0 ), - -UNUSUAL_DEV( 0x0af0, 0x7706, 0x0000, 0x0000, - "Option", - "GI 0451 SD-Card", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - 0 ), - -UNUSUAL_DEV( 0x0af0, 0x7901, 0x0000, 0x0000, - "Option", - "GI 0452 SD-Card", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - 0 ), - -UNUSUAL_DEV( 0x0af0, 0x7A01, 0x0000, 0x0000, - "Option", - "GI 0461 SD-Card", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - 0 ), - -UNUSUAL_DEV( 0x0af0, 0x7A05, 0x0000, 0x0000, - "Option", - "GI 0461 SD-Card", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - 0 ), - -UNUSUAL_DEV( 0x0af0, 0x8300, 0x0000, 0x0000, - "Option", - "GI 033x SD-Card", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - 0 ), - -UNUSUAL_DEV( 0x0af0, 0x8302, 0x0000, 0x0000, - "Option", - "GI 033x SD-Card", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - 0 ), - -UNUSUAL_DEV( 0x0af0, 0x8304, 0x0000, 0x0000, - "Option", - "GI 033x SD-Card", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - 0 ), - -UNUSUAL_DEV( 0x0af0, 0xc100, 0x0000, 0x0000, - "Option", - "GI 070x SD-Card", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - 0 ), - -UNUSUAL_DEV( 0x0af0, 0xd057, 0x0000, 0x0000, - "Option", - "GI 1505 SD-Card", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - 0 ), - -UNUSUAL_DEV( 0x0af0, 0xd058, 0x0000, 0x0000, - "Option", - "GI 1509 SD-Card", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - 0 ), - -UNUSUAL_DEV( 0x0af0, 0xd157, 0x0000, 0x0000, - "Option", - "GI 1515 SD-Card", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - 0 ), - -UNUSUAL_DEV( 0x0af0, 0xd257, 0x0000, 0x0000, - "Option", - "GI 1215 SD-Card", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - 0 ), - -UNUSUAL_DEV( 0x0af0, 0xd357, 0x0000, 0x0000, - "Option", - "GI 1505 SD-Card", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - 0 ), - -/* Reported by Ben Efros */ -UNUSUAL_DEV( 0x0bc2, 0x3010, 0x0000, 0x0000, - "Seagate", - "FreeAgent Pro", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_SANE_SENSE ), - -UNUSUAL_DEV( 0x0d49, 0x7310, 0x0000, 0x9999, - "Maxtor", - "USB to SATA", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_SANE_SENSE), - -/* - * Pete Zaitcev , bz#164688. - * The device blatantly ignores LUN and returns 1 in GetMaxLUN. - */ -UNUSUAL_DEV( 0x0c45, 0x1060, 0x0100, 0x0100, - "Unknown", - "Unknown", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_SINGLE_LUN ), - -/* Submitted by Joris Struyve */ -UNUSUAL_DEV( 0x0d96, 0x410a, 0x0001, 0xffff, - "Medion", - "MD 7425", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_INQUIRY), - -/* - * Entry for Jenoptik JD 5200z3 - * - * email: car.busse@gmx.de - */ -UNUSUAL_DEV( 0x0d96, 0x5200, 0x0001, 0x0200, - "Jenoptik", - "JD 5200 z3", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_INQUIRY), - -/* Reported by Jason Johnston */ -UNUSUAL_DEV( 0x0dc4, 0x0073, 0x0000, 0x0000, - "Macpower Technology Co.LTD.", - "USB 2.0 3.5\" DEVICE", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY), - -/* Reported by Lubomir Blaha - * I _REALLY_ don't know what 3rd, 4th number and all defines mean, but this - * works for me. Can anybody correct these values? (I able to test corrected - * version.) - */ -UNUSUAL_DEV( 0x0dd8, 0x1060, 0x0000, 0xffff, - "Netac", - "USB-CF-Card", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_INQUIRY ), - -/* Reported by Edward Chapman (taken from linux-usb mailing list) - Netac OnlyDisk Mini U2CV2 512MB USB 2.0 Flash Drive */ -UNUSUAL_DEV( 0x0dd8, 0xd202, 0x0000, 0x9999, - "Netac", - "USB Flash Disk", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), - - -/* Patch by Stephan Walter - * I don't know why, but it works... */ -UNUSUAL_DEV( 0x0dda, 0x0001, 0x0012, 0x0012, - "WINWARD", - "Music Disk", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), - -/* Reported by Ian McConnell */ -UNUSUAL_DEV( 0x0dda, 0x0301, 0x0012, 0x0012, - "PNP_MP3", - "PNP_MP3 PLAYER", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), - -/* Reported by Jim McCloskey */ -UNUSUAL_DEV( 0x0e21, 0x0520, 0x0100, 0x0100, - "Cowon Systems", - "iAUDIO M5", - USB_SC_DEVICE, USB_PR_BULK, NULL, - US_FL_NEED_OVERRIDE ), - -/* Submitted by Antoine Mairesse */ -UNUSUAL_DEV( 0x0ed1, 0x6660, 0x0100, 0x0300, - "USB", - "Solid state disk", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_INQUIRY ), - -/* Submitted by Daniel Drake - * Reported by dayul on the Gentoo Forums */ -UNUSUAL_DEV( 0x0ea0, 0x2168, 0x0110, 0x0110, - "Ours Technology", - "Flash Disk", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), - -/* Reported by Rastislav Stanik */ -UNUSUAL_DEV( 0x0ea0, 0x6828, 0x0110, 0x0110, - "USB", - "Flash Disk", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), - -/* Reported by Benjamin Schiller - * It is also sold by Easylite as DJ 20 */ -UNUSUAL_DEV( 0x0ed1, 0x7636, 0x0103, 0x0103, - "Typhoon", - "My DJ 1820", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE | US_FL_GO_SLOW | US_FL_MAX_SECTORS_64), - -/* Patch by Leonid Petrov mail at lpetrov.net - * Reported by Robert Spitzenpfeil - * http://www.qbik.ch/usb/devices/showdev.php?id=1705 - * Updated to 103 device by MJ Ray mjr at phonecoop.coop - */ -UNUSUAL_DEV( 0x0f19, 0x0103, 0x0100, 0x0100, - "Oracom Co., Ltd", - "ORC-200M", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), - -/* David Kuehling : - * for MP3-Player AVOX WSX-300ER (bought in Japan). Reports lots of SCSI - * errors when trying to write. - */ -UNUSUAL_DEV( 0x0f19, 0x0105, 0x0100, 0x0100, - "C-MEX", - "A-VOX", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), - -/* Submitted by Nick Holloway */ -UNUSUAL_DEV( 0x0f88, 0x042e, 0x0100, 0x0100, - "VTech", - "Kidizoom", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY ), - -/* Reported by Michael Stattmann */ -UNUSUAL_DEV( 0x0fce, 0xd008, 0x0000, 0x0000, - "Sony Ericsson", - "V800-Vodafone 802", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_NO_WP_DETECT ), - -/* Reported by The Solutor */ -UNUSUAL_DEV( 0x0fce, 0xd0e1, 0x0000, 0x0000, - "Sony Ericsson", - "MD400", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_DEVICE), - -/* Reported by Jan Mate - * and by Soeren Sonnenburg */ -UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000, - "Sony Ericsson", - "P990i", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ), - -/* Reported by Emmanuel Vasilakis */ -UNUSUAL_DEV( 0x0fce, 0xe031, 0x0000, 0x0000, - "Sony Ericsson", - "M600i", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), - -/* Reported by Ricardo Barberis */ -UNUSUAL_DEV( 0x0fce, 0xe092, 0x0000, 0x0000, - "Sony Ericsson", - "P1i", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), - -/* Reported by Kevin Cernekee - * Tested on hardware version 1.10. - * Entry is needed only for the initializer function override. - * Devices with bcd > 110 seem to not need it while those - * with bcd < 110 appear to need it. - */ -UNUSUAL_DEV( 0x1019, 0x0c55, 0x0000, 0x0110, - "Desknote", - "UCR-61S2B", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_ucr61s2b_init, - 0 ), - -UNUSUAL_DEV( 0x1058, 0x0704, 0x0000, 0x9999, - "Western Digital", - "External HDD", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_SANE_SENSE), - -/* Reported by Fabio Venturi - * The device reports a vendor-specific bDeviceClass. - */ -UNUSUAL_DEV( 0x10d6, 0x2200, 0x0100, 0x0100, - "Actions Semiconductor", - "Mtp device", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - 0), - -/* Reported by Pascal Terjan - * Ignore driver CD mode and force into modem mode by default. - */ -UNUSUAL_DEV( 0x1186, 0x3e04, 0x0000, 0x0000, - "D-Link", - "USB Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, option_ms_init, US_FL_IGNORE_DEVICE), - -/* Reported by Kevin Lloyd - * Entry is needed for the initializer function override, - * which instructs the device to load as a modem - * device. - */ -UNUSUAL_DEV( 0x1199, 0x0fff, 0x0000, 0x9999, - "Sierra Wireless", - "USB MMC Storage", - USB_SC_DEVICE, USB_PR_DEVICE, sierra_ms_init, - 0), - -/* Reported by Jaco Kroon - * The usb-storage module found on the Digitech GNX4 (and supposedly other - * devices) misbehaves and causes a bunch of invalid I/O errors. - */ -UNUSUAL_DEV( 0x1210, 0x0003, 0x0100, 0x0100, - "Digitech HMG", - "DigiTech Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), - -/* Reported by fangxiaozhi - * This brings the HUAWEI data card devices into multi-port mode - */ -UNUSUAL_DEV( 0x12d1, 0x1001, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1004, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1401, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1402, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1403, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1404, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1405, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1406, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1407, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1408, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1409, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x140A, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x140B, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x140C, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x140D, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x140E, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x140F, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1410, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1411, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1412, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1413, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1414, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1415, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1416, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1417, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1418, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1419, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x141A, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x141B, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x141C, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x141D, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x141E, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x141F, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1420, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1421, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1422, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1423, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1424, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1425, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1426, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1427, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1428, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1429, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x142A, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x142B, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x142C, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x142D, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x142E, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x142F, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1430, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1431, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1432, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1433, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1434, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1435, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1436, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1437, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1438, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x1439, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x143A, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x143B, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x143C, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x143D, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x143E, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), -UNUSUAL_DEV( 0x12d1, 0x143F, 0x0000, 0x0000, - "HUAWEI MOBILE", - "Mass Storage", - USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_huawei_e220_init, - 0), - -/* Reported by Vilius Bilinkevicius */ -UNUSUAL_DEV( 0x1370, 0x6828, 0x0110, 0x0110, - "SWISSBIT", - "Black Silver", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), - -/* Reported by Qinglin Ye */ -UNUSUAL_DEV( 0x13fe, 0x3600, 0x0100, 0x0100, - "Kingston", - "DT 101 G2", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_BULK_IGNORE_TAG ), - -/* Reported by Francesco Foresti */ -UNUSUAL_DEV( 0x14cd, 0x6600, 0x0201, 0x0201, - "Super Top", - "IDE DEVICE", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), - -/* Reported by Alexandre Oliva - * JMicron responds to USN and several other SCSI ioctls with a - * residue that causes subsequent I/O requests to fail. */ -UNUSUAL_DEV( 0x152d, 0x2329, 0x0100, 0x0100, - "JMicron", - "USB to ATA/ATAPI Bridge", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE | US_FL_SANE_SENSE ), - -/* Reported by Robert Schedel - * Note: this is a 'super top' device like the above 14cd/6600 device */ -UNUSUAL_DEV( 0x1652, 0x6600, 0x0201, 0x0201, - "Teac", - "HD-35PUK-B", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), - -/* Reported by Jesse Feddema */ -UNUSUAL_DEV( 0x177f, 0x0400, 0x0000, 0x0000, - "Yarvik", - "PMP400", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_BULK_IGNORE_TAG | US_FL_MAX_SECTORS_64 ), - -/* Reported by Hans de Goede - * These Appotech controllers are found in Picture Frames, they provide a - * (buggy) emulation of a cdrom drive which contains the windows software - * Uploading of pictures happens over the corresponding /dev/sg device. */ -UNUSUAL_DEV( 0x1908, 0x1315, 0x0000, 0x0000, - "BUILDWIN", - "Photo Frame", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_BAD_SENSE ), -UNUSUAL_DEV( 0x1908, 0x1320, 0x0000, 0x0000, - "BUILDWIN", - "Photo Frame", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_BAD_SENSE ), -UNUSUAL_DEV( 0x1908, 0x3335, 0x0200, 0x0200, - "BUILDWIN", - "Photo Frame", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_NO_READ_DISC_INFO ), - -/* Reported by Sven Geggus - * This encrypted pen drive returns bogus data for the initial READ(10). - */ -UNUSUAL_DEV( 0x1b1c, 0x1ab5, 0x0200, 0x0200, - "Corsair", - "Padlock v2", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_INITIAL_READ10 ), - -/* Patch by Richard Schütz - * This external hard drive enclosure uses a JMicron chip which - * needs the US_FL_IGNORE_RESIDUE flag to work properly. */ -UNUSUAL_DEV( 0x1e68, 0x001b, 0x0000, 0x0000, - "TrekStor GmbH & Co. KG", - "DataStation maxi g.u", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE | US_FL_SANE_SENSE ), - -/* Reported by Jasper Mackenzie */ -UNUSUAL_DEV( 0x1e74, 0x4621, 0x0000, 0x0000, - "Coby Electronics", - "MP3 Player", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_BULK_IGNORE_TAG | US_FL_MAX_SECTORS_64 ), - -UNUSUAL_DEV( 0x2116, 0x0320, 0x0001, 0x0001, - "ST", - "2A", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY), - -/* patch submitted by Davide Perini - * and Renato Perini - */ -UNUSUAL_DEV( 0x22b8, 0x3010, 0x0001, 0x0001, - "Motorola", - "RAZR V3x", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ), - -/* - * Patch by Constantin Baranov - * Report by Andreas Koenecke. - * Motorola ROKR Z6. - */ -UNUSUAL_DEV( 0x22b8, 0x6426, 0x0101, 0x0101, - "Motorola", - "MSnc.", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_FIX_INQUIRY | US_FL_FIX_CAPACITY | US_FL_BULK_IGNORE_TAG), - -/* Reported by Radovan Garabik */ -UNUSUAL_DEV( 0x2735, 0x100b, 0x0000, 0x9999, - "MPIO", - "HS200", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_GO_SLOW ), - -/* Reported by Frederic Marchal - * Mio Moov 330 - */ -UNUSUAL_DEV( 0x3340, 0xffff, 0x0000, 0x0000, - "Mitac", - "Mio DigiWalker USB Sync", - USB_SC_DEVICE,USB_PR_DEVICE,NULL, - US_FL_MAX_SECTORS_64 ), - -/* Reported by Andrey Rahmatullin */ -UNUSUAL_DEV( 0x4102, 0x1020, 0x0100, 0x0100, - "iRiver", - "MP3 T10", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_RESIDUE ), - -/* Reported by Sergey Pinaev */ -UNUSUAL_DEV( 0x4102, 0x1059, 0x0000, 0x0000, - "iRiver", - "P7K", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_MAX_SECTORS_64 ), - -/* - * David Härdeman - * The key makes the SCSI stack print confusing (but harmless) messages - */ -UNUSUAL_DEV( 0x4146, 0xba01, 0x0100, 0x0100, - "Iomega", - "Micro Mini 1GB", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ), - -/* - * Nick Bowler - * SCSI stack spams (otherwise harmless) error messages. - */ -UNUSUAL_DEV( 0xc251, 0x4003, 0x0100, 0x0100, - "Keil Software, Inc.", - "V2M MotherBoard", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_NOT_LOCKABLE), - -/* Reported by Andrew Simmons */ -UNUSUAL_DEV( 0xed06, 0x4500, 0x0001, 0x0001, - "DataStor", - "USB4500 FW1.04", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_CAPACITY_HEURISTICS), - -/* Reported by Alessio Treglia */ -UNUSUAL_DEV( 0xed10, 0x7636, 0x0001, 0x0001, - "TGE", - "Digital MP3 Audio Player", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ), - -/* Control/Bulk transport for all SubClass values */ -USUAL_DEV(USB_SC_RBC, USB_PR_CB, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_8020, USB_PR_CB, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_QIC, USB_PR_CB, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_UFI, USB_PR_CB, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_8070, USB_PR_CB, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_SCSI, USB_PR_CB, USB_US_TYPE_STOR), - -/* Control/Bulk/Interrupt transport for all SubClass values */ -USUAL_DEV(USB_SC_RBC, USB_PR_CBI, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_8020, USB_PR_CBI, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_QIC, USB_PR_CBI, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_UFI, USB_PR_CBI, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_8070, USB_PR_CBI, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_SCSI, USB_PR_CBI, USB_US_TYPE_STOR), - -/* Bulk-only transport for all SubClass values */ -USUAL_DEV(USB_SC_RBC, USB_PR_BULK, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_8020, USB_PR_BULK, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_QIC, USB_PR_BULK, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_UFI, USB_PR_BULK, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_8070, USB_PR_BULK, USB_US_TYPE_STOR), -USUAL_DEV(USB_SC_SCSI, USB_PR_BULK, 0), diff --git a/ANDROID_3.4.5/drivers/usb/storage/unusual_ene_ub6250.h b/ANDROID_3.4.5/drivers/usb/storage/unusual_ene_ub6250.h deleted file mode 100644 index 5667f5d3..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/unusual_ene_ub6250.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#if defined(CONFIG_USB_STORAGE_ENE_UB6250) || \ - defined(CONFIG_USB_STORAGE_ENE_UB6250_MODULE) - -UNUSUAL_DEV(0x0cf2, 0x6250, 0x0000, 0x9999, - "ENE", - "ENE UB6250 reader", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, 0), - -#endif /* defined(CONFIG_USB_STORAGE_ENE_UB6250) || ... */ diff --git a/ANDROID_3.4.5/drivers/usb/storage/unusual_freecom.h b/ANDROID_3.4.5/drivers/usb/storage/unusual_freecom.h deleted file mode 100644 index 59a26115..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/unusual_freecom.h +++ /dev/null @@ -1,26 +0,0 @@ -/* Unusual Devices File for the Freecom USB/IDE adaptor - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#if defined(CONFIG_USB_STORAGE_FREECOM) || \ - defined(CONFIG_USB_STORAGE_FREECOM_MODULE) - -UNUSUAL_DEV( 0x07ab, 0xfc01, 0x0000, 0x9999, - "Freecom", - "USB-IDE", - USB_SC_QIC, USB_PR_FREECOM, init_freecom, 0), - -#endif /* defined(CONFIG_USB_STORAGE_FREECOM) || ... */ diff --git a/ANDROID_3.4.5/drivers/usb/storage/unusual_isd200.h b/ANDROID_3.4.5/drivers/usb/storage/unusual_isd200.h deleted file mode 100644 index 14cca0c4..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/unusual_isd200.h +++ /dev/null @@ -1,57 +0,0 @@ -/* Unusual Devices File for In-System Design, Inc. ISD200 ASIC - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#if defined(CONFIG_USB_STORAGE_ISD200) || \ - defined(CONFIG_USB_STORAGE_ISD200_MODULE) - -UNUSUAL_DEV( 0x054c, 0x002b, 0x0100, 0x0110, - "Sony", - "Portable USB Harddrive V2", - USB_SC_ISD200, USB_PR_BULK, isd200_Initialization, - 0), - -UNUSUAL_DEV( 0x05ab, 0x0031, 0x0100, 0x0110, - "In-System", - "USB/IDE Bridge (ATA/ATAPI)", - USB_SC_ISD200, USB_PR_BULK, isd200_Initialization, - 0), - -UNUSUAL_DEV( 0x05ab, 0x0301, 0x0100, 0x0110, - "In-System", - "Portable USB Harddrive V2", - USB_SC_ISD200, USB_PR_BULK, isd200_Initialization, - 0), - -UNUSUAL_DEV( 0x05ab, 0x0351, 0x0100, 0x0110, - "In-System", - "Portable USB Harddrive V2", - USB_SC_ISD200, USB_PR_BULK, isd200_Initialization, - 0), - -UNUSUAL_DEV( 0x05ab, 0x5701, 0x0100, 0x0110, - "In-System", - "USB Storage Adapter V2", - USB_SC_ISD200, USB_PR_BULK, isd200_Initialization, - 0), - -UNUSUAL_DEV( 0x0bf6, 0xa001, 0x0100, 0x0110, - "ATI", - "USB Cable 205", - USB_SC_ISD200, USB_PR_BULK, isd200_Initialization, - 0), - -#endif /* defined(CONFIG_USB_STORAGE_ISD200) || ... */ diff --git a/ANDROID_3.4.5/drivers/usb/storage/unusual_jumpshot.h b/ANDROID_3.4.5/drivers/usb/storage/unusual_jumpshot.h deleted file mode 100644 index 54be78b5..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/unusual_jumpshot.h +++ /dev/null @@ -1,27 +0,0 @@ -/* Unusual Devices File for the Lexar "Jumpshot" Compact Flash reader - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#if defined(CONFIG_USB_STORAGE_JUMPSHOT) || \ - defined(CONFIG_USB_STORAGE_JUMPSHOT_MODULE) - -UNUSUAL_DEV( 0x05dc, 0x0001, 0x0000, 0x0001, - "Lexar", - "Jumpshot USB CF Reader", - USB_SC_SCSI, USB_PR_JUMPSHOT, NULL, - US_FL_NEED_OVERRIDE), - -#endif /* defined(CONFIG_USB_STORAGE_JUMPSHOT) || ... */ diff --git a/ANDROID_3.4.5/drivers/usb/storage/unusual_karma.h b/ANDROID_3.4.5/drivers/usb/storage/unusual_karma.h deleted file mode 100644 index 6df03972..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/unusual_karma.h +++ /dev/null @@ -1,26 +0,0 @@ -/* Unusual Devices File for the Rio Karma - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#if defined(CONFIG_USB_STORAGE_KARMA) || \ - defined(CONFIG_USB_STORAGE_KARMA_MODULE) - -UNUSUAL_DEV( 0x045a, 0x5210, 0x0101, 0x0101, - "Rio", - "Rio Karma", - USB_SC_SCSI, USB_PR_KARMA, rio_karma_init, 0), - -#endif /* defined(CONFIG_USB_STORAGE_KARMA) || ... */ diff --git a/ANDROID_3.4.5/drivers/usb/storage/unusual_onetouch.h b/ANDROID_3.4.5/drivers/usb/storage/unusual_onetouch.h deleted file mode 100644 index 0abb819c..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/unusual_onetouch.h +++ /dev/null @@ -1,36 +0,0 @@ -/* Unusual Devices File for the Maxtor OneTouch USB hard drive's button - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#if defined(CONFIG_USB_STORAGE_ONETOUCH) || \ - defined(CONFIG_USB_STORAGE_ONETOUCH_MODULE) - -/* Submitted by: Nick Sillik - * Needed for OneTouch extension to usb-storage - */ -UNUSUAL_DEV( 0x0d49, 0x7000, 0x0000, 0x9999, - "Maxtor", - "OneTouch External Harddrive", - USB_SC_DEVICE, USB_PR_DEVICE, onetouch_connect_input, - 0), - -UNUSUAL_DEV( 0x0d49, 0x7010, 0x0000, 0x9999, - "Maxtor", - "OneTouch External Harddrive", - USB_SC_DEVICE, USB_PR_DEVICE, onetouch_connect_input, - 0), - -#endif /* defined(CONFIG_USB_STORAGE_ONETOUCH) || ... */ diff --git a/ANDROID_3.4.5/drivers/usb/storage/unusual_realtek.h b/ANDROID_3.4.5/drivers/usb/storage/unusual_realtek.h deleted file mode 100644 index e41f50c9..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/unusual_realtek.h +++ /dev/null @@ -1,41 +0,0 @@ -/* Driver for Realtek RTS51xx USB card reader - * - * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - * - * Author: - * wwang (wei_wang@realsil.com.cn) - * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China - */ - -#if defined(CONFIG_USB_STORAGE_REALTEK) || \ - defined(CONFIG_USB_STORAGE_REALTEK_MODULE) - -UNUSUAL_DEV(0x0bda, 0x0138, 0x0000, 0x9999, - "Realtek", - "USB Card Reader", - USB_SC_DEVICE, USB_PR_DEVICE, init_realtek_cr, 0), - -UNUSUAL_DEV(0x0bda, 0x0158, 0x0000, 0x9999, - "Realtek", - "USB Card Reader", - USB_SC_DEVICE, USB_PR_DEVICE, init_realtek_cr, 0), - -UNUSUAL_DEV(0x0bda, 0x0159, 0x0000, 0x9999, - "Realtek", - "USB Card Reader", - USB_SC_DEVICE, USB_PR_DEVICE, init_realtek_cr, 0), - -#endif /* defined(CONFIG_USB_STORAGE_REALTEK) || ... */ diff --git a/ANDROID_3.4.5/drivers/usb/storage/unusual_sddr09.h b/ANDROID_3.4.5/drivers/usb/storage/unusual_sddr09.h deleted file mode 100644 index 59a7e37b..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/unusual_sddr09.h +++ /dev/null @@ -1,56 +0,0 @@ -/* Unusual Devices File for SanDisk SDDR-09 SmartMedia reader - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#if defined(CONFIG_USB_STORAGE_SDDR09) || \ - defined(CONFIG_USB_STORAGE_SDDR09_MODULE) - -UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100, - "Microtech", - "CameraMate (DPCM_USB)", - USB_SC_SCSI, USB_PR_DPCM_USB, NULL, 0), - -UNUSUAL_DEV( 0x04e6, 0x0003, 0x0000, 0x9999, - "Sandisk", - "ImageMate SDDR09", - USB_SC_SCSI, USB_PR_EUSB_SDDR09, usb_stor_sddr09_init, - 0), - -/* This entry is from Andries.Brouwer@cwi.nl */ -UNUSUAL_DEV( 0x04e6, 0x0005, 0x0100, 0x0208, - "SCM Microsystems", - "eUSB SmartMedia / CompactFlash Adapter", - USB_SC_SCSI, USB_PR_DPCM_USB, usb_stor_sddr09_dpcm_init, - 0), - -UNUSUAL_DEV( 0x066b, 0x0105, 0x0100, 0x0100, - "Olympus", - "Camedia MAUSB-2", - USB_SC_SCSI, USB_PR_EUSB_SDDR09, usb_stor_sddr09_init, - 0), - -UNUSUAL_DEV( 0x0781, 0x0200, 0x0000, 0x9999, - "Sandisk", - "ImageMate SDDR-09", - USB_SC_SCSI, USB_PR_EUSB_SDDR09, usb_stor_sddr09_init, - 0), - -UNUSUAL_DEV( 0x07af, 0x0006, 0x0100, 0x0100, - "Microtech", - "CameraMate (DPCM_USB)", - USB_SC_SCSI, USB_PR_DPCM_USB, NULL, 0), - -#endif /* defined(CONFIG_USB_STORAGE_SDDR09) || ... */ diff --git a/ANDROID_3.4.5/drivers/usb/storage/unusual_sddr55.h b/ANDROID_3.4.5/drivers/usb/storage/unusual_sddr55.h deleted file mode 100644 index fcb7e12c..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/unusual_sddr55.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Unusual Devices File for SanDisk SDDR-55 SmartMedia reader - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#if defined(CONFIG_USB_STORAGE_SDDR55) || \ - defined(CONFIG_USB_STORAGE_SDDR55_MODULE) - -/* Contributed by Peter Waechtler */ -UNUSUAL_DEV( 0x07c4, 0xa103, 0x0000, 0x9999, - "Datafab", - "MDSM-B reader", - USB_SC_SCSI, USB_PR_SDDR55, NULL, - US_FL_FIX_INQUIRY), - -/* SM part - aeb */ -UNUSUAL_DEV( 0x07c4, 0xa109, 0x0000, 0xffff, - "Datafab Systems, Inc.", - "USB to CF + SM Combo (LC1)", - USB_SC_SCSI, USB_PR_SDDR55, NULL, 0), - -UNUSUAL_DEV( 0x0c0b, 0xa109, 0x0000, 0xffff, - "Acomdata", - "SM", - USB_SC_SCSI, USB_PR_SDDR55, NULL, 0), - -UNUSUAL_DEV( 0x55aa, 0xa103, 0x0000, 0x9999, - "Sandisk", - "ImageMate SDDR55", - USB_SC_SCSI, USB_PR_SDDR55, NULL, 0), - -#endif /* defined(CONFIG_USB_STORAGE_SDDR55) || ... */ diff --git a/ANDROID_3.4.5/drivers/usb/storage/unusual_usbat.h b/ANDROID_3.4.5/drivers/usb/storage/unusual_usbat.h deleted file mode 100644 index 38e79c4e..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/unusual_usbat.h +++ /dev/null @@ -1,43 +0,0 @@ -/* Unusual Devices File for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#if defined(CONFIG_USB_STORAGE_USBAT) || \ - defined(CONFIG_USB_STORAGE_USBAT_MODULE) - -UNUSUAL_DEV( 0x03f0, 0x0207, 0x0001, 0x0001, - "HP", - "CD-Writer+ 8200e", - USB_SC_8070, USB_PR_USBAT, init_usbat_cd, 0), - -UNUSUAL_DEV( 0x03f0, 0x0307, 0x0001, 0x0001, - "HP", - "CD-Writer+ CD-4e", - USB_SC_8070, USB_PR_USBAT, init_usbat_cd, 0), - -UNUSUAL_DEV( 0x04e6, 0x1010, 0x0000, 0x9999, - "Shuttle/SCM", - "USBAT-02", - USB_SC_SCSI, USB_PR_USBAT, init_usbat_flash, - US_FL_SINGLE_LUN), - -UNUSUAL_DEV( 0x0781, 0x0005, 0x0005, 0x0005, - "Sandisk", - "ImageMate SDDR-05b", - USB_SC_SCSI, USB_PR_USBAT, init_usbat_flash, - US_FL_SINGLE_LUN), - -#endif /* defined(CONFIG_USB_STORAGE_USBAT) || ... */ diff --git a/ANDROID_3.4.5/drivers/usb/storage/usb.c b/ANDROID_3.4.5/drivers/usb/storage/usb.c deleted file mode 100644 index 95f5395a..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/usb.c +++ /dev/null @@ -1,1127 +0,0 @@ -/* Driver for USB Mass Storage compliant devices - * - * Current development and maintenance by: - * (c) 1999-2003 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * Developed with the assistance of: - * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) - * (c) 2003-2009 Alan Stern (stern@rowland.harvard.edu) - * - * Initial work by: - * (c) 1999 Michael Gee (michael@linuxspecific.com) - * - * usb_device_id support by Adam J. Richter (adam@yggdrasil.com): - * (c) 2000 Yggdrasil Computing, Inc. - * - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI and ATAPI commands in - * mind when they created this document. The commands are all very - * similar to commands in the SCSI-II and ATAPI specifications. - * - * It is important to note that in a number of cases this class - * exhibits class-specific exemptions from the USB specification. - * Notably the usage of NAK, STALL and ACK differs from the norm, in - * that they are used to communicate wait, failed and OK on commands. - * - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifdef CONFIG_USB_STORAGE_DEBUG -#define DEBUG -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "usb.h" -#include "scsiglue.h" -#include "transport.h" -#include "protocol.h" -#include "debug.h" -#include "initializers.h" - -#include "sierra_ms.h" -#include "option_ms.h" - -/* Some informational data */ -MODULE_AUTHOR("Matthew Dharm "); -MODULE_DESCRIPTION("USB Mass Storage driver for Linux"); -MODULE_LICENSE("GPL"); - -static unsigned int delay_use = 0;/*add by jay*/ -module_param(delay_use, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device"); - -static char quirks[128]; -module_param_string(quirks, quirks, sizeof(quirks), S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks"); - - -/* - * The entries in this table correspond, line for line, - * with the entries in usb_storage_usb_ids[], defined in usual-tables.c. - */ - -/* The vendor name should be kept at eight characters or less, and - * the product name should be kept at 16 characters or less. If a device - * has the US_FL_FIX_INQUIRY flag, then the vendor and product names - * normally generated by a device thorugh the INQUIRY response will be - * taken from this list, and this is the reason for the above size - * restriction. However, if the flag is not present, then you - * are free to use as many characters as you like. - */ - -#define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ - vendor_name, product_name, use_protocol, use_transport, \ - init_function, Flags) \ -{ \ - .vendorName = vendor_name, \ - .productName = product_name, \ - .useProtocol = use_protocol, \ - .useTransport = use_transport, \ - .initFunction = init_function, \ -} - -#define COMPLIANT_DEV UNUSUAL_DEV - -#define USUAL_DEV(use_protocol, use_transport, use_type) \ -{ \ - .useProtocol = use_protocol, \ - .useTransport = use_transport, \ -} - -static struct us_unusual_dev us_unusual_dev_list[] = { -# include "unusual_devs.h" - { } /* Terminating entry */ -}; - -static struct us_unusual_dev for_dynamic_ids = - USUAL_DEV(USB_SC_SCSI, USB_PR_BULK, 0); - -#undef UNUSUAL_DEV -#undef COMPLIANT_DEV -#undef USUAL_DEV - -#ifdef CONFIG_LOCKDEP - -static struct lock_class_key us_interface_key[USB_MAXINTERFACES]; - -static void us_set_lock_class(struct mutex *mutex, - struct usb_interface *intf) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct usb_host_config *config = udev->actconfig; - int i; - - for (i = 0; i < config->desc.bNumInterfaces; i++) { - if (config->interface[i] == intf) - break; - } - - BUG_ON(i == config->desc.bNumInterfaces); - - lockdep_set_class(mutex, &us_interface_key[i]); -} - -#else - -static void us_set_lock_class(struct mutex *mutex, - struct usb_interface *intf) -{ -} - -#endif - -#ifdef CONFIG_PM /* Minimal support for suspend and resume */ - -int usb_stor_suspend(struct usb_interface *iface, pm_message_t message) -{ - struct us_data *us = usb_get_intfdata(iface); - - /* Wait until no command is running */ - mutex_lock(&us->dev_mutex); - - US_DEBUGP("%s\n", __func__); - if (us->suspend_resume_hook) - (us->suspend_resume_hook)(us, US_SUSPEND); - - /* When runtime PM is working, we'll set a flag to indicate - * whether we should autoresume when a SCSI request arrives. */ - - mutex_unlock(&us->dev_mutex); - return 0; -} -EXPORT_SYMBOL_GPL(usb_stor_suspend); - -int usb_stor_resume(struct usb_interface *iface) -{ - struct us_data *us = usb_get_intfdata(iface); - - mutex_lock(&us->dev_mutex); - - US_DEBUGP("%s\n", __func__); - if (us->suspend_resume_hook) - (us->suspend_resume_hook)(us, US_RESUME); - - mutex_unlock(&us->dev_mutex); - return 0; -} -EXPORT_SYMBOL_GPL(usb_stor_resume); - -int usb_stor_reset_resume(struct usb_interface *iface) -{ - struct us_data *us = usb_get_intfdata(iface); - - US_DEBUGP("%s\n", __func__); - - /* Report the reset to the SCSI core */ - usb_stor_report_bus_reset(us); - - /* FIXME: Notify the subdrivers that they need to reinitialize - * the device */ - return 0; -} -EXPORT_SYMBOL_GPL(usb_stor_reset_resume); - -#endif /* CONFIG_PM */ - -/* - * The next two routines get called just before and just after - * a USB port reset, whether from this driver or a different one. - */ - -int usb_stor_pre_reset(struct usb_interface *iface) -{ - struct us_data *us = usb_get_intfdata(iface); - - US_DEBUGP("%s\n", __func__); - - /* Make sure no command runs during the reset */ - mutex_lock(&us->dev_mutex); - return 0; -} -EXPORT_SYMBOL_GPL(usb_stor_pre_reset); - -int usb_stor_post_reset(struct usb_interface *iface) -{ - struct us_data *us = usb_get_intfdata(iface); - - US_DEBUGP("%s\n", __func__); - - /* Report the reset to the SCSI core */ - usb_stor_report_bus_reset(us); - - /* FIXME: Notify the subdrivers that they need to reinitialize - * the device */ - - mutex_unlock(&us->dev_mutex); - return 0; -} -EXPORT_SYMBOL_GPL(usb_stor_post_reset); - -/* - * fill_inquiry_response takes an unsigned char array (which must - * be at least 36 characters) and populates the vendor name, - * product name, and revision fields. Then the array is copied - * into the SCSI command's response buffer (oddly enough - * called request_buffer). data_len contains the length of the - * data array, which again must be at least 36. - */ - -void fill_inquiry_response(struct us_data *us, unsigned char *data, - unsigned int data_len) -{ - if (data_len<36) // You lose. - return; - - memset(data+8, ' ', 28); - if(data[0]&0x20) { /* USB device currently not connected. Return - peripheral qualifier 001b ("...however, the - physical device is not currently connected - to this logical unit") and leave vendor and - product identification empty. ("If the target - does store some of the INQUIRY data on the - device, it may return zeros or ASCII spaces - (20h) in those fields until the data is - available from the device."). */ - } else { - u16 bcdDevice = le16_to_cpu(us->pusb_dev->descriptor.bcdDevice); - int n; - - n = strlen(us->unusual_dev->vendorName); - memcpy(data+8, us->unusual_dev->vendorName, min(8, n)); - n = strlen(us->unusual_dev->productName); - memcpy(data+16, us->unusual_dev->productName, min(16, n)); - - data[32] = 0x30 + ((bcdDevice>>12) & 0x0F); - data[33] = 0x30 + ((bcdDevice>>8) & 0x0F); - data[34] = 0x30 + ((bcdDevice>>4) & 0x0F); - data[35] = 0x30 + ((bcdDevice) & 0x0F); - } - - usb_stor_set_xfer_buf(data, data_len, us->srb); -} -EXPORT_SYMBOL_GPL(fill_inquiry_response); - -static int usb_stor_control_thread(void * __us) -{ - struct us_data *us = (struct us_data *)__us; - struct Scsi_Host *host = us_to_host(us); - - for(;;) { - US_DEBUGP("*** thread sleeping.\n"); - if (wait_for_completion_interruptible(&us->cmnd_ready)) - break; - - US_DEBUGP("*** thread awakened.\n"); - - /* lock the device pointers */ - mutex_lock(&(us->dev_mutex)); - - /* lock access to the state */ - scsi_lock(host); - - /* When we are called with no command pending, we're done */ - if (us->srb == NULL) { - scsi_unlock(host); - mutex_unlock(&us->dev_mutex); - US_DEBUGP("-- exiting\n"); - break; - } - - /* has the command timed out *already* ? */ - if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { - us->srb->result = DID_ABORT << 16; - goto SkipForAbort; - } - - scsi_unlock(host); - - /* reject the command if the direction indicator - * is UNKNOWN - */ - if (us->srb->sc_data_direction == DMA_BIDIRECTIONAL) { - US_DEBUGP("UNKNOWN data direction\n"); - us->srb->result = DID_ERROR << 16; - } - - /* reject if target != 0 or if LUN is higher than - * the maximum known LUN - */ - else if (us->srb->device->id && - !(us->fflags & US_FL_SCM_MULT_TARG)) { - US_DEBUGP("Bad target number (%d:%d)\n", - us->srb->device->id, us->srb->device->lun); - us->srb->result = DID_BAD_TARGET << 16; - } - - else if (us->srb->device->lun > us->max_lun) { - US_DEBUGP("Bad LUN (%d:%d)\n", - us->srb->device->id, us->srb->device->lun); - us->srb->result = DID_BAD_TARGET << 16; - } - - /* Handle those devices which need us to fake - * their inquiry data */ - else if ((us->srb->cmnd[0] == INQUIRY) && - (us->fflags & US_FL_FIX_INQUIRY)) { - unsigned char data_ptr[36] = { - 0x00, 0x80, 0x02, 0x02, - 0x1F, 0x00, 0x00, 0x00}; - - US_DEBUGP("Faking INQUIRY command\n"); - fill_inquiry_response(us, data_ptr, 36); - us->srb->result = SAM_STAT_GOOD; - } - - /* we've got a command, let's do it! */ - else { - US_DEBUG(usb_stor_show_command(us->srb)); - us->proto_handler(us->srb, us); - usb_mark_last_busy(us->pusb_dev); - } - - /* lock access to the state */ - scsi_lock(host); - - /* indicate that the command is done */ - if (us->srb->result != DID_ABORT << 16) { - US_DEBUGP("scsi cmd done, result=0x%x\n", - us->srb->result); - us->srb->scsi_done(us->srb); - } else { -SkipForAbort: - US_DEBUGP("scsi command aborted\n"); - } - - /* If an abort request was received we need to signal that - * the abort has finished. The proper test for this is - * the TIMED_OUT flag, not srb->result == DID_ABORT, because - * the timeout might have occurred after the command had - * already completed with a different result code. */ - if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { - complete(&(us->notify)); - - /* Allow USB transfers to resume */ - clear_bit(US_FLIDX_ABORTING, &us->dflags); - clear_bit(US_FLIDX_TIMED_OUT, &us->dflags); - } - - /* finished working on this command */ - us->srb = NULL; - scsi_unlock(host); - - /* unlock the device pointers */ - mutex_unlock(&us->dev_mutex); - } /* for (;;) */ - - /* Wait until we are told to stop */ - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (kthread_should_stop()) - break; - schedule(); - } - __set_current_state(TASK_RUNNING); - return 0; -} - -/*********************************************************************** - * Device probing and disconnecting - ***********************************************************************/ - -/* Associate our private data with the USB device */ -static int associate_dev(struct us_data *us, struct usb_interface *intf) -{ - US_DEBUGP("-- %s\n", __func__); - - /* Fill in the device-related fields */ - us->pusb_dev = interface_to_usbdev(intf); - us->pusb_intf = intf; - us->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; - US_DEBUGP("Vendor: 0x%04x, Product: 0x%04x, Revision: 0x%04x\n", - le16_to_cpu(us->pusb_dev->descriptor.idVendor), - le16_to_cpu(us->pusb_dev->descriptor.idProduct), - le16_to_cpu(us->pusb_dev->descriptor.bcdDevice)); - US_DEBUGP("Interface Subclass: 0x%02x, Protocol: 0x%02x\n", - intf->cur_altsetting->desc.bInterfaceSubClass, - intf->cur_altsetting->desc.bInterfaceProtocol); - - /* Store our private data in the interface */ - usb_set_intfdata(intf, us); - - /* Allocate the control/setup and DMA-mapped buffers */ - us->cr = kmalloc(sizeof(*us->cr), GFP_KERNEL); - if (!us->cr) { - US_DEBUGP("usb_ctrlrequest allocation failed\n"); - return -ENOMEM; - } - - us->iobuf = usb_alloc_coherent(us->pusb_dev, US_IOBUF_SIZE, - GFP_KERNEL, &us->iobuf_dma); - if (!us->iobuf) { - US_DEBUGP("I/O buffer allocation failed\n"); - return -ENOMEM; - } - return 0; -} - -/* Works only for digits and letters, but small and fast */ -#define TOLOWER(x) ((x) | 0x20) - -/* Adjust device flags based on the "quirks=" module parameter */ -static void adjust_quirks(struct us_data *us) -{ - char *p; - u16 vid = le16_to_cpu(us->pusb_dev->descriptor.idVendor); - u16 pid = le16_to_cpu(us->pusb_dev->descriptor.idProduct); - unsigned f = 0; - unsigned int mask = (US_FL_SANE_SENSE | US_FL_BAD_SENSE | - US_FL_FIX_CAPACITY | - US_FL_CAPACITY_HEURISTICS | US_FL_IGNORE_DEVICE | - US_FL_NOT_LOCKABLE | US_FL_MAX_SECTORS_64 | - US_FL_CAPACITY_OK | US_FL_IGNORE_RESIDUE | - US_FL_SINGLE_LUN | US_FL_NO_WP_DETECT | - US_FL_NO_READ_DISC_INFO | US_FL_NO_READ_CAPACITY_16 | - US_FL_INITIAL_READ10); - - p = quirks; - while (*p) { - /* Each entry consists of VID:PID:flags */ - if (vid == simple_strtoul(p, &p, 16) && - *p == ':' && - pid == simple_strtoul(p+1, &p, 16) && - *p == ':') - break; - - /* Move forward to the next entry */ - while (*p) { - if (*p++ == ',') - break; - } - } - if (!*p) /* No match */ - return; - - /* Collect the flags */ - while (*++p && *p != ',') { - switch (TOLOWER(*p)) { - case 'a': - f |= US_FL_SANE_SENSE; - break; - case 'b': - f |= US_FL_BAD_SENSE; - break; - case 'c': - f |= US_FL_FIX_CAPACITY; - break; - case 'd': - f |= US_FL_NO_READ_DISC_INFO; - break; - case 'e': - f |= US_FL_NO_READ_CAPACITY_16; - break; - case 'h': - f |= US_FL_CAPACITY_HEURISTICS; - break; - case 'i': - f |= US_FL_IGNORE_DEVICE; - break; - case 'l': - f |= US_FL_NOT_LOCKABLE; - break; - case 'm': - f |= US_FL_MAX_SECTORS_64; - break; - case 'n': - f |= US_FL_INITIAL_READ10; - break; - case 'o': - f |= US_FL_CAPACITY_OK; - break; - case 'r': - f |= US_FL_IGNORE_RESIDUE; - break; - case 's': - f |= US_FL_SINGLE_LUN; - break; - case 'w': - f |= US_FL_NO_WP_DETECT; - break; - /* Ignore unrecognized flag characters */ - } - } - us->fflags = (us->fflags & ~mask) | f; -} - -/* Get the unusual_devs entries and the string descriptors */ -static int get_device_info(struct us_data *us, const struct usb_device_id *id, - struct us_unusual_dev *unusual_dev) -{ - struct usb_device *dev = us->pusb_dev; - struct usb_interface_descriptor *idesc = - &us->pusb_intf->cur_altsetting->desc; - struct device *pdev = &us->pusb_intf->dev; - - /* Store the entries */ - us->unusual_dev = unusual_dev; - us->subclass = (unusual_dev->useProtocol == USB_SC_DEVICE) ? - idesc->bInterfaceSubClass : - unusual_dev->useProtocol; - us->protocol = (unusual_dev->useTransport == USB_PR_DEVICE) ? - idesc->bInterfaceProtocol : - unusual_dev->useTransport; - us->fflags = USB_US_ORIG_FLAGS(id->driver_info); - adjust_quirks(us); - - if (us->fflags & US_FL_IGNORE_DEVICE) { - dev_info(pdev, "device ignored\n"); - return -ENODEV; - } - - /* - * This flag is only needed when we're in high-speed, so let's - * disable it if we're in full-speed - */ - if (dev->speed != USB_SPEED_HIGH) - us->fflags &= ~US_FL_GO_SLOW; - - if (us->fflags) - dev_info(pdev, "Quirks match for vid %04x pid %04x: %lx\n", - le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct), - us->fflags); - - /* Log a message if a non-generic unusual_dev entry contains an - * unnecessary subclass or protocol override. This may stimulate - * reports from users that will help us remove unneeded entries - * from the unusual_devs.h table. - */ - if (id->idVendor || id->idProduct) { - static const char *msgs[3] = { - "an unneeded SubClass entry", - "an unneeded Protocol entry", - "unneeded SubClass and Protocol entries"}; - struct usb_device_descriptor *ddesc = &dev->descriptor; - int msg = -1; - - if (unusual_dev->useProtocol != USB_SC_DEVICE && - us->subclass == idesc->bInterfaceSubClass) - msg += 1; - if (unusual_dev->useTransport != USB_PR_DEVICE && - us->protocol == idesc->bInterfaceProtocol) - msg += 2; - if (msg >= 0 && !(us->fflags & US_FL_NEED_OVERRIDE)) - dev_notice(pdev, "This device " - "(%04x,%04x,%04x S %02x P %02x)" - " has %s in unusual_devs.h (kernel" - " %s)\n" - " Please send a copy of this message to " - " and " - "\n", - le16_to_cpu(ddesc->idVendor), - le16_to_cpu(ddesc->idProduct), - le16_to_cpu(ddesc->bcdDevice), - idesc->bInterfaceSubClass, - idesc->bInterfaceProtocol, - msgs[msg], - utsname()->release); - } - - return 0; -} - -/* Get the transport settings */ -static void get_transport(struct us_data *us) -{ - switch (us->protocol) { - case USB_PR_CB: - us->transport_name = "Control/Bulk"; - us->transport = usb_stor_CB_transport; - us->transport_reset = usb_stor_CB_reset; - us->max_lun = 7; - break; - - case USB_PR_CBI: - us->transport_name = "Control/Bulk/Interrupt"; - us->transport = usb_stor_CB_transport; - us->transport_reset = usb_stor_CB_reset; - us->max_lun = 7; - break; - - case USB_PR_BULK: - us->transport_name = "Bulk"; - us->transport = usb_stor_Bulk_transport; - us->transport_reset = usb_stor_Bulk_reset; - break; - } -} - -/* Get the protocol settings */ -static void get_protocol(struct us_data *us) -{ - switch (us->subclass) { - case USB_SC_RBC: - us->protocol_name = "Reduced Block Commands (RBC)"; - us->proto_handler = usb_stor_transparent_scsi_command; - break; - - case USB_SC_8020: - us->protocol_name = "8020i"; - us->proto_handler = usb_stor_pad12_command; - us->max_lun = 0; - break; - - case USB_SC_QIC: - us->protocol_name = "QIC-157"; - us->proto_handler = usb_stor_pad12_command; - us->max_lun = 0; - break; - - case USB_SC_8070: - us->protocol_name = "8070i"; - us->proto_handler = usb_stor_pad12_command; - us->max_lun = 0; - break; - - case USB_SC_SCSI: - us->protocol_name = "Transparent SCSI"; - us->proto_handler = usb_stor_transparent_scsi_command; - break; - - case USB_SC_UFI: - us->protocol_name = "Uniform Floppy Interface (UFI)"; - us->proto_handler = usb_stor_ufi_command; - break; - } -} - -/* Get the pipe settings */ -static int get_pipes(struct us_data *us) -{ - struct usb_host_interface *altsetting = - us->pusb_intf->cur_altsetting; - int i; - struct usb_endpoint_descriptor *ep; - struct usb_endpoint_descriptor *ep_in = NULL; - struct usb_endpoint_descriptor *ep_out = NULL; - struct usb_endpoint_descriptor *ep_int = NULL; - - /* - * Find the first endpoint of each type we need. - * We are expecting a minimum of 2 endpoints - in and out (bulk). - * An optional interrupt-in is OK (necessary for CBI protocol). - * We will ignore any others. - */ - for (i = 0; i < altsetting->desc.bNumEndpoints; i++) { - ep = &altsetting->endpoint[i].desc; - - if (usb_endpoint_xfer_bulk(ep)) { - if (usb_endpoint_dir_in(ep)) { - if (!ep_in) - ep_in = ep; - } else { - if (!ep_out) - ep_out = ep; - } - } - - else if (usb_endpoint_is_int_in(ep)) { - if (!ep_int) - ep_int = ep; - } - } - - if (!ep_in || !ep_out || (us->protocol == USB_PR_CBI && !ep_int)) { - US_DEBUGP("Endpoint sanity check failed! Rejecting dev.\n"); - return -EIO; - } - - /* Calculate and store the pipe values */ - us->send_ctrl_pipe = usb_sndctrlpipe(us->pusb_dev, 0); - us->recv_ctrl_pipe = usb_rcvctrlpipe(us->pusb_dev, 0); - us->send_bulk_pipe = usb_sndbulkpipe(us->pusb_dev, - usb_endpoint_num(ep_out)); - us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev, - usb_endpoint_num(ep_in)); - if (ep_int) { - us->recv_intr_pipe = usb_rcvintpipe(us->pusb_dev, - usb_endpoint_num(ep_int)); - us->ep_bInterval = ep_int->bInterval; - } - return 0; -} - -/* Initialize all the dynamic resources we need */ -static int usb_stor_acquire_resources(struct us_data *us) -{ - int p; - struct task_struct *th; - - us->current_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!us->current_urb) { - US_DEBUGP("URB allocation failed\n"); - return -ENOMEM; - } - - /* Just before we start our control thread, initialize - * the device if it needs initialization */ - if (us->unusual_dev->initFunction) { - p = us->unusual_dev->initFunction(us); - if (p) - return p; - } - - /* Start up our control thread */ - th = kthread_run(usb_stor_control_thread, us, "usb-storage"); - if (IS_ERR(th)) { - dev_warn(&us->pusb_intf->dev, - "Unable to start control thread\n"); - return PTR_ERR(th); - } - us->ctl_thread = th; - - return 0; -} - -/* Release all our dynamic resources */ -static void usb_stor_release_resources(struct us_data *us) -{ - US_DEBUGP("-- %s\n", __func__); - - /* Tell the control thread to exit. The SCSI host must - * already have been removed and the DISCONNECTING flag set - * so that we won't accept any more commands. - */ - US_DEBUGP("-- sending exit command to thread\n"); - complete(&us->cmnd_ready); - if (us->ctl_thread) - kthread_stop(us->ctl_thread); - - /* Call the destructor routine, if it exists */ - if (us->extra_destructor) { - US_DEBUGP("-- calling extra_destructor()\n"); - us->extra_destructor(us->extra); - } - - /* Free the extra data and the URB */ - kfree(us->extra); - usb_free_urb(us->current_urb); -} - -/* Dissociate from the USB device */ -static void dissociate_dev(struct us_data *us) -{ - US_DEBUGP("-- %s\n", __func__); - - /* Free the buffers */ - kfree(us->cr); - usb_free_coherent(us->pusb_dev, US_IOBUF_SIZE, us->iobuf, us->iobuf_dma); - - /* Remove our private data from the interface */ - usb_set_intfdata(us->pusb_intf, NULL); -} - -/* First stage of disconnect processing: stop SCSI scanning, - * remove the host, and stop accepting new commands - */ -static void quiesce_and_remove_host(struct us_data *us) -{ - struct Scsi_Host *host = us_to_host(us); - - /* If the device is really gone, cut short reset delays */ - if (us->pusb_dev->state == USB_STATE_NOTATTACHED) { - set_bit(US_FLIDX_DISCONNECTING, &us->dflags); - wake_up(&us->delay_wait); - } - - /* Prevent SCSI scanning (if it hasn't started yet) - * or wait for the SCSI-scanning routine to stop. - */ - cancel_delayed_work_sync(&us->scan_dwork); - - /* Balance autopm calls if scanning was cancelled */ - if (test_bit(US_FLIDX_SCAN_PENDING, &us->dflags)) - usb_autopm_put_interface_no_suspend(us->pusb_intf); - - /* Removing the host will perform an orderly shutdown: caches - * synchronized, disks spun down, etc. - */ - scsi_remove_host(host); - - /* Prevent any new commands from being accepted and cut short - * reset delays. - */ - scsi_lock(host); - set_bit(US_FLIDX_DISCONNECTING, &us->dflags); - scsi_unlock(host); - wake_up(&us->delay_wait); -} - -/* Second stage of disconnect processing: deallocate all resources */ -static void release_everything(struct us_data *us) -{ - usb_stor_release_resources(us); - dissociate_dev(us); - - /* Drop our reference to the host; the SCSI core will free it - * (and "us" along with it) when the refcount becomes 0. */ - scsi_host_put(us_to_host(us)); -} - -/* Delayed-work routine to carry out SCSI-device scanning */ -static void usb_stor_scan_dwork(struct work_struct *work) -{ - struct us_data *us = container_of(work, struct us_data, - scan_dwork.work); - struct device *dev = &us->pusb_intf->dev; - - dev_dbg(dev, "starting scan\n"); - - /* For bulk-only devices, determine the max LUN value */ - if (us->protocol == USB_PR_BULK && !(us->fflags & US_FL_SINGLE_LUN)) { - mutex_lock(&us->dev_mutex); - us->max_lun = usb_stor_Bulk_max_lun(us); - mutex_unlock(&us->dev_mutex); - } - scsi_scan_host(us_to_host(us)); - dev_dbg(dev, "scan complete\n"); - - /* Should we unbind if no devices were detected? */ - - usb_autopm_put_interface(us->pusb_intf); - clear_bit(US_FLIDX_SCAN_PENDING, &us->dflags); -} - -static unsigned int usb_stor_sg_tablesize(struct usb_interface *intf) -{ - struct usb_device *usb_dev = interface_to_usbdev(intf); - - if (usb_dev->bus->sg_tablesize) { - return usb_dev->bus->sg_tablesize; - } - return SG_ALL; -} - -/* First part of general USB mass-storage probing */ -int usb_stor_probe1(struct us_data **pus, - struct usb_interface *intf, - const struct usb_device_id *id, - struct us_unusual_dev *unusual_dev) -{ - struct Scsi_Host *host; - struct us_data *us; - int result; - - US_DEBUGP("USB Mass Storage device detected\n"); - - /* - * Ask the SCSI layer to allocate a host structure, with extra - * space at the end for our private us_data structure. - */ - host = scsi_host_alloc(&usb_stor_host_template, sizeof(*us)); - if (!host) { - dev_warn(&intf->dev, - "Unable to allocate the scsi host\n"); - return -ENOMEM; - } - - /* - * Allow 16-byte CDBs and thus > 2TB - */ - host->max_cmd_len = 16; - host->sg_tablesize = usb_stor_sg_tablesize(intf); - *pus = us = host_to_us(host); - memset(us, 0, sizeof(struct us_data)); - mutex_init(&(us->dev_mutex)); - us_set_lock_class(&us->dev_mutex, intf); - init_completion(&us->cmnd_ready); - init_completion(&(us->notify)); - init_waitqueue_head(&us->delay_wait); - INIT_DELAYED_WORK(&us->scan_dwork, usb_stor_scan_dwork); - - /* Associate the us_data structure with the USB device */ - result = associate_dev(us, intf); - if (result) - goto BadDevice; - - /* Get the unusual_devs entries and the descriptors */ - result = get_device_info(us, id, unusual_dev); - if (result) - goto BadDevice; - - /* Get standard transport and protocol settings */ - get_transport(us); - get_protocol(us); - - /* Give the caller a chance to fill in specialized transport - * or protocol settings. - */ - return 0; - -BadDevice: - US_DEBUGP("storage_probe() failed\n"); - release_everything(us); - return result; -} -EXPORT_SYMBOL_GPL(usb_stor_probe1); - -/* Second part of general USB mass-storage probing */ -int usb_stor_probe2(struct us_data *us) -{ - int result; - struct device *dev = &us->pusb_intf->dev; - - /* Make sure the transport and protocol have both been set */ - if (!us->transport || !us->proto_handler) { - result = -ENXIO; - goto BadDevice; - } - US_DEBUGP("Transport: %s\n", us->transport_name); - US_DEBUGP("Protocol: %s\n", us->protocol_name); - - /* fix for single-lun devices */ - if (us->fflags & US_FL_SINGLE_LUN) - us->max_lun = 0; - - /* Find the endpoints and calculate pipe values */ - result = get_pipes(us); - if (result) - goto BadDevice; - - /* - * If the device returns invalid data for the first READ(10) - * command, indicate the command should be retried. - */ - if (us->fflags & US_FL_INITIAL_READ10) - set_bit(US_FLIDX_REDO_READ10, &us->dflags); - - /* Acquire all the other resources and add the host */ - result = usb_stor_acquire_resources(us); - if (result) - goto BadDevice; - snprintf(us->scsi_name, sizeof(us->scsi_name), "usb-storage %s", - dev_name(&us->pusb_intf->dev)); - result = scsi_add_host(us_to_host(us), dev); - if (result) { - dev_warn(dev, - "Unable to add the scsi host\n"); - goto BadDevice; - } - - /* Submit the delayed_work for SCSI-device scanning */ - usb_autopm_get_interface_no_resume(us->pusb_intf); - set_bit(US_FLIDX_SCAN_PENDING, &us->dflags); - - if (delay_use > 0) - dev_dbg(dev, "waiting for device to settle before scanning\n"); - queue_delayed_work(system_freezable_wq, &us->scan_dwork, - delay_use * HZ); - return 0; - - /* We come here if there are any problems */ -BadDevice: - US_DEBUGP("storage_probe() failed\n"); - release_everything(us); - return result; -} -EXPORT_SYMBOL_GPL(usb_stor_probe2); - -/* Handle a USB mass-storage disconnect */ -void usb_stor_disconnect(struct usb_interface *intf) -{ - struct us_data *us = usb_get_intfdata(intf); - - US_DEBUGP("storage_disconnect() called\n"); - quiesce_and_remove_host(us); - release_everything(us); -} -EXPORT_SYMBOL_GPL(usb_stor_disconnect); - -/* The main probe routine for standard devices */ -static int storage_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct us_unusual_dev *unusual_dev; - struct us_data *us; - int result; - int size; - - /* - * If libusual is configured, let it decide whether a standard - * device should be handled by usb-storage or by ub. - * If the device isn't standard (is handled by a subdriver - * module) then don't accept it. - */ - if (usb_usual_check_type(id, USB_US_TYPE_STOR) || - usb_usual_ignore_device(intf)) - return -ENXIO; - - /* - * Call the general probe procedures. - * - * The unusual_dev_list array is parallel to the usb_storage_usb_ids - * table, so we use the index of the id entry to find the - * corresponding unusual_devs entry. - */ - - size = ARRAY_SIZE(us_unusual_dev_list); - if (id >= usb_storage_usb_ids && id < usb_storage_usb_ids + size) { - unusual_dev = (id - usb_storage_usb_ids) + us_unusual_dev_list; - } else { - unusual_dev = &for_dynamic_ids; - - US_DEBUGP("%s %s 0x%04x 0x%04x\n", "Use Bulk-Only transport", - "with the Transparent SCSI protocol for dynamic id:", - id->idVendor, id->idProduct); - } - - result = usb_stor_probe1(&us, intf, id, unusual_dev); - if (result) - return result; - - /* No special transport or protocol settings in the main module */ - - result = usb_stor_probe2(us); - return result; -} - -/*********************************************************************** - * Initialization and registration - ***********************************************************************/ - -static struct usb_driver usb_storage_driver = { - .name = "usb-storage", - .probe = storage_probe, - .disconnect = usb_stor_disconnect, - .suspend = usb_stor_suspend, - .resume = usb_stor_resume, - .reset_resume = usb_stor_reset_resume, - .pre_reset = usb_stor_pre_reset, - .post_reset = usb_stor_post_reset, - .id_table = usb_storage_usb_ids, - .supports_autosuspend = 1, - .soft_unbind = 1, -}; - -static int __init usb_stor_init(void) -{ - int retval; - - pr_info("Initializing USB Mass Storage driver...\n"); - - /* register the driver, return usb_register return code if error */ - retval = usb_register(&usb_storage_driver); - if (retval == 0) { - pr_info("USB Mass Storage support registered.\n"); - usb_usual_set_present(USB_US_TYPE_STOR); - } - return retval; -} - -static void __exit usb_stor_exit(void) -{ - US_DEBUGP("usb_stor_exit() called\n"); - - /* Deregister the driver - * This will cause disconnect() to be called for each - * attached unit - */ - US_DEBUGP("-- calling usb_deregister()\n"); - usb_deregister(&usb_storage_driver) ; - - usb_usual_clear_present(USB_US_TYPE_STOR); -} - -module_init(usb_stor_init); -module_exit(usb_stor_exit); diff --git a/ANDROID_3.4.5/drivers/usb/storage/usb.h b/ANDROID_3.4.5/drivers/usb/storage/usb.h deleted file mode 100644 index 75f70f04..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/usb.h +++ /dev/null @@ -1,204 +0,0 @@ -/* Driver for USB Mass Storage compliant devices - * Main Header File - * - * Current development and maintenance by: - * (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * Initial work by: - * (c) 1999 Michael Gee (michael@linuxspecific.com) - * - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI and ATAPI commands in - * mind when they created this document. The commands are all very - * similar to commands in the SCSI-II and ATAPI specifications. - * - * It is important to note that in a number of cases this class - * exhibits class-specific exemptions from the USB specification. - * Notably the usage of NAK, STALL and ACK differs from the norm, in - * that they are used to communicate wait, failed and OK on commands. - * - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _USB_H_ -#define _USB_H_ - -#include -#include -#include -#include -#include -#include -#include - -struct us_data; -struct scsi_cmnd; - -/* - * Unusual device list definitions - */ - -struct us_unusual_dev { - const char* vendorName; - const char* productName; - __u8 useProtocol; - __u8 useTransport; - int (*initFunction)(struct us_data *); -}; - - -/* Dynamic bitflag definitions (us->dflags): used in set_bit() etc. */ -#define US_FLIDX_URB_ACTIVE 0 /* current_urb is in use */ -#define US_FLIDX_SG_ACTIVE 1 /* current_sg is in use */ -#define US_FLIDX_ABORTING 2 /* abort is in progress */ -#define US_FLIDX_DISCONNECTING 3 /* disconnect in progress */ -#define US_FLIDX_RESETTING 4 /* device reset in progress */ -#define US_FLIDX_TIMED_OUT 5 /* SCSI midlayer timed out */ -#define US_FLIDX_SCAN_PENDING 6 /* scanning not yet done */ -#define US_FLIDX_REDO_READ10 7 /* redo READ(10) command */ -#define US_FLIDX_READ10_WORKED 8 /* previous READ(10) succeeded */ - -#define USB_STOR_STRING_LEN 32 - -/* - * We provide a DMA-mapped I/O buffer for use with small USB transfers. - * It turns out that CB[I] needs a 12-byte buffer and Bulk-only needs a - * 31-byte buffer. But Freecom needs a 64-byte buffer, so that's the - * size we'll allocate. - */ - -#define US_IOBUF_SIZE 64 /* Size of the DMA-mapped I/O buffer */ -#define US_SENSE_SIZE 18 /* Size of the autosense data buffer */ - -typedef int (*trans_cmnd)(struct scsi_cmnd *, struct us_data*); -typedef int (*trans_reset)(struct us_data*); -typedef void (*proto_cmnd)(struct scsi_cmnd*, struct us_data*); -typedef void (*extra_data_destructor)(void *); /* extra data destructor */ -typedef void (*pm_hook)(struct us_data *, int); /* power management hook */ - -#define US_SUSPEND 0 -#define US_RESUME 1 - -/* we allocate one of these for every device that we remember */ -struct us_data { - /* The device we're working with - * It's important to note: - * (o) you must hold dev_mutex to change pusb_dev - */ - struct mutex dev_mutex; /* protect pusb_dev */ - struct usb_device *pusb_dev; /* this usb_device */ - struct usb_interface *pusb_intf; /* this interface */ - struct us_unusual_dev *unusual_dev; /* device-filter entry */ - unsigned long fflags; /* fixed flags from filter */ - unsigned long dflags; /* dynamic atomic bitflags */ - unsigned int send_bulk_pipe; /* cached pipe values */ - unsigned int recv_bulk_pipe; - unsigned int send_ctrl_pipe; - unsigned int recv_ctrl_pipe; - unsigned int recv_intr_pipe; - - /* information about the device */ - char *transport_name; - char *protocol_name; - __le32 bcs_signature; - u8 subclass; - u8 protocol; - u8 max_lun; - - u8 ifnum; /* interface number */ - u8 ep_bInterval; /* interrupt interval */ - - /* function pointers for this device */ - trans_cmnd transport; /* transport function */ - trans_reset transport_reset; /* transport device reset */ - proto_cmnd proto_handler; /* protocol handler */ - - /* SCSI interfaces */ - struct scsi_cmnd *srb; /* current srb */ - unsigned int tag; /* current dCBWTag */ - char scsi_name[32]; /* scsi_host name */ - - /* control and bulk communications data */ - struct urb *current_urb; /* USB requests */ - struct usb_ctrlrequest *cr; /* control requests */ - struct usb_sg_request current_sg; /* scatter-gather req. */ - unsigned char *iobuf; /* I/O buffer */ - dma_addr_t iobuf_dma; /* buffer DMA addresses */ - struct task_struct *ctl_thread; /* the control thread */ - - /* mutual exclusion and synchronization structures */ - struct completion cmnd_ready; /* to sleep thread on */ - struct completion notify; /* thread begin/end */ - wait_queue_head_t delay_wait; /* wait during reset */ - struct delayed_work scan_dwork; /* for async scanning */ - - /* subdriver information */ - void *extra; /* Any extra data */ - extra_data_destructor extra_destructor;/* extra data destructor */ -#ifdef CONFIG_PM - pm_hook suspend_resume_hook; -#endif - - /* hacks for READ CAPACITY bug handling */ - int use_last_sector_hacks; - int last_sector_retries; -}; - -/* Convert between us_data and the corresponding Scsi_Host */ -static inline struct Scsi_Host *us_to_host(struct us_data *us) { - return container_of((void *) us, struct Scsi_Host, hostdata); -} -static inline struct us_data *host_to_us(struct Scsi_Host *host) { - return (struct us_data *) host->hostdata; -} - -/* Function to fill an inquiry response. See usb.c for details */ -extern void fill_inquiry_response(struct us_data *us, - unsigned char *data, unsigned int data_len); - -/* The scsi_lock() and scsi_unlock() macros protect the sm_state and the - * single queue element srb for write access */ -#define scsi_unlock(host) spin_unlock_irq(host->host_lock) -#define scsi_lock(host) spin_lock_irq(host->host_lock) - -/* General routines provided by the usb-storage standard core */ -#ifdef CONFIG_PM -extern int usb_stor_suspend(struct usb_interface *iface, pm_message_t message); -extern int usb_stor_resume(struct usb_interface *iface); -extern int usb_stor_reset_resume(struct usb_interface *iface); -#else -#define usb_stor_suspend NULL -#define usb_stor_resume NULL -#define usb_stor_reset_resume NULL -#endif - -extern int usb_stor_pre_reset(struct usb_interface *iface); -extern int usb_stor_post_reset(struct usb_interface *iface); - -extern int usb_stor_probe1(struct us_data **pus, - struct usb_interface *intf, - const struct usb_device_id *id, - struct us_unusual_dev *unusual_dev); -extern int usb_stor_probe2(struct us_data *us); -extern void usb_stor_disconnect(struct usb_interface *intf); - -#endif diff --git a/ANDROID_3.4.5/drivers/usb/storage/usual-tables.c b/ANDROID_3.4.5/drivers/usb/storage/usual-tables.c deleted file mode 100644 index b9692791..00000000 --- a/ANDROID_3.4.5/drivers/usb/storage/usual-tables.c +++ /dev/null @@ -1,118 +0,0 @@ -/* Driver for USB Mass Storage devices - * Usual Tables File for usb-storage and libusual - * - * Copyright (C) 2009 Alan Stern (stern@rowland.harvard.edu) - * - * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more - * information about this driver. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - - -/* - * The table of devices - */ -#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ - vendorName, productName, useProtocol, useTransport, \ - initFunction, flags) \ -{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } - -#define COMPLIANT_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ - vendorName, productName, useProtocol, useTransport, \ - initFunction, flags) \ -{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ - .driver_info = (flags) } - -#define USUAL_DEV(useProto, useTrans, useType) \ -{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans), \ - .driver_info = ((useType)<<24) } - -struct usb_device_id usb_storage_usb_ids[] = { -# include "unusual_devs.h" - { } /* Terminating entry */ -}; -EXPORT_SYMBOL_GPL(usb_storage_usb_ids); - -MODULE_DEVICE_TABLE(usb, usb_storage_usb_ids); - -#undef UNUSUAL_DEV -#undef COMPLIANT_DEV -#undef USUAL_DEV - - -/* - * The table of devices to ignore - */ -struct ignore_entry { - u16 vid, pid, bcdmin, bcdmax; -}; - -#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ - vendorName, productName, useProtocol, useTransport, \ - initFunction, flags) \ -{ \ - .vid = id_vendor, \ - .pid = id_product, \ - .bcdmin = bcdDeviceMin, \ - .bcdmax = bcdDeviceMax, \ -} - -static struct ignore_entry ignore_ids[] = { -# include "unusual_alauda.h" -# include "unusual_cypress.h" -# include "unusual_datafab.h" -# include "unusual_ene_ub6250.h" -# include "unusual_freecom.h" -# include "unusual_isd200.h" -# include "unusual_jumpshot.h" -# include "unusual_karma.h" -# include "unusual_onetouch.h" -# include "unusual_realtek.h" -# include "unusual_sddr09.h" -# include "unusual_sddr55.h" -# include "unusual_usbat.h" - { } /* Terminating entry */ -}; - -#undef UNUSUAL_DEV - - -/* Return an error if a device is in the ignore_ids list */ -int usb_usual_ignore_device(struct usb_interface *intf) -{ - struct usb_device *udev; - unsigned vid, pid, bcd; - struct ignore_entry *p; - - udev = interface_to_usbdev(intf); - vid = le16_to_cpu(udev->descriptor.idVendor); - pid = le16_to_cpu(udev->descriptor.idProduct); - bcd = le16_to_cpu(udev->descriptor.bcdDevice); - - for (p = ignore_ids; p->vid; ++p) { - if (p->vid == vid && p->pid == pid && - p->bcdmin <= bcd && p->bcdmax >= bcd) - return -ENXIO; - } - return 0; -} -EXPORT_SYMBOL_GPL(usb_usual_ignore_device); diff --git a/ANDROID_3.4.5/drivers/usb/usb-common.c b/ANDROID_3.4.5/drivers/usb/usb-common.c deleted file mode 100644 index d29503e9..00000000 --- a/ANDROID_3.4.5/drivers/usb/usb-common.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Provides code common for host and device side USB. - * - * 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, version 2. - * - * If either host side (ie. CONFIG_USB=y) or device side USB stack - * (ie. CONFIG_USB_GADGET=y) is compiled in the kernel, this module is - * compiled-in as well. Otherwise, if either of the two stacks is - * compiled as module, this file is compiled as module as well. - */ - -#include -#include -#include - -const char *usb_speed_string(enum usb_device_speed speed) -{ - static const char *const names[] = { - [USB_SPEED_UNKNOWN] = "UNKNOWN", - [USB_SPEED_LOW] = "low-speed", - [USB_SPEED_FULL] = "full-speed", - [USB_SPEED_HIGH] = "high-speed", - [USB_SPEED_WIRELESS] = "wireless", - [USB_SPEED_SUPER] = "super-speed", - }; - - if (speed < 0 || speed >= ARRAY_SIZE(names)) - speed = USB_SPEED_UNKNOWN; - return names[speed]; -} -EXPORT_SYMBOL_GPL(usb_speed_string); - -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/usb-skeleton.c b/ANDROID_3.4.5/drivers/usb/usb-skeleton.c deleted file mode 100644 index b4a71679..00000000 --- a/ANDROID_3.4.5/drivers/usb/usb-skeleton.c +++ /dev/null @@ -1,679 +0,0 @@ -/* - * USB Skeleton driver - 2.2 - * - * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - * This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c - * but has been rewritten to be easier to read and use. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* Define these values to match your devices */ -#define USB_SKEL_VENDOR_ID 0xfff0 -#define USB_SKEL_PRODUCT_ID 0xfff0 - -/* table of devices that work with this driver */ -static const struct usb_device_id skel_table[] = { - { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(usb, skel_table); - - -/* Get a minor range for your devices from the usb maintainer */ -#define USB_SKEL_MINOR_BASE 192 - -/* our private defines. if this grows any larger, use your own .h file */ -#define MAX_TRANSFER (PAGE_SIZE - 512) -/* MAX_TRANSFER is chosen so that the VM is not stressed by - allocations > PAGE_SIZE and the number of packets in a page - is an integer 512 is the largest possible packet on EHCI */ -#define WRITES_IN_FLIGHT 8 -/* arbitrarily chosen */ - -/* Structure to hold all of our device specific stuff */ -struct usb_skel { - struct usb_device *udev; /* the usb device for this device */ - struct usb_interface *interface; /* the interface for this device */ - struct semaphore limit_sem; /* limiting the number of writes in progress */ - struct usb_anchor submitted; /* in case we need to retract our submissions */ - struct urb *bulk_in_urb; /* the urb to read data with */ - unsigned char *bulk_in_buffer; /* the buffer to receive data */ - size_t bulk_in_size; /* the size of the receive buffer */ - size_t bulk_in_filled; /* number of bytes in the buffer */ - size_t bulk_in_copied; /* already copied to user space */ - __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ - __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ - int errors; /* the last request tanked */ - bool ongoing_read; /* a read is going on */ - bool processed_urb; /* indicates we haven't processed the urb */ - spinlock_t err_lock; /* lock for errors */ - struct kref kref; - struct mutex io_mutex; /* synchronize I/O with disconnect */ - struct completion bulk_in_completion; /* to wait for an ongoing read */ -}; -#define to_skel_dev(d) container_of(d, struct usb_skel, kref) - -static struct usb_driver skel_driver; -static void skel_draw_down(struct usb_skel *dev); - -static void skel_delete(struct kref *kref) -{ - struct usb_skel *dev = to_skel_dev(kref); - - usb_free_urb(dev->bulk_in_urb); - usb_put_dev(dev->udev); - kfree(dev->bulk_in_buffer); - kfree(dev); -} - -static int skel_open(struct inode *inode, struct file *file) -{ - struct usb_skel *dev; - struct usb_interface *interface; - int subminor; - int retval = 0; - - subminor = iminor(inode); - - interface = usb_find_interface(&skel_driver, subminor); - if (!interface) { - err("%s - error, can't find device for minor %d", - __func__, subminor); - retval = -ENODEV; - goto exit; - } - - dev = usb_get_intfdata(interface); - if (!dev) { - retval = -ENODEV; - goto exit; - } - - /* increment our usage count for the device */ - kref_get(&dev->kref); - - /* lock the device to allow correctly handling errors - * in resumption */ - mutex_lock(&dev->io_mutex); - - retval = usb_autopm_get_interface(interface); - if (retval) - goto out_err; - - /* save our object in the file's private structure */ - file->private_data = dev; - mutex_unlock(&dev->io_mutex); - -exit: - return retval; -} - -static int skel_release(struct inode *inode, struct file *file) -{ - struct usb_skel *dev; - - dev = file->private_data; - if (dev == NULL) - return -ENODEV; - - /* allow the device to be autosuspended */ - mutex_lock(&dev->io_mutex); - if (dev->interface) - usb_autopm_put_interface(dev->interface); - mutex_unlock(&dev->io_mutex); - - /* decrement the count on our device */ - kref_put(&dev->kref, skel_delete); - return 0; -} - -static int skel_flush(struct file *file, fl_owner_t id) -{ - struct usb_skel *dev; - int res; - - dev = file->private_data; - if (dev == NULL) - return -ENODEV; - - /* wait for io to stop */ - mutex_lock(&dev->io_mutex); - skel_draw_down(dev); - - /* read out errors, leave subsequent opens a clean slate */ - spin_lock_irq(&dev->err_lock); - res = dev->errors ? (dev->errors == -EPIPE ? -EPIPE : -EIO) : 0; - dev->errors = 0; - spin_unlock_irq(&dev->err_lock); - - mutex_unlock(&dev->io_mutex); - - return res; -} - -static void skel_read_bulk_callback(struct urb *urb) -{ - struct usb_skel *dev; - - dev = urb->context; - - spin_lock(&dev->err_lock); - /* sync/async unlink faults aren't errors */ - if (urb->status) { - if (!(urb->status == -ENOENT || - urb->status == -ECONNRESET || - urb->status == -ESHUTDOWN)) - err("%s - nonzero write bulk status received: %d", - __func__, urb->status); - - dev->errors = urb->status; - } else { - dev->bulk_in_filled = urb->actual_length; - } - dev->ongoing_read = 0; - spin_unlock(&dev->err_lock); - - complete(&dev->bulk_in_completion); -} - -static int skel_do_read_io(struct usb_skel *dev, size_t count) -{ - int rv; - - /* prepare a read */ - usb_fill_bulk_urb(dev->bulk_in_urb, - dev->udev, - usb_rcvbulkpipe(dev->udev, - dev->bulk_in_endpointAddr), - dev->bulk_in_buffer, - min(dev->bulk_in_size, count), - skel_read_bulk_callback, - dev); - /* tell everybody to leave the URB alone */ - spin_lock_irq(&dev->err_lock); - dev->ongoing_read = 1; - spin_unlock_irq(&dev->err_lock); - - /* do it */ - rv = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL); - if (rv < 0) { - err("%s - failed submitting read urb, error %d", - __func__, rv); - dev->bulk_in_filled = 0; - rv = (rv == -ENOMEM) ? rv : -EIO; - spin_lock_irq(&dev->err_lock); - dev->ongoing_read = 0; - spin_unlock_irq(&dev->err_lock); - } - - return rv; -} - -static ssize_t skel_read(struct file *file, char *buffer, size_t count, - loff_t *ppos) -{ - struct usb_skel *dev; - int rv; - bool ongoing_io; - - dev = file->private_data; - - /* if we cannot read at all, return EOF */ - if (!dev->bulk_in_urb || !count) - return 0; - - /* no concurrent readers */ - rv = mutex_lock_interruptible(&dev->io_mutex); - if (rv < 0) - return rv; - - if (!dev->interface) { /* disconnect() was called */ - rv = -ENODEV; - goto exit; - } - - /* if IO is under way, we must not touch things */ -retry: - spin_lock_irq(&dev->err_lock); - ongoing_io = dev->ongoing_read; - spin_unlock_irq(&dev->err_lock); - - if (ongoing_io) { - /* nonblocking IO shall not wait */ - if (file->f_flags & O_NONBLOCK) { - rv = -EAGAIN; - goto exit; - } - /* - * IO may take forever - * hence wait in an interruptible state - */ - rv = wait_for_completion_interruptible(&dev->bulk_in_completion); - if (rv < 0) - goto exit; - /* - * by waiting we also semiprocessed the urb - * we must finish now - */ - dev->bulk_in_copied = 0; - dev->processed_urb = 1; - } - - if (!dev->processed_urb) { - /* - * the URB hasn't been processed - * do it now - */ - wait_for_completion(&dev->bulk_in_completion); - dev->bulk_in_copied = 0; - dev->processed_urb = 1; - } - - /* errors must be reported */ - rv = dev->errors; - if (rv < 0) { - /* any error is reported once */ - dev->errors = 0; - /* to preserve notifications about reset */ - rv = (rv == -EPIPE) ? rv : -EIO; - /* no data to deliver */ - dev->bulk_in_filled = 0; - /* report it */ - goto exit; - } - - /* - * if the buffer is filled we may satisfy the read - * else we need to start IO - */ - - if (dev->bulk_in_filled) { - /* we had read data */ - size_t available = dev->bulk_in_filled - dev->bulk_in_copied; - size_t chunk = min(available, count); - - if (!available) { - /* - * all data has been used - * actual IO needs to be done - */ - rv = skel_do_read_io(dev, count); - if (rv < 0) - goto exit; - else - goto retry; - } - /* - * data is available - * chunk tells us how much shall be copied - */ - - if (copy_to_user(buffer, - dev->bulk_in_buffer + dev->bulk_in_copied, - chunk)) - rv = -EFAULT; - else - rv = chunk; - - dev->bulk_in_copied += chunk; - - /* - * if we are asked for more than we have, - * we start IO but don't wait - */ - if (available < count) - skel_do_read_io(dev, count - chunk); - } else { - /* no data in the buffer */ - rv = skel_do_read_io(dev, count); - if (rv < 0) - goto exit; - else if (!(file->f_flags & O_NONBLOCK)) - goto retry; - rv = -EAGAIN; - } -exit: - mutex_unlock(&dev->io_mutex); - return rv; -} - -static void skel_write_bulk_callback(struct urb *urb) -{ - struct usb_skel *dev; - - dev = urb->context; - - /* sync/async unlink faults aren't errors */ - if (urb->status) { - if (!(urb->status == -ENOENT || - urb->status == -ECONNRESET || - urb->status == -ESHUTDOWN)) - err("%s - nonzero write bulk status received: %d", - __func__, urb->status); - - spin_lock(&dev->err_lock); - dev->errors = urb->status; - spin_unlock(&dev->err_lock); - } - - /* free up our allocated buffer */ - usb_free_coherent(urb->dev, urb->transfer_buffer_length, - urb->transfer_buffer, urb->transfer_dma); - up(&dev->limit_sem); -} - -static ssize_t skel_write(struct file *file, const char *user_buffer, - size_t count, loff_t *ppos) -{ - struct usb_skel *dev; - int retval = 0; - struct urb *urb = NULL; - char *buf = NULL; - size_t writesize = min(count, (size_t)MAX_TRANSFER); - - dev = file->private_data; - - /* verify that we actually have some data to write */ - if (count == 0) - goto exit; - - /* - * limit the number of URBs in flight to stop a user from using up all - * RAM - */ - if (!(file->f_flags & O_NONBLOCK)) { - if (down_interruptible(&dev->limit_sem)) { - retval = -ERESTARTSYS; - goto exit; - } - } else { - if (down_trylock(&dev->limit_sem)) { - retval = -EAGAIN; - goto exit; - } - } - - spin_lock_irq(&dev->err_lock); - retval = dev->errors; - if (retval < 0) { - /* any error is reported once */ - dev->errors = 0; - /* to preserve notifications about reset */ - retval = (retval == -EPIPE) ? retval : -EIO; - } - spin_unlock_irq(&dev->err_lock); - if (retval < 0) - goto error; - - /* create a urb, and a buffer for it, and copy the data to the urb */ - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - retval = -ENOMEM; - goto error; - } - - buf = usb_alloc_coherent(dev->udev, writesize, GFP_KERNEL, - &urb->transfer_dma); - if (!buf) { - retval = -ENOMEM; - goto error; - } - - if (copy_from_user(buf, user_buffer, writesize)) { - retval = -EFAULT; - goto error; - } - - /* this lock makes sure we don't submit URBs to gone devices */ - mutex_lock(&dev->io_mutex); - if (!dev->interface) { /* disconnect() was called */ - mutex_unlock(&dev->io_mutex); - retval = -ENODEV; - goto error; - } - - /* initialize the urb properly */ - usb_fill_bulk_urb(urb, dev->udev, - usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), - buf, writesize, skel_write_bulk_callback, dev); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - usb_anchor_urb(urb, &dev->submitted); - - /* send the data out the bulk port */ - retval = usb_submit_urb(urb, GFP_KERNEL); - mutex_unlock(&dev->io_mutex); - if (retval) { - err("%s - failed submitting write urb, error %d", __func__, - retval); - goto error_unanchor; - } - - /* - * release our reference to this urb, the USB core will eventually free - * it entirely - */ - usb_free_urb(urb); - - - return writesize; - -error_unanchor: - usb_unanchor_urb(urb); -error: - if (urb) { - usb_free_coherent(dev->udev, writesize, buf, urb->transfer_dma); - usb_free_urb(urb); - } - up(&dev->limit_sem); - -exit: - return retval; -} - -static const struct file_operations skel_fops = { - .owner = THIS_MODULE, - .read = skel_read, - .write = skel_write, - .open = skel_open, - .release = skel_release, - .flush = skel_flush, - .llseek = noop_llseek, -}; - -/* - * usb class driver info in order to get a minor number from the usb core, - * and to have the device registered with the driver core - */ -static struct usb_class_driver skel_class = { - .name = "skel%d", - .fops = &skel_fops, - .minor_base = USB_SKEL_MINOR_BASE, -}; - -static int skel_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_skel *dev; - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - size_t buffer_size; - int i; - int retval = -ENOMEM; - - /* allocate memory for our device state and initialize it */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - err("Out of memory"); - goto error; - } - kref_init(&dev->kref); - sema_init(&dev->limit_sem, WRITES_IN_FLIGHT); - mutex_init(&dev->io_mutex); - spin_lock_init(&dev->err_lock); - init_usb_anchor(&dev->submitted); - init_completion(&dev->bulk_in_completion); - - dev->udev = usb_get_dev(interface_to_usbdev(interface)); - dev->interface = interface; - - /* set up the endpoint information */ - /* use only the first bulk-in and bulk-out endpoints */ - iface_desc = interface->cur_altsetting; - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - endpoint = &iface_desc->endpoint[i].desc; - - if (!dev->bulk_in_endpointAddr && - usb_endpoint_is_bulk_in(endpoint)) { - /* we found a bulk in endpoint */ - buffer_size = usb_endpoint_maxp(endpoint); - dev->bulk_in_size = buffer_size; - dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; - dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!dev->bulk_in_buffer) { - err("Could not allocate bulk_in_buffer"); - goto error; - } - dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!dev->bulk_in_urb) { - err("Could not allocate bulk_in_urb"); - goto error; - } - } - - if (!dev->bulk_out_endpointAddr && - usb_endpoint_is_bulk_out(endpoint)) { - /* we found a bulk out endpoint */ - dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; - } - } - if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) { - err("Could not find both bulk-in and bulk-out endpoints"); - goto error; - } - - /* save our data pointer in this interface device */ - usb_set_intfdata(interface, dev); - - /* we can register the device now, as it is ready */ - retval = usb_register_dev(interface, &skel_class); - if (retval) { - /* something prevented us from registering this driver */ - err("Not able to get a minor for this device."); - usb_set_intfdata(interface, NULL); - goto error; - } - - /* let the user know what node this device is now attached to */ - dev_info(&interface->dev, - "USB Skeleton device now attached to USBSkel-%d", - interface->minor); - return 0; - -error: - if (dev) - /* this frees allocated memory */ - kref_put(&dev->kref, skel_delete); - return retval; -} - -static void skel_disconnect(struct usb_interface *interface) -{ - struct usb_skel *dev; - int minor = interface->minor; - - dev = usb_get_intfdata(interface); - usb_set_intfdata(interface, NULL); - - /* give back our minor */ - usb_deregister_dev(interface, &skel_class); - - /* prevent more I/O from starting */ - mutex_lock(&dev->io_mutex); - dev->interface = NULL; - mutex_unlock(&dev->io_mutex); - - usb_kill_anchored_urbs(&dev->submitted); - - /* decrement our usage count */ - kref_put(&dev->kref, skel_delete); - - dev_info(&interface->dev, "USB Skeleton #%d now disconnected", minor); -} - -static void skel_draw_down(struct usb_skel *dev) -{ - int time; - - time = usb_wait_anchor_empty_timeout(&dev->submitted, 1000); - if (!time) - usb_kill_anchored_urbs(&dev->submitted); - usb_kill_urb(dev->bulk_in_urb); -} - -static int skel_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct usb_skel *dev = usb_get_intfdata(intf); - - if (!dev) - return 0; - skel_draw_down(dev); - return 0; -} - -static int skel_resume(struct usb_interface *intf) -{ - return 0; -} - -static int skel_pre_reset(struct usb_interface *intf) -{ - struct usb_skel *dev = usb_get_intfdata(intf); - - mutex_lock(&dev->io_mutex); - skel_draw_down(dev); - - return 0; -} - -static int skel_post_reset(struct usb_interface *intf) -{ - struct usb_skel *dev = usb_get_intfdata(intf); - - /* we are sure no URBs are active - no locking needed */ - dev->errors = -EPIPE; - mutex_unlock(&dev->io_mutex); - - return 0; -} - -static struct usb_driver skel_driver = { - .name = "skeleton", - .probe = skel_probe, - .disconnect = skel_disconnect, - .suspend = skel_suspend, - .resume = skel_resume, - .pre_reset = skel_pre_reset, - .post_reset = skel_post_reset, - .id_table = skel_table, - .supports_autosuspend = 1, -}; - -module_usb_driver(skel_driver); - -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/wusbcore/Kconfig b/ANDROID_3.4.5/drivers/usb/wusbcore/Kconfig deleted file mode 100644 index f29fdd7f..00000000 --- a/ANDROID_3.4.5/drivers/usb/wusbcore/Kconfig +++ /dev/null @@ -1,42 +0,0 @@ -# -# Wireless USB Core configuration -# -config USB_WUSB - tristate "Enable Wireless USB extensions (EXPERIMENTAL)" - depends on EXPERIMENTAL - depends on USB - depends on PCI - depends on UWB - select CRYPTO - select CRYPTO_BLKCIPHER - select CRYPTO_CBC - select CRYPTO_MANAGER - select CRYPTO_AES - help - Enable the host-side support for Wireless USB. - - To compile this support select Y (built in). It is safe to - select even if you don't have the hardware. - -config USB_WUSB_CBAF - tristate "Support WUSB Cable Based Association (CBA)" - depends on USB - help - Some WUSB devices support Cable Based Association. It's used to - enable the secure communication between the host and the - device. - - Enable this option if your WUSB device must to be connected - via wired USB before establishing a wireless link. - - It is safe to select even if you don't have a compatible - hardware. - -config USB_WUSB_CBAF_DEBUG - bool "Enable CBA debug messages" - depends on USB_WUSB_CBAF - help - Say Y here if you want the CBA to produce a bunch of debug messages - to the system log. Select this if you are having a problem with - CBA support and want to see more of what is going on. - diff --git a/ANDROID_3.4.5/drivers/usb/wusbcore/Makefile b/ANDROID_3.4.5/drivers/usb/wusbcore/Makefile deleted file mode 100644 index b3bd3130..00000000 --- a/ANDROID_3.4.5/drivers/usb/wusbcore/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -ccflags-$(CONFIG_USB_WUSB_CBAF_DEBUG) := -DDEBUG - -obj-$(CONFIG_USB_WUSB) += wusbcore.o -obj-$(CONFIG_USB_HWA_HCD) += wusb-wa.o -obj-$(CONFIG_USB_WUSB_CBAF) += wusb-cbaf.o - - -wusbcore-y := \ - crypto.o \ - devconnect.o \ - dev-sysfs.o \ - mmc.o \ - pal.o \ - rh.o \ - reservation.o \ - security.o \ - wusbhc.o - -wusb-cbaf-y := cbaf.o - -wusb-wa-y := \ - wa-hc.o \ - wa-nep.o \ - wa-rpipe.o \ - wa-xfer.o diff --git a/ANDROID_3.4.5/drivers/usb/wusbcore/cbaf.c b/ANDROID_3.4.5/drivers/usb/wusbcore/cbaf.c deleted file mode 100644 index 7f78f300..00000000 --- a/ANDROID_3.4.5/drivers/usb/wusbcore/cbaf.c +++ /dev/null @@ -1,662 +0,0 @@ -/* - * Wireless USB - Cable Based Association - * - * - * Copyright (C) 2006 Intel Corporation - * Inaky Perez-Gonzalez - * Copyright (C) 2008 Cambridge Silicon Radio Ltd. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * - * WUSB devices have to be paired (associated in WUSB lingo) so - * that they can connect to the system. - * - * One way of pairing is using CBA-Cable Based Association. First - * time you plug the device with a cable, association is done between - * host and device and subsequent times, you can connect wirelessly - * without having to associate again. That's the idea. - * - * This driver does nothing Earth shattering. It just provides an - * interface to chat with the wire-connected device so we can get a - * CDID (device ID) that might have been previously associated to a - * CHID (host ID) and to set up a new triplet - * (connection context), with the CK being the secret, or connection - * key. This is the pairing data. - * - * When a device with the CBA capability connects, the probe routine - * just creates a bunch of sysfs files that a user space enumeration - * manager uses to allow it to connect wirelessly to the system or not. - * - * The process goes like this: - * - * 1. Device plugs, cbaf is loaded, notifications happen. - * - * 2. The connection manager (CM) sees a device with CBAF capability - * (the wusb_chid etc. files in /sys/devices/blah/OURDEVICE). - * - * 3. The CM writes the host name, supported band groups, and the CHID - * (host ID) into the wusb_host_name, wusb_host_band_groups and - * wusb_chid files. These get sent to the device and the CDID (if - * any) for this host is requested. - * - * 4. The CM can verify that the device's supported band groups - * (wusb_device_band_groups) are compatible with the host. - * - * 5. The CM reads the wusb_cdid file. - * - * 6. The CM looks up its database - * - * 6.1 If it has a matching CHID,CDID entry, the device has been - * authorized before (paired) and nothing further needs to be - * done. - * - * 6.2 If the CDID is zero (or the CM doesn't find a matching CDID in - * its database), the device is assumed to be not known. The CM - * may associate the host with device by: writing a randomly - * generated CDID to wusb_cdid and then a random CK to wusb_ck - * (this uploads the new CC to the device). - * - * CMD may choose to prompt the user before associating with a new - * device. - * - * 7. Device is unplugged. - * - * When the device tries to connect wirelessly, it will present its - * CDID to the WUSB host controller. The CM will query the - * database. If the CHID/CDID pair found, it will (with a 4-way - * handshake) challenge the device to demonstrate it has the CK secret - * key (from our database) without actually exchanging it. Once - * satisfied, crypto keys are derived from the CK, the device is - * connected and all communication is encrypted. - * - * References: - * [WUSB-AM] Association Models Supplement to the Certified Wireless - * Universal Serial Bus Specification, version 1.0. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define CBA_NAME_LEN 0x40 /* [WUSB-AM] table 4-7 */ - -/* An instance of a Cable-Based-Association-Framework device */ -struct cbaf { - struct usb_device *usb_dev; - struct usb_interface *usb_iface; - void *buffer; - size_t buffer_size; - - struct wusb_ckhdid chid; - char host_name[CBA_NAME_LEN]; - u16 host_band_groups; - - struct wusb_ckhdid cdid; - char device_name[CBA_NAME_LEN]; - u16 device_band_groups; - - struct wusb_ckhdid ck; -}; - -/* - * Verify that a CBAF USB-interface has what we need - * - * According to [WUSB-AM], CBA devices should provide at least two - * interfaces: - * - RETRIEVE_HOST_INFO - * - ASSOCIATE - * - * If the device doesn't provide these interfaces, we do not know how - * to deal with it. - */ -static int cbaf_check(struct cbaf *cbaf) -{ - int result; - struct device *dev = &cbaf->usb_iface->dev; - struct wusb_cbaf_assoc_info *assoc_info; - struct wusb_cbaf_assoc_request *assoc_request; - size_t assoc_size; - void *itr, *top; - int ar_rhi = 0, ar_assoc = 0; - - result = usb_control_msg( - cbaf->usb_dev, usb_rcvctrlpipe(cbaf->usb_dev, 0), - CBAF_REQ_GET_ASSOCIATION_INFORMATION, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber, - cbaf->buffer, cbaf->buffer_size, 1000 /* FIXME: arbitrary */); - if (result < 0) { - dev_err(dev, "Cannot get available association types: %d\n", - result); - return result; - } - - assoc_info = cbaf->buffer; - if (result < sizeof(*assoc_info)) { - dev_err(dev, "Not enough data to decode association info " - "header (%zu vs %zu bytes required)\n", - (size_t)result, sizeof(*assoc_info)); - return result; - } - - assoc_size = le16_to_cpu(assoc_info->Length); - if (result < assoc_size) { - dev_err(dev, "Not enough data to decode association info " - "(%zu vs %zu bytes required)\n", - (size_t)assoc_size, sizeof(*assoc_info)); - return result; - } - /* - * From now on, we just verify, but won't error out unless we - * don't find the AR_TYPE_WUSB_{RETRIEVE_HOST_INFO,ASSOCIATE} - * types. - */ - itr = cbaf->buffer + sizeof(*assoc_info); - top = cbaf->buffer + assoc_size; - dev_dbg(dev, "Found %u association requests (%zu bytes)\n", - assoc_info->NumAssociationRequests, assoc_size); - - while (itr < top) { - u16 ar_type, ar_subtype; - u32 ar_size; - const char *ar_name; - - assoc_request = itr; - - if (top - itr < sizeof(*assoc_request)) { - dev_err(dev, "Not enough data to decode associaton " - "request (%zu vs %zu bytes needed)\n", - top - itr, sizeof(*assoc_request)); - break; - } - - ar_type = le16_to_cpu(assoc_request->AssociationTypeId); - ar_subtype = le16_to_cpu(assoc_request->AssociationSubTypeId); - ar_size = le32_to_cpu(assoc_request->AssociationTypeInfoSize); - ar_name = "unknown"; - - switch (ar_type) { - case AR_TYPE_WUSB: - /* Verify we have what is mandated by [WUSB-AM]. */ - switch (ar_subtype) { - case AR_TYPE_WUSB_RETRIEVE_HOST_INFO: - ar_name = "RETRIEVE_HOST_INFO"; - ar_rhi = 1; - break; - case AR_TYPE_WUSB_ASSOCIATE: - /* send assoc data */ - ar_name = "ASSOCIATE"; - ar_assoc = 1; - break; - }; - break; - }; - - dev_dbg(dev, "Association request #%02u: 0x%04x/%04x " - "(%zu bytes): %s\n", - assoc_request->AssociationDataIndex, ar_type, - ar_subtype, (size_t)ar_size, ar_name); - - itr += sizeof(*assoc_request); - } - - if (!ar_rhi) { - dev_err(dev, "Missing RETRIEVE_HOST_INFO association " - "request\n"); - return -EINVAL; - } - if (!ar_assoc) { - dev_err(dev, "Missing ASSOCIATE association request\n"); - return -EINVAL; - } - - return 0; -} - -static const struct wusb_cbaf_host_info cbaf_host_info_defaults = { - .AssociationTypeId_hdr = WUSB_AR_AssociationTypeId, - .AssociationTypeId = cpu_to_le16(AR_TYPE_WUSB), - .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId, - .AssociationSubTypeId = cpu_to_le16(AR_TYPE_WUSB_RETRIEVE_HOST_INFO), - .CHID_hdr = WUSB_AR_CHID, - .LangID_hdr = WUSB_AR_LangID, - .HostFriendlyName_hdr = WUSB_AR_HostFriendlyName, -}; - -/* Send WUSB host information (CHID and name) to a CBAF device */ -static int cbaf_send_host_info(struct cbaf *cbaf) -{ - struct wusb_cbaf_host_info *hi; - size_t name_len; - size_t hi_size; - - hi = cbaf->buffer; - memset(hi, 0, sizeof(*hi)); - *hi = cbaf_host_info_defaults; - hi->CHID = cbaf->chid; - hi->LangID = 0; /* FIXME: I guess... */ - strlcpy(hi->HostFriendlyName, cbaf->host_name, CBA_NAME_LEN); - name_len = strlen(cbaf->host_name); - hi->HostFriendlyName_hdr.len = cpu_to_le16(name_len); - hi_size = sizeof(*hi) + name_len; - - return usb_control_msg(cbaf->usb_dev, usb_sndctrlpipe(cbaf->usb_dev, 0), - CBAF_REQ_SET_ASSOCIATION_RESPONSE, - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0x0101, - cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber, - hi, hi_size, 1000 /* FIXME: arbitrary */); -} - -/* - * Get device's information (CDID) associated to CHID - * - * The device will return it's information (CDID, name, bandgroups) - * associated to the CHID we have set before, or 0 CDID and default - * name and bandgroup if no CHID set or unknown. - */ -static int cbaf_cdid_get(struct cbaf *cbaf) -{ - int result; - struct device *dev = &cbaf->usb_iface->dev; - struct wusb_cbaf_device_info *di; - size_t needed; - - di = cbaf->buffer; - result = usb_control_msg( - cbaf->usb_dev, usb_rcvctrlpipe(cbaf->usb_dev, 0), - CBAF_REQ_GET_ASSOCIATION_REQUEST, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0x0200, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber, - di, cbaf->buffer_size, 1000 /* FIXME: arbitrary */); - if (result < 0) { - dev_err(dev, "Cannot request device information: %d\n", result); - return result; - } - - needed = result < sizeof(*di) ? sizeof(*di) : le32_to_cpu(di->Length); - if (result < needed) { - dev_err(dev, "Not enough data in DEVICE_INFO reply (%zu vs " - "%zu bytes needed)\n", (size_t)result, needed); - return -ENOENT; - } - - strlcpy(cbaf->device_name, di->DeviceFriendlyName, CBA_NAME_LEN); - cbaf->cdid = di->CDID; - cbaf->device_band_groups = le16_to_cpu(di->BandGroups); - - return 0; -} - -static ssize_t cbaf_wusb_chid_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct usb_interface *iface = to_usb_interface(dev); - struct cbaf *cbaf = usb_get_intfdata(iface); - char pr_chid[WUSB_CKHDID_STRSIZE]; - - ckhdid_printf(pr_chid, sizeof(pr_chid), &cbaf->chid); - return scnprintf(buf, PAGE_SIZE, "%s\n", pr_chid); -} - -static ssize_t cbaf_wusb_chid_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - ssize_t result; - struct usb_interface *iface = to_usb_interface(dev); - struct cbaf *cbaf = usb_get_intfdata(iface); - - result = sscanf(buf, - "%02hhx %02hhx %02hhx %02hhx " - "%02hhx %02hhx %02hhx %02hhx " - "%02hhx %02hhx %02hhx %02hhx " - "%02hhx %02hhx %02hhx %02hhx", - &cbaf->chid.data[0] , &cbaf->chid.data[1], - &cbaf->chid.data[2] , &cbaf->chid.data[3], - &cbaf->chid.data[4] , &cbaf->chid.data[5], - &cbaf->chid.data[6] , &cbaf->chid.data[7], - &cbaf->chid.data[8] , &cbaf->chid.data[9], - &cbaf->chid.data[10], &cbaf->chid.data[11], - &cbaf->chid.data[12], &cbaf->chid.data[13], - &cbaf->chid.data[14], &cbaf->chid.data[15]); - - if (result != 16) - return -EINVAL; - - result = cbaf_send_host_info(cbaf); - if (result < 0) - return result; - result = cbaf_cdid_get(cbaf); - if (result < 0) - return result; - return size; -} -static DEVICE_ATTR(wusb_chid, 0600, cbaf_wusb_chid_show, cbaf_wusb_chid_store); - -static ssize_t cbaf_wusb_host_name_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct usb_interface *iface = to_usb_interface(dev); - struct cbaf *cbaf = usb_get_intfdata(iface); - - return scnprintf(buf, PAGE_SIZE, "%s\n", cbaf->host_name); -} - -static ssize_t cbaf_wusb_host_name_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - ssize_t result; - struct usb_interface *iface = to_usb_interface(dev); - struct cbaf *cbaf = usb_get_intfdata(iface); - - result = sscanf(buf, "%63s", cbaf->host_name); - if (result != 1) - return -EINVAL; - - return size; -} -static DEVICE_ATTR(wusb_host_name, 0600, cbaf_wusb_host_name_show, - cbaf_wusb_host_name_store); - -static ssize_t cbaf_wusb_host_band_groups_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct usb_interface *iface = to_usb_interface(dev); - struct cbaf *cbaf = usb_get_intfdata(iface); - - return scnprintf(buf, PAGE_SIZE, "0x%04x\n", cbaf->host_band_groups); -} - -static ssize_t cbaf_wusb_host_band_groups_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - ssize_t result; - struct usb_interface *iface = to_usb_interface(dev); - struct cbaf *cbaf = usb_get_intfdata(iface); - u16 band_groups = 0; - - result = sscanf(buf, "%04hx", &band_groups); - if (result != 1) - return -EINVAL; - - cbaf->host_band_groups = band_groups; - - return size; -} - -static DEVICE_ATTR(wusb_host_band_groups, 0600, - cbaf_wusb_host_band_groups_show, - cbaf_wusb_host_band_groups_store); - -static const struct wusb_cbaf_device_info cbaf_device_info_defaults = { - .Length_hdr = WUSB_AR_Length, - .CDID_hdr = WUSB_AR_CDID, - .BandGroups_hdr = WUSB_AR_BandGroups, - .LangID_hdr = WUSB_AR_LangID, - .DeviceFriendlyName_hdr = WUSB_AR_DeviceFriendlyName, -}; - -static ssize_t cbaf_wusb_cdid_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct usb_interface *iface = to_usb_interface(dev); - struct cbaf *cbaf = usb_get_intfdata(iface); - char pr_cdid[WUSB_CKHDID_STRSIZE]; - - ckhdid_printf(pr_cdid, sizeof(pr_cdid), &cbaf->cdid); - return scnprintf(buf, PAGE_SIZE, "%s\n", pr_cdid); -} - -static ssize_t cbaf_wusb_cdid_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - ssize_t result; - struct usb_interface *iface = to_usb_interface(dev); - struct cbaf *cbaf = usb_get_intfdata(iface); - struct wusb_ckhdid cdid; - - result = sscanf(buf, - "%02hhx %02hhx %02hhx %02hhx " - "%02hhx %02hhx %02hhx %02hhx " - "%02hhx %02hhx %02hhx %02hhx " - "%02hhx %02hhx %02hhx %02hhx", - &cdid.data[0] , &cdid.data[1], - &cdid.data[2] , &cdid.data[3], - &cdid.data[4] , &cdid.data[5], - &cdid.data[6] , &cdid.data[7], - &cdid.data[8] , &cdid.data[9], - &cdid.data[10], &cdid.data[11], - &cdid.data[12], &cdid.data[13], - &cdid.data[14], &cdid.data[15]); - if (result != 16) - return -EINVAL; - - cbaf->cdid = cdid; - - return size; -} -static DEVICE_ATTR(wusb_cdid, 0600, cbaf_wusb_cdid_show, cbaf_wusb_cdid_store); - -static ssize_t cbaf_wusb_device_band_groups_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct usb_interface *iface = to_usb_interface(dev); - struct cbaf *cbaf = usb_get_intfdata(iface); - - return scnprintf(buf, PAGE_SIZE, "0x%04x\n", cbaf->device_band_groups); -} - -static DEVICE_ATTR(wusb_device_band_groups, 0600, - cbaf_wusb_device_band_groups_show, - NULL); - -static ssize_t cbaf_wusb_device_name_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct usb_interface *iface = to_usb_interface(dev); - struct cbaf *cbaf = usb_get_intfdata(iface); - - return scnprintf(buf, PAGE_SIZE, "%s\n", cbaf->device_name); -} -static DEVICE_ATTR(wusb_device_name, 0600, cbaf_wusb_device_name_show, NULL); - -static const struct wusb_cbaf_cc_data cbaf_cc_data_defaults = { - .AssociationTypeId_hdr = WUSB_AR_AssociationTypeId, - .AssociationTypeId = cpu_to_le16(AR_TYPE_WUSB), - .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId, - .AssociationSubTypeId = cpu_to_le16(AR_TYPE_WUSB_ASSOCIATE), - .Length_hdr = WUSB_AR_Length, - .Length = cpu_to_le32(sizeof(struct wusb_cbaf_cc_data)), - .ConnectionContext_hdr = WUSB_AR_ConnectionContext, - .BandGroups_hdr = WUSB_AR_BandGroups, -}; - -static const struct wusb_cbaf_cc_data_fail cbaf_cc_data_fail_defaults = { - .AssociationTypeId_hdr = WUSB_AR_AssociationTypeId, - .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId, - .Length_hdr = WUSB_AR_Length, - .AssociationStatus_hdr = WUSB_AR_AssociationStatus, -}; - -/* - * Send a new CC to the device. - */ -static int cbaf_cc_upload(struct cbaf *cbaf) -{ - int result; - struct device *dev = &cbaf->usb_iface->dev; - struct wusb_cbaf_cc_data *ccd; - char pr_cdid[WUSB_CKHDID_STRSIZE]; - - ccd = cbaf->buffer; - *ccd = cbaf_cc_data_defaults; - ccd->CHID = cbaf->chid; - ccd->CDID = cbaf->cdid; - ccd->CK = cbaf->ck; - ccd->BandGroups = cpu_to_le16(cbaf->host_band_groups); - - dev_dbg(dev, "Trying to upload CC:\n"); - ckhdid_printf(pr_cdid, sizeof(pr_cdid), &ccd->CHID); - dev_dbg(dev, " CHID %s\n", pr_cdid); - ckhdid_printf(pr_cdid, sizeof(pr_cdid), &ccd->CDID); - dev_dbg(dev, " CDID %s\n", pr_cdid); - dev_dbg(dev, " Bandgroups 0x%04x\n", cbaf->host_band_groups); - - result = usb_control_msg( - cbaf->usb_dev, usb_sndctrlpipe(cbaf->usb_dev, 0), - CBAF_REQ_SET_ASSOCIATION_RESPONSE, - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0x0201, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber, - ccd, sizeof(*ccd), 1000 /* FIXME: arbitrary */); - - return result; -} - -static ssize_t cbaf_wusb_ck_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - ssize_t result; - struct usb_interface *iface = to_usb_interface(dev); - struct cbaf *cbaf = usb_get_intfdata(iface); - - result = sscanf(buf, - "%02hhx %02hhx %02hhx %02hhx " - "%02hhx %02hhx %02hhx %02hhx " - "%02hhx %02hhx %02hhx %02hhx " - "%02hhx %02hhx %02hhx %02hhx", - &cbaf->ck.data[0] , &cbaf->ck.data[1], - &cbaf->ck.data[2] , &cbaf->ck.data[3], - &cbaf->ck.data[4] , &cbaf->ck.data[5], - &cbaf->ck.data[6] , &cbaf->ck.data[7], - &cbaf->ck.data[8] , &cbaf->ck.data[9], - &cbaf->ck.data[10], &cbaf->ck.data[11], - &cbaf->ck.data[12], &cbaf->ck.data[13], - &cbaf->ck.data[14], &cbaf->ck.data[15]); - if (result != 16) - return -EINVAL; - - result = cbaf_cc_upload(cbaf); - if (result < 0) - return result; - - return size; -} -static DEVICE_ATTR(wusb_ck, 0600, NULL, cbaf_wusb_ck_store); - -static struct attribute *cbaf_dev_attrs[] = { - &dev_attr_wusb_host_name.attr, - &dev_attr_wusb_host_band_groups.attr, - &dev_attr_wusb_chid.attr, - &dev_attr_wusb_cdid.attr, - &dev_attr_wusb_device_name.attr, - &dev_attr_wusb_device_band_groups.attr, - &dev_attr_wusb_ck.attr, - NULL, -}; - -static struct attribute_group cbaf_dev_attr_group = { - .name = NULL, /* we want them in the same directory */ - .attrs = cbaf_dev_attrs, -}; - -static int cbaf_probe(struct usb_interface *iface, - const struct usb_device_id *id) -{ - struct cbaf *cbaf; - struct device *dev = &iface->dev; - int result = -ENOMEM; - - cbaf = kzalloc(sizeof(*cbaf), GFP_KERNEL); - if (cbaf == NULL) - goto error_kzalloc; - cbaf->buffer = kmalloc(512, GFP_KERNEL); - if (cbaf->buffer == NULL) - goto error_kmalloc_buffer; - - cbaf->buffer_size = 512; - cbaf->usb_dev = usb_get_dev(interface_to_usbdev(iface)); - cbaf->usb_iface = usb_get_intf(iface); - result = cbaf_check(cbaf); - if (result < 0) { - dev_err(dev, "This device is not WUSB-CBAF compliant" - "and is not supported yet.\n"); - goto error_check; - } - - result = sysfs_create_group(&dev->kobj, &cbaf_dev_attr_group); - if (result < 0) { - dev_err(dev, "Can't register sysfs attr group: %d\n", result); - goto error_create_group; - } - usb_set_intfdata(iface, cbaf); - return 0; - -error_create_group: -error_check: - kfree(cbaf->buffer); -error_kmalloc_buffer: - kfree(cbaf); -error_kzalloc: - return result; -} - -static void cbaf_disconnect(struct usb_interface *iface) -{ - struct cbaf *cbaf = usb_get_intfdata(iface); - struct device *dev = &iface->dev; - sysfs_remove_group(&dev->kobj, &cbaf_dev_attr_group); - usb_set_intfdata(iface, NULL); - usb_put_intf(iface); - kfree(cbaf->buffer); - /* paranoia: clean up crypto keys */ - kzfree(cbaf); -} - -static const struct usb_device_id cbaf_id_table[] = { - { USB_INTERFACE_INFO(0xef, 0x03, 0x01), }, - { }, -}; -MODULE_DEVICE_TABLE(usb, cbaf_id_table); - -static struct usb_driver cbaf_driver = { - .name = "wusb-cbaf", - .id_table = cbaf_id_table, - .probe = cbaf_probe, - .disconnect = cbaf_disconnect, -}; - -module_usb_driver(cbaf_driver); - -MODULE_AUTHOR("Inaky Perez-Gonzalez "); -MODULE_DESCRIPTION("Wireless USB Cable Based Association"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/wusbcore/crypto.c b/ANDROID_3.4.5/drivers/usb/wusbcore/crypto.c deleted file mode 100644 index 7e4bf95f..00000000 --- a/ANDROID_3.4.5/drivers/usb/wusbcore/crypto.c +++ /dev/null @@ -1,518 +0,0 @@ -/* - * Ultra Wide Band - * AES-128 CCM Encryption - * - * Copyright (C) 2007 Intel Corporation - * Inaky Perez-Gonzalez - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * - * We don't do any encryption here; we use the Linux Kernel's AES-128 - * crypto modules to construct keys and payload blocks in a way - * defined by WUSB1.0[6]. Check the erratas, as typos are are patched - * there. - * - * Thanks a zillion to John Keys for his help and clarifications over - * the designed-by-a-committee text. - * - * So the idea is that there is this basic Pseudo-Random-Function - * defined in WUSB1.0[6.5] which is the core of everything. It works - * by tweaking some blocks, AES crypting them and then xoring - * something else with them (this seems to be called CBC(AES) -- can - * you tell I know jack about crypto?). So we just funnel it into the - * Linux Crypto API. - * - * We leave a crypto test module so we can verify that vectors match, - * every now and then. - * - * Block size: 16 bytes -- AES seems to do things in 'block sizes'. I - * am learning a lot... - * - * Conveniently, some data structures that need to be - * funneled through AES are...16 bytes in size! - */ - -#include -#include -#include -#include -#include -#include -#include - -static int debug_crypto_verify = 0; - -module_param(debug_crypto_verify, int, 0); -MODULE_PARM_DESC(debug_crypto_verify, "verify the key generation algorithms"); - -static void wusb_key_dump(const void *buf, size_t len) -{ - print_hex_dump(KERN_ERR, " ", DUMP_PREFIX_OFFSET, 16, 1, - buf, len, 0); -} - -/* - * Block of data, as understood by AES-CCM - * - * The code assumes this structure is nothing but a 16 byte array - * (packed in a struct to avoid common mess ups that I usually do with - * arrays and enforcing type checking). - */ -struct aes_ccm_block { - u8 data[16]; -} __attribute__((packed)); - -/* - * Counter-mode Blocks (WUSB1.0[6.4]) - * - * According to CCM (or so it seems), for the purpose of calculating - * the MIC, the message is broken in N counter-mode blocks, B0, B1, - * ... BN. - * - * B0 contains flags, the CCM nonce and l(m). - * - * B1 contains l(a), the MAC header, the encryption offset and padding. - * - * If EO is nonzero, additional blocks are built from payload bytes - * until EO is exahusted (FIXME: padding to 16 bytes, I guess). The - * padding is not xmitted. - */ - -/* WUSB1.0[T6.4] */ -struct aes_ccm_b0 { - u8 flags; /* 0x59, per CCM spec */ - struct aes_ccm_nonce ccm_nonce; - __be16 lm; -} __attribute__((packed)); - -/* WUSB1.0[T6.5] */ -struct aes_ccm_b1 { - __be16 la; - u8 mac_header[10]; - __le16 eo; - u8 security_reserved; /* This is always zero */ - u8 padding; /* 0 */ -} __attribute__((packed)); - -/* - * Encryption Blocks (WUSB1.0[6.4.4]) - * - * CCM uses Ax blocks to generate a keystream with which the MIC and - * the message's payload are encoded. A0 always encrypts/decrypts the - * MIC. Ax (x>0) are used for the successive payload blocks. - * - * The x is the counter, and is increased for each block. - */ -struct aes_ccm_a { - u8 flags; /* 0x01, per CCM spec */ - struct aes_ccm_nonce ccm_nonce; - __be16 counter; /* Value of x */ -} __attribute__((packed)); - -static void bytewise_xor(void *_bo, const void *_bi1, const void *_bi2, - size_t size) -{ - u8 *bo = _bo; - const u8 *bi1 = _bi1, *bi2 = _bi2; - size_t itr; - for (itr = 0; itr < size; itr++) - bo[itr] = bi1[itr] ^ bi2[itr]; -} - -/* - * CC-MAC function WUSB1.0[6.5] - * - * Take a data string and produce the encrypted CBC Counter-mode MIC - * - * Note the names for most function arguments are made to (more or - * less) match those used in the pseudo-function definition given in - * WUSB1.0[6.5]. - * - * @tfm_cbc: CBC(AES) blkcipher handle (initialized) - * - * @tfm_aes: AES cipher handle (initialized) - * - * @mic: buffer for placing the computed MIC (Message Integrity - * Code). This is exactly 8 bytes, and we expect the buffer to - * be at least eight bytes in length. - * - * @key: 128 bit symmetric key - * - * @n: CCM nonce - * - * @a: ASCII string, 14 bytes long (I guess zero padded if needed; - * we use exactly 14 bytes). - * - * @b: data stream to be processed; cannot be a global or const local - * (will confuse the scatterlists) - * - * @blen: size of b... - * - * Still not very clear how this is done, but looks like this: we - * create block B0 (as WUSB1.0[6.5] says), then we AES-crypt it with - * @key. We bytewise xor B0 with B1 (1) and AES-crypt that. Then we - * take the payload and divide it in blocks (16 bytes), xor them with - * the previous crypto result (16 bytes) and crypt it, repeat the next - * block with the output of the previous one, rinse wash (I guess this - * is what AES CBC mode means...but I truly have no idea). So we use - * the CBC(AES) blkcipher, that does precisely that. The IV (Initial - * Vector) is 16 bytes and is set to zero, so - * - * See rfc3610. Linux crypto has a CBC implementation, but the - * documentation is scarce, to say the least, and the example code is - * so intricated that is difficult to understand how things work. Most - * of this is guess work -- bite me. - * - * (1) Created as 6.5 says, again, using as l(a) 'Blen + 14', and - * using the 14 bytes of @a to fill up - * b1.{mac_header,e0,security_reserved,padding}. - * - * NOTE: The definition of l(a) in WUSB1.0[6.5] vs the definition of - * l(m) is orthogonal, they bear no relationship, so it is not - * in conflict with the parameter's relation that - * WUSB1.0[6.4.2]) defines. - * - * NOTE: WUSB1.0[A.1]: Host Nonce is missing a nibble? (1e); fixed in - * first errata released on 2005/07. - * - * NOTE: we need to clean IV to zero at each invocation to make sure - * we start with a fresh empty Initial Vector, so that the CBC - * works ok. - * - * NOTE: blen is not aligned to a block size, we'll pad zeros, that's - * what sg[4] is for. Maybe there is a smarter way to do this. - */ -static int wusb_ccm_mac(struct crypto_blkcipher *tfm_cbc, - struct crypto_cipher *tfm_aes, void *mic, - const struct aes_ccm_nonce *n, - const struct aes_ccm_label *a, const void *b, - size_t blen) -{ - int result = 0; - struct blkcipher_desc desc; - struct aes_ccm_b0 b0; - struct aes_ccm_b1 b1; - struct aes_ccm_a ax; - struct scatterlist sg[4], sg_dst; - void *iv, *dst_buf; - size_t ivsize, dst_size; - const u8 bzero[16] = { 0 }; - size_t zero_padding; - - /* - * These checks should be compile time optimized out - * ensure @a fills b1's mac_header and following fields - */ - WARN_ON(sizeof(*a) != sizeof(b1) - sizeof(b1.la)); - WARN_ON(sizeof(b0) != sizeof(struct aes_ccm_block)); - WARN_ON(sizeof(b1) != sizeof(struct aes_ccm_block)); - WARN_ON(sizeof(ax) != sizeof(struct aes_ccm_block)); - - result = -ENOMEM; - zero_padding = sizeof(struct aes_ccm_block) - - blen % sizeof(struct aes_ccm_block); - zero_padding = blen % sizeof(struct aes_ccm_block); - if (zero_padding) - zero_padding = sizeof(struct aes_ccm_block) - zero_padding; - dst_size = blen + sizeof(b0) + sizeof(b1) + zero_padding; - dst_buf = kzalloc(dst_size, GFP_KERNEL); - if (dst_buf == NULL) { - printk(KERN_ERR "E: can't alloc destination buffer\n"); - goto error_dst_buf; - } - - iv = crypto_blkcipher_crt(tfm_cbc)->iv; - ivsize = crypto_blkcipher_ivsize(tfm_cbc); - memset(iv, 0, ivsize); - - /* Setup B0 */ - b0.flags = 0x59; /* Format B0 */ - b0.ccm_nonce = *n; - b0.lm = cpu_to_be16(0); /* WUSB1.0[6.5] sez l(m) is 0 */ - - /* Setup B1 - * - * The WUSB spec is anything but clear! WUSB1.0[6.5] - * says that to initialize B1 from A with 'l(a) = blen + - * 14'--after clarification, it means to use A's contents - * for MAC Header, EO, sec reserved and padding. - */ - b1.la = cpu_to_be16(blen + 14); - memcpy(&b1.mac_header, a, sizeof(*a)); - - sg_init_table(sg, ARRAY_SIZE(sg)); - sg_set_buf(&sg[0], &b0, sizeof(b0)); - sg_set_buf(&sg[1], &b1, sizeof(b1)); - sg_set_buf(&sg[2], b, blen); - /* 0 if well behaved :) */ - sg_set_buf(&sg[3], bzero, zero_padding); - sg_init_one(&sg_dst, dst_buf, dst_size); - - desc.tfm = tfm_cbc; - desc.flags = 0; - result = crypto_blkcipher_encrypt(&desc, &sg_dst, sg, dst_size); - if (result < 0) { - printk(KERN_ERR "E: can't compute CBC-MAC tag (MIC): %d\n", - result); - goto error_cbc_crypt; - } - - /* Now we crypt the MIC Tag (*iv) with Ax -- values per WUSB1.0[6.5] - * The procedure is to AES crypt the A0 block and XOR the MIC - * Tag against it; we only do the first 8 bytes and place it - * directly in the destination buffer. - * - * POS Crypto API: size is assumed to be AES's block size. - * Thanks for documenting it -- tip taken from airo.c - */ - ax.flags = 0x01; /* as per WUSB 1.0 spec */ - ax.ccm_nonce = *n; - ax.counter = 0; - crypto_cipher_encrypt_one(tfm_aes, (void *)&ax, (void *)&ax); - bytewise_xor(mic, &ax, iv, 8); - result = 8; -error_cbc_crypt: - kfree(dst_buf); -error_dst_buf: - return result; -} - -/* - * WUSB Pseudo Random Function (WUSB1.0[6.5]) - * - * @b: buffer to the source data; cannot be a global or const local - * (will confuse the scatterlists) - */ -ssize_t wusb_prf(void *out, size_t out_size, - const u8 key[16], const struct aes_ccm_nonce *_n, - const struct aes_ccm_label *a, - const void *b, size_t blen, size_t len) -{ - ssize_t result, bytes = 0, bitr; - struct aes_ccm_nonce n = *_n; - struct crypto_blkcipher *tfm_cbc; - struct crypto_cipher *tfm_aes; - u64 sfn = 0; - __le64 sfn_le; - - tfm_cbc = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(tfm_cbc)) { - result = PTR_ERR(tfm_cbc); - printk(KERN_ERR "E: can't load CBC(AES): %d\n", (int)result); - goto error_alloc_cbc; - } - result = crypto_blkcipher_setkey(tfm_cbc, key, 16); - if (result < 0) { - printk(KERN_ERR "E: can't set CBC key: %d\n", (int)result); - goto error_setkey_cbc; - } - - tfm_aes = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(tfm_aes)) { - result = PTR_ERR(tfm_aes); - printk(KERN_ERR "E: can't load AES: %d\n", (int)result); - goto error_alloc_aes; - } - result = crypto_cipher_setkey(tfm_aes, key, 16); - if (result < 0) { - printk(KERN_ERR "E: can't set AES key: %d\n", (int)result); - goto error_setkey_aes; - } - - for (bitr = 0; bitr < (len + 63) / 64; bitr++) { - sfn_le = cpu_to_le64(sfn++); - memcpy(&n.sfn, &sfn_le, sizeof(n.sfn)); /* n.sfn++... */ - result = wusb_ccm_mac(tfm_cbc, tfm_aes, out + bytes, - &n, a, b, blen); - if (result < 0) - goto error_ccm_mac; - bytes += result; - } - result = bytes; -error_ccm_mac: -error_setkey_aes: - crypto_free_cipher(tfm_aes); -error_alloc_aes: -error_setkey_cbc: - crypto_free_blkcipher(tfm_cbc); -error_alloc_cbc: - return result; -} - -/* WUSB1.0[A.2] test vectors */ -static const u8 stv_hsmic_key[16] = { - 0x4b, 0x79, 0xa3, 0xcf, 0xe5, 0x53, 0x23, 0x9d, - 0xd7, 0xc1, 0x6d, 0x1c, 0x2d, 0xab, 0x6d, 0x3f -}; - -static const struct aes_ccm_nonce stv_hsmic_n = { - .sfn = { 0 }, - .tkid = { 0x76, 0x98, 0x01, }, - .dest_addr = { .data = { 0xbe, 0x00 } }, - .src_addr = { .data = { 0x76, 0x98 } }, -}; - -/* - * Out-of-band MIC Generation verification code - * - */ -static int wusb_oob_mic_verify(void) -{ - int result; - u8 mic[8]; - /* WUSB1.0[A.2] test vectors - * - * Need to keep it in the local stack as GCC 4.1.3something - * messes up and generates noise. - */ - struct usb_handshake stv_hsmic_hs = { - .bMessageNumber = 2, - .bStatus = 00, - .tTKID = { 0x76, 0x98, 0x01 }, - .bReserved = 00, - .CDID = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, - 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, - 0x3c, 0x3d, 0x3e, 0x3f }, - .nonce = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, - 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, - 0x2c, 0x2d, 0x2e, 0x2f }, - .MIC = { 0x75, 0x6a, 0x97, 0x51, 0x0c, 0x8c, - 0x14, 0x7b } , - }; - size_t hs_size; - - result = wusb_oob_mic(mic, stv_hsmic_key, &stv_hsmic_n, &stv_hsmic_hs); - if (result < 0) - printk(KERN_ERR "E: WUSB OOB MIC test: failed: %d\n", result); - else if (memcmp(stv_hsmic_hs.MIC, mic, sizeof(mic))) { - printk(KERN_ERR "E: OOB MIC test: " - "mismatch between MIC result and WUSB1.0[A2]\n"); - hs_size = sizeof(stv_hsmic_hs) - sizeof(stv_hsmic_hs.MIC); - printk(KERN_ERR "E: Handshake2 in: (%zu bytes)\n", hs_size); - wusb_key_dump(&stv_hsmic_hs, hs_size); - printk(KERN_ERR "E: CCM Nonce in: (%zu bytes)\n", - sizeof(stv_hsmic_n)); - wusb_key_dump(&stv_hsmic_n, sizeof(stv_hsmic_n)); - printk(KERN_ERR "E: MIC out:\n"); - wusb_key_dump(mic, sizeof(mic)); - printk(KERN_ERR "E: MIC out (from WUSB1.0[A.2]):\n"); - wusb_key_dump(stv_hsmic_hs.MIC, sizeof(stv_hsmic_hs.MIC)); - result = -EINVAL; - } else - result = 0; - return result; -} - -/* - * Test vectors for Key derivation - * - * These come from WUSB1.0[6.5.1], the vectors in WUSB1.0[A.1] - * (errata corrected in 2005/07). - */ -static const u8 stv_key_a1[16] __attribute__ ((__aligned__(4))) = { - 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87, - 0x78, 0x69, 0x5a, 0x4b, 0x3c, 0x2d, 0x1e, 0x0f -}; - -static const struct aes_ccm_nonce stv_keydvt_n_a1 = { - .sfn = { 0 }, - .tkid = { 0x76, 0x98, 0x01, }, - .dest_addr = { .data = { 0xbe, 0x00 } }, - .src_addr = { .data = { 0x76, 0x98 } }, -}; - -static const struct wusb_keydvt_out stv_keydvt_out_a1 = { - .kck = { - 0x4b, 0x79, 0xa3, 0xcf, 0xe5, 0x53, 0x23, 0x9d, - 0xd7, 0xc1, 0x6d, 0x1c, 0x2d, 0xab, 0x6d, 0x3f - }, - .ptk = { - 0xc8, 0x70, 0x62, 0x82, 0xb6, 0x7c, 0xe9, 0x06, - 0x7b, 0xc5, 0x25, 0x69, 0xf2, 0x36, 0x61, 0x2d - } -}; - -/* - * Performa a test to make sure we match the vectors defined in - * WUSB1.0[A.1](Errata2006/12) - */ -static int wusb_key_derive_verify(void) -{ - int result = 0; - struct wusb_keydvt_out keydvt_out; - /* These come from WUSB1.0[A.1] + 2006/12 errata - * NOTE: can't make this const or global -- somehow it seems - * the scatterlists for crypto get confused and we get - * bad data. There is no doc on this... */ - struct wusb_keydvt_in stv_keydvt_in_a1 = { - .hnonce = { - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f - }, - .dnonce = { - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f - } - }; - - result = wusb_key_derive(&keydvt_out, stv_key_a1, &stv_keydvt_n_a1, - &stv_keydvt_in_a1); - if (result < 0) - printk(KERN_ERR "E: WUSB key derivation test: " - "derivation failed: %d\n", result); - if (memcmp(&stv_keydvt_out_a1, &keydvt_out, sizeof(keydvt_out))) { - printk(KERN_ERR "E: WUSB key derivation test: " - "mismatch between key derivation result " - "and WUSB1.0[A1] Errata 2006/12\n"); - printk(KERN_ERR "E: keydvt in: key\n"); - wusb_key_dump(stv_key_a1, sizeof(stv_key_a1)); - printk(KERN_ERR "E: keydvt in: nonce\n"); - wusb_key_dump( &stv_keydvt_n_a1, sizeof(stv_keydvt_n_a1)); - printk(KERN_ERR "E: keydvt in: hnonce & dnonce\n"); - wusb_key_dump(&stv_keydvt_in_a1, sizeof(stv_keydvt_in_a1)); - printk(KERN_ERR "E: keydvt out: KCK\n"); - wusb_key_dump(&keydvt_out.kck, sizeof(keydvt_out.kck)); - printk(KERN_ERR "E: keydvt out: PTK\n"); - wusb_key_dump(&keydvt_out.ptk, sizeof(keydvt_out.ptk)); - result = -EINVAL; - } else - result = 0; - return result; -} - -/* - * Initialize crypto system - * - * FIXME: we do nothing now, other than verifying. Later on we'll - * cache the encryption stuff, so that's why we have a separate init. - */ -int wusb_crypto_init(void) -{ - int result; - - if (debug_crypto_verify) { - result = wusb_key_derive_verify(); - if (result < 0) - return result; - return wusb_oob_mic_verify(); - } - return 0; -} - -void wusb_crypto_exit(void) -{ - /* FIXME: free cached crypto transforms */ -} diff --git a/ANDROID_3.4.5/drivers/usb/wusbcore/dev-sysfs.c b/ANDROID_3.4.5/drivers/usb/wusbcore/dev-sysfs.c deleted file mode 100644 index 10183457..00000000 --- a/ANDROID_3.4.5/drivers/usb/wusbcore/dev-sysfs.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * WUSB devices - * sysfs bindings - * - * Copyright (C) 2007 Intel Corporation - * Inaky Perez-Gonzalez - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * - * Get them out of the way... - */ - -#include -#include -#include -#include "wusbhc.h" - -static ssize_t wusb_disconnect_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - struct usb_device *usb_dev; - struct wusbhc *wusbhc; - unsigned command; - u8 port_idx; - - if (sscanf(buf, "%u", &command) != 1) - return -EINVAL; - if (command == 0) - return size; - usb_dev = to_usb_device(dev); - wusbhc = wusbhc_get_by_usb_dev(usb_dev); - if (wusbhc == NULL) - return -ENODEV; - - mutex_lock(&wusbhc->mutex); - port_idx = wusb_port_no_to_idx(usb_dev->portnum); - __wusbhc_dev_disable(wusbhc, port_idx); - mutex_unlock(&wusbhc->mutex); - wusbhc_put(wusbhc); - return size; -} -static DEVICE_ATTR(wusb_disconnect, 0200, NULL, wusb_disconnect_store); - -static ssize_t wusb_cdid_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - ssize_t result; - struct wusb_dev *wusb_dev; - - wusb_dev = wusb_dev_get_by_usb_dev(to_usb_device(dev)); - if (wusb_dev == NULL) - return -ENODEV; - result = ckhdid_printf(buf, PAGE_SIZE, &wusb_dev->cdid); - strcat(buf, "\n"); - wusb_dev_put(wusb_dev); - return result + 1; -} -static DEVICE_ATTR(wusb_cdid, 0444, wusb_cdid_show, NULL); - -static ssize_t wusb_ck_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - int result; - struct usb_device *usb_dev; - struct wusbhc *wusbhc; - struct wusb_ckhdid ck; - - result = sscanf(buf, - "%02hhx %02hhx %02hhx %02hhx " - "%02hhx %02hhx %02hhx %02hhx " - "%02hhx %02hhx %02hhx %02hhx " - "%02hhx %02hhx %02hhx %02hhx\n", - &ck.data[0] , &ck.data[1], - &ck.data[2] , &ck.data[3], - &ck.data[4] , &ck.data[5], - &ck.data[6] , &ck.data[7], - &ck.data[8] , &ck.data[9], - &ck.data[10], &ck.data[11], - &ck.data[12], &ck.data[13], - &ck.data[14], &ck.data[15]); - if (result != 16) - return -EINVAL; - - usb_dev = to_usb_device(dev); - wusbhc = wusbhc_get_by_usb_dev(usb_dev); - if (wusbhc == NULL) - return -ENODEV; - result = wusb_dev_4way_handshake(wusbhc, usb_dev->wusb_dev, &ck); - memset(&ck, 0, sizeof(ck)); - wusbhc_put(wusbhc); - return result < 0 ? result : size; -} -static DEVICE_ATTR(wusb_ck, 0200, NULL, wusb_ck_store); - -static struct attribute *wusb_dev_attrs[] = { - &dev_attr_wusb_disconnect.attr, - &dev_attr_wusb_cdid.attr, - &dev_attr_wusb_ck.attr, - NULL, -}; - -static struct attribute_group wusb_dev_attr_group = { - .name = NULL, /* we want them in the same directory */ - .attrs = wusb_dev_attrs, -}; - -int wusb_dev_sysfs_add(struct wusbhc *wusbhc, struct usb_device *usb_dev, - struct wusb_dev *wusb_dev) -{ - int result = sysfs_create_group(&usb_dev->dev.kobj, - &wusb_dev_attr_group); - struct device *dev = &usb_dev->dev; - if (result < 0) - dev_err(dev, "Cannot register WUSB-dev attributes: %d\n", - result); - return result; -} - -void wusb_dev_sysfs_rm(struct wusb_dev *wusb_dev) -{ - struct usb_device *usb_dev = wusb_dev->usb_dev; - if (usb_dev) - sysfs_remove_group(&usb_dev->dev.kobj, &wusb_dev_attr_group); -} diff --git a/ANDROID_3.4.5/drivers/usb/wusbcore/devconnect.c b/ANDROID_3.4.5/drivers/usb/wusbcore/devconnect.c deleted file mode 100644 index 231009af..00000000 --- a/ANDROID_3.4.5/drivers/usb/wusbcore/devconnect.c +++ /dev/null @@ -1,1133 +0,0 @@ -/* - * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8]) - * Device Connect handling - * - * Copyright (C) 2006 Intel Corporation - * Inaky Perez-Gonzalez - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * - * FIXME: docs - * FIXME: this file needs to be broken up, it's grown too big - * - * - * WUSB1.0[7.1, 7.5.1, ] - * - * WUSB device connection is kind of messy. Some background: - * - * When a device wants to connect it scans the UWB radio channels - * looking for a WUSB Channel; a WUSB channel is defined by MMCs - * (Micro Managed Commands or something like that) [see - * Design-overview for more on this] . - * - * So, device scans the radio, finds MMCs and thus a host and checks - * when the next DNTS is. It sends a Device Notification Connect - * (DN_Connect); the host picks it up (through nep.c and notif.c, ends - * up in wusb_devconnect_ack(), which creates a wusb_dev structure in - * wusbhc->port[port_number].wusb_dev), assigns an unauth address - * to the device (this means from 0x80 to 0xfe) and sends, in the MMC - * a Connect Ack Information Element (ConnAck IE). - * - * So now the device now has a WUSB address. From now on, we use - * that to talk to it in the RPipes. - * - * ASSUMPTIONS: - * - * - We use the the as device address the port number where it is - * connected (port 0 doesn't exist). For unauth, it is 128 + that. - * - * ROADMAP: - * - * This file contains the logic for doing that--entry points: - * - * wusb_devconnect_ack() Ack a device until _acked() called. - * Called by notif.c:wusb_handle_dn_connect() - * when a DN_Connect is received. - * - * wusb_devconnect_acked() Ack done, release resources. - * - * wusb_handle_dn_alive() Called by notif.c:wusb_handle_dn() - * for processing a DN_Alive pong from a device. - * - * wusb_handle_dn_disconnect()Called by notif.c:wusb_handle_dn() to - * process a disconenct request from a - * device. - * - * __wusb_dev_disable() Called by rh.c:wusbhc_rh_clear_port_feat() when - * disabling a port. - * - * wusb_devconnect_create() Called when creating the host by - * lc.c:wusbhc_create(). - * - * wusb_devconnect_destroy() Cleanup called removing the host. Called - * by lc.c:wusbhc_destroy(). - * - * Each Wireless USB host maintains a list of DN_Connect requests - * (actually we maintain a list of pending Connect Acks, the - * wusbhc->ca_list). - * - * LIFE CYCLE OF port->wusb_dev - * - * Before the @wusbhc structure put()s the reference it owns for - * port->wusb_dev [and clean the wusb_dev pointer], it needs to - * lock @wusbhc->mutex. - */ - -#include -#include -#include -#include -#include -#include "wusbhc.h" - -static void wusbhc_devconnect_acked_work(struct work_struct *work); - -static void wusb_dev_free(struct wusb_dev *wusb_dev) -{ - if (wusb_dev) { - kfree(wusb_dev->set_gtk_req); - usb_free_urb(wusb_dev->set_gtk_urb); - kfree(wusb_dev); - } -} - -static struct wusb_dev *wusb_dev_alloc(struct wusbhc *wusbhc) -{ - struct wusb_dev *wusb_dev; - struct urb *urb; - struct usb_ctrlrequest *req; - - wusb_dev = kzalloc(sizeof(*wusb_dev), GFP_KERNEL); - if (wusb_dev == NULL) - goto err; - - wusb_dev->wusbhc = wusbhc; - - INIT_WORK(&wusb_dev->devconnect_acked_work, wusbhc_devconnect_acked_work); - - urb = usb_alloc_urb(0, GFP_KERNEL); - if (urb == NULL) - goto err; - wusb_dev->set_gtk_urb = urb; - - req = kmalloc(sizeof(*req), GFP_KERNEL); - if (req == NULL) - goto err; - wusb_dev->set_gtk_req = req; - - req->bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE; - req->bRequest = USB_REQ_SET_DESCRIPTOR; - req->wValue = cpu_to_le16(USB_DT_KEY << 8 | wusbhc->gtk_index); - req->wIndex = 0; - req->wLength = cpu_to_le16(wusbhc->gtk.descr.bLength); - - return wusb_dev; -err: - wusb_dev_free(wusb_dev); - return NULL; -} - - -/* - * Using the Connect-Ack list, fill out the @wusbhc Connect-Ack WUSB IE - * properly so that it can be added to the MMC. - * - * We just get the @wusbhc->ca_list and fill out the first four ones or - * less (per-spec WUSB1.0[7.5, before T7-38). If the ConnectAck WUSB - * IE is not allocated, we alloc it. - * - * @wusbhc->mutex must be taken - */ -static void wusbhc_fill_cack_ie(struct wusbhc *wusbhc) -{ - unsigned cnt; - struct wusb_dev *dev_itr; - struct wuie_connect_ack *cack_ie; - - cack_ie = &wusbhc->cack_ie; - cnt = 0; - list_for_each_entry(dev_itr, &wusbhc->cack_list, cack_node) { - cack_ie->blk[cnt].CDID = dev_itr->cdid; - cack_ie->blk[cnt].bDeviceAddress = dev_itr->addr; - if (++cnt >= WUIE_ELT_MAX) - break; - } - cack_ie->hdr.bLength = sizeof(cack_ie->hdr) - + cnt * sizeof(cack_ie->blk[0]); -} - -/* - * Register a new device that wants to connect - * - * A new device wants to connect, so we add it to the Connect-Ack - * list. We give it an address in the unauthorized range (bit 8 set); - * user space will have to drive authorization further on. - * - * @dev_addr: address to use for the device (which is also the port - * number). - * - * @wusbhc->mutex must be taken - */ -static struct wusb_dev *wusbhc_cack_add(struct wusbhc *wusbhc, - struct wusb_dn_connect *dnc, - const char *pr_cdid, u8 port_idx) -{ - struct device *dev = wusbhc->dev; - struct wusb_dev *wusb_dev; - int new_connection = wusb_dn_connect_new_connection(dnc); - u8 dev_addr; - int result; - - /* Is it registered already? */ - list_for_each_entry(wusb_dev, &wusbhc->cack_list, cack_node) - if (!memcmp(&wusb_dev->cdid, &dnc->CDID, - sizeof(wusb_dev->cdid))) - return wusb_dev; - /* We don't have it, create an entry, register it */ - wusb_dev = wusb_dev_alloc(wusbhc); - if (wusb_dev == NULL) - return NULL; - wusb_dev_init(wusb_dev); - wusb_dev->cdid = dnc->CDID; - wusb_dev->port_idx = port_idx; - - /* - * Devices are always available within the cluster reservation - * and since the hardware will take the intersection of the - * per-device availability and the cluster reservation, the - * per-device availability can simply be set to always - * available. - */ - bitmap_fill(wusb_dev->availability.bm, UWB_NUM_MAS); - - /* FIXME: handle reconnects instead of assuming connects are - always new. */ - if (1 && new_connection == 0) - new_connection = 1; - if (new_connection) { - dev_addr = (port_idx + 2) | WUSB_DEV_ADDR_UNAUTH; - - dev_info(dev, "Connecting new WUSB device to address %u, " - "port %u\n", dev_addr, port_idx); - - result = wusb_set_dev_addr(wusbhc, wusb_dev, dev_addr); - if (result < 0) - return NULL; - } - wusb_dev->entry_ts = jiffies; - list_add_tail(&wusb_dev->cack_node, &wusbhc->cack_list); - wusbhc->cack_count++; - wusbhc_fill_cack_ie(wusbhc); - - return wusb_dev; -} - -/* - * Remove a Connect-Ack context entry from the HCs view - * - * @wusbhc->mutex must be taken - */ -static void wusbhc_cack_rm(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) -{ - list_del_init(&wusb_dev->cack_node); - wusbhc->cack_count--; - wusbhc_fill_cack_ie(wusbhc); -} - -/* - * @wusbhc->mutex must be taken */ -static -void wusbhc_devconnect_acked(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) -{ - wusbhc_cack_rm(wusbhc, wusb_dev); - if (wusbhc->cack_count) - wusbhc_mmcie_set(wusbhc, 0, 0, &wusbhc->cack_ie.hdr); - else - wusbhc_mmcie_rm(wusbhc, &wusbhc->cack_ie.hdr); -} - -static void wusbhc_devconnect_acked_work(struct work_struct *work) -{ - struct wusb_dev *wusb_dev = container_of(work, struct wusb_dev, - devconnect_acked_work); - struct wusbhc *wusbhc = wusb_dev->wusbhc; - - mutex_lock(&wusbhc->mutex); - wusbhc_devconnect_acked(wusbhc, wusb_dev); - mutex_unlock(&wusbhc->mutex); - - wusb_dev_put(wusb_dev); -} - -/* - * Ack a device for connection - * - * FIXME: docs - * - * @pr_cdid: Printable CDID...hex Use @dnc->cdid for the real deal. - * - * So we get the connect ack IE (may have been allocated already), - * find an empty connect block, an empty virtual port, create an - * address with it (see below), make it an unauth addr [bit 7 set] and - * set the MMC. - * - * Addresses: because WUSB hosts have no downstream hubs, we can do a - * 1:1 mapping between 'port number' and device - * address. This simplifies many things, as during this - * initial connect phase the USB stack has no knoledge of - * the device and hasn't assigned an address yet--we know - * USB's choose_address() will use the same euristics we - * use here, so we can assume which address will be assigned. - * - * USB stack always assigns address 1 to the root hub, so - * to the port number we add 2 (thus virtual port #0 is - * addr #2). - * - * @wusbhc shall be referenced - */ -static -void wusbhc_devconnect_ack(struct wusbhc *wusbhc, struct wusb_dn_connect *dnc, - const char *pr_cdid) -{ - int result; - struct device *dev = wusbhc->dev; - struct wusb_dev *wusb_dev; - struct wusb_port *port; - unsigned idx, devnum; - - mutex_lock(&wusbhc->mutex); - - /* Check we are not handling it already */ - for (idx = 0; idx < wusbhc->ports_max; idx++) { - port = wusb_port_by_idx(wusbhc, idx); - if (port->wusb_dev - && memcmp(&dnc->CDID, &port->wusb_dev->cdid, sizeof(dnc->CDID)) == 0) - goto error_unlock; - } - /* Look up those fake ports we have for a free one */ - for (idx = 0; idx < wusbhc->ports_max; idx++) { - port = wusb_port_by_idx(wusbhc, idx); - if ((port->status & USB_PORT_STAT_POWER) - && !(port->status & USB_PORT_STAT_CONNECTION)) - break; - } - if (idx >= wusbhc->ports_max) { - dev_err(dev, "Host controller can't connect more devices " - "(%u already connected); device %s rejected\n", - wusbhc->ports_max, pr_cdid); - /* NOTE: we could send a WUIE_Disconnect here, but we haven't - * event acked, so the device will eventually timeout the - * connection, right? */ - goto error_unlock; - } - - devnum = idx + 2; - - /* Make sure we are using no crypto on that "virtual port" */ - wusbhc->set_ptk(wusbhc, idx, 0, NULL, 0); - - /* Grab a filled in Connect-Ack context, fill out the - * Connect-Ack Wireless USB IE, set the MMC */ - wusb_dev = wusbhc_cack_add(wusbhc, dnc, pr_cdid, idx); - if (wusb_dev == NULL) - goto error_unlock; - result = wusbhc_mmcie_set(wusbhc, 0, 0, &wusbhc->cack_ie.hdr); - if (result < 0) - goto error_unlock; - /* Give the device at least 2ms (WUSB1.0[7.5.1p3]), let's do - * three for a good measure */ - msleep(3); - port->wusb_dev = wusb_dev; - port->status |= USB_PORT_STAT_CONNECTION; - port->change |= USB_PORT_STAT_C_CONNECTION; - /* Now the port status changed to connected; khubd will - * pick the change up and try to reset the port to bring it to - * the enabled state--so this process returns up to the stack - * and it calls back into wusbhc_rh_port_reset(). - */ -error_unlock: - mutex_unlock(&wusbhc->mutex); - return; - -} - -/* - * Disconnect a Wireless USB device from its fake port - * - * Marks the port as disconnected so that khubd can pick up the change - * and drops our knowledge about the device. - * - * Assumes there is a device connected - * - * @port_index: zero based port number - * - * NOTE: @wusbhc->mutex is locked - * - * WARNING: From here it is not very safe to access anything hanging off - * wusb_dev - */ -static void __wusbhc_dev_disconnect(struct wusbhc *wusbhc, - struct wusb_port *port) -{ - struct wusb_dev *wusb_dev = port->wusb_dev; - - port->status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE - | USB_PORT_STAT_SUSPEND | USB_PORT_STAT_RESET - | USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED); - port->change |= USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE; - if (wusb_dev) { - dev_dbg(wusbhc->dev, "disconnecting device from port %d\n", wusb_dev->port_idx); - if (!list_empty(&wusb_dev->cack_node)) - list_del_init(&wusb_dev->cack_node); - /* For the one in cack_add() */ - wusb_dev_put(wusb_dev); - } - port->wusb_dev = NULL; - - /* After a device disconnects, change the GTK (see [WUSB] - * section 6.2.11.2). */ - if (wusbhc->active) - wusbhc_gtk_rekey(wusbhc); - - /* The Wireless USB part has forgotten about the device already; now - * khubd's timer will pick up the disconnection and remove the USB - * device from the system - */ -} - -/* - * Refresh the list of keep alives to emit in the MMC - * - * Some devices don't respond to keep alives unless they've been - * authenticated, so skip unauthenticated devices. - * - * We only publish the first four devices that have a coming timeout - * condition. Then when we are done processing those, we go for the - * next ones. We ignore the ones that have timed out already (they'll - * be purged). - * - * This might cause the first devices to timeout the last devices in - * the port array...FIXME: come up with a better algorithm? - * - * Note we can't do much about MMC's ops errors; we hope next refresh - * will kind of handle it. - * - * NOTE: @wusbhc->mutex is locked - */ -static void __wusbhc_keep_alive(struct wusbhc *wusbhc) -{ - struct device *dev = wusbhc->dev; - unsigned cnt; - struct wusb_dev *wusb_dev; - struct wusb_port *wusb_port; - struct wuie_keep_alive *ie = &wusbhc->keep_alive_ie; - unsigned keep_alives, old_keep_alives; - - old_keep_alives = ie->hdr.bLength - sizeof(ie->hdr); - keep_alives = 0; - for (cnt = 0; - keep_alives < WUIE_ELT_MAX && cnt < wusbhc->ports_max; - cnt++) { - unsigned tt = msecs_to_jiffies(wusbhc->trust_timeout); - - wusb_port = wusb_port_by_idx(wusbhc, cnt); - wusb_dev = wusb_port->wusb_dev; - - if (wusb_dev == NULL) - continue; - if (wusb_dev->usb_dev == NULL || !wusb_dev->usb_dev->authenticated) - continue; - - if (time_after(jiffies, wusb_dev->entry_ts + tt)) { - dev_err(dev, "KEEPALIVE: device %u timed out\n", - wusb_dev->addr); - __wusbhc_dev_disconnect(wusbhc, wusb_port); - } else if (time_after(jiffies, wusb_dev->entry_ts + tt/2)) { - /* Approaching timeout cut out, need to refresh */ - ie->bDeviceAddress[keep_alives++] = wusb_dev->addr; - } - } - if (keep_alives & 0x1) /* pad to even number ([WUSB] section 7.5.9) */ - ie->bDeviceAddress[keep_alives++] = 0x7f; - ie->hdr.bLength = sizeof(ie->hdr) + - keep_alives*sizeof(ie->bDeviceAddress[0]); - if (keep_alives > 0) - wusbhc_mmcie_set(wusbhc, 10, 5, &ie->hdr); - else if (old_keep_alives != 0) - wusbhc_mmcie_rm(wusbhc, &ie->hdr); -} - -/* - * Do a run through all devices checking for timeouts - */ -static void wusbhc_keep_alive_run(struct work_struct *ws) -{ - struct delayed_work *dw = to_delayed_work(ws); - struct wusbhc *wusbhc = container_of(dw, struct wusbhc, keep_alive_timer); - - mutex_lock(&wusbhc->mutex); - __wusbhc_keep_alive(wusbhc); - mutex_unlock(&wusbhc->mutex); - - queue_delayed_work(wusbd, &wusbhc->keep_alive_timer, - msecs_to_jiffies(wusbhc->trust_timeout / 2)); -} - -/* - * Find the wusb_dev from its device address. - * - * The device can be found directly from the address (see - * wusb_cack_add() for where the device address is set to port_idx - * +2), except when the address is zero. - */ -static struct wusb_dev *wusbhc_find_dev_by_addr(struct wusbhc *wusbhc, u8 addr) -{ - int p; - - if (addr == 0xff) /* unconnected */ - return NULL; - - if (addr > 0) { - int port = (addr & ~0x80) - 2; - if (port < 0 || port >= wusbhc->ports_max) - return NULL; - return wusb_port_by_idx(wusbhc, port)->wusb_dev; - } - - /* Look for the device with address 0. */ - for (p = 0; p < wusbhc->ports_max; p++) { - struct wusb_dev *wusb_dev = wusb_port_by_idx(wusbhc, p)->wusb_dev; - if (wusb_dev && wusb_dev->addr == addr) - return wusb_dev; - } - return NULL; -} - -/* - * Handle a DN_Alive notification (WUSB1.0[7.6.1]) - * - * This just updates the device activity timestamp and then refreshes - * the keep alive IE. - * - * @wusbhc shall be referenced and unlocked - */ -static void wusbhc_handle_dn_alive(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) -{ - mutex_lock(&wusbhc->mutex); - wusb_dev->entry_ts = jiffies; - __wusbhc_keep_alive(wusbhc); - mutex_unlock(&wusbhc->mutex); -} - -/* - * Handle a DN_Connect notification (WUSB1.0[7.6.1]) - * - * @wusbhc - * @pkt_hdr - * @size: Size of the buffer where the notification resides; if the - * notification data suggests there should be more data than - * available, an error will be signaled and the whole buffer - * consumed. - * - * @wusbhc->mutex shall be held - */ -static void wusbhc_handle_dn_connect(struct wusbhc *wusbhc, - struct wusb_dn_hdr *dn_hdr, - size_t size) -{ - struct device *dev = wusbhc->dev; - struct wusb_dn_connect *dnc; - char pr_cdid[WUSB_CKHDID_STRSIZE]; - static const char *beacon_behaviour[] = { - "reserved", - "self-beacon", - "directed-beacon", - "no-beacon" - }; - - if (size < sizeof(*dnc)) { - dev_err(dev, "DN CONNECT: short notification (%zu < %zu)\n", - size, sizeof(*dnc)); - return; - } - - dnc = container_of(dn_hdr, struct wusb_dn_connect, hdr); - ckhdid_printf(pr_cdid, sizeof(pr_cdid), &dnc->CDID); - dev_info(dev, "DN CONNECT: device %s @ %x (%s) wants to %s\n", - pr_cdid, - wusb_dn_connect_prev_dev_addr(dnc), - beacon_behaviour[wusb_dn_connect_beacon_behavior(dnc)], - wusb_dn_connect_new_connection(dnc) ? "connect" : "reconnect"); - /* ACK the connect */ - wusbhc_devconnect_ack(wusbhc, dnc, pr_cdid); -} - -/* - * Handle a DN_Disconnect notification (WUSB1.0[7.6.1]) - * - * Device is going down -- do the disconnect. - * - * @wusbhc shall be referenced and unlocked - */ -static void wusbhc_handle_dn_disconnect(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) -{ - struct device *dev = wusbhc->dev; - - dev_info(dev, "DN DISCONNECT: device 0x%02x going down\n", wusb_dev->addr); - - mutex_lock(&wusbhc->mutex); - __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, wusb_dev->port_idx)); - mutex_unlock(&wusbhc->mutex); -} - -/* - * Handle a Device Notification coming a host - * - * The Device Notification comes from a host (HWA, DWA or WHCI) - * wrapped in a set of headers. Somebody else has peeled off those - * headers for us and we just get one Device Notifications. - * - * Invalid DNs (e.g., too short) are discarded. - * - * @wusbhc shall be referenced - * - * FIXMES: - * - implement priorities as in WUSB1.0[Table 7-55]? - */ -void wusbhc_handle_dn(struct wusbhc *wusbhc, u8 srcaddr, - struct wusb_dn_hdr *dn_hdr, size_t size) -{ - struct device *dev = wusbhc->dev; - struct wusb_dev *wusb_dev; - - if (size < sizeof(struct wusb_dn_hdr)) { - dev_err(dev, "DN data shorter than DN header (%d < %d)\n", - (int)size, (int)sizeof(struct wusb_dn_hdr)); - return; - } - - wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr); - if (wusb_dev == NULL && dn_hdr->bType != WUSB_DN_CONNECT) { - dev_dbg(dev, "ignoring DN %d from unconnected device %02x\n", - dn_hdr->bType, srcaddr); - return; - } - - switch (dn_hdr->bType) { - case WUSB_DN_CONNECT: - wusbhc_handle_dn_connect(wusbhc, dn_hdr, size); - break; - case WUSB_DN_ALIVE: - wusbhc_handle_dn_alive(wusbhc, wusb_dev); - break; - case WUSB_DN_DISCONNECT: - wusbhc_handle_dn_disconnect(wusbhc, wusb_dev); - break; - case WUSB_DN_MASAVAILCHANGED: - case WUSB_DN_RWAKE: - case WUSB_DN_SLEEP: - /* FIXME: handle these DNs. */ - break; - case WUSB_DN_EPRDY: - /* The hardware handles these. */ - break; - default: - dev_warn(dev, "unknown DN %u (%d octets) from %u\n", - dn_hdr->bType, (int)size, srcaddr); - } -} -EXPORT_SYMBOL_GPL(wusbhc_handle_dn); - -/* - * Disconnect a WUSB device from a the cluster - * - * @wusbhc - * @port Fake port where the device is (wusbhc index, not USB port number). - * - * In Wireless USB, a disconnect is basically telling the device he is - * being disconnected and forgetting about him. - * - * We send the device a Device Disconnect IE (WUSB1.0[7.5.11]) for 100 - * ms and then keep going. - * - * We don't do much in case of error; we always pretend we disabled - * the port and disconnected the device. If physically the request - * didn't get there (many things can fail in the way there), the stack - * will reject the device's communication attempts. - * - * @wusbhc should be refcounted and locked - */ -void __wusbhc_dev_disable(struct wusbhc *wusbhc, u8 port_idx) -{ - int result; - struct device *dev = wusbhc->dev; - struct wusb_dev *wusb_dev; - struct wuie_disconnect *ie; - - wusb_dev = wusb_port_by_idx(wusbhc, port_idx)->wusb_dev; - if (wusb_dev == NULL) { - /* reset no device? ignore */ - dev_dbg(dev, "DISCONNECT: no device at port %u, ignoring\n", - port_idx); - return; - } - __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, port_idx)); - - ie = kzalloc(sizeof(*ie), GFP_KERNEL); - if (ie == NULL) - return; - ie->hdr.bLength = sizeof(*ie); - ie->hdr.bIEIdentifier = WUIE_ID_DEVICE_DISCONNECT; - ie->bDeviceAddress = wusb_dev->addr; - result = wusbhc_mmcie_set(wusbhc, 0, 0, &ie->hdr); - if (result < 0) - dev_err(dev, "DISCONNECT: can't set MMC: %d\n", result); - else { - /* At least 6 MMCs, assuming at least 1 MMC per zone. */ - msleep(7*4); - wusbhc_mmcie_rm(wusbhc, &ie->hdr); - } - kfree(ie); -} - -/* - * Walk over the BOS descriptor, verify and grok it - * - * @usb_dev: referenced - * @wusb_dev: referenced and unlocked - * - * The BOS descriptor is defined at WUSB1.0[7.4.1], and it defines a - * "flexible" way to wrap all kinds of descriptors inside an standard - * descriptor (wonder why they didn't use normal descriptors, - * btw). Not like they lack code. - * - * At the end we go to look for the WUSB Device Capabilities - * (WUSB1.0[7.4.1.1]) that is wrapped in a device capability descriptor - * that is part of the BOS descriptor set. That tells us what does the - * device support (dual role, beacon type, UWB PHY rates). - */ -static int wusb_dev_bos_grok(struct usb_device *usb_dev, - struct wusb_dev *wusb_dev, - struct usb_bos_descriptor *bos, size_t desc_size) -{ - ssize_t result; - struct device *dev = &usb_dev->dev; - void *itr, *top; - - /* Walk over BOS capabilities, verify them */ - itr = (void *)bos + sizeof(*bos); - top = itr + desc_size - sizeof(*bos); - while (itr < top) { - struct usb_dev_cap_header *cap_hdr = itr; - size_t cap_size; - u8 cap_type; - if (top - itr < sizeof(*cap_hdr)) { - dev_err(dev, "Device BUG? premature end of BOS header " - "data [offset 0x%02x]: only %zu bytes left\n", - (int)(itr - (void *)bos), top - itr); - result = -ENOSPC; - goto error_bad_cap; - } - cap_size = cap_hdr->bLength; - cap_type = cap_hdr->bDevCapabilityType; - if (cap_size == 0) - break; - if (cap_size > top - itr) { - dev_err(dev, "Device BUG? premature end of BOS data " - "[offset 0x%02x cap %02x %zu bytes]: " - "only %zu bytes left\n", - (int)(itr - (void *)bos), - cap_type, cap_size, top - itr); - result = -EBADF; - goto error_bad_cap; - } - switch (cap_type) { - case USB_CAP_TYPE_WIRELESS_USB: - if (cap_size != sizeof(*wusb_dev->wusb_cap_descr)) - dev_err(dev, "Device BUG? WUSB Capability " - "descriptor is %zu bytes vs %zu " - "needed\n", cap_size, - sizeof(*wusb_dev->wusb_cap_descr)); - else - wusb_dev->wusb_cap_descr = itr; - break; - default: - dev_err(dev, "BUG? Unknown BOS capability 0x%02x " - "(%zu bytes) at offset 0x%02x\n", cap_type, - cap_size, (int)(itr - (void *)bos)); - } - itr += cap_size; - } - result = 0; -error_bad_cap: - return result; -} - -/* - * Add information from the BOS descriptors to the device - * - * @usb_dev: referenced - * @wusb_dev: referenced and unlocked - * - * So what we do is we alloc a space for the BOS descriptor of 64 - * bytes; read the first four bytes which include the wTotalLength - * field (WUSB1.0[T7-26]) and if it fits in those 64 bytes, read the - * whole thing. If not we realloc to that size. - * - * Then we call the groking function, that will fill up - * wusb_dev->wusb_cap_descr, which is what we'll need later on. - */ -static int wusb_dev_bos_add(struct usb_device *usb_dev, - struct wusb_dev *wusb_dev) -{ - ssize_t result; - struct device *dev = &usb_dev->dev; - struct usb_bos_descriptor *bos; - size_t alloc_size = 32, desc_size = 4; - - bos = kmalloc(alloc_size, GFP_KERNEL); - if (bos == NULL) - return -ENOMEM; - result = usb_get_descriptor(usb_dev, USB_DT_BOS, 0, bos, desc_size); - if (result < 4) { - dev_err(dev, "Can't get BOS descriptor or too short: %zd\n", - result); - goto error_get_descriptor; - } - desc_size = le16_to_cpu(bos->wTotalLength); - if (desc_size >= alloc_size) { - kfree(bos); - alloc_size = desc_size; - bos = kmalloc(alloc_size, GFP_KERNEL); - if (bos == NULL) - return -ENOMEM; - } - result = usb_get_descriptor(usb_dev, USB_DT_BOS, 0, bos, desc_size); - if (result < 0 || result != desc_size) { - dev_err(dev, "Can't get BOS descriptor or too short (need " - "%zu bytes): %zd\n", desc_size, result); - goto error_get_descriptor; - } - if (result < sizeof(*bos) - || le16_to_cpu(bos->wTotalLength) != desc_size) { - dev_err(dev, "Can't get BOS descriptor or too short (need " - "%zu bytes): %zd\n", desc_size, result); - goto error_get_descriptor; - } - - result = wusb_dev_bos_grok(usb_dev, wusb_dev, bos, result); - if (result < 0) - goto error_bad_bos; - wusb_dev->bos = bos; - return 0; - -error_bad_bos: -error_get_descriptor: - kfree(bos); - wusb_dev->wusb_cap_descr = NULL; - return result; -} - -static void wusb_dev_bos_rm(struct wusb_dev *wusb_dev) -{ - kfree(wusb_dev->bos); - wusb_dev->wusb_cap_descr = NULL; -}; - -static struct usb_wireless_cap_descriptor wusb_cap_descr_default = { - .bLength = sizeof(wusb_cap_descr_default), - .bDescriptorType = USB_DT_DEVICE_CAPABILITY, - .bDevCapabilityType = USB_CAP_TYPE_WIRELESS_USB, - - .bmAttributes = USB_WIRELESS_BEACON_NONE, - .wPHYRates = cpu_to_le16(USB_WIRELESS_PHY_53), - .bmTFITXPowerInfo = 0, - .bmFFITXPowerInfo = 0, - .bmBandGroup = cpu_to_le16(0x0001), /* WUSB1.0[7.4.1] bottom */ - .bReserved = 0 -}; - -/* - * USB stack's device addition Notifier Callback - * - * Called from drivers/usb/core/hub.c when a new device is added; we - * use this hook to perform certain WUSB specific setup work on the - * new device. As well, it is the first time we can connect the - * wusb_dev and the usb_dev. So we note it down in wusb_dev and take a - * reference that we'll drop. - * - * First we need to determine if the device is a WUSB device (else we - * ignore it). For that we use the speed setting (USB_SPEED_WIRELESS) - * [FIXME: maybe we'd need something more definitive]. If so, we track - * it's usb_busd and from there, the WUSB HC. - * - * Because all WUSB HCs are contained in a 'struct wusbhc', voila, we - * get the wusbhc for the device. - * - * We have a reference on @usb_dev (as we are called at the end of its - * enumeration). - * - * NOTE: @usb_dev locked - */ -static void wusb_dev_add_ncb(struct usb_device *usb_dev) -{ - int result = 0; - struct wusb_dev *wusb_dev; - struct wusbhc *wusbhc; - struct device *dev = &usb_dev->dev; - u8 port_idx; - - if (usb_dev->wusb == 0 || usb_dev->devnum == 1) - return; /* skip non wusb and wusb RHs */ - - usb_set_device_state(usb_dev, USB_STATE_UNAUTHENTICATED); - - wusbhc = wusbhc_get_by_usb_dev(usb_dev); - if (wusbhc == NULL) - goto error_nodev; - mutex_lock(&wusbhc->mutex); - wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, usb_dev); - port_idx = wusb_port_no_to_idx(usb_dev->portnum); - mutex_unlock(&wusbhc->mutex); - if (wusb_dev == NULL) - goto error_nodev; - wusb_dev->usb_dev = usb_get_dev(usb_dev); - usb_dev->wusb_dev = wusb_dev_get(wusb_dev); - result = wusb_dev_sec_add(wusbhc, usb_dev, wusb_dev); - if (result < 0) { - dev_err(dev, "Cannot enable security: %d\n", result); - goto error_sec_add; - } - /* Now query the device for it's BOS and attach it to wusb_dev */ - result = wusb_dev_bos_add(usb_dev, wusb_dev); - if (result < 0) { - dev_err(dev, "Cannot get BOS descriptors: %d\n", result); - goto error_bos_add; - } - result = wusb_dev_sysfs_add(wusbhc, usb_dev, wusb_dev); - if (result < 0) - goto error_add_sysfs; -out: - wusb_dev_put(wusb_dev); - wusbhc_put(wusbhc); -error_nodev: - return; - - wusb_dev_sysfs_rm(wusb_dev); -error_add_sysfs: - wusb_dev_bos_rm(wusb_dev); -error_bos_add: - wusb_dev_sec_rm(wusb_dev); -error_sec_add: - mutex_lock(&wusbhc->mutex); - __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, port_idx)); - mutex_unlock(&wusbhc->mutex); - goto out; -} - -/* - * Undo all the steps done at connection by the notifier callback - * - * NOTE: @usb_dev locked - */ -static void wusb_dev_rm_ncb(struct usb_device *usb_dev) -{ - struct wusb_dev *wusb_dev = usb_dev->wusb_dev; - - if (usb_dev->wusb == 0 || usb_dev->devnum == 1) - return; /* skip non wusb and wusb RHs */ - - wusb_dev_sysfs_rm(wusb_dev); - wusb_dev_bos_rm(wusb_dev); - wusb_dev_sec_rm(wusb_dev); - wusb_dev->usb_dev = NULL; - usb_dev->wusb_dev = NULL; - wusb_dev_put(wusb_dev); - usb_put_dev(usb_dev); -} - -/* - * Handle notifications from the USB stack (notifier call back) - * - * This is called when the USB stack does a - * usb_{bus,device}_{add,remove}() so we can do WUSB specific - * handling. It is called with [for the case of - * USB_DEVICE_{ADD,REMOVE} with the usb_dev locked. - */ -int wusb_usb_ncb(struct notifier_block *nb, unsigned long val, - void *priv) -{ - int result = NOTIFY_OK; - - switch (val) { - case USB_DEVICE_ADD: - wusb_dev_add_ncb(priv); - break; - case USB_DEVICE_REMOVE: - wusb_dev_rm_ncb(priv); - break; - case USB_BUS_ADD: - /* ignore (for now) */ - case USB_BUS_REMOVE: - break; - default: - WARN_ON(1); - result = NOTIFY_BAD; - }; - return result; -} - -/* - * Return a referenced wusb_dev given a @wusbhc and @usb_dev - */ -struct wusb_dev *__wusb_dev_get_by_usb_dev(struct wusbhc *wusbhc, - struct usb_device *usb_dev) -{ - struct wusb_dev *wusb_dev; - u8 port_idx; - - port_idx = wusb_port_no_to_idx(usb_dev->portnum); - BUG_ON(port_idx > wusbhc->ports_max); - wusb_dev = wusb_port_by_idx(wusbhc, port_idx)->wusb_dev; - if (wusb_dev != NULL) /* ops, device is gone */ - wusb_dev_get(wusb_dev); - return wusb_dev; -} -EXPORT_SYMBOL_GPL(__wusb_dev_get_by_usb_dev); - -void wusb_dev_destroy(struct kref *_wusb_dev) -{ - struct wusb_dev *wusb_dev = container_of(_wusb_dev, struct wusb_dev, refcnt); - - list_del_init(&wusb_dev->cack_node); - wusb_dev_free(wusb_dev); -} -EXPORT_SYMBOL_GPL(wusb_dev_destroy); - -/* - * Create all the device connect handling infrastructure - * - * This is basically the device info array, Connect Acknowledgement - * (cack) lists, keep-alive timers (and delayed work thread). - */ -int wusbhc_devconnect_create(struct wusbhc *wusbhc) -{ - wusbhc->keep_alive_ie.hdr.bIEIdentifier = WUIE_ID_KEEP_ALIVE; - wusbhc->keep_alive_ie.hdr.bLength = sizeof(wusbhc->keep_alive_ie.hdr); - INIT_DELAYED_WORK(&wusbhc->keep_alive_timer, wusbhc_keep_alive_run); - - wusbhc->cack_ie.hdr.bIEIdentifier = WUIE_ID_CONNECTACK; - wusbhc->cack_ie.hdr.bLength = sizeof(wusbhc->cack_ie.hdr); - INIT_LIST_HEAD(&wusbhc->cack_list); - - return 0; -} - -/* - * Release all resources taken by the devconnect stuff - */ -void wusbhc_devconnect_destroy(struct wusbhc *wusbhc) -{ - /* no op */ -} - -/* - * wusbhc_devconnect_start - start accepting device connections - * @wusbhc: the WUSB HC - * - * Sets the Host Info IE to accept all new connections. - * - * FIXME: This also enables the keep alives but this is not necessary - * until there are connected and authenticated devices. - */ -int wusbhc_devconnect_start(struct wusbhc *wusbhc) -{ - struct device *dev = wusbhc->dev; - struct wuie_host_info *hi; - int result; - - hi = kzalloc(sizeof(*hi), GFP_KERNEL); - if (hi == NULL) - return -ENOMEM; - - hi->hdr.bLength = sizeof(*hi); - hi->hdr.bIEIdentifier = WUIE_ID_HOST_INFO; - hi->attributes = cpu_to_le16((wusbhc->rsv->stream << 3) | WUIE_HI_CAP_ALL); - hi->CHID = wusbhc->chid; - result = wusbhc_mmcie_set(wusbhc, 0, 0, &hi->hdr); - if (result < 0) { - dev_err(dev, "Cannot add Host Info MMCIE: %d\n", result); - goto error_mmcie_set; - } - wusbhc->wuie_host_info = hi; - - queue_delayed_work(wusbd, &wusbhc->keep_alive_timer, - (wusbhc->trust_timeout*CONFIG_HZ)/1000/2); - - return 0; - -error_mmcie_set: - kfree(hi); - return result; -} - -/* - * wusbhc_devconnect_stop - stop managing connected devices - * @wusbhc: the WUSB HC - * - * Disconnects any devices still connected, stops the keep alives and - * removes the Host Info IE. - */ -void wusbhc_devconnect_stop(struct wusbhc *wusbhc) -{ - int i; - - mutex_lock(&wusbhc->mutex); - for (i = 0; i < wusbhc->ports_max; i++) { - if (wusbhc->port[i].wusb_dev) - __wusbhc_dev_disconnect(wusbhc, &wusbhc->port[i]); - } - mutex_unlock(&wusbhc->mutex); - - cancel_delayed_work_sync(&wusbhc->keep_alive_timer); - wusbhc_mmcie_rm(wusbhc, &wusbhc->wuie_host_info->hdr); - kfree(wusbhc->wuie_host_info); - wusbhc->wuie_host_info = NULL; -} - -/* - * wusb_set_dev_addr - set the WUSB device address used by the host - * @wusbhc: the WUSB HC the device is connect to - * @wusb_dev: the WUSB device - * @addr: new device address - */ -int wusb_set_dev_addr(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev, u8 addr) -{ - int result; - - wusb_dev->addr = addr; - result = wusbhc->dev_info_set(wusbhc, wusb_dev); - if (result < 0) - dev_err(wusbhc->dev, "device %d: failed to set device " - "address\n", wusb_dev->port_idx); - else - dev_info(wusbhc->dev, "device %d: %s addr %u\n", - wusb_dev->port_idx, - (addr & WUSB_DEV_ADDR_UNAUTH) ? "unauth" : "auth", - wusb_dev->addr); - - return result; -} diff --git a/ANDROID_3.4.5/drivers/usb/wusbcore/mmc.c b/ANDROID_3.4.5/drivers/usb/wusbcore/mmc.c deleted file mode 100644 index b8c72583..00000000 --- a/ANDROID_3.4.5/drivers/usb/wusbcore/mmc.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8]) - * MMC (Microscheduled Management Command) handling - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * - * WUIEs and MMC IEs...well, they are almost the same at the end. MMC - * IEs are Wireless USB IEs that go into the MMC period...[what is - * that? look in Design-overview.txt]. - * - * - * This is a simple subsystem to keep track of which IEs are being - * sent by the host in the MMC period. - * - * For each WUIE we ask to send, we keep it in an array, so we can - * request its removal later, or replace the content. They are tracked - * by pointer, so be sure to use the same pointer if you want to - * remove it or update the contents. - * - * FIXME: - * - add timers that autoremove intervalled IEs? - */ -#include -#include -#include -#include "wusbhc.h" - -/* Initialize the MMCIEs handling mechanism */ -int wusbhc_mmcie_create(struct wusbhc *wusbhc) -{ - u8 mmcies = wusbhc->mmcies_max; - wusbhc->mmcie = kcalloc(mmcies, sizeof(wusbhc->mmcie[0]), GFP_KERNEL); - if (wusbhc->mmcie == NULL) - return -ENOMEM; - mutex_init(&wusbhc->mmcie_mutex); - return 0; -} - -/* Release resources used by the MMCIEs handling mechanism */ -void wusbhc_mmcie_destroy(struct wusbhc *wusbhc) -{ - kfree(wusbhc->mmcie); -} - -/* - * Add or replace an MMC Wireless USB IE. - * - * @interval: See WUSB1.0[8.5.3.1] - * @repeat_cnt: See WUSB1.0[8.5.3.1] - * @handle: See WUSB1.0[8.5.3.1] - * @wuie: Pointer to the header of the WUSB IE data to add. - * MUST BE allocated in a kmalloc buffer (no stack or - * vmalloc). - * THE CALLER ALWAYS OWNS THE POINTER (we don't free it - * on remove, we just forget about it). - * @returns: 0 if ok, < 0 errno code on error. - * - * Goes over the *whole* @wusbhc->mmcie array looking for (a) the - * first free spot and (b) if @wuie is already in the array (aka: - * transmitted in the MMCs) the spot were it is. - * - * If present, we "overwrite it" (update). - * - * - * NOTE: Need special ordering rules -- see below WUSB1.0 Table 7-38. - * The host uses the handle as the 'sort' index. We - * allocate the last one always for the WUIE_ID_HOST_INFO, and - * the rest, first come first serve in inverse order. - * - * Host software must make sure that it adds the other IEs in - * the right order... the host hardware is responsible for - * placing the WCTA IEs in the right place with the other IEs - * set by host software. - * - * NOTE: we can access wusbhc->wa_descr without locking because it is - * read only. - */ -int wusbhc_mmcie_set(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, - struct wuie_hdr *wuie) -{ - int result = -ENOBUFS; - unsigned handle, itr; - - /* Search a handle, taking into account the ordering */ - mutex_lock(&wusbhc->mmcie_mutex); - switch (wuie->bIEIdentifier) { - case WUIE_ID_HOST_INFO: - /* Always last */ - handle = wusbhc->mmcies_max - 1; - break; - case WUIE_ID_ISOCH_DISCARD: - dev_err(wusbhc->dev, "Special ordering case for WUIE ID 0x%x " - "unimplemented\n", wuie->bIEIdentifier); - result = -ENOSYS; - goto error_unlock; - default: - /* search for it or find the last empty slot */ - handle = ~0; - for (itr = 0; itr < wusbhc->mmcies_max - 1; itr++) { - if (wusbhc->mmcie[itr] == wuie) { - handle = itr; - break; - } - if (wusbhc->mmcie[itr] == NULL) - handle = itr; - } - if (handle == ~0) - goto error_unlock; - } - result = (wusbhc->mmcie_add)(wusbhc, interval, repeat_cnt, handle, - wuie); - if (result >= 0) - wusbhc->mmcie[handle] = wuie; -error_unlock: - mutex_unlock(&wusbhc->mmcie_mutex); - return result; -} -EXPORT_SYMBOL_GPL(wusbhc_mmcie_set); - -/* - * Remove an MMC IE previously added with wusbhc_mmcie_set() - * - * @wuie Pointer used to add the WUIE - */ -void wusbhc_mmcie_rm(struct wusbhc *wusbhc, struct wuie_hdr *wuie) -{ - int result; - unsigned handle, itr; - - mutex_lock(&wusbhc->mmcie_mutex); - for (itr = 0; itr < wusbhc->mmcies_max; itr++) { - if (wusbhc->mmcie[itr] == wuie) { - handle = itr; - goto found; - } - } - mutex_unlock(&wusbhc->mmcie_mutex); - return; - -found: - result = (wusbhc->mmcie_rm)(wusbhc, handle); - if (result == 0) - wusbhc->mmcie[itr] = NULL; - mutex_unlock(&wusbhc->mmcie_mutex); -} -EXPORT_SYMBOL_GPL(wusbhc_mmcie_rm); - -static int wusbhc_mmc_start(struct wusbhc *wusbhc) -{ - int ret; - - mutex_lock(&wusbhc->mutex); - ret = wusbhc->start(wusbhc); - if (ret >= 0) - wusbhc->active = 1; - mutex_unlock(&wusbhc->mutex); - - return ret; -} - -static void wusbhc_mmc_stop(struct wusbhc *wusbhc) -{ - mutex_lock(&wusbhc->mutex); - wusbhc->active = 0; - wusbhc->stop(wusbhc, WUSB_CHANNEL_STOP_DELAY_MS); - mutex_unlock(&wusbhc->mutex); -} - -/* - * wusbhc_start - start transmitting MMCs and accepting connections - * @wusbhc: the HC to start - * - * Establishes a cluster reservation, enables device connections, and - * starts MMCs with appropriate DNTS parameters. - */ -int wusbhc_start(struct wusbhc *wusbhc) -{ - int result; - struct device *dev = wusbhc->dev; - - WARN_ON(wusbhc->wuie_host_info != NULL); - - result = wusbhc_rsv_establish(wusbhc); - if (result < 0) { - dev_err(dev, "cannot establish cluster reservation: %d\n", - result); - goto error_rsv_establish; - } - - result = wusbhc_devconnect_start(wusbhc); - if (result < 0) { - dev_err(dev, "error enabling device connections: %d\n", result); - goto error_devconnect_start; - } - - result = wusbhc_sec_start(wusbhc); - if (result < 0) { - dev_err(dev, "error starting security in the HC: %d\n", result); - goto error_sec_start; - } - /* FIXME: the choice of the DNTS parameters is somewhat - * arbitrary */ - result = wusbhc->set_num_dnts(wusbhc, 0, 15); - if (result < 0) { - dev_err(dev, "Cannot set DNTS parameters: %d\n", result); - goto error_set_num_dnts; - } - result = wusbhc_mmc_start(wusbhc); - if (result < 0) { - dev_err(dev, "error starting wusbch: %d\n", result); - goto error_wusbhc_start; - } - - return 0; - -error_wusbhc_start: - wusbhc_sec_stop(wusbhc); -error_set_num_dnts: -error_sec_start: - wusbhc_devconnect_stop(wusbhc); -error_devconnect_start: - wusbhc_rsv_terminate(wusbhc); -error_rsv_establish: - return result; -} - -/* - * wusbhc_stop - stop transmitting MMCs - * @wusbhc: the HC to stop - * - * Stops the WUSB channel and removes the cluster reservation. - */ -void wusbhc_stop(struct wusbhc *wusbhc) -{ - wusbhc_mmc_stop(wusbhc); - wusbhc_sec_stop(wusbhc); - wusbhc_devconnect_stop(wusbhc); - wusbhc_rsv_terminate(wusbhc); -} - -/* - * Set/reset/update a new CHID - * - * Depending on the previous state of the MMCs, start, stop or change - * the sent MMC. This effectively switches the host controller on and - * off (radio wise). - */ -int wusbhc_chid_set(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid) -{ - int result = 0; - - if (memcmp(chid, &wusb_ckhdid_zero, sizeof(*chid)) == 0) - chid = NULL; - - mutex_lock(&wusbhc->mutex); - if (chid) { - if (wusbhc->active) { - mutex_unlock(&wusbhc->mutex); - return -EBUSY; - } - wusbhc->chid = *chid; - } - mutex_unlock(&wusbhc->mutex); - - if (chid) - result = uwb_radio_start(&wusbhc->pal); - else - uwb_radio_stop(&wusbhc->pal); - return result; -} -EXPORT_SYMBOL_GPL(wusbhc_chid_set); diff --git a/ANDROID_3.4.5/drivers/usb/wusbcore/pal.c b/ANDROID_3.4.5/drivers/usb/wusbcore/pal.c deleted file mode 100644 index d0b172c5..00000000 --- a/ANDROID_3.4.5/drivers/usb/wusbcore/pal.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Wireless USB Host Controller - * UWB Protocol Adaptation Layer (PAL) glue. - * - * Copyright (C) 2008 Cambridge Silicon Radio Ltd. - * - * 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, see . - */ -#include "wusbhc.h" - -static void wusbhc_channel_changed(struct uwb_pal *pal, int channel) -{ - struct wusbhc *wusbhc = container_of(pal, struct wusbhc, pal); - - if (channel < 0) - wusbhc_stop(wusbhc); - else - wusbhc_start(wusbhc); -} - -/** - * wusbhc_pal_register - register the WUSB HC as a UWB PAL - * @wusbhc: the WUSB HC - */ -int wusbhc_pal_register(struct wusbhc *wusbhc) -{ - uwb_pal_init(&wusbhc->pal); - - wusbhc->pal.name = "wusbhc"; - wusbhc->pal.device = wusbhc->usb_hcd.self.controller; - wusbhc->pal.rc = wusbhc->uwb_rc; - wusbhc->pal.channel_changed = wusbhc_channel_changed; - - return uwb_pal_register(&wusbhc->pal); -} - -/** - * wusbhc_pal_register - unregister the WUSB HC as a UWB PAL - * @wusbhc: the WUSB HC - */ -void wusbhc_pal_unregister(struct wusbhc *wusbhc) -{ - uwb_pal_unregister(&wusbhc->pal); -} diff --git a/ANDROID_3.4.5/drivers/usb/wusbcore/reservation.c b/ANDROID_3.4.5/drivers/usb/wusbcore/reservation.c deleted file mode 100644 index 6f4fafdc..00000000 --- a/ANDROID_3.4.5/drivers/usb/wusbcore/reservation.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * WUSB cluster reservation management - * - * Copyright (C) 2007 Cambridge Silicon Radio Ltd. - * - * 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, see . - */ -#include -#include - -#include "wusbhc.h" - -/* - * WUSB cluster reservations are multicast reservations with the - * broadcast cluster ID (BCID) as the target DevAddr. - * - * FIXME: consider adjusting the reservation depending on what devices - * are attached. - */ - -static int wusbhc_bwa_set(struct wusbhc *wusbhc, u8 stream, - const struct uwb_mas_bm *mas) -{ - if (mas == NULL) - mas = &uwb_mas_bm_zero; - return wusbhc->bwa_set(wusbhc, stream, mas); -} - -/** - * wusbhc_rsv_complete_cb - WUSB HC reservation complete callback - * @rsv: the reservation - * - * Either set or clear the HC's view of the reservation. - * - * FIXME: when a reservation is denied the HC should be stopped. - */ -static void wusbhc_rsv_complete_cb(struct uwb_rsv *rsv) -{ - struct wusbhc *wusbhc = rsv->pal_priv; - struct device *dev = wusbhc->dev; - struct uwb_mas_bm mas; - char buf[72]; - - switch (rsv->state) { - case UWB_RSV_STATE_O_ESTABLISHED: - uwb_rsv_get_usable_mas(rsv, &mas); - bitmap_scnprintf(buf, sizeof(buf), mas.bm, UWB_NUM_MAS); - dev_dbg(dev, "established reservation: %s\n", buf); - wusbhc_bwa_set(wusbhc, rsv->stream, &mas); - break; - case UWB_RSV_STATE_NONE: - dev_dbg(dev, "removed reservation\n"); - wusbhc_bwa_set(wusbhc, 0, NULL); - break; - default: - dev_dbg(dev, "unexpected reservation state: %d\n", rsv->state); - break; - } -} - - -/** - * wusbhc_rsv_establish - establish a reservation for the cluster - * @wusbhc: the WUSB HC requesting a bandwidth reservation - */ -int wusbhc_rsv_establish(struct wusbhc *wusbhc) -{ - struct uwb_rc *rc = wusbhc->uwb_rc; - struct uwb_rsv *rsv; - struct uwb_dev_addr bcid; - int ret; - - rsv = uwb_rsv_create(rc, wusbhc_rsv_complete_cb, wusbhc); - if (rsv == NULL) - return -ENOMEM; - - bcid.data[0] = wusbhc->cluster_id; - bcid.data[1] = 0; - - rsv->target.type = UWB_RSV_TARGET_DEVADDR; - rsv->target.devaddr = bcid; - rsv->type = UWB_DRP_TYPE_PRIVATE; - rsv->max_mas = 256; /* try to get as much as possible */ - rsv->min_mas = 15; /* one MAS per zone */ - rsv->max_interval = 1; /* max latency is one zone */ - rsv->is_multicast = true; - - ret = uwb_rsv_establish(rsv); - if (ret == 0) - wusbhc->rsv = rsv; - else - uwb_rsv_destroy(rsv); - return ret; -} - - -/** - * wusbhc_rsv_terminate - terminate the cluster reservation - * @wusbhc: the WUSB host whose reservation is to be terminated - */ -void wusbhc_rsv_terminate(struct wusbhc *wusbhc) -{ - if (wusbhc->rsv) { - uwb_rsv_terminate(wusbhc->rsv); - uwb_rsv_destroy(wusbhc->rsv); - wusbhc->rsv = NULL; - } -} diff --git a/ANDROID_3.4.5/drivers/usb/wusbcore/rh.c b/ANDROID_3.4.5/drivers/usb/wusbcore/rh.c deleted file mode 100644 index 59ff254d..00000000 --- a/ANDROID_3.4.5/drivers/usb/wusbcore/rh.c +++ /dev/null @@ -1,452 +0,0 @@ -/* - * Wireless USB Host Controller - * Root Hub operations - * - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * - * We fake a root hub that has fake ports (as many as simultaneous - * devices the Wireless USB Host Controller can deal with). For each - * port we keep an state in @wusbhc->port[index] identical to the one - * specified in the USB2.0[ch11] spec and some extra device - * information that complements the one in 'struct usb_device' (as - * this lacs a hcpriv pointer). - * - * Note this is common to WHCI and HWA host controllers. - * - * Through here we enable most of the state changes that the USB stack - * will use to connect or disconnect devices. We need to do some - * forced adaptation of Wireless USB device states vs. wired: - * - * USB: WUSB: - * - * Port Powered-off port slot n/a - * Powered-on port slot available - * Disconnected port slot available - * Connected port slot assigned device - * device sent DN_Connect - * device was authenticated - * Enabled device is authenticated, transitioned - * from unauth -> auth -> default address - * -> enabled - * Reset disconnect - * Disable disconnect - * - * This maps the standard USB port states with the WUSB device states - * so we can fake ports without having to modify the USB stack. - * - * FIXME: this process will change in the future - * - * - * ENTRY POINTS - * - * Our entry points into here are, as in hcd.c, the USB stack root hub - * ops defined in the usb_hcd struct: - * - * wusbhc_rh_status_data() Provide hub and port status data bitmap - * - * wusbhc_rh_control() Execution of all the major requests - * you can do to a hub (Set|Clear - * features, get descriptors, status, etc). - * - * wusbhc_rh_[suspend|resume]() That - * - * wusbhc_rh_start_port_reset() ??? unimplemented - */ -#include -#include -#include "wusbhc.h" - -/* - * Reset a fake port - * - * Using a Reset Device IE is too heavyweight as it causes the device - * to enter the UnConnected state and leave the cluster, this can mean - * that when the device reconnects it is connected to a different fake - * port. - * - * Instead, reset authenticated devices with a SetAddress(0), followed - * by a SetAddresss(AuthAddr). - * - * For unauthenticated devices just pretend to reset but do nothing. - * If the device initialization continues to fail it will eventually - * time out after TrustTimeout and enter the UnConnected state. - * - * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. - * - * Supposedly we are the only thread accesing @wusbhc->port; in any - * case, maybe we should move the mutex locking from - * wusbhc_devconnect_auth() to here. - * - * @port_idx refers to the wusbhc's port index, not the USB port number - */ -static int wusbhc_rh_port_reset(struct wusbhc *wusbhc, u8 port_idx) -{ - int result = 0; - struct wusb_port *port = wusb_port_by_idx(wusbhc, port_idx); - struct wusb_dev *wusb_dev = port->wusb_dev; - - if (wusb_dev == NULL) - return -ENOTCONN; - - port->status |= USB_PORT_STAT_RESET; - port->change |= USB_PORT_STAT_C_RESET; - - if (wusb_dev->addr & WUSB_DEV_ADDR_UNAUTH) - result = 0; - else - result = wusb_dev_update_address(wusbhc, wusb_dev); - - port->status &= ~USB_PORT_STAT_RESET; - port->status |= USB_PORT_STAT_ENABLE; - port->change |= USB_PORT_STAT_C_RESET | USB_PORT_STAT_C_ENABLE; - - return result; -} - -/* - * Return the hub change status bitmap - * - * The bits in the change status bitmap are cleared when a - * ClearPortFeature request is issued (USB2.0[11.12.3,11.12.4]. - * - * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. - * - * WARNING!! This gets called from atomic context; we cannot get the - * mutex--the only race condition we can find is some bit - * changing just after we copy it, which shouldn't be too - * big of a problem [and we can't make it an spinlock - * because other parts need to take it and sleep] . - * - * @usb_hcd is refcounted, so it won't disappear under us - * and before killing a host, the polling of the root hub - * would be stopped anyway. - */ -int wusbhc_rh_status_data(struct usb_hcd *usb_hcd, char *_buf) -{ - struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); - size_t cnt, size; - unsigned long *buf = (unsigned long *) _buf; - - /* WE DON'T LOCK, see comment */ - size = wusbhc->ports_max + 1 /* hub bit */; - size = (size + 8 - 1) / 8; /* round to bytes */ - for (cnt = 0; cnt < wusbhc->ports_max; cnt++) - if (wusb_port_by_idx(wusbhc, cnt)->change) - set_bit(cnt + 1, buf); - else - clear_bit(cnt + 1, buf); - return size; -} -EXPORT_SYMBOL_GPL(wusbhc_rh_status_data); - -/* - * Return the hub's descriptor - * - * NOTE: almost cut and paste from ehci-hub.c - * - * @wusbhc is assumed referenced and @wusbhc->mutex unlocked - */ -static int wusbhc_rh_get_hub_descr(struct wusbhc *wusbhc, u16 wValue, - u16 wIndex, - struct usb_hub_descriptor *descr, - u16 wLength) -{ - u16 temp = 1 + (wusbhc->ports_max / 8); - u8 length = 7 + 2 * temp; - - if (wLength < length) - return -ENOSPC; - descr->bDescLength = 7 + 2 * temp; - descr->bDescriptorType = 0x29; /* HUB type */ - descr->bNbrPorts = wusbhc->ports_max; - descr->wHubCharacteristics = cpu_to_le16( - 0x00 /* All ports power at once */ - | 0x00 /* not part of compound device */ - | 0x10 /* No overcurrent protection */ - | 0x00 /* 8 FS think time FIXME ?? */ - | 0x00); /* No port indicators */ - descr->bPwrOn2PwrGood = 0; - descr->bHubContrCurrent = 0; - /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ - memset(&descr->u.hs.DeviceRemovable[0], 0, temp); - memset(&descr->u.hs.DeviceRemovable[temp], 0xff, temp); - return 0; -} - -/* - * Clear a hub feature - * - * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. - * - * Nothing to do, so no locking needed ;) - */ -static int wusbhc_rh_clear_hub_feat(struct wusbhc *wusbhc, u16 feature) -{ - int result; - - switch (feature) { - case C_HUB_LOCAL_POWER: - /* FIXME: maybe plug bit 0 to the power input status, - * if any? - * see wusbhc_rh_get_hub_status() */ - case C_HUB_OVER_CURRENT: - result = 0; - break; - default: - result = -EPIPE; - } - return result; -} - -/* - * Return hub status (it is always zero...) - * - * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. - * - * Nothing to do, so no locking needed ;) - */ -static int wusbhc_rh_get_hub_status(struct wusbhc *wusbhc, u32 *buf, - u16 wLength) -{ - /* FIXME: maybe plug bit 0 to the power input status (if any)? */ - *buf = 0; - return 0; -} - -/* - * Set a port feature - * - * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. - */ -static int wusbhc_rh_set_port_feat(struct wusbhc *wusbhc, u16 feature, - u8 selector, u8 port_idx) -{ - struct device *dev = wusbhc->dev; - - if (port_idx > wusbhc->ports_max) - return -EINVAL; - - switch (feature) { - /* According to USB2.0[11.24.2.13]p2, these features - * are not required to be implemented. */ - case USB_PORT_FEAT_C_OVER_CURRENT: - case USB_PORT_FEAT_C_ENABLE: - case USB_PORT_FEAT_C_SUSPEND: - case USB_PORT_FEAT_C_CONNECTION: - case USB_PORT_FEAT_C_RESET: - return 0; - case USB_PORT_FEAT_POWER: - /* No such thing, but we fake it works */ - mutex_lock(&wusbhc->mutex); - wusb_port_by_idx(wusbhc, port_idx)->status |= USB_PORT_STAT_POWER; - mutex_unlock(&wusbhc->mutex); - return 0; - case USB_PORT_FEAT_RESET: - return wusbhc_rh_port_reset(wusbhc, port_idx); - case USB_PORT_FEAT_ENABLE: - case USB_PORT_FEAT_SUSPEND: - dev_err(dev, "(port_idx %d) set feat %d/%d UNIMPLEMENTED\n", - port_idx, feature, selector); - return -ENOSYS; - default: - dev_err(dev, "(port_idx %d) set feat %d/%d UNKNOWN\n", - port_idx, feature, selector); - return -EPIPE; - } - - return 0; -} - -/* - * Clear a port feature... - * - * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. - */ -static int wusbhc_rh_clear_port_feat(struct wusbhc *wusbhc, u16 feature, - u8 selector, u8 port_idx) -{ - int result = 0; - struct device *dev = wusbhc->dev; - - if (port_idx > wusbhc->ports_max) - return -EINVAL; - - mutex_lock(&wusbhc->mutex); - switch (feature) { - case USB_PORT_FEAT_POWER: /* fake port always on */ - /* According to USB2.0[11.24.2.7.1.4], no need to implement? */ - case USB_PORT_FEAT_C_OVER_CURRENT: - break; - case USB_PORT_FEAT_C_RESET: - wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_RESET; - break; - case USB_PORT_FEAT_C_CONNECTION: - wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_CONNECTION; - break; - case USB_PORT_FEAT_ENABLE: - __wusbhc_dev_disable(wusbhc, port_idx); - break; - case USB_PORT_FEAT_C_ENABLE: - wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_ENABLE; - break; - case USB_PORT_FEAT_SUSPEND: - case USB_PORT_FEAT_C_SUSPEND: - dev_err(dev, "(port_idx %d) Clear feat %d/%d UNIMPLEMENTED\n", - port_idx, feature, selector); - result = -ENOSYS; - break; - default: - dev_err(dev, "(port_idx %d) Clear feat %d/%d UNKNOWN\n", - port_idx, feature, selector); - result = -EPIPE; - break; - } - mutex_unlock(&wusbhc->mutex); - - return result; -} - -/* - * Return the port's status - * - * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. - */ -static int wusbhc_rh_get_port_status(struct wusbhc *wusbhc, u16 port_idx, - u32 *_buf, u16 wLength) -{ - __le16 *buf = (__le16 *)_buf; - - if (port_idx > wusbhc->ports_max) - return -EINVAL; - - mutex_lock(&wusbhc->mutex); - buf[0] = cpu_to_le16(wusb_port_by_idx(wusbhc, port_idx)->status); - buf[1] = cpu_to_le16(wusb_port_by_idx(wusbhc, port_idx)->change); - mutex_unlock(&wusbhc->mutex); - - return 0; -} - -/* - * Entry point for Root Hub operations - * - * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. - */ -int wusbhc_rh_control(struct usb_hcd *usb_hcd, u16 reqntype, u16 wValue, - u16 wIndex, char *buf, u16 wLength) -{ - int result = -ENOSYS; - struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); - - switch (reqntype) { - case GetHubDescriptor: - result = wusbhc_rh_get_hub_descr( - wusbhc, wValue, wIndex, - (struct usb_hub_descriptor *) buf, wLength); - break; - case ClearHubFeature: - result = wusbhc_rh_clear_hub_feat(wusbhc, wValue); - break; - case GetHubStatus: - result = wusbhc_rh_get_hub_status(wusbhc, (u32 *)buf, wLength); - break; - - case SetPortFeature: - result = wusbhc_rh_set_port_feat(wusbhc, wValue, wIndex >> 8, - (wIndex & 0xff) - 1); - break; - case ClearPortFeature: - result = wusbhc_rh_clear_port_feat(wusbhc, wValue, wIndex >> 8, - (wIndex & 0xff) - 1); - break; - case GetPortStatus: - result = wusbhc_rh_get_port_status(wusbhc, wIndex - 1, - (u32 *)buf, wLength); - break; - - case SetHubFeature: - default: - dev_err(wusbhc->dev, "%s (%p [%p], %x, %x, %x, %p, %x) " - "UNIMPLEMENTED\n", __func__, usb_hcd, wusbhc, reqntype, - wValue, wIndex, buf, wLength); - /* dump_stack(); */ - result = -ENOSYS; - } - return result; -} -EXPORT_SYMBOL_GPL(wusbhc_rh_control); - -int wusbhc_rh_suspend(struct usb_hcd *usb_hcd) -{ - struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); - dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__, - usb_hcd, wusbhc); - /* dump_stack(); */ - return -ENOSYS; -} -EXPORT_SYMBOL_GPL(wusbhc_rh_suspend); - -int wusbhc_rh_resume(struct usb_hcd *usb_hcd) -{ - struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); - dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__, - usb_hcd, wusbhc); - /* dump_stack(); */ - return -ENOSYS; -} -EXPORT_SYMBOL_GPL(wusbhc_rh_resume); - -int wusbhc_rh_start_port_reset(struct usb_hcd *usb_hcd, unsigned port_idx) -{ - struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); - dev_err(wusbhc->dev, "%s (%p [%p], port_idx %u) UNIMPLEMENTED\n", - __func__, usb_hcd, wusbhc, port_idx); - WARN_ON(1); - return -ENOSYS; -} -EXPORT_SYMBOL_GPL(wusbhc_rh_start_port_reset); - -static void wusb_port_init(struct wusb_port *port) -{ - port->status |= USB_PORT_STAT_HIGH_SPEED; -} - -/* - * Alloc fake port specific fields and status. - */ -int wusbhc_rh_create(struct wusbhc *wusbhc) -{ - int result = -ENOMEM; - size_t port_size, itr; - port_size = wusbhc->ports_max * sizeof(wusbhc->port[0]); - wusbhc->port = kzalloc(port_size, GFP_KERNEL); - if (wusbhc->port == NULL) - goto error_port_alloc; - for (itr = 0; itr < wusbhc->ports_max; itr++) - wusb_port_init(&wusbhc->port[itr]); - result = 0; -error_port_alloc: - return result; -} - -void wusbhc_rh_destroy(struct wusbhc *wusbhc) -{ - kfree(wusbhc->port); -} diff --git a/ANDROID_3.4.5/drivers/usb/wusbcore/security.c b/ANDROID_3.4.5/drivers/usb/wusbcore/security.c deleted file mode 100644 index fa810a83..00000000 --- a/ANDROID_3.4.5/drivers/usb/wusbcore/security.c +++ /dev/null @@ -1,577 +0,0 @@ -/* - * Wireless USB Host Controller - * Security support: encryption enablement, etc - * - * Copyright (C) 2006 Intel Corporation - * Inaky Perez-Gonzalez - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * - * FIXME: docs - */ -#include -#include -#include -#include -#include -#include "wusbhc.h" - -static void wusbhc_set_gtk_callback(struct urb *urb); -static void wusbhc_gtk_rekey_done_work(struct work_struct *work); - -int wusbhc_sec_create(struct wusbhc *wusbhc) -{ - wusbhc->gtk.descr.bLength = sizeof(wusbhc->gtk.descr) + sizeof(wusbhc->gtk.data); - wusbhc->gtk.descr.bDescriptorType = USB_DT_KEY; - wusbhc->gtk.descr.bReserved = 0; - - wusbhc->gtk_index = wusb_key_index(0, WUSB_KEY_INDEX_TYPE_GTK, - WUSB_KEY_INDEX_ORIGINATOR_HOST); - - INIT_WORK(&wusbhc->gtk_rekey_done_work, wusbhc_gtk_rekey_done_work); - - return 0; -} - - -/* Called when the HC is destroyed */ -void wusbhc_sec_destroy(struct wusbhc *wusbhc) -{ -} - - -/** - * wusbhc_next_tkid - generate a new, currently unused, TKID - * @wusbhc: the WUSB host controller - * @wusb_dev: the device whose PTK the TKID is for - * (or NULL for a TKID for a GTK) - * - * The generated TKID consist of two parts: the device's authenicated - * address (or 0 or a GTK); and an incrementing number. This ensures - * that TKIDs cannot be shared between devices and by the time the - * incrementing number wraps around the older TKIDs will no longer be - * in use (a maximum of two keys may be active at any one time). - */ -static u32 wusbhc_next_tkid(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) -{ - u32 *tkid; - u32 addr; - - if (wusb_dev == NULL) { - tkid = &wusbhc->gtk_tkid; - addr = 0; - } else { - tkid = &wusb_port_by_idx(wusbhc, wusb_dev->port_idx)->ptk_tkid; - addr = wusb_dev->addr & 0x7f; - } - - *tkid = (addr << 8) | ((*tkid + 1) & 0xff); - - return *tkid; -} - -static void wusbhc_generate_gtk(struct wusbhc *wusbhc) -{ - const size_t key_size = sizeof(wusbhc->gtk.data); - u32 tkid; - - tkid = wusbhc_next_tkid(wusbhc, NULL); - - wusbhc->gtk.descr.tTKID[0] = (tkid >> 0) & 0xff; - wusbhc->gtk.descr.tTKID[1] = (tkid >> 8) & 0xff; - wusbhc->gtk.descr.tTKID[2] = (tkid >> 16) & 0xff; - - get_random_bytes(wusbhc->gtk.descr.bKeyData, key_size); -} - -/** - * wusbhc_sec_start - start the security management process - * @wusbhc: the WUSB host controller - * - * Generate and set an initial GTK on the host controller. - * - * Called when the HC is started. - */ -int wusbhc_sec_start(struct wusbhc *wusbhc) -{ - const size_t key_size = sizeof(wusbhc->gtk.data); - int result; - - wusbhc_generate_gtk(wusbhc); - - result = wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid, - &wusbhc->gtk.descr.bKeyData, key_size); - if (result < 0) - dev_err(wusbhc->dev, "cannot set GTK for the host: %d\n", - result); - - return result; -} - -/** - * wusbhc_sec_stop - stop the security management process - * @wusbhc: the WUSB host controller - * - * Wait for any pending GTK rekeys to stop. - */ -void wusbhc_sec_stop(struct wusbhc *wusbhc) -{ - cancel_work_sync(&wusbhc->gtk_rekey_done_work); -} - - -/** @returns encryption type name */ -const char *wusb_et_name(u8 x) -{ - switch (x) { - case USB_ENC_TYPE_UNSECURE: return "unsecure"; - case USB_ENC_TYPE_WIRED: return "wired"; - case USB_ENC_TYPE_CCM_1: return "CCM-1"; - case USB_ENC_TYPE_RSA_1: return "RSA-1"; - default: return "unknown"; - } -} -EXPORT_SYMBOL_GPL(wusb_et_name); - -/* - * Set the device encryption method - * - * We tell the device which encryption method to use; we do this when - * setting up the device's security. - */ -static int wusb_dev_set_encryption(struct usb_device *usb_dev, int value) -{ - int result; - struct device *dev = &usb_dev->dev; - struct wusb_dev *wusb_dev = usb_dev->wusb_dev; - - if (value) { - value = wusb_dev->ccm1_etd.bEncryptionValue; - } else { - /* FIXME: should be wusb_dev->etd[UNSECURE].bEncryptionValue */ - value = 0; - } - /* Set device's */ - result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), - USB_REQ_SET_ENCRYPTION, - USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, - value, 0, NULL, 0, 1000 /* FIXME: arbitrary */); - if (result < 0) - dev_err(dev, "Can't set device's WUSB encryption to " - "%s (value %d): %d\n", - wusb_et_name(wusb_dev->ccm1_etd.bEncryptionType), - wusb_dev->ccm1_etd.bEncryptionValue, result); - return result; -} - -/* - * Set the GTK to be used by a device. - * - * The device must be authenticated. - */ -static int wusb_dev_set_gtk(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) -{ - struct usb_device *usb_dev = wusb_dev->usb_dev; - - return usb_control_msg( - usb_dev, usb_sndctrlpipe(usb_dev, 0), - USB_REQ_SET_DESCRIPTOR, - USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, - USB_DT_KEY << 8 | wusbhc->gtk_index, 0, - &wusbhc->gtk.descr, wusbhc->gtk.descr.bLength, - 1000); -} - - -/* FIXME: prototype for adding security */ -int wusb_dev_sec_add(struct wusbhc *wusbhc, - struct usb_device *usb_dev, struct wusb_dev *wusb_dev) -{ - int result, bytes, secd_size; - struct device *dev = &usb_dev->dev; - struct usb_security_descriptor *secd; - const struct usb_encryption_descriptor *etd, *ccm1_etd = NULL; - const void *itr, *top; - char buf[64]; - - secd = kmalloc(sizeof(*secd), GFP_KERNEL); - if (secd == NULL) { - result = -ENOMEM; - goto out; - } - - result = usb_get_descriptor(usb_dev, USB_DT_SECURITY, - 0, secd, sizeof(*secd)); - if (result < sizeof(*secd)) { - dev_err(dev, "Can't read security descriptor or " - "not enough data: %d\n", result); - goto out; - } - secd_size = le16_to_cpu(secd->wTotalLength); - secd = krealloc(secd, secd_size, GFP_KERNEL); - if (secd == NULL) { - dev_err(dev, "Can't allocate space for security descriptors\n"); - goto out; - } - result = usb_get_descriptor(usb_dev, USB_DT_SECURITY, - 0, secd, secd_size); - if (result < secd_size) { - dev_err(dev, "Can't read security descriptor or " - "not enough data: %d\n", result); - goto out; - } - bytes = 0; - itr = &secd[1]; - top = (void *)secd + result; - while (itr < top) { - etd = itr; - if (top - itr < sizeof(*etd)) { - dev_err(dev, "BUG: bad device security descriptor; " - "not enough data (%zu vs %zu bytes left)\n", - top - itr, sizeof(*etd)); - break; - } - if (etd->bLength < sizeof(*etd)) { - dev_err(dev, "BUG: bad device encryption descriptor; " - "descriptor is too short " - "(%u vs %zu needed)\n", - etd->bLength, sizeof(*etd)); - break; - } - itr += etd->bLength; - bytes += snprintf(buf + bytes, sizeof(buf) - bytes, - "%s (0x%02x/%02x) ", - wusb_et_name(etd->bEncryptionType), - etd->bEncryptionValue, etd->bAuthKeyIndex); - if (etd->bEncryptionType == USB_ENC_TYPE_CCM_1) - ccm1_etd = etd; - } - /* This code only supports CCM1 as of now. */ - /* FIXME: user has to choose which sec mode to use? - * In theory we want CCM */ - if (ccm1_etd == NULL) { - dev_err(dev, "WUSB device doesn't support CCM1 encryption, " - "can't use!\n"); - result = -EINVAL; - goto out; - } - wusb_dev->ccm1_etd = *ccm1_etd; - dev_dbg(dev, "supported encryption: %s; using %s (0x%02x/%02x)\n", - buf, wusb_et_name(ccm1_etd->bEncryptionType), - ccm1_etd->bEncryptionValue, ccm1_etd->bAuthKeyIndex); - result = 0; -out: - kfree(secd); - return result; -} - -void wusb_dev_sec_rm(struct wusb_dev *wusb_dev) -{ - /* Nothing so far */ -} - -/** - * Update the address of an unauthenticated WUSB device - * - * Once we have successfully authenticated, we take it to addr0 state - * and then to a normal address. - * - * Before the device's address (as known by it) was usb_dev->devnum | - * 0x80 (unauthenticated address). With this we update it to usb_dev->devnum. - */ -int wusb_dev_update_address(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) -{ - int result = -ENOMEM; - struct usb_device *usb_dev = wusb_dev->usb_dev; - struct device *dev = &usb_dev->dev; - u8 new_address = wusb_dev->addr & 0x7F; - - /* Set address 0 */ - result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), - USB_REQ_SET_ADDRESS, 0, - 0, 0, NULL, 0, 1000 /* FIXME: arbitrary */); - if (result < 0) { - dev_err(dev, "auth failed: can't set address 0: %d\n", - result); - goto error_addr0; - } - result = wusb_set_dev_addr(wusbhc, wusb_dev, 0); - if (result < 0) - goto error_addr0; - usb_set_device_state(usb_dev, USB_STATE_DEFAULT); - usb_ep0_reinit(usb_dev); - - /* Set new (authenticated) address. */ - result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), - USB_REQ_SET_ADDRESS, 0, - new_address, 0, NULL, 0, - 1000 /* FIXME: arbitrary */); - if (result < 0) { - dev_err(dev, "auth failed: can't set address %u: %d\n", - new_address, result); - goto error_addr; - } - result = wusb_set_dev_addr(wusbhc, wusb_dev, new_address); - if (result < 0) - goto error_addr; - usb_set_device_state(usb_dev, USB_STATE_ADDRESS); - usb_ep0_reinit(usb_dev); - usb_dev->authenticated = 1; -error_addr: -error_addr0: - return result; -} - -/* - * - * - */ -/* FIXME: split and cleanup */ -int wusb_dev_4way_handshake(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev, - struct wusb_ckhdid *ck) -{ - int result = -ENOMEM; - struct usb_device *usb_dev = wusb_dev->usb_dev; - struct device *dev = &usb_dev->dev; - u32 tkid; - __le32 tkid_le; - struct usb_handshake *hs; - struct aes_ccm_nonce ccm_n; - u8 mic[8]; - struct wusb_keydvt_in keydvt_in; - struct wusb_keydvt_out keydvt_out; - - hs = kcalloc(3, sizeof(hs[0]), GFP_KERNEL); - if (hs == NULL) { - dev_err(dev, "can't allocate handshake data\n"); - goto error_kzalloc; - } - - /* We need to turn encryption before beginning the 4way - * hshake (WUSB1.0[.3.2.2]) */ - result = wusb_dev_set_encryption(usb_dev, 1); - if (result < 0) - goto error_dev_set_encryption; - - tkid = wusbhc_next_tkid(wusbhc, wusb_dev); - tkid_le = cpu_to_le32(tkid); - - hs[0].bMessageNumber = 1; - hs[0].bStatus = 0; - memcpy(hs[0].tTKID, &tkid_le, sizeof(hs[0].tTKID)); - hs[0].bReserved = 0; - memcpy(hs[0].CDID, &wusb_dev->cdid, sizeof(hs[0].CDID)); - get_random_bytes(&hs[0].nonce, sizeof(hs[0].nonce)); - memset(hs[0].MIC, 0, sizeof(hs[0].MIC)); /* Per WUSB1.0[T7-22] */ - - result = usb_control_msg( - usb_dev, usb_sndctrlpipe(usb_dev, 0), - USB_REQ_SET_HANDSHAKE, - USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, - 1, 0, &hs[0], sizeof(hs[0]), 1000 /* FIXME: arbitrary */); - if (result < 0) { - dev_err(dev, "Handshake1: request failed: %d\n", result); - goto error_hs1; - } - - /* Handshake 2, from the device -- need to verify fields */ - result = usb_control_msg( - usb_dev, usb_rcvctrlpipe(usb_dev, 0), - USB_REQ_GET_HANDSHAKE, - USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE, - 2, 0, &hs[1], sizeof(hs[1]), 1000 /* FIXME: arbitrary */); - if (result < 0) { - dev_err(dev, "Handshake2: request failed: %d\n", result); - goto error_hs2; - } - - result = -EINVAL; - if (hs[1].bMessageNumber != 2) { - dev_err(dev, "Handshake2 failed: bad message number %u\n", - hs[1].bMessageNumber); - goto error_hs2; - } - if (hs[1].bStatus != 0) { - dev_err(dev, "Handshake2 failed: bad status %u\n", - hs[1].bStatus); - goto error_hs2; - } - if (memcmp(hs[0].tTKID, hs[1].tTKID, sizeof(hs[0].tTKID))) { - dev_err(dev, "Handshake2 failed: TKID mismatch " - "(#1 0x%02x%02x%02x vs #2 0x%02x%02x%02x)\n", - hs[0].tTKID[0], hs[0].tTKID[1], hs[0].tTKID[2], - hs[1].tTKID[0], hs[1].tTKID[1], hs[1].tTKID[2]); - goto error_hs2; - } - if (memcmp(hs[0].CDID, hs[1].CDID, sizeof(hs[0].CDID))) { - dev_err(dev, "Handshake2 failed: CDID mismatch\n"); - goto error_hs2; - } - - /* Setup the CCM nonce */ - memset(&ccm_n.sfn, 0, sizeof(ccm_n.sfn)); /* Per WUSB1.0[6.5.2] */ - memcpy(ccm_n.tkid, &tkid_le, sizeof(ccm_n.tkid)); - ccm_n.src_addr = wusbhc->uwb_rc->uwb_dev.dev_addr; - ccm_n.dest_addr.data[0] = wusb_dev->addr; - ccm_n.dest_addr.data[1] = 0; - - /* Derive the KCK and PTK from CK, the CCM, H and D nonces */ - memcpy(keydvt_in.hnonce, hs[0].nonce, sizeof(keydvt_in.hnonce)); - memcpy(keydvt_in.dnonce, hs[1].nonce, sizeof(keydvt_in.dnonce)); - result = wusb_key_derive(&keydvt_out, ck->data, &ccm_n, &keydvt_in); - if (result < 0) { - dev_err(dev, "Handshake2 failed: cannot derive keys: %d\n", - result); - goto error_hs2; - } - - /* Compute MIC and verify it */ - result = wusb_oob_mic(mic, keydvt_out.kck, &ccm_n, &hs[1]); - if (result < 0) { - dev_err(dev, "Handshake2 failed: cannot compute MIC: %d\n", - result); - goto error_hs2; - } - - if (memcmp(hs[1].MIC, mic, sizeof(hs[1].MIC))) { - dev_err(dev, "Handshake2 failed: MIC mismatch\n"); - goto error_hs2; - } - - /* Send Handshake3 */ - hs[2].bMessageNumber = 3; - hs[2].bStatus = 0; - memcpy(hs[2].tTKID, &tkid_le, sizeof(hs[2].tTKID)); - hs[2].bReserved = 0; - memcpy(hs[2].CDID, &wusb_dev->cdid, sizeof(hs[2].CDID)); - memcpy(hs[2].nonce, hs[0].nonce, sizeof(hs[2].nonce)); - result = wusb_oob_mic(hs[2].MIC, keydvt_out.kck, &ccm_n, &hs[2]); - if (result < 0) { - dev_err(dev, "Handshake3 failed: cannot compute MIC: %d\n", - result); - goto error_hs2; - } - - result = usb_control_msg( - usb_dev, usb_sndctrlpipe(usb_dev, 0), - USB_REQ_SET_HANDSHAKE, - USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, - 3, 0, &hs[2], sizeof(hs[2]), 1000 /* FIXME: arbitrary */); - if (result < 0) { - dev_err(dev, "Handshake3: request failed: %d\n", result); - goto error_hs3; - } - - result = wusbhc->set_ptk(wusbhc, wusb_dev->port_idx, tkid, - keydvt_out.ptk, sizeof(keydvt_out.ptk)); - if (result < 0) - goto error_wusbhc_set_ptk; - - result = wusb_dev_set_gtk(wusbhc, wusb_dev); - if (result < 0) { - dev_err(dev, "Set GTK for device: request failed: %d\n", - result); - goto error_wusbhc_set_gtk; - } - - /* Update the device's address from unauth to auth */ - if (usb_dev->authenticated == 0) { - result = wusb_dev_update_address(wusbhc, wusb_dev); - if (result < 0) - goto error_dev_update_address; - } - result = 0; - dev_info(dev, "device authenticated\n"); - -error_dev_update_address: -error_wusbhc_set_gtk: -error_wusbhc_set_ptk: -error_hs3: -error_hs2: -error_hs1: - memset(hs, 0, 3*sizeof(hs[0])); - memset(&keydvt_out, 0, sizeof(keydvt_out)); - memset(&keydvt_in, 0, sizeof(keydvt_in)); - memset(&ccm_n, 0, sizeof(ccm_n)); - memset(mic, 0, sizeof(mic)); - if (result < 0) - wusb_dev_set_encryption(usb_dev, 0); -error_dev_set_encryption: - kfree(hs); -error_kzalloc: - return result; -} - -/* - * Once all connected and authenticated devices have received the new - * GTK, switch the host to using it. - */ -static void wusbhc_gtk_rekey_done_work(struct work_struct *work) -{ - struct wusbhc *wusbhc = container_of(work, struct wusbhc, gtk_rekey_done_work); - size_t key_size = sizeof(wusbhc->gtk.data); - - mutex_lock(&wusbhc->mutex); - - if (--wusbhc->pending_set_gtks == 0) - wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid, &wusbhc->gtk.descr.bKeyData, key_size); - - mutex_unlock(&wusbhc->mutex); -} - -static void wusbhc_set_gtk_callback(struct urb *urb) -{ - struct wusbhc *wusbhc = urb->context; - - queue_work(wusbd, &wusbhc->gtk_rekey_done_work); -} - -/** - * wusbhc_gtk_rekey - generate and distribute a new GTK - * @wusbhc: the WUSB host controller - * - * Generate a new GTK and distribute it to all connected and - * authenticated devices. When all devices have the new GTK, the host - * starts using it. - * - * This must be called after every device disconnect (see [WUSB] - * section 6.2.11.2). - */ -void wusbhc_gtk_rekey(struct wusbhc *wusbhc) -{ - static const size_t key_size = sizeof(wusbhc->gtk.data); - int p; - - wusbhc_generate_gtk(wusbhc); - - for (p = 0; p < wusbhc->ports_max; p++) { - struct wusb_dev *wusb_dev; - - wusb_dev = wusbhc->port[p].wusb_dev; - if (!wusb_dev || !wusb_dev->usb_dev || !wusb_dev->usb_dev->authenticated) - continue; - - usb_fill_control_urb(wusb_dev->set_gtk_urb, wusb_dev->usb_dev, - usb_sndctrlpipe(wusb_dev->usb_dev, 0), - (void *)wusb_dev->set_gtk_req, - &wusbhc->gtk.descr, wusbhc->gtk.descr.bLength, - wusbhc_set_gtk_callback, wusbhc); - if (usb_submit_urb(wusb_dev->set_gtk_urb, GFP_KERNEL) == 0) - wusbhc->pending_set_gtks++; - } - if (wusbhc->pending_set_gtks == 0) - wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid, &wusbhc->gtk.descr.bKeyData, key_size); -} diff --git a/ANDROID_3.4.5/drivers/usb/wusbcore/wa-hc.c b/ANDROID_3.4.5/drivers/usb/wusbcore/wa-hc.c deleted file mode 100644 index 9e4a9246..00000000 --- a/ANDROID_3.4.5/drivers/usb/wusbcore/wa-hc.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Wire Adapter Host Controller Driver - * Common items to HWA and DWA based HCDs - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * - * FIXME: docs - */ -#include -#include -#include "wusbhc.h" -#include "wa-hc.h" - -/** - * Assumes - * - * wa->usb_dev and wa->usb_iface initialized and refcounted, - * wa->wa_descr initialized. - */ -int wa_create(struct wahc *wa, struct usb_interface *iface) -{ - int result; - struct device *dev = &iface->dev; - - result = wa_rpipes_create(wa); - if (result < 0) - goto error_rpipes_create; - /* Fill up Data Transfer EP pointers */ - wa->dti_epd = &iface->cur_altsetting->endpoint[1].desc; - wa->dto_epd = &iface->cur_altsetting->endpoint[2].desc; - wa->xfer_result_size = usb_endpoint_maxp(wa->dti_epd); - wa->xfer_result = kmalloc(wa->xfer_result_size, GFP_KERNEL); - if (wa->xfer_result == NULL) - goto error_xfer_result_alloc; - result = wa_nep_create(wa, iface); - if (result < 0) { - dev_err(dev, "WA-CDS: can't initialize notif endpoint: %d\n", - result); - goto error_nep_create; - } - return 0; - -error_nep_create: - kfree(wa->xfer_result); -error_xfer_result_alloc: - wa_rpipes_destroy(wa); -error_rpipes_create: - return result; -} -EXPORT_SYMBOL_GPL(wa_create); - - -void __wa_destroy(struct wahc *wa) -{ - if (wa->dti_urb) { - usb_kill_urb(wa->dti_urb); - usb_put_urb(wa->dti_urb); - usb_kill_urb(wa->buf_in_urb); - usb_put_urb(wa->buf_in_urb); - } - kfree(wa->xfer_result); - wa_nep_destroy(wa); - wa_rpipes_destroy(wa); -} -EXPORT_SYMBOL_GPL(__wa_destroy); - -/** - * wa_reset_all - reset the WA device - * @wa: the WA to be reset - * - * For HWAs the radio controller and all other PALs are also reset. - */ -void wa_reset_all(struct wahc *wa) -{ - /* FIXME: assuming HWA. */ - wusbhc_reset_all(wa->wusb); -} - -MODULE_AUTHOR("Inaky Perez-Gonzalez "); -MODULE_DESCRIPTION("Wireless USB Wire Adapter core"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/wusbcore/wa-hc.h b/ANDROID_3.4.5/drivers/usb/wusbcore/wa-hc.h deleted file mode 100644 index d6bea3e0..00000000 --- a/ANDROID_3.4.5/drivers/usb/wusbcore/wa-hc.h +++ /dev/null @@ -1,417 +0,0 @@ -/* - * HWA Host Controller Driver - * Wire Adapter Control/Data Streaming Iface (WUSB1.0[8]) - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * - * This driver implements a USB Host Controller (struct usb_hcd) for a - * Wireless USB Host Controller based on the Wireless USB 1.0 - * Host-Wire-Adapter specification (in layman terms, a USB-dongle that - * implements a Wireless USB host). - * - * Check out the Design-overview.txt file in the source documentation - * for other details on the implementation. - * - * Main blocks: - * - * driver glue with the driver API, workqueue daemon - * - * lc RC instance life cycle management (create, destroy...) - * - * hcd glue with the USB API Host Controller Interface API. - * - * nep Notification EndPoint managent: collect notifications - * and queue them with the workqueue daemon. - * - * Handle notifications as coming from the NEP. Sends them - * off others to their respective modules (eg: connect, - * disconnect and reset go to devconnect). - * - * rpipe Remote Pipe management; rpipe is what we use to write - * to an endpoint on a WUSB device that is connected to a - * HWA RC. - * - * xfer Transfer management -- this is all the code that gets a - * buffer and pushes it to a device (or viceversa). * - * - * Some day a lot of this code will be shared between this driver and - * the drivers for DWA (xfer, rpipe). - * - * All starts at driver.c:hwahc_probe(), when one of this guys is - * connected. hwahc_disconnect() stops it. - * - * During operation, the main driver is devices connecting or - * disconnecting. They cause the HWA RC to send notifications into - * nep.c:hwahc_nep_cb() that will dispatch them to - * notif.c:wa_notif_dispatch(). From there they will fan to cause - * device connects, disconnects, etc. - * - * Note much of the activity is difficult to follow. For example a - * device connect goes to devconnect, which will cause the "fake" root - * hub port to show a connect and stop there. Then khubd will notice - * and call into the rh.c:hwahc_rc_port_reset() code to authenticate - * the device (and this might require user intervention) and enable - * the port. - * - * We also have a timer workqueue going from devconnect.c that - * schedules in hwahc_devconnect_create(). - * - * The rest of the traffic is in the usual entry points of a USB HCD, - * which are hooked up in driver.c:hwahc_rc_driver, and defined in - * hcd.c. - */ - -#ifndef __HWAHC_INTERNAL_H__ -#define __HWAHC_INTERNAL_H__ - -#include -#include -#include -#include -#include -#include -#include - -struct wusbhc; -struct wahc; -extern void wa_urb_enqueue_run(struct work_struct *ws); - -/** - * RPipe instance - * - * @descr's fields are kept in LE, as we need to send it back and - * forth. - * - * @wa is referenced when set - * - * @segs_available is the number of requests segments that still can - * be submitted to the controller without overloading - * it. It is initialized to descr->wRequests when - * aiming. - * - * A rpipe supports a max of descr->wRequests at the same time; before - * submitting seg_lock has to be taken. If segs_avail > 0, then we can - * submit; if not, we have to queue them. - */ -struct wa_rpipe { - struct kref refcnt; - struct usb_rpipe_descriptor descr; - struct usb_host_endpoint *ep; - struct wahc *wa; - spinlock_t seg_lock; - struct list_head seg_list; - atomic_t segs_available; - u8 buffer[1]; /* For reads/writes on USB */ -}; - - -/** - * Instance of a HWA Host Controller - * - * Except where a more specific lock/mutex applies or atomic, all - * fields protected by @mutex. - * - * @wa_descr Can be accessed without locking because it is in - * the same area where the device descriptors were - * read, so it is guaranteed to exist umodified while - * the device exists. - * - * Endianess has been converted to CPU's. - * - * @nep_* can be accessed without locking as its processing is - * serialized; we submit a NEP URB and it comes to - * hwahc_nep_cb(), which won't issue another URB until it is - * done processing it. - * - * @xfer_list: - * - * List of active transfers to verify existence from a xfer id - * gotten from the xfer result message. Can't use urb->list because - * it goes by endpoint, and we don't know the endpoint at the time - * when we get the xfer result message. We can't really rely on the - * pointer (will have to change for 64 bits) as the xfer id is 32 bits. - * - * @xfer_delayed_list: List of transfers that need to be started - * (with a workqueue, because they were - * submitted from an atomic context). - * - * FIXME: this needs to be layered up: a wusbhc layer (for sharing - * comonalities with WHCI), a wa layer (for sharing - * comonalities with DWA-RC). - */ -struct wahc { - struct usb_device *usb_dev; - struct usb_interface *usb_iface; - - /* HC to deliver notifications */ - union { - struct wusbhc *wusb; - struct dwahc *dwa; - }; - - const struct usb_endpoint_descriptor *dto_epd, *dti_epd; - const struct usb_wa_descriptor *wa_descr; - - struct urb *nep_urb; /* Notification EndPoint [lockless] */ - struct edc nep_edc; - void *nep_buffer; - size_t nep_buffer_size; - - atomic_t notifs_queued; - - u16 rpipes; - unsigned long *rpipe_bm; /* rpipe usage bitmap */ - spinlock_t rpipe_bm_lock; /* protect rpipe_bm */ - struct mutex rpipe_mutex; /* assigning resources to endpoints */ - - struct urb *dti_urb; /* URB for reading xfer results */ - struct urb *buf_in_urb; /* URB for reading data in */ - struct edc dti_edc; /* DTI error density counter */ - struct wa_xfer_result *xfer_result; /* real size = dti_ep maxpktsize */ - size_t xfer_result_size; - - s32 status; /* For reading status */ - - struct list_head xfer_list; - struct list_head xfer_delayed_list; - spinlock_t xfer_list_lock; - struct work_struct xfer_work; - atomic_t xfer_id_count; -}; - - -extern int wa_create(struct wahc *wa, struct usb_interface *iface); -extern void __wa_destroy(struct wahc *wa); -void wa_reset_all(struct wahc *wa); - - -/* Miscellaneous constants */ -enum { - /** Max number of EPROTO errors we tolerate on the NEP in a - * period of time */ - HWAHC_EPROTO_MAX = 16, - /** Period of time for EPROTO errors (in jiffies) */ - HWAHC_EPROTO_PERIOD = 4 * HZ, -}; - - -/* Notification endpoint handling */ -extern int wa_nep_create(struct wahc *, struct usb_interface *); -extern void wa_nep_destroy(struct wahc *); - -static inline int wa_nep_arm(struct wahc *wa, gfp_t gfp_mask) -{ - struct urb *urb = wa->nep_urb; - urb->transfer_buffer = wa->nep_buffer; - urb->transfer_buffer_length = wa->nep_buffer_size; - return usb_submit_urb(urb, gfp_mask); -} - -static inline void wa_nep_disarm(struct wahc *wa) -{ - usb_kill_urb(wa->nep_urb); -} - - -/* RPipes */ -static inline void wa_rpipe_init(struct wahc *wa) -{ - spin_lock_init(&wa->rpipe_bm_lock); - mutex_init(&wa->rpipe_mutex); -} - -static inline void wa_init(struct wahc *wa) -{ - edc_init(&wa->nep_edc); - atomic_set(&wa->notifs_queued, 0); - wa_rpipe_init(wa); - edc_init(&wa->dti_edc); - INIT_LIST_HEAD(&wa->xfer_list); - INIT_LIST_HEAD(&wa->xfer_delayed_list); - spin_lock_init(&wa->xfer_list_lock); - INIT_WORK(&wa->xfer_work, wa_urb_enqueue_run); - atomic_set(&wa->xfer_id_count, 1); -} - -/** - * Destroy a pipe (when refcount drops to zero) - * - * Assumes it has been moved to the "QUIESCING" state. - */ -struct wa_xfer; -extern void rpipe_destroy(struct kref *_rpipe); -static inline -void __rpipe_get(struct wa_rpipe *rpipe) -{ - kref_get(&rpipe->refcnt); -} -extern int rpipe_get_by_ep(struct wahc *, struct usb_host_endpoint *, - struct urb *, gfp_t); -static inline void rpipe_put(struct wa_rpipe *rpipe) -{ - kref_put(&rpipe->refcnt, rpipe_destroy); - -} -extern void rpipe_ep_disable(struct wahc *, struct usb_host_endpoint *); -extern int wa_rpipes_create(struct wahc *); -extern void wa_rpipes_destroy(struct wahc *); -static inline void rpipe_avail_dec(struct wa_rpipe *rpipe) -{ - atomic_dec(&rpipe->segs_available); -} - -/** - * Returns true if the rpipe is ready to submit more segments. - */ -static inline int rpipe_avail_inc(struct wa_rpipe *rpipe) -{ - return atomic_inc_return(&rpipe->segs_available) > 0 - && !list_empty(&rpipe->seg_list); -} - - -/* Transferring data */ -extern int wa_urb_enqueue(struct wahc *, struct usb_host_endpoint *, - struct urb *, gfp_t); -extern int wa_urb_dequeue(struct wahc *, struct urb *); -extern void wa_handle_notif_xfer(struct wahc *, struct wa_notif_hdr *); - - -/* Misc - * - * FIXME: Refcounting for the actual @hwahc object is not correct; I - * mean, this should be refcounting on the HCD underneath, but - * it is not. In any case, the semantics for HCD refcounting - * are *weird*...on refcount reaching zero it just frees - * it...no RC specific function is called...unless I miss - * something. - * - * FIXME: has to go away in favour of an 'struct' hcd based sollution - */ -static inline struct wahc *wa_get(struct wahc *wa) -{ - usb_get_intf(wa->usb_iface); - return wa; -} - -static inline void wa_put(struct wahc *wa) -{ - usb_put_intf(wa->usb_iface); -} - - -static inline int __wa_feature(struct wahc *wa, unsigned op, u16 feature) -{ - return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), - op ? USB_REQ_SET_FEATURE : USB_REQ_CLEAR_FEATURE, - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - feature, - wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, - NULL, 0, 1000 /* FIXME: arbitrary */); -} - - -static inline int __wa_set_feature(struct wahc *wa, u16 feature) -{ - return __wa_feature(wa, 1, feature); -} - - -static inline int __wa_clear_feature(struct wahc *wa, u16 feature) -{ - return __wa_feature(wa, 0, feature); -} - - -/** - * Return the status of a Wire Adapter - * - * @wa: Wire Adapter instance - * @returns < 0 errno code on error, or status bitmap as described - * in WUSB1.0[8.3.1.6]. - * - * NOTE: need malloc, some arches don't take USB from the stack - */ -static inline -s32 __wa_get_status(struct wahc *wa) -{ - s32 result; - result = usb_control_msg( - wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0), - USB_REQ_GET_STATUS, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, - &wa->status, sizeof(wa->status), - 1000 /* FIXME: arbitrary */); - if (result >= 0) - result = wa->status; - return result; -} - - -/** - * Waits until the Wire Adapter's status matches @mask/@value - * - * @wa: Wire Adapter instance. - * @returns < 0 errno code on error, otherwise status. - * - * Loop until the WAs status matches the mask and value (status & mask - * == value). Timeout if it doesn't happen. - * - * FIXME: is there an official specification on how long status - * changes can take? - */ -static inline s32 __wa_wait_status(struct wahc *wa, u32 mask, u32 value) -{ - s32 result; - unsigned loops = 10; - do { - msleep(50); - result = __wa_get_status(wa); - if ((result & mask) == value) - break; - if (loops-- == 0) { - result = -ETIMEDOUT; - break; - } - } while (result >= 0); - return result; -} - - -/** Command @hwahc to stop, @returns 0 if ok, < 0 errno code on error */ -static inline int __wa_stop(struct wahc *wa) -{ - int result; - struct device *dev = &wa->usb_iface->dev; - - result = __wa_clear_feature(wa, WA_ENABLE); - if (result < 0 && result != -ENODEV) { - dev_err(dev, "error commanding HC to stop: %d\n", result); - goto out; - } - result = __wa_wait_status(wa, WA_ENABLE, 0); - if (result < 0 && result != -ENODEV) - dev_err(dev, "error waiting for HC to stop: %d\n", result); -out: - return 0; -} - - -#endif /* #ifndef __HWAHC_INTERNAL_H__ */ diff --git a/ANDROID_3.4.5/drivers/usb/wusbcore/wa-nep.c b/ANDROID_3.4.5/drivers/usb/wusbcore/wa-nep.c deleted file mode 100644 index f67f7f1e..00000000 --- a/ANDROID_3.4.5/drivers/usb/wusbcore/wa-nep.c +++ /dev/null @@ -1,305 +0,0 @@ -/* - * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8]) - * Notification EndPoint support - * - * Copyright (C) 2006 Intel Corporation - * Inaky Perez-Gonzalez - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * - * This part takes care of getting the notification from the hw - * only and dispatching through wusbwad into - * wa_notif_dispatch. Handling is done there. - * - * WA notifications are limited in size; most of them are three or - * four bytes long, and the longest is the HWA Device Notification, - * which would not exceed 38 bytes (DNs are limited in payload to 32 - * bytes plus 3 bytes header (WUSB1.0[7.6p2]), plus 3 bytes HWA - * header (WUSB1.0[8.5.4.2]). - * - * It is not clear if more than one Device Notification can be packed - * in a HWA Notification, I assume no because of the wording in - * WUSB1.0[8.5.4.2]. In any case, the bigger any notification could - * get is 256 bytes (as the bLength field is a byte). - * - * So what we do is we have this buffer and read into it; when a - * notification arrives we schedule work to a specific, single thread - * workqueue (so notifications are serialized) and copy the - * notification data. After scheduling the work, we rearm the read from - * the notification endpoint. - * - * Entry points here are: - * - * wa_nep_[create|destroy]() To initialize/release this subsystem - * - * wa_nep_cb() Callback for the notification - * endpoint; when data is ready, this - * does the dispatching. - */ -#include -#include -#include - -#include "wa-hc.h" -#include "wusbhc.h" - -/* Structure for queueing notifications to the workqueue */ -struct wa_notif_work { - struct work_struct work; - struct wahc *wa; - size_t size; - u8 data[]; -}; - -/* - * Process incoming notifications from the WA's Notification EndPoint - * [the wuswad daemon, basically] - * - * @_nw: Pointer to a descriptor which has the pointer to the - * @wa, the size of the buffer and the work queue - * structure (so we can free all when done). - * @returns 0 if ok, < 0 errno code on error. - * - * All notifications follow the same format; they need to start with a - * 'struct wa_notif_hdr' header, so it is easy to parse through - * them. We just break the buffer in individual notifications (the - * standard doesn't say if it can be done or is forbidden, so we are - * cautious) and dispatch each. - * - * So the handling layers are is: - * - * WA specific notification (from NEP) - * Device Notification Received -> wa_handle_notif_dn() - * WUSB Device notification generic handling - * BPST Adjustment -> wa_handle_notif_bpst_adj() - * ... -> ... - * - * @wa has to be referenced - */ -static void wa_notif_dispatch(struct work_struct *ws) -{ - void *itr; - u8 missing = 0; - struct wa_notif_work *nw = container_of(ws, struct wa_notif_work, work); - struct wahc *wa = nw->wa; - struct wa_notif_hdr *notif_hdr; - size_t size; - - struct device *dev = &wa->usb_iface->dev; - -#if 0 - /* FIXME: need to check for this??? */ - if (usb_hcd->state == HC_STATE_QUIESCING) /* Going down? */ - goto out; /* screw it */ -#endif - atomic_dec(&wa->notifs_queued); /* Throttling ctl */ - dev = &wa->usb_iface->dev; - size = nw->size; - itr = nw->data; - - while (size) { - if (size < sizeof(*notif_hdr)) { - missing = sizeof(*notif_hdr) - size; - goto exhausted_buffer; - } - notif_hdr = itr; - if (size < notif_hdr->bLength) - goto exhausted_buffer; - itr += notif_hdr->bLength; - size -= notif_hdr->bLength; - /* Dispatch the notification [don't use itr or size!] */ - switch (notif_hdr->bNotifyType) { - case HWA_NOTIF_DN: { - struct hwa_notif_dn *hwa_dn; - hwa_dn = container_of(notif_hdr, struct hwa_notif_dn, - hdr); - wusbhc_handle_dn(wa->wusb, hwa_dn->bSourceDeviceAddr, - hwa_dn->dndata, - notif_hdr->bLength - sizeof(*hwa_dn)); - break; - } - case WA_NOTIF_TRANSFER: - wa_handle_notif_xfer(wa, notif_hdr); - break; - case DWA_NOTIF_RWAKE: - case DWA_NOTIF_PORTSTATUS: - case HWA_NOTIF_BPST_ADJ: - /* FIXME: unimplemented WA NOTIFs */ - /* fallthru */ - default: - dev_err(dev, "HWA: unknown notification 0x%x, " - "%zu bytes; discarding\n", - notif_hdr->bNotifyType, - (size_t)notif_hdr->bLength); - break; - } - } -out: - wa_put(wa); - kfree(nw); - return; - - /* THIS SHOULD NOT HAPPEN - * - * Buffer exahusted with partial data remaining; just warn and - * discard the data, as this should not happen. - */ -exhausted_buffer: - dev_warn(dev, "HWA: device sent short notification, " - "%d bytes missing; discarding %d bytes.\n", - missing, (int)size); - goto out; -} - -/* - * Deliver incoming WA notifications to the wusbwa workqueue - * - * @wa: Pointer the Wire Adapter Controller Data Streaming - * instance (part of an 'struct usb_hcd'). - * @size: Size of the received buffer - * @returns 0 if ok, < 0 errno code on error. - * - * The input buffer is @wa->nep_buffer, with @size bytes - * (guaranteed to fit in the allocated space, - * @wa->nep_buffer_size). - */ -static int wa_nep_queue(struct wahc *wa, size_t size) -{ - int result = 0; - struct device *dev = &wa->usb_iface->dev; - struct wa_notif_work *nw; - - /* dev_fnstart(dev, "(wa %p, size %zu)\n", wa, size); */ - BUG_ON(size > wa->nep_buffer_size); - if (size == 0) - goto out; - if (atomic_read(&wa->notifs_queued) > 200) { - if (printk_ratelimit()) - dev_err(dev, "Too many notifications queued, " - "throttling back\n"); - goto out; - } - nw = kzalloc(sizeof(*nw) + size, GFP_ATOMIC); - if (nw == NULL) { - if (printk_ratelimit()) - dev_err(dev, "No memory to queue notification\n"); - goto out; - } - INIT_WORK(&nw->work, wa_notif_dispatch); - nw->wa = wa_get(wa); - nw->size = size; - memcpy(nw->data, wa->nep_buffer, size); - atomic_inc(&wa->notifs_queued); /* Throttling ctl */ - queue_work(wusbd, &nw->work); -out: - /* dev_fnend(dev, "(wa %p, size %zu) = result\n", wa, size, result); */ - return result; -} - -/* - * Callback for the notification event endpoint - * - * Check's that everything is fine and then passes the data to be - * queued to the workqueue. - */ -static void wa_nep_cb(struct urb *urb) -{ - int result; - struct wahc *wa = urb->context; - struct device *dev = &wa->usb_iface->dev; - - switch (result = urb->status) { - case 0: - result = wa_nep_queue(wa, urb->actual_length); - if (result < 0) - dev_err(dev, "NEP: unable to process notification(s): " - "%d\n", result); - break; - case -ECONNRESET: /* Not an error, but a controlled situation; */ - case -ENOENT: /* (we killed the URB)...so, no broadcast */ - case -ESHUTDOWN: - dev_dbg(dev, "NEP: going down %d\n", urb->status); - goto out; - default: /* On general errors, we retry unless it gets ugly */ - if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS, - EDC_ERROR_TIMEFRAME)) { - dev_err(dev, "NEP: URB max acceptable errors " - "exceeded, resetting device\n"); - wa_reset_all(wa); - goto out; - } - dev_err(dev, "NEP: URB error %d\n", urb->status); - } - result = wa_nep_arm(wa, GFP_ATOMIC); - if (result < 0) { - dev_err(dev, "NEP: cannot submit URB: %d\n", result); - wa_reset_all(wa); - } -out: - return; -} - -/* - * Initialize @wa's notification and event's endpoint stuff - * - * This includes the allocating the read buffer, the context ID - * allocation bitmap, the URB and submitting the URB. - */ -int wa_nep_create(struct wahc *wa, struct usb_interface *iface) -{ - int result; - struct usb_endpoint_descriptor *epd; - struct usb_device *usb_dev = interface_to_usbdev(iface); - struct device *dev = &iface->dev; - - edc_init(&wa->nep_edc); - epd = &iface->cur_altsetting->endpoint[0].desc; - wa->nep_buffer_size = 1024; - wa->nep_buffer = kmalloc(wa->nep_buffer_size, GFP_KERNEL); - if (wa->nep_buffer == NULL) { - dev_err(dev, "Unable to allocate notification's read buffer\n"); - goto error_nep_buffer; - } - wa->nep_urb = usb_alloc_urb(0, GFP_KERNEL); - if (wa->nep_urb == NULL) { - dev_err(dev, "Unable to allocate notification URB\n"); - goto error_urb_alloc; - } - usb_fill_int_urb(wa->nep_urb, usb_dev, - usb_rcvintpipe(usb_dev, epd->bEndpointAddress), - wa->nep_buffer, wa->nep_buffer_size, - wa_nep_cb, wa, epd->bInterval); - result = wa_nep_arm(wa, GFP_KERNEL); - if (result < 0) { - dev_err(dev, "Cannot submit notification URB: %d\n", result); - goto error_nep_arm; - } - return 0; - -error_nep_arm: - usb_free_urb(wa->nep_urb); -error_urb_alloc: - kfree(wa->nep_buffer); -error_nep_buffer: - return -ENOMEM; -} - -void wa_nep_destroy(struct wahc *wa) -{ - wa_nep_disarm(wa); - usb_free_urb(wa->nep_urb); - kfree(wa->nep_buffer); -} diff --git a/ANDROID_3.4.5/drivers/usb/wusbcore/wa-rpipe.c b/ANDROID_3.4.5/drivers/usb/wusbcore/wa-rpipe.c deleted file mode 100644 index f0d546c5..00000000 --- a/ANDROID_3.4.5/drivers/usb/wusbcore/wa-rpipe.c +++ /dev/null @@ -1,530 +0,0 @@ -/* - * WUSB Wire Adapter - * rpipe management - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * - * FIXME: docs - * - * RPIPE - * - * Targeted at different downstream endpoints - * - * Descriptor: use to config the remote pipe. - * - * The number of blocks could be dynamic (wBlocks in descriptor is - * 0)--need to schedule them then. - * - * Each bit in wa->rpipe_bm represents if an rpipe is being used or - * not. Rpipes are represented with a 'struct wa_rpipe' that is - * attached to the hcpriv member of a 'struct usb_host_endpoint'. - * - * When you need to xfer data to an endpoint, you get an rpipe for it - * with wa_ep_rpipe_get(), which gives you a reference to the rpipe - * and keeps a single one (the first one) with the endpoint. When you - * are done transferring, you drop that reference. At the end the - * rpipe is always allocated and bound to the endpoint. There it might - * be recycled when not used. - * - * Addresses: - * - * We use a 1:1 mapping mechanism between port address (0 based - * index, actually) and the address. The USB stack knows about this. - * - * USB Stack port number 4 (1 based) - * WUSB code port index 3 (0 based) - * USB Address 5 (2 based -- 0 is for default, 1 for root hub) - * - * Now, because we don't use the concept as default address exactly - * like the (wired) USB code does, we need to kind of skip it. So we - * never take addresses from the urb->pipe, but from the - * urb->dev->devnum, to make sure that we always have the right - * destination address. - */ -#include -#include -#include -#include -#include - -#include "wusbhc.h" -#include "wa-hc.h" - -static int __rpipe_get_descr(struct wahc *wa, - struct usb_rpipe_descriptor *descr, u16 index) -{ - ssize_t result; - struct device *dev = &wa->usb_iface->dev; - - /* Get the RPIPE descriptor -- we cannot use the usb_get_descriptor() - * function because the arguments are different. - */ - result = usb_control_msg( - wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0), - USB_REQ_GET_DESCRIPTOR, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_RPIPE, - USB_DT_RPIPE<<8, index, descr, sizeof(*descr), - 1000 /* FIXME: arbitrary */); - if (result < 0) { - dev_err(dev, "rpipe %u: get descriptor failed: %d\n", - index, (int)result); - goto error; - } - if (result < sizeof(*descr)) { - dev_err(dev, "rpipe %u: got short descriptor " - "(%zd vs %zd bytes needed)\n", - index, result, sizeof(*descr)); - result = -EINVAL; - goto error; - } - result = 0; - -error: - return result; -} - -/* - * - * The descriptor is assumed to be properly initialized (ie: you got - * it through __rpipe_get_descr()). - */ -static int __rpipe_set_descr(struct wahc *wa, - struct usb_rpipe_descriptor *descr, u16 index) -{ - ssize_t result; - struct device *dev = &wa->usb_iface->dev; - - /* we cannot use the usb_get_descriptor() function because the - * arguments are different. - */ - result = usb_control_msg( - wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), - USB_REQ_SET_DESCRIPTOR, - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE, - USB_DT_RPIPE<<8, index, descr, sizeof(*descr), - HZ / 10); - if (result < 0) { - dev_err(dev, "rpipe %u: set descriptor failed: %d\n", - index, (int)result); - goto error; - } - if (result < sizeof(*descr)) { - dev_err(dev, "rpipe %u: sent short descriptor " - "(%zd vs %zd bytes required)\n", - index, result, sizeof(*descr)); - result = -EINVAL; - goto error; - } - result = 0; - -error: - return result; - -} - -static void rpipe_init(struct wa_rpipe *rpipe) -{ - kref_init(&rpipe->refcnt); - spin_lock_init(&rpipe->seg_lock); - INIT_LIST_HEAD(&rpipe->seg_list); -} - -static unsigned rpipe_get_idx(struct wahc *wa, unsigned rpipe_idx) -{ - unsigned long flags; - - spin_lock_irqsave(&wa->rpipe_bm_lock, flags); - rpipe_idx = find_next_zero_bit(wa->rpipe_bm, wa->rpipes, rpipe_idx); - if (rpipe_idx < wa->rpipes) - set_bit(rpipe_idx, wa->rpipe_bm); - spin_unlock_irqrestore(&wa->rpipe_bm_lock, flags); - - return rpipe_idx; -} - -static void rpipe_put_idx(struct wahc *wa, unsigned rpipe_idx) -{ - unsigned long flags; - - spin_lock_irqsave(&wa->rpipe_bm_lock, flags); - clear_bit(rpipe_idx, wa->rpipe_bm); - spin_unlock_irqrestore(&wa->rpipe_bm_lock, flags); -} - -void rpipe_destroy(struct kref *_rpipe) -{ - struct wa_rpipe *rpipe = container_of(_rpipe, struct wa_rpipe, refcnt); - u8 index = le16_to_cpu(rpipe->descr.wRPipeIndex); - - if (rpipe->ep) - rpipe->ep->hcpriv = NULL; - rpipe_put_idx(rpipe->wa, index); - wa_put(rpipe->wa); - kfree(rpipe); -} -EXPORT_SYMBOL_GPL(rpipe_destroy); - -/* - * Locate an idle rpipe, create an structure for it and return it - * - * @wa is referenced and unlocked - * @crs enum rpipe_attr, required endpoint characteristics - * - * The rpipe can be used only sequentially (not in parallel). - * - * The rpipe is moved into the "ready" state. - */ -static int rpipe_get_idle(struct wa_rpipe **prpipe, struct wahc *wa, u8 crs, - gfp_t gfp) -{ - int result; - unsigned rpipe_idx; - struct wa_rpipe *rpipe; - struct device *dev = &wa->usb_iface->dev; - - rpipe = kzalloc(sizeof(*rpipe), gfp); - if (rpipe == NULL) - return -ENOMEM; - rpipe_init(rpipe); - - /* Look for an idle pipe */ - for (rpipe_idx = 0; rpipe_idx < wa->rpipes; rpipe_idx++) { - rpipe_idx = rpipe_get_idx(wa, rpipe_idx); - if (rpipe_idx >= wa->rpipes) /* no more pipes :( */ - break; - result = __rpipe_get_descr(wa, &rpipe->descr, rpipe_idx); - if (result < 0) - dev_err(dev, "Can't get descriptor for rpipe %u: %d\n", - rpipe_idx, result); - else if ((rpipe->descr.bmCharacteristics & crs) != 0) - goto found; - rpipe_put_idx(wa, rpipe_idx); - } - *prpipe = NULL; - kfree(rpipe); - return -ENXIO; - -found: - set_bit(rpipe_idx, wa->rpipe_bm); - rpipe->wa = wa_get(wa); - *prpipe = rpipe; - return 0; -} - -static int __rpipe_reset(struct wahc *wa, unsigned index) -{ - int result; - struct device *dev = &wa->usb_iface->dev; - - result = usb_control_msg( - wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), - USB_REQ_RPIPE_RESET, - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE, - 0, index, NULL, 0, 1000 /* FIXME: arbitrary */); - if (result < 0) - dev_err(dev, "rpipe %u: reset failed: %d\n", - index, result); - return result; -} - -/* - * Fake companion descriptor for ep0 - * - * See WUSB1.0[7.4.4], most of this is zero for bulk/int/ctl - */ -static struct usb_wireless_ep_comp_descriptor epc0 = { - .bLength = sizeof(epc0), - .bDescriptorType = USB_DT_WIRELESS_ENDPOINT_COMP, -/* .bMaxBurst = 1, */ - .bMaxSequence = 31, -}; - -/* - * Look for EP companion descriptor - * - * Get there, look for Inara in the endpoint's extra descriptors - */ -static struct usb_wireless_ep_comp_descriptor *rpipe_epc_find( - struct device *dev, struct usb_host_endpoint *ep) -{ - void *itr; - size_t itr_size; - struct usb_descriptor_header *hdr; - struct usb_wireless_ep_comp_descriptor *epcd; - - if (ep->desc.bEndpointAddress == 0) { - epcd = &epc0; - goto out; - } - itr = ep->extra; - itr_size = ep->extralen; - epcd = NULL; - while (itr_size > 0) { - if (itr_size < sizeof(*hdr)) { - dev_err(dev, "HW Bug? ep 0x%02x: extra descriptors " - "at offset %zu: only %zu bytes left\n", - ep->desc.bEndpointAddress, - itr - (void *) ep->extra, itr_size); - break; - } - hdr = itr; - if (hdr->bDescriptorType == USB_DT_WIRELESS_ENDPOINT_COMP) { - epcd = itr; - break; - } - if (hdr->bLength > itr_size) { - dev_err(dev, "HW Bug? ep 0x%02x: extra descriptor " - "at offset %zu (type 0x%02x) " - "length %d but only %zu bytes left\n", - ep->desc.bEndpointAddress, - itr - (void *) ep->extra, hdr->bDescriptorType, - hdr->bLength, itr_size); - break; - } - itr += hdr->bLength; - itr_size -= hdr->bDescriptorType; - } -out: - return epcd; -} - -/* - * Aim an rpipe to its device & endpoint destination - * - * Make sure we change the address to unauthenticathed if the device - * is WUSB and it is not authenticated. - */ -static int rpipe_aim(struct wa_rpipe *rpipe, struct wahc *wa, - struct usb_host_endpoint *ep, struct urb *urb, gfp_t gfp) -{ - int result = -ENOMSG; /* better code for lack of companion? */ - struct device *dev = &wa->usb_iface->dev; - struct usb_device *usb_dev = urb->dev; - struct usb_wireless_ep_comp_descriptor *epcd; - u8 unauth; - - epcd = rpipe_epc_find(dev, ep); - if (epcd == NULL) { - dev_err(dev, "ep 0x%02x: can't find companion descriptor\n", - ep->desc.bEndpointAddress); - goto error; - } - unauth = usb_dev->wusb && !usb_dev->authenticated ? 0x80 : 0; - __rpipe_reset(wa, le16_to_cpu(rpipe->descr.wRPipeIndex)); - atomic_set(&rpipe->segs_available, le16_to_cpu(rpipe->descr.wRequests)); - /* FIXME: block allocation system; request with queuing and timeout */ - /* FIXME: compute so seg_size > ep->maxpktsize */ - rpipe->descr.wBlocks = cpu_to_le16(16); /* given */ - /* ep0 maxpktsize is 0x200 (WUSB1.0[4.8.1]) */ - rpipe->descr.wMaxPacketSize = cpu_to_le16(ep->desc.wMaxPacketSize); - rpipe->descr.bHSHubAddress = 0; /* reserved: zero */ - rpipe->descr.bHSHubPort = wusb_port_no_to_idx(urb->dev->portnum); - /* FIXME: use maximum speed as supported or recommended by device */ - rpipe->descr.bSpeed = usb_pipeendpoint(urb->pipe) == 0 ? - UWB_PHY_RATE_53 : UWB_PHY_RATE_200; - - dev_dbg(dev, "addr %u (0x%02x) rpipe #%u ep# %u speed %d\n", - urb->dev->devnum, urb->dev->devnum | unauth, - le16_to_cpu(rpipe->descr.wRPipeIndex), - usb_pipeendpoint(urb->pipe), rpipe->descr.bSpeed); - - /* see security.c:wusb_update_address() */ - if (unlikely(urb->dev->devnum == 0x80)) - rpipe->descr.bDeviceAddress = 0; - else - rpipe->descr.bDeviceAddress = urb->dev->devnum | unauth; - rpipe->descr.bEndpointAddress = ep->desc.bEndpointAddress; - /* FIXME: bDataSequence */ - rpipe->descr.bDataSequence = 0; - /* FIXME: dwCurrentWindow */ - rpipe->descr.dwCurrentWindow = cpu_to_le32(1); - /* FIXME: bMaxDataSequence */ - rpipe->descr.bMaxDataSequence = epcd->bMaxSequence - 1; - rpipe->descr.bInterval = ep->desc.bInterval; - /* FIXME: bOverTheAirInterval */ - rpipe->descr.bOverTheAirInterval = 0; /* 0 if not isoc */ - /* FIXME: xmit power & preamble blah blah */ - rpipe->descr.bmAttribute = ep->desc.bmAttributes & 0x03; - /* rpipe->descr.bmCharacteristics RO */ - /* FIXME: bmRetryOptions */ - rpipe->descr.bmRetryOptions = 15; - /* FIXME: use for assessing link quality? */ - rpipe->descr.wNumTransactionErrors = 0; - result = __rpipe_set_descr(wa, &rpipe->descr, - le16_to_cpu(rpipe->descr.wRPipeIndex)); - if (result < 0) { - dev_err(dev, "Cannot aim rpipe: %d\n", result); - goto error; - } - result = 0; -error: - return result; -} - -/* - * Check an aimed rpipe to make sure it points to where we want - * - * We use bit 19 of the Linux USB pipe bitmap for unauth vs auth - * space; when it is like that, we or 0x80 to make an unauth address. - */ -static int rpipe_check_aim(const struct wa_rpipe *rpipe, const struct wahc *wa, - const struct usb_host_endpoint *ep, - const struct urb *urb, gfp_t gfp) -{ - int result = 0; /* better code for lack of companion? */ - struct device *dev = &wa->usb_iface->dev; - struct usb_device *usb_dev = urb->dev; - u8 unauth = (usb_dev->wusb && !usb_dev->authenticated) ? 0x80 : 0; - u8 portnum = wusb_port_no_to_idx(urb->dev->portnum); - -#define AIM_CHECK(rdf, val, text) \ - do { \ - if (rpipe->descr.rdf != (val)) { \ - dev_err(dev, \ - "rpipe aim discrepancy: " #rdf " " text "\n", \ - rpipe->descr.rdf, (val)); \ - result = -EINVAL; \ - WARN_ON(1); \ - } \ - } while (0) - AIM_CHECK(wMaxPacketSize, cpu_to_le16(ep->desc.wMaxPacketSize), - "(%u vs %u)"); - AIM_CHECK(bHSHubPort, portnum, "(%u vs %u)"); - AIM_CHECK(bSpeed, usb_pipeendpoint(urb->pipe) == 0 ? - UWB_PHY_RATE_53 : UWB_PHY_RATE_200, - "(%u vs %u)"); - AIM_CHECK(bDeviceAddress, urb->dev->devnum | unauth, "(%u vs %u)"); - AIM_CHECK(bEndpointAddress, ep->desc.bEndpointAddress, "(%u vs %u)"); - AIM_CHECK(bInterval, ep->desc.bInterval, "(%u vs %u)"); - AIM_CHECK(bmAttribute, ep->desc.bmAttributes & 0x03, "(%u vs %u)"); -#undef AIM_CHECK - return result; -} - -#ifndef CONFIG_BUG -#define CONFIG_BUG 0 -#endif - -/* - * Make sure there is an rpipe allocated for an endpoint - * - * If already allocated, we just refcount it; if not, we get an - * idle one, aim it to the right location and take it. - * - * Attaches to ep->hcpriv and rpipe->ep to ep. - */ -int rpipe_get_by_ep(struct wahc *wa, struct usb_host_endpoint *ep, - struct urb *urb, gfp_t gfp) -{ - int result = 0; - struct device *dev = &wa->usb_iface->dev; - struct wa_rpipe *rpipe; - u8 eptype; - - mutex_lock(&wa->rpipe_mutex); - rpipe = ep->hcpriv; - if (rpipe != NULL) { - if (CONFIG_BUG == 1) { - result = rpipe_check_aim(rpipe, wa, ep, urb, gfp); - if (result < 0) - goto error; - } - __rpipe_get(rpipe); - dev_dbg(dev, "ep 0x%02x: reusing rpipe %u\n", - ep->desc.bEndpointAddress, - le16_to_cpu(rpipe->descr.wRPipeIndex)); - } else { - /* hmm, assign idle rpipe, aim it */ - result = -ENOBUFS; - eptype = ep->desc.bmAttributes & 0x03; - result = rpipe_get_idle(&rpipe, wa, 1 << eptype, gfp); - if (result < 0) - goto error; - result = rpipe_aim(rpipe, wa, ep, urb, gfp); - if (result < 0) { - rpipe_put(rpipe); - goto error; - } - ep->hcpriv = rpipe; - rpipe->ep = ep; - __rpipe_get(rpipe); /* for caching into ep->hcpriv */ - dev_dbg(dev, "ep 0x%02x: using rpipe %u\n", - ep->desc.bEndpointAddress, - le16_to_cpu(rpipe->descr.wRPipeIndex)); - } -error: - mutex_unlock(&wa->rpipe_mutex); - return result; -} - -/* - * Allocate the bitmap for each rpipe. - */ -int wa_rpipes_create(struct wahc *wa) -{ - wa->rpipes = wa->wa_descr->wNumRPipes; - wa->rpipe_bm = kzalloc(BITS_TO_LONGS(wa->rpipes)*sizeof(unsigned long), - GFP_KERNEL); - if (wa->rpipe_bm == NULL) - return -ENOMEM; - return 0; -} - -void wa_rpipes_destroy(struct wahc *wa) -{ - struct device *dev = &wa->usb_iface->dev; - - if (!bitmap_empty(wa->rpipe_bm, wa->rpipes)) { - char buf[256]; - WARN_ON(1); - bitmap_scnprintf(buf, sizeof(buf), wa->rpipe_bm, wa->rpipes); - dev_err(dev, "BUG: pipes not released on exit: %s\n", buf); - } - kfree(wa->rpipe_bm); -} - -/* - * Release resources allocated for an endpoint - * - * If there is an associated rpipe to this endpoint, Abort any pending - * transfers and put it. If the rpipe ends up being destroyed, - * __rpipe_destroy() will cleanup ep->hcpriv. - * - * This is called before calling hcd->stop(), so you don't need to do - * anything else in there. - */ -void rpipe_ep_disable(struct wahc *wa, struct usb_host_endpoint *ep) -{ - struct wa_rpipe *rpipe; - - mutex_lock(&wa->rpipe_mutex); - rpipe = ep->hcpriv; - if (rpipe != NULL) { - u16 index = le16_to_cpu(rpipe->descr.wRPipeIndex); - - usb_control_msg( - wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0), - USB_REQ_RPIPE_ABORT, - USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE, - 0, index, NULL, 0, 1000 /* FIXME: arbitrary */); - rpipe_put(rpipe); - } - mutex_unlock(&wa->rpipe_mutex); -} -EXPORT_SYMBOL_GPL(rpipe_ep_disable); diff --git a/ANDROID_3.4.5/drivers/usb/wusbcore/wa-xfer.c b/ANDROID_3.4.5/drivers/usb/wusbcore/wa-xfer.c deleted file mode 100644 index 57c01ab0..00000000 --- a/ANDROID_3.4.5/drivers/usb/wusbcore/wa-xfer.c +++ /dev/null @@ -1,1616 +0,0 @@ -/* - * WUSB Wire Adapter - * Data transfer and URB enqueing - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * - * How transfers work: get a buffer, break it up in segments (segment - * size is a multiple of the maxpacket size). For each segment issue a - * segment request (struct wa_xfer_*), then send the data buffer if - * out or nothing if in (all over the DTO endpoint). - * - * For each submitted segment request, a notification will come over - * the NEP endpoint and a transfer result (struct xfer_result) will - * arrive in the DTI URB. Read it, get the xfer ID, see if there is - * data coming (inbound transfer), schedule a read and handle it. - * - * Sounds simple, it is a pain to implement. - * - * - * ENTRY POINTS - * - * FIXME - * - * LIFE CYCLE / STATE DIAGRAM - * - * FIXME - * - * THIS CODE IS DISGUSTING - * - * Warned you are; it's my second try and still not happy with it. - * - * NOTES: - * - * - No iso - * - * - Supports DMA xfers, control, bulk and maybe interrupt - * - * - Does not recycle unused rpipes - * - * An rpipe is assigned to an endpoint the first time it is used, - * and then it's there, assigned, until the endpoint is disabled - * (destroyed [{h,d}wahc_op_ep_disable()]. The assignment of the - * rpipe to the endpoint is done under the wa->rpipe_sem semaphore - * (should be a mutex). - * - * Two methods it could be done: - * - * (a) set up a timer every time an rpipe's use count drops to 1 - * (which means unused) or when a transfer ends. Reset the - * timer when a xfer is queued. If the timer expires, release - * the rpipe [see rpipe_ep_disable()]. - * - * (b) when looking for free rpipes to attach [rpipe_get_by_ep()], - * when none are found go over the list, check their endpoint - * and their activity record (if no last-xfer-done-ts in the - * last x seconds) take it - * - * However, due to the fact that we have a set of limited - * resources (max-segments-at-the-same-time per xfer, - * xfers-per-ripe, blocks-per-rpipe, rpipes-per-host), at the end - * we are going to have to rebuild all this based on an scheduler, - * to where we have a list of transactions to do and based on the - * availability of the different required components (blocks, - * rpipes, segment slots, etc), we go scheduling them. Painful. - */ -#include -#include -#include -#include -#include -#include - -#include "wa-hc.h" -#include "wusbhc.h" - -enum { - WA_SEGS_MAX = 255, -}; - -enum wa_seg_status { - WA_SEG_NOTREADY, - WA_SEG_READY, - WA_SEG_DELAYED, - WA_SEG_SUBMITTED, - WA_SEG_PENDING, - WA_SEG_DTI_PENDING, - WA_SEG_DONE, - WA_SEG_ERROR, - WA_SEG_ABORTED, -}; - -static void wa_xfer_delayed_run(struct wa_rpipe *); - -/* - * Life cycle governed by 'struct urb' (the refcount of the struct is - * that of the 'struct urb' and usb_free_urb() would free the whole - * struct). - */ -struct wa_seg { - struct urb urb; - struct urb *dto_urb; /* for data output? */ - struct list_head list_node; /* for rpipe->req_list */ - struct wa_xfer *xfer; /* out xfer */ - u8 index; /* which segment we are */ - enum wa_seg_status status; - ssize_t result; /* bytes xfered or error */ - struct wa_xfer_hdr xfer_hdr; - u8 xfer_extra[]; /* xtra space for xfer_hdr_ctl */ -}; - -static void wa_seg_init(struct wa_seg *seg) -{ - /* usb_init_urb() repeats a lot of work, so we do it here */ - kref_init(&seg->urb.kref); -} - -/* - * Protected by xfer->lock - * - */ -struct wa_xfer { - struct kref refcnt; - struct list_head list_node; - spinlock_t lock; - u32 id; - - struct wahc *wa; /* Wire adapter we are plugged to */ - struct usb_host_endpoint *ep; - struct urb *urb; /* URB we are transferring for */ - struct wa_seg **seg; /* transfer segments */ - u8 segs, segs_submitted, segs_done; - unsigned is_inbound:1; - unsigned is_dma:1; - size_t seg_size; - int result; - - gfp_t gfp; /* allocation mask */ - - struct wusb_dev *wusb_dev; /* for activity timestamps */ -}; - -static inline void wa_xfer_init(struct wa_xfer *xfer) -{ - kref_init(&xfer->refcnt); - INIT_LIST_HEAD(&xfer->list_node); - spin_lock_init(&xfer->lock); -} - -/* - * Destroy a transfer structure - * - * Note that the xfer->seg[index] thingies follow the URB life cycle, - * so we need to put them, not free them. - */ -static void wa_xfer_destroy(struct kref *_xfer) -{ - struct wa_xfer *xfer = container_of(_xfer, struct wa_xfer, refcnt); - if (xfer->seg) { - unsigned cnt; - for (cnt = 0; cnt < xfer->segs; cnt++) { - if (xfer->is_inbound) - usb_put_urb(xfer->seg[cnt]->dto_urb); - usb_put_urb(&xfer->seg[cnt]->urb); - } - } - kfree(xfer); -} - -static void wa_xfer_get(struct wa_xfer *xfer) -{ - kref_get(&xfer->refcnt); -} - -static void wa_xfer_put(struct wa_xfer *xfer) -{ - kref_put(&xfer->refcnt, wa_xfer_destroy); -} - -/* - * xfer is referenced - * - * xfer->lock has to be unlocked - * - * We take xfer->lock for setting the result; this is a barrier - * against drivers/usb/core/hcd.c:unlink1() being called after we call - * usb_hcd_giveback_urb() and wa_urb_dequeue() trying to get a - * reference to the transfer. - */ -static void wa_xfer_giveback(struct wa_xfer *xfer) -{ - unsigned long flags; - - spin_lock_irqsave(&xfer->wa->xfer_list_lock, flags); - list_del_init(&xfer->list_node); - spin_unlock_irqrestore(&xfer->wa->xfer_list_lock, flags); - /* FIXME: segmentation broken -- kills DWA */ - wusbhc_giveback_urb(xfer->wa->wusb, xfer->urb, xfer->result); - wa_put(xfer->wa); - wa_xfer_put(xfer); -} - -/* - * xfer is referenced - * - * xfer->lock has to be unlocked - */ -static void wa_xfer_completion(struct wa_xfer *xfer) -{ - if (xfer->wusb_dev) - wusb_dev_put(xfer->wusb_dev); - rpipe_put(xfer->ep->hcpriv); - wa_xfer_giveback(xfer); -} - -/* - * If transfer is done, wrap it up and return true - * - * xfer->lock has to be locked - */ -static unsigned __wa_xfer_is_done(struct wa_xfer *xfer) -{ - struct device *dev = &xfer->wa->usb_iface->dev; - unsigned result, cnt; - struct wa_seg *seg; - struct urb *urb = xfer->urb; - unsigned found_short = 0; - - result = xfer->segs_done == xfer->segs_submitted; - if (result == 0) - goto out; - urb->actual_length = 0; - for (cnt = 0; cnt < xfer->segs; cnt++) { - seg = xfer->seg[cnt]; - switch (seg->status) { - case WA_SEG_DONE: - if (found_short && seg->result > 0) { - dev_dbg(dev, "xfer %p#%u: bad short segments (%zu)\n", - xfer, cnt, seg->result); - urb->status = -EINVAL; - goto out; - } - urb->actual_length += seg->result; - if (seg->result < xfer->seg_size - && cnt != xfer->segs-1) - found_short = 1; - dev_dbg(dev, "xfer %p#%u: DONE short %d " - "result %zu urb->actual_length %d\n", - xfer, seg->index, found_short, seg->result, - urb->actual_length); - break; - case WA_SEG_ERROR: - xfer->result = seg->result; - dev_dbg(dev, "xfer %p#%u: ERROR result %zu\n", - xfer, seg->index, seg->result); - goto out; - case WA_SEG_ABORTED: - dev_dbg(dev, "xfer %p#%u ABORTED: result %d\n", - xfer, seg->index, urb->status); - xfer->result = urb->status; - goto out; - default: - dev_warn(dev, "xfer %p#%u: is_done bad state %d\n", - xfer, cnt, seg->status); - xfer->result = -EINVAL; - goto out; - } - } - xfer->result = 0; -out: - return result; -} - -/* - * Initialize a transfer's ID - * - * We need to use a sequential number; if we use the pointer or the - * hash of the pointer, it can repeat over sequential transfers and - * then it will confuse the HWA....wonder why in hell they put a 32 - * bit handle in there then. - */ -static void wa_xfer_id_init(struct wa_xfer *xfer) -{ - xfer->id = atomic_add_return(1, &xfer->wa->xfer_id_count); -} - -/* - * Return the xfer's ID associated with xfer - * - * Need to generate a - */ -static u32 wa_xfer_id(struct wa_xfer *xfer) -{ - return xfer->id; -} - -/* - * Search for a transfer list ID on the HCD's URB list - * - * For 32 bit architectures, we use the pointer itself; for 64 bits, a - * 32-bit hash of the pointer. - * - * @returns NULL if not found. - */ -static struct wa_xfer *wa_xfer_get_by_id(struct wahc *wa, u32 id) -{ - unsigned long flags; - struct wa_xfer *xfer_itr; - spin_lock_irqsave(&wa->xfer_list_lock, flags); - list_for_each_entry(xfer_itr, &wa->xfer_list, list_node) { - if (id == xfer_itr->id) { - wa_xfer_get(xfer_itr); - goto out; - } - } - xfer_itr = NULL; -out: - spin_unlock_irqrestore(&wa->xfer_list_lock, flags); - return xfer_itr; -} - -struct wa_xfer_abort_buffer { - struct urb urb; - struct wa_xfer_abort cmd; -}; - -static void __wa_xfer_abort_cb(struct urb *urb) -{ - struct wa_xfer_abort_buffer *b = urb->context; - usb_put_urb(&b->urb); -} - -/* - * Aborts an ongoing transaction - * - * Assumes the transfer is referenced and locked and in a submitted - * state (mainly that there is an endpoint/rpipe assigned). - * - * The callback (see above) does nothing but freeing up the data by - * putting the URB. Because the URB is allocated at the head of the - * struct, the whole space we allocated is kfreed. - * - * We'll get an 'aborted transaction' xfer result on DTI, that'll - * politely ignore because at this point the transaction has been - * marked as aborted already. - */ -static void __wa_xfer_abort(struct wa_xfer *xfer) -{ - int result; - struct device *dev = &xfer->wa->usb_iface->dev; - struct wa_xfer_abort_buffer *b; - struct wa_rpipe *rpipe = xfer->ep->hcpriv; - - b = kmalloc(sizeof(*b), GFP_ATOMIC); - if (b == NULL) - goto error_kmalloc; - b->cmd.bLength = sizeof(b->cmd); - b->cmd.bRequestType = WA_XFER_ABORT; - b->cmd.wRPipe = rpipe->descr.wRPipeIndex; - b->cmd.dwTransferID = wa_xfer_id(xfer); - - usb_init_urb(&b->urb); - usb_fill_bulk_urb(&b->urb, xfer->wa->usb_dev, - usb_sndbulkpipe(xfer->wa->usb_dev, - xfer->wa->dto_epd->bEndpointAddress), - &b->cmd, sizeof(b->cmd), __wa_xfer_abort_cb, b); - result = usb_submit_urb(&b->urb, GFP_ATOMIC); - if (result < 0) - goto error_submit; - return; /* callback frees! */ - - -error_submit: - if (printk_ratelimit()) - dev_err(dev, "xfer %p: Can't submit abort request: %d\n", - xfer, result); - kfree(b); -error_kmalloc: - return; - -} - -/* - * - * @returns < 0 on error, transfer segment request size if ok - */ -static ssize_t __wa_xfer_setup_sizes(struct wa_xfer *xfer, - enum wa_xfer_type *pxfer_type) -{ - ssize_t result; - struct device *dev = &xfer->wa->usb_iface->dev; - size_t maxpktsize; - struct urb *urb = xfer->urb; - struct wa_rpipe *rpipe = xfer->ep->hcpriv; - - switch (rpipe->descr.bmAttribute & 0x3) { - case USB_ENDPOINT_XFER_CONTROL: - *pxfer_type = WA_XFER_TYPE_CTL; - result = sizeof(struct wa_xfer_ctl); - break; - case USB_ENDPOINT_XFER_INT: - case USB_ENDPOINT_XFER_BULK: - *pxfer_type = WA_XFER_TYPE_BI; - result = sizeof(struct wa_xfer_bi); - break; - case USB_ENDPOINT_XFER_ISOC: - dev_err(dev, "FIXME: ISOC not implemented\n"); - result = -ENOSYS; - goto error; - default: - /* never happens */ - BUG(); - result = -EINVAL; /* shut gcc up */ - }; - xfer->is_inbound = urb->pipe & USB_DIR_IN ? 1 : 0; - xfer->is_dma = urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP ? 1 : 0; - xfer->seg_size = le16_to_cpu(rpipe->descr.wBlocks) - * 1 << (xfer->wa->wa_descr->bRPipeBlockSize - 1); - /* Compute the segment size and make sure it is a multiple of - * the maxpktsize (WUSB1.0[8.3.3.1])...not really too much of - * a check (FIXME) */ - maxpktsize = le16_to_cpu(rpipe->descr.wMaxPacketSize); - if (xfer->seg_size < maxpktsize) { - dev_err(dev, "HW BUG? seg_size %zu smaller than maxpktsize " - "%zu\n", xfer->seg_size, maxpktsize); - result = -EINVAL; - goto error; - } - xfer->seg_size = (xfer->seg_size / maxpktsize) * maxpktsize; - xfer->segs = (urb->transfer_buffer_length + xfer->seg_size - 1) - / xfer->seg_size; - if (xfer->segs >= WA_SEGS_MAX) { - dev_err(dev, "BUG? ops, number of segments %d bigger than %d\n", - (int)(urb->transfer_buffer_length / xfer->seg_size), - WA_SEGS_MAX); - result = -EINVAL; - goto error; - } - if (xfer->segs == 0 && *pxfer_type == WA_XFER_TYPE_CTL) - xfer->segs = 1; -error: - return result; -} - -/* Fill in the common request header and xfer-type specific data. */ -static void __wa_xfer_setup_hdr0(struct wa_xfer *xfer, - struct wa_xfer_hdr *xfer_hdr0, - enum wa_xfer_type xfer_type, - size_t xfer_hdr_size) -{ - struct wa_rpipe *rpipe = xfer->ep->hcpriv; - - xfer_hdr0 = &xfer->seg[0]->xfer_hdr; - xfer_hdr0->bLength = xfer_hdr_size; - xfer_hdr0->bRequestType = xfer_type; - xfer_hdr0->wRPipe = rpipe->descr.wRPipeIndex; - xfer_hdr0->dwTransferID = wa_xfer_id(xfer); - xfer_hdr0->bTransferSegment = 0; - switch (xfer_type) { - case WA_XFER_TYPE_CTL: { - struct wa_xfer_ctl *xfer_ctl = - container_of(xfer_hdr0, struct wa_xfer_ctl, hdr); - xfer_ctl->bmAttribute = xfer->is_inbound ? 1 : 0; - memcpy(&xfer_ctl->baSetupData, xfer->urb->setup_packet, - sizeof(xfer_ctl->baSetupData)); - break; - } - case WA_XFER_TYPE_BI: - break; - case WA_XFER_TYPE_ISO: - printk(KERN_ERR "FIXME: ISOC not implemented\n"); - default: - BUG(); - }; -} - -/* - * Callback for the OUT data phase of the segment request - * - * Check wa_seg_cb(); most comments also apply here because this - * function does almost the same thing and they work closely - * together. - * - * If the seg request has failed but this DTO phase has succeeded, - * wa_seg_cb() has already failed the segment and moved the - * status to WA_SEG_ERROR, so this will go through 'case 0' and - * effectively do nothing. - */ -static void wa_seg_dto_cb(struct urb *urb) -{ - struct wa_seg *seg = urb->context; - struct wa_xfer *xfer = seg->xfer; - struct wahc *wa; - struct device *dev; - struct wa_rpipe *rpipe; - unsigned long flags; - unsigned rpipe_ready = 0; - u8 done = 0; - - switch (urb->status) { - case 0: - spin_lock_irqsave(&xfer->lock, flags); - wa = xfer->wa; - dev = &wa->usb_iface->dev; - dev_dbg(dev, "xfer %p#%u: data out done (%d bytes)\n", - xfer, seg->index, urb->actual_length); - if (seg->status < WA_SEG_PENDING) - seg->status = WA_SEG_PENDING; - seg->result = urb->actual_length; - spin_unlock_irqrestore(&xfer->lock, flags); - break; - case -ECONNRESET: /* URB unlinked; no need to do anything */ - case -ENOENT: /* as it was done by the who unlinked us */ - break; - default: /* Other errors ... */ - spin_lock_irqsave(&xfer->lock, flags); - wa = xfer->wa; - dev = &wa->usb_iface->dev; - rpipe = xfer->ep->hcpriv; - dev_dbg(dev, "xfer %p#%u: data out error %d\n", - xfer, seg->index, urb->status); - if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS, - EDC_ERROR_TIMEFRAME)){ - dev_err(dev, "DTO: URB max acceptable errors " - "exceeded, resetting device\n"); - wa_reset_all(wa); - } - if (seg->status != WA_SEG_ERROR) { - seg->status = WA_SEG_ERROR; - seg->result = urb->status; - xfer->segs_done++; - __wa_xfer_abort(xfer); - rpipe_ready = rpipe_avail_inc(rpipe); - done = __wa_xfer_is_done(xfer); - } - spin_unlock_irqrestore(&xfer->lock, flags); - if (done) - wa_xfer_completion(xfer); - if (rpipe_ready) - wa_xfer_delayed_run(rpipe); - } -} - -/* - * Callback for the segment request - * - * If successful transition state (unless already transitioned or - * outbound transfer); otherwise, take a note of the error, mark this - * segment done and try completion. - * - * Note we don't access until we are sure that the transfer hasn't - * been cancelled (ECONNRESET, ENOENT), which could mean that - * seg->xfer could be already gone. - * - * We have to check before setting the status to WA_SEG_PENDING - * because sometimes the xfer result callback arrives before this - * callback (geeeeeeze), so it might happen that we are already in - * another state. As well, we don't set it if the transfer is inbound, - * as in that case, wa_seg_dto_cb will do it when the OUT data phase - * finishes. - */ -static void wa_seg_cb(struct urb *urb) -{ - struct wa_seg *seg = urb->context; - struct wa_xfer *xfer = seg->xfer; - struct wahc *wa; - struct device *dev; - struct wa_rpipe *rpipe; - unsigned long flags; - unsigned rpipe_ready; - u8 done = 0; - - switch (urb->status) { - case 0: - spin_lock_irqsave(&xfer->lock, flags); - wa = xfer->wa; - dev = &wa->usb_iface->dev; - dev_dbg(dev, "xfer %p#%u: request done\n", xfer, seg->index); - if (xfer->is_inbound && seg->status < WA_SEG_PENDING) - seg->status = WA_SEG_PENDING; - spin_unlock_irqrestore(&xfer->lock, flags); - break; - case -ECONNRESET: /* URB unlinked; no need to do anything */ - case -ENOENT: /* as it was done by the who unlinked us */ - break; - default: /* Other errors ... */ - spin_lock_irqsave(&xfer->lock, flags); - wa = xfer->wa; - dev = &wa->usb_iface->dev; - rpipe = xfer->ep->hcpriv; - if (printk_ratelimit()) - dev_err(dev, "xfer %p#%u: request error %d\n", - xfer, seg->index, urb->status); - if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS, - EDC_ERROR_TIMEFRAME)){ - dev_err(dev, "DTO: URB max acceptable errors " - "exceeded, resetting device\n"); - wa_reset_all(wa); - } - usb_unlink_urb(seg->dto_urb); - seg->status = WA_SEG_ERROR; - seg->result = urb->status; - xfer->segs_done++; - __wa_xfer_abort(xfer); - rpipe_ready = rpipe_avail_inc(rpipe); - done = __wa_xfer_is_done(xfer); - spin_unlock_irqrestore(&xfer->lock, flags); - if (done) - wa_xfer_completion(xfer); - if (rpipe_ready) - wa_xfer_delayed_run(rpipe); - } -} - -/* - * Allocate the segs array and initialize each of them - * - * The segments are freed by wa_xfer_destroy() when the xfer use count - * drops to zero; however, because each segment is given the same life - * cycle as the USB URB it contains, it is actually freed by - * usb_put_urb() on the contained USB URB (twisted, eh?). - */ -static int __wa_xfer_setup_segs(struct wa_xfer *xfer, size_t xfer_hdr_size) -{ - int result, cnt; - size_t alloc_size = sizeof(*xfer->seg[0]) - - sizeof(xfer->seg[0]->xfer_hdr) + xfer_hdr_size; - struct usb_device *usb_dev = xfer->wa->usb_dev; - const struct usb_endpoint_descriptor *dto_epd = xfer->wa->dto_epd; - struct wa_seg *seg; - size_t buf_itr, buf_size, buf_itr_size; - - result = -ENOMEM; - xfer->seg = kcalloc(xfer->segs, sizeof(xfer->seg[0]), GFP_ATOMIC); - if (xfer->seg == NULL) - goto error_segs_kzalloc; - buf_itr = 0; - buf_size = xfer->urb->transfer_buffer_length; - for (cnt = 0; cnt < xfer->segs; cnt++) { - seg = xfer->seg[cnt] = kzalloc(alloc_size, GFP_ATOMIC); - if (seg == NULL) - goto error_seg_kzalloc; - wa_seg_init(seg); - seg->xfer = xfer; - seg->index = cnt; - usb_fill_bulk_urb(&seg->urb, usb_dev, - usb_sndbulkpipe(usb_dev, - dto_epd->bEndpointAddress), - &seg->xfer_hdr, xfer_hdr_size, - wa_seg_cb, seg); - buf_itr_size = buf_size > xfer->seg_size ? - xfer->seg_size : buf_size; - if (xfer->is_inbound == 0 && buf_size > 0) { - seg->dto_urb = usb_alloc_urb(0, GFP_ATOMIC); - if (seg->dto_urb == NULL) - goto error_dto_alloc; - usb_fill_bulk_urb( - seg->dto_urb, usb_dev, - usb_sndbulkpipe(usb_dev, - dto_epd->bEndpointAddress), - NULL, 0, wa_seg_dto_cb, seg); - if (xfer->is_dma) { - seg->dto_urb->transfer_dma = - xfer->urb->transfer_dma + buf_itr; - seg->dto_urb->transfer_flags |= - URB_NO_TRANSFER_DMA_MAP; - } else - seg->dto_urb->transfer_buffer = - xfer->urb->transfer_buffer + buf_itr; - seg->dto_urb->transfer_buffer_length = buf_itr_size; - } - seg->status = WA_SEG_READY; - buf_itr += buf_itr_size; - buf_size -= buf_itr_size; - } - return 0; - -error_dto_alloc: - kfree(xfer->seg[cnt]); - cnt--; -error_seg_kzalloc: - /* use the fact that cnt is left at were it failed */ - for (; cnt > 0; cnt--) { - if (xfer->is_inbound == 0) - kfree(xfer->seg[cnt]->dto_urb); - kfree(xfer->seg[cnt]); - } -error_segs_kzalloc: - return result; -} - -/* - * Allocates all the stuff needed to submit a transfer - * - * Breaks the whole data buffer in a list of segments, each one has a - * structure allocated to it and linked in xfer->seg[index] - * - * FIXME: merge setup_segs() and the last part of this function, no - * need to do two for loops when we could run everything in a - * single one - */ -static int __wa_xfer_setup(struct wa_xfer *xfer, struct urb *urb) -{ - int result; - struct device *dev = &xfer->wa->usb_iface->dev; - enum wa_xfer_type xfer_type = 0; /* shut up GCC */ - size_t xfer_hdr_size, cnt, transfer_size; - struct wa_xfer_hdr *xfer_hdr0, *xfer_hdr; - - result = __wa_xfer_setup_sizes(xfer, &xfer_type); - if (result < 0) - goto error_setup_sizes; - xfer_hdr_size = result; - result = __wa_xfer_setup_segs(xfer, xfer_hdr_size); - if (result < 0) { - dev_err(dev, "xfer %p: Failed to allocate %d segments: %d\n", - xfer, xfer->segs, result); - goto error_setup_segs; - } - /* Fill the first header */ - xfer_hdr0 = &xfer->seg[0]->xfer_hdr; - wa_xfer_id_init(xfer); - __wa_xfer_setup_hdr0(xfer, xfer_hdr0, xfer_type, xfer_hdr_size); - - /* Fill remainig headers */ - xfer_hdr = xfer_hdr0; - transfer_size = urb->transfer_buffer_length; - xfer_hdr0->dwTransferLength = transfer_size > xfer->seg_size ? - xfer->seg_size : transfer_size; - transfer_size -= xfer->seg_size; - for (cnt = 1; cnt < xfer->segs; cnt++) { - xfer_hdr = &xfer->seg[cnt]->xfer_hdr; - memcpy(xfer_hdr, xfer_hdr0, xfer_hdr_size); - xfer_hdr->bTransferSegment = cnt; - xfer_hdr->dwTransferLength = transfer_size > xfer->seg_size ? - cpu_to_le32(xfer->seg_size) - : cpu_to_le32(transfer_size); - xfer->seg[cnt]->status = WA_SEG_READY; - transfer_size -= xfer->seg_size; - } - xfer_hdr->bTransferSegment |= 0x80; /* this is the last segment */ - result = 0; -error_setup_segs: -error_setup_sizes: - return result; -} - -/* - * - * - * rpipe->seg_lock is held! - */ -static int __wa_seg_submit(struct wa_rpipe *rpipe, struct wa_xfer *xfer, - struct wa_seg *seg) -{ - int result; - result = usb_submit_urb(&seg->urb, GFP_ATOMIC); - if (result < 0) { - printk(KERN_ERR "xfer %p#%u: REQ submit failed: %d\n", - xfer, seg->index, result); - goto error_seg_submit; - } - if (seg->dto_urb) { - result = usb_submit_urb(seg->dto_urb, GFP_ATOMIC); - if (result < 0) { - printk(KERN_ERR "xfer %p#%u: DTO submit failed: %d\n", - xfer, seg->index, result); - goto error_dto_submit; - } - } - seg->status = WA_SEG_SUBMITTED; - rpipe_avail_dec(rpipe); - return 0; - -error_dto_submit: - usb_unlink_urb(&seg->urb); -error_seg_submit: - seg->status = WA_SEG_ERROR; - seg->result = result; - return result; -} - -/* - * Execute more queued request segments until the maximum concurrent allowed - * - * The ugly unlock/lock sequence on the error path is needed as the - * xfer->lock normally nests the seg_lock and not viceversa. - * - */ -static void wa_xfer_delayed_run(struct wa_rpipe *rpipe) -{ - int result; - struct device *dev = &rpipe->wa->usb_iface->dev; - struct wa_seg *seg; - struct wa_xfer *xfer; - unsigned long flags; - - spin_lock_irqsave(&rpipe->seg_lock, flags); - while (atomic_read(&rpipe->segs_available) > 0 - && !list_empty(&rpipe->seg_list)) { - seg = list_entry(rpipe->seg_list.next, struct wa_seg, - list_node); - list_del(&seg->list_node); - xfer = seg->xfer; - result = __wa_seg_submit(rpipe, xfer, seg); - dev_dbg(dev, "xfer %p#%u submitted from delayed [%d segments available] %d\n", - xfer, seg->index, atomic_read(&rpipe->segs_available), result); - if (unlikely(result < 0)) { - spin_unlock_irqrestore(&rpipe->seg_lock, flags); - spin_lock_irqsave(&xfer->lock, flags); - __wa_xfer_abort(xfer); - xfer->segs_done++; - spin_unlock_irqrestore(&xfer->lock, flags); - spin_lock_irqsave(&rpipe->seg_lock, flags); - } - } - spin_unlock_irqrestore(&rpipe->seg_lock, flags); -} - -/* - * - * xfer->lock is taken - * - * On failure submitting we just stop submitting and return error; - * wa_urb_enqueue_b() will execute the completion path - */ -static int __wa_xfer_submit(struct wa_xfer *xfer) -{ - int result; - struct wahc *wa = xfer->wa; - struct device *dev = &wa->usb_iface->dev; - unsigned cnt; - struct wa_seg *seg; - unsigned long flags; - struct wa_rpipe *rpipe = xfer->ep->hcpriv; - size_t maxrequests = le16_to_cpu(rpipe->descr.wRequests); - u8 available; - u8 empty; - - spin_lock_irqsave(&wa->xfer_list_lock, flags); - list_add_tail(&xfer->list_node, &wa->xfer_list); - spin_unlock_irqrestore(&wa->xfer_list_lock, flags); - - BUG_ON(atomic_read(&rpipe->segs_available) > maxrequests); - result = 0; - spin_lock_irqsave(&rpipe->seg_lock, flags); - for (cnt = 0; cnt < xfer->segs; cnt++) { - available = atomic_read(&rpipe->segs_available); - empty = list_empty(&rpipe->seg_list); - seg = xfer->seg[cnt]; - dev_dbg(dev, "xfer %p#%u: available %u empty %u (%s)\n", - xfer, cnt, available, empty, - available == 0 || !empty ? "delayed" : "submitted"); - if (available == 0 || !empty) { - dev_dbg(dev, "xfer %p#%u: delayed\n", xfer, cnt); - seg->status = WA_SEG_DELAYED; - list_add_tail(&seg->list_node, &rpipe->seg_list); - } else { - result = __wa_seg_submit(rpipe, xfer, seg); - if (result < 0) { - __wa_xfer_abort(xfer); - goto error_seg_submit; - } - } - xfer->segs_submitted++; - } -error_seg_submit: - spin_unlock_irqrestore(&rpipe->seg_lock, flags); - return result; -} - -/* - * Second part of a URB/transfer enqueuement - * - * Assumes this comes from wa_urb_enqueue() [maybe through - * wa_urb_enqueue_run()]. At this point: - * - * xfer->wa filled and refcounted - * xfer->ep filled with rpipe refcounted if - * delayed == 0 - * xfer->urb filled and refcounted (this is the case when called - * from wa_urb_enqueue() as we come from usb_submit_urb() - * and when called by wa_urb_enqueue_run(), as we took an - * extra ref dropped by _run() after we return). - * xfer->gfp filled - * - * If we fail at __wa_xfer_submit(), then we just check if we are done - * and if so, we run the completion procedure. However, if we are not - * yet done, we do nothing and wait for the completion handlers from - * the submitted URBs or from the xfer-result path to kick in. If xfer - * result never kicks in, the xfer will timeout from the USB code and - * dequeue() will be called. - */ -static void wa_urb_enqueue_b(struct wa_xfer *xfer) -{ - int result; - unsigned long flags; - struct urb *urb = xfer->urb; - struct wahc *wa = xfer->wa; - struct wusbhc *wusbhc = wa->wusb; - struct wusb_dev *wusb_dev; - unsigned done; - - result = rpipe_get_by_ep(wa, xfer->ep, urb, xfer->gfp); - if (result < 0) - goto error_rpipe_get; - result = -ENODEV; - /* FIXME: segmentation broken -- kills DWA */ - mutex_lock(&wusbhc->mutex); /* get a WUSB dev */ - if (urb->dev == NULL) { - mutex_unlock(&wusbhc->mutex); - goto error_dev_gone; - } - wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, urb->dev); - if (wusb_dev == NULL) { - mutex_unlock(&wusbhc->mutex); - goto error_dev_gone; - } - mutex_unlock(&wusbhc->mutex); - - spin_lock_irqsave(&xfer->lock, flags); - xfer->wusb_dev = wusb_dev; - result = urb->status; - if (urb->status != -EINPROGRESS) - goto error_dequeued; - - result = __wa_xfer_setup(xfer, urb); - if (result < 0) - goto error_xfer_setup; - result = __wa_xfer_submit(xfer); - if (result < 0) - goto error_xfer_submit; - spin_unlock_irqrestore(&xfer->lock, flags); - return; - - /* this is basically wa_xfer_completion() broken up wa_xfer_giveback() - * does a wa_xfer_put() that will call wa_xfer_destroy() and clean - * upundo setup(). - */ -error_xfer_setup: -error_dequeued: - spin_unlock_irqrestore(&xfer->lock, flags); - /* FIXME: segmentation broken, kills DWA */ - if (wusb_dev) - wusb_dev_put(wusb_dev); -error_dev_gone: - rpipe_put(xfer->ep->hcpriv); -error_rpipe_get: - xfer->result = result; - wa_xfer_giveback(xfer); - return; - -error_xfer_submit: - done = __wa_xfer_is_done(xfer); - xfer->result = result; - spin_unlock_irqrestore(&xfer->lock, flags); - if (done) - wa_xfer_completion(xfer); -} - -/* - * Execute the delayed transfers in the Wire Adapter @wa - * - * We need to be careful here, as dequeue() could be called in the - * middle. That's why we do the whole thing under the - * wa->xfer_list_lock. If dequeue() jumps in, it first locks urb->lock - * and then checks the list -- so as we would be acquiring in inverse - * order, we just drop the lock once we have the xfer and reacquire it - * later. - */ -void wa_urb_enqueue_run(struct work_struct *ws) -{ - struct wahc *wa = container_of(ws, struct wahc, xfer_work); - struct wa_xfer *xfer, *next; - struct urb *urb; - - spin_lock_irq(&wa->xfer_list_lock); - list_for_each_entry_safe(xfer, next, &wa->xfer_delayed_list, - list_node) { - list_del_init(&xfer->list_node); - spin_unlock_irq(&wa->xfer_list_lock); - - urb = xfer->urb; - wa_urb_enqueue_b(xfer); - usb_put_urb(urb); /* taken when queuing */ - - spin_lock_irq(&wa->xfer_list_lock); - } - spin_unlock_irq(&wa->xfer_list_lock); -} -EXPORT_SYMBOL_GPL(wa_urb_enqueue_run); - -/* - * Submit a transfer to the Wire Adapter in a delayed way - * - * The process of enqueuing involves possible sleeps() [see - * enqueue_b(), for the rpipe_get() and the mutex_lock()]. If we are - * in an atomic section, we defer the enqueue_b() call--else we call direct. - * - * @urb: We own a reference to it done by the HCI Linux USB stack that - * will be given up by calling usb_hcd_giveback_urb() or by - * returning error from this function -> ergo we don't have to - * refcount it. - */ -int wa_urb_enqueue(struct wahc *wa, struct usb_host_endpoint *ep, - struct urb *urb, gfp_t gfp) -{ - int result; - struct device *dev = &wa->usb_iface->dev; - struct wa_xfer *xfer; - unsigned long my_flags; - unsigned cant_sleep = irqs_disabled() | in_atomic(); - - if (urb->transfer_buffer == NULL - && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) - && urb->transfer_buffer_length != 0) { - dev_err(dev, "BUG? urb %p: NULL xfer buffer & NODMA\n", urb); - dump_stack(); - } - - result = -ENOMEM; - xfer = kzalloc(sizeof(*xfer), gfp); - if (xfer == NULL) - goto error_kmalloc; - - result = -ENOENT; - if (urb->status != -EINPROGRESS) /* cancelled */ - goto error_dequeued; /* before starting? */ - wa_xfer_init(xfer); - xfer->wa = wa_get(wa); - xfer->urb = urb; - xfer->gfp = gfp; - xfer->ep = ep; - urb->hcpriv = xfer; - - dev_dbg(dev, "xfer %p urb %p pipe 0x%02x [%d bytes] %s %s %s\n", - xfer, urb, urb->pipe, urb->transfer_buffer_length, - urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP ? "dma" : "nodma", - urb->pipe & USB_DIR_IN ? "inbound" : "outbound", - cant_sleep ? "deferred" : "inline"); - - if (cant_sleep) { - usb_get_urb(urb); - spin_lock_irqsave(&wa->xfer_list_lock, my_flags); - list_add_tail(&xfer->list_node, &wa->xfer_delayed_list); - spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags); - queue_work(wusbd, &wa->xfer_work); - } else { - wa_urb_enqueue_b(xfer); - } - return 0; - -error_dequeued: - kfree(xfer); -error_kmalloc: - return result; -} -EXPORT_SYMBOL_GPL(wa_urb_enqueue); - -/* - * Dequeue a URB and make sure uwb_hcd_giveback_urb() [completion - * handler] is called. - * - * Until a transfer goes successfully through wa_urb_enqueue() it - * needs to be dequeued with completion calling; when stuck in delayed - * or before wa_xfer_setup() is called, we need to do completion. - * - * not setup If there is no hcpriv yet, that means that that enqueue - * still had no time to set the xfer up. Because - * urb->status should be other than -EINPROGRESS, - * enqueue() will catch that and bail out. - * - * If the transfer has gone through setup, we just need to clean it - * up. If it has gone through submit(), we have to abort it [with an - * asynch request] and then make sure we cancel each segment. - * - */ -int wa_urb_dequeue(struct wahc *wa, struct urb *urb) -{ - unsigned long flags, flags2; - struct wa_xfer *xfer; - struct wa_seg *seg; - struct wa_rpipe *rpipe; - unsigned cnt; - unsigned rpipe_ready = 0; - - xfer = urb->hcpriv; - if (xfer == NULL) { - /* NOthing setup yet enqueue will see urb->status != - * -EINPROGRESS (by hcd layer) and bail out with - * error, no need to do completion - */ - BUG_ON(urb->status == -EINPROGRESS); - goto out; - } - spin_lock_irqsave(&xfer->lock, flags); - rpipe = xfer->ep->hcpriv; - /* Check the delayed list -> if there, release and complete */ - spin_lock_irqsave(&wa->xfer_list_lock, flags2); - if (!list_empty(&xfer->list_node) && xfer->seg == NULL) - goto dequeue_delayed; - spin_unlock_irqrestore(&wa->xfer_list_lock, flags2); - if (xfer->seg == NULL) /* still hasn't reached */ - goto out_unlock; /* setup(), enqueue_b() completes */ - /* Ok, the xfer is in flight already, it's been setup and submitted.*/ - __wa_xfer_abort(xfer); - for (cnt = 0; cnt < xfer->segs; cnt++) { - seg = xfer->seg[cnt]; - switch (seg->status) { - case WA_SEG_NOTREADY: - case WA_SEG_READY: - printk(KERN_ERR "xfer %p#%u: dequeue bad state %u\n", - xfer, cnt, seg->status); - WARN_ON(1); - break; - case WA_SEG_DELAYED: - seg->status = WA_SEG_ABORTED; - spin_lock_irqsave(&rpipe->seg_lock, flags2); - list_del(&seg->list_node); - xfer->segs_done++; - rpipe_ready = rpipe_avail_inc(rpipe); - spin_unlock_irqrestore(&rpipe->seg_lock, flags2); - break; - case WA_SEG_SUBMITTED: - seg->status = WA_SEG_ABORTED; - usb_unlink_urb(&seg->urb); - if (xfer->is_inbound == 0) - usb_unlink_urb(seg->dto_urb); - xfer->segs_done++; - rpipe_ready = rpipe_avail_inc(rpipe); - break; - case WA_SEG_PENDING: - seg->status = WA_SEG_ABORTED; - xfer->segs_done++; - rpipe_ready = rpipe_avail_inc(rpipe); - break; - case WA_SEG_DTI_PENDING: - usb_unlink_urb(wa->dti_urb); - seg->status = WA_SEG_ABORTED; - xfer->segs_done++; - rpipe_ready = rpipe_avail_inc(rpipe); - break; - case WA_SEG_DONE: - case WA_SEG_ERROR: - case WA_SEG_ABORTED: - break; - } - } - xfer->result = urb->status; /* -ENOENT or -ECONNRESET */ - __wa_xfer_is_done(xfer); - spin_unlock_irqrestore(&xfer->lock, flags); - wa_xfer_completion(xfer); - if (rpipe_ready) - wa_xfer_delayed_run(rpipe); - return 0; - -out_unlock: - spin_unlock_irqrestore(&xfer->lock, flags); -out: - return 0; - -dequeue_delayed: - list_del_init(&xfer->list_node); - spin_unlock_irqrestore(&wa->xfer_list_lock, flags2); - xfer->result = urb->status; - spin_unlock_irqrestore(&xfer->lock, flags); - wa_xfer_giveback(xfer); - usb_put_urb(urb); /* we got a ref in enqueue() */ - return 0; -} -EXPORT_SYMBOL_GPL(wa_urb_dequeue); - -/* - * Translation from WA status codes (WUSB1.0 Table 8.15) to errno - * codes - * - * Positive errno values are internal inconsistencies and should be - * flagged louder. Negative are to be passed up to the user in the - * normal way. - * - * @status: USB WA status code -- high two bits are stripped. - */ -static int wa_xfer_status_to_errno(u8 status) -{ - int errno; - u8 real_status = status; - static int xlat[] = { - [WA_XFER_STATUS_SUCCESS] = 0, - [WA_XFER_STATUS_HALTED] = -EPIPE, - [WA_XFER_STATUS_DATA_BUFFER_ERROR] = -ENOBUFS, - [WA_XFER_STATUS_BABBLE] = -EOVERFLOW, - [WA_XFER_RESERVED] = EINVAL, - [WA_XFER_STATUS_NOT_FOUND] = 0, - [WA_XFER_STATUS_INSUFFICIENT_RESOURCE] = -ENOMEM, - [WA_XFER_STATUS_TRANSACTION_ERROR] = -EILSEQ, - [WA_XFER_STATUS_ABORTED] = -EINTR, - [WA_XFER_STATUS_RPIPE_NOT_READY] = EINVAL, - [WA_XFER_INVALID_FORMAT] = EINVAL, - [WA_XFER_UNEXPECTED_SEGMENT_NUMBER] = EINVAL, - [WA_XFER_STATUS_RPIPE_TYPE_MISMATCH] = EINVAL, - }; - status &= 0x3f; - - if (status == 0) - return 0; - if (status >= ARRAY_SIZE(xlat)) { - printk_ratelimited(KERN_ERR "%s(): BUG? " - "Unknown WA transfer status 0x%02x\n", - __func__, real_status); - return -EINVAL; - } - errno = xlat[status]; - if (unlikely(errno > 0)) { - printk_ratelimited(KERN_ERR "%s(): BUG? " - "Inconsistent WA status: 0x%02x\n", - __func__, real_status); - errno = -errno; - } - return errno; -} - -/* - * Process a xfer result completion message - * - * inbound transfers: need to schedule a DTI read - * - * FIXME: this functio needs to be broken up in parts - */ -static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer) -{ - int result; - struct device *dev = &wa->usb_iface->dev; - unsigned long flags; - u8 seg_idx; - struct wa_seg *seg; - struct wa_rpipe *rpipe; - struct wa_xfer_result *xfer_result = wa->xfer_result; - u8 done = 0; - u8 usb_status; - unsigned rpipe_ready = 0; - - spin_lock_irqsave(&xfer->lock, flags); - seg_idx = xfer_result->bTransferSegment & 0x7f; - if (unlikely(seg_idx >= xfer->segs)) - goto error_bad_seg; - seg = xfer->seg[seg_idx]; - rpipe = xfer->ep->hcpriv; - usb_status = xfer_result->bTransferStatus; - dev_dbg(dev, "xfer %p#%u: bTransferStatus 0x%02x (seg %u)\n", - xfer, seg_idx, usb_status, seg->status); - if (seg->status == WA_SEG_ABORTED - || seg->status == WA_SEG_ERROR) /* already handled */ - goto segment_aborted; - if (seg->status == WA_SEG_SUBMITTED) /* ops, got here */ - seg->status = WA_SEG_PENDING; /* before wa_seg{_dto}_cb() */ - if (seg->status != WA_SEG_PENDING) { - if (printk_ratelimit()) - dev_err(dev, "xfer %p#%u: Bad segment state %u\n", - xfer, seg_idx, seg->status); - seg->status = WA_SEG_PENDING; /* workaround/"fix" it */ - } - if (usb_status & 0x80) { - seg->result = wa_xfer_status_to_errno(usb_status); - dev_err(dev, "DTI: xfer %p#%u failed (0x%02x)\n", - xfer, seg->index, usb_status); - goto error_complete; - } - /* FIXME: we ignore warnings, tally them for stats */ - if (usb_status & 0x40) /* Warning?... */ - usb_status = 0; /* ... pass */ - if (xfer->is_inbound) { /* IN data phase: read to buffer */ - seg->status = WA_SEG_DTI_PENDING; - BUG_ON(wa->buf_in_urb->status == -EINPROGRESS); - if (xfer->is_dma) { - wa->buf_in_urb->transfer_dma = - xfer->urb->transfer_dma - + seg_idx * xfer->seg_size; - wa->buf_in_urb->transfer_flags - |= URB_NO_TRANSFER_DMA_MAP; - } else { - wa->buf_in_urb->transfer_buffer = - xfer->urb->transfer_buffer - + seg_idx * xfer->seg_size; - wa->buf_in_urb->transfer_flags - &= ~URB_NO_TRANSFER_DMA_MAP; - } - wa->buf_in_urb->transfer_buffer_length = - le32_to_cpu(xfer_result->dwTransferLength); - wa->buf_in_urb->context = seg; - result = usb_submit_urb(wa->buf_in_urb, GFP_ATOMIC); - if (result < 0) - goto error_submit_buf_in; - } else { - /* OUT data phase, complete it -- */ - seg->status = WA_SEG_DONE; - seg->result = le32_to_cpu(xfer_result->dwTransferLength); - xfer->segs_done++; - rpipe_ready = rpipe_avail_inc(rpipe); - done = __wa_xfer_is_done(xfer); - } - spin_unlock_irqrestore(&xfer->lock, flags); - if (done) - wa_xfer_completion(xfer); - if (rpipe_ready) - wa_xfer_delayed_run(rpipe); - return; - -error_submit_buf_in: - if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) { - dev_err(dev, "DTI: URB max acceptable errors " - "exceeded, resetting device\n"); - wa_reset_all(wa); - } - if (printk_ratelimit()) - dev_err(dev, "xfer %p#%u: can't submit DTI data phase: %d\n", - xfer, seg_idx, result); - seg->result = result; -error_complete: - seg->status = WA_SEG_ERROR; - xfer->segs_done++; - rpipe_ready = rpipe_avail_inc(rpipe); - __wa_xfer_abort(xfer); - done = __wa_xfer_is_done(xfer); - spin_unlock_irqrestore(&xfer->lock, flags); - if (done) - wa_xfer_completion(xfer); - if (rpipe_ready) - wa_xfer_delayed_run(rpipe); - return; - -error_bad_seg: - spin_unlock_irqrestore(&xfer->lock, flags); - wa_urb_dequeue(wa, xfer->urb); - if (printk_ratelimit()) - dev_err(dev, "xfer %p#%u: bad segment\n", xfer, seg_idx); - if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) { - dev_err(dev, "DTI: URB max acceptable errors " - "exceeded, resetting device\n"); - wa_reset_all(wa); - } - return; - -segment_aborted: - /* nothing to do, as the aborter did the completion */ - spin_unlock_irqrestore(&xfer->lock, flags); -} - -/* - * Callback for the IN data phase - * - * If successful transition state; otherwise, take a note of the - * error, mark this segment done and try completion. - * - * Note we don't access until we are sure that the transfer hasn't - * been cancelled (ECONNRESET, ENOENT), which could mean that - * seg->xfer could be already gone. - */ -static void wa_buf_in_cb(struct urb *urb) -{ - struct wa_seg *seg = urb->context; - struct wa_xfer *xfer = seg->xfer; - struct wahc *wa; - struct device *dev; - struct wa_rpipe *rpipe; - unsigned rpipe_ready; - unsigned long flags; - u8 done = 0; - - switch (urb->status) { - case 0: - spin_lock_irqsave(&xfer->lock, flags); - wa = xfer->wa; - dev = &wa->usb_iface->dev; - rpipe = xfer->ep->hcpriv; - dev_dbg(dev, "xfer %p#%u: data in done (%zu bytes)\n", - xfer, seg->index, (size_t)urb->actual_length); - seg->status = WA_SEG_DONE; - seg->result = urb->actual_length; - xfer->segs_done++; - rpipe_ready = rpipe_avail_inc(rpipe); - done = __wa_xfer_is_done(xfer); - spin_unlock_irqrestore(&xfer->lock, flags); - if (done) - wa_xfer_completion(xfer); - if (rpipe_ready) - wa_xfer_delayed_run(rpipe); - break; - case -ECONNRESET: /* URB unlinked; no need to do anything */ - case -ENOENT: /* as it was done by the who unlinked us */ - break; - default: /* Other errors ... */ - spin_lock_irqsave(&xfer->lock, flags); - wa = xfer->wa; - dev = &wa->usb_iface->dev; - rpipe = xfer->ep->hcpriv; - if (printk_ratelimit()) - dev_err(dev, "xfer %p#%u: data in error %d\n", - xfer, seg->index, urb->status); - if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS, - EDC_ERROR_TIMEFRAME)){ - dev_err(dev, "DTO: URB max acceptable errors " - "exceeded, resetting device\n"); - wa_reset_all(wa); - } - seg->status = WA_SEG_ERROR; - seg->result = urb->status; - xfer->segs_done++; - rpipe_ready = rpipe_avail_inc(rpipe); - __wa_xfer_abort(xfer); - done = __wa_xfer_is_done(xfer); - spin_unlock_irqrestore(&xfer->lock, flags); - if (done) - wa_xfer_completion(xfer); - if (rpipe_ready) - wa_xfer_delayed_run(rpipe); - } -} - -/* - * Handle an incoming transfer result buffer - * - * Given a transfer result buffer, it completes the transfer (possibly - * scheduling and buffer in read) and then resubmits the DTI URB for a - * new transfer result read. - * - * - * The xfer_result DTI URB state machine - * - * States: OFF | RXR (Read-Xfer-Result) | RBI (Read-Buffer-In) - * - * We start in OFF mode, the first xfer_result notification [through - * wa_handle_notif_xfer()] moves us to RXR by posting the DTI-URB to - * read. - * - * We receive a buffer -- if it is not a xfer_result, we complain and - * repost the DTI-URB. If it is a xfer_result then do the xfer seg - * request accounting. If it is an IN segment, we move to RBI and post - * a BUF-IN-URB to the right buffer. The BUF-IN-URB callback will - * repost the DTI-URB and move to RXR state. if there was no IN - * segment, it will repost the DTI-URB. - * - * We go back to OFF when we detect a ENOENT or ESHUTDOWN (or too many - * errors) in the URBs. - */ -static void wa_xfer_result_cb(struct urb *urb) -{ - int result; - struct wahc *wa = urb->context; - struct device *dev = &wa->usb_iface->dev; - struct wa_xfer_result *xfer_result; - u32 xfer_id; - struct wa_xfer *xfer; - u8 usb_status; - - BUG_ON(wa->dti_urb != urb); - switch (wa->dti_urb->status) { - case 0: - /* We have a xfer result buffer; check it */ - dev_dbg(dev, "DTI: xfer result %d bytes at %p\n", - urb->actual_length, urb->transfer_buffer); - if (wa->dti_urb->actual_length != sizeof(*xfer_result)) { - dev_err(dev, "DTI Error: xfer result--bad size " - "xfer result (%d bytes vs %zu needed)\n", - urb->actual_length, sizeof(*xfer_result)); - break; - } - xfer_result = wa->xfer_result; - if (xfer_result->hdr.bLength != sizeof(*xfer_result)) { - dev_err(dev, "DTI Error: xfer result--" - "bad header length %u\n", - xfer_result->hdr.bLength); - break; - } - if (xfer_result->hdr.bNotifyType != WA_XFER_RESULT) { - dev_err(dev, "DTI Error: xfer result--" - "bad header type 0x%02x\n", - xfer_result->hdr.bNotifyType); - break; - } - usb_status = xfer_result->bTransferStatus & 0x3f; - if (usb_status == WA_XFER_STATUS_ABORTED - || usb_status == WA_XFER_STATUS_NOT_FOUND) - /* taken care of already */ - break; - xfer_id = xfer_result->dwTransferID; - xfer = wa_xfer_get_by_id(wa, xfer_id); - if (xfer == NULL) { - /* FIXME: transaction might have been cancelled */ - dev_err(dev, "DTI Error: xfer result--" - "unknown xfer 0x%08x (status 0x%02x)\n", - xfer_id, usb_status); - break; - } - wa_xfer_result_chew(wa, xfer); - wa_xfer_put(xfer); - break; - case -ENOENT: /* (we killed the URB)...so, no broadcast */ - case -ESHUTDOWN: /* going away! */ - dev_dbg(dev, "DTI: going down! %d\n", urb->status); - goto out; - default: - /* Unknown error */ - if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS, - EDC_ERROR_TIMEFRAME)) { - dev_err(dev, "DTI: URB max acceptable errors " - "exceeded, resetting device\n"); - wa_reset_all(wa); - goto out; - } - if (printk_ratelimit()) - dev_err(dev, "DTI: URB error %d\n", urb->status); - break; - } - /* Resubmit the DTI URB */ - result = usb_submit_urb(wa->dti_urb, GFP_ATOMIC); - if (result < 0) { - dev_err(dev, "DTI Error: Could not submit DTI URB (%d), " - "resetting\n", result); - wa_reset_all(wa); - } -out: - return; -} - -/* - * Transfer complete notification - * - * Called from the notif.c code. We get a notification on EP2 saying - * that some endpoint has some transfer result data available. We are - * about to read it. - * - * To speed up things, we always have a URB reading the DTI URB; we - * don't really set it up and start it until the first xfer complete - * notification arrives, which is what we do here. - * - * Follow up in wa_xfer_result_cb(), as that's where the whole state - * machine starts. - * - * So here we just initialize the DTI URB for reading transfer result - * notifications and also the buffer-in URB, for reading buffers. Then - * we just submit the DTI URB. - * - * @wa shall be referenced - */ -void wa_handle_notif_xfer(struct wahc *wa, struct wa_notif_hdr *notif_hdr) -{ - int result; - struct device *dev = &wa->usb_iface->dev; - struct wa_notif_xfer *notif_xfer; - const struct usb_endpoint_descriptor *dti_epd = wa->dti_epd; - - notif_xfer = container_of(notif_hdr, struct wa_notif_xfer, hdr); - BUG_ON(notif_hdr->bNotifyType != WA_NOTIF_TRANSFER); - - if ((0x80 | notif_xfer->bEndpoint) != dti_epd->bEndpointAddress) { - /* FIXME: hardcoded limitation, adapt */ - dev_err(dev, "BUG: DTI ep is %u, not %u (hack me)\n", - notif_xfer->bEndpoint, dti_epd->bEndpointAddress); - goto error; - } - if (wa->dti_urb != NULL) /* DTI URB already started */ - goto out; - - wa->dti_urb = usb_alloc_urb(0, GFP_KERNEL); - if (wa->dti_urb == NULL) { - dev_err(dev, "Can't allocate DTI URB\n"); - goto error_dti_urb_alloc; - } - usb_fill_bulk_urb( - wa->dti_urb, wa->usb_dev, - usb_rcvbulkpipe(wa->usb_dev, 0x80 | notif_xfer->bEndpoint), - wa->xfer_result, wa->xfer_result_size, - wa_xfer_result_cb, wa); - - wa->buf_in_urb = usb_alloc_urb(0, GFP_KERNEL); - if (wa->buf_in_urb == NULL) { - dev_err(dev, "Can't allocate BUF-IN URB\n"); - goto error_buf_in_urb_alloc; - } - usb_fill_bulk_urb( - wa->buf_in_urb, wa->usb_dev, - usb_rcvbulkpipe(wa->usb_dev, 0x80 | notif_xfer->bEndpoint), - NULL, 0, wa_buf_in_cb, wa); - result = usb_submit_urb(wa->dti_urb, GFP_KERNEL); - if (result < 0) { - dev_err(dev, "DTI Error: Could not submit DTI URB (%d), " - "resetting\n", result); - goto error_dti_urb_submit; - } -out: - return; - -error_dti_urb_submit: - usb_put_urb(wa->buf_in_urb); -error_buf_in_urb_alloc: - usb_put_urb(wa->dti_urb); - wa->dti_urb = NULL; -error_dti_urb_alloc: -error: - wa_reset_all(wa); -} diff --git a/ANDROID_3.4.5/drivers/usb/wusbcore/wusbhc.c b/ANDROID_3.4.5/drivers/usb/wusbcore/wusbhc.c deleted file mode 100644 index 0faca16d..00000000 --- a/ANDROID_3.4.5/drivers/usb/wusbcore/wusbhc.c +++ /dev/null @@ -1,450 +0,0 @@ -/* - * Wireless USB Host Controller - * sysfs glue, wusbcore module support and life cycle management - * - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * - * Creation/destruction of wusbhc is split in two parts; that that - * doesn't require the HCD to be added (wusbhc_{create,destroy}) and - * the one that requires (phase B, wusbhc_b_{create,destroy}). - * - * This is so because usb_add_hcd() will start the HC, and thus, all - * the HC specific stuff has to be already initialized (like sysfs - * thingies). - */ -#include -#include -#include "wusbhc.h" - -/** - * Extract the wusbhc that corresponds to a USB Host Controller class device - * - * WARNING! Apply only if @dev is that of a - * wusbhc.usb_hcd.self->class_dev; otherwise, you loose. - */ -static struct wusbhc *usbhc_dev_to_wusbhc(struct device *dev) -{ - struct usb_bus *usb_bus = dev_get_drvdata(dev); - struct usb_hcd *usb_hcd = bus_to_hcd(usb_bus); - return usb_hcd_to_wusbhc(usb_hcd); -} - -/* - * Show & store the current WUSB trust timeout - * - * We don't do locking--it is an 'atomic' value. - * - * The units that we store/show are always MILLISECONDS. However, the - * value of trust_timeout is jiffies. - */ -static ssize_t wusb_trust_timeout_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev); - - return scnprintf(buf, PAGE_SIZE, "%u\n", wusbhc->trust_timeout); -} - -static ssize_t wusb_trust_timeout_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev); - ssize_t result = -ENOSYS; - unsigned trust_timeout; - - result = sscanf(buf, "%u", &trust_timeout); - if (result != 1) { - result = -EINVAL; - goto out; - } - /* FIXME: maybe we should check for range validity? */ - wusbhc->trust_timeout = trust_timeout; - cancel_delayed_work(&wusbhc->keep_alive_timer); - flush_workqueue(wusbd); - queue_delayed_work(wusbd, &wusbhc->keep_alive_timer, - (trust_timeout * CONFIG_HZ)/1000/2); -out: - return result < 0 ? result : size; -} -static DEVICE_ATTR(wusb_trust_timeout, 0644, wusb_trust_timeout_show, - wusb_trust_timeout_store); - -/* - * Show the current WUSB CHID. - */ -static ssize_t wusb_chid_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev); - const struct wusb_ckhdid *chid; - ssize_t result = 0; - - if (wusbhc->wuie_host_info != NULL) - chid = &wusbhc->wuie_host_info->CHID; - else - chid = &wusb_ckhdid_zero; - - result += ckhdid_printf(buf, PAGE_SIZE, chid); - result += sprintf(buf + result, "\n"); - - return result; -} - -/* - * Store a new CHID. - * - * - Write an all zeros CHID and it will stop the controller - * - Write a non-zero CHID and it will start it. - * - * See wusbhc_chid_set() for more info. - */ -static ssize_t wusb_chid_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev); - struct wusb_ckhdid chid; - ssize_t result; - - result = sscanf(buf, - "%02hhx %02hhx %02hhx %02hhx " - "%02hhx %02hhx %02hhx %02hhx " - "%02hhx %02hhx %02hhx %02hhx " - "%02hhx %02hhx %02hhx %02hhx\n", - &chid.data[0] , &chid.data[1] , - &chid.data[2] , &chid.data[3] , - &chid.data[4] , &chid.data[5] , - &chid.data[6] , &chid.data[7] , - &chid.data[8] , &chid.data[9] , - &chid.data[10], &chid.data[11], - &chid.data[12], &chid.data[13], - &chid.data[14], &chid.data[15]); - if (result != 16) { - dev_err(dev, "Unrecognized CHID (need 16 8-bit hex digits): " - "%d\n", (int)result); - return -EINVAL; - } - result = wusbhc_chid_set(wusbhc, &chid); - return result < 0 ? result : size; -} -static DEVICE_ATTR(wusb_chid, 0644, wusb_chid_show, wusb_chid_store); - - -static ssize_t wusb_phy_rate_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev); - - return sprintf(buf, "%d\n", wusbhc->phy_rate); -} - -static ssize_t wusb_phy_rate_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev); - uint8_t phy_rate; - ssize_t result; - - result = sscanf(buf, "%hhu", &phy_rate); - if (result != 1) - return -EINVAL; - if (phy_rate >= UWB_PHY_RATE_INVALID) - return -EINVAL; - - wusbhc->phy_rate = phy_rate; - return size; -} -static DEVICE_ATTR(wusb_phy_rate, 0644, wusb_phy_rate_show, wusb_phy_rate_store); - -/* Group all the WUSBHC attributes */ -static struct attribute *wusbhc_attrs[] = { - &dev_attr_wusb_trust_timeout.attr, - &dev_attr_wusb_chid.attr, - &dev_attr_wusb_phy_rate.attr, - NULL, -}; - -static struct attribute_group wusbhc_attr_group = { - .name = NULL, /* we want them in the same directory */ - .attrs = wusbhc_attrs, -}; - -/* - * Create a wusbhc instance - * - * NOTEs: - * - * - assumes *wusbhc has been zeroed and wusbhc->usb_hcd has been - * initialized but not added. - * - * - fill out ports_max, mmcies_max and mmcie_{add,rm} before calling. - * - * - fill out wusbhc->uwb_rc and refcount it before calling - * - fill out the wusbhc->sec_modes array - */ -int wusbhc_create(struct wusbhc *wusbhc) -{ - int result = 0; - - wusbhc->trust_timeout = WUSB_TRUST_TIMEOUT_MS; - wusbhc->phy_rate = UWB_PHY_RATE_INVALID - 1; - - mutex_init(&wusbhc->mutex); - result = wusbhc_mmcie_create(wusbhc); - if (result < 0) - goto error_mmcie_create; - result = wusbhc_devconnect_create(wusbhc); - if (result < 0) - goto error_devconnect_create; - result = wusbhc_rh_create(wusbhc); - if (result < 0) - goto error_rh_create; - result = wusbhc_sec_create(wusbhc); - if (result < 0) - goto error_sec_create; - return 0; - -error_sec_create: - wusbhc_rh_destroy(wusbhc); -error_rh_create: - wusbhc_devconnect_destroy(wusbhc); -error_devconnect_create: - wusbhc_mmcie_destroy(wusbhc); -error_mmcie_create: - return result; -} -EXPORT_SYMBOL_GPL(wusbhc_create); - -static inline struct kobject *wusbhc_kobj(struct wusbhc *wusbhc) -{ - return &wusbhc->usb_hcd.self.controller->kobj; -} - -/* - * Phase B of a wusbhc instance creation - * - * Creates fields that depend on wusbhc->usb_hcd having been - * added. This is where we create the sysfs files in - * /sys/class/usb_host/usb_hostX/. - * - * NOTE: Assumes wusbhc->usb_hcd has been already added by the upper - * layer (hwahc or whci) - */ -int wusbhc_b_create(struct wusbhc *wusbhc) -{ - int result = 0; - struct device *dev = wusbhc->usb_hcd.self.controller; - - result = sysfs_create_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group); - if (result < 0) { - dev_err(dev, "Cannot register WUSBHC attributes: %d\n", result); - goto error_create_attr_group; - } - - result = wusbhc_pal_register(wusbhc); - if (result < 0) - goto error_pal_register; - return 0; - -error_pal_register: - sysfs_remove_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group); -error_create_attr_group: - return result; -} -EXPORT_SYMBOL_GPL(wusbhc_b_create); - -void wusbhc_b_destroy(struct wusbhc *wusbhc) -{ - wusbhc_pal_unregister(wusbhc); - sysfs_remove_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group); -} -EXPORT_SYMBOL_GPL(wusbhc_b_destroy); - -void wusbhc_destroy(struct wusbhc *wusbhc) -{ - wusbhc_sec_destroy(wusbhc); - wusbhc_rh_destroy(wusbhc); - wusbhc_devconnect_destroy(wusbhc); - wusbhc_mmcie_destroy(wusbhc); -} -EXPORT_SYMBOL_GPL(wusbhc_destroy); - -struct workqueue_struct *wusbd; -EXPORT_SYMBOL_GPL(wusbd); - -/* - * WUSB Cluster ID allocation map - * - * Each WUSB bus in a channel is identified with a Cluster Id in the - * unauth address pace (WUSB1.0[4.3]). We take the range 0xe0 to 0xff - * (that's space for 31 WUSB controllers, as 0xff can't be taken). We - * start taking from 0xff, 0xfe, 0xfd... (hence the += or -= 0xff). - * - * For each one we taken, we pin it in the bitap - */ -#define CLUSTER_IDS 32 -static DECLARE_BITMAP(wusb_cluster_id_table, CLUSTER_IDS); -static DEFINE_SPINLOCK(wusb_cluster_ids_lock); - -/* - * Get a WUSB Cluster ID - * - * Need to release with wusb_cluster_id_put() when done w/ it. - */ -/* FIXME: coordinate with the choose_addres() from the USB stack */ -/* we want to leave the top of the 128 range for cluster addresses and - * the bottom for device addresses (as we map them one on one with - * ports). */ -u8 wusb_cluster_id_get(void) -{ - u8 id; - spin_lock(&wusb_cluster_ids_lock); - id = find_first_zero_bit(wusb_cluster_id_table, CLUSTER_IDS); - if (id >= CLUSTER_IDS) { - id = 0; - goto out; - } - set_bit(id, wusb_cluster_id_table); - id = (u8) 0xff - id; -out: - spin_unlock(&wusb_cluster_ids_lock); - return id; - -} -EXPORT_SYMBOL_GPL(wusb_cluster_id_get); - -/* - * Release a WUSB Cluster ID - * - * Obtained it with wusb_cluster_id_get() - */ -void wusb_cluster_id_put(u8 id) -{ - id = 0xff - id; - BUG_ON(id >= CLUSTER_IDS); - spin_lock(&wusb_cluster_ids_lock); - WARN_ON(!test_bit(id, wusb_cluster_id_table)); - clear_bit(id, wusb_cluster_id_table); - spin_unlock(&wusb_cluster_ids_lock); -} -EXPORT_SYMBOL_GPL(wusb_cluster_id_put); - -/** - * wusbhc_giveback_urb - return an URB to the USB core - * @wusbhc: the host controller the URB is from. - * @urb: the URB. - * @status: the URB's status. - * - * Return an URB to the USB core doing some additional WUSB specific - * processing. - * - * - After a successful transfer, update the trust timeout timestamp - * for the WUSB device. - * - * - [WUSB] sections 4.13 and 7.5.1 specifies the stop retrasmittion - * condition for the WCONNECTACK_IE is that the host has observed - * the associated device responding to a control transfer. - */ -void wusbhc_giveback_urb(struct wusbhc *wusbhc, struct urb *urb, int status) -{ - struct wusb_dev *wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, urb->dev); - - if (status == 0 && wusb_dev) { - wusb_dev->entry_ts = jiffies; - - /* wusbhc_devconnect_acked() can't be called from - atomic context so defer it to a work queue. */ - if (!list_empty(&wusb_dev->cack_node)) - queue_work(wusbd, &wusb_dev->devconnect_acked_work); - else - wusb_dev_put(wusb_dev); - } - - usb_hcd_giveback_urb(&wusbhc->usb_hcd, urb, status); -} -EXPORT_SYMBOL_GPL(wusbhc_giveback_urb); - -/** - * wusbhc_reset_all - reset the HC hardware - * @wusbhc: the host controller to reset. - * - * Request a full hardware reset of the chip. This will also reset - * the radio controller and any other PALs. - */ -void wusbhc_reset_all(struct wusbhc *wusbhc) -{ - uwb_rc_reset_all(wusbhc->uwb_rc); -} -EXPORT_SYMBOL_GPL(wusbhc_reset_all); - -static struct notifier_block wusb_usb_notifier = { - .notifier_call = wusb_usb_ncb, - .priority = INT_MAX /* Need to be called first of all */ -}; - -static int __init wusbcore_init(void) -{ - int result; - result = wusb_crypto_init(); - if (result < 0) - goto error_crypto_init; - /* WQ is singlethread because we need to serialize notifications */ - wusbd = create_singlethread_workqueue("wusbd"); - if (wusbd == NULL) { - result = -ENOMEM; - printk(KERN_ERR "WUSB-core: Cannot create wusbd workqueue\n"); - goto error_wusbd_create; - } - usb_register_notify(&wusb_usb_notifier); - bitmap_zero(wusb_cluster_id_table, CLUSTER_IDS); - set_bit(0, wusb_cluster_id_table); /* reserve Cluster ID 0xff */ - return 0; - -error_wusbd_create: - wusb_crypto_exit(); -error_crypto_init: - return result; - -} -module_init(wusbcore_init); - -static void __exit wusbcore_exit(void) -{ - clear_bit(0, wusb_cluster_id_table); - if (!bitmap_empty(wusb_cluster_id_table, CLUSTER_IDS)) { - char buf[256]; - bitmap_scnprintf(buf, sizeof(buf), wusb_cluster_id_table, - CLUSTER_IDS); - printk(KERN_ERR "BUG: WUSB Cluster IDs not released " - "on exit: %s\n", buf); - WARN_ON(1); - } - usb_unregister_notify(&wusb_usb_notifier); - destroy_workqueue(wusbd); - wusb_crypto_exit(); -} -module_exit(wusbcore_exit); - -MODULE_AUTHOR("Inaky Perez-Gonzalez "); -MODULE_DESCRIPTION("Wireless USB core"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/usb/wusbcore/wusbhc.h b/ANDROID_3.4.5/drivers/usb/wusbcore/wusbhc.h deleted file mode 100644 index 3a2d0916..00000000 --- a/ANDROID_3.4.5/drivers/usb/wusbcore/wusbhc.h +++ /dev/null @@ -1,496 +0,0 @@ -/* - * Wireless USB Host Controller - * Common infrastructure for WHCI and HWA WUSB-HC drivers - * - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * - * This driver implements parts common to all Wireless USB Host - * Controllers (struct wusbhc, embedding a struct usb_hcd) and is used - * by: - * - * - hwahc: HWA, USB-dongle that implements a Wireless USB host - * controller, (Wireless USB 1.0 Host-Wire-Adapter specification). - * - * - whci: WHCI, a PCI card with a wireless host controller - * (Wireless Host Controller Interface 1.0 specification). - * - * Check out the Design-overview.txt file in the source documentation - * for other details on the implementation. - * - * Main blocks: - * - * rh Root Hub emulation (part of the HCD glue) - * - * devconnect Handle all the issues related to device connection, - * authentication, disconnection, timeout, reseting, - * keepalives, etc. - * - * mmc MMC IE broadcasting handling - * - * A host controller driver just initializes its stuff and as part of - * that, creates a 'struct wusbhc' instance that handles all the - * common WUSB mechanisms. Links in the function ops that are specific - * to it and then registers the host controller. Ready to run. - */ - -#ifndef __WUSBHC_H__ -#define __WUSBHC_H__ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Time from a WUSB channel stop request to the last transmitted MMC. - * - * This needs to be > 4.096 ms in case no MMCs can be transmitted in - * zone 0. - */ -#define WUSB_CHANNEL_STOP_DELAY_MS 8 - -/** - * Wireless USB device - * - * Describe a WUSB device connected to the cluster. This struct - * belongs to the 'struct wusb_port' it is attached to and it is - * responsible for putting and clearing the pointer to it. - * - * Note this "complements" the 'struct usb_device' that the usb_hcd - * keeps for each connected USB device. However, it extends some - * information that is not available (there is no hcpriv ptr in it!) - * *and* most importantly, it's life cycle is different. It is created - * as soon as we get a DN_Connect (connect request notification) from - * the device through the WUSB host controller; the USB stack doesn't - * create the device until we authenticate it. FIXME: this will - * change. - * - * @bos: This is allocated when the BOS descriptors are read from - * the device and freed upon the wusb_dev struct dying. - * @wusb_cap_descr: points into @bos, and has been verified to be size - * safe. - */ -struct wusb_dev { - struct kref refcnt; - struct wusbhc *wusbhc; - struct list_head cack_node; /* Connect-Ack list */ - u8 port_idx; - u8 addr; - u8 beacon_type:4; - struct usb_encryption_descriptor ccm1_etd; - struct wusb_ckhdid cdid; - unsigned long entry_ts; - struct usb_bos_descriptor *bos; - struct usb_wireless_cap_descriptor *wusb_cap_descr; - struct uwb_mas_bm availability; - struct work_struct devconnect_acked_work; - struct urb *set_gtk_urb; - struct usb_ctrlrequest *set_gtk_req; - struct usb_device *usb_dev; -}; - -#define WUSB_DEV_ADDR_UNAUTH 0x80 - -static inline void wusb_dev_init(struct wusb_dev *wusb_dev) -{ - kref_init(&wusb_dev->refcnt); - /* no need to init the cack_node */ -} - -extern void wusb_dev_destroy(struct kref *_wusb_dev); - -static inline struct wusb_dev *wusb_dev_get(struct wusb_dev *wusb_dev) -{ - kref_get(&wusb_dev->refcnt); - return wusb_dev; -} - -static inline void wusb_dev_put(struct wusb_dev *wusb_dev) -{ - kref_put(&wusb_dev->refcnt, wusb_dev_destroy); -} - -/** - * Wireless USB Host Controller root hub "fake" ports - * (state and device information) - * - * Wireless USB is wireless, so there are no ports; but we - * fake'em. Each RC can connect a max of devices at the same time - * (given in the Wireless Adapter descriptor, bNumPorts or WHCI's - * caps), referred to in wusbhc->ports_max. - * - * See rh.c for more information. - * - * The @status and @change use the same bits as in USB2.0[11.24.2.7], - * so we don't have to do much when getting the port's status. - * - * WUSB1.0[7.1], USB2.0[11.24.2.7.1,fig 11-10], - * include/linux/usb_ch9.h (#define USB_PORT_STAT_*) - */ -struct wusb_port { - u16 status; - u16 change; - struct wusb_dev *wusb_dev; /* connected device's info */ - u32 ptk_tkid; -}; - -/** - * WUSB Host Controller specifics - * - * All fields that are common to all Wireless USB controller types - * (HWA and WHCI) are grouped here. Host Controller - * functions/operations that only deal with general Wireless USB HC - * issues use this data type to refer to the host. - * - * @usb_hcd Instantiation of a USB host controller - * (initialized by upper layer [HWA=HC or WHCI]. - * - * @dev Device that implements this; initialized by the - * upper layer (HWA-HC, WHCI...); this device should - * have a refcount. - * - * @trust_timeout After this time without hearing for device - * activity, we consider the device gone and we have to - * re-authenticate. - * - * Can be accessed w/o locking--however, read to a - * local variable then use. - * - * @chid WUSB Cluster Host ID: this is supposed to be a - * unique value that doesn't change across reboots (so - * that your devices do not require re-association). - * - * Read/Write protected by @mutex - * - * @dev_info This array has ports_max elements. It is used to - * give the HC information about the WUSB devices (see - * 'struct wusb_dev_info'). - * - * For HWA we need to allocate it in heap; for WHCI it - * needs to be permanently mapped, so we keep it for - * both and make it easy. Call wusbhc->dev_info_set() - * to update an entry. - * - * @ports_max Number of simultaneous device connections (fake - * ports) this HC will take. Read-only. - * - * @port Array of port status for each fake root port. Guaranteed to - * always be the same length during device existence - * [this allows for some unlocked but referenced reading]. - * - * @mmcies_max Max number of Information Elements this HC can send - * in its MMC. Read-only. - * - * @start Start the WUSB channel. - * - * @stop Stop the WUSB channel after the specified number of - * milliseconds. Channel Stop IEs should be transmitted - * as required by [WUSB] 4.16.2.1. - * - * @mmcie_add HC specific operation (WHCI or HWA) for adding an - * MMCIE. - * - * @mmcie_rm HC specific operation (WHCI or HWA) for removing an - * MMCIE. - * - * @set_ptk: Set the PTK and enable encryption for a device. Or, if - * the supplied key is NULL, disable encryption for that - * device. - * - * @set_gtk: Set the GTK to be used for all future broadcast packets - * (i.e., MMCs). With some hardware, setting the GTK may start - * MMC transmission. - * - * NOTE: - * - * - If wusb_dev->usb_dev is not NULL, then usb_dev is valid - * (wusb_dev has a refcount on it). Likewise, if usb_dev->wusb_dev - * is not NULL, usb_dev->wusb_dev is valid (usb_dev keeps a - * refcount on it). - * - * Most of the times when you need to use it, it will be non-NULL, - * so there is no real need to check for it (wusb_dev will - * disappear before usb_dev). - * - * - The following fields need to be filled out before calling - * wusbhc_create(): ports_max, mmcies_max, mmcie_{add,rm}. - * - * - there is no wusbhc_init() method, we do everything in - * wusbhc_create(). - * - * - Creation is done in two phases, wusbhc_create() and - * wusbhc_create_b(); b are the parts that need to be called after - * calling usb_hcd_add(&wusbhc->usb_hcd). - */ -struct wusbhc { - struct usb_hcd usb_hcd; /* HAS TO BE 1st */ - struct device *dev; - struct uwb_rc *uwb_rc; - struct uwb_pal pal; - - unsigned trust_timeout; /* in jiffies */ - struct wusb_ckhdid chid; - uint8_t phy_rate; - struct wuie_host_info *wuie_host_info; - - struct mutex mutex; /* locks everything else */ - u16 cluster_id; /* Wireless USB Cluster ID */ - struct wusb_port *port; /* Fake port status handling */ - struct wusb_dev_info *dev_info; /* for Set Device Info mgmt */ - u8 ports_max; - unsigned active:1; /* currently xmit'ing MMCs */ - struct wuie_keep_alive keep_alive_ie; /* protected by mutex */ - struct delayed_work keep_alive_timer; - struct list_head cack_list; /* Connect acknowledging */ - size_t cack_count; /* protected by 'mutex' */ - struct wuie_connect_ack cack_ie; - struct uwb_rsv *rsv; /* cluster bandwidth reservation */ - - struct mutex mmcie_mutex; /* MMC WUIE handling */ - struct wuie_hdr **mmcie; /* WUIE array */ - u8 mmcies_max; - /* FIXME: make wusbhc_ops? */ - int (*start)(struct wusbhc *wusbhc); - void (*stop)(struct wusbhc *wusbhc, int delay); - int (*mmcie_add)(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, - u8 handle, struct wuie_hdr *wuie); - int (*mmcie_rm)(struct wusbhc *wusbhc, u8 handle); - int (*dev_info_set)(struct wusbhc *, struct wusb_dev *wusb_dev); - int (*bwa_set)(struct wusbhc *wusbhc, s8 stream_index, - const struct uwb_mas_bm *); - int (*set_ptk)(struct wusbhc *wusbhc, u8 port_idx, - u32 tkid, const void *key, size_t key_size); - int (*set_gtk)(struct wusbhc *wusbhc, - u32 tkid, const void *key, size_t key_size); - int (*set_num_dnts)(struct wusbhc *wusbhc, u8 interval, u8 slots); - - struct { - struct usb_key_descriptor descr; - u8 data[16]; /* GTK key data */ - } __attribute__((packed)) gtk; - u8 gtk_index; - u32 gtk_tkid; - struct work_struct gtk_rekey_done_work; - int pending_set_gtks; - - struct usb_encryption_descriptor *ccm1_etd; -}; - -#define usb_hcd_to_wusbhc(u) container_of((u), struct wusbhc, usb_hcd) - - -extern int wusbhc_create(struct wusbhc *); -extern int wusbhc_b_create(struct wusbhc *); -extern void wusbhc_b_destroy(struct wusbhc *); -extern void wusbhc_destroy(struct wusbhc *); -extern int wusb_dev_sysfs_add(struct wusbhc *, struct usb_device *, - struct wusb_dev *); -extern void wusb_dev_sysfs_rm(struct wusb_dev *); -extern int wusbhc_sec_create(struct wusbhc *); -extern int wusbhc_sec_start(struct wusbhc *); -extern void wusbhc_sec_stop(struct wusbhc *); -extern void wusbhc_sec_destroy(struct wusbhc *); -extern void wusbhc_giveback_urb(struct wusbhc *wusbhc, struct urb *urb, - int status); -void wusbhc_reset_all(struct wusbhc *wusbhc); - -int wusbhc_pal_register(struct wusbhc *wusbhc); -void wusbhc_pal_unregister(struct wusbhc *wusbhc); - -/* - * Return @usb_dev's @usb_hcd (properly referenced) or NULL if gone - * - * @usb_dev: USB device, UNLOCKED and referenced (or otherwise, safe ptr) - * - * This is a safe assumption as @usb_dev->bus is referenced all the - * time during the @usb_dev life cycle. - */ -static inline struct usb_hcd *usb_hcd_get_by_usb_dev(struct usb_device *usb_dev) -{ - struct usb_hcd *usb_hcd; - usb_hcd = container_of(usb_dev->bus, struct usb_hcd, self); - return usb_get_hcd(usb_hcd); -} - -/* - * Increment the reference count on a wusbhc. - * - * @wusbhc's life cycle is identical to that of the underlying usb_hcd. - */ -static inline struct wusbhc *wusbhc_get(struct wusbhc *wusbhc) -{ - return usb_get_hcd(&wusbhc->usb_hcd) ? wusbhc : NULL; -} - -/* - * Return the wusbhc associated to a @usb_dev - * - * @usb_dev: USB device, UNLOCKED and referenced (or otherwise, safe ptr) - * - * @returns: wusbhc for @usb_dev; NULL if the @usb_dev is being torn down. - * WARNING: referenced at the usb_hcd level, unlocked - * - * FIXME: move offline - */ -static inline struct wusbhc *wusbhc_get_by_usb_dev(struct usb_device *usb_dev) -{ - struct wusbhc *wusbhc = NULL; - struct usb_hcd *usb_hcd; - if (usb_dev->devnum > 1 && !usb_dev->wusb) { - /* but root hubs */ - dev_err(&usb_dev->dev, "devnum %d wusb %d\n", usb_dev->devnum, - usb_dev->wusb); - BUG_ON(usb_dev->devnum > 1 && !usb_dev->wusb); - } - usb_hcd = usb_hcd_get_by_usb_dev(usb_dev); - if (usb_hcd == NULL) - return NULL; - BUG_ON(usb_hcd->wireless == 0); - return wusbhc = usb_hcd_to_wusbhc(usb_hcd); -} - - -static inline void wusbhc_put(struct wusbhc *wusbhc) -{ - usb_put_hcd(&wusbhc->usb_hcd); -} - -int wusbhc_start(struct wusbhc *wusbhc); -void wusbhc_stop(struct wusbhc *wusbhc); -extern int wusbhc_chid_set(struct wusbhc *, const struct wusb_ckhdid *); - -/* Device connect handling */ -extern int wusbhc_devconnect_create(struct wusbhc *); -extern void wusbhc_devconnect_destroy(struct wusbhc *); -extern int wusbhc_devconnect_start(struct wusbhc *wusbhc); -extern void wusbhc_devconnect_stop(struct wusbhc *wusbhc); -extern void wusbhc_handle_dn(struct wusbhc *, u8 srcaddr, - struct wusb_dn_hdr *dn_hdr, size_t size); -extern void __wusbhc_dev_disable(struct wusbhc *wusbhc, u8 port); -extern int wusb_usb_ncb(struct notifier_block *nb, unsigned long val, - void *priv); -extern int wusb_set_dev_addr(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev, - u8 addr); - -/* Wireless USB fake Root Hub methods */ -extern int wusbhc_rh_create(struct wusbhc *); -extern void wusbhc_rh_destroy(struct wusbhc *); - -extern int wusbhc_rh_status_data(struct usb_hcd *, char *); -extern int wusbhc_rh_control(struct usb_hcd *, u16, u16, u16, char *, u16); -extern int wusbhc_rh_suspend(struct usb_hcd *); -extern int wusbhc_rh_resume(struct usb_hcd *); -extern int wusbhc_rh_start_port_reset(struct usb_hcd *, unsigned); - -/* MMC handling */ -extern int wusbhc_mmcie_create(struct wusbhc *); -extern void wusbhc_mmcie_destroy(struct wusbhc *); -extern int wusbhc_mmcie_set(struct wusbhc *, u8 interval, u8 repeat_cnt, - struct wuie_hdr *); -extern void wusbhc_mmcie_rm(struct wusbhc *, struct wuie_hdr *); - -/* Bandwidth reservation */ -int wusbhc_rsv_establish(struct wusbhc *wusbhc); -void wusbhc_rsv_terminate(struct wusbhc *wusbhc); - -/* - * I've always said - * I wanted a wedding in a church... - * - * but lately I've been thinking about - * the Botanical Gardens. - * - * We could do it by the tulips. - * It'll be beautiful - * - * --Security! - */ -extern int wusb_dev_sec_add(struct wusbhc *, struct usb_device *, - struct wusb_dev *); -extern void wusb_dev_sec_rm(struct wusb_dev *) ; -extern int wusb_dev_4way_handshake(struct wusbhc *, struct wusb_dev *, - struct wusb_ckhdid *ck); -void wusbhc_gtk_rekey(struct wusbhc *wusbhc); -int wusb_dev_update_address(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev); - - -/* WUSB Cluster ID handling */ -extern u8 wusb_cluster_id_get(void); -extern void wusb_cluster_id_put(u8); - -/* - * wusb_port_by_idx - return the port associated to a zero-based port index - * - * NOTE: valid without locking as long as wusbhc is referenced (as the - * number of ports doesn't change). The data pointed to has to - * be verified though :) - */ -static inline struct wusb_port *wusb_port_by_idx(struct wusbhc *wusbhc, - u8 port_idx) -{ - return &wusbhc->port[port_idx]; -} - -/* - * wusb_port_no_to_idx - Convert port number (per usb_dev->portnum) to - * a port_idx. - * - * USB stack USB ports are 1 based!! - * - * NOTE: only valid for WUSB devices!!! - */ -static inline u8 wusb_port_no_to_idx(u8 port_no) -{ - return port_no - 1; -} - -extern struct wusb_dev *__wusb_dev_get_by_usb_dev(struct wusbhc *, - struct usb_device *); - -/* - * Return a referenced wusb_dev given a @usb_dev - * - * Returns NULL if the usb_dev is being torn down. - * - * FIXME: move offline - */ -static inline -struct wusb_dev *wusb_dev_get_by_usb_dev(struct usb_device *usb_dev) -{ - struct wusbhc *wusbhc; - struct wusb_dev *wusb_dev; - wusbhc = wusbhc_get_by_usb_dev(usb_dev); - if (wusbhc == NULL) - return NULL; - mutex_lock(&wusbhc->mutex); - wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, usb_dev); - mutex_unlock(&wusbhc->mutex); - wusbhc_put(wusbhc); - return wusb_dev; -} - -/* Misc */ - -extern struct workqueue_struct *wusbd; -#endif /* #ifndef __WUSBHC_H__ */ -- cgit